summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.bzrignore162
-rw-r--r--BUILD/FINISH.sh1
-rw-r--r--BUILD/Makefile.am44
-rw-r--r--BUILD/SETUP.sh4
-rwxr-xr-xBUILD/compile-alpha-cxx10
-rwxr-xr-xBUILD/compile-alpha-debug7
-rwxr-xr-xBUILD/compile-ia64-debug-max13
-rwxr-xr-xBUILD/compile-pentium-debug2
-rwxr-xr-xBUILD/compile-pentium-debug-max2
-rwxr-xr-xBUILD/compile-pentium-debug-no-bdb2
-rwxr-xr-xBUILD/compile-pentium-debug-openssl13
-rwxr-xr-xBUILD/compile-pentium-max2
-rwxr-xr-xBUILD/compile-pentium-mysqlfs-debug13
-rwxr-xr-xBUILD/compile-pentium-pgcc23
-rwxr-xr-xBUILD/compile-pentium-symbols15
-rwxr-xr-xBUILD/compile-solaris-sparc-debug16
-rw-r--r--BitKeeper/etc/logging_ok41
-rwxr-xr-xBitKeeper/triggers/post-commit49
-rwxr-xr-xBuild-tools/Do-all-build-steps8
-rwxr-xr-xBuild-tools/Do-compile2
-rwxr-xr-xBuild-tools/Do-rpm25
-rw-r--r--Docs/Flags/argentina.eps149
-rw-r--r--Docs/Flags/argentina.gifbin348 -> 187 bytes
-rw-r--r--Docs/Flags/argentina.pdfbin0 -> 923 bytes
-rw-r--r--Docs/Flags/australia.eps145
-rw-r--r--Docs/Flags/australia.gifbin689 -> 663 bytes
-rw-r--r--Docs/Flags/australia.pdfbin0 -> 1382 bytes
-rw-r--r--Docs/Flags/austria.eps109
-rw-r--r--Docs/Flags/austria.gifbin132 -> 132 bytes
-rw-r--r--Docs/Flags/austria.pdfbin0 -> 816 bytes
-rw-r--r--Docs/Flags/belgium.eps98
-rw-r--r--Docs/Flags/belgium.gifbin0 -> 116 bytes
-rw-r--r--Docs/Flags/belgium.pdfbin0 -> 790 bytes
-rw-r--r--Docs/Flags/belgium.txt (renamed from Docs/Flags/island.eps)0
-rw-r--r--Docs/Flags/bulgaria.eps109
-rw-r--r--Docs/Flags/bulgaria.gifbin141 -> 141 bytes
-rw-r--r--Docs/Flags/bulgaria.pdfbin0 -> 821 bytes
-rw-r--r--Docs/Flags/canada.eps149
-rw-r--r--Docs/Flags/canada.gifbin407 -> 411 bytes
-rw-r--r--Docs/Flags/canada.pdfbin0 -> 1103 bytes
-rw-r--r--Docs/Flags/chile.eps115
-rw-r--r--Docs/Flags/chile.gifbin370 -> 256 bytes
-rw-r--r--Docs/Flags/chile.pdfbin0 -> 978 bytes
-rw-r--r--Docs/Flags/china.eps93
-rw-r--r--Docs/Flags/china.gifbin224 -> 227 bytes
-rw-r--r--Docs/Flags/china.pdfbin0 -> 945 bytes
-rw-r--r--Docs/Flags/costa-rica.eps98
-rw-r--r--Docs/Flags/costa-rica.gifbin0 -> 147 bytes
-rw-r--r--Docs/Flags/costa-rica.pdfbin0 -> 845 bytes
-rw-r--r--Docs/Flags/costa-rica.txt (renamed from Docs/Flags/island.gif)0
-rw-r--r--Docs/Flags/czech-republic.eps137
-rw-r--r--Docs/Flags/czech-republic.gifbin248 -> 180 bytes
-rw-r--r--Docs/Flags/czech-republic.pdfbin0 -> 936 bytes
-rw-r--r--Docs/Flags/denmark.eps149
-rw-r--r--Docs/Flags/denmark.gifbin253 -> 204 bytes
-rw-r--r--Docs/Flags/denmark.pdfbin0 -> 1011 bytes
-rw-r--r--Docs/Flags/estonia.eps103
-rw-r--r--Docs/Flags/estonia.gifbin126 -> 126 bytes
-rw-r--r--Docs/Flags/estonia.pdfbin0 -> 820 bytes
-rw-r--r--Docs/Flags/finland.eps149
-rw-r--r--Docs/Flags/finland.gifbin192 -> 131 bytes
-rw-r--r--Docs/Flags/finland.pdfbin0 -> 834 bytes
-rw-r--r--Docs/Flags/france.eps149
-rw-r--r--Docs/Flags/france.gifbin158 -> 146 bytes
-rw-r--r--Docs/Flags/france.pdfbin0 -> 796 bytes
-rw-r--r--Docs/Flags/germany.eps79
-rw-r--r--Docs/Flags/germany.gifbin126 -> 126 bytes
-rw-r--r--Docs/Flags/germany.pdfbin0 -> 804 bytes
-rw-r--r--Docs/Flags/great-britain.eps141
-rw-r--r--Docs/Flags/great-britain.gifbin1193 -> 511 bytes
-rw-r--r--Docs/Flags/great-britain.pdfbin0 -> 1348 bytes
-rw-r--r--Docs/Flags/greece.eps149
-rw-r--r--Docs/Flags/greece.gifbin282 -> 267 bytes
-rw-r--r--Docs/Flags/greece.pdfbin0 -> 1006 bytes
-rw-r--r--Docs/Flags/hungary.eps109
-rw-r--r--Docs/Flags/hungary.gifbin141 -> 141 bytes
-rw-r--r--Docs/Flags/hungary.pdfbin0 -> 822 bytes
-rw-r--r--Docs/Flags/iceland.eps141
-rw-r--r--Docs/Flags/iceland.gifbin197 -> 159 bytes
-rw-r--r--Docs/Flags/iceland.pdfbin0 -> 867 bytes
-rw-r--r--Docs/Flags/indonesia.eps98
-rw-r--r--Docs/Flags/indonesia.gifbin133 -> 113 bytes
-rw-r--r--Docs/Flags/indonesia.pdfbin0 -> 804 bytes
-rw-r--r--Docs/Flags/ireland.eps149
-rw-r--r--Docs/Flags/ireland.gifbin158 -> 146 bytes
-rw-r--r--Docs/Flags/ireland.pdfbin0 -> 794 bytes
-rw-r--r--Docs/Flags/italy.eps149
-rw-r--r--Docs/Flags/italy.gifbin158 -> 146 bytes
-rw-r--r--Docs/Flags/italy.pdfbin0 -> 794 bytes
-rw-r--r--Docs/Flags/japan.eps149
-rw-r--r--Docs/Flags/japan.gifbin357 -> 192 bytes
-rw-r--r--Docs/Flags/japan.pdfbin0 -> 971 bytes
-rw-r--r--Docs/Flags/latvia.eps137
-rw-r--r--Docs/Flags/latvia.gifbin117 -> 126 bytes
-rw-r--r--Docs/Flags/latvia.pdfbin0 -> 819 bytes
-rw-r--r--Docs/Flags/mexico.eps98
-rw-r--r--Docs/Flags/mexico.gifbin0 -> 615 bytes
-rw-r--r--Docs/Flags/mexico.pdfbin0 -> 1072 bytes
-rw-r--r--Docs/Flags/mexico.txt (renamed from Docs/Flags/island.txt)0
-rw-r--r--Docs/Flags/netherlands.eps143
-rw-r--r--Docs/Flags/netherlands.gifbin141 -> 141 bytes
-rw-r--r--Docs/Flags/netherlands.pdfbin0 -> 824 bytes
-rwxr-xr-xDocs/Flags/norway.eps98
-rwxr-xr-xDocs/Flags/norway.gifbin0 -> 159 bytes
-rw-r--r--Docs/Flags/norway.pdfbin0 -> 864 bytes
-rw-r--r--Docs/Flags/norway.txt (renamed from Docs/Flags/kroatia.eps)0
-rw-r--r--Docs/Flags/philippines.eps98
-rw-r--r--Docs/Flags/philippines.gifbin0 -> 620 bytes
-rw-r--r--Docs/Flags/philippines.pdfbin0 -> 1197 bytes
-rw-r--r--Docs/Flags/philippines.txt (renamed from Docs/Flags/kroatia.gif)0
-rw-r--r--Docs/Flags/poland.eps115
-rw-r--r--Docs/Flags/poland.gifbin132 -> 113 bytes
-rw-r--r--Docs/Flags/poland.pdfbin0 -> 809 bytes
-rw-r--r--Docs/Flags/portugal.eps147
-rw-r--r--Docs/Flags/portugal.gifbin633 -> 628 bytes
-rw-r--r--Docs/Flags/portugal.pdfbin0 -> 1189 bytes
-rw-r--r--Docs/Flags/romania.eps149
-rw-r--r--Docs/Flags/romania.gifbin158 -> 158 bytes
-rw-r--r--Docs/Flags/romania.pdfbin0 -> 798 bytes
-rw-r--r--Docs/Flags/russia.eps143
-rw-r--r--Docs/Flags/russia.gifbin141 -> 141 bytes
-rw-r--r--Docs/Flags/russia.pdfbin0 -> 829 bytes
-rw-r--r--Docs/Flags/singapore.eps149
-rw-r--r--Docs/Flags/singapore.gifbin389 -> 377 bytes
-rw-r--r--Docs/Flags/singapore.pdfbin0 -> 1056 bytes
-rwxr-xr-xDocs/Flags/slovenia.eps98
-rw-r--r--Docs/Flags/slovenia.gifbin0 -> 609 bytes
-rw-r--r--Docs/Flags/slovenia.pdfbin0 -> 1133 bytes
-rwxr-xr-x[-rw-r--r--]Docs/Flags/slovenia.txt (renamed from Docs/Flags/kroatia.txt)0
-rw-r--r--Docs/Flags/south-africa.eps141
-rw-r--r--Docs/Flags/south-africa.gifbin650 -> 415 bytes
-rw-r--r--Docs/Flags/south-africa.pdfbin0 -> 1151 bytes
-rw-r--r--Docs/Flags/south-africa1.eps87
-rw-r--r--Docs/Flags/south-africa1.gifbin650 -> 0 bytes
-rw-r--r--Docs/Flags/south-korea.eps149
-rw-r--r--Docs/Flags/south-korea.gifbin663 -> 669 bytes
-rw-r--r--Docs/Flags/south-korea.pdfbin0 -> 1444 bytes
-rw-r--r--Docs/Flags/spain.eps111
-rw-r--r--Docs/Flags/spain.gifbin138 -> 132 bytes
-rw-r--r--Docs/Flags/spain.pdfbin0 -> 809 bytes
-rw-r--r--Docs/Flags/sweden.eps145
-rw-r--r--Docs/Flags/sweden.gifbin193 -> 131 bytes
-rw-r--r--Docs/Flags/sweden.pdfbin0 -> 837 bytes
-rw-r--r--Docs/Flags/switzerland.eps121
-rw-r--r--Docs/Flags/switzerland.gifbin237 -> 135 bytes
-rw-r--r--Docs/Flags/switzerland.pdfbin0 -> 844 bytes
-rw-r--r--Docs/Flags/taiwan.eps115
-rw-r--r--Docs/Flags/taiwan.gifbin377 -> 371 bytes
-rw-r--r--Docs/Flags/taiwan.pdfbin0 -> 1050 bytes
-rw-r--r--Docs/Flags/turkey.eps98
-rw-r--r--Docs/Flags/turkey.gifbin0 -> 344 bytes
-rw-r--r--Docs/Flags/turkey.pdfbin0 -> 987 bytes
-rw-r--r--Docs/Flags/turkey.txt (renamed from Docs/Flags/south-africa1.txt)0
-rw-r--r--Docs/Flags/ukraine.eps133
-rw-r--r--Docs/Flags/ukraine.gifbin132 -> 113 bytes
-rw-r--r--Docs/Flags/ukraine.pdfbin0 -> 810 bytes
-rw-r--r--Docs/Flags/usa.eps145
-rw-r--r--Docs/Flags/usa.gifbin731 -> 717 bytes
-rw-r--r--Docs/Flags/usa.pdfbin0 -> 1444 bytes
-rw-r--r--Docs/Flags/yugoslavia.eps98
-rw-r--r--Docs/Flags/yugoslavia.gifbin250 -> 141 bytes
-rw-r--r--Docs/Flags/yugoslavia.pdfbin0 -> 829 bytes
-rw-r--r--Docs/Makefile.am124
-rwxr-xr-xDocs/Support/colspec-fix.pl52
-rwxr-xr-xDocs/Support/docbook-fixup.pl165
-rwxr-xr-xDocs/Support/docbook-split70
-rwxr-xr-xDocs/Support/generate-flag-images46
-rwxr-xr-xDocs/Support/make-docbook24
-rwxr-xr-xDocs/Support/test-make-manual-de137
-rwxr-xr-xDocs/Support/update-reserved-words.pl89
-rwxr-xr-xDocs/Support/xwf67
-rw-r--r--Docs/bk.txt3
-rw-r--r--Docs/internals.texi505
-rw-r--r--Docs/manual.de.texi56081
-rw-r--r--Docs/manual.ja.texi2
-rw-r--r--Docs/manual.texi19352
-rw-r--r--Docs/mirrors.texi410
-rw-r--r--Docs/my_sys.txt140
-rw-r--r--Docs/mysqld_error.txt458
-rw-r--r--Docs/section.Infolinks.texi880
-rw-r--r--Docs/section.Testimonials.texi31
-rw-r--r--Docs/section.Users.texi414
-rw-r--r--Docs/template.texi522
-rw-r--r--Docs/world.sql5386
-rw-r--r--Makefile.am27
-rw-r--r--SSL/NOTES376
-rw-r--r--SSL/cacert.pem21
-rw-r--r--SSL/client-cert.pem67
-rw-r--r--SSL/client-key.pem15
-rw-r--r--SSL/client-req.pem30
-rwxr-xr-xSSL/run-client10
-rwxr-xr-xSSL/run-server9
-rw-r--r--SSL/server-cert.pem67
-rw-r--r--SSL/server-key.pem15
-rw-r--r--SSL/server-req.pem30
-rw-r--r--VC++Files/InstallShield/Script Files/Setup.dbgbin0 -> 28458 bytes
-rw-r--r--VC++Files/InstallShield/Script Files/Setup.inobin0 -> 58611 bytes
-rw-r--r--VC++Files/InstallShield/Script Files/Setup.insbin0 -> 57122 bytes
-rw-r--r--VC++Files/InstallShield/Script Files/Setup.obsbin0 -> 65611 bytes
-rw-r--r--VC++Files/InstallShield/Script Files/Setup.rul640
-rw-r--r--VC++Files/client/mysql.dsp102
-rw-r--r--VC++Files/client/mysqladmin.dsp92
-rw-r--r--VC++Files/client/mysqlclient.dsp494
-rw-r--r--VC++Files/client/mysqlclient.dsw29
-rw-r--r--VC++Files/client/mysqldump.dsp102
-rw-r--r--VC++Files/client/mysqlimport.dsp93
-rw-r--r--VC++Files/client/mysqlshow.dsp92
-rw-r--r--VC++Files/dbug/dbug.dsp98
-rw-r--r--VC++Files/dbug/dbug.dsw29
-rw-r--r--VC++Files/heap/heap.dsp195
-rw-r--r--VC++Files/innobase/innobase.dsp441
-rw-r--r--VC++Files/isam/isam.dsp206
-rw-r--r--VC++Files/isam/isam.dsw29
-rw-r--r--VC++Files/isamchk/isamchk.dsp98
-rw-r--r--VC++Files/libmysql/libmySQL.dsp465
-rw-r--r--VC++Files/libmysql/libmysql.dsw29
-rw-r--r--VC++Files/libmysqltest/myTest.dsp92
-rw-r--r--VC++Files/libmysqltest/mytest.dsw29
-rw-r--r--VC++Files/merge/merge.dsp142
-rw-r--r--VC++Files/merge/merge.dsw29
-rw-r--r--VC++Files/myisam/myisam.dsp292
-rw-r--r--VC++Files/myisamchk/myisamchk.dsp104
-rw-r--r--VC++Files/myisamlog/myisamlog.dsp105
-rw-r--r--VC++Files/myisammrg/myisammrg.dsp173
-rw-r--r--VC++Files/myisampack/myisampack.dsp107
-rw-r--r--VC++Files/mysql.dsp80
-rw-r--r--VC++Files/mysql.dsw656
-rw-r--r--VC++Files/mysqlbinlog/mysqlbinlog.dsp103
-rw-r--r--VC++Files/mysqlcheck/mysqlcheck.dsp102
-rw-r--r--VC++Files/mysqlmanager/MySqlManager.dsp253
-rw-r--r--VC++Files/mysqlmanager/mysqlmanager.dsw29
-rw-r--r--VC++Files/mysqlshutdown/myshutdown.dsp101
-rw-r--r--VC++Files/mysqlshutdown/mysqlshutdown.dsp119
-rw-r--r--VC++Files/mysqlwatch/mysqlwatch.dsp70
-rw-r--r--VC++Files/mysys/mysys.dsp507
-rw-r--r--VC++Files/mysys/mysys.dsw29
-rw-r--r--VC++Files/pack_isam/pack_isam.dsp103
-rw-r--r--VC++Files/perror/perror.dsp109
-rw-r--r--VC++Files/regex/regex.dsp114
-rw-r--r--VC++Files/regex/regex.dsw29
-rw-r--r--VC++Files/replace/replace.dsp93
-rw-r--r--VC++Files/sql/mysqld.dsp1281
-rw-r--r--VC++Files/sql/mysqldmax.dsp1003
-rw-r--r--VC++Files/sql/old/mysqld.dsw29
-rw-r--r--VC++Files/strings/backup/strings.dsp244
-rw-r--r--VC++Files/strings/backup/strings.dsw29
-rw-r--r--VC++Files/strings/noMASM/strings.dsp246
-rw-r--r--VC++Files/strings/strings.dsp248
-rw-r--r--VC++Files/test1/test1.dsp102
-rw-r--r--VC++Files/thr_insert_test/thr_insert_test.dsp109
-rw-r--r--VC++Files/thr_test/thr_test.dsp104
-rw-r--r--VC++Files/vio/vio.dsp108
-rw-r--r--VC++Files/zlib/contrib/asm386/zlibvc.dsp651
-rw-r--r--VC++Files/zlib/contrib/asm386/zlibvc.dsw41
-rw-r--r--VC++Files/zlib/zlib.dsp186
-rw-r--r--acconfig.h15
-rw-r--r--acinclude.m4248
-rw-r--r--bdb/include/btree_ext.h122
-rw-r--r--bdb/include/clib_ext.h38
-rw-r--r--bdb/include/common_ext.h44
-rw-r--r--bdb/include/env_ext.h35
-rw-r--r--bdb/include/hash_ext.h106
-rw-r--r--bdb/include/lock_ext.h39
-rw-r--r--bdb/include/log_ext.h33
-rw-r--r--bdb/include/mp_ext.h33
-rw-r--r--bdb/include/os_ext.h62
-rw-r--r--bdb/include/qam_ext.h56
-rw-r--r--bdb/include/tcl_ext.h89
-rw-r--r--bdb/include/txn_ext.h24
-rw-r--r--bdb/include/xa_ext.h17
-rwxr-xr-xbuild-tags11
-rw-r--r--client/Makefile.am6
-rw-r--r--client/client_priv.h9
-rw-r--r--client/completion_hash.cc75
-rw-r--r--client/completion_hash.h33
-rw-r--r--client/connect_test.c29
-rw-r--r--client/errmsg.c53
-rw-r--r--client/get_password.c57
-rw-r--r--client/insert_test.c37
-rw-r--r--client/list_test.c42
-rw-r--r--client/my_readline.h29
-rw-r--r--client/mysql.cc340
-rw-r--r--client/mysqladmin.c26
-rw-r--r--client/mysqlbinlog.cc116
-rw-r--r--client/mysqlcheck.c12
-rw-r--r--client/mysqldump.c32
-rw-r--r--client/mysqlmanager-pwgen.c157
-rw-r--r--client/mysqlmanagerc.c178
-rw-r--r--client/mysqlshow.c14
-rw-r--r--client/mysqltest.c958
-rw-r--r--client/password.c31
-rw-r--r--client/readline.cc50
-rw-r--r--client/select_test.c28
-rw-r--r--client/showdb_test.c22
-rw-r--r--client/sql_string.cc31
-rw-r--r--client/sql_string.h29
-rw-r--r--client/ssl_test.c22
-rw-r--r--client/thimble.cc20
-rw-r--r--client/thread_test.c33
-rw-r--r--client/violite.c394
-rwxr-xr-xconfig.guess9
-rwxr-xr-xconfig.sub16
-rw-r--r--configure.in172
-rw-r--r--dbug/dbug.c4
-rw-r--r--dbug/dbug_analyze.c2
-rw-r--r--dbug/example1.c2
-rw-r--r--dbug/example2.c2
-rw-r--r--dbug/example3.c2
-rw-r--r--dbug/factorial.c2
-rw-r--r--dbug/main.c2
-rw-r--r--dbug/sanity.c2
-rw-r--r--div/deadlock_test.c16
-rw-r--r--extra/Makefile.am2
-rw-r--r--extra/comp_err.c31
-rw-r--r--extra/my_print_defaults.c33
-rw-r--r--extra/mysql_install.c196
-rw-r--r--extra/perror.c34
-rw-r--r--extra/replace.c31
-rw-r--r--extra/resolve_stack_dump.c50
-rw-r--r--fs/CorbaFS.idl38
-rw-r--r--fs/Makefile.am93
-rw-r--r--fs/README58
-rwxr-xr-xfs/RunServer.sh2
-rw-r--r--fs/database.c628
-rw-r--r--fs/dump.sql28
-rw-r--r--fs/korbit-kernel-2.4.1-patch35661
-rw-r--r--fs/libmysqlfs.c151
-rw-r--r--fs/libmysqlfs.h81
-rw-r--r--fs/my.cnf5
-rw-r--r--fs/mysqlcorbafs.c991
-rw-r--r--fs/mysqlcorbafs.h157
-rw-r--r--fs/mysqlcorbafs_test.c92
-rwxr-xr-xfs/mysqlfsck11
-rw-r--r--heap/_check.c12
-rw-r--r--heap/_rectest.c6
-rw-r--r--heap/heapdef.h7
-rw-r--r--heap/hp_block.c6
-rw-r--r--heap/hp_clear.c8
-rw-r--r--heap/hp_close.c12
-rw-r--r--heap/hp_create.c44
-rw-r--r--heap/hp_delete.c12
-rw-r--r--heap/hp_extra.c6
-rw-r--r--heap/hp_hash.c94
-rw-r--r--heap/hp_info.c6
-rw-r--r--heap/hp_open.c11
-rw-r--r--heap/hp_panic.c6
-rw-r--r--heap/hp_rename.c6
-rw-r--r--heap/hp_rfirst.c6
-rw-r--r--heap/hp_rkey.c8
-rw-r--r--heap/hp_rlast.c6
-rw-r--r--heap/hp_rnext.c8
-rw-r--r--heap/hp_rprev.c6
-rw-r--r--heap/hp_rrnd.c6
-rw-r--r--heap/hp_rsame.c6
-rw-r--r--heap/hp_scan.c6
-rw-r--r--heap/hp_static.c6
-rw-r--r--heap/hp_test1.c8
-rw-r--r--heap/hp_test2.c47
-rw-r--r--heap/hp_update.c6
-rw-r--r--heap/hp_write.c13
-rw-r--r--include/Makefile.am17
-rw-r--r--include/config-win.h36
-rw-r--r--include/dbug.h29
-rw-r--r--include/errmsg.h34
-rw-r--r--include/ft_global.h39
-rw-r--r--include/getopt.h16
-rw-r--r--include/hash.h30
-rw-r--r--include/heap.h36
-rw-r--r--include/m_ctype.h95
-rw-r--r--include/m_string.h32
-rw-r--r--include/md5.h (renamed from sql/md5.h)29
-rw-r--r--include/merge.h29
-rw-r--r--include/my_alarm.h29
-rw-r--r--include/my_base.h67
-rw-r--r--include/my_bitmap.h29
-rw-r--r--include/my_dir.h29
-rw-r--r--include/my_getopt.h53
-rw-r--r--include/my_global.h (renamed from include/global.h)125
-rw-r--r--include/my_list.h29
-rw-r--r--include/my_net.h84
-rw-r--r--include/my_no_pthread.h29
-rw-r--r--include/my_nosys.h29
-rw-r--r--include/my_pthread.h48
-rw-r--r--include/my_semaphore.h51
-rw-r--r--include/my_sys.h228
-rw-r--r--include/my_tree.h50
-rw-r--r--include/myisam.h122
-rw-r--r--include/myisammrg.h39
-rw-r--r--include/myisampack.h29
-rw-r--r--include/mysql.h291
-rw-r--r--include/mysql_com.h91
-rw-r--r--include/mysql_embed.h30
-rw-r--r--include/mysqld_error.h27
-rw-r--r--include/mysys_err.h29
-rw-r--r--include/nisam.h29
-rw-r--r--include/queues.h30
-rw-r--r--include/raid.h34
-rw-r--r--include/sslopt-case.h38
-rw-r--r--include/sslopt-longopts.h31
-rw-r--r--include/sslopt-usage.h32
-rw-r--r--include/sslopt-vars.h30
-rw-r--r--include/t_ctype.h20
-rw-r--r--include/thr_alarm.h49
-rw-r--r--include/thr_lock.h31
-rw-r--r--include/violite.h211
-rw-r--r--innobase/btr/btr0btr.c8
-rw-r--r--innobase/btr/btr0cur.c17
-rw-r--r--innobase/btr/btr0sea.c2
-rw-r--r--innobase/buf/buf0buf.c2
-rw-r--r--innobase/buf/buf0lru.c9
-rw-r--r--innobase/data/data0data.c2
-rw-r--r--innobase/dict/dict0boot.c109
-rw-r--r--innobase/dict/dict0crea.c20
-rw-r--r--innobase/dict/dict0dict.c35
-rw-r--r--innobase/dict/dict0load.c38
-rw-r--r--innobase/eval/eval0eval.c8
-rw-r--r--innobase/fil/fil0fil.c11
-rw-r--r--innobase/fsp/fsp0fsp.c8
-rw-r--r--innobase/ibuf/ibuf0ibuf.c20
-rw-r--r--innobase/include/Makefile.am2
-rw-r--r--innobase/include/Makefile.i2
-rw-r--r--innobase/include/btr0btr.ic6
-rw-r--r--innobase/include/buf0buf.ic7
-rw-r--r--innobase/include/dict0dict.ic2
-rw-r--r--innobase/include/dyn0dyn.h7
-rw-r--r--innobase/include/ha0ha.ic2
-rw-r--r--innobase/include/row0mysql.ic3
-rw-r--r--innobase/include/row0vers.ic2
-rw-r--r--innobase/include/srv0srv.h1
-rw-r--r--innobase/include/sync0rw.ic3
-rw-r--r--innobase/include/univ.i3
-rw-r--r--innobase/lock/lock0lock.c7
-rw-r--r--innobase/log/log0log.c17
-rw-r--r--innobase/mem/mem0dbg.c6
-rw-r--r--innobase/mtr/mtr0mtr.c8
-rw-r--r--innobase/odbc/odbc0odbc.c2
-rw-r--r--innobase/os/os0file.c33
-rw-r--r--innobase/os/os0thread.c6
-rw-r--r--innobase/page/page0cur.c9
-rw-r--r--innobase/page/page0page.c6
-rw-r--r--innobase/pars/pars0opt.c3
-rw-r--r--innobase/pars/pars0pars.c2
-rw-r--r--innobase/que/que0que.c46
-rw-r--r--innobase/rem/rem0cmp.c2
-rw-r--r--innobase/rem/rem0rec.c4
-rw-r--r--innobase/row/row0ins.c4
-rw-r--r--innobase/row/row0mysql.c97
-rw-r--r--innobase/row/row0purge.c2
-rw-r--r--innobase/row/row0sel.c21
-rw-r--r--innobase/row/row0uins.c2
-rw-r--r--innobase/row/row0umod.c2
-rw-r--r--innobase/row/row0upd.c2
-rw-r--r--innobase/srv/srv0srv.c68
-rw-r--r--innobase/srv/srv0start.c36
-rw-r--r--innobase/sync/sync0arr.c2
-rw-r--r--innobase/sync/sync0rw.c6
-rw-r--r--innobase/sync/sync0sync.c2
-rw-r--r--innobase/trx/trx0purge.c6
-rw-r--r--innobase/trx/trx0rec.c5
-rw-r--r--innobase/trx/trx0roll.c10
-rw-r--r--innobase/trx/trx0trx.c10
-rw-r--r--innobase/trx/trx0undo.c8
-rw-r--r--isam/_cache.c20
-rw-r--r--isam/_dbug.c6
-rw-r--r--isam/_dynrec.c26
-rw-r--r--isam/_key.c6
-rw-r--r--isam/_locking.c6
-rw-r--r--isam/_packrec.c12
-rw-r--r--isam/_page.c6
-rw-r--r--isam/_search.c6
-rw-r--r--isam/_statrec.c8
-rw-r--r--isam/changed.c6
-rw-r--r--isam/close.c6
-rw-r--r--isam/create.c14
-rw-r--r--isam/delete.c8
-rw-r--r--isam/extra.c7
-rw-r--r--isam/info.c6
-rw-r--r--isam/isamchk.c14
-rw-r--r--isam/isamdef.h6
-rw-r--r--isam/isamlog.c10
-rw-r--r--isam/log.c6
-rw-r--r--isam/open.c6
-rw-r--r--isam/pack_isam.c32
-rw-r--r--isam/panic.c6
-rw-r--r--isam/range.c6
-rw-r--r--isam/rfirst.c6
-rw-r--r--isam/rkey.c6
-rw-r--r--isam/rlast.c6
-rw-r--r--isam/rnext.c6
-rw-r--r--isam/rprev.c6
-rw-r--r--isam/rrnd.c6
-rw-r--r--isam/rsame.c6
-rw-r--r--isam/rsamepos.c6
-rw-r--r--isam/sort.c6
-rw-r--r--isam/static.c8
-rw-r--r--isam/test1.c8
-rw-r--r--isam/test2.c16
-rw-r--r--isam/test3.c10
-rw-r--r--isam/update.c6
-rw-r--r--isam/write.c8
-rw-r--r--libmysql/Makefile.am19
-rw-r--r--libmysql/Makefile.shared18
-rw-r--r--libmysql/conf_to_src.c29
-rw-r--r--libmysql/dll.c31
-rw-r--r--libmysql/errmsg.c54
-rw-r--r--libmysql/get_password.c31
-rw-r--r--libmysql/libmysql.c698
-rw-r--r--libmysql/libmysql.def122
-rw-r--r--libmysql/manager.c273
-rw-r--r--libmysql/net.c427
-rw-r--r--libmysql/password.c31
-rw-r--r--libmysql/violite.c443
-rw-r--r--libmysql_r/Makefile.am2
-rw-r--r--libmysqld/Makefile.am135
-rw-r--r--libmysqld/copyright14
-rw-r--r--libmysqld/embedded_priv.h32
-rw-r--r--libmysqld/examples/Makefile.am26
-rwxr-xr-xlibmysqld/examples/test-run138
-rw-r--r--libmysqld/lib_load.cc44
-rw-r--r--libmysqld/lib_sql.cc600
-rw-r--r--libmysqld/lib_vio.c215
-rw-r--r--libmysqld/libmysqld.c2091
-rw-r--r--libmysqld/libmysqld.def72
-rwxr-xr-xltconfig4
-rw-r--r--man/Makefile.am2
-rw-r--r--[-rwxr-xr-x]man/isamchk.12
-rw-r--r--man/isamlog.12
-rw-r--r--man/mysql.14
-rw-r--r--man/mysql_zap.12
-rw-r--r--[-rwxr-xr-x]man/mysqlaccess.12
-rw-r--r--[-rwxr-xr-x]man/mysqladmin.12
-rw-r--r--[-rwxr-xr-x]man/mysqld.14
-rw-r--r--man/mysqld_multi.14
-rw-r--r--[-rwxr-xr-x]man/mysqld_safe.1 (renamed from man/safe_mysqld.1)20
-rw-r--r--[-rwxr-xr-x]man/mysqldump.12
-rw-r--r--[-rwxr-xr-x]man/mysqlshow.12
-rw-r--r--[-rwxr-xr-x]man/perror.12
-rw-r--r--man/replace.12
-rw-r--r--man/which.22
-rw-r--r--merge/Makefile.am8
-rw-r--r--merge/mrg_close.c (renamed from merge/close.c)8
-rw-r--r--merge/mrg_create.c (renamed from merge/create.c)8
-rw-r--r--merge/mrg_def.h (renamed from merge/mrgdef.h)6
-rw-r--r--merge/mrg_delete.c (renamed from merge/delete.c)8
-rw-r--r--merge/mrg_extra.c (renamed from merge/extra.c)8
-rw-r--r--merge/mrg_info.c (renamed from merge/info.c)8
-rw-r--r--merge/mrg_locking.c (renamed from merge/_locking.c)8
-rw-r--r--merge/mrg_open.c (renamed from merge/open.c)16
-rw-r--r--merge/mrg_panic.c (renamed from merge/panic.c)8
-rw-r--r--merge/mrg_rrnd.c (renamed from merge/rrnd.c)8
-rw-r--r--merge/mrg_rsame.c (renamed from merge/rsame.c)8
-rw-r--r--merge/mrg_static.c (renamed from merge/static.c)8
-rw-r--r--merge/mrg_update.c (renamed from merge/update.c)8
-rw-r--r--myisam/Makefile.am19
-rw-r--r--myisam/ft_boolean_search.c494
-rw-r--r--myisam/ft_dump.c233
-rw-r--r--myisam/ft_eval.c10
-rw-r--r--myisam/ft_eval.h7
-rw-r--r--myisam/ft_nlq_search.c (renamed from myisam/ft_search.c)127
-rw-r--r--myisam/ft_parser.c152
-rw-r--r--myisam/ft_static.c32
-rw-r--r--myisam/ft_stem.c7
-rw-r--r--myisam/ft_stopwords.c15
-rw-r--r--myisam/ft_test1.c10
-rw-r--r--myisam/ft_test1.h7
-rw-r--r--myisam/ft_update.c211
-rw-r--r--myisam/ftdefs.h73
-rw-r--r--myisam/fulltext.h1
-rw-r--r--myisam/mi_cache.c26
-rw-r--r--myisam/mi_changed.c8
-rw-r--r--myisam/mi_check.c252
-rw-r--r--myisam/mi_checksum.c6
-rw-r--r--myisam/mi_close.c6
-rw-r--r--myisam/mi_create.c111
-rw-r--r--myisam/mi_dbug.c8
-rw-r--r--myisam/mi_delete.c15
-rw-r--r--myisam/mi_delete_all.c13
-rw-r--r--myisam/mi_delete_table.c10
-rw-r--r--myisam/mi_dynrec.c92
-rw-r--r--myisam/mi_extra.c46
-rw-r--r--myisam/mi_info.c10
-rw-r--r--myisam/mi_key.c36
-rw-r--r--myisam/mi_locking.c34
-rw-r--r--myisam/mi_log.c6
-rw-r--r--myisam/mi_open.c102
-rw-r--r--myisam/mi_packrec.c12
-rw-r--r--myisam/mi_page.c10
-rw-r--r--myisam/mi_panic.c6
-rw-r--r--myisam/mi_range.c22
-rw-r--r--myisam/mi_rename.c10
-rw-r--r--myisam/mi_rfirst.c6
-rw-r--r--myisam/mi_rkey.c12
-rw-r--r--myisam/mi_rlast.c6
-rw-r--r--myisam/mi_rnext.c4
-rw-r--r--myisam/mi_rnext_same.c8
-rw-r--r--myisam/mi_rprev.c4
-rw-r--r--myisam/mi_rrnd.c6
-rw-r--r--myisam/mi_rsame.c11
-rw-r--r--myisam/mi_rsamepos.c6
-rw-r--r--myisam/mi_scan.c6
-rw-r--r--myisam/mi_search.c1253
-rw-r--r--myisam/mi_static.c12
-rw-r--r--myisam/mi_statrec.c63
-rw-r--r--myisam/mi_test1.c8
-rw-r--r--myisam/mi_test2.c158
-rw-r--r--myisam/mi_test3.c6
-rw-r--r--myisam/mi_test_all.res90
-rwxr-xr-xmyisam/mi_test_all.sh20
-rw-r--r--myisam/mi_unique.c6
-rw-r--r--myisam/mi_update.c16
-rw-r--r--myisam/mi_write.c256
-rw-r--r--myisam/myisamchk.c580
-rw-r--r--myisam/myisamdef.h126
-rw-r--r--myisam/myisamlog.c15
-rw-r--r--myisam/myisampack.c44
-rw-r--r--myisam/sort.c166
-rw-r--r--myisammrg/Makefile.am4
-rw-r--r--myisammrg/myrg_close.c8
-rw-r--r--myisammrg/myrg_create.c18
-rw-r--r--myisammrg/myrg_def.h (renamed from myisammrg/mymrgdef.h)6
-rw-r--r--myisammrg/myrg_delete.c8
-rw-r--r--myisammrg/myrg_extra.c13
-rw-r--r--myisammrg/myrg_info.c2
-rw-r--r--myisammrg/myrg_locking.c8
-rw-r--r--myisammrg/myrg_open.c60
-rw-r--r--myisammrg/myrg_panic.c8
-rw-r--r--myisammrg/myrg_queue.c2
-rw-r--r--myisammrg/myrg_rfirst.c2
-rw-r--r--myisammrg/myrg_rkey.c2
-rw-r--r--myisammrg/myrg_rlast.c2
-rw-r--r--myisammrg/myrg_rnext.c2
-rw-r--r--myisammrg/myrg_rprev.c2
-rw-r--r--myisammrg/myrg_rrnd.c2
-rw-r--r--myisammrg/myrg_rsame.c8
-rw-r--r--myisammrg/myrg_static.c12
-rw-r--r--myisammrg/myrg_update.c8
-rw-r--r--myisammrg/myrg_write.c30
-rw-r--r--mysql-test/Makefile.am2
-rwxr-xr-xmysql-test/create-test-result4
-rwxr-xr-xmysql-test/fix-result22
-rw-r--r--mysql-test/include/have_bdb.inc2
-rw-r--r--mysql-test/include/have_gemini.inc2
-rw-r--r--mysql-test/include/have_innodb.inc2
-rw-r--r--mysql-test/include/have_isam.inc2
-rw-r--r--mysql-test/include/have_openssl.inc4
-rw-r--r--mysql-test/include/have_openssl_1.inc4
-rw-r--r--mysql-test/include/have_openssl_2.inc4
-rw-r--r--mysql-test/include/master-slave.inc9
-rw-r--r--mysql-test/include/not_embedded.inc5
-rw-r--r--mysql-test/install_test_db.sh28
-rw-r--r--mysql-test/mysql-test-run.sh840
-rw-r--r--mysql-test/r/alias.result59
-rw-r--r--mysql-test/r/alter_table.result82
-rw-r--r--mysql-test/r/analyse.result7
-rw-r--r--mysql-test/r/auto_increment.result59
-rw-r--r--mysql-test/r/backup.result30
-rw-r--r--mysql-test/r/bdb-crash.result29
-rw-r--r--mysql-test/r/bdb-deadlock.result21
-rw-r--r--mysql-test/r/bdb.result621
-rw-r--r--mysql-test/r/bench_count_distinct.result4
-rw-r--r--mysql-test/r/big_test.require2
-rw-r--r--mysql-test/r/bigint.result63
-rw-r--r--mysql-test/r/binary.result22
-rw-r--r--mysql-test/r/bulk_replace.result11
-rw-r--r--mysql-test/r/case.result23
-rw-r--r--mysql-test/r/check.result5
-rw-r--r--mysql-test/r/comments.result13
-rw-r--r--mysql-test/r/compare.result8
-rw-r--r--mysql-test/r/count_distinct.result35
-rw-r--r--mysql-test/r/count_distinct2.result129
-rw-r--r--mysql-test/r/create.result85
-rw-r--r--mysql-test/r/ctype_latin1_de.result207
-rw-r--r--mysql-test/r/delayed.result20
-rw-r--r--mysql-test/r/delete.result26
-rw-r--r--mysql-test/r/dirty-close.result4
-rw-r--r--mysql-test/r/dirty_close.result9
-rw-r--r--mysql-test/r/distinct.result178
-rw-r--r--mysql-test/r/drop.result39
-rw-r--r--mysql-test/r/empty_table.result6
-rw-r--r--mysql-test/r/err000001.result25
-rw-r--r--mysql-test/r/explain.result17
-rw-r--r--mysql-test/r/flush.result29
-rw-r--r--mysql-test/r/foreign_key.result15
-rw-r--r--mysql-test/r/fulltext.result145
-rw-r--r--mysql-test/r/fulltext_cache.result54
-rw-r--r--mysql-test/r/fulltext_distinct.result43
-rw-r--r--mysql-test/r/fulltext_left_join.result29
-rw-r--r--mysql-test/r/fulltext_multi.result26
-rw-r--r--mysql-test/r/fulltext_order_by.result65
-rw-r--r--mysql-test/r/fulltext_update.result20
-rw-r--r--mysql-test/r/fulltext_var.result6
-rw-r--r--mysql-test/r/func_crypt.result4
-rw-r--r--mysql-test/r/func_date_add.result35
-rw-r--r--mysql-test/r/func_encrypt.result136
-rw-r--r--mysql-test/r/func_equal.result14
-rw-r--r--mysql-test/r/func_group.result74
-rw-r--r--mysql-test/r/func_in.result13
-rw-r--r--mysql-test/r/func_like.result11
-rw-r--r--mysql-test/r/func_math.result13
-rw-r--r--mysql-test/r/func_misc.result4
-rw-r--r--mysql-test/r/func_op.result5
-rw-r--r--mysql-test/r/func_regexp.result29
-rw-r--r--mysql-test/r/func_set.result9
-rw-r--r--mysql-test/r/func_str.result84
-rw-r--r--mysql-test/r/func_system.result6
-rw-r--r--mysql-test/r/func_test.result23
-rw-r--r--mysql-test/r/func_time.result160
-rw-r--r--mysql-test/r/func_timestamp.result8
-rw-r--r--mysql-test/r/gcc296.result15
-rw-r--r--mysql-test/r/gemini.result370
-rw-r--r--mysql-test/r/grant_cache.result153
-rw-r--r--mysql-test/r/group_by.result313
-rw-r--r--mysql-test/r/handler.result139
-rw-r--r--mysql-test/r/have_openssl.require2
-rw-r--r--mysql-test/r/have_openssl_1.require2
-rw-r--r--mysql-test/r/have_openssl_2.require (renamed from mysql-test/r/have_gemini.require)2
-rw-r--r--mysql-test/r/have_symlink.require2
-rw-r--r--mysql-test/r/having.result59
-rw-r--r--mysql-test/r/heap.result122
-rw-r--r--mysql-test/r/identity.result2
-rw-r--r--mysql-test/r/innodb.result520
-rw-r--r--mysql-test/r/innodb_cache.result15
-rw-r--r--mysql-test/r/ins000001.result9
-rw-r--r--mysql-test/r/insert.result15
-rw-r--r--mysql-test/r/insert_select.result55
-rw-r--r--mysql-test/r/isam.result73
-rw-r--r--mysql-test/r/isolation.result61
-rw-r--r--mysql-test/r/join.result174
-rw-r--r--mysql-test/r/join_crash.result109
-rw-r--r--mysql-test/r/join_outer.result321
-rw-r--r--mysql-test/r/key.result130
-rw-r--r--mysql-test/r/key_diff.result13
-rw-r--r--mysql-test/r/key_primary.result10
-rw-r--r--mysql-test/r/keywords.result12
-rw-r--r--mysql-test/r/kill.result7
-rw-r--r--mysql-test/r/limit.result27
-rw-r--r--mysql-test/r/lock.result43
-rw-r--r--mysql-test/r/lock_multi.result18
-rw-r--r--mysql-test/r/merge.result332
-rw-r--r--mysql-test/r/multi_update.result41
-rw-r--r--mysql-test/r/myisam.result51
-rw-r--r--mysql-test/r/not_embedded.require2
-rw-r--r--mysql-test/r/null.result26
-rw-r--r--mysql-test/r/null_key.result71
-rw-r--r--mysql-test/r/odbc.result8
-rw-r--r--mysql-test/r/openssl_1.result2
-rw-r--r--mysql-test/r/openssl_2.result2
-rw-r--r--mysql-test/r/order_by.result329
-rw-r--r--mysql-test/r/order_fill_sortbuf.result10
-rw-r--r--mysql-test/r/overflow.result2
-rw-r--r--mysql-test/r/query_cache.result492
-rw-r--r--mysql-test/r/raid.result188
-rw-r--r--mysql-test/r/range.result84
-rw-r--r--mysql-test/r/rename.result25
-rw-r--r--mysql-test/r/replace.result23
-rw-r--r--mysql-test/r/rollback.result9
-rw-r--r--mysql-test/r/rpl000001.result82
-rw-r--r--mysql-test/r/rpl000002.result25
-rw-r--r--mysql-test/r/rpl000003.result12
-rw-r--r--mysql-test/r/rpl000004.result28
-rw-r--r--mysql-test/r/rpl000005.result14
-rw-r--r--mysql-test/r/rpl000006.result24
-rw-r--r--mysql-test/r/rpl000007.result19
-rw-r--r--mysql-test/r/rpl000008.result22
-rw-r--r--mysql-test/r/rpl000009.result80
-rw-r--r--mysql-test/r/rpl000010.result12
-rw-r--r--mysql-test/r/rpl000011.result14
-rw-r--r--mysql-test/r/rpl000012.result25
-rw-r--r--mysql-test/r/rpl000013.result17
-rw-r--r--mysql-test/r/rpl000014.result43
-rw-r--r--mysql-test/r/rpl000015.result34
-rw-r--r--mysql-test/r/rpl000016.result58
-rw-r--r--mysql-test/r/rpl000017.result9
-rw-r--r--mysql-test/r/rpl000018.result8
-rw-r--r--mysql-test/r/rpl_compat.result77
-rw-r--r--mysql-test/r/rpl_failsafe.result33
-rw-r--r--mysql-test/r/rpl_get_lock.result12
-rw-r--r--mysql-test/r/rpl_log.result98
-rw-r--r--mysql-test/r/rpl_magic.result36
-rw-r--r--mysql-test/r/rpl_mystery22.result19
-rw-r--r--mysql-test/r/rpl_skip_error.result11
-rw-r--r--mysql-test/r/rpl_sporadic_master.result19
-rw-r--r--mysql-test/r/sel000001.result5
-rw-r--r--mysql-test/r/sel000002.result5
-rw-r--r--mysql-test/r/sel000003.result5
-rw-r--r--mysql-test/r/sel000031.result8
-rw-r--r--mysql-test/r/sel000032.result8
-rw-r--r--mysql-test/r/sel000033.result6
-rw-r--r--mysql-test/r/sel000100.result26
-rw-r--r--mysql-test/r/select.result1453
-rw-r--r--mysql-test/r/select_found.result70
-rw-r--r--mysql-test/r/select_safe.result29
-rw-r--r--mysql-test/r/show_check.result133
-rw-r--r--mysql-test/r/slave-running.result1
-rw-r--r--mysql-test/r/slave-stopped.result1
-rw-r--r--mysql-test/r/status.result13
-rw-r--r--mysql-test/r/symlink.result65
-rw-r--r--mysql-test/r/tablelock.result36
-rw-r--r--mysql-test/r/temp_table.result44
-rw-r--r--mysql-test/r/truncate.result12
-rw-r--r--mysql-test/r/type_blob.result187
-rw-r--r--mysql-test/r/type_date.result49
-rw-r--r--mysql-test/r/type_datetime.result24
-rw-r--r--mysql-test/r/type_decimal.result147
-rw-r--r--mysql-test/r/type_enum.result8
-rw-r--r--mysql-test/r/type_float.result33
-rw-r--r--mysql-test/r/type_ranges.result154
-rw-r--r--mysql-test/r/type_time.result12
-rw-r--r--mysql-test/r/type_timestamp.result34
-rw-r--r--mysql-test/r/type_uint.result6
-rw-r--r--mysql-test/r/type_year.result6
-rw-r--r--mysql-test/r/union.result159
-rw-r--r--mysql-test/r/update.result73
-rw-r--r--mysql-test/r/user_var.result16
-rw-r--r--mysql-test/r/varbinary.result21
-rw-r--r--mysql-test/r/variables.result21
-rw-r--r--mysql-test/r/warnings.result9
-rwxr-xr-xmysql-test/resolve-stack8
-rw-r--r--mysql-test/std_data/des_key_file4
-rw-r--r--mysql-test/std_data/gemini.dat5
-rw-r--r--mysql-test/std_data/master-bin.001bin113 -> 98 bytes
-rw-r--r--mysql-test/t/alter_table.test29
-rw-r--r--mysql-test/t/analyse.test1
-rw-r--r--mysql-test/t/auto_increment.test15
-rw-r--r--mysql-test/t/backup.test6
-rw-r--r--mysql-test/t/bdb-crash.test1
-rw-r--r--mysql-test/t/bdb.test16
-rw-r--r--mysql-test/t/bench_count_distinct.test3
-rw-r--r--mysql-test/t/bigint.test23
-rw-r--r--mysql-test/t/bulk_replace.test14
-rw-r--r--mysql-test/t/check.test5
-rw-r--r--mysql-test/t/count_distinct2-master.opt1
-rw-r--r--mysql-test/t/count_distinct2.test79
-rw-r--r--mysql-test/t/create.test20
-rw-r--r--mysql-test/t/ctype_latin1_de-master.opt1
-rw-r--r--mysql-test/t/ctype_latin1_de.test46
-rw-r--r--mysql-test/t/dirty_close.test (renamed from mysql-test/t/dirty-close.test)0
-rw-r--r--mysql-test/t/distinct.test11
-rw-r--r--mysql-test/t/drop.test44
-rw-r--r--mysql-test/t/flush.test32
-rw-r--r--mysql-test/t/fulltext.test68
-rw-r--r--mysql-test/t/fulltext_cache.test14
-rw-r--r--mysql-test/t/fulltext_distinct.test41
-rw-r--r--mysql-test/t/fulltext_left_join.test2
-rw-r--r--mysql-test/t/fulltext_order_by.test7
-rw-r--r--mysql-test/t/fulltext_var.test5
-rw-r--r--mysql-test/t/func_crypt.test3
-rw-r--r--mysql-test/t/func_encrypt-master.opt1
-rw-r--r--mysql-test/t/func_encrypt.test67
-rw-r--r--mysql-test/t/func_like.test2
-rw-r--r--mysql-test/t/func_str.test6
-rw-r--r--mysql-test/t/func_system.test2
-rw-r--r--mysql-test/t/func_time.test12
-rw-r--r--mysql-test/t/gemini.test355
-rw-r--r--mysql-test/t/grant_cache-master.opt1
-rw-r--r--mysql-test/t/grant_cache.test102
-rw-r--r--mysql-test/t/group_by.test40
-rw-r--r--mysql-test/t/handler.test67
-rw-r--r--mysql-test/t/having.test12
-rw-r--r--mysql-test/t/heap.test38
-rw-r--r--mysql-test/t/innodb.test105
-rw-r--r--mysql-test/t/innodb_cache-master.opt1
-rw-r--r--mysql-test/t/innodb_cache.test14
-rw-r--r--mysql-test/t/insert.test12
-rw-r--r--mysql-test/t/insert_select.test58
-rw-r--r--mysql-test/t/isam.test59
-rw-r--r--mysql-test/t/isolation.test208
-rw-r--r--mysql-test/t/join.test2
-rw-r--r--mysql-test/t/key.test8
-rw-r--r--mysql-test/t/keywords.test4
-rw-r--r--mysql-test/t/kill.test8
-rw-r--r--mysql-test/t/limit.test2
-rw-r--r--mysql-test/t/lock.test42
-rw-r--r--mysql-test/t/lock_multi.test49
-rw-r--r--mysql-test/t/merge.test58
-rw-r--r--mysql-test/t/multi_update.test53
-rw-r--r--mysql-test/t/myisam.test2
-rw-r--r--mysql-test/t/null.test1
-rw-r--r--mysql-test/t/openssl_1.test6
-rw-r--r--mysql-test/t/openssl_2.test5
-rw-r--r--mysql-test/t/order_by.test49
-rw-r--r--mysql-test/t/order_fill_sortbuf-master.opt1
-rw-r--r--mysql-test/t/order_fill_sortbuf.test21
-rw-r--r--mysql-test/t/query_cache-master.opt1
-rw-r--r--mysql-test/t/query_cache.test336
-rw-r--r--mysql-test/t/rename.test16
-rw-r--r--mysql-test/t/rpl000001.test31
-rw-r--r--mysql-test/t/rpl000002.test2
-rw-r--r--mysql-test/t/rpl000009.test53
-rw-r--r--mysql-test/t/rpl000014.test10
-rw-r--r--mysql-test/t/rpl000015.test14
-rw-r--r--mysql-test/t/rpl000016-slave.opt1
-rwxr-xr-xmysql-test/t/rpl000016-slave.sh1
-rw-r--r--mysql-test/t/rpl000016.test17
-rwxr-xr-xmysql-test/t/rpl000017-slave.sh3
-rw-r--r--mysql-test/t/rpl000017.test4
-rwxr-xr-xmysql-test/t/rpl000018-master.sh3
-rw-r--r--mysql-test/t/rpl000018.test7
-rw-r--r--mysql-test/t/rpl_compat.test86
-rw-r--r--mysql-test/t/rpl_failsafe.test24
-rw-r--r--mysql-test/t/rpl_get_lock.test3
-rw-r--r--mysql-test/t/rpl_log.test57
-rw-r--r--mysql-test/t/rpl_magic.test31
-rw-r--r--mysql-test/t/rpl_mystery22.test1
-rw-r--r--mysql-test/t/rpl_sporadic_master.test8
-rw-r--r--mysql-test/t/select.test6
-rw-r--r--mysql-test/t/select_found.test34
-rw-r--r--mysql-test/t/show_check.test42
-rw-r--r--mysql-test/t/status.test10
-rw-r--r--mysql-test/t/symlink.test89
-rw-r--r--mysql-test/t/tablelock.test7
-rw-r--r--mysql-test/t/truncate.test6
-rw-r--r--mysql-test/t/type_datetime.test9
-rw-r--r--mysql-test/t/type_enum.test1
-rw-r--r--mysql-test/t/union.test79
-rw-r--r--mysql-test/t/update.test11
-rw-r--r--mysql-test/t/varbinary.test16
-rw-r--r--mysql-test/xml/README74
-rw-r--r--mysql-test/xml/tests/sel000001.xml21
-rw-r--r--mysql-test/xml/tests/sel000002.xml20
-rw-r--r--mysql-test/xml/tests/sel000003.xml21
-rw-r--r--mysql-test/xml/tests/sel000004.xml17
-rw-r--r--mysql-test/xml/tests/sel000005.xml17
-rw-r--r--mysql-test/xml/tests/sel000006.xml17
-rw-r--r--mysql-test/xml/tests/sel000007.xml17
-rw-r--r--mysql-test/xml/tests/sel000008.xml17
-rw-r--r--mysql-test/xml/tests/sel000009.xml17
-rw-r--r--mysql-test/xml/tests/sel000010.xml17
-rw-r--r--mysql-test/xml/tests/sel000011.xml17
-rw-r--r--mysql-test/xml/tests/sel000012.xml16
-rw-r--r--mysql-test/xml/tests/sel000013.xml16
-rw-r--r--mysql-test/xml/tests/sel000014.xml17
-rw-r--r--mysql-test/xml/tests/sel000015.xml17
-rw-r--r--mysql-test/xml/tests/sel000016.xml17
-rw-r--r--mysql-test/xml/tests/sel000017.xml17
-rw-r--r--mysql-test/xml/tests/sel000018.xml17
-rw-r--r--mysql-test/xml/tests/sel000019.xml17
-rw-r--r--mysql-test/xml/tests/sel000020.xml17
-rw-r--r--mysql-test/xml/tests/sel000021.xml17
-rw-r--r--mysql-test/xml/tests/sel000022.xml17
-rw-r--r--mysql-test/xml/tests/sel000023.xml17
-rw-r--r--mysql-test/xml/tests/sel000024.xml17
-rw-r--r--mysql-test/xml/tests/sel000025.xml17
-rw-r--r--mysql-test/xml/tests/sel000026.xml17
-rw-r--r--mysql-test/xml/tests/sel000027.xml17
-rw-r--r--mysql-test/xml/tests/sel000028.xml17
-rw-r--r--mysql-test/xml/tests/sel000029.xml17
-rw-r--r--mysql-test/xml/tests/sel000030.xml17
-rw-r--r--mysql-test/xml/xsl/README4
-rw-r--r--mysql-test/xml/xsl/mysqltest.xsl59
-rw-r--r--mysys/Makefile.am12
-rw-r--r--mysys/array.c32
-rw-r--r--mysys/charset.c85
-rw-r--r--mysys/checksum.c31
-rw-r--r--mysys/default.c50
-rw-r--r--mysys/errors.c29
-rw-r--r--mysys/getopt.c4
-rw-r--r--mysys/getopt1.c2
-rw-r--r--mysys/getvar.c31
-rw-r--r--mysys/hash.c49
-rw-r--r--mysys/list.c29
-rw-r--r--mysys/make-conf.c31
-rw-r--r--mysys/md5.c (renamed from sql/md5.c)34
-rw-r--r--mysys/mf_brkhant.c29
-rw-r--r--mysys/mf_cache.c23
-rw-r--r--mysys/mf_casecnv.c37
-rw-r--r--mysys/mf_dirname.c114
-rw-r--r--mysys/mf_fn_ext.c29
-rw-r--r--mysys/mf_format.c128
-rw-r--r--mysys/mf_getdate.c29
-rw-r--r--mysys/mf_iocache.c768
-rw-r--r--mysys/mf_iocache2.c134
-rw-r--r--mysys/mf_keycache.c109
-rw-r--r--mysys/mf_loadpath.c32
-rw-r--r--mysys/mf_pack.c36
-rw-r--r--mysys/mf_pack2.c53
-rw-r--r--mysys/mf_path.c29
-rw-r--r--mysys/mf_qsort2.c29
-rw-r--r--mysys/mf_radix.c29
-rw-r--r--mysys/mf_same.c29
-rw-r--r--mysys/mf_sleep.c29
-rw-r--r--mysys/mf_sort.c31
-rw-r--r--mysys/mf_soundex.c29
-rw-r--r--mysys/mf_stripp.c29
-rw-r--r--mysys/mf_tempfile.c41
-rw-r--r--mysys/mf_unixpath.c29
-rw-r--r--mysys/mf_util.c29
-rw-r--r--mysys/mf_wcomp.c29
-rw-r--r--mysys/mf_wfile.c29
-rw-r--r--mysys/mulalloc.c29
-rw-r--r--mysys/my_alarm.c29
-rw-r--r--mysys/my_alloc.c113
-rw-r--r--mysys/my_append.c29
-rw-r--r--mysys/my_bit.c31
-rw-r--r--mysys/my_bitmap.c33
-rw-r--r--mysys/my_chsize.c29
-rw-r--r--mysys/my_clock.c31
-rw-r--r--mysys/my_compress.c35
-rw-r--r--mysys/my_copy.c29
-rw-r--r--mysys/my_create.c29
-rw-r--r--mysys/my_delete.c30
-rw-r--r--mysys/my_div.c29
-rw-r--r--mysys/my_dup.c39
-rw-r--r--mysys/my_error.c29
-rw-r--r--mysys/my_fopen.c29
-rw-r--r--mysys/my_fstream.c34
-rw-r--r--mysys/my_getopt.c577
-rw-r--r--mysys/my_getwd.c29
-rw-r--r--mysys/my_init.c33
-rw-r--r--mysys/my_lib.c40
-rw-r--r--mysys/my_lock.c29
-rw-r--r--mysys/my_lockmem.c29
-rw-r--r--mysys/my_lread.c29
-rw-r--r--mysys/my_lwrite.c29
-rw-r--r--mysys/my_malloc.c29
-rw-r--r--mysys/my_messnc.c29
-rw-r--r--mysys/my_mkdir.c29
-rw-r--r--mysys/my_net.c29
-rw-r--r--mysys/my_once.c29
-rw-r--r--mysys/my_open.c29
-rw-r--r--mysys/my_pread.c29
-rw-r--r--mysys/my_pthread.c71
-rw-r--r--mysys/my_quick.c29
-rw-r--r--mysys/my_read.c43
-rw-r--r--mysys/my_realloc.c29
-rw-r--r--mysys/my_redel.c29
-rw-r--r--mysys/my_rename.c29
-rw-r--r--mysys/my_seek.c38
-rw-r--r--mysys/my_static.c36
-rw-r--r--mysys/my_static.h29
-rw-r--r--mysys/my_symlink.c29
-rw-r--r--mysys/my_symlink2.c50
-rw-r--r--mysys/my_tempnam.c23
-rw-r--r--mysys/my_thr_init.c29
-rw-r--r--mysys/my_vsnprintf.c58
-rw-r--r--mysys/my_wincond.c29
-rw-r--r--mysys/my_winsem.c406
-rw-r--r--mysys/my_winthread.c29
-rw-r--r--mysys/my_write.c29
-rw-r--r--mysys/mysys_priv.h31
-rw-r--r--mysys/ptr_cmp.c32
-rw-r--r--mysys/queues.c49
-rw-r--r--mysys/raid.cc155
-rw-r--r--mysys/safemalloc.c29
-rw-r--r--mysys/string.c31
-rw-r--r--mysys/test_charset.c33
-rw-r--r--mysys/test_dir.c29
-rw-r--r--mysys/test_fn.c29
-rw-r--r--mysys/testhash.c31
-rw-r--r--mysys/thr_alarm.c36
-rw-r--r--mysys/thr_lock.c29
-rw-r--r--mysys/thr_mutex.c44
-rw-r--r--mysys/thr_rwlock.c29
-rw-r--r--mysys/tree.c108
-rw-r--r--mysys/typelib.c32
-rw-r--r--pstack/Makefile.am36
-rw-r--r--pstack/aout/Makefile.am1
-rw-r--r--pstack/aout/aout64.h475
-rw-r--r--pstack/aout/stab.def264
-rw-r--r--pstack/aout/stab_gnu.h37
-rw-r--r--pstack/bucomm.c238
-rw-r--r--pstack/bucomm.h85
-rw-r--r--pstack/budbg.h58
-rw-r--r--pstack/debug.c3509
-rw-r--r--pstack/debug.h798
-rw-r--r--pstack/demangle.h90
-rw-r--r--pstack/filemode.c266
-rw-r--r--pstack/ieee.c7602
-rw-r--r--pstack/ieee.h138
-rw-r--r--pstack/libiberty.h180
-rw-r--r--pstack/linuxthreads.c90
-rw-r--r--pstack/linuxthreads.h28
-rw-r--r--pstack/pstack.c2745
-rw-r--r--pstack/pstack.h22
-rw-r--r--pstack/pstacktrace.h24
-rw-r--r--pstack/rddbg.c462
-rw-r--r--pstack/stabs.c5082
-rw-r--r--readline/bind.c65
-rw-r--r--readline/callback.c1
-rw-r--r--readline/complete.c33
-rw-r--r--readline/display.c20
-rw-r--r--readline/funmap.c12
-rw-r--r--readline/histexpand.c15
-rw-r--r--readline/histfile.c8
-rw-r--r--readline/history.c2
-rw-r--r--readline/history.h6
-rw-r--r--readline/histsearch.c2
-rw-r--r--readline/input.c2
-rw-r--r--readline/isearch.c6
-rw-r--r--readline/kill.c34
-rw-r--r--readline/macro.c19
-rw-r--r--readline/readline.c63
-rw-r--r--readline/readline.h38
-rw-r--r--readline/rlstdc.h4
-rw-r--r--readline/rltty.c11
-rw-r--r--readline/search.c20
-rw-r--r--readline/shell.c1
-rw-r--r--readline/terminal.c21
-rw-r--r--readline/tilde.c12
-rw-r--r--readline/tilde.h4
-rw-r--r--readline/undo.c9
-rw-r--r--readline/util.c14
-rw-r--r--readline/vi_mode.c72
-rw-r--r--regex/cclass.h6
-rw-r--r--regex/cname.h4
-rw-r--r--regex/debug.c2
-rw-r--r--regex/main.c18
-rw-r--r--regex/regcomp.c74
-rw-r--r--regex/regcomp.ih2
-rw-r--r--regex/regerror.c10
-rw-r--r--regex/regexec.c2
-rw-r--r--regex/regexp.c2
-rw-r--r--regex/regfree.c2
-rw-r--r--regex/reginit.c4
-rw-r--r--regex/split.c2
-rw-r--r--scripts/Makefile.am9
-rw-r--r--scripts/explain_log.sh383
-rw-r--r--scripts/make_binary_distribution.sh9
-rw-r--r--scripts/mysql_config.sh13
-rw-r--r--scripts/mysql_explain_log.sh383
-rw-r--r--scripts/mysql_fix_extensions.sh16
-rw-r--r--scripts/mysql_fix_privilege_tables.sh19
-rw-r--r--scripts/mysql_install_db.sh27
-rw-r--r--scripts/mysql_new_fix_privilege_tables.sh25
-rw-r--r--scripts/mysqld_multi.sh40
-rw-r--r--scripts/mysqld_safe-watch.sh (renamed from scripts/safe_mysqld-watch.sh)2
-rw-r--r--scripts/mysqld_safe.sh (renamed from scripts/safe_mysqld.sh)100
-rw-r--r--sql-bench/Comments/interbase18
-rw-r--r--sql-bench/Makefile.am8
-rw-r--r--sql-bench/as3ap.sh636
-rw-r--r--sql-bench/bench-count-distinct.sh258
-rw-r--r--sql-bench/bench-init.pl.sh28
-rw-r--r--sql-bench/crash-me.sh41
-rw-r--r--sql-bench/limits/db2.cfg270
-rw-r--r--sql-bench/limits/interbase-dialect1.cfg514
-rw-r--r--sql-bench/limits/interbase-dialect3.cfg514
-rw-r--r--sql-bench/limits/interbase-superserver.cfg514
-rw-r--r--sql-bench/run-all-tests.sh20
-rw-r--r--sql-bench/server-cfg.sh221
-rw-r--r--sql-bench/test-ATIS.sh17
-rw-r--r--sql-bench/test-alter-table.sh14
-rw-r--r--sql-bench/test-big-tables.sh16
-rw-r--r--sql-bench/test-connect.sh88
-rw-r--r--sql-bench/test-insert.sh114
-rw-r--r--sql-bench/test-select.sh18
-rw-r--r--sql-bench/test-transactions.sh297
-rw-r--r--sql-bench/test-wisconsin.sh68
-rw-r--r--sql/ChangeLog5
-rw-r--r--sql/Makefile.am38
-rw-r--r--sql/cache_manager.cc12
-rw-r--r--sql/cache_manager.h10
-rw-r--r--sql/convert.cc26
-rw-r--r--sql/custom_conf.h6
-rw-r--r--sql/derror.cc47
-rw-r--r--sql/des_key_file.cc107
-rw-r--r--sql/field.cc338
-rw-r--r--sql/field.h186
-rw-r--r--sql/field_conv.cc6
-rw-r--r--sql/filesort.cc324
-rw-r--r--sql/frm_crypt.cc6
-rw-r--r--sql/gen_lex_hash.cc20
-rw-r--r--sql/ha_berkeley.cc53
-rw-r--r--sql/ha_berkeley.h8
-rw-r--r--sql/ha_gemini.cc3630
-rw-r--r--sql/ha_gemini.h208
-rw-r--r--sql/ha_heap.cc48
-rw-r--r--sql/ha_heap.h9
-rw-r--r--sql/ha_innodb.cc (renamed from sql/ha_innobase.cc)348
-rw-r--r--sql/ha_innodb.h (renamed from sql/ha_innobase.h)36
-rw-r--r--sql/ha_isam.cc29
-rw-r--r--sql/ha_isam.h18
-rw-r--r--sql/ha_isammrg.cc16
-rw-r--r--sql/ha_isammrg.h11
-rw-r--r--sql/ha_myisam.cc250
-rw-r--r--sql/ha_myisam.h26
-rw-r--r--sql/ha_myisammrg.cc51
-rw-r--r--sql/ha_myisammrg.h6
-rw-r--r--sql/handler.cc201
-rw-r--r--sql/handler.h82
-rw-r--r--sql/hash_filo.cc6
-rw-r--r--sql/hash_filo.h8
-rw-r--r--sql/hostname.cc6
-rw-r--r--sql/init.cc6
-rw-r--r--sql/item.cc55
-rw-r--r--sql/item.h49
-rw-r--r--sql/item_buff.cc6
-rw-r--r--sql/item_cmpfunc.cc24
-rw-r--r--sql/item_cmpfunc.h12
-rw-r--r--sql/item_create.cc44
-rw-r--r--sql/item_create.h8
-rw-r--r--sql/item_func.cc267
-rw-r--r--sql/item_func.h138
-rw-r--r--sql/item_strfunc.cc249
-rw-r--r--sql/item_strfunc.h50
-rw-r--r--sql/item_sum.cc327
-rw-r--r--sql/item_sum.h42
-rw-r--r--sql/item_timefunc.cc18
-rw-r--r--sql/item_timefunc.h126
-rw-r--r--sql/item_uniq.cc6
-rw-r--r--sql/item_uniq.h6
-rw-r--r--sql/key.cc12
-rw-r--r--sql/lex.h49
-rw-r--r--sql/lex_symbol.h6
-rw-r--r--sql/lock.cc169
-rw-r--r--sql/log.cc454
-rw-r--r--sql/log_event.cc1893
-rw-r--r--sql/log_event.h661
-rw-r--r--sql/matherr.c8
-rw-r--r--sql/mf_iocache.cc646
-rw-r--r--sql/mini_client.cc624
-rw-r--r--sql/mini_client.h42
-rw-r--r--sql/my_lock.c8
-rw-r--r--sql/mysql_priv.h171
-rw-r--r--sql/mysqld.cc980
-rw-r--r--sql/net_pkg.cc17
-rw-r--r--sql/net_serv.cc457
-rw-r--r--sql/opt_ft.h2
-rw-r--r--sql/opt_range.cc274
-rw-r--r--sql/opt_range.h29
-rw-r--r--sql/opt_sum.cc21
-rw-r--r--sql/password.c8
-rw-r--r--sql/procedure.cc6
-rw-r--r--sql/procedure.h6
-rw-r--r--sql/records.cc19
-rw-r--r--sql/repl_failsafe.cc853
-rw-r--r--sql/repl_failsafe.h38
-rw-r--r--sql/share/Makefile.am6
-rw-r--r--sql/share/charsets/Index4
-rw-r--r--sql/share/czech/errmsg.txt383
-rw-r--r--sql/share/danish/errmsg.txt9
-rw-r--r--sql/share/dutch/errmsg.txt38
-rw-r--r--sql/share/english/errmsg.txt9
-rw-r--r--sql/share/estonian/errmsg.txt358
-rw-r--r--sql/share/french/errmsg.txt9
-rw-r--r--sql/share/german/errmsg.txt9
-rw-r--r--sql/share/greek/errmsg.txt9
-rw-r--r--sql/share/hungarian/errmsg.txt9
-rw-r--r--sql/share/italian/errmsg.txt9
-rw-r--r--sql/share/japanese/errmsg.txt9
-rw-r--r--sql/share/korean/errmsg.txt9
-rw-r--r--sql/share/norwegian-ny/errmsg.txt9
-rw-r--r--sql/share/norwegian/errmsg.txt9
-rw-r--r--sql/share/polish/errmsg.txt9
-rw-r--r--sql/share/portuguese/errmsg.txt9
-rw-r--r--sql/share/romanian/errmsg.txt9
-rw-r--r--sql/share/russian/errmsg.txt9
-rw-r--r--sql/share/slovak/errmsg.txt9
-rw-r--r--sql/share/spanish/errmsg.txt9
-rw-r--r--sql/share/swedish/errmsg.OLD20
-rw-r--r--sql/share/swedish/errmsg.txt9
-rw-r--r--sql/share/ukrainian/errmsg.txt9
-rw-r--r--sql/slave.cc2297
-rw-r--r--sql/slave.h397
-rw-r--r--sql/sql_acl.cc394
-rw-r--r--sql/sql_acl.h11
-rw-r--r--sql/sql_analyse.cc45
-rw-r--r--sql/sql_analyse.h37
-rw-r--r--sql/sql_base.cc377
-rw-r--r--sql/sql_cache.cc3460
-rw-r--r--sql/sql_cache.h418
-rw-r--r--sql/sql_class.cc65
-rw-r--r--sql/sql_class.h338
-rw-r--r--sql/sql_crypt.cc6
-rw-r--r--sql/sql_crypt.h6
-rw-r--r--sql/sql_db.cc256
-rw-r--r--sql/sql_delete.cc573
-rw-r--r--sql/sql_do.cc2
-rw-r--r--sql/sql_handler.cc278
-rw-r--r--sql/sql_insert.cc101
-rw-r--r--sql/sql_lex.cc83
-rw-r--r--sql/sql_lex.h87
-rw-r--r--sql/sql_list.cc8
-rw-r--r--sql/sql_list.h96
-rw-r--r--sql/sql_load.cc133
-rw-r--r--sql/sql_manager.cc8
-rw-r--r--sql/sql_map.cc6
-rw-r--r--sql/sql_map.h6
-rw-r--r--sql/sql_parse.cc1679
-rw-r--r--sql/sql_rename.cc29
-rw-r--r--sql/sql_repl.cc881
-rw-r--r--sql/sql_repl.h48
-rw-r--r--sql/sql_select.cc1552
-rw-r--r--sql/sql_select.h40
-rw-r--r--sql/sql_show.cc337
-rw-r--r--sql/sql_sort.h55
-rw-r--r--sql/sql_string.cc119
-rw-r--r--sql/sql_string.h30
-rw-r--r--sql/sql_table.cc440
-rw-r--r--sql/sql_test.cc9
-rw-r--r--sql/sql_udf.cc17
-rw-r--r--sql/sql_udf.h6
-rw-r--r--sql/sql_union.cc260
-rw-r--r--sql/sql_update.cc526
-rw-r--r--sql/sql_yacc.yy1362
-rw-r--r--sql/stacktrace.c12
-rw-r--r--sql/structs.h37
-rw-r--r--sql/table.cc25
-rw-r--r--sql/table.h20
-rw-r--r--sql/thr_malloc.cc10
-rw-r--r--sql/time.cc27
-rw-r--r--sql/udf_example.cc8
-rw-r--r--sql/uniques.cc166
-rw-r--r--sql/unireg.cc12
-rw-r--r--sql/unireg.h8
-rw-r--r--strings/Makefile.am4
-rw-r--r--strings/atof.c31
-rw-r--r--strings/bchange.c34
-rw-r--r--strings/bcmp.c48
-rw-r--r--strings/bcopy-duff.c29
-rw-r--r--strings/bfill.c18
-rw-r--r--strings/bmove.c18
-rw-r--r--strings/bmove512.c31
-rw-r--r--strings/bmove_upp.c31
-rw-r--r--strings/bzero.c16
-rw-r--r--strings/conf_to_src.c29
-rw-r--r--strings/ctype-big5.c31
-rw-r--r--strings/ctype-czech.c33
-rw-r--r--strings/ctype-euc_kr.c31
-rw-r--r--strings/ctype-gb2312.c31
-rw-r--r--strings/ctype-gbk.c35
-rw-r--r--strings/ctype-latin1_de.c361
-rw-r--r--strings/ctype-sjis.c31
-rw-r--r--strings/ctype-tis620.c18
-rw-r--r--strings/ctype-ujis.c18
-rw-r--r--strings/ctype.c33
-rw-r--r--strings/do_ctype.c31
-rw-r--r--strings/int2str.c31
-rw-r--r--strings/is_prefix.c31
-rw-r--r--strings/llstr.c31
-rw-r--r--strings/longlong2str-x86.s29
-rw-r--r--strings/longlong2str.c31
-rw-r--r--strings/memcmp.c29
-rw-r--r--strings/memcpy.c29
-rw-r--r--strings/memset.c18
-rw-r--r--strings/r_strinstr.c31
-rw-r--r--strings/str2int.c34
-rw-r--r--strings/str_test.c31
-rw-r--r--strings/strappend.c33
-rw-r--r--strings/strcat.c16
-rw-r--r--strings/strcend.c31
-rw-r--r--strings/strchr.c16
-rw-r--r--strings/strcmp.c16
-rw-r--r--strings/strcont.c31
-rw-r--r--strings/strend.c18
-rw-r--r--strings/strfill.c31
-rw-r--r--strings/strings-not-used.h18
-rw-r--r--strings/strings-x86.s377
-rw-r--r--strings/strinstr.c31
-rw-r--r--strings/strlen.c16
-rw-r--r--strings/strmake.c31
-rw-r--r--strings/strmov.c31
-rw-r--r--strings/strnlen.c31
-rw-r--r--strings/strnmov.c31
-rw-r--r--strings/strrchr.c16
-rw-r--r--strings/strstr.c18
-rw-r--r--strings/strto.c31
-rw-r--r--strings/strtol.c31
-rw-r--r--strings/strtoll.c31
-rw-r--r--strings/strtoul.c31
-rw-r--r--strings/strtoull.c31
-rw-r--r--strings/strxmov.c18
-rw-r--r--strings/strxnmov.c18
-rw-r--r--strings/t_ctype.h20
-rw-r--r--strings/udiv.c31
-rw-r--r--support-files/binary-configure.sh2
-rwxr-xr-xsupport-files/build-tags9
-rw-r--r--support-files/mysql-max.spec.sh4
-rw-r--r--support-files/mysql-multi.server.sh8
-rw-r--r--support-files/mysql.server.sh8
-rw-r--r--support-files/mysql.spec.sh35
-rwxr-xr-xtests/fork2_test.pl2
-rwxr-xr-xtests/fork_big.pl2
-rwxr-xr-xtests/insert_and_repair.pl2
-rwxr-xr-xtests/mail_to_db.pl110
-rw-r--r--tests/myisam-big-rows.tst72
-rwxr-xr-xtests/rename_test.pl2
-rwxr-xr-xtests/test_delayed_insert.pl2
-rw-r--r--tools/Makefile.am20
-rw-r--r--tools/managertest1.nc16
-rw-r--r--tools/mysqlmanager-sample.pwd1
-rw-r--r--tools/mysqlmanager.c1857
-rw-r--r--vio/Makefile.am27
-rw-r--r--vio/Vio.cc23
-rw-r--r--vio/Vio.h64
-rw-r--r--vio/VioAcceptorFd.cc18
-rw-r--r--vio/VioAcceptorFd.h23
-rw-r--r--vio/VioConnectorFd.cc22
-rw-r--r--vio/VioConnectorFd.h19
-rw-r--r--vio/VioFd.cc156
-rw-r--r--vio/VioFd.h38
-rw-r--r--vio/VioPipe.cc25
-rw-r--r--vio/VioPipe.h38
-rw-r--r--vio/VioSSL.cc292
-rw-r--r--vio/VioSSL.h54
-rw-r--r--vio/VioSSLAcceptorFd.cc4
-rw-r--r--vio/VioSSLFactoriesFd.cc360
-rw-r--r--vio/VioSSLFactoriesFd.h64
-rw-r--r--vio/VioSocket.cc326
-rw-r--r--vio/VioSocket.h55
-rw-r--r--vio/test-ssl.c147
-rw-r--r--vio/test-sslclient.c105
-rw-r--r--vio/test-sslserver.c157
-rw-r--r--vio/version.cc7
-rw-r--r--vio/vio-global.h33
-rw-r--r--vio/vio.c132
-rw-r--r--vio/vioelitexx.cc26
-rw-r--r--vio/violite.h101
-rw-r--r--vio/viosocket.c (renamed from sql/violite.c)178
-rw-r--r--vio/viossl.c360
-rw-r--r--vio/viosslfactories.c344
-rw-r--r--vio/viotest-ssl.c156
-rw-r--r--vio/viotest-ssl.cc104
-rw-r--r--vio/viotypes.h32
1413 files changed, 213332 insertions, 37129 deletions
diff --git a/.bzrignore b/.bzrignore
index 1699cf52943..9ba7f037a1b 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -7,6 +7,7 @@
*.la
*.lo
*.o
+*.reject
*.spec
*/*_pure_*warnings
*/.pure
@@ -20,6 +21,8 @@
.out
.snprj/*
.vimrc
+50
+=6
BitKeeper/etc/config
BitKeeper/etc/csets
BitKeeper/etc/csets-in
@@ -32,6 +35,7 @@ BitKeeper/tmp/bkr3sAHD
BitKeeper/tmp/gone
COPYING
COPYING.LIB
+Docs/#manual.texi#
Docs/INSTALL-BINARY
Docs/include.texi
Docs/manual.aux
@@ -54,6 +58,8 @@ Docs/manual_letter.ps
Docs/manual_toc.html
Docs/my_sys.doc
Docs/mysql.info
+Docs/tex.fmt
+Docs/texi2dvi.out
INSTALL-SOURCE
Logs/*
MIRRORS
@@ -115,17 +121,32 @@ bdb/dist/template/rec_txn
bdb/examples_java
bdb/hash/hash_auto.c
bdb/include/btree_auto.h
+bdb/include/btree_ext.h
+bdb/include/clib_ext.h
+bdb/include/common_ext.h
bdb/include/crdel_auto.h
bdb/include/db_auto.h
+bdb/include/db_ext.h
bdb/include/db_server.h
+bdb/include/env_ext.h
bdb/include/gen_client_ext.h
bdb/include/gen_server_ext.h
bdb/include/hash_auto.h
+bdb/include/hash_ext.h
+bdb/include/lock_ext.h
bdb/include/log_auto.h
+bdb/include/log_ext.h
+bdb/include/mp_ext.h
+bdb/include/mutex_ext.h
+bdb/include/os_ext.h
bdb/include/qam_auto.h
+bdb/include/qam_ext.h
bdb/include/rpc_client_ext.h
bdb/include/rpc_server_ext.h
+bdb/include/tcl_ext.h
bdb/include/txn_auto.h
+bdb/include/txn_ext.h
+bdb/include/xa_ext.h
bdb/java/src/com/sleepycat/db/DbConstants.java
bdb/log/log_auto.c
bdb/qam/qam_auto.c
@@ -151,6 +172,8 @@ client/mysqlbinlog
client/mysqlcheck
client/mysqldump
client/mysqlimport
+client/mysqlmanager-pwgen
+client/mysqlmanagerc
client/mysqlshow
client/mysqltest
client/mysys_priv.h
@@ -168,6 +191,7 @@ db-*.*.*
dbug/user.t
extra/comp_err
extra/my_print_defaults
+extra/mysql_install
extra/perror
extra/replace
extra/resolve_stack_dump
@@ -179,6 +203,8 @@ include/my_config.h
include/my_global.h
include/mysql_version.h
include/widec.h
+innobase/conftest.s1
+innobase/conftest.subs
innobase/ib_config.h
innobase/ib_config.h.in
isam/isamchk
@@ -196,12 +222,113 @@ libmysql_r/acconfig.h
libmysql_r/conf_to_src
libmysql_r/my_static.h
libmysql_r/mysys_priv.h
+libmysqld/backup_dir
+libmysqld/convert.cc
+libmysqld/derror.cc
+libmysqld/errmsg.c
+libmysqld/examples/completion_hash.cc
+libmysqld/examples/completion_hash.h
+libmysqld/examples/link_sources
+libmysqld/examples/my_readline.h
+libmysqld/examples/mysql
+libmysqld/examples/mysql.cc
+libmysqld/examples/mysqltest
+libmysqld/examples/mysqltest.c
+libmysqld/examples/readline.cc
+libmysqld/examples/sql_string.cc
+libmysqld/examples/sql_string.h
+libmysqld/examples/test-gdbinit
+libmysqld/field.cc
+libmysqld/field_conv.cc
+libmysqld/filesort.cc
+libmysqld/get_password.c
+libmysqld/ha_berkeley.cc
+libmysqld/ha_heap.cc
+libmysqld/ha_innobase.cc
+libmysqld/ha_innodb.cc
+libmysqld/ha_isam.cc
+libmysqld/ha_isammrg.cc
+libmysqld/ha_myisam.cc
+libmysqld/ha_myisammrg.cc
+libmysqld/handler.cc
+libmysqld/hash_filo.cc
+libmysqld/hostname.cc
+libmysqld/init.cc
+libmysqld/item.cc
+libmysqld/item_buff.cc
+libmysqld/item_cmpfunc.cc
+libmysqld/item_create.cc
+libmysqld/item_func.cc
+libmysqld/item_strfunc.cc
+libmysqld/item_sum.cc
+libmysqld/item_timefunc.cc
+libmysqld/item_uniq.cc
+libmysqld/key.cc
+libmysqld/lock.cc
+libmysqld/log.cc
+libmysqld/log_event.cc
+libmysqld/md5.c
+libmysqld/mf_iocache.cc
+libmysqld/mini_client.cc
+libmysqld/net_pkg.cc
+libmysqld/net_serv.cc
+libmysqld/opt_ft.cc
+libmysqld/opt_range.cc
+libmysqld/opt_sum.cc
+libmysqld/password.c
+libmysqld/procedure.cc
+libmysqld/records.cc
+libmysqld/repl_failsafe.cc
+libmysqld/simple-test
+libmysqld/slave.cc
+libmysqld/sql_acl.cc
+libmysqld/sql_analyse.cc
+libmysqld/sql_base.cc
+libmysqld/sql_cache.cc
+libmysqld/sql_class.cc
+libmysqld/sql_command
+libmysqld/sql_crypt.cc
+libmysqld/sql_db.cc
+libmysqld/sql_delete.cc
+libmysqld/sql_do.cc
+libmysqld/sql_handler.cc
+libmysqld/sql_insert.cc
+libmysqld/sql_lex.cc
+libmysqld/sql_list.cc
+libmysqld/sql_load.cc
+libmysqld/sql_manager.cc
+libmysqld/sql_map.cc
+libmysqld/sql_parse.cc
+libmysqld/sql_rename.cc
+libmysqld/sql_repl.cc
+libmysqld/sql_select.cc
+libmysqld/sql_show.cc
+libmysqld/sql_string.cc
+libmysqld/sql_table.cc
+libmysqld/sql_test.cc
+libmysqld/sql_udf.cc
+libmysqld/sql_union.cc
+libmysqld/sql_unions.cc
+libmysqld/sql_update.cc
+libmysqld/sql_yacc.cc
+libmysqld/stacktrace.c
+libmysqld/table.cc
+libmysqld/thr_malloc.cc
+libmysqld/time.cc
+libmysqld/uniques.cc
+libmysqld/unireg.cc
libtool
linked_client_sources
linked_include_sources
linked_libmysql_r_sources
linked_libmysql_sources
+linked_libmysqld_sources
+linked_libmysqldex_sources
linked_server_sources
+linked_tools_sources
+locked
+myisam/FT1.MYD
+myisam/FT1.MYI
myisam/ft_dump
myisam/ft_eval
myisam/ft_test1
@@ -218,14 +345,23 @@ mysql-test/gmon.out
mysql-test/install_test_db
mysql-test/mysql-test-run
mysql-test/r/*.reject
+mysql-test/r/rpl000002.eval
+mysql-test/r/rpl000014.eval
+mysql-test/r/rpl000015.eval
+mysql-test/r/rpl000016.eval
+mysql-test/r/rpl_log.eval
+mysql-test/r/slave-running.eval
+mysql-test/r/slave-stopped.eval
mysql-test/share/mysql
mysql-test/var/*
mysql.kdevprj
mysql.proj
mysqld.S
mysqld.sym
+mysys/#mf_iocache.c#
mysys/test_charset
mysys/test_dir
+mysys/test_io_cache
mysys/test_thr_alarm
mysys/test_thr_lock
mysys/testhash
@@ -239,7 +375,9 @@ scripts/make_binary_distribution
scripts/msql2mysql
scripts/mysql_config
scripts/mysql_convert_table_format
+scripts/mysql_explain_log
scripts/mysql_find_rows
+scripts/mysql_fix_extensions
scripts/mysql_fix_privilege_tables
scripts/mysql_install_db
scripts/mysql_setpermission
@@ -247,10 +385,12 @@ scripts/mysql_zap
scripts/mysqlaccess
scripts/mysqlbug
scripts/mysqld_multi
+scripts/mysqld_safe
scripts/mysqldumpslow
scripts/mysqlhotcopy
scripts/safe_mysqld
sql-bench/Results-linux/ATIS-mysql_bdb-Linux_2.2.14_my_SMP_i686
+sql-bench/bench-count-distinct
sql-bench/bench-init.pl
sql-bench/compare-results
sql-bench/compare-results-all
@@ -269,6 +409,7 @@ sql-bench/test-connect
sql-bench/test-create
sql-bench/test-insert
sql-bench/test-select
+sql-bench/test-transactions
sql-bench/test-wisconsin
sql/.gdbinit
sql/gen_lex_hash
@@ -277,11 +418,17 @@ sql/lex_hash.h
sql/mini_client_errors.c
sql/mysqlbinlog
sql/mysqld
+sql/mysqld-purecov
+sql/mysqld-purify
+sql/mysqld-quantify
+sql/new.cc
sql/share/*.sys
sql/share/charsets/gmon.out
sql/share/gmon.out
+sql/share/mysql
sql/share/norwegian-ny/errmsg.sys
sql/share/norwegian/errmsg.sys
+sql/sql_select.cc.orig
sql/sql_yacc.cc
sql/sql_yacc.h
stamp-h
@@ -303,5 +450,16 @@ support-files/mysql.server
support-files/mysql.spec
tags
tmp/*
-bdb/include/db_ext.h
-bdb/include/mutex_ext.h
+tools/my_vsnprintf.c
+tools/mysqlmanager
+tools/mysqlmngd
+tools/mysys_priv.h
+vio/test-ssl
+vio/test-sslclient
+vio/test-sslserver
+vio/viotest-ssl
+Docs/mysql.xml
+mysql-test/r/rpl000001.eval
+Docs/safe-mysql.xml
+mysys/test_vsnprintf
+Docs/manual.de.log
diff --git a/BUILD/FINISH.sh b/BUILD/FINISH.sh
index fbeaf1e3c68..82f31a14dc4 100644
--- a/BUILD/FINISH.sh
+++ b/BUILD/FINISH.sh
@@ -1,5 +1,6 @@
cflags="$c_warnings $extra_flags"
cxxflags="$cxx_warnings $base_cxxflags $extra_flags"
+extra_configs="$extra_configs $local_infile_configs"
configure="./configure $base_configs $extra_configs"
for arg
do
diff --git a/BUILD/Makefile.am b/BUILD/Makefile.am
new file mode 100644
index 00000000000..438b3a528cd
--- /dev/null
+++ b/BUILD/Makefile.am
@@ -0,0 +1,44 @@
+# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#
+# 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
+
+## Process this file with automake to create Makefile.in
+
+EXTRA_DIST = FINISH.sh \
+ SETUP.sh \
+ compile-alpha \
+ compile-alpha-ccc \
+ compile-alpha-cxx \
+ compile-alpha-debug \
+ compile-ia64-debug-max \
+ compile-pentium \
+ compile-pentium-debug \
+ compile-pentium-debug-max \
+ compile-pentium-debug-no-bdb \
+ compile-pentium-debug-openssl \
+ compile-pentium-gcov \
+ compile-pentium-gprof \
+ compile-pentium-max \
+ compile-pentium-myodbc \
+ compile-pentium-mysqlfs-debug \
+ compile-pentium-pgcc \
+ compile-solaris-sparc \
+ compile-solaris-sparc-debug \
+ compile-solaris-sparc-fortre \
+ compile-solaris-sparc-purify
+
+# Don't update the files from bitkeeper
+%::SCCS/s.%
diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh
index 9204d4216d1..348a5be0f1e 100644
--- a/BUILD/SETUP.sh
+++ b/BUILD/SETUP.sh
@@ -57,6 +57,10 @@ static_link="--with-mysqld-ldflags=-all-static --with-client-ldflags=-all-static
alpha_configs="" # Not used yet
pentium_configs=""
sparc_configs=""
+# we need local-infile in all binaries for rpl000001
+# if you need to disable local-infile in the client, write a build script
+# and unset local_infile_configs
+local_infile_configs="--enable-local-infile"
debug_configs="--with-debug"
diff --git a/BUILD/compile-alpha-cxx b/BUILD/compile-alpha-cxx
index 2992604644b..3e6eee9a0d6 100755
--- a/BUILD/compile-alpha-cxx
+++ b/BUILD/compile-alpha-cxx
@@ -1,17 +1,17 @@
/bin/rm -f */.deps/*.P */*.o
make -k clean
/bin/rm -f */.deps/*.P */*.o
-/bin/rm -f config.cache mysql-*.tar.gz
+/bin/rm -f */.deps/*.P config.cache innobase/config.cache bdb/build_unix/config.cache mysql-*.tar.gz
aclocal; autoheader; aclocal; automake; autoconf
-CC=ccc CFLAGS="-fast" CXX=cxx CXXFLAGS="-fast -noexceptions -nortti" ./configure --prefix=/usr/local/mysql --disable-shared --with-extra-charsets=complex --enable-thread-safe-client --with-mysqld-ldflags=-non_shared --with-client-ldflags=-non_shared
+CC=ccc CFLAGS="-fast" CXX=cxx CXXFLAGS="-fast -noexceptions -nortti" ./configure --prefix=/usr/local/mysql --disable-shared --with-extra-charsets=complex --enable-thread-safe-client --with-mysqld-ldflags=-non_shared --with-client-ldflags=-non_shared --without-extra-tools
-make
-rm */.deps/*
+make -j2
+find . -name ".deps" | xargs rm -r
make
if [ $? = 0 ]
then
- rm */.deps/*
+ find . -name ".deps" | xargs rm -r
bin/mysqladmin shutdown
sur make install
if [ $? = 0 ]
diff --git a/BUILD/compile-alpha-debug b/BUILD/compile-alpha-debug
index 6672027445e..60d1b9af659 100755
--- a/BUILD/compile-alpha-debug
+++ b/BUILD/compile-alpha-debug
@@ -1,7 +1,8 @@
+/bin/rm -f */.deps/*.P */*.o
make -k clean
-/bin/rm -f */.deps/*.P
-/bin/rm -f config.cache
+/bin/rm -f */.deps/*.P */*.o
+/bin/rm -f */.deps/*.P config.cache innobase/config.cache bdb/build_unix/config.cache mysql-*.tar.gz
aclocal; autoheader; aclocal; automake; autoconf
-CFLAGS=-O6 CXX=gcc CXXFLAGS="-O6 -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --with-debug
+CFLAGS=-O1 CC=gcc CXX=gcc CXXFLAGS="-O1 -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --with-debug --with-extra-charsets=complex --without-extra-tools
make
diff --git a/BUILD/compile-ia64-debug-max b/BUILD/compile-ia64-debug-max
new file mode 100755
index 00000000000..9cd54de428d
--- /dev/null
+++ b/BUILD/compile-ia64-debug-max
@@ -0,0 +1,13 @@
+gmake -k clean || true
+/bin/rm -f */.deps/*.P config.cache innobase/config.cache bdb/build_unix/config.cache
+
+aclocal && autoheader && aclocal && automake && autoconf
+(cd bdb/dist && sh s_all)
+(cd innobase && aclocal && autoheader && aclocal && automake && autoconf)
+if [ -d gemini ]
+then
+ (cd gemini && aclocal && autoheader && aclocal && automake && autoconf)
+fi
+
+CC=ecc CFLAGS="-w1 -DEXTRA_DEBUG -DSAFEMALLOC -DSAFE_MUTEX -O2" CXX=ecc CXXFLAGS="-w1 -DEXTRA_DEBUG -DSAFEMALLOC -DSAFE_MUTEX -O2" ./configure --prefix=/usr/local/mysql --with-extra-charsets=complex --enable-thread-safe-client --with-mysqld-ldflags=-all-static --with-client-ldflags=-all-static --with-debug --with-innodb --with-embedded-server
+gmake
diff --git a/BUILD/compile-pentium-debug b/BUILD/compile-pentium-debug
index 7d25ac4a406..d8a6b60809b 100755
--- a/BUILD/compile-pentium-debug
+++ b/BUILD/compile-pentium-debug
@@ -6,7 +6,7 @@ path=`dirname $0`
extra_flags="$pentium_cflags $debug_cflags"
c_warnings="$c_warnings $debug_extra_warnings"
cxx_warnings="$cxx_warnings $debug_extra_warnings"
-extra_configs="$pentium_configs $debug_configs"
+extra_configs="$pentium_configs $debug_configs $static_link"
extra_configs="$extra_configs "
diff --git a/BUILD/compile-pentium-debug-max b/BUILD/compile-pentium-debug-max
index 993c48565b8..1684686ce8c 100755
--- a/BUILD/compile-pentium-debug-max
+++ b/BUILD/compile-pentium-debug-max
@@ -8,6 +8,6 @@ c_warnings="$c_warnings $debug_extra_warnings"
cxx_warnings="$cxx_warnings $debug_extra_warnings"
extra_configs="$pentium_configs $debug_configs"
-extra_configs="$extra_configs --with-berkeley-db --with-innodb --enable-local-infile"
+extra_configs="$extra_configs --with-berkeley-db --with-innodb --with-embedded-server --with-openssl"
. "$path/FINISH.sh"
diff --git a/BUILD/compile-pentium-debug-no-bdb b/BUILD/compile-pentium-debug-no-bdb
index fad58bec437..d7e70f868cc 100755
--- a/BUILD/compile-pentium-debug-no-bdb
+++ b/BUILD/compile-pentium-debug-no-bdb
@@ -4,6 +4,6 @@ path=`dirname $0`
. "$path/SETUP.sh"
extra_flags="$pentium_cflags $debug_cflags"
-extra_configs="$pentium_configs $debug_configs --without-berkeley-db"
+extra_configs="$pentium_configs $debug_configs --without-berkeley-db $static_link"
. "$path/FINISH.sh"
diff --git a/BUILD/compile-pentium-debug-openssl b/BUILD/compile-pentium-debug-openssl
new file mode 100755
index 00000000000..5de1c18a5d7
--- /dev/null
+++ b/BUILD/compile-pentium-debug-openssl
@@ -0,0 +1,13 @@
+#! /bin/sh
+
+path=`dirname $0`
+. "$path/SETUP.sh"
+
+extra_flags="$pentium_cflags $debug_cflags"
+c_warnings="$c_warnings $debug_extra_warnings"
+cxx_warnings="$cxx_warnings $debug_extra_warnings"
+extra_configs="$pentium_configs $debug_configs"
+
+extra_configs="$extra_configs --with-debug=full --with-vio --with-openssl --without-innodb"
+
+. "$path/FINISH.sh"
diff --git a/BUILD/compile-pentium-max b/BUILD/compile-pentium-max
index 55f88ef4748..9838e6a287b 100755
--- a/BUILD/compile-pentium-max
+++ b/BUILD/compile-pentium-max
@@ -8,6 +8,6 @@ extra_configs="$pentium_configs"
strip=yes
extra_configs="$extra_configs --with-innodb --with-berkeley-db \
- --enable-thread-safe-client"
+ --enable-thread-safe-client --with-openssl --with-vio"
. "$path/FINISH.sh"
diff --git a/BUILD/compile-pentium-mysqlfs-debug b/BUILD/compile-pentium-mysqlfs-debug
new file mode 100755
index 00000000000..6643553d943
--- /dev/null
+++ b/BUILD/compile-pentium-mysqlfs-debug
@@ -0,0 +1,13 @@
+#! /bin/sh
+
+path=`dirname $0`
+. "$path/SETUP.sh"
+
+extra_flags="$pentium_cflags $debug_cflags"
+c_warnings="$c_warnings $debug_extra_warnings"
+cxx_warnings="$cxx_warnings $debug_extra_warnings"
+extra_configs="$pentium_configs $debug_configs $static_link"
+
+extra_configs="$extra_configs --with-debug=full --with-mysqlfs --without-server --without-pstack"
+
+. "$path/FINISH.sh"
diff --git a/BUILD/compile-pentium-pgcc b/BUILD/compile-pentium-pgcc
index ee70fd2bde0..2d806009b21 100755
--- a/BUILD/compile-pentium-pgcc
+++ b/BUILD/compile-pentium-pgcc
@@ -1,10 +1,21 @@
AM_MAKEFLAGS="-j 2"
-make -k clean
+gmake -k clean || true
/bin/rm -f */.deps/*.P config.cache
-
-aclocal; autoheader; aclocal; automake; autoconf
-
+
+aclocal && autoheader && aclocal && automake && autoconf
+(cd bdb/dist && sh s_all)
+(cd innobase && aclocal && autoheader && aclocal && automake && autoconf)
+if [ -d gemini ]
+then
+ (cd gemini && aclocal && autoheader && aclocal && automake && autoconf)
+fi
+
export PATH=/usr/local/pgcc/bin:$PATH
-CFLAGS="-O6 -mpentiumpro -fomit-frame-pointer -mstack-align-double" CXX=gcc CXXFLAGS="-O6 -mpentiumpro -fomit-frame-pointer -felide-constructors -fno-exceptions -fno-rtti -mstack-align-double" ./configure --prefix=/usr/local/mysql --enable-assembler --with-mysqld-ldflags=-all-static --disable-shared --with-extra-charsets=complex --enable-thread-safe-client
-make -j 2
+CFLAGS="-Wimplicit -Wreturn-type -Wid-clash-51 -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wimplicit-function-dec -Wimplicit-int -Wparentheses -Wsign-compare -Wwrite-strings -Wunused -O6 -mpentiumpro -fomit-frame-pointer -mstack-align-double" CXX=gcc CXXFLAGS="-Wimplicit -Wreturn-type -Wid-clash-51 -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wimplicit-function-dec -Wimplicit-int -Wparentheses -Wsign-compare -Wwrite-strings -Woverloaded-virtual -Wextern-inline -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor -felide-constructors -fno-exceptions -fno-rtti -O6 -fomit-frame-pointer -mpentiumpro -mstack-align-double" ./configure --prefix=/usr/local/mysql --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client --with-mysqld-ldflags=-all-static --with-client-ldflags=-all-static
+
+gmake -j 4
+
+mkdir -p tmp
+nm --numeric-sort sql/mysqld > tmp/mysqld.sym
+objdump -d sql/mysqld > tmp/mysqld.S
strip sql/mysqld
diff --git a/BUILD/compile-pentium-symbols b/BUILD/compile-pentium-symbols
deleted file mode 100755
index 4f63763606f..00000000000
--- a/BUILD/compile-pentium-symbols
+++ /dev/null
@@ -1,15 +0,0 @@
-#! /bin/sh
-
-path=`dirname $0`
-. "$path/SETUP.sh"
-
-extra_flags="$pentium_cflags $fast_cflags -g"
-extra_configs="$pentium_configs"
-
-# Use the optimized version if it exists
-if test -d /usr/local/BerkeleyDB-opt/
-then
- extra_configs="$extra_configs --with-berkeley-db=/usr/local/BerkeleyDB-opt/"
-fi
-
-. "$path/FINISH.sh"
diff --git a/BUILD/compile-solaris-sparc-debug b/BUILD/compile-solaris-sparc-debug
new file mode 100755
index 00000000000..0b6a7219593
--- /dev/null
+++ b/BUILD/compile-solaris-sparc-debug
@@ -0,0 +1,16 @@
+#! /bin/sh
+
+gmake -k clean || true
+/bin/rm -f */.deps/*.P config.cache
+
+aclocal && autoheader && aclocal && automake && autoconf
+(cd bdb/dist && sh s_all)
+(cd innobase && aclocal && autoheader && aclocal && automake && autoconf)
+if [ -d gemini ]
+then
+ (cd gemini && aclocal && autoheader && aclocal && automake && autoconf)
+fi
+
+CFLAGS="-g -Wimplicit -Wreturn-type -Wid-clash-51 -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wimplicit-function-dec -Wimplicit-int -Wparentheses -Wsign-compare -Wwrite-strings -Wunused -O3 -fno-omit-frame-pointer -mcpu=v8 -Wa,-xarch=v8plusa" CXX=gcc CXXFLAGS="-Wimplicit -Wreturn-type -Wid-clash-51 -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wimplicit-function-dec -Wimplicit-int -Wparentheses -Wsign-compare -Wwrite-strings -Woverloaded-virtual -Wextern-inline -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor -felide-constructors -fno-exceptions -fno-rtti -O3 -fno-omit-frame-pointer -mcpu=v8 -Wa,-xarch=v8plusa -g" ./configure --prefix=/usr/local/mysql --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client --with-debug
+
+gmake -j 4
diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok
index 53c1cde915e..8fe2d68a95b 100644
--- a/BitKeeper/etc/logging_ok
+++ b/BitKeeper/etc/logging_ok
@@ -1,16 +1,51 @@
+Administrator@co3064164-a.
+Administrator@co3064164-a.rochd1.qld.optushome.com.au
+Administrator@fred.
Miguel@light.local
+Sinisa@sinisa.nasamreza.org
+ahlentz@co3064164-a.rochd1.qld.optusnet.com.au
+arjen@co3064164-a.bitbike.com
+arjen@fred.bitbike.com
+bell@sanja.is.com.ua
+davida@isil.mysql.com
heikki@donna.mysql.fi
+heikki@hundin.mysql.fi
+jani@hynda.mysql.fi
+jani@janikt.pp.saunalahti.fi
+jani@rhols221.adsl.netsonic.fi
+jcole@abel.spaceapes.com
+jcole@main.burghcom.com
+jcole@mugatu.spaceapes.com
+jcole@sarvik.tfr.cafe.ee
+jcole@tetra.spaceapes.com
jorge@linux.jorge.mysql.com
+kaj@work.mysql.com
+miguel@hegel.local
miguel@light.local
monty@bitch.mysql.fi
monty@donna.mysql.fi
monty@hundin.mysql.fi
monty@tik.mysql.fi
+monty@tramp.mysql.fi
monty@work.mysql.com
mwagner@cash.mwagner.org
+mwagner@evoq.mwagner.org
paul@central.snake.net
+paul@teton.kitebird.com
+root@x3.internalnet
sasha@mysql.sashanet.com
serg@serg.mysql.com
-heikki@hundin.mysql.fi
-jani@hynda.mysql.fi
-miguel@hegel.local
+tfr@sarvik.tfr.cafe.ee
+tim@bitch.mysql.fi
+tim@black.box
+tim@hundin.mysql.fi
+tim@threads.polyesthetic.msg
+tim@white.box
+tim@work.mysql.com
+tom@basil-firewall.home.com
+tonu@hundin.mysql.fi
+tonu@volk.internalnet
+tonu@x153.internalnet
+tonu@x3.internalnet
+venu@work.mysql.com
+zak@linux.local
diff --git a/BitKeeper/triggers/post-commit b/BitKeeper/triggers/post-commit
index dc5f2f2b824..275c278f29d 100755
--- a/BitKeeper/triggers/post-commit
+++ b/BitKeeper/triggers/post-commit
@@ -4,6 +4,7 @@
TO=dev-public@mysql.com
FROM=$USER@mysql.com
INTERNALS=internals@lists.mysql.com
+DOCS=docs-commit@mysql.com
LIMIT=10000
if [ "$REAL_EMAIL" = "" ]
@@ -17,37 +18,65 @@ BK_STATUS=$BK_STATUS$BK_COMMIT
if [ "$BK_STATUS" = OK ]
then
+
+#++
+# dev-public@
+#--
echo "Commit successful, notifying developers at $TO"
(
cat <<EOF
-List-ID: <bk.mysql>
+List-ID: <bk.mysql-4.0>
From: $FROM
To: $TO
-Subject: bk commit into 3.23 tree
+Subject: bk commit - 4.0 tree
EOF
bk changes -v -r+
bk cset -r+ -d
) | head -n $LIMIT | /usr/sbin/sendmail -t
+
+#++
+# internals@ mail
+#--
echo "Notifying internals list at $INTERNALS"
(
cat <<EOF
-List-ID: <bk.mysql>
+List-ID: <bk.mysql-4.0>
From: $FROM
To: $INTERNALS
-Subject: bk commit into 3.23 tree
+Subject: bk commit into 4.0 tree
+
+Below is the list of changes that have just been committed into a
+4.0 repository of $USER. When $USER does a push, they will be propogated to
+the main repository and within 24 hours after the push to the public repository.
+For information on how to access the public repository
+see http://www.mysql.com/doc/I/n/Installing_source_tree.html
+
+EOF
+ bk changes -v -r+
+ bk cset -r+ -d
+ ) | head -n $LIMIT | /usr/sbin/sendmail -t
-Below is the list of changes that have just been commited into a local
-3.23. repository of $USER. When $USER does a push, they will be
-propogaged to the main repository and within 24 hours after the push into
-the public repository. For information on how to access
-the public repository see
-http://www.mysql.com/doc/I/n/Installing_source_tree.html
+#++
+# docs-commit@ mail
+#--
+ bk changes -v -r+ | grep -q Docs/manual.texi
+ if [ $? -eq 0 ]
+ then
+ echo "Notifying docs list at $DOCS"
+ (
+ cat <<EOF
+List-ID: <bk.mysql-4.0>
+From: $FROM
+To: $DOCS
+Subject: bk commit - 4.0 tree (Manual)
EOF
bk changes -v -r+
bk cset -r+ -d
) | head -n $LIMIT | /usr/sbin/sendmail -t
+ fi
+
else
echo "commit failed because '$BK_STATUS', sorry life is hard..."
fi
diff --git a/Build-tools/Do-all-build-steps b/Build-tools/Do-all-build-steps
index eb14b7105cd..8ff8851aecd 100755
--- a/Build-tools/Do-all-build-steps
+++ b/Build-tools/Do-all-build-steps
@@ -63,9 +63,13 @@ aclocal; autoheader; aclocal; automake; autoconf
--with-low-memory \
--with-mit-threads=yes $EXTRA_CONFIG \
--enable-thread-safe-client \
- --with-berkeley-db \
--enable-local-infile \
- --with-innodb
+ --with-berkeley-db \
+ --with-innodb \
+ --with-vio \
+ --without-pstack \
+ --with-extra-tools \
+ --with-embedded-server
gmake -j 2
diff --git a/Build-tools/Do-compile b/Build-tools/Do-compile
index ffd8815fdb1..e05f19181c0 100755
--- a/Build-tools/Do-compile
+++ b/Build-tools/Do-compile
@@ -225,7 +225,7 @@ if ($opt_stage <= 5 && !$opt_no_test && !$opt_no_mysqltest)
{
system("mkdir $bench_tmpdir") if (! -d $bench_tmpdir);
safe_cd("${test_dir}/mysql-test");
- check_system("./mysql-test-run --tmpdir=$bench_tmpdir --master_port=$mysql_tcp_port --slave_port=$slave_port --sleep=10", "tests were successful");
+ check_system("./mysql-test-run --tmpdir=$bench_tmpdir --master_port=$mysql_tcp_port --slave_port=$slave_port --manager-port=$manager_port --no-manager --sleep=10", "tests were successful");
}
# Start the server if we are going to run any of the benchmarks
diff --git a/Build-tools/Do-rpm b/Build-tools/Do-rpm
index 62c7536570a..410338b9ce6 100755
--- a/Build-tools/Do-rpm
+++ b/Build-tools/Do-rpm
@@ -5,6 +5,7 @@
function copy_to_bmachine
{
if [ x$local_build = x1 ]; then
+ rm -f $2
cp $1 $2
else
scp $1 $owner@$bmachine:$2
@@ -14,6 +15,7 @@ function copy_to_bmachine
function copy_from_bmachine
{
if [ x$local_build = x1 ]; then
+ rm -f $2
cp $1 $2
else
scp $owner@$bmachine:$1 $2
@@ -104,10 +106,7 @@ while test $# -gt 0; do
done
echo "Removing old MySQL packages"
-rm -rf $rpmdir/BUILD/mysql-*
-rm -f $rpmdir/SOURCES/mysql-*
-rm -f $rpmdir/SRPMS/MySQL-*
-rm -f $rpmdir/SPEC/mysql-*
+rm -f $bpath/NEW-RPMS/MySQL-*rpm
if [ ! -d "$logdir" ]; then
echo "$logdir does not exist, creating"
@@ -119,12 +118,20 @@ if [ ! -f "$tarball" ]; then
exit 1
fi
-echo "Building RPM for MySQL version $VER on $bmachine"
-
log=$logdir/Log-RPM-`date +%y%m%d-%H%M`
+echo "Building RPM for MySQL version $VER on $bmachine"
+echo "Details in $log"
+
(
set -x
+# remove old stuff
+rm -rf $rpmdir/BUILD/mysql-*
+rm -f $rpmdir/SOURCES/mysql-*
+rm -f $rpmdir/SRPMS/MySQL-*
+rm -f $rpmdir/SPECS/mysql-*
+rm -rf /var/tmp/mysql
+
# Copy MySQL source and spec files
#Sasha: I left the scp stuff commented out instead of deleted to make it
@@ -170,7 +177,7 @@ if [ ! x$skip_perl=x1 ]; then
set -x
# First clean up so we do not get old versions when wildcard matching
- rm -f $rpmdir/SOURCES/DBI-*.spec
+ rm -f $rpmdir/SOURCES/DBI-*.spec $rpmdir/SOURCES/mysql*
rm -f $rpmdir/RPMS/i386/Perl-*.rpm
rm -f $rpmdir/SRPMS/Perl-*.rpm
rm -f $rpmdir/RPMS/i386/MySQL*-$VER_NO_DASH*.rpm
@@ -240,5 +247,9 @@ if [ x$local_build != x1 ]; then
# And the perl ones
#scp $owner@$bmachine:$rpmdir/RPMS/i386/Perl*-*.rpm $bpath/NEW-RPMS
#scp $owner@$bmachine:$rpmdir/SRPMS/Perl*-*.rpm $bpath/NEW-RPMS
+
+ #Remove some of the files that can interfere with future builds
+
+ rm -rf /var/tmp/mysql
fi
) > $log 2>&1
diff --git a/Docs/Flags/argentina.eps b/Docs/Flags/argentina.eps
index 840e24188ad..c0a9dae067e 100644
--- a/Docs/Flags/argentina.eps
+++ b/Docs/Flags/argentina.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: argentina.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-181818181818181818181818181818181818181818181818181818181818
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
-181818181818181818181818181818181818181818181818181818181818
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
-181818181818181818181818181818181818181818181818181818181818
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
-181818181818181818181818181818181818181818181818181818181818
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
-181818181818181818181818181818181818181818181818181818181818
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
-181818181818181818181818181818181818181818181818181818181818
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
-676767676767676767676767676767676767676767676767676767676767
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2
-f7f7f7f7f7f7f7f7f7f7f7f7f7f8f9f9f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f5f3f2f6f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7e6cdc5eef7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f8fafdfdfaf7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f5f0f2f2f1f6f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7e79441419eebf7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f9fdf3eefdf8f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f3f3eee9f1f3f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7c93f00004fd5f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f9fde9edfdf8f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f2f3e4eaf2f3f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7c43e00014ed0f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7fafdfdfaf7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f6f1f1f2f1f6f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7ec9b4c4ca4f1f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f8f9f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f5f3f2f6f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7e9d5cdf1f7f7f7f7f7f7f7f7f7f7f7f7f7
-585858585858585858585858585858585858585858585858585858585858
-c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8
-f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1
-181818181818181818181818181818181818181818181818181818181818
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
-181818181818181818181818181818181818181818181818181818181818
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
-181818181818181818181818181818181818181818181818181818181818
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
-181818181818181818181818181818181818181818181818181818181818
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
-181818181818181818181818181818181818181818181818181818181818
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
-181818181818181818181818181818181818181818181818181818181818
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000001818181818181818181818181818181818181818181818
+181818181818180000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b50000efefefefefefefefefefefefefefefefefefef
+efefefefefefefefefefef00001818181818181818181818181818181818
+181818181818181818181818180000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b50000efefefefefefefefefefefefef
+efefefefefefefefefefefefefefefefef00001818181818181818181818
+181818181818181818181818181818181818180000b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b50000efefefefefefef
+efefefefefefefefefefefefefefefefefefefefefefef00001818181818
+181818181818181818181818181818181818181818181818180000b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b50000ef
+efefefefefefefefefefefefefefefefefefefefefefefefefefefefef00
+001818181818181818181818181818181818181818181818181818181818
+180000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b50000efefefefefefefefefefefefefefefefefefefefefefefefef
+efefefefef00001818181818181818181818181818181818181818181818
+181818181818180000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b50000efefefefefefefefefefefefefefefefefefef
+efefefefefefefefefefef00006161616161616161616161616161616161
+616161616161616161616161610000cacacacacacacacacacacacacacaca
+cacacacacacacacacacacacacacaca0000f2f2f2f2f2f2f2f2f2f2f2f2f2
+f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f20000f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f9f9f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7
+f7f7f7f7f6f3f3f6f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7f7f7f7f7f7eccbccecf7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7
+f7f7f7f7f7f7f7f7fafdfdfaf7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7
+f7f7f7f7f7f7f7f7f7f6f0f2f2f0f6f7f7f7f7f7f7f7f7f7f7f7f70000f7
+f7f7f7f7f7f7f7f7f7f7f7ec9b45459becf7f7f7f7f7f7f7f7f7f7f7f700
+00f7f7f7f7f7f7f7f7f7f7f7f7f9fdf2eefdf9f7f7f7f7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f7f7f7f7f7f3f2ede9f2f3f7f7f7f7f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7cb45000045cbf7f7f7f7f7f7f7
+f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f9fdebeafdf9f7f7f7f7f7
+f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f3f2e7e7f2f3f7f7f7
+f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7cb45000045cbf7
+f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7fafdfdfa
+f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f6f1f2
+f2f1f6f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7ec
+9b45459becf7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f9f9f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7
+f7f7f7f7f6f3f3f6f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7f7f7f7f7f7eccbcbecf7f7f7f7f7f7f7f7f7f7f7f7f700006363636363
+636363636363636363636363636363636363636363636363630000cbcbcb
+cbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcb0000f2
+f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f200
+001818181818181818181818181818181818181818181818181818181818
+180000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b50000efefefefefefefefefefefefefefefefefefefefefefefefef
+efefefefef00001818181818181818181818181818181818181818181818
+181818181818180000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b50000efefefefefefefefefefefefefefefefefefef
+efefefefefefefefefefef00001818181818181818181818181818181818
+181818181818181818181818180000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b50000efefefefefefefefefefefefef
+efefefefefefefefefefefefefefefefef00001818181818181818181818
+181818181818181818181818181818181818180000b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b50000efefefefefefef
+efefefefefefefefefefefefefefefefefefefefefefef00001818181818
+181818181818181818181818181818181818181818181818180000b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b50000ef
+efefefefefefefefefefefefefefefefefefefefefefefefefefefefef00
+001818181818181818181818181818181818181818181818181818181818
+180000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b50000efefefefefefefefefefefefefefefefefefefefefefefefef
+efefefefef00000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/argentina.gif b/Docs/Flags/argentina.gif
index 8fef5c3f455..b1bba9778cc 100644
--- a/Docs/Flags/argentina.gif
+++ b/Docs/Flags/argentina.gif
Binary files differ
diff --git a/Docs/Flags/argentina.pdf b/Docs/Flags/argentina.pdf
new file mode 100644
index 00000000000..4ccb26eec76
--- /dev/null
+++ b/Docs/Flags/argentina.pdf
Binary files differ
diff --git a/Docs/Flags/australia.eps b/Docs/Flags/australia.eps
index f98c03e2c83..9f772787ae7 100644
--- a/Docs/Flags/australia.eps
+++ b/Docs/Flags/australia.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: australia.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-cf7b0e0808087cc6730808081084c4080808080808080808080808080808
-3f5c0600000050005300000009603a000000000000000000000000000000
-43b5b6b5b5b5a600b1b5b5b5b7b246b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-b1d2b73608087cc67308083dbcd3a5080808080808080809080808080808
-8d3e612f00005000530000355e4285000000000000000001000000000000
-bc3e82c0b5b5a600b1b5b5c17a43bfb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-096bd4cf7b0e7cc6731083d0d36108080808080808084d990c0808080808
-0162753f5c06500053095f3c7b5b00000000000000004796040000000000
-b5cd7e43b5b7a600b1b7b13e87ccb5b5b5b5b5b5b5b5c8ddb6b5b5b5b5b5
-0c0c2bb5d3b8a3c6a2bcd3ae250c0c080808080808087bba170808080808
-040424913e6478008061438f1e04040000000000000077b70f0000000000
-b6b6bfbd3f85b000bc7d43c1bdb6b6b5b5b5b5b5b5b5d5e6b9b5b5b5b5b5
-d5d5d5d5d5d5d2c6d3d5d5d5d5d5c9080808080808080d0d080808080808
-4c4c4c4c4c4a3c00414a4c4c4c4c48000000000000000505000000000000
-4c4c4c4c4c4a3c00414a4c4c4c4c52b5b5b5b5b5b5b5b6b6b5b5b5b5b5b5
-d3d3d3d4d7d6d4c6d4d6d7d4d3d3c7080808080808080808080808080808
-51515152545044004950555251514c000000000000000000000000000000
-55555555545044004950555555555bb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-0a0a2fb9d2b19fc69db7d2b3290a0a080808080808080808080808080808
-0202288f3a6374007c613e8e220202000000000000000000000000000000
-b5b5c0b73b8aaf00bb823ebcbeb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-0b74d6ce720b7cc6730e7bcfd46b0908080808080808080808080c080808
-036b6f435703500053065c3f756201000000000000000000000004000000
-b6cd7649b8b6a600b1b7b5437ecdb5b5b5b5b5b5b5b5b5b5b5b5b6b5b5b5
-b9d2b12f08087cc673080836b7d2ab080808110808080808080eac520808
-8f3a6328000050005300002f613e870000000a00000000000006a94d0000
-b73a8abfb5b5a600b1b5b5c0823ebab5b5b5b8b5b5b5b5b5b5b6e2cab5b5
-c7720b08080877bf6f0808080e7abd080819c757080808080819ae6f0808
-3c57030000004d004f000000065b37000011c552000000000012ac6a0000
-47b8b6b5b5b5a607b1b5b5b5b7b54ab5b5baeacbb5b5b5b5b5bae3d1b5b5
-08080808080808080808080808080808081c9e50080808080f080a0a0808
-0000000000000000000000000000000000149a4a00000000070002020000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5badec9b5b5b5b5b7b5b6b5b5b5
-0808080808080808080808080808080808080808080808119a0b08080808
-000000000000000000000000000000000000000000000009960300000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b7ddb6b5b5b5b5
-0808080808080808080808080808080808080808080808080c0808080808
-000000000000000000000000000000000000000000000000040000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b6b5b5b5b5b5
-080808080808080c08080808080808080808080808080808080808080808
-000000000000000400000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b6b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080809439144090808080808080808080808080808080808080808
-0000000000013d8e3d010000000000000000000000000000000000000000
-b5b5b5b5b5b5c5dbc5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080809b0f7b1090808080808080808080808081308080808080808
-000000000001adf7af010000000000000000000000000c00000000000000
-b5b5b5b5b5b5e3f7e4b5b5b5b5b5b5b5b5b5b5b5b5b5b8b5b5b5b5b5b5b5
-08080808081c8eed8f1d08080808080808080808083ccc3a080808080808
-0000000000158aed8c15000000000000000000000035cb34000000000000
-b5b5b5b5b5bbdaf4dabbb5b5b5b5b5b5b5b5b5b5b5c3ebc3b5b5b5b5b5b5
-0808080808082c1b2c08080808080808080808080827af26080808080808
-0000000000002513250000000000000000000000001fac1e000000000000
-b5b5b5b5b5b5bfbabfb5b5b5b5b5b5b5b5b5b5b5b5bde3bdb5b5b5b5b5b5
-080808080808080808080808080808080808080808080808080808080808
000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080808080808080808080808080808080808080808080808
000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+000000000000000000000000000000000000000000000000000000000000
+00000000000000cf7c0e08080877c67a0808080e7ccf0808080808080808
+0808080808080800003f5d06000000500053000000065e3f000000000000
+000000000000000000000043b5b7b5b5b5ab00acb5b5b5b7b543b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b50000b3d2b737080877c67a080837b7d2b30808
+0808080808080908080808080800008e3d622f000050005300002f623d8e
+0000000000000000010000000000000000bc3d82c0b5b5ab00acb5b5c082
+3dbcb5b5b5b5b5b5b5b5b5b5b5b5b5b5b50000096cd5cf7c0e77c67a0e7c
+cfd56c0908080808080808419c12080808080800000164753f5d06500053
+065d3f756401000000000000003b990b00000000000000b5cd7e43b5b7ab
+00acb7b5437ecdb5b5b5b5b5b5b5b5c5deb8b5b5b5b5b50000080828b3d2
+b7a0c6a2b7d2b32808080808080808080868c91f08080808080000000021
+8e3d6279007c623d8e2100000000000000000063c81800000000000000b5
+b5bebc3d82b500b5823dbcbeb5b5b5b5b5b5b5b5b5cfeabbb5b5b5b5b500
+00d6d6d6d6d6d5d3c6d3d5d6d6d6d6d6080808080808080e0e0808080808
+080000505050504f4d4200424d4f50505050000000000000000606000000
+0000000000505050504f4d4200424d4f50505050b5b5b5b5b5b5b5b7b7b5
+b5b5b5b5b50000d6d6d6d6d6d6d3c6d3d6d6d6d6d6d60808080808080808
+080808080808080000505050505050420042505050505050000000000000
+0000000000000000000000505050505050420042505050505050b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b500000b0b2bb5d2b7a0c6a2b7d2b52b0b0b0808
+080808080808080808080808080000030324913d6179007c623d91240303
+0000000000000000000000000000000000b6b6bfbd3d82b500b5823dbdbf
+b6b6b5b5b5b5b5b5b5b5b5b5b5b5b5b5b50000096dd5cf7b0e77c67a0e7c
+cfd56c0908080808080808080808080a08080800000165753f5c06500053
+065d3f7564010000000000000000000000030000000000b5cd7e43b5b7ab
+00acb7b5437ecdb5b5b5b5b5b5b5b5b5b5b5b5b6b5b5b50000b3d2b73608
+0877c67a080837b7d2b30808080f080808080808099861080800008f3d61
+2e000050005300002f623d8e0000000800000000000001955b00000000bc
+3d82c0b5b5ab00acb5b5c0823dbcb5b5b5b7b5b5b5b5b5b5b5ddcdb5b500
+00cf7a0e08080877c67a0808080e7bcf08080fbd5d080808080812a98708
+0800003f5b06000000500053000000065c3f000008bb5800000000000aa6
+830000000042b5b7b5b5b5ab00acb5b5b5b6b543b5b5b7e7ccb5b5b5b5b5
+b8e1d8b5b500000808080808080808080808080808080808199e64080808
+080d080b0b080800000000000000000000000000000000000000129b5f00
+0000000500030300000000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5badf
+ceb5b5b5b5b6b5b6b6b5b500000808080808080808080808080808080808
+0808080808080c9a0f080808080000000000000000000000000000000000
+0000000000000000049607000000000000b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b6ddb7b5b5b5b500000808080808080808080808
+080808080808080808080808081008080808080000000000000000000000
+0000000000000000000000000000000800000000000000b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b7b5b5b5b5b500000808080808
+08080a080808080808080808080808080808080808080808080000000000
+0000000003000000000000000000000000000000000000000000000000b5
+b5b5b5b5b5b5b6b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500
+000808080808083886380a08080808080808080808080808080808080808
+080000000000000000328231020000000000000000000000000000000000
+0000000000b5b5b5b5b5b5c2d8c2b6b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b50000080808080808a7f7b70808080808080808080808080810
+080808080808080000000000000000a4f7b5000000000000000000000000
+0008000000000000000000b5b5b5b5b5b5e1f7e5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b7b5b5b5b5b5b5b5000008080808081b95f39e2108080808080808
+0808080827c242080808080808000000000000001491f39b1a0000000000
+00000000000020c03c0000000000000000b5b5b5b5b5badcf6dfbcb5b5b5
+b5b5b5b5b5b5b5b5bde8c5b5b5b5b5b5b500000808080808082f25340808
+0808080808080808080825b63f0808080808080000000000000000281e2e
+0000000000000000000000001eb3390000000000000000b5b5b5b5b5b5c0
+bdc1b5b5b5b5b5b5b5b5b5b5b5b5bde5c4b5b5b5b5b5b500000808080808
+080808080808080808080808080808080808080808080808080000000000
+0000000000000000000000000000000000000000000000000000000000b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500
+000808080808080808080808080808080808080808080808080808080808
+080000000000000000000000000000000000000000000000000000000000
+0000000000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b500000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/australia.gif b/Docs/Flags/australia.gif
index 1f403f92503..6c766cbb614 100644
--- a/Docs/Flags/australia.gif
+++ b/Docs/Flags/australia.gif
Binary files differ
diff --git a/Docs/Flags/australia.pdf b/Docs/Flags/australia.pdf
new file mode 100644
index 00000000000..f7a1d0fd53d
--- /dev/null
+++ b/Docs/Flags/australia.pdf
Binary files differ
diff --git a/Docs/Flags/austria.eps b/Docs/Flags/austria.eps
index 7a0b56f3690..c6c35dc81e2 100644
--- a/Docs/Flags/austria.eps
+++ b/Docs/Flags/austria.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: austria.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6
+d6d6d6d6d6d6d6d6d6d6d6d6d60000505050505050505050505050505050
+505050505050505050505050505050000050505050505050505050505050
+50505050505050505050505050505050500000f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700
+00f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000d7d7d7d7d7
+d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d70000535353
+535353535353535353535353535353535353535353535353535353000054
+545454545454545454545454545454545454545454545454545454545400
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7
-575757575757575757575757575757575757575757575757575757575757
-575757575757575757575757575757575757575757575757575757575757
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4
-464646464646464646464646464646464646464646464646464646464646
-474747474747474747474747474747474747474747474747474747474747
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/austria.gif b/Docs/Flags/austria.gif
index d72b945741a..26a97856627 100644
--- a/Docs/Flags/austria.gif
+++ b/Docs/Flags/austria.gif
Binary files differ
diff --git a/Docs/Flags/austria.pdf b/Docs/Flags/austria.pdf
new file mode 100644
index 00000000000..d50b4f265cd
--- /dev/null
+++ b/Docs/Flags/austria.pdf
Binary files differ
diff --git a/Docs/Flags/belgium.eps b/Docs/Flags/belgium.eps
new file mode 100644
index 00000000000..d27fda0e1e1
--- /dev/null
+++ b/Docs/Flags/belgium.eps
@@ -0,0 +1,98 @@
+%!PS-Adobe-2.0 EPSF-2.0
+%%Creator: pnmtops
+%%Title: belgium.ps
+%%Pages: 1
+%%BoundingBox: 290 385 321 407
+%%EndComments
+/readstring {
+ currentfile exch readhexstring pop
+} bind def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
+%%EndProlog
+%%Page: 1 1
+gsave
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
+{ rpicstr readstring }
+{ gpicstr readstring }
+{ bpicstr readstring }
+true 3
+colorimage
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000003ffffffffffffffffffffc6c6c6
+c6c6c6c6c6c6c6000000000000000000000003d6d6d6d6d6d6d6d6d6d600
+000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000003ffffffffffffff
+ffffffc6c6c6c6c6c6c6c6c6c6000000000000000000000003d6d6d6d6d6
+d6d6d6d6d600000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000003ff
+ffffffffffffffffffc6c6c6c6c6c6c6c6c6c60000000000000000000000
+03d6d6d6d6d6d6d6d6d6d600000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+0000000003ffffffffffffffffffffc6c6c6c6c6c6c6c6c6c60000000000
+00000000000003d6d6d6d6d6d6d6d6d6d600000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+0000000000000000000003ffffffffffffffffffffc6c6c6c6c6c6c6c6c6
+c6000000000000000000000003d6d6d6d6d6d6d6d6d6d600000000000000
+000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000003ffffffffffffffffffffc6c6c6
+c6c6c6c6c6c6c6000000000000000000000003d6d6d6d6d6d6d6d6d6d600
+000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000003ffffffffffffff
+ffffffc6c6c6c6c6c6c6c6c6c6000000000000000000000003d6d6d6d6d6
+d6d6d6d6d600000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000003ff
+ffffffffffffffffffc6c6c6c6c6c6c6c6c6c60000000000000000000000
+03d6d6d6d6d6d6d6d6d6d600000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+0000000003ffffffffffffffffffffc6c6c6c6c6c6c6c6c6c60000000000
+00000000000003d6d6d6d6d6d6d6d6d6d600000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+0000000000000000000003ffffffffffffffffffffc6c6c6c6c6c6c6c6c6
+c6000000000000000000000003d6d6d6d6d6d6d6d6d6d600000000000000
+000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000003ffffffffffffffffffffc6c6c6
+c6c6c6c6c6c6c6000000000000000000000003d6d6d6d6d6d6d6d6d6d600
+000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000003ffffffffffffff
+ffffffc6c6c6c6c6c6c6c6c6c6000000000000000000000003d6d6d6d6d6
+d6d6d6d6d600000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000003ff
+ffffffffffffffffffc6c6c6c6c6c6c6c6c6c60000000000000000000000
+03d6d6d6d6d6d6d6d6d6d600000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+0000000003ffffffffffffffffffffc6c6c6c6c6c6c6c6c6c60000000000
+00000000000003d6d6d6d6d6d6d6d6d6d600000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+0000000000000000000003ffffffffffffffffffffc6c6c6c6c6c6c6c6c6
+c6000000000000000000000003d6d6d6d6d6d6d6d6d6d600000000000000
+000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000003ffffffffffffffffffffc6c6c6
+c6c6c6c6c6c6c6000000000000000000000003d6d6d6d6d6d6d6d6d6d600
+000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000003ffffffffffffff
+ffffffc6c6c6c6c6c6c6c6c6c6000000000000000000000003d6d6d6d6d6
+d6d6d6d6d600000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000003ff
+ffffffffffffffffffc6c6c6c6c6c6c6c6c6c60000000000000000000000
+03d6d6d6d6d6d6d6d6d6d600000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+0000000003ffffffffffffffffffffc6c6c6c6c6c6c6c6c6c60000000000
+00000000000003d6d6d6d6d6d6d6d6d6d600000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+0000000000000000000003ffffffffffffffffffffc6c6c6c6c6c6c6c6c6
+c6000000000000000000000003d6d6d6d6d6d6d6d6d6d600000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/belgium.gif b/Docs/Flags/belgium.gif
new file mode 100644
index 00000000000..2bb101dc501
--- /dev/null
+++ b/Docs/Flags/belgium.gif
Binary files differ
diff --git a/Docs/Flags/belgium.pdf b/Docs/Flags/belgium.pdf
new file mode 100644
index 00000000000..7696d4af102
--- /dev/null
+++ b/Docs/Flags/belgium.pdf
Binary files differ
diff --git a/Docs/Flags/island.eps b/Docs/Flags/belgium.txt
index e69de29bb2d..e69de29bb2d 100644
--- a/Docs/Flags/island.eps
+++ b/Docs/Flags/belgium.txt
diff --git a/Docs/Flags/bulgaria.eps b/Docs/Flags/bulgaria.eps
index 6f4a07c616c..2eb04535d36 100644
--- a/Docs/Flags/bulgaria.eps
+++ b/Docs/Flags/bulgaria.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: bulgaria.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0
-e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0
-a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0
000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+00000000000000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700
+00f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f70000a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7
+a7a7a7a7a7a7a7a7a7a7a7a7a70000e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2
+e2e2e2e2e2e2e2e2e2e2e2e2e2e2e20000a7a7a7a7a7a7a7a7a7a7a7a7a7
+a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a700000000000000000000000000
+000000000000000000000000000000000000000000b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5000000000000000000
000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5000000
000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
000000000000000000000000000000000000000000000000000000000000
+000000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+000000000000000000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+000000000000000000000000000000000000000000b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5000000000000000000
+000000000000000000000000000000000000000000000000008383838383
+8383838383838383838383838383838383838383838383838300003d3d3d
+3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d000000
000000000000000000000000000000000000000000000000000000000000
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d
-333333333333333333333333333333333333333333333333333333333333
+00000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/bulgaria.gif b/Docs/Flags/bulgaria.gif
index 35c0b117062..4c7377e907c 100644
--- a/Docs/Flags/bulgaria.gif
+++ b/Docs/Flags/bulgaria.gif
Binary files differ
diff --git a/Docs/Flags/bulgaria.pdf b/Docs/Flags/bulgaria.pdf
new file mode 100644
index 00000000000..24cb072598d
--- /dev/null
+++ b/Docs/Flags/bulgaria.pdf
Binary files differ
diff --git a/Docs/Flags/canada.eps b/Docs/Flags/canada.eps
index b770266de60..7773f12a699 100644
--- a/Docs/Flags/canada.eps
+++ b/Docs/Flags/canada.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: canada.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-c6c6c6c6c6c6c6e0f7f7f7f7f7f7f7f7f7f7f7f7f7f7dac6c6c6c6c6c6c6
-0000000000000083f7f7f7f7f7f7f7f7f7f7f7f7f7f76300000000000000
-0000000000000083f7f7f7f7f7f7f7f7f7f7f7f7f7f76300000000000000
-c6c6c6c6c6c6c6e0f7f7f7f7f7f7f7f7f7f7f7f7f7f7dac6c6c6c6c6c6c6
-0000000000000083f7f7f7f7f7f7f7f7f7f7f7f7f7f76300000000000000
-0000000000000083f7f7f7f7f7f7f7f7f7f7f7f7f7f76300000000000000
-c6c6c6c6c6c6c6e0f7f7f7f7f7f7f7f7f7f7f7f7f7f7dac6c6c6c6c6c6c6
-0000000000000083f7f7f7f7f7f7f7f7f7f7f7f7f7f76300000000000000
-0000000000000083f7f7f7f7f7f7f7f7f7f7f7f7f7f76300000000000000
-c6c6c6c6c6c6c6e0f7f7f7f7f7f7f6f7f7f7f7f7f7f7dac6c6c6c6c6c6c6
-0000000000000083f7f7f7f7f7f7f3f7f7f7f7f7f7f76300000000000000
-0000000000000083f7f7f7f7f7f7f3f7f7f7f7f7f7f76300000000000000
-c6c6c6c6c6c6c6e0f7f7f7f7f7f7e5ebf7f7f7f7f7f7dac6c6c6c6c6c6c6
-0000000000000083f7f7f7f7f7f79dbaf7f7f7f7f7f76300000000000000
-0000000000000083f7f7f7f7f7f79dbaf7f7f7f7f7f76300000000000000
-c6c6c6c6c6c6c6e0f7f7f7f7f6f5d0d6f4f7f7f7f7f7dac6c6c6c6c6c6c6
-0000000000000083f7f7f7f7f2ed324fe9f7f7f7f7f76300000000000000
-0000000000000083f7f7f7f7f2ed324fe9f7f7f7f7f76300000000000000
-c6c6c6c6c6c6c6e0f7f7f7f7f7d2c6c7d7f7f7f7f7f7dac6c6c6c6c6c6c6
-0000000000000083f7f7f7f7f73c000355f7f7f7f7f76300000000000000
-0000000000000083f7f7f7f7f73c000356f7f7f7f7f76300000000000000
-c6c6c6c6c6c6c6e0f7f7f7f1f7dac6c6e0f7f1f7f7f7dac6c6c6c6c6c6c6
-0000000000000083f7f7f7d7f764000081f6d9f7f7f76300000000000000
-0000000000000083f7f7f7d8f764000081f6d9f7f7f76300000000000000
-c6c6c6c6c6c6c6e0f7ede8d6d5e1c6c6e5d1dbe6f0f7dac6c6c6c6c6c6c6
-0000000000000083f7c4a951488a00009a3869a0d2f76300000000000000
-0000000000000083f7c4a952488a00009a386aa0d2f76300000000000000
-c6c6c6c6c6c6c6e0f7f3c7c6c6c7c6c6c7c6c6caf6f7dac6c6c6c6c6c6c6
-0000000000000083f7e106000003000002000014f0f76300000000000000
-0000000000000083f7e106000003000002000014f0f76300000000000000
-c6c6c6c6c6c6c6e0f7efcbc6c6c6c6c6c6c6c6cff1f7dac6c6c6c6c6c6c6
-0000000000000083f7cd1b00000000000000002bd9f76300000000000000
-0000000000000083f7cd1b00000000000000002bd9f76300000000000000
-c6c6c6c6c6c6c6e0f7f7eeddccc6c6c6c6cedff0f7f7dac6c6c6c6c6c6c6
-0000000000000083f7f7c87420000000002a7ed2f7f76300000000000000
-0000000000000083f7f7c87420000000002a7ed2f7f76300000000000000
-c6c6c6c6c6c6c6e0f7f7f7f7d7c6c7c7c6ddf7f7f7f7dac6c6c6c6c6c6c6
-0000000000000083f7f7f7f7560003030072f7f7f7f76300000000000000
-0000000000000083f7f7f7f7560003030073f7f7f7f76300000000000000
-c6c6c6c6c6c6c6e0f7f7f7f6f0f5e7edf4f0f7f7f7f7dac6c6c6c6c6c6c6
-0000000000000083f7f7f7f2d6eaa8c4e8d4f6f7f7f76300000000000000
-0000000000000083f7f7f7f2d6eaa8c5e8d5f6f7f7f76300000000000000
-c6c6c6c6c6c6c6e0f7f7f7f7f7f7e6ecf7f7f7f7f7f7dac6c6c6c6c6c6c6
-0000000000000083f7f7f7f7f7f7a3c0f7f7f7f7f7f76300000000000000
-0000000000000083f7f7f7f7f7f7a4c1f7f7f7f7f7f76300000000000000
-c6c6c6c6c6c6c6e0f7f7f7f7f7f7e6ebf7f7f7f7f7f7dac6c6c6c6c6c6c6
-0000000000000083f7f7f7f7f7f79fbcf7f7f7f7f7f76300000000000000
-0000000000000083f7f7f7f7f7f79fbcf7f7f7f7f7f76300000000000000
-c6c6c6c6c6c6c6e0f7f7f7f7f7f7f5f6f7f7f7f7f7f7dac6c6c6c6c6c6c6
-0000000000000083f7f7f7f7f7f7edf0f7f7f7f7f7f76300000000000000
-0000000000000083f7f7f7f7f7f7edf0f7f7f7f7f7f76300000000000000
-c6c6c6c6c6c6c6e0f7f7f7f7f7f7f7f7f7f7f7f7f7f7dac6c6c6c6c6c6c6
-0000000000000083f7f7f7f7f7f7f7f7f7f7f7f7f7f76300000000000000
-0000000000000083f7f7f7f7f7f7f7f7f7f7f7f7f7f76300000000000000
-c6c6c6c6c6c6c6e0f7f7f7f7f7f7f7f7f7f7f7f7f7f7dac6c6c6c6c6c6c6
-0000000000000083f7f7f7f7f7f7f7f7f7f7f7f7f7f76300000000000000
-0000000000000083f7f7f7f7f7f7f7f7f7f7f7f7f7f76300000000000000
-c6c6c6c6c6c6c6e0f7f7f7f7f7f7f7f7f7f7f7f7f7f7dac6c6c6c6c6c6c6
-0000000000000083f7f7f7f7f7f7f7f7f7f7f7f7f7f76300000000000000
-0000000000000083f7f7f7f7f7f7f7f7f7f7f7f7f7f76300000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000c6c6c6c6c6c6c6def7f7f7f7f7f7f7f7f7f7f7f7f7f7de
+c6c6c6c6c6c6c60000000000000000007bf7f7f7f7f7f7f7f7f7f7f7f7f7
+f778000000000000000000000000000000007bf7f7f7f7f7f7f7f7f7f7f7
+f7f7f779000000000000000000c6c6c6c6c6c6c6def7f7f7f7f7f7f7f7f7
+f7f7f7f7f7dec6c6c6c6c6c6c60000000000000000007bf7f7f7f7f7f7f7
+f7f7f7f7f7f7f778000000000000000000000000000000007bf7f7f7f7f7
+f7f7f7f7f7f7f7f7f779000000000000000000c6c6c6c6c6c6c6def7f7f7
+f7f7f7f7f7f7f7f7f7f7f7dec6c6c6c6c6c6c60000000000000000007bf7
+f7f7f7f7f7f7f7f7f7f7f7f7f77800000000000000000000000000000000
+7bf7f7f7f7f7f7f7f7f7f7f7f7f7f779000000000000000000c6c6c6c6c6
+c6c6def7f7f7f7f7f7f7f7f7f7f7f7f7f7dec6c6c6c6c6c6c60000000000
+000000007bf7f7f7f7f7f7f5f5f7f7f7f7f7f77800000000000000000000
+0000000000007bf7f7f7f7f7f7f5f5f7f7f7f7f7f7790000000000000000
+00c6c6c6c6c6c6c6def7f7f7f7f7f7e8e8f7f7f7f7f7f7dec6c6c6c6c6c6
+c60000000000000000007bf7f7f7f7f7f7adadf7f7f7f7f7f77800000000
+0000000000000000000000007bf7f7f7f7f7f7adadf7f7f7f7f7f7790000
+00000000000000c6c6c6c6c6c6c6def7f7f7f7f7f5d3d3f5f7f7f7f7f7de
+c6c6c6c6c6c6c60000000000000000007bf7f7f7f7f5ec4242ecf5f7f7f7
+f778000000000000000000000000000000007bf7f7f7f7f5ec4242ecf5f7
+f7f7f779000000000000000000c6c6c6c6c6c6c6def7f7f7f7f7d5c6c6d5
+f7f7f7f7f7dec6c6c6c6c6c6c60000000000000000007bf7f7f7f7f74a01
+014af7f7f7f7f778000000000000000000000000000000007bf7f7f7f7f7
+4a01014af7f7f7f7f779000000000000000000c6c6c6c6c6c6c6def7f7f7
+f2f7dcc6c6dcf7f2f7f7f7dec6c6c6c6c6c6c60000000000000000007bf7
+f7f7dcf76f00006ff7dcf7f7f77800000000000000000000000000000000
+7bf7f7f7dcf76f00006ff7dcf7f7f779000000000000000000c6c6c6c6c6
+c6c6def7eee9d9d5e4c6c6e4d5d9e9eef7dec6c6c6c6c6c6c60000000000
+000000007bf7caaf5e4995000095495eafcaf77800000000000000000000
+0000000000007bf7caaf5f4996000096495fafcaf7790000000000000000
+00c6c6c6c6c6c6c6def7f4c8c6c6c7c6c6c7c6c6c8f3f7dec6c6c6c6c6c6
+c60000000000000000007bf7e508000004000004000008e5f77800000000
+0000000000000000000000007bf7e508000004000004000008e5f7790000
+00000000000000c6c6c6c6c6c6c6def7f0cdc6c6c6c6c6c6c6c6cdf0f7de
+c6c6c6c6c6c6c60000000000000000007bf7d222000000000000000022d2
+f778000000000000000000000000000000007bf7d2220000000000000000
+22d2f779000000000000000000c6c6c6c6c6c6c6def7f7ecdccbc6c6c6c6
+cbdcecf7f7dec6c6c6c6c6c6c60000000000000000007bf7f6c16d1b0000
+00001b6dc0f6f778000000000000000000000000000000007bf7f6c16d1b
+000000001b6dc1f6f779000000000000000000c6c6c6c6c6c6c6def7f7f7
+f7dbc6c6c6c6dbf7f7f7f7dec6c6c6c6c6c6c60000000000000000007bf7
+f7f7f76b000000006bf7f7f7f77800000000000000000000000000000000
+7bf7f7f7f76b000000006bf7f7f7f779000000000000000000c6c6c6c6c6
+c6c6def7f7f7f7eef2e9e9f2eef6f7f7f7dec6c6c6c6c6c6c60000000000
+000000007bf7f7f7f4c8dcb0b0dcc8f4f7f7f77800000000000000000000
+0000000000007bf7f7f7f4c9dcb0b0dcc9f4f7f7f7790000000000000000
+00c6c6c6c6c6c6c6def7f7f7f7f7f7e9e9f7f7f7f7f7f7dec6c6c6c6c6c6
+c60000000000000000007bf7f7f7f7f7f7b2b2f7f7f7f7f7f77800000000
+0000000000000000000000007bf7f7f7f7f7f7b2b2f7f7f7f7f7f7790000
+00000000000000c6c6c6c6c6c6c6def7f7f7f7f7f7e9e9f7f7f7f7f7f7de
+c6c6c6c6c6c6c60000000000000000007bf7f7f7f7f7f7aeaef7f7f7f7f7
+f778000000000000000000000000000000007bf7f7f7f7f7f7aeaef7f7f7
+f7f7f779000000000000000000c6c6c6c6c6c6c6def7f7f7f7f7f7f4f4f7
+f7f7f7f7f7dec6c6c6c6c6c6c60000000000000000007bf7f7f7f7f7f7ea
+e9f7f7f7f7f7f778000000000000000000000000000000007bf7f7f7f7f7
+f7eaeaf7f7f7f7f7f779000000000000000000c6c6c6c6c6c6c6def7f7f7
+f7f7f7f7f7f7f7f7f7f7f7dec6c6c6c6c6c6c60000000000000000007bf7
+f7f7f7f7f7f7f7f7f7f7f7f7f77800000000000000000000000000000000
+7bf7f7f7f7f7f7f7f7f7f7f7f7f7f779000000000000000000c6c6c6c6c6
+c6c6def7f7f7f7f7f7f7f7f7f7f7f7f7f7dec6c6c6c6c6c6c60000000000
+000000007bf7f7f7f7f7f7f7f7f7f7f7f7f7f77800000000000000000000
+0000000000007bf7f7f7f7f7f7f7f7f7f7f7f7f7f7790000000000000000
+00c6c6c6c6c6c6c6def7f7f7f7f7f7f7f7f7f7f7f7f7f7dec6c6c6c6c6c6
+c60000000000000000007bf7f7f7f7f7f7f7f7f7f7f7f7f7f77800000000
+0000000000000000000000007bf7f7f7f7f7f7f7f7f7f7f7f7f7f7790000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/canada.gif b/Docs/Flags/canada.gif
index 322d4b985b7..af672caf33d 100644
--- a/Docs/Flags/canada.gif
+++ b/Docs/Flags/canada.gif
Binary files differ
diff --git a/Docs/Flags/canada.pdf b/Docs/Flags/canada.pdf
new file mode 100644
index 00000000000..4ba0fd45ec6
--- /dev/null
+++ b/Docs/Flags/canada.pdf
Binary files differ
diff --git a/Docs/Flags/chile.eps b/Docs/Flags/chile.eps
index 8a5411a32a3..121bf0a51b3 100644
--- a/Docs/Flags/chile.eps
+++ b/Docs/Flags/chile.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: chile.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-08080808080808080811f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-0000000000000000000af7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-08080808272008080811f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-0000000020190000000af7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-b5b5b5b5bebcb5b5b5b8f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-08080808776e08080811f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-0000000073690000000af7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-b5b5b5b5d4d1b5b5b5b8f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-08080808c7bd08080811f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-00000000c5bb0000000af7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-b5b5b5b5eae7b5b5b5b8f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-0868e3e9f7f6e9e16111f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-0062e2e8f7f6e8e05b0af7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-b5cff1f3f7f7f3f1cdb8f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-08083eddf7f7d9390811f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-000038dcf7f7d833000af7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-b5b5c4f0f7f7efc3b5b8f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-080808c1f7f7b8080811f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-000000bff7f7b500000af7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-b5b5b5e8f7f7e5b5b5b8f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-08081fe86066e8190811f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-000018e85b61e711000af7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-b5b5bbf3cdcff3bab5b8f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-08083a2808082c360811f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-000033210000262f000af7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-b5b5c3beb5b5bfc2b5b8f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-0e0e0e0e0e0e0e0e0e17f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6
-00000000000000000009f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0
-b0b0b0b0b0b0b0b0b0b3f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000101010101010101010101010101010101010101
-010101010101010101010101010101010101010101010101010101010101
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
+0000000000000008080808080808080808f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7000000000000000000000000f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000b5b5b5b5b5b5b5b5b5b5f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7000008080808232408080808f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f70000000000001c1c00000000f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000b5b5b5b5bcbdb5b5b5b5f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7000008080808727208080808f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000000000006d6d000000
+00f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000b5b5b5b5d2d2b5
+b5b5b5f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7000008080808c2
+c208080808f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000000000
+00c0c000000000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000b5
+b5b5b5e8e8b5b5b5b5f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700
+000866dfe5f6f6e5e06708f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f700000062dee4f6f6e4de6200f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000b5cff0f2f7f7f2f0cfb5f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f70000080841def7f7de410808f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7000000003bddf7f7dd3b0000f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000b5b5c5f0f7f7f0c5b5b5f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f70000080808bcf7f7bc080808f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f70000000000baf7f7ba000000f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000b5b5b5e7f7f7e7b5b5b5f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7000008081beb6969eb1c0808f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000000014ea6565ea1400
+00f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000b5b5baf4d0d0f4
+bab5b5f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7000008083b2f08
+082e3b0808f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000000034
+28000028340000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000b5
+b5c3c0b5b5c0c3b5b5f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700
+0008080808080808080808f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7000000000000000000000000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000b5b5b5b5b5b5b5b5b5b5f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f70000c4c4c4c4c4c4c4c4c4c4c7c7c7c7c7c7c7c7c7c7c7c7c7
+c7c7c7c7c7c7c70000000000000000000000000303030303030303030303
+030303030303030303000002020202020202020202030303030303030303
+03030303030303030303030000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/chile.gif b/Docs/Flags/chile.gif
index e7afe88df8b..dcd21381a0a 100644
--- a/Docs/Flags/chile.gif
+++ b/Docs/Flags/chile.gif
Binary files differ
diff --git a/Docs/Flags/chile.pdf b/Docs/Flags/chile.pdf
new file mode 100644
index 00000000000..6a1bfb10c0a
--- /dev/null
+++ b/Docs/Flags/chile.pdf
Binary files differ
diff --git a/Docs/Flags/china.eps b/Docs/Flags/china.eps
index 97b87f4727f..d76667bb762 100644
--- a/Docs/Flags/china.eps
+++ b/Docs/Flags/china.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: china.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c7e1c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000037602000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6cfc6c6c6c9c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000250000000e00000000000000000000000000000000000000000000
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6efc9c6c6c7e1c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000b70e00000377010000000000000000000000000000000000000000
+00000000000000000000000000c6c6c6c6c6c6c7e1c7c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000027602000000000000
000000000000000000000000000000000000000000000000000000000000
-c6d7f4fef7e2c7c6c9c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-004bccfcda7d03000d000000000000000000000000000000000000000000
+00000000000000000000000000000000000000c6c6c6cec6c6c6cac6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000240000001000
000000000000000000000000000000000000000000000000000000000000
-c6c6e2fff2c6c6c7d3c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-00007dffc301000338010000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000c6c6c6eeca
+c6c6c7e1c7c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
+b41000000276020000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6e5d4e9c8c6c6d7c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-00008a3b9c0a00004c000000000000000000000000000000000000000000
+00c6d7f3fef7e3c7c6cac6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000004ac8fbd88103000f000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c7c6c6c7c7d0c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000003000003042a00000000000000000000000000000000000000000000
+00000000000000c6c6e2fff3c6c6c7d1c7c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6000000007cffc901000233020000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6dac6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000015800000000000000000000000000000000000000000000
+00000000000000000000000000c6c6e6d5eac9c6c6d9c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6000000008c42a20b000053000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000000000000000c6c6c7c6c6c7c7cec6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000005000005032301
000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000c6c6c6c6c6
+c6c6dcc6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
+000000016100000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/china.gif b/Docs/Flags/china.gif
index 4baf243f158..6e0c5eb42aa 100644
--- a/Docs/Flags/china.gif
+++ b/Docs/Flags/china.gif
Binary files differ
diff --git a/Docs/Flags/china.pdf b/Docs/Flags/china.pdf
new file mode 100644
index 00000000000..9706ee48a28
--- /dev/null
+++ b/Docs/Flags/china.pdf
Binary files differ
diff --git a/Docs/Flags/costa-rica.eps b/Docs/Flags/costa-rica.eps
new file mode 100644
index 00000000000..b225246c0c7
--- /dev/null
+++ b/Docs/Flags/costa-rica.eps
@@ -0,0 +1,98 @@
+%!PS-Adobe-2.0 EPSF-2.0
+%%Creator: pnmtops
+%%Title: costa-rica.ps
+%%Pages: 1
+%%BoundingBox: 290 385 321 407
+%%EndComments
+/readstring {
+ currentfile exch readhexstring pop
+} bind def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
+%%EndProlog
+%%Page: 1 1
+gsave
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
+{ rpicstr readstring }
+{ gpicstr readstring }
+{ bpicstr readstring }
+true 3
+colorimage
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000808080808080808080808080808080808080808080808
+080808080808080000000000000000000000000000000000000000000000
+0000000000000000000000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b500000808080808080808080808080808080808
+080808080808080808080808080000000000000000000000000000000000
+0000000000000000000000000000000000b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500000808080808080808080808
+080808080808080808080808080808080808080000000000000000000000
+0000000000000000000000000000000000000000000000b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b50000a6a6a6a6a6
+a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a60000a3a3a3
+a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a30000e1
+e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e100
+00f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f70000e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7
+e7e7e7e7e7e7e7e7e7e7e7e7e70000a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7
+a7a7a7a7a7a7a7a7a7a7a7a7a7a7a70000a7a7a7a7a7a7a7a7a7a7a7a7a7
+a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a70000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000e7e7e7e7e7
+e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e70000a7a7a7
+a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a70000a7
+a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a700
+00f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f70000a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9
+a9a9a9a9a9a9a9a9a9a9a9a9a90000a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7
+a7a7a7a7a7a7a7a7a7a7a7a7a7a7a70000e2e2e2e2e2e2e2e2e2e2e2e2e2
+e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e200000808080808080808080808
+080808080808080808080808080808080808080000000000000000000000
+0000000000000000000000000000000000000000000000b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500000808080808
+080808080808080808080808080808080808080808080808080000000000
+0000000000000000000000000000000000000000000000000000000000b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500
+000808080808080808080808080808080808080808080808080808080808
+080000000000000000000000000000000000000000000000000000000000
+0000000000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b500000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/costa-rica.gif b/Docs/Flags/costa-rica.gif
new file mode 100644
index 00000000000..becc817fdcc
--- /dev/null
+++ b/Docs/Flags/costa-rica.gif
Binary files differ
diff --git a/Docs/Flags/costa-rica.pdf b/Docs/Flags/costa-rica.pdf
new file mode 100644
index 00000000000..881d2018d83
--- /dev/null
+++ b/Docs/Flags/costa-rica.pdf
Binary files differ
diff --git a/Docs/Flags/island.gif b/Docs/Flags/costa-rica.txt
index e69de29bb2d..e69de29bb2d 100644
--- a/Docs/Flags/island.gif
+++ b/Docs/Flags/costa-rica.txt
diff --git a/Docs/Flags/czech-republic.eps b/Docs/Flags/czech-republic.eps
index afa50e9a82d..c179b95db17 100644
--- a/Docs/Flags/czech-republic.eps
+++ b/Docs/Flags/czech-republic.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: czech-republic.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-56e2f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-50e1f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-caf1f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-081ba5f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-0014a2f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-b5bae0f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-08080856e2f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-00000050e1f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-b5b5b5caf1f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-080808081ba5f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-0000000014a2f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-b5b5b5b5bae0f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-08080808080856e2f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-00000000000050e1f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-b5b5b5b5b5b5caf1f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-080808080808081ba5f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-0000000000000014a2f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-b5b5b5b5b5b5b5bae0f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-08080808080808080856e2f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-00000000000000000050e1f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-b5b5b5b5b5b5b5b5b5cbf1f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-080808080808080808081ba5f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-0000000000000000000014a3f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-b5b5b5b5b5b5b5b5b5b5bae0f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-08080808080808080808080856e2f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-00000000000000000000000050e1f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-b5b5b5b5b5b5b5b5b5b5b5b5caf1f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-080808080808080808080808081ba6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6
-0000000000000000000000000014a3f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0
-b5b5b5b5b5b5b5b5b5b5b5b5b5bae0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0
-080808080808080808080808081f93c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000000010101010101010101010101010101
-b5b5b5b5b5b5b5b5b5b5b5b5b59f31010101010101010101010101010101
-08080808080808080808080954bcc6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b46d0a00000000000000000000000000000000
-080808080808080808081f93c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b59f31000000000000000000000000000000000000
-08080808080808080954bcc6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b46d0a00000000000000000000000000000000000000
-080808080808081f92c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+0000000000000056e2f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7000050e1f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000caf1f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f70000081ba5f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f700000013a2f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000b5bae0f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7000008080856e2f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7000000000050e1f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000b5b5b5caf1f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000080808081b
+a5f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000000000
+0013a2f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000b5
+b5b5b5bae0f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700
+0008080808080856e2f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7000000000000000050e1f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000b5b5b5b5b5b5caf1f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f70000080808080808081ba5f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f700000000000000000013a2f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000b5b5b5b5b5b5b5bae0f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7000008080808080808080856e2f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7000000000000000000000050e1f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000b5b5b5b5b5b5b5b5b5caf1f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000080808080808080808081b
+a5f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000000000000000000000
+0013a2f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000b5b5b5b5b5b5b5
+b5b5b5bae0f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700000808080808
+0808080808080856e2f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000000000
+00000000000000000050e1f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000b5
+b5b5b5b5b5b5b5b5b5b5b5caf1f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700
+00080808080808080808080808081ba5f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f700000000000000000000000000000013a2f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000b5b5b5b5b5b5b5b5b5b5b5b5b5bae0f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f70000080808080808080808080808081784c7c7c7c7c7c7c7c7
+c7c7c7c7c7c7c70000000000000000000000000000000000030303030303
+0303030303030303030000b5b5b5b5b5b5b5b5b5b5b5b5b5a73f03030303
+0303030303030303030303000008080808080808080808080845b5c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000000
+0000000000000000000000000000000000b5b5b5b5b5b5b5b5b5b5b5b57b
+100000000000000000000000000000000000000808080808080808080817
+84c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
+0000000000000000000000000000000000000000000000b5b5b5b5b5b5b5
+b5b5b5a73f00000000000000000000000000000000000000000808080808
+0808080845b5c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
+0000000000000000000000000000000000000000000000000000000000b5
+b5b5b5b5b5b5b5b57b100000000000000000000000000000000000000000
+00080808080808081784c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
+0000000000b5b5b5b5b5b5b5a73f00000000000000000000000000000000
+0000000000000008080808080845b5c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
+0000000000000000000000b5b5b5b5b5b57b100000000000000000000000
+00000000000000000000000000080808081784c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000000
+0000000000000000000000000000000000b5b5b5b5a73f00000000000000
+0000000000000000000000000000000000000008080845b5c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
+0000000000000000000000000000000000000000000000b5b5b57b100000
+00000000000000000000000000000000000000000000000000081784c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
+0000000000000000000000000000000000000000000000000000000000b5
+a73f00000000000000000000000000000000000000000000000000000000
+0045b5c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
+00000000007b100000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b59f31000000000000000000000000000000000000000000
-08080808080954bcc6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b46d0a00000000000000000000000000000000000000000000
-080808081f93c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
-b5b5b5b59f31000000000000000000000000000000000000000000000000
-08080954bcc6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000000000000000000000000000000000000
-b5b5b46d0a00000000000000000000000000000000000000000000000000
-081f92c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000000000000000000000000000000000000
-b59f31000000000000000000000000000000000000000000000000000000
-53bcc6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000000000000000000000000000000000000
-6e0a00000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/czech-republic.gif b/Docs/Flags/czech-republic.gif
index 10d5a3c72e9..eeaeb4b791b 100644
--- a/Docs/Flags/czech-republic.gif
+++ b/Docs/Flags/czech-republic.gif
Binary files differ
diff --git a/Docs/Flags/czech-republic.pdf b/Docs/Flags/czech-republic.pdf
new file mode 100644
index 00000000000..7fb2680269f
--- /dev/null
+++ b/Docs/Flags/czech-republic.pdf
Binary files differ
diff --git a/Docs/Flags/denmark.eps b/Docs/Flags/denmark.eps
index 2f397c4af16..c3ddf74f725 100644
--- a/Docs/Flags/denmark.eps
+++ b/Docs/Flags/denmark.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: denmark.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-c7c7c7c7c7c7c7c9fffffffac7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c8
-0000000000000008fffffff0000000000000000000000000000000000000
-0000000000000008ffffffe9000000000000000000000000000000000000
-c7c7c7c7c7c7c7c9fffffffac7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c8
-0000000000000008fffffff0000000000000000000000000000000000000
-0000000000000008ffffffe9000000000000000000000000000000000000
-c7c6c7c6c6c6c7c9fffffffac7c6c6c6c6c6c6c6c6c6c6c6c6c6c7c6c7c8
-0000000000000008fffffff0000000000000000000000000000000000000
-0000000000000008ffffffe9000000000000000000000000000000000000
-c7c7c7c6c7c7c7c9fffffff9c7c7c7c6c6c6c6c6c6c6c6c6c6c7c7c7c7c8
-0000000000000008fffffff0000000000000000000000000000000000000
-0000000000000008ffffffe9000000000000000000000000000000000000
-c7c6c7c7c7c7c7c9fffffffac7c7c7c7c7c7c7c7c7c7c7c6c7c7c6c7c7c8
-0000000000000008fffffff0000000000000000000000000000000000000
-0000000000000008ffffffe9000000000000000000000000000000000000
-c7c7c6c7c7c7c7c8fffffffac7c7c7c7c6c6c6c6c6c6c7c7c6c7c6c7c7c8
-0000000000000008fffffff0000000000000000000000000000000000000
-0000000000000008ffffffe9000000000000000000000000000000000000
-c7c7c7c7c7c7c7c9fffffff9c7c7c7c7c6c6c6c6c6c6c7c7c7c7c7c7c7c8
-0000000000000008fffffff0000000000000000000000000000000000000
-0000000000000008ffffffe9000000000000000000000000000000000000
-c7c7c7c7c7c7c6c9fffffffac6c7c7c7c7c6c6c6c7c7c7c7c7c7c6c7c7c8
-060606060606060efffffff0060606060606060606060606060606060606
-020202020202020affffffe9020202020202020202020202020202020202
-fefefefefefefefefffffffffefefefefefefefefefefefefefefefefefe
-fefefefefefefefefffffffffefefefefefefefefefefefefefefefefefe
-fbfbfbfbfbfbfbfbfffffffffbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfb
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-fdfdfdfdfdfdfdfdfffffffffdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfd
-f3f3f3f3f3f3f3f3fffffffef3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3
-f3f3f3f3f3f3f3f3fffffffef3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3
-c7c7c6c6c6c6c6c8fffffff9c7c6c6c6c7c6c6c6c6c6c7c6c6c6c6c6c6c8
-0000000000000008fffffff0000000000000000000000000000000000000
-0000000000000008ffffffe9000000000000000000000000000000000000
-c7c6c6c7c7c7c7c8fffffff9c7c7c7c7c7c7c7c7c7c7c6c6c6c6c7c6c7c8
-0000000000000008fffffff0000000000000000000000000000000000000
-0000000000000008ffffffe9000000000000000000000000000000000000
-c7c7c7c7c7c7c7c8fffffffac7c7c7c7c7c7c7c7c7c7c6c7c7c7c7c7c7c8
-0000000000000008fffffff0000000000000000000000000000000000000
-0000000000000008ffffffe9000000000000000000000000000000000000
-c7c7c7c7c7c7c6c8fffffffac7c7c7c7c7c7c6c7c6c7c7c6c7c7c7c7c7c8
-0000000000000008fffffff0000000000000000000000000000000000000
-0000000000000008ffffffe9000000000000000000000000000000000000
-c6c7c7c7c7c7c7c8fffffff9c7c7c7c7c7c7c7c6c7c7c7c7c7c7c6c7c7c8
-0000000000000008fffffff0000000000000000000000000000000000000
-0000000000000008ffffffe9000000000000000000000000000000000000
-c7c7c7c7c6c7c7c9fffffff9c7c6c7c7c6c7c7c7c7c7c7c6c7c7c7c6c7c7
-0000000000000008fffffff0000000000000000000000000000000000000
-0000000000000008ffffffe9000000000000000000000000000000000000
-c7c7c7c7c7c6c6c8fffffffac6c7c7c7c7c6c7c7c6c7c7c6c7c7c7c7c7c8
-0000000000000008fffffff0000000000000000000000000000000000000
-0000000000000008ffffffe9000000000000000000000000000000000000
-c7c7c7c7c7c7c6c9fffffffac6c7c6c7c6c6c6c7c7c7c7c7c6c7c6c7c7c8
-0000000000000008fffffff0000000000000000000000000000000000000
-0000000000000008ffffffe9000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000c7c7c7c7c7c7c7c7fffffffcc7c7c7c7c7c6c7c7c7c7c7
+c6c7c7c7c7c7c700000000000000000000fffffffc000000000000000000
+00000000000000000000000000000000000000fffffff500000000000000
+00000000000000000000000000c7c7c7c7c7c7c7c7fffffffcc7c7c7c7c7
+c7c7c7c7c7c7c7c7c7c7c7c7c700000000000000000000fffffffc000000
+00000000000000000000000000000000000000000000000000fffffff500
+00000000000000000000000000000000000000c7c6c7c6c6c6c7c7ffffff
+fcc7c6c6c6c6c6c6c6c6c6c6c6c6c6c7c7c7c700000000000000000000ff
+fffffc000000000000000000000000000000000000000000000000000000
+00fffffff50000000000000000000000000000000000000000c7c7c7c6c7
+c7c7c7fffffffcc6c7c7c6c6c6c6c6c6c6c6c6c6c7c6c7c7c70000000000
+0000000000fffffffc000000000000000000000000000000000000000000
+00000000000000fffffff500000000000000000000000000000000000000
+00c7c6c7c7c7c6c7c7fffffffcc6c7c7c7c7c7c7c7c7c7c7c7c7c7c6c7c7
+c700000000000000000000fffffffc000000000000000000000000000000
+00000000000000000000000000fffffff500000000000000000000000000
+00000000000000c7c7c6c7c7c7c7c7fffffffcc7c7c6c7c6c6c6c6c6c6c6
+c7c6c7c7c7c6c700000000000000000000fffffffc000000000000000000
+00000000000000000000000000000000000000fffffff500000000000000
+00000000000000000000000000c7c7c7c6c7c6c7c7fffffffcc6c7c7c7c6
+c6c6c6c6c7c7c6c7c7c6c7c6c700000000000000000000fffffffc000000
+00000000000000000000000000000000000000000000000000fffffff500
+00000000000000000000000000000000000000c7c7c7c7c7c7c6c7ffffff
+fcc7c6c7c6c6c7c7c6c7c7c7c7c7c7c7c6c7c700000000000000000000ff
+fffffc000000000000000000000000000000000000000000000000000000
+00fffffff50000000000000000000000000000000000000000fcfcfcfcfc
+fcfcfcfffffffffcfcfcfcfcfcfbfcfcfcfcfbfcfcfcfcfcfc0000fcfcfc
+fcfcfcfcfcfffffffffcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfc0000f5
+f5f5f5f5f5f5f5fffffffff5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f500
+00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffff0000c7c7c7c6c7c7c6c6ffffff
+fcc6c6c6c7c7c6c6c7c7c7c7c6c6c6c7c7c7c700000000000000000000ff
+fffffc000000000000000000000000000000000000000000000000000000
+00fffffff50000000000000000000000000000000000000000c7c7c6c6c7
+c6c7c7fffffffcc6c7c7c7c7c7c7c6c7c6c6c7c7c7c7c6c7c70000000000
+0000000000fffffffc000000000000000000000000000000000000000000
+00000000000000fffffff500000000000000000000000000000000000000
+00c7c6c6c7c7c6c7c7fffffffcc7c7c7c7c7c6c7c6c7c6c7c7c7c6c7c7c7
+c700000000000000000000fffffffc000000000000000000000000000000
+00000000000000000000000000fffffff500000000000000000000000000
+00000000000000c7c6c7c7c7c7c6c7fffffffcc7c6c6c6c7c7c7c7c7c7c7
+c7c7c6c7c7c7c700000000000000000000fffffffc000000000000000000
+00000000000000000000000000000000000000fffffff500000000000000
+00000000000000000000000000c7c7c7c6c7c7c7c7fffffffcc6c6c6c7c6
+c7c6c7c6c7c7c6c7c7c7c6c7c700000000000000000000fffffffc000000
+00000000000000000000000000000000000000000000000000fffffff500
+00000000000000000000000000000000000000c7c7c7c7c7c6c7c7ffffff
+fcc7c7c7c6c7c7c7c7c6c7c6c6c7c6c7c7c6c700000000000000000000ff
+fffffc000000000000000000000000000000000000000000000000000000
+00fffffff50000000000000000000000000000000000000000c7c7c7c7c6
+c6c6c6fffffffcc6c6c7c7c6c7c7c6c7c6c7c7c7c7c7c6c6c70000000000
+0000000000fffffffc000000000000000000000000000000000000000000
+00000000000000fffffff500000000000000000000000000000000000000
+00c7c7c6c7c7c7c7c7fffffffcc6c7c6c6c7c7c7c7c7c7c6c7c6c6c7c7c7
+c700000000000000000000fffffffc000000000000000000000000000000
+00000000000000000000000000fffffff500000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/denmark.gif b/Docs/Flags/denmark.gif
index 1d8e687adcc..b2cda874fce 100644
--- a/Docs/Flags/denmark.gif
+++ b/Docs/Flags/denmark.gif
Binary files differ
diff --git a/Docs/Flags/denmark.pdf b/Docs/Flags/denmark.pdf
new file mode 100644
index 00000000000..c405a7b0f11
--- /dev/null
+++ b/Docs/Flags/denmark.pdf
Binary files differ
diff --git a/Docs/Flags/estonia.eps b/Docs/Flags/estonia.eps
index e34768c3442..a73cd8eecce 100644
--- a/Docs/Flags/estonia.eps
+++ b/Docs/Flags/estonia.eps
@@ -1,48 +1,57 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: estonia.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-080808080808080808080808080808080808080808080808080808080808
000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080808080808080808080808080808080808080808080808
000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080808080808080808080808080808080808080808080808
000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080808080808080808080808080808080808080808080808
+000000000000000808080808080808080808080808080808080808080808
+080808080808080000000000000000000000000000000000000000000000
+0000000000000000000000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b500000808080808080808080808080808080808
+080808080808080808080808080000000000000000000000000000000000
+0000000000000000000000000000000000b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500000808080808080808080808
+080808080808080808080808080808080808080000000000000000000000
+0000000000000000000000000000000000000000000000b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500000808080808
+080808080808080808080808080808080808080808080808080000000000
+0000000000000000000000000000000000000000000000000000000000b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500
+000808080808080808080808080808080808080808080808080808080808
+080000000000000000000000000000000000000000000000000000000000
+0000000000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b500000808080808080808080808080808080808080808080808
+080808080808080000000000000000000000000000000000000000000000
+0000000000000000000000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b500000505050505050505050505050505050505
+050505050505050505050505050000000000000000000000000000000000
+00000000000000000000000000000000007a7a7a7a7a7a7a7a7a7a7a7a7a
+7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a00000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080808080808080808080808080808080808080808080808
000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080808080808080808080808080808080808080808080808
000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-050505050505050505050505050505050505050505050505050505050505
000000000000000000000000000000000000000000000000000000000000
-757575757575757575757575757575757575757575757575757575757575
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
@@ -57,31 +66,33 @@ b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000a4a4a4a4a4
+a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a40000a4a4a4
+a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a40000a4
+a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a400
+00f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700
+00f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f700000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1
-b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1
-b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/estonia.gif b/Docs/Flags/estonia.gif
index b8bbf1dbb78..ac2c62b78e9 100644
--- a/Docs/Flags/estonia.gif
+++ b/Docs/Flags/estonia.gif
Binary files differ
diff --git a/Docs/Flags/estonia.pdf b/Docs/Flags/estonia.pdf
new file mode 100644
index 00000000000..12056acb79d
--- /dev/null
+++ b/Docs/Flags/estonia.pdf
Binary files differ
diff --git a/Docs/Flags/finland.eps b/Docs/Flags/finland.eps
index c88fa4e2eaa..847a0fdd30d 100644
--- a/Docs/Flags/finland.eps
+++ b/Docs/Flags/finland.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: finland.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-f7f7f7f7f7f7f7f018181825f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f5b5b5b5b9f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f018181825f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f5b5b5b5b9f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f018181825f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f5b5b5b5b9f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f018181825f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f5b5b5b5b9f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f018181825f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f5b5b5b5b9f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f018181825f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f5b5b5b5b9f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f018181825f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f5b5b5b5b9f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f2f2f2f2f2f2f2eb18181825f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2
-f5f5f5f5f5f5f5f3b5b5b5b9f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5
-f7f7f7f7f7f7f7f7efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-191919191919191918181818191919191919191919191919191919191919
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
-181818181818181818181818181818181818181818181818181818181818
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
-181818181818181818181818181818181818181818181818181818181818
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
-222222222222222218181819222222222222222222222222222222222222
-b8b8b8b8b8b8b8b8b5b5b5b5b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
-f7f7f7f7f7f7f7f018181825f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f5b5b5b5b9f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f018181825f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f5b5b5b5b9f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f018181825f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f5b5b5b5b9f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f018181825f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f5b5b5b5b9f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f018181825f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f5b5b5b5b9f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f018181825f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f5b5b5b5b9f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f018181825f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f5b5b5b5b9f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f018181825f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f5b5b5b5b9f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000f7f7f7f7f7f7f7f71818181bf7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7b5b5b5b6f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7efefefeff7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f71818181bf7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7b5b5b5b6f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7efefefeff7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7181818
+1bf7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7b5
+b5b5b6f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7
+f7f7f71818181bf7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7
+f7f7f7f7f7b5b5b5b6f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7
+f7f7f7f7f7f7f7efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700
+00f7f7f7f7f7f7f7f71818181bf7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f7b5b5b5b6f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f7efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f70000f7f7f7f7f7f7f7f71818181bf7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7b5b5b5b6f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7efefefeff7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f71818181bf7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7b5b5b5b6f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7efefefeff7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7181818
+1bf7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7b5
+b5b5b6f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700001b1b1b1b1b
+1b1b1b181818181b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b0000b6b6b6
+b6b6b6b6b6b5b5b5b5b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b60000ef
+efefefefefefefefefefefefefefefefefefefefefefefefefefefefef00
+001818181818181818181818181818181818181818181818181818181818
+180000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b50000efefefefefefefefefefefefefefefefefefefefefefefefef
+efefefefef00001818181818181818181818181818181818181818181818
+181818181818180000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b50000efefefefefefefefefefefefefefefefefefef
+efefefefefefefefefefef00001818181818181818181818181818181818
+181818181818181818181818180000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b50000efefefefefefefefefefefefef
+efefefefefefefefefefefefefefefefef0000f7f7f7f7f7f7f7f7181818
+1bf7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7b5
+b5b5b6f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7
+f7f7f71818181bf7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7
+f7f7f7f7f7b5b5b5b6f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7
+f7f7f7f7f7f7f7efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700
+00f7f7f7f7f7f7f7f71818181bf7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f7b5b5b5b6f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f7efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f70000f7f7f7f7f7f7f7f71818181bf7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7b5b5b5b6f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7efefefeff7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f71818181bf7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7b5b5b5b6f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7efefefeff7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7181818
+1bf7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7b5
+b5b5b6f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7
+f7f7f71818181bf7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7
+f7f7f7f7f7b5b5b5b6f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7
+f7f7f7f7f7f7f7efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700
+00f7f7f7f7f7f7f7f71818181bf7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f7b5b5b5b6f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f7efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f700000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/finland.gif b/Docs/Flags/finland.gif
index a43a398f8f1..08f367ce95c 100644
--- a/Docs/Flags/finland.gif
+++ b/Docs/Flags/finland.gif
Binary files differ
diff --git a/Docs/Flags/finland.pdf b/Docs/Flags/finland.pdf
new file mode 100644
index 00000000000..aa0506be383
--- /dev/null
+++ b/Docs/Flags/finland.pdf
Binary files differ
diff --git a/Docs/Flags/france.eps b/Docs/Flags/france.eps
index 6367b8b98ca..7d5b7fa0830 100644
--- a/Docs/Flags/france.eps
+++ b/Docs/Flags/france.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: france.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-08080808080808080814f7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-08080808080808080814f7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-08080808080808080814f7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-08080808080808080814f7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-08080808080808080814f7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-08080808080808080814f7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-08080808080808080814f7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-08080808080808080814f7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-08080808080808080814f7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-08080808080808080814f7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-08080808080808080814f7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-08080808080808080814f7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-08080808080808080814f7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-08080808080808080814f7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-08080808080808080814f7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-08080808080808080814f7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-08080808080808080814f7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-08080808080808080814f7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-08080808080808080814f7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-08080808080808080814f7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000808080808080808080bf7f7f7f7f7f7f7f7f7f7c6c6c6
+c6c6c6c6c6c6c6000000000000000000000003f7f7f7f7f7f7f7f7f7f700
+0000000000000000000000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7
+f70000000000000000000000000808080808080808080bf7f7f7f7f7f7f7
+f7f7f7c6c6c6c6c6c6c6c6c6c6000000000000000000000003f7f7f7f7f7
+f7f7f7f7f7000000000000000000000000b5b5b5b5b5b5b5b5b5b6f7f7f7
+f7f7f7f7f7f7f70000000000000000000000000808080808080808080bf7
+f7f7f7f7f7f7f7f7f7c6c6c6c6c6c6c6c6c6c60000000000000000000000
+03f7f7f7f7f7f7f7f7f7f7000000000000000000000000b5b5b5b5b5b5b5
+b5b5b6f7f7f7f7f7f7f7f7f7f70000000000000000000000000808080808
+080808080bf7f7f7f7f7f7f7f7f7f7c6c6c6c6c6c6c6c6c6c60000000000
+00000000000003f7f7f7f7f7f7f7f7f7f7000000000000000000000000b5
+b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f70000000000000000000000
+000808080808080808080bf7f7f7f7f7f7f7f7f7f7c6c6c6c6c6c6c6c6c6
+c6000000000000000000000003f7f7f7f7f7f7f7f7f7f700000000000000
+0000000000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f70000000000
+000000000000000808080808080808080bf7f7f7f7f7f7f7f7f7f7c6c6c6
+c6c6c6c6c6c6c6000000000000000000000003f7f7f7f7f7f7f7f7f7f700
+0000000000000000000000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7
+f70000000000000000000000000808080808080808080bf7f7f7f7f7f7f7
+f7f7f7c6c6c6c6c6c6c6c6c6c6000000000000000000000003f7f7f7f7f7
+f7f7f7f7f7000000000000000000000000b5b5b5b5b5b5b5b5b5b6f7f7f7
+f7f7f7f7f7f7f70000000000000000000000000808080808080808080bf7
+f7f7f7f7f7f7f7f7f7c6c6c6c6c6c6c6c6c6c60000000000000000000000
+03f7f7f7f7f7f7f7f7f7f7000000000000000000000000b5b5b5b5b5b5b5
+b5b5b6f7f7f7f7f7f7f7f7f7f70000000000000000000000000808080808
+080808080bf7f7f7f7f7f7f7f7f7f7c6c6c6c6c6c6c6c6c6c60000000000
+00000000000003f7f7f7f7f7f7f7f7f7f7000000000000000000000000b5
+b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f70000000000000000000000
+000808080808080808080bf7f7f7f7f7f7f7f7f7f7c6c6c6c6c6c6c6c6c6
+c6000000000000000000000003f7f7f7f7f7f7f7f7f7f700000000000000
+0000000000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f70000000000
+000000000000000808080808080808080bf7f7f7f7f7f7f7f7f7f7c6c6c6
+c6c6c6c6c6c6c6000000000000000000000003f7f7f7f7f7f7f7f7f7f700
+0000000000000000000000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7
+f70000000000000000000000000808080808080808080bf7f7f7f7f7f7f7
+f7f7f7c6c6c6c6c6c6c6c6c6c6000000000000000000000003f7f7f7f7f7
+f7f7f7f7f7000000000000000000000000b5b5b5b5b5b5b5b5b5b6f7f7f7
+f7f7f7f7f7f7f70000000000000000000000000808080808080808080bf7
+f7f7f7f7f7f7f7f7f7c6c6c6c6c6c6c6c6c6c60000000000000000000000
+03f7f7f7f7f7f7f7f7f7f7000000000000000000000000b5b5b5b5b5b5b5
+b5b5b6f7f7f7f7f7f7f7f7f7f70000000000000000000000000808080808
+080808080bf7f7f7f7f7f7f7f7f7f7c6c6c6c6c6c6c6c6c6c60000000000
+00000000000003f7f7f7f7f7f7f7f7f7f7000000000000000000000000b5
+b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f70000000000000000000000
+000808080808080808080bf7f7f7f7f7f7f7f7f7f7c6c6c6c6c6c6c6c6c6
+c6000000000000000000000003f7f7f7f7f7f7f7f7f7f700000000000000
+0000000000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f70000000000
+000000000000000808080808080808080bf7f7f7f7f7f7f7f7f7f7c6c6c6
+c6c6c6c6c6c6c6000000000000000000000003f7f7f7f7f7f7f7f7f7f700
+0000000000000000000000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7
+f70000000000000000000000000808080808080808080bf7f7f7f7f7f7f7
+f7f7f7c6c6c6c6c6c6c6c6c6c6000000000000000000000003f7f7f7f7f7
+f7f7f7f7f7000000000000000000000000b5b5b5b5b5b5b5b5b5b6f7f7f7
+f7f7f7f7f7f7f70000000000000000000000000808080808080808080bf7
+f7f7f7f7f7f7f7f7f7c6c6c6c6c6c6c6c6c6c60000000000000000000000
+03f7f7f7f7f7f7f7f7f7f7000000000000000000000000b5b5b5b5b5b5b5
+b5b5b6f7f7f7f7f7f7f7f7f7f70000000000000000000000000808080808
+080808080bf7f7f7f7f7f7f7f7f7f7c6c6c6c6c6c6c6c6c6c60000000000
+00000000000003f7f7f7f7f7f7f7f7f7f7000000000000000000000000b5
+b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f70000000000000000000000
+000808080808080808080bf7f7f7f7f7f7f7f7f7f7c6c6c6c6c6c6c6c6c6
+c6000000000000000000000003f7f7f7f7f7f7f7f7f7f700000000000000
+0000000000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f70000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/france.gif b/Docs/Flags/france.gif
index 13fcbf29e66..f44b729895a 100644
--- a/Docs/Flags/france.gif
+++ b/Docs/Flags/france.gif
Binary files differ
diff --git a/Docs/Flags/france.pdf b/Docs/Flags/france.pdf
new file mode 100644
index 00000000000..036e96eadef
--- /dev/null
+++ b/Docs/Flags/france.pdf
Binary files differ
diff --git a/Docs/Flags/germany.eps b/Docs/Flags/germany.eps
index 568543e3680..e06e98b1883 100644
--- a/Docs/Flags/germany.eps
+++ b/Docs/Flags/germany.eps
@@ -1,22 +1,22 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: germany.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
@@ -40,48 +40,59 @@ colorimage
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-464646464646464646464646464646464646464646464646464646464646
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000004040404040404040404040404040404040
+404040404040404040404040400000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000000000000000000000000000ececececec
+ececececececececececececececececececececececececec00008e8e8e
+8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e000000
000000000000000000000000000000000000000000000000000000000000
+00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ff0000d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6
+d6d6d6000000000000000000000000000000000000000000000000000000
+00000000000000ffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffff0000d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6
+d6d6d6d6d6d6d6d6d6000000000000000000000000000000000000000000
+00000000000000000000000000ffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffff0000d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6
+d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6000000000000000000000000000000
+00000000000000000000000000000000000000ffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffff0000d6d6d6d6d6d6d6d6d6
+d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6000000000000000000
+00000000000000000000000000000000000000000000000000ffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffff0000d6d6d6
+d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6000000
000000000000000000000000000000000000000000000000000000000000
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
-999999999999999999999999999999999999999999999999999999999999
+00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ff0000d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6
+d6d6d6000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6
000000000000000000000000000000000000000000000000000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6
-000000000000000000000000000000000000000000000000000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6
-000000000000000000000000000000000000000000000000000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6
-000000000000000000000000000000000000000000000000000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6
-000000000000000000000000000000000000000000000000000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6
000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/germany.gif b/Docs/Flags/germany.gif
index e25a855b3d2..aedbb037a32 100644
--- a/Docs/Flags/germany.gif
+++ b/Docs/Flags/germany.gif
Binary files differ
diff --git a/Docs/Flags/germany.pdf b/Docs/Flags/germany.pdf
new file mode 100644
index 00000000000..01df1c4cb3a
--- /dev/null
+++ b/Docs/Flags/germany.pdf
Binary files differ
diff --git a/Docs/Flags/great-britain.eps b/Docs/Flags/great-britain.eps
index 97a7ffc9b57..19464e1e3b7 100644
--- a/Docs/Flags/great-britain.eps
+++ b/Docs/Flags/great-britain.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: great-britain.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-cfd85508080808080808080811e4c6c6d70808080808080808080967decd
-2db24f000000000000000000099600009f0000000000000000000162ab20
-2ec2cab5b5b5b5b5b5b5b5b5b8970000aeb5b5b5b5b5b5b5b5b5b5cfb520
-ccc7dfa31b0808080808080811e4c6c6d7080808080808080825b4dbc6ce
-1c057a9c1300000000000000099600009f00000000000000001ea8670127
-1c057bdbbab5b5b5b5b5b5b5b8970000aeb5b5b5b5b5b5b5b5bdda670127
-edd9c6cfd85508080808080811e4c6c6d70808080808080967decdc7dde9
-e160012eb14f000000000000099600009f0000000000000162ab200373e3
-e760012ec2cab5b5b5b5b5b5b8970000aeb5b5b5b5b5b5b5cfb5210374ec
-2fc4e9ccc7dea31b0808080811e4c6c6d7080808080825b4dbc6ceedb423
-28c2b21c057a9c1300000000099600009f00000000001ea8670129c2b21c
-c0e9b21c057adabab5b5b5b5b8970000aeb5b5b5b5b5bdd9670129c2e4bc
-080b78edd9c6cfd85508080811e4c6c6d70808080967ddccc7dde8650908
-000373e160012db14f000000099600009f0000000162aa200373e1600100
-b5b6d4e760012dc1cab5b5b5b8970000aeb5b5b5b5cfb4200374eccfb5b5
-0808082fc4e9ccc7dea31b0811e4c6c6d7080825b4dac6ceedb423080808
-00000029c2b21d05799c1300099600009f00001ea8660129c2b21c000000
-b5b5b5c0e9b21d057adabab5b8970000aeb5b5bdd9660129c2e4bdb5b5b5
-080808080b78edd9c6cfd85511e4c6c6d70967ddccc7dde8650908080808
-000000000473e161012db14f099600009f0162aa200474e1600100000000
-b5b5b5b5b6d4e761012dc1cab8970000aeb5cfb4200475eccfb5b5b5b5b5
-0e0e0e0e0e0e35c9eaccc8dfaae4c6c6deb4dcc7cfedb9290e0e0e0e0e0e
-0606060606062ec7b31f0b7fa3960000a7aa6c072bc3b722060606060606
-b7b7b7b7b7b7c2eab31f0b7fde970000b0db6c072bc3e6beb7b7b7b7b7b7
-e4e4e4e4e4e4e4e4e5e5e5e5e5d9c6c6dde5e5e5e5e5e4e4e4e4e4e4e4e4
-9a9a9a9a9a9a9a9a9b9b9a9a9b5e0000709b9a9a9b9b9a9a9a9a9a9a9a9a
-9b9b9b9b9b9b9b9b9b9b9a9a9b5f0000719b9a9a9b9b9b9b9b9b9b9b9b9b
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
+00000000000000cfd95608080808080808080808e4c6c6e4080808080808
+0808080856d9cf00002db25000000000000000000000a00000a000000000
+00000000000050b22d00002ec2cab5b5b5b5b5b5b5b5b5b5a30000a3b5b5
+b5b5b5b5b5b5b5b5cac22e0000cbc7dea41b0808080808080808e4c6c6e4
+08080808080808081ba4dec7cb00001b057a9d130000000000000000a000
+00a00000000000000000139d7a051b00001b057bdbbab5b5b5b5b5b5b5b5
+a30000a3b5b5b5b5b5b5b5b5badb7b051b0000eed9c6cfd9560808080808
+0808e4c6c6e40808080808080856d9cfc6d9ee0000e25e002db250000000
+00000000a00000a00000000000000050b22d005ee20000e65f012ec2cab5
+b5b5b5b5b5b5a30000a3b5b5b5b5b5b5b5cac22e005fe6000031c6e9cbc7
+dea41b0808080808e4c6c6e408080808081ba4dec7cbe9c63100002ac5b0
+1b057a9d130000000000a00000a00000000000139d7a051bb0c52a0000c0
+e9b11b057adbbab5b5b5b5b5a30000a3b5b5b5b5b5badb7a051bb1eac000
+00080c7aeed9c6cfd95608080808e4c6c6e40808080856d9cfc6d9ee7a0c
+080000000476e25e002db15000000000a00000a00000000050b12d005ee2
+7604000000b5b6d4e65f012dc1cab5b5b5b5a30000a3b5b5b5b5cac12d00
+5fe6d5b6b5000008080831c6e9ccc7dea41b0808e4c6c6e408081ba4dec7
+cce9c63108080800000000002ac5b01c05799d130000a00000a00000139d
+79051cb0c52a0000000000b5b5b5c0e9b11c0579dbbab5b5a30000a3b5b5
+badb79051cb1eac0b5b5b50000080808080c7aeed9c6cfd95608e4c6c6e4
+0856d9cfc6d9ee7a0c080808080000000000000476e25f012db15000a000
+00a00050b12d005fe27604000000000000b5b5b5b5b6d4e760012dc1cab5
+a30000a3b5cac12d0160e7d5b6b5b5b5b5000008080808080831c6e9ccc7
+dea4e5c6c6e5a4dec7cce9c63108080808080800000000000000002ac5b1
+1c05799da10000a19d79051cb1c52a0000000000000000b5b5b5b5b5b5c0
+e9b21c0579dba30000a3db79051cb1eac0b5b5b5b5b5b50000e4e4e4e4e4
+e4e4e5e7e7e6e6e7dcc6c6dce7e6e6e7e7e5e4e4e4e4e4e4e40000a0a0a0
+a0a0a0a0a1a3a2a0a0a26c00006ca2a0a0a2a3a1a0a0a0a0a0a0a00000a3
+a3a3a3a3a3a3a3a4a3a1a1a36d00006da3a1a1a3a4a3a3a3a3a3a3a3a300
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-dbdbdbdbdbdbdbdfe9e8e6e6e8dbc6c6e0e8e6e6e8e9dddbdbdbdbdbdbdb
-9f9f9f9f9f9f9fa3aea79f9fab6a00007eaa9f9fa8aea19f9f9f9f9f9f9f
-abababababababacafa8a0a0ac6b00007faba0a0a9afacababababababab
-0808080808083ed2e6cac8e098e4c6c6dda3dec7cceac42f080808080808
-00000000000037d1a0120a8b93960000a59c79051db3c228000000000000
-b5b5b5b5b5b5c4eda0130a8ddb970000b0db7a051db3e9c0b5b5b5b5b5b5
-08080808108af0d6c6d2d04411e4c6c6d70855d8cfc6d9ed780b08080808
-000000000887dd4e003cb33d099600009f004fb12d0161e2730300000000
-b5b5b5b5b7d9df4e003cccc5b8970000aeb5cac12d0161e7d4b6b5b5b5b5
-0808083ed2e6cac8e091130811e4c6c6d708081aa3dec7cce9c42f080808
-00000037d09f120a8b8c0b00099600009f0000139c79051db2c228000000
-b5b5b5c4ec9f130b8dd9b8b5b8970000aeb5b5badb7a051db2e9c0b5b5b5
-08108bf0d5c6d2d04408080811e4c6c6d70808080855d8cfc6d9ed780b08
-000887dd4d003cb33e000000099600009f000000004fb12d0160e1730300
-b5b7d9df4d003cccc5b5b5b5b8970000aeb5b5b5b5cac12d0160e7d4b6b5
-3dd2e6cac8e191130808080811e4c6c6d708080808081ba3dec7cce9c42f
-37d09f120b8c8c0b00000000099600009f0000000000139c7a051cb2c229
-c4ec9f120b8dd9b8b5b5b5b5b8970000aeb5b5b5b5b5badb7a051cb2e9c0
-f0d6c6d2d04408080808080811e4c6c6d70808080808080855d8cfc6d9ee
-dd4d003db43d000000000000099600009f000000000000004fb12e0160e3
-df4d003dccc5b5b5b5b5b5b5b8970000aeb5b5b5b5b5b5b5cac22e0160e7
-cac8e191130808080808080811e4c6c6d708080808080808081ba3dec7cb
-120b8c8c0b00000000000000099600009f0000000000000000139c7a051a
-120b8ed9b8b5b5b5b5b5b5b5b8970000aeb5b5b5b5b5b5b5b5badb7b051a
-d2d24408080808080808080811e4c6c6d70808080808080808080855dacf
-3bb63e000000000000000000099600009f000000000000000000004fb32c
-3bcdc5b5b5b5b5b5b5b5b5b5b8970000aeb5b5b5b5b5b5b5b5b5b5cac32c
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000e4e4e4e4e4e4e4e5e7e7e6e6e7dcc6c6dc
+e7e6e6e7e7e5e4e4e4e4e4e4e40000a0a0a0a0a0a0a0a1a3a2a0a0a26c00
+006ca2a0a0a2a3a1a0a0a0a0a0a0a00000a3a3a3a3a3a3a3a3a4a3a1a1a3
+6d00006da3a1a1a3a4a3a3a3a3a3a3a3a3000008080808080831c6e9ccc7
+dea4e5c6c6e5a4dec7cce9c63108080808080800000000000000002ac4b1
+1c05799da10000a19d79051cb1c52a0000000000000000b5b5b5b5b5b5c0
+e9b21c0579dba30000a3db79051cb2eac0b5b5b5b5b5b50000080808080c
+7aeed9c6cfd95608e4c6c6e40856d9cfc6d9ee7a0c080808080000000000
+000476e260012db15000a00000a00050b12d0060e27604000000000000b5
+b5b5b5b6d4e760012dc1cbb5a30000a3b5cac12d0160e7d5b6b5b5b5b500
+0008080831c6e9ccc7dea41b0808e4c6c6e408081ba4dec7cce9c6310808
+0800000000002ac4b11c05799d140000a00000a00000139d79051cb1c52a
+0000000000b5b5b5c0e9b11c0579dbbab5b5a30000a3b5b5badb79051cb1
+eac0b5b5b50000080c7aeed9c6cfd95608080808e4c6c6e40808080856d9
+cfc6d9ee7a0c080000000476e25f002db15000000000a00000a000000000
+50b12d005ee17604000000b5b6d4e65f012dc1cbb5b5b5b5a30000a3b5b5
+b5b5cac12d005fe6d5b6b5000031c6e9cbc7dea41b0808080808e4c6c6e4
+08080808081ba4dec7cbe9c63100002ac4b01b057a9d140000000000a000
+00a00000000000139d7a051bb0c52a0000c0e9b11b057adbbab5b5b5b5b5
+a30000a3b5b5b5b5b5badb7a051bb1eac00000eed9c6cfd9560808080808
+0808e4c6c6e40808080808080856d9cfc6d9ee0000e25f002db250000000
+00000000a00000a00000000000000050b22d005ee10000e65f012dc2cbb5
+b5b5b5b5b5b5a30000a3b5b5b5b5b5b5b5cac22e005fe60000cbc7dea41b
+0808080808080808e4c6c6e408080808080808081ba4dec7cb00001b057a
+9d140000000000000000a00000a00000000000000000139d7a051b00001b
+057adbbab5b5b5b5b5b5b5b5a30000a3b5b5b5b5b5b5b5b5badb7b051b00
+00cfd95608080808080808080808e4c6c6e40808080808080808080856d9
+cf00002db25000000000000000000000a00000a000000000000000000000
+50b22d00002dc2cbb5b5b5b5b5b5b5b5b5b5a30000a3b5b5b5b5b5b5b5b5
+b5b5cac22e00000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/great-britain.gif b/Docs/Flags/great-britain.gif
index 0f555d078b3..ae92b536ad3 100644
--- a/Docs/Flags/great-britain.gif
+++ b/Docs/Flags/great-britain.gif
Binary files differ
diff --git a/Docs/Flags/great-britain.pdf b/Docs/Flags/great-britain.pdf
new file mode 100644
index 00000000000..f29dfd48861
--- /dev/null
+++ b/Docs/Flags/great-britain.pdf
Binary files differ
diff --git a/Docs/Flags/greece.eps b/Docs/Flags/greece.eps
index 3c022139c56..f59baa86106 100644
--- a/Docs/Flags/greece.eps
+++ b/Docs/Flags/greece.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: greece.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-1818181897f7a61818181818181818181818181818181818181818181818
-b5b5b5b5daf7dfb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefeff4f7f4efefefefefefefefefefefefefefefefefefefefefefef
-1818181897f7a61818181818181818181818181818181818181818181818
-b5b5b5b5daf7dfb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefeff4f7f4efefefefefefefefefefefefefefefefefefefefefefef
-1818181897f7a618181818bbc7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7
-b5b5b5b5daf7dfb5b5b5b5e5e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9
-efefefeff4f7f4efefefeff5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5
-1818181897f7a618181818e7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-b5b5b5b5daf7dfb5b5b5b5f2f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-efefefeff4f7f4efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-97979797cdf7d49797979777767676767676767676767676767676767676
-dadadadaeaf7ecdadadadad1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1
-f4f4f4f4f6f7f6f4f4f4f4f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2
-f7f7f7f7f7f7f7f7f7f7f725181818181818181818181818181818181818
-f7f7f7f7f7f7f7f7f7f7f7b9b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-f7f7f7f7f7f7f7f7f7f7f7efefefefefefefefefefefefefefefefefefef
-a6a6a6a6d4f7daa6a6a6a66a676767676767676767676767676767676767
-dfdfdfdfedf7eedfdfdfdfcdcccccccccccccccccccccccccccccccccccc
-f4f4f4f4f6f7f6f4f4f4f4f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2
-1818181897f7a618181818e7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-b5b5b5b5daf7dfb5b5b5b5f2f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-efefefeff4f7f4efefefeff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-1818181897f7a618181818c9d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6
-b5b5b5b5daf7dfb5b5b5b5e9edededededededededededededededededed
-efefefeff4f7f4efefefeff6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6
-1818181897f7a61818181818181818181818181818181818181818181818
-b5b5b5b5daf7dfb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefeff4f7f4efefefefefefefefefefefefefefefefefefefefefefef
-1818181897f7a61818181818181818181818181818181818181818181818
-b5b5b5b5daf7dfb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefeff4f7f4efefefefefefefefefefefefefefefefefefefefefefef
-e7e7e7e7f0f7f1e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7
-f2f2f2f2f5f7f5f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-555555555555555555555555555555555555555555555555555555555555
-c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7
-f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1
-181818181818181818181818181818181818181818181818181818181818
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
-878787878787878787878787878787878787878787878787878787878787
-d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6
-f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6
-e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4
-f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5
-181818181818181818181818181818181818181818181818181818181818
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
-181818181818181818181818181818181818181818181818181818181818
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000001818181893f7ac18181818181818181818181818181818
+181818181818180000b5b5b5b5d9f7e1b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b50000efefefeff3f7f4efefefefefefefefefefefef
+efefefefefefefefefefef00001818181893f7ac18181818181818181818
+181818181818181818181818180000b5b5b5b5d9f7e1b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b50000efefefeff3f7f4efefefefefef
+efefefefefefefefefefefefefefefefef00001818181893f7ac18181818
+b1c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c50000b5b5b5b5d9f7e1b5b5
+b5b5e2e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e80000efefefeff3f7f4
+efefefeff4f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f500001818181893
+f7ac18181818def7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000b5b5b5
+b5d9f7e1b5b5b5b5f0f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000ef
+efefeff3f7f4efefefeff6f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700
+0093939393caf7d5939393937a7979797979797979797979797979797979
+790000d9d9d9d9e9f7edd9d9d9d9d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2
+d2d2d20000f3f3f3f3f5f7f6f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3
+f3f3f3f3f30000f7f7f7f7f7f7f7f7f7f7f72e1818181818181818181818
+181818181818180000f7f7f7f7f7f7f7f7f7f7f7bcb5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b50000f7f7f7f7f7f7f7f7f7f7f7f0efefefefefefef
+efefefefefefefefefefef0000acacacacd5f7deacacacac686161616161
+616161616161616161616161610000e1e1e1e1edf7f0e1e1e1e1cccacaca
+cacacacacacacacacacacacacacaca0000f4f4f4f4f6f7f6f4f4f4f4f2f2
+f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f200001818181893f7ac18181818
+def7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000b5b5b5b5d9f7e1b5b5
+b5b5f0f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000efefefeff3f7f4
+efefefeff6f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700001818181893
+f7ac18181818c8dededededededededededededededededede0000b5b5b5
+b5d9f7e1b5b5b5b5e9f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f00000ef
+efefeff3f7f4efefefeff5f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f600
+001818181893f7ac18181818181818181818181818181818181818181818
+180000b5b5b5b5d9f7e1b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b50000efefefeff3f7f4efefefefefefefefefefefefefefefefefef
+efefefefef00001818181893f7ac18181818181818181818181818181818
+181818181818180000b5b5b5b5d9f7e1b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b50000efefefeff3f7f4efefefefefefefefefefefef
+efefefefefefefefefefef0000dedededeecf7efdededededededededede
+dedededededededededededede0000f0f0f0f0f4f7f5f0f0f0f0f0f0f0f0
+f0f0f0f0f0f0f0f0f0f0f0f0f0f0f00000f6f6f6f6f7f7f7f6f6f6f6f6f6
+f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f60000f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700006161616161
+616161616161616161616161616161616161616161616161610000cacaca
+cacacacacacacacacacacacacacacacacacacacacacacacacacaca0000f2
+f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f200
+001818181818181818181818181818181818181818181818181818181818
+180000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b50000efefefefefefefefefefefefefefefefefefefefefefefefef
+efefefefef00007979797979797979797979797979797979797979797979
+797979797979790000d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2
+d2d2d2d2d2d2d2d2d20000f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3
+f3f3f3f3f3f3f3f3f3f3f30000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000c5c5c5c5c5c5c5c5c5c5c5
+c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c50000e8e8e8e8e8e8e8e8e8
+e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e80000f5f5f5f5f5f5f5
+f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f500001818181818
+181818181818181818181818181818181818181818181818180000b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b50000ef
+efefefefefefefefefefefefefefefefefefefefefefefefefefefefef00
+001818181818181818181818181818181818181818181818181818181818
+180000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b50000efefefefefefefefefefefefefefefefefefefefefefefefef
+efefefefef00000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/greece.gif b/Docs/Flags/greece.gif
index 1ede215a373..264b295b374 100644
--- a/Docs/Flags/greece.gif
+++ b/Docs/Flags/greece.gif
Binary files differ
diff --git a/Docs/Flags/greece.pdf b/Docs/Flags/greece.pdf
new file mode 100644
index 00000000000..d54d8b3e153
--- /dev/null
+++ b/Docs/Flags/greece.pdf
Binary files differ
diff --git a/Docs/Flags/hungary.eps b/Docs/Flags/hungary.eps
index e405fc3cffe..38d9cae079f 100644
--- a/Docs/Flags/hungary.eps
+++ b/Docs/Flags/hungary.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: hungary.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6
+d6d6d6d6d6d6d6d6d6d6d6d6d60000505050505050505050505050505050
+505050505050505050505050505050000050505050505050505050505050
+50505050505050505050505050505050500000f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700
+00f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700005353535353
+535353535353535353535353535353535353535353535353530000cbcbcb
+cbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcb000053
+535353535353535353535353535353535353535353535353535353535300
000000000000000000000000000000000000000000000000000000000000
+000000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7
-575757575757575757575757575757575757575757575757575757575757
-575757575757575757575757575757575757575757575757575757575757
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-464646464646464646464646464646464646464646464646464646464646
-c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8
-464646464646464646464646464646464646464646464646464646464646
+000000000000000000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+000000000000000000000000000000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5000000000000000000
000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+000000000000000000000000000000000000000000000000000000b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+000000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/hungary.gif b/Docs/Flags/hungary.gif
index eca0e109bbe..eb14887b5bb 100644
--- a/Docs/Flags/hungary.gif
+++ b/Docs/Flags/hungary.gif
Binary files differ
diff --git a/Docs/Flags/hungary.pdf b/Docs/Flags/hungary.pdf
new file mode 100644
index 00000000000..51ba552f2ba
--- /dev/null
+++ b/Docs/Flags/hungary.pdf
Binary files differ
diff --git a/Docs/Flags/iceland.eps b/Docs/Flags/iceland.eps
index c2a5529eb42..8a1bc21f4c8 100644
--- a/Docs/Flags/iceland.eps
+++ b/Docs/Flags/iceland.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: iceland.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-080808080808080feec6c6e3080808080808080808080808080808080808
-0000000000000008c60000cb000000000000000000000000000000000000
-b5b5b5b5b5b5b5b7c70000d6b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080feec6c6e3080808080808080808080808080808080808
-0000000000000008c60000cb000000000000000000000000000000000000
-b5b5b5b5b5b5b5b7c70000d6b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080feec6c6e3080808080808080808080808080808080808
-0000000000000008c60000cb000000000000000000000000000000000000
-b5b5b5b5b5b5b5b7c70000d6b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080feec6c6e3080808080808080808080808080808080808
-0000000000000008c60000cb000000000000000000000000000000000000
-b5b5b5b5b5b5b5b7c70000d6b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080feec6c6e3080808080808080808080808080808080808
-0000000000000008c60000cb000000000000000000000000000000000000
-b5b5b5b5b5b5b5b7c70000d6b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080feec6c6e3080808080808080808080808080808080808
-0000000000000008c60000cb000000000000000000000000000000000000
-b5b5b5b5b5b5b5b7c70000d6b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080feec6c6e3080808080808080808080808080808080808
-0000000000000008c60000cb000000000000000000000000000000000000
-b5b5b5b5b5b5b5b7c70000d6b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-0e0e0e0e0e0e0e15eec6c6e40e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e
-060606060606060ec60000cb060606060606060606060606060606060606
-b7b7b7b7b7b7b7b9c70000d6b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7
-ecececececececece6c6c6e9ecececececececececececececececececec
-c5c5c5c5c5c5c5c59f0000aec5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5
-c6c6c6c6c6c6c6c6a00000afc6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
+000000000000000808080808080808efc6c6ec0808080808080808080808
+0808080808080800000000000000000000cf0000cb000000000000000000
+0000000000000000000000b5b5b5b5b5b5b5b5cf0000ceb5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b500000808080808080808efc6c6ec0808080808
+0808080808080808080808080800000000000000000000cf0000cb000000
+0000000000000000000000000000000000b5b5b5b5b5b5b5b5cf0000ceb5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500000808080808080808efc6c6
+ec08080808080808080808080808080808080800000000000000000000cf
+0000cb0000000000000000000000000000000000000000b5b5b5b5b5b5b5
+b5cf0000ceb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500000808080808
+080808efc6c6ec0808080808080808080808080808080808080000000000
+0000000000cf0000cb0000000000000000000000000000000000000000b5
+b5b5b5b5b5b5b5cf0000ceb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500
+000808080808080808efc6c6ec0808080808080808080808080808080808
+0800000000000000000000cf0000cb000000000000000000000000000000
+0000000000b5b5b5b5b5b5b5b5cf0000ceb5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b500000808080808080808efc6c6ec0808080808080808080808
+0808080808080800000000000000000000cf0000cb000000000000000000
+0000000000000000000000b5b5b5b5b5b5b5b5cf0000ceb5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b500000808080808080808efc6c6ec0808080808
+0808080808080808080808080800000000000000000000cf0000cb000000
+0000000000000000000000000000000000b5b5b5b5b5b5b5b5cf0000ceb5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500000808080808080808efc6c6
+ec08080808080808080808080808080808080800000000000000000000cf
+0000cb0000000000000000000000000000000000000000b5b5b5b5b5b5b5
+b5cf0000ceb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b50000ececececec
+ececece9c6c6e8ecececececececececececececececececec0000cbcbcb
+cbcbcbcbcbad0000adcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcb0000ce
+cececececececeae0000adcececececececececececececececececece00
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-e6e6e6e6e6e6e6e6e9c6c6ebe6e6e6e6e6e6e6e6e6e6e6e6e6e6e6e6e6e6
-cecececececececeae0000becececececececececececececececececece
-d7d7d7d7d7d7d7d7af0000c0d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7
-080808080808080feec6c6e3080808080808080808080808080808080808
-0000000000000008c60000cb000000000000000000000000000000000000
-b5b5b5b5b5b5b5b7c70000d6b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080feec6c6e3080808080808080808080808080808080808
-0000000000000008c60000cb000000000000000000000000000000000000
-b5b5b5b5b5b5b5b7c70000d6b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080feec6c6e3080808080808080808080808080808080808
-0000000000000008c60000cb000000000000000000000000000000000000
-b5b5b5b5b5b5b5b7c70000d6b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080feec6c6e3080808080808080808080808080808080808
-0000000000000008c60000cb000000000000000000000000000000000000
-b5b5b5b5b5b5b5b7c70000d6b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080feec6c6e3080808080808080808080808080808080808
-0000000000000008c60000cb000000000000000000000000000000000000
-b5b5b5b5b5b5b5b7c70000d6b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080feec6c6e3080808080808080808080808080808080808
-0000000000000008c60000cb000000000000000000000000000000000000
-b5b5b5b5b5b5b5b7c70000d6b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080feec6c6e3080808080808080808080808080808080808
-0000000000000008c60000cb000000000000000000000000000000000000
-b5b5b5b5b5b5b5b7c70000d6b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080feec6c6e3080808080808080808080808080808080808
-0000000000000008c60000cb000000000000000000000000000000000000
-b5b5b5b5b5b5b5b7c70000d6b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000efefefefefefefefe9c6c6e8efefefefef
+efefefefefefefefefefefefef0000cfcfcfcfcfcfcfcfad0000adcfcfcf
+cfcfcfcfcfcfcfcfcfcfcfcfcfcfcf0000cfcfcfcfcfcfcfcfae0000adcf
+cfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcf00000808080808080808efc6c6
+ec08080808080808080808080808080808080800000000000000000000cf
+0000cb0000000000000000000000000000000000000000b5b5b5b5b5b5b5
+b5cf0000ceb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500000808080808
+080808efc6c6ec0808080808080808080808080808080808080000000000
+0000000000cf0000cb0000000000000000000000000000000000000000b5
+b5b5b5b5b5b5b5cf0000ceb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500
+000808080808080808efc6c6ec0808080808080808080808080808080808
+0800000000000000000000cf0000cb000000000000000000000000000000
+0000000000b5b5b5b5b5b5b5b5cf0000ceb5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b500000808080808080808efc6c6ec0808080808080808080808
+0808080808080800000000000000000000cf0000cb000000000000000000
+0000000000000000000000b5b5b5b5b5b5b5b5cf0000ceb5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b500000808080808080808efc6c6ec0808080808
+0808080808080808080808080800000000000000000000cf0000cb000000
+0000000000000000000000000000000000b5b5b5b5b5b5b5b5cf0000ceb5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500000808080808080808efc6c6
+ec08080808080808080808080808080808080800000000000000000000cf
+0000cb0000000000000000000000000000000000000000b5b5b5b5b5b5b5
+b5cf0000ceb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500000808080808
+080808efc6c6ec0808080808080808080808080808080808080000000000
+0000000000cf0000cb0000000000000000000000000000000000000000b5
+b5b5b5b5b5b5b5cf0000ceb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500
+000808080808080808efc6c6ec0808080808080808080808080808080808
+0800000000000000000000cf0000cb000000000000000000000000000000
+0000000000b5b5b5b5b5b5b5b5cf0000ceb5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b500000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/iceland.gif b/Docs/Flags/iceland.gif
index ee4d17f5d04..4fe0c0b8124 100644
--- a/Docs/Flags/iceland.gif
+++ b/Docs/Flags/iceland.gif
Binary files differ
diff --git a/Docs/Flags/iceland.pdf b/Docs/Flags/iceland.pdf
new file mode 100644
index 00000000000..3509de59ba8
--- /dev/null
+++ b/Docs/Flags/iceland.pdf
Binary files differ
diff --git a/Docs/Flags/indonesia.eps b/Docs/Flags/indonesia.eps
index e69de29bb2d..9dcef0824df 100644
--- a/Docs/Flags/indonesia.eps
+++ b/Docs/Flags/indonesia.eps
@@ -0,0 +1,98 @@
+%!PS-Adobe-2.0 EPSF-2.0
+%%Creator: pnmtops
+%%Title: indonesia.ps
+%%Pages: 1
+%%BoundingBox: 290 385 321 407
+%%EndComments
+/readstring {
+ currentfile exch readhexstring pop
+} bind def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
+%%EndProlog
+%%Page: 1 1
+gsave
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
+{ rpicstr readstring }
+{ gpicstr readstring }
+{ bpicstr readstring }
+true 3
+colorimage
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f70000f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4
+f4f4f4f4f4f4f4f4f40000f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4
+f4f4f4f4f4f4f4f4f4f4f40000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700
+00f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700
+00f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f700000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/indonesia.gif b/Docs/Flags/indonesia.gif
index 1c421df50ba..e05af4c8ff4 100644
--- a/Docs/Flags/indonesia.gif
+++ b/Docs/Flags/indonesia.gif
Binary files differ
diff --git a/Docs/Flags/indonesia.pdf b/Docs/Flags/indonesia.pdf
new file mode 100644
index 00000000000..48bd801fa15
--- /dev/null
+++ b/Docs/Flags/indonesia.pdf
Binary files differ
diff --git a/Docs/Flags/ireland.eps b/Docs/Flags/ireland.eps
index 610b2086fd7..01251367922 100644
--- a/Docs/Flags/ireland.eps
+++ b/Docs/Flags/ireland.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: ireland.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-0000000000000000000cf7f7f7f7f7f7f7f7f7f8ffffffffffffffffffff
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7f4d6d6d6d6d6d6d6d6d6d6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f8ffffffffffffffffffff
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7f4d6d6d6d6d6d6d6d6d6d6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f8ffffffffffffffffffff
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7f4d6d6d6d6d6d6d6d6d6d6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f8ffffffffffffffffffff
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7f4d6d6d6d6d6d6d6d6d6d6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f8ffffffffffffffffffff
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7f4d6d6d6d6d6d6d6d6d6d6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f8ffffffffffffffffffff
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7f4d6d6d6d6d6d6d6d6d6d6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f8ffffffffffffffffffff
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7f4d6d6d6d6d6d6d6d6d6d6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f8ffffffffffffffffffff
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7f4d6d6d6d6d6d6d6d6d6d6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f8ffffffffffffffffffff
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7f4d6d6d6d6d6d6d6d6d6d6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f8ffffffffffffffffffff
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7f4d6d6d6d6d6d6d6d6d6d6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f8ffffffffffffffffffff
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7f4d6d6d6d6d6d6d6d6d6d6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f8ffffffffffffffffffff
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7f4d6d6d6d6d6d6d6d6d6d6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f8ffffffffffffffffffff
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7f4d6d6d6d6d6d6d6d6d6d6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f8ffffffffffffffffffff
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7f4d6d6d6d6d6d6d6d6d6d6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f8ffffffffffffffffffff
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7f4d6d6d6d6d6d6d6d6d6d6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f8ffffffffffffffffffff
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7f4d6d6d6d6d6d6d6d6d6d6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f8ffffffffffffffffffff
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7f4d6d6d6d6d6d6d6d6d6d6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f8ffffffffffffffffffff
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7f4d6d6d6d6d6d6d6d6d6d6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f8ffffffffffffffffffff
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7f4d6d6d6d6d6d6d6d6d6d6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f8ffffffffffffffffffff
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7f4d6d6d6d6d6d6d6d6d6d6
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000003f7f7f7f7f7f7f7f7f7f7ffffff
+ffffffffffffff0000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f7d6
+d6d6d6d6d6d6d6d6d6000000000000000000000003f7f7f7f7f7f7f7f7f7
+f700000000000000000000000000000000000000000003f7f7f7f7f7f7f7
+f7f7f7ffffffffffffffffffff0000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7
+f7f7f7f7f7d6d6d6d6d6d6d6d6d6d6000000000000000000000003f7f7f7
+f7f7f7f7f7f7f700000000000000000000000000000000000000000003f7
+f7f7f7f7f7f7f7f7f7ffffffffffffffffffff0000b5b5b5b5b5b5b5b5b5
+b6f7f7f7f7f7f7f7f7f7f7d6d6d6d6d6d6d6d6d6d6000000000000000000
+000003f7f7f7f7f7f7f7f7f7f70000000000000000000000000000000000
+0000000003f7f7f7f7f7f7f7f7f7f7ffffffffffffffffffff0000b5b5b5
+b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f7d6d6d6d6d6d6d6d6d6d6000000
+000000000000000003f7f7f7f7f7f7f7f7f7f70000000000000000000000
+0000000000000000000003f7f7f7f7f7f7f7f7f7f7ffffffffffffffffff
+ff0000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f7d6d6d6d6d6d6d6
+d6d6d6000000000000000000000003f7f7f7f7f7f7f7f7f7f70000000000
+0000000000000000000000000000000003f7f7f7f7f7f7f7f7f7f7ffffff
+ffffffffffffff0000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f7d6
+d6d6d6d6d6d6d6d6d6000000000000000000000003f7f7f7f7f7f7f7f7f7
+f700000000000000000000000000000000000000000003f7f7f7f7f7f7f7
+f7f7f7ffffffffffffffffffff0000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7
+f7f7f7f7f7d6d6d6d6d6d6d6d6d6d6000000000000000000000003f7f7f7
+f7f7f7f7f7f7f700000000000000000000000000000000000000000003f7
+f7f7f7f7f7f7f7f7f7ffffffffffffffffffff0000b5b5b5b5b5b5b5b5b5
+b6f7f7f7f7f7f7f7f7f7f7d6d6d6d6d6d6d6d6d6d6000000000000000000
+000003f7f7f7f7f7f7f7f7f7f70000000000000000000000000000000000
+0000000003f7f7f7f7f7f7f7f7f7f7ffffffffffffffffffff0000b5b5b5
+b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f7d6d6d6d6d6d6d6d6d6d6000000
+000000000000000003f7f7f7f7f7f7f7f7f7f70000000000000000000000
+0000000000000000000003f7f7f7f7f7f7f7f7f7f7ffffffffffffffffff
+ff0000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f7d6d6d6d6d6d6d6
+d6d6d6000000000000000000000003f7f7f7f7f7f7f7f7f7f70000000000
+0000000000000000000000000000000003f7f7f7f7f7f7f7f7f7f7ffffff
+ffffffffffffff0000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f7d6
+d6d6d6d6d6d6d6d6d6000000000000000000000003f7f7f7f7f7f7f7f7f7
+f700000000000000000000000000000000000000000003f7f7f7f7f7f7f7
+f7f7f7ffffffffffffffffffff0000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7
+f7f7f7f7f7d6d6d6d6d6d6d6d6d6d6000000000000000000000003f7f7f7
+f7f7f7f7f7f7f700000000000000000000000000000000000000000003f7
+f7f7f7f7f7f7f7f7f7ffffffffffffffffffff0000b5b5b5b5b5b5b5b5b5
+b6f7f7f7f7f7f7f7f7f7f7d6d6d6d6d6d6d6d6d6d6000000000000000000
+000003f7f7f7f7f7f7f7f7f7f70000000000000000000000000000000000
+0000000003f7f7f7f7f7f7f7f7f7f7ffffffffffffffffffff0000b5b5b5
+b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f7d6d6d6d6d6d6d6d6d6d6000000
+000000000000000003f7f7f7f7f7f7f7f7f7f70000000000000000000000
+0000000000000000000003f7f7f7f7f7f7f7f7f7f7ffffffffffffffffff
+ff0000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f7d6d6d6d6d6d6d6
+d6d6d6000000000000000000000003f7f7f7f7f7f7f7f7f7f70000000000
+0000000000000000000000000000000003f7f7f7f7f7f7f7f7f7f7ffffff
+ffffffffffffff0000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f7d6
+d6d6d6d6d6d6d6d6d6000000000000000000000003f7f7f7f7f7f7f7f7f7
+f700000000000000000000000000000000000000000003f7f7f7f7f7f7f7
+f7f7f7ffffffffffffffffffff0000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7
+f7f7f7f7f7d6d6d6d6d6d6d6d6d6d6000000000000000000000003f7f7f7
+f7f7f7f7f7f7f700000000000000000000000000000000000000000003f7
+f7f7f7f7f7f7f7f7f7ffffffffffffffffffff0000b5b5b5b5b5b5b5b5b5
+b6f7f7f7f7f7f7f7f7f7f7d6d6d6d6d6d6d6d6d6d6000000000000000000
+000003f7f7f7f7f7f7f7f7f7f70000000000000000000000000000000000
+0000000003f7f7f7f7f7f7f7f7f7f7ffffffffffffffffffff0000b5b5b5
+b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f7d6d6d6d6d6d6d6d6d6d6000000
+000000000000000003f7f7f7f7f7f7f7f7f7f70000000000000000000000
+0000000000000000000003f7f7f7f7f7f7f7f7f7f7ffffffffffffffffff
+ff0000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f7d6d6d6d6d6d6d6
+d6d6d6000000000000000000000003f7f7f7f7f7f7f7f7f7f70000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/ireland.gif b/Docs/Flags/ireland.gif
index a550678761f..631be2f33b9 100644
--- a/Docs/Flags/ireland.gif
+++ b/Docs/Flags/ireland.gif
Binary files differ
diff --git a/Docs/Flags/ireland.pdf b/Docs/Flags/ireland.pdf
new file mode 100644
index 00000000000..5f84f52f049
--- /dev/null
+++ b/Docs/Flags/ireland.pdf
Binary files differ
diff --git a/Docs/Flags/italy.eps b/Docs/Flags/italy.eps
index 20c7c7d5da3..7de3ddd9c1f 100644
--- a/Docs/Flags/italy.eps
+++ b/Docs/Flags/italy.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: italy.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-0000000000000000000cf7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5b8f7f7f7f7f7f7f7f7f7e400000000000000000000
-0000000000000000000cf7f7f7f7f7f7f7f7f7e400000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000003f7f7f7f7f7f7f7f7f7f7c6c6c6
+c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f700
+000000000000000000000000000000000000000003f7f7f7f7f7f7f7f7f7
+f700000000000000000000000000000000000000000003f7f7f7f7f7f7f7
+f7f7f7c6c6c6c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7
+f7f7f7f7f700000000000000000000000000000000000000000003f7f7f7
+f7f7f7f7f7f7f700000000000000000000000000000000000000000003f7
+f7f7f7f7f7f7f7f7f7c6c6c6c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5
+b6f7f7f7f7f7f7f7f7f7f700000000000000000000000000000000000000
+000003f7f7f7f7f7f7f7f7f7f70000000000000000000000000000000000
+0000000003f7f7f7f7f7f7f7f7f7f7c6c6c6c6c6c6c6c6c6c60000b5b5b5
+b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f700000000000000000000000000
+000000000000000003f7f7f7f7f7f7f7f7f7f70000000000000000000000
+0000000000000000000003f7f7f7f7f7f7f7f7f7f7c6c6c6c6c6c6c6c6c6
+c60000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f700000000000000
+000000000000000000000000000003f7f7f7f7f7f7f7f7f7f70000000000
+0000000000000000000000000000000003f7f7f7f7f7f7f7f7f7f7c6c6c6
+c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f700
+000000000000000000000000000000000000000003f7f7f7f7f7f7f7f7f7
+f700000000000000000000000000000000000000000003f7f7f7f7f7f7f7
+f7f7f7c6c6c6c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7
+f7f7f7f7f700000000000000000000000000000000000000000003f7f7f7
+f7f7f7f7f7f7f700000000000000000000000000000000000000000003f7
+f7f7f7f7f7f7f7f7f7c6c6c6c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5
+b6f7f7f7f7f7f7f7f7f7f700000000000000000000000000000000000000
+000003f7f7f7f7f7f7f7f7f7f70000000000000000000000000000000000
+0000000003f7f7f7f7f7f7f7f7f7f7c6c6c6c6c6c6c6c6c6c60000b5b5b5
+b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f700000000000000000000000000
+000000000000000003f7f7f7f7f7f7f7f7f7f70000000000000000000000
+0000000000000000000003f7f7f7f7f7f7f7f7f7f7c6c6c6c6c6c6c6c6c6
+c60000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f700000000000000
+000000000000000000000000000003f7f7f7f7f7f7f7f7f7f70000000000
+0000000000000000000000000000000003f7f7f7f7f7f7f7f7f7f7c6c6c6
+c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f700
+000000000000000000000000000000000000000003f7f7f7f7f7f7f7f7f7
+f700000000000000000000000000000000000000000003f7f7f7f7f7f7f7
+f7f7f7c6c6c6c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7
+f7f7f7f7f700000000000000000000000000000000000000000003f7f7f7
+f7f7f7f7f7f7f700000000000000000000000000000000000000000003f7
+f7f7f7f7f7f7f7f7f7c6c6c6c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5
+b6f7f7f7f7f7f7f7f7f7f700000000000000000000000000000000000000
+000003f7f7f7f7f7f7f7f7f7f70000000000000000000000000000000000
+0000000003f7f7f7f7f7f7f7f7f7f7c6c6c6c6c6c6c6c6c6c60000b5b5b5
+b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f700000000000000000000000000
+000000000000000003f7f7f7f7f7f7f7f7f7f70000000000000000000000
+0000000000000000000003f7f7f7f7f7f7f7f7f7f7c6c6c6c6c6c6c6c6c6
+c60000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f700000000000000
+000000000000000000000000000003f7f7f7f7f7f7f7f7f7f70000000000
+0000000000000000000000000000000003f7f7f7f7f7f7f7f7f7f7c6c6c6
+c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f700
+000000000000000000000000000000000000000003f7f7f7f7f7f7f7f7f7
+f700000000000000000000000000000000000000000003f7f7f7f7f7f7f7
+f7f7f7c6c6c6c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7
+f7f7f7f7f700000000000000000000000000000000000000000003f7f7f7
+f7f7f7f7f7f7f700000000000000000000000000000000000000000003f7
+f7f7f7f7f7f7f7f7f7c6c6c6c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5
+b6f7f7f7f7f7f7f7f7f7f700000000000000000000000000000000000000
+000003f7f7f7f7f7f7f7f7f7f70000000000000000000000000000000000
+0000000003f7f7f7f7f7f7f7f7f7f7c6c6c6c6c6c6c6c6c6c60000b5b5b5
+b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f700000000000000000000000000
+000000000000000003f7f7f7f7f7f7f7f7f7f70000000000000000000000
+0000000000000000000003f7f7f7f7f7f7f7f7f7f7c6c6c6c6c6c6c6c6c6
+c60000b5b5b5b5b5b5b5b5b5b6f7f7f7f7f7f7f7f7f7f700000000000000
+000000000000000000000000000003f7f7f7f7f7f7f7f7f7f70000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/italy.gif b/Docs/Flags/italy.gif
index 511dba800c7..d59cf5ef55e 100644
--- a/Docs/Flags/italy.gif
+++ b/Docs/Flags/italy.gif
Binary files differ
diff --git a/Docs/Flags/italy.pdf b/Docs/Flags/italy.pdf
new file mode 100644
index 00000000000..02c7d316a05
--- /dev/null
+++ b/Docs/Flags/italy.pdf
Binary files differ
diff --git a/Docs/Flags/japan.eps b/Docs/Flags/japan.eps
index 8dee6e497ba..c8ea7aa8afe 100644
--- a/Docs/Flags/japan.eps
+++ b/Docs/Flags/japan.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: japan.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7edddd6d7dfeff7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7c17652557cccf7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7c27653557cccf7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f2d4c6c6c6c6c6c6d8f4f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7de4500000000000157e9f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7de4600000000000158e9f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f2ccc6c6c6c6c6c6c6c6d0f5f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7de1f000000000000000030eaf7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7de1f000000000000000030eaf7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7d4c6c6c6c6c6c6c6c6c6c6d9f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7430000000000000000000060f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7440000000000000000000060f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7ecc6c6c6c6c6c6c6c6c6c6c6c7f1f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7be000000000000000000000003d8f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7be000000000000000000000003d9f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7ddc6c6c6c6c6c6c6c6c6c6c6c6e2f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7720000000000000000000000008ff7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7720000000000000000000000008ff7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7d6c6c6c6c6c6c6c6c6c6c6c6c6dbf7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f74e0000000000000000000000006bf7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f74e0000000000000000000000006bf7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7d6c6c6c6c6c6c6c6c6c6c6c6c6dcf7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f74f0000000000000000000000006cf7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f74f0000000000000000000000006df7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7dec6c6c6c6c6c6c6c6c6c6c6c6e3f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f77600000000000000000000000093f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f77600000000000000000000000093f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7edc6c6c6c6c6c6c6c6c6c6c6c7f2f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7c6000000000000000000000005def7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7c6000000000000000000000005def7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7d6c6c6c6c6c6c6c6c6c6c6dcf7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f74f000000000000000000006cf7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f74f000000000000000000006df7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f4cec6c6c6c6c6c6c6c6d2f5f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7e52a00000000000000003deff7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7e52a00000000000000003deff7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f4d8c6c6c6c6c6c7dbf5f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7e7580200000000056aeff7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7e7590200000000056beff7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f0e1dadbe3f2f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7d389666890dcf7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7d389666890dcf7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7
+f7f7f7f7f7f7f7eedfd7d7dfeef7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7
+f7f7f7f7f7f7f7f7f7ca7c57577ccaf7f7f7f7f7f7f7f7f7f7f7f70000f7
+f7f7f7f7f7f7f7f7f7f7f7ca7c57577ccaf7f7f7f7f7f7f7f7f7f7f7f700
+00f7f7f7f7f7f7f7f7f7f7f3d6c6c6c6c6c6c6d6f3f7f7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f7f7f7e45000000000000050e4f7f7f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f7f7f7e45000000000000050e4f7f7f7f7f7
+f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f3cec6c6c6c6c6c6c6c6cef3f7f7
+f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7e427000000000000000027e4
+f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7e4270000000000000000
+27e4f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7d6c6c6c6c6c6c6c6
+c6c6c6d6f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7500000000000
+000000000050f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f750000000
+0000000000000050f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7eec6c6
+c6c6c6c6c6c6c6c6c6c6eef7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7ca
+000000000000000000000000caf7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7ca000000000000000000000000caf7f7f7f7f7f7f7f70000f7f7f7f7f7
+f7f7f7dfc6c6c6c6c6c6c6c6c6c6c6c6dff7f7f7f7f7f7f7f70000f7f7f7
+f7f7f7f7f77c0000000000000000000000007cf7f7f7f7f7f7f7f70000f7
+f7f7f7f7f7f7f77c0000000000000000000000007cf7f7f7f7f7f7f7f700
+00f7f7f7f7f7f7f7f7d7c6c6c6c6c6c6c6c6c6c6c6c6d7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f75700000000000000000000000057f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f75700000000000000000000000057f7f7f7
+f7f7f7f7f70000f7f7f7f7f7f7f7f7d7c6c6c6c6c6c6c6c6c6c6c6c6d7f7
+f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f757000000000000000000000000
+57f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f75700000000000000000000
+000057f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7dfc6c6c6c6c6c6c6c6
+c6c6c6c6dff7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f77c000000000000
+0000000000007cf7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f77c00000000
+00000000000000007cf7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7eec6c6
+c6c6c6c6c6c6c6c6c6c6eef7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7c9
+000000000000000000000000caf7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7ca000000000000000000000000caf7f7f7f7f7f7f7f70000f7f7f7f7f7
+f7f7f7f7d6c6c6c6c6c6c6c6c6c6c6d6f7f7f7f7f7f7f7f7f70000f7f7f7
+f7f7f7f7f7f7500000000000000000000050f7f7f7f7f7f7f7f7f70000f7
+f7f7f7f7f7f7f7f7500000000000000000000050f7f7f7f7f7f7f7f7f700
+00f7f7f7f7f7f7f7f7f7f3cec6c6c6c6c6c6c6c6cef3f7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f7f7e427000000000000000027e4f7f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f7f7e427000000000000000027e4f7f7f7f7
+f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f3d6c6c6c6c6c6c6d6f3f7f7f7
+f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7e45000000000000050e4f7
+f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7e45000000000000050
+e4f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7eedfd7d7df
+eef7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7c97c56
+567cc9f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7ca
+7c57577ccaf7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700
+00f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f700000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/japan.gif b/Docs/Flags/japan.gif
index 37ebca66f04..7d6a9adbd78 100644
--- a/Docs/Flags/japan.gif
+++ b/Docs/Flags/japan.gif
Binary files differ
diff --git a/Docs/Flags/japan.pdf b/Docs/Flags/japan.pdf
new file mode 100644
index 00000000000..c98ff331611
--- /dev/null
+++ b/Docs/Flags/japan.pdf
Binary files differ
diff --git a/Docs/Flags/latvia.eps b/Docs/Flags/latvia.eps
index 9c1f81f3ddc..606f7e70b3c 100644
--- a/Docs/Flags/latvia.eps
+++ b/Docs/Flags/latvia.eps
@@ -2,7 +2,7 @@
%%Creator: pnmtops
%%Title: latvia.ps
%%Pages: 1
-%%BoundingBox: 295 365 317 396
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
@@ -13,9 +13,8 @@
%%EndProlog
%%Page: 1 1
gsave
-295.44 365.64 translate
-21.12 30.72 scale
-0.5 0.5 translate 90 rotate -0.5 -0.5 translate
+290.64 385.44 translate
+30.72 21.12 scale
32 22 8
[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
@@ -26,71 +25,71 @@ colorimage
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-000000000000009494949494949494949494949494949494949494949494
-949494949494940000101010101010101010101010101010101010101010
-101010101010101010000018181818181818181818181818181818181818
-181818181818181818181800009494949494949494949494949494949494
-949494949494949494949494940000101010101010101010101010101010
-101010101010101010101010101010000018181818181818181818181818
-181818181818181818181818181818181800009494949494949494949494
-949494949494949494949494949494949494940000101010101010101010
-101010101010101010101010101010101010101010000018181818181818
-181818181818181818181818181818181818181818181800009494949494
-949494949494949494949494949494949494949494949494940000101010
-101010101010101010101010101010101010101010101010101010000018
-181818181818181818181818181818181818181818181818181818181800
-009494949494949494949494949494949494949494949494949494949494
-940000101010101010101010101010101010101010101010101010101010
-101010000018181818181818181818181818181818181818181818181818
-181818181800009494949494949494949494949494949494949494949494
-949494949494940000101010101010101010101010101010101010101010
-101010101010101010000018181818181818181818181818181818181818
-181818181818181818181800009494949494949494949494949494949494
-949494949494949494949494940000101010101010101010101010101010
-101010101010101010101010101010000018181818181818181818181818
-181818181818181818181818181818181800009494949494949494949494
-949494949494949494949494949494949494940000101010101010101010
-101010101010101010101010101010101010101010000018181818181818
-18181818181818181818181818181818181818181818180000ffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00
-00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffff00009494949494949494949494
-949494949494949494949494949494949494940000101010101010101010
-101010101010101010101010101010101010101010000018181818181818
-181818181818181818181818181818181818181818181800009494949494
-949494949494949494949494949494949494949494949494940000101010
-101010101010101010101010101010101010101010101010101010000018
-181818181818181818181818181818181818181818181818181818181800
-009494949494949494949494949494949494949494949494949494949494
-940000101010101010101010101010101010101010101010101010101010
-101010000018181818181818181818181818181818181818181818181818
-181818181800009494949494949494949494949494949494949494949494
-949494949494940000101010101010101010101010101010101010101010
-101010101010101010000018181818181818181818181818181818181818
-181818181818181818181800009494949494949494949494949494949494
-949494949494949494949494940000101010101010101010101010101010
-101010101010101010101010101010000018181818181818181818181818
-181818181818181818181818181818181800009494949494949494949494
-949494949494949494949494949494949494940000101010101010101010
-101010101010101010101010101010101010101010000018181818181818
-181818181818181818181818181818181818181818181800009494949494
-949494949494949494949494949494949494949494949494940000101010
-101010101010101010101010101010101010101010101010101010000018
-181818181818181818181818181818181818181818181818181818181800
-009494949494949494949494949494949494949494949494949494949494
-940000101010101010101010101010101010101010101010101010101010
-101010000018181818181818181818181818181818181818181818181818
-181818181800000000000000000000000000000000000000000000000000
+00000000000000a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5
+a5a5a5a5a5a5a50000000000000000000000000000000000000000000000
+000000000000000000000010101010101010101010101010101010101010
+10101010101010101010100000a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5
+a5a5a5a5a5a5a5a5a5a5a5a5a50000000000000000000000000000000000
+000000000000000000000000000000000010101010101010101010101010
+10101010101010101010101010101010100000a5a5a5a5a5a5a5a5a5a5a5
+a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a50000000000000000000000
+000000000000000000000000000000000000000000000010101010101010
+10101010101010101010101010101010101010101010100000a5a5a5a5a5
+a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a50000000000
+000000000000000000000000000000000000000000000000000000000010
+101010101010101010101010101010101010101010101010101010101000
+00a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5
+a50000000000000000000000000000000000000000000000000000000000
+000000000010101010101010101010101010101010101010101010101010
+10101010100000a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5
+a5a5a5a5a5a5a50000000000000000000000000000000000000000000000
+000000000000000000000010101010101010101010101010101010101010
+10101010101010101010100000a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5
+a5a5a5a5a5a5a5a5a5a5a5a5a50000000000000000000000000000000000
+000000000000000000000000000000000010101010101010101010101010
+10101010101010101010101010101010100000a5a5a5a5a5a5a5a5a5a5a5
+a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a50000000000000000000000
+000000000000000000000000000000000000000000000010101010101010
+10101010101010101010101010101010101010101010100000dbdbdbdbdb
+dbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdb0000a3a3a3
+a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a30000ab
+ababababababababababababababababababababababababababababab00
+00f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f70000dcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc
+dcdcdcdcdcdcdcdcdcdcdcdcdc0000a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3
+a3a3a3a3a3a3a3a3a3a3a3a3a3a3a30000ababababababababababababab
+ababababababababababababababababab0000a5a5a5a5a5a5a5a5a5a5a5
+a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a50000000000000000000000
+000000000000000000000000000000000000000000000010101010101010
+10101010101010101010101010101010101010101010100000a5a5a5a5a5
+a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a50000000000
+000000000000000000000000000000000000000000000000000000000010
+101010101010101010101010101010101010101010101010101010101000
+00a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5
+a50000000000000000000000000000000000000000000000000000000000
+000000000010101010101010101010101010101010101010101010101010
+10101010100000a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5
+a5a5a5a5a5a5a50000000000000000000000000000000000000000000000
+000000000000000000000010101010101010101010101010101010101010
+10101010101010101010100000a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5
+a5a5a5a5a5a5a5a5a5a5a5a5a50000000000000000000000000000000000
+000000000000000000000000000000000010101010101010101010101010
+10101010101010101010101010101010100000a5a5a5a5a5a5a5a5a5a5a5
+a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a50000000000000000000000
+000000000000000000000000000000000000000000000010101010101010
+10101010101010101010101010101010101010101010100000a5a5a5a5a5
+a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a50000000000
+000000000000000000000000000000000000000000000000000000000010
+101010101010101010101010101010101010101010101010101010101000
+00a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5
+a50000000000000000000000000000000000000000000000000000000000
+000000000010101010101010101010101010101010101010101010101010
+101010101000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000
diff --git a/Docs/Flags/latvia.gif b/Docs/Flags/latvia.gif
index 8a898328ebe..b8ba782b703 100644
--- a/Docs/Flags/latvia.gif
+++ b/Docs/Flags/latvia.gif
Binary files differ
diff --git a/Docs/Flags/latvia.pdf b/Docs/Flags/latvia.pdf
new file mode 100644
index 00000000000..1d06690e980
--- /dev/null
+++ b/Docs/Flags/latvia.pdf
Binary files differ
diff --git a/Docs/Flags/mexico.eps b/Docs/Flags/mexico.eps
new file mode 100644
index 00000000000..c6f4f0a79de
--- /dev/null
+++ b/Docs/Flags/mexico.eps
@@ -0,0 +1,98 @@
+%!PS-Adobe-2.0 EPSF-2.0
+%%Creator: pnmtops
+%%Title: mexico.ps
+%%Pages: 1
+%%BoundingBox: 290 385 321 407
+%%EndComments
+/readstring {
+ currentfile exch readhexstring pop
+} bind def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
+%%EndProlog
+%%Page: 1 1
+gsave
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
+{ rpicstr readstring }
+{ gpicstr readstring }
+{ bpicstr readstring }
+true 3
+colorimage
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000005ffffffffffffffffffffc6c6c6
+c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5b7fffffffffffffffffffe00
+000000000000000000000000000000000000000005ffffffffffffffffff
+fe00000000000000000000000000000000000000000005ffffffffffffff
+ffffffc6c6c6c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5b7ffffffffff
+fffffffffe00000000000000000000000000000000000000000005ffffff
+fffffffffffffe00000000000000000000000000000000000000000005ff
+ffffffffffffffffffc6c6c6c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5
+b7fffffffffffffffffffe00000000000000000000000000000000000000
+000005fffffffffffffffffffe0000000000000000000000000000000000
+0000000005ffffffffffffffffffffc6c6c6c6c6c6c6c6c6c60000b5b5b5
+b5b5b5b5b5b5b7fffffffffffffffffffe00000000000000000000000000
+000000000000000005fffffffffffffffffffe0000000000000000000000
+0000000000000000000005ffffffffffffffffffffc6c6c6c6c6c6c6c6c6
+c60000b5b5b5b5b5b5b5b5b5b7fffffffffffffffffffe00000000000000
+000000000000000000000000000005fffffffffffffffffffe0000000000
+0000000000000000000000000000000005ffffffffffffffffffffc6c6c6
+c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5b7fffffffffffffffffffe00
+000000000000000000000000000000000000000005ffffffffffffffffff
+fe00000000000000000000000000000000000000000005fffffffee0bbe1
+ffffffc6c6c6c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5b7fffffffed2
+95d3fffffe00000000000000000000000000000000000000000005ffffff
+fec876c7fffffe00000000000000000000000000000000000000000005ff
+ffc4ae7f8683cdffffc6c6c6c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5
+b7ffffd790453e3daefffe00000000000000000000000000000000000000
+000005ffffbc6114010295fffe0000000000000000000000000000000000
+0000000005fffcd699827c838df6ffc6c6c6c6c6c6c6c6c6c60000b5b5b5
+b5b5b5b5b5b5b7fffbdca23f383c47f3fe00000000000000000000000000
+000000000000000005ffface770600000cf0fe0000000000000000000000
+0000000000000000000005f3e89eaa827eb98de6f5c6c6c6c6c6c6c6c6c6
+c60000b5b5b5b5b5b5b5b5b5b7f6eab996493b9a53def800000000000000
+000000000000000000000000000005f1e28f8319038123d2f30000000000
+0000000000000000000000000000000005cfcf77bab38a93bdbdd5c6c6c6
+c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5b7dbcf97a18c5159a1cae200
+000000000000000000000000000000000000000005c3bc67796521298bab
+cd00000000000000000000000000000000000000000005fa8cbd7c4c6076
+c079fdc6c6c6c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5b7fbadcba194
+839bb6abfc00000000000000000000000000000000000000000005f978b8
+78542f63a668fb00000000000000000000000000000000000000000005ff
+e2829a795dbd8ee1ffc6c6c6c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5
+b7ffe5a9bf5657c8b9e7fe00000000000000000000000000000000000000
+000005ffd86ecd2d20c780d9fe0000000000000000000000000000000000
+0000000005ffffe68b989f86f5ffffc6c6c6c6c6c6c6c6c6c60000b5b5b5
+b5b5b5b5b5b5b7ffffe8b4aba8b5f4fffe00000000000000000000000000
+000000000000000005ffffdd7d8a8c78f0fffe0000000000000000000000
+0000000000000000000005fffffffffefeffffffffc6c6c6c6c6c6c6c6c6
+c60000b5b5b5b5b5b5b5b5b5b7fffffffffefefffffffe00000000000000
+000000000000000000000000000005fffffffffefefffffffe0000000000
+0000000000000000000000000000000005ffffffffffffffffffffc6c6c6
+c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5b7fffffffffffffffffffe00
+000000000000000000000000000000000000000005ffffffffffffffffff
+fe00000000000000000000000000000000000000000005ffffffffffffff
+ffffffc6c6c6c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5b7ffffffffff
+fffffffffe00000000000000000000000000000000000000000005ffffff
+fffffffffffffe00000000000000000000000000000000000000000005ff
+ffffffffffffffffffc6c6c6c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5
+b7fffffffffffffffffffe00000000000000000000000000000000000000
+000005fffffffffffffffffffe0000000000000000000000000000000000
+0000000005ffffffffffffffffffffc6c6c6c6c6c6c6c6c6c60000b5b5b5
+b5b5b5b5b5b5b7fffffffffffffffffffe00000000000000000000000000
+000000000000000005fffffffffffffffffffe0000000000000000000000
+0000000000000000000005ffffffffffffffffffffc6c6c6c6c6c6c6c6c6
+c60000b5b5b5b5b5b5b5b5b5b7fffffffffffffffffffe00000000000000
+000000000000000000000000000005fffffffffffffffffffe0000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/mexico.gif b/Docs/Flags/mexico.gif
new file mode 100644
index 00000000000..206d1236ef1
--- /dev/null
+++ b/Docs/Flags/mexico.gif
Binary files differ
diff --git a/Docs/Flags/mexico.pdf b/Docs/Flags/mexico.pdf
new file mode 100644
index 00000000000..c983198d2b5
--- /dev/null
+++ b/Docs/Flags/mexico.pdf
Binary files differ
diff --git a/Docs/Flags/island.txt b/Docs/Flags/mexico.txt
index e69de29bb2d..e69de29bb2d 100644
--- a/Docs/Flags/island.txt
+++ b/Docs/Flags/mexico.txt
diff --git a/Docs/Flags/netherlands.eps b/Docs/Flags/netherlands.eps
index 6f4d9906a11..94795e98baa 100644
--- a/Docs/Flags/netherlands.eps
+++ b/Docs/Flags/netherlands.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: netherlands.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7
-575757575757575757575757575757575757575757575757575757575757
-575757575757575757575757575757575757575757575757575757575757
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c
-464646464646464646464646464646464646464646464646464646464646
-c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8
-080808080808080808080808080808080808080808080808080808080808
-000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080808080808080808080808080808080808080808080808
-000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080808080808080808080808080808080808080808080808
-000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080808080808080808080808080808080808080808080808
-000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080808080808080808080808080808080808080808080808
-000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080808080808080808080808080808080808080808080808
-000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6
+d6d6d6d6d6d6d6d6d6d6d6d6d60000505050505050505050505050505050
+505050505050505050505050505050000050505050505050505050505050
+50505050505050505050505050505050500000f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700
+00f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700005959595959
+595959595959595959595959595959595959595959595959590000535353
+5353535353535353535353535353535353535353535353535353530000cb
+cbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcb00
+000808080808080808080808080808080808080808080808080808080808
+080000000000000000000000000000000000000000000000000000000000
+0000000000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b500000808080808080808080808080808080808080808080808
+080808080808080000000000000000000000000000000000000000000000
+0000000000000000000000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b500000808080808080808080808080808080808
+080808080808080808080808080000000000000000000000000000000000
+0000000000000000000000000000000000b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500000808080808080808080808
+080808080808080808080808080808080808080000000000000000000000
+0000000000000000000000000000000000000000000000b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500000808080808
+080808080808080808080808080808080808080808080808080000000000
+0000000000000000000000000000000000000000000000000000000000b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500
+000808080808080808080808080808080808080808080808080808080808
+080000000000000000000000000000000000000000000000000000000000
+0000000000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b500000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/netherlands.gif b/Docs/Flags/netherlands.gif
index c09d3eb495c..2f236b58949 100644
--- a/Docs/Flags/netherlands.gif
+++ b/Docs/Flags/netherlands.gif
Binary files differ
diff --git a/Docs/Flags/netherlands.pdf b/Docs/Flags/netherlands.pdf
new file mode 100644
index 00000000000..098629aee10
--- /dev/null
+++ b/Docs/Flags/netherlands.pdf
Binary files differ
diff --git a/Docs/Flags/norway.eps b/Docs/Flags/norway.eps
new file mode 100755
index 00000000000..af62cbef81f
--- /dev/null
+++ b/Docs/Flags/norway.eps
@@ -0,0 +1,98 @@
+%!PS-Adobe-2.0 EPSF-2.0
+%%Creator: pnmtops
+%%Title: norway.ps
+%%Pages: 1
+%%BoundingBox: 290 385 321 407
+%%EndComments
+/readstring {
+ currentfile exch readhexstring pop
+} bind def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
+%%EndProlog
+%%Page: 1 1
+gsave
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
+{ rpicstr readstring }
+{ gpicstr readstring }
+{ bpicstr readstring }
+true 3
+colorimage
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000c6c6c6c6c6c6c6c6d00808d0c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c600000000000000000000cf0000cb000000000000000000
+00000000000000000000000000000000000000ecb5b5e900000000000000
+00000000000000000000000000c6c6c6c6c6c6c6c6d00808d0c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c600000000000000000000cf0000cb000000
+00000000000000000000000000000000000000000000000000ecb5b5e900
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6d00808
+d0c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c600000000000000000000cf
+0000cb000000000000000000000000000000000000000000000000000000
+00ecb5b5e90000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6d00808d0c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
+0000000000cf0000cb000000000000000000000000000000000000000000
+00000000000000ecb5b5e900000000000000000000000000000000000000
+00c6c6c6c6c6c6c6c6d00808d0c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c600000000000000000000cf0000cb000000000000000000000000000000
+00000000000000000000000000ecb5b5e900000000000000000000000000
+00000000000000c6c6c6c6c6c6c6c6d00808d0c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c600000000000000000000cf0000cb000000000000000000
+00000000000000000000000000000000000000ecb5b5e900000000000000
+00000000000000000000000000c6c6c6c6c6c6c6c6d00808d0c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c600000000000000000000cf0000cb000000
+00000000000000000000000000000000000000000000000000ecb5b5e900
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6d00808
+d0c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c600000000000000000000cf
+0000cb000000000000000000000000000000000000000000000000000000
+00ecb5b5e90000000000000000000000000000000000000000d0d0d0d0d0
+d0d0d0b00808b0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d00000cbcbcb
+cbcbcbcbcbad0000adcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcb0000e9
+e9e9e9e9e9e9e9e3b5b5e3e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e900
+000808080808080808080808080808080808080808080808080808080808
+080000000000000000000000000000000000000000000000000000000000
+0000000000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b500000808080808080808080808080808080808080808080808
+080808080808080000000000000000000000000000000000000000000000
+0000000000000000000000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b50000d0d0d0d0d0d0d0d0b00808b0d0d0d0d0d0
+d0d0d0d0d0d0d0d0d0d0d0d0d00000cfcfcfcfcfcfcfcfad0000adcfcfcf
+cfcfcfcfcfcfcfcfcfcfcfcfcfcfcf0000ecececececececece3b5b5e3ec
+ececececececececececececececececec0000c6c6c6c6c6c6c6c6d00808
+d0c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c600000000000000000000cf
+0000cb000000000000000000000000000000000000000000000000000000
+00ecb5b5e90000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6d00808d0c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
+0000000000cf0000cb000000000000000000000000000000000000000000
+00000000000000ecb5b5e900000000000000000000000000000000000000
+00c6c6c6c6c6c6c6c6d00808d0c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c600000000000000000000cf0000cb000000000000000000000000000000
+00000000000000000000000000ecb5b5e900000000000000000000000000
+00000000000000c6c6c6c6c6c6c6c6d00808d0c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c600000000000000000000cf0000cb000000000000000000
+00000000000000000000000000000000000000ecb5b5e900000000000000
+00000000000000000000000000c6c6c6c6c6c6c6c6d00808d0c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c600000000000000000000cf0000cb000000
+00000000000000000000000000000000000000000000000000ecb5b5e900
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6d00808
+d0c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c600000000000000000000cf
+0000cb000000000000000000000000000000000000000000000000000000
+00ecb5b5e90000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6d00808d0c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
+0000000000cf0000cb000000000000000000000000000000000000000000
+00000000000000ecb5b5e900000000000000000000000000000000000000
+00c6c6c6c6c6c6c6c6d00808d0c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c600000000000000000000cf0000cb000000000000000000000000000000
+00000000000000000000000000ecb5b5e900000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/norway.gif b/Docs/Flags/norway.gif
new file mode 100755
index 00000000000..e88d1029f3e
--- /dev/null
+++ b/Docs/Flags/norway.gif
Binary files differ
diff --git a/Docs/Flags/norway.pdf b/Docs/Flags/norway.pdf
new file mode 100644
index 00000000000..aaddf8c5ec4
--- /dev/null
+++ b/Docs/Flags/norway.pdf
Binary files differ
diff --git a/Docs/Flags/kroatia.eps b/Docs/Flags/norway.txt
index e69de29bb2d..e69de29bb2d 100644
--- a/Docs/Flags/kroatia.eps
+++ b/Docs/Flags/norway.txt
diff --git a/Docs/Flags/philippines.eps b/Docs/Flags/philippines.eps
new file mode 100644
index 00000000000..9c3b242568a
--- /dev/null
+++ b/Docs/Flags/philippines.eps
@@ -0,0 +1,98 @@
+%!PS-Adobe-2.0 EPSF-2.0
+%%Creator: pnmtops
+%%Title: philippines.ps
+%%Pages: 1
+%%BoundingBox: 290 385 321 407
+%%EndComments
+/readstring {
+ currentfile exch readhexstring pop
+} bind def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
+%%EndProlog
+%%Page: 1 1
+gsave
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
+{ rpicstr readstring }
+{ gpicstr readstring }
+{ bpicstr readstring }
+true 3
+colorimage
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000a91d080808080808080808080808080808080808080808
+080808080808080000a71600000000000000000000000000000000000000
+0000000000000000000000e2bbb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b50000f7e45a0808080808080808080808080808
+080808080808080808080808080000f6e354000000000000000000000000
+0000000000000000000000000000000000f3efcbb5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b50000f7fdf9a91d080808080808
+080808080808080808080808080808080808080000f6f8f5a71600000000
+0000000000000000000000000000000000000000000000eb3bbae2bbb5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b50000f9fdf9f7e4
+5a0808080808080808080808080808080808080808080808080000f5f8f5
+f7e3540000000000000000000000000000000000000000000000000000c8
+4fb2f7f2ccb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500
+00f7f8f7f7f7f7a91d080808080808080808080808080808080808080808
+080000f7f6f7f7f7f7a71600000000000000000000000000000000000000
+0000000000f7eaf7f7f7f7e2bbb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b50000f7f7f7f7f7f8f7e45a0808080808080808080808080808
+080808080808080000f7f7f7f7f6f5f7e354000000000000000000000000
+0000000000000000000000f7f7f7f7e8d8f7f2ccb5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b50000f7f7f8f7f9fbf7f8f7a91d080808080808
+080808080808080808080808080000f7f7f5f7f5f0f7f5f6a71600000000
+0000000000000000000000000000000000f7f7dcf7c785f7e1f2e2bbb5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b50000f7f7fcfafafdf8fcf9f7e4
+5a0808080808080808080808080808080808080000f7f6eef2f5f2f6eef3
+f7e3540000000000000000000000000000000000000000f7f26eaba44bd6
+66b9f7f2ccb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b50000f7f7f7feff
+fffffaf7f7f7f7a91d080808080808080808080808080808080000f7f7f6
+f4fffffcf2f7f7f7f7a616000000000000000000000000000000000000f7
+f7ea2800000290f7f7f7f7dfbbb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500
+00f7fafafffffffffdfaf8f7fafbe45a0808080808080808080808080808
+080000f7f2f1fefffffff7f2f4f7f5f6e354000000000000000000000000
+0000000000f5a49c0100000048a4caf79d71f2ccb5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b50000f7fafafffffffffdfaf8f7fbfdf4d7c4c4c4c4c4c4c4c4
+c4c4c4c4c4c4c40000f7f2f1fefffffff7f2f4f7f5f9e255000000000000
+0000000000000000000000f4a49c0200000049a4caf68a43c75602020202
+02020202020202020202020000f7f7f7fefffffffaf7f7f7f7e8cbc6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000f7f7f6f4fffffcf2f7f7f7f7a61600
+0000000000000000000000000000000000f7f7ea2800000290f7f7f7f793
+16000000000000000000000000000000000000f7f7fcfafafdf8fcf9f7f3
+d7c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000f7f6eef2f5f2f6eef3
+f7e4550000000000000000000000000000000000000000f7f26eaba44bd6
+66b9f7e4560000000000000000000000000000000000000000f7f7f8f7f9
+fbf7f8f7e8cbc6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000f7f7f5
+f7f5f0f7f5f6a816000000000000000000000000000000000000000000f7
+f7dcf7c785f7e1f2a8160000000000000000000000000000000000000000
+00f7f7f7f7f7f8f7f3d7c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000f7f7f7f7f6f5f7e455000000000000000000000000000000000000
+0000000000f7f7f7f7e8d8f7e45600000000000000000000000000000000
+00000000000000f7f7f7f7f7f7e8cbc6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000f7f6f7f7f7f7a81600000000000000000000000000
+0000000000000000000000f7edf7f7f7f7a8160000000000000000000000
+00000000000000000000000000f8fcf9f7f3d7c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000f6f8f5f7e455000000000000000000
+0000000000000000000000000000000000d553adf7e45600000000000000
+00000000000000000000000000000000000000f8fdfae8cbc6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000f6f8f5a81600000000
+0000000000000000000000000000000000000000000000e642ada8160000
+00000000000000000000000000000000000000000000000000f7f4d7c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000f7e355
+0000000000000000000000000000000000000000000000000000000000f7
+d95600000000000000000000000000000000000000000000000000000000
+00e8cbc6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000a81600000000000000000000000000000000000000000000000000
+0000000000a8160000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/philippines.gif b/Docs/Flags/philippines.gif
new file mode 100644
index 00000000000..884f2a5e8d2
--- /dev/null
+++ b/Docs/Flags/philippines.gif
Binary files differ
diff --git a/Docs/Flags/philippines.pdf b/Docs/Flags/philippines.pdf
new file mode 100644
index 00000000000..0b6639c24db
--- /dev/null
+++ b/Docs/Flags/philippines.pdf
Binary files differ
diff --git a/Docs/Flags/kroatia.gif b/Docs/Flags/philippines.txt
index e69de29bb2d..e69de29bb2d 100644
--- a/Docs/Flags/kroatia.gif
+++ b/Docs/Flags/philippines.txt
diff --git a/Docs/Flags/poland.eps b/Docs/Flags/poland.eps
index 40d4363a515..06c580e1625 100644
--- a/Docs/Flags/poland.eps
+++ b/Docs/Flags/poland.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: poland.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6
-f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0
-f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-010101010101010101010101010101010101010101010101010101010101
-010101010101010101010101010101010101010101010101010101010101
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
+00000000000000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700
+00f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700
+00f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f70000c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7
+c7c7c7c7c7c7c70000030303030303030303030303030303030303030303
+030303030303030303000003030303030303030303030303030303030303
+03030303030303030303030000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/poland.gif b/Docs/Flags/poland.gif
index 756f9398ee3..902b49f745d 100644
--- a/Docs/Flags/poland.gif
+++ b/Docs/Flags/poland.gif
Binary files differ
diff --git a/Docs/Flags/poland.pdf b/Docs/Flags/poland.pdf
new file mode 100644
index 00000000000..e2c696dda21
--- /dev/null
+++ b/Docs/Flags/poland.pdf
Binary files differ
diff --git a/Docs/Flags/portugal.eps b/Docs/Flags/portugal.eps
index 7bd24809850..01a83ecd6d1 100644
--- a/Docs/Flags/portugal.eps
+++ b/Docs/Flags/portugal.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: portugal.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-0000000000000000000ac6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-0000000000000000000ac6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-0000000000000000000ac6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-0000000000000000000ac6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-00000000000000033b6cd2cac6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b4bcc16033010000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-00000000000035c390a0dbe0e5cac6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5badfd4d58e93ba2900000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-000000000035e6bf77a5cdbed1eac9c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5bae6bb5194581086da26000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-0000000003c33fe2c4b7b8c8e0e3e0c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b4dfb8973e68614691b7b2000000000000000000000000000000
-0000000000000000342f302f000000000000000000000000000000000000
-000000003b904ebae65668e2bde5dec7c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5bcd4bf04e05064cd12b7b1240000000000000000000000000000
-0000000000000000e0cbd0cd000000000000000000000000000000000000
-0000000065dd91d658222963d7dad7d2c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5c4e4d26e501b2252737b7d530000000000000000000000000000
-0000000000000000b8bcbea8000000000000000000000000000000000000
-0000000064d0c8e363272e6ededaefcec6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5c4dbdb9a5b2027618c9aea4d0000000000000000000000000000
-0000000000000000babdc0aa000000000000000000000000000000000000
-00000000369700a6d95668d5bedce4c5c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5bad6b511a75064941e85bc1e0000000000000000000000000000
-00000000000000009bcbd088000000000000000000000000000000000000
-0000000001ba8fc8f7939df6d0cde3c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b4d7d097ce3f4fca874fae000000000000000000000000000000
-000000000000000006484503000000000000000000000000000000000000
-00000000002bdfc497a3bcd8e4e8c8c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b9e1dca73124a9d0d31e000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-00000000000029b9a3abdee3e3c8c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b9dcd9d89aa6ae1d00000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-00000000000000002859cfc7c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b7bb4d20000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-0000000000000000000ac6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-0000000000000000000ac6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-0000000000000000000ac6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-0000000000000000000ac6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000002c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5b30000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000002c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5b30000000000
+000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000002c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5
+b30000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+0000000002c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000b5b5b5
+b5b5b5b5b5b5b30000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+0000000000000000013462d2cac6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000b5b5b5b5b5b5b5b4bac35d31010000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000002ec0989ddde0e6cac6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000b5b5b5b5b5b5b9ded7d49795bc2c00000000000000
+000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000002ee3bd749ccfbdd0eacac6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000b5b5b5b5b5b9e5bc5991610a80db2c
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000001c046dfc5bbbb
+c4e2e3e2c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000b5b5b5b5b4debb9d3b
+65653b9ab3bc010000000000000000000000000000000000000000000000
+002b29292b00000000000000000000000000000000000000000000000034
+9843b8e45f5fe4bbe6dec8c6c6c6c6c6c6c6c6c6c6c6c6c6c60000b5b5b5
+b5bad7bd08d85959d807bfaf2f0000000000000000000000000000000000
+00000000000000d8cdcdd800000000000000000000000000000000000000
+000000000060da9ecf63282863d4d9d4d5c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000b5b5b5b5c3e3d6685822225868796d610000000000000000000000
+00000000000000000000000000b4bebeb400000000000000000000000000
+000000000000000000000061d5c9e35f26265fe3d8efd1c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000b5b5b5b5c4dcdda3551f1f559b8fea5c0000000000
+00000000000000000000000000000000000000b1bdbdb100000000000000
+0000000000000000000000000000000000349801a3d75f5fd7bce0e3c7c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000b5b5b5b5bad7b414a25959a21596b5
+2e0000000000000000000000000000000000000000000000009acdcd9a00
+000000000000000000000000000000000000000000000001bc81c3f69292
+f6cfcbe6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000b5b5b5b5b4d9cc91ca
+4a4aca8141bb010000000000000000000000000000000000000000000000
+000751510700000000000000000000000000000000000000000000000000
+2de2c9a4a6bbd9e2ebc9c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000b5b5b5
+b5b5b9e3ddad281fafccdf2b000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000002fc0989ddde0e6c9c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000b5b5b5b5b5b5baded7d49795bc2b00000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000013462d2cac6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b4bac35d31010000000000000000
+000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000002c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5b30000000000
+000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000002c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000b5b5b5b5b5b5b5b5b5
+b30000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+0000000002c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000b5b5b5
+b5b5b5b5b5b5b30000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+0000000000000000000002c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000b5b5b5b5b5b5b5b5b5b30000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/portugal.gif b/Docs/Flags/portugal.gif
index 91bf32addb2..add53255d60 100644
--- a/Docs/Flags/portugal.gif
+++ b/Docs/Flags/portugal.gif
Binary files differ
diff --git a/Docs/Flags/portugal.pdf b/Docs/Flags/portugal.pdf
new file mode 100644
index 00000000000..d1f66f846db
--- /dev/null
+++ b/Docs/Flags/portugal.pdf
Binary files differ
diff --git a/Docs/Flags/romania.eps b/Docs/Flags/romania.eps
index 03b53f502a1..c20a7b6871b 100644
--- a/Docs/Flags/romania.eps
+++ b/Docs/Flags/romania.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: romania.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-08080808080808080815fffffffffffffffffffac6c6c6c6c6c6c6c6c6c6
-0000000000000000000dffffffffffffffffffe800000000000000000000
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
-08080808080808080815fffffffffffffffffffac6c6c6c6c6c6c6c6c6c6
-0000000000000000000dffffffffffffffffffe800000000000000000000
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
-08080808080808080815fffffffffffffffffffac6c6c6c6c6c6c6c6c6c6
-0000000000000000000dffffffffffffffffffe800000000000000000000
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
-08080808080808080815fffffffffffffffffffac6c6c6c6c6c6c6c6c6c6
-0000000000000000000dffffffffffffffffffe800000000000000000000
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
-08080808080808080815fffffffffffffffffffac6c6c6c6c6c6c6c6c6c6
-0000000000000000000dffffffffffffffffffe800000000000000000000
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
-08080808080808080815fffffffffffffffffffac6c6c6c6c6c6c6c6c6c6
-0000000000000000000dffffffffffffffffffe800000000000000000000
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
-08080808080808080815fffffffffffffffffffac6c6c6c6c6c6c6c6c6c6
-0000000000000000000dffffffffffffffffffe800000000000000000000
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
-08080808080808080815fffffffffffffffffffac6c6c6c6c6c6c6c6c6c6
-0000000000000000000dffffffffffffffffffe800000000000000000000
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
-08080808080808080815fffffffffffffffffffac6c6c6c6c6c6c6c6c6c6
-0000000000000000000dffffffffffffffffffe800000000000000000000
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
-08080808080808080815fffffffffffffffffffac6c6c6c6c6c6c6c6c6c6
-0000000000000000000dffffffffffffffffffe800000000000000000000
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
-08080808080808080815fffffffffffffffffffac6c6c6c6c6c6c6c6c6c6
-0000000000000000000dffffffffffffffffffe800000000000000000000
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
-08080808080808080815fffffffffffffffffffac6c6c6c6c6c6c6c6c6c6
-0000000000000000000dffffffffffffffffffe800000000000000000000
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
-08080808080808080815fffffffffffffffffffac6c6c6c6c6c6c6c6c6c6
-0000000000000000000dffffffffffffffffffe800000000000000000000
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
-08080808080808080815fffffffffffffffffffac6c6c6c6c6c6c6c6c6c6
-0000000000000000000dffffffffffffffffffe800000000000000000000
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
-08080808080808080815fffffffffffffffffffac6c6c6c6c6c6c6c6c6c6
-0000000000000000000dffffffffffffffffffe800000000000000000000
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
-08080808080808080815fffffffffffffffffffac6c6c6c6c6c6c6c6c6c6
-0000000000000000000dffffffffffffffffffe800000000000000000000
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
-08080808080808080815fffffffffffffffffffac6c6c6c6c6c6c6c6c6c6
-0000000000000000000dffffffffffffffffffe800000000000000000000
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
-08080808080808080815fffffffffffffffffffac6c6c6c6c6c6c6c6c6c6
-0000000000000000000dffffffffffffffffffe800000000000000000000
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
-08080808080808080815fffffffffffffffffffac6c6c6c6c6c6c6c6c6c6
-0000000000000000000dffffffffffffffffffe800000000000000000000
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
-08080808080808080815fffffffffffffffffffac6c6c6c6c6c6c6c6c6c6
-0000000000000000000dffffffffffffffffffe800000000000000000000
-b5b5b5b5b5b5b5b5b5ab0000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000808080808080808080bffffffffffffffffffffc6c6c6
+c6c6c6c6c6c6c6000000000000000000000003fffffffffffffffffffc00
+0000000000000000000000b5b5b5b5b5b5b5b5b5b3000000000000000000
+000000000000000000000000000808080808080808080bffffffffffffff
+ffffffc6c6c6c6c6c6c6c6c6c6000000000000000000000003ffffffffff
+fffffffffc000000000000000000000000b5b5b5b5b5b5b5b5b5b3000000
+000000000000000000000000000000000000000808080808080808080bff
+ffffffffffffffffffc6c6c6c6c6c6c6c6c6c60000000000000000000000
+03fffffffffffffffffffc000000000000000000000000b5b5b5b5b5b5b5
+b5b5b3000000000000000000000000000000000000000000000808080808
+080808080bffffffffffffffffffffc6c6c6c6c6c6c6c6c6c60000000000
+00000000000003fffffffffffffffffffc000000000000000000000000b5
+b5b5b5b5b5b5b5b5b3000000000000000000000000000000000000000000
+000808080808080808080bffffffffffffffffffffc6c6c6c6c6c6c6c6c6
+c6000000000000000000000003fffffffffffffffffffc00000000000000
+0000000000b5b5b5b5b5b5b5b5b5b3000000000000000000000000000000
+000000000000000808080808080808080bffffffffffffffffffffc6c6c6
+c6c6c6c6c6c6c6000000000000000000000003fffffffffffffffffffc00
+0000000000000000000000b5b5b5b5b5b5b5b5b5b3000000000000000000
+000000000000000000000000000808080808080808080bffffffffffffff
+ffffffc6c6c6c6c6c6c6c6c6c6000000000000000000000003ffffffffff
+fffffffffc000000000000000000000000b5b5b5b5b5b5b5b5b5b3000000
+000000000000000000000000000000000000000808080808080808080bff
+ffffffffffffffffffc6c6c6c6c6c6c6c6c6c60000000000000000000000
+03fffffffffffffffffffc000000000000000000000000b5b5b5b5b5b5b5
+b5b5b3000000000000000000000000000000000000000000000808080808
+080808080bffffffffffffffffffffc6c6c6c6c6c6c6c6c6c60000000000
+00000000000003fffffffffffffffffffc000000000000000000000000b5
+b5b5b5b5b5b5b5b5b3000000000000000000000000000000000000000000
+000808080808080808080bffffffffffffffffffffc6c6c6c6c6c6c6c6c6
+c6000000000000000000000003fffffffffffffffffffc00000000000000
+0000000000b5b5b5b5b5b5b5b5b5b3000000000000000000000000000000
+000000000000000808080808080808080bffffffffffffffffffffc6c6c6
+c6c6c6c6c6c6c6000000000000000000000003fffffffffffffffffffc00
+0000000000000000000000b5b5b5b5b5b5b5b5b5b3000000000000000000
+000000000000000000000000000808080808080808080bffffffffffffff
+ffffffc6c6c6c6c6c6c6c6c6c6000000000000000000000003ffffffffff
+fffffffffc000000000000000000000000b5b5b5b5b5b5b5b5b5b3000000
+000000000000000000000000000000000000000808080808080808080bff
+ffffffffffffffffffc6c6c6c6c6c6c6c6c6c60000000000000000000000
+03fffffffffffffffffffc000000000000000000000000b5b5b5b5b5b5b5
+b5b5b3000000000000000000000000000000000000000000000808080808
+080808080bffffffffffffffffffffc6c6c6c6c6c6c6c6c6c60000000000
+00000000000003fffffffffffffffffffc000000000000000000000000b5
+b5b5b5b5b5b5b5b5b3000000000000000000000000000000000000000000
+000808080808080808080bffffffffffffffffffffc6c6c6c6c6c6c6c6c6
+c6000000000000000000000003fffffffffffffffffffc00000000000000
+0000000000b5b5b5b5b5b5b5b5b5b3000000000000000000000000000000
+000000000000000808080808080808080bffffffffffffffffffffc6c6c6
+c6c6c6c6c6c6c6000000000000000000000003fffffffffffffffffffc00
+0000000000000000000000b5b5b5b5b5b5b5b5b5b3000000000000000000
+000000000000000000000000000808080808080808080bffffffffffffff
+ffffffc6c6c6c6c6c6c6c6c6c6000000000000000000000003ffffffffff
+fffffffffc000000000000000000000000b5b5b5b5b5b5b5b5b5b3000000
+000000000000000000000000000000000000000808080808080808080bff
+ffffffffffffffffffc6c6c6c6c6c6c6c6c6c60000000000000000000000
+03fffffffffffffffffffc000000000000000000000000b5b5b5b5b5b5b5
+b5b5b3000000000000000000000000000000000000000000000808080808
+080808080bffffffffffffffffffffc6c6c6c6c6c6c6c6c6c60000000000
+00000000000003fffffffffffffffffffc000000000000000000000000b5
+b5b5b5b5b5b5b5b5b3000000000000000000000000000000000000000000
+000808080808080808080bffffffffffffffffffffc6c6c6c6c6c6c6c6c6
+c6000000000000000000000003fffffffffffffffffffc00000000000000
+0000000000b5b5b5b5b5b5b5b5b5b3000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/romania.gif b/Docs/Flags/romania.gif
index 2d38df262bf..a6ffa4ad0c2 100644
--- a/Docs/Flags/romania.gif
+++ b/Docs/Flags/romania.gif
Binary files differ
diff --git a/Docs/Flags/romania.pdf b/Docs/Flags/romania.pdf
new file mode 100644
index 00000000000..45503c541bf
--- /dev/null
+++ b/Docs/Flags/romania.pdf
Binary files differ
diff --git a/Docs/Flags/russia.eps b/Docs/Flags/russia.eps
index 85c5899d891..ce1e2cb22c1 100644
--- a/Docs/Flags/russia.eps
+++ b/Docs/Flags/russia.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: russia.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3
-a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0
-e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0
-080808080808080808080808080808080808080808080808080808080808
000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080808080808080808080808080808080808080808080808
-000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080808080808080808080808080808080808080808080808
-000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080808080808080808080808080808080808080808080808
-000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080808080808080808080808080808080808080808080808
-000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-080808080808080808080808080808080808080808080808080808080808
-000000000000000000000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-909090909090909090909090909090909090909090909090909090909090
-000000000000000000000000000000000000000000000000000000000000
-333333333333333333333333333333333333333333333333333333333333
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700
+00f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f70000a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9
+a9a9a9a9a9a9a9a9a9a9a9a9a90000a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7
+a7a7a7a7a7a7a7a7a7a7a7a7a7a7a70000e2e2e2e2e2e2e2e2e2e2e2e2e2
+e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e200000808080808080808080808
+080808080808080808080808080808080808080000000000000000000000
+0000000000000000000000000000000000000000000000b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500000808080808
+080808080808080808080808080808080808080808080808080000000000
+0000000000000000000000000000000000000000000000000000000000b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500
+000808080808080808080808080808080808080808080808080808080808
+080000000000000000000000000000000000000000000000000000000000
+0000000000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b500000808080808080808080808080808080808080808080808
+080808080808080000000000000000000000000000000000000000000000
+0000000000000000000000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b500000808080808080808080808080808080808
+080808080808080808080808080000000000000000000000000000000000
+0000000000000000000000000000000000b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500000808080808080808080808
+080808080808080808080808080808080808080000000000000000000000
+0000000000000000000000000000000000000000000000b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500008686868686
+868686868686868686868686868686868686868686868686860000000000
+00000000000000000000000000000000000000000000000000000000003d
+3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d00
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/russia.gif b/Docs/Flags/russia.gif
index f72e7f78da6..f76e19d7f1b 100644
--- a/Docs/Flags/russia.gif
+++ b/Docs/Flags/russia.gif
Binary files differ
diff --git a/Docs/Flags/russia.pdf b/Docs/Flags/russia.pdf
new file mode 100644
index 00000000000..84c304cba32
--- /dev/null
+++ b/Docs/Flags/russia.pdf
Binary files differ
diff --git a/Docs/Flags/singapore.eps b/Docs/Flags/singapore.eps
index bc5faf248a7..5ebedcb4f94 100644
--- a/Docs/Flags/singapore.eps
+++ b/Docs/Flags/singapore.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: singapore.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-c6c6c6c6c6cbc9c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-0000000001180d0000000000000000000000000000000000000000000000
-0000000001180e0000000000000000000000000000000000000000000000
-c6c6c6d7ecd6c7c6c8c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-00000054bd5004000b000000000000000000000000000000000000000000
-00000054bd5004000b000000000000000000000000000000000000000000
-c6c6d8f4cdc6c6c8e9ccc6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000059e72200000aae1f0000000000000000000000000000000000000000
-000059e72200000aae1f0000000000000000000000000000000000000000
-c6c7f3dfc6c7c9c6cfc8c6cac6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-0004e07d000410002c0b0015000000000000000000000000000000000000
-0004e07d000410002d0b0015000000000000000000000000000000000000
-c6cff7d2c6dbe0c6c6c6d6e5c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-002af73e0067830000004d9b010000000000000000000000000000000000
-002bf73f0067830000004e9c010000000000000000000000000000000000
-c6cef7d3c6c9c9c6c6c6c9c9c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-0029f740000d0d0000000d0d000000000000000000000000000000000000
-0029f740000d0d0000000d0d000000000000000000000000000000000000
-c6c7f2e0c6c6c7c9c6c6cac6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-0003dd810000060e00001500000000000000000000000000000000000000
-0003dd810000060e00001500000000000000000000000000000000000000
-c6c6d7f4cec6dcdfc6d4e6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000052e927006c7e0048a102000000000000000000000000000000000000
-000053e927006d7e0048a102000000000000000000000000000000000000
-c6c6c6d5ebd8cbc9c6c9c9c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-0000004bb859160d000d0e00000000000000000000000000000000000000
-0000004bb85a160d000d0e00000000000000000000000000000000000000
-c8c8c8c8c8cbcac8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8
-070707070716100707070707070707070707070707070707070707070707
-070707070716100707070707070707070707070707070707070707070707
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6
-f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000c6c6c6c6c6cbc9c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c600000000000000170e0000000000000000000000000000
+00000000000000000000000000000000170e000000000000000000000000
+00000000000000000000000000c6c6c6d6ecd7c7c6c8c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6000000000050bd5405000a000000000000
+000000000000000000000000000000000000000050bd5405000a00000000
+00000000000000000000000000000000000000c6c6d7f4cdc6c6c8e8cdc6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000055e925000008aa
+2400000000000000000000000000000000000000000000000055e9250000
+08aa2400000000000000000000000000000000000000000000c6c7f2e0c6
+c6cac6cfc9c6cac6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c600000003de
+81000211002c0e0013000000000000000000000000000000000000000000
+03de82000211002d0e001400000000000000000000000000000000000000
+00c6cef7d3c6dae1c6c6c6d3e7c7c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c600000028f74200618900000042a5020000000000000000000000000000
+00000000000028f74200618900000043a503000000000000000000000000
+00000000000000c6cef7d3c6c9c9c6c6c6c9c9c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c600000028f742000f0f0000000e0f000000000000000000
+00000000000000000000000028f742000f0f0000000e1000000000000000
+00000000000000000000000000c6c7f2e0c6c6c7c9c6c6cac6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c600000003de810000030f00001300000000
+00000000000000000000000000000000000003de820000030f0000130000
+00000000000000000000000000000000000000c6c6d7f4cdc6dae0c6d2e8
+c7c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000055e92500658400
+3ea8030000000000000000000000000000000000000000000055e9250065
+84003ea8030000000000000000000000000000000000000000c6c6c6d6ec
+d7cac9c6c9cac6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
+50bd541510000f1200000000000000000000000000000000000000000000
+000050bd541510000f120000000000000000000000000000000000000000
+00c6c6c6c6c6cbc9c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c600000000000000170e0000000000000000000000000000000000000000
+00000000000000000000170e000000000000000000000000000000000000
+00000000000000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f70000f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4
+f4f4f4f4f4f4f4f4f40000f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4
+f4f4f4f4f4f4f4f4f4f4f40000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700
+00f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700
+00f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f700000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/singapore.gif b/Docs/Flags/singapore.gif
index 7fbd3f87f62..38b06409764 100644
--- a/Docs/Flags/singapore.gif
+++ b/Docs/Flags/singapore.gif
Binary files differ
diff --git a/Docs/Flags/singapore.pdf b/Docs/Flags/singapore.pdf
new file mode 100644
index 00000000000..1d2666f851c
--- /dev/null
+++ b/Docs/Flags/singapore.pdf
Binary files differ
diff --git a/Docs/Flags/slovenia.eps b/Docs/Flags/slovenia.eps
new file mode 100755
index 00000000000..59b6482f5fa
--- /dev/null
+++ b/Docs/Flags/slovenia.eps
@@ -0,0 +1,98 @@
+%!PS-Adobe-2.0 EPSF-2.0
+%%Creator: pnmtops
+%%Title: slovenia.ps
+%%Pages: 1
+%%BoundingBox: 290 385 321 407
+%%EndComments
+/readstring {
+ currentfile exch readhexstring pop
+} bind def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
+%%EndProlog
+%%Page: 1 1
+gsave
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
+{ rpicstr readstring }
+{ gpicstr readstring }
+{ bpicstr readstring }
+true 3
+colorimage
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7ad4d463b3b3b5340
+e5f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f77d221a0f0f0f
+2814c0f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7ad8a8f97
+97978593c7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f79b43
+330d39085d18e2f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7
+753c2c0533005811bcf7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7
+f7f7b58a95b291b576a9c6f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700
+00f7f7f79b08080c55080808e2f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f70000f7f7f7750000054f000000bcf7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000f7f7f7b5b5b5b281b5b5b5c6f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f70000f7f7f79b0808149a080808e2f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f70000f7f7f77500000c97000000bcf7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000f7f7f7b5b5b5b8ddb5b5b5c6f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f70000a9a9a9763f3a74f52f6316a6a9a9a9a9a9
+a9a9a9a9a9a9a9a9a9a9a9a9a90000a7a7a74f393370f5295e0e7fa7a7a7
+a7a7a7a7a7a7a7a7a7a7a7a7a7a7a70000e2e2e2aac4c3d3f7c0ceb9b6e2
+e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2000008080836dae0e0f7cbf5aa
+2108080808080808080808080808080808080800000000000cd9dfdff7c9
+f59c000000000000000000000000000000000000000000b5b5b597eff1f1
+f7ebf6d59eb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5000008080822bd
+c3e9f7d8c1a0080808080808080808080808080808080808080000000000
+05d1e8f3f7eee792000000000000000000000000000000000000000000b5
+b5b5a3e0f5f7f7f6f5bbb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500
+000808080872c3b5c1b1bf3d080808080808080808080808080808080808
+0800000000000059e8e4e7e2dd1f00000000000000000000000000000000
+0000000000b5b5b5b5a8f5f5f5f5eb9fb5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b500000808080812c0e0c4eb8308080808080808080808080808
+080808080808080000000000000096f0e8f0510000000000000000000000
+0000000000000000000000b5b5b5b5acb8f6f5f3a0b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b50000080808080816abf0770908080808080808
+08080808080808080808080808000000000000000179dc44000000000000
+0000000000000000000000000000000000b5b5b5b5b5aaaade9cb4b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500000808080808080925080808
+080808080808080808080808080808080808080000000000000000000200
+0000000000000000000000000000000000000000000000b5b5b5b5b5b5b4
+9bb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500008686868686
+868686868686868686868686868686868686868686868686860000000000
+00000000000000000000000000000000000000000000000000000000003d
+3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d00
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/slovenia.gif b/Docs/Flags/slovenia.gif
new file mode 100644
index 00000000000..2cac6590840
--- /dev/null
+++ b/Docs/Flags/slovenia.gif
Binary files differ
diff --git a/Docs/Flags/slovenia.pdf b/Docs/Flags/slovenia.pdf
new file mode 100644
index 00000000000..b00ca0e6467
--- /dev/null
+++ b/Docs/Flags/slovenia.pdf
Binary files differ
diff --git a/Docs/Flags/kroatia.txt b/Docs/Flags/slovenia.txt
index e69de29bb2d..e69de29bb2d 100644..100755
--- a/Docs/Flags/kroatia.txt
+++ b/Docs/Flags/slovenia.txt
diff --git a/Docs/Flags/south-africa.eps b/Docs/Flags/south-africa.eps
index 702df9d4e6a..6c080095104 100644
--- a/Docs/Flags/south-africa.eps
+++ b/Docs/Flags/south-africa.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: south-africa.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-0000001fb8e6cac6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b5b5b5bde6a3140000000000000000000000000000000000000000000000
-0000001fb8a4140000000000000000000000000000000000000000000000
-000000000169e9d6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5d1df5100000000000000000000000000000000000000000000
-000000000169d85100000000000000000000000000000000000000000000
-00000000000023bde6cac6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5bee8a3140000000000000000000000000000000000000000
-00000000000023bda3140000000000000000000000000000000000000000
-080000000000000370ebd6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b7b5b5b5b5b5b5b6d3df5100000000000000000000000000000000000000
-000000000000000370da5100000000000000000000000000000000000000
-db480000000000000028c3e6cac6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-f5cab5b5b5b5b5b5b5c0e9a3140000000000000000000000000000000000
-00000000000000000028c3a3140000000000000000000000000000000000
-4bddac1d0000000000000477edd6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-4bdde7bdb5b5b5b5b5b5b6d5e05100000000000000000000000000000000
-000000000000000000000477dc5100000000000000000000000000000000
-000982eb74050000000000002dc8e6d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8
-000982f4d7b6b5b5b5b5b5b5c1eaa45a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
-0000000000000000000000002dc8a45a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
-00000025b8d23d00000000000005769f9f9f9f9f9f9f9f9f9f9f9f9f9f9f
-00000025b8f2c7b5b5b5b5b5b5b6d5e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0
-0000000000000000000000000005769f9f9f9f9f9f9f9f9f9f9f9f9f9f9f
-000000000054e19f15000000000000000000000000000000000000000000
-000000000054e2e3bbb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
000000000000000000000000000000000000000000000000000000000000
-0000000000000c8ae9670100000000000000000000000000000000000000
-0000000000000c8af6d3b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
000000000000000000000000000000000000000000000000000000000000
-000000000000159ee1530000000000000000000000000000000000000000
-000000000000159ef6cdb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
000000000000000000000000000000000000000000000000000000000000
-000000000268e88b0c000000000000000000000000000000000000000000
-000000000268ecdeb9b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+000000000000000000001eb6e7cac6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000b5b5b5bde6a7160000000000000000000000000000
+00000000000000000000000000001eb6a716000000000000000000000000
+00000000000000000000000000000000000167e8d7c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000b5b5b5b5b5d1e05400000000000000
+0000000000000000000000000000000000000000000167d9540000000000
+0000000000000000000000000000000000000000000000000022bce7cac6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000b5b5b5b5b5b5bee7a7
+160000000000000000000000000000000000000000000000000000000022
+bca716000000000000000000000000000000000000000000000700000000
+0000026eead7c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000b7b5b5
+b5b5b5b5b6d2e15400000000000000000000000000000000000000000000
+000000000000026edb540000000000000000000000000000000000000000
+00d9450000000000000026c1e7cac6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000f4c9b5b5b5b5b5b5b5bfe9a7160000000000000000000000000000
+000000000000000000000000000026c1a716000000000000000000000000
+0000000000000050e0a81a0000000000000374ecd7c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6000050e0e6bdb5b5b5b5b5b5b6d4e25400000000000000
+0000000000000000000000000000000000000000000374dd540000000000
+00000000000000000000000000000b87eb70040000000000002bc6e7d7d7
+d7d7d7d7d7d7d7d7d7d7d7d7d70000000b87f5d6b6b5b5b5b5b5b5c0eaa7
+53535353535353535353535353535300000000000000000000000000002b
+c6a7545454545454545454545454545454000000000028bdcf3900000000
+00000576a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7000000000028bdf1c6b5b5
+b5b5b5b5b6d5e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2000000000000000000
+0000000000000576a7a7a7a7a7a7a7a7a7a7a7a7a7a7a700000000000000
+59e49b130000000000000000000000000000000000000000000000000000
+000059e5e2bbb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5000000
000000000000000000000000000000000000000000000000000000000000
-00000034cac22c0000000000000b89b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3
-00000034caedc2b5b5b5b5b5b5b8dae5e5e5e5e5e5e5e5e5e5e5e5e5e5e5
-000000000000000000000000000b89b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3
-001195e760010000000000003cd4944c4c4c4c4c4c4c4c4c4c4c4c4c4c4c
-001195f6d1b5b5b5b5b5b5b5c5ed90464646464646464646464646464646
-0000000000000000000000003cd5dcc8c8c8c8c8c8c8c8c8c8c8c8c8c8c8
-5fe79812000000000000098ad64508080808080808080808080808080808
-5fe8e1bab5b5b5b5b5b5b7dad63f00000000000000000000000000000000
-00000000000000000000098aecc6b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-cd360000000000000036cf93130808080808080808080808080808080808
-f1c5b5b5b5b5b5b5b5c4eb900c0000000000000000000000000000000000
-00000000000000000036d1dcb8b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-030000000000000783d54508080808080808080808080808080808080808
-b6b5b5b5b5b5b5b7d8d63f00000000000000000000000000000000000000
-000000000000000783ebc6b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-00000000000031cb94140808080808080808080808080808080808080808
-b5b5b5b5b5b5c2ea910c0000000000000000000000000000000000000000
-00000000000031ccdcb8b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-00000000057dd44608080808080808080808080808080808080808080808
-b5b5b5b5b6d6d64000000000000000000000000000000000000000000000
-00000000057deac6b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-0000002ac795140808080808080808080808080808080808080808080808
-b5b5b5c0ea920c0000000000000000000000000000000000000000000000
-0000002ac7dcb8b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+000000000000000e90e86301000000000000000000000000000000000000
+0000000000000000000e90f6d2b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5000000000000000000000000000000000000000000000000000000
+000000000000000000000000000e90e86301000000000000000000000000
+0000000000000000000000000000000e90f6d2b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5000000000000000000000000000000000000000000
+00000000000000000000000000000000000059e49b130000000000000000
+000000000000000000000000000000000000000059e5e2bbb5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5000000000000000000000000000000
+0000000000000000000000000000000000000000000028bdcf3900000000
+00000576a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7000000000028bdf1c6b5b5
+b5b5b5b5b6d5e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2000000000000000000
+0000000000000576a7a7a7a7a7a7a7a7a7a7a7a7a7a7a70000000b87eb70
+040000000000002bc6a95959595959595959595959595959590000000b87
+f5d6b6b5b5b5b5b5b5c0eaa7535353535353535353535353535353000000
+00000000000000000000002bc6e2cbcbcbcbcbcbcbcbcbcbcbcbcbcbcb00
+0050e0a81a0000000000000374dd5a080808080808080808080808080808
+08000050e0e6bdb5b5b5b5b5b5b6d4e25400000000000000000000000000
+0000000000000000000000000000000374ebccb5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b50000d9450000000000000026c1a91d08080808080808080808
+080808080808080000f4c9b5b5b5b5b5b5b5bfe9a7160000000000000000
+000000000000000000000000000000000000000026c1e2bbb5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5000007000000000000026edb5a080808080808
+080808080808080808080808080000b7b5b5b5b5b5b5b6d2e15400000000
+000000000000000000000000000000000000000000000000026ee9ccb5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5000000000000000022bcaa1d08
+080808080808080808080808080808080808080000b5b5b5b5b5b5bee7a8
+160000000000000000000000000000000000000000000000000000000022
+bce2bbb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500000000000001
+67da5b080808080808080808080808080808080808080808080000b5b5b5
+b5b5d1e15500000000000000000000000000000000000000000000000000
+0000000167e7ccb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500
+000000001eb6aa1d08080808080808080808080808080808080808080808
+080000b5b5b5bde6a8160000000000000000000000000000000000000000
+00000000000000001eb6e2bbb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b500000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/south-africa.gif b/Docs/Flags/south-africa.gif
index 7fd4ced4469..3ed8559eb2a 100644
--- a/Docs/Flags/south-africa.gif
+++ b/Docs/Flags/south-africa.gif
Binary files differ
diff --git a/Docs/Flags/south-africa.pdf b/Docs/Flags/south-africa.pdf
new file mode 100644
index 00000000000..6b6286a7794
--- /dev/null
+++ b/Docs/Flags/south-africa.pdf
Binary files differ
diff --git a/Docs/Flags/south-africa1.eps b/Docs/Flags/south-africa1.eps
deleted file mode 100644
index 702df9d4e6a..00000000000
--- a/Docs/Flags/south-africa1.eps
+++ /dev/null
@@ -1,87 +0,0 @@
-%!PS-Adobe-2.0 EPSF-2.0
-%%Creator: pnmtops
-%%Title: noname.ps
-%%Pages: 1
-%%BoundingBox: 291 371 320 391
-%%EndComments
-/readstring {
- currentfile exch readhexstring pop
-} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
-%%EndProlog
-%%Page: 1 1
-gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
-{ rpicstr readstring }
-{ gpicstr readstring }
-{ bpicstr readstring }
-true 3
-colorimage
-0000001fb8e6cac6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b5b5b5bde6a3140000000000000000000000000000000000000000000000
-0000001fb8a4140000000000000000000000000000000000000000000000
-000000000169e9d6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5d1df5100000000000000000000000000000000000000000000
-000000000169d85100000000000000000000000000000000000000000000
-00000000000023bde6cac6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b5b5b5b5b5b5bee8a3140000000000000000000000000000000000000000
-00000000000023bda3140000000000000000000000000000000000000000
-080000000000000370ebd6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-b7b5b5b5b5b5b5b6d3df5100000000000000000000000000000000000000
-000000000000000370da5100000000000000000000000000000000000000
-db480000000000000028c3e6cac6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-f5cab5b5b5b5b5b5b5c0e9a3140000000000000000000000000000000000
-00000000000000000028c3a3140000000000000000000000000000000000
-4bddac1d0000000000000477edd6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-4bdde7bdb5b5b5b5b5b5b6d5e05100000000000000000000000000000000
-000000000000000000000477dc5100000000000000000000000000000000
-000982eb74050000000000002dc8e6d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8
-000982f4d7b6b5b5b5b5b5b5c1eaa45a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
-0000000000000000000000002dc8a45a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
-00000025b8d23d00000000000005769f9f9f9f9f9f9f9f9f9f9f9f9f9f9f
-00000025b8f2c7b5b5b5b5b5b5b6d5e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0
-0000000000000000000000000005769f9f9f9f9f9f9f9f9f9f9f9f9f9f9f
-000000000054e19f15000000000000000000000000000000000000000000
-000000000054e2e3bbb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-000000000000000000000000000000000000000000000000000000000000
-0000000000000c8ae9670100000000000000000000000000000000000000
-0000000000000c8af6d3b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-000000000000000000000000000000000000000000000000000000000000
-000000000000159ee1530000000000000000000000000000000000000000
-000000000000159ef6cdb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-000000000000000000000000000000000000000000000000000000000000
-000000000268e88b0c000000000000000000000000000000000000000000
-000000000268ecdeb9b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-000000000000000000000000000000000000000000000000000000000000
-00000034cac22c0000000000000b89b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3
-00000034caedc2b5b5b5b5b5b5b8dae5e5e5e5e5e5e5e5e5e5e5e5e5e5e5
-000000000000000000000000000b89b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3
-001195e760010000000000003cd4944c4c4c4c4c4c4c4c4c4c4c4c4c4c4c
-001195f6d1b5b5b5b5b5b5b5c5ed90464646464646464646464646464646
-0000000000000000000000003cd5dcc8c8c8c8c8c8c8c8c8c8c8c8c8c8c8
-5fe79812000000000000098ad64508080808080808080808080808080808
-5fe8e1bab5b5b5b5b5b5b7dad63f00000000000000000000000000000000
-00000000000000000000098aecc6b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-cd360000000000000036cf93130808080808080808080808080808080808
-f1c5b5b5b5b5b5b5b5c4eb900c0000000000000000000000000000000000
-00000000000000000036d1dcb8b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-030000000000000783d54508080808080808080808080808080808080808
-b6b5b5b5b5b5b5b7d8d63f00000000000000000000000000000000000000
-000000000000000783ebc6b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-00000000000031cb94140808080808080808080808080808080808080808
-b5b5b5b5b5b5c2ea910c0000000000000000000000000000000000000000
-00000000000031ccdcb8b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-00000000057dd44608080808080808080808080808080808080808080808
-b5b5b5b5b6d6d64000000000000000000000000000000000000000000000
-00000000057deac6b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-0000002ac795140808080808080808080808080808080808080808080808
-b5b5b5c0ea920c0000000000000000000000000000000000000000000000
-0000002ac7dcb8b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-grestore
-showpage
-%%Trailer
diff --git a/Docs/Flags/south-africa1.gif b/Docs/Flags/south-africa1.gif
deleted file mode 100644
index 7fd4ced4469..00000000000
--- a/Docs/Flags/south-africa1.gif
+++ /dev/null
Binary files differ
diff --git a/Docs/Flags/south-korea.eps b/Docs/Flags/south-korea.eps
index a363ab514c4..8147ce78acf 100644
--- a/Docs/Flags/south-korea.eps
+++ b/Docs/Flags/south-korea.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: south-korea.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7eff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f5f7f7f7f7f7f7
-f7f7f7f7f7f7eff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f5f7f7f7f7f7f7
-f7f7f7f7f7f7eff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f5f7f7f7f7f7f7
-f7f7f7f7f7985ad7f7f7f7f7f7f7f7f7f7f7f7f7f7f7c255d3f7f7f7f7f7
-f7f7f7f7f7985ad7f7f7f7f7f7f7f7f7f7f7f7f7f7f7c255d3f7f7f7f7f7
-f7f7f7f7f7985ad7f7f7f7f7f7f7f7f7f7f7f7f7f7f7c255d3f7f7f7f7f7
-f7f7f7f7d6434363f7f7f7f7f7f7f7f7f7f7f7f7f7f0474476f6f7f7f7f7
-f7f7f7f7d6434363f7f7f7f7f7f7f7f7f7f7f7f7f7f0474476f6f7f7f7f7
-f7f7f7f7d6434363f7f7f7f7f7f7f7f7f7f7f7f7f7f0474476f6f7f7f7f7
-f7f7f7f7584345e4f7f7f7f7f7f6f1f1f7f7f7f7f7f7ba5a4391f7f7f7f7
-f7f7f7f7584345e4f7f7f7f7f7f4d7d9f5f7f7f7f7f7ba5a4391f7f7f7f7
-f7f7f7f7584345e4f7f7f7f7f7f4d8d9f5f7f7f7f7f7ba5a4391f7f7f7f7
-f7f7f7f7d65ab0f7f7f7f7f5decac6c6cbe0f6f7f7f7f76570dcf7f7f7f7
-f7f7f7f7d65ab0f7f7f7f7ef791300001884f3f7f7f7f76570dcf7f7f7f7
-f7f7f7f7d65ab0f7f7f7f7ef791300001885f3f7f7f7f76570dcf7f7f7f7
-f7f7f7f7f7f3f7f7f7f7f5d2c6c6c6c6c6c6d6f7f7f7f7ecf4f7f7f7f7f7
-f7f7f7f7f7f3f7f7f7f7ed3a0000000000004ef4f7f7f7ecf4f7f7f7f7f7
-f7f7f7f7f7f3f7f7f7f7ed3a0000000000004ef4f7f7f7ecf4f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7d9c6c6c6c6c6c6c6c6e3f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f76c00000000000000008ff7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f76e00000000000000008ff7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7eebbc6c6c6c6bc68548ecef7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7ee0a000000000000000026f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f41600000000095a6d3526f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7c8b1c6c6c6c53908080875f5f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7c600000000000000000001eaf7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7ea140000000187b5b5b54eeaf7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7c75fc6c6c66a080808082cf4f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7c500000000000000000000e7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7ea6300000058b5b5b5b593e8f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7ed114b6b36080808080838f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7ed0900000000000000001df7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f4b7755789b5b5b5b5b5a9f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f76b080808080808080884f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f76600000000000000007ef7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7d0b5b5b5b5b5b5b5b5d5f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7eef6f7f7f7ea3508080808080844f1f7f7f7ecedf7f7f7f7f7
-f7f7f7f7f7eef6f7f7f7e92f0000000000003ef1f7f7f7ecedf7f7f7f7f7
-f7f7f7f7f7eef6f7f7f7f3c1b5b5b5b5b5b5c6f5f7f7f7ecedf7f7f7f7f7
-f7f7f7f7cd569af7f7f7f7eb70140808187bf0f7f7f7f76b60d6f7f7f7f7
-f7f7f7f7cd569af7f7f7f7ea6b0c00001177f0f7f7f7f76b60d6f7f7f7f7
-f7f7f7f7cd569af7f7f7f7f4d2b8b5b5b9d5f5f7f7f7f76b60d6f7f7f7f7
-f7f7f7f7604b52dff7f7f7f7f7f1d0d2f3f7f7f7f7f7b4794787f7f7f7f7
-f7f7f7f7604b52dff7f7f7f7f7f1cfd1f3f7f7f7f7f7b4794787f7f7f7f7
-f7f7f7f7604b52dff7f7f7f7f7f5ecedf6f7f7f7f7f7b4794787f7f7f7f7
-f7f7f7f7e0504563f7f7f7f7f7f7f7f7f7f7f7f7f7f14a4678f5f7f7f7f7
-f7f7f7f7e0504563f7f7f7f7f7f7f7f7f7f7f7f7f7f14a4678f5f7f7f7f7
-f7f7f7f7e0504563f7f7f7f7f7f7f7f7f7f7f7f7f7f14a4678f5f7f7f7f7
-f7f7f7f7f79c64ddf7f7f7f7f7f7f7f7f7f7f7f7f7f7d060d8f7f7f7f7f7
-f7f7f7f7f79c64ddf7f7f7f7f7f7f7f7f7f7f7f7f7f7d060d8f7f7f7f7f7
-f7f7f7f7f79c64ddf7f7f7f7f7f7f7f7f7f7f7f7f7f7d060d8f7f7f7f7f7
-f7f7f7f7f7f7f4f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f4f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f4f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f0f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f6f7f7f7f7f7f70000f7f7f7f7f7f7f0f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f6f7f7f7f7f7f70000f7f7f7f7f7f7f0f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f6f7f7f7f7f7f70000f7f7f7f7f79f58d5f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7d05ac3f7f7f7f7f70000f7f7f7f7f79f58d5f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7d05ac3f7f7f7f7f70000f7f7f7f7f79f58
+d5f7f7f7f7f7f7f7f7f7f7f7f7f7f7d05ac3f7f7f7f7f70000f7f7f7f7db
+43435df7f7f7f7f7f7f7f7f7f7f7f7f7f54d446ef1f7f7f7f70000f7f7f7
+f7db43435df7f7f7f7f7f7f7f7f7f7f7f7f7f54d446ef1f7f7f7f70000f7
+f7f7f7db43435df7f7f7f7f7f7f7f7f7f7f7f7f7f54d446ef1f7f7f7f700
+00f7f7f7f75a4344dff7f7f7f7f7f7f2f2f7f7f7f7f7f7c660447df7f7f7
+f70000f7f7f7f75a4344dff7f7f7f7f7f6dddcf6f7f7f7f7f7c660447df7
+f7f7f70000f7f7f7f75a4344dff7f7f7f7f7f6dddcf6f7f7f7f7f7c66044
+7df7f7f7f70000f7f7f7f7d659a7f7f7f7f7f6e0cbc6c6cbe0f6f7f7f7f7
+7261d4f7f7f7f70000f7f7f7f7d659a7f7f7f7f7f3851a00001780f2f7f7
+f7f77261d4f7f7f7f70000f7f7f7f7d659a7f7f7f7f7f3851a00001880f2
+f7f7f7f77261d4f7f7f7f70000f7f7f7f7f7f2f7f7f7f7f6d4c6c6c6c6c6
+c6d4f6f7f7f7eef0f7f7f7f7f70000f7f7f7f7f7f2f7f7f7f7f246000000
+00000044f2f7f7f7eef0f7f7f7f7f70000f7f7f7f7f7f2f7f7f7f7f24600
+000000000044f2f7f7f7eef0f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7dc
+c6c6c6c6c6c6c6c6dff7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7
+f77a000000000000000080f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7f7f77d000000000000000080f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7
+f7f7f7f7f3b9c6c6c6c6c173598ecbf7f7f7f7f7f7f7f7f7f70000f7f7f7
+f7f7f7f7f7f7f311000000000000000017f5f7f7f7f7f7f7f7f7f70000f7
+f7f7f7f7f7f7f7f7f62000000000054f683517f5f7f7f7f7f7f7f7f7f700
+00f7f7f7f7f7f7f7f7f7d2abc6c6c6c6490808086cf1f7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f7f7d000000000000000000000d8f7f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f7f7ed1a0000000078b5b5b556d8f7f7f7f7
+f7f7f7f7f70000f7f7f7f7f7f7f7f7f7cf5cc6c6c67c080808081ef0f7f7
+f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7ce00000000000000000000d3
+f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7ec6500000046b5b5b5b5
+a0d4f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f113507544080808
+080825f6f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f10b00000000
+000000000bf2f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f5b8714e
+7cb5b5b5b5b5a7f2f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f76e
+08080808080808086cf7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7
+f76a000000000000000065f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7f7f7d1b5b5b5b5b5b5b5b5cef7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7
+f2f7f7f7f7ea3408080808080830e8f7f7f7f4ecf7f7f7f7f70000f7f7f7
+f7f7f2f7f7f7f7ea2d00000000000029e7f7f7f7f4ecf7f7f7f7f70000f7
+f7f7f7f7f2f7f7f7f7f3c1b5b5b5b5b5b5c0f3f7f7f7f4ecf7f7f7f7f700
+00f7f7f7f7d85f9df7f7f7f7e9690f08080e65e7f7f7f7f7845bd7f7f7f7
+f70000f7f7f7f7d85f9df7f7f7f7e9640800000660e6f7f7f7f7845bd7f7
+f7f7f70000f7f7f7f7d85f9df7f7f7f7f3d0b7b5b5b7cff3f7f7f7f7845b
+d7f7f7f7f70000f7f7f7f75f4650e1f7f7f7f7f7ecc3c2eaf7f7f7f7f7ca
+78486cf7f7f7f70000f7f7f7f75f4650e1f7f7f7f7f7ebc1c0eaf7f7f7f7
+f7ca78486cf7f7f7f70000f7f7f7f75f4650e1f7f7f7f7f7f4e9e8f3f7f7
+f7f7f7ca78486cf7f7f7f70000f7f7f7f7dd534961f7f7f7f7f7f7f7f7f7
+f7f7f7f7f6504671ebf7f7f7f70000f7f7f7f7dd534961f7f7f7f7f7f7f7
+f7f7f7f7f7f7f6504671ebf7f7f7f70000f7f7f7f7dd534961f7f7f7f7f7
+f7f7f7f7f7f7f7f7f6504671ebf7f7f7f70000f7f7f7f7f79659d1f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7d359bff7f7f7f7f70000f7f7f7f7f79659d1f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7d359bff7f7f7f7f70000f7f7f7f7f79659
+d1f7f7f7f7f7f7f7f7f7f7f7f7f7f7d359bff7f7f7f7f70000f7f7f7f7f7
+f6eff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f5f7f7f7f7f7f70000f7f7f7
+f7f7f6eff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f5f7f7f7f7f7f70000f7
+f7f7f7f7f6eff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f5f7f7f7f7f7f700
+00f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f700000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/south-korea.gif b/Docs/Flags/south-korea.gif
index 0d8630ba963..f9a74adc732 100644
--- a/Docs/Flags/south-korea.gif
+++ b/Docs/Flags/south-korea.gif
Binary files differ
diff --git a/Docs/Flags/south-korea.pdf b/Docs/Flags/south-korea.pdf
new file mode 100644
index 00000000000..877d792caa8
--- /dev/null
+++ b/Docs/Flags/south-korea.pdf
Binary files differ
diff --git a/Docs/Flags/spain.eps b/Docs/Flags/spain.eps
index 340fe9c7671..bd318f2160a 100644
--- a/Docs/Flags/spain.eps
+++ b/Docs/Flags/spain.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: spain.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7
-040404040404040404040404040404040404040404040404040404040404
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-fdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfd
+00000000000000ffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffff0000fcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfc
+fcfcfcfcfcfcfcfcfc000000000000000000000000000000000000000000
+00000000000000000000000000ffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000000000000000000000000000
+00000000000000000000000000000000000000ffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000000000
+00000000000000000000000000000000000000000000000000ffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
000000000000000000000000000000000000000000000000000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000000000000000000000000000000000000000
+00000000000000ffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000000000000000000000000000000000
+00000000000000000000000000ffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000000000000000000000000000
+00000000000000000000000000000000000000ffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000000000
+00000000000000000000000000000000000000000000000000ffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
000000000000000000000000000000000000000000000000000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000000000000000000000000000000000000000
+00000000000000c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7
+c7c7c7c7c7c7c70000030303030303030303030303030303030303030303
+030303030303030303000000000000000000000000000000000000000000
+00000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+00000000000000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
000000000000000000000000000000000000000000000000000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
000000000000000000000000000000000000000000000000000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
000000000000000000000000000000000000000000000000000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000000000000000000000000000000000000000000000000000000000
-fcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfc
-f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3
-000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/spain.gif b/Docs/Flags/spain.gif
index 9d2e1be0fe7..f5ad336b00d 100644
--- a/Docs/Flags/spain.gif
+++ b/Docs/Flags/spain.gif
Binary files differ
diff --git a/Docs/Flags/spain.pdf b/Docs/Flags/spain.pdf
new file mode 100644
index 00000000000..2606d779597
--- /dev/null
+++ b/Docs/Flags/spain.pdf
Binary files differ
diff --git a/Docs/Flags/sweden.eps b/Docs/Flags/sweden.eps
index 47cd1fa3e9c..18a7c8765ba 100644
--- a/Docs/Flags/sweden.eps
+++ b/Docs/Flags/sweden.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: sweden.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-0808080808080810fffffff1080808080808080808080808080808080808
-0000000000000008fffffff0000000000000000000000000000000000000
-b5b5b5b5b5b5b5af0000000bb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-0808080808080810fffffff1080808080808080808080808080808080808
-0000000000000008fffffff0000000000000000000000000000000000000
-b5b5b5b5b5b5b5af0000000bb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-0808080808080810fffffff1080808080808080808080808080808080808
-0000000000000008fffffff0000000000000000000000000000000000000
-b5b5b5b5b5b5b5af0000000bb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-0808080808080810fffffff1080808080808080808080808080808080808
-0000000000000008fffffff0000000000000000000000000000000000000
-b5b5b5b5b5b5b5af0000000bb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-0808080808080810fffffff1080808080808080808080808080808080808
-0000000000000008fffffff0000000000000000000000000000000000000
-b5b5b5b5b5b5b5af0000000bb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-0808080808080810fffffff1080808080808080808080808080808080808
-0000000000000008fffffff0000000000000000000000000000000000000
-b5b5b5b5b5b5b5af0000000bb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-0808080808080810fffffff1080808080808080808080808080808080808
-0000000000000008fffffff0000000000000000000000000000000000000
-b5b5b5b5b5b5b5af0000000bb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-0e0e0e0e0e0e0e16fffffff10e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e
-060606060606060efffffff0060606060606060606060606060606060606
-b1b1b1b1b1b1b1ab0000000ab1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1
-fefefefefefefefefffffffffefefefefefefefefefefefefefefefefefe
-fefefefefefefefefffffffffefefefefefefefefefefefefefefefefefe
-010101010101010100000000010101010101010101010101010101010101
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
000000000000000000000000000000000000000000000000000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
000000000000000000000000000000000000000000000000000000000000
-f3f3f3f3f3f3f3f3fffffffef3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3
-f3f3f3f3f3f3f3f3fffffffef3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3
-080808080808080800000000080808080808080808080808080808080808
-0808080808080810fffffff1080808080808080808080808080808080808
-0000000000000008fffffff0000000000000000000000000000000000000
-b5b5b5b5b5b5b5af0000000bb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-0808080808080810fffffff1080808080808080808080808080808080808
-0000000000000008fffffff0000000000000000000000000000000000000
-b5b5b5b5b5b5b5af0000000bb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-0808080808080810fffffff1080808080808080808080808080808080808
-0000000000000008fffffff0000000000000000000000000000000000000
-b5b5b5b5b5b5b5af0000000bb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-0808080808080810fffffff1080808080808080808080808080808080808
-0000000000000008fffffff0000000000000000000000000000000000000
-b5b5b5b5b5b5b5af0000000bb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-0808080808080810fffffff1080808080808080808080808080808080808
-0000000000000008fffffff0000000000000000000000000000000000000
-b5b5b5b5b5b5b5af0000000bb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-0808080808080810fffffff1080808080808080808080808080808080808
-0000000000000008fffffff0000000000000000000000000000000000000
-b5b5b5b5b5b5b5af0000000bb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-0808080808080810fffffff1080808080808080808080808080808080808
-0000000000000008fffffff0000000000000000000000000000000000000
-b5b5b5b5b5b5b5af0000000bb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-0808080808080810fffffff1080808080808080808080808080808080808
-0000000000000008fffffff0000000000000000000000000000000000000
-b5b5b5b5b5b5b5af0000000bb5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+000000000000000000000000000000000000000000000000000000000000
+000000000000000808080808080808fffffffc0808080808080808080808
+0808080808080800000000000000000000fffffffc000000000000000000
+0000000000000000000000b5b5b5b5b5b5b5b500000002b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b500000808080808080808fffffffc0808080808
+0808080808080808080808080800000000000000000000fffffffc000000
+0000000000000000000000000000000000b5b5b5b5b5b5b5b500000002b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500000808080808080808ffffff
+fc08080808080808080808080808080808080800000000000000000000ff
+fffffc0000000000000000000000000000000000000000b5b5b5b5b5b5b5
+b500000002b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500000808080808
+080808fffffffc0808080808080808080808080808080808080000000000
+0000000000fffffffc0000000000000000000000000000000000000000b5
+b5b5b5b5b5b5b500000002b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500
+000808080808080808fffffffc0808080808080808080808080808080808
+0800000000000000000000fffffffc000000000000000000000000000000
+0000000000b5b5b5b5b5b5b5b500000002b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b500000808080808080808fffffffc0808080808080808080808
+0808080808080800000000000000000000fffffffc000000000000000000
+0000000000000000000000b5b5b5b5b5b5b5b500000002b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b500000808080808080808fffffffc0808080808
+0808080808080808080808080800000000000000000000fffffffc000000
+0000000000000000000000000000000000b5b5b5b5b5b5b5b500000002b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500000808080808080808ffffff
+fc08080808080808080808080808080808080800000000000000000000ff
+fffffc0000000000000000000000000000000000000000b5b5b5b5b5b5b5
+b500000002b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b50000fcfcfcfcfc
+fcfcfcfffffffffcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfc0000fcfcfc
+fcfcfcfcfcfffffffffcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfc000002
+020202020202020000000002020202020202020202020202020202020200
+00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000000000000000000000000000000000000000
+00000000000000ffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000000000000000000000000000000000
+00000000000000000000000000ffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000000000000000000000000000
+000000000000000000000000000000000000000808080808080808ffffff
+fc08080808080808080808080808080808080800000000000000000000ff
+fffffc0000000000000000000000000000000000000000b5b5b5b5b5b5b5
+b500000002b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500000808080808
+080808fffffffc0808080808080808080808080808080808080000000000
+0000000000fffffffc0000000000000000000000000000000000000000b5
+b5b5b5b5b5b5b500000002b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500
+000808080808080808fffffffc0808080808080808080808080808080808
+0800000000000000000000fffffffc000000000000000000000000000000
+0000000000b5b5b5b5b5b5b5b500000002b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b500000808080808080808fffffffc0808080808080808080808
+0808080808080800000000000000000000fffffffc000000000000000000
+0000000000000000000000b5b5b5b5b5b5b5b500000002b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b500000808080808080808fffffffc0808080808
+0808080808080808080808080800000000000000000000fffffffc000000
+0000000000000000000000000000000000b5b5b5b5b5b5b5b500000002b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500000808080808080808ffffff
+fc08080808080808080808080808080808080800000000000000000000ff
+fffffc0000000000000000000000000000000000000000b5b5b5b5b5b5b5
+b500000002b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500000808080808
+080808fffffffc0808080808080808080808080808080808080000000000
+0000000000fffffffc0000000000000000000000000000000000000000b5
+b5b5b5b5b5b5b500000002b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500
+000808080808080808fffffffc0808080808080808080808080808080808
+0800000000000000000000fffffffc000000000000000000000000000000
+0000000000b5b5b5b5b5b5b5b500000002b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b500000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/sweden.gif b/Docs/Flags/sweden.gif
index e16ede8e641..df7151b5aa8 100644
--- a/Docs/Flags/sweden.gif
+++ b/Docs/Flags/sweden.gif
Binary files differ
diff --git a/Docs/Flags/sweden.pdf b/Docs/Flags/sweden.pdf
new file mode 100644
index 00000000000..718d57600fd
--- /dev/null
+++ b/Docs/Flags/sweden.pdf
Binary files differ
diff --git a/Docs/Flags/switzerland.eps b/Docs/Flags/switzerland.eps
index 517919e3125..635eef9f80a 100644
--- a/Docs/Flags/switzerland.eps
+++ b/Docs/Flags/switzerland.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: switzerland.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c7c7c7c7c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000404040400000000000000000000000000
-000000000000000000000000000404040400000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c9f7f7f7f4c6c6c6c6c6c6c6c6c6c6c6c6c6
-0000000000000000000000000ff7f7f7e700000000000000000000000000
-00000000000000000000000010f7f7f7e700000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c9f7f7f7f4c6c6c6c6c6c6c6c6c6c6c6c6c6
-0000000000000000000000000ff7f7f7e700000000000000000000000000
-00000000000000000000000010f7f7f7e700000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c9f7f7f7f4c6c6c6c6c6c6c6c6c6c6c6c6c6
-0000000000000000000000000ff7f7f7e700000000000000000000000000
-00000000000000000000000010f7f7f7e700000000000000000000000000
-c6c6c6c6c6c6c6c6c6c8c8c8cbf7f7f7f4c8c8c8c8c6c6c6c6c6c6c6c6c6
-00000000000000000008080817f7f7f7e708080807000000000000000000
-00000000000000000008080817f7f7f7e708080807000000000000000000
-c6c6c6c6c6c6c6c6c9f7f7f7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6
-00000000000000000cf7f7f7f7f7f7f7f7f7f7f7e3000000000000000000
-00000000000000000cf7f7f7f7f7f7f7f7f7f7f7e3000000000000000000
-c6c6c6c6c6c6c6c6c9f7f7f7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6
-00000000000000000cf7f7f7f7f7f7f7f7f7f7f7e3000000000000000000
-00000000000000000cf7f7f7f7f7f7f7f7f7f7f7e3000000000000000000
-c6c6c6c6c6c6c6c6c9f7f7f7f7f7f7f7f7f7f7f7f3c6c6c6c6c6c6c6c6c6
-00000000000000000cf7f7f7f7f7f7f7f7f7f7f7e3000000000000000000
-00000000000000000cf7f7f7f7f7f7f7f7f7f7f7e3000000000000000000
-c6c6c6c6c6c6c6c6c8f5f5f5f5f7f7f7f7f5f5f5f1c6c6c6c6c6c6c6c6c6
-00000000000000000beeeeeeeff7f7f7f6eeeeeeda000000000000000000
-00000000000000000cefefefeff7f7f7f6efefefdb000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c9f7f7f7f4c6c6c6c6c6c6c6c6c6c6c6c6c6
-0000000000000000000000000ff7f7f7e700000000000000000000000000
-00000000000000000000000010f7f7f7e700000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c9f7f7f7f4c6c6c6c6c6c6c6c6c6c6c6c6c6
-0000000000000000000000000ff7f7f7e700000000000000000000000000
-00000000000000000000000010f7f7f7e700000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c9f7f7f7f4c6c6c6c6c6c6c6c6c6c6c6c6c6
-0000000000000000000000000ff7f7f7e700000000000000000000000000
-00000000000000000000000010f7f7f7e700000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c9f5f5f5f2c6c6c6c6c6c6c6c6c6c6c6c6c6
-0000000000000000000000000feaeaeada00000000000000000000000000
-0000000000000000000000000febebebdb00000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00c6c6c6c6c6c6c6c6c6c6c6c6c7f7f7f7f7c6c6c6c6c6c6c6c6c6c6c6c6
+c6000000000000000000000000000003f7f7f7f700000000000000000000
+000000000000000000000000000000000003f7f7f7f70000000000000000
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c7f7f7f7f7c6c6c6c6c6c6
+c6c6c6c6c6c6c6000000000000000000000000000003f7f7f7f700000000
+000000000000000000000000000000000000000000000003f7f7f7f70000
+00000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6c6c7f7f7f7f7
+c6c6c6c6c6c6c6c6c6c6c6c6c6000000000000000000000000000003f7f7
+f7f700000000000000000000000000000000000000000000000000000003
+f7f7f7f7000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c7f7f7f7f7c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
+00000003f7f7f7f700000000000000000000000000000000000000000000
+000000000003f7f7f7f7000000000000000000000000000000c6c6c6c6c6
+c6c6c6c7f7f7f7f7f7f7f7f7f7f7f7f7c6c6c6c6c6c6c6c6c60000000000
+000000000003f7f7f7f7f7f7f7f7f7f7f7f7000000000000000000000000
+0000000000000003f7f7f7f7f7f7f7f7f7f7f7f700000000000000000000
+00c6c6c6c6c6c6c6c6c7f7f7f7f7f7f7f7f7f7f7f7f7c6c6c6c6c6c6c6c6
+c60000000000000000000003f7f7f7f7f7f7f7f7f7f7f7f7000000000000
+0000000000000000000000000003f7f7f7f7f7f7f7f7f7f7f7f700000000
+00000000000000c6c6c6c6c6c6c6c6c7f7f7f7f7f7f7f7f7f7f7f7f7c6c6
+c6c6c6c6c6c6c60000000000000000000003f7f7f7f7f7f7f7f7f7f7f7f7
+0000000000000000000000000000000000000003f7f7f7f7f7f7f7f7f7f7
+f7f70000000000000000000000c6c6c6c6c6c6c6c6c7f7f7f7f7f7f7f7f7
+f7f7f7f7c6c6c6c6c6c6c6c6c60000000000000000000003f7f7f7f7f7f7
+f7f7f7f7f7f70000000000000000000000000000000000000003f7f7f7f7
+f7f7f7f7f7f7f7f70000000000000000000000c6c6c6c6c6c6c6c6c6c7c7
+c7c8f7f7f7f7c7c7c7c7c6c6c6c6c6c6c6c6c60000000000000000000000
+03030306f7f7f7f703030303000000000000000000000000000000000000
+000003030306f7f7f7f7030303030000000000000000000000c6c6c6c6c6
+c6c6c6c6c6c6c6c7f7f7f7f7c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
+00000000000000000003f7f7f7f700000000000000000000000000000000
+000000000000000000000003f7f7f7f70000000000000000000000000000
+00c6c6c6c6c6c6c6c6c6c6c6c6c7f7f7f7f7c6c6c6c6c6c6c6c6c6c6c6c6
+c6000000000000000000000000000003f7f7f7f700000000000000000000
+000000000000000000000000000000000003f7f7f7f70000000000000000
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c7f7f7f7f7c6c6c6c6c6c6
+c6c6c6c6c6c6c6000000000000000000000000000003f7f7f7f700000000
+000000000000000000000000000000000000000000000003f7f7f7f70000
+00000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c7c7c7c7
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000303
+030300000000000000000000000000000000000000000000000000000000
+03030303000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/switzerland.gif b/Docs/Flags/switzerland.gif
index 98cef7c28d6..8212d226678 100644
--- a/Docs/Flags/switzerland.gif
+++ b/Docs/Flags/switzerland.gif
Binary files differ
diff --git a/Docs/Flags/switzerland.pdf b/Docs/Flags/switzerland.pdf
new file mode 100644
index 00000000000..26935b96dfc
--- /dev/null
+++ b/Docs/Flags/switzerland.pdf
Binary files differ
diff --git a/Docs/Flags/taiwan.eps b/Docs/Flags/taiwan.eps
index a514bdf2af4..a57a8242464 100644
--- a/Docs/Flags/taiwan.eps
+++ b/Docs/Flags/taiwan.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: taiwan.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-080808080808081108080808080813c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000900000000000000000000000000000000000000000000
-b5b5b5b5b5b5b5b7b5b5b5b5b5b5aa000000000000000000000000000000
-0808080808490e9e11450808080813c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000043069a0a3f0000000000000000000000000000000000000000
-b5b5b5b5b5c7b7deb8c6b5b5b5b5aa000000000000000000000000000000
-0808080e14658bb28d59170c080813c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000060c6087b089530f04000000000000000000000000000000000000
-b5b5b5b7b8cfd9e4dacbb9b6b5b5aa000000000000000000000000000000
-0808080baba1f7f7f7a0a009080813c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-00000003a89ef7f7f79d9c00000000000000000000000000000000000000
-b5b5b5b6e2dff7f7f7dfdfb5b5b5aa000000000000000000000000000000
-0808082b5becf7f7f7e06025080813c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-0000002456ecf7f7f7df5b1e000000000000000000000000000000000000
-b5b5b5bfccf4f7f7f7f1cdbdb5b5aa000000000000000000000000000000
-0808082556eaf7f7f7de5a20080813c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-0000001e50eaf7f7f7dd5418000000000000000000000000000000000000
-b5b5b5bdcaf3f7f7f7f0ccbcb5b5aa000000000000000000000000000000
-0808080bb099f7f7f799a509080813c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-00000004ad96f7f7f795a201000000000000000000000000000000000000
-b5b5b5b6e3ddf7f7f7dde0b5b5b5aa000000000000000000000000000000
-0808080d0e6b82b2855f100b080813c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-0000000507667eb081590903000000000000000000000000000000000000
-b5b5b5b6b7d0d7e4d7cdb7b6b5b5aa000000000000000000000000000000
-0808080808440c970f410808080813c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-00000000003e0493073b0000000000000000000000000000000000000000
-b5b5b5b5b5c6b6dcb7c5b5b5b5b5aa000000000000000000000000000000
-0e0e0e0e0e0e0e150e0e0e0e0e0e19c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000700000000000000000000000000000000000000000000
-b0b0b0b0b0b0b0b2b0b0b0b0b0b0a6000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
-010101010101010101010101010101000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000080808080808081108080808080808c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000900000000000000000000000000
+0000000000000000000000b5b5b5b5b5b5b5b7b5b5b5b5b5b5b500000000
+000000000000000000000000000808080808470e9e0f470808080808c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000041069a07410000000000
+0000000000000000000000000000000000b5b5b5b5b5c6b7deb7c6b5b5b5
+b5b500000000000000000000000000000000000808080d126289b28b6013
+0d080808c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000060a5d85b087
+5b0b050000000000000000000000000000000000000000b5b5b5b6b8ced8
+e4d9cdb8b6b5b5b500000000000000000000000000000000000808080aac
+9df7f7f7a0aa0a080808c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
+02a99af7f7f79ca7020000000000000000000000000000000000000000b5
+b5b5b6e2def7f7f7dfe2b6b5b5b500000000000000000000000000000000
+000808082759e8f7f7f7e85b25080808c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c600000000002053e8f7f7f7e8551e000000000000000000000000000000
+0000000000b5b5b5bdcbf3f7f7f7f3ccbdb5b5b500000000000000000000
+000000000000000808082858e8f7f7f7e85a26080808c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c600000000002052e8f7f7f7e8551f000000000000000000
+0000000000000000000000b5b5b5becbf3f7f7f7f3ccbdb5b5b500000000
+000000000000000000000000000808080aac9cf7f7f79faa09080808c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6000000000002a999f7f7f79ca701000000
+0000000000000000000000000000000000b5b5b5b5e2def7f7f7dfe2b5b5
+b5b500000000000000000000000000000000000808080e136487b2896113
+0d080808c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000060b5e83b085
+5c0c050000000000000000000000000000000000000000b5b5b5b7b8ced8
+e4d8ceb8b6b5b5b500000000000000000000000000000000000808080808
+480e9e0f480808080808c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
+000042069b074200000000000000000000000000000000000000000000b5
+b5b5b5b5c7b7deb7c7b5b5b5b5b500000000000000000000000000000000
+00080808080808081108080808080808c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000900000000000000000000000000000000000000
+0000000000b5b5b5b5b5b5b5b7b5b5b5b5b5b5b500000000000000000000
+00000000000000c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
+000000000000000000000002020202020202020202020202020200000000
+00000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00000000000000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/taiwan.gif b/Docs/Flags/taiwan.gif
index 5cfc3d46425..379afea61ce 100644
--- a/Docs/Flags/taiwan.gif
+++ b/Docs/Flags/taiwan.gif
Binary files differ
diff --git a/Docs/Flags/taiwan.pdf b/Docs/Flags/taiwan.pdf
new file mode 100644
index 00000000000..013b5c16d9a
--- /dev/null
+++ b/Docs/Flags/taiwan.pdf
Binary files differ
diff --git a/Docs/Flags/turkey.eps b/Docs/Flags/turkey.eps
new file mode 100644
index 00000000000..7df5bfe70dc
--- /dev/null
+++ b/Docs/Flags/turkey.eps
@@ -0,0 +1,98 @@
+%!PS-Adobe-2.0 EPSF-2.0
+%%Creator: pnmtops
+%%Title: turkey.ps
+%%Pages: 1
+%%BoundingBox: 290 385 321 407
+%%EndComments
+/readstring {
+ currentfile exch readhexstring pop
+} bind def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
+%%EndProlog
+%%Page: 1 1
+gsave
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
+{ rpicstr readstring }
+{ gpicstr readstring }
+{ bpicstr readstring }
+true 3
+colorimage
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00c6c6c6c6c6c6c6c6c8d9e4d9c9c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c600000000000000000000095f97610d0000000000000000000000000000
+00000000000000000000000000095f97610d000000000000000000000000
+00000000000000c6c6c6c6c6c6c6d1f1e4cac6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c600000000000000000039da951600000000000000000000
+00000000000000000000000000000000000039da96160000000000000000
+00000000000000000000000000c6c6c6c6c6c6d0f5dec6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6000000000000000033ed78000000000000
+000000000000000000000000000000000000000000000033ee7800000000
+00000000000000000000000000000000000000c6c6c6c6c6c6efeec6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000002ccca02
+0000000000000000000000000000000000000000000000000000000002cc
+ca020000000000000000000000000000000000000000000000c6c6c6c6c6
+d2f7ddc6c6c6c6c6c6d6c8cbc6c6c6c6c6c6c6c6c6c6c6c6c60000000000
+00003af77300000000000051091800000000000000000000000000000000
+000000003af7730000000000005209180000000000000000000000000000
+00c6c6c6c6c6dbf7d5c6c6c6c6c6cbe8f4d4c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000068f74c00000000001babe54600000000000000000000
+0000000000000000000069f74d00000000001babe5460000000000000000
+00000000000000c6c6c6c6c6dbf7d5c6c6c6c6c6cee7f1d9c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000068f74c000000000028a5d85f00000000
+0000000000000000000000000000000069f74d000000000028a5d8600000
+00000000000000000000000000c6c6c6c6c6d2f7ddc6c6c6c6c6c6d5c9c7
+c6c6c6c6c6c6c6c6c6c6c6c6c6000000000000003af77200000000000048
+0d0700000000000000000000000000000000000000003af7730000000000
+00490d07000000000000000000000000000000c6c6c6c6c6c6efeec6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000002ccca02
+0000000000000000000000000000000000000000000000000000000002cc
+ca020000000000000000000000000000000000000000000000c6c6c6c6c6
+c6d0f5dec6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
+00000033ed78000000000000000000000000000000000000000000000000
+000000000033ee7800000000000000000000000000000000000000000000
+00c6c6c6c6c6c6c6d1f1e4cac6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c600000000000000000039da951600000000000000000000000000000000
+00000000000000000000000039da96160000000000000000000000000000
+00000000000000c6c6c6c6c6c6c6c6c8d9e4d9c9c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c600000000000000000000095f97610d0000000000000000
+00000000000000000000000000000000000000095f97610d000000000000
+00000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/turkey.gif b/Docs/Flags/turkey.gif
new file mode 100644
index 00000000000..45064417a3f
--- /dev/null
+++ b/Docs/Flags/turkey.gif
Binary files differ
diff --git a/Docs/Flags/turkey.pdf b/Docs/Flags/turkey.pdf
new file mode 100644
index 00000000000..899624408a8
--- /dev/null
+++ b/Docs/Flags/turkey.pdf
Binary files differ
diff --git a/Docs/Flags/south-africa1.txt b/Docs/Flags/turkey.txt
index e69de29bb2d..e69de29bb2d 100644
--- a/Docs/Flags/south-africa1.txt
+++ b/Docs/Flags/turkey.txt
diff --git a/Docs/Flags/ukraine.eps b/Docs/Flags/ukraine.eps
index fe2436fa554..1cf43b4b53c 100644
--- a/Docs/Flags/ukraine.eps
+++ b/Docs/Flags/ukraine.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: ukraine.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-181818181818181818181818181818181818181818181818181818181818
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
-181818181818181818181818181818181818181818181818181818181818
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
-181818181818181818181818181818181818181818181818181818181818
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
-181818181818181818181818181818181818181818181818181818181818
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
-181818181818181818181818181818181818181818181818181818181818
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
-181818181818181818181818181818181818181818181818181818181818
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
-181818181818181818181818181818181818181818181818181818181818
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
-181818181818181818181818181818181818181818181818181818181818
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
-181818181818181818181818181818181818181818181818181818181818
-b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
-efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
-1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f
-b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7
-e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8
-fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-010101010101010101010101010101010101010101010101010101010101
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
000000000000000000000000000000000000000000000000000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
000000000000000000000000000000000000000000000000000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
000000000000000000000000000000000000000000000000000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000000000001818181818181818181818181818181818181818181818
+181818181818180000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b50000efefefefefefefefefefefefefefefefefefef
+efefefefefefefefefefef00001818181818181818181818181818181818
+181818181818181818181818180000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b50000efefefefefefefefefefefefef
+efefefefefefefefefefefefefefefefef00001818181818181818181818
+181818181818181818181818181818181818180000b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b50000efefefefefefef
+efefefefefefefefefefefefefefefefefefefefefefef00001818181818
+181818181818181818181818181818181818181818181818180000b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b50000ef
+efefefefefefefefefefefefefefefefefefefefefefefefefefefefef00
+001818181818181818181818181818181818181818181818181818181818
+180000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b50000efefefefefefefefefefefefefefefefefefefefefefefefef
+efefefefef00001818181818181818181818181818181818181818181818
+181818181818180000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b50000efefefefefefefefefefefefefefefefefefef
+efefefefefefefefefefef00001818181818181818181818181818181818
+181818181818181818181818180000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b50000efefefefefefefefefefefefef
+efefefefefefefefefefefefefefefefef00001818181818181818181818
+181818181818181818181818181818181818180000b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b50000efefefefefefef
+efefefefefefefefefefefefefefefefefefefefefefef00001818181818
+181818181818181818181818181818181818181818181818180000b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b50000ef
+efefefefefefefefefefefefefefefefefefefefefefefefefefefefef00
+001818181818181818181818181818181818181818181818181818181818
+180000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b50000efefefefefefefefefefefefefefefefefefefefefefefefef
+efefefefef0000fcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfc
+fcfcfcfcfcfcfc0000fefefefefefefefefefefefefefefefefefefefefe
+fefefefefefefefefe000003030303030303030303030303030303030303
+03030303030303030303030000ffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000000000000000000000000000
+00000000000000000000000000000000000000ffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000000000
+00000000000000000000000000000000000000000000000000ffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
000000000000000000000000000000000000000000000000000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000000000000000000000000000000000000000
+00000000000000ffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000000000000000000000000000000000
+00000000000000000000000000ffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000000000000000000000000000
+00000000000000000000000000000000000000ffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000000000
+00000000000000000000000000000000000000000000000000ffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
000000000000000000000000000000000000000000000000000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
000000000000000000000000000000000000000000000000000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000000000000000000000000000000000000000000000000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/ukraine.gif b/Docs/Flags/ukraine.gif
index b951bef5b2a..77deda40904 100644
--- a/Docs/Flags/ukraine.gif
+++ b/Docs/Flags/ukraine.gif
Binary files differ
diff --git a/Docs/Flags/ukraine.pdf b/Docs/Flags/ukraine.pdf
new file mode 100644
index 00000000000..9731eb218ba
--- /dev/null
+++ b/Docs/Flags/ukraine.pdf
Binary files differ
diff --git a/Docs/Flags/usa.eps b/Docs/Flags/usa.eps
index 31bd9996d11..08d78b8d8e6 100644
--- a/Docs/Flags/usa.eps
+++ b/Docs/Flags/usa.eps
@@ -1,87 +1,98 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Creator: pnmtops
-%%Title: noname.ps
+%%Title: usa.ps
%%Pages: 1
-%%BoundingBox: 291 371 320 391
+%%BoundingBox: 290 385 321 407
%%EndComments
/readstring {
currentfile exch readhexstring pop
} bind def
-/rpicstr 30 string def
-/gpicstr 30 string def
-/bpicstr 30 string def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
%%EndProlog
%%Page: 1 1
gsave
-291.6 371.4 translate
-28.8 19.2 scale
-30 20 8
-[ 30 0 0 -20 0 20 ]
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
{ rpicstr readstring }
{ gpicstr readstring }
{ bpicstr readstring }
true 3
colorimage
-182608340a122c08300e0e31082b1ec6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
-111f002d020a25002907062a00240b000000000000000000000000000000
-b9bdb5c1b6b8bfb5c0b7b7c0b5bfad000000000000000000000000000000
-1a2422331d182b243117183223291fdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc
-121d1a2c1610241c2a0f112b1c2211717171717171717171717171717171
-babdbcc1bbb9bfbdc0b9b9c0bdbeb4717171717171717171717171717171
-0a134413301e134513262813451316f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-020b3e0c29170b3f0c1f210c3f0c0ff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-b5b8c5b8c0bbb8c6b8bdbeb8c6b8b9f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-28360e54101b430e4e1212500e4029c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9
-212f064e08133d06480b0a49063a17101010101010101010101010101010
-bec2b7cab7bac5b7c8b8b8c9b7c5b1101010101010101010101010101010
-080e580a3f250b5b0a30340a5b0c14d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9
-00065302391e035603292d02550406616161616161616161616161616161
-b5b7cbb6c4bdb6ccb6c0c1b6ccb6b0616161616161616161616161616161
-2a3d085c0b1b4c0856110f5808492cf7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-233700570313460051090753004325f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-bec4b5ccb6bac8b5cab7b7cbb5c7bff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-080c5d084425096008323708600913cccccccccccccccccccccccccccccc
-000458003e1e015b002b30005a01021f1f1f1f1f1f1f1f1f1f1f1f1f1f1f
-b5b6cdb5c5bdb5cdb5c1c2b5cdb5ac1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f
-293f085e0a1a4e0858100e5a084b29d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6
-22390059021348005308065500451b525252525252525252525252525252
-bec4b5cdb6bac8b5cbb7b7ccb5c7b5525252525252525252525252525252
-080c58094222095b083034085a0a16f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-000452013b1b015500292e0055020ff7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-b5b6cbb5c5bcb5ccb5c0c1b5ccb5b9f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-23370e500d19440e4b12114c0e4224cfcfcfcfcfcfcfcfcfcfcfcfcfcfcf
-1b31064a05113e06450a0946063c132f2f2f2f2f2f2f2f2f2f2f2f2f2f2f
-bcc2b7c9b6bac5b7c7b8b8c8b7c5b22f2f2f2f2f2f2f2f2f2f2f2f2f2f2f
-4f504857484d524856494956485155d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3
-494a425142474d4250434351424c47424242424242424242424242424242
-c9c9c7cbc7c8cac7cbc7c7cbc7c9c1424242424242424242424242424242
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2
-3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e
-3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e
-d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0
-323232323232323232323232323232323232323232323232323232323232
-323232323232323232323232323232323232323232323232323232323232
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5
-4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e
-4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e
-cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd
-232323232323232323232323232323232323232323232323232323232323
-232323232323232323232323232323232323232323232323232323232323
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
-d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9
-5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d
-5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d
-c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000182608330b112d082e100c32082915c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000101f002d030926002708042b00220e000000000000
+0000000000000000000000b9bdb5c1b6b8bfb5c0b7b6c1b5beb900000000
+000000000000000000000000001a2421341c162d2330151a34212617dcdc
+dcdcdcdcdcdcdcdcdcdcdcdcdc0000121d192d140e261b290d132d1a1f10
+6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f0000babdbcc1bab9bfbcc0b8bac1bc
+bdb96f6f6f6f6f6f6f6f6f6f6f6f6f6f6f0000091246122f21124712232c
+12471308f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000010a400a28190a410a
+1c260a410b00f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000b5b8c6b8c0bcb8
+c6b8bcbfb8c6b8b5f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7000028370d5510
+18480d4c1411540d3b24cacacacacacacacacacacacacacaca0000213105
+4f08104105460d094e05351d1313131313131313131313131313130000be
+c2b6cab7b9c7b6c8b8b7cab6c3bd13131313131313131313131313131300
+00080d5a0a3e280a5d0a2b3a0a5b0c08d8d8d8d8d8d8d8d8d8d8d8d8d8d8
+d800000005540237210257022433025505005d5d5d5d5d5d5d5d5d5d5d5d
+5d5d5d0000b5b6ccb5c4beb6ccb5bfc3b5ccb6b55d5d5d5d5d5d5d5d5d5d
+5d5d5d5d5d0000293f085d0b18500854140c5c084325f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f700002238005703104a004e0c0456003d1df7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000bec4b5ccb6b9c9b5cab8b6ccb5c5bdf7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f70000080b5f0842280862082c3e08600b08cdcd
+cdcdcdcdcdcdcdcdcdcdcdcdcd0000000359003c21005c002538005a0300
+2525252525252525252525252525250000b5b6cdb5c5beb5ceb5bfc4b5cd
+b6b525252525252525252525252525252500002940085d0b17510855130c
+5c084424d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5000021390058030f4b004f
+0b0457003e1d4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a0000bec4b5ccb6b9c9
+b5cab8b6ccb5c6bd4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a0000090c560a3e
+24095909283a0a570b09f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000010450
+02381d015401213402510301f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000b5
+b6cbb5c4bdb5cbb5bec3b5cbb6b5f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700
+002035114b0f1842114515114a11391cd1d1d1d1d1d1d1d1d1d1d1d1d1d1
+d10000192f094507103c093f0e0944093315383838383838383838383838
+3838380000bcc2b7c7b7b9c5b7c6b9b7c7b7c3bb38383838383838383838
+3838383838000047493e523e424d3e4f413e523e4a46d1d1d1d1d1d1d1d1
+d1d1d1d1d1d1d100004143384c383d4738493b384c384440383838383838
+3838383838383838380000c6c7c4c9c4c5c8c4c8c5c4c9c4c7c638383838
+38383838383838383838380000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000d5d5d5d5d5d5d5d5d5d5d5
+d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d500004a4a4a4a4a4a4a4a4a
+4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a00004a4a4a4a4a4a4a
+4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a0000cdcdcdcdcd
+cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd0000252525
+252525252525252525252525252525252525252525252525252525000025
+252525252525252525252525252525252525252525252525252525252500
+00f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f70000d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8
+d8d8d8d8d8d8d800005d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d
+5d5d5d5d5d5d5d5d5d00005d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d
+5d5d5d5d5d5d5d5d5d5d5d0000cacacacacacacacacacacacacacacacaca
+cacacacacacacacacacacacaca0000121212121212121212121212121212
+121212121212121212121212121212000012121212121212121212121212
+12121212121212121212121212121212120000f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000dcdcdcdcdc
+dcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc00006f6f6f
+6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f00006f
+6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f00
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
grestore
showpage
%%Trailer
diff --git a/Docs/Flags/usa.gif b/Docs/Flags/usa.gif
index da9f4e27d6c..4d9c261808d 100644
--- a/Docs/Flags/usa.gif
+++ b/Docs/Flags/usa.gif
Binary files differ
diff --git a/Docs/Flags/usa.pdf b/Docs/Flags/usa.pdf
new file mode 100644
index 00000000000..f8bd86fdd1a
--- /dev/null
+++ b/Docs/Flags/usa.pdf
Binary files differ
diff --git a/Docs/Flags/yugoslavia.eps b/Docs/Flags/yugoslavia.eps
index e69de29bb2d..221d510451d 100644
--- a/Docs/Flags/yugoslavia.eps
+++ b/Docs/Flags/yugoslavia.eps
@@ -0,0 +1,98 @@
+%!PS-Adobe-2.0 EPSF-2.0
+%%Creator: pnmtops
+%%Title: yugoslavia.ps
+%%Pages: 1
+%%BoundingBox: 290 385 321 407
+%%EndComments
+/readstring {
+ currentfile exch readhexstring pop
+} bind def
+/rpicstr 32 string def
+/gpicstr 32 string def
+/bpicstr 32 string def
+%%EndProlog
+%%Page: 1 1
+gsave
+290.64 385.44 translate
+30.72 21.12 scale
+32 22 8
+[ 32 0 0 -22 0 22 ]
+{ rpicstr readstring }
+{ gpicstr readstring }
+{ bpicstr readstring }
+true 3
+colorimage
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000808080808080808080808080808080808080808080808
+080808080808080000000000000000000000000000000000000000000000
+0000000000000000000000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b500000808080808080808080808080808080808
+080808080808080808080808080000000000000000000000000000000000
+0000000000000000000000000000000000b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500000808080808080808080808
+080808080808080808080808080808080808080000000000000000000000
+0000000000000000000000000000000000000000000000b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500000808080808
+080808080808080808080808080808080808080808080808080000000000
+0000000000000000000000000000000000000000000000000000000000b5
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b500
+000808080808080808080808080808080808080808080808080808080808
+080000000000000000000000000000000000000000000000000000000000
+0000000000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b500000808080808080808080808080808080808080808080808
+080808080808080000000000000000000000000000000000000000000000
+0000000000000000000000b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+b5b5b5b5b5b5b5b5b5b5b500005555555555555555555555555555555555
+555555555555555555555555550000505050505050505050505050505050
+5050505050505050505050505050500000cacacacacacacacacacacacaca
+cacacacacacacacacacacacacacacacaca0000f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f700
+00f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f70000d7d7d7d7d7
+d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d70000535353
+535353535353535353535353535353535353535353535353535353000054
+545454545454545454545454545454545454545454545454545454545400
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c60000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000c6c6c6c6c6c6c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000c6c6c6c6c6
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c60000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+00c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+c60000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/yugoslavia.gif b/Docs/Flags/yugoslavia.gif
index 650eac242d6..e1dd52a0541 100644
--- a/Docs/Flags/yugoslavia.gif
+++ b/Docs/Flags/yugoslavia.gif
Binary files differ
diff --git a/Docs/Flags/yugoslavia.pdf b/Docs/Flags/yugoslavia.pdf
new file mode 100644
index 00000000000..1156cd257b8
--- /dev/null
+++ b/Docs/Flags/yugoslavia.pdf
Binary files differ
diff --git a/Docs/Makefile.am b/Docs/Makefile.am
index 17def904875..b9feeec04db 100644
--- a/Docs/Makefile.am
+++ b/Docs/Makefile.am
@@ -21,7 +21,8 @@ info_TEXINFOS = manual.texi
targets = manual.txt mysql.info manual.html
BUILT_SOURCES = $(targets) manual_toc.html include.texi
-EXTRA_DIST = $(noinst_SCRIPTS) $(BUILT_SOURCES) mysqld_error.txt INSTALL-BINARY
+EXTRA_DIST = $(noinst_SCRIPTS) $(BUILT_SOURCES) mysqld_error.txt \
+ INSTALL-BINARY mirrors.texi
all: $(targets) txt_files
@@ -47,72 +48,133 @@ include.texi: ../configure.in
grep "MYSQL_TCP_PORT_DEFAULT=" ../configure.in | \
sed -e 's;MYSQL_TCP_PORT_DEFAULT=;;' >> $@
+
+#
+# English Manual
+#
+
+# GNU Info
mysql.info: manual.texi include.texi
cd $(srcdir) && $(MAKEINFO) --no-split -I $(srcdir) $<
+# Plain Text
manual.txt: manual.texi include.texi
cd $(srcdir) && \
$(MAKEINFO) -I $(srcdir) --no-headers --no-split --output $@ $<
+# HTML, all in one file
manual.html: manual.texi include.texi $(srcdir)/Support/texi2html
cd $(srcdir) && @PERL@ $(srcdir)/Support/texi2html $(TEXI2HTML_FLAGS) $<
-
manual_toc.html: manual.html
-
-# Fix: add --output-comment with some interesting info?
-# Fix: @image worked with a older version of pdftex.
-# Note: @image will work if we first convert all images to pdf ...
-# is that worth it?
-# Comment: We need to run pdftex 2 times to get the cross references right.
+# PDF, Portable Document Format
manual.pdf: manual.texi
- cat manual.texi | sed -e 's|@image{[^}]*} *||g' > manual-tmp.texi
+ sed -e 's|@image{[^}]*} *||g' <$< >manual-tmp.texi
pdftex --interaction=nonstopmode manual-tmp.texi
texindex manual-tmp.??
pdftex --interaction=nonstopmode manual-tmp.texi
texindex manual-tmp.??
pdftex --interaction=nonstopmode manual-tmp.texi
- mv manual-tmp.pdf manual.pdf
+ mv manual-tmp.pdf $@
rm -f manual-tmp.*
touch $@
-# Target to produce NuSphere Manual
-nusphere.pdf: manual.texi
- cat manual.texi \
- | sed -e 's/@example/@smallexample/g' \
- -e 's/@end example/@end smallexample/g' \
- -e 's/@c ifnusphere //g' \
- -e 's|@image{[^}]*} *||g' \
- > manual-tmp.texi
+# XML, DocBook 4.0
+mysql.xml: manual.texi include.texi
+ $(MAKEINFO) --force --no-ifinfo --docbook $<
+ mv $@ mysql-tmp.xml
+ Support/docbook-fixup.pl <mysql-tmp.xml >$@
+ rm -f mysql-tmp.xml
+
+# Postscript, A4 Paper
+manual_a4.ps: manual.texi include.texi
+ TEXINPUTS=$(srcdir):$$TEXINPUTS \
+ MAKEINFO='$(MAKEINFO) -I $(srcdir)' \
+ $(TEXI2DVI) --batch --texinfo --quiet '@afourpaper' $<
+ $(DVIPS) -t a4 manual.dvi -o $@
+ touch $@
+
+# Postscript, US Letter Paper
+manual_letter.ps: manual.texi include.texi
+ TEXINPUTS=$(srcdir):$$TEXINPUTS \
+ MAKEINFO='$(MAKEINFO) -I $(srcdir)' \
+ $(TEXI2DVI) --batch $<
+ $(DVIPS) -t letter manual.dvi -o $@
+ touch $@
+
+
+#
+# German Manual
+#
+
+# GNU Info
+mysql.de.info: manual.de.texi include.texi
+ cd $(srcdir) && $(MAKEINFO) --no-split -I $(srcdir) $<
+
+# Plain Text
+manual.de.txt: manual.de.texi include.texi
+ cd $(srcdir) && \
+ $(MAKEINFO) -I $(srcdir) --no-headers --no-split --output $@ $<
+
+# HTML, all in one file
+manual.de.html: manual.de.texi include.texi $(srcdir)/Support/texi2html
+ cd $(srcdir) && @PERL@ $(srcdir)/Support/texi2html $(TEXI2HTML_FLAGS) $<
+manual_toc.de.html: manual.html
+
+# PDF, Portable Document Format
+manual.de.pdf: manual.de.texi
+ sed -e 's|@image{[^}]*} *||g' <$< >manual-tmp.texi
pdftex --interaction=nonstopmode manual-tmp.texi
texindex manual-tmp.??
pdftex --interaction=nonstopmode manual-tmp.texi
texindex manual-tmp.??
pdftex --interaction=nonstopmode manual-tmp.texi
- mv manual-tmp.pdf nusphere.pdf
+ mv manual-tmp.pdf $@
rm -f manual-tmp.*
touch $@
-# Target to produce DocBook XML
-mysql.xml: manual.texi include.texi
- $(MAKEINFO) --force --no-ifinfo --docbook manual.texi
+# XML, DocBook 4.0
+mysql.de.xml: manual.de.texi include.texi
+ $(MAKEINFO) --force --no-ifinfo --docbook $<
+ mv $@ mysql-tmp.xml
+ Support/docbook-fixup.pl <mysql-tmp.xml >$@
+ rm -f mysql-tmp.xml
-# The texi2dvi gives a lot of harmless errors. Just ignore them unless
-# you want to help with the typesetting part.
-# This is the European papersize version
-manual_a4.ps: manual.texi include.texi
+# Postscript, A4 Paper
+manual_a4.de.ps: manual.de.texi include.texi
TEXINPUTS=$(srcdir):$$TEXINPUTS \
MAKEINFO='$(MAKEINFO) -I $(srcdir)' \
$(TEXI2DVI) --batch --texinfo --quiet '@afourpaper' $<
- $(DVIPS) -t a4 manual.dvi -o $@
+ $(DVIPS) -t a4 manual.de.dvi -o $@
touch $@
-# This is the American papersize version
-manual_letter.ps: manual.texi include.texi
+# Postscript, US Letter Paper
+manual_letter.de.ps: manual.de.texi include.texi
TEXINPUTS=$(srcdir):$$TEXINPUTS \
MAKEINFO='$(MAKEINFO) -I $(srcdir)' \
$(TEXI2DVI) --batch $<
- $(DVIPS) -t letter manual.dvi -o $@
+ $(DVIPS) -t letter manual.de.dvi -o $@
+ touch $@
+
+
+#
+# Miscellaneous
+#
+
+# Target to produce NuSphere Manual
+nusphere.pdf: manual.texi
+ sed -e 's/@example/@smallexample/g' \
+ -e 's/@end example/@end smallexample/g' \
+ -e 's/@c ifnusphere //g' \
+ -e 's|@image{[^}]*} *||g' \
+ <$< >manual-tmp.texi
+ pdftex --interaction=nonstopmode manual-tmp.texi
+ texindex manual-tmp.??
+ pdftex --interaction=nonstopmode manual-tmp.texi
+ texindex manual-tmp.??
+ pdftex --interaction=nonstopmode manual-tmp.texi
+ mv manual-tmp.pdf $@
+ rm -f manual-tmp.*
touch $@
# Include images for the manual in the distribution
@@ -131,7 +193,7 @@ dist-hook:
GT = $(srcdir)/Support/generate-text-files.pl
../INSTALL-SOURCE: mysql.info $(GT)
- perl -w $(GT) mysql.info "Installing" "Compatibility" > $@
+ perl -w $(GT) mysql.info "Installing" "Tutorial" > $@
# We put the description for the binary installation here so that
# people who download source wont have to see it. It is moved up to
diff --git a/Docs/Support/colspec-fix.pl b/Docs/Support/colspec-fix.pl
new file mode 100755
index 00000000000..21abb90fef9
--- /dev/null
+++ b/Docs/Support/colspec-fix.pl
@@ -0,0 +1,52 @@
+#!/usr/bin/perl -w
+
+#
+# Script to rewrite colspecs from relative values to absolute values
+#
+
+# arjen 2002-03-14 append "cm" specifier to colwidth field.
+
+use strict;
+
+my $table_width = 12.75; # cm
+my $gutter_width = 0.09; # cm
+
+my $str = join '', <>;
+
+$str =~ s{([\t ]*(<colspec colwidth=\".+?\" />\s*)+)}
+ {&rel2abs($1)}ges;
+
+print STDOUT $str;
+exit;
+
+#
+# Definitions for helper sub-routines
+#
+
+sub msg {
+ print STDERR shift, "\n";
+}
+
+sub rel2abs {
+ my $str = shift;
+
+ my @widths = ();
+ my $total = 0;
+ my $output = '';
+
+ $str =~ /^(\s+)/;
+ my $ws = $1;
+
+ while ($str =~ m/<colspec colwidth="(\d+)\*" \/>/g) {
+ $total += $1;
+ push @widths, $1;
+ }
+
+ my $unit = ($table_width - ($#widths * $gutter_width)) / ($total);
+
+ foreach (@widths) {
+ $output .= $ws . '<colspec colwidth="'. sprintf ("%0.2f", $_ * $unit) .'cm" />' . "\n";
+ }
+
+ return $output . "\n$ws";
+}
diff --git a/Docs/Support/docbook-fixup.pl b/Docs/Support/docbook-fixup.pl
new file mode 100755
index 00000000000..ba2e9b3779d
--- /dev/null
+++ b/Docs/Support/docbook-fixup.pl
@@ -0,0 +1,165 @@
+#!/usr/bin/perl -w
+
+# Fix the output of `makeinfo --docbook` version 4.0c
+# Convert the broken docbook output to well-formed XML that conforms to the O'Reilly idiom
+# See code for detailed comments
+# Authors: Arjen Lentz and Zak Greant
+
+use strict;
+
+my $data = '';
+my @apx = ();
+my $apx = '';
+my @nodes = ();
+my $nodes = '';
+
+msg ("\n-- Post-processing `makeinfo --docbook` output --");
+msg ("** Written to work with makeinfo version 4.0c **\n");
+
+msg ("Discarding DTD - not required by subsequent scripts");
+# <> is a magic filehandle - either reading lines from stdin or from file(s) specified on the command line
+<>;
+
+msg ("Create an XML PI with ISO-8859-1 character encoding");
+$data = "<?xml version='1.0' encoding='ISO-8859-1'?>";
+
+msg ("Get the rest of the data");
+$data = $data . join "", <>;
+
+msg ("Add missing <bookinfo> and <abstract> opening tags");
+# Note the absence of the g (global) pattern modified. This situation can only happen once.
+# ...as soon as we find the first instance, we can stop looking.
+$data =~ s/<book lang="en">/<book lang="en"><bookinfo><abstract>/;
+
+msg ("Removing mailto: from email addresses...");
+$data =~ s/mailto://g;
+
+msg ("Removing INFORMALFIGURE...");
+$data =~ s{<informalfigure>.+?</informalfigure>}
+ {}gs;
+
+msg ("Convert ampersands to XML escape sequences ");
+$data =~ s/&(?!\w+;)/&amp;/g;
+
+msg ("Changing @@ to @...");
+$data =~ s/@@/@/g;
+
+msg ("Rework references of the notation '<n>'");
+# Need to talk to Arjen about what the <n> bits are for
+$data =~ s/<(\d)>/[$1]/g;
+
+msg ("Changing '_' to '-' in references...");
+$data =~ s{((?:id|linkend)=\".+?\")}
+ {&underscore2hyphen($1)}gex;
+
+msg ("Changing ULINK to SYSTEMITEM...");
+$data =~ s{<ulink url=\"(.+?)\">\s*</ulink>}
+ {<systemitem role=\"url\">$1</systemitem>}gs;
+
+msg ("Adding PARA inside ENTRY...");
+$data =~ s{<entry>(.*?)</entry>}
+ {<entry><para>$1</para></entry>}gs;
+
+msg ("Fixing spacing problem with titles...");
+$data =~ s{(</\w+>)(\w{2,})}
+ {$1 $2}gs;
+
+msg ("Adding closing / to XREF and COLSPEC tags...");
+$data =~ s{<(xref|colspec) (.+?)>}
+ {<$1 $2 />}gs;
+
+# Probably need to strip these
+msg ('Adding "See " to XREFs that used to be @xref...');
+$data =~ s{([.'!)])\s*<xref }
+ {$1 See <xref }gs;
+
+msg ('Adding "see " to (XREFs) that used to be (@pxref)...');
+$data =~ s{([([,;])(\s*)<xref }
+ {$1$2see <xref }gs;
+
+msg ("Making first row in table THEAD...");
+$data =~ s{( *)<tbody>(\s*<row>.+?</row>)}
+ {$1<thead>$2\n$1</thead>\n$1<tbody>}gs;
+
+msg ("Removing EMPHASIS inside THEAD...");
+$data =~ s{<thead>(.+?)</thead>}
+ {"<thead>".&strip_tag($1, 'emphasis')."</thead>"}gsex;
+
+msg ("Removing empty PARA...");
+$data =~ s{<para>\s*</para>}
+ {}gs;
+
+msg ("Removing lf before /PARA in ENTRY...");
+$data =~ s{\n(</para></entry>)}
+ {$1}gs;
+
+msg ("Removing whitespace before /PARA if not on separate line...");
+$data =~ s{(\S+)[\t ]+</para>}
+ {$1</para>}g;
+
+msg ("Removing PARA around INDEXTERM if no text in PARA...");
+$data =~ s{<para>((?:<indexterm role=\"[^"]+\">(?:<(primary|secondary)>[^>]+</\2>)+?</indexterm>)+?)\s*</para>}
+ {$1}gs;
+
+@apx = ("Users", "MySQL Testimonials", "News", "GPL-license", "LGPL-license");
+
+foreach $apx (@apx) {
+ msg ("Removing appendix $apx...");
+ $data =~ s{<appendix id=\"$apx\">(.+?)</appendix>}
+ {}gs;
+
+ # Skip to next appendix regex if the regex did not match anything
+ next unless (defined $&);
+
+ msg ("...Building list of removed nodes...");
+
+ # Split the last bracketed regex match into an array
+ # Extract the node names from the tags and push them into an array
+ foreach (split "\n", $&) {
+ push @nodes, $1 if /<\w+ id=\"(.+?)\">/
+ }
+}
+
+# 2002-02-22 arjen@mysql.com (added fix " /" to end of regex, to make it match)
+msg ("Fixing references to removed nodes...");
+# Merge the list of node names into a set of regex alternations
+$nodes = join "|", @nodes;
+
+# Find all references to removed nodes and convert them to absolute URLs
+$data =~ s{<\w+ linkend="($nodes)" />}
+ {&xref2link($1)}ges;
+
+print STDOUT $data;
+exit;
+
+#
+# Definitions for helper sub-routines
+#
+
+sub msg {
+ print STDERR shift, "\n";
+}
+
+sub strip_tag($$) {
+ (my $str, my $tag) = @_;
+ $str =~ s{<$tag>(.+?)</$tag>}{$1}gs;
+ return $str;
+}
+
+sub underscore2hyphen($) {
+ my $str = shift;
+ $str =~ tr/_/-/;
+ return $str;
+}
+
+sub xref2link {
+ my $ref = shift;
+ $ref =~ tr/ /_/;
+ $ref =~ s{^((.)(.).+)$}{$2/$3/$1.html};
+ return "http://www.mysql.com/doc/" . $ref;
+}
+
+# We might need to encode the high-bit characters to ensure proper representation
+# msg ("Converting high-bit characters to entities");
+# $data =~ s/([\200-\400])/&get_entity($1)>/gs;
+# There is no get_entity function yet - no point writing it til we need it :)
diff --git a/Docs/Support/docbook-split b/Docs/Support/docbook-split
new file mode 100755
index 00000000000..eafb437efe4
--- /dev/null
+++ b/Docs/Support/docbook-split
@@ -0,0 +1,70 @@
+#! /usr/bin/perl -w
+# O'Reilly's Perl script to chop mysql.xml into separate ch/apps/index files.
+# The indexes are actually not used, they're created straight from the xrefs.
+# Breaks the MySQL reference manual into chapters, appendices, and indexes.
+
+use strict;
+
+my $app_letter = "a"; # Start appendix letters at "a"
+my $chap_num = 1; # Start chapter numbers at one (there is no preface)
+my $directory = "mysql_refman_" . time;
+my $ext = ".xml";
+my $line = "";
+my $output_name = "";
+my $start_text = "";
+
+mkdir $directory unless -d $directory;
+
+while (defined $line) {
+ if ($line =~ /(<chapter.+)/i ) {
+ $start_text = $1;
+ $output_name = sprintf("ch%02d%s", $chap_num, $ext);
+ ++$chap_num;
+ &process_file("chapter");
+ }
+ elsif ($line =~ /(<appendix.+)/i ) {
+ $start_text = $1 ;
+ $output_name = "app$app_letter$ext";
+ ++$app_letter;
+ &process_file("appendix");
+ }
+ elsif ($line =~ /(<index\s+id=")(.*?)(">.*)/i ) {
+ $start_text = $1 . $2 . $3;
+ $output_name = lc($2) . $ext;
+ &process_file("index");
+ }
+ else {
+ # Skip junk in between chapters, appendices and indexes.
+ $line = <>;
+ }
+}
+
+sub process_file {
+ my $marker = shift;
+ my $path = "$directory/$output_name";
+
+ open (OUTPUT_FILE, ">$path") or die "Cannot open $path";
+
+ print STDERR "Creating $path\n";
+
+ # Print out XML PI
+ print OUTPUT_FILE "<?xml version='1.0' encoding='ISO-8859-1'?>\n";
+
+ # Print whatever happened to appear at the end of the previous chapter.
+ print OUTPUT_FILE "$start_text\n" if $start_text;
+
+ while (defined $line) {
+ $line = <>;
+
+ # Note: Anything after the terminating marker is lost, just like
+ # lines in between chapters.
+ if ($line =~ /(.*<\/\s*$marker\s*>)/i ) {
+ print OUTPUT_FILE "$1\n" if $1;
+ close OUTPUT_FILE;
+ return;
+ }
+ print OUTPUT_FILE $line;
+ }
+}
+
+exit 0;
diff --git a/Docs/Support/generate-flag-images b/Docs/Support/generate-flag-images
index 903c610d4bc..21140388012 100755
--- a/Docs/Support/generate-flag-images
+++ b/Docs/Support/generate-flag-images
@@ -1,37 +1,31 @@
#!/bin/sh
-tmp=/tmp/temp-pic.pnm
-
-all="argentina austria czech-republic germany great-britain hungary israel
-italy russia portugal sweden canada usa south-korea japan taiwan australia
-romania denmark france estonia poland singapore bulgaria south-africa
-netherlands chile ukraine greece finland switzerland croatia china
-brazil spain iceland ireland denmark"
-
-new=""
+flags=`grep @image mirrors.texi | cut -d" " -f1 | cut -d/ -f2 | tr -d "}" | sort | uniq`
set -x
-cd Flags
-
-# for c in $all; do cp empty.png $c.pdf; done; exit
+cd Flags
-for c in $new
+for c in $flags
do
- # For HTML version
- giftopnm ../Raw-Flags/$c.gif | \
- pnmscale -xsize 30 > $tmp
- pnmpaste $tmp 1 1 ../Images/flag-background.pnm > $c.pnm
- rm -f $tmp
- # For web version
+ # For PNM, to be used later
+ giftopnm ../Raw-Flags/$c.gif | pnmscale -xsize 30 > $c-tmp.pnm
+ pnmpaste $c-tmp.pnm 1 1 ../Images/flag-background.pnm > $c.pnm
+ rm -f $c-tmp.pnm
+
+ # For GIF version
ppmtogif $c.pnm > $c.gif
# or cjpeg -optimize -quality 70 -outfile $c.jpg
- # For PDF version (this coredumps. use empty file until fixed)
- # pnmtopng -verbose $c.pnm > $c.png
- cp ../Images/empty.png $c.pdf
- # For TeX version
- giftopnm ../Raw-Flags/$c.gif | \
- pnmscale -xsize 30 | \
- pnmtops -noturn > $c.eps
+
+ # For EPS version
+ pnmtops -noturn $c.pnm > $c.eps
+
+ # For PDF version
+ ps2pdf $c.eps $c.pdf
+
# For text version
echo -n "" > $c.txt
+
+ # PNM isn't really needed
+ rm -f $c.pnm
+
done
diff --git a/Docs/Support/make-docbook b/Docs/Support/make-docbook
new file mode 100755
index 00000000000..bdca812d7ab
--- /dev/null
+++ b/Docs/Support/make-docbook
@@ -0,0 +1,24 @@
+#!/bin/sh
+# 2002-01-30 arjen@mysql.com
+# Use this to create mysql.xml (the DocBook XML format output of manual.texi)
+# Requires makeinfo 4.0c
+
+#create include.texi with version/port #
+ echo "@c This file is autogenerated by the Makefile" > include.texi
+ echo -n "@set mysql_version " >> include.texi
+ grep "AM_INIT_AUTOMAKE(mysql, " ../configure.in | \
+ sed -e 's;AM_INIT_AUTOMAKE(mysql, ;;' -e 's;);;' >> include.texi
+ echo -n "@set default_port " >> include.texi
+ grep "MYSQL_TCP_PORT_DEFAULT=" ../configure.in | \
+ sed -e 's;MYSQL_TCP_PORT_DEFAULT=;;' >> include.texi
+
+# produce DocBook XML
+ makeinfo --force --no-ifinfo --docbook -o - manual.texi |\
+ Support/docbook-fixup.pl > mysql.xml
+
+ # See if the XML output is well-formed
+ xmlwf mysql.xml
+
+ # If all is well, keep processing
+ cat mysql.xml | Support/colspec-fix.pl | Support/docbook-split;
+
diff --git a/Docs/Support/test-make-manual-de b/Docs/Support/test-make-manual-de
new file mode 100755
index 00000000000..a5c03001bda
--- /dev/null
+++ b/Docs/Support/test-make-manual-de
@@ -0,0 +1,137 @@
+#!/bin/sh
+
+needed_flags=0
+needed_texi2html=0
+needed_texinfo_tex=0
+needed_include_texi=0
+
+if [ -z $BROWSER ]; then
+ BROWSER=netscape
+ echo "BROWSER not set, using $BROWSER"
+fi
+
+die ()
+{
+ echo
+ echo $1
+ cleanup
+ exit 1
+}
+
+cleanup ()
+{
+ echo "Cleaning up..."
+ if [ $needed_flags ]; then
+ bk clean Flags
+ fi
+
+ if [ $needed_texi2html ]; then
+ bk clean Support/texi2html
+ fi
+
+ if [ $needed_texinfo_tex ]; then
+ bk clean Support/texinfo.tex
+ fi
+
+ if [ $needed_include_texi ]; then
+ rm -f include.texi
+ fi
+
+ for file in \
+ manual.de.aux manual.de.cp manual.de.cps manual.de.dvi \
+ manual.de.fn manual.de.fns manual.de.ky manual.de.html \
+ manual.de.pg manual.de.toc manual.de.tp manual.de.vr \
+ mysql.de.info manual.de_toc.html ;
+ do
+ rm -f $file
+ done
+
+}
+
+
+if [ -e Flags/usa.txt ]; then
+ echo "Good, Flags are there."
+else
+ echo -n "Checking out Flags..."
+ bk edit Flags >/dev/null 2>&1
+ echo " Done."
+ needed_flags=1
+fi
+
+if [ -e Support/texi2html ]; then
+ echo "Good, texi2html is there."
+else
+ echo -n "Checking out texi2html..."
+ bk edit Support/texi2html >/dev/null 2>&1
+ echo " Done."
+ needed_texi2html=1
+fi
+
+if [ -e Support/texinfo.tex ]; then
+ echo "Good, texinfo.tex is there."
+else
+ echo -n "Checking out texinfo.tex..."
+ bk edit Support/texinfo.tex >/dev/null 2>&1
+ echo " Done."
+ needed_texinfo_tex=1
+fi
+
+if [ -e include.texi ]; then
+ echo "Good, include.texi is there."
+else
+ echo -n "Creating include.texi..."
+ bk edit ../configure.in >/dev/null 2>&1
+ echo "@c This file was generated by test-make-manual" > include.texi
+ echo -n "@set mysql_version " >> include.texi
+ grep "AM_INIT_AUTOMAKE(mysql, " ../configure.in | \
+ sed -e 's;AM_INIT_AUTOMAKE(mysql, ;;' -e 's;);;' >> include.texi
+ echo -n "@set default_port " >> include.texi
+ grep "MYSQL_TCP_PORT_DEFAULT=" ../configure.in | \
+ sed -e 's;MYSQL_TCP_PORT_DEFAULT=;;' >> include.texi
+ echo " Done."
+ needed_include_texi=1
+fi
+
+echo -n "Running makeinfo..."
+makeinfo --no-split -I . manual.de.texi
+
+if [ $? != 0 ]; then
+ die "Manual has errors - fix before you commit"
+else
+ echo " Looks good."
+fi
+
+
+echo -n "Running texi2html..."
+/usr/bin/perl ./Support/texi2html -iso -number manual.de.texi
+
+if [ $? != 0 ]; then
+ die "Manual has errors - fix before you commit"
+else
+ echo " Looks good."
+fi
+
+
+echo -n "Running texi2dvi..."
+texi2dvi --batch manual.de.texi > texi2dvi.out
+
+if [ $? != 0 ]; then
+ die "Manual has errors - fix before you commit (saved in texi2dvi.out)"
+else
+ rm texi2dvi.out
+ echo " Looks good."
+fi
+
+echo
+echo
+echo "Please examine your modifications in \`manual.de.html'."
+echo
+echo "If you would like to use a different browser, set the 'BROWSER' environment"
+echo "variable."
+echo
+
+$BROWSER file:`pwd`/manual.de_toc.html
+
+echo "-- Press Enter to Continue --"
+read junk
+cleanup
diff --git a/Docs/Support/update-reserved-words.pl b/Docs/Support/update-reserved-words.pl
new file mode 100755
index 00000000000..e7f8329009e
--- /dev/null
+++ b/Docs/Support/update-reserved-words.pl
@@ -0,0 +1,89 @@
+#!/usr/bin/perl
+
+# Based on a Emacs macro by david@mysql.com
+# Implemented in Perl by jeremy@mysql.com
+# 2001-11-20 Fixups by arjen@mysql.com, 2 keywords and 15 synonyms were missing
+# 2001-12-07 Fixup by arjen@mysql.com, add column headings for multitable.
+
+print STDERR "Scanning lex.h for symbols..\n";
+open LEX, "<../sql/lex.h";
+while($line = <LEX>) {
+ if($line =~ /\{\s*\"([A-Z_]+)\"/) {
+ $words{$1} = $1;
+ } elsif($line =~ /sql_functions/) {
+ last;
+ };
+};
+close LEX;
+
+print STDERR "Scanning sql_yacc.yy for non-reserved words...\n";
+open YACC, "<../sql/sql_yacc.yy";
+while(<YACC> !~ /^keyword:/) {};
+while(($line = <YACC>) =~ /[\s|]+([A-Z_]+)/) {
+ $keyword = $1;
+ $keyword =~ s/_SYM//;
+ delete $words{$keyword};
+};
+close YACC;
+
+
+$list = sprintf("\@c Reserved word list updated %s by %s.\n".
+ "\@c To regenerate, use Support/update-reserved-words.pl.\n\n",
+ &pretty_date, $ENV{USER});
+
+
+print STDERR "Copying reserved words to an array...\n";
+foreach(keys %words) { push @words, $words{$_}; };
+
+print STDERR "Sorting array...\n";
+@words = sort @words;
+
+printf STDERR "There are %i reserved words.\n", scalar @words;
+
+@pre = ("\@item", "\@tab", " \@tab", "\@tab");
+@post = ("", "\n", "", "\n");
+
+for($i=0; $word = shift(@words); $i++) {
+ $list .= sprintf "%s %-30s %s", $pre[$i%4], "\@code\{$word\}", $post[$i%4];
+}; $list .= "\n";
+
+open OLD, "<manual.texi";
+open NEW, ">manual-tmp.texi";
+
+print STDERR "Copying beginning of manual.texi...\n";
+while(($line = <OLD>) !~ /START_OF_RESERVED_WORDS/) { print NEW $line; };
+print NEW "\@c START_OF_RESERVED_WORDS\n\n";
+print STDERR "Inserting list of reserved words...\n";
+print NEW "\@multitable \@columnfractions .25 .25 .25 .25\n";
+print NEW "\@item \@strong{Word} \@tab \@strong{Word} \@tab \@strong{Word} \@tab \@strong{Word}\n";
+print NEW $list;
+print NEW "\@end multitable\n";
+print STDERR "Skipping over old list...\n";
+while(($line = <OLD>) !~ /END_OF_RESERVED_WORDS/) {};
+print NEW "\n\@c END_OF_RESERVED_WORDS\n";
+print STDERR "Copying end of manual.texi...\n";
+while($line = <OLD>) { print NEW $line; };
+
+close OLD;
+close NEW;
+
+print STDERR "Moving manual-tmp.texi to manual.texi...\n";
+unlink "manual.texi";
+rename "manual-tmp.texi", "manual.texi";
+
+print STDERR "Reserved word list updated successfully!\n";
+
+sub pretty_date {
+ @time = ($time = shift)?((localtime($time))[0..6]):((localtime)[0..6]);
+
+ ($sec, $min, $hour, $mday, $mon, $year, $wday) = @time;
+ $wday = (Sun,Mon,Tue,Wed,Thu,Fri,Sat)[$wday];
+ $mon = (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec)[$mon];
+ $year += 1900;
+
+ $pretty = sprintf("%s %s %2i %02i:%02i:%02i %i",
+ $wday, $mon, $mday, $hour, $min, $sec, $year);
+
+ return $pretty;
+};
+
diff --git a/Docs/Support/xwf b/Docs/Support/xwf
new file mode 100755
index 00000000000..38f89774fe8
--- /dev/null
+++ b/Docs/Support/xwf
@@ -0,0 +1,67 @@
+#!/usr/bin/perl -w
+#
+# Parse document and report first syntax (well-formedness) error found.
+#
+
+use strict;
+use XML::Parser;
+use Getopt::Std;
+
+my %opts;
+getopts('e', \%opts);
+my $ENTREFS = exists( $opts{'e'} ); # flag: check ent refs
+
+my $parser = XML::Parser->new(
+ ErrorContext => 2, # output error context
+ );
+
+# get input from files
+if( @ARGV ) {
+ foreach( @ARGV ) {
+ my $file = $_;
+ unless( -r $file ) {
+ print STDERR "ERROR: Can't open '$file'.\n";
+ return;
+ }
+ my $input = '';
+ open( F, $file );
+ while( <F> ) { $input .= $_; }
+ close F;
+
+ # parse and report errors
+ if( &parse_string( $input )) {
+ print STDERR "ERROR in $file:\n$@\n";
+ } else {
+ print STDERR "'$file' is well-formed.\n";
+ }
+ }
+ print "All files checked.\n";
+
+# get input from STDIN
+} else {
+ my $input = "";
+ while( <STDIN> ) { $input .= $_; }
+ if( &parse_string( $input )) {
+ print STDERR "ERROR in stream:\n$@\n";
+ } else {
+ print STDERR "No syntax errors found in XML stream.\n";
+ }
+}
+
+
+# parse the string and return error message
+#
+# NOTE: By default, entity refs are not expanded. XML::Parser can be
+# told not to expand entity refs, but will still try to find
+# replacement text just in case, which we don't want. Therefore, we
+# need to do a stupid regexp replacement, removing entities from input.
+#
+sub parse_string {
+ my $string = shift;
+ unless( $ENTREFS ) {
+ $string =~ s/\&[^\s;]+;//g; # remove entity references
+ }
+ eval { $parser->parse( $string ); };
+ $@ =~ s/at \/.*?$//s; # remove module line number
+ return $@;
+}
diff --git a/Docs/bk.txt b/Docs/bk.txt
index cb2521b2b05..4c83c48aea6 100644
--- a/Docs/bk.txt
+++ b/Docs/bk.txt
@@ -55,5 +55,4 @@ Their developers, and especially the president of the company Larry McVoy really
like MySQL and are very anxious to help us. Make sure it is obvious that you
work for MySQL, of course. And, of course, do not bug them with little things
that you can figure out on your own or with my help - they were nice to offer us
-support, but we should not abuse it.
-
+support, but we should not abuse it. \ No newline at end of file
diff --git a/Docs/internals.texi b/Docs/internals.texi
index 2195b42d9a0..39e254f0f50 100644
--- a/Docs/internals.texi
+++ b/Docs/internals.texi
@@ -1,26 +1,30 @@
\input texinfo @c -*-texinfo-*-
-@c Copyright 1998 TcX AB, Detron HB and Monty Program KB
+@c Copyright 2002 MySQL AB, TcX AB, Detron HB and Monty Program KB
@c
@c %**start of header
@setfilename internals.info
+
@c We want the types in the same index
-@c @synindex tp fn cp
@synindex cp fn
+
@iftex
-@c Well this is normal in Europe. Maybe this should go into the include.texi?
@afourpaper
@end iftex
+
@c Get version and other info
@include include.texi
+
@ifclear tex-debug
@c This removes the black squares in the right margin
@finalout
@end ifclear
+
@c Set background for HTML
@set _body_tags BGCOLOR=#FFFFFF TEXT=#000000 LINK=#101090 VLINK=#7030B0
-@settitle @strong{MySQL} internals Manual for version @value{mysql_version}.
-@setchapternewpage off
+@settitle @strong{MySQL} Internals Manual for version @value{mysql_version}.
+@setchapternewpage odd
@paragraphindent 0
+
@c %**end of header
@ifinfo
@@ -35,67 +39,77 @@ END-INFO-DIR-ENTRY
@sp 10
@center @titlefont{@strong{MySQL} Internals Manual}
@sp 10
-@center Copyright @copyright{} 1998 TcX AB, Detron HB and Monty Program KB
+@center Copyright @copyright{} 1998-2002 MySQL AB
+@page
@end titlepage
-@node Top, Introduction, (dir), (dir)
+@node Top, caching, (dir), (dir)
@ifinfo
This is a manual about @strong{MySQL} internals.
@end ifinfo
@menu
+* caching:: How MySQL Handles Caching
+* flush tables:: How MySQL Handles @code{FLUSH TABLES}
+* filesort:: How MySQL Does Sorting (@code{filesort})
+* coding guidelines:: Coding Guidelines
+* mysys functions:: Functions In The @code{mysys} Library
+* DBUG:: DBUG Tags To Use
+* protocol:: MySQL Client/Server Protocol
@end menu
-@node caching,,,
-@chapter How MySQL handles caching
+
+@node caching, flush tables, Top, Top
+@chapter How MySQL Handles Caching
@strong{MySQL} has the following caches:
(Note that the some of the filename have a wrong spelling of cache. :)
-@itemize @bullet
+@table @strong
-@item Key cache
+@item Key Cache
A shared cache for all B-tree index blocks in the different NISAM
files. Uses hashing and reverse linked lists for quick caching of the
last used blocks and quick flushing of changed entries for a specific
table. (@file{mysys/mf_keycash.c})
-@item Record cache
+@item Record Cache
This is used for quick scanning of all records in a table.
(@file{mysys/mf_iocash.c} and @file{isam/_cash.c})
-@item Table cache
+@item Table Cache
This holds the last used tables. (@file{sql/sql_base.cc})
-@item Hostname cache
+@item Hostname Cache
For quick lookup (with reverse name resolving). Is a must when one has a
slow DNS.
(@file{sql/hostname.cc})
-@item Privilege cache
+@item Privilege Cache
To allow quick change between databases the last used privileges are
cached for each user/database combination.
(@file{sql/sql_acl.cc})
-@item Heap table cache
-Many use of GROUP BY or DISTINCT caches all found
-rows in a HEAP table (this is a very quick in-memory table with hash index)
+@item Heap Table Cache
+Many use of @code{GROUP BY} or @code{DISTINCT} caches all found rows in
+a @code{HEAP} table. (This is a very quick in-memory table with hash index.)
+
+@item Join Row Cache
+For every full join in a @code{SELECT} statement (a full join here means
+there were no keys that one could use to find the next table in a list),
+the found rows are cached in a join cache. One @code{SELECT} query can
+use many join caches in the worst case.
+@end table
-@item Join row cache.
-For every full join in a SELECT statement (a full join here means there
-were no keys that one could use to find the next table in a list), the
-found rows are cached in a join cache. One SELECT query can use many
-join caches in the worst case.
-@end itemize
-@node flush tables,,,
-@chapter How MySQL handles flush tables
+@node flush tables, filesort, caching, Top
+@chapter How MySQL Handles @code{FLUSH TABLES}
@itemize @bullet
@item
-Flush tables is handled in @code{sql/sql_base.cc::close_cached_tables()}.
+Flush tables is handled in @file{sql/sql_base.cc::close_cached_tables()}.
@item
The idea of flush tables is to force all tables to be closed. This
@@ -109,8 +123,8 @@ all tables)!
When one does a @code{FLUSH TABLES}, the variable @code{refresh_version}
will be incremented. Every time a thread releases a table it checks if
the refresh version of the table (updated at open) is the same as
-the current refresh_version. If not it will close it and broadcast
-a signal on COND_refresh (to wait any thread that is waiting for
+the current @code{refresh_version}. If not it will close it and broadcast
+a signal on @code{COND_refresh} (to wait any thread that is waiting for
all instanses of a table to be closed).
@item
@@ -119,8 +133,8 @@ The current @code{refresh_version} is also compared to the open
refresh version is different the thread will free all locks, reopen the
table and try to get the locks again; This is just to quickly get all
tables to use the newest version. This is handled by
-@code{sql/lock.cc::mysql_lock_tables()} and
-@code{sql/sql_base.cc::wait_for_tables()}.
+@file{sql/lock.cc::mysql_lock_tables()} and
+@file{sql/sql_base.cc::wait_for_tables()}.
@item
When all tables has been closed @code{FLUSH TABLES} will return an ok
@@ -134,8 +148,8 @@ After this it will give other threads a chance to open the same tables.
@end itemize
-@node Filesort,,,
-@chapter How MySQL does sorting (filesort)
+@node filesort, coding guidelines, flush tables, Top
+@chapter How MySQL Does Sorting (@code{filesort})
@itemize @bullet
@@ -146,7 +160,7 @@ Read all rows according to key or by table scanning.
Store the sort-key in a buffer (@code{sort_buffer}).
@item
-When the buffer gets full, run a qsort on it and store the result
+When the buffer gets full, run a @code{qsort} on it and store the result
in a temporary file. Save a pointer to the sorted block.
@item
@@ -174,8 +188,9 @@ and then we read the rows in the sorted order into a row buffer
@end itemize
-@node Coding guidelines,,,
-@chapter Coding guidelines
+
+@node coding guidelines, mysys functions, filesort, Top
+@chapter Coding Guidelines
@itemize @bullet
@@ -183,24 +198,28 @@ and then we read the rows in the sorted order into a row buffer
We are using @uref{http://www.bitkeeper.com/, BitKeeper} for source management.
@item
-You should use the @strong{MySQL} 3.23 or 4.0 source for all developments.
+You should use the @strong{MySQL} 4.0 source for all developments.
@item
If you have any questions about the @strong{MySQL} source, you can post these
-to @email{developers@@mysql.com} and we will answer them.
-Note that we will shortly change the name of this list to
-@email{internals@@mysql.com}, to more accurately reflect what should be
-posted to this list.
+to @email{dev-public@@mysql.com} and we will answer them. Please
+remember to not use this internal email list in public!
@item
-Try to write code in a lot of black boxes that can be reused or at
-least have a clean interface.
+Try to write code in a lot of black boxes that can be reused or use at
+least a clean, easy to change interface.
@item
Reuse code; There is already a lot of algorithms in MySQL for list handling,
queues, dynamic and hashed arrays, sorting, etc. that can be reused.
@item
+Use the @code{my_*} functions like @code{my_read()}/@code{my_write()}/
+@code{my_malloc()} that you can find in the @code{mysys} library instead
+of the direct system calls; This will make your code easier to debug and
+more portable.
+
+@item
Try to always write optimized code, so that you don't have to
go back and rewrite it a couple of months later. It's better to
spend 3 times as much time designing and writing an optimal function than
@@ -221,25 +240,23 @@ Don't use two commands on the same line.
Do not check the same pointer for @code{NULL} more than once.
@item
-Use long function and variable names in English; This makes your code
-easier to read. Use the 'varible_name' style instead of 'VariableName'.
+Use long function and variable names in English. This makes your code
+easier to read.
@item
-Think assembly - make it easier for the compiler to optimize your code.
+Use @code{my_var} as opposed to @code{myVar} or @code{MyVar} (@samp{_}
+rather than dancing SHIFT to seperate words in identifiers).
@item
-Comment your code when you do something that someone else may think
-is not ''trivial''.
+Think assembly - make it easier for the compiler to optimize your code.
@item
-Use the @code{my_*} functions like @code{my_read()}/@code{my_write()}/
-@code{my_malloc()} that you can find in the @code{mysys} library instead
-of the direct system calls; This will make your code easier to debug and
-more portable.
+Comment your code when you do something that someone else may think
+is not ``trivial''.
@item
-Use @code{libstring} functions instead of standard libc string functions
-whenever possible.
+Use @code{libstring} functions (in the @file{strings} directory)
+instead of standard @code{libc} string functions whenever possible.
@item
Avoid using @code{malloc()} (its REAL slow); For memory allocations
@@ -254,10 +271,6 @@ easily discuss it thoroughly if some other developer thinks there is better
way to do the same thing!
@item
-Use my_var as opposed to myVar or MyVar (@samp{_} rather than dancing SHIFT
-to seperate words in identifiers).
-
-@item
Class names start with a capital letter.
@item
@@ -270,26 +283,25 @@ Any @code{#define}'s are in all-caps.
Matching @samp{@{} are in the same column.
@item
-Put the @samp{@{} after a 'switch' on the same line
+Put the @samp{@{} after a @code{switch} on the same line, as this gives
+better overall indentation for the switch statement:
@example
switch (arg) {
@end example
-Because this gives better overall indentation for the switch statement.
-
@item
-In all other cases, @{ and @} should be on their own line, except
-if there is nothing inside @{ @}.
+In all other cases, @samp{@{} and @samp{@}} should be on their own line, except
+if there is nothing inside @samp{@{} and @samp{@}}.
@item
-Have a space after 'if'
+Have a space after @code{if}
@item
-Put a space after ',' for function arguments
+Put a space after @samp{,} for function arguments
@item
-Functions return 0 on success, and non-zero on error, so you can do:
+Functions return @samp{0} on success, and non-zero on error, so you can do:
@example
if(a() || b() || c()) { error("something went wrong"); }
@@ -337,113 +349,110 @@ Suggested mode in emacs:
(setq c-default-style "MY")
@end example
-@node mysys functions,,,
-@chapter mysys functions
-
-Functions i mysys: (For flags se my_sys.h)
-
- int my_copy _A((const char *from,const char *to,myf MyFlags));
- - Copy file
-
- int my_delete _A((const char *name,myf MyFlags));
- - Delete file
-
- int my_getwd _A((string buf,uint size,myf MyFlags));
- int my_setwd _A((const char *dir,myf MyFlags));
- - Get and set working directory
-
- string my_tempnam _A((const char *pfx,myf MyFlags));
- - Make a uniq temp file name by using dir and adding something after
- pfx to make name uniq. Name is made by adding a uniq 6 length-string
- and TMP_EXT after pfx.
- Returns pointer to malloced area for filename. Should be freed by
- free().
-
- File my_open _A((const char *FileName,int Flags,myf MyFlags));
- File my_create _A((const char *FileName,int CreateFlags,
- int AccsesFlags, myf MyFlags));
- int my_close _A((File Filedes,myf MyFlags));
- uint my_read _A((File Filedes,byte *Buffer,uint Count,myf MyFlags));
- uint my_write _A((File Filedes,const byte *Buffer,uint Count,
- myf MyFlags));
- ulong my_seek _A((File fd,ulong pos,int whence,myf MyFlags));
- ulong my_tell _A((File fd,myf MyFlags));
- - Use instead of open,open-with-create-flag, close read and write
- to get automatic error-messages (flag: MYF_WME) and only have
- to test for != 0 if error (flag: MY_NABP).
-
- int my_rename _A((const char *from,const char *to,myf MyFlags));
- - Rename file
-
- FILE *my_fopen _A((const char *FileName,int Flags,myf MyFlags));
- FILE *my_fdopen _A((File Filedes,int Flags,myf MyFlags));
- int my_fclose _A((FILE *fd,myf MyFlags));
- uint my_fread _A((FILE *stream,byte *Buffer,uint Count,myf MyFlags));
- uint my_fwrite _A((FILE *stream,const byte *Buffer,uint Count,
- myf MyFlags));
- ulong my_fseek _A((FILE *stream,ulong pos,int whence,myf MyFlags));
- ulong my_ftell _A((FILE *stream,myf MyFlags));
- - Same read-interface for streams as for files
-
- gptr _mymalloc _A((uint uSize,const char *sFile,
- uint uLine, myf MyFlag));
- gptr _myrealloc _A((string pPtr,uint uSize,const char *sFile,
- uint uLine, myf MyFlag));
- void _myfree _A((gptr pPtr,const char *sFile,uint uLine));
- int _sanity _A((const char *sFile,unsigned int uLine));
- gptr _myget_copy_of_memory _A((const byte *from,uint length,
- const char *sFile, uint uLine,
- myf MyFlag));
- - malloc(size,myflag) is mapped to this functions if not compiled
- with -DSAFEMALLOC
-
- void TERMINATE _A((void));
- - Writes malloc-info on stdout if compiled with -DSAFEMALLOC.
-
- int my_chsize _A((File fd,ulong newlength,myf MyFlags));
- - Change size of file
-
- void my_error _D((int nr,myf MyFlags, ...));
- - Writes message using error number (se mysys/errors.h) on
- stdout or curses if MYSYS_PROGRAM_USES_CURSES() is called.
-
- void my_message _A((const char *str,myf MyFlags));
- - Writes message-string on
- stdout or curses if MYSYS_PROGRAM_USES_CURSES() is called.
-
- void my_init _A((void ));
- - Start each program (in main) with this.
- void my_end _A((int infoflag));
- - Gives info about program.
- - If infoflag & MY_CHECK_ERROR prints if some files are left open
- - If infoflag & MY_GIVE_INFO prints timing info and malloc info
- about prog.
-
- int my_redel _A((const char *from, const char *to, int MyFlags));
- - Delete from before rename of to to from. Copyes state from old
- file to new file. If MY_COPY_TIME is set sets old time.
-
- int my_copystat _A((const char *from, const char *to, int MyFlags));
- - Copye state from old file to new file.
- If MY_COPY_TIME is set sets copy also time.
-
- string my_filename _A((File fd));
- - Give filename of open file.
-
- int dirname _A((string to,const char *name));
- - Copy name of directory from filename.
-
- int test_if_hard_path _A((const char *dir_name));
- - Test if dirname is a hard path (Starts from root)
-
- void convert_dirname _A((string name));
- - Convert dirname acording to system.
- - In MSDOS changes all caracters to capitals and changes '/' to
- '\'
- string fn_ext _A((const char *name));
- - Returns pointer to extension in filename
- string fn_format _A((string to,const char *name,const char *dsk,
- const char *form,int flag));
+
+@node mysys functions, DBUG, coding guidelines, Top
+@chapter Functions In The @code{mysys} Library
+
+Functions in @code{mysys}: (For flags see @file{my_sys.h})
+
+@table @code
+@item int my_copy _A((const char *from, const char *to, myf MyFlags));
+Copy file from @code{from} to @code{to}.
+
+@item int my_delete _A((const char *name, myf MyFlags));
+Delete file @code{name}.
+
+@item int my_getwd _A((string buf, uint size, myf MyFlags));
+@item int my_setwd _A((const char *dir, myf MyFlags));
+Get and set working directory.
+
+@item string my_tempnam _A((const char *pfx, myf MyFlags));
+Make a unique temporary file name by using dir and adding something after
+@code{pfx} to make name unique. The file name is made by adding a unique
+six character string and @code{TMP_EXT} after @code{pfx}.
+Returns pointer to @code{malloc()}'ed area for filename. Should be freed by
+@code{free()}.
+
+@item File my_open _A((const char *FileName,int Flags,myf MyFlags));
+@item File my_create _A((const char *FileName, int CreateFlags, int AccsesFlags, myf MyFlags));
+@item int my_close _A((File Filedes, myf MyFlags));
+@item uint my_read _A((File Filedes, byte *Buffer, uint Count, myf MyFlags));
+@item uint my_write _A((File Filedes, const byte *Buffer, uint Count, myf MyFlags));
+@item ulong my_seek _A((File fd,ulong pos,int whence,myf MyFlags));
+@item ulong my_tell _A((File fd,myf MyFlags));
+Use instead of open, open-with-create-flag, close, read, and write
+to get automatic error messages (flag @code{MYF_WME}) and only have
+to test for != 0 if error (flag @code{MY_NABP}).
+
+@item int my_rename _A((const char *from, const char *to, myf MyFlags));
+Rename file from @code{from} to @code{to}.
+
+@item FILE *my_fopen _A((const char *FileName,int Flags,myf MyFlags));
+@item FILE *my_fdopen _A((File Filedes,int Flags,myf MyFlags));
+@item int my_fclose _A((FILE *fd,myf MyFlags));
+@item uint my_fread _A((FILE *stream,byte *Buffer,uint Count,myf MyFlags));
+@item uint my_fwrite _A((FILE *stream,const byte *Buffer,uint Count, myf MyFlags));
+@item ulong my_fseek _A((FILE *stream,ulong pos,int whence,myf MyFlags));
+@item ulong my_ftell _A((FILE *stream,myf MyFlags));
+Same read-interface for streams as for files.
+
+@item gptr _mymalloc _A((uint uSize,const char *sFile,uint uLine, myf MyFlag));
+@item gptr _myrealloc _A((string pPtr,uint uSize,const char *sFile,uint uLine, myf MyFlag));
+@item void _myfree _A((gptr pPtr,const char *sFile,uint uLine));
+@item int _sanity _A((const char *sFile,unsigned int uLine));
+@item gptr _myget_copy_of_memory _A((const byte *from,uint length,const char *sFile, uint uLine,myf MyFlag));
+@code{malloc(size,myflag)} is mapped to these functions if not compiled
+with @code{-DSAFEMALLOC}.
+
+@item void TERMINATE _A((void));
+Writes @code{malloc()} info on @code{stdout} if compiled with
+@code{-DSAFEMALLOC}.
+
+@item int my_chsize _A((File fd, ulong newlength, myf MyFlags));
+Change size of file @code{fd} to @code{newlength}.
+
+@item void my_error _D((int nr, myf MyFlags, ...));
+Writes message using error number (see @file{mysys/errors.h}) on @code{stdout},
+or using curses, if @code{MYSYS_PROGRAM_USES_CURSES()} has been called.
+
+@item void my_message _A((const char *str, myf MyFlags));
+Writes @code{str} on @code{stdout}, or using curses, if
+@code{MYSYS_PROGRAM_USES_CURSES()} has been called.
+
+@item void my_init _A((void ));
+Start each program (in @code{main()}) with this.
+
+@item void my_end _A((int infoflag));
+Gives info about program.
+If @code{infoflag & MY_CHECK_ERROR}, prints if some files are left open.
+If @code{infoflag & MY_GIVE_INFO}, prints timing info and malloc info
+about program.
+
+@item int my_redel _A((const char *from, const char *to, int MyFlags));
+Delete @code{from} before rename of @code{to} to @code{from}. Copies state
+from old file to new file. If @code{MY_COPY_TIME} is set, sets old time.
+
+@item int my_copystat _A((const char *from, const char *to, int MyFlags));
+Copy state from old file to new file. If @code{MY_COPY_TIME} is set,
+sets old time.
+
+@item string my_filename _A((File fd));
+Returns filename of open file.
+
+@item int dirname _A((string to, const char *name));
+Copy name of directory from filename.
+
+@item int test_if_hard_path _A((const char *dir_name));
+Test if @code{dir_name} is a hard path (starts from root).
+
+@item void convert_dirname _A((string name));
+Convert dirname according to system.
+In MSDOS, changes all characters to capitals and changes @samp{/} to @samp{\}.
+
+@item string fn_ext _A((const char *name));
+Returns pointer to extension in filename.
+
+@item string fn_format _A((string to,const char *name,const char *dsk,const char *form,int flag));
format a filename with replace of library and extension and
converts between different systems.
params to and name may be identicall
@@ -457,39 +466,93 @@ Functions i mysys: (For flags se my_sys.h)
"open(fn_format(temp_buffe,name,"","",4),...)" to unpack home and
convert filename to system-form.
- string fn_same _A((string toname,const char *name,int flag));
- - Copys directory and extension from name to toname if neaded.
- copy can be forced by same flags that in fn_format.
+@item string fn_same _A((string toname, const char *name, int flag));
+Copys directory and extension from @code{name} to @code{toname} if neaded.
+Copying can be forced by same flags used in @code{fn_format()}.
+
+@item int wild_compare _A((const char *str, const char *wildstr));
+Compare if @code{str} matches @code{wildstr}. @code{wildstr} can contain
+@samp{*} and @samp{?} as wildcard characters.
+Returns 0 if @code{str} and @code{wildstr} match.
+
+@item void get_date _A((string to, int timeflag));
+Get current date in a form ready for printing.
+
+@item void soundex _A((string out_pntr, string in_pntr))
+Makes @code{in_pntr} to a 5 char long string. All words that sound
+alike have the same string.
+
+@item int init_key_cache _A((ulong use_mem, ulong leave_this_much_mem));
+Use caching of keys in MISAM, PISAM, and ISAM.
+@code{KEY_CACHE_SIZE} is a good size.
+Remember to lock databases for optimal caching.
+
+@item void end_key_cache _A((void));
+End key caching.
+
+
+@node DBUG, protocol, mysys functions, Top
+@chapter DBUG Tags To Use
+
+Here is some of the tags we now use:
+(We should probably add a couple of new ones)
- int wild_compare _A((const char *str,const char *wildstr));
- - Compare if str matches wildstr. Wildstr can contain "*" and "?"
- as match-characters.
- Returns 0 if match.
+@table @code
+@item enter
+Arguments to the function.
- void get_date _A((string to,int timeflag));
- - Get current date in a form ready for printing.
+@item exit
+Results from the function.
- void soundex _A((string out_pntr, string in_pntr))
- - Makes in_pntr to a 5 chars long string. All words that sounds
- alike have the same string.
+@item info
+Something that may be interesting.
- int init_key_cache _A((ulong use_mem,ulong leave_this_much_mem));
- - Use cacheing of keys in MISAM, PISAM, and ISAM.
- KEY_CACHE_SIZE is a good size.
- - Remember to lock databases for optimal cacheing
+@item warning
+When something doesn't go the usual route or may be wrong.
- void end_key_cache _A((void));
- - End key-cacheing.
+@item error
+When something went wrong.
-@node protocol,,,
-@chapter MySQL client/server protocol
+@item loop
+Write in a loop, that is probably only useful when debugging
+the loop. These should normally be deleted when one is
+satisfied with the code and it has been in real use for a while.
+@end table
-Raw packet without compression
-==============================
+Some specific to mysqld, because we want to watch these carefully:
+
+@table @code
+@item trans
+Starting/stopping transactions.
+
+@item quit
+@code{info} when mysqld is preparing to die.
+
+@item query
+Print query.
+@end table
+
+
+@node protocol, , DBUG, Top
+@chapter MySQL Client/Server Protocol
+
+@menu
+* raw packet without compression::
+* raw packet with compression::
+* basic packets::
+* communication::
+* fieldtype codes::
+@end menu
+
+@node raw packet without compression, raw packet with compression, protocol, protocol
+@section Raw Packet Without Compression
+
+@example
-------------------------------------------------
| Packet Length | Packet no | Data |
| 3 Bytes | 1 Byte | n Bytes |
-------------------------------------------------
+@end example
3 Byte packet length
The length is calculated with int3store
@@ -506,13 +569,16 @@ n Byte data
The packet length can be recalculated with:
length = byte1 + (256 * byte2) + (256 * 256 * byte3)
-
-Raw packet with compression
-===========================
+
+@node raw packet with compression, basic packets, raw packet without compression, protocol
+@section Raw Packet With Compression
+
+@example
-----------------------------------------------------
| Packet Length | Packet no | Uncomp. Packet Length |
| 3 Bytes | 1 Byte | 3 Bytes |
-----------------------------------------------------
+@end example
3 Byte packet length
The length is calculated with int3store
@@ -521,14 +587,23 @@ Raw packet with compression
1 Byte packet no
3 Byte uncompressed packet length
-If compression is used the first 7 bytes of each paket
-is the header of the paket.
-
-Basic packets
-==============
-OK-packet
+If compression is used the first 7 bytes of each packet
+is the header of the packet.
+
+@node basic packets, communication, raw packet with compression, protocol
+@section Basic Packets
+
+@menu
+* ok packet::
+* error packet::
+@end menu
+
+@node ok packet, error packet, basic packets, basic packets
+@subsection OK Packet
+
For details see sql/net_pkg.cc
function send_ok
+@example
-------------------------------------------------
| Header | No of Rows | Affected Rows |
| | 1 Byte | 1-8 Byte |
@@ -539,6 +614,7 @@ OK-packet
| Messagetext |
| n Byte |
-------------------------------------------------
+@end example
Header
1 byte number of rows ? (always 0 ?)
@@ -549,7 +625,11 @@ OK-packet
1-8 bytes length of message
n bytes messagetext
-Error-packet
+
+@node error packet, , ok packet, basic packets
+@subsection Error Packet
+
+@example
-------------------------------------------------
| Header | Statuscode | Error no |
| | 1 Byte | 2 Byte |
@@ -557,7 +637,8 @@ Error-packet
| Messagetext | 0x00 |
| n Byte | 1 Byte |
-------------------------------------------------
-
+@end example
+
Header
1 byte status code (0xFF = ERROR)
2 byte error number (is only sent to new 3.23 clients.
@@ -565,9 +646,8 @@ Error-packet
1 byte 0x00
-
-The communication
-=================
+@node communication, fieldtype codes, basic packets, protocol
+@section Communication
> Packet from server to client
< Paket from client tor server
@@ -658,9 +738,10 @@ The communication
n data
-Fieldtype Codes:
-================
+@node fieldtype codes, , communication, protocol
+@section Fieldtype Codes
+@example
display_length |enum_field_type |flags
----------------------------------------------------
Blob 03 FF FF 00 |01 FC |03 90 00 00
@@ -679,7 +760,7 @@ Datetime 03 13 00 00 |01 0C |03 00 00 00
Timestamp 03 0E 00 00 |01 07 |03 61 04 00
Time 03 08 00 00 |01 0B |03 00 00 00
Date 03 0A 00 00 |01 0A |03 00 00 00
-
+@end example
@c The Index was empty, and ugly, so I removed it. (jcole, Sep 7, 2000)
diff --git a/Docs/manual.de.texi b/Docs/manual.de.texi
new file mode 100644
index 00000000000..dc9d0bf53dc
--- /dev/null
+++ b/Docs/manual.de.texi
@@ -0,0 +1,56081 @@
+\input texinfo @c -*-texinfo-*-
+@c Copyright 1997-2001 TcX AB, Detron HB und MySQL Finland AB
+@c
+@c *********************************************************
+@c Note that @node names are used on our Website.
+@c So do not change node names without checking
+@c Makefile.am und SitePages first.
+@c *********************************************************
+@c
+@c %**start of header
+
+@c there's a better way to do this.. i just don't know it yet
+@c sed will remove the "@c ifnusphere " to make this valid
+@c ifnusphere @set nusphere 1
+
+@setfilename mysql.de.info
+
+@c We want the types in the same index
+@syncodeindex tp fn
+
+@c Get version information. This file is generated by the Makefile!!
+@include include.texi
+
+@ifclear tex-debug
+@c This removes the black squares in the right margin
+@finalout
+@end ifclear
+
+@c Set background für HTML
+@set _body_tags BGCOLOR=silver TEXT=#000000 LINK=#101090 VLINK=#7030B0
+@c Set some style elements für the manual in HTML form. 'suggested'
+@c natural language colors: aqua, black, blue, fuchsia, gray, green,
+@c lime, maroon, navy, olive, purple, red, silver, teal, white, und
+@c yellow. From Steeve Buehler <ahr@YogElements.com>
+@set _extra_head <style> code {color:purple} tt {color:green} samp {color:navy} pre {color:maroon} </style>
+
+@settitle MySQL-Referenzhandbuch für Version @value{mysql_version}
+
+@c We want single-sided heading format, with chapters on new pages. To
+@c get double-sided format change 'on' below to 'odd'
+@ifclear nusphere
+@setchapternewpage on
+@end ifclear
+
+@ifset nusphere
+@setchapternewpage odd
+@end ifset
+
+@paragraphindent 0
+
+@ifset nusphere
+@smallbook
+@end ifset
+
+@c %**end of header
+
+@ifinfo
+@format
+START-INFO-DIR-ENTRY
+* mysql: (mysql). MySQL documentation.
+END-INFO-DIR-ENTRY
+@end format
+@end ifinfo
+
+@titlepage
+@sp 10
+@center @titlefont{MySQL-Referenzhandbuch}
+@sp 10
+@center Copyright @copyright{} 1997-2002 MySQL AB
+@c blank page after title page makes page 1 be a page front.
+@c also makes the back of the title page blank.
+@page
+@end titlepage
+
+@c Short contents, blank page, long contents.
+@c until i can figure out the blank page, no short contents.
+@c @shortcontents
+@c @page
+@c @page
+@contents
+
+@c This should be added. The HTML conversion also needs a MySQL version
+@c Anzahl somewhere.
+
+@iftex
+@c change this to double if you want formatting für double-sided
+@c printing
+@headings single
+
+@oddheading @thischapter @| @| @thispage
+@evenheading @thispage @| @| MySQL - Technische Referenz für Version @value{mysql_version}
+
+@end iftex
+
+
+@node Top, Introduction, (dir), (dir)
+@c German node Top
+
+@c @ifhtml
+@c <IMG SRC="Images/mysql-logo.gif">
+@c <!--Image doesn't exist. Can't find suitable replacement. (Matt) -->
+@c @end ifhtml
+
+@ifinfo
+Das ist das Handbuch für das MySQL-Datenbanksystem. Diese Version gehört
+zur MySQL-Version @value{mysql_version}. Sie finden ein Handbuch zu jeder
+älteren Version von MySQL in der Binär- oder Quelldistribution der
+entsprechenden Version.
+@end ifinfo
+
+
+
+@menu
+* Introduction::
+* Deutsch::
+* Installing::
+* Tutorial::
+* MySQL Database Administration::
+* MySQL Optimisation::
+* Reference::
+* Table types::
+* Clients::
+* Extending MySQL::
+* Problems::
+* Benutzer::
+* MySQL-Benutzung durch Kunden::
+* Contrib::
+* Credits::
+* News::
+* Porting::
+* Environment variables::
+* Regexp::
+* GPL license::
+* LGPL license::
+* Function Index::
+* Concept Index::
+@end menu
+
+@node Introduction, Deutsch, Top, Top
+@c German node Einführung
+@chapter Allgemeine Informationen über MySQL
+
+@cindex Überblick
+@cindex Allgemeine Informationen
+
+MySQL ist ein sehr schneller und robuster, Multi-Thread und Multi-User
+SQL-Datenbank-Server (SQL = Structured Query Language, strukturierte
+Abfrage-Sprache).
+Die Einsatzgebiete des MySQL Server liegen in Hochleistungsapplikationen
+und in der Einbindung in weit verbreitete Massen-Software.
+@code{MySQL} ist eine Schutzmarke von @code{MySQL AB}.
+
+Die MySQL Software steht unter einer @code{Doppellizenz}. Sie
+können sie entweder frei im Sinne der @code{GNU GENERAL PUBLIC LICENSE}
+(@uref{http://www.gnu.org/licenses/}) verwenden, oder Sie erwerben eine
+komerzielle Lizenz, wenn Sie nicht durch die Restriktionen der GPL
+gebunden sein wollen.
+@xref{Lizenzpolitik}.
+
+@uref{http://www.mysql.com/, die MySQL Homepage}
+enthält die letzten Informationen über MySQL.
+
+Die folgende Liste beschreibt nützliche Teile des Handbuchs.
+
+@itemize @bullet
+@item
+Informationen zu dem Unternehmen hinter MySQL: @ref{What is MySQL AB}.
+
+@item
+Eine Diskussion der Fähigkeiten von MySQL: @ref{Features}.
+
+@item
+Installationsanweisungen: @ref{Installing}.
+
+@item
+Tipps zur Portierung von MySQL auf neue Architekturen oder Betriebssysteme:
+@ref{Porting}.
+
+@item
+Informationen zum Upgrade von einem Release der Version 3.23:
+@ref{Upgrading-from-3.23}.
+
+@item
+Informationen zum Upgrade von einem Release der Version 3.22:
+@ref{Upgrading-from-3.22}.
+
+@item
+Einführungs-Tutorial zu MySQL: @ref{Tutorial}.
+
+@item
+SQL-Beispiele und Informationen zu Benchmarks befinden sich im
+Benchmark-Verzeichnis (@file{sql-bench} in der Distribution).
+
+@item
+Die Geschichte neuer Features und Bugfixes: @ref{News}.
+
+@item
+@c German FIX was @nqs{Feature-Probleme}; no idea what @nqs is??
+Eine Liste bekannter Bugs und Feature-Probleme: @ref{Bugs}.
+
+@item
+Zukunftspläne: @ref{TODO}.
+
+@item
+Eine Liste aller Beteiligten, die zu diesem Projekt beitrugen: @ref{Credits}.
+@end itemize
+
+@strong{WICHTIG:}
+
+Berichte zu Fehlern (oft Bugs genannt) sowie Fragen und Bemerkungen sollten
+an die Mailingliste geschickt werden: @email{mysql@@lists.mysql.com}.
+@xref{Bug reports}.
+Das @code{mysqlbug} Skript sollte benutzt werden, um Fehlerberichte zu
+erzeugen.
+@c FIX! RPMs are also binary
+Bei Quelltext-Distributionen liegt das @code{mysqlbug} Skript im
+@file{scripts} Verzeichnis. Bei Binärdistributionen liegt @code{mysqlbug}
+im @file{bin} Verzeichnis. Wenn Sie einen empfindlichen Sicherheits-Bug in
+MySQL gefunden haben, sollten Sie eine E-Mail an
+@email{security@@mysql.com} schicken.
+
+@cindex Fehler, berichten
+@cindex Berichten, Fehler
+@cindex Mailing-Listen-Adresse
+@cindex @code{mysqlbug}-Skript, Speicherort
+
+
+
+
+@node Deutsch, Installing, Introduction, Top
+@c German node <no English equivalent>
+@chapter Vorbemerkungen zum deutschen Handbuch
+
+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:
+
+@itemize @bullet
+@item
+In diesem Handbuch wird nicht geupdated, sondern aktualisiert.
+@item
+Eine MySQL-Distribution wird nicht gedownloaded, sondern herunter
+geladen.
+@item
+Und Transaktionen werden nicht gerollbackt, sondern zurückgerollt.
+@end itemize
+
+Womit wir auch schon bei der besonderen Herausforderung wären: Jeder,
+der sich mit Transaktionen auskennt, weiß, dass beim Fehlschlagen einer
+solchen ein Rollback-Befehl ausgeführt wird. Dieses Hauptwort ins
+Deutsche zu übersetzen, würde zum Verständnis wenig beitragen - im
+Gegenteil.
+
+Damit bleiben alle technischen Fachbegriffe, die sich so und nicht
+anders etabliert haben, englisch:
+
+@itemize @bullet
+@item
+Ein SQL-Statement wird nicht als "Erklärung in der Strukturierten
+AbfrageSprache (SAS)" übersetzt.
+@item
+Abkürzungen wie TCP/IP werden nicht zu ÜSP/ZP
+(ÜbertragungsSteuerungsProtokoll/ZwischennetzProtokoll).
+@item
+Ein Client bleibt ein Client, und ein Server ein Server.
+@end itemize
+
+Die Fallstricke einer Übersetzung stecken allerdings in den Details:
+
+@itemize @bullet
+@item
+Jeder SQL-Kenner weiß, was eine "query" ist. In diesem Handbuch ist
+das eine Anfrage.
+@item
+Gibt es Probleme bei der Übermittlung einer Anfrage, kann es sein,
+dass eine Zeitüberschreitung eintritt. Der Profi hätte wahrscheinlich
+nach "Timeout" gesucht.
+@item
+Manche Dinge sind einfacher: Ein "string" ist eine Zeichenkette
+(obwohl für Profis vielleicht ungewohnt), ein "hex value" ein
+hexadezimaler Wert.
+@end itemize
+
+Richtig spannend wird die Übersetzung bei Wörtern, die in der deutschen
+Fachsprache zumeist englisch verwendet werden, obwohl es passende
+deutsche Entsprechungen gibt:
+
+@itemize @bullet
+@item
+Im Hauptspeicher ("RAM") zwischengespeicherte Daten werden auf die
+Festplatte zurückgeschrieben. Im Englischen heißt das "flushed to
+disk", und im Deutschen werden die Daten häufig "geflushed".
+@item
+Daten werden zwischengespeichert ("gecached").
+@item
+Speicher wird zugewiesen. Man kann auch "alloziert" sagen, was dem
+englischen "allocated" näher kommt.
+@end itemize
+
+Alle diese Entsprechungen, bei denen die deutsche Sprache eher in
+Vergessenheit geraten ist, wurden zweisprachig aufgenommen. Beispiele:
+
+@itemize @bullet
+@item
+Alle Daten werden zwischen Anfragen auf die Festplatte zurück
+geschrieben (flush).
+@item
+Aktualisieren Sie (Update), wenn alles in Ordnung ist.
+@item
+Auf eine höhere Version von MySQL aktualisieren (Upgrade) ...
+@end itemize
+
+Gelegentlich wird auch in diesem Handbuch die "Performance getuned",
+neue "Features" eines MySQL-"Release" werden beschrieben usw. Anregungen
+für eine weiter gehende Eindeutschung nimmt der Übersetzer gern
+entgegen. Insbesondere gilt das auch für Hinweise zur Verkürzung
+deutscher Ausdrücke. Beispielsweise heißt "case sensitive" (14
+Buchstaben) im Handbuch "abhängig von der verwendeten
+Groß-/Kleinschreibung" (44 Buchstaben).
+
+Letzter Punkt: Die Übersetzung erfolgte in äußerst enger Anlehnung an
+das englischsprachige Original. Nichts wurde hinzugefügt (ausser diesem
+Vorwort), geändert oder weggelassen (Ausnahme: die Geschichte der
+Änderungen (ChangeLog) vor Version 3.23). Es liegt in der Natur der
+Dinge, dass weder Original noch Übersetzung frei von Fehlern sind
+(obwohl wir das anstreben). Berichten Sie bitte Übersetzungsfehler,
+stilistische "Bugs", die das Verständnis beeinträchtigen und sonstige
+Anmerkungen zur Übersetzung direkt an:
+
+@c German FIX added escape @@ in e-mail address.
+Stefan Hinz, @email{handbuch@@mysql.com}
+
+Berlin, im Februar 2002
+
+Stefan Hinz, @uref{http://iConnect.de,iConnect GmbH Berlin}
+
+
+@menu
+* Manual-info::
+* What-is::
+* What is MySQL AB::
+* Licensing and Support::
+* MySQL 4.0 In A Nutshell::
+* MySQL Information Sources::
+* Compatibility::
+* TODO::
+* Comparisons::
+@end menu
+
+@node Manual-info, What-is, Deutsch, Deutsch
+@c German node Handbuch-Informationen
+@section Über dieses Handbuch
+
+@cindex Speicherort des Online-Handbuchs
+@cindex Handbuch, Online-Speicherort
+
+Das ist ein Referenzhandbuch. Es enthält keine allgemeinen Anleitungen zu
+SQL oder relationalen Datenbankkonzepten.
+@c German FIX these references don't exist:
+@c Wenn Sie allgemeine Informationen über SQL suchen,
+@c finden Sie diese hier: @ref{SQL allgemein}.
+@c Bücher, die sich speziell mit MySQL beschäftigen,
+@c finden Sie hier: @ref{MySQL-Bücher}.
+
+Da die MySQL Datenbank Software eine laufende Weiterentwicklung erfährt, wird
+das Handbuch regelmäßig aktualisiert.
+Die jeweils aktuellste Version dieses Handbuchs befindet sich unter
+@uref{http://www.mysql.com/documentation/}.
+Dieses Handbuch ist gegenwärtig verfügbar in Texinfo, als Klartext
+(plain text), Info, HTML, PostScript und PDF. Das Primärdokument ist die
+Texinfo-Datei.
+Die HTML-Version wird automatisch produziert, indem eine modifizierte
+Version von @code{texi2html} benutzt wird. Die Klartext- und Info-
+Versionen werden mit @code{makeinfo} hergestellt. Die PostScript-Version
+wird mit @code{texi2dvi} und @code{dvips} produziert. Die PDF-Version
+wird mit @code{pdftex} hergestellt.
+
+Wenn Sie Schwierigkeiten haben, Informationen zu finden, beachten Sie bitte
+auch die durchsuchbare PHP Version des Handbuchs unter
+@uref{http://www.mysql.com/doc/}.
+
+Wenn Sie Vorschläge für Hinzufügungen oder Korrekturen dieses Handbuchs
+haben, schicken Sie sie bitte an das Handbuch-Team:
+@email{docs@@mysql.com}.
+
+@cindex Handbuch, verfügbare Formate
+@cindex Texinfo
+
+Dieses Handbuch wurde geschrieben und wird gewartet von David Axmark,
+Michael (Monty) Widenius, Jeremy Cole, und Paul DuBois. Andere
+Kontributoren sind unter @ref{Credits} aufgelistet.
+Die deutsche Übersetzung stammt von Stefan Hinz. Für die
+Aktualität ist Jan Lehnardt zuständig.
+
+Das Copyright (2002) für dieses liegt bei der schwedischen Firma
+@code{MySQL AB}. @xref{Copyright}.
+
+
+@menu
+* Manual conventions::
+@end menu
+
+@node Manual conventions, , Manual-info, Manual-info
+@c German node Handbuch-Konventionen
+@subsection Konventionen in diesem Handbuch
+
+Dieses Handbuch benutzt bestimmte typographische Konventionen:
+
+@cindex Handbuch, typografische Konventionen
+@cindex Typografische Konventionen
+@cindex Konventionen, typografische
+
+@table @asis
+@item @code{constant}
+Schriftart gleicher Breite (nicht-proportionale Schrift) wird für
+Befehle und Optionen benutzt, für SQL-Statements, Datenbank-, Tabellen-
+und Spaltennamen, für C- und PERL-Code und für Umgebungsvariablen.
+Beispiel: ``Um festzustellen, wie @code{mysqladmin} funktioniert, rufen
+Sie den Befehl mit der @code{--help} Option auf.''
+
+@item @file{filename}
+Schriftart gleicher Breite, die von Anführungszeichen umgeben ist, wird
+für Datei- und Pfadnamen benutzt. Beispiel: ``Die Distribution wird im
+Verzeichnis @file{/usr/local/} installiert.''
+
+@item @samp{c}
+Schriftart gleicher Breite, die von Anführungszeichen umgeben ist, wird
+auch benutzt um Zeichenfolgen anzuzeigen. Beispiel: ``Um ein
+Platzhalterzeichen einzugeben, benutzen Sie das @samp{%} Zeichen.''
+
+@item @emph{italic}
+Kursivschrift wird für Hervorhebungen verwendet, @emph{wie in diesem
+Beispiel}.
+
+@item @strong{boldface}
+Fettschrift wird für Namen von Zugriffsrechten verwendet (zum Beispiel:
+``Gewähren Sie das @strong{process} Zugriffsrecht nicht leichtfertig'')
+und gelegentlich, um @strong{besonders starke Hervorhebungen} zu kennzeichnen.
+@end table
+
+Wenn Befehle gezeigt werden, die durch ein bestimmtes Programm
+ausgeführt werden sollen, wird dieses Programm durch einen Prompt
+(Eingabeaufforderung) vor dem Befehl angezeigt. Der @code{shell>} Prompt
+zum Beispiel zeigt an, dass Sie den Befehl von Ihrer Login-Shell aus
+ausführen sollen. @code{mysql>} zeigt an, dass Sie den Befehl vom
+@code{mysql} Client-Programm aus ausführen sollen:
+
+@example
+shell> geben sie hier ein shell-kommando ein
+mysql> geben sie hier ein mysql-kommando ein
+@end example
+
+Shell-Befehle werden mit der Bourne-Shell-Syntax dargestellt. Wenn Sie
+eine @code{csh}-Shell benutzen, müssen die Befehle evtl. etwas anders
+eingegeben werden. Das folgende Beispiel zeigt, wie mit der Bourne-Shell eine
+Umgebungsvariable gesetzt wird und anschließend ein Befehl abgesetzt
+wird:
+
+@example
+shell> VARNAME=wert irgendein_befehl
+@end example
+
+@cindex Shell-Syntax
+@cindex Befehlssyntax
+
+Um @code{csh} auszuführen, würden Sie folgende Sequenz ausführen:
+
+@example
+shell> setenv VARNAME wert
+shell> irgendein_befehl
+@end example
+
+Oft müssen Datenbank-, Tabellen- und Spaltennamen in konkreten Befehlen
+ersetzt werden. Um anzuzeigen, dass eine solche Ersetzung notwendig ist,
+benutzt dieses Handbuch @code{db_name}, @code{tbl_name} und
+@code{col_name}. Sie könnten zum Beispiel folgendes Statement sehen:
+
+@example
+mysql> SELECT spalten_name FROM datenbank_name.tabellen_name;
+@end example
+
+Wenn Sie ein ähnliches Statement eingeben wollen, müssen Sie Ihre
+eigenen Datenbank-, Tabellen- und Spaltennamen eingeben, zum Beispiel
+wie folgt:
+
+@example
+mysql> SELECT autor_name FROM bibliothek.autorenliste;
+@end example
+
+SQL-Statements können in Groß- und Kleinschreibung geschrieben werden.
+Wenn dieses Handbuch SQL-Statements darstellt, wird Großschreibung
+verwendet, um spezielle Schlüsselworte in diesem Kontext hervorzuheben.
+Kleinschreibung wird für den Rest des Statements verwendet. Folgendes
+könnten Sie im Kontext des @code{SELECT} Statements sehen:
+
+@example
+mysql> SELECT count(*) FROM tabellen_name;
+@end example
+
+Im Kontext der @code{COUNT()} Funktion hingegen könnte dasselbe
+Statement wie folgt geschrieben werden:
+
+@example
+mysql> select COUNT(*) from tabellen_name;
+@end example
+
+Wenn keine besondere Hervorhebung beabsichtigt wird, werden alle
+Schlüsselworte in Großschreibung dargestellt.
+
+In Syntax-Beschreibungen werden eckige Klammern (@samp{[} und @samp{]})
+benutzt, um wahlfrei (optionale) Wörter oder Klauseln anzuzeigen:
+
+@example
+DROP TABLE [IF EXISTS] tabellen_name
+@end example
+
+Wenn ein Syntaxelement aus einer Anzahl von Alternativen besteht, werden
+die Alternativen durch gerade Striche (@samp{|}) voneinander getrennt.
+Wenn genau ein Element aus einer Anzahl von Möglichkeiten ausgewählt
+werden (@strong{kann}), werden die Alternativen mit eckigen Klammern
+aufgelistet (@samp{[} und @samp{]}):
+
+@example
+TRIM([[BOTH | LEADING | TRAILING] [remstr] FROM] str)
+@end example
+
+Wenn genau ein Element aus einer Anzahl von Möglichkeiten ausgewählt
+werden @strong{muss}, werden die Alternativen innerhalb geschweifter
+Klammern aufgelistet (@samp{@{} und @samp{@}}):
+
+@example
+@{DESCRIBE | DESC@} tbl_name @{col_name | wild@}
+@end example
+
+
+@node What-is, What is MySQL AB, Manual-info, Deutsch
+@c German node Was ist MySQL?
+@section Was ist MySQL?
+
+@cindex MySQL, Definition
+@cindex MySQL, Einführung
+
+
+MySQL, die populärste Open Source SQL-Datenbank, wird von MySQL AB zur
+Verfügung gestellt. MySQL AB ist ein kommerzielles Unternehmen, dessen
+Geschäft darin besteht, Serviceleistungen rund um die MySQL-Datenbank
+zur Verfügung zu stellen. @xref{What is MySQL AB}.
+
+@table @asis
+
+@item MySQL ist ein Datenbank-Managementsystem.
+
+Eine Datenbank ist eine strukturierte Sammlung von Daten. Das kann alles
+sein - von einer einfachen Einkaufsliste über eine Bildergalerie bis zu
+riesigen Informationsmengen in einem Unternehmensnetzwerk. Um Daten zu
+einer Computer-Datenbank hinzuzufügen, auf sie zuzugreifen und sie zu
+verarbeiten, benötigen Sie ein Datenbank-Managementsystem wie MySQL. Weil
+Computer sehr gut darin sind, große Datenmengen zu handhaben, spielt
+Datenbank-Management eine zentrale Rolle im Computer-Bereich, sowohl bei
+Anwendungen, die allein laufen (Stand-Alone-Utilities) als auch als Teil
+anderer Anwendungen.
+@cindex Datenbanken, Definition
+
+@item MySQL ist ein relationales Datenbank-Managementsystem.
+
+Eine relationale Datenbank speichert Daten in separaten Tabellen,
+anstatt sie alle in einem einzigen großen Speicherraum unterzubringen.
+Hierdurch werden hohe Geschwindigkeit und Flexibilität erreicht. Die
+Tabellen werden durch definierte Beziehungen verbunden (Relationen), was
+es möglich macht, Daten aus verschiedenen Tabellen auf Nachfrage zu
+kombinieren. Der SQL-Teil von MySQL steht für "Structured Query
+Language" (strukturierte Abfragesprache) - die verbreitetste
+standardisierte Sprache für Datenbankzugriffe.
+
+@cindex Relationale Datenbanken, Definition
+@cindex SQL, Definition
+@item MySQL ist Open-Source-Software.
+
+Open Source bedeutet, dass es für jeden möglich ist, solche Software zu
+benutzen und zu verändern. Jeder kann MySQL aus dem Internet herunter
+laden und benutzen, ohne irgend etwas zu bezahlen. Jeder, der daran
+interessiert ist, kann den Quelltext studieren und den eigenen
+Bedürfnissen entsprechend verändern. MySQL benutzt die GPL (GNU
+General Public License) @uref{http://www.gnu.org}, um festzulegen, was
+Sie mit der Software tun dürfen und was Sie nicht tun dürfen, abhängig
+von unterschiedlichen Situationen. Wenn Ihnen die GPL Probleme bereitet
+oder wenn Sie MySQL in eine kommerzielle Anwendung einbetten müssen,
+können Sie eine kommerziell lizensierte Version von uns erwerben.
+
+@cindex Open Source, Definition
+@cindex General Public License
+
+@item Warum sollten Sie MySQL benutzen?
+
+MySQL ist sehr schnell, zuverlässig und leicht zu benutzen. Wenn Sie
+nach diesen Eigenschaften suchen, sollten Sie MySQL ausprobieren. MySQL
+besitzt eine ganze Reihe praktischer Features, die in enger Kooperation
+mit unseren Benutzern entwickelt wurden. Einen Performance-Vergleich
+zwischen MySQL und einigen anderen Datenbank-Managementsystemen finden
+Sie auf unserer Benchmark-Seite.
+@xref{MySQL Benchmarks}.
+
+MySQL wurde ursprünglich entwickelt, um sehr große Datenbanken
+handhaben zu können, und zwar sehr viel schneller als existierende
+Lösungen. Es wurde mehrere Jahre in höchst anspruchsvollen
+Produktionsumgebungen eingesetzt. Heutzutage bietet MySQL eine
+umfangreiche Reihe sehr nützlicher Funktionen. Connectivity,
+Geschwindigkeit und Sicherheit machen MySQL äußerst geeignet, um auf
+Datenbanken über das Internet zuzugreifen.
+
+@item Die technischen Features von MySQL
+
+Weiter führende technische Informationen finden Sie unter
+@ref{Reference}. MySQL ist ein Client-Server-System, das aus einem
+multi-thread SQL-Server besteht, der unterschiedliche Backends,
+verschiedene Client-Programme und -Bibliotheken, Verwaltungswerkzeuge
+und etliche Programmschnittstellen unterstützt.
+
+Wir stellen MySQL auch als multi-thread Bibliothek zur Verfügung, die
+Sie mit Ihren Anwendungen verknüpfen können, um ein kleineres,
+schnelleres und leichter zu bedienendes Produkt zu erhalten.
+
+@item MySQL stellt beigesteuerte (contributed) Software in großer Menge
+zur Verfügung.
+
+Es ist sehr wahrscheinlich, dass Ihre Lieblingsanwendung oder -sprache
+bereits MySQL unterstützt.
+
+@end table
+
+@cindex Aussprache, MySQL
+@cindex MySQL, Aussprache
+@cindex Ziele von MySQL
+Offiziell wird MySQL 'Mai Ess Ku Ell' ausgesprochen (nicht 'Mai
+Siekwel'). Wir vermeiden allerdings, Leute zu korrigieren, die
+Mai-Siekwel sagen.
+
+@cindex MySQL-Geschichte
+@cindex Geschichte von MySQL
+@cindex MySQL, Name
+@cindex My, Ursprung
+
+Wir fingen ursprünglich mit der Intention an, den @code{mSQL}-Code zu
+benutzen, um unsere eigenen Tabellen anzusprechen, wobei wir unsere
+eigenen schnellen Low-Level-Routinen (ISAM) benutzten. Nach einigem
+Testen gelangten wir allerdings zur Überzeugung, dass @code{mSQL} weder
+schnell noch flexibel genug wäre, um unsere Anforderungen abzudecken.
+Dies resultierte in einer neuen SQL-Schnittstelle zu unserer Datenbank,
+allerdings mit fast derselben API-Schnittstelle, wie sie @code{mSQL}
+benutzt. Diese API wurde gewählt, weil sie es erlaubte, Code von
+Drittanbietern einfach zu portieren. Die Entstehung des Namens MySQL ist
+nicht völlig geklärt. Unser Basis-Verzeichnis und eine große Anzahl
+unserer Bibliotheken und Werkzeuge hatten immer schon das Präfix ``my''
+während mehr als 10 Jahren. Wie auch immer, auch Montys Tochter (einige
+Jahre jünger) heißt My. Welcher der beiden Umstände MySQL den Namen
+gab, ist immer noch ein Rätsel, sogar für uns.
+
+
+@menu
+* Features::
+* Stability::
+* Table size::
+* Year 2000 compliance::
+@end menu
+
+@node Features, Stability, What-is, What-is
+@c German node Features
+@subsection Die wichtigsten Features von MySQL
+
+@cindex Haupt-Features von MySQL
+@cindex Features von MySQL
+
+Die folgende Liste beschreibt einige wichtige Charakteristika von MySQL:
+
+@c This list is too technical und should be divided into one feature
+@c list comparable to commercial competition und a very technical on
+@c with max limits (from crash-me) und so on.
+@itemize @bullet
+@item
+Voll multi-thread unter Benutzung von Kernel-Threads. Das bedeutet, dass
+Sie sehr einfach mehrere Prozessoren benutzen können, falls verfügbar.
+
+@item
+C-, C++-, Eiffel-, Java-, Perl-, PHP-, Python- und Tcl-APIs. @xref{Clients}.
+
+@item
+Läuft auf vielen verschiedenen Plattformen. @xref{Which OS}.
+
+@item
+Viele Spaltentypen: vorzeichenbehaftete / vorzeichenlose Ganzzahlen
+(Integer), die 1, 2, 3, 4 und 8 Byte lang sind, @code{FLOAT},
+@code{DOUBLE}, @code{CHAR}, @code{VARCHAR}, @code{TEXT}, @code{BLOB},
+@code{DATE}, @code{TIME}, @code{DATETIME}, @code{TIMESTAMP},
+@code{YEAR}, @code{SET}, und @code{ENUM} Typen.
+@xref{Column types}.
+
+@item
+Sehr schnelle Joins durch Benutzung eines optimierten Multi-Joins in
+einem Durchgang (one-sweep multi-join).
+
+@item
+Volle Operator- und Funktionsunterstützung in @code{SELECT}- und
+@code{WHERE}-Teilen von Anfragen. Beispiel:
+
+@example
+mysql> SELECT CONCAT(vorname, " ", nachname) FROM tabellen_name
+ WHERE einkommen/dependents > 10000 AND age > 30;
+@end example
+
+@item
+SQL-Funktionen sind durch eine hoch optimierte Klassenbibliothek
+implementiert und sollten so schnell sein, wie es geht! Üblicherweise
+gibt es überhaupt keine Speicherzuordnung (memory allocation) nach der
+Initialisierung von Anfragen.
+
+@item
+Volle Unterstützung für SQL-@code{GROUP BY} und @code{ORDER BY}-
+Klauseln. Unterstützung für Gruppierungsfunktionen (@code{COUNT()},
+@code{COUNT(DISTINCT ...)}, @code{AVG()}, @code{STD()}, @code{SUM()},
+@code{MAX()} und @code{MIN()}).
+
+@item
+Unterstützung für @code{LEFT OUTER JOIN} und @code{RIGHT OUTER JOIN} mit
+ANSI-SQL und ODBC-Syntax.
+
+@item
+Sie können Tabellen aus unterschiedlichen Datenbanken in ein und
+derselben SQL-Anfrage benutzen (ab Version 3.22).
+
+@item
+Ein System von Zugriffsberechtigungen und Passwörtern, das sehr flexibel
+und sicher ist, und das Host-basierende Verifizierung erlaubt.
+Passwörter sind sicher, weil jeder Passwort-Verkehr verschlüsselt wird,
+wenn Sie sich mit einem Server verbinden.
+
+@item
+ODBC (Open-DataBase-Connectivity) Unterstützung für Win32 (mit
+Quelltext). Alle ODBC 2.5 Funktionen und viele weitere. Sie können zum
+Beispiel MS Access benutzen, um sich mit Ihrem MySQL-Server zu
+verbinden. @xref{ODBC}.
+
+@item
+Sehr schnelle B-tree disk Tabellen mit Index-Kompression.
+
+@item
+Bis zu 32 Indexe pro Tabelle erlaubt. Jeder Index kann aus 1 bis 16
+Spalten oder Teilen von Spalten bestehen. Die maximale Indexlänge
+beträgt 500 Bytes (das ändert sich evtl., wenn MySQL kompiliert wird).
+Ein Index kann das Präfix eines @code{CHAR}- oder @code{VARCHAR}-Felds
+benutzen.
+
+@item
+Datensätze fester und variabler Länge.
+
+@item
+Im Arbeitsspeicher gehaltene Hash-Tabellen, die als temporäre Tabellen
+benutzt werden.
+
+@item
+Kann große Datenbanken handhaben. Wir selbst benutzen MySQL bei einigen
+Datenbanken, die 50 Mio. Datensätze haben und wir kennen Benutzer, die
+MySQL mit 60.000 Tabellen und etwa 5 Milliarden Zeilen benutzen.
+
+@item
+Alle Spalten können Vorgabewerte (Defaults) haben. Sie können @code{INSERT}
+benutzen, um eine Untermenge der Tabellenspalten mit Werten zu
+bestücken. Diejenigen Spalten, die nicht explizit angesprochen werden,
+werden auf ihre Vorgabewerte gesetzt.
+
+@item
+Benutzt GNU Automake, Autoconf und Libtool aus Portabilitätsgründen.
+
+@item
+Geschrieben in C und C++. Getestet mit großen Anzahl verschiedener
+Compiler.
+
+@item
+Ein sehr schnelles Thread-basierendes Speicherzuordnungs-System (memory
+allocation system).
+
+@item
+Keine Speicherlecks (memory leaks). MySQL wurde mit Purify getestet,
+einem kommerziellen Werkzeug zur Entdeckung von Speicherlecks.
+
+@item
+Beinhaltet @code{myisamchk}, ein sehr schnelles Dienstprogramm zur Überprüfung,
+Optimierung und Reparatur von Tabellen. Die gesamte Funktionalität von
+@code{myisamchk} steht auch über die SQL-Schnittstelle zur Verfügung.
+@xref{MySQL Database Administration}.
+
+@item
+Volle Unterstützung für mehrere unterschiedliche Zeichensätze, incl. ISO-
+8859-1 (Latin1), big5, ujis und weitere. So sind zum Beispiel die
+skandinavischen Zeichen `@ringaccent{a}', `@"a' und `@"o' in Tabellen-
+und Spaltennamen erlaubt.
+
+@item
+Alle Daten werden mit dem ausgewählten Zeichensatz gespeichert. Alle
+Vergleiche für normale Zeichenkettenvergleiche sind unabhängig von
+Groß- und Kleinschreibung.
+
+@item
+Die Sortierung ist abhängig vom gewählten Zeichensatz (schwedisch als
+Vorgabe). Das kann beim Start des MySQL-Servers geändert werden. Um
+beispielsweise eine sehr fortgeschrittene Sortierung zu sehen, sehen Sie
+sich den tschechischen Sortier-Code an. MySQL unterstützt viele
+unterschiedliche Zeichensätze, die bei der Kompilierung und während der
+Laufzeit festgelegt werden können. Der neue Zeichensatz 'latin_de' sorgt
+für eine korrekte deutsche Sortierreihenfolge.
+
+@item
+Aliase auf Tabellen und Spalten sind erlaubt, wie im SQL92-Standard
+festgelegt.
+
+@item
+@code{DELETE}, @code{INSERT}, @code{REPLACE} und @code{UPDATE} geben die
+Anzahl der Zeilen zurück, die geändert wurden (bzw. betroffen sind). Es
+ist statt dessen auch möglich, die Anzahl der übereinstimmenden Zeilen
+zurückzugeben, indem beim Verbindungsstart zum Server ein entsprechendes
+Flag gesetzt wird.
+
+@item
+Funktionsnamen kollidieren nicht mit Tabellen- oder Spaltennamen.
+@code{ABS} zum Beispiel ist ein gültiger Spaltenname. Die einzige
+Einschränkung besteht drin, dass in einem Funktionsaufruf keine
+Leerzeichen zwischen Funktionsname und der öffnenden runden Klammer, die
+diesem folgt @samp{(}, erlaubt ist. @xref{Reserved words}.
+
+@item
+Alle MySQL-Programme können mit der @code{--help} oder @code{-?} Option
+aufgerufen werden, um Online-Hilfe zu erhalten.
+
+@item
+Der Server kann Clients Fehlermeldungen in verschiedenen Sprachen zur
+Verfügung stellen.
+@xref{Languages}.
+
+@item
+Clients können sich mit dem MySQL-Server über TCP/IP Sockets,
+Unix Sockets (Unix) oder Named Pipes (NT) verbinden.
+
+@item
+Der MySQL-spezifische @code{SHOW}-Befehl kann benutzt werden, um
+Informationen über Datenbanken, Tabellen und Indexe zu erhalten. Der
+@code{EXPLAIN}-Code kann benutzt werden um festzustellen, wie der
+Optimierer eine Anfrage auflöst.
+@end itemize
+
+
+@node Stability, Table size, Features, What-is
+@c German node Stabilität
+@subsection Wie stabil ist MySQL?
+
+@cindex Stabilität
+
+Dieser Abschnitt beschäftigt sich mit den Fragen ``Wie stabil ist
+MySQL?'' und ``Kann ich mich auf MySQL bei diesem Projekt verlassen?''
+Wir werden versuchen, einige Dinge klar zu stellen und einige der
+wichtigeren Fragen zu beantworten, die offensichtlich viele Leute
+beschäftigen. Dieser Abschnitt wurde aus Informationen zusammen
+gestellt, die aus der Mailing-Liste gesammelt wurden (die sehr aktiv
+beim Berichten von Bugs ist).
+
+Bei TcX funktioniert MySQL ohne jegliche Probleme in unseren Projekten
+seit Mitte 1996. Als MySQL einer breiteren Öffentlichkeit zugänglich
+gemacht wurde, fiel uns auf, dass es einige Teile von ``ungetestetem
+Code'' gab, die schnell von neuen Benutzern gefunden wurden, die
+Anfragen machten, die von unseren eigenen abwichen. Seitdem hat jedes
+neue Release weniger Portabilitätsprobleme als das vorhergehende (obwohl
+jedes viele neue Features hat).
+
+Jedes Release von MySQL war benutzbar. Probleme gab es nur, wenn
+Benutzer anfingen, Code aus den ``Grauzonen'' zu benutzen. Natürlich
+wissen Benutzer von ausserhalb nicht, was diese Grauzonen sind, daher
+versucht dieser Abschnitt, die momentan bekannten aufzuzeigen. Die
+Beschreibungen hier beziehen sich auf Version 3.23 von MySQL. Alle
+bekannten und berichteten Bugs werden in der letzten Version behoben,
+mit Ausnahme der Bugs, die im Bugs-Abschnitt aufgelistet sind, was Dinge
+sind, die auf das Design zurückzuführen sind. @xref{Bugs}.
+
+MySQL ist in mehrfachen Ebenen (Layers) und verschiedenen unabhängigen
+Modulen geschrieben. Diese Module sind im Folgenden aufgeführt, wobei
+angezeigt wird, wie gut getestet jedes von ihnen ist:
+
+@cindex Module, Auflistung
+
+@table @strong
+@item Der ISAM Tabellen-Handler --- stabil
+Dieser verwaltet Speicherung und Abfrage aller Daten in MySQL Version
+3.22 und früher. In allen Releases von MySQL gab es nicht einen einzigen
+(berichteten) Bug in diesem Code. Die einzige Möglichkeit, eine
+zerstörte (korrumpierte) Tabelle zu erhalten, besteht darin, den Server
+mitten während eines Updates zu killen. Selbst dadurch ist es
+unwahrscheinlich, dass Daten unwiederbringlich zerstört werden, denn
+alle Daten werden zwischen Anfragen auf die Festplatte zurück
+geschrieben (flush). Es hat nicht einen einzigen Bug-Bericht gegeben, in
+dem von verlorenen Daten aufgrund von MySQL-Bugs berichtet wurde.
+
+@cindex ISAM-Tabellen-Handler
+@cindex Speicherung, Daten
+@cindex Abfrage, Daten
+@cindex Daten, ISAM-Tabellen-Handler
+
+@item Der MyISAM Tabellen-Handler --- stabil
+Dieser wurde in MySQL Version 3.23 hinzu gefügt. Er basiert zum großen
+Teil auf dem ISAM Tabellen-Code, hat aber eine Menge neuer und sehr
+nützlicher Features.
+
+@item Der Parser und lexikalische Analysator --- stabil
+Es hat seit sehr langer Zeit keinen einzigen berichteten Bug in diesem
+System gegeben.
+
+@item Der C Client-Code --- stabil
+Keine bekannten Probleme. Im frühen 3.20 Release gab es einige
+Einschränkungen hinsichtlich der Größe des Sende- / Empfangs-Puffers
+(buffer size). Ab Version 3.21 ist die Puffergröße jetzt dynamisch, bis
+zu einem Vorgabewert von 16 M.
+
+@item Standard-Client-Programme --- stabil
+Dies beinhaltet @code{mysql}, @code{mysqladmin}, @code{mysqlshow},
+@code{mysqldump} und @code{mysqlimport}.
+
+@item Basis-SQL --- stabil
+Die grundlegenden SQL-Funktionen, Zeichenketten-Klassen und dynamisches
+Speicher-Handling. Nicht ein einziger berichteter Bug in diesem System.
+
+@item Anfragen-Optimierer (Query optimizer) --- stabil
+
+@item Bereichs-Optimierer (Range optimizer) --- stabil
+
+@item Join-Optimierer (Join optimizer) --- stabil
+
+@item Sperren (Locking) --- Gamma
+Dies ist sehr system-abhängig. Auf einigen Systemen gibt es große
+Probleme, wenn Standard-Betriebssystem-Sperren verwendet wird
+(@code{fcntl()}). In solchen Fällen sollten Sie den MySQL-Daemon mit dem
+Flag @code{--skip-locking} laufen lassen. Bekannt ist, dass solche
+Probleme auf manchen Linux-Systemen vorkommen sowie auf SunOS, wenn NFS-
+gemountete Dateisysteme verwendet werden.
+
+@item Linux-Threads --- stabil
+Das hauptsächliche Problem fand sich im @code{fcntl()}-Aufruf, der durch
+Benutzung der @w{@code{--skip-locking}}-Option bei @code{mysqld} behoben
+werden kann. Einige Leute haben Lockup-Probleme mit Version 0.5
+berichtet. Linux-Threads müssen rekompiliert werden, wenn Sie mehr als
+1000 gleichzeitige Verbindungen benutzen wollen. Obwohl es möglich ist,
+so viele Verbindungen mit den vorgabemäßigen Linux-Threads laufen zu
+lassen (obwohl man nie über 1021 kommen wird), macht das vorgabemäßige
+Stack-Spacing von 2 MB die Applikation unstabil, und wir konnten einen
+Coredump reproduzieren, nachdem 1021 Verbindungen im Leerlauf (idle
+connections) hergestellt wurden. @xref{Linux}.
+
+@item Solaris 2.5+ pthreads --- stabil
+Wir benutzen dies für unsere gesamte Produktionsarbeit.
+
+@item MIT-pthreads (andere Systeme) --- stabil
+Seit Version 3.20.15 gab es keine berichteten Bugs mehr, und keine
+bekannten Bugs seit Version 3.20.16. Auf einigen Systemen gibt es ein
+``Misfeature'', das heißt einige Operationen sind recht langsam (1/20
+Sekunde Schlafzyklus zwischen jeder Anfrage). Natürlich können MIT-
+Threads alles ein bisschen verlangsamen, aber Index-basierende
+@code{SELECT}-Statements werden üblicherweise in einem Zeit-Frame
+ausgeführt, also sollte es kein mutex locking/thread juggling geben.
+
+@item Andere Thread-Implementierungen --- Beta - Gamma
+Die Ports zu anderen Systemen sind noch sehr neu und können Bugs haben,
+möglicherweise auch in MySQL, aber in den meisten Fällen in der Thread-
+Implementierung selbst.
+
+@item @code{LOAD DATA ...}, @code{INSERT ... SELECT} --- stabil
+Einige Leute dachten, hier Bugs gefunden zu haben, aber üblicherweise
+haben sich diese als Missverständnisse heraus gestellt. Bitte sehen Sie
+zuerst im Handbuch nach, bevor Sie Bugs berichten!
+
+@item @code{ALTER TABLE} --- stabil
+Einige Änderungen in Version 3.22.12.
+
+@item DBD --- stabil
+Wird jetzt von Jochen Wiedmann gewartet
+(@email{wiedmann@@neckar-alb.de}). Danke!
+
+@item @code{mysqlaccess} --- stabil
+Geschrieben und gewartet von Yves Carlier
+(@email{Yves.Carlier@@rug.ac.be}). Danke!
+
+@item @code{GRANT} --- stabil
+große Änderungen in MySQL Version 3.22.12.
+
+@item @strong{MyODBC} (benutzt ODBC SDK 2.5) --- Gamma
+Scheint mit einigen Programmen gut zu laufen.
+
+@item Replikation -- Beta / Gamma
+Wir arbeiten noch an der Replikation, also erwarten Sie nicht, dass
+diese schon felsenfest steht. Auf der anderen Seite benutzen MySQL-
+Benutzer diese bereits mit guten Resultaten.
+
+@item BDB-Tabellen -- Beta
+Der Berkeley-Datenbank-Code ist sehr stabil, aber wir verbessern immer
+noch die Schnittstelle zwischen MySQL und BDB-Tabellen, also wird es
+einige Zeit dauern, bevor dies so gut wie andere Tabellentypen getestet
+ist.
+
+@item InnoDB-Tabellen -- Beta
+Diese wurden @code{MySQL} kürzlich hinzu gefügt. Sie scheinen gut zu
+funktionieren und können nach einigen anfänglichen Tests benutzt werden.
+
+@item Automatische Wiederherstellung von MyISAM-Tabellen - Beta
+Dies betrifft nur den neuen Code, der beim Öffnen einer Tabelle
+nachsieht, ob diese korrekt geschlossen wurde und ein automatisches
+Überprüfen / Reparieren der Tabelle ausführt, falls das nicht der Fall
+war.
+
+@item MERGE-Tabellen -- Beta / Gamma
+Die Benutzung von Schlüsseln bei @code{MERGE}-Tabellen ist noch nicht
+sehr ausgetestet. Der restliche Teile des @code{MERGE}-Codes ist recht
+gut getestet.
+
+@item FULLTEXT -- Beta
+Textsuche scheint zu funktionieren, wird aber noch nicht viel
+eingesetzt.
+
+@end table
+
+MySQL AB stellt E-Mail-Support für zahlende Kunden bereit, aber die
+MySQL-Mailingliste bietet üblicher Weise Antworten für die meisten
+Fragen. Bugs werden meist direkt mit einem Patch behoben; für
+schwerwiegende Bugs gibt es fast immer ein neues Release.
+
+
+@node Table size, Year 2000 compliance, Stability, What-is
+@c German node Tabellengröße
+@subsection Wie groß können MySQL-Tabellen sein?
+
+@cindex Tabellen, maximale Größe
+@cindex Größe von Tabellen
+@cindex Betriebssysteme, Dateigrößen-Beschränkungen
+@cindex Beschränkungen, Dateigröße
+@cindex Dateien, Dateigröße
+
+MySQL Version 3.22 hat eine Begrenzung auf 4G bei der Tabellengröße.
+Mit dem neuen @code{MyISAM} in MySQL Version 3.23 wurde die maximale
+Tabellengröße auf 8 Millionen Terabytes (2 ^ 63 bytes) hochgeschraubt.
+
+Beachten Sie allerdings, dass Betriebssysteme ihre eigenen Dateigrößen-
+Beschränkungen haben. Hier sind einige Beispiele:
+
+@multitable @columnfractions .5 .5
+@item @strong{Betriebssystem} @tab @strong{Dateigrößen-Beschränkung}
+@item Linux-Intel 32 bit @tab 2G, 4G oder mehr, abhängig von der Linux-Version
+@item Linux-Alpha @tab 8T (?)
+@item Solaris 2.5.1 @tab 2G (möglich sind 4G mit Patch)
+@item Solaris 2.6 @tab 4G
+@item Solaris 2.7 Intel @tab 4G
+@item Solaris 2.7 ULTRA-SPARC @tab 8T (?)
+@end multitable
+
+Auf Linux 2.2 kann man größere Tabellen als 2G benutzen, wenn man den
+LFS-Patch für das ext2 Dateisystem benutzt. Auf Linux 2.4 existiert
+zusätzlich ein Patch für das ReiserFS, um Unterstützung für große
+Dateien zu erhalten.
+
+Letztlich wird die Tabellengröße für MySQL normalerweise durch das
+Betriebssystem begrenzt.
+
+Vorgabemäßig haben MySQL-Tabellen eine maximale Größe von etwa 4G. Sie
+können die maximale Tabellengröße für eine Tabelle mit dem @code{SHOW
+TABLE STATUS}-Befehl überprüfen oder mit @code{myisamchk -dv
+tabellen_name}. @xref{SHOW}.
+
+Wenn Sie größere Tabellen als 4G benötigen (und Ihr Betriebssystem dies
+unterstützt), sollten Sie die @code{AVG_ROW_LENGTH}- und
+@code{MAX_ROWS}-Parameter benutzen, wenn Sie Ihre Tabelle anlegen.
+@xref{CREATE TABLE}. Sie können diese auch später setzen, mit
+@code{ALTER TABLE}. @xref{ALTER TABLE}.
+
+Falls auf Ihre große Tabelle nur mit Lesezugriff zugegriffen wird
+(read-only), können Sie auch @code{myisampack} benutzen, um mehrere
+Tabellen zu vereinen (merge) und sie zu einer zu komprimieren.
+@code{myisampack} komprimiert eine Tabelle üblicherweise mindestens um
+50%, also können Sie effektiv viel größere Tabellen benutzen.
+@xref{myisampack, ,@code{myisampack}}.
+
+Sie können die Dateibegrenzung des Betriebssystems für @code{MyISAM}
+Daten-Dateien umgehen, indem Sie die @code{RAID}-Option benutzen.
+@xref{CREATE TABLE}.
+
+Eine weitere Lösung kann die MERGE-Bibliothek darstellen, die Ihnen
+erlaubt, eine Sammlung identischer Tabellen zugleich zu benutzen.
+@xref{MERGE, MERGE tables}.
+
+
+@node Year 2000 compliance, , Table size, What-is
+@c German node Jahr-2000-Konformität
+@subsection Jahr-2000-Konformität
+
+@cindex Jahr-2000-Konformität
+@cindex Kompatibilität, Y2K, Jahr 2000
+@cindex Datumsfunktionen, Y2K, Jahr-2000-Konformität
+
+MySQL selbst hat keine Probleme mit der Jahr-2000-Konformität:
+
+@itemize @bullet
+@item
+MySQL benutzt Unix-Zeitfunktionen und hat keine Probleme mit
+Datumsangaben bis @code{2069}. Alle zweistelligen Jahresangaben werden
+als Angaben zwischen @code{1970} und @code{2069}, betrachtet, was
+bedeutet, dass, wenn Sie @code{01} in einer Spalte speichern, MySQL dies
+als @code{2001} behandelt.
+
+@item
+Alle MySQL Datumsfunktionen sind in einer Datei @file{sql/time.cc}
+gespeichert und sehr sorgfältig kodiert, um Jahr-2000-sicher zu sein.
+
+@item
+In MySQL Version 3.22 und später kann der neue Spaltentyp @code{YEAR}
+Jahre @code{0} und von @code{1901} bis @code{2155} in 1 Byte speichern
+und sie mit 2 oder 4 Ziffern anzeigen.
+@end itemize
+
+Probleme können Sie bekommen, wenn Sie MySQL mit Applikationen benutzen,
+die MySQL auf eine Art benutzen, die nicht Jahr-2000-sicher ist. Zum
+Beispiel speichern oder ändern viele alte Applikationen Jahresangaben,
+indem sie zweistellige Werte benutzen (was mehrdeutig ist), anstatt
+vierstellige Werte zu nehmen. Dieses Problem kann durch Applikationen
+verschlimmert werden, die Werte wie @code{00} oder @code{99} als Anzeiger
+``fehlender'' Werte benutzen.
+
+Leider sind diese Probleme möglicherweise schwer zu beheben, weil
+verschiedene Applikationen von unterschiedlichen Programmierern
+geschrieben sein können, von denen jeder einen anderen Satz von
+Konventionen und Funktionen benutzt haben kann, was die Handhabung von
+Datumsangaben betrifft.
+
+Hier ist eine einfache Demonstration, die zeigt, dass MySQL keine
+Probleme mit Datumsangaben bis zum Jahr 2030 hat:
+
+@example
+mysql> DROP TABLE IF EXISTS y2k;
+Query OK, 0 rows affected (0.01 sec)
+
+mysql> CREATE TABLE y2k (date date, date_time datetime, time_stamp timestamp);
+Query OK, 0 rows affected (0.00 sec)
+
+mysql> INSERT INTO y2k VALUES
+ -> ("1998-12-31","1998-12-31 23:59:59",19981231235959),
+ -> ("1999-01-01","1999-01-01 00:00:00",19990101000000),
+ -> ("1999-09-09","1999-09-09 23:59:59",19990909235959),
+ -> ("2000-01-01","2000-01-01 00:00:00",20000101000000),
+ -> ("2000-02-28","2000-02-28 00:00:00",20000228000000),
+ -> ("2000-02-29","2000-02-29 00:00:00",20000229000000),
+ -> ("2000-03-01","2000-03-01 00:00:00",20000301000000),
+ -> ("2000-12-31","2000-12-31 23:59:59",20001231235959),
+ -> ("2001-01-01","2001-01-01 00:00:00",20010101000000),
+ -> ("2004-12-31","2004-12-31 23:59:59",20041231235959),
+ -> ("2005-01-01","2005-01-01 00:00:00",20050101000000),
+ -> ("2030-01-01","2030-01-01 00:00:00",20300101000000),
+ -> ("2050-01-01","2050-01-01 00:00:00",20500101000000);
+Query OK, 13 rows affected (0.01 sec)
+Records: 13 Duplicates: 0 Warnings: 0
+
+mysql> SELECT * FROM y2k;
++------------+---------------------+----------------+
+| date | date_time | time_stamp |
++------------+---------------------+----------------+
+| 1998-12-31 | 1998-12-31 23:59:59 | 19981231235959 |
+| 1999-01-01 | 1999-01-01 00:00:00 | 19990101000000 |
+| 1999-09-09 | 1999-09-09 23:59:59 | 19990909235959 |
+| 2000-01-01 | 2000-01-01 00:00:00 | 20000101000000 |
+| 2000-02-28 | 2000-02-28 00:00:00 | 20000228000000 |
+| 2000-02-29 | 2000-02-29 00:00:00 | 20000229000000 |
+| 2000-03-01 | 2000-03-01 00:00:00 | 20000301000000 |
+| 2000-12-31 | 2000-12-31 23:59:59 | 20001231235959 |
+| 2001-01-01 | 2001-01-01 00:00:00 | 20010101000000 |
+| 2004-12-31 | 2004-12-31 23:59:59 | 20041231235959 |
+| 2005-01-01 | 2005-01-01 00:00:00 | 20050101000000 |
+| 2030-01-01 | 2030-01-01 00:00:00 | 20300101000000 |
+| 2050-01-01 | 2050-01-01 00:00:00 | 00000000000000 |
++------------+---------------------+----------------+
+13 rows in set (0.00 sec)
+
+@end example
+
+Das zeigt, dass die @code{DATE}- und @code{DATETIME}-Typen für zukünftige
+Datumsangaben keine Probleme bereiten werden (sie handhaben Datumsangaben
+bis zum Jahr 9999).
+
+Der @code{TIMESTAMP}-Typ, der zur Speicherung der aktuellen Zeit benutzt
+wird, hat nur einen Bereich bis zu @code{2030-01-01}. @code{TIMESTAMP} hat
+einen Bereich von @code{1970} bis @code{2030} auf 32-Bit-Maschinen
+(vorzeichenbehafteter Wert). Auf 64-Bit-Maschinen handhabt dieser
+Spaltentyp bis zu @code{2106} (vorzeichenloser Wert).
+
+Obwohl MySQL Jahr-2000-kompatibel ist, sind Sie dafür verantwortlich,
+mehrdeutige Eingaben zu vermeiden. Siehe @ref{Year 2000 compliance} wegen
+der Regeln, die MySQL anwendet, wenn mehrdeutige Datumsangaben gemacht
+werden (Datumsangaben, die zweistellige Jahreswerte verwenden).
+
+
+
+@node What is MySQL AB, Licensing and Support, What-is, Deutsch
+@c German node Was ist MySQL AB?
+@section Was ist MySQL AB?
+
+@cindex MySQL AB, Definition
+
+@code{MySQL AB} ist das Unternehmen der MySQL Gründer und Hauptentwickler.
+MySQL AB wurde ursprünglich in Schweden von David Axmark, Allan Larsson
+und Michael @code{Monty} Widenius gegründet.
+
+Alle Entwickler des MySQL Servers sind Angestellte dieses Unternehmens.
+Wir sind eine virtuelle Firma mit Mitarbeitern, die über die ganze Welt
+verstreut in aller Herren Länder sitzen. Der Hauptteil unserer Kommunikation
+untereinander, mit unseren Anwendern, Unterstützern und Partnern wird über
+das Internet abgewickelt
+
+Wir haben uns der Entwicklung und Verbreitung des MySQL Datenbankservers
+verschrieben. MySQL hält das Copyright der MySQL Quelltexte, des MySQL Logos
+und dieses Handbuchs.. @xref{What-is}.
+
+
+Die MySQL-Kernwerte zeigen unsere Verpflichtung gegenüber MySQL und Open
+Source.
+
+Wir wollen, dass MySQL folgendes ist:
+
+@itemize @bullet
+@item
+Die beste und meist benutzte Datenbank der Welt.
+@item
+Verfügbar für alle. Alle sollen sich MySQL leisten können.
+@item
+Leicht zu benutzen.
+@item
+Kontinuierlich verbessert, trotzdem immer schnell und sicher bleibend.
+@item
+Es soll Spass machen, MySQL zu benutzen und zu verbessern.
+@item
+Frei von Bugs.
+@end itemize
+
+
+MySQL AB und die Leute von MySQL AB:
+
+@itemize @bullet
+@item
+Verbreiten die Open-Source-Philosophie und unterstützen die
+Open-Source-Community.
+@item
+Bemühen sich, gute Bürger zu sein.
+@item
+Bevorzugen Partner, die unsere Werte und unsere Geisteshaltung teilen.
+@item
+Beantworten Mail und geben Support.
+@item
+Sind ein virtuelles Unternehmen, das mit anderen im Netzwerk
+zusammenarbeitet (networking).
+@item
+Arbeiten gegen Software-Patente.
+@end itemize
+
+@menu
+* MySQL AB business model and services::
+@end menu
+
+@node MySQL AB business model and services, , What is MySQL AB, What is MySQL AB
+@c German node MySQL AB Geschäftsmodell und Services
+@subsection Geschäftsmodell und Dienstleistungen von MySQL AB
+
+Eine der uns häufig gestellten Fragen ist: Wie kann man von etwas leben,
+das man kostenlos abgibt? Hier ist die Antwort:
+MySQL AB verdient Geld mit Support, Dienstleistungen, kommerziellen
+Lizenzen und Lizenzgebühren, das wir dazu verwenden, die
+Produktentwicklung zu finanzieren und die MySQL-Geschäftsfelder
+auszubauen.
+
+
+Unser Unternehmen läuft seit der Gründung profitabel. Im Oktober 2001
+akzeptierten wir eine Risikokapitalfinanzierung durch führende
+skandinavische Investoren und eine Handvoll Business-Angels. Die
+Investitionen werden genutzt, um unser Geschäftsmodell auf solide Füße
+zu stellen und eine Grundlage für nachhaltiges Wachstum zu schaffen.
+
+@menu
+* Business Services Support::
+* Business Services Training::
+* Business Services Consulting::
+* Business Services Commercial licenses::
+* Business Services Partnering::
+* Business Services Advertising::
+* Contact information::
+@end menu
+
+@node Business Services Support, Business Services Training, MySQL AB business model and services, MySQL AB business model and services
+@c German node Business Services Support
+@subsubsection Support
+
+MySQL AB gehört den Gründern und Haupt-Entwicklern der MySQL-Datenbank
+und wird von ihnen betrieben. Die Entwickler fühlen sich verpflichtet,
+Kunden und anderen Benutzern Support zu bieten, um mit deren
+Bedürfnissen und Problemen in Kontakt zu bleiben. Unser gesamter Support
+wird durch qualifizierte Entwickler geleistet. Wirklich schwierige
+Fragen werden von Michael @code{Monty} Widenius beantwortet, der der
+erste Entwickler des MySQL-Servers ist. @xref{Support}.
+
+Um Support unterschiedlicher Grade zu bestellen, besuchen Sie bitte die
+Bestellseite unter @uref{https://order.mysql.com/}. Wenn Sie nur
+beschränkten Zugriff auf das Internet haben, setzen Sie sich bitte mit
+unserem Vertrieb unter @email{sales@@mysql.com} in Verbindung.
+
+@node Business Services Training, Business Services Consulting, Business Services Support, MySQL AB business model and services
+@c German node Business Services Training
+@subsubsection Training und Zertifizierung
+
+MySQL AB führt Schulungen zu MySQL und verwandten Themen weltweit durch.
+Wir bieten sowohl offene Kurse als auch In-house-Trainings an, die auf
+die speziellen Bedürfnisse Ihres Unternehmens zugeschnitten sind.
+MySQL-Schulungen werden auch durch unsere Partner durchgeführt, die
+Authorised MySQL Training Center.
+
+Unsere Schulungsmaterialien benutzen dieselben Beispiel-Datenbanken wie
+unsere Dokumentation und unsere Beispiel-Applikationen und werden
+ständig aktualisiert, um den Entwicklungsstand der neusten MySQL-Version
+widerzuspiegeln. Unsere Trainer erhalten Rückhalt vom Entwicklungsteam,
+um die Trainingsqualität und die kontinuierliche Entwicklung des
+Schulungsmaterials sicherzustellen. Das stellt auch sicher, dass keine
+während der Kurse aufgetretenen Fragen unbeantwortet bleiben.
+
+Wenn Sie an unseren Schulungen teilnehmen, können Sie sicher sein, die
+Ziele zu erreichen, die Sie mit Ihren MySQL-bezogenen Applikationen
+anstreben. Ausserdem haben Sie folgende Vorteile:
+
+@itemize @bullet
+@item
+Sie sparen Zeit.
+@item
+Sie verbessern die Performance Ihrer Applikation(en).
+@item
+Sie verringern die Notwendigkeit zusätzlicher Hardware, was Kosten
+spart.
+@item
+Sie verbessern Ihre Sicherheit.
+@item
+Sie erhöhen die Zufriedenheit Ihrer Kunden und Mitarbeiter.
+@item
+Sie bereiten sich auf die MySQL-Zertifizierung vor.
+@end itemize
+
+Wenn Sie an unseren Schulungen Interesse als möglicher Teilnehmer oder
+Trainingspartner haben, besuchen Sie bitte die Seite unter
+@uref{http://www.mysql.com/training/}. Wenn Sie nur beschränkten Zugriff
+auf das Internet haben, setzen Sie sich bitte mit unserem
+Trainingspersonal unter @email{training@@mysql.com} in Verbindung.
+
+Die Veröffentlichung des MySQL-Zertifizierungsprogramms ist für 2002
+geplant. Details finden Sie unter
+@uref{http://www.mysql.com/training/certification.html}. Wenn Sie stets
+die neusten Informationen über das MySQL-Zertifizierungsprogramm haben
+wollen, schicken Sie bitte eine E-Mail an
+@email{certification@@mysql.com}.
+
+
+@c German FIX this node entry was missing but the section was there...
+@node Business Services Consulting, Business Services Commercial licenses, Business Services Training, MySQL AB business model and services
+@c German node Business Services Consulting
+@subsubsection Beratung
+MySQL AB und seine authorisierten Partner bieten Benutzern des
+MySQL-Servers und denen, die ihn in ihre Software einbetten wollen,
+Beratungsleistungen, weltweit.
+
+Unsere Berater können Ihnen helfen, Ihre Datenbanken zu entwerfen und zu
+optimieren, effiziente Anfragen zu konstruieren, Ihre Plattform auf
+optimale Performance zu tunen, Migrationsprobleme zu lösen, Replikation
+aufzusetzen, robuste transaktionale Applikationen zu bauen und vieles
+mehr. Wir helfen auch Kunden dabei, den MySQL-Server für den
+Großflächigen Einsatz in ihre Produkte und Applikationen einzubauen.
+
+Unsere Berater arbeiten in enger Kooperation mit unserem
+Entwicklungsteam, was die technische Qualität unserer Dienstleistungen
+sicherstellt. Beratungsaufgaben erstrecken sich von zweitägigen
+Power-Start-Sessions bis zu Projekten, die Wochen und Monate dauern.
+Unsere Kompetenz deckt nicht nur den MySQL-Server ab, sondern auch
+Programmier- und Skripting-Sprachen wie PHP, Perl und andere.
+
+Wenn Sie an unseren Beratungsleistungen interessiert sind oder ein
+Consulting-Partner werden wollen, besuchen Sie bitte unsere Seite unter
+@uref{http://www.mysql.com/consulting/}. Wenn Sie nur beschränkten
+Zugriff auf das Internet haben, setzen Sie sich bitte mit unserem
+Beratungspersonal unter @email{consulting@@mysql.com} in Verbindung.
+
+@node Business Services Commercial licenses, Business Services Partnering, Business Services Consulting, MySQL AB business model and services
+@c German node Business Services Commercial Licenses
+@subsubsection Kommerzielle Lizenzen
+
+Die MySQL-Datenbank wird unter der @code{GNU General Public License}
+veröffentlicht (@code{GPL}). Das bedeutet, dass die MySQL-Software
+kostenlos unter der GPL benutzt werden darf. Wenn Sie nicht an die
+GPL-Bedingungen gebunden sein wollen (was in der Folge bedeutet, dass
+auch Ihre eigenen Applikationen GPL werden), können Sie eine
+kommerzielle Lizenz für dasselbe Produkt unter
+@uref{https://order.mysql.com/} erwerben.
+
+Weil MySQL AB das Copyright am MySQL-Server besitzt, können wir eine
+@code{duale Lizensierung} einsetzen, was heißt, dass dasselbe Produkt
+sowohl unter der GPL als auch unter einer kommerziellen Lizenz
+erhältlich ist. Das berührt in keiner Weise die Verpflichtung von MySQL
+AB gegenüber @code{Open Source}. Wegen Details, wann eine kommerzielle
+Lizenz erforderlich ist, sehen Sie bitte unter
+@ref{Lizenzpolitik} nach.
+
+Wir verkaufen auch kommerzielle Lizenzen von Open-Source-GPL-Software
+Dritter. Ein gutes Beispiel hierfür ist der
+@code{InnoDB}-Tabellen-Handler, der ACID-Unterstützung, Sperren auf
+Zeilenebene, Wiederherstellung nach Abstürzen, Multiversionierung,
+Fremdschlüsselunterstützung und vieles mehr bietet.
+
+@node Business Services Partnering, Business Services Advertising, Business Services Commercial licenses, MySQL AB business model and services
+@c German node Business Services Partnering
+@subsubsection Partnerprogramme
+@cindex Partnerschaft mit MySQL AB
+
+MySQL AB hat ein weltweites Partnerprogramm, dass Schulungskurse,
+Support, Beratung, Lösungen, Publikationen plus Weiterverkauf und
+Vertrieb von MySQL und verwandten Produkten beinhaltet. Partner
+erscheinen unter @uref{http://www.mysql.com/} auf der Website und
+erhalten das Recht, spezielle Versionen der MySQL-Schutzmarken zu
+benutzen, um ihre Produkte zu identifizieren und ihr Geschäft
+voranzutreiben. Wenn Sie interessiert sind, ein MySQL-AB-Partner zu
+werden, schicken Sie bitte eine E-Mail an @email{partner@@mysql.com}.
+
+Das Wort @code{MySQL} und das MySQL-Delphin-Logo sind Schutzmarken von
+MySQL AB. @xref{MySQL AB Logos and Trademarks}.
+
+@node Business Services Advertising, Contact information, Business Services Partnering, MySQL AB business model and services
+@c German node Business Services Advertising
+@subsubsection Werbung
+
+Die MySQL-Website (@uref{http://www.mysql.com/}) ist bei Entwicklern und
+Benutzern beliebt. Im Oktober 2001 bedienten wir 10 Millionen
+Seitenanfragen (PageViews). Unsere Besucher repräsentieren eine Gruppe,
+die Kaufentscheidungen und Empfehlungen sowohl für Software als auch für
+Hardware trifft. 12% unserer Besucher genehmigen Kaufentscheidungen,
+lediglich 9% sind überhaupt nicht an Kaufentscheidungen beteiligt. Mehr
+als 65% haben innerhalb des letzten halben Jahres online eingekauft, 70%
+planen, in den nächsten Monaten einzukaufen. Wenn Sie Interesse haben,
+Werbebanner auf unserer Website @uref{http://www.mysql.com/} zu
+schalten, setzen Sie sich bitte mit @email{advertising@@mysql.com} in
+Kontakt.
+
+@node Contact information, , Business Services Advertising, MySQL AB business model and services
+@c German node Kontaktinformationen
+@subsubsection Kontaktinformationen
+
+@cindex Kontaktinformationen
+@cindex Lizensierung, Kontaktinformationen
+@cindex Werbung, Kontaktinformationen
+@cindex Anstellung, Kontaktinformationen
+@cindex Partnerschaft mit MySQL
+@cindex Anstellung bei MySQL
+@cindex Jobs bei MySQL
+
+Die MySQL Website (@uref{http://www.mysql.com/})
+enthält die neusten Informationen über MySQL und MySQL AB.
+
+Für Presseservice und Anfragen aller Art, die in unseren
+Veröffentlichungen (@uref{http://www.mysql.com/news/}) nicht
+behandelt werden, wenden Sie sich bitte an
+@email{press@@mysql.com}.
+
+Zeitnahe, präzise Antworten auf technische Fragen erhalten Sie, wenn Sie
+unter @uref{https://order.mysql.com/, order} einen unserer
+@uref{http://www.mysql.com/Support/arrangements/types.html,
+Support-Verträge} abschließen.
+MySQL-Support wird von den MySQL-Entwicklern geleistet, weshalb der
+Standard extrem hoch ist.
+
+Informationen über MySQL Trainig erhalten Sie unter
+@uref{http://www.mysql.com/training/}. Wenn Sie einen
+eingeschränkten Internetzugang haben, kontaktieren Sie
+bitte unser Trainingspersonal unter @email{training@@mysql.com}.
+@xref{Business Services Training}.
+
+Für Informationen über das MySQL Zertifizierungsprogramm
+erhalten Sie unter @uref{http://www.mysql.com/training/certification.html}.
+Wenn Sie weiterhin über das MySQL Zertifizierungsprogramm informiert
+werden wollen, schreiben Sie eine E-Mail an @email{certification@@mysql.com}.
+@xref{Business Services Consulting}.
+
+Kommerzielle Lizenzen können online unter @uref{https://order.mysql.com/}
+abgewickelt werden. Dort finden Sie ausserdem Informationen darüber,
+wie Sie ihre Bestellung per Fax erledigen können. Wenn Sie Fragen bezüglich
+der Lizensierung haben, oder Sie ein Angebot über eine größere Lizenzerteilung
+erhalten wollen, füllen Sie bitte Das Kontaktformular auf unserer Website
+(@uref{http://www.mysql.com/}) aus, oder schicken Sie eine E-Mail
+an @email{licensing@@mysql.com} (für Lizenzfragen) oder an
+@email{sales@@mysql.com} (für Verkaufsinformationen).
+@xref{Lizenzpolitik}.
+
+Wenn Sie daran interessiert sind, ein Werbebanner auf unserer Website
+(@uref{http://www.mysql.com/}) zu schalten, schicken Sie bitte
+eine E-Mail an @email{advertising@@mysql.com}.
+@xref{Business Services Advertising}.
+
+Wenn Sie ein Unternehmen vertreten, dass an einer Partnerschaft mit MySQL
+interessiert ist, schicken Sie bitte eine E-Mail an
+@email{partner@@mysql.com}.
+
+Für weitere Informationen über die MySQL Schutzmarkenbestimmungen, beachten
+Sie bitte @uref{http://www.mysql.com/company/trademark.html} oder kontaktieren
+Sie @email{trademark@@mysql.com}.
+@c German FIX changed 'and' to 'und' to make German xref work
+@xref{MySQL AB Logos and Trademarks}.
+
+Wenn Sie an einem der Jobs interessiert sind, die im
+@uref{http://www.mysql.com/development/jobs/, jobs}-Abschnitt aufgeführt
+sind, schicken Sie bitte eine E-Mail an @email{jobs@@mysql.com}. Bitte
+senden Sie ihre CV nicht als Anhang an dieser mail mit, sondern
+fügen Sie sie lieber am Ende ihrer mail als Klartext (plain text) ein.
+
+Allgemeine Diskussionen mit vielen unserer Benutzer können Sie auf den
+entsprechenden @uref{http://www.mysql.com/documentation/lists.html,
+Mailing-Listen} führen.
+
+Fehlerberichte (Auch Bugreporte genannt), sowie Fragen und Kommentare, sollten
+an die Mailingliste @email{mysql@@lists.mysql.com} gehen. Wenn Sie
+ein empfindliches Sicherheitsloch im MySQL Server gefunden haben, sollten
+@c German FIX added . after schreiben and after the xref.
+Sie eine E-Mail an @email{security@@mysql.com} schreiben.
+@xref{Bug reports}.
+
+Wenn Sie Benchmarkergebnis haben, die wir veröffentlichen können, kontaktieren
+Sie uns unter @email{benchmarks@@mysql.com}.
+
+Wenn Sie Vorschläge für Hinzufügungen oder Korrekturen dieses Handbuchs
+haben, schicken Sie sie bitte an das Handbuch-Team:
+@email{docs@@mysql.com}.
+
+Fragen zur Arbeitsweise oder zu Inhalten unserer Website(@uref{http://www.mysql.com/})
+stellen Sie bitte an @email{webmaster@@mysql.com}.
+
+Fragen über das MySQL Portal (@uref{http://www.mysql.com/portal/})
+können an @email{portals@@mysql.com} geschickt werden.
+
+Die Datenschutzbestimmungen von MySQL AB können Sie unter
+@uref{http://www.mysql.com/company/privacy.html} einsehen.
+Für irgendwelche Fragen darüber, wenden Sie sich bitte an
+@email{privacy@@mysql.com}.
+
+Allgemeine Informationsanfragen schicken Sie bitte an @email{info@@mysql.com}.
+
+
+@node Licensing and Support, MySQL 4.0 In A Nutshell, What is MySQL AB, Deutsch
+@c German node Lizensierung and Support
+@section MySQL Support and Lizensierung
+
+@cindex Lizensierungsbedingungen
+@cindex Supportbedingungen
+
+Dieser Abschnitt beschreibt die MySQL Support und Lizensierungsvereinbarungen
+
+
+@menu
+* Support::
+* Copyright::
+* MySQL AB Logos and Trademarks::
+* Lizenzpolitik::
+@end menu
+
+@node Support, Copyright, Licensing and Support, Licensing and Support
+@c German node Support
+@subsection Support den MySQL AB anbietet
+
+@cindex Support, Arten
+@cindex Arten von Support
+@cindex Kommerzieller Support, Arten
+@cindex Kosten, Support
+@cindex Lizensierungskosten
+@cindex Supportkosten
+@cindex Preise, Support
+
+Wir versuchen, technischen Support in einem breiten und umfassenden
+Blickwinkel zu sehen. Fast jedes Problem im Zusammenhang mit
+MySQL-Software ist für uns wichtig, wenn es für Sie wichtig ist.
+Typischerweise suchen Kunden Hilfe dabei, wie man unterschiedliche
+Befehle und Dienstprogramme zum Funktionieren bringt, wie
+Performance-Flaschenhälse beseitigt werden können, wie man beschädigte
+Systeme repariert, wie sich Betriebssysteme oder Netzwerkkonfigurationen
+auf MySQL auswirken, wie man Datensicherung und Wiederherstellung
+optimal konfiguriert, wie man APIs benutzt usw.
+Unser Support deckt nur den MySQL-Server und unsere eigenen
+Dienstprogramme ab, nicht Produkte Dritter, die auf den MySQL-Server
+zugreifen, obwohl wir auch hierbei versuchen, zu helfen wo wir können.
+
+Detaillierte Informationen über unsere unterschiedlichen
+Support-Optionen finden Sie auf @uref{https://order.mysql.com/}, wo auch
+Support-Verträge online bestellt werden können. Wenn Sie nur
+beschränkten Zugriff auf das Internet haben, setzen Sie sich mit unserem
+Vertrieb unter @email{sales@@mysql.com} in Verbindung.
+
+Technischer Support ist wie eine Lebensversicherung. Sie können
+jahrelang ohne solches glücklich sein, doch wenn die Stunde schlägt,
+kann es zu spät sein, diese(n) zu kaufen!
+Wenn Sie den MySQL-Server für wichtige Applikationen nutzen und
+plötzlich Problemen begegnen, kann es möglicherweise zu lange dauern,
+alle Antworten selbst herauszufinden. Es kann daher sein, dass Sie
+unmittelbaren Zugriff auf die erfahrensten MySQL-Problemlöser benötigen,
+und da
+
+@node Copyright, MySQL AB Logos and Trademarks, Support, Licensing and Support
+@c German node Copyright
+@subsection Copyrights und Lizenzen, die von MySQL verwendet werden.
+
+@cindex copyrights
+@cindex licenses
+
+@code{MySQL AB} besitzt das Copyright des MySQL Quellcodes,
+der MySQL Logos and Schutzmarken und dieses Handbuch
+@xref{What is MySQL AB}.
+Es gibt einige verschiedene Lizenzen, die für die MySQL Distribution
+relevant sind:
+
+@enumerate
+@item
+
+Der MySQL-spezifische Quelltext, der benötigt wird, um die
+@code{mysqlclient}-Bibliothek zu kompilieren, ist unter der @code{LGPL}
+lizensiert. Programme im @file{client}-Verzeichnis sind GPL. Jede Datei hat
+einen Header, aus dem ersichtlich ist, welches Copyright für diese Datei
+gilt.
+
+@item Die Client-Bibliothek und die (GNU @code{getopt})-Bibliothek werden
+von der ``GNU LIBRARY GENERAL PUBLIC LICENSE'' abgedeckt. @xref{LGPL license}.
+
+@item
+Der gesamte Quelltext des Servers und der (GNU @code{readline})-Bibliothek
+werden von der ``GNU GENERAL PUBLIC LICENSE'' abgedeckt. @xref{GPL license}.
+Diese findet sich unter anderem als Datei @file{COPYING} in den
+Distributionen.
+
+@item Einige Teile des Quelltextes (die @code{regexp}-Bibliothek) werden
+von einem Copyright in Berkeley-Art abgedeckt.
+
+@item
+Ältere Versionen von (3.22 und früher) stehen unter einer
+strikteren Lizenz
+(@uref{http://www.mysql.com/support/arrangements/mypl.html}).
+Bitte beachten sie die Dokumentation der speziellen Version für
+weitere Informationen.
+
+
+@item
+Das Handbuch steht @emph{nicht} unter einer GPL-artigen Lizenz.
+Die Benutzung des Handbuchs unterliegt den folgenden Bestimmungen.
+@itemize @bullet
+@item
+Die Konvertierung in andere Formate ist erlaubt, der Inhalt jedoch
+darf auf keinen Fall geändert oder bearbeitet werden.
+@item
+Sie können eine gedruckte Version für den Privaten Gebrauch erstellen
+@item
+Für alle anderen Zwecke, wie den Verkauf von gedruckten Kopien
+oder die Verwendung (auch in Teilen) des Handbuchs in anderen
+Veröffentlichungen, ist eine vorherige Vereinbarung mit MySQL AB
+erforderlich.
+@end itemize
+Bitte senden Sie eine E-Mail an @email{docs@@mysql.com} für weitere Informationen
+oder wenn Sie daran interessiert sind, eine Übersetzung zu erstellen.
+@end enumerate
+
+Für Informationen darüber, wie die MySQL Lizenzen in der Praxis arbeiten
+beachten Sie bitte @ref{Lizenzpolitik}.
+Siehe auch @ref{MySQL AB Logos and Trademarks}.
+
+
+
+@menu
+* Verwendung des MySQL Servers unter einer kommerziellen Lizenz::
+* Webserver::
+@end menu
+
+@node Verwendung des MySQL Servers unter einer kommerziellen Lizenz, Webserver, Copyright, Copyright
+@c German node <no English equivalent>
+@subsubsection Verwendung des MySQL Servers unter einer kommerziellen Lizenz
+
+@c German FIX added . after schreiben and after the xref.
+@cindex ISP-Services
+@cindex Services, ISP
+@cindex Services, Web
+@cindex Internet Service Provider
+
+Internet Service Provider (ISP) hosten oft MySQL-Server für ihre Kunden.
+Aufgrund der GPL-Lizenz ist hierfür keine Lizensierung erforderlich.
+
+Auf der anderen Seite ermutigen wir Leute, ISPs zu benutzen, die
+MySQL-Support haben, und das wird ihnen Vertrauen geben, dass ihr ISP im
+Falle von Problemen mit ihrer MySQL-Installation helfen wird, das Problem
+zu lösen (in manchen Fällen mit der Hilfe des MySQL-Entwicklungsteams).
+
+Alle ISPs, die auf dem neuesten Stand der Dinge bleiben wollen, sollten sich
+in die @code{announce}-Mailing-Liste eintragen, um auf der Hut zu sein vor
+schwerwiegenden Problemen, die für ihre MySQL-Installationen relevant sein
+könnten.
+
+Beachten Sie bitte, dass ein ISP ohne MySQL-Lizenz seinen Kunden zumindest
+Lesezugriff auf den Quelltext der MySQL-Installation geben sollte, damit
+die Kunden feststellen können, dass diese korrekt gepatcht ist.
+
+
+@node Webserver, , Verwendung des MySQL Servers unter einer kommerziellen Lizenz, Copyright
+@c German node <no English equivalent>
+@subsubsection Einen Webserver betreiben, der MySQL benutzt
+
+@cindex Webserver, betreiben
+@cindex Einen Webserver betreiben
+
+Wenn Sie MySQL in Verbindung mit einem Webserver unter Unix betreiben,
+brauchen Sie nicht für eine Lizenz zu bezahlen.
+
+Das gilt selbst dann, wenn Sie einen kommerziellen Webserver betreiben, der
+MySQL benutzt, weil Sie nicht selbst eine eingebettete MySQL-Version
+verkaufen. Dennoch bitten wir Sie, in einem solchen Fall MySQL-Support zu
+kaufen, weil MySQL Ihrem Unternehmen hilft.
+
+
+@node MySQL AB Logos and Trademarks, Lizenzpolitik, Copyright, Licensing and Support
+@c German node MySQL AB Logos und Schutzmarken
+@subsection MySQL-AB-Logos und -Schutzmarken
+
+@cindex Logos
+@cindex Schutzmarken
+
+Viele MySQL-Datenbankbenutzer wollen auf Ihren Websites, ihren Büchern
+und Packungsprodukten das MySQL-AB-Delphin-Logo zeigen. Wir begrüßen
+das und ermuntern dazu, weisen aber darauf hin, dass das Wort
+@code{MySQL} und das MySQL-Delphin-Logo Schutzmarken von MySQL AB sind
+und nur so benutzt werden dürfen, wie in unserer Schutzmarken-Richtlinie
+unter @uref{http://www.mysql.com/company/trademark.html} festgelegt.
+
+
+
+
+@menu
+* The Original MySQL logo::
+* MySQL Logos that may be Used Without Written Permission::
+* When need MySQL logo permission::
+* MySQL AB Partnership Logos::
+@end menu
+
+@node The Original MySQL logo, MySQL Logos that may be Used Without Written Permission, MySQL AB Logos and Trademarks, MySQL AB Logos and Trademarks
+@c German node Das Original-MySQL-Logo
+@subsubsection Das Original-MySQL-Logo
+
+@c FIX: picture: MySQL logo
+
+Das MySQL-Delphin-Logo wurde von der finnischen Werbeagentur Priority im
+Jahr 2001 entworfen. Der Delphin wurde als passendes Symbol für die
+MySQL-Datenbank gewählt, weil er schlau, schnell und schlank ist und
+mühelos durch die Daten-Ozeane navigiert. Ausserdem mögen wir Delphine.
+
+Das Original-MySQL-Logo darf nur von Repräsentanten von MySQL AB und von
+Personen benutzt werden, die eine schriftliche Erlaubnis hierfür haben.
+
+@node MySQL Logos that may be Used Without Written Permission, When need MySQL logo permission, The Original MySQL logo, MySQL AB Logos and Trademarks
+@c German node MySQL-Logos die ohne schriftliche Erlaubnis benutzt werden dürfen
+@subsubsection MySQL-Logos die ohne schriftliche Erlaubnis benutzt werden dürfen
+
+@c FIX: pictures: powered by, works with, included - logos
+
+Wir haben einen Satz spezieller Logos für @emph{vorbehaltliche
+Benutzung} angelegt, die von unserer Website unter
+@uref{http://www.mysql.com/downloads/logos.html} herunter geladen werden
+können und von Dritten auf ihren Websites ohne schriftliche Erlaubnis
+von MySQL AB benutzt werden dürfen. Der Gebrauch dieser Logos ist - wie
+der Name anzeigt - nicht völlig uneingeschränkt, sondern unterliegt
+unseren Schutzmarken-Richtlinien, die Sie auf unserer Website finden.
+Sie sollten diese Richtlinien lesen, wenn Sie planen, die Logos zu
+benutzen. Die Anforderungen sind im Wesentlichen:
+
+@itemize @bullet
+@item
+Benutzen Sie das gewünschte Logo von der @uref{http://www.mysql.com/}-
+Site. Sie dürfen die Größe nach Ihren Bedürfnissen anpassen, aber keine
+Farben oder das Design ändern noch die Grafik in sonstiger Form
+verändern.
+
+@item
+Heben Sie hervor, dass Sie - und nicht MySQL AB - der Betreiber und
+Eigner der Site ist, auf der die MySQL-Schutzmarke gezeigt wird.
+
+@item
+Sie dürfen die Schutzmarke nicht auf eine Weise benutzen, die MySQL AB
+oder dem Wert der MySQL-AB-Schutzmarken schadet. Wir behalten uns das
+Recht vor, das Recht zur Benutzung der MySQL-AB-Schutzmarke zu
+widerrufen.
+
+@item
+Wenn Sie die Schutzmarke auf einer Website benutzen, machen Sie sie
+anklickbar, wobei direkt nach @uref{http://www.mysql.com/} verlinkt
+wird.
+
+@item
+Wenn Sie die MySQL-Datenbank unter GPL in einer Applikation benutzen,
+muss Ihre Applikation (i) Open Source sein, (ii) in der Lage sein, sich
+mit einem MySQL-Server zu verbinden.
+@end itemize
+
+Setzen Sie sich unter @email{trademark@@mysql.com} mit uns in
+Verbindung, um wegen spezieller Arrangements anzufragen, die Ihren
+Bedürfnissen entsprechen.
+
+@node When need MySQL logo permission, MySQL AB Partnership Logos, MySQL Logos that may be Used Without Written Permission, MySQL AB Logos and Trademarks
+@c German node Wann Sie eine Erlaubnis für die Benutzung des MySQL-Logos benötigen
+@subsubsection Wann Sie eine Erlaubnis für die Benutzung des MySQL-Logos benötigen
+
+In folgenden Fällen benötigen Sie eine schriftliche Erlaubnis von MySQL
+AB, bevor Sie die MySQL-Logos benutzen:
+
+@itemize @bullet
+@item
+Wenn Sie irgend ein MySQL-AB-Logo irgendwo ausser auf Ihrer Website
+zeigen.
+
+@item
+Wenn Sie irgend ein MySQL-AB-Logo ausser den oben erwähnten Logos zur
+@emph{vorbehaltlichen Benutzung} auf Websites oder anderswo anzeigen.
+@end itemize
+
+Aus rechtlichen und kommerziellen Gründen müssen wir die Benutzung der
+MySQL-Schutzmarken auf Produkten, Büchern usw. beobachten. Üblicherweise
+verlangen wir eine Gebühr für das Anzeigen von MySQL-AB-Logos auf
+kommerziellen Produkten, weil wir der Meinung sind, das es vertretbar
+ist, dass einige der Erlöse für die Weiterentwicklung der MySQL-
+Datenbank zurückfließen.
+
+@node MySQL AB Partnership Logos, , When need MySQL logo permission, MySQL AB Logos and Trademarks
+@c German node MySQL-AB-Partnerschafts-Logos
+@subsubsection MySQL-AB-Partnerschafts-Logos
+
+@c FIX: pictures: partnership logos - Bertrand?
+
+@c German FIX part of the this paragraph was at the end of Lizenzpolitik.
+@c (i.e. that section was pasted into the middle of this one ;-)
+MySQL-Partnerschafts-Logos dürfen nur von Unternehmen und Personen
+benutzt werden, die eine schriftliche Partnerschaftsvereinbarung mit
+MySQL AB haben. Partnerschaften beinhalten eine Zertifizierung als
+MySQL-Trainer oder -Berater. Sehen Sie bitte unter
+@c German FIX change @xref into @ref 'cos it's not a separate sentence.
+@ref{Business Services Partnering,,Partnerschaft} nach.
+
+@node Lizenzpolitik, , MySQL AB Logos and Trademarks, Licensing and Support
+@c German node <no English equivalent>
+@subsection MySQL-Lizenzpolitik
+
+@cindex Lizenzpolitik
+@cindex technischer Support, Lizensierung
+@cindex Support, Lizensierung
+@cindex General Public License, MySQL
+
+Die formalen Bedingungen der GPL-Lizenz stehen unter @ref{GPL license}.
+Im Wesentlichen ist unsere Lizenzpolitik und die Interpretation der
+GPL wie folgt:
+
+Beachten Sie bitte, dass ältere Versionen von MySQL immer noch einer
+@uref{http://www.mysql.com/Support/arrangements/mypl.html, strengeren
+Lizenz} unterliegen. Sehen Sie in der Dokumentation der betreffenden
+Version wegen entsprechender Informationen nach. Wenn Sie eine kommerzielle
+Lizenz benötigen, weil die GPL-Lizenz nicht zu den Anforderungen Ihrer
+Applikation passt, können Sie eine Lizenz unter
+@uref{https://order.mysql.com/} kaufen.
+
+Für normalen internen Gebrauch kostet MySQL nichts. Sie brauchen uns nichts
+zu bezahlen, wenn Sie nicht wollen.
+
+Eine Lizenz wird benötigt:
+
+@itemize @minus
+@item
+Wenn Sie ein Programm, das nicht freie Software ist, mit Code des
+MySQL-Servers oder der Client-Programme verbinden, die den GPL-Copyrights
+unterliegen. Das ist zum Beispiel der Fall, wenn Sie MySQL als
+eingebetteten Server (Embedded Server) in Ihren Applikationen benutzen,
+oder wenn Sie dem MySQL-Server Erweiterungen hinzufügen, die nicht freie
+Software sind. In diesen Fällen würden Ihre Applikation bzw. Ihr Code
+ebenfalls GPL werden, weil die GPL in solchen Fällen wie ein Virus wirkt.
+Sie können dieses Problem vermeiden, wenn Sie den MySQL-Server mit einer
+kommerziellen Lizenz von MySQL AB erwerben.
+Siehe @uref{http://www.gnu.org/copyleft/gpl-faq.html}.
+@item
+Wenn Sie eine kommerzielle Applikation haben, die NUR mit MySQL
+funktioniert, und wenn Sie die Applikation zusammen mit dem MySQL-Server
+ausliefern. Wir betrachten so etwas als Einbindung, selbst wenn es über das
+Netzwerk geschieht.
+
+@item
+Wenn Sie eine Distribution von MySQL besitzen und nicht den Quelltext für
+Ihre Kopie des MySQL-Servers zur Verfügung stellen, so wie es in der
+GPL-Lizenz festgelegt ist.
+xxx You have a Distribution of MySQL und you xxx Arjen: What does this mean: ...don't provide the
+source code for your copy of the MySQL server ... xxx Shouldn't it be: for your application ... ??? xxx
+, as defined in the GPL license. xxx
+@end itemize
+
+Eine Lizenz wird @strong{NICHT} benötigt:
+
+@itemize @minus
+
+@item
+Sie benötigen keine Lizenz, wenn Sie den Client-Code in kommerzielle
+Programme einschliessen. Der Client-Teil von MySQL unterliegt der
+LGPL @code{GNU Library General Public License}-Lizenz. Der
+@code{mysql}-Kommandozeilen-Client beinhaltet Code der
+@code{readline}-Bibliothek, die unter @code{GPL} steht.
+
+@item
+Wenn Sie für Ihre Art der Benutzung von MySQL keine Lizenz benötigen, aber
+MySQL mögen und die weitere Entwicklung fördern wollen, sind Sie herzlich
+eingeladen, in jedem Fall eine Lizenz zu erwerben.
+
+@item
+Wenn Sie MySQL in einem kommerziellen Zusammenhang benutzen und davon
+profitieren, bitten wir Sie, dass Sie die Weiterentwicklung von MySQL
+fördern, indem Sie einen bestimmten Grad von Support kaufen. Wir meinen,
+dass es vernünftig ist, wenn wir Sie bitten, MySQL zu unterstützen, wenn
+MySQL Ihren Geschäften hilft. (Ansonsten würde es bei Support-Anfragen
+bedeuten, dass Sie nicht nur etwas für umsonst benutzen, in das wir eine
+Menge Arbeit gesteckt haben, sondern dass Sie uns auch noch auffordern,
+kostenlosen Support zu liefern.)
+@end itemize
+
+In Situationen, wo eine MySQL-Lizenz benötigt wird, brauchen Sie eine
+Lizenz pro Maschine, auf der der MySQL-Server läuft. Eine
+Mehrprozessor-Maschine zählt jedoch als eine einzelne Maschine, und es gibt
+keine Beschränkung hinsichtlich der Anzahl von MySQL-Servern, die auf einer
+Maschine laufen, oder hinsichtlich der Anzahl von Clients, die zur gleichen
+Zeit mit einem Server verbunden sind, der auf dieser Maschine läuft!
+
+Falls Sie nicht sicher sind, ob für Ihre spezielle Benutzung von MySQL eine
+Lizenz erforderlich ist, lesen Sie diesen Abschnitt bitte nochmals, bevor
+Sie uns kontaktieren. @xref{Contact information}.
+
+Wenn Sie eine MySQL-Lizenz benötigen, ist die Bezahlung am einfachsten,
+wenn Sie das Lizenzformular auf dem Secure-Server von MySQL unter
+@uref{https://order.mysql.com/} benutzen.
+@c German FIX this section no longer exists (no price info in manual)
+@c Andere Zahlungsformen werden unter @ref{Zahlungsinformationen} besprochen.
+
+
+@menu
+* Using MySQL word in presentations::
+* Using MySQL word in company and product names::
+@end menu
+
+@node Using MySQL word in presentations, Using MySQL word in company and product names, Lizenzpolitik, Lizenzpolitik
+@c German node Benutzung des Worts MySQL in Präsentationen
+@subsubsection Benutzung des Worts @code{MySQL} in Druckmaterialien oder
+Präsentationen
+
+MySQL AB begrüßt Verweise auf die MySQL-Datenbank, aber das Wort
+@code{MySQL} ist eine Schutzmarke von MySQL AB. Deshalb müssen Sie der
+ersten oder deutlichsten Erwähnung des Worts @code{MySQL} das
+Schutzmarken-Symbol @code{TM} hinzufügen, und wo angebracht deutlich
+machen, dass @code{MySQL} eine Schutzmarke von MySQL AB ist. Details
+entnehmen Sie bitte unserer Schutzmarken-Richtlinie unter
+@uref{http://www.mysql.com/company/trademark.html}.
+
+
+@node Using MySQL word in company and product names, , Using MySQL word in presentations, Lizenzpolitik
+@c German node Benutzung des Worts MySQL in Unternehmens- und Produktnamen
+@subsubsection Benutzung des Worts @code{MySQL} in Unternehmens- und
+Produktnamen
+
+Die Benutzung des Worts @code{MySQL} in Produkt- und Unternehmensnamen
+oder in Internet-Domänen-Namen ist nur mit vorheriger schriftlicher
+Erlaubnis durch MySQL AB gestattet.
+
+
+@node MySQL 4.0 In A Nutshell, MySQL Information Sources, Licensing and Support, Deutsch
+@c German node MySQL 4.0 kurz und bündig
+@section MySQL 4.0 kurz und bündig
+
+Dateline: 16. Oktober 2001, Uppsala, Schweden
+
+Lange durch MySQL AB angekündigt und lange von unseren Benutzern
+erwartet: Der MySQL-Server 4.0 ist jetzt in der Alpha-Version zum
+Herunterladen von @uref{http://www.mysql.com/} und unseren Mirrors
+verfügbar.
+
+Die neuen Haupt-Features des MySQL-Servers 4.0 sind eng mit unserem
+bestehenden Geschäft und den Community-Nutzern verzahnt. Durch ihn wird
+die MySQL-Datenbank-Software als Lösung für geschäftskritische
+Schwerlast-Datenbanksysteme verbessert. Weitere neue Features zielen auf
+die Benutzer eingebetteter Datenbanken.
+
+
+
+@menu
+* Nutshell Stepwise Rollout::
+* Nutshell Ready for Immediate Development Use::
+* Nutshell Embedded MySQL::
+* Nutshell Other features::
+* Nutshell Future features::
+* Nutshell 4.1 development release::
+@end menu
+
+@node Nutshell Stepwise Rollout, Nutshell Ready for Immediate Development Use, MySQL 4.0 In A Nutshell, MySQL 4.0 In A Nutshell
+@c German node Kurz und bündig - Schritt für Schritt
+@subsection Schritt für Schritt
+
+Das Erscheinen des MySQL-Servers 4.0 wird in mehreren Schritten
+erfolgen, wobei die erste Version 4.0.0 genannt wird und bereits die
+meisten neuen Features enthält. Zusätzliche Features werden in die
+Versionen 4.0.1, 4.0.2 usw. eingebaut, höchstwahrscheinlich innerhalb
+weniger Monate. MySQL 4.0 wird als Beta gekennzeichnet. In MySQL 4.1
+werden dann weitere neue Features hinzugefügt. Es wird angestrebt, das
+Alpha-Release Anfang 2002 herauszubringen.
+
+
+@node Nutshell Ready for Immediate Development Use, Nutshell Embedded MySQL, Nutshell Stepwise Rollout, MySQL 4.0 In A Nutshell
+@c German node Kurz und bündig - für den sofortigen Entwicklungseinsatz
+@subsection Für den sofortigen Entwicklungseinsatz
+
+Es wird nicht empfohlen, Produktionssysteme auf den MySQL-Server 4.0
+umzustellen, bis dieser in der Beta-Version veröffentlicht wird. Selbst
+das anfängliche Release hat unsere ausgiebigen Tests ohne jegliche
+Fehler durchlaufen, auf allen Plattformen, auf denen wir testen. Wegen
+der großen Zahl neuer Features empfehlen wir daher den MySQL-Server
+selbst in der Alpha-Version für Entwicklungsarbeiten, wobei in Betracht
+gezogen werden kann, dass der MySQL-Server 4.0 das Stadium "stabil"
+erreichen wird, bevor Applikationen hiermit veröffentlicht werden, die
+jetzt im Entwicklungsstadium sind.
+
+
+@node Nutshell Embedded MySQL, Nutshell Other features, Nutshell Ready for Immediate Development Use, MySQL 4.0 In A Nutshell
+@c German node Kurz und bündig - eingebettetes MySQL
+@subsection Eingebettetes MySQL
+
+@code{libmysqld} macht den MySQL-Server für einen erheblich ausgedehnten
+Bereich von Applikationen geeignet. Wenn man die eingebettete MySQL-
+Server-Bibliothek benutzt, kann man den MySQL-Server in
+unterschiedlichste Applikationen und elektronische Geräte einbetten, bei
+denen der Endbenutzer keinerlei Ahnung davon hat, dass ihnen eine
+Datenbank unterlegt ist. Der eingebettete MySQL-Server ist ideal für
+Benutzung hinter den Kulissen in Internet-Geräten, öffentlichen Kiosken,
+schlüsselfertigen Hardware-/Software-Einheiten, Hochlast-Internet-
+Servern oder Datenbanken, die auf CD-ROM vertrieben werden.
+
+Viele Benutzer von eingebettetem MySQL können von der @emph{dualen
+Lizensierung} der MySQL-Software profitieren. Neben der GPL-Lizenz sind
+auch kommerzielle Lizenzen für diejenigen verfügbar, die nicht an die
+GPL gebunden sein wollen. Die eingebettete MySQL-Bibliothek benutzt
+dieselbe Schnittstelle wie die normale Client-Bibliothek und ist daher
+angenehm und leicht zu benutzen. @xref{libmysqld}.
+
+
+@node Nutshell Other features, Nutshell Future features, Nutshell Embedded MySQL, MySQL 4.0 In A Nutshell
+@c German node Kurz und bündig - weitere Features
+@subsection Weitere ab MySQL 4.0.0 verfügbare Features
+
+@itemize @bullet
+@item
+Version 4.0 erhöht die @emph{Geschwindigkeit des MySQL-Servers} in
+einigen Bereichen noch weiter, zum Beispiel bei Massen-@code{INSERT}s,
+beim Suchen auf komprimierten Indexen, der Erzeugung von
+@code{FULLTEXT}-Indexen oder auch bei @code{COUNT(DISTINCT)}.
+
+@item
+Der Tabellen-Handler @code{InnoDB} wird jetzt als Feature des
+standardmäßigen MySQL-Servers angeboten und enthält vollständige
+Unterstützung für @code{Transaktionen} und @code{Sperren auf
+Zeilenebene}.
+
+@item
+Der MySQL-Server 4.0 unterstützt sichere Kommunikation zwischen Client
+und Server, wodurch die Sicherheit gegen böswilliges Eindringen und
+unbefugten Zugriff erheblich erhöht wird. Bei Web-Applikationen, die ein
+Grundpfeiler der MySQL-Benutzung sind, konnten Web-Entwickler immer
+schon SSL verwenden, um den Verkehr zwischen Endbenutzer-Browser und der
+Web-Applikation zu sichern, sei sie nun in PHP, Perl, ASP oder mit
+irgend einem anderen Web-Entwicklungswerkzeug geschrieben. Der Verkehr
+zwischen dem Entwicklungswerkzeug und dem mysqld-Serverprozess konnte
+bislang aber nur dadurch gesichert werden, dass die Prozesse auf
+Computern innerhalb derselben Firewall residierten. Ab MySQL-Server 4.0
+kann der @emph{mysqld}-Server-Daemon-Prozess selbst @code{Secure Sockets
+Layer} (@code{SSL}) benutzen, was ihn in die Lage versetzt, eine sichere
+Datenübertragung zwischen einer MySQL-Datenbank und beispielsweise einer
+Windows-Applikation ausserhalb der Firewall aufzubauen.
+
+@item
+Unsere deutschen, österreichischen und schweizerischen Benutzer werden
+bemerken, dass es einen neuen Zeichensatz latin_de gibt, der die
+@emph{deutsche Sortierreihenfolge} beinhaltet, indem deutsche Umlaute in
+derselben Sortierung erscheinen wie bei deutschen Telefonbüchern üblich.
+
+@item
+Zu den Features, die die @code{Migration} von anderen Datenbanksystemen
+zum MySQL-Server erleichtern, gehören @code{TRUNCATE TABLE} (wie in
+Oracle) und @code{IDENTITY} a1s Synonym für automatisch hochgezählte
+Schlüssel (wie in Sybase). viele Benutzer werden sich auch darüber
+freuen, dass der MySQL-Server jetzt das @code{UNION}-Statement
+unterstützt, ein lang erwartetes Standard-SQL-Feature.
+
+@item
+Bei der Erstellung neuer Features für neue Benutzer haben wir die
+Gemeinschaft treuer Benutzer nicht vergessen. Es gibt jetzt Multi-
+Tabellen-@code{DELETE}-Statements. Durch das Hinzufügen von
+Unterstützung für @code{symbolisches Verknüpfen} von @code{MyISAM} auf
+Tabellenebene (und nicht nicht - wie bisher - auf Datenbankebene), sowie
+durch das vorgabemäßige Anschalten der Verknüpfungen unter Windows
+hoffen wir zeigen zu können, dass wir Verbesserungsvorschläge ernst
+nehmen. Funktionen wie @code{SQL_CALC_FOUND_ROWS} und
+@code{FOUND_ROWS()} ermöglichen herauszufinden, wie viele Zeilen eine
+Anfrage ohne eine @code{LIMIT}-Klausel zurückgegeben hätte.
+@end itemize
+
+
+@node Nutshell Future features, Nutshell 4.1 development release, Nutshell Other features, MySQL 4.0 In A Nutshell
+@c German node Kurz und bündig - zukünftige Features
+@subsection Zukünftige Features in MySQL 4.0
+
+Für die kommenden Releases des MySQL-Servers 4.0 (4.0.1, 4.0.2 usw.)
+können Sie folgende Features erwarten, die noch in der Entwicklung sind:
+
+@itemize @bullet
+@item
+Benutzer des MySQL-Servers für geschäftskritische Hochlast-Anwendungen
+werden die Ergänzungen unseres Replikationssystems und unsere Online-
+"Hot"-Datensicherung begrüßen. Spätere Versionen von 4.0 werden
+@code{absturzsichere Replikation} beinhalten, die es bereits in Version
+4.0.0 gibt, sowie den @code{LOAD DATA FROM MASTER}-Befehl, der bald das
+Aufsetzen von Slaves automatisieren wird. @code{online backup} wird das
+Hinzufügen eines neuen Replikations-Slaves erleichtern, ohne dass man
+den Master herunterfahren muss, und es gibt auf Systemen mit vielen
+Aktualisierungen nur geringe Geschwindigkeitseinbussen.
+
+@item
+Als Bequemlichkeits-Feature für Datenbank-Administratoren wird
+hinzugefügt, dass mysqld-Parameter (Startoptionen) bald ohne das
+Herunterfahren des Servers gesetzt werden können.
+
+@item
+Die neuen Eigenschaften des MySQL-Servers 4.0 für die Volltext-
+(@code{FULLTEXT})-Suche ermöglichen die @code{FULLTEXT}-Indexierung
+großer Texte sowohl mit binärer wie auch mit natürlichsprachiger
+Suchlogik. Benutzer können minimale Wortlängen anpassen und ihre
+eigenen Stopp-Wort-Listen in jeder menschlichen Sprache festlegen,
+wodurch gänzlich neue Applikationen ermöglicht werden, die auf dem
+MySQL-Server aufbauen.
+
+@item
+Viele Applikationen mit starkem Lesezugriff werden durch die noch weiter
+erhöhte Geschwindigkeit des neu geschriebenen @code{Schlüssel-Caches}
+profitieren.
+
+@item
+Viele Entwickler wird auch die @code{MySQL-Befehlshilfe} im Client
+freuen.
+@end itemize
+
+
+@node Nutshell 4.1 development release, , Nutshell Future features, MySQL 4.0 In A Nutshell
+@c German node Kurz und bündig - Entwicklungs-Release
+@subsection MySQL 4.1, das folgende Entwicklungs-Release
+
+Intern wird durch das neue .frm-Dateiformat für Tabellendefinitionen in
+MySQL-Server 4.0 die Grundlage für neue Features in MySQL-Server 4.1
+gelegt, beispielsweise @code{verschachtelte Unterabfragen},
+@code{gespeicherte Prozeduren} und @code{Fremdschlüssel-
+Integritätsregeln}, die ganz oben auf der Wunschliste vieler unserer
+Kunden stehen. Daneben werden auch einfachere Erweiterungen wie Multi-
+Tabellen-@code{UPDATE}-Statements hinzugefügt.
+
+Nach diesen Ergänzungen werden Kritiker des MySQL-Datenbankservers es
+noch schwerer haben, auf Schwächen des MySQL-Datenbank-Managementsystems
+hinzuweisen. MySQL, das seit langem für seine Stabilität,
+Geschwindigkeit und Einfachheit der Benutzung bekannt ist, wird dann den
+Anforderungen sehr anspruchsvoller Käufer genügen.
+
+
+@node MySQL Information Sources, Compatibility, MySQL 4.0 In A Nutshell, Deutsch
+@c German node MySQL-Informationsquellen
+@section MySQL-Informationsquellen
+
+
+
+@menu
+* Portals::
+* Questions::
+@end menu
+
+@node Portals, Questions, MySQL Information Sources, MySQL Information Sources
+@c German node Portale
+@subsection MySQL-Portale
+
+@cindex MySQL-Portale
+@cindex Handbücher, über MySQL
+@cindex Bücher, über MySQL
+@cindex MySQL-Testimonials
+@cindex Benutzer, von MySQL
+@cindex News-Sites
+@cindex Suchmaschinen, Web
+@cindex Web-Suchmaschinen
+@cindex Online-Magazine
+@cindex Magazine, online
+@cindex Websites
+@cindex Dienstleistungen
+@cindex PHP, Websites
+@cindex Berater, Liste
+@cindex Web-Seiten, verschiedene
+@cindex @code{Contrib}-Verzeichnis
+@cindex URLs zu MySQL-Informationen
+@cindex MySQL-bezogene Informations-URLs
+
+Die MySQL-Portale (@uref{http://www.mysql.com/portal/}) auf unserer
+Website bieten ein breites Spektrum MySQL-bezogener Informationen und
+Links. Sie sind so aufgebaut, dass Sie leicht die Dinge finden, die Sie
+interessieren.
+
+Sie können sich als Benutzer registrieren. In diesem Fall können Sie
+alle Dinge in den Portalen kommentieren und bewerten und auch selbst
+Dinge beisteuern. Bei der Registrierung können Sie auch angeben, ob und
+- wenn ja - welche Newsletter aus welchen Kategorien Sie beziehen
+wollen.
+
+Einige der momentanen MySQL-Portal-Kategorien:
+
+@itemize @bullet
+@item Bücher
+Hier finden Sie alle möglichen MySQL- oder Computer-bezogenen Bücher, die
+Sie kommentieren, bewerten oder kaufen können. Während dieses Handbuch
+(insbesondere die Online-Version) immer noch der richtige Platz für
+aktuellste technische Informationen ist, ist sein vorrangiges Ziel,
+alles zu enthalten, was man über das MySQL-Datenbanksystem wissen kann.
+Manchmal ist es nett, ein gebundenes Buch zu haben, dass man im Bett
+oder auf Reisen lesen kann. Wenn Sie ein Buch über die angegebenen
+Hyperlinks kaufen, tragen Sie zur Entwicklung der MySQL-Software bei.
+
+@item Entwicklung
+Dieses Portal hat Links auf Seiten, die den MySQL-Server für
+unterschiedliche Zwecke benutzen, mit einer Beschreibung jeder Site.
+Diese Informationen können Ihnen eine gute Vorstellung davon geben, wer
+MySQL-Datenbank-Software benutzt und wie der MySQL-Server ihre
+Anforderungen erfüllt.
+Teile Sie uns auch @emph{Ihre} Site oder Erfolgsgeschichte mit!
+
+@item Software
+Hier finden Sie eine Vielzahl von Applikationen und Wrappern, die den
+MySQL-Server benutzen, die Sie auch herunter laden können.
+
+@item Distributionen
+Hier finden Sie die verschiedenen Linux-Distributionen und weitere
+Software-Pakete, die die MySQL-Software enthalten.
+
+@item Berater
+Hier finden Sie Informationen über MySQL-Berater.
+
+@item Partner
+Hier finden Sie alle MySQL-Partner.
+@end itemize
+
+
+@node Questions, , Portals, MySQL Information Sources
+@c German node Fragen
+@subsection MySQL-Mailing-Listen
+
+@cindex Berichten, Fehler
+@cindex MySQL-Mailing-Listen
+
+
+Dieser Abschnitt führt Sie in die MySQL-Mailing-Listen ein und zeigt einige
+Richtlinien und ihre Benutzung auf.
+
+
+@menu
+* Mailing-list::
+* Asking questions::
+* Bug reports::
+* Answering questions::
+@end menu
+
+@node Mailing-list, Asking questions, Questions, Questions
+@c German node Mailing-Listen
+@subsubsection Die MySQL-Mailing-Listen
+
+@cindex Mailing-Listen
+@cindex E-Mail-Listen
+
+Um die MySQL-Haupt-Mailing-Liste zu abonnieren, schicken Sie eine Nachricht
+an die E-Mail-Adresse @email{mysql-subscribe@@lists.mysql.com}.
+
+Um sich aus der MySQL-Haupt-Mailing-Liste auszutragen, schicken Sie eine
+Nachricht an die E-Mail-Adresse @email{mysql-unsubscribe@@lists.mysql.com}.
+
+Von Bedeutung ist nur die Adresse, unter der Sie Ihre Nachrichten
+abschicken. Betreffzeile und Text der Nachricht werden ignoriert.
+
+@c the last two addresses in this paragraph are NOT @email because they
+@c shouldn't be live links.
+Wenn Ihre Antwortadresse nicht gültig ist, können Sie Ihre Adresse explizit
+angeben. Fügen Sie einen Bindestrich zum Abonnement- oder
+Abmelde-Kommando hinzu, gefolgt von Ihrer Adresse, wobei das
+@samp{@@}-Zeichen in Ihrer Adresse durch @samp{=} ersetzt wird. Um sich zum
+Beispiel mit @code{your_name@@host.domain} einzutragen, schicken Sie eine
+Nachricht an @code{mysql-subscribe-your_name=host.domain@@lists.mysql.com}.
+
+Mails an @email{mysql-subscribe@@lists.mysql.com} oder
+@email{mysql-unsubscribe@@lists.mysql.com} werden automatisch vom ezmlm
+Mailing-Listen-Prozessor bearbeitet. Informationen über ezmlm sind
+auf @uref{http://www.ezmlm.org, The ezmlm Website} verfügbar.
+
+Um eine Nachricht an die Liste selbst zu schicken, schicken Sie eine Mail
+an @code{mysql@@lists.mysql.com}. Schicken aber bitte @emph{keine} Mail an
+@email{mysql@@lists.mysql.com}, die das Abonnieren oder Austragen betrifft,
+denn Mails an diese Adresse werden automatisch an tausende anderer Benutzer
+verteilt.
+
+@c __review__jan_2001_11_13
+Wenn Ihre lokale Site viele Abonnenten für @email{mysql@@lists.mysql.com}
+hat, sollten Sie evtl. eine lokale Mailing-Liste einrichten, so dass
+Nachrichten, die von @code{lists.mysql.com} an Ihre Site gesandt werden, an
+die lokale Liste verteilt werden. In solchen Fällen wenden Sie sich bitte
+an Ihre Systemadministrator, um zur lokalen Mailing-Liste hinzugefügt oder
+aus ihr gelöscht zu werden.
+
+Wenn Sie wollen, dass der Traffic einer Mailing-Liste in eine separate
+Mailbox Ihres E-Mail-Programms geleitet wird, setzen Sie einen Filter,
+der auf die E-Mail-Header (Kopfdaten) reagiert. Sie können dazu entweder
+den @code{List-ID:}- oder den @code{Delivered-To:}-Header benutzen, um die
+Listennachrichten zu erkennen.
+
+Die folgenden MySQL-Mailing-Listen existieren:
+
+@table @code
+@item @email{announce-subscribe@@lists.mysql.com} announce
+Diese Liste kündigt neue Versionen von MySQL und verwandter Programme an.
+Sie hat geringen Traffic; alle MySQL-Benutzer sollten sie abonnieren.
+
+@item @email{mysql-subscribe@@lists.mysql.com} mysql
+Die Hauptliste für allgemeine MySQL-Diskussionen. Bitte beachten Sie, dass
+bestimmte Themen besser in spezialisierteren Listen diskutiert werden. Wenn
+Sie an die falsche Liste posten, erhalten Sie vielleicht keine Antwort!
+
+@item @email{mysql-digest-subscribe@@lists.mysql.com} mysql-digest
+Die @code{mysql}-Liste in Digest-Form (zusammengefasst). Anstelle
+individueller Nachrichten wird einmal pro Tag eine große Mail mit allen
+Nachrichten dieses Tages geschickt.
+
+@item @email{bugs-subscribe@@lists.mysql.com} bugs
+An diese Liste sollte Sie ausschließlich komplette, wiederholbare
+Bug-Berichte schicken, indem Sie das @code{mysqlbug}-Skript benutzen. (Wenn
+Sie unter Windows arbeiten, sollten Sie eine Beschreibung des
+Betriebssystems und der MySQL-Version hinzufügen.)
+Vorzugsweise sollten Sie den Problemfall mit der letzten stabilen oder
+Entwicklungs-Version von MySQL testen, bevor Sie den Bericht posten! Jeder
+sollte in der Lage sein, den Bug zu wiederholen, indem einfach @code{mysql
+test < Skript} auf den beigefügten Testfall angewandt wird. Alle Bugs, die
+auf dieser Liste gepostet werden, werden im nächsten MySQL-Release behoben
+oder dokumentiert! Wenn nur kleinere Code-Änderungen betroffen sind, werden
+wir zusätzlich ein Patch bereitstellen, das das Problem behebt.
+
+@item @email{bugs-digest-subscribe@@lists.mysql.com} bugs-digest
+Die Digest-Version (zusammengefasst) der @code{bugs}-Liste.
+
+@item @email{internals-subscribe@@lists.mysql.com} internals
+Eine Liste für Leute, die am MySQL-Code arbeiten. Auf dieser Liste kann man
+auch die MySQL-Entwicklung diskutieren und Patches posten.
+
+@item @email{internals-digest-subscribe@@lists.mysql.com} internals-digest
+Die Digest-Version (zusammengefasst) der @code{internals}-Liste.
+
+@item @email{java-subscribe@@lists.mysql.com} java
+Diskussionen über MySQL und Java, hauptsächlich über JDBC-Treiber.
+
+@item @email{java-digest-subscribe@@lists.mysql.com} java-digest
+Eine @code{java}-Liste.
+
+@item @email{win32-subscribe@@lists.mysql.com} win32
+Alles betreffend MySQL auf Microsoft-Betriebssystemen wie Win95, Win98, NT, XP,
+und Win2000.
+
+@item @email{win32-digest-subscribe@@lists.mysql.com} win32-digest
+Die Digest-Version (zusammengefasst) der @code{win32}-Liste.
+
+@item @email{myodbc-subscribe@@lists.mysql.com} myodbc
+Alles betreffend ODBC-Verbindungen zu MySQL.
+
+@item @email{myodbc-digest-subscribe@@lists.mysql.com} myodbc-digest
+Die Digest-Version (zusammengefasst) der @code{myodbc}-Liste.
+
+@item @email{plusplus-subscribe@@lists.mysql.com} plusplus
+Alles, was das Programmieren mit der C++-API von MySQL betrifft.
+
+@item @email{plusplus-digest-subscribe@@lists.mysql.com} plusplus-digest
+Die Digest-Version (zusammengefasst) der @code{plusplus}-Liste.
+
+@c __review_jan_2001_11_13
+@item @email{msql-mysql-modules-subscribe@@lists.mysql.com} msql-mysql-modules
+Eine Liste zur Perl-Unterstützung in MySQL. msql-mysql-modules
+
+@item @email{msql-mysql-modules-digest-subscribe@@lists.mysql.com} msql-mysql-modules-digest
+Die Digest-Version (zusammengefasst) der @code{msql-mysql-modules}-Liste.
+@end table
+
+Alle Listen abonnieren Sie - und tragen sich wieder aus - auf dieselbe Art
+wie oben beschrieben. Tragen Sie in Ihre Mail zum Abonnieren oder Austragen
+die entsprechende Mailing-Liste ein anstelle von @code{mysql}. Um sich zum
+Beispiel für die @code{myodbc}-Liste einzutragen, schicken Sie eine
+Nachricht an @email{myodbc-subscribe@@lists.mysql.com} oder
+@email{myodbc-unsubscribe@@lists.mysql.com}.
+
+Wenn Sie keine Antwort auf Ihre Fragen von der Mailing-Liste erhalten, ist
+eine Option, für den Support von MySQL AB zu bezahlen, was Sie in direkten
+Kontakt mit den MySQL-Entwicklern bringt. @xref{Support}.
+
+Die folgende Tabelle listet einige Mailing-Listen in anderen Sprachen als
+englisch auf. Beachten Sie, dass diese nicht von MySQL AB unterhalten
+werden. Daher können wir nicht für die Qualität dieser Listen garantieren.
+
+@table @code
+@item @email{mysql-france-subscribe@@yahoogroups.com} Eine französische Mailing-Liste
+@item @email{list@@tinc.net} Eine koreanische Mailing-Liste
+Schicken Sie eine E-Mail mit dem Betreff @code{subscribe mysql
+your@@email.address} an diese Liste.
+@item @email{mysql-de-request@@lists.4t2.com} Eine deutsche Mailing-Liste
+Schicken Sie eine E-Mail mit dem Betreff @code{subscribe mysql-de
+your@@email.address} an diese Liste.
+Informationen über diese Liste finden Sie unter
+@uref{http://www.4t2.com/mysql}.
+@item @email{mysql-br-request@@listas.linkway.com.br} Eine portugiesische Mailing-Liste.
+Schicken Sie eine E-Mail mit dem Betreff @code{subscribe mysql-br
+your@@email.address} an diese Liste.
+@item @email{mysql-alta@@elistas.net} Eine spanische Mailing-Liste.
+Schicken Sie eine E-Mail mit dem Betreff @code{subscribe mysql
+your@@email.address} an diese Liste.
+@end table
+
+
+@node Asking questions, Bug reports, Mailing-list, Questions
+@c German node Fragen stellen
+@subsubsection Wie man Fragen stellt oder Bugs berichtet
+
+@cindex Netz-Etikette
+@cindex Mailing-Listen, Speicherort der Archive
+@cindex Durchsuchen, MySQL-Webseiten
+
+Bevor Sie einen Bug berichten oder eine Frage stellen, tun Sie bitte
+folgendes:
+
+@itemize @bullet
+@item
+Suchen Sie im MySQL-Online-Handbuch:
+@*
+@uref{http://www.mysql.com/documentation/manual.php}
+@*
+Wir bemühen uns, das Handbuch aktuell zu halten, indem wir es häufig mit
+Lösungen für neu bekannt gewordene Probleme aktualisieren!
+
+@item
+Durchsuchen Sie die MySQL-Mailing-Listen-Archive:
+@*
+@uref{http://www.mysql.com/documentation/}
+@*
+@item
+Sie können ausserdem @uref{http://www.mysql.com/search.html} benutzen, um
+alle Webseiten zu durchsuchen (inklusive des Handbuchs), die unter
+@uref{http://www.mysql.com/} zu finden sind.
+@end itemize
+
+Wenn Sie weder im Handbuch noch in den Archiven eine Antwort finden können,
+versuchen Sie es mit Ihrem lokalen MySQL-Experten. Wenn Sie immer noch
+keine Antwort auf Ihre Frage finden, lesen Sie den nächsten Abschnitt über
+die Mailing-Listen unter @email{mysql@@lists.mysql.com}.
+
+
+@node Bug reports, Answering questions, Asking questions, Questions
+@c German node Bug-Berichte
+@subsubsection Wie man Bugs oder Probleme berichtet
+
+@cindex Bugs, berichten
+@cindex Berichten, Bugs
+@cindex Probleme, berichten
+@cindex Fehler, berichten
+@cindex @code{mysqlbug}-Skript
+@cindex Erzeugen, Bug-Berichte
+@cindex Skripts, @code{mysqlbug}
+
+Einen guten Bug-Bericht zu schreiben braucht Geduld, aber es gleich beim
+ersten Mal richtig zu machen spart Ihnen und uns Zeit. Ein guter
+Bug-Bericht enthält einen kompletten Testfall für den Bug, der es sehr
+wahrscheinlich macht, dass wir ihn im nächsten Release beheben. Dieser
+Abschnitt hilft Ihnen, Ihren Bericht korrekt zu schreiben, damit Sie Ihre
+Zeit nicht damit verschwenden, etwas zu schreiben, was uns wenig oder gar
+nicht weiterhilft.
+
+Wir ermutigen jeden, das @code{mysqlbug}-Skript zu benutzen, um einen
+Bug-Bericht anzufertigen (oder einen Bericht über irgendein anderes
+Problem), falls das möglich ist. Der @code{mysqlbug} findet sich im
+@file{Skripts}-Verzeichnis der Quelldistribution, bzw. im
+@file{bin}-Verzeichnis der Binärdistribution, im Verzeichnis unterhalb
+Ihres MySQL-Installationsverzeichnisses. Falls es Ihnen nicht möglich ist,
+@code{mysqlbug} zu benutzen, sollten Sie trotzdem alle notwendigen
+Informationen mitliefern, die in diesem Abschnitt aufgeführt sind.
+
+Das @code{mysqlbug}-Skript hilft Ihnen, einen Bericht zu erstellen, der
+viele der folgenden Informationen automatisch einschließt, aber falls
+etwas Wichtiges fehlt, fügen Sie es bitte Ihrer Nachricht hinzu! Bitte
+lesen Sie diesen Abschnitt sorgfältig und stellen Sie sicher, dass alle
+hier beschriebenen Informationen in Ihrem Bericht enthalten sind.
+
+@cindex Bug-Berichte, E-Mail-Adresse
+Für gewöhnlich sollten Sie Ihren Bug-Bericht und Probleme an
+@email{mysql@@lists.mysql.com} schicken. Wenn Sie einen Testfall erzeugen
+können, der den Bug klar demonstriert, sollten Sie ihn an die
+@email{bugs@@lists.mysql.com}-Liste schicken. Beachten Sie, dass Sie nur
+einen kompletten, nachvollziehbaren Bug-Bericht an diese Liste schicken
+sollten, indem Sie das @code{mysqlbug}-Skript benutzen. Falls Sie unter
+Windows arbeiten, sollten Sie eine Beschreibung des Betriebssystems und der
+MySQL-Version hinzufügen. Vorzugsweise sollten Sie den Problemfall mit der
+letzten stabilen oder Entwicklungs-Version von MySQL testen, bevor Sie den
+Bericht posten! Jeder sollte in der Lage sein, den Bug zu wiederholen,
+indem einfach @code{mysqltest < Skript} auf den beigefügten Testfall
+angewandt wird. Alle Bugs, die auf dieser Liste gepostet werden, werden im
+nächsten MySQL-Release behoben oder dokumentiert! Wenn nur kleinere
+Code-Änderungen betroffen sind, werden wir zusätzlich ein Patch
+bereitstellen, das das Problem behebt.
+
+Denken Sie daran, dass es immer möglich ist, auf eine Nachricht zu
+antworten, die zu viele Informationen enthält, aber nicht immer auf eine,
+die zu wenige Informationen enthält. Oft lassen Leute Fakten aus, weil sie
+denken, die Ursache eines Probleme zu kennen und annehmen, dass einige
+Details nicht von Wichtigkeit sind. Ein gutes Prinzip ist folgendes: Falls
+Sie im Zweifel sind, ob Sie etwas Bestimmtes mitteilen sollten, teilen Sie
+es mit! Es ist tausendmal schneller und weniger ärgerlich, ein paar Zeilen
+mehr in Ihrem Bericht zu schreiben, als gezwungen zu sein, noch einmal zu
+fragen und auf die Antwort zu warten, weil Sie beim ersten Mal nicht genug
+Informationen geliefert haben.
+
+Die häufigste Fehler besteht darin, dass Leute die Versionsnummer der
+MySQL-Distribution, die sie benutzen nicht angeben, oder vergessen anzugeben,
+auf welcher Plattform sie MySQL installiert haben (inklusive der
+Betriebssystem-Version). Diese Informationen sind äußerst relevant, und in
+99 von 100 Fällen ist der Bug-Bericht ohne sie nutzlos! Sehr oft erhalten
+wir Fragen wie 'Warum funktioniert das bei mir nicht?', nur um
+herauszufinden, dass das beschriebene Feature nicht in der benutzten
+MySQL-Version implementiert war, oder dass der Bug, der im Bericht
+beschrieben wurde, bereits in einer neueren MySQL-Version behoben wurde.
+Manchmal ist der Fehler plattformabhängig; in solchen Fällen ist es
+praktisch unmöglich, irgend etwas zu beheben, ohne das Betriebssystem und
+die Versionsnummer des Betriebssystems zu kennen.
+
+Denken Sie auch daran, Informationen über Ihren Compiler einzuschließen,
+falls sie MySQL selbst kompilieren. Oft finden Leute Fehler in
+Compilern und denken, dass das Problem MySQL-bezogen ist. Die meisten
+Compiler werden permanent weiter entwickelt und werden von Version zu
+Version besser. Um festzustellen, ob ein Problem von Ihrem Compiler abhängt
+oder nicht, müssen wir wissen, welcher Compiler benutzt wird. Beachten Sie,
+dass jedes Compiler-Problem als Bug-Bericht betrachtet und deshalb
+entsprechend berichtet werden sollte.
+
+Es ist äußerst hilfreich, wenn eine gute Beschreibung des Probleme in
+Ihrem Bug-Bericht eingeschlossen ist, das heißt ein gutes Beispiel aller
+Dinge, die Sie getan haben, die zu dem Problem führten, sowie das Problem
+selbst. Die besten Bug-Berichte sind diejenigen, die ein komplettes
+Beispiel zeigen, wie man den Bug oder das Problem reproduzieren kann.
+@xref{Reproduceable test case}.
+
+Wenn ein Programm eine Fehlermeldung produziert, ist es sehr wichtig,
+diese in Ihren Bericht einzuschließen! Wenn wir in den Archiven der
+Programme suchen, ist es besser, wenn die Fehlernachricht exakt mit
+derjenigen übereinstimmt, die das Programm produziert. (Sogar
+Groß-/Kleinschreibung sollte berücksichtigt werden!) Sie sollten nie
+versuchen, sich daran zu erinnern, was die Fehlernachricht war; stattdessen
+sollten Sie die gesamte Nachricht per Kopieren und Einfügen in Ihrem
+Bericht unterbringen!
+
+Wenn Sie ein Problem mit MyODBC haben, sollten Sie versuchen, eine
+MyODBC-Trace-Datei zu erstellen. @xref{MyODBC bug report}.
+
+Bitten denken Sie daran, dass viele Leute, die Ihren Bericht lesen, dabei
+ein 80-Spalten-Anzeigegerät benutzen. Wenn Sie Berichte oder Beispiele
+erzeugen, indem Sie das @code{mysql}-Kommandozeilen-Werkzeug benutzen, sollten
+Sie deshalb die @code{--vertical}-Option (oder den
+@code{\G}-Statement-Begrenzer) für Ausgaben benutzen, die ansonsten die
+verfügbare Anzeigebreite überschreiten würden (zum Beispiel beim
+@code{EXPLAIN SELECT}-Statement; siehe dazu das Beispiel weiter unten).
+@cindex Bug-Berichte, Kriterien für
+Bitte schließen Sie folgende Informationen in Ihren Bug-Bericht ein:
+
+@itemize @bullet
+@item
+Die Versionsnummer der MySQL-Distribution, die Sie benutzen (zum Beispiel
+MySQL Version 3.23.22). Sie finden heraus, welche Version Sie benutzen,
+indem Sie @code{mysqladmin version} eingeben. @code{mysqladmin} findet
+sich im @file{bin}-Verzeichnis unterhalb Ihres
+MySQL-Installationsverzeichnisses.
+
+@item
+Hersteller und Modell der Maschine, auf der Sie arbeiten.
+
+@item
+Name und Version des Betriebssystems. Bei den meisten Betriebssystemen
+läßt sich diese Information herausfinden, indem man das Unix-Kommando
+@code{uname -a} ausführt.
+
+@item
+Manchmal ist die Größe des Arbeitsspeichers (real und virtuell) relevant.
+Im Zweifelsfall schließen Sie diese Werte ein.
+
+@item
+Wenn Sie eine Quelldistribution von MySQL benutzen, werden Name und
+Versionsnummer des Compilers benötigt. Wenn Sie eine Binärdistribution
+haben, geben Sie den Namen der Distribution an.
+
+@item
+Wenn das Problem während der Kompilation auftritt, schließen Sie die
+exakte Fehlermeldung (bzw. -meldungen) ein und zusätzlich ein paar Zeilen
+des Kontextes um den problembehafteten Code herum in der Datei, wo der
+Fehler auftrat.
+
+@item
+Falls @code{mysqld} abstürzt, sollten Sie auch die Anfrage (Query)
+mitteilen, die @code{mysqld} zum Absturz brachte. Gewöhnlich können Sie das
+herausfinden, indem Sie @code{mysqld} mit angeschaltetem Logging laufen
+lassen. @xref{Using log files}.
+
+@item
+Falls irgend eine Datenbanktabelle mit dem Problem zu tun hat, schließen
+Sie die Ausgabe von @code{mysqldump --no-data db_name tbl_name1 tbl_name2
+...} ein. Das ist sehr leicht zu bewerkstelligen und eine sehr hilfreiche
+Möglichkeit, Informationen über jegliche Tabelle in einer Datenbank zu
+erhalten, die uns hilft, eine Situation herzustellen, die mit derjenigen
+übereinstimmt, die Sie haben.
+
+@item
+Bei Bugs, die sich auf Geschwindigkeitsprobleme beziehen, oder bei
+Problemen mit @code{SELECT}-Statements, sollten Sie immer die Ausgabe von
+@code{EXPLAIN SELECT ...} einschließen, und zumindest die Anzahl der
+Zeilen, die das @code{SELECT}-Statement produziert. Je mehr Informationen
+Sie uns über Ihre Situation geben, desto wahrscheinlicher ist es, dass
+Ihnen jemand helfen kann! Das folgende Beispiel ist ein sehr gutes Beispiel
+eines Bug-Berichts (es sollte natürlich mit dem @code{mysqlbug}-Skript
+berichtet werden):
+
+Beispiel unter Benutzung des @code{mysql}-Kommandozeilen-Werkzeugs (achten Sie
+auf die Benutzung des @code{\G}-Statement-Begrenzers für Statements, deren
+Ausgabebreite ansonsten die von 80-Zeilen-Ausgabegeräten überschreiten
+würde):
+
+@example
+mysql> SHOW VARIABLES;
+mysql> SHOW COLUMNS FROM ...\G
+ <Ausgabe von SHOW COLUMNS>
+mysql> EXPLAIN SELECT ...\G
+ <Ausgabe von EXPLAIN>
+mysql> FLUSH STATUS;
+mysql> SELECT ...;
+ <Eine Kurzfassung der Ausgabe von SELECT,
+ inclusive der Zeit, die die Anfrage benötigte>
+mysql> SHOW STATUS;
+ <Ausgabe von SHOW STATUS>
+@end example
+
+@item
+Wenn ein Problem auftritt, während @strong{mysqld} läuft, legen Sie nach
+Möglichkeit ein Eingabeskript bei, das die Anomalie reproduziert. Dieses
+Skript sollte alle notwendigen Quelltextdateien beinhalten. Je exakter das
+Skript Ihre Situation reproduzieren kann, desto besser. Wenn Sie einen
+wiederholbaren Testfall erstellen können, sollten Sie ihn an
+@email{bugs@@lists.mysql.com} schicken, damit er mit hoher Priorität
+behandelt wird!
+
+Falls Sie kein Skript zur Verfügung stellen können, sollten Sie zumindest
+die Ausgaben von @code{mysqladmin variables extended-status processlist} in
+Ihrer Mail mitschicken, um einige Informationen darüber zu geben, wie Ihr
+System arbeitet!
+
+@item
+Falls Sie keinen Testfall mit ein paar Zeilen produzieren können oder falls
+Ihre Tabelle zu Groß ist, um an die Mailing-Liste geschickt zu werden
+(mehr als 10 Zeilen), sollten Sie mit @code{mysqldump} einen Dump Ihrer
+Tabellen machen und eine @file{README}-Datei erzeugen, die Ihr Problem
+beschreibt.
+
+Erzeugen Sie ein komprimiertes Archiv Ihrer Dateien, indem Sie @code{tar}
+und @code{gzip} oder @code{zip} benutzen, und benutzen Sie @code{ftp}, um
+das Archiv nach @uref{ftp://Support.mysql.com/pub/mysql/secret/} zu
+transferieren. Schicken Sie danach eine kurze Beschreibung des Probleme an
+@email{bugs@@lists.mysql.com}.
+
+@item
+Wenn Sie glauben, dass MySQL auf eine Anfrage hin merkwürdige Ergebnisse
+liefert, fügen Sie nicht nur das Ergebnis bei, sondern auch, wie das
+Ergebnis Ihrer Meinung nach aussehen sollte, sowie eine Erklärung, wie Sie
+zu dieser Meinung gelangt sind.
+
+@item
+Wenn Sie ein Beispiel Ihres Problems schildern, ist es besser, die
+Variablen-, Tabellen- etc. Namen zu verwenden, die in Ihrer aktuellen
+Situation existieren, anstatt sich neue Namen auszudenken. Das Problem
+könnte nämlich etwas mit dem Namen der Variablen oder Tabelle zu tun haben!
+Diese Fälle sind zwar selten, aber hier sollte man lieber auf Nummer sicher
+gehen. Letztlich sollte es für Sie auch leichter sein, ein Beispiel zur
+Verfügung zu stellen, das Ihre tatsächliche Situation schildert, und es ist
+in jedem Fall besser für uns. Falls Sie mit Daten arbeiten, die Sie keinen
+anderen zeigen wollen, können Sie @code{ftp} benutzen, um die Daten nach
+@uref{ftp://Support.mysql.com/pub/mysql/secret/} zu transferieren. Falls
+die Daten streng geheim sind und Sie sie nicht einmal uns zeigen wollen,
+legen Sie bitte ein Beispiel mit anderen Namen an, betrachten Sie dies aber
+bitte als allerletzte Möglichkeit.
+
+@item
+Fügen Sie alle Optionen ein, die den relevanten Programmen übergeben
+wurden, falls möglich. Geben Sie zum Beispiel die Optionen an, die Sie
+benutzt haben, als Sie den @code{mysqld}-Daemon gestartet haben, und die
+Sie für Client-Programme wie @code{mysql} benutzen, sowie
+diejenigen, die Sie für die Konfiguration des @code{configure}-Skripts
+nehmen, denn diesen sind oft der Schlüssel für Antworten und deshalb
+äußerst relevant!
+Es ist immer eine gute Idee, sie in jedem Fall anzugeben! Wenn Sie Module
+wie Perl oder PHP benutzen, fügen Sie bitte die Versionszahl von diesen mit
+ein.
+
+@item
+Wenn sich Ihre Frage auf das Berechtigungssystem (Zugriffsberechtigungen auf
+den Datenbank-Server) bezieht, fügen Sie bitte die Ausgabe von
+@code{mysqlaccess}, die Ausgabe von @code{mysqladmin reload} und alle
+Fehlermeldungen, die Sie erhalten, wenn Sie versuchen, sich zu verbinden,
+bei! Wenn Sie Ihre Zugriffsberechtigungen testen, sollten Sie zunächst
+@code{mysqlaccess} ausführen. Führen Sie danach @code{mysqladmin reload
+version} aus und versuchen Sie dann, sich mit dem Programm zu verbinden,
+das Probleme macht. @code{mysqlaccess} liegt im @file{bin}-Verzeichnis
+unter Ihrem MySQL-Installationsverzeichnis.
+MySQL-Installationsverzeichnis.
+
+@item
+Wenn Sie einen Patch für ein Bug haben, ist das gut, aber nehmen Sie bitte
+nicht an, dass der Patch alles ist, was wir brauchen. Gehen Sie auch nicht
+davon aus, dass wir den Patch benutzen werden, wenn Sie nicht auch einige
+notwendige Informationen mitschicken, zum Beispiel Testfälle, die den Bug
+zeigen, der durch Ihren Patch behoben wird. Möglicherweise finden wir
+Probleme, die Ihr Patch verursacht, oder wir verstehen ihn überhaupt nicht.
+Wenn das der Fall ist, können wir ihn nicht benutzen.
+
+Wenn wir nicht genau feststellen können, wofür der Patch gedacht ist,
+werden wir ihn nicht benutzen. In diesen Fällen werden uns Testfälle weiter
+helfen. Zeigen Sie darin auf, dass der Patch all die Situationen bewältigt,
+die eintreten können. Falls wir einen Grenzfall finden (sogar, wenn es ein
+seltener ist), bei dem der Patch nicht funktioniert, ist er vielleicht
+nutzlos.
+
+@item
+Vermutungen, worin der Bug besteht, warum er auftritt oder wovon er
+abhängt, sind meist falsch. Selbst das MySQL-Team kann solche Dinge nicht
+erraten, sondern muss einen Debugger benutzen, um den wahren Grund des Bugs
+feststellen zu können.
+
+@item
+Geben Sie in Ihrer Mail zu erkennen, dass Sie das Referenzhandbuch gelesen
+und die Mail-Archive durchgesehen haben, damit andere wissen, dass Sie
+versucht haben, das Problem selbst zu lösen.
+
+@item
+Wenn Sie einen @code{parse error} erhalten, überprüfen Sie bitte genau Ihre
+Syntax! Wenn Sie nichts Falsches darin finden können, ist es sehr
+wahrscheinlich, dass Ihre aktuelle Version von MySQL die Anfrage, die Sie
+formuliert haben, nicht unterstützt. Wenn Sie die aktuelle Version benutzen
+und das Handbuch unter @uref{http://www.mysql.com/documentation/manual.php}
+die Syntax, die Sie benutzen, nicht beschreibt, unterstützt MySQL Ihre
+Anfrage nicht. In diesem Fall bleibt Ihnen nur, die Syntax entweder selbst
+zu implementieren oder per E-Mail an @email{mysql-licensing@@mysql.com}
+nach einem Angebot für die Implementation anzufragen!
+
+Wenn das Handbuch die Syntax, die Sie benutzen, beschreibt, Sie aber eine
+ältere Version von MySQL benutzen, sollten Sie in der
+MySQL-Änderungsgeschichte (Change History) nachsehen, wann die Syntax
+implementiert wurde. In diesem Fall haben Sie die Möglichkeit, ein Upgrade
+auf eine neuere Version von MySQL vorzunehmen.
+@xref{News}.
+
+@item
+Wenn Sie ein Problem in der Art haben, dass Ihre Daten anscheinend
+beschädigt sind oder Sie Fehlermeldungen bekommen, wenn Sie auf eine
+bestimmte Tabelle zugreifen, sollten Sie zunächst Ihre Tabellen überprüfen
+und anschließend reparieren, indem Sie @code{myisamchk} oder @code{CHECK
+TABLE} und @code{REPAIR TABLE} benutzen.
+@xref{MySQL Database Administration}.
+
+@item
+Wenn Sie oft beschädigte Tabellen erhalten, sollten Sie versuchen
+herauszufinden, wann und warum das geschieht! In diesem Fall kann die
+@file{mysql-data-directory/'hostname'.err}-Datei einige Informationen
+darüber enthalten, was geschehen ist. @xref{Error log}. Bitte fügen Sie
+jede relevante Information aus dieser Datei in Ihren Bug-Bericht ein!
+Normalerweise sollte @code{mysqld} @strong{NIE} eine Tabelle zerstören,
+ausser wenn der Server mitten während eines Updates gekillt wurde! Wenn Sie
+den Grund für den Absturz von @code{mysqld} herausfinden können, ist es
+sehr viel einfacher für uns, Ihnen eine Lösung des Problems an die Hand zu
+geben!
+@xref{What is crashing}.
+
+@item
+Falls möglich, sollten Sie die aktuellste Version von MySQL herunter laden,
+installieren und überprüfen, ob das Ihr Problem löst. Alle Versionen
+von MySQL werden gründlich getestet und sollten ohne Probleme
+funktionieren! Wir halten uns daran, alles so abwärtskompatibel wie
+möglich zu machen. Daher sollte es Ihnen möglich sein, innerhalb von
+Minuten die MySQL-Version auszutauschen!
+@xref{Which version}.
+@end itemize
+
+@cindex Technischer Support, E-Mail-Adresse
+@cindex Support, E-Mail-Adresse
+@cindex Kunden-Support, E-Mail-Adresse
+@cindex E-Mail-Adresse, für Kunden-Support
+Wenn Sie ein Support-Kunde sind, schicken Sie bitte den Bug-Bericht an
+@email{mysql-Support@@mysql.com}, damit dieser eine höhere Priorität in der
+Bearbeitung erfährt. Schicken Sie ihn gleichzeitig an die entsprechende
+Mailing-Liste, um zu sehen, ob schon jemand anderes das selbe Problem hatte
+(und vielleicht gelöst hat).
+
+Informationen zu Bug-Berichten siehe @strong{MyODBC} und @ref{ODBC Problems}.
+
+Lösungen für häufig auftretende Probleme siehe @xref{Problems}.
+
+Wenn Ihnen Antworten individuell zugesandt werden und nicht an die
+Mailing-Liste, wird es als gute Etikette betrachtet, die Antworten
+zusammenzufassen und die Zusammenfassung an die Mailing-Liste zu schicken,
+damit andere von den Antworten profitieren können, die Ihnen geholfen
+haben, Ihr Problem zu lösen!
+
+
+@node Answering questions, , Bug reports, Questions
+@c German node Fragen beantworten
+@subsubsection Richtlinien für die Beantwortung von Fragen auf der Mailing-Liste
+
+@cindex Netz-Etikette
+@cindex Fragen, Antworten
+@cindex Fragen beantworten, Etikette
+@cindex Mailing-Listen, Richtlinien
+
+Wenn Sie davon ausgehen, dass Ihre Antwort auf breites Interesse stößt,
+sollten Sie an die Mailing-Liste posten, statt direkt der Person zu
+antworten, die die Frage stellte. Versuchen Sie, Ihre Antwort so allgemein
+zu halten, dass auch andere als der ursprünglich Fragende von Ihrer Antwort
+profitieren können. Wenn Sie an die Liste posten, stellen Sie bitte sicher,
+dass Ihre Antwort kein Duplikat einer vorhergehenden Antwort ist.
+
+Versuchen Sie, den wesentlichen Teil der Frage in Ihrer Antwort
+zusammenzufassen. Fühlen Sie sich nicht verpflichtet, die gesamte
+ursprüngliche Nachricht zu zitieren.
+
+Bitte schicken Sie Ihre Mailnachrichten nicht im HTML-Format! Viele
+Benutzer lesen Nachrichten mit nicht HTML-fähigen Anwendungen!
+
+
+
+@node Compatibility, TODO, MySQL Information Sources, Deutsch
+@c German node Kompatibilität
+@section Wie Standard-kompatibel ist MySQL?
+
+@cindex Kompatibilität mit ANSI SQL
+@cindex Standard-Kompatibilität
+@cindex Erweiterungen von ANSI SQL
+@cindex ANSI SQL92, Erweiterungen
+
+
+Dieser Abschnitt beschreibt, wie sich MySQL zum ANSI SQL-Standard verhält.
+MySQL hat viele Erweiterungen zum ANSI SQL-Standard, und hier steht, welche
+das sind und wie man sie benutzt. Hier finden Sie auch Informationen über
+Funktionalität, die MySQL fehlt, und wie man mit diesen Unterschieden
+umgeht.
+
+
+@menu
+* Standards::
+* ANSI mode::
+* Extensions to ANSI::
+* Differences from ANSI::
+* Bugs::
+@end menu
+
+@node Standards, ANSI mode, Compatibility, Compatibility
+@c German node Standards
+@subsection An welche Standards hält sich MySQL?
+
+Entry-Level-SQL92. ODBC-Levels 0-2.
+
+Wir beabsichtigen ANSI SQL99 vollständig zu unterstützen. Dies
+wollen wir jedoch keinesfalls auf Kosten von Geschwindigkeit
+oder Codequalität erreichen.
+
+@node ANSI mode, Extensions to ANSI, Standards, Compatibility
+@c German node ANSI-Modus
+@subsection MySQL im ANSI-Modus laufen lassen
+
+@cindex Laufen lassen, ANSI-Modus
+@cindex ANSI-Modus, laufen lassen
+
+Wenn Sie @code{mysqld} mit der @code{--ansi}-Option starten, ändert sich
+folgendes Verhalten von MySQL:
+
+@itemize @bullet
+@item
+@code{||} ist Zeichenketten-Verkettung (Konkatenation) anstelle von
+@code{OR}.
+
+@item
+Sie können eine beliebige Anzahl von Leerzeichen zwischen Funktionnamen und
+@samp{(} eingeben. Das führt zwangsläufig dazu, dass alle Funktionsnamen
+als reservierte Wörter behandelt werden.
+
+@item
+@samp{"} ist dann ein Quotierungsbezeichner (wie das MySQL-
+@samp{`}-Anführungszeichen) und kein Zeichen, dass einen String einschließt.
+
+@item
+@code{REAL} wird zu einem Synonym für @code{FLOAT} anstelle eines Synonyms
+für @code{DOUBLE}.
+
+@item
+Der Standard-Isolationslevel für Transaktionen ist @code{SERIALIZABLE}.
+@xref{SET TRANSACTION}.
+@end itemize
+
+Das ist dasselbe, als würde man
+@code{--sql-mode=REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,SERIALIZE,ONLY_FULL_GROUP_BY}
+benutzen.
+
+@node Extensions to ANSI, Differences from ANSI, ANSI mode, Compatibility
+@c German node Erweiterungen zu ANSI
+@subsection MySQL-Erweiterungen zu ANSI SQL92
+
+@cindex Hinweise
+MySQL beinhaltet einige Erweiterungen, die Sie in anderen SQL-Datenbanken
+wahrscheinlich nicht finden werden. Passen Sie auf, wenn Sie diese
+benutzen, denn Ihr Code ist dann nicht mehr kompatibel mit anderen
+SQL-Servern. In einigen Fällen können Sie Code schreiben, der
+MySQL-Erweiterungen enthält und dennoch portabel ist, indem Sie Kommentare
+in der Form @code{/*! ... */} benutzen. In diesem Fall wird MySQL den Code
+innerhalb des Kommentars parsen und ausführen wie jedes andere
+MySQL-Statement, aber andere SQL-Server werden die Erweiterungen
+ignorieren. Zum Beispiel:
+
+@example
+SELECT /*! STRAIGHT_JOIN */ col_name FROM tabelle1, tabelle2 WHERE ...
+@end example
+
+Wenn Sie hinter @code{'!'} die Versionsnummer angeben, wird die Syntax nur
+ausgeführt, wenn die MySQL-Version gleich oder neuer als die benutzte
+Versionsnummer ist:
+
+@example
+CREATE /*!32302 TEMPORARY */ TABLE (a int);
+@end example
+
+Je höher bedeutet, wenn Sie Version 3.23.02 oder neuer haben, wird MySQL
+das @code{TEMPORARY}-Schlüsselwort benutzen.
+
+MySQL-Erweiterungen sind:
+
+@itemize @bullet
+@item
+Die Feldtypen @code{MEDIUMINT}, @code{SET}, @code{ENUM} und die
+unterschiedlichen @code{BLOB}- und @code{TEXT}-Typen.
+
+@item
+Die Feldattribute @code{AUTO_INCREMENT}, @code{BINARY}, @code{NULL},
+@code{UNSIGNED} und @code{ZEROFILL}.
+
+@item
+Alle Zeichenkettenvergleiche achten vorgabemäßig nicht auf
+Groß-/Kleinschreibung, wobei die Sortierreihenfolge vom aktuell
+verwendeten Zeichensatz abhängig ist (ISO-8859-1 Latin1 als Vorgabe). Wenn
+Sie das nicht wollen, sollten Sie Ihre Spalten mit dem
+@code{BINARY}-Attribut deklarieren oder den @code{BINARY}-Cast
+benutzen, der dafür sorgt, dass Vergleiche mit der ASCII-Sortierung
+durchgeführt werden, die der MySQL-Server-Host benutzt.
+
+@item
+MySQL legt jede Datenbank als Verzeichnis unterhalb des MySQL-data-
+Verzeichnisses an und Tabellen innerhalb einer Datenbank als Dateien in dem
+Datenbank-Verzeichnis.
+
+Das hat ein paar Auswirkungen:
+
+@cindex Datenbanknamen, Groß-/Kleinschreibung
+@cindex Tabellennamen, Groß-/Kleinschreibung
+@cindex Groß-/Kleinschreibung von Datenbanknamen
+@cindex Groß-/Kleinschreibung von Tabellennamen
+
+@itemize @minus
+
+@item
+Bei Datenbanknamen und Tabellennamen wird auf Unterschiede in der
+Groß-/Kleinschreibung geachtet, wenn das Betriebssystem auf
+Groß-/Kleinschreibung achtet (wie auf den meisten Unix-Systemen).
+@xref{Case sensitivity}.
+
+@item
+Datenbank-, Tabellen-, Index-, Spalten- oder Alias-Namen dürfen mit einer
+Ziffer beginnen (aber nicht ausschließlich aus Ziffern bestehen).
+
+@item
+Sie können Standard-Kommandos des Betriebssystems benutzen, um Tabellen zu
+sichern (Datensicherung), umzubenennen, zu verschieben, zu löschen und zu kopieren.
+Um zum Beispiel eine Tabelle umzubennen, benennen Sie die Dateien
+@file{.MYD}, @file{.MYI} und @file{.frm} um, die der Tabelle entsprechen.
+@end itemize
+
+@item
+In SQL-Statements können Sie Tabellen aus verschiedenen Datenbanken mit der
+@code{db_name.tbl_name}-Syntax ansprechen. Einige SQL-Syntax stellen
+dieselbe Funktionalität zur Verfügung, nennen dies aber @code{User space}.
+MySQL unterstützt keine Tablespaces wie in folgendem Beispiel:
+@code{create tabelle ralph.meine_tabelle...IN mein_tablespace}.
+
+@item
+@code{LIKE} ist für numerische Spalten erlaubt.
+
+@item
+Die Benutzung von @code{INTO OUTFILE} und @code{STRAIGHT_JOIN} in einem
+@code{SELECT}-Statement. @xref{SELECT, , @code{SELECT}}.
+
+@item
+Die Option @code{SQL_SMALL_RESULT} in einem @code{SELECT}-Statement.
+
+@item
+@code{EXPLAIN SELECT}, um eine Beschreibung zu erhalten, wie Tabellen
+verknüpft werden (Join).
+
+@item
+Die Benutzung von Index-Namen, Indexen auf ein Prefix eines Feldes, und die
+Benutzung von @code{INDEX} oder @code{KEY} in einem @code{CREATE TABLE}-
+Statement. @xref{CREATE TABLE, , @code{CREATE TABLE}}.
+
+@item
+Die Benutzung von @code{TEMPORARY} oder @code{IF NOT EXISTS} mit @code{CREATE TABLE}.
+
+@item
+Die Benutzung von @code{COUNT(DISTINCT list)}, wobei 'list' mehr als ein
+Element ist.
+
+@item
+Die Benutzung von @code{CHANGE spalten_name}, @code{DROP spalten_name}, oder
+@code{DROP INDEX}, @code{IGNORE} oder @code{RENAME} in einem @code{ALTER
+TABLE}-Statement. @xref{ALTER TABLE, , @code{ALTER TABLE}}.
+
+@item
+Die Benutzung von @code{RENAME TABLE}. @xref{RENAME TABLE, , @code{RENAME TABLE}}.
+
+@item
+Die Benutzung mehrfacher @code{ADD}-, @code{ALTER}-, @code{DROP}-, oder
+@code{CHANGE}-Klauseln in einem @code{ALTER TABLE} Statement.
+
+@item
+Die Benutzung von @code{DROP TABLE} mit the keywords @code{IF EXISTS}.
+
+@item
+Sie können mehrere Tabellen löschen mit einem einzigen @code{DROP
+TABLE}-Statement.
+
+@item
+Die @code{LIMIT}-Klausel des @code{DELETE}-Statements.
+
+@item
+Die @code{DELAYED}-Klausel der @code{INSERT}- und @code{REPLACE}-
+Statements.
+
+@item
+Die @code{LOW_PRIORITY}-Klausel der @code{INSERT}-, @code{REPLACE}-,
+@code{DELETE}- und @code{UPDATE}-Statements.
+
+@cindex Oracle-Kompabilität
+@cindex Kompatibilität, mit Oracle
+@item
+Die Benutzung von @code{LOAD DATA INFILE}. In vielen Fällen ist diese
+Syntax kompatibel mit Oracles @code{LOAD DATA INFILE}. @xref{LOAD DATA, ,
+@code{LOAD DATA}}.
+
+@item
+Die @code{ANALYZE TABLE}-, @code{CHECK TABLE}-, @code{OPTIMIZE TABLE}- und
+@code{REPAIR TABLE}-Statements.
+
+@item
+Das @code{SHOW}-Statement.
+@xref{SHOW, , @code{SHOW}}.
+
+@item
+Zeichenketten dürfen sowohl durch @samp{"} als auch durch @samp{'}
+eingeschlossen werden, nicht nur durch @samp{'}.
+
+@item
+Die Benutzung des Escape(@samp{\})Zeichens.
+
+@item
+Das @code{SET OPTION}-Statement. @xref{SET OPTION, , @code{SET OPTION}}.
+
+@item
+Sie müssen nicht alle ausgewählten Spalten im @code{GROUP BY}-Teil nennen.
+Hierdurch ergibt sich eine bessere Performance für einige sehr spezifische,
+aber recht gewöhnliche Anfragen.
+
+@item
+Man kann @code{ASC} und @code{DESC} bei @code{GROUP BY} spezifizieren.
+
+@item
+Um es Benutzern leichter zu machen, die von anderen SQL-Umgebungen kommen,
+unterstützt MySQL Aliase für viele Funktionen. Zum Beispiel unterstützen
+alle Zeichenketten-Funktionen sowohl die ANSI-SQL-Syntax als auch die
+ODBC-Syntax.
+
+@item
+MySQL kennt die Operatoren @code{||} und @code{&&}, die logisches Oder und
+logisches Und bedeuten, wie in der Programmiersprache C. In MySQL sind
+@code{||} und @code{OR} Synonyme, wie auch @code{&&} und @code{AND}.
+Aufgrund dieser freundlichen Syntax unterstützt MySQL nicht den
+ANSI-SQL-@code{||}-Operator für Zeichenketten-Verkettung (Konkatenation);
+benutzen Sie statt dessen @code{CONCAT()}. Weil @code{CONCAT()} eine
+beliebige Anzahl von Argumenten entgegennimmt, ist es leicht, die Benutzung
+des @code{||}-Operators zu MySQL zu konvertieren.
+
+@item
+@code{CREATE DATABASE} oder @code{DROP DATABASE}.
+@xref{CREATE DATABASE, , @code{CREATE DATABASE}}.
+
+@cindex PostgreSQL-Kompatibilität
+@cindex Kompatibilität, mit PostgreSQL
+@item
+Der @code{%}-Operator ist ein Synonym für @code{MOD()}. Das heißt @code{N
+% M} ist äquivalent zu @code{MOD(N,M)}. @code{%} wird für C-Programmierer
+und für Kompatibilität mit PostgreSQL unterstützt.
+
+@item
+Die @code{=}-, @code{<>}-, @code{<=}-, @code{<}-, @code{>=}-, @code{>}-,
+@code{<<}-, @code{>>}-, @code{<=>}-, @code{AND}-, @code{OR}- oder
+@code{LIKE}-Operatoren können in Spaltenvergleichen links von @code{FROM}
+in @code{SELECT} Statements benutzt werden. Beispiel:
+
+@example
+mysql> SELECT spalte1=1 AND spalte2=2 FROM tabelle_name;
+@end example
+
+@item
+Die @code{LAST_INSERT_ID()}-Funktion.
+@xref{mysql_insert_id, , @code{mysql_insert_id()}}.
+
+@item
+Die @code{REGEXP}- und @code{NOT REGEXP}-Operatoren für erweiterte reguläre
+Ausdrücke.
+
+@item
+@code{CONCAT()} oder @code{CHAR()} mit einem Argument oder mehr als zwei
+Argumenten. (In MySQL können diese Funktionen jede beliebige Anzahl von
+Argumenten entgegennehmen.)
+
+@item Die Funktionen @code{BIT_COUNT()}, @code{CASE}, @code{ELT()},
+@code{FROM_DAYS()}, @code{FORMAT()}, @code{IF()}, @code{PASSWORD()},
+@code{ENCRYPT()}, @code{md5()}, @code{ENCODE()}, @code{DECODE()},
+@code{PERIOD_ADD()}, @code{PERIOD_DIFF()}, @code{TO_DAYS()} oder
+@code{WEEKDAY()}.
+
+@item
+Die Benutzung von @code{TRIM()}, um Teile von Zeichenketten zu entfernen.
+ANSI SQL unterstützt nur die Entfernung einzelner Zeichen.
+
+@item
+Die @code{GROUP BY}-Funktionen @code{STD()}, @code{BIT_OR()} und
+@code{BIT_AND()}.
+
+@item
+Die Benutzung von @code{REPLACE} anstelle von @code{DELETE} + @code{INSERT}.
+@xref{REPLACE, , @code{REPLACE}}.
+
+@item
+Das @code{FLUSH flush_option}-Statement.
+
+@item
+Die Möglichkeit, Variablen in einem Statement mit @code{:=} zu setzen:
+@example
+SELECT @@a:=SUM(total),@@b=COUNT(*),@@a/@@b AS avg FROM test_tabelle;
+SELECT @@t1:=(@@t2:=1)+@@t3:=4,@@t1,@@t2,@@t3;
+@end example
+
+@end itemize
+
+
+@node Differences from ANSI, Bugs, Extensions to ANSI, Compatibility
+@c German node Unterschiede zu ANSI
+@subsection MySQL-Unterschiede im Vergleich zu ANSI SQL92
+
+Wir versuchen möglichst, dass MySQL dem ANSI-SQL-Standard und dem
+ODBC-SQL-Standard folgt, aber in einigen Fällen macht MySQL Dinge auf
+andere Weise:
+
+@itemize @bullet
+@item
+@code{--} ist nur dann ein Kommentar, wenn darauf Whitespace folgt.
+@xref{ANSI diff comments}.
+
+@item
+Bei @code{VARCHAR}-Spalten werden Leerzeichen am Ende entfernt, wenn der
+Wert gespeichert wird. @xref{Bugs}.
+
+@item
+In einigen Fällen ändern sich @code{CHAR}-Spalten automatisch (silent) in
+@code{VARCHAR}-Spalten. @xref{Silent column changes}.
+
+@item
+Zugriffsrechte für eine Tabelle werden nicht automatisch widerrufen, wenn
+Sie eine Tabelle löschen. Sie müssen explizit ein @code{REVOKE}-Statement
+absetzen, um die Zugriffsrechte für eine Tabelle zu widerrufen.
+@xref{GRANT, , @code{GRANT}}.
+
+@item
+@code{NULL AND FALSE} werden zu @code{NULL} ausgewertet und nicht zu
+@code{FALSE}. Der Grund hierfür liegt darin, dass wir meinen, dass es keine
+gute Idee ist, eine Menge von Sonderkonditionen für diesen Fall auswerten
+zu müssen.
+@end itemize
+
+
+@menu
+* ANSI diff Sub-selects::
+* ANSI diff SELECT INTO TABLE::
+* ANSI diff Transactions::
+* ANSI diff Triggers::
+* ANSI diff Foreign Keys::
+* Beschädigte Fremdschlüssel::
+* ANSI diff Views::
+* ANSI diff comments::
+@end menu
+
+@node ANSI diff Sub-selects, ANSI diff SELECT INTO TABLE, Differences from ANSI, Differences from ANSI
+@c German node Fehlende Sub-Selects
+@subsubsection Sub-Selects
+
+@cindex Sub-Selects
+
+MySQL unterstützt momentan nur Sub-Selects der Form @code{INSERT
+... SELECT ...} und @code{REPLACE ... SELECT ...}. In anderen
+Zusammenhängen können Sie allerdings die Funktion @code{IN()} benutzen.
+
+In vielen Fällen können Sie Ihre Anfragen ohne Sub-Selects schreiben:
+
+@example
+SELECT * FROM tabelle1 WHERE id IN (SELECT id FROM tabelle2);
+@end example
+
+Das kann wie folgt umgeschrieben werden:
+
+@example
+SELECT tabelle1.* FROM tabelle1,tabelle2 WHERE tabelle1.id=tabelle2.id;
+@end example
+
+Die Anfragen:
+@example
+SELECT * FROM tabelle1 WHERE id NOT IN (SELECT id FROM tabelle2);
+SELECT * FROM tabelle1 WHERE NOT EXISTS (SELECT id FROM tabelle2 where tabelle1.id=tabelle2.id);
+@end example
+
+Können wie folgt umgeschrieben werden:
+
+@example
+SELECT tabelle1.* FROM tabelle1 LEFT JOIN tabelle2 ON tabelle1.id=tabelle2.id where tabelle2.id IS NULL
+@end example
+
+Für kompliziertere Unteranfragen (Subqueries) können Sie oft temporäre
+Tabelle anlegen, die die Unteranfrage enthalten. In einigen Fällen wird
+diese Option allerdings nicht funktionieren. Am häufigsten treten diese
+Fälle mit @code{DELETE}-Statements auf, wofür Standard-SQL keine
+Verknüpfungen (Joins) unterstützt. Für solche Situationen sind zwei
+Optionen verfügbar, solange MySQL noch keine Unteranfragen unterstützt.
+
+Die erste Option besteht darin, eine prozedurale Programmiersprache (wie
+PHP oder Perl) zu benutzen, um eine @code{SELECT}-Anfrage zu erhalten, die
+die Primärschlüssel enthält, die benötigt werden, um die entsprechenden
+Datensätze zu löschen, und dann diese Werte zu benutzen, um das
+@code{DELETE}-Statement zu formulieren (@code{DELETE FROM ... WHERE ... IN
+(key1, key2, ...)}).
+
+Die zweite Option besteht darin, interaktives SQL zu benutzen, um
+automatisch eine Reihe von @code{DELETE}-Statements zu formulieren, indem
+die MySQL-Erweiterung @code{CONCAT()} benutzt wird (anstelle des
+Standard-Operators @code{||}).
+Beispiel:
+
+@example
+SELECT CONCAT('DELETE FROM tabelle1 WHERE pkid = ', tabelle1.pkid, ';')
+ FROM tabelle1, tabelle2
+ WHERE tabelle1.spalte1 = tabelle2.spalte2;
+@end example
+
+Sie können diese Anfrage in eine Skriptdatei schreiben und deren Eingabe an
+den Kommandozeilen-Interpreter @code{mysql} leiten und von dort die Ausgabe
+zurück an eine zweite Instanz des Interpreters:
+
+@example
+prompt> mysql --skip-column-names meine_db < mein_skript.sql | mysql meine_db
+@end example
+
+MySQL 4.0 unterstützt das Löschen aus mehreren Tabellen (multi-table
+deletes), was benutzt werden kann, um effizient Zeilen zu löschen,
+basierend auf den Informationen aus einer Tabelle oder sogar aus mehreren
+Tabellen zur gleichen Zeit.
+
+@node ANSI diff SELECT INTO TABLE, ANSI diff Transactions, ANSI diff Sub-selects, Differences from ANSI
+@c German node Fehlendes SELECT INTO TABLE
+@subsubsection @code{SELECT INTO TABLE}
+
+@findex SELECT INTO TABLE
+
+MySQL unterstützt noch nicht die Oracle-SQL-Erweiterung @code{SELECT ...
+INTO TABLE ...}. MySQL unterstützt statt dessen die ANSI-SQL-Syntax
+@code{INSERT INTO ... SELECT ...}, die im Prinzip dasselbe ist.
+@xref{INSERT SELECT}.
+
+@example
+INSERT INTO tabelle_temp2 (fldID) SELECT tabelle_temp1.fldOrder_ID FROM tabelle_temp1 WHERE
+tabelle_temp1.fldOrder_ID > 100;
+@end example
+
+Alternativ können Sie @code{SELECT INTO OUTFILE...} oder @code{CREATE TABLE
+... SELECT} benutzen, um Ihre Probleme zu lösen.
+
+
+@node ANSI diff Transactions, ANSI diff Triggers, ANSI diff SELECT INTO TABLE, Differences from ANSI
+@c German node Fehlende Transaktionen
+@subsubsection Transaktionen
+
+@cindex Transaktionen, Support
+
+Weil MySQL heutzutage Transaktionen unterstützt, gelten die folgenden
+Erörterungen nur, wenn Sie nur Tabellentypen benutzen, die nicht
+transaktionssicher sind. @xref{COMMIT}.
+
+Oft wird von neugierigen oder kritischen Leuten gefragt: ``Warum ist MySQL
+keine transaktionale Datenbank?'' oder ``Warum unterstützt MySQL keine
+Transaktionen?''
+
+MySQL hat sich bewusst entschieden, andere Paradigmen für die
+Datenintegrität zu unterstützen: ``atomische Operationen.'' Es entspricht
+unserer Denkweise und unserer Erfahrung, dass atomische Operationen gleiche
+oder bessere Integrität bei wesentlich besserer Performance gewährleisten.
+Nichtsdestotrotz schätzen und verstehen wir das transaktionale
+Datenbank-Paradigma und planen, im Verlauf der nächsten Releases
+transaktionssichere Tabellen einzuführen, auf der Basis der
+Transaktionssicherheit pro einzelner Tabelle. Wir werden unseren Benutzern
+die Entscheidung überlassen, ob Sie in ihren Applikationen den
+Geschwindigkeitsvorteil atomischer Operationen benötigen oder die
+transaktionalen Features.
+
+Wie benutzt man die Features von MySQL, um rigorose Integrität
+beizubehalten, und wie sind diese Features im Vergleich mit dem
+transaktionalen Paradigma zu bewerten?
+
+Zunächst ist es nach dem transaktionalen Paradigma bequemer, mit
+Transaktionen zu arbeiten, wenn Ihre Applikationen auf eine Weise
+geschrieben sind, dass sie in kritischen Situationen ``rollback'' anstelle
+von ``commit'' aufrufen. Darüber hinaus stellen Transaktionen sicher, dass
+unbeendete Updates oder zerstörende Aktivitäten nicht an die Datenbank
+abgesetzt werden; der Server hat die Gelegenheit, ein automatisches
+Rollback durchzuführen, wodurch Ihre Datenbank gerettet wird.
+
+In fast allen Fällen erlaubt Ihnen MySQL, potentiellen Problemen
+vorzubauen, indem einfache Überprüfungen eingebaut und einfache Skripte
+laufen gelassen werden, die die Datenbanken auf Inkonsistenzen prüfen und
+automatisch reparieren oder Warnmeldungen ausgeben, wenn so etwas passiert.
+Beachten Sie auch, dass allein durch die Benutzung der MySQL-Logdatei oder
+durch das Hinzufügen einer speziellen Logdatei Tabellen perfekt repariert
+werden können, ohne dass ein Verlust an Datenintegrität eintritt.
+
+Darüber hinaus können fatale transaktionale Updates so umgeschrieben
+werden, dass sie atomisch sind. In der Tat gehen wir so weit zu sagen, dass
+alle Integritätsprobleme, die Transaktionen lösen, mit @code{LOCK TABLES}
+oder atomischen Update durchgeführt werden können, was sicherstellt, dass
+Sie nie einen automatischen Abbruch von der Datenbank bekommen, was ein
+gewöhnliches Problem transaktionaler Datenbanken darstellt.
+
+Nicht einmal Transaktionen können jeden Verlust verhindern, wenn der Server
+abstürzt. In solchen Fällen können sogar transaktionale Systeme Daten
+verlieren. Der Unterschied zwischen unterschiedlichen Systemen besteht
+einzig darin, wie kurz die Zeitverzögerung ist, in der Daten verloren gehen
+könnten. Kein System ist 100%-ig sicher, sondern lediglich ``sicher
+genug''. Selbst von Oracle, ansonsten als das sicherste aller
+transaktionalen Datenbanken berühmt, wird berichtet, dass es manchmal in
+solchen Situationen Daten verliert.
+
+Um mit MySQL auf der sicheren Seite zu sein, brauchen Sie lediglich
+Datensicherungen und angeschaltetes Update-Logging. Damit können Sie in
+jeder denkbaren Situation genau wie mit jeder beliebigen transaktionalen
+Datenbank Daten wiederherstellen. Natürlich ist es immer eine gute Idee,
+Datensicherungen zu haben, unabhängig von der verwendeten Datenbank.
+
+
+Das transaktionale Paradigma hat seine Vor- und Nachteile. Viele
+Benutzer und Applikationsentwickler verlassen sich auf die Einfachheit, mit
+der sie um Probleme herum Code schreiben können, dort wo anscheinend ein
+Abbruch erfolgt ist, oder wo es notwendig ist, haben sie womöglich ein
+bisschen mehr Arbeit mit MySQL, weil sie anders denken oder mehr schreiben
+müssen. Wenn Ihnen atomische Operationen neu sind oder Sie vertrauter mit
+Transaktionen sind (oder Sie sich damit besser fühlen), kommen Sie nicht
+gleich zur Schlussfolgerung, dass sich MySQL nicht mit diesen Überlegungen
+beschäftigt hat. Zuverlässigkeit und Integrität stehen für uns absolut im
+Vordergrund. Aktuelle Schätzungen gehen davon aus, dass zur Zeit mehr als
+eine Million @code{mysqld}-Server laufen, von denen viele in
+Produktionsumgebungen eingesetzt werden. Wir hören sehr, sehr selten von
+Benutzern, die irgendwelche Daten verloren haben, und in fast allen Fällen
+sind Benutzerfehler im Spiel. Das ist unserer Meinung nach der beste Beweis
+für die Stabilität und Zuverlässigkeit von MySQL.
+
+Im übrigen lassen die aktuellen Features von MySQL Zuverlässigkeit und
+Integrität auf Transaktionsebene oder besser zu, wenn in bestimmten
+Situationen Integrität von höchster Wichtigkeit ist. Wenn Sie Tabellen mit
+@code{LOCK TABLES} sperren, werden alle Updates angehalten, bis jegliche
+Integritätsprüfungen durchgeführt sind. Wenn Sie nur eine Lesesperre (Read
+Lock) machen (im Gegensatz zu einer Schreibsperre - Write Lock), werden
+Lese- und Einfügeoperationen noch zugelassen. Die neu eingefügten
+Datensätze können von nicht Clients gesehen werden, die eine
+@code{READ}-Sperre haben, bis sie ihre Lesesperre aufheben. Mit
+@code{INSERT DELAYED} können Sie Einfügeoperationen in eine lokale
+Warteschlange (Local Queue) stellen, solange, bis die Sperren aufgehoben
+sind, ohne dass der Client warten muss, bis die Einfügeoperationen
+abgeschlossen sind. @xref{INSERT DELAYED}.
+
+``Atomisch'', so wie wir es meinen, ist nichts Magisches. Es bedeutet nur,
+dass Sie sicher sein können, dass kein anderer Benutzer mit irgendeinem
+laufenden Update in Konflikt kommen kann, und dass es nie ein automatisches
+Rollback geben kann (was bei transaktionsbasierenden Systemen vorkommen
+kann, wenn Sie nicht sehr vorsichtig sind). MySQL garantiert auch, dass es
+keine schmutzigen Lesezugriffe (Dirty Reads) gibt. Sie finden einige
+Beispiele, wie man atomische Updates schreibt, im Abschnitt über Commits
+und Rollbacks.
+@c German FIX This section no longer exists
+@c @xref{Commit-Rollback}.
+
+Wir haben reichlich über Integrität und Performance nachgedacht und
+glauben, dass unser atomisches Paradigma sowohl Zuverlässigkeit als auch
+extrem hohe Performance gewährleistet, und zwar drei- bis fünfmal
+schneller, als es die schnellste und optimal eingestellte transaktionale
+Datenbank schafft. Wir haben Transaktionen nicht deshalb heraus gelassen,
+weil sie schwer zu machen sind. Der Hauptgrund für die Entscheidung für
+atomische Operationen gegen Transaktionen liegt darin, dass wir dadurch
+viele Geschwindigkeitsoptimierungen machen konnten, die auf andere Art
+nicht möglich gewesen wären.
+
+Viele unserer Benutzer, für die Geschwindigkeit das Wichtigste ist, haben
+keinerlei Bedenken hinsichtlich Transaktionen. Für sie sind Transaktionen
+kein Thema. Diejenigen Benutzer, die Sorgen mit Transaktionen haben oder
+sich darüber wundern, dass MySQL diese nicht unterstützt, gibt es eine
+``MySQL-Art'', die wir weiter oben beschrieben haben. Denjenigen, denen
+Sicherheit wichtiger als Geschwindigkeit ist, empfehlen wir die Benutzung
+von @code{BDB}- oder @code{InnoDB}-Tabellen für alle kritischen Daten.
+@xref{Table types}.
+
+Ein letzter Hinweis: Wir arbeiten zur Zeit an einem sicheren
+Replikationsschema, vom dem wir glauben, dass es besser als jedes
+kommerzielle Replikationssystem ist, das wir kennen. Dieses System wird mit
+dem atomischen, nicht-transaktionalen Paradigma mit höchster
+Zuverlässigkeit laufen. Bleiben Sie dran!
+
+
+@node ANSI diff Triggers, ANSI diff Foreign Keys, ANSI diff Transactions, Differences from ANSI
+@c German node Fehlende Trigger
+@subsubsection Gespeicherte Prozeduren und Trigger
+
+@cindex Fehlende Prozeduren und Trigger, Definition
+@cindex Prozeduren, gespeicherte
+@cindex Trigger, gespeicherte
+
+Eine gespeicherte Prozedur ist ein Satz von SQL-Kommandos, die kompiliert
+und auf dem Server gespeichert werden können. Wenn dies einmal geschehen
+ist, müssen Clients nicht mehr die gesamte Anfrage absetzen, sondern können
+sich auf die gespeicherte Prozedur beziehen. Hiermit wird bessere
+Performance erreicht, den die Anfrage muss nur einmal geparst werden, und
+es muss weniger Information zwischen Client und Server ausgetauscht werden.
+Man kann sogar die konzeptionelle Ebene steigern, indem man Bibliotheken
+von Funktionen auf dem Server bereit hält.
+
+Ein Trigger ist eine gespeicherte Prozedur, die aufgerufen wird, wenn ein
+bestimmtes Ereignis eintritt. Beispielsweise kann man eine gespeicherte
+Prozedur installieren, die jedes Mal ausgeführt wird, wenn ein Datensatz
+aus einer Transaktionstabelle gelöscht wird, und die automatisch den dazu
+gehörigen Kunden aus einer Kundentabelle löscht, wenn alle seine
+Transaktionen gelöscht wurden.
+
+Für ein späteres Release ist geplant, dass MySQL gespeicherte Prozeduren
+handhaben kann, aber ohne Trigger. Trigger verlangsamen üblicherweise
+alles, sogar Anfragen, für die sie nicht benötigt werden.
+
+Um festzustellen, ab wann MySQL gespeicherte Prozeduren bekommen wird, siehe
+auch @ref{TODO}.
+
+
+@node ANSI diff Foreign Keys, Beschädigte Fremdschlüssel, ANSI diff Triggers, Differences from ANSI
+@c German node Fehlende Fremdschlüssel
+@subsubsection Fremdschlüssel
+
+@cindex Fremdschlüssel
+@cindex Schlüssel, Fremdschlüssel
+
+Beachten Sie, dass Fremdschlüssel in SQL nicht dazu benutzt werden, um
+Tabellen zu verknüpfen, sondern hauptsächlich, um die referentielle
+Integrität zu überprüfen (Fremdschlüssel-Restriktionen). Wenn Sie durch ein
+@code{SELECT}-Statement Ergebnisse aus mehreren Tabellen erhalten wollen,
+tun Sie dies, indem Sie Tabellen verknüpfen (Join):
+
+@example
+SELECT * von tabelle1,tabelle2 where tabelle1.id = tabelle2.id;
+@end example
+
+@xref{JOIN, , @code{JOIN}}. @xref{example-Foreign keys}.
+
+Die @code{FOREIGN KEY}-Syntax in MySQL existiert nur aus
+Kompatibilitätsgründen mit den @code{CREATE TABLE}-Kommandos anderer
+Hersteller; sie tut nichts. Die @code{FOREIGN KEY}-Syntax ohne @code{ON
+DELETE ...} wird hauptsächlich für Dokumentationszwecke benutzt. Einige
+ODBC-Applikationen benutzen dies vielleicht, um automatische
+@code{WHERE}-Klauseln zu erzeugen, aber das läßt sich üblicherweise leicht
+überschreiben. @code{FOREIGN KEY} wird manchmal als Restriktionsprüfung
+benutzt, aber eine solche Überprüfung ist in der Praxis nicht notwendig,
+wenn Zeilen in Tabellen in der richtigen Reihenfolge eingefügt werden.
+MySQL unterstützt diese Klauseln nur, weil manche Applikationen verlangen,
+dass sie existieren (egal ob sie funktionieren oder nicht).
+
+In MySQL können Sie das Problem, dass @code{ON DELETE...} nicht
+implementiert ist, dadurch umgehen, dass Sie das entsprechende
+@code{DELETE}-Statement einer Applikation hinzufügen, wenn Sie Datensätze
+aus einer Tabelle löschen, die Fremdschlüssel hat. In der Praxis ist das
+genauso schnell (in einigen Fällen schneller) und wesentlich portabler, als
+wenn Sie Fremdschlüssel benutzen würden.
+
+In naher Zukunft werden wir die @code{FOREIGN KEY}-Implementation
+erweitern, so dass zumindest die Information in der Datei, die die Tabelle
+spezifiziert, gespeichert wird und somit durch @code{mysqldump} und ODBC
+abgefragt werden kann. Zu einem späteren Zeitpunkt werden wir
+Fremdschlüssel-Restriktionen für Applikationen implementieren, die nicht
+leicht durch entsprechendes Programmieren umgangen werden können.
+
+
+
+@node Beschädigte Fremdschlüssel, ANSI diff Views, ANSI diff Foreign Keys, Differences from ANSI
+@c German node <no English equivalent>
+@subsubsection Warum wir Fremdschlüssel nicht implementiert haben
+
+@cindex Fremdschlüssel, warum sie nicht implementiert sind
+
+Viele Leute, die Datenbanken unterrichten und programmieren, sind der
+festen Meinung, dass referentielle Integrität durch den Datenbank-Server
+erzwungen werden sollte. In der Tat ist dieser Ansatz in vielen Fällen sehr
+hilfreich. In vielen Gesprächen mit Datenbankbenutzern haben wir jedoch
+festgestellt, dass Fremdschlüssel oft missbraucht werden, was schwer-
+wiegende Probleme verursachen kann. Selbst wenn sie in korrekter Weise
+benutzt werden, sind sie keine magische Lösung für das Problem
+referentieller Integrität, obwohl sie die Dinge in einigen Fällen einfacher
+gestalten.
+
+Wegen der obigen Beobachtungen haben wir der Implementation von
+Fremdschlüsseln keine hohe Priorität zugewiesen. Unsere Benutzerbasis
+bestand bislang zumeist aus Entwicklern, denen es nichts ausmachte,
+referentielle Integrität im Code der Applikation zu erzwingen, und die dies
+sogar bevorzugten, weil es ihnen mehr Kontrolle gab.
+
+In den letzten Jahren hat sich unsere Benutzerbasis jedoch um einiges
+ausgeweitet. Mittlerweile haben wir viele Benutzer, die es schätzen würden,
+wenn MySQL erzwungene referentielle Integrität implementiert hätte. Aus
+diesem Grund werden wir Fremdschlüssel in naher Zukunft implementieren.
+Allerdings können wir zur Zeit noch kein definitives Auslieferungsdatum
+nennen.
+
+Einige Vorteile der Erzwingung von Fremdschlüsseln:
+
+@itemize @bullet
+@item
+Einen sauberen Entwurf der Beziehungen vorausgesetzt machen es
+Fremdschlüssel-Restriktionen schwieriger für einen Programmierer,
+Inkonsistenzen in eine Datenbank einzuführen.
+
+@item
+Wenn kaskadierende Updates und Deletes benutzt werden können, kann dies den
+Client-Code vereinfachen.
+
+@item
+Sauber entworfene Fremdschlüssel-Regeln sind hilfreich, Beziehungen
+zwischen Tabellen zu dokumentieren.
+@end itemize
+
+Nachteile:
+
+@itemize @bullet
+@item
+MySQL unterstützt noch keine erzwungene referentielle Integrität. Wenn Ihre
+Applikation also davon abhängt, können Sie sie solange nicht mit MySQL
+benutzen, bis wir dieses Feature implementieren.
+
+@item
+Fehler, die beim Entwurf von Schlüsselbeziehungen leicht zu machen sind,
+können schwer wiegende Probleme verursachen, zum Beispiel Zirkelbezüge oder
+eine falsche Kombination kaskadierender Deletes.
+
+@item
+Eine sauber geschriebene Applikation wird intern sicherstellen, dass sie
+referentielle Integritäts-Restriktionen nicht verletzt, bevor sie mit einer
+Anfrage fortfährt. Deshalb werden zusätzliche Überprüfungen auf
+Datenbankebene solche Applikationen nur verlangsamen.
+
+@item
+Es ist nichts Ungewöhnliches, dass ein Datenbankadministrator eine so
+komplexe Topologie von Beziehungen einführt, dass es sehr schwierig, wenn
+nicht gar unmöglich wird, einzelne Tabellen zu sichern oder
+wiederherzustellen.
+@end itemize
+
+
+@node ANSI diff Views, ANSI diff comments, Beschädigte Fremdschlüssel, Differences from ANSI
+@c German node Fehlende Sichten
+@subsubsection Sichten (Views)
+
+@cindex Sichten (Views)
+
+MySQL unterstützt noch keine Sichten, aber wir planen, diese in Version 4.1
+zu implementieren.
+
+Sichten sind äußerst nützlich, um Benutzern Zugang zu einem Satz von
+Beziehungen wie zu einer einzigen Tabelle zu gewähren (Lesezugriff). Viele
+SQL-Datenbanken lassen es nicht zu, dass irgend welche Zeilen in einer
+Sicht aktualisiert werden (Update). Statt dessen müssen die einzelnen
+Tabellen aktualisiert werden.
+
+Weil MySQL meist in Applikationen und in Web-Systemen eingesetzt werden, wo
+der Applikationsprogrammierer volle Kontrolle über die Datenbankbenutzung
+hat, sehen die meisten unserer Benutzer Sichten als nicht sehr wichtig an.
+(Zumindest war niemand interessiert genug, um die Implementation von
+Sichten zu finanzieren.)
+
+In MySQL werden Sichten nicht benötigt, um den Zugriff auf Spalten zu
+beschränken, weil MySQL ein sehr ausgefeiltes System der
+Zugriffsberechtigungen hat. @xref{Privilege system}.
+
+
+@node ANSI diff comments, , ANSI diff Views, Differences from ANSI
+@c German node Fehlende Kommentare
+@subsubsection @samp{--} als Beginn eines Kommentars
+
+@cindex Kommentare, Beginn
+@cindex Beginn, Kommentar
+
+Einige andere SQL-Datenbanken benutzen @samp{--}, um Kommentare zu
+beginnen. MySQL benutzt @samp{#} als Anfangszeichen, wenn auch das
+@code{mysql}-Kommandozeilen-Werkzeug alle Zeilen entfernt, die mit @samp{--}
+anfangen. Sie können in MySQL auch Kommentare im C-Stil verwenden @code{/*
+Das ist ein Kommentar */}. @xref{Comments}.
+
+MySQL ab Version 3.23.3 unterstützt Kommentare, die mit @samp{--} beginnen,
+allerdings nur, wenn der Kommentarbeginn von einem Leerzeichen gefolgt
+wird. Der Grund liegt darin, dass dieser degenerierte Kommentar-Stil eine
+Menge Probleme mit automatisch generierten SQL-Anfragen verursacht, die
+Ähnliches wie den folgenden Code benutzen, wo automatisch der Wert einer
+Zahlung für @code{!zahlung!} eingefügt wird:
+
+@example
+UPDATE tabelle_name SET kredit=kredit-!zahlung!
+@end example
+
+Was, glauben Sie, passiert, wenn der Wert von @code{zahlung} negativ wird?
+
+Weil @code{1--1} in SQL zulässig ist, sind wir der Meinung, dass es
+furchtbar ist, dass @samp{--} den Anfang eines Kommentars bedeutet.
+
+In MySQL ab Version 3.23 können Sie allerdings folgendes benutzen:
+@code{1-- Das ist ein Kommentar}
+
+Die folgenden Erörterungen treffen nur zu, wenn Sie eine MySQL-Version vor
+3.23 laufen lassen:
+
+Wenn Sie ein SQL-Programm in einer Textdatei haben, das @samp{--}-Kommentare
+enthält, sollten Sie folgendes benutzen:
+
+@example
+shell> replace " --" " #" < text-datei-mit-merkwuerigen-kommentaren.sql \
+ | mysql datenbank
+@end example
+
+anstelle des üblichen:
+
+@example
+shell> mysql datenbank < text-datei-mit-merkwuerdigen-kommentaren.sql
+@end example
+
+Sie können auch die Kommandodatei ``direkt'' editieren, um die
+@samp{--}-Kommentare zu @samp{#}-Kommentaren zu machen:
+
+@example
+shell> replace " --" " #" -- text-datei-mit-merkwuerdigen-kommentaren.sql
+@end example
+
+Machen Sie die Änderungen mit folgendem Befehl rückgängig:
+
+@example
+shell> replace " #" " --" -- text-datei-mit-merkwuerdigen-kommentaren.sql
+@end example
+
+
+
+@node Bugs, , Differences from ANSI, Compatibility
+@c German node Bugs
+@subsection Bekannte Fehler und Design-Unzulänglichkeiten in MySQL
+
+@cindex Bugs, bekannte
+@cindex Fehler, bekannte
+@cindex Design, Probleme
+@cindex Bekannte Fehler
+
+Die folgenden Probleme sind bekannt. Ihre Behebung hat eine sehr hohe
+Priorität:
+
+@itemize @bullet
+@item
+@code{ANALYZE TABLE} kann eine BDB-Tabelle in manchen Fällen unbenutzbar
+machen, bis @code{mysqld} neu gestartet wird. Wenn so etwas passiert,
+stehen Fehlermeldungen wie die folgende in der MySQL-Fehler-Datei (Error
+File):
+
+@example
+001207 22:07:56 bdb: log_flush: LSN past current end-of-log
+@end example
+
+@item
+Führen Sie mit einer @code{BDB}-Tabelle nicht @code{ALTER TABLE} aus, wenn
+Sie mit dieser noch nicht abgeschlossene Mehrfach-Statement-Transaktionen
+durchführen. (Die Transaktion wird wahrscheinlich ignoriert.)
+
+@item
+@code{ANALYZE TABLE}, @code{OPTIMIZE TABLE} und @code{REPAIR TABLE} können
+Probleme bei Tabellen verursachen, für die @code{INSERT DELAYED} benutzt
+wird.
+
+@item
+Wenn Sie @code{LOCK TABLE ..} und @code{FLUSH TABLES ..} benutzen, können
+Sie nicht sicher sein, dass bei der fraglichen Tabelle keine halb
+abgeschlossenen Transaktionen im Gange sind.
+
+@item
+BDB-Tabellen lassen sich etwas langsam öffnen. Wenn Sie viele BDB-Tabellen
+in einer Datenbank haben, kann es sehr lange dauern, bis Sie den
+@code{mysql}-Client für diese Datenbank benutzen können, wenn Sie die
+@code{-A}-Option oder @code{rehash} benutzen. Das macht sich speziell dann
+bemerkbar, wenn Sie einen große Tabellen-Cache benutzen.
+
+@item
+Das momentane Replikationsprotokoll kann nicht mit @code{LOAD DATA INFILE}
+und mit Zeilenbegrenzungszeichen (line terminator characters) umgehen, die
+mehr als 1 Zeichen enthalten.
+@end itemize
+
+Folgende Probleme sind bekannt und werden zu gegebener Zeit behoben:
+@itemize @bullet
+@item
+Momentan funktioniert @code{MATCH} nur bei @code{SELECT}-Statements.
+
+@item
+Wenn Sie @code{SET CHARACTER SET} benutzen, können Sie keine
+landesspezifischen (nationalen) Zeichen für Datenbank-, Tabellen- und
+Spaltennamen verwenden (also z. B. kein ä, ö, ü).
+
+@item
+@code{DELETE FROM merge_table} ohne @code{WHERE} löscht nur die Zuordnung
+(das Mapping) für die Tabelle, nicht alles in der zugeordneten (gemappten)
+Tabelle.
+
+@item
+Sie können den Server nicht in ein anderes Verzeichnis bauen, wenn Sie
+MIT-Pthreads verwenden. Weil dies Änderungen an MIT-Pthreads bedingen
+würde, werden wir dieses Problem wahrscheinlich nicht beheben.
+
+@item
+@code{BLOB}-Werte können nicht ``zuverlässig'' in @code{GROUP BY}-,
+@code{ORDER BY} oder @code{DISTINCT}-Klauseln benutzt werden. In diesen
+Fällen werden bei Vergleichen nur die ersten @code{max_sort_length}
+Bytes (Vorgabewert 1024) von @code{BLOB}s benutzt. Die Voreinstellung kann
+mit der @code{-O max_sort_length}-Option für @code{mysqld} geändert werden.
+In den meisten Fällen können Sie als Workaround eine Teilzeichenkette
+(Substring) verwenden: @code{SELECT DISTINCT LEFT(blob,2048) FROM
+tabelle}.
+
+@item
+Berechnungen werden mit @code{BIGINT} oder @code{DOUBLE} durchgeführt
+(beide sind normalerweise 64 Bits lang). Es hängt von der verwendeten
+Funktion ab, welche Genauigkeit man erhält. Als allgemeine Regel gilt, dass
+Bit-Funktionen mit @code{BIGINT}-Genauigkeit, @code{IF} und @code{ELT()}
+mit @code{BIGINT}- oder @code{DOUBLE}-Genauigkeit und der Rest mit
+@code{DOUBLE}-Genauigkeit durchgeführt werden. Man sollte vermeiden,
+vorzeichenlose Werte, die größer als 63 Bits sind (9223372036854775807),
+zu verwenden, ausser für Bit-Felder!
+MySQL 4.0 bietet eine bessere @code{BIGINT}-Handhabung als MySQL 3.23.
+
+@item
+Bei allen Zeichenketten-Spalten ausser bei @code{BLOB}- und
+@code{TEXT}-Spalten werden Leerzeichen am Ende automatisch entfernt, wenn
+sie abgerufen werden. Bei @code{CHAR}-Typen ist das okay und kann gemäß
+ANSI-SQL92 als ein Feature betrachtet werden. Der Bug besteht darin, dass
+in MySQL auch @code{VARCHAR}-Spalten auf dieselbe Art behandelt werden.
+
+@item
+Pro Tabelle können höchstens 255 @code{ENUM}- und @code{SET}-Spalten
+verwendet werden.
+
+@item
+@code{safe_mysqld} leitet alle Nachrichten von @code{mysqld} in die
+@code{mysqld}-Logdatei um. Ein Problem ergibt sich, wenn Sie
+@code{mysqladmin refresh} benutzen, um die Logdatei zu schließen und
+wieder zu öffnen. In diesem Fall werden @code{stdout} und @code{stderr}
+immer noch in die alte Logdatei geleitet.
+Wenn Sie @code{--log} umfangreich benutzen, sollten Sie @code{safe_mysqld}
+editieren, um in @file{'hostname'.err} anstelle von @file{'hostname'.log}
+zu loggen, damit Sie den Speicherplatz für das alte Log leicht neu belegen
+können, indem Sie das alte Log löschen und @code{mysqladmin refresh}
+ausführen.
+
+@item
+Im @code{UPDATE}-Statement, werden Spalten von links nach rechts
+aktualisiert (Update). Wenn Sie sich auf eine aktualisierte Spalte
+beziehen, erhalten Sie den aktualisierten Werte anstelle des ursprünglichen
+Werts. Beispiel:
+
+@example
+mysql> UPDATE tabelle SET KEY=KEY+1,KEY=KEY+1;
+@end example
+
+Dieses Statement aktualisiert @code{KEY} mit @code{2} anstelle von
+@code{1}.
+
+@item
+Sie können temporäre Tabellen nicht öfter als einmal innerhalb derselbe
+Anfrage benutzen. Das Folgende zum Beispiel funktioniert nicht:
+
+@example
+select * from temporaere_tabelle, temporaere_tabelle as t2;
+@end example
+
+@item
+@code{RENAME} funktioniert nicht bei @code{TEMPORARY}-Tabellen.
+
+@item
+Unter Umständen behandelt der Optimierer (Optimizer) @code{DISTINCT}
+unterschiedlich, je nachdem, ob Sie 'versteckte' Spalten in einem Join
+benutzen oder nicht. In einem Join werden versteckte Spalten als Teil des
+Ergebnisses gezählt (selbst wenn sie nicht angezeigt werden), während
+versteckte Spalten in normalen Anfragen nicht an einem @code{DISTINCT}-Vergleich
+teilnehmen. Zukünftig werden wir dieses Verhalten wahrscheinlich ändern, so
+dass versteckte Spalten nie verglichen werden, wenn @code{DISTINCT} ausgeführt
+wird.
+
+Hierfür ein Beispiel:
+
+@example
+SELECT DISTINCT mp3id FROM band_downloads WHERE userid = 9 ORDER BY id
+DESC;
+@end example
+
+und
+
+@example
+SELECT DISTINCT band_downloads.mp3id, FROM band_downloads,band_mp3
+WHERE band_downloads.userid = 9 AND band_mp3.id = band_downloads.mp3id
+ORDER BY band_downloads.id DESC;
+@end example
+
+Im zweiten Fall bekommen Sie in MySQL 3.23.x möglicherweise zwei identische
+Zeilen in der Ergebnismenge (weil die versteckten 'id'-Spalten
+unterschiedlich sein können).
+
+Beachten Sie, dass dies nur für Anfragen zutrifft, bei denen die ORDER
+BY-Spalten nicht im Ergebnis enthalten sind. ANSI-SQL erlaubt dies nicht
+
+@item
+Weil MySQL es zuläßt, mit Tabellentypen zu arbeiten, die keine
+Transaktionen unterstützen (und folglich Daten nicht per @code{rollback} in
+den vorherigen Zustand bringen können), verhalten sich einige Dinge in
+MySQL etwas anderes als in anderen SQL-Servern. Das kann manchmal etwas
+ungünstig sein, weil Spaltenwerte in der Applikation überprüft werden
+müssen. Auf der anderen Seite erhalten Sie dadurch eine nette
+Geschwindigkeitssteigerung, weil es MySQL gestattet, einige Optimierungen
+vorzunehmen, die ansonsten sehr schwer durchzuführen sein würden.
+
+Wenn Sie eine Spalte auf einen nicht zulässigen Wert setzen, speichert
+MySQL, statt ein Rollback durchzuführen, den @code{besten möglichen Wert}
+in der Spalte:
+
+@itemize @minus
+@item
+Wenn Sie versuchen, in einer numerischen Spalte einen Wert ausserhalb des
+Wertebereichs zu speichern, speichert MySQL statt dessen den kleinsten oder
+größten möglichen Wert.
+
+@item
+Wenn Sie versuchen, eine Zeichenkette, die nicht mit einer Zahl beginnt, in
+einer numerischen Spalte zu speichern, speichert MySQL 0.
+
+@item
+Wenn Sie versuchen, @code{NULL} in einer Spalte zu speichern, die keine
+@code{NULL}-Werte zuläßt, speichert MySQL 0 oder @code{''} (leere
+Zeichenkette). (Man kann dieses Verhalten jedoch mit der
+-DDONT_USE_DEFAULT_FIELDS-Kompilierungs-Option ändern.)
+
+@item
+MySQL läßt zu, dass einige falsche Datumswerte in @code{DATE}- und
+@code{DATETIME}-Spalten gespeichert werden (wie 2000-02-31 oder
+2000-02-00). Wenn das Datum völlig falsch ist, speichert MySQL den
+speziellen Datumswert 0000-00-00 in der Spalte.
+
+@item
+Wenn Sie @code{enum} auf einen nicht unterstützten Wert setzen, wird es auf
+den Fehlerwert 'leere Zeichenkette' oder (bei numerischen Werten) auf 0
+gesetzt.
+@end itemize
+
+@item
+Wenn Sie @code{PROCEDURE} auf eine Anfrage ausführen, die eine leere
+Ergebnismenge liefert, kann es in einigen Fällen vorkommen, dass
+@code{PROCEDURE} die Spalten nicht umwandelt.
+
+@item
+Wenn Sie eine Tabelle vom Typ @code{MERGE} anlegen, wird nicht überprüft,
+ob die zugrunde liegenden Tabellen von einem kompatiblen Typ sind.
+
+@item
+MySQL kann bislang nicht mit @code{NaN}-, @code{-Inf}- und
+@code{Inf}-Werten in Doubles umgehen. Wenn Sie diese benutzen, gibt es
+Probleme, wenn Daten importiert oder exportiert werden. Als Zwischenlösung
+sollten Sie @code{NaN} in @code{NULL} umwandeln (falls möglich) und
+@code{-Inf} und @code{Inf} in den kleinsten bzw. größten möglichen Wert.
+
+@item
+Negative Zahlen in der @code{LIMIT}-Klausel werden als große positive
+Zahlen behandelt.
+
+@item
+Wenn Sie @code{ALTER TABLE} benutzen, um einen @code{UNIQUE}-Index zu einer
+Tabelle hinzuzufügen, die in einer @code{MERGE}-Tabelle benutzt wird, und
+dann @code{ALTER TABLE} benutzen, um der @code{MERGE}-Tabelle einen
+normalen Index hinzuzufügen, weicht die Reihenfolge der Schlüssel für die
+Tabellen ab. Das liegt daran, dass @code{ALTER TABLE}
+@code{UNIQUE}-Schlüssel vor normalen Schlüsseln einfügt, um doppelte
+Schlüssel so früh wie möglich erkennen zu können.
+@end itemize
+
+Folgende bekannte Bugs gibt es in früheren Versionen von MySQL:
+
+@itemize @bullet
+@item
+Man kann einen hängenden Thread erhalten, wenn man @code{DROP TABLE} auf
+eine Tabelle ausführt, die zu vielen Tabellen gehört, die mit @code{LOCK
+TABLES} gesperrt sind.
+
+@item
+In folgenden Fällen können Sie einen Core Dump erhalten:
+
+@itemize @minus
+@item
+Die Routine für verzögertes Einfügen (Delayed Insert Handler) hat noch nie
+ausgeführte Einfügeoperationen (Pending Inserts) auf eine Tabelle.
+
+@item
+@code{LOCK tabelle} mit @code{WRITE}
+
+@item
+@code{FLUSH TABLES}
+@end itemize
+
+@item
+Vor MySQL-Version 3.23.2 kann ein @code{UPDATE} fehlschlagen, dass einen
+Schlüssel mit einer @code{WHERE}-Klausel auf denselben Schlüssel
+aktualisiert, weil der Schlüssel benutzt wurde, um nach Datensätzen zu
+suchen, und dieselbe Zeile mehrfach gefunden wurde:
+
+@example
+UPDATE tabelle SET KEY=KEY+1 WHERE KEY > 100;
+@end example
+
+Ein Workaround besteht in der Benutzung von:
+
+@example
+mysql> UPDATE tabelle SET KEY=KEY+1 WHERE KEY+0 > 100;
+@end example
+
+Das funktioniert, weil MySQL auf Ausdrücke (Expressions) in der
+@code{WHERE}-Klausel keine Indizes benutzt.
+
+@item
+Vor MySQL-Version 3.23 wurden alle numerischen Typen als Festkomma-Felder
+behandelt. Das bedeutet, dass Sie festlegen müssen, wie viele
+Dezimalstellen ein Fließkomma-Feld haben soll. Alle Werte wurden mit der
+korrekten Anzahl von Dezimalstellen zurückgegeben.
+@end itemize
+
+Was Plattform-spezifische Bugs angeht, sehen Sie bitte im Abschnitt über
+Kompilieren und Portieren nach.
+
+
+@node TODO, Comparisons, Compatibility, Deutsch
+@c German node TODO
+@section MySQL und die Zukunft (das TODO)
+
+@cindex TODO-Liste für MySQL
+
+
+Dieser Anhang listet die Features auf, für die wir eine Implementierung in
+MySQL geplant haben.
+
+Alles auf dieser Liste gibt nur ungefähr die Reihenfolge wieder, in der es
+gemacht werden wird. Wenn Sie die Prioritäten beeinflussen wollen,
+registrieren Sie bitte eine Lizenz oder unterstützen Sie uns und teilen uns
+mit, was Sie schneller gemacht haben wollen. @xref{Lizenzpolitik}.
+
+Geplant ist, dass wir in Zukunft den kompletten ANSI-SQL99-Standard
+unterstützen, aber mit einer Menge nützlicher Erweiterungen. Die
+Herausforderung liegt darin, dass durchzuführen, ohne
+Geschwindigkeitsvorteile zu opfern oder den Code zu kompromittieren.
+
+
+@menu
+* TODO MySQL 4.0::
+* TODO future::
+* TODO sometime::
+* TODO unplanned::
+@end menu
+
+@node TODO MySQL 4.0, TODO future, TODO, TODO
+@c German node TODO MySQL 4.0
+@subsection Dinge, die in Version 4.0 enthalten sein sollten
+
+Wir haben uns der Entwicklung von MySQL Version 4.0 zugewandt. Die meisten
+grundsätzlichen Dinge, die wir in Version 4.0 haben wollen, sind bereits
+gemacht. Das Ziel ist, den Rest der folgenden Features schnell einzubauen
+und dann zur Entwicklung von MySQL 4.1 überzugehen.
+@c German FIX Added . after @xref.
+@xref{MySQL 4.0 In A Nutshell}.
+
+Der News-Abschnitt für 4.0 beinhaltet eine Liste der Features, die wir
+bereits im 4.0-Baum implementiert haben. @xref{News-4.0.x}.
+
+@itemize @bullet
+@item
+Benutzern erlauben, die Startoptionen zu ändern, ohne den Server herunter
+fahren zu müssen.
+@item
+Störsichere Replikation.
+@item
+Mehr Funktionen für die Volltextsuche.
+@xref{Volltext-Features in MySQL 4.0}.
+@item
+Neuer Schlüssel-Cache
+@item
+Neues Dateiformat für die Tabellendefinition (@code{.frm}-Dateien). Das
+versetzt uns in die Lage, nicht irgendwann keine Bits mehr zu haben, wenn
+wir weitere Tabellenoptionen hinzufügen. Es wird nach wie vor möglich sein,
+in 4.0 das alte @code{.frm}-Dateiformat zu benutzen. Alle neu erzeugten
+Tabellen werden jedoch das neue Format benutzen.
+
+Das neue Dateiformat versetzt uns in die Lage, neue Spaltentypen, mehr
+Optionen für Schlüssel und @code{FOREIGN KEY}-Support hinzuzufügen.
+@item
+Die Replikation sollte mit @code{RAND()} und Benutzer-Variablen
+@code{@@var} funktionieren.
+@item
+Online-Datensicherung mit sehr geringen Performance-Einbussen. Das Online-Backup
+wird das Hinzufügen eines neuen Replikations-Slaves erleichtern, ohne dass
+man den Master herunter fahren muss.
+@item
+Es zulassen, dass @code{DELETE} auf @code{MyISAM}-Tabellen den
+Datensatz-Cache benutzt. Um das zu tun, müssen wir den Thread-Cache für
+Datensätze aktualisieren, wenn wir die @code{.MYD}-Datei aktualisieren.
+@item
+Zeichensatz-Festlegungen (Casts) und Syntax für die Handhabung mehrerer
+Zeichensätze.
+@item
+Hilfe für alle Befehle des Clients.
+@item
+Sichere Verbindungen (mit SSL).
+@item
+@code{SHOW COLUMNS FROM tabelle} (der vom @code{mysql}-Client benutzt für
+die Erweiterung von Spaltennamen benutzt wird) sollte nicht die Tabelle
+öffnen, sondern nur die Definitionsdatei. Das wird weniger Speicher
+beanspruchen und sehr viel schneller sein.
+@item
+Bei der Benutzung von @code{SET CHARACTER SET} sollten wir die gesamte
+Anfrage übersetzen und nicht nur Zeichenketten. Das würde Benutzern
+ermöglichen, landesspezifische Zeichen auch in Datenbank-, Tabellen- und
+Spaltenamen zu benutzen.
+@item
+Hinzufügen einer portablen Schnittstelle zu @code{gethostbyaddr_r()},
+damit wir @code{ip_to_hostname()} davon abhalten können, andere Threads zu
+blockieren, während es DNS-Lookups durchführt.
+@item
+Hinzufügen der @code{record_in_range()}-Methode zu @code{MERGE}-Tabellen,
+um den richtigen Index auswählen zu können, wenn es viele gibt, aus denen
+ausgewählt werden kann. Wir sollten auch die info-Schnittstelle erweitern,
+um die Schlüsselverteilung für jeden Index zu erhalten, wenn @code{analyze}
+über alle Unter-Tabellen läuft.
+@item
+@code{SET SQL_DEFAULT_TABLE_TYPE=[MyISAM | INNODB | BDB | HEAP]}.
+@end itemize
+
+
+@node TODO future, TODO sometime, TODO MySQL 4.0, TODO
+@c German node TODO zukünftig
+@subsection Dinge, die in naher Zukunft erledigt werden müssen
+
+@itemize @bullet
+@item
+Unteranfragen (Subqueries).
+@code{select id from t where grp in (select grp from g where u > 100)}
+@item
+Atomische Multi-Tabellen-Updates, zum Beispiel @code{update items,month set
+items.price=month.price where items.id=month.id;};
+@item
+Abgeleitete Tabellen (Derived Tables).
+@example
+select a.col1, b.col2 from (select max(col1) as col1 from root_table ) a,
+other_table b where a.col1=b.col1
+@end example
+
+Das könnte erreicht werden, indem für die Dauer der Anfrage automatisch
+temporäre Tabellen für die abgeleiteten Tabellen erzeugt werden.
+@item
+Hinzufügen eines @code{PREPARE} von Statements und Senden von Parametern an
+@code{mysqld}.
+@item
+Erweiterung des Client-Server-Protokolls, um Warnungen (Warnings) zu
+unterstützen.
+@item
+Hinzufügen von Optionen zum Client-Server-Protokoll, um
+Fortschrittsanzeigen für lange laufende Kommandos zu erhalten.
+@item
+Hinzufügen von Datenbank und echtem Tabellennamen (im Falle von Alias) zur
+MYSQL_FIELD-Struktur.
+@item
+Nicht mehr als die festgelegte Anzahl von Threads zulassen, um MyISAM
+recover zeitgleich laufen zu lassen.
+@item
+@code{INSERT ... SELECT} ändern, um optional konkurrierende Inserts zu
+benutzen.
+@item
+@code{RENAME DATABASE} implementieren. Damit das sicher für alle
+Tabellen-Handler funktioniert, sollte es wie folgt laufen:
+@itemize @bullet
+@item
+Neue Datenbank anlegen.
+@item
+Für jede Tabelle ein Umbenennen der Tabelle zu einer anderen Datenbank
+durchführen, wie wir es schon mit dem @code{RENAME}-Befehl machen.
+@item
+Alte Datenbank löschen.
+@end itemize
+@item
+Die Original-Feldtypen zurückgeben, wenn @code{SELECT MIN(column)... GROUP
+BY} ausgeführt wird.
+@item
+Mehrfache Ergebnismengen (Multiple Result Sets).
+@item
+Änderung des Protokolls, um Binärübertragung von Werten zu ermöglichen. Um
+das effizient zu machen, müssen wir eine API hinzufügen, die Bindung
+(Binding) von Variablen erlaubt.
+
+
+@code{mysqld}.
+@item
+Es soll möglich sein, @code{long_query_time} mit einer Auflösung in
+Mikrosekunden festzulegen.
+@item
+Hinzufügen eines konfigurierbaren Prompts zum
+@code{mysql}-Kommandozeilen-Werkzeug, mit Optionen wie Datenbank in Benutzung,
+Zeit und Datum ...
+@item
+Hinzufügen von Bereichsüberprüfung (Range Checking) zu
+@code{MERGE}-Tabellen.
+@item
+@code{myisampack}-Code in den Server einlinken.
+@item
+Portierung von MySQL auf BeOS.
+@item
+Portierung von MySQL-Clients auf LynxOS.
+@item
+Hinzufügen eines temporären Schlüssel-Puffer-Caches während
+@code{INSERT/DELETE/UPDATE}, um den vorherigen Zustand elegant
+wiederherstellen zu können, wenn der Index voll wird.
+@item
+Wenn ein @code{ALTER TABLE} auf eine Tabelle durchgeführt wird, die per
+Symlink auf einer anderen Festplatte ist, temporäre Tabellen auf dieser
+Festplatte erzeugen.
+@item
+Implementierung eines @code{DATE/DATETIME}-Typs, der
+Zeitzonen-Informationen sauber handhabt, damit der Umgang mit Datumswerten
+in verschiedenen Zeitzonen leichter wird.
+@item
+FreeBSD- und MIT-pThreads; nehmen schlafende Threads CPU in Anspruch?
+@item
+Prüfen, ob gesperrte Threads CPU beanspruchen.
+@item
+Configure reparieren, so dass man alle Bibliotheken (wie @code{MyISAM})
+ohne Threads kompilieren kann.
+@item
+Hinzufügen einer Option, um regelmäßig die Schlüsselseiten (Key Pages) für
+Tabellen mit verzögerten Schlüsseln (Delayed Keys) zu löschen (flush), wenn
+Sie eine Weile nicht in Gebrauch waren.
+@item
+Verknüpfungen (Join) auf Teile des Schlüssels zulassen (Optimierungsthema).
+@item
+@code{INSERT SQL_CONCURRENT} und @code{mysqld --concurrent-insert} sollen
+ein konkurrierendes Insert am Ende der Datei machen, falls die Datei
+lese-gesperrt ist.
+@item
+@code{FOREIGN}-Key-Festlegungen in der @file{.frm}-Datei speichern.
+@item
+Kaskadierendes Löschen (@code{DELETE})
+@item
+Serverseitige Cursor.
+@item
+Prüfen, ob @code{lockd} mit modernen Linux-Kernels funktioniert; wenn
+nicht, müssen wir @code{lockd} überarbeiten! Um das zu testen, startet man
+@code{mysqld} mit @code{--enable-locking} und läßt die verschiedenen fork*
+test suits laufen. Sie sollten keine Fehler produzieren, wenn @code{lockd}
+funktioniert.
+@item
+SQL-Variablen in @code{LIMIT} zulassen, wie @code{LIMIT @@a,@@b}.
+@item
+Aktualisierung von Variablen in @code{UPDATE}-Statements zulassen, zum
+Beispiel: @code{UPDATE TABLE foo SET @@a=a+b,a=@@a, b=@@a+c}
+@item
+Wenn Benutzervariablen aktualisiert werden, so ändern, dass man sie mit
+@code{GROUP BY} benutzen kann wie in folgendem Beispiel:
+@code{SELECT id, @@a:=count(*), sum(sum_col)/@@a FROM tabelle GROUP BY id}.
+@item
+Keine automatischen @code{DEFAULT}-Werte zu Spalten hinzufügen. Fehler
+ausgeben, wenn ein @code{INSERT} benutzt wird, dass keine Spalte enthält,
+die keinen @code{DEFAULT}-Wert hat.
+@item
+Caching von Anfragen und Ergebnissen. Das sollte als separates Modul
+gemacht werden, das jede Anfrage prüft. Falls diese Anfrage im Cache ist,
+soll das Cache-Ergebnis zurückgegeben werden. Wenn man eine Tabelle
+aktualisiert, sollte man so wenige Anfragen wie möglich aus dem Cache
+entfernen. Das sollte eine große Geschwindigkeitssteigerung auf Maschinen
+geben, die viel RAM haben und wo Anfragen of wiederholt werden (wie
+WWW-Applikationen). Eine Idee wäre, nur Anfrage des Typs
+@code{SELECT CACHED ...}
+zu cachen.
+@item
+@file{libmysql.c} überarbeiten, damit zwei @code{mysql_query()}-Befehle in
+einer Zeile stehen können, ohne dass Ergebnisse gelesen werden oder man
+eine nette Fehlermeldung erhält, wenn man das tut.
+@item
+Optimierung des @code{BIT}-Typs, so dass er 1 Bit aufnimmt (momentan nimmt
+@code{BIT} 1 Zeichen auf).
+@item
+Prüfen, warum MIT-pThreads @code{ctime()} auf einigen FreeBSD-Systemen
+nicht funktioniert.
+@item
+Hinzufügen einer @code{IMAGE}-Option zu @code{LOAD DATA INFILE}, damit
+@code{TIMESTAMP}- und @code{AUTO_INCREMENT}-Felder nicht aktualisiert
+werden.
+@item
+@code{LOAD DATE INFILE.. UPDATE}-Syntax hinzufügen.
+@itemize @bullet
+@item
+Wenn Daten bei Tabellen mit Primärschlüssel den Primärschlüssel enthalten,
+werden Einträge, die zu diesem Primärschlüssel passen, vom Rest der Spalten
+aktualisert. Spalten, die im herein kommenden Datenstrom NICHT enthalten
+sind, werden jedoch nicht berührt.
+@item
+Bei Tabellen mit Primärschlüsseln, wo im herein kommenden Datenstrom ein
+Teil des Schlüssels fehlt, oder wenn kein Primärschlüssel eingegeben wird,
+wird die Eingabe so behandelt wie jetzt schon @code{LOAD DATA INFILE ...
+REPLACE INTO}.
+@end itemize
+@item
+@code{LOAD DATA INFILE} soll auch folgende Syntax verstehen:
+@example
+LOAD DATA INFILE 'datei.txt' INTO TABLE tabelle
+TEXT_FIELDS (text_feld1, text_feld2, text_feld3)
+SET tabelle_feld1=concatenate(text_feld1, text_feld2), tabelle_feld3=23
+IGNORE text_feld3
+
+Das kann benutzt werden, um zusätzliche Spalten in der Textdatei zu
+überspringen oder um Spalten basierend auf Ausdrücken in den gelesenen
+Daten zu aktualisieren ...
+@end example
+@item
+@code{LOAD DATA INFILE 'datei' INTO TABLE 'tabelle' ERRORS TO err_tabelle}
+Das würde bewirken, dass alle Fehler und Warnungen in der err_tabelle
+mitgeschrieben werden. Diese Tabelle hätte etwa folgende Struktur:
+
+@example
+zeile_nummer - Zeilennummer in der Datendatei
+fehler_nachricht - die Fehler-/Warnungs-Nachricht
+und vielleicht
+@c German FIX changed all "@cQuestion ..." lines to "@c Question ..." (space).
+@c Question: ??? This is already logged in zeile_nummer (line_number)!
+daten_zeile - die Zeilennummer der Datendatei
+@end example
+@item
+Hinzufügen von echter @code{VARCHAR}-Unterstützung (gibt es schon in
+MyISAM).
+@item
+Automatische Ausgabe von @code{mysql} an Netscape.
+@item
+@code{LOCK DATABASES}. (mit vielerlei Optionen)
+@item
+
+
+Ändern wie Sortierung Speicher alloziert, um bessere
+Speicherausnutzung zu erhalten.
+@item
+@code{DECIMAL}- und @code{NUMERIC}-Typen können keine exponentiellen Zahlen
+lesen; @code{Field_decimal::store(const char *from,uint len)} muss neu
+kodiert werden, um das zu beheben.
+@item
+@code{mysql.cc} überarbeiten, damit weniger @code{malloc()}-Aufrufe
+durchgeführt werden, wenn Feldnamen gehasht werden.
+@item
+Funktionen:
+ADD_TO_SET(wert,set) und REMOVE_FROM_SET(wert,set)
+@item
+Benutzung von @code{t1 JOIN t2 ON ...} und @code{t1 JOIN t2 USING ...}
+hinzufügen. Momentan kann man diese Syntax nur mit @code{LEFT JOIN}
+benutzen.
+@item
+Volle Unterstützung für @code{unsigned long long}-Typen hinzufügen.
+@item
+Viele weitere Variablen für @code{show status}. Zähler für:
+@code{INSERT}-/@code{DELETE}-/@code{UPDATE}-Statements. Gelesene und
+aktualisierte Datensätze. Select auf 1 Tabelle und Selects mit Joins.
+Durchschnittliche Anzahl von Tabellen in Selects. Anzahl von @code{ORDER
+BY}- und @code{GROUP BY}-Anfragen.
+@item
+Wenn man @code{mysql} mitten in einer Anfrage abbricht, sollte man eine
+neue Verbindung herstellen und die alte, laufende Anfrage killen.
+Alternativ könnte man den Versuch unternehmen, so etwas im Server zu
+entdecken.
+@item
+Eine Handler-Schnittstelle für Tabelleninformation hinzufügen, damit man
+sie als Systemtabelle benutzen kann. Das wäre ein bisschen langsam, wenn
+man Informationen über alle Tabellen abfragt, aber sehr flexibel.
+@code{SHOW INFO FROM tabelle} für Basisinformationen über Tabellen sollte
+implementiert werden.
+@item
+Unterstützung für UNICODE hinzufügen.
+@item
+@code{NATURAL JOIN} und @code{UNION JOIN}.
+@item
+Anfragen wie @code{select a from crash_me left join crash_me2 using (a)}
+zulassen; in diesem Fall wird angenommen, dass a aus der crash_me-Tabelle
+kommt.
+@item
+Überarbeitung, damit @code{ON} und @code{USING} mit dem
+@code{JOIN}-Verknüpfungstyp funktioniert.
+@item
+Oracle-mäßiges @code{CONNECT BY PRIOR ...}, um hierarchische Strukturen zu
+durchsuchen.
+
+
+@item
+@code{mysqladmin copy datenbank neue_datenbank}. -- Erfordert, dass
+@code{mysqld} der COPY-Befehl hinzugefügt wird.
+@item
+Prozessliste sollte die Anzahl von Anfragen pro Thread zeigen.
+@item
+
+
+@code{SHOW HOSTS} zur Informationsausgaben über den Hostnamen-Cache.
+@item
+
+
+
+@item
+Format von @code{DATETIME} ändern, um Bruchteile von Sekunden zu speichern.
+@item
+Alle fehlenden ANSI92- und ODBC 3.0-Typen hinzufügen.
+@item
+Für berechnete Spalten Tabellennamen von leerer Zeichenkette zu @code{NULL}
+ändern.
+@item
+'Item_copy_string' nicht auf numerische Werte anwenden, um
+Zahl->Zeichenkette->Zahl-Umwandlung zu vermeiden, im Falle von:
+@code{SELECT COUNT(*)*(id+0) FROM tabelle GROUP BY id}
+@item
+Benutzung der neuen GNU-regexp-Bibliothek anstelle der aktuellen
+ermöglichen (die GNU-Bibliothek sollte viel schneller sein als die alte).
+@item
+@code{ALTER TABLE} sollte nicht mehr Clients abbrechen, die @code{INSERT
+DELAYED} ausführen.
+@item
+So überarbeiten, dass, wenn Spalten, auf die in einer @code{UPDATE}-Klausel
+verwiesen wird, die alten Werte enthalten, bevor das Update begonnen wird.
+@item
+@code{myisamchk}, @code{REPAIR} und @code{OPTIMIZE TABLE} sollten in der
+Lage sein, mit Fällen umzugehen, wo die Daten und / oder Indexdateien
+symbolische Links sind.
+@item
+Simulation von @code{pread()}/@code{pwrite()} auf Windows einarbeiten, um
+konkurrierende Inserts zu ermöglichen.
+@item
+Ein Logdatei-Analyzer, aus dem Informationen herausgefiltert (geparst)
+werden können, welche Tabellen am häufigsten angesprochen werden, wie oft
+Verknüpfungen (Joins) mit mehreren Tabellen ausgeführt werden usw. Es
+sollte Benutzern helfen, Bereiche oder Dinge im Tabellenentwurf zu
+erkennen, die optimiert werden können, um sehr viel effizientere Anfragen
+auszuführen.
+@item
+Add @code{SUM(DISTINCT)}
+@item
+@code{ANY()}-,@code{EVERY()}- und @code{SOME()}-Gruppierungsfunktionen
+hinzufügen. In ANSI-SQL funktionieren diese auf boolsche Spalten, aber wir
+können sie so erweitern, dass sie mit beliebigen Spalten / Ausdrücken
+funktionieren, indem wir folgendes anwenden: wert == 0 -> FALSE und
+wert <> 0 -> TRUE.
+@item
+So überarbeiten, dass @code{MAX(column)} vom selben Typ ist wie der
+Spaltentyp.
+@example
+create tabelle t1 (a DATE);
+insert into t1 values (now());
+create tabelle t2 select max(a) von t1;
+show columns from t2;
+@end example
+@item
+Eine nette Syntax für ein Statement entwickeln, dass auf eine Zeile ein
+@code{UPDATE} ausführt, wenn sie existiert, und eine neue Zeile einfügt
+(@code{INSERT}), wenn sie nicht existiert (so wie @code{REPLACE} bei
+@code{INSERT} / @code{DELETE} funktioniert).
+@end itemize
+
+
+@node TODO sometime, TODO unplanned, TODO future, TODO
+@c German node TODO irgendwann
+@subsection Dinge die irgendwann gemacht werden müssen
+
+@itemize @bullet
+@item
+Funktion implementieren: @code{get_changed_tables(timeout,table1,table2,...)}
+@item
+Lesen durch Tabellen so ändern, das memmap benutzt wird, falls möglich.
+Momentan benutzen nur komprimierte Tabellen memmap.
+@item
+Ein neues Zugriffsrecht @strong{'Show_priv'} für @code{SHOW}-Befehle
+hinzufügen.
+@item
+Den automatischen Zeitstempel-Code netter machen. Zeitstempel zum
+Update-Log hinzufügen mit @code{SET TIMESTAMP=#;}
+@item
+An manchen Stellen read/write mutex benutzen, um mehr Geschwindigkeit zu
+erhalten.
+@item
+Volle Unterstützung von Fremdschlüsseln. Wahrscheinlich wird man zuerst
+einmal eine prozedurale Sprache implementieren wollen.
+@item
+Einfache Sichten (Views; zunächst auf eine Tabelle, später auf jeden
+beliebigen Ausdruck).
+@item
+Automatisches Schließen einiger Tabellen, wenn eine Tabelle, eine
+temporäre Tabelle oder eine temporäre Datei einen Fehler 23 bekommt
+(nicht genug offene Dateien).
+@item
+Wenn ein Feld=# gefunden wird, alle Vorkommen von Feld auf # setzen.
+Momentan wird das nur in einigen einfachen Fällen gemacht.
+@item
+Alle konstanten Ausdrücke mit berechneten Ausdrücken austauschen, falls
+möglich.
+@item
+schlüssel = ausdruck optimieren. Momentan wird nur schlüssel = feld oder
+schlüssel = konstante optimiert.
+@item
+Einige der Copy-Funktionen verbinden, um netter Code zu erhalten.
+@item
+@file{sql_yacc.yy} in einen Inline-Parser umändern, um die Größe zu
+reduzieren und bessere Fehlermeldungen zu erhalten (5 Tage).
+@item
+Den Parser so ändern, dass er nur eine Regel pro unterschiedlicher Anzahl
+von Argumenten in Funktionen benutzt.
+@item
+Die Benutzung von vollen Berechnungsnamen (full calculation names) im
+ORDER-Teil (order part). (Für ACCESS97)
+@item
+@code{UNION}, @code{MINUS}, @code{INTERSECT} und @code{FULL OUTER JOIN}.
+(Momentan wird nur @code{LEFT OUTER JOIN} unterstützt.)
+@item
+@code{UNIQUE} bei Feldern zulassen, die @code{NULL} sein können.
+@item
+@code{SQL_OPTION MAX_SELECT_TIME=#} um einer Anfrage eine Zeitbeschränkung
+zu setzen.
+@item
+@c Question: Check translation!
+Make the update log to a Datenbank.
+Update soll in eine Datenbank loggen.
+@item
+Negative @code{LIMIT}-Parameter, um Daten vom Ende abrufen zu können.
+@item
+@c Question: Alarm? Wake up?
+Alarm around client connect/read/write Funktionen.
+@item
+Bitte beachten sie die Änderungen in @code{safe_mysqld}: Nach FSSTND (woran
+sich Debian versucht zu halten) sollten PID-Dateien als
+@file{/var/run/<progname>.pid} angelegt werden und Log-Datei in
+@file{/var/log}. Es wäre nett, wenn man "DATADIR" in die erste Deklaration
+von "pidfile" und "log" packen könnte, damit die Unterbringung dieser
+Dateien mit einem einzigen Statement geändert werden könnte.
+@item
+Einem Client erlauben, Mitloggen anzufordern.
+@item
+Benutzung von @code{zlib()} für @code{gzip}-te Dateien in @code{LOAD DATA
+INFILE} zulassen.
+@item
+Sortieren und Gruppieren von @code{BLOB}-Spalten in Ordnung bringen
+(teilweise bereits gelöst).
+@item
+Gespeicherte Prozeduren. Wird aktuell nicht als sehr wichtig erachtet, weil
+gespeicherte Prozeduren noch nicht sehr standardisiert sind. Ein weiteres
+Problem besteht darin, dass es echte gespeicherte Prozeduren dem Optimierer
+viel schwerer machen und dass in vielen Fällen das Ergebnis langsamer sein
+wird als vorher. Auf der anderen Seite werden wir versuchen, eine einfache
+(atomische) Update-Sprache hinzuzufügen, die benutzt werden kann, um
+Schleifen und ähnliches im MySQL-Server zu schreiben.
+@item
+So ändern, dass Semaphore benutzt werden, wenn Threads gezählt werden. Man
+sollte zuerst eine Semaphor-Bibliothek zu MIT-pThreads implementieren.
+@item
+Keinen neuen @code{AUTO_INCREMENT}-Wert zuweisen, wenn eine Spalte auf 0
+gesetzt wird. Statt dessen @code{NULL} setzen.
+@item
+Volle Unterstützung von Verknüpfungen (@code{JOIN}) mit Klammern.
+@item
+Als Alternative für einen Thread pro Verbindung einen Pool von Threads
+verwalten, der die Anfragen handhabt.
+@item
+Einem gestatten, mehr als eine Sperre (Lock) mit @code{GET_LOCK} zu
+erhalten. Wenn man das tut, muss man die möglichen Deadlocks handhaben, die
+diese Änderung einführen wird.
+@end itemize
+
+Zeitangaben stehen für den Umfang der Arbeit, nicht für echte Zeit.
+
+
+@node TODO unplanned, , TODO sometime, TODO
+@c German node TODO ungeplant
+@subsection Ein paar Dinge, für deren Umsetzung wir keine Pläne haben
+
+@itemize @bullet
+@item
+Nichts; auf lange Sicht planen wir, voll ANSI-92- / ANSI-99-kompatibel zu
+sein.
+@end itemize
+
+
+@node Comparisons, , TODO, Deutsch
+@c German node Vergleiche
+@section MySQL im Vergleich mit anderen Datenbanken
+
+@cindex Datenbanken, MySQL im Vergleich mit anderen
+@cindex Vergleich, MySQL zu anderen
+
+
+Dieser Abschnitt vergleicht MySQL mit anderen populären Datenbanken.
+
+Dieser Abschnitt wurde von den MySQL-Entwicklern geschrieben. Das sollte
+man beim Lesen im Hinterkopf behalten. In diesem Abschnitt sind - soweit
+uns bekannt - keine sachlichen Fehler enthalten. Wenn Sie etwas finden, was
+Sie als sachlichen Fehler erachten, kontaktieren Sie uns bitte unter
+@email{docs@@mysql.com}.
+
+Eine Liste aller unterstützten Limits, Funktionen und Typen finden Sie auf
+der @code{crash-me}-Webseite auf
+@uref{http://www.mysql.com/information/crash-me.php}.
+
+
+@menu
+* Compare mSQL::
+* Compare PostgreSQL::
+@end menu
+
+@node Compare mSQL, Compare PostgreSQL, Comparisons, Comparisons
+@c German node Vergleich mit mSQL
+@subsection MySQL im Vergleich mit @code{mSQL}
+
+@table @strong
+@item Performance
+
+Um einen echten Geschwindigkeitsvergleich zu sehen, schauen Sie bitte in
+der wachsenden Liste der MySQL-Benchmarks nach. @xref{MySQL Benchmarks}.
+
+Weil es keinen Overhead für die Erzeugung von Threads besitzt, einen
+kleineren Parser, weniger Features und einfache Sicherheitsmechanismen,
+sollte @code{mSQL} in folgenden Punkten schneller sein:
+
+@itemize @bullet
+@item
+Tests, die wiederholten Verbindungsaufbau und -abbau durchführen, wobei
+während jeder Verbindung eine sehr einfache Anfrage ausgeführt wird.
+
+@item
+@code{INSERT}-Operationen auf sehr einfache Tabellen mit wenigen Spalten
+und Schlüsseln.
+
+@item
+@code{CREATE TABLE} und @code{DROP TABLE}.
+
+@item
+@code{SELECT} auf alles, was kein Index ist. (Ein Tabellen-Scan ist sehr
+einfach.)
+@end itemize
+
+Weil diese Operationen so einfach sind, ist es schwer, hier besser zu sein,
+wenn man beim Starten einen größeren Overhead hat. Nachdem die Verbindung
+erst einmal aufgebaut ist, sollte MySQL wesentlich bessere Leistungsdaten
+bringen.
+
+Andererseits ist MySQL sehr viel schneller als @code{mSQL} (und den meisten
+anderen SQL-Implementationen) bei Folgendem:
+
+@itemize @bullet
+@item
+Komplexe @code{SELECT}-Operationen.
+
+@item
+Wenn große Ergebnismengen abgefragt werden (MySQL hat ein besseres,
+schnelleres und sichereres Protokoll).
+
+@item
+Tabellen mit Zeichenketten variabler Länge, denn MySQL hat eine
+effizientere Handhabung und kann Indizes auf @code{VARCHAR}-Spalten haben.
+
+@item
+Handhabung von Tabellen mit vielen Spalten.
+
+@item
+Handhabung von Tabellen mit großer Datensatzlänge.
+
+@item
+@code{SELECT} mit vielen Ausdrücken.
+
+@item
+@code{SELECT} auf große Tabellen.
+
+@item
+Handhabung vieler gleichzeitiger Verbindungen. MySQL ist voll
+Multi-Thread-fähig. Jede Verbindung hat ihren eigenen Thread, was bedeutet,
+dass kein Thread auf einen anderen warten muss (ausser wenn ein Thread eine
+Tabelle verändert, auf die ein anderer Thread zugreifen will). In
+@code{mSQL} müssen nach dem Verbindungsaufbau alle anderen warten, bis die
+erste Verbindung beendet wurde, egal, ob diese Verbindung eine Anfrage
+ausführt, die kurz oder lang ist. Wenn die erste Verbindung abgebaut wird,
+kann die zweite bedient werden, während alle anderen noch warten, usw.
+
+@item
+Joins (Verknüpfungen).
+@code{mSQL} kann krankhaft langsam werden, wenn Sie die Reihenfolge von
+Tabellen in einem @code{SELECT}-Statement ändern. In einem Benchmark-Test
+wurde beobachtet, dass es mehr als 15000-mal langsamer werden kann als
+MySQL. Das liegt daran, dass @code{mSQL} keinen Verknüpfungs-Optimierer
+(Join Optimizer) besitzt, der die Tabellen in optimale Reihenfolge bringt.
+Wenn Sie allerdings exakt die richtige Reihenfolge in @code{mSQL}2 benutzen
+und wenn die @code{WHERE}-Klausel einfach ist und Spalten-Indexe benutzt,
+wird die Verknüpfung relativ schnell sein!
+@xref{MySQL Benchmarks}.
+
+@item
+@code{ORDER BY} und @code{GROUP BY}.
+
+@item
+@code{DISTINCT}.
+
+@item
+Benutzung von @code{TEXT}- oder @code{BLOB}-Spalten.
+@end itemize
+
+@item SQL-Features
+
+@itemize @bullet
+@item @code{GROUP BY} und @code{HAVING}.
+@code{mSQL} unterstützt @code{GROUP BY} überhaupt nicht.
+MySQL unterstützt @code{GROUP BY} vollständig, sowohl mit @code{HAVING} als
+auch mit den folgenden Funktionen: @code{COUNT()}, @code{AVG()}, @code{MIN()},
+@code{MAX()}, @code{SUM()} und @code{STD()}. @code{COUNT(*)} ist darauf
+optimiert, sehr schnell Ergebnisse zu liefern, wenn @code{SELECT} aus einer
+Tabelle abfragt, wenn keine andere Spalte abgerufen wird und wenn es keine
+@code{WHERE}-Klausel gibt. @code{MIN()} und @code{MAX()} können
+Zeichenketten-Argumente entgegennehmen.
+
+@item @code{INSERT} und @code{UPDATE} mit Berechnungen.
+MySQL kann Berechnungen in @code{INSERT}- oder @code{UPDATE}-Statements
+ausführen. Beispiel:
+
+@example
+mysql> UPDATE SET x=x*10+y WHERE x<20;
+@end example
+
+@item Aliase.
+MySQL hat Spalten-Aliase.
+
+@item Qualifizierende Spaltenamen.
+In MySQL muss man nicht den voll qualifizierenden Namen benutzen, wenn eine
+Spalte in den benutzten Tabellen eindeutig ist.
+
+@item @code{SELECT} mit Funktionen.
+MySQL hat viele Funktionen (zu viele, um sie hier aufzulisten; siehe
+@ref{Functions}).
+
+@end itemize
+
+@item Effiziente Ausnutzung von Speicherplatz
+Das heißt, wie klein können Sie Ihre Tabellen machen?
+
+MySQL hat sehr präzise Typen, deshalb können Sie Tabellen erzeugen, die
+sehr wenig Platz brauchen. Ein Beispiel für einen nützlichen MySQL-Datentyp
+ist @code{MEDIUMINT}, der 3 Bytes lang ist. Wenn Sie 100 Millionen
+Datensätze haben, ist es schon von Wichtigkeit, auch nur ein Byte pro
+Datensatz zu sparen.
+
+@code{mSQL2} hat eine begrenztere Anzahl von Spaltentypen, daher ist es
+schwieriger, kleine Tabellen zu erhalten.
+
+@item Stabilität
+Dieser Punkt ist schwieriger objektiv zu beurteilen. Eine Erörterung der
+Stabilität von MySQL finden Sie hier: @ref{Stability}.
+
+Wir haben keine Erfahrungen mit der Stabilität von @code{mSQL}, daher
+können wir nichts darüber sagen.
+
+@item Preis
+Ein weiterer wichtiger Punkt ist die Lizenz. MySQL hat eine flexiblere
+Lizenz als @code{mSQL} und kostet auch weniger als @code{mSQL}. Welches
+Produkt auch immer Sie verwenden, ziehen Sie bitte zumindestens in
+Betracht, für eine Lizenz oder E-Mail-Support zu zahlen. (Sie müssen
+natürlich notwendigerweise eine Lizenz erwerben, wenn Sie MySQL in ein
+Produkt einbeziehen, das Sie verkaufen.)
+
+@item Perl-Schnittstellen
+MySQL hat prinzipiell dieselben Schnittstelle zu Perl wie @code{mSQL}, mit
+einigen zusätzlichen Features.
+
+@item JDBC (Java)
+MySQL hat aktuell eine große Anzahl von JDBC-Treibern:
+
+@itemize @bullet
+@item
+Die mm-Treiber: Ein Typ-4 JDBC-Treiber von Mark Matthews
+@email{mmatthew@@ecn.purdue.edu}. Er ist unter LGPL veröffentlicht.
+
+@item
+Der Resin-Treiber. Das ist ein kommerzieller JDBC-Treiber, der unter Open
+Source veröffentlicht ist. @uref{http://www.caucho.com/Projekte/jdbc-mysql/index.xtp}
+
+@item
+Der gwe-Treiber: Eine Java-Schnittstelle von GWE technologies (wird nicht
+mehr unterstützt).
+
+@item
+Der jms-Treiber: Ein verbesserter gwe-Treiber von Xiaokun Kelvin ZHU
+@email{X.Zhu@@brad.ac.uk} (wird nicht mehr unterstützt).
+
+@item
+Der twz-Treiber: Ein Typ-4 JDBC-Treiber von Terrence W. Zellers
+@email{zellert@@voicenet.com}. Das ist ein kommerzieller Treiber, der für
+Privatgebrauch und Schulungszwecke kostenlos ist (wird nicht mehr
+unterstützt).
+@end itemize
+
+Der empfohlene Treiber ist der mm-Treiber. Der Resin-Treiber mag auch gut
+sein (zumindest sehen die Benchmarks gut aus), aber wir haben über diesen
+Treiber noch nicht allzu viele Informationen erhalten.
+
+Wir wissen, dass @code{mSQL} einen JDBC-Treiber hat, aber wir haben zu
+wenig Erfahrung damit, um ihn in einen Vergleich einzubeziehen.
+
+@item Entwicklungsgeschwindigkeit
+MySQL hat ein sehr kleines Entwicklerteam, aber wir arbeiten schon lange
+mit C und C++ und sind daher sehr schnell. Weil Threads, Funktionen,
+@code{GROUP BY} usw. noch nicht in @code{mSQL} implementiert sind, hat es
+eine Menge aufzuholen. Um das in den richtigen Blickwinkel zu rücken,
+können Sie sich die @code{mSQL} @file{HISTORY}-Datei des letzten Jahres
+ansehen und sie mit dem News-Abschnitt des MySQL Referenzhandbuchs
+vergleichen (@pxref{News}). Es ist ziemlich offensichtlich, welches System
+sich schneller entwickelt hat.
+
+@item Utilities
+Sowohl @code{mSQL} als auch MySQL haben viele interessante von Dritten
+entwickelte Werkzeuge. Weil es sehr einfach ist, aufwärts zu portieren (von
+@code{mSQL} zu MySQL), sind fast alle interessanten Applikationen, die für
+@code{mSQL} verfügbar sind, auch für MySQL erhältlich.
+
+MySQL liefert ein einfaches @code{msql2mysql}-Programm mit, das
+Unterschiede in der Schreibweise zwischen @code{mSQL} und MySQL für die
+meistbenutzten C-API-Funktionen bereinigt.
+Es ändert zum Beispiel Instanzen von @code{msqlConnect()} zu
+@code{mysql_connect()}. Ein Client-Programm von @code{mSQL} zu MySQL zu
+konvertieren, erfordert meist nur geringe Anstrengung.
+@end table
+
+
+
+@menu
+* Using mSQL tools::
+* Protocol differences::
+* Syntax differences::
+@end menu
+
+@node Using mSQL tools, Protocol differences, Compare mSQL, Compare mSQL
+@c German node mSQL-Werkzeuge benutzen
+@subsubsection Wie man @code{mSQL}-Werkzeuge für MySQL konvertiert
+
+@cindex MySQL-Werkzeuge, Konvertierung
+@cindex Konvertierung, Werkzeuge
+@cindex Werkzeuge, Konvertierung
+
+Nach unserer Erfahrung nimmt es wenig Zeit in Anspruch, Werkzeuge wie
+@code{msql-tcl} und @code{msqljava} zu konvertieren, die die
+@code{mSQL}-C-API benutzen, damit sie mit der MySQL-C-API funktionieren.
+
+Die Konvertierungsprozedur läuft wie folgt:
+
+@enumerate
+@item
+Lassen Sie das Shell-Skript @code{msql2mysql} über den Quelltext laufen.
+Das erfordert das @code{replace}-Programm, das mit MySQL ausgeliefert wird.
+
+@item
+Kompilieren.
+
+@item
+Alle Kompilierfehler beheben.
+@end enumerate
+
+Die Unterschiede zwischen der @code{mSQL}-C-API und der MySQL-C-API sind:
+
+@itemize @bullet
+@item
+MySQL benutzt eine @code{MYSQL}-Struktur als Verbindungstyp, (@code{mSQL}
+benutzt einen @code{int}).
+
+@item
+@code{mysql_connect()} nimmt einen Zeiger (Pointer) auf eine
+@code{MYSQL}-Struktur als Parameter auf. Es ist einfach, einen global zu
+definieren oder @code{malloc()} zu benutzen, um einen zu erhalten.
+@code{mysql_connect()} nimmt zusätzlich zwei Parameter auf, um Benutzer und
+Passwort zu spezifizieren. Sie können diese als Vorgabewert der Benutzung
+auf @code{NULL, NULL} setzen.
+
+@item
+@code{mysql_error()} nimmt die @code{MYSQL}-Struktur als Parameter auf.
+Fügen Sie einfach den Parameter zu Ihrem alten @code{msql_error()}-Code
+hinzu, wenn Sie alten Code portieren.
+
+@item
+MySQL gibt eine Fehlernummer und eine Textnachricht für alle Fehler zurück.
+@code{mSQL} gibt nur eine Fehlernachricht zurück.
+
+@item
+Aufgrund der Tatsache, dass MySQL mehrfache Verbindungen zum Server von
+demselben Prozess aus unterstützt, existieren einige Inkompatibilitäten.
+@end itemize
+
+
+@node Protocol differences, Syntax differences, Using mSQL tools, Compare mSQL
+@c German node Protokollunterschiede
+@subsubsection Wie sich @code{mSQL}- und MySQL-Client/Server-Kommunikationsprotokolle unterscheiden
+
+@cindex Kommunikationsprotokolle
+@cindex mSQL, im Vergleich zu MySQL
+
+Es gibt genug Unterschiede, so dass es unmöglich ist (oder zumindest nicht
+leicht), beide zu unterstützen.
+
+Die signifikantesten Protokollunterschiede zwischen MySQL und @code{mSQL}
+sind folgende:
+
+@itemize @bullet
+@item
+Ein Nachrichtenpuffer (Message Buffer) darf viele Ergebniszeilen enthalten.
+
+@item
+Die Nachrichtenpuffer werden dynamisch vergrößert, wenn die Anfrage oder
+das Ergebnis größer sind als der aktuelle Puffer, bis hin zu einer
+konfigurierbaren Server- und Client-Grenze.
+
+@item
+Alle Pakete werden nummeriert, um duplizierte oder fehlende Pakete
+abzufangen.
+
+@item
+Alle Spaltenwerte werden in ASCII gesendet. Die Längen von Spalten und
+Zeilen werden als komprimierte Binärkodierung gesendet (1, 2 oder 3
+Bytes).
+
+@item
+MySQL kann ungepuffert im Ergebnis lesen (ohne die volle Ergebnismenge im
+Client speichern zu müssen).
+
+@item
+Wenn ein einzelner Lese- / Schreibvorgang mehr als 30 Sekunden in Anspruch
+nimmt, schließt der Server die Verbindung.
+
+@item
+Wenn eine Verbindung länger als 8 Stunden im Leerlauf ist, schließt der
+Server die Verbindung.
+@end itemize
+
+
+@c Question Steve: Check this node for the English original!
+@node Syntax differences, , Protocol differences, Compare mSQL
+@c German node Syntaxunterschiede
+@subsubsection Wie sich die @code{mSQL} 2.0 SQL-Syntax von MySQL unterscheidet
+
+@noindent
+@strong{Spaltentypen}
+
+@table @code
+@item
+MySQL hat folgende zusätzliche Typen (unter anderem;
+@pxref{CREATE TABLE, , @code{CREATE TABLE}}):
+@itemize @bullet
+@item
+@code{ENUM}-Typ für einen Satz von Zeichenketten.
+@item
+@code{SET}-Typ für viele Sätze von Zeichenketten.
+@item
+@code{BIGINT}-Typ für 64-Bit-Ganzzahlen (Integer).
+@end itemize
+@item
+MySQL unterstützt folgende zusätzliche Typ-Attribute:
+@itemize @bullet
+@item
+@code{UNSIGNED}-Option für Ganzzahl-Spalten (Integer).
+@item
+@code{ZEROFILL}-Option für Ganzzahl-Spalten (Integer).
+@item
+@code{AUTO_INCREMENT}-Option für Ganzzahl-Spalten (Integer), die ein
+@code{PRIMARY KEY} sind.
+@xref{mysql_insert_id, , @code{mysql_insert_id()}}.
+@item
+@code{DEFAULT}-Wert für alle Spalten.
+@end itemize
+@item mSQL2
+@code{mSQL}-Spaltentypen korrespondieren mit den unten dargestellten
+MySQL-Typen:
+@multitable @columnfractions .15 .85
+@item @code{mSQL} @strong{Typ} @tab @strong{Korrespondierender MySQL-Typ}
+@item @code{CHAR(len)} @tab @code{CHAR(len)}
+@item @code{TEXT(len)} @tab @code{TEXT(len)}. @code{len} ist die maximale
+Länge.
+Und @code{LIKE} funktioniert.
+@item @code{INT} @tab @code{INT}. Mit vielen weiteren Optionen!
+@item @code{REAL} @tab @code{REAL}. Or @code{FLOAT}. Beide 4- und
+8-Byte-Versionen sind verfügbar.
+@item @code{UINT} @tab @code{INT UNSIGNED}
+@item @code{DATE} @tab @code{DATE}. Benutzt ANSI-SQL-Format statt
+@code{mSQL}'s eigenem Format.
+@item @code{TIME} @tab @code{TIME}
+@item @code{MONEY} @tab @code{DECIMAL(12,2)}. Ein Festkomma-Wert mit zwei
+Dezimalstellen.
+@end multitable
+@end table
+
+@noindent
+@strong{Index-Erzeugung}
+
+@table @code
+@item MySQL
+Indizes können bei der Erzeugung der Tabelle mit dem @code{CREATE
+TABLE}-Statement festgelegt werden.
+@item mSQL
+Indexe müssen erzeugt werden, nachdem die Tabelle erzeugt wurde, mit einem
+separaten @code{CREATE INDEX}-Statements.
+@end table
+
+@noindent
+@strong{Einfügen eines eindeutigen Identifikators (Unique Identifier) in eine Tabelle}
+
+@table @code
+@item MySQL
+Benutzen Sie @code{AUTO_INCREMENT} als Spaltentyp-Spezifizierer.
+@xref{mysql_insert_id, , @code{mysql_insert_id()}}.
+@item mSQL
+Erzeugen Sie eine @code{SEQUENCE} auf eine Tabelle und wählen Sie die
+@code{_seq}-Spalte.
+@end table
+
+@noindent
+@strong{Wie man einen eindeutigen Identifikator (Unique Identifier) für eine Zeile erhält}
+
+@table @code
+@item MySQL
+Fügen Sie der Tabelle einen @code{PRIMARY KEY} oder @code{UNIQUE}-Schlüssel
+hinzu und benutzen Sie diesen.
+Neu ab Version 3.23.11: Wenn der @code{PRIMARY}- oder
+@code{UNIQUE}-Schlüssel nur aus einer Spalte besteht und diese vom Typ
+Ganzzahl (Integer) ist, können Sie auf diese auch mit @code{_rowid}
+verweisen.
+@item mSQL
+Benutzen Sie die @code{_rowid}-Spalte. Beachten Sie, dass sich
+@code{_rowid} im Zeitverlauf möglicherweise ändert, abhängig von vielen
+Faktoren.
+@end table
+
+@noindent
+@strong{Wie man die Zeit erhält, zu der eine Spalte zuletzt geändert wurde}
+
+@table @code
+@item MySQL
+Fügen Sie der Tabelle eine @code{TIMESTAMP}-Spalte hinzu. Diese Spalte wird
+automatisch auf das aktuelle Datum und die aktuelle Zeit gesetzt, und zwar
+bei @code{INSERT}- und @code{UPDATE}-Statements, es sein denn, der Spalte
+wird explizit ein Wert zugewiesen, auch der @code{NULL}-Wert.
+
+@item mSQL
+Benutzen Sie die @code{_timestamp}-Spalte .
+@end table
+
+@noindent
+@strong{@code{NULL}-Wert-Vergleiche}
+
+@table @code
+@item MySQL
+MySQL folgt ANSI-SQL, daher wird ein Vergleich mit @code{NULL} immer zu
+@code{NULL} ausgewertet.
+@item mSQL
+In @code{mSQL} ist @code{NULL = NULL} TRUE. Sie müssen @code{=NULL} zu
+@code{IS NULL} und @code{<>NULL} zu @code{IS NOT NULL}, wenn Sie alten Code
+von @code{mSQL} zu MySQL portieren.
+@end table
+
+@noindent
+@strong{Zeichenketten-Vergleich}
+
+@table @code
+@item MySQL
+Normalerweise werden Zeichenketten-Vergleiche so durchgeführt, dass sie
+unabhängig von der verwendeten Groß-/Kleinschreibung laufen, wobei die
+Sortierreihenfolge vom aktuell verwendeten Zeichensatz abhängt (ISO-8859-1
+Latin1 als Vorgabewert). Wenn Sie das nicht wollen, deklarieren Sie Ihre
+Spalten mit dem @code{BINARY}-Attribut, was bewirkt, dass Vergleiche nach
+der ASCII-Reihenfolge durchgeführt werden, wobei der ASCII-Zeichensatz
+gilt, den der MySQL-Server-Host verwendet.
+@item mSQL
+Alle Zeichenketten-Vergleiche werden so durchgeführt, dass sie abhängig von
+der verwendeten Groß-/Kleinschreibung laufen. Die Sortierung erfolgt in
+ASCII-Reihenfolge.
+@end table
+
+@noindent
+@strong{Suche, die unabhängig von Groß-/Kleinschreibung läuft}
+
+@table @code
+@item MySQL
+@code{LIKE} ist ein Operator, der abhängig oder unabhängig von der
+Groß-/Kleinschreibung läuft, was davon abhängt, welche Spalten verwendet
+werden. Wenn möglich, benutzt MySQL Indexe, wenn das @code{LIKE}-Argument
+nicht mit einem Platzhalterzeichen (Wildcard) beginnt.
+@item mSQL
+Benutzt @code{CLIKE}.
+@end table
+
+@noindent
+@strong{Handhabung von Leerzeichen am Ende}
+
+@table @code
+@item MySQL
+Entfernt alle Leerzeichen am Ende von @code{CHAR}- und
+@code{VARCHAR}-Spalten. Benutzen Sie eine @code{TEXT}-Spalte, wenn dieses
+Verhalten unerwünscht ist.
+@item mSQL
+Behält Leerzeichen am Ende bei.
+@end table
+
+@noindent
+@strong{@code{WHERE}-Klauseln}
+
+@table @code
+@item MySQL
+MySQL priorisiert alles korrekt (@code{AND} wird vor @code{OR}
+ausgewertet). Um @code{mSQL}-Verhalten in MySQL zu erreichen, benutzen
+Sie Klammern (wie im unten stehenden Beispiel gezeigt).
+@item mSQL
+Wertet alles von links nach rechts aus. Das bedeutet, dass einige logische
+Berechnungen mit mehr als drei Argumenten überhaupt nicht ausgedrückt
+werden können. Das heißt auch, dass Sie einige Anfragen ändern müssen,
+wenn Sie auf MySQL umsteigen. Das einfachste ist, Klammern hinzuzufügen.
+Nehmen wir an, Sie haben die folgende @code{mSQL}-Anfrage:
+@example
+mysql> SELECT * FROM tabelle WHERE a=1 AND b=2 OR a=3 AND b=4;
+@end example
+Damit MySQL dies auf dieselbe Art auswertet wie @code{mSQL}, müssen Sie
+Klammern hinzufügen:
+@example
+mysql> SELECT * FROM tabelle WHERE (a=1 AND (b=2 OR (a=3 AND (b=4))));
+@end example
+@end table
+
+@noindent
+@strong{Zugriffskontrolle}
+
+@table @code
+@item MySQL
+Hat Tabellen, in denen Berechtigungsoptionen pro Benutzer, Host, und
+Datenbank gespeichert werden. @xref{Privileges}.
+@item mSQL
+Hat eine Datei @file{mSQL.acl}, in der Sie Lese-/Schreibrechte für Benutzer
+gewähren können.
+@item
+@end table
+
+
+@node Compare PostgreSQL, , Compare mSQL, Comparisons
+@c German node Vergleich mit PostgreSQL
+@subsection MySQL im Vergleich mit PostgreSQL
+
+@cindex PostgreSQL im Vergleich mit MySQL, Überblick
+
+Wenn Sie das Folgende lesen, beachten Sie bitte, dass sich beide Produkte
+stetig entwickeln. Wir bei MySQL AB und die PostgreSQL-Entwickler geben
+sich alle Mühe, unsere jeweilige Datenbank so gut wie möglich zu machen.
+Daher sind es beide Produkte wert bei der Wahl einer kommerziellen Datenbank
+ernsthaft in Betracht gezogen zu werden.
+
+Der folgende Vergleich wurde von uns bei MySQL AB durchgeführt. Wir haben
+uns bemüht, so akkurat und fair wie möglich zu sein. Da wir aber keine
+vollständige Kenntnis aller PostgreSQL-Features haben, während wir MySQL
+sehr genau kennen, haben wir vielleicht ein paar Dinge falsch verstanden.
+Wir werden das jedenfalls korrigieren, wenn es uns zu Ohren kommt.
+
+Zunächst wollen wir feststellen, dass sowohl PostgreSQL als auch MySQL weit
+verbreitete Produkte sind, die aber unterschiedliche Entwurfsziele haben,
+auch wenn beide sich bemühen, ANSI-SQL-kompatibel zu sein. Das bedeutet,
+dass MySQL für einige Applikationen besser geeignet ist, PostgreSQL für
+andere. Wenn Sie überlegen, welche Datenbank Sie wählen sollen, sollten Sie
+zunächst prüfen, ob die Features der Datenbank für Ihre Applikation
+zufrieden stellend sind. Wenn Sie satte Geschwindigkeit brauchen, wird Ihre
+Wahl wahrscheinlich auf MySQL fallen. Wenn Sie einige der speziellen
+Merkmale brauchen, die nur PostgreSQL anbieten kann, sollten Sie
+@code{PostgreSQL} benutzen.
+
+@cindex PostgreSQL/MySQL, Strategien
+
+
+@menu
+* MySQL-PostgreSQL goals::
+* MySQL-PostgreSQL features::
+* MySQL-PostgreSQL benchmarks::
+@end menu
+
+@node MySQL-PostgreSQL goals, MySQL-PostgreSQL features, Compare PostgreSQL, Compare PostgreSQL
+@c German node MySQL-PostgreSQL-Ziele
+@subsubsection Entwicklungsstragien von MySQL und PostgreSQL
+
+Wenn wir MySQL Dinge hinzufügen, ist es für uns eine Sache der Ehre, eine
+optimale, definitive Lösungen zu schaffen. Der Code sollte so gut sein,
+dass wir keine Notwendigkeit erkennen, ihn in der absehbaren Zukunft zu
+ändern. Wir wollen auch nicht Geschwindigkeit für Features opfern, sondern
+sind aufs Äußerste bestrebt, eine Lösung zu finden, die maximalen
+Durchsatz bietet. Das bedeutet, dass die Entwicklung ein bisschen länger
+dauert, aber die Endergebnisse sind es wert. Diese Art von Entwicklung ist
+nur möglich, weil der gesamte Server-Code nur von wenigen Leuten geprüft
+wird (aktuell zwei), bevor er in den MySQL-Server aufgenommen wird.
+
+Wir bei MySQL AB halten viel von häufigen Releases, um in der Lage zu sein,
+neue Features schnell an unsere Benutzer heraus zu geben. Deshalb bringen
+wir etwa alle drei Wochen ein kleines Release heraus und einen größeren
+Zweig (Branch) einmal im Jahr. Alle Releases werden gründlich mit unseren
+Testwerkzeugen auf vielen verschiedenen Plattformen getestet.
+
+PostgreSQL basiert auf einem Kern (Kernel), zu dem viele Leute etwas
+beigesteuert haben. Bei diesem Vorgehen ist es sinnvoll, dem Hinzufügen
+neuer Features Priorität einzuräumen, statt sie optimal zu implementieren,
+denn man kann immer noch später Dinge optimieren, wenn sich die
+Notwendigkeit hierfür ergibt.
+
+Ein weiterer großer Unterschied zwischen MySQL und PostgreSQL besteht
+darin, dass praktisch der gesamte Code des MySQL-Servers von Entwicklern
+kodiert wurde, die bei MySQL AB angestellt sind und die immer noch am
+Server-Code arbeiten. Ausnahmen bilden die Transaktions-Engines und die
+Regexp-Bibliothek.
+
+Das steht in scharfem Kontrast zum PostgreSQL-Code, wo der größte Teil des
+Codes von einer großen Gruppe von Leuten mit unterschiedlichem Hintergrund
+kodiert wird. Erst kürzlich gaben die PostgreSQL-Entwickler bekannt, dass
+ihre aktuelle Entwicklergruppe endlich Zeit gefunden hat, einen Blick auf
+all den Code der aktuellen PostgreSQL-Version zu werfen.
+
+Beide der genannten Entwicklungsmethoden hat Ihre Vorzüge und Nachteile.
+Wir hier bei MySQL AB sind natürlich der Meinung, dass unser Modell besser
+ist, weil unser Modell bessere Konsistenz gewährleistet sowie mehr
+optimalen und damit wiederverwendbaren Code und deshalb nach unserer
+Meinung weniger Bugs. Weil wir die Autoren des MySQL-Server-Codes sind,
+sind wir besser im Stande, neue Features und Releases zu koordinieren.
+
+
+@node MySQL-PostgreSQL features, MySQL-PostgreSQL benchmarks, MySQL-PostgreSQL goals, Compare PostgreSQL
+@c German node MySQL-PostgreSQL-Features
+@subsubsection Feature-Vergleich von MySQL und PostgreSQL
+
+@cindex PostgreSQL/MySQL, Features
+
+Auf der Seite @uref{http://www.mysql.com/information/crash-me.php,
+crash-me} finden Sie eine Liste der Datenbank-Konstrukte und
+-Beschränkungen, die man automatisch mit einem Programm entdecken kann.
+Beachten Sie jedoch, dass sich etliche numerische Beschränkungen mit
+Start-Optionen der jeweiligen Datenbank ändern lassen. Die genannte Seite
+ist jedoch äußerst nützlich, wenn Sie sicher stellen wollen, dass Ihre
+Applikationen mit vielen unterschiedlichen Datenbanken funktionieren, oder
+wenn Sie Ihre Applikation von einer Datenbank zu einer anderen konvertieren
+wollen.
+
+MySQL bietet folgende Vorzüge gegenüber PostgreSQL:
+
+@itemize @bullet
+@item
+@code{MySQL} ist generell viel schneller als PostgreSQL.
+@xref{MySQL-PostgreSQL benchmarks}.
+
+@item
+MySQL hat eine viel größere Benutzer-Basis als PostgreSQL, deshalb ist der
+Code besser getestet und hat sich historisch als stabiler erwiesen als der
+von PostgreSQL. MySQL wird sehr viel mehr in Produktionsumgebungen
+eingesetzt als PostgreSQL, hauptsächlich dank der Tatsache, dass MySQL AB,
+früher TCX DataKonsult AB, kommerziellen Support von höchster Qualität für
+MySQL geleistet hat, von dem Tag an, wo MySQL veröffentlicht wurde,
+wohingegen PostgreSQL bis vor kurzem nicht supported war.
+
+@item
+MySQL funktioniert unter Windows besser als PostgreSQL. MySQL läuft als
+native Windows-Applikation (als Systemdienst unter NT/Win2000/WinXP),
+während PostgreSQL unter der cygwin-Emulation läuft. Uns ist zu Ohren
+gekommen, dass PostgreSQL nicht unter Windows nicht sehr stabil läuft, aber
+wir konnten das selbst noch nicht überprüfen.
+
+@item
+MySQL hat mehr APIs zu anderen Sprachen und wird von mehr existierenden
+Programmen unterstützt als PostgreSQL. @xref{Contrib}.
+
+@item
+MySQL läuft auf 24/7-Systemen unter hoher Last. In den meisten Fällen
+braucht man nie irgend welche Cleanups auf MySQL laufen lassen. PostgreSQL
+unterstützt noch keine 24/7-Systeme, weil man gelegentlich @code{VACUUM()}
+laufen lassen muss, um durch @code{UPDATE}- und @code{DELETE}-Kommandos
+beanspruchten Platz zurück zu gewinnen, sowie um statistische Analysen
+durchzuführen, die entscheidend sind, um mit PostgreSQL gute Performance zu
+erzielen. @code{VACUUM()} wird auch benötigt nach dem Hinzufügen vieler
+Zeilen in eine Tabelle. Auf einem ausgelasteten System mit vielen
+Änderungen muss @code{VACUUM()} sehr häufig laufen gelassen werden, im
+schlimmsten Fall mehrmals täglich. Während @code{VACUUM()} läuft, was
+Stunden dauern kann, wenn die Datenbank Groß ist, ist die Datenbank vom
+Produktionsstandpunkt her gesehen praktisch tot. Das PostgreSQL-Team hat
+die Behebung dessen auf seiner TODO-Liste, aber wir vermuten, dass es nicht
+einfach sein wird, das dauerhaft zu beheben.
+
+@item
+Ein funktionierendes, getestetes Replikations-Feature, das unter anderem
+von folgenden Sites benutzt wird:
+@itemize @minus
+@item Yahoo Finance (@uref{http://finance.yahoo.com})
+@item Mobile.de (@uref{http://www.mobile.de/})
+@item Slashdot (@uref{http://www.slashdot.org})
+@end itemize
+
+@item
+In der MySQL-Distribution werden zwei unterschiedliche Test-Suites
+mitgeliefert:
+@file{mysql-test-run} und
+@uref{http://www.mysql.com/information/crash-me.php,crash-me}, sowie eine
+Benchmark-Suite. Das Testsystem wird rege mit Code aktualisiert, um jedes
+neue Feature und alle wiederholbaren Fehler, die uns zu Ohren kamen, zu
+testen. Vor jedem Release testen wir MySQL auf vielen verschiedenen
+Plattformen. Diese Tests sind technisch ausgereifter als alles, was wir von
+PostgreSQL gesehen haben, und sie stellen sicher, dass MySQL auf einem
+hohen Standard gehalten wird.
+
+@item
+Es gibt wesentlich mehr gedruckte Bücher über MySQL als über PostgreSQL.
+Alle großen Verlage wie O'Reilly, Sams, Que und New Riders bieten Bücher
+über MySQL an. Alle MySQL-Features werden ausserdem im
+MySQL-Online-Handbuch dokumentiert, denn wenn ein neues Feature
+implementiert wird, sind die MySQL-Entwickler gehalten, es zu
+dokumentieren, bevor es in den Quelltext eingeschlossen wird.
+
+@item
+MySQL unterstützt mehr Standard-ODBC-Funktionen als @code{PostgreSQL}.
+
+@item
+MySQL hat ein technisch ausgereifteres @code{ALTER TABLE}.
+
+@item
+MySQL unterstützt Tabellen ohne Transaktionen für Applikationen, die so
+viel Geschwindigkeit brauchen, wie sie bekommen können. Tabellen können
+Arbeitsspeicher-basierend, @code{HEAP}-Tabellen oder Festplatten-basierend
+@code{MyISAM} sein. @xref{Table types}.
+
+@item
+MySQL unterstützt zwei verschiedene Tabellen-Handler, die Transaktionen
+unterstützen: @code{BerkeleyDB} und @code{InnoDB}. Weil jede
+Transaktions-Engine unter unterschiedlichen Bedingungen unterschiedlich
+leistungsfähig ist, gibt das dem Applikationsschreiber mehr Optionen, die
+optimale Lösung für seinen Bedarf zu finden. @xref{Table types}.
+
+@item
+@code{MERGE}-Tabellen geben Ihnen eine einzigartige Möglichkeit, eine
+augenblickliche Sicht (View) über eine Reihe identischer Tabellen zu machen
+und diese wie eine zu benutzen. Das ist perfekt für Systeme, auf denen Sie
+Log-Dateien haben, die Sie zum Beispiel nach Monat sortieren. @xref{MERGE}.
+
+@item
+Die Option, Nur-Lese-Tabellen zu komprimieren, aber dennoch direkten
+Zugriff auf die Zeilen der Tabelle zu haben, gibt Ihnen dadurch bessere
+Performance, dass Festplattenzugriffe minimiert werden. Das ist sehr
+nützlich, wenn Sie Dinge archivieren. @xref{myisampack}.
+
+@item
+MySQL hat internen Support für Volltextsuche. @xref{Fulltext Search}.
+
+@item
+Sie können von derselben Verbindung aus auf viele Datenbanken zugreifen
+(was natürlich von Ihren Zugriffsrechten abhängt).
+
+@item
+MySQL wurde von Anfang an multi-threaded kodiert, während PostgreSQL
+Prozesse benutzt. Umschalten zwischen unterschiedlichen Zusammenhängen
+(Context Switching) und Zugriff auf allgemeine Speicherbereiche geht
+zwischen Threads wesentlich schneller als zwischen separaten Prozessen. Das
+bringt MySQL einen großen Geschwindigkeitsvorteil in
+Mehrbenutzer-Applikationen und macht es obendrein für MySQL einfacher, den
+vollen Nutzen aus symmetrischen Multiprozessor-Systemen (SMP) zu ziehen.
+
+@item
+MySQL hat ein technisch ausgereifteres System der Zugriffsberechtigungen
+(Berechtigungssystem) als PostgreSQL.
+PostgreSQL unterstützt nur @code{INSERT}-, @code{SELECT}- und
+@code{UPDATE/DELETE}-Rechtegewährung (Grants) pro Benutzer auf eine
+Datenbank oder Tabelle. MySQL dagegen erlaubt es Ihnen, einen kompletten
+Satz unterschiedlicher Zugriffsrechte auf Datenbank-, Tabellen- und
+Spaltenebene festzulegen. MySQL gestattet es auch, Zugriffsrechte als
+Host- und Benutzer-Kombinationen festzulegen. @xref{GRANT}.
+
+@item
+MySQL unterstützt ein komprimiertes Client/Server-Protokoll, was die
+Performance über langsame Verbindungen verbessert.
+
+@item
+MySQL führt ein ``Tabellen-Handler''-Konzept ein und ist die einzige
+relationale Datenbank, die wir kennen, die um dieses Konzept herum
+aufgebaut ist. Das sorgt dafür, dass unterschiedliche
+Low-Level-Tabellentypen an die SQL-Engine angeflanscht werden können, und
+dass jeder Tabellentyp für unterschiedliche Performance-Charakteristiken
+optimiert werden kann.
+
+@item
+Alle MySQL-Tabellentypen (ausser @strong{InnoDB}) sind als Dateien
+implementiert (eine Tabelle pro Datei), wodurch Datensicherungen,
+Verschieben, Löschen und sogar Symlinks auf Datenbanken und Tabellen
+wirklich einfach werden, selbst wenn der Server herunter gefahren ist.
+
+@item
+Werkzeuge, um @strong{MyISAM}-Tabellen (der meistbenutzte MySQL-Tabellentyp) zu
+reparieren und zu optimieren. Ein Reparaturwerkzeug wird nur dann benötigt,
+wenn eine Datendatei physikalisch beschädigt wurde, was üblicherweise bei
+Hardwareproblemen der Fall ist. Das Werkzeug kann meist den größten Teil der
+Daten retten.
+
+@item
+Auf eine höhere Version von MySQL aktualisieren (Upgrade) geht problemlos.
+Wenn Sie MySQL aktualisieren, brauchen Sie Ihre Daten nicht zusichern (dump)
+und zurückzusichern (restore), wie Sie es mit PostgreSQL tun müssen, wenn Sie
+dieses aktualisieren.
+@end itemize
+
+Nachteile von MySQL im Vergleich zu PostgreSQL:
+
+@itemize @bullet
+@item
+Die Transaktionsunterstützung in MySQL ist noch nicht so gut getestet wie
+das System von PostgreSQL.
+
+@item
+
+Weil MySQL Threads benutzt, die auf vielen Betriebssystemen noch nicht ganz
+tadellos funktionieren, muss man entweder die Binärdateien von
+@uref{http://www.mysql.com/downloads} benutzen oder genau unsere
+Anweisungen auf @uref{http://www.mysql.com/doc/I/n/installation_source.html}
+befolgen, um eine optimale Binärdatei zu erhalten, die in jedem Fall
+funktioniert.
+
+@item
+Tabellensperren (Locks), die von den nicht transaktionalen
+@code{MyISAM}-Tabellen benutzt werden, sind in vielen Fällen schneller als
+Seiten-Sperren (Page Locks), Zeilen-Sperren (Row Locks) oder Versionierung
+(Versioning). Der Nachteil liegt jedoch darin, dass, wenn man nicht
+berücksichtigt, wie Tabellensperren funktioniert, eine einzige lang
+laufende Anfrage eine Tabelle lange Zeit für Updates blockieren kann. Das
+kann gewöhnlich durch entsprechenden Entwurf der Applikation vermieden
+werden. Falls nicht, kann man immer noch die Tabelle, die das Problem
+verursacht, zu einem der transaktionalen Tabellentypen umändern.
+@xref{Table locking}.
+
+@item
+Mit UDF (User Defined Functions, Benutzerdefinierten Funktionen) kann man
+MySQL sowohl hinsichtlich SQL-Funktionen als auch Aggregaten erweitern,
+aber das ist noch nicht so einfach und flexibel wie in PostgreSQL.
+@xref{MySQL internals}.
+
+@item
+Updates, die über mehrere Tabellen laufen, sind in MySQL schwieriger
+durchzuführen. Das wird jedoch in MySQL 4.0 mit dem
+Multi-Table-@code{UPDATE} behoben sein und in MySQL 4.1 mit den Subselects.
+In MySQL 4.0 kann man Multi-Table-Deletes nutzen, um zeitgleich in mehreren
+Tabellen zu löschen. @xref{DELETE}.
+@end itemize
+
+PostgreSQL hat momentan folgende Vorteile gegenüber MySQL:
+
+Weil wir die Pläne (Roadmap) von MySQL kennen, haben wir in der folgenden
+Tabelle die Versionsnummern der jeweiligen MySQL-Version untergebracht, die
+das entsprechende Feature unterstützen wird. Leider konnten wir das nicht
+für frühere Vergleiche machen, denn wir kennen nicht kennen nicht die Pläne
+(Roadmap) von PostgreSQL.
+
+@multitable @columnfractions .70 .30
+@item @strong{Feature} @tab @strong{MySQL version}
+@item Subselects @tab 4.1
+@item Fremdschlüssel @tab 4.0 und 4.1
+@item Sichten (Views) @tab 4.2
+@item Gespeicherte Prozeduren @tab 4.1
+@item Erweiterbares Typ-System @tab Nicht geplant
+@item Unions @tab 4.0
+@item Full Join @tab 4.0 oder 4.1
+@item Trigger @tab 4.1
+@item Constrainst @tab 4.1
+@item Cursor @tab 4.1 oder 4.2
+@item Erweiterbare Indextypen wie R-Trees @tab R-trees sind geplant für 4.2
+@item Vererbte (Inherited) Tabellen @tab Nicht geplant
+@end multitable
+
+Andere Gründe, PostgreSQL zu benutzen:
+
+@itemize @bullet
+@item
+Im Standardgebrauch ist PostgreSQL in einigen Fällen näher an ANSI-SQL
+angelehnt.
+
+@item
+Man kann PostgreSQL beschleunigen, indem man Dinge als gespeicherte
+Prozeduren kodiert.
+
+@item
+PostgreSQL hat ein größeres Entwicklerteam, das Code zum Server
+beisteuert.
+@end itemize
+
+Nachteile von PostgreSQL im Vergleich zu MySQL:
+
+@itemize @bullet
+@item
+@code{VACUUM()} macht es problematisch, PostgreSQL in 24/7-Umgebungen
+einzusetzen.
+
+@item
+Nur Transaktionstabellen.
+
+@item
+Viel langsamere @code{INSERT}, @code{DELETE} und @code{UPDATE} Anweisungen.
+@end itemize
+
+Eine vollständige Aufstellung der Nachteile finden Sie in der ersten
+Tabelle dieses Abschnitts.
+
+
+
+@node MySQL-PostgreSQL benchmarks, , MySQL-PostgreSQL features, Compare PostgreSQL
+@c German node MySQL-PostgreSQL-Benchmarks
+@subsubsection Benchmark-Vergleiche von MySQL und PostgreSQL
+
+@cindex PostgreSQL im Vergleich mit MySQL, Benchmarks
+
+Der einzige Open-Source-Benchmark-Test, den wir kennen, der benutzt werden
+kann, um MySQL und PostgreSQL (und andere Datenbanken) miteinander zu
+vergleichen, ist unser eigener. Man findet ihn auf
+@uref{http://www.mysql.com/information/benchmarks.html}.
+
+Wir haben mehrfach bei den PostgreSQL-Entwicklern und bei einigen
+PostgreSQL-Benutzer nachgefragt, ob sie bereit wären, uns zu helfen, diesen
+Benchmark-Test zu erweitern, um ihn zu dem definitiven Benchmark-Test für
+Datenbanken zu machen, haben aber leider keinerlei Rückmeldung erhalten.
+
+Wir, die MySQL-Entwickler, haben deshalb viele Stunden damit verbracht,
+für den Benchmark-Test maximale Performance aus PostgreSQL heraus zu
+bekommen, aber da wir mit PostgreSQL nicht sehr weitgehend vertraut sind,
+sind wir sicher, dass wir einige Dinge versäumt haben. Auf der
+Benchmark-Seite haben wir genau dokumentiert, wie wir den Benchmark-Test
+durchgeführt haben, deshalb sollte es für jeden einfach sein, ihn zu
+wiederholen und unsere Ergebnisse zu bestätigen.
+
+Die Benchmarks werden üblicherweise mit und ohne die @code{--fast}-Option
+durchgeführt. Wenn wir sie mit @code{--fast} durchführen, versuchen wir,
+jeden Trick zu nutzen, den der Server benutzt, um den Code so schnell wie
+möglich auszuführen. Die Idee dahinter ist, dass der Server zeigen sollte,
+wie er mit Vorgabeeinstellungen läuft und @code{--fast} sollte zeigen, wie
+der Server läuft, wenn der Applikationsentwickler Erweiterungen im Server
+nutzt, um seine Applikation schneller laufen zu lassen.
+
+Wenn wir PostgreSQL mit der @code{--fast}-Option laufen lassen, machen wir
+ein @code{VACUUM()} nach jedem größeren Tabellen-@code{UPDATE} und
+@code{DROP TABLE}, um die Datenbank in beste Verfassung für die folgenden
+@code{SELECT}s zu bringen. Die Zeit für @code{VACUUM()} wird separat
+gemessen.
+
+PostgreSQL 7.1.1 konnten wir jedoch nicht mit der Option @code{--fast}
+laufen lassen, weil der Postmaster (der PostgreSQL Daemon) während eines
+@code{INSERT}-Tests starb und die Datenbank so beschädigt war, dass es
+unmöglich war, den Postmaster neu zu starten. Nachdem dies zweimal
+geschehen war, entschieden wir uns, den Test mit @code{--fast} bis zum
+nächsten PostgreSQL-Release zu verschieben. Die Details zur Maschine, die
+wir für den Benchmark benutzten, stehen auf der Benchmark-Seite.
+
+Bevor wir uns den anderen Benchmarks, die wir kennen, zuwenden, möchten wir
+ein paar Hintergrundinformationen zu Benchmarks geben:
+
+Es ist sehr einfach, einen Test zu schreiben, der zeigt, dass JEDE
+BELIEBIGE Datenbank die beste der Welt ist, indem man den Test einfach auf
+etwas beschränkt, was diese Datenbank sehr gut kann und nichts anderes
+testet, was die Datenbank nicht gut kann. Wenn man dann noch das Ergebnis
+mittels einer einzigen Zahl veröffentlicht, macht das die Dinge sogar noch
+einfacher.
+
+Das wäre, als ob wir die Geschwindigkeit von MySQL gegenüber PostgreSQL
+anhand der Messzeit-Zusammenfassung der MySQL-Benchmarks auf unserer
+Webseite vergleichen würden. Auf dieser Basis wäre MySQL mehr als 40 Mal
+schneller als PostgreSQL, was natürlich nicht stimmt. Wir könnten die Sache
+sogar noch verschlimmern, indem wir nur etwas testen, worin PostgreSQL die
+schlechtesten Leistungsdaten bringt und geltend machen, dass MySQL mehr als
+2000 Mal schneller ist als PostgreSQL.
+
+Tatsache ist, dass MySQL eine Menge Optimierungen vornimmt, die PostgreSQL
+nicht vornimmt. Das ist natürlich auch umgekehrt so. Ein SQL-Optimierer ist
+eine sehr komplexe Sache, und ein Unternehmen könnte Jahre damit zubringen,
+nur den Optimierer schneller und schneller zu machen.
+
+Wenn Sie sich die Ergebnisse der Benchmarks ansehen, sollten Sie nach
+Dingen Ausschau halten, die Sie in Ihrer Applikation durchführen, und dann
+nur diese Ergebnisse benutzen, um zu entscheiden, welche Datenbank wohl am
+besten für Ihre Applikation geeignet ist. Die Benchmark-Ergebnisse zeigen
+ausserdem auf, worin eine bestimmte Datenbank nicht gut ist, was Ihnen eine
+Ahnung davon geben sollte, welche Dinge Sie am besten vermeiden und was Sie
+auf andere Weise machen sollten.
+
+Wir kennen zwei Benchmark-Tests, die behaupten, dass PostgreSQL bessere
+Leistungsdaten bringt als MySQL. Beide waren Mehrbenutzer-Tests, ein Test,
+den zu schreiben wir bei MySQL AB nie die Zeit hatten, hauptsächlich, weil
+es eine wirklich große Aufgabe ist, wenn man will, dass der Test fair zu
+allen Datenbanken ist.
+
+Einer der Tests ist derjenige, für den Great Bridge bezahlt hat, und über
+den Sie hier lesen können:
+@uref{http://www.greatbridge.com/about/press.php?content_id=4}.
+
+Es ist wahrscheinlich der schlechteste Benchmark-Test, den wir jemals
+gesehen haben. Er war nicht nur so eingestellt, dass er das testete, was
+PostgreSQL absolut am besten kann, er war auch völlig unfair zu jeder
+anderen Datenbank, die in diesen Test einbezogen wurde.
+
+@strong{ACHTUNG}: Wir wissen, dass niemand der hauptsächlichen
+PostgreSQL-Entwickler die Art mochte, wie Great Bridge den Test
+durchgeführt hat, daher geben wir ihnen keinerlei Schuld dafür.
+
+Dieser Benchmark wurde in einer Menge Postings und Newsgroups verurteilt,
+daher beschränken wir uns hier darauf, kurz einige Dinge zu wiederholen,
+die dabei nicht stimmten.
+
+@itemize @bullet
+@item
+Die Tests wurden mit einem teuren, kommerziellen Werkzeug durchgeführt, was es
+für ein Open-Source-Unternehmen wie uns unmöglich macht, den Benchmark zu
+verifizieren, selbst einfach nur zu überprüfen, wie der Benchmark
+eigentlich durchgeführt wurde. Das Werkzeug ist nicht einmal ein echtes
+Benchmark-Werkzeug, sondern vielmehr ein Applikations-/Setup-Test-Werkzeug. Darauf
+als ``Standard''-Benchmark-Werkzeug Bezug zu nehmen heißt, es mit der Wahrheit
+nicht so genau zu nehmen.
+
+@item
+Great Bridge hat zugegeben, dass sie die PostgreSQL-Datenbank optimiert
+haben (mit @code{VACUUM()} vor dem Test) und dass sie das Starten vor dem
+Test getuned haben, etwas, das sie für keine der anderen getesteten
+Datenbanken gemacht haben. Dazu heißt es: ``Dieser Prozess optimiert
+Indexe und gibt etwas Festplattenspeicher frei. Die optimierten Indexe
+steigern die Performance um etliches.'' Unsere Benchmarks zeigen deutlich,
+dass der Unterschied bei einer großen Menge von Selects auf eine Datenbank
+mit und ohne @code{VACUUM()} leicht Faktor zehn betragen kann.
+
+@item
+Die Testergebnisse waren ebenfalls merkwürdig. Die AS3AP-Test-Dokumentation
+erwähnt, dass der Test ``Auswahlen, einfache Verknüpfungen, Projektionen,
+Aggregierungen, 1-Tupel-Updates und Massen-Updates'' durchführt.
+
+PostgreSQL ist gut bei der Durchführung von @code{SELECT}s und @code{JOIN}s
+(speziell nach einem @code{VACUUM()}), performt aber nicht so gut bei
+@code{INSERT}s oder @code{UPDATE}s. Die Benchmarks scheinen anzuzeigen,
+dass nur @code{SELECT}s durchgeführt wurden (oder sehr wenige Updates). Das
+würde die guten Ergebnisse für PostgreSQL in diesem Test erklären. Etwas
+weiter unten wird erläutert, wie es zu den schlechten Ergebnissen für MySQL
+kam.
+
+@item
+Sie ließen den so genannten Benchmark von einer Windows-Maschine zu einer
+Linux-Maschine über ODBC laufen, was ein normaler Datenbankbenutzer nie
+machen würde, wenn er eine unter hoher Last laufende
+Mehrbenutzer-Applikation laufen lassen würde. Dadurch wurde eher der
+ODBC-Treiber und das benutzte Windows-Protokoll zwischen den Clients
+getestet als die Datenbank selbst.
+
+@item
+Als Sie die Datenbank mit Oracle und MS-SQL betrieben (Great Bridge hat
+indirekt angedeutet, dass das die Datenbanken waren, die im Test benutzt
+wurden), benutzten sie nicht das native Protokoll, sondern statt dessen
+ODBC. Jeder, der jemals Oracle benutzt hat, weiß, dass alle echten
+Applikationen die native Schnittstelle anstatt ODBC benutzen. Einen Test
+mit ODBC fahren und erklären, dass das irgend etwas mit Situationen des
+echten Lebens zu tun hat, kann kaum als fair erachtet werden. Sie hätten
+zwei Tests fahren sollen: einen mit und einen ohne ODBC, um die korrekten
+Fakten zu ermitteln (natürlich, nachdem sie Experten geholt hätten, die
+alle getesteten Datenbanken optimal eingestellt hätten).
+
+@item
+Sie verweisen auf die TPC-C-Tests, erwähnen aber an keiner Stelle, dass der
+Test, den sie fuhren, kein echter TPC-C-Test war und dass es ihnen nicht
+einmal erlaubt ist, das einen TPC-C-Test zu nennen. Ein TPC-C-Test darf nur
+nach den Regeln durchgeführt werden, die vom TPC-Rat (TPC Council)
+festgelegt wurden (@uref{http://www.tpc.org}). Great Bridge hat das nicht
+getan. Damit haben sie sowohl das Markenzeichen TPC verletzt als auch ihre
+eigenen Benchmarks in Misskredit gebracht. Die Regeln, die vom TPC-Rat
+aufgestellt wurden, sind sehr streng, um sicherzustellen, dass niemand
+falsche Ergebnisse produziert oder nicht beweisbare Erklärungen abgibt.
+Offensichtlich hat das Great Bridge nicht interessiert.
+
+@item
+Nach dem ersten Test haben wir Kontakt mit Great Bridge aufgenommen und
+ihnen gegenüber einige der offensichtlichen Fehler erwähnt, die sie bei
+MySQL gemacht haben:
+
+@itemize @minus
+@item
+Sie haben MySQL mit einer Debug-Version unseres ODBC-Treibers laufen
+lassen.
+
+@item
+Sie haben MySQL auf einem Linux-System laufen lassen, das nicht für Threads
+optimiert war.
+
+@item
+Sie haben eine alte MySQL-Version zu einem Zeitpunkt benutzt, als eine
+empfohlene neuere bereits verfügbar war.
+
+@item
+Sie haben MySQL nicht mit den richtigen Optionen für hohe Last und
+Mehrbenutzerbetrieb gestartet (die vorgabemäßige Installation von MySQL
+ist auf minimalen Ressourcenverbrauch eingestellt).
+@end itemize
+
+Great Bridge hat einen neuen Test gefahren, wobei zwar unsere optimierten
+ODBC-Treiber und bessere Startoptionen für MySQL benutzt wurden, weigerte
+sich aber, entweder unsere aktualisierte glibc-Bibliothek oder unsere
+Standard-Binärversion (von mehr als 80% unserer Benutzer genutzt) zu
+verwenden, sondern benutzte statt dessen eine statisch gelinkte feste
+glibc-Bibliothek.
+
+Nach allem, was wir wissen, hat Great Bridge nichts getan, um
+sicherzustellen, dass die anderen Datenbanken korrekt konfiguriert wurden,
+um in ihrer Testumgebung gut zu laufen. Wir sind jedoch sicher, dass sie
+weder Oracle noch Microsoft kontaktiert haben, um sie um Rat in dieser
+Angelegenheit zu bitten ;)
+
+@item
+Der Benchmark wurde von Great Bridge bezahlt und sie beschlossen, nur
+teilweise, ausgewählte Ergebnisse zu veröffentlichen (statt alles publik zu
+machen).
+@end itemize
+
+Tim Perdue, seit langer Zeit PostgreSQL-Fan und ein widerwilliger
+MySQL-Benutzer, hat einen Vergleich auf
+@uref{http://www.phpbuilder.com/columns/tim20001112.php3,phpbuilder}
+veröffentlicht.
+
+Als wir von diesem Vergleich erfuhren, telefonierten wir mit Tim Perdue zu
+diesem Thema, weil es eine Menge merkwürdiger Dinge in seinen Ergebnissen
+gab. Er behauptete zum Beispiel, dass MySQL bei seinem Test ein Problem mit
+fünf Benutzern hatte, während wir wissen, dass es Benutzer mit ähnlichen
+Maschinen wie seine gibt, die MySQL mit 2000 simultanen Verbindungen
+betreiben, die 400 Anfragen pro Sekunde abarbeiten. (In diesem Fall war die
+Beschränkung durch die Web-Bandbreite gegeben, nicht durch die Datenbank.)
+
+Es schien, als hätte er einen Linux-Kernel benutzt, der entweder Probleme
+mit vielen Threads hatte, wie ein Kernel vor Version 2.4, der ein Problem
+mit vielen Threads auf Mehrprozessor-Maschinen hat. Wir haben in diesem
+Handbuch dokumentiert, wie man das behebt, und Tim sollte sich dieses
+Problems bewusst sein.
+
+Das andere mögliche Problem könnte eine alte glibc-Bibliothek gewesen sein,
+und dass Tim keine MySQL-Binärdistribution von unserer Site benutzte, die
+mit einer korrigierten glibc-Bibliothek gelinkt ist, sondern statt dessen
+eine eigene Version kompiliert hat. Bei jedem der genannten Fälle würden
+die Symptome genau die sein, die Tim gemessen hat.
+
+Wir haben Tim gebeten, uns Zugang zu seinen Daten zu geben, damit wir den
+Benchmark-Test wiederholen könnten, sowie die MySQL-Version auf seiner
+Maschine zu prüfen, um herauszufinden, was falsch lief, und er hat
+versprochen, uns entsprechende Mitteilung zu geben. Das hat er bis heute
+nicht gemacht.
+
+Aus diesem Grund können wir auch diesem Benchmark in keiner Weise vertrauen
+:(
+
+Im Zeitverlauf haben sich die Dinge auch geändert und die genannten
+Benchmarks sind nicht mehr so relevant. MySQL hat mittlerweile eine Reihe
+unterschiedlicher Tabellen-Handler mit unterschiedlichen Verhältnissen
+zwischen Geschwindigkeit und Anzahl gleichzeitiger Zugriffe
+(Speed/Concurrency Tradeoffs). @xref{Table types}. Es wäre interessant zu
+sehen, wie die obigen Tests mit den verschiedenen transaktionalen Tabellen
+von MySQL laufen würden. PostgreSQL hat natürlich auch neue Features
+erhalten, seit die Tests durchgeführt wurden. Weil die genannten Tests
+nicht öffentlich erhältlich sind, gibt es keine Möglichkeit für uns
+herauszufinden, wie die Datenbank heute mit denselben Tests laufen würde.
+
+
+Fazit:
+
+Der einzige Benchmark, der heutzutage existiert, den jeder herunter laden
+und laufen lassen kann, um MySQL und PostgreSQL zu vergleichen, ist der
+MySQL-Benchmark-Test. Wir hier bei MySQL sind der Überzeugung, dass
+Open-Source-Datenbanken mit Open-Source-Werkzeuge getestet werden sollten! Das
+ist die einzige Möglichkeit, um sicherzustellen, dass niemand Tests fährt,
+die nicht reproduzierbar sind, und diese dazu benutzt, um zu behaupten,
+dass eine Datenbank besser sei als die eine andere. Ohne die Fakten zu
+kennen ist es unmöglich, auf die Behauptungen des Testers einzugehen.
+
+Eine Sache, die wir merkwürdig finden, ist, dass jeder Test, den wir zu
+PostgreSQL gesehen haben - und wo es unmöglich ist, diesen zu wiederholen
+-, behauptet, dass PostgreSQL in den meisten Hinsichten besser sei, während
+unsere Tests, die jeder reproduzieren kann, eindeutig das Gegenteil
+beweisen. Damit wollen wir nicht sagen, dass PostgreSQL nicht vieles sehr
+gut kann (das kann es!) oder dass es nicht unter bestimmten Umständen
+schneller ist als MySQL. Wir würden nur gern einen fairen Test sehen, der
+zeigt, worin PostgreSQL sehr gut ist, damit wir einen freundlichen
+Wettbewerb anzetteln können!
+
+Mehr Informationen über unsere Benchmark-Suite finden Sie unter @xref{MySQL Benchmarks}.
+
+Wir arbeiten an einer noch besseren Benchmark-Suite, die Mehrbenutzer-Tests
+beinhaltet sowie eine bessere Dokumentation dessen, was die einzelnen Tests
+genau tun und wie man weitere Tests zur Suite hinzufügt.
+
+@node Installing, Tutorial, Deutsch, Top
+@c German node Installation
+@chapter Installation von MySQL
+
+@cindex Installation, Überblick
+
+
+Dieses Kapitel beschreibt, woher man MySQL bezieht und wie man MySQL
+installiert:
+
+@itemize @bullet
+@item
+Eine Liste der Site, von denen Sie MySQL beziehen können, finden Sie unter
+@ref{Getting MySQL, , Wie man MySQL erhält}.
+
+@item
+@c German FIX unsplit @ref
+Um festzustellen, welche Plattformen unterstützt werden, siehe
+@ref{Which OS}. Beachten Sie bitte, dass nicht alle
+unterstützten Systeme gleich gut
+sind, um MySQL laufen zu lassen. Auf einigen läuft es sehr viel robuster
+und effizienter als auf anderen - siehe @ref{Which OS} für
+Details.
+
+@item
+Mehrere Versionen von MySQL sind sowohl als Binär- als auch als
+Quellcode-Distributionen erhältlich. Wir stellen auch öffentlichen Zugriff
+auf unseren aktuellen Quellcode-Baum für diejenigen zur Verfügung, die die
+aktuellsten Entwicklungen sehen und uns helfen wollen, neuen Code zu
+testen. Um festzustellen, welche Version und welche Art von Distribution Sie
+benutzen sollten, siehe @ref{Which version}. Im Zweifelsfall benutzen Sie
+die Binärdistribution.
+
+@item
+Installationsanleitungen für Binär- und Quelldistributionen sind
+beschrieben in @ref{MySQL binaries} und @ref{Installing source}. Jede
+Anleitung enthält einen Abschnitt über System-spezifische Probleme, denen
+Sie begegnen können.
+
+@item
+Prozeduren, die nach der Installation durchgeführt werden sollen / müssen,
+finden Sie unter @ref{Post-installation}. Diese Prozeduren gelten, egal ob
+Sie MySQL von einer Binär- oder einer Quellcode-Distribution installieren.
+@end itemize
+
+
+@menu
+* Quick Standard Installation::
+* General Installation Issues::
+* Installing source::
+* Post-installation::
+* Upgrade::
+* Operating System Specific Notes::
+* Perl support::
+@end menu
+
+@node Quick Standard Installation, General Installation Issues, Installing, Installing
+@c German node Schnelle Standard-Installation
+@section Schnelle Standard-Installation von MySQL
+
+@c This node name ist special
+
+
+@menu
+* Linux-RPM::
+* Windows installation::
+@end menu
+
+@node Linux-RPM, Windows installation, Quick Standard Installation, Quick Standard Installation
+@c German node Linux-RPM
+@subsection MySQL auf Linux installieren
+
+@cindex RPM-Datei
+@cindex RedHat Package Manager
+
+Die empfohlene Vorgehensweise für die Installation von MySQL auf Linux ist
+die Benutzung einer RPM-Datei. Die MySQL-RPMs werden aktuell auf einer
+RedHat-Version 6.2 gebaut, sollten aber auch auf anderen Linux-Versionen
+funktionieren, die @code{rpm} unterstützen und @code{glibc} benutzen.
+
+Wenn Sie Probleme mit einer RPM-Datei haben, wenn Sie beispielsweise den
+Fehler ``@code{Sorry, the host 'xxxx' could not be looked up}'' erhalten,
+sehen Sie bitte unter @ref{Linux-RPM} nach.
+
+Die RPM-Dateien, die Sie benutzen sollten, sind:
+
+@itemize @bullet
+@item @code{MySQL-VERSION.i386.rpm}
+
+Der MySQL-Server. Sie brauchen diese, es sei denn, Sie wollen sich
+lediglich mit einem MySQL-Server verbinden, der auf einer anderen Maschine
+läuft.
+
+@item @code{MySQL-client-VERSION.i386.rpm}
+
+Die Standard-MySQL-Client-Programme. Dieses Paket sollten Sie wohl immer
+installieren.
+
+@item @code{MySQL-bench-VERSION.i386.rpm}
+
+Tests und Benchmarks. Erfordert Perl und msql-mysql-modules RPMs.
+
+@item @code{MySQL-devel-VERSION.i386.rpm}
+
+Bibliotheken und Include-Dateien, die benötigt werden, wenn Sie andere
+MySQL-Clients kompilieren wollen, beispielsweise Perl-Module.
+
+@item @code{MySQL-VERSION.src.rpm}
+
+Dieses Paket enthält den Quelltext für alle obigen Pakete. Es kann auch
+dazu benutzt werden, um RPMs für andere Architekturen zu bauen (zum
+Beispiel für Alpha oder SPARC).
+@end itemize
+
+Um alle Dateien in einem RPM-Paket zu sehen, geben Sie folgendes ein:
+@example
+shell> rpm -qpl MySQL-VERSION.i386.rpm
+@end example
+
+Um eine minimale Standard-Installation durchzuführen, geben Sie folgendes
+ein:
+
+@example
+shell> rpm -i MySQL-VERSION.i386.rpm MySQL-client-VERSION.i386.rpm
+@end example
+
+Um nur das Client-Paket zu installieren, geben Sie folgendes ein:
+
+@example
+shell> rpm -i MySQL-client-VERSION.i386.rpm
+@end example
+
+Das RPM legt Dateien in @file{/var/lib/mysql} ab. Ausserdem erzeugt das RPM
+die entsprechenden Einträge in @file{/etc/rc.d/}, um den Server beim Booten
+automatisch zu starten. (Falls Sie bereits vorher eine Installation
+durchgeführt haben, bedeutet das, dass Sie eine Kopie Ihrer vorher
+installierten MySQL-Startdateien machen sollten, falls Sie darin Änderungen
+vorgenommen haben, damit Sie diese Änderungen nicht verlieren.)
+
+Nach der Installation der RPM-Datei(en) sollte der @code{mysqld}-Daemon
+laufen und Sie sollten jetzt in der Lage sein, mit der Benutzung von MySQL
+zu beginnen. @xref{Post-installation}.
+
+Wenn etwas schief geht, finden Sie weitere Informationen im Kapitel über
+die Binär-Installationen. @xref{MySQL binaries}.
+
+@node Windows installation, , Linux-RPM, Quick Standard Installation
+@c German node Windows-Installation
+@subsection Installation von MySQL unter Windows
+
+Der MySQL-Server für Windows ist in zwei Distributionstypen erhältlich:
+@enumerate
+@item
+Die Binärdistribution enthält ein Setup-Programm, das alles Benötigte
+installiert, so dass Sie den Server sofort starten können.
+@item
+Die Quelldistribution enthält den gesamten Code und
+Unterstützungsdateien, um die ausführbaren Dateien unter Benutzung des
+VC++-6.0-Kompilers zu bauen.
+@xref{Windows source build}.
+@end enumerate
+
+Im Allgemeinen sollten Sie die Binärdistribution benutzen.
+
+Sie benötigen folgendes:
+@itemize @bullet
+@item
+Ein Windows-32-Bit-Betriebssystem der Familien Windows 9x, ME, NT oder
+Windows 2000. Die NT-Familie gestattet, den MySQL-Server als
+Systemdienst laufen zu lassen. @xref{NT start}.
+
+Wenn Sie Tabellen benutzen, die größer als 4 GB sind, sollten Sie MySQL
+auf NTFS oder einem neueren Dateisystem installieren. Vergessen Sie bei
+der Erzeugung der Tabellen nicht, @code{MAX_ROWS} und
+@code{AVG_ROW_LENGTH} zu benutzen. @xref{CREATE TABLE}.
+@item
+TCP/IP-Protokollunterstützung.
+@item
+Die MySQL-Binär- oder Quelldistribution für Windows kann von
+@uref{http://www.mysql.com/downloads/} herunter geladen werden.
+
+Hinweis: Die Distributionsdateien werden in einem komprimierten Format
+zur Verfügung gestellt. Wir empfehlen die Benutzung eines FTP-Clients,
+der in der Lage ist, abgebrochene FTP-Downloads wieder aufzunehmen
+(resume).
+@item
+Ein @code{ZIP}-Programm, um die Distributionsdatei zu entpacken.
+@item
+Genug Platz auf der Festplatte, um die Datenbanken entsprechend Ihren
+Anforderungen zu entpacken, zu installieren und zu erzeugen.
+@item
+Wenn Sie planen, sich über @code{ODBC} mit dem MySQL-Server zu
+verbinden, benötigen Sie zusätzlich den @code{MyODBC}-Treiber.
+@xref{ODBC}.
+@end itemize
+
+
+
+@menu
+* Windows binary installation::
+@end menu
+
+@node Windows binary installation, , Windows installation, Windows installation
+@c German node Windows-Binärinstallation
+@subsubsection Binärdateien installieren
+
+@enumerate
+@item
+Wenn Sie auf einem NT- oder Windows-2000-Server arbeiten, melden Sie
+sich als Benutzer mit Administrationsrechten an.
+@item
+Wenn Sie ein Upgrade einer früheren MySQL-Installation durchführen,
+müssen Sie den Server anhalten. Wenn Sie den Server als Systemdienst
+laufen lassen, geben Sie ein:
+
+@example
+C:\> NET STOP MySQL
+@end example
+
+Ansonsten geben Sie folgendes ein:
+
+@example
+C:\mysql\bin> mysqladmin -u root shutdown
+@end example
+
+@item
+Auf NT-/Windows-2000-Maschinen müssen Sie auch den Systemdienst
+entfernen, wenn Sie die ausführbare Datei des Servers (z. B. -max or -nt) austauschen wollen:
+
+@example
+C:\mysql\bin> mysqld-max-nt --remove
+@end example
+
+@item
+Entpacken Sie die Distributionsdatei in ein temporäres Verzeichnis.
+@item
+Starten Sie @file{setup.exe}, um den Installationsprozess zu beginnen.
+Wenn Sie in ein anderes Verzeichnis als das vorgabemäßige
+(@file{c:\mysql}) installieren wollen, legen Sie mit der Schaltfläche
+@code{Durchsuchen} das gewünschte Verzeichnis fest.
+@item
+Beenden Sie den Installationsprozess.
+@end enumerate
+
+
+Seit MySQL 3.23.38 enthält die Windows-Distribution sowohl die normalen als
+auch die @strong{MySQL-Max}-Binärdateien. Der wichtigste Vorteil der
+Benutzung der normalen @code{mysqld.exe}-Binärdatei liegt darin, dass sie
+etwas schneller ist und weniger Ressourcen belegt.
+
+Hier ist eine Liste der unterschiedlichen MySQL-Server, die Sie benutzen
+können:
+@multitable @columnfractions .25 .75
+@item @code{mysqld} @tab Kompiliert mit komplettem Debugging und automatischer Überprüfung der Speicherzuordnung (memory allocation), symbolischen Links, InnoDB- und BDB-Tabellen.
+@item @code{mysqld-opt} @tab Optimierte Binärdistribution ohne Unterstützung von Transaktionstabellen.
+@item @code{mysqld-nt} @tab Optimierte Binärdatei für NT mit Unterstützung von Named Pipes. Man kann diese Version auf Windows 98 laufen lassen, aber in diesem Fall werden keine Named Pipes angelegt und man muss TCP/IP installiert haben.
+@item @code{mysqld-max} @tab Optimierte Binärdistribution mit Unterstützung symbolischer Links, InnoDB und BDB-Tabellen.
+@item @code{mysqld-max-nt} @tab Wie @code{mysqld-max}, aber mit Unterstützung von Named Pipes kompiliert.
+@end multitable
+
+Alle genannten Binärdistributionen sind für den Pentium Pro Prozessor
+optimiert, sollten aber auf jedem Intel-Prozessor >= 386 laufen.
+
+ACHTUNG: Wenn Sie InnoDB-Tabellen benutzen wollen, müssen Sie bestimmte
+Start-Optionen in Ihrer @file{my.ini}-Datei festlegen! @xref{InnoDB start}.
+
+
+@node General Installation Issues, Installing source, Quick Standard Installation, Installing
+@c German node Allgemeine Installationsthemen
+@section Allgemeine Installationsthemen
+
+@c @node Methods of Installation, , ,
+@c @subsection Installationsmethoden
+
+@c FIX: this needs to be written?
+
+
+
+@menu
+* Getting MySQL::
+* Which OS::
+* Which version::
+* Installation layouts::
+* Many versions::
+* MySQL binaries::
+@end menu
+
+@node Getting MySQL, Which OS, General Installation Issues, General Installation Issues
+@c German node Wie man MySQL erhält
+@subsection Wie man MySQL erhält
+
+@cindex Download
+@cindex MySQL-Version
+@cindex Version, aktuelle
+@cindex Wie man MySQL erhält
+@cindex Mirror-Sites
+@cindex URLS zum Download von MySQL
+
+Sehen Sie wegen Informationen zur aktuellen Version und für
+Download-Anweisungen auf @uref{http://www.mysql.com/, MySQL home page}
+nach.
+
+Unser Haupt-Mirror-Server für den Download ist hier:
+
+@uref{http://mirrors.sunsite.dk/mysql/}
+
+Wenn Sie Interesse haben, eine MySQL-Mirror-Site beizusteuern, können Sie
+anonymes rsync mit @code{rsync://sunsite.dk/ftp/mirrors/mysql/} machen.
+Schicken Sie bitte eine E-Mail an @email{webmaster@@mysql.com} und geben
+Sie uns Bescheid, wo Ihr Mirror liegt, damit wir ihn der unten stehenden
+Liste hinzufügen können.
+
+Wenn Sie Probleme beim Download von unserer Hauptseite aus haben, probieren
+Sie eine der unten stehenden Mirror-Sites.
+
+Geben Sie bitte @email{webmaster@@mysql.com} Bescheid, wenn Sie auf
+schlechte oder veraltete Mirror-Sites stoßen.
+
+@c START_OF_MIRROR_LISTING
+
+@c German FIX added include of mirror listing (old German text was bad Texinfo)
+
+@c Mirrors list is created by PHP script (that really needs to be documented!) from database (tfr@mysql.com)
+@include mirrors.texi
+
+@c END_OF_MIRROR_LISTING
+
+
+@node Which OS, Which version, Getting MySQL, General Installation Issues
+@c German node Welches Betriebssystem
+@subsection Betriebssysteme, die von MySQL unterstützt werden
+
+@cindex Betriebssysteme, unterstützte
+@cindex Native Thread-Unterstützung
+@cindex Thread-Unterstützung
+@cindex Prozess-Unterstützung
+@cindex Unterstützung, für Betriebssysteme
+
+Wir benutzen GNU Autoconf, daher ist es möglich, MySQL auf alle modernen
+Betriebssysteme zu portieren, auf denen Posix-Threads und ein C++-Kompiler
+funktionieren. (Um nur den Client-Code zu kompilieren, wir lediglich ein
+C++-Kompiler benötigt.) Wir benutzen und entwickeln die Software selbst
+hauptsächlich auf Sun Solaris (Versionen 2.5 - 2.7) und SuSE Linux Version
+7.x.
+
+Beachten Sie, dass die native Thread-Unterstützung für viele
+Betriebssysteme nur mit den neuesten Versionen funktioniert. Es wurde
+berichtet, dass MySQL erfolgreich auf folgenden Betriebssystemen /
+Thread-Paket-Kombinationen kompiliert wurde:
+
+@itemize @bullet
+@item
+AIX 4.x mit nativen Threads. @xref{IBM-AIX}.
+@item
+Amiga.
+@item
+BSDI 2.x mit enthaltenem MIT-pThreads-Paket. @xref{BSDI}.
+@item
+BSDI 3.0, 3.1 und 4.x mit nativen Threads. @xref{BSDI}.
+@item
+DEC Unix 4.x mit nativen Threads. @xref{Alpha-DEC-UNIX}.
+@item
+FreeBSD 2.x mit enthaltenem MIT-pThreads-Paket. @xref{FreeBSD}.
+@item
+FreeBSD 3.x und 4.x mit nativen Threads. @xref{FreeBSD}.
+@item
+HP-UX 10.20 mit enthaltenem MIT-pThreads-Paket. @xref{HP-UX 10.20}.
+@item
+HP-UX 11.x mit nativen Threads. @xref{HP-UX 11.x}.
+@item
+Linux 2.0+ mit LinuxThreads 0.7.1+ oder @code{glibc} 2.0.7+. @xref{Linux}.
+@item
+Mac OS X Server. @xref{Mac OS X}.
+@item
+NetBSD 1.3/1.4 Intel und NetBSD 1.3 Alpha (benötigt GNU make). @xref{NetBSD}.
+@item
+OpenBSD > 2.5 mit nativen Threads. OpenBSD < 2.5 mit enthaltenem
+MIT-pThreads-Paket. @xref{OpenBSD}.
+@item
+OS/2 Warp 3, FixPack 29 und OS/2 Warp 4, FixPack 4. @xref{OS/2}.
+@item
+SGI Irix 6.x mit nativen Threads. @xref{SGI-Irix}.
+@item
+Solaris 2.5 und höher mit nativen Threads auf SPARC und x86. @xref{Solaris}.
+@item
+SunOS 4.x mit enthaltenem MIT-pThreads-Paket. @xref{Solaris}.
+@item
+SCO OpenServer mit einem aktuellen Port des FSU-PThreads-Pakets. @xref{SCO}.
+@item
+SCO UnixWare 7.0.1. @xref{SCO Unixware}.
+@item
+Tru64 Unix
+@item
+Windows 95, Windows 98, NT und Windows 2000. @xref{Windows}.
+@end itemize
+
+Beachten Sie, dass nicht alle Plattformen gleichermaßen gut geeignet sind,
+um MySQL laufen zu lassen. Wie gut eine bestimmte Plattform für hohe Last
+und geschäftskritische Anwendungen geeignet ist, hängt von folgenden
+Faktoren ab:
+
+@itemize @bullet
+@item
+Allgemeine Stabilität der Thread-Bibliothek. Eine Plattform mag in anderer
+Hinsicht einen exzellenten Ruf haben, aber wenn die Thread-Bibliothek
+unstabil ist, die von MySQL aufgerufen wird, läuft MySQL nur so stabil wie
+die Thread-Bibliothek, selbst wenn alles Sonstige perfekt ist.
+
+@item
+Fähigkeit des Kernels und / oder der Thread-Bibliothek, die Vorteile von
+@strong{SMP} auf Mehrprozessor-Systemen wahrzunehmen. Mit anderen Worten:
+Wenn ein Prozess einen Thread anlegen, sollte es für diesen Thread möglich
+sein, auf anderen Prozessoren zu laufen als der Original-Prozess.
+
+@item
+Fähigkeit des Kernels und / oder der Thread-Bibliothek, viele Threads
+laufen zu lassen, die häufig einen Mutex über eine kurze, kritische Region
+anlegen / lösen können ohne exzessive Kontext-Umschaltungen. Mit anderen
+Worten: Wenn die Implementation von @code{pThread_mutex_lock()} zu sehr
+darauf bedacht ist, CPU zu erlangen, wird das MySQL gewaltig schmerzen.
+Wenn man sich dieser Tatsache nicht bewusst ist, machen zusätzliche
+Prozessoren MySQL in der Tat langsamer.
+
+@item
+Allgemeine Stabilität und Performance des Dateisystems.
+
+@item
+Fähigkeit des Dateisystems, überhaupt mit großen Dateien umgehend zu
+können, und zwar effizient, wenn Ihre Tabellen Groß sind.
+
+@item
+Unser Grad von Erfahrung, hier bei MySQL AB, mit der Plattform. Wenn wir
+eine Plattform gut kennen, setzen wir plattformspezifische Optimierungen /
+Verbesserungen (Fixes) ein, die zur Kompilierzeit aktiv werden. Darüber
+hinaus können wir Sie beraten, wie Sie Ihr System optimal für MySQL
+konfigurieren.
+
+@item
+Umfang des Testens ähnlicher Konfigurationen, das wir intern durchgeführt
+haben.
+
+@item
+Anzahl von Benutzern, die MySQL auf dieser Plattform erfolgreich mit
+ähnlichen Konfigurationen haben laufen lassen. Wenn diese Zahl Groß ist,
+ist die Wahrscheinlichkeit viel geringer, plattformspezifische
+Überraschungen zu erleben.
+@end itemize
+
+Nach den genannten Kriterien sind die besten Plattformen für MySQL bislang
+x86 mit SuSE Linux 7.1, 2.4 Kernel und ReiserFS (oder jede ähnliche
+Linux-Distribution) und Sparc mit Solaris 2.7 oder 2.8. FreeBSD kommt als
+drittes, aber wir hoffen wirklich, dass es zur Spitze aufschließt, sobald
+erst einmal die Thread-Bibliothek verbessert ist. Wir hoffen auch, dass wir
+alle anderen Plattformen, auf denen MySQL kompiliert werden kann und
+korrekt läuft, die aber nicht ganz denselben Grad an Stabilität und
+Performance aufweisen, in die Spitzenkategorie aufnehmen können. Das
+erfordert von unserer Seite aus einige Kooperationsbemühungen mit den
+Entwicklern der Betriebssystem-Bibliothek-Komponenten, von denen MySQL
+abhängt. Wenn Sie Interesse daran haben, eine dieser Komponenten zu
+verbessern und in der Lage sind, ihre Entwicklung zu beeinflussen, und
+detailliertere Informationen darüber brauchen, was MySQL benötigt, um
+besser zu laufen, schicken Sie eine E-Mail an
+@email{internals@@lists.mysql.com}.
+
+Beachten Sie bitte auch, dass der obige Vergleich nichts darüber aussagen
+will, dass ein Betriebssystem allgemein besser oder schlechter als ein
+anderes sei. Wir reden hier über die Auswahl eines bestimmten
+Betriebssystems für einen ganz bestimmten Zweck - nämlich, MySQL laufen zu
+lassen, und vergleichen die Betriebssysteme nur in dieser Hinsicht.
+Folglich wäre das Ergebnis dieses Vergleichs ein anderes, wenn wir weitere
+Belange berücksichtigen würden. In manchen Fällen liegt der Grund, warum
+ein Betriebssystem besser als ein anderes geeignet ist, schlicht darin,
+dass wir auf dieser speziellen Plattform mehr Tests und Optimierungen
+durchgeführt haben. Wir stellen hier nur unsere Beobachtungen dar, um Ihnen
+bei der Entscheidung zu helfen, auf welcher Plattform Sie MySQL benutzen
+sollten.
+
+
+@node Which version, Installation layouts, Which OS, General Installation Issues
+@c German node Welche Version
+@subsection Welche MySQL-Version Sie benutzen sollten
+
+@cindex MySQL-Binärdistribution
+@cindex MySQL-Quelldistribution
+@cindex Release-Nummer
+@cindex Version, Auswahl
+@cindex Auswahl, einer MySQL-Version
+
+Zunächst müssen Sie entscheiden, ob Sie das letzte Entwicklungs-Release
+oder das letzte stabile Release benutzen wollen:
+
+@itemize @bullet
+@item
+Normalerweise, wenn Sie MySQL zum ersten Mal benutzen, oder wenn Sie
+versuchen, MySQL auf ein System zu portieren, für das es keine
+Binärdistribution gibt, empfehlen wir, das stabile Release zu nehmen
+(aktuell Version @value{mysql_version}). Beachten Sie, dass alle
+MySQL-Releases mit den MySQL-Benchmarks und einer umfassenden Test-Suite
+getestet sind, bevor das Release heraus gegeben wird.
+
+@item
+Wenn Sie ein altes System laufen lassen und es aktualisieren möchten, aber
+nicht riskieren wollen, dass ein Update nicht reibungslos klappt, sollten
+Sie zur aktuellsten Version des Zweiges aktualisieren, den Sie benutzen
+(bei dem nur die letzte Versionsnummer neuer ist als Ihre, also z. B. von
+3.23.36 auf 3.23.44, wenn 3.23.44 die neueste Version des Zweigs ist). Wir
+haben uns innerhalb der Versions-Zweige bemüht, nur schwere Fehler zu
+beseitigen und kleine, relativ sichere Änderungen zu machen.
+@end itemize
+
+Als nächstes müssen Sie entscheiden, ob Sie eine Quelldistribution oder
+eine Binärdistribution nehmen wollen. In den meisten Fällen ist es ratsam,
+eine Binärdistribution zu nehmen, wenn eine für Ihre Plattform existiert,
+weil sich diese im Allgemeinen leichter installieren läßt als eine
+Quelldistribution.
+
+In folgenden Fällen fahren Sie mit einer Quellinstallation wahrscheinlich
+besser:
+
+@itemize @bullet
+@item
+Wenn Sie MySQL an einer ganz bestimmten Stelle installieren wollen. (Die
+Standard-Binärdistributionen sind an jeder Stelle lauffähig, aber
+vielleicht wollen Sie noch mehr Flexibilität haben.)
+
+@item
+Um unterschiedlichen Bedürfnissen von Benutzern entgegen zu kommen, stellen
+wir zwei unterschiedliche Binärversionen zur Verfügung: Eine, die mit den
+nicht transaktionalen Tabellen-Handlern kompiliert ist (eine kleine,
+schnelle Binärdatei), sowie eine, die mit den wichtigsten erweiterten
+Optionen wie transaktionssicheren Tabellen kompiliert ist. Beide Versionen
+sind aus derselben Quelldistribution kompiliert. Alle nativen
+@code{MySQL}-Clients können sich mit beiden MySQL-Versionen verbinden.
+
+Die erweiterte MySQL-Binärdistribution ist mit dem @code{-max}-Suffix
+gekennzeichnet und ist mit denselben Optionen konfiguriert wie
+@code{mysqld-max}. @xref{mysqld-max, , @code{mysqld-max}}.
+
+Wenn Sie das @code{MySQL-Max}-RPM benutzen wollen, müssen Sie zuerst das
+Standard-@code{MySQL}-RPM installieren.
+
+@item
+Wenn Sie @code{mysqld} mit einigen zusätzlichen Features konfigurieren
+wollen, die NICHT in den Standard-Binärdistributionen enthalten sind. Hier
+ist eine Liste der gebräuchlichsten Zusatzoptionen, die Sie vielleicht
+nutzen wollen:
+
+@itemize @bullet
+@item @code{--with-berkeley-db}
+@item @code{--with-innodb}
+@item @code{--with-raid}
+@item @code{--with-libwrap}
+@item @code{--with-named-z-lib (ist in einigen Binärdateien enthalten)}
+@item @code{--with-debug[=full]}
+@end itemize
+
+@item
+Die vorgabemäßige Binärdistribution wird normalerweise mit Unterstützung
+für alle Zeichensätze kompiliert und sollte auf einer Vielzahl von
+Prozessoren derselben Prozessorfamilie laufen.
+
+Wenn Sie einen schnelleren MySQL-Server erhalten wollen, können Sie ihn
+erneut kompilieren und nur die Zeichensätze benutzen, die Sie brauchen. Sie
+können auch einen besseren Kompiler (wie @code{pgcc}) oder andere
+Kompilieroptionen benutzen, die besser auf Ihren Prozessor optimiert sind.
+
+@item
+Wenn Sie einen Bug gefunden und dem MySQL-Entwicklungsteam mitgeteilt
+haben, werden Sie wahrscheinlich einen Patch erhalten, den Sie mit der
+Quelldistribution verwenden müssen, um den Bug zu beheben.
+
+@item
+Wenn Sie den C- und C++-Code lesen (und / oder ändern) wollen, aus dem
+MySQL besteht, müssten Sie eine Quelldistribution laden. Der Quellcode ist
+immer das ''letzte Handbuch''. Quelldistributionen enthalten auch mehr
+Tests und Beispiele als Binärdistributionen.
+@end itemize
+
+@cindex naming, releases of MySQL
+@cindex Releases, Benennungsschema
+
+Das MySQL Benennungsschema benutzt Release-Nummern, die aus drei Zahlen und
+einem Suffix bestehen. Ein Release-Name wie @code{mysql-3.21.17-beta} zum
+Beispiel wird wie folgt interpretiert:
+
+@itemize @bullet
+@item
+Die erste Zahl (@code{3}) beschreibt das Dateiformat. Alle
+Version-3-Releases haben dasselbe Dateiformat.
+
+@item
+Die zweite Zahl (@code{21}) ist die Release-Ebene (Level). Normalerweise
+kann man hier zwischen zweien auswählen. Einer ist der stabile Zweig des
+Releases (aktuell @code{23}), der andere ist der Entwicklungs-Zweig
+(aktuell @code{4.0}). Normalerweise sind beide stabil, aber die
+Entwicklungsversion kann Macken oder fehlende Dokumentation neuer Features
+haben oder sich auf einigen Systemen nicht kompilieren lassen.
+
+@item
+Die dritte Zahl (@code{17}) ist die Versionsnummer innerhalb der
+Release-Ebene. Diese wird für jede neue Distribution hochgezählt.
+Üblicherweise werden Sie die neueste Version der Release-Ebene einsetzen
+wollen, die Sie gewählt haben.
+
+@item
+Das Suffix (@code{beta}) zeigt den Stabilitätsgrad des Releases an.
+Mögliche Suffixe sind:
+
+@itemize @minus
+@item
+@code{alpha} zeigt an, dass das Release größere Abschnitte von neuem Code
+enthält, der noch nicht zu 100% getestet wurde. Bekannte Bugs
+(üblicherweise gibt es keine) sind im News-Abschnitt dokumentiert.
+@xref{News}. In den meisten Alpha-Releases gibt es neue Befehle und
+Erweiterungen. Bei einem Alpha-Release können durch aktive
+Weiterentwicklung größere Code-Änderungen vorkommen, aber alles wird
+getestet, bevor ein Release veröffentlicht wird. Es sollte in keinem
+MySQL-Release bekannte Bugs geben.
+
+@item
+@code{beta} bedeutet, dass jeglicher neue Code getestet wurde. Es wurden
+keine neuen Features hinzugefügt, die bei altem Code Probleme verursachen
+könnten. Es sollte keine bekannten Bugs geben. Eine Version wird von Alpha
+auf Beta gesetzt, wenn innerhalb der Alpha-Version mindestens einen Monat
+lang keine schweren Fehler mehr berichtet wurden. Wir planen für eine
+solche Version dann keine neuen Features mehr, die einen alten Befehl
+unzuverlässiger machen könnten.
+
+@item
+@code{gamma} ist eine Beta-Version, die eine ganze Weile draussen war und
+offensichtlich gut funktioniert. Nur kleinere Problembehebungen wurden
+hinzugefügt. So etwas nennen viele andere Unternehmen ein Release.
+
+@item
+Wenn eine Version kein Suffix besitzt, bedeutet das, dass diese Version
+schon eine ganze Weile auf vielen unterschiedlichen Sites eingesetzt wird,
+wobei keine Bugs ausser plattformspezifischen Bugs berichtet wurden. Für
+ein solches Release werden nur kritische Fehlerbehebungen durchgeführt. So
+etwas nennen wir ein stabiles Release.
+@end itemize
+@end itemize
+
+Alle Versionen von MySQL laufen durch unsere Standard-Tests und
+-Benchmarks, um sicherzustellen, dass man sie relativ sicher benutzen kann.
+Weil die Standard-Tests im Laufe der Zeit erweitert werden, um auf alle
+früher gefundenen Bugs zu prüfen, wird die Test-Suite immer besser.
+
+@cindex releases, testing
+@cindex Testen, von MySQL-Releases
+
+Beachten Sie, dass alle Releases mindestens wie folgt getestet wurden:
+
+@table @asis
+@item Mit der internen Test-Suite
+Diese ist Teil unseres Produktionssystems für einen Kunden. Sie besitzt
+viele Tabellen mit Hunderten Megabytes an Daten.
+
+@item Mit der MySQL-Benchmark-Suite
+Diese läßt eine Reihe gebräuchlicher Anfragen laufen. Das ist zusätzlich
+ein Test darauf, ob die letzten Optimierungen den Code tatsächlich
+schneller gemacht haben.
+@xref{MySQL Benchmarks}.
+
+@item Mit dem @code{crash-me}-Test
+Dieser Test versucht festzustellen, welche Features die Datenbank
+unterstützt und was ihre Fähigkeiten und Beschränkungen sind. @xref{MySQL Benchmarks}.
+@end table
+
+Ein weiterer Test besteht darin, dass wir die neueste MySQL-Version in
+unserer internen Entwicklungsumgebung einsetzen, mindestens auf einer
+Maschine. Wir arbeiten hierbei mit mehr als 100 Gigabytes an Daten.
+
+
+@node Installation layouts, Many versions, Which version, General Installation Issues
+@c German node Installationslayouts
+@subsection Installationslayouts
+
+@cindex Installationslayouts
+@cindex Layout der Installation
+@cindex Verzeichnisstruktur, Vorgabe
+@cindex Vorgabemäßiger Installationsort
+
+Dieser Abschnitt beschreibt das vorgabemäßige Layout der Verzeichnisse,
+die durch die Installation von Binär- und Quelldistributionen angelegt
+werden.
+
+Eine Binärdistribution wird installiert, indem sie an die
+Installationsstelle entpackt wird, die Sie auswählen (typischer Weise
+@file{/usr/local/mysql}). Die Installation erstellt folgende Verzeichnisse
+an dieser Stelle:
+
+@multitable @columnfractions .3 .7
+@item @strong{Verzeichnis} @tab @strong{Verzeichnisinhalt}
+@item @file{bin} @tab Client-Programme und der
+@code{mysqld}-Server
+@item @file{data} @tab Log-Dateien, Datenbanken
+@item @file{include} @tab Include-(Header)-Dateien
+@item @file{lib} @tab Bibliotheken
+@item @file{scripts} @tab @code{mysql_install_db}
+@item @file{share/mysql} @tab Dateien mit Fehlernachrichten
+@item @file{sql-bench} @tab Benchmarks
+@end multitable
+
+Eine Quelldistribution wird installiert, nachdem Sie sie konfiguriert und
+kompiliert haben. Vorgabemäßig werden Dateien unter @file{/usr/local}
+installiert, und zwar in den folgenden Unterverzeichnissen:
+
+@multitable @columnfractions .3 .7
+@item @strong{Verzeichnis} @tab @strong{Verzeichnisinhalt}
+@item @file{bin} @tab Client-Programme und -Skripte
+@item @file{include/mysql} @tab Include-(Header)-Dateien
+@item @file{info} @tab Dokumentation im Info-Format
+@item @file{lib/mysql} @tab Bibliotheken
+@item @file{libexec} @tab Der @code{mysqld}-Server
+@item @file{share/mysql} @tab Dateien mit Fehlernachrichten
+@item @file{sql-bench} @tab Benchmarks und @code{crash-me}-Test
+@item @file{var} @tab Datenbanken und Log-Dateien
+@end multitable
+
+Innerhalb eines Installationsverzeichnisses weicht das Layout einer
+Quellinstallation von dem einer Binärinstallation wie folgt ab:
+
+@itemize @bullet
+@item
+Der @code{mysqld}-Server wird in das @file{libexec}-Verzeichnis installiert
+und nicht in das @file{bin}-Verzeichnis.
+
+@item
+Das Daten-Verzeichnis ist @file{var} und nicht @file{data}.
+
+@item
+@code{mysql_install_db} wird in das @file{/usr/local/bin} Verzeichnis
+installiert und nicht in @file{/usr/local/mysql/Skripts}.
+
+@item
+Die Header-Datei und Bibliotheksverzeichnisse sind @file{include/mysql} und
+@file{lib/mysql} und nicht @file{include} und @file{lib}.
+@end itemize
+
+Sie können Ihre eigene Binärinstallation aus einer kompilierten
+Quelldistribution erzeugen, indem Sie das Skript
+@file{Skripts/make_binary_Distribution} ausführen.
+
+
+@node Many versions, MySQL binaries, Installation layouts, General Installation Issues
+@c German node Viele Versionen
+@subsection Wann und wie Updates veröffentlicht werden
+
+@cindex Releases, Updates
+@cindex Updates, Releases von MySQL
+
+MySQL entwickelt sich ziemlich schnell hier bei MySQL AB und wir wollen,
+dass andere MySQL-Benutzer daran teilhaben. Wir versuchen, immer dann ein
+neues Release heraus zu bringen, wenn wir sehr nützliche Features haben,
+für die offensichtlich ein Bedarf besteht.
+
+Auch versuchen wir, unseren Benutzern zu helfen, wenn Sie nach Features
+anfragen, die einfach zu implementieren sind. Wir notieren, was unsere
+lizensierten Nutzer haben wollen, und insbesondere, was unsere Benutzer mit
+erweitertem E-Mail-Support haben wollen, und versuchen ihnen, eben das zu
+bieten.
+
+Niemand muss einen neuen Release herunter laden. Im News-Abschnitt steht
+stets, ob das neue Release etwas beinhaltet, was Sie wirklich brauchen.
+@xref{News}.
+
+Wenn wir MySQL aktualisieren, fahren wir folgende Politik:
+
+@itemize @bullet
+@item
+Bei kleineren Updates wird die letzte Zahl (von rechts) in der
+Versionsnummer herauf gezählt (Minor Release). Wenn es größere neue
+Features gibt oder kleinere Inkompatibilitäten mit vorherigen Versionen,
+wird die zweite Zahl der Versionsnummer herauf gezählt (Major Release).
+Wenn sich das Dateiformat ändert, wird die erste Zahl herauf gezählt.
+
+@item
+@c Question: This is supposed to mean "stable major releases". What does it
+have to do with "small bugs" => minor releases?
+Stable tested releases are meant to appear about 1-2 times a year, but
+if small bugs are found, a release mit only bug fixes will be released.
+Als stabil getestete Releases sollten etwa ein- bis zweimal im Jahr
+erscheinen, aber wenn kleinere Fehler gefunden werden, wird nur ein Release
+mit Bug-Fixes heraus gegeben.
+
+
+@item
+Funktionierende Releases sollten etwa alle 1 bis 8 Wochen erscheinen.
+
+@item
+Binärdistributionen für einige Plattformen werden von uns für größere
+Releases (Major) heraus gegeben. Andere Leute stellen vielleicht auch
+Binärdistributionen für andere Systeme her, aber nicht so häufig.
+
+@item
+Patches stellen wir üblicherweise zur Verfügung, sobald wir kleinere Bugs
+ausfindig gemacht und behoben haben.
+
+@item
+Für nicht kritische, aber störende Bugs machen wir Patches verfügbar, wenn
+sie uns zugesandt werden. Ansonsten kombinieren wir mehrere davon in einem
+größeren Patch.
+
+@item
+Wenn durch unglückliche Umstände ein Release einen schweren Fehler enthält,
+erstellen wir sobald wie möglich ein neues Release. Das würden wir auch
+gern bei anderen Unternehmen so sehen.
+@end itemize
+
+
+@c Question: I will not translate this paragraph now. Please update this!
+The current stable release ist Version 3.23; We have already moved active
+Entwicklung to Version 4.0. Bugs will still be fixed in the stable version.
+We don't believe in a complete freeze, as this also leaves out bug fixes
+und things that ``must be done.'' ``Somewhat frozen'' means that we may
+add small things that ``almost surely will not affect anything that's
+already working.''
+
+
+@node MySQL binaries, , Many versions, General Installation Issues
+@c German node MySQL-Binärdistributionen
+@subsection MySQL-Binärdistributionen, die von MySQL AB kompiliert wurden
+
+@cindex Binärdistributionen
+
+Als Service stellen wir bei MySQL AB einen Satz von Binärdistributionen von
+MySQL zur Verfügung, die auf unserer Site kompiliert wurden oder auf Sites
+von Kunden, die uns freundlicherweise Zugang zu Ihren Maschinen gewährt
+haben.
+
+Diese Distributionen werden mit @code{Skripts/make_binary_distribution}
+erzeugt und mit folgenden Kompilern und Optionen konfiguriert:
+
+@table @asis
+@item SunOS 4.1.4 2 sun4c mit @code{gcc} 2.7.2.1
+@code{CC=gcc CXX=gcc CXXFLAGS="-O3 -felide-constructors" ./configure --prefix=/usr/local/mysql --disable-shared --with-extra-charsets=complex --enable-assembler}
+
+@item SunOS 5.5.1 (und höher) sun4u mit @code{egcs} 1.0.3a oder 2.90.27 oder gcc 2.95.2 und neuer
+@code{CC=gcc CFLAGS="-O3" CXX=gcc CXXFLAGS="-O3 -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --with-low-memory --with-extra-charsets=complex --enable-assembler}
+
+@item SunOS 5.6 i86pc mit @code{gcc} 2.8.1
+@code{CC=gcc CXX=gcc CXXFLAGS=-O3 ./configure --prefix=/usr/local/mysql --with-low-memory --with-extra-charsets=complex}
+
+@item Linux 2.0.33 i386 mit @code{pgcc} 2.90.29 (@code{egcs} 1.0.3a)
+@code{CFLAGS="-O3 -mpentium -mstack-align-double" CXX=gcc CXXFLAGS="-O3 -mpentium -mstack-align-double -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --enable-assembler --with-mysqld-ldflags=-all-static --with-extra-charsets=complex}
+
+@item Linux 2.2.x mit x686 mit @code{gcc} 2.95.2
+@code{CFLAGS="-O3 -mpentiumpro" CXX=gcc CXXFLAGS="-O3 -mpentiumpro -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --enable-assembler --with-mysqld-ldflags=-all-static --disable-shared --with-extra-charset=complex}
+
+@item SCO 3.2v5.0.4 i386 mit @code{gcc} 2.7-95q4
+@code{CC=gcc CXX=gcc CXXFLAGS=-O3 ./configure --prefix=/usr/local/mysql --with-extra-charsets=complex}
+
+@item AIX 2 4 mit @code{gcc} 2.7.2.2
+@code{CC=gcc CXX=gcc CXXFLAGS=-O3 ./configure --prefix=/usr/local/mysql --with-extra-charsets=complex}
+
+@item OSF1 V4.0 564 alpha mit @code{gcc} 2.8.1
+@code{CC=gcc CFLAGS=-O CXX=gcc CXXFLAGS=-O3 ./configure --prefix=/usr/local/mysql --with-low-memory --with-extra-charsets=complex}
+
+@item Irix 6.3 IP32 mit @code{gcc} 2.8.0
+@code{CC=gcc CXX=gcc CXXFLAGS=-O3 ./configure --prefix=/usr/local/mysql --with-extra-charsets=complex}
+
+@item BSDI BSD/OS 3.1 i386 mit @code{gcc} 2.7.2.1
+@code{CC=gcc CXX=gcc CXXFLAGS=-O ./configure --prefix=/usr/local/mysql --with-extra-charsets=complex}
+
+@item BSDI BSD/OS 2.1 i386 mit @code{gcc} 2.7.2
+@code{CC=gcc CXX=gcc CXXFLAGS=-O3 ./configure --prefix=/usr/local/mysql --with-extra-charsets=complex}
+@end table
+
+Wenn jemand optimalere Optionen für die obigen Konfigurationen hat, können
+diese jederzeit der Entwickler-Mailing-Liste unter
+@email{internals@@lists.mysql.com} mitgeteilt werden.
+
+RPM-Distributionen von MySQL-Version 3.22 wurden durch Benutzer
+beigesteuert. Ab Version 3.22 werden die RPMs von uns bei MySQL AB erzeugt.
+
+Wenn Sie eine Debug-Version von MySQL kompilieren wollen, müssen Sie den
+oben genannten Kompilierzeilen @code{--with-debug} oder
+@code{--with-debug=full} hinzufügen und jegliche
+@code{-fomit-frame-pointer}-Optionen entfernen.
+
+
+@node Installing source, Post-installation, General Installation Issues, Installing
+@c German node Installation der Quelldistribution
+@section Installation der Quelldistribution
+
+@cindex Installation, Quelldistribution
+@cindex Quelldistribution, Installation
+@cindex Installation, Überblick
+
+Bevor Sie mit der Quellinstallation fortfahren, sehen Sie nach, ob eine
+Binärdistribution für Ihre Plattform verfügbar ist, die so wie Sie wollen
+funktioniert. Wir geben uns viel Mühe, die Binärdistributionen mit den
+bestmöglichen Optionen zu bauen.
+
+Sie benötigen folgende Werkzeuge, um MySQL aus der Quelldistribution zu bauen
+und zu installieren:
+
+@itemize @bullet
+@item
+GNU @code{gunzip}, um die Distribution zu entpacken.
+
+@item
+Ein vernünftiges @code{tar}, um die Distribution zu entpacken. Von GNU
+@code{tar} ist bekannt, dass es funktioniert. Sun @code{tar} ist dafür
+bekannt, dass es Probleme verursacht.
+
+@item
+Einen funktionierenden ANSI-C++-Kompiler. @code{gcc} >= 2.95.2, @code{egcs} >= 1.0.2
+oder @code{egcs 2.91.66}, SGI C++ und SunPro C++ sind einige der Kompiler,
+von denen bekannt ist, dass sie funktionieren. @code{libg++} wird nicht
+benötigt, wenn Sie @code{gcc} benutzen. @code{gcc} 2.7.x hat einen Bug, der
+es verunmöglicht, einige perfekt der vorgeschriebenen Form entsprechende
+C++-Dateien zu kompilieren, zum Beispiel @file{sql/sql_base.cc}. Wenn Sie
+nur @code{gcc} 2.7.x zur Verfügung haben, müssen Sie Ihren @code{gcc}
+aktualisieren, um MySQL kompilieren zu können. @code{gcc} 2.8.1 ist
+ebenfalls für Probleme auf einigen Plattformen bekannt, daher sollten Sie
+auch diesen vermeiden, wenn Sie einen neueren Kompiler für diese Plattform
+zur Verfügung haben.
+
+@code{gcc} >= 2.95.2 wird für das Kompilieren von MySQL-Versionen 3.23.x
+empfohlen.
+
+@item
+Ein gutes @code{make}-Programm. GNU @code{make} wird stets empfohlen und
+ist manchmal erforderlich. Wenn Sie Probleme bekommen, empfehlen wir, es
+mit GNU @code{make} 3.75 oder neuer zu versuchen.
+@end itemize
+
+Wenn Sie eine aktuelle Version von @strong{gcc} verwenden (aktuell genug,
+um die @code{-fno-exceptions}-Option zu verstehen), ist es @strong{SEHR
+WICHTIG}, dass Sie diese Option benutzen. Ansonsten könnte es sein, dass
+Sie eine Binärdatei kompilieren, die zu zufälligen Zeitpunkten abstürzt.
+Wir empfehlen zusätzlich, dass Sie @code{-felide-contructors} und
+@code{-fno-rtti} zusammen mit @code{-fno-exceptions} benutzen. Im Zweifel
+gehen Sie wie folgt vor:
+
+@example
+
+CFLAGS="-O3" CXX=gcc CXXFLAGS="-O3 -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --enable-assembler --with-mysqld-ldflags=-all-static
+
+@end example
+
+Für die meisten Systeme werden Sie dadurch eine schnelle, stabile
+Binärinstallation erhalten.
+
+@c texi2html fails to split chapters if I use strong für all of this.
+Wenn Sie Probleme bekommen, @strong{BITTE BENUTZEN SIE IMMER
+@code{mysqlbug}} zum Fragenstellen die Liste
+@email{mysql@@lists.mysql.com}. Selbst wenn das Problem kein Bug ist,
+sammelt @code{mysqlbug} Systeminformationen, die anderen helfen werden, Ihr
+Problem zu lösen. Wenn Sie @code{mysqlbug} nicht benutzen, verringern Sie
+die Möglichkeit, eine Lösung Ihres Problems zu bekommen! @code{mysqlbug}
+finden Sie im @file{scripts}-Verzeichnis, nachdem Sie die Distribution
+entpackt haben. @xref{Bug reports}.
+
+
+
+@menu
+* Quick install::
+* Applying patches::
+* configure options::
+* Installing source tree::
+* Compilation problems::
+* MIT-pthreads::
+* Windows source build::
+@end menu
+
+@node Quick install, Applying patches, Installing source, Installing source
+@c German node Schnellinstallation
+@subsection Schnellinstallation, Überblick
+
+Die grundlegenden Befehle, die Sie ausführen müssen, um eine
+MySQL-Quelldistribution zu installieren, sind:
+
+@example
+shell> groupadd mysql
+shell> useradd -g mysql mysql
+shell> gunzip < mysql-VERSION.tar.gz | tar -xvf -
+shell> cd mysql-VERSION
+shell> ./configure --prefix=/usr/local/mysql
+shell> make
+shell> make install
+shell> scripts/mysql_install_db
+shell> chown -R root /usr/local/mysql
+shell> chown -R mysql /usr/local/mysql/var
+shell> chgrp -R mysql /usr/local/mysql
+shell> cp support-files/my-medium.cnf /etc/my.cnf
+shell> /usr/local/mysql/bin/safe_mysqld --user=mysql &
+@end example
+
+@c German FIX added @samp before {#}
+Wenn Sie Unterstützung für InnoDB-Tabellen haben wollen, sollten Sie die
+Datei @code{/etc/my.cnf} editieren und die @samp{#}-Zeichen vor den Parametern
+entfernen, der mit @code{innodb_...} beginnen. @xref{Option files}.
+@xref{InnoDB start}.
+
+Wenn Sie mit einem Quell-RPM anfangen, gehen Sie wie folgt vor:
+
+@example
+shell> rpm --rebuild MySQL-VERSION.src.rpm
+@end example
+
+Das erzeugt ein Binär-RPM, das Sie installieren können.
+
+Sie können neue Benutzer hinzufügen, indem Sie das
+@code{bin/mysql_setpermission}-Skript benutzen, falls Sie die @code{DBI}-
+und @code{Msql-Mysql-modules}-Perl-Module installieren.
+
+Eine detailliertere Beschreibung folgt.
+
+Um eine Quelldistribution zu installieren, führen Sie die unten stehenden
+Schritte aus und gehen dann weiter zu @ref{Post-installation}, um die
+Schritte nach der Installation und ein paar Tests durchzuführen.
+
+@enumerate
+@item
+Wählen Sie das Verzeichnis, in dem Sie die Distribution entpacken wollen,
+und wechseln Sie dort hinein.
+
+@item
+Holen Sie sich eine Distributionsdatei von einer der Sites, die unter
+@ref{Getting MySQL, , Wie man MySQL erhält} aufgelistet sind.
+
+@item
+Wenn Sie Berkeley-DB-Tabellen mit MySQL verwenden wollen, müssen Sie sich
+eine gepatchte Version des Berkeley-DB-Quellcodes besorgen. Bitte lesen Sie
+das Kapitel über Berkeley-DB-Tabellen, bevor Sie fortfahren. @xref{BDB}.
+
+MySQL-Quelldistributionen stehen als komprimierte @code{tar}-Archive zur
+Verfügung und haben Namen wie @file{mysql-VERSION.tar.gz}, wobei
+@code{VERSION} eine Zahl ist, wie @value{mysql_version}.
+
+@item
+Fügen Sie einen Benutzer (User) und eine Gruppe (Group) hinzu, unter dem /
+der @code{mysqld} laufen soll:
+
+@example
+shell> groupadd mysql
+shell> useradd -g mysql mysql
+@end example
+
+Diese Befehle fügen den Benutzer @code{mysql} und die Gruppe @code{mysql}
+hinzu. Die Syntax für @code{useradd} und @code{groupadd} kann sich auf
+unterschiedlichen Unix-Systemen geringfügig unterscheiden. Die Befehle
+können @code{adduser} und @code{addgroup} heißen. Wenn Sie wollen, können
+Sie Benutzer und Gruppe auch anders nennen als @code{mysql}.
+
+@item
+Entpacken Sie die Distribution ins aktuelle Verzeichnis:
+@example
+shell> gunzip < /pfad/zu/mysql-VERSION.tar.gz | tar xvf -
+@end example
+
+Dieser Befehl erzeugt ein Verzeichnis namens @file{mysql-VERSION}.
+
+@item
+Wechseln Sie in das oberste Verzeichnis der entpackten Distribution:
+
+@example
+shell> cd mysql-VERSION
+@end example
+
+Beachten Sie, dass Sie aktuell MySQL aus diesem obersten Verzeichnis
+konfigurieren und bauen müssen. Sie können MySQL nicht in ein anderes
+Verzeichnis bauen.
+
+@item
+Konfigurieren Sie das Release und kompilieren Sie alles:
+
+@example
+shell> ./configure --prefix=/usr/local/mysql
+shell> make
+@end example
+
+Wenn Sie @code{configure} laufen lassen, können Sie dabei einige Optionen
+angeben. Geben Sie @code{./configure --help} ein, um eine Liste von
+Optionen zu erhalten. @ref{configure options, , @code{configure}-Optionen}
+erörtert einige der nützlicheren Optionen.
+
+Wenn @code{configure} fehlschlägt und Sie sich wegen Hilfe an
+@email{mysql@@lists.mysql.com} wenden, geben Sie bitte alle Zeilen aus
+@file{config.log} an, von denen Sie annehmen, dass sie bei der
+Problembehebung hilfreich sein könnten. Fügen Sie auch die letzten Zeilen
+der Ausgabe von @code{configure} hinzu, wenn @code{configure} abbricht.
+Schicken Sie den Bug-Bericht ein, indem Sie das @code{mysqlbug}-Skript
+benutzen. @xref{Bug reports}.
+
+Wenn das Kompilieren fehlschlägt, sehen Sie unter
+@ref{Compilation problems} nach, was bei einer Reihe geläufiger Probleme
+hilft.
+
+@item
+Installieren Sie alles:
+
+@example
+shell> make install
+@end example
+
+Eventuell müssen Sie diesen Befehl als @code{root} ausführen.
+
+@item
+Erzeugen Sie die MySQL-Berechtigungstabellen (Grant Tables, nur notwendig,
+wenn Sie MySQL noch nie vorher installiert haben):
+
+@example
+shell> scripts/mysql_install_db
+@end example
+
+Beachten Sie, dass bei MySQL-Versionen vor Version 3.22.10 der MySQL-Server
+startet, wenn Sie @code{mysql_install_db} laufen lassen. Das gilt für
+neuere Versionen nicht mehr!
+
+@item
+Ändern Sie den Besitzer der Binärdateien zu @code{root} und den Besitzer
+des Daten-Verzeichnisses zu dem Benutzer, unter dem Sie @code{mysqld} laufen
+lassen wollen:
+
+@example
+shell> chown -R root /usr/local/mysql
+shell> chown -R mysql /usr/local/mysql/var
+shell> chgrp -R mysql /usr/local/mysql
+@end example
+
+Der erste Befehl ändert die @code{owner}-Attribute der Dateien auf den
+Benutzer @code{root}, der zweite ändert die @code{owner}-Attribute des
+Daten-Verzeichnisses auf den Benutzer @code{mysql} und der dritte ändert die
+@code{group}-Attribute auf die Gruppe @code{mysql}.
+
+@item
+Wenn Sie die Unterstützung für die Perl-@code{DBI}/@code{DBD}-Schnittstelle
+hinzufügen wollen, sehen Sie unter @ref{Perl} nach.
+
+@item
+Wenn Sie wollen, dass MySQL automatisch startet, wenn Sie Ihre Maschine
+hoch fahren, kopieren Sie @code{support-files/mysql.server} an die Stelle,
+wo Ihr System seine Startdateien hat. Weitere Informationen finden Sie im
+@code{support-files/mysql.server}-Skript selbst sowie unter
+@ref{Automatic start}.
+@end enumerate
+
+Nachdem alles installiert wurde, sollten Sie Ihre Distribution
+initialisieren und testen:
+
+@example
+shell> /usr/local/mysql/bin/safe_mysqld --user=mysql &
+@end example
+
+Wenn dieser Befehl sofort mit @code{mysqld daemon ended} fehlschlägt,
+finden Sie einige Informationen dazu in der Datei
+@file{mysql-Daten-Verzeichnis/'hostname'.err}. Der wahrscheinliche Grund ist
+der, dass bereits ein anderer @code{mysqld}-Server läuft. @xref{Multiple servers}.
+
+@xref{Post-installation}.
+
+
+@node Applying patches, configure options, Quick install, Installing source
+@c German node Patches anwenden
+@subsection Wie man Patches anwendet
+
+@cindex Patches, anwenden
+@cindex Anwenden, Patches
+
+Manchmal erscheinen Patches auf der Mailing-Liste oder werden auf
+@uref{http://www.mysql.com/Downloads/Patches, Patches-Bereich} auf der
+MySQL-Website eingestellt.
+
+Um einen Patch aus der Mailing-Liste anzuwenden, speichern Sie die
+Nachricht, in der der Patch enthalten ist, in eine Datei. Wechseln Sie dann
+ins oberste Verzeichnis Ihres MySQL-Source-Trees und geben Sie folgende
+Befehle ein:
+
+@example
+shell> patch -p1 < patch-datei-name
+shell> rm config.cache
+shell> make clean
+@end example
+
+Patches von der FTP-Site werden als Klartextdateien (Plain Text) oder als
+mit @code{gzip} komprimierte Dateien distribuiert. Ein Klartext-Patch
+wenden Sie genau so an, wie oben für die Patches von der Mailing-Liste
+beschrieben. Um ein komprimiertes Patch anzuwenden, wechseln Sie ins
+oberste Verzeichnis Ihres MySQL-Source-Trees und geben Sie folgende Befehle
+ein:
+
+@example
+shell> gunzip < patch-datei-name.gz | patch -p1
+shell> rm config.cache
+shell> make clean
+@end example
+
+Nachdem Sie einen Patch angewendet haben, folgen Sie den Anweisungen für
+eine normale Installation vom Quellcode, indem Sie mit dem Schritt
+@code{./configure} anfangen. Nach dem Schritt @code{make install}, starten
+Sie den MySQL-Server neu.
+
+Es kann sein, dass Sie jeden laufenden Server anhalten müssen, bevor Sie
+@code{make install} laufen lassen können. (Das machen Sie mit
+@code{mysqladmin shutdown}.) Einige Systeme lassen es nicht zu, dass eine
+neue Programmversion installiert wird, wenn diese eine Version ersetzt, die
+momentan ausgeführt wird.
+
+
+@node configure options, Installing source tree, Applying patches, Installing source
+@c German node Optionen konfigurieren
+@subsection Typische @code{configure}-Optionen
+
+@findex without-server-Option
+@cindex @code{configure}-Skript
+@cindex Optionen, configure
+@cindex Konfigurationsoptionen
+@cindex Log-Dateien
+@cindex Dateien, Log
+
+Das @code{configure}-Skript gibt Ihnen in großem Umfang Kontrolle über die
+Konfigurationsmöglichkeiten Ihrer MySQL-Distribution. Typischerweise machen
+Sie das unter Verwendung der Optionen auf der
+@code{configure}-Kommandozeile. Sie können ausserdem @code{configure}
+beeinflussen, indem Sie bestimmte Umgebungsvariablen benutzen.
+@xref{Environment variables}. Um eine Liste der Optionen zu erhalten, die
+@code{configure} unterstützt, geben Sie folgendes ein:
+
+@example
+shell> ./configure --help
+@end example
+
+Einige der gebräuchlicheren @code{configure}-Optionen sind im Folgenden
+beschrieben:
+
+@itemize @bullet
+@item
+Um nur die MySQL-Client Bibliotheken und Client-Programme und nicht den
+Server zu kompilieren, benutzen Sie die @code{--ohne-server}-Option:
+
+@example
+shell> ./configure --without-server
+@end example
+
+@c FIX incorrect..
+
+Wenn Sie keinen C++-Kompiler haben, können Sie @code{mysql} nicht
+kompilieren (MySQL ist das einzige Client-Programm, das C++ erfordert). In
+diesem Fall können Sie den Code in @code{configure} entfernen, der auf den
+C++-Kompiler testet, und dann @code{./configure} mit der
+@code{--without-server}-Option eingeben. Dieser Kompilierschritt wird nach
+wie vor versuchen, @code{mysql} zu bauen, aber Sie können alle Warnungen zu
+@file{mysql.cc} ignorieren. (Wenn @code{make} anhält, versuchen Sie
+@code{make -k}, um ihm mitzuteilen, dass es mit dem Rest des Builds
+fortfahren soll, auch wenn Fehler auftreten.)
+
+@item
+Wenn Sie nicht wollen, dass Ihre Log-Dateien und Datenbankverzeichnisse
+unter @file{/usr/local/var} liegen, benutzen Sie ein
+@code{configure}-Kommando wie folgendes:
+
+@example
+shell> ./configure --prefix=/usr/local/mysql
+shell> ./configure --prefix=/usr/local \
+ --localstatedir=/usr/local/mysql/data
+@end example
+
+Der erste Befehl ändert das Installationspräfix, so dass alles unter
+@file{/usr/local/mysql} statt unter @file{/usr/local} installiert wird. Der
+zweite Befehl bewahrt das vorgabemäßige Installationspräfix, aber
+überschreibt die vorgabemäßige Stelle für Datenbankverzeichnisse
+(normalerweise @file{/usr/local/var}) und ändert sie zu
+@code{/usr/local/mysql/data}.
+
+@cindex Speicherort des Sockets ändern
+@cindex Socket-Speicherort, ändern
+@cindex mysql.sock, Änderung des Speicherorts
+@item
+
+Wenn Sie Unix benutzen und wollen, dass der MySQL-Socket an anderer Stelle
+liegt als vorgabemäßig (normalerweise im Verzeichnis @file{/tmp} oder
+@file{/var/run}), benutzen Sie ein @code{configure}-Kommando wie folgendes:
+
+@example
+shell> ./configure --with-unix-socket-path=/usr/local/mysql/tmp/mysql.sock
+@end example
+
+Beachten Sie, dass die angegebene Datei mit einem absoluten Pfadnamen
+angegeben werden muss! Sie können den Speicherort von @file{mysql.sock}
+auch später noch ändern, indem Sie die MySQL Optionsdateien benutzen.
+@xref{Problems with mysql.sock}.
+
+@cindex Kompilieren, statisch
+@cindex Statisch, Kompilieren
+@item
+Wenn Sie statisch gelinkte Programme kompilieren wollen (um zum Beispiel
+eine Binärdistribution zu machen, mehr Geschwindigkeit zu erhalten oder
+Probleme mit RedHat-Linux-Distributionen zu umgehen (Workaround)), geben
+Sie @code{configure} wie folgt ein:
+
+@example
+shell> ./configure --with-client-ldflags=-all-static \
+ --with-mysqld-ldflags=-all-static
+@end example
+
+
+
+@tindex @code{CC} Umgebungsvariable
+@tindex Umgebungsvariable, @code{CC}
+@tindex @code{CXX} Umgebungsvariable
+@tindex Umgebungsvariable, @code{CXX}
+@cindex @code{gcc}
+@cindex C++-Kompiler, @code{gcc}
+@cindex Kompiler, C++ @code{gcc}
+@item
+Wenn Sie @code{gcc} benutzen und @code{libg++} oder @code{libstdc++} nicht
+installiert haben, können Sie @code{configure} mitteilen, @code{gcc} als
+Ihren C++-Kompiler zu benutzen:
+
+@example
+shell> CC=gcc CXX=gcc ./configure
+@end example
+
+Wenn Sie @code{gcc} als C++-Kompiler benutzen, versucht dieser nicht,
+@code{libg++} oder @code{libstdc++} zu linken.
+
+Hier sind einige gebräuchliche Umgebungsvariablen, die man in Abhängigkeit
+vom verwendeten Kompiler setzen kann:
+
+@tindex CXXFLAGS Umgebungsvariable
+@tindex Umgebungsvariable, CXXFLAGS
+@multitable @columnfractions .20 .80
+@item gcc 2.7.2.1 @tab
+CC=gcc CXX=gcc CXXFLAGS="-O3 -felide-constructors"
+@item egcs 1.0.3a @tab
+CC=gcc CXX=gcc CXXFLAGS="-O3 -felide-constructors -fno-exceptions -fno-rtti"
+@item gcc 2.95.2 @tab
+CFLAGS="-O3 -mpentiumpro" CXX=gcc CXXFLAGS="-O3 -mpentiumpro -felide-constructors -fno-exceptions -fno-rtti"
+@item pgcc 2.90.29 oder newer @tab
+CFLAGS="-O3 -mpentiumpro -mstack-align-double" CXX=gcc CXXFLAGS="-O3 -mpentiumpro -mstack-align-double -felide-constructors -fno-exceptions -fno-rtti"
+@end multitable
+
+In den meisten Fällen erhalten Sie eine ziemlich optimale MySQL-Binärdatei,
+indem Sie die Optionen von weiter oben nutzen und die folgenden Optionen
+zur Konfigurationszeile hinzufügen:
+
+@example
+--prefix=/usr/local/mysql --enable-assembler --with-mysqld-ldflags=-all-static
+@end example
+
+Die komplette Konfigurationszeile würde also etwa wie folgt aussehen (für
+alle aktuellen gcc-Versionen):
+
+@example
+CFLAGS="-O3 -mpentiumpro" CXX=gcc CXXFLAGS="-O3 -mpentiumpro -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --enable-assembler --with-mysqld-ldflags=-all-static
+@end example
+
+Die Binärdistributionen, die wir auf der MySQL-Website unter
+@uref{http://www.mysql.com} zur Verfügung stellen, sind allesamt mit voller
+Optimierung kompiliert und sollten daher für die meisten Benutzer perfekt
+sein. @xref{MySQL binaries}. Einiges können Sie noch fein justieren, um
+noch schnellere Binärdistributionen zu erhalten, aber das ist nur etwas für
+fortgeschrittene Benutzer. @xref{Compile and link options}.
+
+Wenn der Build fehlschlägt und Fehler produziert, die aussagen, dass Ihr
+Kompiler oder Linker nicht in der Lage ist, die gemeinsam benutzte
+(shared) Bibliothek @file{libmysqlclient.so.#} (@samp{#} ist eine
+Versionsnummer) zu erzeugen, können Sie dieses Problem umgehen, indem Sie
+die @code{--disable-shared}-Option von @code{configure} benutzen. In diesem
+Fall baut @code{configure} keine gemeinsam benutzte
+@code{libmysqlclient.so.#}-Bibliothek.
+
+@cindex Vorgabewerte, Unterdrückung
+@cindex Unterdrückung, Vorgabewerte
+@item
+Sie können MySQL so konfigurieren, dass keine @code{DEFAULT}-Spaltenwerte
+für Nicht-@code{NULL}-Spalten benutzt werden (also Spalten, bei denen nicht
+zulässig ist, dass sie @code{NULL} sind). Das führt dazu, dass
+@code{INSERT}-Statements einen Fehler erzeugen, ausser wenn ausdrücklich
+Werte für Spalten angegeben werden, die einen Nicht-@code{NULL}-Werte
+verlangen. Um die Benutzung von Vorgabewerten zu unterdrücken, geben Sie
+@code{configure} wie folgt ein:
+
+@tindex CXXFLAGS Umgebungsvariable
+@tindex Umgebungsvariable, CXXFLAGS
+@example
+shell> CXXFLAGS=-DDONT_USE_DEFAULT_FIELDS ./configure
+@end example
+
+@cindex Zeichensätze
+@findex configure-Option, --with-charset
+@findex configure-Option, --with-extra-charset
+@item
+Als Vorgabe benutzt MySQL den Zeichensatz ISO-8859-1 (Latin1). Um diesen
+Vorgabesatz zu ändern, benutzen Sie die @code{--with-charset}-Option:
+@example
+shell> ./configure --with-charset=CHARSET
+@end example
+@code{CHARSET} kann einer der folgenden sein: @code{big5}, @code{cp1251}, @code{cp1257},
+@code{czech}, @code{danish}, @code{dec8}, @code{dos}, @code{euc_kr},
+@code{gb2312}, @code{gbk}, @code{german1}, @code{hebrew}, @code{hp8},
+@code{hungarian}, @code{koi8_ru}, @code{koi8_ukr}, @code{latin1},
+@code{latin2}, @code{sjis}, @code{swe7}, @code{tis620}, @code{ujis},
+@code{usa7} oder @code{win1251ukr}.
+@xref{Character sets}.
+
+Wenn Sie Zeichen zwischen Server und Client konvertieren wollen, sollten
+Sie sich den @code{SET OPTION CHARACTER SET}-Befehl ansehen.
+@xref{SET OPTION, , @code{SET OPTION}}.
+
+@cindex @code{myisamchk}
+@strong{Achtung:} Wenn Sie Zeichensätze ändern, nachdem Sie irgend welche
+Tabellen angelegt haben, müssen Sie @code{myisamchk -r -q} über jede
+Tabelle laufen lassen, denn ansonsten könnten Ihre Indexe falsch sortiert
+werden. (Das kann passieren, wenn Sie MySQL installieren, ein paar Tabellen
+erzeugen und danach MySQL rekonfigurieren, so dass es einen anderen
+Zeichensatz benutzt, und dann neu installieren.)
+
+Mit der Option @code{--with-extra-charset=LIST} können Sie zusätzliche
+Zeichensätze definieren, die in den Server einkompiliert werden sollen.
+
+Hierbei ist @code{LIST} entweder eine Liste eines Zeichensatzes, die durch
+Leerzeichen getrennt ist, oder @code{complex}, um alle Zeichen
+einzuschließen, die nicht dynamisch geladen werden können, oder
+@code{all}, um alle Zeichensätze in die Binärdateien einzuschließen.
+
+@item
+Um MySQL mit Debug-Code zu konfigurieren, benutzen Sie die
+@code{--with-debug}-Option:
+@example
+shell> ./configure --with-debug
+@end example
+Das bewirkt, dass eine sichere Speicherzuweisung (Memory Allocator)
+eingeschlossen wird, die einige Fehler finden kann und die Ausgaben
+liefert, was passiert ist. @xref{Debugging server}.
+
+@item
+Wenn Ihre Client-Programme Threads benutzen, müssen Sie zusätzlich eine
+Thread-sichere Version der MySQL-Client-Bibliothek mit der
+@code{--enable-Thread-safe-client}-configure-Option kompilieren. Hierdurch
+wird eine @code{libmysqlclient_r}-Bibliothek angelegt, mit der Sie Ihre
+threaded Applikationen linken können. @xref{Threaded clients}.
+
+@item
+Optionen, die zu bestimmten Systemen gehören, finden sich im
+systemspezifischen Abschnitt dieses Handbuchs. @xref{Which OS, , Betriebssystemspezifische Anmerkungen}.
+@end itemize
+
+
+@node Installing source tree, Compilation problems, configure options, Installing source
+@c German node Installation vom Entwicklungs-Source-Tree
+@subsection Installation vom Entwicklungs-Source-Tree
+
+@cindex Entwicklungs-Source-Tree
+@cindex BitKeeper-Tree
+@cindex CVS-Tree
+
+@strong{VORSICHT:} Sie sollten diesen Abschnitt nur lesen, wenn Sie daran
+interessiert sind, uns beim Testen von neuem Code zu helfen. Wenn Sie nur
+wollen, dass MySQL auf Ihrem System läuft, sollten Sie eine
+Standard-Distribution wählen (entweder eine Quell- oder eine
+Binärdistribution).
+
+Um unseren aktuellsten Entwicklungs-Source-Tree zu bekommen, folgen Sie
+diesen Anweisungen:
+
+@enumerate
+@item
+Laden Sie @strong{BitKeeper} von
+@uref{http://www.bitmover.com/cgi-bin/download.cgi} herunter. Sie benötigen
+@strong{Bitkeeper} 2.0 oder neuer, um auf unser Repository zuzugreifen.
+
+@item
+Folgen Sie den Anweisungen, um BitKeeper zu installieren.
+
+@item
+Nachdem @strong{BitKeeper} installiert ist, benutzen Sie diesen Befehl, um
+den MySQL-3.23-Branch zu klonen:
+
+@example
+shell> bk clone bk://work.mysql.com:7000 mysql
+@end example
+
+Um den 4.0-Branch zu klonen, benutzen Sie statt dessen diesen Befehl:
+
+@example
+shell> bk clone bk://work.mysql.com:7001 mysql-4.0
+@end example
+
+Das erstmalige Herunterladen des Source-Trees kann eine Weile dauern,
+abhängig von Ihrer Verbindungsgeschwindigkeit. Bitte Geduld.
+
+@item
+Sie brauchen GNU @code{autoconf}, @code{automake}, @code{libtool} und
+@code{m4}, um die nächsten Befehle auszuführen.
+Wenn Sie in diesem Stadium seltsame Fehler erhalten, überprüfen Sie bitte,
+ob Sie wirklich @code{libtool} installiert haben!
+
+@example
+shell> cd mysql
+shell> bk -r edit
+shell> aclocal; autoheader; autoconf; automake;
+shell> ./configure # Geben Sie hier Ihre Lieblingsoptionen an
+shell> make
+@end example
+
+Eine Sammlung unserer Standard-configure-Skripts befindet sich im
+@file{BUILD/} Unterverzeichnis. Wenn Sie faul sind, können Sie
+@file{BUILD/compile-pentium-debug} benutzen. Um für unterschiedliche
+Architekturen zu kompilieren, ändern Sie das Skript ab und entfernen die
+Flags, die Pentium-spezifisch sind.
+
+@item
+Wenn der Build fertig ist, lassen Sie @code{make install} laufen. Seien Sie
+damit vorsichtig auf Produktionsmaschinen, denn dieser Befehl kann Ihre
+Live-Release-Installation überschreiben! Wenn Sie eine weitere Installation
+von MySQL haben, empfehlen wir, dass Sie @code{./configure} mit anderen
+Werten für die @code{prefix}-, @code{tcp-port}- und
+@code{unix-socket-path}-Optionen ausführen als die, die für Ihren
+Produktionsserver benutzt werden.
+
+@item
+Spielen Sie reichlich mit Ihrer neuen Installation herum und versuchen Sie,
+die neuen Features zum Absturz zu bringen. Fangen Sie an, indem Sie
+@code{make test} laufen lassen. @xref{MySQL-Test-Suite}.
+
+@item
+Wenn Sie bis zum @code{make}-Stadium gekommen sind und die Distribution
+sich nicht kompilieren läßt, berichten Sie das bitte an
+@email{bugs@@lists.mysql.com}. Wenn Sie die letzten Versionen der
+erforderlichen GNU-Werkzeuge installiert haben und sie abstürzen, wenn Sie
+versuchen, Ihre Konfigurationsdateien zu verarbeiten, berichten Sie das
+bitte ebenfalls. Wenn Sie jedoch @code{aclocal} und einen @code{Befehl
+nicht gefunden}-Fehler erhalten, berichten Sie diesen nicht. Stellen Sie
+statt dessen sicher, dass alle notwendigen Werkzeuge installiert sind und dass
+Ihre @code{PATH}-Variable korrekt gesetzt ist, damit Ihre Shell diese
+finden kann.
+
+@item
+Nach der erstmaligen @code{bk clone}-Operation, um den Source-Tree zu
+erhalten, sollten Sie in regelmäßigen Abständen @code{bk pull} laufen
+lassen, um Aktualisierungen zu erhalten.
+
+@item
+Sie erhalten die Änderungen-Geschichte (Change History) des Trees mit allen
+Diffs, indem Sie @code{bk sccstool} benutzen. Wenn Sie seltsame Diffs sehen
+oder Code, zu dem Sie Fragen haben, zögern Sie nicht, uns eine E-Mail an
+@email{internals@@lists.mysql.com} zu schicken. Auch wenn Sie meinen, eine
+bessere Idee zu haben, wie etwas gemacht werden sollte, schicken Sie uns
+eine E-Mail an dieselbe Adresse, mit einem Patch. @code{bk diffs} erzeugt
+ein Patch für Sie, nachdem Sie Änderungen am Quellcode durchgeführt haben.
+Wenn Sie keine Zeit haben, Ihre Idee zu kodieren, schicken Sie einfach eine
+Beschreibung.
+
+@item
+@strong{BitKeeper} hat ein nettes Hilfe-Dienstprogramm, auf das Sie über @code{bk
+helptool} zugreifen können.
+
+@end enumerate
+
+
+@node Compilation problems, MIT-pthreads, Installing source tree, Installing source
+@c German node Kompilierungsprobleme
+@subsection Probleme beim Kompilieren?
+
+@cindex Kompilieren, Probleme
+@cindex Probleme, Kompilieren
+@cindex Rekonfigurieren
+@cindex @code{config.cache}-Datei
+@cindex Dateien, @code{config.cache}
+
+Alle MySQL-Programme lassen sich sauber ohne Warnungen auf Solaris mit
+@code{gcc} kompilieren. Auf anderen Systemen können Warnungen wegen
+Unterschieden in System-Include-Dateien auftreten. Siehe @ref{MIT-pthreads}
+wegen Warnungen, die auftreten können, wenn Sie MIT-pThreads verwenden.
+Wegen anderer Probleme sehen Sie bitte in der unten stehenden Liste nach.
+
+Die Lösung für viele Probleme beinhaltet Rekonfigurieren. Wenn Sie
+rekonfigurieren müssen, beachten Sie Folgendes:
+
+@cindex @code{configure} nach dem ersten Aufruf laufen lassen
+@cindex @code{configure}, laufen lassen nach dem ersten Aufruf
+@cindex Rekonfigurieren
+@cindex config.cache
+@itemize @bullet
+@item
+Wenn @code{configure} laufen gelassen wird, nachdem es schon einmal lief,
+benutzt es möglicherweise Informationen, die bei vorherigen Aufrufen
+gesammelt wurden. Diese Information wird in der Datei @file{config.cache}
+gespeichert. Wenn @code{configure} startet, sucht es diese Datei und liest
+ihren Inhalt, wenn sie existiert, unter der Annahme, dass diese Information
+immer noch stimmt. Diese Annahme ist falsch, wenn Sie rekonfigurieren.
+
+@item
+Immer, wenn Sie @code{configure} laufen lassen, müssen Sie auch @code{make}
+laufen lassen, um erneut zu kompilieren. Sie werden jedoch einige alte
+Objektdateien vorheriger Builds entfernen wollen, denn diese wurden mit
+anderen Konfigurationsoptionen kompiliert.
+@end itemize
+
+Um zu verhindern, dass alte Konfigurationsinformationen oder Objektdateien
+benutzt werden, geben Sie vor dem erneuten Aufruf von @code{configure}
+folgende Befehle ein:
+
+@example
+shell> rm config.cache
+shell> make clean
+@end example
+
+Alternativ können Sie auch @code{make distclean} laufen lassen.
+
+Die unten stehende Liste beschreibt einige der Probleme, die beim
+Kompilieren von MySQL am häufigsten auftreten:
+
+@itemize @bullet
+@item
+@cindex @code{cc1plus}-Probleme
+@cindex @code{fatal signal 11}
+@cindex @code{sql_yacc.cc}-Probleme
+@cindex Interne Kompiler-Fehler
+@cindex Virtueller Speicher, Probleme beim Kompilieren
+@cindex configure-Option, --with-low-memory
+Wenn Sie Probleme beim Kompilieren von @file{sql_yacc.cc} erhalten, die den
+unten gezeigten ähneln, haben Sie wahrscheinlich keinen Arbeitsspeicher
+oder Swap-Platz (Auslagerungsdatei) mehr.
+
+@example
+Internal compiler error: Programm cc1plus got fatal signal 11
+ oder
+Out of virtual memory
+ oder
+Virtual memory exhausted
+@end example
+
+Das Problem liegt darin, dass @code{gcc} riesige Mengen von Arbeitsspeicher
+benötigt, um @file{sql_yacc.cc} mit Inline-Funktionen zu kompilieren.
+Versuchen Sie, @code{configure} mit der @code{--with-low-memory}-Option
+auszuführen:
+
+@example
+shell> ./configure --with-low-memory
+@end example
+
+Diese Option veranlasst, dass @code{-fno-inline} zur Kompilierzeile
+hinzugefügt wird, wenn Sie @code{gcc} benutzen, bzw. @code{-O0}, wenn Sie
+etwas anderes benutzen. Sie sollten die @code{--with-low-memory}-Option
+selbst dann benutzen, wenn Sie glauben, so viel Arbeitsspeicher und
+Swap-Platz zu haben, dass Ihnen diese unmöglich ausgehen können. Das
+Problem wurde selbst auf Systemen mit großzügiger Hardware-Ausstattung
+beobachtet, und die @code{--with-low-memory}-Option behebt es
+üblicherweise.
+
+@item
+Vorgabemäßig sucht @code{configure} @code{c++} als Kompiler-Namen aus und
+GNU @code{c++} linkt mit @code{-lg++}. Wenn Sie @code{gcc} benutzen, kann
+dieses Verhalten Probleme bei Konfigurationen wie dieser verursachen:
+
+@cindex C++-Kompiler kann keine ausführbaren Dateien (Executables) erzeugen
+@example
+configure: error: installation oder configuration problem:
+c++ compiler cannot create executables.
+@end example
+
+@tindex CXX-Umgebungsvariable
+@tindex Umgebungsvariable, CXX
+Eventuell stoßen Sie beim Kompilieren auch auf Probleme, die mit
+@code{g++}, @code{libg++} oder @code{libstdc++} zu tun haben.
+
+Eine Ursache dieser Probleme liegt darin, dass Sie kein @code{g++} haben
+dürfen, oder Sie dürfen @code{g++} haben, aber nicht @code{libg++} oder
+@code{libstdc++}. Schauen Sie in die @file{config.log}-Datei! Sie sollten
+die genaue Ursache enthalten, warum Ihr C++-Kompiler nicht funktioniert! Um
+dieses Problem zu umgehen, können Sie @code{gcc} als Ihren C++-Kompiler
+benutzen. Versuchen Sie, die Umgebungsvariable @code{CXX} auf @code{"gcc
+-O3"} zu setzen. Beispiel:
+
+@tindex CXX-Umgebungsvariable
+@tindex Umgebungsvariablen, CXX
+@example
+shell> CXX="gcc -O3" ./configure
+@end example
+
+Das funktioniert, weil @code{gcc} C++-Quellen genau so gut wie @code{g++}
+kompiliert, aber vorgabemäßig weder @code{libg++} noch @code{libstdc++}
+linkt.
+
+Eine andere Möglichkeit, das Problem zu beheben, besteht natürlich darin,
+@code{g++}, @code{libg++} und @code{libstdc++} zu installieren.
+
+@item
+Wenn Ihr Kompilieren mit Fehlern wie dem folgenden fehlschlägt, müssen Sie
+Ihre Version von @code{make} auf GNU @code{make} aktualisieren:
+
+@example
+making all in mit-pThreads
+make: Fatal error in reader: Makefile, line 18:
+Badly formed macro assignment
+ oder
+make:Datei `Makefile' line 18: Must be a separator (:
+ oder
+pThread.h: No such file or directory
+@end example
+
+@cindex Solaris-Troubleshooting
+@cindex FreeBSD-Troubleshooting
+@cindex Troubleshooting, Solaris
+@cindex Troubleshooting, FreeBSD
+Von Solaris und FreeBSD ist bekannt, dass sie problembehaftete
+@code{make}-Programme haben.
+
+GNU @code{make} Version 3.75 funktioniert bekanntermaßen.
+
+@tindex CC-Umgebungsvariable
+@tindex Umgebungsvariable, CC
+@tindex CXX-Umgebungsvariable
+@tindex Umgebungsvariable, CXX
+@tindex CFLAGS-Umgebungsvariable
+@tindex Umgebungsvariable, CFLAGS
+@tindex CXXFLAGS-Umgebungsvariable
+@tindex Umgebungsvariable, CXXFLAGS
+@item
+Wenn Sie Flags definieren wollen, die von Ihrem C- oder C++-Kompiler
+benutzt werden, fügen Sie die Flags den @code{CFLAGS}- und
+@code{CXXFLAGS}-Umgebungsvariablen hinzu. Sie können auf diese Weise auch
+die Kompilernamen festlegen, indem Sie @code{CC} und @code{CXX} benutzen.
+Beispiel:
+
+@example
+shell> CC=gcc
+shell> CFLAGS=-O3
+shell> CXX=gcc
+shell> CXXFLAGS=-O3
+shell> export CC CFLAGS CXX CXXFLAGS
+@end example
+
+Siehe @ref{MySQL binaries}: Eine Liste von Flag-Definitionen, die sich
+auf verschiedenen Systemen als nützlich erwiesen haben.
+
+@item
+Wenn Sie einen Fehler wie den folgenden erhalten, müssen Sie Ihren
+@code{gcc}-Kompiler aktualisieren:
+
+@example
+client/libmysql.c:273: parse error before `__attribute__'
+@end example
+
+@code{gcc} 2.8.1 funktioniert bekanntermaßen, aber wir empfehlen statt
+dessen @code{gcc} 2.95.2 oder @code{egcs} 1.0.3a.
+
+@item
+Wenn Sie Fehler wie die unten stehenden erhalten, wenn Sie @code{mysqld}
+kompilieren, hat @code{configure} den Typ des letzten Arguments für
+@code{accept()}, @code{getsockname()} oder @code{getpeername()} nicht
+korrekt erkannt:
+
+@example
+cxx: Error: mysqld.cc, line 645: In this statement, the referenced
+ type of the pointer value "&length" is "unsigned long", which
+ is not compatible with "int".
+new_sock = accept(sock, (struct sockaddr *)&cAddr, &length);
+@end example
+
+Um das zu beheben, editieren Sie die @file{config.h}-Datei (die von
+@code{configure} angelegt wird). Suchen Sie nach folgenden Zeilen:
+
+@example
+/* Define as the base type of the last arg to accept */
+#define SOCKET_SIZE_TYPE XXX
+@end example
+
+Ändern Sie @code{XXX} zu @code{size_t} oder @code{int}, abhängig von Ihrem
+Betriebssystem. (Beachten Sie, dass Sie das jedes Mal tun müssen, wenn Sie
+@code{configure} laufen lassen, weil @code{configure} die Datei
+@file{config.h} neu erzeugt.)
+
+@item
+Die @file{sql_yacc.cc}-Datei wird von @file{sql_yacc.yy} erzeugt.
+Normalerweise muss der Build-Prozess keine @file{sql_yacc.cc} erzeugen,
+weil MySQL schon mit einer fertig erzeugten Kopie daher kommt. Wenn Sie sie
+jedoch neu erzeugen müssen, könnten Sie folgenden Fehler erhalten:
+
+@example
+"sql_yacc.yy", line xxx fatal: default action causes potential...
+@end example
+
+Das ist ein Indiz dafür, dass Ihre Version von @code{yacc} fehlerhaft ist.
+Sie müssen statt dessen wahrscheinlich @code{bison} (die GNU-Version von
+@code{yacc}) installieren und benutzen.
+
+@item
+Wenn Sie @code{mysqld} oder einen MySQL-Client debuggen wollen, lassen Sie
+@code{configure} mit der @code{--with-debug}-Option laufen. Kompilieren Sie
+danach neu und linken Sie Ihre Clients mit der neuen Client-Bibliothek.
+@xref{Debugging client}.
+@end itemize
+
+@node MIT-pthreads, Windows source build, Compilation problems, Installing source
+@c German node MIT-pThreads
+@subsection Anmerkungen zu MIT-pThreads
+
+@cindex MIT-pThreads
+@cindex Thread-Unterstützung, nicht-native
+
+Dieser Abschnitt beschreibt einige der Themen im Zusammenhang mit MIT-pThreads.
+
+Beachten Sie, dass Sie auf Linux KEINE MIT-pThreads benutzen, sondern statt
+dessen LinuxThreads installieren sollten!
+@xref{Linux}.
+
+Wenn Ihr System keine native Thread-Unterstützung bietet, müssen Sie MySQL
+unter Verwendung des MIT-pThread-Pakets bauen. Das betrifft ältere
+FreeBSD-Systeme, SunOS 4.x, Solaris 2.4 und früher und einige andere.
+@xref{Which OS}.
+
+@itemize @bullet
+@item
+Auf den meisten Systemen können Sie die Benutzung von erzwingen, indem Sie
+@code{configure} mit der @code{--with-mit-Threads}-Option laufen lassen:
+
+@example
+shell> ./configure --with-mit-threads
+@end example
+
+Wenn Sie MIT-pThreads benutzen, wird das Bauen (Building) in ein
+Nicht-Quellcode-Verzeichnis nicht unterstützt, weil wir die Änderungen an
+diesem Code minimal halten wollen.
+
+@item
+Die Überprüfungen, die festlegen, ob MIT-pThreads benutzt werden sollten
+oder nicht, finden nur in dem Teil des Konfigurationsprozesses statt, der
+mit dem Server-Code zu tun hat. Wenn Sie die Distribution mit
+@code{--without-server} konfigurieren, um nicht den Client-Code zu bauen,
+wissen die Clients nicht, ob sie MIT-pThreads benutzen sollen oder nicht
+und werden vorgabemäßig Unix-Socket-Verbindungen benutzen. Weil
+Unix-Sockets unter MIT-pThreads nicht laufen, heißt das, dass Sie
+@code{-h} oder @code{--host} benutzen müssen, wenn Sie Client-Programme
+laufen lassen.
+
+@item
+Wenn MySQL so kompiliert wird, dass es MIT-pThreads benutzt, wird
+System-Sperren (System Locking) vorgabemäßig aus Performance-Gründen
+ausgeschaltet. Mit der @code{--use-locking}-Option können Sie dem Server
+mitteilen, System-Sperren zu benutzen.
+
+@item
+Manchmal schlägt der pThread-@code{bind()}-Befehl fehl und bindet nicht an
+ein Socket, ohne jede Fehlermeldung (zumindest auf Solaris). Als Ergebnis
+schlagen alle Verbindungen zum Server fehl. Beispiel:
+
+@example
+shell> mysqladmin version
+mysqladmin: connect to server at '' failed;
+error: 'Can't connect to mysql server on localhost (146)'
+@end example
+
+Die Lösung besteht darin, den @code{mysqld}-Server zu killen und neu zu
+starten. Uns ist das nur dann passiert, wenn wir den Server gezwungen
+haben, herunter zu fahren und sofort danach einen Neustart durchgeführt
+haben.
+
+@item
+Bei MIT-pThreads läßt sich der @code{sleep()}-Systemaufruf nicht mit
+@code{SIGINT} (break) unterbrechen. Das merken Sie nur, wenn Sie
+@code{mysqladmin --sleep} ausführen. Sie müssen dann warten, bis der
+@code{sleep()}-Aufruf beendet wurde, bevor die Unterbrechungsanforderung
+(Interrupt) bedient wird und der Prozess anhält.
+
+@item
+Wenn Sie linken, erhalten Sie möglicherweise Warnmeldungen wie diese
+(zumindest auf Solaris). Sie können sie ignorieren:
+
+@example
+ld: warning: symbol `_iob' hat differing sizes:
+ (file /my/local/pThreads/lib/libpThread.a(findfp.o) value=0x4;
+file /usr/lib/libc.so value=0x140);
+ /my/local/pThreads/lib/libpThread.a(findfp.o) definition taken
+ld: warning: symbol `__iob' hat differing sizes:
+ (file /my/local/pThreads/lib/libpThread.a(findfp.o) value=0x4;
+file /usr/lib/libc.so value=0x140);
+ /my/local/pThreads/lib/libpThread.a(findfp.o) definition taken
+@end example
+
+@item
+Einige weitere Warnungen können ebenfalls ignoriert werden:
+
+@example
+implicit declaration of function `int strtoll(...)'
+implicit declaration of function `int strtoul(...)'
+@end example
+
+@item
+Wir haben es bislang nicht geschafft, @code{readline} mit MIT-pThreads zum
+Laufen zu bringen. (Das wird zwar nicht benötigt, mag aber für einige
+interessant sein.)
+@end itemize
+
+@menu
+* Windows-Umgebung vorbereiten::
+@end menu
+
+@node Windows-Umgebung vorbereiten, , MIT-pthreads, MIT-pthreads
+@c German node <no English equivalent>
+@subsubsection Vorbereitung der Windows-Umgebung
+
+@node Windows source build, , MIT-pthreads, Installing source
+@c German node Windows-Quelldistribution
+@subsection Windows-Quelldistribution
+
+Sie benötigen folgendes:
+
+@itemize @bullet
+@item
+VC++-6.0-Kompiler (aktualisiert mit Service-Pack 4 oder 5 und dem
+Präprozessor-Paket). Das Präprozessor-Paket wird für den Makro-Assembler
+benötigt. Weitere Details finden Sie unter:
+@uref{http://msdn.microsoft.com/vstudio/sp/vs6sp5/faq.asp}.
+@item
+Die MySQL-Quelldistribution für Windows, die von
+@uref{http://www.mysql.com/downloads/} herunter geladen werden kann.
+@end itemize
+
+MySQL bauen
+
+@enumerate
+@item
+Erzeugen Sie ein Arbeitsverzeichnis (z. B. workdir).
+@item
+Entpacken Sie die Quelldistribution in dieses Verzeichnis.
+@item
+Starten Sie den VC++-6.0-Kompiler.
+@item
+Wählen Sie im @code{File}-Menü @code{Open Workspace}.
+@item
+Öffnen Sie den @file{mysql.dsw}-Workspace, den Sie im Arbeitsverzeichnis
+finden.
+@item
+Wählen Sie im @code{Build}-Menü das @code{Set Active Configuration}-
+Menü.
+@item
+Wählen Sie @code{mysqld - Win32 Debug} und klicken Sie auf OK.
+@item
+Drücken Sie @code{F7}, um mit dem Bauen des Debug-Servers, der
+Bibliotheken und einiger Client-Applikationen zu beginnen.
+@item
+Wenn das Kompilieren beendet ist, kopieren Sie die Bibliotheken und die
+ausführbaren Dateien in ein separates Verzeichnis.
+@item
+Kompilieren Sie die Release-Versionen, die Sie haben wollen, auf
+dieselbe Art.
+@item
+Erzeugen Sie das Verzeichnis für die MySQL-Dateien, z. B.
+@file{c:\mysql}.
+@item
+Kopieren Sie aus dem Arbeitsverzeichnis folgende Verzeichnisse in das
+c:\mysql-Verzeichnis:
+
+@itemize @bullet
+@item Data
+@item Docs
+@item Share
+@end itemize
+
+@item
+Erzeugen Sie das Verzeichnis @file{c:\mysql\bin} und kopieren Sie alle
+Server und Clients, die Sie vorher kompiliert haben, hinein.
+@item
+Wenn Sie wollen, können Sie auch das @file{lib}-Verzeichnis erzeugen und
+die vorher kompilierten Bibliotheken hinein kopieren.
+@item
+Führen Sie mit Visual Studio ein Clean durch.
+@end enumerate
+
+Konfigurieren und starten Sie den Server auf dieselbe Weise wie bei der
+Windows-Binärdistribution. @xref{Windows-Umgebung vorbereiten}.
+
+
+@node Post-installation, Upgrade, Installing source, Installing
+@c German node Nach der Installation
+@section Einstellungen und Tests nach der Installation
+
+@cindex Nach der Installation, Einstellungen und Tests
+@cindex Testen, nach der Installation
+@cindex Setup, nach der Installation
+
+
+Wenn Sie MySQL erst einmal installiert haben (aus einer Binär- oder einer
+Quelldistribution), müssen Sie die Berechtigungstabellen (Grant Tables)
+initialisieren, den Server starten und sicherstellen, dass der Server
+korrekt funktioniert. Eventuell wollen Sie auch einrichten, dass der Server
+automatisch gestartet und angehalten wird, wenn Ihr System startet oder
+herunter gefahren wird.
+
+Normalerweise installieren Sie die Berechtigungstabellen und starten den
+Server wie folgt:
+Bei der Installation einer Quelldistribution:
+@cindex Start, den Server
+@cindex Server, starten
+
+@example
+shell> ./scripts/mysql_install_db
+shell> cd mysql_installations_verzeichnis
+shell> ./bin/safe_mysqld --user=mysql &
+@end example
+
+Bei einer Binärdistribution (nicht RPM- oder pkg-Pakete) tun Sie folgendes:
+
+@example
+shell> cd mysql_installations_verzeichnis
+shell> ./bin/mysql_install_db
+shell> ./bin/safe_mysqld --user=mysql &
+@end example
+
+Das legt die @code{mysql}-Datenbank an, die alle Zugriffsrechte auf
+Datenbanken enthält, die @code{test}-Datenbank, die Sie benutzen können, um
+MySQL zu testen und zusätzlich Berechtigungseinträge für den Benutzer, der
+@code{mysql_install_db} ausführt sowie einen @code{root}-Benutzer (ohne
+Passworte!). Durch den letzten Befehl wird der @code{mysqld}-Server
+gestartet.
+
+@code{mysql_install_db} überschreibt keine alten Berechtigungstabellen,
+deshalb sollte es unter allen Umständen sicher sein. Wenn Sie die
+@code{test}-Datenbank nicht haben wollen, können Sie sie mit
+@code{mysqladmin -u root drop test} entfernen.
+
+Am einfachsten läßt sich das Durchtesten vom obersten Verzeichnis der
+MySQL-Distribution durchführen. Bei einer Binärdistribution ist das Ihr
+Installationsverzeichnis (üblicherweise etwas wie @file{/usr/local/mysql}).
+Bei einer Quelldistribution ist es das Hauptverzeichnis Ihres
+MySQL-Source-Trees.
+@cindex Testen, den Server
+
+
+In den unten dargestellten Befehlen dieses Abschnitts und der folgenden
+Unterabschnitte ist @code{BINDIR} der Pfad zu dem Speicherort, wo Programme
+wie @code{mysqladmin} und @code{safe_mysqld} installiert sind. Bei einer
+Binärdistribution ist das @file{bin}-Verzeichnis innerhalb der
+Distribution. Bei einer Quelldistribution ist @code{BINDIR} wahrscheinlich
+@file{/usr/local/bin}, es sei denn, Sie haben ein anderes
+Installationsverzeichnis als @file{/usr/local} angegeben, als Sie
+@code{configure} laufen ließen. @code{EXECDIR} ist der Speicherort, in dem
+der @code{mysqld}-Server installiert ist. Bei einer Binärdistribution ist
+das derselbe wie @code{BINDIR}. Bei einer Quelldistribution ist
+@code{EXECDIR} wahrscheinlich @file{/usr/local/libexec}.
+
+Das Durchtesten wird im Folgenden detailliert beschrieben.
+@cindex Testen, Installation
+
+@enumerate
+@item
+Falls notwendig, starten Sie den @code{mysqld}-Server und richten die
+anfänglichen MySQL-Berechtigungstabellen ein, die alle Zugriffsrechte
+enthalten, die festlegen, wie sich Benutzer mit dem Server verbinden
+dürfen. Das wird normalerweise mit dem @code{mysql_install_db}-Skript
+gemacht:
+
+@example
+shell> scripts/mysql_install_db
+@end example
+
+Typischerweise müssen Sie @code{mysql_install_db} nur laufen lassen, wenn
+Sie MySQL zum ersten Mal installieren. Wenn Sie eine existierende
+Installation aktualisieren (Update), können Sie deshalb diesen Schritt
+überspringen. (@code{mysql_install_db} ist jedoch ziemlich sicher und
+aktualisiert keine bereits existierenden Tabellen, daher können Sie im
+Zweifel immer @code{mysql_install_db} laufen lassen.)
+
+@code{mysql_install_db} erzeugt sechs Tabellen (@code{user}, @code{db},
+@code{host}, @code{tables_priv}, @code{columns_priv} und @code{func}) in
+der @code{mysql}-Datenbank. Eine Beschreibung der anfänglichen
+Zugriffsrechte wird in @ref{Privileges} festgelegt. Kurz gesagt
+erlauben diese Zugriffsrechte dem MySQL-Benutzer @code{root}, alles zu tun,
+und jedem, Datenbanken anzulegen oder zu benutzen, deren Name @code{'test'}
+ist oder mit @code{'test_'} beginnt.
+
+Wenn Sie die Zugriffsberechtigungstabellen (Grant Tables) nicht einrichten,
+wird folgender Fehler in der Logdatei erscheinen, wenn Sie den Server
+starten:
+
+@tindex host.frm, problems finding
+@example
+mysqld: Can't find file: 'host.frm'
+@end example
+
+Dasselbe kann auch bei einer MySQL-Binärdistribution passieren, wenn Sie
+MySQL nicht mit exakt @code{./bin/safe_mysqld} starten!
+@xref{safe_mysqld, , @code{safe_mysqld}}.
+
+Eventuell müssen Sie @code{mysql_install_db} als @code{root} laufen lassen.
+Wenn Sie wollen, können Sie jedoch den MySQL-Server als unprivilegierter
+(non-@code{root})-Benutzer laufen lassen, vorausgesetzt, dieser Benutzer
+darf Dateien im Datenbank-Verzeichnis lesen und schreiben. Anweisungen, wie
+Sie MySQL als unprivilegierter Benutzer laufen lassen können, finden Sie in
+@ref{Privilege changes, , Den MySQL-Benutzer ändern}.
+
+Wenn Sie Probleme mit @code{mysql_install_db} bekommen, sehen Sie bitte
+unter @ref{mysql_install_db, , @code{mysql_install_db}} nach.
+
+Es gibt eine Reihe von Alternativen zum Laufenlassen des
+@code{mysql_install_db}-Skripts, was mit der MySQL-Distribution
+mitgeliefert wird:
+
+@itemize @bullet
+@item
+Sie können @code{mysql_install_db} editieren, bevor Sie es laufen lassen,
+um die anfänglichen Zugriffsrechte zu ändern, die in die Rechtetabellen
+installiert werden. Das ist nützlich, wenn Sie MySQL auf einer großen Zahl
+von Maschinen mit denselben Zugriffsrechten installieren wollen. In diesem
+Fall müssen Sie wahrscheinlich nur ein paar zusätzliche
+@code{INSERT}-Statements für die @code{mysql.user}- und
+@code{mysql.db}-Tabellen hinzufügen!
+
+@item
+Wenn Sie Dinge in den Berechtigungstabellen ändern wollen, nachdem diese
+installiert wurden, lassen Sie @code{mysql_install_db} laufen und geben
+dann den Befehl @code{mysql -u root mysql} ein, um sich als
+MySQL-@code{root}-Benutzer mit den Berechtigungstabellen zu verbinden.
+Danach können Sie SQL-Statements eingeben, um die Tabellen direkt zu
+verändern.
+
+@item
+Es ist möglich, die Berechtigungstabellen komplett neu zu erzeugen, nachdem
+Sie angelegt wurden. Das werden Sie zum Beispiel tun wollen, wenn Sie die
+Tabellen bereits angelegt haben, Sie nun aber neu anlegen wollen, weil Sie
+@code{mysql_install_db} editiert haben.
+@end itemize
+
+Zu weiteren Informationen über diese Alternativen siehe
+@ref{Privilege system}.
+
+@item
+Starten Sie den MySQL-Server wie folgt:
+
+@example
+shell> cd mysql_installations_verzeichnis
+shell> bin/safe_mysqld &
+@end example
+
+Wenn Sie Probleme haben, den Server zu starten, sehen Sie unter
+@ref{Starting server} nach.
+
+@item
+Benutzen Sie @code{mysqladmin}, um sicherzustellen, dass der Server läuft.
+Die folgenden Befehle sind ein einfacher Test, um zu überprüfen, ob der
+Server läuft und auf Verbindungen reagiert:
+
+@example
+shell> BINDIR/mysqladmin version
+shell> BINDIR/mysqladmin variables
+@end example
+
+Die Ausgabe von @code{mysqladmin version} kann geringfügig variieren,
+abhängig von Ihrer Plattform und der Version von MySQL, sollte aber etwa
+wie folgt aussehen:
+
+@example
+shell> BINDIR/mysqladmin version
+mysqladmin Ver 8.14 Distrib 3.23.32, for linux on i586
+Copyright (C) 2000 MySQL AB & MySQL Finnland AB & TCX DataKonsult AB
+This software comes mit ABSOLUTELY NO WARRANTY. This ist free software,
+und you are welcome to modify und redistribute it under the GPL license
+
+Server version 3.23.32-debug
+Protokoll version 10
+Connection Localhost via Unix socket
+TCP port 3306
+UNIX socket /tmp/mysql.sock
+Uptime: 16 sec
+
+Threads: 1 Questions: 9 Slow queries: 0 Opens: 7 Flush tables: 2 Open tables: 0 Queries per second avg: 0.000 Memory in use: 132K Max memory used: 16773K
+@end example
+
+Um ein Gefühl dafür zu bekommen, was Sie sonst noch mit
+@code{BINDIR/mysqladmin} tun können, rufen Sie es mit der
+@code{--help}-Option auf.
+
+@item
+Stellen Sie sicher, dass Sie den Server herunter fahren können:
+@cindex Server, Herunterfahren
+@cindex Herunterfahren, den Server
+
+@example
+shell> BINDIR/mysqladmin -u root shutdown
+@end example
+
+@item
+Stellen Sie sicher, dass Sie den Server erneut starten können. Tun Sie das
+unter Benutzung von @code{safe_mysqld} oder indem Sie @code{mysqld} direkt
+aufrufen. Beispiel:
+
+@cindex Server, neu starten
+@cindex Neustart, des Servers
+
+@example
+shell> BINDIR/safe_mysqld --log &
+@end example
+
+Wenn @code{safe_mysqld} fehlschlägt, versuchen Sie, es vom
+MySQL-Installationsverzeichnis aus zu starten (falls Sie noch nicht dort
+sind). Wenn das nicht funktioniert, sehen Sie unter see @ref{Starting server} nach.
+
+@item
+Lassen Sie ein paar einfache Tests ablaufen um sicherzustellen, dass der
+Server funktioniert. Die Ausgabe sollte ähnlich der folgenden sein:
+
+@example
+shell> BINDIR/mysqlshow
++-----------+
+| Databases |
++-----------+
+| mysql |
++-----------+
+
+shell> BINDIR/mysqlshow mysql
+Datenbank: mysql
++--------------+
+| Tables |
++--------------+
+| columns_priv |
+| db |
+| func |
+| host |
+| tables_priv |
+| user |
++--------------+
+
+shell> BINDIR/mysql -e "select host,db,user from db" mysql
++------+--------+------+
+| host | db | user |
++------+--------+------+
+| % | test | |
+| % | test_% | |
++------+--------+------+
+@end example
+
+Zusätzlich gibt es eine Benchmark-Suite im @file{sql-bench}-Verzeichnis
+(unterhalb des MySQL-Installationsverzeichnisses), die Sie benutzen können,
+um die Leistungsdaten von MySQL auf verschiedenen Plattformen zu
+vergleichen. Das @file{sql-bench/Results}-Verzeichnis enthält die
+Ergebnisse vieler Testläufe mit verschiedenen Datenbanken und Plattformen.
+Um alle Tests durchzuführen, geben Sie folgende Befehle ein:
+
+@example
+shell> cd sql-bench
+shell> run-all-tests
+@end example
+
+Wenn Sie kein @file{sql-bench}-Verzeichnis haben, benutzen Sie
+wahrscheinlich ein RPM für eine Binärdistribution. (Quelldistributions-RPMs
+beinhalten das Benchmark-Verzeichnis.) In diesem Fall müssen Sie die
+Benchmark-Suite zuerst installieren, bevor Sie sie benutzen können. Ab
+MySQL Version 3.22 gibt es Benchmark-RPM-Dateien, die
+@file{mysql-bench-VERSION-i386.rpm} benannt sind, die Benchmark-Code und
+Daten enthalten.
+
+Wenn Sie eine Quelldistribution haben, können Sie auch die Tests im
+@file{tests}-Unterverzeichnis ausführen. Um beispielsweise
+@file{auto_increment.tst} auszuführen, geben Sie folgendes ein:
+
+@example
+shell> BINDIR/mysql -vvf test < ./tests/auto_increment.tst
+@end example
+
+Die Ergebnisse stehen dann in der @file{./tests/auto_increment.res}-Datei.
+@end enumerate
+
+
+@menu
+* mysql_install_db::
+* Starting server::
+* Automatic start::
+@end menu
+
+@node mysql_install_db, Starting server, Post-installation, Post-installation
+@c German node mysql_install_db
+@subsection Probleme mit @code{mysql_install_db}
+@cindex @code{mysql_install_db}-Skript
+@cindex Skripte, @code{mysql_install_db}
+
+Der Zweck des @code{mysql_install_db}-Skripts ist, neue
+MySQL-Berechtigungstabellen zu erzeugen. Es betrifft keine anderen Daten!
+Es tut nichts, wenn Sie bereits MySQL-Berechtigungstabellen installiert
+haben!
+
+Wenn Sie Ihre Berechtigungstabellen neu erzeugen wollen, sollten Sie den
+@code{mysqld}-Server herunter fahren, falls er läuft, und dann etwas
+Ähnliches wie folgendes tun:
+
+@example
+mv mysql-data-verzeichnis/mysql mysql-data-verzeichnis/mysql-old
+mysql_install_db
+@end example
+
+Dieser Abschnitt listet Probleme auf, denen Sie vielleicht begegnen, wenn
+Sie @code{mysql_install_db} laufen lassen:
+
+@table @strong
+@item @code{mysql_install_db} installiert die Berechtigungstabellen nicht.
+
+Eventuell stellen Sie fest, dass @code{mysql_install_db} bei der
+Installations der Berechtigungstabellen fehlschlägt und mit folgenden
+Meldungen endet:
+
+@example
+starting mysqld daemon with databases from XXXXXX
+mysql daemon ended
+@end example
+
+In diesem Fall sollten Sie einen gründlichen Blick in die Log-Datei werfen!
+Diese sollte sich im Verzeichnis @file{XXXXXX} befinden, das in der
+Fehlermeldung ausgegeben wird, und sollte anzeigen, warum @code{mysqld}
+nicht startete. Wenn Sie nicht verstehen, was passiert ist, schicken Sie
+einen Bug-Bericht inklusive Log. Benutzen Sie hierfür @code{mysqlbug}!
+@xref{Bug reports}.
+
+@item Es läuft bereits ein @code{mysqld}-Daemon.
+
+In diesem Fall müssen Sie wahrscheinlich @code{mysql_install_db} überhaupt
+nicht starten. Sie müssen @code{mysql_install_db} nur einmal starten, und
+zwar, wenn Sie MySQL zum ersten Mal installieren.
+
+@item Die Installation eines zweiten @code{mysqld}-Daemons schlägt fehl,
+wenn bereits ein Daemon läuft.
+
+Das kann vorkommen, wenn Sie bereits eine existierende MySQL-Installation
+haben, aber eine neue Installation an einem anderen Speicherort
+unterbringen wollen (zum Beispiel für Testzwecke, oder vielleicht wollen
+Sie auch einfach zwei Installationen zugleich laufen lassen. Im Allgemeinen
+ist der Grund für das Problem, wenn Sie versuchen, den zweiten Server
+laufen zu lassen, dass der zweite Server versucht, denselben Socket und
+Port wie der alte zu benutzen. In diesem Fall erhalten Sie als
+Fehlermeldung: @code{Can't start server: Bind on TCP/IP port: Address
+already in use} oder @code{Can't start server : Bind on unix socket...}.
+@xref{Multiple servers}.
+
+@item Sie haben keinen Schreibzugriff auf @file{/tmp}.
+@cindex Schreibzugriff, tmp
+@cindex Temporäre Datei, Schreibzugriff
+@cindex Dateien, @code{tmp}
+
+Wenn Sie keinen Schreibzugriff haben, um eine Socket-Datei am
+vorgabemäßigen Ort anzulegen (in @file{/tmp}) oder keine Berechtigung, um
+temporäre Dateien in @file{/tmp} anzulegen, erhalten Sie einen Fehler, wenn
+Sie @code{mysql_install_db} laufen lassen oder starten oder wenn Sie
+@code{mysqld} benutzen.
+
+So können Sie einen anderen Socket und ein anderes temporäres Verzeichnis
+festlegen:
+
+@tindex TMPDIR Umgebungsvariable
+@tindex MYSQL_UNIX_PORT Umgebungsvariable
+@tindex Umgebungsvariable, TMPDIR
+@tindex Umgebungsvariable, MYSQL_UNIX_PORT
+@example
+shell> TMPDIR=/irgendein_temporaeres_verzeichnis/
+shell> MYSQL_UNIX_PORT=/irgendein_temporaeres_verzeichnis/mysqld.sock
+shell> export TMPDIR MYSQL_UNIX_PORT
+@end example
+
+@xref{Problems with mysql.sock}.
+
+@file{irgendein_temporaeres_verzeichnis} sollte der Pfad zu einem
+Verzeichnis sein, für das Sie Schreibberechtigung haben.
+@xref{Environment variables}.
+
+Danach sollten Sie in der Lage sein, @code{mysql_install_db} laufen zu
+lassen und den Server zu starten, und zwar mit folgenden Befehlen:
+
+@example
+shell> scripts/mysql_install_db
+shell> BINDIR/safe_mysqld &
+@end example
+
+@item @code{mysqld} stürzt sofort ab
+
+Wenn Sie RedHat Version 5.0 mit einer Version von @code{glibc} laufen
+lassen, die älter als 2.0.7-5 ist, sollten Sie sicherstellen, dass Sie alle
+@code{glibc}-Patches installiert haben!
+Darüber gibt es jede Menge Informationen in den MySQL-Mail-Archiven. Links
+zu den Mail-Archiven finden Sie online unter
+@uref{http://www.mysql.com/documentation/}.
+Siehe auch @ref{Linux}.
+
+Sie können @code{mysqld} auch manuell starten, dabei die
+@code{--skip-grant-tables}-Option benutzen und dann die
+Berechtigungsinformationen selbst mit @code{mysql} eintragen:
+
+@example
+shell> BINDIR/safe_mysqld --skip-grant-tables &
+shell> BINDIR/mysql -u root mysql
+@end example
+
+Von @code{mysql} aus geben Sie die SQL-Befehle ein, die in
+@code{mysql_install_db} stehen. Stellen Sie sicher, dass Sie danach
+@code{mysqladmin flush-privileges} oder @code{mysqladmin reload} laufen
+lassen, um dem Server mitzuteilen, die Berechtigungstabellen neu zu laden.
+@end table
+
+
+@node Starting server, Automatic start, mysql_install_db, Post-installation
+@c German node Server starten
+@subsection Probleme mit dem Start des MySQL-Servers
+@cindex Server, Startprobleme
+@cindex Probleme, beim Starten des Servers
+
+Wenn Sie Tabellen einsetzen werden, die Transaktionen unterstützen (InnoDB,
+BDB), sollten Sie zuerst eine my.cnf-Datei anlegen und die
+Startoptionen für die Tabellentypen setzen, die Sie einsetzen wollen.
+@xref{Table types}.
+
+Im allgemeinen starten Sie den @code{mysqld}-Server auf eine der drei
+folgenden Weisen:
+
+@itemize @bullet
+@item
+Indem Sie @code{mysql.server} aufrufen. Dieses Skript wird hauptsächlich
+beim Systemstart und -herunterfahren eingesetzt. Es wird ausführlicher in
+@ref{Automatic start} beschrieben.
+
+@item
+Indem Sie @code{safe_mysqld} aufrufen. Dieses Skript versucht die korrekten
+Optionen für @code{mysqld} festzustellen und läßt den Server dann mit
+diesen Optionen laufen. @xref{safe_mysqld, ,@code{safe_mysqld}}.
+
+@item
+Auf Windows NT sollten Sie @code{mysqld} wie folgt als Systemdienst
+starten:
+@example
+bin\mysqld-nt --install # MySQL als Systemdienst installieren
+@end example
+
+Jetzt können Sie @code{mysqld} wie folgt starten / anhalten:
+@example
+NET START mysql
+NET STOP mysql
+@end example
+
+Beachten Sie, dass Sie in diesem Fall keine weiteren Optionen für
+@code{mysqld} benutzen können!
+
+Sie können den Systemdienst wie folgt entfernen:
+@example
+bin\mysqld-nt --remove # MySQL als Systemdienst entfernen
+@end example
+
+@item
+Indem Sie @code{mysqld} direkt aufrufen.
+@end itemize
+
+Wenn der @code{mysqld}-Daemon hoch fährt, wechselt er in das
+Daten-Verzeichnis. Dort erwartet er, Log-Dateien und die (process ID)-Datei
+schreiben zu können. Ebenfalls erwartet er dort, Datenbanken zu finden.
+
+Der Speicherort des Daten-Verzeichnisses wird zum Zeitpunkt des Kompilierens
+der Distribution fest verdrahtet. Wenn @code{mysqld} jedoch erwartet, das
+Daten-Verzeichnis irgendwo sonst als an der Stelle zu finden, wo es auf
+Ihrem System tatsächlich ist, funktioniert er nicht richtig. Wenn Sie
+Probleme mit fehlerhaften Pfaden haben, können Sie durch den Aufruf von
+@code{mysqld} mit der @code{--help}-Option herausfinden, welche Optionen
+@code{mysqld} erlaubt und was die vorgabemäßigen Pfad-Einstellung sind.
+Sie können die Vorgaben überschreiben, indem Sie die korrekten Pfadnamen
+als Kommandozeilen-Argumente für @code{mysqld} festlegen. (Diese Optionen
+können auch bei @code{safe_mysqld} benutzt werden.)
+
+Normalerweise sollte es lediglich nötig sein, @code{mysqld} das
+Basis-Verzeichnis mitzuteilen, wo MySQL installiert ist. Das können Sie mit
+der Option @code{--basedir} machen. Zusätzlich können Sie @code{--help}
+benutzen, um die Auswirkung der Pfadänderungsoptionen zu überprüfen
+(beachten Sie, dass @code{--help} die letzte Option des
+@code{mysqld}-Befehls wein @emph{muss}. Beispiel:
+
+@example
+shell> EXECDIR/mysqld --basedir=/usr/local --help
+@end example
+
+Wenn Sie die Pfadeinstellungen erst einmal festgelegt haben, die Sie
+wollen, starten Sie den Server ohne die @code{--help}-Option.
+
+Mit welcher Methode auch immer Sie den Server starten: Wenn er nicht
+korrekt hoch fährt, untersuchen Sie die Log-Datei, um zu sehen, ob Sie den
+Grund dafür herausfinden können. Log-Dateien liegen im Daten-Verzeichnis
+(typischerweise @file{/usr/local/mysql/data} bei einer Binärdistribution,
+@file{/usr/local/var} bei einer Quelldistribution und
+@file{\mysql\data\mysql.err} unter Windows). Suchen Sie im Daten-Verzeichnis
+nach Dateien mit Namen der Form @file{host_name.err} und
+@file{host_name.log}, wobei @code{host_name} der Name Ihres Server-Hosts
+ist. Sehen Sie in den letzten paar Zeilen dieser Dateien nach:
+
+@example
+shell> tail host_name.err
+shell> tail host_name.log
+@end example
+
+Wenn Sie etwas wie das Folgende in der Log-Datei finden:
+@example
+000729 14:50:10 bdb: Recovery function for LSN 1 27595 failed
+000729 14:50:10 bdb: warning: ./test/t1.db: No such file or directory
+000729 14:50:10 Can't init databases
+@end example
+
+Das bedeutet, dass Sie @code{mysqld} nicht mit @code{--bdb-no-recover}
+gestartet haben und Berkeley DB findet, dass etwas mit seinen Log-Dateien
+nicht in Ordnung ist, als es versuchte, Ihre Datenbanken
+wiederherzustellen. Um weitermachen zu können, sollten Sie alle alten
+Berkeley-DB-Log-Dateien aus dem Datenbankverzeichnis an eine andere Stelle
+verschieben, wo Sie sie später untersuchen können. Die Log-Dateien sind wie
+@file{log.0000000001} benannt, wobei die Nummer im Zeitablauf hochgezählt
+wird.
+
+Wenn Sie @code{mysqld} mit BDB-Tabellenunterstützung laufen lassen und
+@code{mysqld} beim Start einen Speicherauszug (Core Dump) liefert, könnte
+das an Problemen mit den BDB-Wiederherstellungs-Logs liegen. In diesem Fall
+können Sie versuchen, @code{mysqld} mit @code{--bdb-no-recover} zu starten.
+Wenn das hilft, sollten Sie danach alle @file{log.*}-Dateien aus dem
+Daten-Verzeichnis entfernen und versuchen, @code{mysqld} erneut zu starten.
+
+Wenn Sie folgenden Fehler bekommen, bedeutet das, dass ein anderes Programm
+(oder ein anderer @code{mysqld}-Server) bereits den TCP/IP-Port oder
+-Socket benutzt, den @code{mysqld} versucht zu benutzen:
+
+@example
+Can't start server: Bind on TCP/IP-Port: Address already in use
+ oder
+Can't start server : Bind on unix socket...
+@end example
+
+Benutzen Sie @code{ps}, um sicherzustellen, dass kein weiterer
+@code{mysqld}-Server läuft. Wenn Sie keinen weiteren Server finden, können
+Sie den Befehl @code{telnet ihr-host-name tcp-ip-port-nummer} eingeben und
+mehrere Male @code{EINGABE} drücken. Wenn Sie keine Fehlermeldung wie
+@code{telnet: Unable to connect to remote host: Connection refused}
+erhalten, benutzt irgend etwas anderes den TCP/IP-Port, den @code{mysqld}
+versucht zu benutzen. Siehe @ref{mysql_install_db} und @ref{Multiple servers}.
+
+Wenn @code{mysqld} gerade läuft, können Sie herausfinden, welche
+Pfadeinstellungen er benutzt, indem Sie folgenden Befehl ausführen:
+
+@example
+shell> mysqladmin variables
+@end example
+
+oder
+
+@example
+shell> mysqladmin -h 'ihr-host-name' variables
+@end example
+
+Wenn @code{safe_mysqld} hoch den Server hoch fährt, Sie sich aber nicht mit
+ihm verbinden können, stellen Sie sicher, dass Sie einen Eintrag wie den
+folgenden in @file{/etc/hosts} haben:
+
+@example
+127.0.0.1 localhost
+@end example
+
+Dieses Problem tritt nur auf Systemen auf, die keine funktionierende
+Thread-Bibliothek besitzen, und für die MySQL so konfiguriert werden muss,
+dass es MIT-pThreads benutzt.
+
+Wenn Sie es nicht schaffen, @code{mysqld} zu starten, können Sie versuchen,
+eine Trace-Datei anzulegen, um das Problem zu finden. @xref{Making trace files}.
+
+Wenn Sie InnoDB-Tabellen benutzen, sehen Sie bei den InnoDB-spezifischen
+Startoptionen nach. @xref{InnoDB start}.
+
+Wenn Sie BDB-(Berkeley DB)-Tabellen benutzen, sollten Sie sich mit den
+verschiedenen Startoptionen von BDB vertraut machen. @xref{BDB start}.
+
+
+@node Automatic start, , Starting server, Post-installation
+@c German node Automatischer Start
+@subsection MySQL automatisch starten und anhalten
+
+@cindex Start, Server automatisch starten
+@cindex Anhalten, den Server
+@cindex Server, starten und anhalten
+
+Die @code{mysql.server}- und @code{safe_mysqld}-Skripte können benutzt
+werden, um den Server automatisch beim Hochfahren des Systems zu starten.
+@code{mysql.server} kann ebenfalls dazu benutzt werden, den Server
+anzuhalten.
+
+Das @code{mysql.server}-Skript kann benutzt werden, um den Server zu
+starten oder anzuhalten, indem man es mit den @code{start}- oder
+@code{stop}-Argumenten aufruft:
+
+@example
+shell> mysql.server start
+shell> mysql.server stop
+@end example
+
+@code{mysql.server} liegt im @file{share/mysql}-Verzeichnis unterhalb des
+MySQL-Installationsverzeichnisses oder im @file{support-files}-Verzeichnis
+des MySQL-Source-Trees.
+
+Bevor @code{mysql.server} den Server startet, wechselt es in das
+MySQL-Installationsverzeichnis. Dann ruft es @code{safe_mysqld} auf.
+Eventuell müssen Sie @code{mysql.server} editieren, wenn Sie eine
+Binärdistribution haben, die Sie an eine nicht stardardmäßige Stelle
+installiert haben. Ändern Sie es so ab, dass es in das richtige Verzeichnis
+wechselt (@code{cd}), bevor es @code{safe_mysqld} startet. Wenn Sie wollen,
+dass der Server unter einem bestimmten Benutzer läuft, fügen Sie eine
+entsprechende @code{user}-Zeile zur @file{/etc/my.cnf}-Datei hinzu, so wie
+weiter unten in diesem Abschnitt dargestellt.
+
+@code{mysql.server stop} hält den Server an, indem es ihm ein Signal
+sendet. Sie können den Server auch automatisch herunter fahren, indem Sie
+@code{mysqladmin shutdown} ausführen.
+
+Wenn Sie möchten, können Sie diese Start- und Stop-Befehle an den
+entsprechenden Stellen Ihrer @file{/etc/rc*}-Dateien einfügen, wenn Sie
+MySQL für Produktions-Applikationen benutzen. Beachten Sie, wenn Sie
+@code{mysql.server} editieren und dann gelegentlich MySQL aktualisieren
+(Update), dass dann Ihre geänderte Version überschrieben wird. Daher
+sollten Sie eine Kopie Ihrer editierten Version machen, die Sie erneut
+installieren können.
+
+Wenn Ihr System @file{/etc/rc.local} benutzt, um externe Skripte zu
+starten, sollten Sie folgendes anhängen:
+@example
+/bin/sh -c 'cd /usr/local/mysql ; ./bin/safe_mysqld --user=mysql &'
+@end example
+
+@cindex Den Speicherort des Sockets ändern
+Sie können Optionen für @code{mysql.server} in einer globalen
+@file{/etc/my.cnf}-Datei hinzufügen. Eine typische @file{/etc/my.cnf}-Datei
+sieht wie folgt aus:
+
+@example
+[mysqld]
+datadir=/usr/local/mysql/var
+socket=/var/tmp/mysql.sock
+port=3306
+user=mysql
+
+[mysql.server]
+basedir=/usr/local/mysql
+@end example
+
+Das @code{mysql.server}-Skript kennt folgende Optionen:
+@code{datadir}, @code{basedir} und @code{pid-file}.
+
+Folgende Tabelle zeigt, welche Optionsgruppen jedes der Startskripts aus
+den Optionsdateien liest:
+
+@multitable @columnfractions .20 .80
+@item @strong{Skript} @tab @strong{Optionsgruppen}
+@item @code{mysqld} @tab @code{mysqld} und @code{server}
+@item @code{mysql.server} @tab @code{mysql.server}, @code{mysqld}, und @code{server}
+@item @code{safe_mysqld} @tab @code{mysql.server}, @code{mysqld}, und @code{server}
+@end multitable
+
+@xref{Option files}.
+
+
+@node Upgrade, Operating System Specific Notes, Post-installation, Installing
+@c German node Upgrade
+@section MySQL aktualisieren (Upgrade / Downgrade)
+
+@cindex Upgrade
+@cindex Downgrade
+
+Sie können die MySQL-form- und data-Dateien jederzeit für verschiedene
+Versionen auf derselben Architektur benutzen, solange Sie dieselbe
+Grundversion von MySQL haben. Die aktuelle Grundversion ist 3. Wenn Sie den
+Zeichensatz ändern, während MySQL läuft (was auch die Sortierreihenfolge
+betreffen kann), müssen Sie @code{myisamchk -r -q} auf alle Tabellen
+ausführen. Ansonsten könnte es sein, dass Ihre Indexe nicht korrekt
+sortiert werden.
+
+Wenn Sie vor neuen Versionen zurück schrecken, können Sie Ihren alten
+@code{mysqld} zu etwas wie @code{mysqld}-'alte-versions-nummer' umbenennen.
+Wenn Ihr neuer @code{mysqld} dann etwas Unerwartetes tut, können Sie ihn
+einfach anhalten und mit Ihrem alten @code{mysqld} neu starten!
+
+Wenn Sie ein Upgrade vornehmen, sollte Sie natürlich Ihre alten Datenbanken
+sichern.
+
+Wenn Sie nach einem Upgrade auf Probleme mit neu kompilierten
+Client-Programmen stoßen, zum Beispiel @code{Commands out of sync} oder
+unerwartete Speicherauszüge (Core Dumps), haben sie wahrscheinlich einen
+alten Header oder eine alte Bibliotheksdatei benutzt, als Sie die Programme
+kompilierten. In diesem Fall sollten Sie das Datum Ihrer
+@file{mysql.h}-Datei und @file{libmysqlclient.a}-Bibliothek überprüfen, um
+sicherzustellen, dass sie aus der neuen MySQL-Distribution stammten. Wenn
+nicht, kompilieren sie Ihre Programme bitte neu!
+
+Wenn Sie Probleme der Art erhalten, dass Ihr neuer @code{mysqld}-Server
+nicht startet oder dass Sie sich nicht ohne Passwort verbinden können,
+überprüfen Sie, ob Sie nicht etwa noch die alte @file{my.cnf}-Datei Ihrer
+alten Installation haben! Sie können das mit @code{program-name
+--print-defaults} tun. Wenn es irgend etwas anderes als den Programmnamen
+ausgibt, haben Sie eine aktive @code{my.cnf}-Datei, die sich auf die Dinge
+auswirkt!
+
+Es ist eine gute Idee, die @code{Msql-Mysql-modules}-Distribution neu zu
+bauen und neu zu installieren, wann immer Sie ein neues Release von MySQL
+installieren, speziell dann, wenn Sie Symptome wie die bemerken, dass alle
+Ihre @code{DBI}-Skripte mit Core-Dumps abbrechen, nachdem Sie MySQL
+aktualisiert haben.
+
+
+@cindex Kompatibilität, zwischen MySQL-Versionen
+@cindex Upgrade, 3.23 auf 4.0
+@menu
+* Upgrading-from-3.23::
+* Upgrading-from-3.22::
+* Upgrading-from-3.21::
+* Upgrading-from-3.20::
+* Upgrading-to-arch::
+@end menu
+
+@node Upgrading-from-3.23, Upgrading-from-3.22, Upgrade, Upgrade
+@c German node Upgrading-from-3.23
+@subsection Upgrade von 3.23 auf Version 4.0
+
+Sie können Ihre alten data-Dateien ohne jede Änderung mit Version 4.0
+benutzen. Wenn Sie Ihre Daten eines MySQL-4.0-Servers für einen älteren
+Server verwenden wollen, müssen Sie @code{mysqldump} benutzen.
+
+Alte Clients sollen mit einem Server Version 4.0 ohne jedes Problem
+funktionieren.
+
+Die folgende Liste stellt dar, auf was Sie aufpassen müssen, wenn Sie auf
+Version 4.0 aktualisieren (Upgrade):
+
+@itemize @bullet
+@item
+@file{safe_mysqld} wurde zu @file{mysqld_safe} umbenannt.
+@item
+Die alten C-API-Funktionen @code{mysql_drop_db}, @code{mysql_create_db} und
+@code{mysql_connect} werden nicht mehr unterstützt, es sei denn, MySQL wird
+mit @code{USE_OLD_FUNCTIONS} kompiliert.
+@item
+Sie sollten @code{TRUNCATE TABLE} benutzen, wenn Sie alle Zeilen aus einer
+Tabelle löschen wollen und Ihnen egal ist, wie viele Zeilen gelöscht
+wurden. (@code{TRUNCATE TABLE} ist schneller als @code{DELETE FROM tabelle}).
+@item
+Sie bekommen einen Fehler, wenn Sie ein aktives @code{LOCK TABLES} oder
+eine aktive Transaktion am Laufen haben, wenn Sie versuchen, @code{TRUNCATE
+TABLE} oder @code{DROP DATABASE} auszuführen.
+@item
+Sie sollten Ganzzahl-(Integer)-Werte in BIGINT-Spalten benutzen (anstelle
+von Zeichenketten wie in MySQL 3.23). Man kann immer noch Zeichenketten
+benutzen, aber die Benutzung von Ganzzahlen ist viel effizienter.
+@item
+Das Format von @code{SHOW OPEN TABLE} hat sich geändert.
+@item
+Multithreaded Clients sollten @code{mysql_thread_init()} und
+@code{mysql_thread_end()} benutzen. @xref{Threaded clients}.
+@end itemize
+@node Upgrading-from-3.22, Upgrading-from-3.21, Upgrading-from-3.23, Upgrade
+@c German node Upgrading-from-3.22
+@subsection Upgrade von einer Version 3.22 auf 3.23
+
+@cindex Kompatibilität, zwischen MySQL-Versionen
+@cindex Upgrade, 3.22 to 3.23
+
+MySQL-Version 3.23 unterstützt Tabellen des neuen @code{MyISAM}-Typs und
+des alten @code{ISAM}-Typs. Sie müssen Ihre alten Tabellen nicht
+konvertieren, um sie mit Version 3.23 einsetzen zu können. Vorgabemäßig
+werden alle neuen Tabellen mit dem Typ @code{MyISAM} angelegt (es sei denn,
+Sie starten @code{mysqld} mit der @code{--default-table-type=isam}-Option).
+Sie können eine @code{ISAM}-Tabelle zu einer @code{MyISAM}-Tabelle mit
+@code{ALTER TABLE tabelle TYPE=MyISAM} konvertieren oder mit dem
+Perl-Skript @code{mysql_convert_table_format}.
+
+Clients der Versionen 3.22 und 3.21 funktionieren ohne jedes Problem mit
+einem Server der Version 3.23.
+
+Die folgende Liste stellt dar, auf was Sie aufpassen müssen, wenn Sie auf
+Version 3.23 aktualisieren (Upgrade):
+
+@itemize @bullet
+@item
+Alle Tabellen, die den @code{tis620}-Zeichensatz benutzen, müssen mit
+@code{myisamchk -r} oder @code{REPAIR TABLE} in Ordnung gebracht werden.
+
+@item
+Wenn Sie ein @code{DROP DATABASE} auf eine mit symbolischem Link verknüpfte
+Datenbank ausführen, werden sowohl der symbolische Links als auch die
+Datenbank gelöscht. (Das war in Version 3.22 nicht der Fall, weil configure
+den @code{readlink}-Systemaufruf nicht erkannte).
+
+@item
+@code{OPTIMIZE TABLE} funktioniert jetzt nur bei @strong{MyISAM}-Tabellen.
+Bei anderen Tabellentypen können Sie @code{ALTER TABLE} benutzen, um die
+Tabelle zu optimieren. Während der Ausführung von @code{OPTIMIZE TABLE}
+wird die Tabelle jetzt vor dem Zugriff anderer Threads gesperrt.
+
+@item
+Der MySQL-Client @code{mysql} wir jetzt vorgabemäßig mit der Option
+@code{--no-named-commands (-g)} gestartet. Diese Option kann mit
+@code{--enable-named-commands (-G)} abgeschaltet werden. Dies kann ein paar
+Inkompatibilitätsprobleme verursachen, zum Beispiel in SQL-Skripten, die
+benannte (named) Befehle ohne ein Semikolon! Befehle im Langformat dagegen
+funktionieren noch auf der ersten Zeile.
+@c Question: ... still work from the first line?
+some cases, für Beispiel in SQL Skripts that use named Befehle ohne a
+semicolon! Long format Befehle still work from the first line.
+
+@item
+If you are using the @code{german} character sort order, you must repair
+all your Tabellen mit @code{isamchk -r}, as we have made some changes in
+the sort order!
+
+@item
+The default return type of @code{IF} will now depend on both arguments
+und not only the first argument.
+
+@item
+@code{AUTO_INCREMENT} funktioniert nicht mit negativen Zahlen. Der Grund
+liegt darin, dass negative Zahlen beim Übergang von -1 auf 0 Probleme
+verursachen. @code{AUTO_INCREMENT} wird jetzt bei MyISAM-Tabellen auf einem
+niedrigeren Level gehandhabt und ist viel schneller als vorher. Bei
+MyISAM-Tabellen werden alte Zahlen auch nicht mehr wieder benutzt, selbst
+wenn Sie einige Zeilen aus der Tabelle löschen.
+
+@item
+@code{CASE}, @code{DELAYED}, @code{ELSE}, @code{END}, @code{FULLTEXT},
+@code{INNER}, @code{RIGHT}, @code{THEN} und @code{WHEN} sind jetzt
+reservierte Wörter.
+
+@item
+@code{FLOAT(X)} ist jetzt ein echter Fließkomma-Typ und kein Wert mit
+einer festen Anzahl von Dezimalstellen.
+
+@item
+Wenn Sie @code{DECIMAL(length,dec)} deklarieren, beinhaltet das
+Längen-Argument nicht mehr den Platz für das Vorzeichen oder den
+Dezimalpunkt.
+
+@item
+Eine @code{TIME}-Zeichenkette muss jetzt von einem der folgenden Formate
+sein:
+@code{[[[DAYS] [H]H:]MM:]SS[.bruchteil]} oder
+@code{[[[[[H]H]H]H]MM]SS[.bruchteil]}
+
+@item
+@code{LIKE} vergleicht jetzt Zeichenketten unter Verwendung derselben
+Vergleichsregeln wie @code{'='}. Wenn Sie das alte Verhalten benötigen,
+können Sie MySQL mit dem @code{CXXFLAGS=-DLIKE_CMP_TOUPPER}-Flag
+kompilieren.
+
+@item
+@code{REGEXP} arbeitet jetzt bei normalen (nicht binären) Zeichenketten
+unabhängig von der Groß-/Kleinschreibung.
+
+@item
+Wenn Sie Tabellen prüfen / reparieren, sollten Sie @code{CHECK TABLE} oder
+@code{myisamchk} für @code{MyISAM}-Tabellen (@code{.MYI}) benutzen und
+@code{isamchk} für ISAM-Tabellen (@code{.ISM}).
+
+@item
+Wenn Sie wollen, dass @code{mysqldump}-Dateien zwischen MySQL-Version 3.22
+und Version 3.23 kompatibel sind, sollten Sie nicht die @code{--opt}- oder
+@code{--full}-Option für @code{mysqldump} benutzen.
+
+@item
+Überprüfen Sie Ihre Aufrufe von @code{DATE_FORMAT()} und stellen Sie
+sicher, dass vor jedem Formatierungszeichen ein @samp{%} steht. (Spätere
+MySQL-Versionen 3.22 ließen diese Syntax zu.)
+
+@item
+@code{mysql_fetch_fields_direct} ist jetzt eine Funktion (es war ein Makro)
+und gibt einen Zeiger auf @code{MYSQL_FIELD} anstelle eines
+@code{MYSQL_FIELD} zurück.
+
+@item
+@code{mysql_num_fields()} kann nicht mehr für ein @code{MYSQL*}-Objekt
+benutzt werden (es ist jetzt eine Funktion, die @code{MYSQL_RES*} als
+Argument nimmt. Sie sollten jetzt statt dessen @code{mysql_field_count()}
+benutzen.
+
+@item
+In MySQL-Version 3.22 war die Ausgabe von @code{SELECT DISTINCT ...} fast
+immer sortiert. In Version 3.23 müssen Sie @code{GROUP BY} oder @code{ORDER
+BY} benutzen, um eine sortierte Ausgabe zu erhalten.
+
+@item
+@code{SUM()} gibt jetzt @code{NULL} zurück statt 0, wenn es keine überein
+stimmenden Zeilen gibt. Das ist in Übereinstimmung mit ANSI-SQL.
+
+@item
+Ein @code{AND} oder @code{OR} mit @code{NULL}-Werten gibt jetzt @code{NULL}
+anstelle von 0 zurück. Das betrifft hauptsächlich Anfragen, die @code{NOT}
+bei einem @code{AND/OR}-Ausdruck wie @code{NOT NULL} = @code{NULL}
+benutzen.
+@code{LPAD()} und @code{RPAD()} kürzen die Ergebnis-Zeichenkette, wenn sie
+länger als das Längen-Argument ist.
+@end itemize
+
+@node Upgrading-from-3.21, Upgrading-from-3.20, Upgrading-from-3.22, Upgrade
+@c German node Upgrading-from-3.21
+@subsection Upgrade von Version 3.21 auf Version 3.22
+
+@cindex Kompatibilität, zwischen MySQL-Versionen
+@cindex Upgrade, 3.21 auf 3.22
+
+Nichts, was die Kompatibilität betrifft, hat sich zwischen Version 3.21 und
+3.22 geändert. Die einzige Falle ist die, dass neue Tabellen, die unter
+Verwendung des @code{DATE}-Typs erzeugt werden, die neue Art der
+Datenspeicherung benutzen. Diese neuen Felder kann man daher nicht von
+einer alten Version von @code{mysqld} ansprechen.
+
+Nachdem Sie MySQL-Version 3.22 installiert haben, starten Sie den neuen
+Server und lassen dann das @code{mysql_fix_privilege_tables}-Skript laufen.
+Dieses fügt die neuen Zugriffsberechtigungen ein, die Sie benötigen, um den
+@code{GRANT}-Befehl zu benutzen. Wenn Sie das vergessen, erhalten Sie ein
+@code{Access denied}, wenn Sie versuchen, @code{ALTER TABLE}, @code{CREATE
+INDEX} oder @code{DROP INDEX} zu benutzen. Wenn Ihr MySQL-Root ein Passwort
+benötigt, müssen Sie dieses als Argument zu
+@code{mysql_fix_privilege_tables} angeben.
+
+Die C-API-Schnittstelle für @code{mysql_real_connect()} hat sich geändert.
+Wenn Sie ein altes Client-Programm haben, das diese Funktion aufruft,
+müssen Sie eine @code{0} als neues @code{db}-Argument einfügen (oder den
+Client neu kodieren, so dass er das @code{db}-Element für schnellere
+Verbindungen benutzt). Zusätzlich müssen Sie @code{mysql_init()} aufrufen,
+bevor Sie @code{mysql_real_connect()} aufrufen! Diese Änderung wurde
+durchgeführt, damit die neue @code{mysql_options()}-Funktion in der
+@code{MYSQL}-Handler-Struktur Optionen speichern kann.
+
+The @code{mysqld}-Variable @code{key_buffer} wurde umbenannt in
+@code{key_buffer_size}, Sie können aber in Ihren Startdateien immer noch
+den alten Namen verwenden.
+
+
+@node Upgrading-from-3.20, Upgrading-to-arch, Upgrading-from-3.21, Upgrade
+@c German node Upgrading-from-3.20
+@subsection Upgrade von Version 3.20 auf Version 3.21
+
+@cindex Upgrade, 3.20 auf 3.21
+
+Wenn Sie eine Version benutzen, die älter als Version 3.20.28 ist, und auf
+Version 3.21 umstellen wollen, müssen Sie folgendes tun:
+
+Sie können den @code{mysqld}-Server Version 3.21 mit @code{safe_mysqld
+--old-protocol} starten, um ihn mit Clients aus einer Distribution Version
+3.20 zu benutzen. In diesem Fall gibt die neue Client-Funktion
+@code{mysql_errno()} überhaupt keine Server-Fehler zurück, nur
+@code{CR_UNKNOWN_ERROR} (funktioniert aber bei Client-Fehlern), und der
+Server benutzt die alte @code{password()}-Überprüfung statt der neuen.
+
+Wenn Sie die @code{--old-protocol}-Option @strong{NICHT} für @code{mysqld}
+benutzen, müssen Sie folgende Änderungen durchführen:
+
+@itemize @bullet
+@item
+Jeder Client-Code muss neu kompiliert werden. Wenn Sie ODBC benutzen,
+müssen Sie die neuen @strong{MyODBC}-2.x-Treiber verwenden.
+@item
+Sie müssen das Skript @code{Skripts/add_long_password} laufen lassen, um
+das @code{Password}-Feld in der @code{mysql.user}-Tabelle zu
+@code{CHAR(16)} zu ändern.
+@item
+Alle Passwörter müssen in der @code{mysql.user}-Tabelle neu zugewiesen
+werden (um 62-Bit- statt 31-Bit-Passwörter zu erhalten).
+@item
+Das Tabellenformat hat sich nicht geändert, daher müssen Sie keinerlei
+Tabellen konvertieren.
+@end itemize
+
+MySQL-Version 3.20.28 und höher kann das neue @code{user}-Tabellenformat
+handhaben, ohne sich auf Clients auszuwirken. Wenn Sie eine MySQL-Version
+vor Version 3.20.28 haben, funktionieren Passwörter damit nicht mehr, wenn
+Sie die @code{user}-Tabelle konvertieren. Um auf Nummer Sicher zu gehen,
+sollten Sie mindestens auf Version 3.20.28 aktualisieren und erst dann auf
+Version 3.21.
+
+@cindex Protokoll-Unverträglichkeit
+Der neue Client-Code funktioniert bei einem 3.20.x @code{mysqld}-Server.
+Wenn Sie daher Probleme mit 3.21.x bekommen, können Sie den alten
+3.20.x-Server benutzen, ohne die Clients neu kompilieren zu müssen.
+
+Wenn Sie nicht die @code{--old-protocol}-Option für @code{mysqld} benutzen,
+werden alte Clients folgende Fehlermeldung ausgeben:
+
+@example
+ERROR: Protocol mismatch. Server Version = 10 Client Version = 9
+@end example
+
+Die neue Perl-@code{DBI}/@code{DBD}-Schnittstelle unterstützt auch die alte
+@code{mysqlperl}-Schnittstelle. Die einzige Änderung, die Sie machen
+müssen, wenn Sie @code{mysqlperl} benutzen, ist, die Argumente für die
+@code{connect()}-Funktion zu ändern. Die neuen Argumente sind: @code{host},
+@code{database}, @code{user} und @code{password} (die @code{user}- und
+@code{password}-Argumente haben die Plätze getauscht.
+@xref{Perl DBI Class, , Perl-@code{DBI}-Klasse}.
+
+Folgende Änderungen können Anfragen in alten Applikationen betreffen:
+
+@itemize @bullet
+@item
+@code{HAVING} muss jetzt vor einer möglichen @code{ORDER BY}-Klausel
+spezifiziert werden.
+@item
+Die Parameter für @code{LOCATE()} wurden getauscht.
+@item
+Es gibt einige neue reservierte Wörter. Die wichtigsten sind @code{DATE},
+@code{TIME} und @code{TIMESTAMP}.
+@end itemize
+
+
+@node Upgrading-to-arch, , Upgrading-from-3.20, Upgrade
+@c German node Upgrading-to-arch
+@subsection Upgrade auf eine andere Architektur
+
+@cindex Upgrade, auf andere Architektur
+
+Wenn Sie MySQL-Version 3.23 benutzen, können Sie die @code{.frm}-,
+@code{.MYI}- und @code{.MYD}-Dateien zwischen verschiedenen Architekturen
+kopieren, die dasselbe Fließkomma-Format unterstützen. (MySQL kümmert sich
+um eventuelle Byte-Tausch-Belange.)
+
+Die MySQL-@code{ISAM}-Daten und Index-Dateien (@file{.ISD} und
+@file{*.ISM}, je nachdem) sind Architektur-abhängig und in manchen Fällen
+Betriebssystem-abhängig. Wenn Sie Ihre Applikationen auf eine andere
+Maschine mit einer unterschiedlichen Architektur oder einem anderen
+Betriebssystem verlagern wollen, wollten Sie nicht einfach eine Datenbank
+verschieben, indem Sie deren Dateien auf die andere Maschine kopieren.
+Benutzen Sie statt dessen @code{mysqldump}.
+
+Vorgabemäßig erzeugt @code{mysqldump} eine Datei mit SQL-Statements. Sie
+können diese Datei auf die andere Maschine übertragen und Sie als Eingabe
+für den @code{mysql}-Client benutzen.
+
+@code{mysqldump --help} zeigt Ihnen, welche Optionen verfügbar sind. Wenn
+Sie die Daten mit einer neueren Version von MySQL benutzen werden, sollten
+Sie @code{mysqldump --opt} mit der neueren Version benutzen, um einen
+schnellen, kompakten Dump zu erhalten.
+
+Die einfachste (wenngleich nicht schnellste) Art, eine Datenbank von einer
+Maschine auf eine andere zu bringen, ist, die folgenden Befehle auf der
+Maschine auszuführen, auf der die Datenbank liegt:
+
+@example
+shell> mysqladmin -h 'anderer hostname' create db_name
+shell> mysqldump --opt db_name \
+ | mysql -h 'anderer hostname' db_name
+@end example
+
+Wenn Sie eine Datenbank von einer entfernten Maschine über ein langsames
+Netzwerk kopieren wollen, können Sie folgendes benutzen:
+
+@example
+shell> mysqladmin create db_name
+shell> mysqldump -h 'anderer hostname' --opt --compress db_name \
+ | mysql db_name
+@end example
+
+Sie können das Ergebnis auch in einer Datei speichern, diese Datei auf die
+Zielmaschine übertragen und dort in die Datenbank laden. Sie können zum
+Beispiel wie folgt die Datenbank in eine Datei auf der Quellmaschine
+ausgeben (dumpen):
+
+@example
+shell> mysqldump --quick db_name | gzip > db_name.inhalte.gz
+@end example
+
+(Die in diesem Beispiel erzeugte Datei ist komprimiert.) Übertragen Sie die
+Datei, die die Datenbankinhalte enthält, auf die Zielmaschine und geben Sie
+dort diese Befehle ein:
+
+@example
+shell> mysqladmin create db_name
+shell> gunzip < db_name.inhalte.gz | mysql db_name
+@end example
+
+@cindex @code{mysqldump}
+@cindex @code{mysqlimport}
+Sie können auch @code{mysqldump} und @code{mysqlimport} benutzen, um den
+Datenbank-Transfer zu bewerkstelligen.
+Das ist bei großen Tabellen wesentlich schneller als die Benutzung von
+@code{mysqldump}. In den unten dargestellten Befehlen repräsentiert
+@code{DUMPDIR} den vollen Pfadnamen des Verzeichnisses, das Sie benutzen,
+um die Ausgabe von @code{mysqldump} zu speichern.
+
+Legen Sie zunächst das Verzeichnis für die Ausgabe-Dateien an und geben Sie
+die Datenbank aus (Dump):
+
+@example
+shell> mkdir DUMPDIR
+shell> mysqldump --tab=DUMPDIR db_name
+@end example
+
+Übertragen Sie dann die Dateien des @code{DUMPDIR}-Verzeichnisses in ein
+entsprechendes Verzeichnis auf der Zielmaschine und laden Sie dort die
+Dateien in MySQL:
+
+@example
+shell> mysqladmin create db_name # Datenbank erzeugen
+shell> cat DUMPDIR/*.sql | mysql db_name # Tabellen in der Datenbank erzeugen
+shell> mysqlimport db_name DUMPDIR/*.txt # Daten in die Tabellen laden
+@end example
+
+Vergessen Sie auch nicht, die @code{mysql}-Datenbank zu kopieren, den dort
+befinden Sie die Berechtigungstabellen (@code{user}, @code{db},
+@code{host}). Eventuell müssen Sie die Befehle als
+MySQL-@code{root}-Benutzer auf der neuen Maschine eingeben, um die
+@code{mysql}-Datenbank angelegt zu bekommen.
+
+Nachdem Sie die @code{mysql}-Datenbank auf die neue Maschine kopiert haben,
+führen Sie @code{mysqladmin flush-privileges} aus, damit der Server die
+Berechtigungsinformationen neu einliest.
+
+
+@node Operating System Specific Notes, Perl support, Upgrade, Installing
+@c German node Clientseitig
+@section Betriebssystem-spezifische Anmerkungen
+
+
+
+@menu
+* Linux::
+* Windows::
+* Solaris::
+* BSD Notes::
+* Mac OS X::
+* Other Unix Notes::
+* OS/2::
+* BeOS::
+* Novell Netware::
+@end menu
+
+@node Linux, Windows, Operating System Specific Notes, Operating System Specific Notes
+@c German node Linux
+@subsection Linux (alle Linux-Versionen)
+
+
+Die Anmerkungen weiter unten, die @strong{glibc} betreffen, gelten nur
+dann, wenn Sie MySQL selbst bauen. Wenn Sie Linux auf einer x86-Maschine
+fahren, ist es in den meisten Fällen wesentlich besser, einfach unsere
+Binärdateien zu benutzen. Wir linken unsere Binärdateien an die am besten
+gepatchte Version von @strong{glibc}, die wir bieten können, und mit den
+besten Kompiler-Optionen, wobei wir versuchen, MySQL für Hochlast-Server
+geeignet zu machen. Wenn Sie also den Text unten lesen und sich nicht
+sicher sind, was Sie tun sollen, sollten Sie zunächst unsere Binärdateien
+ausprobieren, um zu sehen, ob diese Ihren Anforderungen entsprechen.
+Kümmern Sie sich nur dann um einen eigenen Build, wenn Sie feststellen,
+dass unsere Binärdateien nicht gut genug sind. In diesem Fall wären wir für
+einen Hinweis dazu dankbar, damit wir beim nächsten Mal eine bessere
+Binärdatei bauen können. Für eine typische Benutzung, selbst bei einer
+großen Zahl gleichzeitiger Verbindungen und / oder Tabellen, die größer
+als 2 GB sind, sind unsere Binärdateien in den meisten Fällen die beste
+Wahl.
+
+MySQL benutzt auf Linux LinuxThreads. Wenn Sie eine alte Linux-Version
+benutzen, die keine @code{glibc2} hat, müssen Sie LinuxThreads
+installieren, bevor Sie MySQL kompilieren. Sie erhalten LinuxThreads unter
+@uref{http://www.mysql.com/downloads/Linux}.
+
+@strong{ACHTUNG:} Wir haben einige seltsame Probleme bei Linux 2.2.14 und
+MySQL auf SMP-Systemen festgestellt. Wenn Sie ein SMP-System haben,
+empfehlen wir, so schnell wie möglich auf Linux 2.4 zu aktualisieren
+(Upgrade)! Dadurch wird Ihr System ausserdem schneller und stabiler!
+
+Beachten Sie, dass @code{glibc}-Versionen vor und einschließlich Version
+2.1.1 einen schweren Fehler im @code{pThread_mutex_timedwait}-Handling
+haben, was benutzt wird, wenn Sie @code{INSERT DELAYED} verwenden. Wir
+empfehlen, vor einem Upgrade der glibc @code{INSERT DELAYED} nicht zu
+verwenden.
+
+Wenn Sie planen, mehr als 1000 gleichzeitige Verbindungen zu haben, müssen
+Sie einige Änderungen an LinuxThreads vornehmen, es neu kompilieren und mit
+der neuen @file{libpThread.a} linken. Setzen Sie @code{PTHREAD_THREADS_MAX} in
+@file{sysdeps/unix/sysv/linux/bits/local_lim.h} auf 4096 herauf und setzen
+Sie @code{STACK_SIZE} in @file{linuxThreads/internals.h} auf 256 KB
+herunter. Die Pfade sind relativ zum Wurzelverzeichnis von @code{glibc}.
+Beachten Sie, dass MySQL bei etwa 600 bis 1000 Verbindungen nicht stabil
+läuft, wenn @code{STACK_SIZE} auf den Vorgabewert von 2 MB gesetzt wird.
+
+Wenn Sie Probleme damit bekommen, dass MySQL nicht genug Dateien oder
+Verbindungen öffnen kann, haben Sie möglicherweise Linux nicht so
+konfiguriert, dass es genug Dateien handhaben kann.
+
+In Linux 2.2 und Folgenden können Sie die Anzahl der allozierten
+Datei-Handler herausbekommen, wenn Sie folgendes eingeben:
+
+@example
+cat /proc/sys/fs/file-max
+cat /proc/sys/fs/dquot-max
+cat /proc/sys/fs/super-max
+@end example
+
+Wenn Sie mehr als 16M Speicher haben, sollten Sie etwas Ähnliches wie
+folgendes in Ihr Boot-Skript (@file{/etc/rc/boot.local} auf SuSE)
+eintragen:
+
+@example
+echo 65536 > /proc/sys/fs/file-max
+echo 8192 > /proc/sys/fs/dquot-max
+echo 1024 > /proc/sys/fs/super-max
+@end example
+
+Das können Sie auch von der Kommandozeile aus als Root eingeben, aber in
+diesem Fall werden die alten Beschränkungen wieder benutzt, wenn Sie Ihren
+Computer neu starten.
+
+Zusätzlich sollten Sie in /etc/my.cnf einfügen:
+
+@example
+[safe_mysqld]
+open-files-limit=8192
+@end example
+
+Das sollte MySQL erlauben, bis zu 8192 Verbindungen und Dateien zu
+erzeugen.
+
+Die @code{STACK_SIZE}-Konstante in LinuxThreads steuert das Spacing von
+Thread-Stacks im Adressraum. Sie muss Groß genug sein, damit reichlich
+Platz für den Stack jedes individuellen Threads bleibt, aber klein genug,
+um den Stack irgend eines Threads davon abzuhalten, mit den globalen
+@code{mysqld}-Daten zu kollidieren. Wie wir durch Experimentieren heraus
+fanden, unmappt die Linux-Implementation von @code{mmap()} erfolgreich eine
+bereits gemappte Region, wenn Sie sie anweisen, eine Adresse auszumappen,
+die bereits in Benutzung ist, wobei sie alle Daten der gesamten Seite auf
+Null setzt, statt einen Fehler zurück zu geben. Daher beruht die Sicherheit
+von @code{mysqld} oder jeder anderen Thread-Applikation auf dem
+"Gentleman"-Verhalten des Codes, der Threads erzeugt. Der Benutzer muss
+Vorkehrungen treffen, die sicherstellen, dass die Anzahl laufender Threads
+jederzeit ausreichend gering ist, damit die Thread-Stacks sich vom globalen
+Heap fernhalten. Bei @code{mysqld} sollten Sie dieses "Gentleman"-Verhalten
+forcieren, indem Sie einen vernünftigen Wert für die the
+@code{max_connections}-Variable setzen.
+
+Wenn Sie MySQL selbst bauen und sich nicht mit dem Patchen von LinuxThreads
+herum plagen wollen, sollten Sie @code{max_connections} auf einen Wert
+nicht größer als 500 setzen. Dieser Wert sollte sogar noch kleiner sein,
+wenn Sie einen großen Schlüsselpuffer (Key Buffer), große Heap-Tabellen
+oder andere Dinge haben, die @code{mysqld} dazu bringen könnten, eine Menge
+Speicher zu allozieren, oder wenn Sie einen 2.2-Kernel mit einem 2GB-Patch
+fahren. Wenn Sie unsere Binärdateien oder RPM-Versionen 3.23.23 oder später
+benutzen, können Sie @code{max_connections} sicher auf 1500 setzen, unter
+der Annahme, dass es keine großen Schlüsselpuffer oder Heap-Tabellen mit
+vielen Daten gibt. Je mehr Sie @code{STACK_SIZE} in LinuxThreads reduzieren
+können, desto mehr können Sie sicher Threads erzeugen. Wir empfehlen einen
+Wert zwischen 128K und 256K.
+
+Wenn Sie viele gleichzeitige Verbindungen benutzen, bekommen Sie vielleicht
+Probleme durch ein "Feature" im 2.2-Kernel, der einen Prozess dafür
+bestraft, dass er sich aufspaltet (fork) oder einen Kindprozess klont, um
+einen Fork-Bombenangriff (Fork Bomb Attack) zu verhindern. Das bringt MySQL
+dazu, nicht so gut zu skalieren, wenn Sie die Anzahl gleichzeitiger Clients
+erhöhen. Wir konnten beobachten, dass sich das auf Einprozessor-Systemen
+mit sehr langsamer Thread-Erzeugung bemerkbar macht, was sich darin zeigt,
+dass es sehr lange dauern kann, sich mit MySQL zu verbinden (bis zu einer
+Minute), und genau so lange, um es herunter zu fahren. Auf
+Multiprozessor-Systemen haben wir einen allmählichen Abfall der
+Anfrage-Geschwindigkeit beobachtet, wenn die Anzahl der Clients zunimmt. Im
+Verlauf der Suche nach einer Lösung haben wir von einem unserer Benutzer
+einen Kernel-Patch erhalten, von dem dieser sagt, dass er auf seiner Site
+eine beträchtliche Rolle spielt. Der Patch ist hier verfügbar
+(@uref{http://www.mysql.com/downloads/patches/linux-fork.patch}).
+Inzwischen haben wir recht ausführliche Tests dieses Patchs sowohl auf
+Entwicklungs- als auch auf Produktionssystemen gemacht. Er hat die
+Performance von @code{MySQL} erheblich verbessert, ohne irgend welche
+Probleme zu verursachen, und wir empfehlen ihn jetzt denjenigen unserer
+Benutzer, die immer noch Hochlast-Server auf 2.2-Kerneln fahren. Dieses
+Problem wurde im 2.4-Kernel behoben. Wenn Sie daher nicht zufrieden mit der
+momentanen Performance Ihres Systems sind, ist es wahrscheinlich einfacher,
+auf 2.4 zu aktualisieren, statt den 2.2-Kernel zu patchen, was zusätzlich
+zur Behebung dieses Fairness-Bugs auch noch Multiprozessor-Systemen einen
+netten Schub gibt.
+
+Wir haben MySQL auf dem 2.4-Kernel auf einer Zweiprozessor-Maschine
+getestet und haben festgestellt, dass MySQL VIEL bessere Leistungsdaten
+bringt - es gab praktisch keine Verlangsamung bei Anfragen bis ganz herauf
+zu 1000 Clients, und der Skalierungsfaktor von MySQL (berechnet als
+Verhältnis von maximalem Durchsatz zum Durchsatz mit 1 Client) war 100%.
+Ähnliches haben wir auf einer Vierprozessor-Maschine beobachtet - praktisch
+keine Verlangsamung, während die Anzahl der Clients bis auf 1000 stieg
+sowie ein Skalierungsfaktor von 300%. Für einen unter Hochlast fahrenden
+Multiprozessor-Server empfehlen wir daher ausdrücklich den 2.4-Kernel.
+Weiter haben wir festgestellt, dass es essentiell wichtig ist, den
+@code{mysqld}-Prozess auf dem 2.4-Kernel mit der höchstmöglichen Priorität
+laufen zu lassen, um maximale Performance zu erreichen. Das kann dadurch
+erreicht werden, dass man den @code{renice -20 $$}-Befehl zu
+@code{safe_mysqld} hinzufügt. Bei unseren Tests auf der
+Vierprozessor-Maschine ergab die Erhöhung der Priorität eine 60%-ige
+Steigerung des Durchsatzes bei 400 Clients.
+
+Wir sind derzeit dabei, mehr Informationen über die Performance von
+@code{MySQL} auf dem 2.4-Kernel auf 4-Weg- und 8-Weg-Systemen zu bekommen.
+Wenn Sie Zugang zu einem solchen System haben und einige Benchmarks gemacht
+haben, schicken Sie bitte eine Mail mit den Ergebnissen an
+@email{docs@@mysql.com} - wir werden Sie dem Handbuch hinzufügen.
+
+Es gibt eine weitere Sache, die die Performance von MySQL stark
+beeinträchtigt, besonders auf SMP-Systemen. Die Implementation von mutex
+in LinuxThreads in @strong{glibc-2.1} ist sehr schlecht für Programme mit
+vielen Threads, die den mutex nur für kurze Zeit behalten. Wenn Sie MySQL
+mit unveränderten @strong{LinuxThreads} linken, führt ironischerweise
+auf einem SMP-System in manchen Fällen das Entfernen von Prozessoren zu
+einer Leistungssteigerung von MySQL. Für @strong{glibc 2.1.3} haben wir ein
+Patch bereit gestellt, um dieses Verhalten zu korrigieren:
+@uref{http://www.mysql.com/downloads/Linux/linuxThreads-2.1-patch,linuxThreads-2.1-patch}
+
+Bei Verwendung von @strong{glibc-2.2.2} benutzt MySQL-Version 3.23.36 den
+adaptiven mutex, der sogar viel besser als der gepatchte von
+@strong{glibc-2.1.3} ist. Seien Sie jedoch davor gewarnt, dass unter
+bestimmten Umständen der aktuelle mutex-Code in @strong{glibc-2.2.2}
+überdrehen kann, was die Performance von MySQL beeinträchtigt. Die Gefahr,
+dass solche Umstände eintreten, kann dadurch verringert werden, dass der
+@code{mysqld}-Prozess auf die höchste Priorität gesetzt wird. Zusätzlich
+konnten wir das Überdrehverhalten mit einem Patch korrigieren, der
+@uref{http://www.mysql.com/downloads/Linux/linuxThreads-2.2.2.patch,hier}
+erhältlich ist. Der Patch kombiniert die Korrektur des Überdrehens, die
+maximale Anzahl von Threads und das Stack-Spacing in einem. Sie wenden es
+auf das @code{linuxThreads}-Verzeichnis mit @code{patch -p0
+</tmp/linuxThreads-2.2.2.patch} an. Wir hoffen, dass der Patch in irgend
+einer Form in zukünftigen Releases von @code{glibc-2.2} enthalten sein
+wird. Wie es auch sei, wenn Sie mit @code{glibc-2.2.2} linken, müssen Sie
+immer noch @code{STACK_SIZE} und @code{PTHREAD_THREADS_MAX} korrigieren.
+Wir hoffen, dass diese Vorgabewerte zukünftig auf akzeptablere Werte für
+eine MySQL-Hochlast-Einrichtung gesetzt werden, so dass Ihr eigener Build
+auf @code{./configure; make; make install} reduziert werden kann.
+
+Wir empfehlen, dass Die die oben genannten Patches benutzen, um eine
+spezielle statische Version von @code{libpThread.a} zu bauen, die Sie nur
+für statisches Linken mit @code{MySQL} benutzen. Wir wissen, dass die
+Patches für @code{MySQL} sicher sind und seine Performance erheblich
+verbessern, aber wir können diesbezüglich nichts über andere Applikationen
+sagen. Wenn Sie andere Applikationen mit der gepatchten Version der
+Bibliothek linken oder eine gepatchte gemeinsam benutzte (shared) Version
+bauen und auf Ihrem System installieren, tun Sie das auf eigenes Risiko,
+was andere Applikationen betrifft, die von @code{LinuxThreads} abhängen.
+
+Wenn Sie während der Installation von MySQL irgend welche seltsamen
+Probleme bekommen oder gebräuchliche Utilities hängen bleiben, ist es sehr
+wahrscheinlich, dass diese entweder Bibliotheks- oder Compiler-bezogen
+sind. In diesem Fall wird die Benutzung unserer Binärdatei sie beheben.
+
+Ein bekanntes Problem der Binärdistribution ist, dass Sie auf älteren
+Linux-Systemen, die @code{libc} benutzen (wie RedHat 4.x oder Slackware)
+nicht-schwere (non-fatal) Probleme mit der Auflösung von Hostnamen
+bekommen.
+@xref{Linux-RPM}.
+
+Wenn Sie LinuxThreads benutzen, werden Sie feststellen, dass mindestens
+drei Prozesse laufen. Das sind in Wirklichkeit Threads. Es gibt einen
+Thread für den LinuxThreads-Manager, einen Thread, um Verbindungen zu
+handhaben und einen Thread, um Alarme und Signale zu handhaben.
+
+Beachten Sie, dass der Linux-Kernel und die LinuxThread-Bibliothek
+vorgabemäßig nur 1024 Threads haben können. Das bedeutet, dass Sie auf
+einem ungepatchten System nur höchstens 1021 Verbindungen zu MySQL haben
+können. Die Seite @uref{http://www.volano.com/linuxnotes.html} enthält
+Informationen, wie man diese Beschränkung umgeht.
+
+Wenn Sie einen toten @code{mysqld}-Daemon-Prozess mit @code{ps} sehen,
+bedeutet das üblicherweise, dass Sie einen Bug in MySQL oder eine zerstörte
+Tabelle gefunden haben. @xref{Crashing}.
+
+Um auf Linux einen Speicherauszug (Core Dump) zu erhalten, wenn
+@code{mysqld} mit einem SIGSEGV-Signal stirbt, können Sie @code{mysqld} mit
+der @code{--core-file}-Option starten. Beachten Sie, dass Sie
+wahrscheinlich @code{core file size} hoch setzen müssen, indem Sie
+@code{ulimit -c 1000000} zu @code{safe_mysqld} hinzufügen oder
+@code{safe_mysqld} mit @code{--core-file-sizes=1000000} starten.
+@xref{safe_mysqld, , @code{safe_mysqld}}.
+
+Wenn Sie Ihren eigenen MySQL-Client linken und bei der Ausführung diesen
+Fehler erhalten,
+
+@example
+ld.so.1: ./my: fatal: libmysqlclient.so.4: open failed: No such file or directory
+@end example
+
+kann das Problem durch eine der folgenden Methoden behoben werden:
+
+@itemize @bullet
+@item
+Linken Sie den Client mit dem folgenden Flag (anstelle von @code{-Lpath}):
+@code{-Wl,r/path-libmysqlclient.so}.
+
+@item
+Kopieren Sie @code{libmysqclient.so} nach @file{/usr/lib}.
+
+@tindex LD_RUN_PATH Umgebungsvariable
+@tindex Umgebungsvariable, LD_RUN_PATH
+@item
+Fügen Sie der @code{LD_RUN_PATH}-Umgebungsvariablen den Pfadnamen des
+Verzeichnisses hinzu, wo @code{libmysqlclient.so} liegt, bevor Sie Ihren
+Client laufen lassen.
+@end itemize
+
+Wenn Sie den Fujitsu-Compiler @code{(fcc / FCC)} benutzen, werden Sie beim
+Kompilieren von MySQL einige Probleme bekommen, weil die
+Linux-Header-Dateien sehr @code{gcc}-orientiert sind.
+
+Folgende @code{configure}-Zeile sollte mit @code{fcc/FCC} funktionieren:
+
+@example
+CC=fcc CFLAGS="-O -K fast -K lib -K omitfp -Kpreex -D_GNU_SOURCE -DCONST=konstante -DNO_STRTOLL_PROTO" CXX=FCC CXXFLAGS="-O -K fast -K lib -K omitfp -K preex --no_exceptions --no_rtti -D_GNU_SOURCE -DCONST=konstante -Dalloca=__builtin_alloca -DNO_STRTOLL_PROTO '-D_EXTERN_INLINE=static __inline'" ./configure --prefix=/usr/local/mysql --enable-assembler --with-mysqld-ldflags=-all-static --disable-shared --with-low-memory
+@end example
+
+@menu
+* Binary notes-Linux::
+* Linux-x86::
+* Linux-SPARC::
+* Linux-Alpha::
+* Linux-PowerPC::
+* Linux-MIPS::
+* Linux-IA64::
+@end menu
+
+@node Binary notes-Linux, Linux-x86, Linux, Linux
+@c German node Linux-Binärdateien
+@subsubsection Anmerkungen zur Binärdistribution (Linux)
+
+@cindex Binärdistributionen, unter Linux
+@cindex Linux, Binärdistribution
+
+MySQL benötigt zumindest Linux-Version 2.0.
+
+@strong{ACHTUNG}:
+Wir haben Berichte von MySQL-Benutzern erhalten, die schwer wiegende
+Stabilitätsprobleme mit Linux-Kernel 2.2.14 mitgeteilt haben. Wenn Sie
+diesen Kernel benutzen, sollten Sie auf 2.2.19 (oder neuer) oder auf einen
+2.4-Kernel aktualisieren. Wenn Sie eine Mehrprozessormaschine haben,
+sollten Sie auf jeden Fall in Betracht ziehen, 2.4 zu benutzen, weil Ihnen
+das erhebliche Geschwindigkeitssteigerung geben wird.
+
+Die Binärdistribution wird mit @code{-static} gelinkt, was normalerweise
+heißt, dass Sie sich nicht um die Version der Systembibliotheken kümmern
+müssen, die Sie haben. Ausserdem brauchen Sie nicht LinuxThread
+installieren. Ein Programm, das mit @code{-static} gelinkt ist, ist etwas
+größer als ein dynamisch gelinktes Programm, und gleichzeitig etwas
+schneller (3-5%). Ein Problem liegt jedoch darin, dass Sie bei einem
+statisch gelinkten Programm keine benutzerdefinierten Funktionen (UDF)
+benutzen können. Wenn Sie UDF-Funktionen schreiben oder benutzen wollen
+(das ist nur etwas für C- oder C++-Programmierer), müssen Sie MySQL selbst
+kompilieren und das dynamische Linken benutzen.
+
+Wenn Sie ein @code{libc}-basierendes System benutzen (statt eines
+@code{glibc2}-Systems), bekommen Sie bei der Binärdistribution
+wahrscheinlich Probleme mit der Auflösung von Hostnamen und mit
+@code{getpwnam()}. (Das liegt daran, dass @code{glibc} leider von einigen
+externen Bibliotheken abhängt, um Hostnamen aufzulösen und und
+@code{getpwent()}, selbst wenn es mit @code{-static} kompiliert wird.) In
+diesem Fall erhalten Sie wahrscheinlich folgende Fehlermeldung, wenn Sie
+@code{mysql_install_db} ausführen:
+
+@example
+Sorry, the host 'xxxx' could not be looked up
+@end example
+
+oder den folgenden Fehler, wenn Sie versuchen, @code{mysqld} mit der
+@code{--user}-Option laufen zu lassen:
+
+@example
+getpwnam: No such file or directory
+@end example
+
+Sie können dieses Problem auf eine der folgenden Weisen lösen:
+
+@itemize @bullet
+@item
+Holen Sie sich eine MySQL-Quelldistribution (eine RPM oder die
+@code{tar.gz}-Distribution) und installieren Sie statt dessen diese.
+@item
+Führen Sie @code{mysql_install_db --force} aus. Das führt nicht den
+@code{resolveip}-Test in @code{mysql_install_db} aus. Der Nachteil ist,
+dass Sie keine Hostnamen in the Berechtigungstabellen benutzen können,
+sondern nur IP-Nummern (ausser für @code{localhost}). Wenn Sie ein altes
+MySQL-Release benutzen, das @code{--force} nicht unterstützt, müssen Sie
+den @code{resolveip}-Test in @code{mysql_install} mit einem Editor
+deaktivieren.
+@item
+Starten Sie @code{mysqld} mit @code{su} anstelle von @code{--user}.
+@end itemize
+
+Die Linux-Intel-Binärdatei und die RPM-Releases von MySQL sind für höchst
+mögliche Geschwindigkeit konfiguriert. Wir versuchen immer, den schnellsten
+stabilen Kompiler zu benutzen, der verfügbar ist.
+
+MySQL-Perl-Unterstützung erfordert Perl-Version 5.004_03 oder neuer.
+
+Auf einigen Linux-2.2-Versionen erhalten Sie womöglich den Fehler
+@code{Resource temporarily unavailable}, wenn Sie eine Menge neuer
+Verbindungen zu einem @code{mysqld}-Server über TCP/IP aufmachen.
+
+Das Problem liegt darin, dass Linux eine Verzögerung zwischen dem
+Schließen eines TCP/IP-Sockets und dem tatsächlichen Freigeben durch das
+System hat. Da es nur Platz für eine bestimmte Anzahl von TCP/IP-Slots
+gibt, bekommen Sie den genannten Fehler, wenn Sie viele neue
+TCP/IP-Verbindungen innerhalb kurzer Zeit aufbauen, zum Beispiel, wenn Sie
+den MySQL-@file{test-connect}-Benchmark über TCP/IP laufen lassen.
+
+Wir haben dieses Problem mehrfach an verschiedene Linux-Mailing-Listen
+geschrieben, konnten aber bislang keine saubere Lösung erhalten.
+
+Die einzige bekannte 'Behebung' des Problems liegt darin, persistente
+Verbindungen bei Ihren Clients zu verwenden oder Sockets zu benutzen, wenn
+Sie den Datenbankserver und die Clients auf derselben Maschine laufen
+lassen. Wir hoffen, dass zukünftig der @code{Linux 2.4}-Kernel dieses
+Problem lösen wird.
+
+
+@node Linux-x86, Linux-SPARC, Binary notes-Linux, Linux
+@c German node Linux-x86
+@subsubsection Anmerkungen zu Linux x86
+
+MySQL erfordert @code{libc}-Version 5.4.12 oder neuer. Bekannt ist, dass
+@code{libc} 5.4.46 funktioniert. @code{glibc}-Version 2.0.6 und später
+sollten ebenfalls funktionieren. Es hat einige Probleme mit den
+@code{glibc}-RPMs von RedHat gegeben. Wenn Sie Probleme haben, prüfen Sie
+daher, ob es Updates gibt! Die @code{glibc}-2.0.7-19- und -2.0.7-29-RPMs
+funktionieren bekanntermaßen ebenfalls.
+
+Bei einigen älteren Linux-Distributionen kann @code{configure} einen Fehler
+wie folgt produzieren:
+
+@example
+Syntaxfehler in sched.h. Ändern Sie _P zu __P in der
+/usr/include/sched.h-Datei. Siehe das Installationskapitel im
+Referenzhandbuch.
+@end example
+
+Machen Sie, was die (englischsprachige) Fehlermeldung sagt. Fügen Sie also
+einen zusätzlichen Unterstrich zum @code{_P}-Makro hinzu, das nur einen
+Unterstrich hat, und versuchen Sie es noch einmal.
+
+Möglicherweise erhalten Sie beim Kompilieren Warnungen. Die folgenden davon
+können ignoriert werden:
+
+@example
+mysqld.cc -o objs-thread/mysqld.o
+mysqld.cc: In function `void init_signals()':
+mysqld.cc:315: warning: assignment of negative value `-1' to `long unsigned int'
+mysqld.cc: In function `void * signal_hand(void *)':
+mysqld.cc:346: warning: assignment of negative value `-1' to `long unsigned int'
+@end example
+
+In Debian-GNU/Linux müssen Sie folgendes tun, damit MySQL beim Hochfahren
+des Systems automatisch startet:
+
+@example
+shell> cp support-files/mysql.server /etc/init.d/mysql.server
+shell> /usr/sbin/update-rc.d mysql.server defaults 99
+@end example
+
+@code{mysql.server} befindet sich im @file{share/mysql}-Verzeichnis
+unterhalb des MySQL-Installationsverzeichnisses oder im
+@file{support-files}-Verzeichnis des MySQL-Source-Trees.
+
+Wenn @code{mysqld} beim Start immer einen Speicherauszug (Core Dump)
+erzeugt, kann das Problem darin liegen, dass Sie eine alte
+@file{/lib/libc.a} haben. Versuchen Sie sie umzubenennen, entfernen Sie
+dann @file{sql/mysqld}, führen Sie ein neues @code{make install} durch und
+versuchen Sie es noch einmal. Dieses Problem wurde von einigen
+Slackware-Installationen berichtet.
+
+Wenn Sie beim Linken von @code{mysqld} folgenden Fehler erhalten, bedeutet
+das, dass Ihre @file{libg++.a} nicht korrekt installiert ist:
+
+@example
+/usr/lib/libc.a(putc.o): In function `_IO_putc':
+putc.o(.text+0x0): multiple definition of `_IO_putc'
+@end example
+
+Sie können vermeiden, dass @file{libg++.a} benutzt wird, indem Sie
+@code{configure} wie folgt ablaufen lassen:
+
+@example
+shell> CXX=gcc ./configure
+@end example
+
+
+@node Linux-SPARC, Linux-Alpha, Linux-x86, Linux
+@c German node Linux-SPARC
+@subsubsection Anmerkungen zu Linux SPARC
+
+Bei einigen Implementationen ist @code{readdir_r()} fehlerhaft. Das äußert
+sich darin, dass @code{SHOW DATABASES} immer einen leeren Satz (Empty Set)
+zurück gibt. Das kann behoben werden, indem @code{HAVE_READDIR_R} aus
+
+
+Einige Probleme erfordern, dass Sie Ihre Linux-Installation patchen. Der
+Patch befindet sich unter
+@uref{http://www.mysql.com/downloads/patches/Linux-sparc-2.0.30.diff}.
+
+Dieser Patch bezieht sich auf Linux-Distribution
+@file{sparclinux-2.0.30.tar.gz}, die auf @code{vger.rutgers.edu} verfügbar
+ist (eine Version von Linux, die nie mit der offiziellen 2.0.30 verbunden
+wurde). Zusätzlich müssen Sie LinuxThreads 0.6 oder neuer installieren.
+
+
+@node Linux-Alpha, Linux-PowerPC, Linux-SPARC, Linux
+@c German node Linux-Alpha
+@subsubsection Anmerkungen zu Linux Alpha
+
+MySQL-Version 3.23.12 ist die erste MySQL-Version, die auf Linux-Alpha
+getestet wurde. Wenn Sie planen, MySQL auf Linux-Alpha einzusetzen, stellen
+Sie sicher, dass Sie diese oder eine neuere Version haben.
+
+Wir haben MySQL auf Alpha mit unseren Benchmarks und unserer Test-Suite
+getestet, und es scheint gut zu funktionieren. Hauptsächlich noch nicht
+getestet haben wird, wie die Dinge mit vielen gleichzeitigen Verbindungen
+funktionieren.
+
+Wir kompilieren die Standard-MySQL-Binärdatei mit SuSE 6.4, Kernel
+2.2.13-SMP, Compaq-C-Kompiler Version 6.2-504 und Compaq-C++-Kompiler
+Version 6.3-005 auf einer Compaq-DS20-Maschine mit einem
+Alpha-EV6-Prozessor.
+
+Sie finden die genannten Kompiler auf
+@uref{http://www.support.compaq.com/alpha-tools}). Durch die Verwendung
+dieser Kompiler anstelle von gcc erhalten wir eine 9% bis 14% bessere
+Performance für MySQL.
+
+Beachten Sie, dass die Konfigurationszeile die Binärversion auf die
+aktuelle CPU optimiert. Das heißt, dass Sie unsere Binärdatei nur benutzen
+können, wenn Sie einen Alpha-EV6-Prozessor haben. Ausserdem haben wir
+statisch kompiliert, um Bibliothek-Probleme zu vermeiden.
+
+@example
+CC=ccc CFLAGS="-fast" CXX=cxx CXXFLAGS="-fast -noexceptions -nortti" ./configure --prefix=/usr/local/mysql --disable-shared --with-extra-charsets=complex --enable-thread-safe-client --with-mysqld-ldflags=-non_shared --with-client-ldflags=-non_shared
+@end example
+
+Bei Benutzung von egcs funktionierte bei uns die folgende
+Konfigurationszeile:
+
+@example
+CFLAGS="-O3 -fomit-frame-pointer" CXX=gcc CXXFLAGS="-O3 -fomit-frame-pointer -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --disable-shared
+@end example
+
+Einige bekannte Probleme, wenn MySQL auf Linux-Alpha läuft:
+
+@itemize @bullet
+@item
+Das Debuggen von threaded Applikationen wie MySQL funktioniert nicht mit
+@code{gdb 4.18}. Statt dessen sollten Sie gdb 5.0 herunter laden und
+benutzen!
+
+@item
+Wenn Sie versuchen, @code{mysqld} unter Benutzung von @code{gcc} statisch
+zu linken, wird das resultierende Image beim Starten einen Speicherauszug
+(Core Dump) erzeugen. Mit anderen Worten: Benutzen Sie @strong{NICHT}
+@code{--with-mysqld-ldflags=-all-static} mit @code{gcc}.
+@end itemize
+
+
+@node Linux-PowerPC, Linux-MIPS, Linux-Alpha, Linux
+@c German node Linux-PowerPC
+@subsubsection Anmerkungen zu Linux PowerPC
+
+MySQL sollte auf MkLinux mit dem neuesten @code{glibc}-Paket funktionieren
+(getestet mit @code{glibc} 2.0.7).
+
+
+@node Linux-MIPS, Linux-IA64, Linux-PowerPC, Linux
+@c German node Linux-MIPS
+@subsubsection Anmerkungen zu Linux MIPS
+
+Um MySQL auf Qube2 zum Laufen zu bringen (Linux Mips), benötigen Sie die
+neuesten @code{glibc}-Bibliotheken (@code{glibc-2.0.7-29C2} funktioniert
+bekanntermaßen). Ausserdem müssen Sie den @code{egcs}-C++-Kompiler
+(@code{egcs-1.0.2-9}, @code{gcc 2.95.2} oder neuer) benutzen.
+
+
+@node Linux-IA64, , Linux-MIPS, Linux
+@c German node Linux-IA64
+@subsubsection Anmerkungen zu Linux IA64
+
+Um MySQL auf Linux Ia64 zu kompilieren, mussten wir folgendes tun (wir
+vermuten, dass das leichter wird, wenn die neue gcc-Version für ia64
+herausgebracht wird).
+
+Unter Verwendung von @code{gcc-2.9-final}:
+
+@example
+CFLAGS="-O2" CXX=gcc CXXFLAGS="-O2 -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --enable-assembler --with-mysqld-ldflags=-all-static --disable-shared --with-extra-charsets=complex
+@end example
+
+Nach @code{make} werden Sie einen Fehler erhalten, dass
+@code{sql/opt_range.cc} nicht kompiliert (interner Kompiler-Fehler). Um das
+zu beheben, gehen Sie ins sql-Verzeichnis und tippen Sie erneut @code{make}
+ein. Kopieren Sie die Kompilierzeile, ändern Sie aber -O2 zu -O0. Die
+Datei sollte nunmehr kompilieren.
+
+Jetzt können Sie folgendes tun:
+
+@example
+cd ..
+make
+make_install
+@end example
+
+und @code{mysqld} sollte lauffähig sein.
+
+Auf Ia64 benutzen die MySQL-Client-Binärdateien gemeinsam genutzte (shared)
+Bibliotheken. Wenn Sie daher unsere Binärdistribution an anderer Stelle als
+@file{/usr/local/mysql} benutzen, müssen Sie entweder
+@file{/etc/ld.so.conf} ändern oder den Pfad zum Verzeichnis hinzufügen, wo
+Sie @file{libmysqlclient.so} haben, und zwar in der
+@code{LD_LIBRARY_PATH}-Umgebungsvariablen.
+
+@xref{Link errors}.
+
+@node Windows, Solaris, Linux, Operating System Specific Notes
+@c German node Windows
+@subsection Anmerkungen zu Windows
+
+Dieser Abschnitt beschreibt Installation und Benutzung von MySQL auf
+Windows. Diese Information steht zusätzlich in der @file{README}-Datei, die
+mit der MySQL-Windows-Distribution mitgeliefert wird.
+
+
+
+@menu
+* Win95 start::
+* NT start::
+* Windows running::
+* Windows and SSH::
+* Windows symbolic links::
+* Windows client compiling::
+* Windows vs Unix::
+@end menu
+
+@node Win95 start, NT start, Windows, Windows
+@c German node Win95-Start
+@subsubsection Wie man MySQL auf Win95 / Win98 startet
+
+MySQL benutzt TCP/IP, um einen Client mit einem Server zu verbinden. (Das
+erlaubt jeder beliebigen Maschine in Ihrem Netzwerk, sich mit Ihrem
+MySQL-Server zu verbinden.) Aus diesem Grund müssen Sie MySQL auf Ihrer
+Maschine installieren, bevor Sie MySQL starten. Sie finden TCP/IP auf Ihrer
+Windows-CD-ROM.
+
+Beachten Sie, dass Sie bei Verwendung eines alten Win95-Releases (zum
+Beispiel OSR2) wahrscheinlich ist, dass Sie ein altes Winsock-Paket haben!
+MySQL erfordert Winsock 2! Sie erhalten das neueste Winsock von
+@uref{http://www.microsoft.com/}. Win98 enthält die neue
+Winsock-2-Bibliothek, deshalb trifft das Gesagte nicht auf Win98 zu.
+
+Um den @code{mysqld}-Server zu starten, öffnen Sie ein MS-DOS-Fenster
+(MS-DOS-Eingabeaufforderung) und geben Sie ein:
+
+@example
+C:\> C:\mysql\bin\mysqld
+@end example
+
+Das startet @code{mysqld} im Hintergrund ohne Fenster.
+
+Sie können den MySQL-Server killen, indem Sie eingeben:
+
+@example
+C:\> C:\mysql\bin\mysqladmin -u root shutdown
+@end example
+
+Beachten Sie, dass Win95 und Win98 die Erzeugung von Named Pipes nicht
+unterstützen. Auf Win95 und Win98 können Sie Named Pipes nur benutzen, um
+sich zu einem entfernten MySQL-Server zu verbinden, der auf einem
+NT-Server-Host läuft. (Natürlich muss auch der MySQL-Server Named Pipes
+unterstützen. Beispielsweise läßt die Verwendung von @code{mysqld-opt}
+unter NT keine Named-Pipe-Verbindungen zu. Sie sollten daher entweder
+@code{mysqld-nt} oder @code{mysqld-max-nt} verwenden.)
+
+Wenn @code{mysqld} nicht startet, überprüfen Sie bitte die
+@file{\mysql\data\mysql.err}-Datei um zu sehen, ob der Server eine Meldung
+ausgegeben hat, die auf die Ursache des Problems hinweist. Sie können auch
+versuchen, den Server mit @code{mysqld --standalone} zu starten. In diesem
+Fall erscheinen vielleicht nützliche Informationen auf dem Bildschirm, die
+Ihnen bei der Lösung des Problems helfen.
+
+Die letzte Option besteht darin, @code{mysqld} mit @code{--standalone
+--debug} zu starten. In diesem Fall schreibt @code{mysqld} eine Log-Datei
+@file{C:\mysqld.trace}, die die Ursache enthalten könnte, warum
+@code{mysqld} nicht startet. @xref{Making trace files}.
+
+
+@node NT start, Windows running, Win95 start, Windows
+@c German node NT-Start
+@subsubsection MySQL auf Windows NT oder Windows 2000 starten
+
+Der Win95-/Win98-Abschnitt trifft auch auf NT/Win2000 zu, mit folgenden
+Unterschieden:
+
+Damit MySQL mit TCP/IP auf NT läuft, müssen Sie Service-Pack 3 (oder neuer)
+installieren!
+
+Beachten Sie, dass alles Folgende, das für NT zutrifft, ebenfalls für
+Win2000 zutrifft!
+
+Für NT/Win2000 ist der Servername @code{mysqld-nt}. Normalerweise sollten
+Sie MySQL auf NT/Win2000 als Systemdienst installieren:
+
+@example
+C:\> C:\mysql\bin\mysqld-nt --install
+@end example
+
+oder
+
+@example
+C:\> C:\mysql\bin\mysqld-max-nt --install
+@end example
+
+(Unter Windows NT können Sie in der Tat jede der Server-Binärdateien als
+Systemdienst installieren, aber nur diejenigen, die Namen haben, die auf
+@code{-nt.exe} enden, bieten Unterstützung für Named Pipes.)
+
+Sie können MySQL mit diesen Befehlen starten und anhalten:
+
+@example
+C:\> NET START mysql
+C:\> NET STOP mysql
+@end example
+
+Beachten Sie, dass Sie in diesem Fall keine weiteren Optionen für
+@code{mysqld-nt} angeben können!
+
+Sie können @code{mysqld-nt} auf NT auch als allein ablaufendes Programm
+(Stand-alone) laufen lassen, wenn Sie @code{mysqld-nt} mit irgend welchen
+Optionen starten wollen! Wenn Sie @code{mysqld-nt} auf NT ohne Optionen
+laufen lassen, versucht @code{mysqld-nt}, sich mit den Vorgabeoptionen als
+Systemdienst zu starten. Wenn Sie @code{mysqld-nt} angehalten haben, müssen
+Sie es mit @code{NET START mysql} neu starten.
+
+Der Systemdienst wird installiert mit dem Namen @code{MySQL}. Einmal
+installiert, muss er mit dem Systemdienst-Steuerungs-Manager (SCM) in der
+Systemsteuerung gestartet werden, oder indem Sie den @code{NET START
+MySQL}-Befehl benutzen. Wenn irgend welche Optionen angegeben werden
+sollen, müssen diese als ``Startparameter'' im SCM-Dienstprogramm angegeben
+werden, bevor Sie den MySQL-Dienst starten. Wenn @code{mysqld-nt} läuft,
+kann er mit @code{mysqladmin} oder dem SCM-Dienstprogramm angehalten werden, oder
+indem Sie den Befehl @code{NET STOP MySQL} benutzen. Wenn Sie SCM benutzen
+@code{mysqld-nt}, um den Server anzuhalten, gibt es eine seltsame Meldung
+von SCM über @code{mysqld shutdown normally}. Wenn er als Systemdienst
+läuft, hat @code{mysqld-nt} keinen Zugriff auf die Konsole. Daher werden
+auch keine Meldungen angezeigt.
+
+Auf NT erhalten Sie möglicherweise folgende Systemdienst-Fehlermeldungen:
+@c Question: Die folgenden deutschen Meldungen auf NT überprüfen!
+@multitable @columnfractions .3 .7
+@item Zugriff verboten @tab Bedeutung: @code{mysqld-nt.exe} kann nicht
+gefunden werden.
+@item Kann nicht registrieren @tab Bedeutung: Der Pfad ist falsch.
+@item Installation des Systemdienstes fehlgeschlagen. @tab Bedeutung: Der
+Systemdienst ist bereits installiert oder der
+Systemdienst-Steuerungs-Manager ist in einem schlechten Zustand.
+@end multitable
+
+Wenn Sie Problem haben, @code{mysqld-nt} als Systemdienst zu installieren,
+versuchen Sie, ihn mit dem vollen Pfad zu installieren:
+
+@example
+C:\> C:\mysql\bin\mysqld-nt --install
+@end example
+
+Wenn das nicht funktioniert, können Sie erreichen, dass @code{mysqld-nt}
+korrekt startet, indem Sie den Pfad in der Registrierung korrigieren!
+
+Wenn Sie nicht wollen, dass @code{mysqld-nt} als Systemdienst startet,
+können Sie ihn wie folgt starten:
+
+@example
+C:\> C:\mysql\bin\mysqld-nt --standalone
+@end example
+
+oder
+
+@example
+C:\> C:\mysql\bin\mysqld --standalone --debug
+@end example
+
+Letztgenanntes gibt Ihnen eine Debug-Spur in @file{C:\mysqld.trace}.
+@xref{Making trace files}.
+
+
+@node Windows running, Windows and SSH, NT start, Windows
+@c German node Laufen lassen auf Windows
+@subsubsection MySQL auf Windows laufen lassen
+
+@cindex TCP/IP
+@cindex Named Pipes
+
+MySQL unterstützt TCP/IP auf allen Windows-Plattformen und Named Pipes auf
+NT. Vorgabemäßig werden Named Pipes für lokale Verbindungen auf NT und TCP/IP für
+alle anderen Fälle benutzt, wenn der Client TCP/IP installiert hat. Der
+Hostname legt fest, welches Protokoll benutzt wird:
+
+@multitable @columnfractions .3 .7
+@strong{Hostname} @tab @strong{Protokoll}
+@item NULL (keiner) @tab Auf NT zuerst Named Pipes versuchen. Wenn das
+nicht funktioniert, TCP/IP benutzen. Auf Win95/Win98 wird TCP/IP benutzt.
+@item . @tab Named Pipes
+@item localhost @tab TCP/IP zum aktuellen Host
+@item hostname @tab TCP/IP
+@end multitable
+
+Sie können erzwingen, dass ein MySQL-Client Named Pipes benutzt, indem Sie
+die @code{--pipe}-Option oder @code{.} als Hostnamen angeben. Benutzen Sie
+die @code{--socket}-Option, um den Namen der Pipe festzulegen.
+
+Sie können feststellen, ob MySQL funktioniert, indem Sie die folgenden
+Befehle eingeben:
+
+@example
+C:\> C:\mysql\bin\mysqlshow
+C:\> C:\mysql\bin\mysqlshow -u root mysql
+C:\> C:\mysql\bin\mysqladmin version status proc
+C:\> C:\mysql\bin\mysql test
+@end example
+
+Wenn @code{mysqld} nur langsam auf Verbindungen auf Win95/Win98 antwortet,
+gibt es wahrscheinlich ein Problem mit Ihrem DNS. Starten Sie in diesem
+Fall @code{mysqld} mit @code{--skip-name-resolve} und benutzen Sie nur
+@code{localhost} und IP-Nummern in den MySQL Berechtigungstabellen. Sie
+können DNS bei einer Verbindung zu einem @code{mysqld-nt}-MySQL-Server, der
+auf NT läuft, ebenfalls dadurch vermeiden, dass Sie das
+@code{--pipe}-Argument verwenden, um die Benutzung von Named Pipes
+festzulegen. Das funktioniert bei den meisten MySQL-Clients.
+
+Es gibt zwei Versionen des MySQL-Kommadozeilen-Werkzeugs:
+@multitable @columnfractions .25 .75
+@item @code{mysql} @tab Kompiliert auf nativem Windows, was sehr
+eingeschränkte Texteditiermöglichkeiten bietet.
+@item @code{mysqlc} @tab Kompiliert mit dem Cygnus-GNU-Kompiler und
+-Bibliotheken, was @code{readline}-Editiermöglichkeit bietet.
+@end multitable
+
+Wenn Sie @code{mysqlc.exe} benutzen wollen, müssen Sie
+@file{C:\mysql\lib\cygwinb19.dll} in Ihr Windows-Systemverzeichnis kopieren
+(@file{\windows\system} oder ein ähnlicher Ort).
+
+Vorgabemäßig geben die Berechtigungen auf Windows allen lokalen Benutzern
+volle Zugriffsrechte auf alle Datenbanken, ohne ein Passwort anzugeben. Um
+MySQL sicherer zu machen, sollten Sie für alle Benutzer ein Passwort setzen
+und die Zeile in der Tabelle @code{mysql.user}, die @code{Host='localhost'}
+und @code{User=''} enthält, löschen.
+
+Sie sollten auch für den @code{root}-Benutzer ein Passwort vergeben. Das
+folgende Beispiel entfernt den anonymen Benutzer, der von jedem genutzt
+werden kann, um auf die @code{test}-Datenbank zuzugreifen und setzt dann
+für den @code{root}-Benutzer ein Passwort:
+
+@example
+C:\> C:\mysql\bin\mysql mysql
+mysql> DELETE FROM user WHERE Host='localhost' AND User='';
+mysql> QUIT
+C:\> C:\mysql\bin\mysqladmin reload
+C:\> C:\mysql\bin\mysqladmin -u root password ihr_passwort
+@end example
+
+Nachdem Sie das Passwort gesetzt haben, sollten Sie den
+@code{mysqld}-Server herunter fahren, was Sie mit folgendem Befehl
+bewerkstelligen können:
+
+@example
+C:\> mysqladmin --user=root --password=ihr_passwort shutdown
+@end example
+
+Wenn Sie die alte Shareware-Version von MySQL-Version 3.21 unter Windows
+benutzen, schlägt der genannte Befehl mit einem Fehler fehl:
+@code{parse error near 'SET OPTION password'}. Die Lösung besteht darin,
+auf die aktuelle MySQL-Version zu aktualisieren, die frei verfügbar ist.
+
+Mit den neuen MySQL-Versionen können Sie auf einfache Art neue Benutzer
+hinzufügen und Zugriffsrechte mit den @code{GRANT}- und
+@code{REVOKE}-Befehlen ändern.
+@xref{GRANT}.
+
+@node Windows and SSH, Windows symbolic links, Windows running, Windows
+@c German node Windows und SSH
+@subsubsection Verbinden mit einem entfernten MySQL-Server von Windows mit SSH aus
+
+@c FIX this ist ugly, real ugly.
+
+@cindex SSH
+@cindex Verbinden, auf entfernte Maschine mit SSH
+
+Hier ist eine Anmerkung dazu, wie man sich über eine sichere Verbindung zu
+einem entfernten MySQL-Server mit SSH verbindet (von David Carlson
+@email{dcarlson@@mplcomm.com}):
+
+@itemize @bullet
+@item
+Installieren Sie einen SSH-Client auf Ihrer Windows-Maschine. Das beste
+nicht kostenlose Werkzeug, das ich gefunden habe, ist @code{SecureCRT} von
+@uref{http://www.vundyke.com/}. Eine andere Option ist @code{f-secure} von
+@uref{http://www.f-secure.com/}. Sie finden kostenlose Werkzeuge über
+@strong{Google} auf
+@uref{http://directory.google.com/Top/Computers/Security/Products_and_Tools/Cryptography/SSH/Clients/Windows/}.
+
+@item
+Starten Sie Ihren Windows-SSH-Client.
+Konfigurieren Sie: @code{Host_Name = ihr_mysql_server_URL_oder_IP}.
+Konfigurieren Sie: @code{userid=ihre_userid}, um sich an Ihrem Server
+anzumelden (wahrscheinlich nicht dasselbe wie Ihr MySQL-Benutzername /
+-Passwort).
+
+@item
+Konfigurieren Sie Port-Forwarding. Machen Sie entweder ein Remote Forward
+(einstellen: @code{local_port: 3306}, @code{remote_host:
+ihr_mysql_servername_oder_ip}, @code{remote_port: 3306} ) oder ein lokales
+Forward (einstellen: @code{port: 3306}, @code{host: localhost},
+@code{remote port: 3306}).
+
+@item
+Speichern Sie alles, damit Sie es beim nächsten Mal nicht noch einmal
+eingeben müssen.
+
+@item
+Melden Sie sich an Ihrem Server mit der SSH-Sitzung, die Sie gerade erzeugt
+haben.
+
+@item
+Starten Sie auf Ihrer Windows-Maschine irgend eine Applikation wie Access.
+
+@item
+Erzeugen Sie unter Windows eine neue Datei und stellen Sie eine Verknüpfung
+zu MySQL her, indem Sie den ODBC-Treiber so benutzen, wie Sie es
+normalerweise tun, AUSSER dass Sie @code{localhost} als MySQL-Host-Server
+eingeben - NICHT @code{yourmysqlservername}.
+@end itemize
+
+Jetzt sollten Sie eine ODBC-Verbindung zu MySQL haben, die mit SSH
+verschlüsselt ist.
+
+
+@node Windows symbolic links, Windows client compiling, Windows and SSH, Windows
+@c German node Symbolische Links auf Windows
+@subsubsection Daten auf verschiedenen Platten unter Win32 aufteilen
+
+@cindex Symbolische Links
+@cindex Mehrere Festplatten benutzen, um Daten zu speichern
+@c Question: using multiple disks to start data (should be: store data)
+@cindex Festplatten, Daten verteilen über mehrere
+
+Ab MySQL-Version 3.23.16 werden die @code{mysqld-max}- und
+@code{mysql-max-nt}-Server in der MySQL-Distribution mit der
+@code{-DUSE_SYMDIR}-Option kompiliert. Das gibt Ihnen die Möglichkeit,
+Datenbanken auf verschiedene Festplatten zu verteilen, indem Sie
+symbolische Links darauf machen (in ähnlicher Weise, wie symbolische Links
+unter Unix funktionieren).
+
+Unter Windows legen Sie einen symbolischen Link auf eine Datenbank an,
+indem Sie eine Datei erzeugen, die den Pfad zum Zielverzeichnis enthält,
+und diese Datei im @file{mysql_data}-Verzeichnis unter dem Dateiname
+@file{Datenbank.sym} speichern. Beachten Sie, dass der symbolische Link nur
+dann benutzt wird, wenn das Verzeichnis @file{mysql_data_dir\datenbank}
+nicht existiert.
+
+Wenn Ihr MySQL-Daten-Verzeichnis beispielsweise @file{C:\mysql\data} ist und
+Sie die Datenbank @code{foo} dort haben wollen, die aber in
+@file{D:\data\foo} liegt, erzeugen Sie die Datei
+@file{C:\mysql\data\foo.sym}, die als Text @code{D:\data\foo\} enthält.
+Dann werden alle Tabellen, die in der Datenbank @code{foo} sind, in
+@file{D:\data\foo} erzeugt.
+
+Beachten Sie, dass wir dieses Feature nicht vorgabemäßig aktiviert haben,
+weil es mit Geschwindigkeitsnachteilen verbunden ist. Es ist selbst dann
+nicht aktiviert, wenn Sie MySQL mit Unterstützung dafür kompiliert haben.
+Um symbolische Links zu aktivieren, müssen Sie in Ihre @code{my.cnf}- oder
+@code{my.ini}-Datei folgenden Eintrag machen:
+
+@example
+[mysqld]
+use-symbolic-links
+@end example
+
+In MySQL 4.0 werden symbolische Links vorgabemäßig aktiviert sein. Wenn
+Sie dies deaktivieren wollen, benutzen Sie die @code{skip-symlink}-Option.
+
+
+@node Windows client compiling, Windows vs Unix, Windows symbolic links, Windows
+@c German node Windows kompilieren
+@subsubsection MySQL-Clients auf Windows kompilieren
+
+@cindex Kompilieren, auf Windows
+@cindex Windows, Kompilieren auf
+
+In Ihren Quell-Dateien sollten Sie @file{windows.h} einschließen, bevor
+Sie @file{mysql.h} einschließen:
+
+@example
+#if defined(_WIN32) || defined(_WIN64)
+#include <windows.h>
+#endif
+#include <mysql.h>
+@end example
+
+Sie können Ihren Code entweder mit der dynamischen
+@file{libmysql.lib}-Bibliothek linken, die nur ein Wrapper zum Laden der
+@file{libmysql.dll} bei Bedarf ist, oder mit der statischen
+@file{mysqlclient.lib}-Bibliothek.
+
+Beachten Sie, dass MySQL-Client-Bibliotheken als threaded Bibliotheken
+kompiliert werden, daher sollten Sie auch Ihren Code so kompilieren, dass
+er multi-threaded ist!
+
+
+@node Windows vs Unix, , Windows client compiling, Windows
+@c German node Windows / Unix
+@subsubsection MySQL-Windows im Vergleich zu Unix-MySQL
+
+@cindex Windows, im Vergleich zu Unix
+@cindex Betriebssysteme, Windows im Vergleich zu Unix
+
+MySQL-Windows hat sich mittlerweile als sehr stabil erwiesen. Diese Version
+von MySQL hat dieselben Features wie die entsprechende Unix-Version,
+allerdings mit folgenden Ausnahmen:
+
+@table @strong
+@item Windows 95 und Threads
+Windows 95 hat ein etwa 200 Bytes großes Hauptspeicher-Leck (Memory Leak) für
+jede Thread-Erzeugung. Jede Verbindung zu MySQL erzeugt eine neues Thread,
+daher sollten Sie @code{mysqld} nicht für längere Zeiträume auf Windows 95
+laufen lassen, wenn Ihr Server viele Verbindungen handhabt! Windows NT und
+Windows 98 haben diesen Bug nicht.
+
+@item Gleichzeitige Lesezugriffe
+MySQL vertraut auf @code{pread()}- und @code{pwrite()}-Aufrufe, um in der
+Lage zu sein, @code{INSERT} und @code{SELECT} zu mischen. Momentan benutzen
+wir mutexes, um @code{pread()} / @code{pwrite()} zu emulieren. Langfristig
+werden wir die Dateiebenen-Schnittstelle durch eine virtuelle Schnittstelle
+ersetzen, um die @code{readfile()}- / @code{writefile()}-Schnittstelle auf
+NT mit höherer Geschwindigkeit benutzen zu können.
+Die aktuelle Implementation begrenzt die Anzahl offener Dateien, die MySQL
+benutzen kann, auf 1024, was bedeutet, dass Sie nicht so viele
+gleichzeitige Threads auf NT benutzen können wie auf Unix.
+
+@item Blockierendes Lesen
+MySQL benutzt blockierendes Lesen (Blocking Read) für jede Verbindung. Das
+bedeutet in der Anwendung:
+
+@itemize @bullet
+@item
+Eine Verbindung wird nicht automatisch nach 8 Stunden abgebaut, wie es
+unter der Unix-Version von MySQL der Fall ist.
+
+@item
+Wenn eine Verbindung hängen bleibt, ist es unmöglich, sie abzubrechen, ohne
+MySQL zu killen.
+
+@item
+@code{mysqladmin kill} funktioniert nicht für schlafende Verbindungen.
+
+@item
+@code{mysqladmin shutdown} kann nicht abgebrochen werden, solange es noch
+schlafende Verbindungen gibt.
+@end itemize
+
+Geplant ist, dieses Problem zu beheben, sobald unsere Windows-Entwickler
+ein nettes Workaround heraus gefunden haben.
+
+@item UDF-Funktionen
+Momentan unterstützt MySQL-Windows keine benutzerdefinierten Funktionen
+(UDF, user defined functions).
+
+@item @code{DROP DATABASE}
+Sie können keine Datenbank löschen, die durch irgend einen Thread in
+Benutzung ist.
+
+@item MySQL vom Task-Manager aus killen
+Sie können MySQL nicht vom Task-Manager oder mit dem Shutdown-Dienstprogramm unter
+Windows 95 killen. Sie müssen es mit @code{mysqladmin shutdown} herunter
+fahren.
+
+@item Von Groß-/Kleinschreibung unabhängige Namen
+Unter Windows sind Dateinamen unabhängig von der Groß-/Kleinschreibung.
+Daher sind Datenbank- und Tabellennamen in MySQL für Windows ebenfalls
+unabhängig von der Groß-/Kleinschreibung. Die einzige Einschränkung ist
+die, dass Datenbank- und Tabellennamen innerhalb eines bestimmten
+Statements dieselbe Groß-/Kleinschreibung haben müssen.
+@xref{Case sensitivity}.
+
+@item Das @samp{\}-Verzeichnis-Zeichen
+Bestandteile von Pfadnamen werden unter Windows mit dem @samp{\}-Zeichen
+getrennt, das in MySQL als Fluchtzeichen (Escape Character) dient. Wenn Sie
+@code{LOAD DATA INFILE} oder @code{SELECT ... INTO OUTFILE} benutzen,
+müssen Sie @samp{\} an solchen Stellen doppelt eingeben:
+
+@example
+mysql> LOAD DATA INFILE "C:\\tmp\\skr.txt" INTO TABLE skr;
+mysql> SELECT * INTO OUTFILE 'C:\\tmp\\skr.txt' FROM skr;
+@end example
+
+Alternativ können Sie auch Dateinamen im Unix-Stil mit @samp{/}-Zeichen
+benutzen:
+
+@example
+mysql> LOAD DATA INFILE "C:/tmp/skr.txt" INTO TABLE skr;
+mysql> SELECT * INTO OUTFILE 'C:/tmp/skr.txt' FROM skr;
+@end example
+
+@item @code{Can't open named pipe}-Fehler
+Wenn Sie MySQL-Version 3.22 auf NT mit den neuesten MySQL-Clients benutzen,
+erhalten Sie folgende Fehlermeldung:
+
+@example
+error 2017: can't open named pipe to host: . pipe...
+@end example
+
+@tindex .my.cnf Datei
+Das liegt daran, dass die MySQL-Version für NT auf NT vorgabemäßig Named
+Pipes benutzt. Sie können diesen Fehler vermeiden, indem Sie bei den neuen
+MySQL-Clients die @code{--host=localhost}-Option benutzen oder eine
+Optionsdatei @file{C:\my.cnf} anlegen, die folgendes enthält:
+
+@example
+[client]
+host = localhost
+@end example
+
+@item @code{Access denied for user}-Fehler
+Wenn Sie den Fehler @code{Access denied for user: 'ein-benutzer@@unknown'
+to database 'mysql'} erhalten, wenn Sie auf einen MySQL-Server auf
+derselben Maschine zugreifen, heißt das, dass MySQL Ihren Hostnamen nicht
+richtig auflösen kann.
+
+Um das zu beheben, legen Sie eine Datei @file{\windows\hosts} mit folgender
+Zeile an:
+
+@example
+127.0.0.1 localhost
+@end example
+
+@item @code{ALTER TABLE}
+Wenn Sie ein @code{ALTER TABLE}-Statement ausführen, ist die Tabelle gegen
+Benutzung durch andere Threads gesperrt. Das hat damit zu tun, dass Sie
+unter Windows keine Datei löschen können, die durch andere Threads in
+Benutzung ist. (Zukünftig finden wir möglicherweise einen Weg, dieses
+Problem zu umgehen.)
+
+@item @code{DROP TABLE} auf eine Tabelle, die durch eine
+@code{MERGE}-Tabelle in Benutzung ist, funktioniert nicht. Der
+@code{MERGE}-Handler führt sein Tabellen-Mapping versteckt vor MySQL durch.
+Weil Windows das Löschen von Dateien verbietet, die offen sind, müssen Sie
+zuerst alle @code{MERGE}-Tabellen flushen (mit @code{FLUSH TABLES}) oder
+die @code{MERGE}-Tabelle löschen, bevor Sie die Tabelle löschen. Wir werden
+das zusammen mit der Einführung von Sichten (@code{VIEW}s) beheben.
+@end table
+
+Hier sind einige Themen für diejenigen, die uns beim Windows-Release helfen
+wollen:
+
+@cindex Windows, offene Fragen
+
+@itemize @bullet
+@item
+Einen Ein-Benutzer-Server @code{MYSQL.DLL} herstellen. Das könnte alles
+beinhalten, was einen Standard-Server ausmacht, ausser Thread-Erzeugung.
+Das würde es erheblich erleichtern, MySQL in Applikationen zu benutzen, die
+keinen echten Client/Server und keinen Zugriff auf den Server von anderen
+Hosts benötigen.
+
+@item
+Ein paar nette Start- und Stop-Icons zur MySQL-Installation hinzufügen.
+
+@item
+Ein Werkzeug bauen, das Registrierungseinträge für die MySQL-Startoptionen
+handhabt. Das Lesen der Registrierungseinträge ist bereits in
+@file{mysqld.cc} kodiert, sollte aber umgeschrieben werden, damit es mehr
+Parameter-orientiert ist. Das Werkzeug sollte auch in der Lage sein, die
+@file{C:\my.cnf}-Optionsdatei zu aktualisieren, wenn der Benutzer diese
+lieber als die Registrierungsdatei benutzen will.
+
+@item
+Wenn man @code{mysqld} als Systemdienst mit @code{--install} (auf NT)
+installiert, wäre es nett, wenn man vorgabemäßige Optionen auf der
+Kommandozeile hinzufügen könnte. Im Moment muss man diese fehlende
+Möglichkeit durch eine Liste der Parameter in der @file{C:\my.cnf}-Datei
+ersetzen.
+
+@item
+Es wäre eine feine Sache, wenn man @code{mysqld} vom Task-Manager aus
+killen könnte. Momentan muss man @code{mysqladmin shutdown} benutzen.
+
+@item
+@code{readline} auf Windows portieren, damit es im
+@code{mysql}-Kommandozeilen-Werkzeug benutzt werden kann.
+
+@item
+GUI-Versionen der Standard-MySQL-Clients (@code{mysql},
+@code{mysqlshow}, @code{mysqladmin} und @code{mysqldump}) wären nett.
+
+@item
+Nett wäre auch, wenn die Socket-Lese- und Schreib-Funktionen in
+@file{net.c} unterbrechbar wären. Das würde es ermöglichen, offen Threads
+mit @code{mysqladmin kill} auf Windows zu killen.
+
+@item
+@c Question: Is it my lack of English or why don't I understand the
+following two lines?
+@code{mysqld} always starts in the "C" locale und not in the default locale.
+We would like to have @code{mysqld} use the current locale für the sort order.
+
+@item
+Benutzerdefinierte Funktionen (UDF) mit @code{.DLL}s implementieren.
+
+@item
+Makros hinzufügen, um die schnelleren, Thread-sicheren
+Inkrementierungs-/Dekrementierungsmethoden nutzen zu können, die Windows
+bietet.
+
+@end itemize
+
+Weitere Windows-spezifische Themen sind in der @file{README}-Datei
+beschrieben, die mit der MySQL-Windows-Distribution ausgeliefert wird.
+
+
+@node Solaris, BSD Notes, Windows, Operating System Specific Notes
+@c German node Solaris
+@subsection Anmerkungen zu Solaris
+
+@cindex Installationsprobleme auf Solaris
+@cindex Probleme, Installation auf Solaris
+@cindex Tar, Probleme auf Solaris
+@cindex Fehler, Verzeichnisprüfsumme
+@cindex Prüfsummenfehler
+
+Auf Solaris bekommen Sie vielleicht schon Probleme, bevor Sie überhaupt
+Ihre MySQL-Distribution entpackt haben! Solaris-@code{tar} kann nicht mit
+langen Dateinamen umgehen. Daher sehen Sie vielleicht einen Fehler wie den
+folgenden, wenn Sie MySQL entpacken:
+
+@example
+x mysql-3.22.12-beta/bench/Results/ATIS-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase, 0 Bytes, 0 tape blocks
+tar: directory checksum error (Verzeichnis-Prüfsummenfehler)
+@end example
+
+In diesem Fall müssen Sie GNU-@code{tar} (@code{gtar}) benutzen, um die
+Distribution zu entpacken. Sie finden eine vorkompilierte Version für
+Solaris auf @uref{http://www.mysql.com/downloads/}.
+
+Native Sun-Threads funktinieren nur auf Solaris 2.5 und höher. Auf 2.4 und
+früher benutzt MySQL automatisch MIT-pThreads.
+@xref{MIT-pthreads}.
+
+Vielleicht erhalten Sie von configure folgenden Fehler:
+
+@example
+checking for restartable system calls... configure: error can not run test
+programs while cross compiling
+@end example
+
+Das bedeutet, dass mit Ihrer Kompiler-Installation etwas nicht stimmt! In
+diesem Fall sollten Sie Ihren Kompiler auf eine neuere Version
+aktualisieren. Eventuell sind Sie in der Lage, das Problem zu lösen, indem
+Sie folgende Zeile in die @file{config.cache}-Datei einfügen:
+
+@example
+ac_cv_sys_restartable_syscalls=$@{ac_cv_sys_restartable_syscalls='no'@}
+@end example
+
+Wenn Sie Solaris auf einer SPARC benutzen, ist der empfohlene Kompiler
+@code{gcc} 2.95.2. Sie finden ihn auf @uref{http://gcc.gnu.org/}.
+Beachten Sie, dass @code{egcs} 1.1.1 und @code{gcc} 2.8.1 auf SPARC nicht
+zuverlässig laufen!
+
+Die empfohlene @code{configure}-Zeile ist bei der Benutzung von @code{gcc}
+2.95.2:
+
+@example
+CC=gcc CFLAGS="-O3" \
+CXX=gcc CXXFLAGS="-O3 -felide-constructors -fno-exceptions -fno-rtti" \
+./configure --prefix=/usr/local/mysql --with-low-memory --enable-assembler
+@end example
+
+Wenn Sie eine Ultra-Sparc haben, erhalten Sie 4 % mehr Performance, wenn
+Sie "-mcpu=v8 -Wa,-xarch=v8plusa" zu CFLAGS und CXXFLAGS hinzufügen.
+
+Wenn Sie einen Sun Workshop (Fortre) 5.3 (oder neueren) Kompiler haben,
+können Sie @code{configure} wie folgt laufen lassen:
+
+@example
+CC=cc CFLAGS="-Xa -fast -xO4 -native -xstrconst -mt" \
+CXX=CC CXXFLAGS="-noex -xO4 -mt" \
+./configure --prefix=/usr/local/mysql --enable-assembler
+@end example
+
+In den MySQL-Benchmarks haben wir auf einer Ultra-Sparc 6%
+Geschwindigkeitssteigerung erreicht, wenn wir Sun Workshop 5.3 benutzen, im
+Vergleich mit der Benutzung von gcc mit -mcpu-Flags.
+
+Wenn Sie Probleme mit @code{fdatasync} oder @code{sched_yield} bekommen,
+können Sie diese beheben, indem Sie @code{LIBS=-lrt} zur
+Konfigurationszeile hinzufügen.
+
+Der folgende Absatz ist nur für ältere Kompiler als WorkShop 5.3 relevant:
+
+Eventuell müssen Sie auch das @code{configure}-Skript editieren und
+folgende Zeile ändern:
+
+@example
+#if !defined(__STDC__) || __STDC__ != 1
+@end example
+
+Ändern zu:
+
+@example
+#if !defined(__STDC__)
+@end example
+
+Wenn Sie @code{__STDC__} mit der @code{-Xc}-Option anschalten, kann der
+Sun-Kompiler nicht mit der Solaris-@file{pThread.h}-Header-Datei
+kompilieren. Das ist ein Bug von Sun (Kompiler-Problem oder beschädigte
+Include-Datei).
+
+Wenn @code{mysqld} beim Laufenlassen eine Fehlermeldung wie die unten
+stehende ausgibt, haben Sie versucht, MySQL mit dem Sun-Kompiler zu
+kompilieren, ohne die Multi-Thread-Option (@code{-mt}) anzuschalten:
+
+@example
+libc internal error: _rmutex_unlock: rmutex not held
+@end example
+
+Fügen Sie @code{-mt} zu @code{CFLAGS} und @code{CXXFLAGS} hinzu und
+versuchen Sie es noch einmal.
+
+Wenn Sie folgenden Fehler beim Kompilieren von MySQL mit @code{gcc}
+erhalten, ist Ihr @code{gcc} nicht für Ihre Version von Solaris
+konfiguriert:
+
+@example
+shell> gcc -O3 -g -O2 -DDBUG_OFF -o thr_alarm ...
+./thr_alarm.c: In function `signal_hand':
+./thr_alarm.c:556: too many arguments to function `sigwait'
+@end example
+
+Die einzige richtige Möglichkeit in diesem Fall ist, sich die neueste
+Version von @code{gcc} zu besorgen und Sie mit Ihrem aktuellen
+@code{gcc}-Kompiler zu kompilieren. Zumindest auf Solaris 2.5 haben fast
+alle Binärversionen von @code{gcc} alte, unbrauchbare Include-Dateien, die
+alle Programme beschädigen, die Threads benutzen (und möglicherweise auch
+andere Programme)!
+
+Solaris stellt keine statischen Versionen aller Systembibliotheken zur
+Verfügung (@code{libpThreads} und @code{libdl}). Daher können Sie MySQL
+nicht mit @code{--static} kompilieren. Wenn Sie es dennoch versuchen,
+erhalten Sie folgenden Fehler:
+
+@example
+ld: fatal: library -ldl: not found
+
+oder
+
+undefined reference to `dlopen'
+
+oder
+
+cannot find -lrt
+@end example
+
+Wenn zu viele Prozesse zu schnell hintereinander versuchen, sich mit
+@code{mysqld} zu verbinden, werden Sie folgenden Fehler im MySQL-Log sehen:
+
+@example
+Error in accept: Protocol error
+@end example
+
+Als Workaround können Sie versuchen, den Server mit der
+@code{--set-variable back_log=50}-Option zu starten. @xref{Command-line options}.
+
+Wenn Sie Ihren eigenen MySQL-Client linken, erhalten Sie möglicherweise
+folgenden Fehler, wenn Sie versuchen, ihn auszuführen:
+
+@example
+ld.so.1: ./my: fatal: libmysqlclient.so.#: open failed: No such file or directory
+@end example
+
+Dieses Problem kann mit einer der folgenden Methoden vermieden werden:
+
+@itemize @bullet
+@item
+Linken Sie den Client mit folgendem Flag (anstelle von @code{-Lpath}):
+@code{-Wl,r/full-path-to-libmysqlclient.so}.
+
+@item
+Kopieren Sie @file{libmysqclient.so} nach @file{/usr/lib}.
+
+@tindex LD_RUN_PATH-Umgebungsvariable
+@tindex Umgebungsvariable, LD_RUN_PATH
+@item
+Fügen Sie den Pfadnamen des Verzeichnisses, wo @file{libmysqlclient.so}
+liegt, der @code{LD_RUN_PATH}-Umgebungsvariablen hinzu, bevor Sie Ihren
+Client laufen lassen.
+@end itemize
+
+Wenn Sie die @code{--with-libwrap}-configure-Option benutzen, müssen Sie
+auch die Bibliotheken einschließen, die @file{libwrap.a} benötigt:
+
+@example
+--with-libwrap="/opt/NUtcpwrapper-7.6/lib/libwrap.a -lnsl -lsocket
+@end example
+
+Wenn Sie Probleme mit configure haben, wenn Sie versuchen, mit @code{-lz}
+zu linken und keine @code{zlib} installiert haben, haben Sie zwei
+Möglichkeiten:
+
+@itemize @bullet
+@item
+Wenn Sie in der Lage sein wollen, dass komprimierte Kommunikationsprotokoll
+zu benutzen, müssen Sie zlib von ftp.gnu.org laden und installieren.
+
+@item
+Konfigurieren Sie mit @code{--with-named-z-libs=no}.
+@end itemize
+
+Wenn Sie gcc benutzen und Probleme mit dem Laden von @code{UDF}-Funktionen
+in MySQL haben, versuchen Sie, @code{-lgcc} zur Link-Zeile für die
+@code{UDF}-Funktion hinzuzufügen.
+
+Wenn Sie wollen, dass MySQL automatisch startet, kopieren Sie
+@file{Support-files/mysql.server} nach @file{/etc/init.d} und erzeugen Sie
+einen symbolischen Link darauf, den Sie @file{/etc/rc3.d/S99mysql.server}
+nennen.
+
+
+
+
+@menu
+* Solaris 2.7::
+* Solaris x86::
+@end menu
+
+@node Solaris 2.7, Solaris x86, Solaris, Solaris
+@c German node Solaris 2.7
+@subsubsection Anmerkungen zu Solaris 2.7/2.8
+
+Normalerweise können Sie eine Solaris-2.6-Binärdatei für Solaris 2.7 und
+2.8 benutzen. Die meisten Dinge, die Solaris 2.6 betreffen, treffen auch
+für Solaris 2.7 und 2.8 zu.
+
+Beachten Sie, dass MySQL-Version 3.23.4 und höher in der Lage sein sollte,
+automatisch neue Versionen von Solaris zu erkennen und Workarounds für die
+folgenden Probleme zu aktivieren!
+
+Solaris 2.7 / 2.8 hat einige Bugs in den Include-Dateien. Eventuell sehen
+Sie folgenden Fehler, wenn Sie @code{gcc} benutzen:
+
+@example
+/usr/include/widec.h:42: warning: `getwc' redefined
+/usr/include/wchar.h:326: warning: this is the location of the previous
+definition
+@end example
+
+Wenn das auftritt, können Sie folgendes tun, um das Problem zu lösen:
+
+Kopieren Sie @code{/usr/include/widec.h} nach
+@code{.../lib/gcc-lib/os/gcc-version/include} und ändern Sie Zeile 41 von:
+
+@example
+#if !defined(lint) && !defined(__lint)
+
+nach
+
+#if !defined(lint) && !defined(__lint) && !defined(getwc)
+@end example
+
+Alternativ können Sie @file{/usr/include/widec.h} direkt editieren. Egal,
+wie Sie vorgehen: Nachdem Sie die Fehlerbehebung durchgeführt haben,
+sollten Sie @file{config.cache} entfernen und @code{configure} noch einmal
+laufen lassen!
+
+Wenn Sie beim Laufenlassen von @code{make} folgende Fehler bekommen, liegt
+das daran, dass @code{configure} die @file{curses.h}-Datei nicht erkannte
+(vermutlich aufgrund des Fehlers in @file{/usr/include/widec.h}):
+
+@example
+In file included by mysql.cc:50:
+/usr/include/term.h:1060: syntax error before `,'
+/usr/include/term.h:1081: syntax error before `;'
+@end example
+
+Das Problem lösen Sie auf eine der folgenden Weisen:
+
+@itemize @bullet
+@item
+Konfigurieren Sie mit @code{CFLAGS=-DHAVE_CURSES_H CXXFLAGS=-DHAVE_CURSES_H ./configure}.
+
+@item
+Editieren Sie @file{/usr/include/widec.h}, wie weiter oben gezeigt, und
+lassen Sie configure noch einmal laufen.
+
+@item
+Entfernen Sie die @code{#define HAVE_TERM}-Zeile aus der
+@file{config.h}-Datei und lassen Sie @code{make} noch einmal laufen.
+@end itemize
+
+Wenn Sie das Problem bekommen, dass Ihr Linker @code{-lz} nicht finden
+kann, wenn Sie Ihr Client-Programm linken, liegt das wahrscheinlich daran,
+dass Ihre @file{libz.so}-Datei in @file{/usr/local/lib} installiert ist.
+Sie können das mit einer der folgenden Methoden beheben:
+
+@itemize @bullet
+@item
+Fügen Sie @file{/usr/local/lib} zu @code{LD_LIBRARY_PATH} hinzu.
+
+@item
+Fügen Sie einen Link auf @file{libz.so} von @file{/lib} hinzu.
+
+@item
+Wenn Sie Solaris 8 benutzen, können Sie die optionale zlib aus Ihrer
+Solaris-8-CD-Distribution installieren.
+
+@item
+Konfigurieren Sie MySQL mit der @code{--with-named-z-libs=no}-Option.
+@end itemize
+
+
+@node Solaris x86, , Solaris 2.7, Solaris
+@c German node Solaris x86
+@subsubsection Anmerkungen zu Solaris x86
+
+Auf Solaris 2.8 auf x86 erzeugt @code{mysqld} einen Speicherauszug (Core
+Dump), wenn Sie darin 'strip' laufen lassen.
+
+Wenn Sie @code{gcc} oder @code{egcs} auf Solaris x86 benutzen und Probleme
+mit Speicherauszügen (Core Dumps) unter Last erleben, sollten Sie folgenden
+@code{configure}-Befehl benutzen:
+
+@example
+CC=gcc CFLAGS="-O3 -fomit-frame-pointer -DHAVE_CURSES_H" \
+CXX=gcc \
+CXXFLAGS="-O3 -fomit-frame-pointer -felide-constructors -fno-exceptions -fno-rtti -DHAVE_CURSES_H" \
+./configure --prefix=/usr/local/mysql
+@end example
+
+Das vermeidet Probleme mit der @code{libstdc++}-Bibliothek und mit
+C++-Ausnahmefehlern.
+
+Wenn das nicht hilft, sollten Sie eine Debug-Version kompilieren und sie
+mit einer Trace-Datei oder unter @code{gdb} laufen lassen. @xref{Using gdb on mysqld}.
+
+
+@node BSD Notes, Mac OS X, Solaris, Operating System Specific Notes
+@c German node BSD
+@subsection Anmerkungen zu BSD
+
+
+
+@menu
+* FreeBSD::
+* NetBSD::
+* OpenBSD::
+* OpenBSD 2.5::
+* OpenBSD 2.8::
+* BSDI::
+* BSDI2::
+* BSDI3::
+* BSDI4::
+@end menu
+
+@node FreeBSD, NetBSD, BSD Notes, BSD Notes
+@c German node FreeBSD
+@subsubsection Anmerkungen zu FreeBSD
+
+FreeBSD 3.x wird für MySQL empfohlen, weil das Thread-Paket sehr viel
+integrierter ist.
+
+Die einfachste und daher empfohlene Art der Installation ist die Benutzung
+der mysql-server- und mysql-client-Ports, die auf
+@uref{http://www.freebsd.org} verfügbar sind.
+
+Durch deren Benutzung erhalten Sie:
+@itemize @bullet
+@item
+Ein funktionierendes MySQL mit allen Optimierungen bereits aktiviert, von
+denen bekannt ist, dass Sie auf Ihrer Version von FreeBSD funktionieren.
+
+@item
+Automatische Konfiguration, automatisches Build.
+
+@item
+Start-Skripte, die in /usr/local/etc/rc.d installiert werden.
+
+@item
+Die Möglichkeit festzustellen, welche Dateien installiert sind, mit
+pkg_info -L. Und die Möglichkeit, sie mit pkg_delete zu entfernen, wenn Sie
+MySQL nicht mehr auf dieser Maschine haben wollen.
+@end itemize
+
+Empfohlen wird die Benutzung von MIT-pThreads auf FreeBSD 2.x und von
+nativen Threads auf Version 3 und höher. Es ist möglich, auf einigen späten
+2.2.x-Versionen mit nativen Threads zu arbeiten, aber Sie können beim
+Herunterfahren von @code{mysqld} Probleme bekommen.
+
+Die MySQL-@file{Makefile}-Dateien erfordern GNU-make (@code{gmake}). Wenn
+Sie MySQL kompilieren wollen, müssen Sie zuerst GNU-@code{make}
+installieren.
+
+Stellen Sie sicher, dass Ihr Namensauflöser (Name Resolver) korrekt
+eingerichtet ist. Ansonsten erleben Sie vielleicht Resolver-Verzögerungen
+oder -Fehler, wenn Sie sich mit @code{mysqld} verbinden.
+
+Stellen Sie sicher, dass der @code{localhost}-Eintrag in der
+@file{/etc/hosts}-Datei stimmt. Ansonsten werden Sie Probleme haben, sich
+mit der Datenbank zu verbinden. Die @file{/etc/hosts}-Datei sollte mit
+folgender Zeile beginnen:
+
+@example
+127.0.0.1 localhost localhost.ihre.domain
+@end example
+
+Wenn Sie bemerken, dass @code{configure} MIT-pThreads benutzen wird, lesen
+Sie die Anmerkungen zu MIT-pThreads. @xref{MIT-pthreads}.
+
+Wenn @code{make install} meldet, dass es @file{/usr/include/pThreads} nicht
+finden kann, hat @code{configure} nicht entdeckt, dass Sie MIT-pThreads
+benötigen. Das kann durch die Ausführung folgender Befehle behoben werden:
+
+@example
+shell> rm config.cache
+shell> ./configure --with-mit-threads
+@end example
+
+FreeBSD ist dafür bekannt, dass es vorgabemäßig einen sehr niedrigen Wert
+für Datei-Handles eingestellt hat. @xref{Not enough file handles}.
+Kommentieren Sie den Abschnitt ulimit -n section in safe_mysqld aus oder
+erhöhen Sie die Werte für den @code{mysqld}-Benutzer in /etc/login.conf
+(und bauen Sie es neu mit cap_mkdb /etc/login.conf). Stellen Sie ausserdem
+sicher, dass Sie die korrekte Klasse für diesen Benutzer in der
+Passwort-Datei einstellen, wenn Sie nicht den Vorgabewert benutzen
+(benutzen Sie chpass mysqld-user-name). @xref{safe_mysqld,
+,@code{safe_mysqld}}.
+
+Wenn Sie Probleme mit dem aktuellen Datum in MySQL erhalten, wird das
+Setzen der @code{TZ}-Variablen das wahrscheinlich beheben.
+@xref{Environment variables}.
+
+Um ein sicheres, stabiles System zu erhalten, sollten Sie ausschließlich
+FreeBSD-Kernels benutzen, die als @code{-STABLE} markiert sind.
+
+
+@node NetBSD, OpenBSD, FreeBSD, BSD Notes
+@c German node NetBSD
+@subsubsection Anmerkungen zu NetBSD
+
+Um auf NetBSD zu kompilieren, benötigen Sie GNU @code{make}. Ansonsten wird
+das Kompilieren abstürzen, wenn @code{make} versucht, @code{lint} auf
+C++Dateien laufen zu lassen.
+
+
+@node OpenBSD, OpenBSD 2.5, NetBSD, BSD Notes
+@c German node OpenBSD
+@subsubsection Anmerkungen zu OpenBSD
+
+
+
+@node OpenBSD 2.5, OpenBSD 2.8, OpenBSD, BSD Notes
+@c German node <no English equivalent>
+@subsubsection Anmerkungen zu OpenBSD 2.5
+
+Auf OpenBSD-Version 2.5 können Sie MySQL mit nativen Threads mit folgenden
+Optionen kompilieren:
+
+@example
+CFLAGS=-pThread CXXFLAGS=-pThread ./configure --with-mit-threads=no
+@end example
+
+
+@node OpenBSD 2.8, BSDI, OpenBSD 2.5, BSD Notes
+@c German node OpenBSD 2.8
+@subsubsection Anmerkungen zu OpenBSD 2.8
+
+Unsere Benutzer haben berichtet, dass OpenBSD 2.8 einen Thread-Bug hat, der
+Probleme mit MySQL verursacht. Die OpenBSD-Entwickler haben das Problem
+behoben, aber seit dem 25. Januar 2001 ist es nur im ``-current''-Zweig
+verfügbar. Die Symptome dieses Thread-Bugs sind langsames Antworten, hohe
+Lase, hohe Prozessorauslastung und Abstürze.
+
+
+@node BSDI, BSDI2, OpenBSD 2.8, BSD Notes
+@c German node BSDI
+@subsubsection Anmerkungen zu BSD/OS
+
+
+
+@node BSDI2, BSDI3, BSDI, BSD Notes
+@c German node <no English equivalent>
+@subsubsection Anmerkungen zu BSD/OS Version 2.x
+
+Wenn Sie folgenden Fehler beim Kompilieren von MySQL erhalten, ist Ihr
+@code{ulimit}-Wert für virtuellen Speicher zu niedrig:
+
+@example
+item_func.h: In method `Item_func_ge::Item_func_ge(const Item_func_ge &)':
+item_func.h:28: virtual memory exhausted
+make[2]: *** [item_func.o] Error 1
+@end example
+
+Versuchen Sie, @code{ulimit -v 80000} zu benutzen, und lassen Sie
+@code{make} erneut laufen. Wenn das nicht funktioniert und Sie @code{bash}
+benutzen, versuchen Sie, statt dessen @code{csh} oder @code{sh} zu
+benutzen. Einige BSDI-Benutzer haben Probleme mit @code{bash} und
+@code{ulimit} berichtet.
+
+Wenn Sie @code{gcc} benutzen, müssen Sie eventuell auch den
+@code{--with-low-memory}-Flag für @code{configure} benutzen, um in der Lage
+zu sein, @file{sql_yacc.cc} zu kompilieren.
+
+Wenn Sie Probleme mit dem aktuellen Datum in MySQL erhalten, wird das
+Setzen der @code{TZ}-Variablen das wahrscheinlich beheben.
+@xref{Environment variables}.
+
+@node BSDI3, BSDI4, BSDI2, BSD Notes
+@c German node BSDI3
+@subsubsection Anmerkungen zu BSD/OS Version 3.x
+
+Aktualisieren Sie auf BSD/OS Version 3.1. Wenn das nicht möglich ist,
+installieren Sie BSDI-Patch M300-038.
+
+Benutzen Sie zur Konfiguration von MySQL folgenden Befehl:
+
+@example
+shell> env CXX=shlicc++ CC=shlicc2 \
+ ./configure \
+ --prefix=/usr/local/mysql \
+ --localstatedir=/var/mysql \
+ --without-perl \
+ --with-unix-socket-path=/var/mysql/mysql.sock
+@end example
+
+Folgendes funktioniert bekanntermaßen ebenfalls:
+
+@example
+shell> env CC=gcc CXX=gcc CXXFLAGS=-O3 \
+ ./configure \
+ --prefix=/usr/local/mysql \
+ --with-unix-socket-path=/var/mysql/mysql.sock
+@end example
+
+Wenn Sie wollen, können Sie die Verzeichnisorte ändern oder aber die
+Vorgabewerte benutzen, indem Sie einfach keine Speicherorte angeben.
+
+Wenn Sie Performance-Probleme unter Hochlast bekommen, versuchen Sie die
+@code{--skip-thread-priority}-Option für @code{mysqld}! Dies führt alle
+Threads mit derselben Priorität aus. Auf BSDI-Version 3.1 gibt Ihnen das
+bessere Performance (zumindest solange, bis BSDI ihren Thread-Scheduler in
+Ordnung bringt).
+
+Wenn Sie beim Kompilieren den Fehler @code{virtual memory exhausted}
+erhalten, probieren Sie es mit @code{ulimit -v 80000} und lassen Sie
+@code{make} noch einmal laufen. Wenn das nicht funktioniert und Sie
+@code{bash} benutzen, versuchen Sie, statt dessen @code{csh} oder @code{sh}
+zu benutzen. Einige BSDI-Benutzer haben Probleme mit @code{bash} und
+@code{ulimit} berichtet.
+
+
+@node BSDI4, , BSDI3, BSD Notes
+@c German node BSDI4
+@subsubsection Anmerkungen zu BSD/OS Version 4.x
+
+BSDI-Version 4.x hat einige auf Threads bezogene Bugs. Wenn Sie auf dieser
+Plattform MySQL benutzen wollen, sollten Sie alle Patches installieren, die
+sich auf Threads beziehen. Zumindest M400-023 sollte installiert sein.
+
+Auf einigen Systemen mit BSDI-Version 4.x bekommen Sie vielleicht Probleme
+mit gemeinsam verwendeten (shared) Bibliotheken. Das äußert sich darin,
+dass Sie keinerlei Client-Programme wie @code{mysqladmin} ausführen können.
+In diesem Fall müssen Sie MySQL so rekonfigurieren, dass keine gemeinsam
+genutzten Bibliotheken benutzt werden, indem Sie die
+@code{--disable-shared}-Option für configure benutzen.
+
+Einige Kunden hatten auf BSDI 4.0.1 Probleme damit, dass die
+@code{mysqld}-Binärdatei nach einiger Zeit keine Tabellen mehr öffnen
+konnte. Das liegt an einigen Bugs, die sich auf Bibliothek / System
+beziehen, und die @code{mysqld} veranlassen, das aktuelle Verzeichnis zu
+wechseln, ohne danach gefragt zu haben!
+
+Die Lösung besteht darin, entweder auf 3.23.34 zu aktualisieren oder nach
+dem Laufenlassen von @code{configure} die Zeile @code{#define
+HAVE_REALPATH} aus @code{config.h} zu entfernen, bevor Sie make laufen
+lassen.
+
+Beachten Sie, dass sich aus dem Gesagten ergibt, dass Sie auf BSDI keine
+symbolischen Links von Datenbankverzeichnissen zu einem anderen
+Datenbankverzeichnis oder symbolische Links von einer Tabelle zu einer
+anderen Datenbank herstellen können! (Ein symbolischer Link auf eine andere
+Platte ist okay.)
+
+
+@node Mac OS X, Other Unix Notes, BSD Notes, Operating System Specific Notes
+@c German node Mac OS X
+@subsection Anmerkungen zu Mac OS X
+
+
+
+@menu
+* Mac OS X Public Beta::
+* Mac OS X Server::
+@end menu
+
+@node Mac OS X Public Beta, Mac OS X Server, Mac OS X, Mac OS X
+@c German node Mac OS X Public Beta
+@subsubsection Mac OS X Public Beta
+
+MySQL sollte ohne jedes Problem auf Mac OS X Public Beta (Darwin) laufen.
+Die pThread-Patches für dieses Betriebssystem benötigen Sie nicht!
+
+
+@node Mac OS X Server, , Mac OS X Public Beta, Mac OS X
+@c German node Mac OS X Server
+@subsubsection Mac OS X Server
+
+Bevor Sie versuchen, MySQL auf Mac OS X Server zu konfigurieren, müssen Sie
+das pThread-Paket von @uref{http://www.prnet.de/RegEx/mysql.html}
+installieren.
+
+Unsere Binärdatei für Mac OS X wird kompiliert auf Rhapsody 5.5, mit
+folgender Konfigurationszeile:
+
+@example
+CC=gcc CFLAGS="-O2 -fomit-frame-pointer" CXX=gcc CXXFLAGS="-O2 -fomit-frame-pointer" ./configure --prefix=/usr/local/mysql "--with-comment=Official MySQL binary" --with-extra-charsets=complex --disable-shared
+@end example
+
+Wenn Sie der Ressourcen-Datei Ihrer Shell Aliase hinzufügen wollen, um auf
+@code{mysql} und @code{mysqladmin} von der Kommandozeile aus zuzugreifen,
+geben Sie ein:
+
+@example
+alias mysql '/usr/local/mysql/bin/mysql'
+alias mysqladmin '/usr/local/mysql/bin/mysqladmin'
+@end example
+
+
+@node Other Unix Notes, OS/2, Mac OS X, Operating System Specific Notes
+@c German node Andere Unixe
+@subsection Anmerkungen zu anderen Unixen
+
+
+
+@menu
+* Binary notes-HP-UX::
+* HP-UX 10.20::
+* HP-UX 11.x::
+* IBM-AIX::
+* SunOS::
+* Alpha-DEC-UNIX::
+* Alpha-DEC-OSF1::
+* SGI-Irix::
+* SCO::
+* SCO Unixware::
+@end menu
+
+@node Binary notes-HP-UX, HP-UX 10.20, Other Unix Notes, Other Unix Notes
+@c German node Binary notes-HP-UX
+@subsubsection Anmerkungen zu HP-UX Notes für Binärdistributionen
+
+@cindex HP-UX, Binärdistribution
+@cindex Binärdistributionen, auf HP-UX
+
+Einige Binärdistributionen von MySQL für HP-UX werden als HP-Depot-Datei
+und als Tar-Datei ausgeliefert. Um die Depot-Datei benutzen zu können,
+müssen Sie mindestens HP-UX 10.x haben, um auf HP's Software-Depot-Werkzeuge
+zugreifen zu können.
+
+Die HP-Version von MySQL wurde auf einem HP 9000/8xx-Server unter HP-UX
+10.20 kompiliert und benutzt MIT-pThreads. Unter dieser Konfiguration
+arbeitet sie bekanntermaßen gut. MySQL-Version 3.22.26 und neuer kann auch
+mit HP's nativem Thread-Paket gebaut werden.
+
+Weitere Konfigurationen, die ebenfalls funktionieren können:
+
+@itemize @bullet
+@item
+HP 9000/7xx mit HP-UX 10.20+
+@item
+HP 9000/8xx mit HP-UX 10.30
+@end itemize
+
+Folgende Konfigurationen werden fast mit Sicherheit nicht laufen:
+
+@itemize @bullet
+@item
+HP 9000/7xx oder 8xx mit HP-UX 10.x, wobei x < 2
+@item
+HP 9000/7xx oder 8xx mit HP-UX 9.x
+@end itemize
+
+Um die Distribution zu installieren, benutzen Sie die unten stehenden
+Befehle, wobei @code{/pfad/zum/depot} der volle Pfadname der Depot-Datei
+ist:
+
+@itemize @bullet
+@item
+Um alles inklusive Server, Client- und Entwicklungs-Werkzeuge zu installieren:
+
+@example
+shell> /usr/sbin/swinstall -s /pfad/zum/depot mysql.full
+@end example
+
+@item
+Um nur den Server zu installieren:
+
+@example
+shell> /usr/sbin/swinstall -s /pfad/zum/depot mysql.server
+@end example
+
+@item
+Um nur das Client-Paket zu installieren:
+
+@example
+shell> /usr/sbin/swinstall -s /pfad/zum/depot mysql.client
+@end example
+
+@item
+Um nur die Entwicklungs-Werkzeuge zu installieren:
+
+@example
+shell> /usr/sbin/swinstall -s /pfad/zum/depot mysql.developer
+@end example
+@end itemize
+
+Das Depot speichert Binärdateien und Bibliotheken in @file{/opt/mysql} und
+Daten in @file{/var/opt/mysql}. Es legt auch die entsprechenden Einträge in
+@file{/etc/init.d} und @file{/etc/rc2.d} an, um den Server automatisch beim
+Hochfahren zu starten. Das setzt @code{root}-Rechte zum Installieren
+voraus.
+
+Um die HP-UX-tar.gz-Distribution zu installieren, müssen Sie GNU @code{tar}
+haben.
+
+
+@node HP-UX 10.20, HP-UX 11.x, Binary notes-HP-UX, Other Unix Notes
+@c German node HP-UX 10.20
+@subsubsection Anmerkungen zu HP-UX Version 10.20
+
+Es gibt einige kleine Probleme, wenn Sie MySQL auf HP-UX kompilieren. Wir
+empfehlen, anstelle des nativen HP-UX-Kompilers @code{gcc} zu benutzen,
+weil @code{gcc} besseren Code produziert!
+
+Wir empfehlen die Benutzung von gcc 2.95 auf HP-UX. Benutzen Sie keine
+hohen Optimierungs-Flags (wie -O6), weil das eventuell für HP-UX nicht
+sicher ist.
+
+Beachten Sie, dass MIT-pThreads nicht mit dem HP-UX-Kompiler kompiliert
+werden können, weil dieser keine @code{.S}-(Assembler)-Dateien kompilieren
+kann.
+
+Folgende Konfigurationszeile sollte funktionieren:
+
+@example
+CFLAGS="-DHPUX -I/opt/dce/include" CXXFLAGS="-DHPUX -I/opt/dce/include -felide-constructors -fno-exceptions -fno-rtti" CXX=gcc ./configure --with-pThread --with-named-Thread-libs='-ldce' --prefix=/usr/local/mysql --disable-shared
+@end example
+
+Wenn Sie @code{gcc} 2.95 selbst kompilieren, sollten Sie ihn NICHT mit den
+DCE-Bibliotheken (@code{libdce.a} oder @code{libcma.a}) linken, wenn Sie
+MySQL mit MIT-pThreads kompilieren wollen. Wenn Sie DCE- und
+MIT-pThreads-Pakete mischen, erhalten Sie einen @code{mysqld}, mit dem Sie
+sich nicht verbinden können. Entfernen Sie die DCE-Bibliotheken, während
+Sie @code{gcc} 2.95 kompilieren!
+
+
+@node HP-UX 11.x, IBM-AIX, HP-UX 10.20, Other Unix Notes
+@c German node HP-UX 11.x
+@subsubsection Anmerkungen zu HP-UX Version 11.x
+
+Für HP-UX Version 11.x empfehlen wir MySQL-Version 3.23.15 oder später.
+
+Wegen einiger kritischer Bugs in den Standard-HP-UX-Bibliotheken sollten
+Sie folgende Patches installieren, bevor Sie MySQL auf HP-UX 11.0 laufen
+lassen:
+
+@example
+PHKL_22840 Streams cumulative
+PHNE_22397 ARPA cumulative
+@end example
+
+Das löst das Problem, dass man @code{EWOULDBLOCK} von @code{recv()}
+und @code{EBADF} von @code{accept()} in threaded Applikationen erhält.
+
+Wenn Sie @code{gcc} 2.95.1 auf einem nicht-gepatchten HP-UX-11.x-System
+benutzen, erhalten Sie den Fehler:
+
+@example
+In file included by /usr/include/unistd.h:11,
+ by ../include/global.h:125,
+ by mysql_priv.h:15,
+ by item.cc:19:
+/usr/include/sys/unistd.h:184: declaration of C function ...
+/usr/include/sys/pThread.h:440: previous declaration ...
+In file included by item.h:306,
+ by mysql_priv.h:158,
+ by item.cc:19:
+@end example
+
+Das Problem liegt darin, dass HP-UX @code{pThreads_atfork()} nicht
+konsistent definiert. Es hat konfliktbehaftete Prototypes in
+@file{/usr/include/sys/unistd.h}:184 und
+@file{/usr/include/sys/pThread.h}:440 (Details weiter unten).
+
+Eine Lösung besteht darin, @file{/usr/include/sys/unistd.h} nach
+@file{mysql/include} zu kopieren und @file{unistd.h} zu editieren, wobei es
+so abgeändert wird, dass es der Definition in @file{pThread.h} entspricht.
+Hier ist der Diff:
+
+@example
+183,184c183,184
+< extern int pThread_atfork(void (*prepare)(), void (*parent)(),
+< void (*child)());
+---
+> extern int pThread_atfork(void (*prepare)(void), void (*parent)(void),
+> void (*child)(void));
+@end example
+
+Danach sollte folgende Konfigurationszeile funktionieren:
+
+@example
+CFLAGS="-fomit-frame-pointer -O3 -fpic" CXX=gcc CXXFLAGS="-felide-constructors -fno-exceptions -fno-rtti -O3" ./configure --prefix=/usr/local/mysql --disable-shared
+@end example
+
+Hier sind ein paar Informationen über das Kompilieren von MySQL mit dem
+HP-UX:x-Kompiler, die uns ein Benutzer der HP-UX-Version 11.x geschickt
+hat:
+
+@example
+ Environment:
+ proper compilers.
+ setenv CC cc
+ setenv CXX aCC
+ flags
+ setenv CFLAGS -D_REENTRANT
+ setenv CXXFLAGS -D_REENTRANT
+ setenv CPPFLAGS -D_REENTRANT
+ % aCC -V
+ aCC: HP ANSI C++ B3910B X.03.14.06
+ % cc -V /tmp/empty.c
+ cpp.ansi: HP92453-01 A.11.02.00 HP C Preprocessor (ANSI)
+ ccom: HP92453-01 A.11.01.00 HP C Compiler
+ cc: "/tmp/empty.c", line 1: warning 501: Empty source file.
+
+ configuration:
+ ./configure --with-pThread \
+ --prefix=/source-control/mysql \
+ --with-named-Thread-libs=-lpThread \
+ --with-low-memory
+
+ added '#define _CTYPE_INCLUDED' to include/m_ctype.h. This
+ symbol ist the one defined in HP's /usr/include/ctype.h:
+
+ /* Don't include std ctype.h when this is included */
+ #define _CTYPE_H
+ #define __CTYPE_INCLUDED
+ #define _CTYPE_INCLUDED
+ #define _CTYPE_USING /* Don't put names in global namespace. */
+@end example
+
+@itemize @bullet
+@item
+Ich muss den Compile-Time-Flag @code{-D_REENTRANT} benutzen, um den
+Kompiler dazu zu bringen, den Prototype für @code{localtime_r} zu erkennen.
+Alternativ hätte ich auch den Prototype für @code{localtime_r} bereit
+stellen können. Aber ich wollte weitere Bugs abfangen, in die ich sonst
+gerannt wäre. Ich war nicht sicher, wo ich es benötigen würde, daher fügte
+ich es zu allen Flags hinzu.
+@item
+Die Optimierungs-Flags, die MySQL benutzt (-O3), werden von den
+HP-Kompilern nicht erkannt. Ich habe die Flags nicht geändert.
+@end itemize
+
+Wenn Sie folgenden Fehler von @code{configure} erhalten:
+
+@example
+checking for cc option to accept ANSI C... no
+configure: error: MySQL requires a ANSI C compiler (and a C++ compiler). Try gcc. See the installation chapter in the reference manual.
+@end example
+
+Überprüfen Sie, dass Sie den Pfad zum K&R-Kompiler nicht vor dem Pfad zum
+HP-UX-C- und C++-Kompiler haben.
+
+
+@node IBM-AIX, SunOS, HP-UX 11.x, Other Unix Notes
+@c German node IBM-AIX
+@subsubsection Anmerkungen zu IBM-AIX
+
+@cindex Probleme, Installation auf IBM-AIX
+
+Automatische Erkennung von @code{xlC} fehlt bei Autoconf, daher wird ein
+@code{configure}-Befehl wie folgender benötigt, wenn Sie MySQL kompilieren
+(dieses Beispiel benutzt den IBM-Kompiler):
+
+@example
+export CC="xlc_r -ma -O3 -qstrict -qoptimize=3 -qmaxmem=8192 "
+export CXX="xlC_r -ma -O3 -qstrict -qoptimize=3 -qmaxmem=8192"
+export CFLAGS="-I /usr/local/include"
+export LDLFAGS="-L /usr/local/lib"
+export CPPFLAGS=$CFLAGS
+export CXXFLAGS=$CFLAGS
+
+./configure --prefix=/usr/local \
+ --localstatedir=/var/mysql \
+ --sysconfdir=/etc/mysql \
+ --sbindir='/usr/local/bin' \
+ --libexecdir='/usr/local/bin' \
+ --enable-thread-safe-client \
+ --enable-large-files
+@end example
+
+Das sind die Optionen, die benutzt werden, um die MySQL-Distribution zu
+kompilieren, die sich auf @uref{http://www-frec.bull.com/} befindet.
+
+Wenn Sie in obiger Konfigurationszeile @code{-O3} zu @code{-O2} ändern,
+müssen Sie auch die @code{-qstrict}-Option entfernen (das ist eine
+Beschränkung im IBM-C-Kompiler).
+
+Wenn Sie @code{gcc} oder @code{egcs} benutzen, um MySQL zu kompilieren,
+@strong{MÜSSEN} Sie den @code{-fno-exceptions}-Flag benutzen, weil das
+Exception-Handling in @code{gcc} / @code{egcs} nicht Thread-sicher ist!
+(Das wurde mit @code{egcs} 1.1. getestet.) Es gibt auch ein paar bekannte
+Probleme mit dem IBM-Assembler, die dazu führen können, dass schlechter
+Code erzeugt wird, wenn er zusammen mit gcc benutzt wird.
+
+Wir empfehlen folgende @code{configure}-Zeile für @code{egcs} und
+@code{gcc 2.95} auf AIX:
+
+@example
+CC="gcc -pipe -mcpu=power -Wa,-many" \
+CXX="gcc -pipe -mcpu=power -Wa,-many" \
+CXXFLAGS="-felide-constructors -fno-exceptions -fno-rtti" \
+./configure --prefix=/usr/local/mysql --with-low-memory
+@end example
+
+@code{-Wa,-many} ist notwendig, damit das Kompilieren gelingt. Das Problem
+ist IBM bekannt, hat es aber nicht eilig, es zu beheben, weil ein
+Workaround verfügbar ist. Wir wissen nicht, ob @code{-fno-exceptions} für
+@code{gcc 2.95} erforderlich ist, aber weil MySQL keine Exceptions benutzt
+und die obige Option schnelleren Code erzeugt, empfehlen wir, dass Sie
+diese Option für @code{egcs / gcc} immer benutzen.
+
+Wenn Sie ein Problem mit Assembler-Code bekommen, versuchen Sie, -mcpu=xxx
+so anzupassen, dass es zu Ihrem Prozessor passt. Typischerweise wird man
+power2, power oder powerpc benutzen, alternativ kann man eventuell 604 oder
+604e benutzen. Ich bin nicht ganz sicher, aber ich würde sagen, dass
+"power" meist sicher sein sollte, selbst auf einer power2-Maschine.
+
+Wenn Sie nicht wissen, welchen Prozessor Sie haben, geben Sie "uname -m"
+ein. Das gibt eine Zeichenkette zurück, die etwa wie "000514676700"
+aussieht, mit dem Format xxyyyyyymmss, wobei xx und ss immer die Nullen
+sind (0). yyyyyy ist eine eindeutige System-ID und mm ist die ID des
+CPU-Planars. Eine Tabelle dieser Werte liegt auf
+@uref{http://www.rs6000.ibm.com/doc_link/en_US/a_doc_lib/cmds/aixcmds5/uname.htm}.
+Darin finden Sie Maschinentyp und Maschinenmodell, was Sie benutzen können,
+um herauszufinden, welchen Prozessortyp Sie haben.
+
+Wenn Sie Probleme mit Signalen haben (MySQL stirbt unerwartet unter hoher
+Last), haben Sie vielleicht einen Betriebssystem-Bug bei Threads und
+Signalen gefunden. In diesem Fall können Sie MySQL anweisen, keine Signale
+zu benutzen, indem Sie es wie folgt konfigurieren:
+
+@example
+shell> CFLAGS=-DDONT_USE_THR_ALARM CXX=gcc \
+ CXXFLAGS="-felide-constructors -fno-exceptions -fno-rtti -DDONT_USE_THR_ALARM" \
+ ./configure --prefix=/usr/local/mysql --with-debug --with-low-memory
+@end example
+
+Das berührt nicht die Performance von MySQL, hat aber den Nebeneffekt, dass
+Sie keine Clients auf einer Verbindung mit @code{mysqladmin kill} oder
+@code{mysqladmin shutdown} killen können, die ``schlafen''. Statt dessen
+wird der Client sterben, wenn er den nächsten Befehl sendet.
+
+Bei einigen Versionen von AIX für das Linken mit @code{libbind.a} bei
+@code{getservbyname} zu einem Speicherauszug (Core Dump). Das ist ein
+AIX-Bug, der IBM berichtet werden sollte.
+
+Bei AIX 4.2.1 und gcc müssen Sie folgende Änderungen durchführen:
+
+Nach dem Konfigurieren müssen Sie @file{config.h} und
+@file{include/my_config.h} editieren und die Zeile ändern, in der steht:
+
+@example
+#define HAVE_SNPRINTF 1
+@end example
+
+zu
+
+@example
+#undef HAVE_SNPRINTF
+@end example
+
+Schließlich müssen Sie in @file{mysqld.cc} einen Prototype für initgoups
+hinzufügen:
+
+@example
+#ifdef _AIX41
+extern "C" int initgroups(const char *,int);
+#endif
+@end example
+
+
+@node SunOS, Alpha-DEC-UNIX, IBM-AIX, Other Unix Notes
+@c German node SunOS
+@subsubsection Anmerkungen zu SunOS 4
+
+Auf SunOS 4 werden MIT-pThreads benötigt, um MySQL zu kompilieren, was
+letztlich bedeutet, dass Sie GNU-@code{make} benötigen.
+
+Einige SunOS-4-Systeme haben Probleme mit dynamischen Bibliotheken und
+@code{libtool}. Sie können folgende @code{configure}-Zeile benutzen, um das
+Problem zu vermeiden:
+
+@example
+shell> ./configure --disable-shared --with-mysqld-ldflags=-all-static
+@end example
+
+Wenn Sie @code{readline} kompilieren, erhalten Sie vielleicht Warnungen
+über duplizierte Defines. Diese können ignoriert werden.
+
+Wenn Sie @code{mysqld} kompilieren, gibt es ein paar @code{implicit
+declaration of function}-Warnungen. Diese können ignoriert werden.
+
+
+@node Alpha-DEC-UNIX, Alpha-DEC-OSF1, SunOS, Other Unix Notes
+@c German node Alpha-DEC-UNIX
+@subsubsection Anmerkungen zu Alpha-DEC-UNIX (Tru64)
+
+Wenn Sie egcs 1.1.2 auf Digital Unix benutzen, sollten Sie auf gcc 2.95.2
+aktualisieren, weil egcs auf DEC einige schwer wiegende Bugs hat!
+
+Wenn Sie threaded Programme unter Digital Unix kompilieren, empfiehlt die
+Dokumentation, die @code{-pThread}-Option für @code{cc} und @code{cxx} und
+die Bibliotheken @code{-lmach -lexc} zu benutzen (zusätzlich zu
+@code{-lpThread}). Sie sollten @code{configure} wie folgt laufen lassen:
+
+@example
+CC="cc -pThread" CXX="cxx -pThread -O" \
+./configure --with-named-thread-libs="-lpThread -lmach -lexc -lc"
+@end example
+
+Wenn Sie @code{mysqld} kompilieren, sehen Sie eventuell eine Reihe von
+Warnungen wie die folgende:
+
+@example
+mysqld.cc: In function void handle_connections()':
+mysqld.cc:626: passing long unsigned int *' as argument 3 of
+accept(int,sockadddr *, int *)'
+@end example
+
+Sie können diese Warnungen ignorieren. Sie treten auf, weil
+@code{configure} nur Fehler entdecken kann, keine Warnungen.
+
+Wenn Sie den Server direkt von the Kommandozeile starten, haben Sie
+vielleicht Probleme, dass er stirbt, wenn Sie sich ausloggen. (Wenn Sie
+sich ausloggen, erhalten Ihre offenen Prozesse ein @code{SIGHUP}-Signal.)
+Wenn das der Fall ist, starten Sie den Server wie folgt:
+
+@example
+shell> nohup mysqld [options] &
+@end example
+
+@code{nohup} bewirkt, dass der folgende Befehl jegliche
+@code{SIGHUP}-Signale, die vom Terminal gesendet werden, ignoriert.
+Alternativ starten Sie den Server mit @code{safe_mysqld}, was @code{mysqld}
+mit @code{nohup} für Sie aufruft.
+@xref{safe_mysqld, , @code{safe_mysqld}}.
+
+Wenn Sie ein Problem beim Kompilieren von mysys/get_opt.c bekommen,
+entfernen Sie einfach die Zeile #define _NO_PROTO am Anfang dieser Datei!
+
+Wenn Sie den CC-Kompiler von Compaq benutzen, sollte die folgende
+Konfigurationszeile funktionieren:
+
+@example
+CC="cc -pThread"
+CFLAGS="-O4 -ansi_alias -ansi_args -fast -inline speed all -arch host"
+CXX="cxx -pThread"
+CXXFLAGS="-O4 -ansi_alias -ansi_args -fast -inline speed all -arch host"
+export CC CFLAGS CXX CXXFLAGS
+./configure \
+--prefix=/usr/local/mysql \
+--with-low-memory \
+--enable-large-files \
+--enable-shared=yes \
+--with-named-Thread-libs="-lpThread -lmach -lexc -lc"
+gnumake
+@end example
+
+Wenn Sie ein Problem mit libtool beim Kompilieren mit gemeinsam genutzten
+(shared) Bibliotheken bekommen wie oben, wenn Sie @code{mysql} linken,
+sollten Sie dies folgendermaßen umgehen können:
+
+@example
+cd mysql
+/bin/sh ../libtool --mode=link cxx -pThread -O3 -DDBUG_OFF \
+-O4 -ansi_alias -ansi_args -fast -inline speed \
+-speculate all \ -arch host -DUNDEF_HAVE_GETHOSTBYNAME_R \
+-o mysql mysql.o readline.o sql_string.o completion_hash.o \
+../readline/libreadline.a -lcurses \
+../libmysql/.libs/libmysqlclient.so -lm
+cd ..
+gnumake
+gnumake install
+Skripts/mysql_install_db
+@end example
+
+
+@node Alpha-DEC-OSF1, SGI-Irix, Alpha-DEC-UNIX, Other Unix Notes
+@c German node Alpha-DEC-OSF1
+@subsubsection Anmerkungen zu Alpha-DEC-OSF1
+
+Wenn Sie Probleme beim Kompilieren haben und DEC @code{CC} und @code{gcc}
+installiert sind, versuchen Sie, @code{configure} wie folgt laufen zu
+lassen:
+
+@example
+CC=cc CFLAGS=-O CXX=gcc CXXFLAGS=-O3 \
+./configure --prefix=/usr/local/mysql
+@end example
+
+Wenn Sie Probleme mit der @file{c_asm.h}-Datei bekommen, können Sie wie
+folgt eine 'dummy'-@file{c_asm.h}-Datei erzeugen und benutzen:
+
+@example
+touch include/c_asm.h
+CC=gcc CFLAGS=-I./include \
+CXX=gcc CXXFLAGS=-O3 \
+./configure --prefix=/usr/local/mysql
+@end example
+
+Beachten Sie, dass die im Folgenden beschriebenen Probleme mit dem
+@code{ld}-Programm behoben werden können, indem Sie das neueste
+DEC-(Compaq)-Patch-Kit herunterladen, und zwar von folgender Seite:
+@uref{http://ftp.Support.compaq.com/public/unix/}.
+
+Auf OSF1 V4.0D und Kompiler "DEC C V5.6-071 auf Digital Unix V4.0 (Rev.
+878)" zeigt der Kompiler einige seltsame Verhaltensweisen (undefinierte
+@code{asm}-Symbole). Ausserdem scheint @code{/bin/ld} beschädigt zu sein
+(Probleme mit @code{_exit undefined}-Fehlern, die auftreten, wenn Sie
+@code{mysqld} linken). Auf diesem System konnten wir MySQL mit folgender
+@code{configure}-Zeile kompilieren, nachdem wir @code{/bin/ld} mit der
+Version von OSF 4.0C ersetzt haben:
+
+@example
+CC=gcc CXX=gcc CXXFLAGS=-O3 ./configure --prefix=/usr/local/mysql
+@end example
+
+Beim Digital-Kompiler "C++ V6.1-029" sollte folgendes funktionieren:
+
+@example
+CC=cc -pThread
+CFLAGS=-O4 -ansi_alias -ansi_args -fast -inline speed -speculate all -arch host
+CXX=cxx -pThread
+CXXFLAGS=-O4 -ansi_alias -ansi_args -fast -inline speed -speculate all -arch host -noexceptions -nortti
+export CC CFLAGS CXX CXXFLAGS
+./configure --prefix=/usr/mysql/mysql --with-mysqld-ldflags=-all-static --disable-shared --with-named-thread-libs="-lmach -lexc -lc"
+@end example
+
+In einigen Versionen von OSF1 ist die @code{alloca()}-Funktion beschädigt.
+Beheben Sie dies, indem Sie die Zeile in @file{config.h} entfernen, die
+@code{'HAVE_ALLOCA'} definiert.
+
+Die @code{alloca()}-Funktion kann ebenfalls einen falschen Prototyp in
+@code{/usr/include/alloca.h} haben. Die Warnung, die hieraus resultiert,
+kann ignoriert werden.
+
+@code{configure} benutzt automatisch folgenden Thread-Bibliotheken:
+@code{--with-named-thread-libs="-lpThread -lmach -lexc -lc"}.
+
+Wenn Sie @code{gcc} benutzen, können Sie auch versuchen, @code{configure}
+wie folgt laufen zu lassen:
+
+@example
+shell> CFLAGS=-D_PTHREAD_USE_D4 CXX=gcc CXXFLAGS=-O3 ./configure ....
+@end example
+
+Wenn Sie Probleme mit Signalen haben (MySQL stirbt unerwartet unter
+Hochlast), haben Sie vielleicht einen Betriebssystem-Bug bei Threads und
+Signalen gefunden. In diesem Fall können Sie MySQL anweisen, keine Signale
+zu benutzen, indem Sie es wie folgt konfigurieren:
+
+@example
+shell> CFLAGS=-DDONT_USE_THR_ALARM \
+ CXXFLAGS=-DDONT_USE_THR_ALARM \
+ ./configure ...
+@end example
+
+Das berührt nicht die Performance von MySQL, hat aber den Nebeneffekt, dass
+Sie keine Clients auf einer Verbindung mit @code{mysqladmin kill} oder
+@code{mysqladmin shutdown} killen können, die ``schlafen''. Statt dessen
+wird der Client sterben, wenn er den nächsten Befehl sendet.
+
+Bei @code{gcc} 2.95.2 erhalten Sie wahrscheinlich folgenden
+Kompilierfehler:
+
+@example
+sql_acl.cc:1456: Internal compiler error in `scan_region', at except.c:2566
+Please submit a full bug report.
+@end example
+
+Um das zu beheben, wechseln Sie ins @code{sql}-Verzeichnis und machen ein
+``Kopieren und Einfügen'' der letzten @code{gcc}-Zeile, ändern aber
+@code{-O3} zu @code{-O0} (oder fügen @code{-O0} unmittelbar nach @code{gcc}
+hinzu, falls Sie keine @code{-O}-Option auf Ihrer Kompilierzeile haben.)
+Danach wechseln Sie einfach direkt zurück in oberste Verzeichnis und lassen
+@code{make} noch einmal laufen.
+
+@node SGI-Irix, SCO, Alpha-DEC-OSF1, Other Unix Notes
+@c German node SGI-Irix
+@subsubsection Anmerkungen zu SGI Irix
+
+Wenn Sie Irix-Version 6.5.3 oder neuer benutzen, kann @code{mysqld} nur
+dann Threads erzeugen, wenn Sie ihn als Benutzer mit
+@code{CAP_SCHED_MGT}-Zugriffsrechten (wie @code{root}) laufen lassen oder
+dem @code{mysqld}-Server dieses Recht mit dem folgenden Befehl geben:
+
+@example
+shell> chcap "CAP_SCHED_MGT+epi" /opt/mysql/libexec/mysqld
+@end example
+
+Sie müssen eventuell in @file{config.h} einige Dinge umdefinieren, nachdem
+Sie @code{configure} laufen gelassen haben und vor dem Kompilieren.
+
+In einigen Irix-Implementationen ist die @code{alloca()}-Funktion
+beschädigt. Wenn der @code{mysqld}-Server bei manchen
+@code{SELECT}-Statements stirbt, entfernen Sie die Zeilen aus
+@file{config.h}, die @code{HAVE_ALLOC} und @code{HAVE_ALLOCA_H} definieren.
+Wenn @code{mysqladmin create} nicht funktioniert, entfernen Sie die Zeile
+aus @file{config.h}, die @code{HAVE_READDIR_R} definiert. Eventuell müssen
+Sie auch die @code{HAVE_TERM_H}-Zeile entfernen.
+
+SGI empfiehlt, dass Sie alle Patches auf dieser Seite auf einmal
+installieren:
+http://Support.sgi.com/surfzone/patches/patchset/6.2_indigo.rps.html
+
+Als absolutes Minimum sollten Sie das letzte Kernel-Rollup installieren,
+das letzte @code{rld}-Rollup und das letzte @code{libc}-Rollup.
+
+In jedem Fall brauchen Sie für die pThread-Unterstützung alle POSIX-Patches
+auf dieser Seite:
+
+@uref{http://Support.sgi.com/surfzone/patches/patchset/6.2_posix.rps.html}
+
+Wenn Sie beim Kompilieren von @file{mysql.cc} etwa folgenden Fehler
+erhalten:
+
+@example
+"/usr/include/curses.h", line 82: error(1084): invalid combination of type
+@end example
+
+Geben Sie folgendes im obersten Verzeichnis Ihres MySQL-Source-Trees ein:
+
+@example
+shell> extra/replace bool curses_bool < /usr/include/curses.h > include/curses.h
+shell> make
+@end example
+
+Es wurden ausserdem Scheduling-Probleme berichtet. Wenn nur ein Thread
+läuft, läuft alles recht langsam. Das können Sie vermeiden, indem Sie einen
+weiteren Client-Starten. Daraus kann sich eine zwei- bis zehnfache
+Geschwindigkeitssteigerung für den anderen Thread ergeben. Das liegt an
+einem Problem mit Irix-Threads, das kaum zu verstehen ist. Eventuell müssen
+Sie improvisieren, um eine Lösung zu finden, bis dies behoben ist.
+
+Wenn Sie mit @code{gcc} kompilieren, können Sie folgenden
+@code{configure}-Befehl benutzen:
+
+@example
+CC=gcc CXX=gcc CXXFLAGS=-O3 \
+./configure --prefix=/usr/local/mysql --enable-thread-safe-client --with-named-thread-libs=-lpThread
+@end example
+
+Auf Irix 6.5.11 mit nativen Irix-C- und C++-Kompilern der Version 7.3.1.2
+soll auch folgendes funktionieren:
+
+@example
+CC=cc CXX=CC CFLAGS='-O3 -n32 -TARG:platform=IP22 -I/usr/local/include \
+-L/usr/local/lib' CXXFLAGS='-O3 -n32 -TARG:platform=IP22 \
+-I/usr/local/include -L/usr/local/lib' ./configure --prefix=/usr/local/mysql \
+--with-berkeley-db --with-innodb \
+--with-libwrap=/usr/local --with-named-curses-libs=/usr/local/lib/libncurses.a
+@end example
+
+
+@node SCO, SCO Unixware, SGI-Irix, Other Unix Notes
+@c German node SCO
+@subsubsection Anmerkungen zu SCO
+
+Die aktuelle Portierung wird auf ``sco3.2v5.0.4''-
+und-``sco3.2v5.0.5''-Systemen getestet. Die Portierung auf ``sco 3.2v4.2''
+ist ebenfalls weit fortgeschritten.
+
+Momentan ist der empfohlene Kompiler auf OpenServer gcc 2.95.2. Damit
+sollten Sie in der Lage sein, MySQL einfach durch folgendes zu kompilieren:
+
+@example
+CC=gcc CXX=gcc ./configure ... (options)
+@end example
+
+@enumerate
+@item
+Bei OpenServer 5.0.X müssen Sie GDS in Skunkware 95 (95q4c) benutzen. Das
+ist deshalb notwendig, weil GNU-@code{gcc} 2.7.2 in Skunkware 97 kein
+GNU-@code{as} hat. Sie können auch @code{egcs} 1.1.2 oder neuer benutzen
+@uref{http://www.egcs.com/}. Wenn Sie @code{egcs} 1.1.2 benutzen, müssen
+Sie folgenden Befehl eingeben:
+
+@example
+shell> cp -p /usr/include/pThread/stdtypes.h /usr/local/lib/gcc-lib/i386-pc-sco3.2v5.0.5/egcs-2.91.66/include/pThread/
+@end example
+
+@item
+Sie brauchen die Portierung von GCC 2.5.x für dieses Produkt und das
+Entwicklungssystem. Sie werden auf dieser Version von SCO Unix benötigt.
+Sie können nicht lediglich das GCC-Dev-System benutzen.
+
+@item
+Sie sollten zuerst das FSU-PThreads-Paket holen und installieren. Dieses
+finden Sie auf
+@uref{http://www.cs.wustl.edu/~schmidt/ACE_wrappers/FSU-Threads.tar.gz}.
+Sie finden ein vorkompiliertes Paket auf
+@uref{http://www.mysql.com/downloads/SCO/FSU-Threads-3.5c.tar.gz}.
+
+@item
+FSU-PThreads kann mit SCO Unix 4.2 mit TCP/IP kompiliert werden. Oder mit
+OpenServer 3.0 oder Open Desktop 3.0 (OS 3.0 ODT 3.0), mit installiertem
+SCO-Entwicklungssystem unter Benutzung einer guten Portierung von GCC 2.5.x
+ODT oder OS 3.0. Hierbei brauchen Sie eine gute Portierung von GCC 2.5.x.
+Ohne gute Portierung gibt es eine Menge Probleme. Die Portierung für dieses
+Produkt erfordert das SCO-Unix-Entwicklungssystem. Ohne dieses fehlen die
+Bibliotheken und der Linker, die benötigt werden.
+
+@item
+Um FSU-PThreads auf Ihrem System zu bauen, tun Sie folgendes:
+
+@enumerate a
+@item
+Lassen Sie @code{./configure} im @file{Threads/src}-Verzeichnis laufen und
+wählen Sie die SCO-OpenServer-Option. Dieser Befehl kopiert
+@file{Makefile.SCO5} nach @file{Makefile}.
+
+@item
+Lassen Sie @code{make} laufen.
+
+@item
+Um in das vorgabemäßige @file{/usr/include}-Verzeichnis zu installieren,
+loggen Sie sich als Root ein und wechseln (@code{cd}) Sie in das
+@file{thread/src}-Verzeichnis. Führen Sie dann @code{make install} aus.
+@end enumerate
+
+@item
+Denken Sie daran, GNU @code{make} zu benutzen, wenn Sie MySQL machen.
+
+@item
+Wenn Sie @code{safe_mysqld} nicht als Root starten, erhalten Sie
+wahrscheinlich nur die 110 offenen Dateien pro Prozess. @code{mysqld} macht
+darüber in der Log-Datei einen Eintrag.
+
+@item
+Bei SCO 3.2V5.0.5 sollten Sie FSU-PThreads-Version 3.5c oder neuer
+benutzen. Ausserdem sollten Sie gcc 2.95.2 oder neuer benutzen!
+
+Folgender @code{configure}-Befehl sollte funktionieren:
+
+@example
+shell> ./configure --prefix=/usr/local/mysql --disable-shared
+@end example
+
+@item
+Bei SCO 3.2V4.2 sollten Sie FSU-PThreads-Version 3.5c oder neuer benutzen.
+Folgender @code{configure}-Befehl sollte funktionieren:
+
+@example
+shell> CFLAGS="-D_XOPEN_XPG4" CXX=gcc CXXFLAGS="-D_XOPEN_XPG4" \
+ ./configure \
+ --prefix=/usr/local/mysql \
+ --with-named-thread-libs="-lgThreads -lsocket -lgen -lgThreads" \
+ --with-named-curses-libs="-lcurses"
+@end example
+
+Möglicherweise bekommen Sie Probleme mit einigen Include-Dateien. In diesem
+Fall finden Sie neue, SCO-spezifische Include-Dateien auf
+@uref{http://www.mysql.com/downloads/SCO/SCO-3.2v4.2-includes.tar.gz}.
+Entpacken Sie diese Datei ins @file{include}-Verzeichnis Ihres
+MySQL-Source-Trees.
+@end enumerate
+
+Anmerkungen zur SCO-Entwicklung:
+
+@itemize @bullet
+@item
+MySQL kann FSU-PThreads automatisch erkennen und @code{mysqld} mit
+@code{-lgThreads -lsocket -lgThreads} linken.
+
+@item
+@c Question: Good translation for "re-entrant"?
+Die SCO-Entwicklungsbibliotheken sind re-entrant in FSU-PThreads. SCO
+behauptet, dass seine Bibliotheken-Funktionen re-entrant sind, daher müssen
+sie mit FSU-PThreads re-entrant sein. FSU-PThreads auf OpenServer versucht,
+das SCO-Scheme zu benutzen, um Bibliotheken re-entrant zu machen.
+
+@item
+FSU-PThreads (zumindest die Version auf @uref{http://www.mysql.com/}) wird
+mit gelinktem GNU-@code{malloc} ausgeliefert. Wenn Sie Problemen mit der
+Speicherbenutzung begegnen, stellen Sie sicher, dass @file{gmalloc.o} in
+@file{libgThreads.a} und @file{libgThreads.so} beinhaltet ist.
+
+@item
+In FSU-PThreads achten folgende Systemaufrufe auf pThreads: @code{read()},
+@code{write()}, @code{getmsg()}, @code{connect()}, @code{accept()},
+@code{select()} und @code{wait()}.
+@end itemize
+
+Wenn Sie DBI auf SCO installieren wollen, müssen Sie @file{Makefile} in
+DBI-xxx und jedem Unterverzeichnis editieren.
+
+Beachten Sie, dass folgendes gcc 2.95.2 oder neuer voraussetzt:
+
+@example
+ALT: NEU:
+CC = cc CC = gcc
+CCCDLFLAGS = -KPIC -W1,-Bexport CCCDLFLAGS = -fpic
+CCDLFLAGS = -wl,-Bexport CCDLFLAGS =
+
+LD = ld LD = gcc -G -fpic
+LDDLFLAGS = -G -L/usr/local/lib LDDLFLAGS = -L/usr/local/lib
+LDFLAGS = -belf -L/usr/local/lib LDFLAGS = -L/usr/local/lib
+
+LD = ld LD = gcc -G -fpic
+OPTIMISE = -Od OPTIMISE = -O1
+
+OLD:
+CCCFLAGS = -belf -dy -w0 -U M_XENIX -DPERL_SCO5 -I/usr/local/include
+
+NEW:
+CCFLAGS = -U M_XENIX -DPERL_SCO5 -I/usr/local/include
+@end example
+
+Das liegt daran, dass der Perl-dynaloader keine @code{DBI}-Module lädt, die
+mit @code{icc} oder @code{cc} kompiliert wurden.
+
+Perl funktioniert am besten, wenn es mit @code{cc} kompiliert wird.
+
+
+@node SCO Unixware, , SCO, Other Unix Notes
+@c German node SCO Unixware
+@subsubsection Anmerkungen zu SCO Unixware Version 7.0
+
+Sie benötigen mindestens MySQL-Version 3.22.13, weil diese Version einige
+Portabilitätsprobleme unter Unixware behebt.
+
+Wir waren in der Lage, MySQL mit folgendem @code{configure}-Befehl auf
+Unixware Version 7.0.1 zu kompilieren:
+
+@example
+CC=cc CXX=CC ./configure --prefix=/usr/local/mysql
+@end example
+
+Wenn Sie @code{gcc} benutzen wollen, müssen Sie @code{gcc} 2.95.2 oder
+neuer benutzen.
+
+
+
+
+@node OS/2, BeOS, Other Unix Notes, Operating System Specific Notes
+@c German node OS/2
+@subsection Anmerkungen zu OS/2
+
+MySQL benutzt eine ganze Menge offener Dateien. Deswegen sollten Sie Ihrer
+@file{CONFIG.SYS}-Datei folgendes hinzufügen:
+
+@example
+SET EMXOPT=-c -n -h1024
+@end example
+
+Wenn Sie das nicht tun, erhalten Sie wahrscheinlich folgenden Fehler:
+
+@example
+File 'xxxx' not found (Errcode: 24)
+@end example
+
+Wenn Sie MySQL auf OS/2 Warp 3 einsetzen, wird FixPack 29 oder höher
+benötigt. Bei OS/2 Warp 4 wird FixPack 4 oder höher benötigt. Das erfordert
+die PThreads-Bibliothek. MySQL muss auf einer Partition installiert werden,
+die lange Dateinamen unterstützt, also zum Beispiel HPFS, FAT32 usw.
+
+Das @file{INSTALL.CMD}-Skript muss von OS/2's eigener @file{CMD.EXE} aus
+laufen gelassen werden und funktioniert eventuell nicht mit Ersatz-Shells
+wie @file{4OS2.EXE}.
+
+Das @file{scripts/mysql-install-db}-Skript wurde umbenannt. Es heißt jetzt
+@file{install.cmd} und ist ein REXX-Skript, welches die vorgabemäßigen
+MySQL-Sicherheitseinstellungen einstellt und die WorkPlace-Shell-Icons für
+MySQL erstellt.
+
+Unterstützung für dynamische Module wird einkompiliert, ist aber noch nicht
+komplett durchgetestet. Dynamische Module sollten unter Benutzung der
+PThreads-Runtime-Bibliothek kompiliert werden.
+
+@example
+gcc -Zdll -Zmt -Zcrtdll=pthrdrtl -I../include -I../regex -I.. \
+ -o example udf_example.cc -L../lib -lmysqlclient udf_example.def
+mv example.dll example.udf
+@end example
+
+@strong{Beachten Sie:} Aufgrund von Beschränkungen in OS/2 dürfen
+UDF-module-name-stems nicht länger als 8 Zeichen sein. Module werden im
+@file{/mysql2/udf}-Verzeichnis gespeichert; das
+@code{safe-mysqld.cmd}-Skript trägt dieses Verzeichnis in die
+@code{BEGINLIBPATH}-Umgebungsvariable ein. Wenn Sie UDF-Module benutzen,
+werden festgelegte Erweiterungen ignoriert - es wird nicht angenommen, dass
+sie @file{.udf} sind.
+Unter Unix zum Beispiel könnte das gemeinsam genutzte (shared) Module
+@file{example.so} benannt sein. Sie würden daraus eine Funktion wie folgt
+laden:
+
+@example
+mysql> CREATE FUNCTION metaphon RETURNS STRING SONAME "example.so";
+@end example
+
+Unter OS/2 würde das Modul @file{example.udf} heißen, aber Sie würden
+nicht die Modul-Erweiterung angeben:
+
+@example
+mysql> CREATE FUNCTION metaphon RETURNS STRING SONAME "example";
+@end example
+
+
+@node BeOS, Novell Netware, OS/2, Operating System Specific Notes
+@c German node BeOS
+@subsection Anmerkungen zu BeOS
+
+Wir sind sehr daran interessiert, MySQL auf BeOS ans Laufen zu bringen,
+aber leider kennen wir niemanden, der sich mit BeOS auskennt oder Zeit hat,
+eine Portierung durchzuführen.
+
+Wir sind daran interessiert, jemanden für eine Portierung zu finden, und
+wir werden ihn / sie bei allen technischen Fragen helfen, die bei einer
+Portierung auftreten können.
+
+Wir haben vor einiger Zeit mit einigen BeOS-Entwicklern gesprochen, die uns
+sagten, dass MySQL zu 80% auf BeOS portiert ist, aber wir haben schon eine
+Weile nichts von ihnen gehört.
+
+
+@node Novell Netware, , BeOS, Operating System Specific Notes
+@c German node Novell Netware
+@subsection Anmerkungen zu Novell Netware
+
+Wir sind sehr daran interessiert, MySQL auf Netware ans Laufen zu bringen,
+aber leider kennen wir niemanden, der sich mit Netware auskennt oder Zeit hat,
+eine Portierung durchzuführen.
+
+Wir sind daran interessiert, jemanden für eine Portierung zu finden, und
+wir werden ihn / sie bei allen technischen Fragen helfen, die bei einer
+Portierung auftreten können.
+
+@node Perl support, , Operating System Specific Notes, Installing
+@c German node Perl-Unterstützung
+@section Anmerkungen zur Perl-Installation
+
+@cindex Perl, Installation
+@cindex Installation, Perl
+
+@code{DBI}/@code{DBD}-Schnittstelle
+
+
+@menu
+* Perl installation::
+* ActiveState Perl::
+* Windows Perl::
+* Perl support problems::
+@end menu
+
+@node Perl installation, ActiveState Perl, Perl support, Perl support
+@c German node Perl-Installation
+@subsection Installation von Perl unter Unix
+
+Perl-Unterstützung für MySQL wird durch die @code{DBI}/@code{DBD}-
+Client-Schnittstelle zur Verfügung gestellt. @xref{Perl}. Der Perl-
+@code{DBD}/@code{DBI}-Client-Code erfordert Perl Version 5.004 oder
+später. Die Schnittstelle @strong{funktioniert nicht}, wenn Sie eine
+ältere Version von Perl haben.
+
+MySQL-Perl-Unterstützung erfordert ausserdem, dass Sie MySQL-Client-
+Programmierunterstützung installiert haben. Wenn Sie MySQL von RPM-
+Dateien installiert haben, sind Client-Programme im Client-RPM
+enthalten, aber Client-Programmierunterstützung ist im Entwickler-RPM.
+Stellen Sie sicher, dass Sie auch das letztgenannte RPM installiert
+haben.
+
+Ab Version 3.22.8 wird Perl-Unterstützung getrennt von der Haupt-MySQL-
+Unterstützung ausgeliefert. Wenn Sie Perl-Unterstützung installieren
+wollen, können Sie die benötigten Dateien von
+@uref{http://www.mysql.com/Downloads/Contrib/} herunter laden.
+
+Die Perl-Distributionen werden als komprimierte @code{tar}-Archive zur
+Verfügung gestellt und haben Namen wie @file{MODULE-VERSION.tar.gz},
+wobei @code{MODULE} der Modulname und @code{VERSION} die Versionsnummer
+ist. Sie sollten die @code{Data-Dumper}-, @code{DBI}- und @code{Msql-
+Mysql-modules}-Distributionen laden und sie in dieser Reihenfolge
+installieren. Die Installationsprozedur ist unten dargestellt. Das
+Beispiel gilt für das @code{Data-Dumper}-Modul, ist aber für alle drei
+Distributionen dieselbe:
+
+@enumerate
+@item
+Entpacken Sie die Distribution ins aktuelle Verzeichnis.
+@example
+shell> gunzip < Data-Dumper-VERSION.tar.gz | tar xvf -
+@end example
+Dieser Befehl erzeugt ein Verzeichnis namens @file{Data-Dumper-
+VERSION}.
+
+@item
+Wechseln Sie ins oberste Verzeichnis der entpackten Distribution:
+@example
+shell> cd Data-Dumper-VERSION
+@end example
+
+@item
+Bauen Sie die Distribution und kompilieren Sie alles:
+@example
+shell> perl Makefile.PL
+shell> make
+shell> make test
+shell> make install
+@end example
+@end enumerate
+
+Der @code{make test}-Befehl ist wichtig, weil er sicherstellt, dass die
+Module funktionieren. Beachten Sie, dass der MySQL-Server während der
+Befehlsausführung bei der @code{Msql-Mysql-modules}-Installation laufen
+muss, um den Schnittstellen-Code auszuführen, den ansonsten schlägt der
+Test fehl.
+
+Es ist eine gute Idee, die @code{Msql-Mysql-modules}-Distribution neu zu
+kompilieren und zu installieren, wenn Sie ein neues Release von MySQL
+installieren, insbesondere, wenn Sie Symptome feststellen wie dass alle
+Ihre @code{DBI}-Skripte einen Coredump liefern, nachdem Sie auf eine
+höhere Version von MySQL aktualisiert haben.
+
+Wenn Sie keine Rechte haben, die Perl-Module im Systemverzeichnis zu
+installieren, oder wenn Sie lokale Perl-Module installieren wollen,
+könnte Ihnen der folgende Link helfen:
+
+@example
+@uref{http://www.iserver.com/support/contrib/perl5/modules.html}
+@end example
+
+Suchen Sie nach der Überschrift
+@code{Installing New Modules that Require Locally Installed Modules}.
+
+
+@node ActiveState Perl, Windows Perl, Perl installation, Perl support
+@c German node ActiveState-Perl
+@subsection Installation von ActiveState-Perl unter Windows
+
+@cindex Installation, Perl unter Windows
+@cindex Perl, Installation unter Windows
+@cindex ActiveState-Perl
+
+Um das MySQL-@code{DBD}-Modul mit ActiveState-Perl unter Windows zu
+installieren, gehen Sie wie folgt vor:
+
+@itemize @bullet
+@item
+Laden Sie ActiveState-Perl von
+@uref{http://www.activestate.com/Products/ActivePerl/}
+und installieren Sie es.
+
+@item
+Öffnen Sie eine MS-DOS-Eingabeaufforderung.
+
+@item
+Setzen Sie - falls erforderlich - die HTTP_proxy-Variable, zum Beispiel
+wie folgt:
+
+@example
+set HTTP_proxy=my.proxy.com:3128
+@end example
+
+@item
+Starten Sie das PPM-Programm:
+
+@example
+C:\> c:\perl\bin\ppm.pl
+@end example
+
+@item
+Falls noch nicht geschehen, installieren Sie @code{DBI}:
+
+@example
+ppm> install DBI
+@end example
+
+@item
+Wenn das erfolgreich verlief, führen Sie folgenden Befehl aus:
+
+@example
+install
+ftp://ftp.de.uu.net/pub/CPAN/authors/id/JWIED/DBD-mysql-1.2212.x86.ppd
+@end example
+@end itemize
+
+Das sollte zumindest bei ActiveState-Perl Version 5.6 funktionieren.
+
+Wenn Sie es nicht schaffen, dass oben Genanntes funktioniert, sollten
+Sie statt dessen den @strong{MyODBC}-Treiber installieren und sich mit
+dem MySQL-Server über ODBC verbinden:
+
+@example
+use DBI;
+$dbh= DBI->connect("DBI:ODBC:$dsn","$user","$password") ||
+ die "Fehler $DBI::errstr beim Verbinden mit $dsn\n";
+@end example
+
+
+@node Windows Perl, Perl support problems, ActiveState Perl, Perl support
+@c German node Windows-Perl
+@subsection Installation der MySQL-Perl-Distribution unter Windows
+
+Die MySQL-Perl-Distribution enthält @code{DBI},
+@code{DBD:MySQL} und @code{DBD:ODBC}.
+
+@itemize @bullet
+@item
+Laden Sie die Perl-Distribution für Windows von
+@uref{http://www.mysql.com/download.html}.
+
+@item
+Entpacken Sie die Distribution in @code{C:}, so dass Sie ein
+@file{C:\PERL}-Verzeichnis erhalten.
+
+@item
+Fügen Sie Ihrem Pfad @file{C:\PERL\BIN} hinzu.
+
+@item
+Fügen Sie Ihrem Pfad das Verzeichnis @file{C:\PERL\BIN\MSWIN32-x86-
+thread} oder @file{C:\PERL\BIN\MSWIN32-x86} hinzu.
+
+@item
+Testen Sie, ob @code{perl} funktioniert, indem Sie @code{perl -v} in
+einer MS-DOS-Eingabeaufforderung ausführen.
+@end itemize
+
+
+@node Perl support problems, , Windows Perl, Perl support
+@c German node Perl-Unterstützung Probleme
+@subsection Probleme bei der Benutzung von Perl @code{DBI}/@code{DBD}-Schnittstelle
+
+@cindex Probleme, Installation von Perl
+@cindex Perl DBI/DBD, Installationsprobleme
+
+Wenn Perl ausgibt, dass es das @file{../mysql/mysql.so}-Modul nicht
+finden kann, liegt das Problem wahrscheinlich darin, dass Perl die
+gemeinsam genutzte @file{libmysqlclient.so} nicht findet.
+
+Das können Sie mit einer der folgenden Methoden beheben:
+
+@itemize @bullet
+@item
+Kompilieren Sie die @code{Msql-Mysql-modules}-Distribution mit
+@code{perl Makefile.PL -static -config} statt mit @code{perl
+Makefile.PL}.
+
+@item
+Kopieren Sie @code{libmysqlclient.so} in das Verzeichnis, in dem Ihre
+anderen gemeinsam genutzten Bibliotheken liegen (wahrscheinlich
+@file{/usr/lib} oder @file{/lib}).
+
+@item
+Unter Linux können Sie der @file{/etc/ld.so.conf}-Datei den Pfadnamen
+des Verzeichnisses hinzufügen, in dem @file{libmysqlclient.so} liegt.
+
+@tindex LD_RUN_PATH-Umgebungsvariable
+@tindex Umgebungsvariable, LD_RUN_PATH
+@item
+Fügen Sie der @code{LD_RUN_PATH}-Umgebungsvariablen den Pfadnamen des
+Verzeichnisses hinzu, in dem @file{libmysqlclient.so} liegt.
+@end itemize
+
+Wenn Sie folgende Fehler von @code{DBD-mysql} erhalten, benutzen Sie
+wahrscheinlich @code{gcc} (oder eine alte Binärdatei, die mit @code{gcc}
+kompiliert wurde):
+
+@example
+/usr/bin/perl: can't resolve symbol '__moddi3'
+/usr/bin/perl: can't resolve symbol '__divdi3'
+@end example
+
+Fügen Sie @code{-L/usr/lib/gcc-lib/... -lgcc} zum Link-Befehl hinzu,
+wenn die @file{mysql.so}-Bibliothek gebaut wird (überprüfen Sie die
+Ausgabe von @code{make} nach @file{mysql.so}, wenn Sie den Perl-Client
+kompilieren). Die @code{-L}-Option sollte den Pfadnamen des
+Verzeichnisses angeben, in dem @file{libgcc.a} auf Ihrem System liegt.
+
+Ein weiterer Grund für dieses Problem kann sein, dass Perl und MySQL
+nicht beide mit @code{gcc} kompiliert wurden. In diesem Fall können Sie
+die fehlende Übereinstimmung (Mismatch) durch Kompilieren von beiden mit
+@code{gcc} aufheben.
+
+Wenn Sie folgende Fehler von @code{Msql-Mysql-modules} erhalten, wenn
+Sie die Tests laufen lassen:
+
+@example
+t/00base............install_driver(mysql) failed: Can't load
+'../blib/arch/auto/DBD/mysql/mysql.so' for module DBD::mysql:
+../blib/arch/auto/DBD/mysql/mysql.so: undefined symbol: uncompress at
+/usr/lib/perl5/5.00503/i586-linux/DynaLoader.pm line 169.
+@end example
+
+Bedeutet das, dass Sie die Kompressionsbibliothek (-lz) in die Link-
+Zeile einschließen müssen. Das kann man durch folgende Änderung in der
+Datei @file{lib/DBD/mysql/Install.pm} tun:
+
+@example
+$sysliblist .= " -lm";
+
+ändern in
+
+$sysliblist .= " -lm -lz";
+@end example
+
+Danach @strong{müssen} Sie 'make realclean' laufen lassen und danach mit
+der Installation von Anfang an beginnen.
+
+Wenn Sie das Perl-Modul auf einem System laufen lassen wollen, das
+dynamisches Linken nicht unterstützt (wie SCO), können Sie eine
+statische Version von Perl erzeugen, die @code{DBI} und @code{DBD-mysql}
+enthält. Das bringt man zum Laufen, indem man eine Version von Perl
+erzeugt, in der der @code{DBI}-Code eingelinkt ist, und diese über das
+aktuelle Perls installiert. Dann benutzen Sie diese, um eine Version von
+Perl zu bauen, die zusätzlich den @code{DBD}-Code eingelinkt hat, und
+installieren diese.
+
+Unter SCO müssen folgende Umgebungsvariablen gesetzt sein:
+
+@example
+shell> LD_LIBRARY_PATH=/lib:/usr/lib:/usr/local/lib:/usr/progressive/lib
+or
+shell>
+LD_LIBRARY_PATH=/usr/lib:/lib:/usr/local/lib:/usr/ccs/lib:/usr/progressive/lib:/usr/skunk/lib
+shell>
+LIBPATH=/usr/lib:/lib:/usr/local/lib:/usr/ccs/lib:/usr/progressive/lib:/usr/skunk/lib
+shell>
+MANPATH=scohelp:/usr/man:/usr/local1/man:/usr/local/man:/usr/skunk/man:
+@end example
+
+Erzeugen Sie zuerst ein Perl, das ein statisch gelinktes @code{DBI}
+enthält, indem Sie diese Befehle im Verzeichnis ausführen, in dem Ihre
+@code{DBI}-Distribution liegt:
+
+@example
+shell> perl Makefile.PL -static -config
+shell> make
+shell> make install
+shell> make perl
+@end example
+
+Dann müssen Sie das neue Perl installieren. Die Ausgabe von @code{make
+perl} zeigt den genauen @code{make}-Befehl an, den Sie für die
+Installation ausführen müssen. Unter SCO ist das @code{make -f
+Makefile.aperl inst_perl MAP_TARGET=perl}.
+
+Benutzen Sie als nächstes dieses soeben erzeugte Perl, um ein weiteres
+Perl zu erzeugen, dass auch ein statisch gelinktes @code{DBD::mysql}
+enthält, indem Sie diese Befehle im Verzeichnis ausführen, in dem Ihre
+@code{Msql-Mysql-modules}-Distribution liegt:
+
+@example
+shell> perl Makefile.PL -static -config
+shell> make
+shell> make install
+shell> make perl
+@end example
+
+Zum Schluss müssen Sie dieses neue Perl installieren. Hierbei zeigt die
+Ausgabe von @code{make perl} wiederum, welcher Befehl benutzt werden
+muss.
+
+@node Tutorial, MySQL Database Administration, Installing, Top
+@c German node Tutorial
+@chapter Einführung in MySQL: Ein MySQL-Tutorial
+
+@cindex Tutorial
+@c Question: Uh - what's a defined terminal monitor?
+@cindex terminal monitor, defined
+@c Question: Uh - what's that for the index?
+@cindex monitor, terminal
+@cindex Optionen, von MySQL
+
+
+Dieses Kapitel enthält eine Einführung in MySQL in Form eines Tutorials.
+Datei wird gezeigt, wie Sie das @code{mysql}-Client-Programm benutzen, um
+eine einfache Datenbank zu erzeugen und zu benutzen. @code{mysql} (auch
+``Terminal-Monitor'' oder einfach ``Monitor'' genannt) ist ein interaktives
+Programm, mit dem Sie sich mit einem MySQL-Server verbinden, Anfragen
+(Queries) absetzen und die Ergebnisse ansehen können. @code{mysql} kann
+auch im Stapelbetrieb (Batch Mode) benutzt werden: Sie schreiben Ihre
+Anfragen zuerst in eine Datei und veranlassen dann @code{mysql}, die
+Inhalte dieser Datei auszuführen. Hier werden beide Möglichkeiten
+beschrieben, @code{mysql} zu benutzen.
+
+Sie können @code{mysql} mit der @code{--help}-Option aufrufen, um eine
+Liste der Optionen zu sehen:
+
+@example
+shell> mysql --help
+@end example
+
+Dieses Kapitel setzt voraus, dass @code{mysql} auf Ihrer Maschine
+installiert ist und dass ein MySQL-Server verfügbar ist, mit dem Sie sich
+verbinden können. Wenn das nicht der Fall sein sollte, setzen Sie sich mit
+Ihrem MySQL-Administrator in Verbindung. (Wenn @emph{Sie} der Administrator
+sind, müssen Sie in anderen Abschnitten des Handbuchs nachsehen.)
+
+Dieses Kapitel beschreibt den gesamten Prozess der Einrichtung und
+Benutzung einer Datenbank. Wenn Sie lediglich wissen wollen, wie man auf
+eine bereits existierende Datenbank zugreift, können Sie die Abschnitte
+überspringen, die beschreiben, wie man eine Datenbank und die Tabellen, die
+sie enthält, erzeugt.
+
+Weil dieses Kapitel ein Tutorial ist, wurden notwendigerweise viele Details
+ausgelassen. Sehen Sie in den relevanten Abschnitten dieses Handbuchs nach,
+wenn Sie weitere Informationen zu den Themen suchen, die hier besprochen
+werden.
+
+
+@menu
+* Connecting-disconnecting::
+* Entering queries::
+* Database use::
+* Getting information::
+* Examples::
+* Batch mode::
+* Twin::
+* Apache::
+@end menu
+
+@node Connecting-disconnecting, Entering queries, Tutorial, Tutorial
+@c German node Verbinden und Trennen
+@section Verbindung zum Server herstellen und trennen
+
+@cindex Verbinden, mit dem Server
+@cindex Verbindung trennen, mit dem Server
+@cindex Server, verbinden
+@cindex Server, Verbindung trennen
+
+Um sich zum Server zu verbinden, müssen Sie beim Aufruf von @code{mysql} in
+der Regel einen MySQL-Benutzernamen und üblicherweise auch ein Passwort
+angeben. Wenn der Server auf einer anderen Maschine als der läuft, von der
+Sie sich einloggen, müssen Sie auch einen Hostnamen angeben. Setzen Sie
+sich mit Ihrem Administrator in Verbindung, um herauszubekommen, welche
+Verbindungsparameter Sie benutzen sollten (das heißt welchen Host,
+welchen Benutzername und welches Passwort Sie verwenden sollen). Wenn Sie
+die richtigen Parameter kennen, sollten Sie sich wie folgt verbinden
+können:
+
+@example
+shell> mysql -h host -u user -p
+Enter password: ********
+@end example
+
+@code{********} steht für Ihr Passwort. Geben Sie es ein, wenn @code{mysql}
+@code{Enter password:} anzeigt.
+
+Wenn das funktioniert hat, sehen Sie ein paar einführende Informationen,
+gefolgt von der @code{mysql>}-Eingabeaufforderung:
+
+
+@example
+shell> mysql -h host -u user -p
+Enter password: ********
+Welcome to the MySQL monitor. Commands end mit ; or \g.
+Your MySQL connection id ist 459 to server version: 3.22.20a-log
+
+Type 'help' for help.
+
+mysql>
+@end example
+
+Die Eingabeaufforderung sagt Ihnen, dass @code{mysql} bereit für die
+Eingabe von Befehlen ist.
+
+Einige
+Einige MySQL-Installationen erlauben Benutzern, sich als anonyme
+(unbenannte) Benutzer mit dem Server auf dem lokalen Host zu verbinden.
+Wenn das auf Ihrer Maschine der Fall ist, können Sie sich mit diesem Server
+verbinden, indem Sie @code{mysql} ohne irgend welche Optionen aufrufen:
+
+@example
+shell> mysql
+@end example
+
+Nachdem Sie sich erfolgreich verbunden haben, können Sie die Verbindung
+jederzeit trennen, indem Sie @code{QUIT} an der
+@code{mysql>}-Eingabeaufforderung eingeben.
+
+@example
+mysql> QUIT
+Bye
+@end example
+
+Sie können die Verbindung auch trennen, indem Sie STRG+D eingeben.
+
+Die meisten Beispiele der folgenden Abschnitte setzen voraus, dass Sie mit
+dem Server verbunden sind. Das wird durch @code{mysql>} angezeigt.
+
+
+@node Entering queries, Database use, Connecting-disconnecting, Tutorial
+@c German node Anfragen eingeben
+@section Anfragen eingeben
+
+@cindex Absetzen, Anfragen
+@cindex Anfragen, absetzen
+@cindex Eingeben, Anfragen
+
+Stellen Sie sicher, dass Sie mit dem Server verbunden sind, wie im
+vorherigen Abschnitt erörtert. Dadurch wird noch keine Datenbank
+ausgewählt, mit der Sie arbeiten können, aber das ist in Ordnung. Hier ist
+es erst einmal wichtiger, herauszufinden, wie Sie Anfragen (Queries)
+absetzen, als direkt mit dem Erzeugen von Tabellen, dem Einladen von Daten
+in diese und der Abfrage von Daten aus diesen zu beginnen. Dieser Abschnitt
+beschreibt die grundlegenden Prinzipien der Befehlseingabe, indem etliche
+Anfragen gezeigt werden, die Sie ausprobieren können, um sich mit der
+Arbeitsweise von @code{mysql} vertraut zu machen.
+
+Hier ist ein einfacher Befehl, der den Server bittet, Ihnen seine
+Versionsnummer und das aktuelle Datum mitzuteilen. Geben Sie folgendes an
+der @code{mysql>}-Eingabeaufforderung ein und drücken Sie die Eingabetaste:
+
+@example
+mysql> SELECT VERSION(), CURRENT_DATE;
++--------------+--------------+
+| version() | CURRENT_DATE |
++--------------+--------------+
+| 3.22.20a-log | 1999-03-19 |
++--------------+--------------+
+1 row in set (0.01 sec)
+mysql>
+@end example
+
+Diese Anfrage erläutert verschiedene Dinge über @code{mysql}:
+
+@itemize @bullet
+@item
+Ein Befehl besteht normalerweise aus einem SQL-Statement, gefolgt von einem
+Semikolon. (Es gibt ein paar Ausnahmen, bei denen das Semikolon nicht
+benötigt wird. @code{QUIT}, das vorher erwähnt wurde, stellt eine solche
+Ausnahme dar. Wir kommen später noch zu anderen Ausnahmen.)
+
+@item
+Wenn Sie einen Befehl absetzen, sendet @code{mysql} ihn zum Server, der ihn
+ausführt, und zeigt die Ergebnisse an. Danach wird eine neue
+@code{mysql>}-Eingabeaufforderung angezeigt, um klar zu machen, dass es für
+einen weiteren Befehl bereit ist.
+
+@item
+@code{mysql} zeigt die Ausgabe der Anfrage in Tabellenform an (Zeilen und
+Spalten). Die erste Zeile enthält Spaltenüberschriften. Die folgenden
+Zeilen sind die Ergebnisse der Anfrage. Normalerweise sind die
+Spaltenüberschriften die Spaltennamen der Tabellen, die Sie abfragen. Wenn
+Sie statt der Spaltennamen den Wert eines Ausdrucks abfragen (wie im
+gezeigten Beispiel), beschriftet @code{mysql} die Spaltenüberschrift mit
+dem Ausdruck selbst.
+
+@item
+@code{mysql} zeigt, wie viele Zeilen zurück gegeben wurden und wie lang die
+Ausführung der Anfrage dauerte, was ihnen eine grobe Einschätzung der
+Server-Performance ermöglicht. Diese Werte sind ungenau, weil sie die
+Wanduhrzeit repräsentieren (und nicht die Prozessor- oder Maschinenzeit),
+und weil sie von Faktoren wie der Serverlast und der Netzwerk-Wartezeit
+beeinflusst werden. (Um uns kurz zu fassen, zeigen wir die ``rows in
+set''-Zeile in den weiteren Beispielen dieses Kapitels nicht mehr an.)
+@end itemize
+
+Schlüsselwörter können in beliebiger Schreibweise (Groß und klein)
+eingegeben werden. Folgende Anfragen sind gleichwertig:
+
+@example
+mysql> SELECT VERSION(), CURRENT_DATE;
+mysql> select version(), current_date;
+mysql> SeLeCt vErSiOn(), current_DATE;
+@end example
+
+Hier kommt eine weitere Anfrage. Sie zeigt, wie Sie @code{mysql} als
+einfachen Rechner benutzen können:
+
+@example
+mysql> SELECT SIN(PI()/4), (4+1)*5;
++-------------+---------+
+| SIN(PI()/4) | (4+1)*5 |
++-------------+---------+
+| 0.707107 | 25 |
++-------------+---------+
+@end example
+
+Die bislang gezeigten Befehle sind relativ kurze, einzeilige Statements.
+Sie können allerdings auch mehrfache Statements auf einer einzelnen Zeile
+eingeben. Beenden Sie einfach jedes davon mit einem Semikolon:
+
+@example
+mysql> SELECT VERSION(); SELECT NOW();
++--------------+
+| version() |
++--------------+
+| 3.22.20a-log |
++--------------+
+
++---------------------+
+| NOW() |
++---------------------+
+| 1999-03-19 00:15:33 |
++---------------------+
+@end example
+
+Ein Befehl muss nicht auf einer einzelnen Zeile eingegeben werden, so dass
+längere Befehle, die mehrere Zeilen erfordern, kein Problem darstellen.
+@code{mysql} stellt anhand des beendenden Semikolons fest, wo Ihr Statement
+endet, und nicht etwa anhand des Zeilenendes. (Mit anderen Worten
+akzeptiert @code{mysql} Freiformat-Eingaben: Es sammelt Eingabezeilen,
+führt sie aber solange nicht aus, bis es das Semikolon sieht.)
+
+Hier ist ein einfaches Statement, auf mehrere Zeilen verteilt:
+
+@example
+mysql> SELECT
+ -> USER()
+ -> ,
+ -> CURRENT_DATE;
++--------------------+--------------+
+| USER() | CURRENT_DATE |
++--------------------+--------------+
+| joesmith@@localhost | 1999-03-18 |
++--------------------+--------------+
+@end example
+
+Sehen Sie, wie sich die Eingabeaufforderung von @code{mysql>} zu @code{->}
+ändert, nachdem Sie die erste Zeile der Mehrzeilen-Anfrage eingegeben
+haben. Auf diese Weise zeigt @code{mysql} an, dass es noch nicht das
+komplette Statement gesehen hat und auf den Rest wartet. Die
+Eingabeaufforderung ist Ihr Freund, denn sie stellt wertvolle Rückmeldungen
+zur Verfügung. Wenn Sie diese Rückmeldungen nutzen, werden Sie immer dessen
+gewahr sein, worauf @code{mysql} wartet.
+
+Wenn Sie den Befehl, den Sie gerade eingeben, nicht ausführen wollen,
+können Sie ihn mit @code{\c} abbrechen:
+
+@example
+mysql> SELECT
+ -> USER()
+ -> \c
+mysql>
+@end example
+
+Beachten Sie auch hierbei die Eingabeaufforderung. Sie ändert sich zurück
+zu @code{mysql>}, nachdem Sie @code{\c} eingegeben haben, und diese
+Rückmeldung bedeutet, dass @code{mysql} für einen weiteren Befehl bereit
+ist.
+
+Folgende Tabelle zeigt alle Eingabeaufforderungen, denen Sie begegnen
+können, und fasst zusammen, was sie über den Zustand von @code{mysql}
+aussagen:
+
+@cindex Eingabeaufforderungen, Bedeutungen
+@multitable @columnfractions .10 .9
+@item @strong{Eingabeaufforderung} @tab @strong{Bedeutung}
+@item @code{mysql>} @tab Bereit für den nächsten Befehl.
+@item @code{@ @ @ @ ->} @tab Wartet auf die nächste Zeile eines
+mehrzeiligen Befehls.
+@item @code{@ @ @ @ '>} @tab Wartet auf die nächste Zeile und
+fasst eine Zeichenkette zusammen, die mit einem Apostroph (@samp{'})
+beginnt.
+@item @code{@ @ @ @ ">} @tab Wartet auf die nächste Zeile und
+fasst eine Zeichenkette zusammen, die mit Anführungszeichen (@samp{"})
+beginnt.
+@end multitable
+
+Mehrzeilige Statements passieren häufig aus Versehen, wenn Sie vorhaben,
+einen Befehl auf einer einzelnen Zeile abzusetzen, aber das beendende
+Semikolon vergessen. In diesem Fall wartet @code{mysql} auf weitere
+Eingaben:
+
+@example
+mysql> SELECT USER()
+ ->
+@end example
+
+Wenn so etwas passiert (Sie dachten, Sie hätten ein Statement eingegeben,
+aber die einzige Antwort ist die @code{->}-Eingabeaufforderung), wartet
+@code{mysql} höchstwahrscheinlich auf das Semikolon. Wenn Sie nicht darauf
+achten, was Ihnen die Eingabeaufforderung mitteilen will, könnten Sie eine
+ganze Weile herum sitzen, bevor Sie feststellen, was Sie tun müssen. Geben
+Sie ein Semikolon ein, um das Statement zu vollenden, und @code{mysql} wird
+es ausführen:
+
+@example
+mysql> SELECT USER()
+ -> ;
++--------------------+
+| USER() |
++--------------------+
+| joesmith@@localhost |
++--------------------+
+@end example
+
+Die @code{'>}- und @code{">}-Eingabeaufforderungen kommen bei der Sammlung
+von Zeichenketten vor. In MySQL können Sie Zeichenketten wahlweise in
+@samp{'}- oder @samp{"}-Zeichen eingeschlossen eingeben (zum Beispiel
+@code{'hallo'} oder @code{"tschüß"}), und @code{mysql} läßt Sie auch
+Zeichenketten eingeben, die sich über mehrere Zeilen erstrecken. Wenn Sie
+eine @code{'>}- oder @code{">}-Eingabeaufforderung sehen, heißt das, dass
+Sie eine Zeile eingegeben haben, die eine Zeichenkette enthält, die mit
+@samp{'} oder @samp{"} beginnt, dass Sie aber noch nicht das entsprechende
+beendende Zeichen (ebenfalls @samp{'} oder @samp{"}) eingegeben haben. Das
+ist in Ordnung, wenn Sie tatsächlich eine mehrzeilige Zeichenkette
+eingeben, aber wie wahrscheinlich ist das? Nicht sehr wahrscheinlich.
+Wahrscheinlicher ist, dass die @code{'>}- und
+@code{">}-Eingabeaufforderungen anzeigen, dass Sie versehentlich ein
+@samp{'}- oder @samp{"}-Zeichen ausgelassen haben. Beispiel:
+
+@example
+mysql> SELECT * FROM meine_tabelle WHERE name = "Schmidt AND age < 30;
+ ">
+@end example
+
+Wenn Sie dieses @code{SELECT}-Statement eingeben, dann EINGABE drücken und
+auf das Ergebnis warten, wird nichts passieren. Statt sich zu fragen, warum
+diese Anfrage so lange dauert, beachten Sie des Rätsels Lösung, die die
+@code{">}-Eingabeaufforderung anzeigt. Sie sagt Ihnen, dass @code{mysql}
+auf den Rest einer nicht beendeten Zeichenkette wartet. (Sehen Sie den
+Fehler im Statement? Der Zeichenkette @code{"Schmidt} fehlt das zweite
+Anführungszeichen.)
+
+Was machen Sie in diesem Fall? Das einfachste ist, den Befehl abzubrechen.
+Sie können jetzt allerdings nicht einfach @code{\c} eingeben, weil
+@code{mysql} es als Teil der Zeichenkette interpretieren würde, die es
+gerade sammelt! Geben Sie daher zuerst das schließende Anführungszeichen
+ein, damit @code{mysql} weiß, dass die Zeichenkette zuende ist, und erst
+danach @code{\c}:
+
+@example
+mysql> SELECT * FROM meine_tabelle WHERE name = "Schmidt AND age < 30;
+ "> "\c
+mysql>
+@end example
+
+Die Eingabeaufforderung ändert sich wieder zu @code{mysql>} und zeigt damit
+an, dass @code{mysql} für einen weiteren Befehl bereit ist.
+
+Es ist wichtig, die Bedeutung der @code{'>}- und
+@code{">}-Eingabeaufforderungen zu kennen, denn wenn Sie versehentlich
+eine nicht beendete Zeichenkette eingeben, werden alle folgenden Zeilen,
+die Sie eingeben, von @code{mysql} ignoriert - inklusive einer Zeile, die
+@code{QUIT} enthält! Das kann recht verwirrend sein, besonders dann, wenn
+Sie nicht wissen, dass Sie das schließende Anführungszeichen eingeben
+müssen, bevor Sie den aktuellen Befehl abbrechen können.
+
+
+@node Database use, Getting information, Entering queries, Tutorial
+@c German node Datenbankbenutzung
+@section Eine Datenbank erzeugen und benutzen
+
+@cindex Datenbanken, erzeugen
+@cindex Datenbanken, benutzen
+@cindex Erzeugen, Datenbanken
+
+
+Jetzt, wo Sie wissen, wie Sie Befehle eingeben, ist es Zeit, auf eine
+Datenbank zuzugreifen.
+
+Nehmen wir an, Sie haben zuhause mehrere Haustiere (Ihre Menagerie) und Sie
+wollen unterschiedliche Arten von Information über sie im Überblick
+behalten. Das können Sie tun, indem Sie Tabellen erzeugen, die Ihre Daten
+beinhalten, und die Sie mit den gewünschten Informationen füllen. Dann
+können Sie verschiedene Arten von Fragen über Ihre Haustiere beantworten,
+indem Sie Daten aus den Tabellen abrufen. Dieser Abschnitt zeigt Ihnen:
+
+@itemize @bullet
+@item
+Wie Sie eine Datenbank erzeugen
+@item
+Wie Sie eine Tabelle anlegen
+@item
+Wie Sie Daten in die Tabelle laden
+@item
+Wie Sie auf unterschiedliche Weise Daten aus der Tabelle abfragen
+@item
+Wie Sie mehrere Tabellen benutzen
+@end itemize
+
+Die Menagerie-Datenbank wird (bewusst) einfach sein, aber man kann sich
+leicht Situationen im echten Leben vorstellen, in denen ein ähnlicher Typ
+von Datenbank benutzt werden könnte. Beispielsweise könnte ein Bauer eine
+solche Datenbankbenutzung, um den Überblick über sein Vieh zu behalten,
+oder ein Tierarzt, um seine Patientendaten im Griff zu haben. Sie finden
+eine Menagerie-Distribution, die einige der benutzten Anfragen und
+Beispielsdaten enthält, auf der MySQL-Website.
+Sie finden die Distribution entweder unter
+@uref{http://www.mysql.com/downloads/Contrib/Examples/menagerie.tar.gz,komprimiertes @code{tar}-Format}
+oder unter
+@uref{http://www.mysql.com/downloads/Contrib/Beispiele/menagerie.zip,Zip-Format}.
+
+Benutzen Sie das @code{SHOW}-Statement, um herauszufinden, welche
+Datenbanken zur Zeit auf dem Server existieren:
+
+@example
+mysql> SHOW DATABASES;
++----------+
+| database |
++----------+
+| mysql |
+| test |
+| tmp |
++----------+
+@end example
+
+Die Liste der Datenbanken weicht wahrscheinlich von derjenigen auf Ihrer
+Maschine ab, aber wahrscheinlich befinden sich die @code{mysql}- und
+@code{test}-Datenbanken darunter. Die @code{mysql}-Datenbank ist notwendig,
+weil darin die Zugriffsrechte für Benutzer gespeichert sind. Die
+@code{test}-Datenbank ist meist als Arbeitsbereich zum Ausprobieren dabei.
+
+Wenn die @code{test}-Datenbank existiert, versuchen Sie, darauf
+zuzugreifen:
+
+@example
+mysql> USE test
+database changed
+@end example
+
+Beachten Sie, dass @code{USE} - wie @code{QUIT} - kein Semikolon erfordert.
+(Sie können solche Statements mit einem Semikolon beenden, wenn Sie wollen,
+es schadet nicht.) Das @code{USE}-Statement ist auch auf andere Art
+besonders: Es muss auf einer einzigen Zeile eingegeben werden.
+
+Sie können die @code{test}-Datenbank für die folgenden Beispiele benutzen
+(wenn Sie Zugriff darauf haben), aber alles, was Sie dort anlegen, kann von
+jedem sonstigen, der Zugriff darauf hat, entfernt werden. Aus diesem Grund
+sollten Sie besser Ihren MySQL-Administrator um Erlaubnis bitten, eine
+eigene Datenbankbenutzung zu können. Nehmen wir an, Sie wollen Ihre
+Datenbank @code{menagerie} nennen. Dafür muss der Administrator folgenden
+Befehl eingeben:
+
+@example
+mysql> GRANT ALL ON menagerie.* TO ihr_mysql_name;
+@end example
+
+Wobei @code{ihr_mysql_name} der MySQL-Benutzername ist, der Ihnen
+zugewiesen wurde.
+
+
+@menu
+* Creating database::
+* Creating tables::
+* Loading tables::
+* Retrieving data::
+@end menu
+
+@node Creating database, Creating tables, Database use, Database use
+@c German node Datenbank erzeugen
+@subsection Eine Datenbank erzeugen und auswählen
+
+@cindex Auswählen, Datenbanken
+@cindex Datenbanken, auswählen
+
+Wenn der Administrator für Sie eine Datenbank erzeugt, wenn er Ihre
+Zugriffsrechte einträgt, können Sie sie unmittelbar benutzen. Ansonsten
+müssen Sie sie selbst anlegen:
+
+@example
+mysql> CREATE DATABASE menagerie;
+@end example
+
+Unter Unix sind Datenbanknamen abhängig von der Groß-/Kleinschreibung (im
+Gegensatz zu SQL-Schlüsselwörtern), daher müssen Sie sich auf Ihre
+Datenbank immer mit @code{menagerie} beziehen, nicht mit @code{Menagerie},
+@code{MENAGERIE} oder irgend einer anderen Variante. Dasselbe gilt für
+Tabellennamen. (Unter Windows trifft diese Beschränkung nicht zu. Dennoch
+muss man sich bei einer gegebenen Anfrage auf Datenbanken und Tabellen in
+derselben Schreibweise beziehen.)
+
+Das Erzeugen einer Datenbank wählt diese nicht zur Benutzung aus. Das
+müssen Sie explizit tun. Um @code{menagerie} zur aktuell ausgewählten
+Datenbank zu machen, benutzen Sie folgenden Befehl:
+
+@example
+mysql> USE menagerie
+database changed
+@end example
+
+Ihre Datenbank muss nur einmal erzeugt werden, aber Sie müssen sie jedes
+Mal zur Benutzung auswählen, wenn Sie eine @code{mysql}-Sitzung beginnen.
+Das können Sie durch die Eingabe eines @code{USE}-Statements wie oben
+beschrieben tun. Alternativ können Sie die Datenbank auf der Kommandozeile
+auswählen, wenn Sie @code{mysql} aufrufen. Geben Sie einfach ihren Namen
+nach den Verbindungsparametern ein, die Sie ansonsten eingeben müssen.
+Beispiel:
+
+@example
+shell> mysql -h host -u user -p menagerie
+Enter password: ********
+@end example
+
+Beachten Sie, dass @code{menagerie} auf der gezeigten Kommandozeile nicht
+Ihr Passwort ist! Wenn Sie Ihr Passwort auf der Kommandozeile nach der
+@code{-p}-Option eingeben wollen, müssen Sie das ohne Leerzeichen
+dazwischen machen (beispielsweise als @code{-pmeinpasswort}, nicht als
+@code{-p meinpasswort}). Es wird allerdings nicht empfohlen, das Passwort
+auf der Kommandozeile einzugeben, denn dann kann es durch andere Benutzer,
+die auf Ihrer Maschine eingeloggt sind, ausspioniert werden.
+
+
+@node Creating tables, Loading tables, Creating database, Database use
+@c German node Tabellen erzeugen
+@subsection Eine Tabelle erzeugen
+
+@cindex Tabellen, erzeugen
+@cindex Erzeugen, Tabellen
+Die Datenbank zu erzeugen ist leicht, aber bis jetzt ist sie noch leer, wie
+Ihnen @code{SHOW TABLES} zeigt:
+
+@example
+mysql> SHOW TABLES;
+Empty set (0.00 sec)
+@end example
+
+Der schwierigere Teil besteht darin, sich zu entscheiden, wie die Struktur
+Ihrer Datenbank sein sollte: Welche Tabellen Sie benötigen und welche
+Spalten in jeder Tabelle enthalten sein sollen.
+
+Sie brauchen eine Tabelle, die für jedes Ihrer Haustiere einen Datensatz
+enthält. Diese kann @code{pet}-Tabelle genannt werden, und sie sollte
+zumindest den Namen jedes Tiers enthalten. Weil lediglich der Name nicht
+besonders interessant ist, sollte die Tabelle weitere Informationen
+enthalten. Wenn zum Beispiel mehr als eine Person in Ihrer Familie ein
+Haustier hält, würden Sie den Namen des Besitzers jedes Haustiers auflisten
+wollen. Ausserdem wollen Sie vielleicht ein paar grundlegende Informationen
+wie Art und Geschlecht einfügen.
+
+Was ist mit dem Alter? Diese Information könnte interessant sein, aber es
+ist keine gute Idee, sie in der Datenbank zu speichern. Das Alter ändert
+sich, wenn die Zeit vergeht, was bedeutet, dass Sie Ihre Datensätze oft
+aktualisieren müssen. Statt dessen ist es besser, einen festen Wert wie das
+Geburtsdatum zu speichern. Immer, wenn Sie dann das Alter benötigen,
+berechnen Sie es als Differenz zwischen dem aktuellen Datum und dem
+Geburtstag. MySQL stellt Funktionen für Datumsberechnungen zur Verfügung,
+daher ist so etwas nicht schwer. Ausserdem hat die Speicherung von
+Geburtsdaten anstelle von Alter weitere Vorteile:
+
+@itemize @bullet
+@item
+Sie können die Datenbank für Aufgaben wie die Erzeugung einer Liste
+bevorstehender Tier-Geburtstage benutzen. (Wenn Sie das etwas albern
+finden, bedenken Sie, dass sich dieselbe Frage zum Beispiel bei einer
+Geschäftsdatenbank stellt, um Kunden herauszufinden, denen Sie in Kürze
+Geburtstagswünsche schicken wollen, also für die Computer-unterstützte
+persönliche Note.)
+
+@item
+Sie können Altersberechnungen mit anderen Bezugsdaten als dem aktuellen
+Datum durchführen. Wenn Sie das Sterbedatum speichern, können Sie zum
+Beispiel leicht errechnen, wie alt ein Haustier war, als es starb.
+@end itemize
+
+Wahrscheinlich fallen Ihnen weitere Informationen ein, die sinnvoller Weise
+in der @code{pet}-Tabelle gespeichert werden könnten. Für unser Beispiel
+sollen die bisher identifizierten Informationen fürs Erste ausreichen:
+Name, Besitzer, Art, Geschlecht, Geburtstag und Sterbetag.
+
+Legen Sie mit einem @code{CREATE TABLE}-Statement das Layout Ihrer Tabelle
+fest:
+
+@example
+mysql> CREATE TABLE pet (name VARCHAR(20), besitzer VARCHAR(20),
+ -> art VARCHAR(20), geschlecht CHAR(1), geburtstag DATE, sterbetag DATE);
+@end example
+
+@code{VARCHAR} ist für die @code{name}-, @code{besitzer}- und
+@code{art}-Spalten eine gute Wahl, weil die Spaltenwerte in der Länge
+variieren werden. Diese Spalten müssen auch nicht alle gleich sein, also
+@code{20} Zeichen lang. Sie können jede beliebige Länge zwischen @code{1}
+und @code{255} wählen, was immer Ihnen vernünftig erscheint. (Wenn Sie eine
+schlechte Wahl getroffen haben und sich später herausstellt, dass Sie eine
+längere Spalte brauchen, stellt MySQL ein @code{ALTER TABLE}-Statement zur
+Verfügung.)
+
+Das Geschlecht der Tiere kann vielfältig dargestellt werden, zum Beispiel
+als @code{"m"} und @code{"w"}, oder auch als @code{"männlich"} und
+@code{"weiblich"}. Am einfachsten ist es, hierfür einzelne Zeichen wie
+@code{"m"} und @code{"w"} zu verwenden.
+
+Der @code{DATE}-Datentyp für @code{geburtstag} und @code{sterbetag} liegt
+auf der Hand.
+
+Nachdem Sie eine Tabelle angelegt haben, sollte @code{SHOW TABLES} auch
+etwas zeigen:
+
+@example
+mysql> SHOW TABLES;
++---------------------+
+| Tables in menagerie |
++---------------------+
+| pet |
++---------------------+
+@end example
+
+Um sicherzustellen, dass Ihre Tabelle so wie erwartet angelegt wurde,
+benutzen Sie das @code{DESCRIBE}-Statement:
+
+@example
+mysql> DESCRIBE pet;
++------------+-------------+------+-----+---------+-------+
+| Field | Type | Null | Key | Default | Extra |
++------------+-------------+------+-----+---------+-------+
+| name | varchar(20) | YES | | NULL | |
+| besitzer | varchar(20) | YES | | NULL | |
+| art | varchar(20) | YES | | NULL | |
+| geschlecht | char(1) | YES | | NULL | |
+| geburtstag | date | YES | | NULL | |
+| sterbetag | date | YES | | NULL | |
++------------+-------------+------+-----+---------+-------+
+@end example
+
+Sie können @code{DESCRIBE} jederzeit benutzen, zum Beispiel, wenn Sie die
+Namen der Spalten Ihrer Tabelle vergessen haben oder von welchem Datentyp
+sie sind.
+
+
+@node Loading tables, Retrieving data, Creating tables, Database use
+@c German node Tabellen füllen
+@subsection Daten in Tabellen einladen
+
+@cindex Einladen, Tabellen
+@cindex Tabellen, Daten einladen
+@cindex Daten, in Tabellen laden
+
+Nachdem Sie Ihre Tabelle erzeugt haben, müssen Sie sie mit Daten füllen.
+Hierfür sind die @code{LOAD DATA}- und @code{INSERT}-Statements nützlich.
+
+Nehmen wir an, Sie haben Haustiere wie unten aufgeführt. (Achten Sie bei
+den Datumsangaben bitte darauf, dass MySQL Daten im
+@code{YYYY-MM-DD}-Format erwartet, was von dem Format abweichen kann, an
+das Sie gewohnt sind.)
+
+@multitable @columnfractions .16 .16 .16 .16 .16 .16
+@item @strong{name} @tab @strong{besitzer} @tab @strong{art} @tab @strong{geschlecht} @tab @strong{geburtstag} @tab @strong{sterbetag}
+@item Fluffy @tab Harold @tab Katze @tab w @tab 1993-02-04 @tab
+@item Claws @tab Gwen @tab Katze @tab m @tab 1994-03-17 @tab
+@item Buffy @tab Harold @tab Hund @tab w @tab 1989-05-13 @tab
+@item Fang @tab Benny @tab Hund @tab m @tab 1990-08-27 @tab
+@item Bowser @tab Diane @tab Hund @tab m @tab 1998-08-31 @tab 1995-07-29
+@item Chirpy @tab Gwen @tab Vogel @tab w @tab 1998-09-11 @tab
+@item Whistler @tab Gwen @tab Vogel @tab @tab 1997-12-09 @tab
+@item Slim @tab Benny @tab Schlange @tab m @tab 1996-04-29 @tab
+@end multitable
+
+Weil Sie mit einer leeren Tabelle beginnen, ist eine einfache Möglichkeit,
+diese mit Daten zu füllen, dass Sie eine Textdatei erzeugen, die eine Zeile
+für jedes Ihrer Tiere enthält, und die Inhalte dieser Datei dann mit einem
+einzigen Statement in die Tabelle laden.
+
+Erzeugen Sie also eine Textdatei @file{pet.txt}, die einen Datensatz pro
+Zeile enthält, mit Werten, die durch TAB-Zeichen getrennt sind, und zwar in
+der Reihenfolge, in der die Spalten im @code{CREATE TABLE}-Statement
+aufgeführt waren. Fehlende Werte (wie unbekanntes Geschlecht oder
+Sterbedaten für Tiere, die noch leben) ersetzen Sie mit @code{NULL}-Werten.
+Um das in Ihrer Textdatei darzustellen, nehmen Sie @code{\N}. Der Datensatz
+für den Vogel Whistler zum Beispiel sieht wie folgt aus (wobei der Leerraum
+zwischen den Werten ein einzelnes TAB-Zeichen darstellt):
+
+@multitable @columnfractions .15 .15 .15 .15 .25 .15
+@item @code{Whistler} @tab @code{Gwen} @tab @code{Vogel} @tab @code{\N} @tab @code{1997-12-09} @tab @code{\N}
+@end multitable
+
+Um die Textdatei @file{pet.txt} in die @code{pet}-Tabelle zu laden,
+benutzen Sie folgenden Befehl:
+
+@example
+mysql> LOAD DATA LOCAL INFILE "pet.txt" INTO TABLE pet;
+@end example
+
+Sie können das Trennzeichen für die Spalten und das Zeichen für Zeilenende
+im @code{LOAD DATA}-Statement explizit festlegen, wenn Sie wollen, aber
+vorgabemäßig sind das das TAB-Zeichen und das Zeilenvorschub-Zeichen. Das
+reicht für das Statement aus, um die Datei @file{pet.txt} korrekt
+einzulesen.
+
+Wenn Sie einzeln neue Datensätze hinzufügen wollen, ist das
+@code{INSERT}-Statement nützlich. In seiner einfachsten Form geben Sie für
+jede Spalte Werte an, in genau der Reihenfolge, in der die Spalten im
+@code{CREATE TABLE}-Statement aufgeführt wurden. Nehmen wir an, dass Diane
+einen neuen Hamster namens Puffball bekommt. Sie fügen einen neuen
+Datensatz mittels @code{INSERT}-Statement wie folgt hinzu:
+
+@example
+mysql> INSERT INTO pet
+ -> VALUES ('Puffball','Diane','Hamster','w','1999-03-30',NULL);
+@end example
+
+Beachten Sie, dass hierbei Zeichenketten- und Datumswerte in
+Anführungszeichen stehen. Mit @code{INSERT} können Sie auch direkt
+@code{NULL} einfügen, um einen fehlenden Wert darzustellen. Sie können
+dafür nicht @code{\N} wie bei @code{LOAD DATA} verwenden.
+
+Diesem Beispiel können Sie auch entnehmen, dass es einiger Tipparbeit
+bedurft hätte, die anfänglichen Datensätze mit mehreren
+@code{INSERT}-Statements einzufügen, statt hierfür ein einziges @code{LOAD
+DATA}-Statement zu verwenden.
+
+
+@node Retrieving data, , Loading tables, Database use
+@c German node Daten abrufen
+@subsection Informationen aus einer Tabelle abfragen
+
+@cindex Daten, abrufen
+@cindex Tabellen, Daten abrufen
+@cindex Abrufen, Daten aus Tabellen
+@cindex Entladen, Tabellen
+
+
+Das @code{SELECT}-Statement wird benutzt, um Informationen aus einer
+Tabelle herauszuziehen. Die allgemeine Form des Statements ist:
+
+@example
+SELECT auszuwählende_spalten
+FROM tabelle
+WHERE gewünschte_bedingungen
+@end example
+
+@code{auszuwählende_spalten} bezeichnet, was Sie sehen wollen. Das kann
+entweder eine Liste von Spalten sein oder @code{*}, um ``alle Spalten'' zu
+bezeichnen. @code{tabelle} kennzeichnet die Tabelle, aus der Sie Spalten
+abfragen wollen. Die @code{WHERE}-Klausel ist optional. Wenn sie vorhanden
+ist, kennzeichnet @code{gewünschte_bedingungen} die Bedingungen, mit denen
+die Zeilen übereinstimmen müssen, damit sie abgefragt werden.
+
+
+@menu
+* Selecting all::
+* Selecting rows::
+* Selecting columns::
+* Sorting rows::
+* Date calculations::
+* Working with NULL::
+* Pattern matching::
+* Counting rows::
+* Multiple tables::
+@end menu
+
+@node Selecting all, Selecting rows, Retrieving data, Retrieving data
+@c German node Alles auswählen
+@subsubsection Alle Daten auswählen
+
+Die einfachste Form von @code{SELECT} fragt alles aus einer Tabelle ab:
+
+@example
+mysql> SELECT * FROM pet;
++----------+----------+----------+------------+------------+------------+
+| name | besitzer | art | geschlecht | geburtstag | sterbetag |
++----------+----------+----------+------------+------------+------------+
+| Fluffy | Harold | Katze | w | 1993-02-04 | NULL |
+| Claws | Gwen | Katze | m | 1994-03-17 | NULL |
+| Buffy | Harold | Hund | w | 1989-05-13 | NULL |
+| Fang | Benny | Hund | m | 1990-08-27 | NULL |
+| Bowser | Diane | Hund | m | 1998-08-31 | 1995-07-29 |
+| Chirpy | Gwen | Vogel | w | 1998-09-11 | NULL |
+| Whistler | Gwen | Vogel | NULL | 1997-12-09 | NULL |
+| Slim | Benny | Schlange | m | 1996-04-29 | NULL |
+| Puffball | Diane | Hamster | w | 1999-03-30 | NULL |
++----------+----------+----------+------------+------------+------------+
+@end example
+
+Diese Form von @code{SELECT} ist nützlich, wenn Sie Ihre gesamte Tabelle
+abfragen wollen, zum Beispiel, wenn Sie sich gerade mit einem anfänglichen
+Satz Daten geladen haben. Wie das so passiert, zeigt die Ausgabe einen
+Fehler auf: Bowser scheint gestorben zu sein, bevor er geboren wurde! In
+den Original-Stammbaum-Papieren finden Sie, dass das korrekte Geburtsjahr
+1989 ist, nicht 1998.
+
+Es gibt eine ganze Reihe Möglichkeiten, das zu beheben:
+
+@itemize @bullet
+@item
+Editieren Sie die Datei @file{pet.txt} und beheben Sie den Fehler. Leeren
+Sie dann die Tabelle und laden Sie erneut Daten hinein, indem Sie zuerst
+@code{DELETE} und dann @code{LOAD DATA} benutzen:
+
+@example
+mysql> SET AUTOCOMMIT=1; # Für schnelles Neuerzeugen der Tabelle
+mysql> DELETE FROM pet;
+mysql> LOAD DATA LOCAL INFILE "pet.txt" INTO TABLE pet;
+@end example
+
+Wenn Sie das jedoch tun, müssen Sie die Daten für Puffball erneut eingeben.
+
+@item
+Den fehlerhaften Datensatz mit einem @code{UPDATE}-Statement in Ordnung
+bringen:
+
+@example
+mysql> UPDATE pet SET geburtstag = "1989-08-31" WHERE name = "Bowser";
+@end example
+@end itemize
+
+Wie gezeigt ist es einfach, eine ganze Tabelle abzufragen. Aber
+typischerweise wird das selten gewünscht sein, besonders, wenn die Tabelle
+Groß wird. Statt dessen werden Sie an der Antwort auf bestimmte Fragen
+interessiert sein, wobei Sie ein paar Beschränkungen in Bezug auf die
+Informationen, die Sie wollen, festlegen. Schauen wir uns einige
+Auswahl-Anfragen an, hinsichtlich der Fragen in Bezug auf Ihre Haustiere,
+die sie beantworten.
+
+
+@node Selecting rows, Selecting columns, Selecting all, Retrieving data
+@c German node Zeilen auswählen
+@subsubsection Bestimmte Zeilen auswählen
+
+@cindex Zeilen, auswählen
+@cindex Tabellen, Zeilen auswählen
+
+Sie können nur bestimmte Zeilen Ihrer Tabelle auswählen. Wenn Sie zum
+Beispiel die Geburtstags-Änderung von Bowser überprüfen wollen, wählen Sie
+Bowsers Datensatz wie folgt aus:
+
+@example
+mysql> SELECT * FROM pet WHERE name = "Bowser";
++--------+----------+---------+-------------+------------+------------+
+| name | besitzer | art | geschlecht | geburtstag | sterbetag |
++--------+----------+---------+-------------+------------+------------+
+| Bowser | Diane | dog | m | 1989-08-31 | 1995-07-29 |
++--------+----------+---------+-------------+------------+------------+
+@end example
+
+
+Die Ausgabe bestätigt, dass das Jahr inzwischen korrekt als 1989, nicht
+1998, eingetragen ist.
+
+Vergleiche von Zeichenketten achten normalerweise nicht auf
+Groß-/Kleinschreibung, daher können Sie den Namen als @code{"bowser"},
+@code{"BOWSER"} usw. angeben. Das Anfrageergebnis wird dasselbe bleiben.
+
+Sie können für jede Spalte Bedingungen festlegen, nicht nur für
+@code{name}. Wenn Sie zum Beispiel wissen wollen, welche Tiere nach 1998
+geboren wurden, formulieren Sie eine Bedingung für die
+@code{geburtstag}-Spalte:
+
+@example
+mysql> SELECT * FROM pet WHERE geburtstag >= "1998-1-1";
++----------+----------+---------+-------------+------------+-----------+
+| name | besitzer | art | geschlecht | geburtstag | sterbetag |
++----------+----------+---------+-------------+------------+-----------+
+| Chirpy | Gwen | Vogel | w | 1998-09-11 | NULL |
+| Puffball | Diane | Hamster | w | 1999-03-30 | NULL |
++----------+----------+---------+-------------+------------+-----------+
+@end example
+
+Sie können Bedingungen kombinieren, um zum Beispiel weibliche Hunde
+festzustellen:
+
+@example
+mysql> SELECT * FROM pet WHERE art = "Hund" AND geschlecht = "w";
++-------+-----------+---------+------------+------------+-----------+
+| name | besitzer | art | geschlecht | geburtstag | sterbetag |
++-------+-----------+---------+------------+------------+-----------+
+| Buffy | Harold | Hund | w | 1989-05-13 | NULL |
++-------+-----------+---------+------------+------------+-----------+
+@end example
+
+Die vorherige Anfrage benutzt den logischen Operator @code{AND}. Es gibt
+auch einen @code{OR}-Operator:
+
+@example
+mysql> SELECT * FROM pet WHERE art = "Schlange" OR art = "Vogel";
++----------+----------+---------+-------------+------------+-----------+
+| name | besitzer | art | geschlecht | geburtstag | sterbetag |
++----------+----------+---------+-------------+------------+-----------+
+| Chirpy | Gwen | Vogel | w | 1998-09-11 | NULL |
+| Whistler | Gwen | Vogel | NULL | 1997-12-09 | NULL |
+| Slim | Benny | Schlange| m | 1996-04-29 | NULL |
++----------+----------+---------+-------------+------------+-----------+
+@end example
+
+@code{AND} und @code{OR} können gemischt werden. Wenn Sie das tun, ist es
+eine gute Idee, Klammern zu verwenden, um anzuzeigen, wie die Bedingungen
+gruppiert werden sollen:
+
+@example
+mysql> SELECT * FROM pet WHERE (art = "Katze" AND geschlecht = "m")
+ -> OR (art = "Hund" AND geschlecht = "w");
++-------+-----------+---------+-------------+------------+-----------+
+| name | besitzer | art | geschlecht | geburtstag | sterbetag |
++-------+-----------+---------+-------------+------------+-----------+
+| Claws | Gwen | Katze | m | 1994-03-17 | NULL |
+| Buffy | Harold | Hund | w | 1989-05-13 | NULL |
++-------+-----------+---------+-------------+------------+-----------+
+@end example
+
+
+@node Selecting columns, Sorting rows, Selecting rows, Retrieving data
+@c German node Spalten auswählen
+@subsubsection Bestimmte Spalten auswählen
+
+@cindex Spalten, auswählen
+@cindex Tabellen, Spalten auswählen
+
+Wenn Sie nicht ganze Zeilen Ihrer Tabelle sehen wollen, geben Sie einfach
+die Spalten an, an denen Sie interessiert sind, getrennt durch Kommas. Wenn
+Sie zum Beispiel wissen wollen, wann Ihre Tiere geboren wurden, wählen Sie
+die @code{name}- und @code{geburtstag}-Spalten aus:
+
+@example
+mysql> SELECT name, geburtstag FROM pet;
++----------+------------+
+| name | geburtstag |
++----------+------------+
+| Fluffy | 1993-02-04 |
+| Claws | 1994-03-17 |
+| Buffy | 1989-05-13 |
+| Fang | 1990-08-27 |
+| Bowser | 1989-08-31 |
+| Chirpy | 1998-09-11 |
+| Whistler | 1997-12-09 |
+| Slim | 1996-04-29 |
+| Puffball | 1999-03-30 |
++----------+------------+
+@end example
+
+Um herauszufinden, wem welches Haustier gehört, benutzen Sie diese Anfrage:
+
+@example
+mysql> SELECT besitzer FROM pet;
++----------+
+| besitzer |
++----------+
+| Harold |
+| Gwen |
+| Harold |
+| Benny |
+| Diane |
+| Gwen |
+| Gwen |
+| Benny |
+| Diane |
++----------+
+@end example
+
+@findex DISTINCT
+Beachten Sie jedoch, dass diese Anfrage einfach die @code{besitzer}-Spalte
+jedes Datensatzes abfragt, wodurch mehrere von ihnen mehrfach erscheinen.
+Um die Ausgabe zu minimieren, fragen Sie jeden eindeutigen Datensatz nur
+einmal ab, indem Sie das Schlüsselwort @code{DISTINCT} verwenden:
+
+@example
+mysql> SELECT DISTINCT besitzer FROM pet;
++-----------+
+| besitzer |
++-----------+
+| Benny |
+| Diane |
+| Gwen |
+| Harold |
++-----------+
+@end example
+
+Sie können eine @code{WHERE}-Klausel verwenden, um die Auswahl von Zeilen
+mit der Auswahl von Spalten zu kombinieren. Um zum Beispiel nur die
+Geburtstage von Hunden und Katzen zu erhalten, benutzen Sie diese Anfrage:
+
+@example
+mysql> SELECT name, art, geburtstag FROM pet
+ -> WHERE art = "Hund" OR art = "Katze";
++--------+---------+------------+
+| name | art | geburtstag |
++--------+---------+------------+
+| Fluffy | Katze | 1993-02-04 |
+| Claws | Katze | 1994-03-17 |
+| Buffy | Hund | 1989-05-13 |
+| Fang | Hund | 1990-08-27 |
+| Bowser | Hund | 1989-08-31 |
++--------+---------+------------+
+@end example
+
+
+@node Sorting rows, Date calculations, Selecting columns, Retrieving data
+@c German node Zeilen sortieren
+@subsubsection Zeilen sortieren
+
+@cindex Zeilen, sortieren
+@cindex sortieren, Tabellenzeilen
+@cindex sortieren, Daten
+@cindex Tabellen, Zeilen sortieren
+
+Sie haben bei den vorherigen Beispielen vielleicht bemerkt, dass die
+Ergebniszeilen in keiner bestimmten Reihenfolge angezeigt werden. Häufig
+ist es jedoch einfacher, die Ausgabe der Anfrage zu überprüfen, wenn die
+Zeilen auf sinnvolle Art sortiert werden. Um ein Ergebnis zu sortieren,
+benutzen Sie die @code{ORDER BY}-Klausel.
+
+Hier sind die Geburtstage der Haustiere, sortiert nach Geburtstag:
+
+@example
+mysql> SELECT name, geburtstag FROM pet ORDER BY geburtstag;
++----------+------------+
+| name | geburtstag |
++----------+------------+
+| Buffy | 1989-05-13 |
+| Bowser | 1989-08-31 |
+| Fang | 1990-08-27 |
+| Fluffy | 1993-02-04 |
+| Claws | 1994-03-17 |
+| Slim | 1996-04-29 |
+| Whistler | 1997-12-09 |
+| Chirpy | 1998-09-11 |
+| Puffball | 1999-03-30 |
++----------+------------+
+@end example
+
+Um in umgekehrter Reihenfolge zu sortieren, fügen Sie das @code{DESC}-
+(descending) Schlüsselwort zum Namen der Spalte, die Sie sortieren wollen,
+hinzu:
+
+@example
+mysql> SELECT name, geburtstag FROM pet ORDER BY geburtstag DESC;
++----------+------------+
+| name | geburtstag |
++----------+------------+
+| Puffball | 1999-03-30 |
+| Chirpy | 1998-09-11 |
+| Whistler | 1997-12-09 |
+| Slim | 1996-04-29 |
+| Claws | 1994-03-17 |
+| Fluffy | 1993-02-04 |
+| Fang | 1990-08-27 |
+| Bowser | 1989-08-31 |
+| Buffy | 1989-05-13 |
++----------+------------+
+@end example
+
+Sie können über mehrere Spalten sortieren. Um beispielsweise zuerst nach
+der Art des Tieres und dann nach dem Geburtsdatum innerhalb der Tierart zu
+sortieren (die jüngsten Tiere zuerst), benutzen Sie folgende Anfrage:
+
+@example
+mysql> SELECT name, art, geburtstag FROM pet ORDER BY art, geburtstag DESC;
++----------+----------+------------+
+| name | art | geburtstag |
++----------+----------+------------+
+| Chirpy | Vogel | 1998-09-11 |
+| Whistler | Vogel | 1997-12-09 |
+| Claws | Katze | 1994-03-17 |
+| Fluffy | Katze | 1993-02-04 |
+| Fang | Hund | 1990-08-27 |
+| Bowser | Hund | 1989-08-31 |
+| Buffy | Hund | 1989-05-13 |
+| Puffball | Hamster | 1999-03-30 |
+| Slim | Schlange | 1996-04-29 |
++----------+----------+------------+
+@end example
+
+Beachten Sie, dass sich das @code{DESC}-Schlüsselwort nur auf die Spalte
+bezieht, die unmittelbar davor steht (@code{geburtstag}). @code{art}-Werte
+werden nach wie vor in aufsteigender Reihenfolge sortiert.
+
+
+@node Date calculations, Working with NULL, Sorting rows, Retrieving data
+@c German node Datumsberechnungen
+@subsubsection Datumsberechnungen
+
+@cindex Datumsberechnungen
+@cindex Berechnungen, Datumswerte
+@cindex Extrahieren, Datumswerte
+@cindex Alter, berechnen
+
+MySQL stellt etliche Funktionen zur Verfügung, mit denen Sie
+Datumsberechnungen wie Altersberechnungen oder das Extrahieren von
+Datumsteilen durchführen können.
+
+Um festzustellen, wie alt jedes Ihrer Haustiere ist, berechnen Sie die
+Differenz im Jahresanteil des aktuellen Datums und des Geburtstags und
+subtrahieren eins, wenn das aktuelle Datum früher im Kalender erscheint als
+das Geburtsdatum. Folgende Anfrage zeigt für jedes Haustier das
+Geburtsdatum, das aktuelle Datum und das Alter in Jahren:
+
+@example
+mysql> SELECT name, geburtstag, CURRENT_DATE,
+ -> (YEAR(CURRENT_DATE)-YEAR(geburtstag))
+ -> - (RIGHT(CURRENT_DATE,5)<RIGHT(geburtstag,5))
+ -> AS age
+ -> FROM pet;
++----------+------------+--------------+------+
+| name | geburtstag | CURRENT_DATE | age |
++----------+------------+--------------+------+
+| Fluffy | 1993-02-04 | 2001-08-29 | 8 |
+| Claws | 1994-03-17 | 2001-08-29 | 7 |
+| Buffy | 1989-05-13 | 2001-08-29 | 12 |
+| Fang | 1990-08-27 | 2001-08-29 | 11 |
+| Bowser | 1989-08-31 | 2001-08-29 | 11 |
+| Chirpy | 1998-09-11 | 2001-08-29 | 2 |
+| Whistler | 1997-12-09 | 2001-08-29 | 3 |
+| Slim | 1996-04-29 | 2001-08-29 | 5 |
+| Puffball | 1999-03-30 | 2001-08-29 | 2 |
++----------+------------+--------------+------+
+@end example
+
+Hier zieht @code{YEAR()} den Jahresanteil eines Datums heraus.
+@code{RIGHT()} zieht die rechts stehenden fünf Zeichen heraus, die für den
+@code{MM-DD}-Teil des Datums stehen. Der Teil in dem Ausdruck, der die
+@code{MM-DD}-Werte vergleicht, wird zu 1 oder 0 ausgewertet, was die
+Jahresdifferenz ein Jahr nach unten anpasst, wenn @code{CURRENT_DATE}
+früher im Jahr erscheint als @code{geburtstag}. Der gesamte Ausdruck ist
+als Überschrift etwas plump, daher wir ein Alias (@code{age}) benutzt, um
+die Spaltenüberschrift etwas lesbarer zu machen.
+
+Die Anfrage funktioniert, aber das Ergebnis könnte leichter überblickt
+werden, wenn die Zeilen in einer bestimmten Reihenfolge angezeigt würden.
+Das kann man erreichen, indem man eine @code{ORDER BY name}-Klausel
+hinzufügt, um die Ausgabe nach Namen zu sortieren:
+
+@example
+mysql> SELECT name, geburtstag, CURRENT_DATE,
+ -> (YEAR(CURRENT_DATE)-YEAR(geburtstag))
+ -> - (RIGHT(CURRENT_DATE,5)<RIGHT(geburtstag,5))
+ -> AS age
+ -> FROM pet ORDER BY name;
++----------+------------+--------------+------+
+| name | geburtstag | CURRENT_DATE | age |
++----------+------------+--------------+------+
+| Bowser | 1989-08-31 | 2001-08-29 | 11 |
+| Buffy | 1989-05-13 | 2001-08-29 | 12 |
+| Chirpy | 1998-09-11 | 2001-08-29 | 2 |
+| Claws | 1994-03-17 | 2001-08-29 | 7 |
+| Fang | 1990-08-27 | 2001-08-29 | 11 |
+| Fluffy | 1993-02-04 | 2001-08-29 | 8 |
+| Puffball | 1999-03-30 | 2001-08-29 | 2 |
+| Slim | 1996-04-29 | 2001-08-29 | 5 |
+| Whistler | 1997-12-09 | 2001-08-29 | 3 |
++----------+------------+--------------+------+
+@end example
+
+Um die Ausgabe nach Alter (@code{age}) statt nach @code{name} zu sortieren,
+benutzen Sie einfach eine andere @code{ORDER BY}-Klausel:
+
+@example
+mysql> SELECT name, geburtstag, CURRENT_DATE,
+ -> (YEAR(CURRENT_DATE)-YEAR(geburtstag))
+ -> - (RIGHT(CURRENT_DATE,5)<RIGHT(geburtstag,5))
+ -> AS age
+ -> FROM pet ORDER BY age;
++----------+------------+--------------+------+
+| name | geburtstag | CURRENT_DATE | age |
++----------+------------+--------------+------+
+| Chirpy | 1998-09-11 | 2001-08-29 | 2 |
+| Puffball | 1999-03-30 | 2001-08-29 | 2 |
+| Whistler | 1997-12-09 | 2001-08-29 | 3 |
+| Slim | 1996-04-29 | 2001-08-29 | 5 |
+| Claws | 1994-03-17 | 2001-08-29 | 7 |
+| Fluffy | 1993-02-04 | 2001-08-29 | 8 |
+| Fang | 1990-08-27 | 2001-08-29 | 11 |
+| Bowser | 1989-08-31 | 2001-08-29 | 11 |
+| Buffy | 1989-05-13 | 2001-08-29 | 12 |
++----------+------------+--------------+------+
+@end example
+
+
+Eine ähnliche Anfrage kann benutzt werden, um das Alter am Sterbetag bei
+Tieren festzustellen, die gestorben sind. Das können Sie feststellen, indem
+Sie überprüfen, ob der @code{sterbetag}-Wert @code{NULL} ist. Dann
+berechnen Sie für diejenigen Tiere mit Nicht-@code{NULL}-Werten den
+Unterschied zwischen @code{sterbetag}- und @code{geburtstag}-Werten:
+
+@example
+mysql> SELECT name, geburtstag, sterbetag,
+ -> (YEAR(sterbetag)-YEAR(geburtstag)) - (RIGHT(sterbetag,5)<RIGHT(geburtstag,5))
+ -> AS age
+ -> FROM pet WHERE sterbetag IS NOT NULL ORDER BY age;
++--------+------------+------------+------+
+| name | geburtstag | sterbetag | age |
++--------+------------+------------+------+
+| Bowser | 1989-08-31 | 1995-07-29 | 5 |
++--------+------------+------------+------+
+@end example
+
+Die Anfrage benutzt @code{sterbetag IS NOT NULL} statt @code{sterbetag !=
+NULL}, weil @code{NULL} ein spezieller Wert ist. Das wird später erklärt.
+@xref{Working with NULL, , Mit @code{NULL}-Werten arbeiten}.
+
+Was ist, wenn Sie wissen wollen, welche Tiere nächsten Monat Geburtstag
+haben? Für diese Art von Berechnung sind Jahre und Tage irrelevant. Sie
+wollen lediglich den Monatsanteil der @code{geburtstag}-Spalte extrahieren.
+MySQL bietet etliche Funktionen für die Extraktion von Datumsanteilen, wie
+@code{YEAR()}, @code{MONTH()} und @code{DAYOFMONTH()}. @code{MONTH()} ist
+hier die richtige Funktion. Um festzustellen, wie sie funktioniert, geben
+Sie eine Anfrage ein, die sowohl die Werte von @code{geburtstag} als auch
+die von @code{MONTH(geburtstag)} ausgibt:
+
+@example
+mysql> SELECT name, geburtstag, MONTH(geburtstag) FROM pet;
++----------+------------+-------------------+
+| name | geburtstag | MONTH(geburtstag) |
++----------+------------+-------------------+
+| Fluffy | 1993-02-04 | 2 |
+| Claws | 1994-03-17 | 3 |
+| Buffy | 1989-05-13 | 5 |
+| Fang | 1990-08-27 | 8 |
+| Bowser | 1989-08-31 | 8 |
+| Chirpy | 1998-09-11 | 9 |
+| Whistler | 1997-12-09 | 12 |
+| Slim | 1996-04-29 | 4 |
+| Puffball | 1999-03-30 | 3 |
++----------+------------+-------------------+
+@end example
+
+Tiere mit Geburtstagen im kommenden Monat zu finden ist ebenfalls leicht.
+Nehmen wir an, der aktuelle Monat ist April. Dann ist der Monatswert
+@code{4} und Sie suchen nach Tieren, die im Mai (Monat 5) geboren sind, wie
+folgt:
+
+@example
+mysql> SELECT name, geburtstag FROM pet WHERE MONTH(geburtstag) = 5;
++-------+------------+
+| name | geburtstag |
++-------+------------+
+| Buffy | 1989-05-13 |
++-------+------------+
+@end example
+
+Ein bisschen komplizierter ist es, wenn der aktuelle Monat Dezember ist.
+Hier können Sie nicht einfach eins zur Monatszahl (@code{12}) hinzufügen,
+weil es keinen 13. Monat gibt. Statt dessen suchen Sie nach Tieren, die im
+Januar (Monat 1) geboren sind.
+
+Sie können die Anfrage sogar so schreiben, dass sie unabhängig davon
+funktioniert, was der aktuelle Monat ist. Auf diese Art brauchen Sie keine
+bestimmte Monatszahl in der Anfrage benutzen. @code{DATE_ADD()} erlaubt
+Ihnen, einem gegebenen Datum ein Zeitintervall hinzuzufügen. Wenn Sie dem
+Wert von @code{NOW()} einen Monat hinzufügen und dann den Monatsanteil mit
+@code{MONTH()} extrahieren, ergibt das den Monat, der die kommenden
+Geburtstage enthält:
+
+@example
+mysql> SELECT name, geburtstag FROM pet
+ -> WHERE MONTH(geburtstag) = MONTH(DATE_ADD(NOW(), INTERVAL 1 MONTH));
+@end example
+
+Eine andere Möglichkeit, diese Aufgabe zu erfüllen, ist, @code{1} zu
+addieren, um den nächsten Monat nach dem aktuellen zu erhalten (nach
+Gebrauch der Modulo-Funktion (@code{MOD}), um den Monatswert auf @code{0}
+zu stellen, falls er aktuell @code{12}) ist:
+
+@example
+mysql> SELECT name, geburtstag FROM pet
+ -> WHERE MONTH(geburtstag) = MOD(MONTH(NOW()), 12) + 1;
+@end example
+
+@code{MONTH} gibt eine Zahl zwischen 1 und 12 zurück.
+@code{MOD(irgendwas,12)} gibt eine Zahl zwischen 0 und 11 zurück. Daher
+muss die Addition nach @code{MOD()} erfolgen, weil wir ansonsten von
+November (11) bis Januar (1) gehen würden.
+
+
+@node Working with NULL, Pattern matching, Date calculations, Retrieving data
+@c German node Mit NULL arbeiten
+@subsubsection Mit @code{NULL}-Werten arbeiten
+
+@findex NULL
+@cindex NULL-Wert
+
+Der @code{NULL}-Wert birgt Überraschungen, bis Sie mit ihm vertraut sind.
+Konzeptionell bedeutet @code{NULL} einen fehlenden oder unbekannten Wert.
+Er wird in einiger Hinsicht anders als andere Werte behandelt. Um auf
+@code{NULL} zu testen, können Sie nicht die arithmetischen
+Vergleichoperatoren wie @code{=}, @code{<} oder @code{!=} verwenden. Um
+sich das zu veranschaulichen, probieren Sie folgenden Anfrage:
+
+@example
+mysql> SELECT 1 = NULL, 1 != NULL, 1 < NULL, 1 > NULL;
++----------+-----------+----------+----------+
+| 1 = NULL | 1 != NULL | 1 < NULL | 1 > NULL |
++----------+-----------+----------+----------+
+| NULL | NULL | NULL | NULL |
++----------+-----------+----------+----------+
+@end example
+
+Wie man sieht, erhält man aus diesen Vergleichen keine sinnvollen
+Ergebnisse. Benutzen Sie statt dessen die @code{IS NULL}- und @code{IS NOT
+NULL}-Operatoren:
+
+@example
+mysql> SELECT 1 IS NULL, 1 IS NOT NULL;
++-----------+---------------+
+| 1 IS NULL | 1 IS NOT NULL |
++-----------+---------------+
+| 0 | 1 |
++-----------+---------------+
+@end example
+
+In MySQL bedeutet 0 oder @code{NULL} logisch Falsch und alles sonstige
+bedeutet logisch Wahr. Der vorgabemäßige Wahrheitswert einer Boolschen
+Operation ist 1.
+
+Diese besondere Behandlung von @code{NULL} ist der Grund, warum es im
+vorherigen Abschnitt notwendig war, mit @code{sterbetag IS NOT NULL}
+anstelle von @code{sterbetag != NULL} festzustellen, welche Tiere nicht
+mehr leben.
+
+
+@node Pattern matching, Counting rows, Working with NULL, Retrieving data
+@c German node Suchmuster
+@subsubsection Übereinstimmende Suchmuster
+
+@cindex Übereinstimmende Suchmuster
+@cindex Übereinstimmung, Suchmuster
+@cindex Ausdrücke, erweitert
+
+MySQL stellt Standard-SQL-Suchmuster-Übereinstimmung zur Verfügung, ebenso
+wie eine Art der Suchmuster-Übereinstimmung, die auf regulären Ausdrücken
+basiert, die denen ähnlich sind, die von Unix-Hilfsprogrammen wie
+@code{vi}, @code{grep} und @code{sed} benutzt werden.
+
+SQL-Suchmuster-Übereinstimmung gestattet Ihnen, @samp{_} zu benutzen, um
+ein einzelnes Zeichen und @samp{%}, um eine beliebige Anzahl von Zeichen
+(inklusive des 0-Zeichens) zu finden. In den MySQL-SQL-Suchmustern spielt
+die Groß-/Kleinschreibung vorgabemäßig keine Rolle. Einige Beispiele sind
+unten dargestellt. Beachten Sie, dass Sie @code{=} oder @code{!=} nicht
+benutzen können, wenn Sie SQL-Suchmuster benutzen. Stattdessen müssen Sie
+die @code{LIKE}- oder @code{NOT LIKE}-Vergleichsoperatoren benutzen.
+
+So finden Sie Namen, die mit @samp{b} anfangen:
+
+@example
+mysql> SELECT * FROM pet WHERE name LIKE "b%";
++--------+----------+------+------------+------------+------------+
+| name | besitzer | art | geschlecht | geburtstag | sterbetag |
++--------+----------+------+------------+------------+------------+
+| Buffy | Harold | Hund | w | 1989-05-13 | NULL |
+| Bowser | Diane | Hund | m | 1989-08-31 | 1995-07-29 |
++--------+----------+------+------------+------------+------------+
+@end example
+
+So finden Sie Namen, die auf @samp{fy} enden:
+
+@example
+mysql> SELECT * FROM pet WHERE name LIKE "%fy";
++--------+----------+-------+------------+------------+-----------+
+| name | besitzer | art | geschlecht | geburtstag | sterbetag |
++--------+----------+-------+------------+------------+-----------+
+| Fluffy | Harold | Katze | w | 1993-02-04 | NULL |
+| Buffy | Harold | Hund | w | 1989-05-13 | NULL |
++--------+----------+-------+------------+------------+-----------+
+@end example
+
+So finden Sie Namen, die @samp{w} enthalten:
+
+@example
+mysql> SELECT * FROM pet WHERE name LIKE "%w%";
++----------+----------+---------+-------------+------------+------------+
+| name | besitzer | art | geschlecht | geburtstag | sterbetag |
++----------+----------+---------+-------------+------------+------------+
+| Claws | Gwen | Katze | m | 1994-03-17 | NULL |
+| Bowser | Diane | Hund | m | 1989-08-31 | 1995-07-29 |
+| Whistler | Gwen | bird | NULL | 1997-12-09 | NULL |
++----------+----------+---------+-------------+------------+------------+
+@end example
+
+Um Namen zu finden, die genau fünf Zeichen enthalten, benutzen Sie das
+@samp{_}-Suchmuster-Zeichen:
+
+@example
+mysql> SELECT * FROM pet WHERE name LIKE "_____";
++-------+----------+---------+-------------+------------+-----------+
+| name | besitzer | art | geschlecht | geburtstag | sterbetag |
++-------+----------+---------+-------------+------------+-----------+
+| Claws | Gwen | Katze | m | 1994-03-17 | NULL |
+| Buffy | Harold | Hund | w | 1989-05-13 | NULL |
++-------+----------+---------+-------------+------------+-----------+
+@end example
+
+Die andere Art von Suchmuster-Übereinstimmung benutzt erweiterte reguläre
+Ausdrücke. Wenn Sie bei dieser Art von Suchmuster auf Übereinstimmung
+prüfen, benutzen Sie die @code{REGEXP}- und @code{NOT REGEXP}-Operatoren
+(oder @code{RLIKE} und @code{NOT RLIKE}, die synonym sind).
+
+Einige Charakteristika erweiterter regulärer Ausdrücke sind:
+
+@itemize @bullet
+@item
+@samp{.} findet jedes beliebige Zeichen.
+
+@item
+Eine Zeichenklasse @samp{[...]} findet jedes Zeichen innerhalb der
+eckigen Klammern. So stimmt zum Beispiel @samp{[abc]} mit @samp{a},
+@samp{b} oder @samp{c} überein. Um einen Bereich von Zeichen zu benennen,
+benutzen Sie einen Bindestrich. @samp{[a-z]} stimmt mit jedem Buchstaben in
+Kleinschreibung überein, wohingegen @samp{[0-9]} mit jeder Ziffer
+übereinstimmt.
+
+@item
+@samp{*} stimmt mit null oder mehr Instanzen der Sache überein, die ihm
+voransteht. @samp{x*} zum Beispiel stimmt mit einer beliebigen Anzahl von
+@samp{x}-Zeichen überein. @samp{[0-9]*} stimmt mit einer beliebigen Anzahl
+von Ziffern überein, und @samp{.*} mit jeder Anzahl von irgendetwas.
+
+@item
+Reguläre Ausdrücke achten auf Groß-/Kleinschreibung, aber Sie können eine
+Zeichenklasse benutzen, um beide Schreibungen zu finden, wenn Sie wollen.
+@samp{[aA]} zum Beispiel stimmt mit @samp{a} in Groß- und Kleinschreibung
+überein und @samp{[a-zA-Z]} mit jedem Buchstaben in Groß- und
+Kleinschreibung.
+
+@item
+Das Suchmuster stimmt überein, wenn es irgendwo in dem Wert auftaucht, der
+überprüft wird. (SQL-Suchmuster stimmen nur überein, wenn sie mit dem
+gesamten Wert übereinstimmen.)
+
+@item
+Um ein Suchmuster so zu verankern, dass er mit dem Anfang oder dem Ende des
+überprüften Werts übereinstimmen muss, benutzen Sie @samp{^} am Anfang oder
+@samp{$} am Ende des Suchmusters.
+@end itemize
+
+Um darzustellen, wie erweiterte reguläre Ausdrücke funktionieren, werden
+die @code{LIKE}-Anfragen von oben noch einmal mit @code{REGEXP} gezeigt.
+
+Um Namen zu finden, die mit @samp{b} anfangen, benutzen Sie @samp{^}, um
+auf Übereinstimmung am Anfang des Namens zu prüfen:
+
+@example
+mysql> SELECT * FROM pet WHERE name REGEXP "^b";
++--------+-----------+---------+-------------+------------+------------+
+| name | besitzer | art | geschlecht | geburtstag | sterbetag |
++--------+-----------+---------+-------------+------------+------------+
+| Buffy | Harold | Hund | w | 1989-05-13 | NULL |
+| Bowser | Diane | Hund | m | 1989-08-31 | 1995-07-29 |
++--------+-----------+---------+-------------+------------+------------+
+@end example
+
+Vor MySQL-Version 3.23.4 achtet @code{REGEXP} auf Groß-/Kleinschreibung.
+Daher gibt diese Anfrage ein Ergebnis ohne Zeilen zurück. Um sowohl Groß-
+als auch Kleinschreibung von @samp{b} zu finden, benutzen Sie statt dessen
+folgende Anfrage:
+
+@example
+mysql> SELECT * FROM pet WHERE name REGEXP "^[bB]";
+@end example
+
+Ab MySQL 3.23.4 müssen Sie, um die Beachtung der Groß-/Kleinschreibung in
+einem @code{REGEXP}-Vergleich zu erzwingen, das @code{BINARY}-Schlüsselwort
+verwenden, um eine der Zeichenketten zu einer binären Zeichenkette zu
+machen. Diese Anfrage stimmt nur mit @samp{b} in Kleinschreibung am Anfang
+eines Namens überein:
+
+@example
+mysql> SELECT * FROM pet WHERE name REGEXP BINARY "^b";
+@end example
+
+Um Namen zu finden, die auf @samp{fy} enden, benutzen Sie @samp{$}, um
+Übereinstimmung am Ende des Namens zu finden:
+
+@example
+mysql> SELECT * FROM pet WHERE name REGEXP "fy$";
++--------+-----------+---------+-------------+------------+-----------+
+| name | besitzer | art | geschlecht | geburtstag | sterbetag |
++--------+-----------+---------+-------------+------------+-----------+
+| Fluffy | Harold | Katze | w | 1993-02-04 | NULL |
+| Buffy | Harold | Hund | w | 1989-05-13 | NULL |
++--------+-----------+---------+-------------+------------+-----------+
+@end example
+
+Um Namen zu finden, die @samp{w} in Groß- oder Kleinschreibung enthalten,
+benutzen Sie diese Anfrage:
+
+@example
+mysql> SELECT * FROM pet WHERE name REGEXP "w";
++----------+----------+---------+-------------+------------+------------+
+| name | besitzer | art | geschlecht | geburtstag | sterbetag |
++----------+----------+---------+-------------+------------+------------+
+| Claws | Gwen | Katze | m | 1994-03-17 | NULL |
+| Bowser | Diane | Hund | m | 1989-08-31 | 1995-07-29 |
+| Whistler | Gwen | bird | NULL | 1997-12-09 | NULL |
++----------+----------+---------+-------------+------------+------------+
+@end example
+
+Weil ein Suchmuster mit regulären Ausdrücken an beliebiger Stelle im Wert
+gefunden wird, ist es bei der vorherigen Anfrage nicht notwendig, ein
+Jokerzeichen (Wildcard) auf irgendeine Seite des Suchmusters zu setzen, um
+nach Übereinstimmung im gesamten Wert zu suchen, wie es bei SQL-Suchmustern
+der Fall sein müsste.
+
+Um Namen zu finden, die genau fünf Zeichen enthalten, benutzen Sie @samp{^}
+und @samp{$}, um mit Anfang und Ende des Namens Übereinstimmung zu finden,
+und fünf Instanzen von @samp{.} dazwischen:
+
+@example
+mysql> SELECT * FROM pet WHERE name REGEXP "^.....$";
++-------+-----------+---------+-------------+------------+-----------+
+| name | besitzer | art | geschlecht | geburtstag | sterbetag |
++-------+-----------+---------+-------------+------------+-----------+
+| Claws | Gwen | Katze | m | 1994-03-17 | NULL |
+| Buffy | Harold | Hund | w | 1989-05-13 | NULL |
++-------+-----------+---------+-------------+------------+-----------+
+@end example
+
+Sie könnten die vorherige Anfrage auch unter Verwendung des @samp{@{n@}}-
+``wiederhole-@code{n}-mal''-Operators schreiben:
+
+@example
+mysql> SELECT * FROM pet WHERE name REGEXP "^.@{5@}$";
++-------+-----------+---------+-------------+------------+-----------+
+| name | besitzer | art | geschlecht | geburtstag | sterbetag |
++-------+-----------+---------+-------------+------------+-----------+
+| Claws | Gwen | Katze | m | 1994-03-17 | NULL |
+| Buffy | Harold | Hund | w | 1989-05-13 | NULL |
++-------+-----------+---------+-------------+------------+-----------+
+@end example
+
+
+@node Counting rows, Multiple tables, Pattern matching, Retrieving data
+@c German node Zeilen zählen
+@subsubsection Zeilen zählen
+
+@cindex Zeilen, zählen
+@cindex Tabellen, Zeilen zählen
+@cindex zählen, Tabellenzeilen
+
+Datenbanken werden oft benutzt, um die Frage zu beantworten, wie oft eine
+bestimmte Art von Daten in einer Tabelle erscheint. Sie wollen
+beispielsweise wissen, wie viele Haustiere Sie haben, oder wie viele
+Haustiere jeder Besitzer hat, oder Sie wollen verschiedene Arten von
+Zählungen Ihrer Tiere durchführen.
+
+Die Gesamtzahl der Tiere zählen, die Sie haben, ist dieselbe Frage wie
+``Wie viele Zeilen sind in der @code{pet}-Tabelle?'', denn es gibt einen
+Datensatz pro Haustier. Die @code{COUNT()}-Funktion zählt die Anzahl von
+Nicht-@code{NULL}-Ergebnissen, daher lautet die Anfrage, um Ihre Tiere zu
+zählen, wie folgt:
+
+@example
+mysql> SELECT COUNT(*) FROM pet;
++----------+
+| COUNT(*) |
++----------+
+| 9 |
++----------+
+@end example
+
+Sie haben vorher schon einmal die Namen der Leute abgefragt, die Haustiere
+besitzen. Sie können @code{COUNT()} benutzen, wenn Sie herausfinden wollen,
+wie viele Tiere jeder Besitzer hat:
+
+@example
+mysql> SELECT besitzer, COUNT(*) FROM pet GROUP BY besitzer;
++-----------+----------+
+| besitzer | COUNT(*) |
++-----------+----------+
+| Benny | 2 |
+| Diane | 2 |
+| Gwen | 3 |
+| Harold | 2 |
++-----------+----------+
+@end example
+
+Beachten Sie die Benutzung von @code{GROUP BY}, um alle Datensätze für
+jeden @code{besitzer} zu gruppieren. Ohne das erhalten Sie eine
+Fehlermeldung:
+
+@example
+mysql> SELECT besitzer, COUNT(besitzer) FROM pet;
+ERROR 1140 at line 1: Mixing of GROUP columns (MIN(),MAX(),COUNT()...)
+with no GROUP columns is illegal if there is no GROUP BY clause
+@end example
+
+@code{COUNT()} und @code{GROUP BY} sind nützlich, um Ihre Daten auf
+verschiedene Weise zu charakterisieren. Die folgenden Beispiele zeigen
+verschiedene Möglichkeiten, um Zählungen Ihrer Tiere durchzuführen.
+
+Anzahl der Tiere pro Art:
+
+@example
+mysql> SELECT art, COUNT(*) FROM pet GROUP BY art;
++---------+----------+
+| art | COUNT(*) |
++---------+----------+
+| Vogel | 2 |
+| Katze | 2 |
+| Hund | 3 |
+| Hamster | 1 |
+| Schlange| 1 |
++---------+----------+
+@end example
+
+Anzahl der Tiere pro Geschlecht:
+
+@example
+mysql> SELECT geschlecht, COUNT(*) FROM pet GROUP BY geschlecht;
++-------------+----------+
+| geschlecht | COUNT(*) |
++-------------+----------+
+| NULL | 1 |
+| w | 4 |
+| m | 4 |
++-------------+----------+
+@end example
+
+(In dieser Ausgabe zeigt @code{NULL} an, dass das Geschlecht unbekannt
+ist.)
+
+Anzahl der Tiere pro Kombination von Art und Geschlecht:
+
+@example
+mysql> SELECT art, geschlecht, COUNT(*) FROM pet GROUP BY art, geschlecht;
++---------+-------------+----------+
+| art | geschlecht | COUNT(*) |
++---------+-------------+----------+
+| Vogel | NULL | 1 |
+| Vogel | w | 1 |
+| Katze | w | 1 |
+| Katze | m | 1 |
+| Hund | w | 1 |
+| Hund | m | 2 |
+| Hamster | w | 1 |
+| Schlange| m | 1 |
++---------+-------------+----------+
+@end example
+
+Sie müssen nicht die gesamte Tabelle abfragen, wenn Sie @code{COUNT()}
+benutzen. Die vorherige Anfrage beispielsweise sieht lediglich für Hunde
+und Katzen wie folgt aus:
+
+@example
+mysql> SELECT art, geschlecht, COUNT(*) FROM pet
+ -> WHERE art = "Hund" OR art = "Katze"
+ -> GROUP BY art, geschlecht;
++---------+-------------+----------+
+| art | geschlecht | COUNT(*) |
++---------+-------------+----------+
+| Katze | w | 1 |
+| Katze | m | 1 |
+| Hund | w | 1 |
+| Hund | m | 2 |
++---------+-------------+----------+
+@end example
+
+Oder wenn Sie die Anzahl von Tieren pro Geschlecht wissen wollen,
+beschränkt auf die Tiere, deren Geschlecht bekannt ist:
+
+@example
+mysql> SELECT art, geschlecht, COUNT(*) FROM pet
+ -> WHERE geschlecht IS NOT NULL
+ -> GROUP BY art, geschlecht;
++---------+-------------+----------+
+| art | geschlecht | COUNT(*) |
++---------+-------------+----------+
+| Vogel | w | 1 |
+| Katze | w | 1 |
+| Katze | m | 1 |
+| Hund | w | 1 |
+| Hund | m | 2 |
+| Hamster | w | 1 |
+| Schlange| m | 1 |
++---------+-------------+----------+
+@end example
+
+
+@node Multiple tables, , Counting rows, Retrieving data
+@c German node Mehrere Tabellen
+@subsubsection Mehr als eine Tabelle benutzen
+
+@cindex Tabellen, mehrere
+
+In der @code{pet}-Tabelle behalten Sie die Übersicht über Ihre Haustiere.
+Wenn Sie weitere Informationen über sie aufzeichnen wollen, beispielsweise
+Ereignisse in ihrem Leben wie Besuche beim Tierarzt oder wenn Nachwuchs zur
+Welt kommt, brauchen Sie eine weitere Tabelle. Wie sollte diese aussehen?
+Sie benötigt:
+
+@itemize @bullet
+@item
+Den Namen des Haustiers, damit Sie wissen, auf welches Tier sich jedes
+Ereignis bezieht.
+
+@item
+Ein Datum, damit Sie wissen, wann sich das Ereignis zugetragen hat.
+
+@item
+Ein Feld, um das Ereignis zu beschreiben.
+
+@item
+Ein Feld für den Typ des Ereignisses, wenn Sie in der Lage sein wollen,
+Ereignisse zu kategorisieren.
+@end itemize
+
+Nach diesen Vorüberlegungen könnte das @code{CREATE TABLE}-Statement für
+die @code{ereignis}-Tabelle wie folgt aussehen:
+
+@example
+mysql> CREATE TABLE ereignis (name VARCHAR(20), datum DATE,
+ -> typ VARCHAR(15), bemerkung VARCHAR(255));
+@end example
+
+Wie bei der @code{pet}-Tabelle ist es am einfachsten, die anfänglichen
+Datensätze mit Hilfe einer TAB-getrennten Textdatei einzuladen, die
+folgende Informationen enthält:
+
+@multitable @columnfractions .15 .15 .15 .55
+@item Fluffy @tab 1995-05-15 @tab Nachwuchs @tab 4 Kätzchen, 3 weiblich, 1 männlich
+@item Buffy @tab 1993-06-23 @tab Nachwuchs @tab 5 Hündchen, 2 weiblich, 3 männlich
+@item Buffy @tab 1994-06-19 @tab Nachwuchs @tab 3 Hündchen, 3 weiblich
+@item Chirpy @tab 1999-03-21 @tab Tierarzt @tab Schnabel gerade gebogen
+@item Slim @tab 1997-08-03 @tab Tierarzt @tab Gebrochene Rippe
+@item Bowser @tab 1991-10-12 @tab Zwinger
+@item Fang @tab 1991-10-12 @tab Zwinger
+@item Fang @tab 1998-08-28 @tab Geburtstag @tab Geschenk: neues Kauspielzeug
+@item Claws @tab 1998-03-17 @tab Geburtstag @tab Geschenk: neues Flohhalsband
+@item Whistler @tab 1998-12-09 @tab Geburtstag @tab Erster Geburtstag
+@end multitable
+
+Laden Sie die Datensätze wie folgt ein:
+
+@example
+mysql> LOAD DATA LOCAL INFILE "ereignis.txt" INTO TABLE ereignis;
+@end example
+
+Auf der Grundlage dessen, was Sie durch die Abfragen der @code{pet}-Tabelle
+gelernt haben, sollten sie in der Lage sein, Abfragen der Datensätze der
+@code{ereignis}-Tabelle durchzuführen, was prinzipiell dasselbe ist. Aber
+wann ist die @code{ereignis}-Tabelle allein nicht ausreichend, um Fragen zu
+beantworten, die Sie stellen könnten?
+
+Nehmen wir an, Sie wollen herausfinden, wie alt jedes Haustier war, als es
+Nachwuchs bekam. In der @code{ereignis}-Tabelle steht, wann das geschah,
+aber um das Alter der Mutter auszurechnen, wird ihr Geburtstag benötigt.
+Weil dieser in der @code{pet}-Tabelle steht, brauchen Sie für diese Anfrage
+beide Tabellen:
+
+@example
+mysql> SELECT pet.name, (TO_DAYS(datum) - TO_DAYS(geburtstag))/365 AS age,anmerkung
+ -> FROM pet, ereignis
+ -> WHERE pet.name = ereignis.name AND typ = "Nachwuchs";
++--------+------+------------------------------------+
+| name | age | anmerkung |
++--------+------+------------------------------------+
+| Fluffy | 2.27 | 4 kätzchen, 3 weiblich, 1 männlich |
+| Buffy | 4.12 | 5 hündchen, 2 weiblich, 3 männlich |
+| Buffy | 5.10 | 3 hündchen, 3 weiblich |
++--------+------+------------------------------------+
+@end example
+
+Zu dieser Anfrage gibt es einiges anzumerken:
+
+@itemize @bullet
+@item
+In der @code{FROM}-Klausel stehen zwei Tabellen, weil die Anfrage aus
+beiden Tabellen Informationen herausziehen muss.
+
+@item
+Wenn Sie Informationen aus mehreren Tabellen verbinden (englisch: join),
+müssen Sie angeben, wie Datensätze in der einen Tabelle mit solchen in der
+anderen Tabelle in Übereinstimmung gebracht werden können. Das ist einfach,
+weil beide eine @code{name}-Spalte haben. Die Anfrage benutzt die
+@code{WHERE}-Klausel, um Datensätze beider Tabellen basierend auf den
+@code{name}-Werten in Übereinstimmung zu bringen.
+
+@item
+Weil die @code{name}-Spalte in beiden Tabellen vorkommt, müssen Sie
+angeben, welche Tabelle Sie meinen, wenn Sie auf die Spalte verweisen. Das
+wird gemacht, indem dem Spaltennamen der Tabellenname voran gestellt wird.
+@end itemize
+
+Sie müssen nicht unbedingt zwei verschiedene Tabellen haben, um eine
+Verknüpfung (Join) durchzuführen. Manchmal ist es nützlich, eine Tabelle
+mit sich selbst zu verknüpfen, wenn Sie nämlich Datensätze in einer Tabelle
+mit Datensätze in derselben Tabelle vergleichen wollen. Um zum Beispiel
+Zuchtpaare unter Ihren Haustieren zu finden, können Sie die
+@code{pet}-Tabelle mit sich selbst verknüpfen, um Paare von männlichen und
+weiblichen Tieren derselben Art zusammen zu bringen:
+
+@example
+mysql> SELECT p1.name, p1.geschlecht, p2.name, p2.geschlecht, p1.art
+ -> FROM pet AS p1, pet AS p2
+ -> WHERE p1.art = p2.art AND p1.geschlecht = "w" AND p2.geschlecht = "m";
++--------+-------------+--------+-------------+---------+
+| name | geschlecht | name | geschlecht | art |
++--------+-------------+--------+-------------+---------+
+| Fluffy | w | Claws | m | Katze |
+| Buffy | w | Fang | m | Hund |
+| Buffy | w | Bowser | m | Hund |
++--------+-------------+--------+-------------+---------+
+@end example
+
+In dieser Anfrage legen wir Aliase für den Tabellennamen fest, um auf die
+Spalten verweisen zu können und um auseinander zu halten, auf welche
+Instanz der Tabelle sich jede Spaltenreferenz bezieht.
+
+
+@node Getting information, Examples, Database use, Tutorial
+@c German node Informationen bekommen
+@section Informationen über Datenbanken und Tabellen
+
+@cindex Datenbanken, Informationen über
+@cindex Tabellen, Informationen über
+@findex DESCRIBE
+
+Was ist, wenn Sie den Namen einer Datenbank oder Tabelle vergessen haben
+oder für eine gegebene Tabelle die Struktur nicht mehr kennen (wie zum
+Beispiel die Spalten heißen)? MySQL löst solcherlei Probleme mit diversen
+Statements, die Informationen über die Datenbanken und Tabellen
+bereitstellen, die es unterstützt.
+
+@code{SHOW DATABASES} kennen Sie schon. Dieses listet die Datenbanken auf,
+die vom Server verwaltet werden. Um herauszufinden, welche Datenbank
+aktuell ausgewählt ist, benutzen Sie die @code{DATABASE()}-Funktion:
+
+@example
+mysql> SELECT DATABASE();
++------------+
+| DATABASE() |
++------------+
+| menagerie |
++------------+
+@end example
+
+Wenn Sie noch keine Datenbank ausgewählt haben, ist das Ergebnis leer.
+
+Um herauszufinden, welche Tabellen die aktuelle Datenbank enthält (wenn Sie
+sich zum Beispiel über den Namen einer Tabelle nicht sicher sind), benutzen
+Sie folgenden Befehl:
+
+@example
+mysql> SHOW TABLES;
++---------------------+
+| Tables in menagerie |
++---------------------+
+| ereignis |
+| pet |
++---------------------+
+@end example
+
+Wenn Sie die Struktur einer Tabelle sehen wollen, ist der
+@code{DESCRIBE}-Befehl nützlich. Er zeigt Informationen über jede
+Tabellenspalte an:
+
+@example
+mysql> DESCRIBE pet;
++------------+-------------+------+-----+---------+-------+
+| Field | Type | Null | Key | Default | Extra |
++------------+-------------+------+-----+---------+-------+
+| name | varchar(20) | YES | | NULL | |
+| besitzer | varchar(20) | YES | | NULL | |
+| art | varchar(20) | YES | | NULL | |
+| geschlecht | char(1) | YES | | NULL | |
+| geburtstag | date | YES | | NULL | |
+| sterbetag | date | YES | | NULL | |
++------------+-------------+------+-----+---------+-------+
+@end example
+
+@code{Field} zeigt den Spaltennamen, @code{Type} ist der Datentyp der
+Spalte, @code{Null} zeigt an, ob die Spalte @code{NULL}-Werte enthalten darf
+oder nicht, @code{Key} zeigt an, ob die Spalte indiziert ist oder nicht und
+@code{Default} legt den Vorgabewert der Spalte fest.
+
+Wenn Sie Indexe auf eine Tabelle haben, zeigt Ihnen @code{SHOW INDEX FROM
+tabelle} Informationen über diese an.
+
+
+@node Examples, Batch mode, Getting information, Tutorial
+@c German node Beispiele
+@section Beispiele gebräuchlicher Anfragen (Queries)
+
+@cindex Anfragen, Beispiele
+@cindex Beispiele, Anfragen
+
+Hier finden sich Beispiele, wie geläufige Probleme mit MySQL gelöst werden
+können.
+
+Einige der Beispiele benutzen die Tabelle @code{shop}, die den Stückpreis
+für jeden Artikel für bestimmte Händler enthält. Unter der Annahme, dass
+jeder Händler einen einzelnen fest Preis pro Artikel hat, ist
+(@code{artikel}, @code{haendler}) der Primärschlüssel für diese Datensätze.
+
+Starten Sie das Kommandozeilen-Werkzeug @code{mysql} und wählen Sie eine
+Datenbank aus:
+
+@example
+mysql ihr-datenbank-name
+@end example
+
+(Bei den meisten MySQL-Installationen können Sie die Datenbank 'test'
+auswählen.)
+
+Erzeugen Sie die Beispiel-Tabelle wie folgt:
+
+@example
+CREATE TABLE shop (
+ artikel INT(4) UNSIGNED ZEROFILL DEFAULT '0000' NOT NULL,
+ haendler CHAR(20) DEFAULT '' NOT NULL,
+ preis DOUBLE(16,2) DEFAULT '0.00' NOT NULL,
+ PRIMARY KEY(artikel, dealer));
+
+INSERT INTO shop VALUES
+(1,'A',3.45),(1,'B',3.99),(2,'A',10.99),(3,'B',1.45),(3,'C',1.69),
+(3,'D',1.25),(4,'D',19.95);
+@end example
+
+Die Beispieldaten sehen jetzt so aus:
+
+@example
+mysql> SELECT * FROM shop;
+
++---------+---------+-------+
+| artikel | haendler| preis |
++---------+---------+-------+
+| 0001 | A | 3.45 |
+| 0001 | B | 3.99 |
+| 0002 | A | 10.99 |
+| 0003 | B | 1.45 |
+| 0003 | C | 1.69 |
+| 0003 | D | 1.25 |
+| 0004 | D | 19.95 |
++---------+---------+-------+
+@end example
+
+
+
+@menu
+* example-Maximum-column::
+* example-Maximum-row::
+* example-Maximum-column-group::
+* example-Maximum-column-group-row::
+* example-user-variables::
+* example-Foreign keys::
+* Searching on two keys::
+* Calculating days::
+@end menu
+
+@node example-Maximum-column, example-Maximum-row, Examples, Examples
+@c German node Beispiel Maximum-Spalte
+@subsection Der höchste Wert einer Spalte
+
+``Was ist die höchste Artikelnummer?''
+
+@example
+SELECT MAX(artikel) AS artikel FROM shop
+
++---------+
+| artikel |
++---------+
+| 4 |
++---------+
+@end example
+
+
+@node example-Maximum-row, example-Maximum-column-group, example-Maximum-column, Examples
+@c German node Beispiel Maximum-Zeile
+@subsection Die Zeile, die den höchsten Wert einer bestimmten Spalte enthält
+
+``Suche Artikelnummer, Händler und Preis des teuersten Artikels.''
+
+In ANSI-SQL wird das mit einer Unterabfrage (Sub-Query) durchgeführt:
+
+@example
+SELECT artikel, haendler, preis
+FROM shop
+WHERE preis=(SELECT MAX(preis) FROM shop)
+@end example
+
+In MySQL (was noch keine Unterabfragen hat) führen Sie das in zwei
+Schritten durch:
+
+@enumerate
+@item
+Mit einem @code{SELECT}-Statement ermitteln Sie den höchsten Preis in der
+Tabelle.
+@item
+Mit diesem Wert stellen Sie die aktuelle Anfrage zusammen:
+@example
+SELECT artikel, haendler, preis
+FROM shop
+WHERE preis=19.95
+@end example
+@end enumerate
+
+Eine andere Lösung besteht darin, alle Zeilen absteigend nach Preis zu
+sortieren und nur die erste Zeile zu nehmen, indem Sie die
+MySQL-spezifische @code{LIMIT}-Klausel benutzen:
+
+@example
+SELECT artikel, haendler, preis
+FROM shop
+ORDER BY preis DESC
+LIMIT 1
+@end example
+
+@strong{ACHTUNG}: Wenn es mehrere teuerste Artikel gibt (die zum Beispiel
+alle 19.95 kosten), zeigt die @code{LIMIT}-Lösung nur einen davon!
+
+
+@node example-Maximum-column-group, example-Maximum-column-group-row, example-Maximum-row, Examples
+@c German node Beispiel Maximum-Spalte-Gruppe
+@subsection Höchster Wert einer Spalte pro Gruppe
+
+``Was ist der höchste Preis pro Artikel?''
+
+@example
+SELECT artikel, MAX(preis) AS preis
+FROM shop
+GROUP BY artikel
+
++---------+-------+
+| artikel | preis |
++---------+-------+
+| 0001 | 3.99 |
+| 0002 | 10.99 |
+| 0003 | 1.69 |
+| 0004 | 19.95 |
++---------+-------+
+@end example
+
+
+@node example-Maximum-column-group-row, example-user-variables, example-Maximum-column-group, Examples
+@c German node Beispiel Maximum-Spalte-Gruppe-Zeile
+@subsection Die Zeilen, die das gruppenweise Maximum eines bestimmten Felds enthalten
+
+``Suche für jeden Artikel den oder die Händler mit den teuersten Preisen.''
+
+In ANSI-SQL würden Sie das wie folgt mit einer Unterabfrage erledigen:
+
+@example
+SELECT artikel, haendler, preis
+FROM shop s1
+WHERE preis=(SELECT MAX(s2.preis)
+ FROM shop s2
+ WHERE s1.artikel = s2.artikel);
+@end example
+
+In MySQL macht man das am besten in mehreren Schritten:
+
+@enumerate
+@item
+Die Liste (artikel,maxpreis) holen.
+@item
+Für jeden Artikel die korrespondierenden Zeilen holen, die den höchsten
+Preis gespeichert haben.
+@end enumerate
+
+Das kann auf einfache Weise mit einer temporären Tabelle geschehen:
+
+@example
+CREATE TEMPORARY TABLE tmp (
+ artikel INT(4) UNSIGNED ZEROFILL DEFAULT '0000' NOT NULL,
+ preis DOUBLE(16,2) DEFAULT '0.00' NOT NULL);
+
+LOCK TABLES shop read;
+
+INSERT INTO tmp SELECT artikel, MAX(preis) FROM shop GROUP BY artikel;
+
+SELECT shop.artikel, haendler, shop.preis FROM shop, tmp
+WHERE shop.artikel=tmp.artikel AND shop.preis=tmp.preis;
+
+UNLOCK TABLES;
+
+DROP TABLE tmp;
+@end example
+
+Wenn Sie keine @code{TEMPORARY}-Tabelle benutzen, müssen Sie zusätzlich die
+'tmp'-Tabelle sperren.
+
+``Kann das mit einer einzigen Anfrage durchgeführt werden?''
+
+Ja, aber nur unter Verwendung eines recht ineffizienten Tricks, den wir den
+``MAX-CONCAT-Trick'' nennen:
+
+@example
+SELECT artikel,
+ SUBSTRING( MAX( CONCAT(LPAD(preis,6,'0'),haendler) ), 7) AS haendler,
+ 0.00+LEFT( MAX( CONCAT(LPAD(preis,6,'0'),haendler) ), 6) AS preis
+FROM shop
+GROUP BY artikel;
+
++---------+---------+-------+
+| artikel | haendler| preis |
++---------+---------+-------+
+| 0001 | B | 3.99 |
+| 0002 | A | 10.99 |
+| 0003 | C | 1.69 |
+| 0004 | D | 19.95 |
++---------+---------+-------+
+@end example
+
+Das letzte Beispiel kann etwas effizienter gemacht werden, wenn man das
+Aufteilen der verketteten Spalte im Client durchführt.
+
+
+@node example-user-variables, example-Foreign keys, example-Maximum-column-group-row, Examples
+@c German node Beispiel Benutzer-Variablen
+@subsection Wie Benutzer-Variablen verwendet werden
+
+Sie können MySQL-Benutzer-Variablen verwenden, um Ergebnisse
+zwischenzuspeichern, ohne sie in temporäre Variablen im Client speichern zu
+müssen.
+@xref{Variables}.
+
+Um zum Beispiel die Artikel mit dem höchsten und dem niedrigsten Preis
+herauszufinden, können Sie folgendes machen:
+
+@example
+select @@min_preis:=min(preis),@@max_preis:=max(preis) from shop;
+select * from shop where preis=@@min_preis or preis=@@max_preis;
+
++---------+---------+-------+
+| artikel | haendler| preis |
++---------+---------+-------+
+| 0003 | D | 1.25 |
+| 0004 | D | 19.95 |
++---------+---------+-------+
+@end example
+
+
+@node example-Foreign keys, Searching on two keys, example-user-variables, Examples
+@c German node Beispiel Fremdschlüssel
+@subsection Wie Fremdschlüssel (Foreign Keys) verwendet werden
+
+@cindex Fremdschlüssel
+@cindex Schlüssel, Fremdschlüssel
+
+Sie brauchen keine Fremdschlüssel, um zwei Tabellen zu verknüpfen.
+
+Das einzige, was MySQL nicht durchführt, ist der @code{CHECK}, um
+sicherzustellen, dass die Schlüssel, die Sie benutzen, in der oder den
+Tabelle(n) existieren, auf die Sie verweisen, und es löscht auch nicht
+automatisch Zeilen aus einer Tabelle mit einer Fremdschlüssel-Definition.
+Wenn Sie Ihre Schlüssel wie gewöhnlich benutzen, funktioniert das gut:
+
+
+@example
+CREATE TABLE personen (
+ id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
+ name CHAR(60) NOT NULL,
+ PRIMARY KEY (id)
+);
+
+CREATE TABLE hemden (
+ id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
+ stil ENUM('t-shirt', 'polo', 'dress') NOT NULL,
+ farbe ENUM('rot', 'blau', 'orange', 'weiß', 'schwarz') NOT NULL,
+ besitzer SMALLINT UNSIGNED NOT NULL references personen,
+ PRIMARY KEY (id)
+);
+
+
+INSERT INTO personen VALUES (NULL, 'Antonio Paz');
+
+INSERT INTO hemden VALUES
+(NULL, 'polo', 'blau', LAST_INSERT_ID()),
+(NULL, 'dress', 'weiß', LAST_INSERT_ID()),
+(NULL, 't-shirt', 'blau', LAST_INSERT_ID());
+
+
+INSERT INTO personen VALUES (NULL, 'Lilliana Angelovska');
+
+INSERT INTO hemden VALUES
+(NULL, 'dress', 'orange', LAST_INSERT_ID()),
+(NULL, 'polo', 'rot', LAST_INSERT_ID()),
+(NULL, 'dress', 'blau', LAST_INSERT_ID()),
+(NULL, 't-shirt', 'weiß', LAST_INSERT_ID());
+
+
+SELECT * FROM personen;
++----+---------------------+
+| id | name |
++----+---------------------+
+| 1 | Antonio Paz |
+| 2 | Lilliana Angelovska |
++----+---------------------+
+
+SELECT * FROM hemden;
++----+---------+--------+----------+
+| id | stil | farbe | besitzer |
++----+---------+--------+----------+
+| 1 | polo | blau | 1 |
+| 2 | dress | weiß | 1 |
+| 3 | t-shirt | blau | 1 |
+| 4 | dress | orange | 2 |
+| 5 | polo | rot | 2 |
+| 6 | dress | blau | 2 |
+| 7 | t-shirt | weiß | 2 |
++----+---------+--------+----------+
+
+
+SELECT h.* FROM personen p, hemden h
+ WHERE p.name LIKE 'Lilliana%'
+ AND h.besitzer = p.id
+ AND h.farbe <> 'weiß';
+
++----+-------+--------+----------+
+| id | stil | farbe | besitzer |
++----+-------+--------+----------+
+| 4 | dress | orange | 2 |
+| 5 | polo | rot | 2 |
+| 6 | dress | blau | 2 |
++----+-------+--------+----------+
+@end example
+
+
+@node Searching on two keys, Calculating days, example-Foreign keys, Examples
+@c German node Suche über zwei Schlüssel
+@subsection Über zwei Schlüssel suchen
+
+@findex UNION
+@cindex Suchen, zwei Schlüssel
+@cindex Schlüssel, suchen über zwei
+MySQL optimiert derzeit noch nicht, wenn Sie über zwei unterschiedliche
+Schlüssel suchen, die mit @code{OR} kombiniert werden (eine Suche mit einem
+Schlüssel mit verschiedenen @code{OR}-Teilen wird recht gut optimiert):
+
+@example
+SELECT feld1_index, feld2_index FROM test_tabelle WHERE feld1_index = '1'
+OR feld2_index = '1'
+@end example
+
+Der Grund liegt darin, dass wir bislang noch keine Zeit hatten, hierfür
+eine effiziente Möglichkeit zu implementieren, die das für allgemeine Fälle
+abhandelt. (Die @code{AND}-Handhabung ist im Vergleich jetzt komplett
+allgemein und funktioniert sehr gut.)
+
+In der Zwischenzeit können Sie dieses Problem sehr effizient lösen, indem
+Sie eine @code{TEMPORARY}-Tabelle verwenden. Diese Art der Optimierung ist
+ebenfalls sehr gut, wenn Sie sehr komplizierte Anfragen verwenden, bei
+denen der SQL-Server die Optimierungen in falscher Reihenfolge durchführt.
+
+@example
+CREATE TEMPORARY TABLE tmp
+SELECT feld1_index, feld2_index FROM test_tabelle WHERE feld1_index = '1';
+INSERT INTO tmp
+SELECT feld1_index, feld2_index FROM test_tabelle WHERE feld2_index = '1';
+SELECT * from tmp;
+DROP TABLE tmp;
+@end example
+
+Diese Möglichkeit der Anfrage ist im Endeffekt ein @code{UNION} von zwei
+Anfragen.
+
+
+@node Calculating days, , Searching on two keys, Examples
+@c German node Tage berechnen
+@subsection Besuche pro Tag berechnen
+
+@findex BIT_OR
+@findex BIT_COUNT
+@findex <<
+@cindex Bit_Funktionen, Beispiel
+
+Folgendes zeigt, wie Sie die Bit-Gruppen-Funktionen benutzen können, um die
+Anzahl der Tage pro Monat zu zählen, in denen ein Benutzer eine Web-Seite
+besucht hat.
+
+@example
+CREATE TABLE t1 (jahr YEAR(4), monat INT(2) UNSIGNED ZEROFILL, tag INT(2) UNSIGNED ZEROFILL);
+INSERT INTO t1 VALUES(2000,1,1),(2000,1,20),(2000,1,30),(2000,2,2),(2000,2,23),(2000,2,23);
+
+SELECT jahr,monat,BIT_COUNT(BIT_OR(1<<tag)) AS tage FROM t1 GROUP BY jahr,monat;
+
+Das gibt folgendes Ergebnis zurück:
+
++------+-------+------+
+| jahr | monat | tage |
++------+-------+------+
+| 2000 | 01 | 3 |
+| 2000 | 02 | 2 |
++------+-------+------+
+@end example
+
+Dies berechnet, wie viele verschiedene Tage für eine gegebene
+Jahr-Monats-Kombination benutzt wurden, bei automatischer Entfernung
+doppelter Einträge (Duplikate).
+
+
+@node Batch mode, Twin, Examples, Tutorial
+@c German node Stapelbetrieb
+@section @code{mysql} im Stapelbetrieb (Batch Mode)
+
+@cindex Modi, Stapel
+@cindex Stapelbetrieb
+@cindex Laufenlassen, Stapelbetrieb
+@cindex Skript-Dateien
+@cindex Dateien, Skript
+
+In den vorherigen Abschnitten haben Sie @code{mysql} interaktiv benutzt, um
+Anfragen einzugeben und die Ergebnisse zu betrachten. Sie können
+@code{mysql} auch im Stapelbetrieb benutzen. Dafür schreiben Sie dei
+Befehle, die Sie ausführen wollen, in eine Datei, und teilen @code{mysql}
+dann mit, seine Eingaben aus dieser Datei zu lesen:
+
+@example
+shell> mysql < stapel-datei
+@end example
+
+Wenn Sie auf der Kommandozeile Verbindungsparameter angeben müssen, könnte
+der Befehl wie folgt aussehen:
+
+@example
+shell> mysql -h host -u user -p < stapel-datei
+Enter password: ********
+@end example
+
+Wenn Sie @code{mysql} auf diese Weise benutzen, erzeugen Sie eine
+Skript-Datei und führen dann das Skript aus.
+
+Warum sollten Sie ein Skript benutzen? Hier sind ein paar Gründe:
+
+@itemize @bullet
+@item
+Wenn Sie eine Anfrage wiederholt ausführen (sagen wir jeden Tag oder jede
+Woche), vermeiden Sie mit einem Skript, dass Sie sie jedes Mal zur
+Ausführung erneut eintippen müssen.
+
+@item
+Sie können aus existierenden Anfragen neue Anfragen erzeugen, die ähnlich
+sind, indem Sie die Skript-Dateien kopieren und editieren.
+
+@item
+Der Stapelbetrieb kann auch für die Entwicklung einer Anfrage nützlich
+sein, insbesondere, wenn Sie mehrzeilige Befehle oder Befehlssequenzen aus
+mehreren Statements entwickeln. Wenn Sie einen Fehler machen, müssen Sie
+nicht alles noch einmal tippen, sondern editieren einfach Ihr Skript, um
+den Fehler zu beheben, und weisen @code{mysql} an, es erneut auszuführen.
+
+@item
+Wenn Sie eine Anfrage haben, die eine größere Ausgabe erzeugt, können Sie
+die Ausgabe durch einen Pager laufen lassen, statt zuzusehen, wie Sie über
+den Bildschirm flimmert:
+
+@example
+shell> mysql < stapel-datei | more
+@end example
+
+@item
+Für weitere Verarbeitung können Sie die Ausgabe auch in eine Datei lenken:
+
+@example
+shell> mysql < stapel-datei > mysql.ausgabe
+@end example
+
+@item
+Sie können Ihr Skript an andere Leute verteilen, so dass auch sie die
+Befehle laufen lassen können.
+
+@item
+In einigen Situationen ist interaktive Benutzung nicht angebracht, zum
+Beispiel dann, wenn Sie eine Anfrage durch einen @code{cron}-Job ausführen
+lassen. In diesem Fall brauchen Sie Stapelbetrieb.
+@end itemize
+
+Das Standard-Ausgabeformat ist anders (präziser), wenn Sie @code{mysql} im
+Stapelbetrieb laufen lassen, als wenn Sie es interaktiv nutzen. Die Ausgabe
+von @code{SELECT DISTINCT art FROM pet} zum Beispiel sieht so aus, wenn Sie
+sie interaktiv laufen lassen:
+
+@example
++---------+
+| art |
++---------+
+| Vogel |
+| Katze |
+| Hund |
+| Hamster |
+| Schlange|
++---------+
+@end example
+
+Aber wie folgt, wenn sie im Stapelbetrieb läuft:
+
+@example
+art
+Vogel
+Katze
+Hund
+Hamster
+Schlange
+@end example
+
+Wenn Sie im Stapelbetrieb das interaktive Ausgabeformat haben wollen,
+benutzen Sie @code{mysql -t}. Um die Befehle auszugeben, die ausgeführt
+werden, benutzen Sie @code{mysql -vvv}.
+
+
+@node Twin, Apache, Batch mode, Tutorial
+@c German node Twin
+@section Anfragen aus dem Zwillings-Projekt
+
+@cindex Zwillingsforschung, Anfragen
+@cindex Anfragen, Zwillingsforschungs-Projekt
+
+Bei Analytikerna und Lentus haben wir die Systeme und die Feldarbeit für
+ein großes Forschungsprojekt gemacht. Dieses Projekt ist eine
+Zusammenarbeit zwischen dem Institut für Umweltmedizin des Karolinska
+Institutes, Stockholm, und der Abteilung für klinische Forschung bei
+Altersprozessen und Psychologie der University of Southern California.
+
+Das Projekt beinhaltet einen Screening-Teil, bei dem alle Zwillinge in
+Schweden, die älter als 65 Jahre sind, per Telefon interviewt wurden.
+Zwillinge, die bestimmte Kriterien erfüllen, werden im nächsten Schritt
+weiter untersucht. In diesem späteren Stadium werden Zwillinge, die
+teilnehmen wollen, von einem Arzt-Schwester-Team besucht. Einige
+Untersuchungen beinhalten physische und neuropsychologische Untersuchungen,
+Labortests, Neuroimaging, Bewertungen des psychischen Zustands und eine
+Sammlung der Familiengeschichten. Zusätzlich werden Daten über medizinische
+und umweltbedingte Risikofaktoren gesammelt.
+
+Weitere Informationen zu den Zwillingsstudien finden Sie hier:
+
+@example
+@url{http://www.imm.ki.se/TWIN/TWINGREATBRITAINW.HTM}
+@end example
+
+Der spätere Teil des Projekts wird mit einer Web-Schnittstelle verwaltet,
+die Perl und MySQL benutzt.
+
+Jeden Abend werden alle Daten der Interviews in eine MySQL-Datenbank
+verschoben.
+
+
+
+@menu
+* Twin pool::
+* Twin event::
+@end menu
+
+@node Twin pool, Twin event, Twin, Twin
+@c German node Twin-Pool
+@subsection Alle nicht verteilten Zwillinge finden
+
+Mit folgender Anfrage wird festgelegt, wer in den zweiten Teil des Projekts
+geht:
+
+@example
+select
+ concat(p1.id, p1.tvab) + 0 as tvid,
+ concat(p1.christian_name, " ", p1.surname) as Name,
+ p1.postal_code as Code,
+ p1.city as City,
+ pg.abrev as Area,
+ if(td.participation = "Aborted", "A", " ") as A,
+ p1.dead as dead1,
+ l.event as event1,
+ td.suspect as tsuspect1,
+ id.suspect as isuspect1,
+ td.severe as tsevere1,
+ id.severe as isevere1,
+ p2.dead as dead2,
+ l2.event as event2,
+ h2.nurse as nurse2,
+ h2.doctor as doctor2,
+ td2.suspect as tsuspect2,
+ id2.suspect as isuspect2,
+ td2.severe as tsevere2,
+ id2.severe as isevere2,
+ l.finish_date
+from
+ twin_project as tp
+ /* For Twin 1 */
+ left join twin_data as td on tp.id = td.id and tp.tvab = td.tvab
+ left join informant_data as id on tp.id = id.id and tp.tvab = id.tvab
+ left join harmony as h on tp.id = h.id and tp.tvab = h.tvab
+ left join lentus as l on tp.id = l.id and tp.tvab = l.tvab
+ /* For Twin 2 */
+ left join twin_data as td2 on p2.id = td2.id and p2.tvab = td2.tvab
+ left join informant_data as id2 on p2.id = id2.id and p2.tvab = id2.tvab
+ left join harmony as h2 on p2.id = h2.id and p2.tvab = h2.tvab
+ left join lentus as l2 on p2.id = l2.id and p2.tvab = l2.tvab,
+ person_data as p1,
+ person_data as p2,
+ postal_groups as pg
+where
+ /* p1 gets main twin and p2 gets his/her twin. */
+ /* ptvab is a field inverted by tvab */
+ p1.id = tp.id and p1.tvab = tp.tvab and
+ p2.id = p1.id and p2.ptvab = p1.tvab and
+ /* Just the sceening survey */
+ tp.survey_no = 5 and
+ /* Skip if partner died before 65 but allow emigration (dead=9) */
+ (p2.dead = 0 or p2.dead = 9 or
+ (p2.dead = 1 and
+ (p2.sterbetag_date = 0 or
+ (((to_days(p2.sterbetag_date) - to_days(p2.geburtstagday)) / 365)
+ >= 65))))
+ and
+ (
+ /* Twin is suspect */
+ (td.future_contact = 'Yes' and td.suspect = 2) or
+ /* Twin is suspect - Informant is Blessed */
+ (td.future_contact = 'Yes' and td.suspect = 1 and id.suspect = 1) or
+ /* No twin - Informant is Blessed */
+ (ISNULL(td.suspect) and id.suspect = 1 and id.future_contact = 'Yes') or
+ /* Twin broken off - Informant is Blessed */
+ (td.participation = 'Aborted'
+ and id.suspect = 1 and id.future_contact = 'Yes') or
+ /* Twin broken off - No inform - Have partner */
+ (td.participation = 'Aborted' and ISNULL(id.suspect) and p2.dead = 0))
+ and
+ l.event = 'Finished'
+ /* Get at area code */
+ and substring(p1.postal_code, 1, 2) = pg.code
+ /* Not already distributed */
+ and (h.nurse is NULL or h.nurse=00 or h.doctor=00)
+ /* Has not refused or been aborted */
+ and not (h.status = 'Refused' or h.status = 'Aborted'
+ or h.status = 'Died' or h.status = 'Other')
+order by
+ tvid;
+@end example
+
+Einige Erläuterungen:
+@table @asis
+@item @code{concat(p1.id, p1.tvab) + 0 as tvid}
+Wir wollen nach den verketteten @code{id} und @code{tvab} in numerischer
+Reihenfolge sortieren. Indem wir @code{0} hinzufügen, bringen wir MySQL
+dazu, das Ergebnis als Zahl zu behandeln.
+@item Spalte @code{id}
+Diese identifiziert ein Zwillingspaar. Sie ist in allen Tabellen Schlüssel.
+@item Spalte @code{tvab}
+Diese identifiziert ein Zwillingspaar. Sie hat einen Wert von @code{1} oder
+@code{2}.
+@item Spalte @code{ptvab}
+Sie ist die Umkehrung von @code{tvab}. Wenn @code{tvab} @code{1} ist, ist
+sie @code{2}, und umgekehrt. Sie ist dafür da, MySQL die Optimierung der
+Anfrage zu erleichtern.
+@end table
+Diese Anfrage demonstriert unter anderem, wie man ein Nachschlagen (Lookup)
+in einer Tabelle von derselben Tabelle aus mit einem Join durchführt
+(@code{p1} und @code{p2}). In dem Beispiel wird das dazu benutzt, um
+festzustellen, ob der Partner eines Zwillings vor Erreichen des 65.
+Lebensjahrs starb. Wenn das der Fall ist, wird die Zeile nicht
+zurückgegeben.
+
+Das Geschilderte existiert in allen Tabellen mit zwillingsbezogenen
+Informationen. Wir haben einen Schlüssel auf beide @code{id,tvab} (alle
+Tabellen), und auf @code{id,ptvab} (@code{person_data}), um Anfragen
+schneller zu machen.
+
+Auf unserer Produktionsmaschine (einer 200MHz-UltraSPARC) gibt diese
+Anfrage etwa 150 bis 200 Zeilen zurück und benötigt weniger als eine
+Sekunde.
+
+Die aktuelle Anzahl von Datensätzen in den oben benutzten Tabellen:
+@multitable @columnfractions .3 .5
+@item @strong{Tabelle} @tab @strong{Zeilen}
+@item @code{person_data} @tab 71074
+@item @code{lentus} @tab 5291
+@item @code{twin_project} @tab 5286
+@item @code{twin_data} @tab 2012
+@item @code{informant_data} @tab 663
+@item @code{harmony} @tab 381
+@item @code{postal_groups} @tab 100
+@end multitable
+
+
+@node Twin event, , Twin pool, Twin
+@c German node Twin-Ereignis
+@subsection Eine Tabelle über den Zustand von Zwillingspaaren zeigen
+
+Jedes Interview endet mit einem Statuscode, genannt @code{ereignis}. Die
+unten stehende Anfrage wird benutzt, um eine Tabelle über alle
+Zwillingspaare anzuzeigen, kombiniert mit dem Ereignis. Das zeigt an, wie
+viele Paare beider Zwillingen im Zustand beendet sind, bei wie vielen
+Paaren ein Zwilling im Zustand beendet ist, welche ein Interview abgelehnt
+haben usw.
+
+@example
+select
+ t1.event,
+ t2.event,
+ count(*)
+from
+ lentus as t1,
+ lentus as t2,
+ twin_project as tp
+where
+ /* We are looking at one pair at a time */
+ t1.id = tp.id
+ and t1.tvab=tp.tvab
+ and t1.id = t2.id
+ /* Just the sceening survey */
+ and tp.survey_no = 5
+ /* This makes each pair only appear once */
+ and t1.tvab='1' and t2.tvab='2'
+group by
+ t1.event, t2.event;
+@end example
+
+
+@node Apache, , Twin, Tutorial
+@c German node Apache
+@section MySQL mit Apache benutzen
+
+@cindex Apache
+
+
+
+
+Der Contrib-Abschnitt beinhaltet Programme, mit denen Sie Ihre Benutzer
+durch eine MySQL-Datenbank authentifizieren können, und mit denen Sie Ihre
+Logdateien in eine MySQL-Tabelle schreiben können. @xref{Contrib}.
+
+Sie können das Log-Format von Apache so ändern, dass es durch MySQL leicht
+gelesen werden kann, indem Sie folgendes in die Apache-Konfigurationsdatei
+schreiben:
+
+@example
+LogFormat \
+ "\"%h\",%@{%Y%m%d%H%M%S@}t,%>s,\"%b\",\"%@{Content-Type@}o\", \
+ \"%U\",\"%@{Referer@}i\",\"%@{User-Agent@}i\""
+@end example
+
+In MySQL können Sie dann etwas wie das hier tun:
+
+@example
+LOAD DATA INFILE '/local/access_log' INTO TABLE tabelle
+FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ESCAPED BY '\\'
+@end example
+
+
+@node MySQL Database Administration, MySQL Optimisation, Tutorial, Top
+@c German node MySQL-Datenbankadministration
+@chapter MySQL-Datenbankadministration
+
+
+
+@menu
+* Configuring MySQL::
+* Privilege system::
+* User Account Management::
+* Disaster Prevention::
+* Database Administration::
+* Localisation::
+* Server-Side Scripts::
+* Client-Side Scripts::
+* Log Files::
+* Replication::
+@end menu
+
+@node Configuring MySQL, Privilege system, MySQL Database Administration, MySQL Database Administration
+@c German node MySQL konfigurieren
+@section MySQL konfigurieren
+
+
+
+
+@menu
+* Command-line options::
+* Option files::
+* Installing many servers::
+* Multiple servers::
+@end menu
+
+@node Command-line options, Option files, Configuring MySQL, Configuring MySQL
+@c German node Kommandozeilenoptionen
+@subsection mysqld-Kommandozeilenoptionen
+
+@findex Kommandozeilenoptionen
+@cindex Optionen, Kommandozeile
+@cindex mysqld-Optionen
+
+@code{mysqld} akzeptiert folgende Kommandozeilenoptionen:
+
+@table @code
+@item --ansi
+ANSI-SQL-Syntax anstelle von MySQL-Syntax benutzen. @xref{ANSI mode}.
+
+@item -b, --basedir=path
+Pfad zum Installationsverzeichnis. Gewöhnlich werden alle Pfade relativ zu
+diesem aufgelöst.
+
+@item --big-tables
+große Ergebnismengen zulassen, indem alle temporären Mengen in eine Datei
+gesichert werden. Das löst die meisten 'table full'-Fehler, verlangsamt
+aber in den Fällen Anfragen, in denen Tabellen im Speicher ausreichen
+würden. Ab Version 3.23.2 ist MySQL in der Lage, das automatisch zu lösen,
+indem für kleine temporäre Tabellen der Arbeitsspeicher benutzt wird und
+auf Festplatten-Tabellen umgeschaltet wird, wenn das nötig ist.
+
+@item --bind-address=IP
+IP-Adresse zum Anbinden (bind).
+
+@item --character-sets-dir=path
+Verzeichnis, wo Zeichensätze sind. @xref{Character sets}.
+
+@item --chroot=path
+Chroot den @code{mysqld}-Daemon beim Start. Empfohlene
+Sicherheitsmaßnahme. Wird allerdings @code{LOAD DATA INFILE} und
+@code{SELECT ... INTO OUTFILE} etwas einschränken.
+
+@item --core-file
+Schreibt eine Core-Datei, wenn @code{mysqld} stirbt. Auf manchen Systemen
+müssen Sie zusätzliche @code{--core-file-size} für @code{safe_mysqld}
+angeben. @xref{safe_mysqld, ,@code{safe_mysqld}}.
+
+@item -h, --datadir=path
+Pfad zum Datenbank-Wurzelverzeichnis.
+
+@item --default-character-set=charset
+Setzt den vorgabemäßigen Zeichensatz. @xref{Character sets}.
+
+@item --default-table-type=type
+Setzt den vorgabemäßigen Tabellentyp für Tabellen. @xref{Table types}.
+
+@item --debug[...]=
+Wenn MySQL mit @code{--with-debug} konfiguriert ist, können Sie diese
+Option benutzen, um eine Trace-Datei darüber zu erhalten, was @code{mysqld}
+tut. @xref{Making trace files}.
+
+@item --delay-key-write-for-all-tables
+Schlüsselpuffer (Key Buffer) für jegliche @code{MyISAM}-Tabellen nicht
+leeren (flush).
+@xref{Server parameters}.
+
+@item --enable-locking
+System-Sperren einschalten. Beachten Sie, dass Sie bei der Benutzung dieser
+Option auf Systemen, die kein voll funktionsfähiges lockd() besitzen (wie
+Linux), mysqld leicht zum Deadlock bringen können.
+
+@item -T, --exit-info
+Eine Bit-Maske verschiedener Flags, mit denen man den mysqld-Server
+debuggen kann. Man sollte diese Option nicht benutzen, wenn man nicht ganz
+genau weiß, was sie tut!
+
+@item --flush
+Alle Änderungen nach jedem SQL-Befehl auf Platte zurückschreiben (flush).
+Normalerweise schreibt MySQL alle Änderungen nach jedem SQL-Befehl auf
+Platte und läßt das Betriebssystem sich um das Synchronisieren auf Platte
+kümmern.
+@xref{Crashing}.
+
+@item -?, --help
+Kurze Hilfe ausgeben und beenden.
+
+@item --init-file=file
+Beim Start SQL-Befehle aus dieser Datei lesen.
+
+@item -L, --language=...
+Client-Fehlermeldungen in der angegebenen Sprache. Kann als voller Pfad
+angegeben werden. @xref{Languages}.
+
+@item -l, --log[=datei]
+Loggt Verbindungen und Anfragen in datei. @xref{Query log}.
+
+@item --log-isam[=datei]
+Loggt alle ISAM- / MyISAM-Änderungen in datei (wird nur benutzt, um ISAM /
+MyISAM zu debuggen).
+
+@item --log-slow-queries[=datei]
+Loggt alle Anfragen, die länger als @code{long_query_time} Sekunden für die
+Ausführung benötigt haben, in datei. @xref{Slow query log}.
+
+@item --log-update[=datei]
+Loggt Updates in @code{datei.#}, wobei @code{#} eine eindeutige Zahl ist,
+falls nicht vorgegeben.
+@xref{Update log}.
+
+@item --log-long-format
+Loggt einige zusätzliche Informationen ins Update-Log. Wenn Sie
+@code{--log-slow-queries} benutzen, werden Anfragen, die keine Indexe
+benutzen, in die Langsame-Anfragen-Log-Datei geloggt.
+
+@item --low-priority-updates
+Operationen, die Tabellen ändern
+(@code{INSERT}/@code{DELETE}/@code{UPDATE}), haben geringere Priorität als
+Selects. Das kann auch mit @code{@{INSERT | REPLACE | UPDATE | DELETE@}
+LOW_PRIORITY ...} durchgeführt werden, um lediglich die Priorität einer
+einzelnen Anfrage zu verringern, oder mit @code{SET OPTION
+SQL_LOW_PRIORITY_UPDATES=1}, um die Priorität in einem Thread zu ändern.
+@xref{Table locking}.
+
+@item --memlock
+Sperrt den @code{mysqld}-Prozess in den Arbeitsspeicher. Das funktioniert
+nur, wenn Ihr System den @code{mlockall()}-Systemaufruf versteht (wie
+Solaris). Das kann helfen, wenn Sie Probleme damit haben, dass Ihr
+Betriebssystem @code{mysqld} veranlasst, auf Platte zu swappen.
+
+@item --myisam-recover [=option[,option...]]], wobei option eine
+Kombination von @code{DEFAULT}, @code{BACKUP}, @code{FORCE} oder
+@code{QUICK} ist. Sie können sie auch explizit auf @code{""} setzen, wenn
+Sie diese Option ausschalten wollen. Wenn die Option benutzt wird,
+überprüft @code{mysqld} beim Öffnen, ob die Tabelle als zerstört markiert
+ist oder ob die Tabelle nicht ordnungsgemäß geschlossen wurde. (Die letzte
+Option funktioniert nur, wenn Sie mysqld mit @code{--skip-locking} laufen
+lassen). Wenn das der Fall ist, läßt @code{mysqld} eine Überprüfung der
+Tabelle laufen. Wenn die Tabelle beschädigt war, versucht @code{mysqld},
+sie zu reparieren.
+
+Folgende Optionen beeinflussen, wie repair funktioniert.
+
+@multitable @columnfractions .3 .7
+@item DEFAULT @tab Dasselbe, als würde man für @code{--myisam-recover}
+ keine Option angeben.
+@item BACKUP @tab Wenn die Tabelle während der Wiederherstellung geändert
+ wurde, eine Datensicherung der @file{tabelle.MYD}-Datendatei als
+ @file{tabelle-datetime.BAK} speichern.
+@item FORCE @tab Eine Wiederherstellung selbst dann laufen lassen, wenn
+ man mehr als eine Zeile aus der .MYD-Datei verlieren wird.
+@item QUICK @tab Die Zeilen der Tabelle nicht überprüfen, wenn es keine
+ gelöschten Blocks gibt.
+@end multitable
+
+Bevor eine Tabelle automatisch repariert wird, fügt MySQL darüber eine
+Bemerkung in das Fehler-Log. Wenn Sie in der Lage sein wollen, die meisten
+Sachen ohne Benutzer-Intervention zu beheben, sollten Sie die Optionen
+@code{BACKUP,FORCE} benutzen. Das erzwingt ein Reparieren einer Tabelle,
+selbst wenn dabei einige Zeilen gelöscht würden, erhält aber die alte
+Datendatei als Datensicherung, so dass Sie später herausfinden können, was
+passiert ist.
+
+@item --pid-file=pfad
+Pfad zur pid-Datei, die von @code{safe_mysqld} benutzt wird.
+
+@item -P, --port=...
+Port-Nummer, um auf TCP/IP-Verbindungen zu warten (listen).
+
+@item -o, --old-protocol
+Das 3.20-Protokoll für Kompatibilität mit einigen sehr alten Clients
+benutzen.
+
+@item --one-thread
+Nur einen Thread benutzen (zum Debuggen unter Linux). @xref{Debugging server}.
+
+@item -O, --set-variable var=option
+Weist einer Variablen einen Wert zu. @code{--help} listet Variablen auf.
+Sie finden eine komplette Beschreibung aller Variablen im @code{SHOW
+VARIABLES}-Abschnitt dieses Handbuchs. @xref{SHOW VARIABLES}. Der Abschnitt
+über das Tunen der Serverparameter enthält Informationen darüber, wie man
+diese optimiert. @xref{Server parameters}.
+
+@item --safe-mode
+Einige Optimierungsschritte überspringen. Setzt
+@code{--skip-delay-key-write} voraus.
+
+@item --safe-show-database
+Keine Datenbanken anzeigen, für die der Benutzer keine Zugriffsrechte hat.
+
+@item --safe-user-create
+Wenn das angeschaltet ist, kann ein Benutzer keine neuen Benutzer mit dem
+GRANT-Befehl anlegen, wenn der Benutzer kein @code{INSERT}-Zugriffsrecht
+auf die @code{mysql.user}-Tabelle oder irgend welche Spalten dieser Tabelle
+hat.
+
+@item --skip-concurrent-insert
+Die Fähigkeit abschalten, gleichzeitig auf @code{MyISAM}-Tabellen
+auszuwählen (select) und einzufügen (insert). (Sollte nur benutzt werden,
+wenn Sie der Meinung sind, ein Bug in diesem Feature gefunden zu haben.)
+
+@item --skip-delay-key-write
+Die @code{delay_key_write}-Option für alle Tabellen ignorieren.
+@xref{Server parameters}.
+
+@item --skip-grant-tables
+Diese Option veranlasst den Server, das Zugriffsrechte-System überhaupt
+nicht zu benutzen. Das gibt jedem @emph{vollen Zugriff} auf alle
+Datenbanken! (Einen laufenden Server können Sie anweisen, die
+Berechtigungstabellen erneut zu verwenden, indem Sie @code{mysqladmin
+flush-privileges} oder @code{mysqladmin reload} ausführen.)
+
+@item --skip-host-cache
+Nie den Host-Name-Cache für schnellere Name-IP-Auflösung benutzen, sondern
+statt dessen bei jeder Verbindung beim DNS-Server anfragen. @xref{DNS}.
+
+@item --skip-locking
+System-Sperren nicht benutzen. Um @code{isamchk} oder @code{myisamchk}
+auszuführen, müssen Sie den Server herunter fahren. @xref{Stability}.
+Beachten Sie, dass Sie in MySQL-Version 3.23 @code{REPAIR} und @code{CHECK}
+benutzen können, um @code{MyISAM}-Tabellen zu reparieren / zu prüfen.
+
+@item --skip-name-resolve
+Hostnamen werden nicht aufgelöst. Alle @code{Host}-Spaltenwerte in den
+Berechtigungstabellen müssen IP-Nummern oder @code{localhost} sein.
+@xref{DNS}.
+
+@item --skip-networking
+Auf überhaupt keine TCP/IP-Verbindungen warten (listen). Jede Interaktion
+mit @code{mysqld} muss über Unix-Sockets erfolgen. Diese Option wird
+ausdrücklich empfohlen für Systeme, auf denen nur lokale Anfragen
+(Requests) erlaubt sind. @xref{DNS}.
+
+@item --skip-new
+Keine neuen, möglicherweise falschen Routinen benutzen. Setzt
+@code{--skip-delay-key-write} voraus. Setzt ausserdem den vorgabemäßigen
+Tabellentyp auf @code{ISAM}. @xref{ISAM}.
+
+@item --skip-symlink
+Keine Dateien löschen oder umbenennen, auf die eine mit Symlink verknüpfte
+Datei im Daten-Verzeichnis zeigt.
+
+@item --skip-safemalloc
+Wenn MySQL mit @code{--with-debug=full} konfiguriert wird, überprüfen alle
+Programme den Arbeitsspeicher auf Überlauf, bei jeder Speicher-Allokation
+und -Freigabe. Da dieses Prüfen sehr langsam ist, können Sie es vermeiden,
+wenn Sie keine Arbeitsspeicherprüfung benötigten, indem Sie diese Option
+benutzen.
+
+@item --skip-show-database
+Keine 'SHOW DATABASE'-Befehle zulassen, wenn der Benutzer keine
+@strong{process}-Berechtigung hat.
+
+@item --skip-stack-trace
+Keine Stack-Traces schreiben. Diese Option ist nützlich, wenn Sie
+@code{mysqld} unter einem Debugger laufen lassen. @xref{Debugging server}.
+
+@item --skip-thread-priority
+Benutzung von Thread-Prioritäten abschalten, um schnellere Antwortzeiten zu
+erzielen.
+
+@item --socket=pfad
+Socket-Datei, die anstelle des vorgabemäßigen @code{/tmp/mysql.sock} für
+lokale Verbindungen benutzt wird.
+
+@item --sql-mode=option[,option[,option...]]
+Option kann jede beliebige Kombination von @code{REAL_AS_FLOAT},
+@code{PIPES_AS_CONCAT}, @code{ANSI_QUOTES}, @code{IGNORE_SPACE},
+@code{SERIALIZE} und @code{ONLY_FULL_GROUP_BY} sein. Sie kann auch leer
+sein (@code{""}), wenn Sie dies zurücksetzen wollen.
+
+Alle oben angegebenen Optionen festlegen ist dasselbe wie --ansi benutzen.
+Mit dieser Option kann man nur benötigte SQL-Modi anschalten.
+@xref{ANSI mode}.
+
+@item transaction-isolation= @{ READ-UNCOMMITTED | READ-COMMITTED | REPEATABLE-READ | SERIALIZABLE @}
+Setzt das vorgabemäßige Transaktions-Isolations-Level.
+@c German FIX unsplit @xref
+@xref{SET TRANSACTION}.
+
+@item -t, --tmpdir=pfad
+Pfad für temporäre Dateien. Es kann nützlich sein, wenn Ihr vorgabemäßiges
+@code{/tmp}-Verzeichnis auf einer Partition liegt, die zu klein ist, um
+temporäre Tabellen zu speichern.
+
+@item -u, --user=benutzername
+Den @code{mysqld}-Daemon unter dem Benutzer @code{benutzername} laufen
+lassen. Diese Option ist @emph{zwingend notwendig}, wenn @code{mysqld} als
+Root gestartet wird.
+
+@item -V, --version
+Versionsinformationen ausgeben und beenden.
+
+@item -W, --warnings
+Warnmeldungen wie @code{Aborted connection...} in die @code{.err}-Datei
+ausgeben. @xref{Communication errors}.
+@end table
+
+
+@node Option files, Installing many servers, Command-line options, Configuring MySQL
+@c German node Optionsdateien
+@subsection my.cnf-Optionsdateien
+
+@cindex Vorgabemäßige Optionen
+@cindex Optionsdateien
+@cindex Erzeugen, vorgabemäßige Startoptionen
+@cindex Startoptionen, vorgabemäßige
+
+Seit Version 3.22 kann MySQL vorgabemäßige Startoptionen für den Server
+und für Clients aus Optionsdateien lesen.
+
+MySQL liest Vorgabeoptionen aus folgenden Dateien unter Unix:
+
+@tindex .my.cnf-Datei
+@multitable @columnfractions .3 .7
+@item @strong{Dateiname} @tab @strong{Zweck}
+@item @code{/etc/my.cnf} @tab Globale Optionen
+@item @code{DATADIR/my.cnf} @tab Server-spezifische Optionen
+@item @code{defaults-extra-file} @tab Die Datei, die mit --defaults-extra-file=# festgelegt wird
+@item @code{~/.my.cnf} @tab Benutzerspezifische Optionen
+@end multitable
+
+@code{DATADIR} ist das MySQL-Daten-Verzeichnis (typischerweise
+@file{/usr/local/mysql/data} bei einer Binärinstallation oder
+@file{/usr/local/var} bei einer Quellinstallation). Beachten Sie, dass das
+das Verzeichnis ist, das zur Konfigurationszeit festgelegt wurde, nicht
+das, das mit @code{--datadir} festgelegt wird, wenn @code{mysqld} startet!
+(@code{--datadir} hat keinen Einfluss darauf, wo der Server nach
+Optionsdateien sucht, denn er sucht nach ihnen, bevor er irgend welche
+Kommandozeilenargumente verarbeitet.)
+
+MySQL liest Vorgabeoptionen aus folgenden Dateien unter Windows:
+
+@multitable @columnfractions .3 .7
+@item @strong{Dateiname} @tab @strong{Zweck}
+@item @code{Windows-System-Verzeichnis\my.ini} @tab Globale Optionen
+@item @code{C:\my.cnf} @tab Globale Optionen
+@item @code{C:\mysql\data\my.cnf} @tab Server-spezifische Optionen
+@end multitable
+
+Beachten Sie, dass Sie unter Windows alle Pfade mit @code{/} statt mit
+@code{\} angeben sollten. Wenn Sie @code{\} benutzen, müssen Sie das
+doppelt (@code{\\}) tun, weil @code{\} in MySQL das Fluchtzeichen
+(Escape-Character) ist.
+
+@cindex Umgebungsvariablen
+MySQL versucht, Optionsdateien in der oben angegebenen Reihenfolge zu
+lesen. Wenn es mehrere Optionsdateien gibt, erlangt eine Option, die in
+einer Datei festgelegt wird, die später gelesen wird, Vorrang über dieselbe
+Option, die in einer sonstigen Optionsdatei festgelegt wurde. Optionen, die
+auf der Kommandozeile festgelegt werden, erlangen Vorrang vor Optionen in
+jeglichen Optionsdateien. Einige Optionen können durch Umgebungsvariablen
+festgelegt werden. Optionen, die auf der Kommandozeile oder in
+Optionsdateien festgelegt werden, haben Vorrang vor Werten in
+Umgebungsvariablen. @xref{Environment variables}.
+Folgende Programme unterstützen Optionsdateien: @code{mysql},
+@code{mysqladmin}, @code{mysqld}, @code{mysqldump}, @code{mysqlimport},
+@code{mysql.server}, @code{myisamchk} und @code{myisampack}.
+
+Sie können Optionsdateien benutzen, um jede beliebig lange Option
+festzulegen, die ein Programm unterstützt! Starten Sie das Programm mit
+@code{--help}, um eine Liste der verfügbaren Optionen zu erhalten.
+
+Eine Optionsdatei kann Zeilen der folgenden Formate enthalten:
+
+@table @code
+@item #Kommentar
+Kommentarzeilen fangen mit @samp{#} oder @samp{;} an. Leere Zeilen werden
+ignoriert.
+
+@item [group]
+@code{group} ist der Name des Programms oder der Gruppe, für das oder die
+Sie Optionen setzen wollen. Nach einer Gruppen-Zeile beziehen sich alle
+@code{option}- oder @code{set-variable}-Zeilen auf die benannte Gruppe, bis
+zum Ende der Optionsdatei oder bis eine andere Gruppe angegeben wird.
+
+@item option
+Das ist äquivalent zu @code{--option} auf der Kommandozeile.
+
+@item option=value
+Das ist äquivalent zu @code{--option=value} auf der Kommandozeile.
+
+@item set-variable = variable=value
+Das ist äquivalent zu @code{--set-variable variable=value} auf der Kommandozeile.
+Diese Syntax muss verwendet werden, um eine @code{mysqld}-Variable zu
+setzen.
+@end table
+
+Die @code{client}-Gruppe gestattet Ihnen, Optionen anzugeben, die sich auf
+alle MySQL-Clients (nicht auf @code{mysqld}) beziehen. Diese Gruppe eignet
+sich bestens dafür, das Passwort festzulegen, das Sie benutzen, um sich mit
+dem Server zu verbinden. (Stellen Sie jedoch sicher, dass die Optionsdatei
+nur für Sie les- und schreibbar ist.)
+
+Beachten Sie, dass bei Optionen und Werten alle führenden Leerzeichen und
+solche am Zeilenende automatisch entfernt werden. Sie können in der
+Zeichenkette für den Wert die Escape-Sequenzen @samp{\b}, @samp{\t},
+@samp{\n}, @samp{\r}, @samp{\\} und @samp{\s} benutzen (@samp{\s} ist das
+Leerzeichen).
+
+Hier ist eine typische globale Optionsdatei:
+
+@example
+[client]
+port=3306
+socket=/tmp/mysql.sock
+
+[mysqld]
+port=3306
+socket=/tmp/mysql.sock
+set-variable = key_buffer_size=16M
+set-variable = max_allowed_packet=1M
+
+[mysqldump]
+quick
+@end example
+
+Hier ist eine typische Benutzer-Optionsdatei:
+
+@example
+[client]
+# Folgendes Passwort wird an alle Standard-MySQL-Clients geschickt:
+password=mein_password
+
+[mysql]
+no-auto-rehash
+set-variable = connect_timeout=2
+
+[mysqlhotcopy]
+interactive-timeout
+
+@end example
+
+@tindex .my.cnf Datei
+Wenn Sie eine Quelldistribution haben, finden Sie Beispielkonfigurationen
+in den Dateien mit Namen @file{my-xxxx.cnf} im
+@file{Support-files}-Verzeichnis. Wenn Sie eine Binärdistribution haben,
+suchen Sie im @file{DIR/support-files}-Verzeichnis, wobei @code{DIR} der
+Pfadname zum MySQL-Installationsverzeichnis ist (typischerweise
+@file{/usr/local/mysql}). Aktuell finden Sie dort beispielhafte
+Konfigurationsdateien für kleine, mittlere, große und sehr große Systeme.
+Sie können @file{my-xxxx.cnf} in Ihr Heimatverzeichnis kopieren, um damit
+zu experimentieren (benennen Sie die Kopie in @file{.my.cnf} um).
+
+Alle MySQL-Clients, die Optionsdateien unterstützen, unterstützen folgende
+Optionen:
+
+@multitable @columnfractions .40 .60
+@item --no-defaults @tab Keine Optionsdateien einlesen.
+@item --print-defaults @tab Den Programmnamen und alle Optionen, die das Programm erhalten wird, ausgeben.
+@item --defaults-file=voller-pfad-zur-vorgabe-datei @tab Nur die angegebene Konfigurationsdatei benutzen.
+@item --defaults-extra-file=voller-pfad-zur-vorgabe-datei @tab Diese Konfigurationsdatei nach der globalen Konfigurationsdatei einlesen, aber vor der Benutzer-Konfigurationsdatei.
+@end multitable
+
+Beachten Sie, dass die oben aufgeführten Optionen auf der Kommandozeile
+zuerst angegeben werden müssen, damit sie funktionieren!
+@code{--print-defaults} kann jedoch direkt nach den
+@code{--defaults-xxx-file}-Befehlen angegeben werden.
+
+Hinweis für Entwickler: Optionsdatei-Handhabung ist schlicht dadurch
+implementiert, dass alle übereinstimmenden Optionen verarbeitet werden
+(das heißt, Optionen in der entsprechenden Gruppe), vor jeglichen
+Kommandozeilen-Argumenten. Das funktioniert sehr gut bei Programmen, die
+die letzte Instanz einer Option benutzen, die mehrfach festgelegt wurde.
+Wenn Sie ein altes Programm benutzen, das mehrfach festgelegte Optionen auf
+diese Art handhabt, aber keine Optionsdateien liest, müssen Sie nur zwei
+Zeilen hinzufügen, um diese Fähigkeit hinzuzufügen. Sehen Sie im Quellcode
+irgend eines Standard-MySQL-Clients nach, wie das gemacht wird.
+
+In Shellskripts können Sie den @file{my_print_defaults}-Befehl benutzen, um
+die Konfigurationsdateien zu parsen:
+
+@example
+
+shell> my_print_defaults client mysql
+--port=3306
+--socket=/tmp/mysql.sock
+--no-auto-rehash
+@end example
+
+Die Ausgabe enthält alle Optionen für die Gruppen 'client' und 'mysql'.
+
+
+@node Installing many servers, Multiple servers, Option files, Configuring MySQL
+@c German node Viele Server installieren
+@subsection Viele Server auf derselben Maschine installieren
+
+@cindex Nach der Installation, mehrere Server
+@cindex Mehrere Server installieren
+@cindex Mehrere Server starten
+
+In einigen Fällen brauchen Sie vielleicht viele verschiedene
+@code{mysqld}-Daemons (Server), die auf derselben Maschine laufen.
+Beispielsweise wollen Sie eine neue MySQL-Version zum Testen benutzen,
+während gleichzeitig eine alte Version für die Produktion läuft, oder Sie
+wollen verschiedenen Benutzern Zugriff auf verschiedene
+@code{mysqld}-Server geben, die sie selbst verwalten.
+
+Eine Möglichkeit, einen neuen Server laufen zu lassen, besteht darin, ihn
+mit einem anderen Socket und einem anderen Port wie folgt zu starten:
+
+@tindex @code{MYSQL_UNIX_PORT}-Umgebungsvariable
+@tindex @code{MYSQL_TCP_PORT}-Umgebungsvariable
+@tindex Umgebungsvariable, @code{MYSQL_UNIX_PORT}
+@tindex Umgebungsvariable, @code{MYSQL_TCP_PORT}
+@example
+shell> MYSQL_UNIX_PORT=/tmp/mysqld-neu.sock
+shell> MYSQL_TCP_PORT=3307
+shell> export MYSQL_UNIX_PORT MYSQL_TCP_PORT
+shell> scripts/mysql_install_db
+shell> bin/safe_mysqld &
+@end example
+
+Der Umgebungsvariablen-Appendix beinhaltet eine Liste anderer
+Umgebungsvariablen, die Sie benutzen können, um @code{mysqld} zu steuern.
+@xref{Environment variables}.
+
+Der oben gezeigte Weg ist die 'schnelle und schmutzige' Lösung, die man
+üblicherweise zum Testen benutzt. Das nette daran ist, dass alle
+Verbindungen, die Sie in obiger Shell aufbauen, automatisch an den neuen
+laufenden Server weiter geleitet werden!
+
+Wenn Sie dasselbe dauerhafter durchführen wollen, sollten Sie für jeden
+Server eine Optionsdatei erzeugen. @xref{Option files}. In Ihrem
+Startskript, das beim Hochfahren ausgeführt wird (mysql.server?) sollten
+Sie für beide Server folgendes festlegen:
+
+@code{safe_mysqld --default-file=pfad-zur-optionsdatei}
+
+Zumindest folgende Optionen sollten für jeden Server unterschiedlich sein:
+
+@table @code
+@item port=#
+@item socket=pfad
+@item pid-file=pfad
+@end table
+
+Folgende Optionen sollten unterschiedlich sein, wenn sie benutzt werden:
+
+@table @code
+@item log=pfad
+@item log-bin=pfad
+@item log-update=pfad
+@item log-isam=pfad
+@item bdb-logdir=pfad
+@end table
+
+Wenn Sie mehr Performance erreichen wollen, können Sie auch folgendes
+unterschiedlich festlegen:
+
+@table @code
+@item tmpdir=pfad
+@item bdb-tmpdir=pfad
+@end table
+
+@xref{Command-line options}.
+
+Wenn Sie binäre MySQL-Versionen installieren (.tar-Dateien) und sie mit
+@code{./bin/safe_mysqld} starten, müssen Sie in den meisten Fällen
+lediglich die @code{socket}- und @code{port}-Argumente in
+@code{safe_mysqld} hinzufügen / ändern.
+
+
+
+
+@node Multiple servers, , Installing many servers, Configuring MySQL
+@c German node Mehrere Server
+@subsection Viele MySQL-Server auf derselben Maschine laufen lassen
+
+@cindex Mehrere Server
+@cindex Servers, mehrere
+@cindex Laufen lassen, mehrere Server
+
+Unter bestimmten Umständen wollen Sie vielleicht mehrere Server auf
+derselben Maschine laufen lassen. Beispielsweise wollen Sie ein neues
+MySQL-Release testen, Ihre bestehende Produktionseinrichtung aber
+unangetastet lassen. Oder Sie sind ein Internet-Service-Provider, der
+unabhängige MySQL-Installationen für verschiedene Kunden hat.
+
+Wenn Sie mehrere Server laufen lassen wollen, ist es am einfachsten, die
+Server mit unterschiedlichen TCP/IP-Ports und Socket-Dateien laufen zu
+lassen, damit sie nicht beide auf demselben TCP/IP-Port oder derselben
+Socket-Datei auf Verbindungen warten. @xref{mysqld_multi, ,
+@code{mysqld_multi}}.
+
+Nehmen wir einen existierenden Server an, der auf die existierende
+Port-Nummer und Socket-Datei konfiguriert ist. Sie konfigurieren einen
+neuen Server mit einem @code{configure}-Befehl, etwa wie folgt:
+
+@example
+shell> ./configure --with-tcp-port=port_nummer \
+ --with-unix-socket-path=datei \
+ --prefix=/usr/local/mysql-3.22.9
+@end example
+
+Hier müssen @code{port_nummer} und @code{datei} anders als die
+vorgabemäßigen Werte sein. Der @code{--prefix}-Wert sollte ein
+Installationsverzeichnis festlegen, das anders ist als dasjenige, unter dem
+die existierende MySQL-Installation liegt.
+
+Sie können den Socket, der vom aktuell laufenden MySQL-Server benutzt wird,
+mit folgendem Befehl feststellen:
+
+@example
+shell> mysqladmin -h hostname --port=port_nummer variables
+@end example
+
+Wenn Sie ``@code{localhost}'' als Hostnamen festlegen, benutzt
+@code{mysqladmin} Unix-Sockets anstelle von TCP/IP.
+
+Wenn Sie einen MySQL-Server auf dem Port laufen haben, den Sie benutzt
+haben, bekommen Sie eine Liste der wichtigsten konfigurierbaren Variablen
+in MySQL, inklusive des Socketnamens.
+
+Sie müssen keinen neuen MySQL-Server kompilieren, nur um ihn mit einem
+anderen Port und Socket zu starten. Sie können Port und Socket zur Laufzeit
+als Optionen von @code{safe_mysqld} festlegen:
+
+@example
+shell> /pfad/zu/safe_mysqld --socket=datei --port=port_nummer
+@end example
+
+@code{mysqld_multi} kann ebenfalls @code{safe_mysqld} (oder @code{mysqld})
+als Argument nehmen und die Optionen von einer Konfigurationsdatei an
+@code{safe_mysqld} und weiter an @code{mysqld} durchreichen.
+
+Wenn Sie den neuen Server mit demselben Datenbankverzeichnis laufen lassen
+und Loggen angeschaltet haben, sollten Sie auch den Namen der Logdateien
+für @code{safe_mysqld} mit @code{--log}, @code{--log-update} oder
+@code{--log-slow-queries} festlegen. Ansonsten versuchen beide Server, in
+dieselbe Logdatei zu schreiben.
+
+@strong{ACHTUNG}: Normalerweise sollten Sie nie zulassen, dass zwei Server
+Daten in derselben Datenbank aktualisieren! Wenn Ihr Betriebssystem kein
+fehlerfreies System-Sperren (System Locking) unterstützt, führt das zu
+unliebsamen Überraschungen!
+
+Wenn Sie für den zweiten Server ein anderes Datenbankverzeichnis benutzen
+wollen, können Sie das mit der @code{--datadir=path}-Option für
+@code{safe_mysqld} angeben.
+
+@strong{HINWEIS:} Mehrere MySQL-Server (@code{mysqld}) auf verschiedenen
+Maschinen laufen lassen, die auf ein gemeinsames Datenverzeichnis über
+@code{NFS} zugreifen, ist generell eine @strong{SCHLECHTE IDEE}! Das
+Problem liegt darin, dass @code{NFS} zum Flaschenhals in Punkto
+Geschwindigkeit wird, denn es ist nicht für solche Zwecke gedacht. Und
+letztlich müssten Sie immer noch eine Lösung dafür finden, dass sich zwei
+oder mehr @code{mysqlds} nicht in die Quere kommen. Momentan gibt es keine
+Plattform, die mit 100%-iger Zuverlässigkeit Datei-Sperren (File Locking,
+gewöhnlich mit dem @code{lockd}-Daemon) in jeder Situation durchführt.
+Dennoch stellt @code{NFS} ein weiteres mögliches Risiko dar, denn es macht
+es dem @code{lockd}-Daemon noch schwieriger, Datei-Sperren zu handhaben.
+Machen Sie es sich also leicht und vergessen Sie diese Idee! Die
+funktionierende Lösung ist, einen Computer mit einem Betriebssystem
+einzusetzen, dass Threads effizient handhabt und mehrere Prozessoren hat.
+
+Wenn Sie sich mit einem MySQL-Server verbinden wollen, der mit einem
+anderen Port läuft als mit dem, der in Ihren Client kompiliert ist, können
+Sie folgende Methoden benutzen:
+
+@itemize @bullet
+@item
+Starten Sie den Client mit @code{--host 'hostname' --port=port_nummer}, um
+sich über TCP/IP zu verbinden, oder mit @code{[--host localhost]
+--socket=datei}, um sich über ein Unix-Socket zu verbinden.
+
+@item
+In Ihren C- oder Perl-Programmen können Sie die Port- oder Socket-Argumente
+angeben, wenn Sie sich mit dem MySQL-Server verbinden.
+
+@item
+Wenn Sie das Perl-@code{DBD::mysql}-Modul benutzen, können Sie die Optionen
+aus den MySQL-Optionsdateien lesen. @xref{Option files}.
+
+@example
+$dsn = "DBI:mysql:test;mysql_read_default_group=client;mysql_read_default_file=/usr/local/mysql/data/my.cnf"
+$dbh = DBI->connect($dsn, $user, $password);
+@end example
+
+@item
+@tindex MYSQL_UNIX_PORT-Umgebungsvariable
+@tindex MYSQL_TCP_PORT-Umgebungsvariable
+@tindex Umgebungsvariable, MYSQL_UNIX_PORT
+@tindex Umgebungsvariable, MYSQL_TCP_PORT
+Setzen Sie die @code{MYSQL_UNIX_PORT}- und
+@code{MYSQL_TCP_PORT}-Umgebungsvariablen, so dass sie auf den Unix-Socket
+und TCP/IP-Port zeigen, bevor Sie Ihre Clients starten. Wenn Sie
+normalerweise eine speziellen Socket oder Port benutzen, sollten Sie die
+Befehle zum Setzen dieser Umgebungsvariablen in Ihrer @file{.login}-Datei
+unterbringen.
+@xref{Environment variables}.
+
+@item
+@tindex .my.cnf Datei
+Legen Sie den vorgabemäßigen Socket und TCP/IP-Port in der
+@file{.my.cnf}-Datei in Ihrem Heimatverzeichnis fest.
+@xref{Option files}.
+@end itemize
+
+
+@node Privilege system, User Account Management, Configuring MySQL, MySQL Database Administration
+@c German node Berechtigungssystem
+@section Allgemeine Sicherheitsthemen und das MySQL-Zugriffsberechtigungssystem
+
+@cindex System, Sicherheit
+@cindex Zugriffsberechtigungen
+@cindex Berechtigungen, Zugriff
+@cindex Sicherheitssystem
+@cindex ACLs
+
+MySQL hat ein fortgeschrittenes, aber nicht standardisiertes Sicherheits-
+bzw. Berechtigungssystem. Dieser Abschnitt beschreibt, wie es funktioniert.
+
+
+
+@menu
+* General security::
+* Security::
+* Privileges options::
+* What Privileges::
+* Privileges::
+* Privileges provided::
+* Connecting::
+* Connection access::
+* Request access::
+* Access denied::
+@end menu
+
+@node General security, Security, Privilege system, Privilege system
+@c German node Allgemeine Sicherheitsrichtlinien
+@subsection Allgemeine Sicherheitsrichtlinien
+
+Jeder, der MySQL auf einem Computer benutzt, der mit dem Internet verbunden
+ist, sollte diesen Abschnitt lesen, um die gebräuchlichsten
+Sicherheitsfehler zu vermeiden.
+
+Wenn wir über Sicherheit sprechen, unterstreichen wir die Notwendigkeit,
+den gesamten Server-Host (und nicht nur den MySQL-Server) gegen alle Arten
+möglicher Angriffe abzusichern: Lauschangriffe, Änderungen (Altering),
+Playback und Dienstverweigerung (Denial of Service). Dieser Abschnitt deckt
+nicht alle Aspekte von Verfügbarkeit und Fehlertoleranz ab.
+
+MySQL benutzt ein Sicherheitssystem, das auf Zugriffssteuerungslisten
+(Access Control Lists, ACLs) für alle Verbindungen, Anfragen und sonstige
+Operationen basiert, die ein Benutzer durchführen kann. Zusätzlich gibt es
+einige Unterstützung für SSL-verschlüsselte Verbindungen zwischen
+MySQL-Clients und -Servern. Viele der hier geschilderten Konzepte sind
+überhaupt nicht spezifisch für MySQL, sondern beziehen sich auf fast alle
+Applikationen.
+
+Wenn Sie MySQL laufen lassen, sollten Sie möglichst immer folgende
+Richtlinien beachten:
+
+@itemize @bullet
+@item
+GEBEN SIE NIEMALS JEMANDEM AUSSER DEM MySQL-ROOT-BENUTZER ZUGRIFF AUF DIE
+@code{user}-TABELLE IN DER @code{mysql}-DATENBANK! Das verschlüsselte
+Passwort ist das echte Passwort in MySQL. Wenn Sie das in der the
+@code{user}-Tabelle aufgeführte Passwort für einen gegebenen Benutzer
+kennen, können Sie sich leicht als dieser Benutzer einloggen, wenn Sie
+Zugriff auf den Host haben, der für dieses Benutzerkonto aufgeführt ist.
+
+@item
+Lernen Sie das MySQL-Zugriffsberechtigungssystem. Die @code{GRANT}- und
+@code{REVOKE}-Befehle werden benutzt, um den Zugriff auf MySQL zu steuern.
+Gewähren Sie nicht mehr Zugriffsrechte als notwendig. Gewähren Sie niemals
+Zugriffsrechte für alle Hosts.
+
+Checkliste:
+@itemize @minus
+@item
+Probieren Sie @code{mysql -u root}. Wenn es Ihnen gelingt, sich erfolgreich
+mit dem Server zu verbinden, ohne nach einem Passwort gefragt zu werden,
+haben Sie ein Problem, denn jeder kann sich als MySQL-@code{root}-Benutzer
+mit dem Server verbinden und hat volle Berechtigungen! Lesen Sie in diesem
+Fall noch einmal die MySQL-Installationsanweisungen durch und achten Sie
+insbesondere auf den Teil, der sich mit dem Setzen des
+@code{root}-Passworts beschäftigt.
+@item
+Benutzen Sie den Befehl @code{SHOW GRANTS} und prüfen Sie nach, wer Zugriff
+auf was hat. Entfernen Sie die Berechtigungen, die nicht notwendig sind,
+indem Sie den @code{REVOKE}-Befehl benutzen.
+@end itemize
+@item
+Halten Sie keine Klartext-Passwörter in Ihrer Datenbank. Wenn Ihr Computer
+kompromittiert wird, kann der Einbrecher die gesamte Liste von Passwörtern
+nehmen und benutzen. Benutzen Sie statt dessen @code{MD5()} oder eine
+andere Einweg-Hash-Funktion.
+@item
+Benutzen Sie keine Passwörter aus Lexika. Es gibt spezielle Programme, um
+diese zu knacken. Selbst Passwörter wie ``xfish98'' sind sehr schlecht.
+Viel besser ist ``duag98'', was dasselbe Wort ``fish'' enthält, aber um
+eine Taste nach links auf einer QUERTZ-Tastatur verschoben. Eine weitere
+Methode ist, etwas wie ``Mhall'' zu benutzen, was die ersten Buchstaben des
+Satzes ``Mary had a little lamb'' enthält. Das läßt sich leicht merken und
+eintippen, aber schwierig durch jemanden erraten, der es nicht kennt.
+@item
+Investieren Sie in eine Firewall. Diese schützt sie vor mindestens 50%
+aller Exploits in jeglicher Software. Installieren Sie MySQL hinter einer
+Firewall oder in einer entmilitarisierten Zone (Demilitarized Zone, DMZ).
+
+Checkliste:
+@itemize @minus
+@item
+Versuchen Sie, Ihre Ports vom Internet aus zu scannen, indem Sie ein Werkzeug
+wie @code{nmap} benutzen. MySQL benutzt vorgabemäßig Port 3306. Dieser
+Port sollte von nicht vertrauenswürdigen Hosts aus unerreichbar sein. Eine
+weitere einfache Methode, um zu überprüfen, ob Ihr MySQL-Port offen ist
+oder nicht, ist, den folgenden Befehl von einer entfernten Maschine aus zu
+benutzen, wobei @code{server_host} der Hostname Ihres MySQL-Servers ist:
+
+@example
+shell> telnet server_host 3306
+@end example
+
+Wenn Sie eine Verbindung und einige sinnlose Zeichen erhalten, ist der Port
+offen und sollte auf Ihrer Firewall oder Ihrem Router geschlossen werden,
+sofern Sie nicht einen wirklich guten Grund haben, ihn offen zu halten.
+Wenn @code{telnet} einfach hängt oder die Verbindung abgelehnt wird, ist
+alles in Ordnung, der Port ist blockiert.
+@end itemize
+
+@item
+Trauen Sie keinen Daten, die von Benutzern eingegeben werden. Sie können
+versuchen, Ihren Code auszutricksen, indem Sie spezielle oder escapete
+Zeichenfolgen in Web-Formulare, URLs oder sonstige Applikationen, die Sie
+hergestellt haben, eingeben. Stellen Sie sicher, dass Ihre Applikation
+sicher bleibt, wenn ein Benutzer etwas wie ``@code{; DROP DATABASE
+mysql;}'' eingibt. Das ist ein extremes Beispiel, aber große
+Sicherheitslücken und Datenverlust können eintreten, wenn ein Hacker
+ähnliche Techniken benutzt und Sie nicht darauf vorbereitet sind.
+
+Denken Sie auch daran, numerische Daten zu überprüfen. Ein häufiger Fehler
+besteht darin, nur Zeichenketten zu schützen. Manchmal denken Leute, dass
+eine Datenbank, die nur öffentlich zugängliche Daten enthält, nicht
+geschützt werden muss. Das stimmt nicht. Auf solche Datenbanken können
+zumindest Dienstverweigerungsangriffe (Denial-of-Service-Attacken)
+durchgeführt werden. Die einfachste Art, sich vor dieser Art von Angriffen
+zu schützen, ist, Apostrophe um numerische Konstanten herum zu benutzen:
+@code{SELECT * FROM tabelle WHERE ID='234'} statt @code{SELECT * FROM
+tabelle WHERE ID=234}. MySQL wandelt diese Zeichenkette automatisch in eine
+Zahl um und entfernt alle nicht-numerischen Zeichen aus ihr.
+
+Checkliste:
+@itemize @minus
+@item
+Alle Web-Applikationen:
+@itemize @bullet
+@item
+Versuchen Sie, @samp{'} und @samp{"} in alle Ihr Web-Formulare einzugeben.
+Wenn Sie irgend welche MySQL-Fehler erhalten, untersuchen Sie das Problem
+unverzüglich!
+@item
+Versuchen Sie, jedwede dynamischen URLs zu ändern, indem Sie @code{%22}
+(@samp{"}), @code{%23} (@samp{#}) und @code{%27} (@samp{'}) zu den URLs
+hinzufügen.
+@item
+Versuchen Sie, Datentypen in dynamischen URLs von numerischen zu
+Zeichentypen zu ändern, die Zeichen aus den vorherigen Beispielen
+enthalten. Ihre Applikation sollte gegen solche und ähnliche Angriffe
+sicher sein.
+@item
+Versuchen Sie Buchstaben, Leerzeichen und Sonderzeichen anstelle von Zahlen
+in numerische Felder einzugeben. Ihre Applikation sollte diese entfernen,
+bevor sie sie MySQL übergibt, und Ihre Applikation sollte einen Fehler
+erzeugen. Es ist sehr gefährlich, nicht geprüfte Werte an MySQL zu
+übergeben!
+@item
+Überprüfen Sie Datengrößen, bevor Sie sie an MySQL übergeben.
+@item
+Überlegen Sie, ob es sinnvoll ist, dass sich Ihre Applikation mit einem
+anderen Benutzernamen mit der Datenbank verbindet als mit dem, den Sie für
+Verwaltungszwecke benutzen. Geben Sie Applikationen nicht mehr
+Zugriffsberechtigungen als sie brauchen.
+@end itemize
+@item
+Benutzer von PHP:
+@itemize @bullet
+@item Sehen Sie sich die @code{addslashes()}-Funktion an.
+Ab PHP 4.0.3 ist eine @code{mysql_escape_string()}-Funktion verfügbar, die
+auf der Funktion mit demselben Namen in der MySQL-C-API basiert.
+@end itemize
+@item
+Benutzer der MySQL-C-API:
+@itemize @bullet
+@item Sehen Sie sich den @code{mysql_escape_string()}-API-Aufruf an.
+@end itemize
+@item
+Benutzer von MySQL++:
+@itemize @bullet
+@item Sehen Sie sich die @code{escape}- und @code{quote}-Modifier für
+Query-Streams an.
+@end itemize
+@item
+Benutzer der Perl-DBI:
+@itemize @bullet
+@item Sehen Sie sich die @code{quote()}-Methode an oder benutzen Sie
+Platzhalter.
+@end itemize
+@item
+Benutzer von Java-JDBC:
+@itemize @bullet
+@item Benutzen Sie ein @code{PreparedStatement}-Objekt und Platzhalter.
+@end itemize
+@end itemize
+
+@item
+Übermitteln Sie keine Klartextdaten (unverschlüsselte Daten) über das
+Internet. Diese Daten sind für jeden zugänglich, der Zeit und Möglichkeit
+hat, sie abzuhören und sie für die eigenen Zwecke zu benutzen. Benutzen Sie
+statt dessen ein verschlüsseltes Protokoll wie SSL oder SSH. MySQL
+unterstützt ab Version 4.0.0 interne SSL-Verbindungen.
+SSH-Port-Forwarding kann benutzt werden, um einen verschlüsselten (und
+komprimierten) Kommunikationstunnel zu erzeugen.
+@item
+Lernen Sie die Benutzung der @code{tcpdump}- und @code{strings}-Utilities.
+In den meisten Fällen können Sie mit einem Befehl wie dem folgenden
+feststellen, ob MySQL-Datenströme verschlüsselt sind oder nicht:
+
+@example
+shell> tcpdump -l -i eth0 -w - src or dst port 3306 | strings
+@end example
+
+(Das funktioniert unter Linux und sollte mit kleineren Änderungen auf
+anderen Systemen funktionieren.) Achtung: Wenn Sie keine Daten sehen,
+heißt das nicht immer, dass sie verschlüsselt sind. Wenn Sie hohe
+Sicherheit benötigen, sollten Sie sich mit einem Sicherheitsexperten in
+Verbindung setzen.
+@end itemize
+
+
+@node Security, Privileges options, General security, Privilege system
+@c German node Sicherheit
+@subsection Wie Sie MySQL gegen Cracker sicher machen
+
+@cindex Cracker, Sicherheit gegen
+@cindex Sicherheit, gegen Cracker
+
+Wenn Sie sich mit einem MySQL-Server verbinden, sollten Sie normalerweise
+ein Passwort benutzen. Das Passwort wird nicht als Klartext über die
+Verbindung übermittelt. Allerdings ist der Verschlüsselungsalgorithmus
+nicht sehr stark, so dass ein cleverer Angreifer mit einiger Mühe das
+Passwort knacken kann, wenn er in der Lage ist, den Verkehr zwischen Client
+und Server abzuhören. Wenn die Verbindung zwischen Client und Server über
+ein nicht vertrauenswürdiges Netzwerk geht, sollten Sie einen SSH-Tunnel
+benutzen, um die Kommunikation zu verschlüsseln.
+
+Jede sonstige Information wird als Klartext übermittelt, die von jedem
+gelesen werden kann, der in der Lage ist, die Verbindung abzuhören. Wenn
+Sie das beunruhigt, können Sie das komprimierte Protokoll benutzen (ab
+MySQL-Version 3.22), um so etwas zu erschweren. Um die Dinge noch sicherer
+zu machen, sollten Sie @code{ssh} benutzen. Sie finden einen Open-Source-
+@code{ssh}-Client auf @uref{http://www.openssh.org} und einen kommerziellen
+@code{ssh}-Client auf @uref{http://www.ssh.com}. Mit diesen erhalten Sie
+eine verschlüsselte TCP/IP-Verbindung zwischen einem MySQL-Server und einem
+MySQL-Client.
+
+Um ein MySQL-System sicher zu machen, sollten Sie auf jeden Fall folgende
+Vorschläge in Betracht ziehen:
+
+@itemize @bullet
+@item
+Benutzen Sie Passwörter für alle MySQL-Benutzer. Bedenken Sie, dass sich
+jeder beliebige als andere Person einloggen kann, und zwar so einfach wie
+@code{mysql -u anderer_benutzer db_name}, wenn @code{anderer_benutzer} kein
+Passwort hat. Es ist ein normales Verhalten bei
+Client-Server-Applikationen, dass der Client einen beliebigen Benutzernamen
+angeben kann. Sie können das Passwort für alle Benutzer ändern, indem Sie
+das @code{mysql_install_db}-Skript editieren, bevor Sie es laufen lassen,
+oder nur das Passwort für den MySQL-@code{root}-Benutzer, wie folgt:
+
+@example
+shell> mysql -u root mysql
+mysql> UPDATE user SET Password=PASSWORD('neues_passwort')
+ WHERE user='root';
+mysql> FLUSH PRIVILEGES;
+@end example
+
+@item
+Lassen Sie den MySQL-Daemon nicht als Unix-@code{root}-Benutzer laufen. Das
+ist sehr gefährlich, denn jeder Benutzer mit @code{FILE}-Berechtigung ist
+dann in der Lage, Dateien als @code{root} zu erzeugen (zum Beispiel
+@code{~root/.bashrc}). Um das zu verhindern, weigert sich @code{mysqld},
+als @code{root} zu laufen, es sei denn, das wird direkt durch die
+@code{--user=root}-Option angegeben.
+
+@code{mysqld} kann unter einem gewöhnlichen Benutzer ohne besondere Rechte
+laufen. Sie können auch einen neuen Unix-Benutzer @code{mysql} anlegen, um
+alles noch sicherer zu machen. Wenn Sie @code{mysqld} als ein anderer
+Unix-Benutzer laufen lassen, müssen Sie nicht den @code{root}-Benutzernamen
+in der @code{user}-Tabelle ändern, denn MySQL-Benutzernamen haben nichts
+mit den Unix-Benutzernamen zu tun. Um @code{mysqld} als anderer
+Unix-Benutzer zu starten, fügen Sie eine @code{user}-Zeile hinzu, die den
+Benutzernamen zur @code{[mysqld]}-Gruppe der
+@file{/etc/my.cnf}-Optionsdatei oder der @file{my.cnf}-Optionsdatei im
+Daten-Verzeichnis des Servers hinzufügt. Beispiel:
+
+@example
+[mysqld]
+user=mysql
+@end example
+
+Das bewirkt, dass der Server als der festgelegte Benutzer gestartet wird,
+egal ob Sie ihn manuell oder mit @code{safe_mysqld} oder
+@code{mysql.server} starten. Weitere Details finden Sie unter @ref{Privilege changes, , MySQL-Benutzer ändern}.
+
+@item
+Unterstützen Sie keine Symlinks auf Tabellen (das kann mit der
+@code{--skip-symlink}-Option abgeschaltet werden). Das ist insbesondere
+wichtig, wenn Sie @code{mysqld} als Root laufen lassen, weil jeder, der
+Schreibzugriff auf das mysqld-Daten-Verzeichnis hat, dann jede Datei im
+System zerstören könnte!
+@xref{Symbolic links to tables}.
+
+@item
+Überprüfen Sie, dass der Unix-Benutzer, der @code{mysqld} laufen läßt, der
+einzige Benutzer mit Lese-/Schreibzugriffen auf die Datenbankverzeichnisse
+ist.
+
+@item
+Geben Sie nicht allen Benutzern das @strong{process}-Zugriffsrecht. Die
+Ausgabe von @code{mysqladmin processlist} zeigt den Text der aktuell
+ausgeführten Anfragen, so dass jeder, der diesen Befehl ausführen darf, in
+der Lage wäre, eine Anfrage eines anderen Benutzers wie @code{UPDATE user
+SET password=PASSWORD('not_secure')} einzusehen.
+
+@code{mysqld} reserviert eine zusätzliche Verbindung für Benutzer, die das
+@strong{process}-Zugriffsrecht haben, so dass sich ein
+MySQL-@code{root}-Benutzer einloggen und Dinge überprüfen kann, selbst wenn
+alle normalen Verbindungen in Benutzung sind.
+
+@item
+Geben Sie nicht allen Benutzern das @strong{file}-Zugriffsrecht. Jeder
+Benutzer, der dieses Zugriffsrecht hat, kann irgendwo im Dateisystem
+Dateien mit den Rechten des the @code{mysqld}-Daemons schreiben! Um das
+etwas sicherer zu machen, sind alle Dateien, die mit @code{SELECT ... INTO
+OUTFILE} erzeugt werden, für jeden lesbar und können keine existierenden
+Dateien überschreiben.
+
+@tindex /etc/passwd
+Das @strong{file}-Zugriffsrecht kann auch benutzt werden, um jede Datei zu
+lesen, auf die der Unix-Benutzer Zugriff hat, als der der Server läuft. Das
+könnte zum Beispiel durch Benutzung von @code{LOAD DATA} missbraucht
+werden, um @file{/etc/passwd} in eine Tabelle zu laden, die anschließend
+mit @code{SELECT} gelesen wird.
+
+@item
+Wenn Sie Ihrem DNS nicht trauen, sollten Sie IP-Nummern anstelle von
+Hostnamen in den Berechtigungstabellen verwenden. In jedem Fall sollten Sie
+sehr vorsichtig damit sein, Einträge in Berechtigungstabellen vorzunehmen,
+die Hostnamen mit Platzhaltern (Wildcards) verwenden!
+
+@item
+Wenn Sie die Anzahl der Verbindungen für einen einzelnen Benutzer
+beschränken wollen, können Sie das tun, indem Sie die
+@code{max_user_Verbindungen}-Variable in @code{mysqld} setzen.
+@end itemize
+
+
+
+@node Privileges options, What Privileges, Security, Privilege system
+@c German node Berechtigungsoptionen
+@subsection Startoptionen für @code{mysqld} in Bezug auf Sicherheit
+
+Folgende @code{mysqld}-Optionen berühren Sicherheitsaspekte:
+
+@table @code
+@item --safe-show-database
+Mit dieser Option gibt @code{SHOW DATABASES} nur die Datenbanken zurück,
+für die der Benutzer irgend welche Rechte hat.
+
+@item --safe-user-create
+Wenn das angeschaltet ist, kann ein Benutzer keine neuen Benutzer mit dem
+@code{GRANT}-Befehl anlegen, wenn der kein @code{INSERT}-Zugriffsrecht auf
+die @code{mysql.user}-Tabelle hat. Wenn Sie dem Benutzer nur das Recht
+geben wollen, neue Benutzer mit den Berechtigungen anzulegen, die er
+vergeben darf, sollten Sie ihm folgende Berechtigung geben:
+
+@example
+GRANT INSERT(benutzer) on mysql.user to 'benutzer'@'hostname';
+@end example
+
+Das stellt sicher, dass der Benutzer keine Berechtigungsspalten direkt
+ändern kann, sondern dafür den @code{GRANT}-Befehl benutzen muss.
+
+@item --skip-grant-tables
+Diese Option veranlasst den Server, das Berechtigungssystem überhaupt nicht
+zu benutzen. Das gibt jedem @emph{vollen Zugriff} auf alle Datenbanken!
+(Einen laufenden Server können Sie veranlassen, die Berechtigungstabellen
+erneut zu verwenden, indem Sie @code{mysqladmin flush-privileges} oder
+@code{mysqladmin reload} ausführen.)
+
+@item --skip-name-resolve
+Hostnamen werden nicht aufgelöst. Alle @code{Host}-Spaltenwerte in den
+Berechtigungstabellen müssen IP-Nummern oder @code{localhost} sein.
+
+@item --skip-networking
+Keine TCP/IP-Verbindungen über das Netzwerk zulassen. Alle Verbindungen zu
+@code{mysqld} müssen über Unix-Sockets gemacht werden. Diese Option ist
+ungeeignet für Systeme, die MIT-pThreads benutzen, weil das
+MIT-pThreads-Paket keine Unix-Sockets unterstützt.
+
+@item --skip-show-database
+Mit dieser Option gibt das @code{SHOW DATABASES}-Statement nichts zurück.
+
+@end table
+
+
+@node What Privileges, Privileges, Privileges options, Privilege system
+@c German node Welche Berechtigungen
+@subsection Was das Berechtigungssystem macht
+
+@cindex System, Berechtigungen
+@cindex Berechtigungssystem
+@cindex Passwörter, Sicherheit
+
+Die primäre Funktion des MySQL-Berechtigungssystem ist, einen Benutzer zu
+authentifizieren, der sich von einem gegebenen Host aus verbindet, und
+diesen Benutzer Berechtigungen auf eine Datenbank zuzuordnen, wie
+@strong{select}, @strong{insert}, @strong{update} und @strong{delete}.
+
+Zusätzliche Funktionalität beinhaltet die Möglichkeit, einen anonymen
+Benutzer anzulegen und Berechtigungen für MySQL-spezifische Funktionen wie
+@code{LOAD DATA INFILE} und für administrative Operationen zu gewähren.
+
+
+@node Privileges, Privileges provided, What Privileges, Privilege system
+@c German node Berechtigungen
+@subsection Wie das Berechtigungssystem funktioniert
+
+@cindex Berechtigungssystem, Beschreibung
+
+Das MySQL-Berechtigungssystem stellt sicher, dass alle Benutzer nur genau
+die Dinge tun dürfen, zu denen sie berechtigt sind. Wenn Sie sich mit einem
+MySQL-Server verbinden, wird Ihre Identität @strong{durch den Host, von dem
+Sie sich aus verbinden,} festgelegt und @strong{durch den Benutzernamen,
+den Sie angeben}. Das System gewährt Berechtigungen gemäß Ihrer Identität
+und gemäß dem, @strong{was Sie tun wollen}.
+
+MySQL zieht sowohl Hostnamen als auch Benutzernamen heran, um Sie zu
+identifizieren, weil es kaum Grund gibt anzunehmen, dass ein gegebener
+Benutzername derselben Person woanders auf dem Internet gehört. So muss zum
+Beispiel der Benutzer @code{bill}, der sich von @code{whitehouse.gov} aus
+verbindet, nicht notwendigerweise dieselbe Person sein, die sich als
+Benutzer @code{bill} von @code{microsoft.com} aus verbindet.
+MySQL erlaubt Ihnen deshalb, Benutzer auf unterschiedlichen Hosts
+auseinander zu halten, die zufällig denselben Namen haben: Sie können
+@code{bill} einen Satz von Berechtigungen für Verbindungen von
+@code{whitehouse.gov} und einen anderen Satz von Berechtigungen für
+Verbindungen von @code{microsoft.com} aus gewähren.
+
+Die MySQL-Zugriffskontrolle läuft in zwei Phasen ab:
+
+@itemize @bullet
+@item
+Phase 1: Der Server überprüft, ob Sie das Recht haben, sich verbinden zu
+können.
+
+@item
+Phase 2: Angenommen, Sie haben das Recht, sich zu verbinden, dann überprüft
+der Server jede Anfrage, die Sie absetzen, um festzustellen, ob Sie
+ausreichende Rechte haben, um diese auszuführen. Wenn Sie zum Beispiel
+Zeilen aus einer Tabellen in einer Datenbank auswählen oder eine Tabelle in
+einer Datenbank löschen, stellt der Server sicher, dass Sie die
+@strong{select}-Berechtigung für die Tabelle bzw. die
+@strong{drop}-Berechtigung für die Datenbank haben.
+@end itemize
+
+Der Server benutzt die @code{user}-, @code{db}- und @code{host}-Tabellen in
+der @code{mysql}-Datenbank in beiden Phasen der Zugriffskontrolle. Die
+Felder in diesen Berechtigungstabellen sind unten dargestellt:
+
+@multitable @columnfractions .2 .25 .25 .25
+@item @strong{Tabellenname} @tab @code{user} @tab @code{db} @tab @code{host}
+
+@item @strong{Geltungsbereichs-Felder} @tab @code{Host} @tab @code{Host} @tab @code{Host}
+@item @tab @code{User} @tab @code{Db} @tab @code{Db}
+@item @tab @code{Password} @tab @code{User} @tab
+
+@item @strong{Berechtigungs-Felder} @tab @code{Select_priv} @tab @code{Select_priv} @tab @code{Select_priv}
+@item @tab @code{Insert_priv} @tab @code{Insert_priv} @tab @code{Insert_priv}
+@item @tab @code{Update_priv} @tab @code{Update_priv} @tab @code{Update_priv}
+@item @tab @code{Delete_priv} @tab @code{Delete_priv} @tab @code{Delete_priv}
+@item @tab @code{Index_priv} @tab @code{Index_priv} @tab @code{Index_priv}
+@item @tab @code{Alter_priv} @tab @code{Alter_priv} @tab @code{Alter_priv}
+@item @tab @code{Create_priv} @tab @code{Create_priv} @tab @code{Create_priv}
+@item @tab @code{Drop_priv} @tab @code{Drop_priv} @tab @code{Drop_priv}
+@item @tab @code{Grant_priv} @tab @code{Grant_priv} @tab @code{Grant_priv}
+@item @tab @code{References_priv} @tab @tab
+@item @tab @code{Reload_priv} @tab @tab
+@item @tab @code{Shutdown_priv} @tab @tab
+@item @tab @code{Process_priv} @tab @tab
+@item @tab @code{File_priv} @tab @tab
+@end multitable
+
+In der zweiten Phase der Zugriffskontrolle (Anfrage-Verifikation), zieht
+der Server gegebenenfalls zusätzlich die @code{tables_priv}- und
+@code{columns_priv}-Tabellen heran, falls Ihre Anfrage Tabellen betrifft.
+Die Felder in diesen Tabellen sind unten dargestellt:
+
+@multitable @columnfractions .2 .25 .25
+@item @strong{Tabellenname} @tab @code{tables_priv} @tab @code{columns_priv}
+
+@item @strong{Geltungsbereichs-Felder} @tab @code{Host} @tab @code{Host}
+@item @tab @code{Db} @tab @code{Db}
+@item @tab @code{User} @tab @code{User}
+@item @tab @code{Table_name} @tab @code{Table_name}
+@item @tab @tab @code{Column_name}
+
+@item @strong{Berechtigungs-Felder} @tab @code{Table_priv} @tab @code{Column_priv}
+@item @tab @code{Column_priv} @tab
+
+@item @strong{Sonstige Felder} @tab @code{Timestamp} @tab @code{Timestamp}
+@item @tab @code{Grantor} @tab
+@end multitable
+
+Jede Berechtigungstabelle enthält Geltungsbereichsfelder und
+Berechtigungsfelder.
+
+Geltungsbereichsfelder legen den Geltungsbereich jedes Eintrags in den
+Tabellen fest, das heißt, der Kontext, für den der Eintrag gilt. So würde
+zum Beispiel ein @code{user}-Tabelleneintrag mit @code{Host}- und
+@code{User}-Werten von @code{'thomas.loc.gov'} und @code{'bob'} benutzt
+werden, um Verbindungen zum Server zu authentifizieren, die von @code{bob}
+vom Host @code{thomas.loc.gov} gemacht werden. In ähnlicher Weise bewirkt
+ein @code{db}-Tabelleneintrag in die Felder @code{Host}, @code{User} und
+@code{Db} mit @code{'thomas.loc.gov'}, @code{'bob'} und @code{'reports'},
+dass diese benutzt werden, wenn sich @code{bob} vom Host
+@code{thomas.loc.gov} verbindet und auf die @code{reports}-Datenbank zugreift.
+Die @code{tables_priv}- und @code{columns_priv}-Tabellen enthalten
+Geltungsbereichsfelder, die Tabellen oder Tabellen-Spalten-Kombinationen
+angeben, auf die sich der jeweilige Eintrag bezieht.
+
+@cindex Groß-/Kleinschreibung, bei der Zugriffsprüfung
+Für Zwecke der Zugriffsprüfung sind Vergleiche von @code{Host}-Werten
+unabhängig von der verwendeten Groß-/Kleinschreibung. @code{User},
+@code{Password}, @code{Db} und @code{Table_name}-Werte sind abhängig von
+der verwendeten Groß-/Kleinschreibung. @code{Column_name}-Werte sind ab
+MySQL-Version 3.22.12 unabhängig von der verwendeten
+Groß-/Kleinschreibung.
+
+Berechtigungsfelder zeigen die Berechtigungen an, die durch den
+Tabelleneintrag gewährt werden, das heißt, welche Operationen durchgeführt
+werden können. Der Server kombiniert die Informationen in den verschiedenen
+Berechtigungstabellen, um daraus eine komplette Beschreibung der
+Berechtigungen des Benutzers zu formulieren. Die Regeln, nach denen hierbei
+vorgegangen wird, sind in @ref{Request access} beschrieben.
+
+Geltungsbereichsfelder sind Zeichenketten, die wie unten dargestellt
+deklariert werden. Der Vorgabewert für jedes Feld ist die leere
+Zeichenkette:
+
+@multitable @columnfractions .15 .15 .7
+@item @strong{Feldname} @tab @strong{Typ}
+@item @code{Host} @tab @code{CHAR(60)}
+@item @code{User} @tab @code{CHAR(16)}
+@item @code{Password} @tab @code{CHAR(16)}
+@item @code{Db} @tab @code{CHAR(64)} @tab (@code{CHAR(60)} für
+die @code{tables_priv}- und @code{columns_priv}-Tabellen)
+@item @code{Table_name} @tab @code{CHAR(60)}
+@item @code{Column_name} @tab @code{CHAR(60)}
+@end multitable
+
+In den @code{user}-, @code{db}- und @code{host}-Tabellen werden alle Felder
+als @code{ENUM('N','Y')} deklariert. Jedes Feld kann einen Wert von
+@code{'N'} oder @code{'Y'} haben. Der Vorgabewert ist @code{'N'}.
+
+In den @code{tables_priv}- und @code{columns_priv}-Tabellen werden Felder
+als @code{SET}-Felder deklariert:
+
+@multitable @columnfractions .2 .2 .6
+@item @strong{Tabellenname} @tab @strong{Feldname} @tab @strong{Mögliche Set-Elemente}
+@item @code{tables_priv} @tab @code{Table_priv} @tab @code{'Select', 'Insert',
+'Update', 'Delete', 'Create', 'Drop', 'Grant', 'Referenzs', 'Index', 'Alter'}
+@item @code{tables_priv} @tab @code{Column_priv} @tab @code{'Select', 'Insert',
+'Update', 'References'}
+@item @code{columns_priv} @tab @code{Column_priv} @tab @code{'Select', 'Insert',
+'Update', 'References'}
+@end multitable
+
+Kurz gesagt benutzt der Server die Berechtigungstabellen wie folgt:
+
+@itemize @bullet
+@item
+Das @code{user}-Tabellenbereichsfeld legt fest, ob eingehende Verbindungen
+zugelassen oder abgewiesen werden. Bei zugelassenen Verbindungen zeigen
+Berechtigungen, die in der @code{user}-Tabelle vergeben sind, die globalen
+(Superuser-) Rechte des Benutzers an. Diese Berechtigungen treffen auf
+@strong{alle} Datenbanken auf dem Server zu.
+
+@item
+Die @code{db}- und @code{host}-Tabellen werden zusammen benutzt:
+
+@itemize @minus
+@item
+Die Geltungsbereichsfelder der @code{db}-Tabelle legen fest, welche
+Benutzer auf welche Datenbanken von welchen Hosts aus zugreifen können. Die
+Berechtigungsfelder legen fest, welche Operationen zugelassen sind.
+
+@item
+Die @code{host}-Tabelle wird als Erweiterung der @code{db}-Tabelle benutzt,
+wenn Sie wollen, dass ein gegebener @code{db}-Tabelleneintrag auf
+verschiedene Hosts zutrifft. Wenn Sie zum Beispiel wollen, dass ein
+Benutzer eine Datenbank von mehreren Hosts in Ihrem Netzwerk aus benutzen
+kann, lassen Sie den @code{Host}-Wert in der @code{db}-Tabelle des
+Benutzers leer, und füllen dann die @code{host}-Tabelle mit einem Eintrag
+für jeden dieser Hosts. Dieser Mechanismus ist ausführlicher in
+@ref{Request access} beschrieben.
+@end itemize
+
+@item
+Die @code{tables_priv}- und @code{columns_priv}-Tabellen sind der
+@code{db}-Tabelle ähnlich, aber feinkörniger: Sie beziehen sich auf
+Tabellen- und Spaltenebenen und nicht auf Datenbankebene.
+@end itemize
+
+Beachten Sie, dass die Verwaltungsberechtigungen (@strong{reload},
+@strong{shutdown} usw.) nur in der @code{user}-Tabelle festgelegt werden.
+Das liegt daran, dass Verwaltungsoperationen Operationen auf dem Server
+selbst sind und nicht Datenbank-spezifisch, so dass es keinen Grund gibt,
+solche Berechtigungen in den anderen Berechtigungstabellen aufzuführen. So
+muss nur die @code{user}-Tabelle untersucht werden um festzustellen, ob man
+Verwaltungsoperationen durchführen kann oder nicht.
+
+Das @strong{file}-Zugriffsrecht wird auch nur in der @code{user}-Tabelle
+festgelegt. Es ist als solches keine Verwaltungsberechtigung, aber Ihre
+Möglichkeit, Dateien auf dem Server zu lesen oder zu schreiben, ist
+unabhängig von der Datenbank, auf die Sie zugreifen.
+
+Der @code{mysqld}-Server liest die Inhalte der Berechtigungstabellen
+einmal, und zwar beim Start. Änderungen in den Berechtigungstabellen werden
+wirksam wie in @ref{Privilege changes} geschildert.
+
+Wenn Sie die Inhalte der Berechtigungstabellen ändern, sollten Sie
+sicherstellen, dass Ihre Änderungen Berechtigungen einführen, die Sie so
+haben wollen. Hilfe bei der Diagnose von Problemen finden Sie unter
+@ref{Access denied}. Hinweise zu Sicherheitsthemen finden Sie unter
+@pxref{Security}.
+
+Ein nützliches Diagnosetool ist das @code{mysqlaccess}-Skript, das Yves
+Carlier für die MySQL-Distribution bereit gestellt hat. Rufen Sie
+@code{mysqlaccess} mit der @code{--help}-Option auf, um herauszufinden, wie
+es funktioniert. Beachten Sie, dass @code{mysqlaccess} den Zugriff nur
+anhand der @code{user}-, @code{db}- und @code{host}-Tabellen überprüft. Es
+überprüft keine Tabellen- oder Spaltenebenen-Berechtigungen.
+
+
+@node Privileges provided, Connecting, Privileges, Privilege system
+@c German node Zur Verfügung gestellte Berechtigungen
+@subsection Von MySQL zur Verfügung gestellte Berechtigungen
+
+@cindex Berechtigungsinformation, Speicherort
+
+Informationen über Benutzerberechtigungen sind in den @code{user}-,
+@code{db}-, @code{host}-, @code{tables_priv}- und
+@code{columns_priv}-Tabellen in der @code{mysql}-Datenbank gespeichert (das
+heißt in der Datenbank, die @code{mysql} heißt). Der MySQL-Server liest
+die Inhalte dieser Tabellen, wenn er startet, und in den Fällen, die unter
+@ref{Privilege changes} geschildert sind.
+
+Die Namen, die in diesem Handbuch benutzt werden, um auf die Berechtigungen
+zu verweisen, die MySQL zur Verfügung stellt, sind unten dargestellt,
+zusammen mit den Tabellenspaltennamen, die jeder Berechtigung in the
+Berechtigungstabellen zugeordnet sind, und dem Kontext, auf den die
+Berechtigung zutrifft.
+
+@multitable @columnfractions .15 .25 .6
+@item @strong{Berechtigung} @tab @strong{Spalte} @tab @strong{Kontext}
+@item @strong{select} @tab @code{Select_priv} @tab Tabellen
+@item @strong{insert} @tab @code{Insert_priv} @tab Tabellen
+@item @strong{update} @tab @code{Update_priv} @tab Tabellen
+@item @strong{delete} @tab @code{Delete_priv} @tab Tabellen
+@item @strong{index} @tab @code{Index_priv} @tab Tabellen
+@item @strong{alter} @tab @code{Alter_priv} @tab Tabellen
+@item @strong{create} @tab @code{Create_priv} @tab Datenbanken, Tabellen oder Indexe
+@item @strong{drop} @tab @code{Drop_priv} @tab Datenbanken oder Tabellen
+@item @strong{grant} @tab @code{Grant_priv} @tab Datenbanken oder Tabellen
+@item @strong{References} @tab @code{References_priv} @tab Datenbanken oder Tabellen
+@item @strong{reload} @tab @code{Reload_priv} @tab Serververwaltung
+@item @strong{shutdown} @tab @code{Shutdown_priv} @tab Serververwaltung
+@item @strong{process} @tab @code{Process_priv} @tab Serververwaltung
+@item @strong{file} @tab @code{File_priv} @tab Dateizugriff auf den Server
+@end multitable
+
+Die @strong{select}-, @strong{insert}-, @strong{update}- und
+@strong{delete}-Berechtigungen erlauben Ihnen, Operationen auf Zeilen in
+existierenden Tabellen in einer Datenbank durchzuführen.
+
+@code{SELECT}-Statements erfordern die @strong{select}-Berechtigung nur
+dann, wenn tatsächlich Zeilen aus einer Tabelle abgerufen werden. Sie
+können bestimmte @code{SELECT}-Statements selbst ohne Berechtigung
+durchführen, um auf jede der Datenbanken auf dem Server zuzugreifen.
+Beispielsweise könnten Sie den @code{mysql}-Client als einfachen
+Taschenrechner benutzen:
+
+@example
+mysql> SELECT 1+1;
+mysql> SELECT PI()*2;
+@end example
+
+Die @strong{index}-Berechtigung erlaubt Ihnen, Indexe zu erzeugen oder zu
+entfernen.
+
+Die @strong{alter}-Berechtigung erlaubt Ihnen, @code{ALTER TABLE} zu
+benutzen.
+
+Die @strong{create}- und @strong{drop}-Berechtigungen erlauben Ihnen, neue
+Datenbanken und Tabellen zu erzeugen oder bestehende Datenbanken und
+Tabellen zu entfernen.
+
+Denken Sie daran, dass ein Benutzer, dem Sie die @strong{drop}-Berechtigung
+für die @code{mysql}-Datenbank gewähren, in der Lage ist, die Datenbank zu
+löschen, in der die MySQL-Zugriffsberechtigungen gespeichert sind!
+
+Die @strong{grant}-Berechtigung erlaubt Ihnen, die Berechtigungen, die Sie
+selbst besitzen, an andere Benutzer zu vergeben.
+
+Die @strong{file}-Berechtigung erlaubt Ihnen, Dateien auf dem Server zu
+lesen und zu schreiben, wenn Sie die @code{LOAD DATA INFILE}- und
+@code{SELECT ... INTO OUTFILE}-Statements benutzen. Jeder Benutzer, dem
+diese Berechtigung gewährt wurde, kann jedwede Datei lesen oder schreiben,
+die der MySQL-Server lesen oder schreiben darf.
+
+Die restlichen Berechtigungen werden für Verwaltungsoperationen benutzt,
+die mit dem @code{mysqladmin}-Programm durchgeführt werden. Die unten
+stehende Tabelle zeigt, welche @code{mysqladmin}-Befehle mit jeder
+Verwaltungsberechtigung ausgeführt werden können:
+
+@multitable @columnfractions .15 .85
+@item @strong{Berechtigung} @tab @strong{Befehle, die dem Berechtigten erlaubt sind}
+@item @strong{reload} @tab @code{reload}, @code{refresh},
+@code{flush-privileges}, @code{flush-hosts}, @code{flush-logs} und
+@code{flush-tables}
+@item @strong{shutdown} @tab @code{shutdown}
+@item @strong{process} @tab @code{processlist}, @code{kill}
+@end multitable
+
+Der @code{reload}-Befehl weist den Server an, die Berechtigungstabellen neu
+einzulesen. Der @code{refresh}-Befehl schreibt alle Tabellen auf Platte
+(flush) und öffnet und schließt die Log-Dateien. @code{flush-privileges}
+ist ein Synonym für @code{reload}. Die anderen @code{flush-*}-Befehle
+führen Funktionen aus, die @code{refresh} ähnlich sind, aber im Umfang
+beschränkter und daher in einigen Fällen zu bevorzugen. Wenn Sie zum
+Beispiel nur die Log-Dateien flushen wollen, ist @code{flush-logs}
+@code{refresh} vorzuziehen.
+
+Der @code{shutdown}-Befehl fährt den Server herunter.
+
+Der @code{processlist}-Befehl zeigt Informationen über die Threads an, die
+im Server ausgeführt werden. Der @code{kill}-Befehl killt Server-Threads.
+Ihre eigenen Threads können Sie jederzeit anzeigen oder killen, aber Sie
+brauchen die @strong{process}-Berechtigung, um Threads anzuzeigen oder zu
+killen, die von anderen Benutzern initiiert wurden. @xref{KILL}.
+
+Es ist generell eine gute Idee, Berechtigungen nur den Nutzern zu gewähren,
+die diese tatsächlich brauchen, aber speziell bei folgenden Berechtigungen
+sollten Sie besondere Vorsicht walten lassen:
+
+@itemize @bullet
+@item
+Die @strong{grant}-Berechtigung erlaubt Benutzern, Ihre Berechtigungen an
+andere Benutzer zu übertragen. Zwei Benutzer mit unterschiedlichen
+Berechtigungen und mit der @strong{grant}-Berechtigung sind in der Lage,
+Ihre Berechtigungen zu kombinieren.
+
+@item
+Die @strong{alter}-Berechtigung kann benutzt werden, um das
+Berechtigungssystem zu unterlaufen, indem Tabellen umbenannt werden.
+
+@item
+Die @strong{file}-Berechtigung kann missbraucht werden, um jede öffentlich
+lesbare Datei auf dem Server in eine Datenbanktabelle einzulesen, auf deren
+Inhalte dann mit @code{SELECT} zugegriffen werden kann. Das beinhaltet die
+Inhalte aller Datenbanken, die vom Server gehostet werden!
+
+@item
+Die @strong{shutdown}-Berechtigung kann missbraucht werden, um andere
+Benutzer komplett vom Server auszuschließen, indem der Server beendet
+wird.
+
+@item
+Die @strong{process}-Berechtigung kann benutzt werden, um den Klartext von
+momentan ablaufenden Anfragen einzusehen, inklusive Anfragen, die
+Passwörter setzen oder ändern.
+
+@item
+Zugriffsrechte auf die @code{mysql}-Datenbank können benutzt werden, um
+Passwörter zu ändern und auf sonstige Berechtigungsinformationen
+zuzugreifen. (Passwörter werden verschlüsselt gespeichert, daher kann ein
+böswilliger Benutzer sie nicht einfach lesen und anschließend die
+Klartext-Passwörter kennen.) Wenn man auf die
+@code{mysql.user}-Passwort-Spalte zugreifen kann, kann man das nutzen, um
+sich als beliebiger Benutzer am MySQL-Server anzumelden. (Mit ausreichenden
+Rechten kann derselbe Benutzer dann Passwörter durch eigene ersetzen.)
+@end itemize
+
+Es gibt einige Dinge, die Sie mit dem MySQL-Berechtigungssystem nicht tun
+können:
+
+@itemize @bullet
+@item
+Sie können nicht ausdrücklich festlegen, dass ein bestimmter Benutzer
+keinen Zugriff haben soll. Das heißt, Sie können nicht explizit mit einem
+bestimmten Benutzer vergleichen und dann die Verbindung ablehnen.
+
+@item
+Sie können nicht festlegen, dass ein Benutzer das Recht hat, Tabellen in
+einer Datenbank zu erzeugen oder zu löschen, aber nicht die Datenbank
+selbst zu erzeugen oder zu löschen.
+@end itemize
+
+
+@node Connecting, Connection access, Privileges provided, Privilege system
+@c German node Verbinden
+@subsection Verbinden mit dem MySQL-Server
+
+@cindex Verbinden, mit dem MySQL-Server
+@cindex Vorgabemäßiger Hostname
+@cindex Hostname, Vorgabe
+@cindex Server, verbinden
+
+MySQL-Client-Programme erfordern im Allgemeinen, dass Sie
+Verbindungsparameter festlegen, wenn Sie sich mit einem MySQL-Server
+verbinden wollen: Der Host, mit dem Sie sich verbinden wollen, Ihr
+Benutzername und Ihr Passwort. Beispielsweise kann der @code{mysql}-Client
+wie folgt gestartet werden (optionale Argumente sind in @samp{[} und
+@samp{]} eingeschlossen):
+
+@example
+shell> mysql [-h hostname] [-u benutzername] [-pihr_passwort]
+@end example
+
+Alternative Formen der @code{-h}-, @code{-u}- und @code{-p}-Optionen sind
+@code{--host=hostname}, @code{--user=benutzername} und
+@code{--password=ihr_passwort}. Beachten Sie, dass zwischen @code{-p} oder
+@code{--password=} und dem folgenden Passwort @emph{kein Leerzeichen}
+steht!
+
+@strong{ACHTUNG:} Ein Passwort auf der Kommandozeile anzugeben ist nicht
+sicher! Jeder Benutzer auf Ihrem System kann dann Ihr Passwort
+herausfinden, indem er einen Befehl wie @code{ps auxww} eingibt.
+@xref{Option files}.
+
+@code{mysql} benutzt Vorgabewerte für Verbindungsparameter, die auf der
+Kommandozeile nicht angegeben sind:
+
+@itemize @bullet
+@item
+Der vorgabemäßige Hostname ist @code{localhost}.
+
+@item
+Der vorgabemäßige Benutzername ist Ihr Unix-Loginname.
+
+@item
+Es wird kein Passwort übergeben, wenn @code{-p} fehlt.
+@end itemize
+
+Für einen Unix-Benutzer @code{joe} sind daher folgende Befehle
+gleichbedeutend:
+
+@example
+shell> mysql -h localhost -u joe
+shell> mysql -h localhost
+shell> mysql -u joe
+shell> mysql
+@end example
+
+Andere MySQL-Clients verhalten sich ähnlich.
+
+Auf Unix-Systemen können Sie andere Vorgabewerte festlegen, die benutzt
+werden, wenn Sie eine Verbindung aufmachen, so dass Sie diese nicht jedes
+Mal auf der Kommandozeile eingeben müssen, wenn Sie ein Client-Programm
+aufrufen. Das kann auf verschiedene Weise gemacht werden:
+
+@itemize @bullet
+@item
+@tindex .my.cnf-Datei
+Sie können Verbindungsparameter im @code{[client]}-Abschnitt der
+@file{.my.cnf}-Konfigurationsdatei in Ihrem Heimatverzeichnis festlegen.
+Der relevante Abschnitt der Datei sieht etwa wie folgt aus:
+
+@example
+[client]
+host=hostname
+user=benutzername
+password=ihr_passwort
+@end example
+
+@xref{Option files}.
+
+@item
+@tindex @code{MYSQL_HOST}-Umgebungsvariable
+@tindex Umgebungsvariable, @code{MYSQL_HOST}
+@tindex @code{MYSQL_PWD}-Umgebungsvariable
+@tindex Umgebungsvariable, @code{MYSQL_PWD}
+@tindex @code{USER}-Umgebungsvariable
+@tindex Umgebungsvariable, @code{USER}
+Sie können Verbindungsparameter festlegen, indem Sie Umgebungsvariablen
+benutzen. Der Host kann für @code{mysql} festgelegt werden, indem
+@code{MYSQL_HOST} benutzt wird. Der MySQL-Benutzername kann mit @code{USER}
+festgelegt werden (nur für Windows). Das Passwort kann mit @code{MYSQL_PWD}
+festgelegt werden (aber das ist unsicher, siehe nächster Abschnitt).
+@xref{Environment variables}.
+@end itemize
+
+
+@node Connection access, Request access, Connecting, Privilege system
+@c German node Verbindungszugriff
+@subsection Zugriffskontrolle, Phase 1: Verbindungsüberprüfung
+
+@cindex Zugriffskontrolle
+@cindex Kontrolle über den Zugriff
+@cindex Verbindung, Überprüfung
+@cindex Testen, Verbindung mit dem Server
+
+Wenn Sie versuchen, sich mit einem MySQL-Server zu verbinden, akzeptiert
+der Server die Verbindung oder weist sie zurück, abhängig von Ihrer
+Identität und davon, ob Sie diese mit dem korrekten Passwort verifizieren
+können. Falls nicht, lehnt der Server den Zugriff vollständig ab. Ansonsten
+akzeptiert der Server die Verbindung, geht dann in Phase 2 und wartet auf
+Anfragen.
+
+Ihre Identität basiert auf zwei Informationsbestandteilen:
+
+@itemize @bullet
+@item
+Dem Host, von dem Sie sich verbinden
+
+@item
+Ihrem MySQL-Benutzernamen
+@end itemize
+
+Die Identitätsüberprüfung wird anhand der drei Geltungsbereichs-Felder der
+@code{user}-Tabelle, nämlich (@code{Host}, @code{User} und @code{Password})
+durchgeführt. Der Server akzeptiert die Verbindung nur, wenn ein
+@code{user}-Tabelleneintrag mit Ihrem Hostnamen und Benutzernamen
+übereinstimmt und Sie das korrekte Passwort angeben können.
+
+Werte in den Geltungsbereichs-Feldern der @code{user}-Tabelle können wie folgt
+festgelegt werden:
+
+@itemize @bullet
+@item
+Ein @code{Host}-Wert kann ein Hostname oder eine IP-Nummer sein, oder
+@code{'localhost'}, was die lokale Maschine angibt.
+
+@item
+@cindex Platzhalter (Wildcards), in der @code{mysql.user}-Tabelle
+Sie können die Platzhalterzeichen @samp{%} und @samp{_} im @code{Host}-Feld
+benutzen.
+
+@item
+Ein @code{Host}-Wert @code{'%'} stimmt mit jedem Hostnamen überein.
+
+@item
+Ein leerer @code{Host}-Wert bedeutet, dass die Berechtigung zusammen mit
+dem Eintrag in der @code{host}-Tabelle gilt, der mit dem angegebenen
+Hostnamen übereinstimmt. Weitere Informationen hierzu finden Sie im
+nächsten Kapitel.
+
+@cindex Netmask-Notation, in der @code{mysql.user}-Tabelle
+@item
+Ab MySQL-Version 3.23 können @code{Host}-Werte als IP-Nummern festgelegt
+werden, und Sie können eine Netmask festlegen, die angibt, wie viele
+Adress-Bits für die Netzwerknummer benutzt werden. Beispiel:
+
+@example
+GRANT ALL PRIVILEGES on db.* to david@@'192.58.197.0/255.255.255.0';
+@end example
+
+Das erlaubt jedem, sich von einer IP zu verbinden, bei der folgendes gilt:
+
+@example
+benutzer_ip & netmask = host_ip.
+@end example
+
+Im obigen Beispiel können sich alle IP's im Intervall zwischen 192.58.197.0
+bis 192.58.197.255 mit dem MySQL-Server verbinden.
+
+@item
+@cindex anonymer Benutzer
+Platzhalterzeichen sind im @code{User}-Feld nicht erlaubt. Sie können aber
+einen leeren Wert angeben, der mit jedem Namen übereinstimmt. Wenn der
+Eintrag in der @code{user}-Tabelle, der mit einer hereinkommenden
+Verbindung übereinstimmt, einen leeren Benutzernamen hat, wird angenommen,
+dass der Benutzer der anonyme Benutzer ist (der Benutzer ohne Namen), und
+nicht der Name, den der Client tatsächlich angegeben hat. Das bedeutet,
+dass ein leerer Benutzername für alle weiteren Zugriffsüberprüfungen
+während der laufenden Verbindung benutzt wird (also während Phase 2).
+
+@item
+Das @code{Password}-Feld kann leer sein. Das bedeutet nicht, dass jedes
+Passwort übereinstimmt, sondern dass der Benutzer sich ohne Angabe eines
+Passworts verbinden muss.
+@end itemize
+
+@findex PASSWORD()
+Nicht-leere @code{Password}-Werte repräsentieren verschlüsselte Passwörter.
+MySQL speichert Passwörter nicht im Klartext, so dass jeder sie sehen
+könnte. Statt dessen wird das Passwort eines Benutzers, der sich zu
+verbinden versucht, verschlüsselt (unter Benutzung der
+@code{PASSWORD()}-Funktion). Das verschlüsselte Passwort wird dann benutzt,
+wenn Client / Server prüfen, ob das Passwort korrekt ist (das geschieht,
+ohne dass das verschlüsselte Passwort jemals über die Verbindung übertragen
+wird). Beachten Sie, dass aus der Sicht von MySQL das verschlüsselte
+Passwort das ECHTE Passwort ist, daher sollten Sie niemandem Zugriff darauf
+geben! Insbesondere sollten Sie keinem normalen Benutzer Lesezugriff auf
+die Tabellen der @code{mysql}-Datenbank geben!
+
+Die unten stehenden Beispiele zeigen, wie unterschiedliche Kombinationen
+von @code{Host}- und-@code{User}-Werten in den
+@code{user}-Tabelleneinträgen auf hereinkommende Verbindungen zutreffen:
+
+@multitable @columnfractions .25 .15 .60
+@item @code{Host} @strong{Wert} @tab @code{User} @strong{Wert} @tab @strong{Verbindungen, die mit dem Eintrag übereinstimmen}
+@item @code{'thomas.loc.gov'} @tab @code{'fred'} @tab @code{fred}, der sich von @code{thomas.loc.gov} aus verbindet
+@item @code{'thomas.loc.gov'} @tab @code{''} @tab Jeder Benutzer, der sich von @code{thomas.loc.gov} aus verbindet
+@item @code{'%'} @tab @code{'fred'} @tab @code{fred}, der sich von jedem Host aus verbindet
+@item @code{'%'} @tab @code{''} @tab Jeder Benutzer, der sich von jedem Host aus verbindet
+@item @code{'%.loc.gov'} @tab @code{'fred'} @tab @code{fred}, der sich von jedem beliebigen Host in der @code{loc.gov}-Domäne aus verbindet
+@item @code{'x.y.%'} @tab @code{'fred'} @tab @code{fred}, der sich von @code{x.y.net}, @code{x.y.com}, @code{x.y.edu} usw. aus verbindet (wahrscheinlich eher unsinnig)
+@item @code{'144.155.166.177'} @tab @code{'fred'} @tab @code{fred}, der sich vom Host mit der IP-Adresse @code{144.155.166.177} aus verbindet
+@item @code{'144.155.166.%'} @tab @code{'fred'} @tab @code{fred}, der sich von jedem beliebigen Host im Class-C-Subnet @code{144.155.166} aus verbindet
+@item @code{'144.155.166.0/255.255.255.0'} @tab @code{'fred'} @tab Dasselbe wie im vorherigen Beispiel
+@end multitable
+
+Weil Sie im @code{Host}-Feld IP-Platzhalterwerte verwenden können
+(beispielsweise @code{'144.155.166.%'}, was mit jedem Host in einem Subnet
+übereinstimmt), besteht die Möglichkeit, dass jemand diese Fähigkeit
+ausbeutet, indem er einen Host zum Beispiel
+@code{144.155.166.somewhere.com} nennt. Um solche Versuche zu vereiteln,
+verbietet MySQL den Vergleich mit Hostnamen, die mit Ziffern und einem
+Punkt übereinstimmen. Wenn Sie daher einen Host haben, der so wie
+@code{1.2.foo.com} benannt ist, wird sein Name nie mit der
+@code{Host}-Spalte der Berechtigungstabellen übereinstimmen. Nur eine
+IP-Nummer kann mit dem IP-Platzhalterwert übereinstimmen.
+
+Eine hereinkommende Verbindung kann mit mehr als einem Eintrag in der
+@code{user}-Tabelle übereinstimmen. Beispielsweise würde eine Verbindung
+von @code{thomas.loc.gov} aus durch @code{fred} mit mehreren der oben
+genannten Einträge übereinstimmen. Wie entscheidet der Server, welcher der
+Einträge benutzt werden soll, wenn mehrere zutreffen? Der Server löst
+dieses Problem, indem er die @code{user}-Tabelle nach dem Einlesen beim
+Start sortiert, und danach die Einträge in sortierter Form durchsieht, wenn
+ein Benutzer versucht, sich zu verbinden. Der erste übereinstimmende
+Eintrag ist der, der benutzt wird.
+
+Das Sortieren der @code{user}-Tabelle funktioniert wie folgt. Nehmen Sie
+an, dass die @code{user}-Tabelle so aussieht:
+
+@example
++-----------+----------+-
+| Host | User | ...
++-----------+----------+-
+| % | root | ...
+| % | jeffrey | ...
+| localhost | root | ...
+| localhost | | ...
++-----------+----------+-
+@end example
+
+Wenn der Server die Tabelle liest, ordnet er die Einträge mit den
+spezifischsten Einträgen für die @code{Host}-Werte zuerst ein (@code{'%'}
+in der @code{Host}-Spalte bedeutet ``jeder Host'' und ist am
+unspezifischsten). Einträge mit denselben @code{Host}-Werten werden mit den
+spezifischsten @code{User}-Werten zuerst geordnet (ein leerer
+@code{User}-Wert bedeutet ``jeder Benutzer'' und ist am
+unspezifischsten). Die daraus resultierende sortierte @code{user}-Tabelle
+sieht wie folgt aus:
+
+@example
++-----------+----------+-
+| Host | User | ...
++-----------+----------+-
+| localhost | root | ...
+| localhost | | ...
+| % | jeffrey | ...
+| % | root | ...
++-----------+----------+-
+@end example
+
+@cindex Berechtigungstabellen, sortieren
+@cindex sortieren, Berechtigungstabellen
+@cindex @code{user}-Tabelle, sortieren
+Beim Versuch einer Verbindung durchsucht der Server die sortierten Einträge
+und benutzt die ersten übereinstimmenden. Bei einer Verbindung von
+@code{localhost} aus durch @code{jeffrey} stimmen die Werte zuerst mit den
+Einträgen von @code{'localhost'} in der @code{Host}-Spalte überein. Hiervon
+stimmt der Eintrag mit dem leeren Benutzernamen sowohl mit dem verbindenden
+Host als auch mit dem Benutzernamen überein. (@code{'%'/'jeffrey'} hätte
+auch übereingestimmt, aber er ist nicht der erste Tabelleneintrag, der
+gefunden wird.)
+
+Hier ist ein weiteres Beispiel. Nehmen Sie an, die @code{user}-Tabelle
+sieht wie folgt aus:
+
+@example
++----------------+----------+-
+| Host | User | ...
++----------------+----------+-
+| % | jeffrey | ...
+| thomas.loc.gov | | ...
++----------------+----------+-
+@end example
+
+Die sortierte Tabelle sieht wie folgt aus:
+
+@example
++----------------+----------+-
+| Host | User | ...
++----------------+----------+-
+| thomas.loc.gov | | ...
+| % | jeffrey | ...
++----------------+----------+-
+@end example
+
+Eine Verbindung von @code{thomas.loc.gov} aus durch @code{jeffrey} stimmt
+mit dem ersten Eintrag überein, wohingegen eine Verbindung von
+@code{whitehouse.gov} aus durch @code{jeffrey} mit dem zweiten Eintrag
+übereinstimmt.
+
+Ein häufiges Missverständnis besteht darin zu denken, dass bei einem
+angegebenen Benutzernamen alle Einträge, die explizit den Benutzer nennen,
+zuerst benutzt werden, wenn der Server versucht, eine Übereinstimmung für
+die Verbindung zu finden. Das stimmt schlicht nicht. Das vorherige Beispiel
+stellt das dar, wobei eine Verbindung von @code{thomas.loc.gov} aus durch
+@code{jeffrey} zuerst gerade nicht mit dem Eintrag übereinstimmt, der
+@code{'jeffrey'} als @code{User}-Feldwert enthält, sondern mit dem Eintrag,
+der keinen Benutzernamen enthält!
+
+Wenn Sie Probleme haben, sich mit dem Server zu verbinden, geben Sie die
+@code{user}-Tabelle aus und sortieren Sie sich von Hand, um zu sehen, wo
+die erste Übereinstimmung stattfindet.
+
+
+@node Request access, Access denied, Connection access, Privilege system
+@c German node Anfragezugriff
+@subsection Zugriffskontrolle, Phase 2: Anfrageüberprüfung
+
+Wenn Sie erst einmal eine Verbindung hergestellt haben, geht der Server in
+Phase 2. Bei jeder Anfrage, die über diese Verbindung hereinkommt, prüft
+der Server, ob Sie ausreichende Berechtigungen haben, sie auszuführen,
+wobei es auf die Operation ankommt, die Sie ausführen wollen. Hier kommen
+die Berechtigungsfelder der Berechtigungstabellen ins Spiel. Diese
+Berechtigungen können aus jeder der @code{user}-, @code{db}-,
+@code{host}-, @code{tables_priv}- oder @code{columns_priv}-Tabellen
+stammen. Die Berechtigungstabellen werden mit @code{GRANT}- und
+@code{REVOKE}-Befehlen verändert. @xref{GRANT, , @code{GRANT}}. (Hilfreich
+sind die Ausführungen unter @ref{Privileges}, wo die Felder aufgelistet
+sind, die sich in jeder der Berechtigungstabellen finden.)
+
+Die @code{user}-Tabelle gewährt Berechtigungen, die Ihnen auf globaler
+Ebene zugeordnet sind und die unabhängig von der gerade aktuellen Datenbank
+zutreffen. Wenn beispielsweise die @code{user}-Tabelle Ihnen die
+@strong{delete}-Berechtigung gewährt, können Sie Zeilen aus jeder Datenbank
+auf dem Server-Host löschen! Mit anderen Worten: Berechtigungen in der
+@code{user}-Tabelle sind Superuser-Berechtigungen. Es ist klug,
+Berechtigungen in der @code{user}-Tabelle nur Superusern wie Server- oder
+Datenbankverwaltern zu gewähren. Bei anderen Benutzern sollten Sie
+Berechtigungen in der @code{user}-Tabelle auf @code{'N'} gesetzt lassen und
+Berechtigungen nur auf Datenbank-Ebene gewähren, indem Sie die @code{db}-
+und @code{host}-Tabellen benutzen.
+
+@cindex anonymer Benutzer
+@cindex Platzhalter, in @code{mysql.db}-Tabelle
+@cindex Platzhalter, in @code{mysql.host}-Tabelle
+Die @code{db}- und @code{host}-Tabellen gewähren Datenbank-spezifische
+Berechtigungen. Werte in den Geltungsbereichs-Feldern können wie folgt
+festgelegt werden:
+
+@itemize @bullet
+@item
+Die Platzhalterzeichen @samp{%} und @samp{_} können in den @code{Host}- und
+@code{Db}-Feldern jeder Tabelle benutzt werden.
+
+@item
+Ein @code{'%'}-@code{Host}-Wert in der @code{db}-Tabelle bedeutet ``jeder
+Host.'' Ein leerer @code{Host}-Wert in der @code{db}-Tabelle bedeutet
+``sieh in der @code{host}-Tabelle wegen weiterer Informationen nach''.
+
+@item
+Ein @code{'%'}- oder leerer @code{Host}-Wert in der @code{host}-Tabelle
+bedeutet ``jeder Host''.
+
+@item
+Ein @code{'%'}- oder leerer @code{Db}-Wert in einer der Tabellen bedeutet
+``jede Datenbank''.
+
+@item
+Ein leerer @code{User}-Wert in einer der Tabellen entspricht dem anonymen
+Benutzer.
+@end itemize
+
+@cindex Berechtigungstabellen, sortieren
+@cindex sortieren, Berechtigungstabellen
+@cindex @code{db}-Tabelle, sortieren
+@cindex @code{host}-Tabelle, sortieren
+Die @code{db}- und @code{host}-Tabellen werden eingelesen und sortiert,
+wenn der Server hoch fährt (zur gleichen Zeit, wenn er die
+@code{user}-Tabelle einliest). Die @code{db}-Tabelle wird nach den
+Geltungsbereichs-Feldern @code{Host}, @code{Db} und @code{User} sortiert.
+Die @code{host}-Tabelle wird nach den Geltungsbereichs-Feldern @code{Host}
+und @code{Db} sortiert. Bei der @code{user}-Tabelle werden die
+spezifischsten Werte zuerst und die unspezifischsten Werte zuletzt
+einsortiert, und wenn der Server nach übereinstimmenden Einträgen sucht,
+benutzt er die erste Übereinstimmung, die er findet.
+
+
+@cindex Platzhalter, in @code{mysql.tables_priv}-Tabelle
+@cindex Platzhalter, in @code{mysql.columns_priv}-Tabelle
+Die @code{tables_priv}- und @code{columns_priv}-Tabellen gewähren Tabellen-
+und Spalten-spezifische Berechtigungen. Werte in der
+Geltungsbereichs-Feldern können wie folgt festgelegt werden:
+
+@itemize @bullet
+@item
+Die Platzhalterzeichen @samp{%} und @samp{_} können im @code{Host}-Feld
+beider Tabellen benutzt werden.
+
+@item
+Ein @code{'%'}- oder leerer @code{Host}-Wert in jeder der beiden Tabellen bedeutet ``jeder Host.''
+
+@item
+Die @code{Db}-, @code{Table_name}- und @code{Column_name}-Felder dürfen in
+beiden Tabellen keine Platzhalter enthalten oder leer sein.
+@end itemize
+
+Die @code{tables_priv}- und @code{columns_priv}-Tabellen werden nach den
+@code{Host}-, @code{Db}- und @code{User}-Feldern sortiert. Das geschieht
+ähnlich wie das Sortieren der @code{db}-Tabelle, wenngleich das Sortieren
+einfacher ist, weil nur das @code{Host}-Feld Platzhalter enthalten darf.
+
+Der Prozess der Anfragenüberprüfung ist weiter unten beschrieben. (Wenn Sie
+mit dem Quelltext für die Zugangsüberprüfung vertraut sind, werden Sie
+feststellen, dass die Beschreibung hier leicht vom im Code verwendeten
+Algorithmus abweicht. Die Beschreibung stellt dar, was der Code tatsächlich
+tut; sie weicht nur deshalb ab, um die Erklärung zu erleichtern.)
+
+Bei Verwaltungsanfragen (@strong{shutdown}, @strong{reload} usw.) prüft der
+Server nur den @code{user}-Tabelleneintrag, weil das die einzige Tabelle
+ist, die Verwaltungsberechtigungen festlegt. Zugriff wird gewährt, wenn der
+Eintrag die verlangte Operation erlaubt, ansonsten wird er verweigert. Wenn
+Sie zum Beispiel @code{mysqladmin shutdown} ausführen wollen, aber Ihr
+@code{user}-Tabelleneintrag Ihnen nicht die @strong{shutdown}-Berechtigung
+gewährt, wird der Zugriff verweigert, ohne dass die @code{db}- oder
+@code{host}-Tabellen geprüft werden. (Sie enthalten keine
+@code{Shutdown_priv}-Spalte, daher gibt es keinen Grund, sie zur Prüfung
+heranzuziehen.)
+
+Bei Datenbank-bezogenen Anfragen (@strong{insert}, @strong{update} usw.)
+prüft der Server zuerst die globalen (superuser-) Berechtigungen, indem er
+im @code{user}-Tabelleneintrag nachsieht. Wenn der Eintrag die verlangte
+Operation erlaubt, wird der Zugriff gewährt. Wenn die globalen
+Berechtigungen in der @code{user}-Tabelle unzureichend sind, stellt der
+Server die Datenbank-spezifischen Berechtigungen des Benutzers fest, indem
+er die @code{db}- und @code{host}-Tabellen prüft:
+
+@enumerate
+@item
+Der Server sieht in der @code{db}-Tabelle nach einer Übereinstimmung in den
+@code{Host}-, @code{Db}- und @code{User}-Feldern nach. In den @code{Host}-
+und @code{User}-Feldern wird nach Übereinstimmung mit dem Hostnamen
+gesucht, von dem aus sich der Benutzer verbindet, und nach Übereinstimmung
+mit dem MySQL-Benutzernamen. Im @code{Db}-Feld wird nach Übereinstimmung
+mit der Datenbank gesucht, mit der sich der Benutzer verbinden will. Wenn
+es keinen Eintrag für @code{Host} und @code{User} gibt, wird der Zugriff
+verweigert.
+
+@item
+Wenn es keinen übereinstimmenden @code{db}-Tabelleneintrag gibt und das
+@code{Host}-Feld nicht leer ist, bestimmt dieser Eintrag die
+Datenbank-spezifischen Berechtigungen des Benutzers.
+
+@item
+Wenn das @code{Host}-Feld des übereinstimmenden @code{db}-Tabelleneintrags
+leer ist, bedeutet das, dass die @code{host}-Tabelle festlegt, welchen
+Hosts Zugriff auf die Datenbank erlaubt werden soll. In diesem Fall schlägt
+der Server weiter in der @code{host}-Tabelle nach, um eine Übereinstimmung
+in den @code{Host}- und @code{Db}-Feldern zu finden. Wenn kein
+@code{host}-Tabelleneintrag passt, wird der Zugriff verweigert. Bei einer
+Übereinstimmung werden die Datenbank-spezifischen Berechtigungen des
+Benutzers als Schnittmenge (@emph{nicht} Vereinigungsmenge!) der
+Berechtigungen in den @code{db}- und @code{host}-Tabelleneinträgen
+berechnet, was die Berechtigungen ergibt, die in beiden Einträgen
+@code{'Y'} sind. (Auf diese Weise können Sie allgemeine Berechtigungen in
+den @code{db}-Tabelleneinträgen vergeben und diese dann fallweise von Host
+zu Host beschränken, indem Sie die @code{host}-Tabelleneinträge benutzen.)
+@end enumerate
+
+Nachdem die Datenbank-spezifischen Berechtigungen festgestellt wurden, die
+durch die @code{db}- und @code{host}-Tabelleneinträge gewährt werden, fügt
+der Server diese zu den globalen Berechtigungen in der @code{user}-Tabelle
+hinzu. Wenn das Ergebnis die verlangte Operation erlaubt, wird der Zugriff
+gewährt. Ansonsten prüft der Server die Tabellen- und
+Spalten-Berechtigungen des Benutzers in den @code{tables_priv}- und
+@code{columns_priv}-Tabellen und fügt diese zu den Benutzerberechtigungen
+hinzu. Aus dem Ergebnis ergibt sich, ob der Zugriff erlaubt oder verweigert
+wird.
+
+Als Boole'scher Term ausgedrückt kann die vorstehende Beschreibung der
+Berechnung der Benutzerrechte wie folgt zusammengefasst werden:
+
+@example
+globale Berechtigungen
+ODER (Datenbankberechtigungen UND Hostberechtigungen)
+ODER Tabellenberechtigungen
+ODER Spaltenberechtigungen
+@end example
+
+Vielleicht ist es nicht offensichtlich, warum der Server bei anfänglich als
+unzureichend herausgefundenen globalen @code{user}-Eintragsberechtigungen
+für die verlangte Operation diese Berechtigungen anschließend zu den
+Datenbank-, Tabellen- und Spalten-spezifischen Berechtigungen hinzuzählt.
+Der Grund liegt darin, dass eine Anfrage möglicherweise mehr als eine Sorte
+von Berechtigungen erfordert. Wenn Sie beispielsweise ein @code{INSERT ...
+SELECT}-Statement ausführen, brauchen Sie eventuell sowohl die
+@strong{insert}- als auch die @strong{select}-Berechtigung. Ihre
+Berechtigungen mögen so sein, dass der @code{user}-Tabelleneintrag eine
+Berechtigung enthält und der @code{db}-Tabelleneintrag die andere. In
+diesem Fall haben Sie die notwendigen Berechtigungen, die Anfrage
+auszuführen, aber das Server kann das nicht aus nur einer der beiden
+Tabellen heraus erkennen, sondern muss dafür die Einträge beider Tabellen
+kombinieren.
+
+@cindex @code{host}-Tabelle
+@cindex Tabellen, @code{host}
+
+Die @code{host}-Tabelle kann benutzt werden, um eine Liste sicherer Server
+zu pflegen.
+
+Bei TcX enthält die @code{host}-Tabelle eine Liste aller Maschine des
+lokalen Netzwerks. Diesen werden alle Berechtigungen gewährt.
+
+Sie können die @code{host}-Tabelle auch dazu benutzen, die Host
+aufzuführen, die @emph{nicht} sicher sind. Nehmen Sie an, Sie haben eine
+Maschine @code{oeffentlich.ihre.domaene}, die an einem öffentlichen Ort
+ist, den Sie als nicht sicher erachten. Sie können allen Hosts in Ihrem
+Netzwerk Zugriff gewähren ausser dieser Maschine, indem Sie die
+@code{host}-Tabelleneinträge wie folgt benutzen:
+
+@example
++--------------------------+----+-
+| Host | Db | ...
++--------------------------+----+-
+| oeffentlich.ihre.domane | % | ... (alle Berechtigungen auf 'N' gesetzt)
+| %.ihre.domaene | % | ... (alle Berechtigungen auf 'Y' gesetzt)
++--------------------------+----+-
+@end example
+
+@cindex Berechtigungen, Änderungen
+@cindex Änderungen der Berechtigungen
+@cindex Tabellen, gewähren
+@cindex Berechtigungstabellen
+
+Natürlich sollten Sie Ihre Einträge in die Berechtigungstabellen immer
+testen (indem Sie zum Beispiel @code{mysqlaccess} benutzen), um
+sicherzustellen, dass Ihre Zugriffsberechtigungen tatsächlich so gesetzt
+sind, wie Sie denken.
+
+
+@node Access denied, , Request access, Privilege system
+@c German node Zugriff verweigert
+@subsection Gründe für @code{Access denied}-Fehler
+
+Wenn Sie beim Verbindungsversuch zu einem MySQL-Server @code{Access
+denied}-Fehler bekommen, gibt Ihnen die folgende Liste ein paar Hinweise,
+das Problem zu beheben:
+
+@itemize @bullet
+@item
+Haben Sie nach der Installation von MySQL das
+@code{mysql_install_db}-Skript laufen lassen, um die anfänglichen
+Berechtigungstabelleninhalte zu konfigurieren? Wenn nicht, tun Sie das!
+@xref{Default privileges}. Testen Sie die anfänglichen
+Berechtigungen, indem Sie folgenden Befehl ausführen:
+
+@example
+shell> mysql -u root test
+@end example
+
+Der Server sollte die Verbindung ohne Fehlermeldung zulassen. Stellen Sie
+auch sicher, dass Sie eine Datei @file{user.MYD} im
+MySQL-Datenbankverzeichnis haben. Üblicherweise ist das
+@file{PFAD/var/mysql/user.MYD}, wobei @code{PFAD} der Pfadname zum
+MySQL-Installationsverzeichnis ist.
+
+@item
+Nach einer gerade durchgeführten Installation sollten Sie sich mit dem
+Server verbinden und Ihre Benutzer und deren Zugriffsberechtigungen
+einrichten:
+
+@example
+shell> mysql -u root mysql
+@end example
+
+Der Server sollte die Verbindung zulassen, weil der
+MySQL-@code{root}-Benutzer anfänglich kein Passwort hat. Das ist ein
+Sicherheitsrisiko, daher sollten Sie das @code{root}-Passwort einrichten,
+während Sie Ihre anderen MySQL-Benutzer einrichten.
+
+Wenn Sie versuchen, sich als @code{root} zu verbinden, und folgenden Fehler
+erhalten:
+
+@example
+Access denied for user: '@@unknown' to database mysql
+@end example
+
+heißt das, dass Sie in der @code{user}-Tabelle keinen Eintrag
+@code{'root'} im @code{User}-Spaltenwert haben und dass @code{mysqld} den
+Hostnamen für Ihren Client nicht auflösen kann. In diesem Fall müssen Sie
+den Server mit der @code{--skip-grant-tables}-Option neu starten und Ihrer
+@file{/etc/hosts}- oder @file{\windows\hosts}-Datei einen Eintrag für Ihren
+Host hinzufügen.
+
+@item
+Wenn Sie einen Fehler wie folgt erhalten:
+
+@example
+shell> mysqladmin -u root -pxxxx ver
+Access denied for user: 'root@@localhost' (Using password: YES)
+@end example
+
+bedeutet das, dass Sie ein falsches Passwort benutzen. @xref{Passwords}.
+
+Wenn Sie das Root-Passwort vergessen haben, können Sie @code{mysqld} mit
+@code{--skip-grant-tables} neu starten, um das Passwort zu ändern. Diese
+Option wird weiter hinten im Handbuch ausführlicher beschrieben.
+
+Wenn Sie den obigen Fehler erhalten, obwohl Sie kein Passwort angegeben
+haben, bedeutet das, dass in einer der @code{my.ini}-Dateien ein falsches
+Passwort steht. @xref{Option files}. Sie können die Benutzung der
+Optionsdateien mit der @code{--no-defaults}-Option wie folgt verhindern:
+
+@example
+shell> mysqladmin --no-defaults -u root ver
+@end example
+
+@item
+@cindex @code{mysql_fix_privilege_tables}
+Wenn Sie eine bestehende MySQL-Installation von einer Version vor 3.22.11
+auf Version 3.22.11 oder später aktualisiert haben, haben Sie das
+@code{mysql_fix_privilege_tables}-Skript ausgeführt? Falls nicht, tun Sie
+das! Die Struktur der Berechtigungstabellen hat sich ab MySQL-Version
+3.22.11 geändert, als das @code{GRANT}-Statement mit Funktion erfüllt
+wurde.
+
+@item
+Falls es aussieht, als hätten sich Ihre Berechtigungen mitten in einer
+Sitzung geändert, kann es sein, dass ein Superuser sie geändert hat. Das
+Neuladen der Berechtigungstabellen betrifft neue
+Client-Verbindungen, aber auch bestehende Verbindungen, wie in
+@ref{Privilege changes} beschrieben.
+
+@item
+Wenn Sie es nicht schaffen, dass Ihr Passwort funktioniert, denken Sie
+daran, dass Sie die @code{PASSWORD()}-Funktion benutzen müssen, wenn Sie
+das Passwort mit den @code{INSERT}-, @code{UPDATE}- oder @code{SET
+PASSWORD}-Statements setzen. Die @code{PASSWORD()}-Funktion wird nicht
+benötigt, wenn Sie das Passwort mit dem @code{GRANT ... INDENTIFIED
+BY}-Statement oder dem @code{mysqladmin password}-Befehl setzen.
+@xref{Passwords}.
+
+@item
+@code{localhost} ist ein Synonym für Ihren lokalen Hostnamen und
+gleichzeitig der vorgabemäßige Host, mit dem sich Clients versuchen zu
+verbinden, wenn Sie nicht explizit einen Hostnamen angeben. Verbindungen zu
+@code{localhost} funktionieren jedoch nicht, wenn Sie auf einem System
+arbeiten, das MIT-pThreads benutzt (@code{localhost}-Verbindungen werden
+über Unix-Sockets hergestellt, die von MIT-pThreads nicht unterstützt
+werden). Um auf solchen Systemen Probleme zu vermeiden, sollten Sie die
+@code{--host}-Option zu benutzen, um den Serverhost explizit anzugeben. Das
+stellt eine TCP/IP-Verbindung zum @code{mysqld}-Server her. In diesem Fall
+muss Ihr echter Hostname in den @code{user}-Tabelleneinträgen auf dem
+Server-Host stehen. (Das gilt sogar dann, wenn Sie ein Client-Programm auf
+demselben Host fahren, wo der Server läuft.)
+
+@item
+Wenn Sie beim Versuch, sich mit @code{mysql -u user_name db_name} mit einer
+Datenbank zu verbinden, einen @code{Access denied}-Fehler erhalten, gibt es
+eventuell ein Problem mit der @code{user}-Tabelle. Das können Sie
+überprüfen, indem Sie @code{mysql -u root mysql} und folgendes
+SQL-Statement absetzen:
+
+@example
+mysql> SELECT * FROM user;
+@end example
+
+Das Ergebnis sollte einen Eintrag enthalten, in dem die @code{Host}- und
+@code{User}-Spalten mit dem Hostnamen Ihres Computers und Ihrem
+MySQL-Benutzernamen übereinstimmen.
+
+@item
+Die @code{Access denied}-Fehlermeldung sagt Ihnen, als wer Sie sich
+versuchen einzuloggen, den Host, von dem aus Sie versuchen, sich zu
+verbinden, und ob Sie ein Passwort benutzen oder nicht. Normalerweise
+sollten Sie in der @code{user}-Tabelle einen Eintrag haben, der exakt mit
+Ihrem Hostnamen und Ihrem Benutzernamen übereinstimmt, die in der
+Fehlermeldung ausgegeben wurden. Wenn Sie zum Beispiel eine Fehlermeldung
+erhalten, die @code{Using password: NO} enthält, bedeutet das, dass Sie
+versuchen sich einzuloggen, ohne ein Passwort anzugeben.
+
+@item
+Wenn Sie folgenden Fehler erhalten, wenn Sie sich von einem anderen Host
+als dem, auf dem der MySQL-Server läuft, zu verbinden, gibt es keine Zeile
+in der @code{user}-Tabelle, die mit Ihrem Host übereinstimmt:
+
+@example
+Host ... is not allowed to connect to this MySQL server
+@end example
+
+Das können Sie mit dem Kommandozeilentool @code{mysql} beheben (auf dem
+Serverhost!) und eine Zeile zur @code{user}-, @code{db}- oder
+@code{host}-Tabelle hinzufügen, die eine Benutzername-/Hostname-Kombination
+enthält, von wo aus Sie sich verbinden wollen; danach führen Sie
+@code{mysqladmin flush-privileges} aus. Wenn Sie nicht MySQL-Version 3.22
+laufen lassen und die IP-Nummer oder den Hostnamen der Maschine nicht
+kennen, von der aus Sie sich verbinden, sollten Sie einen Eintrag mit
+@code{'%'} als @code{Host}-Spaltenwert in die @code{user}-Tabelle einfügen
+und @code{mysqld} mit der @code{--log}-Option auf der Servermaschine neu
+starten. Nach dem Verbinden von der Client-Maschine aus zeigt die
+Information im MySQL-Log an, wie Sie sich wirklich verbunden haben.
+(Ersetzen Sie danach @code{'%'} im @code{user}-Tabelleneintrag durch den
+tatsächlichen Hostnamen, der im Log steht. Ansonsten erhalten Sie ein
+System, das unsicher ist.)
+
+Ein weiterer Grund für diesen Fehler unter Linux kann sein, dass Sie eine
+Binärversion von MySQL benutzen, die mit einer anderen glibc-Version
+kompiliert wurde als die, die Sie benutzen. In diesem Fall sollten Sie
+entweder die glibc Ihres Betriebssystems aktualisieren oder die
+Quellversion von MySQL herunter laden und sie selbst kompilieren. Ein
+Quell-RPM läßt sich normalerweise sehr einfach kompilieren und
+installieren, daher stellt dies kein großes Problem dar.
+
+@item
+Wenn Sie eine Fehlermeldung erhalten, in der der Hostname nicht angezeigt
+wird oder eine IP-Nummer ist, obwohl Sie sich mit einem Hostnamen versuchen
+zu verbinden:
+
+@example
+shell> mysqladmin -u root -pxxxx -h ein-hostname ver
+Access denied für user: 'root@' (Using password: YES)
+@end example
+
+bedeutet das, dass MySQL einen Fehler beim Auflösen der IP zu einem
+Hostnamen erhielt. In diesem Fall können Sie @code{mysqladmin flush-hosts}
+ausführen, um den internen DNS-Cache zu flushen. @xref{DNS}.
+
+Einige dauerhafte Lösungen sind:
+
+@itemize @minus
+@item
+Versuchen Sie herauszufinden, was mit Ihrem DNS-Server nicht funktioniert,
+und beheben Sie das Problem.
+
+@item
+Geben Sie in den MySQL-Berechtigungstabellen IP-Nummern statt Hostnamen an.
+
+@item
+Starten Sie @code{mysqld} mit @code{--skip-name-resolve}.
+
+@item
+Starten Sie @code{mysqld} mit @code{--skip-host-cache}.
+
+@item
+Verbinden Sie sich zu @code{localhost} wenn Sie Server und Client auf
+derselben Maschine laufen lassen.
+
+@item
+Tragen Sie die Client-Maschinennamen in @code{/etc/hosts} ein.
+@end itemize
+
+@item
+Wenn @code{mysql -u root test} funktioniert, aber @code{mysql -h
+your_hostname -u root test} zu @code{Access denied} führt, haben Sie
+eventuell nicht den korrekten Namen Ihres Hosts in der @code{user}-Tabelle.
+Ein häufiges Problem hierbei ist, dass der @code{Host}-Wert im
+@code{user}-Tabelleneintrag einen unqualifizierten Hostnamen festlegt, die
+Namensauflösungsroutinen Ihres Systems aber einen voll qualifizierten
+Domänennamen zurückgeben (oder umgekehrt). Wenn Sie zum Beispiel einen
+Eintrag mit dem Host @code{'tcx'} in der @code{user}-Tabelle haben, Ihr DNS
+MySQL aber mitteilt, dass Ihr Hostname @code{'tcx.subnet.se'} ist,
+funktioniert der Eintrag nicht. Fügen Sie der @code{user}-Tabelle einen
+Eintrag hinzu, der die IP-Nummer Ihres Hosts als @code{Host}-Spaltenwert
+enthält. (Alternativ könnten Sie der @code{user}-Tabelle einen Eintrag mit
+einem @code{Host}-Wert hinzufügen, der einen Platzhalter enthält, zum
+Beispiel @code{'tcx.%'}. Allerdings ist die Benutzung von
+Hostnamensendungen mit @samp{%} @emph{unsicher} und wird daher @emph{nicht}
+empfohlen!)
+
+@item
+Wenn @code{mysql -u benutzername test} funktioniert, aber @code{mysql -u
+benutzername andere_datenbank} nicht, haben Sie wahrscheinlich keinen
+Eintrag für @code{andere_datenbank} in der @code{db}-Tabelle.
+
+@item
+Wenn @code{mysql -u benutzername datenbankname} funktioniert, wenn es auf
+der Servermaschine ausgeführt wird, aber @code{mysql -u hostname -u
+benutzername datenbankname} nicht, wenn es auf einer anderen Clientmaschine
+ausgeführt wird, ist die Clientmaschine wahrscheinlich nicht in der
+@code{user}-Tabelle oder der @code{db}-Tabelle aufgeführt.
+
+@item
+Wenn Sie gar nicht herausfinden können, warum Sie @code{Access denied}
+erhalten, entfernen Sie aus der @code{user}-Tabelle alle Einträge, die
+@code{Host}-Werte haben, die Platzhalter enthalten (Einträge, die @samp{%}
+oder @samp{_} enthalten). Ein sehr häufiger Fehler besteht darin, einen
+neuen Eintrag mit @code{Host}=@code{'%'} und
+@code{User}=@code{'irgendein_benutzer'} in der Annahme hinzuzufügen, dass
+einem das erlaubt, @code{localhost} anzugeben, um sich von derselben
+Maschine aus zu verbinden. Der Grund, warum das nicht funktioniert, ist,
+dass die vorgabemäßigen Berechtigungen einen Eintrag mit
+@code{Host}=@code{'localhost'} und @code{User}=@code{''} enthalten. Weil
+dieser Eintrag einen @code{Host}-Wert @code{'localhost'} hat, der
+spezifischer ist als @code{'%'}, wird er vorrangig vor dem neuen Eintrag
+benutzt, wenn man sich von @code{localhost} verbindet! Das korrekte
+Vorgehen ist, einen zweiten Eintrag mit @code{Host}=@code{'localhost'} und
+@code{User}=@code{'irgendein_benutzer'} hinzuzufügen, oder den Eintrag mit
+@code{Host}=@code{'localhost'} und @code{User}=@code{''} zu entfernen.
+
+@item
+Wenn Sie den folgenden Fehler erhalten, gibt es eventuell Probleme mit der
+@code{db}- oder der @code{host}-Tabelle:
+
+@example
+Access to database denied
+@end example
+
+Wenn der aus der @code{db}-Tabelle ausgewählte Eintrag einen leeren Wert in
+der @code{Host}-Spalte hat, stellen Sie sicher, dass es einen oder mehrere
+korrespondierende Einträge in der @code{host}-Tabelle gibt, die festlegen,
+auf welche Hosts der @code{db}-Tabelleneintrag zutrifft.
+
+Wenn Sie bei der Benutzung der SQL-Befehle @code{SELECT ... INTO OUTFILE}
+oder @code{LOAD DATA INFILE} einen Fehler erhalten, enthält Ihr Eintrag in
+der @code{user}-Tabelle wahrscheinlich keine angeschaltete
+@strong{file}-Berechtigung.
+
+@item
+@cindex Konfigurationsdateien
+@cindex Umgebungsvariablen
+@tindex .my.cnf-Datei
+Denken Sie daran, dass Client-Programme Verbindungsparameter benutzen, die
+in Konfigurationsdateien oder Umgebungsvariablen festgelegt sind.
+@xref{Environment variables}. Wenn ein Client anscheinend falsche
+vorgabemäßige Verbindungsparameter sendet, wenn Sie diese nicht auf der
+Kommandozeile angeben, überprüfen Sie Ihre Umgebung und die
+@file{.my.cnf}-Datei in Ihrem Heimatverzeichnis. Überprüfen Sie
+gegebenenfalls auch systemweite MySQL-Konfigurationsdateien, obwohl es sehr
+viel unwahrscheinlicher ist, dass Client-Verbindungsparameter in diesen
+festgelegt werden. @xref{Option files}. Wenn Sie beim Laufenlassen eines
+Clients ohne irgend welche Optionen @code{Access denied} erhalten, stellen
+Sie sicher, dass Sie kein altes Passwort in irgendeiner Optionsdatei
+angegeben haben! @xref{Option files}.
+
+@item
+Wenn Sie in den Berechtigungstabellen direkte Änderungen vornehmen (indem
+Sie ein @code{INSERT}- oder @code{UPDATE}-Statement benutzen) und Ihre
+Änderungen anscheinend ignoriert werden, denken Sie daran, dass sie ein
+@code{FLUSH PRIVILEGES}-Statement absetzen müssen oder einen
+@code{mysqladmin flush-privileges}-Befehl ausführen, um den Server zu
+veranlassen, die Berechtigungstabellen neu einzulesen. Ansonsten haben Ihre
+Änderungen keine Auswirkung, bis der Server das nächste Mal gestartet wird.
+Denken Sie auch daran, wenn Sie ein @code{root}-Passwort mit einem
+@code{UPDATE}-Befehl festgelegt haben, dass Sie dieses solange nicht
+angeben müssen, bis Sie die Berechtigungen flushen, weil der Server vorher
+nicht weiß, dass Sie Ihr Passwort geändert haben!
+
+@item
+Wenn Sie Zugriffsprobleme mit einem Perl-, PHP-, Python- oder ODBC-Programm
+haben, versuchen Sie, sich mit @code{mysql -u benutzername datenbankname}
+oder @code{mysql -u benutzername -pihr_passwort datenbankname} zu
+verbinden. Wenn es Ihnen gelingt, sich mittels des @code{mysql}-Clients zu
+verbinden, gibt es ein Problem mit Ihrem Programm und nicht mit den
+Zugriffsberechtigungen. (Beachten Sie, dass zwischen @code{-p} und dem
+Passwort kein Leerzeichen steht; alternativ können Sie auch die
+@code{--password=ihr_passwort}-Syntax benutzen, um Ihr Passwort anzugeben.
+Wenn Sie die @code{-p}-Option allein benutzen, wird MySQL eine
+Eingabeaufforderung für das Passwort anzeigen.)
+
+@item
+Zum Testen starten Sie den @code{mysqld}-Daemon mit der
+@code{--skip-grant-tables}-Option. Anschließend können Sie die
+MySQL-Berechtigungstabellen ändern und das @code{mysqlaccess}-Skript
+benutzen, um zu sehen, ob Ihre Änderungen den gewünschten Effekt haben oder
+nicht. Wenn Sie mit Ihren Änderungen zufrieden sind, führen Sie
+@code{mysqladmin flush-privileges} aus, um @code{mysqld} mitzuteilen, die
+neuen Berechtigungstabellen zu benutzen. @strong{Beachten Sie:} Das
+Neuladen der Berechtigungstabellen überschreibt die
+@code{--skip-grant-tables}-Option. Das erlaubt Ihnen, den Server zu
+veranlassen, die Berechtigungstabellen wieder zu benutzen, ohne ihn
+herunter und dann wieder herauf fahren zu müssen.
+
+@item
+Wenn alles andere fehlschlägt, starten Sie den @code{mysqld}-Daemon mit
+einer Debugging-Option (zum Beispiel @code{--debug=d,general,query}). Das
+gibt Host- und Benutzerinformationen über Verbindungsversuche aus sowie
+Informationen über jeden abgesetzten Befehl. @xref{Making trace files}.
+
+@item
+Wenn Sie irgend welche anderen Probleme mit den MySQL-Berechtigungstabellen
+haben und meinen, das Problem der Mailing-Liste mitteilen zu müssen,
+stellen Sie immer einen Auszug Ihrer MySQL-Berechtigungstabellen zur
+Verfügung. Sie können einen Auszug der Tabellen mit dem @code{mysqldump
+mysql}-Befehl erzeugen. Berichten Sie Ihr Problem - wie immer - unter
+Benutzung des @code{mysqlbug}-Skripts. @xref{Bug reports}. In einigen
+Fällen müssen Sie vielleicht @code{mysqld} mit @code{--skip-grant-tables}
+neu starten, um @code{mysqldump} benutzen zu können.
+@end itemize
+
+
+@node User Account Management, Disaster Prevention, Privilege system, MySQL Database Administration
+@c German node Benutzerkontenverwaltung
+@section MySQL-Benutzerkonten-Verwaltung
+
+
+
+@menu
+* GRANT::
+* User names::
+* Privilege changes::
+* Default privileges::
+* Adding users::
+* Passwords::
+* Password security::
+@end menu
+
+@node GRANT, User names, User Account Management, User Account Management
+@c German node GRANT
+@subsection @code{GRANT}- und @code{REVOKE}-Syntax
+
+@findex GRANT
+@findex REVOKE
+
+@cindex Berechtigungen, gewähren
+@cindex Berechtigungen, entziehen
+@cindex global Berechtigungen
+@cindex entziehen, Berechtigungen
+@cindex gewähren, Berechtigungen
+
+@example
+GRANT berechtigung_art [(spalten_liste)] [, berechtigung_art [(spalten_liste)] ...]
+ ON @{tabelle | * | *.* | datenbank.*@}
+ TO benutzername [IDENTIFIED BY 'passwort']
+ [, benutzername [IDENTIFIED BY 'passwort'] ...]
+ [REQUIRE
+ [@{SSL| X509@}]
+ [CIPHER cipher [AND]]
+ [ISSUER issuer [AND]]
+ [SUBJECT subject]]
+ [WITH GRANT OPTION]
+
+REVOKE berechtigung_art [(spalten_liste)] [, berechtigung_art [(spalten_liste)] ...]
+ ON @{tabelle | * | *.* | datenbank.*@}
+ FROM benutzername [, benutzername ...]
+@end example
+
+@code{GRANT} ist implementiert ab MySQL Version 3.22.11. Bei früheren
+MySQL-Versionen bewirkt das @code{GRANT}-Statement nichts.
+
+Die @code{GRANT}- und @code{REVOKE}-Befehle erlauben Systemverwaltern,
+Benutzer anzulegen und MySQL-Benutzern Rechte auf vier Berechtigungsebenen
+zu gewähren und zu entziehen:
+
+@table @strong
+@item Globale Ebene
+Globale Berechtigungen betreffen alle Datenbanken auf einem gegebenen
+Server. Diese Berechtigungen werden in der @code{mysql.user}-Tabelle
+gespeichert.
+
+@item Datenbank-Ebene
+Datenbank-Berechtigungen betreffen alle Tabellen in einer gegebenen
+Datenbank. Diese Berechtigungen werden in den @code{mysql.db}- und
+@code{mysql.host}-Tabellen gespeichert.
+
+@item Tabellen-Ebene
+Tabellen-Berechtigungen betreffen alle Spalten in einer gegebenen Tabelle.
+Diese Berechtigungen werden in der @code{mysql.tables_priv}-Tabelle
+gespeichert.
+
+@item Spalten-Ebene
+Spalten-Berechtigungen betreffen einzelne Spalten in einer gegebenen
+Tabelle. Diese Berechtigungen werden in der
+@code{mysql.columns_priv}-Tabelle gespeichert.
+@end table
+
+Wenn Sie ein @code{GRANT} für einen Benutzer angeben, den es nicht gibt,
+wird dieser Benutzer erzeugt. Beispiele, wie @code{GRANT} funktioniert,
+finden Sie unter @ref{Adding users}.
+
+Bei @code{GRANT} und @code{REVOKE}-Statements kann @code{berechtigung_art}
+wie folgt angegeben werden:
+
+@example
+ALL PRIVILEGES FILE RELOAD
+ALTER INDEX SELECT
+CREATE INSERT SHUTDOWN
+DELETE PROCESS UPDATE
+DROP REFERENCES USAGE
+@end example
+
+@code{ALL} ist ein Synonym für @code{ALL PRIVILEGES}. @code{REFERENCES} ist
+noch nicht implementiert. @code{USAGE} ist momentan ein Synonym für ``keine
+Berechtigungen''. Es kann benutzt werden, um einen Benutzer zu erzeugen,
+der keine Berechtigungen hat.
+
+Um einem Benutzer die @strong{grant}-Berechtigung zu entziehen, benutzen
+Sie einen @code{berechtigung_art}-Wert @code{GRANT OPTION}:
+
+@example
+REVOKE GRANT OPTION ON ... FROM ...;
+@end example
+
+Die einzigen @code{berechtigung_art}-Werte, die Sie für eine Tabelle
+festlegen können, sind @code{SELECT}, @code{INSERT}, @code{UPDATE},
+@code{DELETE}, @code{CREATE}, @code{DROP}, @code{GRANT}, @code{INDEX} und
+@code{ALTER}.
+
+Die einzigen @code{berechtigung_art}-Werte, die Sie für eine Spalte
+festlegen können (im Falle, dass Sie eine @code{spalten_liste}-Klausel
+benutzen), sind @code{SELECT}, @code{INSERT} und @code{UPDATE}.
+
+Sie können globale Berechtigungen setzen, indem Sie die @code{ON
+*.*}-Syntax benutzen. Datenbank-Berechtigungen setzen Sie mit der @code{ON
+datenbank.*}-Syntax. Wenn Sie @code{ON *} setzen und eine aktuelle
+Datenbank ausgewählt haben, setzen Sie die Berechtigungen für diese
+Datenbank. (@strong{ACHTUNG:} Wenn Sie @code{ON *} festlegen und
+@emph{keine} aktuelle Datenbank ausgewählt haben, betrifft das die globalen
+Berechtigungen!)
+
+Um die Rechtegewährung für Benutzer von uneindeutigen Hosts aus zu
+ermöglichen, unterstützt MySQL den @code{benutzername}-Wert in der Form
+@code{benutzer@@host}. Wenn Sie eine @code{user}-Zeichenkette festlegen
+wollen, die Sonderzeichen enthält (wie @samp{-}), oder eine
+@code{host}-Zeichenkette, die Sonderzeichen oder Platzhalterzeichen enthält
+(wie @samp{%}), können Sie Benutzernamen oder Hostnamen in
+Anführungszeichen setzen (beispielsweise @code{'test-benutzer'@@'test-hostname'}).
+
+Sie können im Hostnamen Platzhalter angeben. @code{benutzer@@"%.loc.gov"}
+zum Beispiel trifft auf @code{benutzer} für jeden Host in der Domäne
+@code{loc.gov} zu. @code{benutzer@@"144.155.166.%"} trifft auf
+@code{benutzer} für jeden Host im @code{144.155.166}-Class-C-Subnetz zu.
+
+Die einfache Form @code{benutzer} ist ein Synonym für
+@code{benutzer@@"%"}. @strong{ACHTUNG:} Wenn Sie anonymen Benutzern
+erlauben, sich mit dem MySQL-Server zu verbinden (was vorgabemäßig der
+Fall ist), sollten Sie auch alle lokalen Benutzer als
+@code{benutzer@@localhost} hinzufügen, weil ansonsten der Eintrag für den
+anonymen Benutzer für den lokalen Host in der @code{mysql.user}-Tabelle
+benutzt wird, wenn der Benutzer versucht, sich von der lokalen Maschine in
+den MySQL-Server einzuloggen! Anonyme Benutzer werden definiert, indem
+Einträge mit @code{User=''} in die @code{mysql.user}-Tabelle eingefügt
+werden. Das können Sie mit folgender Anfrage überprüfen:
+
+@example
+mysql> SELECT Host,User FROM mysql.user WHERE User='';
+@end example
+
+Momentan unterstützt @code{GRANT} nur Host-, Datenbank-, Tabellen- und
+Spaltennamen mit maximal 60 Zeichen. Ein Benutzername kann bis zu 16
+Zeichen lang sein.
+
+Die Berechtigungen für eine Tabelle oder Spalte werden durch ein logisches
+ODER der Berechtigungen auf jeder der vier Berechtigungsebenen zusammen
+gesetzt. Wenn die @code{mysql.user}-Tabelle beispielsweise festlegt, dass
+ein Benutzer eine globalen @strong{select}-Berechtigung hat, kann diese
+nicht durch Einträge auf Datenbank-, Tabellen- oder Spaltenebene widerrufen
+werden.
+
+Die Berechtigungen für eine Spalte können wie folgt berechnet werden:
+
+@example
+Globale Berechtigungen
+ODER (Datenbank-Berechtigungen UND Host-Berechtigungen)
+ODER Tabellen-Berechtigungen
+ODER Spalten-Berechtigungen
+@end example
+
+In den meisten Fällen können Sie einem Benutzer Rechte auf lediglich einer
+der Berechtigungsebenen gewähren, wodurch das Leben nicht so kompliziert
+ist wie oben dargestellt. Die Details der Prozedur zur Überprüfung der
+Berechtigungen sind in @ref{Privilege system} dargestellt.
+
+Wenn Sie Berechtigungen für eine Benutzer-/Hostname-Kombination gewähren,
+die in der @code{mysql.user}-Tabelle nicht existiert, wird ein Eintrag
+hinzugefügt und verbleibt dort, bis der mit einem @code{DELETE}-Befehl
+gelöscht wird. Mit anderen Worten: @code{GRANT} kann eventuell
+@code{user}-Tabelleneinträge erzeugen, aber @code{REVOKE} entfernt diese
+nicht, sondern Sie müssen das explizit mit @code{DELETE} machen.
+
+@cindex Passwörter, setzen
+Ab MySQL-Version 3.22.12 wird, wenn ein neuer Benutzer erzeugt wird oder
+wenn Sie globale Grant-Berechtigungen haben, das Passwort des Benutzers
+durch die @code{IDENTIFIED BY}-Klausel festgelegt, wenn eine angegeben
+wird. Wenn der Benutzer bereits ein Passwort hat, wird es durch das neue
+ersetzt.
+
+@strong{ACHTUNG:} Wenn Sie einen neuen Benutzer anlegen, aber keine
+@code{IDENTIFIED BY}-Klausel angeben, hat der neue Benutzer kein Passwort.
+Das ist unsicher.
+
+Passwörter können auch mit dem @code{SET PASSWORD}-Befehl gesetzt werden.
+@xref{SET OPTION, , @code{SET OPTION}}.
+
+Wenn Sie Berechtigungen für eine Datenbank gewähren, wird ein Eintrag in
+der @code{mysql.db}-Tabellen erzeugt, falls notwendig. Wenn alle
+Berechtigungen für die Datenbank mit @code{REVOKE} widerrufen wurden, wird
+dieser Eintrag gelöscht.
+
+Wenn ein Benutzer überhaupt keine Berechtigungen auf eine Tabelle hat, wird
+die Tabelle nicht angezeigt, wenn der Benutzer nach einer Liste von
+Tabellen anfragt (zum Beispiel mit einem @code{SHOW TABLES}-Statement).
+
+Die @code{mit GRANT OPTION}-Klausel gibt dem Benutzer die Möglichkeit,
+anderen Benutzern jegliche der Berechtigungen zu vergeben, die der Benutzer
+auf der angegebenen Berechtigungsebene hat. Sie sollten vorsichtig damit
+sein, wem Sie die @strong{grant}-Berechtigung geben, denn zwei Benutzer mit
+unterschiedlichen Berechtigungen können in der Lage sein, Ihre
+Berechtigungen zu addieren!
+
+Sie können einem Benutzer keine Berechtigung gewähren, die Sie selbst nicht
+haben; die @strong{grant}-Berechtigung erlaubt Ihnen nur, die
+Berechtigungen zu vergeben, die Sie selbst besitzen.
+
+Wenn Sie einem Benutzer die @strong{grant}-Berechtigung auf einer
+bestimmten Berechtigungsebene geben, denken Sie daran, dass der Benutzer
+jegliche Berechtigungen, die der Benutzer schon besitzt (oder die ihm in
+Zukunft gewährt werden!), auf dieser Ebene auch an andere Benutzer gewährt
+werden können. Nehmen Sie an, Sie gewähren einem Benutzer die
+@strong{insert}-Berechtigung auf eine Datenbank. Wenn Sie danach die
+@strong{select}-Berechtigung auf die Datenbank mit @code{WITH GRANT OPTION}
+gewähren, kann der Benutzer nicht nur die @strong{select}-Berechtigung
+weiter geben, sondern auch @strong{insert}. Wenn Sie dem Benutzer danach
+die @strong{update}-Berechtigung auf die Datenbank gewähren, kann der
+Benutzer insgesamt @strong{insert}, @strong{select} und @strong{update}
+weiter geben.
+
+Sie sollten einem normalen Benutzer keine @strong{alter}-Berechtigung
+gewähren. Wenn Sie das tun, kann der Benutzer versuchen, das
+Berechtigungssystem zu unterlaufen, indem er Tabellen umbenennt!
+
+Beachten Sie: Wenn Sie Tabellen- oder Spalten-Berechtigungen auch nur für
+einen Benutzer gewähren, untersucht der Server Tabellen- und
+Spalten-Berechtigungen für alle Benutzer. Dadurch wird MySQL etwas
+langsamer.
+
+Wenn @code{mysqld} startet, werden alle Berechtigungen in den Speicher
+eingelesen. Datenbank-, Tabellen- und Spalten-Berechtigungen werden sofort
+wirksam. Berechtigungen auf Benutzerebene werden wirksam, wenn sich der
+Benutzer das nächste Mal verbindet. Änderungen in den
+Berechtigungstabellen, die Sie mit @code{GRANT} oder @code{REVOKE}
+durchführen, werden vom Server sofort bemerkt. Wenn Sie
+Berechtigungstabellen manuell ändern (mit @code{INSERT}, @code{UPDATE}
+usw.), müssen Sie ein @code{FLUSH PRIVILEGES}-Statement ausführen oder
+@code{mysqladmin flush-privileges} laufen lassen, um den Server zu
+veranlassen, die Berechtigungstabellen neu zu laden.
+@xref{Privilege changes}.
+
+@cindex ANSI SQL, Unterschiede zu
+Die größten Unterschiede zwischen ANSI SQL und MySQL-Versionen von
+@code{GRANT} sind:
+
+@itemize @bullet
+@item
+In MySQL werden Berechtigungen für eine Benutzername-/Hostname-Kombination
+vergeben und nicht nur für einen Benutzernamen.
+
+@item
+ANSI SQL hat keine globalen oder Datenbankebene-Berechtigungen und
+unterstützt nicht alle Berechtigungsarten, die MySQL unterstützt. MySQL
+unterstützt nicht die ANSI-SQL-@code{TRIGGER}-, @code{EXECUTE}- oder
+@code{UNDER}-Berechtigungen.
+
+@item
+ANSI-SQL-Berechtigungen werden auf hierarchische Art strukturiert. Wenn Sie
+einen Benutzer entfernen, werden alle Berechtigungen, die dieser Benutzer
+gewährt hat, widerrufen. In MySQL werden die gewährten Berechtigungen nicht
+automatisch widerrufen, sondern Sie müssen das selbst tun.
+
+@item
+Wenn Sie in MySQL das @code{INSERT}-Recht nur für Teile der Spalten einer
+Tabelle haben, können Sie dennoch @code{INSERT}-Statements auf der Tabelle
+ausführen. Die Spalten, für die Sie keine @code{INSERT}-Berechtigung haben,
+werden auf ihre Vorgabewerte gesetzt. ANSI SQL erfordert, dass Sie die
+@code{INSERT}-Berechtigung auf alle Spalten haben.
+
+@item
+Wenn Sie eine Tabelle in ANSI SQL löschen, werden alle Berechtigungen für
+die Tabelle widerrufen. Wenn Sie eine Berechtigung in ANSI SQL widerrufen,
+werden alle Berechtigungen, die auf dieser Berechtigung basierend gewährt
+wurden, widerrufen. In MySQL können Berechtigungen nur explizit mit
+@code{REVOKE}-Befehlen oder durch die Manipulation der
+MySQL-Berechtigungstabellen widerrufen werden.
+@end itemize
+
+-----------
+@cindex SSL- und X509-Grundlagen
+MySQL unterstützt SSL-verschlüsselte Verbindungen. Um zu verstehen, wie
+MySQL SSL benutzt, müssen wir einige Grundlagen von SSL und X509 erläutern.
+Leute, die damit schon vertraut sind, können dieses Kapitel überspringen.
+
+Vorgabemäßig benutzt MySQL unverschlüsselte Verbindungen zwischen Client
+und Server. Das heißt, dass jeder auf dem Weg dazwischen lauschen und Ihre
+Daten, die übertragen werden, mitlesen kann. Darüber hinaus könnten einige
+Leute auch den Inhalt von Daten ändern, die zwischen Client und Server
+ausgetauscht werden. Möglicherweise haben Sie auch wirklich geheime Daten
+über öffentliche Netzwerke zu übertragen, und eine Öffentlichkeit solcher
+Art ist unakzeptabel.
+
+SSL ist ein Protokoll, das unterschiedliche Verschlüsselungsalgorithmen
+benutzt, um sicherzustellen, dass Daten aus einem öffentlichen Netzwerk
+vertraut werden kann. Es besitzt Mechanismen, um Veränderungen, Verlust
+oder wiederholtes Abspielen (Replay) von Daten zu entdecken. SSL enthält
+auch Algorithmen, um die Identität zu erkennen und zu überprüfen, indem der
+X509-Standard benutzt wird.
+
+@cindex Was ist Verschlüsselung
+Mittels Verschlüsselung werden jegliche Arten von Daten unlesbar gemacht.
+Darüber hinaus werden in der heutigen Praxis Verschlüsselungsalgorithmen
+viele weitere Elemente hinzugefügt. Sie sollten vielen Arten bekannter
+Angriffe widerstehen, wie dem Herumspielen mit der Reihenfolge
+verschlüsselter Nachrichten oder dem doppelten Abspielen (Replay) von
+Daten.
+
+@cindex Was ist ein X509-Zertifikat?
+X509 ist der Standard, der es ermöglicht, jemanden im Internet zu
+identifizieren. Er wird meistens beim E-Commerce über das Internet benutzt.
+Kurz gesagt sollte es ein Unternehmen namens "Zertifizierungsautorität"
+geben, die jedem elektronische Zertifikate zuordnet, der diese braucht.
+Zertifikate beruhen auf asymmetrischen Verschlüsselungsalgorithmen, die
+zwei Verschlüsselungsschlüssel haben - öffentlichen und geheimen.
+Zertifikatsbesitzer können ihre Identität jeder anderen Seite beweisen.
+Zertifikate beinhalten den öffentlichen Schlüssel des Besitzers. Alle
+Daten, die damit verschlüsselt werden, können nur vom Besitzer des geheimen
+Schlüssels entschlüsselt werden.
+
+@cindex Mögliche Fragen:
+Frage: Warum benutzt MySQL nicht standardmäßig verschlüsselte Verbindungen?
+Antwort: Weil es MySQL langsamer macht. Jede zusätzliche Funktionalität
+erfordert, dass ein Computer zusätzliche Arbeit verrichtet, und das
+Verschlüsseln von Daten ist eine CPU-intensive Operation, die leicht die
+Zeit und Leistung übertreffen kann, die MySQL selbst verbraucht und
+benötigt. MySQL ist vorgabemäßig auf Geschwindigkeit optimiert.
+Frage: Ich brauche mehr Informationen über SSL / X509 / Verschlüsselung
+usw.
+Antwort: Benutzen Sie Ihre bevorzugte Internet-Suchmaschine und suchen Sie
+nach den Schlüsselwörtern, die Sie interessieren.
+
+
+@cindex SSL-bezogene Optionen
+
+MySQL kann x509-Zertifikat-Attribute prüfen, zusätzlich zum meist benutzten
+Benutzername-/Passwort-Schema. Alle gewöhnlich Optionen werden immer noch
+benötigt (Benutzername, Passwörter, IP-Adressmaske,
+Datenbank-/Tabellenname).
+
+Es gibt verschiedene Möglichkeiten, Verbindungen zu begrenzen:
+
+@itemize @bullet
+@item
+Ohne jegliche SSL-/X509-Optionen werden alle Arten verschlüsselter und
+unverschlüsselter Verbindungen zugelassen, wenn Benutzername und Passwort
+gültig sind.
+
+@item
+Die @code{REQUIRE SSL}-Option erzwingt SSL-verschlüsselte Verbindungen.
+Beachten Sie, dass dieses Erfordernis übergangen werden kann, wenn es
+irgend welche weiteren ACL-Datensätze gibt, die Verbindungen ohne SSL
+zulassen.
+
+Beispiel:
+@example
+GRANT ALL PRIVILEGES ON test.* TO root@@localhost IDENTIFIED BY "goodsecret" REQUIRE SSL
+@end example
+
+
+@item
+* @code{REQUIRE X509} Wenn ein X509-Zertifikat erforderlich ist, bedeutet
+das, dass der Client ein gültiges Zertifikat haben muss, aber wir kümmern
+uns nicht um das genaue Zertifikat, den Herausgeber (Issuer) oder den
+Betreff (Subject). Die einzige Einschränkung ist, dass es möglich sein
+sollte, seine Unterschrift (Signature) mit einigen unserer CA-Zertifikate
+zu überprüfen.
+
+Beispiel:
+@example
+GRANT ALL PRIVILEGES ON test.* TO root@@localhost IDENTIFIED BY "goodsecret" REQUIRE X509
+@end example
+
+@item
+@code{REQUIRE ISSUER issuer} macht Verbindungen restriktiver: Jetzt muss
+der Client ein gültiges X509-Zertifikat vorlegen, das von einem CA-Issuer
+herausgegeben wurde. Die Benutzung von X509-Zertifikaten impliziert immer
+Verschlüsselung, daher wird die Option "SSL" nicht mehr benötigt.
+
+Beispiel:
+@example
+GRANT ALL PRIVILEGES ON test.* TO root@@localhost IDENTIFIED BY "goodsecret" REQUIRE ISSUER "C=FI, ST=Some-State, L=Helsinki, O=MySQL Finnland AB, CN=Tonu Samuel/Email=tonu@@mysql.com"
+@end example
+
+@item
+@code{REQUIRE SUBJECT betreff} erfordert, dass der Client ein gültiges
+X509-Zertifikat mit dem Betreff "betreff" darauf hat. Wenn der Client ein
+gültiges Zertifikat hat, was aber einen anderen Betreff besitzt, wird die
+Verbindung nicht zugelassen.
+
+Beispiel:
+@example
+GRANT ALL PRIVILEGES ON test.* TO root@@localhost IDENTIFIED BY "goodsecret" REQUIRE SUBJECT "C=EE, ST=Some-State, L=Tallinn, O=MySQL demo client certificate, CN=Tonu Samuel/Email=tonu@@mysql.com"
+@end example
+
+@item
+@code{REQUIRE CIPHER cipher} wird benötigt um sicherzustellen, dass
+Chiffrierungen und Schlüssellängen benutzt werden, die stark genug sind.
+SSL selbst kann schwach sein, wenn alte Algorithmen mit kurzen
+Verschlüsselungsschlüsseln benutzt werden. Wenn diese Option benutzt wird,
+können wir exakte Chiffrierungen anfordern, bevor die Verbindung erlaubt
+wird.
+
+Beispiel:
+@example
+GRANT ALL PRIVILEGES ON test.* TO root@@localhost IDENTIFIED BY "goodsecret" REQUIRE CIPHER "EDH-RSA-DES-CBC3-SHA"
+@end example
+
+Es ist erlaubt, die Optionen in Kombination wie folgt zu benutzen:
+@example
+GRANT ALL PRIVILEGES ON test.* TO root@@localhost IDENTIFIED BY "goodsecret"
+ REQUIRE SUBJECT "C=EE, ST=Some-State, L=Tallinn, O=MySQL demo client certificate, CN=Tonu Samuel/Email=tonu@@mysql.com"
+ AND ISSUER "C=FI, ST=Some-State, L=Helsinki, O=MySQL Finnland AB, CN=Tonu Samuel/Email=tonu@@mysql.com"
+ AND CIPHER "EDH-RSA-DES-CBC3-SHA"
+@end example
+
+Es ist aber nicht erlaubt, irgend eine der Optionen doppelt zu benutzen.
+Nur unterschiedliche Optionen dürfen gemischt werden.
+@end itemize
+-----------
+
+@node User names, Privilege changes, GRANT, User Account Management
+@c German node Benutzernamen
+@subsection MySQL-Benutzernamen und -Passwörter
+
+@cindex Benutzernamen und Passwörter
+@cindex Passwörter, für Benutzer
+
+Es gibt mehrere Unterschiede in der Art, wie Benutzernamen und Passwörter
+von MySQL benutzt werden, und der Art, wie sie von Unix oder Windows
+benutzt werden:
+
+@itemize @bullet
+@item
+Benutzernamen, wie sie von MySQL für Authentifizierungszwecke benutzt
+werden, haben nicht zu tun mit Unix-Benutzernamen (Login-Namen) oder
+Windows-Benutzernamen. Die meisten MySQL-Clients versuchen sich zwar
+vorgabemäßig einzuloggen, indem sie den aktuellen Unix-Benutzernamen als
+den MySQL-Benutzernamen verwenden, aber das geschieht nur aus Gründen der
+Bequemlichkeit. Client-Programme lassen zu, dass ein anderer Name mit den
+@code{-u}- oder @code{--user}-Optionen angegeben wird. Das bedeutet, dass
+Sie eine Datenbank nicht auf irgend eine Weise sicher machen können, wenn
+nicht alle MySQL-Benutzernamen Passwörter haben. Jeder kann versuchen, sich
+mit dem Server zu verbinden, indem er irgend einen Namen angibt, und wird
+damit Erfolg haben, wenn er einen Namen angibt, der kein Passwort hat.
+
+@item
+MySQL-Benutzernamen können bis zu 16 Zeichen lang sein; Unix-Benutzernamen
+sind typischerweise auf 8 Zeichen begrenzt.
+
+@item
+MySQL-Passwörter haben nichts mit Unix-Passwörtern zu tun. Es gibt keine
+notwendige Verbindungen zwischen dem Passwort, das Sie benutzen, um sich an
+einer Unix-Maschine anzumelden, und dem Passwort, das Sie benutzen, um auf
+eine Datenbank auf dieser Maschine zuzugreifen.
+
+@item
+@c German FIX unsplit @ref
+MySQL verschlüsselt Passwörter mit einem anderen Algorithmus als dem, der
+während des Unix-Login-Prozesses benutzt wird, siehe die Beschreibungen der
+@code{PASSWORD()}- und @code{ENCRYPT()}-Funktionen in
+@ref{Miscellaneous functions}.
+Beachten Sie, dass trotz der Tatsache, dass das Passwort
+'zerhackt' gespeichert wird, es ausreicht, Ihr 'zerhacktes' Passwort zu
+kennen, um sich am MySQL-Server anmelden zu können!
+@end itemize
+
+MySQL-Benutzer und ihre Berechtigungen werden normalerweise mit dem
+@code{GRANT}-Befehl erzeugt. @xref{GRANT}.
+
+Wenn Sie sich an einem MySQL-Server mit einem Kommandozeilen-Client
+anmelden, sollten Sie das Passwort mit @code{--password=ihr-passwort}
+eingeben. @xref{Connecting}.
+
+@example
+mysql --user=monty --password=rate_mal datenbankname
+@end example
+
+Wenn Sie möchten, dass der Client eine Eingabeaufforderung für das Passwort
+präsentiert, sollten Sie @code{--password} ohne Argument benutzen.
+
+@example
+mysql --user=monty --password datenbankname
+@end example
+
+Oder in der kurzen Form:
+
+@example
+mysql -u monty -p datenbankname
+@end example
+
+Beachten Sie, dass in den letzten Beispielen 'datenbankname' @strong{NICHT}
+das Passwort ist.
+
+Wenn Sie die @code{-p}-Option zur Eingabe des Passworts benutzen wollen,
+tun Sie das wie folgt:
+
+@example
+mysql -u monty -prate_mal datenbankname
+@end example
+
+Auf einigen Systemen kürzt die Bibliothek, die MySQL benutzt, um die
+Eingabeaufforderung für das Passwort auszugeben, das Passwort auf 8
+Zeichen. Intern hat MySQL keine Beschränkung hinsichtlich der Länge des
+Passworts.
+
+
+@node Privilege changes, Default privileges, User names, User Account Management
+@c German node Berechtigungsänderungen
+@subsection Wann Berechtigungsänderungen wirksam werden
+
+Wenn @code{mysqld} startet, werden alle Berechtigungstabelleninhalte in den
+Arbeitsspeicher eingelesen und werden zu diesem Zeitpunkt wirksam.
+
+Änderungen in den Berechtigungstabellen, die mit @code{GRANT},
+@code{REVOKE} oder @code{SET PASSWORD} durchgeführt werden, werden
+unmittelbar vom Server bemerkt.
+
+Wenn Sie die Berechtigungstabellen manuell ändern (mit @code{INSERT},
+@code{UPDATE} usw.), müssen Sie ein @code{FLUSH PRIVILEGES}-Statement
+ausführen oder @code{mysqladmin flush-privileges} oder @code{mysqladmin
+reload} laufen lassen, um den Server anzuweisen, die Berechtigungstabellen
+neu einzulesen. Ansonsten haben Ihre Änderungen @emph{keine Auswirkung},
+bis Sie den Server neu starten. Wenn Sie die Berechtigungstabellen manuell
+ändern, aber vergessen, die Berechtigungen neu zu laden, werden Sie sich
+wundern, warum trotz Ihrer Änderungen kein Unterschied zu bemerken ist!
+
+Wenn der Server bemerkt, dass sich die Berechtigungstabellen geändert
+haben, werden bestehende Client-Verbindungen wie folgt davon betroffen:
+
+@itemize @bullet
+@item
+Tabellen- und Spalten-Berechtigungsänderungen werden bei der nächsten
+Anfrage des Clients wirksam.
+
+@item
+Datenbank-Berechtigungsänderungen werden beim nächsten @code{USE
+datenbank}-Befehl wirksam.
+@end itemize
+
+Globale Berechtigungsänderungen und Passwortänderungen werden beim nächsten
+Mal wirksam, wenn sich der Client verbindet.
+
+
+@node Default privileges, Adding users, Privilege changes, User Account Management
+@c German node Vorgabemäßige Berechtigungen
+@subsection Einrichtung der anfänglichen MySQL-Berechtigungen
+
+@cindex Berechtigungen, vorgabemäßig
+@cindex Vorgaben, Berechtigungen
+@cindex Root-Passwort
+@cindex Superuser
+@cindex Benutzer, Root
+@cindex anonymer Benutzer
+@cindex Passwort, Root-Benutzer
+
+Nach der Installation von MySQL konfigurieren Sie die anfänglichen
+Zugriffsberechtigungen, indem Sie @code{scripts/mysql_install_db} laufen
+lassen.
+@xref{Quick install}.
+Das @code{mysql_install_db}-Skript startet den @code{mysqld}-Server und
+initialisiert dann die Berechtigungstabellen, so dass diese folgenden Satz
+an Berechtigungen enthalten:
+
+@itemize @bullet
+@item
+Der MySQL-@code{root}-Benutzer wird als Superuser angelegt, der alles tun
+darf. Verbindungen müssen vom lokalen Host aus gemacht werden.
+
+@strong{HINWEIS:}
+Das anfängliche @code{root}-Passwort ist leer, daher kann sich jeder als
+@code{root} @emph{ohne Passwort} verbinden und hat alle Berechtigungen.
+
+@item
+@cindex anonymer Benutzer
+Ein anonymer Benutzer wird erzeugt, der mit Datenbanken, die den Namen
+@code{'test'} haben oder mit @code{'test_'} anfangen, alles tun darf.
+Verbindungen müssen vom lokalen Host aus gemacht werden. Das heißt, dass
+sich jeder lokale Benutzer ohne Passwort verbinden kann und als anonymer
+Benutzer behandelt wird.
+
+@item
+Andere Berechtigungen werden verweigert. Beispielsweise können normale
+Benutzer nicht @code{mysqladmin shutdown} oder @code{mysqladmin
+processlist} benutzen.
+@end itemize
+
+@strong{HINWEIS:} Die vorgabemäßigen Berechtigungen sind unter Windows
+anders.
+@xref{Windows running}.
+
+Weil Ihre Installation anfangs weit offen ist, sollten Sie als eins der
+ersten Dinge ein Passwort für den MySQL-@code{root}-Benutzer anlegen. Das
+können Sie wie folgt tun (beachten Sie, dass das Passwort mit der
+@code{PASSWORD()}-Funktion angegeben wird):
+
+@example
+shell> mysql -u root mysql
+mysql> UPDATE user SET Password=PASSWORD('neues_passwort')
+ WHERE user='root';
+mysql> FLUSH PRIVILEGES;
+@end example
+
+Ab MySQL-Version 3.22 können Sie das @code{SET PASSWORD}-Statement
+benutzen:
+
+@example
+shell> mysql -u root mysql
+mysql> SET PASSWORD FOR root=PASSWORD('neues_passwort');
+@end example
+
+Eine weitere Möglichkeit, das Passwort zu setzen, besteht in der Benutzung
+des @code{mysqladmin}-Befehls:
+
+@example
+shell> mysqladmin -u root password neues_passwort
+@end example
+
+Nur Benutzer mit Schreib-/Aktualisierungszugriff auf die
+@code{mysql}-Datenbank können das Passwort für andere Benutzer ändern. Alle
+normalen Benutzer (nicht anonyme Benutzer) können nur ihr eigenes Passwort
+ändern, entweder mit einem der obigen Befehle oder mit @code{SET
+PASSWORD=PASSWORD('neues_passwort')}.
+
+Denken Sie daran, wenn Sie das Passwort in der @code{user}-Tabelle direkt
+mit der ersten Methode ändern, dass Sie den Server anweisen müssen, die
+Berechtigungstabellen neu einzulesen (mit @code{FLUSH PRIVILEGES}), weil
+die Änderungen ansonsten nicht wahrgenommen werden.
+
+Sobald das @code{root}-Passwort gesetzt wurde, müssen Sie in der Folge
+immer das Passwort angeben, wenn Sie sich als @code{root} mit dem Server
+verbinden.
+
+Eventuell wollen Sie das @code{root}-Passwort leer lassen, damit Sie es für
+die weitere Konfiguration oder für Tests nicht angeben müssen. Stellen Sie
+jedoch sicher, dass Sie es setzen, bevor Sie Ihre Installation für irgend
+welche Produktionsaufgaben benutzen.
+
+Sehen Sie im @code{scripts/mysql_install_db}-Skript nach, wie es die
+vorgabemäßigen Berechtigungen installiert. Sie können das als Grundlage
+für das Hinzufügen weiterer Benutzer nehmen.
+
+Wenn Sie wollen, dass die anfänglichen Berechtigungen anders sind als die
+gerade beschriebenen, können Sie @code{mysql_install_db} abändern, bevor
+Sie es benutzen.
+
+@cindex Berechtigungstabellen, neu erzeugen
+@cindex neu erzeugen, Berechtigungstabellen
+Um die Berechtigungstabellen komplett neu zu erzeugen, entfernen Sie alle
+@file{.frm}-, @file{.MYI}- und @file{.MYD}-Dateien im Verzeichnis, das die
+@code{mysql}-Datenbank enthält. (Das ist das Verzeichnis namens
+@file{mysql} unter dem Datenbank-Verzeichnis, was aufgelistet wird, wenn
+Sie @code{mysqld --help} laufen lassen.) Lassen Sie dann das
+@code{mysql_install_db}-Skript laufen, eventuell nachdem Sie es editiert
+haben, um die Berechtigungen zu enthalten, die Sie haben wollen.
+
+@strong{HINWEIS:} Bei MySQL-Versionen vor Version 3.22.10 sollten Sie die
+@file{.frm}-Dateien NICHT löschen. Wenn Sie das versehentlich doch tun,
+müssen Sie sie aus Ihrer MySQL-Distribution zurück kopieren, bevor Sie
+@code{mysql_install_db} laufen lassen.
+
+
+@node Adding users, Passwords, Default privileges, User Account Management
+@c German node Benutzer hinzufügen
+@subsection Neue MySQL-Benutzer hinzufügen
+
+@findex GRANT-Statement
+@findex Statements, GRANT
+
+@cindex Berechtigungen, hinzufügen
+@cindex hinzufügen, neue Benutzerberechtigungen
+@cindex Benutzerberechtigungen, hinzufügen
+
+Sie können Benutzer auf zwei Arten hinzufügen: Indem Sie
+@code{GRANT}-Statements verwenden oder indem Sie die
+MySQL-Berechtigungstabellen direkt verändern. Die bevorzugte Methode ist,
+@code{GRANT}-Statements zu benutzen, denn sie sind präziser und weniger
+fehleranfällig. @xref{GRANT}.
+
+Ausserdem gibt es eine Menge von Dritten beigesteuerte Programme wie
+@code{phpmyadmin}, die benutzt werden können, um Benutzer zu erzeugen und
+zu verwalten. @xref{Contrib}.
+
+Die unten stehenden Beispiele zeigen, wie man den @code{mysql}-Client
+benutzt, um neue Benutzer zu erzeugen. Die Beispiele setzen voraus, dass
+Berechtigungen mit den Vorgabewerten eingerichtet wurden, die im vorherigen
+Abschnitt beschrieben wurden. Um also Änderungen machen zu können, müssen
+Sie sich von derselben Maschine aus verbinden, wo @code{mysqld} läuft, und
+Sie müssen sich als MySQL-@code{root}-Benutzer verbinden, und der
+@code{root}-Benutzer muss die @strong{insert}-Berechtigung für die
+@code{mysql}-Datenbank und die @strong{reload}-Verwaltungsberechtigung
+haben. Wenn Sie bereits das @code{root}-Benutzerpasswort geändert haben,
+müssen Sie es für die unten stehenden @code{mysql}-Befehle eingeben.
+
+Sie fügen neue Benutzer mit @code{GRANT}-Statements hinzu:
+
+@example
+shell> mysql --user=root mysql
+mysql> GRANT ALL PRIVILEGES ON *.* TO monty@@localhost
+ IDENTIFIED BY 'ein_passwort' WITH GRANT OPTION;
+mysql> GRANT ALL PRIVILEGES ON *.* TO monty@@"%"
+ IDENTIFIED BY 'ein_passwort' WITH GRANT OPTION;
+mysql> GRANT RELOAD,PROCESS ON *.* TO admin@@localhost;
+mysql> GRANT USAGE ON *.* TO dummy@@localhost;
+@end example
+
+Diese @code{GRANT}-Statements richten drei neue Benutzer ein:
+
+@table @code
+@item monty
+Einen echten Superuser, der sich von irgendwo her mit dem Server verbinden
+kann, aber das Passwort @code{'ein_passwort'} dafür verwenden muss.
+Beachten Sie, dass man @code{GRANT}-Statements sowohl für
+@code{monty@@localhost} als auch für @code{monty@@"%"} verwenden muss. Wenn
+man keinen Eintrag mit @code{localhost} hinzufügt, hat der Eintrag für den
+anonymen Benutzer für @code{localhost} Vorrang, der durch
+@code{mysql_install_db} angelegt wird, wenn man sich vom lokalen Host aus
+verbindet, weil dieser einen spezifischeren @code{Host}-Feldwert hat und
+daher früher in der @code{user}-Tabellen-Sortierreihenfolge auftaucht.
+
+@item admin
+Ein Benutzer, der sich ohne Passwort von @code{localhost} aus verbinden
+kann und der die @strong{reload}- und @strong{process}-
+Verwaltungsberechtigungen hat. Das erlaubt dem Benutzt, die
+@code{mysqladmin reload}-, @code{mysqladmin refresh}- und @code{mysqladmin
+flush-*}-Befehle sowie @code{mysqladmin processlist} auszuführen. Es werden
+keine Datenbank-bezogenen Berechtigungen gewährt. (Diese können später
+gewährt werden, indem zusätzliche @code{GRANT}-Statements ausgeführt
+werden.)
+
+@item dummy
+Ein Benutzer, der sich ohne Passwort verbinden kann, aber nur vom lokalen
+Host aus. Die globalen Berechtigungen sind alle auf @code{'N'} gesetzt -
+diese @code{USAGE}-Berechtigung erlaubt Ihnen, einen Benutzer ohne
+Berechtigungen anzulegen. Es wird angenommen, dass Sie später
+Datenbank-spezifische Berechtigungen gewähren.
+@end table
+
+@findex INSERT-Statement, Grant-Berechtigungen
+@findex Statements, INSERT
+Sie können dieselben Benutzerzugriffsinformationen direkt mittels
+@code{INSERT}-Statements eingeben und dann den Server anweisen, die
+Berechtigungstabellen neu zu laden:
+
+@example
+shell> mysql --user=root mysql
+mysql> INSERT INTO user VALUES('localhost','monty',PASSWORD('ein_passwort'),
+ 'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
+mysql> INSERT INTO user VALUES('%','monty',PASSWORD('ein_passwort'),
+ 'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
+mysql> INSERT INTO user SET Host='localhost',User='admin',
+ Reload_priv='Y', Process_priv='Y';
+mysql> INSERT INTO user (Host,User,Password)
+ VALUES('localhost','dummy','');
+mysql> FLUSH PRIVILEGES;
+@end example
+
+Abhängig von Ihrer MySQL-Version müssen Sie oben eventuell eine andere
+Anzahl von @code{'Y'}-Werten eingeben (Versionen vor Version 3.22.11 hatten
+weniger Berechtigungsspalten). Beim @code{admin}-Benutzer wird die besser
+lesbare @code{INSERT}-Syntax benutzt, die ab Version 3.22.11 verfügbar ist.
+
+Beachten Sie, dass Sie für die Einrichtung eines Superusers lediglich einen
+@code{user}-Tabelleneintrag mit Berechtigungsfeldern einrichten müssen, die
+auf @code{'Y'} gesetzt sind. Es sind keine @code{db}- oder
+@code{host}-Tabelleneinträge nötig.
+
+The Berechtigungsspalten in der @code{user}-Tabelle wurden im letzten
+@code{INSERT}-Statement nicht explizit gesetzt (für den Benutzer
+@code{dummy}), daher erhalten diese Spalten ihren Vorgabewert von
+@code{'N'}. Das ist dasselbe, was @code{GRANT USAGE} macht.
+
+Das folgende Beispiel fügt einen Benutzer @code{custom} hinzu, der sich von
+@code{localhost}, @code{server.domain} und @code{whitehouse.gov} aus
+verbinden kann. Er will auf die @code{bankkonto}-Datenbank nur von
+@code{localhost} aus zugreifen, auf die @code{spesen}-Datenbank nur von
+@code{whitehouse.gov} aus und auf die @code{kunde}-Datenbank von allen drei
+Hosts aus. Er will von allen drei Hosts aus das Passwort @code{dumm}
+benutzen.
+
+Um die Berechtigungen dieses Benutzers mit @code{GRANT}-Statements
+einzurichten, geben Sie folgende Befehle ein:
+
+@example
+shell> mysql --user=root mysql
+mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
+ ON bankkonto.*
+ TO custom@@localhost
+ IDENTIFIED BY 'dumm';
+mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
+ ON spesen.*
+ TO custom@@whitehouse.gov
+ IDENTIFIED BY 'dumm';
+mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
+ ON kunde.*
+ TO custom@@'%'
+ IDENTIFIED BY 'dumm';
+@end example
+
+Der Grund, warum wir Grant-Statements für den Benutzer 'custom' eingeben,
+ist, dass wir dem Benutzer Zugriff auf MySQL sowohl von der lokalen
+Maschine mit Unix-Sockets als auch von der entfernten Maschine
+'whitehouse.gov' über TCP/IP geben wollen.
+
+Um die Benutzerberechtigungen durch direkte Änderungen an den
+Berechtigungstabellen einzugeben, geben Sie folgende Befehle ein (beachten
+Sie das @code{FLUSH PRIVILEGES} am Ende):
+
+@example
+shell> mysql --user=root mysql
+mysql> INSERT INTO user (Host,User,Password)
+ VALUES('localhost','custom',PASSWORD('dumm'));
+mysql> INSERT INTO user (Host,User,Password)
+ VALUES('server.domain','custom',PASSWORD('dumm'));
+mysql> INSERT INTO user (Host,User,Password)
+ VALUES('whitehouse.gov','custom',PASSWORD('dumm'));
+mysql> INSERT INTO db
+ (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
+ Create_priv,Drop_priv)
+ VALUES
+ ('localhost','bankkonto','custom','Y','Y','Y','Y','Y','Y');
+mysql> INSERT INTO db
+ (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
+ Create_priv,Drop_priv)
+ VALUES
+ ('whitehouse.gov','spesen','custom','Y','Y','Y','Y','Y','Y');
+mysql> INSERT INTO db
+ (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
+ Create_priv,Drop_priv)
+ VALUES('%','kunde','custom','Y','Y','Y','Y','Y','Y');
+mysql> FLUSH PRIVILEGES;
+@end example
+
+Die ersten drei @code{INSERT}-Statements fügen @code{user}-Tabelleneinträge
+hinzu, die dem Benutzer @code{custom} erlauben, sich von den verschiedenen
+Hosts aus mit dem gegebenen Passwort zu verbinden, gewähren ihm aber keine
+Berechtigungen (alle Berechtigungen werden auf den Vorgabewert @code{'N'}
+gesetzt). Die nächsten drei @code{INSERT}-Statements fügen
+@code{db}-Tabelleneinträge hinzu, die @code{custom} Berechtigungen für die
+@code{bankkonto}-, @code{spesen}- und @code{kunde}-Datenbanken gewähren,
+aber nur, wenn auf sie von den korrekten Hosts aus zugegriffen wird. Wie
+immer, wenn die Berechtigungstabellen direkt verändert werden, muss dem
+Server gesagt werden, dass er sie neu laden muss (mit @code{FLUSH
+PRIVILEGES}), damit die Berechtigungsänderungen wirksam werden.
+
+Wenn Sie einem bestimmten Benutzer Zugriff von irgendeiner Maschine in
+einer gegebenen Domäne geben wollen, können Sie ein @code{GRANT}-Statement
+wie das folgende absetzen:
+
+@example
+mysql> GRANT ...
+ ON *.*
+ TO benutzername@@"%.domaene.de"
+ IDENTIFIED BY 'passwort';
+@end example
+
+Um dasselbe durch direkte Änderung der Berechtigungstabellen einzugeben,
+machen Sie folgendes:
+
+@example
+mysql> INSERT INTO user VALUES ('%.domaene.de', 'benutzername',
+ PASSWORD('passwort'),...);
+mysql> FLUSH PRIVILEGES;
+@end example
+
+Sie können auch @code{xmysqladmin}, @code{mysql_webadmin} und sogar
+@code{xmysql} benutzen, um die Werte in den Berechtigungstabellen
+einzufügen, zu ändern und zu aktualisieren. Sie finden diese Werkzeuge unter
+@uref{http://www.mysql.com/downloads/contrib/,Contrib-Verzeichnis der
+MySQL-Website}.
+
+
+@node Passwords, Password security, Adding users, User Account Management
+@c German node Passwörter
+@subsection Passwörter einrichten
+
+@findex PASSWORD()
+@findex SET PASSWORD Statement
+
+@cindex Passwörter, setzen
+@cindex setzen, Passwörter
+
+In den meisten Fällen sollten Sie @code{GRANT} benutzen, um Ihre Benutzer /
+Passwörter einzurichten, daher trifft das folgende nur für fortgeschrittene
+Benutzer zu. @xref{GRANT, , @code{GRANT}}.
+
+Die Beispiele in den vorherigen Abschnitten erläutern ein wichtiges
+Prinzip: Wenn Sie ein nicht leeres Passwort mit @code{INSERT}- oder
+@code{UPDATE}-Statements setzen, müssen Sie die @code{PASSWORD()}-Funktion
+benutzen, um es zu verschlüsseln. Das liegt daran, dass die
+@code{user}-Tabelle Passwörter in verschlüsselter Form speichert, nicht als
+Klartext. Wenn Sie diese Tatsache vergessen, ist es möglich, dass sie
+Passwörter wie folgt setzen:
+
+@example
+shell> mysql -u root mysql
+mysql> INSERT INTO user (Host,User,Password)
+ VALUES('%','heinzholger','keks');
+mysql> FLUSH PRIVILEGES;
+@end example
+
+Das Ergebnis ist, dass der Klartextwert @code{'keks'} als Passwort in
+der @code{user}-Tabelle gespeichert ist. Wenn der Benutzer @code{heinzholger}
+versucht, sich mittels dieses Passworts mit dem Server zu verbinden,
+verschlüsselt der @code{mysql}-Client es mit @code{PASSWORD()}, erzeugt
+damit einen Authentifikationsvektor, der auf dem @strong{verschlüsselten}
+Passwort und einer Zufallszahl basiert, die er vom Server erhält, und
+schickt das Ergebnis zum Server. Der Server benutzt den
+@code{password}-Wert in der @code{user}-Tabelle (den @strong{nicht
+verschlüsselten} Wert @code{'keks'}), um dieselben Berechnungen
+durchzuführen, und vergleicht die Ergebnisse. Der Vergleich schlägt fehl
+und der Server verweigert die Verbindung:
+
+@example
+shell> mysql -u heinzholger -pkeks test
+Access denied
+@end example
+
+Passwörter müssen verschlüsselt sein, wenn sie in die @code{user}-Tabelle
+eingefügt werden, daher hätte das @code{INSERT}-Statement also wie folgt
+formuliert sein müssen:
+
+@example
+mysql> INSERT INTO user (Host,User,Password)
+ VALUES('%','heinzholger',PASSWORD('keks'));
+@end example
+
+Sie müssen die @code{PASSWORD()}-Funktion auch benutzen, wenn Sie @code{SET
+PASSWORD}-Statements gebrauchen:
+
+@example
+mysql> SET PASSWORD FOR heinzholger@@"%" = PASSWORD('keks');
+@end example
+
+Wenn Sie Passwörter mit dem @code{GRANT ... IDENTIFIED BY}-Statement oder
+dem @code{mysqladmin password}-Befehl setzen, wird die
+@code{PASSWORD()}-Funktion nicht benötigt. Beide sorgen dafür, dass das
+Passwort verschlüsselt wird, daher würden Sie ein Passwort @code{'keks'}
+wie folgt setzen:
+
+@example
+mysql> GRANT USAGE ON *.* TO heinzholger@@"%" IDENTIFIED BY 'keks';
+@end example
+
+oder
+
+@example
+shell> mysqladmin -u heinzholger password keks
+@end example
+
+@strong{NOTE:} @code{PASSWORD()} verschlüsselt Passwörter nicht auf
+dieselbe Art, wie das bei Unix-Passwörtern der Fall ist. Wenn daher Ihr
+Unix-Passwort und Ihr MySQL-Passwort identisch sind, sollten Sie daraus
+nicht schließen, dass @code{PASSWORD()} denselben Verschlüsselungswert
+ergibt wie der, der in der Unix-Passwortdatei gespeichert ist.
+@xref{User names}.
+
+
+@node Password security, , Passwords, User Account Management
+@c German node Passwort-Sicherheit
+@subsection Wie Sie Ihre Passwörter sicher halten
+
+Es ist nicht ratsam, Ihr Passwort so einzugeben, dass es von anderen
+Benutzern entdeckt werden kann. Die verschiedenen Methoden, Passwörter
+bei der Benutzung von Client-Programmen einzugeben, sind unten aufgeführt,
+jeweils mit einer Einschätzung des Risikos der Methode:
+
+@itemize @bullet
+@item
+Geben Sie einem normalen Benutzer nie Zugriff auf die
+@code{mysql.user}-Tabelle. Wenn jemand das verschlüsselte Passwort für
+einen Benutzer kennt, ermöglicht ihm das, sich als dieser Benutzer
+einzuloggen. Die Passwörter sind nur 'zerhackt', so dass niemand das echte
+Passwort sehen können sollte, das Sie benutzen (falls Sie ein ähnliches
+Passwort für Ihre anderen Applikationen benutzen sollten).
+
+@item
+Sie können auf der Kommandozeile die @code{-pyour_pass}- oder
+@code{--password=your_pass}-Option benutzen. Das ist bequem, aber unsicher,
+weil Ihr Passwort für Systemzustandsprogramme (wie @code{ps}) sichtbar
+wird, die möglicherweise von anderen Benutzer aufgerufen werden, um
+Kommandozeilen anzuzeigen. (MySQL-Clients überschreiben typischerweise die
+Kommandozeilenargumente während der Initialisierungssequenz mit Nullen,
+dennoch gibt es einen kurzen Zeitraum, während dessen der Wert sichtbar
+ist.)
+
+@item
+Sie können eine @code{-p}- oder @code{--password}-Option (ohne
+@code{ihr_passwort}-Wert) benutzen. In diesem Fall erbittet das
+Client-Programm das Passwort vom Terminal:
+@findex -p-Option
+@findex -password-Option
+
+@example
+shell> mysql -u benutzername -p
+Enter password: ********
+@end example
+
+Die @samp{*}-Zeichen stehen für Ihr Passwort.
+
+Es ist sicherer, Ihr Passwort auf diese Art einzugeben statt auf der
+Kommandozeile, weil es für andere Benutzer nicht sichtbar wird. Diese
+Methode ist jedoch nur für Programme geeignet, die interaktiv laufen. Wenn
+Sie einen Client von einem Skript aus aufrufen wollen, das nicht interaktiv
+läuft, gibt es keine Möglichkeit, das Passwort vom Terminal aus einzugeben.
+Auf solchen Systemen kann es sogar vorkommen, dass die erste Zeile Ihres
+Skripts gelesen und (fälschlicherweise) als Ihr Passwort interpretiert
+wird!
+
+@item
+@tindex .my.cnf-Datei
+Sie können Ihr Passwort in einer Konfigurationsdatei speichern.
+Beispielsweise können Sie Ihr Passwort im @code{[client]}-Abschnitt der
+@file{.my.cnf}-Datei in Ihrem Heimatverzeichnis aufführen:
+
+@example
+[client]
+password=ihr_passwort
+@end example
+
+Wenn Sie Ihr Passwort in @file{.my.cnf} speichern, sollte die Datei nicht
+für die Gruppe (group) lesbar oder schreibbar sein. Stellen Sie sicher,
+dass der Zugriffsmodus der Datei @code{400} oder @code{600} ist.
+
+@xref{Option files}.
+@item
+Sie können Ihr Passwort in der @code{MYSQL_PWD}-Umgebungsvariablen
+speichern, aber diese Methode wird als extrem unsicher erachtet und sollte
+nicht gewählt werden. Einige Versionen von @code{ps} beinhalten eine
+Option, die Umgebung laufender Prozesse anzeigen zu lassen; Ihr Passwort
+würde dann für alle im Klartext lesbar sein, wenn Sie @code{MYSQL_PWD}
+setzen. Selbst auf Systemen ohne eine solche Version von @code{ps} ist es
+nicht ratsam, anzunehmen, dass es keine andere Methode gibt,
+Prozessumgebungen einzusehen. @xref{Environment variables}.
+@end itemize
+
+Alles in allem sind die sichersten Methoden, das Passwort entweder durch
+Client-Programm entgegen nehmen zu lassen oder es in einer sauber
+abgesicherten @file{.my.cnf}-Datei einzugeben.
+
+
+@node Disaster Prevention, Database Administration, User Account Management, MySQL Database Administration
+@c German node Katastrophenschutz und Wiederherstellung
+@section Katastrophenschutz und Wiederherstellung
+
+
+
+@menu
+* Backup::
+* BACKUP TABLE::
+* RESTORE TABLE::
+* CHECK TABLE::
+* REPAIR TABLE::
+* Table maintenance::
+* Maintenance regimen::
+* Table-info::
+@end menu
+
+@node Backup, BACKUP TABLE, Disaster Prevention, Disaster Prevention
+@c German node Datensicherung
+@subsection Datenbank-Datensicherungen
+
+@cindex Datenbanken, Datensicherungen
+@cindex Datensicherungen
+
+Weil MySQL-Tabellen als Dateien gespeichert werden, ist es leicht, eine
+Datensicherung durchzuführen. Um eine konsistente Datensicherung zu
+erhalten, machen Sie ein @code{LOCK TABLES} auf die relevanten Tabellen,
+gefolgt von @code{FLUSH TABLES} für die Tabellen.
+@xref{LOCK TABLES, , @code{LOCK TABLES}}.
+@xref{FLUSH, , @code{FLUSH}}.
+Sie brauchen lediglich eine Lesesperre (Read Lock); das erlaubt anderen
+Threads, die Tabellen weiterhin abzufragen, während Sie eine Kopie der
+Dateien im Datenbank-Verzeichnis machen. @code{FLUSH TABLE} wird benötigt,
+um sicherzustellen, dass alle aktiven Indexseiten auf Platte zurück
+geschrieben werden, bevor Sie die Datensicherung beginnen.
+
+Wenn Sie eine Tabellensicherung auf SQL-Ebene machen wollen, können Sie
+@code{SELECT INTO OUTFILE} oder @code{BACKUP TABLE} benutzen.
+@xref{SELECT}. @xref{BACKUP TABLE}.
+
+Eine weitere Möglichkeit, eine Datenbank zu sichern, stellt die Benutzung
+des @code{mysqldump}-Programms oder des @code{mysqlhotcopy-Skript}s dar.
+@xref{mysqldump, , @code{mysqldump}}. @xref{mysqlhotcopy, ,
+@code{mysqlhotcopy}}.
+
+@enumerate
+@item
+Machen Sie eine komplette Sicherung Ihrer Datenbanken:
+
+@example
+shell> mysqldump --tab=/pfad/zum/verzeichnis/ --opt --full
+
+or
+
+shell> mysqlhotcopy Datenbank /pfad/zum/verzeichnis/
+@end example
+
+Sie können auch einfach alle Tabellendateien (@file{*.frm}-, @file{*.MYD}-
+und @file{*.MYI}-Dateien) kopieren, solange der Server nicht gerade etwas
+aktualisiert. Das Skript @code{mysqlhotcopy} benutzt diese Methode.
+
+@item
+@cindex Log-Dateien, Namen
+Halten Sie @code{mysqld} an, wenn er läuft, und starten Sie ihn mit der
+@code{--log-update[=datei]}-Option. @xref{Update log}. Die
+Update-Log-Datei(en) gibt Ihnen die Information, die Sie dafür benötigen,
+um Änderungen an der Datenbank zu replizieren, die ab dem Zeitpunkt
+durchgeführt wurden, als Sie @code{mysqldump} ausführten.
+@end enumerate
+
+Wenn Sie etwas wiederherstellen müssen, versuchen Sie zunächst, Ihre
+Tabellen mit @code{REPAIR TABLE} oder @code{myisamchk -r} wieder
+herzustellen. Das sollte in 99,9% aller Fälle funktionieren. Wenn
+@code{myisamchk} fehlschlägt, probieren Sie folgende Prozedur (das
+funktioniert nur, wenn Sie MySQL mit @code{--log-update} gestartet haben.
+@xref{Update log}.):
+
+@enumerate
+@item
+Stellen Sie die originale @code{mysqldump}-Datensicherung wieder her.
+@item
+Führen Sie folgenden Befehl aus, um die Aktualisierungen (Updates) im
+Binär-Log noch einmal laufen zu lassen:
+
+@example
+shell> mysqlbinlog hostname-bin.[0-9]* | mysql
+@end example
+
+Wenn Sie das Update-Log benutzen, können Sie folgendes machen:
+
+@example
+shell> ls -1 -t -r hostname.[0-9]* | xargs cat | mysql
+@end example
+@end enumerate
+
+@code{ls} wird benutzt, um alle Update-Log-Dateien in der richtigen
+Reihenfolge zu erhalten.
+
+Mit @code{SELECT * INTO OUTFILE 'datei' FROM tabelle} können Sie auch
+selektive Datensicherungen herstellen und diese wieder herstellen mit
+@code{LOAD DATA INFILE 'datei' REPLACE ...}. Um Duplikate zu vermeiden,
+benötigen Sie einen Primärschlüssel (@code{PRIMARY KEY}) oder einen
+eindeutigen Schlüssel (@code{UNIQUE}) in der Tabelle. Das Schlüsselwort
+@code{REPLACE} führt dazu, dass alte Datensätze durch neue ersetzt werden,
+wenn ein neuer Datensatz einen alten auf einem eindeutigen Schlüsselwert
+duplizieren würde.
+
+Wenn Sie bei der Datensicherung auf Ihrem System Performance-Probleme
+bekommen, können Sie diese lösen, indem Sie Replikation einrichten und die
+Datensicherungen auf dem Slave statt auf dem Master durchführen.
+@xref{Replication Intro}.
+
+Wenn Sie ein Veritas-Dateisystem benutzen, können Sie folgendes tun:
+
+@enumerate
+@item
+Führen Sie einen Client- (Perl ?) @code{FLUSH TABLES mit READ LOCK} aus.
+
+@item
+Forken Sie eine Shell oder führen Sie einen anderen Client aus @code{mount
+vxfs snapshot}.
+
+@item
+Führen Sie im ersten Client @code{UNLOCK TABLES} aus.
+
+@item
+Kopieren Sie die Dateien von snapshot
+
+@item
+Unmounten Sie snapshot
+@end enumerate
+
+
+@node BACKUP TABLE, RESTORE TABLE, Backup, Disaster Prevention
+@c German node BACKUP TABLE
+@subsection @code{BACKUP TABLE}-Syntax
+
+@findex BACKUP TABLE
+
+@cindex Datensicherungen, Datenbank
+
+@example
+BACKUP TABLE tabelle[,tabelle...] TO '/pfad/zum/backup/verzeichnis'
+@end example
+
+Machen Sie eine Kopie aller Tabellendateien ins Datensicherungsverzeichnis,
+was die Mindestanforderung für die Wiederherstellung darstellt. Momentan
+funktioniert das nur bei @code{MyISAM}-Tabellen. Bei @code{MyISAM}-Tabellen
+kopiert man @code{.frm}- (Definition) und @code{.MYD}- (Daten) Dateien. Die
+Indexdatei kann aus diesen beiden aufgebaut werden.
+
+@c German FIX changed @xref to @ref
+Bevor Sie diesen Befehl ausführen, sehen Sie bitte unter
+@ref{Backup} nach.
+
+Während der Datensicherung gilt eine Lesesperre (Read Lock) für jede
+Tabelle, eine nach der anderen, während sie gesichert werden. Wenn Sie
+mehrere Tabellen als Schnappschuss sichern wollen, müssen Sie zuerst ein
+@code{LOCK TABLES} ausführen, das eine Lesesperre für jede Tabelle in der
+zu sichernden Gruppe enthält.
+
+Der Befehl gibt eine Tabelle mit folgenden Spalten zurück:
+
+@multitable @columnfractions .35 .65
+@item @strong{Spalte} @tab @strong{Wert}
+@item Table @tab Tabellenname
+@item Op @tab Immer ``backup''
+@item Msg_type @tab @code{status}, @code{error}, @code{info} oder @code{warning}.
+@item Msg_text @tab Die Meldung.
+@end multitable
+
+Beachten Sie, dass @code{BACKUP TABLE} erst ab MySQL 3.23.25 verfügbar ist.
+
+
+@node RESTORE TABLE, CHECK TABLE, BACKUP TABLE, Disaster Prevention
+@c German node RESTORE TABLE
+@subsection @code{RESTORE TABLE}-Syntax
+
+@findex RESTORE TABLE
+
+@example
+RESTORE TABLE tabelle[,tabelle...] FROM '/pfad/zum/backup/verzeichnis'
+@end example
+
+Stellt die Tabelle(n) aus der Datensicherung her, die mit @code{BACKUP
+TABLE} gesichert wurde(n). Bestehende Tabellen werden nicht überschrieben;
+wenn Sie über bestehende Tabellen wiederherstellen wollen, erhalten Sie
+eine Fehlermeldung. RESTORE benötigt länger als Datensicherung, weil der Index neu
+aufgebaut werden muss. Je mehr Schlüssel Sie haben, desto länger dauert es.
+Genau wie @code{BACKUP TABLE} funktioniert RESTORE momentan nur mit
+@code{MyISAM}-Tabellen.
+
+
+Der Befehl gibt eine Tabelle mit folgenden Spalten zurück:
+
+@multitable @columnfractions .35 .65
+@item @strong{Spalte} @tab @strong{Wert}
+@item Table @tab Tabellenname
+@item Op @tab Immer ``restore''
+@item Msg_type @tab @code{status}, @code{error}, @code{info} oder @code{warning}.
+@item Msg_text @tab Die Meldung.
+@end multitable
+
+
+@node CHECK TABLE, REPAIR TABLE, RESTORE TABLE, Disaster Prevention
+@c German node CHECK TABLE
+@subsection @code{CHECK TABLE}-Syntax
+
+@findex CHECK TABLE
+
+@example
+CHECK TABLE tabelle[,tabelle...] [option [option...]]
+
+option = QUICK | FAST | MEDIUM | EXTENDED | CHANGED
+@end example
+
+@code{CHECK TABLE} funktioniert nur bei @code{MyISAM}-Tabellen. Bei
+@code{MyISAM}-Tabellen ist es dasselbe, wie @code{myisamchk -m tabelle}
+über die Tabelle laufen zu lassen.
+
+Wenn Sie keine Option angeben, wird @code{MEDIUM} benutzt.
+
+Prüft die Tabelle(n) auf Fehler. Bei @code{MyISAM}-Tabellen werden die
+Schlüssel-Statistiken aktualisiert. Der Befehl gibt eine Tabelle mit
+folgenden Spalten zurück:
+
+@multitable @columnfractions .35 .65
+@item @strong{Spalte} @tab @strong{Wert}
+@item Table @tab Tabellenname
+@item Op @tab Immer ``check''.
+@item Msg_type @tab @code{status}, @code{error}, @code{info} oder @code{warning}.
+@item Msg_text @tab Die Meldung.
+@end multitable
+
+Beachten Sie, dass Sie viele Zeilen an Information für jede geprüfte
+Tabelle erhalten. Die letzte Zeile enthält den @code{Msg_type status} und
+sollte normalerweise @code{OK} sein. Wenn Sie nicht @code{OK} erhalten, oder @code{Not
+checked}, sollten Sie im Normalfall eine Reparatur der Tabelle durchführen.
+@xref{Table maintenance}. @code{Not checked} bedeutet, dass bei der Tabelle
+der angegebene @code{TYPE} MySQL mitgeteilt hat, dass es keinerlei
+Notwendigkeit gab, die Tabelle zu prüfen.
+
+Die unterschiedlichen Prüfoptionen stehen für folgendes:
+
+@multitable @columnfractions .20 .80
+@item @strong{Option} @tab @strong{Bedeutung}
+@item @code{QUICK} @tab Keine Zeilen nach falschen Verknüpfungen (Links) durchsehen (scannen).
+@item @code{FAST} @tab Nur Tabellen prüfen, die nicht ordnungsgemäß geschlossen wurden.
+@item @code{CHANGED} @tab Nur Tabellen prüfen, die seit der letzten Prüfung geändert wurden oder die nicht ordnungsgemäß geschlossen wurden.
+@item @code{MEDIUM} @tab Zeilen durchsehen (scannen), um zu bestätigen, dass gelöschte Verknüpfungen (Links) in Ordnung sind. Diese Option berechnet auch eine Schlüssel-Prüfsumme für die Zeilen und bestätigt diese mit einer berechneten Prüfsumme für die Schlüssel.
+@item @code{EXTENDED} @tab Schlägt komplett alle Schlüssel für jede Zeile nach (Lookup). Hierdurch wird sichergestellt, dass die Tabelle 100% konsistent ist, aber das benötigt lange Zeit!
+@end multitable
+
+Bei @code{MyISAM}-Tabellen dynamischer Größe führt eine Prüfung immer
+eine @code{MEDIUM}-Prüfung durch. Bei Zeilen statischer Länge wird das
+Durchsehen (Scan) der Zeilen durch @code{QUICK} und @code{FAST}
+übersprungen, weil solche Zeilen sehr selten beschädigt sind.
+
+Sie können Prüfoptionen wie folgt kombinieren:
+
+@example
+CHECK TABLE test_tabelle FAST QUICK;
+@end example
+
+Das würde nur eine QUICK-Prüfung der Tabelle durchführen, wenn diese nicht
+ordnungsgemäß geschlossen worden wäre.
+
+@strong{HINWEIS:} In einigen Fällen kann @code{CHECK TABLE} zu einer
+Änderung der Tabelle führen! Das geschieht, wenn die Tabelle als
+'beschädigt' oder 'nicht ordnungsgemäß geschlossen' gekennzeichnet ist,
+aber @code{CHECK TABLE} keine Probleme in der Tabelle gefunden hat. In
+diesem Fall kennzeichnet @code{CHECK TABLE} die Tabelle als in Ordnung.
+
+Wenn eine Tabelle beschädigt ist, liegt das Problem höchst wahrscheinlich
+in den Indexen und nicht im Daten-Teil. Alle oben genannten Prüfoptionen
+prüfen die Indexe gründlich und sollten daher die meisten Fehler finden.
+
+Wenn Sie lediglich eine Tabelle prüfen wollen, von der Sie annehmen, dass
+sie in Ordnung ist, sollten Sie keine Prüfoptionen oder die
+@code{QUICK}-Option angeben. Letztere sollte benutzt werden, wenn Sie es
+eilig haben und das sehr geringe Risiko auf sich nehmen können, dass
+@code{QUICK} keinen Fehler in der Daten-Datei findet. (In den meisten Fällen
+sollte MySQL bei normalem Gebrauch jeden Fehler in der Daten-Datei finden.
+Wenn das geschieht, wird die Tabelle als 'beschädigt' gekennzeichnet, was
+bedeutet, dass die Tabelle solange nicht benutzt werden kann, bis sie
+repariert ist.)
+
+@code{FAST} und @code{CHANGED} sind in erster Linie für die Benutzung durch
+ein Skript vorgesehen (zum Beispiel für die Ausführung durch cron), wenn
+Sie Ihre Tabellen von Zeit zu Zeit prüfen wollen. Für die meisten
+Anwendungsfälle sollte man @code{FAST} vor @code{CHANGED} bevorzugen. (Der
+einzige Fall, wo das nicht so ist, ist, wenn Sie vermuten, einen Bug im
+@code{MyISAM}-Code gefunden zu haben.)
+
+@code{EXTENDED} ist nur für den Fall vorgesehen, dass Sie eine normale
+Prüfung haben durchlaufen lassen, aber immer noch seltsame Fehler von einer
+Tabelle erhalten, wenn MySQL versucht, eine Zeile zu aktualisieren oder
+eine Zeile über einen Schlüssel zu finden (das ist sehr unwahrscheinlich,
+wenn eine normale Prüfung durchgelaufen ist!).
+
+Es wurde berichtet, dass bei der Tabellenprüfung einige Dinge nicht
+automatisch korrigiert werden können:
+
+@itemize @bullet
+@item
+@code{Found row where the auto_increment column has the value 0}.
+
+Das bedeutet, dass es in der Tabelle eine Zeile gibt, in der die
+@code{auto_increment}-Index-Spalte den Wert 0 enthält. (Es ist möglich,
+eine Zeile zu erzeugen, in der die auto_increment-Spalte 0 ist, indem man
+die Spalte explizit mit einem @code{UPDATE}-Statement auf 0 setzt.)
+
+Das ist für sich genommen kein Fehler, kann aber Probleme verursachen, wenn
+Sie die Tabelle dumpen und dann wiederherstellen, oder ein @code{ALTER
+TABLE} auf die Tabelle machen. In diesen Fällen ändert sich der Wert der
+auto_increment-Spalte gemäß den Regeln für auto_increment-Spalten, was
+Probleme wie doppelte Schlüsseleintragsfehler bringen könnte.
+
+Um diese Warnmeldung loszuwerden, führen Sie einfach ein
+@code{UPDATE}-Statement durch und setzen die Spalte auf irgend einen
+anderen Wert als 0.
+@end itemize
+
+
+@node REPAIR TABLE, Table maintenance, CHECK TABLE, Disaster Prevention
+@c German node REPAIR TABLE
+@subsection @code{REPAIR TABLE}-Syntax
+
+@findex REPAIR TABLE
+
+@example
+REPAIR TABLE tabelle[,tabelle...] [QUICK] [EXTENDED]
+@end example
+
+@code{REPAIR TABLE} funktioniert nur bei @code{MyISAM}-Tabellen und ist
+dasselbe, wie @code{myisamchk -r tabelle} auf die Tabelle auszuführen.
+
+Normalerweise sollten sie diesen Befehl nie ausführen müssen, aber wenn ein
+Unglück passiert, ist es sehr wahrscheinlich, dass Sie alle Daten einer
+MyISAM-Tabelle mit @code{REPAIR TABLE} retten können. Wenn Ihre Tabellen
+häufig beschädigt werden, sollten Sie versuchen, den Grund hierfür
+herauszufinden! @xref{Crashing}. @xref{MyISAM table problems}.
+
+@code{REPAIR TABLE} repariert eine möglicherweise beschädigte Tabelle. Der
+Befehl gibt eine Tabelle mit folgenden Spalten zurück:
+
+@multitable @columnfractions .35 .65
+@item @strong{Spalte} @tab @strong{Wert}
+@item Table @tab Tabellenname
+@item Op @tab Immer ``repair''
+@item Msg_type @tab @code{status}, @code{error}, @code{info} oder @code{warning}.
+@item Msg_text @tab Die Meldung.
+@end multitable
+
+Beachten Sie, dass Sie viele Zeilen an Informationen für jede reparierte
+Tabelle erhalten. Die letzte Zeile enthält den @code{Msg_type status} und
+sollte normalerweise @code{OK} sein. Wenn Sie nicht @code{OK} erhalten,
+sollten Sie versuchen, die Tabelle mit @code{myisamchk -o} zu reparieren,
+weil @code{REPAIR TABLE} noch nicht alle Optionen von @code{myisamchk}
+enthält. In naher Zukunft werden wir das flexibler gestalten.
+
+Wenn @code{QUICK} angegeben wird, versucht MySQL lediglich ein
+@code{REPAIR} des Indexbaums.
+
+Wenn Sie @code{EXTENDED} benutzen, erzeugt MySQL den Index Zeile für Zeile,
+anstatt einen Index auf einmal durch Sortieren zu erzeugen. Das kann bei
+Schlüsseln fester Länge besser sein, wenn Sie lange @code{char()}-Schlüssel
+haben, die sich gut komprimieren lassen.
+
+
+@node Table maintenance, Maintenance regimen, REPAIR TABLE, Disaster Prevention
+@c German node Tabellenwartung
+@subsection Benutzung von @code{myisamchk} für Tabellenwartung und Absturzreparatur
+
+Ab MySQL-Version 3.23.13 können Sie MyISAM-Tabellen mit dem @code{CHECK
+TABLE}-Befehl überprüfen. @xref{CHECK TABLE}. Mit dem @code{REPAIR
+TABLE}-Befehl können Sie Tabellen reparieren. @xref{REPAIR TABLE}.
+
+Um MyISAM-Tabellen (@code{.MYI} und @code{.MYD}) zu überprüfen und / oder
+zu reparieren, sollten sie das @code{myisamchk}-Dienstprogramm benutzen. Um
+ISAM-Tabellen (@code{.ISM} und @code{.ISD}) zu überprüfen und / oder zu
+reparieren, sollten Sie das @code{isamchk}-Dienstprogramm benutzen.
+@xref{Table types}.
+
+Der folgende Text behandelt @code{myisamchk}, trifft aber voll umfänglich
+auch auf das alte @code{isamchk} zu.
+
+Sie können das @code{myisamchk}-Dienstprogramm benutzen, um Informationen über
+Ihre Datenbanktabellen zu erhalten, sie zu prüfen und zu reparieren, oder
+um sie zu optimieren. Die folgenden Abschnitte beschreiben, wie man
+@code{myisamchk} aufruft (inklusive einer Beschreibung seiner Optionen),
+wie man einen Wartungsplan für Tabellen erstellt und wie die
+unterschiedlichen Funktionen von @code{myisamchk} benutzt werden.
+
+In den meisten Fällen können Sie auch den Befehl @code{OPTIMIZE TABLES}
+benutzen, um Tabellen zu optimieren und zu reparieren, aber dieser ist
+nicht so schnell und (in Fall wirklich schwerer Fehler) nicht so
+zuverlässig wie @code{myisamchk}.
+Auf der anderen Seite ist @code{OPTIMIZE TABLE} leichter zu benutzen, und
+Sie brauchen sich nicht um das Flushen von Tabellen zu kümmern.
+@xref{OPTIMIZE TABLE, , @code{OPTIMIZE TABLE}}.
+
+Obwohl das Reparieren bei @code{myisamchk} recht sicher ist, ist es immer
+eine gute Idee, eine Datensicherung zu machen, bevor eine Reparatur
+durchgeführt wird (oder etwas Sonstiges, das viele Änderungen an einer
+Tabelle durchführt).
+
+
+
+@menu
+* myisamchk syntax::
+* myisamchk general options::
+* myisamchk check options::
+* myisamchk repair options::
+* myisamchk other options::
+* myisamchk memory::
+* Crash recovery::
+* Check::
+* Repair::
+* Optimisation::
+@end menu
+
+@node myisamchk syntax, myisamchk general options, Table maintenance, Table maintenance
+@c German node myisamchk-Syntax
+@subsubsection Aufrufsyntax von @code{myisamchk}
+
+@code{myisamchk} wird wie folgt aufgerufen:
+
+@example
+shell> myisamchk [optionen] tabelle
+@end example
+
+@code{optionen} legt fest, was @code{myisamchk} tun soll. Die Optionen sind
+unten beschrieben. (Sie erhalten eine Liste der Optionen, wenn Sie
+@code{myisamchk --help} eingeben.) Ohne Optionen aufgerufen prüft
+@code{myisamchk} einfach nur Ihre Tabelle. Um mehr Informationen zu
+erhalten oder @code{myisamchk} anzuweisen, korrigierende Aktionen
+durchzuführen, geben Sie Optionen wie unten und in den folgenden
+Abschnitten beschrieben an.
+
+@code{tabelle} ist die Datenbanktabelle, die Sie prüfen oder reparieren
+wollen. Wenn Sie @code{myisamchk} anderswo als im Datenbank-Verzeichnis
+ausführen, müssen Sie den Pfad zur Datei angeben, denn @code{myisamchk}
+weiß nicht, wo Ihre Datenbank liegt. In der Tat kümmert sich
+@code{myisamchk} nicht darum, ob die Dateien, die es bearbeiten soll, in
+einem Datenbank-Verzeichnis liegen oder nicht; sie können diese Dateien
+daher an eine andere Stelle kopieren und die Wiederherstellungsoperationen
+dort durchführen.
+
+Sie können in der @code{myisamchk}-Befehlszeile mehrere Tabellen angeben,
+wenn Sie wollen. Sie können auch einen Namen als Indexdateinamen angeben
+(mit dem Suffix @file{.MYI}), was Ihnen gestattet, alle Tabellen in einem
+Verzeichnis anzugeben, indem Sie das Muster @file{*.MYI} benutzen. Wenn Sie
+zum Beispiel in einem Datenbank-Verzeichnis sind, können Sie alle Tabellen
+im Verzeichnis wie folgt prüfen:
+
+@example
+shell> myisamchk *.MYI
+@end example
+
+Wenn Sie nicht im Datenbank-Verzeichnis sind, können Sie alle dortigen
+Tabellen prüfen, indem Sie den Pfad zum Verzeichnis angeben:
+
+@example
+shell> myisamchk /pfad/zum/datenbank_verzeichnis/*.MYI
+@end example
+
+Sie können sogar alle Tabellen in allen Datenbanken prüfen, indem Sie einen
+Platzhalter im Pfad zum MySQL-Daten-Verzeichnis angeben:
+
+@example
+shell> myisamchk /pfad/zum/datadir/*/*.MYI
+@end example
+
+Um schnell alle Tabellen zu prüfen, wird folgender Befehl empfohlen:
+
+@example
+myisamchk --silent --fast /pfad/zum/datadir/*/*.MYI
+isamchk --silent /pfad/zum/datadir/*/*.ISM
+@end example
+
+Wenn Sie alle Tabellen prüfen und alle Tabellen reparieren wollen, die
+beschädigt sind, können Sie folgende Kommandozeile eingeben:
+
+@example
+myisamchk --silent --force --fast --update-state -O key_buffer=64M -O sort_buffer=64M -O read_buffer=1M -O write_buffer=1M /pfad/zum/datadir/*/*.MYI
+isamchk --silent --force -O key_buffer=64M -O sort_buffer=64M -O read_buffer=1M -O write_buffer=1M /pfad/zum/datadir/*/*.ISM
+@end example
+
+Hierbei wird angenommen, dass Sie mehr als 64 MB Arbeitsspeicher frei
+haben.
+
+Wenn Sie einen Fehler wie den folgenden erhalten:
+
+@example
+myisamchk: warning: 1 clients is using oder hasn't closed the table properly
+@end example
+
+Bedeutet das, dass Sie versuchen, eine Tabelle zu überprüfen, die durch ein
+anderes Programm aktualisiert wurde (wie dem @code{mysqld}-Server), das die
+Datei noch nicht geschlossen hat oder das abgestürzt ist, ohne die Datei
+ordnungsgemäß zu schließen.
+
+Wenn @code{mysqld} läuft, müssen Sie ein Sync/Schließen aller Tabellen mit
+@code{FLUSH TABLES} erzwingen und sicherstellen, dass niemand die Tabellen
+benutzt, während Sie @code{myisamchk} laufen lassen. In MySQL-Version 3.23
+ist die einfachste Möglichkeit, dieses Problem zu vermeiden, die Benutzung
+von @code{CHECK TABLE} anstelle von @code{myisamchk}.
+
+
+
+@node myisamchk general options, myisamchk check options, myisamchk syntax, Table maintenance
+@c German node Allgemeine Optionen für myisamchk
+@subsubsection Allgemeine Optionen für @code{myisamchk}
+
+@cindex Optionen, @code{myisamchk}
+@cindex @code{myisamchk}, Optionen
+
+@code{myisamchk} unterstützt folgende Optionen:
+
+@table @code
+@item -# oder --debug=debug_optionen
+Ausgabe eines Debug-Logs. Die Zeichenkette @code{debug_optionen} ist häufig
+@code{'d:t:o,dateiname'}.
+@item -? oder --help
+Hilfetext ausgeben und beenden.
+@item -O var=option, --set-variable var=option
+Setzt den Wert einer Variablen. Mögliche Variablen und ihre Vorgabewerte
+für myisamchk können mit @code{myisamchk --help} herausgefunden werden:
+@multitable @columnfractions .3 .7
+@item key_buffer_size @tab 523264
+@item read_buffer_size @tab 262136
+@item write_buffer_size @tab 262136
+@item sort_buffer_size @tab 2097144
+@item sort_key_blocks @tab 16
+@item decode_bits @tab 9
+@end multitable
+
+@code{sort_buffer_size} wird benutzt, wenn Schlüssel repariert werden,
+indem Schlüssel sortiert werden, was der Normalfall ist, wenn Sie
+@code{--recover} benutzen.
+
+@code{key_buffer_size} wird benutzt, wenn Sie die Tabelle mit
+@code{--extended-check} prüfen oder wenn die Schlüssel repariert werden,
+indem Schlüssel Zeile für Zeile in die Tabelle eingefügt werden (als wenn
+normale Einfügeoperationen (Insert) durchgeführt werden). Eine Reparatur
+mittels Key-Buffer (Schlüsselpuffer) wird in folgenden Fällen benutzt:
+
+@itemize @bullet
+@item
+Wenn Sie @code{--safe-recover} benutzen.
+@item
+Wenn die temporären Dateien, die benötigt werden, um die Schlüssel zu
+sortieren, mehr als zweimal so Groß werden würden, als wenn die
+Schlüsseldatei direkt erzeugt würde. Das ist oft dann der Fall, wenn Sie
+große @code{CHAR}-, @code{VARCHAR}- oder @code{TEXT}-Schlüssel haben, weil
+das Sortieren die gesamten Schlüssel während des Sortierens speichern muss.
+Wenn Sie viel temporären Platz haben und @code{myisamchk} zwingen können,
+mittels Sortieren zu reparieren, können Sie die
+@code{--sort-recover}-Option benutzen.
+@end itemize
+
+Die Reparatur durch den Key-Buffer (Schlüsselpuffer) nimmt weit weniger
+Plattenplatz in Anspruch als wenn Sortieren benutzt wird, ist aber auch
+viel langsamer.
+
+Wenn Sie eine schnellere Reparatur wollen, setzen Sie die obigen Variablen
+auf ungefähr 1/4 Ihres verfügbaren Arbeitsspeichers. Sie können beide
+Variablen auf große Werte setzen, weil nur einer der oben aufgeführten
+Puffer zur gleichen Zeit benutzt wird.
+
+@item -s oder --silent
+Schweigsamer Modus. Ausgaben erfolgen nur im Fehlerfall. Sie können
+@code{-s} doppelt benutzen (@code{-ss}), um @code{myisamchk} sehr
+schweigsam zu machen.
+@item -v oder --verbose
+Geschwätziger Modus. Es werden mehr Informationen ausgegeben. Dies kann
+auch bei @code{-d} und @code{-e} benutzt werden. Benutzen Sie @code{-v}
+mehrfach (@code{-vv}, @code{-vvv}), um noch ausführlichere Meldungen
+auszugeben!
+@item -V oder --version
+Die aktuelle Version von @code{myisamchk} ausgeben und beenden.
+@item -w or, --wait
+Statt einen Fehler auszugeben, wenn die Tabelle gesperrt ist, warten, bis
+die Tabelle entsperrt ist, bevor fortgefahren wird. Beachten Sie: Wenn Sie
+@code{mysqld} auf der Tabelle mit @code{--skip-locking} laufen lassen, kann
+die Tabelle nur mit einem weiteren @code{myisamchk}-Befehl gesperrt werden.
+@end table
+
+
+@node myisamchk check options, myisamchk repair options, myisamchk general options, Table maintenance
+@c German node Prüfoptionen für myisamchk
+@subsubsection Prüfoptionen für @code{myisamchk}
+
+@cindex Prüfoptionen, myisamchk
+@cindex Tabellen, prüfen
+
+@table @code
+@item -c oder --check
+Tabelle auf Fehler überprüfen. Das ist die vorgabemäßige Operation, wenn
+Sie @code{myisamchk} keine sonstigen Optionen angeben, die dies
+überschreiben.
+
+@item -e oder --extend-check
+Tabelle SEHR gründlich prüfen (was recht langsam ist, wenn Sie viele Indexe
+haben). Diese Option sollte nur in Extremfällen benutzt werden.
+Normalerweise sollten @code{myisamchk} oder @code{myisamchk --medium-check}
+in fast allen Fällen in der Lage sein, herauszufinden, ob es in der Tabelle
+irgend welche Fehler gibt.
+
+Wenn Sie @code{--extended-check} benutzen und viel Arbeitsspeicher haben,
+setzen Sie den Wert von @code{key_buffer_size} um etliches herauf!
+
+@item -F oder --fast
+Nur Tabellen prüfen, die nicht ordnungsgemäß geschlossen wurden.
+@item -C oder --check-only-changed
+Nur Tabellen prüfen, die seit der letzten Prüfung geändert wurden.
+@item -f oder --force
+@code{myisamchk} mit @code{-r} (repair) auf die Tabelle neu starten, wenn
+@code{myisamchk} in der Tabelle irgend welche Fehler findet.
+@item -i oder --information
+Statistische Informationen über die Tabelle, die geprüft wird, ausgeben.
+@item -m oder --medium-check
+Schneller als extended-check, findet aber nur 99,99% aller Fehler. Das
+sollte allerdings in den meisten Fällen ausreichen.
+@item -U oder --update-state
+In der @file{.MYI}-Datei speichern, wann die Tabelle geprüft wurde und ob
+die Tabelle beschädigt wurde. Das sollte benutzt werden, um vollen Nutzen
+aus der @code{--check-only-changed}-Option ziehen zu können. Sie sollten
+diese Option nicht benutzen, wenn der @code{mysqld}-Server die Tabelle
+benutzt und Sie ihn mit @code{--skip-locking} laufen lassen.
+@item -T oder --read-only
+Die Tabelle nicht als geprüft kennzeichnen. Das ist hilfreich, wenn Sie
+@code{myisamchk} benutzen, um eine Tabelle zu prüfen, die von irgend einer
+anderen Applikation benutzt wird, die kein Sperren durchführt (wie
+@code{mysqld --skip-locking}).
+@end table
+
+
+@node myisamchk repair options, myisamchk other options, myisamchk check options, Table maintenance
+@c German node Reparaturoptionen für myisamchk
+@subsubsection Reparaturoptionen für @code{myisamchk}
+
+@cindex Reparaturoptionen, myisamchk
+@cindex Dateien, reparieren
+
+Folgende Optionen werden benutzt, wenn Sie @code{myisamchk} mit @code{-r}
+oder @code{-o} starten:
+
+@table @code
+@item -D # oder --data-file-length=#
+Maximale Länge der Daten-Datei (wenn die Daten-Datei neu erzeugt wird, wenn
+sie 'voll' ist).
+@item -e oder --extend-check
+Es wird versucht, jede mögliche Zeile der Daten-Datei wiederherzustellen.
+Normalerweise wird dies auch eine Menge Zeilen-'Müll' finden. Benutzen Sie
+diese Option nur dann, wenn Sie völlig verzweifelt sind.
+@item -f oder --force
+Alte temporäre Dateien (@code{tabelle.TMD}) werden überschrieben, anstatt
+abzubrechen.
+@item -k # oder keys-used=#
+Wenn Sie ISAM benutzen, weist das den ISAM-Tabellen-Handler an, nur die
+ersten @code{#}-Indexe zu benutzen. Wenn Sie @code{MyISAM} benutzen, sagt
+es dem Handler, welche Schlüssel benutzt werden sollen, wobei jedes
+Binärbit für einen Schlüssel steht (der erste Schlüssel ist Bit 0). Das
+kann benutzt werden, um schnelleres Einfügen (Insert) zu erreichen!
+Deaktivierte Indexe können reaktiviert werden, indem man @code{myisamchk
+-r} benutzt.
+@item -l oder --no-symlinks
+Symbolischen Links wird nicht gefolgt. Normalerweise repariert
+@code{myisamchk} die Tabelle, auf die ein Symlink verweist. Diese Option
+gibt es in MySQL 4.0 nicht, weil MySQL 4.0 während der Reparatur keine
+Symlinks entfernt.
+@item -r oder --recover
+Kann fast alles reparieren, ausser eindeutige Schlüssel, die nicht
+eindeutig sind (was ein extrem unwahrscheinlicher Fehler bei ISAM- /
+MyISAM-Tabellen ist). Wenn Sie eine Tabelle wiederherstellen wollen,
+sollten Sie zuerst diese Option ausprobieren. Nur wenn myisamchk berichtet,
+dass die Tabelle mit @code{-r} nicht wiederhergestellt werden kann, sollten
+Sie @code{-o} probieren. (Hinweis: Im unwahrscheinlichen Fall, dass
+@code{-r} fehlschlägt, ist die Daten-Datei immer noch intakt.) Wenn Sie
+viel Arbeitsspeicher haben, sollten Sie die Größe von
+@code{sort_buffer_size} herauf setzen!
+@item -o oder --safe-recover
+Benutzt eine alte Wiederherstellungsmethode (liest alle Zeilen der Reihe
+nach und aktualisiert alle Indexbäume, basierend auf den gefundenen
+Zeilen); das ist sehr viel langsamer als @code{-r}, kann aber eine Reihe
+sehr unwahrscheinlicher Fälle behandeln, die @code{-r} nicht behandeln
+kann. Diese Wiederherstellungsmethode benutzt viel weniger Plattenspeicher
+als @code{-r}. Normalerweise sollte man immer zuerst versuchen, mit
+@code{-r} zu reparieren und nur im Falle des Fehlschlagens @code{-o}
+benutzen.
+
+Wenn Sie viel Arbeitsspeicher haben, sollten Sie die Größe von
+@code{key_buffer_size} herauf setzen!
+@item -n oder --sort-recover
+Zwingt @code{myisamchk} zu sortieren, um Schlüssel aufzulösen, selbst wenn
+die temporären Dateien sehr Groß sein sollten. Diese Option hat keine
+Auswirkung, wenn Sie Volltextschlüssel in der Tabelle haben.
+
+@item --character-sets-dir=...
+Verzeichnis, wo Zeichensätze gespeichert sind.
+@item --set-character-set=name
+Ändert den Zeichensatz, der vom Index benutzt wird.
+@item -t oder --tmpdir=path
+Pfad zum Speichern temporärer Dateien. Wenn dieser nicht gesetzt ist,
+benutzt @code{myisamchk} hierfür die Umgebungsvariable @code{TMPDIR}.
+@item -q oder --quick
+Repariert schneller, indem die Daten-Datei nicht verändert wird. Man kann
+ein zweites @code{-q} angeben, um @code{myisamchk} zu zwingen, die
+Original-Daten-Datei zu ändern, falls doppelte Schlüssel auftreten.
+@item -u oder --unpack
+Datei entpacken, die mit myisampack gepackt wurde.
+@end table
+
+
+@node myisamchk other options, myisamchk memory, myisamchk repair options, Table maintenance
+@c German node Andere Optionen für myisamchk
+@subsubsection Weitere Optionen für @code{myisamchk}
+
+Weitere Aktionen, die @code{myisamchk} ausführen kann, neben der Prüfung
+und Reparatur von Tabellen:
+
+@table @code
+@item -a oder --analyze
+Analysiert die Verteilung von Schlüsseln. Das verbessert die Performance
+bei Tabellenverknüpfungen (Joins), indem der Join-Optimierer in die Lage
+versetzt wird, besser auszuwählen, in welcher Reihenfolge die Tabellen
+verknüpft werden sollten und welche Schlüssel er dabei verwenden sollte:
+@code{myisamchk --describe --verbose tabelle'} oder Benutzung von
+@code{SHOW KEYS} in MySQL.
+@item -d oder --description
+Gibt ein paar Informationen über die Tabelle aus.
+@item -A oder --set-auto-increment[=value]
+Zwingt auto_increment, mit diesem oder einem höheren Wert anzufangen. Wenn
+kein Wert angegeben wird, wird der nächste auto_increment-Wert auf den
+höchsten benutzten Wert für den auto-Schlüssel + 1 gesetzt.
+@item -S oder --sort-index
+Sortiert die Blöcke des Indexbaums in Hoch-Niedrig-Reihenfolge. Das
+optimiert Suchoperationen und macht das Durchsehen (Scanning) von Tabellen
+nach Schlüsseln schneller.
+@item -R oder --sort-records=#
+Sortiert Datensätze in Übereinstimmung mit einem Index. Das macht Ihre
+Daten viel konzentrierter und kann @code{SELECT} mit Bereichen und
+@code{ORDER BY}-Operationen auf diesem Index erheblich beschleunigen. (Beim
+ersten Sortieren kann das SEHR langsam sein!) Um die Anzahl von Indexen
+einer Tabelle herauszufinden, benutzen Sie @code{SHOW INDEX}, was die
+Indexe einer Tabelle in genau der Reihenfolge zeigt, in der
+@code{myisamchk} sie sieht. Indexe werden mit 1 beginnend nummeriert.
+@end table
+
+
+@node myisamchk memory, Crash recovery, myisamchk other options, Table maintenance
+@c German node Speicher bei myisamchk
+@subsubsection Speicherbenutzung von @code{myisamchk}
+
+@cindex memory usage, myisamchk
+
+Die Speicherzuordnung ist wichtig, wenn Sie @code{myisamchk} laufen lassen.
+@code{myisamchk} benutzt nicht mehr Speicher, als Sie mir der
+@code{-O}-Option festlegen. Wenn Sie @code{myisamchk} für sehr große
+Dateien benutzen wollen, sollten Sie zuerst entscheiden, wieviel Speicher
+Sie benutzen wollen. Die Vorgabe liegt bei nur etwa 3 MB, um Dinge zu
+reparieren. Indem größere Werte benutzt werden, können Sie
+@code{myisamchk} dazu bringen, schneller zu arbeiten. Wenn Sie
+beispielsweise 32 MB Arbeitsspeicher haben, könnten Sie Optionen wie die
+folgende benutzen (zusätzlich zu weiteren Optionen, die Sie eventuell
+angeben):
+
+@example
+shell> myisamchk -O sort=16M -O key=16M -O read=1M -O write=1M ...
+@end example
+
+@code{-O sort=16M} sollte für die meisten Fälle ausreichen.
+
+Denken Sie daran, dass @code{myisamchk} temporäre Dateien in @code{TMPDIR}
+benutzt. Wenn @code{TMPDIR} auf ein Speicher-Dateisystem zeigt, können
+Kein-Speicher-Fehler schnell auftreten. Wenn das passiert, setzen Sie
+@code{TMPDIR} so, dass es auf ein Verzeichnis mit mehr Speicherplatz zeigt
+und starten Sie @code{myisamchk} erneut.
+
+Beim Reparieren benötigt @code{myisamchk} große Mengen von
+Festplattenspeicher:
+
+@itemize @bullet
+@item
+Die doppelte Größe der Daten-Datei (die Originaldatei und eine Kopie).
+Dieser Platz wird nicht benötigt, wenn die Reparatur mit @code{--quick}
+durchgeführt wird, weil in diesem Fall nur die Index-Datei neu erzeugt
+wird. Der Platz wird auf derselben Festplatte benötigt, wo die
+Original-Daten-Datei liegt!
+@item
+Platz für die neue Index-Datei, die die alte ersetzt. Die alte Index-Datei
+wird beim Start beschnitten, daher kann man diesen Platz üblicherweise
+ignorieren. Der Platz wird auf derselben Platte benötigt, auf der die
+Original-Index-Datei liegt!
+@item
+Wenn Sie @code{--recover} oder @code{--sort-recover} benutzen (aber nicht,
+wenn Sie @code{--safe-recover} benutzen), brauchen Sie Platz für einen
+Sortierpuffer (Sort Buffer) für:
+@code{(größter_schlüssel + zeilen_zeiger_länge) * anzahl_der_zeilen * 2}.
+Sie können die Länge der Schlüssel und die Zeilen-Zeiger-Länger mit
+@code{myisamchk -dv tabelle} prüfen.
+Dieser Platz wird auf der temporären Platte zugeordnet (festgelegt durch
+@code{TMPDIR} oder @code{--tmpdir=#}).
+@end itemize
+
+Wenn Sie während der Reparatur ein Problem mit dem Plattenplatz bekommen,
+können Sie @code{--safe-recover} anstelle von @code{--recover}
+ausprobieren.
+
+
+@node Crash recovery, Check, myisamchk memory, Table maintenance
+@c German node Fehlerbeseitigung nach Abstürzen
+@subsubsection Benutzung von @code{myisamchk} für die Fehlerbeseitigung nach Abstürzen
+
+@cindex Absturz, Wiederherstellung
+@cindex Wiederherstellung, nach Absturz
+
+Wenn Sie @code{mysqld} mit @code{--skip-locking} laufen lassen (was auf
+einigen Systemen wie Linux die Vorgabe ist), können Sie @code{myisamchk}
+nicht zuverlässig dafür benutzen, eine Tabelle zu prüfen, wenn
+@code{mysqld} diese Tabelle benutzt. Wenn Sie sicher sein können, dass
+niemand auf die Tabellen mit @code{mysqld} zugreift, während Sie
+@code{myisamchk} laufen lassen, müssen Sie nur ein @code{mysqladmin
+flush-tables} durchführen, bevor Sie anfangen, die Tabellen zu prüfen. Wenn
+Sie das nicht garantieren können, müssen Sie @code{mysqld} herunter fahren,
+während Sie die Tabellen prüfen. Wenn Sie @code{myisamchk} laufen lassen,
+währen @code{mysqld} die Tabellen aktualisiert, erhalten Sie möglicherweise
+die Meldung, dass eine Tabelle beschädigt ist, selbst wenn sie es nicht
+ist.
+
+Wenn Sie @code{--skip-locking} nicht benutzen, können Sie jederzeit
+@code{myisamchk} benutzen, um Tabellen zu prüfen. Während Sie das tun,
+warten alle Clients, die versuchen, die Tabelle zu aktualisieren, bis
+@code{myisamchk} fertig ist, bevor sie weiter machen.
+
+Wenn Sie @code{myisamchk} benutzen, um Tabellen zu reparieren oder zu
+optimieren, @strong{MÜSSEN} Sie stets sicherstellen, dass der
+@code{mysqld}-Server die Tabelle nicht benutzt (das trifft auch zu, wenn
+Sie @code{--skip-locking} benutzen). Wenn Sie @code{mysqld} nicht herunter
+fahren, sollten Sie zumindest @code{mysqladmin flush-tables} ausführen,
+bevor Sie @code{myisamchk} benutzen.
+
+Dieses Kapitel beschreibt, wie man MySQL-Datenbanken auf Datenbeschädigung
+prüft und damit umgeht. Wenn Ihre Tabellen häufig beschädigt sind, wollten
+Sie versuchen, den Grund hierfür herauszufinden! @xref{Crashing}.
+
+Der Abschnitt über @code{MyISAM}-Tabellen enthält Gründe, warum eine
+Tabelle beschädigt sein könnte. @xref{MyISAM table problems}.
+
+Wenn Sie eine Wiederherstellung nach einem Absturz durchführen, ist es
+wichtig zu wissen, das jede Tabelle @code{tabelle} in einer Datenbank mit
+drei Dateien im Datenbank-Verzeichnis korrespondiert:
+
+@multitable @columnfractions .2 .8
+@item @strong{Datei} @tab @strong{Zweck}
+@item @file{tabelle.frm} @tab Tabellendefinitionsdatei (form)
+@item @file{tabelle.MYD} @tab Daten-Datei (data)
+@item @file{tabelle.MYI} @tab Index-Datei (index)
+@end multitable
+
+Jeder der drei Dateitypen kann auf verschiedene Weisen beschädigt werden.
+Probleme treten aber zumeist bei Daten-Dateien und Index-Dateien auf.
+
+@code{myisamchk} funktioniert so, dass Zeile für Zeile eine Kopie der
+@file{.MYD}-(data)-Datei gemacht wird. Es beendet die Reparaturphase damit,
+dass die alte @file{.MYD}-Datei entfernt wird und die neue Datei mit dem
+Orginal-Dateinamen benannt wird. Wenn Sie @code{--quick} benutzen, erzeugt
+@code{myisamchk} keine temporäre @file{.MYD}-Datei, sondern nimmt statt
+dessen an, dass die @file{.MYD}-Datei korrekt ist, und erzeugt nur eine
+neue Index-Datei, ohne die @file{.MYD}-Datei zu berühren. Das ist sicher,
+weil @code{myisamchk} automatisch feststellt, wenn die @file{.MYD}-Datei
+beschädigt ist, und die Reparatur in diesem Fall abbricht. Sie können
+@code{myisamchk} auch mit zwei @code{--quick}-Optionen aufrufen. In diesem
+Fall bricht @code{myisamchk} bei einigen Fehlern (wie doppelten
+Schlüsseleinträgen) nicht ab, sondern versucht statt dessen, diese
+aufzulösen, indem die @file{.MYD}-Datei verändert wird. Normalerweise ist
+die Benutzung von zwei @code{--quick}-Optionen nur sinnvoll, wenn Sie zu
+wenig frei Plattenplatz haben, um eine normale Reparatur durchzuführen. In
+diesem Fall sollten Sie zumindest eine Datensicherung machen, bevor Sie
+@code{myisamchk} laufen lassen.
+
+
+@node Check, Repair, Crash recovery, Table maintenance
+@c German node Prüfung
+@subsubsection Wie Tabellen auf Fehler überprüft werden
+
+@cindex Prüfen, Tabellen auf Fehler
+@cindex Tabellen, Fehlerprüfung
+@cindex Fehler, Tabellen prüfen auf
+
+Um eine MyISAM-Tabelle zu prüfen, benutzen Sie folgende Befehle:
+
+@table @code
+@item myisamchk tabelle
+Das findet 99.99% aller Fehler. Nicht gefunden werden Beschädigungen, die
+@strong{NUR} die Daten-Datei betreffen (was sehr ungewöhnlich ist). Wenn
+Sie eine Tabelle prüfen wollen, sollten Sie @code{myisamchk} normalerweise
+ohne Optionen oder entweder mit der @code{-s}- oder @code{--silent}-Option
+laufen lassen.
+
+@item myisamchk -m tabelle
+Das findet 99.999% aller Fehler. Zuerst prüft es alle Indexeinträge auf
+Fehler und liest dann alle Zeilen durch. Es berechnet eine Prüfsumme für
+alle Schlüssel in den Zeilen und bestätigt dann, dass die Prüfsumme mit der
+Prüfsumme für die Schlüssel im Indexbaum übereinstimmt.
+
+@item myisamchk -e tabelle
+Das führt eine vollständige, gründlich Prüfung aller Daten durch (@code{-e}
+bedeutet ``extended check'' - erweiterte Prüfung). Es führt ein Prüf-Lesen
+jedes Schlüssels für jede Zeile durch, um zu bestätigen, dass sie
+tatsächlich auf die richtige Zeile verweisen. Das kann bei einer großen
+Tabelle mit vielen Schlüsseln SEHR LANG dauern. @code{myisamchk} hält
+normalerweise an, wenn es den ersten Fehler gefunden hat. Wenn Sie mehr
+Informationen haben wollen, können Sie die
+@code{--verbose}-(@code{-v})-Option benutzen. Das veranlasst
+@code{myisamchk}, weiterzumachen, bis maximal 20 Fehler gefunden wurden.
+Bei normalem Gebrauch ist ein einfaches @code{myisamchk} (ohne weitere
+Argumente ausser dem Tabellennamen) ausreichend.
+
+@item myisamchk -e -i tabelle
+Wie der vorherige Befehl, jedoch weist die @code{-i}-Option
+@code{myisamchk} an, zusätzlich einige statistische Informationen
+auszugeben.
+@end table
+
+
+@node Repair, Optimisation, Check, Table maintenance
+@c German node Reparatur
+@subsubsection Wie Tabellen repariert werden
+
+@cindex Tabellen, Reparatur
+@cindex Reparatur, Tabellen
+
+Der folgende Abschnitt behandelt nur die Benutzung von @code{myisamchk} mit
+@code{MyISAM}-Tabellen (Erweiterungen @code{.MYI} und @code{.MYD}). Wenn
+Sie @code{ISAM}-Tabellen benutzen (Erweiterungen @code{.ISM} und
+@code{.ISD}), sollten Sie statt dessen @code{isamchk} benutzen.
+
+Ab MySQL-Version 3.23.14 können Sie MyISAM-Tabellen mit dem
+@code{REPAIR TABLE}-Befehl reparieren. @xref{REPAIR TABLE}.
+
+Zu den Symptomen einer beschädigten Tabelle gehören Anfragen, die
+unerwartet abbrechen, und beobachtbare Fehler wie folgender:
+
+@itemize @bullet
+@item
+@file{tabelle.frm} is locked against change
+@item
+Can't find file @file{tabelle.MYI} (Errcode: ###)
+@item
+Unexpected end of file
+@item
+Record file is crashed
+@item
+Got error ### from table handler
+
+Um mehr Information über den Fehler zu erhalten, lassen Sie @code{perror
+###} laufen. Hier sind die häufigsten Fehler, die auf ein Problem mit der
+Tabelle hinweisen:
+
+@example
+shell> perror 126 127 132 134 135 136 141 144 145
+126 = Index-Datei ist beschädigt / falsches Dateiformat
+127 = Daten-Datei ist beschädigt
+132 = Alte Datenbank-Datei
+134 = Datensatz wurde bereits gelöscht (oder Daten-Datei beschädigt)
+135 = Kein Platz mehr in der Daten-Datei
+136 = Kein Platz mehr in der Index-Datei
+141 = Doppelter Eintrag für eindeutigen Schlüssel oder Beschränkung beim Schreiben oder Aktualisiern
+144 = Tabelle ist beschädigt und die letzte Reparatur ist fehlgeschlagen
+145 = Tabelle ist als beschädigt gekennzeichnet und sollte repariert werden
+@end example
+
+Beachten Sie, dass Fehler 135 (kein Platz mehr in der Daten-Datei) kein
+Fehler ist, der durch eine einfache Reparatur behoben werden kann. In
+diesem Fall müssen Sie folgendes durchführen:
+
+@example
+ALTER TABLE tabelle MAX_ROWS=xxx AVG_ROW_LENGTH=yyy;
+@end example
+
+@end itemize
+
+In den anderen Fällen müssen Sie Ihre Tabellen reparieren. @code{myisamchk}
+kann üblicherweise die meisten Dinge, die schief gehen können, finden und
+beheben.
+
+Der Reparaturprozess läuft in vier Phasen ab, die unten beschrieben sind.
+Bevor Sie anfangen, sollten Sie in das Datenbank-Verzeichnis wechseln und
+die Berechtigungen der Tabellen-Dateien prüfen. Stellen Sie sicher, dass
+diese durch den Unix-Benutzer lesbar sind, unter dem @code{mysqld} läuft
+(und für Sie, weil Sie auf die Dateien zugreifen müssen, wenn Sie sie
+prüfen). Wenn Sie in der Folge Dateien verändern müssen, müssen diese für
+Sie auch schreibbar sein.
+
+Wenn Sie MySQL-Version 3.23.16 und höher benutzen, können (und sollten) Sie
+die @code{CHECK}- und @code{REPAIR}-Befehle benutzen, um
+@code{MyISAM}-Tabellen zu prüfen und zu reparieren. @xref{REPAIR TABLE}.
+
+Der Handbuchabschnitt über Tabellenwartung beinhaltet die Optionen für
+@code{isamchk} / @code{myisamchk}. @xref{Table maintenance}.
+
+Der folgende Abschnitt ist für Fälle, in denen die obigen Befehle
+fehlschlagen, oder wenn Sie die erweiterten Features benutzen wollen, die
+@code{isamchk} / @code{myisamchk} zur Verfügung stellt.
+
+Wenn Sie eine Tabelle von der Kommandozeile aus reparieren wollen, müssen
+Sie zuerst den @code{mysqld}-Server herunter fahren. Beachten Sie bei
+@code{mysqladmin shutdown} auf einen entfernten Server, dass der
+@code{mysqld}-Server noch für eine Weile aktiv bleibt, nachdem
+@code{mysqladmin} beendet ist, bis alle Anfragen beendet und alle Schlüssel
+auf Platte zurück geschrieben (flush) wurden.
+
+@noindent
+@strong{Phase 1: Prüfen Ihrer Tabellen}
+
+Lassen Sie @code{myisamchk *.MYI} laufen, oder @code{myisamchk -e *.MYI},
+wenn Sie mehr Zeit haben. Benutzen Sie die @code{-s}-(silent)-Option, um
+unnötige Informationen zu unterdrücken.
+
+Wenn der @code{mysqld}-Server herunter gefahren ist, sollten Sie die
+@code{--update}-Option benutzen, um @code{myisamchk} zu veranlassen, die
+Tabelle als 'geprüft' zu kennzeichnen.
+
+Sie müssen nur die Tabellen reparieren, bei denen @code{myisamchk} bekannt
+gibt, dass sie Fehler enthalten. Gehen Sie bei solchen Tabellen zu Phase 2
+über.
+
+Wenn Sie beim Prüfen merkwürdige Fehler erhalten (wie @code{out of
+memory}-Fehler), oder wenn @code{myisamchk} abstürzt, gehen Sie zu Phase
+3.
+
+@noindent
+@strong{Phase 2: Einfache, sichere Reparatur}
+
+HINWEIS: Wenn Sie wollen, dass die Reparatur sehr viel schneller abläuft,
+sollten Sie allen @code{isamchk/myisamchk}-Befehlen folgendes hinzufügen:
+@code{-O sort_buffer=# -O key_buffer=#} (wobei # etwa 1/4 des verfügbaren
+Arbeitsspeichers ist).
+
+Probieren Sie zuerst @code{myisamchk -r -q tabelle} (@code{-r -q} bedeutet
+``quick recovery mode'' - schnelles Wiederherstellen). Dies versucht, die
+Index-Datei zu reparieren, ohne die Daten-Datei zu berühren. Wenn die
+Daten-Datei alles enthält, was sie sollte, und die Löschverknüpfungen auf
+die korrekten Stellen in der Daten-Datei zeigen, sollte das funktionieren
+und die Tabelle ist repariert. Machen Sie dann mit der Reparatur der
+nächsten Tabelle weiter. Ansonsten führen Sie folgende Prozedur durch:
+
+@enumerate
+@item
+Machen Sie eine Datensicherung der Daten-Datei, bevor Sie fortfahren.
+
+@item
+Geben Sie @code{myisamchk -r tabelle} (@code{-r} bedeutet ``recovery mode''
+- Wiederherstellung) ein. Das entfernt falsche und gelöschte Datensätze aus
+der Daten-Datei und stellt die Index-Datei wieder her.
+
+@item
+Wenn die vorherigen Schritte fehlschlagen, geben Sie @code{myisamchk
+--safe-recover tabelle} ein. Der Modus für sicheres Wiederherstellen
+benutzt eine alte Wiederherstellungsmethode, die ein paar Fälle behandelt,
+die der normale Wiederherstellungsmodus nicht behandelt (ist aber
+langsamer).
+@end enumerate
+
+Wenn Sie bei der Reparatur merkwürdige Fehler erhalten (wie @code{out of
+memory}-Fehler), oder wenn @code{myisamchk} abstürzt, gehen Sie zu Phase
+3.
+
+@noindent
+@strong{Phase 3: Schwierige Reparatur}
+
+Diese Phase sollten Sie nur dann erreichen, wenn der erste 16-KB-Block der
+Index-Datei zerstört ist oder falsche Informationen enthält, oder wenn die
+Index-Datei fehlt. In diesem Fall ist es notwendig, eine neue Index-Datei
+zu erzeugen. Das machen Sie wie folgt:
+
+@enumerate
+@item
+Verschieben Sie die Daten-Datei an einen sicheren Ort.
+
+@item
+Benutzen Sie die Tabellen-Beschreibungsdatei, um eine neue (leere)
+Daten-Datei und Index-Dateien zu erzeugen:
+
+@example
+shell> mysql datenbank
+mysql> SET AUTOCOMMIT=1;
+mysql> TRUNCATE TABLE tabelle;
+mysql> quit
+@end example
+
+Wenn Ihre SQL-Version kein @code{TRUNCATE TABLE} hat, benutzen Sie statt
+dessen @code{DELETE FROM tabelle}.
+
+@item
+Kopieren Sie Ihre alte Daten-Datei zurück, über die neu erzeugte
+Daten-Datei. (Verschieben Sie Ihre alte Daten-Datei nicht einfach, damit
+Sie eine Kopie erhalten, falls etwas schief geht.)
+@end enumerate
+
+Gehen Sie zurück zu Phase 2. @code{myisamchk -r -q} sollte jetzt
+funktionieren. (Das sollte keine Endlosschleife sein.)
+
+@noindent
+@strong{Phase 4: Sehr schwierige Reparatur}
+
+Diese Phase sollten Sie nur dann erreichen, wenn auch die
+Beschreibungsdatei beschädigt ist. Das sollte nie passieren, weil die
+Beschreibungsdatei nicht verändert wird, nachdem die Tabelle erzeugt wurde:
+
+@enumerate
+@item
+Stellen Sie die Beschreibungsdatei von einer Datensicherung wieder her und
+gehen Sie zurück zu Phase 3. Sie können auch die Index-Datei
+wiederherstellen und zu Phase 2 zurück gehen. Im letzteren Fall sollten
+Sie mit @code{myisamchk -r} anfangen.
+
+@item
+Wenn Sie keine Datensicherung haben, aber genau wissen, wie die Tabelle
+erzeugt wurde, erzeugen Sie eine Kopie der Tabelle in einer anderen
+Datenbank. Entfernen Sie die neue Daten-Datei und verschieben Sie die
+Beschreibungs- und Index-Dateien von der anderen Datenbank in Ihre
+beschädigte Datenbank. Das ergibt neue Beschreibungs- und Index-Dateien,
+läßt aber die Daten-Datei in Ruhe. Gehen Sie zurück zu Phase 2 und
+versuchen Sie, die Index-Datei wiederherzustellen.
+@end enumerate
+
+
+@node Optimisation, , Repair, Table maintenance
+@c German node Optimierung
+@subsubsection Tabellenoptimierung
+
+@cindex Tabellen, Optimierung
+@cindex Optimierung, Tabellen
+
+Um fragmentierte Datensätze zu vereinigen und verschwendeten Speicherplatz
+zu beseitigen, der sich durch Löschen und Aktualisieren von Datensätzen
+ergibt, lassen Sie @code{myisamchk} im Wiederherstellungsmodus laufen:
+
+@example
+shell> myisamchk -r tabelle
+@end example
+
+Auf dieselbe Weise können Sie eine Tabelle optimieren, indem Sie das
+SQL-Statement @code{OPTIMIZE TABLE} benutzen. @code{OPTIMIZE TABLE} führt
+eine Reparatur der Tabelle und eine Analyse der Schlüssel durch und
+sortiert den Indexbaum, um schnelleres Nachschlagen der Schlüssel (Key
+Lookup) zu ermöglichen. Ausserdem schaltet es die Möglichkeit ungewollter
+Interaktionen zwischen einem Dienstprogramm und dem Server aus, weil der Server
+bei der Benutzung von @code{OPTIMIZE TABLE} die ganze Arbeit verrichtet.
+@xref{OPTIMIZE TABLE}.
+
+@code{myisamchk} hat eine Anzahl weiterer Optionen, die Sie für die
+Verbesserung der Performance einer Tabelle benutzen können:
+
+@table @code
+@item -S, --sort-index
+@item -R index_nummer, --sort-records=index_nummer
+@item -a, --analyze
+@end table
+
+Eine detaillierte Beschreibung der Optionen steht unter
+@xref{myisamchk syntax}.
+
+
+@node Maintenance regimen, Table-info, Table maintenance, Disaster Prevention
+@c German node Wartungsplan
+@subsection Wartungsplan für Tabellen erstellen
+
+@cindex Wartung, Tabellen
+@cindex Tabellen, Wartungsplan
+
+Ab MySQL-Version 3.23.13 können Sie MyISAM-Tabellen mit dem @code{CHECK
+TABLE}-Befehl prüfen. @xref{CHECK TABLE}. Sie können Tabellen mit dem
+@code{REPAIR TABLE}-Befehl reparieren. @xref{REPAIR TABLE}.
+
+Es ist eine gute Idee, Tabellenüberprüfungen auf regelmäßiger Basis
+durchzuführen statt darauf zu warten, dass Probleme auftreten. Für
+Wartungszwecke benutzen Sie @code{myisamchk -s}, um Tabellen zu überprüfen.
+Die @code{-s}-Option (Kurzform für @code{--silent}) veranlasst
+@code{myisamchk}, im schweigsamen Modus zu laufen, wobei Meldungen nur
+ausgegeben werden, wenn Fehler auftreten.
+
+@tindex .pid-(process ID)-Datei
+Ebenfalls eine gute Idee ist es, Tabellen zu überprüfen, wenn der Server
+hoch fährt. Wenn beispielsweise die Maschine mitten während einer
+Aktualisierung (Update) neu gebootet hat, müssen Sie üblicherweise alle
+Tabellen prüfen, die betroffen sein könnten. (Das ist ein Fall von
+``erwarteter Tabellenbeschädigung''.) Sie können @code{safe_mysqld} einen
+Test hinzufügen, der @code{myisamchk} laufen läßt, um alle Tabellen zu
+überprüfen, die innerhalb der letzten 24 Stunden geändert wurden, wenn nach
+einem Reboot eine alte @file{.pid}-(process ID)-Datei übrig blieb. (Die
+@file{.pid}-Datei wird von @code{mysqld} erzeugt, wenn er hoch fährt, und
+entfernt, wenn er normal beendet wird. Die Anwesenheit einer
+@file{.pid}-Datei beim Systemstart zeigt an, dass @code{mysqld} regelwidrig
+abgebrochen wurde.)
+
+Eine noch bessere Testmethode besteht darin, jede Tabelle zu prüfen, deren
+Zeit der letzten Änderung neuer ist als die der @file{.pid}-Datei.
+
+Ausserdem sollten Sie Ihre Tabellen regelmäßig während der normalen
+Systemtätigkeit prüfen. Bei MySQL AB lassen wir einen @code{cron}-Job
+laufen, um alle wichtigen Tabellen einmal pro Woche zu prüfen, indem wir
+folgende Zeile in der @file{crontab}-Datei benutzen:
+
+@example
+35 0 * * 0 /pfad/zu/myisamchk --fast --silent /pfad/zu/datadir/*/*.MYI
+@end example
+
+Das gibt Informationen über beschädigte Tabellen aus, so dass wir diese
+prüfen und reparieren können, falls notwendig.
+
+Da wir mittlerweile seit einigen Jahren keinerlei unerwartet beschädigte
+Tabellen hatten (Tabellen, die aus anderen Gründen als Hardware-Schäden
+beschädigt wurden), reicht uns einmal pro Woche völlig aus.
+
+Wir empfehlen, dass Sie jede Nacht @code{myisamchk -s} auf alle Tabellen
+ausführen, die während der letzten 24 Stunden aktualisiert wurden, bis Sie
+MySQL so sehr vertrauen, wie wir selbst das mittlerweile tun.
+
+@cindex Tabellen, defragmentieren
+Normalerweise brauchen Sie MySQL-Tabellen nicht so sehr warten. Wenn Sie
+Tabellen mit Zeilen dynamischer Länge ändern (Tabellen mit
+@code{VARCHAR}-, @code{BLOB}- oder @code{TEXT}-Spalten) oder Tabellen mit
+vielen gelöschten Zeilen haben, werden Sie diese von Zeit zu Zeit (einmal
+im Monat?) defragmentieren wollen bzw. freien Speicherplatz schaffen.
+
+Das können Sie mit @code{OPTIMIZE TABLE} auf die in Frage kommenden
+Tabellen tun, oder, wenn Sie den @code{mysqld}-Server für eine Weile
+herunter fahren können:
+
+@example
+isamchk -r --silent --sort-index -O sort_buffer_size=16M */*.ISM
+myisamchk -r --silent --sort-index -O sort_buffer_size=16M */*.MYI
+@end example
+
+
+@node Table-info, , Maintenance regimen, Disaster Prevention
+@c German node Tabelleninformation
+@subsection Informationen über eine Tabelle erhalten
+
+@cindex Tabellen, Informationen
+
+Um eine Beschreibung einer Tabelle oder Statistiken über sie zu erhalten,
+benutzen Sie die unten stehenden Befehle. Einige davon werden später
+detaillierter erläutert:
+
+@table @code
+@item myisamchk -d tabelle
+Läßt @code{myisamchk} im ``Beschreibungsmodus'' laufen, um eine
+Beschreibung Ihrer Tabelle zu erzeugen. Wenn Sie den MySQL-Server mit der
+@code{--skip-locking}-Option starten, kann @code{myisamchk} eventuell
+Fehler über eine Tabelle berichten, die aktualisiert wird, während es
+läuft. Weil @code{myisamchk} jedoch im Beschreibungsmodus keine Tabelle
+ändert, gibt es kein Risiko, dass Daten zerstört werden.
+
+@item myisamchk -d -v tabelle
+Um mehr Informationen über das, was @code{myisamchk} tut, zu erzeugen,
+fügen Sie @code{-v} als Option hinzu, damit es im geschwätzigen Modus
+läuft.
+
+@item myisamchk -eis tabelle
+Zeigt nur die wichtigsten Informationen über die Tabelle. Das ist langsam,
+weil es die ganze Tabelle lesen muss.
+
+@item myisamchk -eiv tabelle
+Wie @code{-eis}, sagt aber zusätzlich, was getan werden muss.
+@end table
+
+@cindex Beispiele, @code{myisamchk}-Ausgabe
+@cindex @code{myisamchk}, Beispiele der Ausgabe
+Beispiel einer @code{myisamchk -d}-Ausgabe:
+@example
+MyISAM file: firma.MYI
+Record format: Fixed length
+Data records: 1403698 Deleted blocks: 0
+Recordlength: 226
+
+table description:
+Key Start Len Index Type
+1 2 8 unique double
+2 15 10 multip. text packed stripped
+3 219 8 multip. double
+4 63 10 multip. text packed stripped
+5 167 2 multip. unsigned short
+6 177 4 multip. unsigned long
+7 155 4 multip. text
+8 138 4 multip. unsigned long
+9 177 4 multip. unsigned long
+ 193 1 text
+@end example
+
+Beispiel einer @code{myisamchk -d -v}-Ausgabe:
+@example
+MyISAM file: firma
+Record format: Fixed length
+File-version: 1
+Creation time: 1999-10-30 12:12:51
+Recover time: 1999-10-31 19:13:01
+Status: checked
+Data records: 1403698 Deleted blocks: 0
+Datafile parts: 1403698 Deleted data: 0
+Datafilepointer (bytes): 3 Keyfile pointer (bytes): 3
+Max datafile length: 3791650815 Max keyfile length: 4294967294
+Recordlength: 226
+
+table description:
+Key Start Len Index Type Rec/key Root Blocksize
+1 2 8 unique double 1 15845376 1024
+2 15 10 multip. text packed stripped 2 25062400 1024
+3 219 8 multip. double 73 40907776 1024
+4 63 10 multip. text packed stripped 5 48097280 1024
+5 167 2 multip. unsigned short 4840 55200768 1024
+6 177 4 multip. unsigned long 1346 65145856 1024
+7 155 4 multip. text 4995 75090944 1024
+8 138 4 multip. unsigned long 87 85036032 1024
+9 177 4 multip. unsigned long 178 96481280 1024
+ 193 1 text
+@end example
+
+Beispiel einer @code{myisamchk -eis}-Ausgabe:
+@example
+Checking MyISAMDatei: firma
+Key: 1: Keyblocks used: 97% Packed: 0% Max levels: 4
+Key: 2: Keyblocks used: 98% Packed: 50% Max levels: 4
+Key: 3: Keyblocks used: 97% Packed: 0% Max levels: 4
+Key: 4: Keyblocks used: 99% Packed: 60% Max levels: 3
+Key: 5: Keyblocks used: 99% Packed: 0% Max levels: 3
+Key: 6: Keyblocks used: 99% Packed: 0% Max levels: 3
+Key: 7: Keyblocks used: 99% Packed: 0% Max levels: 3
+Key: 8: Keyblocks used: 99% Packed: 0% Max levels: 3
+Key: 9: Keyblocks used: 98% Packed: 0% Max levels: 4
+Total: Keyblocks used: 98% Packed: 17%
+
+Records: 1403698 M.recordlength: 226 Packed: 0%
+Recordspace used: 100% Empty space: 0% Blocks/Record: 1.00
+Record blocks: 1403698 Delete blocks: 0
+Recorddata: 317235748 Deleted data: 0
+Lost space: 0 Linkdata: 0
+
+User time 1626.51, System time 232.36
+Maximum resident set size 0, Integral resident set size 0
+Non physical pagefaults 0, Physical pagefaults 627, Swaps 0
+Blocks in 0 out 0, Messages in 0 out 0, Signals 0
+Voluntary context switches 639, Involuntary context switches 28966
+@end example
+
+Beispiel einer @code{myisamchk -eiv}-Ausgabe:
+@example
+Checking MyISAM file: firma
+Data records: 1403698 Deleted blocks: 0
+- check file-size
+- check delete-chain
+block_size 1024:
+index 1:
+index 2:
+index 3:
+index 4:
+index 5:
+index 6:
+index 7:
+index 8:
+index 9:
+No recordlinks
+- check index reference
+- check data record references index: 1
+Key: 1: Keyblocks used: 97% Packed: 0% Max levels: 4
+- check data record references index: 2
+Key: 2: Keyblocks used: 98% Packed: 50% Max levels: 4
+- check data record references index: 3
+Key: 3: Keyblocks used: 97% Packed: 0% Max levels: 4
+- check data record references index: 4
+Key: 4: Keyblocks used: 99% Packed: 60% Max levels: 3
+- check data record references index: 5
+Key: 5: Keyblocks used: 99% Packed: 0% Max levels: 3
+- check data record references index: 6
+Key: 6: Keyblocks used: 99% Packed: 0% Max levels: 3
+- check data record references index: 7
+Key: 7: Keyblocks used: 99% Packed: 0% Max levels: 3
+- check data record references index: 8
+Key: 8: Keyblocks used: 99% Packed: 0% Max levels: 3
+- check data record references index: 9
+Key: 9: Keyblocks used: 98% Packed: 0% Max levels: 4
+Total: Keyblocks used: 9% Packed: 17%
+
+- check records und index references
+[LOTS OF ROW NUMBERS DELETED]
+
+Records: 1403698 M.recordlength: 226 Packed: 0%
+Recordspace used: 100% Empty space: 0% Blocks/Record: 1.00
+Record blocks: 1403698 Delete blocks: 0
+Recorddata: 317235748 Deleted data: 0
+Lost space: 0 Linkdata: 0
+
+User time 1639.63, System time 251.61
+Maximum resident set size 0, Integral resident set size 0
+Non physical pagefaults 0, Physical pagefaults 10580, Swaps 0
+Blocks in 4 out 0, Messages in 0 out 0, Signals 0
+Voluntary context switches 10604, Involuntary context switches 122798
+@end example
+
+Hier stehen die Größen der Daten- und Index-Dateien der Tabelle, die in
+den vorstehenden Beispielen benutzt wurde:
+
+@example
+-rw-rw-r-- 1 monty tcx 317235748 Jan 12 17:30 firma.MYD
+-rw-rw-r-- 1 davida tcx 96482304 Jan 12 18:35 firma.MYM
+@end example
+
+Erläuterungen der Informationen, die @code{myisamchk} erzeugt, werden unten
+gegeben. ``keyfile'' ist die Index-Datei. ``Record'' und ``row'' sind
+Synonyme:
+
+@table @code
+@item ISAM file
+Name der ISAM-(Index)-Datei.
+
+@item Isam-version
+Version des ISAM-Formats. Momentan immer 2.
+
+@item Creation time
+Wann die Daten-Datei erzeugt wurde.
+
+@item Recover time
+Wann die Index-/Daten-Datei das letzte Mal rekonstruiert wurden.
+
+@item Data records
+Wie viele Datensätze in der Tabelle sind.
+
+@item Deleted blocks
+Wie viele gelöschte Blöcke noch Platz belegen.
+Sie können Ihre Tabelle optimieren, um diesen Platz zu minimieren.
+@xref{Optimisation}.
+
+@item Datafile: Parts
+Bei dynamischem Datensatzformat zeigt dies an, wie viele Datenblöcke es
+gibt. Bei einer optimierten Tabelle ohne fragmentierte Datensätze ist das
+dasselbe wie @code{Data records}.
+
+@item Deleted data
+Wie viele Bytes nicht zurückgewonnener gelöschter Daten es gibt.
+Sie können Ihre Tabelle optimieren, um diesen Platz zu minimieren.
+@xref{Optimisation}.
+
+@item Datafile pointer
+Die Größe des Daten-Datei-Zeigers in Bytes. Das sind normalerweise 2, 3, 4
+oder 5 Bytes. Die meisten Tabellen schaffen 2 Bytes, aber das kann bislang
+von MySQL noch nicht gesteuert werden. Bei festen Tabellen ist das eine
+Datensatzadresse. Bei dynamischen Tabellen ist es eine Byte-Adresse.
+
+@item Keyfile pointer
+Die Größe des Index-Datei-Zeigers in Bytes. Sie beträgt normalerweise 1, 2
+oder 3 Bytes. Die meisten Tabellen schaffen 2 Bytes, aber das wird von
+MySQL automatisch berechnet. Es ist immer die Block-Adresse.
+
+@item Max datafile length
+Wie lang die Daten-Datei (@code{.MYD}-Datei) der Tabelle werden kann, in
+Bytes.
+
+@item Max keyfile length
+Wie lang die Index-Datei (@code{.MYI}-Datei) der Tabelle werden kann, in
+Bytes.
+
+@item Recordlength
+Wie viel Platz jeder Datensatz benötigt, in Bytes.
+
+@item Record format
+Das Format, das benutzt wird, um Tabellenzeilen zu speichern.
+Die oben stehenden Beispiele benutzen @code{Fixed length}.
+Andere mögliche Werte sind @code{Compressed} und @code{Packed}.
+
+@item Table description
+Eine Liste aller Schlüssel in der Tabelle. Für jeden Schlüssel werden
+einige Low-Level-Informationen angezeigt:
+
+@table @code
+@item Key
+Die Nummer des Schlüssels.
+
+@item Start
+Wo im Datensatz dieser Index-Teil anfängt.
+
+@item Len
+Wie lang dieser Index-Teil ist. Bei gepackten Zahlen sollte das immer die
+gesamte Länge der Spalte sein. Bei Zeichenketten kann es kürzer als die
+gesamte Länge der indizierten Spalte sein, weil Sie ein Prefix einer
+Zeichenkettenspalte indexieren können.
+
+@item Index
+@code{unique} oder @code{multip.} (multiple). Zeigt an, ob ein Wert einmal
+oder mehrfach in diesem Index vorkommen darf.
+
+@item Type
+Welchen Datentyp dieser Index-Teil hat. Das ist ein ISAM-Datentyp mit den
+Optionen @code{packed}, @code{stripped} oder @code{empty}.
+
+@item Root
+Adresse des Root-Index-Blocks.
+
+@item Blocksize
+Die Größe jedes Index-Blocks. Vorgabemäßig ist das 1024, doch dieser Wert
+kann beim Kompilieren geändert werden.
+
+@item Rec/key
+Das ist ein statistischer Wert, der vom Optimierer benutzt wird. Es sagt
+aus, wie viele Datensätze es pro Wert für diesen Schlüssel gibt. Ein
+eindeutiger Schlüssel hat immer einen Wert von 1. Das kann aktualisiert
+werden, nachdem eine Tabelle geladen wurde (oder in größerem Umfang
+geändert) mit @code{myisamchk -a}. Wenn dies überhaupt nicht aktualisiert
+wurde, wird ein Wert von 30 angenommen.
+@end table
+
+@item
+Im ersten Beispiel oben ist der neunte Schlüssel ein mehrteiliger Schlüssel
+mit zwei Teilen.
+
+@item Keyblocks used
+Welcher Prozentsatz von Schlüsselblöcken benutzt wird. Weil die Tabellen,
+die in den Beispielen benutzt wurden, direkt vorher mit @code{myisamchk}
+reorganisiert wurden, sind diese Werte sehr hoch (sehr nahe am
+theoretischen Maximum).
+
+@item Packed
+MySQL versucht, Schlüssel mit einem gemeinsamen Suffix zu packen. Das geht
+nur bei @code{CHAR}-, @code{VARCHAR} und @code{DECIMAL}-Schlüsseln. Bei
+langen Zeichenketten wie Namen kann das den benutzten Platz signifikant
+verringern. Im dritten Beispiel oben ist der vierte Schlüssel zehn Zeichen
+lang, wodurch ein 60%-ige Verringerung des Platzbedarfs erreicht wird.
+
+@item Max levels
+Wie tief der B-Baum für diesen Schlüssel ist. große Tabellen mit langen
+Schlüsseln haben hohe Werte.
+
+@item Records
+Wie viele Zeilen in der Tabelle enthalten sind.
+
+@item M.recordlength
+Die durchschnittliche Datensatzlänge. Bei Tabellen mit Datensätzen fester
+Länge ist das die exakte Datensatzlänge.
+
+@item Packed
+MySQL schneidet Leerzeichen am Ende von Zeichenketten ab. Der
+@code{Packed}-Wert zeigt an, welcher Prozentsatz dadurch gespart wurde.
+
+@item Recordspace used
+Welcher Prozentsatz der Daten-Datei benutzt wird.
+
+@item Empty space
+Welcher Prozentsatz der Daten-Datei unbenutzt ist.
+
+@item Blocks/Record
+Durchschnittliche Anzahl der Blöcke pro Datensatz (das heißt, aus wie
+vielen Verknüpfungen (Links) ein fragmentierter Datensatz zusammengesetzt
+ist). Bei Tabellen mit festem Format ist das immer 1. Dieser Wert sollte so
+nah wie möglich an 1,0 bleiben. Wenn er zu Groß wird, können Sie die
+Tabelle @code{myisamchk} reorganisieren.
+@xref{Optimisation}.
+
+@item Recordblocks
+Wie viele Blöcke (Verknüpfungen, Links) benutzt werden. Bei festem Format
+ist das die Anzahl der Datensätze.
+
+@item Deleteblocks
+Wie viele Blöcke (Verknüpfungen, Links) gelöscht sind.
+
+@item Recorddata
+Wie viele Bytes in der Daten-Datei benutzt sind.
+
+@item Deleted data
+Wie viele Bytes in der Daten-Datei gelöscht sind (unbenutzt).
+
+@item Lost space
+Wenn ein Datensatz auf eine kürzere Länge aktualisiert wird, geht etwas
+Platz verloren. Das ist die Summe aller solcher Verluste in Bytes.
+
+@item Linkdata
+When das dynamische Tabellenformat benutzt wird, werden Datensatzfragmente
+mit Zeigern (Pointer) verknüpft (jeder mit 4 bis 7 Bytes). @code{Linkdata}
+ist die Summe des Speicherplatzes, der von diesen Zeigern benutzt wird.
+@end table
+
+Wenn eine Tabelle mit @code{myisampack} komprimiert wurde, gibt
+@code{myisamchk -d} zusätzliche Informationen über jede Tabellenspalte aus,
+siehe @ref{myisampack, , @code{myisampack}}, wo sich ein Beispiel solcher
+Informationen und was sie bedeuten befindet.
+
+
+@node Database Administration, Localisation, Disaster Prevention, MySQL Database Administration
+@c German node Datenbankadministration
+@section Datenbankverwaltung Sprachreferenz
+
+
+
+
+@menu
+* OPTIMIZE TABLE::
+* ANALYZE TABLE::
+* FLUSH::
+* KILL::
+* SHOW::
+@end menu
+
+@node OPTIMIZE TABLE, ANALYZE TABLE, Database Administration, Database Administration
+@c German node OPTIMIZE TABLE
+@subsection @code{OPTIMIZE TABLE}-Syntax
+
+@findex OPTIMIZE TABLE
+
+@cindex Tabellen, defragmentieren
+@cindex Tabellen, Fragmentierung
+
+@example
+OPTIMIZE TABLE tabelle[,tabelle]...
+@end example
+
+@code{OPTIMIZE TABLE} sollte benutzt werden, wenn Sie große Teile der
+Tabelle gelöscht haben oder bei Tabellen mit Zeilen variabler Länge viele
+Änderungen durchgeführt haben (Tabellen, die @code{VARCHAR}-, @code{BLOB}-
+oder @code{TEXT}-Spalten enthalten). Gelöschte Datensätze werden in einer
+verknüpften Liste vorgehalten, und nachfolgenden @code{INSERT}-Operationen
+benutzen die Positionen alter Datensätze. Sie können @code{OPTIMIZE TABLE}
+benutzen, um unbenutzten Platz freizugeben und die Daten-Datei zu
+defragmentieren.
+
+Momentan funktioniert @code{OPTIMIZE TABLE} nur auf @strong{MyISAM}- und
+@code{BDB}-Tabellen. Bei @code{BDB}-Tabellen ist @code{OPTIMIZE TABLE}
+momentan auf @code{ANALYZE TABLE} gemappt. @xref{ANALYZE TABLE}.
+
+Sie können @code{OPTIMIZE TABLE} auf andere Tabellentypen zum Laufen
+bringen, indem Sie @code{mysqld} mit @code{--skip-new} oder
+@code{--safe-mode} starten, aber in diesem Fall wird @code{OPTIMIZE TABLE}
+lediglich auf @code{ALTER TABLE} gemappt.
+
+@code{OPTIMIZE TABLE} funktioniert wie folgt:
+@itemize @bullet
+@item
+Wenn die Tabelle gelöschte oder aufgeteilte Zeilen hat, wird sie repariert.
+@item
+Wenn die Index-Seiten nicht sortiert sind, werden sie sortiert.
+@item
+Wenn die Statistiken nicht aktuell sind (und eine Reparatur nicht durch das
+Sortieren des Indexes durchgeführt werden könnte), werden sie aktualisiert.
+@end itemize
+
+@code{OPTIMIZE TABLE} für @code{MyISAM}-Tabellen ist äquivalent zum
+Laufenlassen von @code{myisamchk --quick --check-changed-tables
+--sort-index --analyze} auf die Tabelle.
+
+Beachten Sie, dass die Tabelle während der Zeit, in der @code{OPTIMIZE TABLE} läuft, gesperrt ist!
+
+
+@node ANALYZE TABLE, FLUSH, OPTIMIZE TABLE, Database Administration
+@c German node ANALYZE TABLE
+@subsection @code{ANALYZE TABLE}-Syntax
+
+@findex ANALYZE TABLE
+
+@example
+ANALYZE TABLE tabelle[,tabelle...]
+@end example
+
+Analysiert und speichert die Schlüsselverteilung der Tabelle. Während der
+Analyse ist die Tabelle mit einer Lesesperre gesperrt. Das funktioniert auf
+@code{MyISAM} und @code{BDB}-Tabellen.
+
+Das ist äquivalent zum Laufenlassen von @code{myisamchk -a} auf die
+Tabelle.
+
+MySQL benutzt die gespeicherte Schlüsselverteilung, um zu entscheiden, in
+welcher Reihenfolge Tabellen verknüpft werden sollen, wenn man eine
+Verknüpfung (Join) auf irgend etwas anderes als eine Konstante macht.
+
+Der Befehl gibt eine Tabelle mit folgenden Spalten zurück:
+
+@multitable @columnfractions .35 .65
+@item @strong{Spalte} @tab @strong{Wert}
+@item Table @tab Tabellenname.
+@item Op @tab Immer ``analyze''.
+@item Msg_type @tab @code{status}, @code{error}, @code{info} oder @code{warning}.
+@item Msg_text @tab Die Meldung.
+@end multitable
+
+Sie können die gespeicherte Schlüsselverteilung mit dem @code{SHOW
+INDEX}-Befehl überprüfen. @xref{SHOW DATABASE INFO}.
+
+Wenn die Tabelle seit dem letzten @code{ANALYZE TABLE}-Befehl nicht
+geändert wurde, wird sie nicht noch einmal analysiert.
+
+
+@node FLUSH, KILL, ANALYZE TABLE, Database Administration
+@c German node FLUSH
+@subsection @code{FLUSH}-Syntax
+
+@findex FLUSH
+
+@cindex @code{mysqladmin}
+@cindex Löschen, Caches
+@cindex Caches, löschen
+
+@example
+FLUSH flush_option [,flush_option]
+@end example
+
+Wenn Sie einige der internen Caches, die MySQL benutzt, löschen wollen,
+benutzen Sie den @code{FLUSH}-Befehl. Um @code{FLUSH} ausführen zu können,
+müssen Sie die @strong{RELOAD}-Berechtigung haben.
+
+@code{flush_option} kann eine der folgenden sein:
+
+@multitable @columnfractions .15 .85
+@item @code{HOSTS} @tab Leert die Host-Cache-Tabellen. Sie sollten die
+Host-Tabellen flushen, wenn einige Ihrer Hosts die IP-Nummer ändern oder
+wenn Sie die Fehlermeldung @code{Host ... is blocked} erhalten. Wenn mehr
+als @code{max_connect_errors} Fehler in einer Zeile für einen gegebenen
+Host während der Verbindung zum MySQL-Server vorkommen, nimmt MySQL an,
+dass etwas nicht stimmt und blockiert den Host von weiteren
+Verbindungsversuchen. Wenn die Host-Tabellen geflusht werden, gestattet das
+dem Host, einen erneuten Verbindungsversuch zu machen.
+@c German FIX unwrapped @xref
+@xref{Blocked host}. Sie können @code{mysqld} mit @code{-O
+max_connection_errors=999999999} starten, um diese Fehlermeldung zu
+vermeiden.
+
+@item @code{LOGS} @tab Schließt alle Log-Dateien und öffnet sie danach
+wieder. Wenn Sie die Update-Log-Datei oder eine binäre Log-Datei ohne
+Erweiterung angegeben haben, wird die Erweiterungsnummer der Log-Datei um
+eins relativ zur vorherigen Datei hoch gezählt. Wenn Sie eine Erweiterung
+im Dateinamen benutzt haben, schließt MySQL die Update-Log-Datei und
+öffnet sie danach wieder. @xref{Update log}. Das ist dasselbe, wie
+dem @code{mysqld}-Server das @code{SIGHUP}-Signal senden.
+
+@item @code{PRIVILEGES} @tab Lädt die Berechtigungen aus den
+Berechtigungstabellen der @code{mysql}-Datenbank neu.
+
+@item @code{TABLES} @tab Schließt alle offenen Tabellen und erzwingt, dass
+alle Tabellen in Benutzung geschlossen werden.
+
+@item @code{[TABLE | TABLES] tabelle [,tabelle...]} @tab Flusht nur die
+angegebenen Tabellen.
+
+@item @code{TABLES WITH READ LOCK} @tab Schließt alle offenen Tabellen und
+sperrt alle Tabellen aller Datenbanken mit einer Lesesperre, bis man
+@code{UNLOCK TABLES} ausführt. Das ist eine sehr bequeme Möglichkeit,
+Datensicherungen zu erzeugen, wenn Sie ein Dateisystem wie Veritas haben,
+das Schnappschüsse aufnehmen kann.
+
+@item @code{STATUS} @tab Setzt alle Status-Variablen auf null zurück. Das
+sollte man nur benutzen, wenn man eine Anfrage debuggt.
+@end multitable
+
+Jeden der oben genannten Befehle können Sie auch mit dem
+@code{mysqladmin}-Dienstprogramm ausführen, indem Sie @code{flush-hosts},
+@code{flush-logs}, @code{reload} oder @code{flush-tables}-Befehle
+eingeben.
+
+Sehen Sie sich auch den @code{RESET}-Befehl an, der bei der Replikation
+benutzt wird. @xref{Replication SQL}.
+
+
+
+@node KILL, SHOW, FLUSH, Database Administration
+@c German node KILL
+@subsection @code{KILL}-Syntax
+
+@findex KILL
+
+@cindex @code{mysqladmin}
+
+@example
+KILL Thread_id
+@end example
+
+Jede Verbindung zu @code{mysqld} läuft durch einen separaten Thread. Sie
+können sehen, welche Threads laufen, indem Sie den @code{SHOW
+PROCESSLIST}-Befehl ausführen, und einen Thread killen, indem Sie den
+@code{KILL Thread_id}-Befehl ausführen.
+
+Wenn Sie die @strong{process}-Berechtigung haben, können Sie alle Threads
+sehen und killen. Ansonsten können Sie nur Ihre eigenen Threads sehen und
+killen.
+
+Sie können auch die @code{mysqladmin processlist}- und @code{mysqladmin
+kill}-Befehle benutzen, um Threads einzusehen und zu killen.
+
+Wenn Sie ein @code{KILL} ausführen, wird ein Thread-spezifischer @code{kill
+flag} für den Thread gesetzt.
+
+In den meisten Fällen kann es einige Zeit dauern, bis der Thread stirbt,
+weil der kill-Flag nur in bestimmten Intervallen geprüft wird:
+
+@itemize @bullet
+@item
+Bei @code{SELECT}-, @code{ORDER BY}- und @code{GROUP BY}-Schleifen wird der
+Flag geprüft, nachdem ein Block von Zeilen gelesen wurde. Wenn der
+kill-Flag gesetzt ist, wird das Statement abgebrochen.
+@item
+Bei @code{ALTER TABLE} wird der kill-Flag geprüft, bevor jeder Block von
+Zeilen aus der Original-Tabelle gelesen wird. Wenn der Flag gesetzt ist,
+wird der Befehl abgebrochen und die temporäre Tabelle wird gelöscht.
+@item
+Bei @code{UPDATE TABLE} und @code{DELETE TABLE} wird der kill-Flag geprüft,
+nachdem jeder Block gelesen wurde sowie nach jeder aktualisierten oder
+gelöschten Zeile. Wenn der Flag gesetzt ist, wird das Statement
+abgebrochen. Beachten Sie, dass die Änderungen nicht zurück gerollt
+(Rollback) werden, wenn Sie keine Transaktionen benutzen!
+@item
+@code{GET_LOCK()} wird mit @code{NULL} abgebrochen.
+@item
+Ein @code{INSERT DELAYED}-Thread flusht schnell alle Zeilen, die er im
+Speicher hat, und stirbt.
+@item
+Wenn der Thread im Tabellen-Lock-Handler ist (Status: @code{Locked}), wird
+die Tabellen-Sperre schnell abgebrochen.
+@item
+Wenn der Thread bei einem @code{write}-Aufruf auf freien Plattenplatz
+wartet, wird der Schreibvorgang mit einer Meldung, dass die Platte voll
+ist, abgebrochen.
+@end itemize
+
+
+
+
+@node SHOW, , KILL, Database Administration
+@c German node SHOW
+@subsection @code{SHOW}-Syntax
+
+@findex SHOW DATABASE INFO
+@findex SHOW DATABASES
+@findex SHOW TABLES
+@findex SHOW COLUMNS
+@findex SHOW FIELDS
+@findex SHOW INDEX
+@findex SHOW KEYS
+@findex SHOW STATUS
+@findex SHOW VARIABLES
+@findex SHOW PROCESSLIST
+@findex SHOW TABLE STATUS
+@findex SHOW GRANTS
+@findex SHOW CREATE TABLE
+@findex SHOW MASTER STATUS
+@findex SHOW MASTER LOGS
+@findex SHOW SLAVE STATUS
+
+@example
+ SHOW DATABASES [LIKE platzhalter]
+oder SHOW [OPEN] TABLES [FROM datenbank] [LIKE platzhalter]
+oder SHOW [FULL] COLUMNS FROM tabelle [FROM datenbank] [LIKE platzhalter]
+oder SHOW INDEX FROM tabelle [FROM datenbank]
+oder SHOW TABLE STATUS [FROM datenbank] [LIKE platzhalter]
+oder SHOW STATUS [LIKE platzhalter]
+oder SHOW VARIABLES [LIKE platzhalter]
+oder SHOW LOGS
+oder SHOW [FULL] PROCESSLIST
+oder SHOW GRANTS FOR benutzer
+oder SHOW CREATE TABLE tabelle
+oder SHOW MASTER STATUS
+oder SHOW MASTER LOGS
+oder SHOW SLAVE STATUS
+@end example
+
+@code{SHOW} stellt Informationen über Datenbanken, Tabellen, Spalten oder
+Status-Informationen über den Server zur Verfügung. Wenn der @code{LIKE
+platzhalter}-Teil benutzt wird, kann die @code{platzhalter}-Zeichenkette
+eine Zeichenkette sein, die die SQL-@samp{%}- und @samp{_}-
+Platzhalterzeichen benutzt.
+
+
+
+@menu
+* SHOW DATABASE INFO::
+* SHOW TABLE STATUS::
+* SHOW STATUS::
+* SHOW VARIABLES::
+* SHOW LOGS::
+* SHOW PROCESSLIST::
+* SHOW GRANTS::
+* SHOW CREATE TABLE::
+@end menu
+
+@node SHOW DATABASE INFO, SHOW TABLE STATUS, SHOW, SHOW
+@c German node SHOW DATABASE INFO
+@subsubsection Informationen über Datenbank, Tabellen, Spalten und Indexe abrufen
+
+@cindex Anzeigen, Informationen, @code{SHOW}
+
+Sie können @code{datenbank.tabelle} als Alternative zur @code{tabelle FROM
+datenbank}-Syntax benutzen. Diese beiden Statements sind äquivalent:
+
+@example
+mysql> SHOW INDEX FROM tabelle FROM datenbank;
+mysql> SHOW INDEX FROM datenbank.tabelle;
+@end example
+
+@code{SHOW DATABASES} listet die Datenbanken auf dem MySQL-Server-Host auf.
+Diese Liste erhalten Sie auch mit dem @code{mysqlshow}-Befehl.
+
+@code{SHOW TABLES} listet die Tabellen in einer gegebenen Datenbank auf.
+Sie erhalten diese Liste auch mit dem @code{mysqlshow datenbank}-Befehl.
+
+@strong{HINWEIS:} Wenn ein Benutzer keinerlei Berechtigungen für eine
+Tabelle hat, wird die Tabelle in der Ausgabe von @code{SHOW TABLES} oder
+@code{mysqlshow datenbank} nicht aufgeführt.
+
+@code{SHOW OPEN TABLES} listet die Tabellen auf, die momentan im
+Tabellen-Cache geöffnet sind. @xref{Open tables}. Das @code{Comment}-Feld
+zeigt an, wie oft die Tabelle gecachet (@code{cached}) und in Benutzung
+(@code{in_use}) ist.
+
+@code{SHOW COLUMNS} listet die Spalten in einer gegebenen Tabelle auf. Wenn
+Sie die @code{FULL}-Option angeben, erhalten Sie auch die Berechtigungen,
+die Sie für jede Spalte besitzen. Wenn die Spaltentypen von dem abweichen,
+was Sie erwarten, nämlich, was Sie im @code{CREATE TABLE}-Statement
+angegeben haben, beachten Sie, dass MySQL manchmal Spaltentypen ändert.
+@xref{Silent column changes}.
+
+Das @code{DESCRIBE}-Statement gibt ähnliche Informationen wie @code{SHOW
+COLUMNS} aus. @xref{DESCRIBE, , @code{DESCRIBE}}.
+
+@code{SHOW FIELDS} ist ein Synonym für @code{SHOW COLUMNS}. @code{SHOW
+KEYS} ist ein Synonym für @code{SHOW INDEX}. Sie können die Spalten oder
+Indexe einer Tabelle auch mit @code{mysqlshow Datenbanktabelle} oder
+@code{mysqlshow -k Datenbanktabelle} anzeigen.
+
+@code{SHOW INDEX} gibt die Index-Informationen in einem Format aus, das dem
+@code{SQLStatistics}-Aufruf in ODBC stark ähnelt. Folgende Spalten werden
+zurückgegeben:
+
+@multitable @columnfractions .35 .65
+@item @strong{Spalte} @tab @strong{Bedeutung}
+@item @code{Table} @tab Name der Tabelle.
+@item @code{Non_unique} @tab 0, wenn der Index keine Duplikate enthalten darf.
+@item @code{Key_name} @tab Name des Indexes.
+@item @code{Seq_in_index} @tab Spaltensequenznummer im Index, zählt ab 1.
+@item @code{Column_name} @tab Spaltenname.
+@item @code{Collation} @tab Wie die Spalte im Index sortiert ist.
+ In MySQL können diese Werte @samp{A} (Ascending - aufsteigend)
+ oder @code{NULL} (Not sorted - unsortiert) sein.
+@item @code{Cardinality} @tab Anzahl der eindeutigen Werte im Index.
+ Dieser Wert wird durch Laufenlassen von @code{isamchk -a} aktualisiert.
+@item @code{Sub_part} @tab Anzahl der indizierten Zeichen, wenn die Spalte nur teilweise indiziert ist.
+ @code{NULL}, wenn der gesamte Schlüssel indiziert ist.
+@item @code{Comment} @tab Verschiedene Anmerkungen. Momentan teilt es nur mit,
+ ob der Index FULLTEXT ist oder nicht.
+@end multitable
+
+Beachten Sie: Weil @code{Cardinality} basierend auf statistischen Werten
+gezählt wird, die als Ganzzahlen gespeichert sind, ist es nicht
+notwendigerweise bei kleinen Tabellen korrekt.
+
+
+@node SHOW TABLE STATUS, SHOW STATUS, SHOW DATABASE INFO, SHOW
+@c German node SHOW TABLE STATUS
+@subsubsection @code{SHOW TABLE STATUS}
+
+@cindex anzeigen, Tabellen-Status
+@cindex Tabellen, Status anzeigen
+@cindex Status, Tabellen
+
+@example
+SHOW TABLE STATUS [FROM datenbank] [LIKE platzhalter]
+@end example
+
+@code{SHOW TABLE STATUS} (neu in Version 3.23) funktioniert wie @code{SHOW
+STATUS}, zeigt aber viele weitere Informationen über jede Tabelle. Diese
+Liste erhalten Sie auch mit dem @code{mysqlshow --status datenbank}-Befehl.
+Folgende Spalten werden zurückgegeben:
+
+@multitable @columnfractions .30 .70
+@item @strong{Spalte} @tab @strong{Bedeutung}
+@item @code{Name} @tab Name der Tabelle.
+@item @code{Type} @tab Typ der Tabelle. @xref{Table types}.
+@item @code{Row_format} @tab Das Zeilenspeicherformat (fest, dynamisch oder komprimiert).
+@item @code{Rows} @tab Anzahl der Zeilen.
+@item @code{Avg_row_length} @tab Durchschnittliche Zeilenlänge.
+@item @code{Data_length} @tab Länge der Daten-Datei.
+@item @code{Max_data_length} @tab Maximale Länge der Daten-Datei.
+@item @code{Index_length} @tab Länge der Index-Datei.
+@item @code{Data_free} @tab Anzahl der zugewiesenen (allocated), aber nicht benutzten Bytes.
+@item @code{Auto_increment} @tab Nächster autoincrement-Wert.
+@item @code{Create_time} @tab Wann die Tabelle erzeugt wurde.
+@item @code{Update_time} @tab Wann die Daten-Datei das letzte Mal aktualisiert wurde.
+@item @code{Check_time} @tab Wann die Tabelle das letzte Mal geprüft wurde.
+@item @code{Create_options} @tab Zusätzliche Optionen, die beim @code{CREATE TABLE} benutzt wurden.
+@item @code{Comment} @tab Der Kommentar, der beim Erzeugen der Tabelle angegeben wurde (oder einige Informationen, warum MySQL nicht auf die Tabelleninformationen zugreifen konnte).
+@end multitable
+
+Bei @code{InnoDB}-Tabellen wird im Tabellenkommentar der freie Platz im
+Tablespace ausgegeben.
+
+
+@node SHOW STATUS, SHOW VARIABLES, SHOW TABLE STATUS, SHOW
+@c German node SHOW STATUS
+@subsubsection @code{SHOW STATUS}
+
+@cindex @code{mysqladmin}
+@code{SHOW STATUS} zeigt Server-Status-Informationen an (wie
+@code{mysqladmin extended-status}). Die Ausgabe ähnelt der unten stehenden,
+obwohl Format und Anzahl der Zeilen wahrscheinlich abweichen:
+
+@example
++--------------------------+------------+
+| Variable_name | Value |
++--------------------------+------------+
+| Aborted_clients | 0 |
+| Aborted_connects | 0 |
+| Bytes_received | 155372598 |
+| Bytes_sent | 1176560426 |
+| Connections | 30023 |
+| Created_tmp_disk_tables | 0 |
+| Created_tmp_tables | 8340 |
+| Created_tmp_files | 60 |
+| Delayed_insert_Threads | 0 |
+| Delayed_writes | 0 |
+| Delayed_errors | 0 |
+| Flush_commands | 1 |
+| Handler_delete | 462604 |
+| Handler_read_first | 105881 |
+| Handler_read_key | 27820558 |
+| Handler_read_next | 390681754 |
+| Handler_read_prev | 6022500 |
+| Handler_read_rnd | 30546748 |
+| Handler_read_rnd_next | 246216530 |
+| Handler_update | 16945404 |
+| Handler_write | 60356676 |
+| Key_blocks_used | 14955 |
+| Key_read_requests | 96854827 |
+| Key_reads | 162040 |
+| Key_write_requests | 7589728 |
+| Key_writes | 3813196 |
+| Max_used_connections | 0 |
+| Not_flushed_key_blocks | 0 |
+| Not_flushed_delayed_rows | 0 |
+| Open_tables | 1 |
+| Open_files | 2 |
+| Open_streams | 0 |
+| Opened_tables | 44600 |
+| Questions | 2026873 |
+| Select_full_join | 0 |
+| Select_full_range_join | 0 |
+| Select_range | 99646 |
+| Select_range_check | 0 |
+| Select_scan | 30802 |
+| Slave_running | OFF |
+| Slave_open_temp_tables | 0 |
+| Slow_launch_threads | 0 |
+| Slow_queries | 0 |
+| Sort_merge_passes | 30 |
+| Sort_range | 500 |
+| Sort_rows | 30296250 |
+| Sort_scan | 4650 |
+| Table_locks_immediate | 1920382 |
+| Table_locks_waited | 0 |
+| Threads_cached | 0 |
+| Threads_created | 30022 |
+| Threads_connected | 1 |
+| Threads_running | 1 |
+| Uptime | 80380 |
++--------------------------+------------+
+@end example
+
+@cindex variables, status
+The status variables listed höher have the following Bedeutung:
+
+@multitable @columnfractions .35 .65
+@item @strong{Variable} @tab @strong{Bedeutung}
+@item @code{Aborted_clients} @tab Anzahl der Verbindungen, die abgebrochen
+wurden, weil der Client starb, ohne die Verbindung ordnungsgemäß zu
+schließen. @xref{Communication errors}.
+@item @code{Aborted_connects} @tab Anzahl der fehlgeschlagenen Versuche,
+sich mit dem MySQL-Server zu verbinden. @xref{Communication errors}.
+@item @code{Bytes_received} @tab Anzahl der Bytes, die von allen Clients
+empfangen wurden.
+@item @code{Bytes_sent} @tab Anzahl der Bytes, die an alle Clients gesendet
+wurden.
+@item @code{Connections} @tab Anzahl der Verbindungsversuche zum MySQL-Server.
+@item @code{Created_tmp_disk_tables} @tab Anzahl der (implizit) auf der
+Platte erzeugten temporären Tabellen bei der Ausführung von Statements.
+@item @code{Created_tmp_tables} @tab Anzahl der (implizit) im
+Arbeitsspeicher erzeugten temporären Tabellen bei der Ausführung von
+Statements.
+@item @code{Created_tmp_files} @tab Wie viele temporäre Dateien
+@code{mysqld} erzeugt hat.
+@item @code{Delayed_insert_Threads} @tab Anzahl der verzögerten
+Insert-Handler-Threads in Benutzung.
+@item @code{Delayed_writes} @tab Anzahl der Zeilen, die mit @code{INSERT
+DELAYED} geschrieben wurden.
+@item @code{Delayed_errors} @tab Anzahl der Zeilen, die mit @code{INSERT
+DELAYED} geschrieben wurden, und bei denen irgend ein Fehler auftrat
+(wahrscheinlich @code{duplicate key}).
+@item @code{Flush_commands} @tab Anzahl der ausgeführten @code{FLUSH}-Befehle.
+@item @code{Handler_delete} @tab Wie oft eine Zeile aus einer Tabelle
+gelöscht wurde.
+@item @code{Handler_read_first} @tab Wie oft der erste Eintrag aus einem
+Index gelesen wurde. Wenn dieser Wert hoch ist, legt das nahe, dass der
+Server viele komplette Index-Scans macht (zum Beispiel @code{SELECT spalte1
+FROM foo}, unter der Annahme, dass spalte1 indiziert ist).
+@item @code{Handler_read_key} @tab Anzahl der Anfragen, eine Zeile
+basierend auf einem Schlüssel zu lesen. Wenn dieser Wert hoch ist, ist das
+ein gutes Indiz dafür, dass Ihre Anfragen und Tabellen korrekt indiziert
+sind.
+@item @code{Handler_read_next} @tab Anzahl der Anfragen, die nächste Zeile
+in der Reihenfolge des Schlüssels zu lesen. Dieser Wert wird herauf
+gezählt, wenn Sie eine Index-Spalte mit einer Bereichsbeschränkung (Limit)
+abfragen. Er wird ebenfalls herauf gezählt, wenn Sie einen Index-Scan
+durchführen.
+@item @code{Handler_read_rnd} @tab Anzahl der Anfragen, eine Zeile
+basierend auf einer festen Position zu lesen. Dieser Wert wird hoch sein,
+wenn Sie viele Anfragen ausführen, die erfordern, dass das Ergebnis
+sortiert wird.
+@item @code{Handler_read_rnd_next} @tab Anzahl der Anfragen, die nächste
+Zeile in der Daten-Datei zu lesen. Dieser Wert wird hoch sein, wenn Sie
+viele Tabellen-Scans durchführen. Im Allgemeinen weist das darauf hin, dass
+Ihre Tabellen nicht korrekt indiziert sind, oder dass Ihre Anfragen nicht
+so geschrieben sind, dass Sie Vorteile aus den Indexen ziehen, die Sie
+haben.
+@item @code{Handler_update} @tab Anzahl der Anfragen, eine Zeile in einer
+Tabelle zu aktualisieren.
+@item @code{Handler_write} @tab Anzahl der Anfragen, eine Zeile in eine
+Tabelle einzufügen.
+@item @code{Key_blocks_used} @tab Die Anzahl der benutzten Blocks im
+Schlüssel-Cache.
+@item @code{Key_read_requests} @tab Die Anzahl der Anfragen, einen
+Schlüssel-Block aus dem Cache zu lesen.
+@item @code{Key_reads} @tab Die Anzahl physikalischer Lesezugriffen eines
+Schlüssel-Blocks von der Platte.
+@item @code{Key_write_requests} @tab Die Anzahl der Anfragen, einen
+Schlüssel-Block in den Cache zu schreiben.
+@item @code{Key_writes} @tab Die Anzahl physikalischer Schreibvorgänge
+eines Schlüssel-Blocks auf Platte.
+@item @code{Max_used_connections} @tab Die höchste Anzahl von Verbindungen,
+die gleichzeitig in Benutzung sind.
+@item @code{Not_flushed_key_blocks} @tab Schlüssel-Blöcke im
+Schlüssel-Cache, die verändert wurden, aber noch nicht auf die Platte
+zurück geschrieben (flush).
+@item @code{Not_flushed_delayed_rows} @tab Anzahl der Zeilen, die in
+@code{INSERT DELAY}-Warteschleifen darauf warten, geschrieben zu werden.
+@item @code{Open_tables} @tab Anzahl der offenen Tabellen.
+@item @code{Open_files} @tab Anzahl der offenen Dateien.
+@item @code{Open_streams} @tab Anzahl der offenen Streams (hauptsächlich
+zum Loggen benutzt).
+@item @code{Opened_tables} @tab Anzahl der Tabellen, die geöffnet wurden.
+@item @code{Select_full_join} @tab Anzahl der Joins ohne Schlüssel (sollte
+0 sein).
+@item @code{Select_full_range_join} @tab Anzahl der Joins, bei denen eine
+Bereichssuche auf die Referenztabelle statt fand.
+@item @code{Select_range} @tab Anzahl der Joins, bei denen Bereiche auf die
+erste Tabelle benutzt wurden. (Es ist normalerweise unkritisch, wenn dieser
+Wert hoch ist.)
+@item @code{Select_scan} @tab Anzahl der Joins, bei denen die erste Tabelle
+gescannt wurde.
+@item @code{Select_range_check} @tab Anzahl der Joins ohne Schlüssel, bei
+denen nach jeder Zeile auf Schlüsselbenutzung geprüft wurde (sollte 0
+sein).
+@item @code{Questions} @tab Anzahl der Anfragen, die zum Server geschickt
+wurden.
+@item @code{Slave_open_temp_tables} @tab Anzahl der temporären Tabellen,
+die momentan vom Slave-Thread geöffnet sind.
+@item @code{Slow_launch_threads} @tab Anzahl der Threads, die länger als
+@code{slow_launch_time} brauchten, um sich zu verbinden.
+@item @code{Slow_queries} @tab Anzahl der Anfragen, die länger als
+@code{long_query_time} benötigten. @xref{Slow query log}.
+@item @code{Sort_merge_passes} @tab Anzahl der Verschmelzungen (Merge), die
+von einem Sortiervorgang benötigt wurden. Wenn dieser Wert hoch ist,
+sollten Sie in Betracht ziehen, @code{sort_buffer} herauf zu setzen.
+@item @code{Sort_range} @tab Anzahl der Sortiervorgänge, die mit Bereichen
+durchgeführt wurden.
+@item @code{Sort_rows} @tab Anzahl der sortierten Zeilen.
+@item @code{Sort_scan} @tab Anzahl der Sortiervorgänge, die durchgeführt
+wurden, indem die Tabelle gescannt wurde.
+@item @code{Table_locks_immediate} @tab Wie oft eine Tabellensperre sofort
+erlangt wurde. Verfügbar nach Version 3.23.33.
+@item @code{Table_locks_waited} @tab Wie oft eine Tabellensperre nicht
+sofort erlangt werden konnte und gewartet werden musst. Wenn dieser Wert
+hoch ist und Sie Performance-Probleme haben, sollten Sie zunächst Ihre
+Anfragen optimieren und dann entweder Ihre Tabelle(n) zerteilen oder
+Replikation benutzen. Verfügbar nach Version 3.23.33.
+@item @code{Threads_cached} @tab Anzahl der Threads im Thread-Cache.
+@item @code{Threads_connected} @tab Anzahl der momentan offenen
+Verbindungen.
+@item @code{Threads_created} @tab Anzahl der Threads, die zur Handhabung
+von Verbindungen erzeugt wurden.
+@item @code{Threads_running} @tab Anzahl der Threads, die nicht schlafen.
+@item @code{Uptime} @tab Seit wie vielen Sekunden der Server hoch gefahren
+ist.
+@end multitable
+
+Einige Anmerkungen zum oben Aufgeführten:
+
+@itemize @bullet
+@item
+Wenn @code{Opened_tables} hoch ist, ist Ihre @code{table_cache}-Variable
+wahrscheinlich zu niedrig.
+@item
+Wenn @code{key_reads} hoch ist, ist Ihr @code{key_cache} wahrscheinlich zu
+klein. Die Cache-Zugriffsrate kann mit @code{key_reads} /
+@code{key_read_requests} berechnet werden.
+@item
+Wenn @code{Handler_read_rnd} hoch ist, haben Sie wahrscheinlich viele
+Anfragen, die MySQL zwingen, ganze Tabellen zu scannen, oder Sie haben
+Joins, die Schlüssel nicht richtig benutzen.
+@item
+Wenn @code{Threads_created} hoch ist, sollten Sie eventuell die
+@code{Thread_cache_size}-Variable herauf setzen.
+@item
+Wenn @code{Created_tmp_disk_tables} hoch ist, sollten Sie eventuell die
+@code{tmp_table_size}-Variable herauf setzen, damit temporäre Tabellen im
+Speicher erzeugt werden statt auf der Platte.
+@end itemize
+
+
+@node SHOW VARIABLES, SHOW LOGS, SHOW STATUS, SHOW
+@c German node SHOW VARIABLES
+@subsubsection @code{SHOW VARIABLES}
+
+@example
+SHOW VARIABLES [LIKE platzhalter]
+@end example
+
+@code{SHOW VARIABLES} zeigt die Werte einiger MySQL-Systemvariablen. Sie
+erhalten diese List auch mit dem @code{mysqladmin variables}-Befehl. Wenn
+die Vorgabewerte unpassend sind, können Sie die meisten dieser Variablen
+mit Kommandozeilenoptionen setzen, wenn Sie @code{mysqld} hoch fahren.
+@xref{Command-line options}.
+
+Die Ausgabe ähnelt der unten stehenden,
+obwohl Format und Anzahl der Zeilen wahrscheinlich abweichen:
+
+@example
++-------------------------+---------------------------+
+| Variable_name | Value |
++-------------------------+---------------------------+
+| ansi_mode | OFF |
+| back_log | 50 |
+| basedir | /my/monty/ |
+| bdb_cache_size | 16777216 |
+| bdb_log_buffer_size | 32768 |
+| bdb_home | /my/monty/data/ |
+| bdb_max_lock | 10000 |
+| bdb_logdir | |
+| bdb_shared_data | OFF |
+| bdb_tmpdir | /tmp/ |
+| binlog_cache_size | 32768 |
+| concurrent_insert | ON |
+| connect_timeout | 5 |
+| datadir | /my/monty/data/ |
+| delay_key_write | ON |
+| delayed_insert_limit | 100 |
+| delayed_insert_timeout | 300 |
+| delayed_queue_size | 1000 |
+| flush | OFF |
+| flush_time | 0 |
+| have_bdb | YES |
+| have_innodb | YES |
+| have_raid | YES |
+| have_openssl | NO |
+| init_file | |
+| interactive_timeout | 28800 |
+| join_buffer_size | 131072 |
+| key_buffer_size | 16776192 |
+| language | /my/monty/share/english/ |
+| large_files_support | ON |
+| log | OFF |
+| log_update | OFF |
+| log_bin | OFF |
+| log_slave_updates | OFF |
+| long_query_time | 10 |
+| low_priority_updates | OFF |
+| lower_case_table_names | 0 |
+| max_allowed_packet | 1048576 |
+| max_binlog_cache_size | 4294967295 |
+| max_connections | 100 |
+| max_connect_errors | 10 |
+| max_delayed_threads | 20 |
+| max_heap_table_size | 16777216 |
+| max_join_size | 4294967295 |
+| max_sort_length | 1024 |
+| max_tmp_tables | 32 |
+| max_write_lock_count | 4294967295 |
+| myisam_recover_options | DEFAULT |
+| myisam_sort_buffer_size | 8388608 |
+| net_buffer_length | 16384 |
+| net_read_timeout | 30 |
+| net_retry_count | 10 |
+| net_write_timeout | 60 |
+| open_files_limit | 0 |
+| pid_file | /my/monty/data/donna.pid |
+| port | 3306 |
+| protocol_version | 10 |
+| record_buffer | 131072 |
+| query_buffer_size | 0 |
+| safe_show_database | OFF |
+| server_id | 0 |
+| skip_locking | ON |
+| skip_networking | OFF |
+| skip_show_database | OFF |
+| slow_launch_time | 2 |
+| socket | /tmp/mysql.sock |
+| sort_buffer | 2097116 |
+| table_cache | 64 |
+| table_type | MYISAM |
+| Thread_cache_size | 4 |
+| Thread_stack | 65536 |
+| tmp_table_size | 1048576 |
+| tmpdir | /tmp/ |
+| version | 3.23.29a-gamma-debug |
+| wait_timeout | 28800 |
++-------------------------+---------------------------+
+@end example
+
+Jede Option ist unten beschrieben. Die Werte für Puffergrößen, Längen und
+Stack-Größen sind in Bytes angegeben. Sie können Wert mit den Suffixen
+@samp{K} oder @samp{M} angeben, um Kilobytes oder Megabytes zu
+kennzeichnen. @code{16M} zum Beispiel bedeutet 16 Megabytes. Bei den
+Suffixen spielt Groß-/Kleinschreibung keine Rolle, @code{16M} und
+@code{16m} sind äquivalent:
+
+@cindex Variablen, Werte
+@table @code
+@item @code{ansi_mode}.
+Ist @code{ON}, wenn @code{mysqld} mit @code{--ansi} gestartet wurde.
+@xref{ANSI mode}.
+
+@item @code{back_log}
+Die Anzahl unerledigter Verbindungsanforderung, die MySQL haben kann. Dies
+kommt ins Spiel, wenn der Haupt-Thread von MySQL @strong{SEHR} viele
+Verbindungsanforderungen in sehr kurzer Zeit erhält. Dann dauert es etwas
+(wenngleich sehr kurz), damit der Haupt-Thread die Verbindung prüfen und
+einen neuen Thread starten kann. Der @code{back_log}-Wert zeigt an, wie
+viele Verbindungen während dieser kurzen Zeit gestapelt (gestackt) werden können, bevor
+MySQL für einen Moment aufhört, neue Anforderungen zu beantworten. Sie
+brauchen diesen Wert nur dann herauf setzen, wenn Sie eine große Zahl von
+Verbindungen in kurzer Zeit erwarten.
+
+Mit anderen Worten ist dieser Wert die Größe der Listen-Queue
+(Warteschlange) für herein kommende TCP/IP-Verbindungen. Ihr Betriebssystem
+hat seine eigene Beschränkung hinsichtlich der Größe dieser Queue. Die
+Handbuchseiten zum Unix-@code{listen(2)}-System sollten hier weitere
+Details haben. Sehen Sie in der Dokumentation Ihres Betriebssystems nach,
+wie hoch der Wert dieser Variablen maximal sein kann. Wenn Sie versuchen,
+@code{back_log} höher als die Begrenzung Ihres Betriebssystems zu setzen,
+ist das ineffektiv.
+
+@item @code{basedir}
+Der Wert der @code{--basedir}-Option.
+
+@item @code{bdb_cache_size}
+Der zugewiesene Puffer, um Index und Zeilen bei @code{BDB}-Tabellen zu
+cachen. Wenn Sie keine @code{BDB}-Tabellen benutzen, sollten Sie
+@code{mysqld} mit @code{--skip-bdb} starten, um für diesen Cache keinen
+Arbeitsspeicher zu verschwenden.
+
+@item @code{bdb_log_buffer_size}
+Der zugewiesene Puffer, um Index und Zeilen bei @code{BDB}-Tabellen zu
+cachen. Wenn Sie keine @code{BDB}-Tabellen benutzen, sollten Sie diesen
+Wert auf o setzen und @code{mysqld} mit @code{--skip-bdb} starten, um für
+diesen Cache keinen Arbeitsspeicher zu verschwenden.
+
+@item @code{bdb_home}
+Der Wert der @code{--bdb-home}-Option.
+
+@item @code{bdb_max_lock}
+Die maximale Anzahl von Sperren (Vorgabewert: 1000), die bei einer
+@code{BDB}-Tabelle aktiv sein können. Sie sollten diesen Wert herauf
+setzen, wenn Sie Fehler folgender Art bekommen: @code{bdb:
+Lock table is out of available locks} oder @code{Got error 12 from ...},
+wenn Sie lange Transaktionen durchführen oder wenn @code{mysqld} viele
+Zeile untersuchen muss, um die Anfrage zu berechnen.
+
+@item @code{bdb_logdir}
+Der Wert der @code{--bdb-logdir}-Option.
+
+@item @code{bdb_shared_data}
+Ist @code{ON}, wenn Sie @code{--bdb-shared-data} benutzen.
+
+@item @code{bdb_tmpdir}
+Der Wert der @code{--bdb-tmpdir}-Option.
+
+@item @code{binlog_cache_size}. Die Größe des Caches, in dem
+SQL-Statements für das Binär-Log während einer Transaktion vorgehalten
+werden. Wenn Sie oft große, aus vielen Statements bestehende Transaktionen
+durchführen, können Sie diesen Wert herauf setzen, um mehr Performance zu
+erzielen. @xref{COMMIT}.
+
+@item @code{character_set}
+Der vorgabemäßige Zeichensatz.
+
+@item @code{character_sets}
+Die unterstützten Zeichensätze.
+
+@item @code{concurrent_inserts}
+Falls @code{ON} (Vorgabe), läßt MySQL @code{INSERT} auf
+@code{MyISAM}-Tabellen zu, auf die zur gleichen Zeit @code{SELECT}-Anfragen
+laufen. Sie können diese Option ausschalten, indem Sie @code{mysqld} mit
+@code{--safe} oder @code{--skip-new} starten.
+
+@cindex timeout
+@item @code{connect_timeout}
+Die Anzahl von Sekunden, die der @code{mysqld}-Server auf ein
+Verbindungspaket wartet, bevor er mit @code{Bad handshake} antwortet.
+
+@item @code{datadir}
+Der Wert der @code{--datadir}-Option.
+
+@item @code{delay_key_write}
+Falls angeschaltet (Vorgabe), akzeptiert MySQL die
+@code{delay_key_write}-Option von @code{CREATE TABLE}. Das heißt, dass der
+Schlüsselpuffer für Tabellen bei dieser Option nicht bei jeder
+Index-Aktualisierung auf Platte zurückgeschrieben (flush) wird, sondern
+nur, wenn eine Tabelle geschlossen wird. Das beschleunigt Schreibvorgänge
+auf Schlüssel ganz erheblich, aber Sie sollten eine automatische Prüfung
+aller Tabellen mit @code{myisamchk --fast --force} hinzufügen, wenn Sie
+diese Option benutzen. Beachten Sie: Wenn Sie @code{mysqld} mit der
+@code{--delay-key-write-for-all-tables}-Option startet, heißt das, dass
+alle Tabelle so behandelt werden, als wenn sie mit der
+@code{delay_key_write}-Option erzeugt worden wären. Sie können diesen Flag
+löschen, wenn Sie @code{mysqld} mit @code{--skip-new} oder
+@code{--safe-mode} starten.
+
+@item @code{delayed_insert_limit}
+Nachdem @code{delayed_insert_limit} Zeilen eingefügt wurden, prüft der
+@code{INSERT DELAYED}-Handler, ob noch irgend welche
+@code{SELECT}-Statements anhängig sind. Falls ja, wird deren Ausführung
+zugelassen, bevor weiter gemacht wird.
+
+@item @code{delayed_insert_timeout}
+Wie lange ein @code{INSERT DELAYED}-Thread auf @code{INSERT}-Statements
+warten soll, bevor abgebrochen wird.
+
+@item @code{delayed_queue_size}
+Welche Warteschleifen-(Queue)-Speichergröße (in Zeilen) für die Handhabung
+von @code{INSERT DELAYED} zugewiesen werden soll. Wenn die Queue voll ist,
+wartet jeder Client, der @code{INSERT DELAYED} ausführt, bis es wieder
+Platz in der Queue gibt.
+
+@item @code{flush}
+Ist @code{ON}, wenn Sie MySQL mit der @code{--flush}-Option gestartet
+haben.
+
+@item @code{flush_time}
+Wenn diese Variable auf einen Wert ungleich 0 gesetzt wird, dann werden
+alle @code{flush_time} Sekunden alle Tabelle geschlossen (um Ressourcen
+frei zu geben und Dinge auf Platte zurück zu schreiben). Diese Option
+empfehlen wir nur auf Windows 95, Windows 98 oder auf Systemen, auf denen
+Sie sehr wenige Ressourcen haben.
+
+@item @code{have_bdb}
+Ist @code{YES}, wenn @code{mysqld} Berkeley-DB-Tabellen unterstützt. Ist
+@code{DISABLED}, wenn @code{--skip-bdb} benutzt wird.
+@item @code{have_innodb}
+Ist @code{YES}, wenn @code{mysqld} InnoDB-Tabellen unterstützt. Ist
+@code{DISABLED}, wenn @code{--skip-innodb} benutzt wird.
+@item @code{have_raid}
+Ist @code{YES}, wenn @code{mysqld} die @code{RAID}-Option unterstützt.
+@item @code{have_openssl}
+Ist @code{YES}, wenn @code{mysqld} SSL (Verschlüsselung) auf dem
+Client-/Server-Protokoll unterstützt.
+
+@item @code{init_file}
+Der Name der Datei, die mit der @code{--init-file}-Option angegeben wurde,
+als Sie den Server starteten. Das ist eine Datei mit SQL-Statements, die
+der Server beim Start ausführen soll.
+
+@item @code{interactive_timeout}
+Die Anzahl von Sekunden, die der Server bei einer interaktiven Verbindung
+wartet, bis er sie schließt. Ein interaktiver Client ist definiert als
+Client, der die @code{CLIENT_INTERACTIVE}-Option für
+@code{mysql_real_connect()} benutzt. Siehe auch @code{wait_timeout}.
+
+@item @code{join_buffer_size}
+Die Größe des Puffers, der für volle Joins benutzt wird (Joins, die keine
+Indexe benutzen). Der Puffer wird einmal pro vollem Join zwischen zwei
+Tabellen zugewiesen. Setzen Sie diesen Wert herauf, um einen schnelleren
+vollen Join zu erhalten, wenn das Addieren von Indexen nicht möglich ist.
+(Normalerweise ist die beste Art, schnelle Joins zu erhalten, das Addieren
+von Indexen.)
+
+@c Make texi2html Support index @anchor{Index cache size}. Then change
+@c some xrefs to point here
+@cindex Indexe, Blockgröße
+@item @code{key_buffer_size}
+Index-Blöcke werden gepuffert und von allen Threads geteilt.
+@code{key_buffer_size} ist die Größe des Puffers, der für Index-Blöcke
+benutzt wird.
+
+Setzen Sie diesen Wert herauf, um eine bessere Index-Handhabung zu erzielen
+(für alle Lesevorgänge und für mehrfache Schreibvorgänge), so weit, wie Sie
+es sich leisten können; 64 MB auf einer 256-MB-Maschine, auf der
+hauptsächlich MySQL läuft, ist ein gebräuchlicher Wert. Wenn Sie diesen
+Wert allerdings zu hoch setzen (mehr als 50% Ihres gesamten
+Arbeitsspeichers), kann es sein, dass Ihr System anfängt auszulagern
+(Paging), was SEHR langsam werden kann. Denken Sie daran, dass Sie Platzt
+für den Dateisystem-Cache des Betriebssystems lassen müssen, weil MySQL
+Daten-Lesen nicht cachet.
+
+Sie können die Performance des Schlüsselpuffers mit @code{show status}
+überprüfen und sich die Variablen @code{Key_read_requests},
+@code{Key_reads}, @code{Key_write_requests} und @code{Key_writes} ansehen.
+Das Verhältnis @code{Key_reads/Key_read_request} sollte normalerweise <
+0,01 sein. @code{Key_write/Key_write_requests} ist üblicherweise nahe 1,
+wenn Sie hauptsächlich Aktualisieren (Update) und Löschen (Delete)
+ausführen, kann aber sehr viel kleiner werden, wenn Sie tendenziell
+Aktualisierungen ausführen, die viele Zeilen gleichzeitig betreffen, oder
+wenn Sie @code{delay_key_write} benutzen. @xref{SHOW}.
+
+Um noch mehr Geschwindigkeit beim Schreiben vieler Zeilen auf einmal zu
+erhalten, benutzen Sie @code{LOCK TABLES}. @xref{LOCK TABLES, , @code{LOCK TABLES}}.
+
+@item @code{language}
+Die Sprache, in der Fehlermeldungen ausgegeben werden.
+
+@item @code{large_file_support}
+Ob @code{mysqld} mit Optionen für die Unterstützung großer Dateien
+kompiliert wurde.
+
+@item @code{locked_in_memory}
+Ob @code{mysqld} mit @code{--memlock} in den Speicher gesperrt wurde.
+
+@item @code{log}
+Ob das Loggen aller Anfragen angeschaltet ist.
+
+@item @code{log_update}
+Ob das Update-Log angeschaltet ist.
+
+@item @code{log_bin}
+Ob das Binär-Log angeschaltet ist.
+
+@item @code{log_slave_updates}
+Ob Aktualisierungen vom Slave geloggt werden sollen.
+
+@item @code{long_query_time}
+Wenn eine Anfrage länger als diesen Wert (in Sekunden) benötigt, wird der
+@code{Slow_queries}-Zähler hoch gezählt. Wenn Sie @code{--log-slow-queries}
+benutzen, wird die Anfrage in die Slow-Query-Logdatei geschrieben.
+@xref{Slow query log}.
+
+@item @code{lower_case_table_names}
+Wenn auf 1 gesetzt, werden Tabellennamen in Kleinschreibung auf Platte
+gespeichert. Tabellennamen sind dann unabhängig von der verwendeten
+Groß-/Kleinschreibung.
+@xref{Case sensitivity}.
+
+@item @code{max_allowed_packet}
+Die maximale Größe eine Pakets. Der Nachrichtenpuffer wird auf
+@code{net_buffer_length} Bytes Länge initialisiert, kann aber wenn nötig
+bis zu @code{max_allowed_packet} Bytes Groß werden. Der Vorgabewert ist
+klein, um große (möglicherweise falsche) Pakete abzufangen. Sie müssen
+diesen Wert erhöhen, wenn Sie große @code{BLOB}-Spalten verwenden. Er
+sollte so Groß sein wie die größte @code{BLOB}-Spalte, die Sie verwenden
+wollen. Das aktuelle Protokoll begrenzt @code{max_allowed_packet} auf 16 MB.
+
+@item @code{max_binlog_cache_size}
+Wenn eine Transaktion aus mehreren Statements mehr als diese Speichermenge
+benötigt, erhält man den Fehler "Multi-Statement transaction required more
+than 'max_binlog_cache_size' bytes of storage".
+
+@item @code{max_binlog_size}
+Verfügbar nach Version 3.23.33. Wenn ein Schreibvorgang ins binäre
+(Replikations-) Log den angegebenen Wert übersteigt, werden die Logs
+rotiert. Sie können den Wert auf weniger als 1024 Bytes setzen oder auf
+mehr als 1 GB. Vorgabe ist 1 GB.
+
+@item @code{max_connections}
+Die Anzahl von Clients, die gleichzeitig verbunden sind. Wenn Sie diesen
+Wert hoch setzen, wird die Anzahl der Datei-Deskriptoren heraufgesetzt, die
+@code{mysqld} benötigt. Siehe weiter unten, Bemerkungen zu Beschränkungen
+bei Datei-Deskriptoren. @xref{Too many connections}.
+
+@item @code{max_connect_errors}
+Wenn es mehr als diese Anzahl unterbrochener Verbindungen von einem Host
+gibt, wird dieser Host von weiteren Verbindungen abgeschnitten. Sie können
+diese Sperre mit dem @code{FLUSH HOSTS}-Befehl aufheben.
+
+@item @code{max_delayed_Threads}
+Nicht mehr als diese Anzahl von Threads zulassen, um @code{INSERT
+DELAYED}-Statements abzuarbeiten. Wenn Sie versuchen, Daten in eine neue
+Tabelle einzufügen, wenn alle @code{INSERT DELAYED}-Threads in Benutzung
+sind, wird die Zeile eingefügt, als ob das @code{DELAYED}-Attribut nicht
+angegeben wäre.
+
+@item @code{max_heap_table_size}
+Kein Erzeugen von Heap-Tabellen zulassen, die größer als dieser Wert sind.
+
+@item @code{max_join_size}
+Joins, die wahrscheinlich mehr als @code{max_join_size} Datensätze lesen
+werden, geben einen Fehler zurück. Setzen Sie diesen Wert, wenn Ihre
+Benutzer dazu neigen, Joins auszuführen, denen eine @code{WHERE}-Klausel
+fehlt und die daher lange Zeit benötigen und womöglich Millionen von Zeilen
+zurück geben.
+
+@item @code{max_sort_length}
+Die Anzahl von Bytes, die beim Sortieren von @code{BLOB}- oder
+@code{TEXT}-Werten benutzt werden (nur die ersten @code{max_sort_length}
+Bytes jedes Werts werden benutzt, der Rest wird ignoriert).
+
+@item @code{max_user_connections}
+Die maximale Anzahl aktiver Verbindungen für einen einzelnen Benutzer (0 =
+keine Beschränkung).
+
+@item @code{max_tmp_tables}
+(Diese Option macht bislang noch nichts.)
+Maximale Anzahl von temporären Tabellen, die ein Client zur selben Zeit
+offen halten darf.
+
+@item @code{max_write_lock_count}
+Nach dieser Anzahl Schreibsperren wird einigen Lesesperren erlaubt,
+zwischendurch zu laufen.
+
+@item @code{myisam_recover_options}
+Der Wert der @code{--myisam-recover}-Option.
+
+@item @code{myisam_sort_buffer_size}
+Der Puffer, der beim Sortieren des Indexes zugewiesen wird, wenn man ein
+@code{REPAIR} oder ausführt oder Indexe mit @code{CREATE INDEX} oder
+@code{ALTER TABLE} erzeugt.
+
+@item @code{myisam_max_extra_sort_file_size}.
+Wenn das Erzeugen der temporären Datei für schnelle Index-Erzeugung um
+diesen Wert größer sein würde als die Benutzung des Schlüssel-Caches, wird
+die Schlüssel-Cache-Methode bevorzugt. Wird hauptsächlich benutzt, um lange
+Zeichen-Schlüssel in großen Tabellen zu zwingen, die langsamere
+Schlüssel-Cache-Methode zu benutzen, um den Index zu erzeugen.
+@strong{HINWEIS:} Dieser Parameter wird in Megabytes angegeben!
+
+@item @code{myisam_max_sort_file_size}
+Die maximale Größe der temporären Datei, die MySQL benutzen darf, während
+es den Index erzeugt (während @code{REPAIR}, @code{ALTER TABLE} oder
+@code{LOAD DATA INFILE}). Wenn die Datei größer als dieser Wert würde, wird
+der Index über den Schlüssel-Cache erzeugt (was langsamer ist).
+@strong{HINWEIS:} Dieser Parameter wird in Megabytes angegeben!
+
+@item @code{net_buffer_length}
+Der Kommunikationspuffer wird zwischen Anfragen auf diesen Wert zurück
+gesetzt. Normalerweise sollte das nicht geändert werden, aber wenn Sie sehr
+wenig Arbeitsspeicher haben, können Sie ihn auf die erwartete Größe einer
+Anfrage setzen (also die erwartete Länge von SQL-Statements, die von
+Clients gesendet werden. Wenn Statements diese Länge überschreiten, wird
+der Puffer automatisch vergrößert, bis zu @code{max_allowed_packet} Bytes.)
+
+@item @code{net_read_timeout}
+Anzahl von Sekunden, die auf weitere Daten von einer Verbindung gewartet
+wird, bevor das Lesen abgebrochen wird. Beachten Sie: Wenn keine Daten von
+einer Verbindung erwartet werden, ist der Timeout durch
+@code{write_timeout} definiert. Siehe auch @code{slave_read_timeout}.
+
+@item @code{net_retry_count}
+Wenn ein Lesevorgang auf einem Kommunikations-Port unterbrochen wird, wird
+so oft wie angegeben neu versucht, bevor aufgegeben wird. Dieser Wert
+sollte auf @code{FreeBSD} recht hoch sein, weil interne
+Unterbrechnungsanforderungen (Interrupts) an alle Threads gesendet werden.
+
+@item @code{net_write_timeout}
+Anzahl von Sekunden, die auf das Schreiben eines Blocks zu einer Verbindung
+gewartet wird, bis das Schreiben abgebrochen wird.
+
+@item @code{open_files_limit}
+Wenn dieser Wert ungleich 0 ist, benutzt @code{mysqld} Datei-Deskriptoren,
+die mit @code{setrlimit()} benutzt werden. Wenn dieser Wert gleich 0 ist,
+reserviert @code{mysqld} @code{max_connections * 5} oder
+@code{max_connections + table_cache * 2} (je nachdem, was größer ist)
+Anzahl von Dateien. Sie sollten diesen Wert herauf setzen, wenn
+@code{mysqld} Ihnen die Fehlermeldung 'Too many open files' gibt.
+
+@item @code{pid_file}
+Der Wert der @code{--pid-file}-Option.
+
+@item @code{port}
+Der Wert der @code{--port}-Option.
+
+@item @code{protocol_version}
+Die Protokoll-Version, die vom MySQL-Server benutzt wird.
+
+@item @code{record_buffer}
+Jeder Thread, der einen sequentiellen Scan ausführt, alloziert einen Puffer
+dieser Größe für jede Tabelle, die er scannt. Wenn Sie viele sequentielle
+Scans ausführen, sollten Sie diesen Wert herauf setzen.
+
+@item @code{record_rnd_buffer}
+Wenn Zeilen nach einem Sortiervorgang in sortierter Reihenfolge gelesen
+werden, werden die Zeilen aus diesem Puffer gelesen, um Suchvorgänge auf
+der Platte zu vermeiden. Wenn dieser Wert nicht gesetzt ist, wird er auf
+den Wert von @code{record_buffer} gesetzt.
+
+@item @code{query_buffer_size}
+Die anfängliche Zuweisung des Anfragen-Puffers. Wenn die meisten Ihrer
+Anfragen lang sind (zum Beispiel beim Einfügen von Blobs), sollten Sie
+diesen Wert herauf setzen!
+
+@item @code{safe_show_databases}
+Keine Datenbanken zeigen, wenn der Benutzer keinerlei Datenbank- oder
+Tabellen-Berechtigungen dafür hat. Das kann die Sicherheit erhöhen, wenn
+Sie sich Sorgen machen, dass Leute in der Lage sind zu sehen, welche
+Datenbanken andere Benutzer haben. Siehe auch
+@code{skip_show_databases}.
+
+@item @code{server_id}
+Der Wert der @code{--server-id}-Option.
+
+@item @code{skip_locking}
+Ist @code{OFF}, wenn @code{mysqld} externes Sperren benutzt.
+
+@item @code{skip_networking}
+Ist @code{ON}, wenn nur lokale (Socket-) Verbindungen zugelassen sind.
+
+@item @code{skip_show_databases}
+Hält Leute davon ab, @code{SHOW DATABASES} zu benutzen, wenn sie keine
+the @code{PROCESS_PRIV}-Berechtigung haben. Das kann die Sicherheit erhöhen, wenn
+Sie sich Sorgen machen, dass Leute in der Lage sind zu sehen, welche
+Datenbanken andere Benutzer haben. Siehe auch @code{safe_show_databases}.
+
+@item @code{slave_read_timeout}
+Anzahl von Sekunden, die auf weitere Daten von einer
+Master-/Slave-Verbindung gewartet wird, bevor das Lesen abgebrochen wird.
+
+@item @code{slow_launch_time}
+Wenn das Erzeugen des Threads länger als dieser Wert (in Sekunden) dauert,
+word der @code{Slow_launch_threads}-Zähler herauf gezählt.
+
+@item @code{socket}
+Der Unix-Socket, der vom Server benutzt wird.
+
+@item @code{sort_buffer}
+Jeder Thread, der einen Sortierdurchgang durchführen muss, alloziert einen
+Puffer dieser Größe. Setzen Sie diesen Wert herauf, um schnellere
+@code{ORDER BY}- oder @code{GROUP BY}-Operationen zu erhalten.
+@xref{Temporary files}.
+
+@item @code{table_cache}
+Die Anzahl offener Tabellen für alle Threads. Wenn dieser Wert herauf
+gesetzt wird, erhöht sich die Anzahl von Datei-Deskriptoren, die
+@code{mysqld} benötigt. Sie können prüfen, ob Sie den Tabellen-Cache
+vergrößern müssen, indem Sie die @code{Opened_tables}-Variable prüfen.
+@xref{SHOW}. Wenn diese Variable sehr Groß ist und Sie @code{FLUSH TABLES}
+nicht oft brauchen (was lediglich alle Tabellen zwingt, geschlossen und
+wieder geöffnet zu werden), sollten Sie den Wert dieser Variablen herauf
+setzen.
+
+Wegen weiterer Informationen zum Tabellen-Cache sehen Sie unter
+@ref{Open tables} nach.
+
+@item @code{table_type}
+Der vorgabemäßige Tabellentyp.
+
+@item @code{thread_cache_size}
+Wie viele Threads in einem Cache für weitere Benutzung offen gehalten
+werden sollen. Wenn eine Client die Verbindung schließt, werden die
+Threads des Clients in den Cache geschrieben, wenn es nicht mehr als
+@code{Thread_cache_size} Threads als vorher gibt. Alle neuen Threads werden
+zuerst aus dem Cache genommen und nur, wenn der Cache leer ist, wird ein
+neuer Thread erzeugt. Diese Variable kann hoch gesetzt werden, um die
+Performance zu verbessern, wenn Sie sehr viele neue Verbindungen haben.
+(Normalerweise führt das nicht zu namhafter Performance-Steigerung, wenn
+Sie eine gute Thread-Implementierung haben.) Wie effizient der aktuelle
+Thread-Cache für Sie ist, können Sie feststellen, indem Sie den Unterschied
+zwischen @code{Connections} und @code{Threads_created} betrachten.
+
+@item @code{thread_concurrency}
+On Solaris, @code{mysqld} will call @code{thr_setconcurrency()} mit
+this value. @code{thr_setconcurrency()} permits the Applikation to give
+the Threads System a hint für the desired Anzahl von Threads that should
+be run at the same time.
+
+@item @code{thread_stack}
+Die Stack-Größe jedes Threads. Viele der Beschränkungen, die durch den
+@code{crash-me}-Test festgestellt werden, hängen von diesem Wert ab. Der
+Vorgabewert ist Groß genug für normale Operationen.
+@xref{MySQL Benchmarks}.
+
+@item @code{timezone}
+Die Zeitzone für den Server.
+
+@item @code{tmp_table_size}
+Wenn eine temporäre Tabelle im Arbeitsspeicher diese Größe überschreitet,
+wandelt MySQL sie automatisch in eine @code{MyISAM}-Tabelle auf der Platte
+um. Setzen Sie den Wert von @code{tmp_table_size} herauf, wenn Sie viele
+fortgeschrittene @code{GROUP BY}-Anfragen und viel Arbeitsspeicher haben.
+
+@item @code{tmpdir}
+Das Verzeichnis, das für temporäre Dateien und temporäre Tabellen benutzt
+wird.
+
+@item @code{version}
+Die Versionsnummer des Servers.
+
+@item @code{wait_timeout}
+Die Anzahl von Sekunden, die der Server auf Aktivität auf einer Verbindung
+wartet, bevor er sie schließt. Siehe auch @code{interactive_timeout}.
+@end table
+
+Der Handbuchabschnitt, der das Tunen von MySQL beschreibt, enthält einige
+Informationen darüber, wie die oben aufgeführten Variablen getunt werden.
+@xref{Server parameters}.
+
+
+@node SHOW LOGS, SHOW PROCESSLIST, SHOW VARIABLES, SHOW
+@c German node SHOW LOGS
+@subsubsection @code{SHOW LOGS}
+
+@code{SHOW LOGS} zeigt Ihnen Statusinformationen über bestehende
+Log-Dateien. Momentan werden nur Informationen über Berkeley-DB-Log-Dateien
+angezeigt.
+
+@itemize @bullet
+@item @code{File} zeigt den vollen Pfad zur Log-Datei.
+@item @code{Type} zeigt den Typ der Log-Datei (@code{BDB} für
+Berkeley-DB-Log-Dateien).
+@item @code{Status} zeigt den Status der Log-Datei (@code{FREE}, wenn die
+Datei entfernt werden kann, oder @code{IN USE}, wenn die Datei vom
+Transaktions-Subsystem benötigt wird)
+@end itemize
+
+
+@node SHOW PROCESSLIST, SHOW GRANTS, SHOW LOGS, SHOW
+@c German node SHOW PROCESSLIST
+@subsubsection @code{SHOW PROCESSLIST}
+
+@findex Threads
+@findex PROCESSLIST
+
+@cindex Threads, anzeigen
+@cindex Prozesse, anzeigen
+
+@code{SHOW PROCESSLIST} zeigt, welche Threads laufen. Diese Information
+erhalten Sie auch mit dem @code{mysqladmin processlist}-Befehl. Wenn Sie
+die @strong{process}-Berechtigung haben, können Sie alle Threads sehen.
+Ansonsten sehen Sie nur Ihre eigenen Threads. @xref{KILL, , @code{KILL}}.
+Wenn Sie die @code{FULL}-Option nicht benutzen, werden nur die ersten 100
+Zeichen jeder Anfrage gezeigt.
+
+Dieser Befehl ist sehr nützlich, wenn Sie die 'too many
+connections'-Fehlermeldung erhalten und herausfinden wollen, was vor sich
+geht. MySQL reserviert eine zusätzliche Verbindung für einen Client mit der
+@code{Process_priv}-Berechtigung, um sicherzustellen, dass Sie sich
+jederzeit einloggen und das System prüfen können (unter der Annahme, dass
+Sie diese Berechtigung nicht allen Ihren Benutzern geben).
+
+
+@node SHOW GRANTS, SHOW CREATE TABLE, SHOW PROCESSLIST, SHOW
+@c German node SHOW GRANTS
+@subsubsection @code{SHOW GRANTS}
+
+@cindex Berechtigungen, anzeigen
+
+@code{SHOW GRANTS FOR benutzer} listet die @code{Grant}-Befehle auf, die
+abgesetzt werden müssen, um die Berechtigungen für einen Benutzer zu
+duplizieren. Beispiel:
+
+@example
+mysql> SHOW GRANTS FOR root@@localhost;
++----------------------------------------------------------------------+
+| Grants for root@@localhost |
++----------------------------------------------------------------------+
+| GRANT ALL PRIVILEGES ON *.* TO 'root'@@'localhost' WITH GRANT OPTION |
++----------------------------------------------------------------------+
+@end example
+
+
+@node SHOW CREATE TABLE, , SHOW GRANTS, SHOW
+@c German node SHOW CREATE TABLE
+@subsubsection @code{SHOW CREATE TABLE}
+
+Zeigt ein @code{CREATE TABLE}-Statement an, das die angegebene Tabelle
+erzeugt:
+
+@example
+mysql> show create table tabelle\G
+*************************** 1. row ***************************
+ Table: tabelle
+Create Table: CREATE TABLE tabelle (
+ id int(11) default NULL auto_increment,
+ s char(60) default NULL,
+ PRIMARY KEY (id)
+) TYPE=MyISAM
+
+@end example
+
+@code{SHOW CREATE TABLE} setzt Tabellen- und Spaltennamen gemäß der
+@code{SQL_QUOTE_SHOW_CREATE}-Option in Anführungszeichen.
+@ref{SET OPTION, , @code{SET OPTION SQL_QUOTE_SHOW_CREATE}}.
+
+
+@node Localisation, Server-Side Scripts, Database Administration, MySQL Database Administration
+@c German node Lokalisierung
+@section MySQL-Lokalisierung und internationaler Gebrauch
+
+
+
+@menu
+* Character sets::
+* Languages::
+* Adding character set::
+* Character arrays::
+* String collating::
+* Multi-byte characters::
+* Problems with character sets::
+@end menu
+
+@node Character sets, Languages, Localisation, Localisation
+@c German node Zeichensätze
+@subsection Der für Daten und Sortieren benutzte Zeichensatz
+
+@cindex Zeichensätze
+@cindex Daten, Zeichensätze
+@cindex sortieren, Zeichensätze
+
+Vorgabemäßig benutzt MySQL den ISO-8859-1-(Latin1)-Zeichensatz, wobei nach
+schwedischer / finnischer Reihenfolge sortiert wird. Dieser Zeichensatz ist
+für die USA und Westeuropa geeignet.
+
+Alle standardmäßigen MySQL-Binärdistributionen werden mit
+@code{--with-extra-charsets=complex} kompiliert. Das fügt allen
+Standard-Programmen Code hinzu, damit diese @code{latin1} und alle
+Multi-Byte-Zeichensätze in der Binärdatei handhaben können. Andere
+Zeichensätze werden bei Bedarf aus einer Zeichensatz-Definitionsdatei
+geladen.
+
+Der Zeichensatz legt fest, welche Zeichen in Namen erlaubt sind und wie
+Dinge durch die @code{ORDER BY}- und @code{GROUP BY}-Klauseln des
+@code{SELECT}-Statements sortiert werden.
+
+Sie können den Zeichensatz mit der @code{--default-character-set}-Option
+ändern, wenn Sie den Server starten. Die verfügbaren Zeichensätze hängen
+von den @code{--with-charset=charset}- und @code{--with-extra-charset=
+list-of-charset | complex | all}-Optionen für @code{configure} ab und den
+Zeichensatz-Konfigurationsdateien, die in @file{SHAREDIR/charsets/Index}
+aufgeführt sind. @xref{configure options}.
+
+Wenn Sie den Zeichensatz ändern, wenn Sie MySQL laufen lassen (was
+eventuell auch die Sortierreihenfolge ändert), müssen Sie @code{myisamchk
+-r -q} über alle Tabellen laufen lassen. Ansonsten sind Ihre Indexe
+eventuell nicht richtig sortiert.
+
+Wenn sich ein Client mit dem MySQL-Server verbindet, schickt der Server den
+vorgabemäßigen Zeichensatz, der in Benutzung ist, an den Client. Der
+Client schaltet für diese Verbindung auf den Gebrauch dieses Zeichensatzes
+um.
+
+Man sollte bei einer SQL-Anfrage @code{mysql_real_escape_string()}
+benutzen, wenn man Zeichenketten escapet. @code{mysql_real_escape_string()}
+ist identisch mit der alten @code{mysql_escape_string()}-Funktion, ausser
+dass es die MySQL-Connection-Handle als ersten Parameter nimmt.
+
+Wenn der Client mit anderen Pfaden kompiliert wird, als wo der Server
+installiert ist, und der Benutzer, der MySQL konfigurierte, nicht alle
+Zeichensätze in die MySQL-Binärdatei eingeschlossen hat, muss man für den
+Client festlegen, wo dieser die zusätzlichen Zeichensätze finden kann, die
+er benötigt, falls der Server mit einem anderen Zeichensatz läuft als der
+Client.
+
+Das kann man in einer MySQL-Optionsdatei festlegen:
+
+@example
+[client]
+character-sets-dir=/usr/local/mysql/share/mysql/charsets
+@end example
+
+Wobei der Pfad auf das Verzeichnis zeigt, in dem sich die dynamischen
+MySQL-Zeichensätze befinden.
+
+Man kann den Client zwingen, einen bestimmten Zeichensatz zu benutzen,
+indem man angibt:
+
+@example
+[client]
+default-character-set=character-set-name
+@end example
+
+Aber normalerweise wird das nie benötigt.
+
+
+@menu
+* German character set::
+@end menu
+
+@node German character set, , Character sets, Character sets
+@c German node Deutscher Zeichensatz
+@subsubsection Deutscher Zeichensatz
+
+Um eine deutsche Sortierreihenfolge zu erhalten, startet man @code{mysqld}
+mit @code{--default-character-set=latin_de}. Das ergibt die folgenden
+Kennzeichen:
+
+Beim Sortieren und Vergleichen von Zeichenketten wird das folgende Mapping
+auf die Zeichenketten durchgeführt, bevor der Vergleich ausgeführt wird:
+
+@example
+ä -> ae
+ö -> oe
+ü -> ue
+ß -> ss
+@end example
+
+Alle Akzentzeichen werden in ihr Nicht-Akzent-Pendant in Großschreibung
+umgewandelt. Alle Buchstaben werden in Großschreibung umgewandelt.
+
+Beim Zeichenkettenvergleich mit @code{LIKE} wird das Mapping von einem auf
+zwei Buchstaben nicht durchgeführt. Alle Buchstaben werden in
+Großschreibung umgewandelt. Akzente werden aus allen Buchstaben entfernt,
+mit folgenden Ausnahmen: @code{Ü}, @code{ü}, @code{Ö}, @code{ö}, @code{Ä}
+und @code{ä}.
+
+
+@node Languages, Adding character set, Character sets, Localisation
+@c German node Sprachen
+@subsection Nicht englische Fehlermeldungen
+
+@cindex Fehlermeldungen, Sprachen
+@cindex Meldungen, Sprachen
+@cindex Dateien, Fehlermeldungen
+@cindex Sprachunterstützung
+
+@code{mysqld} kann Fehlermeldungen in folgenden Sprachen ausgeben:
+tschechisch, dänisch, niederländisch, englisch (die Vorgabe), estnisch,
+französisch, deutsch, griechisch, ungarisch, italienisch, japanisch,
+koreanisch, norwegisch, norwegisch-ny, polnisch, portugiesisch, rumänisch,
+russisch, slowakisch, spanisch und schwedisch.
+
+Um @code{mysqld} mit einer bestimmten Sprache zu starten, benutzen Sie die
+@code{--language=sprache} oder @code{-L sprache}-Optionen. Beispiel:
+
+@example
+shell> mysqld --language=german
+@end example
+
+oder:
+
+@example
+shell> mysqld --language=/usr/local/share/german
+@end example
+
+Beachten Sie, dass alle Sprachnamen in Kleinschreibung angegeben werden.
+
+Die Sprachdateien liegen (vorgabemäßig) in
+@file{@var{mysql_base_dir}/share/@var{language}/}.
+
+Um die Fehlermeldungsdatei zu aktualisieren, editieren Sie die
+@file{errmsg.txt}-Datei und führen folgenden Befehl aus, um die
+@file{errmsg.sys}-Datei zu erzeugen:
+
+@example
+shell> comp_err errmsg.txt errmsg.sys
+@end example
+
+Wenn Sie auf eine neuere Version von MySQL aktualisieren, denken Sie daran,
+Ihre Änderungen mit der neuen @file{errmsg.txt}-Datei zu wiederholen!
+
+
+@node Adding character set, Character arrays, Languages, Localisation
+@c German node Zeichensatz hinzufügen
+@subsection Einen neuen Zeichensatz hinzufügen
+
+@cindex Zeichensätze, hinzufügen
+@cindex hinzufügen, Zeichensätze
+
+Um MySQL einen weiteren Zeichensatz hinzuzufügen, führen Sie folgende
+Prozedur durch:
+
+Entscheiden Sie, ob der Zeichensatz einfach oder komplex ist. Wenn der
+Zeichensatz keine besonderen Zeichenkettenvergleichsroutinen zum Sortieren
+und keine Multi-Byte-Unterstützung benötigt, ist er einfach. Wenn er eines
+oder beide Features benötigt, ist er komplex.
+
+@code{latin1} und @code{dänisch} zum Beispiel sind einfache Zeichensätze,
+wohingegen @code{big5} oder @code{tschechisch} komplexe Zeichensätze sind.
+
+Im folgenden Abschnitt wird angenommen, dass Sie Ihren Zeichensatz
+@code{MEINSET} nennen.
+
+Bei einem einfachen Zeichensatz machen Sie folgendes:
+
+@enumerate
+@item
+Fügen Sie MEINSET am Ende der @file{sql/share/charsets/Index}-Datei hinzu.
+Geben Sie ihm eine eindeutige Nummer.
+
+@item
+Erzeugen Sie die Datei @file{sql/share/charsets/MEINSET.conf}.
+(Sie können hierfür als Grundlage @file{sql/share/charsets/latin1.conf}
+benutzen).
+
+Die Syntax für die Datei ist sehr einfach:
+
+@itemize @bullet
+@item
+Kommentare fangen mit einem '#'-Zeichen an und gehen bis zum Ende der
+Zeile.
+@item
+Wörter werden durch beliebige Mengen von Leerraum getrennt.
+@item
+Bei der Definition des Zeichensatzes muss jedes Wort eine Zahl im
+hexadezimalen Format sein.
+@item
+Das @code{ctype}-Array nimmt bis zu 257 Wörter auf. Die @code{to_lower}-,
+@code{to_upper}- und @code{sort_order}-Arrays nehmen danach jeweils bis zu
+256 Wörter auf.
+@end itemize
+
+@xref{Character arrays}.
+
+@item
+Fügen Sie den Zeichensatznamen den @code{CHARSETS_AVAILABLE}- und
+@code{COMPILED_CHARSETS}-Listen in @code{configure.in} hinzu.
+
+@item
+Rekonfigurieren, rekompilieren und testen Sie.
+
+@end enumerate
+
+Bei einem komplexen Zeichensatz machen Sie folgendes:
+
+@enumerate
+@item
+Erzeugen Sie die Datei @file{strings/ctype-MEINSET.c} in der
+MySQL-Quelldistribution.
+
+@item
+Fügen Sie MEINSET am Ende der @file{sql/share/charsets/Index}-Datei hinzu.
+Weisen Sie ihm eine eindeutige Nummer zu.
+
+@item
+Sehen Sie sich eine der bestehenden @file{ctype-*.c}-Dateien an, um zu
+sehen, was definiert werden muss, zum Beispiel
+@file{strings/ctype-big5.c}. Beachten Sie, dass die Arrays in Ihrer Datei
+Namen wie @code{ctype_MEINSET}, @code{to_lower_MEINSET} usw. haben müssen.
+Das entspricht den Arrays im einfachen Zeichensatz.
+@xref{Character arrays}. Bei einem komplexen Zeichensatz
+
+@item
+fügen Sie am Anfang der Datei einen speziellen Kommentar wie folgt ein:
+
+@example
+/*
+ * Dieser Kommentar wird von configure geparst, um ctype.c zu erzeugen,
+ * also ändern Sie ihn nicht, wenn Sie nicht genau wissen, was Sie tun.
+ *
+ * .configure. number_MEINSET=MYNUMBER
+ * .configure. strxfrm_multiply_MEINSET=N
+ * .configure. mbmaxlen_MEINSET=N
+ */
+@end example
+
+Das @code{configure}-Programm benutzt diesen Kommentar, um den Zeichensatz
+automatisch in die MySQL-Bibliothek einzufügen.
+
+Die Zeilen mit strxfrm_multiply und mbmaxlen werden in den folgenden
+Abschnitten erläutert. Geben Sie diese nur dann ein, wenn Sie die
+Zeichenketten-Vergleichsfunktionen oder die
+Multi-Byte-Zeichensatzfunktionen benötigen.
+
+@item
+Danach sollten Sie einige der folgenden Funktionen erzeugen:
+
+@itemize @bullet
+@item @code{my_strncoll_MEINSET()}
+@item @code{my_strcoll_MEINSET()}
+@item @code{my_strxfrm_MEINSET()}
+@item @code{my_like_range_MEINSET()}
+@end itemize
+
+@xref{String collating}.
+
+@item
+Fügen Sie den Zeichensatznamen den @code{CHARSETS_AVAILABLE}- und
+@code{COMPILED_CHARSETS}-Listen in @code{configure.in} hinzu.
+
+@item
+Rekonfigurieren, rekompilieren und testen Sie.
+@end enumerate
+
+Die Datei @file{sql/share/charsets/README} enthält einige weitere
+Anweisungen.
+
+Wenn Sie wollen, dass der Zeichensatz in die MySQL-Distribution aufgenommen
+wird, senden Sie einen Patch an @email{internals@@lists.mysql.com}.
+
+
+@node Character arrays, String collating, Adding character set, Localisation
+@c German node Zeichen-Arrays
+@subsection Die Zeichen-Definitions-Arrays
+
+@code{to_lower[]} und @code{to_upper[]} sind einfache Arrays, die die
+Buchstaben in Klein- und Großschreibung enthalten, die jedem Mitglied des
+Zeichensatzes entsprechen. Beispiel:
+
+@example
+to_lower['A'] enthält 'a'
+to_upper['a'] enthält 'A'
+@end example
+
+@code{sort_order[]} ist eine Map, die anzeigt, wie Buchstaben für
+Vergleichs- und Sortierzwecke geordnet werden sollten. Bei vielen
+Zeichensätzen ist das dasselbe wie @code{to_upper[]} (was bedeutet, dass
+das Sortieren ohne Berücksichtigung der Groß-/Kleinschreibung erfolgt).
+MySQL sortiert Buchstaben auf der Grundlage des Wertes von
+@code{sort_order[character]}. Wegen komplizierterer Sortierregeln sehen Sie
+die Erörterung zu Zeichenketten-Vergleichen unten an
+@xref{String collating}.
+
+@code{ctype[]} ist ein Array von Bit-Werten, mit einem Element pro Zeichen.
+(Beachten Sie, dass @code{to_lower[]}, @code{to_upper[]} und
+@code{sort_order[]} durch den Buchstabenwert indiziert werden, aber
+@code{ctype[]} durch den Buchstabenwert + 1. Das ist aus Gründen der
+Abwärtskompatibilität notwendig, um EOF (Dateiende) handhaben zu können.)
+
+Sie finden folgenden Bitmasken-Definitionen in @file{m_ctype.h}:
+
+@example
+#define _U 01 /* Großschreibung */
+#define _L 02 /* Kleinschreibung */
+#define _N 04 /* Numerisch (Ziffer) */
+#define _S 010 /* Leerzeichen */
+#define _P 020 /* Punkt */
+#define _C 040 /* Steuerungszeichen (Control) */
+#define _B 0100 /* leer */
+#define _X 0200 /* heXadezimale Ziffer */
+@end example
+
+Der @code{ctype[]}-Eintrag für jeden Buchstaben sollte die
+Vereinigungsmenge der betreffenden Bitmasken-Werte sein, die den Buchstaben
+beschreiben. @code{'A'} beispielsweise ist Buchstabe in Großschreibung
+(@code{_U}) und gleichzeitig eine hexadezimale Ziffer (@code{_X}), daher
+sollte @code{ctype['A'+1]} folgenden Wert erhalten:
+
+@example
+_U + _X = 01 + 0200 = 0201
+@end example
+
+
+@node String collating, Multi-byte characters, Character arrays, Localisation
+@c German node Zeichenketten-Vergleich
+@subsection Unterstützung für Zeichenketten-Vergleich
+
+@cindex Vergleich, Zeichenketten
+@cindex Zeichenkettenvergleich
+
+Wenn die Sortierregeln Ihrer Sprache zu komplex sind, um durch die einfache
+@code{sort_order[]}-Tabelle gehandhabt zu werden, müssen Sie die
+Zeichenketten-Vergleichsfunktionen benutzen.
+
+Zum jetzigen Zeitpunkt ist die beste Dokumentation hierüber die
+Zeichensätze, die bereits implementiert sind. Sehen Sie sich als Beispiele
+die Zeichensätze big5, tschechisch, gbk, sjis und tis160 an.
+
+Sie müssen den @code{strxfrm_multiply_MEINSET=N}-Wert mit einem speziellen
+Kommentar am Anfang der Datei festlegen. @code{N} sollte auf das höchste
+Verhältnis gesetzt werden, auf das die Zeichenketten während
+@code{my_strxfrm_MEINSET} anwachsen können (es muss eine positive Ganzzahl
+sein).
+
+
+@node Multi-byte characters, Problems with character sets, String collating, Localisation
+@c German node Multi-Byte-Zeichen
+@subsection Unterstützung für Multi-Byte-Zeichen
+
+@cindex Buchstaben, Multi-Byte
+@cindex Multi-Byte-Zeichen
+
+Wenn Sie Unterstützung für einen neuen Zeichensatz hinzufügen wollen, der
+Multi-Byte-Buchstaben enthält, müssen Sie die Multi-Byte-Zeichenfunktionen
+benutzen.
+
+Zum jetzigen Zeitpunkt ist die beste Dokumentation hierüber die
+Zeichensätze, die bereits implementiert sind. Sehen Sie sich als Beispiele
+die Zeichensätze euc_kr, gb2312, gbk, sjis und ujis an. Diese sind in den
+@code{ctype-'charset'.c}-Dateien im @file{strings}-Verzeichnis
+implementiert.
+
+Sie müssen den @code{mbmaxlen_MEINSET=N}-Wert in einem speziellen Kommentar
+am Anfang der Quelldatei angeben. @code{N} sollte auf die Größe in Bytes
+des größten Buchstabens im Zeichensatz gesetzt werden.
+
+@node Problems with character sets, , Multi-byte characters, Localisation
+@c German node Probleme mit Zeichensätzen
+@subsection Probleme mit Zeichensätzen
+
+Wenn Sie versuchen, einen Zeichensatz zu benutzen, der nicht in Ihre
+Binärdatei kompiliert ist, können Sie verschiedene Probleme bekommen:
+
+@itemize @bullet
+@item
+Ihr Programm hat einen falschen Pfad zum Speicherort der Zeichensätze.
+(Vorgabe ist @file{/usr/local/mysql/share/mysql/charsets}). Das kann durch
+die Benutzung der @code{--character-sets-dir}-Option für das fragliche
+Programm behoben werden.
+@item
+Der Zeichensatz ist ein Multi-Byte-Zeichensatz, der nicht dynamisch geladen
+werden kann. Wenn das der Fall ist, müssen Sie das Programm mit
+Unterstützung für diesen Zeichensatz neu kompilieren.
+@item
+Der Zeichensatz ist ein dynamischer Zeichensatz, aber Sie haben keine
+configure-Datei dafür. In diesem Fall müssen Sie die configure-Datei für
+den Zeichensatz aus einer neuen MySQL-Distribution installieren.
+@item
+Ihre @file{Index}-Datei enthält nicht den Namen für den Zeichensatz.
+
+@example
+ERROR 1105: File '/usr/local/share/mysql/charsets/?.conf' not found
+(Errcode: 2)
+@end example
+
+In diesem Fall müssen Sie sich entweder eine neue @code{Index}-Datei holen
+oder den Namen jedes fehlenden Zeichensatzes von Hand eintragen.
+@end itemize
+
+Bei MyISAM-Tabellen können Sie den Zeichensatznamen und die Anzahl für eine
+Tabelle mit @code{myisamchk -dvv tabelle} prüfen.
+
+
+@node Server-Side Scripts, Client-Side Scripts, Localisation, MySQL Database Administration
+@c German node Serverseitige Skripte
+@section Serverseitige Skripte und Dienstprogramme für MySQL
+
+
+
+@menu
+* Server-Side Overview::
+* safe_mysqld::
+* mysqld_multi::
+* myisampack::
+* mysqld-max::
+@end menu
+
+@node Server-Side Overview, safe_mysqld, Server-Side Scripts, Server-Side Scripts
+@c German node Überblick über serverseitige Programme
+@subsection Überblick über serverseitige Programme und Dienstprogramme
+
+@cindex Umgebungsvariablen
+@cindex Programme, Auflistung
+
+Alle MySQL-Clients, die mittels der @code{mysqlclient}-Bibliothek mit dem
+Server kommunizieren, benutzen folgenden Umgebungsvariablen:
+
+@tindex @code{MYSQL_UNIX_PORT}-Umgebungsvariable
+@tindex Umgebungsvariable, @code{MYSQL_UNIX_PORT}
+@tindex @code{MYSQL_TCP_PORT}-Umgebungsvariable
+@tindex Umgebungsvariable, @code{MYSQL_TCP_PORT}
+@tindex @code{MYSQL_PWD}-Umgebungsvariable
+@tindex Umgebungsvariable, @code{MYSQL_PWD}
+@tindex @code{MYSQL_DEBUG}-Umgebungsvariable
+@tindex Umgebungsvariable, @code{MYSQL_DEBUG}
+@multitable @columnfractions .25 .75
+@item @strong{Name} @tab @strong{Beschreibung}
+@item @code{MYSQL_UNIX_PORT} @tab Der vorgabemäßige Socket; benutzt für Verbindungen zu @code{localhost}
+@item @code{MYSQL_TCP_PORT} @tab Der vorgabemäßige TCP/IP-Port
+@item @code{MYSQL_PWD} @tab Das vorgabemäßige Passwort
+@item @code{MYSQL_DEBUG} @tab Debug-Trace-Optionen beim Debuggen
+@item @code{TMPDIR} @tab Das Verzeichnis, in dem temporäre Tabellen / Dateien erzeugt werden
+@end multitable
+
+Die Benutzung von @code{MYSQL_PWD} ist unsicher.
+@xref{Connecting}.
+
+@tindex @code{MYSQL_HISTFILE}-Umgebungsvariable
+@tindex Umgebungsvariable, @code{MYSQL_HISTFILE}
+@tindex @code{HOME}-Umgebungsvariable
+@tindex Umgebungsvariable, @code{HOME}
+@cindex History-Datei
+@cindex Kommandozeilen-History
+@tindex .mysql-History-Datei
+Der @file{mysql}-Client benutzt die Datei, die in der
+@code{MYSQL_HISTFILE}-Umgebungsvariablen angegeben ist, um die
+Kommandozeilen-History zu speichern. Der Vorgabewert für die History-Datei
+ist @file{$HOME/.mysql_history}, wobei @code{$HOME} der Wert der
+@code{HOME}-Umgebungsvariablen ist. @xref{Environment variables}.
+
+Alle MySQL-Programme nehmen viele unterschiedliche Optionen auf. Jedes
+MySQL-Programm bietet jedoch eine @code{--help}-Option, die Sie benutzen
+können, um eine vollständige Beschreibung der unterschiedlichen
+Programmoptionen zu erhalten. Probieren Sie zum Beispiel @code{mysql
+--help} aus.
+
+Sie können Vorgabeoptionen für alle Standard-Client-Programme mit einer
+Optionsdatei überschreiben. @ref{Option files}.
+
+Die unten stehende Liste beschreibt kurz die MySQL-Programme:
+
+@table @code
+
+@cindex @code{myisamchk}
+@item myisamchk
+Dienstprogramm zur Beschreibung, Prüfung, Optimierung und Reparatur von
+MySQL-Tabellen. Weil @code{myisamchk} viele Funktionen hat, ist es in einem
+eigenen Kapitel beschrieben. @xref{MySQL Database Administration}.
+
+@cindex @code{make_binary_distribution}
+@item make_binary_distribution
+Macht ein Binär-Release eines kompilierten MySQL. Dieses könnte über FTP an
+@file{/pub/mysql/Incoming} oder an @code{Support.mysql.com} geschickt
+werden, damit andere MySQL-Benutzer es benutzen können.
+
+@cindex @code{msql2mysql}
+@item msql2mysql
+Ein Shell-Skript, das @code{mSQL}-Programme zu MySQL konvertiert. Es deckt
+nicht alle Fälle ab, ist aber hilfreich, um mit dem Konvertieren
+anzufangen.
+
+@cindex @code{mysqlaccess}
+@item mysqlaccess
+Ein Skript, das die Zugriffsberechtigungen für eine Host-, Benutzer- und
+Datenbank-Kombination prüft.
+
+@cindex @code{mysqladmin}
+@item mysqladmin
+Dienstprogramm für die Durchführung von Verwaltungsoperationen wie Erzeugen
+und Löschen von Datenbanken, Neuladen der Berechtigungstabellen,
+Zurückschreiben von Tabellen auf Platte und Neuöffnen von Log-Dateien.
+@code{mysqladmin} kann auch benutzt werden, um Versionsnummer sowie Status-
+und Prozess-Informationen vom Server zu erhalten.
+@xref{mysqladmin, , @code{mysqladmin}}.
+
+@cindex @code{mysqlbug}
+@item mysqlbug
+Das MySQL-Bug-Bericht-Skript. Dieses Skript sollte immer benutzt werden,
+wenn Sie einen Bug-Bericht an die MySQL-Liste ausfüllen.
+
+@cindex @code{mysqld}
+@item mysqld
+Der SQL-Daemon. Dieser sollte immer laufen.
+
+@cindex @code{mysqldump}
+@item mysqldump
+Dumpt eine MySQL-Datenbank in eine Datei als SQL-Statements oder als
+Tabulator-separierte Textdateien. Verbesserte Freeware, ursprünglich von
+Igor Romanenko. @xref{mysqldump, , @code{mysqldump}}.
+
+@cindex @code{mysqlimport}
+@item mysqlimport
+Importiert Textdateien in die jeweiligen Tabellen mittels @code{LOAD DATA
+INFILE}. @xref{mysqlimport, , @code{mysqlimport}}.
+
+@cindex @code{mysqlshow}
+@item mysqlshow
+Zeigt Informationen über Datenbanken, Tabellen, Spalten und Indexe an.
+
+@cindex @code{mysql_install_db}
+@item mysql_install_db
+Erzeugt die MySQL-Berechtigungstabellen mit vorgabemäßigen Berechtigungen.
+Dieses Skript wird gewöhnlich nur einmal ausgeführt, wenn Sie MySQL das
+erste Mal auf einem System installieren.
+
+@cindex @code{replace}
+@item replace
+Ein Dienstprogramm, das von @code{msql2mysql} benutzt wird, aber auch
+darüber hinaus benutzt werden kann. @code{replace} ändert Zeichenketten in
+Dateien oder auf der Standardeingabe. Benutzt eine finite Status-Maschine,
+um zuerst Übereinstimmung mit längeren Zeichenketten zu finden. Kann
+benutzt werden, um Zeichenketten umzudrehen. Der folgende Befehl zum
+Beispiel dreht @code{a} und @code{b} in den angegebenen Dateien um:
+
+@example
+shell> replace a b b a --Datei1 Datei2 ...
+@end example
+@end table
+
+
+@node safe_mysqld, mysqld_multi, Server-Side Overview, Server-Side Scripts
+@c German node safe_mysqld
+@subsection safe_mysqld, der Wrapper um mysqld
+
+@cindex Werkzeuge, safe_mysqld
+@cindex Skripts
+@cindex @code{safe_mysqld}
+
+@code{safe_mysqld} ist die empfohlene Art, einen @code{mysqld}-Daemon unter
+Unix zu starten. @code{safe_mysqld} fügt einige Sicherheits-Features hinzu
+wie das Neustarten des Servers, wenn ein Fehler auftritt, und das
+Mitschreiben von Laufzeitinformationen in eine Log-Datei.
+
+Wenn Sie nicht @code{--mysqld=#} oder @code{--mysqld-version=#} benutzen,
+benutzt @code{safe_mysqld} eine ausführbare Datei namens @code{mysqld-max},
+wenn es diese gibt. Wenn nicht, startet @code{safe_mysqld} @code{mysqld}.
+Das macht es sehr einfach, @code{mysqld-max} anstelle von @code{mysqld}
+versuchsweise zu benutzen. Kopieren Sie einfach @code{mysqld-max} dorthin,
+wo @code{mysqld} liegt, und es wird benutzt werden.
+
+Normalerweise sollte man das @code{safe_mysqld}-Skript nie editieren,
+sondern statt dessen die Optionen für @code{safe_mysqld} in den
+@code{[safe_mysqld]}-Abschnitt der @code{my.cnf}-Datei einfügen.
+@code{safe_mysqld} liest alle Optionen des @code{[mysqld]}-,
+@code{[server]}- und @code{[safe_mysqld]}-Abschnitts aus den
+Optionsdateien. @xref{Option files}.
+
+Beachten Sie, dass alle Optionen auf der Kommandozeile für
+@code{safe_mysqld} an @code{mysqld} durchgereicht werden. Wenn Sie in
+@code{safe_mysqld} irgend welche Optionen benutzen wollen, die
+@code{mysqld} nicht unterstützt, müssen Sie diese in der Optionsdatei
+angeben.
+
+Die meisten Optionen für @code{safe_mysqld} sind dieselben wie die Optionen
+für @code{mysqld}. @xref{Command-line options}.
+
+@code{safe_mysqld} unterstützt folgende Optionen:
+
+@table @code
+@item --basedir=pfad
+@item --core-file-size=#
+Größe der Core-Datei, die @code{mysqld} in der Lage sein sollte zu
+erzeugen. Wird an @code{ulimit -c} durchgereicht.
+@item --datadir=pfad
+@item --defaults-extra-file=pfad
+@item --defaults-file=pfad
+@item --err-log=pfad
+@item --ledir=pfad
+Pfad zu @code{mysqld}
+@item --log=pfad
+@item --mysqld=mysqld-version
+Name der @code{mysqld}-Version im @code{ledir}-Verzeichnis, die Sie starten
+wollen.
+@item --mysqld-version=version
+Ähnlich wie @code{--mysqld=}, aber hier für nur das Suffix für
+@code{mysqld} angegeben. Wenn Sie zum Beispiel @code{--mysqld-version=max}
+benutzen, startet @code{safe_mysqld} die @code{ledir/mysqld-max}-Version.
+Wenn das Argument für @code{--mysqld-version} leer ist, wird
+@code{ledir/mysqld} benutzt.
+@item --no-defaults
+@item --open-files-limit=#
+Anzahl der Dateien, die @code{mysqld} in der Lage sein sollte zu öffnen.
+Wird an @code{ulimit -n} durchgereicht. Beachten Sie, dass Sie
+@code{safe_mysqld} als Root starten müssen, damit dies korrekt
+funktioniert!
+@item --pid-file=pfad
+@item --port=#
+@item --socket=pfad
+@item --timezone=#
+Setzt die Zeitzone (die @code{TZ})-Variable auf den Wert dieses Parameters.
+@item --user=#
+@end table
+
+Das @code{safe_mysqld}-Skript ist so geschrieben, dass es normalerweise
+einen Server starten kann, der aus einer Quell- oder einer Binärversion von
+MySQL installiert wurde, selbst wenn diese den Server an etwas anderen
+Stellen installieren. @code{safe_mysqld} erwartet, dass eine der folgenden
+Bedingungen zutrifft:
+
+@itemize @bullet
+@item
+Server und Datenbanken liegen relativ zum Verzeichnis, aus dem
+@code{safe_mysqld} aufgerufen wird. @code{safe_mysqld} sucht unterhalb
+seines Arbeitsverzeichnisses nach @file{bin}- und
+@file{data}-Verzeichnissen (bei Binärdistributionen) oder nach
+@file{libexec}- und @file{var}-Verzeichnissen (bei Quelldistributionen).
+Diese Bedingung sollte zutreffen, wenn Sie @code{safe_mysqld} aus Ihrem
+MySQL-Installationsverzeichnis ausführen (zum Beispiel
+@file{/usr/local/mysql} bei einer Binärdistribution).
+
+@item
+Wenn Server und Datenbanken nicht relativ zum Arbeitsverzeichnis liegen,
+versucht @code{safe_mysqld}, sie anhand absoluter Pfadnamen zu finden.
+Typische Speicherort sind @file{/usr/local/libexec} und
+@file{/usr/local/var}. Die tatsächlichen Speicherorte werden festgelegt,
+wenn die Distribution gebaut wird, woher @code{safe_mysqld} kommt. Sie
+sollten korrekt sein, wenn MySQL an einem Standardort installiert wurde.
+@end itemize
+
+Weil @code{safe_mysqld} versucht, Server und Datenbanken relativ zum
+eigenen Arbeitsverzeichnis zu finden, können Sie eine Binärdistribution von
+MySQL irgendwo hin installieren, so lange Sie @code{safe_mysqld} aus dem
+MySQL-Installationsverzeichnis starten:
+
+@example
+shell> cd mysql_installations_verzeichnis
+shell> bin/safe_mysqld &
+@end example
+
+Wenn @code{safe_mysqld} fehlschlägt, selbst wenn es aus dem
+MySQL-Installationsverzeichnis aufgerufen wurde, können Sie es so ändern,
+dass es den Pfad zu @code{mysqld} und die Pfadnamen-Optionen benutzt, die
+auf Ihrem System korrekt sind. Beachten Sie, dass bei zukünftigen
+Aktualisierungen von MySQL Ihre veränderte Version von @code{safe_mysqld}
+überschrieben wird. Daher sollten Sie eine Kopie Ihrer editierten Version
+machen, damit Sie diese neu installieren können.
+
+
+@node mysqld_multi, myisampack, safe_mysqld, Server-Side Scripts
+@c German node mysqld_multi
+@subsection mysqld_multi, Programm zur Verwaltung mehrerer MySQL-Server
+
+@cindex Werkzeuge, mysqld_multi
+@cindex Skripts
+@cindex multi mysqld
+@cindex @code{mysqld_multi}
+
+@code{mysqld_multi} ist für die Verwaltung mehrerer @code{mysqld}-Prozesse
+gedacht, die auf unterschiedlichen UNIX-Sockets und TCP/IP-Ports laufen.
+
+Das Programm sucht nach Gruppe(n), die [mysqld#] benannt sind, in my.cnf
+(oder der angegebenen --config-file=...), wobei # jede positive Zahl ab 1
+sein kann. Diese Gruppen sollten dieselben sein wie die übliche
+@code{[mysqld]}-Gruppe (zum Beispiel Optionen für mysqld, siehe
+ausführliche Informationen im Handbuch über diese Gruppe), aber mit
+denjenigen Port-, Socket- usw. Optionen, die für jeden separaten
+@code{mysqld}-Prozess gewünscht sind. Die Zahl im Gruppennamen hat eine
+andere Funktion: Sie kann benutzt werden, um bestimmte @code{mysqld}-Server
+zu starten, anzuhalten, oder Berichte über sie mit diesem Programm
+auszugeben. Unten stehen weitere Informationen zur Benutzung und zu den
+Optionen.
+
+@example
+Benutzung: mysqld_multi [OPTIONS] @{start|stop|report@} [GNR,GNR,GNR...]
+oder mysqld_multi [OPTIONS] @{start|stop|report@} [GNR-GNR,GNR,GNR-GNR,...]
+@end example
+
+Die GNR oben bedeutet die Gruppennummer. Sie können jede GNR starten,
+anhalten oder Berichtsinformationen über sie ausgeben, oder über mehrere
+von ihnen zugleich. (Siehe --example) Die GNRs in der Liste können mit
+Komma getrennt oder mit Bindestrich kombiniert werden, wobei letzteres
+heißt, dass alle GNRs zwischen GNR1-GNR2 betroffen sind. Ohne GNR-Argument
+werden alle gefundenen Gruppen entweder gestartet, angehalten, oder es
+werden Berichtsinformationen über sie ausgegeben. Beachten Sie, dass Sie in
+der GNR-Liste keinen Leerraum haben dürfen. Alles nach Leerraum wird
+ignoriert.
+
+@code{mysqld_multi} unterstützt folgende Optionen:
+
+@table @code
+@cindex config-file option
+@item --config-file=...
+Alternative config-Datei. HINWEIS: Das betrifft nicht die eigenen Optionen
+des Programms (Gruppe @code{[mysqld_multi]}), sondern nur die Gruppen
+[mysqld#]. Ohne diese Option wird alles aus der normalen my.cnfDatei heraus
+gesucht.
+@cindex Beispiel option
+@item --example
+Zeigt ein Beispiel einer config-Datei.
+@cindex help option
+@item --help
+Hilfetext ausgeben und beenden.
+@cindex log option
+@item --log=...
+Log-Datei. Name und voller Pfad zur Log-Datei. HINWEIS: Wenn es die Datei
+gibt, wird alles angehängt.
+@cindex mysqladmin option
+@item --mysqladmin=...
+@code{mysqladmin}-Binärdatei, die zum Herunterfahren des Servers benutzt
+wird.
+@cindex mysqld option
+@item --mysqld=...
+@code{mysqld}-Binärdatei, die benutzt wird. Beachten Sie, dass Sie auch
+@code{safe_mysqld} diese Option angeben können. Die Optionen werden an
+@code{mysqld} durchgereicht. Stellen Sie jedoch sicher, dass Sie
+@code{mysqld} in Ihrer Umgebungsvariablen @code{PATH} haben oder bearbeiten
+Sie @code{safe_mysqld}.
+@cindex no-log option
+@item --no-log
+An stdout ausgeben statt in die Log-Datei. Vorgabemäßig ist die Log-Datei
+angeschaltet.
+@cindex password option
+@item --password=...
+Passwort für Benutzer von @code{mysqladmin}.
+@cindex tcp-ip option
+@item --tcp-ip
+Zu MySQL-Server(n) über den TCP/IP-Port statt über den UNIX-Socket
+verbinden. Das betrifft das Anhalten und Berichten. Wenn eine Socket-Datei
+fehlt, kann der Server trotzdem laufen, aber man kann nur über den
+TCP/IP-Port auf ihn zugreifen. Vorgabemäßig wird die Verbindung über den
+UNIX-Socket hergestellt.
+@cindex user option
+@item --user=...
+MySQL-Benutzer von @code{mysqladmin}.
+@cindex version option
+@item --version
+Versionsnummer ausgeben und beenden.
+@end table
+
+Einige Anmerkungen zu @code{mysqld_multi}:
+
+@itemize @bullet
+@item
+Stellen Sie sicher, dass der MySQL-Benutzer, der die @code{mysqld}-Dienste
+anhält (indem er zum Beispiel @code{mysqladmin} benutzt), dasselbe Passwort
+und denselben Benutzernamen für alle Daten-Verzeichnisse benutzt, auf die
+zugegriffen wird (zur 'mysql'-Datenbank). Stellen Sie ausserdem sicher,
+dass der Benutzer die 'Shutdown_priv'-Berechtigung hat! Wenn Sie viele
+Daten-Verzeichnisse und viele verschiedene 'mysql'-Datenbanken mit
+unterschiedlichen Passwörtern für den MySQL-'root'-Benutzer haben, sollten
+Sie einen allgemeinen 'multi_admin'-Benutzer anlegen, der dasselbe Passwort
+benutzt (siehe unten). Hier ein Beispiel dafür:
+@example
+shell> mysql -u root -S /tmp/mysql.sock -proot_password -e
+"GRANT SHUTDOWN ON *.* TO multi_admin@@localhost IDENTIFIED BY 'multipass'"
+@xref{Privileges}.
+@end example
+Das oben Angegebene müssen Sie für jeden laufenden @code{mysqld} im
+Daten-Verzeichnis tun, das Sie haben (ändern Sie einfach den Socket,
+-S=...).
+@item
+@code{pid-file} ist sehr wichtig, wenn Sie @code{safe_mysqld} benutzen, um
+@code{mysqld} zu starten (zum Beispiel --mysqld=safe_mysqld). Jeder
+@code{mysqld} sollte seine eigene @code{pid-file} haben. Der Vorteil der
+Benutzung von @code{safe_mysqld} anstelle von @code{mysqld} direkt ist
+hierbei, dass @code{safe_mysqld} jeden @code{mysqld}-Prozess 'bewacht' und
+neu startet, falls ein @code{mysqld}-Prozess wegen eines Signals kill -9
+fehlschlägt oder ähnliches (wenn beispielsweise Speicherzugriffsfehler
+auftreten, was bei MySQL natürlich nie passiert ;-). Beachten Sie bitte,
+dass es für das @code{safe_mysqld}-Skript eventuell erforderlich ist, es
+von einer bestimmten Stelle aus zu starten. Das heißt, dass Sie eventuell
+in ein bestimmtes Verzeichnis wechseln müssen, bevor Sie
+@code{mysqld_multi} starten. Wenn Sie beim Starten Probleme haben, sehen
+Sie bitte im @code{safe_mysqld}-Skript nach. Überprüfen Sie insbesondere
+folgende Zeilen:
+@example
+--------------------------------------------------------------------------
+MY_PWD=`pwd` Check if we are starting this relative (for the binary
+release) if test -d /data/mysql -a -f ./share/mysql/englisch/errmsg.sys
+-a -x ./bin/mysqld
+--------------------------------------------------------------------------
+@xref{safe_mysqld, , @code{safe_mysqld}}.
+@end example
+Der obige Test soll erfolgreich verlaufen, ansonsten können Sie Probleme
+bekommen.
+@item
+Vermeiden Sie Gefahren, die auftauchen, wenn Sie mehrere @code{mysqlds} im
+selben Daten-Verzeichnis starten. Benutzen Sie unterschiedlichen
+Daten-Verzeichnisse, es sei denn, Sie wissen @strong{GENAU}, was Sie tun!
+@item
+Die Socket-Datei und der TCP/IP-Port müssen für jeden @code{mysqld}
+verschieden sein.
+@item
+Die erste und die fünfte @code{mysqld}-Gruppe wurden beim Beispiel
+absichtlich ausgelassen. Sie haben eventuell 'Lücken' in der config-Datei.
+Das gibt Ihnen mehr Flexibilität. Die Reihenfolge, in der die
+@code{mysqlds} gestartet oder angehalten werden, hängt von der Reihenfolge
+ab, in der sie in der config-Datei erscheinen.
+@item
+Wenn Sie auf eine bestimmte Gruppe verweisen wollen, wenn Sie GNR bei
+diesem Programm benutzen, nehmen Sie einfach die Nummer am Ende des
+Gruppennamens ( [mysqld# <== ).
+@item
+Eventuell sollten Sie die Option '--user' für @code{mysqld} benutzen, aber
+um das zu tun, müssen Sie root sein, wenn Sie das
+@code{mysqld_multi}-Skript starten. Wenn Sie die Option in der config-Datei
+haben, macht das nichts; Sie erhalten nur eine Warnmeldung, wenn Sie nicht
+der Superuser sind und die @code{mysqlds} unter @strong{IHREM} UNIX-Account
+gestartet werden. @strong{WICHTIG}: Stellen Sie sicher, dass die
+@code{pid-file} und das Daten-Verzeichnis für @strong{DENJENIGEN}
+UNIX-Benutzer lesbar und schreibbar sind (und ausführbar im letzteren
+Fall), als der der spezifische @code{mysqld}-Prozess gestartet wird.
+Benutzen Sie hier @strong{NICHT} den UNIX-root-Account, es sei denn, Sie
+wissen @strong{GENAU}, was Sie tun!
+@item
+@strong{SEHR WICHTIG}: Stellen Sie sicher, dass Sie die Bedeutung der
+Optionen verstehen, die an die @code{mysqlds} durchgereicht werden und
+@strong{WARUM} Sie mehrere verschiedene @code{mysqld}-Prozesse haben
+wollen. Mehrere @code{mysqlds} in einem Daten-Verzeichnis starten
+@strong{ergibt keine zusätzliche Performance} bei einem threaded System!
+@end itemize
+
+@xref{Multiple servers}.
+
+Hier ist ein Beispiel einer config-Datei für @code{mysqld_multi}.
+
+@example
+# Diese Datei sollte wahrscheinlich in Ihrem Heimatverzeichnis liegen (~/.my.cnf) oder in /etc/my.cnf
+# Version 2.1 von Jani Tolonen
+
+[mysqld_multi]
+mysqld = /usr/local/bin/safe_mysqld
+mysqladmin = /usr/local/bin/mysqladmin
+user = multi_admin
+password = multipass
+
+[mysqld2]
+socket = /tmp/mysql.sock2
+port = 3307
+pid-file = /usr/local/mysql/var2/hostname.pid2
+datadir = /usr/local/mysql/var2
+language = /usr/local/share/mysql/english
+user = john
+
+[mysqld3]
+socket = /tmp/mysql.sock3
+port = 3308
+pid-file = /usr/local/mysql/var3/hostname.pid3
+datadir = /usr/local/mysql/var3
+language = /usr/local/share/mysql/swedish
+user = monty
+
+[mysqld4]
+socket = /tmp/mysql.sock4
+port = 3309
+pid-file = /usr/local/mysql/var4/hostname.pid4
+datadir = /usr/local/mysql/var4
+language = /usr/local/share/mysql/estonian
+user = tonu
+
+[mysqld6]
+socket = /tmp/mysql.sock6
+port = 3311
+pid-file = /usr/local/mysql/var6/hostname.pid6
+datadir = /usr/local/mysql/var6
+language = /usr/local/share/mysql/japanese
+user = jani
+@end example
+
+@xref{Option files}.
+
+
+@node myisampack, mysqld-max, mysqld_multi, Server-Side Scripts
+@c German node myisampack
+@subsection myisampack, MySQL-Programm zum Erzeugen komprimierter Nur-Lese-Tabellen
+
+@cindex komprimierte Tabellen
+@cindex Tabellen, komprimierte
+@cindex MyISAM, komprimierte Tabellen
+@cindex @code{myisampack}
+@cindex @code{pack_isam}
+
+@code{myisampack} wird benutzt, um MyISAM-Tabellen zu komprimieren.
+@code{pack_isam} wird benutzt, um ISAM-Tabellen zu komprimieren. Weil
+ISAM-Tabellen veraltet sind, wird hier nur @code{myisampack} erörtert, aber
+alles, was auf @code{myisampack} zutrifft, gilt auch für @code{pack_isam}.
+
+@code{myisampack} funktioniert, indem jede Spalte in der Tabelle separat
+komprimiert wird. Die Informationen, die benötigt werden, um Spalten zu
+dekomprimieren, werden in den Arbeitsspeicher gelesen, wenn die Tabelle
+geöffnet wird. Das ergibt viel bessere Performance beim Zugriff auf
+einzelne Datensätze, denn man muss nur exakt einen Datensatz
+dekomprimieren, nicht einen viel größeren Block, wie das zum Beispiel bei
+der Benutzung von Stacker auf MS-DOS nötig ist. Üblicherweise komprimiert
+@code{myisampack} die Daten-Datei auf 40%-70%.
+
+MySQL benutzt Speicher-Mapping (@code{mmap()}) auf komprimierte Tabellen
+und geht zu normalen Lesen / Schreiben von Dateien zurück, wenn
+@code{mmap()} nicht funktioniert.
+
+Für @code{myisampack} gibt es momentan zwei Einschränkungen:
+@itemize @bullet
+@item
+Nach dem Komprimieren ist die Tabelle nur-lesbar.
+@item
+@code{myisampack} kann auch @code{BLOB}- oder @code{TEXT}-Spalten
+komprimieren. Das ältere @code{pack_isam} konnte das nicht.
+@end itemize
+
+Die Behebung dieser Einschränkungen steht mit niedrigen Priorität auf
+unserer TODO-Liste.
+
+@code{myisampack} wird wie folgt aufgerufen:
+
+@example
+shell> myisampack [options] Dateiname ...
+@end example
+
+Jeder Dateiname sollte der Name einer Index-(@file{.MYI})-Datei sein. Wenn
+Sie nicht im Datenbank-Verzeichnis sind, müssen Sie den Pfadnamen zur Datei
+angeben. Die @file{.MYI} Erweiterung kann weggelassen werden.
+
+@code{myisampack} unterstützt folgende Optionen:
+
+@table @code
+@item -b, --backup
+Stellt eine Datensicherung der Tabelle als @code{tabelle.OLD} her.
+
+@item -#, --debug=debug_options
+Debug-Log ausgeben. Die @code{debug_options}-Zeichenkette ist häufig
+@code{'d:t:o,filename'}.
+
+@item -f, --force
+Erzwingt die Komprimierung der Tabelle, selbst wenn sie dadurch größer
+wird oder die temporäre Datei existiert. @code{myisampack} erzeugt eine
+temporäre Datei namens @file{tabelle.TMD}, während es die Tabelle
+komprimiert. Wenn Sie @code{myisampack} killen, kann es sein, dass die
+@file{.TMD}-Datei nicht gelöscht wird. Normalerweise wird @code{myisampack}
+mit einer Fehlermeldung beendet, wenn es eine existierende
+@file{tabelle.TMD}-Datei findet. Mit @code{--force} packt @code{myisampack}
+die Tabelle trotzdem.
+
+@item -?, --help
+Hilfetext ausgeben und beenden.
+
+@item -j große_tabelle, --join=große_tabelle
+Verbindet alle Tabellen, die auf der Kommandozeile angegeben wurden, in
+eine einzige große Tabelle @code{große_tabelle}. Alle Tabellen, die
+kombiniert werden sollen, MÜSSEN identisch sein (dieselben Spaltennamen und
+-typen, dieselben Indexe usw.).
+
+@item -p #, --packlength=#
+Legt die Speichergröße der Datensatzlänge in Bytes fest. Der Wert sollte
+1, 2 oder 3 sein. (@code{myisampack} speichert alle Zeilen mit
+Längenzeigern von 1, 2, oder 3 Bytes. In den meisten Fällen kann
+@code{myisampack} den richtigen Längenwert festlegen, bevor es anfängt, die
+Datei zu komprimieren. Während des Komprimierungsprozesses stellt es aber
+eventuell fest, dass es eine kürzere Länge hätte nehmen können. In diesem
+Fall gibt @code{myisampack} einen Hinweis aus, dass Sie beim nächsten Mal,
+wenn Sie dieselbe Datei packen, eine kürzere Datensatzlänge nehmen
+sollten.)
+
+@item -s, --silent
+Schweigsamer Modus. Ausgaben erfolgen nur, wenn Fehler auftreten.
+
+@item -t, --test
+Tabelle nicht tatsächlich komprimieren, sondern nur testweise packen.
+
+@item -T dir_name, --tmp_dir=dir_name
+Das genannte Verzeichnis als Speicherort der temporären Tabelle benutzen.
+
+@item -v, --verbose
+Geschwätziger Modus. Informationen über den Fortschritt und das
+Komprimierungsergebnis ausgeben.
+
+@item -V, --version
+Versionsinformationen ausgeben und beenden.
+
+@item -w, --wait
+Warten und noch einmal versuchen, wenn die Tabelle in Benutzung ist. Wenn
+der @code{mysqld}-Server mit der @code{--skip-locking}-Option aufgerufen
+wurde, ist es keine gute Idee, @code{myisampack} aufzurufen, wenn die
+Tabelle während des Komprimierungsprozesses möglicherweise aktualisiert
+wird.
+@end table
+
+@cindex Beispiele, komprimierte Tabellen
+Die unten stehende Befehlssequenz zeigt eine typische
+Tabellen-Komprimierungssitzung:
+
+@example
+shell> ls -l station.*
+-rw-rw-r-- 1 monty my 994128 Apr 17 19:00 station.MYD
+-rw-rw-r-- 1 monty my 53248 Apr 17 19:00 station.MYI
+-rw-rw-r-- 1 monty my 5767 Apr 17 19:00 station.frm
+
+shell> myisamchk -dvv station
+
+MyISAM file: station
+Isam-version: 2
+Creation time: 1996-03-13 10:08:58
+Recover time: 1997-02-02 3:06:43
+Data records: 1192 Deleted blocks: 0
+Datafile: Parts: 1192 Deleted data: 0
+Datafile pointer (bytes): 2 Keyfile pointer (bytes): 2
+Max datafile length: 54657023 Max keyfile length: 33554431
+Recordlength: 834
+Record format: Fixed length
+
+table description:
+Key Start Len Index Type Root Blocksize Rec/key
+1 2 4 unique unsigned long 1024 1024 1
+2 32 30 multip. text 10240 1024 1
+
+Field Start Length Type
+1 1 1
+2 2 4
+3 6 4
+4 10 1
+5 11 20
+6 31 1
+7 32 30
+8 62 35
+9 97 35
+10 132 35
+11 167 4
+12 171 16
+13 187 35
+14 222 4
+15 226 16
+16 242 20
+17 262 20
+18 282 20
+19 302 30
+20 332 4
+21 336 4
+22 340 1
+23 341 8
+24 349 8
+25 357 8
+26 365 2
+27 367 2
+28 369 4
+29 373 4
+30 377 1
+31 378 2
+32 380 8
+33 388 4
+34 392 4
+35 396 4
+36 400 4
+37 404 1
+38 405 4
+39 409 4
+40 413 4
+41 417 4
+42 421 4
+43 425 4
+44 429 20
+45 449 30
+46 479 1
+47 480 1
+48 481 79
+49 560 79
+50 639 79
+51 718 79
+52 797 8
+53 805 1
+54 806 1
+55 807 20
+56 827 4
+57 831 4
+
+shell> myisampack station.MYI
+Compressing station.MYI: (1192 records)
+- Calculating statistics
+
+normal: 20 empty-space: 16 empty-zero: 12 empty-fill: 11
+pre-space: 0 end-space: 12 table-lookups: 5 zero: 7
+Original trees: 57 After join: 17
+- Compressing file
+87.14%
+
+shell> ls -l station.*
+-rw-rw-r-- 1 monty my 127874 Apr 17 19:00 station.MYD
+-rw-rw-r-- 1 monty my 55296 Apr 17 19:04 station.MYI
+-rw-rw-r-- 1 monty my 5767 Apr 17 19:00 station.frm
+
+shell> myisamchk -dvv station
+
+MyISAM file: station
+Isam-version: 2
+Creation time: 1996-03-13 10:08:58
+Recover time: 1997-04-17 19:04:26
+Data records: 1192 Deleted blocks: 0
+Datafile: Parts: 1192 Deleted data: 0
+Datafilepointer (bytes): 3 Keyfile pointer (bytes): 1
+Max datafile length: 16777215 Max keyfile length: 131071
+Recordlength: 834
+Record format: Compressed
+
+table description:
+Key Start Len Index Type Root Blocksize Rec/key
+1 2 4 unique unsigned long 10240 1024 1
+2 32 30 multip. text 54272 1024 1
+
+Field Start Length Type Huff tree Bits
+1 1 1 constant 1 0
+2 2 4 zerofill(1) 2 9
+3 6 4 no zeros, zerofill(1) 2 9
+4 10 1 3 9
+5 11 20 table-lookup 4 0
+6 31 1 3 9
+7 32 30 no endspace, not_always 5 9
+8 62 35 no endspace, not_always, no empty 6 9
+9 97 35 no empty 7 9
+10 132 35 no endspace, not_always, no empty 6 9
+11 167 4 zerofill(1) 2 9
+12 171 16 no endspace, not_always, no empty 5 9
+13 187 35 no endspace, not_always, no empty 6 9
+14 222 4 zerofill(1) 2 9
+15 226 16 no endspace, not_always, no empty 5 9
+16 242 20 no endspace, not_always 8 9
+17 262 20 no endspace, no empty 8 9
+18 282 20 no endspace, no empty 5 9
+19 302 30 no endspace, no empty 6 9
+20 332 4 always zero 2 9
+21 336 4 always zero 2 9
+22 340 1 3 9
+23 341 8 table-lookup 9 0
+24 349 8 table-lookup 10 0
+25 357 8 always zero 2 9
+26 365 2 2 9
+27 367 2 no zeros, zerofill(1) 2 9
+28 369 4 no zeros, zerofill(1) 2 9
+29 373 4 table-lookup 11 0
+30 377 1 3 9
+31 378 2 no zeros, zerofill(1) 2 9
+32 380 8 no zeros 2 9
+33 388 4 always zero 2 9
+34 392 4 table-lookup 12 0
+35 396 4 no zeros, zerofill(1) 13 9
+36 400 4 no zeros, zerofill(1) 2 9
+37 404 1 2 9
+38 405 4 no zeros 2 9
+39 409 4 always zero 2 9
+40 413 4 no zeros 2 9
+41 417 4 always zero 2 9
+42 421 4 no zeros 2 9
+43 425 4 always zero 2 9
+44 429 20 no empty 3 9
+45 449 30 no empty 3 9
+46 479 1 14 4
+47 480 1 14 4
+48 481 79 no endspace, no empty 15 9
+49 560 79 no empty 2 9
+50 639 79 no empty 2 9
+51 718 79 no endspace 16 9
+52 797 8 no empty 2 9
+53 805 1 17 1
+54 806 1 3 9
+55 807 20 no empty 3 9
+56 827 4 no zeros, zerofill(2) 2 9
+57 831 4 no zeros, zerofill(1) 2 9
+@end example
+
+Die Informationen, die @code{myisampack} ausgibt, sind unten beschrieben:
+
+@table @code
+@item normal
+Die Anzahl von Spalten, für die keine spezielle Komprimierung benutzt wird.
+
+@item empty-space
+Die Anzahl von Spalten, die Werte enthalten, die ausschließlich aus
+Leerzeichen bestehen. Diese Werte nehmen 1 Bit in Anspruch.
+
+@item empty-zero
+Die Anzahl von Spalten, die Werte enthalten, die nur aus binären Nullen
+bestehen. Diese Werte nehmen 1 Bit in Anspruch.
+
+@item empty-fill
+Die Anzahl von Ganzzahl-Spalten, die nicht den gesamten Bereich Ihres Typs
+einnehmen. Diese werden auf einen kleineren Typ geändert (eine
+@code{INTEGER}-Spalte kann zum Beispiel auf @code{MEDIUMINT} geändert
+werden).
+
+@item pre-space
+Die Anzahl von Dezimal-Spalten, die mit führenden Leerzeichen gespeichert
+sind. In diesem Fall enthält jeder Wert einen Zähler für die Anzahl
+führender Leerzeichen.
+
+@item end-space
+Die Anzahl von Spalten, die viele Leerzeichen am Ende enthalten. In diesem
+Fall enthält jeder Wert einen Zähler für die Anzahl von Leerzeichen am
+Ende.
+
+@item table-lookup
+Die Spalte hat nur eine kleine Anzahl verschiedener Werte, die in
+@code{ENUM} umgewandelt werden, bevor die Huffman-Kompression durchgeführt
+wird.
+
+@item zero
+Die Anzahl von Spalten, bei denen alle Werte 0 sind.
+
+@item Original trees
+Die anfängliche Anzahl von Huffman-Bäumen.
+
+@item After join
+Die Anzahl von unterschiedlichen Huffman-Bäumen, die übrig sind, nachdem
+Bäume zusammengefasst wurden, um etwas Header-Platz zu sparen.
+@end table
+
+Nachdem eine Tabelle komprimiert wurde, gibt @code{myisamchk -dvv}
+zusätzliche Informationen über jedes Feld aus:
+
+@table @code
+@item Type
+Der Feldtyp kann folgende Deskriptoren enthalten:
+
+@table @code
+@item constant
+Alle Zeilen haben denselben Wert.
+
+@item no endspace
+Kein Leerzeichen am Ende speichern.
+
+@item no endspace, not_always
+Kein Leerzeichen am Ende speichern und bei allen Werten keine Komprimierung
+für Leerzeichen am Ende durchführen.
+
+@item no endspace, no empty
+Kein Leerzeichen am Ende speichern. Keine leeren Werte speichern.
+
+@item table-lookup
+Die Spalte wurde zu @code{ENUM} umgewandelt.
+
+@item zerofill(n)
+Die wichtigsten @code{n} Bytes im Wert sind immer 0 und wurden nicht
+gespeichert.
+
+@item no zeros
+Keine Nullen speichern.
+
+@item always zero
+0-Werte sind in 1 Bit gespeichert.
+@end table
+
+@item Huff tree
+Der Huffman-Baum, der zu dem Feld gehört.
+
+@item Bits
+Die Anzahl von Bits, die im Huffman-Baum benutzt werden.
+@end table
+
+Nachdem Sie @code{pack_isam}/@code{myisampack} laufen gelassen haben,
+müssen Sie @code{isamchk} / @code{myisamchk} laufen lassen, um den Index
+neu zu erzeugen. Zugleich können Sie die Index-Blöcke sortieren und die
+Statistiken erzeugen, die benötigt werden, damit der MySQL-Optimierer
+effizienter läuft:
+
+@example
+myisamchk -rq --analyze --sort-index tabelle.MYI
+isamchk -rq --analyze --sort-index tabelle.ISM
+@end example
+
+Nachdem Sie die komprimierte Tabelle ins MySQL-Datenbank-Verzeichnis
+gespielt haben, müssen Sie @code{mysqladmin flush-tables} ausführen, um
+@code{mysqld} anzuweisen, die neue Tabelle zu benutzen.
+
+Wenn Sie eine gepackte Tabelle entpacken wollen, können Sie das mit der
+@code{--unpack}-Option für @code{isamchk} oder @code{myisamchk} tun.
+
+
+@node mysqld-max, , myisampack, Server-Side Scripts
+@c German node mysqld-max
+@subsection mysqld-max, ein erweiterter mysqld-Server
+
+@cindex @code{mysqld-max}
+
+@code{mysqld-max} ist der MySQL-Server (@code{mysqld}), der mit folgenden
+configure-Optionen konfiguriert wurde:
+
+@multitable @columnfractions .3 .7
+@item @strong{Option} @tab @strong{Kommentar}
+@item --with-server-suffix=-max @tab Zur @code{mysqld}-Versionszeichenkette ein Suffix hinzufügen.
+@item --with-bdb @tab Unterstützung für Berkeley-DB-(BDB)-Tabellen
+@item --with-innodb @tab Unterstützung für InnoDB-Tabellen.
+@item CFLAGS=-DUSE_SYMDIR @tab Symbolische-Links-Unterstützung für Windows.
+@end multitable
+
+Sie finden die MySQL-max-Binärdateien unter
+@uref{http://www.mysql.com/downloads/mysql-max-3.23.html}.
+
+Die Windows-MySQL-3.23-Binärdistribution beinhaltet sowohl die
+Standard-@code{mysqld.exe}-Binärdatei als auch die
+@code{mysqld-max.exe}-Binärdatei.
+@uref{http://www.mysql.com/downloads/mysql-3.23.html}.
+@xref{Windows installation}.
+
+Beachten Sie, dass, weil InnoDB und Berkeley-DB nicht für alle Plattformen
+verfügbar sind, einige der @code{Max}-Binärdateien eventuell noch
+Unterstützung für diese beiden Typen haben. Sie können überprüfen, welche
+Tabellentypen unterstützt werden, indem Sie die folgende Anfrage ausführen:
+
+@example
+mysql> show variables like "have_%";
++---------------+-------+
+| Variable_name | Value |
++---------------+-------+
+| have_bdb | YES |
+| have_innodb | NO |
+| have_isam | YES |
+| have_raid | NO |
+| have_openssl | NO |
++---------------+-------+
+@end example
+
+Die Bedeutung dieser Werte ist:
+
+@multitable @columnfractions .3 .7
+@item @strong{Wert} @tab @strong{Bedeutung}.
+@item YES @tab Die Option ist aktiviert und benutzbar.
+@item NO @tab MySQL ist nicht mit Unterstützung für diese Option kompiliert.
+@item DISABLED @tab Die xxxx-Option ist deaktiviert, weil @code{mysqld} mit @code{--skip-xxxx} gestartet wurde oder weil @code{mysqld} nicht mit allen notwendigen Optionen gestartet wurde, um die Option zu aktivieren. In diesem Fall sollte die @code{hostname.err}-Datei den Grund dafür enthalten, warum die Option deaktiviert wurde.
+@end multitable
+
+@strong{HINWEIS}: Um InnoDB-Tabellen erzeugen zu können, @strong{MÜSSEN}
+Sie Ihre Startoptionen editieren und zumindest die
+@code{innodb_data_file_path}-Option eingeben. @xref{InnoDB start}.
+
+Um bessere Performance für BDB-Tabellen zu erzielen, sollten Sie auch für
+diese einige Konfigurationsoptionen angeben. @xref{BDB start}.
+
+@code{safe_mysqld} versucht automatisch, eine @code{mysqld}-Binärdatei mit
+dem @code{-max}-Präfix zu starten. Das macht es sehr einfach, eine andere
+@code{mysqld}-Binärdatei in einer bestehenden Installation auszutesten.
+Lassen Sie einfach @code{configure} mit den Optionen, die Sie wollen,
+laufen, und installieren Sie dann die neue @code{mysqld}-Binärdatei als
+@code{mysqld-max} im selben Verzeichnis, wo Ihre alte
+@code{mysqld}-Binärdatei liegt. @xref{safe_mysqld, , @code{safe_mysqld}}.
+
+Der @code{mysqld-max}-RPM benutzt das oben erwähnte
+@code{safe_mysqld}-Feature. Er installiert nur die ausführbare Datei
+@code{mysqld-max} und @code{safe_mysqld} benutzt diese automatisch, wenn
+@code{safe_mysqld} neu gestartet wird.
+
+Folgende Tabelle zeigt, welche Tabellentypen unsere
+Standard-@strong{MySQL-Max}-Binärdateien beinhalten:
+
+@multitable @columnfractions .4 .3 .3
+@item @strong{System} @tab @strong{BDB} @tab @strong{InnoDB}
+@item AIX 4.3 @tab NEIN @tab JA
+@item HP-UX 11.0 @tab NEIN @tab JA
+@item Linux-Alpha @tab NEIN @tab JA
+@item Linux-Intel @tab JA @tab JA
+@item Linux-Ia64 @tab NEIN @tab JA
+@item Solaris-intel @tab NEIN @tab JA
+@item Solaris-sparc @tab JA @tab JA
+@item SCO OSR5 @tab JA @tab JA
+@item UnixWare @tab JA @tab JA
+@item Windows/NT @tab JA @tab JA
+@end multitable
+
+
+@node Client-Side Scripts, Log Files, Server-Side Scripts, MySQL Database Administration
+@c German node Clientseitige Skripte
+@section Clientseitige Skripte und Hilfsprogramme von MySQL
+
+
+
+@menu
+* Client-Side Overview::
+* mysql::
+* mysqladmin::
+* Using mysqlcheck::
+* mysqldump::
+* mysqlhotcopy::
+* mysqlimport::
+* mysqlshow::
+* perror::
+* Batch Commands::
+@end menu
+
+@node Client-Side Overview, mysql, Client-Side Scripts, Client-Side Scripts
+@c German node Überblick über die clientseitigen Skripte
+@subsection Überblick über die clientseitigen Skripte und Dienstprogramme
+
+@cindex Umgebungsvariablen
+@cindex Programme, Auflistung
+
+Alle MySQL-Clients, die mittels der @code{mysqlclient}-Bibliothek mit dem
+Server kommunizieren, benutzen folgende Umgebungsvariablen:
+
+@tindex @code{MYSQL_UNIX_PORT}-Umgebungsvariable
+@tindex Umgebungsvariable, @code{MYSQL_UNIX_PORT}
+@tindex @code{MYSQL_TCP_PORT}-Umgebungsvariable
+@tindex Umgebungsvariable, @code{MYSQL_TCP_PORT}
+@tindex @code{MYSQL_PWD}-Umgebungsvariable
+@tindex Umgebungsvariable, @code{MYSQL_PWD}
+@tindex @code{MYSQL_DEBUG}-Umgebungsvariable
+@tindex Umgebungsvariable, @code{MYSQL_DEBUG}
+@multitable @columnfractions .25 .75
+@item @strong{Name} @tab @strong{Beschreibung}
+@item @code{MYSQL_UNIX_PORT} @tab Der vorgabemäßige Socket, benutzt für Verbindungen zu @code{localhost}
+@item @code{MYSQL_TCP_PORT} @tab Der vorgabemäßige TCP/IP-Port
+@item @code{MYSQL_PWD} @tab Das vorgabemäßige Passwort
+@item @code{MYSQL_DEBUG} @tab Debug-Trace-Optionen beim Debuggen
+@item @code{TMPDIR} @tab Das Verzeichnis, in dem temporäre Tabellen / Dateien erzeugt werden
+@end multitable
+
+Die Benutzung von @code{MYSQL_PWD} ist unsicher.
+@xref{Connecting}.
+
+@tindex @code{MYSQL_HISTFILE}-Umgebungsvariable
+@tindex Umgebungsvariable, @code{MYSQL_HISTFILE}
+@tindex @code{HOME}-Umgebungsvariable
+@tindex Umgebungsvariable, @code{HOME}
+@cindex History-Datei
+@cindex Kommandozeilen-History
+@tindex .mysql_History-Datei
+Der @file{mysql}-Client benutzt die Datei in der @code{MYSQL_HISTFILE}-
+Umgebungsvariablen genannte Datei, um die Kommandozeilen-History zu
+speichern. Der Vorgabewert für die History-Datei ist
+@file{$HOME/.mysql_history}, wobei @code{$HOME} der Wert der
+@code{HOME}-Umgebungsvariablen ist. @xref{Environment variables}.
+
+Alle MySQL-Programme haben viele verschiedene Optionen. Jedes
+MySQL-Programm stellt jedoch ein @code{--help}-Option zur Verfügung, die
+Sie benutzen können, um eine vollständige Beschreibung der verschiedenen
+Optionen des Programms zu erhalten. Probieren Sie zum Beispiel @code{mysql
+--help} aus.
+
+Sie können die vorgabemäßigen Optionen für alle Standard-Client-Programme
+mit einer Optionsdatei überschreiben. @ref{Option files}.
+
+Die unten stehende Liste beschreibt kurz die MySQL-Programme:
+
+@table @code
+@cindex @code{myisamchk}
+@item myisamchk
+Dienstprogramm zur Beschreibung, Prüfung, Optimierung und Reparatur von
+MySQL-Tabellen. Weil @code{myisamchk} viele Funktionen hat, ist es in einem
+eigenen Kapitel beschrieben. @xref{MySQL Database Administration}.
+
+@cindex @code{make_binary_distribution}
+@item make_binary_distribution
+Macht ein Binär-Release eines kompilierten MySQL. Dieses könnte über FTP an
+@file{/pub/mysql/Incoming} oder an @code{Support.mysql.com} geschickt
+werden, damit andere MySQL-Benutzer es benutzen können.
+
+@cindex @code{msql2mysql}
+@item msql2mysql
+Ein Shell-Skript, das @code{mSQL}-Programme zu MySQL konvertiert. Es deckt
+nicht alle Fälle ab, ist aber hilfreich, um mit dem Konvertieren
+anzufangen.
+
+@cindex @code{mysqlaccess}
+@item mysqlaccess
+Ein Skript, das die Zugriffsberechtigungen für eine Host-, Benutzer- und
+Datenbank-Kombination prüft.
+
+@cindex @code{mysqladmin}
+@item mysqladmin
+Dienstprogramm für die Durchführung von Verwaltungsoperationen wie Erzeugen
+und Löschen von Datenbanken, Neulanden der Berechtigungstabellen,
+Zurückschreiben von Tabellen auf Platte und Neuöffnen von Log-Dateien.
+@code{mysqladmin} kann auch benutzt werden, um Versionsnummer sowie Status-
+und Prozess-Informationen vom Server zu erhalten.
+@xref{mysqladmin, , @code{mysqladmin}}.
+
+@cindex @code{mysqlbug}
+@item mysqlbug
+Das MySQL-Bug-Bericht-Skript. Dieses Skript sollte immer benutzt werden,
+wenn Sie einen Bug-Bericht an die MySQL-Liste ausfüllen.
+
+@cindex @code{mysqld}
+@item mysqld
+Der SQL-Daemon. Dieser sollte immer laufen.
+
+@cindex @code{mysqldump}
+@item mysqldump
+Dumpt eine MySQL-Datenbank in eine Datei als SQL-Statements oder als
+Tabulator-separierte Textdateien. Verbesserte Freeware, ursprünglich von
+Igor Romanenko. @xref{mysqldump, , @code{mysqldump}}.
+
+@cindex @code{mysqlimport}
+@item mysqlimport
+Importiert Textdateien in die jeweiligen Tabellen mittels @code{LOAD DATA
+INFILE}. @xref{mysqlimport, , @code{mysqlimport}}.
+
+@cindex @code{mysqlshow}
+@item mysqlshow
+Zeigt Informationen über Datenbanken, Tabellen, Spalten und Indexe an.
+
+@cindex @code{mysql_install_db}
+@item mysql_install_db
+Erzeugt die MySQL-Berechtigungstabellen mit vorgabemäßigen Berechtigungen.
+Dieses Skript wird gewöhnlich nur einmal ausgeführt, wenn Sie MySQL das
+erste Mal auf einem System installieren.
+
+@cindex @code{replace}
+@item replace
+Ein Dienstprogramm, das von @code{msql2mysql} benutzt wird, aber auch
+darüber hinaus benutzt werden kann. @code{replace} ändert Zeichenketten in
+Dateien oder auf der Standardeingabe. Benutzt eine finite Status-Maschine,
+um zuerst Übereinstimmung mit längeren Zeichenketten zu finden. Kann
+benutzt werden, um Zeichenketten umzudrehen. Der folgende Befehl zum
+Beispiel dreht @code{a} und @code{b} in den angegebenen Dateien um:
+
+@example
+shell> replace a b b a --Datei1 Datei2 ...
+@end example
+@end table
+
+
+@node mysql, mysqladmin, Client-Side Overview, Client-Side Scripts
+@c German node mysql
+@subsection Das Kommandozeilen-Werkzeug
+
+@cindex Kommandozeilen-Werkzeug
+@cindex Werkzeuge, Kommandozeile
+@cindex Skripte
+@cindex @code{mysql}
+
+@code{mysql} ist eine einfache SQL-Shell (mit GNU
+@code{readline}-Fähigkeiten). Sie unterstützt interaktiven und nicht
+interaktiven Gebrauch. Wenn sie interaktiv benutzt wird, werden
+Anfrageergebnisse in einem ASCII-Tabellenformat ausgegeben. Wenn sie nicht
+interaktiv benutzt wird (zum Beispiel als Filter), wird das Ergebnis in
+Tabulator-separiertem Format ausgegeben. (Das Ausgabeformat kann mit den
+Kommandozeilenoptionen geändert werden.) Skripte können Sie einfach wie
+folgt laufen lassen:
+
+@example
+shell> mysql datenbank < skript.sql > ausgabe.tab
+@end example
+
+Wenn Sie Probleme haben, die auf ungenügenden Speicher beim Client
+zurückzuführen sind, benutzen Sie die @code{--quick}-Option! Diese zwingt
+@code{mysql}, @code{mysql_use_result()} statt @code{mysql_store_result()}
+zu benutzen, um die Ergebnismenge zu holen.
+
+Die Benutzung von @code{mysql} ist sehr einfach. Starten Sie es einfach wie
+folgt:
+@code{mysql datenbank} oder @code{mysql --user=benutzername
+--password=ihr_passwort datenbank}. Geben Sie ein SQL-Statement ein,
+beenden Sie es mit @samp{;}, @samp{\g} oder @samp{\G}, und drücken Sie die
+Eingabetaste.
+
+@cindex @code{mysql}-Kommandozeilenoptionen
+@cindex Kommandozeilenoptionen, @code{mysql}
+@cindex Optionen, Kommandozeile, @code{mysql}
+@cindex Startparameter, @code{mysql}
+@code{mysql} unterstützt folgende Optionen:
+
+@table @code
+@cindex @code{help}, @code{mysql}-Option
+@item -?, --help
+Hilfetext ausgeben und beenden.
+
+@cindex @code{no-auto-rehash}, @code{mysql}-Option
+@item -A, --no-auto-rehash
+Kein automatisches Rehashing. Man muss 'rehash' benutzen, um Tabellen- und
+Feld-Vervollständigung zu erhalten. Durch die Option wird mysql schneller
+gestartet.
+
+@cindex @code{batch}, @code{mysql}-Option
+@item -B, --batch
+Ergebnisse mit einem Tabulator als Trennzeichen ausgeben, jede
+Tabellenzeile auf einer neuen Zeile. Keine History-Datei benutzen.
+
+@cindex @code{character-sets-dir}, @code{mysql}-Option
+@item --character-sets-dir=...
+Verzeichnis, in dem sich die Zeichensätze befinden.
+
+@cindex @code{compress}, @code{mysql}-Option
+@item -C, --compress
+Im Client-Server-Protokoll Komprimierung benutzen.
+
+@cindex @code{debug}, @code{mysql}-Option
+@item -#, --debug[=...]
+Debug loggen. Vorgabe ist 'd:t:o,/tmp/mysql.trace'.
+
+@cindex @code{database}, @code{mysql}-Option
+@item -D, --database=...
+Datenbank, die benutzt werden soll. Hauptsächlich nützlich in der
+@code{my.cnf}-Datei.
+
+@cindex @code{default-character-set}, @code{mysql}-Option
+@item --default-character-set=...
+Den vorgabemäßigen Zeichensatz setzen.
+
+@cindex @code{execute}, @code{mysql}-Option
+@item -e, --execute=...
+Befehl ausführen und beenden. (Ausgabe wie bei --batch)
+
+@cindex @code{vertical}, @code{mysql}-Option
+@item -E, --vertical
+Ausgabe einer Anfrage (Zeilen) vertikal darstellen. Ohne diese Option
+können Sie diese Ausgabe auch dadurch erzwingen, dass Sie Ihre Statements
+mit @code{\G} beenden.
+
+@cindex @code{force}, @code{mysql}-Option
+@item -f, --force
+Weitermachen, auch wenn ein SQL-Fehler auftritt.
+
+@cindex @code{no-named-commands}, @code{mysql}-Option
+@item -g, --no-named-commands
+Benannte Befehle werden deaktiviert. Benutzen Sie nur die \*-Form, oder
+benutzen Sie benannte Befehle nur bei Zeilen, die mit einem Semikolon
+enden. Ab Version 10.9 startet der Client vorgabemäßig mit ANGESCHALTETER
+Option! Wenn die -g-Option angeschaltet ist, funktionieren Befehle im
+Langformat jedoch immer noch von der ersten Zeile aus.
+
+@cindex @code{enable-named-commands}, @code{mysql}-Option
+@item -G, --enable-named-commands
+Benannte Befehle sind @strong{angeschaltet}. Befehle im Langformat sind
+ebenso zugelassen wie die abgekürzten \*-Befehle.
+
+@cindex @code{ignore-space}, @code{mysql}-Option
+@item -i, --ignore-space
+Leerzeichen nach Funktionsnamen ignorieren.
+
+@cindex @code{host}, @code{mysql}-Option
+@item -h, --host=...
+Connect to the given host.
+
+@cindex @code{html}, @code{mysql}-Option
+@item -H, --html
+HTML-Ausgabe produzieren.
+
+@cindex @code{skip-line-numbers}, @code{mysql}-Option
+@item -L, --skip-line-numbers
+Bei Fehlern keine Zeilennummer ausgeben. Nützlich, wenn man mit
+Ergebnisdateien vergleichen will, die Fehlermeldungen enthalten.
+
+@cindex @code{no-pager}, @code{mysql}-Option
+@item --no-pager
+Pager deaktivieren und nach stdout ausgeben. Siehe auch interaktive Hilfe
+(\h).
+
+@cindex @code{no-tee}, @code{mysql}-Option
+@item --no-tee
+Ausgabedatei (Outfile) deaktivieren. Siehe auch interaktive Hilfe (\h).
+
+@cindex @code{unbuffered}, @code{mysql}-Option
+@item -n, --unbuffered
+Nach jeder Anfrage Buffer zurückschreiben (flush).
+
+@cindex @code{skip-column-names}, @code{mysql}-Option
+@item -N, --skip-column-names
+In Ergebnissen keine Spaltennamen ausgeben.
+
+@cindex @code{set-variable}, @code{mysql}-Option
+@item -O, --set-variable var=option
+Einer Variablen einen Wert zuweisen. @code{--help} listet Variablen auf.
+
+@cindex @code{one-database}, @code{mysql}-Option
+@item -o, --one-database
+Nur die vorgabemäßige Datenbank aktualisieren. Das ist nützlich, wenn man
+in der Update-Logdatei Aktualisierungen (Updates) auf eine andere Datenbank
+überspringen will.
+
+@cindex @code{pager}, @code{mysql}-Option
+@item @code{--pager[=...]}
+Ausgabetyp. Vorgabe ist Ihre @code{ENV}-Variable @code{PAGER}. Gültige
+Pager sind less, more, cat [> Dateiname] usw. Siehe auch interaktive Hilfe
+(\h). Diese Option funktioniert nicht im Stapelmodus. Der Pager
+funktioniert nur unter UNIX.
+
+@cindex @code{password}, @code{mysql}-Option
+@item -p[password], --password[=...]
+Passwort, das für die Verbindung zum Server benutzt wird. Wenn das Passwort
+nicht auf der Kommandozeile angegeben wird, wird eine Eingabeaufforderung
+dafür ausgegeben. Beachten Sie: Wenn Sie die Kurzform @code{-p} benutzen,
+darf zwischen der Option und dem Passwort kein Leerzeichen stehen.
+
+@cindex @code{port}, @code{mysql}-Option
+@item -P --port=...
+TCP/IP-Portnummer, die für die Verbindung benutzt wird.
+
+@cindex @code{quick}, @code{mysql}-Option
+@item -q, --quick
+Ergebnisse nicht cachen, Zeile für Zeile ausgeben. Das kann den Server
+verlangsamen, wenn die Ausgabe verschoben wird. Keine History-Datei
+benutzen.
+
+@cindex @code{raw}, @code{mysql}-Option
+@item -r, --raw
+Spaltenwerte ohne Escape-Umwandlung schreiben. Benutzt für @code{--batch}.
+
+@cindex @code{silent}, @code{mysql}-Option
+@item -s, --silent
+Schweigsamer sein.
+
+@cindex @code{socket}, @code{mysql}-Option
+@item -S --socket=...
+Socket-Datei, die für die Verbindung benutzt wird.
+
+@cindex @code{table}, @code{mysql}-Option
+@item -t --table
+Ausgabe im Tabellenformat. Das ist die Vorgabe im Nicht-Stapelmodus.
+
+@cindex @code{debug-info}, @code{mysql}-Option
+@item -T, --debug-info
+Beim Verlassen einige Debug-Informationen ausgeben.
+
+@cindex @code{tee}, @code{mysql}-Option
+@item --tee=...
+Alles an die Ausgabedatei anhängen. Siehe auch interaktive Hilfe (\h).
+Funktioniert nicht im Stapelmodus.
+
+@cindex @code{user}, @code{mysql}-Option
+@item -u, --user=#
+Benutzer zum Einloggen, falls nicht der aktuelle UNIX-Benutzer.
+
+@cindex @code{safe-updates}, @code{mysql}-Option
+@item -U, --safe-updates[=#], --i-am-a-dummy[=#]
+Läßt nur @code{UPDATE} und @code{DELETE} zu, die Schlüssel benutzen. Siehe
+unten wegen weiterer Informationen über diese Option. Sie können diese
+Option zurücksetzen, wenn Sie sie in Ihrer @code{my.cnf}-Datei haben, indem
+Sie @code{--safe-updates=0} benutzen.
+
+@cindex @code{verbose}, @code{mysql}-Option
+@item -v, --verbose
+Geschwätzigere Ausgabe (-v -v -v ergibt das Tabellen-Ausgabeformat).
+
+@cindex @code{version}, @code{mysql}-Option
+@item -V, --version
+Versionsinformationen ausgeben und beenden.
+
+@cindex @code{wait}, @code{mysql}-Option
+@item -w, --wait
+Wenn die Verbindung geschlossen wurde, warten und noch einmal versuchen,
+statt abzubrechen.
+@end table
+
+Mit @code{-O} oder @code{--set-variable} können Sie auch die folgenden
+Variablen setzen:
+
+@cindex timeout, @code{connect_timeout}-Variable
+@cindex @code{connect_timeout}-Variable
+@cindex @code{max_allowed_packet}
+@cindex @code{net_buffer_length}
+@cindex @code{select_limit}
+@cindex @code{max_join_size}
+@multitable @columnfractions .3 .2 .5
+@item Variablenname @tab Vorgabe @tab Beschreibung
+@item connect_timeout @tab 0 @tab Anzahl von Sekunden, bevor die Verbindung wegen Zeitüberschreitung abgebrochen wird
+@item max_allowed_packet @tab 16777216 @tab Maximale Paketlänge, die zum Server gesendet bzw. von diesem empfangen wird
+@item net_buffer_length @tab 16384 @tab Puffer für TCP/IP- und Socket-Kommunikation
+@item select_limit @tab 1000 @tab Automatisches Limit für SELECT bei Benutzung von --i-am-a-dummy
+@item max_join_size @tab 1000000 @tab Automatisches Limit für Zeilen in einem Join bei Benutzung von --i-am-a-dummy.
+@end multitable
+
+Wenn Sie 'help' auf der Kommandozeile eingeben, gibt @code{mysql} die
+Befehle aus, die es unterstützt:
+
+@cindex Befehle, Auflistung
+@example
+mysql> help
+
+MySQL-Befehle:
+help (\h) Diesen Text anzeigen.
+? (\h) Synonym für `help'.
+clear (\c) Lösch-Befehl.
+connect (\r) Erneut mit dem Server verbinden. Optionale Argumente sind db und host.
+edit (\e) Befehl mit $EDITOR editieren.
+ego (\G) Befehl an den MySQL-Server schicken, Ergebnis vertikal anzeigen.
+exit (\q) mysql beenden. Dasselbe wie quit.
+go (\g) Befehl an den MySQL-Server schicken.
+nopager (\n) Pager deaktivieren, nach stdout ausgeben.
+notee (\t) Nicht in die Ausgabedatei (Outfile) schreiben.
+pager (\P) PAGER [auf_pager] setzen. Anfrageergebnisse über PAGER ausgeben.
+print (\p) Aktuellen Befehl ausgeben.
+quit (\q) mysql beenden.
+rehash (\#) Vervollständigungs-Hash neu aufbauen.
+source (\.) Eine SQLsSkriptdatei ausführen. Benötigt einen Dateinamen als Argument.
+status (\s) Statusinformationen vom Server abrufen.
+tee (\T) Ausgabedatei [auf_outfile] setzen. Alles an die angegebene Ausgabedatei anhängen.
+use (\u) Eine andere Datenbankbenutzung. Benötigt Datenbanknamen als Argument.
+@end example
+
+Bei diesen Befehlen funktioniert PAGER nur unter UNIX.
+
+@cindex status command
+Der @code{status}-Befehl gibt Ihnen einige Informationen über die
+Verbindung und den Server, den Sie benutzen. Wenn der Server im
+@code{--safe-updates}-Modus läuft, gibt @code{status} auch die Werte der
+@code{mysql}-Variablen aus, die Ihre Anfragen beeinflussen.
+
+@cindex @code{safe-mode}-Befehl
+Eine nützliche Startoption für Anfänger (eingeführt in MySQL-Version
+3.23.11) ist @code{--safe-updates} (oder @code{--i-am-a-dummy} für
+Benutzer, die irgendwann ein @code{DELETE FROM tabelle} eingeben, aber
+vergessen, die @code{WHERE}-Klausel) zu benutzen. Wenn Sie diese Option
+benutzen, schickt @code{mysql} beim Öffnen der Verbindung folgenden Befehl
+an den MySQL-Server:
+
+@example
+SET SQL_SAFE_UPDATES=1,SQL_SELECT_LIMIT=#select_limit#,
+ SQL_MAX_JOIN_SIZE=#max_join_size#"
+@end example
+
+Wobei @code{#select_limit#} und @code{#max_join_size#} Variablen sind, die
+auf der @code{mysql}-Kommandozeile gesetzt werden können.
+@c German FIX unsplit @xref
+@xref{SET OPTION}.
+
+Die Auswirkung davon ist folgende:
+
+@itemize @bullet
+@item
+@code{UPDATE}- oder @code{DELETE}-Statements ohne Schlüsselbeschränkung im
+@code{WHERE}-Teil sind nicht zugelassen. Man kann jedoch ein
+@code{UPDATE/DELETE} durch die Benutzung von @code{LIMIT} erzwingen:
+@example
+UPDATE tabelle SET not_key_column=# WHERE not_key_column=# LIMIT 1;
+@end example
+@item
+Alle großen Ergebnisse werden automatisch auf @code{#select_limit#} Zeilen
+begrenzt.
+@item
+@code{SELECT}'s, die wahrscheinlich mehr als @code{#max_join_size}
+Zeilenkombinationen durchgehen müssen, werden abgebrochen.
+@end itemize
+
+Einige nützliche Anmerkungen zum @code{mysql}-Client:
+
+Einige Daten sind lesbarer, wenn sie vertikal angezeigt werden statt auf
+die übliche horizontale kastenähnliche Art. Langer Text zum Beispiel, der
+Zeilenumbrüche beinhaltet, ist bei vertikaler Ausgabe meist viel einfacher
+zu lesen.
+
+@example
+mysql> select * from mails where length(txt) < 300 limit 300,1\G
+*************************** 1. row ***************************
+ msg_nro: 3068
+ date: 2000-03-01 23:29:50
+time_zone: +0200
+mail_from: Monty
+ reply: monty@@no.spam.com
+ mail_to: "Thimble Smith" <tim@@no.spam.com>
+ sbj: UTF-8
+ txt: >>>>> "Thimble" == Thimble Smith writes:
+
+Thimble> Hi. Meines Erachtens eine gute Idee. Kennt sich jemand mit UTF-8
+Thimble> oder Unicode aus? Ansonsten packe ich das auf meine TODO-Liste
+Thimble> und warte, was passiert.
+
+Ja, mach das bitte!
+
+Regards,
+Monty
+ Datei: inbox-jani-1
+ hash: 190402944
+1 row in set (0.09 sec)
+@end example
+
+@itemize @bullet
+@item
+Zum Mitloggen benutzen Sie die @code{tee}-Option. @code{tee} wird mit der
+Option @code{--tee=...} oder interaktiv auf der Kommandozeile mi dem Befehl
+@code{tee} gestartet. Alle Daten, die auf dem Bildschirm erscheinen, werden
+auch in die angegebene Datei geschrieben. Das kann auch für Debug-Zwecke
+sehr hilfreich sein. @code{tee} kann von der Kommandozeile aus mit dem
+Befehl @code{notee} deaktiviert werden. Wenn @code{tee} noch einmal
+eingegeben wird, wird wiederum mit dem Loggen begonnen. Ohne Parameter wird
+die vorherige Datei wiederum benutzt. Beachten Sie, dass @code{tee} die
+Ergebnisse nach jedem Befehl in die Datei zurückschreibt, direkt bevor die
+Kommandozeilenaufforderung für den nächsten Befehl erscheint.
+
+@item
+Das Durchstöbern oder Durchsuchen der Ergebnisse im interaktiven Modus in
+UNIX-less, -more oder einem ähnlichen Programm ist jetzt möglich mit der
+Option @code{--pager[=...]}. Ohne Argument aufgerufen sieht der
+@code{mysql}-Client in der Umgebungsvariablen PAGER nach und setzt
+@code{pager} auf diesen Wert. @code{pager} kann von der interaktiven
+Kommandozeile mit dem Befehl @code{pager} gestartet und mit @code{nopager}
+deaktiviert werden. Optional nimmt der Befehl ein Argument entgegen und
+setzt @code{pager} darauf. @code{pager} kann ohne Argument aufgerufen
+werden, aber das erfordert, dass die Option @code{--pager} benutzt wurde,
+ansonsten gibt @code{pager} in stdout aus. @code{pager} funktioniert nur
+unter UNIX, denn es benutzt die popen()-Funktion, die es unter Windows
+nicht gibt. Unter Windows kann statt dessen die @code{tee}-Option benutzt
+werden, wenngleich diese in manchen Situationen nicht ganz so handlich ist
+wie @code{pager}.
+
+@item
+Ein paar Tipps zu @code{pager}: Sie können es benutzen, um in eine Datei zu
+schreiben:
+@example
+mysql> pager cat > /tmp/log.txt
+@end example
+Die Ergebnisse werden nur in eine Datei geschrieben. Sie können auch
+Optionen an Programme übergeben, die Sie mit @code{pager} zusammen benutzen
+wollen:
+@example
+mysql> pager less -n -i -S
+@end example
+Beachten Sie hierbei die Option '-S'. Beim Durchstöbern der Ergebnisse
+werden Sie diese wahrscheinlich als sehr nützlich erachten. Probieren Sie
+dei Option mit horizontaler Ausgabe (Befehle enden mit '\g', oder ';') und
+mit vertikaler Ausgabe (Befehle enden mit '\G') aus. Manchmal ist ein sehr
+breites Ergebnis schwer am Bildschirm zu lesen. Mit der Option -S für less
+können Sie die Ergebnisse im interaktiven less von links nach rechts
+durchstöbern, wobei verhindert wird, dass Zeilen, die länger sind als Ihre
+Bildschirmbreite, in die nächste Zeile umgebrochen werden. Das kann ein
+Ergebnis sehr viel lesbarer gestalten. Sie können den Modus im interaktiven
+less an- und abschalten, wenn Sie '-S' benutzen. Siehe 'h' für weitere
+Hilfe zu less.
+
+@item
+Zum Schluss (falls Sie das nicht schon aus den oben aufgeführten Beispielen
+heraus gefunden haben ;-) können Sie sehr komplexe Dinge tun, um die
+Ergebnisse zu handhaben. Folgendes würde die Ergebnisse beispielsweise an
+zwei verschiedene Dateien in zwei unterschiedlichen Verzeichnissen
+schicken, auf zwei unterschiedlichen Festplatten, die auf /dr1 und /dr2
+gemountet sind, und dennoch die Ergebnisse über less am Bildschirm
+anzeigen:
+@example
+mysql> pager cat | tee /dr1/tmp/res.txt | tee /dr2/tmp/res2.txt | less -n -i -S
+@end example
+
+@item
+Sie können die obigen Funktionen auch kombinieren, indem Sie @code{tee}
+anschalten und @code{pager} auf 'less' setzen. Dann können Sie die
+Ergebnisse in 'less' durchstöbern und trotzdem wird alles zugleich an eine
+Datei angehängt. Der Unterschied zwischen @code{UNIX tee}, was mit
+@code{pager} benutzt wird, und dem im @code{mysql}-Client eingebauten
+@code{tee} ist, dass das eingebaute @code{tee} sogar dann funktioniert,
+wenn kein @code{UNIX tee} verfügbar ist. Darüber hinaus gibt das eingebaute
+@code{tee} alles, was mitgeloggt wird, auch am Bildschirm aus, wohingegen
+das @code{UNIX tee} in Verbindung mit @code{pager} nicht so viel mitloggt.
+Letztlich läßt sich das interaktive @code{tee} auch handlicher aus- und
+einschalten, wenn Sie teilweise mitloggen wollen, aber in der Lage sein,
+das Feature zwischendurch auszuschalten.
+@end itemize
+
+
+@node mysqladmin, Using mysqlcheck, mysql, Client-Side Scripts
+@c German node mysqladmin
+@subsection mysqladmin, Verwaltung eines MySQL-Servers
+
+@cindex Administration, Server
+@cindex Serververwaltung
+@cindex @code{mysladmn}
+
+Ein Dienstprogramm, um Verwaltungsoperationen durchzuführen. Die Syntax ist::
+
+@example
+shell> mysqladmin [OPTIONS] befehl [befehl-option] befehl ...
+@end example
+
+Sie erhalten eine Auflistung der Optionen, die Ihre
+@code{mysqladmin}-Version unterstützt, indem Sie @code{mysqladmin --help}
+ausführen.
+
+Das aktuelle @code{mysqladmin} unterstützt folgende Befehle:
+
+@table @code
+@item create datenbank
+Eine neue Datenbank erzeugen.
+
+@item drop datenbank
+Eine Datenbank und alle ihre Tabellen löschen.
+
+@item extended-status
+Eine erweiterte Statusmeldung vom Server ausgeben.
+
+@item flush-hosts
+Alle gecacheten Hosts zurückschreiben (flush).
+
+@item flush-logs
+Alle Logs zurückschreiben (flush).
+
+@item flush-tables
+Alle Tabellen zurückschreiben (flush).
+
+@item flush-privileges
+Berechtigungstabellen neu laden (dasselbe wie reload).
+
+@item kill id,id,...
+MySQL-Threads killen.
+
+@item password
+Ein neues Passwort setzen. Altes Passwort zu neuem Passwort ändern.
+
+@item ping
+Überprüfen, ob mysqld lebt.
+
+@item processlist
+Auflistung aktiver Threads im Server.
+
+@item reload
+Berechtigungstabellen neu laden.
+
+@item refresh
+Alle Tabellen zurückschreiben (flush), Log-Dateien schließen und erneut
+öffnen.
+
+@item shutdown
+Server herunter fahren.
+
+@item slave-start
+Slave-Replikations-Thread starten.
+
+@item slave-stop
+Slave-Replikations-Thread anhalten.
+
+@item status
+Eine kurze Statusmeldung vom Server ausgeben.
+
+@item variables
+Verfügbare Variablen ausgeben.
+
+@item version
+Versionsinformation vom Server abrufen.
+@end table
+
+Alle Befehle können auf ihr eindeutiges Präfix abgekürzt werden. Beispiel:
+
+@example
+shell> mysqladmin proc stat
++----+-------+-----------+----+-------------+------+-------+------+
+| Id | User | Host | db | Command | Time | State | Info |
++----+-------+-----------+----+-------------+------+-------+------+
+| 6 | monty | localhost | | Processlist | 0 | | |
++----+-------+-----------+----+-------------+------+-------+------+
+Uptime: 10077 Threads: 1 Questions: 9 Slow queries: 0 Opens: 6 Flush tables: 1 Open tables: 2 Memory in use: 1092K Max memory used: 1116K
+@end example
+
+@cindex Status-Befehl, Ergebnisse
+Das Ergebnis des @code{mysqladmin status}-Befehls hat folgende Spalten:
+
+@cindex uptime
+@multitable @columnfractions .3 .7
+@item Uptime @tab Anzahl von Sekunden, seit der MySQL-Server hoch gefahren ist.
+@cindex Threads
+@item Threads @tab Anzahl aktiver Threads (Clients).
+@cindex questions
+@item Questions @tab Anzahl von Questions von Clients, seit @code{mysqld} gestartet wurde.
+@cindex slow queries
+@item Slow queries @tab Anfragen, die länger als @code{long_query_time} Sekunden benötigten. @xref{Slow query log}.
+@cindex opens
+@item Opens @tab Wie viele Tabellen @code{mysqld} geöffnet hat.
+@cindex flush tables
+@cindex tables, flush
+@item Flush Tables @tab Anzahl von @code{flush ...}-, @code{refresh}- und @code{reload}-Befehlen.
+@cindex open tables
+@item Open Tables @tab Anzahl der Tabellen, die gerade geöffnet sind.
+@cindex memory use
+@item Memory in use @tab Arbeitsspeicher, der direkt vom @code{mysqld}-Code beansprucht wird (nur verfügbar, wenn MySQL mit --with-debug=full kompiliert wurde).
+@cindex max memory used
+@item Max memory used @tab Maximaler Arbeitsspeicher, der direkt vom @code{mysqld}-Code beansprucht wird (nur verfügbar, wenn MySQL mit --with-debug=full kompiliert wurde).
+@end multitable
+
+Wenn Sie @code{mysqladmin shutdown} auf einem Socket ausführen (mit anderen
+Worten, auf dem Computer, wo @code{mysqld} läuft), wartet
+@code{mysqladmin}, bis MySQL die @code{pid-file} entfernt hat, um
+sicherzustellen, dass der @code{mysqld}-Server korrekt angehalten wurde.
+
+
+@node Using mysqlcheck, mysqldump, mysqladmin, Client-Side Scripts
+@c German node mysqlcheck
+@subsection Benutzung von @code{mysqlcheck} für Tabellenwartung und Wiederherstellung nach Abstürzen
+
+Ab MySQL-Version 3.23.38 können Sie ein neues Prüf- und Reparatur-Werkzeug
+für @code{MyISAM}-Tabellen einsetzen. Der Unterschied zu @code{myisamchk}
+ist, dass @code{mysqlcheck} benutzt werden kann, wenn der
+@code{mysqld}-Server läuft, wohingegen @code{myisamchk} nur benutzt werden
+sollte, wenn er nicht läuft. Der Vorteil ist, dass Sie den Server zum
+Prüfen oder zur Reparatur Ihrer Tabellen nicht mehr herunter fahren müssen.
+
+@code{mysqlcheck} benutzt die MySQL-Server-Befehle @code{CHECK},
+@code{REPAIR}, @code{ANALYZE} und @code{OPTIMIZE} auf eine für den Benutzer
+bequeme Weise.
+
+Es gibt drei alternative Möglichkeiten, @code{mysqlcheck} aufzurufen:
+
+@example
+shell> mysqlcheck [OPTIONS] datenbank [tabellen]
+shell> mysqlcheck [OPTIONS] --databases datenbank1 [datenbank2 datenbank3...]
+shell> mysqlcheck [OPTIONS] --all-databases
+@end example
+
+Daher kann es hinsichtlich der Auswahl von Datenbanken und Tabellen ähnlich
+wie @code{mysqldump} benutzt werden.
+
+@code{mysqlcheck} besitzt im Vergleich zu den anderen Clients ein
+besonderes Feature: Das vorgabemäßige Verhalten, Tabellen mit -c zu
+prüfen, kann geändert werden, indem die Binärdatei umbenannt wird. Wenn Sie
+nur ein Werkzeug haben wollen, das vorgabemäßig Tabellen repariert,
+kopieren Sie eine @code{mysqlcheck} mit einem neuen Namen auf Ihre
+Festplatte, nämlich @code{mysqlrepair}, oder legen alternativ einen
+symbolischen Link auf @code{mysqlrepair} und benennen den Link
+@code{mysqlrepair}. Wenn Sie jetzt @code{mysqlrepair} aufrufen, repariert
+es vorgabemäßig Tabellen.
+
+Folgende Namen können Sie benutzen, um das vorgabemäßige Verhalten von
+@code{mysqlcheck} zu verändern:
+
+@example
+mysqlrepair: Vorgabe-Option: -r (reparieren)
+mysqlanalyze: Vorgabe-Option: -a (analysieren)
+mysqloptimize: Vorgabe-Option: -o (optimieren)
+@end example
+
+Die verfügbaren Optionen für @code{mysqlcheck} sind hier aufgelistet. Bitte
+prüfen Sie mit @code{mysqlcheck --help}, welche davon Ihre Version
+unterstützt.
+
+@table @code
+@item -A, --all-databases
+Prüft alle Datenbanken. Das ist dasselbe wie --databases mit allen
+Datenbanken ausgewählt.
+@item -1, --all-in-1
+Statt für jede Tabelle eine Anfrage auszuführen, alle Anfragen in 1 Anfrage
+pro Datenbank ausführen. Tabellennamen stehen in einer durch Kommas
+getrennten Liste.
+@item -a, --analyze
+Analysiert die angegebene Tabelle.
+@item --auto-repair
+Wenn eine geprüfte Tabelle beschädigt ist, sie automatisch reparieren. Die
+Reparatur wird durchgeführt, nachdem alle Tabellen geprüft wurden, falls
+beschädigte gefunden wurden.
+@item -#, --debug=...
+Debug-Log-Datei ausgeben. Das ist häufig 'd:t:o,filename'.
+@item --character-sets-dir=...
+Verzeichnis, wo Zeichensätze gespeichert sind.
+@item -c, --check
+Tabelle auf Fehler prüfen.
+@item -C, --check-only-changed
+Nur die Tabellen prüfen, die seit der letzten Prüfung geändert wurden oder
+die nicht ordnungsgemäß geschlossen wurden.
+@item --compress
+Kompression im Client-Server-Protokoll benutzen.
+@item -?, --help
+Diese Nachricht ausgeben und beenden.
+@item -B, --databases
+Mehrere Datenbanken prüfen. Beachten Sie den Unterschied im Gebrauch: In
+diesem Fall werden keine Tabellen angegeben. Alle Namensargumente werden
+als Datenbanknamen erachtet.
+@item --default-character-set=...
+Setzt den vorgabemäßigen Zeichensatz.
+@item -F, --fast
+Nur Tabellen prüfen, die nicht ordnungsgemäß geschlossen wurden.
+@item -f, --force
+Fortfahren, auch wenn ein SQL-Fehler auftritt.
+@item -e, --extended
+Wenn Sie diese Option beim Prüfen von Tabellen benutzen, stellt das sicher,
+dass die Tabelle zu 100% konsistent ist, dauert aber sehr lange.
+Wenn Sie diese Option beim Reparieren von Tabellen benutzen, wird eine
+erweiterte Reparatur der Tabelle durchgeführt, was nicht nur sehr lange
+dauern kann, sondern auch viele 'Müll'-Zeilen produzieren kann!
+@item -h, --host=...
+Mit dem angegebenen Host verbinden.
+@item -m, --medium-check
+Schneller als extended-check, findet aber nur 99,99% aller Fehler. Sollte
+in den meisten Fällen genügen.
+@item -o, --optimize
+Tabelle optimieren.
+@item -p, --password[=...]
+Passwort, das bei der Verbindung zum Server benutzt werden soll. Wenn das
+Passwort nicht angegeben wird, wird vom Terminal eine Eingabeaufforderung
+präsentiert.
+@item -P, --port=...
+Portnummer, die für Verbindungen zum Server benutzt werden soll.
+@item -q, --quick
+Wenn Sie diese Option beim Prüfen von Tabellen benutzen, verhindert das,
+dass die Zeilen nach falschen Verknüpfungen (Links) durchgesehen werden
+(gescannt). Das ist die schnellste Prüfmethode.
+Wenn Sie diese Option beim Reparieren von Tabellen benutzen, wird versucht,
+nur den Index-Baum zu reparieren. Das ist die schnellste Reparaturmethode.
+@item -r, --repair
+Kann fast alles reparieren, ausser eindeutige Schlüssel, die nicht
+eindeutig sind.
+@item -s, --silent
+Nur Fehlermeldungen ausgeben.
+@item -S, --socket=...
+Socket-Datei, die für die Verbindung benutzt werden soll.
+@item --tables
+Option --databases (-B) überschreiben.
+@item -u, --user=#
+Benutzer zum Einloggen, falls nicht der aktuelle Unix-Benutzer.
+@item -v, --verbose
+Informationen über die verschiedenen Phasen ausgeben.
+@item -V, --version
+Versionsinformationen ausgeben und beenden.
+@end table
+
+
+@node mysqldump, mysqlhotcopy, Using mysqlcheck, Client-Side Scripts
+@c German node mysqldump
+@subsection mysqldump, Tabellenstrukturen und -daten dumpen
+
+@cindex dumpen, Datenbanken
+@cindex Datenbanken, dumpen
+@cindex Tabellen, dumpen
+@cindex Datensicherung, Datenbanken
+
+@cindex @code{mysqldump}
+Dienstprogramm, um eine Datenbank oder eine Sammlung von Datenbanken zu
+sichern oder um Daten auf einen anderen SQL-Server zu übertragen (nicht
+notwendigerweise ein MySQL-Server). Der Dump enthält SQL-Statements, um
+Datenbanken und Tabellen zu erzeugen und / oder Tabellen mit Daten zu
+füllen.
+
+Wenn Sie eine Datensicherung auf dem Server machen, sollten Sie in Betracht
+ziehen, statt dessen @code{mysqlhotcopy} zu benutzen. @xref{mysqlhotcopy, ,
+@code{mysqlhotcopy}}.
+
+@example
+shell> mysqldump [OPTIONS] datenbank [tabellen]
+OR mysqldump [OPTIONS] --databases [OPTIONS] datenbank1 [datenbank2 datenbank3...]
+OR mysqldump [OPTIONS] --all-databases [OPTIONS]
+@end example
+
+Wenn Sie keine Tabellen angeben oder @code{--databases} bzw.
+@code{--all-databases} benutzen, wird die gesamte Datenbank (bzw. werden
+alle Datenbanken) gedumpt.
+
+Sie erhalten eine Auflistung der Optionen, die Ihre Version von
+@code{mysqldump} unterstützt, indem Sie @code{mysqldump --help} eingeben.
+
+Wenn Sie @code{mysqldump} ohne @code{--quick} oder @code{--opt} ausführen,
+beachten Sie, dass @code{mysqldump} die gesamte Ergebnismenge in den
+Arbeitsspeicher lädt, bevor das Ergebnis gedumpt wird. Das kann zu
+Problemen führen, wenn Sie eine große Datenbank dumpen.
+
+Wenn Sie eine neue Version des @code{mysqldump}-Programms benutzen und
+einen Dump erzeugen, der in einen sehr alten MySQL-Server eingelesen werden
+soll, sollten Sie die @code{--opt}- und @code{-e}-Optionen nicht benutzen.
+
+@code{mysqldump} unterstützt folgende Optionen:
+
+@table @code
+@item --add-locks
+Führt @code{LOCK TABLES} vor und @code{UNLOCK TABLE} nach jedem
+Tabellen-Dump durch (um schnelleres Einfügen in MySQL zu erreichen).
+@item --add-drop-table
+Ein @code{drop table} vor jedem @code{create}-Statement hinzufügen.
+@item -A, --all-databases
+Alle Datenbanken dumpen. Das ist dasselbe wie @code{--databases} mit allen
+Datenbanken ausgewählt.
+@item -a, --all
+Alle MySQL-spezifischen Optionen für @code{create} benutzen.
+@item --allow-keywords
+Erzeugung von Spaltennamen zulassen, die Schlüsselwörter sind. Das
+funktioniert, indem jedem Spaltenname der Tabellenname als Präfix angefügt
+wird.
+@item -c, --complete-insert
+Vollständige @code{insert}-Statements benutzen (mit Spaltennamen).
+@item -C, --compress
+Alle Informationen zwischen Client und Server komprimieren, wenn bei
+Kompression unterstützen.
+@item -B, --databases
+Mehrere Datenbanken prüfen. Beachten Sie den Unterschied im Gebrauch: In
+diesem Fall werden keine Tabellen angegeben. Alle Namensargumente werden
+als Datenbanknamen erachtet. Vor jeder Ausgabe einer neuen Datenbank wird
+@code{USE datenbank;} eingefügt.
+@item --delayed
+Zeilen mit dem @code{INSERT DELAYED}-Befehl einfügen.
+@item -e, --extended-insert
+Die neue mehrzeilige @code{INSERT}-Syntax benutzen. (Ergibt kompaktere und
+schnellere inserts-Statements.)
+@item -#, --debug[=option_string]
+Programmbenutzung tracen (für Debug-Zwecke).
+@item --help
+Hilfetext ausgeben und beenden.
+@item --fields-terminated-by=...
+@itemx --fields-enclosed-by=...
+@itemx --fields-optionally-enclosed-by=...
+@itemx --fields-escaped-by=...
+@itemx --lines-terminated-by=...
+Diese Optionen werden zusammen mit der @code{-T}-Option benutzt und haben
+dieselbe Bedeutung wie die entsprechenden Klauseln für @code{LOAD DATA
+INFILE}. @xref{LOAD DATA, , @code{LOAD DATA}}.
+@item -F, --flush-logs
+Log-Datei im MySQL-Server zurückschreiben, bevor der Dump durchgeführt
+wird.
+@item -f, --force,
+Fortfahren, selbst wenn beim Dump einer Tabelle ein SQL-Fehler auftritt.
+@item -h, --host=..
+Daten auf dem MySQL-Server auf dem genannten Host dumpen. Der
+vorgabemäßige Host ist @code{localhost}.
+@item -l, --lock-tables.
+Alle Tabellen sperren, bevor mit dem Dump begonnen wird. Die Tabellen
+werden mit @code{READ LOCAL} gesperrt, um gleichzeitiges Einfügen zu
+erlauben (bei @code{MyISAM}-Tabellen).
+@item -n, --no-create-db
+'CREATE DATABASE /*!32312 IF NOT EXISTS*/ datenbank;' wird nicht in die
+Ausgabe gschrieben. Diese Zeile wird ansonsten hinzugefügt, wenn
+--databases oder --all-databases angegeben wurde.
+@item -t, --no-create-info
+Keine Tabellenerzeugungsinformation schreiben (das @code{CREATE
+TABLE}-Statement).
+@item -d, --no-data
+Keine Zeileninformationen für die Tabelle schreiben. Das ist sehr
+nützlich, wenn Sie lediglich einen Dump der Tabellenstruktur erzeugen
+wollen.
+@item --opt
+Dasselbe wie @code{--quick --add-drop-table --add-locks --extended-insert
+--lock-tables}. Das sollte den schnellstmöglichen Dump zum Einlesen in
+einen MySQL-Server ergeben.
+@item -pihr_passwort, --password[=ihr_passwort]
+Das Passwort, das für die Verbindung zum Server benutzt werden soll. Wenn
+Sie keinen @samp{=ihr_passwort}-Teil angeben, zeigt @code{mysqldump} eine
+Eingabeaufforderung für Ihr Passwort.
+@item -P port_num, --port=port_num
+Die TCP/IP-Portnummer, die für die Verbindung zu einem Host benutzt werden
+soll. (Diese wird für Verbindungen zu Hosts ausser @code{localhost}
+benutzt, für den Unix-Sockets benutzt werden.)
+@item -q, --quick
+Anfrage nicht puffern, sondern direkt zu stdout dumpen. Benutzt für die
+Durchführung @code{mysql_use_result()}.
+@item -r, --result-file=...
+Direkte Ausgabe in die angegebene Datei. Diese Ausgabe sollte bei MS-DOS
+benutzt werden, weil sie verhindert, dass das Zeichen für neue Zeile '\n'
+in '\n\r' (new line + carriage return) umgewandelt werden.
+@item -S /pfad/zu/socket, --socket=/pfad/zu/socket
+Die Socket-Datei, die für die Verbindung zu @code{localhost} benutzt werden
+soll (was der vorgabemäßige Host ist).
+@item --tables
+Überschreibt die Option --databases (-B).
+@item -T, --tab=pfad-zu-einem-verzeichnis
+Erzeugt eine @code{tabelle.sql}-Datei, die die SQL-CREATE-Befehle enthält,
+und eine @code{tabelle.txt}-Datei, die die Daten enthält, für jede
+angegebene Tabelle. @strong{HINWEIS}: Das funktioniert nur, wenn
+@code{mysqldump} auf derselben Maschine läuft wie der @code{mysqld}-Daemon.
+Das Format der @code{.txt}-Datei hängt von den @code{--fields-xxx}- und
+@code{--lines--xxx}-Optionen ab.
+@item -u benutzername, --user=benutzername
+Der MySQL-Benutzername, der für die Verbindung zum Server benutzt werden
+soll. Der Vorgabewert ist Ihr Unix-Loginname.
+@item -O var=option, --set-variable var=option
+Den Wert einer Variablen setzen. Die möglichen Werte sind unten aufgeführt.
+@item -v, --verbose
+Geschwätziger Modus. Gibt mehr Informationen darüber aus, was das Programm
+tut.
+@item -V, --version
+Versionsinformationen ausgeben und beenden.
+@item -w, --where='wo-bedingung'
+Nur ausgewählte Datensätze dumpen. Beachten Sie, dass Anführungszeichen
+zwingend erforderlich sind:
+
+@example
+"--where=user='jimf'" "-wuserid>1" "-wuserid<1"
+@end example
+@item -O net_buffer_length=#, where # < 16M
+Beim Erzeugen von mehrzeiligen insert-Statements (wie bei der Option
+@code{--extended-insert} oder @code{--opt}), erzeugt @code{mysqldump}
+Zeilen bis zur Länge von @code{net_buffer_length}. Wenn Sie diesen Wert
+herauf setzen, müssen Sie sicherstellen, dass die
+@code{max_allowed_packet}-Variable im MySQL-Server größer als
+@code{net_buffer_length} ist.
+@end table
+
+Der häufigste Gebrauch von @code{mysqldump} dient wahrscheinlich der
+Herstellung einer Datensicherung ganzer Datenbanken. @xref{Backup}.
+
+@example
+mysqldump --opt datenbank > datensicherung.sql
+@end example
+
+Diese können Sie zurück in MySQL einlesen mit:
+
+@example
+mysql datenbank < datensicherung.sql
+@end example
+
+oder
+
+@example
+mysql -e "source /pfad-zur-datensicherung/datensicherung.sql" datenbank
+@end example
+
+Ausserdem ist es sehr nützlich, um einen anderen MySQL-Server mit
+Informationen aus einer Datenbank zu füllen:
+
+@example
+mysqldump --opt datenbank | mysql ---host=entfernter-host -C datenbank
+@end example
+
+Es ist möglich, mehrere Datenbanken mit einem Befehl zu dumpen:
+
+@example
+mysqldump --databases datenbank1 [datenbank2 datenbank3...] > meine_datenbanken.sql
+@end example
+
+Wenn Sie alle Datenbanken dumpen wollen, benutzen Sie:
+
+@example
+mysqldump --all-databases > alle_datenbanken.sql
+@end example
+
+
+@node mysqlhotcopy, mysqlimport, mysqldump, Client-Side Scripts
+@c German node mysqlhotcopy
+@subsection mysqlhotcopy, MySQL-Datenbanken und Tabellen kopieren
+
+@cindex dumpen, Datenbanken
+@cindex Datenbanken, dumpen
+@cindex Tabellen, dumpen
+@cindex Datensicherung, Datenbanken
+
+@code{mysqlhotcopy} ist a perl Skript that uses @code{LOCK TABLES},
+@code{FLUSH TABLES} und @code{cp} oder @code{scp} to quickly make a backup
+of a Datenbank. It's the fastest way to make a backup of the Datenbank,
+of single Tabellen but it can only be run on the same machine where the
+Datenbankverzeichnisse are.
+
+@example
+mysqlhotcopy datenbank [/pfad/zu/new_Verzeichnis]
+
+mysqlhotcopy datenbank_1 ... datenbank_n /pfad/zu/new_Verzeichnis
+
+mysqlhotcopy datenbank./regex/
+@end example
+
+@code{mysqlhotcopy} unterstützt folgende Optionen:
+
+@table @code
+@item -?, --help
+Hilfe ausgeben und beenden.
+@item -u, --user=#
+Benutzername zum Einloggen.
+@item -p, --password=#
+Passwort für die Verbindung zum Server.
+@item -P, --port=#
+Port zur Verbindung zum lokalen Server.
+@item -S, --socket=#
+Socket zur Verbindung zum lokalen Server.
+@item --allowold
+Nicht abbrechen, wenn das Ziel bereits existiert (sondern in _old umbenennen)
+@item --keepold
+Vorheriges (jetzt umbenanntes) Ziel nach dem Durchführen nicht löschen.
+@item --noindices
+Keine kompletten Index-Dateien in die Kopie einfügen, um die Datensicherung
+kleiner und schneller zu machen. Die Indexe können später mit
+@code{myisamchk -rq.} neu aufgebaut werden.
+@item --method=#
+Kopiermethode (@code{cp} oder @code{scp}).
+@item -q, --quiet
+Keine Meldungen ausgeben, ausser bei Fehlern.
+@item --debug
+Debug anschalten.
+@item -n, --dryrun
+Aktionen berichten, ohne sie auszuführen.
+@item --regexp=#
+Alle Datenbanken mit übereinstimmenden regexp-Namen sichern.
+@item --suffix=#
+Suffix für Namen kopierter Datenbanken.
+@item --checkpoint=#
+Checkpoint-Eingang in angegebene datenbank.tabelle einfügen.
+@item --flushlog
+Log-Dateien zurückschreiben, sobald alle Tabellen gesperrt sind.
+@item --tmpdir=#
+Temporäres Verzeichnis (anstelle von /tmp).
+@end table
+
+Geben Sie @code{perldoc mysqlhotcopy} ein, um eine vollständigere
+Dokumentation von @code{mysqlhotcopy} zu erhalten.
+
+@code{mysqlhotcopy} liest die Gruppen @code{[client]} und
+@code{[mysqlhotcopy]} aus den Optionsdateien.
+
+Damit Sie @code{mysqlhotcopy} ausführen können, benötigen Sie Schreibrechte
+im Datensicherungsverzeichnis, @code{SELECT}-Berechtigung auf die Tabellen,
+die Sie kopieren wollen, und die MySQL-@code{Reload}-Berechtigung (damit
+Sie @code{FLUSH TABLES} ausführen können).
+
+
+@node mysqlimport, mysqlshow, mysqlhotcopy, Client-Side Scripts
+@c German node mysqlimport
+@subsection mysqlimport, Daten aus Textdateien importieren
+
+@cindex importieren, Daten
+@cindex Daten, importieren
+@cindex Dateien, Text-
+@cindex Textdateien, importieren
+@cindex @code{mysqlimport}
+
+@code{mysqlimport} stellt eine Kommandozeilen-Schnittstelle für das
+@code{LOAD DATA INFILE} SQL-Statement zur Verfügung. Die meisten Optionen
+für @code{mysqlimport} entsprechen denselben Optionen für @code{LOAD DATA
+INFILE}. @xref{LOAD DATA, , @code{LOAD DATA}}.
+
+@code{mysqlimport} wird wie folgt aufgerufen:
+
+@example
+shell> mysqlimport [optionen] datenbank textdatei1 [textdatei2....]
+@end example
+
+Bei jeder Textdatei, die auf der Kommandozeile angegeben wird, entfernt
+@code{mysqlimport} jegliche Erweiterungen vom Dateinamen und benutzt das
+Ergebnis, um festzulegen, in welche Tabelle der Dateiinhalt importiert
+werden soll. Dateien namens @file{patient.txt}, @file{patient.text} und
+@file{patient} beispielsweise würden alle in eine Tabelle namens
+@code{patient} importiert werden.
+
+@code{mysqlimport} unterstützt folgende Optionen:
+
+@table @code
+@item -c, --columns=...
+Diese Option nimmt ein durch Kommas getrennte Auflistung von Feldnamen als
+Argument entgegen. Die Feldliste wird benutzt, um einen korrekten
+@code{LOAD DATA INFILE}-Befehl zu erzeugen, der an MySQL durchgereicht
+wird. @xref{LOAD DATA, , @code{LOAD DATA}}.
+
+@item -C, --compress
+Komprimiert alle Informationen zwischen Client und Server, wenn bei
+Kompression unterstützen.
+
+@item -#, --debug[=option_string]
+Programmbenutzung tracen (zum Debuggen).
+
+@item -d, --delete
+Tabelle leeren, bevor die Textdatei importiert wird.
+
+@item --fields-terminated-by=...
+@itemx --fields-enclosed-by=...
+@itemx --fields-optionally-enclosed-by=...
+@itemx --fields-escaped-by=...
+@itemx --lines-terminated-by=...
+Diese Optionen haben dieselbe Bedeutung wie die entsprechenden Klauseln für
+@code{LOAD DATA INFILE}. @xref{LOAD DATA, , @code{LOAD DATA}}.
+
+@item -f, --force
+Fehler ignorieren. Wenn beispielsweise eine Tabelle für eine Textdatei
+nicht existiert, mit den verbleibenden Dateien weitermachen. Ohne
+@code{--force} wird @code{mysqlimport} beendet, wenn die Tabelle nicht
+existiert.
+
+@item --help
+Hilfetext ausgeben und beenden.
+
+@item -h host_name, --host=host_name
+Daten in den MySQL-Server auf dem genannten Host importieren. Der
+vorgabemäßige Host ist @code{localhost}.
+
+@item -i, --ignore
+Siehe Beschreibung für die @code{--replace}-Option.
+
+@item -l, --lock-tables
+@strong{ALLE} Tabellen für Schreibvorgänge sperren, bevor irgend welche
+Textdateien verarbeitet werden. Das stellt sich, dass alle Tabellen auf dem
+Server synchronisiert werden.
+
+@item -L, --local
+Liest Eingabedateien vom Client. Vorgabemäßig wird angenommen, dass
+Textdateien auf dem Server liegen, wenn Sie sich über @code{localhost}
+verbinden (was der vorgabemäßige Host ist).
+
+@item -pihr_passwort, --password[=ihr_passwort]
+Das Passwort, das für die Verbindung zum Server benutzt werden soll. Wenn
+Sie keinen @samp{=ihr_passwort}-Teil angeben, zeigt @code{mysqlimport}
+eine Eingabeaufforderung für Ihr Passwort.
+
+@item -P port_num, --port=port_num
+Die TCP/IP-Portnummer, die für die Verbindung zu einem Host benutzt werden
+soll. (Diese wird für Verbindungen zu Hosts ausser @code{localhost}
+benutzt, für den Unix-Sockets benutzt werden.)
+
+@item -r, --replace
+Die @code{--replace}- und @code{--ignore}-Optionen steuern die Handhabung
+von Eingabe-Datensätzen, die bestehende Datensätze auf eindeutigen
+Schlüsseln duplizieren würden. Wenn Sie @code{--replace} angeben, werden
+bestehende Zeilen ersetzt, die denselben eindeutigen Schlüsselwert
+besitzen. Wenn Sie @code{--ignore} angeben, werden Zeilen, die eine
+bestehende Zeile duplizieren würden, übersprungen. Wenn Sie keine der
+beiden Optionen angeben, tritt ein Fehler auf, wenn ein doppelter
+Schlüsseleintrag gefunden wird, und der Rest der Textdatei wird ignoriert.
+
+@item -s, --silent
+Schweigsamer Modus. Ausgaben erfolgen nur, wenn Fehler auftreten.
+
+@item -S /pfad/zu/socket, --socket=/pfad/zu/socket
+Die Socket-Datei, die für die Verbindung zu @code{localhost} benutzt werden
+soll (der der vorgabemäßige Host ist).
+
+@item -u benutzername, --user=benutzername
+Der MySQL-Benutzername, der für die Verbindung zum Server benutzt werden
+soll. Der Vorgabewert ist Ihr Unix-Loginname.
+
+@item -v, --verbose
+Geschwätziger Modus. Mehr Informationen darüber ausgeben, was das Programm
+macht.
+
+@item -V, --version
+Versionsinformationen ausgeben und beenden.
+@end table
+
+Hier ist ein Beispiel für die Benutzung von @code{mysqlimport}:
+
+@example
+$ mysql --version
+mysql Ver 9.33 Distrib 3.22.25, for pc-linux-gnu (i686)
+$ uname -a
+Linux xxx.com 2.2.5-15 #1 Mon Apr 19 22:21:09 EDT 1999 i586 unknown
+$ mysql -e 'CREATE TABLE imptest(id INT, n VARCHAR(30))' test
+$ ed
+a
+100 Max Sydow
+101 Graf Dracula
+.
+w imptest.txt
+32
+q
+$ od -c imptest.txt
+0000000 1 0 0 \t M a x S y d o w \n 1 0
+0000020 1 \t G r a f D r a c u l a \n
+0000040
+$ mysqlimport --local test imptest.txt
+test.imptest: Records: 2 Deleted: 0 Skipped: 0 Warnings: 0
+$ mysql -e 'SELECT * FROM imptest' test
++------+---------------+
+| id | n |
++------+---------------+
+| 100 | Max Sydow |
+| 101 | Graf Dracula |
++------+---------------+
+@end example
+
+
+@node mysqlshow, perror, mysqlimport, Client-Side Scripts
+@c German node mysqlshow
+@subsection Datenbanken, Tabellen und Spalten anzeigen
+
+@cindex Datenbanken, anzeigen
+@cindex anzeigen, Datenbankinformationen
+@cindex Tabellen, anzeigen
+@cindex Spalten, anzeigen
+@cindex Anzeigen, Datenbankinformationen
+
+@code{mysqlshow} wird benutzt, um schnell nachzusehen, welche Datenbanken,
+Tabellen und Tabellenspalten es gibt.
+
+Mit dem @code{mysql}-Programm können Sie dieselben Information mit den
+@code{SHOW}-Befehlen erhalten. @xref{SHOW}.
+
+@code{mysqlshow} wird wie folgt aufgerufen:
+
+@example
+shell> mysqlshow [optionen] [datenbank [tabelle [spalte]]]
+@end example
+
+@itemize @bullet
+@item
+Wenn keine Datenbank angegeben wird, werden alle passenden Datenbanken
+gezeigt.
+@item
+Wenn keine Tabelle angegeben wird, werden alle passenden Tabellen in der
+Datenbank gezeigt.
+@item
+Wenn keine Spalte angegeben wird, werden alle passenden Spalten und
+Spaltentypen in der Tabelle gezeigt.
+@end itemize
+
+Beachten Sie, dass Sie in neueren MySQL-Versionen nur die Datenbanken,
+Tabellen und Spalten sehen können, für die Sie irgend welche Berechtigungen
+haben.
+
+Wenn das letzte Argument einen Shell- oder SQL-Platzhalter enthält
+(@code{*}, @code{?}, @code{%} oder @code{_}), wird nur das gezeigt, was dem
+Platzhalter entspricht. Das kann zu Verwirrung führen, wenn Sie Spalten
+einer Tabelle anzeigen, die einen Unterstrich (@code{_}) enthalten, weil
+Ihnen @code{mysqlshow} in diesem Fall nur die Tabellennamen zeigt, die dem
+Muster entsprechen. Das kann leicht durch Hinzufügen eines zusätzlichen
+@code{%} am Ende der Kommandozeile (als separates Argument) behoben werden.
+
+
+@node perror, Batch Commands, mysqlshow, Client-Side Scripts
+@c German node perror
+@subsection perror, Erklärung der Fehler-Codes
+
+@cindex Fehlermeldungen, anzeigen
+@cindex perror
+
+@code{perror} wird benutzt, um Fehlermeldungen auszugeben. @code{perror}
+wird wie folgt aufgerufen:
+
+@example
+shell> perror [optionen] [ERRORCODE [ERRORCODE...]]
+
+For example:
+
+shell> perror 64 79
+Error code 64: Machine ist not on the network
+Error code 79: Can not access a needed shared library
+@end example
+
+@code{perror} wird benutzt, um eine Beschreibung für einen
+Systemfehler-Code anzuzeigen, oder einen Fehler-Code des
+MyISAM/ISAM-Tabellen-Handlers. Die Fehlermeldungen sind hauptsächlich
+abhängig vom Betriebssystem.
+
+
+@node Batch Commands, , perror, Client-Side Scripts
+@c German node Stapelbefehle
+@subsection Wie SQL-Befehle aus einer Textdatei laufen gelassen werden
+
+@c FIX add the 'source' befehl
+
+Der @code{mysql}-Client wird typischerweise interaktiv benutzt, wie folgt:
+
+@example
+shell> mysql datenbank
+@end example
+
+Es ist jedoch möglich, Ihre SQL-Befehle in eine Datei zu schreiben und
+@code{mysql} anzuweisen, ihre Eingaben aus dieser Datei zu lesen. Um das zu
+tun, erzeugen Sie eine Textdatei @file{textdatei}, die die Befehle enthält,
+die Sie ausführen wollen. Dann rufen Sie @code{mysql} wie gezeigt auf:
+
+@example
+shell> mysql datenbank < textdatei
+@end example
+
+Sie können Ihre Textdatei auch mit einem @code{USE datenbank}-Statement
+beginnen lassen. In diesem Fall ist es nicht notwendig, den Datenbanknamen
+auf der Kommandozeile anzugeben:
+
+@example
+shell> mysql < textdatei
+@end example
+
+@xref{Client-Side Scripts}.
+
+
+@node Log Files, Replication, Client-Side Scripts, MySQL Database Administration
+@c German node Log-Dateien
+@section Die MySQL-Log-Dateien
+
+@cindex Log-Dateien
+
+MySQL hat mehrere unterschiedliche Log-Dateien, die Ihnen helfen können
+herauszufinden, was innerhalb @code{mysqld} vor sich geht:
+
+@multitable @columnfractions .3 .7
+@item Die Fehler-Log-Datei @tab Probleme, die beim Start, beim Laufenlassen oder beim Anhalten von @code{mysqld} auftreten.
+@item Die ISAM-Log-Datei @tab Loggt alle Änderungen in ISAM-Tabellen mit. Wird nur benutzt, um den ISAM-Code zu debuggen.
+@item Die Anfragen-Log-Datei @tab Hergestellte Verbindungen und ausgeführte Anfragen.
+@item Die Update-Log-Datei @tab Veraltet: Speichert Statements, die Daten verändern.
+@item Die Binär-Log-Datei @tab Speichert alle Statements, die etwas ändern. Wird auch für Replikation benutzt.
+@item Die Slow-Log-Datei @tab Speichert alle Anfragen, die länger als @code{long_query_time} zur Ausführung benötigten oder keine Indexe benutzten.
+@end multitable
+
+Alle Log-Dateien liegen im @code{mysqld} Daten-Verzeichnis. Sie können
+@code{mysqld} zwingen, die Log-Dateien neu zu öffnen (oder in manchen
+Fällen auf eine neue Log-Datei umzuschalten), indem Sie @code{FLUSH LOGS}
+ausführen. @xref{FLUSH}.
+
+
+
+@menu
+* Error log::
+* Query log::
+* Update log::
+* Binary log::
+* Slow query log::
+* Log file maintenance::
+@end menu
+
+@node Error log, Query log, Log Files, Log Files
+@c German node Fehler-Log-Datei
+@subsection Die Fehler-Log-Datei
+
+@code{mysqld} schreibt alle Fehler nach stderr, die das
+@code{safe_mysqld}-Skript in eine Datei namens @code{'hostname'.err}
+umleitet. (Unter Windows schreibt @code{mysqld} direkt in die Datei
+@file{\mysql\data\mysql.err}.)
+
+Diese enthält Informationen, wann @code{mysqld} gestartet und angehalten
+wurde und zusätzlich jeden kritischen Fehler, der während der Laufzeit
+passierte. Wenn @code{mysqld} unerwartet stirbt und @code{safe_mysqld} ihn
+neu starten muss, schreibt @code{safe_mysqld} eine @code{restarted
+mysqld}-Zeile in diese Datei. Diese Log-Datei enthält auch Warnungen, wenn
+@code{mysqld} eine Tabelle bemerkt, die automatisch geprüft oder repariert
+werden muss.
+
+Auf manchen Betriebssystemen enthält die Fehler-Log-Datei einen
+Stack-Trace, wo @code{mysqld} starb. Dieser kann benutzt werden, um
+herauszufinden, wo @code{mysqld} starb. @xref{Using stack trace}.
+
+
+@node Query log, Update log, Error log, Log Files
+@c German node Anfragen-Log-Datei
+@subsection Die allgemeine Anfragen-Log-Datei
+
+@cindex Anfragen-Log-Datei
+@cindex Dateien, Anfragen-Log-Datei
+
+Wenn Sie wissen wollen, was innerhalb @code{mysqld} geschieht, sollten Sie
+ihn mit @code{--log[=file]} starten. Diese Option loggt alle Verbindungen
+und Anfragen in die Log-Datei (vorgabemäßig @file{'hostname'.log}
+benannt). Diese Log-Datei kann sehr nützlich sein, wenn Sie einen Fehler in
+einem Client vermuten und wissen wollen, was genau @code{mysqld} sich bei
+dem dachte, was es vom Client geschickt bekam.
+
+Vorgabemäßig startet das @code{mysql.server}-Skript den MySQL-Server mit
+der @code{-l}-Option. Wenn Sie bessere Performance brauchen, wenn Sie MySQL
+in einer Produktionsumgebung starten, können Sie die @code{-l}-Option aus
+@code{mysql.server} entfernen oder sie zu @code{--log-binary} ändern.
+
+Die Einträge in diese Log-Datei werden geschrieben, wenn @code{mysqld} die
+Anfragen erhält. Die Reihenfolge kann vor derjenigen abweichen, in der die
+Statements ausgeführt werden. Das steht im Gegensatz zur Update-Log-Datei
+und zur Binär-Log-Datei, bei denen geschrieben wird, nachdem die Anfrage
+ausgeführt wurde, aber bevor irgend welche Sperren aufgehoben werden.
+
+
+@node Update log, Binary log, Query log, Log Files
+@c German node Update-Log-Datei
+@subsection Die Update-Log-Datei
+
+@cindex Update-Log-Datei
+@cindex Dateien, Update-Log-Datei
+
+@strong{HINWEIS}: Die Update-Log-Datei wird durch die binäre Log-Datei
+ersetzt. @xref{Binary log}. Mit dieser können Sie alles machen, was
+Sie mit der Update-Log-Datei machen können.
+
+Wenn er mit der @code{--log-update[=datei]}-Option gestartet wird, schreibt
+@code{mysqld} eine Log-Datei, die alle SQL-Befehle enthält, die Daten
+aktualisieren. Wenn kein Dateiname angegeben wird, ist die Vorgabe der Name
+der Host-Maschine. Wenn ein Dateiname angegeben wird, der aber keine
+Pfadangabe enthält, wird die Datei ins Daten-Verzeichnis geschrieben. Wenn
+@file{datei} keine Erweiterung hat, erzeugt @code{mysqld} eine Log-Datei,
+die er wie folgt benennt: @file{datei.###}, wobei @code{###} eine Zahl ist,
+die jedes Mal hochgezählt wird, wenn Sie @code{mysqladmin refresh} oder
+@code{mysqladmin flush-logs} oder das @code{FLUSH LOGS}-Statement
+ausführen, oder wenn Sie den Server neu starten.
+
+@strong{HINWEIS:} Damit das dargestellte Schema funktioniert, sollten Sie
+NICHT eigene Dateien mit demselben Dateinamen wie die Update-Log-Datei plus
+Erweiterungen, die als die hochgezählte Zahl betrachtet werden könnten, im
+Verzeichnis anlegen, das von der Update-Log-Datei benutzt wird!
+
+Wenn Sie die @code{--log} oder @code{-l}-Optionen benutzen, schreibt
+@code{mysqld} eine allgemeine Log-Datei mit dem Dateinamen
+@file{hostname.log}. Neustarts und Refresh-Operationen führen dann nicht
+dazu, dass eine neue Log-Datei erzeugt wird (obwohl diese geschlossen und
+wieder geöffnet wird). In diesem Fall können Sie sie (unter Unix) wie folgt
+kopieren:
+
+@example
+mv hostname.log hostname-old.log
+mysqladmin flush-logs
+cp hostname-old.log ins-datensicherungs-verzeichnis
+rm hostname-old.log
+@end example
+
+Das Mitloggen mittels der Update-Log-Datei ist clever, weil es nur
+Statements loggt, die tatsächlich Daten aktualisieren. Wenn ein
+@code{UPDATE} oder ein @code{DELETE} mit einem @code{WHERE} keine passenden
+Zeilen findet, wird nichts in die Log-Datei geschrieben. Es werden sogar
+@code{UPDATE}-Statements übersprungen, die eine Spalte auf einen Wert
+setzen, die sie bereits hat.
+
+Das Schreiben in die Update-Log-Datei wird unmittelbar durchgeführt,
+nachdem eine Anfrage fertig ist, aber bevor irgend welche Sperren
+aufgehoben sind oder irgendein Commit durchgeführt wurde. Das stellt
+sicher, dass die Log-Datei stets in der Reihenfolge der Ausführung
+mitschreibt.
+
+Wenn Sie eine Datenbank von Update-Log-Datei-Dateien aktualisieren wollen,
+könnten Sie folgendes tun (angenommen, Ihre Update-Log-Dateien haben Namen
+der Form @file{datei.###}):
+
+@example
+shell> ls -1 -t -r datei.[0-9]* | xargs cat | mysql
+@end example
+
+@code{ls} wird benutzt, um alle Log-Dateien in der richtigen Reihenfolge zu
+erhalten.
+
+Das ist nützlich, wenn Sie Datensicherungsdateien nach einem Absturz
+zurückspielen müssen und die Aktualisierungen neu ausführen wollen, die
+zwischen der Zeit der Datensicherung und dem Absturz lagen.
+
+
+@node Binary log, Slow query log, Update log, Log Files
+@c German node Binär-Log-Datei
+@subsection Die binäre Update-Log-Datei
+
+@cindex Binär-Log-Datei
+@cindex Dateien, Binär-Log-Datei
+
+In Zukunft wird die Binär-Log-Datei die Update-Log-Datei ersetzen, daher
+empfehlen wir, dass Sie so bald wie möglich zu diesem Log-Format wechseln!
+
+Die Binär-Log-Datei enthält alle Informationen, die im Update-Log verfügbar
+sind, in einem effizienteren Format. Sie enthält ausserdem Informationen
+darüber, wie lange jede Anfrage brauchte, die die Datenbank aktualisierte.
+
+Die Binär-Log-Datei wird auch benutzt, wenn Sie einen Slave von einem
+Master replizieren. @xref{Replication}.
+
+Mit der @code{--log-bin[=datei]}-Option gestartet, schreibt @code{mysqld}
+eine Log-Datei, die alle SQL-Befehle enthält, die Daten aktualisieren. Wenn
+kein Dateiname angegeben wird, ist die Vorgabe der Name der Host-Machine,
+gefolgt von @code{-bin}. Wenn der Dateiname angegeben wird, aber keine
+Pfadangabe enthält, wird die Datei ins Daten-Verzeichnis geschrieben.
+
+Sie können folgende Optionen für @code{mysqld} benutzen, um zu
+beeinflussen, was in die Binär-Log-Datei geschrieben wird:
+
+@multitable @columnfractions .4 .6
+@item @code{binlog-do-db=datenbank} @tab
+Weist den Master an, Aktualisierungen für die angegebene Datenbank zu
+loggen und alle anderen, nicht explizit erwähnten, auszuschließen.
+(Beispiel: @code{binlog-do-db=eine_datenbank})
+
+@item @code{binlog-ignore-db=datenbank} @tab
+Weist den Master an, Aktualisierungen für die angegebene Datenbank nicht in
+die Binär-Log-Datei zu loggen (Beispiel:
+@code{binlog-ignore-db=eine_datenbank}).
+@end multitable
+
+@code{mysqld} hängt dem Binär-Log-Datei-Dateinamen eine Erweiterung an, die
+eine Zahl ist, die jedes Mal heraufgezählt wird, wenn Sie @code{mysqladmin
+refresh}, @code{mysqladmin flush-logs} oder ein @code{FLUSH LOGS}-Statement
+ausführen oder den Server neu starten.
+
+Damit Sie feststellen können, welche verschiedenen Binär-Log-Datei-Dateien
+benutzt wurden, erzeugt @code{mysqld} auch eine Binär-Log-Index-Datei, die
+die Namen aller benutzten Binär-Log-Datei-Dateien enthält. Vorgabemäßig
+hat diese denselben Namen wie die Binär-Log-Datei, mit der Erweiterung
+@code{'.index'}. Sie können den Namen der Binär-Log-Index-Datei mit der
+@code{--log-bin-index=[filename]}-Option ändern.
+
+Wenn Sie Replikation benutzen, sollten Sie keine alten Binär-Log-Dateien
+löschen, bis Sie sicher sind, dass kein Slave sie jemals wieder benötigen
+wird. Eine Art, das zu tun, ist, einmal pro Tag @code{mysqladmin
+flush-logs} auszuführen, und danach alle Logs zu entfernen, die älter als 3
+Tage sind.
+
+Sie können die Binär-Log-Datei mit dem @code{mysqlbinlog}-Befehl
+untersuchen. Beispielsweise können Sie einen MySQL-Server wie folgt aus der
+Binär-Log-Datei aktualisieren:
+
+@example
+mysqlbinlog log-file | mysql -h server_name
+@end example
+
+Sie können auch das @code{mysqlbinlog}-Programm benutzen, um die
+Binär-Log-Datei direkt von einem entfernten MySQL-Server zu lesen!
+
+@code{mysqlbinlog --help} gibt Ihnen weitere Informationen zur Benutzung
+dieses Programms.
+
+Wenn Sie @code{BEGIN [WORK]} oder @code{SET AUTOCOMMIT=0} verwenden, müssen
+Sie die MySQL-Binär-Log-Datei für Datensicherungen anstelle der alten
+Update-Log-Datei benutzen.
+
+Das Loggen in die Binär-Log-Datei wird unmittelbar nach jeder Anfrage
+geschrieben, aber bevor irgend welche Sperren aufgehoben wurden oder irgend
+ein Commit durchgeführt wurde. Das stellt sicher, dass die Log-Datei in der
+Reihenfolge der Ausführung mitschreibt.
+
+Alle Aktualisierungen (@code{UPDATE}, @code{DELETE} oder @code{INSERT}),
+die eine transaktionale Tabelle (like BDB-Tabellen) ändern, werden bis zu
+einem @code{COMMIT} gecachet. Jegliche Aktualisierungen auf eine nicht
+transaktionale Tabelle werden sofort in der Binär-Log-Datei gespeichert.
+Jedem Thread wird beim Start ein Puffer der Größe @code{binlog_cache_size}
+für die Pufferung von Anfragen zugewiesen. Wenn eine Anfrage größer als
+dieser ist, öffnet der Thread eine temporäre Datei, um den größeren Cache
+zu handhaben. Die temporäre Datei wird gelöscht, wenn der Thread beendet
+wird.
+
+@code{max_binlog_cache_size} kann dazu benutzt werden, um die gesamte
+benutzte Größe zu begrenzen, und um eine Anfrage aus mehreren
+Transaktionen zu cachen.
+
+Wenn Sie die Update- oder Binär-Log-Datei benutzen, funktionieren
+gleichzeitige Einfügeoperationen nicht im Zusammenhang mit @code{CREATE ...
+INSERT} und @code{INSERT ... SELECT}. Damit stellen Sie sicher, dass Sie
+eine exakte Kopie Ihrer Tabellen wieder herstellen können, indem Sie die
+Log-Datei auf eine Datensicherung anwenden.
+
+
+@node Slow query log, Log file maintenance, Binary log, Log Files
+@c German node Langsame-Anfragen-Log-Datei
+@subsection Die Anfragen-Log-Datei für langsame Anfragen
+
+@cindex Langsame-Anfragen-Log-Datei
+@cindex Dateien, Langsame-Anfragen-Log-Datei
+
+Mit der @code{--log-slow-queries[=datei]}-Option gestartet schreibt
+@code{mysqld} eine Log-Datei, die alle SQL-Befehle enthält, die länger als
+@code{long_query_time} zur Ausführung brauchten. Die Zeit, um die
+anfänglichen Tabellensperren zu erhalten, wird nicht zur Ausführungszeit
+hinzugezählt.
+
+Anfragen-Log-Datei für langsame Anfragen wird geschrieben, nachdem jede
+Anfrage ausgeführt wurde und nachdem alle Sperren aufgehoben wurden. Das
+kann von der Reihenfolge abweichen, in der die Statements ausgeführt
+wurden.
+
+Wenn kein Dateiname angegeben wird, ist die Vorgabe der Name der
+Host-Maschine mit dem Suffix @code{-slow.log}. Wenn ein Dateiname angegeben
+wird, der aber keine Pfadangabe enthält, wird die Datei ins Daten-Verzeichnis geschrieben.
+
+Die Anfragen-Log-Datei für langsame Anfragen kann benutzt werden, um
+Anfragen zu finden, die für die Ausführung lange Zeit benötigen und daher
+Kandidaten für Optimierungen sind, was bei einer großen Log-Datei
+allerdings eine schwierige Aufgabe werden kann. Sie können die
+Anfragen-Log-Datei für langsame Anfragen durch den
+@code{mysqldumpslow}-Befehl durchschleifen (pipen), um eine Zusammenfassung
+der Anfragen zu erhalten, die in der Log-Datei erscheinen.
+
+Wenn Sie @code{--log-long-format} benutzen, erscheinen auch Anfragen, die
+keine Indexe benutzen. @xref{Command-line options}.
+
+
+@node Log file maintenance, , Slow query log, Log Files
+@c German node Log-Datei-Wartung
+@subsection Wartung und Pflege der Log-Dateien
+
+@cindex Dateien, Log-Dateien
+@cindex Wartung, Log-Dateien
+@cindex Log-Dateien, Wartung
+
+MySQL hat viele Log-Dateien, die es leicht machen festzustellen, was vor
+sich geht. @xref{Log Files}. Von Zeit zu Zeit jedoch muss man hinter
+@code{MySQL} saubermachen, damit die Log-Dateien nicht zu viel
+Festplattenplatz in Anspruch nehmen.
+
+Wenn Sie MySQL mit Log-Dateien benutzen, werden Sie von Zeit zu Zeit alte
+Log-Dateien entfernen wollen und MySQL mitteilen, in neue Dateien zu
+loggen. @xref{Backup}.
+
+Bei einer Linux-(@code{RedHat})-Installation können Sie hierfür das
+@code{mysql-log-rotate}-Skript benutzen. Wenn Sie MySQL von einer
+RPM-Distribution installiert haben, sollte das Skript automatisch
+installiert worden sein. Beachten Sie, dass Sie damit vorsichtig umgehen
+sollten, wenn Sie die Log-Datei für Replikation benutzen!
+
+Auf anderen Systemen müssen Sie selbst ein kurzes Skript installieren, dass
+Sie von @code{cron} starten können, um Log-Dateien zu handhaben.
+
+Sie können MySQL zwingen, mit neuen Log-Dateien zu starten, indem Sie
+@code{mysqladmin flush-logs} oder den SQL-Befehl @code{FLUSH LOGS}
+benutzen. Wenn Sie MySQL-Version 3.21 benutzen, müssen Sie @code{mysqladmin
+refresh} benutzen.
+
+Der obige Befehl macht folgendes:
+
+@itemize @bullet
+@item
+Wenn standardmäßiges Loggen (@code{--log}) oder Loggen langsamer Anfragen
+(@code{--log-slow-queries}) benutzt wird, wird die Log-Datei geschlossen
+und wieder geöffnet (@file{mysql.log} und @file{`hostname`-slow.log} als
+Vorgabe).
+@item
+Wenn Update-Logging (@code{--log-update}) benutzt wird, wird die
+Update-Log-Datei geschlossen und eine neue Log-Datei mit einer höheren
+Log-Zahl geöffnet.
+@end itemize
+
+Wenn Sie nur eine Update-Log-Datei benutzen, müssen Sie die Log-Dateien nur
+auf Platte zurückschreiben (flush) und dann die alten
+Update-Log-Datei-Dateien zu einer Datensicherungsdatei verschieben. Wenn
+Sie normales Loggen benutzen, können Sie etwas wie das Folgende tun:
+
+@example
+shell> cd mysql-data-verzeichnis
+shell> mv mysql.log mysql.old
+shell> mysqladmin flush-logs
+@end example
+
+Und dann eine Datensicherung nehmen und @file{mysql.old} entfernen.
+
+
+@node Replication, , Log Files, MySQL Database Administration
+@c German node Replikation
+@section Replikation bei MySQL
+
+@cindex Replikation
+@cindex erhöhen, Geschwindigkeit
+@cindex Geschwindigkeit, erhöhen
+@cindex Datenbanken, replizieren
+
+
+Dieses Kapitel beschreibt die verschiedenen Replikationsfeatures in MySQL.
+Es dient als Referenz für die Optionen, die bei Replikation verfügbar sind.
+Sie erhalten eine Einführung in die Replikation und lernen, wie Sie sie
+implementieren. Am Ende des Kapitels werden einige häufige gestellte Fragen
+und die dazugehörigen Antworten aufgelistet sowie Beschreibungen der
+Probleme und wie man sie löst.
+
+
+@menu
+* Replication Intro::
+* Replication Implementation::
+* Replication HOWTO::
+* Replication Features::
+* Replication Options::
+* Replication SQL::
+* Replication FAQ::
+* Replication Problems::
+@end menu
+
+@node Replication Intro, Replication Implementation, Replication, Replication
+@c German node Einführung in die Replikation
+@subsection Einführung in die Replikation
+
+Einweg-Replikation wird benutzt, um sowohl Stabilität als auch
+Geschwindigkeit zu steigern. Was Stabilität betrifft, haben Sie zwei
+Möglichkeiten und können zur Möglichkeit der Datensicherung zurückkehren,
+wenn Sie Probleme mit dem Master haben. Die Geschwindigkeitssteigerung wird
+dadurch erreicht, dass ein Teil der Anfragen, die nichts aktualisieren, an
+den Replikationsserver geschickt werden. Das funktioniert naturgemäß nur
+dann, wenn Anfragen, die nichts aktualisieren, überwiegen, aber das ist der
+Normalfall.
+
+@c German FIX changes @xref to @pxref (because it's in parenthesis).
+Ab Version 3.23.15 unterstützt MySQL intern Einweg-Replikation. Ein Server
+agiert als Master, der andere als Slave. Beachten Sie, dass ein Server
+beide Rolle - als Master und als Slave - in einem Paar spielen kann. Der
+Master hält eine Binär-Log-Datei der Aktualisierungen vor
+(@pxref{Binary log}) sowie eine Index-Datei für Binär-Log-Dateien, um
+hinsichtlich der Log-Rotation auf dem Laufenden zu bleiben. Der Slave
+informiert den Master beim Verbinden darüber, wo er seit der letzten
+erfolgreich durchgeführten Aktualisierung aufgehört hat, schließt zu den
+Aktualisierungen auf, blockiert danach und wartet darauf, dass ihn der
+Master über neue Aktualisierungen informiert.
+
+Beachten Sie, dass alle Aktualisierungen auf eine Datenbank, die repliziert
+wird, durch den Master durchgeführt werden sollten!
+
+Ein weiterer Vorteil von Replikation ist, dass man permanente (live)
+Datensicherungen vom System erhält, wenn man die Datensicherung auf dem
+Slave durchführt statt auf dem Master. @xref{Backup}.
+
+
+@node Replication Implementation, Replication HOWTO, Replication Intro, Replication
+@c German node Replikationsimplementation
+@subsection Replikationsimplementation
+
+@cindex Master-Slave-Einrichtung
+
+@c German FIX changes @xref to @pxref (because it's in parenthesis).
+MySQL-Replikation basiert darauf, dass der Server alle Änderungen Ihrer
+Datenbank im Binär-Log verfolgt (Updates, Deletes usw.)
+(@pxref{Binary log}) und der oder die Slave-Server die gespeicherten
+Anfragen aus der Binär-Log-Datei des Masters lesen, so dass der Slave
+dieselben Anfragen auf seine Kopie der Daten ausführen kann.
+
+Es ist @strong{sehr wichtig} sich klarzumachen, dass die Binär-Log-Datei
+schlicht eine Aufzeichnung ist, die ab einem festen Zeitpunkt an startet
+(ab dem Moment, wo Sie Binär-Loggen starten). Alle Slaves, die Sie
+aufsetzen, benötigen Kopien aller Daten vom Master, wie Sie zu dem
+Zeitpunkt existierten, als Binär-Loggen auf dem Master aktiviert wurde.
+Wenn Sie Ihre Slaves mit Daten starten, die nicht mit dem übereinstimmen,
+was auf dem Master war, @strong{als die Binär-Log-Datei gestartet wurde},
+funktionieren Ihre Slaves womöglich nicht richtig.
+
+Eine zukünftige Version (4.0) von MySQL wird die Notwendigkeit beseitigen,
+(eventuell große) Schnappschüsse von Daten für neue Slaves vorzuhalten,
+die Sie über die Live-Datensicherungs-Funktionalität aufsetzen wollen,
+wobei kein Sperren (Locking) erforderlich ist. Zu dieser Zeit ist es jedoch
+notwendig, alle Schreibzugriffe entweder mit einer globalen Lese-Sperre
+oder durch das Herunterfahren des Masters zu blockieren, während man einen
+Schnappschuss anlegt.
+
+Sobald ein Slave korrekt konfiguriert ist und läuft, verbindet er sich
+einfach mit dem Master und wartet darauf, dass Aktualisierung ausgeführt
+werden. Wenn der Master abgeschaltet wird oder der Slave die Verbindung zum
+Master verliert, versucht er alle @code{master-connect-retry} Sekunden,
+sich neu zu verbinden, bis er sich neu verbinden kann, und nimmt dann das
+Warten auf Aktualisierungen wieder auf.
+
+Jeder Slave achtet darauf, wo er aufgehört hat. Der Master-Server weiß
+nicht, wie viele Slaves es gibt oder welche zu einem gegebenen Zeitpunkt
+auf aktuellem Stand sind.
+
+Der nächste Abschnitt erläutert den Master-Slave-Einrichtungsprozess
+detaillierter.
+
+
+@node Replication HOWTO, Replication Features, Replication Implementation, Replication
+@c German node Wie man Replikation aufsetzt
+@subsection Wie man Replikation aufsetzt
+
+Unten findet sich eine kurze Beschreibung, wie Sie komplette Replikation
+auf Ihrem aktuellen MySQL-Server einrichten können. Es wird angenommen,
+dass Sie alle Ihre Datenbanken replizieren wollen und bislang Replikation
+noch nicht konfiguriert haben. Sie müssen Ihren Master-Server kurz herunter
+fahren, um die unten stehenden Schritte fertigzustellen.
+
+@enumerate
+@item
+Stellen Sie sicher, dass Sie eine aktuelle Version von MySQL auf dem Master
+und dem Slave oder den Slaves haben.
+
+Benutzen Sie Version 3.23.29 oder höher. Vorherige Releases benutzten ein
+anderes Binär-Log-Format und hatten Bugs, die in neueren Releases behoben
+wurden. Bitte berichten Sie keine Bugs, bevor Sie bestätigen können, dass
+das Problem im neuesten Release beobachtet werden kann.
+
+@item
+Richten Sie einen speziellen Replikationsbenutzer auf dem Master mit der
+@code{FILE}-Berechtigung und Berechtigungen, sich von allen Slaves aus zu
+verbinden, ein. Wenn der Benutzer ausschließlich Replikation durchführt
+(was empfohlen wird), müssen Sie ihm keine zusätzlichen Berechtigungen
+geben.
+
+Erzeugen Sie zum Beispiel einen Benutzer namens @code{repl}, der auf Ihren
+Master von jedem Host aus zugreifen kann, mit folgendem Befehl:
+
+@example
+GRANT FILE ON *.* TO repl@@"%" IDENTIFIED BY 'passwort';
+@end example
+
+@item
+Fahren Sie den MySQL-Master herunter:
+
+@example
+mysqladmin -u root -ppasswort shutdown
+@end example
+
+@item
+Machen Sie einen Schnappschuss aller Daten auf Ihrem Master-Server.
+
+Die einfachste Art, das (unter Unix) zu tun, ist, einfach @strong{tar} zu
+benutzen, um ein Archiv Ihre gesamten Daten-Verzeichnisses zu erzeugen. Der
+genaue Speicherort Ihres Daten-Verzeichnisses hängt von Ihrer Installation
+ab.
+
+@example
+tar -cvf /tmp/mysql-snapshot.tar /pfad/zu/data-dir
+@end example
+
+Windows-Benutzer können WinZip oder ähnliche Software benutzen, um ein
+Archiv des Daten-Verzeichnisses anzulegen.
+
+@item
+In der Datei @code{my.cnf} für den Master fügen Sie @code{log-bin} und
+@code{server-id=eindeutige_nummer} zum @code{[mysqld]}-Abschnitt und hinzu
+und starten Sie den Server neu. Es ist sehr wichtig, dass die ID auf dem
+Slave sich von der ID auf dem Master unterscheidet. Denken Sie sich
+@code{server-id} als etwas, dass einer IP-Adresse ähnlich ist - es
+identifiziert in der Gemeinschaft der Replikationspartner die
+Server-Instanz eindeutig.
+
+@example
+[mysqld]
+log-bin
+server-id=1
+@end example
+
+@item
+Starten Sie den MySQL-Master neu.
+
+@item
+Fügen Sie auf dem Slave oder den Slaves folgendes zur Datei
+@code{my.cnf} hinzu:
+
+@example
+master-host=hostname_des_masters
+master-user=replikations_benutzername
+master-password=replikations_benutzerpasswort
+master-port=TCP/IP-Port_für_master>
+server-id=eine_eindeutige_nummer_zwischen_2_und_2^32-1
+@end example
+
+Ersetzen Sie die Beispielwerte durch etwas, was für Ihr System stimmig ist.
+
+@code{server-id} muss für jeden Partner, der an Replikation teilnimmt,
+unterschiedlich sein. Wenn Sie keine server-id angeben, wird sie auf 1
+gesetzt, falls Sie @code{master-host} nicht definiert haben, ansonsten wird
+sie auf 2 gesetzt. Beachten Sie für den Fall, dass sie @code{server-id}
+weglassen, dass der Master Verbindungen von allen Slaves verweigert und die
+Slaves verweigern werden, sich mit dem Master zu verbinden. Daher ist das
+Weglassen der @code{server-id} nur dann eine gute Idee, wenn Sie es nur für
+Datensicherungen mit einer Binär-Log-Datei verwenden.
+
+
+@item
+Kopieren Sie die Schnappschuss-Daten in Ihr Daten-Verzeichnis auf Ihrem
+Slave oder Ihren Slaves. Stellen Sie sicher, dass die Berechtigungen auf
+die Dateien und Verzeichnisse korrekt sind. Der Benutzer, unter dem MySQL
+läuft, muss in der Lage sein, sie zu lesen und zu schreiben, genau wie auf
+dem Master.
+
+@item Starten Sie den Slave oder die Slaves neu.
+
+@end enumerate
+
+Nachdem Sie das Obige durchgeführt haben, sollten sich die Slaves mit dem
+Master verbinden können und alle Aktualisierungen mitbekommen, die nach der
+Aufnahme des Schnappschusses passieren.
+
+
+Wenn Sie vergessen haben, die @code{server-id} für den Slave zu setzen,
+erhalten Sie folgenden Fehler in der Fehler-Log-Datei:
+
+@example
+Warning: one should set server_id to a non-0 value if master_host ist set.
+The server will not act as a slave.
+@end example
+
+Wenn Sie vergessen haben, selbiges für den Master zu machen, sind die
+Slaves nicht in der Lage, sich mit dem Master zu verbinden.
+
+Wenn ein Slave aus irgend welchen Gründen nicht in der Lage ist zu
+replizieren, finden Sie Fehlermeldungen in der Fehler-Log-Datei auf dem
+Slave.
+
+Sobald ein Slave repliziert, finden Sie eine Datei namens
+@code{master.info} im selben Verzeichnis, wo auch Ihre Fehler-Log-Datei
+liegt. Die @code{master.info}-Datei wird vom Slave benutzt, um auf dem
+Laufenden zu bleiben, wie viel der Binär-Log-Datei des Masters er bereits
+abgearbeitet hat. Sie sollten die Datei @strong{NICHT} entfernen oder
+editieren, es sei denn, Sie wissen genau, was Sie tun. Selbst in diesem
+Fall sollten Sie vorzugsweise den @code{CHANGE MASTER TO}-Befehl benutzen.
+
+
+
+
+@node Replication Features, Replication Options, Replication HOWTO, Replication
+@c German node Replikationsfeatures
+@subsection Replikationsfeatures und bekannte Probleme
+
+@cindex Optionen, Replikation
+@cindex @code{my.cnf}-Datei
+@cindex Dateien,@code{my.cnf}
+
+Unten steht eine Erläuterung dessen, was unterstützt wird und was nicht:
+
+@itemize @bullet
+@item
+Replikation läuft korrekt mit @code{AUTO_INCREMENT}-,
+@code{LAST_INSERT_ID}- und @code{TIMESTAMP}-Werten.
+@item
+@code{RAND()} bei Updates repliziert nicht korrekt. Benutzen Sie
+@code{RAND(ein_nicht_zufalls_ausdruck)}, wenn Sie Updates mit
+@code{RAND()} replizieren. Sie können zum Beispiel @code{UNIX_TIMESTAMP()}
+als Argument für @code{RAND()} benutzen.
+@item
+Sie müssen auf Master und Slave denselben Zeichensatz
+(@code{--default-character-set}) benutzen. Wenn nicht, erhalten Sie
+eventuell Fehler wegen doppelter Schlüsseleinträge (duplicate key) auf dem
+Slave, weil ein Schlüssel, der auf dem Master als eindeutig betrachtet
+wird, das in einem anderen Zeichensatz eventuell nicht ist.
+@item
+@code{LOAD DATA INFILE} wird korrekt gehandhabt, solange die Datei zur Zeit
+der Update-Ausführung noch auf dem Master-Server liegt. @code{LOAD LOCAL
+DATA INFILE} wird übersprungen.
+@item
+Aktualisierungsanfragen, die Benutzer-Variablen benutzen, sind (noch) nicht
+replikationssicher.
+@item
+@code{FLUSH}-Befehle werden nicht in der Binär-Log-Datei gespeichert und
+werden deswegen nicht auf den Slaves repliziert. Das stellt normalerweise
+kein Problem dar, weil @code{FLUSH} nichts ändert. In Bezug auf die
+@code{MySQL}-Berechtigungstabellen heißt das jedoch, dass Sie bei direkten
+Änderungen in diesen Tabellen ohne Benutzung des @code{GRANT}-Statements
+und der anschließenden Replikation der
+@code{MySQL}-Berechtigungs-Datenbank auf den Slaves @code{FLUSH PRIVILEGES}
+ausführen müssen, damit die neuen Berechtigungen wirksam werden.
+@item
+Temporäre Tabellen werden ab Version 3.23.29 korrekt repliziert,
+ausgenommen im Fall, dass Sie den Slave-Server schließen (nicht nur den
+Slave-Thread), Sie noch einige temporäre Tabellen offen haben und diese bei
+nachfolgenden Aktualisierungen benutzt werden. Um mit diesem Problem fertig
+zu werden, schließen Sie den Slave mit @code{SLAVE STOP} und prüfen dann
+die @code{Slave_open_temp_tables}-Variable, um zu sehen, ob Sie 0 ist. Dann
+führen Sie @code{mysqladmin shutdown} aus. Wenn die Variable nicht 0 ist,
+starten Sie den Slave-Thread neu mit @code{SLAVE START} und probieren es
+noch einmal. Zukünftig (ab Version 4.0) wird es eine sauberere Lösung
+geben.
+In früheren Versionen wurden temporäre Tabellen nicht korrekt repliziert.
+Wir empfehlen, dass Sie entweder auf eine neuere Version aktualisieren oder
+vor allen Anfragen mit temporären Tabellen @code{SET SQL_LOG_BIN=0} auf
+alle Clients ausführen.
+@item
+MySQL unterstütz nur einen Master und viele Slaves. In Version 4.x wird ein
+Abstimmungsalgorithmus eingebaut, der automatisch den Master umschaltet,
+wenn etwas mit dem aktuellen Master schief geht. Ausserdem werden wir
+'Agenten'-Prozesse einführen, die bei der Lastverteilung helfen, indem sie
+SELECT-Anfragen an verschiedene Slaves senden.
+@item
+Ab Version 3.23.26 ist es sicher, Server in einer zirkulären
+Master-Slave-Beziehung mit angeschaltetem @code{log-slave-updates} zu
+verbinden. Beachten Sie jedoch, dass bei dieser Art von Einrichtung viele
+Anfrage nicht richtig funktionieren, es sei denn, Ihr Client-Code ist so
+geschrieben, dass er sich um mögliche Probleme kümmert, die durch
+Aktualisierungen auftreten können, die in unterschiedlicher Reihenfolge auf
+verschiedenen Servern laufen.
+
+Das bedeutet, dass Sie eine Einrichtung wie die folgende machen können:
+
+@example
+A -> B -> C -> A
+@end example
+
+Diese Einrichtung funktioniert nur dann, wenn Sie ausschließlich
+Aktualisierungen ausführen, die nicht zwischen den Tabellen zu Konflikten
+führen. Mit anderen Worten, wenn Sie Daten in A und C einfügen, sollten Sie
+nie eine Zeile in A einfügen, die zu einem Konflikt mit einem Schlüsselwert
+bei einem Zeilen-Einfügevorgang in C führt. Ebenfalls sollte Sie nie
+dieselben Zeilen auf zwei Servern einfügen, wenn die Reihenfolge, in der
+die Aktualisierungen durchgeführt werden, eine Rolle spielt.
+
+Beachten Sie, dass sich das Log-Format in Version 3.23.26 geändert hat, so
+das Slaves vor Version 3.23.26 diese nicht lesen können.
+@item
+Wenn die Anfrage auf dem Slave zu einem Fehler führt, beendet sich der
+Slave-Thread und in der @code{.err}-Datei erscheint eine Meldung. Sie
+sollten sich dann manuell mit dem Slave verbinden, die Ursache des Fehlers
+beheben (zum Beispiel nicht existierende Tabellen) und dann den SQL-Befehl
+@code{SLAVE START} laufen lassen (verfügbar ab Version 3.23.16). In Version
+3.23.15 müssen Sie den Server neu starten.
+@item
+Wenn die Verbindung zum Master verloren geht, versucht der Slave
+unmittelbar, sich neu zu verbinden, und wenn das fehlschlägt, alle
+@code{master-connect-retry} Sekunden (Vorgabe 60 Sekunden). Deswegen ist es
+sicher, den Master herunter zu fahren und dann nach einer Weile wieder
+hochzufahren. Der Slave ist auch in der Lage, mit
+Netzwerk-Verbindungsausfällen umzugehen.
+@item
+Den Slave (sauber) herunterzufahren ist ebenfalls sicher, weil er sich
+merkt, wo er aufgehört hat. Unsauberes Herunterfahren kann zu Problemen
+führen, insbesondere dann, wenn der Platten-Cache nicht synchronisiert
+wurde, als das System starb. Die Fehlertoleranz Ihres Systems wird stark
+verbessert, wenn Sie ein gutes UPS haben.
+@item
+Wenn der Master auf einem Port auf Anfragen wartet, der nicht Standard ist,
+müssen Sie diesen mit dem @code{master-port}-Parameter in @code{my.cnf}
+angeben.
+@item
+In Version 3.23.15 werden alle Tabellen und Datenbanken repliziert. Ab
+Version 3.23.16 können Sie die Replikation mit der
+@code{replicate-do-db}-Anweisung in @code{my.cnf} auf einen Satz von
+Datenbanken beschränken oder einen Satz von Datenbanken mit
+@code{replicate-ignore-db} ausschließen. Beachten Sie, dass es bis Version
+3.23.23 einen Bug gab, so dass mit @code{LOAD DATA INFILE} nicht sauber
+umgegangen wurde, wenn Sie diesen Befehl in einer Datenbank ausführten, die
+von der Replikation ausgeschlossen war.
+@item
+Ab Version 3.23.16 schaltet @code{SET SQL_LOG_BIN = 0}
+Replikations-(Binär)-Loggen auf dem Master aus und @code{SET SQL_LOG_BIN =
+1} schaltet es wieder an. Sie benötigen die process-Berechtigung, um das
+auszuführen.
+@item
+Ab Version 3.23.19, you can clean up stale Replikation leftovers when
+something goes wrong und you want a clean start mit @code{FLUSH MASTER}
+und @code{FLUSH SLAVE}-Befehle. In Version 3.23.26 we have renamed them to
+@code{RESET MASTER} und @code{RESET SLAVE} respectively to clarify
+what they do. The old @code{FLUSH} variants still work, though, for
+Kompatibilität.
+
+@item
+Ab Version 3.23.21, you can use @code{LOAD TABLE FROM MASTER} for
+network backup und to set up Replikation initially. We have recently
+received a Anzahl von bug reports concerning it that we are investigating, so
+we recommend that you use it only in testing until we make it mehr stable.
+@item
+Ab Version 3.23.23, you can change masters und adjust log position
+mit @code{CHANGE MASTER TO}.
+@item
+Ab Version 3.23.23, you tell the master that updates in certain
+Datenbanken should not be logged to the Binär-Log-Datei mit @code{binlog-ignore-db}.
+@item
+Ab Version 3.23.26 können Sie @code{replicate-rewrite-db} benutzen, um den
+Slave anzuweisen, Aktualisierungen einer Datenbank auf dem Master auf eine
+mit einem anderen Namen auf dem Slave anzuwenden.
+@item
+Ab Version 3.23.28 können Sie @code{PURGE MASTER LOGS TO 'log-name'}
+benutzen, um alte Log-Dateien loszuwerden, während der Slave läuft.
+@end itemize
+
+
+@node Replication Options, Replication SQL, Replication Features, Replication
+@c German node Replikationsoptionen
+@subsection Replikationsoptionen in my.cnf
+
+Wenn Sie Replikation benutzen, empfehlen wir, dass Sie MySQL-Version
+3.23.30 oder höher benutzen. Ältere Versionen funktionieren, haben aber
+einige Bugs und fehlende Features.
+
+Sowohl auf dem Master als auch auf dem Slave müssen Sie die
+@code{server-id}-Option benutzen. Diese setzt eine eindeutige
+Replikations-ID. Sie sollten einen eindeutigen Wert im Bereich zwischen 1
+und 2^32-1 für jeden Master und Slave benutzen. Beispiel: @code{server-id=3}
+
+In folgender Tabelle stehen die Optionen, die Sie für den @strong{MASTER}
+benutzen können:
+
+@multitable @columnfractions .3 .7
+
+@item @strong{Option} @tab @strong{Beschreibung}
+@item @code{log-bin=dateiname} @tab
+Schreibt in die binäre Update-Log-Datei am angegebenen Ort. Beachten Sie,
+dass, wenn Sie ihr einen Parameter mit einer Erweiterung angeben (zum
+Beispiel @code{log-bin=/mysql/logs/replikation.log}), Versionen bis zu
+3.23.24 während der Replikation nicht richtig funktionieren, wen Sie
+@code{FLUSH LOGS} ausführen. Das Problem ist seit Version 3.23.25 behoben.
+Wenn Sie Log-Namen dieser Art benutzen, wird @code{FLUSH LOGS} auf dem
+binären Log ignoriert. Um das Log zu löschen, führen Sie @code{FLUSH
+MASTER} aus. Vergessen Sie dabei nicht, @code{FLUSH SLAVE} auf allen Slaves
+laufen zu lassen.Ab Version 3.23.26 sollten Sie @code{RESET MASTER} und
+@code{RESET SLAVE} benutzen.
+
+@item @code{log-bin-index=dateiname} @tab
+Weil der Benutzer @code{FLUSH LOGS}-Befehle ausführen könnte, muss man
+wissen, welches Log momentan aktiv ist und welche in welcher Reihenfolge
+durch Log-Rotation herausgenommen wurden. Diese Informationen sind in der
+Binär-Log-Index-Datei gespeichert. Der Vorgabewert ist `hostname`.index.
+
+Beispiel: @code{log-bin-index=datenbank.index}.
+
+@item @code{sql-bin-update-same} @tab
+Falls gesetzt, führt das Setzen von @code{SQL_LOG_BIN} auf einen Wert
+automatisch dazu, dass @code{SQL_LOG_UPDATE} auf denselben Wert gesetzt
+wird, und umgekehrt.
+
+@item @code{binlog-do-db=datenbank} @tab
+Weist den Master an, Aktualisierung in die Binär-Log-Datei zu loggen, wenn
+die aktuelle Datenbank 'datenbank' ist. Alle anderen Datenbanken werden
+ignoriert. Beachten Sie bei der Benutzung, dass Sie sicherstellen sollten,
+dass Sie Aktualisierungen nur in der aktuellen Datenbank ausführen.
+
+Beispiel: @code{binlog-do-db=eine_datenbank}.
+
+@item @code{binlog-ignore-db=datenbank} @tab
+Weist den Master an, das Aktualisierung der aktuellen Datenbank 'datenbank'
+nicht in der Binär-Log-Datei gespeichert werden sollen. ignoriert. Beachten
+Sie bei der Benutzung, dass Sie sicherstellen sollten, dass Sie
+Aktualisierungen nur in der aktuellen Datenbank ausführen.
+
+Beispiel: @code{binlog-ignore-db=eine_datenbank}
+@end multitable
+
+Folgende Tabelle enthält die Optionen, die Sie für @strong{SLAVE} benutzen
+können:
+
+@multitable @columnfractions .3 .7
+
+@item @strong{Option} @tab @strong{Beschreibung}
+@item @code{master-host=host} @tab
+Hostname des Masters oder IP-Adresse für Replikation. Falls nicht gesetzt,
+startet der Slave-Thread nicht.
+
+Beispiel: @code{master-host=datenbank-master.meinefirma.de}.
+
+@item @code{master-user=benutzername} @tab
+Der Benutzer, den der Slave-Thread für Authentifizierung benutzt, wenn er
+sich mit dem Master verbindet. Der Benutzer muss die
+@code{FILE}-Berechtigung besitzen. Wenn der Master-Benutzer nicht gesetzt
+ist, wird Benutzer @code{test} angenommen.
+
+Beispiel: @code{master-user=steve}.
+
+@item @code{master-password=passwort} @tab
+Das Passwort, das der Slave-Thread für Authentifizierung benutzt, wenn er
+sich mit dem Master verbindet. Wenn nicht gesetzt, wird ein leeres Passwort
+angenommen.
+
+Beispiel: @code{master-password=hund}.
+
+@item @code{master-port=portnummer} @tab
+Der Port, auf dem der Master auf Verbindungen wartet. Wenn nicht gesetzt,
+wird die kompilierte Einstellung von @code{MYSQL_PORT} angenommen. Wenn Sie
+nicht an den @code{configure}-Optionen gedreht haben, sollte das 3306 sein.
+
+Beispiel: @code{master-port=3306}.
+
+@item @code{master-connect-retry=sekunden} @tab
+Die Anzahl Sekunden, die der Slave-Thread schläft, bevor er wiederum
+versucht, sich mit dem Master zu verbinden, falls der Master herunter fuhr
+oder die Verbindung verloren ging. Vorgabewert ist 60.
+
+Beispiel: @code{master-connect-retry=60}.
+
+@item @code{master-ssl} @tab
+Schaltet SSL an.
+
+Beispiel: @code{master-ssl}.
+
+@item @code{master-ssl-key} @tab
+Der Name der SSL-Schlüsseldatei für den Master.
+
+Beispiel: @code{master-ssl-key=SSL/master-key.pem}.
+
+@item @code{master-ssl-cert} @tab
+Der Dateiname des SSL-Zertifikats für den Master.
+
+Beispiel: @code{master-ssl-key=SSL/master-cert.pem}.
+
+@item @code{master-info-file=dateiname} @tab
+Der Speicherort der Datei, die sich merkt, bis wohin der Master während des
+Replikationsprozesses verfolgt wurde. Vorgabewert ist master.info im data-
+Verzeichnis.
+
+Beispiel: @code{master-info-file=master.info}.
+
+@item @code{replicate-do-table=datenbank.tabelle} @tab
+Weist den Slave-Thread an, die Replikation auf die angegebene Tabelle zu
+beschränken. Um mehr als eine Tabelle anzugeben, benutzen Sie die Anweisung
+mehrfach, einmal für jede Tabelle. Das funktioniert auch bei
+Datenbank-übergreifenden Aktualisierungen, im Gegensatz zu
+@code{replicate-do-db}.
+
+Beispiel: @code{replicate-do-table=eine_datenbank.eine_tabelle}.
+
+@item @code{replicate-ignore-table=datenbank.tabelle} @tab
+Weist den Slave-Thread an, die angegebene Tabelle nicht zu replizieren. Um
+mehr als eine Tabelle anzugeben, die ignoriert werden soll, geben Sie die
+Anweisung mehrfach ein, einmal für jede Tabelle. Das funktioniert auch bei
+Datenbank-übergreifenden Aktualisierungen, im Gegensatz zu
+@code{replicate-ignore-db}.
+
+Beispiel: @code{replicate-ignore-table=eine_datenbank.eine_tabelle}.
+
+@item @code{replicate-wild-do-table=datenbank.tabelle} @tab
+Weist den Slave-Thread an, die Replikation auf Tabellen zu beschränken, die
+dem angegebenen Platzhalter-Muster entsprechen. Um mehr als ein
+Tabellenmuster anzugeben, das ignoriert werden soll, geben Sie die
+Anweisung mehrfach ein, einmal für jedes Tabellenmuster. Das funktioniert
+auch bei Datenbank-übergreifenden Aktualisierungen.
+
+Beispiel: @code{replicate-wild-do-table=foo%.bar%} repliziert nur
+Aktualisierungen auf Tabellen in allen Datenbanken, die mit 'foo' anfangen
+und deren Tabellennamen mit 'bar' beginnen.
+
+@item @code{replicate-wild-ignore-table=datenbank.tabelle} @tab
+Weist den Slave-Thread an, Tabellen nicht zu replizieren, die dem
+angegebenen Platzhalter-Muster entsprechen. Um mehr als ein
+Tabellenmuster anzugeben, das ignoriert werden soll, geben Sie die
+Anweisung mehrfach ein, einmal für jedes Tabellenmuster. Das funktioniert
+auch bei Datenbank-übergreifenden Aktualisierungen.
+
+Beispiel: @code{replicate-wild-ignore-table=foo%.bar%} aktualisiert keine
+Tabellen in Datenbanken, die mit 'foo' anfangen und deren Tabellennamen mit
+'bar' beginnen.
+
+@item @code{replicate-ignore-db=datenbank} @tab
+Weist den Slave-Thread an, die angegebene Datenbank nicht zu replizieren.
+Um mehr als eine Datenbank anzugeben, die ignoriert werden soll, geben Sie
+die Anweisung mehrfach ein, einmal für jede Datenbank. Diese Option
+funktioniert nicht für Datenbank-übergreifende Aktualisierungen. Wenn Sie
+Datenbank-übergreifende Aktualisierungen brauchen, stellen Sie sicher, dass
+Sie Version 3.23.28 oder höher verwenden und benutzen Sie
+@code{replicate-wild-ignore-table=datenbank.%}
+
+Beispiel: @code{replicate-ignore-db=eine_datenbank}.
+
+@item @code{replicate-do-db=datenbank} @tab
+
+Weist den Slave-Thread an, die Replikation auf die angegebene Datenbank zu
+beschränken. Um mehr als eine Datenbank anzugeben, benutzen Sie die
+Anweisung mehrfach, einmal für jede Datenbank. Beachten Sie, dass das nicht
+funktioniert, wenn Sie Datenbank-übergreifende Anfragen wie @code{UPDATE
+eine_datenbank.eine_tabelle SET foo='bar'} ausführen, während Sie eine
+andere oder keine Datenbank ausgewählt haben. Wenn Sie
+Datenbank-übergreifende Aktualisierungen brauchen, stellen Sie sicher, dass
+Sie Version 3.23.28 oder höher verwenden und benutzen Sie
+@code{replicate-wild-do-table=datenbank.%}.
+
+Beispiel: @code{replicate-do-db=eine_datenbank}.
+
+@item @code{log-slave-updates} @tab
+Weist den Slave an, Aktualisierungen vom Slave-Thread in die binäre
+Log-Datei zu schreiben. Ist vorgabemäßig ausgeschaltet. Sie müssen diese
+Option anschalten, wenn Sie planen, die Slave in eine zirkuläre Kette zu
+hängen ('Daisy-Chain').
+
+@item @code{replicate-rewrite-db=von_name->zu_name} @tab
+Aktualisierungen auf eine Datenbank mit einem anderen Namen als dem
+Orginalnamen.
+
+Beispiel: @code{replicate-rewrite-db=master_datenbank->slave_datenbank}.
+
+@item @code{skip-slave-start} @tab
+Weist den Slave-Server an, den Slave nicht beim Hochfahren zu starten. Der
+Benutzer kann ihn später mit @code{SLAVE START} starten.
+
+@item @code{slave_read_timeout=#} @tab
+Anzahl von Sekunden, die der Slave auf weitere Daten vom Master wartet,
+bevor er abbricht.
+@end multitable
+
+
+@node Replication SQL, Replication FAQ, Replication Options, Replication
+@c German node SQL und Replikation
+@subsection SQL-Befehle in Bezug auf Replikation
+
+@cindex SQL-Befehle, Replikation
+@cindex Befehle, Replikation
+@cindex Replikation, Befehle
+
+Replikation kann über die SQL-Schnittstelle gesteuert werden. Hier eine
+Zusammenfassung der Befehle:
+
+@multitable @columnfractions .30 .70
+@item @strong{Befehl} @tab @strong{Beschreibung}
+
+@item @code{SLAVE START}
+ @tab Startet den Slave-Thread. (Slave)
+
+@item @code{SLAVE STOP}
+ @tab Hält den Slave-Thread an. (Slave)
+
+@item @code{SET SQL_LOG_BIN=0}
+ @tab Schaltet das Loggen in die Update-Log-Datei aus, wenn der Benutzer
+die process-Berechtigung hat. Wird ansonsten ignoriert. (Master)
+
+@item @code{SET SQL_LOG_BIN=1}
+ @tab Schaltet das Loggen in die Update-Log-Datei wieder an, wenn der
+Benutzer die process-Berechtigung hat. Wird ansonsten ignoriert. (Master)
+
+@item @code{SET SQL_SLAVE_SKIP_COUNTER=n}
+ @tab Die nächsten @code{n} Ereignisse vom Master ignorieren. Gilt nur,
+wenn der Slave-Thread nicht läuft, gibt ansonsten einen Fehler aus.
+Nützlich für den Ausgleich von Replikationsabweichungen.
+
+@item @code{RESET MASTER}
+ @tab Löscht alle Binär-Log-Dateien, die in der Index-Datei aufgeführt
+sind, und setzt die BinärLog-Index-Datei auf leer zurück. In Versionen vor
+3.23.26 versions heißt dieser Befehl @code{FLUSH MASTER}. (Master)
+
+@item @code{RESET SLAVE}
+ @tab Führt dazu, dass der Slave seine Replikationsposition in den
+Master-Logs vergisst. In Versionen vor 3.23.26 versions heißt dieser
+Befehl @code{FLUSH SLAVE}. (Slave)
+
+@item @code{LOAD TABLE tabelle FROM MASTER}
+ @tab Lädt eine Kopie der Tabelle vom Master auf den Slave. (Slave)
+
+@item @code{CHANGE MASTER TO master_def_list}
+ @tab Ändert die Master-Parameters auf den Wert, der in
+@code{master_def_list} angegeben ist, und startet den Slave-Thread neu.
+@code{master_def_list} ist eine durch Kommas getrennte Liste
+@code{master_def}, wobei @code{master_def} eins der folgenden Elemente ist:
+@code{MASTER_HOST}, @code{MASTER_USER}, @code{MASTER_PASSWORD},
+@code{MASTER_PORT}, @code{MASTER_CONNECT_RETRY}, @code{MASTER_LOG_FILE}
+oder @code{MASTER_LOG_POS}. Beispiel:
+
+@example
+
+CHANGE MASTER TO
+ MASTER_HOST='master2.meinefirma.com',
+ MASTER_USER='replikation',
+ MASTER_PASSWORD='gro33esgeheimnis',
+ MASTER_PORT=3306,
+ MASTER_LOG_FILE='master2-bin.001',
+ MASTER_LOG_POS=4;
+
+@end example
+
+Sie müssen nur die Werte angeben, die geändert werden sollen. Die Werte,
+die Sie auslassen, bleiben dieselben, ausser wenn Sie den Host oder den
+Port ändern. In diesem Fall nimmt der Slave an, dass der Master ein anderer
+ist, weil Sie sich zu einem anderen Host oder über einen anderen Port
+verbinden. Daher treffen die alten Werte von Log und Position nicht mehr zu
+und werden automatisch auf eine leere Zeichenkette bzw. auf 0 zurück
+gesetzt (dem Startwert). Beachten Sie, dass sich der Slave beim Neustart an
+seinen alten Master erinnert. Falls das nicht wünschenswert ist, sollten
+Sie die @file{master.info}-Datei löschen, bevor Sie neu starten. Der Slave
+liest dann seinen Master aus der Datei @code{my.cnf} oder von der
+Kommandozeile. (Slave)
+
+@item @code{SHOW MASTER STATUS}
+ @tab Stellt Statusinformationen über die Binär-Log-Datei des Masters zur
+Verfügung. (Master)
+
+@item @code{SHOW SLAVE STATUS}
+ @tab Stellt Statusinformationen über die wichtigsten Parameter des
+Slave-Threads zur Verfügung. (Slave)
+@item @code{SHOW MASTER LOGS}
+ @tab Nur verfügbar ab Version 3.23.28. Listet die Binär-Log-Dateien auf
+dem Master auf. Sie sollten diesen Befehl vor @code{PURGE MASTER LOGS TO}
+benutzen, um herauszufinden, wie weit Sie gehen sollten.
+
+@item @code{PURGE MASTER LOGS TO 'logname'}
+ @tab Verfügbar ab Version 3.23.28. Löscht alle Replikations-Logs, die in
+der Index-Log-Datei aufgeführt sind, die vor dem angegebenen Log liegen und
+entfernt Sie aus dem Log-Index, so dass die angegebene Log-Datei nunmehr
+die erste wird. Beispiel:
+
+@example
+PURGE MASTER LOGS TO 'mysql-bin.010'
+@end example
+
+Dieser Befehl macht nichts und schlägt mit einer Fehlermeldung fehl, wenn
+Sie einen aktiven Slave haben, der momentan eine der Log-Dateien liest, die
+Sie zu löschen versuchen. Wenn Sie jedoch einen schlafenden Slave haben und
+gerade eine der Log-Dateien löschen, die dieser Slave lesen will, wird der
+Slave nicht in der Lage sein zu replizieren, sobald er wach wird. Der
+Befehl kann sicher verwendet werden, während Slaves replizieren - Sie
+brauchen diese also nicht anhalten.
+
+Zuerst müssen Sie alle Slaves mit @code{SHOW SLAVE STATUS} überprüfen, um
+festzustellen, an welcher Log-Datei sie gerade sind, dann eine Auflistung
+aller Log-Dateien auf dem Master mit @code{SHOW MASTER LOGS} machen, die
+früheste davon herausfinden, an der noch ein Slave arbeitet (wenn alle
+Slaves aktuell sind, ist das die letzte Log-Datei auf der Liste), dann alle
+Logs, die Sie löschen wollen, sichern (optional), und schließlich bis zum
+Ziel-Log löschen.
+
+@end multitable
+
+
+@node Replication FAQ, Replication Problems, Replication SQL, Replication
+@c German node Replikations-FAQ
+@subsection Replikation - Häufig gestellte Fragen
+
+@cindex @code{Binlog_Dump}
+@strong{Frage}: Warum sehe ich manchmal mehr als eine
+@code{Binlog_Dump}-Thread auf dem Master, nachdem ich den Slave neu
+gestartet habe?
+
+@strong{Antwort}: @code{Binlog_Dump} ist ein kontinuierlicher Prozess, der
+folgendermaßen vom Server gehandhabt wird:
+
+@itemize @bullet
+@item
+Zu den Aktualisierungen aufschließen.
+@item
+Sobald keine Aktualisierungen mehr übrig sind, in den Zustand
+@code{pThread_cond_wait()} gehen, durch den er entweder durch eine
+Aktualisierung oder einen Kill erweckt werden kann.
+@item
+Beim Aufwachen den Grund dafür prüfen. Wenn er nicht sterben soll,
+mit der @code{Binlog_dump}-Schleife weitermachen.
+@item
+Wenn ein schwerer Fehler auftritt, wenn zum Beispiel ein toter Client
+entdeckt wird, die Schleife beenden.
+@end itemize
+
+Wenn der Slave-Thread also beim Slave anhält, bemerkt das der entsprechende
+@code{Binlog_Dump}-Thread auf dem Master solange nicht, bis zumindest eine
+Aktualisierung (oder ein Kill) auf den Master durchgeführt wird, was
+benötigt wird, um ihn von @code{pThread_cond_wait()} aufzuwecken. In der
+Zwischenzeit könnte der Slave bereits eine weitere Verbindung geöffnet
+haben, die in einem weiteren @code{Binlog_Dump}-Thread resultiert.
+
+Das beschriebene Problem sollten in Versionen ab 3.23.26 nicht auftreten.
+In Version 3.23.26 kam @code{server-id} für jeden Replikationsserver hinzu,
+und nun werden alle alten Zombie-Threads auf dem Master gekillt, wenn ein
+neuer Replikations-Thread sich vom selben Slave aus verbindet.
+
+@strong{Frage}: Wie rotiere ich Replikations-Logs?
+
+@strong{Antwort}: In Version 3.23.28 sollten Sie den @code{PURGE MASTER
+LOGS TO}-Befehl benutzen, nachdem festgestellt wurde, welche Logs gelöscht
+werden können und nachdem sie optional gesichert wurden. In früheren
+Versionen ist der Prozess sehr viel anstrengender und kann nicht sicher
+durchgeführt werden, ohne alle Slaves anzuhalten, falls Sie planen,
+Log-Namen wiederholt zu verwenden. Sie müssen die Slave-Threads anhalten,
+die Binär-Log-Index-Datei editieren, alle alten Logs löschen, den Master
+neu starten, die Slave-Threads neu starten und dann die alten Log-Dateien
+entfernen.
+
+
+@strong{Frage}: Wie aktualisiere ich bei einer laufenden
+Replikationseinrichtung?
+
+@strong{Antwort}: Wenn Sie vor Version 3.23.26 aktualisieren, sollten Sie
+nur die Master-Tabellen sperren, warten, bis die Slaves auf aktuellem Stand
+sind, und dann @code{FLUSH MASTER} auf dem Master und @code{FLUSH SLAVE}
+auf dem Slave laufen lassen, um die Logs zurückzusetzen, und danach neue
+Versionen des Masters und des Slaves neu starten. Beachten Sie, dass der
+Slave für einige Zeit heruntergefahren bleiben kann - weil der Master alle
+Aktualisierung loggt, wird der Slave in der Lage sein, auf den aktuellen
+Stand zu kommen, sobald er hoch gefahren ist und sich verbinden kann.
+
+Nach Version 3.23.26 wurde das Replikationsprotokoll für Änderungen
+gesperrt, daher können Sie Masters und Slaves im laufenden Betrieb auf eine
+neuere 3.23-Version aktualisieren, und Sie können unterschiedliche
+Versionen von MySQL auf Slave und Master laufen haben, solange beide neuer
+als Version 3.23.26 sind.
+
+@cindex Replikation, Zweiweg-
+@strong{Frage}: Welche Dinge sollte ich beachten, wenn ich
+Zweiweg-Replikation aufsetze?
+
+@strong{Antwort}: MySQL-Replikation unterstützt derzeit kein
+Sperr-Protokoll zwischen Master und Slave, um die Atomizität einer
+verteilten (Cross-Server-) Aktualisierung zu gewährleisten. Mit anderen
+Worten ist es für einen Client A möglich, eine Aktualisierung zu Co-Master
+1 zu machen. In der Zwischenzeit, bevor er sich an Co-Master 2 wendet,
+könnte Client B eine Aktualisierung auf Co-Master 2 machen, die dazu führt,
+dass die Aktualisierung von Client A anders funktioniert als auf Master 1.
+Wenn daher die Aktualisierung von Client A zu Co-Master 2 durchdringt,
+produziert das Tabellen, die anders sein werden als die auf Co-Master 1,
+selbst nachdem alle Aktualisierungen von Co-Master 2 ebenfalls durchgeführt
+wurden. Daher sollten sie keine zwei Server in einer Zweiweg-Replikation
+verketten, es sei denn, Sie können sicher sein, dass Ihre Aktualisierungen
+immer in bestimmter Reihenfolge ablaufen, oder indem Sie irgendwie in Ihrem
+Client-Code Vorkehrungen gegen Aktualisierung treffen, die nicht in der
+richtigen Reihenfolge sind.
+
+Sie müssen sich auch darüber im Klaren sein, dass Zweiweg-Replikation Ihre
+Performance nicht wesentlich verbessert, falls überhaupt, sofern
+Aktualisierungen betroffen sind. Beide Server müssen ungefähr dieselbe
+Menge Aktualisierungen durchführen, was auch ein Server hätte tun können.
+Der einzige Unterschied liegt darin, dass es sehr viel weniger
+Lock-Contention gibt, weil die Aktualisierungen, die von einem anderen
+Server stammen, in einem Slave-Thread serialisiert werden. Dennoch kann der
+erzielte Vorteil durch Netzwerk-Verzögerungen konterkariert werden.
+
+@cindex Performance, verbessern
+@cindex erhöhen, Performance
+@strong{Frage}: Wie kann ich Replikation benutzen, um die Performance
+meines Systems zu verbessern?
+
+@strong{Antwort}: Sie sollten einen Server als Master aufsetzen und alle
+Schreibvorgänge zu ihm lenken, und so viele Slaves wie möglich einrichten
+und die Lesevorgänge zwischen Master und Slaves verteilen. Ausserdem können
+Sie die Slaves mit @code{--skip-bdb}, @code{--low-priority-updates} und
+@code{--delay-key-write-for-all-tables} starten, um für die Slaves
+Geschwindigkeitsverbesserungen zu erzielen. In diesem Fall benutzt der
+Slave nicht transaktionale @code{MyISAM}-Tabellen anstelle von
+@code{BDB}-Tabellen, um mehr Geschwindigkeit zu erhalten.
+
+@strong{Frage}: Was muss ich in meinem Client-Code tun, damit dieser
+Performance-verbessernde Replikation nutzt?
+
+@strong{Antwort}:
+Wenn der Teil Ihres Codes, der für den Datenbankzugriff zuständig ist,
+korrekt abstrahiert / modularisiert ist, sollte die Konvertierung zur
+replizierten Einrichtung sehr glatt und einfach verlaufen: Ändern Sie die
+Implementation Ihres Datenbankzugriffs so, dass von irgend einem Slave oder
+dem Master gelesen und immer zum Master geschrieben wird. Wenn Ihr Code
+nicht diese Abstraktionsebene besitzt, ist die Einrichtung eines
+Replikationssystems ein guter Grund, ihn zu säubern. Sie könnten damit
+beginnen, eine Wrapper-Bibliothek oder ein Wrapper-Modul mit folgenden
+Funktionen zu benutzen:
+
+@itemize @bullet
+@item
+@code{safe_writer_connect()}
+@item
+@code{safe_reader_connect()}
+@item
+@code{safe_reader_query()}
+@item
+@code{safe_writer_query()}
+@end itemize
+
+@code{safe_} bedeutet, dass die Funktion sich um die Handhabung jeglicher
+Fehlerbedingungen kümmert.
+
+Danach sollten Sie Ihren Client-Code so umwandeln, dass er die
+Wrapper-Bibliothek benutzt. Dieser Prozess kann anfangs etwas anstrengend
+und aufregend sein, wird sich aber auf lange Sicht lohnen. Alle
+Applikationen, die dem geschilderten Muster folgen, werden ebenfalls Nutzen
+aus der Master-/Slaves-Lösung ziehen. Der Code wird sich viel einfacher
+pflegen lassen und Optionen zur Problemlösung werden trivial sein. Sie
+brauchen einfach nur ein oder zwei Funktionen zu ändern, um zum Beispiel zu
+loggen, wie lang jede Anfrage dauerte, oder welche Anfrage unter Ihren
+Tausenden einen Fehler produzierte. Wenn Sie schon eine Menge Code
+geschrieben haben, wollen Sie den Umwandlungsprozess wahrscheinlich
+automatisieren. Hierfür können Sie zum Beispiel Monty's
+@code{replace}-Dienstprogramm benutzen, das der Standard-Distribution von
+MySQL beiliegt, oder Ihr eigenes Perl-Skript schreiben. Hoffentlich folgt
+Ihr Code irgend einem erkennbaren Muster - wenn nicht, ist es
+wahrscheinlich ohnehin besser, ihn neu zu schreiben, oder zumindest, ihn
+durchzugehen und manuell in ein Muster zu bringen.
+
+Beachten Sie, dass Sie natürlich andere Namen für die Funktionen verwenden
+können. Wichtig ist, eine einheitliche Schnittstelle für Verbindungen zum
+Lesen, Verbindungen zum Schreiben, Durchführen von Lesevorgängen und
+Durchführung von Schreibvorgängen zu haben.
+
+
+@strong{Frage}: Wann und in welchem Umfang kann MySQL-Replikation die
+Performance meines Systems verbessern?
+
+@strong{Antwort}: MySQL-Replikation bringt die meisten Vorteile auf einem
+System mit häufigen Lesevorgängen und nicht so häufigen Schreibvorgängen.
+Theoretisch können Sie eine Einrichtung aus einem Master und vielen Slaves
+so skalieren, dass Sie solange Slaves hinzufügen, bis Sie entweder keine
+Netzwerk-Bandbreite mehr haben oder bis Ihre Aktualisierungslast so weit
+ansteigt, dass der Master sie nicht mehr handhaben kann.
+
+Im festlegen zu können, wie viele Slaves sie haben können, bevor die
+zusätzlichen Vorteile aufgewogen werden, und um wieviel Sie die Performance
+Ihrer Site steigern können, müssen Sie Ihre Anfragenmuster kennen und
+empirisch (durch Benchmarks) festlegen, wie das Verhältnis zwischen dem
+Durchsatz von Lesevorgängen (pro Sekunde, oder @code{max_reads}) und
+Schreibvorgängen (@code{max_writes}) auf einem typischen Master und einem
+typischen Slave ist. Das unten stehende Beispiel zeigt Ihnen eine eher
+vereinfachte Berechnung, was Sie mit Replikation für ein imaginäres System
+erreichen können.
+
+Nehmen wir an, Ihr Systemlast besteht aus 10% Schreibvorgängen und 90%
+Lesevorgängen, und Sie haben festgestellt, dass @code{max_reads} = 1200 - 2
+* @code{max_writes} ist. Mit anderen Worten kann Ihr System 1.200
+Lesevorgänge pro Sekunde ohne Schreibzugriffe ausführen, und der
+durchschnittliche Schreibvorgang ist zweimal so langsam wie der
+durchschnittliche Lesevorgang, und das Verhältnis ist linear. Nehmen wir
+ferner an, dass Ihr Master und Slave dieselbe Kapazität haben, und dass es
+N Slaves und 1 Master gibt. Dann gilt für jeden Server (Master oder Slave):
+
+@code{lesen = 1200 - 2 * schreiben} (aus Benchmarks)
+
+@code{lesen = 9 * schreiben / (N + 1) } (lesen aufgeteilt, aber schreiben
+geht an alle Server)
+
+@code{9 * schreiben / (N+1) + 2 * schreiben = 1200}
+
+@code{schreiben = 1200/(2 + 9/(N+1)}
+
+Wenn also N = 0, was bedeutet, dass es keine Replikation gibt, kann Ihr
+System 1200 / 11, also etwa 109 Schreibvorgänge pro Sekunden handhaben (was
+heißt, dass Sie neunmal so viele Lesevorgänge haben, was der Natur Ihrer
+Applikation entspricht).
+
+Wenn N = 1 ist, können Sie bis zu 184 Schreibvorgänge pro Sekunde haben.
+
+Wenn N = 8 ist, können Sie bis zu 400 haben.
+
+Wenn N = 17 ist, können Sie 480 haben.
+
+Wenn schließlich N gegen unendlich geht (und Ihr Budget gegen negativ
+unendlich), können Sie sehr nahe an 600 Schreibvorgänge pro Sekunde kommen
+und damit den Systemdurchsatz um etwa den Faktor 5,5 erhöhen. Mit nur 8
+Servern jedoch kommen Sie bereits auf eine Steigerung um fast den Faktor 4.
+
+Beachten Sie, dass diese Berechnungen von unbegrenzter Netzwerk-Bandbreite
+ausgehen und verschiedene andere Faktoren vernachlässigen, die auf Ihrem
+System signifikant sein könnten. In vielen Fällen werden Sie nicht in der
+Lage sein, präzise vorauszusagen, was auf Ihrem System passieren wird, wenn
+Sie N Replikations-Slaves hinzufügen. Dennoch kann die Beantwortung
+folgender Fragen Ihnen helfen zu entscheiden, ob und wie viel (wenn
+überhaupt) Replikation bewirken kann, dass sich Ihre System-Performance
+verbessert:
+
+@itemize @bullet
+@item
+Was ist das Lese-/Schreibverhältnis auf Ihrem System?
+@item
+Wieviel zusätzliche Schreiblast kann ein Server handhaben, wenn Sie die
+Leselast verringern?
+@item
+Für wie viele Slave haben Sie Bandbreite auf Ihrem Netzwerk?
+@end itemize
+
+@strong{Frage}: Wie kann ich Replikation benutzen, um Redundanz / hohe
+Verfügbarkeit zur Verfügung zu stellen?
+
+@strong{Antwort}: Mit den momentan verfügbaren Features würden Sie einen
+Master und einen Slave (nicht mehrere Slaves) aufsetzen und ein Skript
+schreiben, das den Master beobachtet, um zu sehen, ob er hochgefahren ist,
+und Ihre Applikationen und die Slaves anweisen, den Master im Falle von
+Fehlschlägen zu ändern. Einige Vorschläge:
+set up a master und a slave (or several slaves) und write a Skript
+
+@itemize @bullet
+@item
+Um einem Slave mitzuteilen, den Master zu ändern, benutzen Sie den
+@code{CHANGE MASTER TO}-Befehl.
+@item
+Eine gute Möglichkeit, Ihre Applikationen darüber informiert zu halten, wo
+der Master ist, ist ein dynamischer DNS-Eintrag für den Master. Bei
+@strong{bind} können Sie @code{nsupdate} benutzen, um Ihr DNS dynamisch zu
+aktualisieren.
+@item
+Sie sollten Ihre Slaves mit der @code{log-bin}-Option und ohne
+@code{log-slave-updates} laufen lassen. Auf diese Art wird der Slave bereit
+sein, ein Master zu werden, sobald Sie @code{STOP SLAVE} eingeben,
+@code{RESET MASTER} und @code{CHANGE MASTER TO} auf den anderen Slaves. Das
+wird auch dabei helfen, fehlgelaufene Aktualisierungen zu entdecken, die
+auf Grund von Fehlkonfiguration des Slaves passieren (im Idealfall sollten
+Sie die Zugriffsrechte so konfigurieren, dass kein Client einen Slave
+aktualisieren kann, ausser der Slave-Thread), in Kombination mit den Bugs
+in Ihren Client-Programmen (die den Slave nie direkt aktualisieren
+sollten).
+
+@end itemize
+
+Momentan arbeiten wir an der Integration eines Systems in MySQL, das
+automatisch den Master auswählt, aber bis es fertig ist, müssen Sie Ihre
+eigenen Beobachtungswerkzeuge schaffen.
+
+
+@node Replication Problems, , Replication FAQ, Replication
+@c German node Replikationsprobleme
+@subsection Problemlösung bei Replikation
+
+Wenn Sie den Anweisungen gefolgt sind und Ihre Replikationseinrichtung
+nicht funktioniert, beseitigen Sie zunächst die Möglichkeit von
+Benutzerfehlern, indem Sie folgendes prüfen:
+
+@itemize @bullet
+@item
+Loggt der Master in die Binär-Log-Datei? Prüfen Sie das mit @code{SHOW
+MASTER STATUS}. Wenn das der Fall ist, ist die @code{Position} nicht 0.
+Wenn nicht, überprüfen Sie, ob Sie dem Master die @code{log-bin}-Option
+angegeben und die @code{server-id} gesetzt haben.
+@item
+Läuft der Slave? Überprüfen Sie das mit @code{SHOW SLAVE STATUS}. Die
+Antwort steht in der @code{Slave_running}-Spalte. Wenn nicht, überprüfen
+Sie die Slave-Optionen und überprüfen Sie die Fehler-Log-Datei auf
+Meldungen.
+@item
+Wenn der Slave läuft, hat er eine Verbindung mit dem Master hergestellt?
+Führen Sie @code{SHOW PROCESSLIST} aus, finden Sie den Thread mit dem
+@code{System user}-Wert in der @code{User}-Spalte und @code{none} in der
+@code{Host}-Spalte und überprüfen Sie die @code{State}-Spalte. Wenn dort
+steht @code{connecting to master}, überprüfen Sie die Berechtigungen für
+den Replikations-Benutzer auf dem Master, den Master-Hostnamen, Ihre
+DNS-Einrichtung, ob der Master tatsächlich läuft, ob er durch den Slave
+erreichbar ist, und wenn all das in Ordnung zu sein scheint, lesen Sie die
+Fehler-Log-Dateien.
+@item
+Wenn der Slave lief, aber dann anhielt, schauen Sie in die Ausgabe von SHOW
+SLAVE STATUS und überprüfen Sie die Fehler-Log-Dateien. Das passiert
+üblicherweise, wenn eine Anfrage, die auf dem Master funktionierte, auf dem
+Slave fehlschlägt. Das sollte nie vorkommen, wenn Sie einen korrekten
+Schnappschuss des Masters aufgenommen haben und die Daten nie auf dem Slave
+ausserhalb des Slave-Threads verändern. Wenn das doch auftritt, ist es ein
+Bug und sollte berichtet werden.
+@item
+Wenn eine Anfrage, die auf dem Master funktionierte, nicht auf dem Slave
+läuft, und eine komplette Datenbank-Synchronisation (das richtige, was man
+tun sollte) nicht ratsam erscheint, versuchen Sie folgendes:
+@itemize @minus
+@item
+Überprüfen Sie zunächst, ob irgend ein 'streunender' Datensatz im Weg ist.
+Finden Sie heraus, wie das geschehen konnte, dann löschen Sie ihn und
+lassen @code{SLAVE START} laufen.
+@item
+Wenn das Obige nicht funktioniert oder nicht zutrifft, versuchen Sie
+herauszufinden, ob es sicher ist, die Aktualisierung manuell durchzuführen
+(falls notwendig) und ignorieren Sie dann die nächste Anfrage vom Master.
+@item
+Wenn Sie sich entschieden haben, dass Sie die nächste Anfrage überspringen
+können, führen Sie @code{SET SQL_SLAVE_SKIP_COUNTER=1; SLAVE START;} aus,
+um eine Anfrage zu überspringen, die kein auto_increment oder
+last_insert_id benutzt, ansonsten @code{SET SQL_SLAVE_SKIP_COUNTER=2; SLAVE
+START;}. Der Grund, warum auto_increment- / last_insert_id-Anfragen anders
+sind, liegt darin, dass für Sie zwei Ereignisse in der Binär-Log-Datei des
+Masters verzeichnet sind.
+
+@item
+Wenn Sie sicher sind, dass der Slave perfekt mit dem Master synchronisiert
+gestartet ist, und dass niemand die fraglichen Tabellen ausserhalb des
+Slave-Threads aktualisiert hat, berichten Sie den Bug, damit wir die oben
+beschriebenen Tricks nicht noch einmal machen müssen.
+@end itemize
+@item
+Stellen Sie sicher, dass es sich nicht um alten Bug handelt, indem
+Sie auf die aktuellste Version aktualisieren.
+@item
+Wenn alles Weitere fehlschlägt, lesen Sie die Fehler-Log-Dateien. Wenn
+diese Groß sind, führen Sie ein @code{grep -i slave /pfad/zu/your-log.err}
+auf dem Slave durch. Es gibt kein allgemeines Muster, nach dem man auf dem
+Master suchen könnte, weil die einzigen Fehler, die dieser mitschreibt,
+allgemeine Systemfehler sind - falls möglich, wird er Fehler an die Slaves
+senden, wenn etwas schief ging.
+@end itemize
+
+Wenn Sie sicher sind, dass es keine Benutzerfehler gibt und die Replikation
+immer noch nicht funktioniert oder nicht stabil ist, ist es an der Zeit,
+einen Bug-Bericht auszuarbeiten. Um dem Bug auf die Spur zu kommen,
+brauchen wir soviel Informationen von Ihnen wie möglich. Bitte nehmen Sie
+sich etwas Zeit und schreiben Sie einen guten Bug-Bericht. Im Idealfall
+hätten wir gerne einen Test-Fall in dem Format, das Sie im
+@code{mysql-test/t/rpl*}-Verzeichnis des Source-Baums finden. Wenn Sie
+einen solchen Test-Fall schicken, können Sie in den meisten Fällen ein Patch
+innerhalb von ein oder zwei Tagen erwarten. Diese Zeitspanne hängt
+allerdings von einer Anzahl weiterer Faktoren ab.
+
+Die zweitbeste Option ist ein einfaches Programm mit leicht
+konfigurierbaren Verbindungsargumenten für Master und Slave, das das
+Problem auf Ihrem System veranschaulicht. Sie können dies in Perl oder C
+schreiben, abhängig davon, welche Sprache Sie besser beherrschen.
+
+Wenn Sie den Bug auf eine der beiden oben beschriebenen Weisen
+demonstrieren können, benutzen Sie @code{mysqlbug}, um einen Bug-Bericht
+vorzubereiten, und schicken Sie ihn an @email{bugs@@lists.mysql.com}. Wenn
+Sie ein 'Phantom' haben - ein Problem, das auftritt, aber nicht einfach
+reproduziert werden kann - tun Sie folgendes:
+
+@itemize @bullet
+@item
+Stellen Sie sicher, dass kein Benutzerfehler im Spiel ist. Beispielsweise
+könnte der Slave ausserhalb des Slave-Threads aktualisiert werden - dann
+sind die Daten nicht synchronisiert und Sie haben womöglich einen Fehler
+wegen doppelter Schlüsseleinträge bei Aktualisierungen, wobei der
+Slave-Thread dann anhält und darauf wartet, dass Sie die Tabellen manuell
+in Ordnung und in Synchronisation bringen.
+@item
+Lassen Sie den Slave mit @code{log-slave-updates} und @code{log-bin} laufen
+- das behält eine Log-Datei aller Aktualisierungen auf dem Slave bei.
+@item
+Sichern Sie alle Beweise, bevor Sie die Replikation zurück setzen. Wenn wir
+keine oder nur schemenhafte Informationen haben, brauchen wir eine Weile,
+um dem Problem auf den Grund zu gehen. Die Beweise, die Sie für uns sammeln
+sollten, sind:
+@itemize @minus
+@item
+Alle Binär-Log-Dateien auf dem Master.
+@item
+Alle Binär-Log-Dateien auf dem Slave.
+@item
+Die Ausgabe von @code{SHOW MASTER STATUS} auf dem Master zu der Zeit, als
+Sie das Problem entdeckten.
+@item
+Die Ausgabe von @code{SHOW SLAVE STATUS} auf dem Master zu der Zeit, als
+Sie das Problem entdeckten.
+@item
+Fehler-Log-Dateien auf Master und Slave.
+@end itemize
+@item
+Benutzen Sie @code{mysqlbinlog}, um die Binär-Log-Dateien zu untersuchen.
+Folgendes sollte hilfreich sein, um eine Anfrage zu finden, die Probleme
+verursacht, zum Beispiel:
+@example
+mysqlbinlog -j pos_from_slave_status /pfad/zu/log_from_slave_status | head
+@end example
+@end itemize
+
+Sobald Sie die Beweise des Phantomproblems gesammelt haben, versuchen Sie
+zuerst, es in einen separaten Test-Fall zu isolieren. Berichten Sie dann
+das Problem an @email{bugs@@lists.mysql.com}, wobei Sie soviel
+Informationen wie möglich mitschicken.
+
+
+
+
+@node MySQL Optimisation, Reference, MySQL Database Administration, Top
+@c German node MySQL-Optimierung
+@chapter MySQL-Optimierung
+
+
+
+Optimierung ist eine komplizierte Aufgabe, weil sie ein umfassendes
+Verständnis des gesamten Systems voraussetzt. Es ist möglich, einige lokale
+Optimierungen Ihres Systems oder Ihrer Applikation mit geringem Wissen
+durchzuführen. Je optimaler Sie allerdings Ihr System gestalten wollen,
+desto mehr müssen Sie darüber wissen.
+
+Dieses Kapitel erklärt und gibt Beispiele für verschiedene Möglichkeiten,
+MySQL zu optimieren. Denken Sie allerdings daran, dass es immer noch
+zusätzliche Möglichkeiten gibt, das System noch schneller zu machen.
+
+
+@menu
+* Optimise Overview::
+* Query Speed::
+* Locking Issues::
+* Optimising Database Structure::
+* Optimising the Server::
+* Disk issues::
+@end menu
+
+@node Optimise Overview, Query Speed, MySQL Optimisation, MySQL Optimisation
+@c German node Überblick über Optimierung
+@section Überblick über Optimierung
+
+Der wichtigste Teil, um ein System schnell zu machen, ist natürlich das
+grundlegende Design. Ausserdem müssen Sie wissen, welche Dinge Ihr System
+macht und was die Flaschenhälse sind.
+
+Die wichtigsten Flaschenhälse sind:
+@itemize @bullet
+@item Suchvorgänge auf Festplatte.
+Die Festplatte benötigt Zeit, um ein Stück Daten zu finden. Bei modernen
+Festplatten (Stand: 1999) ist die mittlere Zugriffszeit üblicherweise
+weniger als 10 ms, daher können theoretisch etwa 1.000 Suchvorgänge pro
+Sekunde durchgeführt werden. Bei neueren Festplatten wird diese Zeit
+allmählich besser. Für einzelne Tabellen ist sie sehr schwer zu optimieren.
+Eine Möglichkeit, das zu optimieren, besteht darin, Daten auf mehr als eine
+Platte zu verteilen.
+
+@item Lesen von / Schreiben auf Festplatte.
+Wenn die Festplatte in der richtigen Position ist, um die Daten zu lesen,
+die wir brauchen, kann sie bei modernen Platten (Stand: 1999) etwas 10 bis
+20 MB pro Sekunde heraus geben. Das ist leichter zu optimieren als
+Suchvorgänge, weil man von mehrfachen Festplatten parallel lesen kann.
+
+@item CPU-Zyklen.
+Wenn die Daten im Hauptspeicher sind (oder bereits dort waren), müssen sie
+verarbeitet werden, um das Ergebnis zu erhalten. Kleine Tabellen im
+Vergleich zum Arbeitsspeicher ist der Faktor, der am meisten begrenzt. Auf
+der anderen Seite ist Geschwindigkeit bei kleinen Tabellen üblicherweise
+nicht das Problem.
+
+@item Speicher-Bandbreite.
+Wenn der Prozessor mehr Daten braucht, als in den CPU-Cache passen, wird
+die Bandbreite des Hauptspeichers zum Flaschenhals. Auf den meisten
+Systemen ist das ein ungewöhnlicher Flaschenhals, aber man sollte sich
+dessen bewusst sein.
+@end itemize
+
+
+
+
+@menu
+* Design Limitations::
+* Portability::
+* Internal use::
+* MySQL Benchmarks::
+* Custom Benchmarks::
+@end menu
+
+@node Design Limitations, Portability, Optimise Overview, Optimise Overview
+@c German node Design-Einschränkungen
+@subsection MySQL-Design-Einschränkungen
+
+@cindex Design, Einschränkungen
+@cindex Einschränkungen, Design
+
+Weil MySQL extrem schnelles Tabellensperren beherrscht (mehrfache Leser /
+einzelne Schreiber), ist das größte verbleibende Problem eine Mischung aus
+einem laufenden Strom von Einfügevorgängen und langsamen Selects auf
+dieselbe Tabelle.
+
+Wir glauben, dass diese Wahl auf einer sehr großen Anzahl von Systemen
+letztlich einen Gewinn darstellt. Auch dieser Fall ist üblicherweise
+dadurch zu lösen, dass man mehrfache Kopien der Tabelle vorhält, aber man
+benötigt mehr Anstrengung und Hardware.
+
+Wir arbeiten auch an einigen Erweiterungen, um dieses Problem in Hinsicht
+auf einige häufige Applikationsnischen zu lösen.
+
+
+@node Portability, Internal use, Design Limitations, Optimise Overview
+@c German node Portabilität
+@subsection Portabilität
+
+@cindex Portabilität
+@cindex Crash-me-Programm
+@cindex Programme, Crash-me
+
+Weil alle SQL-Server unterschiedliche Teile von SQL implementieren, ist es
+immer Arbeit, portable SQL-Applikationen zu schreiben. Bei sehr einfachen
+Selects und Inserts ist das sehr einfach, aber je mehr Sie brauchen, desto
+schwieriger wird es. Wenn Sie eine Applikation wollen, die bei vielen
+Datenbanken noch schnell läuft, wird es sogar noch schwieriger!
+
+Um eine komplexe Applikation portabel zu machen, müssen Sie sich für eine
+Reihe von SQL-Servern entscheiden, mit denen sie funktionieren soll.
+
+Sie können das MySQL-Crash-me-Programm bzw. die Webpage
+@uref{http://www.mysql.com/information/crash-me.php} benutzen, um
+Funktionen, Typen und Einschränkungen zu finden, die Sie mit einer Auswahl
+von Datenbank-Servern benutzen können. Crash-me testet bei weitem nicht
+alles, was möglich ist, aber mit etwa 450 unterschiedlichen Dingen ist es
+recht umfassend.
+
+Sie sollten zum Beispiel keine Spaltennamen benutzen, die länger als 10
+Zeichen sind, wenn Sie auch Informix oder DB2 benutzen wollen.
+
+Sowohl die MySQL-Benchmarks als auch die Crash-me-Programme sind sehr
+Datenbank-abhängig. Indem Sie einen Blick darauf werfen, wie wir damit
+umgegangen sind, bekommen Sie ein Gefühl dafür, was Sie in Ihrer
+Applikation schreiben müssen, damit diese Datenbank-unabhängig läuft. Die
+Benchmark-Tests selbst befinden sich im @file{sql-bench}-Verzeichnis der
+MySQL-Quelldistribution. Sie sind in Perl mit der
+DBI-Datenbank-Schnittstelle geschrieben (die den Zugriffsteil des Problems
+löst).
+
+Siehe @uref{http://www.mysql.com/information/benchmarks.html} wegen der
+Ergebnisse aus diesem Benchmark-Test.
+
+Wie Sie an den Ergebnissen sehen, haben alle Datenbanken einige
+Schwachpunkte, das heißt, sie haben verschiedene Design-Kompromisse, die
+zu unterschiedlichem Verhalten führen.
+
+Wenn Sie nach Datenbank-Unabhängigkeit streben, müssen Sie ein gutes Gefühl
+für die Flaschenhälse jedes SQL-Servers bekommen. MySQL ist SEHR schnell
+beim Abrufen und Aktualisieren von Dingen, hat aber Probleme, wenn
+gleichzeitig langsame Leser / Schreiber auf dieselbe Tabelle zugreifen.
+Oracle hat ein großes Problem, wenn Sie versuchen, auf Zeilen zuzugreifen,
+der kürzlich aktualisiert wurden (solange, bis sie auf Platte
+zurückgeschrieben wurden). Transaktionale Datenbanken sind allgemein nicht
+sehr gut darin, Zusammenfassungstabellen aus Log-Tabellen zu erzeugen, weil
+in diesem Fall Sperren auf Zeilenebene fast nutzlos ist.
+
+Um Ihre Applikation @emph{wirklich} Datenbank-unabhängig zu machen, müssen
+Sie eine leicht erweiterbare Schnittstelle definieren, über die Sie Ihre
+Daten manipulieren. Weil auf den meisten Systemen C++ verfügbar ist, ist es
+sinnvoll, C++-Klassen als Schnittstellen zu den Datenbanken zu benutzen.
+
+Wenn Sie irgend ein spezifisches Feature einer Datenbankbenutzung (wie den
+@code{REPLACE}-Befehl in MySQL), sollten Sie eine Methode für die anderen
+SQL-Server codieren, um dasselbe Feature (wenngleich langsamer) zu
+implementieren. Bei MySQL können Sie die @code{/*! */}-Syntax benutzen, um
+MySQL-spezifische Schlüsselwörter in einer Anfrage zu verwenden. Der Code
+innerhalb von @code{/**/} wird von den meisten anderen SQL-Servern als
+Kommentar behandelt (ignoriert).
+
+Wenn WIRKLICH hohe Performance wichtiger als Exaktheit ist, wie bei einigen
+Web-Applikationen, besteht eine Möglichkeit darin, eine Applikationsebene
+zu erzeugen, die alle Ergebnisse cachet, um Ihnen noch höhere Performance
+zu bringen. Indem Sie alte Ergebnisse nach einer Weile 'auslaufen' lassen,
+können Sie den Cache in vernünftiger Weise 'frisch' halten. Das ist in
+Fällen extrem hoher Last recht nett, wobei Sie den Cache dynamisch
+vergrößern und die Verfallszeit (Expire Timeout) höher setzen können, bis
+wieder Normalauslastung eintritt.
+
+In diesem Fall sollte die Tabellenerzeugungsinformation Informationen über
+die ursprüngliche Cache-Größe enthalten und darüber, wie oft die Tabelle
+normalerweise aktualisiert (refresh) werden sollte.
+
+
+@node Internal use, MySQL Benchmarks, Portability, Optimise Overview
+@c German node Interner Gebrauch
+@subsection Wofür benutzen wir MySQL?
+
+@cindex Gebrauch, von MySQL
+@cindex Kunden, von MySQL
+
+In der anfänglichen Phase der Entwicklung von MySQL wurden die Features von
+MySQL für unseren größten Kunden gemacht. Dieser macht Data-Warehousing
+für eine Reihe der größten Einzelhändler in Schweden.
+
+Aus allen Verkaufsstellen erhalten wir wöchentliche Zusammenfassungen aller
+Bonuskarten-Transaktionen, und es wird erwartet, dass daraus nützliche
+Informationen für die Eigentümer der Verkaufsstellen zur Verfügung gestellt
+werden, damit diese herausfinden können, wie ihre Werbemaßnahmen ihre
+Kunden beeinflussen.
+
+Die Datenmenge ist recht riesig (etwa 7 Millionen
+Zusammenfassungs-Transaktionen pro Monat), und wir haben Daten von 4 bis 10
+Jahren, die wir dem Benutzer präsentieren müssen. Wir bekamen wöchentliche
+Anfragen von Kunden, die 'sofortigen' Zugriff auf neue Berichte aus diesen
+Daten wollten.
+
+Die Lösung bestand darin, alle Informationen monatsweise in komprimierten
+'Transaktions-' Tabellen zu speichern. Wir haben einen Satz einfacher
+Makros (ein Skript), die aus diesen Tabellen Zusammenfassungstabellen
+erzeugen, die nach verschiedenen Kriterien gruppiert sind (Produktgruppe,
+Kunden-ID, Verkaufsstelle usw.). Die Berichte sind Web-Seiten, die
+dynamisch durch ein kleines Perl-Skript erzeugt werden, das eine Web-Seite
+parst, die enthaltenen SQL-Statements ausführt und die Ergebnisse einfügt.
+Wir hätten statt dessen PHP oder mod_perl benutzt, aber diese waren damals
+noch nicht verfügbar.
+
+Für grafische Darstellungen schrieben wir ein einfaches Werkzeug in
+@code{C}, das GIFs auf der Grundlage der Ergebnisse einer SQL-Anfrage
+erzeugen kann (nach einigem Verarbeiten des Ergebnisses). Dieses wird
+ebenfalls dynamisch durch ein Perl-Skript ausgeführt, das die
+@code{HTML}-Dateien parst.
+
+In den meisten Fällen kann ein neuer Bericht einfach durch das Kopieren
+eines bestehenden Skripts und das Verändern der SQL-Anfrage darin erzeugt
+werden. In einigen Fällen müssen wir einer bestehenden
+Zusammenfassungstabelle weitere Felder hinzufügen oder eine neue
+generieren, aber auch das ist recht einfach, weil wir alle
+Transaktionstabellen auf Platte haben. (Momentan haben wir mindestens 50 GB
+an Transaktionstabellen und 200 GB weiterer Kundendaten.)
+
+Wir lassen unsere Kunden auch direkt mit ODBC auf die Transaktionstabellen
+zugreifen, so dass fortgeschrittene Benutzer selbst mit den Daten
+experimentieren können.
+
+Wir hatten mit der Handhabung keinerlei Probleme, auf einer recht
+bescheidenen Sun Ultra SPARCstation (2x200 MHz). Kürzlich haben wir einen
+unserer Server auf eine mit 2 Prozessoren bestückte 400 MHz-UltraSPARC
+erweitert und planen jetzt, Transaktionen auf Produktebene zu handhaben,
+was eine zehnfache Steigerung der Datenmenge bedeuten würde. Wir glauben,
+dass wir auch damit Schritt halten können, indem wir unseren Systemen
+einfach mehr Festplattenplatz hinzufügen.
+
+Wir experimentieren auch mit Intel-Linux, um in der Lage zu sein, mehr
+CPU-Power preisgünstiger zu erhalten. Jetzt, wo wir das binäre portable
+Datenbankformat haben (neu seit Version 3.23), werden wir dieses für einige
+Teile der Applikation benutzen.
+
+Unser anfängliches Gefühl sagt uns, dass Linux viel besser bei geringer bis
+mittlerer Last ist, während Solaris wegen der extremen
+Festplatten-Eingabe-/Ausgabe-Geschwindigkeit (Disk-IO) bei Hochlast besser
+ist, aber wir können noch nichts Endgültiges darüber aussagen. Nach einigen
+Diskussionen mit den Linux-Kernel-Entwicklern ist das eventuell ein
+Seiteneffekt von Linux, das dem Stapel-Job so viel Ressourcen gibt, dass
+die interaktive Performance sehr gering wird. Dadurch scheint die Maschine
+sehr langsam und unempfänglich für Eingaben zu lassen, während große
+Stapel-Jobs abgearbeitet werden. Wir hoffen, dass dies in zukünftigen
+Linux-Kernels besser gehandhabt wird.
+
+
+@node MySQL Benchmarks, Custom Benchmarks, Internal use, Optimise Overview
+@c German node MySQL-Benchmarks
+@subsection Die MySQL-Benchmark-Suite
+
+@cindex Benchmark-Suite
+@cindex Crash-me-Programm
+
+Dieser Abschnitt sollte eine technische Beschreibung der MySQL-
+Benchmark-Suite (und von @code{crash-me}) enthalten, aber diese
+Beschreibung wurde noch nicht geschrieben. Momentan können Sie eine gute
+Idee über den Benchmark bekommen, wenn Sie einen Blick auf den Code und die
+Ergebnisse im @file{sql-bench}-Verzeichnis jeder MySQL-Quelldistribution
+werfen.
+
+Diese Benchmark-Suite ist als Benchmark gedacht, der jedem Benutzer
+mitteilt, welche Dinge in einer gegebenen SQL-Implementation gut performen
+und welche schlecht.
+
+Beachten Sie, dass dieser Benchmark single-threaded ist. Daher misst er die
+minimale Zeit der Operationen. In Zukunft planen wir, auch etliche
+multi-threaded Test hinzuzufügen.
+
+Beispiele (die auf derselben NT-4.0-Maschine liefen):
+
+@multitable @columnfractions .6 .2 .2
+@strong{2.000.000 Zeilen vom Index lesen} @tab @strong{Sekunden} @tab @strong{Sekunden}
+@item mysql @tab 367 @tab 249
+@item mysql_odbc @tab 464
+@item db2_odbc @tab 1206
+@item informix_odbc @tab 121126
+@item ms-sql_odbc @tab 1634
+@item oracle_odbc @tab 20800
+@item solid_odbc @tab 877
+@item sybase_odbc @tab 17614
+@end multitable
+
+@multitable @columnfractions .6 .2 .2
+@strong{350.768 Zeilen einfügen} @tab @strong{Sekunden} @tab @strong{Sekunden}
+@item mysql @tab 381 @tab 206
+@item mysql_odbc @tab 619
+@item db2_odbc @tab 3460
+@item informix_odbc @tab 2692
+@item ms-sql_odbc @tab 4012
+@item oracle_odbc @tab 11291
+@item solid_odbc @tab 1801
+@item sybase_odbc @tab 4802
+@end multitable
+
+Im obigen Test lief MySQL mit einem 8 MB Index-Cache.
+
+Weitere Benchmark-Ergebnisse haben wir unter
+@uref{http://www.mysql.com/information/benchmarks.html} gesammelt.
+
+Beachten Sie, dass Oracle nicht beinhaltet ist, weil sie gebeten haben,
+entfernt zu werden. Alle Oracle-Benchmarks müssen von Oracle freigegeben
+werden! Wir glauben, dass das die Aussagefähigkeit von Oracle-Benchmarks
+@strong{SEHR} zweifelhaft erscheinen läßt, weil alle obigen Benchmarks
+dafür da sind zu zeigen, was eine Standard-Installation bei einem einzelnen
+Client machen kann.
+
+Um eine Benchmark-Suite laufen zu lassen, müssen Sie eine
+MySQL-Quelldistribution herunter laden, den Perl-DBI-Treiber und den
+Perl-DBD-Treiber für die gewünschte Datenbank installieren und dann
+folgendes tun:
+
+@example
+cd sql-bench
+perl run-all-tests --server=#
+@end example
+
+Wobei # einer der unterstützten Server ist. Sie erhalten eine Auflistung
+aller Optionen und unterstützten Server, indem Sie @code{run-all-tests
+--help} ausführen.
+
+@cindex Crash-me
+@code{Crash-me} versucht herauszufinden, welche Features eine Datenbank
+unterstützt und wo ihre Fähigkeiten und Einschränkungen sind, indem
+tatsächliche Anfragen ausgeführt werden. Beispielsweise stellt es fest:
+
+@itemize @bullet
+@item
+Welche Spaltentypen unterstützt werden.
+@item
+Wie viele Indexe unterstützt werden.
+@item
+Welche Funktionen unterstützt werden.
+@item
+Wie Groß eine Anfrage sein kann.
+@item
+Wie Groß eine @code{VARCHAR}-Spalte sein kann.
+@end itemize
+
+Sie finden die Ergebnisse von Crash-me für viele verschiedene Datenbanken
+unter @uref{http://www.mysql.com/information/crash-me.php}.
+
+
+@node Custom Benchmarks, , MySQL Benchmarks, Optimise Overview
+@c German node Benutzerspezifische Benchmarks
+@subsection Wie Sie Ihre eigenen Benchmarks benutzen
+
+@cindex Benchmarks
+@cindex Performance, Benchmarks
+
+Sie sollten Ihre Applikation und Datenbank auf jeden Fall einem
+Benchmark-Test unterziehen um herauszufinden, wo Flaschenhälse sind. Indem
+Sie einen Flaschenhals beseitigen (oder ihn durch ein 'Dummy-Modul'
+ersetzen), können Sie leicht den nächsten Flaschenhals herausfinden (usw.).
+Selbst wenn die insgesamte Performance für Ihre Applikation ausreichend
+ist, sollten Sie zumindest einen Plan für jeden Flaschenhals aufstellen und
+entscheiden, auf welche Weise dieser beseitigt werden soll, wenn Sie eines
+Tages die zusätzliche Performance benötigen.
+
+Als Beispiel für ein portables Benchmark-Programm schauen Sie sich die
+MySQL-Benchmark-Suite an. @xref{MySQL Benchmarks, , MySQL-Benchmarks}. Sie
+können jedes Programm dieser Suite nehmen und es Ihren Bedürfnissen
+entsprechend abändern. Wenn Sie das tun, können Sie unterschiedliche
+Lösungen für Ihr Problem finden und testen, was bei Ihnen wirklich die
+schnellste Lösung ist.
+
+Es ist häufig der Fall, dass Probleme nur dann auftreten, wenn das System
+unter schwerer Last läuft. Viele Kunden nahmen mit uns Kontakt auf, nachdem
+sie ein (getestetes) System in eine Produktionsumgebung stellten und
+Lastprobleme bekamen. Bei jedem dieser Fälle gab es bislang entweder
+Probleme mit dem Grund-Design (Tabellen-Scans laufen NICHT gut unter hoher
+Last) oder im Zusammenhang mit dem Betriebssystem / den Bibliotheken. Das
+meiste davon wäre @strong{SEHR} viel einfacher zu beheben, wenn die Systeme
+nicht bereits in einer Produktionsumgebung liefen.
+
+Um solcherlei Probleme zu vermeiden, sollten Sie einige Anstrengung darauf
+verwenden, Ihre gesamte Applikation unter der schlimmstmöglichen Last zu
+benchmarken! Hierfür können Sie Super Smack benutzen, das Sie hier
+erhalten:
+@uref{http://www.mysql.com/downloads/super-smack/super-smack-1.0.tar.gz}.
+Wie der Name nahelegt, kann es Ihr System auf die Knie zwingen, wenn Sie
+das wollen. Achten Sie daher darauf, es nur auf Entwicklungssystemen zu
+verwenden.
+
+
+@node Query Speed, Locking Issues, Optimise Overview, MySQL Optimisation
+@c German node Anfragen-Geschwindigkeit
+@section @code{SELECT}s und andere Anfragen optimieren
+
+@cindex Anfragen, Geschwindigkeit von
+@cindex Berechtigungsprüfungen, Auswirkung auf Geschwindigkeit
+@cindex Geschwindigkeit, von Anfragen
+
+Zunächst etwas, das alle Anfragen betrifft: Je komplexer das
+Berechtigungssystem, das Sie einrichten, desto mehr Overhead bekommen Sie.
+
+Falls Sie noch keinerlei @code{GRANT}-Statements ausgeführt haben,
+optimiert MySQL die Berechtigungsprüfung zum Teil. Wenn Sie also sehr hohe
+Zugriffszahlen haben, kann es einen Zeitvorteil darstellen, Grants zu
+vermeiden. Ansonsten können mehr Berechtigungsprüfungen in einem größeren
+Overhead resultieren.
+
+Wenn Sie Probleme bei einer bestimmten MySQL-Funktion haben, können Sie den
+Zeitbedarf jederzeit wie folgt mit dem MySQL-Client feststellen:
+
+@example
+mysql> select benchmark(1000000,1+1);
++------------------------+
+| benchmark(1000000,1+1) |
++------------------------+
+| 0 |
++------------------------+
+1 row in set (0.32 sec)
+@end example
+
+Das Ergebnis zeigt, dass MySQL 1.000.000 @code{+}-Operationen in 0,32
+Sekunden auf einer @code{PentiumII-400MHz}-Maschine ausführen kann.
+
+Alle MySQL-Funktionen sollten sehr optimiert sein, aber es mag einige
+Ausnahmen geben und @code{benchmark(schleifenzaehler,ausdruck)} ist ein
+großartiges Werkzeug, um herauszufinden, ob das das Problem bei Ihrer
+Anfrage darstellt.
+
+
+
+@menu
+* EXPLAIN::
+* Estimating performance::
+* SELECT speed::
+* Where optimisations::
+* DISTINCT optimisation::
+* LEFT JOIN optimisation::
+* LIMIT optimisation::
+* Insert speed::
+* Update speed::
+* Delete speed::
+* Tips::
+@end menu
+
+@node EXPLAIN, Estimating performance, Query Speed, Query Speed
+@c German node EXPLAIN
+@subsection @code{EXPLAIN}-Syntax (Informationen über ein @code{SELECT} erhalten)
+
+@findex EXPLAIN
+@findex SELECT, Optimierung
+
+@example
+ EXPLAIN tabelle
+oder EXPLAIN SELECT select_optionen
+@end example
+
+@code{EXPLAIN tabelle} ist ein Synonym für @code{DESCRIBE tabelle} oder
+@code{SHOW COLUMNS FROM tabelle}.
+
+Wenn Sie einem @code{SELECT}-Statement das Schlüsselwort @code{EXPLAIN}
+voran stellen, erklärt MySQL explains, wie er das @code{SELECT} ausführen
+würde, indem Informationen darüber gemacht werden, wie Tabellen verknüpft
+(Join) werden und in welcher Reihenfolge.
+
+Mit der Hilfe von @code{EXPLAIN} können Sie erkennen, wo Sie Tabellen
+Indexe hinzufügen müssen, um ein schnelleres @code{SELECT} zu erhalten, das
+Indexe benutzt, um die Datensätze zu finden. Ausserdem sehen Sie, ob der
+Optimierer die Tabellen in optimaler Reihenfolge verknüpft. Um den
+Optimierer zu zwingen, eine spezielle Verknüpfungsreihenfolge bei einem
+@code{SELECT}-Statement einzuhalten, fügen Sie eine
+@code{STRAIGHT_JOIN}-Klausel hinzu.
+
+Bei nicht einfachen Verknüpfungen (Joins) gibt @code{EXPLAIN} für jede
+Tabelle, die im @code{SELECT}-Statement benutzt wurde, eine
+Informationszeile zurück. Die Tabellen sind in der Reihenfolge aufgelistet,
+in der sie gelesen werden würden. MySQL löst alle Joins mit einer
+Single-Sweep-Multi-Join-Methode auf. Das bedeutet, dass MySQL eine Zeile
+aus der ersten Tabelle liest, dann die passende Zeile in der zweiten
+Tabelle sucht, dann in der dritten Tabelle usw. Wenn alle Tabellen
+verarbeitet wurden, gibt er die ausgewählten Spalten aus und geht
+rückwärts durch die Tabellenliste durch, bis eine Tabelle gefunden wird,
+bei der es weitere passende Zeilen gibt. Die nächste Zeile wird aus dieser
+Tabelle gelesen, und der Prozess fährt mit der nächsten Tabelle fort.
+
+Die Ausgabe von @code{EXPLAIN} enthält folgende Spalten:
+
+@table @code
+@item table
+Die Tabelle, auf die sich die Ausgabezeile bezieht.
+
+@item type
+Der Join-Typ. Informationen über die verschiedenen Typen finden Sie weiter
+unten.
+
+@item possible_keys
+Die @code{possible_keys}-Spalte gibt an, welche Indexe MySQL verwenden
+konnte, um Zeilen in dieser Tabelle zu finden. Beachten Sie, dass diese
+Spalte völlig unabhängig von der Reihenfolge der Tabellen ist. Das heißt,
+dass einige der Schlüssel in possible_keys möglicherweise bei der
+tatsächlich verwendeten Tabellenreihenfolge nicht verwendbar sind.
+
+Wenn diese Spalte leer ist, gibt es keine relevanten Indexe. In diesem Fall
+können Sie die Performance Ihrer Anfrage womöglich verbessern, indem Sie
+die @code{WHERE}-Klausel untersuchen, um festzustellen, ob diese auf eine
+oder mehrere Spalten verweist, die zweckmäßigerweise indiziert werden
+sollten. Wenn das der Fall ist, erzeugen Sie einen entsprechenden Index und
+prüfen Sie die Anfrage noch einmal mit @code{EXPLAIN}. @xref{ALTER TABLE}.
+
+Um zu sehen, welche Indexe eine Tabelle hat, benutzen Sie @code{SHOW INDEX
+FROM tabelle}.
+
+@item key
+@c German FIX changed @xref to @ref
+Die @code{key}-Spalte gibt den Schlüssel an, den MySQL tatsächlich benutzen
+wird. Der Schlüssel ist @code{NULL}, wenn kein Index gewählt wurde. Wenn
+MySQL den falschen Index wählt, können Sie ihn wahrscheinlich zwingen,
+einen anderen Index zu nehmen, indem Sie @code{myisamchk --analyze} oder
+@ref{myisamchk syntax} ausführen oder @code{USE INDEX/IGNORE INDEX}
+benutzen. @xref{JOIN}.
+
+@item key_len
+Die @code{key_len}-Spalte gibt die Länge des Schlüssels an, den MySQL
+benutzen wird. Die Länge ist @code{NULL}, wenn @code{key} @code{NULL} ist.
+Beachten Sie, dass Ihnen das angibt, wie viele Teile eines mehrteiligen
+Schlüssels MySQL tatsächlich benutzen wird.
+
+@item ref
+Die @code{ref}-Spalte zeigt an, welche Spalten oder Konstanten beim
+@code{key} benutzt werden, um Zeilen aus der Tabelle auszuwählen.
+
+@item rows
+die @code{rows}-Spalte gibt die Anzahl von Zeilen an, von denen MySQL
+annimmt, dass es sie untersuchen muss, um die Anfrage auszuführen.
+
+@item Extra
+Diese Spalte enthält zusätzliche Informationen darüber, wie MySQL die
+Anfrage auflösen wird. Folgende unterschiedliche Text-Zeichenketten können
+in dieser Spalte stehen:
+
+@table @code
+@item Distinct
+MySQL wird die Suche nach weiteren Zeilen für die aktuelle
+Zeilenkombination nicht fortsetzen, nachdem er die erste passende Zeile
+gefunden hat.
+
+@item Not exists
+MySQL war in der Lage, eine @code{LEFT JOIN}-Optimierung der Anfrage
+durchzuführen, und wird keine weiteren Spalten in dieser Tabelle für die
+vorherige Zeilenkombination mehr untersuchen, nachdem er eine Zeile
+gefunden hat, die den @code{LEFT JOIN}-Kriterien entspricht.
+
+Hier ist ein Beispiel dafür:
+
+@example
+SELECT * FROM t1 LEFT JOIN t2 ON t1.id=t2.id WHERE t2.id IS NULL;
+@end example
+
+Angenommen, @code{t2.id} ist mit @code{NOT NULL} definiert. In diesem Fall
+scannt MySQL @code{t1} und schlägt die Zeilen in @code{t2} über
+@code{t1.id} nach. Wenn MySQL eine übereinstimmende Zeile in @code{t2}
+findet, weiß er, dass @code{t2.id} nie @code{NULL} sein kann und scannt
+nicht durch den Rest der Zeilen in @code{t2}, die dieselbe @code{id} haben.
+Mit anderen Worten, für jede Zeile in @code{t1} muss MySQL nur ein einziges
+Mal in @code{t2} nachschlagen, unabhängig davon, wie viel übereinstimmende
+Zeilen es in @code{t2} gibt.
+
+@item @code{range checked for each record (index map: #)}
+MySQL hat keinen gut geeigneten Index zum Benutzen gefunden. Statt dessen
+wird er für jede Zeilenkombination in der vorherigen Tabelle eine Prüfung
+vornehmen, welchen Index er benutzen soll (falls überhaupt) und diesen
+Index benutzen, um Zeilen aus der Tabelle abzurufen. Das ist nicht sehr
+schnell, aber immer noch schneller, als einen Join ohne Index
+durchzuführen.
+
+@item Using filesort
+MySQL braucht einen zusätzlichen Durchgang, um herauszufinden, wie die
+Zeilen in sortierter Reihenfolge abgerufen werden sollen. Die Sortierung
+wird durchgeführt, indem in Abhängigkeit vom @code{join type} durch alle
+Zeilen durchgegangen wird und der Sortierschlüssel und Zeiger auf die
+Zeilen für alle Zeilen gespeichert wird, die dem @code{WHERE} entsprechen.
+Danach werden die Schlüssel sortiert. Schließlich werden die Zeilen in
+sortierter Reihenfolge abgerufen.
+
+@item Using index
+Die Spalteninformation wird aus der Tabelle abgerufen, indem nur
+Informationen aus dem Index-Baum benutzt werden, ohne dass zum Suchen
+zusätzlich in den tatsächlichen Zeilen gelesen werden muss. Das kann
+gemacht werden, wenn alle benutzten Spalten der Tabelle Teil desselben
+Indexes sind.
+
+@item Using temporary
+Um die Anfrage aufzulösen muss MySQL eine temporäre Tabelle erzeugen, die
+das Ergebnis enthält. Das passiert typischerweise, wenn Sie ein @code{ORDER
+BY} auf eine andere Spalte setzen als auf die, die Sie im @code{GROUP BY}
+angegeben haben.
+
+@item Where used
+Eine @code{WHERE}-Klausel wird benutzt, um zu begrenzen, bei welchen Zeilen
+auf Übereinstimmung in der nächsten Tabelle gesucht wird oder welche Zeilen
+an den Client geschickt werden. Wenn Sie diese Information nicht haben und
+die Tabelle vom Typ @code{ALL} oder @code{index} ast, ist vielleicht in
+Ihrer Anfrage etwas falsch (falls Sie nicht vorhaben, alle Zeilen aus der
+Tabelle zu holen / zu untersuchen).
+@end table
+
+Wenn Sie wollen, dass Ihre Anfragen so schnell wie möglich laufen, sollten
+Sie auf @code{Using filesort} und @code{Using temporary} achten.
+@end table
+
+Die verschiedenen Join-Typen sind unten aufgeführt, sortiert vom besten zum
+schlechtesten Typ:
+
+@cindex Systemtabelle
+@cindex Tabellen, System-
+@table @code
+@item system
+Die Tabelle hat nur eine Zeile (= Systemtabelle). Das ist ein spezieller
+Fall des @code{const}-Join-Typs.
+
+@cindex Konstanten-Tabelle
+@cindex Tabellen, Konstanten-
+@item const
+Die Tabelle hat höchsten eine übereinstimmende Zeile, die am Anfang der
+Anfrage gelesen werden wird. Weil es nur eine Zeile gibt, können
+Spaltenwerte in dieser Zeile vom Optimierer als Konstanten betrachtet
+werden. @code{const}-Tabellen sind sehr schnell, weil sie nur einmal
+gelesen werden!
+
+@item eq_ref
+Aus dieser Tabelle wird für jede Zeilenkombination der vorherigen Tabellen
+eine Zeile gelesen. Das ist der bestmögliche Join-Typ, ausgenommen die
+@code{const}-Typen. Er wird benutzt, wenn alle Teile eines Indexes vom Join
+benutzt werden und der Index @code{UNIQUE} oder ein @code{PRIMARY KEY} ist.
+
+@item ref
+Alle Zeilen mit übereinstimmenden Index-Werten werden für jede
+Zeilenkombination der vorherigen Tabellen gelesen. @code{ref} wird benutzt,
+wenn der Join nur das am weitesten links stehende Präfix des Schlüssels
+benutzt, oder wenn der Schlüssel nicht @code{UNIQUE} oder ein @code{PRIMARY
+KEY} ist (mit anderen Worten, wenn der Join auf der Grundlage des
+Schlüsselwerts keine einzelne Zeile auswählen kann). Wenn der Schlüssel,
+der benutzt wird, nur mit einigen wenigen Zeilen übereinstimmt, ist dieser
+Join-Typ gut.
+
+@item range
+Nur Zeilen, die innerhalb eines angegebenen Bereichs sind, werden abrufen,
+wobei ein Index benutzt wird, um die Zeilen auszuwählen. Die
+@code{key}-Spalte gibt an, welcher Index benutzt wird. @code{key_len}
+enthält den längsten Schlüsselteil, der benutzt wurde. Die
+@code{ref}-Spalte ist für diesen Typ NULL.
+
+@item index
+Das ist dasselbe wie @code{ALL}, ausser dass nur der Index-Baum gescannt
+wird. Das ist üblicherweise schneller als @code{ALL}, weil die Index-Datei
+üblicherweise kleiner ist als die Daten-Datei.
+
+@item ALL
+Für jede Zeilenkombination der vorherigen Tabellen wird ein kompletter
+Tabellenscan durchgeführt. Das ist normalerweise nicht gut, wenn die
+Tabelle die erste Tabelle ist, die nicht als @code{const} gekennzeichnet
+ist, und üblicherweise @strong{sehr} schlecht in allen anderen Fällen. Sie
+können @code{ALL} normalerweise vermeiden, indem Sie mehr Indexe
+hinzufügen, so dass die Zeile auf der Grundlage der Konstanten-Werte oder
+Spaltenwerte von früheren Tabellen abgerufen werden kann.
+@end table
+
+Sie erhalten einen guten Anhaltspunkt, wie gut ein Join ist, wenn Sie alle
+Werte in der @code{rows}-Spalte der @code{EXPLAIN}-Ausgabe multiplizieren.
+Das sollte grob aussagen, wie vielen Zeilen MySQL untersuchen muss, um die
+Anfrage auszuführen. Diese Anzahl wird auch benutzt, wenn Sie Anfragen mit
+der @code{max_join_size}-Variablen begrenzen.
+@xref{Server parameters}.
+
+Das folgende Beispiel zeigt, wie ein @code{JOIN} progressiv optimiert
+werden kann, indem die Informationen genutzt werden, die @code{EXPLAIN}
+bereit stellt.
+
+Angenommen, Sie haben unten stehendes @code{SELECT}-Statement, das Sie mit
+@code{EXPLAIN} untersuchen:
+
+@example
+EXPLAIN SELECT tt.TicketNumber, tt.TimeIn,
+ tt.ProjectReference, tt.EstimatedShipDate,
+ tt.ActualShipDate, tt.ClientID,
+ tt.ServiceCodes, tt.RepetitiveID,
+ tt.CurrentProcess, tt.CurrentDPPerson,
+ tt.RecordVolume, tt.DPPrinted, et.COUNTRY,
+ et_1.COUNTRY, do.CUSTNAME
+ FROM tt, et, et AS et_1, do
+ WHERE tt.SubmitTime IS NULL
+ AND tt.ActualPC = et.EMPLOYID
+ AND tt.AssignedPC = et_1.EMPLOYID
+ AND tt.ClientID = do.CUSTNMBR;
+@end example
+
+Nehmen wir bei diesem Beispiel folgendes an:
+
+@itemize @bullet
+@item
+Die Spalten, die verglichen werden, wurden wie folgt deklariert:
+
+@multitable @columnfractions .1 .2 .7
+@item @strong{Tabelle} @tab @strong{Spalte} @tab @strong{Spaltentyp}
+@item @code{tt} @tab @code{ActualPC} @tab @code{CHAR(10)}
+@item @code{tt} @tab @code{AssignedPC} @tab @code{CHAR(10)}
+@item @code{tt} @tab @code{ClientID} @tab @code{CHAR(10)}
+@item @code{et} @tab @code{EMPLOYID} @tab @code{CHAR(15)}
+@item @code{do} @tab @code{CUSTNMBR} @tab @code{CHAR(15)}
+@end multitable
+
+@item
+Die Tabellen haben die unten stehenden Indexe:
+
+@multitable @columnfractions .1 .9
+@item @strong{Tabelle} @tab @strong{Index}
+@item @code{tt} @tab @code{ActualPC}
+@item @code{tt} @tab @code{AssignedPC}
+@item @code{tt} @tab @code{ClientID}
+@item @code{et} @tab @code{EMPLOYID} (primary key)
+@item @code{do} @tab @code{CUSTNMBR} (primary key)
+@end multitable
+
+@item
+Die @code{tt.ActualPC}-Werte sind nicht gleichmäßig verteilt.
+@end itemize
+
+Anfangs, bevor die Optimierung durchgeführt wurde, ergab das
+@code{EXPLAIN}-Statement folgende Informationen:
+
+@example
+table type possible_keys key key_len ref rows Extra
+et ALL PRIMARY NULL NULL NULL 74
+do ALL PRIMARY NULL NULL NULL 2135
+et_1 ALL PRIMARY NULL NULL NULL 74
+tt ALL AssignedPC,ClientID,ActualPC NULL NULL NULL 3872
+ range checked for each record (key map: 35)
+@end example
+
+Weil @code{type} bei jeder Tabelle @code{ALL} ist, zeigt die Ausgabe, dass
+MySQL eine komplette Verknüpfung (Full Join) aller Tabellen durchführt! Das
+dauert recht lange, weil das Produkt der Zeilenanzahl in jeder Tabelle
+untersucht werden muss! In diesem Fall ist das @code{74 * 2.135 * 74 *
+3.872 = 45.268.558.720} Zeilen. Wenn die Tabellen größer wären, können Sie
+sich vorstellen, wie lange das dauern würde.
+
+Ein Problem liegt hier darin, dass MySQL (noch) keine Indexe auf Spalten
+effizient benutzen kann, wenn sie unterschiedlich deklariert sind. In
+diesem Zusammenhang sind @code{VARCHAR} und @code{CHAR} dasselbe, es sei
+denn, sie sind mit unterschiedlichen Längen deklariert. Weil
+@code{tt.ActualPC} als @code{CHAR(10)} und @code{et.EMPLOYID} als
+@code{CHAR(15)} deklariert ist, gibt eine Unstimmigkeit der Längen.
+
+Um diese Ungleichheit der Spaltenlängen zu beheben, benutzen Sie
+@code{ALTER TABLE}, um @code{ActualPC} von 10 auf 15 Zeichen zu verlängern:
+
+@example
+mysql> ALTER TABLE tt MODIFY ActualPC VARCHAR(15);
+@end example
+
+Jetzt sind @code{tt.ActualPC} und @code{et.EMPLOYID} beide
+@code{VARCHAR(15)}. Eine erneute Ausführung des @code{EXPLAIN}-Statements
+ergibt dieses Ergebnis:
+
+@example
+table type possible_keys key key_len rew rows Extra
+tt ALL AssignedPC,ClientID,ActualPC NULL NULL NULL 3872 where used
+do ALL PRIMARY NULL NULL NULL 2135
+ range checked for each record (key map: 1)
+et_1 ALL PRIMARY NULL NULL NULL 74
+ range checked for each record (key map: 1)
+et eq_ref PRIMARY PRIMARY 15 tt.ActualPC 1
+@end example
+
+Das ist nicht perfekt, aber viel besser (das Produkt der @code{rows}-Werte
+ist jetzt um einen Faktor 74 niedriger). Diese Version wird innerhalb von
+ein paar Sekunden ausgeführt.
+
+Eine zweite Änderung kann durchgeführt werden, um die Unstimmigkeit der
+Spaltenlängen für die @code{tt.AssignedPC = et_1.EMPLOYID}- und
+@code{tt.ClientID = do.CUSTNMBR}-Vergleiche zu beheben:
+
+@example
+mysql> ALTER TABLE tt MODIFY AssignedPC VARCHAR(15),
+ MODIFY ClientID VARCHAR(15);
+@end example
+
+Jetzt ergibt @code{EXPLAIN} folgende Ausgabe:
+
+@example
+table type possible_keys key key_len rew rows Extra
+et ALL PRIMARY NULL NULL NULL 74
+tt rew AssignedPC,ClientID,ActualPC ActualPC 15 et.EMPLOYID 52 where used
+et_1 eq_ref PRIMARY PRIMARY 15 tt.AssignedPC 1
+do eq_ref PRIMARY PRIMARY 15 tt.ClientID 1
+@end example
+
+Das ist fast so gut, wie es überhaupt geht.
+
+Das verbleibende Problem besteht darin, dass MySQL vorgabemäßig annimmt,
+dass die Werte in der @code{tt.ActualPC}-Spalte gleichmäßig verteilt sind,
+was in der @code{tt}-Tabelle nicht der Fall ist. Glücklicherweise ist es
+einfach, MySQL darüber zu informieren:
+
+@example
+shell> myisamchk --analyze PFAD_ZU_MYSQL_DATENBANK/tt
+shell> mysqladmin refresh
+@end example
+
+Jetzt ist der Join perfekt und @code{EXPLAIN} ergibt dieses Ergebnis:
+
+@example
+table type possible_keys key key_len ref rows Extra
+tt ALL AssignedPC,ClientID,ActualPC NULL NULL NULL 3872 where used
+et eq_ref PRIMARY PRIMARY 15 tt.ActualPC 1
+et_1 eq_ref PRIMARY PRIMARY 15 tt.AssignedPC 1
+do eq_ref PRIMARY PRIMARY 15 tt.ClientID 1
+@end example
+
+Beachten Sie, dass die @code{rows}-Spalte in der Ausgabe von @code{EXPLAIN}
+eine gehobene Form von Vermutung des MySQL-Join-Optimierers ist. Um eine
+Anfrage zu optimieren, sollten Sie überprüfen, ob diese Zahlen der Wahrheit
+nahe kommen. Wenn nicht, erhalten Sie eventuell bessere Performance, wenn
+Sie @code{STRAIGHT_JOIN} in Ihrem @code{SELECT}-Statement benutzen und
+versuchen, die Tabellen in der @code{FROM}-Klausel in anderer Reihenfolge
+anzugeben.
+
+
+@node Estimating performance, SELECT speed, EXPLAIN, Query Speed
+@c German node Performance abschätzen
+@subsection Anfragen-Performance abschätzen
+
+@cindex abschätzen, Anfragen-Performance
+@cindex Anfragen, Performance abschätzen
+@cindex Performance, abschätzen
+
+In den meisten Fällen können Sie die Performance schätzen, indem Sie
+Suchvorgänge auf Festplatte zählen. Bei kleinen Tabellen können Sie die
+Zeile üblicherweise mit 1 Festplatten-Suchvorgang finden (weil der Index
+wahrscheinlich im Cache ist). Bei größeren Tabellen können Sie schätzen,
+dass Sie (bei der Benutzung von B++-Baum-Indexen) brauchen werden:
+@code{log(zeilen_zahl) / log(index_block_laenge / 3 * 2 / (index_laenge +
+daten_zeiger_laenge)) + 1} Suchvorgänge, um die Zeile zu finden.
+
+In MySQL ist ein Index-Block üblicherweise 1024 Bytes lang und der
+Daten-Zeiger üblicherweise 4 Bytes. Eine 500.000-Zeilen-Tabelle mit einer
+Indexlänge von 3 (medium integer) ergibt:
+@code{log(500.000)/log(1024/3*2/(3+4)) + 1} = 4 Suchvorgänge.
+
+Da der obige Index etwa 500.000 * 7 * 3/2 = 5,2 MB benötigen würde
+(angenommen, dass die Index-Puffer zu 2/3 gefüllt sind, was ein typischer
+Wert sit), haben Sie wahrscheinlich viel vom Index im Arbeitsspeicher und
+werden wahrscheinlich nur 1 bis 2 Betriebssystem-Aufrufe benötigen, um
+Daten zu lesen, um die Zeile zu finden.
+
+Bei Schreibvorgängen brauchen Sie jedoch 4 Suchanfragen (wie oben), um
+herauszufinden, wo der neue Index platziert wird, und normalerweise 2
+Suchvorgänge, um den Index zu aktualisieren und die Zeile zu schreiben.
+
+Beachten Sie, dass oben Gesagtes nicht bedeutet, dass Ihre Applikation
+allmählich mit N log N verfällt! Solange alles durch das Betriebssystem
+oder den SQL-Server gecachet wird, werden die Dinge nur marginal langsamer,
+wenn die Tabellen größer werden. Wenn die Daten zu Groß werden, um
+gecachet zu werden, werden die Dinge anfangen, viel langsamer zu laufen,
+bis Ihre Applikation schließlich komplett durch Suchvorgänge auf
+Festplatte ausgebremst wird (die mit N log N zunehmen). Um das zu
+vermeiden, vergrößern Sie den Index-Cache, wenn die Daten wachsen.
+@xref{Server parameters}.
+
+
+@node SELECT speed, Where optimisations, Estimating performance, Query Speed
+@c German node SELECT-Geschwindigkeit
+@subsection Geschwindigkeit von @code{SELECT}-Anfragen
+
+@findex SELECT-Geschwindigkeit
+
+@cindex Geschwindigkeit, von Anfragen
+
+Wenn Sie ein langsames @code{SELECT ... WHERE} schneller machen wollen, ist
+im Allgemeinen das erste, was zu prüfen ist, ob Sie einen Index hinzufügen
+können oder nicht. @xref{MySQL indexes, , MySQL-Indexe}. Alle Verweise
+(Reference) zwischen verschiedenen Tabellen sollten üblicherweise mit
+Indexen gemacht werden. Sie können den @code{EXPLAIN}-Befehl benutzen, um
+herauszufinden, welche Indexe für ein @code{SELECT} benutzt werden.
+@xref{EXPLAIN, , @code{EXPLAIN}}.
+
+Einige allgemeine Tipps:
+
+@itemize @bullet
+@item
+Um MySQL zu helfen, Anfragen besser zu optimieren, lassen Sie
+@code{myisamchk --analyze} auf eine Tabelle laufen, nachdem sie mit
+relevanten Daten gefüllt wurde. Das aktualisiert einen Wert für jeden
+Index-Teil, der die durchschnittliche Anzahl von Zeilen angibt, die
+denselben Wert haben. (Bei eindeutigen Indexen ist das natürlich immer 1).
+MySQL benutzt diesen Wert, um zu entscheiden, welcher Index benutzt werden
+soll, wenn Sie zwei Tabellen mit einem 'nicht konstanten Ausdruck'
+verbinden. Sie können das Ergebnis nach dem Laufenlassen von @code{analyze}
+mit @code{SHOW INDEX FROM tabelle} überprüfen und die
+@code{Cardinality}-Spalte untersuchen.
+
+@item
+Um einen Index und Daten gemäß einem Index zu sortieren, benutzen Sie
+@code{myisamchk --sort-index --sort-records=1} (wenn Sie nach Index 1
+sortieren wollen). Wenn Sie einen eindeutigen Index haben, von dem Sie alle
+Datensätze gemäß der Reihenfolge dieses Indexes lesen wollen, ist das eine
+gute Art, das schneller zu machen. Beachten Sie jedoch, dieses Sortieren
+nicht optimal geschrieben wird und bei einer großen Tabelle lange dauert!
+@end itemize
+
+
+@node Where optimisations, DISTINCT optimisation, SELECT speed, Query Speed
+@c German node WHERE-Optimierung
+@subsection Wie MySQL @code{WHERE}-Klauseln optimiert
+
+@findex WHERE
+
+@cindex Optimierungen
+
+Die @code{WHERE}-Optimierungen wurden hier in den @code{SELECT}-Teil
+aufgenommen, weil sie meist in Verbindung mit @code{SELECT} benutzt werden,
+aber dieselben Optimierungen treffen für @code{WHERE} bei @code{DELETE}-
+und @code{UPDATE}-Statements zu.
+
+Beachten Sie auch, dass dieser Abschnitt nicht vollständig ist. MySQL führt
+viele Optimierungen durch und wir hatten noch keine Zeit, alle davon zu
+dokumentieren.
+
+Einige der Optimierungen, die MySQL durchführt, sind unten aufgeführt:
+
+@itemize @bullet
+@item
+Entfernung unnötiger Klammern:
+@example
+ ((a AND b) AND c OR (((a AND b) AND (c AND d))))
+-> (a AND b AND c) OR (a AND b AND c AND d)
+@end example
+@item
+Konstanten-'Falten' (Folding):
+@example
+ (a<b AND b=c) AND a=5
+-> b>5 AND b=c AND a=5
+@end example
+@item
+Bedingungsentfernung bei Konstanten (notwendig wegen Konstanten-'Falten'):
+@example
+ (B>=5 AND B=5) OR (B=6 AND 5=5) OR (B=7 AND 5=6)
+-> B=5 OR B=6
+@end example
+@item
+Konstante Ausdrücke, die von Indexen benutzt werden, werden nur einmal
+ausgewertet.
+@item
+@code{COUNT(*)} auf eine einzelne Tabelle ohne ein @code{WHERE} wird direkt
+aus der Tabelleninformation abgerufen. Das wird auch bei jeglichen
+@code{NOT NULL}-Ausdrücken gemacht, wenn diese nur für eine Tabelle benutzt
+werden.
+@item
+Früherkennung ungültiger Konstanten-Ausdrücke. MySQL stellt schnell fest,
+dass einige @code{SELECT}-Statements unmöglich sind, und gibt keine Zeilen
+zurück.
+@item
+@code{HAVING} wird mit @code{WHERE} vereinigt, wenn Sie @code{GROUP BY}
+oder Gruppen-Funktionen (@code{COUNT()}, @code{MIN()} usw.) nicht
+benutzen.
+@item
+Für jeden Sub-Join wird ein einfacheres @code{WHERE} konstruiert, um eine
+schnelle @code{WHERE}-Evaluierung für jeden Sub-Join zu erzielen, und auch,
+um Datensätze so bald wie möglich überspringen zu können.
+@cindex Konstanten-Tabelle
+@cindex Tabellen, Konstanten-
+@item
+Alle Konstanten-Tabellen werden zuerst gelesen, vor jeder anderen Tabelle
+in der Anfrage. Eine Konstanten-Tabelle ist:
+@itemize @minus
+@item
+Eine leere Tabelle oder eine Tabelle mit 1 Zeile.
+@item
+Eine Tabelle, die bei einer @code{WHERE}-Klausel auf einen
+@code{UNIQUE}-Index oder einen @code{PRIMARY KEY} benutzt wird, wobei alle
+Index-Teile mit konstanten Ausdrücken benutzt werden und die Index-Teile
+als @code{NOT NULL} definiert sind.
+@end itemize
+Alle folgenden Tabellen werden als Konstanten-Tabellen benutzt:
+@example
+mysql> SELECT * FROM t WHERE primary_key=1;
+mysql> SELECT * FROM t1,t2
+ WHERE t1.primary_key=1 AND t2.primary_key=t1.id;
+@end example
+
+@item
+Die beste Join-Kombination, um Tabellen zu verknüpfen, wird gefunden, wenn
+man alle Möglichkeiten probiert. Wenn alle Spalten in @code{ORDER BY} und
+in @code{GROUP BY} aus derselben Tabelle stammen, wird diese Tabelle
+vorzugsweise vorn hingestellt, wenn verknüpft wird.
+@item
+Wenn es eine @code{ORDER BY}-Klausel und eine andere @code{GROUP
+BY}-Klausel gibt, oder wenn @code{ORDER BY} oder @code{GROUP BY} Spalten
+aus Tabellen enthält, die nicht aus der ersten Tabelle in der Join-Reihe
+stammen, wird eine temporäre Tabelle erzeugt.
+@item
+Wenn Sie @code{SQL_SMALL_RESULT} benutzen, benutzt MySQL eine temporäre
+Tabelle im Arbeitsspeicher.
+@item
+Jeder Tabellen-Index wird abgefragt und der beste Index, der weniger als
+30% der Zeilen überspannt, wird benutzt. Wenn ein solcher Index nicht
+gefunden werden kann, wird ein schneller Tabellenscan benutzt.
+@item
+In einigen Fällen kann MySQL Zeilen vom Index lesen, ohne überhaupt in der
+Daten-Datei nachzuschlagen. Wenn alle Spalten, die vom Index benutzt
+werden, numerisch sind, wird nur der Index-Baum benutzt, um die Anfrage
+aufzulösen.
+@item
+Bevor jeder Datensatz herausgegeben wird, werden die, die nicht mit der
+@code{HAVING}-Klausel übereinstimmen, übersprungen.
+@end itemize
+
+Einige Beispiele von Anfragen, die sehr schnell sind:
+
+@example
+mysql> SELECT COUNT(*) FROM tabelle;
+mysql> SELECT MIN(schluessel_teil1),MAX(schluessel_teil1) FROM tabelle;
+mysql> SELECT MAX(schluessel_teil2) FROM tabelle
+ WHERE schluessel_teil_1=konstante;
+mysql> SELECT ... FROM tabelle
+ ORDER BY schluessel_teil1,schluessel_teil2,... LIMIT 10;
+mysql> SELECT ... FROM tabelle
+ ORDER BY schluessel_teil1 DESC,schluessel_teil2 DESC,... LIMIT 10;
+@end example
+
+Die folgenden Anfragen werden aufgelöst, indem nur der Index-Baum benutzt
+wird (unter der Annahme, dass die indizierten Spalten numerisch sind):
+
+@example
+mysql> SELECT schluessel_teil1,schluessel_teil2 FROM tabelle WHERE schluessel_teil1=val;
+mysql> SELECT COUNT(*) FROM tabelle
+ WHERE schluessel_teil1=val1 AND schluessel_teil2=val2;
+mysql> SELECT schluessel_teil2 FROM tabelle GROUP BY schluessel_teil1;
+@end example
+
+Die folgenden Anfragen benutzen Indexierung, um die Zeilen in sortierter
+Reihenfolge abzufragen, ohne einen separaten Sortierdurchgang:
+
+@example
+mysql> SELECT ... FROM tabelle ORDER BY schluessel_teil1,schluessel_teil2,... ;
+mysql> SELECT ... FROM tabelle ORDER BY schluessel_teil1 DESC,schluessel_teil2 DESC,... ;
+@end example
+
+
+@node DISTINCT optimisation, LEFT JOIN optimisation, Where optimisations, Query Speed
+@c German node DISTINCT-Optimierung
+@subsection Wie MySQL @code{DISTINCT} optimiert
+
+@findex DISTINCT
+
+@cindex Optimierung, DISTINCT
+
+@code{DISTINCT} wird für alle Spalten in @code{GROUP BY} umgewandelt,
+@code{DISTINCT} in Kombination mit @code{ORDER BY} benötigt in vielen
+Fällen ebenfalls eine temporäre Tabelle.
+
+Wenn @code{LIMIT #} mit @code{DISTINCT} kombiniert wird, hält MySQL an,
+sobald er @code{#} eindeutige Zeilen findet.
+
+Wenn Sie nicht Spalten aus allen benutzten Tabellen verwenden, hält MySQL
+mit dem Scannen der nicht benutzten Tabellen an, sobald er die erste
+Übereinstimmung gefunden hat.
+
+@example
+SELECT DISTINCT t1.a FROM t1,t2 where t1.a=t2.a;
+@end example
+
+Im Beispiel wird angenommen, dass t1 vor t2 benutzt wird (überprüfen Sie
+das mit @code{EXPLAIN}). In diesem Fall hört MySQL auf, von t2 zu lesen
+(für diese bestimmte Zeile in t1), sobald die erste Zeile in t2 gefunden
+wurde.
+
+
+@node LEFT JOIN optimisation, LIMIT optimisation, DISTINCT optimisation, Query Speed
+@c German node LEFT-JOIN-Optimierung
+@subsection Wie MySQL @code{LEFT JOIN} optimiert
+
+@findex LEFT JOIN
+
+@cindex Optimierung, LEFT JOIN
+
+@code{A LEFT JOIN B} ist in MySQL wie folgt implementiert:
+
+@itemize @bullet
+@item
+Die Tabelle @code{B} wird als abhängig von Tabelle @code{A} und allen
+Tabellen, von denen @code{A} abhängig ist, gesetzt.
+
+@item
+Die Tabelle @code{A} wird als abhängig von allen Tabellen (ausser @code{B})
+gesetzt, die in der @code{LEFT JOIN}-Bedingung aufgeführt sind.
+
+@item
+Alle @code{LEFT JOIN}-Bedingungen werden zu @code{WHERE}-Klausel
+verschoben.
+
+@item
+Alle Standard-Join-Optimierungen werden durchgeführt, mit der Ausnahme,
+dass eine Tabelle immer nach allen Tabellen gelesen wird, von denen sie
+abhängig ist. Wenn es eine zirkuläre Abhängigkeit gibt, gibt MySQL einen
+Fehler aus.
+
+@item
+Alle Standard-@code{WHERE}-Optimierungen werden durchgeführt.
+
+@item
+Wenn es eine Zeile in @code{A} gibt, die mit der @code{WHERE}-Klausel
+übereinstimmt, aber keine Zeile in @code{B}, die mit der @code{LEFT
+JOIN}-Bedingung übereinstimmt, wird eine zusätzliche Zeile für @code{B}
+erzeugt, deren Spalten alle auf @code{NULL} gesetzt sind.
+
+@item
+Wenn Sie @code{LEFT JOIN} benutzen, um Zeilen zu finden, die in einer
+Tabelle nicht existieren, und Sie folgendes im @code{WHERE}-Teil angeben:
+@code{spalten_name IS NULL}, wobei spalten_name eine Spalte ist, die als
+@code{NOT NULL} deklariert ist, hört MySQL mit der Suche nach weiteren
+Zeilen auf (für eine bestimmte Schlüsselkombination), nachdem er eine Zeile
+gefunden hat, die mit der @code{LEFT JOIN}-Bedingung übereinstimmt.
+@end itemize
+
+@code{RIGHT JOIN} ist analog zu @code{LEFT JOIN} implementiert.
+
+Die Lese-Reihenfolge der Tabellen, die von @code{LEFT JOIN} und
+@code{STRAIGHT JOIN} erzwungen wird, hilft dem Optimierer (der berechnet,
+in welcher Reihenfolge die Tabellen verknüpft werden sollen), seine Arbeit
+schneller durchzuführen, weil weniger Tabellenvertauschungen überprüft
+werden müssen.
+
+Beachten Sie, dass das oben Gesagte bedeutet, dass bei einer Anfrage des
+folgenden Typs:
+
+@example
+SELECT * FROM a,b LEFT JOIN c ON (c.key=a.key) LEFT JOIN d (d.key=a.key) WHERE b.key=d.key
+@end example
+
+MySQL einen kompletten Scan von @code{b} durchführen wird, weil der
+@code{LEFT JOIN} erzwingt, dass diese vor @code{d} gelesen wird.
+
+Das läßt sich in diesem Fall beheben, indem die Anfrage wie folgt geändert
+wird:
+
+@example
+SELECT * FROM b,a LEFT JOIN c ON (c.key=a.key) LEFT JOIN d (d.key=a.key) WHERE b.key=d.key
+@end example
+
+
+@node LIMIT optimisation, Insert speed, LEFT JOIN optimisation, Query Speed
+@c German node LIMIT-Optimierung
+@subsection Wie MySQL @code{LIMIT} optimiert
+
+@findex LIMIT
+
+@cindex Optimierung, LIMIT
+
+In einigen Fällen handhabt MySQL die Anfrage unterschiedlich, wenn Sie
+@code{LIMIT #} statt @code{HAVING} benutzen:
+
+@itemize @bullet
+@item
+Wenn Sie nur einige wenige Zeilen mit @code{LIMIT} auswählen, benutzt MySQL
+in einigen Fällen Indexe, wenn er ansonsten vorzugsweise einen
+vollständigen Tabellenscan durchführen würde.
+@item
+Wenn Sie @code{LIMIT #} mit @code{ORDER BY} benutzen, beendet MySQL das
+Sortieren, sobald er die ersten @code{#} Zeilen gefunden hat, anstatt die
+gesamte Tabelle zu sortieren.
+@item
+Wenn Sie @code{LIMIT #} mit @code{DISTINCT} kombinieren, hört MySQL auf,
+sobald er @code{#} eindeutige Zeilen gefunden hat.
+@item
+In einigen Fällen kann @code{GROUP BY} aufgelöst werden, indem der
+Schlüssel in der Reihenfolge gelesen wird (oder der Schlüssel sortiert
+wird) und danach Zusammenfassungen berechnet werden, bis sich der
+Schlüsselwert ändert. In diesem Fall berechnet @code{LIMIT #} keine
+unnötigen @code{GROUP BY}'s.
+@item
+Sobald MySQL die ersten @code{#} Zeilen an den Client geschickt hat, wird
+die Anfrage abgebrochen.
+@item
+@code{LIMIT 0} gibt immer schnell eine leere Ergebnismenge (empty set)
+zurück. Das ist nützlich, um die Anfrage zu überprüfen und die Spaltentypen
+der Ergebnisspalten zu erhalten.
+@item
+Die Größe der temporären Tabellen benutzt @code{LIMIT #}, um zu berechnen,
+wieviel Platz benötigt wird, um die Anfrage aufzulösen.
+@end itemize
+
+
+@node Insert speed, Update speed, LIMIT optimisation, Query Speed
+@c German node INSERT-Geschwindigkeit
+@subsection Geschwindigkeit von @code{INSERT}-Anfragen
+
+@findex INSERT
+
+@cindex Geschwindigkeit, beim Einfügen
+@cindex Einfügen, Geschwindigkeit
+
+Die Zeit, einen Datensatz einzufügen, besteht ungefähr aus:
+
+@itemize @bullet
+@item
+Verbindung: (3)
+@item
+Anfrage an den Server schicken: (2)
+@item
+Anfrage parsen: (2)
+@item
+Datensatz einfügen: (1 x Größe des Datensatzes)
+@item
+Indexe einfügen: (1 x Anzahl der Indexe)
+@item
+Schließen: (1)
+@end itemize
+
+Wobei die Zahlen in etwa proportional zur Gesamtzeit sind. Diese Berechnung
+zieht den anfänglichen Overhead, um Tabellen zu öffnen, nicht in Betracht
+(was einmal für jede gleichzeitig laufende Anfrage gemacht wird).
+
+Die Größe der Tabelle verlangsamt das Einfügen von Indexen um N log N
+(B-Bäume).
+
+Einige Möglichkeiten, die Geschwindigkeit von Einfügeoperationen zu
+steigern:
+
+@itemize @bullet
+@item
+Wenn Sie viele Zeilen vom selben Client aus zur gleichen Zeit einfügen,
+benutzen Sie mehrfache Werte (Liste) im @code{INSERT}-Statements. Das geht
+viel schneller (in manchen Fälle um Faktoren) als separate
+@code{INSERT}-Statements zu benutzen. Tunen Sie die
+@code{myisam_bulk_insert_tree_size}-Variable, um das sogar noch zu
+beschleunigen. @xref{SHOW VARIABLES}.
+@item
+Wenn Sie viele Zeilen von unterschiedlichen Clients aus einfügen, können
+Sie mehr Geschwindigkeit erzielen, wenn Sie das @code{INSERT
+DELAYED}-Statement benutzen. @xref{INSERT, , @code{INSERT}}.
+@item
+Beachten Sie, dass Sie mit @code{MyISAM}-Tabellen Zeilen zur selben Zeit
+einfügen können, zu der @code{SELECT}s laufen, wenn es keine gelöschten
+Zeilen in den Tabellen gibt.
+@item
+Wenn Daten in eine Tabelle aus einer Textdatei eingeladen werden, benutzen
+Sie @code{LOAD DATA INFILE}. Das ist üblicherweise 20 mal schneller als
+viele @code{INSERT}-Statements zu benutzen. @xref{LOAD DATA, , @code{LOAD DATA}}.
+@item
+Mit etwas zusätzlicher Mühe ist es möglich, @code{LOAD DATA INFILE} noch
+schneller laufen zu lassen, wenn die Tabelle viele Indexe hat. Gehen Sie
+wie folgt vor:
+
+@enumerate
+@item
+Optional erzeugen Sie die Tabelle mit @code{CREATE TABLE}, zum Beispiel mit
+@code{mysql} oder über die Perl-DBI.
+
+@item
+Führen Sie ein @code{FLUSH TABLES}-Statement oder den Shell-Befehl
+@code{mysqladmin flush-tables} aus.
+
+@item
+Geben Sie @code{myisamchk --keys-used=0 -rq /pfad/zu/db/tabelle} ein.
+Dadurch entfernen Sie die Benutzung aller Indexe von der Tabelle.
+
+@item
+Fügen Sie Daten in die Tabelle mit @code{LOAD DATA INFILE} ein. Dadurch
+werden keine Indexe aktualisiert, was deswegen sehr schnell läuft.
+
+@item
+Wenn Sie in Zukunft nur noch aus der Tabelle lesen, benutzen Sie
+@code{myisampack}, um sie kleiner zu machen. @xref{Compressed format}.
+
+@item
+Erzeugen Sie die Indexe mit @code{myisamchk -r -q /pfad/zu/db/tabelle} neu.
+Hierdurch wird der Index-Baum im Speicher erzeugt, bevor er auf die Platte
+geschrieben wird, was viel schneller ist, weil viele Suchvorgänge auf
+Platte vermieden werden. Der sich ergebende Index-Baum ist ausserdem
+perfekt ausbalanciert.
+
+@item
+Führen Sie ein @code{FLUSH TABLES}-Statement oder den Shell-Befehl
+@code{mysqladmin flush-tables} aus.
+@end enumerate
+
+Diese Prozedur wird in Zukunft in @code{LOAD DATA INFILE} eingebaut werden.
+
+Ab @strong{MySQL 4.0} können Sie auch @code{ALTER TABLE tabelle DISABLE
+KEYS} anstelle von @code{myisamchk --keys-used=0 -rq /pfad/zu/db/tabelle}
+und @code{ALTER TABLE tabelle ENABLE KEYS} anstelle von @code{myisamchk -r
+-q /pfad/zu/db/tabelle} benutzen. Damit können Sie auch die @code{FLUSH
+TABLES}-Schritte überspringen.
+@item
+Sie können die Einfügegeschwindigkeit steigern, indem Sie Tabellen sperren:
+
+@example
+mysql> LOCK TABLES a WRITE;
+mysql> INSERT INTO a VALUES (1,23),(2,34),(4,33);
+mysql> INSERT INTO a VALUES (8,26),(6,29);
+mysql> UNLOCK TABLES;
+@end example
+
+Der hauptsächliche Geschwindigkeitsunterschied liegt darin, dass der
+Index-Puffer nur einmal auf Platte zurück geschrieben wird, nachdem alle
+@code{INSERT}-Statements fertig sind. Normalerweise würden die Index-Puffer
+so oft zurück geschrieben wie es @code{INSERT}-Statements gibt. Das Sperren
+wird nicht benötigt, wenn Sie alle Zeilen mit einem einzigen Statement
+einfügen können.
+
+Durch das Sperren wird auch die Gesamtzeit von Tests auf mehrere
+Verbindungen gesenkt, aber die maximale Wartezeit für einige Threads wird
+erhöht (weil sie auf Sperren warten). Beispiel:
+
+@example
+Thread 1 führt 1000 Einfügevorgänge durch.
+Thread 2, 3 und 4 fügen 1 Einfügevorgang durch.
+Thread 5 führt 1000 Einfügevorgänge durch.
+@end example
+
+Wenn Sie kein Sperren benutzen, sind die Threads 2, 3 und 4 vor 1 und 5
+fertig. Wenn Sie Sperren benutzen, sind 2, 3 und 4 wahrscheinlich nicht vor
+1 oder 5 fertig, aber die Gesamtzeit sollte etwa 40% geringer sein.
+
+Weil @code{INSERT}-, @code{UPDATE}- und @code{DELETE}-Operationen in MySQL
+sehr schnell sind, erhalten Sie bessere Performance über alles, wenn Sie um
+alles herum Sperren hinzufügen, was mehr als etwa 5 Einfügeoperationen oder
+Aktualisierungen (Updates) in einer Zeile durchführt. Wenn Sie sehr viele
+Einfügeoperationen in einer Zeile durchführen, können Sie ein @code{LOCK
+TABLES} machen, gefolgt von einem gelegentlichen @code{UNLOCK TABLES}
+(etwa alle 1.000 Zeilen), um anderen Threads zu gestatten, auf die Tabelle
+zuzugreifen. Das Ergebnis wäre ebenfalls ein netter Geschwindigkeitsgewinn.
+
+Natürlich ist @code{LOAD DATA INFILE} zum Einladen von Daten viel
+schneller.
+@end itemize
+
+Um sowohl für @code{LOAD DATA INFILE} als auch für @code{INSERT} mehr
+Geschwindigkeit zu erzielen, vergrößern Sie den Schlüssel-Puffer.
+@xref{Server parameters}.
+
+
+@node Update speed, Delete speed, Insert speed, Query Speed
+@c German node UPDATE-Geschwindigkeit
+@subsection Geschwindigkeit von @code{UPDATE}-Anfragen
+
+Update-Anfragen werden wie eine @code{SELECT}-Anfrage optimiert, mit dem
+zusätzlichen Overhead eines Schreibvorgangs. Die Geschwindigkeit des
+Schreibvorgangs hängt von der Größe der Daten und von der Anzahl der
+Indexe, die aktualisiert werden, ab. Indexe, die nicht geändert werden,
+werden nicht aktualisiert.
+
+Eine weitere Möglichkeit, Aktualisierungen (Updates) schnell zu machen,
+ist, sie zu verzögern und dann später viele Aktualisierungen hintereinander
+zu machen. Viele Aktualisierungen hintereinander sind viel schneller als
+nur eine zugleich, wenn Sie die Tabelle sperren.
+
+Beachten Sie, dass die Aktualisierung eines Datensatzes bei dynamischem
+Datensatzformat dazu führen kann, dass der Datensatz aufgespalten wird.
+Wenn Sie das oft durchführen, ist es daher sehr wichtig, gelegentlich
+@code{OPTIMIZE TABLE} auszuführen. @xref{OPTIMIZE TABLE, , @code{OPTIMIZE TABLE}}.
+
+
+@node Delete speed, Tips, Update speed, Query Speed
+@c German node DELETE-Geschwindigkeit
+@subsection Geschwindigkeit von @code{DELETE}-Anfragen
+
+Wenn Sie alle Zeilen in der Tabelle löschen wollen, sollten Sie
+@code{TRUNCATE TABLE tabelle} benutzen. @xref{TRUNCATE}.
+
+Die Zeit, die für das Löschen eines Datensatzes benötigt wird, ist exakt
+proportional zur Anzahl der Indexe. Um Datensätze schneller zu löschen,
+können Sie die Größe des Index-Caches herauf setzen.
+@xref{Server parameters}.
+
+
+@node Tips, , Delete speed, Query Speed
+@c German node Tipps
+@subsection Weitere Optimierungstipps
+
+@cindex Optimierung, Tipps
+@cindex Tipps, Optimierung
+
+Ungeordnete Liste von Tipps für schnellere Systeme:
+
+@itemize @bullet
+@item
+Benutzen Sie persistente Verbindungen zur Datenbank, um
+Verbindungs-Overhead zu vermeiden. Wenn Sie keine persistenten Verbindungen
+benutzen können und viele neue Verbindungen zur Datenbank aufmachen,
+sollten Sie den Wert der @code{Thread_cache_size}-Variablen ändern.
+@xref{Server parameters}.
+@item
+Überprüfen Sie immer, dass alle Ihre Anfragen tatsächlich die Indexe
+benutzen, die Sie in den Tabellen erzeugt haben. In MySQL kann man das mit
+dem @code{EXPLAIN}-Befehl tun. @xref{EXPLAIN, Explain, Explain, Handbuch}.
+@item
+Versuchen Sie, komplexe @code{SELECT}-Anfragen auf Tabellen zu vermeiden,
+die viel aktualisiert werden, um Probleme mit Tabellensperren zu vermeiden.
+@item
+Die neuen @code{MyISAM}-Tabellen können Zeilen in eine Tabelle ohne
+gelöschte Zeile zur gleichen Zeit einfügen, wie eine andere Tabelle aus ihr
+liest. Wenn das für Sie wichtig ist, sollten Sie Methoden in Betracht
+ziehen, bei denen Sie keine Zeilen löschen müssen, oder @code{OPTIMIZE
+TABLE} laufen lassen, nachdem Sie viele Zeilen gelöscht haben.
+@item
+Benutzen Sie @code{ALTER TABLE ... ORDER BY ausdruck1,ausdruck2,...}, wenn
+Sie Zeilen zumeist in der Reihenfolge ausdruck1,ausdruck2,... abrufen. Wenn
+Sie diese Option nach großen Änderungen in der Tabelle nutzen, erzielen
+Sie eventuell höhere Performance.
+@item
+In einigen Fällen kann es sinnvoll sein, eine Spalte einzuführen, die auf
+der Grundlage von Informationen aus anderen Spalten 'gehashed' ist. Wenn
+diese Spalte kurz und halbwegs eindeutig ist, kann das schneller sein als
+ein großer Index auf mehrere Spalten. In MySQL ist es sehr einfach, eine
+solche zusätzliche Spalte zu benutzen:
+@code{SELECT * FROM tabelle WHERE hash=MD5(concat(spalte1,spalte2))
+AND spalte_1='constant' AND spalte_2='constant'}
+@item
+Bei Tabellen, die sich viel ändern, sollten Sie versuchen, alle
+@code{VARCHAR}- oder @code{BLOB}-Spalten zu vermeiden. Sonst erhalten Sie
+dynamische Zeilenlängen, sobald Sie eine einzige @code{VARCHAR}- oder
+@code{BLOB}-Spalte verwenden. @xref{Table types}.
+@item
+Normalerweise nützt es nichts, eine Tabelle in verschiedene Tabellen
+aufzuteilen, nur weil die Zeile 'viel' werden. Um auf eine Zeile
+zuzugreifen, ist das wichtigste, was die Performance betrifft, der
+Suchvorgang nach dem ersten Byte der Zeile auf der Platte. Nachdem die
+Daten gefunden wurden, können die meisten neuen Platten die gesamte Zeile
+für die meisten Applikationen schnell genug lesen. Der einzige Fall, wo es
+wirklich etwas ausmacht, wenn eine Tabelle aufgeteilt wird, ist, wenn die
+Tabelle dynamische Zeilenlänge hat (siehe oben), was nicht in eine feste
+Zeilenlänge umgewandelt werden kann, oder wenn Sie die Tabelle sehr oft
+scannen müssen, die meisten der Spalten hierfür aber nicht benötigen.
+@xref{Table types}.
+@item
+Wenn Sie sehr oft etwas auf der Grundlage von Informationen aus sehr vielen
+Zeilen berechnen müssen (zum Beispiel Dinge zählen), ist es wahrscheinlich
+besser, eine neue Tabelle einzuführen und den Zähler in Echtzeit zu
+aktualisieren. Eine Aktualisierung des Typs @code{UPDATE tabelle set
+zaehler=zaehler+1 where index_spalte=konstante} ist sehr schnell!
+
+Das ist sehr wichtig, wenn Sie Datenbanken wie MySQL benutzen, die nur
+Tabellensperren haben (viele Leser / einzelne Schreiber). Bei den meisten
+sonstigen Datenbanken ergibt das ebenfalls bessere Performance, weil der
+Zeilensperr-Manager weniger zu tun haben wird.
+@item
+Wenn Sie Statistiken aus großen Log-Tabellen gewinnen wollen, benutzen Sie
+Zusammenfassungstabellen, statt die gesamte Tabelle zu scannen. Die Wartung
+der Zusammenfassungen sollte wesentlich leichter sein, als die Statistiken
+'live' zu generieren. Es ist viel schneller, neue Zusammenfassungstabellen
+aus den Logs zu erzeugen, wenn sich Dinge ändern (abhängig von
+Geschäftsentscheidungen) als eine laufende Applikation ändern zu müssen!
+@item
+Wenn möglich sollte man Berichte als 'live' oder 'statistisch'
+klassifizieren, wobei die Daten, die für statistische Berichte benötigt
+werden, nur auf der Grundlage von Zusammenfassungstabellen erzeugt werden,
+die aus den eigentlichen Daten generiert werden.
+@item
+Ziehen Sie Vorteile aus der Tatsache, dass Spalten Vorgabewerte haben.
+Fügen Sie nur dann explizit Werte ein, wenn der einzufügende Wert vom
+Vorgabewert abweicht. Das verringert das Parsen, das MySQL durchführen
+muss, und erhöht die Einfügegeschwindigkeit.
+@item
+In einigen Fällen ist es bequem, Daten zu komprimieren und in einem Blob zu
+speichern. In diesem Fall müssen Sie in Ihrer Applikation etwas
+zusätzlichen Code unterbringen, um die Dinge im Blob zu packen bzw. zu
+entpacken. Das kann aber in manchen Phasen etliches an Zugriffen einsparen.
+Das ist praktisch, wenn Sie Daten haben, die mit einer statischen
+Tabellenstruktur nicht konform sind.
+@item
+Normalerweise sollten Sie versuchen, alle Daten nicht redundant zu halten
+(was sich in der Datenbanktheorie dritte Normalform nennt). Scheuen Sie
+sich aber nicht davor, Dinge zu duplizieren oder Zusammenfassungstabellen
+zu erzeugen, wenn Sie dies brauchen, um mehr Geschwindigkeit zu erzielen.
+@item
+Gespeicherte Prozeduren (Stored Procedures) oder UDF (user defined
+functions, benutzerdefinierte Funktionen) sind eine gute Möglichkeit, mehr
+Performance zu erzielen. Sie sollten jedoch immer eine andere (langsamere)
+Möglichkeit parat haben, wenn Sie eine Datenbank benutzen, die gespeicherte
+Prozeduren nicht unterstützt.
+@item
+Man erreicht immer etwas, wenn man Anfragen / Antworten in der Applikation
+cachet und versucht, viele Einfüge- oder Aktualisierungsvorgänge zugleich
+durchzuführen. Wenn Ihre Datenbank Tabellensperren unterstützt (wie MySQL
+und Oracle), sollte das dazu führen, dass der Index-Cache nur einmal auf
+Platte zurück geschrieben wird, nachdem alles Einfügen / Aktualisieren
+ausgeführt ist.
+@item
+Benutzen Sie @code{INSERT /*! DELAYED */}, wenn Sie nicht wissen brauchen,
+wann Ihre Daten geschrieben werden. Das erhöht die Geschwindigkeit, weil
+viele Datensätze mit einem einzige Festplattenschreibzugriff geschrieben
+werden können.
+@item
+Benutzten Sie @code{INSERT /*! LOW_PRIORITY */}, wenn Sie wollen, dass Ihre
+Selects höhere Priorität haben.
+@item
+Benutzen Sie @code{SELECT /*! HIGH_PRIORITY */}, um zu bewirken, dass
+Selects in der Wartereihe nach vorn springen. Das heißt, der Select wird
+sogar dann durchgeführt, wenn jemand darauf wartet, etwas zu schreiben.
+@item
+Benutzen Sie das mehrzeilige @code{INSERT}-Statement, um viele Zeilen mit
+einem SQL-Befehl zu speichern (viele SQL-Server unterstützen das).
+@item
+Benutzen Sie @code{LOAD DATA INFILE}, um größere Datenmengen zu laden. Das
+ist schneller als normale Einfügevorgänge und wird noch schneller, wenn
+@code{myisamchk} in @code{mysqld} integriert wird.
+@item
+Benutzen Sie @code{AUTO_INCREMENT}-Spalten, um eindeutige Werte zu
+erzeugen.
+@item
+Benutzen Sie gelegentlich @code{OPTIMIZE TABLE}, um Fragmentierungen zu
+vermeiden, wenn Sie das dynamische Tabellenformat verwenden.
+@c German FIX changed @xref from TABLE to OPTIMIZE TABLE (point to proper node)
+@xref{OPTIMIZE TABLE}.
+@item
+Benutzen Sie - wenn möglich - @code{HEAP}-Tabellen, um mehr Geschwindigkeit
+zu erzielen. @xref{Table types}.
+@item
+Bei einer normalen Webserver-Konfiguration sollten Bilder als separate
+Dateien gespeichert werden. Das heißt, speichern Sie nur einen Verweis zur
+Datei in der Datenbank. Der Hauptgrund ist, dass normale Webserver viel
+besser darin sind, Dateien zu cachen als Datenbankinhalte. Daher ist es
+viel einfacher, ein schnelles System zu bekommen, wenn Sie Dateien
+benutzen.
+@item
+Benutzen Sie für nicht kritische Daten, auf die oft zugegriffen wird,
+Tabellen im Arbeitsspeicher (zum Beispiel Informationen über die Banner,
+die Benutzern ohne Cookies zuletzt präsentiert wurden).
+@item
+Spalten mit identischen Informationen in unterschiedlichen Tabellen sollten
+identisch deklariert sein und identische Namen haben. Vor Version 3.23
+konnte man ansonsten langsame Joins erhalten.
+
+Versuchen Sie, die Namen einfach zu halten (benutzen Sie @code{name}
+anstelle von @code{kunde_name} in der Kundentabelle). Um Namen für andere
+SQL-Server portabel zu halten, sollten Sie sie kürzer als 18 Zeichen
+halten.
+@item
+Wenn Sie WIRKLICH hohe Geschwindigkeit brauchen, sollten Sie einen Blick
+auf die Low-Level-Schnittstellen zur Datenspeicherung werfen, die die
+unterschiedlichen SQL-Server unterstützen! Wenn Sie zum Beispiel auf
+@code{MyISAM} direkt zugreifen, erhalten Sie eine
+Geschwindigkeitssteigerung um den Faktor 2 bis 5, im Vergleich zur
+Benutzung der SQL-Schnittstelle. Um das durchführen zu können, müssen die
+Daten auf demselben Server liegen wie die Applikation und üblicherweise
+sollte auf sie nur von einem Prozess zugegriffen werden (weil externes
+Dateisperren reichlich langsam ist). Man könnte die oben genannten Probleme
+beseitigen, indem Low-Level-@code{MyISAM}-Befehle in den MySQL-Server
+eingebaut werden (das wäre eine einfache Möglichkeit, bei Bedarf mehr
+Performance zu erlangen). Indem die Datenbankshnittstelle sorgfältig
+entworfen wird, sollte es recht einfach sein, diese Arten von Optimierung
+zu unterstützen.
+@item
+In vielen Fällen ist es schneller, auf Daten aus einer Datenbank (mit einer
+direkten Verbindung) als über eine Textdatei zuzugreifen, schon deshalb,
+weil die Datenbank wahrscheinlich kompakter ist als die Textdatei (wenn Sie
+numerische Daten benutzen) und hierdurch weniger Festplattenzugriffe
+erforderlich sind. Ausserdem wird Code eingespart, weil Sie Ihre
+Textdateien nicht parsen müssen, um Zeilen- und Spaltenbegrenzungen zu
+finden.
+@item
+Ausserdem können Sie Replikation benutzen, um die Geschwindigkeit zu
+steigern. @xref{Replication}.
+@item
+Wenn eine Tabelle mit @code{DELAY_KEY_WRITE=1} deklariert wird, werden
+Aktualisierungen auf Indexe schneller, weil diese nicht auf Platte
+geschrieben werden, bis die Datei geschlossen wird. Der Nachteil ist, dass
+Sie auf diesen Tabellen @code{myisamchk} laufen lassen sollten, bevor Sie
+@code{mysqld} starten, um sicherzustellen, dass diese in Ordnung sind,
+falls irgend etwas @code{mysqld} mittendrin killt. Weil die
+Schlüssel-Informationen jederzeit aus den Daten erzeugt werden können,
+sollten Sie durch @code{DELAY_KEY_WRITE} nichts verlieren.
+@end itemize
+
+
+@node Locking Issues, Optimising Database Structure, Query Speed, MySQL Optimisation
+@c German node Sperren (Locks)
+@section Sperren (Locking)
+
+
+
+
+@menu
+* Internal locking::
+* Table locking::
+@end menu
+
+@node Internal locking, Table locking, Locking Issues, Locking Issues
+@c German node Internes Sperren
+@subsection Wie MySQL Tabellen sperrt
+
+@cindex internes Sperren
+@cindex sperren, Tabellen
+@cindex Tabellen, sperren
+
+Im Anhang finden Sie eine Erörterung zu den unterschiedlichen
+Sperrmethoden. @xref{Locking methods}.
+
+Jedes Sperren in MySQL ist blockierungsfrei. Das wird erreicht, indem alle
+Sperren zugleich am Anfang einer Anfrage angefordert werden, und indem
+Tabellen immer in derselben Reihenfolge gesperrt werden.
+
+The Sperrmethode, die MySQL für @code{WRITE}-Sperren benutzt, funktioniert
+wie folgt:
+
+@itemize @bullet
+@item
+Falls es keine Sperren auf die Tabelle gibt, wird eine Schreibsperre
+gemacht.
+@item
+Ansonsten wird die Sperranforderung in die Schreibsperren-Warteschlange
+eingereiht.
+@end itemize
+
+Die Sperrmethode, die MySQL für @code{READ}Sperren benutzt, funktioniert
+wie folgt:
+
+@itemize @bullet
+@item
+Falls es keine Schreibsperren auf die Tabelle gibt, wird eine Lesesperre
+gemacht.
+@item
+Ansonsten wird die Sperranforderung in die Lesesperren-Warteschlange
+eingereiht.
+@end itemize
+
+Wenn eine Sperre aufgehoben wird, wird die Sperren den Threads in der
+Schreibsperren-Warteschlange verfügbar gemacht, danach den Threads in der
+Lesesperren-Warteschlange.
+
+Das bedeutet, wenn Sie viele Aktualisierungen auf eine Tabelle haben,
+warten @code{SELECT}-Statements, bis es keine Aktualisierungen mehr gibt.
+
+Um das für den Fall zu umgehen, dass es viele @code{INSERT}-
+und-@code{SELECT}-Operationen auf eine Tabelle gibt, können Sie Zeilen in
+eine temporäre Tabelle einfügen und die echte Tabelle gelegentlich aus den
+Daten der temporäre Tabelle aktualisieren.
+
+Das machen Sie wie folgt:
+@example
+mysql> LOCK TABLES echte_tabelle WRITE, einfuege_tabelle WRITE;
+mysql> insert into echte_tabelle select * von einfuege_tabelle;
+mysql> TRUNCATE TABLE einfuege_tabelle;
+mysql> UNLOCK TABLES;
+@end example
+
+Sie können bei @code{INSERT}, @code{UPDATE} oder @code{DELETE} die
+@code{LOW_PRIORITY}-Option oder bei @code{SELECT} die
+@code{HIGH_PRIORITY}-Option benutzen, wenn Sie dem Abruf von Daten in
+bestimmten Fällen Priorität einräumen wollen. Sie können auch @code{mysqld}
+mit @code{--low-priority-updates} starten, um dasselbe Verhalten zu
+erreichen.
+
+Die Benutzung von @code{SQL_BUFFER_RESULT} kann ebenfalls helfen,
+Tabellensperren kürzer zu machen. @xref{SELECT}.
+
+Sie können auch den Sperr-Code in @file{mysys/thr_lock.c} ändern, um eine
+einzige Warteschlagen zu benutzen. In diesem Fall haben Schreibsperren und
+Lesesperren dieselbe Priorität, was bei einigen Applikationen eventuell
+hilfreich ist.
+
+
+@node Table locking, , Internal locking, Locking Issues
+@c German node Tabellensperren
+@subsection Themen, die Tabellensperren betreffen
+
+@cindex Probleme, Tabellensperren
+
+Der Tabellensperren-Code in MySQL ist blockierungsfrei.
+
+MySQL benutzt Tabellensperren (anstelle von Zeilensperren oder
+Spaltensperren) für alle Tabellentypen ausser @code{BDB}-Tabellen, um eine
+sehr hohe Sperrgeschwindigkeit zu erzielen. Bei großen Tabellen ist
+Tabellensperren bei den meisten Applikationen VIEL besser als
+Zeilensperren, aber es gibt natürlich ein paar Fallstricke.
+
+Bei @code{BDB}- und @code{InnoDB}-Tabellen benutzt MySQL Tabellensperren,
+wenn Sie die Tabelle explizit mit @code{LOCK TABLES} sperren oder einen
+Befehl ausführen, der jede Zeile in der Tabelle ändern wird, wie
+@code{ALTER TABLE}. Bei diesen Tabellentypen empfehlen wir, @code{LOCK
+TABLES} überhaupt nicht zu benutzen.
+
+Ab MySQL-Version 3.23.7 können Sie Zeilen in @code{MyISAM}-Tabellen zur
+gleichen Zeit einfügen, während andere Threads aus der Tabelle lesen.
+Beachten Sie, dass das momentan nur funktioniert, wenn es zu der Zeit, zu
+der das Einfügen vorgenommen wird, keine durch gelöschte Zeilen verursachte
+Löcher in der Tabelle gibt. Wenn alle Löcher mit neuen Daten gefüllt
+wurden, werden gleichzeitige Einfügevorgänge automatisch wieder aktiviert.
+
+Tabellensperren ermöglicht, dass viele Threads gleichzeitig aus einer
+Tabelle lesen, aber bevor ein Thread in die Tabelle schreiben kann, muss er
+zunächst exklusiven Zugriff erhalten. Während der Aktualisierung müssen
+andere Threads, die auf diese Tabelle zugreifen wollen, warten, bis die
+Aktualisierung fertig ist.
+
+Weil Aktualisierung von Tabellen normalerweise als wichtiger erachtet
+werden als @code{SELECT}, erhalten alle Statements, die eine Tabelle
+aktualisieren, eine höhere Priorität als Statements, die Informationen aus
+der Tabelle abrufen. Das sollte sicherstellen, dass Aktualisierungen nicht
+'verhungern', wenn viele große Anfragen auf eine bestimmte Tabelle
+durchgeführt werden. (Sie können das ändern, indem Sie bei dem Statement,
+dass die Aktualisierung durchführt, LOW_PRIORITY verwenden, oder beim
+@code{SELECT}-Statement @code{HIGH_PRIORITY}.)
+
+Ab MySQL-Version 3.23.7 können Sie die @code{max_write_lock_count}-Variable
+benutzen, um MySQL zu zwingen, temporär allen @code{SELECT}-Statements, die
+auf eine Tabelle warten, nach einer bestimmten Anzahl von Einfügevorgängen
+auf eine Tabelle höhere Priorität einzuräumen.
+
+Tabellensperren ist jedoch bei folgendem Szenario nicht sehr gut:
+
+@itemize @bullet
+@item
+Ein Client führt ein @code{SELECT} aus, das lange Zeit läuft.
+@item
+Ein anderer Client führt danach ein @code{UPDATE} auf die benutzte Tabelle
+aus. Dieser Client wartet, bis das @code{SELECT} fertig ist.
+@item
+Ein weiterer Client führt ein weiteres @code{SELECT}-Statement auf dieselbe
+Tabelle aus. Weil @code{UPDATE} höhere Priorität als @code{SELECT} hat,
+wartet dieses @code{SELECT}, bis das @code{UPDATE} fertig ist. Es wartet
+auch darauf, dass das erste @code{SELECT} fertig ist!
+@item
+Ein Thread wartet bei etwas wie @code{Platte voll}. In diesem Fall warten
+alle anderen Threads, die auf die problemverursachende Tabelle zugreifen
+wollen, bis mehr Speicher verfügbar gemacht wurde.
+@end itemize
+
+Mögliche Lösungen dieses Problems sind:
+
+@itemize @bullet
+@item
+Versuchen Sie, @code{SELECT}-Statements schneller ablaufen zu lassen.
+Hierfür müssen Sie eventuell Zusammenfassungstabellen erzeugen.
+
+@item
+Starten Sie @code{mysqld} mit @code{--low-priority-updates}. Das gibt allen
+Statements, die eine Tabelle aktualisieren (ändern), geringere Priorität
+als einem @code{SELECT}-Statement. Im vorstehenden Szenario würde das
+@code{SELECT}-Statement vor dem @code{INSERT}-Statement ausgeführt werden.
+
+@item
+Sie können auch einem bestimmten @code{INSERT}-, @code{UPDATE}- oder
+@code{DELETE}-Statement mit dem @code{LOW_PRIORITY}-Attribut geringere
+Priorität geben.
+
+@item
+Starten Sie @code{mysqld} mit einem niedrigen Wert für
+@strong{max_write_lock_count}, um @code{READ}-Sperren nach einer bestimmten
+Anzahl von @code{WRITE}-Sperren zu ermöglichen.
+
+@item
+Sie können festlegen, dass alle Aktualisierungen von einem bestimmten
+Thread mit niedriger Priorität ausgeführt werden, indem Sie den SQL-Befehl
+@code{SET SQL_LOW_PRIORITY_UPDATES=1} benutzen. @xref{SET OPTION, ,
+@code{SET OPTION}}.
+
+@item
+Sie können mit dem @code{HIGH_PRIORITY}-Attribut festlegen, dass ein
+bestimmtes @code{SELECT} sehr wichtig ist. @xref{SELECT, , @code{SELECT}}.
+
+@item
+Wenn Sie Probleme mit @code{INSERT} in Kombination mit @code{SELECT} haben,
+stellen Sie auf die neuen @code{MyISAM}-Tabellen um, weil diese
+gleichzeitige @code{SELECT}s und @code{INSERT}s unterstützen.
+
+@item
+Wenn Sie hauptsächlich @code{INSERT}- und @code{SELECT}-Statements mischen,
+wird das @code{DELAYED}-Attribut für @code{INSERT} wahrscheinlich Ihre
+Probleme lösen. @xref{INSERT, , @code{INSERT}}.
+
+@item
+Wenn Sie Probleme mit @code{SELECT} und @code{DELETE} haben, mag die
+@code{LIMIT}-Option für @code{DELETE} helfen. @xref{DELETE, ,
+@code{DELETE}}.
+@end itemize
+
+
+@node Optimising Database Structure, Optimising the Server, Locking Issues, MySQL Optimisation
+@c German node Optimierung der Datenbank-Struktur
+@section Optimierung der Datenbank-Struktur
+
+
+
+
+@menu
+* Design::
+* Data size::
+* MySQL indexes::
+* Indexes::
+* Multiple-column indexes::
+* Open tables::
+* Table cache::
+* Creating many tables::
+@end menu
+
+@node Design, Data size, Optimising Database Structure, Optimising Database Structure
+@c German node Design
+@subsection MySQL-Datenbank-Design-Überlegungen
+
+@cindex Design, Überlegungen zum Datenbank-Design
+@cindex Datenbank-Design
+@cindex Speicherung von Daten
+
+MySQL speichert Zeilendaten und Indexdaten in separaten Dateien. Viele
+(fast alle) anderen Datenbanken vermischen Zeilen- und Indexdaten in
+derselben Datei. Wir glauben, dass die Wahl, die MySQL getroffen hat, für
+einen sehr weiten Bereich moderner Systeme besser ist.
+
+Eine weitere Möglichkeit, Zeilendaten zu speichern, besteht darin, die
+Information für jede Spalten in einem separaten Bereich zu halten
+(Beispiele sind SDBM und Focus). Das verursacht Performance-Einbussen für
+jede Anfrage, die auf mehr als eine Spalte zugreift. Weil das so schnell
+schlechter wird, wenn auf mehr als eine Spalte zugegriffen wird, glauben
+wir, dass dieses Modell für Mehrzweck-Datenbanken nicht gut ist.
+
+Der häufigere Fall ist, dass Index und Daten zusammen gespeichert sind (wie
+bei Oracle, Sybase usw.). In diesem Fall befindet sich die
+Zeileninformation auf der Leaf-Page des Indexes. Das Gute daran ist, dass
+man sich damit - abhängig davon, wie gut der Index gecachet ist - einen
+Festplatten-Lesezugriff spart. Das Schlechte an diesem Layout sind
+folgende Dinge:
+
+@itemize @bullet
+@item
+Tabellenscannen geht viel langsamer, weil man durch alle Indexe lesen muss,
+um an die Daten zu kommen.
+@item
+Man kann nicht nur die Index-Tabelle benutzen, um Daten einer Anfrage
+abzurufen.
+@item
+Man verliert viel Speicherplatz, weil man Indexe von den Nodes duplizieren
+muss (weil man die Zeile nicht in den Nodes speichern kann).
+@item
+Löschvorgänge werden die Tabelle im Zeitablauf zersetzen (weil Indexe in
+Nodes üblicherweise bei Löschvorgängen nicht aktualisiert werden).
+@item
+Ist es schwieriger, NUR die Index-Daten zu cachen.
+@end itemize
+
+
+@node Data size, MySQL indexes, Design, Optimising Database Structure
+@c German node Datengröße
+@subsection Wie Sie Ihre Daten so klein wie möglich bekommen
+
+@cindex Daten, Größe
+@cindex verringern, Datengröße
+@cindex Speicherplatz, minimieren
+@cindex Tabellen, Performance verbessern
+@cindex Performance, verbessern
+
+Eine der grundlegendsten Optimierungen besteht darin, Ihre Daten (und
+Indexe) dazu zu bekommen, dass sie möglichst wenige Platz auf der Platte
+(und im Arbeitsspeicher) benutzen. Das kann zu gewaltigen Verbesserungen
+führen, weil Lesezugriffe von der Platte schneller ablaufen und
+normalerweise weniger Hauptspeicher benutzt wird. Das Indexieren nimmt
+darüber hinaus weniger Ressourcen in Anspruch, wenn es auf kleinere Spalten
+durchgeführt wird.
+
+MySQL unterstützt viele verschiedene Tabellentypen und Zeilenformate. Wenn
+Sie das richtige Tabellenformat benutzen, kann Ihnen das große
+Performance-Gewinne bringen.
+@xref{Table types}.
+
+Sie erhalten bessere Performance auf eine Tabelle und minimieren den
+benötigten Speicherplatz, wenn Sie die unten aufgeführten Techniken
+verwenden:
+
+@itemize @bullet
+@item
+Benutzen Sie die effizientesten (kleinsten) möglichen Typen. MySQL hat
+viele spezialisierte Typen, die Plattenplatz und Arbeitsspeicher sparen.
+
+@item
+Benutzen Sie - falls möglich - die kleineren Ganzzahl-Typen, um kleinere
+Tabellen zu erhalten. @code{MEDIUMINT} zum Beispiel ist oft besser als
+@code{INT}.
+
+@item
+Deklarieren Sie Spalten - falls möglich - als @code{NOT NULL}. Das macht
+alles schneller und Sie sparen ein Bit pro Spalte. Beachten Sie, dass, wenn
+Sie wirklich @code{NULL} in Ihrer Applikation benötigen, Sie dieses
+natürlich benutzen sollten. Vermeiden Sie nur, einfach alle Spalten
+vorgabemäßig auf @code{NULL} zu haben.
+
+@item
+Wenn Sie keine Spalten variabler Länge haben (@code{VARCHAR}, @code{TEXT}
+oder @code{BLOB}-Spalten), wird ein Festgrößenformat benutzt. Das ist
+schneller, mag aber leider etwas Speicherplatz verschwenden.
+@xref{MyISAM table formats}.
+
+@item
+Der primäre Index einer Tabelle sollte so kurz wie möglich sein. Das macht
+die Identifikation einer Zeile schnell und effizient.
+
+@item
+Bei jeder Tabelle müssen Sie entscheiden, welche Speicher- / Index-Methode
+benutzt werden soll. @xref{Table types}.
+
+@item
+Erzeugen Sie nur die Indexe, die Sie tatsächlich brauchen. Indexe sind gut
+für das Abfragen von Daten, aber schlecht, wenn Sie Dinge schnell speichern
+müssen. Wenn Sie meist auf eine Tabelle zugreifen, indem Sie nach einer
+Kombination von Spalten suchen, legen Sie einen Index auf diese. Der erste
+Index-Teil sollte die meistbenutzte Spalte sein. Wenn Sie IMMER viele
+Spalten benutzen, sollten Sie die Spalte zuerst benutzen, die mehr
+Duplikate hat, um eine bessere Kompression des Indexes zu erzielen.
+
+@item
+Wenn es sehr wahrscheinlich ist, dass eine Spalte ein eindeutiges Präfix
+auf der ersten Anzahl von Zeichen hat, ist es besser, nur dieses Präfix zu
+indexieren. MySQL unterstützt einen Index auf einem Teil einer
+Zeichen-Spalte. Kürzere Indexe sind nicht nur schneller, weil sie weniger
+Plattenplatz brauchen, sondern auch, weil Sie mehr Treffer im Index-Cache
+erhalten und daher weniger Festplattenzugriffe benötigen.
+@xref{Server parameters}.
+
+@item
+Unter manchen Umständen kann es vorteilhaft sein, eine Tabelle zu teilen,
+die sehr oft gescannt wird. Das gilt insbesondere, wenn diese ein
+dynamisches Tabellenformat hat und es möglich ist, durch die Zerlegung eine
+kleinere Tabelle mit statischem Format zu erhalten, die benutzt werden
+kann, um die relevanten Zeilen zu finden.
+@end itemize
+
+
+@node MySQL indexes, Indexes, Data size, Optimising Database Structure
+@c German node MySQL-Indexe
+@subsection Wie MySQL Indexe benutzt
+
+@cindex Indexe, Benutzung von
+
+Indexe werden benutzt, um Zeilen mit einem bestimmten Spaltenwert schnell
+zu finden. Ohne Index müsste MySQL mit dem ersten Datensatz anfangen und
+dann durch die gesamte Tabelle lesen, bis er die relevanten Zeilen findet.
+Je größer die Tabelle, desto mehr Zeit kostet das. Wenn die Tabellen für
+die infrage kommenden Zeilen einen Index hat, kann MySQL schnell eine
+Position bekommen, um mitten in der Daten-Datei loszusuchen, ohne alle
+Daten zu betrachten. Wenn eine Tabelle 1.000 Zeilen hat, ist das mindestens
+100 mal schneller als sequentielles Lesen. Wenn Sie jedoch auf fast alle
+1.000 Zeilen zugreifen müssen, geht sequentielles Lesen schneller, weil man
+mehrfache Festplattenzugriffe einspart.
+
+Alle MySQL-Indexe (@code{PRIMARY}, @code{UNIQUE} und @code{INDEX}) sind in
+B-Bäumen gespeichert. Zeichenketten werden automatisch präfix-komprimiert,
+ebenfalls werden Leerzeichen am Ende komprimiert.
+@c German FIX unsplit @xref
+@xref{CREATE INDEX, ,@code{CREATE INDEX}}.
+
+Indexe werden benutzt, um:
+@itemize @bullet
+@item
+Schnell die Zeilen zu finden, die mit einer @code{WHERE}-Klausel
+übereinstimmen.
+
+@item
+Zeilen aus anderen Tabellen abzurufen, wenn Sie Joins durchführen.
+
+@item
+Den @code{MAX()}- oder @code{MIN()}-Wert für eine spezielle indizierte
+Spalte zu finden. Das wird durch einen Präprozessor optimiert, der
+überprüft, ob Sie @code{WHERE} schluessel_teil_# = constant auf allen
+Schlüsselteilen < N verwenden. In diesem Fall führt MySQL ein einzige
+Schlüsselnachschlagen durch und ersetzt den @code{MIN()}-Ausdruck mit einer
+Konstanten. Wenn alle Ausdrücke durch Konstanten ersetzt sind, gibt die
+Anfrage sofort ein Ergebnis zurück:
+
+@example
+SELECT MIN(schluessel_teil2),MAX(schluessel_teil2) FROM tabelle where schluessel_teil1=10
+@end example
+
+@item
+Eine Tabelle zu sortieren oder zu gruppieren, wenn das Sortieren oder
+Gruppieren mit dem am weitesten links stehenden Präfix eines benutzbaren
+Schlüssels durchgeführt wird (zum Beispiel @code{ORDER BY
+schluessel_teil_1,schluessel_teil_2}). Der Schlüssel wird in umgekehrter
+Reihenfolge gelesen, wenn allen Schlüsselteilen @code{DESC} folgt.
+
+Der Index kann auch benutzt werden, selbst wenn @code{ORDER BY} nicht exakt
+mit dem Index übereinstimmt, solange alle unbenutzten Indexteile und alle
+zusätzlichen @code{ORDER BY}-Spalten Konstanten in der @code{WHERE}-Klausel
+sind. Folgende Anfragen werden einen Index benutzen, um den @code{ORDER
+BY}-Teil aufzulösen:
+
+@example
+SELECT * FROM foo ORDER BY schluessel_teil1,schluessel_teil2,schluessel_teil3;
+SELECT * FROM foo WHERE spalte=konstante ORDER BY spalte, schluessel_teil1;
+SELECT * FROM foo WHERE schluessel_teil1=konstante GROUP BY schluessel_teil2;
+@end example
+
+@item
+In einigen Fällen kann eine Anfrage so optimiert werden, dass Sie Werte
+abruft, ohne in der Daten-Datei nachzuschlagen. Wenn alle benutzten Spalten
+einer Tabelle numerisch sind und ein ganz links stehendes Präfix für einen
+Schlüssel ergeben, können die Werte mit größerer Geschwindigkeit aus dem
+Index-Baum abgerufen werden:
+
+@example
+SELECT schluessel_teil3 FROM tabelle WHERE schluessel_teil1=1
+@end example
+
+@end itemize
+
+Angenommen, Sie führen folgendes @code{SELECT}-Statement aus:
+
+@example
+mysql> SELECT * FROM tabelle WHERE spalte1=val1 AND spalte2=val2;
+@end example
+
+Wenn es einen mehrspaltigen Index auf @code{spalte1} und @code{spalte2}
+gibt, können die entsprechenden Zeilen direkt geholt werden. Wenn es
+separate einspaltige Indexe auf @code{spalte1} und @code{spalte2} gibt,
+versucht der Optimierer, den restriktivsten Index zu finden, indem er
+entscheidet, welcher Index weniger Zeilen finden wird, und diesen Index
+dann benutzen, um Zeilen abzurufen.
+
+@cindex Indexe, ganz links stehendes Präfix von
+@cindex ganz links stehendes Präfix von Indexen
+Wenn die Tabelle einen mehrspaltigen Index hat, kann jedes Präfix auf der
+linken Seite vom Optimierer verwendet werden, um Zeilen zu finden. Wenn Sie
+zum Beispiel einen dreispaltigen Index auf @code{(spalte1,spalte2,spalte3)}
+haben, haben Sie Suchmöglichkeiten auf @code{(spalte1)},
+@code{(spalte1,spalte2)} und @code{(spalte1,spalte2,spalte3)} indiziert.
+
+MySQL kann keinen teilweisen Index verwenden, wenn die Spalten kein ganz
+linkes Präfix des Indexes bilden. Angenommen, Sie haben folgende
+@code{SELECT}-Statements:
+
+@example
+mysql> SELECT * FROM tabelle WHERE spalte1=wert1;
+mysql> SELECT * FROM tabelle WHERE spalte2=wert2;
+mysql> SELECT * FROM tabelle WHERE spalte2=wert2 AND spalte3=wert3;
+@end example
+
+Wenn es einen Index auf @code{(spalte1,spalte2,spalte3)} gibt, benutzt nur die
+erste der drei Anfragen den Index. Die zweite und dritte Anfrage umfassen
+indizierte Spalten, aber @code{(spalte2)} und @code{(spalte2,spalte3)} sind
+nicht die ganz linken Präfixe von @code{(spalte1,spalte2,spalte3)}.
+
+@findex LIKE und Indexe
+@findex LIKE und Platzhalter
+@cindex Indexe und @code{LIKE}
+@cindex Platzhalter und @code{LIKE}
+MySQL benutzt Indexe auch für @code{LIKE}-Vergleiche, wenn das Argument für
+@code{LIKE} eine Zeichenketten-Konstante ist, die nicht mit einem
+Platzhalterzeichen anfängt. Die folgenden @code{SELECT}-Statements zum
+Beispiel benutzen Indexe:
+
+@example
+mysql> select * from tabelle where schluessel_spalte LIKE "Patrick%";
+mysql> select * from tabelle where schluessel_spalte LIKE "Pat%_ck%";
+@end example
+
+Im ersten Statement werden nur Zeilen mit @code{"Patrick" <=
+schluessel_spalte < "Patricl"} berücksichtigt. Im zweiten Statement werden
+nur Zeilen mit @code{"Pat" <= schluessel_spalte < "Pau"} berücksichtigt.
+
+Die folgenden @code{SELECT}-Statements benutzen keine Indexe:
+@example
+mysql> select * from tabelle where schluessel_spalte LIKE "%Patrick%";
+mysql> select * from tabelle where schluessel_spalte LIKE andere_spalte;
+@end example
+
+Im ersten Statement fängt der @code{LIKE}-Wert mit einem Platzhalterzeichen
+an. Im zweiten Statement ist der @code{LIKE}-Wert keine Konstante.
+
+@findex @code{IS NULL} und Indexe
+@cindex Indexe und @code{IS NULL}
+Suchen mit @code{spalte IS NULL} benutzt Indexe, wenn spalte ein Index ist.
+
+MySQL benutzt normalerweise den Index, der die geringste Anzahl von Zeilen
+findet. Ein Index wird benutzt für Spalten, die Sie mit folgenden
+Operatoren vergleichen: @code{=}, @code{>}, @code{>=}, @code{<}, @code{<=},
+@code{BETWEEN} und einem @code{LIKE} ohne Platzhalter-Präfix wie
+@code{'etwas%'}.
+
+Jeder Index, der nicht alle @code{AND}-Ebenen in der @code{WHERE}-Klausel
+umfasst, wird nicht benutzt, um die Anfrage zu optimieren. Mit anderen
+Worte: Um einen Index benutzen zu können, muss ein Präfix des Indexes in
+jeder @code{AND}-Gruppe benutzt werden.
+
+Die folgenden @code{WHERE}-Klauseln benutzen Indexe:
+@example
+... WHERE index_teil1=1 AND index_teil2=2 AND andere_spalte=3
+... WHERE index=1 OR A=10 AND index=2 /* index = 1 OR index = 2 */
+... WHERE index_teil1='hello' AND index_teil_3=5
+ /* optimiert "index_teil1='hello'" */
+... WHERE index1=1 AND index2=2 OR index1=3 AND index3=3;
+ /* kann den Index auf index1 benutzen, aber nicht auf index2 oder index 3 */
+@end example
+
+Die folgenden @code{WHERE}-Klauseln benutzen @strong{KEINE} Indexe:
+@example
+... WHERE index_teil2=1 AND index_teil3=2 /* index_teil_1 wird nicht benutzt */
+... WHERE index=1 OR A=10 /* Index wird nicht in beiden AND-Teilen benutzt */
+... WHERE index_teil1=1 OR index_teil2=10 /* Kein Index umfasst alle Zeilen */
+@end example
+
+Beachten Sie, dass MySQL in manchen Fällen keinen Index benutzt, selbst
+wenn einer verfügbar wäre. Einige solcher Fälle sind hier aufgeführt:
+
+@itemize @bullet
+@item
+Wenn die Benutzung des Indexes erfordern würde, dass MySQL auf mehr als 30%
+der Zeilen in der Tabelle zugreift. (In diesem Fall ist ein Tabellenscan
+wahrscheinlich viel schneller, weil dieser weniger Festplattenzugriffe
+braucht.) Beachten Sie, dass MySQL den Index dennoch benutzt, wenn eine
+Anfrage @code{LIMIT} benutzt, um nur ein paar Zeilen abzufragen, weil er
+dann schneller die wenigen Zeilen im Ergebnis finden kann.
+@end itemize
+
+
+
+
+@node Indexes, Multiple-column indexes, MySQL indexes, Optimising Database Structure
+@c German node Indexe
+@subsection Spalten-Indexe
+
+@cindex Indexe, Spalten
+@cindex Spalten, Indexe
+@cindex Schlüssel
+
+Alle MySQL-Spaltentypen können indiziert werden. Die Benutzung von Indexen
+auf den relevanten Spalten ist die beste Art, die Performance von
+@code{SELECT}-Operationen zu verbessern.
+
+Die maximale Anzahl von Schlüsseln und die maximale Index-Länge ist durch
+den Tabellen-Handler vorgegeben. @xref{Table types}. Bei allen
+Tabellen-Handlern können Sie zumindest 16 Schlüssel und eine
+Gesamtindexlänge von zumindest 256 Bytes haben.
+
+Bei @code{CHAR}- und @code{VARCHAR}-Spalten können Sie ein Präfix einer
+Spalte indexieren. Das ist viel schneller und erfordert weniger
+Plattenspeicher als das Indexieren einer ganzen Spalte. Die Syntax, die im
+@code{CREATE TABLE}-Statement benutzt wird, um ein Spaltenpräfix zu
+indexieren, sieht wie folgt aus:
+
+@example
+KEY index_name (spalten_name(laenge))
+@end example
+
+Das unten stehende Beispiel erzeugt einen Index auf die ersten 10 Zeichen
+der @code{name}-Spalte:
+
+@example
+mysql> CREATE TABLE test (
+ name CHAR(200) NOT NULL,
+ KEY index_name (name(10)));
+@end example
+
+Bei @code{BLOB}- und @code{TEXT}-Spalten müssen Sie ein Präfix der Spalte
+indexieren. Sie können nicht die gesamte Spalte indexieren.
+
+Ab MySQL-Version 3.23.23 können Sie auch spezielle @strong{FULLTEXT}-Indexe
+erzeugen. Sie werden für die Volltextsuche benutzt. Nur der
+@code{MyISAM}-Tabellentyp unterstützt @code{FULLTEXT}-Indexe. Sie können
+nur auf @code{VARCHAR}- und @code{TEXT}-Spalten erzeugt werden. Die
+Indexierung erfolgt immer über die gesamte Spalte; teilweises Indexieren
+wird nicht unterstützt. Siehe @ref{Fulltext Search} für Details.
+
+@node Multiple-column indexes, Open tables, Indexes, Optimising Database Structure
+@c German node Mehrspaltige Indexe
+@subsection Mehrspaltige Indexe
+
+@cindex mehrspaltige Indexe
+@cindex Indexe, mehrspaltige
+@cindex Schlüssel, mehrspaltige
+
+MySQL kann Indexe auf mehrfache Spalten erzeugen. Ein Index darf aus bis zu
+15 Spalten bestehen. (Auf @code{CHAR}- und @code{VARCHAR}-Spalten können
+Sie auch ein Präfix der Spalte als Teil eines Indexes benutzen).
+
+Ein mehrspaltiger Index kann als sortiertes Array betrachtet werden, das
+Werte enthält, die durch die Verkettung der Werte der indizierten Spalten
+erzeugt werden.
+
+MySQL benutzt mehrspaltige Indexe in einer Art, dass Anfragen schnell
+werden, wenn Sie eine bekannte Menge für die erste Spalte des Indexes in
+einer @code{WHERE}-Klausel angeben, selbst wenn Sie keine Werte für die
+anderen Spalten angeben.
+
+Angenommen, einen Tabelle wurde wie folgt erzeugt:
+
+@example
+mysql> CREATE TABLE test (
+ id INT NOT NULL,
+ nachname CHAR(30) NOT NULL,
+ vorname CHAR(30) NOT NULL,
+ PRIMARY KEY (id),
+ INDEX name (nachname,vorname));
+@end example
+
+Dann ist der Index @code{name} ein Index über @code{nachname} und
+@code{vorname}. Der Index wird für Anfragen benutzt, die Werte in einem
+bekannten Bereich für @code{nachname} angeben, oder sowohl für
+@code{nachname} als auch für und @code{vorname}.
+Daher wird der @code{name}-Index in folgenden Anfragen benutzt:
+
+@example
+mysql> SELECT * FROM test WHERE nachname="Widenius";
+
+mysql> SELECT * FROM test WHERE nachname="Widenius"
+ AND vorname="Michael";
+
+mysql> SELECT * FROM test WHERE nachname="Widenius"
+ AND (vorname="Michael" OR vorname="Monty");
+
+mysql> SELECT * FROM test WHERE nachname="Widenius"
+ AND vorname >="M" AND vorname < "N";
+@end example
+
+In folgenden Anfragen wird der @code{name}-Index jedoch NICHT benutzt:
+
+@example
+mysql> SELECT * FROM test WHERE vorname="Michael";
+
+mysql> SELECT * FROM test WHERE nachname="Widenius"
+ OR vorname="Michael";
+@end example
+
+Weitere Informationen über die Art, wie MySQL Indexe benutzt, um die
+Anfragen-Performance zu verbessern, finden Sie unter @ref{MySQL indexes, ,
+MySQL-Indexe}.
+
+
+@node Open tables, Table cache, Multiple-column indexes, Optimising Database Structure
+@c German node Tabellen-Cache
+@subsection Wie MySQL Tabellen öffnet und schließt
+
+@findex table_cache
+
+@cindex Tabellen, öffnen
+@cindex Tabellen, schließen
+@cindex öffnen, Tabellen
+@cindex schließen, Tabellen
+@cindex Tabellen-Cache
+
+@code{table_cache}, @code{max_connections} und @code{max_tmp_tables}
+beeinflussen die maximale Anzahl von Dateien, die der Server offen halten
+kann. Wenn Sie einen oder mehrere dieser Werte erhöhen, können Sie an eine
+Begrenzung stoßen, die durch Ihr Betriebssystem in Bezug auf die Anzahl
+offener Datei-Deskriptoren pro Prozess festgelegt wird. Diese Begrenzung
+kann man jedoch auf vielen Systemen erhöhen. Sehen Sie im Handbuch Ihres
+Betriebssystems nach, wie man das macht, weil die Methode, wie die
+Begrenzung geändert wird, sich von System zu System stark unterscheidet.
+
+@code{table_cache} ist verwandt mit @code{max_connections}. Für 200
+gleichzeitig laufende Verbindungen sollten Sie zum Beispiel einen
+Tabellen-Cache von mindestens @code{200 * n} haben, wobei @code{n} die
+maximale Anzahl von Tabellen in einem Join ist. Zusätzlich müssen Sie
+einige externe Datei-Deskriptoren für temporäre Tabellen und Dateien
+reservieren.
+
+Stellen Sie sicher, dass Ihr Betriebssystem die Anzahl offener
+Datei-Deskriptoren handhaben kann, die durch die
+@code{table_cache}-Einstellung impliziert wird. Wenn
+@code{table_cache} zu hoch gesetzt wird, hat MySQL eventuell keine
+Datei-Deskriptoren mehr und verweigert Verbindungen, führt keine Anfragen
+mehr aus und läuft sehr unzuverlässig. Beachten Sie auch, dass der
+MyISAM-Tabellen-Handler zwei Datei-Deskriptoren für jede einzelne offene
+Tabelle benötigt. Sie können die Anzahl von Datei-Deskriptoren, die für
+MySQL verfügbar sind, in der @code{--open-files-limit=#}-Startoption
+angeben. @xref{Not enough file handles}.
+
+Der Cache offener Tabellen kann bis auf @code{table_cache} anwachsen
+(Vorgabewert 64; das kann mit der @code{-O Tabellen-Cache=#}-Option für
+@code{mysqld} geändert werden). Eine Tabelle wird nie geschlossen, ausser
+wen der Cache voll ist und ein anderer Thread versucht, eine Tabelle zu
+öffnen, oder wenn Sie @code{mysqladmin refresh} oder @code{mysqladmin
+flush-tables} benutzen.
+
+Wenn sich der Tabellen-Cache füllt, benutzt der Server folgenden Prozedur,
+um einen Cache-Eintrag für die Benutzung zu finden:
+
+@itemize @bullet
+@item
+Tabellen, die momentan nicht in Benutzung sind, werden freigegeben, in der
+Reihenfolge der kürzlich am wenigsten benutzten Tabellen.
+
+@item
+Wenn der Cache voll ist und keine Tabellen freigegeben werden können, aber
+eine neue Tabelle geöffnet werden muss, wird der Cache temporär wie
+benötigt vergrößert.
+
+@item
+Wenn der Cache gerade im Zustand temporärer Erweiterung ist und eine
+Tabelle vom Zustand benutzt in den Zustand nicht benutzt wechselt, wird die
+Tabelle geschlossen und vom Cache freigesetzt.
+@end itemize
+
+Eine Tabelle wird für jeden gleichzeitigen Zugriff geöffnet. Das bedeutet,
+dass die Tabelle zweimal geöffnet werden muss, wenn Sie zwei Threads haben,
+die auf dieselbe Tabelle zugreifen oder einen Thread, der auf die Tabelle
+zweimal in derselben Anfrage zugreift (mit @code{AS}). Das erste öffnen
+jeder Tabelle benötigt nur einen Datei-Deskriptor. Der zusätzliche
+Deskriptor wird für die Index-Datei benötigt; dieser Deskriptor wird
+mit allen Threads geteilt (shared).
+
+Wenn Sie eine Tabelle mit dem @code{HANDLER tabelle OPEN}-Statement öffnen,
+wird dem Thread ein dediziertes Tabellenobjekt zugewiesen. Diese
+Tabellenobjekt wird nicht mit anderen Threads geteilt und wird solange
+nicht geschlossen, bis der Thread @code{HANDLER tabelle CLOSE} aufruft oder
+stirbt.
+@xref{INSERT}.
+
+Sie können prüfen, ob Ihr Tabellen-Cache zu klein ist, indem Sie die
+mysqld-Variable @code{opened_tables} ansehen. Wenn diese recht Groß ist,
+selbst wenn Sie nicht viele @code{FLUSH TABLES} ausgeführt haben, sollten
+Sie Ihren Tabellen-Cache vergrößern. @xref{SHOW STATUS}.
+
+
+@node Table cache, Creating many tables, Open tables, Optimising Database Structure
+@c German node Viele Tabellen erzeugen
+@subsection Nachteile der Erzeugung großer Mengen von Tabellen in derselben Datenbank
+
+@cindex Tabellen, zu viele
+
+Wenn Sie viele Dateien in einem Verzeichnis haben, werden open-, close- und
+create-Operationen langsam. Wenn Sie ein @code{SELECT}-Statements auf viele
+unterschiedliche Tabellen ausführen, gibt es ein bisschen Overhead, wenn
+der Tabellen-Cache voll ist, weil für jede Tabelle, die geöffnet wird, eine
+andere geschlossen werden muss. Sie können diese Overhead verringern, indem
+Sie den Tabellen-Cache größer machen.
+
+
+@node Creating many tables, , Table cache, Optimising Database Structure
+@c German node Offene Tabellen
+@subsection Warum gibt es so viele offene Tabellen?
+
+@cindex Tabellen, offene
+@cindex offene Tabellen
+
+Wenn Sie @code{mysqladmin status} ausführen, werden Sie etwa folgendes
+sehen:
+
+@example
+Uptime: 426 Running Threads: 1 Questions: 11082 Reloads: 1 Open Tables: 12
+@end example
+
+Das kann etwas verwirrend sein, wenn Sie nur 6 Tabellen haben.
+
+MySQL ist multi-threaded, daher kann er viele Anfragen auf dieselbe Tabelle
+simultan verarbeiten. Um das Problem zu minimieren, dass zwei Threads
+verschiedene Zustände in Bezug auf dieselbe Datei haben, wird die Tabelle
+unabhängig für jeden gleichzeitigen Thread geöffnet. Das benötigt etwas
+Arbeitsspeicher und einen externen Datei-Deskriptor für die Daten-Datei.
+Der Index-Datei-Deskriptor wird mit allen Threads geteilt.
+
+
+@node Optimising the Server, Disk issues, Optimising Database Structure, MySQL Optimisation
+@c German node Optimierung des Servers
+@section Optimierung des MySQL-Servers
+
+
+
+
+@menu
+* System::
+* Server parameters::
+* Compile and link options::
+* Memory use::
+* DNS::
+* SET OPTION::
+@end menu
+
+@node System, Server parameters, Optimising the Server, Optimising the Server
+@c German node System
+@subsection System / Kompilierzeitpunkt und Tuning der Startparameter
+
+@cindex Kompilieren, Optimierung
+@cindex System-Optimierung
+@cindex Startparameter, tunen
+
+Wir fangen mit den Dingen auf Systemebene an, weil einige dieser
+Entscheidungen sehr früh getroffen werden müssen. In anderen Fällen mag ein
+kurzer Blick auf diesen Teil ausreichen, weil er nicht so wichtig für
+große Verbesserungen ist. Es ist jedoch immer nett, ein Gefühl dafür zu
+bekommen, wie viel man gewinnen kann, wenn man Dinge auf dieser Ebene
+ändert.
+
+Es ist wirklich wichtig, dass vorgabemäßige Betriebssystem zu kennen! Um
+das meiste aus Mehrprozessor-Maschinen herauszuholen, sollte man Solaris
+benutzen (weil die Threads wirklich gut funktionieren) oder Linux (weil der
+2.2-Kernel wirklich gute Mehrprozessor-Unterstützung bietet). Linux hat auf
+32-Bit-Maschinen vorgabemäßig eine Dateigrößenbeschränkung von 2 GB. Das
+wird hoffentlich bald behoben, wenn neue Dateisysteme herausgebracht werden
+(XFS/Reiserfs). Wenn Sie dringen Unterstützung für größere Datei als 2 GB
+auf Linux-Intel-32-Bit benötigen, sollten Sie den LFS-Patch für das
+ext2-Dateisystem holen.
+
+Weil wir MySQL noch nicht auf allzu vielen Plattformen in einer
+Produktionsumgebung getestet haben, empfehlen wir, dass Sie Ihre geplante
+Plattform testen, bevor Sie sich dafür entscheiden.
+
+@cindex Sperren
+Weitere Tipps:
+@itemize @bullet
+@item
+Wenn Sie genug Arbeitsspeicher haben, könnten Sie alle Swap-Geräte
+entfernen. Einige Betriebssysteme benutzen in bestimmten Zusammenhängen ein
+Swap-Gerät, selbst wenn Sie freien Arbeitsspeicher haben.
+@item
+Benutzen Sie die @code{--skip-locking}-MySQL-Option, um externe Sperren zu
+vermeiden. Beachten Sie, dass das die Funktionalität von MySQL nicht
+tangiert, solange Sie nur einen Server laufen lassen. Denken Sie lediglich
+daran, den Server herunterzufahren (oder die relevanten Teile zu sperren),
+bevor Sie @code{myisamchk} laufen lassen. Auf manchen Systemen ist diese
+Umschaltung zwingend erforderlich, weil externes Sperren in keinem Fall
+funktioniert.
+
+Die @code{--skip-locking}-Option ist vorgabemäßig angeschaltet, wenn Sie
+mit MIT-pThreads kompilieren, weil @code{flock()} von MIT-pThreads nicht
+vollständig auf allen Plattformen unterstützt wird. Auch für Linux ist es
+vorgabemäßig angeschaltet, weil Linux-Dateisperren bis jetzt nicht
+zuverlässig funktionieren.
+
+Der einzige Fall, wo Sie @code{--skip-locking} nicht benutzen können, sit,
+wenn Sie mehrfache MySQL-@emph{Server} (nicht Clients) auf denselben Daten
+laufen lassen, oder wenn Sie @code{myisamchk} auf eine Tabelle ausführen,
+ohne zuerst die @code{mysqld}-Server-Tabellen auf Platte zurückzuschreiben
+und zu sperren.
+
+Sie können immer noch @code{LOCK TABLES} / @code{UNLOCK TABLES} benutzen,
+selbst wenn Sie @code{--skip-locking} benutzen.
+@end itemize
+
+
+@node Server parameters, Compile and link options, System, Optimising the Server
+@c German node Serverparameter
+@subsection Serverparameter tunen
+
+@cindex Parameter, Server
+@cindex @code{mysqld}-Server, Puffer-Größen
+@cindex Puffer-Größen, @code{mysqld}-Server
+@cindex Startparameter
+
+Sie erhalten die Puffer-Größen, die der @code{mysqld}-Server benutzt, mit
+diesem Befehl:
+
+@example
+shell> mysqld --help
+@end example
+
+@cindex @code{mysqld}-Optionen
+@cindex Variablen, @code{mysqld}
+Dieser Befehl erzeugt eine Auflistung aller @code{mysqld}-Optionen und
+konfigurierbaren Variablen. Die Ausgabe enthält die Vorgabewerte und sieht
+etwa wie folgt aus:
+
+@example
+Possible variables for option --set-variable (-O) are:
+back_log current value: 5
+bdb_cache_size current value: 1048540
+binlog_cache_size current_value: 32768
+connect_timeout current value: 5
+delayed_insert_timeout current value: 300
+delayed_insert_limit current value: 100
+delayed_queue_size current value: 1000
+flush_time current value: 0
+interactive_timeout current value: 28800
+join_buffer_size current value: 131072
+key_buffer_size current value: 1048540
+lower_case_tabelles current value: 0
+long_query_time current value: 10
+max_allowed_packet current value: 1048576
+max_binlog_cache_size current_value: 4294967295
+max_connections current value: 100
+max_connect_errors current value: 10
+max_delayed_threads current value: 20
+max_heap_table_size current value: 16777216
+max_join_size current value: 4294967295
+max_sort_length current value: 1024
+max_tmp_tables current value: 32
+max_write_lock_count current value: 4294967295
+myisam_sort_buffer_size current value: 8388608
+net_buffer_length current value: 16384
+net_retry_count current value: 10
+net_read_timeout current value: 30
+net_write_timeout current value: 60
+query_buffer_size current value: 0
+record_buffer current value: 131072
+record_rnd_buffer current value: 131072
+slow_launch_time current value: 2
+sort_buffer current value: 2097116
+table_cache current value: 64
+thread_concurrency current value: 10
+tmp_table_size current value: 1048576
+thread_stack current value: 131072
+wait_timeout current value: 28800
+@end example
+
+Wenn aktuell ein @code{mysqld}-Server läuft, können Sie feststellen, welche
+Werte er für die Variablen tatsächlich benutzt, wenn Sie diesen Befehl
+ausführen:
+
+@example
+shell> mysqladmin variables
+@end example
+
+Sie finden eine komplette Beschreibung aller Variablen im @code{SHOW
+VARIABLES}-Abschnitt dieses Handbuchs. @xref{SHOW VARIABLES}.
+
+Wenn Sie @code{SHOW STATUS} eingeben, können Sie einige statistische
+Informationen des Servers sehen. @xref{SHOW STATUS}.
+
+MySQL benutzt Algorithmen, die sehr skalierbar sind, daher können Sie
+üblicherweise mit sehr wenig Arbeitsspeicher fahren. Wenn Sie MySQL jedoch
+mehr Speicher geben, erzielen Sie damit normalerweise auch bessere
+Performance.
+
+Wenn Sie einen MySQL-Server tunen, sind die zwei wichtigsten Variablen
+@code{key_buffer_size} und @code{table_cache}. Sie sollten zunächst sicher
+sein, dass diese beiden richtig gesetzt sind, bevor Sie versuchen, irgend
+eine der anderen Variablen zu ändern.
+
+Wenn Sie viel Arbeitsspeicher haben (>= 256 MB) und viele Tabellen und
+maximale Performance bei einer mäßigen Anzahl von Clients haben wollen,
+sollten Sie etwas wie das Folgende benutzen:
+
+@example
+shell> safe_mysqld -O key_buffer=64M -O table_cache=256 \
+ -O sort_buffer=4M -O record_buffer=1M &
+@end example
+
+Wenn Sie nur 128 MB und nur wenige Tabellen haben, aber viele
+Sortiervorgänge durchführen, können Sie etwas wie das Folgende benutzen:
+
+@example
+shell> safe_mysqld -O key_buffer=16M -O sort_buffer=1M
+@end example
+
+Wenn Sie wenig Arbeitsspeicher und viele Verbindungen haben, können Sie
+etwas wie das Folgende benutzen:
+
+@example
+shell> safe_mysqld -O key_buffer=512k -O sort_buffer=100k \
+ -O record_buffer=100k &
+@end example
+
+Oder sogar:
+
+@example
+shell> safe_mysqld -O key_buffer=512k -O sort_buffer=16k \
+ -O table_cache=32 -O record_buffer=8k -O net_buffer=1K &
+@end example
+
+Wenn Sie @code{GROUP BY} oder @code{ORDER BY} auf Dateien anwenden, die
+größer als Ihr verfügbarer Arbeitsspeicher sind, sollten Sie den Wert von
+@code{record_rnd_buffer} heraufsetzen, um das Lesen von Zeilen nach
+Sortiervorgängen zu beschleunigen.
+
+Wenn Sie MySQL installiert haben, enthält das
+@file{Support-files}-Verzeichnis einige unterschiedliche
+@code{my.cnf}-Beispiel-Dateien: @file{my-huge.cnf}, @file{my-large.cnf},
+@file{my-medium.cnf} und @file{my-small.cnf}. Diese können Sie als
+Grundlage nehmen, um Ihr System zu optimieren.
+
+Wenn es sehr viele Verbindungen gibt, können ``Swapping-Probleme''
+auftauchen, wen Sie @code{mysqld} nicht so konfiguriert haben, dass er für
+jede Verbindung sehr wenig Speicher benutzt. @code{mysqld} bringt natürlich
+bessere Leistungsdaten, wenn Sie genug Speicher für alle Verbindungen
+haben.
+
+Beachten Sie, dass Änderungen einer Option für @code{mysqld} sich nur auf
+diese Instanz des Servers auswirken.
+
+Um die Auswirkung einer Parameteränderung zu sehen, geben Sie folgendes
+ein:
+
+@example
+shell> mysqld -O key_buffer=32m --help
+@end example
+
+Stellen Sie sicher, dass die @code{--help}-Option zuletzt kommt, ansonsten
+wird die Auswirkung jeglicher Optionen, die danach auf der Kommandozeile
+kommen, in der Ausgabe nicht gezeigt.
+output.
+
+
+@node Compile and link options, Memory use, Server parameters, Optimising the Server
+@c German node Kompilier- und Link-Optionen
+@subsection Wie Kompilieren und Linken die Geschwindigkeit von MySQL beeinflusst
+
+@cindex Linken, Geschwindigkeit
+@cindex Kompilieren, Geschwindigkeit
+@cindex Geschwindigkeit, Kompilieren
+@cindex Geschwindigkeit, Linken
+
+Die meisten der folgenden Tests wurden mit den MySQL-Benchmarks unter Linux
+durchgeführt, aber sie sollten einen guten Anhaltspunkt für andere
+Betriebssysteme und Auslastungen geben.
+
+Sie erhalten die schnellste ausführbare Datei, wenn Sie mit @code{-static}
+linken.
+
+Unter Linux erhalten Sie den schnellsten Code, wenn Sie mit @code{pgcc} und
+@code{-O3} kompilieren. Um @file{sql_yacc.cc} mit diesen Optionen zu
+kompilieren, brauchen Sie etwa 200 MB Arbeitsspeicher, weil @code{gcc/pgcc}
+viel Speicher benötigt, um alle Funktionen inline zu machen. Sie sollten
+beim Konfigurieren von MySQL auch @code{CXX=gcc} setzen, um das
+Einschließen der @code{libstdc++}-Bibliothek zu vermeiden (die nicht
+benötigt wird). Beachten Sie, dass bei einigen Version von @code{pgcc} der
+erzeugte Code nur auf echten Pentium-Prozessoren läuft, selbst wenn Sie in
+den Compiler-Optionen angeben, dass Sie wollen, dass der Code auf alle
+Prozessoren vom Typ x586 läuft (wie AMD).
+
+Einfach durch die Benutzung eines besseren Compilers und / oder besserer
+Compiler-Optionen können Sie eine 10-30%-ige Geschwindigkeitssteigerung in
+Ihrer Applikation erhalten. Das ist besonders wichtig, wenn Sie den
+SQL-Server selbst kompilieren!
+
+Wir haben sowohl Cygnus CodeFusion als auch Fujitsu-Compiler getestet, aber
+es stellte sich heraus, dass keiner von beiden ausreichend Bug-frei war,
+damit MySQL mit angeschalteten Optimierungen kompiliert werden konnte.
+
+Wenn Sie MySQL kompilieren, sollten Sie nur Unterstützung für die
+Zeichensätze einschließen, die Sie benutzen werden (Option
+@code{--with-charset=xxx}). Die Standard-MySQL-Binärdistributionen werden
+mit Unterstützung für alle Zeichensätze kompiliert.
+
+Hier ist eine Auflistung einiger Messungen, die wir durchgeführt haben:
+@itemize @bullet
+@item
+Wenn Sie @code{pgcc} benutzen und alles mit @code{-O6} kompilieren, ist der
+@code{mysqld}-Server 1% schneller als mit @code{gcc} 2.95.2.
+
+@item
+Wenn Sie dynamisch linken (ohne @code{-static}), ist das Ergebnis unter
+Linux 13% langsamer. Beachten Sie, dass Sie dennoch dynamisch gelinkte
+MySQL-Bibliotheken benutzen können. Nur beim Server ist das kritisch in
+Bezug auf Performance.
+
+@item
+Wenn Sie Ihre @code{mysqld}-Binärdatei mit @code{strip libexec/mysqld}
+strippen, ist die resultierende Binärdatei bis zu 4% schneller.
+
+@item
+Wenn Sie sich über TCP/IP statt über Unix-Sockets verbinden, ist das auf
+demselben Computer 7,5% langsamer. (Wenn Sie sich zu @code{localhost}
+verbinden, benutzt MySQL vorgabemäßig Sockets.)
+
+@item
+Wenn Sie sich über TCP/IP von einem anderen Computer über ein
+100-MBit-Ethernet verbinden, ist das 8% bis 11% langsamer.
+
+@item
+Wenn Sie mit @code{--with-debug=full} kompilieren, verlangsamen sich die
+meisten Anfragen um 20%, manche Anfragen jedoch werden wesentlich langsamer
+(der MySQL-Benchmarks zeigte 35%). Wenn Sie @code{--with-debug} benutzen,
+beträgt die Verlangsamung nur 15%. Wenn Sie eine @code{mysqld}-Version, die
+mit @code{--with-debug=full} kompiliert wurde, mit @code{--skip-safemalloc}
+starten, ist die Geschwindigkeit etwa dasselbe, als wenn Sie mit
+@code{--with-debug} konfigurieren.
+
+@item
+Auf einer Sun SPARCstation 20 ist SunPro C++ 4.2 5% schneller als
+@code{gcc} 2.95.2.
+
+@item
+Das Kompilieren mit @code{gcc} 2.95.2 für ultrasparc mit der Option
+@code{-mcpu=v8 -Wa,-xarch=v8plusa} ergibt 4% mehr Performance.
+
+@item
+Auf Solaris 2.5.1 sind MIT-pThreads 8% bis 12% langsamer als Solaris-native
+Threads, auf einem Einprozessorsystem. Bei mehr Last / Prozessoren sollte
+der Unterschied größer werden.
+
+@item
+Laufenlassen mit @code{--log-bin} macht @strong{MySQL} 1% langsamer.
+
+@item
+Wenn beim Kompilieren unter Linux-x86 mit gcc keine Frame-Pointers
+@code{-fomit-frame-pointer} oder @code{-fomit-frame-pointer -ffixed-ebp}
+verwendet werden, ist @code{mysqld} 1% bis 4% schneller.
+@end itemize
+
+Die MySQL-Linux-Distribution, die von MySQL AB zur Verfügung gestellt wird,
+wurde früher mit @code{pgcc} kompiliert, aber wir mussten zum normalen gcc
+zurück gehen, weil es einen Bug in @code{pgcc} gibt, der Code erzeugt, der
+nicht auf AMD läuft. Wir werden gcc solange benutzen, bis dieser Bug
+behoben ist. Bis dahin können Sie, falls Sie keine AMD-Maschine haben, eine
+schnellere Binärdatei erhalten, wenn Sie mit @code{pgcc} kompilieren. Die
+Standard-MySQL-Linux-Binärdatei wird statisch gelinkt, um sie schneller und
+portierbarer zu machen.
+
+
+@node Memory use, DNS, Compile and link options, Optimising the Server
+@c German node Speicherbenutzung
+@subsection Wie MySQL Speicher benutzt
+
+@cindex Speicherbenutzung
+
+Die unten stehende Liste zeigt einige Möglichkeiten, wie der
+@code{mysqld}-Server Speicher benutzt. Wo es zutrifft, wird der Name der
+für die Speicherbenutzung relevanten Servervariablen angegeben.
+
+@itemize @bullet
+@item
+Der Schlüssel-Puffer (Variable @code{key_buffer_size}) wird von allen
+Threads geteilt. Andere Puffer, die vom Server benutzt werden, werden bei
+Bedarf zugewiesen. @xref{Server parameters}.
+
+@item
+Jede Verbindung benutzt etwas Thread-spezifischen Platz: Einen Stack
+(Vorgabe 64 KB, Variable @code{thread_stack}), einen Verbindungspuffer
+(Variable @code{net_buffer_length}) und a Ergebnispuffer (Variable
+@code{net_buffer_length}). Die Verbindungspuffer und Ergebnispuffer werden
+bei Bedarf dynamisch bis zu @code{max_allowed_packet} vergrößert. Wenn
+eine Anfrage läuft, wird auch eine Kopie der aktuellen Anfragezeichenkette
+zugewiesen.
+
+@item
+Alle Threads teilen sich denselben grundlegenden Speicher.
+
+@item
+Nur die komprimierten ISAM- / MyISAM-Tabellen werden Speicher-gemappt. Das
+liegt daran, dass der 32-Bit-Adressraum von 4 GB für die meisten großen
+Tabellen nicht Groß genug ist. Wenn Systeme mit 64-Bit-Adressraum
+gebräuchlicher werden, werden wir vielleicht eine allgemeine Unterstützung
+für Speicher-Mapping hinzufügen.
+
+@item
+Jeder Anfrage, die einen sequentiellen Scan über eine Tabelle durchführt,
+wird ein Lesepuffer zugewiesen (Variable @code{record_buffer}).
+
+@item
+Wenn Zeilen in 'zufälliger' Reihenfolge gelesen werden (zum Beispiel nach
+einem Sortiervorgang), wird ein Zufalls-Lesepuffer zugewiesen, um
+Suchvorgänge auf Festplatte zu vermeiden. (Variable @code{record_rnd_buffer}).
+
+@item
+Alle Joins werden in einem Durchgang durchgeführt und die meisten Joins
+können sogar ohne Benutzung einer temporären Tabelle durchgeführt werden.
+Die meisten temporären Tabellen sind Speicher-basierende (HEAP-) Tabellen.
+Temporäre Tabellen mit großer Datensatzlänge (berechnet als Summe aller
+Spaltenlängen) oder die @code{BLOB}-Spalten enthalten, werden auf
+Festplatte gespeichert.
+
+Ein Problem in MySQL-Versionen vor Version 3.23.2 ist, dass Sie den Fehler
+@code{The table tabelle is full} erhalten, wenn die Größe der HEAP-Tabelle
+@code{tmp_table_size} überschreitet. In neueren Versionen wird dies so
+gehandhabt, dass die Speicher-basierende (HEAP-) Tabelle bei Bedarf
+automatisch in eine Festplatten-basierende Tabelle (MyISAM) umgewandelt
+wird. Um das Problem zu umgehen, können Sie die Größe von temporären
+Tabellen durch Setzen der @code{tmp_table_size}-Option für @code{mysqld}
+ändern, oder durch Setzen der SQL-Option @code{SQL_BIG_TABLES} im
+Client-Programm. @xref{SET OPTION, , @code{SET OPTION}}. In MySQL-Version
+3.20 war die maximale Größe der temporären Tabelle
+@code{record_buffer*16}. Wenn Sie also diese Version benutzen, müssen Sie
+den Wert von @code{record_buffer} herauf setzen. Sie können @code{mysqld}
+auch mit der @code{--big-tables}-Option starten, um temporäre Tabellen
+immer auf Festplatte zu speichern. Das wird jedoch die Geschwindigkeit
+vieler komplizierter Anfragen beeinflussen.
+
+@item
+Den meisten Sortier-Anfragen werden ein Sortierpuffer und 0 bis 2 temporäre
+Dateien zugewiesen, abhängig von der Größe der Ergebnismenge.
+@xref{Temporary files}.
+
+@item
+Fast alles Parsen und Berechnen wird in einem lokalen Speicherbereich
+durchgeführt. Für kleine Sachen wird kein Speicher-Overhead benötigt, und
+das normale, langsame Zuweisen und Freimachen von Speicher wird vermieden.
+Speicher wird nur für unerwartet lange Zeichenketten zugewiesen (das wird
+mit @code{malloc()} und @code{free()} gemacht).
+
+@item
+Jede Index-Datei wird einmal geöffnet. Die Daten-Datei wird einmal für
+jeden gleichzeitig laufenden Thread geöffnet. Für jeden gleichzeitigen
+Thread wird eine Tabellenstruktur, Spaltenstrukturen für jede Spalte und
+ein Puffer der Größe @code{3 * n} zugewiesen, wobei @code{n} die maximale
+Zeilenlänge ist (@code{BLOB}-Spalten werden nicht mitgerechnet). Eine
+@code{BLOB}-Spalte benutzt 5 bis 8 Bytes plus die Länge der
+@code{BLOB}-Daten. Der @code{ISAM}- / @code{MyISAM}-Tabellen-Handler
+benutzt einen zusätzlichen Zeilenpuffer für internen Gebrauch.
+
+@item
+Bei jeder Tabelle, die @code{BLOB}-Spalten enthält, wird ein Puffer
+dynamisch vergrößert, um größere @code{BLOB}-Werte einzulesen. Wenn Sie
+eine Tabelle scannen, wird ein Puffer so Groß wie der größte
+@code{BLOB}-Wert zugewiesen.
+
+@item
+Tabellen-Handler für alle Tabellen in Benutzung werden in einem Cache
+gespeichert und als FIFO verwaltet. Normalerweise hat der Cache 64
+Einträge. Wenn eine Tabelle gleichzeitig von zwei laufenden Threads
+benutzt wurde, enthält der Cache zwei Einträge für die Tabelle.
+@xref{Open tables}.
+
+@item
+Ein @code{mysqladmin flush-tables}-Befehl schließt alle Tabellen, die
+nicht in Benutzung sind, und kennzeichnet alle Tabellen in Benutzung als zu
+schließen, sobald der aktuell ausführende Thread fertig ist. Das setzt
+effektiv den meisten benutzten Speicher frei.
+@end itemize
+
+@code{ps} und andere System-Status-Programme berichten vielleicht, dass
+@code{mysqld} viel Arbeitsspeicher benutzt. Das kann durch Thread-Stacks
+auf verschiedenen Speicheradressen verursacht werden. @code{ps} der
+Solaris-Version zum Beispiel zählt den unbenutzten Speicher zwischen Stacks
+zum benutzten Speicher hinzu. Das können Sie bestätigen, wenn Sie den
+verfügbaren Swap mit @code{swap -s} überprüfen. Wir haben @code{mysqld} mit
+kommerziellen Memory-Leak-Detektoren getestet, daher sollte es keine
+Memory-Leaks geben.
+
+
+@node DNS, SET OPTION, Memory use, Optimising the Server
+@c German node DNS
+@subsection Wie MySQL DNS benutzt
+
+@cindex DNS
+@cindex Caching von Hostnamen
+
+Wenn sich ein neuer Thread mit @code{mysqld} verbindet, erzeugt
+@code{mysqld} einen neuen Thread, um die Anfrage zu handhaben. Dieser
+Thread prüft zuerst, ob der Hostname im Hostnamen-Cache ist. Falls nicht,
+ruft der Thread @code{gethostbyaddr_r()} und @code{gethostbyname_r()} auf,
+um den Hostname aufzulösen.
+
+Wenn das Betriebssystem die oben genannten Thread-sicheren Aufrufe nicht
+unterstützt, sperrt der Thread ein Mutex und ruft statt dessen
+@code{gethostbyaddr()} und @code{gethostbyname()} auf. Beachten Sie, dass
+in diesem Fall kein anderer Thread andere Hostnamen auflösen kann, die
+nicht im Hostnamen-Cache sind, bis der erste Thread fertig ist.
+
+Sie können das DNS-Nachschlagen von Hostnamen (DNS-Lookup) abschalten,
+indem Sie @code{mysqld} mit @code{--skip-name-resolve} starten. In diesem
+Fall können Sie jedoch in den MySQL-Berechtigungstabellen nur IP-Nummern
+verwenden.
+
+Wenn Sie ein sehr langsames DNS und viele Hosts haben, können Sie mehr
+Performance erzielen, wenn Sie entweder das DNS-Nachschlagen von Hostnamen
+(DNS-Lookup) abschalten (mit @code{--skip-name-resolve}) oder
+@code{HOST_CACHE_SIZE} (Vorgabe: 128) erhöhen und @code{mysqld}
+neu kompilieren.
+
+Sie können den Hostnamen-Cache mit @code{--skip-host-cache} abschalten. Sie
+können den Hostnamen-Cache mit @code{FLUSH HOSTS} oder @code{mysqladmin
+flush-hosts} löschen.
+
+Wenn Sie keine Verbindungen über @code{TCP/IP} zulassen wollen, starten Sie
+@code{mysqld} mit @code{--skip-networking}.
+
+
+@node SET OPTION, , DNS, Optimising the Server
+@c German node SET OPTION
+@subsection @code{SET}-Syntax
+
+@findex SET OPTION
+
+@example
+SET [OPTION] SQL_VALUE_OPTION= wert, ...
+@end example
+
+@code{SET OPTION} setzt verschiedene Optionen, die die Arbeitsweise des
+Servers oder Ihrer Clients beeinflussen. Jede Option, die Sie setzen,
+bleibt in Kraft, bis die aktuelle Sitzung beendet wird, oder bis Sie die
+Option auf einen anderen Wert setzen.
+
+@table @code
+@item characterset zeichensatz_name | DEFAULT
+Das mappt alle Zeichenketten von und zum Client auf das angegebene Mapping.
+Momentan ist die einzige Option für @code{zeichensatz_name}
+@code{cp1251_koi8}, aber Sie können leicht neue Mappings hinzufügen, indem
+Sie die @file{sql/convert.cc}-Datei in der MySQL-Quelldistribution
+editieren. Das vorgabemäßige Mapping kann durch Setzen des
+@code{zeichensatz_name}-Werts auf @code{DEFAULT} wieder hergestellt
+werden.
+
+Beachten Sie, dass sich die Syntax für das Setzen der
+@code{characterset}-Option von der Syntax für das Setzen anderer Optionen
+unterscheidet.
+
+@item PASSWORD = PASSWORD('ein_passwort')
+@cindex Passwörter, setzen
+Setzt das Passwort für den aktuellen Benutzer. Jeder nicht anonyme Benutzer
+kann sein eigenes Passwort ändern!
+
+@item PASSWORD FOR benutzer = PASSWORD('ein_passwort')
+Setzt das Passwort für einen bestimmten Benutzer auf dem aktuellen
+Server-Host. Das kann nur ein Benutzer mit Zugriff auf die
+@code{mysql}-Datenbank tun. Der Benutzer sollte im
+@code{user@@hostname}-Format eingegeben werden, wobei @code{user} und
+@code{hostname} exakt so sind, wie sie in den @code{User}- und
+@code{Host}-Spalten des @code{mysql.user}-Tabelleneintrags aufgelistet
+sind. Wenn Sie zum Beispiel in den Spalten @code{User} und @code{Host} die
+Einträge @code{'bob'} und @code{'%.loc.gov'} haben wollen, schreiben Sie:
+
+@example
+mysql> SET PASSWORD FOR bob@@"%.loc.gov" = PASSWORD("newpass");
+
+oder
+
+mysql> UPDATE mysql.user SET password=PASSWORD("newpass") where user="bob' und host="%.loc.gov";
+@end example
+
+@item SQL_AUTO_IS_NULL = 0 | 1
+Falls auf @code{1} gesetzt (Vorgabe), wird mit folgendem Konstrukt die
+letzte eingefügte Zeile einer Tabelle mit einer auto_increment-Zeile
+gefunden:
+@code{WHERE auto_increment_spalte IS NULL}. Das wird von einigen
+ODBC-Programme wie Access benutzt.
+
+@item AUTOCOMMIT= 0 | 1
+Falls auf @code{1} gesetzt, werden alle Änderungen einer Tabelle auf einmal
+durchgeführt. Um eine Transaktion aus mehreren Befehlen anzufangen, müssen
+Sie das @code{BEGIN}-Statement benutzen. @xref{COMMIT}. Falls auf @code{0}
+gesetzt, müssen Sie @code{COMMIT} / @code{ROLLBACK} benutzen, um diese
+Transaktion zu akzeptieren / zu widerrufen. @xref{COMMIT}. Beachten Sie,
+dass MySQL nach dem Umschalten vom @code{AUTOCOMMIT}-Modus zum
+@code{AUTOCOMMIT}-Modus ein automatisches @code{COMMIT} auf alle offenen
+Transaktionen durchführt.
+
+@item SQL_BIG_TABLES = 0 | 1
+@cindex table is full
+Falls auf @code{1} gesetzt, werden alle temporären Tabellen auf Platte
+statt im Arbeitsspeicher gespeichert. Das ist etwas langsamer, aber Sie
+erhalten nicht den Fehler @code{The table tabelle is full}, wenn Sie große
+@code{SELECT}-Operationen ausführen, die eine große temporäre Tabelle
+erfordern. Der Vorgabewert für eine neue Verbindung ist @code{0} (das
+heißt, temporäre Tabellen im Arbeitsspeicher benutzen).
+
+@item SQL_BIG_SELECTS = 0 | 1
+Falls auf @code{0} gesetzt, bricht MySQL ab, wenn ein @code{SELECT} versucht
+wird, das wahrscheinlich sehr lange dauern wird. Das ist nützlich, wenn ein
+unratsames @code{WHERE}-Statement abgesetzt wurde. Ein große Anfrage ist
+definiert als ein @code{SELECT}, das wahrscheinlich mehr als
+@code{max_join_size} Zeilen untersuchen muss. Der Vorgabewert für eine neue
+Verbindung ist @code{1} (was alle @code{SELECT}-Statements zuläßt).
+
+@item SQL_BUFFER_RESULT = 0 | 1
+@code{SQL_BUFFER_RESULT} erzwingt, dass das Ergebnis von @code{SELECT}'s in
+eine temporäre Tabelle geschrieben wird. Das hilft MySQL, die
+Tabellensperren frühzeitig aufzuheben, und ist hilfreich in Fällen, wo es
+lange dauert, das Ergebnis an den Client zu senden.
+
+@item SQL_LOW_PRIORITY_UPDATES = 0 | 1
+Falls auf @code{1} gesetzt, warten alle @code{INSERT}-, @code{UPDATE}-,
+@code{DELETE}- und @code{LOCK TABLE WRITE}-Statements, bis es kein
+anhängiges @code{SELECT} oder @code{LOCK TABLE READ} für die betroffene
+Tabelle gibt.
+
+@item SQL_MAX_JOIN_SIZE = wert | DEFAULT
+Nicht zulassen, dass @code{SELECT}s, die wahrscheinlich mehr als
+@code{value} Zeilenkombinationen untersuchen müssen, ausgeführt werden.
+Wenn Sie diesen Wert setzen, können Sie @code{SELECT}s abfangen, bei denen
+Schlüssel nicht korrekt verwendet werden und die wahrscheinlich sehr lange
+dauern. Wenn dieser Wert auf etwas anderes als @code{DEFAULT} gesetzt wird,
+wird der @code{SQL_BIG_SELECTS}-Flag zurückgesetzt. Wenn Sie den
+@code{SQL_BIG_SELECTS}-Flag wieder setzen, wird die
+@code{SQL_MAX_JOIN_SIZE}-Variable ignoriert. Sie können für diese Variable
+einen Vorgabewert setzen, wenn Sie @code{mysqld} mit @code{-O
+max_join_size=#} starten.
+
+@item SQL_SAFE_UPDATES = 0 | 1
+Falls auf @code{1} gesetzt, bricht MySQL ab, wenn ein @code{UPDATE} oder
+@code{DELETE} versucht wird, das keinen Schlüssel oder kein @code{LIMIT} in
+der @code{WHERE}-Klausel benutzt. Das ermöglicht das Abfangen falscher
+Aktualisierungen, wenn SQL-Befehle von Hand eingegeben werden.
+
+@item SQL_SELECT_LIMIT = wert | DEFAULT
+Die maximale Anzahl von Datensätzen, die von @code{SELECT}-Statements
+zurückgegeben werden. Wenn ein @code{SELECT} eine @code{LIMIT}-Klausel hat,
+hat das @code{LIMIT} Vorrang vor dem Wert von @code{SQL_SELECT_LIMIT}. Der
+Vorgabewert für eine neue Verbindung ist ``unbegrenzt.'' Wenn Sie diese
+Begrenzung geändert haben, kann der Vorgabewert wieder hergestellt werden,
+indem Sie einen @code{SQL_SELECT_LIMIT}-Wert von @code{DEFAULT} verwenden.
+
+@item SQL_LOG_OFF = 0 | 1
+Falls auf @code{1} gesetzt, wird für diesen Client kein Loggen ins
+Standard-Log durchgeführt, wenn der Client die
+@strong{process}-Berechtigung hat. Das betrifft nicht die
+Update-Log-Datei!
+
+@item SQL_LOG_UPDATE = 0 | 1
+Falls auf @code{0} gesetzt, wird für diesen Client kein Loggen in die
+Update-Log-Datei durchgeführt, wenn der Client die
+@strong{process}-Berechtigung hat. Das betrifft nicht das Standard-Log!
+
+@item SQL_QUOTE_SHOW_CREATE = 0 | 1
+Falls auf @code{1} gesetzt, setzt @code{SHOW CREATE TABLE} Tabellen- und
+Spaltennamen in Anführungszeichen. Das ist vorgabemäßig
+@strong{angeschaltet}, damit Replikation von Tabellen mit merkwürdigen
+Spaltennamen funktioniert. @ref{SHOW CREATE TABLE, , @code{SHOW CREATE TABLE}}.
+
+@item TIMESTAMP = zeitstempel_wert | DEFAULT
+Setzt die Zeit für diesen Client. Das wird benutzt, um den
+Original-Zeitstempel zu erhalten, wenn sie die Update-Log-Datei benutzen,
+um Zeilen wiederherzustellen. @code{zeitstempel_wert} sollte ein
+UNIX-Epoche-Zeitstempel sein, kein MySQL-Zeitstempel.
+
+@item LAST_INSERT_ID = #
+Setzt den Wert, der von @code{LAST_INSERT_ID()} zurückgegeben wird. Dieser
+wird in der Update-Log-Datei gespeichert, wenn Sie @code{LAST_INSERT_ID()}
+in einem Befehl benutzen, der eine Tabelle aktualisiert.
+
+@item INSERT_ID = #
+Setzt den Wert, der von einem folgenden @code{INSERT}- oder @code{ALTER
+TABLE}-Befehl benutzt wird, wenn ein @code{AUTO_INCREMENT}-Wert eingefügt
+wird. Das wird hauptsächlich zusammen mit der Update-Log-Datei benutzt.
+@end table
+
+
+
+
+
+
+@node Disk issues, , Optimising the Server, MySQL Optimisation
+@c German node Festplatte
+@section Festplatte, Anmerkungen
+
+@cindex Festplatten, Anmerkungen
+@cindex Performance, Anmerkungen zur Festplatte
+
+@itemize @bullet
+@item
+Wie bereits erwähnt sind Suchvorgänge auf der Festplatte ein großer
+Performance-Flaschenhals. Die Probleme werden mehr und mehr deutlich, wenn
+die Datenmenge wächst, so dass effizientes Caching unmöglich wird. Bei
+großen Datenbanken, in denen Sie auf Daten mehr oder weniger zufällig
+zugreifen, können Sie sicher davon ausgehen, dass Sie zumindest eine
+Plattenzugriff brauchen, um zu lesen, und eine Reihe weiterer
+Plattenzugriffe, um Dinge zu schreiben. Um dieses Problem zu minimieren,
+benutzen Sie Platten mit geringen Zugriffszeiten!
+
+@item
+Erhöhen Sie die Anzahl verfügbarer Festplattenscheiben (und verringern Sie
+dadurch den Such-Overhead), indem Sie entweder Dateien auf andere Platten
+symbolisch verknüpfen (SymLink) oder die Platten 'stripen'.
+
+@table @strong
+@item Using Symbolische Links
+Das bedeutet, dass Sie die Index- und / oder Daten-Datei(en) aus dem
+normalen Daten-Verzeichnis auf eine andere Festplatte verknüpfen (die auch
+'gestriped' sein kann). Das macht sowohl den Suchvorgang als auch die
+Lesezeiten besser (wenn die Platten nicht für andere Dinge benutzt werden).
+@xref{Symbolic links}.
+
+@cindex Stripen, Definition
+@item Stripen
+'Stripen' heißt, dass Sie viele Festplatten haben und den ersten Block
+auf die erste Platte legen, den zweiten Block auf die zweite Platte und den
+n-ten Block auf die n-te Platte usw. Das bedeutet, wenn Ihre normale
+Datengröße weniger als die Stripe-Größe ist (oder perfekt passt), dass
+Sie wesentlich bessere Performance erhalten. Beachten Sie, dass Stripen
+sehr stark vom Betriebssystem und von der Stripe-Größe abhängig ist.
+Machen Sie Benchmark-Tests Ihrer Applikation mit unterschiedlichen
+Stripe-Größen. @xref{Custom Benchmarks}.
+
+Beachten Sie, dass der Geschwindigkeitsunterschied für das Stripen
+@strong{sehr} stark vom Parameter abhängig ist. Abhängig davon, wie Sie den
+Stripe-Parameter setzen und von der Anzahl von Festplatten erhalten Sie
+Unterschiede in der Größenordnung von Faktoren. Beachten Sie, dass Sie
+entscheiden müssen, ob Sie für zufällige oder sequentielle Zugriffe
+optimieren.
+@end table
+
+@item
+Aus Gründen der Zuverlässigkeit sollten sie vielleicht RAID 0 + 1 nehmen
+(Stripen + Spiegeln), doch in diesem Fall brauchen Sie 2 * n Laufwerke, um
+n Datenlaufwerke zu haben. Das ist wahrscheinlich die beste Option, wenn
+Sie genug Geld dafür haben! Sie müssen jedoch eventuell zusätzlich in
+Software für die Verwaltung von Volumes investieren, um das effizient zu
+handhaben.
+
+@item
+Eine gute Option ist es, nicht ganz so wichtige Daten (die wieder
+hergestellt werden können) auf RAID-0-Platten zu halten, während wirklich
+wichtige Daten (wie Host-Informationen und Log-Dateien) auf einer RAID-0+1-
+oder RAID-N-Platte gehalten werden. RAID-N kann ein Problem darstellen,
+wenn Sie viele Schreibzugriffe haben, weil Zeit benötigt wird, die
+Paritätsbits zu aktualisieren.
+
+@item
+Sie können auch den Parameter für das Dateisystem setzen, das die Datenbank
+benutzt. Eine einfache Änderung ist, das Dateisystem mit der noatime-Option
+zu mounten. Das bringt es dazu, das Aktualisieren der letzten Zugriffszeit
+in der Inode zu überspringen und vermeidet dadurch einige
+Platten-Suchzugriffe.
+
+@item
+Unter Linux können Sie viel mehr Performance erhalten (bis zu 100% unter
+Last ist nicht ungewöhnlich), wenn Sie hdpram benutzen, um die
+Schnittstelle Ihrer Festplatte zu konfigurieren! Das folgende Beispiel
+sollte recht gute hdparm-Optionen für MySQL (und wahrscheinlich viele
+andere Applikationen) darstellen:
+
+@example
+hdparm -m 16 -d 1
+@end example
+
+Beachten Sie, dass Performance und Zuverlässigkeit beim oben Genannten von
+Ihrer Hardware abhängen, daher empfehlen wir sehr, dass Sie Ihr System
+gründlich testen, nachdem Sie @code{hdparm} benutzt haben! Sehen Sie in der
+Handbuchseite (ManPage) von @code{hdparm} nach weiteren Informationen! Wenn
+@code{hdparm} nicht vernünftig benutzt wird, kann das Ergebnis eine
+Beschädigung des Dateisystems sein. Machen Sie eine Datensicherung von
+allem, bevor Sie experimentieren!
+
+@item
+Auf vielen Betriebssystemen können Sie die Platten mit dem 'async'-Flag
+mounten, um das Dateisystem auf asynchrone Aktualisierung zu setzen. Wenn
+Ihr Computer ausreichend stabil ist, sollte Ihnen das mehr Performance
+geben, ohne zu viel Zuverlässigkeit zu opfern. (Dieser Flag ist unter Linux
+vorgabemäßig angeschaltet.)
+
+@item
+Wenn Sie nicht wissen müssen, wann auf eine Datei zuletzt zugegriffen
+wurden (was auf einem Datenbank-Server nicht wirklich nötig ist), können
+Sie Ihr Dateisystem mit dem noatime-Flag mounten.
+@end itemize
+
+
+
+@menu
+* Symbolic links::
+@end menu
+
+@node Symbolic links, , Disk issues, Disk issues
+@c German node Symbolische Links
+@subsection Symbolische Links benutzen
+
+@cindex Symbolische Links
+@cindex Links, symbolische
+
+Sie können Tabellen und Datenbanken vom Datenbank-Verzeichnis an andere
+Stellen verschieben und sie mit symbolischen Links auf neue Speicherorte
+ersetzen. Das könnten Sie zum Beispiel tun, um eine Datenbank auf ein
+Dateisystem mit mehr freiem Speicherplatz zu verlagern oder um die
+Geschwindigkeit Ihres System durch Verteilen Ihrer Tabellen auf
+unterschiedliche Platten zu steigern.
+
+Die empfohlene Art, das zu tun, ist, nur Datenbanken auf unterschiedliche
+Platten per SymLink zu verknüpfen, und das bei Tabellen nur im Notfall zu
+tun.
+
+@cindex Datenbanken, Symbolische Links
+
+
+@menu
+* Symbolic links to databases::
+* Symbolic links to tables::
+@end menu
+
+@node Symbolic links to databases, Symbolic links to tables, Symbolic links, Symbolic links
+@c German node Symbolische Links auf Datenbanken
+@subsubsection Benutzung symbolischer Links für Datenbanken
+
+Um eine Datenbank per SymLink zu verknüpfen, legt man zuerst ein
+Verzeichnis auf einer Platte mit freiem Speicherplatz an und erzeugt dann
+einen SymLink vom MySQL-Datenbank-Verzeichnis aus darauf:
+
+@example
+shell> mkdir /dr1/datenbanken/test
+shell> ln -s /dr1/datenbanken/test mysqld-datadir
+@end example
+
+MySQL unterstützt nicht das Verknüpfen eines Verzeichnisses zu mehrfachen
+Datenbanken. Wenn Sie ein Datenbank-Verzeichnis mit einem symbolischen Link
+ersetzen, funktioniert das solange gut, wie Sie keinen symbolischen Link
+zwischen Datenbanken machen. Angenommen, Sie haben eine Datenbank
+@code{datenbank1} unter dem MySQL-Daten-Verzeichnis und machen dann einen
+Symlink @code{datenbank2}, der auf @code{datenbank1} zeigt:
+
+@example
+shell> cd /pfad/zu/datadir
+shell> ln -s datenbank1 datenbank2
+@end example
+
+Jetzt erscheint für jede Tabelle @code{tabelle_a} in @code{datenbank1} auch
+eine Tabelle @code{tabelle_a} in @code{datenbank2}. Wenn ein Thread
+@code{datenbank1.tabelle_a} aktualisiert und ein anderer Thread
+@code{datenbank2.tabelle_a} aktualisiert, gibt es Probleme.
+
+Wenn Sie das wirklich brauchen, müssen Sie folgenden Code in
+@file{mysys/mf_format.c} ändern:
+
+@example
+if (flag & 32 || (!lstat(to,&stat_buff) && S_ISLNK(stat_buff.st_mode)))
+@end example
+
+zu:
+
+@example
+if (1)
+@end example
+
+Unter Windows können Sie interne symbolische Links auf Verzeichnisse
+benutzen, indem Sie MySQL mit @code{-DUSE_SYMDIR} kompilieren. Das erlaubt
+Ihnen, verschiedene Datenbanken auf verschiedene Platte zu legen.
+@xref{Windows symbolic links}.
+
+
+@node Symbolic links to tables, , Symbolic links to databases, Symbolic links
+@c German node Symbolische Links auf Tabellen
+@subsubsection Benutzung symbolischer Links für Tabellen
+
+@cindex Datenbanken, Symbolische Links
+
+Vor MySQL 4.0 konnten Sie Tabellen nicht per SymLink verknüpfen, wenn Sie
+nicht sehr sorgfältig dabei vorgingen. Das Problem liegt darin, dass bei
+@code{ALTER TABLE}, @code{REPAIR TABLE} oder @code{OPTIMIZE TABLE} auf eine
+per Symlink verknüpfte Datei die SymLinks entfernt und durch die
+Original-Dateien verknüpft werden. Das geschieht, weil beim obigen Befehl
+eine temporäre Datei im Datenbank-Verzeichnis erzeugt wird, und wenn der
+Befehl ausgeführt ist, die Original-Datei durch die temporäre Datei
+ersetzt wird.
+
+Sie sollten Tabellen auf Systemen, die keinen vollständig funktionierenden
+@code{realpath()}-Aufruf haben, nicht per SymLink verknüpfen. (Zumindest
+Linux und Solaris unterstützen @code{realpath()}.)
+
+In MySQL 4.0 werden Symlinks nur für @code{MyISAM}-Tabellen vollständig
+unterstützt. Bei anderen Tabellentypen erhalten Sie wahrscheinlich
+merkwürdige Probleme, wenn Sie einen der obigen Befehle ausführen.
+
+Die Handhabung symbolischer Links in MySQL 4.0 funktioniert auf folgende
+Art (das gilt meist nur für @code{MyISAM}-Tabellen):
+
+@itemize @bullet
+@item
+Im Daten-Verzeichnis liegen immer die Tabellendefinitionsdatei und die
+Daten-/Index-Dateien.
+
+@item
+Sie können die Index-Datei und die Daten-Datei unabhängig voneinander auf
+unterschiedliche Verzeichnisse per SymLink verknüpfen.
+
+@item
+Das Erzeugen der SymLinks kann durch das Betriebssystem (wenn @code{mysqld}
+nicht läuft) oder mit dem @code{INDEX/DATA
+directory="pfad-zum-verzeichnis"}-Befehl in @code{CREATE TABLE}
+durchgeführt werden. @xref{CREATE TABLE}.
+
+@item
+@code{myisamchk} ersetzt keinen Symlink mit der Index-/Datendatei, sondern
+arbeitet direkt mit den Dateien, auf die die SymLinks verweisen. Jegliche
+temporäre Dateien werden im selben Verzeichnis erzeugt, wo die
+Daten-/Index-Datei ist.
+
+@item
+Wenn Sie eine Tabelle löschen, die Symlinks benutzt, werden sowohl der
+Symlink als auch die Datei, auf die der SymLink zeigt, gelöscht. Das ist
+ein guter Grund dafür, @code{mysqld} NICHT als Root laufen zu lassen und
+niemandem zu erlauben, Schreibzugriff auf die MySQL-Datenbankverzeichnisse
+zu haben.
+
+@item
+Wenn Sie eine Tabelle mit @code{ALTER TABLE RENAME} umbenennen und nicht
+die Datenbank ändern, wird der Symlink im Datenbank-Verzeichnis auf den
+neuen Namen umbenannt und die Daten-/Index-Datei wird entsprechend
+umbenannt.
+
+@item
+Wenn Sie @code{ALTER TABLE RENAME} benutzen, um eine Tabelle in eine andere
+Datenbank zu verschieben, wird die Tabelle in das andere
+Datenbank-Verzeichnis verschoben und die alten SymLinks und die Dateien,
+auf die sie zeigen, werden gelöscht.
+
+@item
+Wenn Sie keine Symlinks benutzen, sollten Sie die
+@code{--skip-symlink}-Option für @code{mysqld} benutzen, damit niemand eine
+Datei ausserhalb des @code{mysqld} Daten-Verzeichnisses löschen oder
+umbenennen kann.
+@end itemize
+
+Dinge, die noch nicht unterstützt werden:
+
+@cindex TODO, SymLinks
+@itemize @bullet
+@item
+@code{ALTER TABLE} ignoriert alle @code{INDEX/DATA directory="pfad"}-Optionen.
+@item
+@code{CREATE TABLE} berichtet nicht, wenn eine Tabelle symbolische Links hat.
+@item
+@code{mysqldump} gibt die Information über symbolische Links nicht in der Ausgabe aus.
+@item
+@code{BACKUP TABLE} und @code{RESTORE TABLE} respektieren keine symbolischen Links.
+@end itemize
+
+
+@node Reference, Table types, MySQL Optimisation, Top
+@c German node Referenz
+@chapter MySQL-Sprachreferenz
+
+
+MySQL hat eine sehr komplexe, aber intuitive und leicht zu erlernende
+SQL-Schnittstelle. Dieses Kapitel beschreibt die verschiedenen Befehle,
+Typen und Funktionen, die Sie kennen müssen, um MySQL effizient und
+effektiv zu benutzen. Dieses Kapitel dient auch als Referenz für die
+gesamte in MySQL beinhaltete Funktionalität. Um dieses Kapitel effektiv zu
+nutzen, sollten Sie unter den verschiedenen Stichworten nachschlagen.
+
+
+@menu
+* Language Structure::
+* Column types::
+* Functions::
+* Data Manipulation::
+* Data Definition::
+* Basic User Commands::
+* Transactional Commands::
+* Fulltext Search::
+* Query Cache::
+@end menu
+
+@node Language Structure, Column types, Reference, Reference
+@c German node Sprachstruktur
+@section Sprachstruktur
+
+
+
+@menu
+* Literals::
+* Legal names::
+* Name case sensitivity::
+* Variables::
+* Comments::
+* Reserved words::
+@end menu
+
+@node Literals, Legal names, Language Structure, Language Structure
+@c German node Literale
+@subsection Literale: Wie Zeichenketten und Zahlen geschrieben werden
+
+@cindex Zeichenketten, Definition
+@cindex Zeichenketten, Fluchtzeichen (Escape-Zeichen)
+@cindex Literale
+@cindex Fluchtzeichen (Escape-Zeichen)
+@cindex Backslash, Fluchtzeichen (Escape-Zeichen)
+
+
+
+Dieser Abschnitt beschreibt die verschiedenen Arten, in MySQL Zeichenketten
+und Zahlen zu schreiben. Ebenfalls enthalten sind die verschiedenen Nuancen
+und Fallstricke, in denen man sich bei den grundlegenden Datentypen von
+MySQL verfangen kann.
+
+
+@menu
+* String syntax::
+* Number syntax::
+* Hexadecimal values::
+* NULL values::
+@end menu
+
+@node String syntax, Number syntax, Literals, Literals
+@c German node Zeichenketten-Syntax
+@subsubsection Zeichenketten
+
+Eine Zeichenkette ist eine Folge von Zeichen, die entweder von Apostrophs
+(einfachen Anführungszeichen, @samp{'}) oder (doppelten) Anführungszeichen
+(@samp{"}) umgeben ist (nur einfache Anführungszeichen, wenn Sie MySQL im
+ANSI-Modus laufen lassen). Beispiele:
+
+@example
+'eine Zeichenkette'
+"eine weitere Zeichenkette"
+@end example
+
+Innerhalb einer Zeichenkette haben bestimmte Folgen eine spezielle
+Bedeutung. Jede dieser Folgen fängt mit einem Backslash (@samp{\}) an,
+bekannt als @emph{Fluchtzeichen (Escape-Zeichen)}. MySQL erkennt folgende
+Flucht-Folgen (Escape-Folgen):
+
+@c these aren't really Funktionen, aber that's wahrscheinlich the most reasonable index
+@table @code
+@findex \0 (ASCII 0)
+@findex NUL
+@item \0
+Ein ASCII-0- (@code{NUL}) Zeichen.
+
+@findex \' (Apostroph)
+@findex single quote (\')
+@item \'
+Ein Apostroph- (@samp{'}) Zeichen.
+
+@findex \" (Anführungszeichen)
+@findex Anführungszeichen (\")
+@item \"
+Ein Anführungszeichen (@samp{"}).
+
+@findex \b (Rückschritt, Backspace)
+@findex backspace (\b)
+@item \b
+Ein Rückschritt- (Backspace-) Zeichen.
+
+@findex \n (neue Zeile)
+@findex newline (\n)
+@item \n
+Ein Neue-Zeile- (Newline-) Zeichen.
+
+@findex \r (Wagenrücklauf (carriage return))
+@findex return (\r)
+@findex Wagenrücklauf (carriage return) (\r)
+@item \r
+Ein Wagenrücklauf- (carriage return) Zeichen.
+
+@findex \t (Tabulator)
+@findex tab (\t)
+@item \t
+Ein Tabulator-Zeichen.
+
+@findex \z (Steuerung-Z) ASCII(26)
+@findex (Steuerung-Z) \z
+@item \z
+ASCII(26) (Steuerung-Z). Dieses Zeichen kann kodiert werden, um das Problem
+zu umgehen, dass ASCII(26) unter Windows für Dateiende (END-OF-FILE) steht.
+(ASCII(26) verursacht Probleme, wenn Sie @code{mysql Datenbank < Dateiname}
+benutzen.)
+
+@findex \\ (Fluchtzeichen, Escape-Zeichen)
+@findex escape (\\)
+@item \\
+Ein Backslash- (@samp{\}) Zeichen.
+
+@c German FIX added space before %
+@findex % (Platzhalterzeichen)
+@findex Wild card character (%)
+@item \%
+Ein @samp{%}-Zeichen. Dieses wird benutzt, um nach literalen Instanzen von
+@samp{%} in Zusammenhängen zu suchen, wo @samp{%} ansonsten als
+Platzhalterzeichen interpretiert werden würde.
+@xref{String comparison functions}.
+
+@findex _ (Platzhalterzeichen)
+@findex Wild card character (_)
+@item \_
+Ein @samp{_}-Zeichen. Dieses wird benutzt, um nach literalen Instanzen von
+@samp{_} in Zusammenhängen zu suchen, wo @samp{_} ansonsten als
+Platzhalterzeichen interpretiert werden würde.
+@xref{String comparison functions}.
+@end table
+
+Beachten Sie, dass bei der Benutzung von @samp{\%} oder @samp{\_} in
+einigen Zeichenketten-Zusammenhängen diese die Zeichenketten @samp{\%} und
+@samp{\_} und nicht @samp{%} und @samp{_} zurückgeben.
+
+@cindex Anführungszeichen, in Zeichenketten
+@noindent
+Es gibt verschiedene Möglichkeiten, Anführungszeichen innerhalb einer
+Zeichenkette zu schreiben:
+
+@itemize @bullet
+@item
+Ein @samp{'} innerhalb einer Zeichenkette, die mit @samp{'} begrenzt wird,
+kann als @samp{''} geschrieben werden.
+
+@item
+Ein @samp{"} innerhalb einer Zeichenkette, die @samp{"} begrenzt wird, kann
+als @samp{""} geschrieben werden.
+
+@item
+Sie können dem Anführungszeichen ein Fluchtzeichen (Escape-Zeichen)
+(@samp{\}) voranstellen.
+
+@item
+Ein @samp{'} innerhalb einer Zeichenkette, die mit @samp{"} begrenzt wird,
+braucht keine spezielle Behandlung und muss nicht verdoppelt oder escapet
+werden. In gleicher Weise benötigt @samp{"} innerhalb einer Zeichenkette,
+die mit @samp{'} begrenzt wird, keine spezielle Behandlung.
+@end itemize
+
+Die unten stehenden @code{SELECT}-Statements zeigen, wie Quoten und Escapen
+funktionieren:
+
+@example
+mysql> SELECT 'hello', '"hello"', '""hello""', 'hel''lo', '\'hello';
++-------+---------+-----------+--------+--------+
+| hello | "hello" | ""hello"" | hel'lo | 'hello |
++-------+---------+-----------+--------+--------+
+
+mysql> SELECT "hello", "'hello'", "''hello''", "hel""lo", "\"hello";
++-------+---------+-----------+--------+--------+
+| hello | 'hello' | ''hello'' | hel"lo | "hello |
++-------+---------+-----------+--------+--------+
+
+mysql> SELECT "Das\nsind\nvier\nZeilen";
++--------------------+
+| Das
+sind
+vier
+Zeilen |
++--------------------+
+@end example
+
+@cindex Binärdaten quoten
+
+Wenn Sie Binärdaten in eine @code{BLOB}-Spalte einfügen, müssen folgende
+Zeichen durch Flucht-Folgen repräsentiert werden:
+@table @code
+@item NUL
+ASCII 0. Dieses geben Sie als @samp{\0} ein (ein Backslash und ein
+ASCII-@samp{0}-Zeichen).
+@item \
+ASCII 92, Backslash. Das geben Sie als @samp{\\} ein.
+@item '
+ASCII 39, Apostroph. Das geben Sie als @samp{\'} ein.
+@item "
+ASCII 34, Anführungszeichen. Das geben Sie als @samp{\"} ein.
+@end table
+
+@cindex Quoten
+@cindex @code{BLOB}, Binärdaten einfügen
+@findex mysql_escape_string()
+@findex DBI->quote
+Wenn Sie C-Code schreiben, können Sie die C-API-Funktion
+@code{mysql_escape_string()} für Fluchtzeichen (Escape-Zeichen) für das
+@code{INSERT}-Statement benutzen. @xref{C API function overview}. In Perl
+können Sie die @code{quote}-Methode des @code{DBI}-Pakets benutzen, um
+Sonderzeichen in die korrekten Flucht-Folgen umzuwandeln.
+@xref{Perl DBI Class, , Perl-@code{DBI}-Klasse}.
+
+Sie sollten auf jede Zeichenkette, die eins der oben erwähnten
+Sonderzeichen enthalten könnte, eine der Flucht-Funktionen anwenden!
+
+
+@node Number syntax, Hexadecimal values, String syntax, Literals
+@c German node Zahlen-Syntax
+@subsubsection Zahlen
+
+@cindex Zahlen
+@cindex gültige Zahlen, Beispiele
+@cindex Ganzzahlen
+@cindex Fließkommazahlen
+@cindex negative Werte
+
+Ganzzahlen werden als Folge von Ziffern repräsentiert. Fließkommazahlen
+benutzen @samp{.} als Dezimalseparator. Jedem Zahlentyp kann @samp{-}
+vorangestellt werden, um einen negativen Wert anzuzeigen.
+
+Beispiele gültiger Ganzzahlen:
+
+@example
+1221
+0
+-32
+@end example
+
+Beispiele gültiger Fließkommazahlen:
+
+@example
+294.42
+-32032.6809e+10
+148.00
+@end example
+
+Eine Ganzzahl kann in einem Fließkomma-Zusammenhang benutzt werden, sie
+wird dann als die äquivalente Fließkommazahl interpretiert.
+
+
+@node Hexadecimal values, NULL values, Number syntax, Literals
+@c German node Hexadezimale Werte
+@subsubsection Hexadezimale Werte
+
+@tindex hexadezimale Werte
+
+MySQL unterstützt hexadezimale Werte. In Zahlen-Zusammenhängen
+funktionieren diese wie eine Ganzzahl (64-Bit-Genauigkeit). Im
+Zeichenketten-Zusammenhang funktionieren sie wie eine binäre Zeichenkette,
+wobei jedes Paar hexadezimaler Ziffern in ein Zeichen umgewandelt wird:
+
+@example
+mysql> SELECT x'FF'
+ -> 255
+mysql> SELECT 0xa+0;
+ -> 10
+mysql> select 0x5061756c;
+ -> Paul
+@end example
+
+Die x'hexadezimale_zeichenkette'-Syntax (neu in Version 4.0) basiert auf
+ANSI-SQL. Die 0x-Syntax basiert auf ODBC. Hexadezimale Zeichenketten werden
+oft von ODBC benutzt, um Werte für BLOB-Spalten anzugeben.
+
+
+@node NULL values, , Hexadecimal values, Literals
+@c German node NULL-Werte
+@subsubsection @code{NULL}-Werte
+
+@tindex NULL-Wert
+
+Der @code{NULL}-Wert bedeutet ``keine Daten'' und unterscheidet sich von
+Werten wie @code{0} bei numerischen Typen oder der leeren Zeichenkette bei
+Zeichenkettentypen. @xref{Problems with NULL, , Probleme mit @code{NULL}}.
+
+@code{NULL} kann durch @code{\N} repräsentiert werden, wenn Sie die
+Textdatei-Import- oder Exportformate (@code{LOAD DATA INFILE}, @code{SELECT
+... INTO OUTFILE}) benutzen. @xref{LOAD DATA, , @code{LOAD DATA}}.
+
+
+@node Legal names, Name case sensitivity, Literals, Language Structure
+@c German node Erlaubte Namen
+@subsection Datenbank-, Tabellen-, Index-, Spalten- und Alias-Namen
+
+@cindex Namen
+@cindex erlaubte Namen
+@cindex Datenbanken, Namen
+@cindex Tabellen, Namen
+@cindex Indexe, Namen
+@cindex Spalten, Namen
+@cindex Aliase, Namen
+
+
+
+Datenbank-, Tabellen-, Index-, Spalten- und Alias-Namen folgen in MySQL
+alle denselben Regeln.
+
+@tindex Bezeichner, quoten
+@tindex Quoten von Bezeichnern
+@tindex `
+@tindex "
+Beachten Sie, dass sich die Regeln ab MySQL-Version 3.23.6 geändert haben,
+als das Quoten von Bezeichnern (für Datenbank-, Tabellen- und Spaltennamen)
+eingeführt wurde, mit @samp{`}. @samp{"} funktioniert ebenfalls, um
+Bezeichner zu quoten, wenn Sie im ANSI-Modus fahren. @xref{ANSI mode}.
+
+@multitable @columnfractions .15 .15 .70
+@item @strong{Bezeichner} @tab @strong{Maximale Länge} @tab @strong{Erlaubte Zeichen}
+@item Datenbank @tab 64 @tab Jedes Zeichen, dass für ein Verzeichnis erlaubt ist, ausser @samp{/} oder @samp{.}.
+@item Tabelle @tab 64 @tab Jedes Zeichen, dass für einen Dateinamen erlaubt ist, ausser @samp{/} oder @samp{.}.
+@item Spalte @tab 64 @tab Alle Zeichen.
+@item Alias @tab 255 @tab Alle Zeichen.
+@end multitable
+
+Hinzuzufügen ist, dass Sie ASCII(0), ASCII(255) oder das Quote-Zeichen in
+einem Bezeichner nicht verwenden dürfen.
+
+Beachten Sie, dass, falls der Bezeichner ein reserviertes Wort ist oder
+Sonderzeichen enthält, er bei der Benutzung immer in @code{`} angegeben
+sein muss:
+
+@example
+SELECT * from `select` where `select`.id > 100;
+@end example
+
+In vorherigen Versionen von MySQL sind die Namensregeln wie folgt:
+
+@itemize @bullet
+@item
+Ein Name muss aus alphanumerischen Zeichen des aktuellen Zeichensatzes
+bestehen und darf darüber hinaus @samp{_} und @samp{$} enthalten. Der
+vorgabemäßige Zeichensatz ist ISO-8859-1 Latin1; dass kann durch die
+@code{--default-character-set}-Option für @code{mysqld} geändert werden.
+@xref{Character sets}.
+
+@item
+Ein Name kann mit jedem Zeichen anfangen, das in einem Namen erlaubt ist.
+Insbesondere kann ein Name auch mit einer Zahl anfangen (das ist in vielen
+anderen Datenbanksystemen anders!). Jedoch kann ein Namen nicht @emph{nur}
+aus Zahlen bestehen.
+
+@item
+Sie können das @samp{.}-Zeichen in Namen nicht benutzen, weil es benutzt
+wird, um das Format zu erweitern, mit dem man auf Spalten verweisen kann
+(siehe unten).
+@end itemize
+
+Es wird empfohlen, dass Sie keine Namen wie @code{1e} verwenden, weil ein
+Ausdruck wie @code{1e+1} mehrdeutig ist. Er kann als der Ausdruck @code{1e
++ 1} oder als die Zahl @code{1e+1} interpretiert werden.
+
+In MySQL können Sie in folgender Form auf Spalten verweisen:
+
+@multitable @columnfractions .35 .65
+@item @strong{Spaltenverweis} @tab @strong{Bedeutung}
+@item @code{spalten_name} @tab Spalte des Namens @code{spalten_name} einer
+beliebigen, in der Anfrage verwendeten Tabelle.
+@item @code{tabelle.spalten_name} @tab Spalte des Namens
+@code{spalten_name} der Tabelle @code{tabelle} der aktuellen Datenbank.
+@item @code{datenbank.tabelle.spalten_name} @tab Spalte des Namens
+@code{spalten_name} der Tabelle @code{tabelle} der Datenbank
+@code{datenbank}. Diese Form ist ab MySQL-Version 3.22 verfügbar.
+@item
+@code{`spalte`} @tab Eine Spalte, die ein reserviertes Wort ist oder
+Sonderzeichen enthält.
+@end multitable
+
+Das @code{tabelle}- oder @code{datenbank.tabelle}-Präfix müssen Sie bei
+einem Spaltenverweis in einem Statement nicht angeben, es sei denn, der
+Verweis wäre ansonsten doppeldeutig. Nehmen Sie zum Beispiel an, die
+Tabellen @code{t1} und @code{t2} enthielten beide jeweils eine Spalte
+@code{c} und Sie verweisen auf @code{c} in einem @code{SELECT}-Statement,
+das sowohl @code{t1} als auch @code{t2} benutzt. In diesem Fall ist
+@code{c} mehrdeutig, weil es innerhalb der im Statement benutzten Tabellen
+nicht eindeutig ist. Daher müssen Sie angeben, welche Tabelle Sie meinen,
+indem Sie @code{t1.c} oder @code{t2.c} schreiben. Ähnliches gilt, wenn Sie
+aus einer Tabelle @code{t} in Datenbank @code{datenbank1} und von eine
+Tabelle @code{t} in Datenbank @code{datenbank2} abrufen. Dann müssen Sie
+auf Spalten in diesen Tabellen als @code{datenbank1.t.spalten_name} und
+@code{datenbank2.t.spalten_name} verweisen.
+
+@cindex ODBC Kompatibilität
+@cindex Kompatibilität, mit ODBC
+Die Syntax @code{.tabelle} bedeutet die Tabelle @code{tabelle} in der
+aktuellen Datenbank. Diese Syntax wird aus Gründen der ODBC-Kompatibilität
+akzeptiert, weil einige ODBC-Programme Tabellenname ein @samp{.}-Zeichen
+voranstellen.
+
+
+@node Name case sensitivity, Variables, Legal names, Language Structure
+@c German node Groß-/Kleinschreibung in Namen
+@subsection Groß-/Kleinschreibung in Namen
+
+@cindex Namen, Groß-/Kleinschreibung
+@cindex Groß-/Kleinschreibung, in Namen
+@cindex Datenbanknamen, Groß-/Kleinschreibung
+@cindex Tabellennamen, Groß-/Kleinschreibung
+@cindex Spaltennamen, Groß-/Kleinschreibung
+@cindex Aliasnamen, Groß-/Kleinschreibung
+
+In MySQL entsprechen Datenbanken und Tabellen Verzeichnissen und Dateien
+innerhalb dieser Verzeichnisse. Folglich hängt die Groß-/Kleinschreibung
+davon ab, wie das zugrunde liegende Betriebssystem die
+Groß-/Kleinschreibung von Datenbank- und Tabellennamen festlegt. Das
+bedeutet, dass Datenbank- und Tabellennamen unter Unix von der
+Groß-/Kleinschreibung abhängen und unter Windows nicht.
+@xref{Extensions to ANSI}.
+
+@strong{HINWEIS:} Obwohl die Groß-/Kleinschreibung für Datenbank- und
+Tabellennamen unter Windows keine Rolle spielt, sollten Sie nicht auf eine
+angegebene Datenbank oder Tabelle innerhalb derselben Anfrage mit
+unterschiedlicher Schreibweise verweisen. Folgende Anfrage würde nicht
+funktionieren, weil sie auf eine Tabelle sowohl mit @code{meine_tabelle}
+als auch mit @code{MEINE_TABELLE} verweist:
+
+@example
+mysql> SELECT * FROM meine_tabelle WHERE MEINE_TABELLE.spalte=1;
+@end example
+
+Spaltennamen hängen in keinem Fall von der verwendeten
+Groß-/Kleinschreibung ab.
+
+Aliase auf Tabellen hängen von der Groß-/Kleinschreibung ab. Folgende
+Anfrage würde nicht funktionieren, weil sie auf den Alias sowohl mit
+@code{a} als auch mit @code{A} verweist:
+
+@example
+mysql> SELECT spalten_name FROM tabelle AS a
+ WHERE a.spalten_name = 1 OR A.spalten_name = 2;
+@end example
+
+Aliase auf Spalten hängen nicht von der verwendeten Groß-/Kleinschreibung
+ab.
+
+Wenn Sie Probleme damit haben, sich an die Schreibweise von Tabellennamen zu
+erinnern, halten Sie sich an eine durchgehende Konvention. Benutzen Sie zum
+Beispiel bei der Erzeugung von Datenbanken und Tabellen Kleinschreibung in
+Namen.
+
+Eine Möglichkeit, dieses Problem zu vermeiden, ist, @code{mysqld} mit
+@code{-O lower_case_tabelles=1} zu starten. Vorgabemäßig ist diese Option
+1 unter Windows und 0 unter Unix.
+
+Wenn @code{lower_case_tabelles} 1 ist, wandelt MySQL alle Tabellennamen in
+Kleinschreibung um, sowohl beim Speichern als auch beim Nachschlagen. Wenn
+Sie diese Option ändern, beachten Sie, dass Sie zuerst Ihre alten
+Tabellennamen in Kleinschreibung umwandeln müssen, bevor Sie @code{mysqld}
+starten.
+
+
+@node Variables, Comments, Name case sensitivity, Language Structure
+@c German node Variablen
+@subsection Benutzer-Variablen
+
+@cindex Variablen, Benutzer-
+@cindex Benutzer-Variablen
+@cindex Namen, Variablen
+
+MySQL unterstützt Thread-spezifische Variablen mit der
+@code{@@variablename}-Syntax. Eine Variable kann aus alphanumerischen
+Zeichen des aktuellen Zeichensatzes sowie aus @samp{_}, @samp{$} und
+@samp{.} bestehen. Der vorgabemäßige Zeichensatz ist ISO-8859-1 Latin1;
+das kann mit der @code{--default-character-set}-Option für @code{mysqld}
+geändert werden. @xref{Character sets}.
+
+Variablen müssen nicht initialisiert werden. Sie enthalten vorgabemäßig
+@code{NULL} und können Ganzzahl-, Real- oder Zeichenketten-Werte speichern.
+Alle Variablen für einen Thread werden automatisch freigegeben, wenn der
+Thread beendet wird.
+
+Sie können eine Variable mit der @code{SET}-Syntax setzen:
+
+@example
+SET @@variable= @{ ganzzahl_ausdruck | realzahl_ausdruck | zeichenketten_ausdruck @} [,@@variable= ...].
+@end example
+
+Sie können eine Variable in einem Ausdruck auch mit der
+@code{@@variable:=expr}-Syntax setzen:
+
+@example
+select @@t1:=(@@t2:=1)+@@t3:=4,@@t1,@@t2,@@t3;
++----------------------+------+------+------+
+| @@t1:=(@@t2:=1)+@@t3:=4 | @@t1 | @@t2 | @@t3 |
++----------------------+------+------+------+
+| 5 | 5 | 1 | 4 |
++----------------------+------+------+------+
+@end example
+
+(Wir mussten hier die @code{:=}-Syntax benutzen, weil @code{=} für
+Vergleiche reserviert ist.)
+
+Benutzer-Variablen können benutzt werden, wo Ausdrücke erlaubt sind.
+Beachten Sie, dass das momentan keine Zusammenhänge einschließt, in denen
+explizit Zahlen erforderlich sind, wie in der @code{LIMIT}-Klausel eines
+@code{SELECT}-Statements oder der @code{IGNORE Anzahl LINES}-Klausel eines
+@code{LOAD DATA}-Statements.
+
+@strong{HINWEIS:} In einem @code{SELECT}-Statement wird jeder Ausdruck
+erst dann ausgewertet, wenn er an den Client geschickt wird. Das heißt,
+dass Sie in der @code{HAVING}-, @code{GROUP BY}- oder @code{ORDER
+BY}-Klausel nicht auf einen Ausdruck verweisen können, der Variablen
+beinhaltet, die nicht im @code{SELECT}-Teil gesetzt wurden. Folgendes
+Statement zum Beispiel funktioniert erwartungsgemäß NICHT:
+
+@example
+SELECT (@@aa:=id) AS a, (@@aa+3) AS b FROM tabelle HAVING b=5;
+@end example
+
+Der Grund ist, dass @code{@@aa} nicht den Wert der aktuellen Zeile enthält,
+sondern den Wert von @code{id} der vorher akzeptierten Zeile.
+
+
+
+@node Comments, Reserved words, Variables, Language Structure
+@c German node Kommentare
+@subsection Kommentar-Syntax
+
+@findex Kommentar-Syntax
+
+@cindex Kommentare, hinzufügen
+
+Der MySQL-Server die Kommentar-Stile @code{# bis Zeilenende}, @code{-- bis
+Zeilenende} und @code{/* mittendrin oder mehrzeilig */}:
+
+@example
+mysql> select 1+1; # Dieser Kommentar geht bis zum Zeilenende
+mysql> select 1+1; -- Dieser Kommentar geht bis zum Zeilenende
+mysql> select 1 /* Das ist ein Kommentar mittendrin */ + 1;
+mysql> select 1+
+/*
+Das ist ein
+mehrzeiliger
+Kommentar
+*/
+1;
+@end example
+
+Beachten Sie, dass Sie beim Kommentarstil @code{--} mindestens ein
+Leerzeichen hinter @code{--} setzen müssen!
+
+Obwohl der Server die Kommentar-Syntax wie beschrieben versteht, gibt es
+einige Einschränkungen in der Art, wie der @code{mysql}-Client @code{/* ...
+*/}-Kommentare parst:
+
+@itemize @bullet
+@item
+Einfache und doppelte Anführungszeichen werden genommen, um den Anfang
+einer Zeichenkette zu bestimmen, selbst innerhalb eines Kommentars. Wenn
+die Zeichenkette nicht durch ein zweites Anführungszeichen innerhalb des
+Kommentars abgeschlossen wird, bemerkt der Parser nicht, dass der Kommentar
+zuende ist. Wenn Sie @code{mysql} interaktiv ausführen, sehen Sie, dass
+@code{mysql} verwirrt ist, weil sich die Eingabeaufforderung von
+@code{mysql>} zu to @code{'>} oder @code{">} ändert.
+
+@item
+Ein Semikolon wird genommen, um das Ende des aktuellen SQL-Statements
+kenntlich zu machen. Alles Folgende wird als Anfang des nächsten Statements
+aufgefasst.
+@end itemize
+
+Diese Einschränkungen gelten sowohl, wenn Sie @code{mysql} interaktiv
+ausführen und wenn Sie Befehle in eine Datei schreiben und @code{mysql} mit
+@code{mysql < some-file} anweisen, seine Eingaben aus dieser Datei zu
+lesen.
+
+MySQL unterstützt nicht den ANSI-SQL-Kommentarstil @samp{--} ohne
+nachfolgendes Leerzeichen. @xref{ANSI diff comments}.
+
+
+@node Reserved words, , Comments, Language Structure
+@c German node Reservierte Wörter
+@subsection Ist MySQL pingelig hinsichtlich reservierter Wörter?
+
+@cindex Schlüsselwörter
+@cindex reservierte Wörter, Ausnahmen
+
+Ein häufiges Problem rührt daher, dass versucht wird, eine Tabelle mit
+Spaltennamen zu erzeugen, den die Namen von Datentypen oder in MySQL
+eingebauten Funktionen entsprechen, wie @code{TIMESTAMP} oder @code{GROUP}.
+Sie dürfen das tun (beispielsweise ist @code{ABS} ein zulässiger
+Spaltenname), aber es sind dann keine Leerzeichen zwischen einem
+Funktionsname und der @samp{(} erlaubt, wenn Sie Funktionen benutzen, deren
+Namen auch Spaltennamen sind.
+
+Folgende Wörter sind in MySQL explizit reserviert. Die meisten davon sind
+in ANSI-SQL92 als Spalten- und / oder Tabellennamen verboten (zum Beispiel
+@code{group}). Einige wenige sind reserviert, weil MySQL sie benötigt und
+(momentan) einen @code{yacc}-Parser benutzt:
+
+@c This ist fixed von including the symbols Tabelle von lex.h here und then running
+@c fix-mysql-reserved-words in emacs (or let David do it):
+@c (defun fix-mysql-reserved-words ()
+@c (interactive)
+@c (let ((cnt 0))
+@c (insert "\n@item ")
+@c (while (looking-at "[ \t]*{ +\"\\([^\"]+\\)\"[ \t]*,.*\n")
+@c (replace-match "@code{\\1}")
+@c (incf cnt)
+@c (if (> cnt 3)
+@c (progn
+@c (setf cnt 0)
+@c (insert "\n@item "))
+@c (insert " @tab ")))))
+@c But remove the non alphanumeric Einträge von Hand first.
+@c Updated after 3.23.4 990928 von David
+
+@multitable @columnfractions .25 .25 .25 .25
+@item @code{action} @tab @code{add} @tab @code{aggregate} @tab @code{all}
+@item @code{alter} @tab @code{after} @tab @code{and} @tab @code{as}
+@item @code{asc} @tab @code{avg} @tab @code{avg_row_length} @tab @code{auto_increment}
+@item @code{between} @tab @code{bigint} @tab @code{bit} @tab @code{binary}
+@item @code{blob} @tab @code{bool} @tab @code{both} @tab @code{by}
+@item @code{cascade} @tab @code{case} @tab @code{char} @tab @code{character}
+@item @code{change} @tab @code{check} @tab @code{checksum} @tab @code{column}
+@item @code{columns} @tab @code{comment} @tab @code{constraint} @tab @code{create}
+@item @code{cross} @tab @code{current_date} @tab @code{current_time} @tab @code{current_timestamp}
+@item @code{data} @tab @code{database} @tab @code{databases} @tab @code{date}
+@item @code{datetime} @tab @code{day} @tab @code{day_hour} @tab @code{day_minute}
+@item @code{day_second} @tab @code{dayofmonth} @tab @code{dayofweek} @tab @code{dayofyear}
+@item @code{dec} @tab @code{decimal} @tab @code{default} @tab @code{delayed}
+@item @code{delay_key_write} @tab @code{delete} @tab @code{desc} @tab @code{describe}
+@item @code{distinct} @tab @code{distinctrow} @tab @code{double} @tab @code{drop}
+@item @code{end} @tab @code{else} @tab @code{escape} @tab @code{escaped}
+@item @code{enclosed} @tab @code{enum} @tab @code{explain} @tab @code{exists}
+@item @code{fields} @tab @code{file} @tab @code{first} @tab @code{float}
+@item @code{float4} @tab @code{float8} @tab @code{flush} @tab @code{foreign}
+@item @code{from} @tab @code{for} @tab @code{full} @tab @code{Funktion}
+@item @code{global} @tab @code{grant} @tab @code{grants} @tab @code{group}
+@item @code{having} @tab @code{heap} @tab @code{high_priority} @tab @code{hour}
+@item @code{hour_minute} @tab @code{hour_second} @tab @code{hosts} @tab @code{identified}
+@item @code{ignore} @tab @code{in} @tab @code{index} @tab @code{infile}
+@item @code{inner} @tab @code{insert} @tab @code{insert_id} @tab @code{int}
+@item @code{integer} @tab @code{interval} @tab @code{int1} @tab @code{int2}
+@item @code{int3} @tab @code{int4} @tab @code{int8} @tab @code{into}
+@item @code{if} @tab @code{is} @tab @code{isam} @tab @code{join}
+@item @code{key} @tab @code{keys} @tab @code{kill} @tab @code{last_insert_id}
+@item @code{leading} @tab @code{left} @tab @code{length} @tab @code{like}
+@item @code{lines} @tab @code{limit} @tab @code{load} @tab @code{local}
+@item @code{lock} @tab @code{logs} @tab @code{long} @tab @code{longblob}
+@item @code{longtext} @tab @code{low_priority} @tab @code{max} @tab @code{max_rows}
+@item @code{match} @tab @code{mediumblob} @tab @code{mediumtext} @tab @code{mediumint}
+@item @code{middleint} @tab @code{min_rows} @tab @code{minute} @tab @code{minute_second}
+@item @code{modify} @tab @code{month} @tab @code{monthname} @tab @code{myisam}
+@item @code{natural} @tab @code{numeric} @tab @code{no} @tab @code{not}
+@item @code{null} @tab @code{on} @tab @code{optimize} @tab @code{option}
+@item @code{optionally} @tab @code{or} @tab @code{order} @tab @code{outer}
+@item @code{outfile} @tab @code{pack_keys} @tab @code{partial} @tab @code{password}
+@item @code{precision} @tab @code{primary} @tab @code{procedure} @tab @code{process}
+@item @code{processlist} @tab @code{privileges} @tab @code{read} @tab @code{real}
+@item @code{references} @tab @code{reload} @tab @code{regexp} @tab @code{rename}
+@item @code{replace} @tab @code{restrict} @tab @code{returns} @tab @code{revoke}
+@item @code{rlike} @tab @code{row} @tab @code{rows} @tab @code{second}
+@item @code{select} @tab @code{set} @tab @code{show} @tab @code{shutdown}
+@item @code{smallint} @tab @code{soname} @tab @code{sql_big_tables} @tab @code{sql_big_selects}
+@item @code{sql_low_priority_updates} @tab @code{sql_log_off} @tab @code{sql_log_update} @tab @code{sql_select_limit}
+@item @code{sql_small_result} @tab @code{sql_big_result} @tab @code{sql_warnings} @tab @code{straight_join}
+@item @code{starting} @tab @code{status} @tab @code{string} @tab @code{table}
+@item @code{tables} @tab @code{temporary} @tab @code{terminated} @tab @code{text}
+@item @code{then} @tab @code{time} @tab @code{timestamp} @tab @code{tinyblob}
+@item @code{tinytext} @tab @code{tinyint} @tab @code{trailing} @tab @code{to}
+@item @code{type} @tab @code{use} @tab @code{using} @tab @code{unique}
+@item @code{unlock} @tab @code{unsigned} @tab @code{update} @tab @code{usage}
+@item @code{values} @tab @code{varchar} @tab @code{variables} @tab @code{varying}
+@item @code{varbinary} @tab @code{mit} @tab @code{write} @tab @code{when}
+@item @code{where} @tab @code{year} @tab @code{year_month} @tab @code{zerofill}
+@end multitable
+
+Folgende Symbole (aus der obigen Tabelle) sind von ANSI-SQL verboten, aber
+von MySQL als Spalten- und Tabellennamen zugelassen. Der Grund ist, dass
+einige davon sehr natürliche Namen sind und viele Leute diese bereits in
+Benutzung haben.
+
+@itemize @bullet
+@item @code{ACTION}
+@item @code{BIT}
+@item @code{DATE}
+@item @code{ENUM}
+@item @code{NO}
+@item @code{TEXT}
+@item @code{TIME}
+@item @code{TIMESTAMP}
+@end itemize
+
+
+@node Column types, Functions, Language Structure, Reference
+@c German node Spaltentypen
+@section Spaltentypen
+
+@cindex Spalten, Typen
+@cindex Typen, Spalten
+
+MySQL unterstützt eine Reihe von Spaltentypen, die in drei Kategorien
+eingeteilt werden können: numerische Typen, Datums- und Zeit-Typen und
+Zeichenketten-Typen. Dieser Abschnitt gibt zuerst einen Überblick über die
+verfügbaren Typen und fasst den Speicherbedarf jedes Spaltentyps zusammen.
+Danach folgt eine detaillierter Beschreibung der Eigenschaften der Typen
+jeder Kategorie. Die detailliertere Beschreibung sollte wegen zusätzlicher
+Informationen über bestimmte Spaltentypen herangezogen werden, wie zu den
+erlaubten Formaten, in denen Sie Werte festlegen können.
+
+Die von MySQL unterstützten Spaltentypen sind unten aufgeführt. Folgende
+Code-Buchstaben werden in der Beschreibung benutzt:
+
+@cindex Anzeigebreite
+@cindex Größe, Anzeigebreite
+@cindex Ziffern
+@cindex Dezimalpunkt
+@cindex Klammern, eckige
+@cindex eckige Klammern
+@table @code
+@item M
+Gibt die maximale Anzeigebreite an. Die größte erlaubte Anzeigebreite ist
+255.
+
+@item D
+Trifft auf Fließkomma-Typen zu und bezeichnet die Anzahl von Ziffern nach
+dem Dezimalpunkt. Der größte mögliche Wert ist 30, aber er sollte nicht
+größer sein als @code{M}-2.
+@end table
+
+Eckige Klammern (@samp{[} und @samp{]}) geben Teile der Typ-Festlegung an,
+die optional sind.
+
+@tindex Typen
+
+@c The @w{-Anzahl} stuff keeps a linebreak von occurring between
+@c the - und Anzahl.
+
+Wenn Sie @code{ZEROFILL} für eine Spalte angeben, beachten Sie, dass MySQL
+der Spalte automatisch ein @code{UNSIGNED}-Attribut hinzufügt.
+
+@table @code
+@tindex TINYINT
+@item TINYINT[(M)] [UNSIGNED] [ZEROFILL]
+
+Eine sehr kleine Ganzzahl. Der vorzeichenbehaftete Bereich ist @code{-128}
+bis @code{127}. Der vorzeichenlose Bereich ist @code{0} to @code{255}.
+
+@tindex SMALLINT
+@item SMALLINT[(M)] [UNSIGNED] [ZEROFILL]
+
+Eine kleine Ganzzahl. Der vorzeichenbehaftete Bereich ist @code{-32768} bis
+@code{32767}. Der vorzeichenlose Bereich ist @code{0} bis @code{65535}.
+
+@tindex MEDIUMINT
+@item MEDIUMINT[(M)] [UNSIGNED] [ZEROFILL]
+
+A Ganzzahl mittlerer Größe. Der vorzeichenbehaftete Bereich ist
+@code{-8388608} bis @code{8388607}. Der vorzeichenlose Bereich ist @code{0}
+bis @code{16777215}.
+
+@tindex INT
+@item INT[(M)] [UNSIGNED] [ZEROFILL]
+
+Eine Ganzzahl normaler Größe. Der vorzeichenbehaftete Bereich ist
+@code{-2147483648} bis @code{2147483647}. Der vorzeichenlose Bereich ist
+@code{0} bis @code{4294967295}.
+
+@tindex INTEGER
+@item INTEGER[(M)] [UNSIGNED] [ZEROFILL]
+
+Ein Synonym für @code{INT}.
+
+@tindex BIGINT
+@item BIGINT[(M)] [UNSIGNED] [ZEROFILL]
+
+Eine große Ganzzahl. Der vorzeichenbehaftete Bereich ist
+@code{-9223372036854775808} bis @code{9223372036854775807}. Der
+vorzeichenlose Bereich ist @code{0} bis @code{18446744073709551615}.
+
+Einiger Dinge sollten Sie sich bei @code{BIGINT}-Spalten bewusst sein:
+
+@itemize @bullet
+@item
+@cindex Rundungsfehler
+Weil alle arithmetischen Berechnungen mit vorzeichenbehafteten
+@code{BIGINT}- oder @code{DOUBLE}-Werten durchgeführt werden, sollten Sie
+keine vorzeichenlosen Ganzzahlen größer als @code{9223372036854775807} (63
+Bits) benutzen, ausser bei Bit-Funktionen! Wenn Sie das doch tun, können
+einige der letzten Ziffern im Ergebnis falsch sein, weil Rundungsfehler
+beim Umwandeln von @code{BIGINT} in @code{DOUBLE} auftreten.
+
+MySQL 4.0 kann @code{BIGINT} in folgenden Fällen handhaben:
+@itemize @bullet
+@item
+Benutzen Sie Ganzzahlen, um große vorzeichenlose Wert in einer
+@code{BIGINT}-Spalte zu speichern.
+@item
+Bei @code{MIN(große_ganzzahl_spalte)} und
+@code{MAX(große_ganzzahl_spalte)}.
+@item
+Bei der Benutzung der Operatoren (@code{+}, @code{-}, @code{*} usw.), wenn
+beide Operanden Ganzzahlen sind.
+@end itemize
+
+@item
+Sie können immer einen genauen Ganzzahlwert in einer @code{BIGINT}-Spalte
+speichern, wenn Sie sie als Zeichenkette speichern, denn in diesem Fall
+wird diese nicht zwischendurch als Double dargestellt.
+@item
+@samp{-}, @samp{+} und @samp{*} benutzen arithmetische
+@code{BIGINT}-Berechnungen, wenn beide Argumente @code{INTEGER}-Werte sind!
+Das heißt, wenn Sie zwei Ganzzahlen multiplizieren (oder Ergebnisse von
+Funktionen, die Ganzzahlen zurückgeben), erhalten Sie vielleicht
+unerwartete Ergebnisse, wenn das Ergebnis größer als
+@code{9223372036854775807} ist.
+@end itemize
+
+@cindex Fließkommazahl
+@tindex FLOAT
+@tindex FLOAT(genauigkeit)
+@item FLOAT(genauigkeit) [ZEROFILL]
+
+Eine Fließkommazahl. Kann nicht vorzeichenlos sein. @code{genauigkeit} ist
+@code{<=24} bei einer Fließkommazahl einfacher Genauigkeit und zwischen 25
+und 53 bei einer Fließkommazahl doppelter Genauigkeit. Diese Typen sind
+wie die unten beschriebenen @code{FLOAT} und @code{DOUBLE}-Typen.
+@code{FLOAT(X)} hat denselben Wertebereich wie die entsprechenden
+@code{FLOAT}- und @code{DOUBLE}-Typen, jedoch ist die Anzeigebreite und die
+Anzahl der Dezimalstellen undefiniert.
+
+In MySQL-Version 3.23 ist das ein echter Fließkommawert. In früheren
+MySQL-Versionen hat @code{FLOAT(genauigkeit)} immer 2 Dezimalstellen.
+
+Beachten Sie, dass bei der Benutzung von @code{FLOAT} unerwartete Probleme
+auftreten können, weil alle Berechnungen in MySQL mit doppelter Genauigkeit
+durchgeführt werden. @xref{No matching rows}.
+
+@cindex ODBC-Kompatibilität
+@cindex Kompatibilität, mit ODBC
+Diese Syntax steht wegen der ODBC-Kompatibilität zur Verfügung.
+
+@tindex FLOAT
+@tindex FLOAT(M,D)
+@item FLOAT[(M,D)] [ZEROFILL]
+
+Eine kleine Fließkommazahl (einfacher Genauigkeit). Kann nicht
+vorzeichenlos sein. Der Wertebereich umfasst @code{@w{-3.402823466E+38}}
+bis @code{@w{-1.175494351E-38}}, @code{0} und @code{@w{1.175494351E-38}}
+bis @code{3.402823466E+38}. M ist die Anzeigebreite und D ist die Anzahl
+von Dezimalstellen. @code{FLOAT} ohne Argument oder mit einem Argument <=
+24 steht für eine Fließkommazahl einfacher Genauigkeit.
+
+@tindex DOUBLE
+@tindex FLOAT(genauigkeit)
+@item DOUBLE[(M,D)] [ZEROFILL]
+
+Eine normal große Fließkommazahl (doppelter Genauigkeit). Kann nicht
+vorzeichenlos sein. Der Wertebereich umfasst
+@code{@w{-1.7976931348623157E+308}} bis
+@code{@w{-2.2250738585072014E-308}}, @code{0} und
+@code{2.2250738585072014E-308} bis @code{1.7976931348623157E+308}. M ist
+die Anzeigebreite und D ist die Anzahl von Dezimalstellen. @code{DOUBLE}
+ohne Argument oder @code{FLOAT(X)} mit 25 <= X <= 53 steht für eine
+Fließkommazahl doppelter Genauigkeit.
+
+@tindex DOUBLE PRECISION
+@tindex REAL
+@item DOUBLE PRECISION[(M,D)] [ZEROFILL]
+@itemx REAL[(M,D)] [ZEROFILL]
+
+Synonyme für @code{DOUBLE}.
+
+@tindex DECIMAL
+@item DECIMAL[(M[,D])] [ZEROFILL]
+
+Eine unkomprimierte Fließkommazahl. Kann nicht vorzeichenlos sein. Verhält
+sich wie eine @code{CHAR}-Spalte: ``Unkomprimiert'' bedeutet, dass die Zahl
+als Zeichenkette gespeichert wird, wobei ein Zeichen für jede Ziffer des
+Wertes steht. Der Dezimalpunkt und, bei negativen Zahlen, das
+@samp{-}-Zeichen, werden in M nicht mitgezählt (aber hierfür wird Platz
+reserviert). Wenn @code{D} 0 ist, haben Werte keinen Dezimalpunkt oder
+Bruchteil. Der maximale Wertebereich von @code{DECIMAL}-Werte ist derselbe
+wie für @code{DOUBLE}, aber der tatsächliche Wertebereich einer gegebenen
+@code{DECIMAL}-Spalte kann durch die Auswahl von @code{M} und @code{D}
+eingeschränkt sein.
+
+Wenn @code{D} weggelassen wird, wird es auf 0 gesetzt. Wenn @code{M}
+ausgelassen wird, wird es auf 10 gesetzt.
+
+Beachten Sie, dass in MySQL-Version 3.22 das @code{M}-Argument den Platz
+für das Vorzeichen und den Dezimalpunkt beinhaltete!
+
+@tindex NUMERIC
+@item NUMERIC(M,D) [ZEROFILL]
+
+Synonym für @code{DECIMAL}.
+
+@tindex DATE
+@item DATE
+
+Ein Datum. Der unterstützte Wertebereich ist @code{'1000-01-01'} bis
+@code{'9999-12-31'}. MySQL zeigt @code{DATE}-Werte im
+@code{'YYYY-MM-DD'}-Format an, gestattet jedoch, @code{DATE}-Spalten Werte
+entweder als Zeichenketten oder als Zahlen zuzuweisen. @xref{DATETIME}.
+
+@tindex DATETIME
+@item DATETIME
+
+Eine Datums-/Zeit-Kombination. Der unterstützte Wertebereich ist
+@code{'1000-01-01 00:00:00'} bis @code{'9999-12-31 23:59:59'}. MySQL zeigt
+@code{DATETIME}-Werte im @code{'YYYY-MM-DD HH:MM:SS'}-Format an, gestattet
+jedoch, @code{DATETIME}-Spalten Werte entweder als Zeichenketten oder als
+Zahlen zuzuweisen.
+@xref{DATETIME}.
+
+@tindex TIMESTAMP
+@item TIMESTAMP[(M)]
+
+Ein Zeitstempel. Der Wertebereich ist @code{'1970-01-01 00:00:00'} bis
+irgendwann im Jahr @code{2037}. MySQL zeigt @code{TIMESTAMP}-Werte im
+@code{YYYYMMDDHHMMSS}-, @code{YYMMDDHHMMSS}-, @code{YYYYMMDD}- oder
+@code{YYMMDD}-Format an, abhängig davon, ob @code{M} @code{14} (oder
+fehlend), @code{12}, @code{8} oder @code{6} ist, gestattet aber, dass Sie
+@code{TIMESTAMP}-Spalten Werte entweder als Zeichenketten oder als Zahlen
+zuweisen. Eine @code{TIMESTAMP}-Spalte ist nützlich, um Datum und Zeit
+einer @code{INSERT}- oder @code{UPDATE}-Operation zu speichern, weil sie
+automatisch auf das Datum und die Zeit der jüngsten Operation gesetzt wird,
+wenn Sie nicht selbst einen Wert zuweisen. Sie können sie auch auf das
+aktuelle Datum und die aktuelle Zeit setzen, indem Sie einen
+@code{NULL}-Wert zuweisen. @xref{Date and time types}.
+
+Ein @code{TIMESTAMP} wird immer mit 4 Bytes gespeichert. Das
+@code{M}-Argument betrifft nur die Anzeige der @code{TIMESTAMP}-Spalte.
+
+Beachten Sie, dass @code{TIMESTAMP(X)}-Spalten, bei denen X 8 oder 14 ist,
+als Zahlen interpretiert werden, während andere @code{TIMESTAMP(X)}-Spalten
+als Zeichenketten interpretiert werden. Das soll lediglich sicherstellen,
+dass Sie Tabellen mit diesen Typen verlässlich dumpen und wiederherstellen
+können! @xref{DATETIME}.
+
+@tindex TIME
+@item TIME
+
+Ein Zeit-Typ. Der Wertebereich ist @code{'-838:59:59'} bis
+@code{'838:59:59'}. MySQL zeigt @code{TIME}-Werte im
+@code{'HH:MM:SS'}-Format an, gestattet aber, @code{TIME}-Spalten Werte
+entweder als Zeichenketten oder als Zahlen zuweisen. @xref{TIME}.
+
+@tindex YEAR
+@item YEAR[(2|4)]
+
+Ein Jahr in 2- oder 4-Ziffernformat (Vorgabe ist 4-Ziffern). Die zulässigen
+Werte reichen von @code{1901} bis @code{2155} sowie @code{0000} im
+4-Ziffern-Jahresformat, und von 1970 bis 2069 beim 2-Ziffernformat (70 bis
+69). MySQL zeigt @code{YEAR}-Werte im @code{YYYY}-Format an, gestattet
+aber, @code{YEAR}-Spalten Werte entweder als Zeichenketten oder als Zahlen
+zuweisen. (Der @code{YEAR}-Typ ist neu seit MySQL-Version 3.22.).
+@xref{YEAR}.
+
+@tindex NATIONAL CHAR
+@tindex NCHAR
+@tindex CHAR
+@tindex CHARACTER
+@item [NATIONAL] CHAR(M) [BINARY]
+
+Eine Zeichenkette fester Länge, die beim Speichern rechts stets mit
+Leerzeichen bis zur angegebenen Länge aufgefüllt wird. Der Wertebereich von
+@code{M} ist 1 bis 255 Zeichen. Leerzeichen am Ende werden beim Abruf des
+Wertes entfernt. @code{CHAR}-Werte werden nach dem vorgabemäßigen
+Zeichensatz ohne Berücksichtigung der Groß-/Kleinschreibung sortiert und
+verglichen, es sei denn, dass Schlüsselwort @code{BINARY} wird angegeben.
+
+@code{NATIONAL CHAR} (Kurzform @code{NCHAR}) ist die Art, wie ANSI-SQL bei
+einer CHAR-Spalte festlegt, dass der vorgabemäßige Zeichensatz verwendet
+werden soll. Das ist der Vorgabewert in MySQL.
+
+@code{CHAR} ist eine Abkürzung für @code{CHARACTER}.
+
+MySQL erlaubt das Anlegen einer Spalte des Typs @code{CHAR(0)}. Das ist
+hauptsächlich nützlich, wenn Sie mit alten Applikationen kompatibel sein
+müssen, die auf die Existenz einer Spalte vertrauen, den Wert aber nicht
+tatsächlich benutzen. Es ist ebenfalls nett, um eine Spalte anzulegen, die
+nur 2 Werte annehmen kann: Eine @code{CHAR(0)}, die nicht als @code{NOT
+NULL} definiert ist, belegt nur 1 Bit und kann 2 Werte annehmen:
+@code{NULL} oder @code{""}. @xref{CHAR}.
+
+@tindex CHARACTER VARYING
+@tindex CHAR VARYING
+@tindex VARCHAR
+@item [NATIONAL] VARCHAR(M) [BINARY]
+
+Eine Zeichenkette variabler Länge. @strong{HINWEIS:} Leerzeichen am Ende
+werden bei der Speicherung des Wertes entfernt (das unterscheidet den Typ
+von der ANSI-SQL-Spezifikation). Der Wertebereich von @code{M} ist 1 bis
+255 Zeichen. @code{VARCHAR}-Werte werden nach dem vorgabemäßigen
+Zeichensatz ohne Berücksichtigung der Groß-/Kleinschreibung sortiert und
+verglichen, es sei denn, dass Schlüsselwort @code{BINARY} wird angegeben.
+@xref{Silent column changes}.
+
+@code{VARCHAR} ist eine Abkürzung für @code{CHARACTER VARYING}.
+@xref{CHAR}.
+
+@tindex TINYBLOB
+@tindex TINYTEXT
+@item TINYBLOB
+@itemx TINYTEXT
+
+Eine @code{BLOB}- oder @code{TEXT}-Spalte mit einer maximalen Länge von 255
+(2^8 - 1) Zeichen. @xref{Silent column changes}. @xref{BLOB}.
+
+@tindex BLOB
+@tindex TEXT
+@item BLOB
+@itemx TEXT
+
+Eine @code{BLOB}- oder @code{TEXT}-Spalte mit einer maximalen Länge von
+65535 (2^16 - 1) Zeichen. @xref{Silent column changes}. @xref{BLOB}.
+
+@tindex MEDIUMBLOB
+@tindex MEDIUMTEXT
+@item MEDIUMBLOB
+@itemx MEDIUMTEXT
+
+Eine @code{BLOB}- oder @code{TEXT}-Spalte mit einer maximalen Länge von
+16777215 (2^24 - 1) Zeichen. @xref{Silent column changes}.
+@xref{BLOB}.
+
+@tindex LONGBLOB
+@tindex LONGTEXT
+@item LONGBLOB
+@itemx LONGTEXT
+
+Eine @code{BLOB}- oder @code{TEXT}-Spalte mit einer maximalen Länge von
+4294967295 (2^32 - 1) Zeichen. @xref{Silent column changes}.
+Beachten Sie, dass Sie nicht den gesamten Wertebereich dieses Typs benutzen
+können, weil das Client-Server-Protokoll und MyISAM-Tabellen momentan eine
+Beschränkungen auf 16 MB pro Kommunikationspaket / Tabellenzeile haben.
+@xref{BLOB}.
+
+@tindex ENUM
+@item ENUM('wert1','wert2',...)
+
+An Aufzählung. Ein Zeichenkettenobjekt, das nur einen Wert haben kann, der
+aus den Auflistungswerten @code{'wert1'}, @code{'wert2'}, @code{...},
+@code{NULL} oder dem speziellen @code{""}-Fehlerwert ausgewählt wird. Eine
+@code{ENUM} kann maximal 65535 unterschiedliche Werte haben. @xref{ENUM}.
+
+@tindex SET
+@item SET('wert1','wert2',...)
+
+Eine Reihe. Ein Zeichenkettenobjekt, das 0 oder mehr Werte haben kann, von
+denen jeder aus den Auflistungswerten @code{'wert1'}, @code{'wert2'},
+@code{...} ausgewählt werden muss. Eine @code{SET} kann maximal 64 Elemente
+haben. @xref{SET}.
+@end table
+
+
+
+@menu
+* Numeric types::
+* Date and time types::
+* String types::
+* Choosing types::
+* Other-vendor column types::
+* Storage requirements::
+@end menu
+
+@node Numeric types, Date and time types, Column types, Column types
+@c German node Numerische Typen
+@subsection Numerische Typen
+
+MySQL unterstützt alle numerischen Typen von ANSI/ISO-SQL92. Diese Typen
+beinhalten die exakten numerischen Datentypen (@code{NUMERIC},
+@code{DECIMAL}, @code{INTEGER} und @code{SMALLINT}) sowie die
+näherungsweisen numerischen Datentypen (@code{FLOAT}, @code{REAL} und
+@code{DOUBLE PRECISION}). Das Schlüsselwort @code{INT} ist ein Synonym für
+@code{INTEGER} und das Schlüsselwort @code{DEC} ist ein Synonym für
+@code{DECIMAL}.
+
+Die @code{NUMERIC}- und @code{DECIMAL}-Typen sind in MySQL als derselbe Typ
+implementiert, wie es vom SQL92-Standard zugelassen ist. Sie werden für
+Werte benutzt, bei denen es wichtig ist, die exakte Genauigkeit zu
+bewahren, zum Beispiel bei monetären Daten. Wenn Sie eine Spalte mit einem
+dieser Typen deklarieren, können Genauigkeit und Bereich festgelegt werden
+(und werden das üblicherweise auch). Beispiel:
+
+@example
+ gehalt DECIMAL(9,2)
+@end example
+
+In diesem Beispiel repräsentiert @code{9} (@code{genauigkeit}) die Anzahl
+signifikanter Dezimalziffern, die für Werte gespeichert werden, und
+@code{2} (@code{bereich}) repräsentiert die Anzahl von Ziffern, die nach
+dem Dezimalpunkt gespeichert werden. In diesem Fall liegt der Wertebereich,
+der in der @code{gehalt}-Spalte gespeichert werden kann, deswegen zwischen
+@code{-9999999.99} und @code{9999999.99}.
+(MySQL kann tatsächlich Zahlen bis zu @code{9999999.99} in dieser Spalte
+speichern, weil er nicht das Vorzeichen für positive Zahlen speichern
+muss).
+
+In ANSI/ISO-SQL92 ist die Syntax @code{DECIMAL(p)} äquivalent zu
+@code{DECIMAL(p,0)}. Gleichermaßen ist die Syntax @code{DECIMAL}
+äquivalent zu @code{DECIMAL(p,0)}, wobei es der Implementation überlassen
+bleibt, den Wert von @code{p} festzulegen. MySQL unterstützt momentan keine
+dieser abweichenden Formen der @code{DECIMAL}- / @code{NUMERIC}-Datentypen.
+Das ist im Allgemeinen kein ernstes Problem, weil der hauptsächliche Nutzen
+dieser Typen darin liegt, sowohl Genauigkeit als auch Bereich explizit
+steuern zu können.
+
+@code{DECIMAL}- und @code{NUMERIC}-Werte sind als Zeichenketten gespeichert
+statt als Fließkommazahlen, um die dezimale Genauigkeit dieser Werte zu
+bewahren. Ein Zeichen wird benutzt für jede Ziffer des Werts, den
+Dezimalpunkt (wenn @code{bereich} > 0) und das @samp{-}-Zeichen (für
+negative Zahlen). Wenn @code{bereich} 0 ist, enthalten @code{DECIMAL}- und
+@code{NUMERIC}-Werte weder Dezimalpunkt noch Bruchteil.
+
+Der maximale Wertebereich von @code{DECIMAL}- und @code{NUMERIC}-Werten ist
+derselbe wie für @code{DOUBLE}, aber der tatsächliche Wertebereich einer
+gegebenen @code{DECIMAL}- oder @code{NUMERIC}-Spalte kann durch
+@code{genauigkeit} oder @code{bereich} für eine gegebene Spalte beschränkt
+werden. Wenn einer solchen Spalte ein Wert mit mehr Ziffern nach dem
+Dezimalpunkt zugewiesen wird, als durch @code{bereich} zugelassen, wird der
+Wert auf diesen @code{bereich} gerundet. Wenn einer @code{DECIMAL}- oder
+@code{NUMERIC}-Spalte ein Wert zugewiesen wird, dessen Größe den
+Wertebereich überschreitet, der von der festgelegten (oder vorgabemäßigen)
+@code{genauigkeit} und @code{bereich} festgelegt wird, speichert MySQL den
+Wert des entsprechenden Endpunkts des Wertebereichs.
+
+Als Erweiterung zum ANSI/ISO-SQL92-Standard unterstützt MySQL auch die
+Ganzzahltypen @code{TINYINT}, @code{MEDIUMINT} und @code{BIGINT}, wie oben
+aufgelistet. Ein andere Erweiterung wird von MySQL unterstützt, um optional
+die Anzeigebreite eines Ganzzahlwerts in Klammern festzulegen, die auf das
+Basis-Schlüsselwort des Typs folgen (zum Beispiel @code{INT(4)}). Die
+optionale Breitenspezifizierung wird benutzt, um die Anzeige von Werten,
+deren Breite geringer ist als für die Spalte festgelegt, linksseitig mit
+Leerzeichen aufzufüllen. Das begrenzt allerdings nicht den Wertebereich,
+der in der Spalte gespeichert werden kann, noch die Anzahl von Ziffern, die
+bei Werten angezeigt werden, die die angegebene Breite für die Spalte
+überschreiten. In Verbindung mit dem optionalen Erweiterungsattribut
+@code{ZEROFILL} wird - statt vorgabemäßig mit Leerzeichen - mit Nullen
+aufgefüllt. Bei einer Spalte zum Beispiel, die als @code{INT(5) ZEROFILL}
+deklariert wurde, wird @code{4} als @code{00004} dargestellt. Beachten Sie,
+dass Werte in einer Ganzzahlspalte, die größer sind als die Anzeigebreite,
+Probleme bei der Erzeugung temporärer Tabellen für einige komplizierte
+Joins durch MySQL auftreten können, weil MySQL in diesen Fällen darauf
+vertraut, dass die Daten in die Original-Spaltenbreite passten.
+
+Alle Ganzzahl-Typen können ein optionales (Nicht-Standard-) Attribut
+@code{UNSIGNED} haben. Vorzeichenlose Werte können dafür benutzt werden,
+nur positive Zahlen in einer Spalte zuzulassen, wenn Sie eine Wertebereich
+brauchen, der etwas größer ausfällt.
+
+Der @code{FLOAT}-Typ wird benutzt, um näherungsweise numerische Datentypen
+zu repräsentieren. Der ANSI/ISO-SQL92-Standard erlaubt eine optionale
+Festlegung der Genauigkeit (aber nicht den Wertebereich des Exponenten) in
+Bits, gefolgt vom Schlüsselwort @code{FLOAT} in Klammern. Die
+MySQL-Implementation unterstützt ebenfalls diese optionale
+Genauigkeitsfestlegung. Wenn das Schlüsselwort @code{FLOAT} für einen
+Spaltentyp ohne Genauigkeitsfestlegung benutzt wird, benutzt MySQL 4 Bytes,
+um die Werte zu speichern. Eine abweichende Syntax wird ebenfalls
+unterstützt, wobei zwei Zahlen in Klammern dem @code{FLOAT}-Schlüsselwort
+folgen. Mit dieser Option legt die erste Zahl wie gehabt den Speicherbedarf
+für den Wert in Bytes fest, und die zweite Zahl legt die Anzahl von Ziffern
+fest, die nach dem Dezimalpunkt gespeichert und angezeigt werden sollen
+(wie bei @code{DECIMAL} und @code{NUMERIC}). Wenn MySQL in einer solchen
+Spalte einen Wert mit mehr Dezimalziffern nach dem Dezimalpunkt speichern
+soll als für die Spalte festgelegt, wird der Wert beim Speichern gerundet,
+um die zusätzlichen Ziffern zu entfernen.
+
+Die @code{REAL}- und @code{DOUBLE PRECISION}-Typen akzeptieren keine
+Genauigkeitsfestlegungen. Als Erweiterung zum ANSI/ISO-SQL92-Standard
+erkennt MySQL @code{DOUBLE} als ein Synonym für den @code{DOUBLE
+PRECISION}-Typ. Im Gegensatz zur Anforderung des Standard, dass die
+Genauigkeit für @code{REAL} kleiner sein muss als die für @code{DOUBLE
+PRECISION}, implementiert MySQL beide als 8-Byte-Fließkommawerte doppelter
+Genauigkeit (wenn er nicht im ``ANSI-Modus'' läuft). Für maximale
+Portabilität sollte Code, der die Speicherung näherungsweiser numerischer
+Daten erfordert, @code{FLOAT} oder @code{DOUBLE PRECISION} ohne Festlegung
+der Genauigkeit oder Anzahl von Dezimalstellen benutzen.
+
+Wenn ein Wert in einer numerischen Spalte gespeichert werden soll, der
+ausserhalb des erlaubten Wertebereichs des Spaltentyps ist, schneidet MySQL
+den Wert auf den entsprechenden Endpunkt des Wertebereichs ab und speichert
+statt dessen diesen Wert.
+
+Der Wertebereich einer @code{INT}-Spalte ist zum Beispiel
+@code{-2147483648} bis @code{2147483647}. Wenn Sie versuchen,
+@code{-9999999999} in eine @code{INT}-Spalte einzufügen, wird der Wert auf
+den unteren Endpunkt des Bereichs abgeschnitten, und es wird
+@code{-2147483648} gespeichert. Gleichermaßen wird beim Einfügen in eine
+solche Spalte nicht @code{9999999999}, sondern @code{2147483647}
+gespeichert.
+
+Wenn die @code{INT}-Spalte @code{UNSIGNED} ist, ist die Größe des
+Wertebereichs dieselbe, aber ihre Endpunkte verschieben sich zu @code{0}
+und @code{4294967295}. Wenn Sie versuchen, @code{-9999999999} bzw.
+@code{9999999999} zu speichern, werden die in der Spalte gespeicherten
+Werte statt dessen zu @code{0} bzw. @code{4294967296}.
+
+Umwandlungen, die aufgrund von Abschneiden geschehen, werden als
+``Warnungen'' bei @code{ALTER TABLE}, @code{LOAD DATA INFILE},
+@code{UPDATE} und in mehrzeiligen @code{INSERT}-Statements berichtet.
+
+
+@node Date and time types, String types, Numeric types, Column types
+@c German node Datums- und Zeit-Typen
+@subsection Datums- und Zeit-Typen
+
+@cindex Typen, Datum und Zeit
+@cindex Datums- und Zeit-Typen
+
+
+
+Die Datums- und Zeit-Typen sind @code{DATETIME}, @code{DATE},
+@code{TIMESTAMP}, @code{TIME} und @code{YEAR}. Jeder dieser Typen hat einen
+zulässigen Wertebereich sowie einen ``0''-Wert, der benutzt wird, wenn Sie
+einen wirklich unzulässigen Wert speichern. Beachten Sie, dass MySQL es
+zuläßt, dass Sie bestimmte 'nicht ganz' zulässige Datumswerte speichern,
+zum Beispiel @code{1999-11-31}. Der Grund hierfür ist, dass wir meinen,
+dass es in der Verantwortung der Applikation liegt, Datumsüberprüfungen
+vorzunehmen, und nicht beim SQL-Server. Um Datumsprüfungen 'schnell' zu
+machen, überprüft MySQL nur, dass der Monat im Bereich 0 bis 12 liegt und
+der Tag im Bereich 0 bis 31. Diese Bereiche sind deshalb so definiert, weil
+es MySQL zuläßt, dass Sie in einer @code{DATE}- oder
+@code{DATETIME}-Spalte Datumsangaben speichern, bei denen der Tag oder
+Monat-Tag 0 sind. Das ist extrem nützlich für Applikationen, die einen
+Geburtstag speichern müssen, dessen exaktes Datum unbekannt ist. In diesem
+Fall können Sie einfach Datumsangaben wie @code{1999-00-00} oder
+@code{1999-01-00} speichern. (Sie können nicht erwarten, von Funktionen wie
+@code{DATE_SUB()} oder @code{DATE_ADD} für solche Datumsangaben korrekte
+Werte zu erhalten.)
+
+Einige allgemeine Überlegungen, die man im Kopf behalten sollte, wenn man
+mit Datums- und Zeit-Typen arbeitet:
+
+@itemize @bullet
+@item
+MySQL ruft Werte für einen gegebenen Datums- oder Zeit-Typ in einem
+Standard-Format ab, versucht aber, eine Vielzahl von Formaten zu
+interpretieren, die Sie bereit stellen (wenn Sie zum Beispiel einen Wert
+angeben, der zugewiesen oder mit einem Datums- oder Zeit-Typ verglichen
+werden soll). Dennoch werden nur die in den folgenden Abschnitten
+beschriebenen Formate unterstützt. Es wird davon ausgegangen, dass Sie
+zulässige Werte bereitstellen; und es können unvorhersehbare Ergebnisse
+zustande kommen, wenn Sie Werte in anderen Formaten angeben.
+
+@item
+Obwohl MySQL versucht, Werte in verschiedenen Formaten zu interpretieren,
+erwartet er immer, dass der Jahresanteil von Datumswerten ganz links steht.
+Datumsangaben müssen in der Reihenfolge Jahr - Monat - Tag gemacht werden
+(zum Beispiel @code{'98-09-04'}) statt in der Reihenfolge Monat - Tag -
+Jahr oder Tag - Monat - Jahr, die anderswo häufig gebraucht werden (zum
+Beispiel @code{'09-04-98'}, @code{'04-09-98'}).
+
+@item
+MySQL wandelt einen Datums- oder Zeitwert automatisch in eine Zahl um, wenn
+der Wert in einem numerischen Zusammenhang benutzt wird, und umgekehrt.
+
+@item
+Wenn MySQL auf einen Datums- oder Zeitwert trifft, der ausserhalb des
+Wertebereichs oder in sonstiger Weise für den Typ nicht zulässig ist (siehe
+Anfang dieses Abschnitts), wird der Wert zum ``0''-Wert dieses Typs
+umgewandelt. (Die Ausnahme ist, dass @code{TIME}-Werte ausserhalb des
+Wertebereichs auf den entsprechenden Endpunkt des @code{TIME}-Wertebereichs
+abgeschnitten werden.) Die unten stehende Tabelle zeigt das Format des
+``0''-Werts für jeden Typ:
+
+@multitable @columnfractions .3 .7
+@item @strong{Spaltentyp} @tab @strong{``0''-Wert}
+@item @code{DATETIME} @tab @code{'0000-00-00 00:00:00'}
+@item @code{DATE} @tab @code{'0000-00-00'}
+@item @code{TIMESTAMP} @tab @code{00000000000000} (Länge abhängig von der Anzeigebreite)
+@item @code{TIME} @tab @code{'00:00:00'}
+@item @code{YEAR} @tab @code{0000}
+@end multitable
+
+@item
+Die ``0''-Werte sind speziell, aber Sie können diese explizit speichern
+oder auf sie verweisen, indem Sie die in der Tabelle dargestellten Werte
+benutzen. Sie können das auch mit den Werten @code{'0'} oder @code{0}
+machen, die leichter zu schreiben sind.
+
+@item
+``0''-Datums- oder -Zeitwerte, die über @strong{MyODBC} benutzt werden,
+werden in @strong{MyODBC}-Version 2.50.12 und höher automatisch in
+@code{NULL} umgewandelt, weil ODBC solche Werte nicht handhaben kann.
+@end itemize
+
+
+@menu
+* Y2K issues::
+* DATETIME::
+* TIME::
+* YEAR::
+@end menu
+
+@node Y2K issues, DATETIME, Date and time types, Date and time types
+@c German node Jahr 2000
+@subsubsection Jahr-2000-Probleme und Datumstypen
+
+@cindex Jahr-2000-Probleme
+@cindex Datumstypen, Jahr-2000-Probleme
+
+MySQL selbst ist Jahr-2000-konform (Jahr-2000-sicher,
+@pxref{Year 2000 compliance}), aber Eingabewerte, die an MySQL
+übergeben werden, sind das möglicherweise nicht. Jede Eingabe von
+Jahreswerten mit 2 Ziffern ist mehrdeutig, weil das Jahrhundert unbekannt
+ist. Solche Werte müssen in 4-stellige Form umgedeutet werden, weil MySQL
+Jahre intern mit 4 Ziffern speichert.
+
+Bei @code{DATETIME}-, @code{DATE}-, @code{TIMESTAMP}- und @code{YEAR}-Typen
+interpretiert MySQL Datumsangaben mit mehrdeutigen Jahreswerten nach
+folgenden Regeln:
+
+@itemize @bullet
+@item
+Jahreswerte im Bereich @code{00 bis 69} werden in @code{2000 bis 2069}
+umgewandelt.
+
+@item
+Jahreswerte im Bereich @code{70 bis 99} werden in @code{1970 bis 1999}
+umgewandelt.
+@end itemize
+
+Denken Sie daran, dass diese Regeln nur eine vernünftige Schätzung dessen
+bedeuten, was die Daten tatsächlich darstellen sollen. Wenn die von MySQL
+benutzten Heuristiken keine korrekten Werte ergeben, müssen Sie eindeutige
+Eingaben in Form 4-stelliger Jahreswerte bereit stellen.
+
+@code{ORDER BY} sortiert 2-stellige @code{YEAR/DATE/DATETIME}-Typen
+korrekt.
+
+Beachten Sie, dass einige Funktionen wie @code{MIN()} und @code{MAX()} ein
+@code{TIMESTAMP / DATE} in eine Zahl umwandeln. Das heißt, dass ein
+Zeitstempel mit einer 2-stelligen Jahresangabe bei diesen Funktionen nicht
+korrekt funktioniert. Das kann in diesem Fall dadurch behoben werden, dass
+der @code{TIMESTAMP / DATE} in ein 4-stelliges Jahresformat umgewandelt
+wird, oder etwas wie @code{MIN(DATE_ADD(zeitstempel,INTERVAL 0 DAYS))}
+benutzt wird.
+
+
+@node DATETIME, TIME, Y2K issues, Date and time types
+@c German node DATETIME
+@subsubsection Die @code{DATETIME}-, @code{DATE}- und @code{TIMESTAMP}-Typen
+
+@tindex DATETIME
+@tindex DATE
+@tindex TIMESTAMP
+
+Die @code{DATETIME}-, @code{DATE}- und @code{TIMESTAMP}-Typen sind
+verwandt. Dieser Abschnitt beschreibt ihre Charakteristiken, wo sie sich
+ähnlich sind und wo sie sich unterscheiden.
+
+Der @code{DATETIME}-Typ wird benutzt, wenn Sie Werte brauchen, die sowohl
+Datums- als auch Zeitinformationen beinhalten. MySQL ruft
+@code{DATETIME}-Werte ab und zeigt sie an im @code{'YYYY-MM-DD
+HH:MM:SS'}-Format. Der unterstützte Wertebereich ist @code{'1000-01-01
+00:00:00'} bis @code{'9999-12-31 23:59:59'}. (``Unterstützt'' heißt, dass
+frühere Werte zwar funktionieren können, dass es aber keine Garantie dafür
+gibt.)
+
+Der @code{DATE}-Typ wird benutzt, wenn Sie nur einen Datumswert brauchen,
+ohne Zeitanteil. MySQL ruft @code{DATE}-Werte ab und zeigt sie an im
+@code{'YYYY-MM-DD'}-Format. Der unterstützte Wertebereich ist
+@code{'1000-01-01'} bis @code{'9999-12-31'}.
+
+Der @code{TIMESTAMP}-Typ ist ein Typ, den Sie dafür benutzen können, um
+@code{INSERT}- oder @code{UPDATE}-Operationen mit dem aktuellen Datum und
+der aktuellen Zeit zu stempeln. Wenn Sie mehrfache @code{TIMESTAMP}-Spalten
+haben, wird nur die erste automatisch aktualisiert.
+
+Die automatische Aktualisierung der @code{TIMESTAMP}-Spalte geschieht unter
+einer der folgenden Bedingungen:
+
+@itemize @bullet
+@item
+Die Spalte wird in einem @code{INSERT}- oder @code{LOAD DATA
+INFILE}-Statement nicht explizit angegeben.
+@item
+Die Spalte wird in einem @code{UPDATE}-Statement nicht explizit angegeben,
+aber ein anderer Spaltenwert ändert sich. (Beachten Sie, dass ein
+@code{UPDATE}, das eine Spalte auf einen Wert setzt, den diese bereits hat,
+nicht dazu führt, dass die @code{TIMESTAMP}-Spalte aktualisiert wird, weil
+MySQL das Aktualisieren in einem solchen Fall auf Effizienzgründen
+ignoriert.)
+@item
+Wenn Sie die @code{TIMESTAMP}-Spalte explizit auf @code{NULL} setzen.
+@end itemize
+
+@code{TIMESTAMP}-Spalten abgesehen von der ersten können ebenfalls auf das
+aktuelle Datum und die aktuelle Zeit gesetzt werden. Setzen Sie die Spalte
+einfach auf @code{NULL} oder auf @code{NOW()}.
+
+Sie können jede @code{TIMESTAMP}-Spalte auf einen Wert setzen, der vom
+aktuellen Datum und der aktuellen Zeit abweicht, indem Sie sie explizit auf
+den gewünschten Wert setzen. Das gilt sogar für die erste
+@code{TIMESTAMP}-Spalte. Sie können diese Eigenschaft benutzen, wenn Sie
+einen @code{TIMESTAMP} auf das aktuelle Datum und die aktuelle Zeit setzen
+wollen, wenn Sie eine Zeile erzeugen, nicht aber, wenn die Zeile später
+aktualisiert wird:
+
+@itemize @bullet
+@item
+Lassen Sie MySQL die Spalte setzen, wenn die Zeile erzeugt wird. Das
+initialisiert sie auf das aktuelle Datum und die aktuelle Zeit.
+
+@item
+Wenn Sie nachfolgende Aktualisierungen anderer Spalten in der Zeile
+durchführen, setzen Sie die @code{TIMESTAMP}-Spalte explizit auf ihren
+aktuellen Wert.
+@end itemize
+
+Auf der anderen Seite finden Sie vielleicht mindestens so einfach, eine
+@code{DATETIME}-Spalte zu benutzen, die Sie auf @code{NOW()}
+initialisieren, wenn die Zeile erzeugt wird, und die Sie bei nachfolgenden
+Aktualisierungen nicht anfassen.
+
+@code{TIMESTAMP}-Werte haben einen Wertebereich von 1970 bis irgendwann im
+Jahr 2037, bei einer Auflösung von einer Sekunde. Werte werden als Zahlen
+angezeigt.
+
+Das Format, in dem MySQL @code{TIMESTAMP}-Werte abruft und anzeigt, hängt
+von der Anzeigebreite ab, wie in der obigen Tabelle dargestellt. Das
+`volle' @code{TIMESTAMP}-Format ist 14 Ziffern, aber
+@code{TIMESTAMP}-Spalten können mit kürzeren Anzeigebreiten angelegt
+werden:
+
+@multitable @columnfractions .3 .7
+@item @strong{Spaltentyp} @tab @strong{Anzeigeformat}
+@item @code{TIMESTAMP(14)} @tab @code{YYYYMMDDHHMMSS}
+@item @code{TIMESTAMP(12)} @tab @code{YYMMDDHHMMSS}
+@item @code{TIMESTAMP(10)} @tab @code{YYMMDDHHMM}
+@item @code{TIMESTAMP(8)} @tab @code{YYYYMMDD}
+@item @code{TIMESTAMP(6)} @tab @code{YYMMDD}
+@item @code{TIMESTAMP(4)} @tab @code{YYMM}
+@item @code{TIMESTAMP(2)} @tab @code{YY}
+@end multitable
+
+Alle @code{TIMESTAMP}-Spalten haben dieselbe Speichergröße, unabhängig von
+der Anzeigebreite. Die gebräuchlichsten Anzeigebreiten sind 6, 8, 12 und
+14. Sie können zur Zeit der Tabellenerzeugung beliebige Anzeigebreiten
+festlegen, aber Werte von 0 oder größer als 14 werden auf 14 gesetzt.
+Ungerade Werte im Bereich von 1 bis 13 werden auf die nächst höhere gerade
+Zahl gesetzt.
+
+Sie können @code{DATETIME}-, @code{DATE}- und @code{TIMESTAMP}-Werte mit
+folgenden Formaten festlegen:
+
+@itemize @bullet
+@item
+Als eine Zeichenkette im @code{'YYYY-MM-DD HH:MM:SS'}- oder @code{'YY-MM-DD
+HH:MM:SS'}-Format. Eine ``entspannte'' Syntax ist zugelassen - jedes
+Satzzeichen kann als Begrenzer zwischen Datumsanteilen oder Zeitanteilen
+verwendet werden. Beispielsweise sind @code{'98-12-31 11:30:45'},
+@code{'98.12.31 11+30+45'}, @code{'98/12/31 11*30*45'} und
+@code{'98@@12@@31 11^30^45'} äquivalent.
+
+@item
+Als eine Zeichenkette im @code{'YYYY-MM-DD'}- oder
+@code{'YY-MM-DD'}-Format. Auch hier ist eine ``entspannte'' Syntax
+zugelassen. Beispielsweise sind @code{'98-12-31'}, @code{'98.12.31'},
+@code{'98/12/31'} und @code{'98@@12@@31'} äquivalent.
+
+@item
+Als eine Zeichenkette ohne Begrenzer im @code{'YYYYMMDDHHMMSS'}- oder
+@code{'YYMMDDHHMMSS'}-Format, vorausgesetzt, die Zeichenkette ergibt als
+Datum einen Sinn. @code{'19970523091528'} und @code{'970523091528'}
+beispielsweise werden als @code{'1997-05-23 09:15:28'} interpretiert, aber
+@code{'971122129015'} ist unzulässig (es hat einen Minutenanteil, der
+keinen Sinn ergibt) und wird in @code{'0000-00-00 00:00:00'} umgewandelt.
+
+@item
+Als eine Zeichenkette ohne Begrenzer im @code{'YYYYMMDD'}- oder
+@code{'YYMMDD'}-Format, vorausgesetzt, die Zeichenkette ergibt als Datum
+einen Sinn. @code{'19970523'} und @code{'970523'} werden als
+@code{'1997-05-23'} interpretiert, aber @code{'971332'} ist unzulässig (es
+hat einen Monatsanteil und einen Tagesanteil, der keinen Sinn ergibt) und
+wird in @code{'0000-00-00'} umgewandelt.
+
+@item
+Als eine Zahl im @code{YYYYMMDDHHMMSS}- oder @code{YYMMDDHHMMSS}-Format,
+vorausgesetzt, die Zahl ergibt als Datum einen Sinn. @code{19830905132800}
+und @code{830905132800} zum Beispiel werden als @code{'1983-09-05
+13:28:00'} interpretiert.
+
+@item
+Als eine Zahl im @code{YYYYMMDD}- oder @code{YYMMDD}-Format, vorausgesetzt,
+die Zahl ergibt als Datum einen Sinn. @code{19830905} und @code{830905} zum
+Beispiel werden als @code{'1983-09-05'} interpretiert.
+
+@item
+Als Ergebnis einer Funktion, die einen Wert zurückgibt, der in einem
+@code{DATETIME}-, @code{DATE}- oder @code{TIMESTAMP}-Zusammenhang einen
+Sinn ergibt, wie @code{NOW()} oder @code{CURRENT_DATE}.
+@end itemize
+
+Unzulässige @code{DATETIME}-, @code{DATE}- oder @code{TIMESTAMP}-Werte
+werden in den ``0''-Wert des jeweiligen Typs umgewandelt (@code{'0000-00-00
+00:00:00'}, @code{'0000-00-00'} oder @code{00000000000000}).
+
+Bei Werten, die als Zeichenketten angegeben werden, die Begrenzer für
+Datumsanteile enthalten, ist es nicht notwendig, zwei Ziffern für Monats-
+oder Tageswerte anzugeben, die weniger als @code{10} sind.
+@code{'1979-6-9'} ist dasselbe wie @code{'1979-06-09'}. Gleichermaßen ist
+es bei Zeichenketten, die Begrenzer für Zeitanteile enthalten, nicht
+notwendig, zwei Ziffern für Stunden-, Monats- oder Sekundenwerte anzugeben,
+die weniger als @code{10} sind. @code{'1979-10-30 1:2:3'} ist dasselbe wie
+@code{'1979-10-30 01:02:03'}.
+
+Werte, die als Zahlen angegeben sind, sollten 6, 8, 12 oder 14 Ziffern lang
+sein. Wenn die Zahl 8 oder 14 Ziffern lang ist, wird angenommen, dass sie
+im @code{YYYYMMDD}- oder @code{YYYYMMDDHHMMSS}-Format ist und dass das Jahr
+durch die ersten 4 Ziffern angegeben wird. Wenn die Zahl 6 oder 12 Ziffern
+lang ist, wird angenommen, dass sie im @code{YYMMDD}- oder
+@code{YYMMDDHHMMSS}-Format ist und dass das Jahr durch die ersten 2 Ziffern
+angegeben wird. Zahlen, die nicht diesen Längen entsprechen, werden
+interpretiert, als ob sie mit führenden Nullen auf die nächst mögliche
+Länge gebracht worden wären.
+
+@cindex nicht begrenzte Zeichenketten
+@cindex Zeichenketten, non-delimited
+Werte, die als nicht begrenzte Zeichenketten angegeben werden, werden
+interpretiert, indem ihre Länge als gegeben angenommen wird. Wenn die
+Zeichenkette 8 oder 14 Zeichen lang ist, wird angenommen, dass das Jahr
+durch die ersten 4 Zeichen angegeben wird. Ansonsten wird angenommen, dass
+das Jahr durch die ersten 2 Zeichen angegeben wird. Die Zeichenkette wird
+von links nach rechts interpretiert, um die Jahres-, Monats-, Tages-,
+Stunden- und Sekundenwerte zu finden, für so viele Anteile, wie in der
+Zeichenkette vorkommen. Das bedeutet, dass Sie keine Zeichenketten benutzen
+sollten, die weniger als 6 Zeichen haben. Wenn Sie zum Beispiel
+@code{'9903'} angeben, in der Annahme, dass das März 1999 darstellt, werden
+Sie feststellen, dass MySQL einen ``0''-Datumswert in Ihre Tabelle einfügt.
+Das liegt daran, dass die Jahres- und Monatswerte @code{99} und @code{03}
+sind, aber der Tagesanteil fehlt (0), so dass der Wert kein zulässiges
+Datum darstellt.
+
+@code{TIMESTAMP}-Spalten speichern zulässige Werte mit der vollen
+Genauigkeit, mit der der Wert angegeben wurde, unabhängig von der
+Anzeigebreite. Das hat mehrere Auswirkungen:
+
+@itemize @bullet
+@item
+Geben Sie immer Jahr, Monat und Tag an, selbst wenn Ihre Spaltentypen
+@code{TIMESTAMP(4)} oder @code{TIMESTAMP(2)} sind. Ansonsten wäre der Wert
+kein zulässiges Datum und @code{0} würde gespeichert werden.
+
+@item
+Wenn Sie @code{ALTER TABLE} benutzen, um eine enge @code{TIMESTAMP}-Spalte
+breiter zu machen, werden Informationen angezeigt, die vorher ``versteckt''
+waren.
+
+@item
+Gleichermaßen führt das Verengen einer @code{TIMESTAMP}-Spalte nicht dazu,
+dass Informationen verloren gehen, ausser in dem Sinn, dass weniger
+Informationen dargestellt werden, wenn die Werte angezeigt werden.
+
+@item
+Obwohl @code{TIMESTAMP}-Werte mit voller Genauigkeit gespeichert werden,
+ist die einzige Funktion, die direkt mit dem zugrunde liegenden
+gespeicherten Wert arbeitet, @code{UNIX_TIMESTAMP()}. Alle anderen
+Funktionen arbeiten mit dem formatierten, abgerufenen Wert. Das bedeutet,
+Sie können keine Funktionen wie @code{HOUR()} oder @code{SECOND()}
+benutzen, wenn nicht auch der relevante Teil des @code{TIMESTAMP}-Werts im
+formatierten Werte enthalten ist. Wenn zum Beispiel der @code{HH}-Teil
+einer @code{TIMESTAMP}-Spalte nicht angezeigt wird, wenn die Anzeigebreite
+nicht mindestens 10 beträgt, wird der Versuch, @code{HOUR()} auf kürzere
+@code{TIMESTAMP}-Werte anzuwenden, unsinnige Ergebnisse erzeugen.
+@end itemize
+
+Bis zu einem gewissen Grad können Sie einem Objekt eines Datumstyp Werte
+eines anderen Datumstyps zuweisen. Jedoch kann eine Änderung des Wertes
+oder ein Informationsverlust eintreten:
+
+@itemize @bullet
+@item
+Wenn Sie einem @code{DATETIME}- oder @code{TIMESTAMP}-Objekt einen
+@code{DATE}-Wert zuweisen, wird der Zeitanteil im Ergebniswert auf
+@code{'00:00:00'} gesetzt, weil der @code{DATE}-Wert keine
+Zeitinformationen enthält.
+
+@item
+Wenn Sie einem @code{DATE}-Objekt einen @code{DATETIME}- oder
+@code{TIMESTAMP}-Wert zuweisen, wird der Zeitanteil des Ergebniswerts
+gelöscht, weil der @code{DATE}-Typ keine Zeitinformationen speichert.
+
+@item
+Denken Sie daran, dass @code{DATETIME}-, @code{DATE}- und
+@code{TIMESTAMP}-Werte zwar in denselben Formaten angegeben werden können,
+dass die Typen jedoch nicht alle denselben Wertebereich haben.
+@code{TIMESTAMP}-Werte zum Beispiel können nicht früher als @code{1970}
+oder später als @code{2037} sein. Das bedeutet, dass ein Datum wie
+@code{'1968-01-01'}, was als @code{DATETIME} oder @code{DATE}-Wert zulässig
+wäre, kein gültiger @code{TIMESTAMP}-Wert ist und in @code{0} umgewandelt
+wird, wenn er einem solchen Objekt zugewiesen wird.
+@end itemize
+
+@cindex Probleme, Datumswerte
+@cindex Datumswerte, Probleme
+Seien Sie auf der Hut vor Fallstricken, wenn Sie Datumswerte angeben:
+
+@itemize @bullet
+@item
+Das entspannte Format läßt Werte als Zeichenketten zu, die täuschen
+können. Ein Wert wie @code{'10:11:12'} zum Beispiel sieht wegen des
+@samp{:}-Begrenzers wie ein Zeitwert aus, wird er aber in einem
+Datums-Zusammenhang benutzt, wird er als das Datum @code{'2010-11-12'}
+interpretiert. Der Wert @code{'10:45:15'} wird in @code{'0000-00-00'}
+umgewandelt, weil @code{'45'} kein zulässiger Monat ist.
+
+@item
+Jahreswerte, die als zwei Ziffern angegeben werden, sind mehrdeutig, weil
+das Jahrhundert unbekannt ist.
+unknown. MySQL interpretiert 2-stellige Jahreswerte nach folgenden Regeln:
+
+@itemize @minus
+@item
+Jahreswerte im Bereich @code{00 bis 69} werden in @code{2000 bis 2069}
+umgewandelt.
+
+@item
+Jahreswerte im Bereich @code{70 bis 99} werden in @code{1970 bis 1999}
+umgewandelt.
+@end itemize
+@end itemize
+
+
+@node TIME, YEAR, DATETIME, Date and time types
+@c German node TIME
+@subsubsection Der @code{TIME}-Typ
+
+@tindex TIME
+
+MySQL ruft @code{TIME}-Werte ab und zeigt sie an im
+@code{'HH:MM:SS'}-Format (oder @code{'HHH:MM:SS'}-Format für große
+Stundenwerte). @code{TIME}-Werte rangieren von @code{'-838:59:59'} bis
+@code{'838:59:59'}. Der Grund dafür, dass der Stundenanteil so Groß sein
+kann, liegt darin, dass der @code{TIME}-Typ nicht nur benutzt werden kann,
+um die Tageszeit zu repräsentieren (wobei die Stunden weniger als 24 sein
+müssen), sondern auch abgelaufene Zeit oder ein Zeitintervall zwischen zwei
+Ereignissen (was viel größer als 24 Stunden oder sogar negativ sein kann).
+
+Sie können @code{TIME}-Werte in einer Vielzahl von Formaten angeben:
+
+@itemize @bullet
+@item
+Als eine Zeichenkette im @code{'D HH:MM:SS.bruchteil'}-Format. (Beachten
+Sie, dass MySQL bislang nicht den Bruchteil für die TIME-Spalte speichert.)
+Man kann auch folgende ``entspannte'' Syntax benutzen:
+
+@code{HH:MM:SS.bruchteil}, @code{HH:MM:SS}, @code{HH:MM}, @code{D HH:MM:SS},
+@code{D HH:MM}, @code{D HH} oder @code{SS}. Hierbei ist @code{D} Tage
+zwischen 0 und 33.
+
+@item
+Als eine Zeichenkette ohne Begrenzer im @code{'HHMMSS'}-Format,
+vorausgesetzt, dass diese als Zeitangabe einen Sinn ergibt. @code{'101112'}
+zum Beispiel wird als @code{'10:11:12'} interpretiert, aber @code{'109712'}
+ist unzulässig (es hat einen Minutenanteil, der keinen Sinn ergibt) und
+wird in @code{'00:00:00'} umgewandelt.
+
+@item
+Als eine Zahl im @code{HHMMSS}-Format, vorausgesetzt, dass diese als
+Zeitangabe einen Sinn ergibt. @code{101112} zum Beispiel wird als
+@code{'10:11:12'} interpretiert. Folgende alternativen Formate werden
+ebenfalls verstanden: @code{SS}, @code{MMSS}, @code{HHMMSS},
+@code{HHMMSS.bruchteil}. Beachten Sie, dass MySQL bislang noch nicht den
+Bruchteil speichert.
+
+@item
+Als Ergebnis einer Funktion, die einen Wert zurück gibt, der in einem
+@code{TIME}-Zusammenhang akzeptabel ist, wie @code{CURRENT_TIME}.
+@end itemize
+
+Bei @code{TIME}-Werten, die als Zeichenketten angegeben sind, die einen
+Begrenzer für den Zeitanteil beinhalten, ist es nicht notwendig, zwei
+Ziffern für Stunden-, Minuten- oder Sekunden-Werte anzugeben, die weniger
+als @code{10} sind. @code{'8:3:2'} ist dasselbe wie @code{'08:03:02'}.
+
+Seien Sie vorsichtig damit, einer @code{TIME}-Spalte ``kurze''
+@code{TIME}-Werte zuzuweisen. Ohne Semikolon interpretiert MySQL Werte
+unter der Annahme, dass die am weitesten rechts stehenden Ziffern Sekunden
+repräsentieren. (MySQL interpretiert @code{TIME}-Werte als vergangene Zeit
+statt als Tageszeit.) Sie könnten zum Beispiel denken, dass @code{'1112'}
+und @code{1112} @code{'11:12:00'} bedeuten (12 Minuten nach 11 Uhr), aber
+MySQL interpretiert sie als @code{'00:11:12'} (11 Minuten, 12 Sekunden).
+Gleichermaßen wird @code{'12'} und @code{12} als @code{'00:00:12'}
+interpretiert. @code{TIME}-Werte mit Semikolon werden statt dessen immer
+als Tageszeit interpretiert. Das heißt, @code{'11:12'} bedeutet
+@code{'11:12:00'}, nicht @code{'00:11:12'}.
+
+Werte, die ausserhalb des @code{TIME}-Wertebereichs liegen, ansonsten aber
+zulässig sind, werden auf den entsprechenden Endpunkt des Wertebereichs
+abgeschnitten. @code{'-850:00:00'} bzw. @code{'850:00:00'} werden in
+@code{'-838:59:59'} bzw. @code{'838:59:59'} umgewandelt.
+
+Unzulässige @code{TIME}-Werte werden in @code{'00:00:00'} umgewandelt.
+Beachten Sie, dass es keine Möglichkeit gibt zu unterscheiden, wenn ein
+Wert von @code{'00:00:00'} in einer Tabelle gespeichert ist, ob dieser
+originär als @code{'00:00:00'} eingegeben wurde oder ob es ein unzulässiger
+Wert war, weil @code{'00:00:00'} selbst ein zulässiger @code{TIME}-Wert
+ist.
+
+
+@node YEAR, , TIME, Date and time types
+@c German node YEAR
+@subsubsection Der @code{YEAR}-Typ
+
+@tindex YEAR
+
+Der @code{YEAR}-Typ ist ein 1-Byte-Typ, der für die Darstellung von Jahren
+benutzt wird.
+
+MySQL ruft @code{YEAR}-Werte ab und speichert sie im @code{YYYY}-Format.
+Der Wertebereich ist @code{1901} bis @code{2155}.
+
+Sie können @code{YEAR}-Werte in einer Vielzahl von Formaten angeben:
+
+@itemize @bullet
+@item
+Als vierstellige Zeichenkette im Wertebereich von @code{'1901'} bis
+@code{'2155'}.
+
+@item
+Als vierstellige Zahl im Wertebereich von @code{1901} bis @code{2155}.
+
+@item
+Als zweistellige Zeichenkette im Wertebereich von @code{'00'} bis
+@code{'99'}. Werte in den Bereichen von @code{'00'} bis @code{'69'} und
+@code{'70'} bis @code{'99'} werden in @code{YEAR}-Werte in den Bereichen
+von @code{2000} bis @code{2069} und @code{1970} bis @code{1999}
+umgewandelt.
+
+@item
+Als zweistellige Zahl im Wertebereich von @code{1} bis @code{99}. Werte in
+den Bereichen von @code{1} bis @code{69} und @code{70} bis @code{99} werden
+in @code{YEAR}-Werte in den Bereichen von @code{2001} bis @code{2069} und
+@code{1970} bis @code{1999} umgewandelt. Beachten Sie, dass der
+Wertebereich für zweistellige Zahlen sich geringfügig vom Wertebereich für
+zweistellige Zeichenketten unterscheidet, weil Sie 0 nicht direkt als Zahl
+eingeben können und sie dann als @code{2000} interpretiert wird. Sie
+@emph{müssen} sie als Zeichenkette @code{'0'} oder @code{'00'} angeben,
+oder sie wird als @code{0000} interpretiert.
+
+@item
+Als Ergebnis einer Funktion, die einen Wert zurück gibt, der in einem
+@code{YEAR}-Zusammenhang akzeptabel ist, wie @code{NOW()}.
+@end itemize
+
+Unzulässige @code{YEAR}-Werte werden in @code{0000} umgewandelt.
+
+
+@node String types, Choosing types, Date and time types, Column types
+@c German node Zeichenketten-Typen
+@subsection Zeichenketten-Typen
+
+@cindex Typen, Zeichenketten
+@cindex Zeichenketten-Typen
+
+@tindex CHAR
+@tindex VARCHAR
+
+
+
+Die Zeichenketten-Typen sind @code{CHAR}, @code{VARCHAR}, @code{BLOB},
+@code{TEXT}, @code{ENUM} und @code{SET}. Dieser Abschnitt beschreibt, wie
+diese Typen funktionieren, ihren Speicherbedarf und wie sie in Anfragen
+benutzt werden.
+
+
+@menu
+* CHAR::
+* BLOB::
+* ENUM::
+* SET::
+@end menu
+
+@node CHAR, BLOB, String types, String types
+@c German node CHAR
+@subsubsection Die @code{CHAR}- und @code{VARCHAR}-Typen
+
+Die @code{CHAR}- und @code{VARCHAR}-Typen sind ähnlich, unterscheiden sich
+aber in der Art, wie sie gespeichert und abgerufen werden.
+
+Die Länge einer @code{CHAR}-Spalte wird auf die Länge festgelegt, die Sie
+bei der Erzeugung der Tabelle angeben. Die Länge kann zwischen 1 und 255
+variieren. (Ab MySQL-Version 3.23 kann die Länge zwischen 0 und 255
+liegen.) Wenn @code{CHAR}-Werte gespeichert werden, werden sie am rechten
+Ende bis zur festgelegten Länge mit Leerzeichen aufgefüllt. Wenn
+@code{CHAR}-Werte abgerufen werden, werden die Leerzeichen am Ende
+entfernt.
+
+Werte in @code{VARCHAR}-Spalten sind Zeichenketten variabler Länge. Sie
+können eine @code{VARCHAR}-Spalte mit jeder Länge zwischen 1 und 255
+deklarieren, genau wie für @code{CHAR}-Spalten. Im Gegensatz zu @code{CHAR}
+werden @code{VARCHAR}-Werte jedoch nur mit so vielen Zeichen wie nötig
+gespeichert, plus 1 Byte, um die Länge zu speichern. Die Werte werden nicht
+aufgefüllt; statt dessen werden Leerzeichen am Ende beim Speichern
+entfernt. (Diese Entfernung von Leerzeichen weicht von der
+ANSI-SQL-Spezifikation ab.)
+
+Wenn Sie einer @code{CHAR}- oder @code{VARCHAR}-Spalte einen Wert zuweisen,
+der die maximale Spaltenlänge überschreitet, wird der Wert so zurecht
+geschnitten, das er passt.
+
+Die unten stehende Tabelle stellt die Unterschiede zwischen den beiden
+Spaltentypen dar, indem das Ergebnis der Speicherung unterschiedlicher
+Zeichenkettenwerte in @code{CHAR(4)}- und @code{VARCHAR(4)}-Spalten gezeigt
+wird:
+
+@c Need to use @(space) to make sure second Spaltenwerte retain spacing
+@c in output für Tabelle below.
+
+@multitable @columnfractions .2 .15 .2 .2 .25
+@item @strong{Wert} @tab @code{CHAR(4)} @tab @strong{Speicherbedarf} @tab @code{VARCHAR(4)} @tab @strong{Speicherbedarf}
+@item @code{''} @tab @code{'@ @ @ @ '} @tab 4 Bytes @tab @code{''} @tab 1 Byte
+@item @code{'ab'} @tab @code{'ab@ @ '} @tab 4 Bytes @tab @code{'ab'} @tab 3 Bytes
+@item @code{'abcd'} @tab @code{'abcd'} @tab 4 Bytes @tab @code{'abcd'} @tab 5 Bytes
+@item @code{'abcdefgh'} @tab @code{'abcd'} @tab 4 Bytes @tab @code{'abcd'} @tab 5 Bytes
+@end multitable
+
+Die Werte, die aus den @code{CHAR(4)}- und @code{VARCHAR(4)}-Spalten
+abgerufen werden, sind in jedem Fall gleich, weil Leerzeichen am Ende von
+@code{CHAR}-Spalten beim Abruf entfernt werden.
+
+Werte in @code{CHAR}- und @code{VARCHAR}-Spalten werden unabhängig von der
+Groß-/Kleinschreibung sortiert und verglichen, es sei denn, beim Erzeugen
+der Tabelle wurde das @code{BINARY}-Attribut festgelegt. Das
+@code{BINARY}-Attribut bedeutet, dass Spaltenwerte abhängig von der
+Groß-/Kleinschreibung in Übereinstimmung mit der ASCII-Reihenfolge der
+Maschine sortiert und verglichen werden, auf der der MySQL-Server läuft.
+@code{BINARY} beeinflusst nicht, wie die Spalte gespeichert oder abgerufen
+wird.
+
+Das @code{BINARY}-Attribut ist 'klebrig', das heißt, dass der gesamte
+Ausdruck als ein @code{BINARY}-Wert verglichen wird, sobald eine
+@code{BINARY}-Spalte im Ausdruck benutzt wird.
+
+MySQL ändert eventuell 'still' den Typ von @code{CHAR}- oder
+@code{VARCHAR}-Spalten bei der Tabellenerzeugung.
+@c German FIX unwrapped @xref
+@xref{Silent column changes}.
+
+
+@node BLOB, ENUM, CHAR, String types
+@c German node BLOB
+@subsubsection Die @code{BLOB}- und @code{TEXT}-Typen
+
+@tindex BLOB
+@tindex TEXT
+
+Ein @code{BLOB} ist großes Binärobjekt (Binary Large OBject), das eine
+variable Menge von Daten enthalten kann. Die vier @code{BLOB}-Typen
+@code{TINYBLOB}, @code{BLOB}, @code{MEDIUMBLOB} und @code{LONGBLOB}
+unterscheiden sich nur hinsichtlich der maximalen Länge der Werte, die sie
+aufnehmen können.
+@xref{Storage requirements}.
+
+Die vier @code{TEXT}-Typen @code{TINYTEXT}, @code{TEXT},
+@code{MEDIUMTEXT} und @code{LONGTEXT} entsprechen den vier
+@code{BLOB}-Typen und haben dieselben maximalen Längen und denselben
+Speicherbedarf. Der einzige Unterschied zwischen @code{BLOB}- und
+@code{TEXT}-Typen ist, dass beim Sortieren und Vergleichen bei
+@code{BLOB}-Werten Groß-/Kleinschreibung berücksichtigt wird, bei
+@code{TEXT}-Werten dagegen nicht. Mit anderen Worten ist ein @code{TEXT}
+ein @code{BLOB} ohne Berücksichtigung der Groß-/Kleinschreibung.
+
+Wenn Sie einer @code{BLOB}- oder @code{TEXT}-Spalte einen Wert zuweisen,
+der die maximale Länge des Spaltentyps überschreitet, wird der Wert so
+zurecht geschnitten, dass er passt.
+
+In fast jeder Hinsicht können Sie eine @code{TEXT}-Spalte als eine
+@code{VARCHAR}-Spalte betrachten, die so Groß sein kann, wie Sie wollen.
+Gleichermaßen können Sie eine @code{BLOB}-Spalte als eine @code{VARCHAR
+BINARY}-Spalte betrachten. Die Unterschiede sind:
+
+@itemize @bullet
+@item
+Seit MySQL-Version 3.23.2 können Sie Indexe auf @code{BLOB}- und
+@code{TEXT}-Spalten anlegen. Ältere Versionen von MySQL unterstützten das
+nicht.
+
+@item
+Leerzeichen am Ende werden beim Speichern von @code{BLOB}- und
+@code{TEXT}-Spalten nicht wie bei @code{VARCHAR}-Spalten entfernt.
+
+@item
+@cindex Vorgabewerte, @code{BLOB}- und @code{TEXT}-Spalten
+@cindex @code{BLOB}-Spalten, Vorgabewerte
+@cindex @code{TEXT}-Spalten, Vorgabewerte
+@code{BLOB}- und @code{TEXT}-Spalten können keine @code{DEFAULT}-Werte
+haben.
+@end itemize
+
+@strong{MyODBC} definiert @code{BLOB}-Werte als @code{LONGVARBINARY} und
+@code{TEXT}-Werte als @code{LONGVARCHAR}.
+
+Weil @code{BLOB}- und @code{TEXT}-Werte extrem lang sein können, treffen
+Sie bei der Benutzung eventuell auf Beschränkungen:
+
+@itemize @bullet
+@item
+Wenn Sie @code{GROUP BY} oder @code{ORDER BY} für @code{BLOB}- oder
+@code{TEXT}-Spalten benutzen wollen, müssen Sie den Spaltenwert in ein
+Objekt fester Länge umwandeln. Standardmäßig wird das mit der
+@code{SUBSTRING}-Funktion gemacht. Beispiel:
+
+@example
+mysql> select kommentar from tabelle,substring(kommentar,20) as substr
+ ORDER BY substr;
+@end example
+
+Wenn Sie das nicht tun, werden nur die ersten @code{max_sort_length} Bytes
+der Spalte beim Sortieren benutzt. Der Vorgabewert von
+@code{max_sort_length} ist 1024; dieser Wert kann mit der @code{-O}-Option
+geändert werden, wenn der @code{mysqld}-Server gestartet wird. Sie können
+auf einen Ausdruck, der @code{BLOB}- oder @code{TEXT}-Werte enthält,
+gruppieren, indem Sie die Spaltenposition angeben oder ein Alias benutzen:
+
+@example
+mysql> select id,substring(blob_spalte,1,100) from tabelle
+ GROUP BY 2;
+mysql> select id,substring(blob_spalte,1,100) as b from tabelle
+ GROUP BY b;
+@end example
+
+@item
+Die maximale Größe eines @code{BLOB}- oder @code{TEXT}-Objekts wird durch
+seinen Typ festgelegt, aber der größte Wert, den Sie tatsächlich zwischen
+Client und Server übertragen können, wird von der Menge verfügbaren
+Arbeitsspeichers und der Größe des Kommunikationspuffers festgelegt. Sie
+können die Nachrichtenpuffergröße ändern, müssen das aber auf beiden
+Seiten, also beim Client und beim Server, tun. @xref{Server parameters}.
+@end itemize
+
+Beachten Sie, dass intern jeder @code{BLOB}- oder @code{TEXT}-Wert durch
+ein separat zugewiesenes Objekt dargestellt wird. Das steht im Gegensatz zu
+allen anderen Spaltentypen, für die Speicherplatz einmal pro Spalte
+zugewiesen wird, wenn die Tabelle geöffnet wird.
+
+
+@node ENUM, SET, BLOB, String types
+@c German node ENUM
+@subsubsection Der @code{ENUM}-Typ
+
+@tindex ENUM
+
+Ein @code{ENUM} ist ein Zeichenketten-Objekt, dessen Wert normalerweise aus
+einer Liste zulässiger Werte ausgesucht wird, die explizit bei der
+Spaltenspezifizierung bei der Tabellenerzeugung aufgezählt werden.
+
+Der Wert kann unter bestimmten Umständen auch die leere Zeichenkette
+(@code{""}) oder @code{NULL} sein:
+
+@itemize @bullet
+@item
+Wenn Sie in eine @code{ENUM} einen ungültigen Wert einfügen (das ist eine
+Zeichenkette, die es in der Auflistung zugelassener Werte nicht gibt), wird
+statt dessen die leere Zeichenkette als spezieller Fehlerwert eingefügt.
+Diese Zeichenkette kann von einer 'normalen' leeren Zeichenkette dadurch
+unterschieden werden, dass diese Zeichenkette den numerischen Wert 0 hat.
+Mehr dazu später.
+
+@item
+Wenn ein @code{ENUM} als @code{NULL} deklariert ist, ist @code{NULL}
+ebenfalls ein zulässiger Wert für die Spalte und der Vorgabewert ist
+@code{NULL}. Wenn ein @code{ENUM} als @code{NOT NULL} deklariert ist, ist
+der Vorgabewert das erste Element der Auflistung erlaubter Werte.
+@end itemize
+
+Jeder Aufzählungswert hat einen Index:
+
+@itemize @bullet
+@item
+Werte der Auflistung zulässiger Elemente in der Spaltenspezifikation fangen
+mit 1 an.
+
+@item
+Der Indexwert des Fehlerwerts leere Zeichenkette ist 0. Folglich können Sie
+folgendes @code{SELECT}-Statement benutzen, um Zeilen zu finden, denen
+unzulässige @code{ENUM}-Werte zugewiesen wurden:
+
+@example
+mysql> SELECT * FROM tabelle WHERE enum_spalte=0;
+@end example
+
+@item
+Der Index des @code{NULL}-Werts ist @code{NULL}.
+@end itemize
+
+Wenn beispielsweise eine Spalte als @code{ENUM("eins", "zwei", "drei")}
+festgelegt wurde, kann sie einen der unten dargestellen Werte besitzen. Der
+Index jedes Werts wird auch dargestellt:
+
+@multitable @columnfractions .2 .8
+@item @strong{Wert} @tab @strong{Index}
+@item @code{NULL} @tab @code{NULL}
+@item @code{""} @tab 0
+@item @code{"eins"} @tab 1
+@item @code{"zwei"} @tab 2
+@item @code{"drei"} @tab 3
+@end multitable
+
+Eine Aufzählung kann maximal 65535 Elemente enthalten.
+
+Groß-/Kleinschreibung ist irrelevant, wenn Sie einer @code{ENUM}-Spalte
+Werte zuweisen. Jedoch haben Werte, die später aus der Spalte abgerufen
+werden, dieselbe Groß-/Kleinschreibung wie die Werte, die für die
+Festlegung zulässiger Werte bei der Tabellenerzeugung verwendet wurden.
+
+Wenn Sie eine @code{ENUM} in einem numerischen Zusammenhang benutzen, wird
+der Index des Spaltenwerts zurückgegeben. Sie können beispielsweise
+numerische Werte aus einer @code{ENUM}-Spalte wie folgt abrufen:
+
+@example
+mysql> SELECT enum_spalte+0 FROM tabelle;
+@end example
+
+Wenn Sie eine Zahl in eine @code{ENUM} speichern, wird die Zahl als Index
+behandelt und der gespeicherte Wert ist das Aufzählungselement mit diesem
+Index. (Das funktioniert jedoch nicht bei @code{LOAD DATA}, was alle
+Eingaben als Zeichenketten behandelt.)
+
+@code{ENUM}-Werte werden in der Reihenfolge sortiert, wie die
+Aufzählungselemente bei der Spaltenspezifizierung eingegeben wurden. (Mit
+anderen Worten werden @code{ENUM}-Werte nach ihren Indexzahlen sortiert.)
+So wird beispielsweise @code{"a"} vor @code{"b"} einsortiert bei
+@code{ENUM("a", "b")}, aber @code{"b"} wird vor @code{"a"} einsortiert bei
+@code{ENUM("b", "a")}. Die leere Zeichenkette wird vor nicht leeren
+Zeichenketten und @code{NULL}-Werte vor allen anderen Aufzählungswerten
+einsortiert.
+
+Wenn Sie alle möglichen Werte einer @code{ENUM}-Spalte erhalten wollen,
+benutzen Sie: @code{SHOW COLUMNS FROM tabelle LIKE enum_spalte} und gehen
+die @code{ENUM}-Definition in der zweiten Spalte durch.
+
+
+@node SET, , ENUM, String types
+@c German node SET
+@subsubsection Der @code{SET}-Typ
+
+@tindex SET
+
+Ein @code{SET} ist ein Zeichenketten-Objekt, das 0 oder mehr Werte haben
+kann, wovon jedes aus einer Auflistung zulässiger Werte stammen muss, die
+bei der Tabellenerzeugung festgelegt wurden. @code{SET}-Spaltenwerte, die
+aus mehrfachen SET-Elementen bestehen, werden angegeben, indem die Elemente
+durch Kommas (@samp{,}) getrennt werden. Daraus ergibt sich, dass
+@code{SET}-Elemente selbst keine Kommas enthalten dürfen.
+
+Eine Spalte beispielsweise, die als @code{SET("eins", "zwei") NOT NULL}
+festgelegt wurde, kann folgende Werte haben:
+
+@example
+""
+"eins"
+"zwei"
+"eins,zwei"
+@end example
+
+
+Eine @code{SET} kann maximal 64 unterschiedliche Elemente besitzen.
+
+MySQL speichert @code{SET}-Werte numerisch, wobei das niedrigste Bit in der
+Reihenfolge der gespeicherten Werte dem ersten SET-Element entspricht. Wenn
+Sie einen @code{SET}-Wert in einem numerischen Zusammenhang abrufen, hat
+der abgerufene Werte Bits gesetzt, die den SET-Elementen, aus denen sich
+der Spaltenwert zusammensetzt, entspricht. Beispielsweise können Sie
+numerische Werte aus einer @code{SET}-Spalte wie folgt abrufen:
+
+@example
+mysql> SELECT set_spalte+0 FROM tabelle;
+@end example
+
+Wenn in einer @code{SET}-Spalte eine Zahl gespeichert wird, legen die Bits,
+die in der binären Darstellung der Zahl gesetzt sind, die SET-Elemente im
+Spaltenwert fest. Angenommen, eine Spalte ist als
+@code{SET("a","b","c","d")} festgelegt, dann haben die Elemente folgende
+Bitwerte:
+
+@multitable @columnfractions .2 .2 .6
+@item @code{SET} @strong{Element} @tab @strong{Dezimalwert} @tab @strong{Binärwert}
+@item @code{a} @tab @code{1} @tab @code{0001}
+@item @code{b} @tab @code{2} @tab @code{0010}
+@item @code{c} @tab @code{4} @tab @code{0100}
+@item @code{d} @tab @code{8} @tab @code{1000}
+@end multitable
+
+Wenn Sie dieser Spalte einen Wert von @code{9} zuweisen, ist das binär
+@code{1001}. Daher werden der erste und der vierte @code{SET}-Wert, die
+Elemente @code{"a"} und @code{"d"}, ausgewählt, und der Ergebniswert ist
+@code{"a,d"}.
+
+Bei einem Wert, der mehr als ein @code{SET}-Element enthält, spielt es
+keine Rolle, in welcher Reihenfolge die Elemente aufgelistet sind, wenn Sie
+den Wert einfügen. Es spielt ebenfalls keine Rolle, wie oft ein gegebenes
+Element im Wert aufgelistet ist. Wenn der Wert später abgerufen wird,
+erscheint jedes Element im Wert einmal, wobei die Elemente in der
+Reihenfolge erscheinen, in der sie bei der Tabellenerzeugung festgelegt
+wurden. Wenn eine Spalte beispielsweise als @code{SET("a","b","c","d")}
+festgelegt ist, erscheinen @code{"a,d"}, @code{"d,a"} und
+@code{"d,a,a,d,d"} als @code{"a,d"}, wenn sie abgerufen werden.
+
+@code{SET}-Werte werden numerisch sortiert. @code{NULL}-Werte werden vor
+Nicht-@code{NULL}-@code{SET}-Werten einsortiert.
+
+Normalerweise führt man @code{SELECT} auf eine @code{SET}-Spalte mit dem
+@code{LIKE}-Operator oder der @code{FIND_IN_SET()}-Funktion aus:
+
+@example
+mysql> SELECT * FROM tabelle WHERE set_spalte LIKE '%wert%';
+mysql> SELECT * FROM tabelle WHERE FIND_IN_SET('wert',set_spalte)>0;
+@end example
+
+Aber auch folgendes funktioniert:
+
+@example
+mysql> SELECT * FROM tabelle WHERE set_spalte = 'wert1,wert2';
+mysql> SELECT * FROM tabelle WHERE set_spalte & 1;
+@end example
+
+Das erste dieser Statements sucht nach einer exakten Übereinstimmung, das
+zweite sucht Werte, die das erste SET-Element enthalten.
+
+Wenn Sie alle möglichen Werte einer @code{SET}-Spalte erhalten wollen,
+benutzen Sie: @code{SHOW COLUMNS FROM tabelle LIKE set_spalte} und gehen
+die @code{SET}-Definition in der zweiten Spalte durch.
+
+
+@node Choosing types, Other-vendor column types, String types, Column types
+@c German node Typen auswählen
+@subsection Den richtigen Typ für eine Spalte auswählen
+
+@cindex Typen, Spalten
+@cindex Typen auswählen
+
+Um möglichst effizient zu speichern, benutzen Sie in jedem Fall den
+präzisesten Typ. Wenn zum Beispiel eine Ganzzahl-Spalte für Werte im
+Bereich zwischen @code{1} und @code{99999} benutzt wird, ist
+@code{MEDIUMINT UNSIGNED} der beste Typ.
+
+Akkurate Darstellung monetärer Werte ist ein häufiges Problem. In MySQL
+sollten Sie den @code{DECIMAL}-Typ benutzen. Dieser wird als Zeichenkette
+gepeichert, weshalb kein Genauigkeitsverlust auftreten sollte. Wenn
+Genauigkeit nicht allzu wichtig ist, sollte auch der @code{DOUBLE}-Typ
+ausreichen.
+
+Um hohe Präzision zu erzielen, können Sie immer auch in einen Festkommawert
+umwandeln, der in einer @code{BIGINT} gespeichert wird. Das erlaubt Ihnen,
+alle Berechnungen mit Ganzzahlen durchzuführen und die Ergebnisse nur wenn
+notwendig in Fließkommawerte zurückzuwandeln.
+
+
+@node Other-vendor column types, Storage requirements, Choosing types, Column types
+@c German node Spaltentypen anderer Hersteller
+@subsection Spaltentypen anderer Datenbanken benutzen
+
+@cindex Typen, Portabilität
+@cindex Portabilität, Typen
+@cindex Spalten, andere Typen
+
+Um es einfacher zu machen, Code zu verwenden, der für SQL-Implementationen
+anderer Hersteller geschrieben wurde, ordnet (mappt) MySQL Spaltentypen zu
+wie in unten stehender Tabelle dargestellt. Diese Mappings machen es
+leichter, Tabellendefinitionen anderer Datenbanken nach MySQL zu
+verschieben:
+
+@multitable @columnfractions .4 .6
+@item @strong{Typ anderer Hersteller} @tab @strong{MySQL-Typ}
+@item @code{BINARY(NUM)} @tab @code{CHAR(NUM) BINARY}
+@item @code{CHAR VARYING(NUM)} @tab @code{VARCHAR(NUM)}
+@item @code{FLOAT4} @tab @code{FLOAT}
+@item @code{FLOAT8} @tab @code{DOUBLE}
+@item @code{INT1} @tab @code{TINYINT}
+@item @code{INT2} @tab @code{SMALLINT}
+@item @code{INT3} @tab @code{MEDIUMINT}
+@item @code{INT4} @tab @code{INT}
+@item @code{INT8} @tab @code{BIGINT}
+@item @code{LONG VARBINARY} @tab @code{MEDIUMBLOB}
+@item @code{LONG VARCHAR} @tab @code{MEDIUMTEXT}
+@item @code{MIDDLEINT} @tab @code{MEDIUMINT}
+@item @code{VARBINARY(NUM)} @tab @code{VARCHAR(NUM) BINARY}
+@end multitable
+
+Dass Zuordnen (Mapping) von Spaltentypen geschieht bei der Erzeugung der
+Tabelle. Wenn Sie eine Tabelle mit Typen erzeugen, die von anderen
+Herstellern benutzt werden, und dann ein @code{DESCRIBE tabelle}-Statement
+absetzen, zeigt MySQL die Tabellenstruktur mit den äquivalenten MySQL-Typen
+an.
+
+
+@node Storage requirements, , Other-vendor column types, Column types
+@c German node Speicherbedarf
+@subsection Speicherbedarf von Spaltentypen
+
+@cindex Speicherbedarf, Spaltentyp
+@cindex Spalten, Speicherbedarf
+
+Der Speicherbedarf jedes Spaltentyps, der von MySQL unterstützt wird, ist
+unten nach Kategorie sortiert aufgelistet:
+
+@cindex numerische Typen
+@cindex Typen, numerische
+
+@subsubheading Speicherbedarf für numerische Typen
+
+@multitable @columnfractions .5 .5
+@item @strong{Spaltentyp} @tab @strong{Speicherbedarf}
+@item @code{TINYINT} @tab 1 Byte
+@item @code{SMALLINT} @tab 2 Bytes
+@item @code{MEDIUMINT} @tab 3 Bytes
+@item @code{INT} @tab 4 Bytes
+@item @code{INTEGER} @tab 4 Bytes
+@item @code{BIGINT} @tab 8 Bytes
+@item @code{FLOAT(X)} @tab 4, wenn X <= 24, oder 8, wenn 25 <= X <= 53
+@item @code{FLOAT} @tab 4 Bytes
+@item @code{DOUBLE} @tab 8 Bytes
+@item @code{DOUBLE PRECISION} @tab 8 Bytes
+@item @code{REAL} @tab 8 Bytes
+@item @code{DECIMAL(M,D)} @tab @code{M+2} Bytes, wenn D > 0, @code{M+1} Bytes, wenn D = 0 (@code{D}+2, wenn @code{M < D})
+@item @code{NUMERIC(M,D)} @tab @code{M+2} Bytes, wenn D > 0, @code{M+1} Bytes, wenn D = 0 (@code{D}+2, wenn @code{M < D})
+@end multitable
+
+@cindex Datumstypen
+@cindex Zeittypen
+@cindex Typen, Datum
+@cindex Typen, Zeit
+
+@subsubheading Speicherbedarf für Datums- und Zeit-Typen
+
+@multitable @columnfractions .5 .5
+@item @strong{Spaltentyp} @tab @strong{Speicherbedarf}
+@item @code{DATE} @tab 3 Bytes
+@item @code{DATETIME} @tab 8 Bytes
+@item @code{TIMESTAMP} @tab 4 Bytes
+@item @code{TIME} @tab 3 Bytes
+@item @code{YEAR} @tab 1 Byte
+@end multitable
+
+@subsubheading Speicherbedarf für Zeichenketten-Typen
+
+@multitable @columnfractions .5 .5
+@item @strong{Spaltentyp} @tab @strong{Speicherbedarf}
+@item @code{CHAR(M)} @tab @code{M} Bytes, @code{1 <= M <= 255}
+@item @code{VARCHAR(M)} @tab @code{L}+1 Bytes, wobei @code{L <= M} und
+@code{1 <= M <= 255}
+@item @code{TINYBLOB}, @code{TINYTEXT} @tab @code{L}+1 Bytes,
+wobei @code{L} < 2^8
+@item @code{BLOB}, @code{TEXT} @tab @code{L}+2 Bytes,
+wobei @code{L} < 2^16
+@item @code{MEDIUMBLOB}, @code{MEDIUMTEXT} @tab @code{L}+3 Bytes,
+wobei @code{L} < 2^24
+@item @code{LONGBLOB}, @code{LONGTEXT} @tab @code{L}+4 Bytes,
+wobei @code{L} < 2^32
+@item @code{ENUM('wert1','wert2',...)} @tab 1 oder 2 Bytes, abhängig von
+der Anzahl der Aufzählungswerte (65535 Werte maximal)
+@item @code{SET('wert1','wert2',...)} @tab 1, 2, 3, 4 oder 8 Bytes,
+abhängig von der Anzahl von SET-Elementen (64 Elemente maximal)
+@end multitable
+
+@cindex @code{BLOB}, Größe
+@cindex @code{TEXT}, Größe
+@cindex @code{VARCHAR}, Größe
+@code{VARCHAR} und die @code{BLOB}- und @code{TEXT}-Typen sind Typen
+variabler Länge, bei denen der Speicherbedarf von der tatsächlichen Länge
+der Spaltenwerte abhängt (in der vorstehenden Tabelle dargestellt durch
+@code{L}) statt von der maximal möglichen Größe des Typs.
+@code{VARCHAR(10)} zum Beispiel kann eine Zeichenkette mit einer maximalen
+Länge von 10 Zeichen enthalten. Der tatsächliche Speicherbedarf ist die
+Länge der Zeichenkette (@code{L}) plus 1 Byte, um die Länge zu speichern.
+Bei der Zeichenkette @code{'abcd'} ist @code{L} 4 und der Speicherbedarf 5
+Bytes.
+
+Die @code{BLOB}- und @code{TEXT}-Typen benötigen 1, 2, 3 oder 4 Bytes, um
+die Länge des Spaltenwerts zu speichern, abhängig von der maximal möglichen
+Länge des Typs. @xref{BLOB}.
+
+Wenn eine Tabelle irgend welche Spaltentypen variabler Länge enthält, ist
+das Datensatzformat ebenfalls von variabler Länge. Beachten Sie, dass MySQL
+bei der Erzeugung einer Tabelle unter bestimmten Umständen eine Spalte
+eines Typs variabler Länge in einen Typ fester Länge umwandelt, und
+umgekehrt. @xref{Silent column changes}.
+
+@cindex ENUM, Größe
+Die Größe eines @code{ENUM}-Objekts hängt von der Anzahl unterschiedlicher
+Aufzählungswerte ab. Bei Aufzählungen mit bis zu 255 möglichen Werten wird
+1 Byte benutzt, bei Aufzählungen mit bis zu 65535 Werten 2 Bytes.
+@xref{ENUM}.
+
+@cindex SET, Größe
+Die Größe eines @code{SET}-Objekts hängt von der Anzahl unterschiedlicher
+SET-Elemente ab. Wenn die SET-Größe @code{N} ist, belegt das Objekt
+@code{(N+7)/8} Bytes, gerundet auf 1, 2, 3, 4 oder 8 Bytes. Ein @code{SET}
+kann maximal 64 Elemente besitzen. @xref{SET}.
+
+
+@node Functions, Data Manipulation, Column types, Reference
+@c German node Funktionen
+@section Funktionen für die Benutzung in @code{SELECT}- und @code{WHERE}-Klauseln
+
+@cindex Funktionen für @code{SELECT} und @code{WHERE}-Klauseln
+
+Ein @code{select_ausdruck} oder eine @code{where_definition} in einem
+SQL-Statement kann aus jedem beliebigen Ausdruck bestehen, der die unten
+beschriebenen Funktionen benutzt.
+
+Ein Ausdruck, der @code{NULL} enthält, erzeugt immer einen
+@code{NULL}-Wert, wenn es in der Dokumentation für die Operatoren und
+Funktionen, die im Ausdruck vorkommen, nicht anders beschrieben ist.
+
+@strong{HINWEIS:} Zwischen Funktionsname und der folgenden Klammer darf
+kein Leerraum stehen. Das hilft dem MySQL-Parser, zwischen
+Funktionsaufrufen und Tabellen- oder Spaltenverweisen zu unterscheiden, die
+denselben Namen haben wie eine Funktion. Leerzeichen um Argumente herum
+sind dagegen zulässig.
+
+Sie können MySQL zwingen, Leerzeichen nach dem Funktionsnamen zu
+akzeptieren, indem Sie @code{mysqld} mit @code{--ansi} starten oder
+@code{CLIENT_IGNORE_SPACE} bei @code{mysql_connect()}, benutzen, aber in
+diesem Fall werden alle Funktionsnamen zu reservierten Wörtern.
+@xref{ANSI mode}.
+
+@need 2000
+
+Der Kürze zuliebe sind die Ausgaben des @code{mysql}-Programms in gekürzter
+Form dargestellt. Daher wird
+
+@example
+mysql> select MOD(29,9);
++-----------+
+| mod(29,9) |
++-----------+
+| 2 |
++-----------+
+1 rows in set (0.00 sec)
+@end example
+
+wie folgt dargestellt:
+
+@example
+mysql> select MOD(29,9);
+ -> 2
+@end example
+
+
+
+@menu
+* Non-typed Operators::
+* String functions::
+* Numeric Functions::
+* Date and time functions::
+* Other Functions::
+* Group by functions::
+@end menu
+
+@node Non-typed Operators, String functions, Functions, Functions
+@c German node Nicht typenspezifische Operatoren
+@subsection Nicht typenspezifische Operatoren und Funktionen
+
+
+
+@menu
+* Parenthesis::
+* Comparison Operators::
+* Logical Operators::
+* Control flow functions::
+@end menu
+
+@node Parenthesis, Comparison Operators, Non-typed Operators, Non-typed Operators
+@c German node Klammer
+@subsubsection Klammer
+
+@findex () (Klammern)
+@findex Klammern ( und )
+
+@cindex Funktionen, Gruppierungs-
+@cindex Gruppierung, Ausdrücke
+
+@example
+( ... )
+@end example
+
+Benutzen Sie Klammern, um die Reihenfolge der Auswertung in einem Ausdruck
+zu erzwingen. Beispiel:
+
+@example
+mysql> select 1+2*3;
+ -> 7
+mysql> select (1+2)*3;
+ -> 9
+@end example
+
+
+
+@node Comparison Operators, Logical Operators, Parenthesis, Non-typed Operators
+@c German node Vergleichsoperatoren
+@subsubsection Vergleichsoperatoren
+
+@findex Vergleichsoperatoren
+
+@cindex Casts
+@cindex Typumwandlungen
+
+Vergleichsoperationen ergeben einen Wert von @code{1} (TRUE), @code{0}
+(FALSE) oder @code{NULL}. Diese Funktionen funktionieren sowohl bei Zahlen
+als auch bei Zeichenketten. Zeichenketten werden bei Bedarf automatisch in
+Zahlen und Zahlen in Zeichenketten umgewandelt (wie in Perl oder PHP).
+
+MySQL führt Vergleiche nach folgenden Regeln durch:
+
+@itemize @bullet
+@item
+Wenn ein oder beide Argumente @code{NULL} sind, ist das Ergebnis des
+Vergleichs @code{NULL}, ausser beim @code{<=>} Operator.
+
+@item
+Wenn beide Argumente in einer Vergleichsoperation Zeichenketten sind,
+werden sie als Zeichenketten verglichen.
+
+@item
+Wenn beide Argumente Ganzzahlen sind, werden sie als Ganzzahlen verglichen.
+
+@item
+Hexadezimale Werte werden als binäre Zeichenketten behandelt, wenn sie
+nicht mit einer Zahl verglichen werden.
+
+@item
+@cindex ODBC-Kompatibilität
+@cindex Kompatibilität, mit ODBC
+Wenn eins der Argumente eine @code{TIMESTAMP}- oder @code{DATETIME}-Spalte
+ist und das andere Argument eine Konstante, wird die Konstante in einen
+Zeitstempel umgewandelt, bevor der Vergleich durchgeführt wird. Das wird
+gemacht, um ODBC-freundlicher zu sein.
+
+@item
+In allen anderen Fällen werden die Argumente als Fließkommazahlen
+verglichen.
+@end itemize
+
+Vorgabemäßig werden Zeichenketten-Vergleiche unabhängig von der verwendeten
+Groß-/Kleinschreibung durchgeführt, indem der aktuelle Zeichensatz benutzt
+wird (vorgabemäßig ISO-8859-1 Latin1, der auch für englisch exzellent
+funktioniert).
+
+Die unten stehenden Beispiele erläutern die Umwandlung von Zeichenketten in
+Zahlen für Vergleichsoperationen:
+
+@example
+mysql> SELECT 1 > '6x';
+ -> 0
+mysql> SELECT 7 > '6x';
+ -> 1
+mysql> SELECT 0 > 'x6';
+ -> 0
+mysql> SELECT 0 = 'x6';
+ -> 1
+@end example
+
+@table @code
+@findex = (gleich)
+@findex gleich (=)
+@item =
+Gleich:
+@example
+mysql> select 1 = 0;
+ -> 0
+mysql> select '0' = 0;
+ -> 1
+mysql> select '0.0' = 0;
+ -> 1
+mysql> select '0.01' = 0;
+ -> 0
+mysql> select '.01' = 0.01;
+ -> 1
+@end example
+
+@findex <> (ungleich)
+@findex ungleich (<>)
+@findex != (ungleich)
+@findex ungleich (!=)
+@item <>
+@itemx !=
+Ungleich:
+@example
+mysql> select '.01' <> '0.01';
+ -> 1
+mysql> select .01 <> '0.01';
+ -> 0
+mysql> select 'zapp' <> 'zappp';
+ -> 1
+@end example
+
+@findex <= (kleiner oder gleich)
+@findex kleiner oder gleich (<=)
+@item <=
+Kleiner oder gleich:
+@example
+mysql> select 0.1 <= 2;
+ -> 1
+@end example
+
+@findex < (kleiner als)
+@findex kleiner als (<)
+@item <
+Kleiner als:
+@example
+mysql> select 2 < 2;
+ -> 0
+@end example
+
+@findex >= (größer oder gleich)
+@findex größer oder gleich (>=)
+@item >=
+Größer oder gleich:
+@example
+mysql> select 2 >= 2;
+ -> 1
+@end example
+
+@findex > (größer als)
+@findex größer als (>)
+@item >
+Größer als:
+@example
+mysql> select 2 > 2;
+ -> 0
+@end example
+
+@cindex @code{NULL}, testen auf Null
+@findex <=> (Gleich)
+@item <=>
+Null-sicheres gleich:
+@example
+mysql> select 1 <=> 1, NULL <=> NULL, 1 <=> NULL;
+ -> 1 1 0
+@end example
+
+@cindex @code{NULL}, testen auf Null
+@findex IS NULL
+@findex IS NOT NULL
+@item IS NULL
+@itemx IS NOT NULL
+Testet, ob eine Wert @code{NULL} ist oder nicht:
+@example
+mysql> select 1 IS NULL, 0 IS NULL, NULL IS NULL;
+ -> 0 0 1
+mysql> select 1 IS NOT NULL, 0 IS NOT NULL, NULL IS NOT NULL;
+ -> 1 1 0
+@end example
+
+@findex BETWEEN ... AND
+@item ausdruck BETWEEN min AND max
+Wenn @code{ausdruck} größer oder gleich @code{min} ist und @code{ausdruck}
+kleiner oder gleich @code{max} ist, gibt @code{BETWEEN} @code{1} zurück,
+andernfalls @code{0}. Das ist äquivalent zum Ausdruck @code{(min <=
+ausdruck AND ausdruck <= max)}, wenn alle Argumente vom selben Typ sind.
+Das erste Argument (@code{ausdruck}) legt fest, wie der Vergleich
+durchgeführt wird:
+
+@itemize @bullet
+@item
+Wenn @code{ausdruck} eine @code{TIMESTAMP}-, @code{DATE}- oder
+@code{DATETIME}-Spalte ist, werden @code{MIN()} und @code{MAX()} im selben
+Format formatiert als wären sie Konstanten.
+@item
+Wenn @code{ausdruck} ein Zeichenketten-Ausdruck ohne Berücksichtigung der
+Groß-/Kleinschreibung ist, wird ein Zeichenkettenvergleich ohne
+Berücksichtigung der Groß-/Kleinschreibung durchgeführt.
+@item
+Wenn @code{ausdruck} ein Zeichenketten-Ausdruck mit Berücksichtigung der
+Groß-/Kleinschreibung ist, wird ein Zeichenkettenvergleich mit
+Berücksichtigung der Groß-/Kleinschreibung durchgeführt.
+@item
+Wenn @code{ausdruck} ist ein Ganzzahl-Ausdruck ist, wird ein
+Ganzzahlvergleich durchgeführt.
+@item
+Ansonsten wird ein Fließkommazahlenvergleich durchgeführt.
+@end itemize
+
+@example
+mysql> select 1 BETWEEN 2 AND 3;
+ -> 0
+mysql> select 'b' BETWEEN 'a' AND 'c';
+ -> 1
+mysql> select 2 BETWEEN 2 AND '3';
+ -> 1
+mysql> select 2 BETWEEN 2 AND 'x-3';
+ -> 0
+@end example
+
+@findex IN
+@item ausdruck IN (wert,...)
+Gibt @code{1} zurück, wenn @code{ausdruck} einen Wert hat, der in der
+@code{IN}-Liste enthalten ist, ansonsten @code{0}. Wenn alle Werte
+Konstanten sind, werden alle Werte gemäß dem Typ von @code{ausdruck}
+ausgewertet und sortiert. Danach wird ein Element mittels binärer Suche
+gesucht. Das heißt, dass @code{IN} sehr schnell ist, wenn die
+@code{IN}-Werteliste ausschließlich aus Konstanten besteht. Wenn
+@code{ausdruck} ein Zeichenketten-Ausdruck mit Berücksichtigung der
+Groß-/Kleinschreibung ist, wird der Zeichenkettenvergleich unter
+Berücksichtigung der Groß-/Kleinschreibung durchgeführt:
+
+@example
+mysql> select 2 IN (0,3,5,'wefwf');
+ -> 0
+mysql> select 'wefwf' IN (0,3,5,'wefwf');
+ -> 1
+@end example
+
+@findex NOT IN
+@item ausdruck NOT IN (wert,...)
+Dasselbe wie @code{NOT (ausdruck IN (wert,...))}.
+
+@findex ISNULL()
+@item ISNULL(ausdruck)
+Wenn @code{ausdruck} @code{NULL} ist, gibt @code{ISNULL()} @code{1} zurück,
+ansonsten @code{0}:
+@example
+mysql> select ISNULL(1+1);
+ -> 0
+mysql> select ISNULL(1/0);
+ -> 1
+@end example
+
+Beachten Sie, dass ein Vergleich von @code{NULL}-Werten mit @code{=} immer
+UNWAHR ergibt!
+
+@cindex @code{NULL}, testen auf Null
+@findex COALESCE()
+@item COALESCE(liste)
+Gibt das erste Nicht-@code{NULL}-Element in der Liste zurück:
+
+@example
+mysql> select COALESCE(NULL,1);
+ -> 1
+mysql> select COALESCE(NULL,NULL,NULL);
+ -> NULL
+@end example
+
+@findex INTERVAL()
+@item INTERVAL(N,N1,N2,N3,...)
+Gibt @code{0} zurück, wenn @code{N} < @code{N1}, @code{1}, wenn @code{N} <
+@code{N2} usw. Alle Argumente werden als Ganzzahlen behandelt. Es ist
+erforderlich, dass @code{N1} < @code{N2} < @code{N3} < @code{...} <
+@code{Nn} ist, damit diese Funktion korrekt funktioniert. Das liegt daran,
+dass eine (sehr schnelle) binäre Suche benutzt wird:
+
+@example
+mysql> select INTERVAL(23, 1, 15, 17, 30, 44, 200);
+ -> 3
+mysql> select INTERVAL(10, 1, 10, 100, 1000);
+ -> 2
+mysql> select INTERVAL(22, 23, 30, 44, 200);
+ -> 0
+@end example
+@end table
+
+Wenn Sie eine Zeichenkette, die Groß-/Kleinschreibung nicht
+berücksichtigt, mit einem der Standard-Operatoren vergleichen (@code{=},
+@code{<>}..., aber nicht @code{LIKE}), werden Leerzeichen am Ende
+ignoriert:
+
+@example
+mysql> select "a" ="A ";
+ -> 1
+@end example
+
+
+@node Logical Operators, Control flow functions, Comparison Operators, Non-typed Operators
+@c German node Logische Operatoren
+@subsubsection Logische Operatoren
+
+@findex Logische Funktionen
+@findex Funktionen, logische
+
+Alle logischen Funktionen geben @code{1} (TRUE), @code{0} (FALSE) oder
+@code{NULL} (unbekannt, was in den meisten Fällen dasselbe wie FALSE ist)
+zurück:
+
+@table @code
+@findex NOT, logisch
+@findex ! (logisch NOT)
+@item NOT
+@itemx !
+Logisch NOT. Gibt @code{1} zurück, wenn das Argument @code{0} ist,
+ansonsten @code{0}.
+Ausnahme: @code{NOT NULL} gibt @code{NULL} zurück:
+@example
+mysql> select NOT 1;
+ -> 0
+mysql> select NOT NULL;
+ -> NULL
+mysql> select ! (1+1);
+ -> 0
+mysql> select ! 1+1;
+ -> 1
+@end example
+Das letzte Beispiel gibt @code{1} zurück, weil der Ausdruck auf dieselbe
+Art ausgewertet wird wie @code{(!1)+1}.
+
+@findex OR, logisch
+@findex || (logisch OR)
+@item OR
+@itemx ||
+Logisch OR. Gibt @code{1} zurück, wenn eins der Argumente nicht @code{0}
+und nicht @code{NULL} ist:
+@example
+mysql> select 1 || 0;
+ -> 1
+mysql> select 0 || 0;
+ -> 0
+mysql> select 1 || NULL;
+ -> 1
+
+@end example
+
+@findex AND, logisch
+@findex && (logisch AND)
+@item AND
+@itemx &&
+Logisch AND. Gibt @code{0} zurück, wenn eins der Argumente @code{0} oder
+@code{NULL} ist, ansonsten @code{1}:
+@example
+mysql> select 1 && NULL;
+ -> 0
+mysql> select 1 && 0;
+ -> 0
+@end example
+@end table
+
+
+@node Control flow functions, , Logical Operators, Non-typed Operators
+@c German node Ablaufsteuerungsfunktionen
+@subsubsection Ablaufsteuerungsfunktionen
+
+@findex Ablaufsteuerungsfunktionen
+@findex Funktionen, Ablaufsteuerung
+
+@table @code
+@cindex @code{NULL}, testen auf Null
+@findex IFNULL()
+@item IFNULL(ausdruck1,ausdruck2)
+Wenn @code{ausdruck1} nicht @code{NULL} ist, gibt @code{IFNULL()}
+@code{ausdruck1} zurück, ansonsten @code{ausdruck2}. @code{IFNULL()} gibt
+einen numerischen oder einen Zeichenketten-Wert zurück, je nachdem, in
+welchem Zusammenhang es benutzt wird:
+@example
+mysql> select IFNULL(1,0);
+ -> 1
+mysql> select IFNULL(NULL,10);
+ -> 10
+mysql> select IFNULL(1/0,10);
+ -> 10
+mysql> select IFNULL(1/0,'ja');
+ -> 'ja'
+@end example
+
+@findex NULLIF()
+@item NULLIF(ausdruck1,ausdruck2)
+Wenn @code{ausdruck1 = ausdruck2} wahr ist, gibt die Funktion @code{NULL}
+zurück, ansonsten @code{ausdruck1}. Das ist dasselbe wie @code{CASE WHEN x
+= y THEN NULL ELSE x END}:
+@example
+mysql> select NULLIF(1,1);
+ -> NULL
+mysql> select NULLIF(1,2);
+ -> 1
+@end example
+
+Beachten Sie, dass @code{ausdruck1} in MySQL zweimal ausgewertet wird, wenn
+die Argumente gleich sind.
+
+@findex IF()
+@item IF(ausdruck1,ausdruck2,ausdruck3)
+Wenn @code{ausdruck1} TRUE ist (@code{ausdruck1 <> 0} und @code{ausdruck1
+<> NULL}), gibt @code{IF()} @code{ausdruck2} zurück, ansonsten
+@code{ausdruck3}. @code{IF()} gibt einen numerischen oder einen
+Zeichenketten-Wert zurück, je nachdem, in welchem Zusammenhang es benutzt
+wird:
+
+@example
+mysql> select IF(1>2,2,3);
+ -> 3
+mysql> select IF(1<2,'ja','nein');
+ -> 'ja'
+mysql> select IF(strcmp('test','test1'),'nein','ja');
+ -> 'nein'
+@end example
+
+@code{ausdruck1} wird als Ganzzahlwert ausgewertet, woraus folgt, dass Sie
+das Testen auf Fließkomma- oder Zeichenketten-Werte mit einer
+Vergleichsoperation durchführen sollten:
+
+@example
+mysql> select IF(0.1,1,0);
+ -> 0
+mysql> select IF(0.1<>0,1,0);
+ -> 1
+@end example
+
+Im ersten Fall gibt @code{IF(0.1)} @code{0} zurück, weil @code{0.1} in
+einen Ganzzahlwert umgewandelt wird, wodurch es auf @code{IF(0)} getestet
+wird. Das ist vielleicht nicht das, was Sie erwarten. Im zweiten Fall
+testet der Vergleich den Original-Fließkommawert, um zu sehen, ob er nicht
+0 ist. Das Ergebnis des Vergleichs wird als Ganzzahl benutzt.
+
+Der vorgabemäßige Rückgabewert von @code{IF()} (der eine Rolle spielen
+kann, wenn er in einer temporären Tabelle gespeichert wird), wird in
+MySQL-Version 3.23 wie folgt berechnet:
+
+@multitable @columnfractions .55 .45
+@item @strong{Ausdruck} @tab @strong{Rückgabewert}
+@item ausdruck2 oder ausdruck3 gibt Zeichenkette zurück @tab Zeichenkette
+@item ausdruck2 oder ausdruck3 gibt Fließkommawert zurück @tab Fließkommawert
+@item ausdruck2 oder ausdruck3 gibt Ganzzahl zurück @tab Ganzzahl
+@end multitable
+
+@findex CASE
+@item CASE wert WHEN [vergleichs-wert] THEN ergebnis [WHEN [vergleichs-wert] THEN ergebnis ...] [ELSE ergebnis] END
+@item CASE WHEN [bedingung] THEN ergebnis [WHEN [bedingung] THEN ergebnis ...] [ELSE ergebnis] END
+
+Die erste Version gibt @code{ergebnis} zurück, wo
+@code{wert=vergleichs-wert}. Die zweite Version gibt das Ergebnis für die
+erste Bedingung zurück, die WAHR ist. Wenn es keinen übereinstimmenden
+Ergebniswert gab, wird das Ergebnis nach @code{ELSE} zurückgegeben. Wenn es
+keinen @code{ELSE}-Teil gibt, wird @code{NULL} zurückgegeben:
+
+@example
+mysql> SELECT CASE 1 WHEN 1 THEN "eins" WHEN 2 THEN "zwei" ELSE "mehr" END;
+ -> "eins"
+mysql> SELECT CASE WHEN 1>0 THEN "wahr" ELSE "unwahr" END;
+ -> "wahr"
+mysql> SELECT CASE BINARY "B" when "a" then 1 when "b" then 2 END;
+ -> NULL
+@end example
+@end table
+
+Der Typ des Rückgabewerts (@code{INTEGER}, @code{DOUBLE} oder
+@code{STRING}) ist derselbe wie der Typ des ersten zurückgegebenen Werts
+(der Ausdruck nach dem ersten @code{THEN}).
+
+
+@node String functions, Numeric Functions, Non-typed Operators, Functions
+@c German node Zeichenketten-Funktionen
+@subsection Zeichenketten-Funktionen
+
+@findex Zeichenketten-Funktionen
+@findex Funktionen, Zeichenketten
+
+Funktionen für Zeichenkettenwerte geben @code{NULL} zurück, wenn die Länge
+des Ergebnisses größer wäre als der
+@code{max_allowed_packet}-Serverparameter. @xref{Server parameters}.
+
+Bei Funktionen, die mit Zeichenkettenpositionen arbeiten, wird die erste
+Position als 1 gezählt.
+
+@table @code
+@findex ASCII()
+@item ASCII(zeichenkette)
+Gibt den ASCII-Code-Wert des äußersten linken Zeichens der Zeichenkette
+@code{zeichenkette} zurück. Gibt @code{0} zurück, wenn @code{zeichenkette}
+die leere Zeichenkette ist. Gibt @code{NULL} zurück, wenn
+@code{zeichenkette} @code{NULL} ist:
+
+@example
+mysql> select ASCII('2');
+ -> 50
+mysql> select ASCII(2);
+ -> 50
+mysql> select ASCII('dx');
+ -> 100
+@end example
+
+Siehe auch @code{ORD()}-Funktion.
+
+@findex ORD()
+@item ORD(zeichenkette)
+Wenn das äußerste linke Zeichen der Zeichenkette @code{zeichenkette} ein
+Multi-Byte-Zeichen ist, gibt diese Funktion den Code des
+Multi-Byte-Zeichens zurück, indem der ASCII-Code-Wert des Zeichens in
+folgendem Format zurückgegeben wird:
+@code{((erstes byte ASCII code)*256+(zweites byte ASCII code))[*256+drittes byte ASCII code...]}.
+Wenn das äußerste linke Zeichen kein Multi-Byte-Zeichen ist, wird derselbe
+Wert wie bei der @code{ASCII()}-Funktion zurückgegeben:
+
+@example
+mysql> select ORD('2');
+ -> 50
+@end example
+
+@findex CONV()
+@item CONV(N,von_basis,zu_basis)
+Wandelt Zahlen zwischen verschiedenen Zahlsystemen um. Gibt eine
+Zeichenkettendarstellung der Zahl @code{N} zurück, umgewandelt von Basis
+@code{von_basis} zu Basis @code{zu_basis}. Gibt @code{NULL} zurück, wenn
+irgend ein Argument @code{NULL} ist. Das Argument @code{N} wird als
+Ganzzahl interpretiert, kann aber als Ganzzahl oder Zeichenkette angegeben
+werden. Die kleinste Basis ist @code{2} und die größte Basis @code{36}.
+Wenn @code{zu_basis} eine negative Zahl ist, wird @code{N} als
+vorzeichenbehaftete Zahl betrachtet. Ansonsten wird @code{N} als
+vorzeichenlos behandelt. @code{CONV} arbeitet mit 64-Bit-Genauigkeit:
+
+@example
+mysql> select CONV("a",16,2);
+ -> '1010'
+mysql> select CONV("6E",18,8);
+ -> '172'
+mysql> select CONV(-17,10,-18);
+ -> '-H'
+mysql> select CONV(10+"10"+'10'+0xa,10,10);
+ -> '40'
+@end example
+
+@findex BIN()
+@item BIN(N)
+Gibt eine Zeichenkettendarstellung des Binärwerts von @code{N} zurück,
+wobei @code{N} eine @code{BIGINT}-Zahl ist. Das ist äquivalent zu
+@code{CONV(N,10,2)}. Gibt @code{NULL} zurück, wenn @code{N} @code{NULL}
+ist:
+
+@example
+mysql> select BIN(12);
+ -> '1100'
+@end example
+
+@findex OCT()
+@item OCT(N)
+Gibt eine Zeichenkettendarstellung des Oktalwerts von @code{N} zurück,
+wobei @code{N} eine @code{BIGINT}-Zahl ist. Das ist äquivalent zu
+@code{CONV(N,10,8)}. Gibt @code{NULL} zurück, wenn @code{N} @code{NULL}
+ist:
+
+@example
+mysql> select OCT(12);
+ -> '14'
+@end example
+
+@findex HEX()
+@item HEX(N)
+Gibt eine Zeichenkettendarstellung des hexadezimalen Werts von @code{N}
+zurück, wobei @code{N} eine @code{BIGINT}-Zahl ist. Das ist äquivalent zu
+@code{CONV(N,10,16)}. Gibt @code{NULL} zurück, wenn @code{N} @code{NULL}
+ist:
+
+@example
+mysql> select HEX(255);
+ -> 'FF'
+@end example
+
+@findex CHAR()
+@item CHAR(N,...)
+@code{CHAR()} interpretiert die Argumente als Ganzzahlen und gibt eine
+Zeichenkette zurück, die aus den Zeichen besteht, die durch die
+ASCII-Code-Werte dieser Ganzzahlen gegeben sind. @code{NULL}-Werte werden
+übersprungen:
+
+@example
+mysql> select CHAR(77,121,83,81,'76');
+ -> 'MySQL'
+mysql> select CHAR(77,77.3,'77.3');
+ -> 'MMM'
+@end example
+
+@findex CONCAT()
+@item CONCAT(zeichenkette1,zeichenkette2,...)
+Gibt die Zeichenkette zurück, die durch die Verkettung der Argumente
+entsteht. Gibt @code{NULL} zurück, wenn irgend ein Argument @code{NULL}
+ist. Kann mehr als 2 Argumente haben. Ein numerisches Argument wird in die
+äquivalente Zeichenkettenform umgewandelt:
+
+@example
+mysql> select CONCAT('My', 'S', 'QL');
+ -> 'MySQL'
+mysql> select CONCAT('My', NULL, 'QL');
+ -> NULL
+mysql> select CONCAT(14.3);
+ -> '14.3'
+@end example
+
+@findex CONCAT_WS()
+@item CONCAT_WS(trennzeichen, zeichenkette1, zeichenkette2,...)
+
+@code{CONCAT_WS()} steht für CONCAT mit Trennzeichen und ist eine spezielle
+Form von @code{CONCAT()}. Das erste Argument ist das Trennzeichen für die
+restlichen Argumente. Das Trennzeichen kann eine Zeichenkette sein, so wie
+die übrigen Argumente. Wenn das Trennzeichen @code{NULL} ist, ist das
+Ergebnis @code{NULL}. Die Funktion überspringt jegliche @code{NULL}s und
+leere Zeichenketten nach dem Trennzeichen-Argument. Das Trennzeichen wird
+zwischen den zu verknüpfenden Zeichenketten hinzugefügt:
+
+@example
+mysql> select CONCAT_WS(",","Vorname","Zweiter Vorname","Nachname");
+ -> 'Vorname,Zweiter Vorname,Nachname'
+mysql> select CONCAT_WS(",","Vorname",NULL,"Nachname");
+ -> 'Vorname,Nachname'
+@end example
+
+@findex LENGTH()
+@findex OCTET_LENGTH()
+@findex CHAR_LENGTH()
+@findex CHARACTER_LENGTH()
+@item LENGTH(zeichenkette)
+@itemx OCTET_LENGTH(zeichenkette)
+@itemx CHAR_LENGTH(zeichenkette)
+@itemx CHARACTER_LENGTH(zeichenkette)
+Gibt die Länge der Zeichenkette @code{zeichenkette} an:
+
+@example
+mysql> select LENGTH('text');
+ -> 4
+mysql> select OCTET_LENGTH('text');
+ -> 4
+@end example
+
+Beachten Sie, dass bei @code{CHAR_LENGTH()} Multi-Byte-Zeichen nur einmal
+gezählt werden.
+
+@findex LOCATE()
+@findex POSITION()
+@item LOCATE(teilzeichenfolge,zeichenkette)
+@itemx POSITION(teilzeichenfolge IN zeichenkette)
+Gibt die Position des ersten Auftretens der Teilzeichenfolge
+@code{teilzeichenfolge} in der Zeichenkette @code{zeichenkette} an. Gibt
+@code{0} zurück, wenn @code{teilzeichenfolge} nicht in @code{zeichenkette}
+enthalten ist:
+
+@example
+mysql> select LOCATE('bar', 'foobarbar');
+ -> 4
+mysql> select LOCATE('xbar', 'foobar');
+ -> 0
+@end example
+
+Diese Funktion ist Multi-Byte-sicher.
+
+@findex LOCATE()
+@item LOCATE(teilzeichenfolge,zeichenkette,position)
+Gibt die Position des ersten Auftretens der Teilzeichenfolge
+@code{teilzeichenfolge} in der Zeichenkette @code{zeichenkette} ab Position
+@code{position} an. Gibt @code{0} zurück, wenn @code{teilzeichenfolge}
+nicht in @code{zeichenkette} enthalten ist:
+
+@example
+mysql> select LOCATE('bar', 'foobarbar',5);
+ -> 7
+@end example
+
+Diese Funktion ist Multi-Byte-sicher.
+
+@findex INSTR()
+@item INSTR(zeichenkette,teilzeichenfolge)
+Gibt die Position des ersten Auftretens der Teilzeichenfolge
+@code{teilzeichenfolge} in der Zeichenkette @code{zeichenkette} an. Das ist
+dasselbe wie @code{LOCATE()} mit zwei Argumenten, ausser dass die Argumente
+vertauscht sind:
+
+@example
+mysql> select INSTR('foobarbar', 'bar');
+ -> 4
+mysql> select INSTR('xbar', 'foobar');
+ -> 0
+@end example
+
+Diese Funktion ist Multi-Byte-sicher.
+
+@findex LPAD()
+@item LPAD(zeichenkette,laenge,fuellzeichenkette)
+Gibt die Zeichenkette @code{zeichenkette} zurück, links aufgefüllt mit der
+Zeichenkette @code{fuellzeichenkette}, bis @code{zeichenkette}
+@code{laenge} Zeichen lang ist. Wenn @code{zeichenkette} länger als
+@code{laenge} ist, wird sie auf @code{laenge} Zeichen verkürzt.
+
+@example
+mysql> select LPAD('hi',4,'??');
+ -> '??hi'
+@end example
+
+@findex RPAD()
+@item RPAD(zeichenkette,laenge,fuellzeichenkette)
+Gibt die Zeichenkette @code{zeichenkette} zurück, rechts aufgefüllt mit der
+Zeichenkette @code{fuellzeichenkette}, bis @code{zeichenkette}
+@code{laenge} Zeichen lang ist. Wenn @code{zeichenkette} länger als
+@code{laenge} ist, wird sie auf @code{laenge} Zeichen verkürzt.
+
+@example
+mysql> select RPAD('hi',5,'?');
+ -> 'hi???'
+@end example
+
+@findex LEFT()
+@item LEFT(zeichenkette,laenge)
+Gibt die äußersten linken @code{laenge} Zeichen der Zeichenkette
+@code{zeichenkette} zurück:
+
+@example
+mysql> select LEFT('foobarbar', 5);
+ -> 'fooba'
+@end example
+
+Diese Funktion ist Multi-Byte-sicher.
+
+@findex RIGHT()
+@item RIGHT(zeichenkette,laenge)
+Gibt die äußersten rechten @code{laenge} Zeichen der Zeichenkette
+@code{zeichenkette} zurück:
+
+@example
+mysql> select RIGHT('foobarbar', 4);
+ -> 'rbar'
+@end example
+
+Diese Funktion ist Multi-Byte-sicher.
+
+@findex SUBSTRING()
+@findex MID()
+@item SUBSTRING(zeichenkette,position,laenge)
+@itemx SUBSTRING(zeichenkette FROM position FOR laenge)
+@itemx MID(zeichenkette,position,laenge)
+Gibt eine @code{laenge} Zeichen lange Teilzeichenfolge der Zeichenkette
+@code{zeichenkette} ab Position @code{position} zurück. Die abweichende
+Form, die @code{FROM} benutzt, ist ANSI-SQL92-Syntax:
+
+@example
+mysql> select SUBSTRING('Heinzholger',5,6);
+ -> 'zholge'
+@end example
+
+Diese Funktion ist Multi-Byte-sicher.
+
+@findex SUBSTRING()
+@item SUBSTRING(zeichenkette,position)
+@item SUBSTRING(zeichenkette FROM position)
+Gibt eine Teilzeichenfolge der Zeichenkette @code{zeichenkette} ab Position
+@code{position} zurück:
+
+@example
+mysql> select SUBSTRING('Heinzholger',5);
+ -> 'zholger'
+mysql> select SUBSTRING('foobarbar' FROM 4);
+ -> 'barbar'
+@end example
+
+Diese Funktion ist Multi-Byte-sicher.
+
+@findex SUBSTRING_INDEX()
+@item SUBSTRING_INDEX(zeichenkette,begrenzer,zaehler)
+Gibt die Teilzeichenfolge von Zeichenkette @code{zeichenkette} vor
+@code{zaehler} Vorkommen des Begrenzers @code{begrenzer} zurück. Wenn
+@code{zaehler} positiv ist, wird alle links vom letzten Begrenzer
+zurückgegeben (von links gezählt). Wenn @code{zaehler} negativ ist, wird
+alles rechts vom letzten Begrenzer (von rechts gezählt) zurückgegeben:
+
+@example
+mysql> select SUBSTRING_INDEX('www.mysql.com', '.', 2);
+ -> 'www.mysql'
+mysql> select SUBSTRING_INDEX('www.mysql.com', '.', -2);
+ -> 'mysql.com'
+@end example
+
+Diese Funktion ist Multi-Byte-sicher.
+
+@findex LTRIM()
+@item LTRIM(zeichenkette)
+Gibt die Zeichenkette @code{zeichenkette} zurück, bei der führende
+Leerzeichen entfernt wurden:
+
+@example
+mysql> select LTRIM(' barbar');
+ -> 'barbar'
+@end example
+
+@findex RTRIM()
+@item RTRIM(zeichenkette)
+Gibt die Zeichenkette @code{zeichenkette} zurück, bei der Leerzeichen am
+Ende entfernt wurden:
+
+@example
+mysql> select RTRIM('barbar ');
+ -> 'barbar'
+@end example
+
+Diese Funktion ist Multi-Byte-sicher.
+
+@findex TRIM()
+@item TRIM([[BOTH | LEADING | TRAILING] [entfernzeichenkette] FROM] zeichenkette)
+Gibt die Zeichenkette @code{zeichenkette} zurück, bei der alle
+@code{entfernzeichenkette}-Präfixe und / oder -Suffixe entfernt wurden.
+Wenn keiner der Spezifizierer @code{BOTH}, @code{LEADING} oder
+@code{TRAILING} angegeben wird, wird @code{BOTH} angenommen. Wenn
+@code{entfernzeichenkette} nicht angegeben ist, werden Leerzeichen entfernt:
+
+@example
+mysql> select TRIM(' bar ');
+ -> 'bar'
+mysql> select TRIM(LEADING 'x' FROM 'xxxbarxxx');
+ -> 'barxxx'
+mysql> select TRIM(BOTH 'x' FROM 'xxxbarxxx');
+ -> 'bar'
+mysql> select TRIM(TRAILING 'xyz' FROM 'barxxyz');
+ -> 'barx'
+@end example
+
+Diese Funktion ist Multi-Byte-sicher.
+
+@findex SOUNDEX()
+@item SOUNDEX(zeichenkette)
+Gibt eine Soundex-Zeichenkette von @code{zeichenkette} zurück. Zwei
+Zeichenketten, die fast gleich klingen, sollten identische
+Soundex-Zeichenketten haben. Eine Standard-Soundex-Zeichenkette ist 4
+Zeichen lang, aber die @code{SOUNDEX()}-Funktion gibt eine beliebig lange
+Zeichenkette zurück. Sie können @code{SUBSTRING()} auf das Ergebnis
+anwenden, um eine Standard-Soundex-Zeichenkette zu erhalten. Alle nicht
+alphanumerischen Zeichen in der angegebenen Zeichenkette werden ignoriert.
+Alle internationalen alphabetischen Zeichen ausserhalb des Wertebereichs A
+bis Z werden als Vokale behandelt:
+
+@example
+mysql> select SOUNDEX('Hello');
+ -> 'H400'
+mysql> select SOUNDEX('Quadratically');
+ -> 'Q36324'
+@end example
+
+@findex SPACE()
+@item SPACE(N)
+Gibt eine Zeichenkette zurück, die aus @code{N} Leerzeichen besteht:
+
+@example
+mysql> select SPACE(6);
+ -> ' '
+@end example
+
+@findex REPLACE()
+@item REPLACE(zeichenkette,von_zeichenkette,zu_zeichenkette)
+Gibt die Zeichenkette @code{zeichenkette} zurück, bei der alle Vorkommen
+der Zeichenkette @code{von_zeichenkette} durch die Zeichenkette
+@code{zu_zeichenkette} ersetzt wurden:
+
+@example
+mysql> select REPLACE('www.mysql.com', 'w', 'Ww');
+ -> 'WwWwWw.mysql.com'
+@end example
+
+Diese Funktion ist Multi-Byte-sicher.
+
+@findex REPEAT()
+@item REPEAT(zeichenkette,zaehler)
+Gibt eine Zeichenkette zurück, die aus der Zeichenkette @code{zeichenkette}
+besteht, die @code{zaehler} mal wiederholt wurde. Wenn @code{zaehler <= 0}
+ist, wird eine leere Zeichenkette zurückgegeben. Gibt @code{NULL} zurück,
+wenn @code{zeichenkette} oder @code{zaehler} @code{NULL} sind:
+
+@example
+mysql> select REPEAT('MySQL', 3);
+ -> 'MySQLMySQLMySQL'
+@end example
+
+@findex REVERSE()
+@item REVERSE(zeichenkette)
+Gibt die Zeichenkette @code{zeichenkette} in umgedrehter Reihenfolge der
+Zeichen zurück:
+
+@example
+mysql> select REVERSE('abc');
+ -> 'cba'
+@end example
+
+Diese Funktion ist Multi-Byte-sicher.
+
+@findex INSERT()
+@item INSERT(zeichenkette,position,laenge,neue_zeichenkette)
+Gibt die Zeichenkette @code{zeichenkette} zurück, wobei eine
+Teilzeichenfolge ab Position @code{position} mit @code{laenge} Zeichen
+Länge durch die Zeichenkette @code{neue_zeichenkette} ersetzt wurde:
+
+@example
+mysql> select INSERT('Heinzholger', 6, 4, 'DIET');
+ -> 'HeinzDIETer'
+@end example
+
+Diese Funktion ist Multi-Byte-sicher.
+
+@findex ELT()
+@item ELT(N,zeichenkette1,zeichenkette2,zeichenkette3,...)
+Gibt @code{zeichenkette1} zurück, wenn @code{N} = @code{1} ist,
+@code{zeichenkette2}, wenn @code{N} = @code{2} ist usw.. Gibt @code{NULL}
+zurück, wenn @code{N} kleiner als @code{1} oder größer als die Anzahl von
+Argumenten ist. @code{ELT()} ist das Komplement von @code{FIELD()}:
+
+@example
+mysql> select ELT(1, 'ej', 'Heja', 'hej', 'foo');
+ -> 'ej'
+mysql> select ELT(4, 'ej', 'Heja', 'hej', 'foo');
+ -> 'foo'
+@end example
+
+@findex FIELD()
+@item FIELD(zeichenkette,zeichenkette1,zeichenkette2,zeichenkette3,...)
+Gibt den Index von @code{zeichenkette} in der Liste @code{zeichenkette1},
+@code{zeichenkette2}, @code{zeichenkette3}, @code{...} zurück. Gibt
+@code{0} zurück, wenn @code{zeichenkette} nicht gefunden wird.
+@code{FIELD()} ist das Komplement von @code{ELT()}:
+
+@example
+mysql> select FIELD('ej', 'Hej', 'ej', 'Heja', 'hej', 'foo');
+ -> 2
+mysql> select FIELD('fo', 'Hej', 'ej', 'Heja', 'hej', 'foo');
+ -> 0
+@end example
+
+@findex FIND_IN_SET()
+@item FIND_IN_SET(zeichenkette,zeichenkettenliste)
+Gibt einen Wert @code{1} bis @code{N} zurück, wenn die Zeichenkette
+@code{zeichenkette} in der Liste @code{zeichenkettenliste} ist, die aus
+@code{N} Teilzeichenfolgen besteht. Eine Zeichenkettenliste ist eine
+Zeichenkette, die aus Teilzeichenfolgen zusammen gesetzt ist, die durch
+@samp{,}-Zeichen getrennt sind. Wenn das erste Argument eine
+Zeichenketten-Konstante ist und das zweite eine Spalte des Typs @code{SET},
+wird die @code{FIND_IN_SET()}-Funktion optimiert, Bit-Arithmetik zu
+benutzen! Gibt @code{0} zurück, wenn @code{zeichenkette} nicht in
+@code{zeichenkettenliste} ist oder wenn @code{zeichenkettenliste} die leere
+Zeichenkette ist. Gibt @code{NULL} zurück, wenn eines oder beide Argumente
+@code{NULL} sind. Diese Funktion funktioniert nicht korrekt, wenn das erste
+Argument ein @samp{,} enthält:
+
+@example
+mysql> SELECT FIND_IN_SET('b','a,b,c,d');
+ -> 2
+@end example
+
+@findex MAKE_SET()
+@item MAKE_SET(bits,zeichenkette1,zeichenkette2,...)
+Gibt einen Satz (eine Zeichenkette, die Teilzeichenfolgen enthält, die
+durch @samp{,} getrennt sind) zurück, der aus Zeichenketten besteht, die
+das entsprechende Bit in @code{bits} gesetzt haben. @code{zeichenkette1}
+entspricht Bit 0, @code{zeichenkette2} Bit 1 usw. @code{NULL}-Zeichenketten
+in @code{zeichenkette1}, @code{zeichenkette2} usw. werden nicht an das
+Ergebnis angehängt:
+
+@example
+mysql> SELECT MAKE_SET(1,'a','b','c');
+ -> 'a'
+mysql> SELECT MAKE_SET(1 | 4,'hallo','liebe','welt');
+ -> 'hallo,welt'
+mysql> SELECT MAKE_SET(0,'a','b','c');
+ -> ''
+@end example
+
+@findex EXPORT_SET()
+@item EXPORT_SET(bits,an,aus,[trennzeichen,[anzahl_bits]])
+Gibt eine Zeichenkette zurück, in der Sie für jedes bit, das in 'bit'
+gesetzt ist, eine 'an'-Zeichenkette erhalten, und für jedes zurückgesetzte
+Bit eine 'aus'-Zeichenkette. Jede Zeichenkette wird mit 'trennzeichen'
+getrennt (vorgabemäßig ','), und nur die 'anzahl_bits' (vorgabemäßig 64)
+von 'bits' wird benutzt:
+
+@example
+mysql> select EXPORT_SET(5,'Y','N',',',4)
+ -> Y,N,Y,N
+@end example
+
+@findex LCASE()
+@findex LOWER()
+@item LCASE(zeichenkette)
+@itemx LOWER(zeichenkette)
+Gibt die Zeichenkette @code{zeichenkette} zurück, bei der alle Zeichen in
+Kleinschreibung gemäß dem aktuellen Zeichensatz-Mapping (Vorgabe ist
+ISO-8859-1 Latin1) umgewandelt wurden:
+
+@example
+mysql> select LCASE('HEINZholger');
+ -> 'heinzholger'
+@end example
+
+Diese Funktion ist Multi-Byte-sicher.
+
+@findex UCASE()
+@findex UPPER()
+@item UCASE(zeichenkette)
+@itemx UPPER(zeichenkette)
+Gibt die Zeichenkette @code{zeichenkette} zurück, bei der alle Zeichen in
+Großschreibung gemäß dem aktuellen Zeichensatz-Mapping (Vorgabe ist
+ISO-8859-1 Latin1) umgewandelt wurden:
+
+@example
+mysql> select UCASE('Hej');
+ -> 'HEJ'
+@end example
+
+Diese Funktion ist Multi-Byte-sicher.
+
+@findex FILE
+@findex LOAD_FILE()
+@item LOAD_FILE(datei)
+Liest die Datei @code{datei} und gibt den Dateiinhalt als Zeichenkette
+zurück. Die Datei muss auf dem Server sein, Sie müssen den vollen Pfadnamen
+zur Datei angeben und Sie müssen die @strong{file}-Berechtigung besitzen.
+Die Datei muss von allen lesbar sein und kleiner als
+@code{max_allowed_packet}.
+
+Wenn die Datei nicht existiert oder aus den oben genannten Gründen nicht
+gelesen werden kann, gibt die Funktion @code{NULL} zurück:
+
+@example
+mysql> UPDATE tabelle
+ SET blob_spalte=LOAD_FILE("/tmp/bild")
+ WHERE id=1;
+@end example
+@end table
+
+Wenn Sie nicht MySQL-Version 3.23 benutzen, müssen Sie das Lesen der Datei
+innerhalb Ihrer Applikation durchführen und ein @code{INSERT}-Statement
+erzeugen, um die Datenbank mit der Dateiinformation zu aktualisieren. Eine
+Art, das zu tun, finden Sie - wenn Sie die MySQL++-Bibliothek benutzen -
+unter
+@uref{http://www.mysql.com/documentation/mysql++/mysql++-examples.html}.
+
+MySQL konvertiert Zahlen bei Bedarf automatisch in Zeichenketten, und
+umgekehrt:
+
+@example
+mysql> SELECT 1+"1";
+ -> 2
+mysql> SELECT CONCAT(2,' test');
+ -> '2 test'
+@end example
+
+Wenn Sie eine Zahl explizit in eine Zeichenkette umwandeln wollen,
+übergeben Sie sie als Argument an @code{CONCAT()}.
+
+Wenn in einer Zeichenketten-Funktion eine binäre Zeichenkette als Argument
+angegeben wird, ist die resultierende Zeichenkette ebenfalls eine binäre
+Zeichenkette. Eine Zahl, die in eine Zeichenkette umgewandelt wird, wird
+als binäre Zeichenkette behandelt. Das betrifft nur Vergleichsoperationen.
+
+
+
+@menu
+* String comparison functions::
+* Case Sensitivity Operators::
+@end menu
+
+@node String comparison functions, Case Sensitivity Operators, String functions, String functions
+@c German node Zeichenketten-Vergleichsfunktionen
+@subsubsection Zeichenketten-Vergleichsfunktionen
+
+@findex Zeichenketten-Vergleichsfunktionen
+@findex Funktionen, Zeichenketten-Vergleich
+
+@cindex Groß-/Kleinschreibung, in Zeichenketten-Vergleichen
+@cindex Zeichenketten-Vergleiche, Groß-/Kleinschreibung
+
+Normalerweise wird ein Vergleich unter Berücksichtigung der
+Groß-/Kleinschreibung durchgeführt, wenn irgend ein Ausdruck in einem
+Zeichenkettenvergleich abhängig von der verwendeten Groß-/Kleinschreibung
+ist.
+
+@table @code
+@findex LIKE
+@item ausdruck LIKE muster [ESCAPE 'fluchtzeichen']
+Mustervergleich, der den einfachen SQL-Vergleich mit regulären Ausdrücken
+benutzt. Gibt @code{1} (TRUE) oder @code{0} (FALSE) zurück. Bei @code{LIKE}
+können Sie die folgenden zwei Platzhalterzeichen im Muster benutzen:
+
+@multitable @columnfractions .1 .9
+@item @code{%} @tab Entspricht einer beliebigen Anzahl von Zeichen, selbst 0 Zeichen
+@item @code{_} @tab Entspricht genau einem Zeichen
+@end multitable
+
+@example
+mysql> select 'David!' LIKE 'David_';
+ -> 1
+mysql> select 'David!' LIKE '%D%v%';
+ -> 1
+@end example
+
+Um auf literale Instanzen des Platzhalterzeichens zu testen, stellen Sie
+dem Zeichen ein Fluchtzeichen (Escape-Zeichen) voran. Wenn Sie das
+@code{ESCAPE}-Zeichen nicht angeben, wird @samp{\} angenommen:
+
+@multitable @columnfractions .1 .9
+@item @code{\%} @tab Entspricht einem @code{%}-Zeichen
+@item @code{\_} @tab Entspricht einem @code{_}-Zeichen
+@end multitable
+
+@example
+mysql> select 'David!' LIKE 'David\_';
+ -> 0
+mysql> select 'David_' LIKE 'David\_';
+ -> 1
+@end example
+
+Um ein anderes Fluchtzeichen (Escape-Zeichen) anzugeben, benutzen Sie die
+@code{ESCAPE}-Klausel:
+
+@example
+mysql> select 'David_' LIKE 'David|_' ESCAPE '|';
+ -> 1
+@end example
+
+Die folgenden beiden Statements zeigen, dass Zeichenketten-Vergleiche die
+Groß-/Kleinschreibung nicht berücksichtigen, solange nicht einer der
+Operanden eine binäre Zeichenkette ist:
+case insensitive unless one of the operands ist a binäre Zeichenkette:
+
+@example
+mysql> select 'abc' LIKE 'ABC';
+ -> 1
+mysql> SELECT 'abc' LIKE BINARY 'ABC';
+ -> 0
+@end example
+
+@code{LIKE} ist bei numerischen Ausdrücken zulässig! (Das ist eine
+MySQL-Erweiterung zum ANSI-SQL-@code{LIKE}.)
+
+@example
+mysql> select 10 LIKE '1%';
+ -> 1
+@end example
+
+HINWEIS: Weil MySQL die C Escape-Syntax in Zeichenketten benutzt
+(beispielsweise @samp{\n}), müssen Sie jedes @samp{\}-Zeichen, das Sie in
+@code{LIKE}-Zeichenketten benutzen, verdoppeln. Um zum Beispiel nach
+@samp{\n} zu suchen, geben Sie @samp{\\n} ein. Um nach @samp{\} zu suchen,
+geben Sie @samp{\\\\} ein (die Backslashes werden einmal vom Parser
+entfernt und noch einmal, wenn der Mustervergleich durchgeführt wird, so
+dass letztlich ein einzelner Backslash übrig bleibt).
+
+@findex NOT LIKE
+@item ausdruck NOT LIKE muster [ESCAPE 'fluchtzeichen']
+Dasselbe wie @code{NOT (ausdruck LIKE muster [ESCAPE 'fluchtzeichen'])}.
+
+@cindex mSQL-Kompatibilität
+@cindex Kompatibilität, mit mSQL
+@findex REGEXP
+@findex RLIKE
+@item ausdruck REGEXP muster
+@itemx ausdruck RLIKE muster
+Führt einen Mustervergleich eines Zeichenkettenausdrucks @code{ausdruck}
+gegen ein Muster @code{muster} durch. Das Muster kann ein erweiterter
+regulärer Ausdruck sein. @xref{Regexp}. Gibt @code{1} zurück, wenn
+@code{ausdruck} mit @code{muster} übereinstimmt, ansonsten @code{0}.
+@code{RLIKE} ist ein Synonym für @code{REGEXP}, was aus Gründen der
+@code{mSQL}-Kompatibilität zur Verfügung steht. HINWEIS: Weil MySQL die
+C-Escape-Syntax in Zeichenketten benutzt (beispielsweise @samp{\n}), müssen
+Sie jeden @samp{\}, den Sie in Ihren @code{REGEXP}-Zeichenketten benutzen,
+verdoppeln. Ab MySQL-Version 3.23.4 berücksichtigt @code{REGEXP} nicht die
+verwendete Groß-/Kleinschreibung für normale (nicht binäre)
+Zeichenketten:
+
+@example
+mysql> select 'Monty!' REGEXP 'm%y%%';
+ -> 0
+mysql> select 'Monty!' REGEXP '.*';
+ -> 1
+mysql> select 'new*\n*line' REGEXP 'new\\*.\\*line';
+ -> 1
+mysql> select "a" REGEXP "A", "a" REGEXP BINARY "A";
+ -> 1 0
+mysql> select "a" REGEXP "^[a-d]";
+ -> 1
+@end example
+
+@item
+@code{REGEXP} und @code{RLIKE} benutzen den aktuellen Zeichensatz
+(vorgabemäßig ISO-8859-1 Latin1), wenn über den Typ eines Zeichens
+entschieden wird.
+
+@findex NOT REGEXP
+@item ausdruck NOT REGEXP muster
+@itemx ausdruck NOT RLIKE muster
+Dasselbe wie @code{NOT (ausdruck REGEXP muster)}.
+
+@findex STRCMP()
+@item STRCMP(ausdruck1,ausdruck2)
+@code{STRCMP()} gibt @code{0} zurück, wenn die Zeichenketten gleich sind,
+@code{-1}, wenn das erste Argument kleiner als das zweite ist (nach der
+aktuellen Sortierreihenfolge), und ansonsten @code{1}:
+
+@example
+mysql> select STRCMP('text', 'text2');
+ -> -1
+mysql> select STRCMP('text2', 'text');
+ -> 1
+mysql> select STRCMP('text', 'text');
+ -> 0
+@end example
+
+@findex MATCH ... AGAINST()
+@item MATCH (spalte1,spalte2,...) AGAINST (ausdruck)
+@code{MATCH ... AGAINST()} wird für Volltextsuche benutzt und gibt die
+Relevanz zurück - ein Ähnlichkeitsmaß zwischen dem Text in den Spalten
+@code{(spalte1,spalte2,...)} und der Anfrage @code{ausdruck}. Die Relevanz
+ist eine positive Fließkommazahl. 0 Relevanz bedeutet keine Ähnlichkeit.
+Damit @code{MATCH ... AGAINST()} funktioniert, muss zuerst ein
+@strong{FULLTEXT}-Index erzeugt werden. @xref{CREATE TABLE, , @code{CREATE TABLE}}. @code{MATCH ... AGAINST()} ist verfügbar ab MySQL-Version 3.23.23.
+Für Details und Benutzungsbeispiele siehe @pxref{Fulltext Search}.
+@end table
+
+
+@node Case Sensitivity Operators, , String comparison functions, String functions
+@c German node Operatoren und Groß-/Kleinschreibung
+@subsubsection Groß-/Kleinschreibung
+
+@findex Casts
+
+@cindex Cast-Operatoren
+@cindex Operatoren, Cast-
+
+@table @code
+@findex BINARY
+@item @code{BINARY}
+Der @code{BINARY}-Operator macht die folgende Zeichenkette zu einer binären
+Zeichenkette. Das ist eine einfache Möglichkeit, einen Spaltenvergleich
+zwangsweise in Abhängigkeit von der verwendeten Groß-/Kleinschreibung
+durchzuführen, selbst wenn die Spalte nicht als @code{BINARY} oder
+@code{BLOB} definiert ist:
+@example
+mysql> select "a" = "A";
+ -> 1
+mysql> select BINARY "a" = "A";
+ -> 0
+@end example
+
+@code{BINARY} wurde in MySQL-Version 3.23.0 eingeführt.
+
+Beachten Sie, dass MySQL in manchen Fällen nicht in der Lage ist, den Index
+effizient zu benutzen, wenn Sie eine indizierte Spalte zu @code{BINARY}
+machen.
+@end table
+
+Wenn Sie ein Blob ohne Berücksichtigung der Groß-/Kleinschreibung
+vergleichen wollen, können Sie den Blob jederzeit in Großschreibung
+umwandeln, bevor Sie den Vergleich durchführen:
+
+@example
+SELECT 'A' LIKE UPPER(blob_spalte) FROM tabelle;
+@end example
+
+Wir planen, bald Casting zwischen unterschiedlichen Zeichensätzen
+einzuführen, um Zeichenketten-Vergleiche noch flexibler zu machen.
+
+
+@node Numeric Functions, Date and time functions, String functions, Functions
+@c German node Numerische Funktionen
+@subsection Numerische Funktionen
+
+
+
+@menu
+* Arithmetic functions::
+* Mathematical functions::
+@end menu
+
+@node Arithmetic functions, Mathematical functions, Numeric Functions, Numeric Functions
+@c German node Arithmetische Funktionen
+@subsubsection Arithmetische Operationen
+
+Es gibt die üblichen arithmetischen Operatoren. Beachten Sie, dass das
+Ergebnis im Falle von @samp{-}, @samp{+} und @samp{*} mit
+@code{BIGINT}-Genauigkeit (64-Bit) berechnet wird, wenn beide Argumente
+Ganzzahlen sind!
+
+@cindex Operationen, arithmetische
+@cindex arithmetische Ausdrücke
+@table @code
+@findex + (Addition)
+@findex Addition (+)
+@item +
+Addition:
+@example
+mysql> select 3+5;
+ -> 8
+@end example
+
+@findex - (Subtraktion)
+@findex Subtraktion (-)
+@item -
+Subtraktion:
+@example
+mysql> select 3-5;
+ -> -2
+@end example
+
+@findex * (Multiplikation)
+@findex Multiplikation (*)
+@item *
+Multiplication:
+@example
+mysql> select 3*5;
+ -> 15
+mysql> select 18014398509481984*18014398509481984.0;
+ -> 324518553658426726783156020576256.0
+mysql> select 18014398509481984*18014398509481984;
+ -> 0
+@end example
+
+Das Ergebnis des letzten Ausdrucks ist falsch, weil die
+Ganzzahl-Multiplikation den 64-Bit-Wertebereich von
+@code{BIGINT}-Berechnungen überschreitet.
+
+@findex / (Division)
+@findex Division (/)
+@item /
+Division:
+@example
+mysql> select 3/5;
+ -> 0.60
+@end example
+
+Division durch 0 erzeugt ein @code{NULL}-Ergebnis:
+
+@example
+mysql> select 102/(1-1);
+ -> NULL
+@end example
+
+Eine Division wird nur dann mit @code{BIGINT}-Arithmetik berechnet, wenn
+sie in einem Zusammenhang durchgeführt wird, in dem das Ergebnis in eine
+Ganzzahl umgewandelt wird!
+@end table
+
+
+@node Mathematical functions, , Arithmetic functions, Numeric Functions
+@c German node Mathematische Funktionen
+@subsubsection Mathematische Funktionen
+Alle mathematischen Funktionen geben im Fehlerfall @code{NULL} zurück.
+
+@findex mathematische Funktionen
+@findex Funktionen, mathematische
+
+@table @code
+@findex - (unäres Minus)
+@findex Minus, unäres (-)
+@findex unäres Minus (-)
+@item -
+Unäres Minus. Ändert das Vorzeichen des Arguments:
+@example
+mysql> select - 2;
+ -> -2
+@end example
+
+Wenn dieser Operator mit einer @code{BIGINT} benutzt wird, beachten Sie,
+dass der Rückgabewert eine @code{BIGINT} ist! Das bedeutet, dass Sie
+@code{-} auf Ganzzahlen, die den Wert @code{-2^63} haben könnten, vermeiden
+sollten!
+
+@findex ABS()
+@item ABS(X)
+Gibt den absoluten Wert von @code{X} zurück:
+@example
+mysql> select ABS(2);
+ -> 2
+mysql> select ABS(-32);
+ -> 32
+@end example
+
+Diese Funktion kann bei @code{BIGINT}-Werten sicher benutzt werden.
+
+@findex SIGN()
+@item SIGN(X)
+Gibt das Vorzeichen des Arguments als @code{-1}, @code{0} oder @code{1}
+zurück, abhängig davon, ob @code{X} negativ, 0 oder positiv ist:
+@example
+mysql> select SIGN(-32);
+ -> -1
+mysql> select SIGN(0);
+ -> 0
+mysql> select SIGN(234);
+ -> 1
+@end example
+
+@findex MOD()
+@c German FIX added space before %
+@findex % (Modulo)
+@findex Modulo (%)
+@item MOD(N,M)
+@c German FIX added space before %
+@itemx %
+Modulo (wie der @code{%}-Operator in C). Gibt den Rest von @code{N}
+dividiert durch @code{M} zurück:
+@example
+mysql> select MOD(234, 10);
+ -> 4
+mysql> select 253% 7;
+ -> 1
+mysql> select MOD(29,9);
+ -> 2
+@end example
+
+Diese Funktion kann bei @code{BIGINT}-Werten sicher benutzt werden.
+
+@findex FLOOR()
+@item FLOOR(X)
+Gibt den größten Ganzzahl-Wert zurück, der nicht größer als @code{X}
+ist:
+@example
+mysql> select FLOOR(1.23);
+ -> 1
+mysql> select FLOOR(-1.23);
+ -> -2
+@end example
+
+Beachten Sie, dass der Rückgabewert in eine @code{BIGINT} umgewandelt
+wird!
+
+@findex CEILING()
+@item CEILING(X)
+Gibt den kleinsten Ganzzahl-Wert zurück, der nicht kleiner als @code{X}
+ist:
+@example
+mysql> select CEILING(1.23);
+ -> 2
+mysql> select CEILING(-1.23);
+ -> -1
+@end example
+
+Beachten Sie, dass der Rückgabewert in eine @code{BIGINT} umgewandelt wird!
+
+@findex ROUND()
+@item ROUND(X)
+Gibt das Argument @code{X} zurück, gerundet auf die nächste Ganzzahl:
+@example
+mysql> select ROUND(-1.23);
+ -> -1
+mysql> select ROUND(-1.58);
+ -> -2
+mysql> select ROUND(1.58);
+ -> 2
+@end example
+
+Beachten Sie, dass das Verhalten von @code{ROUND()} abhängig von der
+C-Bibliothek-Implementation ist, wenn das Argument in der Mitte zwischen
+zwei Ganzzahlen liegt. Einige runden auf die nächste gerade Zahl, oder
+immer nach oben, immer nach unten oder immer Richtung 0. Wenn Sie eine
+bestimmte Art zu runden brauchen, sollten Sie statt dessen wohldefinierte
+Funktionen wie @code{TRUNCATE()} oder @code{FLOOR()} benutzen.
+
+@findex ROUND()
+@item ROUND(X,D)
+Gibt das Argument @code{X} zurück, gerundet auf eine Zahl mit @code{D}
+Dezimalstellen. Wenn @code{D} @code{0} ist, hat das Ergebnis keinen
+Dezimalpunkt oder Bruchteil:
+
+@example
+mysql> select ROUND(1.298, 1);
+ -> 1.3
+mysql> select ROUND(1.298, 0);
+ -> 1
+@end example
+
+@findex EXP()
+@item EXP(X)
+Gibt den Wert @code{e} (die Basis des natürlichen Logarithmus) hoch
+@code{X} zurück:
+@example
+mysql> select EXP(2);
+ -> 7.389056
+mysql> select EXP(-2);
+ -> 0.135335
+@end example
+@findex LOG()
+@item LOG(X)
+Gibt den natürlichen Logarithmus von @code{X} zurück:
+@example
+mysql> select LOG(2);
+ -> 0.693147
+mysql> select LOG(-2);
+ -> NULL
+@end example
+Wenn Sie den Logarithmus einer Zahl @code{X} zu einer beliebigen Basis
+@code{B} errechnen wollen, benutzen Sie die Formel @code{LOG(X)/LOG(B)}.
+
+@findex LOG10()
+@item LOG10(X)
+Gibt den Logarithmus zur Basis 10 von @code{X} zurück:
+@example
+mysql> select LOG10(2);
+ -> 0.301030
+mysql> select LOG10(100);
+ -> 2.000000
+mysql> select LOG10(-100);
+ -> NULL
+@end example
+
+@findex POW()
+@findex POWER()
+@item POW(X,Y)
+@itemx POWER(X,Y)
+Gibt den Wert @code{X} hoch @code{Y} zurück:
+@example
+mysql> select POW(2,2);
+ -> 4.000000
+mysql> select POW(2,-2);
+ -> 0.250000
+@end example
+
+@findex SQRT()
+@item SQRT(X)
+Gibt die nicht negative Quadratwurzel von @code{X} zurück:
+@example
+mysql> select SQRT(4);
+ -> 2.000000
+mysql> select SQRT(20);
+ -> 4.472136
+@end example
+
+@findex PI()
+@item PI()
+Gibt den Wert PI zurück. Die vorgabemäßig angezeigte Anzahl von
+Dezimalstellen ist 5, aber MySQL benutzt intern die volle doppelte
+Genauigkeit für PI.
+@example
+mysql> select PI();
+ -> 3.141593
+mysql> SELECT PI()+0.000000000000000000;
+ -> 3.141592653589793116
+@end example
+
+@findex COS()
+@item COS(X)
+Gibt den Cosinus von @code{X} zurück, wobei @code{X} in Radianten angegeben
+wird:
+@example
+mysql> select COS(PI());
+ -> -1.000000
+@end example
+
+@findex SIN()
+@item SIN(X)
+Gibt den Sinus von @code{X} zurück, wobei @code{X} in Radianten angegeben
+wird:
+@example
+mysql> select SIN(PI());
+ -> 0.000000
+@end example
+
+@findex TAN()
+@item TAN(X)
+Gibt den Tangens von @code{X} zurück, wobei @code{X} in Radianten angegeben
+wird:
+@example
+mysql> select TAN(PI()+1);
+ -> 1.557408
+@end example
+
+@findex ACOS()
+@item ACOS(X)
+Gibt den Arcuscosinus von @code{X} zurück, dass heißt den Wert, dessen
+Cosinus @code{X} ist. Gibt @code{NULL} zurück, wenn @code{X} nicht im
+Bereich von @code{-1} bis @code{1} liegt:
+@example
+mysql> select ACOS(1);
+ -> 0.000000
+mysql> select ACOS(1.0001);
+ -> NULL
+mysql> select ACOS(0);
+ -> 1.570796
+@end example
+
+@findex ASIN()
+@item ASIN(X)
+Gibt den Arcussinus von @code{X} zurück, das heißt den Wert, dessen Sinus
+@code{X} ist. Gibt @code{NULL} zurück, wenn @code{X} nicht im Bereich von
+@code{-1} bis @code{1} liegt:
+@example
+mysql> select ASIN(0.2);
+ -> 0.201358
+mysql> select ASIN('foo');
+ -> 0.000000
+@end example
+
+@findex ATAN()
+@item ATAN(X)
+Gibt den Arcustangens von @code{X} zurück, das heißt den Wert, dessen
+Tangens @code{X} ist:
+@example
+mysql> select ATAN(2);
+ -> 1.107149
+mysql> select ATAN(-2);
+ -> -1.107149
+@end example
+
+@findex ATAN2()
+@item ATAN2(Y,X)
+Gibt den Arcustangens der beiden Variablen @code{X} und @code{Y} zurück.
+Das ähnelt der Berechnung des Arcustangens von @code{Y / X}, ausser dass
+die Vorzeichen beider Argumente benutzt werden, um den Quadranten des
+Ergebnisses zu bestimmen:
+@example
+mysql> select ATAN(-2,2);
+ -> -0.785398
+mysql> select ATAN(PI(),0);
+ -> 1.570796
+@end example
+
+@findex COT()
+@item COT(X)
+Gibt den Cotangens von @code{X} zurück:
+@example
+mysql> select COT(12);
+ -> -1.57267341
+mysql> select COT(0);
+ -> NULL
+@end example
+
+@findex RAND()
+@item RAND()
+@itemx RAND(N)
+Gibt eine Zufallszahl (Fließkommawert) im Bereich von @code{0} bis
+@code{1.0} zurück. Wenn ein Ganzzahl-Argument @code{N} angegeben wird, wird
+es als Ausgangswert benutzt:
+@example
+mysql> select RAND();
+ -> 0.5925
+mysql> select RAND(20);
+ -> 0.1811
+mysql> select RAND(20);
+ -> 0.1811
+mysql> select RAND();
+ -> 0.2079
+mysql> select RAND();
+ -> 0.7888
+@end example
+Sie können eine Spalte mit @code{RAND()}-Werten nicht in einer @code{ORDER
+BY}-Klausel verwenden, weil @code{ORDER BY} die Spalte mehrfach auswerten
+würde. In MySQL-Version 3.23 können Sie jedoch folgendes tun:
+@code{SELECT * FROM tabelle ORDER BY RAND()}
+
+Das ist nützlich, um eine Zufallsstichprobe aus @code{SELECT * FROM
+tabelle1,tabelle2 WHERE a=b AND c<d ORDER BY RAND() LIMIT 1000} zu
+erhalten.
+
+Beachten Sie, dass ein @code{RAND()} in einer @code{WHERE}-Klausel jedes
+Mal von Neuem ausgewertet wird, wenn @code{WHERE} ausgeführt wird.
+
+@findex LEAST()
+@item LEAST(X,Y,...)
+Mit zwei oder mehr Argumenten gibt die Funktion das kleinste Argument (das
+mit dem niedrigsten Wert) zurück. Die Argumente werden nach folgenden
+Regeln verglichen:
+
+@itemize @bullet
+@item
+Wenn der Rückgabewert in einem @code{INTEGER}-Zusammenhang benutzt wird
+oder alle Argumente Ganzzahl-Werte sind, werden sie als Ganzzahlen
+verglichen.
+
+@item
+Wenn der Rückgabewert in einem @code{REAL}-Zusammenhang benutzt wird oder
+alle Argumente Realzahlen sind, werden sie als Realzahlen verglichen.
+
+@item
+Wenn irgend ein Argument eine von der Groß-/Kleinschreibung abhängige
+Zeichenkette ist, werden die Argumente als Zeichenketten, die von der
+Groß-/Kleinschreibung abhängen, verglichen.
+
+@item
+In sonstigen Fällen werden die Argumente als Zeichenketten verglichen, die
+nicht von der Groß-/Kleinschreibung abhängen:
+@end itemize
+
+@example
+mysql> select LEAST(2,0);
+ -> 0
+mysql> select LEAST(34.0,3.0,5.0,767.0);
+ -> 3.0
+mysql> select LEAST("B","A","C");
+ -> "A"
+@end example
+In MySQL-Versionen vor Version 3.22.5 können Sie @code{MIN()} statt
+@code{LEAST} benutzen.
+
+@findex GREATEST()
+@item GREATEST(X,Y,...)
+Gibt das größte Argument (das mit dem höchsten Wert) zurück. Die Argumente
+werden nach denselben Regeln wie bei @code{LEAST} verglichen:
+@example
+mysql> select GREATEST(2,0);
+ -> 2
+mysql> select GREATEST(34.0,3.0,5.0,767.0);
+ -> 767.0
+mysql> select GREATEST("B","A","C");
+ -> "C"
+@end example
+In MySQL-Versionen vor Version 3.22.5 können Sie @code{MAX()} statt
+@code{GREATEST} benutzen.
+
+@findex DEGREES()
+@item DEGREES(X)
+Gibt das Argument @code{X} zurück, von Radianten zu Grad umgewandelt:
+@example
+mysql> select DEGREES(PI());
+ -> 180.000000
+@end example
+
+@findex RADIANS()
+@item RADIANS(X)
+Gibt das Argument @code{X} zurück, von Grad zu Radianten umgewandelt:
+@example
+mysql> select RADIANS(90);
+ -> 1.570796
+@end example
+
+@findex TRUNCATE()
+@item TRUNCATE(X,D)
+Gibt die Zahl @code{X} zurück, auf @code{D} Dezimalstellen beschnitten.
+Wenn @code{D} @code{0} ist, hat das Ergebnis keinen Dezimalpunkt oder
+Bruchteil:
+@example
+mysql> select TRUNCATE(1.223,1);
+ -> 1.2
+mysql> select TRUNCATE(1.999,1);
+ -> 1.9
+mysql> select TRUNCATE(1.999,0);
+ -> 1
+@end example
+
+Beachten Sie, dass Dezimalzahlen in Computern normalerweise nicht als
+exakte Zahlen, sondern als Double-Werte gespeichert werden. Daher können
+verwirrende Ergebnisse wie im folgenden Beispiel auftreten:
+
+@cindex Rundungsfehler
+@example
+mysql> select TRUNCATE(10.28*100,0);
+ -> 1027
+@end example
+
+Das Obige passiert, weil 10.28 tatsächlich als etwas wie
+10.2799999999999999 gespeichert wird.
+@end table
+
+
+@node Date and time functions, Other Functions, Numeric Functions, Functions
+@c German node Datums- und Zeit-Funktionen
+@subsection Datums- und Zeit-Funktionen
+
+@findex Datums- und Zeit-Funktionen
+@findex Funktionen, Datums- und Zeit-
+
+Eine Beschreibung des Wertebereichs aller Typen und der gültigen Formate
+für Datums- und Zeitwerte finden Sie unter @ref{Date and time types}.
+
+Hier ist ein Beispiel, das Datums-Funktionen benutzt. Die unten stehende
+Anfrage wählt alle Datensätze mit einem @code{datum_spalte}-Wert innerhalb
+der letzten 30 Tage aus:
+
+@example
+mysql> SELECT etwas FROM tabelle
+ WHERE TO_DAYS(NOW()) - TO_DAYS(datum_spalte) <= 30;
+@end example
+
+@table @code
+@findex DAYOFWEEK()
+@item DAYOFWEEK(datum)
+Gibt den Wochentag-Index zurück.
+
+Für @code{datum} gilt: @code{1} = Sonntag, @code{2} = Montag, ... @code{7}
+= Samstag). Diese Index-Werte entsprechen dem ODBC-Standard:
+
+@example
+mysql> select DAYOFWEEK('1998-02-03');
+ -> 3
+@end example
+
+@findex WEEKDAY()
+@item WEEKDAY(datum)
+Gibt den Wochentag-Index für @code{datum} zurück (@code{0} = Montag,
+@code{1} = Dienstag, ... @code{6} = Sonntag):
+
+@example
+mysql> select WEEKDAY('1997-10-04 22:23:00');
+ -> 5
+mysql> select WEEKDAY('1997-11-05');
+ -> 2
+@end example
+
+@findex DAYOFMONTH()
+@item DAYOFMONTH(datum)
+Gibt den Tag des Monats für @code{datum} im Bereich @code{1} bis @code{31}
+zurück:
+
+@example
+mysql> select DAYOFMONTH('1998-02-03');
+ -> 3
+@end example
+
+@findex DAYOFYEAR()
+@item DAYOFYEAR(datum)
+Gibt den Tag des Jahres für @code{datum} im Bereich @code{1} bis @code{366}
+zurück:
+
+@example
+mysql> select DAYOFYEAR('1998-02-03');
+ -> 34
+@end example
+
+@findex MONTH()
+@item MONTH(datum)
+Gibt den Monat für @code{datum} im Bereich @code{1} bis @code{12} zurück:
+
+@example
+mysql> select MONTH('1998-02-03');
+ -> 2
+@end example
+
+@findex DAYNAME()
+@item DAYNAME(datum)
+Gibt den Namen des Wochentags für @code{datum} zurück (auf englisch):
+
+@example
+mysql> select DAYNAME("1998-02-05");
+ -> 'Thursday'
+@end example
+
+@findex MONTHNAME()
+@item MONTHNAME(datum)
+Gibt den Namen des Monats für @code{datum} zurück (auf englisch):
+
+@example
+mysql> select MONTHNAME("1998-02-05");
+ -> 'February'
+@end example
+
+@findex QUARTER()
+@item QUARTER(datum)
+Gibt das Quartal des Jahres für @code{datum} im Bereich @code{1} bis
+@code{4} zurück:
+
+@example
+mysql> select QUARTER('98-04-01');
+ -> 2
+@end example
+
+@findex WEEK()
+@item WEEK(datum)
+@itemx WEEK(datum,erste)
+Mit einem einzelnen Argument gibt diese Funktion die Woche für @code{datum}
+im Bereich @code{0} bis @code{53} zurück (ja, es kann Anfänge der Woche 53
+geben), für Orte, in denen Sonntag der erste Wochentag ist. In der Form mit
+zwei Argumenten gestattet @code{WEEK()} es, festzulegen, ob die Woche am
+Sonntag oder am Montag beginnt. Die Woche beginnt am Sonntag, wenn das
+zweite Argument @code{0} ist, und am Montag, wenn das zweite Argument
+@code{1} ist:
+
+@example
+mysql> select WEEK('1998-02-20');
+ -> 7
+mysql> select WEEK('1998-02-20',0);
+ -> 7
+mysql> select WEEK('1998-02-20',1);
+ -> 8
+mysql> select WEEK('1998-12-31',1);
+ -> 53
+@end example
+
+@findex YEAR()
+@item YEAR(datum)
+Gibt das Jahr für @code{datum} im Bereich @code{1000} bis @code{9999}
+zurück:
+
+@example
+mysql> select YEAR('98-02-03');
+ -> 1998
+@end example
+
+@item YEARWEEK(datum)
+@itemx YEARWEEK(datum,erste)
+Gibt Jahr und Woche für ein Datum zurück. Das zweite Argument funktioniert
+genau wie das zweite Argument von @code{WEEK()}. Beachten Sie, dass das
+Jahr sich in der ersten und letzten Woche des Jahres vom Jahr im
+Datums-Argument unterscheiden kann:
+
+@example
+mysql> select YEARWEEK('1987-01-01');
+ -> 198653
+@end example
+
+@findex HOUR()
+@item HOUR(zeit)
+Gibt die Stunde für @code{zeit} im Bereich @code{0} bis @code{23} zurück:
+
+@example
+mysql> select HOUR('10:05:03');
+ -> 10
+@end example
+
+@findex MINUTE()
+@item MINUTE(zeit)
+Gibt die Minute für @code{zeit} im Bereich @code{0} bis @code{59} zurück:
+
+@example
+mysql> select MINUTE('98-02-03 10:05:03');
+ -> 5
+@end example
+
+@findex SECOND()
+@item SECOND(zeit)
+Gibt die Sekunde für @code{zeit} im Bereich @code{0} bis @code{59} zurück:
+
+@example
+mysql> select SECOND('10:05:03');
+ -> 3
+@end example
+
+@findex PERIOD_ADD()
+@item PERIOD_ADD(P,N)
+Zählt @code{N} Monate zur Periode @code{P} hinzu (im Format @code{YYMM}
+oder @code{YYYYMM}). Gibt einen Wert im Format @code{YYYYMM} zurück.
+
+Beachten Sie, dass das Perioden-Argument @code{P} @emph{kein} Datums-Wert
+ist:
+
+@example
+mysql> select PERIOD_ADD(9801,2);
+ -> 199803
+@end example
+
+@findex PERIOD_DIFF()
+@item PERIOD_DIFF(P1,P2)
+Gibt die Anzahl von Monaten zwischen den Perioden @code{P1} und @code{P2}
+zurück. @code{P1} und @code{P2} sollten im Format @code{YYMM} oder
+@code{YYYYMM} sein.
+
+Beachten Sie, dass die Perioden-Argumente @code{P1} und @code{P2}
+@emph{keine} Datumswerte sind:
+
+@example
+mysql> select PERIOD_DIFF(9802,199703);
+ -> 11
+@end example
+
+@findex DATE_ADD()
+@findex DATE_SUB()
+@findex ADDDATE()
+@findex SUBDATE()
+@findex EXTRACT()
+@item DATE_ADD(datum,INTERVAL ausdruck typ)
+@itemx DATE_SUB(datum,INTERVAL ausdruck typ)
+@itemx ADDDATE(datum,INTERVAL ausdruck typ)
+@itemx SUBDATE(datum,INTERVAL ausdruck typ)
+
+Diese Funktionen führen Datumsberechnungen durch. Sie wurden in
+MySQL-Version 3.22 eingeführt. @code{ADDDATE()} und @code{SUBDATE()} sind
+Synonyme für @code{DATE_ADD()} und @code{DATE_SUB()}.
+
+In MySQL-Version 3.23 können Sie @code{+} und @code{-} anstelle von
+@code{DATE_ADD()} und @code{DATE_SUB()} benutzen, wenn der Ausdruck auf der
+rechten Seite eine DATE oder DATETIME-Spalte ist (siehe Beispiel).
+
+@code{datum} ist ein @code{DATETIME}- oder @code{DATE}-Wert, der das
+Anfangsdatum festlegt. @code{ausdruck} ist ein Ausdruck, der den
+Intervallwert festlegt, der zum Anfangsdatum hinzugezählt oder von diesem
+abgezogen wird. @code{ausdruck} ist eine Zeichenkette; sie kann mit einem
+@samp{-} für negative Intervalle beginnen. @code{typ} ist ein
+Schlüsselwort, das angibt, wie der Ausdruck interpretiert werden soll.
+
+Die verwandte Funktion @code{EXTRACT(typ FROM datum)} gibt das
+'typ'-Intervall des Datums zurück.
+
+Folgende Tabelle zeigt, in welchem Zusammenhang die @code{typ}- und
+@code{ausdruck}-Argumente stehen:
+
+@multitable @columnfractions .5 .5
+@item @code{typ} @strong{wert} @tab @strong{erwartet} @code{ausdruck} @strong{format}
+@item @code{SECOND} @tab @code{Sekunden}
+@item @code{MINUTE} @tab @code{Minuten}
+@item @code{HOUR} @tab @code{Stunden}
+@item @code{DAY} @tab @code{Tage}
+@item @code{MONTH} @tab @code{Monate}
+@item @code{YEAR} @tab @code{Jahre}
+@item @code{MINUTE_SECOND} @tab @code{"Minuten:Sekunden"}
+@item @code{HOUR_MINUTE} @tab @code{"Stunden:Minuten"}
+@item @code{DAY_HOUR} @tab @code{"Tage Stunden"}
+@item @code{YEAR_MONTH} @tab @code{"Jahre-Monate"}
+@item @code{HOUR_SECOND} @tab @code{"Stunden:Minuten:Sekunden"}
+@item @code{DAY_MINUTE} @tab @code{"Tage Stunden:Minuten"}
+@item @code{DAY_SECOND} @tab @code{"Tage Stunden:Minuten:Sekunden"}
+@end multitable
+
+MySQL erlaubt beliebige Satzzeichen-Begrenzer im @code{ausdruck}-Format.
+Die in der Tabelle gezeigten Begrenzer sind Vorschläge. Wenn das
+@code{datum}-Argument ein @code{DATE}-Wert ist und Ihre Berechnungen nur
+@code{YEAR}, @code{MONTH} und @code{DAY}-Anteile beinhalten (also keine
+Zeit-Anteile), ist das Ergebnis ein @code{DATE}-Wert. Ansonsten ist das
+Ergebnis ein @code{DATETIME}-Wert:
+
+@example
+mysql> SELECT "1997-12-31 23:59:59" + INTERVAL 1 SECOND;
+ -> 1998-01-01 00:00:00
+mysql> SELECT INTERVAL 1 DAY + "1997-12-31";
+ -> 1998-01-01
+mysql> SELECT "1998-01-01" - INTERVAL 1 SECOND;
+ -> 1997-12-31 23:59:59
+mysql> SELECT DATE_ADD("1997-12-31 23:59:59",
+ INTERVAL 1 SECOND);
+ -> 1998-01-01 00:00:00
+mysql> SELECT DATE_ADD("1997-12-31 23:59:59",
+ INTERVAL 1 DAY);
+ -> 1998-01-01 23:59:59
+mysql> SELECT DATE_ADD("1997-12-31 23:59:59",
+ INTERVAL "1:1" MINUTE_SECOND);
+ -> 1998-01-01 00:01:00
+mysql> SELECT DATE_SUB("1998-01-01 00:00:00",
+ INTERVAL "1 1:1:1" DAY_SECOND);
+ -> 1997-12-30 22:58:59
+mysql> SELECT DATE_ADD("1998-01-01 00:00:00",
+ INTERVAL "-1 10" DAY_HOUR);
+ -> 1997-12-30 14:00:00
+mysql> SELECT DATE_SUB("1998-01-02", INTERVAL 31 DAY);
+ -> 1997-12-02
+@end example
+
+Wenn Sie einen Intervallwert angeben, der zu kurz ist (nicht alle
+Intervall-Anteile beinhaltet, die vom @code{typ}-Schlüsselwort erwartet
+werden), nimmt MySQL an, dass Sie den äußersten linken Teil des
+Intervallwerts ausgelassen haben. Wenn Sie beispielsweise einen @code{typ}
+@code{DAY_SECOND} angeben, wird vom Wert von @code{ausdruck} erwartet, dass
+dieser Tages-, Stunden-, Minuten- und Sekunden-Anteile enthält. Wenn Sie
+einen Wert wie @code{"1:10"} angeben, nimmt MySQL an, dass die Tages- und
+Stunden-Anteile fehlen und der Wert Minuten und Sekunden darstellt. Mit
+anderen Worten wird @code{"1:10" DAY_SECOND} so interpretiert, dass es
+äquivalent zu @code{"1:10" MINUTE_SECOND} ist. Das ist analog zur Weise,
+wie MySQL @code{TIME}-Werte interpretiert, die eher vergangene Zeit als
+Tageszeit darstellen.
+
+Beachten Sie, dass ein Datumswert automatisch in einen DATETIME-Wert
+umgewandelt wird, wenn Sie einen DATE-Wert zu etwas hinzuzählen oder von
+etwas abziehen, das einen Zeit-Anteil hat:
+
+@example
+mysql> select date_add("1999-01-01", interval 1 day);
+ -> 1999-01-02
+mysql> select date_add("1999-01-01", interval 1 hour);
+ -> 1999-01-01 01:00:00
+@end example
+
+Wenn Sie wirklich falsche Datumsangaben benutzen, ist das Ergebnis
+@code{NULL}. Wenn Sie @code{MONTH}, @code{YEAR_MONTH} oder @code{YEAR}
+hinzuzählen und das Datumsergebnis einen Tag hat, der größer ist als der
+höchste Tag für den neuen Monat, wird der Tag auf den höchsten Tag des
+neuen Monats angepasst:
+
+@example
+mysql> select DATE_ADD('1998-01-30', Interval 1 month);
+ -> 1998-02-28
+@end example
+
+Beachten Sie, dass das Wort @code{INTERVAL} und das
+@code{typ}-Schlüsselwort in den vorstehenden Beispielen nicht von der
+verwendeten Groß-/Kleinschreibung abhängen.
+
+@findex EXTRACT()
+@item EXTRACT(typ FROM datum)
+
+Die @code{EXTRACT()}-Funktion benutzt dieselbe Art von
+Intervalltyp-Spezifikatoren wie @code{DATE_ADD()} oder @code{DATE_SUB()},
+extrahiert aber Anteile aus dem Datum, statt Datumsberechnungen
+durchzuführen:
+
+@example
+mysql> SELECT EXTRACT(YEAR FROM "1999-07-02");
+ -> 1999
+mysql> SELECT EXTRACT(YEAR_MONTH FROM "1999-07-02 01:02:03");
+ -> 199907
+mysql> SELECT EXTRACT(DAY_MINUTE FROM "1999-07-02 01:02:03");
+ -> 20102
+@end example
+
+@findex TO_DAYS()
+@item TO_DAYS(datum)
+Gibt für ein Datum @code{datum} eine Tagesanzahl zurück (die Anzahl von
+Tagen seit dem Jahr 0):
+
+@example
+mysql> select TO_DAYS(950501);
+ -> 728779
+mysql> select TO_DAYS('1997-10-07');
+ -> 729669
+@end example
+
+@code{TO_DAYS()} ist nicht für die Benutzung mit Werten vor der Einführung
+des Gregorianischen Kalenders (1582) vorgesehen, weil es nicht die Tage
+berücksichtigt, die verloren gingen, als der Kalender geändert wurde.
+
+@findex FROM_DAYS()
+@item FROM_DAYS(N)
+Gibt für eine Tagesanzahl @code{N} einen @code{DATE}-Wert zurück:
+
+@example
+mysql> select FROM_DAYS(729669);
+ -> '1997-10-07'
+@end example
+
+@code{FROM_DAYS()} ist nicht für die Benutzung mit Werten vor der Einführung
+des Gregorianischen Kalenders (1582) vorgesehen, weil es nicht die Tage
+berücksichtigt, die verloren gingen, als der Kalender geändert wurde.
+
+@findex DATE_FORMAT()
+@item DATE_FORMAT(datum,format)
+Formatiert den @code{datum}-Wert gemäß der @code{format}-Zeichenkette.
+Folgende Spezifikatoren können in der @code{format}-Zeichenkette benutzt
+werden:
+@multitable @columnfractions .1 .6
+@item @code{%M} @tab Monatsname auf englisch (@code{January} bis @code{December})
+@item @code{%W} @tab Name des Wochentags auf englisch (@code{Sunday} bis @code{Saturday})
+@item @code{%D} @tab Tag des Monats mit englischem Suffix (@code{1st}, @code{2nd}, @code{3rd} usw.)
+@item @code{%Y} @tab Jahr, numerisch, 4 Ziffern
+@item @code{%y} @tab Jahr, numerisch, 2 Ziffern
+@item @code{%X} @tab Jahr der Woche, wobei Sonntag der erste Tag der Woche ist, numerisch, 4 Ziffern, benutzt mit '%V'
+@item @code{%x} @tab Jahr der Woche, wobei Montag der erste Tag der Woche ist, numerisch, 4 Ziffern, benutzt mit '%v'
+@item @code{%a} @tab Abgekürzter Name des Wochentags auf englisch (@code{Sun}..@code{Sat})
+@item @code{%d} @tab Tag des Monats, numerisch (@code{00} bis @code{31})
+@item @code{%e} @tab Tag des Monats, numerisch (@code{0} bis @code{31})
+@item @code{%m} @tab Monat, numerisch (@code{01} bis @code{12})
+@item @code{%c} @tab Monat, numerisch (@code{1} bis @code{12})
+@item @code{%b} @tab Abgekürzter Monatsname auf englisch (@code{Jan} bis @code{Dec})
+@item @code{%j} @tab Tag des Jahrs (@code{001} bis @code{366})
+@item @code{%H} @tab Stunde (@code{00} bis @code{23})
+@item @code{%k} @tab Stunde (@code{0} bis @code{23})
+@item @code{%h} @tab Stunde (@code{01} bis @code{12})
+@item @code{%I} @tab Stunde (@code{01} bis @code{12})
+@item @code{%l} @tab Stunde (@code{1} bis @code{12})
+@item @code{%i} @tab Minuten, numerisch (@code{00} bis @code{59})
+@item @code{%r} @tab Uhrzeit, 12-Stunden-Format (@code{hh:mm:ss [AP]M})
+@item @code{%T} @tab Uhrzeit, 24-Stunden-Format (@code{hh:mm:ss})
+@item @code{%S} @tab Sekunden (@code{00} bis @code{59})
+@item @code{%s} @tab Sekunden (@code{00} bis @code{59})
+@item @code{%p} @tab @code{AM} oder @code{PM}
+@item @code{%w} @tab Wochentag (@code{0}=Sonntag bis @code{6}=Samstag)
+@item @code{%U} @tab Woche (@code{0} bis @code{53}), wobei Sonntag der erste Tag der Woche ist
+@item @code{%u} @tab Woche (@code{0} bis @code{53}), wobei Montag der erste Tag der Woche ist
+@item @code{%V} @tab Woche (@code{1} bis @code{53}), wobei Sonntag der erste Tag der Woche ist. Benutzt mit '%X'
+@item @code{%v} @tab Woche (@code{1} bis @code{53}), wobei Montag der erste Tag der Woche ist. Benutzt mit '%x'
+@item @code{%%} @tab Ein Literal @samp{%}.
+@end multitable
+
+Alle anderen Zeichen werden einfach ohne Interpretation ins Ergebnis
+kopiert:
+
+@example
+mysql> select DATE_FORMAT('1997-10-04 22:23:00', '%W%M%Y');
+ -> 'Saturday October 1997'
+mysql> select DATE_FORMAT('1997-10-04 22:23:00', '%H:%i:%s');
+ -> '22:23:00'
+mysql> select DATE_FORMAT('1997-10-04 22:23:00',
+ '%D%y%a%d%m%b%j');
+ -> '4th 97 Sat 04 10 Oct 277'
+mysql> select DATE_FORMAT('1997-10-04 22:23:00',
+ '%H%k%I%r%T%S%w');
+ -> '22 22 10 10:23:00 PM 22:23:00 00 6'
+mysql> select DATE_FORMAT('1999-01-01', '%X%V');
+ -> '1998 52'
+@end example
+
+Ab MySQL-Version 3.23 ist das @samp{%}-Zeichen vor
+Format-Spezifikator-Zeichen erforderlich. In früheren Versionen von MySQL
+war @samp{%} optional.
+
+@findex TIME_FORMAT()
+@item TIME_FORMAT(zeit,format)
+Dieses wird benutzt wie die obige @code{DATE_FORMAT()}-Funktion, aber die
+@code{format}-Zeichenkette darf nur die Spezifikatoren enthalten, die
+Stunden, Minuten und Sekunden handhaben. Andere Spezifikatoren erzeugen
+einen @code{NULL}-Wert oder @code{0}.
+
+@findex CURDATE()
+@findex CURRENT_DATE
+@item CURDATE()
+@itemx CURRENT_DATE
+Gibt das Datum von heute im @code{'YYYY-MM-DD'}- oder
+@code{YYYYMMDD}-format zurück, abhängig davon, ob die Funktion in einem
+Zeichenketten- oder in einem numerischen Zusammenhang benutzt wird:
+
+@example
+mysql> select CURDATE();
+ -> '1997-12-15'
+mysql> select CURDATE() + 0;
+ -> 19971215
+@end example
+
+@findex CURTIME()
+@findex CURRENT_TIME
+@item CURTIME()
+@itemx CURRENT_TIME
+Gibt die aktuelle Zeit als einen Wert im @code{'HH:MM:SS'}- oder
+@code{HHMMSS}-format zurück, abhängig davon, ob die Funktion in einem
+Zeichenketten- oder in einem numerischen Zusammenhang benutzt wird:
+
+@example
+mysql> select CURTIME();
+ -> '23:50:26'
+mysql> select CURTIME() + 0;
+ -> 235026
+@end example
+
+@findex NOW()
+@findex SYSDATE()
+@findex CURRENT_TIMESTAMP
+@item NOW()
+@itemx SYSDATE()
+@itemx CURRENT_TIMESTAMP
+Gibt das aktuelle Datum und die aktuelle Zeit als einen Wert im
+@code{'YYYY-MM-DD HH:MM:SS'}- oder @code{YYYYMMDDHHMMSS}-Format zurück,
+abhängig davon, ob die Funktion in einem Zeichenketten- oder in einem
+numerischen Zusammenhang benutzt wird:
+
+@example
+mysql> select NOW();
+ -> '1997-12-15 23:50:26'
+mysql> select NOW() + 0;
+ -> 19971215235026
+@end example
+
+@findex UNIX_TIMESTAMP()
+@item UNIX_TIMESTAMP()
+@itemx UNIX_TIMESTAMP(datum)
+Ohne Argument aufgerufen gibt die Funktion einen Unix-Zeitstempel zurück
+(Sekunden seit @code{'1970-01-01 00:00:00'} GMT). Wenn
+@code{UNIX_TIMESTAMP()} mit einem @code{datum}-Argument aufgerufen wird,
+gibt sie den Wert des Arguments als Sekunden seit @code{'1970-01-01
+00:00:00'} GMT zurück. @code{datum} kann eine @code{DATE}-Zeichenkette,
+eine @code{DATETIME}-Zeichenkette, ein @code{TIMESTAMP} oder eine Zahl im
+Format @code{YYMMDD} oder @code{YYYYMMDD} in lokaler Zeit sein:
+
+@example
+mysql> select UNIX_TIMESTAMP();
+ -> 882226357
+mysql> select UNIX_TIMESTAMP('1997-10-04 22:23:00');
+ -> 875996580
+@end example
+
+Wenn @code{UNIX_TIMESTAMP} auf einer @code{TIMESTAMP}-Spalte benutzt wird,
+erhält die Funktion den Wert direkt, ohne implizite
+``zeichenkette-zu-unix-zeitstempel''-Umwandlung. Wenn Sie
+@code{UNIX_TIMESTAMP()} einen falschen Wert oder einen Wert ausserhalb des
+Wertebereichs angeben, gibt sie 0 zurück.
+
+@findex FROM_UNIXTIME()
+@item FROM_UNIXTIME(unix_zeitstempel)
+Gibt das @code{unix_timestamp}-Argument als Wert im @code{'YYYY-MM-DD
+HH:MM:SS'}- oder @code{YYYYMMDDHHMMSS}-Format zurück, abhängig davon, ob
+die Funktion in einem Zeichenketten- oder in einem numerischen Zusammenhang
+benutzt wird:
+
+@example
+mysql> select FROM_UNIXTIME(875996580);
+ -> '1997-10-04 22:23:00'
+mysql> select FROM_UNIXTIME(875996580) + 0;
+ -> 19971004222300
+@end example
+
+@findex FROM_UNIXTIME()
+@item FROM_UNIXTIME(unix_zeitstempel,format)
+Gibt das @code{unix_timestamp}-Argument als Wert zurück, der wie mit der
+@code{format}-Zeichenkette angegeben formatiert ist. @code{format} kann
+dieselben Spezifikatoren wie die @code{DATE_FORMAT()}-Funktion enthalten:
+
+@example
+mysql> select FROM_UNIXTIME(UNIX_TIMESTAMP(),
+ '%Y%D%M%h:%i:%s%x');
+ -> '1997 23rd December 03:43:30 x'
+@end example
+
+@findex SEC_TO_TIME()
+@item SEC_TO_TIME(sekunden)
+Gibt das @code{sekunden}-Argument, umgewandelt in Stunden, Minuten und
+Sekunden, als Wert im @code{'HH:MM:SS'}- oder @code{HHMMSS}-Format zurück,
+abhängig davon, ob die Funktion in einem Zeichenketten- oder in einem
+numerischen Zusammenhang benutzt wird:
+
+@example
+mysql> select SEC_TO_TIME(2378);
+ -> '00:39:38'
+mysql> select SEC_TO_TIME(2378) + 0;
+ -> 3938
+@end example
+
+@findex TIME_TO_SEC()
+@item TIME_TO_SEC(zeit)
+Gibt das @code{zeit}-Argument, umgewandelt in Sekunden, zurück:
+
+@example
+mysql> select TIME_TO_SEC('22:23:00');
+ -> 80580
+mysql> select TIME_TO_SEC('00:39:38');
+ -> 2378
+@end example
+@end table
+
+
+@node Other Functions, Group by functions, Date and time functions, Functions
+@c German node Weitere Funktionen
+@subsection Weitere Funktionen
+
+
+
+@menu
+* Bit functions::
+* Miscellaneous functions::
+@end menu
+
+@node Bit functions, Miscellaneous functions, Other Functions, Other Functions
+@c German node Bit-Funktionen
+@subsubsection Bit-Funktionen
+
+@findex arithmetische Funktionen
+@findex Bit-Funktionen
+@findex Funktionen, arithmetische
+@findex Funktionen, Bit-
+
+MySQL benutzt @code{BIGINT}-Berechnungen (64-Bit) für Bit-Operationen, so
+dass diese Operatoren einen maximalen Wertebereich von 64 Bits haben.
+
+@table @code
+@findex | (bitweises OR)
+@findex OR, bitweises
+@item |
+Bitweises OR:
+@example
+mysql> select 29 | 15;
+ -> 31
+@end example
+
+@findex & (bitweises AND)
+@findex AND, bitweises
+@item &
+Bitweises AND:
+@example
+mysql> select 29 & 15;
+ -> 13
+@end example
+
+@findex << (left shift)
+@item <<
+Verschiebt eine @code{BIGINT}-Zahl nach links:
+@example
+mysql> select 1 << 2;
+ -> 4
+@end example
+
+@findex >> (right shift)
+@item >>
+Verschiebt eine @code{BIGINT}-Zahl nach rechts:
+@example
+mysql> select 4 >> 2;
+ -> 1
+@end example
+
+@findex ~
+@item ~
+Invertiert alle Bits:
+@example
+mysql> select 5 & ~1;
+ -> 4
+@end example
+
+@findex BIT_COUNT()
+@item BIT_COUNT(N)
+Gibt die Anzahl von Bits, die im Argument @code{N} gesetzt sind, zurück:
+@example
+mysql> select BIT_COUNT(29);
+ -> 4
+@end example
+@end table
+
+
+@node Miscellaneous functions, , Bit functions, Other Functions
+@c German node Verschiedene Funktionen
+@subsubsection Verschiedene Funktionen
+
+@findex Verschiedene Funktionen
+@findex Funktionen, verschiedene
+
+@table @code
+@findex DATABASE()
+@item DATABASE()
+Gibt den aktuellen Datenbanknamen zurück:
+
+@example
+mysql> select DATABASE();
+ -> 'test'
+@end example
+
+Wenn es keine aktuelle Datenbank gibt, gibt @code{DATABASE()} die leere
+Zeichenkette zurück.
+
+@findex USER()
+@findex SYSTEM_USER()
+@findex SESSION_USER()
+@item USER()
+@itemx SYSTEM_USER()
+@itemx SESSION_USER()
+Gibt den aktuellen MySQL-Benutzernamen zurück:
+
+@example
+mysql> select USER();
+ -> 'heinzholger@@localhost'
+@end example
+
+Ab MySQL-Version 3.22.11 beinhaltet dieser Wert den Client-Hostnamen sowie
+den Benutzernamen. Sie können nur den Benutzernamen-Anteil wie folgt
+extrahieren (was funktioniert, ob der Wert nun einen Hostnamen-Anteil hat
+oder nicht):
+
+@example
+mysql> select substring_index(USER(),"@@",1);
+ -> 'heinzholger'
+@end example
+
+@findex PASSWORD()
+@item PASSWORD(zeichenkette)
+
+Berechnet eine Passwort-Zeichenkette aus dem Klartext-Passwort
+@code{zeichenkette}. Diese Funktion wird benutzt, um MySQL-Passwörter zum
+Speichern in der @code{Password}-Spalte der
+@code{user}-Berechtigungstabelle zu verschlüsseln:
+
+@example
+mysql> select PASSWORD('schlechtespasswort');
+ -> '1ccbb34b4e2b2f95'
+@end example
+
+@cindex Passwort-Verschlüsselung, Umkehrbarkeit
+Die @code{PASSWORD()}-Verschlüsselung ist nicht umkehrbar.
+
+@code{PASSWORD()} führt keine Passwort-Verschlüsselung in der Art durch,
+wie Unix-Passwörter verschlüsselt werden. Sie sollten nicht annehmen, dass
+Ihr Unix-Passwort und Ihr MySQL-Passwort dasselbe sind. @code{PASSWORD()}
+ergibt denselben verschlüsselten Wert, wie er in der Unix-Passwortdatei
+gespeichert ist. Siehe @code{ENCRYPT()}.
+
+@findex ENCRYPT()
+@item ENCRYPT(zeichenkette[,salt])
+Verschlüsselt @code{zeichenkette} unter Benutzung des
+Unix-@code{crypt()}-Systemaufrufs. Das @code{salt}-Argument sollte eine
+Zeichenkette mit zwei Zeichen sein (ab MySQL-Version 3.22.16 darf
+@code{salt} länger als zwei Zeichen sein):
+
+@example
+mysql> select ENCRYPT("hello");
+ -> 'VxuFAJXVARROc'
+@end example
+
+Wenn @code{crypt()} auf Ihrem System nicht verfügbar ist, gibt
+@code{ENCRYPT()} immer @code{NULL} zurück.
+
+@code{ENCRYPT()} ignoriert alle ausser den ersten 8 Zeichen von
+@code{zeichenkette}, zumindest auf einigen Systemen. Das wird durch den
+zugrunde liegenden @code{crypt()}-Systemaufruf festgelegt.
+
+@findex ENCODE()
+@item ENCODE(zeichenkette,passwort_zeichenkette)
+Verschlüsselt @code{zeichenkette}, indem @code{passwort_zeichenkette} als
+Passwort benutzt wird. Um das Ergebnis zu entschlüsseln, benutzen Sie
+@code{DECODE()}.
+
+Das Ergebnis ist eine binäre Zeichenkette derselben Länge wie
+@code{zeichenkette}. Wenn Sie sie in einer Spalte speichern wollen,
+benutzen Sie eine @code{BLOB}-Spalte.
+
+@findex DECODE()
+@item DECODE(crypt_zeichenkette,passwort_zeichenkette)
+Entschlüsselt die verschlüsselte Zeichenkette @code{crypt_zeichenkette},
+indem @code{passwort_zeichenkette} als Passwort benutzt wird.
+@code{crypt_zeichenkette} sollte eine Zeichenkette sein, die von
+@code{ENCODE()} zurückgegeben wird.
+
+@findex MD5()
+@item MD5(zeichenkette)
+Berechnet eine MD5-Prüfsumme für die Zeichenkette. Der Wert wird als eine
+32 Stellen lange hexadezimale Zahl zurückgegeben, die zum Beispiel als
+Hash-Schlüssel benutzt werden kann:
+
+@example
+mysql> select MD5("testing");
+ -> 'ae2b1fca515949e5d54fb22b8ed95575'
+@end example
+
+Das ist ein "RSA Data Sicherheit, Inc. MD5 Message-Digest Algorithm".
+
+@findex LAST_INSERT_ID([ausdruck])
+@item LAST_INSERT_ID([ausdruck])
+Gibt den letzten automatisch erzeugten Wert zurück, der in eine
+@code{AUTO_INCREMENT}-Spalte eingefügt wurde. @xref{mysql_insert_id,,
+@code{mysql_insert_id()}}.
+
+@example
+mysql> select LAST_INSERT_ID();
+ -> 195
+@end example
+
+Die letzte ID, die erzeugt wurde, wird im Server für jede Verbindung
+separat gespeichert. Sie wird nicht durch andere Clients geändert. Sie wird
+nicht einmal geändert, wenn Sie eine andere @code{AUTO_INCREMENT}-Spalte
+mit einem nicht 'magischen' Wert aktualisieren (also einem Wert, der nicht
+@code{NULL} und nicht @code{0} ist).
+
+Wenn Sie viele Zeilen zugleich mit einem Insert-Statement einfügen, gibt
+@code{LAST_INSERT_ID()} den Wert für die erste eingefügte Zeile zurück. Der
+Grund dafür liegt darin, dass es Ihnen dadurch ermöglicht wird, dasselbe
+@code{INSERT}-Statement auf einfache Weise auf einem anderen Server zu
+reproduzieren.
+
+@cindex Zahlenfolgen-Emulation
+Wenn @code{ausdruck} als Argument zu @code{LAST_INSERT_ID()} angegeben
+wird, wird der Wert des Arguments von der Funktion zurückgegeben, als
+nächster Wert gesetzt, der von @code{LAST_INSERT_ID()} zurückgegeben wird
+und als nächster auto_increment-Wert benutzt. Damit können Sie Zahlenfolgen
+emulieren:
+
+Erzeugen Sie zuerst die Tabelle:
+
+@example
+mysql> create table sequenz (id int not null);
+mysql> insert into sequenz values (0);
+@end example
+
+Danach kann die Tabelle benutzt werden, um wie folgt Zahlenfolgen zu
+erzeugen:
+
+@example
+mysql> update sequenz set id=LAST_INSERT_ID(id+1);
+@end example
+
+Sie können Zahlenfolgen erzeugen, ohne @code{LAST_INSERT_ID()} aufzurufen,
+aber der Nutzen, die Funktion auf diese Art zu benutzen, liegt darin, dass
+der ID-Wert im Server als letzter automatisch erzeugter Wert gehalten wird.
+Sie können die neue ID auf dieselbe Art abrufen, wie Sie jeden anderen
+normalen @code{AUTO_INCREMENT}-Wert in MySQL lesen würden.
+@code{LAST_INSERT_ID()} (ohne Argument) zum Beispiel gibt die neue ID
+zurück. Die C-API-Funktion @code{mysql_insert_id()} kann ebenfalls benutzt
+werden, um den Wert zu erhalten.
+
+Beachten Sie, dass Sie diese Funktion nicht benutzen können, um den Wert
+von @code{LAST_INSERT_ID(ausdruck)} abzurufen, nachdem Sie andere
+SQL-Statements wie @code{SELECT} oder @code{SET} ausgeführt haben, weil
+@code{mysql_insert_id()} nur nach @code{INSERT}- und
+@code{UPDATE}-Statements aktualisiert wird.
+
+
+@findex FORMAT()
+@item FORMAT(X,D)
+Formatiert die Zahl @code{X} in ein Format wie @code{'#,###,###.##'},
+gerundet auf @code{D} Dezimalstellen. Wenn @code{D} @code{0} ist, hat das
+Ergebnis keinen Dezimalpunkt oder Bruchteil:
+
+@example
+mysql> select FORMAT(12332.123456, 4);
+ -> '12,332.1235'
+mysql> select FORMAT(12332.1,4);
+ -> '12,332.1000'
+mysql> select FORMAT(12332.2,0);
+ -> '12,332'
+@end example
+
+@findex VERSION()
+@item VERSION()
+Gibt eine Zeichenkette zurück, die die MySQL-Serverversion anzeigt:
+
+@example
+mysql> select VERSION();
+ -> '3.23.13-log'
+@end example
+
+Wenn Ihre Versionsnummer mit @code{-log} endet, bedeutet das, dass Loggen
+angeschaltet ist.
+
+@findex CONNECTION_ID()
+@item CONNECTION_ID()
+Gibt die Verbindungskennnummer (@code{Thread_id}) für die Verbindung
+zurück. Jede Verbindung hat ihre eigene eindeutige Kennnummer:
+
+@example
+mysql> select CONNECTION_ID();
+ -> 1
+@end example
+
+@cindex Zeitüberschreitung (Timeout)
+@findex GET_LOCK()
+@item GET_LOCK(zeichenkette,zeitueberschreitung)
+Versucht, eine Sperre mit dem Namen, der durch die Zeichenkette
+@code{zeichenkette} angegeben wird, zu erlangen, mit einem Timeout von
+@code{zeitueberschreitung} Sekunden. Gibt @code{1} zurück, wenn die Sperre
+erfolgreich erlangt wurde, und @code{0}, wenn der Versuch wegen
+Zeitüberschreitung abgebrochen wurde, oder @code{NULL}, wenn ein Fehler
+auftrat (wenn zum Beispiel kein Arbeitsspeicher mehr frei ist oder der
+Thread mit @code{mysqladmin kill} gekillt wurde). Eine Sperre wird
+aufgehoben, wenn Sie @code{RELEASE_LOCK()} ausführen, einen neuen
+@code{GET_LOCK()} ausführen oder der Thread beendet wird. Diese Funktion
+kann benutzt werden, um Applikations-Sperren zu implementieren oder um
+Datensatz-Sperren zu simulieren. Sie blockiert Anfragen von anderen Clients
+nach Sperren mit demselben Namen; Clients, die sich auf einen angegebenen
+Namen für die Sperr-Zeichenkette einigen, können die Zeichenkette benutzen,
+um kooperatives beratendes Sperren (advisory locking) auszuführen:
+
+@example
+mysql> select GET_LOCK("lock1",10);
+ -> 1
+mysql> select GET_LOCK("lock2",10);
+ -> 1
+mysql> select RELEASE_LOCK("lock2");
+ -> 1
+mysql> select RELEASE_LOCK("lock1");
+ -> NULL
+@end example
+
+Beachten Sie, dass der zweite @code{RELEASE_LOCK()}-Aufruf @code{NULL}
+zurückgibt, weil die Sperre @code{"lock1"} automatisch durch den zweiten
+@code{GET_LOCK()}-Aufruf aufgehoben wurde.
+
+@findex RELEASE_LOCK()
+@item RELEASE_LOCK(zeichenkette)
+Hebt die Sperre auf, die durch die Zeichenkette @code{zeichenkette} benannt
+ist, die mit @code{GET_LOCK()} erlangt wurde. Gibt @code{1} zurück, wenn
+die Sperre aufgehoben wurde, und @code{0}, wenn die Sperre nicht durch
+diesen Thread gemacht wurde (in diesem Fall wird die Sperre nicht
+aufgehoben), oder @code{NULL}, wenn die benannte Sperre nicht existiert.
+Die Sperre existiert nicht, wenn sie nie durch einen Aufruf von
+@code{GET_LOCK()} erlangt wurde oder wenn sie bereits aufgehoben wurde.
+
+@findex BENCHMARK()
+@item BENCHMARK(zaehler,ausdruck)
+Die @code{BENCHMARK()}-Funktion den Ausdruck @code{ausdruck} wiederholt
+@code{zaehler} mal aus. Sie kann benutzt werden, um die Zeit zu ermitteln,
+die MySQL benötigt, um den Ausdruck zu verarbeiten. Der Ergebniswert ist
+immer @code{0}. Die Funktion ist für die Benutzung im @code{mysql}-Client
+gedacht, der die Ausführungszeiten von Anfragen zum Beispiel wie folgt
+darstellt:
+
+@example
+mysql> select BENCHMARK(1000000,encode("hello","goodbye"));
++----------------------------------------------+
+| BENCHMARK(1000000,encode("hello","goodbye")) |
++----------------------------------------------+
+| 0 |
++----------------------------------------------+
+1 row in set (4.74 sec)
+@end example
+
+Die berichtete Zeit ist die am Client-Ende verstrichene Zeit, nicht die
+Prozessorzeit am Server-Ende. Es ist ratsam, @code{BENCHMARK()} mehrere
+Male auszuführen und das Ergebnis unter Berücksichtigung der Last, unter
+der die Server-Maschine fährt, zu interpretieren.
+
+@findex INET_NTOA()
+@item INET_NTOA(ausdruck)
+Gibt die Netzwerk-Adresse (4 oder 8 Bytes) für den numerischen Ausdruck
+zurück:
+
+@example
+mysql> select INET_NTOA(3520061480);
+ -> "209.207.224.40"
+@end example
+
+@findex INET_ATON()
+@item INET_ATON(ausdruck)
+Gibt eine Ganzzahl zurück, die den numerischen Wert einer Netzwerk-Adresse
+darstellt. Adressen können 4-Byte- oder 8-Byte-Adressen sein:
+
+@example
+mysql> select INET_ATON("209.207.224.40");
+ -> 3520061480
+@end example
+
+Die erzeugte Zahl ist immer in Netzwerk-Byte-Reihenfolge; die obige Zahl
+wird zum Beispiel errechnet als @code{209*255^3 + 207*255^2 + 224*255
++40}.
+
+@findex MASTER_POS_WAIT()
+@item MASTER_POS_WAIT(log_name, log_position)
+Blockiert, bis der Slave während der Replikation die festgelegte Position
+in der Master-Log-Datei erreicht. Wenn die Master-Information nicht
+initialisiert wird, wird NULL zurückgegeben. Wenn der Slave nicht läuft,
+blockiert die Funktion und wartet, bis er gestartet wurde, und geht dann
+hinter die angegebene Position. Wenn der Slave bereits hinter der
+angegebenen Position ist, kehrt die Funktion sofort zurück. Der
+Rückgabewert ist die Anzahl von Log-Events, die sie warten muss, um bis zur
+angegebenen Position zu kommen, oder NULL in Fehlerfällen. Nützlich für die
+Steuerung der Master-Slave-Synchronisation, aber ursprünglich geschrieben,
+um das Testen der Replikation zu erleichtern.
+@end table
+
+
+@node Group by functions, , Other Functions, Functions
+@c German node GROUP-BY-Funktionen
+@subsection Funktionen zur Benutzung bei @code{GROUP BY}-Klauseln
+
+@findex GROUP-BY-Funktionen
+@findex Funktionen, GROUP BY
+
+Wenn Sie in einem Statement eine Gruppierungsfunktion benutzen, die
+keine @code{GROUP BY}-Klausel enthält, ist das gleichbedeutend mit der
+Gruppierung aller Zeilen.
+
+@table @code
+@findex COUNT()
+@item COUNT(ausdruck)
+Gibt die Anzahl der Zeilen mit Nicht-@code{NULL}-Werten zurück, die
+durch ein @code{SELECT}-Statement abgerufen werden:
+
+@example
+mysql> select student.student_name,COUNT(*)
+ from student,kurs
+ where student.student_id=kurs.student_id
+ GROUP BY student_name;
+
+@end example
+
+@code{COUNT(*)} ist insofern anders, als es die Anzahl der abgerufenen
+Zeilen zurückgibt, egal ob sie @code{NULL}-Werte enthalten oder nicht.
+
+@code{COUNT(*)} ist darauf optimiert, das Ergebnis sehr schnell
+zurückzugeben, wenn es mittels eines @code{SELECT} von einer Tabelle
+abruft, wenn keine weiteren Spalten abgerufen werden und es keine
+@code{WHERE}-Klausel gibt. Beispiel:
+
+@example
+mysql> select COUNT(*) from student;
+@end example
+
+@findex COUNT(DISTINCT)
+@findex DISTINCT
+@item COUNT(DISTINCT ausdruck,[ausdruck...])
+Gibt die Anzahl unterschiedlicher Nich-@code{NULL}-Werte zurück:
+
+@example
+mysql> select COUNT(DISTINCT ergebnisse) from student;
+@end example
+
+Bei MySQL erhalten Sie die Anzahl unterschiedlicher
+Ausdruckskombinationen, die nicht NULL enthalten, indem Sie eine Liste
+von Ausdrücken angeben. In ANSI-SQL müssten Sie eine Verkettung aller
+Ausdrücke innerhalb von @code{CODE(DISTINCT ..)} angeben.
+
+@findex AVG()
+@item AVG(ausdruck)
+Gibt den Durchschnittswert von @code{ausdruck} zurück:
+
+@example
+mysql> select student_name, AVG(test_ergebnis)
+ from student
+ GROUP BY student_name;
+@end example
+
+@findex MIN()
+@findex MAX()
+@item MIN(ausdruck)
+@itemx MAX(ausdruck)
+Gibt den kleinsten oder größten Wert von @code{ausdruck} zurück.
+@code{MIN()} und @code{MAX()} können Zeichenketten-Argumente aufnehmen
+und geben in solchen Fällen den kleinsten oder größten Zeichenketten-
+Wert zurück. @xref{MySQL indexes}.
+
+@example
+mysql> select student_name, MIN(test_ergebnis), MAX(test_ergebnis)
+ from student
+ GROUP BY student_name;
+@end example
+
+@findex SUM()
+@item SUM(ausdruck)
+Gibt die Summe von @code{ausdruck} zurück. Beachten Sie, dass der
+Rückgabewert NULL ist, wenn die Ergebnismenge keine Zeilen hat!
+
+@findex STD()
+@findex STDDEV()
+@cindex Oracle-Kompatibilität
+@cindex Kompatibilität, mit Oracle
+@item STD(ausdruck)
+@itemx STDDEV(ausdruck)
+Gibt die Standardabweichung von @code{ausdruck} zurück. Das ist eine
+Erweiterung zu ANSI-SQL. Die @code{STDDEV()}-Form dieser Funktion wird
+aus Gründen der Oracle-Kompatibilität zur Verfügung gestellt.
+
+@findex BIT_OR()
+@item BIT_OR(ausdruck)
+Gibt das bitweise @code{OR} aller Bits in @code{ausdruck} zurück. Die
+Berechnung wird mit 64-Bit-(@code{BIGINT})-Genauigkeit durchgeführt.
+
+@findex BIT_AND()
+@item BIT_AND(ausdruck)
+Gibt das bitweise @code{AND} aller Bits in @code{ausdruck} zurück. Die
+Berechnung wird mit 64-Bit-(@code{BIGINT})-Genauigkeit durchgeführt.
+@end table
+
+@cindex @code{GROUP BY}, Erweiterungen zu ANSI-SQL
+MySQL hat die Benutzung von @code{GROUP BY} erweitert. Sie können
+Spalten oder Berechnungen im @code{SELECT}-Ausdruck angeben, die nicht
+im @code{GROUP BY}-Teil erscheinen. Das steht für @emph{jeden möglichen
+Wert für diese Gruppe}. Das können Sie benutzen, um bessere Performance
+zu erzielen, indem Sie Sortieren und Gruppieren unnötiger Bestandteile
+vermeiden. Zum Beispiel müssen Sie in folgender Anfrage nicht nach
+@code{kunde.name} gruppieren:
+
+@example
+mysql> select bestellung.kunde_id,kunde.name,max(zahlungen)
+ from bestellung,kunde
+ where bestellung.kunde_id = kunde.kunde_id
+ GROUP BY bestellung.kunde_id;
+@end example
+
+In ANSI-SQL müssten Sie der @code{GROUP BY}-Klausel @code{kunde.name}
+hinzufügen. In MySQL ist der Name überflüßig, solange Sie nicht im
+ANSI-Modus fahren.
+
+@strong{Benutzen Sie dieses Feature nicht}, wenn die Spalten, die Sie im
+@code{GROUP BY}-Teil auslassen, in der Gruppe nicht eindeutig sind!
+Sonst erhalten Sie unvorhersagbare Ergebnisse.
+
+In einigen Fällen können Sie @code{MIN()} und @code{MAX()} benutzen, um
+einen bestimmten Spaltenwert zu erhalten, selbst wenn er nicht eindeutig
+ist. Folgendes gibt den Wert von @code{spalte} aus der Zeile zurück, die
+den kleinsten Wert in der @code{sortierung}-Spalte enthält:
+
+@example
+substr(MIN(concat(rpad(sortierung,6,' '),spalte)),7)
+@end example
+
+@node Data Manipulation, Data Definition, Functions, Reference
+@c German node Datenmanipulation
+@section Datenmanipulation: @code{SELECT}, @code{INSERT}, @code{UPDATE}, @code{DELETE}
+
+
+
+@menu
+* SELECT::
+* HANDLER::
+* INSERT::
+* INSERT DELAYED::
+* UPDATE::
+* DELETE::
+* TRUNCATE::
+* REPLACE::
+* LOAD DATA::
+@end menu
+
+@node SELECT, HANDLER, Data Manipulation, Data Manipulation
+@c German node SELECT
+@subsection @code{SELECT}-Syntax
+
+@findex SELECT
+
+@c help SELECT
+@example
+SELECT [STRAIGHT_JOIN] [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
+ [HIGH_PRIORITY]
+ [DISTINCT | DISTINCTROW | ALL]
+ select_ausdruck,...
+ [INTO @{OUTFILE | DUMPFILE@} 'datei' export_optionen]
+ [FROM tabellenreferenz
+ [WHERE where_definition]
+ [GROUP BY @{positive_ganzzahl | spalten_name | formel@} [ASC | DESC], ...]
+ [HAVING where_definition]
+ [ORDER BY @{positive_ganzzahl | spalten_name | formel@} [ASC | DESC] ,...]
+ [LIMIT [offset,] zeilen]
+ [PROCEDURE prozedur_name]
+ [FOR UPDATE | LOCK IN SHARE MODE]]
+@end example
+@c help end
+
+@code{SELECT} wird benutzt, um ausgewählte Zeilen aus einer oder mehreren
+Tabellen abzurufen. @code{select_ausdruck} gibt die Spalten an, die Sie
+abrufen wollen. @code{SELECT} kann auch benutzt werden, um Zeilen ohne
+Bezug zu irgend einer Tabelle abzurufen. Beispiel:
+
+@example
+mysql> SELECT 1 + 1;
+ -> 2
+@end example
+
+Alle benutzten Schlüsselwörter müssen genau in der oben angegebenen
+Reihenfolge genannt werden. Beispielsweise muss eine @code{HAVING}-Klausel
+nach jeglicher @code{GROUP BY}-Klausel und vor jeglicher @code{ORDER
+BY}-Klausel kommen.
+
+@itemize @bullet
+
+@item
+@cindex Aliase, für Ausdrücke
+@cindex Ausdruck-Aliase
+Einem @code{SELECT}-Ausdruck kann mit @code{AS} ein Alias zugewiesen
+werden. Der Alias wird als Spaltenname verwendet und kann bei @code{ORDER
+BY}- oder @code{HAVING}-Klauseln benutzt werden. Beispiel:
+
+@example
+mysql> select concat(nachname,', ',vorname) AS voller_name
+ from tabelle ORDER BY voller_name;
+@end example
+
+@item
+The @code{FROM tabellenreferenz}-Klausel gibt die Tabellen an, aus denen
+Zeilen abgerufen werden sollen. Wenn Sie mehr als eine Tabelle aufführen,
+führen Sie einen Join durch. Informationen über die Join-Syntax finden Sie
+unter @ref{JOIN, , @code{JOIN}}.
+
+@item
+Sie können auf eine Spalte als @code{spalten_name} verweisen, als
+@code{tabelle.spalten_name} oder als @code{datenbank.tabelle.spalten_name}.
+Sie müssen das @code{tabelle}- oder @code{datenbank.tabelle}-Präfix für
+einen Spaltenverweis in einem @code{SELECT}-Statement nicht angeben, es sei
+denn, der Verweis wäre ansonsten mehrdeutig. Sie @ref{Legal names}; hier
+finden sich Beispiele von Mehrdeutigkeit, die erfordern, dass Sie
+ausführlichere Spaltenverweis-Formen benutzen.
+
+@item
+@cindex Aliase, für Tabellen
+@cindex Tabellen-Aliase
+Einem Tabellenverweis kann mit @code{tabelle [AS] alias_name} ein
+Tabellen-Alias zugewiesen werden:
+
+@example
+mysql> select t1.name, t2.gehalt from angestellte AS t1, info AS t2
+ where t1.name = t2.name;
+mysql> select t1.name, t2.gehalt from angestellte t1, info t2
+ where t1.name = t2.name;
+@end example
+
+@item
+Auf Spalten, die für die Ausgabe ausgewählt wurden, kann in @code{ORDER
+BY}- und @code{GROUP BY}-Klauseln mit Spaltennamen, Spalten-Aliasen oder
+Spaltenpositionen verwiesen werden. Spaltenpositionen fangen mit 1 an:
+
+@example
+mysql> select hochschule, region, seed von tournament
+ ORDER BY region, seed;
+mysql> select hochschule, region AS r, seed AS s from turnier
+ ORDER BY r, s;
+mysql> select hochschule, region, seed from turnier
+ ORDER BY 2, 3;
+@end example
+
+Um in absteigender Reihenfolge zu sortieren, fügen Sie dem Namen der
+Spalte das @code{DESC}-Schlüsselwort in the @code{ORDER BY}-Klausel hinzu
+(descending, absteigend), nach der Sie sortieren. Die Vorgabe ist
+aufsteigende Reihenfolge. Das können Sie auch explizit angeben, indem Sie
+das @code{ASC}-Schlüsselwort verwenden.
+
+@item
+In der @code{WHERE}-Klausel können Sie beliebige Funktionen verwenden, die
+MySQL unterstützt. @xref{Functions}.
+
+@item
+Die @code{HAVING}-Klausel kann auf jede Spalte oder jeden Alias verweisen,
+die bzw. der im @code{select_ausdruck} genannt wurde. Die Klausel wird
+zuletzt angewandt, direkt bevor Ergebnisse an den Client geschickt werden,
+ohne jede Optimierung. Benutzen Sie kein @code{HAVING} für Dinge, die in
+der @code{WHERE}-Klausel stehen sollten. Schreiben Sie beispielsweise nicht
+folgendes:
+
+@example
+mysql> select spalten_name from tabelle HAVING spalten_name > 0;
+@end example
+
+Sondern statt dessen:
+
+@example
+mysql> select spalten_name from tabelle WHERE spalten_name > 0;
+@end example
+
+Ab MySQL-Version 3.22.5 können Sie Anfragen auch wie folgt schreiben:
+
+@example
+mysql> select user,max(gehalt) from benutzer
+ group by benutzer HAVING max(gehalt)>10;
+@end example
+
+In älteren MySQL-Versionen schreiben Sie statt dessen:
+
+@example
+mysql> select benutzer,max(gehalt) AS summe from benutzer
+ group by benutzer HAVING summe>10;
+@end example
+
+@item
+@code{SQL_SMALL_RESULT}, @code{SQL_BIG_RESULT}, @code{SQL_BUFFER_RESULT},
+@code{STRAIGHT_JOIN} und @code{HIGH_PRIORITY} sind MySQL Erweiterungen zu
+ANSI-SQL92.
+
+@item
+@code{HIGH_PRIORITY} gibt dem @code{SELECT} höhere Priorität als einem
+Statement, das eine Tabelle aktualisiert. Sie sollten das nur für Anfragen
+benutzen, die sehr schnell sind und sofort durchgeführt werden müssen. Eine
+@code{SELECT HIGH_PRIORITY}-Anfrage läuft, wenn die Tabelle eine
+Lese-Sperre hat, selbst wenn es ein Update-Statement gibt, das darauf
+wartet, dass die Tabelle freigegeben wird.
+
+@item
+@code{SQL_BIG_RESULT} kann bei @code{GROUP BY} oder @code{DISTINCT} benutzt
+werden, um dem Optimierer mitzuteilen, dass das Ergebnis sehr viele Zeilen
+haben wird. In diesem Fall benutzt MySQL bei Bedarf direkt
+Festplatten-basierende temporäre Tabellen. Ausserdem bevorzugt MySQL in
+diesem Fall Sortieren vor dem Anlegen einer temporären Tabelle mit einem
+Schlüssel auf den @code{GROUP BY}-Elementen.
+
+@item
+@cindex @code{GROUP BY}, Erweiterungen zu ANSI-SQL
+Wenn Sie @code{GROUP BY} benutzen, werden die Ausgabe-Zeilen gemäß dem
+@code{GROUP BY} sortiert, als hätten Sie ein @code{ORDER BY} für alle
+Felder im @code{GROUP BY} angegeben. MySQL hat @code{GROUP BY} erweitert,
+so dass Sie dafür auch @code{ASC} und @code{DESC} angeben können:
+
+@example
+SELECT a,COUNT(b) FROM tabelle GROUP BY a DESC
+@end example
+
+@item
+MySQL hat die Benutzung von @code{GROUP BY} erweitert, um es Ihnen zu
+gestatten, auch Felder auszuwählen, die nicht in der @code{GROUP
+BY}-Klausel erwähnt wurden. Wenn Sie nicht die Ergebnisse erhalten, die Sie
+von Ihrer Anfrage erwarten, lesen Sie bitte die @code{GROUP
+BY}-Beschreibung.
+
+@item
+@cindex Hinweise
+@code{SQL_BUFFER_RESULT} erzwingt, dass das Ergebnis in eine temporäre
+Tabelle geschrieben wird. Das hilft MySQL, frühzeitig Tabellensperren
+aufzuheben, und hilft in Fällen, in denen es lange dauert, das Ergebnis an
+den Client zu senden.
+
+@item
+@cindex Hinweise
+@code{SQL_SMALL_RESULT}, eine MySQL-spezifische Option, kann bei
+@code{GROUP BY} oder @code{DISTINCT} benutzt werden, um dem Optimierer
+mitzuteilen, dass der Ergebnissatz klein sein wird. In diesem Fall benutzt
+MySQL schnelle temporäre Tabellen, um die Ergebnistabelle zu speichern,
+anstatt Sortieren zu benutzen. In MySQL-Version 3.23 sollte das
+normalerweise nicht benötigt werden.
+
+@item
+@cindex Hinweise
+@code{STRAIGHT_JOIN} zwingt den Optimierer, Tabellen in der Reihenfolge zu
+verknüpfen, in der sie in der @code{FROM}-Klausel aufgelistet sind. Sie
+können das benutzen, um die Geschwindigkeit einer Anfrage zu erhöhen, wenn
+der Optimierer Tabellen in nicht optimaler Reihenfolge verknüpft.
+@xref{EXPLAIN, , @code{EXPLAIN}}.
+
+@item
+Die @code{LIMIT}-Klausel wird benutzt, um die Anzahl von Zeilen, die vom
+@code{SELECT}-Statement zurückgegeben werden, zu beschränken. @code{LIMIT}
+erwartet ein oder zwei numerische Argumente.
+
+Wenn zwei Argumente angegeben sind, legt das erste den Offset der ersten
+Zeile fest, die zurückgegeben wird, und das zweite gibt die maximale Anzahl
+von Zeilen an, die zurückgegeben werden. Der Offset der anfänglichen Zeile
+ist 0 (nicht 1):
+
+@example
+mysql> select * from tabelle LIMIT 5,10; # Zeilen 6 bis 15 zurückgeben
+@end example
+
+Wenn ein Argument angegeben wird, stellt es die maximale Anzahl von Zeilen
+dar, die zurückgegeben werden:
+
+@example
+mysql> select * from tabelle LIMIT 5; # Die ersten 5 Zeilen zurückgeben
+@end example
+
+Mit anderen Worten ist @code{LIMIT n} äquivalent zu @code{LIMIT 0,n}.
+
+@item
+@tindex /etc/passwd
+Die @code{SELECT ... INTO OUTFILE 'datei'}-Form von @code{SELECT} schreibt
+die ausgewählten Zeilen in eine Datei. Die Datei wird auf dem Server-Host
+erzeugt und darf nicht bereits bestehen (das verhindert unter anderem, dass
+Datenbanktabellen und Dateien wie @file{/etc/passwd} zerstört werden). Sie
+benötigen die @strong{file}-Berechtigung auf dem Server-Host, um diese Form
+von @code{SELECT} auszuführen.
+
+@code{SELECT ... INTO OUTFILE} ist hauptsächlich dafür vorgesehen, um eine
+Tabelle auf der Server-Maschine schnell zu dumpen. Wenn Sie die
+resultierende Datei auf einem anderen Host als dem Server-Host haben
+wollen, können Sie @code{SELECT ... INTO OUTFILE} nicht benutzen. In diesem
+Fall sollten Sie statt dessen ein Client-Programm wie @code{mysqldump
+--tab} oder @code{mysql -e "SELECT ..." > outfile} benutzen, um die Datei
+zu erzeugen.
+
+@code{SELECT ... INTO OUTFILE} ist das Komplement von @code{LOAD DATA
+INFILE}; die Syntax für den @code{export_optionen}-Teil des Statements
+besteht aus denselben @code{FIELDS}- und @code{LINES}-Klauseln, die beim
+@code{LOAD DATA INFILE}-Statement benutzt werden. @xref{LOAD DATA, ,
+@code{LOAD DATA}}.
+
+In der resultierenden Textdatei werden nur folgende Zeichen durch das
+@code{ESCAPED BY}-Zeichen escapet:
+
+@itemize @bullet
+@item Das @code{ESCAPED BY}-Zeichen
+@item Das erste Zeichen in @code{FIELDS TERMINATED BY}
+@item Das erste Zeichen in @code{LINES TERMINATED BY}
+@end itemize
+
+Zusätzlich wird @code{ASCII 0} in @code{ESCAPED BY}, gefolgt von 0
+(@code{ASCII 48}), umgewandelt.
+
+Der Grund hierfür ist, dass Sie jegliche @code{FIELDS TERMINATED BY}-,
+@code{ESCAPED BY}- oder @code{LINES TERMINATED BY}-Zeichen escapen MÜSSEN,
+um die Datei zuverlässig wieder einlesen zu können. @code{ASCII 0} wird
+escapet, um das Lesen mit einigen Pagern zu erleichtern.
+
+Weil sich die resultierende Datei nicht nach der SQL-Syntax richten muss,
+muss nicht weiter escapet werden.
+
+Im Folgenden ein Beispiel, wie man eine Datei in einem Format erhält, das
+von vielen alten Programmen benutzt wird:
+
+@example
+SELECT a,b,a+b INTO OUTFILE "/tmp/resultat.text"
+FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
+LINES TERMINATED BY "\n"
+FROM tabelle;
+@end example
+
+@item
+@findex DUMPFILE
+Wenn Sie @code{INTO DUMPFILE} anstelle von @code{INTO OUTFILE} benutzen,
+schreibt MySQL nur eine Zeile in die Datei, ohne jede Spalten- oder
+Zeilen-Begrenzer und ohne jedes Escapen. Das ist nützlich, wenn Sie ein
+Blob in eine Datei speichern wollen.
+
+@item
+Beachten Sie, dass jede Datei, die von @code{INTO OUTFILE} und @code{INTO
+DUMPFILE} erzeugt wird, für alle Benutzer lesbar ist! Der Grund liegt
+darin, dass der MySQL-Server keine Datei erzeugen kann, die jemandem
+anderen gehört als dem Benutzer, unter dem er läuft (Sie sollten
+@code{mysqld} nie als Root laufen lassen), daher muss die Datei für
+jedermann lesbar sein, damit Sie die Zeilen abrufen können.
+
+@item
+Wenn Sie @code{FOR UPDATE} bei einem Tabellen-Handler mit
+Seiten-/Zeilen-Sperren benutzen, werden die untersuchten Zeilen
+schreib-gesperrt.
+@end itemize
+
+
+
+@menu
+* JOIN::
+* UNION::
+@end menu
+
+@node JOIN, UNION, SELECT, SELECT
+@c German node JOIN
+@subsubsection @code{JOIN}-Syntax
+
+@findex JOIN
+@findex INNER JOIN
+@findex CROSS JOIN
+@findex LEFT JOIN
+@findex LEFT OUTER JOIN
+@findex NATURAL LEFT JOIN
+@findex NATURAL LEFT OUTER JOIN
+@findex RIGHT JOIN
+@findex RIGHT OUTER JOIN
+@findex NATURAL RIGHT JOIN
+@findex NATURAL RIGHT OUTER JOIN
+@findex STRAIGHT_JOIN
+
+MySQL unterstützt folgende @code{JOIN}-Syntaxen für
+@code{SELECT}-Statements:
+
+@example
+tabellen_verweis, tabellen_verweis
+tabellen_verweis [CROSS] JOIN tabellen_verweis
+tabellen_verweis INNER JOIN tabellen_verweis join_bedingung
+tabellen_verweis STRAIGHT_JOIN tabellen_verweis
+tabellen_verweis LEFT [OUTER] JOIN tabellen_verweis join_bedingung
+tabellen_verweis LEFT [OUTER] JOIN tabellen_verweis
+tabellen_verweis NATURAL [LEFT [OUTER]] JOIN tabellen_verweis
+@{ oder tabellen_verweis LEFT OUTER JOIN tabellen_verweis ON bedingungs_ausdruck @}
+tabellen_verweis RIGHT [OUTER] JOIN tabellen_verweis join_bedingung
+tabellen_verweis RIGHT [OUTER] JOIN tabellen_verweis
+tabellen_verweis NATURAL [RIGHT [OUTER]] JOIN tabellen_verweis
+@end example
+
+Wobei @code{tabellen_verweis} definiert ist als:
+@example
+tabelle [[AS] alias] [USE INDEX (schluessel_liste)] [IGNORE INDEX (schluessel_liste)]
+@end example
+
+Und @code{join_bedingung} definiert ist als:
+
+@example
+ON bedingungs_ausdruck |
+USING (spalten_liste)
+@end example
+
+Sie sollten nie irgend welche Bedingungen im @code{ON}-Teil haben, die dazu
+benutzt werden, um die Zeilen, die im Ergebnissatz auftauchen, zu
+beschränken. Wenn Sie so etwas tun wollen, müssen Sie das in der
+@code{WHERE}-Klausel tun.
+
+Beachten Sie, dass vor Version 3.23.17 @code{INNER JOIN} keine
+@code{join_bedingung} aufnahm!
+
+@cindex ODBC-Kompatibilität
+@cindex Kompatibilität, mit ODBC
+Die letzte oben dargestellte @code{LEFT OUTER JOIN}-Syntax gibt es nur aus
+Gründen der Kompatibilität mit ODBC:
+
+@itemize @bullet
+@item
+Einem Tabellenverweis kann mit @code{tabelle AS alias_name} oder
+@code{tabelle alias_name} ein Alias zugewiesen werden:
+
+@example
+mysql> select t1.name, t2.gehalt from angestellte AS t1, info AS t2
+ where t1.name = t2.name;
+@end example
+
+@item
+Der @code{ON}-Bedingungscode ist jeglicher Bedingungscode der Form, wie er
+auch in einer @code{WHERE}-Klausel benutzt werden kann.
+
+@item
+Wenn es für die rechte Tabelle keinen übereinstimmenden Datensatz im
+@code{ON}- oder @code{USING}-Teil eines @code{LEFT JOIN} gibt, wird für die
+rechte Tabelle eine Zeile benutzt, in der alle Spalten auf @code{NULL}
+gesetzt sind. Das können Sie benutzen, um Datensätze in einer Tabelle
+herauszusuchen, die in einer anderen Tabelle kein Gegenstück haben:
+
+@example
+mysql> select tabelle1.* from tabelle1
+ LEFT JOIN tabelle2 ON tabelle1.id=tabelle2.id
+ where tabelle2.id is NULL;
+@end example
+
+Dieses Beispiel findet alle Zeilen in @code{tabelle1} mit einem
+@code{id}-Wert, der in @code{tabelle2} nicht vorhanden ist (also alle
+Zeilen in @code{tabelle1} ohne entsprechende Zeile in @code{tabelle2}).
+Hierbei wird natürlich angenommen, dass @code{tabelle2.id} als @code{NOT
+NULL} deklariert ist. @xref{LEFT JOIN optimisation}.
+
+@item
+Die @code{USING}-@code{(spalten_liste)}-Klausel nennt eine Auflistung von
+Spalten, die in beiden Tabellen existieren müssen. Eine
+@code{USING}-Klausel wie:
+
+@example
+A LEFT JOIN B USING (C1,C2,C3,...)
+@end example
+
+Ist definiert als semantisch identisch mit einem @code{ON}-Ausdruck wie
+diesem:
+
+@example
+A.C1=B.C1 AND A.C2=B.C2 AND A.C3=B.C3,...
+@end example
+
+@item
+Der @code{NATURAL [LEFT] JOIN} zweier Tabellen ist definiert als semantisch
+identisch äquivalent zu einem @code{INNER JOIN} oder einem @code{LEFT JOIN}
+mit einer @code{USING}-Klausel, die alle Spalten nennt, die in beiden
+Tabellen existieren.
+
+@item
+@code{RIGHT JOIN} funktioniert analog wie @code{LEFT JOIN}. Um Code
+zwischen Datenbanken portabel zu halten, wird empfohlen, @code{LEFT JOIN}
+anstelle von @code{RIGHT JOIN} zu benutzen.
+
+@item
+@cindex Hinweise
+@code{STRAIGHT_JOIN} ist identisch mit @code{JOIN}, ausser dass die linke
+Tabelle immer vor der rechten Tabelle gelesen wird. Das kann in den
+(wenigen) Fällen benutzt werden, wo der Optimierer die Tabellen in die
+falsche Reihenfolge bringt.
+
+@item
+@cindex Hinweise
+Ab MySQL-Version 3.23.12 können Sie Hinweise darüber geben, welchen Index
+MySQL benutzen sollte, wenn Informationen aus einer Tabelle abgerufen
+werden. Das ist nützlich, wenn @code{EXPLAIN} zeigt, dass MySQL den
+falschen Index benutzt. Indem Sie @code{USE INDEX (schluessel_liste)}
+angeben, können Sie MySQL anweisen, nur einen der angegebenen Indexe zu
+benutzen, um Zeilen in der Tabelle zu finden. Die alternative Syntax
+@code{IGNORE INDEX (schluessel_liste)} kann benutzt werden, um MySQL
+anzuweisen, einen bestimmten Index nicht zu benutzen.
+@end itemize
+
+Einige Beispiele:
+
+@example
+mysql> select * from tabelle1,tabelle2 where tabelle1.id=tabelle2.id;
+mysql> select * from tabelle1 LEFT JOIN tabelle2 ON tabelle1.id=tabelle2.id;
+mysql> select * from tabelle1 LEFT JOIN tabelle2 USING (id);
+mysql> select * from tabelle1 LEFT JOIN tabelle2 ON tabelle1.id=tabelle2.id
+ LEFT JOIN table3 ON tabelle2.id=table3.id;
+mysql> select * from tabelle1 USE INDEX (schluessel1,schluessel2) WHERE schluessel1=1 und schluessel2=2 AND
+ schluessel3=3;
+mysql> select * from tabelle1 IGNORE INDEX (schluessel3) WHERE schluessel1=1 und schluessel2=2 AND
+ schluessel3=3;
+@end example
+
+@xref{LEFT JOIN optimisation, , @code{LEFT JOIN}-Optimierung}.
+
+
+@node UNION, , JOIN, SELECT
+@c German node UNION
+@subsubsection @code{UNION}-Syntax
+
+@findex UNION
+
+@example
+SELECT ....
+UNION [ALL]
+SELECT ....
+ [UNION
+ SELECT ...]
+@end example
+
+@code{UNION} ist implementiert in MySQL 4.0.0.
+
+@code{UNION} wird benutzt, um das Ergebnis vieler @code{SELECT}-Statements
+in einem Ergebnissatz zu kombinieren.
+
+Die @code{SELECT}-Befehle sind normale SELECT-Befehle, aber mit folgenden
+Einschränkungen:
+
+@itemize @bullet
+@item
+Nur der letzte @code{SELECT}-Befehl darf @code{INTO OUTFILE} enthalten.
+@item
+Nur der letzte @code{SELECT}-Befehl darf @code{ORDER BY} enthalten.
+@end itemize
+
+Wenn Sie das Schlüsselwort @code{ALL} für @code{UNION} nicht benutzen, sind
+alle zurückgegebenen Zeilen eindeutig (unique), als hätten Sie ein
+@code{DISTINCT} für den gesamten Ergebnissatz gemacht. Wenn Sie @code{ALL}
+angeben, erhalten Sie alle übereinstimmenden Zeilen von allen benutzten
+@code{SELECT}-Statements.
+
+@node HANDLER, INSERT, SELECT, Data Manipulation
+@c German node INSERT
+@subsection @code{INSERT}-Syntax
+
+@findex INSERT
+
+@example
+ INSERT [LOW_PRIORITY | DELAYED] [IGNORE]
+ [INTO] tabelle [(spalten_name,...)]
+ VALUES (ausdruck,...),(...),...
+oder INSERT [LOW_PRIORITY | DELAYED] [IGNORE]
+ [INTO] tabelle [(spalten_name,...)]
+ SELECT ...
+oder INSERT [LOW_PRIORITY | DELAYED] [IGNORE]
+ [INTO] tabelle
+ SET spalten_name=ausdruck, spalten_name=ausdruck, ...
+
+@end example
+
+@code{INSERT} fügt neue Zeilen in eine bestehende Tabelle ein. Die
+@code{INSERT ... VALUES}-Form des Statements fügt Zeilen basierend auf
+explizit angegebenen Werten ein. Die @code{INSERT ... SELECT}-Form fügt
+Zeilen ein, die aus einer oder mehreren anderen Tabellen ausgewählt wurden.
+Die @code{INSERT ... VALUES}-Form mit mehrfachen Wertelisten wird ab
+MySQL-Version 3.22.5 unterstützt. Die @code{spalten_name=expression}-Syntax
+wird ab MySQL-Version 3.22.10 unterstützt.
+
+@code{tabelle} ist die Tabelle, in die Zeilen eingefügt werden sollen. Die
+Spaltennamenliste oder die @code{SET}-Klausel geben an, für welche Spalten
+das Statement Werte angibt:
+
+@itemize @bullet
+@item
+Wenn Sie keine Spaltenliste für @code{INSERT ... VALUES} oder @code{INSERT
+... SELECT} angeben, müssen für alle Spalten Werte in der
+@code{VALUES()}-Liste oder vom @code{SELECT} bereit stehen. Wenn Sie die
+Reihenfolge der Tabellenspalten nicht kennen, benutzen Sie @code{DESCRIBE
+tabelle}, um sie herauszufinden.
+
+@item
+Jede Spalte, die nicht explizit in einer Werteliste angegeben wird, wird
+auf ihren Vorgabewert gesetzt. Wenn Sie beispielsweise eine Spaltenliste
+angeben, die nicht alle Tabellenspalten nennt, werden unbenannte Spalten
+auf ihre Vorgabewerte gesetzt. Die Zuweisung von Vorgabewerten ist in
+@ref{CREATE TABLE, , @code{CREATE TABLE}} beschrieben.
+
+@item
+Ein @code{ausdruck} kann sich auf jede Spalte beziehen, die vorher in einer
+Werteliste angegeben wurde. Beispielsweise können Sie folgendes eingeben:
+
+@example
+mysql> INSERT INTO tabelle (spalte1,spalte2) VALUES(15,spalte1*2);
+@end example
+
+Aber nicht das hier:
+
+@example
+mysql> INSERT INTO tabelle (spalte1,spalte2) VALUES(spalte2*2,15);
+@end example
+
+@item
+Wenn Sie das Schlüsselwort @code{LOW_PRIORITY} angeben, wird die Ausführung
+von @code{INSERT} verzögert, bis kein anderer Client mehr aus der Tabelle
+liest. In diesem Fall muss der Client warten, bis das INSERT-Statement
+fertig ist, was lange Zeit dauern kann, wenn die Tabelle stark benutzt
+wird. Das ist im Gegensatz zu @code{INSERT DELAYED}, was den Client sofort
+weitermachen läßt. @xref{INSERT DELAYED}. Beachten Sie, dass
+@code{LOW_PRIORITY} normalerweise nicht bei @code{MyISAM}-Tabellen benutzt
+werden sollte, weil dadurch gleichzeitige Einfügeoperationen verhindert
+werden. @xref{MyISAM}.
+
+@item
+Wenn Sie das Schlüsselwort @code{IGNORE} in einem @code{INSERT} mit vielen
+Wertezeilen angeben, werden alle Zeilen, die einen bestehenden
+@code{PRIMARY}- oder @code{UNIQUE}-Schlüssel duplizieren würden, ignoriert
+und nicht eingefügt. Wenn Sie @code{IGNORE} nicht angeben, wird die
+Einfügeoperation abgebrochen, wenn es eine Zeile gibt, die einen
+bestehenden Schlüsselwert duplizieren würde. Mit der C-API-Funktion
+@code{mysql_info()} können Sie feststellen, wie viele Zeilen in die Tabelle
+eingefügt wurden.
+
+@item
+Wenn MySQL mit der @code{DONT_USE_DEFAULT_FIELDS}-Option konfiguriert
+wurde, erzeugen @code{INSERT}-Statements einen Fehler, wenn Sie nicht
+explizit Werte für alle Spalten angeben, die einen Nicht-@code{NULL}-Wert
+erfordern. @xref{configure options, , @code{configure}-Optionen}.
+
+@item
+Den Wert, der für eine @code{AUTO_INCREMENT}-Spalte benutzt wurde, finden
+Sie mit der @code{mysql_insert_id}-Funktion heraus. @xref{mysql_insert_id,
+, @code{mysql_insert_id()}}.
+@end itemize
+
+@findex mysql_info()
+Wenn Sie ein @code{INSERT ... SELECT}- oder ein @code{INSERT ...
+VALUES}-Statement mit mehrfachen Wertlisten benutzen, können Sie die
+C-API-Funktion @code{mysql_info()} benutzen, um Informationen über die
+Anfrage zu erhalten. Das Format der Informationszeichenkette ist unten
+dargestellt:
+
+@example
+Records: 100 Duplicates: 0 Warnings: 0
+@end example
+
+@code{Duplicates} zeigt die Anzahl von Zeilen, die nicht eingefügt werden
+konnten, weil sie einen bestehenden eindeutigen Indexwert dupliziert
+hätten. @code{Warnings} zeigen die Anzahl von Versuchen, Spaltenwerte
+einzufügen, die in irgend einer Weise problematisch waren. Warnungen
+erfolgen unter folgenden Umständen:
+
+@itemize @bullet
+@item
+Wenn @code{NULL} in eine Spalte eingefügt wird, die als @code{NOT NULL}
+deklariert ist. Die Spalte wird auf ihren Vorgabewert gesetzt.
+
+@item
+Wenn eine numerische Spalte auf einen Wert ausserhalb des Wertebereichs der
+Spalte gesetzt wird. Der Wert wird auf den entsprechenden Endpunkt des
+Bereichs abgeschnitten.
+
+@item
+Wenn eine numerische Spalte auf einen Wert wie @code{'10.34 a'} gesetzt
+wird. Die unsinnigen Zeichen am Ende werden entfernt und der verbleibende
+numerische Anteil eingefügt. Wenn der Wert als Zahl überhaupt keinen Sinn
+ergibt, wird die Spalte auf @code{0} gesetzt.
+
+@item
+Wenn eine Zeichenkette in eine @code{CHAR}-, @code{VARCHAR}-, @code{TEXT}-
+oder @code{BLOB}-Spalte eingefügt wird, die die maximale Länge der Spalte
+überschreitet. Der Wert wird auf die maximale Spaltenlänge beschnitten.
+
+@item
+Wenn ein Wert in eine DATE- oder TIME-Spalte eingefügt wird, der für den
+Spaltentyp nicht zulässig ist. Die Spalte wird auf den entsprechenden
+0-Wert für diesen Typ gesetzt.
+@end itemize
+
+@findex HANDLER
+@node INSERT, INSERT DELAYED, HANDLER, Data Manipulation
+@c German node HANDLER
+@subsection @code{HANDLER}-Syntax
+
+@example
+HANDLER tabelle OPEN [ AS alias ]
+HANDLER tabelle READ index @{ = | >= | <= | < @} (wert1, wert2, ... ) [ WHERE ... ] [LIMIT ... ]
+HANDLER tabelle READ index @{ FIRST | NEXT | PREV | LAST @} [ WHERE ... ] [LIMIT ... ]
+HANDLER tabelle READ @{ FIRST | NEXT @} [ WHERE ... ] [LIMIT ... ]
+HANDLER tabelle CLOSE
+@end example
+
+Das @code{HANDLER}-Statement ermöglicht direkten Zugriff auf die
+MySQL-Tabellenschnittstelle unter Umgehung des SQL-Optimierers. Daher ist
+es schneller als SELECT.
+
+Die erste Form des @code{HANDLER}-Statements öffnet eine Tabelle und macht
+sie über die folgenden @code{HANDLER ... READ}-Routinen zugänglich. Dieses
+Tabellenobjekt wird nicht mit anderen Threads geteilt und wird nicht
+geschlossen, bis der Thread @code{HANDLER tabelle CLOSE} aufruft oder
+stirbt.
+
+Die zweite Form holt eine (oder mehrere, festgelegt durch die
+@code{LIMIT}-Klausel) Zeile, bei der der angegebene Index mit der Bedingung
+übereinstimmt und die @code{WHERE}-Bedingung erfüllt ist. Wenn der Index
+aus mehreren Teilen besteht (also mehrere Spalten überspannt), werden die
+Werte in einer Komma-getrennten Liste angegeben, wobei es möglich ist, nur
+Werte für einige erste Spalten anzugeben.
+
+Die dritte Form holt eine (oder mehrere, festgelegt durch die
+@code{LIMIT}-Klausel) Zeile in Index-Reihenfolge aus der Tabelle, bei der
+die @code{WHERE}-Bedingung erfüllt ist.
+
+Die vierte Form (ohne Index-Angabe) holt eine (oder mehrere, festgelegt
+durch die @code{LIMIT}-Klausel) Zeile in natürlicher Zeilenreihenfolge aus
+der Tabelle (wie in der Daten-Datei gespeichert), bei der die
+@code{WHERE}-Bedingung erfüllt ist. Das ist schneller als @code{HANDLER
+tabelle READ index}, wenn ein kompletter Tabellen-Scan erwünscht ist.
+
+Die letzte Form schließt eine mit @code{HANDLER ... OPEN} geöffnete
+Tabelle.
+
+@code{HANDLER} ist in gewisser Hinsicht ein Statement auf niedriger Ebene
+(Low-Level), dass zum Beispiel keine Konsistenz gewährleistet. Das heißt,
+@code{HANDLER ... OPEN} nimmt @strong{KEINEN} Schnappschuss der Tabelle auf
+und sperrt die Tabelle @strong{NICHT}. Das bedeutet, dass nach
+@code{HANDLER ... OPEN} Tabellendaten verändert werden können (durch diesen
+oder einen anderen Thread) und dass diese Veränderungen nur teilweise in
+@code{HANDLER ... NEXT}- oder @code{HANDLER ... PREV}-Scans erscheinen.
+
+
+
+
+@findex REPLACE ... SELECT
+@findex INSERT ... SELECT
+
+
+
+@menu
+* INSERT SELECT::
+@end menu
+
+@node INSERT SELECT, , INSERT, INSERT
+@c German node INSERT SELECT
+@subsubsection @code{INSERT ... SELECT}-Syntax
+
+@example
+INSERT [LOW_PRIORITY] [IGNORE] [INTO] tabelle [(spalten_liste)] SELECT ...
+@end example
+
+Mit dem @code{INSERT ... SELECT}-Statement können Sie schnell viele Zeilen
+aus einer oder mehreren anderen Tabellen einfügen.
+
+@example
+INSERT INTO temporaere_tabelle2 (fldID) SELECT temporaere_tabelle1.fldOrder_ID FROM temporaere_tabelle1 WHERE
+temporaere_tabelle1.fldOrder_ID > 100;
+@end example
+
+Folgende Bedingungen gelten für ein @code{INSERT ... SELECT}-Statement:
+
+@c German FIX changed all @Minus to @minus
+@itemize @minus
+@item
+Die Ziel-Tabelle des @code{INSERT}-Statements darf nicht in der
+@code{FROM}-Klausel des @code{SELECT}-Teils der Anfrage erscheinen, weil es
+in ANSI-SQL verboten ist, aus derselben Tabelle auszuwählen
+(@code{SELECT}), in die eingefügt wird. (Das Problem liegt darin, dass das
+@code{SELECT} möglicherweise Datensätze finden würde, die früher während
+desselben Laufs eingefügt wurden. Wenn man Sub-Select-Klauseln verwendet,
+könnte die Situation schnell sehr verwirrend werden!)
+
+@item
+@code{AUTO_INCREMENT}-Spalten funktionieren wie gehabt.
+
+@item
+Sie können die C-API-Funktion @code{mysql_info()} benutzen, um
+Informationen über die Anfrage zu erhalten. @xref{INSERT}.
+
+@item
+Um sicherzustellen, dass die Update-Log-Datei/Binär-Log-Datei benutzt
+werden kann, um die Original-Tabellenlänge neu zu erzeugen, läßt MySQL
+während @code{INSERT .... SELECT} keine gleichzeitigen Einfügeoperationen
+zu.
+@end itemize
+
+Sie können natürlich @code{REPLACE} anstelle von @code{INSERT} benutzen, um
+alte Zeilen zu überschreiben.
+
+
+@node INSERT DELAYED, UPDATE, INSERT, Data Manipulation
+@c German node INSERT DELAYED
+@subsection @code{INSERT DELAYED}-Syntax
+
+@findex INSERT DELAYED
+@findex DELAYED
+
+@cindex INSERT DELAYED
+
+@example
+INSERT DELAYED ...
+@end example
+
+Die @code{DELAYED}-Option für das @code{INSERT}-Statement ist eine
+MySQL-spezifische Option, die sehr nützlich ist, wenn Sie Clients haben,
+die nicht warten können, bis das @code{INSERT} fertig ist. Die ist ein
+häufiges Problem, wenn Sie MySQL zum Loggen benutzen und gelegentlich
+@code{SELECT}- und @code{UPDATE}-Statements laufen lassen, die lange Zeit
+benötigen. @code{DELAYED} wurde in MySQL-Version 3.22.15 eingeführt. Es ist
+eine MySQL Erweiterung zu ANSI-SQL92.
+
+@code{INSERT DELAYED} funktioniert nur bei @code{ISAM}- und
+@code{MyISAM}-Tabellen. Beachten Sie: Weil @code{MyISAM}-Tabellen
+gleichzeitige @code{SELECT} und @code{INSERT} unterstützen, wenn es keine
+freien Blöcke mitten in der Daten-Datei gibt, müssen Sie @code{INSERT
+DELAYED} bei @code{MyISAM} nur sehr selten benutzen. @xref{MyISAM}.
+
+Wenn Sie @code{INSERT DELAYED} benutzen, erhält der Client sofort ein Okay,
+und die Zeile wird eingefügt, wenn die Tabelle nicht mehr durch einen
+anderen Thread in Benutzung ist.
+
+Ein weiterer großer Vorteil von @code{INSERT DELAYED} ist, dass
+Einfügeoperationen vieler Clients gebündelt und in einem Block geschrieben
+werden. Das ist viel schneller als viele separate Inserts durchzuführen.
+
+Beachten Sie, dass momentan die Zeilen in der Warteschlange solange nur im
+Arbeitsspeicher gehalten werden, bis sie in die Tabelle eingefügt sind. Das
+heißt, wenn Sie @code{mysqld} auf die harte Tour killen (@code{kill -9})
+oder wenn @code{mysqld} unerwartet stirbt, sind Zeilen in der
+Warteschlange, die noch nicht auf Festplatte geschrieben wurden, verloren!
+
+Im Folgenden ist detailliert beschrieben, was geschieht, wenn Sie die
+@code{DELAYED}-Option für @code{INSERT} oder @code{REPLACE} benutzen. In
+dieser Beschreibung ist der ``Thread'' der Thread, der einen @code{INSERT
+DELAYED}-Befehl empfängt. ``Handler'' ist der Thread, der alle @code{INSERT
+DELAYED}-Statements für ein bestimmte Tabelle handhabt.
+
+@itemize @bullet
+@item
+When ein Thread ein @code{DELAYED}-Statement für eine Tabelle ausführt,
+wird ein Handler-Thread erzeugt, um alle @code{DELAYED}-Statements für die
+Tabelle auszuführen, wenn ein solcher Handler nicht schon existiert.
+
+@item
+Der Thread prüft, ob der Handler bereit eine @code{DELAYED}-Sperre erhalten
+hat oder nicht. Wenn nicht, weist es den Handler-Thread an, das zu tun. Die
+@code{DELAYED}-Sperre kann selbst dann erlangt werden, wenn ein anderer
+Thread eine @code{READ}- oder @code{WRITE}-Sperre auf der Tabelle hat. Der
+Handler wartet jedoch auf alle @code{ALTER TABLE}-Sperren oder @code{FLUSH
+TABLES}, um sicherzustellen, dass die Tabellenstruktur aktuell ist.
+
+@item
+Der Thread führt das @code{INSERT}-Statement aus, aber statt die Zeile in
+die Tabelle zu schreiben stellt er eine Kopie der endgültigen Zeile in eine
+Warteschlange, die vom Handler-Thread verwaltet wird. Alle Syntaxfehler
+werden vom Thread erkannt und dem Client-Programm mitgeteilt.
+
+@item
+Der Client kann die Anzahl von Duplikaten oder den
+@code{AUTO_INCREMENT}-Wert für die resultierende Zeile nicht mitteilen. Er
+kann Sie vom Server nicht erhalten, weil das @code{INSERT} zurückkehrt,
+bevor die Einfügeoperation fertig ist. Wenn Sie die C-API benutzen, gibt
+die @code{mysql_info()}-Funktion aus demselben Grund nichts Sinnvolles
+zurück.
+
+@item
+Die Update-Log-Datei wird vom Handler-Thread aktualisiert, wenn die Zeile
+in die Tabelle eingefügt wird. Im Falle des Einfügens mehrerer Zeilen wird
+die Update-Log-Datei aktualisiert, wenn die erste Zeile eingefügt wird.
+
+@item
+Nachdem alle @code{delayed_insert_limit} Zeilen geschrieben wurden, prüft
+der Handler, ob noch irgend welche @code{SELECT}-Statements anhängig sind
+oder nicht. Falls ja, gestattet er diesen, ausgeführt zu werden, bevor
+weiter gemacht wird.
+
+@cindex delayed_insert_limit
+@cindex timeout
+@item
+Wenn der Handler keine Zeilen mehr in seiner Warteschlange hat, wird die
+Tabellensperre aufgehoben. Wenn innerhalb von @code{delayed_insert_timeout}
+Sekunden keine neuen @code{INSERT DELAYED}-Befehle mehr empfangen werden,
+beendet sich der Handler.
+
+@item
+Wenn mehr als @code{delayed_queue_size} Zeilen bereits in einer bestimmten
+Handler-Warteschlange anhängig sind, wartet der Thread, der nach
+@code{INSERT DELAYED} anfragt, bis es wieder Platz in der Warteschlange
+gibt. Damit wird sichergestellt, dass der @code{mysqld}-Server nicht den
+gesamten Arbeitsspeicher für die DELAYED-Warteschlange verbraucht.
+
+@item
+Der Handler-Thread zeigt sich in der MySQL-Prozessliste mit
+@code{delayed_insert} in der @code{Command}-Spalte. Er wird gekillt, wenn
+Sie einen @code{FLUSH TABLES}-Befehl ausführen oder ihn mit @code{KILL
+Thread_id} killen. Er wird jedoch zuerst alle Zeilen in der Warteschlange
+in die Tabelle schreiben, bevor er sich beendet. Während dieser Zeit
+akzeptiert er keine neuen @code{INSERT}-Befehle von anderen Threads mehr.
+Wenn Sie danach einen @code{INSERT DELAYED}-Befehl ausführen, wird ein
+neuer Handler-Thread erzeugt.
+
+@item
+Beachten Sie, dass oben Gesagtes bedeutet, dass @code{INSERT
+DELAYED}-Befehle höhere Priorität haben als normale @code{INSERT}-Befehle,
+wenn es einen @code{INSERT DELAYED}-Handler gibt, der bereits läuft!
+Andere Aktualisierungsbefehle müssen warten, bis die @code{INSERT
+DELAYED}-Warteschlange leer ist, jemand den Handler-Thread killt (mit
+@code{KILL Thread_id}) oder jemand @code{FLUSH TABLES} ausführt.
+
+@item
+Die folgenden Status-Variablen stellen Informationen über @code{INSERT
+DELAYED}-Befehle bereits:
+
+@multitable @columnfractions .35 .65
+@item @strong{Variable} @tab @strong{Bedeutung}
+@item @code{Delayed_insert_thread} @tab Nummer des Handler-Threads
+@item @code{Delayed_writes} @tab Anzahl der Zeilen, die mit @code{INSERT DELAYED} geschrieben wurden
+@item @code{Not_flushed_delayed_rows} @tab Anzahl der Zeilen, die darauf warten, geschrieben zu werden
+@end multitable
+
+Sie können diese Variablen betrachten, wenn Sie ein @code{SHOW
+STATUS}-Statement oder einen @code{mysqladmin extended-status}-Befehl
+ausführen.
+@end itemize
+
+Beachten Sie, dass @code{INSERT DELAYED} langsamer ist als ein normales
+INSERT, wenn die Tabelle nicht in Benutzung ist. Ausserdem gibt es einen
+zusätzlichen Overhead für den Server, um einen separaten Thread für jede
+Tabelle zu handhaben, für die Sie @code{INSERT DELAYED} benutzen. Das
+heißt, Sie sollten @code{INSERT DELAYED} nur benutzen, wenn Sie es
+wirklich benötigen!
+
+
+@node UPDATE, DELETE, INSERT DELAYED, Data Manipulation
+@c German node UPDATE
+@subsection @code{UPDATE}-Syntax
+
+@findex UPDATE
+
+@example
+UPDATE [LOW_PRIORITY] [IGNORE] tabelle
+ SET spalten_name1=ausdruck1, [spalten_name2=ausdruck2, ...]
+ [WHERE where_definition]
+ [LIMIT #]
+@end example
+
+@code{UPDATE} aktualisiert Spalten in bestehenden Tabellenzeilen mit neuen
+Werten. Die @code{SET}-Klausel gibt an, welche Spalten geändert werden
+sollen und welche Werte ihnen zugewiesen werden. Die @code{WHERE}-Klausel
+legt - falls angegeben - fest, welche Zeilen aktualisiert werden sollen.
+Ansonsten werden alle Zeile aktualisiert. Wenn die @code{ORDER BY}-Klausel
+angegeben ist, werden die Zeilen in der angegebenen Reihenfolge
+aktualisiert.
+
+Wenn Sie das Schlüsselwort @code{LOW_PRIORITY} angeben, wird die Ausführung
+von @code{UPDATE} verzögert, bis keine anderen Clients mehr aus der Tabelle
+lesen.
+
+Wenn Sie das Schlüsselwort @code{IGNORE} angeben, bricht das
+UPDATE-Statement nicht ab, selbst wenn während der Aktualisierung Fehler
+wegen doppelter Schlüsseleinträge auftreten. Zeilen, die Konflikte
+verursachen würden, werden nicht aktualisiert.
+
+Wenn Sie auf eine Spalte von @code{tabelle} in einem Ausdruck zugreifen,
+benutzt @code{UPDATE} den momentanen Wert der Spalte. Folgendes Statement
+zum Beispiel setzt die @code{age}-Spalte auf ihren momentanen Wert plus 1:
+
+@example
+mysql> UPDATE personen SET age=age+1;
+@end example
+
+@code{UPDATE}-Zuweisungen werden von links nach rechts ausgewertet.
+Folgendes Statement zum Beispiel verdoppelt die @code{age}-Spalte und
+inkrementiert sie danach:
+
+@example
+mysql> UPDATE personen SET age=age*2, age=age+1;
+@end example
+
+Wenn Sie eine Spalte auf einen Wert setzen, den sie momentan besitzt,
+erkennt MySQL dies und aktualisiert sie nicht.
+
+@findex mysql_info()
+@code{UPDATE} gibt die Anzahl von Zeilen zurück, die tatsächlich geändert
+wurden. Ab MySQL-Version 3.22 gibt die C-API-Funktion @code{mysql_info()}
+die Anzahl von Zeilen zurück, die übereinstimmten und aktualisiert wurden,
+und die Anzahl von Warnungen, die während @code{UPDATE} geschahen.
+
+In MySQL-Version 3.23 können Sie @code{LIMIT #} benutzen, um
+sicherzustellen, dass nur eine angegebene Anzahl von Zeilen geändert wird.
+
+
+@node DELETE, TRUNCATE, UPDATE, Data Manipulation
+@c German node DELETE
+@subsection @code{DELETE}-Syntax
+
+@findex DELETE
+
+@example
+DELETE [LOW_PRIORITY | QUICK] FROM tabelle
+ [WHERE where_definition]
+ [ORDER BY ...]
+ [LIMIT zeilen]
+
+oder
+
+DELETE [LOW_PRIORITY | QUICK] tabelle[.*] [tabelle[.*] ...] FROM
+tabellenverweis [WHERE where_definition]
+@end example
+
+@code{DELETE} löscht Zeilen aus @code{tabelle}, die mit der in
+@code{where_definition} angegebenen Bedingung übereinstimmen, und gibt die
+Anzahl der gelöschten Datensätze zurück.
+
+Wenn Sie @code{DELETE} ohne @code{WHERE}-Klausel angeben, werden alle
+Zeilen gelöscht. Wenn Sie das im @code{AUTOCOMMIT}-Modus machen,
+funktioniert es wie @code{TRUNCATE}. @xref{TRUNCATE}. In MySQL 3.23 gibt
+@code{DELETE} ohne eine @code{WHERE}-Klausel als Anzahl von betroffenen
+Datensätzen 0 zurück.
+
+Wenn Sie wissen wollen, wie viele Datensätze tatsächlich gelöscht wurden,
+wenn Sie alle Zeilen löschen, und eine Geschwindigkeitseinbusse in Kauf
+nehmen, können Sie ein @code{DELETE}-Statement folgender Form eingeben:
+
+@example
+mysql> DELETE FROM tabelle WHERE 1>0;
+@end example
+
+Beachten Sie, dass das VIEL langsamer als @code{DELETE FROM tabelle} ohne
+@code{WHERE}-Klausel ist, weil es Zeilen eine nach der anderen löscht.
+
+Wenn Sie das Schlüsselwort @code{LOW_PRIORITY} angeben, wird die Ausführung
+von @code{DELETE} verzögert, bis kein anderer Client mehr aus der Tabelle
+liest.
+
+Wenn Sie das Wort @code{QUICK} angeben, fasst der Tabellen-Handler während
+des Löschvorgangs keine Index-Blätter (Index Leafs) zusammen, was bestimmte
+Arten von Löschvorgängen beschleunigen kann.
+
+In MyISAM-Tabellen werden gelöschte Datensätze in einer verknüpften Liste
+verwaltet und nachfolgende @code{INSERT}-Operationen benutzen alte
+Datensatzpositionen neu. Um unbenutzten Platz freizugeben und Dateigrößen
+zu verringern, benutzen Sie das @code{OPTIMIZE TABLE}-Statement oder das
+@code{myisamchk}-Dienstprogramm, um die Tabellen neu zu organisieren.
+@code{OPTIMIZE TABLE} ist einfacher, aber @code{myisamchk} ist schneller.
+Siehe @ref{OPTIMIZE TABLE, , @code{OPTIMIZE TABLE}} und @ref{Optimisation}.
+
+Das Multi-Tabellen-Löschformat wird ab MySQL 4.0.0 unterstützt.
+
+Die Idee ist, dass nur übereinstimmende Zeilen aus den Tabellen, die VOR
+der @code{FROM}-Klausel stehen, gelöscht werden. Die Auswirkung ist, dass
+Sie Zeilen aus vielen Tabellen zugleich löschen können, sowie dass
+zusätzliche Tabellen zum Suchen benutzt werden.
+
+Das @code{.*}-Zeichen nach den Tabellennamen ist nur aus Gründen der
+Kompatibilität mit @code{Access} vorhanden:
+
+@example
+DELETE t1,t2 FROM t1,t2,t3 WHERE t1.id=t2.id AND t2.id=t3.id
+@end example
+
+In diesem Fall werden übereinstimmende Zeilen nur aus den Tabellen
+@code{t1} und @code{t2} gelöscht.
+
+@code{ORDER BY} und Benutzung mehrfacher Tabellen bei DELETE wird in MySQL
+4.0 unterstützt.
+
+Wenn eine @code{ORDER BY}-Klausel benutzt wird, werden die Zeilen in dieser
+Reihenfolge gelöscht. Das ist nur in Verbindung mit @code{LIMIT} wirklich
+sinnvoll. Beispiel:
+
+@example
+DELETE FROM logdatei
+WHERE user = 'jcole'
+ORDER BY zeitstempel
+LIMIT 1
+@end example
+
+Das löscht den ältesten Eintrag (von @code{zeitstempel}), wo die Zeile mit
+der @code{WHERE}-Klausel übereinstimmt.
+
+Die MySQL-spezifische @code{LIMIT rows}-Option für @code{DELETE} weist den
+Server an, welche maximale Anzahl von Zeilen gelöscht wird, bevor die
+Kontrolle an den Client zurück gegeben wird. Das kann benutzt werden um
+sicherzustellen, dass ein bestimmter @code{DELETE}-Befehl nicht zu viel
+Zeit beansprucht. Sie können den @code{DELETE}-Befehl einfach wiederholen,
+bis die Anzahl betroffener Zeilen kleiner ist als der @code{LIMIT}-Wert.
+
+
+@node TRUNCATE, REPLACE, DELETE, Data Manipulation
+@c German node TRUNCATE
+@subsection @code{TRUNCATE}-Syntax
+
+@findex TRUNCATE
+
+@example
+TRUNCATE TABLE tabelle
+@end example
+
+In Version 3.23 wird @code{TRUNCATE TABLE} auf @code{COMMIT ; DELETE FROM
+tabelle} gemappt. @xref{DELETE}.
+
+Die Unterschiede zwischen @code{TRUNCATE TABLE} und @code{DELETE FROM ..}
+sind:
+
+@itemize @bullet
+@item
+TRUNCATE führt ein Löschen und Neuerzeugen der Tabelle durch, was viel
+schneller sit, als Zeilen eine nach der anderen zu löschen.
+@item
+Nicht transaktionssicher. Sie erhalten einen Fehler, wenn Sie eine aktive
+Transaktion haben oder eine aktive Tabellensperre.
+@item
+Gibt die Anzahl gelöschter Zeilen nicht zurück.
+@item
+Solange die Tabellendefinitionsdatei @file{tabelle.frm} gültig ist, kann
+die Tabelle auf diese Weise neu erzeugt werden, selbst wenn die Daten- oder
+Index-Dateien beschädigt wurden.
+@end itemize
+
+@code{TRUNCATE} ist eine Oracle-SQL-Erweiterung.
+
+@node REPLACE, LOAD DATA, TRUNCATE, Data Manipulation
+@c German node REPLACE
+@subsection @code{REPLACE}-Syntax
+
+@findex REPLACE
+
+@example
+ REPLACE [LOW_PRIORITY | DELAYED]
+ [INTO] tabelle [(spalten_name,...)]
+ VALUES (ausdruck,...),(...),...
+or REPLACE [LOW_PRIORITY | DELAYED]
+ [INTO] tabelle [(spalten_name,...)]
+ SELECT ...
+or REPLACE [LOW_PRIORITY | DELAYED]
+ [INTO] tabelle
+ SET spalten_name=ausdruck, spalten_name=ausdruck,...
+@end example
+
+@code{REPLACE} funktioniert genau wie @code{INSERT}, ausser dass der alte
+Datensatz gelöscht wird, bevor ein neuer eingefügt wird, wenn ein alter
+Datensatz in der Tabelle denselben Wert wie der neue auf einem eindeutigen
+Index hat. @xref{INSERT, , @code{INSERT}}.
+
+Mit anderen Worten können Sie auf die Werte einer alten Zeile nicht mit
+einem @code{REPLACE}-Statement zugreifen. In einigen alten MySQL-Versionen
+sah es so aus, als könnten Sie das tun, aber das war ein Bug und wurde
+korrigiert.
+
+Wenn man einen @code{REPLACE}-Befehl benutzt, gibt
+@code{mysql_affected_rows()} 2 zurück, wenn die neue Zeile eine alte
+ersetzte. Das liegt daran, dass in diesem Fall eine Zeile eingefügt wurde
+und dann das Duplikat gelöscht wurde.
+
+Das macht es einfach zu überprüfen, ob @code{REPLACE} eine Zeile
+hinzugefügt oder eine ersetzt hat.
+
+
+@node LOAD DATA, , REPLACE, Data Manipulation
+@c German node LOAD DATA
+@subsection @code{LOAD DATA INFILE}-Syntax
+
+@findex LOAD DATA INFILE
+
+@example
+LOAD DATA [LOW_PRIORITY | CONCURRENT] [LOCAL] INFILE 'datei.txt'
+ [REPLACE | IGNORE]
+ INTO TABLE tabelle
+ [FIELDS
+ [TERMINATED BY '\t']
+ [[OPTIONALLY] ENCLOSED BY '']
+ [ESCAPED BY '\\' ]
+ ]
+ [LINES TERMINATED BY '\n']
+ [IGNORE Anzahl LINES]
+ [(spalten_name,...)]
+@end example
+
+Das @code{LOAD DATA INFILE}-Statement liest Zeilen aus einer Textdatei in
+eine Tabelle mit sehr hoher Geschwindigkeit. Wenn das
+@code{LOCAL}-Schlüsselwort angegeben wird, wird die Datei vom Client-Host
+gelesen. Wenn @code{LOCAL} nicht angegeben wird, muss die Datei auf dem
+Server liegen. (@code{LOCAL} ist verfügbar ab MySQL-Version 3.22.6.)
+
+Aus Sicherheitsgründen müssen Dateien, die als auf dem Server liegende
+Textdateien eingelesen werden, entweder im Datenbank-Verzeichnis liegen
+oder von allen lesbar sein. Darüber hinaus brauchen Sie, wenn Sie
+@code{LOAD DATA INFILE} mit Server-Dateien benutzen, die
+@strong{file}-Berechtigung auf dem Server-Host. @xref{Privileges}.
+
+Wenn Sie das Schlüsselwort @code{LOW_PRIORITY} angeben, wird das
+@code{LOAD DATA}-Statement verzögert, bis keine anderen Clients mehr aus
+der Tabelle lesen.
+
+Wenn Sie das Schlüsselwort @code{CONCURRENT} bei einer
+@code{MyISAM}-Tabelle angeben, können andere Threads Daten aus der Tabelle
+abrufen, während @code{LOAD DATA} ausgeführt wird. Die Benutzung dieser
+Option beeinflusst natürlich die Performance von @code{LOAD DATA} ein
+bisschen, selbst wenn kein anderer Thread die Tabelle zur gleichen Zeit
+benutzt.
+
+@code{LOCAL} ist etwas langsamer, als wenn der Server direkt auf die
+Dateien zugreifen kann, weil die Inhalte der Datei vom Client-Host auf den
+Server-Host übertragen werden müssen. Auf der anderen Seite benötigen Sie
+keine @strong{file}-Berechtigung, um lokale Dateien zu laden.
+
+@c old version
+Wenn Sie MySQL vor Version 3.23.24 benutzen, können Sie nicht aus einer
+FIFO lesen, wenn Sie @code{LOAD DATA INFILE} benutzen. Wenn Sie aus einer
+FIFO lesen müssen (zum Beispiel aus der Ausgabe von gunzip), benutzen Sie
+statt dessen @code{LOAD DATA LOCAL INFILE}.
+
+@cindex @code{mysqlimport}
+Sie können Daten-Dateien auch mit dem @code{mysqlimport}-Dienstprogramm
+laden; es arbeitet, indem es einen @code{LOAD DATA INFILE}-Befehl an den
+Server schickt. Die @code{--local}-Option veranlasst @code{mysqlimport},
+Daten-Dateien vom Client-Host zu lesen. Sie können die
+@code{--compress}-Option angeben, um bessere Performance über langsame
+Netzwerke zu erzielen, wenn der Client und der Server das komprimierte
+Protokoll unterstützen.
+
+Bei der Suche nach Dateien auf dem Server-Host geht der Server nach
+folgenden Regeln vor:
+
+@itemize @bullet
+@item
+Wenn ein absoluter Pfadname angegeben wird, benutzt der Server den
+Pfadnamen so, wie er ist.
+
+@item
+Wenn ein relativer Pfadname mit einer oder mehreren führenden Bestandteilen
+angegeben wird, sucht der Server die Datei relativ zum Daten-Verzeichnis
+des Servers.
+
+@item
+Wenn ein Dateiname ohne führende Bestandteile angegeben wird, sucht der
+Server die Datei im Datenbank-Verzeichnis der aktuellen Datenbank.
+@end itemize
+
+Beachten Sie, dass diese Regeln bedeuten, dass eine Datei, die als
+@file{./meinedatei.txt} angegeben wird, aus dem Daten-Verzeichnis des
+Servers gelesen wird, wohingegen eine Datei, die als @file{meinedatei.txt}
+angegeben wird, aus dem Datenbank-Verzeichnis der aktuellen Datenbank
+gelesen wird. Das folgende @code{LOAD DATA}-Statement beispielsweise liest
+die Datei @file{daten.txt} aus dem Datenbank-Verzeichnis von
+@code{datenbank1}, weil @code{datenbank1} die aktuelle Datenbank ist,
+obwohl das Statement die Datei explizit in eine Tabelle in der
+@code{datenbank2}-Datenbank lädt:
+
+@example
+mysql> USE datenbank1;
+mysql> LOAD DATA INFILE "daten.txt" INTO TABLE datenbank2.meine_tabelle;
+@end example
+
+Die @code{REPLACE}- und @code{IGNORE}-Schlüsselwörter steuern die
+Handhabung von Eingabe-Datensätzen, die bestehende Datensätze auf
+eindeutigen Schlüsselwerten duplizieren. Wenn Sie @code{REPLACE} angeben,
+ersetzen neue Zeilen bestehende Zeilen, die denselben eindeutigen
+Schlüsselwert besitzen. Wenn Sie @code{IGNORE} angeben, werden
+Eingabe-Zeilen, die eine bestehende Zeile auf einem Schlüsselwert
+duplizieren, übersprungen. Wenn Sie keine der beiden Optionen angeben,
+tritt ein Fehler auf, wenn ein doppelter Schlüsselwert gefunden wird, und
+der Rest der Textdatei wird ignoriert.
+
+Wenn Sie Daten aus einer lokalen Datei mit dem @code{LOCAL}-Schlüsselwort
+laden, hat der Server keine Möglichkeit, die Übertragung der Datei mitten
+in einer Operation zu beenden. Daher ist das vorgabemäßige Verhalten
+dasselbe, als wenn @code{IGNORE} angegeben wäre.
+
+Wenn Sie @code{LOAD DATA INFILE} auf einer leeren @code{MyISAM}-Tabelle
+benutzen, werden alle nicht eindeutigen Indexe in einem separaten Stapel
+erzeugt (wie bei @code{REPAIR}). Das macht @code{LOAD DATA INFILE}
+normalerweise viel schneller, wenn Sie viele Indexe haben.
+
+@code{LOAD DATA INFILE} ist das Komplement von @code{SELECT ... INTO OUTFILE}.
+@xref{SELECT, , @code{SELECT}}. Um Daten aus einer Datenbank in eine Datei
+zu schreiben, benutzen Sie @code{SELECT ... INTO OUTFILE}. Um die Datei
+zurück in die Datenbank zu lesen, benutzen Sie @code{LOAD DATA INFILE}. Die
+Syntax der @code{FIELDS}- und @code{LINES}-Klauseln ist für beide Befehle
+dieselbe. Beide Klauseln sind optional, aber @code{FIELDS} muss
+@code{LINES} vorangehen, wenn beide angegeben werden.
+
+Wenn Sie eine @code{FIELDS}-Klausel angeben, ist jede ihrer Unterklauseln
+(@code{TERMINATED BY}, @code{[OPTIONALLY] ENCLOSED BY} und @code{ESCAPED
+BY}) ebenfalls optional, ausser dass Sie zumindest eine von ihnen angeben
+müssen.
+
+Wenn Sie keine @code{FIELDS}-Klausel benutzen, sind die Vorgabewerte
+dieselben, als wenn Sie folgendes geschrieben hätten:
+
+@example
+FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\'
+@end example
+
+Wenn Sie keine @code{LINES}-Klausel angeben, sind die Vorgabewerte
+dieselben, als wenn Sie folgendes geschrieben hätten:
+
+@example
+LINES TERMINATED BY '\n'
+@end example
+
+Mit anderen Worten veranlassen die Vorgabewerte @code{LOAD DATA INFILE},
+beim Lesen von Eingaben wie folgt zu arbeiten:
+
+@itemize @bullet
+@item
+Zeilenbegrenzungen werden an Neue-Zeile-Zeichen gesucht (\n).
+
+@item
+Zeilen werden an Tabulatoren (\t) in Felder aufgeteilt.
+
+@item
+Es wird nicht davon ausgegangen, dass Felder in Anführungszeichen
+eingeschlossen sind.
+
+@item
+Tabulatoren, Neue-Zeile-Zeichen oder @samp{\}, denen ein @samp{\}-Zeichen
+voran gestellt ist, werden als Literale interpretiert, die Teil des
+Feldwerts sind.
+@end itemize
+
+Im Vergleich dazu veranlassen die Vorgabewerte von @code{SELECT ... INTO
+OUTFILE} dieses, wie folgt zu arbeiten:
+
+@itemize @bullet
+@item
+Zwischen Felder werden Tabulatoren (\t) geschrieben.
+
+@item
+Felder werden nicht in Anführungsstriche geschrieben.
+
+@item
+@samp{\} wird benutzt, um Tabulator, Neue-Zeile-Zeichen oder @samp{\}
+innerhalb von Feldwerten zu escapen.
+
+@item
+Am Ende von Zeilen werden Neue-Zeile-Zeichen (\n) geschrieben.
+@end itemize
+
+Beachten Sie, dass Sie @code{FIELDS ESCAPED BY '\\'} (mit zwei Backslashes)
+schreiben müssen, damit der Wert als ein einzelner Backslash gelesen wird.
+
+Die @code{IGNORE anzahl LINES}-Option kann benutzt werden, um eine
+Kopfzeile aus Spaltennamen am Anfang der Datei zu ignorieren:
+
+@example
+mysql> LOAD DATA INFILE "/tmp/datei.txt" into Tabelle test IGNORE 1 LINES;
+@end example
+
+Wenn Sie @code{SELECT ... INTO OUTFILE} zusammen mit @code{LOAD DATA
+INFILE} benutzen, um Daten aus einer Datenbank in eine Datei zu schreiben
+und dann die Datei später zurück in die Datenbank zu lesen, müssen die
+Optionen für die Behandlung von Feldern und Zeilen für beide Befehle
+übereinstimmen. Ansonsten interpretiert @code{LOAD DATA INFILE} die Inhalte
+der Datei nicht korrekt. Angenommen, Sie benutzen @code{SELECT ... INTO
+OUTFILE}, um eine Datei zu schreiben, deren Feldern durch Kommas begrenzt
+sind:
+
+@example
+mysql> SELECT * INTO OUTFILE 'daten.txt'
+ FIELDS TERMINATED BY ','
+ FROM ...;
+@end example
+
+Um die Komma-begrenzte Datei wieder einzulesen, lautet das korrekte
+Statement:
+
+@example
+mysql> LOAD DATA INFILE 'daten.txt' INTO TABLE tabelle2
+ FIELDS TERMINATED BY ',';
+@end example
+
+Wenn Sie statt dessen versuchen, die Datei mit dem unten stehenden
+Statement einzulesen, funktioniert das nicht, weil es @code{LOAD DATA
+INFILE} anweist, nach Tabulatoren zwischen Feldern zu suchen:
+
+@example
+mysql> LOAD DATA INFILE 'daten.txt' INTO TABLE tabelle2
+ FIELDS TERMINATED BY '\t';
+@end example
+
+Das wahrscheinliche Ergebnis ist, dass jede Eingabezeile als ein einzelnes
+Feld interpretiert wird.
+
+@code{LOAD DATA INFILE} kann auch benutzt werden, um Dateien aus externen
+Quellen einzulesen. Eine Datei im dBASE-Format zum Beispiel hat Felder, die
+durch Kommas getrennt und in Anführungszeichens eingeschlossen sind. Wenn
+Zeilen in der Datei von Neue-Zeile-Zeichen begrenzt sind, zeigt der unten
+stehende Befehl die Feld- und Zeilen-Handhabungsoptionen, die für das Laden
+der Datei benutzt werden:
+
+@example
+mysql> LOAD DATA INFILE 'daten.txt' INTO TABLE tabelle
+ FIELDS TERMINATED BY ',' ENCLOSED BY '"'
+ LINES TERMINATED BY '\n';
+@end example
+
+Jede der Feld- oder Zeilen-Handhabungsoptionen kann eine leere Zeichenkette
+angeben (@code{''}). Wenn nicht leer, müssen die @code{FIELDS [OPTIONALLY]
+ENCLOSED BY}- und @code{FIELDS ESCAPED BY}-Werte ein einzelnes Zeichen
+sein. Die @code{FIELDS TERMINATED BY}- und @code{LINES TERMINATED BY}-Werte
+können aus mehr als einem Zeichen bestehen. Um zum Beispiel Zeilen zu
+schreiben, die durch Wagenrücklauf-Neue-Zeile-Paare getrennt sind, oder um
+eine Datei einzulesen, die solche Zeilen enthält, geben Sie eine
+@code{LINES TERMINATED BY '\r\n'}-Klausel an.
+
+Um beispielsweise eine Datei mit Witzen einzulesen, die durch @code{%%}
+getrennt sind, können Sie folgendes eingeben:
+
+@example
+create table witze (a int not null auto_increment primary key, witz text not null);
+load data infile "/tmp/witze.txt" into table witze fields terminated by "" lines terminated by "\n%%\n" (witz);
+@end example
+
+@code{FIELDS [OPTIONALLY] ENCLOSED BY} steuert die Art von
+Anführungszeichen von Feldern. Wenn Sie bei der Ausgabe (@code{SELECT ...
+INTO OUTFILE}) das Wort @code{OPTIONALLY} auslassen, sind alle Felder vom
+@code{ENCLOSED BY}-Zeichen eingeschlossen. Ein Beispiel einer solchen
+Ausgabe (mit Kommas als Feldbegrenzern) ist unten dargestellt:
+
+@example
+"1","eine Zeichenkette","100.20"
+"2","eine Zeichenkette, die ein Komma (,) enthält","102.20"
+"3","eine Zeichenkette, die ein \" Anführungszeichen enthält","102.20"
+"4","eine Zeichenkette, die ein \", Anführungszeichen und Komma (,) enthält","102.20"
+@end example
+
+Wenn Sie @code{OPTIONALLY} angeben, wird das @code{ENCLOSED BY}-Zeichen nur
+benutzt, um @code{CHAR}- und @code{VARCHAR}-Felder zu umschließen:
+
+@example
+1,"eine Zeichenkette",100.20
+2,"eine Zeichenkette mit einem , Komma",102.20
+3,"eine Zeichenkette mit einem \" Anführungszeichen",102.20
+4,"eine Zeichenkette mit \", Anführungszeichen und Komma",102.20
+@end example
+
+Beachten Sie, dass @code{ENCLOSED BY}-Zeichen innerhalb eines Feldwerts
+escapet werden, indem ihnen das @code{ESCAPED BY}-Zeichen vorangestellt
+wird. Beachten Sie auch, dass es bei der Angabe eines leeren empty
+@code{ESCAPED BY}-Werts möglich ist, Ausgaben zu erzeugen, die nicht
+korrekt von @code{LOAD DATA INFILE} eingelesen werden können. Die oben
+dargestellte Ausgabe zum Beispiel würde wie im Folgenden gezeigt
+erscheinen, wenn das Fluchtzeichen (Escape-Zeichen) leer ist. Beachten Sie,
+dass das zweite Feld der vierten Zeile nach dem Anführungszeichen ein Komma
+enthält, was (irrtümlich) als Feldbegrenzer interpretiert wird:
+
+@example
+1,"eine Zeichenkette",100.20
+2,"eine Zeichenkette mit einem , Komma",102.20
+3,"eine Zeichenkette mit einem " Anführungszeichen",102.20
+4,"eine Zeichenkette mit ", Anführungszeichen und Komma",102.20
+@end example
+
+Für die Eingabe wird das @code{ENCLOSED BY}-Zeichen - falls vorhanden - vom
+Ende von Feldwerten entfernt. (Das gilt, egal ob @code{OPTIONALLY}
+angegeben ist oder nicht; @code{OPTIONALLY} hat keine Auswirkung auf die
+Interpretation der Eingabe.) @code{ENCLOSED BY}-Zeichen, denen das
+@code{ESCAPED BY}-Zeichen vorangestellt ist, werden als Teil des aktuellen
+Feldwerts interpretiert. Zusätzlich werden verdoppelte @code{ENCLOSED
+BY}-Zeichen innerhalb von Feldern als ein einzelnes @code{ENCLOSED
+BY}-Zeichen interpretiert, falls das Feld selbst mit diesem Zeichen
+anfängt. Wenn beispielsweise @code{ENCLOSED BY '"'} angegeben wird, werden
+Anführungszeichen wie folgt behandelt:
+
+@example
+"Der ""BIG"" Boss" -> Der "BIG" Boss
+Der "BIG" Boss -> Der "BIG" Boss
+Der ""BIG"" Boss -> Der ""BIG"" Boss
+@end example
+
+@code{FIELDS ESCAPED BY} steuert, wie Sonderzeichen geschrieben oder
+gelesen werden. Wenn das @code{FIELDS ESCAPED BY}-Zeichen nicht leer ist,
+wird es benutzt, um es bei der Ausgabe folgenden Zeichen voranzustellen:
+@itemize @bullet
+@item
+Dem @code{FIELDS ESCAPED BY}-Zeichen
+@item
+Dem @code{FIELDS [OPTIONALLY] ENCLOSED BY}-Zeichen
+@item
+Dem ersten Zeichen von @code{FIELDS TERMINATED BY}- und @code{LINES
+TERMINATED BY}-Werten
+@item
+ASCII @code{0} (was tatsächlich nach dem Fluchtzeichen (Escape-Zeichen)
+als ASCII @code{'0'} geschrieben wird, nicht ein Byte mit Wert 0)
+@end itemize
+
+Wenn das @code{FIELDS ESCAPED BY}-Zeichen leer ist, werden keine Zeichen
+escapet. Es ist wahrscheinlich keine gute Idee, ein leeres Fluchtzeichen
+(Escape-Zeichen) anzugeben, insbesondere, wenn Feldwerte in Ihren Daten
+irgend welche der Zeichen enthalten, die gerade aufgelistet wurden.
+
+Für die Eingabe werden, falls das @code{FIELDS ESCAPED BY}-Zeichen nicht
+leer ist, Vorkommen dieses Zeichens entfernt, und die folgenden Zeichen
+werden buchstäblich als Teil des Feldwerts genommen. Die Ausnahmen sind ein
+escapetes @samp{0} oder @samp{N} (beispielsweise @code{\0} oder @code{\N},
+wenn das Fluchtzeichen (Escape-Zeichen) @samp{\} ist). Diese Folgen werden
+als ASCII-@code{0} interpretiert (ein Byte mit Wert 0) und @code{NULL}.
+Siehe unten zu den Regeln der @code{NULL}-Handhabung.
+
+Weitere Informationen über die @samp{\}-Escape-Syntax finden Sie unter
+@ref{Literals}.
+
+In bestimmten Fällen beeinflussen sich die Handhabungsoptionen für Felder
+und Zeilen gegenseitig:
+
+@itemize @bullet
+@item
+Wenn @code{LINES TERMINATED BY} eine leere Zeichenkette ist und
+@code{FIELDS TERMINATED BY} nicht leer ist, werden Zeile auch durch
+@code{FIELDS TERMINATED BY} begrenzt.
+@item
+Wenn die @code{FIELDS TERMINATED BY}- und @code{FIELDS ENCLOSED BY}-Werte
+beide leer sind (@code{''}), wird ein Festzeilen- (nicht begrenztes) Format
+benutzt. Beim Festzeilenformat werden keine Begrenzer zwischen Feldern
+benutzt. Statt dessen werden Spaltenwerte geschrieben und gelesen, indem
+die Anzeigebreite der Spalten benutzt wird. Wenn eine Spalte zum Beispiel
+als @code{INT(7)} deklariert ist, werden Werte für die Spalte mit
+7-Zeichen-Feldern geschrieben. Bei der Eingabe werden Werte für die Spalte
+mit 7-Zeichen-Feldern bezogen. Festzeilenformate beeinflussen auch die
+Handhabung von @code{NULL}-Werten (siehe unten). Beachten Sie, dass
+Festgrößenformate nicht funktionieren, wenn Sie einen
+Multi-Byte-Zeichensatz benutzen.
+@end itemize
+
+Die Handhabung von @code{NULL}-Werten variiert in Abhängigkeit von den
+@code{FIELDS}- und @code{LINES}-Optionen, die Sie benutzen:
+
+@itemize @bullet
+@item
+Bei den vorgabemäßigen @code{FIELDS}- und @code{LINES}-Werten wird
+@code{NULL} für die Ausgabe als @code{\N} geschrieben und @code{\N} als
+@code{NULL} für die Eingabe gelesen (unter der Annahme, dass das
+@code{ESCAPED BY}-Zeichen @samp{\} ist).
+
+@item
+Wenn @code{FIELDS ENCLOSED BY} nicht leer ist, wird ein Feld, das das
+Literalwort @code{NULL} als seinen Wert enthält, als @code{NULL}-Wert
+gelesen (das weicht ab vom Wort @code{NULL}, begrenzt durch @code{FIELDS
+ENCLOSED BY}-Zeichen, was als die Zeichenkette @code{'NULL'} gelesen wird).
+
+@item
+Wenn @code{FIELDS ESCAPED BY} leer ist, wird @code{NULL} als das Wort
+@code{NULL} gelesen.
+
+@item
+Beim Festzeilenformat (was auftritt, wenn sowohl @code{FIELDS TERMINATED
+BY} als auch @code{FIELDS ENCLOSED BY} leer sind), wird @code{NULL} als
+leere Zeichenkette geschrieben. Beachten Sie, dass das dazu führt, dass
+@code{NULL}-Werte und leere Zeichenketten in der Tabelle nicht mehr
+unterscheidbar sind, wenn in die Datei geschrieben wird, weil sie beide als
+leere Zeichenketten geschrieben werden. Wenn Sie in der Lage sein müssen,
+diese zu unterscheiden, wenn Sie die Datei wieder einlesen, sollten Sie
+kein Festzeilenformat benutzen.
+@end itemize
+
+Einige Fälle werden von @code{LOAD DATA INFILE} nicht unterstützt:
+@itemize @bullet
+
+@item
+Festgrößenzeilen (@code{FIELDS TERMINATED BY} und @code{FIELDS ENCLOSED
+BY} sind beide leer) und @code{BLOB}- oder @code{TEXT}-Spalten.
+
+@item
+Wenn Sie ein Trennzeichen angeben, das dasselbe wie ein anderes ist oder
+einem anderen vorangestellt ist. @code{LOAD DATA INFILE} kann in diesem
+Fall die Eingabe nicht korrekt interpretieren. Folgende
+@code{FIELDS}-Klausel zum Beispiel würde Probleme bereiten:
+
+@example
+FIELDS TERMINATED BY '"' ENCLOSED BY '"'
+@end example
+
+@item
+Wenn @code{FIELDS ESCAPED BY} leer ist, führt ein Feldwert, der ein
+Vorkommen von @code{FIELDS ENCLOSED BY} oder @code{LINES TERMINATED BY}
+gefolgt vom @code{FIELDS TERMINATED BY}-Wert enthält, dazu, dass @code{LOAD
+DATA INFILE} mit dem Einlesen eines Feldes oder einer Zeile zu früh
+aufhört. Das passiert, weil @code{LOAD DATA INFILE} nicht korrekt festlegen
+kann, wo der Feld- oder Zeilenwert endet.
+@end itemize
+
+Das folgende Beispiel lädt alle Spalten der @code{personen}-Tabelle:
+
+@example
+mysql> LOAD DATA INFILE 'personen.txt' INTO TABLE personen;
+@end example
+
+Es ist keine Felderliste angegeben, daher erwartet @code{LOAD DATA INFILE},
+dass die Eingabefelder ein Feld für jede Tabellenspalte enthalten. Die
+Vorgabewerte für @code{FIELDS} und @code{LINES}-Werte werden benutzt.
+
+Wenn Sie Daten nur in einige Tabellenspalten einladen wollen, geben Sie
+eine Felderliste an:
+
+@example
+mysql> LOAD DATA INFILE 'personen.txt'
+ INTO TABLE personen (spalte1,spalte2,...);
+@end example
+
+Eine Felderliste müssen Sie ausserdem angeben, wenn die Reihenfolge der
+Felder in der Eingabedatei von der Reihenfolge der Tabellenspalten
+abweicht. Ansonsten kann MySQL nicht feststellen, wie er Eingabefelder
+Tabellenspalten zuordnen soll.
+
+Wenn eine Zeile zu wenige Felder hat, werden die Spalten, für die es kein
+Eingabefeld gibt, auf ihre Vorgabewerte gesetzt. Die Zuweisung von
+Vorgabewerten ist unter @ref{CREATE TABLE, , @code{CREATE TABLE}}
+beschrieben.
+
+Ein leerer Feldwert wird anders interpretiert als ein fehlender Feldwert:
+
+@itemize @bullet
+@item
+Bei Zeichenketten-Typen wird die Spalte auf die leere Zeichenkette gesetzt.
+
+@item
+Bei numerischen Typen wird die Spalte auf @code{0} gesetzt.
+
+@item
+Bei Datums- und Zeit-Typen wird die Spalte auf den entsprechenden
+``0''-Wert für den Typ gesetzt.
+@xref{Date and time types}.
+@end itemize
+
+Beachten Sie, dass das dieselben Werte sind, die sich ergeben, wenn Sie
+einer Zeichenkette explizit eine leere Zeichenkette zuweisen oder solches
+für einen DATE- oder TIME-Type in einem @code{INSERT}- oder
+@code{UPDATE}-Statement tun.
+
+@code{TIMESTAMP}-Spalten werden nur dann auf das aktuelle Datum und die
+aktuelle Zeit gesetzt, wenn es einen @code{NULL}-Wert für die Spalte gibt
+oder (nur für die erste @code{TIMESTAMP}-Spalte) die
+@code{TIMESTAMP}-Spalte in der Felderliste ausgelassen ist, wenn eine
+Felderliste angegeben wird.
+
+Wenn eine Eingabezeile zu viele Felder hat, werden die zusätzlichen Felder
+ignoriert und die Anzahl von Warnungen herauf gezählt.
+
+@code{LOAD DATA INFILE} betrachtet alle Eingaben als Zeichenketten, daher
+können Sie für @code{ENUM} oder @code{SET}-Spalten keine numerischen Werte
+benutzen, wie Sie das bei @code{INSERT}-Statements tun können. Alle
+@code{ENUM}- und @code{SET}-Werte müssen als Zeichenketten angegeben
+werden!
+
+@findex mysql_info()
+Wenn Sie die C-API benutzen, können Sie Informationen über die Anfrage
+durch den Aufruf der API-Funktion @code{mysql_info()} erhalten, wenn die
+@code{LOAD DATA INFILE}-Anfrage beendet ist. Das Format der
+Informationszeichenkette sieht wie folgt aus:
+
+@example
+Records: 1 Deleted: 0 Skipped: 0 Warnings: 0
+@end example
+
+Warnungen erfolgen unter denselben Umständen, als wenn Werte über das
+@code{INSERT}-Statement (@pxref{INSERT, , @code{INSERT}}) eingefügt werden,
+ausser dass @code{LOAD DATA INFILE} zusätzlich Warnungen erzeugt, wenn es
+zu wenige oder zu viele Felder in der Eingabezeile gibt. Die Warnungen
+werden nirgendwo gespeichert; die Anzahl von Warnungen kann daher nur als
+Anhaltspunkt dafür benutzt werden, ob alles gut ging. Wenn Sie Warnungen
+erhalten und genau wissen wollen, warum Sie diese erhalten, besteht eine
+Möglichkeit dafür darin, @code{SELECT ... INTO OUTFILE} in eine andere
+Datei zu benutzen und diese mit der Original-Eingabedatei zu vergleichen.
+
+Wenn Sie wollen, dass @code{LOAD DATA} aus einer Pipe liest, können Sie
+folgenden Trick benutzen:
+
+@example
+mkfifo /mysql/db/x/x
+chmod 666 /mysql/db/x/x
+cat < /dev/tcp/10.1.1.12/4711 > /nt/mysql/db/x/x
+mysql -e "LOAD DATA INFILE 'x' INTO TABLE x" x
+@end example
+
+Wenn Sie eine MySQL-Version vor 3.23.25 benutzen, können Sie das nur mit
+@code{LOAD DATA LOCAL INFILE} durchführen.
+
+Weitere Informationen über die Effizienz von @code{INSERT} versus
+@code{LOAD DATA INFILE} und Möglichkeiten, die Geschwindigkeit zu steigern,
+finden Sie unter @code{LOAD DATA INFILE}, @xref{Insert speed}.
+
+
+@node Data Definition, Basic User Commands, Data Manipulation, Reference
+@c German node Datendefinition
+@section Datendefinition: @code{CREATE}, @code{DROP}, @code{ALTER}
+
+
+
+@menu
+* CREATE DATABASE::
+* DROP DATABASE::
+* CREATE TABLE::
+* ALTER TABLE::
+* RENAME TABLE::
+* DROP TABLE::
+* CREATE INDEX::
+* DROP INDEX::
+@end menu
+
+@node CREATE DATABASE, DROP DATABASE, Data Definition, Data Definition
+@c German node CREATE DATABASE
+@subsection @code{CREATE DATABASE}-Syntax
+
+@findex CREATE DATABASE
+
+@example
+CREATE DATABASE [IF NOT EXISTS] datenbank
+@end example
+
+@c German FIX unwrapped @ref
+@code{CREATE DATABASE} erzeugt eine Datenbank mit dem angegebenen Namen.
+Die Regeln für erlaubte Datenbanknamen finden Sie unter @ref{Legal names}.
+Ein Fehler tritt auf, wenn die Datenbank bereits existiert und Sie
+@code{IF NOT EXISTS} nicht angeben.
+
+Datenbanken sind in MySQL als Verzeichnisse implementiert, die Dateien
+enthalten, die den Tabellen in der Datenbank entsprechen. Weil es keine
+Tabellen in einer Datenbank gibt, wenn diese erstmalig erzeugt wird,
+erzeugt das @code{CREATE DATABASE}-Statement nur ein Verzeichnis unter dem
+MySQL-Daten-Verzeichnis.
+
+@cindex @code{mysqladmin}
+Sie können auch mit @code{mysqladmin} Datenbanken erzeugen.
+@xref{Client-Side Scripts}.
+
+
+@node DROP DATABASE, CREATE TABLE, CREATE DATABASE, Data Definition
+@c German node DROP DATABASE
+@subsection @code{DROP DATABASE}-Syntax
+
+@findex DROP DATABASE
+
+@example
+DROP DATABASE [IF EXISTS] datenbank
+@end example
+
+@code{DROP DATABASE} löscht alle Tabellen in der Datenbank und löscht die
+Datenbank. Wenn Sie ein @code{DROP DATABASE} auf eine symbolisch verknüpfte
+Datenbank ausführen, werden sowohl der Link als auch die Original-Datenbank
+gelöscht. @strong{Seien Sie mit diesem Befehl sehr vorsichtig!}
+
+@code{DROP DATABASE} gibt die Anzahl von Dateien zurück, die aus dem
+Datenbank-Verzeichnis entfernt wurden. Normalerweise ist das dreimal die
+Anzahl der Tabellen, weil normalerweise jede Tabelle einer
+@file{.MYD}-Datei, einer @file{.MYI}-Datei und einer @file{.frm}-Datei
+entspricht.
+
+Der @code{DROP DATABASE}-Befehl entfernt aus dem angegebenen
+Datenbank-Verzeichnis alle Dateien mit folgenden Erweiterungen:
+
+@multitable @columnfractions .25 .25 .25 .25
+@item .BAK @tab .DAT @tab .HSH @tab .ISD
+@item .ISM @tab .ISM @tab .MRG @tab .MYD
+@item .MYI @tab .db @tab .frm
+@end multitable
+
+Alle Unterverzeichnisse, die aus 2 Ziffern bestehen
+(@code{RAID}-Verzeichnisse), werden ebenfalls gelöscht.
+
+Ab MySQL-Version 3.22 können Sie die Schlüsselwörter @code{IF EXISTS}
+benutzen, um eine Fehlermeldung zu vermeiden, die erscheint, wenn die
+Datenbank nicht existiert.
+
+@cindex @code{mysqladmin}
+Sie können Datenbanken auch mit @code{mysqladmin} löschen.
+@xref{Client-Side Scripts}.
+
+
+
+@node CREATE TABLE, ALTER TABLE, DROP DATABASE, Data Definition
+@c German node CREATE TABLE
+@subsection @code{CREATE TABLE}-Syntax
+
+@findex CREATE TABLE
+
+
+@example
+CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tabelle [(create_definition,...)]
+[tabellen_optionen] [select_statement]
+
+create_definition:
+ spalten_name typ [NOT NULL | NULL] [DEFAULT vorgabe_wert] [AUTO_INCREMENT]
+ [PRIMARY KEY] [referenz_definition]
+ oder PRIMARY KEY (index_spalten_name,...)
+ oder KEY [index_name] (index_spalten_name,...)
+ oder INDEX [index_name] (index_spalten_name,...)
+ oder UNIQUE [INDEX] [index_name] (index_spalten_name,...)
+ oder FULLTEXT [INDEX] [index_name] (index_spalten_name,...)
+ oder [CONSTRAINT symbol] FOREIGN KEY index_name (index_spalten_name,...)
+ [referenz_definition]
+ oder CHECK (ausdruck)
+
+typ:
+ TINYINT[(laenge)] [UNSIGNED] [ZEROFILL]
+ oder SMALLINT[(laenge)] [UNSIGNED] [ZEROFILL]
+ oder MEDIUMINT[(laenge)] [UNSIGNED] [ZEROFILL]
+ oder INT[(laenge)] [UNSIGNED] [ZEROFILL]
+ oder INTEGER[(laenge)] [UNSIGNED] [ZEROFILL]
+ oder BIGINT[(laenge)] [UNSIGNED] [ZEROFILL]
+ oder REAL[(laenge,dezimalstellen)] [UNSIGNED] [ZEROFILL]
+ oder DOUBLE[(laenge,dezimalstellen)] [UNSIGNED] [ZEROFILL]
+ oder FLOAT[(laenge,dezimalstellen)] [UNSIGNED] [ZEROFILL]
+ oder DECIMAL(laenge,dezimalstellen) [UNSIGNED] [ZEROFILL]
+ oder NUMERIC(laenge,dezimalstellen) [UNSIGNED] [ZEROFILL]
+ oder CHAR(laenge) [BINARY]
+ oder VARCHAR(laenge) [BINARY]
+ oder DATE
+ oder TIME
+ oder TIMESTAMP
+ oder DATETIME
+ oder TINYBLOB
+ oder BLOB
+ oder MEDIUMBLOB
+ oder LONGBLOB
+ oder TINYTEXT
+ oder TEXT
+ oder MEDIUMTEXT
+ oder LONGTEXT
+ oder ENUM(wert1,wert2,wert3,...)
+ oder SET(wert1,wert2,wert3,...)
+
+index_spalten_name:
+ spalten_name [(laenge)]
+
+referenz_definition:
+ REFERENCES tabelle [(index_spalten_name,...)]
+ [MATCH FULL | MATCH PARTIAL]
+ [ON DELETE referenz_option]
+ [ON UPDATE referenz_option]
+
+referenz_option:
+ RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT
+
+tabellen_optionen:
+ TYPE = @{BDB | HEAP | ISAM | InnoDB | MERGE | MRG_MYISAM | MYISAM @}
+or AUTO_INCREMENT = #
+or AVG_ROW_LENGTH = #
+or CHECKSUM = @{0 | 1@}
+or COMMENT = "string"
+or MAX_ROWS = #
+or MIN_ROWS = #
+or PACK_KEYS = @{0 | 1 | DEFAULT@}
+or PASSWORD = "string"
+or DELAY_KEY_WRITE = @{0 | 1@}
+or ROW_FORMAT= @{ default | dynamic | fixed | compressed @}
+or RAID_TYPE= @{1 | STRIPED | RAID0 @} RAID_CHUNKS=# RAID_CHUNKSIZE=#
+or UNION = (tabelle,[tabelle...])
+or INSERT_METHOD= @{NO | FIRST | LAST @}
+or DATA directory="verzeichnis"
+or INDEX directory="verzeichnis"
+
+select_statement:
+ [IGNORE | REPLACE] SELECT ... (jedes zulässige SELECT-Statement)
+@end example
+
+@code{CREATE TABLE} erzeugt eine Tabelle mit dem angegebenen Namen in der
+aktuellen Datenbank. Die Regeln für erlaubte Tabellennamen finden Sie unter
+@ref{Legal names}. Ein Fehler tritt auf, wenn es keine aktuelle
+Datenbank gibt oder wenn die Tabelle bereits existiert.
+
+Ab MySQL-Version 3.22 kann der Tabellenname als @code{datenbank.tabelle}
+angegeben werden. Das funktioniert unabhängig davon, ob es eine aktuelle
+Datenbank gibt oder nicht.
+
+In MySQL-Version 3.23 können Sie das @code{TEMPORARY}-Schlüsselwort
+benutzen, wenn Sie eine Tabelle erzeugen. Eine temporäre Tabelle wird
+automatisch gelöscht, wenn eine Verbindung stirbt und der Name sich auf die
+Verbindung bezieht. Das bedeutet, dass zwei verschiedene Verbindungen beide
+denselben temporären Tabellenname benutzen können, oder miteinander oder
+einer bestehenden Tabelle gleichen Namens in Konflikt zu geraten. (Die
+bestehende Tabelle ist versteckt, bis die temporäre Tabelle gelöscht wird.)
+
+Ab MySQL-Version 3.23 können Sie die Schlüsselwörter @code{IF NOT EXISTS}
+benutzen, so dass kein Fehler auftritt, wenn die Tabelle bereits besteht.
+Beachten Sie, dass keine Überprüfung erfolgt, dass die Tabellenstrukturen
+identisch sind.
+
+Jede Tabelle @code{tabelle} wird durch einige Dateien im
+Datenbank-Verzeichnis dargestellt. Im Falle von MyISAM-Tabellen erhalten
+Sie:
+
+@multitable @columnfractions .2 .8
+@item @strong{Datei} @tab @strong{Zweck}
+@item @code{tabelle.frm} @tab Tabellendefinitionsdatei (form)
+@item @code{tabelle.MYD} @tab Daten-Datei
+@item @code{tabelle.MYI} @tab Index-Datei
+@end multitable
+
+Weitere Information über die Eigenschaften der verschiedenen Spaltentypen
+finden Sie unter @ref{Column types}:
+
+@itemize @bullet
+@item
+Wenn weder @code{NULL} noch @code{NOT NULL} angegeben ist, wird die Spalte
+behandelt, als wenn @code{NULL} angegeben worden wäre.
+
+@item
+Eine Ganzzahl-Spalte kann das zusätzliche Attribut @code{AUTO_INCREMENT}
+haben. Wenn Sie einen Wert von @code{NULL} (empfohlen) oder @code{0} in
+eine @code{AUTO_INCREMENT}-Spalte einfügen, wird die Spalte auf
+@code{wert+1} gesetzt, wobei @code{wert} der größte momentan in der
+Tabelle vorhandene Spaltenwert ist. @code{AUTO_INCREMENT}-Folgen fangen mit
+@code{1} an. @xref{mysql_insert_id, , @code{mysql_insert_id()}}.
+
+Wenn Sie eine Zeile löschen, die den höchsten Wert einer
+@code{AUTO_INCREMENT}-Spalte enthält, wird der Wert bei einer @code{ISAM}-
+oder @code{BDB}-Tabelle wieder verwendet, nicht aber bei einer
+@code{MyISAM}- oder @code{InnoDB}-Tabelle. Wenn Sie alle Zeilen in der
+Tabelle mit @code{DELETE FROM tabelle} (ohne ein @code{WHERE}) im
+@code{AUTOCOMMIT}-Modus löschen, fängt die Folge bei allen Tabellentypen
+von Neuem an.
+
+@strong{HINWEIS:} Es darf nur eine @code{AUTO_INCREMENT}-Spalte pro Tabelle
+geben und diese muss indiziert sein. MySQL-Version 3.23 funktioniert
+darüber hinaus nur korrekt, wenn die @code{AUTO_INCREMENT}-Spalte nur
+positive Werte hat. Das Einfügen einer negativen Zahl wird als Einfügen
+einer sehr großen positiven Zahl betrachtet. Damit werden
+Genauigkeitsprobleme vermieden, wenn Zahlen vom positiven zum negativen
+Bereich übergehen. Ausserdem wird sichergestellt, dass man nicht
+versehentlich eine @code{AUTO_INCREMENT}-Spalte erhält, die 0 enthält.
+
+@cindex ODBC-Kompatibilität
+@cindex Kompatibilität, mit ODBC
+Um MySQL kompatibel mit einigen ODBC-Applikationen zu machen, können Sie
+die letzte eingefügte Zeile mit folgender Anfrage finden:
+
+@example
+SELECT * FROM tabelle WHERE auto_spalte IS NULL
+@end example
+
+@item
+@code{NULL}-Werte werden bei @code{TIMESTAMP}-Spalten anders als bei
+anderen Spaltentypen gehandhabt. Sie können @code{NULL} nicht wortgetreu in
+einer @code{TIMESTAMP}-Spalte speichern: Wenn Sie die Spalte auf
+@code{NULL} setzen, wird sie auf das aktuelle Datum und die aktuelle Zeit
+gesetzt. Weil @code{TIMESTAMP}-Spalten sich auf diese Art verhalten,
+treffen die @code{NULL}- und @code{NOT NULL}-Attribute nicht auf normale
+Art zu und werden ignoriert, wenn Sie sie angeben.
+
+Auf der anderen Seite berichtet der Server, um es für MySQL-Clients
+leichter zu machen, @code{TIMESTAMP}-Spalten zu benutzen, dass solchen
+Spalten @code{NULL}-Werte zugewiesen werden können (was stimmt), obwohl
+@code{TIMESTAMP} nie wirklich einen @code{NULL}-Wert enthalten wird. Sie
+können das sehen, wenn Sie @code{DESCRIBE tabelle} eingeben, um eine
+Beschreibung Ihrer Tabelle zu erhalten.
+
+Beachten Sie, dass das Setzen einer @code{TIMESTAMP}-Spalte auf @code{0}
+nicht dasselbe ist wie das Setzen auf @code{NULL}, weil @code{0} ein
+gültiger @code{TIMESTAMP}-Wert ist.
+
+@item
+Wenn kein @code{DEFAULT}-Wert für eine Spalte angegeben wird, weist MySQL
+automatisch einen zu.
+
+Wenn die Spalte @code{NULL} als Wert aufnehmen darf, ist der Vorgabewert
+@code{NULL}.
+
+Wenn die Spalte als @code{NOT NULL} deklariert ist, hängt der Vorgabewert
+vom Spaltentyp ab:
+
+@itemize @minus
+@item
+Bei numerischen Typen ausser denen, die mit dem
+@code{AUTO_INCREMENT}-Attribut deklariert wurden, ist der Vorgabewert
+@code{0}. Bei einer @code{AUTO_INCREMENT}-Spalte ist der Vorgabewert der
+nächste Wert in der Folge.
+
+@item
+Bei Datums- und Zeit-Typen ausser @code{TIMESTAMP} ist der Vorgabewert der
+entsprechende 0-Wert für den Typ. Bei der ersten @code{TIMESTAMP}-Spalte
+einer Tabelle ist der Vorgabewert das aktuelle Datum und die aktuelle Zeit.
+@xref{Date and time types}.
+
+@item
+Bei Zeichenketten-Typen ausser @code{ENUM} ist der Vorgabewert die leere
+Zeichenkette. Bei @code{ENUM} ist der Vorgabewert der erste
+Aufzählungswert.
+@end itemize
+
+Vorgabewerte müssen Konstanten sein. Das heißt zum Beispiel, dass Sie den
+Vorgabewert einer DATE-Spalte nicht als Wert einer Funktion wie
+@code{NOW()} oder @code{CURRENT_DATE} setzen können.
+
+@item
+@code{KEY} ist ein Synonym für @code{INDEX}.
+
+@item
+In MySQL darf ein @code{UNIQUE}-Schlüssel nur unterschiedliche Werte haben.
+Ein Fehler tritt auf, wenn Sie versuchen, eine neue Zeile hinzuzufügen, der
+Schlüsselwert dem einer bestehenden Zeile entspricht.
+
+@item
+@tindex PRIMARY KEY
+Ein @code{PRIMARY KEY} ist ein eindeutiger @code{KEY} mit der zusätzlichen
+Beschränkung, dass alle Schlüsselspalten als @code{NOT NULL} deklariert
+sein müssen. In MySQL wird der Schlüssel @code{PRIMARY} genannt. Eine
+Tabelle darf nur einen @code{PRIMARY KEY} haben. Wenn Sie keinen
+@code{PRIMARY KEY} haben und irgend welche Applikationen nach einem
+@code{PRIMARY KEY} in Ihrer Tabelle verlangen, gibt MySQL den ersten
+@code{UNIQUE}-Schlüssel, der keinerlei @code{NULL}-Spalten hat, als
+@code{PRIMARY KEY} zurück.
+
+@item
+Ein @code{PRIMARY KEY} kann ein mehrspaltiger Index sein. Sie können jedoch
+keinen mehrspaltiger Index mit dem @code{PRIMARY KEY}-Schlüsselattribut in
+einer Spaltenspezifikation erzeugen. Wenn Sie das tun, wird nur die erste
+Spalte als @code{PRIMARY} gekennzeichnet. Sie müssen die @code{PRIMARY
+KEY(index_spalten_name, ...)}-Syntax benutzen.
+
+@item
+Wenn der @code{PRIMARY}- oder @code{UNIQUE}-Schlüssel aus nur einer Spalte
+besteht und diese vom Typ Ganzzahl ist, können Sie auf sie auch als
+@code{_rowid} verweisen (neu ab Version 3.23.11).
+
+@item
+Wenn Sie einem Index keinen Namen zuweisen, wird dem Index derselbe Name
+zugewiesen wie der erste @code{index_spalten_name}, mit einem optionalen
+Suffix (@code{_2}, @code{_3}, @code{...}), um ihn eindeutig zu machen. Sie
+können die Indexnamen für eine Tabelle mit @code{SHOW INDEX FROM tabelle}
+anzeigen. @xref{SHOW, , @code{SHOW}}.
+
+@item
+@cindex @code{NULL}-Werte und Indexe
+@cindex Indexe und @code{NULL}-Werte
+Nur der @code{MyISAM}-Tabellentyp unterstützt Indexe auf Spalten, die
+@code{NULL}-Werte enthalten können. In anderen Fällen müssen Sie solche
+Spalten als @code{NOT NULL} deklarieren, sonst tritt ein Fehler auf.
+
+@item
+Mit der @code{spalten_name(laenge)}-Syntax können Sie einen Index
+festlegen, der nur einen Teil einer @code{CHAR}- oder @code{VARCHAR}-Spalte
+enthält. Das kann die Index-Datei viel kleiner machen.
+@xref{Indexes}.
+
+@item
+@cindex @code{BLOB}-Spalten, Indexierung
+@cindex Indexe und @code{BLOB}-Spalten
+@cindex @code{TEXT}-Spalten, Indexierung
+@cindex Indexe und @code{TEXT}-Spalten
+Nur der @code{MyISAM}-Tabellentyp unterstützt Indexierung auf @code{BLOB}-
+und @code{TEXT}-Spalten. Wenn Sie einen Index auf eine @code{BLOB}- oder
+@code{TEXT}-Spalte setzen, MÜSSEN Sie immer die Länge des Indexes angeben:
+@example
+CREATE TABLE test (blob_spalte BLOB, index(blob_spalte(10)));
+@end example
+
+@item
+Wenn Sie @code{ORDER BY} oder @code{GROUP BY} bei einer @code{TEXT}- oder
+@code{BLOB}-Spalte benutzen, werden nur die ersten @code{max_sort_length}
+Bytes benutzt. @xref{BLOB, , @code{BLOB}}.
+
+@item
+Ab MySQL-Version 3.23.23 können Sie auch spezielle @strong{FULLTEXT}-Indexe
+erzeugen, Diese werden für Volltextsuche benutzt. Nur der
+@code{MyISAM}-Tabellentyp unterstützt @code{FULLTEXT}-Indexe. Sie können
+auf @code{VARCHAR}- und @code{TEXT}-Spalten erzeugt werden. Die Indexierung
+erfolgt immer über die gesamte Spalte, teilweise Indexierung wird nicht
+unterstützt. Siehe @ref{Fulltext Search} für Details zur Funktionsweise.
+
+@item
+Die @code{FOREIGN KEY}-, @code{CHECK}- und @code{REFERENCES}-Klauseln tun
+momentan noch nichts. Die Syntax wird nur aus Gründen der Kompatibilität
+bereit gestellt, um das Portieren von Code von anderen SQL-Servern zu
+erleichtern und um Applikationen laufen zu lassen, die Tabellen mit
+Referenzen erzeugen.
+@c German FIX old ref was @xref{Fehlende Funktionen}.
+@xref{ANSI diff Foreign Keys}.
+
+@item
+Jede @code{NULL}-Spalte benötigt ein zusätzliches Bit, gerundet auf das
+nächste Byte.
+
+@item
+Die maximale Datensatzlänge in Bytes kann wie folgt berechnet werden:
+
+@example
+Zeilenlänge = 1
+ + (Summe Spaltenlängen)
+ + (Anzahl von NULL-Spalten + 7)/8
+ + (Anzahl von Spalten variabler Länge)
+@end example
+
+@item
+Die @code{tabellen_optionen}- und @code{SELECT}-Optionen sind implementiert
+ab MySQL-Version 3.23.
+
+Die unterschiedlichen Tabellentypen sind:
+
+@multitable @columnfractions .20 .80
+@item BDB oder Berkeley_db @tab Transaktionssichere Tabellen mit Seitensperren (Page Locking). @xref{BDB}.
+@item HEAP @tab Die Daten dieser Tabelle werden nur im Arbeitsspeicher gehalten. @xref{HEAP}.
+@item ISAM @tab Der Original-Tabellen-Handler. @xref{ISAM}.
+@item InnoDB @tab Transaktionssichere Tabellen mit Zeilensperren. @xref{InnoDB}.
+@item MERGE @tab Eine Sammlung von MyISAM-Tabellen, die als eine Tabelle benutzt werden. @xref{MERGE}.
+@item MRG_MERGE @tab Ein Alias für MERGE-Tabellen.
+@item MyISAM @tab Der neue binäre portable Tabellen-Handler, der ISAM ersetzt. @xref{MyISAM}.
+@end multitable
+@xref{Table types}.
+
+Wenn ein Tabellentyp angegeben wird und dieser besondere Typ nicht
+verfügbar ist, wählt MySQL den Tabellentyp, der dem angegebenen am nächsten
+kommt. Wenn beispielsweise @code{TYPE=BDB} angegeben wird und die
+Distribution von MySQL keine @code{BDB}-Tabellen unterstützt, wird die
+Tabelle statt dessen als @code{MyISAM} erzeugt.
+
+Die anderen Tabellenoptionen werden benutzt, um das Verhalten der Tabelle
+zu optimieren. In den meisten Fällen müssen Sie keine davon angeben. Die
+Optionen funktionieren bei allen Tabellentypen, falls nicht anders
+angegeben:
+
+@multitable @columnfractions .20 .80
+@item @code{AUTO_INCREMENT} @tab Der nächste auto_increment-Wert, den Sie für Ihre Tabelle setzen wollen (MyISAM).
+@item @code{AVG_ROW_LENGTH} @tab Näherungsweise die durchschnittliche Zeilenlänge Ihrer Tabelle. Diese Option müssen Sie nur für große Tabellen mit unterschiedlich großen Datensätzen setzen.
+@item @code{CHECKSUM} @tab Setzen Sie diesen Wert auf 1, wenn Sie wollen, dass MySQL eine Prüfsumme für alle Zeilen unterhält (macht die Tabelle ein bisschen langsamer bei der Aktualisierung, aber macht es einfacher, beschädigte Tabellen zu finden) (MyISAM).
+@item @code{COMMENT} @tab Ein 60-Zeichen-Kommentar für Ihre Tabelle.
+@item @code{MAX_ROWS} @tab Maximale Anzahl von Zeilen, die Sie in Ihrer Tabelle zu speichern planen.
+@item @code{MIN_ROWS} @tab Minimale Anzahl von Zeilen, die Sie in Ihrer Tabelle zu speichern planen.
+@item @code{PACK_KEYS} @tab Setzen Sie diesen Wert auf 1, wenn Sie einen kleineren Index erhalten wollen. Das macht Aktualisierungen üblicherweise langsamer und liest schneller (MyISAM, ISAM). Setzen auf 0 schaltet die Komprimierung von Schlüsseln ab. Setzen auf @code{DEFAULT} (MySQL 4.0) weist die Tabellen-Handler an, nur lange @code{CHAR}- / @code{VARCHAR}-Spalten zu packen.
+@item @code{PASSWORD} @tab Verschlüsselt die @code{.frm}-Datei mit einem Passwort. Diese Option tut nichts in der Standard-MySQL-Version.
+@item @code{DELAY_KEY_WRITE} @tab Setzen Sie diesen Wert auf 1, wenn Sie Schlüssel-Tabellen-Aktualisierungen verzögern wollen, bis die Tabelle geschlossen wird (MyISAM).
+@item @code{ROW_FORMAT} @tab Definiert, wie die Zeilen gespeichert werden sollen. Momentan funktioniert diese Option nur bei MyISAM-Tabellen, die die @code{DYNAMIC}- und @code{FIXED}-Zeilenformate unterstützen. @xref{MyISAM table formats}.
+@end multitable
+
+Wenn Sie eine @code{MyISAM}-Tabelle benutzen, verwendet MySQL das Produkt
+aus @code{max_rows * avg_row_length} um zu entscheiden, wie Groß die
+resultierende Tabelle sein wird. Wenn Sie keine der obigen Optionen
+angeben, ist die maximale Größe für eine Tabelle 4 GB (oder 2 GB, wenn Ihr
+Betriebssystem nur 2 GB-Tabellen unterstützt). Das geschieht, um
+Zeigergrößen gering zu halten und um den Index kleiner und schneller zu
+machen, wenn Sie nicht wirklich große Dateien benötigen.
+
+Wenn Sie @code{PACK_KEYS} nicht benutzen, ist die Vorgabe, nur
+Zeichenketten zu komprimieren, nicht Zahlen. Wenn Sie @code{PACK_KEYS=1}
+benutzen, werden auch Zahlen komprimiert.
+
+Wenn Sie binäre Zahlschlüssel komprimieren, benutzt MySQL die
+Präfix-Komprimierung. Das bedeutet, dass Sie nur dann einen Nutzen daraus
+ziehen, wenn Sie Zahlen haben, die sich oft wiederholen. Präfix-Kompression
+bedeutet, das jeder Schlüssel ein zusätzliches Byte benötigt, um
+darzustellen, wie viele Bytes des vorherigen Schlüssels für den nächsten
+Schlüssel dieselben sind (beachten Sie, dass der Zeiger auf die Zeile in
+der Reihenfolge 'hohes Byte zuerst' direkt nach dem Schlüssel gespeichert
+wird, um die Kompression zu verbessern). Das heißt, wenn Sie viele gleiche
+Schlüssel auf zwei Zeilen hintereinander haben, werden alle folgenden
+'gleichen' Schlüssel üblicherweise nur 2 Bytes in Anspruch nehmen
+(inklusive dem Zeiger auf die Zeile). Vergleichen Sie das mit dem
+Normalfall, bei dem die folgenden Schlüssel speicher_platz_fuer_schlüssel +
+zeiger_groesse beanspruchen (üblicherweise 4). Auf der anderen Seite
+verlieren Sie 1 Byte pro Schlüssel, wenn alle Schlüssel völlig
+unterschiedlich sind, falls der Schlüssel kein Schlüssel ist, der
+@code{NULL}-Werte haben kann (in diesem Fall wird die komprimierte
+Schlüssellänge, die im selben Byte gespeichert ist, benutzt, um zu
+kennzeichnen, ob ein Schlüssel @code{NULL} ist).
+
+@item
+Wenn Sie ein @code{SELECT} nach dem @code{CREATE}-Statement angeben,
+erzeugt MySQL neue Felder für alle Elemente im @code{SELECT}. Beispiel:
+
+@example
+mysql> CREATE TABLE test (a int not null auto_increment,
+ primary key (a), key(b))
+ TYPE=MyISAM SELECT b,c from test2;
+@end example
+
+Das erzeugt eine @code{MyISAM}-Tabelle mit drei Spalten a, b und c.
+Beachten Sie, dass die Spalten des @code{SELECT}-Statements an die rechte
+Seite der Tabelle angehängt werden, nicht überlappend. Nehmen wir folgendes
+Beispiel:
+
+@example
+mysql> select * from foo;
++---+
+| n |
++---+
+| 1 |
++---+
+
+mysql> create table bar (m int) select n from foo;
+Query OK, 1 row affected (0.02 sec)
+Records: 1 Duplicates: 0 Warnings: 0
+
+mysql> select * from bar;
++------+---+
+| m | n |
++------+---+
+| NULL | 1 |
++------+---+
+1 row in set (0.00 sec)
+@end example
+
+Für jede Zeile in Tabelle @code{foo} wird eine Zeile in @code{bar} mit den
+Werten von @code{foo} und Vorgabewerten für die neuen Spalten eingefügt.
+
+@code{CREATE TABLE ... SELECT} erzeugt nicht automatisch irgend welche
+Indexe. Das wird absichtlich gemacht, um den Befehl so flexibel wie möglich
+zu machen. Wenn Sie Indexe in der erzeugten Tabelle haben wollen, geben Sie
+diese vor dem @code{SELECT}-Statement an:
+
+@example
+mysql> create table bar (unique (n)) select n von foo;
+@end example
+
+Wenn Fehler beim Kopieren der Daten in die Tabelle auftreten, wird diese
+automatisch gelöscht.
+
+Um sicherzustellen, dass die Update-Log-Datei/Binär-Log-Datei benutzt
+werden kann, um die Original-Tabellen neu zu erzeugen, läßt MySQL keine
+gleichzeitigen Einfügeoperationen während @code{CREATE TABLE .... SELECT}
+zu.
+@item
+Die @code{RAID_TYPE}-Option hilft, die 2 GB- / 4 GB-Grenze für die
+MyISAM-Daten-Datei zu durchbrechen (nicht für die Index-Datei), auf
+Betriebssystemen, die keine großen Dateien unterstützen.
+Sie erzielen mehr Geschwindigkeit vom I/O-Flaschenhals, wenn Sie die
+@code{RAID}-Verzeichnisse auf unterschiedliche physikalische Platten legen.
+@code{RAID_TYPE} funktioniert auf jedem Betriebssystem, solange Sie MySQL
+mit @code{--with-raid} konfiguriert haben. Momentan ist der einzige
+zulässige @code{RAID_TYPE} @code{STRIPED} (@code{1} und @code{RAID0} sind
+Aliase dafür).
+
+Wenn Sie @code{RAID_TYPE=STRIPED} bei einer @code{MyISAM}-Tabelle angeben,
+erzeugt @code{MyISAM} @code{RAID_CHUNKS}-Unterverzeichnisse namens 00, 01,
+02 im Datenbank-Verzeichnis. In jedem dieser Verzeichnisse erzeugt
+@code{MyISAM} eine @code{tabelle.MYD}. Wenn Sie Daten in die Daten-Datei
+schreiben, mappt der @code{RAID}-Handler die ersten @code{RAID_CHUNKSIZE} *
+1024 Bytes auf die erste Datei, die nächsten @code{RAID_CHUNKSIZE} * 1024
+Bytes auf die nächste Datei usw.
+
+@item
+@code{UNION} wird benutzt, wenn Sie eine Sammlung identischer Tabelle als
+eine benutzen wollen. Das funktioniert nur bei MERGE-Tabellen. @xref{MERGE}.
+
+Momentan benötigen Sie @code{SELECT}-, @code{UPDATE}-
+und-@code{DELETE}-Berechtigungen auf die Tabellen, die Sie auf eine
+@code{MERGE}-Tabelle mappen. Alle gemappten Tabellen müssen sich in
+derselben Datenbank wie die @code{MERGE}-Tabelle befinden.
+
+@item
+Wenn Sie Daten in eine @code{MERGE}-Tabelle einfügen wollen, müssen Sie mit
+@code{INSERT_METHOD} angeben, in welche Tabelle die Zeile eingefügt werden
+soll. @xref{MERGE}.
+
+@item
+In der erzeugten Tabelle wird der @code{PRIMARY}-Schlüssel zuerst
+platziert, gefolgt von allen @code{UNIQUE}-Schlüsseln und danach von den
+normalen Schlüsseln. Das hilft dem MySQL-Optimierer zu priorisieren,
+welcher Schlüssel benutzt werden soll, und auch, Duplikate von
+@code{UNIQUE}-Schlüsseln zu entdecken.
+
+@item
+Wenn Sie @code{DATA directory="verzeichnis"} oder @code{INDEX
+directory="verzeichnis"} benutzen, können Sie angeben, wohin die
+Tabellen-Handler ihre Tabellen- und Index-Dateien legen sollen. Das
+funktioniert nur bei @code{MyISAM}-Tabellen in @code{MySQL} 4.0, wenn Sie
+die @code{--skip-symlink}-Option nicht benutzen. @xref{Symbolic links to tables}.
+
+@end itemize
+
+
+@menu
+* Silent column changes::
+@end menu
+
+@node Silent column changes, , CREATE TABLE, CREATE TABLE
+@c German node Stille Spaltentyp-Änderungen
+@subsubsection Stille Spaltentyp-Änderungen
+
+@cindex Stille Spaltentyp-Änderungen
+
+In einigen Fällen ändert MySQL lautlos eine Spaltenspezifikation von der,
+die in einem @code{CREATE TABLE}-Statement angegeben wurde. (Das kann auch
+bei @code{ALTER TABLE} passieren.):
+
+@itemize @bullet
+@item
+@code{VARCHAR}-Spalten mit einer Länge kleiner 4 werden in @code{CHAR}
+geändert.
+
+@item
+Wenn irgend eine Spalte in einer Tabelle eine variable Länge hat, hat im
+Ergebnis jede Zeile eine variable Länge. Wenn daher eine Tabelle irgend
+welche Spalten variabler Länge enthält (@code{VARCHAR}, @code{TEXT} oder
+@code{BLOB}), werden alle @code{CHAR}-Spalten, die länger als drei Zeichen
+sind, in @code{VARCHAR}-Spalten umgewandelt. Das beeinflusst die Benutzung
+dieser Spalten in keiner Weise, denn in MySQL ist @code{VARCHAR} nur eine
+andere Art, Zeichen zu speichern. MySQL führt diese Umwandlung durch, weil
+sie Platz spart und Tabellenoperationen schneller macht.
+@xref{Table types}.
+
+@item
+@code{TIMESTAMP}-Anzeigebreiten müssen geradzahlig und im Bereich von 2 bis
+14 sein. Wenn Sie eine Anzeigebreite von 0 oder größer als 14 angeben,
+wird die Größe auf 14 gesetzt. Ungerade Werte im Bereich von 1 bis 13
+werden auf den nächst höheren geraden Wert gesetzt.
+
+@item
+Sie können keinen echten @code{NULL}-Wert in einer @code{TIMESTAMP}-Spalte
+speichern. Wenn Sie sie auf @code{NULL} setzen, wird sie auf das aktuelle
+Datum und die aktuelle Zeit gesetzt. Weil sich @code{TIMESTAMP}-Spalten so
+verhalten, treffen die Attribute @code{NULL} und @code{NOT NULL} nicht auf
+normale Weise zu und werden ignoriert, wenn Sie sie angeben. @code{DESCRIBE
+tabelle} zeigt dagegen immer an, dass einer @code{TIMESTAMP}-Spalte
+@code{NULL}-Werte zugewiesen werden können.
+
+@item
+MySQL mappt bestimmte Spaltentypen, die von anderen
+SQL-Datenbank-Herstellern benutzt werden, auf MySQL-Typen.
+@xref{Other-vendor column types}.
+@end itemize
+
+Wenn Sie sehen wollen, ob MySQL einen anderen Spaltentyp als den, den Sie
+angegeben haben, benutzt hat, geben Sie nach dem Erzeugen oder Ändern Ihrer
+Tabelle ein @code{DESCRIBE tabelle}-Statement ein.
+
+@cindex @code{myisampack}
+Bestimmte andere Spaltentyp-Änderungen können auftreten, wenn Sie eine
+Tabelle mit @code{myisampack} komprimieren. @xref{Compressed format}.
+
+
+@node ALTER TABLE, RENAME TABLE, CREATE TABLE, Data Definition
+@c German node ALTER TABLE
+@subsection @code{ALTER TABLE}-Syntax
+
+@findex ALTER TABLE
+
+@example
+ALTER [IGNORE] TABLE tabelle aenderungs_angabe [, aenderungs_angabe ...]
+
+aenderungs_angabe:
+ ADD [COLUMN] create_definition [FIRST | AFTER spalten_name]
+ oder ADD [COLUMN] (create_definition, create_definition,...)
+ oder ADD INDEX [index_name] (index_spalten_name,...)
+ oder ADD PRIMARY KEY (index_spalten_name,...)
+ oder ADD UNIQUE [index_name] (index_spalten_name,...)
+ oder ADD FULLTEXT [index_name] (index_spalten_name,...)
+ or ADD [CONSTRAINT symbol] FOREIGN KEY index_name (index_spalten_name,...)
+ [referenz_definition]
+ oder ALTER [COLUMN] spalten_name @{SET DEFAULT literal | DROP DEFAULT@}
+ oder CHANGE [COLUMN] alter_spalten_name create_definition
+ oder MODIFY [COLUMN] create_definition
+ oder DROP [COLUMN] spalten_name
+ oder DROP PRIMARY KEY
+ oder DROP INDEX index_name
+ oder DISABLE KEYS
+ oder ENABLE KEYS
+ oder RENAME [TO] neue_tabelle
+ oder ORDER BY spalte
+ oder tabellen_optionen
+@end example
+
+Mit @code{ALTER TABLE} können Sie die Struktur einer bestehenden Tabelle
+ändern. Sie können beispielsweise Spalten hinzufügen oder löschen, Indexe
+erzeugen oder löschen, den Typ bestehender Spalten ändern oder Spalten oder
+die Tabelle selbst umbenennen. Sie können auch den Kommentar für die
+Tabelle und den Typ der Tabelle ändern. @xref{CREATE TABLE, , @code{CREATE TABLE}}.
+
+Wenn Sie @code{ALTER TABLE} benutzen, um eine Spaltenspezifikation zu
+ändern, und @code{DESCRIBE tabelle} anzeigt, dass die Spalte nicht geändert
+wurde, ist es möglich, dass MySQL Ihre Änderungen aus einem der Gründe
+ignoriert hat, die in @ref{Silent column changes} beschrieben sind.
+Wenn Sie beispielsweise versuchen, eine @code{VARCHAR}-Spalte zu
+@code{CHAR} zu ändern, benutzt MySQL dennoch @code{VARCHAR}, wenn die
+Tabelle weitere Spalten variabler Länge enthält.
+
+@code{ALTER TABLE} funktioniert mittels Anlegen einer temporären Kopie der
+Original-Tabelle. Die Änderungen werden an der Kopie durchgeführt, dann
+wird die Original-Tabelle gelöscht und die neue umbenannt. Das wird so
+durchgeführt, dass alle Aktualisierungen automatisch ohne irgend welche
+fehlgeschlagenen Aktualisierungen an die neue Tabelle weitergeleitet
+werden. Während @code{ALTER TABLE} ausgeführt wird, ist die alte Tabelle
+durch andere Clients lesbar. Aktualisierungen und Schreibvorgänge in die
+Tabelle werden angehalten, bis die neue Tabelle bereit ist.
+
+Beachten Sie, dass MySQL immer eine temporäre Tabelle anlegt, wenn Sie für
+@code{ALTER TABLE} irgend eine Option ausser @code{RENAME} angeben, selbst
+wenn die Daten eigentlich nicht kopiert werden müssten (zum Beispiel, wenn
+Sie einen Spaltennamen ändern). Wir planen, dass zu beheben, aber da man
+@code{ALTER TABLE} normalerweise nicht ausführen muss, ist das auf unserer
+TODO-Liste nicht sehr hoch angesetzt.
+
+@itemize @bullet
+@item
+Um @code{ALTER TABLE} ausführen zu können, benötigen Sie @strong{ALTER}-,
+@strong{INSERT}- und @strong{CREATE}-Berechtigungen für die Tabelle.
+
+@item
+@code{IGNORE} ist eine MySQL-Erweiterung zu ANSI-SQL92. Es steuert, wie
+@code{ALTER TABLE} funktioniert, wenn es in der neuen Tabelle Duplikate auf
+eindeutigen Schlüsseln gibt. Wenn @code{IGNORE} nicht angegeben wird, wird
+das Kopieren abgebrochen und zurückgesetzt. Wenn @code{IGNORE} angegeben
+wird, wird bei Zeilen mit Duplikaten auf einem eindeutigen Schlüssel nur
+die erste Zeile benutzt, die anderen werden gelöscht.
+
+@item
+Sie können mehrfache @code{ADD}-, @code{ALTER}-, @code{DROP}- und
+@code{CHANGE}-Klauseln in einem einzigen @code{ALTER TABLE}-Statement
+angeben. Das ist eine MySQL-Erweiterung zu ANSI-SQL92, welches nur eine
+Klausel pro @code{ALTER TABLE}-Statement zuläßt.
+
+@item
+@code{CHANGE spalten_name}, @code{DROP spalten_name} und @code{DROP INDEX}
+sind MySQL-Erweiterungen zu ANSI-SQL92.
+
+@item
+@code{MODIFY} ist eine Oracle-Erweiterung zu @code{ALTER TABLE}.
+
+@item
+Das optionale Wort @code{COLUMN} kann weggelassen werden.
+
+@item
+Wenn Sie @code{ALTER TABLE tabelle RENAME TO neuer_name} ohne weitere
+Optionen benutzen, benennt MySQL einfach die Dateien um, die der Tabelle
+@code{tabelle} entsprechen. Es besteht keine Notwendigkeit, die temporäre
+Tabelle zu erzeugen. @xref{RENAME TABLE,, @code{RENAME TABLE}}.
+
+@item
+Ab @strong{MySQL 4.0} kann das obige Feature explizit aktiviert werden.
+@code{ALTER TABLE ... DISABLE KEYS} veranlasst MySQL, mit dem Aktualisieren
+nicht eindeutiger Indexe für die @code{MyISAM}-Tabelle aufzuhören. Dann
+sollte @code{ALTER TABLE ... ENABLE KEYS} benutzt werden, um fehlende
+Indexe wieder zu erzeugen. Weil MySQL das mit Algorithmen durchführt, die
+viel schneller sind als das Einfügen von Schlüsseln nacheinander, kann das
+Abschalten von Schlüsseln bei Masseneinfügeoperationen erheblich
+Geschwindigkeitsvorteile bringen.
+
+@item
+@code{create_definition}-Klauseln benutzen dieselbe Syntax für @code{ADD}
+und @code{CHANGE} wie bei @code{CREATE TABLE}. Beachten Sie, dass diese
+Syntax den Spaltenname beinhaltet, nicht nur den Spaltentyp.
+@c German FIX unsplit @xref
+@xref{CREATE TABLE, , @code{CREATE TABLE}}.
+
+@item
+Sie können eine Spalte mit einer @code{CHANGE alter_spalten_name
+create_definition}-Klausel umbenennen. Um das zu tun, geben Sie den alten
+und den neuen Spaltennamen und den Typ an, den die Spalte momentan hat. Um
+beispielsweise eine @code{INTEGER}-Spalte von @code{a} nach @code{b}
+umzubenennen, tun Sie folgendes:
+
+@example
+mysql> ALTER TABLE t1 CHANGE a b INTEGER;
+@end example
+
+Wenn Sie einen Spaltentyp, nicht aber den Namen ändern wollen, benötigt
+@code{CHANGE} dennoch zwei Spaltennamen, selbst wenn sie dieselben sind.
+Beispiel:
+
+@example
+mysql> ALTER TABLE t1 CHANGE b b BIGINT NOT NULL;
+@end example
+
+Ab MySQL-Version 3.22.16a können Sie jedoch auch @code{MODIFY} benutzen, um
+einen Spaltentyp ohne Umbenennung zu ändern:
+
+@example
+mysql> ALTER TABLE t1 MODIFY b BIGINT NOT NULL;
+@end example
+
+@item
+Wenn Sie @code{CHANGE} oder @code{MODIFY} benutzen, um eine Spalte zu
+kürzen, für die es einen Index auf einem Teil der Spalte gibt (wenn Sie zum
+Beispiel einen Index auf den ersten 10 Zeichen einer @code{VARCHAR}-Spalte
+haben), können Sie die Spalte nicht kürzer als die Anzahl von Zeichen
+machen, die indiziert sind.
+
+@item
+Wenn Sie versuchen, einen Spaltentyp mit @code{CHANGE} oder @code{MODIFY}
+zu ändern, versucht MySQL, Daten so umzuwandeln, dass sie so gut wie
+möglich zum neuen Typ passen.
+
+@item
+AB MySQL-Version 3.22 können Sie @code{FIRST} oder @code{ADD ... AFTER
+spalten_name} benutzen, um eine Spalte an einer bestimmten Position
+innerhalb einer Tabellenzeile einzufügen. Vorgabemäßig wird die Spalte am
+Ende hinzugefügt.
+
+@findex ALTER COLUMN
+@item
+@code{ALTER COLUMN} gibt einen Vorgabewert für eine Spalte an oder entfernt
+den alten Vorgabewert. Wenn der alte Vorgabewert entfernt wird und die
+Spalte @code{NULL} sein darf, ist der neue Vorgabewert @code{NULL}. Wenn
+die Spalte nicht @code{NULL} sein darf, weist MySQL einen Vorgabewert zu,
+wie in @ref{CREATE TABLE, , @code{CREATE TABLE}} beschrieben.
+
+@findex DROP INDEX
+@item
+@code{DROP INDEX} entfernt einen Index. Das ist eine MySQL-Erweiterung zu
+ANSI-SQL92. @xref{DROP INDEX}.
+
+@item
+Wenn Spalten aus einer Tabelle gelöscht werden, werden sie auch aus
+jeglichen Indexen entfernt, deren Teil sie sind. Wenn alle Spalten, aus
+denen ein Index besteht, gelöscht werden, wird der Index ebenfalls
+gelöscht.
+
+@item
+Wenn eine Tabelle nur eine Spalte enthält, kann die Spalte nicht gelöscht
+werden. Wenn Sie beabsichtigen, die Tabelle zu entfernen, benutzen Sie
+statt dessen @code{DROP TABLE}.
+
+@findex DROP PRIMARY KEY
+@item
+@code{DROP PRIMARY KEY} löscht den Primärschlüssel. Wenn es keinen solchen
+gibt, löscht es den ersten @code{UNIQUE}-Index in der Tabelle. (MySQL
+kennzeichnet den ersten @code{UNIQUE}-Schlüssel als @code{PRIMARY KEY},
+wenn @code{PRIMARY KEY} nicht explizit angegeben wurde.)
+
+@findex UNIQUE
+@findex PRIMARY KEY
+Wenn Sie einen @code{UNIQUE INDEX} oder @code{PRIMARY KEY} zu einer Tabelle
+hinzufügen, wird dieser vor jedem Nicht-@code{UNIQUE}-Index gespeichert, so
+dass MySQL doppelte Schlüsseleinträge so früh wie möglich feststellen kann.
+
+@findex ORDER BY
+@item
+@code{ORDER BY} gestattet Ihnen, eine Tabelle mit Zeilen in einer
+bestimmten Reihenfolge zu erzeugen. Beachten Sie, dass die Tabelle nach
+INSERTs und DELETEs nicht in dieser Reihenfolge verbleibt. In einigen
+Fällen kann es das Sortieren für MySQL erleichtern, wenn die Tabelle nach
+der Spalte geordnet ist, nach der Sie sie später ordnen wollen. Diese
+Option ist hauptsächlich nützlich, wenn Sie wissen, dass Sie die Zeilen
+meistens in einer bestimmten Reihenfolge abfragen werden. Wenn Sie diese
+Option nach großen Änderungen in der Tabelle benutzen, können Sie
+möglicherweise eine höhere Performance erzielen.
+
+@findex ALTER TABLE
+@item
+Wenn Sie @code{ALTER TABLE} auf einer @code{MyISAM}-Tabelle benutzen,
+werden alle nicht eindeutigen Indexe in einem separaten Stapellauf erzeugt
+(wie bei @code{REPAIR}). Das sollte @code{ALTER TABLE} viel schneller
+machen, wenn Sie viele Indexe haben.
+
+@item
+Ab @strong{MySQL 4.0} kann dies explizit aktiviert werden. @code{ALTER
+TABLE ... DISABLE KEYS} veranlasst MySQL, mit der Aktualisierung nicht
+eindeutiger Indexe für @code{MyISAM}-Tabellen aufzuhören. @code{ALTER TABLE
+... ENABLE KEYS} sollte dann benutzt werden, um fehlende Indexe wieder zu
+erzeugen. Weil MySQL das mit Algorithmen durchführt, die viel schneller
+sind als das Einfügen von Schlüsseln nacheinander, kann das Abschalten von
+Schlüsseln bei Masseneinfügeoperationen erheblich Geschwindigkeitsvorteile
+bringen.
+
+@item
+@findex mysql_info()
+Mit der C-API-Funktion @code{mysql_info()} können Sie herausfinden, wie
+viele Datensätze kopiert wurden und (wenn @code{IGNORE} benutzt wird) wie
+viele Datensätze aufgrund der Duplizierung eindeutiger Schlüsselwerte
+gelöscht wurden.
+
+@item
+@cindex Fremdschlüssel
+@cindex Referenzen
+Die @code{FOREIGN KEY}-, @code{CHECK}- und @code{REFERENCES}-Klauseln
+machen nichts. Die Syntax für sie steht nur aus Kompatibilitätsgründen
+bereit, um das Portieren von Code von anderen SQL-Servern zu erleichtern
+und um Applikationen laufen zu lassen, die Tabellen mit Referenzen
+erzeugen.
+@c German FIX old ref was @xref{Fehlende Funktionen}.
+@xref{ANSI diff Foreign Keys}.
+@end itemize
+
+Hier ist ein Beispiel, das einige der Anwendungsfälle von @code{ALTER
+TABLE} zeigt. Wir fangen mit einer Tabelle @code{t1} an, die wie folgt
+erzeugt wird:
+
+@example
+mysql> CREATE TABLE t1 (a INTEGER,b CHAR(10));
+@end example
+
+Um die Tabelle von @code{t1} nach @code{t2} umzubenennen, geben Sie ein:
+
+@example
+mysql> ALTER TABLE t1 RENAME t2;
+@end example
+
+Um Spalte @code{a} von @code{INTEGER} nach @code{TINYINT NOT NULL} zu
+ändern (der Name bleibt derselbe) und Spalte @code{b} von @code{CHAR(10)}
+nach @code{CHAR(20)} zu ändern und gleichzeitig von @code{b} nach @code{c}
+umzubenennen, geben Sie ein:
+
+@example
+mysql> ALTER TABLE t2 MODIFY a TINYINT NOT NULL, CHANGE b c CHAR(20);
+@end example
+
+Jetzt wird eine @code{TIMESTAMP}-Spalte namens @code{d} hinzugefügt:
+
+@example
+mysql> ALTER TABLE t2 ADD d TIMESTAMP;
+@end example
+
+Nunmehr erzeugen wir einen Index auf Spalte @code{d} und machen Spalte
+@code{a} zum Primärschlüssel:
+
+@example
+mysql> ALTER TABLE t2 ADD INDEX (d), ADD PRIMARY KEY (a);
+@end example
+
+Wir entfernen Spalte @code{c}:
+
+@example
+mysql> ALTER TABLE t2 DROP COLUMN c;
+@end example
+
+Und fügen eine neue @code{AUTO_INCREMENT}-Ganzzahl-Spalte namens @code{c}
+hinzu:
+
+@example
+mysql> ALTER TABLE t2 ADD c INT UNSIGNED NOT NULL AUTO_INCREMENT,
+ ADD INDEX (c);
+@end example
+
+Beachten Sie, dass wir @code{c} indiziert haben, weil
+@code{AUTO_INCREMENT}-Spalten indiziert sein müssen, und auch, dass wir
+@code{c} als @code{NOT NULL} deklariert haben, weil indizierte Spalten
+nicht @code{NULL} sein dürfen.
+
+Wenn Sie eine @code{AUTO_INCREMENT}-Spalte hinzufügen, werden automatisch
+Spaltenwerte mit Zahlenfolgen eingefügt. Sie können die erste Zahl setzen,
+indem Sie @code{SET INSERT_ID=#} vor @code{ALTER TABLE} ausführen oder
+indem Sie die @code{AUTO_INCREMENT = #}-Tabellenoption benutzen.
+@xref{SET OPTION}.
+
+Wenn Sie bei MyISAM-Tabellen nicht die @code{AUTO_INCREMENT}-Spalte ändern,
+ist die Folgezahl davon nicht betroffen. Wenn Sie eine
+@code{AUTO_INCREMENT}-Spalte löschen und dann eine weitere
+@code{AUTO_INCREMENT}-Spalte hinzufügen, fangen die Zahlen wieder bei 1 an.
+
+@xref{ALTER TABLE problems}.
+
+
+@node RENAME TABLE, DROP TABLE, ALTER TABLE, Data Definition
+@c German node RENAME TABLE
+@subsection @code{RENAME TABLE}-Syntax
+
+@findex RENAME TABLE
+
+@example
+RENAME TABLE tabelle TO neue_tabelle[, tabelle2 TO neue_tabelle2,...]
+@end example
+
+Das Umbenennen wird atomisch durchgeführt, was heißt, dass kein anderer
+Thread auf die Tabelle(n) zugreifen kann, während umbenannt wird. Das
+ermöglicht, eine Tabelle durch eine leere zu ersetzen:
+
+@example
+CREATE TABLE neue_tabelle (...);
+RENAME TABLE alte_tabelle TO datensicherung_tabelle, neue_tabelle TO alte_tabelle;
+@end example
+
+Das Umbenennen wird von links nach rechts durchgeführt, was bedeutet, dass
+Sie beim Vertauschen zweier Tabellennamen folgendes tun können:
+
+@example
+RENAME TABLE alte_tabelle TO datensicherung_tabelle,
+ neue_tabelle TO alte_tabelle,
+ datensicherung_tabelle TO neue_tabelle;
+@end example
+
+Solange zwei Datenbanken auf derselben Platte liegen, können Sie auch von
+einer Datenbank in eine andere umbenennen:
+
+@example
+RENAME TABLE aktuelle_datenbank.tabelle TO andere_datenbank.tabelle;
+@end example
+
+Wenn Sie @code{RENAME} ausführen, dürfen Sie keine gesperrten Tabellen oder
+aktive Transaktionen haben. Ausserdem benötigen Sie die @code{ALTER}- und
+@code{DROP}-Berechtigungen für die Original-Tabelle und die @code{CREATE}-
+und @code{INSERT}-Berechtigungen auf die neue Tabelle.
+
+Wenn beim Umbenennen mehrfacher Tabellen Fehler auftreten, führt MySQL ein
+entgegengesetztes Umbenennen aller umbenannten Tabellen durch, um alles
+wieder in den Ausgangszustand zu versetzen.
+
+
+@node DROP TABLE, CREATE INDEX, RENAME TABLE, Data Definition
+@c German node DROP TABLE
+@subsection @code{DROP TABLE}-Syntax
+
+@findex DROP TABLE
+
+@example
+DROP TABLE [IF EXISTS] tabelle [, tabelle,...] [RESTRICT | CASCADE]
+@end example
+
+@code{DROP TABLE} entfernt eine oder mehrere Tabellen. Alle Tabellendaten
+und die Tabellendefinition werden @emph{zerstört}, seien Sie daher
+@strong{vorsichtig} mit diesem Befehl!
+
+Ab MySQL-Version 3.22 können Sie die Schlüsselwörter @code{IF EXISTS}
+benutzen, um Fehler zu vermeiden, die auftreten, wenn Tabellen nicht
+existieren.
+
+@code{RESTRICT} und @code{CASCADE} sind wegen leichterer Portierung
+zugelassen. Momentan tun sie nichts.
+
+@strong{HINWEIS}: @code{DROP TABLE} ist nicht transaktionssicher und führt
+automatisch jegliche aktiven Transaktionen zuende.
+
+
+@node CREATE INDEX, DROP INDEX, DROP TABLE, Data Definition
+@c German node CREATE INDEX
+@subsection @code{CREATE INDEX}-Syntax
+
+@findex CREATE INDEX
+
+@cindex Indexe
+@cindex Indexe, mehrteilige
+@cindex mehrteilige Indexe
+
+@example
+CREATE [UNIQUE|FULLTEXT] INDEX index_name ON tabelle (spalten_name[(laenge)],... )
+@end example
+
+Das @code{CREATE INDEX}-Statement macht vor MySQL-Version 3.22 nichts. Ab
+Version 3.22 ist @code{CREATE INDEX} auf ein @code{ALTER TABLE}-Statement
+gemappt, um Indexe zu erzeugen. @xref{ALTER TABLE, , @code{ALTER TABLE}}.
+
+Normalerweise erzeugen Sie alle Indexe auf eine Tabelle zur Zeit, wo die
+Tabelle selbst mit @code{CREATE TABLE} erzeugt wird.
+@c German FIX unsplit @xref
+@xref{CREATE TABLE, ,@code{CREATE TABLE}}.
+@code{CREATE INDEX} gestattet, bestehenden Tabellen
+Indexe hinzuzufügen.
+
+A Spaltenliste der Form @code{(spalte1,spalte2,...)} erzeugt einen
+mehrspaltigen Index. Die Indexwerte werden durch Verkettung der Werte der
+angegebenen Spalten erzeugt.
+
+Bei @code{CHAR}- und @code{VARCHAR}-Spalten können Indexe, die nur einen
+Teil einer Spalte benutzen, mit der @code{spalten_name(laenge)}-Syntax
+erzeugt werden. (Bei @code{BLOB}- und @code{TEXT}-Spalten ist die
+Längenangabe erforderlich.) Unten stehendes Statement zeigt, wie ein Index
+erzeugt wird, der die ersten 10 Zeichen der @code{name}-Spalte benutzt:
+
+@example
+mysql> CREATE INDEX teil_von_name ON kunde (name(10));
+@end example
+
+Weil sich die meisten Namen üblicherweise in den ersten 10 Zeichen
+unterscheiden, sollte dieser Index nicht viel langsamer sein, als wenn der
+Index aus der gesamten @code{name}-Spalte erzeugt worden wäre. Die
+Benutzung von Teilspalten für Indexe kann die Index-Datei auch viel kleiner
+machen, was viel Speicherplatz sparen und zusätzlich
+@code{INSERT}-Operationen beschleunigen kann!
+
+Beachten Sie, dass Sie einen Index auf eine Spalte, die @code{NULL}-Werte
+haben darf, oder auf eine @code{BLOB}/@code{TEXT}-Spalte erst ab
+MySQL-Version 3.23.2 und nur beim @code{MyISAM}-Tabellentyp erzeugen
+können.
+
+Weitere Informationen darüber, wie MySQL Indexe benutzt, finden Sie unter
+@ref{MySQL indexes, , MySQL-Indexe}.
+
+@code{FULLTEXT}-Indexe können nur @code{VARCHAR}- und @code{TEXT}-Spalten
+indexieren und funktionieren nur bei @code{MyISAM}-Tabellen.
+@code{FULLTEXT}-Indexe sind ab MySQL-Version 3.23.23 verfügbar.
+@ref{Fulltext Search}.
+
+
+@node DROP INDEX, , CREATE INDEX, Data Definition
+@c German node DROP INDEX
+@subsection @code{DROP INDEX}-Syntax
+
+@findex DROP INDEX
+
+@example
+DROP INDEX index_name ON tabelle
+@end example
+
+@code{DROP INDEX} löscht den Index namens @code{index_name} aus der Tabelle
+@code{tabelle}. @code{DROP INDEX} macht vor MySQL-Version 3.22 nichts. Ab
+Version 3.22 ist @code{DROP INDEX} auf ein @code{ALTER TABLE}-Statement
+gemappt, um den Index zu löschen. @xref{ALTER TABLE, , @code{ALTER TABLE}}.
+
+
+@node Basic User Commands, Transactional Commands, Data Definition, Reference
+@c German node Grundlegende Benutzerbefehle
+@section Grundlegende Befehle des MySQL-Dienstprogramms für Benutzer
+
+
+
+@menu
+* USE::
+* DESCRIBE::
+@end menu
+
+@node USE, DESCRIBE, Basic User Commands, Basic User Commands
+@c German node USE
+@subsection @code{USE}-Syntax
+
+@findex USE
+
+@example
+USE datenbank
+@end example
+
+Das @code{USE datenbank}-Statement weist MySQL an, @code{datenbank} als
+vorgabemäßige Datenbank für nachfolgende Anfragen zu benutzen. Die
+Datenbank bleibt die aktuelle, entweder bis zum Ende der Sitzung, oder bis
+ein weiteres @code{USE}-Statement abgesetzt wird:
+
+@example
+mysql> USE datenbank1;
+mysql> SELECT count(*) FROM tabelle; # wählt aus von datenbank1.tabelle
+mysql> USE datenbank2;
+mysql> SELECT count(*) FROM tabelle; # wählt aus von datenbank2.tabelle
+@end example
+
+Wenn Sie eine bestimmte Datenbank mit dem @code{USE}-Statement zu aktuellen
+machen, heißt das nicht, dass Sie nicht auf Tabellen in anderen
+Datenbanken zugreifen können. Das unten stehende Beispiel zeigt den Zugriff
+auf die @code{autor}-Tabelle in der @code{datenbank1}-Datenbank und auf
+die @code{herausgeber}-Tabelle in der @code{datenbank2}-Datenbank:
+
+@example
+mysql> USE datenbank1;
+mysql> SELECT autor_name,herausgeber_name FROM autor,datenbank2.herausgeber
+ WHERE autor.herausgeber_id = datenbank2.herausgeber.herausgeber_id;
+@end example
+
+@cindex Sybase Kompatibilität
+@cindex Kompatibilität, mit Sybase
+The @code{USE}-Statement wird für die Sybase-Kompatibilität zur Verfügung
+gestellt.
+
+
+@node DESCRIBE, , USE, Basic User Commands
+@c German node DESCRIBE
+@subsection @code{DESCRIBE}-Syntax (Informationen über Spalten erhalten)
+
+@findex DESC
+@findex DESCRIBE
+
+@example
+@{DESCRIBE | DESC@} tabelle @{spalten_name | platzhalter@}
+@end example
+
+@code{DESCRIBE} ist ein Kürzel für @code{SHOW COLUMNS FROM}.
+@xref{SHOW DATABASE INFO}.
+
+@code{DESCRIBE} stellt Informationen über die Spalten einer Tabelle bereit.
+@code{spalten_name} kann ein Spaltenname oder eine Zeichenkette sein, die
+die SQL-@samp{%}- und -@samp{_}-Platzhalterzeichen enthält.
+
+Wenn die Spaltentypen sich von dem unterscheiden, was Sie auf der Grundlage
+eines @code{CREATE TABLE}-Statements erwartet hätten, beachten Sie, dass
+MySQL manchmal Spaltentypen ändert. @xref{Silent column changes}.
+
+@cindex Oracle-Kompatibilität
+@cindex Kompatibilität, mit Oracle
+Dieses Statement wird für die Oracle-Kompatibilität zur Verfügung gestellt.
+
+Das @code{SHOW}-Statement stellt ähnliche Informationen bereit.
+@xref{SHOW, , @code{SHOW}}.
+
+
+@node Transactional Commands, Fulltext Search, Basic User Commands, Reference
+@c German node Transaktionale Befehle
+@section Transaktionale und Sperrbefehle von MySQL
+
+
+
+@menu
+* COMMIT::
+* LOCK TABLES::
+* SET TRANSACTION::
+@end menu
+
+@node COMMIT, LOCK TABLES, Transactional Commands, Transactional Commands
+@c German node COMMIT
+@subsection @code{BEGIN/COMMIT/ROLLBACK}-Syntax
+
+@findex BEGIN
+@findex COMMIT
+@findex ROLLBACK
+
+Vorgabemäßig läuft MySQL im @code{autocommit}-Modus. Das heißt, dass
+MySQL eine Aktualisierung auf Platte speichert, sobald Sie eine
+Aktualisierung ausführen.
+
+Wenn Sie transaktionssichere Tabellen (wie @code{InnoDB} oder @code{BDB} )
+benutzen, können Sie MySQL mit folgendem Befehl in den
+Nicht-@code{autocommit}-Modus setzen:
+
+@example
+SET AUTOCOMMIT=0
+@end example
+
+Danach müssen Sie @code{COMMIT} benutzen, um Ihre Änderungen auf Platte zu
+sichern, oder @code{ROLLBACK}, wenn Sie die Änderungen verwerfen wollen,
+die Sie seit dem Beginn der Transaktion gemacht haben.
+
+Wenn Sie für eine Reihe von Statements zum @code{AUTOCOMMIT}-Modus
+umschalten wollen, können Sie das @code{BEGIN}- oder @code{BEGIN
+WORK}-Statement benutzen:
+
+@example
+BEGIN;
+SELECT @@A:=SUM(gehalt) FROM tabelle1 WHERE type=1;
+UPDATE tabelle2 SET zusammenfassung=@@A WHERE type=1;
+COMMIT;
+@end example
+
+Beachten Sie, dass bei der Benutzung nicht transaktionssicher Tabellen die
+Änderungen dennoch sofort gespeichert werden, unabhängig vom Status des
+@code{autocommit}-Modus.
+
+Wenn Sie @code{ROLLBACK} bei der Aktualisierung einer nicht transaktionalen
+Tabelle ausführen, erhalten Sie einen Fehler
+(@code{ER_WARNING_NOT_COMPLETE_ROLLBACK}) als Warnung. Alle
+transaktionssicheren Tabellen werden zurückgesetzt, aber nicht
+transaktionale Tabelle ändern sich nicht.
+
+Wenn Sie @code{BEGIN} oder @code{SET AUTOCOMMIT=0} benutzen, sollten Sie
+die MySQL-Binär-Log-Datei für Datensicherungen benutzen statt der älteren
+Update-Log-Datei. Transaktionen werden in der Binär-Log-Datei in einem
+Stück gespeichert, beim @code{COMMIT}, um sicherzustellen, dass
+Transaktionen, die zurückgesetzt werden (Rollback), nicht gespeichert
+werden. @xref{Binary log}.
+
+Folgende Befehle beenden automatisch eine Transaktion (als ob Sie ein
+@code{COMMIT} vor der Ausführung des Befehls ausgeführt hätten:
+
+@multitable @columnfractions .33 .33 .33
+@item @code{ALTER TABLE} @tab @code{BEGIN} @tab @code{CREATE INDEX}
+@item @code{DROP DATABASE} @tab @code{DROP TABLE} @tab @code{RENAME TABLE}
+@item @code{TRUNCATE}
+@end multitable
+
+@c German FIX changed @xref to @xref
+Sie können die Isolationsebene (Isolation Level) für Transaktionen mit
+@code{SET TRANSACTION ISOLATION LEVEL ...} @ref{SET TRANSACTION} ändern.
+
+
+@node LOCK TABLES, SET TRANSACTION, COMMIT, Transactional Commands
+@c German node LOCK TABLES
+@subsection @code{LOCK TABLES/UNLOCK TABLES}-Syntax
+
+@findex LOCK TABLES
+@findex UNLOCK TABLES
+
+@example
+LOCK TABLES tabelle [AS alias] @{READ | [READ LOCAL] | [LOW_PRIORITY] WRITE@}
+ [, tabelle @{READ | [LOW_PRIORITY] WRITE@} ...]
+...
+UNLOCK TABLES
+@end example
+
+@code{LOCK TABLES} sperrt Tabellen für den aktuellen Thread. @code{UNLOCK
+TABLES} hebt alle Sperren auf, die vom aktuellen Thread veranlasst wurden.
+Alle Tabellen, die durch den aktuellen Thread gesperrt sind, werden
+automatisch entsperrt, wenn der Thread ein weiteres @code{LOCK TABLES}
+absetzt oder wenn die Verbindung zum Server geschlossen wird.
+
+Die wichtigsten Gründe für die Benutzung von @code{LOCK TABLES} sind die
+Emulation von Transaktionen oder um mehr Geschwindigkeit bei der
+Aktualisierung von Tabellen zu erhalten. Das wird später detaillierter
+erläutert.
+
+Wenn ein Thread eine @code{READ}-Sperre auf eine Tabelle erlangt, kann
+dieser Thread (und alle anderen Threads) nur aus der Tabelle lesen. Wenn
+ein Thread eine @code{WRITE}-Sperre auf eine Tabelle erlangt, kann nur der
+Thread, der die Sperre veranlasst hat, @code{READ} oder @code{WRITE} auf
+der Tabelle durchführen. Andere Threads werden blockiert.
+
+Der Unterschied zwischen @code{READ LOCAL} und @code{READ} ist, dass
+@code{READ LOCAL} nicht kollidierende @code{INSERT}-Statements während der
+Dauer der Sperre zuläßt. Das kann jedoch nicht benutzt werden, wenn Sie
+Datenbankdateien ausserhalb von MySQL bearbeiten, während die Sperre aktiv
+ist.
+
+Wenn Sie @code{LOCK TABLES} benutzen, müssen Sie alle Tabellen sperren, die
+Sie benutzen werden, und Sie müssen denselben Alias benutzen, den Sie in
+Ihren Anfragen benutzen werden! Wenn Sie eine Tabelle in einer Anfrage
+mehrfach (mit Aliasen) benutzen, müssen Sie für jeden Alias eine Sperre
+machen!
+
+@code{WRITE}-Sperren haben normalerweise höhere Priorität als
+@code{READ}-Sperren, um sicherzustellen, dass Aktualisierungen so früh wie
+möglich bearbeitet werden. Dass heißt, wenn ein Thread eine
+@code{READ}-Sperre erlangt und dann ein anderer Thread eine
+@code{WRITE}-Sperre verlangt, dass nachfolgende @code{READ}-Sperrenanfragen
+warten, bis der @code{WRITE}-Thread die Sperre erhalten und freigegeben
+hat. Sie können @code{LOW_PRIORITY WRITE}-Sperren benutzen, um anderen
+Threads zu gestatten, @code{READ}-Sperren zu erlangen, während der Thread
+auf die @code{WRITE}-Sperre wartet. Sie sollten nur dann @code{LOW_PRIORITY
+WRITE}-Sperren benutzen, wenn Sie sicher sind, dass es irgendwann eine Zeit
+gibt, in der kein anderer Thread eine @code{READ}-Sperre haben wird.
+
+@code{LOCK TABLES} funktioniert wie folgt:
+@enumerate
+@item
+Sortiert alle Tabellen, die gesperrt werden sollen, in einer intern
+definierten Reihenfolge (aus Benutzersicht ist die Reihenfolge
+undefiniert).
+@item
+Wenn eine Tabelle mit einer Lese- und einer Schreibsperre gesperrt ist,
+wird die Schreibsperre vor die Lesesperre platziert.
+@item
+Sperrt eine Tabelle nach der anderen, bis der Thread alle Sperren erhalten
+hat.
+@end enumerate
+
+Diese Methode stellt sicher, dass Tabellensperren blockierungsfrei ist. Bei
+diesem Schema gibt es jedoch ein paar weitere Dinge, derer man sich bewusst
+sein muss:
+
+Wenn Sie eine @code{LOW_PRIORITY_WRITE}-Sperre für eine Tabelle benutzen,
+heißt das, dass MySQL auf diese bestimmte Sperre wartet, bis es keinen
+Thread gibt, der eine @code{READ}-Sperre will. Wenn der Thread die
+@code{WRITE}-Sperre erhalten hat und darauf wartet, die Sperre für die
+nächste Tabelle in der Tabellensperrliste zu erhalten, warten alle anderen
+Threads darauf, dass die @code{WRITE}-Sperre aufgehoben wird. Wenn das bei
+Ihrer Applikation zu ernsthaften Problemen führt, sollten Sie in Betracht
+ziehen, einige Ihrer Tabelle in transaktionssichere Tabelle umzuwandeln.
+
+Es ist sicher, einen Thread mit @code{KILL} zu killen, der auf eine
+Tabellensperre wartet. @xref{KILL}.
+
+Beachten Sie, dass Sie @strong{NICHT} irgend welche Tabellen sperren
+sollten, die Sie mit @code{INSERT DELAYED} benutzen. Das liegt darin, dass
+in diesem Fall das @code{INSERT} von einem separaten Thread durchgeführt
+wird.
+
+Normalerweise müssen Sie Tabellen nicht sperren, weil alle einzelnen
+@code{UPDATE}-Statements atomisch sind. Kein anderer Thread kann mit einem
+aktuell ausgeführten SQL-Statement in die Quere kommen. Es gibt dennoch
+einige Fällen, in denen es wünschenswert sein kann, Tabellen zu sperren:
+
+@itemize @bullet
+@item
+Wenn Sie viele Operationen auf einer großen Zahl von Tabellen laufen
+lassen wollen, ist es viel schneller, die Tabellen zu sperren, die Sie
+benutzen werden. Der Nachteil besteht natürlich darin, dass kein anderer
+Thread eine @code{READ}-gesperrte Tabelle aktualisieren und kein anderer
+Thread eine @code{WRITE}-gesperrte Tabelle lesen kann.
+
+Der Grund, dass einiges mit @code{LOCK TABLES} schneller geht, liegt darin,
+dass MySQL den Schlüssel-Cache für die gesperrten Tabellen nicht auf Platte
+zurückschreibt (flush), bis @code{UNLOCK TABLES} aufgerufen wird
+(normalerweise wird der Schlüssel-Cache nach jedem SQL-Statement auf Platte
+zurückgeschrieben). Das erhöht die Geschwindigkeit bei den Operationen
+INSERT / UPDATE / DELETE bei @code{MyISAM}-Tabellen.
+@item
+Wenn Sie einen Tabellen-Handler in MySQL benutzen, der keine Transaktionen
+unterstützt, müssen Sie @code{LOCK TABLES} benutzen, wenn Sie sicherstellen
+wollen, dass kann anderer Thread zwischen einem @code{SELECT} und einem
+@code{UPDATE} dazwischen kommen kann. Das unten stehende Beispiel erfordert
+@code{LOCK TABLES}, um sicher ausgeführt zu werden:
+
+@example
+mysql> LOCK TABLES trans READ, kunde WRITE;
+mysql> select sum(wert) from trans where kunde_id=irgendeine_id;
+mysql> update kunde set gesamt_wert=summe_aus_vorherigem_statement
+ where kunde_id=irgendeine_id;
+mysql> UNLOCK TABLES;
+@end example
+
+Ohne @code{LOCK TABLES} besteht die Möglichkeit, dass ein anderer Thread
+eine neue Zeile in die @code{trans}-Tabelle einfügt, zwischen der
+Ausführung des @code{SELECT}- und des @code{UPDATE}-Statements.
+@end itemize
+
+Wenn Sie inkrementelle Updates (@code{UPDATE kunde SET
+wert=wert+neuer_wert}) oder die @code{LAST_INSERT_ID()}-Funktion benutzen,
+können Sie @code{LOCK TABLES} in vielen Fällen vermeiden.
+
+Einige Problemfälle können Sie auch lösen, indem Sie die Sperrfunktionen
+auf Benutzerebene @code{GET_LOCK()} und @code{RELEASE_LOCK()} benutzen.
+Diese Sperren werden in einer Hash-Tabelle im Server gespeichert und sind
+mit @code{pThread_mutex_lock()} und @code{pThread_mutex_unlock()} für die
+Erzielung höherer Geschwindigkeit implementiert.
+@xref{Miscellaneous functions}.
+
+Siehe @ref{Internal locking} wegen weiterer Informationen über
+Sperrmethoden.
+
+Sie können alle Tabellen in allen Datenbanken mit Lesesperren sperren, und
+zwar mit dem @code{FLUSH TABLES WITH READ LOCK}-Befehl. @xref{FLUSH}. Das
+ist eine sehr bequeme Möglichkeit, Datensicherungen zu erhalten, wenn Sie
+ein Dateisystem wie Veritas haben, dass Schnappschüsse im Zeitverlauf
+aufnehmen kann.
+
+@strong{HINWEIS}: @code{LOCK TABLES} ist nicht transaktionssicher und
+schickt automatisch jegliche aktiven Transaktionen ab (Commit), bevor es
+versucht, die Tabellen zu sperren.
+
+
+@node SET TRANSACTION, , LOCK TABLES, Transactional Commands
+@c German node SET TRANSACTION
+@subsection @code{SET TRANSACTION}-Syntax
+
+@findex ISOLATION LEVEL
+
+@example
+SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL
+[READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE]
+@end example
+
+Setzt die Transaktionsisolationsebene für die globale, gesamte Sitzung oder
+für die nächste Transaktion.
+
+Das vorgabemäßige Verhalten ist das Setzen der Isolationsebene für die
+nächste (nicht angefangene) Transaktion.
+
+Wenn Sie die @code{GLOBAL}-Berechtigung setzen, betrifft das alle neu
+erzeugten Threads. Sie benötigen dafür die @code{PROCESS}-Berechtigung.
+
+Wenn Sie die @code{SESSION}-Berechtigung setzen, betrifft das die folgenden
+und alle zukünftigen Transaktionen.
+
+Sie können die vorgabemäßige Isolationsebene für @code{mysqld} mit
+@code{--transaction-isolation=...} setzen. @xref{Command-line options}.
+
+
+@node Fulltext Search, Query Cache, Transactional Commands, Reference
+@c German node Volltextsuche
+@section MySQL-Volltextsuche
+
+@cindex Suchen, Volltext
+@cindex Volltextsuche
+@cindex FULLTEXT
+
+Ab Version 3.23.23 bietet MySQL Unterstützung für Volltext-Indexierung und
+-Suche. Volltext-Indexe sind in MySQL Indexe vom Typ @code{FULLTEXT}.
+@code{FULLTEXT}-Indexe können von @code{VARCHAR}- und @code{TEXT}-Spalten
+zur Zeit von @code{CREATE TABLE} erzeugt werden oder später mit @code{ALTER
+TABLE} oder @code{CREATE INDEX} hinzugefügt werden. Bei großen Datenmengen
+ist es viel schneller, einen @code{FULLTEXT}-Index mit @code{ALTER TABLE}
+(oder @code{CREATE INDEX}) hinzuzufügen, als Zeilen in eine leere Tabelle
+mit einem @code{FULLTEXT}-Index einzufügen.
+
+Die Volltextsuche wird mit der @code{MATCH}-Funktion durchgeführt.
+
+@example
+mysql> CREATE TABLE artikel (
+ -> id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
+ -> titel VARCHAR(200),
+ -> artikeltext TEXT,
+ -> FULLTEXT (titel,artikeltext)
+ -> );
+Query OK, 0 rows affected (0.00 sec)
+
+mysql> INSERT INTO artikel VALUES
+ -> (0,'MySQL-Tutorial', 'DBMS steht für DataBase-Management ...'),
+ -> (0,'Wie man MySQL effizient einsetzt', 'Nachdem Sie ...'),
+ -> (0,'MySQL optimieren','In diesem Tutorial wird gezeigt, wie ...'),
+ -> (0,'1001 MySQL-Tricks','1. Lassen Sie mysqld nie als root laufen. 2. Normalisieren ...'),
+ -> (0,'MySQL vs. YourSQL', 'Im folgenden Datenbankvergleich ...'),
+ -> (0,'MySQL-Sicherheitsaspekte', 'Wenn er korrekt konfiguriert ist, ist MySQL ...');
+Query OK, 5 rows affected (0.00 sec)
+Records: 5 Duplicates: 0 Warnings: 0
+
+mysql> SELECT * FROM artikel WHERE MATCH (titel,artikeltext) AGAINST ('Datenbank');
++----+-------------------+---------------------------------------------+
+| id | titel | artikeltext |
++----+-------------------+---------------------------------------------+
+| 5 | MySQL vs. YourSQL | Im folgenden Datenbankvergleich ... |
+| 1 | MySQL-Tutorial | DBMS steht für DataBase-Management ... |
++----+-------------------+---------------------------------------------+
+2 rows in set (0.00 sec)
+@end example
+
+Die Funktion @code{MATCH} prüft eine natürlichsprachige Anfrage gegen
+(@code{AGAINST}) eine Textsammlung (einfach ein Satz von Spalten, der vom
+@code{FULLTEXT}-Index abgedeckt wird). Für jede Zeile in einer Tabelle gibt
+sie eine Relevanz zurück - ein Ähnlichkeitsmaß zwischen dem Text in dieser
+Zeile (in den Spalten, die Teil der Textsammlung sind) und der Anfrage.
+Wenn sie in einer @code{WHERE}-Klausel benutzt wird (siehe Beispiel oben),
+werden die zurückgegebenen Zeilen automatisch nach absteigender Relevanz
+sortiert. Die Relevanz ist eine nicht negative Fließkommazahl. 0 Relevanz
+bedeutet keine Ähnlichkeit. Die Relevanz wird auf der Grundlage der Anzahl
+von Wörtern in der Zeile, der Anzahl eindeutiger Wörter in dieser Zeile,
+der Gesamtzahl von Wörtern in der Textsammlung und der Anzahl von
+Dokumenten (Zeilen) berechnet, die ein bestimmtes Wort enthalten.
+
+Das obige Beispiel ist ein grundlegendes Beispiel der Benutzung der
+@code{MATCH}-Funktion. Die Zeilen werden nach absteigender Relevanz
+zurückgegeben.
+
+@example
+mysql> SELECT id,MATCH (titel,artikeltext) AGAINST ('Tutorial') FROM artikel;
++----+------------------------------------------------+
+| id | MATCH (titel,artikeltext) AGAINST ('Tutorial') |
++----+------------------------------------------------+
+| 1 | 0.64840710366884 |
+| 2 | 0 |
+| 3 | 0.66266459031789 |
+| 4 | 0 |
+| 5 | 0 |
+| 6 | 0 |
++----+------------------------------------------------+
+5 rows in set (0.00 sec)
+@end example
+
+Dieses Beispiel zeigt, wie man Relevanzen abruft. Weil weder die
+@code{WHERE}- noch die @code{ORDER BY}-Klausel vorhanden sind, werden die
+Zeilen unsortiert zurückgegeben.
+
+@example
+mysql> SELECT id, artikeltext, MATCH (titel,artikeltext) AGAINST (
+ -> 'Sicherheits-Implikationen, wenn Sie MySQL als root laufen lassen') AS rang
+ -> FROM artikel WHERE MATCH (titel,artikeltext) AGAINST
+ -> ('Sicherheits-Implikationen, wenn Sie MySQL als root laufen lassen');
++----+----------------------------------------------------------------+-----------------+
+| id | artikeltext | rang |
++----+----------------------------------------------------------------+-----------------+
+| 4 | 1. Lassen Sie mysqld nie als root laufen. 2. Normalisieren ... | 1.5055546709332 |
+| 6 | Wenn er korrekt konfiguriert ist, ist MySQL ... | 1.31140957288 |
++----+----------------------------------------------------------------+-----------------+
+2 rows in set (0.00 sec)
+@end example
+
+Das ist ein komplexeres Beispiel - die Anfrage gibt die Relevanz zurück und
+sortiert die Zeilen auch noch nach absteigender Relevanz. Um das zu
+erzielen, müssen Sie @code{MATCH} zweimal angeben. Beachten Sie, dass das
+keinen zusätzlichen Overhead verursacht, weil der MySQL-Optimierer bemerkt,
+dass diese zwei @code{MATCH}-Aufrufe identisch sind und daher den Code für
+die Volltextsuche nur einmal aufruft.
+
+MySQL benutzt einen sehr einfachen Parser, um Text in Wörter zu zerlegen.
+Ein ``Wort'' ist jede Folge von Buchstaben, Zahlen, @samp{'} und @samp{_}.
+Jedes ``Wort'', das in der Liste der Stopwords vorkommt oder einfach nur
+zu kurz ist (3 Zeichen oder weniger), wird ignoriert.
+
+Jedes korrekte Wort in der Textsammlung und in der Anfrage wird nach seiner
+Signifikanz in der Anfrage oder der Textsammlung gewichtet. Daher hat ein
+Wort, dass in vielen Dokumenten vorkommt, ein geringeres Gewicht (und kann
+sogar 0 Gewicht haben), weil es in dieser bestimmten Textsammlung einen
+geringen semantischen Wert hat. Ansonsten, wenn das Wort selten vorkommt,
+erhält es ein höheres Gewicht. Die Gewichte der Wörter werden anschließend
+kombiniert, um die Relevanz der Zeile zu berechnen.
+
+Solch eine Technik funktioniert am besten bei großen Textsammlungen (in
+der Tat wurde sie sorgfältig darauf optimiert). Bei sehr kleinen Tabellen
+spiegelt die Wortverteilung nicht adäquat seinen semantischen Wert wider,
+so dass dieses Modell manchmal bizarre Ergebnisse ergeben kann:
+
+@example
+mysql> SELECT * FROM artikel WHERE MATCH (titel,artikeltext) AGAINST ('MySQL');
+Empty set (0.00 sec)
+@end example
+
+Die Suche nach dem Wort @code{MySQL} erzeugt im obigen Beispiel keine
+Ergebnisse. Das Wort @code{MySQL} ist in mehr als der Hälfte der Zeilen
+vorhanden und wird deshalb als Stopword betrachtet (eins mit dem
+semantischen Wert 0). Das ist in der Tat das gewünschte Verhalten - eine
+natürlichsprachige Anfrage sollte bei einer 1 GB großen Tabelle nicht jede
+zweite Zeile zurückgeben.
+
+Bei einem Wort, dass in der Hälfte der Zeilen in einer Tabelle
+übereinstimmt, ist es nicht sehr wahrscheinlich, dass relevante Dokumente
+gefunden werden, sondern statt dessen viele irrelevante Dokumente. Das
+kennen wir alle aus Recherchen über Suchmaschinen auf dem Internet. Das ist
+die Überlegung, die dahinter steht, dass solchen Wörtern ein niedriger
+semantischer Wert @strong{in diesem bestimmten Satz von Daten} gegeben
+wird.
+
+
+
+@menu
+* Fulltext Restrictions::
+* Fulltext Fine-tuning::
+* Volltext-Features in MySQL 4.0::
+* Fulltext TODO::
+@end menu
+
+@node Fulltext Restrictions, Fulltext Fine-tuning, Fulltext Search, Fulltext Search
+@c German node Volltext-Einschränkungen
+@subsection Volltext-Einschränkungen
+
+@itemize @bullet
+@item
+Alle Parameter der @code{MATCH}-Funktion müssen Spalten derselben Tabelle
+sein, die Teil desselben Volltext-Indexes ist.
+@item
+Das Argument für @code{AGAINST} muss eine Konstanten-Zeichenkette sein.
+@end itemize
+
+
+@node Fulltext Fine-tuning, Volltext-Features in MySQL 4.0, Fulltext Restrictions, Fulltext Search
+@c German node Volltext-Feineinstellungen
+@subsection MySQL-Volltextsuche fein einstellen
+
+@c German FIX changed @xref to @pxref
+Leider hat die Volltextsuche noch keine durch den Benutzer einstellbare
+Parameter, doch diese stehen sehr weit oben auf der TODO-Liste. Wenn Sie
+jedoch eine MySQL-Quelldistribution
+(@pxref{Installing source})
+haben, können Sie das Verhalten der Volltextsuche in einiger Hinsicht
+ändern.
+
+Beachten Sie, dass die Volltextsuche sorgfältig auf beste Sucheffektivität
+eingestellt wurde. Wenn Sie dieses vorgabemäßige Verhalten ändern, wird
+das die Suchergebnisse in den meisten Fällen verschlechtern. Ändern Sie die
+MySQL-Quelltexte deshalb nur, wenn Sie genau wissen, was Sie tun!
+
+@itemize @bullet
+
+@item
+Die minimale zu indexierende Wortlänge wird in der
+@code{myisam/ftdefs.h}-Datei in folgender Zeile festgelegt:
+@example
+#define MIN_WORD_LEN 4
+@end example
+Ändern Sie diesen Wert nach Belieben, kompilieren Sie MySQL neu und bauen
+Sie Ihre @code{FULLTEXT}-Indexe neu auf.
+
+@item
+Die Stopword-Liste wird in @code{myisam/ft_static.c} definiert. Ändern Sie
+sie nach Ihrem Geschmack, kompilieren Sie MySQL neu und bauen Sie Ihre
+@code{FULLTEXT}-Indexe neu auf.
+
+@item
+Die 50%-Schwelle wird durch das spezielle, ausgewählte Gewichtungsschema
+festgelegt. Um dieses abzuschalten, ändern Sie folgende Zeile in
+@code{myisam/ftdefs.h}:
+@example
+#define GWS_IN_USE GWS_PROB
+@end example
+zu
+@example
+#define GWS_IN_USE GWS_FREQ
+@end example
+und kompilieren Sie MySQL neu.
+In diesem Fall brauchen Sie die Indexe nicht neu aufzubauen.
+
+@end itemize
+
+
+@node Volltext-Features in MySQL 4.0, Fulltext TODO, Fulltext Fine-tuning, Fulltext Search
+@c German node <no English equivalent>
+@subsection Neue Features der Volltextsuche in MySQL 4.0
+
+Dieser Abschnitt enthält eine Auflistung der Volltext-Features, die bereits
+im MySQL-4.0-Baum implementiert sind. Er erläutert den @strong{More
+Funktionen für Volltextsuche}-Eintrag in @ref{TODO}.
+
+@itemize @bullet
+@item @code{REPAIR TABLE} mit @code{FULLTEXT}-Indexen, @code{ALTER TABLE}
+mit @code{FULLTEXT}-Indexen und @code{OPTIMIZE TABLE} mit
+@code{FULLTEXT}-Indexen läuft jetzt bis zu 100 mal schneller.
+
+@item @code{MATCH ... AGAINST} wird folgende @strong{Boolesch Operatoren}
+unterstützen:
+
+@itemize @bullet
+@item @code{+}wort bedeutet, dass das Wort in jeder zurückgegebenen Zeile
+enthalten sein @strong{muss}.
+@item @code{-}wort bedeutet, dass das Wort in jeder zurückgegebenen Zeile
+@strong{nicht} enthalten sein darf.
+@item @code{<} und @code{>} können benutzt werden, um die Wortgewichtung in
+der Anfrage herab- und heraufzusetzen.
+@item @code{~} kann benutzt werden, um einem 'Rausch-Wort' ein
+@strong{negatives} Gewicht zuzuweisen.
+@item @code{*} ist ein Trunkierungsoperator.
+@end itemize
+
+Die Boole'sche Suche benutzt eine vereinfachte Art, die Relevanz zu
+berechnen, die keine 50%-Schwelle hat.
+
+@item Suchen sind jetzt wegen optimierter Suchalgorithmen bis zu 2 mal
+schneller.
+
+@item Das Dienstprogramm @code{ft_dump} wurde für
+Low-Level-@code{FULLTEXT}-Index-Operationen hinzugefügt (Anfragen / Dumps /
+Statistiken).
+
+@end itemize
+
+
+@node Fulltext TODO, , Volltext-Features in MySQL 4.0, Fulltext Search
+@c German node Volltext-TODO-Liste
+@subsection Volltextsuche TODO-Liste
+
+@itemize @bullet
+@item Alle Operationen mit @code{FULLTEXT}-Index @strong{schneller} machen.
+@item Unterstützung für Klammern @code{()} in Boole'scher Volltextsuche.
+@item Phrasensuche, Näherungsoperatoren
+@item Boole'sche Suche funktioniert ohne @code{FULLTEXT}-Index (ja,
+@strong{sehr} langsam).
+@item Unterstützung für "immer indizierte Wörter". Das könnten beliebige
+Zeichenketten sein, die der Benutzer wie Wörter behandeln will. Beispiele
+sind "C++", "AS/400", "TCP/IP" usw.
+@item Unterstützung für Volltextsuche in @code{MERGE}-Tabellen.
+@item Unterstützung für Multi-Byte-Zeichensätze.
+@item Die Stopword-Liste von der Sprache der Daten abhängig machen.
+@item Eindämmen (Stemming, natürlich abhängig von der Sprache der Daten).
+@item Generischer Benutzer-unterstützbarer UDF- (?) Preparser.
+@item Das Modell flexibler machen (durch Hinzufügen einiger regulierbarer
+Parameter für @code{FULLTEXT} in @code{CREATE/ALTER TABLE}).
+@end itemize
+
+
+@c ACHTUNG! Folgender NODE ist neu seit 2002-01-15!
+@c ATTENTION! The following node ist new since 2001-01-15!
+
+@node Query Cache, , Fulltext Search, Reference
+@c German node Anfragen-Cache
+@section MySQL-Anfragen-Cache
+
+@cindex Anfragen-Cache
+@cindex @code{SELECT}, Anfragen-Cache
+
+Ab Version 4.0.1 besitzt der @code{MySQL-Server} einen
+@code{Anfragen-Cache}. Wenn er benutzt wird, speichert er den Text einer
+@code{SELECT}-Anfrage zusammen mit dem entsprechenden Ergebnis, das an den
+Client gesendet wird. Wenn eine weitere identische Anfrage empfangen wird,
+kann der Server die Ergebnisse aus dem Cache beziehen, statt dieselbe
+Anfrage zu parsen und noch einmal auszuführen.
+
+Der Anfragen-Cache ist extrem nützlich in Umgebungen, in denen sich
+(einige) Tabellen nicht häufig ändern und in denen Sie viele identische
+Anfragen haben. Das ist eine typische Situation für viele Web-Server, die
+viele dynamische Inhalte benutzen.
+
+Im folgenden finden Sie einige Performance-Daten für den Anfragen-Cache
+(die wir mit der MySQL-Benchmark-Suite auf einer Linux Alpha 2 x 500 MHz
+mit 2 GB RAM und einem 64-MB-Anfragen-Cache gewonnen haben):
+
+@itemize @bullet
+@item
+Wenn Sie den Anfragen-Cache-Code abschalten wollen, setzen Sie
+@code{query_cache_size=0}. Wenn Sie den Anfragen-Cache-Code abschalten,
+gibt es keinen bemerkbaren Overhead.
+@item
+Wenn alle Anfragen, die Sie ausführen, einfach sind (wie das Auswählen
+einer Zeile aus einer Tabelle mit einer Zeile), sich aber dennoch
+unterscheiden, so dass die Anfragen nicht gecachet werden können, ist der
+Overhead bei einem aktiven Anfragen-Cache 13%. Das sollte als Szenario für
+den schlechtesten Fall angesehen werden. Im echten Leben sind Anfragen
+jedoch meist viel komplizierter, so dass der Overhead normalerweise
+beträchtlich geringer ist.
+@item
+Die Suche nach einer Zeile in einer Einzeilen-Tabelle ist 238% schneller.
+Das kann als minimale Geschwindigkeitssteigerung für eine gecachete Anfrage
+betrachtet werden.
+@end itemize
+
+
+
+@menu
+* Query Cache How::
+* Query Cache Configuration::
+* Query Cache in SELECT::
+* Query Cache Status and Maintenance::
+@end menu
+
+@node Query Cache How, Query Cache Configuration, Query Cache, Query Cache
+@c German node Anfragen-Cache-Funktionsweise
+@subsection Wie der Anfragen-Cache funktioniert
+
+Anfragen werden vor dem Parsen verglichen, daher werden
+
+@example
+SELECT * FROM TABELLE
+@end example
+
+und
+
+@example
+Select * from tabelle
+@end example
+
+als unterschiedliche Anfragen für den Anfragen-Cache betrachtet. Anfragen
+müssen also exakt gleich sein (Byte für Byte), um als identisch erkannt zu
+werden. Zusätzlich kann eine Anfrage als unterschiedlich betrachtet werden,
+wenn ein Client zum Beispiel ein neues Kommunikationsprotokollformat
+benutzt oder einen anderen Zeichensatz als ein anderer Client.
+
+Anfragen, die unterschiedliche Datenbanken, Protokollversionen oder
+unterschiedliche vorgabemäßige Zeichensätze benutzen, werden als
+unterschiedliche Anfragen angesehen und separat gecachet.
+
+Der Cache funktioniert auch bei Anfragen der Art @code{SELECT CALC_ROWS
+...} und @code{SELECT FOUND_ROWS() ...}, weil die Anzahl der gefundenen
+Zeilen ebenfalls im Cache gespeichert wird.
+
+Wenn sich eine Tabelle ändert (@code{INSERT}, @code{UPDATE}, @code{DELETE},
+@code{TRUNCATE}, @code{ALTER} oder @code{DROP TABLE|DATABASE}), werden alle
+gecacheten Anfragen, die diese Tabelle benutzten (möglicherweise über eine
+@code{MRG_MyISAM}-Tabelle!) ungültig und werden aus dem Cache entfernt.
+
+Momentan werden alle @code{InnoDB}-Tabellen beim @code{COMMIT} als für den
+Cache ungültig gekennzeichnet. In Zukunft wird das geändert, so dass nur
+Tabellen, die in der Transaktion geändert wurden, für die entsprechenden
+Cache-Einträge als ungültig markiert werden.
+
+Eine Anfrage kann nicht gecachet werden, wenn sie eine der folgenden
+Funktionen enthält:
+@multitable @columnfractions .25 .25 .25 .25
+@item @strong{Funktion} @tab @strong{Funktion}
+ @tab @strong{Funktion} @tab @strong{Funktion}
+@item @code{Benutzerdefinierte Funktionen} @tab @code{CONNECTION_ID}
+ @tab @code{FOUND_ROWS} @tab @code{GET_LOCK}
+@item @code{RELEASE_LOCK} @tab @code{LOAD_FILE}
+ @tab @code{MASTER_POS_WAIT} @tab @code{NOW}
+@item @code{SYSDATE} @tab @code{CURRENT_TIMESTAMP}
+ @tab @code{CURDATE} @tab @code{CURRENT_DATE}
+@item @code{CURTIME} @tab @code{CURRENT_TIME}
+ @tab @code{DATABASE} @tab @code{ENCRYPT} (mit einem Parameter)
+@item @code{LAST_INSERT_ID} @tab @code{RAND}
+ @tab @code{UNIX_TIMESTAMP} (ohne Parameter) @tab @code{USER}
+@item @code{BENCHMARK}
+@end multitable
+
+Eine Anfrage kann ebenfalls nicht gecachet werden, wenn sie
+Benutzer-Variablen enthält oder wenn sie in der Form @code{SELECT ... IN
+SHARE MODE} oder der Form @code{SELECT * FROM AUTOINCREMENT_FIELD IS NULL}
+(um als ODBC-Workaround die letzte eingefügte ID abzurufen) ist.
+
+@code{FOUND ROWS()} gibt jedoch den korrekten Werte zurück, selbst wenn
+eine vorhergehende Anfrage aus dem Cache geholt wurde.
+
+Anfragen, die keinerlei Tabellen benutzen oder solche, bei denen der
+Benutzer eine Spaltenberechtigung für irgend eine der beteiligten Tabellen
+hat, werden nicht gecachet.
+
+Bevor eine Anfrage aus dem Anfragen-Cache geholt wird, prüft MySQL, ob der
+Benutzer die SELECT-Berechtigung für alle beteiligten Datenbanken und
+Tabellen hat. Wenn nicht, wird das Cache-Ergebnis nicht benutzt.
+
+@node Query Cache Configuration, Query Cache in SELECT, Query Cache How, Query Cache
+@c German node Anfragen-Cache-Konfiguration
+@subsection Anfragen-Cache-Konfiguration
+
+Aufgrund des Anfragen-Caches gibt es ein paar neue @code{MySQL}
+Systemvariablen für @code{mysqld}, die in einer Konfigurationsdatei oder
+auf der Kommandozeile beim Starten von @code{mysqld} gesetzt werden können:
+
+@itemize
+@item @code{query_cache_limit}
+Keine Ergebnisse cachen, die größer als dieser Wert sind (Vorgabe 1 MB).
+
+@item @code{query_cache_size}
+Der zugewiesene Arbeitsspeicher, um Ergebnisse aus alten Anfragen zu
+speichern. Wenn er 0 ist, ist der Anfragen-Cache abgeschaltet (Vorgabe).
+
+@item @code{query_cache_startup_type}
+Dieser Wert (nur Zahlen) kann wie folgt gesetzt werden:
+@multitable @columnfractions .3 .7
+@item @strong{Option} @tab @strong{Beschreibung}
+@item 0 @tab (OFF - AUS, Ergebnisse nicht cachen oder abrufen)
+@item 1 @tab (ON - AN, alle Ergebnisse ausser @code{SELECT SQL_NO_CACHE ...}-Anfragen cachen)
+@item 2 @tab (DEMAND - AUF VERLANGEN, nur @code{SELECT SQL_CACHE ...}-Anfragen cachen)
+@end multitable
+@end itemize
+
+
+Innerhalb eines Threads (Verbindung) kann das Verhalten des Anfragen-Caches
+abweichend von der Vorgabe verändert werden. Die Syntax ist wie folgt:
+
+@code{SQL_QUERY_CACHE_TYPE = OFF | ON | DEMAND}
+@code{SQL_QUERY_CACHE_TYPE = 0 | 1 | 2}
+
+@multitable @columnfractions .3 .7
+@item @strong{Option} @tab @strong{Beschreibung}
+@item 0 oder OFF @tab Keine Ergebnisse cachen oder abrufen.
+@item 1 oder ON @tab Alle Ergebnisse ausser @code{SELECT SQL_NO_CACHE ...}-Anfragen cachen.
+@item 2 oder DEMAND @tab Nur @code{SELECT SQL_CACHE ...}-Anfragen cachen.
+@end multitable
+
+Vorgabemäßig hängt @code{SQL_QUERY_CACHE_TYPE} vom Wert von
+@code{query_cache_startup_type} ab, als der Thread erzeugt wurde.
+
+
+@node Query Cache in SELECT, Query Cache Status and Maintenance, Query Cache Configuration, Query Cache
+@c German node Anfragen-Cache in SELECT
+@subsection Anfragen-Cache-Optionen in @code{SELECT}
+
+Es gibt zwei mögliche Anfragen-Cache-bezogene Parameter, die in einer
+@code{SELECT}-Anfrage angegeben werden können:
+
+@findex SQL_CACHE
+@findex SQL_NO_CACHE
+
+@multitable @columnfractions .3 .7
+@item @strong{Option} @tab @strong{Beschreibung}
+@item @code{SQL_CACHE}
+ @tab Wenn @code{SQL_QUERY_CACHE_TYPE} @code{DEMAND} ist, darf die Anfrage gecachet werden.
+ Wenn @code{SQL_QUERY_CACHE_TYPE} @code{ON} ist, ist das die Vorgabe.
+ Wenn @code{SQL_QUERY_CACHE_TYPE} @code{OFF} ist, nichts tun.
+@item @code{SQL_NO_CACHE}
+ @tab Diese Anfrage wird nicht gecachet.
+@end multitable
+
+
+@node Query Cache Status and Maintenance, , Query Cache in SELECT, Query Cache
+@c German node Anfragen-Cache-Status und -Wartung
+@subsection Anfragen-Cache-Status und -Wartung
+
+Mit dem @code{FLUSH QUERY CACHE}-Befehl können Sie den Anfragen-Cache
+defragmentieren, um den Speicher besser zu benutzen. Dieser Befehl entfernt
+keinerlei Anfragen aus dem Cache.
+@code{FLUSH TABLES} schreibt auch den Anfragen-Cache zurück auf Platte.
+
+Der @code{RESET QUERY CACHE}-Befehl entfernt alle Anfragenergebnisse aus
+dem Anfragen-Cache.
+
+Sie können die Anfragen-Cache-Performance in @code{SHOW STATUS} beobachten:
+
+@multitable @columnfractions .3 .7
+@item @strong{Variable} @tab @strong{Beschreibung}
+@item @code{Qcache_queries_in_cache}
+ @tab Anzahl von Anfragen, die im Cache registriert sind.
+@item @code{Qcache_inserts}
+ @tab Anzahl von Anfragen, die zum Cache hinzugefügt wurden.
+@item @code{Qcache_hits}
+ @tab Anzahl von Cache-Hits.
+@item @code{Qcache_not_cached}
+ @tab Anzahl von nicht gecacheten Anfragen
+ (nicht cachebar oder wegen @code{SQL_QUERY_CACHE_TYPE}).
+@item @code{Qcache_free_memory}
+ @tab Menge des freien Speichers für den Anfragen-Cache.
+@item @code{Qcache_total_blocks}
+ @tab Gesamtzahl von Blöcken im Anfragen-Cache.
+@item @code{Qcache_free_blocks}
+ @tab Anzahl freier Speicherblöcke im Anfragen-Cache.
+@end multitable
+
+Gesamtzahl von Anfragen =
+@code{Qcache_inserts} + @code{Qcache_hits} + @code{Qcache_not_cached}.
+
+Der Anfragen-Cache benutzt variable Blocklängen, so dass
+@code{Qcache_total_blocks} und @code{Qcache_free_blocks} eine
+Speicherfragmentierung des Anfragen-Caches anzeigen können. Nach
+@code{FLUSH QUERY CACHE} verbleibt nur ein einzelner (großer) freier
+Block.
+
+Hinweis: Jede Anfrage benötigt minimal zwei Blöcke (einen für den
+Anfragentext und einen weiteren für das Anfragenergebnis). Ausserdem
+benötigt jede Tabelle, die in einer Anfrage benutzt wurde, einen Block.
+Wenn allerdings zwei oder mehr Anfragen dieselbe Tabelle benutzen, muss nur
+ein Block zugewiesen werden.
+
+
+@c ACHTUNG! Folgender NODE ist geändert, 2002-01-15!
+@c ATTENTION! The following node has been changed 2001-01-15!
+@node Table types, Clients, Reference, Top
+@c German node Tabellentypen
+@chapter MySQL-Tabellentypen
+
+@cindex Tabellentypen, Auswahl
+@cindex @code{InnoDB}-Tabellentyp
+@cindex @code{Berkeley_db}-Tabellentyp
+@cindex @code{HEAP}-Tabellentyp
+@cindex @code{ISAM}-Tabellentyp
+@cindex @code{BDB}-Tabellentyp
+@cindex @code{MERGE}-Tabellentyp
+@cindex MySQL-Tabellentypen
+@cindex @code{MyISAM}-Tabellentyp
+@cindex Typen, Tabellen-
+
+AB MySQL-Version 3.23.6 können Sie unter drei grundlegenden
+Tabellenformaten (@code{ISAM}, @code{HEAP} und @code{MyISAM} wählen. Neuere
+MySQL-Versionen können zusätzliche Tabellentypen unterstützen
+(@code{InnoDB}, oder @code{BDB}), abhängig davon, wie Sie sie kompilieren.
+
+
+Beim Erzeugen einer neuen Tabelle können Sie MySQL mitteilen, welcher
+Tabellentyp dafür benutzt werden soll. MySQL erzeugt immer eine
+@code{.frm}-Datei, die die Tabellen- und Spaltendefinitionen enthält.
+Abhängig vom Tabellentyp werden Index und Daten in anderen Dateien
+gespeichert.
+
+Beachten Sie, dass Sie für die Benutzung von @code{InnoDB}-Tabellen
+zumindest die @code{innodb_data_file_path}-Startoption benötigen.
+@xref{InnoDB start}.
+
+Der vorgabemäßige Tabellentyp in MySQL ist @code{MyISAM}. Wenn Sie
+versuchen, einen Tabellentyp zu benutzen, der nicht einkompiliert oder
+aktiviert ist, erzeugt MySQL statt dessen eine Tabelle vom Typ
+@code{MyISAM}. Das ist ein sehr nützliches Feature, wenn Sie Tabellen
+zwischen unterschiedlichen SQL-Servern kopieren wollen, die
+unterschiedliche Tabellentypen unterstützten (zum Beispiel Tabellen zu
+einem Slave kopieren, der für Geschwindigkeit optimiert ist, aber keine
+transaktionalen Tabellen hat). Dieses automatische Ändern des Tabellentyps
+kann andererseits für neue MySQL-Benutzer sehr verwirrend sein. Wir planen
+für MySQL 4.0, das zu beheben, indem eine Warnung ausgegeben wird, wenn ein
+Tabellentyp automatisch geändert wird.
+
+Sie können Tabellen zwischen unterschiedlichen Typen mit dem @code{ALTER
+TABLE}-Statement umwandeln. @xref{ALTER TABLE, , @code{ALTER TABLE}}.
+
+MySQL unterstützt zwei unterschiedliche Arten von Tabellen:
+transaktionssichere Tabellen (@code{InnoDB} und @code{BDB}) und nicht
+transaktionssichere Tabellen (@code{HEAP}, @code{ISAM}, @code{MERGE} und
+@code{MyISAM}).
+
+Vorteile transaktionssicherer Tabellen (TST):
+
+@itemize @bullet
+@item
+Sicherer. Selbst wenn MySQL abstürzt oder wenn Sie Hardware-Probleme
+bekommen, bekommen Sie Ihre Daten zurück, entweder über automatische
+Wiederherstellung oder von einer Datensicherung plus Transaktionslog-Datei.
+@item
+Sie können viele Statements kombinieren und alle in einem Rutsch mit dem
+@code{COMMIT}-Befehl akzeptieren.
+@item
+Sie können @code{ROLLBACK} ausführen, um Ihre Änderungen zu ignorieren
+(wenn Sie nicht im Auto-Commit-Modus fahren).
+@item
+Wenn eine Aktualisierung fehlschlägt, werden Ihre Änderungen
+zurückgesichert. (Bei nicht transaktionssicheren Tabellen sind
+durchgeführte Änderungen permanent.)
+@end itemize
+
+Vorteile nicht transaktionssicherer Tabellen (NTST):
+
+@itemize @bullet
+@item
+Viel schneller, da es keinen Transaktionsoverhead gibt.
+@item
+Benötigen aufgrund des fehlenden Transaktionsoverheads weniger
+Speicherplatz.
+@item
+Benötigen weniger Arbeitsspeicher für Aktualisierungen.
+@end itemize
+
+Sie können TST- and NTST-Tabellen in denselben Statements kombinieren, um
+das Beste aus beiden Welten zu bekommen.
+
+
+
+@menu
+* MyISAM::
+* MERGE::
+* ISAM::
+* HEAP::
+* InnoDB::
+* BDB::
+@end menu
+
+@node MyISAM, MERGE, Table types, Table types
+@c German node MyISAM
+@section MyISAM-Tabellen
+
+@code{MyISAM} ist der vorgabemäßige Tabellentyp in MySQL-Version 3.23. Er
+basiert auf dem @code{ISAM}-Code und hat viele nützliche Erweiterungen.
+
+Der Index wird in einer Datei mit der Endung @code{.MYI} (MYIndex)
+gespeichert, die Daten in einer Datei mit der Endung @code{.MYD} (MYData).
+Sie können @code{MyISAM}-Tabellen mit dem @code{myisamchk}-Dienstprogramm
+überprüfen und reparieren. @xref{Repair}. Sie können
+@code{MyISAM}-Tabellen mit @code{myisampack} komprimieren, damit sie viel
+weniger Speicherplatz benötigen. @xref{myisampack}.
+
+Folgende Neuerungen gibt es bei @code{MyISAM}:
+
+@itemize @bullet
+@item
+Es gibt einen Flag in der @code{MyISAM}-Datei, der anzeigt, ob die Tabelle
+korrekt geschlossen wurde. Wenn @code{mysqld} mit @code{--myisam-recover}
+gestartet wird, werden @code{MyISAM}-Tabellen beim Öffnen automatisch
+geprüft und / oder repariert, falls die Tabelle nicht korrekt geschlossen
+wurde.
+@item
+Sie können neue Zeilen in eine Tabelle, die keinerlei freie Blöcke mitten
+in der Daten-Datei hat, einfügen (@code{INSERT}), während zeitgleich
+andere Threads aus der Tabelle lesen (zeitgleiches Einfügen). Ein freier
+Block kann entstehen, wenn eine Aktualisierung einer Zeile dynamischer
+Länge, die viele Daten enthält, mit weniger Daten durchgeführt wird, oder
+wenn Zeilen gelöscht werden. Wenn alle freien Blöcke aufgebraucht sind,
+können alle zukünftigen Einfügeoperationen auf die zeitgleiche Art
+erfolgen.
+@item
+Unterstützung für große Dateien (63-Bit) auf Dateisystemen /
+Betriebssystemen, die große Dateien unterstützen.
+@item
+Alle Daten werden mit dem niedrigen Byte zuerst gespeichert. Das macht die
+Daten Maschinen- und Betriebssystem-unabhängig. Die einzige Anforderung
+ist, dass die Maschine zweien-komplementäre vorzeichenbehaftete Ganzzahlen
+(two's-complement signed integers) benutzt, was bei jeder Maschine in den
+letzten 20 Jahren der Fall war), sowie das IEEE-Fließkomma-Format (bei
+Mainstream-Maschinen absolut dominierend). Die einzige Art von Maschinen,
+die vielleicht keine Binärkompatibilität unterstützen, sind eingebettete
+Systeme (Embedded Systems), weil diese manchmal eigentümliche Prozessoren
+haben.
+
+Wenn Daten mit dem niedrigen Byte zuerst gespeichert werden, ergibt sich
+daraus kein großer Geschwindigkeitsnachteil. Die Bytes in einer
+Tabellenzeile sind normalerweise unzusammenhängend und man benötigt kaum
+mehr Ressourcen, um ein unzusammenhängendes Byte in Reihenfolge statt in
+umgekehrter Reihenfolge zu lesen. Der tatsächliche Hole-Spaltenwert-Code
+ist im Vergleich zu sonstigem Code ebenfalls nicht zeitkritisch.
+@item
+Alle Zahlenschlüssel werden mit dem hohen Byte zuerst gespeichert, um
+bessere Index-Kompression zu erzielen.
+@item
+Die interne Handhabung einer @code{AUTO_INCREMENT}-Spalte. @code{MyISAM}
+aktualisiert diese automatisch bei @code{INSERT / UPDATE}. Der
+@code{AUTO_INCREMENT}-Wert kann mit @code{myisamchk} zurückgesetzt werden.
+Das macht @code{AUTO_INCREMENT}-Spalten schneller (mindestens 10%), und
+alten Zahlen werden im Gegensatz zum alten @code{ISAM} nicht wieder
+benutzt. Beachten Sie, dass das alte Verhalten immer noch da ist, wenn ein
+@code{AUTO_INCREMENT} am Ende eines mehrteiligen Schlüssels definiert wird.
+@item
+Wenn er in sortierter Reihenfolge eingefügt wird (wie bei der Benutzung
+einer @code{AUTO_INCREMENT}-Spalte), wird der Schlüsselbaum gespalten, so
+dass der hohe Knoten nur einen Schlüssel enthält. Das verbessert die
+Platzausnutzung im Schlüsselbaum.
+@item
+@code{BLOB}- und @code{TEXT}-Spalten können indiziert werden.
+@item
+@code{NULL}-Werte sind in indizierten Spalten erlaubt. Dafür werden 0 bis 1
+Byte pro Schlüssel benötigt.
+@item
+Die maximale Schlüssellänge beträgt vorgabemäßig 500 Bytes (das kann beim
+Neukompilieren geändert werden). Wenn Schlüssel länger als 250 Bytes sind,
+wird für diese eine höhere Schlüsselblockgröße als die vorgabemäßigen
+1024 Bytes benutzt.
+@item
+Die maximale Anzahl von Schlüsseln pro Tabelle beträgt vorgabemäßig 32.
+Diese kann bis auf 64 erhöht werden, ohne dass @code{myisamchk} neu
+kompiliert werden muss.
+@item
+@code{myisamchk} kennzeichnet Tabellen als geprüft, wenn es mit
+@code{--update-state} läuft. @code{myisamchk --fast} prüft nur die
+Tabellen, die diese Kennzeichnung nicht haben.
+@item
+@code{myisamchk -a} speichert Statistiken für Schlüsselteile (und nicht nur
+für gesamte Schlüssel wie bei @code{ISAM}).
+@item
+Zeilen dynamischer Größe werden viel weniger fragmentiert werden, wenn
+Lösch- mit Aktualisierungs- und Einfügeoperationen gemischt werden. Dafür
+wird gesorgt, indem angrenzende gelöschte Blöcke automatisch kombiniert
+werden und dadurch, dass Blöcke erweitert werden, wenn der nächste Block
+gelöscht wird.
+@item
+@code{myisampack} kann @code{BLOB}- and @code{VARCHAR}-Spalten
+komprimieren.
+@item
+Sie können die Daten-Datei und die Index-Datei in unterschiedliche
+Verzeichnisse legen, um mehr Geschwindigkeit zu erhalten (mit der
+@code{DATA/INDEX DIRECTORY="pfad"}-Option für @code{CREATE TABLE}).
+@xref{CREATE TABLE}.
+@end itemize
+
+@code{MyISAM} unterstützt ausserdem die folgenden Dinge, die MySQL in naher
+Zukunft benutzen können wird:
+
+@itemize @bullet
+@item
+Unterstützung für einen echten @code{VARCHAR}-Typ. Eine
+@code{VARCHAR}-Spalte fängt mit einer in 2 Bytes gespeicherten Länge an.
+@item
+Tabellen mit @code{VARCHAR} können eine feste oder dynamische
+Datensatzlänge haben.
+@item
+@code{VARCHAR} und @code{CHAR} können bis zu 64 KB Groß sein. Alle
+Schlüsselsegmente haben ihre eigene Sprachdefinition. Das versetzt MySQL in
+die Lage, unterschiedliche Sprachdefinitionen pro Spalte zu haben.
+@item
+Ein gehashter berechneter Index kann für @code{UNIQUE} benutzt werden. Das
+erlaubt Ihnen, @code{UNIQUE} auf jeder beliebigen Kombination von Spalten
+in einer Tabelle zu haben. (Sie können jedoch auf einem @code{UNIQUE}
+berechneten Index nicht suchen.)
+@end itemize
+
+Beachten Sie, dass Index-Dateien bei @code{MyISAM} üblicherweise viel
+kleiner sind als bei @code{ISAM}. Das bedeutet, dass @code{MyISAM}
+normalerweise weniger Systemressourcen verbraucht als @code{ISAM},
+allerdings mehr Prozessorleistung beim Einfügen von Daten in einen
+komprimierten Index.
+
+Folgende Optionen für @code{mysqld} können benutzt werden, um das Verhalten
+von @code{MyISAM}-Tabellen zu ändern. @xref{SHOW VARIABLES}.
+
+@multitable @columnfractions .40 .60
+@item @strong{Option} @tab @strong{Beschreibung}
+@item @code{--myisam-recover=#}
+ @tab Automatische Wiederherstellung beschädigter Tabellen.
+@item @code{-O myisam_sort_buffer_size=#}
+ @tab Der beim Wiederherstellen von Tabellen benutzte Puffer.
+@item @code{--delay-key-write-for-all-tables}
+ @tab Keine Schlüsselpuffer zwischen Schreibvorgängen auf jedwede
+MyISAM-Tabelle zurückschreiben (flush).
+@item @code{-O myisam_max_extra_sort_file_size=#}
+ @tab Wird benutzt, um MySQL bei der Entscheidung zu helfen, wann die
+langsame, aber sichere Schlüssel-Cache-Index-Erzeugungsmethode benutzt
+werden sollte. @strong{Hinweis:} Dieser Parameter wird in Megabytes
+angegeben!
+@item @code{-O myisam_max_sort_file_size=#}
+ @tab Die schnelle Index-Sortiermethode beim Erzeugen eines Indexes nicht
+benutzen, wenn die temporäre Datei größer als dieser Wert werden würde.
+@strong{Hinweis:} Dieser Parameter wird in Megabytes angegeben!
+megabytes!--
+@item @code{-O myisam_bulk_insert_tree_size=#}
+ @tab Die Größe des Baum-Caches, der bei der Optimierung von
+Massen-Einfügeoperationen benutzt wird. @strong{Hinweis:} Das ist die
+Begrenzung @strong{pro Thread}!
+@end multitable
+
+Die automatische Wiederherstellung wird aktiviert, wenn Sie @code{mysqld}
+mit @code{--myisam-recover=#} starten. @xref{Command-line options}. Beim
+Öffnen wird geprüft, ob die Tabelle als beschädigt gekennzeichnet ist oder
+ob die Zählvariable für die Tabelle nicht 0 ist und Sie mit
+@code{--skip-locking} laufen lassen. Wenn eine dieser Bedingungen erfüllt
+ist, geschieht folgendes:
+
+@itemize @bullet
+@item
+Die Tabelle wird auf Fehler geprüft.
+@item
+Wenn ein Fehler gefunden wird, wird eine schnelle Reparatur der Tabelle
+versucht (mit Sortieren und ohne Neuerzeugung der Daten-Datei).
+@item
+Wenn die Reparatur wegen eines Fehlers in der Daten-Datei fehlschlägt (zum
+Beispiel ein Fehler wegen eines doppelten Schlüsseleintrags), wird die
+Reparatur noch einmal versucht, diesmal allerdings mit Neuerzeugung der
+Daten-Datei.
+@item
+Wenn dieser Versuch fehlschlägt, wird die Reparatur noch einmal mit der
+alten Reparaturoption versucht (Zeile für Zeile ohne Sortieren schreiben),
+was jede Sorte von Fehler beheben sollte, bei gewissen
+Festplatten-Erfordernissen ...
+@end itemize
+
+Wenn die Wiederherstellung nicht in der Lage ist, alle Zeilen aus einem
+vorher abgeschlossenen Statement wiederherzustellen, und Sie nicht
+@code{FORCE} als Option für @code{myisam-recover} angegeben haben, wird die
+automatische Reparatur mit einer Fehlermeldung in der Fehlerdatei
+abgebrochen:
+
+@example
+Error: Couldn't repair table: test.g00pages
+@end example
+
+Hätten Sie in diesem Fall die @code{FORCE}-Option benutzt, würden Sie statt
+dessen in der Fehlerdatei eine Warnung erhalten:
+
+@example
+Warning: Found 344 of 354 rows when repairing ./test/g00pages
+@end example
+
+Wenn Sie automatisches Wiederherstellung mit der @code{BACKUP}-Option
+laufen lassen, beachten Sie, dass Sie ein Cron-Skript haben sollten, dass
+automatisch Dateien mit Namen wie @file{tabellenname-datetime.BAK} aus den
+Datenbank-Verzeichnissen auf ein Sicherungsmedium verschiebt.
+
+@xref{Command-line options}.
+
+
+
+@menu
+* Key space::
+* MyISAM table formats::
+* MyISAM table problems::
+@end menu
+
+@node Key space, MyISAM table formats, MyISAM, MyISAM
+@c German node Speicherplatz für Schlüssel
+@subsection Für Schlüssel benötigter Speicherplatz
+
+@cindex Speicherplatz für Schlüssel, MyISAM
+
+MySQL unterstützt unterschiedliche Index-Typen, doch der normale Typ ist
+ISAM oder MyISAM. Diese benutzen einen B-Baum-Index, und Sie können die
+Größe der Index-Datei grob als @code{(schluessel_laenge+4)/0.67}
+kalkuliert, summiert über alle Schlüssel. (Das ist der schlechteste Fall,
+bei dem alle Schlüssel in sortierter Reihenfolge eingeordnet werden und es
+keinerlei Schlüssel-Komprimierung gibt.)
+
+Zeichenketten-Indexe werden Leerzeichen-komprimiert. Wenn der erste
+Index-Teil eine Zeichenkette ist, wird er zusätzlich Präfix-komprimiert.
+Leerzeichen-Kompression macht die Index-Datei kleiner als in den obigen
+Zahlen dargestellt, wenn die Zeichenkettenspalte viele Leerzeichen am Ende
+hat oder eine @code{VARCHAR}-Spalte ist, die nicht immer in voller Länge
+genutzt wird. Präfix-Kompression wird bei Schlüsseln benutzt, die mit einer
+Zeichenkette beginnen. Präfix-Kompression hilft, wenn es viele
+Zeichenketten mit identischem Präfix gibt.
+
+Bei @code{MyISAM}-Tabellen können Sie auch Zahlen Präfix-komprimieren,
+indem Sie beim Erzeugen der Tabelle @code{PACK_KEYS=1} angeben. Das hilft,
+wenn Sie viele Ganzzahl-Schlüssel mit identischem Präfix haben, wenn die
+Zahlen mit dem hohen Byte zuerst gespeichert werden.
+
+
+@node MyISAM table formats, MyISAM table problems, Key space, MyISAM
+@c German node MyISAM-Tabellenformate
+@subsection MyISAM-Tabellenformate
+
+@strong{MyISAM} unterstützt 3 verschiedene Tabellentypen. Zwei von ihnen
+werden automatisch gewählt, abhängig vom Spaltentyp, den Sie benutzen. Der
+dritte, komprimierte Tabellen, kann nur mit dem
+@code{myisampack}-Dienstprogramm erzeugt werden.
+
+Wenn Sie eine Tabelle erzeugen (@code{CREATE}) oder ändern (@code{ALTER}),
+können Sie bei Tabellen, die kein @code{BLOB} enthalten, ein dynamisches
+(@code{DYNAMIC}) oder festes (@code{FIXED}) Tabellenformat mit der
+@code{ROW_FORMAT=#}-Tabellenoption erzwingen. Zukünftig werden Sie in der
+Lage sein, Tabellen zu komprimieren / dekomprimieren, indem Sie
+@code{ROW_FORMAT=compressed | default} für @code{ALTER TABLE} angeben.
+@xref{CREATE TABLE}.
+
+
+
+@menu
+* Static format::
+* Dynamic format::
+* Compressed format::
+@end menu
+
+@node Static format, Dynamic format, MyISAM table formats, MyISAM table formats
+@c German node Statisches Format
+@subsubsection Kennzeichen statischer (Festlängen-) Tabellen
+
+Das ist das vorgabemäßige Format. Es wird benutzt, wenn die Tabelle keine
+@code{VARCHAR}-, @code{BLOB}- oder @code{TEXT}-Spalten enthält.
+
+Dieses Format ist das einfachste und sicherste Format. Es ist auch das
+schnellste der Formate auf Platte. Die Geschwindigkeit ergibt sich aus der
+einfachen Weise, wie Daten auf der Platte gefunden werden können. Wenn man
+etwas mit einem Index und statischem Format nachschlägt, ist es sehr
+einfach. Man multipliziert einfach die Zeilennummer mit der Zeilenlänge.
+
+Wenn eine Tabelle gescannt wird, ist es ausserdem sehr einfach, mit jedem
+Plattenzugriff eine konstante Anzahl von Datensätzen zu lesen.
+
+Die Sicherheit zeigt sich, wenn Ihr Computer beim Schreiben in eine
+MyISAM-Datei fester Länge abstürzt. In diesem Fall kann @code{myisamchk}
+leicht herausfinden, wo jede Zeile anfängt und aufhört. Daher kann es
+üblicherweise alle Datensätze mit Ausnahme desjenigen, in den nur teilweise
+geschrieben wurde, wieder herstellen. Beachten Sie, dass in MySQL alle
+Indexe in jedem Fall wiederhergestellt werden können:
+
+@itemize @bullet
+@item
+Alle @code{CHAR}-, @code{NUMERIC}- und @code{DECIMAL}-Spalten werden mit
+Leerzeichen auf die Spaltenbreite aufgefüllt.
+@item
+Sehr schnell.
+@item
+Leicht zu cachen.
+@item
+Nach einem Absturz leicht zu rekonstruieren, weil sich Datensätze an festen
+Positionen befinden.
+@item
+müssen nicht (mit @code{myisamchk}) reorganisiert werden, es sei denn, eine
+riesige Anzahl von Datensätzen wurde gelöscht und Sie wollen dem
+Betriebssystem freien Speicherplatz zurückgeben.
+@item
+Benötigen normalerweise mehr Speicherplatz als dynamische Tabellen.
+@end itemize
+
+
+@node Dynamic format, Compressed format, Static format, MyISAM table formats
+@c German node Dynamisches Format
+@subsubsection Kennzeichen dynamischer Tabellen
+
+@cindex Kennzeichen dynamischer Tabellen
+@cindex Tabellen, dynamische
+
+Dieses Format wird benutzt, wenn die Tabelle irgend welche @code{VARCHAR}-,
+@code{BLOB}- oder @code{TEXT}-Spalten enthält, oder wenn die Tabelle mit
+@code{ROW_FORMAT=dynamic} erzeugt wurde.
+
+Dieses Format ist etwas komplexer, weil jede Zeile einen Header haben muss,
+der aussagt, wie lang sie ist. Ein Datensatz kann ausserdem an mehr als
+einem Speicherplatz enden, wenn er bei einer Aktualisierung verlängert
+wird.
+
+@cindex Tabellen, defragmentieren
+Sie können @code{OPTIMIZE table} oder @code{myisamchk} benutzen, um eine
+Tabelle zu defragmentieren. Wenn Sie statische Daten haben, auf die Sie oft
+zugreifen oder die Sie in derselben Tabelle oft ändern, als @code{VARCHAR}-
+oder @code{BLOB}-Spalten haben, ist es eine gute Idee, die dynamischen
+Spalten in andere Tabellen zu verschieben, einfach um Fragmentierung zu
+vermeiden:
+
+@itemize @bullet
+@item
+Alle Zeichenketten-Spalten sind dynamisch (ausser denen mit einer Länge
+kleiner 4).
+@item
+Jedem Datensatz ist eine Bitmap vorangestellt, die angibt, welche Spalten
+bei Zeichenketten-Spalten leer (@code{''}) sind oder 0 bei numerischen
+Spalten. (Das ist nicht dasselbe wie Spalten, die @code{NULL}-Werte
+enthalten.) Wenn eine Zeichenketten-Spalte nach der Entfernung von
+Leerzeichen am Ende eine Länge von 0 hat oder eine numerische Spalte einen
+Wert von 0 hat, wird sie in der Bitmap markiert und nicht auf Platte
+gespeichert. Nicht leere Zeichenketten werden als ein Längen-Byte plus dem
+Zeichenketten-Inhalt gespeichert.
+@item
+Benötigen üblicherweise weniger Plattenplatz als Festlängen-Tabellen.
+@item
+Jeder Datensatz benutzt nur so viel Speicherplatz wie erforderlich. Wenn
+ein Datensatz größer wird, wird er in so viele Teile wie erforderlich
+aufgeteilt. Hierdurch wird Datensatzfragmentierung hervorgerufen.
+@item
+Wenn Sie eine Zeile mit Informationen aktualisieren, die die Zeilenlänge
+überschreiten, wird die Zeile fragmentiert. In diesem Fall sollten Sie von
+Zeit zu Zeit @code{myisamchk -r} laufen lassen, um bessere Performance zu
+erzielen. Benutzen Sie @code{myisamchk -ei tabellen_name}, um einige
+statistische Informationen zu erhalten.
+@item
+Sind nach einem Absturz nicht so einfach zu rekonstruieren, weil ein
+Datensatz in viele Teile fragmentiert sein und ein Link (Fragment) fehlen
+kann.
+@item
+Die erwartete Zeilenlänge bei Datensätzen dynamischer Länge ist:
+
+@example
+3
++ (anzahl_der_spalten + 7) / 8
++ (anzahl_der_zeichenketten_spalten)
++ komprimierte_groesse_numerischer_spalten
++ laenge_von_zeichenketten
++ (anzahl_von_NULL_spalten + 7) / 8
+@end example
+
+Für jeden Link kommen 6 Bytes hinzu. Ein dynamischer Datensatz wird immer
+dann verknüpft (linked), wenn eine Aktualisierung eine Vergrößerung des
+Datensatzes bewirkt. Jede neue Verknüpfung hat mindestens 20 Bytes, so dass
+die nächste Vergrößerung wahrscheinlich in dieselbe Verknüpfung passt.
+Wenn nicht, entsteht eine weitere Verknüpfung. Sie können mit
+@code{myisamchk -ed} prüfen, wie viele Verknüpfungen es gibt. Alle
+Verknüpfungen können mit @code{myisamchk -r} entfernt werden.
+@end itemize
+
+
+@node Compressed format, , Dynamic format, MyISAM table formats
+@c German node Komprimiertes Format
+@subsubsection Kennzeichen komprimierter Tabellen
+
+@cindex Tabellen, komprimiertes Format
+
+Das ist ein Nur-Lese-Typ, der mit dem optionalen
+@code{myisampack}-Dienstprogramm (@code{pack_isam} für
+@code{ISAM}-Tabellen) erzeugt wird:
+
+@itemize @bullet
+@item
+All MySQL-Distributionen, selbst diejenigen, die es vor der GPL-Version von
+MySQL gab, können Tabellen lesen, die mit @code{myisampack} komprimiert
+wurden.
+@item
+Komprimierte Tabellen benötigen viel weniger Speicherplatz. Das minimiert
+Plattenzugriffe, was sehr nett ist, wenn Sie langsame Platten benutzen (wie
+CD-ROMs).
+@item
+Jeder Datensatz wird separat komprimiert (sehr geringer Zugriffs-Overhead).
+Der Header für einen Datensatz hat eine feste Länge (1 bis 3 Bytes),
+abhängig vom größten Datensatz in der Tabelle. Jede Spalte wird
+unterschiedlich komprimiert. Einige Kompressionstypen sind:
+@itemize @minus
+@item
+Für jede Spalte gibt es üblicherweise eine unterschiedliche
+Huffman-Tabelle.
+@item
+Komprimierung von Leerzeichen am Ende.
+@item
+Komprimierung von Leerzeichen am Anfang.
+@item
+Zahlen mit dem Wert @code{0} werden mit 1 Bit gespeichert.
+@item
+Wenn Werte in einer Ganzzahl-Spalte einen kleinen Wertebereich haben, wird
+die Spalte mit dem kleinsten möglichen Typ gespeichert. Eine
+@code{BIGINT}-Spalte (8 Bytes) kann beispielsweise als
+@code{TINYINT}-Spalte (1 Byte) gespeichert werden, wenn sich alle Werte im
+Bereich von @code{0} bis @code{255} befinden.
+@item
+Wenn eine Spalte nur einen kleinen Satz möglicher Werte besitzt, wird der
+Spaltentyp zu @code{ENUM} umgewandelt.
+@item
+Eine Spalte kann auch eine Kombination der obigen Komprimierungen benutzen.
+@end itemize
+@item
+Kann Datensätze fester oder dynamischer Länge handhaben, aber nicht
+@code{BLOB}- oder @code{TEXT}-Spalten.
+@item
+Kann mit @code{myisamchk} dekomprimiert werden.
+@end itemize
+
+
+@node MyISAM table problems, , MyISAM table formats, MyISAM
+@c German node MyISAM-Tabellenprobleme
+@subsection MyISAM-Tabellenprobleme
+
+Das Dateiformat, das MySQL benutzt, um Daten zu speichern, wurde ausgiebig
+getestet, aber es gibt immer Umstände, die dazu führen können, dass
+Datenbanktabellen beschädigt werden.
+
+
+
+@menu
+* Corrupted MyISAM tables::
+* MyISAM table close::
+@end menu
+
+@node Corrupted MyISAM tables, MyISAM table close, MyISAM table problems, MyISAM table problems
+@c German node Beschädigte MyISAM-Tabellen
+@subsubsection Beschädigte MyISAM-Tabellen
+
+Obwohl das MyISAM-Tabellenformat sehr zuverlässig ist (alle Änderungen an
+einer Tabelle werden geschrieben, bevor das SQL-Statement zurückkehrt),
+können Sie dennoch beschädigte Tabellen bekommen, wenn eines der folgenden
+Dinge passiert:
+
+@itemize @bullet
+@item
+Der @code{mysqld}-Prozess wird mitten in einem Schreibvorgang gekillt.
+@item
+Unerwartetes Herunterfahren des Computers (wenn der Computer beispielsweise
+abgeschaltet wird).
+@item
+Ein Hardware-Fehler.
+@item
+Sie benutzen ein externes Programm (wie myisamchk) auf einer benutzten
+Tabelle.
+@item
+Ein Software-Bug im MySQL- oder MyISAM-Code.
+@end itemize
+
+Typische Symptome einer beschädigten Tabelle sind:
+
+@itemize @bullet
+@item
+Sie erhalten den Fehler @code{Incorrect key file for table: '...'. Try to
+repair it}, wenn Sie Daten aus der Tabelle auswählen.
+@item
+Anfragen finden keine Zeilen in der Tabelle oder geben unvollständige Daten
+zurück.
+@end itemize
+
+Sie können mit dem Befehl @code{CHECK TABLE} prüfen, ob eine Tabelle in
+Ordnung ist. @xref{CHECK TABLE}.
+
+Sie können eine beschädigte Tabelle mit @code{REPAIR TABLE} reparieren.
+@xref{REPAIR TABLE}. Wenn @code{mysqld} nicht läuft, können Sie eine
+Tabelle auch mit dem @code{myisamchk}-Befehl reparieren.
+@code{myisamchk-Syntax}.
+
+Wenn Ihre Tabellen oft beschädigt werden, sollten Sie versuchen, den Grund
+dafür herauszufinden! @xref{Crashing}.
+
+In diesem Fall ist es am wichtigsten zu wissen, ob die Tabelle durch einen
+Absturz von @code{mysqld} beschädigt wurde (das können Sie leicht
+feststellen, wenn es eine aktuelle Zeile @code{restarted mysqld} in der
+mysqld-Fehlerdatei gibt). Wenn das nicht der Fall ist, sollten Sie
+versuchen, daraus einen Testfall zu machen. @xref{Reproduceable test case}.
+
+
+@node MyISAM table close, , Corrupted MyISAM tables, MyISAM table problems
+@c German node MyISAM-Tabellenschließen
+@subsubsection Client benutzt Tabelle oder hat sie nicht korrekt geschlossen
+
+Jede @code{MyISAM}-@code{.MYI}-Datei hat im Header einen Zähler, der
+benutzt werden kann, um zu prüfen, ob die Tabelle korrekt geschlossen
+wurde.
+
+Wenn Sie folgende Warnmeldung von @code{CHECK TABLE} oder @code{myisamchk}
+erhalten:
+
+@example
+# client is using or hasn't closed the table properly
+@end example
+
+heißt das, dass der Zähler nicht mehr synchron ist. Das bedeutet nicht,
+dass die Tabelle beschädigt ist, aber Sie sollten zumindest eine
+Überprüfung vornehmen, um sicherzustellen, dass die Tabelle in Ordnung ist.
+
+Der Zähler funktioniert wie folgt:
+
+@itemize @bullet
+@item
+Wenn die Tabelle das erste Mal in MySQL aktualisiert wird, wird der Zähler
+im Header der Index-Dateien heraufgezählt.
+@item
+Der Zähler wird während weiterer Aktualisierungen nicht verändert.
+@item
+Wenn die letzte Instanz einer Tabelle geschlossen wird (wegen eines
+@code{FLUSH} oder weil es nicht mehr genug Platz im Tabellen-Cache gibt),
+wird der Zähler heruntergezählt, wenn die Tabelle zu irgend einem Zeitpunkt
+aktualisiert wurde.
+@item
+Wenn Sie eine Tabelle reparieren oder prüfen und sie in Ordnung ist, wird
+der Zähler auf 0 zurückgesetzt.
+@item
+Um Probleme zu vermeiden, die durch Interaktion mit anderen Prozessen
+entstehen, die vielleicht eine Prüfung der Tabelle durchführen, wird der
+Zähler beim Schließen nicht heruntergezählt, wenn er 0 war.
+@end itemize
+
+Mit anderen Worten kann der Zähler nur in folgenden Fällen nicht mehr
+synchron sein:
+
+@itemize @bullet
+@item
+Die @code{MyISAM}-Tabellen werden ohne @code{LOCK} und @code{FLUSH TABLES}
+kopiert.
+@item
+MySQL ist zwischen einer Aktualisierung und dem endgültigen Schließen
+abgestürzt. (Beachten Sie, dass die Tabelle trotzdem in Ordnung sein kann,
+weil MySQL stets für alles zwischen jedem Statement Schreibvorgänge
+durchführt.
+@item
+Jemand hat @code{myisamchk --repair} oder @code{myisamchk --update-state}
+auf eine Tabelle ausgeführt, die durch @code{mysqld} in Benutzung war.
+@item
+Viele @code{mysqld}-Server benutzen die Tabelle und einer davon hat
+@code{REPAIR} oder @code{CHECK} der Tabelle ausgeführt, während sie durch
+einen anderen Server in Benutzung war. Hierbei kann @code{CHECK} sicher
+ausgeführt werden (selbst wenn Sie Warnungen von anderen Servern erhalten
+werden), aber @code{REPAIR} sollte vermieden werden, weil es momentan die
+Daten-Datei durch eine neue ersetzt, was anderen Servern nicht signalisiert
+wird.
+@end itemize
+
+
+@node MERGE, ISAM, MyISAM, Table types
+@c German node MERGE
+@section MERGE-Tabellen
+
+@cindex Tabellen, Merge-
+@cindex MERGE-Tabellen, Definition
+
+@code{MERGE}-Tabellen sind neu seit MySQL-Version 3.23.25. Der Code ist
+noch Gamma, sollte aber ausreichend stabil sein.
+
+Eine @code{MERGE}-Tabelle (auch bekannt als @code{MRG_MyISAM}-Tabelle) ist
+eine Sammlung identischer @code{MyISAM}-Tabellen, die wie eine benutzt
+werden können. Sie können auf dieser Sammlung von Tabellen nur
+@code{SELECT}, @code{DELETE} und @code{UPDATE} ausführen. Wenn Sie eine
+@code{MERGE}-Tabelle löschen (@code{DROP}), löschen Sie nur die
+@code{MERGE}-Spezifikation.
+
+Beachten Sie, dass @code{DELETE FROM merge_tabelle} ohne @code{WHERE} nur
+das Mapping für die Tabelle löscht, nicht alles in den gemappten Tabellen.
+(Geplant ist, das in Version 4.1 zu beheben.)
+
+Mit identischen Tabellen ist gemeint, dass alle Tabellen mit identischen
+Spalten- und Schlüsselinformationen erzeugt wurden. Sie können kein MERGE
+auf Tabellen ausführen, deren Spalten unterschiedlich komprimiert sind,
+nicht genau dieselben Spalten oder die Schlüssel in unterschiedlicher
+Reihenfolge haben. Einige der Tabellen können jedoch mit @code{myisampack}
+komprimiert sein. @xref{myisampack}.
+
+Wenn Sie eine @code{MERGE}-Tabelle erzeugen, erhalten Sie eine
+@code{.frm}-Tabellendefinitionsdatei und eine
+@code{.MRG}-Tabellenlistendatei. Die @code{.MRG} enthält lediglich eine
+Liste der Index-Dateien (@code{.MYI}-Dateien), die wie eine benutzt werden
+sollen. Alle benutzten Tabellen müssen in derselben Datenbank wie die
+@code{MERGE}-Tabelle selbst sein.
+
+Momentan benötigen Sie @code{SELECT}-, @code{UPDATE}- und
+@code{DELETE}-Berechtigungen für die Tabellen, die Sie auf eine
+@code{MERGE}-Tabelle mappen.
+
+@code{MERGE}-Tabellen können bei der Lösung folgender Probleme helfen:
+
+@itemize @bullet
+@item
+Auf einfache Weise einen Satz von Log-Tabellen verwalten. Beispielsweise
+können Sie Daten aus unterschiedlichen Monaten in separaten Dateien
+speichern, einige davon mit @code{myisampack} komprimieren und dann eine
+@code{MERGE}-Tabelle erzeugen, um sie wie eine zu benutzen.
+@item
+Mehr Geschwindigkeit. Sie können eine große Nur-Lese-Tabelle nach
+bestimmten Kriterien aufspalten und die verschiedenen Tabellenteile auf
+unterschiedlichen Festplatten speichern. Eine @code{MERGE}-Tabelle darauf
+könnte viel schneller sein als die große Tabelle zu benutzen. (Natürlich
+können Sie auch ein RAID benutzen, um dieselben Vorteile zu erzielen.)
+@item
+Effizientere Suchen durchführen. Wenn Sie genau wissen, wonach Sie suchen,
+können Sie mit einigen Anfragen in lediglich einer der aufgespaltenen
+Tabellen suchen und die @strong{MERGE}-Tabelle für andere benutzen. Es
+können sogar viele unterschiedliche @code{MERGE}-Tabellen aktiv sein,
+möglicherweise mit Dateien, die sich überlappen.
+@item
+Effizientere Reparaturen durchführen. Es ist leichter, die individuellen
+Dateien zu reparieren, die auf eine @code{MERGE}-Datei gemappt sind, als
+eine wirklich große Datei zu reparieren.
+@item
+Sofortiges Mappen vieler Dateien als einer. Eine @code{MERGE}-Tabelle
+benutzt den Index der individuellen Tabellen. Sie muss selbst keinen
+eigenen Index warten. Dadurch können Sie @code{MERGE}-Tabellensammlungen
+SEHR schnell erzeugen oder neu mappen. Beachten Sie, dass Sie die
+Schlüsseldefinitionen angeben, wenn Sie eine @code{MERGE}-Tabelle erzeugen!
+@item
+Wenn Sie einen Satz von Tabellen bei Bedarf oder im Stapel zu einer großen
+Tabelle vereinigen, sollten Sie statt dessen bei Bedarf eine
+@code{MERGE}-Tabelle darauf erzeugen. Das ist viel schneller und spart eine
+Menge Speicherplatz.
+@item
+Umgehen der Dateigrößengrenze des Betriebssystems.
+@item
+Sie können ein Alias / Synonym für eine Tabelle erzeugen, indem Sie sie
+einfach ein MERGE über eine Tabelle benutzen. Das sollte keine spürbaren
+Performance-Auswirkungen haben (nur eine Reihe indirekter Aufrufen und
+memcpy's bei jedem Lesen).
+@end itemize
+
+Die Nachteile von @code{MERGE}-Tabellen sind:
+
+@itemize @bullet
+@item
+Sie können nur identische @code{MyISAM}-Tabellen für eine
+@code{MERGE}-Tabelle benutzen.
+@item
+@code{AUTO_INCREMENT}-Spalten werden bei @code{INSERT} nicht automatisch
+aktualisiert.
+@item
+@code{REPLACE} funktioniert nicht.
+@item
+@code{MERGE}-Tabellen benutzen mehr Datei-Deskriptoren. Wenn Sie eine
+@strong{MERGE} benutzen, die über 10 Tabellen mappt, und 10 Benutzer diese
+benutzen, benötigen Sie 10 * 10 + 10 Datei-Deskriptoren (10 Daten-Dateien
+für 10 Benutzer und 10 gemeinsam genutzte Index-Dateien).
+@item
+Lesevorgänge von Schlüsseln sind langsamer. Wenn Sie eine Leseoperation auf
+einen Schlüssel durchführen, muss der @code{MERGE}-Handler ein Lesen auf
+alle zugrunde liegenden Tabellen ausführen, um zu prüfen, welche am
+nächsten zum angegebenen Schlüssel passt. Wenn Sie ein 'Lese nächsten'
+ausführen, muss der @code{MERGE}-Handler die Lese-Puffer durchsuchen, um
+den nächsten Schlüssel zu finden. Erst wenn ein Schlüsselpuffer
+aufgebraucht ist, muss der Handler den nächsten Schlüsselblock lesen. Das
+macht @code{MERGE}-Schlüssel bei @code{eq_ref}-Suchen viel langsamer, aber
+nicht viel langsamer bei @code{ref}-Suchen.
+@xref{EXPLAIN}.
+@item
+Sie können kein @code{DROP TABLE}, @code{ALTER TABLE} oder @code{DELETE
+FROM tabelle} ohne eine @code{WHERE}-Klausel auf jeder Tabelle, die von
+einer @code{MERGE}-Tabelle gemappt ist, ausführen, wenn diese 'offen' ist.
+Wenn Sie das tun, könnte die @code{MERGE}-Tabelle immer noch auf die
+Originaltabelle verweisen, und Sie würden unerwartete Ergebnisse erhalten.
+@end itemize
+
+Wenn Sie eine @code{MERGE}-Tabelle erzeugen, müssen Sie mit
+@code{UNION(liste-von-tabellen)} angeben, welche Tabellen Sie wie eine
+benutzen wollen. Optional können Sie mit @code{INSERT_METHOD} angeben, ob
+Sie wollen, dass Einfügungen in die @code{MERGE}-Tabelle in der ersten oder
+der letzten Tabelle in der @code{UNION}-Liste geschehen sollen. Wenn Sie
+keine @code{INSERT_METHOD} oder @code{NO} angeben, geben alle
+@code{INSERT}-Befehle auf die @code{MERGE}-Tabelle einen Fehler zurück.
+
+Folgendes Beispiel zeigt, wie Sie @code{MERGE}-Tabellen benutzen:
+
+@example
+CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY, nachricht CHAR(20));
+CREATE TABLE t2 (a INT AUTO_INCREMENT PRIMARY KEY, nachricht CHAR(20));
+INSERT INTO t1 (nachricht) VALUES ("test"),("tabelle"),("t1");
+INSERT INTO t2 (nachricht) VALUES ("test"),("tabelle"),("t2");
+CREATE TABLE gesamt (a INT NOT NULL, nachricht CHAR(20), KEY(a)) TYPE=MERGE UNION=(t1,t2) INSERT_METHOD=LAST;
+@end example
+
+Beachten Sie, dass wir keinen @code{UNIQUE}- oder @code{PRIMARY
+KEY}-Schlüssel in der @code{gesamt}-Tabelle angegeben haben, weil der
+Schlüssel in der @code{gesamt}-Tabelle nicht eindeutig sein wird.
+
+Beachten Sie auch, dass Sie die @code{.MRG}-Datei direkt von ausserhalb des
+MySQL-Servers manipulieren können:
+
+@example
+shell> cd /mysql-data-verzeichnis/aktuelle-datenbank
+shell> ls -1 t1.MYI t2.MYI > gesamt.MRG
+shell> mysqladmin flush-tables
+@end example
+
+Jetzt können Sie Dinge wie folgendes tun:
+
+@example
+mysql> select * from gesamt;
++---+-----------+
+| a | nachricht |
++---+-----------+
+| 1 | test |
+| 2 | table |
+| 3 | t1 |
+| 1 | test |
+| 2 | table |
+| 3 | t2 |
++---+-----------+
+@end example
+
+Um eine @code{MERGE}-Tabelle neu zu mappen, können Sie folgendes tun:
+
+@itemize @bullet
+@item
+Die Tabelle löschen (@code{DROP}) und neu erzeugen.
+@item
+@code{ALTER TABLE tabelle UNION(...)} benutzen.
+@item
+Die @code{.MRG}-Datei ändern und ein @code{FLUSH TABLE} auf die
+@code{MERGE}-Tabelle und alle zugrunde liegenden Tabellen ausführen, um den
+Handler zu zwingen, die neue Definitionsdatei einzulesen.
+@end itemize
+
+
+@menu
+* MERGE table problems::
+@end menu
+
+@node MERGE table problems, , MERGE, MERGE
+@c German node MERGE-Tabellenprobleme
+@subsection MERGE-Tabellenprobleme.
+
+Folgende Probleme sind bei @code{MERGE}-Tabellen bekannt:
+
+@itemize @bullet
+@item
+@code{DELETE FROM merge_tabelle} ohne @code{WHERE} löscht nur das Mapping
+für die Tabelle, nicht alles in den gemappten Tabellen.
+@item
+@code{RENAME TABLE} auf eine Tabelle, die in einer aktiven
+@code{MERGE}-Tabelle benutzt wird, kann die Tabelle beschädigen. Das wird
+in MySQL 4.0.x behoben.
+@item
+Beim Erzeugen einer Tabelle des Typs @code{MERGE} wird nicht geprüft, ob
+die zugrunde liegenden Tabellen kompatible Typen sind. Wenn Sie
+@code{MERGE}-Tabellen in dieser Weise benutzen, ist es sehr wahrscheinlich,
+dass merkwürdige Probleme auftauchen.
+@item
+Wenn Sie @code{ALTER TABLE} benutzen, um als erstes eine
+@code{UNIQUE}-Index zu einer Tabelle hinzuzufügen, die in einer
+@code{MERGE}-Tabelle benutzt wird, und dann @code{ALTER TABLE} benutzen, um
+einen normalen Index auf die @code{MERGE}-Tabelle hinzuzufügen, wird die
+Schlüssel-Reihenfolge für die Tabellen anders sein, wenn es einen alten,
+nicht eindeutigen Schlüssel in der Tabelle gab. Das liegt daran, dass
+@code{ALTER TABLE} @code{UNIQUE}-Schlüssel vor normale Schlüssel einfügt,
+um in der Lage zu sein, doppelte Schlüsseleinträge so früh wie möglich zu
+erkennen.
+@item
+Der Bereichsoptimierer kann @code{MERGE}-Tabellen noch nicht effizient
+benutzen und kann manchmal nicht optimale Joins produzieren. Das wird in
+MySQL 4.0.x behoben.
+@item
+@code{DROP TABLE} auf eine Tabelle, die in einer @code{MERGE}-Tabelle
+benutzt wird, funktioniert unter Windows nicht, weil der
+@code{MERGE}-Handler das Tabellen-Mapping versteckt vor der oberen Ebene
+von MySQL durchführt. Weil Windows es nicht zuläßt, dass Dateien gelöscht
+werden, die offen sind, müssen Sie zuerst alle @code{MERGE}-Tabellen auf
+Platte zurückschreiben (mit @code{FLUSH TABLES}) oder die
+@code{MERGE}-Tabelle löschen, bevor Sie die Tabelle löschen. Das wird zu
+dem Zeitpunkt behoben, wenn Sichten (@code{VIEW}s) eingeführt werden.
+@end itemize
+
+@node ISAM, HEAP, MERGE, Table types
+@c German node ISAM
+@section ISAM-Tabellen
+
+@cindex tables, ISAM
+
+Sie können auch den veralteten @code{ISAM}-Tabellentyp benutzen. Dieser
+wird recht bald verschwinden (wahrscheinlich in MySQL 4.1), weil
+@code{MyISAM} eine bessere Implementation derselbe Sache ist. @code{ISAM}
+benutzt einen @code{B-tree}-Index. Der Index wird in einer Datei mit der
+Endung @code{.ISM} gespeichert, und die Daten in einer Datei mit der Endung
+@code{.ISD}. Sie können @code{ISAM}-Tabellen mit dem
+@code{isamchk}-Dienstprogramm prüfen / reparieren. @xref{Disaster Prevention}.
+
+@code{ISAM} hat folgende Features / Eigenschaften:
+
+@itemize @bullet
+@item Komprimierte und Festlängen-Schlüssel
+@item Feste und dynamische Datensatzlängen
+@item 16 Schlüssel mit 16 Schlüsselteilen pro Schlüssel
+@item Maximale Schlüssellänge 256 (Vorgabe)
+@item Daten werden im Maschinenformat gespeichert. Das ist schnell, aber
+Maschinen- / Betriebssystem-abhängig.
+@end itemize
+
+Die meisten Dinge, die für @code{MyISAM}-Tabellen gelten, gelten auch für
+@code{ISAM}-Tabellen. @xref{MyISAM}. Die größten Unterschiede im Vergleich
+zu @code{MyISAM} sind:
+
+@itemize @bullet
+@item @code{ISAM}-Tabellen sind nicht binärportabel zwischen verschiedenen
+Betriebssystemen / Plattformen.
+@item Handhabt keine Tabellen > 4 GB.
+@item Unterstützt nur Präfix-Komprimierung von Zeichenketten.
+@item Kleinere Schlüssel-Beschränkungen.
+@item Dynamische Tabelle werden schneller fragmentiert.
+@item Tabellen werden mit @code{pack_isam} statt mit @code{myisampack}
+komprimiert.
+@end itemize
+
+Wenn Sie eine @code{ISAM}-Tabelle in eine @code{MyISAM}-Tabelle umwandeln
+wollen, können Sie Dienstprogramme wie @code{mysqlcheck} oder ein
+@code{ALTER TABLE}-Statement benutzen:
+
+@example
+mysql> ALTER TABLE tabelle TYPE = MYISAM;
+@end example
+
+Die eingebetteten (embedded) MySQL-Versionen unterstützen keine
+@code{ISAM}-Tabellen.
+
+@node HEAP, InnoDB, ISAM, Table types
+@c German node HEAP
+@section HEAP-Tabellen
+
+@cindex Tabellen, @code{HEAP}
+
+@code{HEAP}-Tabellen benutzen eine gehashten Index und werden im
+Arbeitsspeicher gespeichert. Das macht sie sehr schnell, aber wenn MySQL
+abstürzt, verlieren Sie alle darin gespeicherten Daten. @code{HEAP} ist
+sehr nützlich für temporäre Tabellen.
+
+Die MySQL-internen @code{HEAP}-Tabellen benutzen 100% dynamisches Hashen
+ohne Overflow-Bereiche. Es wird kein zusätzlicher Platz für freie Listen
+benötigt. @code{HEAP}-Tabellen haben auch keine Probleme mit Löschen plus
+Einfügen, was normalerweise bei gehashten Tabellen häufig vorkommt:
+
+@example
+mysql> CREATE TABLE test TYPE=HEAP SELECT ip,SUM(downloads) as down
+ FROM log_tabelle GROUP BY ip;
+mysql> SELECT COUNT(ip),AVG(down) FROM test;
+mysql> DROP TABLE test;
+@end example
+
+Einige Dinge sollten Sie bei der Benutzung von @code{HEAP}-Tabellen in
+Betracht ziehen:
+
+@itemize @bullet
+@item
+Sie sollten immer @code{MAX_ROWS} im @code{CREATE}-Statement angeben, um
+sicherzustellen, dass Sie nicht versehentlich den gesamten Arbeitsspeicher
+benutzen.
+@item
+Indexe werden nur bei @code{=} und @code{<=>} benutzt (sind aber SEHR
+schnell).
+@item
+@code{HEAP}-Tabellen können nur ganze Schlüssel benutzen, um nach einer
+Zeile zu suchen. Vergleichen Sie das mit @code{MyISAM}-Tabellen, bei denen
+jedes Präfix des Schlüssels für das Suchen von Zeilen benutzt werden kann.
+@item
+@code{HEAP}-Tabellen benutzen ein festes Datensatzlängenformat.
+@item
+@code{HEAP} unterstützt keine @code{BLOB}/@code{TEXT}-Spalten.
+@item
+@code{HEAP} unterstützt keine @code{AUTO_INCREMENT}-Spalten.
+@item
+@code{HEAP} unterstützt keinen Index auf eine @code{NULL}-Spalte.
+@item
+Es darf keine nicht eindeutigen Schlüssel auf eine @code{HEAP}-Tabelle
+geben (das ist ungebräuchlich für gehashte Tabellen).
+@item
+@code{HEAP}-Tabellen werden von allen Clients gemeinsam benutzt (so wie
+jede andere Tabelle).
+@item
+Sie können nicht nach dem nächsten Eintrag in der Reihenfolge suchen (also
+den Index benutzen, um ein @code{ORDER BY} zu machen).
+@item
+Die Daten für @code{HEAP}-Tabellen werden in kleinen Blöcken zugewiesen.
+Die Tabellen sind 100% dynamisch (beim Einfügen). Es werden keine
+Overflow-Bereiche und kein zusätzlicher Platz für Schlüssel benötigt.
+Gelöschte Zeilen werden in eine verknüpfte Liste geschrieben und wieder
+benutzt, wenn Sie neue Daten in die Tabelle einfügen.
+@item
+Sie brauchen genug zusätzlichen Arbeitsspeicher für alle
+@code{HEAP}-Tabellen, die Sie zugleich benutzen wollen.
+@item
+Um Speicher freizugeben, führen Sie @code{DELETE FROM heap_tabelle},
+@code{TRUNCATE heap_tabelle} oder @code{DROP TABLE heap_tabelle} aus.
+@item
+MySQL kann nicht herausfinden, wie viele Zeilen es zwischen zwei Werten
+ungefähr gibt (das wird vom Bereichsoptimierer benötigt, um zu entscheiden,
+welcher Index benutzt wird). Das kann einige Anfragen betreffen, wenn Sie
+eine @code{MyISAM}-Tabelle in eine @code{HEAP}-Tabelle umwandeln.
+@item
+Um sicherzustellen, dass Sie nicht versehentlich etwas Unkluges tun, können
+Sie keine @code{HEAP}-Tabellen größer als @code{max_heap_table_size}
+erzeugen.
+@end itemize
+
+Der für eine Zeile in einer @code{HEAP}-Tabelle benötigte Speicher ist:
+
+@example
+SUM_OVER_ALL_KEYS(max_length_of_key + sizeof(char*) * 2)
++ ALIGN(length_of_row+1, sizeof(char*))
+@end example
+
+@code{sizeof(char*)} ist 4 auf 32-Bit-Maschinen und 8 auf 64-Bit-Maschinen.
+
+
+@node InnoDB, BDB, HEAP, Table types
+@c German node InnoDB
+@section InnoDB-Tabellen
+
+
+
+@menu
+* InnoDB overview::
+* InnoDB start::
+* InnoDB init::
+* Using InnoDB tables::
+* Adding and removing::
+* Backing up::
+* Moving::
+* InnoDB transaction model::
+* Implementation::
+* Table and index::
+* File space management::
+* Error handling::
+* InnoDB restrictions::
+* InnoDB contact information::
+@end menu
+
+@node InnoDB overview, InnoDB start, InnoDB, InnoDB
+@c German node Überblick über InnoDB
+@subsection Überblick über InnoDB-Tabellen
+
+@cindex Transaktionen, Unterstützung
+@cindex transaktionssichere Tabellen
+@cindex ACID
+
+InnoDB stellt MySQL einen transaktionssicheren (@code{ACID}-kompatiblen)
+Tabellen-Handler mit Fähigkeiten für Commit, Rollback und Reparatur nach
+Absturz zur Verfügung. InnoDB beherrscht Sperren auf Zeilenebene sowie ein
+konsistentes, nicht sperrendes Lesen in der Art von Oracle bei
+@code{SELECT}s. Diese Features steigern die Handhabung gleichzeitiger
+Verbindungen und die Performance. Es gibt bei InnoDB keine Notwendigkeit
+für Sperr-Eskalation, weil die Sperren auf Zeilenebene bei InnoDB in sehr
+wenig Speicherplatz passen. InnoDB-Tabellen unterstützen als erster
+Tabellentyp in MySQL @code{FOREIGN KEY}-Beschränkungen.
+
+InnoDB wurde für maximale Performance bei der Bearbeitung großer
+Datenmengen entworfen. Seine Prozessor-Effizienz wird wahrscheinlich von
+keiner anderen Festplatten-basierenden relationalen Datenbank-Engine
+erreicht.
+
+Technisch gesehen ist InnoDB ein komplettes Datenbank-Backend, das unter
+MySQL platziert ist. InnoDB hat seinen eigenen Puffer-Pool, um Daten und
+Indexe im Hauptspeicher zu cachen. InnoDB speichert seine Tabellen und
+Indexe in einem Tabellenplatz (Tablespace), der aus mehreren Dateien
+bestehen kann. Das unterscheidet sich beispielsweise von MyISAM-Tabellen,
+bei denen jede Tabelle als separate Datei gespeichert ist. InnoDB-Tabellen
+können jede beliebige Größe annehmen, sogar auf Betriebssystemen, deren
+Dateigröße auf 2 GB beschränkt ist.
+
+Die neuesten Informationen über InnoDB finden Sie unter
+@uref{http://www.innodb.com/}. Die aktuellste Version des InnoDB-Handbuchs
+ist immer dort zu finden, und Sie können auch kommerzielle Lizenzen und
+kommerziellen Support für InnoDB bestellen.
+
+InnoDB wird momentan (Oktober 2001) für die Produktion auf mehreren großen
+Datenbank-Sites benutzt, die hohe Performance benötigen. Die bekannte
+Internet-Newssite Slashdot.org läuft auf InnoDB. Mytrix Inc. speichert über
+1 TB an Daten in InnoDB, und eine andere Site handhabt eine
+durchschnittliche Last von 800 Einfüge- und Update-Operationen pro Sekunde
+mit InnoDB.
+
+InnoDB-Tabellen sind in der MySQL-Quelldistribution ab Version 3.23.34a
+enthalten und in der MySQL-Max-Binärversion aktiviert. Für Windows sind die
+Max-Binärdateien in der Standarddistribution enthalten.
+
+Wenn Sie eine Binärversion von MySQL herunter geladen haben, die
+Unterstützung für InnoDB enthält, folgen Sie einfach den Anweisungen im
+Handbuch für die Installation einer Binärversion von MySQL. Wenn Sie
+bereits MySQL-3.23 installiert haben, können Sie MySQL-Max am einfachsten
+installieren, indem Sie die ausführbare Datei für den Server
+(@file{mysqld}) durch die entsprechende ausführbare Datei in der
+Max-Distribution ersetzen. MySQL and MySQL-Max unterscheiden sich nur in
+Bezug auf die ausführbare Datei für den Server. @xref{MySQL binaries}. @xref{mysqld-max, , @code{mysqld-max}}.
+
+@c German FIX changed @xref to @ref
+Um MySQL mit InnoDB-Unterstützung zu kompilieren, laden Sie MySQL-3.23.34a
+oder neuer von @uref{http://www.mysql.com/} herunter und konfigurieren Sie
+MySQL mit der @code{--with-innodb}-Option. Sehen Sie im Handbuch unter
+@ref{Installing source} nach.
+
+@example
+cd /pfad/zur/quelldistribution/von/mysql-3.23.37
+./configure --with-innodb
+@end example
+
+Um InnoDB zu benutzen, müssen Sie InnoDB init in Ihrer @file{my.cnf}- oder
+@file{my.ini}-Datei angeben. In dieser Datei müssen Sie mindestens
+folgenden Zeile im @code{[mysqld]}-Abschnitt hinzufügen:
+
+@example
+innodb_data_file_path=ibdata:30M
+@end example
+
+@c German FIX changed @xref to @ref
+Für eine gute Performance ist es jedoch am besten, Optionen wie die unten
+im Abschnitt @ref{InnoDB start} empfohlenen anzugeben.
+
+InnoDB wird unter der GNU-GPL-Lizenz Version 2 (vom Juni 1991) vertrieben.
+In den Quelldistributionen von MySQL erscheint InnoDB als Unterverzeichnis.
+
+
+@node InnoDB start, InnoDB init, InnoDB overview, InnoDB
+@c German node Mit InnoDB anfangen
+@subsection Mit InnoDB anfangen - Optionen
+
+Um InnoDB-Tabellen in MySQL-Max-3.23 zu benutzen, @strong{MÜSSEN} Sie
+Konfigurationsparameter im @code{[mysqld]}-Abschnitt der
+MySQL-Konfigurationsdatei @file{my.cnf} angeben. @xref{Option files}.
+
+Der einzige erforderliche Parameter, um InnoDB in MySQL-Max-3.23 benutzen
+zu können, ist @code{innodb_data_file_path}.
+In MySQL-4.0 müssen Sie nicht einmal @code{innodb_data_file_path} angeben.
+Vorgabemäßig wird eine 64 MB große Daten-Datei @file{ibdata1} im
+@code{datadir} von MySQL erzeugt.
+
+Um jedoch eine gute Performance zu erzielen, MÜSSEN Sie explizit die unten
+in Beispielen aufgeführten InnoDB-Parameter setzen.
+
+Der Vorgabewert für @code{innodb_data_home_dir} ist das @code{datadir} von
+MySQL. Wenn Sie @code{innodb_data_home_dir} nicht angeben, können Sie in
+@code{innodb_data_file_path} keine absoluten Pfade benutzen.
+
+Nehmen wir an, Sie haben eine Windows-NT-Maschine mit 128 MB RAM und einer
+einzelnen 10 GB großen Festplatte. Unten steht ein Beispiel von möglichen
+Konfigurationsparametern in @file{my.cnf} für InnoDB:
+
+@example
+[mysqld]
+# Hier können Ihre sonstigen MySQL-Serveroptionen stehen
+# ...
+#
+innodb_data_home_dir = c:\ibdata
+# Die Daten-Dateien müssen in der Lage sein,
+# Ihre Daten und Indexe aufzunehmen
+innodb_data_file_path = ibdata1:2000M;ibdata2:2000M
+# Puffer-Poolgröße auf 50% bis 80%
+# des Arbeitsspeichers Ihres Computers setzen
+set-variable = innodb_buffer_pool_size=70M
+set-variable = innodb_additional_mem_pool_size=10M
+innodb_log_group_home_dir = c:\iblogs
+# .._log_arch_dir muss dasselbe sein wie
+# .._log_group_home_dir
+innodb_log_arch_dir = c:\iblogs
+innodb_log_archive=0
+set-variable = innodb_log_files_in_group=3
+# Die Log-Dateigröße auf ungefähr 15%
+# der Puffer-Poolgröße setzen
+set-variable = innodb_log_file_size=10M
+set-variable = innodb_log_buffer_size=8M
+# ..flush_log_at_trx_commit auf 0 setzen,
+# wenn Sie es sich leisten können,
+# ein paar der letzten Transaktionen zu verlieren
+innodb_flush_log_at_trx_commit=1
+set-variable = innodb_file_io_threads=4
+set-variable = innodb_lock_wait_timeout=50
+@end example
+
+Beachten Sie, dass die Daten-Dateien bei einigen Betriebssystemen kleiner
+als 2 GB sein müssen! Die Gesamtgröße von Daten-Dateien muss größer oder
+gleich 10 MB sein. Die Gesamtgröße der Log-Dateien MUSS auf
+32-Bit-Computern kleiner als 4 GB sein.
+
+@strong{InnoDB legt keine Verzeichnisse an. Diese müssen Sie selbst
+erzeugen!}
+Stellen Sie auch sicher, dass der MySQL-Server Rechte hat, Dateien in den
+Verzeichnissen anzulegen, die Sie angeben.
+
+Wenn Sie zum ersten Mal eine InnoDB-Datenbank erzeugen, sollten Sie den
+MySQL-Server am besten von der Kommandozeilen-Eingabeaufforderung starten.
+InnoDB gibt dann Informationen über die Datenbank-Erzeugung auf dem
+Bildschirm aus und Sie sehen, was passiert. Unten in Abschnitt 3 sehen Sie,
+wie die Ausgaben aussehen sollten.
+Unter Windows können Sie @file{mysqld-max.exe} so starten:
+@example
+ihr-pfad-zu-mysqld>mysqld-max --standalone --console
+@end example
+
+Nehmen wir an, Sie haben einen Linux-Computer mit 512 MB RAM und drei
+Festplatten mit jeweils 20 GB (in Verzeichnispfaden @file{/}, @file{/dr2}
+and @file{/dr3}). Unten ist ein Beispiel möglicher Konfigurationsparameter
+in @file{my.cnf} für InnoDB:
+
+@example
+[mysqld]
+# Hier können Ihre sonstigen MySQL-Serveroptionen stehen
+# ...
+#
+innodb_data_home_dir = /
+# Die Daten-Dateien müssen in der Lage sein,
+# Ihre Daten und Indexe aufzunehmen
+innodb_data_file_path = ibdata/ibdata1:2000M;dr2/ibdata/ibdata2:2000M
+# Puffer-Poolgröße auf 50% bis 80%
+# des Arbeitsspeichers Ihres Computers setzen
+set-variable = innodb_buffer_pool_size=350M
+set-variable = innodb_additional_mem_pool_size=20M
+innodb_log_group_home_dir = /dr3/iblogs
+# .._log_arch_dir muss dasselbe sein wie
+# .._log_group_home_dir
+innodb_log_arch_dir = /dr3/iblogs
+innodb_log_archive=0
+set-variable = innodb_log_files_in_group=3
+# Die Log-Dateigröße auf ungefähr 15%
+# der Puffer-Poolgröße setzen
+set-variable = innodb_log_file_size=50M
+set-variable = innodb_log_buffer_size=8M
+# ..flush_log_at_trx_commit auf 0 setzen,
+# wenn Sie es sich leisten können,
+# ein paar der letzten Transaktionen zu verlieren
+innodb_flush_log_at_trx_commit=1
+set-variable = innodb_file_io_threads=4
+set-variable = innodb_lock_wait_timeout=50
+#innodb_flush_method=fdatasync
+#innodb_fast_shutdown=1
+#set-variable = innodb_thread_concurrency=5
+@end example
+
+Beachten Sie, dass die beiden Daten-Dateien auf unterschiedliche Platten
+platziert wurden. Der Grund für den Namen @code{innodb_data_file_path}
+ist, dass Sie auch Pfade zu Ihren Daten-Dateien angeben können und dass
+@code{innodb_data_home_dir} nur textlich mit Ihren Daten-Datei-Pfaden
+verkettet wird, wobei ein möglicher Schrägstrich oder Backslash dazwischen
+hinzugefügt wird. InnoDB füllt den Tabellenplatz (Tablespace), der durch
+die Daten-Dateien gebildet wird, von unten nach oben. In manchen Fällen
+verbessert es die Performance der Datenbank, wenn nicht alle Daten auf
+derselben physikalischen Festplatte platziert sind. Es verbessert häufig
+die Performance, Log-Dateien auf anderen Platten als die Daten zu
+platzieren.
+
+Die Bedeutung der Konfigurationsparameter ist wie folgt:
+
+@multitable @columnfractions .30 .70
+@item @strong{Option} @tab @strong{Beschreibung}
+@item @code{innodb_data_home_dir} @tab
+Der allgemeine Teil des Verzeichnispfads für alle InnoDB-Daten-Dateien. Die
+Vorgabe für diesen Parameter ist das @code{datadir} von MySQL.
+@item @code{innodb_data_file_path} @tab
+Pfade zu individuellen Daten-Dateien und ihre Größen. Der volle
+Verzeichnispfad zu jeder Daten-Datei wird durch Verkettung von
+innodb_data_home_dir mit den hier angegebenen Pfaden hergestellt. Die
+Dateigrößen werden in Megabytes angegeben, daher das 'M' nach der obigen
+Angabe. InnoDB versteht auch die Abkürzung 'G', 1G bedeutet 1024M. Ab
+3.23.44 können Sie die Dateigröße auf mehr als 4 GB setzen, wenn das
+Betriebssystem große Dateien unterstützt. Auf einige Betriebssystemen
+müssen Dateien kleiner als 2 GB sein. Die Summe der Dateigrößen muss
+mindestens 10 MB betragen.
+@item @code{innodb_mirrored_log_groups} @tab
+Anzahl identischer Kopien von Log-Gruppen, die für die Datenbank gehalten
+werden. Momentan sollte dieser Parameter auf 1 gesetzt werden.
+@item @code{innodb_log_group_home_dir} @tab
+Verzeichnispfad zu den InnoDB-Log-Dateien.
+@item @code{innodb_log_files_in_group} @tab
+Anzahl von Log-Dateien in der Log-Gruppe. InnoDB schreibt in zirkulärer
+Weise in die Dateien. Hier wird ein Wert 3 empfohlen.
+@item @code{innodb_log_file_size} @tab
+Größe jeder Log-Datei in einer Log-Gruppe in Megabytes. Sinnvolle Werte
+reichen von 1 MB bis 1/n-tel der Größe des Puffer-Pools, die unten
+angegeben wird, wobei n die Anzahl der Log-Dateien in der Gruppe ist. Je
+größer der Wert, desto weniger Checkpoint-Flush-Aktivität wird im Puffer
+benötigt, was Festplatten-Ein- und -Ausgaben erspart. Größere Log-Dateien
+bedeutet jedoch auch, dass die Wiederherstellung im Fall eines Absturzes
+langsamer ist. Die Gesamtgröße aller Log-Dateien muss auf 32-Bit-Computern
+kleiner als 4 GB sein.
+@item @code{innodb_log_buffer_size} @tab
+Die Größe des Puffers, den InnoDB benutzt, um in die Log-Dateien auf
+Platte zu schreiben. Sinnvolle Werte liegen im Bereich von 1 MB bis zur
+Hälfte der Gesamtgröße der Log-Dateien. Ein großer Log-Puffer erlaubt,
+dass große Transaktionen laufen können, ohne dass die Notwendigkeit
+besteht, das Log auf Platte zu schreiben, bis die Transaktion abgeschickt
+(commit) wird. Wenn Sie daher große Transaktionen haben, sparen Sie
+Festplatten-Ein- und Ausgaben, wenn Sie den Log-Puffer Groß machen.
+@item @code{innodb_flush_log_at_trx_commit} @tab
+Normalerweise wird dieser Parameter auf 1 gesetzt, was bedeutet, dass beim
+Abschicken (commit) einer Transaktion das Log auf Platte geschrieben wird
+(flush) und die durch die Transaktion gemachten Änderungen permanent werden
+und einen Datenbankabsturz überleben. Wenn Sie willens sind, in Bezug auf
+diese Sicherheit Kompromisse einzugeben und eher kleine Transaktionen
+laufen lassen, können Sie diesen Wert auf 0 setzen, um Festplatten-Ein- und
+-Ausgaben in Bezug auf die Log-Dateien zu verringern.
+@item @code{innodb_log_arch_dir} @tab
+Das Verzeichnis, in dem komplett geschriebene Log-Dateien archiviert
+werden, wenn Archivierung benutzt wird. Der Wert dieses Parameters sollte
+momentan derselbe sein wie @code{innodb_log_group_home_dir}.
+@item @code{innodb_log_archive} @tab
+Dieser Wert sollte momentan auf 0 gesetzt werden. Weil MySQL die
+Wiederherstellung aus einer Datensicherung unter Benutzung seiner eigenen
+Log-Dateien durchführt, gibt es momentan keine Notwendigkeit,
+InnoDB-Log-Dateien zu archivieren.
+@item @code{innodb_buffer_pool_size} @tab
+Die Größe des Speicherpuffers, den InnoDB benutzt, um Daten und Indexe
+seiner Tabellen zu cachen. Je größer Sie diesen Wert setzen, desto weniger
+Festplatten-Ein- und -Ausgaben werden für den Zugriff auf Daten in Tabellen
+benötigt. Auf einem dedizierten Datenbank-Server können Sie diesen
+Parameter auf bis zu 80% des physikalischen Arbeitsspeichers der Maschine
+setzen. Setzen Sie ihn allerdings nicht zu hoch, weil bei manchen
+Betriebssystemen der Wettbewerb um Arbeitsspeicher zu Paging führt.
+@item @code{innodb_additional_mem_pool_size} @tab
+Die Größe des Speicher-Pools, den InnoDB für die Speicherung von
+Daten-Wörterbuchinformationen und anderen internen Datenstrukturen benutzt.
+Ein sinnvoller Wert hierfür könnte 2 MB sein. Je mehr Tabellen Sie jedoch
+in Ihrer Applikation haben, desto mehr müssen Sie hier zuweisen. Wenn
+InnoDB in diesem Pool keinen Speicherplatz mehr hat, läßt es sich
+Speicherplatz vom Betriebssystem zuweisen und schreibt Warnmeldungen in die
+MySQL-Fehler-Log-Datei.
+@item @code{innodb_file_io_threads} @tab
+Die Anzahl der Datei-Ein- und -Ausgabe-Threads in InnoDB. Normalerweise
+sollte dieser Wert 4 sein, aber Windows-Festplatten könnten von einer
+höheren Zahl profitieren.
+@item @code{innodb_lock_wait_timeout} @tab
+Timeout in Sekunden. Solange wartet eine InnoDB-Transaktion auf eine
+Sperre, bevor sie abgebrochen (Rollback) wird. InnoDB erkennt automatisch
+Transaktionsblockierungen in seiner eigenen Sperr-Tabelle und bricht die
+Transaktion ab (Rollback). Wenn Sie den @code{LOCK TABLES}-Befehl oder
+andere transaktionssichere Tabellen-Handler als InnoDB in derselben
+Transaktion benutzen, kann eine Blockierung auftreten, die InnoDB nicht
+erkennen kann. In solchen Fällen ist ein Timeout nützlich, um die Situation
+zu bereinigen.
+@item @code{innodb_flush_method} @tab
+(Verfügbar ab Version 3.23.40.)
+Der Vorgabewert hierfür ist @code{fdatasync}.
+Ein andere Option ist @code{O_DSYNC}.
+@end multitable
+
+
+@node InnoDB init, Using InnoDB tables, InnoDB start, InnoDB
+@c German node InnoDB initialisieren
+@subsection InnoDB-Tabellenplatz (Tablespace) erzeugen
+
+Angenommen, Sie haben MySQL installiert und @file{my.cnf} so editiert, dass
+sie die notwendigen InnoDB Konfigurationsparameter enthält. Bevor Sie MySQL
+starten, sollten Sie überprüfen, dass die für InnoDB-Daten- und Log-Dateien
+angegebenen Verzeichnisse existieren und dass Sie auf diese Zugriffsrechte
+haben. InnoDB kann keine Verzeichnisse anlegen, nur Dateien. Überprüfen Sie
+auch, ob Sie auf der Festplatte genug Platz für Daten- und Log-Dateien
+haben.
+
+Wenn Sie jetzt MySQL starten, fängt InnoDB an, Ihre Daten- und Log-Dateien
+zu erzeugen. InnoDB gibt dabei etwas wie das folgende aus:
+
+@example
+~/mysqlm/sql > mysqld
+InnoDB: The first specified data file /home/stefan/data/ibdata1 did not exist:
+InnoDB: a new database to be created!
+InnoDB: Setting file /home/stefan/data/ibdata1 size to 134217728
+InnoDB: Database physically writes the file full: wait...
+InnoDB: Data file /home/stefan/data/ibdata2 did not exist: new to be created
+InnoDB: Setting file /home/stefan/data/ibdata2 size to 262144000
+InnoDB: Database physically writes the file full: wait...
+InnoDB: Log file /home/stefan/data/logs/ib_logfile0 did not exist: new to be created
+InnoDB: Setting log file /home/stefan/data/logs/ib_logfile0 size to 5242880
+InnoDB: Log file /home/stefan/data/logs/ib_logfile1 did not exist: new to be created
+InnoDB: Setting log file /home/stefan/data/logs/ib_logfile1 size to 5242880
+InnoDB: Log file /home/stefan/data/logs/ib_logfile2 did not exist: new to be created
+InnoDB: Setting log file /home/stefan/data/logs/ib_logfile2 size to 5242880
+InnoDB: Started
+mysqld: ready for connections
+@end example
+
+Jetzt wurde eine neue InnoDB-Datenbank erzeugt. Sie können sich mit den
+üblichen MySQL-Client-Programmen wie @code{mysql} mit dem MySQL-Server
+verbinden. Wenn Sie den MySQL-Server mit @file{mysqladmin shutdown}
+herunter fahren, gibt InnoDB etwa wie das folgende aus:
+
+@example
+010321 18:33:34 mysqld: Normal shutdown
+010321 18:33:34 mysqld: Shutdown Complete
+InnoDB: Starting shutdown...
+InnoDB: Shutdown completed
+@end example
+
+Wenn Sie jetzt einen Blick auf die Daten-Dateien und Log-Verzeichnisse
+werfen, sehen Sie die erzeugten Dateien. Das Log-Verzeichnis enthält auch
+eine kleine Datei namens @file{ib_arch_log_0000000000}. Diese Datei
+resultiert aus der Datenbank-Erzeugung, nach der InnoDB die
+Log-Archivierung ausgeschaltet hat. Wenn MySQL noch einmal gestartet wird,
+sieht die Ausgabe etwa wie folgt aus:
+
+@example
+~/mysqlm/sql > mysqld
+InnoDB: Started
+mysqld: ready for connections
+@end example
+
+
+
+@menu
+* Error creating InnoDB::
+@end menu
+
+@node Error creating InnoDB, , InnoDB init, InnoDB init
+@c German node Fehler bei der Erzeugung von InnoDB
+@subsubsection Falls etwas bei der Datenbank-Erzeugung schiefgeht
+
+Falls etwas bei der Datenbank-Erzeugung schiefgeht, sollten Sie alle durch
+InnoDB erzeugten Dateien löschen. Das heißt alle Daten-Dateien, alle
+Log-Dateien, die kleine archivierte Log-Datei und - falls Sie bereits
+InnoDB-Tabellen erzeugt haben, auch die entsprechenden @file{.frm}-Dateien
+für diese Tabellen in den MySQL-Datenbankverzeichnissen. Danach können Sie
+die InnoDB-Datenbankerzeugung erneut versuchen.
+
+
+@node Using InnoDB tables, Adding and removing, InnoDB init, InnoDB
+@c German node InnoDB-Tabellen benutzen
+@subsection InnoDB-Tabellen erzeugen
+
+Angenommen, Sie haben den MySQL-Client mit dem Befehl @code{mysql test}
+gestartet. Um eine Tabelle im InnoDB-Format zu erzeugen, müssen Sie im
+SQL-Befehl zur Tabellenerzeugung @code{TYPE = InnoDB} angeben:
+
+@example
+CREATE TABLE kunde (A INT, B CHAR (20), INDEX (A)) TYPE = InnoDB;
+@end example
+
+Dieser SQL-Befehl erzeugt eine Tabelle und einen Index auf die Spalte
+@code{A} im InnoDB-Tabellenplatz (Tablespace), der aus den Daten-Dateien
+besteht, die Sie in @file{my.cnf} angegeben haben. MySQL erzeugt zusätzlich
+eine Datei @file{kunde.frm} im MySQL-Datenbankverzeichnis @file{test}.
+Intern fügt InnoDB seinem eigenen Datenwörterbuch einen Eintrag für die
+Tabelle @code{'test/kunde'} hinzu. Wenn Sie daher eine Tabelle namens
+@code{kunde} in einer anderen Datenbank von MySQL erzeugen, kollidieren die
+Tabellennamen innerhalb InnoDB nicht.
+
+Sie können den freien Speicherplatz im InnoDB-Tabellenplatz (Tablespace)
+mit dem Tabellen-Status-Befehl von MySQL für jede Tabelle, die Sie mit
+@code{TYPE = InnoDB} erzeugt haben, abfragen. Die Menge freien Platzes im
+Tabellenplatz (Tablespace) erscheint im Kommentar-Abschnitt der Tabelle in
+der Ausgabe von @code{SHOW}. Beispiel:
+
+@example
+SHOW TABLE STATUS FROM test LIKE 'kunde'
+@end example
+
+Beachten Sie, dass die Statistiken, die @code{SHOW} über InnoDB-Tabellen
+ausgibt, nur Näherungswerte sind: Sie werden für die SQL-Optimierung
+benutzt. Die für Tabelle und Indexe reservierten Größen in Bytes sind
+allerdings genau.
+
+@subsubsection MyISAM-Tabellen in InnoDB-Tabellen umwandeln
+
+InnoDB hat keine spezielle Optimierung für separate Index-Erzeugung. Daher
+lohnt es sich nicht, die Tabelle zu exportieren und importieren und die
+Indexe danach zu erzeugen. Die schnellste Art, eine Tabelle in InnoDB zu
+ändern, ist, die Einfügungen direkt in eine InnoDB-Tabelle vorzunehmen,
+das heißt, @code{ALTER TABLE ... TYPE=INNODB} zu benutzen oder eine leere
+InnoDB-Tabelle mit identischen Definitionen zu nehmen und die Zeilen mit
+@code{INSERT INTO ... SELECT * FROM ...} einzufügen.
+
+Um eine bessere Kontrolle über den Einfügeprozess zu erhalten, kann es
+besser sein, große Tabellen in Teilstücken einzufügen:
+
+@example
+INSERT INTO neue_tabelle SELECT * FROM alte_tabelle WHERE schluessel > etwas
+ AND schluessel <= etwas_anderes;
+@end example
+
+Nachdem alle Daten eingefügt wurden, können Sie die Tabellen umbenennen.
+
+Während der Umwandlung großer Tabellen sollten Sie den InnoDB-Puffer-Pool
+hoch setzen, um Festplatten-Ein- und -Ausgaben zu verringern, allerdings
+nicht höher als 80% des physikalischen Arbeitsspeichers. Sie sollten die
+InnoDB-Log-Dateien Groß machen und auch den Log-Puffer.
+
+Stellen Sie sicher, dass Sie genug Tabellenplatz (Tablespace) haben!
+InnoDB-Tabellen benötigen viel mehr Platz als MyISAM-Tabellen. Wenn ein
+@code{ALTER TABLE} nicht mehr genug Platz hat, wird ein Rollback gestartet,
+das Stunden dauern kann, wenn es auf der Festplatte stattfindet. Bei
+Einfügeoperationen verwendet InnoDB den Einfügepuffer, um sekundäre
+Index-Datensätze mit Indexen in Stapeln zu vermischen. Das spart eine Menge
+an Festplatten-Ein- und -Ausgaben. Beim Rollback wird kein solcher
+Mechanismus benutzt, weshalb das Rollback bis zu 30 mal länger als das
+Einfügen dauern kann.
+
+Falls Sie keine wertvollen Daten in Ihren InnoDB-Dateien haben, ist es im
+Fall eines 'festgefahrenen' Rollback besser, den Datenbank-Prozess zu
+killen und alle InnoDB-Daten- und Log-Dateien sowie alle InnoDB-Tabellen
+(@file{.frm}-Dateien) zu löschen und noch einmal anzufangen, statt darauf
+zu warten, dass Millionen von Festplatten-Ein- und -Ausgaben beendet
+werden.
+
+@subsubsection Fremdschlüssel-(Foreign Key)-Beschränkungen
+
+InnoDB-Version 3.23.44 hat Fremdschlüssel-(Foreign Key)-Beschränkungen.
+InnoDB ist der erste MySQL-Tabellentyp, der die Definition von
+Fremdschlüssel-Beschränkungen zuläßt, um die Integrität Ihrer Daten zu
+überwachen.
+
+Die Syntax einer Fremdschlüsseldefinition in InnoDB:
+@example
+FOREIGN KEY (index_spalten_name, ...) REFERENCES tabellen_name (index_spalten_name, ...)
+@end example
+
+Beispiel:
+
+@example
+CREATE TABLE eltern(id INT NOT NULL, PRIMARY KEY (id)) TYPE=INNODB;
+CREATE TABLE kind(id INT, eltern_id INT, INDEX par_ind (eltern_id),
+ FOREIGN KEY (eltern_id) REFERENCES eltern(id)) TYPE=INNODB;
+@end example
+
+Beide Tabellen müssen vom Typ InnoDB sein und es muss einen Index geben,
+bei dem der Fremdschlüssel und der referenzierte Schlüssel als erste
+Spalten aufgeführt sind. Jegliches @code{ALTER TABLE} entfernt momentan
+alle Fremdschlüsselbeschränkungen, die für die Tabelle definiert wurden,
+aber nicht die Beschränkungen, die die Tabelle referenzieren.
+Korrespondierende Spalten im Fremdschlüssel und dem referenzierten
+Schlüssel müssen ähnliche interne Datentypen innerhalb InnoDB sein, so dass
+sie ohne Typumwandlung verglichen werden können. Die Längen von
+Zeichenkettentypen müssen nicht dieselben sein. Die Größe und Vorzeichen /
+kein Vorzeichen von Ganzzahltypen müssen dieselben sein.
+
+Beim Prüfen von Fremdschlüsseln setzt InnoDB gemeinsame Sperren auf
+Zeilenebene auf kind- und eltern-Datensätze, die es betrachten muss. InnoDB
+prüft Fremdschlüssel-(Foreign Key)-Beschränkungen sofort: Die Prüfung wird
+nicht bis zu einem Transaktions-Commit verschoben.
+
+InnoDB läßt zu, dass jegliche Tabelle gelöscht wird, selbst wenn das die
+Fremdschlüssel-(Foreign Key)-Beschränkungen durchbrechen würde, die die
+Tabelle referenzieren. Wenn Sie eine Tabelle löschen, werden die
+Beschränkungen, die in ihrem CREATE-Statement definiert wurden, ebenfalls
+gelöscht.
+
+Wenn Sie eine gelöschte Tabelle neu erzeugen, muss sie eine Definition
+haben, die mit den Fremdschlüssel-(Foreign Key)-Beschränkungen konform ist,
+die sie referenzieren. Sie muss die richten Spaltennamen und -typen haben,
+und sie muss - wie oben angegeben - Indexe auf die referenzierten Schlüssel
+haben.
+
+Sie können die Fremdschlüssel-(Foreign Key)-Beschränkungen für eine Tabelle
+wie folgt auflisten:
+@code{T} with
+@example
+SHOW TABLE STATUS FROM ihr_datenbank_name LIKE 'T';
+@end example
+Die Fremdschlüssel-(Foreign Key)-Beschränkungen werden im
+Tabellen-Kommentar der Ausgabe aufgelistet.
+
+InnoDB unterstützt noch kein @code{CASCADE ON DELETE} oder andere spezielle
+Optionen für diese Beschränkungen.
+
+@node Adding and removing, Backing up, Using InnoDB tables, InnoDB
+@c German node Hinzufügen und entfernen
+@subsection Hinzufügen und Entfernen von InnoDB-Daten- und -Log-Dateien
+
+Sie können die Größe einer InnoDB-Daten-Datei nicht vergrößern. Um Ihrem
+Tabellenplatz (Tablespace) mehr hinzuzufügen, müssen Sie eine neue
+Daten-Datei hinzufügen. Um das zu tun, müssen Sie Ihre MySQL-Datenbank
+herunter fahren, die @file{my.cnf}-Datei editieren und eine neue Datei zu
+@code{innodb_data_file_path} hinzufügen. Dann starten Sie MySQL erneut.
+
+Momentan können Sie keine Daten-Datei aus InnoDB entfernen. Um die Größe
+Ihrer Datenbank zu verringern, müssen Sie @file{mysqldump} benutzen, um
+alle Ihre Tabellen zu dumpen, eine neue Datenbank erzeugen und Ihre
+Tabellen in die neue Datenbank importieren.
+
+Wenn Sie die Anzahl oder die Größe Ihrer InnoDB-Log-Dateien ändern wollen,
+müssen Sie MySQL herunter fahren und sicher stellen, dass er ohne Fehler
+herunter fuhr. Dann kopieren Sie die alten Log-Dateien an eine sichere
+Stelle, falls etwas beim Herunterfahren schiefging und Sie die Datenbank
+wiederherstellen müssen. Löschen Sie die alten Log-Dateien aus dem
+Log-Datei-Verzeichnis, editieren Sie @file{my.cnf} und starten Sie MySQL
+noch einmal. InnoDB meldet beim Starten, dass es neue Log-Dateien anlegt.
+
+
+@node Backing up, Moving, Adding and removing, InnoDB
+@c German node Datensicherung InnoDB
+@subsection Datensicherung und Wiederherstellung einer InnoDB-Datenbank
+
+Der Schlüssel zur sicheren Datenbankverwaltung sind regelmäßige
+Datensicherungen. Im eine 'binäre' Sicherung Ihrer Datenbank zu machen, tun
+Sie folgendes:
+
+@itemize @bullet
+@item
+Fahren Sie Ihre MySQL-Datenbank herunter und stellen Sie sicher, dass dabei
+keine Fehler auftraten.
+@item
+Kopieren Sie Ihre Daten-Dateien an eine sichere Stelle.
+@item
+Kopieren Sie alle InnoDB-Log-Dateien an eine sichere Stelle.
+@item
+Kopieren Sie Ihre @file{my.cnf} Konfigurationsdatei(en) an eine sichere
+Stelle.
+@item
+Kopieren Sie alle @file{.frm}-Dateien für Ihre InnoDB-Tabellen an eine
+sichere Stelle.
+@end itemize
+
+Momentan gibt es kein Online- oder inkrementelles Datensicherungsprogramm
+für InnoDB, obwohl diese auf der TODO-Liste sind.
+
+Zusätzlich zu den beschriebenen Binär-Datensicherungen sollten Sie
+ausserdem regelmäßig Dumps Ihrer Tabellen mit @file{mysqldump} machen. Der
+Grund ist, dass eine Binärdatei beschädigt sein kann, ohne dass Sie das
+bemerken. Gedumpte Tabellen werden in Textdateien gespeichert, die
+Menschen-lesbar und viel einfacher als binäre Datenbankdateien sind. Aus
+gedumpten Dateien läßt sich Tabellenbeschädigung leichter erkennen und da
+ihr Format einfacher ist, ist das Risiko ernsthafter Datenbeschädigung in
+ihnen geringer.
+
+Es ist eine gute Idee, Dumps zur gleichen Zeit zu machen wie die binäre
+Datensicherung Ihrer Datenbank. Sie müssen alle Clients aus Ihrer Datenbank
+ausschließen, um konsistente Schnappschüsse aller Ihrer Tabellen im Dump
+zu bekommen. Danach können Sie die binäre Datensicherung machen, so dass
+Sie einen konsistenten Schnappschuss Ihrer Datenbank in zwei Formaten
+haben.
+
+Um in der Lage zu sein, Ihre InnoDB-Datenbank aus den beschriebenen binären
+Datensicherungen wiederherzustellen, müssen Sie Ihre MySQL-Datenbank mit
+allgemeinem Loggen und angeschalteter Log-Archivierung von MySQL laufen
+lassen. Mit allgemeinem Loggen ist hier der Log-Mechanismus des
+MySQL-Servers gemeint, der unabhängig von den InnoDB-Logs ist.
+
+Zum Wiederherstellen nach einem Absturz des MySQL-Serverprozesses ist es
+lediglich nötig, diesen erneut zu starten. InnoDB prüft automatisch die
+Log-Dateien und führt ein Roll-Forward der Datenbank bis zum aktuellen
+Stand durch. InnoDB macht ein automatisches Rollback nicht abgeschlossener
+(committed) Transaktionen, die zur Zeit des Absturzes anhängig waren.
+Während der Wiederherstellung gibt InnoDB etwa folgendes aus:
+
+@example
+~/mysqlm/sql > mysqld
+InnoDB: Database was not shut down normally.
+InnoDB: Starting recovery from log files...
+InnoDB: Starting log scan based on checkpoint at
+InnoDB: log sequence number 0 13674004
+InnoDB: Doing recovery: scanned up to log sequence number 0 13739520
+InnoDB: Doing recovery: scanned up to log sequence number 0 13805056
+InnoDB: Doing recovery: scanned up to log sequence number 0 13870592
+InnoDB: Doing recovery: scanned up to log sequence number 0 13936128
+...
+InnoDB: Doing recovery: scanned up to log sequence number 0 20555264
+InnoDB: Doing recovery: scanned up to log sequence number 0 20620800
+InnoDB: Doing recovery: scanned up to log sequence number 0 20664692
+InnoDB: 1 uncommitted transaction(s) which must be rolled back
+InnoDB: Starting rollback of uncommitted transactions
+InnoDB: Rolling back trx no 16745
+InnoDB: Rolling back of trx no 16745 completed
+InnoDB: Rollback of uncommitted transactions completed
+InnoDB: Starting an apply batch of log records to the database...
+InnoDB: Apply batch completed
+InnoDB: Started
+mysqld: ready for connections
+@end example
+
+Wenn Ihre Datenbank beschädigt wird oder Ihre Festplatte Fehler hat, müssen
+Sie eine Wiederherstellung aus einer Datensicherung durchführen. Im Falle
+der Beschädigung sollten Sie zunächst eine Datensicherung finden, die nicht
+beschädigt ist. Machen Sie aus der Datensicherung eine Wiederherstellung
+aus den allgemeinen Log-Dateien von MySQL unter Beachtung der Anleitungen
+im MySQL-Handbuch.
+
+
+
+@menu
+* InnoDB checkpoints::
+@end menu
+
+@node InnoDB checkpoints, , Backing up, Backing up
+@c German node InnoDB-Checkpoints
+@subsubsection Checkpoints
+
+InnoDB hat einen Checkpoint-Mechanismus implementiert, der sich Fuzzy
+Checkpoint nennt. InnoDB schreibt veränderten Datenbankseiten aus dem
+Puffer-Pool in kleinen Stapeln (Batch) auf Platte (flush), daher besteht
+keine Notwendigkeit, den Puffer-Pool in einem einzelnen Stapel
+zurückzuschreiben, was in der Praxis dazu führen würde, dass SQL-Statements
+von Benutzern für eine Weile angehalten würden.
+
+Bei der Reparatur nach Abstürzen sucht InnoDB nach einem Checkpoint-Label in
+den Log-Dateien. Es weiß, dass alle Änderungen an der Datenbank vor dem
+Label bereits im Platten-Image der Datenbank enthalten sind. InnoDB scannt
+anschließend die Log-Dateien ab dem Checkpoint vorwärts und wendet die
+geloggten Änderungen auf die Datenbank an.
+
+InnoDB schreibt in zirkulärer Art in die Log-Dateien. Alle abgeschickten
+(committed) Änderungen, die dazu führen, dass sich die Datenbankseiten im
+Puffer-Pool vom Image auf der Platte unterscheiden, müssen in den
+Log-Dateien verfügbar sein, für den Fall, dass InnoDB eine
+Wiederherstellung durchführen muss. Das heißt, wenn InnoDB anfängt, eine
+Log-Datei auf zirkuläre Weise wieder zu benutzen, muss es sicherstellen,
+dass die Datenbankseiten-Images auf der Festplatte bereits die Änderungen
+enthalten, die in der Log-Datei mitgeschrieben sind, die InnoDB benutzen
+wird. Mit anderen Worten muss InnoDB einen Checkpoint machen, was oft das
+Zurückschreiben auf Platte (flush) geänderter Datenbankseiten beinhaltet.
+
+Das erklärt, warum es Festplatten-Ein- und -Ausgaben sparen kann, wenn man
+die Log-Dateien sehr Groß macht. Es kann sinnvoll sein, die Gesamtgröße
+der Log-Dateien so Groß wie den Puffer-Pool oder sogar noch größer zu
+machen. Der Nachteil großer Log-Dateien ist, dass eine Reparatur nach
+Absturz länger dauern kann, weil mehr Log-Einträge auf die Datenbank
+angewendet werden müssen.
+
+
+@node Moving, InnoDB transaction model, Backing up, InnoDB
+@c German node Verschieben
+@subsection Eine InnoDB-Datenbank auf eine andere Maschine verschieben
+
+InnoDB-Daten- und Log-Dateien sind auf allen Plattformen binärkompatibel,
+wenn das Fließkommazahlenformat auf den Maschinen dasselbe ist. Sie können
+eine InnoDB-Datenbank einfach verschieben, indem Sie alle relevanten
+Dateien kopieren, die im vorherigen Abschnitt über Datensicherung erwähnt
+wurden. Wenn sich das Fließkommaformat auf den Maschinen unterscheidet,
+sie aber keine @code{FLOAT}- oder @code{DOUBLE}-Datentypen in Ihren
+Tabellen benutzt haben, ist die Prozedur dieselbe: Kopieren Sie einfach die
+relevanten Dateien. Wenn die Formate unterschiedlich sind und Ihre Tabellen
+Fließkomma-Daten enthalten, müssen Sie @file{mysqldump} und
+@file{mysqlimport} benutzen, um diese Tabellen zu verschieben.
+
+Ein Tipp zur Performance: Schalten Sie Auto-Commit aus, wenn Sie Daten in
+Ihre Datenbank importieren (unter der Annahme, dass Ihr Tabellenplatz
+(Tablespace) genug Platz für das große Rollback-Segment enthält, den die
+große Import-Transaktion erzeugen wird). Machen Sie das Commit erst nach
+dem Import einer ganzen Tabelle oder eines Segments einer Tabelle.
+
+
+@node InnoDB transaction model, Implementation, Moving, InnoDB
+@c German node InnoDB-Transaktionsmodell
+@subsection InnoDB-Transaktionsmodell
+
+Im InnoDB-Transaktionsmodell war das Ziel, die besten Eigenschaften einer
+multiversionsfähigen Datenbank mit dem traditionellen Zwei-Phasen-Sperren
+zu verbinden. InnoDB führt Sperren auf Zeilenebene durch und läßt Anfragen
+vorgabemäßig als nicht sperrende konsistente Leseoperationen laufen, im
+Stil von Oracle. Das Tabellensperren ist in InnoDB so platzsparend
+gespeichert, dass keine Sperr-Eskalation benötigt wird: Typischerweise
+dürfen mehrere Benutzer jede Zeile in der Datenbank oder eine beliebige
+Teilmenge der Zeilen sperren, ohne dass InnoDB keinen Speicher mehr hat.
+
+Bei InnoDB findet jede Benutzeraktivität innerhalb von Transaktionen statt.
+Wenn der Auto-Commit-Modus in MySQL benutzt wird, stellt jedes
+SQL-Statement eine einzelne Transaktion dar. Wenn der Auto-Commit-Modus
+ausgeschaltet wird, kann man sich vorstellen, dass ein Benutzer stets eine
+Transaktion offen hat. Wenn er das SQL-@code{COMMIT}- oder
+@code{ROLLBACK}-Statement absetzt, beendet das die aktuelle Transaktion und
+eine neue beginnt. Beide Statements heben alle InnoDB-Sperren auf, die
+während der aktuellen Transaktion gesetzt wurden. Ein @code{COMMIT}
+bedeutet, dass die in der aktuellen Transaktion gemachten Änderungen
+permanent und sichtbar für andere Benutzer gemacht werden. Auf der anderen
+Seite bricht ein @code{ROLLBACK} alle Änderungen ab, die in der aktuellen
+Transaktion gemacht wurden.
+
+
+
+@menu
+* InnoDB consistent read::
+* InnoDB locking reads::
+* InnoDB Next-key locking::
+* InnoDB Locks set::
+* InnoDB Deadlock detection::
+* InnoDB Consistent read example::
+@end menu
+
+@node InnoDB consistent read, InnoDB locking reads, InnoDB transaction model, InnoDB transaction model
+@c German node Konsistentes Lesen bei InnoDB
+@subsubsection Konsistentes Lesen
+
+Konsistentes Lesen bedeutet, dass InnoDB seine Multiversionsfähigkeiten
+nutzt, um einer Anfrage einen Schnappschuss der Datenbank zu einem
+bestimmten Zeitpunkt zu zeigen. Die Anfrage sieht genau die Änderungen, die
+von Transaktionen durchgeführt wurden, die bis zu diesem Zeitpunkt
+abgeschlossen wurden (committed), und keine Änderungen, die später gemacht
+wurden oder die noch nicht abgeschlossen sind. Die Ausnahme von der Regel
+ist, dass die Anfrage die Änderungen sieht, die durch die Transaktion
+selbst durchgeführt wurde, die die Anfrage absetzt.
+
+Wenn eine Transaktion ihr erstes Konsistentes Lesen durchführt, weist
+InnoDB den Schnappschuss oder Zeitpunkt zu, den jedes Konsistente Lesen
+in derselben Transaktion benutzen wird. Im Schnappschuss sind alle
+Transaktionen enthalten, die vor der Zuweisung zum Schnappschuss
+abgeschlossen (committed) wurden. Daher ist Konsistentes Lesens innerhalb
+derselben Transaktion auch untereinander konsistent. Sie können einen
+frischeren Schnappschuss für Ihre Anfragen erhalten, indem Sie die aktuelle
+Transaktion beenden (commit) und danach neue Anfragen absetzen.
+
+Konsistentes Lesen ist der vorgabemäßige Modus, in dem InnoDB
+@code{SELECT}-Statements abarbeitet. Konsistentes Lesen setzt keinerlei
+Sperren auf die Tabellen, auf die es zugreift. Daher können andere Benutzer
+zur selben Zeit, wie Konsistentes Lesen auf die Tabelle durchgeführt wird,
+diese verändern.
+
+
+@node InnoDB locking reads, InnoDB Next-key locking, InnoDB consistent read, InnoDB transaction model
+@c German node Lese-Sperren bei InnoDB
+@subsubsection Lesevorgänge sperren
+
+Unter manchen Umständen ist Konsistentes Lesen nicht wünschenswert.
+Angenommen, Sie wollen eine neue Zeile in die Tabelle @code{kind} einfügen
+und dabei sicherstellen, dass das Kind bereits Eltern in der Tabelle
+@code{eltern} hat.
+
+Wenn Sie Konsistentes Lesen benutzen, um die Tabelle @code{eltern} zu lesen
+und in der Tat die Eltern des Kindes in der Tabelle sehen, können Sie dann
+sicher die Kind-Zeile zur Tabelle @code{kind} hinzufügen? Nein, denn es
+kann sein, dass zwischenzeitlich jemand anderes die Eltern-Zeile aus der
+Tabelle @code{eltern} gelöscht hat und Sie das nicht sehen.
+
+Die Lösung besteht darin, das @code{SELECT} im Sperrmodus durchzuführen.
+@code{LOCK IN SHARE MODE}.
+
+@example
+SELECT * FROM eltern WHERE NAME = 'Hinz' LOCK IN SHARE MODE;
+@end example
+
+Wenn Sie ein Lesen im Share-Modus durchführen, heißt das, dass die letzten
+verfügbaren Daten gelesen werden und eine Shared-Modus-Sperre auf die Zeile
+gesetzt wird, die gelesen wird. Wenn die letzten Daten zu einer noch nicht
+abgeschlossenen Transaktion eines anderen Benutzers gehören, wird gewartet,
+bis die Transaktion abgeschlossen (committed) ist. Eine Shared-Modus-Sperre
+verhindert, dass andere die Zeile aktualisieren oder löschen, die gerade
+gelesen wurde. Nachdem festgestellt wurde, dass die obige Anfrage die
+Eltern @code{'Hinr'} zurückgibt, kann das Kind sicher zur Tabelle
+@code{kind} hinzugefügt und die Transaktion abgeschlossen werden. Dieses
+Beispiel zeigt, wie Sie in Ihren Applikations-Code referentielle Integrität
+integrieren können.
+
+Sehen wir uns ein weiteres Beispiel an. Wir haben ein ganzzahliges
+Zählerfeld in einer Tabelle @code{kind_codes}, was benutzt wird, um jedem
+Kinde, das wir der Tabelle @code{kind} hinzufügen, eine eindeutige Kennung
+zuzuweisen. Es ist offensichtlich, dass Konsistentes Lesen oder
+Shared-Modus-Lesen kein geeignetes Mittel ist, um den aktuellen Wert des
+Zählers zu ermitteln, weil nämlich zwei Benutzer der Datenbank denselben
+Wert des Zählers sehen können und wir daher einen Fehler wegen doppelter
+Schlüsseleinträge erhalten, wenn wir zwei Kinder mit derselben Kennung in
+die Tabelle einfügen.
+
+In diesem Fall gibt es zwei geeignete Möglichkeiten, das Lesen und
+Heraufzählen des Zählers zu implementieren:
+(1) Zuerst den Zähler um eins erhöhen und erst danach lesen.
+(2) Zuerst den Zähler im Sperr-Modus @code{FOR UPDATE} lesen und danach
+heraufzählen:
+
+@example
+SELECT COUNTER_FIELD FROM kind_codes FOR UPDATE;
+UPDATE kind_codes SET COUNTER_FIELD = COUNTER_FIELD + 1;
+@end example
+
+@code{SELECT ... FOR UPDATE} liest die letzten verfügbaren Daten und setzt
+exklusive Sperren auf jede Zeile, die es liest. Daher setzt es dieselben
+Sperren, die ein gesuchtes SQL-@code{UPDATE} auf die Zeilen setzen würde.
+
+
+@node InnoDB Next-key locking, InnoDB Locks set, InnoDB locking reads, InnoDB transaction model
+@c German node Nächsten-Schlüssel-Sperren bei InnoDB
+@subsubsection Nächsten Schlüssel sperren: Wie das Phantom-Problem vermieden wird
+
+Beim Sperren auf Zeilenebene benutzt InnoDB einen Algorithmus, der
+Nächsten-Schlüssel-Sperren genannt wird. InnoDB führt das Sperren auf
+Zeilenebene so durch, dass es beim Suchen oder Scannen eines Indexes auf
+eine Tabelle gemeinsam genutzte (shared) oder exklusive Sperren auf die
+Index-Datensätze setzt, die es findet. Daher werden die Sperren auf
+Zeilenebene genauer Index-Datensatz-Sperren genannt.
+
+Die Sperren, die InnoDB auf Index-Datensätze setzt, betreffen auch die
+'Lücke' vor diesem Index-Datensatz. Wenn ein Benutzer eine gemeinsam
+benutzte (shared) oder exklusive Sperre auf den Datensatz R in einem Index
+hat, kann ein anderen Benutzer keinen Datensatz direkt vor R (in der
+Index-Reihenfolge) einfügen. Dieses Sperren von Lücken wird durchgeführt,
+um das so genannte Phantom-Problem zu vermeiden. Angenommen, man will alle
+Kinder aus der Tabelle @code{kind} lesen und sperren, die eine Kennung
+größer 100 haben, und irgend ein Feld in der ausgewählten Zeile
+aktualisieren:
+
+@example
+SELECT * FROM kind WHERE ID > 100 FOR UPDATE;
+@end example
+
+Angenommen, es gibt einen Index auf der Tabelle @code{kind} auf der Spalte
+@code{ID}. Unsere Anfrage scannt diesen Index ab dem ersten Datensatz, bei
+dem @code{ID} größer als 100 ist. Wenn jetzt die auf den Index-Datensatz
+gesetzten Sperren nicht Einfügeoperationen sperren würden, die in die
+Lücken ausgeführt würden, könnte zwischenzeitlich ein neues Kind in die
+Tabelle eingefügt werden. Wenn jetzt unsere Transaktion noch einmal
+folgendes ausführen würde:
+
+@example
+SELECT * FROM kind WHERE ID > 100 FOR UPDATE;
+@end example
+
+Sehen wir ein neues Kind in der Ergebnismenge, die die Anfrage zurückgibt.
+Das verstößt gegen das Isolationsprinzip von Transaktionen: Eine
+Transaktion sollte in der Lage sein, so abzulaufen, dass die Daten, die sie
+gelesen hat, sich nicht während der Transaktion ändern. Wenn wir einen Satz
+von Zeilen als Daten-Posten betrachten, würde das neue 'Phantom'-Kind
+dieses Isolationsprinzip durchbrechen.
+
+Wenn InnoDB einen Index scannt, kann es auch die Lücke nach dem letzten
+Datensatz im Index sperren. Genau das passiert im vorherigen Beispiel: Die
+Sperren, die von InnoDB gesetzt werden, verhindert jedes Einfügen in die
+Tabelle an Stellen, wo @code{ID} größer als 100 ist.
+
+Sie können Nächsten-Schlüssel-Sperren dazu benutzen, eine
+Eindeutigkeitsprüfung in Ihre Applikation zu implementieren: Wenn Sie Ihre
+Daten im Share-Modus lesen und kein Duplikat für eine Zeile sehen, die Sie
+einfügen werden, können Sie Ihre Zeile sicher einfügen und wissen, dass das
+Nächsten-Schlüssel-Sperren verhindern wird, dass zwischenzeitlich jemand
+eine Duplikatzeile Ihrer Zeile einfügt. Daher gestattet Ihnen das
+Nächsten-Schlüssel-Sperren, die Nicht-Existenz von irgend etwas in Ihrer
+Tabelle zu 'sperren'.
+
+@node InnoDB Locks set, InnoDB Deadlock detection, InnoDB Next-key locking, InnoDB transaction model
+@c German node Bei InnoDB gesetzte Sperren
+@subsubsection Sperren, die in InnoDB durch unterschiedliche SQL-Statements gesetzt werden
+
+@itemize @bullet
+@item
+@code{SELECT ... FROM ...} : Das ist Konsistentes Lesen, es wird ein
+Schnappschuss einer Datenbank gelesen und es werden keine Sperren gesetzt.
+@item
+@code{SELECT ... FROM ... LOCK IN SHARE MODE} : setzt gemeinsam genutztes
+(shared) Nächsten-Schlüssel-Sperren auf alle Index-Datensätze, die beim
+Lesen gefunden werden.
+@item
+@code{SELECT ... FROM ... FOR UPDATE} : setzt exklusives
+Nächsten-Schlüssel-Sperren auf alle Index-Datensätze, die beim Lesen
+gefunden werden.
+@item
+@code{INSERT INTO ... VALUES (...)} : setzt eine exklusive Sperre auf die
+eingefügte Zeile. Beachten Sie, dass diese Sperre kein
+Nächsten-Schlüssel-Sperren ist und andere Benutzer nicht davon abhält,
+etwas in die Lücke vor der eingefügten Zeile einzufügen. Wenn ein Fehler
+wegen doppelter Schlüsseleinträge auftritt, setzt dieser Befehl eine
+gemeinsam genutzte (shared) Sperre auf den doppelten (Duplikat)
+Index-Datensatz.
+@item
+@code{INSERT INTO T SELECT ... FROM S WHERE ...} setzt eine exklusive
+Sperre (kein Nächsten-Schlüssel-Sperren) auf jede Zeile, die in @code{T}
+eingefügt wurde. Sucht nach @code{S} in Form von Konsistentem Lesen, aber
+setzt Nächsten-Schlüssel-Sperren auf @code{S}, wenn bei MySQL das Loggen
+angeschaltet ist. InnoDB muss in letzterem Fall Sperren setzen, weil bei
+einer Roll-Forward-Wiederherstellung aus einer Datensicherung jedes
+SQL-Statement auf genau dieselbe Weise ausgeführt werden muss, wie es
+ursprünglich ausgeführt wurde.
+@item
+@code{CREATE TABLE ... SELECT ...} führt @code{SELECT} als Konsistentes
+Lesen oder mit gemeinsam genutzten (shared) Sperren aus, wie im vorherigen
+Punkt.
+@item
+@code{REPLACE} wird wie Einfügen ausgeführt, wenn es keine Kollision auf
+einem eindeutigen Schlüssel gibt. Ansonsten wird ein exklusives
+Nächsten-Schlüssel-Sperren auf die Reihe gesetzt, die aktualisiert werden
+muss.
+@item
+@code{UPDATE ... SET ... WHERE ...} setzt ein exklusives
+Nächsten-Schlüssel-Sperren auf jeden Datensatz, der beim Suchen gefunden
+wird.
+@item
+@code{DELETE FROM ... WHERE ...} setzt ein exklusives
+Nächsten-Schlüssel-Sperren auf jeden Datensatz, der beim Suchen gefunden
+wird.
+@item
+Wenn auf der Tabelle eine @code{FOREIGN KEY}-Beschränkung definiert ist,
+setzt jedes Einfügen, Aktualisieren oder Löschen, was die Überprüfung der
+Beschränkungsbedingung erfordert, gemeinsam genutzte (shared) Sperren auf
+Datensatzebene auf die Datensätze, die bei der Überprüfung der Beschränkung
+betrachtet werden. Auch im Falle, dass die Beschränkung fehlschlägt, setzt
+InnoDB diese Sperren.
+@item
+@code{LOCK TABLES ... } : setzt Tabellensperren. In der Implementation
+setzt die MySQL-Ebene des Codes diese Sperren. Die automatische
+Blockierungserkennung von InnoDB kann keine Blockierungen bemerken, bei
+denen solche Tabellensperren involviert sind, siehe nächster Abschnitt
+weiter unten. Sehen Sie auch im Abschnitt 13 ('InnoDB-Einschränkungen')
+wegen folgendem nach: Weil MySQL keine Sperren auf Zeilenebene erkennt, ist
+es möglich, dass Sie eine Sperre auf eine Tabelle erhalten, auf der ein
+anderer Benutzer momentan Sperren auf Zeilenebene hat. Das gefährdet
+allerdings nicht die Transaktionsintegrität.
+@end itemize
+
+
+@node InnoDB Deadlock detection, InnoDB Consistent read example, InnoDB Locks set, InnoDB transaction model
+@c German node Blockierungserkennung bei InnoDB
+@subsubsection Blockierungserkennung und Rollback
+
+InnoDB erkennt automatisch eine Blockierung von Transaktionen und rollt die
+Transaktion zurück, deren Sperranforderung diejenige war, die die
+Blockierung aufbaute, also einen Kreis im Warte-Diagramm von Transaktionen.
+InnoDB kann keine Blockierungen erkennen, bei denen eine Sperre im Spiel
+ist, die durch ein MySQL-@code{LOCK TABLES}-Statement verursacht wurde,
+oder wenn eine Sperre durch einen anderen Tabellen-Handler als InnoDB
+gesetzt wurde. Solche Situationen müssen Sie mit
+@code{innodb_lock_wait_timeout}, das in @file{my.cnf} gesetzt wird.
+
+Wenn InnoDB ein komplettes Rollback einer Transaktion durchführt, werden
+alle Sperren der Transaktion aufgehoben. Wenn jedoch nur ein einzelnes
+SQL-Statement als Ergebnis eines Fehlers zurückgerollt wird, können einige
+der Sperren, die durch das SQL-Statement gesetzt wurde, verbleiben. Das
+liegt daran, dass InnoDB Zeilensperren in einem Format speichert, die ihm
+unmöglich machen, im Nachhinein zu erkennen, welche Sperre durch welches
+SQL-Statement gesetzt wurde.
+
+@node InnoDB Consistent read example, , InnoDB Deadlock detection, InnoDB transaction model
+@c German node Konsistentes Lesen bei InnoDB im Beispiel
+@subsubsection Ein Beispiel, wie konsistentes Lesen bei InnoDB funktioniert
+
+Wenn Sie ein Konsistentes Lesen ausführen, also ein gewöhnliches
+@code{SELECT}-Statement, gibt InnoDB Ihrer Transaktion einen Zeitpunkt
+(Timepoint), gemäß dem Ihre Anfrage die Datenbank sieht. Wenn daher
+Transaktion B eine Zeile löscht und das wirksam wird (commit), nachdem Ihr
+Zeitpunkt zugewiesen wurde, werden Sie die Zeile nicht als gelöscht sehen.
+Gleiches gilt für Einfüge- und Aktualisierungsoperationen.
+
+Sie können Ihren Zeitpunkt 'vorstellen', indem Sie Ihre Transaktion
+abschicken (commit) und dann ein weiteres @code{SELECT} ausführen.
+
+Das nennt sich Multiversioned Concurrency Control (multiversionierte
+Gleichzeitigkeitskontrolle):
+
+@example
+ Benutzer A Benutzer B
+
+ set autocommit=0; set autocommit=0;
+zeit
+| SELECT * FROM t;
+| empty set
+| INSERT INTO t VALUES (1, 2);
+|
+v SELECT * FROM t;
+ empty set
+ COMMIT;
+
+ SELECT * FROM t;
+ empty set;
+
+ COMMIT;
+
+ SELECT * FROM t;
+ ---------------------
+ | 1 | 2 |
+ ---------------------
+@end example
+
+Daher sieht Benutzer A die durch B eingefügte Zeile erst, wenn B das
+Einfügen und A seine eigene Transaktion abgeschickt hat (commit), so dass
+der Zeitpunkt hinter das Commit von B 'vorgestellt' ist.
+
+Wenn Sie den 'frischsten' Zustand der Datenbank sehen wollen, sollten Sie
+ein sperrendes Lesen (Locking Read) benutzen:
+
+@example
+SELECT * FROM t LOCK IN SHARE MODE;
+@end example
+
+
+@subsection Tipps zur Performance-Steigerung
+
+@strong{1.}
+Wenn das Unix-@file{top} oder der Windows-@file{Task-Manager} zeigen, dass
+die CPU-Auslastung weniger als 70% beträgt, ist Ihre Auslastung
+wahrscheinlich Platten-gebunden. Das kann daran liegen, dass Sie zu viele
+Transaktionen abschicken (commit) oder dass der Puffer-Pool zu klein ist.
+Dann kann es helfen, den Puffer-Pool zu vergrößern. Setzen Sie ihn aber
+nicht höher als 80% des physikalischen Arbeitsspeichers.
+
+@strong{2.}
+Packen Sie mehrere Änderungen in eine Transaktion. InnoDB muss das Log
+jedes Mal auf Platte zurückschreiben (flush), wenn eine Transaktion
+abgeschickt wird (commit), wenn diese Transaktion irgend welche Änderungen
+an der Datenbank vorgenommen hat. Weil die Rotationsgeschwindigkeit einer
+Platte typischerweise höchsten 167 Umdrehungen pro Sekunde beträgt,
+beschränkt das die Anzahl von Commits auf eben diese Zahl pro Sekunde, wenn
+die Festplatte nicht das Betriebssystem täuscht.
+
+@strong{3.}
+Wenn Sie es sich leisten können, einige der zuletzt abgeschickten
+(committed) Transaktionen zu verlieren, können Sie den
+@file{my.cnf}-Parameter @code{innodb_flush_log_at_trx_commit} auf 0 setzen.
+InnoDB versucht dann trotzdem, das Log einmal pro Sekunde auf Platte
+zurückzuschreiben (flush), doch dieses Zurückschreiben ist nicht
+garantiert.
+
+@strong{4.}
+Machen Sie Ihre Log-Dateien Groß, selbst so Groß wie den Puffer-Pool.
+Wenn InnoDB seine Log-Dateien vollgeschrieben hat, muss es die veränderten
+Inhalte des Puffer-Pools in einem Checkpoint auf Platte schreiben. Kleine
+Log-Dateien verursachen daher unnötige Festplatten-Schreibzugriffe. Der
+Nachteil großer Log-Dateien liegt darin, dass die Wiederherstellungszeit
+länger wird.
+
+@strong{5.}
+Ausserdem sollte der Log-Puffer recht Groß sein, sagen wir 8 MB.
+
+@strong{6.} (Relevant from 3.23.39 up.)
+In einigen Versionen von Linux und Unix ist das Zurückschreiben von Dateien
+auf Platte (flush) mit dem Unix-@code{fdatasync} und anderen ähnlichen
+Methoden überraschend langsam. InnoDB benutzt vorgabemäßig die
+@code{fdatasync}-Funktion. Wenn Sie mit der Datenbank-Schreib-Performance
+nicht zufrieden sind, können Sie versuchen, die @code{innodb_flush_method}
+in @file{my.cnf} auf @code{O_DSYNC} zu setzen, obwohl O_DSYNC auf den
+meisten Systemen langsamer zu sein scheint.
+
+@strong{7.} Wenn Sie Daten in InnoDB importieren, stellen Sie sicher, dass
+MySQL @code{autocommit=1} nicht angeschaltet hat, denn dann benötigt jedes
+Einfügen ein Zurückschreiben des Logs auf Platte (flush). Setzen Sie vor
+Ihre SQL-Importdatei die Zeile
+
+@example
+set autocommit=0;
+@end example
+
+und danach
+
+@example
+commit;
+@end example
+
+Wenn Sie die @file{mysqldump}-Option @code{--opt} benutzen, erhalten Sie
+Dump-Dateien, die sich sehr schnell auch in eine InnoDB-Tabelle importieren
+lassen, selbst ohne sie in die oben erwähnten @code{set autocommit=0; ...
+commit;}-Wrapper zu verpacken.
+
+@strong{8.}
+Hüten Sie sich vor großen Rollbacks beim Einfügen von Massendaten: InnoDB
+benutzt den Einfüge-Puffer, um beim Einfügen Festplatten-Ein- und -Ausgaben
+zu sparen, doch beim entsprechenden Rollback wird kein solcher Mechanismus
+benutzt. Ein Festplatten-gebundenes Rollback kann die 30-fache Zeit des
+entsprechenden Einfügevorgangs in Anspruch nehmen. Es hilft nicht, den
+Datenbankprozess zu killen, weil der Rollback erneut starten wird, wenn die
+Datenbank hochfährt. Die einzige Möglichkeit, ein aus dem Ruder gelaufenes
+Rollback loszuwerden, besteht darin, den Puffer-Pool zu erhöhen, so dass
+das Rollback CPU-gebunden wird und damit schnell läuft, oder indem die
+gesamte InnoDB-Datenbank gelöscht wird.
+
+@strong{9.}
+Seien Sie auch vor anderen großen Festplatten-gebundenen Operationen auf
+der Hut. Benutzen Sie @code{DROP TABLE} oder @code{TRUNCATE} (ab
+MySQL-4.0), um eine Tabelle zu löschen, nicht @code{DELETE FROM tabelle}.
+
+@strong{10.}
+Benutzen Sie das mehrzeilige @code{INSERT}, um den Kommunikations-Overhead
+zwischen Client und Server zu verringern, wenn Sie viele Zeilen einfügen
+müssen:
+
+@example
+INSERT INTO tabelle VALUES (1, 2), (5, 5);
+@end example
+
+Dieser Tipp gilt natürlich für jeden Tabellentyp, nicht nur für InnoDB.
+
+@subsubsection Der InnoDB-Monitor
+
+Ab Version 3.23.41 beinhaltet InnoDB den InnoDB-Monitor, der Informationen
+über den internen Zustand von InnoDB ausgibt. Wenn er angeschaltet ist,
+veranlasst der InnoDB-Monitor den MySQL-Server @file{mysqld}, etwa alle 15
+Sekunden Daten an die Standardausgabe auszugeben (Hinweis: der MySQL-Client
+gibt nichts aus). Diese Daten sind nützlich, um die Performance zu tunen.
+Unter Windows müssen Sie @code{mysqld-max} von einer DOS-Kommandozeile aus
+mit @code{--standalone --console} starten, um die Ausgabe auf das
+DOS-Fenster umzuleiten.
+
+Es gibt einen separaten @code{innodb_lock_monitor}, der dieselben
+Informationen ausgibt wie @code{innodb_monitor}, aber zusätzlich
+Informationen über Sperren, die durch jede Transaktion gesetzt werden.
+
+Die ausgegebene Information enthält Daten über:
+@itemize @bullet
+@item
+Sperren, die auf eine Transaktion warten,
+@item
+Semaphore, die auf Threads warten,
+@item
+anhängige Datei-Ein- und -Ausgabeanforderungen,
+@item
+Puffer-Pool-Statistiken und
+@item
+Bereinigungs- (purge) und Einfüge-Puffer-Vermengungs- (merge) Aktivität des
+Haupt-Threads von InnoDB.
+@end itemize
+
+Sie können den InnoDB-Monitor mit folgendem SQL-Befehl starten:
+
+@example
+CREATE TABLE innodb_monitor(a int) type = innodb;
+@end example
+
+Und ihn mit folgendem Befehl anhalten:
+
+@example
+DROP TABLE innodb_monitor;
+@end example
+
+Die @code{CREATE TABLE}-Syntax ist nur eine Möglichkeit, einen Befehl durch
+den MySQL-SQL-Parser an die InnoDB-Engine durchzureichen. Wenn Sie die
+Datenbank herunter fahren, während der Monitor läuft, und Sie den Monitor
+erneut starten wollen, müssen Sie die Tabelle löschen, bevor Sie ein
+erneutes @code{CREATE TABLE} absetzen können, um den Monitor zu starten.
+Diese Syntax wird sich in zukünftigen Releases möglicherweise ändern.
+
+
+Beispiel für die Ausgabe des InnoDB-Monitors:
+
+@example
+================================
+010809 18:45:06 INNODB MONITOR OUTPUT
+================================
+--------------------------
+LOCKS HELD BY transactions
+--------------------------
+LOCK INFO:
+Number of locks in the record hash table 1294
+LOCKS FOR TRANSACTION ID 0 579342744
+TABLE LOCK table test/tabelle trx id 0 582333343 lock_mode IX
+
+RECORD LOCKS space id 0 page no 12758 n bits 104 table test/tabelle index
+PRIMARY trx id 0 582333343 lock_mode X
+Record lock, heap no 2 PHYSICAL RECORD: n_fields 74; 1-byte offs FALSE;
+info bits 0
+ 0: len 4; hex 0001a801; asc ;; 1: len 6; hex 000022b5b39f; asc ";; 2: len 7;
+hex 000002001e03ec; asc ;; 3: len 4; hex 00000001;
+...
+-----------------------------------------------
+CURRENT SEMAPHORES RESERVED AND SEMAPHORE WAITS
+-----------------------------------------------
+SYNC INFO:
+Sorry, cannot give mutex list info in non-debug version!
+Sorry, cannot give rw-lock list info in non-debug version!
+-----------------------------------------------------
+SYNC ARRAY INFO: reservation count 6041054, signal count 2913432
+4a239430 waited for by thread 49627477 op. S-LOCK file NOT KNOWN line 0
+Mut ex 0 sp 5530989 r 62038708 sys 2155035; rws 0 8257574 8025336; rwx 0 1121090 1848344
+-----------------------------------------------------
+CURRENT PENDING FILE I/O'S
+--------------------------
+Pending normal aio reads:
+Reserved slot, messages 40157658 4a4a40b8
+Reserved slot, messages 40157658 4a477e28
+...
+Reserved slot, messages 40157658 4a4424a8
+Reserved slot, messages 40157658 4a39ea38
+Total of 36 reserved aio slots
+Pending aio writes:
+Total of 0 reserved aio slots
+Pending insert buffer aio reads:
+Total of 0 reserved aio slots
+Pending log writes or reads:
+Reserved slot, messages 40158c98 40157f98
+Total of 1 reserved aio slots
+Pending synchronous reads or writes:
+Total of 0 reserved aio slots
+-----------
+BUFFER POOL
+-----------
+LRU list length 8034
+Free list length 0
+Flush list length 999
+Buffer pool size in pages 8192
+Pending reads 39
+Pending writes: LRU 0, flush list 0, single page 0
+Pages read 31383918, created 51310, written 2985115
+----------------------------
+END OF INNODB MONITOR OUTPUT
+============================
+010809 18:45:22 InnoDB starts purge
+010809 18:45:22 InnoDB purged 0 pages
+@end example
+
+Einige Anmerkungen zur Ausgabe:
+
+@itemize @bullet
+@item
+Wenn der Abschnitt @code{LOCKS HELD BY transactions} warten auf Sperren
+berichtet, kann es sein, dass Ihre Applikation Sperr-Konflikte hat. Die
+Ausgabe kann auch helfen, Gründe für Transaktions-Blockierungen
+aufzuspüren.
+@item
+Der Abschnitt @code{SYNC INFO} berichtet reservierte Semaphore, wenn Sie
+InnoDB mit @code{UNIV_SYNC_DEBUG} kompilieren, definiert in @file{univ.i}.
+@item
+Der Abschnitt @code{SYNC ARRAY INFO} berichtet Threads, die auf ein
+Semaphor warten, und Statistiken, wie viele Male Threads ein Spin oder ein
+Warten auf einem Mutex oder einem Lese-/Schreibe-Sperr-Semaphor benötigten.
+Eine große Anzahl auf Semaphore wartender Threads kann ein Ergebnis von
+Festplatten-Ein- und -Ausgaben oder Konfliktproblemen innerhalb von InnoDB
+sein. Konflikte können durch starke Parallelen von Anfragen oder durch
+Probleme des Betriebssystems beim Thread Scheduling hervorgerufen werden.
+@item
+Der Abschnitt @code{CURRENT PENDING FILE I/O'S} listet anhängige Datei-Ein-
+und -Ausgabeanforderungen auf. Eine große Anzahl davon zeigt an, dass die
+Auslastung Festplatten-Ein- und -Ausgabe-gebunden ist.
+@item
+Der Abschnitt @code{BUFFER POOL} gibt statistische Informationen über
+gelesene und geschriebene Seiten. Aus diesen Zahlen können Sie errechnen,
+wie viele Daten-Datei-Ein- und Ausgaben Ihre Anfragen aktuell durchführen.
+@end itemize
+
+@node Implementation, Table and index, InnoDB transaction model, InnoDB
+@c German node Implementation
+@subsection Implementation des Multiversionings
+
+Weil InnoDB eine multiversionierte Datenbank ist, muss es Informationen
+über alte Versionen von Zeilen im Tabellenplatz (Tablespace) aufbewahren.
+Diese Informationen werden in einer Datenstruktur gespeichert, die wir in
+Anlehnung an eine analoge Struktur in Oracle Rollback-Segment nennen.
+
+InnoDB fügt jeder Zeile, die in der Datenbank gespeichert wird, intern zwei
+Felder hinzu. Ein 6 Byte großes Feld enthält den
+Transaktions-Identifikator der letzten Transaktion, die die Zeile eingefügt
+oder aktualisiert hat. Ein Löschen wir intern als eine Aktualisierung
+behandelt, wobei ein spezielles Bit in die Zeile eingefügt wird, um sie als
+gelöscht zu markieren. Jede Zeile enthält ausserdem ein 7 Byte großes
+Feld, das Roll-Zeiger genannt wird. Der Roll-Zeiger zeigt auf einen
+Rückgängig-Log-Datensatz, der in das Rollback-Segment geschrieben wird.
+Wenn die Zeile aktualisiert wurde, enthält der Rückgängig-Log-Datensatz die
+Informationen, die notwendig sind, um den Inhalt der Zeile wieder
+herzustellen, bevor sie aktualisiert wurde.
+
+InnoDB benutzt die Informationen im Rollback-Segment, um die
+Rückgängig-Operationen durchzuführen, die bei einem Transaktions-Rollback
+notwendig sind. Diese Informationen benutzt es auch dafür, um frühere
+Informationen einer Zeile beim Konsistenten Lesen aufzubauen.
+
+Rückgängig-Logs im Rollback-Segment lassen sich in Logs für Einfügen und
+für Aktualisieren unterteilen. Einfüge-Rückgängig-Logs werden nur für
+Transaktions-Rollbacks benötigt und können verworfen werden, sobald die
+Transaktion abgeschickt ist (commit). Aktualisierungs-Rückgängig-Logs
+werden auch für Konsistentes Lesens benutzt und können daher erst verworfen
+werden, wenn keine Transaktion mehr vorhanden ist, für die InnoDB einen
+Schnappschuss zugewiesen hat, dessen Informationen beim Konsistenten Lesen
+benötigt werden könnten, um daraus eine frühere Version der Datenbank-Zeile
+aufzubauen.
+
+Sie müssen daran denken, Ihre Transaktionen regelmäßig abzuschicken
+(commit), auch die Transaktionen, die nur Konsistentes Lesens ausführen.
+Ansonsten kann InnoDB Daten aus dem Aktualisierungs-Rückgängig-Log nicht
+verwerfen und das Rollback-Segment könnte zu Groß werden und Ihren
+Tabellenplatz (Tablespace) komplett füllen.
+
+Die physikalische Größe eines Rückgängig-Log-Datensatzes im
+Rollback-Segment ist typischerweise kleiner als die entsprechende
+eingefügte oder aktualisierte Zeile. Sie können diese Informationen
+benutzen, um den Platzbedarf für Ihr Rollback-Segment zu berechnen.
+
+In diesem multiversionierten Schema wird eine Zeile nicht unmittelbar
+physikalisch aus der Datenbank entfernt, wenn Sie sie mit einem
+SQL-Statement löschen. Erst wenn InnoDB den Datensatz des
+Aktualisierungs-Rückgängig-Logs löschen kann, der für das Löschen
+geschrieben wurde, kann es die entsprechende Zeile und ihre
+Index-Datensätze auch physikalisch aus der Datenbank entfernen. Diese
+Entfernungsoperation wird Purge genannt und ist recht schnell, wobei sie
+überschlägig dieselbe Zeit benötigt wie das SQL-Statement, das das Löschen
+ausführte.
+
+
+@node Table and index, File space management, Implementation, InnoDB
+@c German node Tabelle und Index
+@subsection Tabellen- und Index-Strukturen
+
+MySQL speichert seine Daten-Wörterbuch-Informationen über Tabellen in
+@file{.frm}-Dateien in den Datenbank-Verzeichnissen. Jedoch hat auch jede
+Tabelle vom Typ InnoDB ihren eigenen Eintrag, in InnoDB-internen
+Daten-Wörterbüchern innerhalb des Tabellenplatzes (Tablespace). Wenn MySQL
+eine Tabelle oder Datenbank löscht, muss er sowohl eine oder mehrere
+@file{.frm}-Datei(en) als auch die entsprechenden Einträge im
+InnoDB-Daten-Wörterbuch löschen. Das ist der Grund, warum Sie
+InnoDB-Tabellen nicht einfach zwischen Datenbanken verschieben können,
+indem Sie die @file{.frm}-Dateien verschieben und warum @code{DROP
+DATABASE} bei InnoDB-Tabellen in MySQL-Versionen bis 3.23.43 nicht
+funktionierte.
+
+Jede InnoDB-Tabelle hat einen speziellen Index, der Cluster-Index genannt
+wird, in dem die Daten der Zeilen gespeichert sind. Wenn Sie auf Ihre
+Tabelle einen @code{PRIMARY KEY} definieren, ist der Index des
+Primärschlüssels der Cluster-Index.
+
+Wenn Sie für Ihre Tabelle keinen Primärschlüssel definieren, erzeugt InnoDB
+intern einen Cluster-Index, bei dem die Zeilen nach der Zeilen-Kennung (ID)
+geordnet sind, die InnoDB Zeilen in einer solchen Tabelle zuweist. Die
+Zeilen-Kennung ist ein 6 Byte großes Feld, das monoton erhöht wird, wenn
+neue Zeilen eingefügt werden. Daher liegen nach der Zeilen-Kennung
+geordnete Zeile physikalisch in der Einfüge-Reihenfolge vor.
+
+Der Zugriff auf eine Zeile über den Cluster-Index ist schnell, weil die
+Zeilendaten auf derselben Seite sind, auf die die Index-Suche führt. In
+vielen Datenbanken werden die Daten traditionell auf einer anderen Seite
+als derjenigen, wo sich der Index-Datensatz befindet, gespeichert. Wenn die
+Tabelle Groß ist, spart die Cluster-Index-Architektur im Vergleich zur
+traditionellen Lösung auf Festplatten-Ein- und -Ausgaben.
+
+In InnoDB enthalten die Datensätze in Nicht-Cluster-Indexen (die wir auch
+sekundäre Indexe nennen) den Primärschlüsselwert für die Zeile. InnoDB
+benutzt diesen Primärschlüsselwert, um vom Cluster-Index aus nach der Zeile
+zu suchen. Beachten Sie, dass die sekundären Indexe mehr Platz benötigen,
+wenn der Primärschlüssel lang ist.
+
+
+
+@menu
+* InnoDB physical structure::
+* InnoDB Insert buffering::
+* InnoDB Adaptive hash::
+* InnoDB Physical record::
+@end menu
+
+@node InnoDB physical structure, InnoDB Insert buffering, Table and index, Table and index
+@c German node Physikalische Struktur von InnoDB
+@subsubsection Physikalische Struktur eines Indexes
+
+Alle Indexe in InnoDB sind B-Bäume, in denen die Index-Datensätze in den
+Blätter-Seiten des Baums gespeichert sind. Die vorgabemäßige Größe einer
+Index-Seite ist 16 KB. Wenn neue Datensätze eingefügt werden, versucht
+InnoDB, 1/16 der Seite für zukünftige Einfügungen und Aktualisierungen des
+Index-Datensatzes freizuhalten.
+
+Wenn Index-Datensätze in sequentieller (aufsteigender oder absteigender)
+Reihenfolge eingefügt werden, sind die resultierenden Index-Seiten ungefähr
+zu 15/16 gefüllt. Wenn der Füllfaktor einer Index-Seite unter 1/12 fällt,
+versucht InnoDB, den Index-Baum zusammenzuziehen, um die Seite
+freizugeben.
+
+
+@node InnoDB Insert buffering, InnoDB Adaptive hash, InnoDB physical structure, Table and index
+@c German node Einfügepuffer von InnoDB
+@subsubsection Einfügepufferung
+
+Häufig wird der Primärschlüssel in Datenbank-Applikationen als eindeutiger
+Identifizierer benutzt und neue Zeilen in aufsteigender Reihenfolge des
+Primärschlüssels eingefügt. Daher erfordern Einfügungen in den
+Cluster-Index keine wahlfreien (random) Lesezugriffe auf die Platte.
+
+Sekundäre Indexe auf der anderen Seite sind üblicherweise nicht eindeutig
+und Einfügungen in sekundäre Indexe erfolgen in einer relativ wahlfreien
+Reihenfolge. Wenn InnoDB keinen speziellen Mechanismus hierfür benutzen
+würde, würden diese viele wahlfreie Festplatten-Ein- und -Ausgaben
+verursachen.
+
+Wenn ein Index-Datensatz in einen nicht eindeutigen sekundären Index
+eingefügt werden soll, prüft InnoDB, ob die sekundäre Index-Seite bereits
+im Puffer-Pool ist. Wenn das der Fall ist, führt InnoDB das Einfügen direkt
+in die Index-Seite durch. Wenn die Index-Seite aber nicht im Puffer-Pool
+gefunden wird, fügt InnoDB den Datensatz in eine spezielle
+Einfüge-Puffer-Struktur ein. Der Einfüge-Puffer wird so klein gehalten,
+dass er komplett in den Puffer-Pool passt, so dass Einfügungen sehr schnell
+durchgeführt werden können.
+
+Der Einfüge-Puffer wird periodisch mit den sekundären Index-Bäumen in der
+Datenbank vermengt. Oft können mehrere Einfügeoperationen auf derselben
+Seite im Index-Baum zusammengefasst werden, so dass Festplatten-Ein- und
+-Ausgaben eingespart werden. Messungen ergaben, dass der Einfüge-Puffer
+Einfügungen in eine Tabelle bis zu 15 mal schneller machen kann.
+
+
+@node InnoDB Adaptive hash, InnoDB Physical record, InnoDB Insert buffering, Table and index
+@c German node Anpassungsfähiger Hash in InnoDB
+@subsubsection Anpassungsfähige Hash-Indexe
+
+Wenn eine Datenbank fast komplette in den Hauptspeicher passt, können
+Anfragen am schnellsten unter Verwendung von Hash-Indexen ausgeführt
+werden. InnoDB hat einen automatischen Mechanismus, der Index-Suchen
+beobachtet, die auf den Indexen durchgeführt werden, die für eine Tabelle
+definiert wurden. Wenn InnoDB bemerkt, dass Anfragen vom Aufbauen eines
+Hash-Indexes profitieren könnten, wird ein solcher Index automatisch
+aufgebaut.
+
+Beachten Sie aber, dass der Hash-Index immer auf der Grundlage eines
+bestehenden B-Baum-Indexes auf die Tabelle aufgebaut wird. InnoDB kann
+einen Hash-Index auf einem Präfix beliebiger Länge des Schlüssels aufbauen,
+der für den B-Baum definiert wurde, abhängig vom Suchmuster, das InnoDB auf
+dem Index-Baum beobachtet. Ein Hash-Index kann partiell sein: Es ist nicht
+erforderlich, dass der gesamte Index-Baum im Puffer-Pool
+zwischengespeichert ist. InnoDB baut Hash-Indexe bei Bedarf automatisch für
+die Index-Seiten auf, auf die oft zugegriffen wird.
+
+In gewisser Hinsicht kommt InnoDB durch den anpassungsfähigen
+Hash-Index-Mechanismus (wobei sich InnoDB üppig verfügbarem Hauptspeicher
+anpasst) der Architektur von Hauptspeicher-Datenbanken nahe.
+
+
+@node InnoDB Physical record, , InnoDB Adaptive hash, Table and index
+@c German node Physikalischer Datensatz in InnoDB
+@subsubsection Physikalische Datensatzstruktur
+
+@itemize @bullet
+@item
+Jeder Index-Datensatz in InnoDB enthält einen Header von 6 Bytes. Der
+Header wird benutzt, um nachfolgende Datensätze zu verknüpfen, sowie beim
+Sperren auf Zeilenebene.
+@item
+Datensätze im Cluster-Index enthalten Felder für alle benutzerdefinierten
+Spalten. Zusätzlich gibt es ein 6 Byte großes Feld für die
+Transaktions-Kennung und ein 7 Byte großes Feld für den Roll-Zeiger.
+@item
+Wenn der Benutzer keinen Primärschlüssel für eine Tabelle definiert hat,
+enthält jeder Cluster-Index-Datensatz zusätzlich ein 6 Byte großes
+Zeilenkennungsfeld.
+@item
+Jeder sekundäre Index-Datensatz enthält auch alle Felder, die für den
+Cluster-Index-Schlüssel definiert wurden.
+@item
+Ein Datensatz enthält auch einen Zeiger zu jedem Feld des Datensatzes. Wenn
+die Gesamtlänge des Feldes in einem Datensatz kleiner als 128 Bytes ist,
+ist der Zeiger 1 Byte lang, ansonsten 2 Bytes.
+@end itemize
+
+@subsubsection Wie eine Auto-Increment-Spalte in InnoDB funktioniert
+
+Wenn der Benutzer nach einem Datenbankstart zuerst einen Datensatz in eine
+Tabelle @code{T} einfügt, in der eine Auto-Increment-Spalte definiert
+wurde, und er keinen expliziten Wert für die Spalte angibt, führt InnoDB
+@code{SELECT MAX(auto-inc-column) FROM T} aus und weist den um 1
+hochgezählten Wert der Spalte und dem Auto-Increment-Zähler der Tabelle zu.
+Wir sagen dazu, dass der Auto-Increment-Zähler für Tabelle @code{T}
+initialisiert wurde.
+
+InnoDB führt dieselbe Prozedur der Initialisierung des
+Auto-Increment-Zählers für eine frisch erzeugte Tabelle durch.
+
+Wenn Sie für die Auto-Increment-Spalte einen Wert von 0 angeben, beachten
+Sie, dass InnoDB die Zeile so behandelt, als hätten Sie den Wert nicht
+angegeben.
+
+Wenn nach der Initialisierung des Auto-Increment-Zählers der Benutzer eine
+Zeile eingibt, in der er explizit den Spaltenwert angibt, und dieser
+größer als der aktuelle Zählerwert ist, wird der Zähler auf den
+angegebenen Spaltenwert gesetzt. Wenn der Benutzer nicht explizit einen
+Wert angibt, zählt InnoDB den Zähler um 1 hoch und weist der Spalte diesen
+neuen Wert zu.
+
+Der Auto-Increment-Mechanismus umgeht beim Zuweisen von Werten vom Zähler
+Sperren und Transaktionshandhabung. Daher können Lücken in der
+Nummernfolge entstehen, wenn Sie Transaktionen zurückrollen (Rollback), die
+Nummern vom Zähler erhalten haben.
+
+Das Verhalten von Auto-Increment ist für die Fälle undefiniert, in denen
+ein Benutzer der Spalte einen negativen Wert gibt oder wenn der Wert
+größer als die größte Ganzzahl wird, die im festgelegten Ganzzahl-Typ
+gespeichert werden kann.
+
+
+@node File space management, Error handling, Table and index, InnoDB
+@c German node Verwaltung von Datei-Speicherplatz
+@subsection Verwaltung von Datei-Speicherplatz und Festplatten-Eingaben / -Ausgaben
+
+
+
+@menu
+* InnoDB Disk i/o::
+* InnoDB File space::
+* InnoDB File Defragmenting::
+@end menu
+
+@node InnoDB Disk i/o, InnoDB File space, File space management, File space management
+@c German node Festplatten-Ein- und -Ausgaben bei InnoDB
+@subsubsection Festplatten-Ein- und -Ausgaben
+
+Bei Festplatten-Ein- und -Ausgaben benutzt InnoDB asynchrone Ein- und
+Ausgaben. Unter Windows NT benutzt es die nativen Ein- und Ausgaben, die
+vom Betriebssystem zur Verfügung gestellt werden. Unter Unix benutzt InnoDB
+simulierte asynchrone Ein- und Ausgaben, die in InnoDB eingebaut sind:
+InnoDB erzeugt eine Reihe von Ein-/Ausgabe-Threads, die sich um Ein- und
+Ausgabeoperationen kümmern, zum Beispiel Vorwärts-Lesen (Read-Ahead).
+Zukünftig werden wir auch für Windows NT simulierte Ein-/Ausgaben
+unterstützen sowie für die Unix-Versionen, die so etwas besitzen, native
+Ein-/Ausgaben.
+
+Unter Windows NT benutzt InnoDB ungepufferte Ein- und Ausgaben. Das heißt,
+dass die Festplatten-Seiten, die InnoDB liest oder schreibt, nicht im
+Datei-Cache des Betriebssystems gepuffert werden. Das spart einiges an
+Arbeitsspeicher-Bandbreite.
+
+Ab Version 3.23.41 benutzt InnoDB eine neuartige Datei-Flush-Technik, die
+Doublewrite heißt. Sie erhöht die Sicherheit bei Reparaturen nach Absturz,
+wenn ein Betriebssystemabsturz oder ein Stromausfall aufgetreten sind, und
+verbessert auf den meisten Unix-Versionen die Performance, indem die
+Notwendigkeit von Fsync-Operationen verringert wird.
+
+Doublewrite bedeutet, dass InnoDB zuerst in einen zusammenhängenden
+Tabellenplatz (Tablespace) namens Doublewrite-Puffer schreibt, bevor Seiten
+in eine Daten-Datei geschrieben werden. Erst nachdem das Schreiben und
+Zurückschreiben (Flush) in den Doublewrite-Puffer fertig sind, schreibt
+InnoDB die Seiten an ihre korrekten Positionen in der Daten-Datei. Wenn das
+Betriebssystem mitten in einem Seiten-Schreiben abstürzt, findet InnoDB bei
+der Wiederherstellung eine gute Kopie der Seite im Doublewrite-Puffer.
+
+Ab Version 3.23.41 können Sie auch eine Raw-Disk-Partition als Daten-Datei
+benutzen, obwohl das bisher noch nicht getestet wurde. Wenn Sie eine neue
+Daten-Datei erzeugen, müssen Sie das Schlüsselwort @code{newraw}
+unmittelbar nach der Daten-Datei-Größe in @code{innodb_data_file_path}
+angeben. Die Partition muss größer oder gleich der Größe sein, die Sie
+angeben. Beachten Sie, dass in InnoDB 1 MB 1024 x 1024 Bytes ist, während 1
+MB in Festplatten-Spezifikationen üblicherweise 1.000.000 Bytes bedeutet.
+
+@example
+innodb_data_file_path=hdd1:5Gnewraw;hdd2:2Gnewraw
+@end example
+
+Wenn Sie die Datenbank wieder starten, @strong{müssen} -sue das
+Schlüsselwort in @code{raw} ändern. Ansonsten schreibt InnoDB über Ihre
+Partition!
+
+@example
+innodb_data_file_path=hdd1:5Graw;hdd2:2Graw
+@end example
+
+Wenn Sie Raw-Disk benutzen, können Sie unter einigen Unixen ungepufferte
+Ein- und Ausgaben ausführen.
+
+Es gibt zwei Vorwärts-Lesen-(Read-Ahead-)Heuristiken in InnoDB:
+sequentielles Vorwärts-Lesen und wahlfreies (random) Vorwärts-Lesen. Beim
+sequentiellen Vorwärts-Lesen bemerkt InnoDB, dass das Zugriffsschema auf
+ein Segment im Tabellenplatz (Tablespace) sequentiell ist. InnoDB schickt
+dann vorab einen Stapel von Lesevorgängen von Datenbankseiten an das
+Ein-/Ausgabesystem. Beim wahlfreien Vorwärts-Lesen bemerkt InnoDB, dass ein
+bestimmter Bereich im Tabellenplatz (Tablespace) im Zustand des vollständig
+Eingelesenwerdens in den Puffer-Pool zu sein scheint. Dann schickt InnoDB
+die verbleibenden Lesevorgänge an das Ein-/Ausgabesystem.
+
+
+@node InnoDB File space, InnoDB File Defragmenting, InnoDB Disk i/o, File space management
+@c German node Speicherplatz in InnoDB
+@subsubsection Speicherplatzverwaltung
+
+Die Daten-Dateien, die Sie in der Konfigurationsdatei definieren, formen
+den Tabellenplatz (Tablespace) von InnoDB. Die Dateien werden einfach
+verkettet, um den Tabellenplatz (Tablespace) zu formen, es wird kein
+Striping benutzt. Momentan können Sie nicht direkt angeben, wo der Platz
+für Ihre Tabellen zugewiesen werden soll, ausser wenn Sie folgende Tatsache
+benutzen: InnoDB weist Speicherplatz von einem neu erzeugten Tabellenplatz
+(Tablespace) vom niedrigen Ende ausgehend zu.
+
+Der Tabellenplatz (Tablespace) besteht aus Datenbankseiten, deren
+vorgabemäßige Größe 16 KB beträgt. Diese Seiten werden bis zu einer
+Ausdehnung von 64 aufeinander folgenden Seiten gruppiert. Die 'Dateien'
+innerhalb eines Tabellenplatzes (Tablespace) werden in InnoDB Segmente
+genannt. Der Name des Rollback-Segments ist in gewisser Hinsicht
+irreführend, weil dieses tatsächlich viele Segmente im Tabellenplatz
+enthält.
+
+Für jeden Index in InnoDB werden zwei Segmente zugewiesen: eins für die
+Nicht-Blätter-Knoten (Non-Leaf-Nodes) des B-Baum, das andere für die
+Blätter-Knoten. Die Idee dahinter ist, für die Blätter-Knoten, die die
+Daten enthalten, bessere Sequentialität zu erzielen.
+
+Wenn ein Segment innerhalb des Tabellenplatzes anwächst, weist ihm InnoDB
+die ersten 32 Seiten individuell zu. Danach fängt InnoDB an, dem Segment
+ganze Ausdehnungen zuzuweisen. InnoDB kann einem großen Segment bis zu
+vier Ausdehnungen auf einmal hinzufügen, um gute Sequentialität für die
+Daten sicherzustellen.
+
+Einige Seiten im Tabellenplatz enthalten Bitmaps anderer Seiten. Daher
+können einige Ausdehnungen in einem InnoDB-Tabellenplatz (Tablespace) nicht
+Segmenten als Ganzes zugewiesen werden, sondern nur als individuelle
+Seiten.
+
+Wenn Sie eine Anfrage @code{SHOW TABLE STATUS FROM ... LIKE ...} ausführen,
+um den verfügbaren freien Platz im Tabellenplatz festzustellen, berichtet
+InnoDB den Platz, der in völlig freien Ausdehnungen im Tabellenplatz sicher
+benutzt werden kann. InnoDB reserviert immer einige Ausdehnungen für
+Säuberungs- und interne Zwecke. Diese Ausdehnungen werden nicht in den
+freien Platz einbezogen.
+
+Wenn Sie Daten aus einer Tabelle löschen, zieht InnoDB die entsprechenden
+B-Baum-Indexe zusammen. Es hängt vom Schema der Löschvorgänge ab, ob das
+individuelle Seiten oder Ausdehnungen im Tabellenplatz freigibt, so dass
+der freigegebene Platz anderen Benutzern zur Verfügung steht. Wenn eine
+Tabelle gelöscht wird oder alle Zeilen aus ihr gelöscht werden, gibt das
+garantiert Platz frei für andere Benutzer, aber denken Sie daran, dass
+gelöschte Zeile physikalisch nur durch eine Purge-Operation entfernt werden
+können, nachdem Sie nicht mehr für ein Transaktions-Rollback oder für
+Konsistentes Lesen benötigt werden.
+
+
+@node InnoDB File Defragmenting, , InnoDB File space, File space management
+@c German node Datei-Defragmentierung in InnoDB
+@subsubsection Eine Tabelle defragmentieren
+
+Wenn es wahlfreie (random) Einfüge- oder Löschvorgänge in die Indexe einer
+Tabelle gibt, können die Indexe fragmentiert werden. Unter Fragmentierung
+verstehen wird, dass die physikalische Reihenfolge der Index-Seiten auf der
+Platte der alphabetischen Reihenfolge der Datensätze auf den Seiten nicht
+nahe kommt oder dass es viele unbenutzte Seiten in den 64-Seiten-Blöcken
+gibt, die dem Index zugewiesen wurden.
+
+Index-Scans können beschleunigt werden, wenn Sie von Zeit zu Zeit
+@code{mysqldump} benutzen, um die Tabelle in eine Textdatei zu dumpen, dann
+die Tabelle zu löschen und sie aus dem Dump neu aufzubauen. Eine weitere
+Möglichkeit zur Defragmentierung besteht darin, den Tabellentyp in
+@code{MyISAM} zu ändern (@code{ALTER}) und danach wieder in @code{InnoDB}
+zurück. Beachten Sie, dass die @code{MyISAM}-Tabelle auf Ihrem
+Betriebssystem in eine einzige Datei passen muss.
+
+Wenn die Einfügungen in einen Index immer aufsteigend sind und Datensätze
+nur vom Ende gelöscht werden, garantiert der
+Speicherplatzverwaltungs-Algorithmus von InnoDB, dass keine Fragmentierung
+im Index auftritt.
+
+
+@node Error handling, InnoDB restrictions, File space management, InnoDB
+@c German node Fehlerbehandlung
+@subsection Fehlerbehandlung
+
+Die Fehlerbehandlung in InnoDB ist nicht immer so, wie es die
+ANSI-SQL-Standards festlegen. Nach ANSI-Standard sollte jeder Fehler
+während eines SQL-Statements ein Rollback des Statements verursachen.
+InnoDB rollt manchmal nur Teile des Statements oder auch die gesamte
+Transaktion zurück. Folgende Liste gibt die Fehlerbehandlung von InnoDB an:
+
+@itemize @bullet
+@item
+Wenn es keinen Speicherplatz mehr im Tabellenplatz (Tablespace) gibt,
+bekommen Sie den MySQL-Fehler @code{'Table is full'} und InnoDB rollt das
+SQL-Statement zurück.
+@item
+Eine Transaktions-Blockierung oder eine Zeitüberschreitung beim Warten auf
+eine Sperre führen dazu, dass InnoDB die gesamte Transaktion zurückrollt.
+@item
+Ein Fehler wegen doppelter Schlüsseleinträge rollt das Einfügen dieser
+Zeile zurück, selbst in einem Statement wie @code{INSERT INTO ... SELECT
+...}. Das wird sich voraussichtlich ändern, so dass das SQL-Statement
+zurückgerollt wird, wenn Sie die @code{IGNORE}-Option in Ihrem Statement
+nicht angegeben haben.
+@item
+Ein Fehler 'row too long' rollt das SQL-Statement zurück.
+@item
+Andere Fehler werden zumeist durch die MySQL-Code-Ebene entdeckt und rollen
+das entsprechende SQL-Statement zurück.
+@end itemize
+
+
+@node InnoDB restrictions, InnoDB contact information, Error handling, InnoDB
+@c German node InnoDB-Einschränkungen
+@subsection Beschränkungen von InnoDB-Tabellen
+
+@itemize @bullet
+
+@item
+@strong{ACHTUNG:} Konvertieren Sie @strong{KEINE} MySQL-Systemtabellen von
+MyISAM in InnoDB-Tabellen! Das wird nicht unterstützt. Wenn Sie es dennoch
+tun, startet MySQL nicht mehr, bis Sie die alten Systemtabellen aus einer
+Datensicherung wiederhergestellt haben oder sie mit dem
+mysql_install_db-Skript neu erzeugen.
+
+@item
+@code{SHOW TABLE STATUS} gibt keine genauen Statistiken über
+InnoDB-Tabellen, ausser über die physikalische Größe, die durch die
+Tabelle reserviert wird. Der Zeilenzähler ist nur eine grobe Schätzung, die
+bei der SQL-Optimierung benutzt wird.
+
+@item
+Wenn Sie versuchen, einen eindeutigen Index auf ein Präfix einer Spalte zu
+erzeugen, erhalten Sie einen Fehler:
+
+@example
+CREATE TABLE T (A CHAR(20), B INT, UNIQUE (A(5))) TYPE = InnoDB;
+@end example
+
+Wenn Sie einen nicht eindeutigen Index auf ein Spaltenpräfix erzeugen,
+erzeugt InnoDB einen Index über die gesamte Spalte.
+@item
+@code{INSERT DELAYED} wird für InnoDB-Tabellen nicht unterstützt.
+@item
+Die MySQL-@code{LOCK TABLES}-Operation weiß nichts von InnoDB-Sperren auf
+Zeilenebene, die in bereits fertigen SQL-Statements gesetzt sind. Das
+bedeutet, dass Sie eine Tabellensperre auf eine Tabelle selbst dann
+erhalten können, wenn es noch Transaktionen anderer Benutzer gibt, die
+Sperren auf Zeilenebene auf dieselbe Tabelle haben. Daher kann es sein,
+dass Ihre Operationen auf die Tabelle warten müssen, wenn sie mit diesen
+Sperren anderer Benutzer kollidieren. Auch eine Blockierung ist möglich.
+Dennoch gefährdet das nicht die Transaktionsintegrität, weil sich die
+Sperren auf Zeilenebene, die InnoDB setzt, um die Integrität kümmern.
+Zusätzlich hindert eine Tabellensperren andere Transaktionen daran, weitere
+Sperren auf Zeilenebene (in einem konfliktbehafteten Sperrmodus) auf die
+Tabelle zu erlangen.
+@item
+Sie können keinen Schlüssel auf eine @code{BLOB}- oder @code{TEXT}-Spalte
+setzen.
+@item
+Eine Tabelle kann nicht mehr als 1.000 Spalten enthalten.
+@item
+@code{DELETE FROM TABLE} erzeugt die Tabelle nicht neu, sondern löscht
+statt dessen alle Zeilen, eine nach der anderen, was nicht sehr schnell
+ist. In zukünftigen MySQL-Versionen können Sie @code{TRUNCATE} benutzen,
+was schnell ist.
+@item
+Die vorgabemäßige Datenbank-Seitengröße in InnoDB beträgt 16 KB. Indem
+Sie den Code neu kompilieren, können Sie sie auf Werte zwischen 8 KB und 64
+KB setzen. Die maximale Zeilenlänge beträgt etwas weniger als die Hälfte
+der Datenbank-Seite in den InnoDB-Versionen kleiner oder gleich 3.23.40. Ab
+Quelldistribution 3.23.41 dürfen BLOB- und TEXT-Spalten bis zu 4 GB Groß
+sein, die gesamte Zeilenlänge kann auch < 4 GB betragen. InnoDB speichert
+Felder, deren Größe kleiner oder gleich 128 Bytes beträgt, nicht auf
+separaten Seiten. Nachdem InnoDB die Zeile geändert hat, indem lange Felder
+auf separaten Seiten gespeichert werden, muss die restliche Zeilenlänge
+weniger als die Hälfte einer Datenbank-Seite betragen. Die maximale
+Schlüssellänge beträgt 7.000 Bytes.
+@item
+Auf einigen Betriebssystemen müssen Daten-Dateien kleiner als 2 GB sein.
+Die Gesamtgröße der Log-Dateien muss auf 32-Bit-Computern kleiner als 4 GB
+sein.
+@item
+Die maximale Größe des Tabellenplatzes (Tablespace) beträgt 4 Milliarden
+Datenbank-Seiten. Das ist auch die maximale Größe für eine Tabelle. Die
+minimale Größe des Tabellenplatzes (Tablespace) beträgt 10 MB.
+@end itemize
+
+
+@node InnoDB contact information, , InnoDB restrictions, InnoDB
+@c German node InnoDB-Kontaktinformationen
+@subsection InnoDB-Kontaktinformationen
+
+Kontaktinformationen von Innobase Oy, Hersteller der InnoDB-Engine:
+Website: @uref{http://www.innodb.com/}.
+E-Mail: @email{Heikki.Tuuri@@innodb.com}
+
+@example
+Telefon: 358-9-6969 3250 (Büro) 358-40-5617367 (mobil)
+Innobase Oy Inc.
+World Trade Center Helsinki
+Aleksanterinkatu 17
+P.O.Box 800
+00101 Helsinki
+Finnland
+@end example
+
+
+@node BDB, , InnoDB, Table types
+@c German node BDB
+@section BDB- oder Berkeley_db-Tabellen
+
+@cindex Tabellen, @code{BDB}
+@cindex Tabellen, @code{Berkeley DB}
+
+
+@menu
+* BDB overview::
+* BDB install::
+* BDB start::
+* BDB characteristics::
+* BDB TODO::
+* BDB portability::
+* BDB errors::
+@end menu
+
+@node BDB overview, BDB install, BDB, BDB
+@c German node BDB-Überblick
+@subsection Überblick über BDB-Tabellen
+
+Unterstützung für BDB-Tabellen ist in der MySQL-Quelldistribution seit
+Version 3.23.34 enthalten und in der MySQL-Max-Binärdistribution aktiviert.
+
+BerkeleyDB, erhältlich unter @uref{http://www.sleepycat.com/}, stattet
+MySQL mit einem transaktionalen Tabellen-Handler aus. Wenn Sie
+BerkeleyDB-Tabellen benutzen, haben Ihre Tabellen eine höhere Chance,
+Abstürze zu überleben. Zusätzlich stehen @code{COMMIT} und @code{ROLLBACK}
+für Transaktionen zur Verfügung. Die MySQL-Quelldistribution enthält eine
+BDB-Distribution, die eine Reihe kleiner Patches hat, damit sie glatter mit
+MySQL zusammen arbeitet. Sie können keine nicht gepatchte
+@code{BDB}-Version für MySQL verwenden.
+
+Wir bei MySQL AB arbeiten in enger Kooperation mit Sleepycat, um die hohe
+Qualität der MySQL-/BDB-Schnittstelle zu halten.
+
+Was den Support für BDB-Tabellen angeht, sehen wir uns in der Pflicht,
+unseren Benutzern zu helfen, Probleme zu lokalisieren und Ihnen zu helfen,
+einen reproduzierbaren Testfall für jegliche Probleme mit BDB-Tabellen zu
+erstellen. Solche ein Fall wird an Sleepycat weiter geleitet, die sich dann
+an uns wenden, um uns zu helfen, das Problem zu finden und zu beheben. Weil
+das also in zwei Schritten abläuft, kann es bei jeglichen Problemen mit
+BDB-Tabellen etwas länger dauern, diese zu lösen, als das bei anderen
+Tabellen-Handlern der Fall ist. Weil jedoch der BerkeleyDB-Code selbst auch
+von vielen sonstigen Applikationen benutzt wird, sind hierbei keine großen
+Probleme zu erwarten. @xref{Support}.
+
+
+@node BDB install, BDB start, BDB overview, BDB
+@c German node BDB installieren
+@subsection BDB installieren
+
+Wenn Sie eine Binärdistribution von MySQL herunter geladen haben, die
+Unterstützung für BerkeleyDB enthält, folgen Sie einfach den Anweisungen
+zur Installation einer Binärversion von MySQL. @xref{MySQL binaries}. @xref{mysqld-max, , @code{mysqld-max}}.
+
+Um MySQL mit BerkeleyDB-Unterstützung zu kompilieren, laden Sie
+MySQL-Version 3.23.34 oder neuer herunter und konfigurieren Sie
+@code{MySQL} mit der @code{--with-berkeley-db}-Option.
+@c German FIX unwrapped @xref
+@xref{Installing source}.
+
+@example
+cd /pfad/zur/quelle/von/mysql-3.23.34
+./configure --with-berkeley-db
+@end example
+
+Bitte sehen Sie wegen aktuellerer Informationen im Handbuch nach, das mit
+der @code{BDB}-Distribution mitgeliefert wird.
+
+Obwohl BerkeleyDB selbst sehr gut getestet und zuverlässig ist, wird die
+MySQL-Schnittstelle noch als Beta-Qualität erachtet. Wir verbessern diese
+aktiv und optimieren sie, um sie sehr bald stabil zu bekommen.
+
+
+@node BDB start, BDB characteristics, BDB install, BDB
+@c German node BDB starten
+@subsection BDB-Startoptionen
+
+Wenn Sie mit @code{AUTOCOMMIT=0} fahren, werden Ihre Änderungen in
+@code{BDB}-Tabellen erst aktualisiert, wenn Sie @code{COMMIT} ausführen.
+Statt dessen können Sie @code{ROLLBACK} ausführen, um Ihre Änderungen zu
+verwerfen. @xref{COMMIT}.
+
+Wenn Sie mit @code{AUTOCOMMIT=1} fahren (der Vorgabe), werden Ihre
+Änderungen sofort abgeschickt. Sie können eine ausgedehnte Transaktion mit
+dem SQL-Befehl @code{BEGIN WORK} starten. Danach werden Ihre Änderungen
+solange nicht abgeschickt, bis Sie @code{COMMIT} ausführen (oder sich für
+@code{ROLLBACK} entscheiden, um Ihre Änderungen zu verwerfen).
+
+Folgende Optionen für @code{mysqld} können benutzt werden, um das Verhalten
+von BDB-Tabellen zu ändern:
+
+@multitable @columnfractions .30 .70
+@item @strong{Option} @tab @strong{Beschreibung}
+@item @code{--bdb-home=directory}
+ @tab Base Verzeichnis für BDB-Tabellen. Das sollte dasselbe Verzeichnis sein, das Sie für --datadir benutzen.
+@item @code{--bdb-lock-detect=#}
+ @tab Berkeley-Sperr-Erkennung. # steht für DEFAULT, OLDEST, RANDOM oder YOUNGEST.
+@item @code{--bdb-logdir=Verzeichnis}
+ @tab BerkeleyDB-Log-Datei-Verzeichnis.
+@item @code{--bdb-no-sync}
+ @tab Flush-Logs nicht synchronisieren.
+@item @code{--bdb-no-recover}
+ @tab BerkeleyDB nicht im Wiederherstellungsmodus starten.
+@item @code{--bdb-shared-data}
+ @tab BerkeleyDB im Multi-Prozess-Modus starten (@code{DB_PRIVATE} bei der Initialisierung von BerkeleyDB nicht verwenden).
+@item @code{--bdb-tmpdir=verzeichnis}
+ @tab Name der temporären Datei von BerkeleyDB.
+@item @code{--skip-bdb}
+ @tab BerkeleyDB nicht benutzen.
+@item @code{-O bdb_max_lock=1000}
+ @tab Setzt die höchste Anzahl möglicher Sperren. @xref{SHOW VARIABLES}.
+@end multitable
+
+Wenn Sie @code{--skip-bdb} benutzen, initialisiert MySQL nicht die
+BerkeleyDB-Bibliothek und spart deshalb viel Speicher. Natürlich können Sie
+@code{BDB}-Tabellen nicht benutzen, wenn Sie diese Option verwenden.
+
+Normalerweise sollten Sie @code{mysqld} ohne @code{--bdb-no-recover}
+starten, wenn Sie vorhaben, BDB-Tabellen zu verwenden. Das kann allerdings
+zu Problemen führen, wenn Sie @code{mysqld} starten und die BDB-Log-Dateien
+beschädigt sind. @xref{Starting server}.
+
+Mit @code{bdb_max_lock} können Sie die maximale Anzahl von Sperren
+festlegen (vorgabemäßig 10.000), die auf einer BDB-Tabelle aktiv sein
+können. Sie sollten diesen Wert herauf setzen, wenn Sie Fehler vom Typ
+@code{bdb: Lock table is out of available locks} oder @code{Got error 12
+from ...} erhalten, wenn Sie lange Transaktionen ausführen oder wenn
+@code{mysqld} viele Zeilen untersuchen muss, um die Anfrage zu berechnen.
+
+Sie könnten auch @code{binlog_cache_size} und @code{max_binlog_cache_size}
+ändern, wenn Sie große, vielzeilige Transaktionen benutzen. @xref{COMMIT}.
+
+
+@node BDB characteristics, BDB TODO, BDB start, BDB
+@c German node BDB-Charakteristiken
+@subsection Kennzeichen von @code{BDB}-Tabellen
+
+@itemize @bullet
+@item
+Um Transaktionen zurückrollen zu können, unterhält BDB Log-Dateien. Um
+maximale Performance zu erzielen, sollten Sie diese auf andere Festplatten
+platzieren als Ihre Datenbanken, indem Sie die @code{--bdb_log_dir}-Option
+benutzen.
+@item
+MySQL macht jedes Mal, wenn eine neue BDB-Log-Datei gestartet wird, einen
+Checkpoint und entfernt alle Log-Dateien, die nicht für aktuelle
+Transaktionen benötigt werden. Sie können auch jederzeit @code{FLUSH LOGS}
+laufen lassen, um einen Checkpoint für die BerkeleyDB-Tabellen anzulegen.
+
+Für die Wiederherstellung nach Abstürzen sollten Sie Datensicherungen der
+Tabellen plus das Binär-Log von MySQL benutzen. @xref{Backup}.
+
+@strong{Achtung}: Wenn Sie alte Log-Dateien löschen, die in Benutzung sind,
+ist BDB nicht in der Lage, Wiederherstellungen durchzuführen, und Sie
+könnten Daten verlieren, wenn etwas schief geht.
+@item
+MySQL erfordert einen @code{PRIMARY KEY} in jeder BDB-Tabelle, um auf
+vorher gelesene Zeilen verweisen zu können. Wenn Sie keine Primärschlüssel
+anlegen, erzeugt MySQL einen versteckten @code{PRIMARY KEY}. Der versteckte
+Schlüssel hat eine Länge von 5 Bytes und wird bei jedem Einfügeversuch um 1
+hochgezählt.
+@item
+Wenn alle Spalten, auf die Sie in einer @code{BDB}-Tabelle zugreifen, Teil
+desselben Indexes oder Teil des Primärschlüssels sind, kann MySQL die
+Anfrage ausführen, ohne auf die tatsächliche Zeile zugreifen zu müssen. Bei
+einer @code{MyISAM}-Tabelle gilt das nur, wenn die Spalten Teil desselben
+Indexes sind.
+@item
+Der @code{PRIMARY KEY} ist schneller als jeder andere Schlüssel, weil
+@code{PRIMARY KEY} zusammen mit den Zeilendaten gespeichert wird. Weil die
+anderen Schlüssel als Schlüsseldaten plus @code{PRIMARY KEY} gespeichert
+werden, ist es wichtig, den @code{PRIMARY KEY} so kurz wie möglich zu
+halten, um Plattenplatz zu sparen und bessere Geschwindigkeit zu erzielen.
+@item
+@code{LOCK TABLES} funktioniert bei @code{BDB}-Tabellen wie bei anderen
+Tabellen. Wenn Sie @code{LOCK TABLE} nicht benutzen, führt MySQL einer
+interne mehrfache Schreibsperre auf die Tabelle aus, um sicherzustellen,
+dass die Tabelle korrekt gesperrt ist, wenn ein anderer Thread eine
+Tabellensperre ausführt.
+@item
+Internes Sperren in @code{BDB}-Tabellen wird auf Seitenebene durchgeführt.
+@item
+@code{SELECT COUNT(*) FROM tabelle} ist langsam, weil @code{BDB}-Tabellen
+keinen Zähler für die Anzahl der Zeilen in der Tabelle unterhalten.
+@item
+Scannen ist langsamer als bei @code{MyISAM}-Tabellen, weil Daten in
+BDB-Tabellen in B-Bäumen und nicht in separaten Daten-Dateien gespeichert
+werden.
+@item
+Die Applikation muss stets darauf vorbereitet sein, Fälle zu handhaben, bei
+denen jegliche Änderung einer @code{BDB}-Tabelle zu einem automatischen
+Rollback führen kann und jegliches Lesen fehlschlagen kann, weil ein
+Blockierungsfehler auftritt.
+@item
+Schlüssel werden nicht auf vorherige Schlüssel komprimiert, wie das bei
+ISAM- und MyISAM-Tabellen der Fall ist. Mit anderen Worten benötigt die
+Schlüsselinformation etwas mehr Platz bei @code{BDB}-Tabellen im Vergleich
+zu MyISAM-Tabellen, die nicht @code{PACK_KEYS=0} benutzen.
+@item
+Oft gibt es Löcher in der BDB-Tabelle, damit Sie neue Zeilen in der Mitte
+des Schlüsselbaums einfügen können. Das macht BDB-Tabellen etwas größer
+als MyISAM-Tabellen.
+@item
+Der Optimierer muss näherungsweise die Anzahl von Zeilen in der Tabelle
+kennen. MySQL löst dieses Problem, indem Einfügeoperationen gezählt werden,
+und unterhält diese in einem separaten Segment in jeder BDB-Tabelle. Wenn
+Sie nicht viele @code{DELETE} oder @code{ROLLBACK} ausführen, sollte diese
+Zahl ausreichend genau für den MySQL-Optimierer sein. Weil MySQL die Zahl
+nur beim Schließen speichert, kann sie falsch sein, wenn MySQL unerwartet
+stirbt. Das sollte kein schwerer Fehler sein, selbst wenn die Zahl nicht
+100% korrekt ist. Man kann die Anzahl von Zeilen aktualisieren, indem man
+@code{ANALYZE TABLE} oder @code{OPTIMIZE TABLE} ausführt.
+@c German FIX Unsplit @xref
+@xref{ANALYZE TABLE}. @xref{OPTIMIZE TABLE}.
+@item
+Wenn die Platte bei einer @code{BDB}-Tabelle voll wird, erhalten Sie einen
+Fehler (wahrscheinlich Fehler 28) und die Transaktion sollte zurückgerollt
+werden. Das steht im Gegensatz zu @code{MyISAM}- and @code{ISAM}-Tabellen,
+bei denen @code{mysqld} wartet, bis genug Plattenplatz frei ist, bevor
+weiter gemacht wird.
+@end itemize
+
+
+@node BDB TODO, BDB portability, BDB characteristics, BDB
+@c German node BDB-TODO-Liste
+@subsection Was in naher Zukunft bei BDB in Ordnung gebracht werden muss
+
+@itemize @bullet
+@item
+Viele BDB-Tabellen zur gleichen Zeit öffnen ist sehr langsam. Wenn Sie
+BDB-Tabellen benutzen wollen, sollten Sie einen sehr großen Tabellen-Cache
+haben (evtl. größer als 256) und beim @code{mysql}-Client
+@code{--no-auto-rehash} benutzen. Das soll partiell in Version 4.0 behoben
+werden.
+@item
+@code{SHOW TABLE STATUS} gibt momentan noch nicht viele Informationen über
+BDB-Tabellen aus.
+@item
+Performance optimieren.
+@item
+Es sollten überhaupt keine Seitensperren mehr benutzt werden, wenn Tabellen
+gescannt werden.
+@end itemize
+
+
+@node BDB portability, BDB errors, BDB TODO, BDB
+@c German node BDB-Portabilität
+@subsection Betriebssysteme, die von @strong{BDB} unterstützt werden
+
+Wenn Sie MySQL mit Unterstützung für BDB-Tabellen gebaut haben und
+folgenden Fehler in der Log-Datei sehen, wenn Sie @code{mysqld} starten:
+
+@example
+bdb: architecture lacks fast mutexes: applications cannot be threaded
+Can't init databases
+@end example
+
+Bedeutet das, dass @code{BDB}-Tabellen für Ihre Architektur nicht
+unterstützt werden. In diesem Fall müssen Sie MySQL erneut bauen, ohne
+Unterstützung für BDB-Tabellen.
+
+HINWEIS: Folgende Liste ist nicht komplett. Sie wird aktualisiert, sobald
+wir mehr Informationen darüber haben.
+
+Momentan wissen wir, dass BDB-Tabellen auf folgenden Betriebssystemen
+laufen:
+
+@itemize @bullet
+@item
+Linux 2.x intel
+@item
+Solaris sparc
+@item
+SCO OpenServer
+@item
+SCO UnixWare 7.0.1
+@end itemize
+
+Auf folgenden Betriebssystemen läuft BDB nicht:
+
+@itemize @bullet
+@item
+Linux 2.x Alpha
+@item
+Mac OS X
+@end itemize
+
+
+@node BDB errors, , BDB portability, BDB
+@c German node BDB-Fehler
+@subsection Fehler, die bei der Benutzung von BDB-Tabellen auftreten können
+
+@itemize @bullet
+@item
+Wenn Sie folgenden Fehler in der @code{hostname.err}-Log-Datei beim Start
+von @code{mysqld} erhalten:
+
+@example
+bdb: Ignoring log file: .../log.XXXXXXXXXX: unsupported log version #
+@end example
+Bedeutet das, dass die neue @code{BDB}-Version das alte Log-Dateiformat
+nicht unterstützt. In diesem Fall müssen Sie alle @code{BDB}-Log-Dateien
+aus Ihrem Datenbankverzeichnis löschen (die Dateien haben das Format
+@code{log.XXXXXXXXXX}) und @code{mysqld} neu starten. Wir empfehlen
+ausserdem, dass Sie @code{mysqldump --opt} auf Ihre alten
+@code{BDB}-Tabellen ausführen, die alten Tabellen löschen und aus dem Dump
+wiederherstellen.
+@item
+Wenn Sie im @code{auto_commit}-Modus fahren und eine Tabelle löschen, die
+durch einen anderen Thread benutzt wird, erhalten Sie womöglich folgende
+Fehlermeldungen in der MySQL-Fehlerdatei:
+
+@example
+001119 23:43:56 bdb: Missing log fileid entry
+001119 23:43:56 bdb: txn_abort: Log undo failed for LSN: 1 3644744: Invalid
+@end example
+
+Das ist kein schwerer Fehler, aber wir empfehlen, alle Tabellen zu löschen,
+wenn Sie nicht im @code{auto_commit}-Modus sind, bis dieses Problem behoben
+ist (die Behebung ist nicht trivial).
+@end itemize
+
+
+@node Clients, Extending MySQL, Table types, Top
+@c German node MySQL-APIs
+@chapter MySQL-APIs
+
+@cindex Client-Werkzeuge
+@cindex APIs
+@cindex @code{mysqlclient}-Bibliothek
+@cindex Puffergrößen, Client
+@cindex Bibliothek, @code{mysqlclient}
+
+
+Dieses Kapitel beschreibt die APIs, die für MySQL bereitstehen, wo man sie
+bekommt und wie man sie benutzt. Die C-API ist am ausführlichsten beschrieben,
+da sie vom MySQL-Team stammt und als Basis für die meisten anderen APIs
+dient.
+
+
+@menu
+* PHP::
+* Perl::
+* ODBC::
+* C::
+* Cplusplus::
+* Java::
+* Python::
+* Tcl::
+* Eiffel::
+@end menu
+
+@node PHP, Perl, Clients, Clients
+@c German node PHP
+@section MySQL-PHP-API
+
+@cindex PHP-API
+
+PHP ist eine serverseitige Skriptsprache, die in HTML eingebettet werden
+kann und mit der man dynamische Webseiten erstellen kann. PHP unterstützt
+eine Vielzahl von Datenbanken. Darunter befindet sich auch MySQL. PHP kann
+als alleinstehendes Programm oder als Teil des Apache Webservers eingesetzt
+werden.
+
+
+Die Distribution und die Dokumentation gibt es unter
+@uref{http://www.php.net/, PHP-Website}.
+
+
+@menu
+* PHP problems::
+@end menu
+
+@node PHP problems, , PHP, PHP
+@c German node PHP-Probleme
+@subsection Allgemeine Probleme mit MySQL und PHP
+
+@itemize @bullet
+@item Error: "Maximum Execution Time Exceeded"
+Dies ist eine PHP-Beschränkung. Ändern sie den Wert für die maximale
+Ausführungszeit in der @file{php3.ini}-Datei. Es ist ausserdem keine
+schlechte Idee, die Beschränkung für die maximale Benutzung von RAM von 8
+MB auf 16 MB per Skript zu verdoppeln.
+
+
+@item Error: "Fatal error: Call to unsupported oder undefined function mysql_connect() in .."
+Das bedeutet, dass Ihre PHP-Version nicht mit MySQL-Unterstützung
+ausgestattet ist. Sie können entweder ein dynamisches MySQL-Modul für PHP
+kompilieren oder PHP mit seiner eingebautet MySQL-Unterstützung neu
+kompilieren. Im PHP-Manual ist dies ausführlich beschrieben.
+
+@item Error: "undefined reference to `uncompress'"
+Die Client-Bibliothek wurde mit der Unterstützung für ein komprimiertes
+Client-/Server-Protokoll kompiliert. Um den Fehler zu beheben, müssen Sie
+@code{-lz} als letztes angeben, wenn Sie gegen @code{-lmysqlclient}
+linken.
+@end itemize
+
+
+@node Perl, ODBC, PHP, Clients
+@c German node Perl
+@section MySQL-Perl-API
+
+@cindex APIs, Perl
+@cindex Perl-API
+
+Dieser Abschnitt dokumentiert die Perl-@code{DBI}-Schnittstelle. Die
+frühere Schnittstelle hieß @code{mysqlperl}. @code{DBI}/@code{DBD} ist
+jetzt die empfohlene Perl-Schnittstelle. @code{mysqlperl} ist überflüßig
+und deshalb hier nicht näher beschrieben.
+
+
+
+@menu
+* DBI with DBD::
+* Perl DBI Class::
+* DBI-info::
+@end menu
+
+@node DBI with DBD, Perl DBI Class, Perl, Perl
+@c German node DBI mit DBD
+@subsection @code{DBI} mit @code{DBD::mysql}
+
+@cindex @code{DBI}-Schnittstelle
+
+@code{DBI} ist eine allgemeine Schnittstelle für viele Datenbanken. Das
+bedeutet, Sie können ein Skript schreiben, dass viele verschiedene
+Datenbanken unterstützt, ohne es zu ändern. Sie brauchen für jeden
+Datenbanktyp einen Datenbank-Treiber (DBD). Für MySQL heißt dieser Treiber
+@code{DBD::mysql}. Für weitere Informationen über Perl5 DBI besuchen Sie
+bitte die @code{DBI}-Website und lesen Sie die Dokumentation:
+
+@example
+@uref{http://www.symbolstone.org/technology/perl/DBI/index.html}
+@end example
+Für weitere Informationen über objektorientierte Programmierung (OOP) in
+Perl5 besuchen Sie die OOP-Seite:
+@example
+@uref{http://language.perl.com/info/documentation.html}
+@end example
+
+Beachten Sie, dass Sie, wenn Sie Transaktionen mit Perl einsetzen wollen,
+@code{Msql-Mysql-modules} der Version 1.2216 oder neuer benötigen.
+
+Installationsanweisungen für MySQL-Perl-Unterstützung finden Sie unter
+@ref{Perl}.
+
+
+@node Perl DBI Class, DBI-info, DBI with DBD, Perl
+@c German node Perl-DBI-Klasse
+@subsection Die @code{DBI}-Schnittstelle
+
+@cindex @code{DBI}-Perl-Modul
+
+@noindent
+@strong{Portable DBI-Methoden}
+
+@multitable @columnfractions .3 .7
+@item @code{connect} @tab Errichtet eine Verbindung zum Datenbankserver.
+@item @code{disconnect} @tab Trennt eine Verbindung zum Datenbankserver.
+@item @code{prepare} @tab Bereitet ein SQL-Statement zur Abfrage vor.
+@item @code{execute} @tab Führt eine vorbereitetes Statement aus.
+@item @code{do} @tab Bereitet ein SQL-Statement vor und führt es aus.
+@item @code{quote} @tab Quotet eine Zeichenkette oder einen @code{BLOB}-Wert zum Einfügen.
+@item @code{fetchrow_array} @tab Holt die nächste Zeile als einen Array aus Feldern.
+@item @code{fetchrow_arrayref} @tab Holt die nächste Zeile als eine Referenz eines Arrays aus Feldern.
+@item @code{fetchrow_hashref} @tab Holt die nächste Zeile als eine Referenz einer Hash-Tabelle.
+@item @code{fetchall_arrayref} @tab Holt alle Zeilen als einen Array von Arrays.
+@item @code{finish} @tab Beendet ein Statement und läßt das System Resourcen freigeben.
+@item @code{rows} @tab Gibt die Anzahl der betroffenen Zeilen zurück.
+@item @code{data_sources} @tab Gibt einen Array mit den verfügbaren Daten auf localhost zurück.
+@item @code{ChopBlanks} @tab Kontroliert, ob die @code{fetchrow_*}-Methoden Leerzeichen entfernen.
+@item @code{NUM_OF_PARAMS} @tab Die Anzahl der Platzhalter in einem vorbereiteten Statement.
+@item @code{NULLABLE} @tab Welche Spalten @code{NULL} sein können.
+@item @code{trace} @tab Tracen zum Debuggen ausführen.
+@end multitable
+
+@noindent
+@strong{MySQL-spezifische Methoden}
+
+@multitable @columnfractions .3 .7
+@item @code{insertid} @tab Der letzte @code{AUTO_INCREMENT}-Wert.
+@item @code{is_blob} @tab Welche Spalten @code{BLOB}-Werte sind.
+@item @code{is_key} @tab Welche Spalten Schlüssel sind.
+@item @code{is_num} @tab Welche Spalten numerisch sind.
+@item @code{is_pri_key} @tab Welche Spalten Primärschlüssel sind.
+@item @code{is_not_null} @tab Welche Spalten NICHT @code{NULL} sein können. Siehe auch @code{NULLABLE}.
+@item @code{length} @tab Maximal mögliche Spaltengröße.
+@item @code{max_length} @tab Maximale Spaltengröße, die im aktuellen Ergebnis enthalten ist.
+@item @code{NAME} @tab Spaltennamen.
+@item @code{NUM_OF_FIELDS} @tab Anzahl der zurückgegebenen Felder.
+@item @code{table} @tab Tabellennamen im zurückgegebenen Ergebnis.
+@item @code{type} @tab Alle Spaltentypen.
+@end multitable
+
+Die Perl-Methoden werden im Folgenden detaillierter erläutert. Die
+Variablen für die zurückgegebenen Werte haben folgende Bedeutung:
+
+@table @code
+@item $dbh
+Datenbank-Handle
+
+@item $sth
+Statement-Handle
+
+@item $rc
+Rückgabe-Code (oft ein Status)
+
+@item $rv
+Rückgabewert (oft ein Status)
+@end table
+
+@noindent
+@strong{Portable DBI-Methoden}
+
+@table @code
+
+@findex DBI->connect()
+@findex connect()-DBI-Methode
+@item connect($datenquelle, $benutzername, $passwort)
+Benutzen Sie die @code{connect}-Methode, um eine Verbindung zur Datenbank
+der Datenquelle herzustellen. Der @code{$datenquelle}-Wert sollte mit
+@code{DBI:Treiber_name:} beginnen. Beispielanwendungen von @code{connect}
+mit dem @code{DBD::mysql} Treiber:
+@example
+$dbh = DBI->connect("DBI:mysql:$datenbank", $benutzer, $passwort);
+$dbh = DBI->connect("DBI:mysql:$datenbank:$hostname",
+ $benutzer, $passwort);
+$dbh = DBI->connect("DBI:mysql:$datenbank:$hostname:$port",
+ $benutzer, $passwort);
+@end example
+Wenn der Benutzername und / oder das Passwort nicht angegeben werden,
+verwendet @code{DBI} die Werte der @code{DBI_USER}- und @code{DBI_PASS}-
+Umgebungsvariablen. Wen Sie keinen Hostnamen angeben, wird @code{'localhost'}
+verwendet. Wenn Sie keine Portnummer angeben, wird der MySQL-Port
+(@value{default_port}) verwendet.
+
+Seit @code{Msql-Mysql-modules}-Version 1.2009 erlaubt der
+@code{$datenquelle}-Wert bestimmte Modifikatoren:
+
+@table @code
+@item mysql_read_default_file=datei
+Liest @file{datei} als eine Optionsdatei. Für weitere Informationen zu
+Optionsdateien beachten Sie bitte @ref{Option files}.
+
+@item mysql_read_default_group=group_name
+Beim Lesen einer Optionsdatei ist die Standardgruppe normalerweise die
+@code{[client]}-Gruppe. Wenn Sie die @code{mysql_read_default_group}-
+Option angeben, wird die Standardgruppe @code{[gruppenname]}.
+
+@item mysql_compression=1
+Aktiviert die Kompression während der Kommunikation zwischen Client und
+Server (ab Version 3.22.3).
+
+@item mysql_socket=/pfad/zur/socket
+Gibt den Pfad des Unix-Sockets an, der zum Verbinden mit dem
+Server verwendet wird (MySQL-Version 3.21.15 oder neuer).
+@end table
+
+Sie können mehrere Modifikatoren angeben, dabei muss jedem ein Semikolon
+vorangestellt sein.
+
+Wenn Sie zum Beispiel vermeiden wollen, dass sie Benutzername und Passwort
+im @code{DBI}-Skript angeben müssen, können Sie sie aus der
+@file{~/.my.cnf}-Optionsdatei nehmen. Ihr @code{connect}-Aufruf sieht
+folgendermaßen aus:
+
+@example
+$dbh = DBI->connect("DBI:mysql:$datenbank"
+ . ";mysql_read_default_file=$ENV@{HOME@}/.my.cnf",
+ $benutzer, $passwort);
+@end example
+
+Dieser Aufruf liest die Optionen für die @code{[client]}-Gruppe aus der
+Optionsdatei. Wenn Sie dasselbe für die @code{[perl]}-Gruppe tun wollen,
+könnte Ihr Code so aussehen:
+
+@example
+$dbh = DBI->connect("DBI:mysql:$Datenbank"
+ . ";mysql_read_default_file=$ENV@{HOME@}/.my.cnf"
+ . ";mysql_read_default_group=perl",
+ $benutzer, $passwort);
+@end example
+
+@findex DBI->disconnect
+@findex disconnect-DBI-Methode
+@item disconnect
+Die @code{disconnect}-Methode beendet die Verbindung mit der Datenbank.
+Dies wird typischerweise kurz vor dem Ende eines Scripts ausgeführt.
+Beispiel:
+@example
+$rc = $dbh->disconnect;
+@end example
+
+@findex DBI->prepare()
+@findex prepare()-DBI-Methode
+@item prepare($statement)
+Bereitet ein SQL-Statement zum Ausführen durch den Datenbankserver vor und
+gibt ein "Statement-Handle" @code{($sth)} zurück, mit der Sie die
+@code{execute}-Methode aufrufen.
+Normalerweise werden Sie @code{SELECT}-Statements (und
+@code{SELECT}-ähnliche Statements so wie @code{SHOW}, @code{DESCRIBE} und
+@code{EXPLAIN}) mit der Bedeutung von @code{prepare} und @code{execute}
+verwenden.
+Beispiel:
+@example
+$sth = $dbh->prepare($statement)
+ or die "$statement: $dbh->errstr kann nicht vorbereitet werden\n";
+@end example
+
+@findex DBI->execute
+@findex execute-DBI-Methode
+@item execute
+Die @code{execute}-Methode führt ein vorbereitetes Statement aus. Bei
+Nicht-@code{SELECT}-Statements gibt @code{execute} die Anzahl der
+betroffenen Zeilen zurück. Wenn Zeilen betroffen sind, gibt @code{execute}
+@code{"0E0"} zurück, was in Perl als 0 und true erkannt wird. Wenn ein
+Fehler auftritt, gibt @code{execute} @code{undef} zurück. Bei
+@code{SELECT}-Statements beginnt @code{execute} die SQL-Anfrage in der
+Datenbank; Sie müssen eine der @code{fetch_*}-Methoden nutzen, die weiter
+unten beschrieben sind, um Daten erhalten. Beispiel:
+@example
+$rv = $sth->execute
+ or die "Die Query: $sth->errstr kann nicht ausgeführt werden.";
+@end example
+
+@findex DBI->do()
+@findex do()-DBI-Methode
+@item do($statement)
+Die @code{do}-Methode bereitet ein Statement vor, führt es aus und gibt die
+Anzahl der betroffenen Zeilen zurück. Wenn Zeilen betroffen sind, gibt
+@code{execute} @code{"0E0"} zurück, was in Perl als 0 und true erkannt
+wird. Diese Methode wird normalerweise verwendet, um
+Nicht-@code{SELECT}-Statements zu bearbeiten, die (z. B. wegen
+Treiber-Beschränkungen) nicht vorbereitet werden können, oder die nicht
+mehr als einmal vorbereitet werden müssen (INSERTS, DELETE usw.). Beispiel:
+@example
+$rv = $dbh->do($statement)
+ or die "$statement: $dbh- >errstr kann nicht vorbereitet werden\n";
+@end example
+
+Im Allgemeinen ist die @code{do}-Methode VIEL schneller (und vorzuziehen)
+als die @code{prepare}/@code{execute}-Methoden, die ohne Parameter
+aufgerufen werden.
+
+@findex DBI->quote()
+@findex quote()-DBI-Methode
+@cindex Zeichenketten quoten
+@cindex Zeichenketten, quoten
+@item quote($string)
+Die @code{quote}-Methode wird verwendet, um Sonderzeichen zu "escapen", die
+in Zeichenketten enthalten sein können, und um notwendige äußere
+Anführungszeichen hinzuzufügen. Beispiel:
+@example
+$sql = $dbh->quote($string)
+@end example
+
+@findex DBI->fetchrow_array
+@findex fetchrow_array-DBI-Methode
+@item fetchrow_array
+Die Methode holt die nächste Datenzeile und gibt sie als ein Array mit den
+Feldwerten zurück. Beispiel:
+@example
+while(@@row = $sth->fetchrow_array) @{
+ print qw($row[0]\t$row[1]\t$row[2]\n);
+@}
+@end example
+
+@findex DBI->fetchrow_arrayref
+@findex fetchrow_arrayref-DBI-Methode
+@item fetchrow_arrayref
+Die Methode holt die nächste Datenzeile und gibt sie als eine Referenz auf
+ein Array mit den Feldwerten zurück. Beispiel:
+@example
+while($row_ref = $sth->fetchrow_arrayref) @{
+ print qw($row_ref->[0]\t$row_ref->[1]\t$row_ref->[2]\n);
+@}
+@end example
+
+@findex DBI->fetchrow_hashref
+@findex fetchrow_hashref-DBI-Methode
+@item fetchrow_hashref
+Diese Methode holt eine Datenzeile und gibt eine Referenz auf einen Hash
+zurück, der Name-/Wert-Paare enthält. Die Methode ist lange nicht so
+performant wie das Verwenden von Referenzen auf ein Array, wie weiter oben
+beschrieben ist. Beispiel:
+@example
+while($hash_ref = $sth->fetchrow_hashref) @{
+ print qw($hash_ref->@{vorname@}\t$hash_ref->@{nachname@}\t\
+ $hash_ref- > title@}\n);
+@}
+@end example
+
+@findex DBI->fetchall_arrayref
+@findex fetchall_arrayref-DBI-Methode
+@item fetchall_arrayref
+Diese Methode gibt alle Zeilen eines Ergebnisses einer SQL-Anfrage zurück.
+Sie gibt eine Referenz auf ein Array mit Referenzen auf Arrays mit den
+Werten der einzelnen Zeilen zurück. Sie können mit zwei verschachtelten
+Schleifen auf die Werte zugreifen. Beispiel:
+@example
+my $table = $sth->fetchall_arrayref
+ or die "$sth->errstr\n";
+my($i, $j);
+for $i ( 0 .. $#@{$table@} ) @{
+ für $j ( 0 .. $#@{$table->[$i]@} ) @{
+ print "$table->[$i][$j]\t";
+ @}
+ print "\n";
+@}
+@end example
+
+@findex DBI->finish
+@findex finish-DBI-Methode
+@item finish
+Bewirkt, dass keine weiteren Daten von dem SQL-Anfrageergebnis geholt
+werden. Sie können diese Methode aufrufen, um Systemressourcen freizugeben.
+Beispiel:
+@example
+s$rc = $sth->finish;
+@end example
+
+@findex DBI->rows
+@findex rows-DBI-Methode
+@item rows
+Gibt die Anzahl der veränderten Zeilen (die aktualisiert oder gelöscht
+wurden) des letzten Befehls zurück. Dies wird normalerweise nach
+Nicht-@code{SELECT}-@code{execute}-Statements verwendet. Beispiel:
+@example
+$rv = $sth->rows;
+@end example
+
+@findex DBI->@{NULLABLE@}
+@findex NULLABLE-DBI-Methode
+@item NULLABLE
+Gibt eine Referenz auf ein Array mit Boole'schen Werten zurück; für jedes
+Element TRUE kann die Spalte @code{NULL}-Werte enthalten. Beispiel:
+@example
+$null_possible = $sth->@{NULLABLE@};
+@end example
+
+@findex DBI->@{NUM_OF_FIELDS@}
+@findex NUM_OF_FIELDS-DBI-Methode
+@item NUM_OF_FIELDS
+Dieses Attribut enthält die Anzahl der Zeilen, die eine @code{SELECT}- oder
+@code{SHOW FIELDS}-SQL-Anfrage zurückgibt. Sie können es verwenden, um zu
+prüfen, ob eine Anfrage ein Ergebnis zurückgegeben hat: 0 weist auf eine
+Nicht-@code{SELECT}-Anfrage hin, wie @code{INSERT}, @code{DELETE} oder
+@code{UPDATE}. Beispiel:
+@example
+$nr_of_fields = $sth->@{NUM_OF_FIELDS@};
+@end example
+
+@findex DBI->datasource()
+@findex datasource()-DBI-Methode
+@item datasource($Treiber_name)
+Diese Methode gibt einen Array zurück, der die Namen der verfügbaren
+Datenbanken auf @code{'localhost'} enthält. Beispiel:
+@example
+@@dbs = DBI->datasource("mysql");
+@end example
+
+@findex DBI->@{ChopBlanks@}
+@findex ChopBlanks-DBI-Methode
+@item ChopBlanks
+Dieses Attribut gibt an, ob die @code{fetchrow_*}-Methoden vor- und
+nachstehende Leerzeichen entfernen. Beispiel:
+@example
+$sth->@{'ChopBlanks'@} =1;
+@end example
+
+@findex DBI->trace
+@findex trace-DBI-Methode
+@item trace($trace_ebene)
+@itemx trace($trace_ebene, $trace_dateiname)
+@code{trace} aktiviert oder deaktiviert "Tracing".
+Wenn @code{DBI} als eine Klassenmethode aufgerufen wird, steuert es das
+"Tracing" mit allen Datenbankverbindungen. Wenn es als Datenbank- oder
+Statement-Handle-Methode aufgerufen wird, steuert es nur die verwendete
+Verbindung (und deren spätere Ableitungen). Wenn Sie @code{$trace_ebene}
+auf 2 setzen, bewirkt es detaillierte Informationen. Der Wert 0 stellt
+"Tracing" ab. Die Ausgabe des "Tracing" wird vorgabemäßig nach "standard
+error" geleitet. Wenn @code{$trace_dateiname} angegeben ist, wird die
+Ausgabe für @emph{alle} "getraceten" Verbindungen an das Ende dieser Datei
+geschrieben. Beispiel:
+@example
+DBI->trace(2); # alles tracen
+DBI->trace(2,"/tmp/dbi.out"); # alles nach /tmp/dbi.out tracen
+$dth->trace(2); # diese Datenbankverbindung tracen
+$sth->trace(2); # dieses Statement-Handle tracen.
+@end example
+
+@tindex @code{DBI_TRACE}-Umgebungsvariable
+@tindex Umgebungsvariable, @code{DBI_TRACE}
+Sie können @code{DBI}-Tracing auch anschalten, indem Sie die
+@code{DBI_TRACE}-Umgebungsvariable setzen. Wenn Sie sie auf einen
+numerischen Wert setzen, ist das dasselbe, wie @code{DBI->(wert)}
+aufzurufen. Wenn Sie sie auf einen Pfadnamen setzen, ist das dasselbe, wie
+@code{DBI->(2,wert)} aufzurufen.
+
+@end table
+
+@noindent
+@strong{MySQL-spezifische Methoden}
+
+Die unten stehenden Methoden sind MySQL-spezifisch und nicht Teil des
+@code{DBI}-Standards. Mehrere von ihnen sind veraltet:
+@code{is_blob}, @code{is_key}, @code{is_num}, @code{is_pri_key},
+@code{is_not_null}, @code{length}, @code{max_length} und @code{table}.
+Wo immer es @code{DBI}-Standard-Alternativen gibt, ist das unten angemerkt:
+
+@table @code
+@findex DBI->@{insertid@}
+@findex insertid-DBI-Methode
+@tindex AUTO_INCREMENT, Benutzung bei DBI
+@item insertid
+Wenn Sie das @code{AUTO_INCREMENT}-Feature von MySQL benutzen, werden neue,
+automatisch heraufgezählte Werte hier gespeichert. Beispiel:
+@example
+$new_id = $sth->@{insertid@};
+@end example
+
+Alternativ können Sie @code{$dbh->@{'mysql_insertid'@}} verwenden.
+
+@findex DBI->@{is_blob@}
+@findex is_blob-DBI-Methode
+@item is_blob
+Gibt eine Referenz auf einen Array mit Boole'schen Werten zurück; für jedes
+Element des Arrays bedeutet der Wert TRUE, dass die entsprechende Spalte
+ein @code{BLOB} ist. Beispiel:
+@example
+$keys = $sth->@{is_blob@};
+@end example
+
+@findex DBI->@{is_key@}
+@findex is_key-DBI-Methode
+@item is_key
+Gibt eine Referenz auf einen Array mit Boole'schen Werten zurück; für jedes
+Element des Arrays bedeutet der Wert TRUE, dass die entsprechende Spalte
+ein Schlüssel ist. Beispiel:
+@example
+$keys = $sth->@{is_key@};
+@end example
+
+@findex DBI->@{is_num@}
+@findex is_num DBI-Methode
+@item is_num
+Gibt eine Referenz auf einen Array mit Boole'schen Werten zurück; für jedes
+Element des Arrays bedeutet der Wert TRUE, dass die entsprechende Spalte
+numerische Werte enthält. Beispiel:
+@example
+$nums = $sth->@{is_num@};
+@end example
+
+@findex DBI->@{is_pri_key@}
+@findex is_pri_key DBI-Methode
+@item is_pri_key
+Gibt eine Referenz auf einen Array mit Boole'schen Werten zurück; für jedes
+Element des Arrays bedeutet der Wert TRUE, dass die entsprechende Spalte
+ein Primärschlüssel ist. Beispiel:
+@example
+$pri_keys = $sth->@{is_pri_key@};
+@end example
+
+@findex DBI->@{is_not_null@}
+@findex is_not_null DBI-Methode
+@item is_not_null
+Gibt eine Referenz auf einen Array mit Boole'schen Werten zurück; für jedes
+Element des Arrays bedeutet der Wert FALSE, dass die entsprechende Spalte
+NULL enthalten kann. Beispiel:
+@example
+$not_nulls = $sth->@{is_not_null@};
+@end example
+
+Das oben beschriebene @code{NULLABLE}-Attribut ist @code{is_not_null} in
+jedem Fall vorzuziehen, da es zum DBI-Standard gehört.
+
+@findex DBI->@{length@}
+@findex length-DBI-Methode
+@findex DBI->@{max_length@}
+@findex max_length-DBI-Methode
+@item length
+@itemx max_length
+Beide Methoden geben je einen Array mit Spaltenlängen zurück. Der
+@code{length}-Array gibt die maximal mögliche Länge jeder Spalte an (wie es
+in der Tabellendefinition festgelegt wurde). Der @code{max_length}-Array
+gibt die Länge des aktuell längsten Wertes in den Spalten an. Beispiel:
+@example
+$lengths = $sth->@{length@};
+$max_lengths = $sth->@{max_length@};
+@end example
+
+@findex DBI->@{NAME@}
+@findex NAME-DBI-Methode
+@item NAME
+Gibt eine Referenz auf ein Array mit den Spaltennamen zurück. Beispiel:
+@example
+$names = $sth->@{NAME@};
+@end example
+
+@findex DBI->@{table@}
+@findex table-DBI-Methode
+@item table
+Gibt eine Referenz auf ein Array mit den Tabellennamen zurück. Beispiel:
+@example
+$tables = $sth->@{table@};
+@end example
+
+@findex DBI->@{type@}
+@findex type-DBI-Methode
+@item type
+Gibt eine Referenz auf ein Array mit den Spaltentypen zurück. Beispiel:
+@example
+$types = $sth->@{type@};
+@end example
+
+@end table
+
+
+@node DBI-info, , Perl DBI Class, Perl
+@c German node DBI-Informationen
+@subsection Weitere @code{DBI}/@code{DBD}-Informationen
+
+@cindex @code{DBI/DBD}
+
+Bitte verwenden Sie den @code{perldoc}-Befehl, um weitere Informationen
+über @code{DBI} zu erhalten.
+
+@example
+perldoc DBI
+perldoc DBI::FAQ
+perldoc DBD::mysql
+@end example
+
+Sie können ausserdem @code{pod2man}, @code{pod2html} usw. verwenden, um in
+andere Formate zu wandeln.
+
+Die neuesten @code{DBI}-Informationen finden Sie auf der @code{DBI} Website:
+@example
+@uref{http://www.symbolstone.org/technology/perl/DBI/index.html}
+@end example
+
+
+@node ODBC, C, Perl, Clients
+@c German node ODBC
+@section MySQL-ODBC-Unterstützung
+
+@cindex ODBC
+@cindex Windows
+@cindex MyODBC
+
+
+
+MySQL unterstützt ODBC mit Hilfe des @strong{MyODBC}-Programms. Dieses
+Kapitel erläutert, wie Sie @strong{MyODBC} installieren und benutzen. Hier
+werden Sie außerdem eine Liste von Programmen finden, die mit
+@strong{MyODBC} zusammenarbeiten.
+
+@menu
+* Installing MyODBC::
+* ODBC administrator::
+* MyODBC connect parameters::
+* ODBC Problems::
+* MyODBC clients::
+* ODBC and last_insert_id::
+* MyODBC bug report::
+@end menu
+
+@node Installing MyODBC, ODBC administrator, ODBC, ODBC
+@c German node MyODBC-Installation
+@subsection Wie Sie MyODBC installieren
+
+@strong{MyODBC} ist ein 32-Bit-ODBC- (2.50) -Level-0- (mit Level-1- und
+Level-2-Features) Treiber für die Anbindung an ODBC-fähige Applikationen an
+MySQL. @strong{MyODBC} funktioniert unter Windows95, Windows98, NT, und
+auf den meisten Unix-Plattformen.
+
+@strong{MyODBC} ist "public domain". Sie finden die neueste Version bei
+@uref{http://www.mysql.com/downloads/api-myodbc.html}.
+
+Wenn Sie ein Problem mit @strong{MyODBC} haben und Ihr Programm auch
+mit OLEDB arbeitet, sollten sie den OLEDB Treiber probieren, den sie im
+"Contrib"-Abschnitt finden. @xref{Contrib}.
+
+Normalerweise müssen Sie @strong{MyODBC} nur auf Windows-Maschinen
+installieren. Sie brauchen @strong{MyODBC} für Unix nur, wenn sie ein
+Programm wie ColdFusion haben, das auf einer Unix-Maschine läuft und ODBC
+für die Datenbankverbindung nutzt.
+
+Wenn Sie @strong{MyODBC} unter Unix installieren wollen, brauchen Sie noch
+einen @strong{ODBC}-Manager. @strong{MyODBC} arbeitet mit den meisten
+Unix-ODBC-Managern zusammen.
+@c German FIX node doesn't exist, should probably be to Portals?
+@c Eine Liste finden Sie in dem @strong{ODBC}-verwandten Linkabschnitt
+@c auf der MySQL-Seite @xref{Nützliche Links}.
+
+Um @strong{MyODBC} unter Windows zu installieren, sollten sie die passende
+@strong{MyODBC} Zip-Datei (für Windows 95/98 oder NT / Windows 2000)
+herunterladen, es mit @code{WINZIP} oder einem ähnlichen Programm
+entpacken, und die @code{SETUP.EXE}-Datei ausführen.
+
+Unter Windows NT kann folgender Fehler während der Installation auftreten
+(@strong{MyODBC}):
+
+@example
+Während des Kopiervorgangs ist ein Fehler aufgetreten:
+C:\WINDOWS\SYSTEM\MFC30.DLL. Starten Sie Windows neu und beginnen die
+Installation erneut, noch bevor sie ein anderes Programm starten, das ODBC
+verwendet.
+@end example
+
+Das Problem in diesem Fall ist, dass ein anderes Programm ODBC verwendet
+und dass unter Windows zwei Programme nicht gleichzeitig auf eine Datei
+zugreifen können. Deshalb kann es sein, dass Sie nicht in der Lage sind,
+die ODBC-Treiber mit Microsofts ODBC Setup Programm zu installieren. In den
+meisten Fällen genügt es, den @code{Ignorieren}-Knopf zu drücken, um die
+restlichen Dateien zu installieren und die Installation abzuschließen. Wenn
+das nicht funktioniert, booten Sie Ihren Rechner im Abgesicherten Modus,
+indem sie F8 vor dem Starten von Windows drücken und den Abgesicherten
+Modus auswählen. Installieren sie @strong{MyODBC}, und starten Sie wieder
+im normalen Modus.
+
+@itemize @bullet
+@item
+Um eine Verbindung mit einer ODBC-Applikation, die MySQL nicht nativ
+unterstützt, von Windows zu Unix herzustellen, müssen Sie zunächst
+@strong{MyODBC} unter Windows installieren.
+@item
+Der Windows-Benutzer muss Zugriffsrechte auf den MySQL-Server der
+Unix-Maschine besitzen. Diese richten Sie mit dem @code{GRANT}-Befehl ein.
+@xref{GRANT,,@code{GRANT}}.
+@item
+Sie müssen wie folgt einen ODBC-DSN-Eintrag erstellen:
+
+@itemize @minus
+@item
+Öffnen Sie die Systemsteuerung der Windows-Maschine.
+@item
+Doppelklicken Sie das ODBC-Datenquellen-Symbol.
+@item
+Klicken Sie auf die Registerkarte Benutzer-DSN.
+@item
+Klicken Sie auf Hinzufügen.
+@item
+Wählen Sie MySQL im Fenster "Neue Datenquelle hinzufügen" und klicken Sie
+auf den Fertig-Knopf.
+@item
+Das MySQL-Treiber-Standard-Konfigurationsfenster wird nun angezeigt.
+@xref{ODBC administrator}.
+@end itemize
+
+@item
+Starten Sie nun ihre Applikation und wählen Sie den ODBC-Treiber mit der
+von ihnen im ODBC angegebenen DSN.
+@end itemize
+
+Bitte beachten Sie, dass weitere Konfigurationsoptionen im MySQL-Fenster
+vorhanden sind (trace, don't prompt on connect usw.). Probieren Sie diese
+aus, wenn Sie Probleme haben.
+
+@node ODBC administrator, MyODBC connect parameters, Installing MyODBC, ODBC
+@c German node ODBC-Administrator
+@subsection Wie Sie die verschiedenen Felder im ODBC-Administrator Programm ausfüllen
+
+@cindex ODBC, Administrator
+
+Es gibt drei Möglichkeiten, den Server unter Windows 95 anzugeben:
+
+@itemize @bullet
+@item
+Verwenden Sie die IP-Adresse des Servers.
+@item
+Fügen Sie der Datei @file{\windows\lmhosts} folgende Informationen an:
+
+@example
+ip hostname
+@end example
+
+Beispiel:
+
+@example
+194.216.84.21 mein_hostname
+@end example
+
+@item
+Konfigurieren Sie DNS:
+@end itemize
+
+Beispiel: Wie Sie das @code{ODBC setup} ausfüllen:
+@example
+Windows DSN Name: test
+Beschreibung: Das ist meine Datenbank
+MySql Datenbank: test
+Server: 194.216.84.21
+User: monty
+Password: mein_passwort
+Port:
+@end example
+
+Der Wert für @code{Windows DSN Namen} muss in ihrem Windows-ODBC-Setup
+eindeutig sein.
+
+Sie müssen die Werte für @code{Server}, @code{User}, @code{Password} oder
+@code{Port} im ODBC-Setup-Fenster nicht angeben. Wenn Sie es jedoch tun,
+werden diese Werte als Standardwerte verwendet, wenn Sie versuchen, eine
+Verbindung aufzubauen. Sie können die Werte auch zur Laufzeit ihres
+Programms angeben.
+
+Wenn Sie die Portnummer nicht angeben, wird der Standard-Port
+(@value{default_port}) verwendet.
+
+Wenn Sie die Option @code{Optionen aus C:\my.cnf lesen} angeben, werden die
+Gruppen @code{client} und @code{odbc} aus der @file{C:\my.cnf}-Datei
+gelesen. Sie können alle Optionen verwenden, die für @code{mysql_options()}
+gültig sind. @xref{mysql_options, , @code{mysql_options}}.
+
+
+@node MyODBC connect parameters, ODBC Problems, ODBC administrator, ODBC
+@c German node MyODBC-Verbindungsparameter
+@subsection Verbindungsparameter für MyODBC
+
+Man kann die folgenden Parameter für @strong{MyODBC} im
+@code{[Servername]}-Abschnitt in der @code{ODBC.INI}-Datei oder über das
+@code{InConnectionString}-Argument im @code{SQLDriverConnect()}-Aufruf
+angeben:
+
+@multitable @columnfractions .2 .2 .6
+@item @strong{Parameter} @tab @strong{Standardwert} @tab @strong{Bedeutung}
+@item user @tab ODBC (unter Windows) @tab Der Benutzername, der verwendet wird, um zu MySQL zu verbinden.
+@item server @tab localhost @tab Der Hostname des MySQL-Servers.
+@item database @tab @tab Die Standarddatenbank
+@item option @tab 0 @tab Eine Ganzzahl, die angibt, wie @strong{MyODBC} arbeiten soll. Siehe unten.
+@item port @tab 3306 @tab Der TCP/IP-Port, der verwendet werden soll, wenn der @code{server} nicht @code{localhost} ist.
+@item stmt @tab @tab Ein Statement, das bei der Verbindung zu @code{MySQL} ausgeführt wird.
+@item password @tab @tab Das Passwort für die @code{server}-@code{user}-Kombination.
+@item socket @tab @tab Der Socket oder die Windows-Pipe, über die verbunden werden soll.
+@end multitable
+
+Die Option "argument" wird verwendet, um @strong{MyODBC} zu sagen, dass der
+Client nicht 100% ODBC-kompatibel ist. Unter Windows setzt man diese Option
+normalerweise im Verbindungsdialog, Sie können aber auch das
+"option"-Argument verwenden. Die folgenden Optionen sind in derselben
+Reihenfolge wie im @strong{MyODBC}-Verbindungsdialog:
+
+@multitable @columnfractions .1 .9
+@item @strong{Bit} @tab @strong{Bedeutung}
+@item 1 @tab Der Client kann nicht damit umgehen, dass @strong{MyODBC} die wirkliche Breite einer Spalte zurückgibt.
+@item 2 @tab Der Client kann nicht damit umgehen, dass MySQL die wirkliche Anzahl an "affected rows" zurückgibt. Wenn dieses Bit gesetzt ist, wird MySQL statt dessen 'found rows' zurückgeben. Dies wird erst ab MySQL 3.21.14 unterstützt.
+@item 4 @tab Erstellt ein Debug-Log in c:\myodbc.log. Das ist dasselbe, als wenn Sie @code{MYSQL_DEBUG=d:t:O,c::\myodbc.log} in Ihre @file{AUTOEXEC.BAT} schreiben.
+@item 8 @tab Entfernt jede Paket-Beschränkung für Ergebnisse und Parameter.
+@item 16 @tab Nicht auf Eingaben warten, sogar wenn der Treiber dies verlangt.
+@item 32 @tab Einen ODBC 1.0 Treiber simulieren.
+@item 64 @tab Die Angabe 'datenbank' in 'datenbank.tabelle.spalte' ignorieren.
+@item 128 @tab Die Verwendung von ODBC-Manager-Zeigern erzwingen (experimentell).
+@item 256 @tab Die Verwendung des erweiterten 'fetch' verbieten (experimentell).
+@item 512 @tab CHAR-Felder bis zur vollen Spaltenlänge füllen.
+@item 1024 @tab SQLDescribeCol() wird voll qualifizierte Spaltennamen zurückgeben.
+@item 2048 @tab Verwendet das komprimierte Client-/Server Protokoll.
+@item 4096 @tab Weist den Server an, Leerzeichen nach einem Funktionsnamen und vor @code{'('} zu ignorieren (wird von PowerBuilder benötigt). So werden alle Funktionsnamen zu Schlüsselwörtern!
+@item 8192 @tab Über "Named Pipes" zu einem @code{mysqld}-Server verbinden, der unter Windows NT läuft.
+@item 16384 @tab Ändert LONGLONG-Spalten zu INT-Spalten (einige Applikationen können mit LONGLONG nicht umgehen).
+@item 32768 @tab Gibt 'user' als Tabellenqualifizierer und Tabellen-Besitzer von SQL-Tabellen zurück (experimentell).
+@item 65536 @tab Liest die Parameter @code{client} und @code{odbc}-Gruppen aus der @file{my.cnf}-Datei.
+@item 131072 @tab Fügt einige Sicherheitsüberprüfungen hinzu (sollte nicht nötig sein, aber ...).
+@end multitable
+
+Wenn Sie viele Optionen haben wollen, sollten Sie die obigen Flags
+hinzufügen. Zum Beispiel gibt Ihnen die Option 12 (4+8) Debugging und keine
+Paketbeschränkungen.
+
+Die Standard-@file{MYODBC.DLL}-Datei wird für optimale Performance
+kompiliert. Wenn Sie @strong{MyODBC} debuggen wollen (um zum Beispiel
+"tracing" zu aktivieren), sollten Sie stattdessen @code{MYODBCD.DLL}
+verwenden. Um diese Datei zu installieren, kopieren Sie @file{MYODBCD.DLL}
+einfach über die installierte @code{MYODBC.DLL}-Datei.
+
+
+@node ODBC Problems, MyODBC clients, MyODBC connect parameters, ODBC
+@c German node ODBC-Probleme
+@subsection Wie Sie Probleme mit MyODBC berichten
+
+@strong{MyODBC} wurde mit Access, Admndemo.exe, C++-Builder,
+Borland Builder 4, Centura Team Developer (vorher Gupta SQL/Windows),
+ColdFusion (unter Solaris und NT mit Service Pack 5), Crystal Reports,
+DataJunction, Delphi, ERwin, Excel, iHTML, FileMaker Pro, FoxPro, Notes
+4.5/4.6, SBSS, Perl DBD-ODBC, Paradox, Powerbuilder, Powerdesigner 32
+bit, VC++ und Visual Basic getestet.
+
+Wenn Sie weitere Applikationen kennen, die mit @strong{MyODBC}
+zusammenarbeiten, sagen Sie uns bitte unter @email{myodbc@@lists.mysql.com}
+Bescheid!
+
+Mit einigen Programmen können Fehler wie diese auftreten: @code{Another
+user hat modifies the record that you have modified}. Meistens lösen Sie
+das folgendermaßen:
+
+@itemize @bullet
+@item
+Fügen Sie der Tabelle einen Primärschlüssel hinzu, wenn noch keiner
+existiert.
+@item
+Fügen Sie eine TIMESTAMP-Spalte hinzu, wenn noch keine existiert.
+@item
+Verwenden Sie ausschließlich 'Double Float'-Felder. Manche Programme
+kommen mit 'Single Float'-Feldern nicht klar.
+@end itemize
+
+Wenn das nicht helfen sollte, dann erstellen Sie eine @code{MyODBC}
+'Trace'-Datei und versuchen Sie, die Fehlerquelle so zu erschließen.
+
+
+@node MyODBC clients, ODBC and last_insert_id, ODBC Problems, ODBC
+@c German node MyODBC-Clients
+@subsection Programme, die bekanntermaßen mit MyODBC zusammenarbeiten
+
+Die meisten Programme sollten mit @strong{MyODBC} zusammenarbeiten. Für die
+unten aufgeführten haben wir es selbst getestet oder haben die Bestätigung
+eines Benutzers, dass es läuft.
+
+@table @asis
+@item @strong{Programm}
+@strong{Anmerkung}
+@cindex Microsoft Access
+
+@item Access
+Um Access zum Laufen zu bringen:
+@itemize @bullet
+@item
+Wenn Sie Access 2000 verwenden, sollten Sie die neuesten (Version 2.6 oder
+höher) Microsoft-MDAC (@code{Microsoft Data Access Components}) von
+@uref{http://www.microsoft.com/data} herunterladen. Dies wird folgenden Bug
+in Access beheben: Wenn Sie Daten nach MySQL exportieren, werden Tabellen-
+und Spaltennamen nicht spezifiziert. Ein anderer Weg, diesen Bug zu
+umgehen, ist, MyODBC auf Version 2.50.33 und MySQL auf Version 3.23.x zu
+aktualisieren, welche beide zusammen einen Workaround für diesen Bug
+implementiert haben.
+
+Ausserdem sollten Sie das Microsoft-Jet-4.0-Service-Pack 5 (SP5)
+einspielen, welches hier
+@uref{http://support.microsoft.com/support/kb/articles/Q 239/1/14.ASP}
+gefunden werden kann. Dies behebt einige Fälle, in denen Spalten als
+@code{#deleted#} in Access markiert sind.
+
+Beachten Sie, dass Sie, wenn Sie die MySQL-Version 3.22 verwenden, den
+MDAC-Patch einspielen und MyODBC 2.50.32 oder 2.50.34 und höher benutzen
+müssen, um dieses Problem zu umgehen.
+@item
+Für alle Access-Versionen sollten Sie die MyODBC-Optionen auf @code{Return
+matching rows} setzen. Für Access 2.0 sollten Sie ausserdem @code{Simulate
+ODBC 1.0} einschalten.
+@item
+Sie sollten einen Timestamp in alle Tabellen einfügen, die Sie
+aktualisieren wollen. Für maximale Portablilität werden
+@code{TIMESTAMP(14)} oder einfach @code{TIMESTAMP} anstelle von
+@code{TIMESTAMP(X)}-Variationen empfohlen.
+@item
+Sie sollten einen Primärschlüssel in Ihren Tabellen haben. Falls nicht,
+können neue oder geänderte Zeilen als @code{#DELETED#} erscheinen.
+@item
+Verwenden sie ausschließlich @code{DOUBLE}-Float-Felder. Access kann nicht
+richtig mit "Single Floats" vergleichen. Die Symptome sind, dass entweder
+neue oder geänderte Zeilen als @code{#DELETED#} erscheinen oder Sie keine
+Zeilen finden oder ändern können.
+@item
+Wenn Sie eine Tabelle mit MyODBC verbinden, die eine @code{BIGINT}-Spalte hat,
+werden die Ergebnisse als @code{#DELETED} angezeigt. Sie umgehen das Problem
+folgendermaßen:
+@itemize @bullet
+@item
+Fügen Sie eine weitere @code{TIMESTAMP}-"Dummy-Spalte" hinzu, am besten
+@code{TIMESTAMP(14)}.
+@item
+Wählen Sie @code{'BIGINT Spalten zu INT wandeln'} im Verbindungsdialog des
+ODBC-DSN-Administrators.
+@item
+Entfernen Sie die Tabellenverknüpfung aus Access und stellen Sie sie wieder
+her.
+@end itemize
+
+Die vorherigen Zeilen werden weiterhin als @code{#DELETED#} angezeigt, aber
+neue/geänderte Zeilen werden korrekt dargestellt.
+@item
+Wenn Sie weiterhin den Fehler @code{Ein anderer Benutzer hat Ihre Daten geändert}
+erhalten, nachdem Sie die @code{TIMESTAMP}-Spalte hinzugefügt haben, könnte
+Ihnen der folgende Trick helfen:
+
+Verwenden Sie anstelle von @code{Datenblattansicht} ein Formular mit den
+von Ihnen gewünschten Feldern und benutzen Sie dann
+@code{Formularblattansicht}. Sie sollten den @code{StandardWert} für die
+@code{TIMESTAMP}-Spalte auf @code{NOW()} setzen. Zusätzlich ist es sicher
+nützlich, die @code{TIMESTAMP}-Spalte zu verstecken, damit Ihre Anwender
+nicht erschrecken.
+@item
+Manchmal erstellt Access ungültige SQL-Anfragen, die MySQL nicht versteht.
+
+
+Wählen Sie zur Lösung dieses Problems
+@code{"Abfrage|SQL-spezifisch|Pass-Through"} aus dem Access-Menü.
+@item
+Wenn Sie statt dessen @code{MEMO}-Spalten haben wollen, sollten Sie die
+Spalte mit @code{ALTER TABLE} in @code{TEXT} ändern.
+@item
+Access kann nicht immer sauber mit @code{DATE}-Spalten umgehen. Wenn Sie ein
+solches Problem haben, ändern Sie die entsprechenden Spalten in @code{DATETIME}.
+@item
+Wenn Sie in Access eine Spalte @code{BYTE} haben, wird Access versuchen,
+diese in @code{TINYINT} anstelle von @code{TINYINT UNSIGNED} zu
+exportieren. Das führt zu Problemen, wenn Sie Werte in der Spalte haben,
+die größer als 127 sind!
+@end itemize
+
+@cindex ADO program
+@item ADO
+Wenn Sie mit der ADO-API und @strong{MyODBC} kodieren, müssen Sie auf
+einige vorgabemäßige Eigenschaften achten, die vom MySQL-Server nicht
+unterstützt werden. Die Benutzung von @code{CursorLocationProperty} als
+@code{adUseServer} zum Beispiel gibt für @code{RecordCountProperty} ein
+Ergebnis von -1 zurück. Um den richtigen Wert zu erhalten, müssen Sie diese
+Eigenschaft auf @code{adUseClient} setzen, wie im unten stehenden
+Visual-Basic-Code gezeigt:
+
+@example
+Dim myconn As New ADODB.Connection
+Dim myrs As New Recordset
+Dim mySQL As String
+Dim myrows As Long
+
+myconn.Open "DSN=MyODBCsample"
+mySQL = "SELECT * from user"
+myrs.Source = mySQL
+Set myrs.ActiveConnection = myconn
+myrs.CursorLocation = adUseClient
+myrs.Open
+myrows = myrs.RecordCount
+
+myrs.Close
+myconn.Close
+@end example
+
+Ein weiterer Workaround besteht darin, ein @code{SELECT COUNT(*)}-Statement
+für eine ähnliche Anfrage zu benutzen, um das korrekte Zählen der Zeilen zu
+erreichen.
+
+@item Active server pages (ASP)
+Sie sollten den Option-Flag @code{Return matching rows} benutzen.
+
+@item BDE-Applikationen
+Damit diese funktionieren, sollten Sie die Option-Flags
+@code{Don't optimize column widths} und @code{Return matching rows}
+benutzen.
+
+@cindex Borland Builder 4
+@item Borland Builder 4
+Wenn Sie eine Anfrage starten, können Sie die Eigenschaft @code{Active}
+oder die Methode @code{Open} benutzen. Beachten Sie, dass @code{Active}
+automatisch mit einer @code{SELECT * FROM ...}-Anfrage startet, was keine
+gute Idee ist, wenn Ihre Tabellen Groß sind!
+@item ColdFusion (unter Unix)
+Die folgenden Informationen sind der ColdFusion-Dokumentation entnommen:
+
+Lesen Sie folgende Informationen, um den ColdFusion-Server für Linux so zu
+konfigurieren, dass er den unixODBC-Treiber bei @strong{MyODBC} für
+MySQL-Datenquellen benutzt. Allaire kann bestätigen, dass die
+@strong{MyODBC}-Version 2.50.26 mit MySQL-Version 3.22.27 und ColdFusion
+für Linux funktioniert. (Jede neuere Version sollte ebenfalls
+funktionieren.) Sie können @strong{MyODBC} von
+@uref{http://www.mysql.com/downloads/api-myodbc.html} herunter laden.
+
+@cindex ColdFusion
+Bei ColdFusion Version 4.5.1 können Sie den ColdFusion Administrator
+benutzen, um die MySQL-Datenquelle hinzuzufügen. Der Treiber liegt der
+ColdFusion Version 4.5.1 jedoch nicht bei. Bevor der MySQL-Treiber in der
+Auswahlliste der ODBC-Datenquellen erscheint, müssen Sie den
+@strong{MyODBC}-Treiber bauen und nach
+@file{/opt/coldfusion/lib/libmyodbc.so} kopieren.
+
+Das Contrib-Verzeichnis enthält das Programm mydsn-xxx.zip, mit dem Sie die
+DSN-Registrierungs-Datei für den MyODBC-Treiber auf
+Coldfusion-Applikationen bauen können.
+
+@cindex DataJunction
+@item DataJunction
+Sie müssen es ändern, damit es @code{VARCHAR} statt @code{ENUM} ausgibt,
+weil es Letzteres in einer Art ausgibt, die MySQL nicht versteht.
+
+@cindex Excel
+@item Excel
+Funktioniert. Einige Tipps:
+@itemize @bullet
+@item
+Wenn Sie Probleme mit Datumsangaben haben, versuchen Sie, sie als
+Zeichenketten mit der @code{CONCAT()}-Funktion abzurufen. Beispiel:
+@example
+select CONCAT(sonnenaufgang), CONCAT(sonnenuntergang)
+ from aufgang_untergang;
+@end example
+Werte, die auf diese Art als Zeichenketten abgerufen werden, sollten
+korrekt als Zeitwerte von Excel97 erkannt werden.
+
+Der Zweck von @code{CONCAT()} in diesem Beispiel ist, ODBC auszutricksen,
+so dass es denkt, dass die Spalte vom Typ "Zeichenkette" sei. Ohne
+@code{CONCAT()} weiß ODBC, dass die Spalte vom Typ "Zeit" ist, und Excel
+versteht das nicht.
+
+Beachten Sie, dass das ein Bug in Excel ist, weil es eine Zeichenkette
+automatisch in eine Zeitangabe umwandelt. Das wäre sehr gut, wenn die
+Quelle eine Textdatei wäre, ist aber einfach nur dumm, wenn die Quelle eine
+ODBC-Verbindung ist, die exakte Typen für jede Spalte übermittelt.
+@end itemize
+@cindex Word
+@item Word
+
+Um Daten von MySQL in Word- / Excel-Dokumente abzurufen, müssen Sie den
+@code{MyODBC}-Treiber benutzen und das Add-in Microsoft Query hinzufügen.
+
+Erzeugen Sie zum Beispiel eine Datenbank mit einer Tabelle, die 2
+Text-Spalten enthält:
+
+@itemize @bullet
+@item
+Fügen Sie Zeilen mit dem @code{mysql}-Kommandozeilenwerkzeug ein.
+@item
+Erzeugen Sie eine DSN-Datei mit dem MyODBC-Treiber, die Sie zum Beispiel my
+nennen, für die oben genannten Datenbank.
+@item
+Öffnen Sie Word.
+@item
+Erzeugen Sie ein leeres Dokument.
+@item
+Öffnen Sie die Symbolleiste 'Datenbank' und klicken Sie auf die
+Schaltfläche 'Datenbank einfügen'.
+@item
+Klicken Sie auf die Schaltfläche 'Daten abrufen'.
+@item
+Klicken Sie auf die Schaltfläche 'MS Query'.
+@item
+Erzeugen Sie in MS Query eine neue Datenquelle unter Benutzung der
+DSN-Datei my.
+@item
+Wählen Sie die neue Anfrage aus.
+@item
+Wählen Sie die Spalten aus, die Sie haben wollen.
+@item
+Legen Sie bei Bedarf einen Filter fest.
+@item
+Legen Sie bei Bedarf eine Sortierung fest.
+@item
+Wählen Sie 'Daten an Word zurückgeben'.
+@item
+Klicken Sie auf 'Beenden'.
+@item
+Klicken Sie auf 'Daten einfügen' und wählen Sie die Datensätze aus.
+@item
+Klicken Sie auf 'OK', und Sie sehen die Zeilen in Ihrem Word-Dokument.
+@end itemize
+
+@cindex odbcadmin
+@item odbcadmin
+Test-Programm für ODBC.
+@cindex Delphi-Programm
+@item Delphi
+Sie müssen BDE-Version 3.2 oder neuer benutzen. Setzen Sie die `Don't
+optimize column width'-Option, wenn Sie sich mit MySQL verbinden.
+
+Hier ist möglicherweise nützlicher Delphi-Code, der sowohl einen
+ODBC-Eintrag als auch einen BDE-Eintrag für @strong{MyODBC} setzt (der
+BDE-Eintrag erfordert einen BDE-Alias-Editor, der kostenlos auf einer
+Delphi Super Page in Ihrer Nähe herunter geladen werden kann (Dank dafür an
+Bryan Brunton @email{bryan@@flesherfab.com}:
+
+@example
+fReg:= TRegistry.Create;
+ fReg.OpenKey('\Software\ODBC\ODBC.INI\DocumentsFab', True);
+ fReg.WriteString('Database', 'Documents');
+ fReg.WriteString('Description', ' ');
+ fReg.WriteString('Driver', 'C:\WINNT\System32\myodbc.dll');
+ fReg.WriteString('Flag', '1');
+ fReg.WriteString('Password', '');
+ fReg.WriteString('Port', ' ');
+ fReg.WriteString('Server', 'xmark');
+ fReg.WriteString('User', 'winuser');
+ fReg.OpenKey('\Software\ODBC\ODBC.INI\ODBC Data Sources', True);
+ fReg.WriteString('DocumentsFab', 'MySQL');
+ fReg.CloseKey;
+ fReg.Free;
+
+ Memo1.Lines.Add('DATABASE NAME=');
+ Memo1.Lines.Add('USER NAME=');
+ Memo1.Lines.Add('ODBC DSN=DocumentsFab');
+ Memo1.Lines.Add('OPEN MODE=READ/WRITE');
+ Memo1.Lines.Add('BATCH COUNT=200');
+ Memo1.Lines.Add('LANGTreiber=');
+ Memo1.Lines.Add('MAX ROWS=-1');
+ Memo1.Lines.Add('SCHEMA CACHE DIR=');
+ Memo1.Lines.Add('SCHEMA CACHE SIZE=8');
+ Memo1.Lines.Add('SCHEMA CACHE TIME=-1');
+ Memo1.Lines.Add('SQLPASSTHRU MODE=SHARED AUTOCOMMIT');
+ Memo1.Lines.Add('SQLQRYMODE=');
+ Memo1.Lines.Add('ENABLE SCHEMA CACHE=FALSE');
+ Memo1.Lines.Add('ENABLE BCD=FALSE');
+ Memo1.Lines.Add('ROWSET SIZE=20');
+ Memo1.Lines.Add('BLOBS TO CACHE=64');
+ Memo1.Lines.Add('BLOB SIZE=32');
+
+ AliasEditor.Add('DocumentsFab','MySQL',Memo1.Lines);
+@end example
+
+@cindex C++-Builder
+@item C++-Builder
+Getestet mit BDE-Version 3.0. Das einzige bekannte Problem ist, dass
+Anfragefelder nicht aktualisiert werden, wenn sich die Tabellenstruktur
+ändert. BDE scheint jedoch keine Primärschlüssel zu erkennen, sondern nur
+den Index PRIMARY, obwohl das eigentlich kein Problem darstellt.
+
+@item Vision
+Sie sollten den Option-Flag @code{Return matching rows} benutzen.
+
+@cindex Visual Basic
+@item Visual Basic
+Damit Sie eine Tabelle aktualisieren können, müssen Sie für die Tabelle
+einen Primärschlüssel definieren.
+
+Visual Basic mit ADO kann keine großen Ganzzahlen handhaben. Das heißt,
+dass einige Anfragen wie @code{SHOW PROCESSLIST} nicht korrekt
+funktionieren. Das läßt sich beheben, indem man die Option
+@code{OPTION=16834} in der ODBC-Verbindungs-Zeichenkette hinzufügt oder die
+@code{Change BIGINT columns to INT}-Option im MySQL-Verbindungsbildschirm
+setzt. Eventuell sollten Sie auch die @code{Return matching rows}-Option
+setzen.
+
+@item VisualInterDev
+Wenn Sie den Fehler @code{[Microsoft][ODBC Driver Manager] Driver does not
+support this parameter} erhalten, kann es daran liegen, dass Sie ein
+@code{BIGINT} in Ihrem Ergebnis haben. Versuchen Sie, die @code{Change
+BIGINT columns to INT}-Option im MySQL-Verbindungsbildschirm zu setzen.
+
+@item Visual Objects
+Sie sollten den Option-Flag @code{Don't optimize column widths} setzen.
+@end table
+
+
+@node ODBC and last_insert_id, MyODBC bug report, MyODBC clients, ODBC
+@c German node ODBC und last_insert_id
+@subsection Wie man den Wert einer @code{AUTO_INCREMENT}-Spalte in ODBC erhält
+
+@cindex AUTO-INCREMENT, ODBC
+
+Ein häufiges Problem ist es, den Wert einer automatisch erzeugten Kennung
+von einem @code{INSERT} zu erhalten. Bei ODBC können Sie etwas wie
+folgendes tun (unter der Annahme, dass @code{auto} ein
+@code{AUTO_INCREMENT}-Feld ist):
+
+@example
+INSERT INTO foo (auto,text) VALUES(NULL,'text');
+SELECT LAST_INSERT_ID();
+@end example
+
+Oder, wenn Sie die Kennung in eine andere Tabelle einfügen wollen:
+
+@example
+INSERT INTO foo (auto,text) VALUES(NULL,'text');
+INSERT INTO foo2 (id,text) VALUES(LAST_INSERT_ID(),'text');
+@end example
+
+@xref{Getting unique ID}.
+
+Bei einigen ODBC-Applikationen (zumindest Delphi und Access) kann folgende
+Anfrage benutzt werden, um eine neu eingefügte Zeile zu finden:
+@example
+SELECT * FROM tabelle WHERE auto IS NULL;
+@end example
+
+
+@node MyODBC bug report, , ODBC and last_insert_id, ODBC
+@c German node MyODBC-Bug-Bericht
+@subsection Probleme mit MyODBC berichten
+
+@cindex berichten, MyODBC-Probleme
+@cindex Probleme, ODBC
+@cindex MyODBC, Probleme berichten
+
+Wenn Sie Probleme mit @strong{MyODBC} bekommen, sollten Sie als erstes eine
+Log-Datei durch den ODBC-Manager anlegen lassen (das Log, das Sie erhalten,
+wenn Sie Logs von ODBCADMIN abfragen) sowie ein @strong{MyODBC}-Log.
+
+Um ein @strong{MyODBC}-Log zu erhalten, tun Sie folgendes:
+
+@enumerate
+@item
+Stellen Sie sicher, dass Sie @code{myodbcd.dll} und nicht @code{myodbc.dll}
+benutzen. Am einfachsten ist es, wenn Sie sich @code{myodbcd.dll} aus der
+MyODBC-Distribution holen und es über @code{myodbc.dll} kopieren, die sich
+wahrscheinlich in Ihrem @code{C:\windows\system32}- oder
+@code{C:\winnt\system32}-Verzeichnis befindet.
+
+Denken Sie daran, dass Sie wahrscheinlich die alten myodbc.dll nach dem
+Testen wiederherstellen wollen, weil Sie um einiges schneller ist als
+@code{myodbcd.dll}.
+@item
+Kreuzen Sie `Trace MyODBC' im @strong{MyODBC}-Verbindungs- bzw.
+Konfigurationsfenster an. Das Log wird in die Datei @file{C:\myodbc.log}
+geschrieben.
+
+Wenn Sie zu diesem Fenster zurückkehren und feststellen, dass die
+Trace-Option nicht mehr angekreuzt ist, heißt das, dass Sie nicht den
+@code{myodbcd.dll}-Treiber benutzen (siehe oben).
+@item
+Starten Sie Ihre Applikation und versuchen Sie, eine Fehlfunktion zu
+bekommen.
+@end enumerate
+
+Untersuchen Sie die @code{MyODBC-Trace-Datei}, um herauszufinden, was
+möglicherweise schief geht. Sie können die abgesetzten Anfragen finden,
+indem Sie nach der Zeichenkette @code{>mysql_real_query} in der
+@file{myodbc.log}-Datei suchen.
+
+Sie sollten die Anfragen auch zusätzlich im @code{mysql}-Monitor oder in
+@code{admndemo} laufen lassen, um herauszufinden, ob der Fehler bei MyODBC
+oder bei MySQL liegt.
+
+Wenn Sie herausgefunden haben, was schief läuft, schicken Sie bitte nur die
+relevanten Zeilen (maximal 40 Zeilen) an @email{myodbc@@lists.mysql.com}.
+Bitte schicken Sie nie die gesamte MyODBC- oder ODBC-Log-Datei!
+
+Wenn Sie nicht herausfinden können, was schief läuft, besteht die letzte
+Option darin, eine Archivdatei anzulegen (tar oder zip), die eine
+MyODBC-Trace-Datei, die ODBC-Log-Datei und eine README-Datei enthält, die
+das Problem erläutert. Schicken Sie diese an
+@uref{ftp://support.mysql.com/pub/mysql/secret}. Nur wir bei MySQL AB haben
+Zugriff auf die Dateien, die Sie hochspielen, und wir gehen mit den Daten
+sehr diskret um!
+
+Wenn Sie ein Programm erzeugen können, das dieses Problem ebenfalls zeigt,
+laden Sie dieses bitte ebenfalls hoch!
+
+Wenn das Programm mit irgend einem anderen SQL-Server funktioniert, sollten
+Sie eine ODBC-Log-Datei anlegen, in der Sie dasselbe in dem anderen
+SQL-Server ausführen.
+
+Bedenken Sie, dass wir umso eher das Problem beheben können, desto mehr
+Informationen Sie uns zur Verfügung stellen!
+
+
+@node C, Cplusplus, ODBC, Clients
+@c German node C
+@section MySQL-C-API
+
+@cindex C-API, datatypes
+@cindex Datentypen, C-API
+
+
+Der C-API-Code wird mit MySQL ausgeliefert. Er ist in der
+@code{mysqlclient}-Bibliothek enthalten und erlaubt C-Programmen, auf eine
+Datenbank zuzugreifen.
+
+Viele Clients in der MySQL-Quelldistribution sind in C geschrieben. Wenn
+Sie nach Beispielen für den Gebrauch der C-API suchen, schauen Sie sich
+diese Clients an. Sie finden Sie im @code{clients}-Verzeichnis in der
+MySQL-Quelldistribution.
+
+Viele andere Client-APIs (alle ausser Java) benutzen die
+@code{mysqlclient}-Bibliothek, um mit dem MySQL-Server zu kommunizieren.
+Das heißt zum Beispiel, dass Sie viele derselben Umgebungsvariablen nutzen
+können, die von anderen Client-Programmen benutzt werden, weil sie von der
+Bibliothek referenziert werden. Eine Liste dieser Variablen findet sich
+unter @ref{Client-Side Scripts}.
+
+Der Client hat eine maximale Kommunikationspuffergröße. Die anfänglich
+zugewiesene Puffergröße (16 KB) wird automatisch bis zur maximale Größe
+(16 MB) vergrößert. Weil Puffergrößen nur bei Bedarf vergrößert werden,
+bedeutet die einfache Erhöhung der maximalen Größe nicht per se, dass mehr
+Ressourcen benutzt werden. Die Überprüfung der Größe ist hauptsächlich
+eine Prüfung auf irrtümliche Anfragen und Kommunikationspakete.
+
+Der Kommunikationspuffer muss Groß genug sein, um ein einzelnes
+SQL-Statement aufzunehmen (für den Client-Server-Verkehr) und eine Zeile
+zurückgegebener Daten (für den Server-Client-Verkehr). Der
+Kommunikationspuffer jedes Threads wird dynamisch vergrößert, um jede
+Anfrage oder Zeile bis zur maximalen Größe zu handhaben. Wenn Sie
+beispielsweise @code{BLOB}-Werte haben, die bis zu 16 MB an Daten
+beinhalten, müssen Sie eine Kommunikationspuffergrenze von zumindest 16 MB
+haben (sowohl beim Server als auch beim Client). Die vorgabemäßige
+maximale Größe beim Client liegt bei 16 MB, aber die vorgabemäßige
+maximale Grenze beim Server liegt bei 1 MB. Das können Sie vergrößern,
+indem Sie den Wert des @code{max_allowed_packet}-Parameters setzen, wenn
+der Server gestartet wird. @xref{Server parameters}.
+
+Der MySQL-Server verringert den Kommunikationspuffer auf
+@code{net_buffer_length} Bytes nach jeder Anfrage. Bei Clients wird die
+Größe des zugewiesenen Puffers bei einer Verbindung nicht herabgesetzt,
+bis die Verbindung geschlossen wird. Dann wird der Client-Speicher wieder
+freigesetzt.
+
+Zum Programmieren mit Threads siehe @ref{Threaded clients}. Um eine
+Standalone-Applikation herzustellen, die "Server" und "Client" im selben
+Programm beinhaltet (und nicht mit einem externen MySQL-Server
+kommuniziert), siehe @ref{libmysqld}.
+
+
+@menu
+* C API datatypes::
+* C API function overview::
+* C API functions::
+* C Thread functions::
+* C Embedded Server func::
+* C API problems::
+* Building clients::
+* Threaded clients::
+* libmysqld::
+@end menu
+
+@node C API datatypes, C API function overview, C, C
+@c German node C-API-Datentypen
+@subsection C-API-Datentypen
+
+@table @code
+@tindex MYSQL C type
+@item MYSQL
+This structure represents a handle to one Datenbank connection. It is
+used für almost all MySQL Funktionen.
+
+@tindex MYSQL_RES C-Typ
+@item MYSQL_RES
+Diese Struktur repräsentiert das Ergebnis einer Anfrage, die Zeilen
+zurückgibt (@code{SELECT}, @code{SHOW}, @code{DESCRIBE}, @code{EXPLAIN}).
+Die von der Anfrage zurückgegebene Informationen wird im Weiteren
+@emph{result set} (Ergebnismenge) genannt.
+
+@tindex MYSQL_ROW C-Typ
+@item MYSQL_ROW
+Das ist eine Typ-sichere Repräsentation einer Zeile von Daten. Momentan ist
+sie als ein Array gezählter Byte-Zeichenketten implementiert. (Sie können
+diese nicht als NULL-begrenzte Zeichenketten behandeln, falls Feldwert
+binäre Daten enthalten können, welche solche Werte intern NULL-Bytes
+enthalten können.) Zeilen werden mit dem Aufruf von
+@code{mysql_fetch_row()} abgeholt.
+
+@tindex MYSQL_FIELD C-Typ
+@item MYSQL_FIELD
+Diese Struktur enthält Informationen über ein Feld, wie Feldname, Feldtyp
+und Feldgröße. Seine Elemente werden weiter unten genauer beschrieben. Sie
+erhalten die @code{MYSQL_FIELD}-Strukturen für jedes Feld durch den
+wiederholten Aufruf von @code{mysql_fetch_field()}. Feldwerte sind nicht
+Teil dieser Struktur, sondern in der @code{MYSQL_ROW}-Struktur enthalten.
+
+
+@tindex MYSQL_FIELD_OFFSET C-Typ
+@item MYSQL_FIELD_OFFSET
+Das ist eine Typ-sichere Repräsentation eines Offsets in einer
+MySQL-Feldliste (benutzt von @code{mysql_field_seek()}.) Offsets sind
+Feldnummern innerhalb einer Zeile, beginnend mit 0.
+
+@tindex my_ulonglong C-Typ
+@tindex my_ulonglong-Werte, Ausgabe
+@item my_ulonglong
+Der Typ, der für die Anzahl von Zeilen und für @code{mysql_affected_rows()},
+@code{mysql_num_rows()}, und @code{mysql_insert_id()} benutzt wird. Dieser
+Typ stellt einen Bereich von @code{0} bis @code{1.84e19} zur Verfügung.
+
+Auf manchen Systemen funktioniert der Versuch, einen Wert des Typs
+@code{my_ulonglong} auszugeben, nicht. Um einen solchen Wert auszugeben,
+wandeln Sie ihn in @code{unsigned long} um und benutzen Sie ein
+@code{%lu}-Ausgabeformat. Beispiel:
+@example
+printf (Anzahl von Zeilen: %lu\n", (unsigned long) mysql_num_rows(result));
+@end example
+@end table
+
+@noindent
+Die @code{MYSQL_FIELD}-Struktur enthält die unten aufgeführten Elemente:
+
+@table @code
+@item char * name
+Der Name des Feldes, als NULL-begrenzte Zeichenkette.
+
+@item char * table
+Der Name der Tabelle, die dieses Feld enthält, falls es kein berechnetes
+Feld ist. Bei berechneten Feldern ist der @code{table}-Wert eine leere
+Zeichenkette.
+
+@item char * def
+Der Vorgabewert dieses Felds als eine NULL-begrenzte Zeichenkette. Dieser
+wird nur gesetzt, wenn Sie @code{mysql_list_fields()} benutzen.
+
+@item enum enum_field_types-Typ
+Der Typ des Felds. Der @code{type}-Wert kann einer der folgenden sein:
+
+@multitable @columnfractions .3 .55
+@item @strong{Typwert} @tab @strong{Typbedeutung}
+@item @code{FIELD_TYPE_TINY} @tab @code{TINYINT}-Feld
+@item @code{FIELD_TYPE_SHORT} @tab @code{SMALLINT}-Feld
+@item @code{FIELD_TYPE_LONG} @tab @code{INTEGER}-Feld
+@item @code{FIELD_TYPE_INT24} @tab @code{MEDIUMINT}-Feld
+@item @code{FIELD_TYPE_LONGLONG} @tab @code{BIGINT}-Feld
+@item @code{FIELD_TYPE_DECIMAL} @tab @code{DECIMAL}- oder @code{NUMERIC}-Feld
+@item @code{FIELD_TYPE_FLOAT} @tab @code{FLOAT}-Feld
+@item @code{FIELD_TYPE_DOUBLE} @tab @code{DOUBLE}- oder @code{REAL}-Feld
+@item @code{FIELD_TYPE_TIMESTAMP} @tab @code{TIMESTAMP}-Feld
+@item @code{FIELD_TYPE_DATE} @tab @code{DATE}-Feld
+@item @code{FIELD_TYPE_TIME} @tab @code{TIME}-Feld
+@item @code{FIELD_TYPE_DATETIME} @tab @code{DATETIME}-Feld
+@item @code{FIELD_TYPE_YEAR} @tab @code{YEAR}-Feld
+@item @code{FIELD_TYPE_STRING} @tab @code{CHAR}- oder @code{VARCHAR}-Feld
+@item @code{FIELD_TYPE_BLOB} @tab @code{BLOB}- oder @code{TEXT}-Feld (benutzen Sie @code{max_length}, um die maximale Länge festzulegen)
+@item @code{FIELD_TYPE_SET} @tab @code{SET}-Feld
+@item @code{FIELD_TYPE_ENUM} @tab @code{ENUM}-Feld
+@item @code{FIELD_TYPE_NULL} @tab @code{NULL}-Feld
+@item @code{FIELD_TYPE_CHAR} @tab Veraltet; benutzen Sie statt dessen @code{FIELD_TYPE_TINY}
+@end multitable
+
+Sie können das @code{IS_NUM()}-Makro benutzen, um zu testen, ob ein Feld
+einen numerischen Typ besitzt oder nicht. Übergeben Sie den
+@code{type}-Wert an @code{IS_NUM()}, und Sie erhalten WAHR (true), wenn das
+Feld numerisch ist:
+
+@example
+if (IS_NUM(field->type))
+ printf("Feld ist numerisch\n");
+@end example
+
+@item unsigned int length
+Die Breite des Felds, wie in der Tabellendefinition festgelegt.
+
+@item unsigned int max_length
+Die maximale Breite des Felds für die Ergebnismenge (die Länge des längsten
+Feldwerts für die Zeilen, die tatsächlich in der Ergebnismenge enthalten
+sind). Wenn Sie @code{mysql_store_result()} oder @code{mysql_list_fields()}
+benutzen, enthält die Variable die maximale Länge für das Feld. Wenn Sie
+@code{mysql_use_result()} benutzen, ist sie 0.
+
+@item unsigned int flags
+Unterschiedliche Bit-Flags für das Feld. Der @code{flags}-Wert kann 0 oder
+mehr der folgenden Bits gesetzt haben:
+
+@multitable @columnfractions .3 .55
+@item @strong{Flag-Wert} @tab @strong{Flag-Bedeutung}
+@item @code{NOT_NULL_FLAG} @tab Feld darf nicht @code{NULL} sein
+@item @code{PRI_KEY_FLAG} @tab Feld ist Teil eines Primärschlüssels
+@item @code{UNIQUE_KEY_FLAG} @tab Feld ist Teil eines eindeutigen Schlüssels
+@item @code{MULTIPLE_KEY_FLAG} @tab Feld ist Teil eines nicht eindeutigen Schlüssels
+@item @code{UNSIGNED_FLAG} @tab Feld hat das @code{UNSIGNED}-Attribute
+@item @code{ZEROFILL_FLAG} @tab Feld hat das @code{ZEROFILL}-Attribute
+@item @code{BINARY_FLAG} @tab Feld hat das @code{BINARY}-Attribute
+@item @code{AUTO_INCREMENT_FLAG} @tab Feld hat das @code{AUTO_INCREMENT}-Attribut
+@item @code{ENUM_FLAG} @tab Feld ist ein @code{ENUM} (veraltet)
+@item @code{BLOB_FLAG} @tab Feld ist ein @code{BLOB} oder @code{TEXT} (veraltet)
+@item @code{TIMESTAMP_FLAG} @tab Feld ist ein @code{TIMESTAMP} (veraltet)
+@end multitable
+
+Die Benutzung der @code{BLOB_FLAG}-, @code{ENUM_FLAG}- und
+@code{TIMESTAMP_FLAG}-Flags ist veraltet, weil sie den Feldtyp statt eines
+Attributs seines Typs angeben. Statt dessen sollten Sie @code{field->type}
+gegen @code{FIELD_TYPE_BLOB}, @code{FIELD_TYPE_ENUM} oder
+@code{FIELD_TYPE_TIMESTAMP} testen.
+
+@noindent
+Das unten stehende Beispiel zeigt eine typische Benutzung des
+@code{flags}-Werts:
+
+@example
+if (field->flags & NOT_NULL_FLAG)
+ printf("Feld darf nicht NULL sein\n");
+@end example
+
+Sie können aus Bequemlichkeitsgründen folgende Makros benutzen, um den
+Bool'schen Status des @code{flags}-Werts zu bestimmen:
+
+@multitable @columnfractions .3 .5
+@item @code{IS_NOT_NULL(flags)} @tab WAHR, wenn der Feldwert als @code{NOT NULL} definiert ist
+@item @code{IS_PRI_KEY(flags)} @tab WAHR, wenn der Feldwert ein Primärschlüssel ist
+@item @code{IS_BLOB(flags)} @tab WAHR, wenn der Feldwert ein @code{BLOB} oder @code{TEXT} ist (veraltet; testen Sie statt dessen @code{field->type})
+@end multitable
+
+@item unsigned int decimals
+Die Anzahl von Dezimalstellen für numerische Felder.
+@end table
+
+
+@node C API function overview, C API functions, C API datatypes, C
+@c German node C-API-Funktionsüberblick
+@subsection C-API-Funktionsüberblick
+
+@cindex C-API, Funktionen
+@cindex Funktionen, C-API
+
+Die in der C-API verfügbaren Funktionen sind unten aufgeführt und im
+nächsten Abschnitt detaillierter beschrieben.
+@xref{C API functions}.
+
+@multitable @columnfractions .3 .7
+@item @strong{mysql_affected_rows()} @tab
+Gibt die Anzahl von Zeilen zurück, die durch die letzte @code{UPDATE}-,
+@code{DELETE}- oder @code{INSERT}-Anfrage geändert, gelöscht bzw.
+hinzugefügt wurden.
+
+@item @strong{mysql_close()} @tab
+Schließt eine Server-Verbindung.
+
+@item @strong{mysql_connect()} @tab
+Stellt die Verbindung mit einem MySQL-Server her. Diese Funktion ist
+veraltet, benutzen Sie statt dessen @code{mysql_real_connect()}.
+
+@item @strong{mysql_change_user()} @tab
+Ändert Benutzer und Datenbank bei einer geöffneten Verbindung.
+
+@item @strong{mysql_character_set_name()} @tab
+Gibt den Namen des vorgabemäßigen Zeichensatzes für die Verbindung zurück.
+
+@item @strong{mysql_create_db()} @tab
+Erzeugt eine Datenbank. Diese Funktion ist veraltet, benutzen Sie statt
+dessen den SQL-Befehl @code{CREATE DATABASE}.
+
+@item @strong{mysql_data_seek()} @tab
+Sucht bis zu einer beliebigen Zeile in einer Anfrage-Ergebnismenge.
+
+@item @strong{mysql_debug()} @tab
+Macht ein @code{DBUG_PUSH} mit der angegebenen Zeichenkette.
+
+@item @strong{mysql_drop_db()} @tab
+Löscht eine Datenbank. Diese Funktion ist veraltet, benutzen Sie statt
+dessen den SQL-Befehl @code{DROP DATABASE}.
+
+@item @strong{mysql_dump_debug_info()} @tab
+Veranlasst den Server, Debug-Informationen in die Log-Datei zu schreiben.
+
+@item @strong{mysql_eof()} @tab
+Stellt fest, ob die letzte Zeile der Ergebnismenge gelesen wurde oder
+nicht. Diese Funktion ist veraltet, benutzen Sie statt dessen
+@code{mysql_errno()} oder @code{mysql_error()}.
+
+@item @strong{mysql_errno()} @tab
+Gibt die Fehlernummer der zuletzt aufgerufenen MySQL-Funktion zurück.
+
+@item @strong{mysql_error()} @tab
+Gibt die Fehlermeldung der zuletzt aufgerufenen MySQL-Funktion zurück.
+
+@item @strong{mysql_real_escape_string()} @tab
+Escapet Sonderzeichen in einer Zeichenkette, die für ein SQL-Statement
+benutzt wird, wobei der aktuelle Zeichensatz der Verbindung berücksichtigt
+wird.
+
+@item @strong{mysql_escape_string()} @tab
+Escapet Sonderzeichen in einer Zeichenkette, die für ein SQL-Statement
+benutzt wird.
+
+@item @strong{mysql_fetch_field()} @tab
+Gibt den Typ des nächsten Tabellenfelds zurück.
+
+@item @strong{mysql_fetch_field_direct()} @tab
+Gibt den Typ eines Tabellenfelds zurück, angegeben durch eine Feldnummer.
+
+@item @strong{mysql_fetch_fields()} @tab
+Gibt ein Array aller Feldstrukturen zurück.
+
+@item @strong{mysql_fetch_lengths()} @tab
+Gibt die Länge aller Spalten in der aktuellen Zeile zurück.
+
+@item @strong{mysql_fetch_row()} @tab
+Holt die nächste Zeile aus der Ergebnismenge.
+
+@item @strong{mysql_field_seek()} @tab
+Setzt den Spaltencursor auf eine bestimmte Spalte.
+
+@item @strong{mysql_field_count()} @tab
+Gibt die Anzahl der Ergebnisspalten für die letzte Anfrage zurück.
+
+@item @strong{mysql_field_tell()} @tab
+Gibt die Position des Feldcursors zurück, der für das letzte
+@code{mysql_fetch_field()} benutzt wurde.
+
+@item @strong{mysql_free_result()} @tab
+Gibt Speicher frei, der von einer Ergebnismenge benutzt wird.
+
+@item @strong{mysql_get_client_info()} @tab
+Gibt Client-Versionsinformationen zurück.
+
+@item @strong{mysql_get_host_info()} @tab
+Gibt eine Zeichenkette zurück, die die Verbindung beschreibt.
+
+@item @strong{mysql_get_proto_info()} @tab
+Gibt die Protokollversion zruück, die von der Verbindung benutzt wird.
+
+@item @strong{mysql_get_server_info()} @tab
+Gibt die Server-Versionsnummer zurück.
+
+@item @strong{mysql_info()} @tab
+Gibt Informationen über die zuletzt ausgeführte Anfrage zurück.
+
+@item @strong{mysql_init()} @tab
+Holt oder initialisiert eine @code{MYSQL}-Struktur.
+
+@item @strong{mysql_insert_id()} @tab
+Gibt die Kennung zurück, die für eine @code{AUTO_INCREMENT}-Spalte durch
+die letzte Anfrage erzeugt wurde.
+
+@item @strong{mysql_kill()} @tab
+Tötet einen angegebenen Thread.
+
+@item @strong{mysql_list_dbs()} @tab
+Gibt die Datenbanknamen zurück, die mit einem einfachen regulären Ausdruck
+übereinstimmen.
+
+@item @strong{mysql_list_fields()} @tab
+Gibt die Feldnamen zurück, die mit einem einfachen regulären Ausdruck
+übereinstimmen.
+
+@item @strong{mysql_list_processes()} @tab
+Gibt eine Liste der aktuellen Server-Threads zurück.
+
+@item @strong{mysql_list_tables()} @tab
+Gibt Tabellenamen zurück, die mit einem einfachen regulären Ausdruck
+übereinstimmen.
+
+@item @strong{mysql_num_fields()} @tab
+Gibt die Anzahl von Spalten in einer Ergebnismenge zurück.
+
+@item @strong{mysql_num_rows()} @tab
+Gibt die Anzahl von Zeilen in einer Ergebnismenge zurück.
+
+@item @strong{mysql_options()} @tab
+Setzt Verbindungsoptionen für @code{mysql_connect()}.
+
+@item @strong{mysql_ping()} @tab
+Prüft, ob die Verbindung zum Server funktioniert oder nicht und verbindet
+sich erneut, falls notwendig.
+
+@item @strong{mysql_Anfrage()} @tab
+Führt eine SQL-Anfrage aus, die als NULL-begrenzte Zeichenkette angegeben
+wird.
+
+@item @strong{mysql_real_connect()} @tab
+Verbindet sich mit einem MySQL-Server.
+
+@item @strong{mysql_real_query()} @tab
+Führt eine SQL-Anfrage aus, die als gezählte Zeichenkette angegeben wird.
+
+@item @strong{mysql_reload()} @tab
+Weist den Server an, die Berechtigungstabellen erneut zu laden.
+
+@item @strong{mysql_row_seek()} @tab
+Sucht bis zu einer Zeile in einer Ergebnismenge, indem sie den Wert
+benutzt, der von @code{mysql_row_tell()} zurückgegeben wird.
+
+@item @strong{mysql_row_tell()} @tab
+Gibt die Zeilencursorposition zurück.
+
+@item @strong{mysql_select_db()} @tab
+Wählt eine Datenbank aus.
+
+@item @strong{mysql_shutdown()} @tab
+Fährt den Datenbankserver herunter.
+
+@item @strong{mysql_stat()} @tab
+Gibt den Serverstatus als Zeichenkette zurück.
+
+@item @strong{mysql_store_result()} @tab
+Ruft eine komplette Ergebnismenge zum Client ab.
+
+@item @strong{mysql_thread_id()} @tab
+Gibt die aktuelle Thread-Kennung zurück.
+
+@item @strong{mysql_thread_safe()} @tab
+Gibt 1 zurück, wenn die Clients Thread-sicher kompiliert sind.
+
+@item @strong{mysql_use_result()} @tab
+Initialisiert den zeilenweisen Abruf einer Ergebnismenge.
+@end multitable
+
+Um sich mit dem Server zu verbinden, rufen Sie @code{mysql_init()} auf, um
+einen Verbindungs-Handler zu initialisieren. Rufen Sie dann
+@code{mysql_real_connect()} mit diesem Handler auf (mit Informationen wie
+Hostname, Benutzername und Passwort). Beim Verbinden setzt
+@code{mysql_real_connect()} den @code{reconnect}-Flag (Teil der
+MYSQL-Struktur) auf einen Wert von @code{1}. Dieser Flag legt bei einer
+Anfrage, die wegen einer verloren gegangenen Serververbindung nicht
+ausgeführt werden kann, fest, dass ein erneutes Verbinden versucht wird,
+bevor aufgegeben wird. Wenn Sie mit der Verbindung fertig sind, rufen Sie
+@code{mysql_close()} auf, um sie zu beenden.
+
+Während eine Verbindung aktiv ist, kann der Client SQL-Anfragen an den
+Server schicken, indem er @code{mysql_query()} oder
+@code{mysql_real_query()} benutzt. Der Unterschied zwischen beiden ist,
+dass @code{mysql_query()} erwartet, dass die Anfrage als NULL-separierte
+Zeichenkette angegeben wird, während @code{mysql_real_query()} eine
+gezählte Zeichenkette erwartet. Wenn die Zeichenkette Binärdaten enthält
+(was NULL-Bytes beinhalten kann), müssen Sie @code{mysql_real_query()}
+benutzen.
+
+Bei jeder Nicht-@code{SELECT}-Anfrage (wie @code{INSERT}, @code{UPDATE},
+@code{DELETE}) finden Sie heraus, wie viele Zeilen geändert (betroffen)
+wurden, indem Sie @code{mysql_affected_rows()} aufrufen.
+
+Bei @code{SELECT}-Anfragen rufen Sie die ausgewählten Zeilen als
+Ergebnismenge ab. (Beachten Sie, dass einige Statements ähnlich wie
+@code{SELECT} sind, weil auch sie Zeilen zurückgeben. Das sind @code{SHOW},
+@code{DESCRIBE} und @code{EXPLAIN}. Sie werden auf dieselbe Weise behandelt
+wie @code{SELECT}-Statements.)
+
+Es gibt für einen Client zwei Möglichkeiten, Ergebnismengen zu verarbeiten.
+Eine Möglichkeit besteht darin, die gesamte Ergebnismenge auf einmal
+abzurufen, indem @code{mysql_store_result()} aufgerufen wird. Diese
+Funktion holt alle Zeilen vom Server ab, die von der Anfrage zurückgegeben
+werden, und speichert sie im Client. Die zweite Möglichkeit besteht darin,
+dass der Client die Ergebnismenge zeilenweise abruft, indem er
+@code{mysql_use_result()} aufruft. Diese Funktion initialisiert den Abruf,
+holt aber keinerlei Zeilen vom Server ab.
+
+In beiden Fällen können Sie auf Zeilen zugreifen, indem Sie
+@code{mysql_fetch_row()} aufrufen. Bei @code{mysql_store_result()} greift
+@code{mysql_fetch_row()} auf Zeilen zurück, die bereits vom Server geholt
+wurden. Bei @code{mysql_use_result()} ruft @code{mysql_fetch_row()} die
+Zeilen direkt vom Server ab. Informationen über die Größe der Daten in
+jeder Zeile sind durch Aufruf von @code{mysql_fetch_lengths()} verfügbar.
+
+Wenn Sie mit einer Ergebnismenge fertig sind, rufen Sie
+@code{mysql_free_result()} auf, um den hierfür benutzten Speicher
+freizugeben.
+
+Die beiden Abrufmechanismen sind komplementär. Client-Programme sollten
+entscheiden, welcher Ansatz der für ihre Erfordernisse geeignetste ist. In
+der Praxis wird für Clients häufiger @code{mysql_store_result()} verwendet.
+
+Ein Vorteil von @code{mysql_store_result()} ist, dass bereits alle Zeilen
+zum Client geholt wurden. Deshalb können Sie nicht nur sequentiell auf
+Zeilen zugreifen, sondern sich in der Ergebnismenge vorwärts und rückwärts
+bewegen, indem Sie @code{mysql_data_seek()} oder @code{mysql_row_seek()}
+benutzen, um die aktuelle Position innerhalb der Ergebnismenge zu ändern.
+Sie können auch herausfinden, wie viele Zeilen es gibt, indem Sie
+@code{mysql_num_rows()} aufrufen. Auf der anderen Seite kann der
+Speicherbedarf für @code{mysql_store_result()} sehr hoch sein, wenn Sie
+große Ergebnismengen abrufen, so dass Speichermangel eintreten kann.
+
+Ein Vorteil von @code{mysql_use_result()} ist, dass der Client weniger
+Arbeitsspeicher für die Ergebnismenge benötigt, weil er nur eine Zeile
+zugleich erhält (und weil weniger Zuweisungs-Overhead da ist, kann
+@code{mysql_use_result()} schneller sein). Die Nachteile liegen darin, dass
+Sie jede Zeile schnell verarbeiten müssen, um zu vermeiden, den Server zu
+blockieren. Ausserdem haben Sie keinen wahlfreien (random) Zugriff auf die
+Zeilen innerhalb einer Ergebnismenge (Sie können auf die Zeilen nur
+sequentiell zugreifen), und Sie wissen nicht, wie viele Zeilen sich in der
+Ergebnismenge befinden, bis Sie sie alle abgerufen haben. Darüber hinaus
+@emph{müssen} Sie alle Zeilen abrufen, selbst wenn Sie während des Abrufs
+feststellen, dass Sie die Information gefunden haben, nach der Sie suchen.
+
+Die API ermöglicht Clients, auf die Anfragen entsprechend zu antworten
+(Zeilen nur wenn nötig abzurufen), ohne zu wissen, ob die Anfragen ein
+@code{SELECT} ist oder nicht. Das erreichen Sie durch Aufruf von
+@code{mysql_store_result()} nach jedem @code{mysql_query()} (oder
+@code{mysql_real_query()}). Wenn der Ergebnismengenaufruf erfolgreich ist,
+war die Anfrage ein @code{SELECT} und Sie können die Zeilen lesen. Wenn der
+Ergebnismengenaufruf fehlschlägt, rufen Sie @code{mysql_field_count()} auf,
+um festzustellen, ob ein Ergebnis erwartet wurde oder nicht. Wenn
+@code{mysql_field_count()} 0 zurückgibt, gab die Anfrage keine Daten zurück
+(was anzeigt, dass sie kein @code{INSERT}, @code{UPDATE}, @code{DELETE}
+usw. war), und es wurde nicht erwartet, dass sie Zeilen zurückgibt. Wenn
+@code{mysql_field_count()} ungleich 0 ist, sollte die Anfrage Zeilen
+zurückgegeben haben, tat das aber nicht. Das zeigt an, dass die Anfrage ein
+@code{SELECT} war, das fehlschlug. Sehen Sie in der Beschreibung von
+@code{mysql_field_count()} wegen eines Beispiels nach, wie das gemacht
+wird.
+
+Sowohl @code{mysql_store_result()} als auch @code{mysql_use_result()}
+gestatten Ihnen, Informationen über die Felder zu erlangen, aus denen die
+Ergebnismenge besteht (die Anzahl der Felder, ihre Namen, Typen usw.). Sie
+können sequentiell auf Feldinformationen innerhalb der Zeile zugreifen,
+indem Sie @code{mysql_fetch_field()} wiederholt aufrufen, oder direkt auf
+die Feldnummer innerhalb einer Zeile durch Aufruf von
+@code{mysql_fetch_field_direct()}. Die aktuelle Feldcursorposition kann
+durch den Aufruf von @code{mysql_field_seek()} geändert werden. Wenn Sie
+den Feldcursor setzen, betrifft das nachfolgende Aufrufe von
+@code{mysql_fetch_field()}. Sie erhalten alle Feldinformationen auf einmal,
+wenn Sie @code{mysql_fetch_fields()} aufrufen.
+
+Um Fehler zu erkennen und zu berichten, stellt MySQL den Zugriff auf
+Fehlerinformationen durch die @code{mysql_errno()}- und
+@code{mysql_error()}-Funktionen zur Verfügung. Diese geben den Fehlercode
+oder die Fehlermeldung für die zuletzt aufgerufenen Funktionen zur
+Verfügung, die erfolgreich sein oder fehlschlagen können, so dass Sie
+feststellen können, wann ein Fehler auftrat und welcher es war.
+
+
+@node C API functions, C Thread functions, C API function overview, C
+@c German node C-API-Funktionen
+@subsection C-API-Funktionsbeschreibungen
+
+
+In den unten stehenden Beschreibungen bedeutet ein Parameter oder
+Rückgabewert von @code{NULL} @code{NULL} im Sinne der
+C-Programmier-Sprache, nicht einen MySQL-@code{NULL}-Wert.
+
+Funktionen, die einen Wert zurückgeben, geben allgemein einen Zeiger oder
+eine Ganzzahl zurück. Falls nicht anders angegeben geben Funktionen, die
+einen Zeiger zurückgeben, einen Nicht-@code{NULL}-Wert zurück, um Erfolg
+anzuzeigen, oder einen @code{NULL}-Wert, um einen Fehler anzuzeigen.
+Funktionen, die eine Ganzzahl zurückgeben, geben 0 zurück, um Erfolg
+anzuzeigen, und Nicht-0, um einen Fehler anzuzeigen. Beachten Sie, dass
+``Nicht-0'' genau das bedeutet. Wenn die Funktionsbeschreibung nichts
+anderes aussagt, testen Sie nicht gegen einen anderen Wert als 0:
+
+@example
+if (ergebnis) /* korrekt */
+ ... FEHLER ...
+
+if (ergebnis < 0) /* nicht korrekt */
+ ... FEHLER ...
+
+if (ergebnis == -1) /* nicht korrekt */
+ ... FEHLER ...
+@end example
+
+Wenn eine Funktion einen Fehler zurückgibt, listet der Unterabschnitt
+@strong{Errors} der Funktionsbeschreibung die möglichen Fehlertypen auf.
+Sie finden heraus, welcher davon auftrat, indem Sie @code{mysql_errno()}
+aufrufen. Eine Zeichenketten-Darstellung des Fehler kann durch Aufruf von
+@code{mysql_error()} erlangt werden.
+
+
+@menu
+* mysql_affected_rows::
+* mysql_close::
+* mysql_connect::
+* mysql_change_user::
+* mysql_character_set_name::
+* mysql_create_db::
+* mysql_data_seek::
+* mysql_debug::
+* mysql_drop_db::
+* mysql_dump_debug_info::
+* mysql_eof::
+* mysql_errno::
+* mysql_error::
+* mysql_escape_string::
+* mysql_fetch_field::
+* mysql_fetch_fields::
+* mysql_fetch_field_direct::
+* mysql_fetch_lengths::
+* mysql_fetch_row::
+* mysql_field_count::
+* mysql_field_seek::
+* mysql_field_tell::
+* mysql_free_result::
+* mysql_get_client_info::
+* mysql_get_host_info::
+* mysql_get_proto_info::
+* mysql_get_server_info::
+* mysql_info::
+* mysql_init::
+* mysql_insert_id::
+* mysql_kill::
+* mysql_list_dbs::
+* mysql_list_fields::
+* mysql_list_processes::
+* mysql_list_tables::
+* mysql_num_fields::
+* mysql_num_rows::
+* mysql_options::
+* mysql_ping::
+* mysql_query::
+* mysql_real_connect::
+* mysql_real_escape_string::
+* mysql_real_query::
+* mysql_reload::
+* mysql_row_seek::
+* mysql_row_tell::
+* mysql_select_db::
+* mysql_shutdown::
+* mysql_stat::
+* mysql_store_result::
+* mysql_thread_id::
+* mysql_use_result::
+@end menu
+
+@node mysql_affected_rows, mysql_close, C API functions, C API functions
+@c German node mysql_affected_rows
+@subsubsection @code{mysql_affected_rows()}
+
+@findex @code{mysql_affected_rows()}
+
+@code{my_ulonglong mysql_affected_rows(MYSQL *mysql)}
+
+@subsubheading Beschreibung
+
+Gibt die Anzahl von Zeilen zurück, die durch das letzte @code{UPDATE}
+geändert, durch das letzte @code{DELETE} gelöscht oder durch das letzte
+@code{INSERT} eingefügt wurden. Kann direkt nach @code{mysql_query()}
+aufgerufen werden, bei @code{UPDATE}-, @code{DELETE}- oder
+@code{INSERT}-Statements. Bei @code{SELECT}-Statements funktioniert
+@code{mysql_affected_rows()} wie @code{mysql_num_rows()}.
+
+@subsubheading Rückgabewerte
+
+Eine Ganzzahl größer als 0 gibt die Anzahl von Zeilen an, die betroffen
+oder abgerufen wurden. 0 gibt an, dass keine Datensätze bei einem
+@code{UPDATE}-Statement geändert wurden, keine Zeilen der
+@code{WHERE}-Klausel in der Anfrage entsprachen oder dass bislang keine
+Anfrage ausgeführt wurde. -1 gibt an, dass die Anfrage einen Fehler
+zurückgab oder dass - bei einer @code{SELECT}-Anfrage -
+@code{mysql_affected_rows()} vor @code{mysql_store_result()} aufgerufen
+wurde.
+
+@subsubheading Fehler
+
+Keine.
+
+@subsubheading Beispiel
+
+@example
+mysql_query(&mysql,"UPDATE produkte SET kosten=kosten*1.25 WHERE gruppe=10");
+printf("%ld produkte updated",(long) mysql_affected_rows(&mysql));
+@end example
+
+Wenn man den Flag @code{CLIENT_FOUND_ROWS} angibt, wenn man sich mit
+@code{mysqld} verbindet, gibt @code{mysql_affected_rows()} die Anzahl von
+Zeilen zurück, die mit dem @code{WHERE}-Statement bei
+@code{UPDATE}-Statements übereinstimmten.
+
+Beachten Sie bei der Benutzung des @code{REPLACE}-Befehls, dass
+@code{mysql_affected_rows()} 2 zurückgibt, wenn die neue Zeile eine alte
+Zeile ersetzte. Das liegt daran, dass in diesem Fall eine neue Zeile
+eingefügt und dann das alte Duplikat gelöscht wurde.
+
+
+@node mysql_close, mysql_connect, mysql_affected_rows, C API functions
+@c German node mysql_close
+@subsubsection @code{mysql_close()}
+
+@findex @code{mysql_close()}
+
+@code{void mysql_close(MYSQL *mysql)}
+
+@subsubheading Beschreibung
+Schließt eine vorher geöffnete Verbindung. @code{mysql_close()} gibt auch
+den Verbindungs-Handle frei, der von @code{mysql} zugewiesen wurde, wenn
+der Handle automatisch mit @code{mysql_init()} oder @code{mysql_connect()}
+zugewiesen wurde.
+
+@subsubheading Rückgabewerte
+
+Keine.
+
+@subsubheading Fehler
+
+Keine.
+
+
+@node mysql_connect, mysql_change_user, mysql_close, C API functions
+@c German node mysql_connect
+@subsubsection @code{mysql_connect()}
+
+@findex @code{mysql_connect()}
+
+@code{MYSQL *mysql_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd)}
+
+@subsubheading Beschreibung
+
+Diese Funktion ist veraltet. Sie sollten statt dessen
+@code{mysql_real_connect()} benutzen.
+
+@code{mysql_connect()} versucht, eine Verbindung zu einer
+MySQL-Datenbankmaschine aufzubauen, die auf @code{host} läuft.
+@code{mysql_connect()} muss erfolgreich beendet werden, bevor Sie irgend
+welche weiteren API-Funktionen aufrufen können, mit Ausnahme von
+@code{mysql_get_client_info()}.
+
+Die Bedeutung der Parameter ist dieselbe wie die entsprechenden Parameter
+bei @code{mysql_real_connect()}, mit dem Unterschied, dass die
+Verbindungsparameter @code{NULL} sein dürfen. In diesem Fall weist die
+C-API automatisch Speicher für die Verbindungsstruktur zu und gibt diesen
+frei, wenn Sie @code{mysql_close()} aufrufen. Der Nachteil dieses Ansatzes
+besteht darin, dass Sie keine Fehlermeldung abrufen können, wenn die
+Verbindung fehlschlägt. (Um Fehlerinformationen von @code{mysql_errno()}
+oder @code{mysql_error()} abrufen zu können, müssen Sie einen gültigen
+@code{MYSQL}-Zeiger angeben.)
+
+@subsubheading Rückgabewerte
+
+Dieselben wie für @code{mysql_real_connect()}.
+
+@subsubheading Fehler
+
+Dieselben wie für @code{mysql_real_connect()}.
+
+
+@node mysql_change_user, mysql_character_set_name, mysql_connect, C API functions
+@c German node mysql_change_user
+@subsubsection @code{mysql_change_user()}
+
+@findex @code{mysql_change_user()}
+
+@code{my_bool mysql_change_user(MYSQL *mysql, const char *user, const
+char *password, const char *db)}
+
+@subsubheading Beschreibung
+
+Ändert den Benutzer und veranlasst, dass die Datenbank, die mit @code{db}
+angegeben wurde, die vorgabemäßige (aktuelle) Datenbank für die Verbindung
+wird, die durch @code{mysql} festgelegt wurde. In nachfolgenden Anfragen
+ist diese Datenbank die Vorgabe für Tabellenverweise, bei denen nicht
+explizit eine Datenbank angegeben wird.
+
+Diese Funktion wurde in MySQL-Version 3.23.3 eingeführt.
+
+@code{mysql_change_user()} schlägt fehl, wenn sich der Benutzer nicht
+authentifizieren kann oder wenn er keine Zugriffsrechte auf die Datenbank
+hat. In diesem Fall werden Benutzer und Datenbank nicht geändert.
+
+Der @code{db}-Parameter kann auf @code{NULL} gesetzt werden, wenn Sie keine
+vorgabemäßige Datenbank haben wollen.
+
+@subsubheading Rückgabewerte
+
+0 für Erfolg. Nicht-0, wenn ein Fehler auftrat.
+
+@subsubheading Fehler
+
+Dieselben, die Sie von @code{mysql_real_connect()} erhalten.
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Befehle wurde in nicht korrekter Reihenfolge ausgeführt.
+@item CR_SERVER_GONE_ERROR
+Der MySQL-Server ist weg.
+@item CR_SERVER_LOST
+Die Verbindung zum Server ging während der Anfrage verloren.
+@item CR_UNKNOWN_ERROR
+Ein unbekannter Fehler ist aufgetreten.
+@item ER_UNKNOWN_COM_ERROR
+Der MySQL-Server hat diesen Befehl nicht implementiert (wahrscheinlich ein
+alter Server).
+@item ER_ACCESS_DENIED_ERROR
+Benutzername oder Passwort sind falsch.
+@item ER_BAD_DB_ERROR
+Die Datenbank existiert nicht.
+@item ER_DBACCESS_DENIED_ERROR
+Der Benutzer hat keine Zugriffsrechte auf die Datenbank.
+@item ER_WRONG_DB_NAME
+Der Datenbankname war zu lang.
+@end table
+
+@subsubheading Beispiel
+
+@example
+if (mysql_change_user(&mysql, "benutzer", "passwort", "neue_datenbank"))
+@{
+ fprintf(stderr, "Änderung des Benutzers fehlgeschlagen. Fehler: %s\n",
+ mysql_error(&mysql));
+@}
+@end example
+
+
+@node mysql_character_set_name, mysql_create_db, mysql_change_user, C API functions
+@c German node mysql_character_set_name
+@subsubsection @code{mysql_character_set_name()}
+
+@findex @code{mysql_character_set_name()}
+
+@code{const char *mysql_character_set_name(MYSQL *mysql)}
+
+@subsubheading Beschreibung
+
+Gibt den vorgabemäßigen Zeichensatz für die aktuelle Verbindung zurück.
+
+@subsubheading Rückgabewerte
+
+Der vorgabemäßige Zeichensatz
+
+@subsubheading Fehler
+
+Keine.
+
+
+@node mysql_create_db, mysql_data_seek, mysql_character_set_name, C API functions
+@c German node mysql_create_db
+@subsubsection @code{mysql_create_db()}
+
+@findex @code{mysql_create_db()}
+
+@code{int mysql_create_db(MYSQL *mysql, const char *db)}
+
+@subsubheading Beschreibung
+Erzeugt die Datenbank, die durch den @code{db}-Parameter angegeben wird.
+
+Diese Funktion ist veraltet. Vorzugsweise sollten Sie @code{mysql_query()}
+benutzen, um statt dessen ein SQL-@code{CREATE DATABASE}-Statement
+abzusetzen.
+
+@subsubheading Rückgabewerte
+
+0, wenn die Datenbank erfolgreich erzeugt wurde. Nicht-0, wenn ein Fehler
+auftrat.
+
+@subsubheading Fehler
+@table @code
+
+@item CR_COMMANDS_OUT_OF_SYNC
+Befehle wurden in nicht korrekter Reihenfolge ausgeführt.
+
+@item CR_SERVER_GONE_ERROR
+Der MySQL-Server ist weg.
+
+@item CR_SERVER_LOST
+Die Verbindung zum Server ging während der Anfrage verloren.
+
+@item CR_UNKNOWN_ERROR
+Ein unbekannter Fehler trat auf.
+@end table
+
+@subsubheading Beispiel
+
+@example
+if(mysql_create_db(&mysql, "meine_datenbank"))
+@{
+ fprintf(stderr, "Erzeugung der neuen Datenbank fehlgeschlagen. Fehler: %s\n",
+ mysql_error(&mysql));
+@}
+@end example
+
+
+@node mysql_data_seek, mysql_debug, mysql_create_db, C API functions
+@c German node mysql_data_seek
+@subsubsection @code{mysql_data_seek()}
+
+@findex @code{mysql_data_seek()}
+
+@code{void mysql_data_seek(MYSQL_RES *result, unsigned long long offset)}
+
+@subsubheading Beschreibung
+Sucht bis zu einer beliebigen Zeile in einer Anfrageergebnismenge. Das
+setzt voraus, dass die Ergebnismengenstruktur das gesamte Anfrageergebnis
+enthält. Daher kann @code{mysql_data_seek()} nur in Verbindung mit
+@code{mysql_store_result()} benutzt werden, nicht in Verbindung mit
+@code{mysql_use_result()}.
+
+Der Offset sollte ein Wert im Bereich von 0 bis
+@code{mysql_num_rows(ergebnis)-1} sein.
+
+@subsubheading Rückgabewerte
+
+Keine.
+
+@subsubheading Fehler
+
+Keine.
+
+
+@node mysql_debug, mysql_drop_db, mysql_data_seek, C API functions
+@c German node mysql_debug
+@subsubsection @code{mysql_debug()}
+
+@findex @code{mysql_debug()}
+
+@code{void mysql_debug(char *debug)}
+
+@subsubheading Beschreibung
+Führt ein @code{DBUG_PUSH} mit der angegebenen Zeichenkette durch.
+@code{mysql_debug()} benutzt die Debug-Bibliothek von Fred Fish. Um diese
+Funktion benutzen zu können, müssen Sie die Client-Bibliothek so
+kompilieren, dass sie Debuggen unterstützt. @xref{Debugging server}.
+@xref{Debugging client}.
+
+@subsubheading Rückgabewerte
+
+Keine.
+
+@subsubheading Fehler
+
+Keine.
+
+@subsubheading Beispiel
+
+Der unten stehende Aufruf führt dazu, dass die Client-Bibliothek eine
+Trace-Datei in @file{/tmp/client.trace} auf der Client-Maschine erzeugt:
+
+@example
+mysql_debug("d:t:O,/tmp/client.trace");
+@end example
+
+
+@node mysql_drop_db, mysql_dump_debug_info, mysql_debug, C API functions
+@c German node mysql_drop_db
+@subsubsection @code{mysql_drop_db()}
+
+@findex @code{mysql_drop_db()}
+
+@code{int mysql_drop_db(MYSQL *mysql, const char *db)}
+
+@subsubheading Beschreibung
+Löscht die Datenbank, die durch den @code{db}-Parameter angegeben wird.
+
+Diese Funktion ist veraltet. Benutzen Sie vorzugsweise
+@code{mysql_query()}, um statt dessen ein SQL-@code{DROP
+DATABASE}-Statement abzusetzen.
+
+@subsubheading Rückgabewerte
+
+0, wenn die Datenbank erfolgreich gelöscht wurde. Nicht-0, wenn ein Fehler
+auftrat.
+
+@subsubheading Fehler
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Befehle wurden nicht in der korrekten Reihenfolge ausgeführt.
+@item CR_SERVER_GONE_ERROR
+Der MySQL-Server ist weg.
+@item CR_SERVER_LOST
+Die Verbindung zum Server ging während der Anfrage verloren.
+@item CR_UNKNOWN_ERROR
+Ein unbekannter Fehler trat auf.
+@end table
+
+@subsubheading Beispiel
+
+@example
+if(mysql_drop_db(&mysql, "meine_datenbank"))
+ fprintf(stderr, "Löschen der Datenbank fehlgeschlagen: Fehler: %s\n",
+ mysql_error(&mysql));
+@end example
+
+
+@node mysql_dump_debug_info, mysql_eof, mysql_drop_db, C API functions
+@c German node mysql_dump_debug_info
+@subsubsection @code{mysql_dump_debug_info()}
+
+@findex @code{mysql_dump_debug_info()}
+
+@code{int mysql_dump_debug_info(MYSQL *mysql)}
+
+@subsubheading Beschreibung
+
+Weist den Server an, Debug-Informationen ins Log zu schreiben. Damit das
+funktioniert, muss der verbundene Benutzer die
+@strong{process}-Berechtigung haben.
+
+@subsubheading Rückgabewerte
+
+0, wenn der Befehl erfolgreich war. Nicht-0, wenn ein Fehler auftrat.
+
+@subsubheading Fehler
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Befehle wurden nicht in der korrekten Reihenfolge ausgeführt.
+@item CR_SERVER_GONE_ERROR
+Der MySQL-Server ist weg.
+@item CR_SERVER_LOST
+Die Verbindung zum Server ging während der Anfrage verloren.
+@item CR_UNKNOWN_ERROR
+Ein unbekannter Fehler trat auf.
+@end table
+
+
+@node mysql_eof, mysql_errno, mysql_dump_debug_info, C API functions
+@c German node mysql_eof
+@subsubsection @code{mysql_eof()}
+
+@findex @code{mysql_eof()}
+
+@code{my_bool mysql_eof(MYSQL_RES *result)}
+
+@subsubheading Beschreibung
+
+Diese Funktion ist veraltet. Benutzen Sie statt dessen @code{mysql_errno()}
+oder @code{mysql_error()}.
+
+@code{mysql_eof()} stellt fest, ob die letzte Zeile einer Ergebnismenge
+gelesen wurde oder nicht.
+
+Wenn Sie eine Ergebnismenge durch einen erfolgreichen Aufruf von
+@code{mysql_store_result()} erhalten, erhält der Client den gesamten Satz
+in einer Operation. In diesem Fall bedeutet eine @code{NULL}-Rückgabe von
+@code{mysql_fetch_row()} immer, dass das Ende der Ergebnismenge erreicht
+wurde und es unnötig ist, @code{mysql_eof()} aufzurufen.
+
+Wenn Sie auf der anderen Seite @code{mysql_use_result()} aufrufen, um den
+Abruf einer Ergebnismenge zu initialisieren, werden die Zeilen des Satzes
+Zeile für Zeile vom Server erlangt, indem Sie @code{mysql_fetch_row()}
+wiederholt aufrufen. Weil während dieses Prozesses ein Verbindungsfehler
+auftreten kann, bedeutet ein @code{NULL}-Rückgabewert von
+@code{mysql_fetch_row()} nicht notwendigerweise, dass das Ende der
+Ergebnismenge auf normale Weise erreicht wurde. In diesem Fall können Sie
+@code{mysql_eof()} benutzen, um festzustellen, was passiert ist.
+@code{mysql_eof()} gibt einen Nicht-0-Wert zurück, wenn das Ende der
+Ergebnismenge erreicht wurde, und 0, wenn ein Fehler auftrat.
+
+Historisch liegt @code{mysql_eof()} vor den Standard-MySQL-Fehlerfunktionen
+@code{mysql_errno()} und @code{mysql_error()}. Weil diese Fehlerfunktionen
+dieselben Informationen zur Verfügung stellen, wird ihre Benutzung des des
+veralteten @code{mysql_eof()} empfohlen. (Sie stellen in der Tat sogar mehr
+Informationen zur Verfügung, weil @code{mysql_eof()} nur einen Bool'schen
+Wert zurückgibt, während die Fehlerfunktionen den Grund angeben, warum der
+Fehler auftrat.)
+
+@subsubheading Rückgabewerte
+
+0, wenn kein Fehler auftrat. Nicht-0, wenn das Ende der Ergebnismenge
+erreicht wurde.
+
+@subsubheading Fehler
+
+Keine.
+
+@subsubheading Beispiel
+
+Folgendes Beispiel zeigt, wie Sie @code{mysql_eof()} benutzen können:
+
+@example
+mysql_query(&mysql,"SELECT * FROM tabelle");
+ergebnis = mysql_use_result(&mysql);
+while((zeile = mysql_fetch_row(ergebnis)))
+@{
+ // Daten verarbeiten usw.
+@}
+if(!mysql_eof(ergebnis)) // mysql_fetch_row() schlug wegen eines Fehlers fehl
+@{
+ fprintf(stderr, "Fehler: %s\n", mysql_error(&mysql));
+@}
+@end example
+
+Sie können denselben Effekt jedoch auch mit den
+Standard-MySQL-Fehlerfunktionen erreichen:
+
+@example
+mysql_query(&mysql,"SELECT * FROM tabelle");
+result = mysql_use_result(&mysql);
+while((zeile = mysql_fetch_row(ergebnis)))
+@{
+ // Daten verarbeiten usw.
+@}
+if(mysql_errno(&mysql)) // mysql_fetch_row() schlug wegen eines Fehlers fehl
+@{
+ fprintf(stderr, "Fehler: %s\n", mysql_error(&mysql));
+@}
+@end example
+
+
+@node mysql_errno, mysql_error, mysql_eof, C API functions
+@c German node mysql_errno
+@subsubsection @code{mysql_errno()}
+
+@findex @code{mysql_errno()}
+
+@code{unsigned int mysql_errno(MYSQL *mysql)}
+
+@subsubheading Beschreibung
+
+Für die von @code{mysql} angegebene Verbindung gibt @code{mysql_errno()}
+den Fehlercode für die zuletzt aufgerufene API-Funktion zurück, die
+erfolgreich sein oder fehlschlagen kann. Ein Rückgabewert von 0 bedeutet,
+dass kein Fehler auftrat. Client-Fehlermeldungsnummern sind in der
+MySQL-@file{errmsg.h}-Header-Datei aufgelistet.
+Server-Fehlermeldungsnummern sind in @file{mysqld_error.h} aufgelistet. In
+der MySQL-Quelldistribution finden Sie eine komplette Liste der
+Fehlermeldungen und Fehlernummern in der Datei
+@file{Docs/mysqld_error.txt}.
+
+@subsubheading Rückgabewerte
+
+Ein Fehlercode-Wert. 0, wenn kein Fehler auftrat.
+
+@subsubheading Fehler
+
+Keine.
+
+
+@node mysql_error, mysql_escape_string, mysql_errno, C API functions
+@c German node mysql_error
+@subsubsection @code{mysql_error()}
+
+@findex @code{mysql_error()}
+
+@code{char *mysql_error(MYSQL *mysql)}
+
+@subsubheading Beschreibung
+
+Für die von @code{mysql} angegebene Verbindung gibt @code{mysql_error()}
+die Fehlermeldung für die zuletzt aufgerufene API-Funktion zurück, die
+erfolgreich sein oder fehlschlagen kann. Eine leere Zeichenkette
+(@code{""}) wird zurückgegeben, wenn kein Fehler auftrat. Das bedeutet,
+dass folgende zwei Tests äquivalent sind:
+
+@example
+if(mysql_errno(&mysql))
+@{
+ // Ein Fehler trat auf
+@}
+
+if(mysql_error(&mysql)[0] != '\0')
+@{
+ // Ein Fehler trat auf
+@}
+@end example
+
+Die Sprache der Client-Fehlermeldungen kann durch erneutes Kompilieren der
+MySQL-Client-Bibliothek geändert werden. Sie können Fehlermeldungen in
+mehreren unterschiedlichen Sprachen auswählen. @xref{Languages}.
+
+@subsubheading Rückgabewerte
+
+Eine Zeichenkette, die den Fehler beschreibt. Eine leere Zeichenkette, wenn
+kein Fehler auftrat.
+
+@subsubheading Fehler
+
+Keine.
+
+
+@node mysql_escape_string, mysql_fetch_field, mysql_error, C API functions
+@c German node mysql_escape_string
+@subsubsection @code{mysql_escape_string()}
+
+@findex @code{mysql_escape_string()}
+
+Statt dessen sollten Sie @code{mysql_real_escape_string()} benutzen!
+
+Das ist identisch mit @code{mysql_real_escape_string()}, ausser dass die
+Verbindung als erstes Argument genommen wird.
+@code{mysql_real_escape_string()} escapet die Zeichenkette gemäß dem
+aktuellen Zeichensatz, wohingegen @code{mysql_escape_string()} die aktuelle
+Zeichensatzeinstellung ignoriert.
+
+
+@node mysql_fetch_field, mysql_fetch_fields, mysql_escape_string, C API functions
+@c German node mysql_fetch_field
+@subsubsection @code{mysql_fetch_field()}
+
+@findex @code{mysql_fetch_field()}
+
+@code{MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *result)}
+
+@subsubheading Beschreibung
+
+Gibt die Definition einer Spalte der Ergebnismenge als
+@code{MYSQL_FIELD}-Struktur zurück. Rufen Sie diese Funktion wiederholt
+auf, um Informationen über alle Spalten in der Ergebnismenge zu erhalten.
+@code{mysql_fetch_field()} gibt @code{NULL} zurück, wenn es keine weiteren
+Felder mehr gibt.
+
+@code{mysql_fetch_field()} wird zurückgesetzt, so dass sie Informationen
+über das erste Feld zurückgibt, und zwar jedes Mal, wenn Sie eine neue
+@code{SELECT}-Anfrage ausführen. Das von @code{mysql_fetch_field()}
+zurückgegebene Feld wird auch durch Aufrufe von @code{mysql_field_seek()}
+betroffen.
+
+Wenn Sie @code{mysql_query()} aufgerufen haben, um ein @code{SELECT} auf
+eine Tabelle auszuführen, aber nicht @code{mysql_store_result()} aufgerufen
+haben, gibt MySQL die vorgabemäßige BLOB-Länge (8 KB) zurück, wenn Sie
+@code{mysql_fetch_field()} aufrufen, um nach der Länge eines
+@code{BLOB}-Felds zu fragen. (Die Größe von 8 KB wird gewählt, weil MySQL
+die maximale Länge des @code{BLOB} nicht kennt. Das wird irgendwann einmal
+konfigurierbar gemacht.) Nachdem Sie die Ergebnismenge erst einmal
+abgerufen haben, enthält @code{field->max_length} die Länge des längsten
+Werts dieser Spalte in der bestimmten Anfrage.
+
+@subsubheading Rückgabewerte
+
+Die @code{MYSQL_FIELD}-Struktur der aktuellen Spalte. @code{NULL}, wenn
+keine Spalten mehr übrig sind.
+
+@subsubheading Fehler
+
+Keine.
+
+@subsubheading Beispiel
+
+@example
+MYSQL_FIELD *field;
+
+while((field = mysql_fetch_field(ergebnis)))
+@{
+ printf("Feldname %s\n", field->name);
+@}
+@end example
+
+
+@node mysql_fetch_fields, mysql_fetch_field_direct, mysql_fetch_field, C API functions
+@c German node mysql_fetch_fields
+@subsubsection @code{mysql_fetch_fields()}
+
+@findex @code{mysql_fetch_fields()}
+
+@code{MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *result)}
+
+@subsubheading Beschreibung
+
+Gibt ein Array aller @code{MYSQL_FIELD}-Strukturen für eine Ergebnismenge
+zurück. Jede Struktur stellt Felddefinitionen für eine Spalte der
+Ergebnismenge zur Verfügung.
+
+@subsubheading Rückgabewerte
+
+Ein Array von @code{MYSQL_FIELD}-Strukturen für alle Spalten einer
+Ergebnismenge.
+
+@subsubheading Fehler
+
+Keine.
+
+@subsubheading Beispiel
+
+@example
+unsigned int num_fields;
+unsigned int i;
+MYSQL_FIELD *fields;
+
+num_fields = mysql_num_fields(ergebnis);
+fields = mysql_fetch_fields(ergebnis);
+for(i = 0; i < num_fields; i++)
+@{
+ printf("Feld %u ist %s\n", i, fields[i].name);
+@}
+@end example
+
+
+@node mysql_fetch_field_direct, mysql_fetch_lengths, mysql_fetch_fields, C API functions
+@c German node mysql_fetch_field_direct
+@subsubsection @code{mysql_fetch_field_direct()}
+
+@findex @code{mysql_fetch_field_direct()}
+
+@code{MYSQL_FIELD *mysql_fetch_field_direct(MYSQL_RES *result, unsigned int feldnr)}
+
+@subsubheading Beschreibung
+
+Mit der Angabe einer Feldnummer @code{feldnr} für eine Spalte innerhalb
+einer Ergebnismenge gibt sie die Felddefinition dieser Spalte als
+@code{MYSQL_FIELD}-Struktur zurück. Sie können diese Funktion verwenden, um
+die Definition für eine beliebige Spalte abzurufen. Der Wert von
+@code{feldnr} sollte im Bereich von 0 bis
+@code{mysql_num_fields(ergebnis)-1} liegen.
+
+@subsubheading Rückgabewerte
+
+Die @code{MYSQL_FIELD}-Struktur für die angegebene Spalte.
+
+@subsubheading Fehler
+
+Keine.
+
+@subsubheading Beispiel
+
+@example
+unsigned int num_fields;
+unsigned int i;
+MYSQL_FIELD *field;
+
+num_fields = mysql_num_fields(ergebnis);
+for(i = 0; i < num_fields; i++)
+@{
+ field = mysql_fetch_field_direct(ergebnis, i);
+ printf("Feld %u ist %s\n", i, field->name);
+@}
+@end example
+
+
+@node mysql_fetch_lengths, mysql_fetch_row, mysql_fetch_field_direct, C API functions
+@c German node mysql_fetch_lengths
+@subsubsection @code{mysql_fetch_lengths()}
+
+@findex @code{mysql_fetch_lengths()}
+
+@code{unsigned long *mysql_fetch_lengths(MYSQL_RES *result)}
+
+@subsubheading Beschreibung
+
+Gibt die Länge der Spalten der aktuellen Zeile innerhalb der Ergebnismenge
+zurück. Wenn Sie vorhaben, Feldwerte zu kopieren, sind diese
+Längeninformationen auch nützlich für Optimierungen, weil Sie vermeiden
+können, @code{strlen()} aufzurufen. Wenn die Ergebnismenge Binärdaten
+enthält, kommt hinzu, dass Sie diese Funktion benutzen @emph{müssen}, um
+die Größe der Daten zu bestimmen, weil @code{strlen()} falsche Ergebnisse
+für Felder zurückgibt, die NULL-Zeichen enthalten.
+
+Die Länge leerer Spalten und von Spalten, die @code{NULL}-Werte enthalten,
+ist 0. Um zu sehen, wie man diese beiden Fälle auseinander hält, sehen Sie
+in der Beschreibung von @code{mysql_fetch_row()} nach.
+
+@subsubheading Rückgabewerte
+
+Ein Array vorzeichenloser langer Ganzzahlen (long integer), die die Größe
+jeder Spalte darstellen (ohne irgend welche begrenzenden NULL-Zeichen).
+@code{NULL}, wenn ein Fehler auftrat.
+
+@subsubheading Fehler
+
+@code{mysql_fetch_lengths()} ist nur für die aktuelle Zeile der
+Ergebnismenge gültig. Sie gibt @code{NULL} zurück, wenn Sie sie vor
+@code{mysql_fetch_row()} oder nach dem Abruf aller Zeilen im Ergebnis
+aufrufen.
+
+@subsubheading Beispiel
+
+@example
+MYSQL_ROW zeile;
+unsigned long *laengen;
+unsigned int anzahl_felder;
+unsigned int i;
+
+zeile = mysql_fetch_row(ergebnis);
+if (zeile)
+@{
+ anzahl_felder = mysql_num_fields(ergebnis);
+ laengen = mysql_fetch_lengths(ergebnis);
+ for(i = 0; i < anzahl_felder; i++)
+ @{
+ printf("Spalte %u ist %lu Bytes lang.\n", i, lengths[i]);
+ @}
+@}
+@end example
+
+
+@node mysql_fetch_row, mysql_field_count, mysql_fetch_lengths, C API functions
+@c German node mysql_fetch_row
+@subsubsection @code{mysql_fetch_row()}
+
+@findex @code{mysql_fetch_row()}
+
+@code{MYSQL_ROW mysql_fetch_row(MYSQL_RES *result)}
+
+@subsubheading Beschreibung
+
+Ruft die nächste Zeile einer Ergebnismenge ab. Wenn sie nach
+@code{mysql_store_result()} benutzt wird, gibt @code{mysql_fetch_row()}
+@code{NULL} zurück, wenn es keine weiteren Zeilen zum Abruf mehr gibt. Wenn
+sie nach @code{mysql_use_result()} benutzt wird, gibt
+@code{mysql_fetch_row()} @code{NULL} zurück, wenn es keine Zeilen mehr zum
+Abruf gibt oder wenn ein Fehler auftrat.
+
+Die Anzahl von Werten in der Zeile wird durch
+@code{mysql_num_fields(ergebnis)} gegeben. Wenn @code{zeile} den
+Rückgabewert eines Aufrufs von @code{mysql_fetch_row()} enthält, wird auf
+Zeiger auf die Werte als @code{zeile[0]} bis
+@code{zeile[mysql_num_fields(ergebnis)-1]} zugegriffen. @code{NULL}-Werte
+in der Zeile werden durch @code{NULL}-Zeiger angezeigt.
+
+Die Längen der Feldwerte in der Zeile können durch Aufruf von
+@code{mysql_fetch_lengths()} bestimmt werden. Leere Felder und Felder, die
+@code{NULL} enthalten, haben beide die Länge 0. Sie können diese
+auseinanderhalten, indem Sie den Zeiger für den Feldwert überprüfen. Wenn
+der Zeiger @code{NULL} ist, ist das Feld @code{NULL}, ansonsten ist das
+Feld leer.
+
+@subsubheading Rückgabewerte
+
+Eine @code{MYSQL_ROW}-Struktur für die nächste Zeile. @code{NULL}, wenn
+keine weiteren Zeilen abzurufen sind oder wenn ein Fehler auftrat.
+
+@subsubheading Fehler
+
+@table @code
+@item CR_SERVER_LOST
+Die Verbindung zum Server ging während der Anfrage verloren.
+@item CR_UNKNOWN_ERROR
+Ein unbekannter Fehler trat auf.
+@end table
+
+@subsubheading Beispiel
+
+@example
+MYSQL_ROW zeile;
+unsigned int anzahl_felder;
+unsigned int i;
+
+anzahl_felder = mysql_num_fields(ergebnis);
+while ((zeile = mysql_fetch_row(ergebnis)))
+@{
+ unsigned long *laengen;
+ laengen = mysql_fetch_lengths(ergebnis);
+ for(i = 0; i < anzahl_felder; i++)
+ @{
+ printf("[%.*s] ", (int) laengen[i], zeile[i] ? zeile[i] : "NULL");
+ @}
+ printf("\n");
+@}
+@end example
+
+
+@node mysql_field_count, mysql_field_seek, mysql_fetch_row, C API functions
+@c German node mysql_field_count
+@subsubsection @code{mysql_field_count()}
+
+@findex @code{mysql_field_count()}
+
+@code{unsigned int mysql_field_count(MYSQL *mysql)}
+
+Wenn Sie eine Version von MySQL vor Version 3.22.24 benutzen, sollten Sie
+statt dessen @code{unsigned int mysql_num_fields(MYSQL *mysql)} benutzen.
+
+@subsubheading Beschreibung
+
+Gibt die Anzahl von Spalten der letzten Anfrage auf der Verbindung zurück.
+
+Normalerweise wird diese Funktion benutzt, wenn @code{mysql_store_result()}
+@code{NULL} zurückgab (und Sie daher keinen Ergebnismengen-Zeiger haben).
+In diesem Fall können Sie @code{mysql_field_count()} aufrufen, um
+festzustellen, ob @code{mysql_store_result()} ein leeres Ergebnis hätte
+zurückgeben sollen oder nicht. Das gestattet dem Client-Programm, die
+richtigen Aktionen zu ergreifen, ohne wissen zu müssen, ob die Anfrage ein
+@code{SELECT} war oder nicht (oder ein @code{SELECT}-ähnliches Statement).
+Das unten stehende Beispiel zeigt, wie man das machen kann.
+
+@xref{NULL mysql_store_result, , @code{NULL mysql_store_result()}}.
+
+@subsubheading Rückgabewerte
+
+Eine vorzeichenlose Ganzzahl, die die Anzahl von Feldern in einer
+Ergebnismenge darstellt.
+
+@subsubheading Fehler
+
+Keine.
+
+@subsubheading Beispiel
+
+@example
+MYSQL_RES *result;
+unsigned int anzahl_felder;
+unsigned int anzahl_zeilen;
+
+if (mysql_query(&mysql,anfrage))
+@{
+ // FEHLER
+@}
+else // Anfrage war erfolgreich, zurückgegebene Daten verarbeiten
+@{
+ ergebnis = mysql_store_result(&mysql);
+ if (ergebnis) // Es gibt Zeilen
+ @{
+ anzahl_felder = mysql_num_fields(ergebnis);
+ // Zeilen abrufen, dann mysql_free_result(result) aufrufen
+ @}
+ else // mysql_store_result() gab nichts zurück, hätte es etwas zurückgeben sollen?
+ @{
+ if(mysql_field_count(&mysql) == 0)
+ @{
+ // Anfrage gibt keine Daten zurück
+ // (Anfrage war kein SELECT)
+ anzahl_zeilen = mysql_affected_rows(&mysql);
+ @}
+ else // mysql_store_result() hätte Daten zurückgeben sollen
+ @{
+ fprintf(stderr, "Fehler: %s\n", mysql_error(&mysql));
+ @}
+ @}
+@}
+@end example
+
+Eine Alternative besteht darin, den @code{mysql_field_count(&mysql)}-Aufruf
+durch @code{mysql_errno(&mysql)} zu ersetzen. In diesem Fall überprüfen Sie
+direkt auf einen Fehler von @code{mysql_store_result()}, statt aus dem Wert
+von @code{mysql_field_count()} zu schlussfolgern, ob das Statement ein
+@code{SELECT} war oder nicht.
+
+
+@node mysql_field_seek, mysql_field_tell, mysql_field_count, C API functions
+@c German node mysql_field_seek
+@subsubsection @code{mysql_field_seek()}
+
+@findex @code{mysql_field_seek()}
+
+@code{MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET offset)}
+
+@subsubheading Beschreibung
+
+Setzt den Feldcursor auf den angegebenen Offset. Der nächste Aufruf von
+@code{mysql_fetch_field()} ruf die Felddefinition der Spalte ab, die mit
+diesem Offset verknüpft ist.
+
+Um bis zum Anfang einer Zeile zu suchen, geben Sie einen @code{offset}-Wert
+von 0 an.
+
+@subsubheading Rückgabewerte
+
+Der vorherige Wert des Feldcursors.
+
+@subsubheading Fehler
+
+Keine.
+
+
+@node mysql_field_tell, mysql_free_result, mysql_field_seek, C API functions
+@c German node mysql_field_tell
+@subsubsection @code{mysql_field_tell()}
+
+@findex @code{mysql_field_tell()}
+
+@code{MYSQL_FIELD_OFFSET mysql_field_tell(MYSQL_RES *result)}
+
+@subsubheading Beschreibung
+
+Gibt die Position des Feldcursors für die letzte @code{mysql_fetch_field()}
+zurück. Dieser Wert kann als Argument für @code{mysql_field_seek()} benutzt
+werden.
+
+@subsubheading Rückgabewerte
+
+Der aktuelle Offset des Feldcursors.
+
+@subsubheading Fehler
+
+Keine.
+
+
+@node mysql_free_result, mysql_get_client_info, mysql_field_tell, C API functions
+@c German node mysql_free_result
+@subsubsection @code{mysql_free_result()}
+
+@findex @code{mysql_free_result()}
+
+@code{void mysql_free_result(MYSQL_RES *result)}
+
+@subsubheading Beschreibung
+
+Gibt den Speicher frei, der für eine Ergebnismenge von
+@code{mysql_store_result()}, @code{mysql_use_result()},
+@code{mysql_list_dbs()} usw. zugewiesen wurde. Wenn Sie mit einer
+Ergebnismenge fertig sind, müssen Sie den von ihr benutzten Speicher durch
+Aufruf von @code{mysql_free_result()} freigeben.
+
+@subsubheading Rückgabewerte
+
+Keine.
+
+@subsubheading Fehler
+
+Keine.
+
+
+@node mysql_get_client_info, mysql_get_host_info, mysql_free_result, C API functions
+@c German node mysql_get_client_info
+@subsubsection @code{mysql_get_client_info()}
+
+@findex @code{mysql_get_client_info()}
+
+@code{char *mysql_get_client_info(void)}
+
+@subsubheading Beschreibung
+
+Returns a string that represents the client Bibliothek version.
+
+@subsubheading Rückgabewerte
+
+A character string that represents the MySQL-Client Bibliothek version.
+
+@subsubheading Fehler
+Keine.
+
+
+@node mysql_get_host_info, mysql_get_proto_info, mysql_get_client_info, C API functions
+@c German node mysql_get_host_info
+@subsubsection @code{mysql_get_host_info()}
+
+@findex @code{mysql_get_host_info()}
+
+@code{char *mysql_get_host_info(MYSQL *mysql)}
+
+@subsubheading Beschreibung
+
+Gibt eine Zeichenkette zurück, die den Typ der benutzten Verbindung
+beschreibt, inklusive des Server-Hostnamens.
+
+@subsubheading Rückgabewerte
+
+Eine Zeichenkette, die den Server-Hostnamen und den Verbindungstyp
+bezeichnet.
+
+@subsubheading Fehler
+
+Keine.
+
+
+@node mysql_get_proto_info, mysql_get_server_info, mysql_get_host_info, C API functions
+@c German node mysql_get_proto_info
+@subsubsection @code{mysql_get_proto_info()}
+
+@findex @code{mysql_get_proto_info()}
+
+@code{unsigned int mysql_get_proto_info(MYSQL *mysql)}
+
+@subsubheading Beschreibung
+
+Gibt die Protokollversion zurück, die von der aktuellen Verbindung benutzt
+wird.
+
+@subsubheading Rückgabewerte
+
+Eine vorzeichenlose Ganzzahl, die die Protokollversion bezeichnet, die von
+der aktuellen Verbindung benutzt wird.
+
+@subsubheading Fehler
+
+Keine.
+
+
+@node mysql_get_server_info, mysql_info, mysql_get_proto_info, C API functions
+@c German node mysql_get_server_info
+@subsubsection @code{mysql_get_server_info()}
+
+@findex @code{mysql_get_server_info()}
+
+@code{char *mysql_get_server_info(MYSQL *mysql)}
+
+@subsubheading Beschreibung
+
+Gibt eine Zeichenkette zurück, die die Server-Versionsnummer bezeichnet.
+
+@subsubheading Rückgabewerte
+
+Eine Zeichenkette, die die Server-Versionsnummer bezeichnet.
+
+@subsubheading Fehler
+
+Keine.
+
+
+@node mysql_info, mysql_init, mysql_get_server_info, C API functions
+@c German node mysql_info
+@subsubsection @code{mysql_info()}
+
+@findex @code{mysql_info()}
+
+@code{char *mysql_info(MYSQL *mysql)}
+
+@subsubheading Beschreibung
+
+Ruft eine Zeichenkette ab, die Informationen über die zuletzt ausgeführte
+Anfrage zurückgibt, aber nur für die unten aufgeführten Statements. Bei
+anderen Statements gibt @code{mysql_info()} @code{NULL} zurück. Das Format
+der Zeichenkette variiert in Abhängigkeit vom Anfragetyp, wie unten
+beschrieben. Die Nummern dienen nur der Veranschaulichung; die Zeichenkette
+enthält die der Anfrage entsprechenden Werte.
+
+@table @code
+@item INSERT INTO ... SELECT ...
+Zeichenkettenformat: @code{Records: 100 Duplicates: 0 Warnings: 0}
+@item INSERT INTO ... VALUES (...),(...),(...)...
+Zeichenkettenformat: @code{Records: 3 Duplicates: 0 Warnings: 0}
+@item LOAD DATA INFILE ...
+Zeichenkettenformat: @code{Records: 1 Deleted: 0 Skipped: 0 Warnings: 0}
+@item ALTER TABLE
+Zeichenkettenformat: @code{Records: 3 Duplicates: 0 Warnings: 0}
+@item UPDATE
+Zeichenkettenformat: @code{Rows matched: 40 Changed: 40 Warnings: 0}
+@end table
+
+Beachten Sie, dass @code{mysql_info()} einen Nicht-@code{NULL}-Wert für das
+@code{INSERT ... VALUES}-Statement nur dann zurückgibt, wenn im Statement
+mehrfache Wertlisten angegeben sind.
+
+@subsubheading Rückgabewerte
+
+Eine Zeichenkette, die zusätzliche Informationen über die zuletzt
+ausgeführte Anfrage bereitstellt. @code{NULL}, wenn für die Anfrage keine
+Information verfügbar ist.
+
+@subsubheading Fehler
+Keine.
+
+
+@node mysql_init, mysql_insert_id, mysql_info, C API functions
+@c German node mysql_init
+@subsubsection @code{mysql_init()}
+
+@findex @code{mysql_init()}
+
+@code{MYSQL *mysql_init(MYSQL *mysql)}
+
+@subsubheading Beschreibung
+
+Alloziert oder initialisiert ein @code{MYSQL}-Objekt, das für
+@code{mysql_real_connect()} geeignet ist. Wenn @code{mysql} ein
+@code{NULL}-Zeiger ist, alloziert, initialisiert und gibt diese Funktion
+ein neues Objekt zurück. Ansonsten wird das Objekt initialisiert und die
+Adresse des Objekts zurückgegeben. Wenn @code{mysql_init()} ein neues
+Objekt alloziert, wird es freigegeben, wenn @code{mysql_close()} aufgerufen
+wird, um die Verbindung zu schließen.
+
+@subsubheading Rückgabewerte
+
+Ein initialisiertes @code{MYSQL*}-Handle. @code{NULL}, wenn der Speicher
+nicht ausreichte, um ein neues Objekt zu allozieren.
+
+@subsubheading Fehler
+
+Im Falle von ungenügendem Speicher wird @code{NULL} zurückgegeben.
+
+
+@node mysql_insert_id, mysql_kill, mysql_init, C API functions
+@c German node mysql_insert_id
+@subsubsection @code{mysql_insert_id()}
+
+@findex @code{mysql_insert_id()}
+
+@code{my_ulonglong mysql_insert_id(MYSQL *mysql)}
+
+@subsubheading Beschreibung
+
+Gibt die Kennung zurück, die für eine @code{AUTO_INCREMENT}-Spalte durch
+die vorherige Anfrage erzeugt wurde. Benutzen Sie diese Funktion, nachdem
+Sie eine @code{INSERT}-Anfrage für eine Tabelle durchgeführt haben, die ein
+@code{AUTO_INCREMENT}-Feld enthält.
+
+Beachten Sie, dass @code{mysql_insert_id()} @code{0} zurückgibt, wenn die
+vorherige Anfrage keinen @code{AUTO_INCREMENT}-Wert erzeugt hat. Wenn Sie
+den Wert für spätere Benutzung speichern wollen, stellen Sie sicher, dass
+Sie @code{mysql_insert_id()} unmittelbar nach der Anfrage aufrufen, die den
+Wert erzeugt.
+
+@code{mysql_insert_id()} wird nach @code{INSERT}- und
+@code{UPDATE}-Statements aktualisiert, die einen @code{AUTO_INCREMENT}-Wert
+erzeugen oder einen Spaltenwert auf @code{LAST_INSERT_ID(ausdruck)} setzen.
+@xref{Miscellaneous functions}.
+
+Beachten Sie auch, dass der Wert der SQL-@code{LAST_INSERT_ID()}-Funktion
+immer den aktuellsten erzeugten @code{AUTO_INCREMENT}-Wert enthält, und
+zwischen Anfragen nicht zurückgesetzt wird, weil der Wert dieser Funktion
+im Server gewartet wird.
+
+@subsubheading Rückgabewerte
+
+Der Wert des @code{AUTO_INCREMENT}-Felds, das durch die vorherige Anfrage
+aktualisiert wurde. Gibt 0 zurück, wenn es keine vorherige Anfrage auf der
+Verbindung gab oder wenn die Anfrage keinen @code{AUTO_INCREMENT}-Wert
+aktualisierte.
+
+@subsubheading Fehler
+
+Keine.
+
+
+@node mysql_kill, mysql_list_dbs, mysql_insert_id, C API functions
+@c German node mysql_kill
+@subsubsection @code{mysql_kill()}
+
+@findex @code{mysql_kill()}
+
+@code{int mysql_kill(MYSQL *mysql, unsigned long pid)}
+
+@subsubheading Beschreibung
+
+Bittet den Server, den Thread zu töten, der durch @code{pid} angegeben
+wurde.
+
+@subsubheading Rückgabewerte
+
+0 für Erfolg. Nicht-0, wenn ein Fehler auftrat.
+
+@subsubheading Fehler
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Befehle wurden nicht in der korrekten Reihenfolge ausgeführt.
+@item CR_SERVER_GONE_ERROR
+Der MySQL-Server ist weg.
+@item CR_SERVER_LOST
+Die Verbindung zum Server ging während der Anfrage verloren.
+@item CR_UNKNOWN_ERROR
+Ein unbekannter Fehler trat auf.
+@end table
+
+
+@node mysql_list_dbs, mysql_list_fields, mysql_kill, C API functions
+@c German node mysql_list_dbs
+@subsubsection @code{mysql_list_dbs()}
+
+@findex @code{mysql_list_dbs()}
+
+@code{MYSQL_RES *mysql_list_dbs(MYSQL *mysql, const char *wild)}
+
+@subsubheading Beschreibung
+
+Gibt eine Ergebnismenge zurück, die aus den Datenbanknamen auf dem Server
+besteht, die mit dem einfachen regulären Ausdruck übereinstimmen, der durch
+den @code{wild}-Parameter angegeben wird. @code{wild} darf die
+Platzhalterzeichen @samp{%} oder @samp{_} enthalten oder ein
+@code{NULL}-Zeiger sein, der mit allen Datenbanken übereinstimmt. Der
+Aufruf von @code{mysql_list_dbs()} ist ähnlich der Ausführung der Anfrage
+@code{SHOW DATABASES [LIKE wild]}.
+
+Sie müssen die Ergebnismenge mit @code{mysql_free_result()} freigeben.
+
+@subsubheading Rückgabewerte
+
+Eine @code{MYSQL_RES}-Ergebnismenge bei Erfolg. @code{NULL}, wenn ein
+Fehler auftrat.
+
+@subsubheading Fehler
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Befehle wurden nicht in der korrekten Reihenfolge ausgeführt.
+@item CR_OUT_OF_MEMORY
+Kein Speicher mehr.
+@item CR_SERVER_GONE_ERROR
+Der MySQL-Server ist weg.
+@item CR_SERVER_LOST
+Die Verbindung zum Server ging während der Anfrage verloren.
+@item CR_UNKNOWN_ERROR
+Ein unbekannter Fehler trat auf.
+@end table
+
+
+@node mysql_list_fields, mysql_list_processes, mysql_list_dbs, C API functions
+@c German node mysql_list_fields
+@subsubsection @code{mysql_list_fields()}
+
+@findex @code{mysql_list_fields()}
+
+@code{MYSQL_RES *mysql_list_fields(MYSQL *mysql, const char *table, const char *wild)}
+
+@subsubheading Beschreibung
+
+Gibt eine Ergebnismenge zurück, die aus Feldnamen in der angegebenen
+Tabelle bestehen, die mit einem einfachen regulären Ausdruck
+übereinstimmen, der durch den @code{wild}-Parameter angegeben wird.
+@code{wild} darf die Platzhalterzeichen @samp{%} oder @samp{_} enthalten
+oder ein @code{NULL}-Zeiger sein, der mit allen Datenbanken übereinstimmt.
+Der Aufruf von @code{mysql_list_fields()} ist ähnlich der Ausführung der
+Anfrage @code{SHOW COLUMNS FROM tabelle [LIKE wild]}.
+
+Beachten Sie, dass empfohlen wird, @code{SHOW COLUMNS FROM tabelle} statt
+@code{mysql_list_fields()} zu benutzen.
+
+Sie müssen die Ergebnismenge mit @code{mysql_free_result()} freigeben.
+
+@subsubheading Rückgabewerte
+
+Eine @code{MYSQL_RES}-Ergebnismenge bei Erfolg. @code{NULL}, wenn ein Fehler auftrat.
+
+@subsubheading Fehler
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Befehle wurden nicht in der korrekten Reihenfolge ausgeführt.
+@item CR_SERVER_GONE_ERROR
+Der MySQL-Server ist weg.
+@item CR_SERVER_LOST
+Die Verbindung zum Server ging während der Anfrage verloren.
+@item CR_UNKNOWN_ERROR
+Ein unbekannter Fehler trat auf.
+@end table
+
+
+@node mysql_list_processes, mysql_list_tables, mysql_list_fields, C API functions
+@c German node mysql_list_processes
+@subsubsection @code{mysql_list_processes()}
+
+@findex @code{mysql_list_processes()}
+
+@code{MYSQL_RES *mysql_list_processes(MYSQL *mysql)}
+
+@subsubheading Beschreibung
+
+Gibt eine Ergebnismenge zurück, die die aktuellen Server-Threads
+beschreibt. Das ist dieselbe Art von Information, die von @code{mysqladmin
+processlist} oder einer @code{SHOW PROCESSLIST}-Anfrage zur Verfügung
+gestellt wird.
+
+Sie müssen die Ergebnismenge mit @code{mysql_free_result()} freigeben.
+
+@subsubheading Rückgabewerte
+
+Eine @code{MYSQL_RES}-Ergebnismenge bei Erfolg. @code{NULL}, wenn ein
+Fehler auftrat.
+
+@subsubheading Fehler
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Befehle wurden nicht in der korrekten Reihenfolge ausgeführt.
+@item CR_SERVER_GONE_ERROR
+Der MySQL-Server ist weg.
+@item CR_SERVER_LOST
+Die Verbindung zum Server ging während der Anfrage verloren.
+@item CR_UNKNOWN_ERROR
+Ein unbekannter Fehler trat auf.
+@end table
+
+
+@node mysql_list_tables, mysql_num_fields, mysql_list_processes, C API functions
+@c German node mysql_list_tables
+@subsubsection @code{mysql_list_tables()}
+
+@findex @code{mysql_list_tables()}
+
+@code{MYSQL_RES *mysql_list_tables(MYSQL *mysql, const char *wild)}
+
+@subsubheading Beschreibung
+
+Gibt eine Ergebnismenge zurück, die aus Tabellennamen in der aktuellen
+Datenbank besteht, die mit einem einfachen regulären Ausdruck
+übereinstimmen, der durch den @code{wild}-Parameter angegeben wird.
+@code{wild} darf die Platzhalterzeichen @samp{%} oder @samp{_} enthalten
+oder ein @code{NULL}-Zeiger sein, der mit allen Tabellen übereinstimmt. Der
+Aufruf von @code{mysql_list_tables()} ist ähnlich der Ausführung der
+Anfrage @code{SHOW tables [LIKE wild]}.
+
+Sie müssen die Ergebnismenge mit @code{mysql_free_result()} freigeben.
+
+@subsubheading Rückgabewerte
+
+Eine @code{MYSQL_RES}-Ergebnismenge bei Erfolg. @code{NULL}, wenn ein Fehler auftrat.
+
+@subsubheading Fehler
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Befehle wurden nicht in der korrekten Reihenfolge ausgeführt.
+@item CR_SERVER_GONE_ERROR
+Der MySQL-Server ist weg.
+@item CR_SERVER_LOST
+Die Verbindung zum Server ging während der Anfrage verloren.
+@item CR_UNKNOWN_ERROR
+Ein unbekannter Fehler trat auf.
+@end table
+
+
+@node mysql_num_fields, mysql_num_rows, mysql_list_tables, C API functions
+@c German node mysql_num_fields
+@subsubsection @code{mysql_num_fields()}
+
+@findex @code{mysql_num_fields()}
+@findex @code{mysql_field_count()}
+
+@code{unsigned int mysql_num_fields(MYSQL_RES *result)}
+
+oder
+
+@code{unsigned int mysql_num_fields(MYSQL *mysql)}
+
+Die zweite Form funktioniert nicht bei MySQL-Version 3.22.24 oder neuer. Um
+ein @code{MYSQL*}-Argument zu übergeben, müssen Sie statt dessen
+@code{unsigned int mysql_field_count(MYSQL *mysql)} benutzen.
+
+@subsubheading Beschreibung
+
+Gibt die Anzahl von Spalten in einer Ergebnismenge zurück.
+
+Beachten Sie, dass Sie die Anzahl von Spalten entweder durch einen Zeiger
+auf die Ergebnismenge oder auf ein Verbindungs-Handle erhalten. Das
+Verbindungs-Handle benutzen Sie, wenn @code{mysql_store_result()} oder
+@code{mysql_use_result()} @code{NULL} zurückgibt (und Sie daher keinen
+Ergebnismengen-Zeiger haben). In diesem Fall können Sie
+@code{mysql_field_count()} aufrufen, um festzustellen, ob
+@code{mysql_store_result()} eine leere Ergebnismenge produziert haben
+sollte oder nicht. Das erlaubt dem Client-Programm, die korrekten Aktionen
+vorzunehmen, ohne wissen zu müssen, ob die Anfrage ein @code{SELECT}- (oder
+@code{SELECT}-ähnliches) Statement war oder nicht. Das unten stehende
+Beispiel zeigt, wie das gemacht wird.
+
+@xref{NULL mysql_store_result, , @code{NULL mysql_store_result()}}.
+
+@subsubheading Rückgabewerte
+
+Eine vorzeichenlose Ganzzahl, die die Anzahl von Feldern in einer
+Ergebnismenge darstellt.
+
+@subsubheading Fehler
+
+Keine.
+
+@subsubheading Beispiel
+
+@example
+MYSQL_RES *ergebnis;
+unsigned int anzahl_felder;
+unsigned int anzahl_zeilen;
+
+if (mysql_query(&mysql,anfrage_zeichenkette))
+@{
+ // FEHLER
+@}
+else // Anfrage erfolgreich, zurückgegebene Daten verarbeiten
+@{
+ ergebnis = mysql_store_result(&mysql);
+ if (ergebnis) // Es gibt Zeilen
+ @{
+ anzahl_felder = mysql_num_fields(ergebnis);
+ // Zeilen abrufen, dann mysql_free_result(ergebnis) aufrufen
+ @}
+ else // mysql_store_result() gab nichts zurück, hätte es das tun sollen?
+ @{
+ if (mysql_errno(&mysql))
+ @{
+ fprintf(stderr, "Fehler: %s\n", mysql_error(&mysql));
+ @}
+ else if (mysql_field_count(&mysql) == 0)
+ @{
+ // Anfrage gibt keine Daten zurück
+ // (war kein SELECT)
+ anzahl_zeilen = mysql_affected_rows(&mysql);
+ @}
+ @}
+@}
+@end example
+
+Eine Alternative (wenn Sie WISSEN, dass Ihre Anfrage eine Ergebnismenge
+hätte zurückgeben sollen) ist es, den @code{mysql_errno(&mysql)}-Aufruf
+durch eine Prüfung zu ersetzen, ob @code{mysql_field_count(&mysql)} gleich
+0 ist. Das passiert nur, wenn etwas schief lief.
+
+
+@node mysql_num_rows, mysql_options, mysql_num_fields, C API functions
+@c German node mysql_num_rows
+@subsubsection @code{mysql_num_rows()}
+
+@findex @code{mysql_num_rows()}
+
+@code{my_ulonglong mysql_num_rows(MYSQL_RES *result)}
+
+@subsubheading Beschreibung
+
+Gibt die Anzahl von Zeilen in der Ergebnismenge zurück.
+
+Die Benutzung von @code{mysql_num_rows()} hängt davon ab, ob Sie
+@code{mysql_store_result()} oder @code{mysql_use_result()} benutzen, um die
+Ergebnismenge zurückzugeben.. Wenn Sie @code{mysql_store_result()}
+benutzen, kann @code{mysql_num_rows()} unmittelbar aufgerufen werden. Wenn
+Sie @code{mysql_use_result()} benutzen, gibt @code{mysql_num_rows()} nicht
+den richtigen Wert zurück, bis alle Zeilen in der Ergebnismenge abgerufen
+wurden.
+
+@subsubheading Rückgabewerte
+
+Die Anzahl von Zeilen in der Ergebnismenge.
+
+@subsubheading Fehler
+
+Keine.
+
+
+@node mysql_options, mysql_ping, mysql_num_rows, C API functions
+@c German node mysql_options
+@subsubsection @code{mysql_options()}
+
+@findex @code{mysql_options()}
+
+@code{int mysql_options(MYSQL *mysql, enum mysql_option option, const char *arg)}
+
+@subsubheading Beschreibung
+
+Kann benutzt werden, um zusätzliche Optionen zu setzen und das Verhalten
+einer Verbindung zu beeinflussen. Diese Funktion kann mehrfach aufgerufen
+werden, um mehrere Optionen zu setzen.
+
+@code{mysql_options()} sollte nach @code{mysql_init()} und vor
+@code{mysql_connect()} oder @code{mysql_real_connect()} aufgerufen werden.
+
+Das @code{option}-Argument ist die Option, die Sie setzen wollen. Das
+@code{arg}-Argument ist der Wert für die Option. Wenn die Option eine
+Ganzzahl ist, sollte @code{arg} auf den Wert der Ganzzahl zeigen.
+
+Mögliche Optionswerte:
+
+@multitable @columnfractions .25 .25 .5
+@item @strong{Option} @tab @strong{Argumenttyp} @tab @strong{Funktion}
+@item @code{MYSQL_OPT_CONNECT_TIMEOUT} @tab @code{unsigned int *} @tab Verbindungszeitüberschreitung (Timeout) in Sekunden.
+@item @code{MYSQL_OPT_COMPRESS} @tab Unbenutzt @tab Das komprimierte Client-/Server-Protokoll verwenden.
+@item @code{MYSQL_OPT_NAMED_PIPE} @tab Unbenutzt @tab Named Pipes benutzen, um sich mit einem MySQL-Server unter NT zu verbinden.
+@item @code{MYSQL_INIT_COMMAND} @tab @code{char *} @tab Befehl, der beim Verbinden mit dem MySQL-Server ausgeführt werden soll. Wird beim erneuten Verbinden automatisch wieder ausgeführt.
+@item @code{MYSQL_READ_DEFAULT_FILE} @tab @code{char *} @tab Optionen aus der benannten Optionsdatei einlesen anstelle von @file{my.cnf}.
+@item @code{MYSQL_READ_DEFAULT_GROUP} @tab @code{char *} @tab Optionen aus der benannten Gruppe von @file{my.cnf} oder der Datei einlesen, die durch @code{MYSQL_READ_DEFAULT_FILE} angegeben wurde.
+@end multitable
+
+Beachten Sie, dass die Gruppe @code{client} immer gelesen wird, wenn Sie
+@code{MYSQL_READ_DEFAULT_FILE} oder @code{MYSQL_READ_DEFAULT_GROUP}
+benutzen.
+
+Die angegebene Gruppe in der Optionsdatei kann folgende Optionen enthalten:
+
+@multitable @columnfractions .3 .7
+@item @code{connect_timeout} @tab Zeitüberschreitung (Timeout) für die
+Verbindung in Sekunden. Unter Linux wird dieser Wert zusätzlich für die
+Wartezeit auf die erste Antwort vom Server benutzt.
+@item @code{compress} @tab Das komprimierte Client-/Server-Protokoll
+benutzen.
+@item @code{database} @tab Mit dieser Datenbank verbinden, wenn im
+Verbindungsbefehl keine Datenbank angegeben wurde.
+@item @code{debug} @tab Debug-Optionen.
+@item @code{host} @tab Vorgabemäßiger Hostname.
+@item @code{init-commund} @tab Befehl, der bei der Verbindung zum
+MySQL-Server ausgeführt wird. Wird automatisch beim erneuten Verbinden
+erneut ausgeführt.
+@item @code{interactive-timeout} @tab Dasselbe wie die Angabe von
+@code{CLIENT_INTERACTIVE} für @code{mysql_real_connect()}.
+@xref{mysql_real_connect}.
+@item @code{password} @tab Vorgabemäßiges Passwort.
+@item @code{pipe} @tab Named Pipes benutzen, um sich mit einem MySQL-Server unter NT zu verbinden.
+@item @code{port} @tab Vorgabemäßige Port-Nummer.
+@item @code{return-found-rows} @tab Weist @code{mysql_info()} an, gefundene
+Zeilen anstelle von aktualisierten Zeilen zurückzugeben, wenn @code{UPDATE}
+benutzt wird.
+@item @code{socket} @tab Vorgabemäßige Socket-Nummer.
+@item
+@item @code{user} @tab Vorgabemäßiger Benutzer.
+@end multitable
+
+Beachten Sie, dass @code{timeout} durch @code{connect_timeout} ersetzt
+wurde. Dennoch wird @code{timeout} noch für eine Weile funktionieren.
+
+Weitere Informationen über Optionsdateien finden Sie unter
+@ref{Option files}.
+
+@subsubheading Rückgabewerte
+
+0 bei Erfolg. Nicht-0, wenn Sie eine unbekannte Option verwenden.
+
+@subsubheading Beispiel
+
+@example
+MYSQL mysql;
+
+mysql_init(&mysql);
+mysql_options(&mysql,MYSQL_OPT_COMPRESS,0);
+mysql_options(&mysql,MYSQL_READ_DEFAULT_GROUP,"odbc");
+if (!mysql_real_connect(&mysql,"host","benutzer","passwort","datenbank",0,NULL,0))
+@{
+ fprintf(stderr, "Keine Verbindung zur Datenbank: Fehler: %s\n",
+ mysql_error(&mysql));
+@}
+@end example
+
+Im obigen Beispiel wird der Client angewiesen, das komprimierte
+Client-/Server-Protokoll zu benutzen und zusätzliche Optionen aus dem
+@code{odbc}-Abschnitt in @code{my.cnf} zu lesen.
+
+
+@node mysql_ping, mysql_query, mysql_options, C API functions
+@c German node mysql_ping
+@subsubsection @code{mysql_ping()}
+
+@findex @code{mysql_ping()}
+
+@code{int mysql_ping(MYSQL *mysql)}
+
+@subsubheading Beschreibung
+
+Prüft, ob die Verbindung zum Server funktioniert oder nicht. Wenn diese weg
+ist, wird automatisch eine erneute Verbindung versucht.
+
+Diese Funktion kann von Clients benutzt werden, die für lange Zeit im
+Leerlauf laufen, um zu prüfen, ob der Server die Verbindung geschlossen
+hat, und sich bei Bedarf erneut zu verbinden.
+
+@subsubheading Rückgabewerte
+
+0, wenn der Server da ist. Nicht-0, wenn ein Fehler auftrat.
+
+@subsubheading Fehler
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Befehle wurden nicht in der korrekten Reihenfolge ausgeführt.
+@item CR_SERVER_GONE_ERROR
+Der MySQL-Server ist weg.
+@item CR_UNKNOWN_ERROR
+Ein unbekannter Fehler trat auf.
+@end table
+
+
+@node mysql_query, mysql_real_connect, mysql_ping, C API functions
+@c German node mysql_query
+@subsubsection @code{mysql_query()}
+
+@findex @code{mysql_query()}
+
+@code{int mysql_query(MYSQL *mysql, const char *anfrage)}
+
+@subsubheading Beschreibung
+Führt die SQL-Anfrage aus, auf die durch die NULL-begrenzte Zeichenkette
+@code{anfrage} gezeigt wird. Die Anfrage muss aus einem einzelnen
+SQL-Statement bestehen. Sie dürfen kein Semikolon (@samp{;}) oder @code{\g}
+zum Statement hinzufügen.
+
+@code{mysql_query()} kann nicht für Anfragen benutzt werden, die Binärdaten
+enthalten. Hierfür sollten Sie statt dessen @code{mysql_real_query()}
+benutzen. (Binärdaten können das @samp{\0}-Zeichen enthalten, was
+@code{mysql_query()} als Ende der Anfrage-Zeichenkette interpretiert.)
+
+Wenn Sie wissen wollen, ob die Anfrage eine Ergebnismenge zurückgeben
+sollte oder nicht, können Sie @code{mysql_field_count()} benutzen, um
+hierauf zu prüfen. @xref{mysql_field_count, , @code{mysql_field_count}}.
+
+@subsubheading Rückgabewerte
+
+0, wenn die Anfrage erfolgreich war. Nicht-0, wenn ein Fehler auftrat.
+
+@subsubheading Fehler
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Befehle wurden nicht in der korrekten Reihenfolge ausgeführt.
+@item CR_SERVER_GONE_ERROR
+Der MySQL-Server ist weg.
+@item CR_SERVER_LOST
+Die Verbindung zum Server ging während der Anfrage verloren.
+@item CR_UNKNOWN_ERROR
+Ein unbekannter Fehler trat auf.
+@end table
+
+
+@node mysql_real_connect, mysql_real_escape_string, mysql_query, C API functions
+@c German node mysql_real_connect
+@subsubsection @code{mysql_real_connect()}
+
+@findex @code{mysql_real_connect()}
+
+@code{MYSQL *mysql_real_connect(MYSQL *mysql, const char *host,
+ const char *user, const char *passwd, const char *db,
+ unsigned int port, const char *unix_socket,
+ unsigned int client_flag)}
+
+@subsubheading Beschreibung
+
+@code{mysql_real_connect()} versucht, eine Verbindung zu einer
+MySQL-Datenbankmaschine aufzubauen, die auf @code{host} läuft.
+@code{mysql_real_connect()} muss erfolgreich verlaufen sein, bevor Sie
+irgend eine andere API-Funktion ausführen können, mit Ausnahme von
+@code{mysql_get_client_info()}.
+
+Die Parameter werden wie folgt angegeben:
+
+@itemize @bullet
+@item
+Der erste Parameter sollte die Adresse einer existierenden
+@code{MYSQL}-Struktur sein. Vor dem Aufruf von @code{mysql_real_connect()}
+müssen Sie @code{mysql_init()} aufrufen, um die @code{MYSQL}-Struktur zu
+initialisieren. Sie können viele der Verbindungsoptionen mit dem
+@code{mysql_options()}-Aufruf ändern. @xref{mysql_options}.
+
+@item
+Der Wert von @code{host} kann entweder ein Hostname oder eine IP-Adresse
+sein. Wenn @code{host} @code{NULL} oder die Zeichenkette @code{"localhost"}
+ist, wird eine Verbindung zum lokalen Host angenommen. Wenn das
+Betriebssystem Sockets (Unix) oder Named Pipes (Windows NT) unterstützt,
+werden diese statt TCP/IP benutzt, um sich mit dem Server zu verbinden.
+
+@item
+Der @code{user}-Parameter enthält die MySQL-Login-Benutzerkennung. Wenn
+@code{user} @code{NULL} ist, wird der aktuelle Benutzer angenommen. Unter
+Unix ist das der aktuelle Login-Name. Unter Windows-ODBC muss der aktuelle
+Benutzername explizit angegeben werden. @xref{ODBC administrator}.
+
+@item
+Der @code{passwd}-Parameter enthält das Passwort für @code{user}. Wenn
+@code{passwd} @code{NULL} ist, werden nur Einträge in der
+@code{user}-Tabelle für Benutzer auf Übereinstimmung überprüft, die ein
+leeres Passwort-Feld haben. Das erlaubt dem Datenbank-Administrator, das
+MySQL-Berechtigungssystem so einzurichten, dass Benutzer unterschiedliche
+Berechtigungen haben, je nachdem, ob sie ein Passwort angegeben haben oder
+nicht.
+
+HINWEIS: Versuchen Sie nicht, dass Passwort zu verschlüsseln, bevor Sie
+@code{mysql_real_connect()} aufrufen. Die Passwortverschlüsselung wird
+automatisch durch die Client-API gehandhabt.
+
+@item
+@code{db} ist der Datenbankname. Wenn @code{db} nicht @code{NULL} ist,
+wird die vorgabemäßige Datenbank für die Verbindung auf diesen Wert
+gesetzt.
+
+@item
+Wenn @code{port} nicht 0 ist, wird dieser Wert als Port-Nummer für die
+TCP/IP-Verbindung benutzt. Beachten Sie, dass der @code{host}-Parameter den
+Verbindungstyp festlegt.
+
+@item
+Wenn @code{unix_socket} nicht @code{NULL} ist, legt die Zeichenkette den
+Socket oder die Named Pipe fest, die benutzt werden sollen. Beachten Sie,
+dass der @code{host}-Parameter den Verbindungstyp festlegt.
+
+@item
+Der Wert von @code{client_flag} ist üblicherweise 0, kann aber unter sehr
+speziellen Umständen auf eine Kombination folgender Flags gesetzt werden:
+
+@multitable @columnfractions .25 .7
+@item @strong{Flag-Name} @tab @strong{Flag-Bedeutung}
+@item @code{CLIENT_COMPRESS} @tab Komprimiertes Protokoll benutzen.
+@item @code{CLIENT_FOUND_ROWS} @tab Die Anzahl gefundener
+(übereinstimmender) Zeilen zurückgeben, nicht die Anzahl betroffener
+Zeilen.
+@item @code{CLIENT_IGNORE_SPACE} @tab Leerzeichen nach Funktionsnamen
+zulassen. Macht alle Funktionsnamen zu reservierten Wörter.
+@item @code{CLIENT_INTERACTIVE} @tab @code{interactive_timeout} Sekunden
+zulassen (anstelle von @code{wait_timeout} Sekunden) von Inaktivität, bevor
+die Verbindung geschlossen wird.
+@item @code{CLIENT_NO_SCHEMA} @tab Die
+@code{datenbank.tabelle.spalte}-Syntax nicht zulassen. Das ist für ODBC.
+Der Flag veranlasst den Parser, einen Fehler zu erzeugen, wenn Sie diese
+Syntax benutzen, was für die Fehlersuche in einigen ODBC-Programmen
+hilfreich ist.
+@item @code{CLIENT_ODBC} @tab Der Client ist ein ODBC-Client. Das
+ändert
+@item @code{CLIENT_SSL} @tab SSL benutzen (verschlüsseltes Protokoll).
+@end multitable
+@end itemize
+
+@subsubheading Rückgabewerte
+
+Ein @code{MYSQL*}-Verbindungs-Handle, wenn die Verbindung erfolgreich war,
+@code{NULL}, wenn die Verbindung nicht erfolgreich war. Bei einer
+erfolgreichen Verbindung ist der Rückgabewert derselbe wie der Wert des
+ersten Parameters, es sei denn, Sie übergeben für diesen Parameter
+@code{NULL}.
+
+@subsubheading Fehler
+
+@table @code
+@item CR_CONN_HOST_ERROR
+Verbindung zum MySQL-Server fehlgeschlagen.
+
+@item CR_CONNECTION_ERROR
+Verbindung zum lokalen MySQL-Server fehlgeschlagen.
+
+@item CR_IPSOCK_ERROR
+IP-Socket konnte nicht erzeugt werden.
+
+@item CR_OUT_OF_MEMORY
+Kein Speicher mehr.
+
+@item CR_SOCKET_CREATE_ERROR
+Unix-Socket konnte nicht erzeugt werden.
+
+@item CR_UNKNOWN_HOST
+IP-Adresse für den Hostnamen konnte nicht gefunden werden.
+
+@item CR_VERSION_ERROR
+Eine Protokollunverträglichkeit resultierte aus dem Versuch, sich mit einer
+Client-Bibliothek mit einem Server zu verbinden, die eine andere
+Protokollversion benutzt. Das kann passieren, wenn Sie eine sehr alte
+Client-Bibliothek benutzen und sich mit einem neuen Server verbinden, der
+nicht mit der @code{--old-protocol}-Option gestartet wurde.
+
+@item CR_NAMEDPIPEOPEN_ERROR
+Named Pipe unter Windows konnte nicht erzeugt werden.
+
+@item CR_NAMEDPIPEWAIT_ERROR
+Fehler beim Warten auf eine Named Pipe unter Windows.
+
+@item CR_NAMEDPIPESETSTATE_ERROR
+Pipe-Handler unter Windows konnte nicht erlangt werden.
+
+@item CR_SERVER_LOST
+Wenn @code{connect_timeout} > 0 ist und die Verbindung zum Server länger
+als @code{connect_timeout} benötigte, oder wenn der Server während der
+Ausführung von @code{init-command} starb.
+
+@end table
+
+@subsubheading Beispiel
+
+@example
+MYSQL mysql;
+
+mysql_init(&mysql);
+mysql_options(&mysql,MYSQL_READ_DEFAULT_GROUP,"your_prog_name");
+if (!mysql_real_connect(&mysql,"host","benutzer","passwort","datenbank",0,NULL,0))
+@{
+ fprintf(stderr, "Verbindung zur Datenbank fehlgeschlagen: Fehler: %s\n",
+ mysql_error(&mysql));
+@}
+@end example
+
+Wenn Sie @code{mysql_options()} benutzen, liest die MySQL-Bibliothek die
+@code{[client]}- und @code{ihr_programm_name}-Abschnitte in der
+@code{my.cnf}-Datei. Das stellt sicher, dass Ihr Programm funktioniert,
+selbst wenn jemand MySQL auf Nicht-Standard-Weise eingerichtet hat.
+
+Beachten Sie, dass @code{mysql_real_connect()} beim Verbinden den
+@code{reconnect}-Flag (Teil der MySQL-Struktur) auf einen Wert von @code{1}
+setzt. Dieser Flag gibt an, dass ein erneuter Verbindungsversuch zum Server
+gemacht wird, bevor aufgegeben wird, wenn eine Anfrage wegen einer verloren
+gegangenen Verbindung nicht ausgeführt werden kann.
+
+
+@node mysql_real_escape_string, mysql_real_query, mysql_real_connect, C API functions
+@c German node mysql_real_escape_string
+@subsubsection @code{mysql_real_escape_string()}
+
+@findex @code{mysql_real_escape_string()}
+
+@code{unsigned int mysql_real_escape_string(MYSQL *mysql, char *nach, const char *von, unsigned int laenge)}
+
+@subsubheading Beschreibung
+
+Diese Funktion wird benutzt, um eine zulässige SQL-Zeichenkette zu
+erzeugen, die Sie in einem SQL-Statement benutzen können.
+@xref{String syntax}.
+
+Die Zeichenkette in @code{von} wird in eine escapete SQL-Zeichenkette
+kodiert, wobei der aktuelle Zeichensatz der Verbindung berücksichtigt wird.
+Das Ergebnis wird in @code{nach} platziert und ein Null-Byte am Ende
+angefügt. Kodierte Zeichen sind @code{NUL} (ASCII 0), @samp{\n}, @samp{\r},
+@samp{\}, @samp{'}, @samp{"} und Control-Z (@pxref{Literals}).
+
+Die Zeichenkette, auf die von @code{von} gezeigt wird, muss @code{laenge}
+Bytes lang sein. Sie müssen den @code{nach}-Puffer so zuweisen, dass er
+mindestens @code{laenge*2+1} Bytes lang ist. (Im schlimmsten Fall muss
+jedes Zeichen mit zwei Bytes kodiert werden, und Sie brauchen Platz für das
+Null-Byte am Ende.) Wenn @code{mysql_escape_string()} zurückgibt, sind die
+Inhalte von @code{nach} eine Null-begrenzte Zeichenkette. Der Rückgabewert
+ist die Länge der kodierten Zeichenkette, ohne das Null-Zeichen am Ende.
+
+@subsubheading Beispiel
+
+@example
+char anfrage[1000],*end;
+
+end = strmov(anfrage,"INSERT INTO tabelle values(");
+*end++ = '\'';
+end += mysql_real_escape_string(&mysql, end,"Was is'n das?",12);
+*end++ = '\'';
+*end++ = ',';
+*end++ = '\'';
+end += mysql_real_escape_string(&mysql, end,"Binärdaten: \0\r\n",17);
+*end++ = '\'';
+*end++ = ')';
+
+if (mysql_real_query(&mysql,anfrage,(unsigned int) (end - anfrage)))
+@{
+ fprintf(stderr, "Einfügen der Zeile fehlgeschlagen, Fehler: %s\n",
+ mysql_error(&mysql));
+@}
+@end example
+
+Die im Beispiel benutzte @code{strmov()}-Funktion ist in der
+@code{mysqlclient}-Bibliothek enthalten und funktioniert wie
+@code{strcpy()}, gibt aber einen Zeiger auf Null am Ende des ersten
+Parameters zurück.
+
+@subsubheading Rückgabewerte
+
+Die Länge des Wertes in @code{nach}, ohne das Null-Zeichen am Ende.
+
+@subsubheading Fehler
+
+Keine.
+
+
+@node mysql_real_query, mysql_reload, mysql_real_escape_string, C API functions
+@c German node mysql_real_query
+@subsubsection @code{mysql_real_query()}
+
+@findex @code{mysql_real_query()}
+
+@code{int mysql_real_query(MYSQL *mysql, const char *anfrage, unsigned int laenge)}
+
+@subsubheading Beschreibung
+
+Führt die SQL-Anfrage aus, auf die von @code{anfrage} gezeigt wird, was
+eine @code{laenge} Bytes lange Zeichenkette sein sollte. Die0 Anfrage muss
+aus einem einzelnen SQL-Statement bestehen. Sie dürfen kein Semikolon
+(@samp{;}) oder @code{\g} zum Statement hinzufügen.
+
+Sie @emph{müssen} @code{mysql_real_query()} statt @code{mysql_query()} für
+Anfragen benutzen, die Binärdaten enthalten, weil Binärdaten das
+@samp{\0}-Zeichen enthalten können. Ausserdem ist @code{mysql_real_query()}
+schneller als @code{mysql_query()}, weil es in der Anfragezeichenkette
+nicht @code{strlen()} aufruft.
+
+Wenn Sie wissen wollen, ob die Anfrage eine Ergebnismenge zurückgeben
+sollte oder nicht, können Sie hierfür @code{mysql_field_count()} benutzen.
+@xref{mysql_field_count, @code{mysql_field_count}}.
+
+@subsubheading Rückgabewerte
+
+0, wenn die Anfrage erfolgreich war. Nicht-0, wenn ein Fehler auftrat.
+
+@subsubheading Fehler
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Befehle wurden nicht in der korrekten Reihenfolge ausgeführt.
+@item CR_SERVER_GONE_ERROR
+Der MySQL-Server ist weg.
+@item CR_SERVER_LOST
+Die Verbindung zum Server ging während der Anfrage verloren.
+@item CR_UNKNOWN_ERROR
+Ein unbekannter Fehler trat auf.
+@end table
+
+
+@node mysql_reload, mysql_row_seek, mysql_real_query, C API functions
+@c German node mysql_reload
+@subsubsection @code{mysql_reload()}
+
+@findex @code{mysql_reload()}
+
+@code{int mysql_reload(MYSQL *mysql)}
+
+@subsubheading Beschreibung
+
+Weist den MySQL-Server an, die Berechtigungstabellen neu zu laden. Der
+verbundene Benutzer muss die @strong{reload}-Berechtigung haben.
+
+Diese Funktion ist veraltet. Vorzugsweise sollten Sie @code{mysql_query()}
+benutzen, um statt dessen ein SQL-@code{FLUSH PRIVILEGES}-Statement
+auszuführen.
+
+@subsubheading Rückgabewerte
+
+0 bei Erfolg. Nicht-0, wenn ein Fehler auftrat.
+
+@subsubheading Fehler
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Befehle wurden nicht in der korrekten Reihenfolge ausgeführt.
+@item CR_SERVER_GONE_ERROR
+Der MySQL-Server ist weg.
+@item CR_SERVER_LOST
+Die Verbindung zum Server ging während der Anfrage verloren.
+@item CR_UNKNOWN_ERROR
+Ein unbekannter Fehler trat auf.
+@end table
+
+
+@node mysql_row_seek, mysql_row_tell, mysql_reload, C API functions
+@c German node mysql_row_seek
+@subsubsection @code{mysql_row_seek()}
+
+@findex @code{mysql_row_seek()}
+
+@code{MYSQL_ROW_OFFSET mysql_row_seek(MYSQL_RES *ergebnis, MYSQL_ROW_OFFSET offset)}
+
+@subsubheading Beschreibung
+Setzt den Zeilencursor auf eine beliebige Zeile in einer
+Anfrageergebnismenge. Dafür ist erforderlich, dass die
+Ergebnismengenstruktur das gesamte Ergebnis der Anfrage enthält, so dass
+@code{mysql_row_seek()} nur in Verbindung mit @code{mysql_store_result()}
+benutzt werden kann, nicht mit @code{mysql_use_result()}.
+
+Der Offset sollte ein Wert sein, der von einem Aufruf von
+@code{mysql_row_tell()} oder @code{mysql_row_seek()} zurückgegeben wird.
+Dieser Wert ist nicht einfach eine Zeilennummer; wenn Sie eine Zeile
+innerhalb einer Ergebnismenge mittels einer Zeilennummer suchen wollen,
+benutzen Sie statt dessen @code{mysql_data_seek()}.
+
+@subsubheading Rückgabewerte
+
+Der vorherige Wert des Zeilencursors. Dieser Wert kann an einen
+nachfolgenden Aufruf von @code{mysql_row_seek()} übergeben werden.
+
+@subsubheading Fehler
+
+Keine.
+
+
+@node mysql_row_tell, mysql_select_db, mysql_row_seek, C API functions
+@c German node mysql_row_tell
+@subsubsection @code{mysql_row_tell()}
+
+@findex @code{mysql_row_tell()}
+
+@code{MYSQL_ROW_OFFSET mysql_row_tell(MYSQL_RES *ergebnis)}
+
+@subsubheading Beschreibung
+
+Gibt die aktuelle Position des Zeilencursors für das letzte
+@code{mysql_fetch_row()} zurück. Dieser Wert kann als Argument für
+@code{mysql_row_seek()} benutzt werden.
+
+Sie sollten @code{mysql_row_tell()} nur nach @code{mysql_store_result()},
+nicht nach @code{mysql_use_result()} benutzen.
+
+@subsubheading Rückgabewerte
+
+Der aktuelle Offset des Zeilencursors.
+
+@subsubheading Fehler
+
+Keine.
+
+
+@node mysql_select_db, mysql_shutdown, mysql_row_tell, C API functions
+@c German node mysql_select_db
+@subsubsection @code{mysql_select_db()}
+
+@findex @code{mysql_select_db()}
+
+@code{int mysql_select_db(MYSQL *mysql, const char *db)}
+
+@subsubheading Beschreibung
+
+Führt dazu, dass die Datenbank, die durch @code{db} angegeben wird, die
+vorgabemäßige (aktuelle) Datenbank auf der von @code{mysql} angegebenen
+Verbindung wird. Bei nachfolgenden Anfragen ist diese Datenbank die Vorgabe
+für Tabellenverweise, die nicht explizit einen Datenbank-Spezifizierer
+enthalten.
+
+@code{mysql_select_db()} schlägt fehl, wenn der verbundene Benutzer keine
+Zugriffsrechte auf die Datenbank hat.
+
+@subsubheading Rückgabewerte
+
+0 bei Erfolg. Nicht-0, wenn ein Fehler auftrat.
+
+@subsubheading Fehler
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Befehle wurden nicht in der korrekten Reihenfolge ausgeführt.
+@item CR_SERVER_GONE_ERROR
+Der MySQL-Server ist weg.
+@item CR_SERVER_LOST
+Die Verbindung zum Server ging während der Anfrage verloren.
+@item CR_UNKNOWN_ERROR
+Ein unbekannter Fehler trat auf.
+@end table
+
+
+@node mysql_shutdown, mysql_stat, mysql_select_db, C API functions
+@c German node mysql_shutdown
+@subsubsection @code{mysql_shutdown()}
+
+@findex @code{mysql_shutdown()}
+
+@code{int mysql_shutdown(MYSQL *mysql)}
+
+@subsubheading Beschreibung
+
+Führt dazu, dass der Datenbankserver herunter fährt. Der verbundene
+Benutzer muss die @strong{shutdown}-Berechtigung haben.
+
+@subsubheading Rückgabewerte
+
+0 bei Erfolg. Nicht-0, wenn ein Fehler auftrat.
+
+@subsubheading Fehler
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Befehle wurden nicht in der korrekten Reihenfolge ausgeführt.
+@item CR_SERVER_GONE_ERROR
+Der MySQL-Server ist weg.
+@item CR_SERVER_LOST
+Die Verbindung zum Server ging während der Anfrage verloren.
+@item CR_UNKNOWN_ERROR
+Ein unbekannter Fehler trat auf.
+@end table
+
+
+@node mysql_stat, mysql_store_result, mysql_shutdown, C API functions
+@c German node mysql_stat
+@subsubsection @code{mysql_stat()}
+
+@findex @code{mysql_stat()}
+
+@code{char *mysql_stat(MYSQL *mysql)}
+
+@subsubheading Beschreibung
+
+Gibt eine Zeichenkette zurück, die Informationen enthält, die ähnlich denen
+sind, die vom @code{mysqladmin status}-Befehl zur Verfügung gestellt
+werden. Das schließt die Betriebszeit (Uptime) in Sekunden und die Anzahl
+laufender Threads, Anfragen (Questions), Neuladen (Reloads) und offener
+Tabellen ein.
+
+@subsubheading Rückgabewerte
+
+Eine Zeichenkette, die den Serverstatus beschreibt. @code{NULL}, wenn ein
+Fehler auftrat.
+
+@subsubheading Fehler
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Befehle wurden nicht in der korrekten Reihenfolge ausgeführt.
+@item CR_SERVER_GONE_ERROR
+Der MySQL-Server ist weg.
+@item CR_SERVER_LOST
+Die Verbindung zum Server ging während der Anfrage verloren.
+@item CR_UNKNOWN_ERROR
+Ein unbekannter Fehler trat auf.
+@end table
+
+
+@node mysql_store_result, mysql_thread_id, mysql_stat, C API functions
+@c German node mysql_store_result
+@subsubsection @code{mysql_store_result()}
+
+@findex @code{mysql_store_result()}
+
+@code{MYSQL_RES *mysql_store_result(MYSQL *mysql)}
+
+@subsubheading Beschreibung
+
+Sie müssen @code{mysql_store_result()} oder @code{mysql_use_result()} für
+jede Anfrage aufrufen, die erfolgreich Daten abruft (@code{SELECT},
+@code{SHOW}, @code{DESCRIBE}, @code{EXPLAIN}).
+
+Für andere Anfragen müssen Sie @code{mysql_store_result()} oder
+@code{mysql_use_result()} nicht aufrufen, es schadet aber auch nicht, noch
+führt es zu wahrnehmbaren Performance-Störungen, wenn Sie
+@code{mysql_store_result()} in jedem Fall aufrufen. Sie können feststellen,
+ob die Anfrage keine Ergebnismenge hatte, wenn Sie prüfen, ob
+@code{mysql_store_result()} 0 zurückgibt (mehr darüber später).
+
+Wenn Sie wissen wollen, ob die Anfrage eine Ergebnismenge zurückgeben
+sollte oder nicht, können Sie hierfür @code{mysql_field_count()} benutzen.
+@xref{mysql_field_count, @code{mysql_field_count}}.
+
+@code{mysql_store_result()} liest das gesamte Ergebnis einer Anfrage zum
+Client ein, weist eine @code{MYSQL_RES}-Struktur zu und platziert das
+Ergebnis in diese Struktur.
+
+@code{mysql_store_results()} gibt einen NULL-Zeiger zurück, wenn die
+Anfrage keine Ergebnismenge zurückgab (wenn die Anfrage zum Beispiel ein
+@code{INSERT}-Statement war).
+
+@code{mysql_store_results()} gibt auch einen NULL-Zeiger zurück, wenn das
+Lesen der Ergebnismenge fehlschlug. Sie können prüfen, ob Sie einen Fehler
+erhielten, wenn @code{mysql_error()} keinen NULL-Zeiger zurückgibt, wenn
+@code{mysql_errno()} ungleich 0 zurückgibt oder wenn
+@code{mysql_field_count()} ungleich 0 zurückgibt.
+
+Eine leere Ergebnismenge wird zurückgegeben, wenn keine Zeilen
+zurückgegeben werden. (Eine leere Ergebnismenge unterscheidet sich als
+Rückgabewert von einem NULL-Zeiger.)
+
+Nachdem Sie erst einmal @code{mysql_store_result()} aufgerufen und ein
+Ergebnis erhalten haben, das kein NULL-Zeiger ist, können Sie
+@code{mysql_num_rows()} aufrufen, um herauszufinden, wie viele Zeilen es in
+der Ergebnismenge gibt.
+
+Sie können @code{mysql_fetch_row()} aufrufen, um Zeilen aus der
+Ergebnismenge zu holen, oder @code{mysql_row_seek()} und
+@code{mysql_row_tell()}, um die aktuelle Zeilenposition innerhalb der
+Ergebnismenge zu erhalten oder zu setzen.
+
+Sie müssen @code{mysql_free_result()} aufrufen, wenn Sie mit der
+Ergebnismenge fertig sind.
+
+@xref{NULL mysql_store_result, , @code{NULL mysql_store_result()}}.
+
+@subsubheading Rückgabewerte
+
+Eine @code{MYSQL_RES}-Ergebnisstruktur mit den Ergebnissen. @code{NULL},
+wenn ein Fehler auftrat.
+
+@subsubheading Fehler
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Befehle wurden nicht in der korrekten Reihenfolge ausgeführt.
+@item CR_OUT_OF_MEMORY
+Kein Speicher mehr.
+@item CR_SERVER_GONE_ERROR
+Der MySQL-Server ist weg.
+@item CR_SERVER_LOST
+Die Verbindung zum Server ging während der Anfrage verloren.
+@item CR_UNKNOWN_ERROR
+Ein unbekannter Fehler trat auf.
+@end table
+
+
+@node mysql_thread_id, mysql_use_result, mysql_store_result, C API functions
+@c German node mysql_thread_id
+@subsubsection @code{mysql_thread_id()}
+
+@findex @code{mysql_thread_id()}
+
+@code{unsigned long mysql_thread_id(MYSQL *mysql)}
+
+@subsubheading Beschreibung
+
+Gibt die Thread-Kennung der aktuellen Verbindung zurück. Der Wert kann als
+Argument für @code{mysql_kill()} benutzt werden, um den Thread zu töten.
+
+Wenn die Verbindung verloren ging und Sie sich mit @code{mysql_ping()}
+erneut verbinden, ändert sich die Thread-Kennung. Das heißt, dass Sie
+nicht die Thread-Kennung holen und für spätere Benutzung speichern sollten.
+Sie sollten sie holen, wenn Sie sie benötigen.
+
+@subsubheading Rückgabewerte
+
+Die Thread-Kennung der aktuellen Verbindung.
+
+@subsubheading Fehler
+
+Keine.
+
+
+@node mysql_use_result, , mysql_thread_id, C API functions
+@c German node mysql_use_result
+@subsubsection @code{mysql_use_result()}
+
+@findex @code{mysql_use_result()}
+
+@code{MYSQL_RES *mysql_use_result(MYSQL *mysql)}
+
+@subsubheading Beschreibung
+
+Sie müssen @code{mysql_store_result()} oder @code{mysql_use_result()} für
+jede Anfrage aufrufen, die erfolgreich Daten abruft (@code{SELECT},
+@code{SHOW}, @code{DESCRIBE}, @code{EXPLAIN}).
+
+@code{mysql_use_result()} initiiert einen Ergebnismengen-Abruf, aber liest
+die Ergebnismenge nicht tatsächlich in den Client wie
+@code{mysql_store_result()}. Statt dessen muss jede Zeile individuell
+abgerufen werden, indem Aufrufe von @code{mysql_fetch_row()} durchgeführt
+werden. Das liest das Ergebnis einer Anfrage direkt vom Server, ohne es in
+einer temporären Tabelle oder einem lokalen Puffer zu speichern, was
+manchmal schneller ist und viel weniger Speicher benutzt als
+@code{mysql_store_result()}. Dem Client wird nur Speicher für die aktuelle
+Zeile zugewiesen sowie ein Kommunikationspuffer, der bis zu
+@code{max_allowed_packet} Bytes Groß werden kann.
+
+Auf der anderen Seite sollten Sie @code{mysql_use_result()} nicht benutzen,
+wenn Sie viele Verarbeitungen für jede Zeile auf der Client-Seite
+durchführen oder wenn die Ausgabe auf den Bildschirm geschickt wird, auf
+dem der Benutzer @code{^S} (stop scroll) eingeben kann. Das bindet den
+Server und verhindert, dass andere Threads irgend welche Tabellen
+aktualisieren können, von denen gerade Daten geholt werden.
+
+Wenn Sie @code{mysql_use_result()} benutzen, müssen Sie
+@code{mysql_fetch_row()} ausführen, bis ein @code{NULL}-Wert zurückgegeben
+wird, denn ansonsten werden die nicht geholten Zeilen als Teil der
+Ergebnismenge bei Ihrer nächsten Anfrage zurückgegeben. Die C-API gibt den
+Fehler @code{Commands out of sync; You can't run this command now} aus,
+wenn Sie das vergessen!
+
+Sie können @code{mysql_data_seek()}, @code{mysql_row_seek()},
+@code{mysql_row_tell()}, @code{mysql_num_rows()} oder
+@code{mysql_affected_rows()} nicht bei einem Ergebnis verwenden, das von
+@code{mysql_use_result()} zurückgegeben wird. Ausserdem dürfen Sie keine
+anderen Anfragen absetzen, bis @code{mysql_use_result()} beendet ist.
+(Nachdem Sie alle Zeilen abgeholt haben, wird @code{mysql_num_rows()}
+jedoch exakt die Anzahl der geholten Zeilen zurückgeben.)
+
+Sie müssen @code{mysql_free_result()} aufrufen, wenn Sie mit der
+Ergebnismenge fertig sind.
+
+@subsubheading Rückgabewerte
+
+Eine @code{MYSQL_RES}-Ergebnisstruktur. @code{NULL}, wenn ein Fehler
+auftrat.
+
+@subsubheading Fehler
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Befehle wurden nicht in der korrekten Reihenfolge ausgeführt.
+@item CR_OUT_OF_MEMORY
+Kein Speicher mehr.
+@item CR_SERVER_GONE_ERROR
+Der MySQL-Server ist weg.
+@item CR_SERVER_LOST
+Die Verbindung zum Server ging während der Anfrage verloren.
+@item CR_UNKNOWN_ERROR
+Ein unbekannter Fehler trat auf.
+@end table
+
+@node C Thread functions, C Embedded Server func, C API functions, C
+@c German node C-Thread-Funktionen
+@subsection C-Threaded-Funktionsbeschreibungen
+
+Sie benötigen folgende Funktionen, wenn Sie einen threaded Client erstellen
+wollen. @xref{Threaded clients}.
+
+
+@menu
+* my_init::
+* mysql_thread_init::
+* mysql_thread_end::
+@end menu
+
+@node my_init, mysql_thread_init, C Thread functions, C Thread functions
+@c German node my_init()
+@subsubsection @code{my_init()}
+
+@findex @code{my_init()}
+
+@subsubheading Beschreibung
+
+Diese Funktion muss einmal im Programm aufgerufen werden, bevor Sie irgend
+eine MySQL-Funktion aufrufen. Sie initialisiert einige globale Variablen,
+die MySQL braucht. Wenn Sie eine Thread-sichere Client-Bibliothek benutzen,
+wird diese ebenfalls @code{mysql_thread_init()} für diesen Thread aufrufen.
+
+Diese Funktion wird automatisch von @code{mysql_init()},
+@code{mysql_server_init()} und @code{mysql_connect()} aufgerufen.
+
+@subsubheading Rückgabewerte
+
+Keine.
+
+@node mysql_thread_init, mysql_thread_end, my_init, C Thread functions
+@c German node mysql_thread_init()
+@subsubsection @code{mysql_thread_init()}
+
+@findex @code{mysql_thread_init()}
+
+@subsubheading Beschreibung
+
+Diese Funktion muss für jeden erzeugten Thread aufgerufen werden, um
+Thread-spezifische Variablen zu initialisieren.
+
+Diese Funktion wird automatisch von @code{my_init()} und
+@code{mysql_connect()} aufgerufen.
+
+@subsubheading Rückgabewerte
+
+Keine.
+
+@node mysql_thread_end, , mysql_thread_init, C Thread functions
+@c German node mysql_thread_end()
+@subsubsection @code{mysql_thread_end()}
+
+@findex @code{mysql_thread_end()}
+
+@subsubheading Beschreibung
+
+Diese Funktion muss vor dem Aufruf von @code{pthread_exit()} aufgerufen
+werden, um den von @code{mysql_thread_init()} zugewiesenen Speicher
+freizusetzen.
+
+Beachten Sie, dass diese Funktion @strong{nicht automatisch} von der
+Client-Bibliothek aufgerufen wird. Sie muss explizit aufgerufen werden, um
+Speicherlecks zu vermeiden.
+
+@subsubheading Rückgabewerte
+
+Keine.
+
+@node C Embedded Server func, C API problems, C Thread functions, C
+@c German node C-Embedded-Server-Funktionen
+@subsection C-Embedded-Server-Funktionsbeschreibungen
+
+Sie müssen folgende Funktionen benutzen, wenn Sie wollen, dass Ihre
+Applikation gegen die eingebettete MySQL-Server-Bibliothek gelinkt werden
+kann. @xref{libmysqld}.
+
+Wenn das Programm mit @code{-lmysqlclient} anstelle von @code{-lmysqld}
+gelinkt wird, tun diese Funktionen nicht. Das ermöglicht die Auswahl
+zwischen der Benutzung des eingebetteten MySQL-Servers und eines
+Standalone-Servers, ohne irgend welchen Code zu verändern.
+
+
+@menu
+* mysql_server_init::
+* mysql_server_end::
+@end menu
+
+@node mysql_server_init, mysql_server_end, C Embedded Server func, C Embedded Server func
+@c German node mysql_server_init()
+@subsubsection @code{mysql_server_init()}
+
+@findex @code{mysql_server_init()}
+
+@code{void mysql_server_init(int argc, const char **argv, const char **groups)}
+
+@subsubheading Beschreibung
+
+Diese Funktion @strong{muss} einmal im Programm aufgerufen werden, bevor
+irgend eine andere MySQL-Funktion aufgerufen wird. Sie startet den Server
+und initialisiert jegliche Subsysteme (@code{mysys}, InnoDB usw.), die der
+Server benutzt. Wenn diese Funktion nicht aufgerufen wird, stürzt das
+Programm ab.
+
+Die @code{argc}- und @code{argv}-Argumente sind analog zu den Argumenten
+für @code{main()}. Das erste Element von @code{argv} wird ignoriert (es
+enthält typischerweise den Programmnamen). Aus Bequemlichkeitsgründen kann
+@code{argc} @code{0} sein, wenn es keine Kommandozeilenargumente für den
+Server gibt.
+
+Die @code{NULL}-begrenzte Liste von Zeichenketten in @code{groups} wählt
+aus, welche Gruppen in den Optionsdateien aktiv sind.
+@xref{Option files}. Aus Bequemlichkeitsgründen kann @code{groups}
+@code{NULL} sein. In diesem Fall ist die @code{[server]}-Gruppe aktiv.
+
+@subsubheading Beispiel
+
+@example
+#include <mysql.h>
+#include <stdlib.h>
+
+static char *server_args[] = @{
+ "Mein Programm", /* Diese Zeichenkette ist unbenutzt */
+ "--datadir=.",
+ "--set-variable=key_buffer_size=32M"
+@};
+static char *server_groups[] = @{
+ "server",
+ "Dieser_Programm_SERVER",
+ (char *)NULL
+@};
+
+int main(void) @{
+ mysql_server_init(sizeof(server_args) / sizeof(char *),
+ server_args, server_groups);
+
+ /* Hier können Sie irgend welche MySQL-API-Funktionen benutzen */
+
+ mysql_server_end();
+
+ return EXIT_SUCCESS;
+@}
+@end example
+
+@subsubheading Rückgabewerte
+
+Keine.
+
+@node mysql_server_end, , mysql_server_init, C Embedded Server func
+@c German node mysql_server_end()
+@subsubsection @code{mysql_server_end()}
+
+@findex @code{mysql_server_end()}
+
+@subsubheading Beschreibung
+
+Diese Funktion @strong{muss} einmal im Programm nach allen anderen
+MySQL-Funktionen aufgerufen werden. Sie fährt den eingebetteten Server
+herunter.
+
+@subsubheading Rückgabewerte
+
+Keine.
+
+@node C API problems, Building clients, C Embedded Server func, C
+@c German node C-API-Probleme
+@subsection Häufige Fragen und Probleme bei der Benutzung der C-API
+
+@tindex @code{mysql_query()}
+@tindex @code{mysql_store_result()}
+
+
+
+@menu
+* NULL mysql_store_result::
+* Query results::
+* Getting unique ID::
+* C API linking problems::
+@end menu
+
+@node NULL mysql_store_result, Query results, C API problems, C API problems
+@c German node NULL mysql_store_result
+@subsubsection Warum gibt @code{mysql_store_result()} manchmal @code{NULL} zurück, nachdem @code{mysql_query()} Erfolg zurückgegeben hat?
+
+@code{mysql_store_result()} kann @code{NULL} zurückgeben, auch nach einem
+erfolgreichen Aufruf von @code{mysql_query()}. Wenn das passiert, bedeutet
+das, dass eine der folgenden Bedingungen eingetreten ist:
+
+@itemize @bullet
+@item
+Es gab einen @code{malloc()}-Fehler (zum Beispiel, wenn die Ergebnismenge
+zu Groß war).
+
+@item
+Die Daten konnten nicht gelesen werden (ein Fehler mit der Verbindung trat
+auf).
+
+@item
+Die Anfrage gab keine Daten zurück (sie war zum Beispiel ein @code{INSERT},
+@code{UPDATE} oder @code{DELETE}).
+@end itemize
+
+Sie können jederzeit prüfen, ob das Statement eine leere Ergebnismenge
+geliefert haben sollte oder nicht, indem Sie @code{mysql_field_count()}
+aufrufen. Wenn @code{mysql_field_count()} 0 zurückliefert, ist das Ergebnis
+leer und die letzte Anfrage war ein Statement, die keine Rückgabewerte
+liefert (zum Beispiel ein @code{INSERT} oder ein @code{DELETE}). Wenn
+@code{mysql_field_count()} einen Nicht-0-Wert zurückgibt, hätte das
+Statement ein nicht leeres Ergebnis zurückliefern sollen. Sehen Sie in der
+Beschreibung von @code{mysql_field_count()}-Funktion wegen eines Beispiels
+nach.
+
+Sie können durch Aufruf von @code{mysql_error()} oder @code{mysql_errno()}
+auf einen Fehler überprüfen.
+
+@cindex Anfragen, C-API-Ergebnisse
+
+
+@node Query results, Getting unique ID, NULL mysql_store_result, C API problems
+@c German node Anfrageergebnisse
+@subsubsection Welche Ergebnisse kann ich von einer Anfrage bekommen?
+
+Zusätzlich zur Ergebnismenge, die von einer Anfrage zurückgegeben wird,
+können Sie auch folgende Informationen bekommen:
+
+@itemize @bullet
+@item
+@code{mysql_affected_rows()} gibt die Anzahl von Zeilen zurück, die durch
+die letzte Anfrage betroffen wurden, wenn Sie ein @code{INSERT},
+@code{UPDATE} oder @code{DELETE} ausführen. Eine Ausnahme besteht darin,
+wenn @code{DELETE} ohne eine @code{WHERE}-Klausel benutzt wird. In diesem
+Fall wird die Tabelle leer neu erzeugt, was viel schneller ist! Daher gibt
+@code{mysql_affected_rows()} 0 für die Anzahl betroffener Datensätze
+zurück.
+
+@item
+@code{mysql_num_rows()} gibt die Anzahl von Zeilen in einer Ergebnismenge
+zurück. Bei @code{mysql_store_result()} kann @code{mysql_num_rows()}
+aufgerufen werden, sobald @code{mysql_store_result()} etwas zurückgibt. Bei
+@code{mysql_use_result()} kann @code{mysql_num_rows()} erst aufgerufen
+werden, nachdem Sie alle Zeilen mit @code{mysql_fetch_row()} geholt haben.
+
+@item
+@code{mysql_insert_id()} gibt die Kennung zurück, die von der letzten
+Anfrage erzeugt wurde, die eine Zeile in eine Tabelle mit einem
+@code{AUTO_INCREMENT}-Index einfügte. @xref{mysql_insert_id, ,
+@code{mysql_insert_id()}}.
+
+@item
+Einige Anfragen (@code{LOAD DATA INFILE ...}, @code{INSERT INTO ... SELECT
+...}, @code{UPDATE}) geben zusätzliche Informationen zurück. Das Ergebnis
+wird von @code{mysql_info()} zurückgegeben. Siehe die Beschreibung für
+@code{mysql_info()} hinsichtlich des Formats der Zeichenkette, die diese
+Funktion zurückgibt. @code{mysql_info()} gibt einen @code{NULL}-Zeiger
+zurück, wenn es keine zusätzlichen Informationen gibt.
+@end itemize
+
+
+@node Getting unique ID, C API linking problems, Query results, C API problems
+@c German node Eindeutige Kennung erhalten
+@subsubsection Wie erhalte ich die eindeutige Kennung für die letzte eingefügte Zeile?
+
+@cindex eindeutige Kennung
+@cindex letzte Zeile, eindeutige Kennung
+@cindex Kennung, eindeutige
+@cindex Tabellen, eindeutige Kennung für die letzte Zeile
+
+Wenn Sie einen Datensatz in eine Tabelle einfügen, der eine Spalte enthält,
+die das @code{AUTO_INCREMENT}-Attribut hat, erhalten Sie die letzte
+erzeugte Kennung durch Aufruf der @code{mysql_insert_id()}-Funktion.
+
+Sie können die Kennung auch dadurch abrufen, dass Sie die
+@code{LAST_INSERT_ID()}-Funktion in einer Anfrage-Zeichenkette verwenden,
+die Sie an @code{mysql_query()} übergeben.
+
+Sie können überprüfen, ob ein @code{AUTO_INCREMENT}-Index benutzt wird,
+wenn Sie folgenden Code ausführen. Er prüft auch, ob die Anfrage ein
+@code{INSERT} mit einem @code{AUTO_INCREMENT}-Index war:
+
+@example
+if (mysql_error(&mysql)[0] == 0 &&
+ mysql_num_fields(ergebnis) == 0 &&
+ mysql_insert_id(&mysql) != 0)
+@{
+ used_id = mysql_insert_id(&mysql);
+@}
+@end example
+
+Die letzte erzeugte Kennung wird im Server auf der Grundlage der jeweiligen
+Verbindung gewartet. Sie wird nicht durch andere Clients geändert. Sie wird
+nicht einmal geändert, wenn Sie eine andere @code{AUTO_INCREMENT}-Spalte
+mit einem nicht magischen Wert aktualisieren (einem Wert, der nicht
+@code{NULL} und nicht @code{0} ist).
+
+Wenn Sie die Kennung benutzen wollen, die für eine Tabelle erzeugt wurde,
+um sie in eine zweite Tabelle einzufügen, können Sie SQL-Statements wie
+folgt benutzen:
+
+@example
+INSERT INTO foo (auto,text)
+ VALUES(NULL,'text'); # Kennung durch Einfügen von NULL erzeugen
+INSERT INTO foo2 (id,text)
+ VALUES(LAST_INSERT_ID(),'text'); # Kennung in zweiter Tabelle benutzen
+@end example
+
+
+@node C API linking problems, , Getting unique ID, C API problems
+@c German node C-API-Linking-Probleme
+@subsubsection Probleme beim Linken mit der C-API
+
+@cindex Linken, Probleme
+@cindex C-API, Link-Probleme
+
+Wenn Sie mit der C-API linken, können auf manchen Systemen folgende Fehler
+auftreten:
+
+@example
+gcc -g -o client test.o -L/usr/local/lib/mysql -lmysqlclient -lsocket -lnsl
+
+Undefined first referenced
+ symbol in file
+floor /usr/local/lib/mysql/libmysqlclient.a(password.o)
+ld: fatal: Symbol referencing errors. No output written to client
+@end example
+
+Wenn das auf Ihrem System passiert, müssen Sie die math-Bibliothek
+einschließen, indem Sie @code{-lm} am Ende der Kompilier- / Link-Zeile
+hinzufügen.
+
+
+@node Building clients, Threaded clients, C API problems, C
+@c German node Clients bauen
+@subsection Client-Programme bauen
+
+@cindex Client-Programme, bauen
+@cindex linken
+@cindex bauen, Client-Programme
+@cindex Programme, Client
+
+Wenn Sie MySQL-Clients kompilieren, die Sie selbst geschrieben oder von
+Dritten erhalten haben, müssen diese mit der @code{-lmysqlclient
+-lz}-Option für den Link-Befehl gelinkt werden. Eventuell sollten Sie auch
+eine @code{-L}-Option verwenden, um dem Linker mitzuteilen, wo sich die
+Bibliothek befindet. Wenn zum Beispiel die Bibliothek in
+@file{/usr/local/mysql/lib} installiert ist, benutzen Sie
+@code{-L/usr/local/mysql/lib -lmysqlclient -lz} für den Link-Befehl.
+
+Für Clients, die MySQL-Header-Dateien benutzen, müssen Sie eventuell eine
+@code{-I}-Option angeben, wenn Sie sie kompilieren (zum Beispiel
+@code{-I/usr/local/mysql/include}), so dass der Kompiler die Header-Dateien
+finden kann.
+
+
+@node Threaded clients, libmysqld, Building clients, C
+@c German node Threaded Clients
+@subsection Wie man einen threaded Client herstellt
+
+@cindex Clients, Threaded
+@cindex Threaded Clients
+
+Die Client-Bibliothek ist fast Thread-sicher. Das größte Problem besteht
+darin, dass die Subroutinen in @file{net.c}, die von Sockets lesen, nicht
+Interrupt-sicher sind. Das wurde mit dem Hintergedanken gemacht, dass Sie
+eventuell Ihre eigenen Alarme haben möchten, die ein langes Lesen vom
+Server unterbrechen können. Wenn Sie Interrupt-Handler für den
+@code{SIGPIPE}-Interrupt installieren, sollte die Socket-Handhabung
+Thread-sicher sein.
+
+In den älteren Binärdistributionen wurden die Client-Bibliotheken
+normalerweise nicht mit der Thread-sicheren Option kompiliert (die
+Windows-Binärdateien sind vorgabemäßig Thread-sicher kompiliert). Neuere
+Binärdistributionen sollten sowohl eine normale als auch eine
+Thread-sichere Client-Bibliothek haben.
+
+Um einen threaded Client zu erhalten, bei dem Sie den Client durch andere
+Threads unterbrechen (interrupt) und Zeitüberschreitungen (Timeouts) setzen
+können, wenn Sie mit dem MySQL-Server kommunizieren, sollten Sie die
+@code{-lmysys}-, @code{-lstring}-, und @code{-ldbug}-Bibliotheken und den
+@code{net_serv.o}-Code benutzen, den der Server benutzt.
+
+Wenn Sie keine Unterbrechungen (Interrupts) oder Zeitüberschreitungen
+(Timeouts) benötigen, können Sie einfach eine Thread-sicher
+Client-Bibliothek @code{(mysqlclient_r)} kompilieren und diese benutzen.
+@xref{C,,MySQL-C-API}. In diesem Fall müssen Sie sich nicht um die
+@code{net_serv.o}-Objektdatei oder die anderen MySQL-Bibliotheken kümmern.
+
+Wenn Sie einen threaded Client benutzen und Unterbrechungen (Interrupts)
+und Zeitüberschreitungen (Timeouts) benutzen wollen, können Sie in
+umfangreicher Weise die Routinen in der @file{thr_alarm.c}-Datei benutzen.
+Wenn Sie Routinen aus der @code{mysys}-Bibliothek benutzen, müssen Sie
+lediglich daran denken, @code{my_init()} zuerst aufzurufen!
+@xref{C Thread functions}.
+
+Alle Funktionen ausser @code{mysql_real_connect()} sind vorgabemäßig
+Thread-sicher. Die folgenden Hinweise beschreiben, wie man eine
+Thread-sichere Client-Bibliothek kompiliert und sie auf Thread-sichere
+Weise benutzt. (Die unten stehenden Hinweise für
+@code{mysql_real_connect()} beziehen sich in der Tat auch auf
+@code{mysql_connect()}. Weil aber @code{mysql_connect()} veraltet ist,
+sollten Sie in jedem Fall @code{mysql_real_connect()} benutzen.)
+
+Um @code{mysql_real_connect()} Thread-sicher zu machen, müssen Sie die
+Client-Bibliothek mit diesem Befehl neu kompilieren:
+
+@example
+shell> ./configure --enable-thread-safe-client
+@end example
+
+Das erzeugt eine Thread-sichere Client-Bibliothek @code{libmysqlclient_r}.
+@code{--enable-thread-safe-client}. Diese Bibliothek ist pro Verbindung
+Thread-sicher. Sie können zwei Threads dieselbe Verbindung benutzen lassen,
+solange Sie folgendes tun:
+
+@itemize @bullet
+@item
+Zwei Threads können zur gleichen Zeit keine Anfrage an MySQL über dieselbe
+Verbindung schicken. Insbesondere müssen Sie sicherstellen, dass zwischen
+einem @code{mysql_query()} und einem @code{mysql_store_result()} kein
+anderer Thread dieselbe Verbindung benutzt.
+@item
+Viele Threads können auf unterschiedliche Ergebnismengen zugreifen, die mit
+@code{mysql_store_result()} abgerufen wurden.
+@item
+Wenn Sie @code{mysql_use_result} benutzen, müssen Sie sicherstellen, dass
+kein anderer Thread irgend etwas über dieselbe Verbindung anfragt, bis die
+Ergebnismenge geschlossen wurde. Für threaded Clients, die dieselbe
+Verbindung benutzen, ist es jedoch am besten, @code{mysql_use_result()} zu
+benutzen.
+@item
+
+Wenn Sie mehrfache Threads über dieselbe Verbindung benutzen wollen, müssen
+Sie eine mutex-Sperre um Ihre @code{mysql_query()}- und
+@code{mysql_store_result()}-Aufruf-Kombination haben. Sobald
+@code{mysql_store_result()} fertig ist, kann die Sperre aufgehoben werden
+und andere Threads können über dieselbe Verbindung anfragen.
+@item
+Wenn Sie mit POSIX-Threads programmieren, können Sie
+@code{pthread_mutex_lock()} und @code{pthread_mutex_unlock()} benutzen, um
+eine mutex-Sperre aufzubauen und aufzuheben.
+@end itemize
+
+Sie müssen folgendes wissen, wenn Sie einen Thread haben, der
+MySQL-Funktionen aufruft, dieser Thread aber keine Verbindung zur
+MySQL-Datenbank aufgebaut hat:
+
+Wenn Sie @code{mysql_init()} oder @code{mysql_connect()} aufrufen, erzeugt
+MySQL eine Thread-spezifische Variable für diesen Thread, die von der
+Debug-Bibliothek benutzt wird (unter anderem).
+
+Wenn Sie in einem Thread-Aufruf eine MySQL-Funktion haben, bevor ein Thread
+@code{mysql_init()} oder @code{mysql_connect()} aufgerufen hat, hat der
+Thread nicht notwendigerweise Thread-spezifische Variablen zur Hand, und
+Sie werden wahrscheinlich früher oder später einen Coredump erhalten.
+
+Damit alles reibungslos funktioniert, müssen Sie folgendes tun:
+
+@enumerate
+@item
+Rufen Sie bei Programmbeginn @code{my_init()} auf, wenn Ihr Programm
+irgend welche MySQL-Funktion vor dem Aufruf von @code{mysql_real_connect()}
+benutzt.
+@item
+Rufen Sie @code{mysql_thread_init()} im Thread-Handler auf, bevor Sie
+irgend welche MySQL-Funktionen aufrufen.
+@item
+Rufen Sie im Thread @code{mysql_thread_end()} auf, bevor Sie
+@code{pthread_exit()} aufrufen. Das gibt Speicher frei, der von
+MySQL-Thread-spezifischen Variablen benutzt wird.
+@end enumerate
+
+Eventuell erhalten Sie Fehler wegen undefinierter Symbole, wenn Sie Ihren
+Client mit @code{mysqlclient_r} linken. In den meisten Fällen liegt das
+daran, dass Sie die Thread-Bibliotheken nicht auf der Link- /
+Kompilierzeile eingeschlossen haben.
+
+@node libmysqld, , Threaded clients, C
+@c German node libmysqld
+@subsection libmysqld, die eingebettete MySQL-Server-Bibliothek
+
+@cindex libmysqld
+@cindex eingebettete MySQL-Server-Bibliothek
+
+
+@menu
+* libmysqld overview::
+* libmysqld compiling::
+* libmysqld example::
+* libmysqld licensing::
+@end menu
+
+@node libmysqld overview, libmysqld compiling, libmysqld, libmysqld
+@c German node libmysqld Überblick
+@subsubsection Überblick über die eingebettete MySQL-Server-Bibliothek
+
+Die eingebettete MySQL-Server-Bibliothek ermöglicht es, einen MySQL-Server
+mit allen Features innerhalb einer Client-Applikation laufen zu lassen. Die
+hauptsächlichen Vorteile sind erhöhte Geschwindigkeit und einfachere
+Verwaltung eingebetteter Applikationen.
+
+@node libmysqld compiling, libmysqld example, libmysqld overview, libmysqld
+@c German node libmysqld kompilieren
+@subsubsection Programme mit @code{libmysqld} kompilieren
+
+Momentan müssen alle unterstützten Bibliotheken explizit aufgelistet
+werden, wenn Sie mit @code{-lmysqld} linken. In Zukunft wird
+@code{mysql_config --libmysqld-libs} die Bibliotheken benennen, um das zu
+erleichtern. Darüber hinaus werden alle unterstützten Bibliotheken
+wahrscheinlich in libmysqld eingeschlossen werden, um dies noch weiter zu
+vereinfachen.
+
+Die korrekten Flags zum Kompilieren und Linken eines threaded Programms
+müssen benutzt werden, selbst wenn Sie nicht direkt irgend welche
+Thread-Funktionen in Ihrem Code aufrufen.
+
+@node libmysqld example, libmysqld licensing, libmysqld compiling, libmysqld
+@c German node libmysqld Beispiel
+@subsubsection Ein einfaches Embedded-Server-Beispiel
+
+Dieses Beispiel-Programm und makefile sollten ohne Änderungen auf einem
+Linux- oder FreeBSD-System funktionieren. Bei anderen Betriebssystemen sind
+kleinere Änderungen notwendig. Dieses Beispiel ist so angelegt, dass
+genügend Details dargestellt werden, um die Problematik zu verstehen, ohne
+zu viel "Verwirrendes" einzubringen, das Teil einer echten Applikation ist.
+
+Um das Beispiel auszuprobieren, erzeugen Sie ein @file{example}-Verzeichnis
+auf derselben Ebene wie das mysql-4.0-Quell-Verzeichnis. Speichern Sie die
+@file{example.c}-Quelle und das @file{GNUmakefile} im Verzeichnis und
+lassen Sie GNU-@file{make} innerhalb des @file{example}-Verzeichnisses
+laufen.
+
+@file{example.c}
+@example
+/*
+ * Ein einfacher Beispiel-Client, der die eingebettete
+ * MySQL-Server-Bibliothek benutzt
+ */
+
+#include <mysql.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+enum on_error @{ E_okay, E_warn, E_fail @};
+
+static void die(MYSQL *db, char *fmt, ...);
+MYSQL *db_connect(const char *dbname);
+void db_disconnect(MYSQL *db);
+void db_do_Anfrage(MYSQL *db, const char *query, enum on_error on_error);
+
+const char *server_groups[] = @{ "test_client_SERVER", "server", NULL @};
+
+int
+main(int argc, char **argv)
+@{
+ MYSQL *one, *two;
+
+ /* Das muss vor allen weiteren mysql-Funktionen aufgerufen werden.
+ *
+ * Sie können mysql_server_init(0, NULL, NULL) benutzen,
+ * was den Server initialisiert und die Gruppen
+ * groups = @{ "server", NULL @} benutzt.
+ *
+ * In Ihre $HOME/.my.cnf-Datei sollten Sie folgendes eintragen:
+
+[test_client_SERVER]
+language = /pfad/zur/quelle/von/mysql/sql/share/english
+
+ * Natürlich können Sie auch argc und argv ändern,
+ * bevor Sie sie an diese Funktion übergeben.
+ * Oder erzeugen Sie neue auf jede Art, die Sie wollen.
+ * Alle Argumente in argv (ausser argv[0], was der Programmname ist)
+ * müssen allerdings gültige Optionen für den MySQL-Server sein.
+ * Wenn Sie diesen Client gegen die normale mysqlclient-
+ * Bibliothek linken, ist diese Funktion nur ein Stumpf, der nichts tut.
+ */
+ mysql_server_init(argc, argv, server_groups);
+
+ one = db_connect("test");
+ two = db_connect(NULL);
+
+ db_do_query(one, "show table status", E_fail);
+ db_do_query(two, "show databases", E_fail);
+
+ mysql_close(two);
+ mysql_close(one);
+
+ /* Folgendes muss nach allen anderen mysql-Funktionen aufgerufen werden */
+ mysql_server_end();
+
+ exit(EXIT_SUCCESS);
+@}
+
+void
+die(MYSQL *db, char *fmt, ...)
+@{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ putc('\n', stderr);
+ if (db)
+ db_disconnect(db);
+ exit(EXIT_FAILURE);
+@}
+
+MYSQL *
+db_connect(const char *dbname)
+@{
+ MYSQL *db = mysql_init(NULL);
+ if (!db)
+ die(db, "mysql_init fehlgeschlagen: kein Speicher mehr");
+ mysql_options(db, MYSQL_READ_DEFAULT_GROUP, "simple");
+ if (!mysql_real_connect(db, NULL, NULL, NULL, dbname, 0, NULL, 0))
+ die(db, "mysql_real_connect fehlgeschlagen: %s", mysql_error(db));
+
+ return db;
+@}
+
+void
+db_disconnect(MYSQL *db)
+@{
+ mysql_close(db);
+@}
+
+/*
+ * show_query: Dieser Code ist aus mysql.cc. Diese Funktion
+ * ist dafür gedacht, intern für db_do_query() benutzt zu werden.
+ */
+static char *
+show_query(MYSQL *db)
+@{
+ MYSQL_RES *res;
+ MYSQL_FIELD *field;
+ MYSQL_ROW row;
+ char sep[256], *psep = sep;
+ char *is_num = 0;
+ char *err = 0;
+ unsigned int length = 1; /* anfangs "|" */
+ unsigned int off;
+
+ if (!(res = mysql_store_result(db)))
+ return mysql_error(db);
+
+ if (!(is_num = malloc(mysql_num_fields(res))))
+ @{
+ err = "Kein Speicher mehr";
+ goto err;
+ @}
+
+ /* set up */
+ *psep++ = '+';
+ while ((field = mysql_fetch_field(res)))
+ @{
+ unsigned int len = strlen(field->name);
+ if (len < field->max_length)
+ len = field->max_length;
+ if (len < 2 && !IS_NOT_NULL(field->flags))
+ len = 2; /* \N */
+ field->max_length = len + 1; /* die API verbiegen ... */
+ len += 2; length += len + 1; /* " " davor, " |" danach */
+ if (length >= 255)
+ @{
+ err = "Zeile zu lang";
+ goto err;
+ @}
+ memset(psep, '-', len); psep += len;
+ *psep++ = '+';
+ *psep = '\0';
+ @}
+
+ /* Spaltenüberschriften */
+ puts(sep);
+ mysql_field_seek(res,0);
+ fputc('|',stdout);
+ für (off=0; (field = mysql_fetch_field(res)) ; off++)
+ @{
+ printf(" %-*s|",field->max_length, field->name);
+ is_num[off]= IS_NUM(field->type);
+ @}
+ fputc('\n',stdout);
+ puts(sep);
+
+ /* Zeilen */
+ while ((row = mysql_fetch_row(res)))
+ @{
+ (void) fputs("|",stdout);
+ mysql_field_seek(res,0);
+ for (off=0 ; off < mysql_num_fields(res); off++)
+ @{
+ field = mysql_fetch_field(res);
+ printf(is_num[off] ? "%*s |" : " %-*s|",
+ field->max_length, row[off] ? (char*) row[off] : "NULL");
+ @}
+ (void) fputc('\n',stdout);
+ @}
+ puts(sep);
+
+err:
+ if (is_num)
+ free(is_num);
+ mysql_free_result(res);
+
+ return err;
+@}
+
+void
+db_do_query(MYSQL *db, const char *query, enum on_error on_error)
+@{
+ char *err = 0;
+ if (mysql_query(db, query) != 0)
+ goto err;
+
+ if (mysql_field_count(db) > 0)
+ @{
+ if ((err = show_query(db)))
+ goto err;
+ @}
+ else if (mysql_affected_rows(db))
+ printf("Betroffene Zeilen: %lld [%s]\n", mysql_affected_rows(db), query);
+
+ return;
+
+err:
+ switch (on_error) @{
+ case E_okay:
+ break;
+ case E_warn:
+ fprintf(stderr, "db_do_query fehlgeschlagen: %s [%s]\n",
+ err ? err : mysql_error(db), query);
+ break;
+ case E_fail:
+ die(db, "db_do_query fehlgeschlagen: %s [%s]",
+ err ? err : mysql_error(db), query);
+ break;
+ @}
+@}
+@end example
+
+@file{GNUmakefile}
+@example
+# Platzieren Sie diese in Ihr mysql-Quell-Verzeichnis
+m := ../mysql-4.0
+
+CC := cc
+CPPFLAGS := -I$m/include -D_thread_SAFE -D_REENTRANT
+CFLAGS := -g -W -Wall
+LDFLAGS := -static
+LDLIBS = $(embed_libs) -lz -lm -lcrypt
+
+ifneq (,$(shell grep FreeBSD /COPYRIGHT 2>/dev/null))
+# FreeBSD
+LDFLAGS += -pThread
+else
+# Linux wird angenommen
+LDLIBS += -lpThread
+endif
+
+
+# Standard-Bibliotheken
+
+embed_libs := \
+ $m/libmysqld/.libs/libmysqld.a \
+ $m/isam/libnisam.a \
+ $m/myisam/libmyisam.a \
+ $m/heap/libheap.a \
+ $m/merge/libmerge.a \
+ $m/myisammrg/libmyisammrg.a
+
+
+# Optional gebaute Bibliotheken
+
+ifneq (,$(shell test -r $m/innobase/usr/libusr.a && echo "yes"))
+embed_libs += \
+ $m/innobase/usr/libusr.a \
+ $m/innobase/odbc/libodbc.a \
+ $m/innobase/srv/libsrv.a \
+ $m/innobase/que/libque.a \
+ $m/innobase/srv/libsrv.a \
+ $m/innobase/dict/libdict.a \
+ $m/innobase/ibuf/libibuf.a \
+ $m/innobase/row/librow.a \
+ $m/innobase/pars/libpars.a \
+ $m/innobase/btr/libbtr.a \
+ $m/innobase/trx/libtrx.a \
+ $m/innobase/read/libread.a \
+ $m/innobase/usr/libusr.a \
+ $m/innobase/buf/libbuf.a \
+ $m/innobase/ibuf/libibuf.a \
+ $m/innobase/eval/libeval.a \
+ $m/innobase/log/liblog.a \
+ $m/innobase/fsp/libfsp.a \
+ $m/innobase/fut/libfut.a \
+ $m/innobase/fil/libfil.a \
+ $m/innobase/lock/liblock.a \
+ $m/innobase/mtr/libmtr.a \
+ $m/innobase/page/libpage.a \
+ $m/innobase/rem/librem.a \
+ $m/innobase/thr/libthr.a \
+ $m/innobase/com/libcom.a \
+ $m/innobase/sync/libsync.a \
+ $m/innobase/data/libdata.a \
+ $m/innobase/mach/libmach.a \
+ $m/innobase/ha/libha.a \
+ $m/innobase/dyn/libdyn.a \
+ $m/innobase/mem/libmem.a \
+ $m/innobase/sync/libsync.a \
+ $m/innobase/ut/libut.a \
+ $m/innobase/os/libos.a \
+ $m/innobase/ut/libut.a
+endif
+
+ifneq (,$(shell test -r $m/bdb/build_unix/libdb.a && echo "yes"))
+embed_libs += $m/bdb/build_unix/libdb.a
+endif
+
+
+# Unterstützte Bibliotheken
+
+embed_libs += \
+ $m/mysys/libmysys.a \
+ $m/strings/libmystrings.a \
+ $m/dbug/libdbug.a \
+ $m/regex/libregex.a
+
+
+# Optional gebaute unterstützte Bibliotheken
+
+ifneq (,$(shell test -r $m/readline/libreadline.a && echo "yes"))
+embed_libs += $m/readline/libreadline.a
+endif
+
+# Das funktioniert bei einfachen Ein-Datei-Test-Programmen
+sources := $(wildcard *.c)
+objects := $(patsubst %c,%o,$(sources))
+targets := $(basename $(sources))
+
+all: $(targets)
+
+clean:
+ rm -f $(targets) $(objects) *.core
+@end example
+
+@node libmysqld licensing, , libmysqld example, libmysqld
+@c German node libmysqld Lizensierung
+@subsubsection Lizensierung des eingebetteten Servers
+
+Der MySQL-Quelltext wird von der GNU-GPL-Lizenz abgedeckt
+(@pxref{GPL license}). Eine Folge davon ist, dass jegliches Programm, das
+durch Linken mit @code{libmysqld} den MySQL-Quelltext enthält, als freie
+Software (unter einer mit der GPL kompatiblen Lizenz) veröffentlicht werden
+muss.
+
+Wir ermutigen jeden, freie Software durch Veröffentlichung von Code unter
+der GPL oder einer kompatiblen Lizenz zu fördern. Für diejenigen, die dazu
+nicht in der Lage sind, ist eine weitere Option, den MySQL-Code von MySQL
+AB unter einer lockereren Lizenz zu erwerben. Wegen Details betreffs dieses
+Themas siehe unter @ref{Lizenzpolitik}.
+
+@node Cplusplus, Java, C, Clients
+@c German node Cplusplus
+@section MySQL-C++-APIs
+
+
+
+@cindex C++-APIs
+
+Zwei APIs sind im
+MySQL-@uref{http://www.mysql.com/Downloads/Contrib/,Contrib-Verzeichnis}
+verfügbar.
+
+
+@menu
+* Borland C++::
+@end menu
+
+@node Borland C++, , Cplusplus, Cplusplus
+@c German node Borland C++
+@subsection Borland C++
+
+@cindex Borland C++-Kompiler
+
+Sie können den MySQL-Windows-Quellcode mit Borlund C++ 5.02 kompilieren.
+(Der Windows-Quellcode beinhaltet nur Projekte für Microsoft VC++, für
+Borland C++ müssen Sie die Projektdateien selbst erstellen).
+
+Ein bekanntes Problem bei Borland C++ ist, dass es eine andere
+Strukturanordnung benutzt als VC++. Das bedeutet, dass Sie Probleme
+bekommen, wenn Sie versuchen, die vorgabemäßigen
+@code{libmysql.dll}-Bibliotheken (die mit VC++ kompiliert wurden) mit
+Borland C++ zu verwenden. Sie können eins der folgenden Dinge tun, um
+dieses Problem zu vermeiden:
+
+@itemize @bullet
+@item
+Sie können statische MySQL-Bibliotheken für Borland C++ verwenden, die Sie
+unter @uref{http://www.mysql.com/downloads/os-win32.html} finden.
+@item
+Rufen Sie @code{mysql_init()} nur mit @code{NULL} als Argument auf, kein
+vorher zugewiesenes (prä-alloziertes) MySQL-Strukt.
+@end itemize
+
+
+@node Java, Python, Cplusplus, Clients
+@c German node Java
+@section MySQL Java Connectivity (JDBC)
+
+@cindex Java-Connectivity
+@cindex JDBC
+
+Es gibt 2 unterstützte JDBC-Treiber für MySQL (den mm-Treiber und den
+Reisin JDBC-Treiber). Sie finden den mm-Treiber unter
+@uref{http://mmmysql.sourceforge.net/} oder
+@uref{http://www.mysql.com/Downloads/Contrib/} und den Reisin-Treiber unter
+@uref{http://www.caucho.com/Projekte/jdbc-mysql/index.xtp}. Wegen der
+Dokumentation sehen Sie sich irgend eine JDBC-Dokumentation durch sowie die
+eigene Dokumentation der Treiber wegen MySQL-spezifischer Features.
+
+
+@node Python, Tcl, Java, Clients
+@c German node Python
+@section MySQL-Python-APIs
+
+@cindex Python-APIs
+
+Das
+MySQL-@uref{http://www.mysql.com/Downloads/Contrib/,Contrib-Verzeichnis}
+enthält eine Python-Schnittstelle, die von Joseph Skinner geschrieben
+wurde.
+
+Sie können auch die Python-Schnittstelle zu iODBC benutzen, um auf einen
+MySQL-Server zuzugreifen.
+@uref{http://starship.skyport.net/~lemburg/,mxODBC}
+
+
+@node Tcl, Eiffel, Python, Clients
+@c German node Tcl
+@section MySQL-Tcl-APIs
+
+@cindex Tcl-APIs
+
+@uref{http://www.binevolve.com/~tdarugar/tcl-sql/, Tcl bei binevolve}.
+Das
+@uref{http://www.mysql.com/Downloads/Contrib,Contrib-Verzeichnis} enthält
+eine Tcl-Schnittstelle, die auf msqltcl 1.50 basiert.
+
+
+@node Eiffel, , Tcl, Clients
+@c German node Eiffel
+@section MySQL-Eiffel-Wrapper
+
+@cindex Eiffel-Wrapper
+@cindex Wrapper, Eiffel
+
+Das
+MySQL-@uref{http://www.mysql.com/Downloads/Contrib/,Contrib-Verzeichnis}
+enthält einen Eiffel-Wrapper, der von Michael Ravits geschrieben wurde.
+
+
+@node Extending MySQL, Problems, Clients, Top
+@c German node MySQL erweitern
+@chapter MySQL erweitern
+
+
+
+@menu
+* MySQL internals::
+* Adding procedures::
+* MySQL-Interna::
+@end menu
+
+@node MySQL internals, Adding procedures, Extending MySQL, Extending MySQL
+@c German node Hinzufügen von Funktionen
+@section Hinzufügen neuer Funktionen zu MySQL
+
+@cindex Funktionen, neue
+@cindex hinzufügen, neue Funktionen
+@cindex benutzerdefinierte Funktionen, hinzufügen
+@cindex UDFs, Definition
+@cindex Funktionen, benutzerdefinierte
+
+Es gibt zwei Möglichkeiten, MySQL neue Funktionen hinzuzufügen:
+
+@itemize @bullet
+@item
+Sie können die Funktion über die benutzerdefinierbare Funktions-
+(UDF-) Schnittstelle hinzufügen. Benutzerdefinierbare Funktionen werden
+dynamisch mittels @code{CREATE FUNCTION} und @code{DROP
+FUNCTION}-Statements hinzugefügt bzw. gelöscht.
+@xref{CREATE FUNCTION, ,@code{CREATE FUNCTION}}.
+
+@item
+Sie können die Funktion als native (eingebaute) MySQL-Funktion hinzufügen.
+Native Funktionen werden in den @code{mysqld}-Server kompiliert und stehen
+dann dauerhaft zur Verfügung.
+@end itemize
+
+Jede Methode hat Vorteile und Nachteile:
+
+@itemize @bullet
+@item
+Wenn Sie eine benutzerdefinierte Funktion schreiben, müssen Sie die
+Objekt-Datei zusätzlich zum Server selbst installieren. Wenn Sie Ihre
+Funktion in den Server einkompilieren, brauchen Sie das nicht zu tun.
+@item
+Sie können der binären MySQL-Distribution benutzerdefinierte Funktionen
+hinzufügen. Native Funktionen erfordern, dass Sie eine Quelldistribution
+verändern.
+@item
+Wenn Sie Ihre MySQL-Distribution aktualisieren, können Sie weiterhin Ihre
+vorher installierten benutzerdefinierten Funktionen benutzen. Bei nativen
+Funktionen müssen Sie Ihre Änderungen jedes Mal wiederholen, wenn Sie
+aktualisieren.
+@end itemize
+
+Gleich welche Methode Sie zum Hinzufügen neuer Funktionen verwenden, können
+Sie diese genau wie die nativen Funktionen, z. B. @code{ABS()} oder
+@code{SOUNDEX()}, benutzen.
+
+
+
+@menu
+* CREATE FUNCTION::
+* Adding UDF::
+* Adding native function::
+@end menu
+
+@node CREATE FUNCTION, Adding UDF, MySQL internals, MySQL internals
+@c German node CREATE FUNCTION
+@subsection @code{CREATE FUNCTION / DROP FUNCTION}-Syntax
+
+@findex CREATE FUNCTION
+@findex DROP FUNCTION
+@findex UDF-Funktionen
+@findex benutzerdefinierte Funktionen
+@findex Funktionen, benutzerdefinierte
+
+@example
+CREATE [AGGREGATE] FUNCTION funktion RETURNS @{STRING|REAL|INTEGER@}
+ SONAME gemeinsame_bibliothek
+
+DROP FUNCTION funktion
+@end example
+
+Eine benutzerdefinierte Funktion (UDF) ist eine Möglichkeit, MySQL durch
+eine neue Funktion zu erweitern, die wie die nativen (eingebauten)
+MySQL-Funktionen, z. B. @code{ABS()} und @code{CONCAT()}, funktioniert.
+
+@code{AGGREGATE} ist eine neue Option für MySQL-Version 3.23. Eine
+@code{AGGREGATE}-Funktion funktioniert genau wie eine native MySQL-
+@code{GROUP}-Funktion wie @code{SUM} oder @code{COUNT()}.
+
+@code{CREATE FUNCTION} speichert den Funktionnamen, -typ und die gemeinsam
+genutzte Bibliothek in der @code{mysql.func}-Systemtabelle. Sie benötigen
+die @strong{insert}- und @strong{delete}-Berechtigungen für die
+@code{mysql}-Datenbank, um Funktionen zu erzeugen und zu löschen.
+
+Alle aktiven Funktionen werden jedes Mal wieder geladen, wenn der Server
+startet, es sei denn, Sie starten ihn mit der
+@code{--skip-grant-tables}-Option. In diesem Fall wird die
+UDF-Initialisierung übersprungen, so dass UDFs nicht verfügbar sind. (Eine
+aktive Funktion ist eine, die mit @code{CREATE FUNCTION} geladen und nicht
+mit @code{DROP FUNCTION} entfernt wurde.)
+
+Wegen weiterer Anleitungen zum Schreiben benutzerdefinierte Funktionen
+siehe @ref{MySQL internals}. Damit der UDF-Mechanismus
+funktioniert, müssen Funktionen in C oder C++ geschrieben sein. Ihr
+Betriebssystem muss dynamisches Laden unterstützen und Sie müssen
+@code{mysqld} dynamisch (nicht statisch) kompiliert haben.
+
+Beachten Sie, dass Sie für das Funktionieren von @code{AGGREGATE} eine
+@code{mysql.func}-Tabelle benötigen, die die Spalte @code{typ} enthält.
+Wenn das nicht der Fall ist, sollten Sie das Skript
+@code{mysql_fix_privilege_tables} laufen lassen, um diesen Mangel zu
+beheben.
+
+
+@node Adding UDF, Adding native function, CREATE FUNCTION, MySQL internals
+@c German node UDF hinzufügen
+@subsection Hinzufügen einer neuen benutzerdefinierten Funktion
+
+@cindex hinzufügen, benutzerdefinierte Funktionen
+@cindex benutzerdefinierte Funktionen, hinzufügen
+@cindex Funktionen, benutzerdefinierte, hinzufügen
+
+
+
+Damit der UDF-Mechanismus funktioniert, müssen Funktionen in C oder C++
+geschrieben sein. Ihr Betriebssystem muss dynamisches Laden unterstützen
+und Sie müssen @code{mysqld} dynamisch (nicht statisch) kompiliert
+haben. Die MySQL-Quelldistribution enthält eine Datei
+@file{sql/udf_example.cc}, die 5 neue Funktionen definiert. Sehen Sie in
+dieser Datei nach, wie die UDF-Aufruf-Konventionen funktionieren.
+
+Damit @code{mysqld} UDF-Funktionen benutzen kann, sollten Sie MySQL mit
+@code{--with-mysqld-ldflags=-rdynamic} konfigurieren. Der Grund liegt
+darin, dass Sie auf vielen Plattformen (inklusive Linux) eine dynamische
+Bibliothek (mit @code{dlopen()}) von einem statisch gelinkten Programm
+laden können, was Sie erhalten würden, wenn Sie
+@code{--with-mysqld-ldflags=-all-static} benutzen. Wenn Sie eine UDF
+benutzen wollen, die auf Symbole von @code{mysqld} zugreifen muss (wie das
+@code{methaPhone}-Beispiel in @file{sql/udf_example.cc}, das
+@code{default_charset_info} benutzt), müssen Sie das Programm mit
+@code{-rdynamic} benutzen (siehe @code{man dlopen}).
+
+Für jede Funktion, die Sie in SQL-Statements benutzen wollen, sollten Sie
+die entsprechenden C- (oder C++-) Funktionen benutzen. In den unten
+stehenden Ausführungen wird ``xxx'' als Beispiel-Funktionsname benutzt. Um
+zwischen SQL- und C-/C++-Benutzung zu unterscheiden, kennzeichnet
+@code{XXX()} (Großschreibung) einen SQL-Funktionsaufruf und @code{xxx()}
+(Kleinschreibung) einen C-/C++-Funktionsaufruf.
+
+The C-/C++-Funktionen, die Sie für die Implementierung der Schnittstelle
+für @code{XXX()} schreiben, sind:
+
+@table @asis
+@item @code{xxx()} (required)
+Die Hauptfunktion. Hier wird das Funktionsergebnis berechnet. Der
+Zusammenhang zwischen dem SQL-Typ und dem Rückgabe-Typ Ihrer
+C-/C++-Funktion ist unten dargestellt:
+
+@multitable @columnfractions .2 .8
+@item @strong{SQL-Typ} @tab @strong{C-/C++-Typ}
+@item @code{STRING} @tab @code{char *}
+@item @code{INTEGER} @tab @code{long long}
+@item @code{REAL} @tab @code{double}
+@end multitable
+
+@item @code{xxx_init()} (optional)
+Die Initialisierungsfunktion für @code{xxx()}. Sie kann für folgendes
+benutzt werden:
+
+@itemize @bullet
+@item
+Um die Anzahl von Argumenten für @code{XXX()} zu prüfen.
+@item
+Um zu prüfen, ob die Argumente vom erforderlichen Typ sind oder,
+alternativ, MySQL mitzuteilen, den Argumenttyp zu erzwingen, den Sie beim
+Aufruf der Hauptfunktion brauchen.
+@item
+Um jeglichen Speicher zuzuweisen, der von der Hauptfunktion benötigt wird.
+@item
+Um die maximale Länge des Ergebnisses anzugeben.
+@item
+Um (für @code{REAL}-Funktionen) die maximale Anzahl von Dezimalstellen
+anzugeben.
+@item
+Um festzulegen, ob das Ergebnis @code{NULL} sein darf oder nicht.
+@end itemize
+
+@item @code{xxx_deinit()} (optional)
+Die Deinitialisierungsfunktion für @code{xxx()}. Sie sollte jeglichen
+Speicher freigeben (deallozieren), der durch die Initialisierungsfunktion
+zugewiesen wurde.
+@end table
+
+Wenn ein SQL-Statement @code{XXX()} aufruft, ruft MySQL die
+Initialisierungsfunktion @code{xxx_init()} auf, damit diese die notwendige
+Einrichtung vornehmen kann wie Argumente prüfen oder Speicherzuweisung.
+Wenn @code{xxx_init()} einen Fehler zurückgibt, wird das SQL-Statement mit
+einer Fehlermeldung abgebrochen, die Haupt- und
+Deinitialisierungsfunktionen werden nicht aufgerufen. Ansonsten wird die
+Hauptfunktion @code{xxx()} für jede Zeile aufgerufen. Nachdem alle Zeilen
+abgearbeitet sind, wird die Deinitialisierungsfunktion @code{xxx_deinit()}
+aufgerufen, damit sie die erforderlichen Aufräumarbeiten ausführen kann.
+
+Alle Funktionen müssen Thread-sicher sein (nicht nur die Hauptfunktion,
+sondern auch die Initialisierungs- und Deinitialisierungsfunktionen). Das
+heißt, dass Sie keinerlei globale oder statische Variablen zuweisen
+dürfen, die sich ändern! Wenn Sie Speicher brauchen, sollten Sie ihn in
+@code{xxx_init()} zuweisen und in @code{xxx_deinit()} freigeben.
+
+
+@menu
+* UDF calling::
+* UDF arguments::
+* UDF return values::
+* UDF compiling::
+@end menu
+
+@node UDF calling, UDF arguments, Adding UDF, Adding UDF
+@c German node UDF-Aufruf-Sequenzen
+@subsubsection UDF-Aufruf-Sequenzen
+
+@cindex Sequenzen aufrufen, UDF
+
+Die Hauptfunktion sollte wie unten dargestellt deklariert werden. Beachten
+Sie, dass sich der Rückgabetyp und der Parameter unterscheiden, abhängig
+davon, wie Sie die SQL-Funktion @code{XXX()} deklarieren, damit sie
+@code{STRING}, @code{INTEGER} oder @code{REAL} im @code{CREATE
+FUNCTION}-Statement zurückgibt:
+
+@noindent
+Bei @code{STRING}-Funktionen:
+
+@example
+char *xxx(UDF_INIT *initid, UDF_ARGS *args,
+ char *result, unsigned long *length,
+ char *is_null, char *error);
+@end example
+
+@noindent
+Bei @code{INTEGER}-Funktionen:
+
+@example
+long long xxx(UDF_INIT *initid, UDF_ARGS *args,
+ char *is_null, char *error);
+@end example
+
+@noindent
+Bei @code{REAL}-Funktionen:
+
+@example
+double xxx(UDF_INIT *initid, UDF_ARGS *args,
+ char *is_null, char *error);
+@end example
+
+Die Initialisierungs- und Deinitialisierungsfunktionen werden wie folgt
+deklariert:
+
+@example
+my_bool xxx_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
+
+void xxx_deinit(UDF_INIT *initid);
+@end example
+
+Der @code{initid}-Parameter wird an alle drei Funktionen übergeben. Er
+zeigt auf eine @code{UDF_INIT}-Struktur, die benutzt wird, um Informationen
+zwischen den Funktionen zu übermitteln. Die
+@code{UDF_INIT}-Strukturmitglieder sind unten aufgelistet. Die
+Initialisierungsfunktion sollte alle Mitglieder ausfüllen, die sie ändern
+will. (Um für ein Mitglied den Vorgabewert zu verwenden, lassen Sie es
+unverändert.)
+
+@table @code
+@item my_bool maybe_null
+@code{xxx_init()} sollte @code{maybe_null} auf @code{1} setzen, wenn
+@code{xxx()} @code{NULL} zurückgeben kann. Der Vorgabewert ist @code{1},
+wenn irgend eins der Argumente als @code{maybe_null} deklariert ist.
+
+@item unsigned int Dezimalstellen
+Anzahl von Dezimalstellen. Der Vorgabewert ist die maximale Anzahl von
+Dezimalstellen in den Argumenten, die an die Hauptfunktion übergeben
+werden. (Wenn der Funktion beispielsweise die Argumente @code{1.34},
+@code{1.345} und @code{1.3} übergeben werden, wäre der Vorgabewert 3, weil
+@code{1.345} 3 Dezimalstellen hat.
+
+@item unsigned int max_length
+Die maximale Länge des Zeichenkettenergebnisses. Der Vorgabewert ist
+unterschiedlich, abhängig vom Ergebnistyp der Funktion. Bei
+Zeichenketten-Funktionen ist die Vorgabe die Länge des längsten Arguments.
+Bei Ganzzahl-Funktionen ist die Vorgabe 21 Ziffern. Bei REAL-Funktionen ist
+die Vorgabe 13 plus die Anzahl von Dezimalstellen, die von
+@code{initid->Dezimalstellen} angezeigt werden. (Bei numerischen Funktionen
+enthält die Länge jedes Vorzeichen- oder Dezimalpunkt-Zeichen.)
+
+Wenn Sie einen Blob zurückgeben wollen, können Sie diesen auf 65 KB oder
+16MB setzen. Der Speicher wird nicht zugewiesen, aber dazu verwendet, um zu
+entscheiden, welcher Spaltentyp benutzt werden soll, falls es notwendig
+werden sollte, Daten temporär zu speichern.
+
+@item char *ptr
+Ein Zeiger, den die Funktion für eigene Zwecke verwenden kann.
+Beispielsweise können Funktionen @code{initid->ptr} benutzen, um
+Informationen über den zugewiesenen Speicher zwischen den Funktionen zu
+kommunizieren. Beispiel, um in @code{xxx_init()} Speicher zuzuweisen und
+ihn diesem Zeiger zuzuordnen:
+
+@example
+initid->ptr = allocated_memory;
+@end example
+
+In @code{xxx()} und @code{xxx_deinit()} verweisen Sie auf
+@code{initid->ptr}, um Speicher zu verwenden oder freizugeben.
+@end table
+
+
+@node UDF arguments, UDF return values, UDF calling, Adding UDF
+@c German node UDF-Argumente
+@subsubsection Verarbeitung von Argumenten
+
+@cindex Verarbeitung von Argumenten
+@cindex Verarbeitung, Argumente
+
+Der @code{args}-Parameter zeigt auf eine @code{UDF_ARGS}-Struktur, die
+unten aufgelistete Mitglieder hat:
+
+@table @code
+@item unsigned int arg_count
+Die Anzahl von Argumenten. Prüfen Sie diesen Wert in der
+Initialisierungsfunktion, wenn Sie wollen, dass Ihre Funktion mit einer
+bestimmten Anzahl von Argumenten aufgerufen wird. Beispiel:
+
+@example
+if (args->arg_count != 2)
+@{
+ strcpy(message,"XXX() benoetigt zwei Argumente");
+ return 1;
+@}
+@end example
+
+
+@item enum Item_result *arg_type
+Die Typen für jedes Argument. Die möglichen Typenwerte sind
+@code{STRING_RESULT}, @code{INT_RESULT} und @code{REAL_RESULT}.
+
+Um sicherzustellen, dass die Argumente vom angegebenen Typ sind und einen
+Fehler zurückgeben, falls nicht, prüfen Sie das @code{arg_type}-Array in
+der Initialisierungsfunktion. Beispiel:
+
+@example
+if (args->arg_type[0] != STRING_RESULT ||
+ args->arg_type[1] != INT_RESULT)
+@{
+ strcpy(message,"XXX() erfordert eine Zeichenkette und eine Ganzzahl");
+ return 1;
+@}
+@end example
+
+Als Alternative dazu, dass Ihre Funktionsargumente von bestimmten Typen
+sein müssen, können Sie die Initialisierungsfunktion benutzen, um die
+@code{arg_type}-Elemente auf die Typen zu setzen, die Sie wollen. Das
+veranlasst MySQL, die Typen der Argumente bei jedem Aufruf von @code{xxx()}
+zu erzwingen. Um beispielsweise zu erzwingen, dass die ersten zwei
+Argumente Zeichenkette und Ganzzahl sind, geben Sie in @code{xxx_init()}
+folgendes ein:
+
+@example
+args->arg_type[0] = STRING_RESULT;
+args->arg_type[1] = INT_RESULT;
+@end example
+
+@item char **args
+@code{args->args} kommuniziert der Initialisierungsfunktion Informationen
+über die allgemeine Natur der Argumente, mit der Ihre Funktion aufgerufen
+wurde. Bei einem Konstanten-Argument @code{i} zeigt @code{args->args[i]}
+auf den Argumentwert. (Siehe unten wegen Anleitungen, wie auf diesen Wert
+korrekt zugegriffen wird.) Bei einem Nicht-Konstanten-Argument ist
+@code{args->args[i]} @code{0}. Ein Konstanten-Argument ist ein Ausdruck,
+der nur Konstanten wie @code{3} oder @code{4*7-2} oder @code{SIN(3.14)}
+benutzt. Ein Nicht-Konstanten-Argument ist ein Ausdruck, der auf Werte
+verweist, die sich von Zeile zu Zeile ändern können, wie Spaltennamen oder
+Funktionen, die mit Nicht-Konstanten-Argumenten aufgerufen werden.
+
+Bei jedem Aufruf der Hauptfunktion enthält @code{args->args} die
+tatsächlichen Argumente, die für die Zeile übergeben werden, die momentan
+verarbeitet wird.
+
+Funktionen können auf ein Argument @code{i} wie folgt verweisen:
+
+@itemize @bullet
+@item
+Ein Argument des Typs @code{STRING_RESULT} wird als ein Zeichenkettenzeiger
+plus einer Länge angegeben, um die Handhabung von Binärdaten oder Daten
+beliebiger Länge zu erlauben. Die Zeichenketten-Inhalte sind als
+@code{args->args[i]} und die Zeichenkettenlänge als @code{args->lengths[i]}
+verfügbar. Sie sollten nicht davon ausgehen, dass Zeichenketten
+null-terminiert sind.
+
+@item
+Bei einem Argument des Typs @code{INT_RESULT} müssen Sie
+@code{args->args[i]} zu einem @code{long long}-Wert machen (cast):
+
+@example
+long long int_val;
+int_val = *((long long*) args->args[i]);
+@end example
+
+@item
+Bei einem Argument des Typs @code{REAL_RESULT} müssen Sie
+@code{args->args[i]} zu einem @code{double}-Wert machen (cast):
+
+@example
+double real_val;
+real_val = *((double*) args->args[i]);
+@end example
+@end itemize
+
+@item unsigned long *lengths
+Bei der Initialisierungsfunktion gibt das @code{lengths}-Array die maximale
+Zeichenkettenlänge jedes Arguments an. Bei jedem Aufruf der Hauptfunktion
+enthält @code{lengths} die tatsächlichen Längen jeglicher
+Zeichenketten-Argumente, die für die momentan verarbeitete Zeile übergeben
+werden. Bei Argumenten des Typs @code{INT_RESULT} oder @code{REAL_RESULT}
+enthält @code{lengths} immer noch die maximale Länge des Arguments (wie bei
+der Initialisierungsfunktion).
+@end table
+
+
+@node UDF return values, UDF compiling, UDF arguments, Adding UDF
+@c German node UDF-Rückgabewerte
+@subsubsection Rückgabewerte und Fehlerbehandlung
+
+@cindex UDFs, Rückgabewerte
+@cindex Rückgabewerte, UDFs
+@cindex Fehler, Handhabung in UDFs
+@cindex Handhabung, Fehler
+
+Die Initialisierungsfunktion sollte @code{0} zurückgeben, wenn kein Fehler
+auftrat, ansonsten @code{1}. Wenn ein Fehler auftritt, sollte
+@code{xxx_init()} eine null-terminierte Fehlermeldung im
+@code{message}-Parameter enthalten. Die Meldung wird an den Client
+übergeben. Der Meldungspuffer ist @code{MYSQL_ERRMSG_SIZE} Zeichen lang,
+aber Sie sollten versuchen, die Meldung kleiner als 80 Zeichen zu halten,
+damit sie auf die Anzeigebreite eines Standard-Terminals passt.
+
+Der Rückgabewert der Hauptfunktion @code{xxx()} ist der Funktionswert, bei
+@code{long long}- und @code{double}-Funktionen. Eine Zeichenkettenfunktion
+sollte einen Zeiger auf das Ergebnis und die Länge der Zeichenkette in den
+@code{length}-Argumenten zurückgeben.
+
+Setzen Sie diese auf die Inhalte und Länge des Rückgabewerts. Beispiel:
+
+@example
+memcpy(result, "ergebnis_zeichenkette", 13);
+*length = 13;
+@end example
+
+Der @code{result}-Puffer, der an die Berechnungsfunktionen übergeben wird,
+ist 255 Byte Groß. Wenn Ihr Ergebnis dort hinein passt, müssen Sie sich um
+die Speicherzuweisung für Ergebnisse nicht kümmern.
+
+Wenn Ihre Zeichenketten-Funktion eine Zeichenkette zurückgeben muss, die
+länger als 255 Bytes ist, müssen Sie den Platz dafür mit @code{malloc()} in
+Ihrer @code{xxx_init()}-Funktion oder Ihrer @code{xxx()}-Funktion zuweisen
+und in Ihrer @code{xxx_deinit()}-Funktion freigeben. Sie können den
+zugewiesenen Speicher im @code{ptr}-Slot in der @code{UDF_INIT}-Struktur
+für erneute Benutzung durch zukünftige @code{xxx()}-Aufrufe speichern.
+@xref{UDF calling}.
+
+Um einen Rückgabewert von @code{NULL} in der Hauptfunktion anzuzeigen,
+setzen Sie @code{is_null} auf @code{1}:
+
+@example
+*is_null = 1;
+@end example
+
+Um eine Fehlerrückgabe in der Hauptfunktion anzuzeigen, setzen Sie den
+@code{error}-Parameter auf @code{1}:
+
+@example
+*error = 1;
+@end example
+
+Wenn @code{xxx()} @code{*error} für beliebige Zeilen auf @code{1} setzt,
+ist der Funktionswert der aktuellen Zeile @code{NULL}, was auch für
+nachfolgende Zeilen gilt, die von dem Statement verarbeitet werden, in dem
+@code{XXX()} aufgerufen wurde. (@code{xxx()} wird für nachfolgende Zeilen
+nicht einmal aufgerufen.) @strong{HINWEIS:} In MySQL-Versionen vor 3.22.10
+sollten Sie sowohl @code{*error} als auch und @code{*is_null} setzen:
+
+@example
+*error = 1;
+*is_null = 1;
+@end example
+
+
+@node UDF compiling, , UDF return values, Adding UDF
+@c German node UDF kompilieren
+@subsubsection Kompilieren und Installieren benutzerdefinierter Funktionen
+
+@cindex Kompilieren, benutzerdefinierte Funktionen
+@cindex UDFs, kompilieren
+@cindex installieren, benutzerdefinierte Funktionen
+
+Dateien, die UDFs implementieren, müssen auf dem Host kompiliert und
+installiert werden, auf dem der Server läuft. Dieser Prozess wird unten am
+Beispiel der UDF-Datei @file{udf_example.cc} beschrieben, die in der
+MySQL-Quelldistribution enthalten ist. Diese Datei enthält folgende
+Funktionen:
+
+@itemize @bullet
+@item
+@code{metaphon()} gibt eine metaphon-Zeichenkette des
+Zeichenkettenarguments zurück. Das ist etwas wie eine Soundex-Zeichenkette,
+nur etwas besser für englisch angepasst.
+@item
+@code{myfunc_double()} gibt die Summe der ASCII-Werte der Zeichen in ihren
+Argumenten zurück, geteilt durch die Summe der Längen ihrer Argumente.
+@item
+@code{myfunc_int()} gibt die Summe der Längen ihrer Argumente zurück.
+@item
+@code{sequence([const int])} gibt eine Sequenz zurück, die mit der
+angegebenen Zahl startet oder mit 1, wenn keine Zahl angegeben wurde.
+@item
+@code{lookup()} gibt die IP-Nummer für einen Hostnamen zurück.
+@item
+@code{reverse_lookup()} gibt den Hostnamen für eine IP-Nummer zurück. Die
+Funktion kann mit einer Zeichenkette @code{"xxx.xxx.xxx.xxx"} oder mit vier
+Zahlen aufgerufen werden.
+@end itemize
+
+Eine dynamisch ladbare Datei sollte als gemeinsam nutzbare Objektdatei
+kompiliert werden, etwa mit folgendem Befehl:
+
+@example
+shell> gcc -shared -o udf_example.so myfunc.cc
+@end example
+
+Die korrekten Kompiler-Optionen für Ihr System finden Sie leicht heraus,
+wenn Sie diesen Befehl im @file{sql}-Verzeichnis Ihres MySQL-Quellbaums
+laufen lassen:
+
+@example
+shell> make udf_example.o
+@end example
+
+Sie sollten einen Kompilierbefehl laufen lassen, der dem ähnelt, was
+@code{make} anzeigt, ausser dass Sie die @code{-c}-Option kurz vor dem
+Zeilenende entfernen und @code{-o udf_example.so} am Zeilenende hinzufügen
+sollten. (Auf manchen Systemen können Sie @code{-c} im Befehl lassen.)
+
+Wenn Sie ein gemeinsam genutztes Objekt kompiliert haben, das UDFs enthält,
+müssen Sie es danach installieren und MySQL darüber informieren. Wenn Sie
+ein gemeinsam genutztes Objekt von @file{udf_example.cc} kompilieren, wird
+eine Datei etwa mit dem Namen @file{udf_example.so} erzeugt (der exakte
+Name variiert von Plattform zu Plattform). Kopieren Sie diese Datei in ein
+Verzeichnis, das von @code{ld} durchsucht wird, wie @file{/usr/lib}. Auf
+vielen Systemen können Sie die @code{LD_LIBRARY}- oder
+@code{LD_LIBRARY_PATH}-Umgebungsvariable so setzen, dass sie auf das
+Verzeichnis zeigt, wo Sie Ihre UDF-Funktionsdateien haben. Das
+@code{dlopen}-Handbuch sagt Ihnen, welche Variable Sie auf Ihrem System
+setzen sollten. Sie sollten diese auf @code{mysql.server} oder
+@code{safe_mysqld} setzen und @code{mysqld} neu starten.
+
+Nachdem die Bibliothek installiert ist, unterrichten Sie @code{mysqld} über
+die neuen Funktionen mit diesen Befehlen:
+
+@example
+mysql> CREATE FUNCTION metaphon RETURNS STRING SONAME "udf_example.so";
+mysql> CREATE FUNCTION myfunc_double RETURNS REAL SONAME "udf_example.so";
+mysql> CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME "udf_example.so";
+mysql> CREATE FUNCTION lookup RETURNS STRING SONAME "udf_example.so";
+mysql> CREATE FUNCTION reverse_lookup RETURNS STRING SONAME "udf_example.so";
+mysql> CREATE AGGREGATE FUNCTION avgcost RETURNS REAL SONAME "udf_example.so";
+@end example
+
+Funktionen können mit @code{DROP FUNCTION} gelöscht werden:
+
+@example
+mysql> DROP FUNCTION metaphon;
+mysql> DROP FUNCTION myfunc_double;
+mysql> DROP FUNCTION myfunc_int;
+mysql> DROP FUNCTION lookup;
+mysql> DROP FUNCTION reverse_lookup;
+mysql> DROP FUNCTION avgcost;
+@end example
+
+Die @code{CREATE FUNCTION}- und @code{DROP FUNCTION}-Statements
+aktualisieren die Systemtabelle @code{func} in der @code{mysql}-Datenbank.
+Der Funktionsname, -typ und gemeinsam genutzte Bibliothek werden in der
+Tabelle gespeichert. Sie benötigen die @strong{insert}- und
+@strong{delete}-Berechtigungen für die @code{mysql}-Datenbank, um
+Funktionen zu erzeugen und zu löschen.
+
+Sie sollten @code{CREATE FUNCTION} nicht benutzen, um eine Funktion
+hinzuzufügen, die bereits erzeugt wurde. Wenn Sie eine Funktion erneut
+installieren wollen, sollten Sie sie zuerst mit @code{DROP FUNCTION}
+entfernen und dann mit @code{CREATE FUNCTION} erneut installieren. Sie
+müssen so etwas zum Beispiel tun, wenn Sie eine neue Version Ihrer Funktion
+kompilieren, damit @code{mysqld} die neue Version erhält. Ansonsten würde
+der Server mit der alten Version weitermachen.
+
+Aktive Funktionen werden jedes Mal neu geladen, wenn der Server startet, es
+sei denn, Sie starten @code{mysqld} mit der
+@code{--skip-grant-tables}-Option. In diesem Fall wird die
+UDF-Initialisierung übersprungen und UDFs sind nicht verfügbar. (Eine
+aktive Funktion ist eine, die mit @code{CREATE FUNCTION} geladen und nicht
+mit @code{DROP FUNCTION} entfernt wurde.)
+
+
+@node Adding native function, , Adding UDF, MySQL internals
+@c German node Native Funktion hinzufügen
+@subsection Hinzufügen einer neuen nativen Function
+
+@cindex hinzufügen, native Funktionen
+@cindex native Funktionen, hinzufügen
+@cindex Funktionen, native, hinzufügen
+
+Die Prozedur zum Hinzufügen einer neuen nativen Funktion wird hier
+beschrieben. Beachten Sie, dass Sie einer Binärdistribution keine nativen
+Funktionen hinzufügen können, weil die Prozedur die Änderung des
+MySQL-Quelltextes beinhaltet. Sie müssen MySQL selbst aus einer
+Quelldistribution kompilieren. Beachten Sie auch, dass Sie die Prozedur
+wiederholen müssen, wenn Sie auf eine andere Version von MySQL
+aktualisieren (beispielsweise wenn eine neue Version herauskommt).
+
+Um eine neue native MySQL-Funktion hinzuzufügen, gehen Sie wie folgt vor:
+
+@enumerate
+@item
+Fügen Sie @file{lex.h} eine neue Zeile hinzu, die den Funktionsnamen im
+@code{sql_functions[]}-Array definiert.
+@item
+Wenn der Funktionsprototyp einfach ist (nur keins, eins, zwei oder drei
+Argumente entgegennimmt), sollten Sie in lex.h SYM(FUNC_ARG#) angeben
+(wobei # die Anzahl von Argumenten ist), als zweites Argument im
+@code{sql_functions[]}-Array, und eine Funktion hinzufügen, die ein
+Funktionsobjekt in @file{item_create.cc} erzeugt. Sehen Sie sich als
+Beispiel hierfür @code{"ABS"} und @code{create_funcs_abs()} an.
+
+Wenn der Funktionsprototyp kompliziert ist (zum Beispiel eine variable
+Anzahl von Argumenten entgegennimmt), sollten Sie zwei Zeile zu
+@file{sql_yacc.yy} hinzufügen. Eine gibt das Präprozessorsymbol an, das
+@code{yacc} definieren soll (das sollte am Anfang der Datei stehen).
+Definieren Sie dann die Funktionsparameter und fügen Sie ein ``item'' mit
+diesen Parametern zur @code{simple_expression}-Parsing-Regel hinzu. Sehen
+Sie sich als Beispiel alle Vorkommen von @code{ATAN} in @file{sql_yacc.yy}
+an, um zu sehen, wie das gemacht wird.
+@item
+Deklarieren Sie in @file{item_func.h} eine Klasse, die von
+@code{Item_num_func} oder @code{Item_str_func} erbt, je nachdem, ob Ihre
+Funktion eine Zahl oder eine Zeichenkette zurückgibt.
+@item
+Fügen Sie in @file{item_func.cc} eine der folgenden Deklarationen hinzu, je
+nachdem, ob Sie eine numerische oder eine Zeichenketten-Funktion
+definieren:
+@example
+double Item_func_newname::val()
+longlong Item_func_newname::val_int()
+String *Item_func_newname::Str(String *str)
+@end example
+
+Wenn Sie Ihr Objekt von irgend einem der Standard-Items erben (wie von
+@code{Item_num_func}, müssen Sie wahrscheinlich eine der oben genannten
+Funktionen definieren und das Elternobjekt sich um die anderen Funktionen
+kümmern lassen. Beispielsweise definiert die @code{Item_str_func}-Klasse
+eine @code{val()}-Funktion, die @code{atof()} auf dem Wert ausführt, der
+von @code{::str()} zurückgegeben wurde.
+
+@item
+Sie müssen wahrscheinlich auch die folgende Objektfunktion definieren:
+@example
+void Item_func_newname::fix_length_und_dec()
+@end example
+Diese Funktion sollte zumindest @code{max_length} basierend auf den
+angegebenen Argumenten berechnen. @code{max_length} ist die maximale Anzahl
+von Zeichen, die die Funktion zurückgeben kann. Diese Funktion sollte auch
+@code{maybe_null = 0} setzen, wenn die Hauptfunktion keinen
+@code{NULL}-Wert zurückgeben kann. Die Funktion kann prüfen, ob irgend eins
+der Funktionsargumente @code{NULL} zurückgeben kann, indem die Argumente
+der @code{maybe_null}-Variable geprüft werden. Sehen Sie sich als typisches
+Beispiel, wie das gemacht wird, @code{Item_func_mod::fix_length_and_dec}
+an.
+@end enumerate
+
+Alle Funktionen müssen Thread-sicher sein (mit anderen Worten: Benutzen Sie
+keine globalen oder statischen Variablen in den Funktionen, ohne sie mit
+mutexes zu schützen).
+
+Wenn Sie von @code{::val()}, @code{::val_int()} oder @code{::str()}
+@code{NULL} zurückgeben wollen, sollten Sie @code{null_value} auf 1 setzen
+und 0 zurückgeben.
+
+Bei @code{::str()}-Objektfunktionen gibt es einige zusätzliche
+Überlegungen, auf die man achten sollte:
+
+@itemize @bullet
+@item
+Das @code{String *str}-Argument stellt einen Zeichenketten-Puffer zur
+Verfügung, der benutzt werden kann, um das Ergebnis zu speichern. (Weitere
+Informationen über den @code{String}-Typ finden Sie durch einen Blick in
+die @file{sql_string.h}-Datei.)
+@item
+Die @code{::str()}-Funktion sollte die Zeichenkette zurückgeben, die das
+Ergebnis enthält, oder @code{(char*) 0}, wenn das Ergebnis @code{NULL} ist.
+@item
+Alle aktuellen Zeichenketten-Funktionen versuchen, die Zuweisung jeglichen
+Speichers zu vermeiden, ausser wenn das absolut notwendig ist!
+@end itemize
+
+
+@node Adding procedures, MySQL-Interna, MySQL internals, Extending MySQL
+@c German node Hinzufügen von Prozeduren
+@section Hinzufügen neuer Prozeduren zu MySQL
+
+@cindex Prozeduren, hinzufügen
+@cindex hinzufügen, Prozeduren
+@cindex neue Prozeduren, hinzufügen
+
+In MySQL können Sie eine Prozedur in C++ definieren, die auf Daten in einer
+Anfrage zugreifen und diese ändern kann, bevor sie an den Client geschickt
+werden. Die Änderung kann Zeile für Zeile oder auf @code{GROUP BY}-Ebene
+geschehen.
+
+Wir haben eine Beispiel-Prozedur in MySQL-Version 3.23 erzeugt, um zu
+zeigen, was getan werden kann.
+
+Zusätzlich empfehlen wir, dass Sie einen Blick auf 'mylua' werfen, das Sie
+im Contrib-Verzeichnis finden. @xref{Contrib}. Hiermit können Sie die
+LUA-Sprache benutzen, um eine Prozedur zur Laufzeit in @code{mysqld} zu
+laden.
+
+
+
+@menu
+* procedure analyse::
+* Writing a procedure::
+@end menu
+
+@node procedure analyse, Writing a procedure, Adding procedures, Adding procedures
+@c German node Prozeduranalyse
+@subsection Prozeduranalyse
+
+@code{analyse([max Elemente,[max memory]])}
+
+Diese Prozedur ist in @file{sql/sql_analyse.cc} definiert. Sie untersucht
+das Ergebnis Ihrer Anfrage und gibt eine Analyse des Ergebnisses zurück:
+
+@itemize @bullet
+@item
+@code{max elements} (Vorgabe 256) ist die maximale Anzahl unterschiedlicher
+Werte, die @code{analyse} pro Spalte findet. Dieses wird von @code{analyse}
+benutzt, um zu prüfen, ob der optimale Spaltentyp vom Typ @code{ENUM} sein
+sollte.
+@item
+@code{max memory} (Vorgabe 8.192) ist der maximale Speicher, den
+@code{analyse} pro Spalte zuweisen sollte, wenn Sie versuchen, alle
+unterschiedlichen (distinct) Werte zu finden.
+@end itemize
+
+@example
+SELECT ... FROM ... WHERE ... Prozeduranalyse([max elements,[max memory]])
+@end example
+
+
+@node Writing a procedure, , procedure analyse, Adding procedures
+@c German node Eine Prozedur schreiben
+@subsection Eine Prozedur schreiben
+
+Im Moment ist die einzige Dokumentation hierfür der Quelltext.
+
+Sie finden alle Informationen über Prozeduren, wenn Sie folgende Dateien
+untersuchen:
+
+@itemize @bullet
+@item @file{sql/sql_analyse.cc}
+@item @file{sql/procedure.h}
+@item @file{sql/procedure.cc}
+@item @file{sql/sql_select.cc}
+@end itemize
+
+
+@node MySQL-Interna, , Adding procedures, Extending MySQL
+@c German node <no English equivalent>
+@section MySQL-Interna
+
+@cindex Interna
+@cindex Thread
+
+Dieses Kapitel beschreibt viele Dinge, die Sie wissen müssen, wenn Sie am
+MySQL-Code arbeiten. Wenn Sie an der MySQL-Entwicklung mitarbeiten wollen,
+Zugriff auf den messerscharfen Code von Zwischenversionen haben wollen,
+oder einfach nur über die Entwicklung auf dem Laufenden bleiben wollen,
+folgen Sie den Anweisungen unter @xref{Installing source}.
+Wenn Sie an MySQL-Interna interessiert sind, sollten Sie auch
+@email{internals@@lists.mysql.com} abonnieren. Das ist eine Liste mit
+relativ geringem Verkehr, verglichen mit @email{mysql@@lists.mysql.com}.
+
+
+
+@menu
+* MySQL-Thread::
+* MySQL-Test-Suite::
+@end menu
+
+@node MySQL-Thread, MySQL-Test-Suite, MySQL-Interna, MySQL-Interna
+@c German node <no English equivalent>
+@subsection MySQL-Thread
+
+Der MySQL-Server erzeugt folgenden Thread:
+
+@itemize @bullet
+
+@item
+Der TCP/IP-Verbindungs-Thread erledigt alle Verbindungsanfragen und erzeugt
+einen neuen dedizierten Thread, um die Verarbeitung von Authentifizierung
+und SQL-Anfragen für jede Verbindung zu handhaben.
+
+@item
+Unter Windows NT gibt es einen Named-Pipe-Handler-Thread, der dasselbe tut
+wie der TCP/IP-Verbindungs-Thread, auf Named-Pipe-Verbindungsanforderungen.
+
+@item
+Der Signal-Thread handhabt alle Signale. Dieser Thread handhabt
+normalerweise auch Alarme und Aufrufe von @code{process_alarm()}, um
+Zeitüberschreitungen auf Verbindungen zu erzwingen, die zu lange im
+Leerlauf waren.
+
+@item
+Wenn @code{mysqld} mit @code{-DUSE_ALARM_THREAD} kompiliert wird, wird ein
+dedizierter Thread erzeugt, der Alarme handhabt. Das ist nur nützlich auf
+manchen Systemen, auf denen es Probleme mit @code{sigwait()} gibt, oder
+wenn man den @code{thr_alarm()}-Code in seiner Applikation ohne einen
+dedizierten Signal-Handhabungs-Thread benutzen will.
+
+@item
+Wenn man die @code{--flush_time=#}-Option benutzt, wird ein dedizierter
+Thread erzeugt, der alle Tabellen im angegebenen Intervall auf Platte
+zurückschreibt.
+
+@item
+Jede Verbindung hat ihren eigenen Thread.
+
+@item
+Jede unterschiedliche Tabelle, auf der man @code{INSERT DELAYED} benutzt,
+erhält ihren eigenen Thread.
+
+@item
+Wenn Sie @code{--master-host} benutzen, wird ein Slave-Replikations-Thread
+gestartet, der Aktualisierungen vom Master liest und anwendet.
+@end itemize
+
+@code{mysqladmin processlist} zeigt nur die Verbindungs-, @code{INSERT
+DELAYED}- und Replikations-Threads.
+
+
+@node MySQL-Test-Suite, , MySQL-Thread, MySQL-Interna
+@c German node <no English equivalent>
+@subsection MySQL-Test-Suite
+
+@cindex mysqltest, MySQL-Test-Suite
+@cindex mysqld testen, mysqltest
+
+Bis vor Kurzem basierte unsere vollumfängliche Haupt-Test-Suite auf
+proprietären Kundendaten und war deshalb nicht öffentlich verfügbar. Der
+einzige öffentlich verfügbare Teil unseres Testprozesses bestand aus dem
+@code{Crash-me}-Test, einem Perl-DBI/DBD-Benchmark, der im
+@code{sql-bench}-Verzeichnis liegt, und verschiedenen Tests im
+@code{tests}-Verzeichnis. Das Fehlen einer standardisierten, öffentlich
+verfügbaren Test-Suite machte es unseren Benutzern und auch Entwicklern
+schwer, Regressionstests auf den MySQL-Code durchzuführen. Um das Problem
+anzugehen, haben wir ein neues Testsystem geschaffen, das ab Version
+3.23.29 den Quell- und Binärdistributionen beiliegt.
+
+Der aktuelle Satz von Testfällen testet nicht alles in MySQL, sollte aber
+die offensichtlichsten Bugs im SQL-Verarbeitungscode offen legen, sowie
+Betriebssystem- und Bibliotheks-Probleme, und er testet recht gründlich die
+Replikation. Unser letztliches Ziel ist es, dass die Tests 100% des Codes
+abdecken. Beiträge zu unserer Test-Suite sind herzlich willkommen,
+besonders Tests, die die Funktionalität untersuchen, die für Ihr System
+kritisch ist, weil das sicherstellt, dass alle zukünftigen MySQL-Releases
+mit Ihren Applikationen funktionieren.
+
+
+
+@menu
+* mysqltest laufen lassen::
+* MySQL-Tests erweitern::
+* mysqltest-Bugs berichten::
+@end menu
+
+@node mysqltest laufen lassen, MySQL-Tests erweitern, MySQL-Test-Suite, MySQL-Test-Suite
+@c German node <no English equivalent>
+@subsubsection Die MySQL-Test-Suite laufen lassen
+
+Das Testsystem besteht aus einem Test-Sprachinterpreter (@code{mysqltest}),
+einem Shell-Skript, um alle Tests laufen zu lassen
+tests(@code{mysql-test-run}), den eigentlichen Testfällen, die in einer
+speziellen Testsprache geschrieben sind, und ihren erwarteten Ergebnissen.
+Um die Test-Suite nach dem Bauen auf Ihrem System laufen zu lassen, geben
+Sie @code{make test} oder @code{mysql-test/mysql-test-run} von der Wurzel
+der Quellinstallation aus ein. Wenn Sie eine Binärdistribution installiert
+haben, wechseln Sie (@code{cd}) zur Wurzel der Installation (zum Beispiel
+@code{/usr/local/mysql}) und geben @code{scripts/mysql-test-run} ein. Alle
+Tests sollten erfolgreich durchlaufen. Wenn nicht, sollten Sie versuchen,
+den Grund herauszufinden, und das Problem zu berichten, wenn es ein Bug in
+MySQL ist. @xref{mysqltest-Bugs berichten}.
+
+Wenn eine Kopie von @code{mysqld} auf Ihrer Maschine läuft, wo Sie die
+Test-Suite laufen lassen wollen, müssen Sie ihn nicht anhalten, solange er
+nicht die Ports @code{9306} und @code{9307} benutzt. Wenn einer dieser
+Ports belegt ist, sollten Sie @code{mysql-test-run} editieren und die Werte
+des Master- und / oder Slave-Ports auf verfügbare Ports ändern.
+
+Sie können einen einzelnen Testfall mit @code{mysql-test/mysql-test-run
+test_name} laufen lassen.
+
+Wenn ein Test fehlschlägt, sollten Sie versuchen, @code{mysql-test-run} mit
+der @code{--force}-Option laufen zu lassen, um zu prüfen, ob irgend ein
+weiterer Test fehlschlägt.
+
+
+@node MySQL-Tests erweitern, mysqltest-Bugs berichten, mysqltest laufen lassen, MySQL-Test-Suite
+@c German node <no English equivalent>
+@subsubsection Die MySQL-Test-Suite erweitern
+
+Sie können die @code{mysqltest}-Sprache benutzen, um Ihre eigenen Testfälle
+zu schreiben. Leider gibt es noch keine komplette Dokumentation dafür - das
+soll in Kürze aber der Fall sein. Sie können sich jedoch die aktuellen
+Testfälle ansehen und sie als Beispiel benutzen. Folgende Punkte sollen
+Ihnen beim Start helfen:
+
+@itemize @bullet
+@item
+Die Tests liegen in @code{mysql-test/t/*.test}
+
+@item
+Ein Testfall besteht aus @code{;}-begrenzten Statements und ist ähnlich der
+Eingabe in den @code{mysql}-Kommandozeilen-Client. Ein Statement ist
+vorgabemäßig eine Anfrage, die an den MySQL-Server geschickt werden soll,
+es sei denn, es wird als interner Befehl erkannt (zum Beispiel
+@code{sleep}).
+
+@item
+Alle Anfragen, die Ergebnisse produzieren, zum Beispiel @code{SELECT},
+@code{SHOW}, @code{EXPLAIN} usw., müssen mit
+@code{@@/pfad/zu/ergebnis/datei} beginnen. Die Datei muss die erwarteten
+Ergebnisse enthalten. Eine einfache Art, die Ergebnisdatei zu erzeugen,
+ist, @code{mysqltest -r < t/test-case-name.test} vom
+@code{mysql-test}-Verzeichnis aus laufen zu lassen und dann die erzeugten
+Ergebnisdateien zu editieren und sie - falls nötig - an die erwartete
+Ausgabe anzupassen. Seien Sie in diesem Fall sehr vorsichtig, keine
+unsichtbaren Zeichen hinzuzufügen oder zu löschen - stellen Sie sicher,
+dass Sie nur den Text ändern und / oder Zeilen löschen. Wenn Sie eine Zeile
+einfügen müssen, achten Sie darauf, dass die Felder mit einem harten
+Tabulator-Zeichen getrennt sind und dass es ein hartes Tabulator-Zeichen am
+Zeilenende gibt. Gegebenfalls sollten Sie @code{od -c} benutzen, um sich zu
+vergewissern, dass Ihr Texteditor beim Editieren nichts durcheinander
+gebracht hat. Wir hoffen natürlich, dass Sie die Ausgabe von
+@code{mysqltest -r} nie editieren müssen, weil das nur der Fall ist, wenn
+Sie einen Bug finden.
+
+@item
+Um mit unserer Einrichtung konsistent zu sein, sollten Sie Ihre
+Ergebnisdateien ins @code{mysql-test/r}-Verzeichnis stellen und sie
+@code{test_name.result} nennen. Wenn der Test mehr als ein Ergebnis
+erzeugt, sollten Sie @code{test_name.a.result}, @code{test_name.b.result}
+usw. verwenden.
+
+@item
+Wenn ein Statement einen Fehler zurückgibt, sollten Sie die Zeile vor dem
+Statement mit @code{--error fehler_nummer} kennzeichnen. Die Fehlernummer
+kann eine Auflistung möglicher Fehlerzahlen sein, getrennt durch
+@code{','}.
+
+@item
+Wenn Sie einen Replikations-Testfall schreiben, sollten Sie in die erste
+Zeile der Testdatei @code{source include/master-slave.inc;} schreiben. Um
+zwischen Master und Slave umzuschalten, benutzen Sie @code{connection
+master;} und @code{connection slave;}. Wenn Sie etwas auf einer
+abwechselnden Verbindung machen müssen, können Sie @code{connection
+master1;} für den Master und @code{connection slave1;} für den Slave
+eingeben.
+
+@item
+Wenn Sie etwas in einer Schleife ausführen müssen, können Sie zum Beispiel
+folgendes tun:
+@example
+let $1=1000;
+while ($1)
+@{
+ # machen Sie Ihre Anfragen hier
+ dec $1;
+@}
+@end example
+
+@item
+Um zwischen Anfragen zu schlafen, benutzen Sie den @code{sleep}-Befehl. Er
+unterstützt Bruchteile von Sekunden, daher können Sie zum Beispiel
+@code{sleep 1.3;} ausführen, um 1,3 Sekunden zu schlafen.
+
+@item
+Um den Slave für Ihren Testfall mit zusätzlichen Optionen laufen zu lassen,
+geben Sie diese im Kommandozeilenformat in
+@code{mysql-test/t/test_name-slave.opt} ein. Für den Master geben Sie sie
+in @code{mysql-test/t/test_name-master.opt} ein.
+
+@item
+Wenn Sie eine Frage zur Test-Suite haben oder einen Testfall beisteuern
+wollen, schicken Sie eine E-Mail an @email{Interna@@lists.mysql.com}. Weil
+die Liste keine Dateianhänge akzeptiert, sollten Sie alle relevanten
+Dateien per FTP an @url{ftp://support.mysql.com/pub/mysql/Incoming}
+schicken.
+
+@end itemize
+
+
+@node mysqltest-Bugs berichten, , MySQL-Tests erweitern, MySQL-Test-Suite
+@c German node <no English equivalent>
+@subsubsection Bugs in der MySQL-Test-Suite berichten
+
+Wenn Ihre MySQL-Version die Test-Suite nicht fehlerfrei durchläuft, sollten
+Sie folgendes tun:
+
+@itemize @bullet
+@item
+Schicken Sie keinen Bug-Bericht, bevor Sie so weit wie möglich
+herausgefunden haben, was schief ging! Benutzen Sie für den Bug-Bericht
+bitte das @code{mysqlbug}-Skript, so dass wir Informationen über Ihr System
+und die @code{MySQL}-Version erhalten. @xref{Bug reports}.
+@item
+Stellen Sie sicher, dass die Ausgabe von @code{mysql-test-run} beiliegt,
+sowie alle Inhalte aller @code{.reject}-Dateien im
+@code{mysql-test/r}-Verzeichnis.
+@item
+Wenn ein Test in der Test-Suite fehlschlägt, prüfen Sie, ob der Test auch
+fehlschlägt, wenn er allein laufen gelassen wird:
+
+@example
+cd mysql-test
+mysql-test-run --local test-name
+@end example
+
+Wenn das fehlschlägt, sollten Sie MySQL mit @code{--with-debug}
+konfigurieren und @code{mysql-test-run} mit der @code{--debug}-Option
+laufen lassen. Wenn auch das fehlschlägt, schicken Sie dei Trace-Datei
+@file{var/tmp/master.trace} an ftp://support.mysql.com/pub/mysql/secret, so
+dass wir sie untersuchen können. Denken Sie bitte daran, eine volle
+Beschreibung Ihres Systems beizufügen sowie die Version Ihrer
+mysqld-Binärdatei und wie Sie sie kompiliert haben.
+
+@item
+Versuchen Sie auch, @code{mysql-test-run} mit der @code{--force}-Option
+laufen zu lassen, um zu sehen, ob auch andere Tests fehlschlagen.
+
+@item
+Wenn Sie MySQL selbst kompiliert haben, sehen Sie im Handbuch nach, wie
+MySQL auf Ihrer Plattform kompiliert wird, oder benutzen Sie vorzugsweise
+eine der Binärdateien, die wir für Sie kompiliert haben und die Sie unter
+@uref{http://www.mysql.com/downloads/} finden. Alle unsere
+Standard-Binärdateien sollten die Test-Suite fehlerfrei durchlaufen!
+
+@item
+Wenn Sie einen Fehler wie @code{Result length mismatch} oder @code{Result
+content mismatch} erhalten, heißt das, dass die Ausgabe des Tests nicht
+genau mit der erwarteten Ausgabe übereinstimmt. Das könnte ein Bug in MySQL
+sein, könnte aber auch heißen, dass Ihre mysqld-Version unter bestimmten
+Umständen leicht abweichende Ausgaben erzeugt.
+
+Fehlgeschlagene Testergebnisse werden in eine Datei mit demselben Namen wie
+die Ergebnisdatei, mit der Endung @code{.reject}, gestellt. Wenn Ihr
+Testfall fehlschlägt, sollten Sie ein DIFF beider Dateien vornehmen. Wenn
+Sie nicht erkennen können, in welcher Hinsicht sie sich unterscheiden,
+untersuchen Sie beide mit @code{od -c} und prüfen Sie auch ihre Längen.
+
+@item
+Wenn ein Testfall völlig fehlschlägt, sollten Sie die Log-Dateien im
+@code{mysql-test/var/log}-Verzeichnis nach Hinweisen untersuchen, was
+schief ging.
+
+@item
+Wenn Sie MySQL mit Debugging kompiliert haben, können Sie versuchen, das zu
+debuggen, indem Sie @code{mysql-test-run} mit den @code{--gdb}- und / oder
+@code{--debug}-Optionen laufen lassen.
+@xref{Making trace files}.
+
+Wenn Sie MySQL nicht für Debugging kompiliert haben, sollten Sie das besser
+tun. Geben Sie einfach die @code{--with-debug}-Option für @code{configure}
+an! @xref{Installing source}.
+@end itemize
+
+
+
+
+@node Problems, Benutzer, Extending MySQL, Top
+@c German node Probleme
+@appendix Probleme und häufige Fehler
+
+@cindex Probleme, häufige Fehler
+@cindex Fehler, häufige
+
+
+Dieses Kapitel listet einige gebräuchliche Probleme und Fehlermeldungen
+auf, denen Benutzer in die Arme laufen. Sie lernen herauszufinden, was das
+Problem ist und wie Sie es lösen. Hier finden sich auch korrekte Lösungen
+einiger häufiger Probleme.
+
+
+@menu
+* What is crashing::
+* Common errors::
+* Installation Issues::
+* Administration Issues::
+* Query Issues::
+* Table Definition Issues::
+@end menu
+
+@node What is crashing, Common errors, Problems, Problems
+@c German node Was ist ein Absturz
+@appendixsec Wie man feststellt, was Probleme verursacht
+
+Wenn Sie Probleme bekommen, sollten Sie als erstes herausfinden, welches
+Programm oder Hardware-Teil die Probleme verursacht:
+
+@itemize @bullet
+@item
+Wenn Sie eins der folgenden Symptome beobachten, gibt es wahrscheinlich ein
+Hardware- (Speicher, Hauptplatine, Prozessor oder Festplatte) oder
+Kernel-Problem:
+@itemize @minus
+@item
+Die Tastatur funktioniert nicht. Normalerweise können Sie das durch Drücken
+der Feststelltaste (Caps Lock) überprüfen. Wenn sich die Anzeigeleuchte
+beim Drücken nicht an- und ausschaltet, müssen Sie Ihre Tastatur ersetzen.
+(Bevor Sie das tun, sollten Sie Ihren Computer neu starten und alle
+Kabelverbindungen zur Tastatur überprüfen.)
+@item
+Der Mauszeiger bewegt sich nicht.
+@item
+Die Maschine antwortet auf entfernte Ping-Versuche nicht.
+@item
+Andere Programme, die mit MySQL nichts zu tun haben, funktionieren nicht
+korrekt.
+@item
+Wenn Ihr System unerwartet neu startet (ein fehlerhaftes Programm auf
+Benutzerebene sollte NIE in der Lage sein, Ihr System zum Absturz zu
+bringen).
+@end itemize
+
+In solchen Fällen sollten Sie zunächst alle Kabel überprüfen und
+Diagnoseprogramme laufen lassen, um Ihre Hardware zu untersuchen! Sie
+sollten auch prüfen, ob Patches, Aktualisierungen oder Service-Packs für
+Ihre Betriebssystem verfügbar sind, die Ihre Probleme möglicherweise lösen.
+Prüfen Sie auch, ob Ihre Bibliotheken (wie glibc) aktuell sind.
+
+Es ist immer eine gute Idee, eine Maschine mit ECC-Speicher zu benutzen, um
+Speicherprobleme frühzeitig zu erkennen!
+@item
+Wenn Ihre Tastatur gesperrt ist, können Sie das eventuell beheben, indem
+Sie sich von einer anderen Maschine aus verbinden und @code{kbd_mode -a}
+ausführen.
+
+@item
+Untersuchen Sie Ihre System-Log-Datei (/var/log/messages oder ähnliches)
+nach Gründen für Ihre Probleme. Wenn Sie glauben, dass das Problem an MySQL
+liegt, sollten Sie auch die Log-Dateien von MySQL überprüfen.
+@xref{Update log}.
+
+@item
+Wenn Sie nicht glauben, ein Hardware-Problem zu haben, sollten Sie
+herausfinden, welches Programm die Probleme verursacht.
+
+Probieren Sie @code{top}, @code{ps}, @code{taskmanager} oder ein ähnliches
+Programm, um zu prüfen, welches Programm die gesamte Prozessorzeit
+konsumiert oder die Maschine blockiert.
+
+@item
+Prüfen Sie mit @code{top}, @code{df} oder einem ähnlichen Programm, wenn
+Sie keinen freien Arbeitsspeicher, Festplattenspeicher, verfügbare
+Datei-Handler oder eine andere kritische Ressource mehr haben.
+
+@item
+Wenn das Problem an einem aus dem Ruder gelaufenen Prozess liegt, können
+Sie versuchen, diesen zu killen. Wenn er nicht sterben will, gibt es
+wahrscheinlich einen Bug im Betriebssystem.
+@end itemize
+
+Wenn Sie alle anderen Möglichkeiten untersucht und ausgeschlossen haben und
+zur Schlussfolgerung gekommen sind, dass die Probleme durch den
+MySQL-Server oder ein MySQL-Client-Programm verursacht werden, ist es an
+der Zeit, einen Bug-Bericht für die Mailing-Liste oder unser Support-Team
+zu schreiben. Machen Sie im Bug-Bericht eine sehr detaillierte
+Beschreibung, wie sich Ihr System verhält und was Sie vermuten, was
+passiert. Sie sollten auch angeben, warum Sie denken, dass MySQL die
+Probleme verursacht. Ziehen Sie alle Situationen in diesem Kapitel in
+Betracht. Geben Sie genau an, welche Probleme wie auftauchen, wenn Sie Ihr
+System untersuchen. Benutzen Sie Kopieren und Einfügen, wenn Sie Ausgaben
+und / oder Fehlermeldungen von Programmen oder aus Log-Dateien beifügen!
+
+Versuchen Sie detailliert zu beschreiben, welches Programm nicht
+funktioniert, und alle Symptome, die Sie sehen! In der Vergangenheit haben
+wir viele Bug-Berichte erhalten, in denen schlicht steht, dass "das System
+nicht funktioniert". Daraus können wir natürlich keinerlei Informationen
+ziehen, wie das Problem gelöst werden könnte.
+
+Wenn ein Programm fehlschlägt, ist es immer nützlich, folgendes zu wissen:
+
+@itemize @bullet
+@item
+Hat das fragliche Programm einen Segmentation-Fehler verursacht (Core
+Dump)?
+@item
+Nimmt das Programm sich die gesamte Prozessorleistung? Überprüfen Sie das
+mit @code{top}. Lassen Sie das Programm eine Weile laufen, denn vielleicht
+evaluiert es gerade nur etwas Schwieriges.
+@item
+Wenn der @code{mysqld}-Server Probleme verursacht, können Sie dann
+@code{mysqladmin -u root ping} oder @code{mysqladmin -u root processlist}
+ausführen?
+@item
+Was sagt ein Client-Programm (zum Beispiel @code{mysql}), wenn Sie
+versuchen, sich mit dem MySQL-Server zu verbinden? Bricht der Client
+zusammen? Erhalten Sie von diesem Programm irgend welche Ausgaben?
+@end itemize
+
+Wenn Sie einen Bug-Bericht senden, sollten Sie immer den Angaben folgen,
+die in diesem Handbuch beschrieben sind. @xref{Asking questions}.
+
+
+@node Common errors, Installation Issues, What is crashing, Problems
+@c German node Häufige Fehler
+@appendixsec Einige gebräuchliche Fehler bei der Benutzung von MySQL
+
+@cindex errors, Auflistung
+
+
+
+Dieser Abschnitt listet einige Fehler auf, die Benutzer häufig erhalten.
+Hier finden Sie Beschreibungen dieser Fehler und wie man die Probleme löst.
+
+
+@menu
+* Error Access denied::
+* Gone away::
+* Can not connect to server::
+* Blocked host::
+* Too many connections::
+* Non-transactional tables::
+* Out of memory::
+* Packet too large::
+* Communication errors::
+* Full table::
+* Cannot create::
+* Commands out of sync::
+* Ignoring user::
+* Cannot find table::
+* Cannot initialize character set::
+* Not enough file handles::
+@end menu
+
+@node Error Access denied, Gone away, Common errors, Common errors
+@c German node Zugriff-verweigert-Fehler
+@appendixsubsec @code{Access denied}-Fehler
+
+@cindex Fehler, Zugriff verweigert
+@cindex Probleme, Zugriff-verweigert-Fehler
+@cindex access denied
+
+@xref{Privileges}, insbesondere @xref{Access denied}.
+
+
+@node Gone away, Can not connect to server, Error Access denied, Common errors
+@c German node Weg gegangen
+@appendixsubsec @code{MySQL server has gone away}-Fehler
+
+Dieser Abschnitt behandelt auch den verwandten @code{Lost connection to
+server during query}-Fehler.
+
+Der häufigste Grund für den @code{MySQL server has gone away}-Fehler ist
+eine Zeitüberschreitung, nach der der Server die Verbindung schloss.
+Vorgabemäßig schließt der Server die Verbindung nach 8 Stunden, wenn
+nichts passiert ist. Sie können diesen Wert mit der
+@code{wait_timeout}-Variablen ändern, die beim Start von @code{mysqld}
+gesetzt wird.
+
+Ein weiterer häufiger Grund für den @code{MySQL server has gone
+away}-Fehler ist das Absetzen eines ``close'' auf Ihre MySQL-Verbindung mit
+dem anschließenden Versuch, auf der geschlossenen Verbindung eine Anfrage
+abzusetzen.
+
+Sie können überprüfen, ob der MySQL-Server gestorben ist, indem Sie
+@code{mysqladmin version} ausführen und die Uptime untersuchen.
+
+Wenn Sie ein Skript haben, müssen Sie die Anfrage lediglich noch einmal für
+den Client absetzen, um eine automatische Neuverbindung zu machen.
+
+Normalerweise können Sie folgende Fehler-Codes für diesen Fall abfragen
+(die Betriebssystem-abhängig sind):
+
+@multitable @columnfractions .3 .7
+@item @code{CR_SERVER_GONE_ERROR} @tab Der Client konnte keine Anfrage an
+den Server schicken.
+@item @code{CR_SERVER_LOST} @tab Der Client erhielt beim Schreiben zum
+Server keinen Fehler, bekam aber keine vollständige (oder überhaupt keine)
+Antwort.
+@end multitable
+
+Sie erhalten diese Fehler auch, wenn Sie eine Anfrage zum Server schicken,
+die falsch oder zu Groß ist. Wenn @code{mysqld} ein Paket erhält, das zu
+Groß oder nicht in Ordnung ist, nimmt er hat, dass etwas mit dem Client
+schief ging und schließt die Verbindung. Wenn Sie große Anfragen brauchen
+(beispielsweise wenn Sie mit @code{BLOB}-Spalten arbeiten), können Sie die
+Anfragebeschränkung erhöhen, indem Sie @code{mysqld} mit der @code{-O
+max_allowed_packet=#}-Option starten (Vorgabe 1 MB). Der zusätzliche
+Speicher wird bei Bedarf zugewiesen, daher benutzt @code{mysqld} nur dann
+mehr Speicher, wenn Sie eine große Anfrage ausführen oder wenn
+@code{mysqld} ein großes Ergebnis zurückgeben muss!
+
+
+@node Can not connect to server, Blocked host, Gone away, Common errors
+@c German node Keine Verbindung zum Server
+@appendixsubsec @code{Can't connect to [local] MySQL server}-Fehler
+
+Ein MySQL-Client unter Unix kann sich auf zwei unterschiedliche Arten mit
+dem @code{mysqld}-Server verbinden: Unix-Sockets, die sich durch eine Datei
+im Dateisystem verbinden (Vorgabe @file{/tmp/mysqld.sock}) oder über
+TCP/IP, was sich über eine Portnummer verbindet. Unix-Sockets sind
+schneller als TCP/IP, können aber nur benutzt werden, wenn man sich zu
+einem Server auf demselben Computer verbindet. Unix-Sockets werden benutzt,
+wenn Sie keinen Hostnamen oder den speziellen Hostnamen @code{localhost}
+angeben.
+
+Unter Windows können Sie sich nur mit TCP/IP verbinden, wenn der
+@code{mysqld}-Server unter Windows 95 / 98 läuft. Wenn er unter Windows NT
+läuft, können Sie sich auch mit Named Pipes verbinden. Der Name der Named
+Pipe ist MySQL. Wenn Sie bei der Verbindung zu @code{mysqld} keinen
+Hostnamen angeben, versucht ein MySQL-Client zuerst, sich über die Named
+Pipe zu verbinden. Erst wenn das fehlschlägt, versucht er, sich über den
+TCP/IP-Port zu verbinden. Sie können die Benutzung von Named Pipes unter
+Windows erzwingen, indem Sie @code{.} als Hostnamen benutzen.
+
+Der Fehler (2002) @code{Can't connect to ...} bedeutet normalerweise, dass
+auf dem System kein MySQL-Server läuft oder dass Sie eine falsche
+Socket-Datei oder einen falschen TCP/IP-Port bei der Verbindung mit dem
+@code{mysqld}-Server benutzen.
+
+Prüfen Sie zuerst mit @code{ps} oder dem Task-Manager unter Windows, ob es
+einen laufenden Prozess namens @code{mysqld} auf Ihrem Server gibt! Wenn es
+keinen @code{mysqld}-Prozess gibt, sollten Sie einen starten. @xref{Starting server}.
+
+Wenn ein @code{mysqld}-Prozess läuft, können Sie den Server mit diesen
+unterschiedlichen Verbindungen überprüfen (die Portnummer und
+Socket-Pfadnamen können auf Ihrem System natürlich anders sein):
+
+@example
+shell> mysqladmin version
+shell> mysqladmin variables
+shell> mysqladmin -h `hostname` version variables
+shell> mysqladmin -h `hostname` --port=3306 version
+shell> mysqladmin -h 'ip_ihres_hosts' version
+shell> mysqladmin --socket=/tmp/mysql.sock version
+@end example
+
+Beachten Sie die Benutzung umgedrehter Anführungszeichen statt normaler
+Anführungszeichen beim @code{hostname}-Befehl. Diese verursachen, dass die
+Ausgabe durch @code{hostname} (das heißt des aktuellen Hostnamens) im
+@code{mysqladmin}-Befehl ersetzt wird.
+
+Hier sind einige Gründe für das Auftreten des @code{Can't connect to local
+MySQL server}-Fehlers:
+
+@itemize @bullet
+@item
+@code{mysqld} läuft nicht.
+@item
+Sie fahren auf einem System, das MIT-pThread verwendet. Wenn Sie auf einem
+System fahren, das keine nativen Threads hat, benutzt @code{mysqld} das
+MIT-pThread-Paket. @xref{Which OS}. Nicht alle
+MIT-pThread-Versionen unterstützen jedoch Unix-Sockets. Auf einem System
+ohne Socket-Unterstützung müssen Sie den Hostnamen immer explizit angeben,
+wenn Sie sich mit dem Server verbinden. Benutzen Sie diesen Befehl, um die
+Verbindung zum Server zu überprüfen:
+@example
+shell> mysqladmin -h `hostname` version
+@end example
+@item
+Jemand hat den Unix-Socket entfernt, den @code{mysqld} benutzt (Vorgabe
+@file{/tmp/mysqld.sock}). Vielleicht gibt es einen @code{cron}-Job, der den
+MySQL-Socket entfernt (beispielsweise ein Job, der alte Dateien aus dem
+@file{/tmp}-Verzeichnis entfernt). Sie können @code{mysqladmin version}
+laufen lassen und überprüfen, dass der Socket, den @code{mysqladmin}
+versucht zu benutzen, tatsächlich existiert. Die Problemlösung besteht in
+diesem Fall darin, den @code{cron}-Job so zu ändern, dass er nicht
+@file{mysqld.sock} entfernt oder den Socket an andere Stelle zu platzieren.
+@xref{Problems with mysql.sock}.
+@item
+Sie haben den @code{mysqld}-Server mit der
+@code{--socket=/pfad/zu/socket}-Option gestartet. Wenn Sie den
+Socket-Pfadnamen zum Server ändern, müssen Sie auch die MySQL-Clients
+darüber unterrichten. Das können Sie tun, indem Sie den Socket-Pfad als
+Argument an den Client übergeben. @xref{Problems with mysql.sock}.
+@item
+Sie benutzen Linux und ein Thread ist gestorben (Core Dump). In diesem Fall
+müssen Sie den anderen @code{mysqld}-Thread killen (beispielsweise mit dem
+@code{mysql_zap}-Skript), bevor Sie einen neuen MySQL-Server starten
+können. @xref{Crashing}.
+@item
+Eventuell haben Sie keine Lese- und Schreibberechtigungen entweder für das
+Verzeichnis, in dem die Socket-Datei liegt, oder keine Berechtigung für die
+Socket-Datei selbst. In diesem Fall können Sie entweder die Berechtigung
+für die Datei und / oder das Verzeichnis ändern oder @code{mysqld} neu
+starten, so dass er ein Verzeichnis benutzt, auf das Sie Zugriff haben.
+@end itemize
+
+Wenn Sie die Fehlermeldung @code{Can't connect to MySQL server on
+ein_hostname} erhalten, können Sie folgendes probieren, um den Grund des
+Problems herauszufinden:
+
+@itemize @bullet
+@item
+Überprüfen Sie, ob der Server hochgefahren ist, indem Sie @code{telnet
+ihr_hostname tcp-ip-port-nummer} ausführen und einige Male die Eingabetaste
+(@code{RETURN}) drücken. Wenn es auf diesem Port einen laufenden
+MySQL-Server gibt, sollten Sie eine Antwort erhalten, die die
+Versionsnummer des Server enthält. Wenn Sie einen Fehler wie @code{telnet:
+Unable to connect to remote host: Connection refused} erhalten, gibt es auf
+diesem Port keinen laufenden Server.
+@item
+Versuchen Sie, sich mit dem @code{mysqld}-Daemon auf der lokalen Maschine
+zu verbinden und prüfen Sie den TCP/IP-Port, den @code{mysqld} laut
+Konfiguration benutzen soll (Variable @code{port}), mit @code{mysqladmin
+variables}.
+@item
+Prüfen Sie, ob Ihr @code{mysqld}-Server nicht gestartet wurde, indem Sie
+die @code{--skip-networking}-Option verwenden.
+@end itemize
+
+
+@node Blocked host, Too many connections, Can not connect to server, Common errors
+@c German node Blockierter Host
+@appendixsubsec @code{Host '...' is blocked}-Fehler
+
+Wenn Sie einen Fehler wie folgt erhalten:
+
+@example
+Host 'hostname' is blocked because of too many connection errors.
+Unblock with 'mysqladmin flush-hosts'
+@end example
+
+Bedeutet das, dass @code{mysqld} zu viele (@code{max_connect_errors})
+Verbindungsanforderungen vom Host @code{'hostname'} erhalten hat, die
+mittendrin unterbrochen wurden. Nach @code{max_connect_errors}
+fehlgeschlagenen Anfragen nimmt @code{mysqld} an, dass etwas nicht stimmt
+(wie ein Angriff eines Crackers) und blockiert weitere
+Verbindungsanforderungen von der Site, bis jemand @code{mysqladmin
+flush-hosts} ausführt.
+
+Vorgabemäßig blockiert @code{mysqld} einen Host nach 10
+Verbindungsfehlern. Das können Sie leicht durch Starten des Servers wie
+folgt ändern:
+
+@example
+shell> safe_mysqld -O max_connect_errors=10000 &
+@end example
+
+Beachten Sie, dass Sie bei dieser Fehlermeldung für einen gegebenen Host
+zunächst prüfen sollten, ob etwas mit den TCP/IP-Verbindungen von diesem
+Host aus nicht stimmt. Wenn Ihre TCP/IP-Verbindungen nicht funktionieren,
+nützt es Ihnen nichts, den Wert der @code{max_connect_errors}-Variablen
+heraufzusetzen!
+
+
+@node Too many connections, Non-transactional tables, Blocked host, Common errors
+@c German node Zu viele Verbindungen
+@appendixsubsec @code{Too many connections}-Fehler
+
+Wenn Sie beim Verbindungsversuch den Fehler @code{Too many connections}
+erhalten, heißt das, dass es bereits @code{max_connections} Clients gibt,
+die mit dem @code{mysqld}-Server verbunden sind.
+
+Wenn Sie mehr Verbindungen als die Vorgabe (100) benötigen, können Sie
+@code{mysqld} mit einem größeren Wert für die
+@code{max_connections}-Variable neu starten.
+
+Beachten Sie, dass @code{mysqld} tatsächlich (@code{max_connections}+1)
+Clients für Verbindungen zuläßt. Die letzte Verbindung wird für einen
+Benutzer mit der @strong{process}-Berechtigung reserviert. Wenn Sie keinem
+normalen Benutzer diese Berechtigung geben (diese sollte sie nie
+benötigen), kann sich ein Administrator mit dieser Berechtigung einloggen
+und @code{SHOW PROCESSLIST} benutzen, um herauszufinden, was schief geht.
+@xref{SHOW}.
+
+Die maximale Anzahl von Verbindungen ist davon abhängig, wie gut die
+Thread-Bibliothek auf der Plattform ist. Linux oder Solaris sollten in der
+Lage sein, 500 bis 1000 gleichzeitige Verbindungen zu unterstützen, abhängig
+davon, wie viel Arbeitsspeicher Sie haben und was Ihre Clients ausführen.
+
+
+@node Non-transactional tables, Out of memory, Too many connections, Common errors
+@c German node Nicht transaktionale Tabellen
+@appendixsubsec @code{Some non-transactional changed tables couldn't be rolled back}-Fehler
+
+@cindex Nicht transaktionale Tabellen
+
+Wenn Sie den Fehler @code{Warning: Some non-transactional changed tables
+couldn't be rolled back} erhalten, wenn Sie ein @code{ROLLBACK} versuchen,
+bedeutet das, dass einige der bei der Transaktion benutzten Tabellen keine
+Transaktionen unterstützen. Diese nicht transkationalen Tabellen werden vom
+@code{ROLLBACK}-Statement nicht betroffen.
+
+Der typischste Fall, bei dem dieser Fehler auftritt, ist, wenn Sie versucht
+haben, eine Tabelle von einem Typ zu erzeugen, der von Ihrer
+@code{mysqld}-Binärdatei nicht unterstützt wird. Wenn @code{mysqld} einen
+Tabellentyp nicht unterstützt (oder wenn der Tabellentyp durch die
+Startoption ausgeschaltet ist), wird statt dessen ein Tabellentyp erzeugt,
+der dem angeforderten am nächsten entspricht (wahrscheinlich
+@code{MyISAM}.
+
+Sie können den Tabellentyp für eine Tabelle wie folgt überprüfen:
+
+@code{SHOW TABLE STATUS LIKE 'tabelle'}. @xref{SHOW TABLE STATUS}.
+
+Sie können die Erweiterungen, die Ihre @code{mysqld}-Binärdatei
+unterstützt, wie folgt überprüfen:
+
+@code{show variables like 'have_%'}. @xref{SHOW VARIABLES}.
+
+
+@node Out of memory, Packet too large, Non-transactional tables, Common errors
+@c German node Kein Speicher verfügbar
+@appendixsubsec @code{No free memory}-Fehler
+
+Wenn Sie eine Anfrage ausführen und etwas wie folgenden Fehler erhalten:
+
+@example
+mysql: No free memory at line 42, 'malloc.c'
+mysql: needed 8136 byte (8k), memory in use: 12481367 Bytes (12189k)
+ERROR 2008: MySQL client ran No free memory
+@end example
+
+Beachten Sie, dass sich dieser Fehler auf den MySQL-Client @code{mysql}
+bezieht. Der Grund für diesen Fehler ist einfach, dass der Client nicht
+genug freien Speicher hat, um das gesamte Ergebnis zu speichern.
+
+Um das Problem zu beheben, prüfen Sie zunächst, ob Ihre Anfrage korrekt
+ist. Sollte sie vernünftigerweise so viele Zeilen zurückgeben? Wenn das der
+Fall ist, können Sie @code{mysql --quick} benutzen, was
+@code{mysql_use_result()} benutzt, um die Ergebnismenge abzurufen.
+Hierdurch wird Last vom Client auf den Server verlagert.
+
+
+@node Packet too large, Communication errors, Out of memory, Common errors
+@c German node Paket zu Groß
+@appendixsubsec @code{Packet too large}-Fehler
+
+Wenn ein MySQL-Client oder der @code{mysqld}-Server ein Paket erhält, das
+größer als @code{max_allowed_packet} Bytes ist, gibt er einen @code{Packet
+too large}-Fehler aus und schließt die Verbindung.
+
+Wenn Sie den @code{mysql}-Client benutzen, müssen Sie einen größeren
+Puffer angeben, indem Sie den Client mit @code{mysql
+--set-variable=max_allowed_packet=8M} starten.
+
+Wenn Sie andere Clients benutzen, die die Angabe der maximalen Paketgröße
+nicht zulassen (wie @code{DBI}), müssen Sie die Paketgröße beim Start des
+Servers setzen. Sie können eine Kommandozeilenoption für @code{mysqld}
+benutzen, um @code{max_allowed_packet} auf eine höhere Größe zu setzen.
+Wenn Sie zum Beispiel beabsichtigen, die volle Länge eines @code{BLOB} in
+eine Tabelle zu speichern, müssen Sie den Server mit der
+@code{--set-variable=max_allowed_packet=16M}-Option starten.
+
+Sie können merkwürdige Probleme mit großen Paketen erhalten, wenn Sie
+große Blobs benutzen, aber @code{mysqld} keinen Zugriff auf genug Speicher
+gegeben haben, um die Anfrage zu handhaben. Wenn Sie vermuten, dass das der
+Fall ist, versuchen Sie, am Anfang des @code{safe_mysqld}-Skripts
+@code{ulimit -d 256000} hinzuzufügen, und starten Sie @code{mysqld} neu.
+
+@node Communication errors, Full table, Packet too large, Common errors
+@c German node Kommunikationsfehler
+@appendixsubsec Kommunikationsfehler / Abgebrochene Verbindung
+
+@cindex Abgebrochene Clients
+@cindex Abgebrochene Verbindung
+@cindex Verbindung, abgebrochen
+
+Ab @code{MySQL 3.23.40} erhalten Sie den @code{Aborted connection}-Fehler
+nur dann, wenn Sie @code{mysqld} mit @code{--warnings} starten.
+
+Wenn Sie Fehler wie den folgenden in Ihrer Fehler-Log-Datei entdecken:
+
+@example
+010301 14:38:23 Aborted connection 854 to db: 'Benutzer' user: 'josh'
+@end example
+
+@xref{Error log}.
+
+Bedeutet das, dass eins der folgenden Dinge passiert ist:
+
+@itemize @bullet
+@item
+Das Client-Programm rief vor dem Beenden nicht @code{mysql_close()} auf.
+@item
+Der Client schlief länger als @code{wait_timeout} oder
+@code{interactive_timeout}, ohne Anfragen auszuführen.
+@c German FIX unsplit @xref
+@xref{SHOW VARIABLES}.
+@item
+Das Client-Programm wurde abrupt während einer Übertragung beendet.
+@end itemize
+
+Wenn das oben Genannte passiert, wird die Servervariable
+@code{Aborted_clients} heraufgezählt.
+
+Die Servervariable @code{Aborted_connects} wird in folgenden Fällen
+heraufgezählt:
+
+@itemize @bullet
+@item
+Wenn ein Verbindungspaket nicht die richtigen Informationen enthält.
+@item
+Wenn der Benutzer keine Berechtigung hat, sich mit einer Datenbank zu
+verbinden.
+@item
+Wenn ein Benutzer ein falsches Passwort angegeben hat.
+@item
+Wenn es länger als @code{connect_timeout} Sekunden dauert, um ein
+Verbindungspaket zu erhalten.
+@end itemize
+
+Beachten Sie, dass obiges auch anzeigen könnte, dass jemand versucht, in
+Ihre Datenbank einzubrechen!
+
+@xref{SHOW VARIABLES}.
+
+Andere Gründe für Probleme mit abgebrochenen Clients / abgebrochenen
+Verbindungen:
+@itemize @bullet
+@item
+Benutzung des Duplex-Ethernet-Protokolls, sowohl Halb- als auch
+Voll-Duplex, unter Linux. Viele Linux-Ethernet-Treiber haben diesen Bug.
+Sie können auf diesen Bug überprüfen, indem Sie eine sehr große Datei via
+FTP zwischen diesen beiden Maschinen übertragen. Wenn ein Transfer nach dem
+Schema schnelle Übertragung - Pause - schnelle Übertragung - Pause läuft,
+haben Sie ein Linux-Duplex-Syndrom. Die einzige Lösung besteht darin, Halb-
+und Vollduplex auf Hubs und Switches auszuschalten.
+@item
+Probleme mit der Thread-Bibliothek, was Unterbrechungen bei Lesevorgängen
+verursacht.
+@item
+Schlecht konfiguriertes TCP/IP.
+@item
+Fehlerhafte Ethernets, Hubs, Switches, Kabel usw. Das kann nur durch
+Austausch von Hardware sauber diagnostiziert werden.
+@item
+@code{max_allowed_packet} ist zu klein oder Anfragen erfordern mehr
+Speicher, als Sie für @code{mysqld} zugewiesen haben.
+@c German FIX unwrapped @xref
+@xref{Packet too large}.
+@end itemize
+
+
+@node Full table, Cannot create, Communication errors, Common errors
+@c German node Tabelle voll
+@appendixsubsec @code{The table is full}-Fehler
+
+@cindex Tabelle ist voll
+
+Der Fehler tritt in älteren MySQL-Versionen auf, wenn eine
+Hauptspeicher-basierende temporäre Tabelle größer als
+@code{tmp_table_size} Bytes wird. Um dieses Problem zu vermeiden, können
+Sie die @code{-O tmp_table_size=#}-Option für @code{mysqld} benutzen, um
+die Größe der temporären Tabelle zu erhöhen, oder die SQL-Option
+@code{SQL_BIG_TABLES} verwenden, bevor Sie die problematische Anfrage
+abschicken. @xref{SET OPTION, , @code{SET OPTION}}.
+
+Sie können auch @code{mysqld} mit der @code{--big-tables}-Option starten.
+Das ist genau dasselbe, wie @code{SQL_BIG_TABLES} für alle Anfragen zu
+benutzen.
+
+In MySQL-Version 3.23 werden Hauptspeicher-basierende temporäre Tabellen
+automatisch in Festplatten-basierende @code{MyISAM}-Tabellen umgewandelt,
+wenn die Tabelle größer als @code{tmp_table_size} wird.
+
+
+@node Cannot create, Commands out of sync, Full table, Common errors
+@c German node Kann nicht erzeugen
+@appendixsubsec @code{Can't create/write to file}-Fehler
+
+@cindex can't create/write to file
+
+Wenn Sie für einige Anfragen Fehler folgenden Typs erhalten:
+
+@example
+Can't create/write to file '\\sqla3fe_0.ism'.
+@end example
+
+Bedeutet das, dass MySQL keine temporäre Datei für die Ergebnismenge im
+angegebenen temporären Verzeichnis erzeugen kann. (Der obige Fehler ist
+eine typische Fehlermeldung unter Windows; die Unix-Fehlermeldung ist
+ähnlich.) Das Problem läßt sich beheben, indem Sie @code{mysqld} mit
+@code{--tmpdir=pfad} starten oder folgendes in Ihrer Optionsdatei ergänzen:
+
+@example
+[mysqld]
+tmpdir=C:/temp
+@end example
+
+Unter der Annahme, dass das @file{c:\\temp}-Verzeichnis existiert.
+@xref{Option files}.
+
+Überprüfen Sie auch den Fehler-Code, den Sie bei @code{perror} erhalten.
+Ein Grund kann ein Fehler wegen fehlenden Festplattenspeichers sein:
+
+@example
+shell> perror 28
+Error code 28: No space left on device
+@end example
+
+
+@node Commands out of sync, Ignoring user, Cannot create, Common errors
+@c German node Befehl nicht synchronisiert
+@appendixsubsec @code{Command out of sync}-Fehler in Client
+
+@cindex Befehle nicht synchronisiert
+
+Wenn Sie den Fehler @code{command out of sync; You can't run this command
+now} in Ihrem Client-Code erhalten, rufen Sie Client-Funktionen in der
+falschen Reihenfolge auf!
+
+Das kann zum Beispiel passieren, wenn Sie @code{mysql_use_result()}
+benutzen und versuchen, eine neue Anfrage auszuführen, bevor Sie
+@code{mysql_free_result()} aufgerufen haben. Der Fehler passiert ebenfalls,
+wenn Sie versuchen, zwei Anfragen auszuführen, die Daten zurückgeben, ohne
+zwischendrin @code{mysql_use_result()} oder @code{mysql_store_result()}
+aufzurufen.
+
+
+@node Ignoring user, Cannot find table, Commands out of sync, Common errors
+@c German node Benutzer ignoriert
+@appendixsubsec @code{User ignored}-Fehler
+
+Wenn Sie folgenden Fehler erhalten:
+
+@code{Found wrong password for user: 'benutzer@@ein_host'; User ignored}
+
+Bedeutet das, dass @code{mysqld} beim Start oder nach dem Neuladen der
+Berechtigungstabellen einen Eintrag in der @code{user}-Tabelle mit einem
+ungültigen Passwort gefunden hat. Als Ergebnis wird der Eintrag vom
+Berechtigungssystem einfach ignoriert.
+
+Mögliche Gründe und Problembehebung:
+
+@itemize @bullet
+@item
+Sie lassen eine neue Version von @code{mysqld} mit einer alten
+@code{user}-Tabelle laufen. Das können Sie prüfen, indem Sie
+@code{mysqlshow mysql user} eingeben, um zu sehen, ob das Passwortfeld
+kürzer als 16 Zeichen ist. Wenn das der Fall ist, können Sie diesen Zustand
+beheben, indem Sie das @code{scripts/add_long_password}-Skript laufen
+lassen.
+
+@item
+Der Benutzer hat ein altes Passwort (8 Zeichen lang) und Sie haben
+@code{mysqld} nicht mit der @code{--old-protocol}-Option gestartet.
+
+@item
+@findex PASSWORD()
+Sie haben in der @code{user}-Tabelle ein Passwort eingegeben, ohne die
+@code{PASSWORD()}-Funktion zu benutzen. Benutzen Sie @code{mysql}, um den
+Benutzer in der @code{user}-Tabelle mit einem neuen Passwort zu
+aktualisieren. Stellen Sie sicher, dass Sie die @code{PASSWORD()}-Funktion
+benutzen:
+
+@example
+mysql> update user set password=PASSWORD('ihr_passwort')
+ where user='XXX';
+@end example
+@end itemize
+
+
+@node Cannot find table, Cannot initialize character set, Ignoring user, Common errors
+@c German node Tabelle nicht gefunden
+@appendixsubsec @code{Table 'xxx' doesn't exist}-Fehler
+
+Wenn Sie den Fehler @code{Table 'xxx' doesn't exist} oder @code{Can't find
+file: 'xxx' (errno: 2)} erhalten, bedeutet das, dass in der aktuellen
+Datenbank keine Tabelle mit dem Namen @code{xxx} existiert.
+
+Beachten Sie, dass Datenbank- und Tabellennamen @strong{abhängig von der
+verwendeten Groß-/Kleinschreibung} sind, weil MySQL Verzeichnisse und
+Dateien benutzt, um Datenbanken und Tabellen zu speichern! (Unter Windows
+sind Datenbank- und Tabellennamen unabhängig von der Schreibweise, aber
+alle Verweise auf eine gegebene Tabelle innerhalb einer Anfrage müssen
+dieselbe Schreibweise benutzen!)
+
+Sie finden heraus, welche Tabellen sich in der aktuellen Datenbank
+befinden, indem Sie @code{SHOW TABLES} eingeben. @xref{SHOW, ,
+@code{SHOW}}.
+
+
+@node Cannot initialize character set, Not enough file handles, Cannot find table, Common errors
+@c German node Zeichensatz kann nicht initialisiert werden
+@appendixsubsec @code{Can@'t initialize charset xxx}-Fehler.
+
+@cindex Multibyte-Zeichensätze
+
+Wenn Sie folgenden Fehler erhalten:
+
+@example
+MySQL Connection Failed: Can't initialize charset xxx
+@end example
+
+Bedeutet das eins der folgenden Dinge:
+
+@itemize @bullet
+@item
+Der Zeichensatz ist ein Multi-Byte-Zeichensatz und Ihr Client unterstützt
+diesen Zeichensatz nicht.
+
+In diesem Fall müssen Sie Ihren Client neu kompilieren und die
+@code{--with-charset=xxx}- oder die @code{--with-extra-charsets=xxx}-Option
+angeben. @xref{configure options}.
+
+Alle Standard-MySQL-Binärdistributionen werden mit
+@code{--with-extra-character-sets=complex} kompiliert, was die
+Unterstützung für alle Multi-Byte-Zeichensätze aktiviert.
+@xref{Character sets}.
+
+@item
+Der Zeichensatz ist ein einfacher Zeichensatz, der nicht in @code{mysqld}
+kompiliert wurde, und die Zeichensatz-Definitionsdateien sind nicht an der
+Stelle, an der der Client sie erwartet.
+
+In diesem Fall müssen Sie:
+
+@itemize @bullet
+@item
+Den Client mit Unterstützung für den Zeichensatz neu kompilieren.
+@xref{configure options}.
+@item
+Dem Client angeben, wo die Zeichensatz-Definitionsdateien sind. Bei vielen
+Clients können Sie das mit der
+@code{--character-sets-dir=pfad-to-charset-dir}-Option machen.
+@item
+Die Zeichensatz-Definitionsdatei in den Pfad kopieren, wo der Client sie zu
+finden erwartet.
+@end itemize
+@end itemize
+
+
+@node Not enough file handles, , Cannot initialize character set, Common errors
+@c German node Nicht genug Datei-Handles
+@appendixsubsec File Not Found
+
+Wenn Sie den Fehler @code{ERROR '...' not found (errno: 23)}, @code{Can't
+open file: ... (errno: 24)} oder irgend einen anderen Fehler mit
+@code{errno 23} oder @code{errno 24} erhalten, bedeutet das, dass Sie MySQL
+nicht genug Datei-Deskriptoren zugewiesen haben. Sie können das
+@code{perror}-Dienstprogramm benutzen, um eine Beschreibung dessen zu
+erhalten, was die Fehlernummer bedeutet:
+
+@example
+shell> perror 23
+File table overflow
+shell> perror 24
+Too many open files
+shell> perror 11
+Resource temporarily unavailable
+@end example
+
+Das Problem hierbei ist, dass @code{mysqld} versucht, zu viele Dateien
+gleichzeitig offen zu halten. Sie können entweder @code{mysqld}
+veranlassen, nicht so viele Dateien auf einmal zu öffnen, oder die Anzahl
+von Datei-Deskriptoren heraufsetzen, über die @code{mysqld} verfügen kann.
+
+Um @code{mysqld} anzuweisen, weniger Dateien zugleich offen zu halten,
+können Sie den Tabellen-Cache kleiner machen, indem Sie die @code{-O
+table_cache=32}-Option für @code{safe_mysqld} benutzen (der Vorgabewert ist
+64). Wenn Sie den Wert von @code{max_connections} verringern, reduziert
+auch das die Anzahl offener Dateien (der Vorgabewert ist 90).
+
+@tindex ulimit
+Um die Anzahl von Datei-Deskriptoren, die @code{mysqld} zur Verfügung
+stehen, zu ändern, können Sie die @code{--open-files-limit=#}-Option für
+@code{safe_mysqld} oder die @code{-O open-files-limit=#}-Option für
+@code{mysqld} benutzen. @xref{SHOW VARIABLES}. Die einfachste Art, das zu
+tun, besteht darin, eine Option zu Ihrer Optionsdatei hinzuzufügen.
+@xref{Option files}. Wenn Sie eine alte @code{mysqld}-Version haben, die
+das nicht unterstützt, können Sie das @code{safe_mysqld}-Skript editieren.
+Es gibt dort eine auskommentierte Zeile @code{ulimit -n 256}. Entfernen Sie
+das @code{'#'}-Zeichen, um diese Zeile zu aktivieren, und ändern Sie die
+Anzahl 256, um die Anzahl verfügbarer Datei-Deskriptoren zu beeinflussen.
+
+Mit @code{ulimit} (und @code{open-files-limit}) kann man die Anzahl von
+Datei-Deskriptoren heraufsetzen, aber nur bis zu der Grenze, die das
+Betriebssystem vorgibt. Darüber hinaus gibt es eine 'harte' Grenze, die nur
+überschrieben werden kann, wenn Sie @code{safe_mysqld} oder @code{mysqld}
+als Root starten (denken Sie daran, dass Sie in diesem Fall auch die
+@code{--user=..}-Option benutzen müssen). Wenn Sie die
+Betriebssystem-Grenze hinsichtlich der Anzahl von Datei-Deskriptoren, die
+für jeden Prozess verfügbar sind, heraufsetzen müssen, schauen Sie in der
+Dokumentation Ihres Betriebssystems nach.
+
+Beachten Sie, dass @code{ulimit} nicht funktioniert, wenn Sie die
+@code{tcsh}-Shell laufen lassen! @code{tcsh} berichtet auch nicht korrekte
+Werte, wenn Sie die aktuellen Grenzen abfragen! In diesem Fall sollten Sie
+@code{safe_mysqld} mit @code{sh} starten!
+
+
+@node Installation Issues, Administration Issues, Common errors, Problems
+@c German node Installationsprobleme
+@appendixsec Installationsbezogene Themen
+
+
+
+@menu
+* Link errors::
+* Changing MySQL user::
+* File permissions ::
+@end menu
+
+@node Link errors, Changing MySQL user, Installation Issues, Installation Issues
+@c German node Link-Fehler
+@appendixsubsec Probleme beim Linken mit der MySQL-Client-Bibliothek
+
+@cindex linken, Fehler
+@cindex Fehler, linken
+@cindex Probleme, linken
+
+Wenn Sie Ihr Programm linken und Fehler für unreferenzierte Symbole
+erhalten, die mit @code{mysql_} beginnen, wie folgende:
+
+@example
+/tmp/ccFKsdPa.o: In function `main':
+/tmp/ccFKsdPa.o(.text+0xb): undefined reference to `mysql_init'
+/tmp/ccFKsdPa.o(.text+0x31): undefined reference to `mysql_real_connect'
+/tmp/ccFKsdPa.o(.text+0x57): undefined reference to `mysql_real_connect'
+/tmp/ccFKsdPa.o(.text+0x69): undefined reference to `mysql_error'
+/tmp/ccFKsdPa.o(.text+0x9a): undefined reference to `mysql_close'
+@end example
+
+Sollten Sie das durch Hinzufügen von
+@code{-Lpath-to-the-mysql-library-lmysqlclient} als @strong{LETZTES} in
+Ihrer Link-Zeile beheben können.
+
+Wenn Sie @code{undefined reference}-Fehler bei der @code{uncompress}- oder
+@code{compress}-Funktion erhalten, fügen Sie @code{-lz} als
+@strong{LETZTES} zu Ihrer Link-Zeile hinzu und versuchen Sie es noch
+einmal!
+
+Wenn Sie @code{undefined reference}-Fehler bei Funktionen erhalten, die es
+auf Ihrem System geben sollte, wie @code{connect}, sehen Sie in der
+Handbuch-Seite (ManPage) für die fragliche Funktion nach, welche
+Bibliotheken Sie zur Link-Zeile hinzufügen sollten!
+
+Wenn Sie @code{undefined reference}-Fehler bei Funktionen erhalten, die es
+auf Ihrem System nicht gibt, wie folgenden:
+
+@example
+mf_format.o(.text+0x201): undefined reference to `__lxstat'
+@end example
+
+Heißt das üblicherweise, dass Ihre Bibliothek auf einem System kompiliert
+wurde, das nicht 100% kompatibel zu Ihrem System ist. In diesem Fall
+sollten Sie die letzte MySQL-Quelldistribution herunter laden und sie
+selbst kompilieren. @xref{Installing source}.
+
+Wenn Sie versuchen, ein Programm laufen zu lassen und Fehler für
+unreferenzierte Symbole erhalten, die mit @code{mysql_} anfangen, oder den
+Fehler, dass die @code{mysqlclient}-Bibliothek nicht gefunden werden kann,
+heißt das, dass Ihr System die gemeinsam genutzte
+@code{libmysqlclient.so}-Bibliothek nicht findet.
+
+Das Problem beheben Sie, indem Sie Ihr System anweisen, dort nach gemeinsam
+genutzten Bibliotheken zu suchen, wo sich die Bibliothek befindet, mit
+einer der folgenden Methoden:
+
+@itemize @bullet
+@item
+Fügen Sie den Pfad zum Verzeichnis, in dem Sie @code{libmysqlclient.so}
+haben, der @code{LD_LIBRARY_PATH}-Umgebungsvariablen hinzu.
+@item
+Fügen Sie den Pfad zum Verzeichnis, in dem Sie @code{libmysqlclient.so}
+haben, der @code{LD_LIBRARY}-Umgebungsvariablen hinzu.
+@item
+Kopieren Sie @code{libmysqlclient.so} an eine Stelle, die von Ihrem System
+durchsucht wird, wie @file{/lib}, und aktualisieren Sie die Informationen
+über gemeinsam genutzte Bibliotheken, indem Sie @code{ldconfig} ausführen.
+@end itemize
+
+Eine weitere Möglichkeit, dieses Problem zu lösen, besteht darin, Ihr
+Programm statisch mit @code{-static} zu linken oder die dynamischen
+MySQL-Bibliotheken zu entfernen, bevor Sie Ihren Code linken. Im letzteren
+Fall sollten Sie sicherstellen, dass keine anderen Programme die
+dynamischen Bibliotheken benutzen!
+
+
+@node Changing MySQL user, File permissions , Link errors, Installation Issues
+@c German node Änderung des MySQL-Benutzers
+@appendixsubsec Wie man MySQL als normaler Benutzer laufen läßt
+
+@cindex starten, @code{mysqld}
+@cindex @code{mysqld}, starten
+
+Der MySQL-Server @code{mysqld} kann von jedem beliebigen Benutzer gestartet
+werden und unter diesem laufen. Damit @code{mysqld} als Unix-Benutzer
+@code{benutzername} läuft, müssen Sie folgendes tun:
+
+@enumerate
+@item
+Halten Sie den Server an, falls er läuft (benutzen Sie @code{mysqladmin
+shutdown}).
+
+@item
+Ändern Sie die Datenbankverzeichnisse und Dateien so, dass
+@code{benutzername} die Berechtigungen zum Lesen und Schreiben von Dateien
+darin hat (das müssen Sie eventuell als Unix-@code{root}-Benutzer machen):
+
+@example
+shell> chown -R benutzername /pfad/zu/mysql/datadir
+@end example
+
+Wenn Verzeichnisse oder Dateien im MySQL-Daten-Verzeichnis symbolische
+Links sind, müssen Sie auch diesen Verknüpfungen folgen und die
+Verzeichnisse und Dateien, auf die sie zeigen, ändern. @code{chown -R} kann
+SymLinks für Sie folgen.
+
+@item
+Starten Sie den Server als Benutzer @code{benutzername} oder, wenn Sie
+MySQL-Version 3.22 oder später benutzen, starten Sie @code{mysqld} als
+Unix-@code{root}-Benutzer und benutzen Sie die
+@code{--user=benutzername}-Option. @code{mysqld} schaltet um und läuft dann
+unter Unix-Benutzer @code{benutzername}, bevor er irgend welche
+Verbindungen annimmt.
+
+@item
+Um den Server automatisch beim Hochfahren des Systems unter dem angegebenen
+Benutzernamen zu starten, fügen Sie zur @code{[mysqld]}-Gruppe der
+@file{/etc/my.cnf}-Optionendatei oder der @file{my.cnf}-Optionendatei im
+Datenverzeichnis des Servers eine @code{user}-Zeile hinzu, die den
+Benutzernamen angibt. Beispiel:
+
+@example
+[mysqld]
+user=benutzername
+@end example
+@end enumerate
+
+Nunmehr sollte Ihr @code{mysqld}-Prozess korrekt unter dem Unix-Benutzer
+@code{benutzername} laufen. Dennoch hat sich eins nicht geändert: Die
+Inhalte der Berechtigungstabellen. Vorgabemäßig (direkt nach dem
+Laufenlassen des Skripts @code{mysql_install_db}, das die
+Berechtigungstabellen installiert), ist der MySQL-Benutzer @code{root} der
+einzige Benutzer mit Zugriffsrechten auf die @code{mysql}-Datenbank. Er ist
+auch der einzige, der Datenbanken erzeugen und löschen kann. Wenn Sie diese
+Berechtigungen nicht geändert haben, sind sie noch gültig. Das sollte Sie
+nicht davon abhalten, auf MySQL als der MySQL-@code{root}-Benutzer
+zuzugreifen, wenn Sie als ein anderer Unix-Benutzer als @code{root}
+eingeloggt sind. Geben Sie einfach für Client-Programme die @code{-u
+root}-Option an.
+
+Beachten Sie, dass der Zugriff auf MySQL als @code{root} (indem Sie
+@code{-u root} auf der Kommandozeile eingeben) @emph{nichts} damit zu tun
+hat, dass Sie MySQL als Unix-@code{root}-Benutzer laufen lassen oder als
+irgend ein anderer Unix-Benutzer. Die Zugriffsberechtigungen und
+Benutzernamen von MySQL sind komplett unterschiedlich von den
+Unix-Benutzernamen. Die einzige Verbindung mit Unix-Benutzernamen besteht
+darin, dass ein Client versuchen wird, sich mit Ihrem Unix-Login-Namen als
+MySQL-Benutzernamen zu verbinden, wenn Sie beim Aufruf eines
+Client-Programms keine @code{-u}-Option angeben.
+
+Wenn Ihre Unix-Box selbst nicht abgesichert ist, sollten Sie zumindest ein
+Passwort für den MySQL-@code{root}-Benutzer in den Berechtigungstabellen
+angeben. Ansonsten kann jeder beliebige Benutzer mit einem Konto auf der
+Maschine @code{mysql -u root datenbank} eingeben und tun, was er will.
+
+
+@node File permissions , , Changing MySQL user, Installation Issues
+@c German node Dateirechte
+@appendixsubsec Probleme mit Dateirechten
+
+@cindex Dateien, Rechte
+@cindex Fehlermeldungen, can't find file
+@cindex Dateien, Nachricht not found
+
+Wenn Sie Probleme mit Dateirechten haben, wenn @code{mysql} zum Beispiel
+folgende Fehlermeldung beim Erzeugen einer Tabelle ausgibt:
+
+@example
+Error: Can't find file: 'pfad/mit/dateiname.frm' (Errcode: 13)
+@end example
+
+@tindex UMASK-Umgebungsvariable
+@tindex Umgebungsvariable, UMASK
+Kann es sein, dass die Umgebungsvariable @code{UMASK} falsch gesetzt ist,
+wenn @code{mysqld} startet. Der vorgabemäßige umask-Wert ist @code{0660}.
+Sie können dieses Verhalten ändern, indem Sie @code{safe_mysqld} wie folgt
+starten:
+
+@example
+shell> UMASK=384 # = 600 in oktal
+shell> export UMASK
+shell> /pfad/zu/safe_mysqld &
+@end example
+
+@tindex UMASK_DIR-Umgebungsvariable
+@tindex Umgebungsvariable, UMASK_DIR
+Vorgabemäßig erzeugt MySQL Datenbank- und @code{RAID}-Verzeichnisse mit
+dem Berechtigungstyp 0700. Dieses Verhalten können Sie durch Setzen der
+@code{UMASK_DIR}-Variablen ändern. Wenn Sie diese setzen, werden neue
+Verzeichnisse mit kombiniertem @code{UMASK} und @code{UMASK_DIR} erzeugt.
+Wenn Sie zum Beispiel Gruppenzugriff auf alle neuen Verzeichnisse geben
+wollen, können Sie folgendes tun:
+
+@example
+shell> UMASK_DIR=504 # = 770 in oktal
+shell> export UMASK_DIR
+shell> /pfad/zu/safe_mysqld &
+@end example
+
+Ab MySQL-Version 3.23.25 nimmt MySQL an, dass die Werte für @code{UMASK}
+und @code{UMASK_DIR} in oktal angegeben sind, wenn sie mit einer 0
+anfangen.
+
+@xref{Environment variables}.
+
+
+@node Administration Issues, Query Issues, Installation Issues, Problems
+@c German node Administrationsprobleme
+@appendixsec Administrationsbezogene Themen
+
+
+
+@menu
+* Crashing::
+* Resetting permissions::
+* Full disk::
+* Temporary files::
+* Problems with mysql.sock::
+* Timezone problems::
+@end menu
+
+@node Crashing, Resetting permissions, Administration Issues, Administration Issues
+@c German node Abstürze
+@appendixsubsec Was zu tun ist, wenn MySQL andauernd abstürzt
+
+@cindex Absturz, wiederholter
+
+Alle MySQL-Versionen werden auf vielen Plattformen getestet, bevor sie
+herausgegeben werden. Das heißt nicht, dass es keinerlei Bugs in MySQL
+gibt, aber es heißt, dass, wenn es Bugs gibt, diese sehr wenige und schwer
+zu finden sind. Wenn Sie ein Problem haben, ist es immer hilfreich
+herauszufinden, was Ihr System zum Absturz bringt, weil Sie dann viel
+bessere Chancen haben, es schnell zu beheben.
+
+Zunächst sollten Sie versuchen herauszufinden, ob das Problem darin
+besteht, dass Ihr @code{mysqld}-Daemon stirbt, oder ob Sie ein Problem mit
+Ihrem Client haben. Sie können herausfinden, seit wann Ihr
+@code{mysqld}-Server hochgefahren ist, indem Sie @code{mysqladmin version}
+ausführen. Wenn @code{mysqld} gestorben ist, finden Sie den Grund hierfür
+womöglich in der Datei @file{mysql-daten-verzeichnis/`hostname`.err}.
+@xref{Error log}.
+
+Viele Abstürze von MySQL werden durch beschädigte Index- oder Daten-Dateien
+verursacht. MySQL aktualisiert die Daten auf Platte mit dem @code{write()}
+Systemaufruf, nach jedem SQL-Statement und bevor der Client über das
+Ergebnis unterrichtet wird. (Das gilt nicht, wenn Sie mit
+@code{delayed_key_writes} fahren, denn in diesem Fall werden nur die Daten
+geschrieben.) Das bedeutet, dass die Daten sicher sind, selbst wenn
+@code{mysqld} abstürzt, weil das Betriebssystem sicherstellt, dass die
+nicht von MySQL zurückgeschriebenen Daten (flush) auf Platte
+zurückgeschrieben werden. Sie können MySQL zwingen, alles nach jedem
+SQL-Befehl auf Platte zurückzusynchronisieren, indem Sie @code{mysqld} mit
+@code{--flush} starten.
+
+Das Gesagte bedeutet, dass Sie normalerweise keine beschädigten Tabellen
+erhalten sollten, ausser in folgenden Fällen:
+
+@itemize @bullet
+@item
+Jemand oder etwas killte @code{mysqld} oder die Maschine mitten während
+einer Aktualisierung.
+@item
+Sie haben einen Bug in @code{mysqld} gefunden, der dazu führte, dass er
+mitten während einer Aktualisierung starb.
+@item
+Jemand manipuliert die Daten- / Index-Dateien ausserhalb von
+@strong{mysqld}, ohne die Tabelle korrekt zu sperren.
+@item
+Wenn Sie viele @code{mysqld}-Server auf denselben Daten auf einem System
+laufen lassen, das Dateisystem-Sperren nicht gut unterstützt (das wird
+normalerweise vom @code{lockd}-Daemon gehandhabt) oder wenn Sie mehrere
+Server mit @code{--skip-locking} fahren.
+@item
+Wenn Sie eine beschädigte Index- / Daten-Datei haben, die sehr falsche
+Daten enthält, die @code{mysqld} durcheinander brachten.
+@item
+Sie haben einen Bug im Datenspeicher-Code gefunden. Das ist nicht sehr
+wahrscheinlich, aber zumindest möglich. In diesem Fall können Sie
+versuchen, den Dateityp auf einen anderen Datenbank-Handler umzustellen,
+indem Sie @code{ALTER TABLE} auf eine reparierte Kopie der Tabelle
+anwenden!
+@end itemize
+
+Weil es sehr schwierig ist herauszufinden, warum etwas abstürzt, versuchen
+Sie zuerst herauszufinden, ob Dinge, die bei anderen funktionieren, bei
+Ihnen abstürzen, oder ob das nicht der Fall ist. Versuchen Sie bitte
+folgendes:
+
+@itemize @bullet
+@item
+Fahren Sie den @code{mysqld}-Daemon mit @code{mysqladmin shutdown} herunter
+und führen Sie @code{myisamchk --silent --force */*.MYI} auf alle Tabellen
+aus. Starten Sie den @code{mysqld}-Daemon erneut. Das stellt sicher, dass
+Sie von einem sauberen Ausgangszustand aus fahren.
+@xref{MySQL Database Administration}.
+
+@item
+Benutzen Sie @code{mysqld --log} und versuchen Sie den Informationen im Log
+zu entnehmen, ob eine bestimmte Anfrage den Server killt oder nicht. Etwa
+95% aller Bugs beziehen sich auf eine bestimmte Anfrage! Normalerweise ist
+das eine der letzten Anfragen in der Log-Datei, direkt bevor MySQL neu
+startete. @xref{Query log}. Wenn Sie MySQL wiederholt mit einer
+der Anfragen killen, selbst wenn Sie alle Tabellen direkt vor der
+Ausführung der Anfrage überprüft haben, haben Sie den Bug eingegrenzt und
+sollten dafür einen Bug-Bericht schreiben! @xref{Bug reports}.
+
+@item
+Versuchen Sie, einen Testfall herzustellen, den wir zur Reproduzierung des
+Problems verwenden können. @xref{Reproduceable test case}.
+
+@item
+Versuchen Sie, die beigefügten mysql-test test und MySQL-Benchmarks laufen
+zu lassen. @xref{MySQL-Test-Suite}. Sie können MySQL recht gut prüfen. Sie
+können den Benchmarks auch selbst Code hinzufügen, der Ihre Applikation
+simuliert! Die Benchmarks finden sich im @file{bench}-Verzeichnis in der
+Quelldistribution oder bei einer Binärdistribution im
+@file{sql-bench}-Verzeichnis unter Ihrem MySQL-Installationsverzeichnis.
+
+@item
+Probieren Sie @code{fork_test.pl} und @code{fork2_test.pl}.
+
+@item
+Wenn Sie MySQL zum Debuggen konfigurieren, ist es wesentlich einfacher,
+Informationen über mögliche Fehler zu erhalten, wenn etwas schief geht.
+Konfigurieren Sie MySQL mit der @code{--with-debug}-Option oder mit der
+@code{--with-debug=full}-Option für @code{configure} neu und kompilieren
+Sie neu. @xref{Debugging server}.
+
+@item
+Wenn MySQL zum Debuggen konfiguriert wird, wird ein sicherer
+Speicher-Zuweiser (Memory Allocator) hinzugefügt, der einige Fehler finden
+kann. Ausserdem erfolgen etliche Ausgaben über das, was gerade geschieht.
+
+@item
+Haben Sie die neuesten Patches für Ihr Betriebssystem installiert?
+
+@item
+Benutzen Sie die @code{--skip-locking}-Option für @code{mysqld}. Auf
+manchen Systemen arbeitet der @code{lockd}-Sperrmanager nicht korrekt. Die
+@code{--skip-locking}-Option weist @code{mysqld} an, keine externen Sperren
+zu benutzen. (Das heißt, dass Sie nicht zwei @code{mysqld}-Server auf
+denselben Daten laufen lassen können und dass Sie vorsichtig sein müssen,
+wenn Sie @code{myisamchk} benutzen, aber es kann aufschlussreich sein, die
+Option testweise zu benutzen.)
+
+@item
+Haben Sie @code{mysqladmin -u root processlist} ausprobiert, wenn
+@code{mysqld} zu laufen scheint, aber nicht antwortet? Manchmal ist
+@code{mysqld} nicht komatös, obwohl es so aussieht. Das Problem kann darin
+bestehen, dass alle Verbindungen in Benutzung sind, oder es kann ein
+internes Sperrproblem vorliegen. @code{mysqladmin processlist} ist
+üblicherweise in der Lage, in solchen Fällen eine Verbindung aufzubauen und
+kann nützliche Informationen über die momentane Anzahl von Verbindungen und
+ihren Status liefern.
+
+@item
+Lassen Sie den Befehl @code{mysqladmin -i 5 status} oder @code{mysqladmin
+-i 5 -r status} in einem separaten Fenster laufen, um statistische
+Informationen auszugeben, während Sie Ihre anderen Anfragen laufen lassen.
+
+@item
+Versuchen Sie folgendes:
+@enumerate
+@item
+Starten Sie @code{mysqld} von @code{gdb} aus (oder in einem anderen
+Debugger).
+@xref{Using gdb on mysqld}.
+
+@item
+Lassen Sie Ihre Test-Skripts laufen.
+
+@item
+Geben Sie die Ablaufverfolgung (Backtrace) und die lokalen Variablen der
+untersten 3 Ebenen aus. In gdb können Sie das mit folgenden Befehle tun,
+wenn @code{mysqld} innerhalb von gdb abgestürzt ist:
+
+@example
+backtrace
+info local
+up
+info local
+up
+info local
+@end example
+
+Mit gdb können Sie auch untersuchen, welchen Thread es gibt (mit @code{info
+thread} und zu einem speziellen Thread umschalten (mit @code{thread #},
+wobei @code{#} die Thread-Kennung ist).
+@end enumerate
+
+@item
+Versuchen Sie, Ihre Applikation mit einem Perl-Skript zu simulieren, um
+MySQL zu zwingen, abzustürzen oder fehlerhaftes Verhalten an den Tag zu
+legen.
+
+@item
+Senden Sie einen normalen Bug-Bericht. @xref{Bug reports}. Geben Sie mehr
+Details an als üblich. Weil MySQL bei vielen Leuten funktioniert, kann es
+sein, dass der Absturz das Ergebnis von etwas ist, das nur auf Ihrem
+Computer existiert (beispielsweise ein Fehler, der aus Ihren besonderen
+Systembibliotheken resultiert).
+
+@item
+Wenn Sie ein Problem mit Tabellen haben, die Zeilen dynamischer Länge
+enthalten, und Sie nicht @code{BLOB/TEXT}-Spalten benutzen (sondern nur
+@code{VARCHAR}-Spalten), können Sie versuchen, alle @code{VARCHAR}- in
+@code{CHAR}-Spalten umzuwandeln, indem Sie @code{ALTER TABLE} verwenden.
+Das erzwingt, dass MySQL Zeilen fester Länge verwendet. Zeilen fester Länge
+benötigen etwas mehr Platz, sind aber fehlertoleranter gegenüber
+Beschädigungen!
+
+Der aktuelle Code mit dynamischen Zeilen ist bei MySQL AB seit mindestens
+drei Jahren ohne jedes Problem in Benutzung, aber naturgemäß sind Zeilen
+dynamischer Länge fehleranfälliger. Daher kann es eine gute Idee sein, das
+oben Gesagte auszuprobieren.
+@end itemize
+
+
+@node Resetting permissions, Full disk, Crashing, Administration Issues
+@c German node Berechtigungen zurücksetzen
+@appendixsubsec Wie ein vergessenes Passwort zurückgesetzt wird
+
+@cindex Passwörter, vergessen
+@cindex Passwörter, zurücksetzen
+@cindex Root-Benutzer, Passwort zurücksetzen
+
+Wenn Sie das @code{root}-Benutzerpasswort für MySQL vergessen haben, können
+Sie es mit folgender Prozedur wiederherstellen:
+
+@enumerate
+@item
+Fahren Sie den @code{mysqld}-Server durch Senden von @code{kill} (nicht
+@code{kill -9}) an den @code{mysqld}-Server herunter. Die Prozess-Kennung
+(PID) wird in einer @code{.pid}-Datei gespeichert, die sich normalerweise
+im MySQL-Datenbank-Verzeichnis befindet:
+
+@example
+kill `cat /mysql-daten-verzeichnis/hostname.pid`
+@end example
+
+Hierfür müssen Sie entweder der Unix-@code{root}-Benutzer sein oder
+derselbe Benutzer, unter dem der Server läuft.
+
+@item
+Starten Sie @code{mysqld} mit der @code{--skip-grant-tables}-Option neu.
+@item
+Verbinden Sie sich mit dem @code{mysqld}-Server mit @code{mysql -h hostname
+mysql} und ändern Sie das Passwort mit einem @code{GRANT}-Befehl.
+@xref{GRANT,,@code{GRANT}}. Sie können dasselbe auch mit @code{mysqladmin
+-h hostname -u benutzer password 'neues_passwort'} machen.
+
+@item
+Laden Sie die Berechtigungstabellen neu mit @code{mysqladmin -h hostname
+flush-privileges} oder mit dem SQL-Befehl @code{FLUSH PRIVILEGES}.
+@end enumerate
+
+Beachten Sie, dass nach dem Start von @code{mysqld} mit
+@code{--skip-grant-tables} jede Benutzung von @code{GRANT}-Befehlen zu
+einem @code{Unknown command}-Fehler führt, bis Sie @code{FLUSH PRIVILEGES}
+ausgeführt haben.
+
+
+@node Full disk, Temporary files, Resetting permissions, Administration Issues
+@c German node Platte voll
+@appendixsubsec Wie MySQL mit vollen Festplatten umgeht
+
+@cindex volle Festplatte
+@cindex Festplatte voll
+
+@noindent
+Wenn etwas hinsichtlich der Festplatte passiert, tut MySQL folgendes:
+
+@itemize @bullet
+@item
+Er prüft einmal pro Minute, um festzustellen, ob es genug Platz gibt, um
+die aktuelle Zeile zu schreiben oder nicht. Wenn genug Platz vorhanden ist,
+wird fortgefahren, als sei nichts geschehen.
+@item
+Alle 6 Minuten schreibt er einen Eintrag in die Log-Datei mit einer Warnung
+wegen voller Festplatte.
+@end itemize
+
+@noindent
+Um das Problem abzumildern, können Sie folgende Aktionen unternehmen:
+
+@itemize @bullet
+@item
+Um einfach weiterzumachen, müssen Sie lediglich genug Festplattenplatz
+freigeben, damit alle Datensätze eingefügt werden können.
+@item
+Um den Thread abzubrechen, müssen Sie @code{mysqladmin kill} an den Thread
+senden. Der Thread wird beim nächsten Mal, wenn er die Festplatte prüft (in
+1 Minute) abgebrochen.
+@item
+Beachten Sie, dass eventuell ein anderer Thread auf die Tabelle wartet, die
+den Zustand ``Platte voll'' verursachte. Wenn Sie mehrere ``gesperrte''
+Threads haben, kann es sein, dass Sie einen Thread killen, der wegen
+``Platte voll'' wartet, dass dafür aber ein anderer Thread weitermacht.
+@end itemize
+
+Ausnahmen zum obigen Verhalten treten bei der Benutzung von @code{REPAIR}
+oder @code{OPTIMIZE} auf, oder wenn die Indexe nach einem @code{LOAD DATA
+INFILE}- oder einem @code{ALTER TABLE}-Statement im Stapel erzeugt werden.
+
+Alle obigen Befehle benutzen eventuell große temporäre Dateien, die - sich
+selbst überlassen - für den Rest des Systems große Probleme verursachen
+können. Wenn MySQL ein ``Platte voll'' erhält, während irgend eine der
+obigen Operationen ausgeführt wird, entfernt er die großen temporären
+Dateien und markiert die Tabelle als beschädigt (ausser bei @code{ALTER
+TABLE}, wobei die alte Tabelle unverändert gelassen wird).
+
+
+@node Temporary files, Problems with mysql.sock, Full disk, Administration Issues
+@c German node Temporäre Dateien
+@appendixsubsec Wohin MySQL temporäre Dateien speichert
+
+MySQL benutzt den Wert der @code{TMPDIR}-Umgebungsvariablen als Pfadnamen
+des Verzeichnisses, in dem temporäre Dateien gespeichert werden. Wenn Sie
+@code{TMPDIR} nicht gesetzt haben, benutzt MySQL die System-Vorgabe, die
+normalerweise @file{/tmp} oder @file{/usr/tmp} ist. Wenn das Dateisystem,
+das Ihr Verzeichnis für temporäre Dateien enthält, zu klein ist, sollten
+Sie @code{safe_mysqld} editieren, um @code{TMPDIR} so zu setzen, dass sie
+auf ein Verzeichnis in einem Dateisystem zeigt, wo Sie genug Platz haben!
+Sie können das temporäre Verzeichnis auch mit der @code{--tmpdir}-Option
+für @code{mysqld} setzen.
+
+MySQL erzeugt alle temporären Dateien als versteckte Dateien. Das stellt
+sicher, dass die temporären Dateien entfernt werden, wenn @code{mysqld}
+beendet wird. Der Nachteil versteckter Dateien ist, dass Sie eine große
+temporäre Datei nicht sehen, die das Dateisystem auffüllt, in dem sich das
+Verzeichnis für temporäre Dateien befindet.
+
+Zum Sortieren (@code{ORDER BY} oder @code{GROUP BY}) benutzt MySQL
+normalerweise ein oder zwei temporäre Dateien. Der maximal benötigte
+Speicherplatz ist:
+
+@example
+(laenge_dessen_was_sortiert_wird + groesse_von(datenbank_zeiger)) *
+anzahl_uebereinstimmender_zeilen * 2
+@end example
+
+@code{groesse_von(datenbank_zeiger)} ist üblicherweise 4, kann in Zukunft
+aber für wirklich große Tabellen anwachsen.
+
+Bei einigen @code{SELECT}-Anfragen erzeugt MySQL zusätzliche temporäre
+SQL-Tabellen. Diese sind nicht versteckt und haben Namen der Form
+@file{SQL_*}.
+
+@code{ALTER TABLE} erzeugt eine temporäre Tabelle im selben Verzeichnis, in
+dem sich die Original-Tabelle befindet.
+
+
+@node Problems with mysql.sock, Timezone problems, Temporary files, Administration Issues
+@c German node Probleme mit mysql.sock
+@appendixsubsec Wie Sie die MySQL-Socket-Datei @file{/tmp/mysql.sock} schützen oder ändern
+
+@cindex @code{mysql.sock}, schützen
+@cindex löschen, @code{mysql.sock}
+
+Wenn Sie Probleme damit haben, dass jeder beliebige den
+MySQL-Kommunikations-Socket @file{/tmp/mysql.sock} löschen kann, können Sie
+unter den meisten Versionen von Unix Ihr @file{/tmp}-Dateisystem schützen,
+indem Sie darauf das @code{sticky} Bit setzen. Loggen Sie sich als
+@code{root} ein und tun Sie folgendes:
+
+@example
+shell> chmod +t /tmp
+@end example
+
+Das schützt Ihr @file{/tmp}-Dateisystem, so dass Dateien nur von ihren
+Besitzern oder dem Superuser (@code{root}) gelöscht werden können.
+
+Sie können überprüfen, ob das @code{sticky} Bit gesetzt ist, indem Sie
+@code{ls -ld /tmp} ausführen. Wenn das letzte Berechtigungsbit @code{t}
+ist, ist das Bit gesetzt.
+
+@cindex Speicherort des Sockets ändern
+
+Sie können den Speicherort ändern, den MySQL benutzt, um die Socket-Datei
+Socket-Datei abzulegen, indem Sie eine der folgenden Prozeduren ausführen:
+
+@itemize @bullet
+@item
+Geben Sie den Pfad in einer globalen oder lokalen Optionsdatei an.
+Beispielsweise können Sie in @code{/etc/my.cnf} eintragen:
+
+@example
+[client]
+socket=pfad-fuer-socket-datei
+
+[mysqld]
+socket=pfad-fuer-socket-datei
+@end example
+@xref{Option files}.
+@item
+Geben Sie den Pfad auf der Kommandozeile für @code{safe_mysqld} und die
+meisten Clients mit der @code{--socket=pfad-fuer-socket-datei}-Option an.
+@item
+Geben Sie den Pfad zum Socket in der
+@code{MYSQL_UNIX_PORT}-Umgebungsvariablen an.
+variable.
+@item
+Definieren Sie den Pfad mit der @code{configure}-Option
+@code{--with-unix-socket-path=pfad-fuer-socket-datei}.
+@xref{configure options}.
+@end itemize
+
+Mit folgendem Befehl können Sie testen, ob der Socket funktioniert:
+
+@example
+shell> mysqladmin --socket=/pfad/zu/socket version
+@end example
+
+@node Timezone problems, , Problems with mysql.sock, Administration Issues
+@c German node Zeitzonen-Probleme
+@appendixsubsec Zeitzonen-Probleme
+
+@cindex Zeitzonen-Probleme
+@cindex Probleme, Zeitzone
+
+@tindex TZ-Umgebungsvariable
+@tindex Umgebungsvariable, TZ
+
+Wenn es Probleme damit gibt, dass @code{SELECT NOW()} Werte in GMT
+(Greenwich Mean Time) zurückgibt und nicht in Ihrer lokalen Zeit, müssen
+Sie die @code{TZ}-Umgebungsvariable auf Ihre aktuelle Zeitzone setzen. Das
+sollte für die Umgebung gemacht werden, in der der Server läuft, zum
+Beispiel in @code{safe_mysqld} oder @code{mysql.server}.
+@xref{Environment variables}.
+
+
+@node Query Issues, Table Definition Issues, Administration Issues, Problems
+@c German node Anfragenprobleme
+@appendixsec Anfragenbezogene Themen
+
+
+
+@menu
+* Case sensitivity::
+* Using DATE::
+* Problems with NULL::
+* Problems with alias::
+* Deleting from related tables::
+* No matching rows::
+@end menu
+
+@node Case sensitivity, Using DATE, Query Issues, Query Issues
+@c German node Groß-/Kleinschreibung
+@appendixsubsec Groß-/Kleinschreibung beim Suchen
+
+@cindex Groß-/Kleinschreibung, beim Suchen
+@cindex Suchen und Groß-/Kleinschreibung
+@cindex chinesisch
+@cindex Big5, chinesische Zeichensatz-Kodierung
+
+Vorgabemäßig sind MySQL-Suchen unabhängig von der verwendeten
+Groß-/Kleinschreibung (obwohl es einige Zeichensätze gibt, die nie
+unabhängig von der verwendeten Groß-/Kleinschreibung sind, wie
+@code{tschechisch}). Wenn Sie daher mit @code{spalten_name LIKE 'a%'}
+suchen, erhalten Sie alle Spaltenwerte, die mit @code{A} oder @code{a}
+anfangen. Wenn Sie die Suche abhängig von der verwendeten
+Groß-/Kleinschreibung machen wollen, verwenden Sie etwas wie
+@code{INSTR(spalten_name, "A")=1}, um ein Präfix zu überprüfen, oder
+benutzen Sie @code{STRCMP(spalten_name, "A") = 0}, wenn der Spaltenwert
+exakt @code{"A"} sein muss.
+
+Einfache Vergleichsoperationen (@code{>=, >, = , < , <=}, Sortieren und
+Gruppieren) basieren auf dem ``Sortierwert'' jedes Zeichens. Buchstaben mit
+demselben Sortierwert (wie E, e und é) werden als dasselbe Zeichen
+behandelt!
+
+In älteren MySQL-Versionen wurden @code{LIKE}-Vergleiche mit dem
+Großschreibungswert jedes Zeichens durchgeführt (E == e, aber E <> é). In
+neueren MySQL-Versionen funktioniert @code{LIKE} genau wie die anderen
+Vergleichsoperatoren.
+
+Wenn Sie wollen, dass eine Spalte immer abhängig von der verwendeten
+Groß-/Kleinschreibung behandelt wird, deklarieren Sie sie als
+@code{BINARY}. @xref{CREATE TABLE, , @code{CREATE TABLE}}.
+
+Wenn Sie chinesische Daten in der so genannten Big5-Kodierung verwenden,
+sollten Sie alle Zeichenspalten @code{BINARY} machen. Das funktioniert,
+weil die Sortierreihenfolge von Big5-Zeichen auf der Reihenfolge von
+ASCII-Codes basiert.
+
+
+@node Using DATE, Problems with NULL, Case sensitivity, Query Issues
+@c German node Benutzung von DATE
+@appendixsubsec Probleme bei der Benutzung von @code{DATE}-Spalten
+
+@findex DATE
+
+@cindex DATE-Spalten, Probleme
+@cindex Probleme, @code{DATE}-Spalten
+
+Das Format eines @code{DATE}-Werts ist @code{'YYYY-MM-DD'}. Gemäß ANSI-SQL
+ist kein anderes Format zulässig. Sie sollten dieses Format in
+@code{UPDATE}-Ausdrücken und in der WHERE-Klausel von
+@code{SELECT}-Statements benutzen. Beispiel:
+
+@example
+mysql> SELECT * FROM tabelle WHERE date >= '1997-05-05';
+@end example
+
+Aus Gründen der Annehmlichkeit konvertiert MySQL automatisch ein Datum in
+eine Zahl, wenn das Datum in einem numerischen Zusammenhang benutzt wird
+(und umgekehrt). MySQL unterstützt ausserdem ein ``entspanntes''
+Zeichenkettenformat beim Aktualisieren und in einer @code{WHERE}-Klausel,
+die ein Datum mit einer @code{TIMESTAMP}-, @code{DATE}- oder einer
+@code{DATETIME}-Spalte vergleicht. (Entspannt heißt hierbei, dass jedes
+beliebige Satzzeichen als Trennzeichen zwischen Bestandteilen benutzt
+werden darf. Beispielsweise sind @code{'1998-08-15'} und
+@code{'1998#08#15'} äquivalent.) MySQL kann auch eine Zeichenkette
+umwandeln, die keine Trennzeichen enthält (wie @code{'19980815'}),
+vorausgesetzt, dass diese als Datum einen Sinn ergibt.
+
+Das spezielle Datum @code{'0000-00-00'} kann als @code{'0000-00-00'}
+gespeichert und abgerufen werden. Wenn man ein @code{'0000-00-00'}-Datum
+über @strong{MyODBC} benutzt, wird es automatisch in @code{NULL}
+umgewandelt (@strong{MyODBC}-Version 2.50.12 und höher), weil ODBC diese
+Art von Datum nicht handhaben kann.
+
+Weil MySQL die oben genannten Umwandlungen durchführt, funktionieren
+folgende Statements:
+
+@example
+mysql> INSERT INTO tabelle (idate) VALUES (19970505);
+mysql> INSERT INTO tabelle (idate) VALUES ('19970505');
+mysql> INSERT INTO tabelle (idate) VALUES ('97-05-05');
+mysql> INSERT INTO tabelle (idate) VALUES ('1997.05.05');
+mysql> INSERT INTO tabelle (idate) VALUES ('1997 05 05');
+mysql> INSERT INTO tabelle (idate) VALUES ('0000-00-00');
+
+mysql> SELECT idate FROM tabelle WHERE idate >= '1997-05-05';
+mysql> SELECT idate FROM tabelle WHERE idate >= 19970505;
+mysql> SELECT mod(idate,100) FROM tabelle WHERE idate >= 19970505;
+mysql> SELECT idate FROM tabelle WHERE idate >= '19970505';
+@end example
+
+@noindent
+Folgendes jedoch funktioniert nicht:
+
+@example
+mysql> SELECT idate FROM tabelle WHERE STRCMP(idate,'19970505')=0;
+@end example
+
+@code{STRCMP()} ist eine Zeichenkettenfunktion, daher wird @code{idate} in
+eine Zeichenkette umgewandelt und ein Zeichenkettenvergleich durchgeführt.
+MySQL wandelt @code{'19970505'} nicht in ein Datum um und führt einen
+Datumsvergleich durch.
+
+Beachten Sie, dass MySQL nicht prüft, ob ein Datum korrekt ist oder nicht.
+Wenn Sie ein falsches Datum wie @code{'1998-2-31'} speichern, wird das
+falsche Datum gespeichert. Wenn das Datum in keinen vernünftigen Wert
+umgewandelt werden kann, wird @code{0} im @code{DATE}-Feld gespeichert. Das
+ist hauptsächlich eine Sache der Geschwindigkeit, und wir sind der Meinung,
+dass es Sache der Applikation und nicht des Servers ist, Datumsangaben zu
+überprüfen.
+
+
+@node Problems with NULL, Problems with alias, Using DATE, Query Issues
+@c German node Probleme mit NULL
+@appendixsubsec Probleme mit @code{NULL}-Werten
+
+@cindex @code{NULL}-Werte im Vergleich mit leeren Werten
+
+@tindex NULL
+
+Das Konzept des @code{NULL}-Wert ist eine häufige Quelle der Verwirrung für
+SQL-Anfänger. Diese denken häufig, @code{NULL} sei dasselbe wie eine leere
+Zeichenkette @code{''}. Das ist nicht der Fall! So sind zum Beispiel
+folgende Statements grundverschieden:
+
+@example
+mysql> INSERT INTO meine_tabelle (Telefon) VALUES (NULL);
+mysql> INSERT INTO meine_tabelle (Telefon) VALUES ("");
+@end example
+
+Beide Statements fügen einen Wert in die @code{Telefon}-Spalte ein, aber
+das erste fügt einen @code{NULL}-Wert und das zweite eine leere
+Zeichenkette ein. Die Bedeutung des ersten ist etwa ``Telefonnummer
+unbekannt'' und des zweiten ``Keine Telefonnummer''.
+
+In SQL ist der @code{NULL}-Wert im Vergleich mit jedem anderen Wert immer
+UNWAHR (false), selbst im Vergleich mit @code{NULL}. Ein Ausdruck, der
+@code{NULL} enthält, erzeugt immer einen @code{NULL}-Wert, ausser wenn es
+in der Dokumentation der Operatoren und Funktionen, die im Ausdruck
+beteiligt sind, anders angegeben ist. Alle Spalten im folgenden Beispiel
+geben @code{NULL} zurück:
+
+@example
+mysql> SELECT NULL,1+NULL,CONCAT('unsichtbar',NULL);
+@end example
+
+Wenn Sie nach Spaltenwerten suchen, die @code{NULL} sind, können Sie nicht
+@code{=NULL} benutzen. Folgendes Statement gibt keine Zeilen zurück, weil
+@code{ausdruck = NULL} für jeden beliebigen Ausdruck UNWAHR (false) ist:
+
+@example
+mysql> SELECT * FROM meine_tabelle WHERE Telefon = NULL;
+@end example
+
+Um nach @code{NULL}-Werten zu suchen, müssen Sie @code{IS NULL} benutzen.
+Folgende Beispiele zeigen, wie Sie die @code{NULL}-Telefonnummer und die
+leere Telefonnummer finden:
+
+@example
+mysql> SELECT * FROM meine_tabelle WHERE Telefon IS NULL;
+mysql> SELECT * FROM meine_tabelle WHERE Telefon = "";
+@end example
+
+In MySQL können Sie - wie bei vielen anderen SQL-Servern - keine Spalten
+indexieren, die @code{NULL}-Werte enthalten dürfen. Sie müssen solche
+Spalten aus @code{NOT NULL} deklarieren. Sie dürfen in eine indexierte
+Spalte keine @code{NULL}-Werte einfügen.
+
+@findex LOAD DATA INFILE
+Wenn Sie Daten mit @code{LOAD DATA INFILE} einlesen, werden leere Spalten
+mit @code{''} aktualisiert. Wenn Sie einen @code{NULL}-Wert in einer Spalte
+haben wollen, müssen Sie in der Textdatei @code{\N} benutzen. Unter manchen
+Umständen kann auch das Literalwort @code{'NULL'} benutzt werden.
+@xref{LOAD DATA, , @code{LOAD DATA}}.
+
+Wenn Sie @code{ORDER BY} benutzen, werden @code{NULL}-Werte zuerst
+angezeigt. Wenn Sie mit @code{DESC} in absteigender Reihenfolge sortieren,
+werden @code{NULL}-Werte zuletzt angezeigt. Wenn Sie @code{GROUP BY}
+benutzen, werden alle @code{NULL}-Werte als gleich betrachtet.
+
+Um die Handhabung von @code{NULL} zu erleichtern, können Sie die @code{IS
+NULL}- und @code{IS NOT NULL}-Operatoren und die @code{IFNULL()}-Funktion
+benutzen.
+
+@cindex @code{TIMESTAMP} und @code{NULL}-Werte
+@cindex @code{AUTO_INCREMENT} und @code{NULL}-Werte
+@cindex @code{NULL}-Werte und @code{TIMESTAMP}-Spalten
+@cindex @code{NULL}-Werte und @code{AUTO_INCREMENT}-Spalten
+Bei manchen Spaltentypen werden @code{NULL}-Werte besonders behandelt. Wenn
+Sie @code{NULL} in die erste @code{TIMESTAMP}-Spalte einer Tabelle
+einfügen, werden das aktuelle Datum und die aktuelle Zeit eingefügt. Wenn
+Sie @code{NULL} in eine @code{AUTO_INCREMENT}-Spalte einfügen, wird die
+nächste Zahl in der Zahlenfolge eingefügt.
+
+
+@node Problems with alias, Deleting from related tables, Problems with NULL, Query Issues
+@c German node Probleme mit alias
+@appendixsubsec Probleme mit @code{alias}
+
+@tindex alias
+
+Sie können ein Alias verwenden, um auf eine Spalte im @code{GROUP BY}-,
+@code{ORDER BY}- oder @code{HAVING}-Teil zu verweisen. Aliase können auch
+verwendet werden, um Spalten bessere Namen zu geben:
+
+@example
+SELECT SQRT(a*b) as wurzel FROM tabelle GROUP BY wurzel HAVING wurzel > 0;
+SELECT id,COUNT(*) AS zaehl FROM tabelle GROUP BY id HAVING zaehl > 0;
+SELECT id AS "kunden-kennung" FROM tabelle;
+@end example
+
+Beachten Sie, dass ANSI-SQL verbietet, in einer @code{WHERE}-Klausel auf
+ein Alias zu verweisen. Das liegt daran, dass der Spaltenwert
+möglicherweise noch nicht feststeht, wenn der @code{WHERE}-Code ausgeführt
+wird. Folgende Anfrage zum Beispiel ist @strong{unzulässig}:
+
+@example
+SELECT id,COUNT(*) AS zaehl FROM tabelle WHERE zaehl > 0 GROUP BY id;
+@end example
+
+Das @code{WHERE}-Statement wird ausgeführt, um festzulegen, welche Zeilen
+im @code{GROUP BY}-Teil enthalten sein sollen, während @code{HAVING}
+benutzt wird, um zu entscheiden, welche Zeilen der Ergebnismenge benutzt
+werden sollten.
+
+
+@node Deleting from related tables, No matching rows, Problems with alias, Query Issues
+@c German node Löschen aus verwandten Tabellen
+@appendixsubsec Zeilen aus verwandten Tabellen löschen
+
+@cindex löschen, Zeilen
+@cindex Zeilen, löschen
+@cindex Tabellen, Zeilen löschen
+
+Weil MySQL keine Sub-Selects oder die Benutzung von mehr als einer Tabelle
+im @code{DELETE}-Statement unterstützt, müssen Sie folgenden Ansatz wählen,
+um Zeilen aus zwei verwandten Tabellen zu löschen:
+
+@enumerate
+@item
+Wählen (@code{SELECT}) Sie die Zeilen auf der Grundlage einer
+@code{WHERE}-Bedingung in der Haupt-Tabelle aus.
+@item
+Löschen (@code{DELETE}) Sie die Zeilen in der Haupt-Tabelle auf der
+Grundlage derselben Bedingung.
+@item
+Löschen Sie die Zeilen aus der verwandten Tabelle, bei denen die verwandte
+Spalte in den ausgewählten Zeilen vorkommt (@code{DELETE FROM
+verwandte_tabelle WHERE verwandte_spalte IN (ausgewaehlte_zeilen)}.
+@end enumerate
+
+Wenn die Gesamtzahl von Zeichen in der Anfrage mit @code{verwandte_spalte}
+mehr als 1.048.576 beträgt (der Vorgabewert von @code{max_allowed_packet},
+sollten Sie sie in kleinere Teile aufspalten und mehrfache
+@code{DELETE}-Statements ausführen. Wahrscheinlich geht das Löschen
+(@code{DELETE}) am Schnellsten, wenn Sie nur 100 bis 1000
+@code{verwandte_spalte}-Kennungen pro Anfrage löschen, wenn
+@code{verwandte_spalte} ein Index ist. Wenn @code{verwandte_spalte} kein
+Index ist, ist die Geschwindigkeit unabhängig von der Anzahl von Argumenten
+in der @code{IN}-Klausel.
+
+
+@node No matching rows, , Deleting from related tables, Query Issues
+@c German node Keine übereinstimmenden Zeilen
+@appendixsubsec Probleme bei keinen übereinstimmenden Zeilen lösen
+
+@cindex keine übereinstimmenden Zeilen
+@cindex Zeilen, Übereinstimmungsprobleme
+
+Wenn Sie eine komplizierte Anfrage haben, die viele Tabellen hat und keine
+Zeilen zurückgibt, sollten Sie folgende Prozedur benutzen, um
+herauszufinden, was bei Ihrer Anfrage falsch ist:
+
+@enumerate
+@item
+Testen Sie die Anfrage mit @code{EXPLAIN} und prüfen Sie, ob Sie etwas
+finden können, das offensichtlich falsch ist. @xref{EXPLAIN, ,
+@code{EXPLAIN}}.
+
+@item
+Wählen Sie in der @code{WHERE}-Klausel nur die Felder aus, die benutzt
+werden.
+
+@item
+Entfernen Sie nacheinander Tabelle für Tabelle aus der Anfrage, bis sie
+Zeilen zurückgibt. Wenn die Tabellen Groß sind, ist es eine gute Idee,
+@code{LIMIT 10} bei der Anfrage zu benutzen.
+
+@item
+Machen Sie ein @code{SELECT} für die Spalte, die mit einer Zeile hätte
+übereinstimmen sollen, gegen die Tabelle, die als letzte aus der Anfrage
+entfernt wurde.
+
+@item
+Wenn Sie @code{FLOAT}- oder @code{DOUBLE}-Spalten mit Zahlen vergleichen,
+die Dezimalstellen haben, können Sie nicht @code{=} benutzen! Das Problem
+tritt in den meisten Computersprachen auf, weil Fließkommawerte keine
+exakten Werte sind:
+
+@example
+mysql> SELECT * FROM tabelle WHERE float_spalte=3.5;
+mysql> SELECT * FROM tabelle WHERE float_spalte between 3.45 und 3.55;
+@end example
+
+In den meisten Fällen kann dies durch Umwandlung von @code{FLOAT} in
+@code{DOUBLE} behoben werden!
+
+@item
+Wenn Sie immer noch nicht herausfinden können, was schief geht, erzeugen
+Sie einen minimalen Test, der mit @code{mysql test < anfrage.sql} laufen
+gelassen werden kann, um Ihre Probleme aufzuzeigen. Sie können eine
+Testdatei mit @code{mysqldump --quick datenbanktabellen > anfrage.sql}
+erzeugen. Öffnen Sie die Datei in einem Editor, entfernen Sie ein paar
+Einfügezeilen (wenn es davon zu viele gibt) und fügen Sie Ihr
+SELECT--Statement am Ende der Datei an.
+
+Testen Sie, ob es hiermit immer noch das Problem gibt:
+
+@example
+shell> mysqladmin create test2
+shell> mysql test2 < anfrage.sql
+@end example
+
+Schicken Sie die Testdatei mittels @code{mysqlbug} an
+@email{mysql@@lists.mysql.com}.
+@end enumerate
+
+
+@node Table Definition Issues, , Query Issues, Problems
+@c German node Tabellendefinitionsprobleme
+@appendixsec Tabellendefinitionsbezogene Themen
+
+
+
+@menu
+* ALTER TABLE problems::
+* Change column order::
+* Temporary table problems::
+@end menu
+
+@node ALTER TABLE problems, Change column order, Table Definition Issues, Table Definition Issues
+@c German node Probleme mit ALTER TABLE
+@appendixsubsec Probleme mit @code{ALTER TABLE}.
+
+@tindex ALTER TABLE
+
+@code{ALTER TABLE} ändert eine Tabelle zum aktuellen Zeichensatz. Wenn Sie
+während @code{ALTER TABLE} einen Fehler wegen doppelter Schlüsseleinträge
+bekommen, liegt das entweder daran, dass die neuen Zeichensätze auf bei
+Schlüsseln auf dieselben Werte gemappt sind, oder dass die Tabelle
+beschädigt ist, wobei Sie @code{REPAIR TABLE} auf die Tabelle laufen lassen
+sollten.
+
+Wenn @code{ALTER TABLE} mit einem Fehler wie folgt stirbt:
+
+@example
+Error on rename of './datenbank/name.frm' to './datenbank/B-a.frm' (Errcode: 17)
+@end example
+
+Kann das Problem darin bestehen, dass MySQL bei einem vorhergehenden
+@code{ALTER TABLE} abgestürzt ist und es eine alte Tabelle namens
+@file{A-etwas} oder @file{B-etwas} gibt, die herum liegt. Gehen Sie in
+diesem Fall ins MySQL-Daten-Verzeichnis und löschen Sie alle Dateien, die
+Namen wie @code{A-} oder @code{B-} haben. (Statt löschen können Sie sie
+auch an eine andere Stelle verschieben.)
+
+@code{ALTER TABLE} funktioniert auf folgenden Weise:
+
+@itemize @bullet
+@item Erzeugt eine neue Tabellen namens @file{A-xxx} mit den angeforderten
+Änderungen.
+@item Alle Zeilen der alten Tabelle werden nach @file{A-xxx} kopiert.
+@item Die alte Tabelle wird in @file{B-xxx} umbenannt.
+@item @file{A-xxx} wird in Ihren alten Tabellennamen umbenannt.
+@item @file{B-xxx} wird gelöscht.
+@end itemize
+
+Wenn etwas bei dieser Umbennungsoperation fehlschlägt, versucht MySQL, die
+Änderungen rückgängig zu machen. Wenn etwas Schwerwiegendes schief geht
+(was natürlich passieren kann), läßt MySQL eventuell die alte Tabelle als
+@file{B-xxx}, aber ein einfaches Umbenennen auf Systemebene sollte Ihre
+Daten zurückbringen.
+
+
+@node Change column order, Temporary table problems, ALTER TABLE problems, Table Definition Issues
+@c German node Änderung der Spalten-Reihenfolge
+@appendixsubsec Wie man die Reihenfolge der Spalten in einer Tabelle ändert
+
+@cindex neu sortieren, Spalten
+@cindex Spalten, ändern
+@cindex ändern, Spalten-Reihenfolge
+@cindex Tabellen, Spalten-Reihenfolge ändern
+
+Im großen und Ganzen geht es bei SQL darum, die Applikation vom
+Daten-Speicherformat zu abstrahieren. Sie sollten immer die Reihenfolge
+angeben, in der Sie Ihre Daten abrufen wollen. Beispiel:
+
+@example
+SELECT spalten_name1, spalten_name2, spalten_name3 FROM tabelle;
+@end example
+
+Das gibt die Spalten in der Reihenfolge @code{spalten_name1},
+@code{spalten_name2}, @code{spalten_name3} zurück, wohingegen:
+
+@example
+SELECT spalten_name1, spalten_name3, spalten_name2 FROM tabelle;
+@end example
+
+die Spalten in der Reihenfolge @code{spalten_name1}, @code{spalten_name3},
+@code{spalten_name2} zurückgibt.
+
+Sie sollten in einer Applikation @strong{NIE} @code{SELECT *} benutzen und
+die Spalten basierend auf ihrer Position abrufen, weil die Reihenfolge, in
+der Spalten zurückgegeben werden, im Zeitablauf @strong{NICHT} garantiert
+werden kann. Eine einfache Änderung in Ihrer Datenbank kann dazu führen,
+dass Ihre Applikation dramatisch scheitert.
+
+Wenn Sie dennoch die Spalten-Reihenfolge ändern wollen, können Sie das wie
+folgt tun:
+
+@enumerate
+@item
+Erzeugen Sie eine neue Tabelle mit den Spalten in der richtigen
+Reihenfolge.
+@item
+Führen Sie @code{INSERT INTO neue_tabelle SELECT
+felder-in-der-reihenfolge-von-neue_tabelle FROM alte_tabelle} aus.
+@item
+Löschen Sie @code{alte_tabelle} oder benennen Sie sie um.
+@item
+Führen Sie @code{ALTER TABLE neue_tabelle RENAME alte_tabelle} aus.
+@end enumerate
+
+
+@node Temporary table problems, , Change column order, Table Definition Issues
+@c German node Probleme mit temporären Tabellen
+@appendixsubsec TEMPORARY TABLE-Probleme
+
+@cindex temporäre Tabellen, Probleme
+
+Im Folgenden eine Auflistung der Beschränkungen bei @code{TEMPORARY TABLES}.
+
+@itemize @bullet
+@item
+Eine temporäre Tabelle kann nur vom Typ @code{HEAP}, @code{ISAM} oder
+@code{MyISAM} sein.
+@item
+Sie können temporäre Tabellen nicht mehr als einmal in derselben Anfrage
+benutzen. Folgendes zum Beispiel funktioniert nicht:
+
+@example
+select * from temporary_table, temporary_table as t2;
+@end example
+
+Das soll in Version 4.0 behoben werden.
+@item
+Sie können kein @code{RENAME} auf eine @code{TEMPORARY}-Tabelle benutzen.
+Beachten Sie, dass @code{ALTER TABLE alter_name RENAME neuer_name} dagegen
+funktioniert!
+Das soll in Version 4.0 behoben werden.
+@end itemize
+
+
+
+@c German FIX this appendix should be removed (as was done from English ver.)
+@node Benutzer, MySQL-Benutzung durch Kunden, Problems, Top
+@c German node <no English equivalent>
+@appendix Einige MySQL-Benutzer
+
+@cindex Benutzer, von MySQL
+@cindex News-Sites
+
+Dieser Anhang listet einige Benutzer von MySQL auf, die uns ihre
+Genehmigung erteilt haben, sie in dieser Dokumentation aufzuführen. Diese
+Liste ist bei weitem nicht vollständig, sollte aber eine allgemeine
+Vorstellung davon geben, wer MySQL benutzt und wofür es benutzt werden
+kann.
+
+
+@appendixsec Allgemeine News-Sites
+
+@itemize @bullet
+
+@item @uref{http://www.yahoo.com/, Yahoo!}
+
+@item @uref{http://slashdot.org/, Slashdot: Eine Pro-Linux- / Tech-News- und Kommentar-/Diskussions-Site}
+
+@item @uref{http://www.linux.com/, Alles über Linux}
+
+@item @uref{http://www.linuxtoday.com/, Linuxtoday}
+
+@item @uref{http://www.32bitsonline.com/, 32Bits Online: weil es mehr als eine Art zu computern gibt}
+
+@item @uref{http://www.freshmeat.net/, Freshmeat: Neues über neue Versionen und computerbezogene Themen}
+
+@end itemize
+
+@cindex Suchmaschinen, web
+@cindex Web-Suchmaschinen
+@appendixsec Einige Web-Suchmaschinen
+
+@itemize @bullet
+
+@item @uref{http://www.aaa.com.au, AAA Matilda Web Search}
+
+@item @uref{http://www.whatsnu.com/, What's New}
+
+@item @uref{http://www.aladin.de/, Aladin}
+
+@item @uref{http://www.columbus-finder.de/, Columbus Finder}
+
+@item @uref{http://www.spider.de/, Spider}
+
+@item @uref{http://www.blitzsuche.de/, Blitzsuche}
+
+@item @uref{http://www.indoseek.co.id, Indoseek Indonesien}
+
+@item @uref{http://www.yaboo.dk/, Yaboo - Yet Another BOOkmarker}
+
+
+@item @uref{http://www.ozsearch.com.au, OzSearch Internet Guide}
+
+@item @uref{http://www.splatsearch.com/, Splat! Search}
+
+@item @uref{http://osdls.library.arizona.edu/, The Open Source Digital Library System Project}
+@end itemize
+
+@appendixsec Einige Informations-Suchmaschinen mit Konzentration auf bestimmte Felder
+
+@itemize @bullet
+
+@item @uref{http://www.spylog.ru/, SpyLOG ; Eine sehr populäre Web-Counter-Site}
+
+@item @uref{http://www.tucows.com/, TuCows Network; Archiv für Freie Software}
+
+@item @uref{http://www.jobvertise.com,Jobvertise: Angebot und Nachfrage nach Jobs}
+
+@item @uref{http://www.musicdatabase.com, die Musik-Datenbank}
+
+@item @uref{http://www.soccersearch.com, Fussball-Suchseite}
+
+@item @uref{http://www.headrush.net/takedown, TAKEDOWN - Ringen}
+
+@item @uref{http://www.lyrics.net, das internationale Liedtext-Netzwerk}
+
+@c German FIX removed comma (",") to make description work inside uref
+@item @uref{http://TheMatrix.com/~matrix/bund_search.phtml, Musiker die andere Musiker suchen (kostenloser Service)}
+
+@item @uref{http://www.addall.com/AddBooks/Stores.html,AddALL Büchersuche und Preisvergleich}
+
+@item @uref{http://www.herbaria.harvard.edu/Data/Gray/gray.html,Harvard's Gray Herbarium Index von Pflanzennamen}
+
+@item @uref{http://www.game-Entwickler.com/, die Spiele-Entwicklungs-Suchmaschine}
+
+@item @uref{www.theinnkeeper.com, der Innkeeper Reiseführer}
+
+@item @uref{http://www.macgamedatabase.com/, die Mac-Game-Datenbank benutzt PHP und MySQL}
+@c Von: Marc Antony Vose <suzerain@suzerain.com>
+
+@item @uref{http://www.csse.monash.edu.au/publications/, Research
+Veröffentlichungen an der Monash University in Australien}
+
+@item @uref{http://www.ipielle.emr.it/bts/index.html,
+Berufsbezogene Gesundheits- und Sicherheits-Website-Datenbank (ein Projekt für die ECC)}
+@c c.presutti@ipielle.emr.it
+
+@c German FIX removed comma (",") to make description work inside uref
+@item @uref{http://data.mch.mcgill.ca/, Bioinformatik-Datenbanken am
+Montreal-Kinderkrankenhaus die MySQL benutzen}
+@c saeed@www.debelle.mcgill.ca
+@end itemize
+
+@cindex Online-Magazine
+@cindex magazines, online
+@appendixsec Online-Magazine
+
+@itemize @bullet
+@item @uref{http://www.spoiler.com, Spoiler Webzine}.
+Ein Online-Magazin für Musik, Literatur, Kunst und Design.
+@item @uref{http://www.linux-magazin.de/newsflash/, Tägliche Nachrichten über Linux in deutscher Sprache}
+@item @uref{http://www.betazine.com,Betazine - Das ultimate Online-Betatester-Magazin}
+@item @uref{http://www.currents.net/ccinfo/aboutcc.html,Computer Currents Magazine}
+@end itemize
+
+@cindex Websites
+@appendixsec Websites die MySQL als Backend benutzen
+
+@itemize @bullet
+
+@item @uref{http://liftoff.msfc.nasa.gov, NASA}
+@item @uref{http://kids.msfc.nasa.gov, NASA KIDS}
+@item @uref{http://science.nasa.gov, Science@@NASA}
+
+@item @uref{http://www.handy.de/, handy.de}
+
+@item @uref{http://lindev.jmc.tju.edu/qwor, Qt Widget and Object Repository}
+
+@item @uref{http://www.samba-choro.com.br, Brasilianische Samba-Site (auf portugiesisch)}
+
+@item @uref{http://pgss.iss.uw.edu.pl/en_index.ISS, polnische allgemeine Sozial-Umschau}
+
+@item @uref{http://www.expo2000.com, Expo2000} Weltweiter Verkauf von
+Ticket für diese Veranstaltung wurde mit MySQL und tcl/tk implementiert.
+Mehr als 5.000 Reiseagenturen in der ganzen Welt hatten Zugriff darauf.
+
+@item @uref{http://www.freevote.com/, FreeVote.com ist ein kostenloser
+Abstimmungsservice mit Millionen Benutzern.}
+
+@item @uref{http://f1.tauzero.se, Forza Motorsport}
+
+@item @uref{http://www.dreamhost.com/, DreamHost Web-Hosting}
+
+@end itemize
+
+@cindex services
+@appendixsec Einige Domain- / Internet- / Web- und verwandte Services
+
+@itemize @bullet
+
+@c German FIX removed comma (",") to make description work inside uref
+@item @uref{http://www.wix.com/mysql-hosting, Registrar von Webprovidern
+die MySQL unterstützen}
+
+@item @uref{http://www.yi.org/, dynamische DNS-Services}
+
+@item @uref{http://www.dynodns.net/, dynamischer Domain-Name-Service}
+
+@item @uref{http://www.ods.org/, Open DNS Project; kostenloser dynamischer DNS-Service}
+
+@c @item @uref{http://dynodns.net, kostenlose dynamische DNS-Implementation}
+@c EMAIL: A Moore <amoore@mooreSysteme.com>
+
+@item @uref{http://www.hn.org/, Hammernode; öffentliche DNS-Server}
+
+@item @uref{http://www.fdns.net/, kostenlose 3rd-Level-Domains}
+
+@item @uref{http://worldcommunity.com/, Online-Datenbank}
+
+@item @uref{http://www.bigbiz.com, BigBiz Internet-Services}
+
+@item @uref{http://virt.circle.net, The Virt Gazette}
+
+@item @uref{http://www.california.com, Global InfoNet Inc}
+
+@item @uref{http://www.webhosters.com, WebHosters - ein Führer für WWW-Provider}
+
+@item @uref{http://online.dn.ru, Internet-Informations-Server}
+
+@item @uref{http://www.stopbit.com, eine Technologie-News-Site}
+
+@item @uref{http://www.worldnetla.net, WorldNet Communications - ein Internet Service Provider}
+
+@item @uref{http://www.netizen.com.au/, Netizen: Web-Beratung in Australien}
+
+@item @uref{http://www.trainingpages.co.uk, Suchseite für Trainingskurse in Großbritannien}
+
+@item @uref{http://chat.nitco.com, Gannon Chat (GPL). Geschrieben in Perl und JavaScript}
+
+@item @uref{http://www.addurls.com/, ein allgemeines Links-Verzeichnis}
+
+@item @uref{http://www.bookmarktracker.com, ein Web-basierender Bookmark-Verwaltungs-Service}
+
+@item @uref{http://www.cdrom.com,Walnut Creek CDROM}
+
+@item @uref{http://www.wwwThread.org/, WWWThread; interaktive Diskussionsforen}
+
+@item @uref{http://pvmon.portici.enea.it/Meteo, auf italienisch; Datenspeicherung von meteo station}
+
+@item @uref{http://www.buysell.net/, Online-"Person To Person"-Auktion}
+
+@item @uref{http://tips.pair.com, Tipps zur Web-Entwicklung}
+
+@c German FIX removed comma (",") to make description work inside uref
+@item @uref{http://www.mailfriends.com, Mailfriends.com ist ein kostenloser Service für jeden der über das Internet einen Freund finden will.}
+
+@item @uref{http://www.uninova.com/cgi-bin/wctelnets?list, Website Telnet BBS List}
+
+@item @uref{http://www.uninova.com/cnc.html, UniNova Digitale Postkarten}
+
+@c @item @uref{http://cabinboy.powersurfr.com, eine Internet-RFC-Suchmaschine}
+
+@item @uref{http://www.dslreports.com, DSL-Provider-Suche mit Testberichten}.
+Mit MySQL und Modperl hergestellt. Alle Seiten werden dynamisch aus einer
+MySQL-Datenbank erzeugt.
+@end itemize
+
+@cindex PHP, Websites
+@appendixsec Websites, die @code{PHP} und MySQL benutzen
+
+@itemize @bullet
+@c @item @uref{http://www.wh200th.com, Site zum 200. Jahrestag des Weißen Hauses}
+
+@item @uref{http://support.jgaa.com/, Jgaa's Internet - Offizielle Support-Site}
+
+@item @uref{http://io.incluso.com, Ionline - online publication:} MySQL, PHP, Java, Web-Programmierung, DB-Entwicklung
+
+@item @uref{http://www.baboo.com, BaBoo(Browse und bookmark). Kostenloser Web-basierender Bookmarkmanager und Kalender}
+
+@item @uref{http://www.courses.pjc.cc.fl.us/Schedule/index.php, Kursplanungssystem am Pensacola Junior College}
+
+@item @uref{http://www.fccj.org, Florida Community College in Jacksonville}
+
+@item @uref{http://www.32bit.com/, 32bit.com; Ein umfangreiches Shareware- / Freeware-Archiv}
+
+@item @uref{http://www.jokes2000.com/, Jokes 2000}
+@c Added 990604; EMAIL: ah@dybdahl.dk
+
+
+@item @uref{http://www.burken.nu/ , Burken.NU} Burken ist ein Webhotel, das Skripte unter anderem für entfernte Benutzer zur Verfügung stellt, beispielsweise Counter, Gästebücher usw.
+@c Added 990608; EMAIL: spacedmp@SpaceDump.Burken.NU (Anders Olausson)
+
+@item @uref{http://tips.pair.com, tips.pair.com} Enthält Tipps zu HTML, JavaScript, 2D-/3D-Grafiken und PHP3/MySQL. Alle Seiten werden aus einer Datenbank erzeugt.
+@c Added 990614; EMAIL: downey@image.dk (Rune Madsen)
+
+@item @uref{http://www.Softwarezrus.com/, Softwarezrus.com} E-Commerce-Site, die Computer verkauft.
+@end itemize
+
+@cindex Berater, Auflistung
+@appendixsec Einige MySQL-Berater
+
+@itemize @bullet
+
+@item @uref{http://iConnect.de, iConnect GmbH Berlin}
+
+@item @uref{http://www.ayni.com, Ayni AG}
+
+@item @uref{http://worldcommunity.com/, Online-Datenbank}
+
+@item @uref{http://www2.dataguard.no/,DataGuard (mit MySQL und PHP)}
+
+@item @uref{http://wwits.net/programs/mysql.phtml, WWITS (mit MySQL und PHP)}
+
+@item @uref{http://www.worldcommunity.com/, WCN - The World Community Network}
+
+@item @uref{http://www.chipcastle.com, Chip Castle Dot Com Inc}
+@c Added 990603 EMAIL: chip@chipcastle.com (Chip Castle)
+
+@item @uref{http://www.cyber.com.au/, Cybersource Pty. Ltd}
+
+@item @uref{http://www.spring.de, Spring infotainment GmbH & Co. KG}
+@c added 990905 "Oliver Pischke" <opischke@spring.de>
+
+@item @uref{http://www.wamdesign.com/, Entwickelt Websites mit MySQL}
+@c Added 990905; max@wamdesign.com
+
+@item @uref{http://www.berkeleyconsultants.com, Berkeley-Berater-Gruppe}
+
+@item @uref{http://www.jammconsulting.com/, JAMM Consulting Inc.}
+
+@end itemize
+
+@appendixsec Programmierung
+
+@cindex Websites, verschiedene
+@appendixsec Nicht kategorisierte Seiten
+
+@itemize @bullet
+
+@item @uref{http://www.feature-showcase.com/htmls/demo_mysql.sql, AZC.COM's Feature Showcase}
+
+@item @uref{http://www.teach.org.uk/subjects/trainingcourse/g.html, Kurssuche}
+
+@item @uref{http://www.northerbys.com, Northerbys Online-Auktionen}
+
+@item @uref{http://www.schiphol.nl/flights/home.htm, Amsterdamer Flughafen Schiphol}
+
+@item @uref{http://TheMatrix.com/seventhsin/query.phtml, CD-Datenbank}
+
+@item @uref{http://TheMatrix.com/~flmm/GEAR.html, Datenbank gebrauchter Audio-Geräte}
+
+@item @uref{http://www.kiss.de/musik-mueller, Notenblätter}
+
+@item @uref{http://www.bagism.com, Bagism - Eine John-Lennon-Fanseite}
+
+@item @uref{http://www.selftaught.com/, US-Folkart-Broker}
+
+@item @uref{http://organizer.net/, Mail lesen auf dem Web}
+
+@item @uref{http://www.mypage.org/, Kostenlose Homepages auf www.somecoolname.mypage.org}
+
+@item @uref{http://www.schulweb.de/, Der Server für Schulen im Web (auf deutsch)}
+
+@item @uref{http://www.ald.net/, Auldhaefen Online-Services}
+
+@item @uref{http://www.cary.net/, CaryNET Information Center}
+
+@item @uref{http://www.Dataden.com/, Dataden Computer Systems}
+
+@item @uref{http://undree.grm.se/ undr@'emuseet (auf schwedisch)}
+
+@item @uref{http://www.him.net/, HOMESITE Internet Marketing}
+
+@item @uref{http://www.jade-v.com/techinfo.html, Jade-V Network Services }
+
+@item @uref{http://ww2010.atmos.uiuc.edu/(Gl)/abt/aknw/tech.rxml, Weather World 2010 Technical Credits} @*
+
+@item @uref{http://gimp.foebud.org/registry/doc/, Über die Gimp-Plugin-Registrierung}
+
+@c German FIX removed comma (",") to make description work inside uref
+@item @uref{http://www.fast-inc.com/produkte/Archiver/database.html, Java-Werkzeug Archiver technical detail (leicht optimistisch was die MySQL-ANSI-92-Kompatibilität betrifft)}
+
+@item @uref{http://www.gamesdomain.com/cheats/usrcheat.phtml, Games Domain Cheats Datenbank}
+
+@item @uref{http://www.kcilink.com/poweredby/, The "Powered By" Page (Kcilink)}
+
+@item @uref{http://www.netcasting.net/index.whtml, Netcasting}
+
+@item @uref{http://homepages.tig.com.au/~mjj/nblTipps, NBL (Australian National Basketball League) tipping}
+
+@item @uref{http://www.cgishop.com/, CGI-Shop}
+
+@item @uref{http://www.whirlycott.com/, Whirlycott: Website-Design}
+
+@item @uref{http://www.mtp.dk, Museum Tusculanum Press}
+
+@item @uref{http://csdgi.historie.ku.dk/biblio, Centro Siciliano di Documentazione}
+
+@item @uref{http://caribou.dyn.ml.org:8000, Quake-Statistik-Datenbank}
+
+@item @uref{http://www.astroforum.ch, Astroforum: Astrologie und verwandte Dinge (auf deutsch)}
+
+@item @uref{http://www.opendebate.com, OpenDebate - Interaktive Umfragen & Offene Diskussionen}
+
+@item @uref{http://vermeer.organik.uni-erlangen.de/dissertationen/, Online-Server für Dissertationen im Bereich Chemie}
+
+@item @uref{http://www.freschinfo.com, FreSch! The Free Scholarship Search Service}
+
+@item @uref{http://www.nada.kth.se/~staffanu/pinball, Stockholmer Flipper-Finder}
+
+@item @uref{http://www.hek.com, HEK - eine Baufirma}
+
+@item @uref{http://www.nbi.nl, Elsevier Business Information}
+
+@item @uref{http://vaccination.medicallink.se/, Medizinische Links (mit ColdFusion und MySQL)}
+
+@item @uref{http://www.joblink-usa.com, Suche nach Jobs & Leuten auf JobLink-USA}
+
+@item @uref{http://www.skydive.net/competfs, Competition Formation Skydiving}
+
+@item @uref{http://www.galaxy-net.net/Galaxy-NET Telecommunikation, E-Commerce und interne Buchhaltung}
+
+@item @uref{http://www.borsen.dk/, Dänemarks führende Wirtschaftszeitung B@o{}rsen}
+
+@item @uref{http://tmmm.simplenet.com/indb/, Die Internet-NES-Datenbank}
+
+@item @uref{http://www.russia.cz, Reisebüro in Prag in 3 Sprachen}
+
+@item @uref{http://www.linkstation.de, Linkstation}
+
+@item @uref{http://www.peoplestaff.com, Durchsuchbare Online-Datenbank bei Peoplestaff}
+
+@item @uref{http://www.dreamhorse.com, Durchsuchbares Datenbank-System für Pferde-bezogene Werbung}
+
+@item @uref{http://pootpoot.com/,The Poot site}
+
+@item @uref{http://grateful.net/hw_html/,"Playin' in the LAN"; Netzwerk-Monitoring-Suite}
+
+@c Update von Christopher Milton <cmilton@bwn.net> 1999-12-21
+@item @uref{http://www.usapa.army.mil,U.S. Army Publishing Agency}
+
+@item @uref{http://www.nekretnine.co.yu/,Makler in Jugoslawien}
+
+@item @uref{http://demo.cpsoft.com/pims/devFAQ.html, PIMS; Patienten-Informations-Management-System}
+
+@item @uref{http://cpsoft.com,Pilkington Software Inc}
+
+@item @uref{http://www.no-quarter.org/, Memorial für Vietnam-Veteranen (The Wall) - Datenbank}
+
+@item @uref{http://www.gamers-union.com/,Gamer's Union ist auf Auktionen für gebrauchtes und nicht mehr gedrucktes Spiele-Material spezialisiert}
+
+@item @uref{http://www.montereyhigh.com/office/dbul.php3, Ein tägliches Bulletin an der Monterey-Highschool}
+
+@item @uref{http://www.myEastside.com,Website der Gemeinde Lake
+Washington's Eastside für Einwohner und Unternehmen}
+
+@item @uref{http://bowling-france.net/, Französische Bowling-Site}
+@end itemize
+
+Schicken Sie Ergänzungen dieser Liste an @email{webmaster@@mysql.com}.
+
+@page
+
+
+
+
+@node MySQL-Benutzung durch Kunden, Contrib, Benutzer, Top
+@c German node <no English equivalent>
+@appendix MySQL-Benutzung durch Kunden
+
+@cindex MySQL-Benutzung
+
+Der Abschnitt 'Einige MySQL-Benutzer' enthält viele verschiedene Links zu
+MySQL-Benutzern, aber wenig Informationen darüber, wie diese MySQL
+benutzen. @xref{Benutzer}. Dieser Handbuch-Abschnitt soll Ihnen Anregungen
+geben, wie MySQL für Problemlösungen eingesetzt wird.
+
+Dieser Abschnitt ist neu und wir planen, hier in Bälde weitere Geschichten
+unterzubringen. Wenn Sie Interesse haben, teilzunehmen, und erzählen
+wollen, wie Sie MySQL in einer einzigartigen Umgebung nutzen, oder
+Erfolgsgeschichten zu Ihrer Benutzung von MySQL haben, schreiben Sie an
+@code{docs@@mysql.com} mit Betreff @code{Success:}. Beachten Sie, dass es
+einige Zeit bis zur Beantwortung dauern kann, da wir sehr beschäftigt sind.
+
+@itemize @bullet
+@item
+@strong{Peter Zaitsev von Spylog.ru} schreibt:
+Ich denke, die Größe meiner Datenbank könnte für Euch interessant sein.
+Die gesamte Datenbank liegt momentan auf 15 Servern und enthält etwa 60.000
+Tabellen, die etwa 5.000.000.000 Zeilen enthalten. Mein unter der höchsten
+Last stehender Server hat momentan etwa 10.000 Tabellen mit 1.000.000.000
+Zeilen. Die größten Tabellen enthalten etwa 50.000.000 Zeilen, und dieser
+Wert wird sich noch steigern, wenn ich auf den 2.4-Kernel mit großen
+Dateien umstelle. Momentan muss ich viele Logs für große Sites löschen, um
+Tabellengröße unter 2 GB zu halten.
+
+@item
+@strong{Texas Instruments} benutzt MySQL für die Handhabung von Tabellen,
+die bis zu 2 Milliarden Zeilen in einer Validations-Regressions-Datenbank
+enthalten.
+@end itemize
+
+@page
+
+
+
+
+@node Contrib, Credits, MySQL-Benutzung durch Kunden, Top
+@c German node Contrib
+@appendix Beigesteuerte Programme
+
+@cindex Beigesteuerte Programme
+@cindex Programme, beigesteuerte
+
+Viele Benutzer von MySQL haben @emph{sehr} nützliche Support-Werkzeuge und
+Add-ons beigesteuert.
+
+@ifclear web
+Eine Auflistung, was unter @uref{http://www.mysql.com/Downloads/Contrib/}
+(oder einem Mirror) verfügbar ist, steht unten. Wenn Sie
+MySQL-Unterstützung für die Perl-@code{DBI}/@code{DBD}-Schnittstelle bauen
+wollen, sollten Sie sich @code{Data-Dumper}, @code{DBI} und die
+@code{Msql-Mysql-modules}-Dateien holen und installieren.
+@xref{Perl}.
+@end ifclear
+
+@appendix sec-APIs
+
+@cindex Perl, Module
+@itemize @bullet
+@item Perl-Module
+@itemize @minus
+@item @uref{http://www.mysql.com/Downloads/Contrib/Data-Dumper-2.101.tar.gz, Data-Dumper-2.101.tar.gz}
+Perl-@code{Data-Dumper}-Module. Nützlich für
+@code{DBI}/@code{DBD}-Unterstützung für ältere Perl-Installationen.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/DBI-1.15.tar.gz, DBI-1.15.tar.gz}
+Perl-@code{DBI}-Module.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/KAMXbase1.2.tar.gz,KAMXbase1.2.tar.gz}
+Konvertiert zwischen @file{.dbf}-Dateien und MySQL-Tabellen. Perl-Module
+geschrieben von Pratap Pereira @email{pereira@@ee.eng.ohio-state.edu},
+erweitert von Kevin A. McGrail
+@email{kmcgrail@@digital1.peregrinehw.com}. Dieser Konverter kann
+MEMO-Felder handhaben.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/Msql-Mysql-modules-1.2216.tar.gz, Msql-Mysql-modules-1.2216.tar.gz}
+Perl-@code{DBD}-Module, um auf mSQL- und MySQL-Datenbanken zuzugreifen.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/Data-ShowTable-3.3.tar.gz, Data-ShowTable-3.3.tar.gz}
+Perl-@code{Data-ShowTable}-Module. Nützlich für @code{DBI}/@code{DBD}-Unterstützung.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/HandySQL-1.1.tar.gz, HandySQL-1.1.tar.gz}
+HandySQL ist ein MySQL-Zugriffsmodul. Es bietet eine C-Schnittstelle, die
+in Perl eingebettet ist und ist ungefähr 20% schneller als reguläres DBI.
+
+@end itemize
+
+@cindex JDBC
+@item JDBC
+@itemize @bullet
+@item @uref{http://www.mysql.com/Downloads/Contrib/mm.mysql.jdbc-1.2c.tar.gz, mm.mysql.jdbc-1.2c.tar.gz}
+Der mm-JDBC-Treiber für MySQL. Das ist ein Produktions-Release und wird
+aktiv weiter entwickelt. Von Mark Matthews (@email{mmatthew@@ecn.purdue.edu}).
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mm.mysql.jdbc-2.0pre5.tar.gz, mm.mysql.jdbc-2.0pre5.tar.gz}
+Der mm-JDBC-Treiber für MySQL. Das ist eine Pre-Release-Beta-Version und
+wird aktiv weiter entwickelt. Von Mark Matthews (@email{mmatthew@@ecn.purdue.edu}).
+Die beiden obigen Treibern stehen unter LGPL-Lizenz. Bitte sehen Sie unter
+@uref{http://www.worldserver.com/mm.mysql/} nach den aktuellsten Treibern
+nach (und wegen weiterer JDBC-Informationen), weil diese Treibern
+vielleicht schon veraltet sind.
+
+@item @uref{http://www.caucho.com/Projekte/jdbc-mysql/index.xtp}
+Der kommerzielle Resin-JDBC-Treiber, der unter Open Source veröffentlicht
+wird. Er behauptet, schneller als der mm-Treiber zu sein, aber wir haben
+darüber bislang noch nicht viele Informationen.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/twz1jdbcForMysql-1.0.4-GA.tar.gz, twz1jdbcForMysql-1.0.4-GA.tar.gz}
+Der twz-Treiber: Ein Typ-4-JDBC-Treiber von Terrence W. Zellers
+@email{zellert@@voicenet.com}. Dieser ist kommerziell, aber kostenlos für
+privaten und Schulungsgebrauch. (Wird nicht mehr unterstützt.)
+@c no answer von Server 990830
+@c You can always find the latest Treiber at @uref{http://www.voicenet.com/~zellert/tjFM/}.
+@item @uref{http://www.mysql.com/Downloads/Contrib/pmdamysql.tgz,pmdamysql.tgz}
+Ein MySQL-PMDA. Stellt MySQL-Serverstatus- und Konfigurationsvariablen zur
+Verfügung.
+@end itemize
+
+@cindex OLEDB
+@item OLEDB
+@itemize @bullet
+@item @uref{http://www.mysql.com/downloads/Win32/MyOLEDB.exe, MyOLEDB.exe}
+OLEDB-Handler für MySQL. Von SWsoft.
+@item @uref{http://www.mysql.com/downloads/Win32/MySamples.zip, MySamples.zip}
+Beispiele und Dokumentation für MyOLEDB. Von SWsoft.
+@item @uref{http://www.mysql.com/downloads/Win32/Myoledb.zip, Myoledb.zip}
+Quelltext für MyOLEDB. Von SWsoft.
+@item @uref{http://www.mysql.com/downloads/Win32/MyOLEDB.chm, MyOLEDB.chm}
+Hilfedateien für MyOLEDB.
+@item @uref{http://www.mysql.com/downloads/Win32/libmyodbc.zip, libmyodbc.zip}
+Statische MyODBC-Bibliothek zum Bauen von MyOLEDB. Basiert auf MyODBC-Code.
+@end itemize
+
+@cindex C++
+@item C++
+@itemize @bullet
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql-c++-0.02.tar.gz, mysql-c++-0.02.tar.gz}
+MySQL-C++-Wrapper-Bibliothek. Von Rolund Haenel,
+@email{rh@@ginster.net}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/MyDAO.tar.gz, MyDAO}
+MySQL-C++-API. Von Satish @email{spitfire@@pn3.vsnl.net.in}. Inspiriert
+von Rolund Haenels C++-API und Ed Carps MyC-Bibliothek.
+
+@item @uref{http://www.mysql.com/download_mysql++.html, mysql++}
+MySQL-C++-API (mehr als nur eine Wrapper-Bibliothek). Ursprünglich von
+@email{kevina@@clark.net}. Mittlerweile gepflegt von Sinisa bei MySQL AB.
+
+@item @uref{http://nelsonjr.homepage.com/NJrAPI,NJrAPI}
+Eine in C++ geschriebene, Datenbank-unabhängige Bibliothek, die MySQL
+unterstützt.
+@end itemize
+
+@cindex Delphi
+@item Delphi
+@itemize @bullet
+@item @uref{http://www.mysql.com/Downloads/Contrib/delphi-interface.gz, delphi-interface.gz}
+Delphi-Schnittstelle zu @code{libmysql.dll}, von Blestan Tabakov,
+@email{root@@tdg.bis.bg}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/DelphiMySQL2.zip, DelphiMySQL2.zip}
+Delphi-Schnittstelle zu @code{libmysql.dll}, von @email{bsilva@@umesd.k12.or.us}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/Udmysel.pas, Udmysql.pas}
+Ein Wrapper für libmysql.dll für die Benutzung in Delphi. Von Reiner Sombrowsky.
+
+@item @uref{http://www.fichtner.net/delphi/mysql.delphi.phtml, Eine Delphi-Schnittstelle zu MySQL.}
+Mit Quelltext. Von Matthias Fichtner.
+
+@c German FIX removed comma (",") to make description work inside uref
+@item @uref{http://www.productivity.org/projects/tmysql/, @strong{TmySQL}
+Eine Bibliothek um MySQL mit Delphi zu benutzen}.
+
+@item @uref{http://www.geocities.com/CapeCanaveral/2064/mysql.html, Delphi TDataset-component}.
+@item
+@item @uref{http://www.mysql.com/Downloads/Contrib/Win32/SBMySQL50Share.exe, Delphi 5 Shareware MySQL Dataset Components}
+@end itemize
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql-ruby-2.2.0.tar.gz, mysql-ruby-2.2.0.tar.gz}
+MySQL Ruvon module. Von TOMITA Masahiro @email{tommy@@tmtm.org}
+@uref{http://www.netlab.co.jp/ruby/, Ruby} ist eine objektorientierte Interpretersprache.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/JdmMysqlTreiber-0.1.0.tar.gz,JdmMysqlTreiber-0.1.0.tar.gz}
+Ein VisualWorks 3.0 Smalltalk-Treiber für MySQL. Von
+@email{joshmiller@@earthlink.net}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/Db.py, Db.py}
+Python-Modul mit Caching. Von @email{gundalf@@rosmail.com}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/MySQLmodule-1.4.tar.gz, MySQLmodule-1.4.tar.gz}
+Python-Schnittstelle für MySQL. Von Joseph Skinner @email{joe@@earthlight.co.nz}. Geändert von Joerg Senekowitsch @email{senekow@@ibm.net}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/MySQL-python-0.3.0.tar.gz, MySQL-python-0.3.0.tar.gz}
+MySQLdb-Python ist eine DB-API v2.0-kompatible Schnittstelle zu MySQL.
+Transaktionen werden unterstützt, wenn der Server und die Tabellen sie
+unterstützen. Sie ist Thread-sicher und enthält ein Kompatibilitätsmodul
+für älteren Code, der für die nicht mehr gepflegte
+MySQLmodule-Schnittstelle geschrieben wurde.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql_mex_12.tar.gz, mysql_mex_1_12.tar.gz}
+Ein Schnittstellenprogramm für das Matlab-Programm von MathWorks. Die
+Schnittstelle wurde von Kimmo Uutela und John Fisher (nicht von Mathworks)
+hergestellt. Siehe
+@uref{http://boojum.hut.fi/~kuutela/mysqlmex.html,mysqlmex.html} wegen
+weiterer Informationen.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysqltcl-1.53.tar.gz, mysqltcl-1.53.tar.gz}
+Tcl-Schnittstelle für MySQL. Basiert auf @file{msqltcl-1.50.tar.gz}.
+Aktualisiert von Tobias Ritzau, @email{tobri@@ida.liu.se}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/MyC-0.1.tar.gz, MyC-0.1.tar.gz}
+Eine Visual-Basic-ähnliche API von Ed Carp.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/sqlscreens-1.0.1.tar.gz, sqlscreens-1.0.1.tar.gz}
+Tcl/Tk-Code, um Datenbank-Screens zu erzeugen. Von Jean-Francois Dockes.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/Vdb-dflts-2.1.tar.gz, Vdb-dflts-2.1.tar.gz}
+Das ist eine neue Version eines Satzes von Bibliothek-Dienstprogrammen, die
+eine generische Schnittstelle zu SQL-Datenbank-Maschinen zur Verfügung
+stellen, um Ihre Applikation zu einer Stufe-3-Applikation (3-Tier) zu
+machen. Der Vorteil ist, dass Sie sehr einfach zwischen verschiedenen
+Datenbank-Maschinen umschalten bzw. zu anderen Datenbanken wechseln können.
+Sie implementieren einfach eine Datei für das neue Backend und brauche
+keinerlei Änderungen an Ihren Applikationen vorzunehmen. Von
+@email{damian@@cablenet.net}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/DbFramework-1.10.tar.gz, DbFramework-1.10.tar.gz}
+DbFramework ist eine Sammlung von Klassen zur Manipulation von
+MySQL-Datenbanken. Die Klassen basieren lose auf der CDIF Data Model
+Subject Area. Von Paul Sharpe @email{paul@@miraclefish.com}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/pike-mysql-1.4.tar.gz, pike-mysql-1.4.tar.gz}
+MySQL-Modul für pike. Zur Benutzung mit dem Roxen-Webserver.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/squile.tar.gz, squile.tar.gz}
+Modul für @code{guile}, das es @code{guile} erlaubt, mit SQL-Datenbanken zu
+interagieren. Von Hal Roberts.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/stk-mysql.tar.gz, stk-mysql.tar.gz}
+Interface für Stk. Stk ist Tk-widgets mit Scheme darunter anstelle von Tcl.
+Von Terry Stefan.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/eiffel-wrapper-1.0.tar.gz,eiffel-wrapper-1.0.tar.gz}
+Eiffel-Wrapper von Michael Ravits.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/SQLmy0.06.tgz,SQLmy0.06.tgz}
+Ersetzbarer FlagShip-Datenbank-Treiber (RDD) für MySQL. Von Alejundro
+Fernundez Herrero.
+@uref{http://www.fship.com/rdds.html, Flagship-RDD-Homepage}
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mydsn-1.0.zip,mydsn-1.0.zip}
+Binärdatei und Quellcode für @code{mydsn.dll}. mydsn sollte benutzt werden,
+um die DSN-Registrierungsdatei für den MyODBC-Treiber in
+Coldfusion-Applikationen zu bauen und zu entfernen. Von Miguel Angel
+Solórzano.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/MySQL-ADA95_API.zip, MySQL-ADA95_API.zip}
+Eine ADA95-Schnittstelle zur MySQL-API. Von Francois Fabien.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/MyTool-DLL_for_VB_und_MySQL.zip, MyTool-DLL_for_VB_und_MySQL.zip}
+Eine DLL mit MySQL-C-API für Visual Basic.
+Von Ken Menzel @email{kenm@@icarz.com}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/MYSQLX.EXE, MYSQL.EXE}
+MySQL-ActiveX-Objekt für den direkten Zugriff auf Ihre MySQL-Server von
+IIS/ASP, VB und VC++ aus, der die langsameren ODBC-Methoden überspringt.
+Voll aktualisierbar, multi-threaded mit voller Unterstützung für alle
+MySQL-Feldtypen (Version 2001.1.1). Von SciBit @uref{http://www.scibit.com/}.
+
+@item @uref{http://www.fastflow.it/mylua/, MyLUA Homepage}
+Wie man die LUA-Sprache benutzt, um MySQL-@code{PROCEDURE} zu schreiben,
+das zur Laufzeit geladen werden kann.
+
+@itemize @bullet
+@item @uref{http://www.mysql.com/Downloads/Contrib/lua-4.0.tar.gz, Lua 4.0}
+LUA 4.0
+@item @uref{http://www.mysql.com/Downloads/Contrib/mylua-3.23.32.1.tar.gz, mylua-3.23.32.1.tar.gz}
+Patch für MySQL 3.23.32, um LUA 4.0 zu benutzen. Von Cristian Giussani.
+@end itemize
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/patched_myodbc.zip, patched_myodbc.zip}
+Patch (für Omniform-4.0-Unterstützung) des MyODBC-Treibers.
+Von Thomas Thaele @email{tthaele@@papenmeier.de}
+
+@end itemize
+
+@appendixsec Clients
+
+@itemize @bullet
+@item Grafische Clients
+@itemize @minus
+@item @uref{http://www.ideit.com/produkte/dbvis/, DbVisualizer}.
+Freeware-JDBC-Client, der Daten und Strukturen mehrerer Datenbanken auf
+einmal grafisch visualisiert. Von Innovative-IT Development AB.
+
+@item @uref{http://www.mysql.com/downloads/gui-clients.html, MySQLGUI}
+Die MySQL-GUI-Client-Homepage. Von Sinisa bei MySQL AB.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql_navigator_0.9.0.tar.gz, MySQL Navigator 0.9}
+MySQL Navigator ist ein MySQL-Datenbank-Server-GUI-Client-Programm. Der
+Zweck von MySQL Navigator ist, eine nützliche Schnittstelle zu
+MySQL-Datenbank-Servern zur Verfügung zu stellen, wobei mehrere
+Betriebssysteme und Sprachen unterstützt werden. Momentan können Sie
+Datenbanken importieren / exportieren, Anfragen eingeben, Ergebnismengen
+holen, Skripte editieren, Skripte laufen lassen, Benutzer hinzufügen,
+ändern und löschen, und Client- und Server-Informationen abrufen. Benutzt
+QT 2.2. GPL @uref{http://sql.kldp.org/mysql, Homepage für MySQL Navigator}.
+
+@item @uref{http://www.mysql.com/downloads/Win32/secman.zip, MySQL-Sicherheits-GUI}
+Eine Benutzer- und Sicherheitsverwaltungs-GUI für MySQL unter Windows.
+Von Martin Jeremic.
+@uref{http://jsoft.webjump.com/, Homepage für MySQL-Sicherheits-GUI}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/kmysqladmin-0.4.1.tar.gz, kmysqladmin-0.4.1.tar.gz}.
+@item @uref{http://www.mysql.com/Downloads/Contrib/kmysqladmin-0.4.1-1.src.rpm, kmysqladmin-0.4.1-1.src.rpm}.
+@item @uref{http://www.mysql.com/Downloads/Contrib/kmysqladmin-0.4.1-1.i386.rpm, kmysqladmin-0.4.1-1.i386.rpm}
+Ein Verwaltungswerkzeug für den MySQL-Server, das QT / KDE benutzt. Nur
+unter Linux getestet.
+
+@item
+@uref{http://www.mysql.com/Downloads/Contrib/mysql-admin-using-java+swing.tar.gz, Java client mit Swing} Von Fredy Fischer,
+@email{se-afs@@dial.eunet.ch}. Sie finden die letzte Version immer unter
+@uref{http://www.trash.net/~ffischer/admin/index.html, hier}.
+
+@item @uref{http://www.mysql.com/downloads/Win32/MySQL-Maker-1.0.zip,MySQL-Maker 1.0}.
+Shareware-MySQL-Client für Windows. Ein WYSIWYG-Werkzeug, mit dem Sie
+Datenbanken und Tabellen erzeugen, ändern und löschen können. Sie können
+die Feldstruktur ändern, Felder hinzufügen und Daten hinzufügen, ändern und
+löschen, direkt ohne ODBC-Treiber.
+@uref{http://www.presult.de/presult/frames/fs_mysqlmaker.html, MySQL-Maker-Homepage}
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysqlwinadmn.zip, mysqlwinadmn.zip}
+Windows-GUI (nur Binärdatei) zur Verwaltung einer Datenbank, von David B. Mansel,
+@email{david@@zhadum.org}.
+
+@item @uref{http://home.online.no/~runeberg/myqa, MyQA}
+Ein Linux-basierender Anfrage-Client für den MySQL-Datenbank-Server. Mit
+MyQA können Sie SQL-Anfragen eingeben, diese ausführen und die Ergebnisse
+betrachten, alles in einer grafischen Benutzerschnittstelle. Die GUI ähnelt
+grob dem 'Anfrage-Analyzer'-Client, der mit dem Microsoft SQL-Server
+ausgeliefert wird.
+
+@item @uref{http://members.xoom.com/_opex_/mysqlmanager/index.html, MySQL-Manager}
+Ein grafischer MySQL-Server-Manager für MySQL-Server. Geschrieben in Java,
+für Windows.
+
+
+@item @uref{http://www.mysql.com/downloads/Win32/netadmin.zip, netadmin.zip}
+Ein Verwaltungswerkzeug für MySQL unter Windows 95/98 und Windows NT 4.0.
+Nur getestet mit MySQL-Versions 3.23.5 bis 3.23.7. Geschrieben mit den
+Tmysql-Komponenten.
+
+Sie können Anfragen schreiben und Tabellen darstellen, Indexe,
+Tabellensyntax sowie Benutzer, Host und Datenbank verwalten und vieles
+mehr. Das Werkzeug ist eine Beta-Version und hat noch viele Bugs. Sie
+können das Programm mit allen Features testen. Bitte schicken Sie Bugs und
+Hinweise an Marco Suess @email{ms@@it-netservice.de}. Original-URL
+@url{http://www.it-netservice.de/pages/Software/index.html}.
+
+@item @uref{http://www.mysql.com/downloads/Win32/netadmin2.zip, netadmin2.zip}
+Neue Version von netadmin. Siehe oben wegen Details.
+
+@item @uref{http://www.mysql.com/downloads/Win32/ARTADMIN203.EXE,Atronic's MySQL-Client für Windows 2.0.3.0}.
+Die Homepage hierfür ist unter @uref{http://www.artronic.hr}.
+
+@item @uref{http://www.mysql.com/downloads/Win32/mysqlfront.zip, mysqlfront}
+Homepage: @uref{http://www.mysqlfront.de/}.
+Win32-Client für die Verwaltung von Datenbanken, Tabellen, Tabellendaten,
+Indexen und Import-/Export-Dateien. Freeware. Von Ansgar Becker.
+
+@c German FIX removed comma (",") to make description work inside uref
+@item @uref{http://www.mysql.com/downloads/Win32/W9xstop.zip,Dienstprogramm
+von Artronic um MySQL unter Windows 9x anzuhalten}.
+
+@item @uref{http://bardo.hyperlink.cz/mysqlmon,ein leichtgewichtiger GUI-Client für Windows}.
+
+@item @uref{http://dbtools.vila.bol.com.br/, DB-Werkzeuge}
+Ein Werkzeug zur Verwaltung von MySQL-Datenbanken. Momentan nur für
+Windows. Einige Features:
+@itemize @bullet
+@item Verwaltung von Servern, Datenbanken, Tabellen, Spalten, Indexen und
+Benutzern.
+@item Import-Assistent, um Strukturen und Daten von MS Access, MS Excel,
+Dbase, FoxPro, Paradox und ODBC Datenbanken zu übernehmen.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/KMYENG113.zip,KMYENG113.zip}
+Eine Verwaltungs-GUI für MySQL. Funktioniert nur unter Windows, kein
+Quellcode verfügbar. Verfügbar in englisch und japanisch. Von Mitunobu Kaneko.
+Homepage: @uref{http://sql.jnts.ne.jp/}
+@end itemize
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/xmysqladmin-1.0.tar.gz, xmysqladmin-1.0.tar.gz}
+Ein X-basierendes Frontend zur MySQL-Datenbank-Maschine. Erlaubt Neuladen,
+Status-Prüfungen, Prozesssteuerung, myisamchk, grant/revoke-Berechtigungen,
+Erzeugung von Datenbanken, Löschen von Datenbanken, Erzeugen, Ändern,
+Durchsuchen und Löschen von Tabellen. Original von Gilbert Therrien,
+@email{gilbert@@ican.net}, jetzt aber Public Domain und von MySQL AB
+unterstützt.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/xmysql-1.9.tar.gz, xmysql-1.9.tar.gz}.
+@item @uref{http://web.wt.net/~dblhack, xmysql-Homepage}
+Ein Frontend zur MySQL-Datenbank-Maschine, mit der man auf einfache Weise
+Anfragen und Tabellenwartung durchführen kann sowie Stapel-Anfrragen. Von
+Rick Mehalick, @email{dblhack@@wt.net}.
+Erfordert @uref{http://bragg.phys.uwm.edu/xforms,xforms 0.88}, um zu
+funktionieren.
+@item @uref{http://www.tamos.net/sw/dbMetrix,dbMetrix}
+Ein Open-Source-Client für das Durchsuchen von Datenbanken und die
+Ausführung von SQL. Unterstützt MySQL, Oracle, PostgreSQL und mSQL.
+@item @uref{http://www.multimania.com/bbrox/GtkSQL,GtkSQL}
+Ein Anfrage-Werkzeug für MySQL und PostgreSQL.
+@item @uref{http://dbman.linux.cz/,dbMan}
+Ein Anfrage-Werkzeug, geschrieben in Perl. Benutzt DBI und Tk.
+@item @uref{http://www.mysql.com/downloads/Win32/Msc201.EXE, Mascon 202}
+@item @uref{http://www.mysql.com/downloads/Win32/FrMsc202.EXE, Free Mascon 202}
+Mascon ist eine mächtige Win32-GUI für die Verwaltung von
+MySQL-Server-Datenbanken. Die Features von Mascon beinhalten visuellen
+Tabellenentwurf, Verbindungen zu mehrfachen Servern, Daten- und
+Blob-Editierung von Tabellen, Sicherheitseinstellungen, SQL-Farb-Coding,
+Dump-Funktionalität und vieles mehr.
+@uref{http://www.scibit.com/produkte/Software/Utils/Mascon.asp,Mascon-Homepage}.
+@item @uref{http://www.virtualbeer.net/dbui/,DBUI}
+DBUI ist ein grafischer Gtk-Datenbank-Editor.
+@item @uref{http://www.rtlabs.com/, MacSQL}
+GUI für MySQL-, ODBC- und JDBC-Datenbanken für Mac OS.
+@item @uref{http://www.caleb.com.au/, JRetriever}
+JRetriever ist ein generisches Datenbank-Frontend-Werkzeug für
+JDBC-kompatible Datenbanken, geschrieben mit Java 2. JRetriever zeigt
+Datenbank- und Tabellenansichten in einem Windows-Explorer-ähnlichen
+Frontend an. Der Benutzer kann Daten entweder durch Klicken auf den
+Tabellen-Ordner oder durch das Zusammenstellen eigener SQL-Statements mit
+dem eingebauten SQL-Editor abrufen. Das Werkzeug wurde mit Oracle 8 und
+MySQL als Backend-Datenbanken getestet. Es erfordert JDK 1.3 von JavaSoft.
+@item @uref{http://www.jetools.com/products/databrowser/, DataBrowser}
+Der DataBrowser ist ein Datenbank- und Plattform-übergreifendes
+Datenzugriffswerkzeug. Es ist benutzerfreundlicher als Werkzeuge wie SQL
+Plus, psql (kommandozeilenbasierende Werkzeuge). Es ist flexibler als TOAD,
+ISQL und PGAccess, die als GUIs auf eine einzige Plattform oder Datenbank
+beschränkt sind.
+@item @uref{http://www.intrex.net/amit/Software/, SQLC}
+Die SQL Console ist eine eigenständige Java-Applikation, mit der Sie auf
+ein SQL-Datenbanksystem zugreifen und SQL-Anfragen und -Aktualisierung
+absetzen können. Es hat eine leicht benutzbare grafische
+Benutzerschnittstelle. Die SQL Console benutzt JDBC, um sich mit dem
+Datenbanksystem zu verbinden. Daher können Sie sich mit den richtigen
+JDBC-Treibern mit diesem Dienstprogramm mit den beliebtesten
+Datenbanksystemen verbinden.
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql_mmc.zip, MySQL MMC}
+MySQL MMC ist ein GUI-Management-Werkzeug, das mit kdevelop entwickelt
+wurde. Es besitzt eine sehr gute Schnittstelle, die komplett Microsoft
+Enterprise Tool (für SQL Server) oder Sybase Central ähnelt. Damit können
+Sie Server, Datenbanken, Tabellen, Indexe und Benutzer verwalten und
+Tabellendaten in Gittern editieren, sowie SQL ausführen.
+@end itemize
+
+@cindex Web-Clients
+@item Web-Clients
+@itemize @minus
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysqladmin-atif-1.0.tar.gz, mysqladmin-atif-1.0.tar.gz}
+WWW-MySQL-Verwaltungswerkzeug für die @code{user}-, @code{db}- und
+@code{host}-Tabellen. Von Tim Sailer, geändert von Atif Ghaffar
+@email{aghaffar@@artemedia.ch}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql-webadmin-1.0a8-rz.tar.gz, mysql-webadmin-1.0a8-rz.tar.gz}
+Ein in PHP-FI geschriebenes Werkzeug zur Verwaltung von MySQL-Datenbanken,
+entfernt über das Web mit einem Web-Browser. Von Peter Kuppelwieser,
+@email{peter.kuppelwieser@@kantea.it}. Aktualisiert von Wim Bonis,
+@email{bonis@@kiss.de}. Wird nicht mehr gepflegt!
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysqladm.tar.gz, mysqladm.tar.gz}
+MySQL-Web-Datenbankadministration, geschrieben in Perl. Von Tim Sailer.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysqladm-2.tar.gz, mysqladm-2.tar.gz}
+Aktualisierte Version von @file{mysqladm.tar.gz}, von High Tide.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/billowmysql.zip, billowmysql.zip}
+Akualisierte Version von @file{mysqladm.tar.gz}, von Ying Gao. Sie erhalten
+die neueste Version von @uref{http://civeng.com/sqldemo/, der Homepage}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/myadmin-0.4.tar.gz, myadmin-0.4.tar.gz}.
+@item @uref{http://myadmin.cheapnet.net/, MyAdmin-Homepage}
+Ein Web-basierender MySQL-Administrator von Mike Machado.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/phpMyAdmin_2.2.0.tar.gz,phpMyAdmin_2.2.0.tar.gz}
+Ein Satz von PHP3-Skripten, um MySQL über das WWW zu administrieren.
+
+@item @uref{http://www.phpwizard.net/Projekte/phpMyAdmin/, phpMyAdmin Homepage}
+Ein PHP3-Werkzeug im Geiste von mysql-webadmin, von Tobias Ratschiller,
+tobias@@dnet.it.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/useradm.tar.gz, useradm.tar.gz}
+MySQL-Administrator in PHP. Von Ofni Thomas @email{othomas@@vaidSysteme.com}.
+
+@item @uref{http://gossamer-thread.com/perl/mysqlman/mysql.cgi, MySQLMan}
+Ähnliche Funktionalität wie phpmyadmin, aber geschrieben in Perl und unter
+Verwenden von HTML-Vorlagen. Von Alex Krohn.
+@end itemize
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql-editor.tar.gz,mysql-editor.tar.gz}
+Mit diesen CGI-Skripten in Perl können Sie die Inhalte von
+MySQL-Datenbanken editieren. Von Tomas Zeman.
+@item
+@uref{http://worldcommunity.com/openquelle/futuresql, FutureSQL Web-Datenbankadministrations-Werkzeug}.
+FutureSQL von Peter F. Brown ist ein Open-Source-Web-Datenbank-Werkzeug für
+die schelle Applikationsentwicklung. Geschrieben in Perl, verwendet MySQL.
+Benutzt @code{DBI:DBD} und @code{CGI.pm}.
+
+Mit FutureSQL können Sie schnell config-Dateien einrichten, um Datensätze
+einer MySQL-Datenbank zu betrachten, zu editieren, zu löschen und
+anderweitig zu verarbeiten. Es benutzt ein Daten-Wörterbuch,
+Konfigurationsdateien und Vorlagen und erlaubt "Pre-Processing" und
+"Post-Processing" von Feldern, Datensätzen und Operationen.
+@end itemize
+
+@cindex Web-Werkzeuge
+@cindex Werkzeuge,, Web
+@appendixsec Web-Werkzeuge
+
+@itemize @bullet
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mod_mysql_include_1.0.tar.gz, mod_mysql_include_1.0.tar.gz}
+Apache-Modul, um HTML von MySQL-Anfragen in Ihre Seiten zu integrieren und
+um Aktualisierungsanfragen auszuführen. Ursprünglich geschrieben, um ein
+einfaches, schnelles Banner-Rotationssystem mit geringem Overhead zu
+implementieren. Von Sasha Pachev.
+
+@item @uref{http://htcheck.sourceforge.net, htCheck} - URL-Überprüfer mit
+MySQL-Backend. Gelistete (spidered) URLs können später abgefragt werden,
+wobei SQL verwendet wird, um verschiedene Sorten von Information abzurufen,
+z. B. Broken Links. Geschrieben von Gabriele Bartolini.
+
+@item @uref{http://www.odbsoft.com/cook/sources.htm}
+Dieses Paket hat diverse Funktionen zum Erzeugen von HTML-Code aus einer
+SQL-Tabellenstruktur und zum Erzeugen von SQL-Statements (Select, Insert,
+Update, Delete) aus einem HTML-Formular. Sie können komplette
+Formular-Schnittstellen zu einer SQL-Datenbank bauen (Anfrage, Hinzufügen,
+Aktualisierung, Löschen), ohne jedes Programmieren! Von Marc Beneteau, @email{marc@@odbsoft.com}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/sqlhtml.tar.gz, sqlhtml.tar.gz}
+SQL/HTML ist ein HTML-Datenbankmanager für MySQL mit @code{DBI} 1.06.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/udmsearch-3.0.23.tar.gz, UdmSearch 3.0.23 (stabile Version)}.
+@c German FIX removed comma (",") to make description work inside uref
+@item @uref{http://www.mysql.com/Downloads/Contrib/mnogosearch-3.1.12.tar.gz, mnogosearch 3.1.12 (Entwicklungs- aber empfohlene Version)}.
+@item @uref{http://search.mnoGo.ru, UdmSearch-Homepage}
+Eine SQL-basierende Suchmaschine fürs Internet. Von Alexander I. Barkov @email{bar@@izhcom.ru}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/wmtcl.doc, wmtcl.doc}.
+@item @uref{http://www.mysql.com/Downloads/Contrib/wmtcl.lex, wmtcl.lex}
+Hiermit können Sie HTML-Dateien mit Einfügungen von Tcl-Code schreiben. Von @email{vvs@@scil.npi.msu.su}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/www-sql-0.5.7.lsm, www-sql-0.5.7.lsm}.
+@item @uref{http://www.mysql.com/Downloads/Contrib/www-sql-0.5.7.tar.gz, www-sql-0.5.7.tar.gz}
+Ein CGI-Programm, das eine HTML-Datei mit speziellen Tags parst, die Tags
+selbst parst und Daten aus einer MySQL-Datenbank einfügt.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/genquery.zip, genquery.zip}
+Perl-SQL-Datenbankschnittstellenpaket für HTML.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/cgi++-0.8.tar.gz, cgi++-0.8.tar.gz}
+Ein Makro-Prozessor, um leicht CGI/Datenbank-Programme in C++ zu schreiben. Von Sasha Pachev.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/webboard-1.0.zip, WebBoard 1.0}
+EU-Industries Internet-Message-Board.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/DBIx-TextIndex-0.02.tar.gz, DBIx-TextIndex-0.02.tar.gz}
+Volltextsuche mit Perl auf @code{BLOB}/@code{TEXT}-Spalten. Von Daniel Koch.
+@end itemize
+
+@cindex Werkzeuge, Benchmark-
+@cindex Benchmark, Werkzeuge
+@appendixsec Performance-Benchmark-Werkzeuge
+
+@itemize @bullet
+@item @uref{http://www.mysql.com/downloads/super-smack/super-smack-1.0.tar.gz,
+ super-smack}
+Multi-Threaded Benchmark-Werkzeug für MySQL und @strong{PostgreSQL}.
+Geschrieben in C++. Leicht zu erweitern für die Unterstützung anderer
+Datenbanken, die C/C++-Client-Bibliotheken haben. Von Sasha Pachev.
+@end itemize
+
+@cindex Werkzeuge, Authentifizierung
+@cindex Authentifizierungswerkzeuge
+@appendixsec Authentifizierungswerkzeuge
+
+@itemize @bullet
+@item @uref{http://www.mysql.com/Downloads/Contrib/ascend-radius-mysql-0.7.2.patch.gz,ascend-radius-mysql-0.7.2.patch.gz}
+Das ist ein Authentifizierungs- und Logging-Patch, der MySQL für Ascend-Radius benutzt. Von @email{takeshi@@SoftAgency.co.jp}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/icradius-0.10.tar.gz, icradius 0.10}
+@uref{http://www.mysql.com/Downloads/Contrib/icradius.README, icradius readme-Datei}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/checkpassword-0.81-mysql-0.6.6.patch.gz,
+checkpassword-0.81-mysql-0.6.6.patch.gz}
+MySQL-Authentifizierungs-Patch für QMAIL und checkpassword. Diese sind
+nützlich für die Benutzerverwaltung (mail, pop account) von MySQL.
+Von @email{takeshi@@SoftAgency.co.jp}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/jradius-diff.gz, jradius-diff.gz}
+MySQL-Unterstützung für Livingston's Radius 2.01. Authentifizierung und
+Abrechnung. Von Jose de Leon, @email{jdl@@thevision.net}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mod_auth_mysql-2.20.tar.gz, mod_auth_mysql-2.20.tar.gz}
+Apache-Authentifizierungsmodul für MySQL. Von Zeev Suraski,
+@email{bourbon@@netvision.net.il}.
+
+@c @strong{Bitte} registrieren Sie dieses Modul unter:
+@c @url{http://bourbon.netvision.net.il/mysql/mod_auth_mysql/register.html}.
+@c Die Registrierungsinformationen werden nur für statistische Zwecke
+@c benutzt und fördern die Weiterentwicklung dieses Moduls!
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mod_log_mysql-1.05.tar.gz, mod_log_mysql-1.05.tar.gz}
+MySQL-Loggingmodul für Apache. Von Zeev Suraski,
+@email{bourbon@@netvision.net.il}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mypasswd-2.0.tar.gz, mypasswd-2.0.tar.gz}
+Zusatz für @code{mod_auth_mysql}. Das kleine Werzeug ermöglicht Ihnen,
+Benutzerdatensätze hinzuzufügen oder zu ändern, wobei Gruppen- und / oder
+Passwort-Einträge in MySQL-Tabellen gespeichert werden. Von Harry
+Brueckner, @email{brueckner@@respublica.de}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql-passwd.README, mysql-passwd.README}.
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql-passwd-1.2.tar.gz, mysql-passwd-1.2.tar.gz}
+Zusatz für @code{mod_auth_mysql}. Ein System aus zwei Bestandteilen zur
+Benutzung mit @code{mod_auth_mysql}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/pam_mysql.tar.gz, pam_mysql.tar.gz}
+Dieses Modul authentifiziert Benutzer via @code{pam}, mit MySQL.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/nsapi_auth_mysql.tar, nsapi_auth_mysql.tar}
+Netscape-Webserver-API- (NSAPI) Funktionen, um (BASIC) Benutzer gegen
+MySQL-Tabellen zu authentifizieren. Von Yuan John Jiang.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/qmail-1.03-mysql-0.6.6.patch.gz,qmail-1.03-mysql-0.6.6.patch.gz}
+Patch für qmail, um Benutzer einer MySQL-Tabelle zu authentifizieren.
+Von @email{takeshi@@SoftAgency.co.jp}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/proftpd-1.2.0rc2-fix-mysql.patch, proftpd-1.2.0rc2-fix-mysql.patch}
+Patch für proftpd1.2.0rc2. Von @email{takeshi@@SoftAgency.co.jp}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/pwcheck_mysql-0.1.tar.gz,pwcheck_mysql-0.1.tar.gz}
+Ein Authentifizierungsmodul für den Cyrus-IMAP-Server. Von Aaron Newsome.
+
+
+@end itemize
+
+@cindex Konverter
+@appendixsec Konverter
+
+@itemize @bullet
+@item @uref{http://www.mysql.com/Downloads/Contrib/mssql2mysql.txt, mssql2mysql.txt}
+Konverter von MS-SQL zu MySQL. Von Michael Kofler.
+@uref{http://www.kofler.cc/mysql/mssql2mysql.html, mssql2mysql Homepage}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/dbf2mysql-1.14.tar.gz, dbf2mysql-1.14.tar.gz}
+Konvertiert zwischen @file{.dbf}-Dateien und MySQL-Tabellen. Von Maarten
+Boekhold (@email{boekhold@@cindy.et.tudelft.nl}), William Volkman und
+Michael Widenius. Dieser Konverter schließt rudimentäre Unterstützung (nur
+lesen) für MEMO-Felder ein.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/dbf2mysql-1.13.tgz, dbf2mysql-1.13.tgz}
+Konvertiert zwischen @file{.dbf}-Dateien und MySQL-Tabellen. Von Maarten
+Boekhold, @email{boekhold@@cindy.et.tudelft.nl} und Michael Widenius.
+Dieser Konverter kann keine MEMO-Felder handhaben.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/dbf2mysql.zip, dbf2mysql.zip}
+Konvertiert zwischen FoxPro-@file{.dbf}-Dateien und MySQL-Tabellen unter Windows.
+Von Alexunder Eltsyn, @email{ae@@nica.ru} oder @email{ae@@usa.net}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/dbf2sql.zip, dbf2sql.zip}
+Kurzes, einfaches Programm, dass Ihnen bei der Überführung Ihrer Daten von
+Foxpro-Tabellen in MySQL-Tabellen helfen kann. Von Danko Josic.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/dump2h-1.20.gz, dump2h-1.20.gz}
+Konvertiert von einer @code{mysqldump}-Ausgabe in eine C-Header-Datei. Von
+Harry Brueckner, @email{brueckner@@mail.respublica.de}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/exportsql.txt, exportsql.txt}
+Ein Skript, das @code{access_to_mysql.txt} ähnelt, ausser dass dieses voll
+konfigurierbar ist, eine bessere Typumwandlung hat (inklusive Erkennung von
+@code{TIMESTAMP}-Feldern), bei der Konvertierung Warnungen und Vorschläge
+bereit stellt, Anführungszeichen, @strong{alle} Sonderzeichen in Text und
+Binärdaten erkennt usw. Es konvertiert ausserdem nach @code{mSQL} Version 1
+und 2, und kostet nichts. Siehe @uref{http://www.cynergi.net/exportsql/}
+wegen der neuesten Version. Von Pedro Freire, @email{Support@@cynergi.net}.
+@strong{HINWEIS:} Funktioniert nicht mit Access 2!
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/access_to_mysql.txt, access_to_mysql.txt}
+Kopieren Sie diese Funktion in ein Access-Modul einer Datenbank, die die
+Tabellen enthält, die Sie exportieren wollen. Siehe auch @code{exportsql}.
+Von Brian Andrews. @strong{HINWEIS:} Funktioniert nicht mit Access 2!
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/importsql.txt, importsql.txt}
+Ein Skript, das genau das Gegenteil von @code{exportsql.txt} macht. Es
+importiert Daten von MySQL in eine Access-Datenbank via ODBC. Das ist sehr
+handlich, wenn es mit exportsql kombiniert wird, weil Sie damit Access für
+das Datenbank-Design und die -Administration verwenden können und das
+Getane dann mit Ihrem MySQL-Server synchronisieren können. Siehe
+@uref{http://www.netdive.com/freebies/importsql/} wegen Aktualisierungen.
+Geschrieben von Laurent Bossavit von NetDIVE.
+@strong{HINWEIS:} Funktioniert nicht mit Access 2!
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mdatabase2sql.bas,
+mdatabase2sql.bas}
+Konverter von Access97 nach MySQL von Moshe Gurvich.
+
+@item
+@uref{http://www.mysql.com/Downloads/Contrib/msql2mysqlWrapper-1.0.tgz,
+msql2mysqlWrapper 1.0}
+Ein C-Wrapper von @code{mSQL} nach MySQL. Von @email{alfred@@sb.net}
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/sqlconv.pl, sqlconv.pl}
+Ein einfaches Skript, das zum Kopieren von Feldern von einer MySQL-Tabelle
+in eine andere im Massenverfahren benutzt werden kann. Im Wesentlichen
+können Sie @code{mysqldump} laufen lassen und die Ausgabe an das
+@code{sqlconv.pl}-Skript übergeben. Das Skript parst die
+@code{mysqldump}-Ausgabe und ordnet die Felder neu, so dass sie in die neue
+Tabelle eingefügt werden können. Ein Beispiel hierfür ist, dass Sie eine
+neue Tabelle für eine andere Site, an der Sie arbeiten, erstellen wollen,
+die Tabelle jedoch ein bisschen anders ist (also die Felder in anderer
+Reihenfolge hat usw.). Von Steve Shreeve.
+@item @uref{http://www.mysql.com/Downloads/Contrib/oracledump oderacledump}
+Perl-Programm, um Oracle-Datenbanken nach MySQL zu konvertieren. Hat
+dasselbe Ausgabeformat wie mysqldump. Von Johan Andersson.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/excel2mysql.pl, excel2mysql.pl}
+Perl-Programm, um Excel-Tabellen in eine MySQL-Datenbank zu importieren.
+Von Stephen Hurd @email{shurd@@sk.sympatico.ca}
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/T2S_100.ZIP, T2S_100.ZIP}.
+Windows-Programm zum Konvertieren von Textdateien in MySQL-Datenbanken. Von
+Asaf Azulay.
+
+@end itemize
+
+@appendixsec MySQL mit anderen Produkten benutzen
+
+@itemize @bullet
+@item @uref{http://www.mysql.com/Downloads/Contrib/emacs-sql-mode.tar.gz, emacs-sql-mode.tar.gz}
+Raw-Portierung eines SQL-Modus für XEmacs. Unterstützt Vervollständigung.
+Original von Peter D. Pezaris @email{pez@@atlantic2.sbi.com} und teilweise
+MySQL-Portierung von David Axmark.
+
+@item @uref{http://www.mysql.com/downloads/Win32/myaccess97_1_4.zip, MyAccess97 1.4}.
+@item @uref{http://www.mysql.com/downloads/Win32/myaccess2000_1_4.zip, MyAccess2000 1.4}.
+
+MyAccess ist ein Add-In für MS-Access 97/2000, mit dem MySQL-Datenbanken
+innerhalb von Access verwaltet werden können. Hauptfunktionen sind:
+@itemize @minus
+@item Erzeugen und Ändern von Tabellen
+@item Anfragen an MySQL ausführen
+@item ''Erzeugen von Tabellen-Skripten'' von MySQL
+@item Importieren / Exportieren von Tabellen aus Access nach MySQL und umgekehrt
+@item Änderungen mitschreiben (Log)
+@item Einen Datenbank-Definitionsbericht anzeigen
+@end itemize
+
+Geschrieben von Hubertus Hiden. @uref{http://www.accessmysql.com, MyAccess-Homepage}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/radius-0.3.tar.gz, radius-0.3.tar.gz}
+Patches für @code{radiusd}, damit es MySQL unterstützt. Von Wim Bonis,
+@email{bonis@@kiss.de}.
+@end itemize
+
+@cindex Werkzeuge, nützliche
+@appendixsec Nützliche Werkzeuge
+
+@itemize @bullet
+@item @uref{http://worldcommunity.com/opensource/utilities/mysql_backup.html, MySQL-Datensicherung}.
+
+Ein Datensicherungsskript für MySQL. Von Peter F. Brown.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mytop, mytop}
+@item @uref{http://public.yahoo.com/~jzawodn/mytop/, mytop Homepage}
+mytop ist ein Perl-Programm, mit dem Sie MySQL-Server beobachten können,
+indem Sie aktive Threads, Anfragen und Server-Performance über alles
+betrachten. Von Jeremy D. Zawodny.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql_watchdog.pl, mysql_watchdog.pl}
+Den MySQL-Daemon auf mögliche Blockierungen überwachen. Von Yermo Lamers,
+@email{yml@@yml.com}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysqltop.tar.gz, mysqltop.tar.gz}
+Sendet eine Anfrage in einem festen Zeitintervall an den Server und zeigt
+die Ergebnistabelle. Von Thomas Wana.
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql_structure_dumper.tar.gz,mysql_structure_dumper.tar.gz}
+Gibt die Struktur aller Tabellen in einer Datenbank aus. Von Thomas Wana.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql_structure_dumper.tgz, structure_dumper.tgz}
+Gibt die Struktur aller Tabellen in einer Datenbank aus. Von Thomas Wana.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysqlsync, mysqlsync-1.0-alpha.tar.gz}.
+Ein Perl-Skript, um entfernte Kopien einer MySQL-Datenbank mit einer
+zentralen Master-Kopie synchronisiert zu halten. Von Mark Jeftovic. @email{markjr@@easydns.com}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/MySQLTutor-0.2.tar.gz, MySQLTutor}.
+MySQLTutor. Ein MySQL-Tutorial für Anfänger.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/MySQLDB.zip, MySQLDB.zip}
+Eine COM-Bibliothek für MySQL von Alok Singh.
+@item @uref{http://www.mysql.com/Downloads/Contrib/MySQLDB-readme.html, MySQLDB-readme.html}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql_replicate.pl, mysql_replicate.pl}
+Perl-Programm, das Replikation handhabt. Von @email{elble@@icculus.nsg.nwu.edu}
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/DBIx-TextIndex-0.02.tar.gz, DBIx-TextIndex-0.02.tar.gz}
+Perl-Skript, das umgekehrte Indexierung für Textsuchen benutzt. Von Daniel
+Koch.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/dbcheck, dbcheck}
+Perl-Skript, das eine Datensicherung der Tabellen macht, bevor isamchk
+darauf laufen gelassen wird. Von Elizabeth.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mybackup}.
+@item @uref{http://www.mswanson.com/mybackup, mybackup-Homepage}
+Wrapper für mysqldump, um alle Datenbanken zu sichern. Von Marc Swanson.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mdu.pl.gz,mdu.pl.gz}
+Gibt die Speicherbenutzung einer MySQL-Datenbank aus.
+@end itemize
+
+@cindex RPMs, für gebräuchliche Werkzeuge
+@cindex Werkzeuge, RPMs für
+@appendixsec RPMs für gebräuchliche Werkzeuge (die meisten sind für RedHat 6.1)
+
+@itemize @bullet
+@item @uref{http://www.mysql.com/Downloads/Contrib/perl-Data-ShowTable-3.3-2.i386.rpm,perl-Data-ShowTable-3.3-2.i386.rpm}
+@item @uref{http://www.mysql.com/Downloads/Contrib/perl-Msql-Mysql-modules-1.2210-2.i386.rpm,perl-Msql-Mysql-modules-1.2210-2.i386.rpm}
+@item @uref{http://www.mysql.com/Downloads/Contrib/php-pg-3.0.13-1.i386.rpm,php-pg-3.0.13-1.i386.rpm}
+@item @uref{http://www.mysql.com/Downloads/Contrib/php-pg-manual-3.0.13-1.i386.rpm,php-pg-manual-3.0.13-1.i386.rpm}
+@item @uref{http://www.mysql.com/Downloads/Contrib/php-pg-mysql-3.0.13-1.i386.rpm,php-pg-mysql-3.0.13-1.i386.rpm}
+@item @uref{http://www.mysql.com/Downloads/Contrib/phpMyAdmin-2.0.5-1.noarch.rpm,phpMyAdmin-2.0.5-1.noarch.rpm}
+@end itemize
+
+@cindex Funktionen, nützliche
+@appendixsec Nützliche Funktionen
+@itemize @bullet
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysnprintf.c,mysnprintf.c}
+sprintf()-Funktion für SQL-Anfragen, die Blobs escapen kann. Von Chunhua Liu.
+@end itemize
+
+@appendixsec Windows-Programme
+@itemize @bullet
+@item @uref{http://www.mysql.com/Downloads/Contrib/LaunchMySQL.zip, LaunchMySQL.zip}
+Das Programm startet den MySQL-Server, fährt ihn herunter und gibt
+Status-Informationen aus. Von Bill Thompson
+@end itemize
+
+@appendixsec Nicht kategorisiert
+
+@itemize @bullet
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/findres.pl, findres.pl}
+Findet reservierte Wörter in Tabellen. Von Nem W Schlecht.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/handicap.tar.gz, handicap.tar.gz}
+Performance-Handicapping-System für Yachten. Benutzt PHP. Von
+@email{rhill@@stobyn.ml.org}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/hylalog-1.0.tar.gz, hylalog-1.0.tar.gz}
+Speichert ausgehende @code{hylafax}-Faxe in einer MySQL-Datenbank. Von
+Sinisa Milivojevic, @email{sinisa@@mysql.com}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mrtg-mysql-1.0.tar.gz, mrtg-mysql-1.0.tar.gz}
+MySQL-Status-Ausgabe mit MRTG, von Luuk de Boer, @email{luuk@@wxs.nl}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/wuftpd-2.4.2.18-mysql_Support.2.tar.gz, wuftpd-2.4.2.18-mysql_Support.2.tar.gz}
+Patches, um Loggen nach MySQL für WU-ftpd hinzuzufügen. Von Zeev Suraski,
+@email{bourbon@@netvision.net.il}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/wu-ftpd-2.6.0-mysql.4.tar.gz,wu-ftpd-2.6.0-mysql.4.tar.gz}
+Patches, um Loggen nach MySQL für WU-ftpd 2.6.0 hinzuzufügen. Von
+@email{takeshi@@SoftAgency.co.jp}, basierend auf den
+Zeev-Suraski-wuftpd-Patches.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/Old-Versions, Alte Versionen}
+Frühere Versionen von Dingen in diesen Listen, an denen Sie wahrscheinlich
+nicht interessiert sind.
+@end itemize
+@page
+
+
+
+
+@node Credits, News, Contrib, Top
+@c German node Danksagungen
+@appendix Danksagungen
+
+@cindex Entwickler, Auflistung
+
+Dieser Anhang listet die Entwickler, Kontributoren und Unterstützer auf,
+die mitgeholfen haben, dass MySQL das wird, was es heute ist.
+
+
+
+@menu
+* Developers::
+* Contributors::
+* Supporters::
+@end menu
+
+@node Developers, Contributors, Credits, Credits
+@c German node Entwickler
+@appendixsec Entwickler bei MySQL AB
+
+Hier sind die Entwickler, die von @code{MySQL AB} angestellt wurden, um an
+@code{MySQL} zu arbeiten, ungefähr in der Reihenfolge ihres Eintritts.
+Neben dem Namen wird aufgelistet, für welche Teilaufgaben der Entwickler
+verantwortlich ist oder welche Leistungen er erbracht hat.
+
+@table @asis
+@item Michael (Monty) Widenius
+Schrieb folgende Bestandteile von MySQL:
+@itemize @bullet
+@item
+Den gesamten Haupt-Code in @code{mysqld}.
+@item
+Neue Funktionen für die Zeichenketten-Bibliothek.
+@item
+Das meiste der @code{mysys}-Bibliothek.
+@item
+Die @code{ISAM}- und @code{MyISAM}-Bibliotheken (B-Baum-Index-Datei-Handler
+mit Index-Komprimierung und verschiedenen Datensatzformaten).
+@item
+Die @code{HEAP}-Bibliothek. Ein Speicher-Tabellensystem mit unserem
+überragenden komplett dynamischen Hashing. In Gebrauch seit 1981 und
+veröffentlicht um 1984.
+@item
+Das @code{replace}-Programm (ansehen, es ist COOL!).
+@item
+@strong{MyODBC}, den ODBC-Treiber für Windows95.
+@item
+Behob Bugs in MIT-pThread, um sie für MySQL zum Laufen zu bringen, sowie
+Unireg, ein curses-basierendes Applikationswerkzeug vielen Utilities.
+@item
+Portierung von @code{mSQL}-Werkzeugen wie @code{msqlperl},
+@code{DBD}/@code{DBI} und @code{db2mysql}.
+@item
+Das meiste von Crash-me und die Grundlage für die MySQL-Benchmarks.
+@end itemize
+
+@item David Axmark
+@itemize @bullet
+@item
+Koordinator und ursprünglicher Haupt-Schreiber des
+@strong{Referenzhandbuchs}, inklusive Verbesserungen von @code{texi2HTML}.
+@item
+Automatische Website-Aktualisierung des Handbuchs.
+@item
+Ursprüngliche Autoconf-, Automake- und Libtool-Unterstützung.
+@item
+Den Lizensierungs-Kram.
+@item
+Teile all der Textdateien. (Heutzutage ist nur noch die @file{README}
+übrig. Der Rest befindet sich im Handbuch.)
+@item
+Viel Testen neuer Features.
+@item
+Unser ``kostenloser'' Inhouse-Software-Anwalt.
+@item
+Derjenige, der die Mailing-Liste wartet (und nie die Zeit hatte, es richtig
+zu machen ...)
+@item
+Unser Original-Portabilitätscode (jetzt mehr als 10 Jahre alt). Heutzutage
+sind nur noch Teile von @code{mysys} übrig.
+@item
+Jemand, den Monty mitten in der Nacht anrufen kann, wenn er gerade das neue
+Feature zum Laufen gebracht hat.
+@end itemize
+
+@item Jani Tolonen
+@itemize @bullet
+@item
+@code{mysqlimport}
+@item
+Etliche Erweiterungen zum @code{mysql}-Client.
+@item
+@code{Prozeduranalyse()}
+@end itemize
+
+@item Sinisa Milivojevic
+@itemize @bullet
+@item
+Kompression (mit @code{zlib}) im Client-Server-Protokoll.
+@item
+Perfektes Hashing für die lexikalische Analyse-Phase.
+@item
+Den MySQLGUI-Client.
+@item
+Derjenige, der mysql++ wartet.
+@end itemize
+
+@item Tonu Samuel
+@itemize @bullet
+@item
+Unser Sicherheitsexperte.
+@item
+Vio-Schnittstelle (die Grundlage für das verschlüsselte Client-Server-Protokoll).
+@item
+MySQL-Dateisystem (eine Art, MySQL-Datenbanken als Dateien und
+Verzeichnisse zu benutzen).
+@item
+Den CASE-Ausdruck.
+@item
+Die MD5()- und COALESCE()-Funktionen.
+@item
+@code{RAID}-Unterstützung für @code{MyISAM}-Tabellen.
+@end itemize
+
+@item Sasha Pachev
+@itemize @bullet
+@item
+Replikation.
+@item
+@code{SHOW CREATE TABLE}.
+@item
+mod_mysql_include
+@item
+cgi++
+@item
+mysql-bench
+@end itemize
+
+@item Matt Wagner
+@itemize @bullet
+@item
+MySQL-Test-Suite.
+@item
+Unser Webmaster.
+@end itemize
+
+@item Miguel Solorzano
+@itemize @bullet
+@item
+Winmysqladmin.
+@end itemize
+
+@item Timothy Smith
+@itemize @bullet
+@item
+Dynamische Zeichen-Unterstützung.
+@item
+Verantwortlich für MySQL-configure.
+@end itemize
+
+@item Sergei Golubchik
+@itemize @bullet
+@item
+Volltextsuche.
+@item
+Fügte Schlüssel zur @code{MERGE}-Bibliothek hinzu.
+@end itemize
+
+@item Jeremy Cole
+@itemize @bullet
+@item
+
+Korrekturlesen und Editieren dieses netten Handbuchs.
+@item
+@code{ALTER TABLE ... ORDER BY ...}.
+@item
+@code{UPDATE ... ORDER BY ...}.
+@item
+@code{DELETE ... ORDER BY ...}.
+@end itemize
+
+@item John Dean
+@itemize @bullet
+@item
+Den MySQL-GUI-Client.
+@end itemize
+
+@item Indrek Siitan
+@itemize @bullet
+@item
+Designer / Programmierer unserer Web-Schnittstelle.
+@end itemize
+@end table
+
+Folgende Nicht-Entwickler arbeiten ebenfalls bei oder zusammen mit MySQL
+AB:
+
+@table @asis
+@item
+Hans Kierkegaard - verantwortlich für die MySQL-Lizenz-Handhabung.
+@item
+Antti Halonen - Vertriebsleiter.
+@item
+Jonas Norrman - Beantwortet Lizensierungsfrage, die an
+@email{info@@mysql.com} geschickt werden.
+@item
+Erik Granberg - bedient MySQL-Partner (und eine Menge sonstiger Kram).
+@item
+Allan Larsson (der BOSS für TCX DataKonsult AB).
+@end table
+
+
+@node Contributors, Supporters, Developers, Credits
+@c German node Kontributoren
+@appendixsec Kontributoren zu MySQL
+
+@cindex Kontributoren, Auflistung
+
+Während @code{MySQL AB} das gesammte Copyright für den @code{MySQL Server}
+und das @code{MySQL manual} besitzt, möchten wir hier diejenigen Menschen
+nennen, die das Ein oder Andere zur @code{MySQL Distribution} beigetragen
+haben. Die Kontributoren sind in eher zufälliger Reihenfolge aufgeführt:
+
+@table @asis
+@item Paul DuBois
+Hilft mit, das Referenzhandbuch korrekt und verständlich zu machen. Das
+beinhaltet, Montys und Davids Englischversuche in das Englisch zu
+übertragen, das andere Leute kennen.
+@item Gianmassimo Vigazzola @email{qwerg@@mbox.vol.it} oder @email{qwerg@@tin.it}
+Die ursprüngliche Portierung auf Win32/NT.
+@item Kim Aldale
+Half, Montys und Davids frühe Englischversuche ins Englische umzuschreiben.
+@item Per Eric Olsson
+Mehr oder weniger konstruktive Kritik und Testen des dynamischen
+Datensatzformats.
+@item Irena Pancirov @email{irena@@mail.yacc.it}
+Win32-Portierung mit dem Borland-Compiler. @code{mysqlshutdown.exe} und
+@code{mysqlwatch.exe}
+@item David J. Hughes
+Er bemühte sich, eine Shareware-SQL-Datenbank herzustellen. Wir bei TcX
+fingen mit @code{mSQL} an, fanden aber, dass es unsere Bedürfnisse nicht
+befriedigen könne, daher schrieben wir stattdessen eine SQL-Schnittstelle
+zu unserem Applikation-Builder Unireg. @code{mysqladmin} und @code{mysql}
+sind Programme, die stark von ihren @code{mSQL}-Pendants beeinflusst sind.
+Wir haben uns große Mühe gegeben, die MySQL-Syntax zu einer Obermenge von
+@code{mSQL} zu machen. Viele API-Ideen sind von @code{mSQL} entliehen,
+damit es einfach ist, kostenlose @code{mSQL}-Programme nach MySQL zu
+portieren. MySQL enthält keinen Code von @code{mSQL}. Zwei Dateien in der
+Distribution (@file{client/insert_test.c} und @file{client/select_test.c})
+basieren auf den entsprechenden (keinem Copyright unterliegenden) Dateien
+in der @code{mSQL}-Distribution, sind aber als Beispiele abgeändert, die
+die notwendigen Änderungen aufzeigen, wenn man Code von @code{mSQL} nach
+MySQL konvertiert. (@code{mSQL} unterliegt dem Copyright von David J. Hughes.)
+@item Fred Fish
+Seine exzellente C-Debugging- und Trace-Bibliothek. Monty hat eine Reihe
+kleinerer Verbesserungen an der Bibliothek vorgenommen (Geschwindigkeit und
+zusätzliche Optionen).
+@item Richard A. O'Keefe
+Seine Public-Domain-Zeichenketten-Bibliothek.
+@item Henry Spencer
+Seine Regex-Bibliothek, benutzt bei @code{WHERE spalte REGEXP regexp}.
+@item Free Software Foundation
+Von ihnen haben wir einen exzellenten Compiler (@code{gcc}), die
+@code{libc}-Bibliothek (aus der wir @file{strto.c} entliehen haben, damit
+einiger Code unter Linux funktioniert), und die @code{readline}-Bibliothek
+(für den @code{mysql}-Client).
+@item Free Software Foundation und das XEmacs-Entwicklungsteam
+Ihr großartiger Editor, der für fast jeden Artikeltext bei TcX/MySQL
+AB/detron benutzt wird.
+@item Patrick Lynch
+Für seine Hilfe bei @code{http://www.mysql.com/}.
+@item Fred Lindberg
+Er half, qmail aufzusetzen, um die MySQL Mailing-Liste zu handhaben, und
+für seine unglaubliche Unterstützung bei der Verwaltung der MySQL
+Mailing-Listen.
+@item Igor Romanenko @email{igor@@frog.kiev.ua}
+@code{mysqldump} (vormals @code{msqldump}, aber portiert und verbessert von
+Monty).
+@item Yuri Dario
+Er unterhält die MySQL-OS/2-Portierung und baut sie aus.
+@item Tim Bunce, Alligator Descartes
+Für die @code{DBD}-(Perl)-Schnittstelle.
+@item Tim Bunce
+Autor von @code{mysqlhotcopy}.
+@item Andreas Koenig @email{a.koenig@@mind.de}
+Für die Perl-Schnittstelle zu MySQL.
+@item Eugene Chan @email{eugene@@acenet.com.sg}
+Für den Port von PHP zu MySQL.
+@item Michael J. Miller Jr. @email{mke@@terrapin.turbolift.com}
+Er schrieb das erste MySQL-Handbuch, und nahm etliche Bereinigungen der
+Rechtschreibung / Sprache für die FAQ vor (aus dieser entstand vor langer
+Zeit das MySQL-Handbuch).
+@item Yan Cailin
+Erster Übersetzer des MySQL-Referenzhandbuch in vereinfachtes Chinesisch,
+Anfang 2000, auf der die Big5- und HK-kodierten Versionen
+(@uref{http://mysql.hitstar.com, mysql.hitstar.com}) basieren.
+@uref{http://linuxdb.yeah.net, Private Homepage bei linuxdb.yeah.net}.
+@item Giovanni Maruzzelli @email{maruzz@@matrice.it}
+Für die Portierung von iODBC (Unix ODBC).
+@item Chris Provenzano
+Portierbarer Benutzerebene-pThread. Aus dem Copyright: Dieses Produkt
+beinhaltet Software, die von Chris Provenzano, University of California,
+Berkeley und Kontributoren entwickelt wurde. Momentan benutzen wir Version
+1_60_beta6, die von Monty gepatcht wurde (siehe @file{with-pThread/Changes-mysql}).
+@item Xavier Leroy @email{Xavier.Leroy@@inria.fr}
+Der Autor von LinuxThread (benutzt von MySQL unter Linux).
+@item Zarko Mocnik @email{zarko.mocnik@@dem.si}
+Sortieren für slowenische Sprache und die @file{cset.tar.gz}-Module, die es
+vereinfachen, andere Zeichensätze hinzuzufügen.
+@item "TAMITO" @email{tommy@@valley.ne.jp}
+Die @code{_MB}-Zeichensatz-Makros und die ujis- und sjis-Zeichensätze.
+@item Joshua Chamas @email{joshua@@chamas.com}
+Grundlage für gleichzeitige Einfügeoperationen, erweiterte Datums-Syntax,
+Debuggen unter NT und Antworten in der MySQL-Mailing-Liste.
+@item Yves Carlier @email{Yves.Carlier@@rug.ac.be}
+@code{mysqlaccess}, ein Programm, das die Zugriffsrechte für einen Benutzer
+anzeigt.
+@item Rhys Stefan @email{rhys@@wales.com} (und GWE Technologies Limited)
+Für JDBC, ein Modul, um Daten aus MySQL mit einem Java-Client zu
+extrahieren.
+@item Dr. Xiaokun Kelvin ZHU @email{X.Zhu@@brad.ac.uk}
+Weiterentwicklung der JDBC-Treiber und anderer MySQL-bezogener
+Java-Werkzeuge.
+@item James Cooper @email{pixel@@organic.com}
+Aufsetzen eines durchsuchbaren Mailing-Listen-Archivs auf seiner Site.
+@item Rick Mehalick @email{Rick_Mehalick@@i-o.com}
+Für @code{xmysql}, einen grafischen X-Client für MySQL.
+@item Doug Sisk @email{sisk@@wix.com}
+Er stellt RPM-Pakete von MySQL für RedHat Linux bereit.
+@item Diemund Alexunder V. @email{axeld@@vial.ethz.ch}
+Er stelle RPM-Pakete von MySQL für RedHat Linux-Alpha bereit.
+@item Antoni Pamies Olive @email{toni@@readysoft.es}
+Er stellt RPM-Versionen vieler MySQL-Clients für Intel und SPARC bereit.
+@item Jay Bloodworth @email{jay@@pathways.sde.state.sc.us}
+Er stellte RPM-Versionen für MySQL-Version 3.21 bereit.
+@item Jochen Wiedmann @email{wiedmann@@neckar-alb.de}
+Für die Wartung der Perl-@code{DBD::mysql}-Module.
+@item Therrien Gilbert @email{gilbert@@ican.net}, Jean-Marc Pouyot @email{jmp@@scalaire.fr}
+Französische Fehlermeldungen.
+@item Petr snajdr, @email{snajdr@@pvt.net}
+Tschechische Fehlermeldungen.
+@item Jaroslaw Lewundowski @email{jotel@@itnet.com.pl}
+Polnische Fehlermeldungen.
+@item Miguel Angel Fernundez Roiz
+Spanische Fehlermeldungen.
+@item Roy-Magne Mo @email{rmo@@www.hivolda.no}
+Norwegische Fehlermeldungen und Testen von Version 3.21.#.
+@item Timur I. Bakeyev @email{root@@timur.tatarstan.ru}
+Russische Fehlermeldungen.
+@item @email{brenno@@dewinter.com} && Filippo Grassilli @email{phil@@hyppo.com}
+Italienische Fehlermeldungen.
+@item Dirk Munzinger @email{dirk@@trinity.saar.de}
+Deutsche Fehlermeldungen.
+@item Billik Stefan @email{billik@@sun.uniag.sk}
+Slowakische Fehlermeldungen.
+@item Stefan Saroiu @email{tzoompy@@cs.washington.edu}
+Rumänische Fehlermeldungen.
+@item Peter Feher
+Ungarische Fehlermeldungen.
+@item Roberto M. Serqueira
+Portugiesische Fehlermeldungen.
+@item Carsten H. Pedersen
+Dänische Fehlermeldungen
+@item David Sacerdote @email{davids@@secnet.com}
+Knowhow für die Sicherheitsprüfung von DNS-Hostnamen.
+@item Wei-Jou Chen @email{jou@@nematic.ieo.nctu.edu.tw}
+Unterstützung für chinesisch(BIG5)-Zeichen.
+@item Wei He @email{hewei@@mail.ied.ac.cn}
+Viel Funktionalität für den chinesischen (GBK-) Zeichensatz.
+@item Zeev Suraski @email{bourbon@@netvision.net.il}
+@code{FROM_UNIXTIME()}-Zeitformatierung, @code{ENCRYPT()}-Funktionen und
+@code{bison}-Ratgeber.
+Aktives Mitglied der Mailing-Liste.
+@item Luuk de Boer @email{luuk@@wxs.nl}
+Portierte (und erweiterte) die Benchmark-Suite für @code{DBI}/@code{DBD}.
+War eine große Hilfe bei @code{Crash-me} und beim Laufenlassen von
+Benchmarks. Einige neue Datumsfunktionen. Das mysql_setpermissions-Skript.
+@item Jay Flaherty @email{fty@@mediapulse.com}
+Große Teile des Perl-@code{DBI}/@code{DBD}-Abschnitts im Handbuch.
+@item Paul Southworth @email{pauls@@etext.org}, Ray Loyzaga @email{yar@@cs.su.oz.au}
+Korrekturlesen des Referenzhandbuchs.
+@item Alexis Mikhailov @email{root@@medinf.chuvashia.su}
+Benutzerdefinierte Funktionen (UDFs); @code{CREATE FUNCTION} und
+@code{DROP FUNCTION}.
+@item Andreas F. Bobak @email{bobak@@relog.ch}
+Die @code{AGGREGATE}-Erweiterung für UDF-Funktionen.
+@item Ross Wakelin @email{R.Wakelin@@march.co.uk}
+Half, InstallShield für MySQL-Win32 aufzusetzen.
+@item Jethro Wright III @email{jetman@@li.net}
+Die @file{libmysql.dll}-Bibliothek.
+@item James Pereria @email{jpereira@@iafrica.com}
+Mysqlmanager, ein grafisches Win32-Werkzeug für die Administration von MySQL.
+@item Curt Sampson @email{cjs@@portal.ca}
+Portierung von MIT-pThread auf NetBSD/Alpha und NetBSD 1.3/i386.
+@item Antony T. Curtis @email{antony.curtis@@olcs.net}
+Portiierung von MySQL auf OS/2.
+@item Martin Ramsch @email{m.ramsch@@computer.org}
+Beispiele im MySQL-Tutorial.
+@item Steve Harvey
+Er machte @code{mysqlaccess} sicherer.
+@item Konark IA-64 Centre of Persistent Systems Private Limited
+@uref{http://www.pspl.co.in/konark/}. Hilfe bei der Win64-Portierung des
+MySQL-Servers.
+@item Albert Chin-A-Young.
+Configure-Aktualisierungen für Tru64, Unterstützung großer Dateien und
+verbesserte Unterstützung von TCP-Wrappern.
+@item John Birrell
+Emulation von pthread_mutex() für OS/2.
+@item Benjamin Pflugmann
+Erweiterte @code{MERGE}-Tabellen, so dass sie @code{INSERTS} handhaben.
+Aktives Mitglied der MySQL-Mailing-Listen.
+@end table
+
+Andere Kontributoren, Bug-Finder und Tester: James H. Thompson, Maurizio
+Menghini, Wojciech Tryc, Luca Berra, Zarko Mocnik, Wim Bonis, Elmar
+Haneke, @email{jehamby@@lightside}, @email{psmith@@BayNetworks.com},
+@email{duane@@connect.com.au}, Ted Deppner @email{ted@@psyber.com},
+Mike Simons, Jaakko Hyvatti.
+
+Und viele Bug-Berichte und Patches von den Leuten auf der Mailing-Liste.
+
+Große Anerkennung zollen wir denjenigen, die uns halfen, Fragen auf der
+@code{mysql@@lists.mysql.com}-Mailing-Liste zu beantworten:
+
+@table @asis
+@item Daniel Koch @email{dkoch@@amcity.com}
+Irix-Setup.
+@item Luuk de Boer @email{luuk@@wxs.nl}
+Benchmark-Fragen.
+@item Tim Sailer @email{tps@@Benutzer.buoy.com}
+@code{DBD-mysql}-Fragen.
+@item Boyd Lynn Gerber @email{gerberb@@zenez.com}
+SCO-bezogene Fragen.
+@item Richard Mehalick @email{RM186061@@shellus.com}
+@code{xmysql}-bezogene Fragen und grundsätzliche Installationsfragen.
+@item Zeev Suraski @email{bourbon@@netvision.net.il}
+Fragen zur Apache-Modul-Konfiguration (log & auth), PHP-bezogene Fragen,
+SQL-Syntax-bezogene Fragen und andere allgemeine Fragen.
+@item France Guasch @email{frankie@@citel.upc.es}
+Allgemeine Fragen.
+@item Jonathan J Smith @email{jsmith@@wtp.net}
+Fragen zu Betriebssystem-spezifschen Dingen bei Linux, SQL-Syntax- und
+andere Dinge, die etwas Überarbeitung bedürfen.
+@item David Sklar @email{sklar@@student.net}
+MySQL von PHP und Perl aus benutzen.
+@item Alistair MacDonald @email{A.MacDonald@@uel.ac.uk}
+Noch nicht festgelegt, aber er ist flexibel und kann Linux und vielleicht
+HP-UX handhaben. Wird versuchen, Benutzer dazu zu bringen, @code{mysqlbug}
+zu benutzen.
+@item John Lyon @email{jlyon@@imag.net}
+Fragen zur Installation von MySQL auf Linux-Systemen, entweder mit
+@file{.rpm}-Dateien oder durch Kompilieren vom Quelltext.
+@item Lorvid Ltd. @email{lorvid@@WOLFENET.com}
+Einfache Fragen zu Rechnung / Lizenz / Support / Copyright.
+@item Patrick Sherrill @email{patrick@@coconet.com}
+Fragen zur ODBC- und VisualC++-Schnittstelle.
+@item Rundy Harmon @email{rjharmon@@uptimecomputers.com}
+@code{DBD}, Linux, und einige SQL-Syntax-Fragen.
+@end table
+
+
+@node Supporters, , Contributors, Credits
+@c German node Unterstützer
+@appendixsec Unterstützer von MySQL
+
+@cindex Unterstützende Unternehmen, Auflistung
+
+Während @code{MySQL AB} das gesammte Copyright für den @code{MySQL Server}
+und das @code{MySQL manual} besitzt, möchten wir hier diejenigen Unternehmen
+nennen, die die Entwicklung des @code{MySQL Servers} unterstützt haben.
+Sie haben geholfen, indem sie uns für die Entwicklung eines neuen
+Features bezahlten, indem sie MySQL-Features selbst entwickelten oder indem
+sie uns Hardware für die MySQL-Entwicklung gaben.
+
+@table @asis
+@item VA Linux / Andover.net
+Stiftete Replikation.
+@item NuSphere
+Editieren des MySQL-Referenzhandbuchs.
+@item Stork Design studio
+Die MySQL-Website zwischen 1998 und 2000.
+@item Intel
+Trugen zur Entwicklung auf Windows- und Linux-Plattformen bei.
+@item Compaq
+Trugen zur Entwicklung auf Linux/Alpha bei.
+@item SWSoft
+Entwicklung der eingebetteten @code{mysqld}-Version.
+@item FutureQuest
+@code{--skip-show-variables}
+@end table
+
+
+
+
+@node News, Porting, Credits, Top
+@c German node Neuigkeiten
+@appendix MySQL-Änderungsverlauf (Change History)
+
+@cindex ChangeLog
+@cindex Änderungen, Log
+@cindex Log, Änderungen
+
+Dieser Anhang listet die Änderungen von Version zu Version im
+MySQL-Quellcode auf.
+
+Beachten Sie, dass wir versuchen, das Handbuch zeitgleich mit den
+Änderungen an MySQL zu aktualisieren. Wenn Sie unten eine Version
+aufgelistet sehen, die Sie auf der
+@uref{http://www.mysql.com/downloads/,MySQL-Download-Seite} nicht finden
+können, heißt das, dass die Version noch nicht veröffentlicht wurde!
+
+
+
+@menu
+* News-4.0.x::
+* News-3.23.x::
+@end menu
+
+@node News-4.0.x, News-3.23.x, News, News
+@c German node Neuigkeiten-4.0.x
+@appendixsec Änderungen in Release 4.0.x (Entwicklung; Alpha)
+
+Wir arbeiten mittlerweile aktiv an MySQL 4.0 und werden nur noch kritische
+Bug-Bereinigungen für MySQL 3.23 herausgeben. Wir aktualisieren diesen
+Abschnitt, wenn wir neue Features hinzufügen, so dass andere unserer
+Entwicklung folgen können.
+
+Unser TODO-Abschnitt enthält, was wir für 4.0 planen. @xref{TODO}.
+
+@cindex Änderungen, Version 4.0
+
+
+@menu
+* News-4.0.2::
+* News-4.0.1::
+* News-4.0.0::
+@end menu
+
+@node News-4.0.2, News-4.0.1, News-4.0.x, News-4.0.x
+@c German node Neuigkeiten-4.0.2
+@appendixsubsec Änderungen in Release 4.0.2
+
+@itemize @bullet
+@item
+Bug in @code{FLUSH QUERY CACHE} behoben.
+@item
+@code{CAST()}- und @code{CONVERT()}-Funktionen hinzugefügt.
+@item
+Reihenfolge geändert, wie Schlüssel in Tabellen erzeugt werden.
+@item
+Neue Spalten @code{Null} und @code{Index_type} zu @code{SHOW INDEX}
+hinzugefügt.
+@end itemize
+
+@node News-4.0.1, News-4.0.0, News-4.0.2, News-4.0.x
+@c German node Neuigkeiten-4.0.1
+@appendixsubsec Änderungen in Release 4.0.1
+
+@itemize @bullet
+@item
+Bug behoben, wenn @code{HANDLER} mit einem nicht unterstützten Tabellentyp
+verwendet wurde.
+@item
+@code{mysqldump} schreibt jetzt @code{ALTER TABLE tabelle DISABLE KEYS} und
+@code{ALTER TABLE tabelle DISABLE KEYS} in den SQL-Dump.
+@item
+@code{mysql_fix_extensions}-Skript hinzugefügt.
+@item
+Stack-Überlaufproblem @code{LOAD DATA FROM MASTER} auf OSF1 behoben.
+@item
+Herunterfahr-Problem auf HPUX behoben.
+@item
+Funktionen @code{des_encrypt()} und @code{des_decrypt()} hinzugefügt.
+@item
+Statement FLUSH DES_KEY_FILE hinzugefügt.
+@item
+mysqld-Option @code{--des-key-file} hinzugefügt.
+@item
+@code{HEX(string)} gibt jetzt die Buchstaben in der Zeichenkette
+konvertiert in hexadezimal zurück.
+@item
+Problem mit @code{GRANT} bei der Benutzung von @code{lower_case_tables ==
+1} behoben.
+@item
+@code{SELECT ... IN SHARE MODE} in @code{SELECT .. LOCK IN SHARE MODE} (wie
+in MySQL 3.23) geändert.
+@item
+Ein neuer Anfragen-Cache, der Ergebnisse identischer @code{SELECT}-Anfragen
+zwischenspeichert.
+@item
+Coredump-Bug auf 64-Bit-Maschinen beim Erhalt eines falschen
+Kommunikationspakets behoben.
+@item
+@code{MATCH ... AGAINST(... IN BOOLEAN MODE)} funktioniert jetzt auch ohne
+@code{FULLTEXT}-Index.
+@item
+Slave, der vom 3.23-Master repliziert, in Ordnung gebracht.
+@item
+Diverse Replikationsprobleme behoben / bereinigt.
+@item
+Herunterfahren funktioniert jetzt auf Mac OS X.
+@item
+@file{myisam/ft_dump}-Werkzeug zur Low-Level-Inspektion von
+@code{FULLTEXT}-Indexen hinzugefügt.
+@item
+Bug in @code{DELETE ... WHERE ... MATCH ...} behoben.
+@item
+Unterstützung für @code{MATCH ... AGAINST(... IN BOOLEAN MODE)}
+hinzugefügt. @strong{Hinweis: Sie müssen Ihre Tabellen mit
+@code{ALTER TABLE tabelle TYPE=MyISAM} neu aufbauen, um Boole'sche
+Volltextsuche benutzen zu können.}
+@item
+@code{LOCATE()} und @code{INSTR()} sind abhängig von der verwendeten
+Groß-/Kleinschreibung, wenn keins der Argumente eine binäre Zeichenkette
+ist.
+@item
+@code{RND()}-Initialisierung geändert, so dass @code{RND(N)} und
+@code{RND(N+1)} verschiedener sind.
+@item
+Coredump-Bug in @code{UPDATE ... ORDER BY} behoben.
+@item
+@code{INSERT INTO .. SELECT} geändert, damit es bei Fehlern vorgabemäßig
+anhält.
+@item
+@code{DATA DIRECTORY}- und @code{INDEX DIRECTORY}-Anweisungen werden unter
+Windows ignoriert.
+@item
+Boole'sche Volltextsuche hinzugefügt. Diese sollte als frühe Alphaversion
+betrachtet werden.
+@item
+@code{MODIFY} und @code{CHANGE} in @code{ALTER TABLE} erweitert, damit sie
+das @code{AFTER}-Schlüsselwort akzeptieren.
+@item
+Index wird jetzt in @code{ORDER BY} von einer ganzen InnoDB-Tabelle
+verwendet.
+@end itemize
+
+@node News-4.0.0, , News-4.0.1, News-4.0.x
+@c German node Neuigkeiten-4.0.0
+@appendixsubsec Änderungen in Release 4.0.0
+
+@itemize @bullet
+@item
+Variablen @code{ft_min_word_len}, @code{ft_max_word_len} und
+@code{ft_max_word_len_for_sort} hinzugefügt.
+@c German FIX removed extra @itemize @bullet from right here
+@item
+Dokumentation für @code{libmysqld}, die eingebettete
+MySQL-Server-Bibliothek, hinzugefügt. Beispielprogramme (ein
+@code{mysql}-Client und @code{mysqltest}-Testprogramm) hinzugefügt, die
+@code{libmysqld} benutzen.
+@item
+@code{my_thread_init()} und @code{my_thread_end()} aus mysql_com.h entfernt
+und @code{mysql_thread_init()} und @code{mysql_thread_end()} zu mysql.h
+hinzugefügt.
+@item
+Vorzeichenlose @code{BIGINT}-Konstanten funktionieren jetzt. @code{MIN()}
+und @code{MAX()} handhabt vorzeichenbehaftete und vorzeichenlose
+@code{BIGINT}-Zahlen korrekt.
+@item
+Neuer Zeichensatz @code{latin_de}, der korrektes deutsches Sortieren
+ermöglicht.
+@item
+@code{TRUNCATE TABLE} und @code{DELETE FROM tabelle} sind jetzt separate
+Funktionen. Ein Vorteil davon ist, dass @code{DELETE FROM tabelle} jetzt
+die Anzahl gelöschter Zeilen zurückgibt.
+@item
+@code{DROP DATABASE} führt jetzt ein @code{DROP TABLE} auf alle Tabellen in
+der Datenbank aus, was ein Problem mit InnoDB-Tabellen behebt.
+@item
+Unterstützung für @code{UNION} hinzugefügt.
+@item
+Eine neue @code{HANDLER}-Schnittstelle zu @code{MyISAM}-Tabellen.
+@item
+Unterstützung für @code{INSERT} auf @code{MERGE}-Tabellen hinzugefügt.
+Patch von Benjamin Pflugmann.
+@item
+@code{WEEK(#,0)} dem Kalender in den USA angepasst.
+@item
+@code{COUNT(DISTINCT)} ist etwa 30% schneller.
+@item
+Alle internen Listen-Handlings in der Geschwindigkeit verbessert.
+@item
+Das Erzeugen von Volltext-Indexen ist jetzt viel schneller.
+@item
+Baum-ähnlicher Cache, um Massen-Einfügevorgänge und die
+@code{myisam_bulk_insert_tree_size}-Variable zu beschleunigen.
+@item
+Suchen auf komprimierten (@code{CHAR}/@code{VARCHAR})-Schlüsseln ist jetzt
+viel schneller.
+@item
+Anfragen folgenden Typs optimiert:
+@code{SELECT DISTINCT * from tabelle ORDER by schluessel_teil1 LIMIT #}
+@item
+@code{SHOW CREATE TABLE} zeigt jetzt alle Tabellenattribute.
+@item
+@code{ORDER BY ... DESC} kann jetzt Schlüssel benutzen.
+@item
+@code{LOAD DATA FROM MASTER} setzt jetzt "auto-magisch" einen Slave auf.
+@item
+@code{safe_mysqld} in @code{mysqld_safe} umbenannt.
+@item
+Unterstützung für symbolische Links auf @code{MyISAM}-Tabellen hinzugefügt.
+Symlink-Handhabung ist jetzt vorgabemäßig für Windows aktiviert.
+@item
+@code{LOAD DATA FROM MASTER} setzt "auto-magisch" einen Slave auf.
+@item
+@code{SQL_CALC_FOUND_ROWS} und @code{FOUND_ROWS()} hinzugefügt. Das
+ermöglicht es herauszufinden, wie viele Zeilen eine Anfrage ohne eine
+@code{LIMIT}-Klausel zurückgegeben hätte.
+@item
+Ausgabeformat von @code{SHOW OPEN TABLES} geändert.
+@item
+@code{SELECT ausdruck LIMIT ...} wird zugelassen.
+@item
+@code{IDENTITY} als Synonym für @code{AUTO_INCREMENT} hinzugefügt (wie
+Sybase).
+@item
+@code{ORDER BY}-Syntax zu @code{UPDATE} und @code{DELETE} hinzugefügt.
+@item
+@code{SHOW INDEXES} ist jetzt ein Synonym für @code{SHOW INDEX}.
+@item
+@code{ALTER TABLE tabelle DISABLE KEYS}- und @code{ALTER TABLE tabelle
+ENABLE KEYS}-Befehle hinzugefügt.
+@item
+@code{IN} kann anstelle von @code{FROM} in @code{SHOW}-Befehlen benutzt
+werden.
+@item
+ANSI-SQL-Syntax @code{X'Hexadezimalzahl'} wird zugelassen.
+@item
+Globale Sperr-Handhabung für @code{FLUSH TABLES with READ LOCK} aufgeräumt.
+@item
+Problem mit @code{DATETIME = constant} in @code{WHERE}-Optimierungen
+behoben.
+@end itemize
+
+
+@node News-3.23.x, , News-4.0.x, News
+@c German node Neuigkeiten-3.23.x
+@appendixsec Änderungen in Release 3.23.x (Stabil)
+
+@cindex changes, version 3.23
+
+Das 3.23-Release hat etliche wichtige Features, die in früheren Versionen
+nicht vorhanden sind. Es wurden drei neue Tabellentypen hinzugefügt:
+
+@table @asis
+@item @strong{MyISAM}
+Eine neue ISAM-Bibliothek, die auf SQL und Unterstützung großer Dateien
+abgestimmt ist.
+@item @strong{BerkeleyDB} oder @strong{BDB}
+Benutzt die Berkeley-DB-Bibliothek von Sleepycat Software, um
+transaktionssichere Tabellen zu implementieren.
+@item @strong{InnoDB}
+Ein transaktionssicherer Tabellen-Handler, der Sperren auf Zeilenebene und
+viele Oracle-ähnliche Features unterstützt.
+@end table
+
+Beachten Sie, dass nur MyISAM in der Standard-Binärdistribution verfügbar
+ist.
+
+Das 3.23-Release beinhaltet ausserdem Unterstützung für
+Datenbank-Replikation zwischen einem Master und vielen Slaves,
+Volltext-Indexierung und vieles mehr.
+
+Alle neuen Features werden in der 4.0-Version weiter entwickelt. Nur
+Bug-Behebungen und kleinere Verbesserungen bestehender Features werden zu
+3.23 hinzugefügt.
+
+Der Replikationscode und der BerkeleyDB-Code sind noch nicht so gut
+getestet wie der Rest des Codes, daher wird es wahrscheinlich zukünftig
+noch einige Releases von 3.23 mit kleineren Behebungen für diesen Teil des
+Codes geben. Solange Sie diese Features nicht benutzen, sollten Sie mit
+MySQL 3.23 auf der sicheren Seite liegen!
+
+Beachten Sie, dass das Gesagte nicht heißt, dass Replikation oder Berkeley
+DB nicht funktionieren. Wir haben den gesamten Code ausgiebig getestet,
+inklusive Replikation und BDB, ohne irgend welche Probleme zu finden. Es
+heißt nur, dass nicht so viele Benutzer diesen Code verwenden wie den Rest
+des Codes, weshalb wir noch nicht 100% auf diesen Teil des Codes vertrauen.
+
+
+@menu
+* News-3.23.43::
+* News-3.23.42::
+* News-3.23.41::
+* News-3.23.40::
+* News-3.23.39::
+* News-3.23.38::
+* News-3.23.37::
+* News-3.23.36::
+* News-3.23.35::
+* News-3.23.34a::
+* News-3.23.34::
+* News-3.23.33::
+* News-3.23.32::
+* News-3.23.31::
+* News-3.23.30::
+* News-3.23.29::
+* News-3.23.28::
+* News-3.23.27::
+* News-3.23.26::
+* News-3.23.25::
+* News-3.23.24::
+* News-3.23.23::
+* News-3.23.22::
+* News-3.23.21::
+* News-3.23.20::
+* News-3.23.19::
+* News-3.23.18::
+* News-3.23.17::
+* News-3.23.16::
+* News-3.23.15::
+* News-3.23.14::
+* News-3.23.13::
+* News-3.23.12::
+* News-3.23.11::
+* News-3.23.10::
+* News-3.23.9::
+* News-3.23.8::
+* News-3.23.7::
+* News-3.23.6::
+* News-3.23.5::
+* News-3.23.4::
+* News-3.23.3::
+* News-3.23.2::
+* News-3.23.1::
+* News-3.23.0::
+@end menu
+
+@node News-3.23.43, News-3.23.42, News-3.23.x, News-3.23.x
+@c German node Neuigkeiten-3.23.43
+@appendixsubsec Änderungen in Release 3.23.43
+@itemize @bullet
+@item
+Bug behoben, der mit sehr geringer Wahrscheinlichkeit auftritt, der keine
+übereinstimmenden Zeilen zurückgab bei SELECT mit vielen Tabellen,
+mehrspaltigen Indexen und 'Bereichs-'-Typen.
+@item
+Coredump-Bug behoben, der mit sehr geringer Wahrscheinlichkeit auftritt,
+wenn man @code{EXPLAIN SELECT} mit vielen Tabellen und @code{ORDER BY}
+ausführt.
+@item
+Bug in @code{LOAD DATA FROM MASTER} bei der Benutzung einer Tabelle mit
+@code{CHECKSUM=1} behoben.
+@item
+Eindeutige Fehlermeldung hinzugefügt, die man bei einer Blockierung
+(Deadlock) während einer Transaktion mit BDB-Tabellen erhält.
+@item
+Problem mit @code{BDB}-Tabellen und @code{UNIQUE}-Spalten, die als
+@code{NULL} definiert wurden, behoben.
+@item
+Problem mit @code{myisampack} bei der Benutzung von CHAR-Spalten, die
+Leerzeichen aufgefüllt wurden, behoben.
+@item
+Patch von Yuri Dario für OS2 angewandt.
+@item
+Bug in @code{--safe-user-create} behoben.
+@end itemize
+
+@node News-3.23.42, News-3.23.41, News-3.23.43, News-3.23.x
+@c German node Neuigkeiten-3.23.42
+@appendixsubsec Änderungen in Release 3.23.42
+@itemize @bullet
+@item
+Problem bei der Benutzung von @code{LOCK TABLES} und @code{BDB}-Tabellen
+behoben.
+@item
+Problem mit @code{REPAIR TABLE} auf MyISAM-Tabellen mit Zeilenlängen
+zwischen 65517 und 65520 Bytes behoben.
+@item
+Seltenen Hänger bei @code{mysqladmin shutdown} behoben, wenn es viel
+Aktivität auf einem anderen Thread gab.
+@item
+Problem mit @code{INSERT DELAYED} behoben, bei dem ein verzögerter Thread
+auf @code{Upgrade locks} ohne ersichtlichen Grund hängen konnte.
+@item
+Problem mit @code{myisampack} und @code{BLOB} behoben.
+@item
+Problem beim Editieren von @code{.MRG}-Tabellen von Hand behoben.
+(Patch von Benjamin Pflugmann).
+@item
+Es wird erzwungen, dass alle Tabellen in einer @code{MERGE}-Tabelle von
+derselben Datenbank kommen.
+@item
+Bug mit @code{LOAD DATA INFILE} und transaktionalen Tabellen behoben.
+@item
+Bug bei der Benutzung von @code{INSERT DELAYED} mit falschen
+Spaltendefinitionen behoben.
+@item
+Coredump während @code{REPAIR} besonders beschädigter Tabellen behoben.
+@item
+Bug in @code{InnoDB}- und @code{AUTO_INCREMENT}-Spalten behoben.
+@item
+Bug in @code{InnoDB} und @code{RENAME TABLE}-Spalten behoben.
+@item
+Kritischer Bug in @code{InnoDB}- und @code{BLOB}-Spalten behoben. Wenn man
+@code{BLOB}-Spalten größer als 8000 Bytes in einer @code{InnoDB}-Tabelle
+benutzte, musste man die Tabelle mit @code{mysqldump} sichern, löschen und
+aus dem Dump neu aufbauen.
+@item
+Großen Patch für OS/2 von Yuri Dario angewandt.
+@item
+Problem mit @code{InnoDB} behoben, bei dem man den Fehler @code{Can't
+execute the given command...} bekommen konnte, selbst wenn man keine aktive
+Transaktion hatte.
+@item
+Einige kleine Probleme behoben, die Gemini betrafen.
+@item
+Echte arithmetische Operationen werden selbst dann in einem
+Ganzzahl-Zusammenhang benutzt, wenn nicht alle Argumente Ganzzahlen sind.
+(Behebt einen wenig häufigen Bug in einigen Ganzzahl-Kontexten.)
+@item
+Unter Windows wird nicht alles in Kleinschreibung erzwungen (um ein Problem
+mit Windows und @code{ALTER TABLE} zu beheben). @code{--lower_case_names}
+funktioniert jetzt auch unter Unix.
+@item
+Automatisches Rollback behoben, das ausgeführt wurde, wenn das Beenden
+eines Threads keinen anderen Thread blockiert.
+@end itemize
+
+@node News-3.23.41, News-3.23.40, News-3.23.42, News-3.23.x
+@c German node Neuigkeiten-3.23.41
+@appendixsubsec Änderungen in Release 3.23.41
+
+@itemize @bullet
+@item
+Option @code{--sql-mode=option[,option[,option]]} hinzugefügt.
+@xref{Command-line options}.
+@item
+Mögliches Problem mit @code{shutdown} auf Solaris behoben, wobei die
+@file{.pid}-Datei nicht gelöscht wurde.
+@item
+InnoDB unterstützt jetzt Zeilen < 4 GB. Die vorherige Beschränkung war
+8.000 Bytes.
+@item
+Die @code{doublewrite}-Datei-Flush-Methode wird in InnoDB benutzt. Sie
+reduziert die Notwendigkeit von Unix-fsync-Aufrufen auf einen Bruchteil und
+verbessert die Performance auf den meisten Unix-Varianten.
+@item
+Sie können jetzt den InnoDB-Monitor benutzen, um etliche Informationen über
+den InnoDB-Status auf die Standardausgabe auszugeben, inklusive Sperren.
+Nützlich zum Tunen der Performance.
+@item
+Mehrere Bugs, die in InnoDB Hänger verursachen konnten, behoben.
+@item
+@code{record_buffer} in @code{record_buffer} und @code{record_rnd_buffer}
+aufgeteilt. Um zu vorherigen MySQL-Versionen kompatibel zu bleiben, wird
+@code{record_rnd_buffer} auf den Wert von @code{record_buffer} gesetzt,
+wenn es nicht explizit gesetzt wird.
+@item
+Optimierungs-Bug in @code{ORDER BY} behoben, bei dem einige @code{ORDER
+BY}-Teile fälschlicherweise entfernt wurden.
+@item
+Overflow-Bug bei @code{ALTER TABLE} und @code{MERGE}-Tabellen behoben.
+@item
+Prototypen für @code{my_thread_init()} und @code{my_thread_end()} zu
+@file{mysql_com.h} hinzugefügt.
+@item
+Option @code{--safe-user-create} to @code{mysqld} hinzugefügt.
+@item
+Bug in @code{SELECT DISTINCT ... HAVING} behoben, der die Fehlermeldung
+@code{Can't find record in '#...} verursachte.
+@end itemize
+
+
+@node News-3.23.40, News-3.23.39, News-3.23.41, News-3.23.x
+@c German node Neuigkeiten-3.23.40
+@appendixsubsec Änderungen in Release 3.23.40
+
+@itemize @bullet
+@item
+Problem mit @code{--low-priority-updates} und @code{INSERT}'s behoben.
+@item
+Bug im Slave-Thread beseitigt, bei dem dieser in seltenen Fällen um 22 Byte
+vor den Offset im Master kommen konnte.
+@item
+@code{slave_wait_timeout} für Replikation hinzugefügt.
+@item
+Problem mit @code{UPDATE} und @code{BDB}-Tabellen behoben.
+@item
+Problematischen Bug in @code{BDB}-Tabellen behoben, der bei der Benutzung
+von Schlüsselteilen auftrat.
+@item
+Problem bei der Benutzung von @code{GRANT FILE ON datenbank.* ...} behoben.
+Vorher wurde die @code{DROP}-Berechtigung für die Datenbank hinzugefügt.
+@item
+Bug bei @code{DELETE FROM tabelle ... LIMIT 0} und @code{UPDATE FROM
+tabelle ... LIMIT 0} behoben, die sich vorher so verhielten, als gäbe es
+keine @code{LIMIT}-Klausel (sie löschten oder aktualisierten alle
+ausgewählten Zeilen).
+@item
+@code{CHECK TABLE} prüft jetzt, ob eine @code{AUTO_INCREMENT}-Spalte den
+Wert 0 enthält.
+@item
+Wenn man @code{SIGHUP} an @code{mysqld} schickt, werden jetzt nur die Logs
+auf Platte zurückgeschrieben (flush), nicht die Replikation zurückgesetzt.
+@item
+Parser in Ordnung gebracht, so dass er jetzt Fließkommazahlen des Typs
+@code{1.0e1} (kein Vorzeichen nach @code{e}) zuläßt.
+@item
+Option @code{--force} für @code{myisamchk} aktualisiert jetzt auch Zustände
+(Status).
+@item
+Option @code{--warnings} für @code{mysqld} hinzugefügt. @code{mysqld} gibt
+jetzt nur den Fehler @code{Aborted connection} aus, wenn diese Option
+benutzt wird.
+@item
+Problem mit @code{SHOW CREATE TABLE} behoben, wenn man keinen @code{PRIMARY
+KEY} hatte.
+@item
+Saubere Behebung der Umbenennung von @code{innodb_unix_file_flush_method}
+in @code{innodb_flush_method}.
+@item
+Bug beim Umwandeln von @code{UNSIGNED BIGINT} in @code{DOUBLE} behoben.
+Dieser verursachte bei Vergleichen mit @code{BIGINT}-Werten ausserhalb des
+vorzeichenbehafteten Bereichs ein Problem.
+@item
+Bug in @code{BDB}-Tabellen behoben, wenn man leere Tabellen abfragte.
+@item
+Bug bei der Benutzung von @code{COUNT(DISTINCT)} mit @code{LEFT JOIN}
+behoben, wenn es keine übereinstimmenden Zeilen gab.
+@item
+Alle Dokumentation bezüglich @code{GEMINI}-Tabellen entfernt. @code{GEMINI}
+wird nicht unter einer Open-Source-Lizenz herausgegeben.
+@end itemize
+
+
+@node News-3.23.39, News-3.23.38, News-3.23.40, News-3.23.x
+@c German node Neuigkeiten-3.23.39
+@appendixsubsec Änderungen in Release 3.23.39
+
+@itemize @bullet
+@item
+Die @code{AUTO_INCREMENT}-Zahlenfolge wurde beim Löschen und Hinzufügen
+einer @code{AUTO_INCREMENT}-Spalte nicht zurückgesetzt.
+@item
+@code{CREATE ... SELECT} erzeugt jetzt nicht eindeutige Indexe verzögert.
+@item
+Problem behoben, bei dem @code{LOCK TABLES tabelle READ} gefolgt von
+@code{FLUSH TABLES} eine exklusive Sperre auf die Tabelle setzte.
+@item
+@code{REAL}-@@Variablen wurden mit 2 Ziffern dargestellt, wenn sie in
+Zeichenketten umgewandelt wurden.
+@item
+Problem mit hängendem Client behoben, wenn @code{LOAD TABLE FROM MASTER}
+fehlschlug.
+@item
+@code{myisamchk --fast --force} repariert jetzt keine Tabellen mehr, bei
+denen nur der Öffnen-Zähler falsch ist.
+@item
+Funktionen zur Handhabung von symbolischen Links hinzugefügt, um sich das
+Leben in Version 4.0 zu erleichtern.
+@item
+Wir benutzen jetzt die @code{-lcma}-Thread-Bibliothek unter HP-UX 10.20, so
+dass MySQL auf HP-UX stabiler läuft.
+@item
+Problem mit @code{IF()} und Anzahl von Dezimalstellen im Ergebnis behoben.
+@item
+Funktionen zum Extrahieren von Datumsanteilen in Ordnung gebracht, so dass
+sie jetzt mit Datumsangaben funktionieren, bei denen Tag und / oder Monat 0
+sind.
+@item
+Argumentlänge in Optionsdateien von 256 auf 512 Zeichen erweitert.
+@item
+Problem bei Herunterfahren, wenn @code{INSERT DELAYED} auf ein @code{LOCK
+TABLE} wartete, behoben.
+@item
+Coredump-Bug in InnoDB behoben, wenn der Tabellenplatz (Tablespace) voll
+war.
+@item
+Problem mit @code{MERGE}-Tabellen und großen Tabellen (> 4 GB) und der
+Benutzung von @code{ORDER BY} behoben.
+@end itemize
+
+
+@node News-3.23.38, News-3.23.37, News-3.23.39, News-3.23.x
+@c German node Neuigkeiten-3.23.38
+@appendixsubsec Änderungen in Release 3.23.38
+
+@itemize @bullet
+@item
+Bug behoben, bei dem @code{SELECT} von @code{MERGE}-Tabellen manchmal zu
+falsch sortierten Zeilen führte.
+@item
+Bug in @code{REPLACE()} bei der Benutzung des ujis-Zeichensatzes behoben.
+@item
+Sleepycat-BDB-Patches 3.2.9.1 und 3.2.9.2 angewandt.
+@item
+Option @code{--skip-stack-trace} zu @code{mysqld} hinzugefügt.
+@item
+@code{CREATE TEMPORARY} funktioniert jetzt mit @code{InnoDB}-Tabellen.
+@item
+@code{InnoDB} zieht jetzt Teile von Schlüsseln (Sub-Keys) ganzen Schlüsseln
+vor.
+@item
+Option @code{CONCURRENT} für @code{LOAD DATA} hinzugefügt.
+@item
+Bessere Fehlermeldung, wenn die Slave-@code{max_allowed_packet}-Variable zu
+niedrig ist, um ein sehr langes Log-Ereignis vom Master zu lesen.
+@item
+Bug behoben, wenn zu viele Zeilen bei der Benutzung von @code{SELECT
+DISTINCT ... HAVING} entfernt wurden.
+@item
+@code{SHOW CREATE TABLE} gibt jetzt @code{TEMPORARY} für temporäre Tabellen
+zurück.
+@item
+@code{Rows_examined} für Langsame-Anfragen-Log-Datei hinzugefügt.
+@item
+Probleme mit Funktion behoben, die eine leere Zeichenkette zurückgab, wenn
+sie zusammen mit einer Gruppenfunktion und einem @code{WHERE} benutzt
+wurde, das keine Zeilenübereinstimmung ergab.
+@item
+Neues Programm @code{mysqlcheck}.
+@item
+Datenbankname zur Ausgabe für administrative Befehle wie @code{CHECK},
+@code{REPAIR}, @code{OPTIMIZE} hinzugefügt.
+@item
+Viele Portabilitätsbehebungen für InnoDB.
+@item
+Optimierer geändert, so dass Anfragen wie @code{SELECT * FROM
+tabelle,tabelle2 ... ORDER BY schluessel_teil1 LIMIT #} den Index auf
+@code{schluessel_teil1} anstelle von @code{filesort} benutzen.
+@item
+Bug bei der Ausführung von @code{LOCK TABLE to_table WRITE,...; INSERT INTO
+to_table... SELECT ...} behoben, wenn @code{to_table} leer war.
+@item
+Bug mit @code{LOCK TABLE} und BDB-Tabellen behoben.
+@end itemize
+
+
+@node News-3.23.37, News-3.23.36, News-3.23.38, News-3.23.x
+@c German node Neuigkeiten-3.23.37
+@appendixsubsec Änderungen in Release 3.23.37
+
+@itemize @bullet
+@item
+Bug bei der Benutzung von @code{MATCH} in @code{HAVING}-Klausel.
+@item
+Bug bei der Benutzung von @code{HEAP}-Tabellen mit @code{LIKE} behoben.
+@item
+@code{--mysql-version} für @code{safe_mysqld} hinzugefügt.
+@item
+@code{INNOBASE} in @code{InnoDB} geändert (weil der @code{INNOBASE}-Name
+bereits benutzt wurde). Alle @code{configure}-Optionen und
+@code{mysqld}-Startoptionen benutzen jetzt @code{innodb} anstelle von
+@code{innobase}. Das heißt, dass Sie jegliche Konfigurationsdateien, in
+denen Sie @code{innobase}-Optionen benutzt haben, ändern müssen, bevor Sie
+auf diese Version aktualisieren!
+@item
+Bug bei der Benutzung von Indexen auf @code{CHAR(255) NULL}-Spalten
+behoben.
+@item
+Slave-Thread wird jetzt auch dann gestartet, wenn @code{master-host} nicht
+gesetzt ist, so lange @code{server-id} gesetzt wird und es eine gültige
+@code{master.info} gibt.
+@item
+Teilweise Aktualisierungen (beendet mit kill) werden jetzt mit einem
+speziellen Fehler-Code in die Binär-Log-Datei geschrieben. Der Slave
+weigert sich, sie auszuführen, wenn der Fehler-Code anzeigt, dass die
+Aktualisierung abnorm beendet wurde, und muss mit @code{SET
+SQL_SLAVE_SKIP_COUNTER=1; SLAVE START} wieder dazu veranlasst werden,
+nachdem eine manuelle Überprüfung / Korrektur der Datenintegrität
+durchgeführt wurde.
+@item
+Bug behoben, der das Löschen einer internen temporären Tabelle beim Beenden
+des Threads irrtümlicherweise in die Binär-Log-Datei schrieb. Dieser Bug
+betraf Replikation.
+@item
+Bug in @code{REGEXP()} auf 64-Bit-Maschinen.
+@item
+@code{UPDATE} und @code{DELETE} mit @code{WHERE eindeutiger_schluessel_teil
+IS NULL} aktualisierte / löschte nicht alle Zeilen.
+@item
+@code{INSERT DELAYED} für Tabellen abgeschaltet, die Transaktionen
+unterstützen.
+@item
+Bug bei der Benutzung von DATE-Funktionen auf
+@code{TEXT}/@code{BLOB}-Spalten mit falschem Datumsformat behoben.
+@item
+UDFs (benutzerdefinierte Funktionen) funktionieren jetzt auch unter
+Windows (Patch von Ralph Masona).
+@item
+Bug in @code{ALTER TABLE} und @code{LOAD DATA INFILE} behoben, der das
+Sortieren von Schlüsseln deaktivierte. Diese Befehle sollten jetzt in den
+meisten Fällen schneller sein.
+@item
+Performance-Bug beim erneuten Öffnen von Tabellen behoben (Tabellen, die
+auf ein @code{FLUSH} oder @code{REPAIR} warteten), die für die nächste
+Anfrage keine Indexe benutzten.
+@item
+Problem mit @code{ALTER TABLE} für Innobase-Tabellen auf FreeBSD behoben.
+@item
+@code{mysqld}-Variablen @code{myisam_max_sort_file_size} und
+@code{myisam_max_extra_sort_file_size} hinzugefügt.
+@item
+Signale werden frühzeitig initialisiert, um Problem mit Signalen in
+Innobase zu vermeiden.
+@item
+Patch für den @code{tis620}-Zeichensatz hinzugefügt, um Vergleiche
+unabhängig von der verwendeten Groß-/Kleinschreibung zu machen und einen
+Bug in @code{LIKE} für diesen Zeichensatz zu beheben. @strong{HINWEIS}:
+Alle Tabellen, die den @code{tis620}-Zeichensatz benutzen, müssen mit
+@code{myisamchk -r} oder @code{REPAIR TABLE} in Ordnung gebracht werden!
+@item
+@code{--skip-safemalloc}-Option zu @code{mysqld} hinzugefügt.
+@end itemize
+
+
+@node News-3.23.36, News-3.23.35, News-3.23.37, News-3.23.x
+@c German node Neuigkeiten-3.23.36
+@appendixsubsec Änderungen in Release 3.23.36
+
+@itemize @bullet
+@item
+Bug behoben, der Datenbanknamen mit einem @samp{.}-Zeichen zuließ. Das
+behebt ein schwerwiegendes Sicherheitsproblem, wenn man @code{mysqld} unter
+dem Benutzer root laufen läßt.
+@item
+Bug behoben, wenn die Erzeugung eines Threads fehlschlägt (das konnte bei
+der Herstellung SEHR vieler Verbindungen in kurzer Zeit passieren).
+@item
+Einige Probleme mit @code{FLUSH TABLES} und @code{TEMPORARY}-Tabellen
+behoben. (Problem mit dem Freisetzen des Schlüssel-Cache und Fehler
+@code{Can't reopen table...}).
+@item
+Problem in Innobase mit anderen Zeichensätze als @code{latin1} und ein
+anderes Problem bei der Benutzung von vielen Spalten behoben.
+@item
+Bug behoben, der einen Coredump bei der Benutzung einer sehr komplexen
+Anfrage mit @code{DISTINCT} und Summenfunktionen verursachte.
+@item
+@code{SET TRANSACTION ISOLATION LEVEL ...} hinzugefügt.
+@item
+@code{SELECT ... FOR UPDATE} hinzugefügt.
+@item
+Bug behoben, bei dem die Anzahl von betroffenen Zeilen nicht zurückgegeben
+wurde, wenn @code{MySQL} ohne Transaktionsunterstützung kompiliert wurde.
+@item
+Bug in @code{UPDATE} behoben, bei dem nicht immer Schlüssel benutzt wurden,
+um die zu aktualisierenden Zeilen zu finden.
+@item
+Bug in @code{CONCAT_WS()} behoben, bei dem diese Funktion falsche
+Ergebnisse zurückgab.
+@item
+@code{CREATE ... INSERT} und @code{INSERT ... SELECT} geändert, so dass
+diese noch kleine gleichzeitigen Einfügevorgänge zulassen, weil das dazu
+führen könnte, dass die Binär-Log-Datei schwer zu wiederholen ist.
+(Gleichzeitige Einfügevorgänge sind aktiviert, wenn Sie nicht die Binär-
+oder Update-Log-Datei verwenden.)
+@item
+Einige Makros geändert, so dass schnelles mutex mit glibc 2.2 verwendet
+werden kann.
+@end itemize
+
+
+@node News-3.23.35, News-3.23.34a, News-3.23.36, News-3.23.x
+@c German node Neuigkeiten-3.23.35
+@appendixsubsec Änderungen in Release 3.23.35
+
+@itemize @bullet
+@item
+Neu eingeführter Bug in @code{ORDER BY} behoben.
+@item
+Falsches Definieren von @code{CLIENT_TRANSACTIONS} behoben.
+@item
+Bug in @code{SHOW VARIABLES} bei der Benutzung von @code{INNOBASE}-Tabellen
+behoben.
+@item
+Das Setzen und Benutzen von Benutzer-Variablen in @code{SELECT DISTINCT}
+funktionierte nicht.
+@item
+@code{SHOW ANALYZE} für kleine Tabellen verbessert.
+@item
+Handhabung von Argumenten im Benchmark-Skript @file{run-all-tests} behoben.
+@end itemize
+
+
+@node News-3.23.34a, News-3.23.34, News-3.23.35, News-3.23.x
+@c German node Neuigkeiten-3.23.34a
+@appendixsubsec Änderungen in Release 3.23.34a
+
+@itemize @bullet
+@item
+Zusätzliche Dateien zur Distribution hinzugefügt, die es ermöglichen, mit
+@code{INNOBASE}-Unterstützung zu kompilieren.
+@end itemize
+
+
+@node News-3.23.34, News-3.23.33, News-3.23.34a, News-3.23.x
+@c German node Neuigkeiten-3.23.34
+@appendixsubsec Änderungen in Release 3.23.34
+
+@itemize @bullet
+@item
+@code{INNOBASE}-Tabellen-Handler und @code{BDB}-Tabellen-Handler zur
+MySQL-Quelldistribution hinzugefügt.
+@item
+Die Dokumentation zu @code{GEMINI}-Tabellen aktualisiert.
+@item
+Bug in @code{INSERT DELAYED} behoben, der den Thread zum Hängen brachte,
+wenn @code{NULL} in eine @code{AUTO_INCREMENT}-Spalte eingefügt wurde.
+@item
+Bug in @code{CHECK TABLE} / @code{REPAIR TABLE} behoben, der einen Thread
+zum Hängen bringen konnte.
+@item
+@code{REPLACE} ersetzt keine Zeile mehr, die mit einem durch
+@code{auto_increment} erzeugten Schlüssel in Konflikt steht.
+@item
+@code{mysqld} setzt jetzt nur @code{CLIENT_TRANSACTIONS} in
+@code{mysql->server_capabilities}, wenn der Server einen
+transaktionssicheren Handler unterstützt.
+@item
+@code{LOAD DATA INFILE} läßt jetzt das Einfügen numerischer Werte in
+@code{ENUM}- und @code{SET}-Spalten zu.
+@item
+Fehlerdiagnose beim Slave-Thread-Exit verbessert.
+@item
+Bug in @code{ALTER TABLE ... ORDER BY} behoben.
+@item
+Option @code{max_user_connections} für @code{mysqld} hinzugefügt.
+@item
+Anfragelänge für Replikation auf @code{max_allowed_packet} begrenzt, nicht
+auf die willkürliche Länge von 4 MB.
+@item
+Leerzeichen um @code{=} herum im Argument zu @code{--set-variable} werden
+zugelassen.
+@item
+Problem beim automatischen Reparieren behoben, der einen Thread im Zustand
+@code{Waiting for table} lassen konnte.
+@item
+@code{SHOW CREATE TABLE} gibt jetzt das @code{UNION()} für
+@code{MERGE}-Tabellen aus.
+@item
+@code{ALTER TABLE} merkt sich jetzt die alte @code{UNION()}-Definition.
+@item
+Bug beim Replizieren von Timestamps behoben.
+@item
+Bug bei der bidirektionalen Replikation behoben.
+@item
+Bug im @code{BDB}-Tabellen-Handler behoben, der bei der Benutzung eines
+Indexes auf mehrteilige Schlüssel vorkam, wenn ein Schlüsselteil
+@code{NULL} sein konnte.
+@item
+@code{MAX()}-Optimierung für Schlüsselteile (Sub-Keys) für
+@code{BDB}-Tabellen verbessert.
+@item
+Problem behoben, bei dem 'Müll'-Ergebnisse bei der Benutzung von
+@code{BDB}-Tabellen und @code{BLOB}- oder @code{TEXT}-Feldern beim
+Verknüpfen (Join) vieler Tabellen auftraten.
+@item
+Problem mit @code{BDB}-Tabellen und @code{TEXT}-Spalten behoben.
+@item
+Bug bei der Benutzung eines @code{BLOB}-Schlüssels behoben, wenn eine
+Konstanten-Zeile nicht gefunden wurde.
+@item
+Problem behoben, dass @code{mysqlbinlog} den Timestamp-Wert für jede
+Anfrage schreibt. Das stellt sicher, dass man dieselben Werte bei
+Datumsfunktionen wie @code{NOW()} bei der Benutzung von @code{mysqlbinlog}
+erhält, um die Anfragen zu einem anderen Server durchzureichen (pipe).
+@item
+Es wird zugelassen, dass @code{--skip-gemini}, @code{--skip-bdb} und
+@code{--skip-innobase} für @code{mysqld} angegeben werden, selbst wenn
+diese Datenbanken nicht in @code{mysqld} einkompiliert sind.
+@item
+Man kann jetzt @code{GROUP BY ... DESC} ausführen.
+@item
+Blockierung im @code{SET}-Code behoben, wenn man @code{SET @@foo=bar}
+ausführte, wobei @code{bar} ein Spaltenverweis ist. Hier wurde die
+Fehlermeldung nicht korrekt erzeugt.
+@end itemize
+
+
+@node News-3.23.33, News-3.23.32, News-3.23.34, News-3.23.x
+@c German node Neuigkeiten-3.23.33
+@appendixsubsec Änderungen in Release 3.23.33
+
+@itemize @bullet
+@item
+DNS-Lookups benutzen jetzt nicht mehr denselben mutex wie der
+Hostnamen-Cache. Das gestattet, dass bekannte Hosts schnell aufgelöst
+werden können, selbst wenn ein DNS-Lookup lange Zeit braucht.
+@item
+@code{--character-sets-dir} für @code{myisampack} hinzugefügt.
+@item
+Warnungen beim Laufenlassen von @code{REPAIR TABLE ... EXTENDED} entfernt.
+@item
+Bug, der einen Coredump bei der Benutzung von @code{GROUP BY} auf ein Alias
+verursachte, wobei der Alias dasselbe wie ein existierender Spaltenname
+war, entfernt.
+@item
+@code{SEQUENCE()} als Beispiel-UDF-Funktion hinzugefügt.
+@item
+@code{mysql_install_db} geändert, so dass es @code{BINARY} für
+@code{CHAR}-Spalten in den Berechtigungstabellen benutzt.
+@item
+@code{TRUNCATE tabelle} zu @code{TRUNCATE TABLE tabelle} geändert, um
+dieselbe Syntax wie Oracle zu verwenden. Bis Version 4.0 lassen wir
+weiterhin @code{TRUNCATE tabelle} zu, um alten Code nicht zum Absturz zu
+bringen.
+@item
+'no found rows'-Bug in @code{MyISAM}-Tabellen behoben, wenn ein @code{BLOB}
+erster Teil eines mehrteiligen Schlüssels war.
+@item
+Bug behoben, bei dem @code{CASE} mit @code{GROUP BY} nicht funktionierte.
+@item
+Option @code{--sort-recover} für @code{myisamchk} hinzugefügt.
+@item
+@code{myisamchk -S} und @code{OPTIMIZE TABLE} funktionieren jetzt unter
+Windows.
+@item
+Bug bei der Benutzung von @code{DISTINCT} auf Ergebnisse von Funktionen
+behoben, die sich auf eine Gruppenfunktion bezogen, wie:
+@example
+SELECT a, DISTINCT SEC_TO_TIME(sum(a)) from tabelle GROUP BY a, b;
+@end example
+@item
+Puffer-Überlauf in @code{libmysqlclient}-Bibliothek behoben. Bug bei der
+Handhabung des @code{STOP}-Ereignisses nach @code{ROTATE}-Ereignis bei
+Replikation.
+@item
+Einen weiteren Puffer-Überlauf in @code{DROP DATABASE} behoben.
+@item
+@code{Table_locks_immediate}- und
+@code{Table_locks_waited}-Status-Variablen hinzugefügt.
+@item
+Bug in Replikation behoben, der den Slave-Server-Start bei existierendem
+@code{master.info} unterbrach. Das behebt einen Bug, der in Version 3.23.32
+eingeführt wurde.
+@item
+@code{SET SQL_SLAVE_SKIP_COUNTER=n}-Befehl hinzugefügt, um nach
+Replikationsstörungen ohne volle Datenbankkopie wiederherzustellen.
+@item
+@code{max_binlog_size}-Variable hinzugefügt; die Binär-Log-Datei wird
+automatisch rotiert, wenn die Größe die Grenze überschreitet.
+@item
+@code{Last_error}, @code{Last_errno} und @code{Slave_skip_counter} für
+@code{SHOW SLAVE STATUS} hinzugefügt.
+@item
+Bug in @code{MASTER_POS_WAIT()}-Funktion behoben.
+@item
+Coredump-Handler auf @code{SIGILL} und @code{SIGBUS} zusätzlich zu
+@code{SIGSEGV}.
+@item
+Auf x86-Linux wird im Coredump-Handler die aktuelle Anfrage und die Thread-
+(Verbindungs-) Kennung, falls verfügbar, angegeben.
+@item
+Mehrere Timing-Bugs in der Test-Suite behoben.
+@item
+@code{mysqltest} erweitert, so dass es sich um Probleme mit dem Timing in
+der Test-Suite kümmert.
+@item
+@code{ALTER TABLE} kann jetzt auch benutzt werden, um die Definition einer
+@code{MERGE}-Tabelle zu ändern.
+@item
+Erzeugung von @code{MERGE}-Tabellen unter Windows in Ordnung gebracht.
+@item
+Portabilitätsbehebungen für OpenBSD und OS/2.
+@item
+@code{--temp-pool}-Option zu @code{mysqld} hinzugefügt. Das Benutzen dieser
+Option führt dazu, dass temporäre Dateien nur einen kleinen Satz von Namen
+benutzen, statt eines eindeutigen Namens für jede neue Datei. Das ist ein
+Workaround um ein Problem im Linux-Kernel beim Erzeugen einer großen Menge
+neuer Dateien mit unterschiedlichen Namen. Beim alten Verhalten scheint es
+so, als ein Linux ein Speicher-'Loch' hätte, weil zum
+Verzeichniseintrags-Cache statt zum Festplatten-Cache zugewiesen
+(alloziert) wird.
+@end itemize
+
+
+@node News-3.23.32, News-3.23.31, News-3.23.33, News-3.23.x
+@c German node Neuigkeiten-3.23.32
+@appendixsubsec Änderungen in Release 3.23.32
+
+@itemize @bullet
+@item
+Code geändert, um um einen Compiler-Bug in Compaq C++ auf OSF1
+herumzuarbeiten, der @code{BACKUP}, @code{RESTORE}, @code{CHECK},
+@code{REPAIR} und @code{ANALYZE TABLE} beschädigte.
+@item
+Option @code{FULL} für @code{SHOW COLUMNS} hinzugefügt. Jetzt wird die
+Berechtigungsliste für die Spalten nur angezeigt, wenn diese Option
+angegeben wird.
+@item
+Bug in @code{SHOW LOGS} behoben, wenn es keine BDB-Logs gab.
+@item
+Timing-Problem in Replikation behoben, dass das Abschicken einer
+Aktualisierung an den Client verzögern konnte, bis eine weitere
+Aktualisierung durchgeführt wurde.
+@item
+Feldnamen bei der Benutzung von @code{mysql_list_fields()} nicht umwandeln.
+Damit bleibt dieser Code kompatibel mit @code{SHOW FIELDS}.
+@item
+@code{MERGE}-Tabellen funktionierten nicht unter Windows.
+@item
+Problem mit @code{SET PASSWORD=...} unter Windows.
+@item
+Fehlende @file{my_config.h} für RPM-Distribution hinzugefügt.
+@item
+@code{TRIM("foo" von "foo")} gab keine leere Zeichenkette zurück.
+@item
+@code{--with-version-suffix} für @code{configure} hinzugefügt.
+@item
+Coredump behoben, wenn der Client eine Verbindung ohne @code{mysql_close()}
+abbrach.
+@item
+Bug in @code{RESTORE TABLE} behoben, wenn man versuchte, aus einem nicht
+vorhandenen Verzeichnis wiederherzustellen.
+@item
+Bug behoben, der einen Coredump auf dem Slave bei der Replikation von
+@code{SET PASSWORD} verursachte.
+@item
+@code{MASTER_POS_WAIT()} hinzugefügt.
+@end itemize
+
+
+@node News-3.23.31, News-3.23.30, News-3.23.32, News-3.23.x
+@c German node Neuigkeiten-3.23.31
+@appendixsubsec Änderungen in Release 3.23.31
+
+@itemize @bullet
+@item
+Die Test-Suite testet jetzt jeden erreichbaren BDB-Schnittstellen-Code.
+Während der Tests fanden und behoben wir viele Fehler im
+Schnittstelle-Code.
+@item
+Die Benutzung von @code{HAVING} auf eine leere Tabelle konnte eine
+Ergebniszeile ergeben, ohne dass es das sollte.
+@item
+Problem behoben, so dass das MySQL-RPM nicht mehr von Perl5 abhängt.
+@item
+Einige Probleme mit @code{HEAP}-Tabellen unter Windows behoben.
+@item
+@code{SHOW TABLE STATUS} zeigte nicht die korrekte durchschnittliche
+Zeilenlänge bei Tabellen größer als 4 GB.
+@item
+@code{CHECK TABLE ... EXTENDED} prüften keine Zeilen-Links für Tabellen
+fester Größe.
+@item
+Option @code{MEDIUM} für @code{CHECK TABLE} hinzugefügt.
+@item
+Problem bei der Benutzung von @code{DECIMAL()}-Schlüsseln auf negative
+Zahlen behoben.
+@item
+@code{HOUR()} (und einige andere @code{TIME}-Funktionen) auf einer
+@code{CHAR}-Spalte gaben immer @code{NULL} zurück.
+@item
+Sicherheits-Bug in etwas behoben (bitte aktualisieren Sie, wenn Sie eine
+frühere MySQL-3.23-Version benutzen).
+@item
+Bug mit Puffer-Überlauf behoben, wenn eine bestimmte Fehlermeldung
+ausgegeben wurde.
+@item
+Benutzung von @code{setrlimit()} unter Linux hinzugefügt, damit
+@code{-O --open-files-limit=#} unter Linux läuft.
+@item
+Neue @code{mysqld}-Variable @code{bdb_version} hinzugefügt.
+@item
+Bug bei der Benutzung von Ausdrücken folgenden Typs behoben:
+@example
+SELECT ... FROM t1 LEFT JOIN t2 ON (t1.a=t2.a) WHERE t1.a=t2.a
+@end example
+In diesem Fall wurde der Test in der @code{WHERE}-Klausel fälschlicherweise
+weg optimiert.
+@item
+Bug in @code{MyISAM} beim Löschen von Schlüsseln mit möglichen
+@code{NULL}-Werten behoben, wenn die erste Schlüsselspalte keine
+Präfix-komprimierte Text-Spalte war.
+@item
+@code{mysql.server} repariert, so dass es den
+@code{mysql.server}-Optionsabschnitt anstelle von @code{mysql_server}
+liest.
+@item
+@code{safe_mysqld} und @code{mysql.server} repariert, so dass sie den
+@code{server}-Optionsabschnitt lesen.
+@item
+@code{thread_created}-Status-Variable zu @code{mysqld} hinzugefügt.
+@end itemize
+
+
+@node News-3.23.30, News-3.23.29, News-3.23.31, News-3.23.x
+@c German node Neuigkeiten-3.23.30
+@appendixsubsec Änderungen in Release 3.23.30
+
+@itemize @bullet
+@item
+@code{SHOW OPEN TABLES}-Befehl hinzugefügt.
+@item
+@code{myisamdump} funktioniert jetzt mit alten @code{mysqld}-Servern.
+@item
+@code{myisamchk -k#} funktioniert jetzt wieder.
+@item
+Problem mit Replikation behoben, wenn die Binär-Log-Datei-Datei auf
+32-Bit-Systemen größer als 2 GB wurde.
+@item
+@code{LOCK TABLES} startet jetzt automatisch eine neue Transaktion.
+@item
+@code{BDB}-Tabellen so geändert, dass sie interne Sub-Transaktionen
+benutzen und offene Dateien wiederholt benutzen, um mehr Geschwindigkeit zu
+erzielen.
+@item
+Option @code{--mysqld=#} für @code{safe_mysqld} hinzugefügt.
+@item
+Hexadezimale Konstanten in @code{--fields-*-by}- und
+@code{--lines-terminated-by}-Optionen für @code{mysqldump} und
+@code{mysqlimport} werden jetzt zugelassen. Von Paul DuBois.
+@item
+Option @code{--safe-show-Datenbank} für @code{mysqld} hinzugefügt.
+@item
+@code{have_bdb}, @code{have_gemini}, @code{have_innobase},
+@code{have_raid} und @code{have_openssl} für @code{SHOW VARIABLES}
+hinzugefügt, um das Testen auf unterstützte Erweiterungen zu erleichtern.
+@item
+Option @code{--open-files-limit} für @code{mysqld} hinzugefügt.
+@item
+Option @code{--open-files} zu @code{--open-files-limit} in
+@code{safe_mysqld} geändert.
+@item
+Bug behoben, bei dem einige Zeilen nicht gefunden wurden, wenn
+@code{HEAP}-Tabellen viele Schlüssel hatten.
+@item
+@code{--bdb-no-sync} funktioniert jetzt.
+@item
+@code{--bdb-recover} in @code{--bdb-no-recover} geändert, weil recover
+vorgabemäßig angeschaltet sein sollte.
+@item
+Die vorgabemäßige Anzahl von BDB-Sperren auf 10.000 geändert.
+@item
+Bug aus Version 3.23.29 behoben, beim Zuweisen der gemeinsam genutzten
+Struktur, die für BDB-Tabellen benötigt wird.
+@item
+@file{mysqld_multi.sh} für benutzerkonfigurierbare Variablen geändert.
+Patch von Christopher McCrory.
+@item
+Include-Dateien für Solaris 2.8 in Ordnung gebracht.
+@item
+Bug mit @code{--skip-networking} auf Debian Linux behoben.
+@item
+Problem behoben, dass einige temporäre Dateien den Namen @code{UNOPENED} in
+Fehlermeldungen hatten.
+@item
+Bug beim Laufenlassen von zwei gleichzeitigen @code{SHOW LOGS}-Anfragen
+behoben.
+@end itemize
+
+
+@node News-3.23.29, News-3.23.28, News-3.23.30, News-3.23.x
+@c German node Neuigkeiten-3.23.29
+@appendixsubsec Änderungen in Release 3.23.29
+
+@itemize @bullet
+@item
+Configure-Aktualisierungen für Tru64, Unterstützung großer Dateien und
+besser TCP-Wrapper-Unterstützung. Von Albert Chin-A-Young.
+@item
+Bug in @code{<=>}-Operator behoben.
+@item
+Bug in @code{REPLACE} mit BDB-Tabellen behoben.
+@item
+@code{LPAD()} und @code{RPAD()} kürzen jetzt die Ergebnis-Zeichenkette,
+wenn sie länger als das Längenargument ist.
+@item
+@code{SHOW LOGS}-Befehl hinzugefügt.
+@item
+Unbenutzte BDB-Logs werden beim Herunterfahren entfernt.
+@item
+Beim Erzeugen einer Tabelle werden @code{PRIMARY}-Schlüsseln zuerst
+gesetzt, gefolgt von @code{UNIQUE}-Schlüsseln.
+@item
+Bug in @code{UPDATE} behoben, wenn mehrteilige Schlüssel benutzt wurden,
+bei denen alle Schlüsselteile sowohl in der Aktualisierung als auch im
+@code{WHERE}-Teil angegeben wurden. In diesem Fall könnte MySQL versuchen,
+einen Datensatz zu aktualisieren, der nicht dem gesamten @code{WHERE}-Teil
+entspricht.
+@item
+Löschen von Tabellen so geändert, dass zunächst die Tabelle und dann die
+@file{.frm}-Datei gelöscht wird.
+@item
+Bug im Hostnamen-Cache behoben, der dazu führte, dass @code{mysqld} den
+Hostnamen als @code{''} in manchen Fehlermeldungen berichtete.
+@item
+Bug mit @code{HEAP}-Tabellen behoben; die Variable
+@code{max_heap_table_size} wurde nicht benutzt. Jetzt kann entweder
+@code{MAX_ROWS} oder @code{max_heap_table_size} benutzt werden, um die
+Größe einer @code{HEAP}-Tabelle zu beschränken.
+@item
+Die vorgabemäßige Server-Kennung auf 1 für Master-Server und 2 für Slaves
+geändert, um die Benutzung der Binär-Log-Datei zu erleichtern.
+@item
+Variable @code{bdb_lock_max} in @code{bdb_max_lock} umbenannt.
+@item
+Unterstützung für @code{auto_increment} auf Unter-Felder (Sub-Fields) für
+BDB-Tabellen hinzugefügt.
+@item
+@code{ANALYZE} von BDB-Tabellen hinzugefügt.
+@item
+In BDB-Tabellen wird jetzt die Anzahl von Zeilen gespeichert. Das hilft,
+Anfragen zu optimieren, wenn dafür die ungefähre Anzahl von Zeilen benötigt
+wird.
+@item
+Wenn es einen Fehler in einem mehrzeiligen Statement gibt, wird jetzt nur
+das letzte Statement zurückgerollt, nicht die gesamte Transaktion.
+@item
+Wenn man @code{ROLLBACK} nach der Aktualisierung einer nicht
+transaktionalen Tabelle ausführt, erhält man als Warnung einen Fehler.
+@item
+Option @code{--bdb-shared-data} für @code{mysqld} hinzugefügt.
+@item
+Status-Variable @code{Slave_open_temp_tables} hinzugefügt.
+@item
+Variablen @code{binlog_cache_size} und @code{max_binlog_cache_size} für
+@code{mysqld} hinzugefügt.
+@item
+@code{DROP TABLE}, @code{RENAME TABLE}, @code{CREATE INDEX} und
+@code{DROP INDEX} sind jetzt Transaktions-Endpunkte.
+@item
+Wenn Sie ein @code{DROP DATABASE} auf eine symbolisch verknüpfte Datenbank
+ausführen, werden sowohl der Link als auch die Original-Datenbank gelöscht.
+@item
+@code{DROP DATABASE} funktioniert jetzt auf OS/2.
+@item
+Bug bei der Ausführung von @code{SELECT DISTINCT ... tabelle1 LEFT JOIN
+tabelle2 ...} behoben, wenn tabelle2 leer war.
+@item
+@code{--abort-slave-event-count}- und
+@code{--disconnect-slave-event-count}-Optionen für @code{mysqld} zum
+Debuggen und Testen der Replikation hinzugefügt.
+@item
+Replikation temporärer Tabellen in Ordnung gebracht. Handhabt alles ausser
+dem Neustart von Slaves.
+@item
+@code{SHOW KEYS} zeigt jetzt, ob ein Schlüssel @code{FULLTEXT} ist oder
+nicht.
+@item
+Neues Skript @file{mysqld_multi}. @xref{mysqld_multi, , @code{mysqld_multi}}.
+@item
+Neues Skript @file{mysql-multi.server.sh} hinzugefügt. Vielen Dank an Tim
+Bunce @email{Tim.Bunce@@ig.co.uk} für die Modifizierung von
+@file{mysql.server}, um auf einfache Weise Hosts zu handhaben, die viele
+@code{mysqld}-Prozesse laufen lassen.
+@item
+@file{safe_mysqld}, @file{mysql.server} und @file{mysql_install_db} wurden
+so abgeändert, dass sie @code{mysql_print_defaults} anstelle verschiedener
+Hacks benutzen, um @file{my.cnf}-Dateien zu lesen. Zusätzlich wurde die
+Handhabung verschiedener Pfade konsistenter gemacht, in Bezug auf wie
+@code{mysqld} vorgabemäßig handhabt.
+@item
+Berkeley-DB-Transaktions-Logs, die nicht mehr in Benutzung sind, werden
+automatisch entfernt.
+@item
+Bug bei mehreren @code{FULLTEXT}-Indexen in einer Tabelle behoben.
+@item
+Warnung hinzugefügt, wenn sich die von Zeilen bei
+@code{REPAIR}/@code{OPTIMIZE} ändert.
+@item
+Patches für OS/2 von @code{Yuri Dario} angewandt.
+@item
+@code{FLUSH TABLES tabelle} schrieb den Index-Baum nicht immer korrekt auf
+die Festplatte zurück.
+@item
+@code{--bootstrap} läuft jetzt in einem separaten Thread. Das behebt ein
+Problem, das bei @code{mysql_install_db} einen Coredump auf einigen
+Linux-Maschinen verursachte.
+@item
+@code{mi_create()} abgeändert, so dass es weniger Stack-Platz benötigt.
+@item
+Bug beim Optimierer, wenn er versucht, @code{MATCH}, mit
+@code{UNIQUE}-Schlüsseln benutzt, zu überoptimieren.
+@item
+@code{Crash-me} und die MySQL-Benchmarks funktionieren jetzt auch mit
+FrontBase.
+@item
+@code{RESTRICT} und @code{CASCADE} werden nach einem @code{DROP TABLE}
+zugelassen, um die Portierung einfacher zu machen.
+@item
+Status-Variable zurückgesetzt, die Probleme hervorrufen konnte, wenn man
+@code{--slow-log} benutzte.
+@item
+Variable @code{connect_timeout} für @code{mysql} und @code{mysqladmin}
+hinzugefügt.
+@item
+@code{connect_timeout} als Alias für @code{timeout} für Optionsdateien, die
+von @code{mysql_options()} gelesen werden, hinzugefügt.
+@end itemize
+
+
+@node News-3.23.28, News-3.23.27, News-3.23.29, News-3.23.x
+@c German node Neuigkeiten-3.23.28
+@appendixsubsec Änderungen in Release 3.23.28
+
+@itemize @bullet
+@item
+Neue Optionen @code{--pager[=...]}, @code{--no-pager}, @code{--tee=...} und
+@code{--no-tee} für den @code{mysql}-Client hinzugefügt. Die entsprechenden
+neuen interaktiven Befehle heißen @code{pager}, @code{nopager}, @code{tee}
+und @code{notee}. Siehe @xref{mysql, , @code{mysql}}, @code{mysql --help}
+und die interaktive Hilfe wegen weiterer Informationen.
+@item
+Absturz behoben, der beim Fehlschlagen der Reparatur von
+@code{MyISAM}-Tabellen auftrat.
+@item
+Größerer Performance-Bug im Tabellensperren-Code behoben, wenn man
+permanent VIELE @code{SELECT}-, @code{UPDATE}- und @code{INSERT}-Statements
+laufen hatte. Das Symptom zeigte sich darin, dass die @code{UPDATE}- und
+@code{INSERT}-Anfragen lange gesperrt waren, während neue
+@code{SELECT}-Statements vor den Aktualisierungen ausgeführt wurden.
+@item
+Beim Lesen von @code{options_files} mit @code{mysql_options()} wurde die
+@code{return-found-rows}-Option ignoriert.
+@item
+Man kann jetzt @code{interactive-timeout} in der Optionsdatei angeben, die
+von @code{mysql_options()} gelesen wird. Das ermöglicht es, Programme, die
+lange laufen (wie @code{mysqlhotcopy}), zu zwingen,
+@code{interactive_timeout} anstelle von @code{wait_timeout} zu benutzen.
+@item
+Zur Langsame-Anfragen-Log-Datei Zeit und Benutzernamen für jede geloggte
+Anfrage hinzugefügt. Wenn Sie @code{--log-long-format} benutzen, werden
+auch Anfragen, die keinen Index benutzen, geloggt, selbst wenn die Anfrage
+weniger als @code{long_query_time} Sekunden benötigt.
+@item
+Problem in @code{LEFT JOIN} behoben, was dazu führte, dass alle Spalten in
+einer Verweistabelle @code{NULL} waren.
+@item
+Problem bei der Benutzung von @code{NATURAL JOIN} ohne Schlüssel behoben.
+@item
+Bug bei der Benutzung eines mehrteiligen Schlüssels behoben, bei dem der
+erste Teil vom Typ @code{TEXT} oder @code{BLOB} war.
+@item
+@code{DROP} von temporären Tabellen wurde nicht in der
+Update-/Binär-Log-Datei gespeichert.
+@item
+Bug behoben, der bei @code{SELECT DISTINCT * ... LIMIT #} nur eine Zeile
+zurückgab.
+@item
+Bug im Assembler-Code in @code{strstr()} für sparc behoben und
+@file{global.h}-Header-Datei aufgeräumt, um ein Problem mit schlechtem
+Aliasing des Compilers zu vermeiden, der bei RedHat 7.0 beiliegt (berichtet
+von Trond Eivind Glomsrød).
+@item
+Die Option @code{--skip-networking} funktioniert jetzt sauber unter Windows
+NT.
+@item
+Lang ausstehender Bug in den @code{ISAM}-Tabellen behoben, wenn eine Zeile
+mit einer Länge von mehr als 65 KB um ein einzelnes Byte gekürzt wurde.
+@item
+Bug in @code{MyISAM} beim Laufenlassen mehrfacher Aktualisierungsprozesse
+auf dieselbe Tabelle behoben.
+@item
+Es wird zugelassen, dass @code{FLUSH TABLE tabelle} benutzt wird.
+@item
+@code{--replicate-ignore-table}, @code{--replicate-do-table},
+@code{--replicate-wild-ignore-table} und @code{--replicate-wild-do-table}
+hinzugefügt.
+@item
+Alle Log-Dateien so geändert, dass sie unseren eigenen
+@code{IO_CACHE}-Mechanismus anstelle von @code{FILE} benutzen, um
+Betriebssystemprobleme zu vermeiden, wenn zu viele Dateien offen sind.
+@item
+Optionen @code{--open-files} und @code{--timezone} für @code{safe_mysqld}
+hinzugefügt.
+@item
+Schweren Bug in @code{CREATE TEMPORARY TABLE ... SELECT ...} behoben.
+@item
+Problem mit @code{CREATE TABLE ... SELECT NULL} behoben.
+@item
+Variablen @code{large_file_support}, @code{net_read_timeout},
+@code{net_write_timeout} und @code{query_buffer_size} für @code{SHOW
+VARIABLES} hinzugefügt.
+@item
+Status-Variablen @code{created_tmp_files} und @code{sort_merge_passes} für
+@code{SHOW STATUS} hinzugefügt.
+@item
+Bug behoben, bei dem kein Index-Name nach der @code{FOREIGN KEY}-Definition
+zugelassen wurde.
+@item
+@code{TRUNCATE tabelle} als ein Synonym für @code{DELETE FROM tabelle}
+hinzugefügt.
+@item
+Bug in einer BDB-Schlüsselvergleichsfunktion beim Vergleich von
+Schlüsselteilen behoben.
+@item
+Variable @code{bdb_lock_max} für @code{mysqld} hinzugefügt.
+@item
+Weitere Tests zur Benchmark-Suite hinzugefügt.
+@item
+Überlauf-Bug im Client-Code bei der Benutzung von überlangen Datenbanknamen
+behoben.
+@item
+@code{mysql_connect()} bricht jetzt unter Linux ab, wenn der Server nicht
+in @code{timeout} Sekunden antwortet.
+@item
+@code{SLAVE START} funktionierte nicht, wenn Sie mit
+@code{--skip-slave-start} starteten und vorher nicht explizit @code{CHANGE
+MASTER TO} laufen ließen.
+@item
+Die Ausgabe von @code{SHOW MASTER STATUS} in Ordnung gebracht, damit sie
+konsistent mit @code{SHOW SLAVE STATUS} ist. (Sie hat jetzt kein
+Verzeichnis im Log-Namen.)
+@item
+@code{PURGE MASTER LOGS TO} hinzugefügt.
+@item
+@code{SHOW MASTER LOGS} hinzugefügt.
+@item
+@code{--safemalloc-mem-limit}-Option für @code{mysqld} hinzugefügt, um
+Speichermangel zu simulieren, wenn mit @code{--with-debug=full} kompiliert
+wurde.
+@item
+Mehrere Coredumps unter Bedingungen, in denen Arbeitsspeicher fehlt,
+behoben.
+@item
+@code{SHOW SLAVE STATUS} benutzte einen nicht initialisierten mutex, wenn
+der Slave noch nicht gestartet wurde.
+@item
+Bug in @code{ELT()} und @code{MAKE_SET()} behoben, wenn die Anfrage eine
+temporäre Tabelle benutzte.
+@item
+@code{CHANGE MASTER TO} ohne Angabe von @code{MASTER_LOG_POS} setzte es auf
+0 statt auf 4 und erreichte die magische Zahl im binären Master-Log.
+@item
+@code{ALTER TABLE ... ORDER BY ...}-Syntax hinzugefügt. Das erzeugt die
+Tabelle mit Zeilen in einer festgelegten Reihenfolge.
+@end itemize
+
+
+@node News-3.23.27, News-3.23.26, News-3.23.28, News-3.23.x
+@c German node Neuigkeiten-3.23.27
+@appendixsubsec Änderungen in Release 3.23.27
+
+@itemize @bullet
+@item
+Bug behoben, bei dem das automatische Reparieren von MyISAM-Tabellen
+manchmal fehlschlug, wenn die Daten-Datei beschädigt war.
+@item
+Bug in @code{SHOW CREATE} bei der Benutzung von
+@code{AUTO_INCREMENT}-Spalten behoben.
+@item
+BDB-Tabellen so geändert, dass sie die neue Vergleichsfunktion in Berkeley
+DB 3.2.3 benutzen.
+@item
+Sie können jetzt Unix-Sockets bei @code{mit-pThread} benutzen.
+@item
+Neuer latin5- (türkischer) Zeichensatz.
+@item
+Kleinere Portabilitätsbehebungen.
+@end itemize
+
+
+@node News-3.23.26, News-3.23.25, News-3.23.27, News-3.23.x
+@c German node Neuigkeiten-3.23.26
+@appendixsubsec Änderungen in Release 3.23.26
+
+@itemize @bullet
+@item
+@code{<>} funktioniert jetzt sauber mit @code{NULL}.
+@item
+Problem mit @code{SUBSTRING_INDEX()} und @code{REPLACE()} behoben (Patch
+von Alexunder Igonitchev).
+@item
+@code{CREATE TEMPORARY TABLE IF NOT EXISTS} gab keinen Fehler, wenn die
+Tabelle existierte.
+@item
+Wenn Sie keinen @code{PRIMARY KEY} in einer BDB-Tabelle erzeugen, wird ein
+versteckter @code{PRIMARY KEY} erzeugt.
+@item
+Nur-Lese-Schlüssel-Optimierung to BDB-Tabellen hinzugefügt.
+@item
+@code{LEFT JOIN} bevorzugte in manchen Fällen einen vollen Tabellen-Scan,
+wenn es keine @code{WHERE}-Klausel gab.
+@item
+Bei der Benutzung von @code{--log-slow-query} die Wartezeit auf eine Sperre
+nicht zählen.
+@item
+Bug im Sperr-Code unter Windows behoben, der dazu führte, dass der
+Schlüssel-Cache berichtete, dass die Schlüssel-Datei beschädigt sei, obwohl
+sie in Ordnung war.
+@item
+Automatische Reparatur von @code{MyISAM}-Tabellen, wenn Sie @code{mysqld}
+mit @code{--myisam-recover} starten, hinzugefügt.
+@item
+Das @code{TYPE=}-Schlüsselwort wurde von @code{CHECK} und @code{REPAIR}
+entfernt. Es wird zugelassen, dass @code{CHECK}-Optionen kombiniert werden.
+(Sie können immer noch @code{TYPE=} benutzen, aber die Benutzung wird nicht
+empfohlen.)
+@item
+Mutex-Bug im binären Replikations-Log behoben - lange
+Aktualisierungsanfragen konnten vom Slave nur teilweise gelesen werden,
+wenn er das zur falschen Zeit machte, was nicht schwerwiegend ist, aber zu
+einem Performance-verschlechternden erneuten Verbinden führte, sowie zu
+einer beunruhigenden Nachricht in der Fehler-Log-Datei.
+@item
+Das Format der Binär-Log-Datei wurde geändert - hinzugefügt wurden magische
+Zahl, Serverversion, Binlog-Version, Server-Kennung und Anfragen-Fehlercode
+für jedes Anfrage-Ereignis.
+@item
+Replikations-Thread vom Slave killt jetzt alle darnieder liegenden Threads
+vom selben Server.
+@item
+Lange Replikations-Benutzernamen wurden bislang nicht korrekt gehandhabt.
+@item
+@code{--replicate-rewrite-db}-Option zu @code{mysqld} hinzugefügt.
+@item
+@code{--skip-slave-start}-Option to @code{mysqld} hinzugefügt.
+@item
+Aktualisierungen, die einen Fehlercode erzeugten (wie @code{INSERT INTO
+foo(schluessel) values (1),(1)}) beendeten bislang irrtümlich den
+Slave-Thread.
+@item
+Optimierung von Anfragen, bei denen @code{DISTINCT} nur auf Spalten aus
+denselben Tabellen benutzt wird, hinzugefügt.
+@item
+Fließkommazahlen ohne Vorzeichen nach dem Exponent (wie 1e1) werden
+zugelassen.
+@item
+@code{SHOW GRANTS} zeigte nicht immer alle Spaltenberechtigungen.
+@item
+@code{--default-extra-file=#} für alle MySQL-Clients hinzugefügt.
+@item
+Spalten, auf die in @code{INSERT}-Statements verwiesen wird, werden nun
+sauber initialisiert.
+@item
+@code{UPDATE} funktioniert nicht immer, wenn es mit einem Bereich auf einem
+Timestamp benutzt wurde, der Teil des Schlüssels war, der benutzt wurde, um
+Zeilen zu finden.
+@item
+Bug in @code{FULLTEXT}-Index beim Einfügen einer @code{NULL}-Spalte
+behoben.
+@item
+@code{mkstemp()} wird jetzt anstelle von @code{tempnam()} benutzt. Basiert
+auf einem Patch von John Jones.
+@end itemize
+
+
+@node News-3.23.25, News-3.23.24, News-3.23.26, News-3.23.x
+@c German node Neuigkeiten-3.23.25
+@appendixsubsec Änderungen in Release 3.23.25
+
+@itemize @bullet
+@item
+@code{database} funktioniert als zweites Argument für @code{mysqlhotcopy}.
+@item
+@code{UMASK} und @code{UMASK_DIR} können jetzt oktal angegeben werden.
+@item
+@code{RIGHT JOIN}. Hierdurch wird @code{RIGHT} zu einem reservierten Wort.
+@item
+@code{@@@@IDENTITY} als ein Synonym für @code{LAST_INSERT_ID()}
+hinzugefügt, aus Gründen der Visual-Basic-Kompatibilität.)
+@item
+Bug in @code{myisamchk} und @code{REPAIR} bei der Benutzung von
+@code{FULLTEXT}-Indexen behoben.
+@item
+@code{LOAD DATA INFILE} funktioniert jetzt mit FIFOs (Patch von Toni L.
+Harbaugh-Blackford).
+@item
+@code{FLUSH LOGS} brach die Replikation ab, wenn Sie einen Log-Namen mit
+einer expliziten Erweiterung als Wert der @code{log-bin}-Option angaben.
+@item
+Bug in @code{MyISAM} mit komprimierten mehrteiligen Schlüsseln behoben.
+@item
+Absturz bei der Benutzung von @code{CHECK TABLE} unter Windows behoben.
+@item
+Bug, bei dem @code{FULLTEXT}-Index immer den koi8_ukr-Zeichensatz
+benutzten, behoben.
+@item
+Berechtigungsüberprüfung für @code{CHECK TABLE} in Ordnung gebracht.
+@item
+Der @code{MyISAM}-Reparatur-/Reindexierungs-Code benutzte nicht die
+@code{--tempdir}-Option für seine temporären Dateien.
+@item
+@code{BACKUP TABLE/RESTORE TABLE} hinzugefügt.
+@item
+Coredump auf @code{CHANGE MASTER TO} behoben, wenn der Slave keinen Master
+hatte, mit dem er startet.
+@item
+Falsche @code{time} in der Prozessliste für @code{Connect} des
+Slave-Threads in Ordnung gebracht.
+@item
+Der Slave loggt jetzt, wann er sich mit dem Master verbindet.
+@item
+Coredump-Bug beim Ausführen von @code{FLUSH MASTER} behoben, wenn man kein
+Dateinamens-Argument für @code{--log-bin} angab.
+@item
+Fehlende @file{ha_berkeley.x}-Dateien zu MySQL unter Windows hinzugefügt.
+@item
+Einige mutex-Bugs im Log-Code behoben, die zu Thread-Blockierungen führen
+konnten, wenn neue Log-Dateien nicht erzeugt werden konnten.
+@item
+Sperrzeit und Anzahl von ausgewählten bearbeiteten Zeilen zur
+Langsame-Anfragen-Log-Datei hinzugefügt.
+@item
+@code{--memlock}-Option für @code{mysqld}, um @code{mysqld} im
+Arbeitsspeicher auf Systemen mit dem @code{mlockall()}-Aufruf (wie in
+Solaris) zu sperren, hinzugefügt.
+@item
+@code{HEAP}-Tabellen benutzten Schlüssel nicht korrekt (Bug aus Version
+3.23.23).
+@item
+Bessere Unterstützung für @code{MERGE}-Tabellen (Schlüssel, Mapping,
+Erzeugung, Dokumentation und mehr) hinzugefügt. @xref{MERGE}.
+@item
+Bug in @code{mysqldump} aus Version 3.23 behoben, der dazu führte, dass
+einige @code{CHAR}-Spalten nicht in Anführungsstrichen standen.
+@item
+@code{analyze}, @code{check}, @code{optimize} und Reparatur-Code
+zusammengefasst.
+@item
+@code{OPTIMIZE TABLE} wird jetzt auf @code{REPAIR} mit Statistiken und
+Sortieren des Index-Baums gemappt. Das heißt, das es momentan nur auf
+@code{MyISAM}-Tabellen funktioniert.
+@item
+Einen pre-alloced Block zu root_malloc hinzugefügt, um weniger mallocs zu
+erhalten.
+@item
+Viele neue Statistik-Variablen hinzugefügt.
+@item
+@code{ORDER BY}-Bug bei BDB-Tabellen behoben.
+@item
+Warnungen entfernt, dass @code{mysqld} die @file{.pid}-Datei unter Windows
+nicht entfernen konnte.
+@item
+@code{--log-isam} zum Loggen von @strong{MyISAM}-Tabellen anstelle von
+isam-Tabellen abgeändert.
+@item
+@code{CHECK TABLE} funktioniert jetzt auch unter Windows.
+@item
+Datei-mutexes hinzugefügt, um @code{pwrite()} unter Windows sicher zu
+machen.
+@end itemize
+
+
+@node News-3.23.24, News-3.23.23, News-3.23.25, News-3.23.x
+@c German node Neuigkeiten-3.23.24
+@appendixsubsec Änderungen in Release 3.23.24
+
+@itemize @bullet
+@item
+@code{mysqld}-Variable @code{created_tmp_disk_tables} hinzugefügt.
+@item
+Um das verlässliche Dumpen und Wiederherstellen von Tabellen mit
+@code{TIMESTAMP(X)}-Spalten zu ermöglichen, berichtet MySQL jetzt Spalten
+mit @code{X} anders als 14 oder 8 als Zeichenketten.
+@item
+Sortierreihenfolge für latin1 abgeändert im Vergleich zu MySQL-Version vor
+3.23.23. Jede Tabelle mit @code{CHAR}-Spalten, die Zeichen mit ASCII-Werten
+größer als 128 enthalten darf, die vor Version 3.23.22 erzeugt oder
+geändert wurde, muss repariert werden!
+@item
+Kleines Speicherleck behoben, das in Version 3.23.22 beim Einfügen einer
+temporären Tabelle eingeführt wurde.
+@item
+Problem mit BDB-Tabellen und Lesen auf einem eindeutigen (nicht primären)
+Schlüssel behoben.
+@item
+Der win1251-Zeichensatz wurde wiederhergestellt (er ist jetzt nur als nicht
+empfohlen gekennzeichnet).
+@end itemize
+
+
+@node News-3.23.23, News-3.23.22, News-3.23.24, News-3.23.x
+@c German node Neuigkeiten-3.23.23
+@appendixsubsec Änderungen in Release 3.23.23
+
+@itemize @bullet
+@item
+Geänderte Sortierreihenfolge für 'deutsch'; Alle Tabellen mit 'deutscher'
+Sortierreihenfolge müssen mit @code{REPAIR TABLE} oder @code{myisamchk}
+repariert werden, bevor sie benutzt werden können!
+@item
+Option @code{--core-file} für @code{mysqld} hinzugefügt, um eine Core-Datei
+unter Linux zu erhalten, wenn @code{mysqld} durch das SIGSEGV-Signal
+stirbt.
+@item
+MySQL-Client @code{mysql} startet jetzt vorgabemäßig mit
+@code{--no-named-commands} (@code{-g}). Diese Option kann mit
+@code{--enable-named-commands} (@code{-G}) abgeschaltet werden. Das kann in
+manchen Fällen Inkompatibilitätsprobleme hervorrufen, zum Beispiel in
+SQL-Skripten, die benannte Befehle ohne Semikolon benutzen!
+Langformat-Befehle funktionieren immer noch von der ersten Zeile.
+@item
+Problem bei der Benutzung vieler anhängiger @code{DROP TABLE}-Statements
+zugleich behoben.
+@item
+Der Optimierer verwendete Schlüssel nicht korrekt bei der Benutzung von
+@code{LEFT JOIN} auf eine leere Tabelle.
+@item
+Kürzerer Hilfetext beim Aufruf von @code{mysqld} mit falschen Optionen.
+@item
+Nicht schwerwiegender @code{free()}-Bug in @code{mysqlimport} behoben.
+@item
+Bug in der @code{MyISAM}-Index-Handhabung von
+@code{DECIMAL}-/@code{NUMERIC}-Schlüsseln behoben.
+@item
+Bug beim gleichzeitigen Einfügen in @code{MyISAM}-Tabellen behoben; in
+manchen Zusammenhängen gab die Benutzung von @code{MIN(schluessel_teil)}
+oder @code{MAX(schluessel_teil)} eine leere Ergebnismenge zurück.
+@item
+@code{mysqlhotcopy} für die Benutzung der neuen @code{FLUSH TABLES
+tabellen_liste}-Syntax aktualisiert. Nur Tabellen, die gesichert werden,
+werden jetzt auf Platte zurückgeschrieben (flush).
+@item
+Verhalten von @code{--enable-thread-safe-client} so geändert, dass sowohl
+nicht gethreadete (@code{-lmysqlclient}) als auch gethreadete
+(@code{-lmysqlclient_r}) Bibliotheken eingebaut werden. Benutzer, die gegen
+ein gethreadetes @code{-lmysqlclient} linkten, müssen jetzt gegen
+@code{libmysqlclient_r} linken.
+@item
+Atomischer @code{RENAME}-Befehl hinzugefügt.
+@item
+Einträge mit @code{NULL} werden in @code{COUNT(DISTINCT ...)} nicht
+gezählt.
+@item
+@code{ALTER TABLE}, @code{LOAD DATA INFILE} auf leere Tabellen und
+@code{INSERT ... SELECT ...} auf leere Tabellen so geändert, dass nicht
+eindeutige Indexe in einem separaten Stapellauf mit Sortieren erzeugt
+werden. Das macht die genannten Aufrufe viel schneller, wenn Sie viele
+Indexe haben.
+@item
+@code{ALTER TABLE} loggt jetzt die zuerst benutzte insert_id korrekt.
+@item
+Absturz beim Hinzufügen eines Vorgabewerts zu einer @code{BLOB}-Spalte
+behoben.
+@item
+Bug bei @code{DATE_ADD/DATE_SUB} behoben, der eine DATETIME anstelle eines
+DATE zurückgab.
+@item
+Problem mit dem Thread-Cache behoben, der dazu führte, dass einige Threads
+als @code{***DEAD***} in @code{SHOW PROCESSLIST} erschienen.
+@item
+Eine Sperre in unserem thr_rwlock-Code beseitigt, die dazu führen konnte,
+dass SELECTs, die zur selben Zeit laufen wie gleichzeitige Einfügevorgänge,
+abstürzen. Das betrifft nur Systeme, die nicht den
+@code{pthread_rwlock_rdlock}-Code haben.
+@item
+Beim Löschen von Zeilen mit einem nicht eindeutigen Schlüssel in einer
+HEAP-Tabelle wurden nicht immer alle Zeilen gelöscht.
+@item
+Bug im Bereichsoptimierer für HEAP-Tabellen bei Suchen auf einem Teil-Index
+behoben.
+@item
+@code{SELECT} auf Teilschlüsseln funktioniert jetzt bei BDB-Tabellen.
+@item
+@code{INSERT INTO bdb_tabelle ... SELECT} funktioniert jetzt bei
+BDB-Tabellen.
+@item
+@code{CHECK TABLE} aktualisiert jetzt Schlüsselstatistiken für die Tabelle.
+@item
+@code{ANALYZE TABLE} aktualisiert jetzt nur Tabellen, die seit dem letzten
+@code{ANALYZE} geändert wurden. Beachten Sie, dass das ein neues Feature
+ist, und dass Tabellen nicht als analysiert gekennzeichnet werden, bis sie
+auf irgend eine Weise mit Version 3.23.23 oder neuer aktualisiert wurden.
+Bei älteren Tabellen müssen Sie @code{CHECK TABLE} ausführen, um die
+Schlüsselverteilung zu aktualisieren.
+@item
+Einige kleinere Berechtigungsprobleme bei @code{CHECK}, @code{ANALYZE},
+@code{REPAIR} und @code{SHOW CREATE} behoben.
+@item
+@code{CHANGE MASTER TO}-Befehl hinzugefügt.
+@item
+@code{FAST}-, @code{QUICK}- @code{EXTENDED}-Überprüfungsarten zu
+@code{CHECK TABLES} hinzugefügt.
+@item
+@code{myisamchk} abgeändert, so dass @code{--fast} und
+@code{--check-changed-tables} auch bei @code{--sort-index} und
+@code{--analyze} berücksichtigt werden.
+@item
+Schwerwiegenden Bug in @code{LOAD TABLE FROM MASTER} behoben, bei dem die
+Tabelle während des Neuaufbaus des Indexes nicht gesperrt wurde.
+@item
+@code{LOAD DATA INFILE} brach die Replikation ab, wenn die Datenbank aus
+der Replikation ausgeschlossen war.
+@item
+Mehr Variablen zu @code{SHOW SLAVE STATUS} und @code{SHOW MASTER STATUS}
+hinzugefügt.
+@item
+@code{SLAVE STOP} gibt jetzt solange nichts zurück, bis der Thread
+tatsächlich beendet ist.
+@item
+Volltextsuche mit der @code{MATCH}-Funktion und @code{FULLTEXT}-Indextyp
+hinzugefügt (für MyISAM-Dateien). Das macht @code{FULLTEXT} zu einem
+reservierten Wort.
+@end itemize
+
+
+@node News-3.23.22, News-3.23.21, News-3.23.23, News-3.23.x
+@c German node Neuigkeiten-3.23.22
+@appendixsubsec Änderungen in Release 3.23.22
+
+@itemize @bullet
+@item
+@code{lex_hash.h} wird jetzt für jede MySQL-Distribution korrekt erzeugt.
+@item
+@code{MASTER} und @code{COLLECTION} sind jetzt reservierte Wörter.
+@item
+Die Log-Datei, die von @code{--slow-query-log} erzeugt wird, enthielt nicht
+die gesamten Anfragen.
+@item
+Offene Transaktionen in BDB-Tabellen werden jetzt nicht mehr zurückgerollt,
+wenn die Verbindung unerwartet geschlossen wird.
+@item
+Workaround für einen Bug in @code{gcc} 2.96 (intel) und @code{gcc} 2.9
+(Ia64) in @code{gen_lex_hash.c} hinzugefügt.
+@item
+Speicherleck in der Client-Bibliothek bei der Benutzung von @code{host=} in
+der @code{my.cnf}-Datei behoben.
+@item
+Funktionen optimiert, die Stunden/Minuten/Sekunden bearbeiten.
+@item
+Bug beim Vergleich des Ergebnisses von @code{DATE_ADD()}/@code{DATE_SUB()}
+mit einer Zahl behoben.
+@item
+Bedeutung von @code{-F, --fast} für @code{myisamchk} geändert. Option
+@code{-C, --check-only-changed} für @code{myisamchk} hinzugefügt.
+@item
+@code{ANALYZE tabelle} zum Aktualisieren von Schlüsselstatistiken für
+Tabellen hinzugefügt.
+@item
+Binäreinheiten @code{0x...} abgeändert, so dass sie vorgabemäßig als
+Ganzzahlen betrachtet werden.
+@item
+Fehlerbehebung für SCO und @code{SHOW PROCESSLIST}.
+@item
+@code{auto-rehash} beim erneuten Verbinden für den @code{mysql}-Client
+hinzugefügt.
+@item
+Neu eingeführten Bug in @code{MyISAM} behoben, bei dem die Index-Datei
+nicht größer als 64 MB werden durfte.
+@item
+@code{SHOW MASTER STATUS} und @code{SHOW SLAVE STATUS} hinzugefügt.
+@end itemize
+
+
+@node News-3.23.21, News-3.23.20, News-3.23.22, News-3.23.x
+@c German node Neuigkeiten-3.23.21
+@appendixsubsec Änderungen in Release 3.23.21
+
+@itemize @bullet
+@item
+@code{mysql_character_set_name(MYSQL *mysql)}-Funktion zur MySQL-C-API
+hinzugefügt.
+@item
+Update-Log-Datei @code{ASCII 0}-sicher gemacht.
+@item
+@code{mysql_config}-Skript hinzugefügt.
+@item
+Problem bei der Benutzung von @code{<} oder @code{>} mit einer CHAR-Spalte,
+die nur teilweise indexiert war, behoben.
+@item
+Man erhielt einen Coredump, wenn die Log-Datei nicht vom MySQL-Benutzer
+lesbar war.
+@item
+@code{mysqladmin} so geändert, dass es die @code{CREATE
+DATABASE}/@code{DROP DATABASE}-Befehle anstelle der alten, nicht
+empfohlenen API-Aufrufe benutzt.
+@item
+@code{chown}-Warnung in @code{safe_mysqld} in Ordnung gebracht.
+@item
+Bug in @code{ORDER BY} behoben, der in Version 3.23.19 eingeführt wurde.
+@item
+@code{DELETE FROM tabelle} wird nur dann optimiert, ein Löschen und
+Neuerzeugen der Tabelle auszuführen, wenn man sich im
+@code{AUTOCOMMIT}-Modus befindet (benötigt für BDB-Tabellen).
+@item
+Zusätzliche Prüfungen hinzugefügt, um Index-Beschädigung zu vermeiden, wenn
+die @code{ISAM}/@code{MyISAM}-Index-Dateien während eines
+@code{INSERT}/@code{UPDATE} voll werden.
+@item
+@code{myisamchk} aktualisierte die Zeilenprüfsumme nicht korrekt, wenn es
+mit @code{-ro} benutzt wurde (sondern gab nur bei nachfolgenden Läufen eine
+Warnung aus).
+@item
+Bug in @code{REPAIR TABLE} behoben, so dass es bei Tabellen ohne Indexe
+funktioniert.
+@item
+Puffer-Überlauf in @code{DROP DATABASE} behoben.
+@item
+@code{LOAD TABLE FROM MASTER} ist ausreichend ohne Bugs, um es als Feature
+vorstellen zu können.
+@item
+@code{MATCH} und @code{AGAINST} sind jetzt reservierte Wörter.
+@end itemize
+
+
+@node News-3.23.20, News-3.23.19, News-3.23.21, News-3.23.x
+@c German node Neuigkeiten-3.23.20
+@appendixsubsec Änderungen in Release 3.23.20
+
+@itemize @bullet
+@item
+Bug in Version 3.23.19 behoben; @code{DELETE FROM tabelle} entfernte die
+.frm-Datei.
+@item
+@code{SHOW CREATE TABLE}.
+@end itemize
+
+
+@node News-3.23.19, News-3.23.18, News-3.23.20, News-3.23.x
+@c German node Neuigkeiten-3.23.19
+@appendixsubsec Änderungen in Release 3.23.19
+
+@itemize @bullet
+@item
+Copyright für alle Dateien zu GPL für den Server-Code und die
+Dienstprogramme und LGPL für die Client-Bibliotheken geändert.
+@item
+Bug behoben, bei dem nicht alle übereinstimmenden Zeilen bei einer
+@code{MyISAM}-Tabelle aktualisiert wurden, wenn man eine Aktualisierung
+basierend auf einem Schlüssel auf eine Tabelle mit vielen Schlüsseln
+durchführte, und sich einige Schlüsselwerte änderten.
+@item
+Die Linux-MySQL-RPMs und -Binärdateien werden jetzt bei einer
+Linux-Thread-Version statisch gelinkt, die schnellere mutex-Handhabung bei
+der Benutzung mit MySQL hat.
+@item
+@code{ORDER BY} kann jetzt @code{REF}-Schlüssel benutzen, um eine
+Untermenge von Zeilen zu finden, die sortiert werden müssen.
+@item
+Der Name von @code{print_defaults} wurde in @code{my_print_defaults}
+geändert, um Namenskonflikte zu vermeiden.
+@item
+@code{NULLIF()} funktioniert jetzt gemäß ANSI-SQL99.
+@item
+@code{net_read_timeout} und @code{net_write_timeout} als Startparameter für
+@code{mysqld} hinzugefügt.
+@item
+Bug behoben, der den Index bei der Ausführung von @code{myisamchk
+--sort-records} auf eine Tabelle mit Präfix-komprimiertem Index zerstörte.
+@item
+pack_isam und myisampack zur Standard-MySQL-Distribution hinzugefügt.
+@item
+Die Syntax @code{BEGIN WORK} hinzugefügt (dasselbe wie @code{BEGIN}).
+@item
+Coredump-Bug bei der Benutzung von @code{ORDER BY} auf
+@code{CONV()}-Ausdruck behoben.
+@item @code{LOAD TABLE FROM MASTER} hinzugefügt.
+@item @code{FLUSH MASTER} und @code{FLUSH SLAVE} hinzugefügt.
+@item Großes/kleines 'endian'-Problem in der Replikation behoben.
+@end itemize
+
+
+@node News-3.23.18, News-3.23.17, News-3.23.19, News-3.23.x
+@c German node Neuigkeiten-3.23.18
+@appendixsubsec Änderungen in Release 3.23.18
+
+@itemize @bullet
+@item
+Problem aus Version 3.23.17 bei der Auswahl eines Zeichensatzes auf der
+Client-Seite behoben.
+@item
+@code{FLUSH TABLES with READ LOCK} geändert, so dass es eine globale Sperre
+macht, die für das Herstellen einer Kopie der MySQL-Daten-Dateien geeignet
+ist.
+@item
+@code{CREATE TABLE ... SELECT ... PROCEDURE} funktioniert jetzt.
+@item
+Interne temporäre Tabellen benutzen jetzt einen komprimierten Index bei der
+Benutzung von @code{GROUP BY} auf @code{VARCHAR/CHAR}-Spalten.
+@item
+Problem behoben beim Sperren derselbe Tabelle mit einer @code{READ}- und
+einer @code{WRITE}-Sperre.
+@item
+Problem mit myisamchk und @code{RAID}-Tabellen behoben.
+@end itemize
+
+
+@node News-3.23.17, News-3.23.16, News-3.23.18, News-3.23.x
+@c German node Neuigkeiten-3.23.17
+@appendixsubsec Änderungen in Release 3.23.17
+
+@itemize @bullet
+@item
+Bug in @code{find_in_set()} behoben, wenn das erste Argument @code{NULL}
+war.
+@item
+Tabellensperren für Berkeley-DB hinzugefügt.
+@item
+Bug bei @code{LEFT JOIN} und @code{ORDER BY} behoben, bei dem die erste
+Tabelle nur eine übereinstimmende Zeile hatte.
+@item
+4 @code{my.cnf}-Beispiel-Dateien im @file{Support-files}-Verzeichnis
+hinzugefügt.
+@item
+@code{duplicated key}-Problem bei der Ausführung großer @code{GROUP BY}s
+behoben. (Dieser Bug wurde wahrscheinlich in Version 3.23.15 eingeführt).
+@item
+Syntax für @code{INNER JOIN} geändert, um ANSI-SQL zu entsprechen.
+@item
+@code{NATURAL JOIN}-Syntax hinzugefügt.
+@item
+Viele Korrekturen in der @code{BDB}-Schnittstelle.
+@item
+Handhabung von @code{--no-defaults} und @code{--defaults-file} für
+@code{safe_mysqld.sh} und @code{mysql_install_db.sh} hinzugefügt.
+@item
+Bug beim Lesen komprimierter Tabellen mit vielen Threads behoben.
+@item
+@code{USE INDEX} funktioniert jetzt mit @code{PRIMARY}-Schlüsseln.
+@item
+@code{BEGIN}-Statement geändert, so dass es eine Transaktion im
+@code{AUTOCOMMIT}-Modus startet.
+@item
+Symbolische-Links-Unterstützung für Windows.
+@item
+Protokoll geändert, so dass der Client weiß, ob der Server im AUTOCOMMIT-
+Modus ist und ob es eine anhängige Transaktion gibt. Wenn das der Fall ist,
+gibt die Client-Bibliothek einen Fehler aus, bevor sie sich wieder mit dem
+Server verbindet, damit der Client weiß, dass der Server ein Rollback
+durchgeführt hat. Das Protokoll ist noch abwärtskompatibel mit den alten
+Clients.
+@item
+@code{KILL} funktioniert jetzt auf einem Thread, der durch ein 'Schreiben'
+auf einen toten Client gesperrt ist.
+@item
+Speicherleck im Replikations-Slave-Thread behoben.
+@item
+Neue Option @code{log-slave-updates} hinzugefügt, die das
+Hintereinanderhängen im Kreis (Daisy-Chaining, 'Ringelrei') von Slaves
+erlaubt.
+@item
+Compile-Fehler auf FreeBSD und anderen Systemen behoben, auf denen
+@code{pthread_t} nicht dasselbe wie @code{int} ist.
+@item
+Herunterfahren des Masters bricht den Slave-Thread nicht mehr ab.
+@item
+Race-Bedingung im @code{INSERT DELAYED}-Code beim Ausführen von @code{ALTER
+TABLE} behoben.
+@item
+Blockierungsüberprüfung für @code{INSERT DELAYED} hinzugefügt.
+@end itemize
+
+
+@node News-3.23.16, News-3.23.15, News-3.23.17, News-3.23.x
+@c German node Neuigkeiten-3.23.16
+@appendixsubsec Änderungen in Release 3.23.16
+
+@itemize @bullet
+@item
+Option @code{TYPE=QUICK} für @code{CHECK} und @code{REPAIR} hinzugefügt.
+@item
+Bug in @code{REPAIR TABLE} behoben, wenn die Tabelle durch einen anderen
+Thread in Benutzung war.
+@item
+Einen Thread-Cache hinzugefügt, um zu ermöglichen, MySQL mit @code{gdb} zu
+debuggen, wenn man viele erneute Verbindungen durchführt. Das verbessert
+auch Systeme, auf denen man keine persistenten Verbindungen benutzen kann.
+@item
+Viele Korrekturen in der Berkeley-DB-Schnittstelle.
+@item
+@code{UPDATE IGNORE} bricht jetzt nicht mehr ab, wenn eine Aktualisierung
+zu einem @code{DUPLICATE_KEY}-Fehler führt.
+@item
+@code{CREATE TEMPORARY TABLE}-Befehle werden in die Update-Log-Datei
+geschrieben.
+@item
+Bug bei der Handhabung von maskierten IP-Nummern in den
+Berechtigungstabellen behoben.
+@item
+Bug mit @code{delayed_key_writes}-Tabellen und @code{CHECK TABLE} behoben.
+@item
+@code{replicate-do-db} und @code{replicate-ignore-db}-Optionen hinzugefügt,
+um auf Datenbanken zu beschränken, die repliziert werden.
+@item
+@code{SQL_LOG_BIN}-Option hinzugefügt.
+@end itemize
+
+
+@node News-3.23.15, News-3.23.14, News-3.23.16, News-3.23.x
+@c German node Neuigkeiten-3.23.15
+@appendixsubsec Änderungen in Release 3.23.15
+
+@itemize @bullet
+@item
+Um @code{mysqld} als @code{root} zu starten, müssen Sie jetzt die @code{--
+user=root}-Option benutzen.
+@item
+Schnittstelle zu Berkeley-DB hinzugefügt. (Diese funktioniert noch nicht
+richtig. Spielen Sie mit ihr auf eigenes Risiko herum!)
+@item
+Replikation zwischen Master und Slaves hinzugefügt.
+@item
+Bug behoben, bei dem ein anderer Thread eine Sperre stehlen konnte, wenn
+ein Thread eine Sperre auf eine Tabelle hatte und einen @code{FLUSH
+TABLES}-Befehl ausführte.
+@item
+Die @code{slow_launch_time}-Variable und die
+@code{slow_launch_thread}-Status-Variable zu @code{mysqld} hinzugefügt.
+Diese können mit @code{mysqladmin variables} und @code{mysqladmin
+extended-status} betrachtet werden.
+@item
+Funktionen @code{INET_NTOA()} und @code{INET_ATON()} hinzugefügt.
+@item
+Der vorgabemäßige Typ von @code{IF()} hängt jetzt vom zweiten und dritten
+Argument ab und nicht nur vom zweiten.
+@item
+Fall behoben, bei dem @code{myisamchk} beim Versuch, eine Tabelle zu
+reparieren, in eine Schleife geraten konnte.
+@item
+@code{INSERT DELAYED} nicht in die Update-Log-Datei schreiben, wenn
+@code{SQL_LOG_UPDATE=0}.
+@item
+Problem mit @code{REPLACE} auf @code{HEAP}-Tabellen behoben.
+@item
+Mögliche Zeichensätze und Zeitzone zu @code{SHOW VARIABLES} hinzugefügt.
+@item
+Bug im Sperr-Code behoben, der zu Sperrproblemen bei gleichzeitigen
+Einfügevorgängen unter hoher Last führen konnte.
+@item
+Problem bei @code{DELETE} vieler Zeilen auf eine Tabelle mit komprimierten
+Schlüsseln behoben, bei dem MySQL den Index scannte, um Zeilen zu finden.
+@item
+Problem mit @code{CHECK} auf Tabelle mit gelöschten Schlüsselblöcken
+behoben.
+@item
+Bug beim Neuverbinden (auf der Client-Seite) behoben, bei dem in manchen
+Situationen Speicher nicht freigegeben wurde.
+@item
+Probleme in der Update-Log-Datei bei der Benutzung von
+@code{LAST_INSERT_ID()} zum Aktualisieren einer Tabelle mit einem
+auto_increment-Schlüssel behoben.
+@item
+Funktion @code{NULLIF()} hinzugefügt.
+@item
+Bug bei der Benutzung von @code{LOAD DATA INFILE} auf eine Tabelle mit
+@code{BLOB/TEXT}-Spalten behoben.
+@item
+MyISAM optimiert, um es beim Einfügen von Schlüsseln in sortierter
+Reihenfolge schneller zu machen.
+@item
+@code{EXPLAIN SELECT ...} gibt jetzt auch aus, ob MySQL eine temporäre
+Tabelle oder Dateisortieren verwendet, wenn das @code{SELECT} aufgelöst
+wird.
+@item
+Optimierung hinzugefügt, um @code{ORDER BY}-Teile zu überspringen, bei
+denen der Teil ein konstanter Ausdruck im @code{WHERE}-Teil ist. Indexe
+können jetzt benutzt werden, selbst wenn das @code{ORDER BY} nicht genau
+mit dem Index übereinstimmt, solange alle nicht benutzten Index-Teile und
+alle zusätzlichen @code{ORDER BY}-Spalten Konstanten in der
+@code{WHERE}-Klausel sind. @xref{MySQL indexes}.
+@item
+@code{UPDATE} und @code{DELETE} auf einen gesamten eindeutigen Schlüssel im
+@code{WHERE}-Teil ist jetzt schneller als vorher.
+@item
+@code{RAID_CHUNKSIZE} so geändert, dass es in 1024 Bytes inkrementiert.
+@item
+Coredump in LOAD_FILE(NULL) behoben.
+@end itemize
+
+
+@node News-3.23.14, News-3.23.13, News-3.23.15, News-3.23.x
+@c German node Neuigkeiten-3.23.14
+@appendixsubsec Änderungen in Release 3.23.14
+
+@itemize @bullet
+@item
+Bug in @code{CONCAT()} behoben, bei dem eins der Argumente eine Funktion
+war, die ein verändertes Argument zurückgab.
+@item
+Kritischen Bug in @code{myisamchk} behoben, wobei es den Header in der
+Index-Datei aktualisierte, wenn man die Tabelle nur prüfte. Das brachte den
+@code{mysqld}-Daemon durcheinander, wenn er dieselbe Tabelle zur gleichen
+Zeit aktualisierte. Jetzt wird der Status in der Index-Datei nur dann
+aktualisiert, wenn man @code{--update-state} benutzt. Bei älteren
+@code{myisamchk}-Versionen sollten Sie @code{--read-only} benutzen, wenn
+Sie Tabellen nur prüfen, wenn es auch nur die geringste Chance gibt, dass
+der @code{mysqld}-Server zur gleichen Zeit auf der Tabelle arbeitet!
+@item
+@code{DROP TABLE} wird nicht mehr in der Update-Log-Datei geloggt.
+@item
+Problem beim Suchen auf @code{DECIMAL()}-Schlüsselfeld behoben, wenn die
+Spalte Daten mit führenden Nullen enthielt.
+@item
+Bug in @code{myisamchk} behoben, wenn auto_increment nicht der erste
+Schlüssel ist.
+@item
+@code{DATETIME} wird im ISO-8601-Format zugelassen: 2000-03-12T12:00:00
+@item
+Dynamische Zeichensätze hinzugefügt. Eine @code{mysqld}-Binärdatei kann
+jetzt viele unterschiedliche Zeichensätze handhaben (welche, können Sie
+beim Start von @code{mysqld} angeben).
+@item
+Befehl @code{REPAIR TABLE} hinzugefügt.
+@item
+C-API-Funktion @code{mysql_thread_safe()} hinzugefügt.
+@item
+@code{UMASK_DIR}-Umgebungsvariable hinzugefügt.
+@item
+Funktion @code{CONNECTION_ID()} hinzugefügt.
+@item
+Bei der Benutzung von @code{=} auf @code{BLOB}- oder @code{VARCHAR
+BINARY}-Schlüsseln, bei denen nur ein Teil der Spalte indexiert war, wurde
+nicht die gesamte Spalte der Ergebniszeile verglichen.
+@item
+Problembehebung für sjis-Zeichensatz und @code{ORDER BY}.
+@item
+Beim Laufenlassen im ANSI-Modus wird nicht mehr zugelassen, dass Spalten
+benutzt werden, die nicht im @code{GROUP BY}-Teil angegeben wurden.
+@end itemize
+
+
+@node News-3.23.13, News-3.23.12, News-3.23.14, News-3.23.x
+@c German node Neuigkeiten-3.23.13
+@appendixsubsec Änderungen in Release 3.23.13
+
+@itemize @bullet
+@item
+Problem behoben bei der Ausführung von Sperren auf dieselbe Tabelle mehr
+als zweimal im selben @code{LOCK TABLE}-Befehl. Dadurch wurde das Problem
+behoben, das man bekam, wenn man test-ATIS test mit @code{--fast} oder
+@code{--check-only-changed} laufen ließ.
+@item
+Option @code{SQL_Puffer_RESULT} für @code{SELECT} hinzugefügt.
+@item
+Leerzeichen am Ende von Double-/Float-Zahlen in Ergebnissen aus temporären
+Tabellen entfernt.
+@code{CHECK TABLE}-Befehl hinzugefügt.
+@item
+Änderungen für MyISAM in Version 3.23.12 hinzugefügt, die wegen
+CVS-Problemen nicht in die Quelldistribution gelangten.
+@item
+Bug behoben, so dass @code{mysqladmin shutdown} darauf wartet, dass der
+lokale Server herunter fährt.
+@item
+Mögliche Endlosschleife bei der Zeitstempel-Berechnung repariert.
+@item
+@code{print_defaults} für die @file{.rpm}-Dateien hinzugefügt.
+@code{mysqlbug} aus der Client-@file{.rpm}-Datei entfernt.
+@end itemize
+
+
+@node News-3.23.12, News-3.23.11, News-3.23.13, News-3.23.x
+@c German node Neuigkeiten-3.23.12
+@appendixsubsec Änderungen in Release 3.23.12
+
+@itemize @bullet
+@item
+Bug in @code{MyISAM} behoben, bei dem @code{REPLACE ... SELECT ...} eine
+beschädigte Tabelle ergeben konnte.
+@item
+Bug in @code{myisamchk} behoben, bei dem der auto_increment-Wert falsch
+zurückgesetzt wurde.
+@item
+VIELE Patches für Linux Alpha. MySQL scheint mittlerweile auf Linux Alpha
+relativ stabil zu laufen.
+@item
+@code{DISTINCT} auf @code{HEAP} temporäre Tabellen so geändert, dass
+gehashte Schlüssel verwendet werden, um doppelte Zeilen (Duplikate) schnell
+zu finden. Das betrifft meistens Anfragen des Typs @code{SELECT DISTINCT
+... GROUP BY ...}. Das behebt ein Problem, bei dem nicht alle Duplikate in
+Anfragen des genannten Typs entfernt wurden. Zusätzlich ist der neue Code
+VIEL schneller.
+@item
+Patches hinzugefügt, damit MySQL auf Mac OS X kompiliert.
+@item
+Option @code{IF NOT EXISTS} für @code{CREATE DATABASE} hinzugefügt.
+@item
+Optionen @code{--all-databases} und @code{--databases} für @code{mysqldump}
+hinzugefügt, um das Dumpen vieler Datenbanken zugleich zu ermöglichen.
+@item
+Bug im komprimierten @code{DECIMAL()}-Index in @code{MyISAM}-Tabellen
+behoben.
+@item
+Bug beim Speichern von 0 in ein Timestamp-Feld behoben.
+@item
+Beim Ausführen von @code{mysqladmin shutdown} auf eine lokale Verbindung
+wartet @code{mysqladmin} jetzt, bis die PID-Datei entfernt ist, bevor es
+sich beendet.
+@item
+Coredump bei einigen @code{COUNT(DISTINCT ...)}-Anfragen behoben.
+@item
+@code{myisamchk} funktioniert jetzt sauber bei RAID-Tabellen.
+@item
+Problem bei @code{LEFT JOIN} und @code{schluessel_feld IS NULL} behoben.
+@item
+Bug in @code{net_clear()} behoben, der den Fehler @code{Aborted connection}
+in MySQL-Clients ausgeben konnte.
+@item
+Optionen @code{USE INDEX (schluessel_liste)} und @code{IGNORE INDEX
+(schluessel_liste)} als Join-Parameter in @code{SELECT} hinzugefügt.
+@item
+@code{DELETE} und @code{RENAME} sollten jetzt auf @code{RAID}-Tabellen
+funktionieren.
+@end itemize
+
+
+@node News-3.23.11, News-3.23.10, News-3.23.12, News-3.23.x
+@c German node Neuigkeiten-3.23.11
+@appendixsubsec Änderungen in Release 3.23.11
+
+@itemize @bullet
+@item
+@code{ALTER TABLE tabelle ADD (feld_liste)}-Syntax wird zugelassen.
+@item
+Problem mit dem Optimierer behoben, der manchmal falsche Schlüssel
+benutzte.
+@item
+@code{GRANT/REVOKE ALL PRIVILEGES} betrifft jetzt nicht mehr @code{GRANT
+OPTION}.
+@item
+Zusätzliche Klammer (@code{)}) aus der Ausgabe von @code{SHOW GRANTS}
+entfernt.
+@item
+Problem beim Speichern von Zahlen in Timestamps behoben.
+@item
+Problem mit Zeitzonen behoben, die einen Halbstunden-Offset haben.
+@item
+Syntax @code{UNIQUE INDEX} in @code{CREATE}-Statements wird jetzt
+zugelassen.
+@item
+@code{mysqlhotcopy} hinzugefügt. Das ist ein schnelles
+Online-Datensicherungsdienstprogramm für lokale MySQL-Datenbanken. Von Tim
+Bunce.
+@item
+Neues, sichereres @code{mysqlaccess} hinzugefügt. Dank an Steve Harvey
+hierfür.
+@item
+Optionen @code{--i-am-a-dummy} und @code{--safe-updates} für @code{mysql}
+hinzugefügt.
+@item
+Variablen @code{select_limit} und @code{max_join_size} für @code{mysql}
+hinzugefügt.
+@item
+SQL-Variablen @code{SQL_MAX_JOIN_SIZE} und @code{SQL_SAFE_UPDATES}
+hinzugefügt.
+@item
+@code{READ LOCAL}-Sperre hinzugefügt, die die Tabelle nicht für
+gleichzeitige Einfügevorgänge sperrt (das wird von @code{mysqldump}
+benutzt).
+@item
+@code{LOCK TABLES ... READ} läßt keine gleichzeitigen Einfügevorgänge mehr
+zu.
+@item
+Option @code{--skip-delay-key-write} für @code{mysqld} hinzugefügt.
+@item
+Sicherheitsproblem im Protokoll betreffend Passwortüberprüfung behoben.
+@item
+@code{_rowid} kann jetzt als Alias für eine eindeutig indexierte Spalte vom
+Typ Ganzzahl benutzt werden.
+@item
+Zurück-Blockieren (Back Blocking) für @code{SIGPIPE} beim Kompilieren mit
+@code{--thread-safe-clients} hinzugefügt, um Dinge für alte Clients sicher
+zu machen.
+@end itemize
+
+
+@node News-3.23.10, News-3.23.9, News-3.23.11, News-3.23.x
+@c German node Neuigkeiten-3.23.10
+@appendixsubsec Änderungen in Release 3.23.10
+
+@itemize @bullet
+@item
+Bug in Version 3.23.9 behoben, bei dem Speicher nicht korrekt freigegeben
+wurde, wenn man @code{LOCK TABLES} ausführte.
+@end itemize
+
+
+@node News-3.23.9, News-3.23.8, News-3.23.10, News-3.23.x
+@c German node Neuigkeiten-3.23.9
+@appendixsubsec Änderungen in Release 3.23.9
+
+@itemize @bullet
+@item
+Problem behoben, dass betroffene Anfragen Berechnungen auf
+Gruppenfunktionen durchführten.
+@item
+Problem mit timestamps und @code{INSERT DELAYED} behoben.
+@item
+@code{datum_spalte BETWEEN konstanten_datum AND konstanten_datum}
+funktioniert.
+@item
+Problem behoben, wenn man nur eine 0 zu @code{NULL} in einer Tabelle mit
+@code{BLOB/TEXT}-Spalten änderte.
+@item
+Bug im Bereichsoptimierer bei der Benutzung von vielen Schlüsselteilen und
+/ oder den mittleren Schlüsselteilen behoben: @code{WHERE K1=1 and K3=2 and
+(K2=2 and K4=4 or K2=3 and K4=5)}
+@item
+Befehl @code{source} für @code{mysql} hinzugefügt, um Lesen von
+Stapeldateien innerhalb des @code{mysql}-Clients zu ermöglichen.
+Original-Patch von Matthew Vanecek.
+@item
+Kritisches Problem mit der @code{WITH GRANT OPTION}-Option behoben.
+@item
+Keinen unnötigen @code{GRANT}-Fehler bei der Benutzung von Tabellen von
+vielen Datenbanken in derselben Anfrage ausgeben.
+@item
+VIO-Wrapper (benötigt für SSL-Unterstützung) hinzugefügt. Von Andrei
+Errapart und Tõnu Samuel).
+@item
+Optimiererproblem bei @code{SELECT} bei der Benutzung von vielen
+überlappenden Indexen behoben. MySQL sollte jetzt in der Lage sein,
+Schlüssel noch besser auszusuchen, wenn es viele Schlüssel zur Auswahl
+gibt.
+@item
+Optimierer so geändert, dass er einen Bereichsschlüssel anstelle eines
+Verweisschlüssels bevorzugt, wenn der Bereichsschlüssel mehr Spalten als
+der Verweisschlüssel benutzen kann (der nur Spalten mit = verwenden
+kann). Folgender Anfragentyp beispielsweise sollte jetzt schneller sein:
+@code{SELECT * from schluessel_teil_1=konstante und schluessel_teil_2 >
+konstante2}
+@item
+Bug behoben, bei dem eine Änderung aller @code{VARCHAR}-Spalten in
+@code{CHAR}-Spalten den Spaltentyp nicht von dynamisch auf fest änderte.
+@item
+Fließkomma-Ausnahmefehler für FreeBSD abgeschaltet, um Coredump beim
+Ausführen von @code{SELECT floor(pow(2,63))} zu vermeiden.
+@item
+@code{mysqld}-Startoption @code{--delay-key-write} in
+@code{--delay-key-write-for-all-tables} geändert.
+@item
+@code{read-next-on-key} für @code{HEAP}-Tabellen hinzugefügt. Das sollte
+alle Probleme mit @code{HEAP}-Tabellen bei der Benutzung von
+Nicht-@code{UNIQUE}-Schlüsseln beheben.
+@item
+Optionen für die Ausgabe vorgabemäßiger Argumente für alle Clients
+hinzugefügt.
+@item
+@code{--log-slow-queries} für @code{mysqld} hinzugefügt, um alle Anfragen
+in einer separate Log-Datei zu loggen, die lange dauerten, mit einer
+Zeitangabe, wie lange die Anfrage benötigte.
+@item
+Coredump bei der Ausführung von @code{WHERE schluessel_spalte=RAND(...)}
+behoben.
+@item
+Optimierungs-Bug in @code{SELECT ... LEFT JOIN ... schluessel_spalte IS
+NULL} behoben, wenn @code{schluessel_spalte} @code{NULL}-Werte enthalten
+konnte.
+@item
+Problem mit 8-Bit-Zeichen als Trennzeichen in @code{LOAD DATA INFILE}
+behoben.
+@end itemize
+
+
+@node News-3.23.8, News-3.23.7, News-3.23.9, News-3.23.x
+@c German node Neuigkeiten-3.23.8
+@appendixsubsec Änderungen in Release 3.23.8
+
+@itemize @bullet
+@item
+Problem bei der Handhabung von Index-Dateien größer als 8 GB behoben.
+@item
+neueste Patches für mit-pThread für NetBSD angewandt.
+@item
+Probleme mit Zeitzonen < GMT - 11 behoben.
+@item
+Bug beim Löschen komprimierter Schlüssel in @code{MyISAM} behoben.
+@item
+Problem mit @code{ISAM} bei der Ausführung einiger @code{ORDER BY ...
+DESC}-Anfragen behoben.
+@item
+Bug bei der Ausführung eines Joins auf einen Text-Schlüssel behoben, der
+nicht den gesamten Schlüssel abdeckte.
+@item
+Option @code{--delay-key-write} schaltete verzögertes Schlüssel-Schreiben
+nicht an.
+@item
+Aktualisierung von @code{TEXT}-Spalten, die nur Änderungen der
+Groß-/Kleinschreibung beinhalteten, in Ordnung gebracht.
+@item
+@code{INSERT DELAYED} aktualisiert jetzt Timestamps, die angegeben sind.
+@item
+Funktion @code{YEARWEEK()} und Optionen @code{x}, @code{X}, @code{v} und
+@code{V} für @code{DATE_FORMAT()} hinzugefügt.
+@item
+Problem mit @code{MAX(indexierte_spalte)} und HEAP-Tabellen behoben.
+@item
+Problem mit @code{BLOB NULL}-Schlüsseln und @code{LIKE} "praefix%"
+behoben.
+@item
+Problem mit @code{MyISAM} und Zeilen fester Länge < 5 Bytes behoben.
+@item
+Problem behoben, bei dem es vorkommen konnte, dass MySQL auf freigegebenen
+Speicher zugriff, wenn er sehr komplizierte @code{GROUP BY}-Anfragen
+ausführte.
+@item
+Coredump behoben, wenn man eine beschädigte Tabelle erhielt, in der ein
+@code{ENUM}-Feldwert zu Groß war.
+@end itemize
+
+
+@node News-3.23.7, News-3.23.6, News-3.23.8, News-3.23.x
+@c German node Neuigkeiten-3.23.7
+@appendixsubsec Änderungen in Release 3.23.7
+
+@itemize @bullet
+@item
+Workaround unter Linux in Ordnung gebracht, um Probleme mit
+@code{pthread_mutex_timedwait}, was bei @code{INSERT DELAYED} benutzt wird,
+zu vermeiden. @xref{Linux}.
+@item
+Man erhält jetzt einen 'disk full'-Fehler, wenn die Festplatten beim
+Sortieren voll wird (statt darauf zu warten, bis mehr Plattenplatz
+verfügbar ist).
+@item
+Bug in @code{MyISAM} mit Schlüsseln > 250 Zeichen behoben.
+@item
+In @code{MyISAM} kann man jetzt ein @code{INSERT} zur selben Zeit
+durchführen, in der andere Threads aus der Tabelle lesen.
+@item
+Variable @code{max_write_lock_count} für @code{mysqld} hinzugefügt, um eine
+@code{READ}-Sperre nach einer bestimmten Anzahl von @code{WRITE}-Sperren zu
+erzwingen.
+@item
+Flag @code{delayed_key_write} bei @code{show variables} invertiert.
+@item
+Variable @code{concurrency} in @code{thread_concurrency} umbenannt.
+@item
+Folgende Funktionen sind jetzt Multi-Byte-sicher:
+@code{LOCATE(teilzeichenfolge,zeichenkette)},
+@code{POSITION(teilzeichenfolge IN zeichenkette)},
+@code{LOCATE(teilzeichenfolge,zeichenkette,position)},
+@code{INSTR(zeichenkette,teilzeichenfolge)},
+@code{LEFT(zeichenkette,laenge)}, @code{RIGHT(zeichenkette,laenge)},
+@code{SUBSTRING(zeichenkette,pos,laenge)}, @code{SUBSTRING(zeichenkette
+FROM position FOR laenge)}, @code{MID(zeichenkette,position,laenge)},
+@code{SUBSTRING(zeichenkette,position)}, @code{SUBSTRING(zeichenkette FROM
+pos)}, @code{SUBSTRING_INDEX(zeichenkette,begrenzer,zaehler)},
+@code{RTRIM(zeichenkette)}, @code{TRIM([[BOTH | TRAILING]
+[entfernzeichenkette] FROM] zeichenkette)},
+@code{REPLACE(zeichenkette,from_zeichenkette,to_zeichenkette)},
+@code{REVERSE(zeichenkette)},
+@code{INSERT(zeichenkette,pos,laenge,newstr)}, @code{LCASE(zeichenkette)},
+@code{LOWER(zeichenkette)}, @code{UCASE(zeichenkette)} und
+@code{UPPER(zeichenkette)}. Patch von Wei He.
+@item
+Coredump beim Aufheben einer Sperre von einer nicht existierenden Tabelle
+behoben.
+@item
+Sperren auf Tabellen werden jetzt entfernt, bevor Duplikate entfernt
+werden.
+@item
+Option @code{FULL} für @code{SHOW PROCESSLIST} hinzugefügt.
+@item
+Option @code{--verbose} für @code{mysqladmin} hinzugefügt.
+@item
+Problem beim automatischen Umwandeln von HEAP in MyISAM behoben.
+@item
+Bug in HEAP-Tabellen behoben, wenn man INSERT + DELETE + INSERT + Scannen
+der Tabelle ausführt.
+@item
+Bugs auf Alpha mit @code{REPLACE()} und @code{LOAD DATA INFILE} behoben.
+@item
+@code{mysqld}-Variable @code{interactive_timeout} hinzugefügt.
+@item
+Argument für @code{mysql_data_seek()} von @code{ulong} zu @code{ulonglong}
+geändert.
+@end itemize
+
+
+@node News-3.23.6, News-3.23.5, News-3.23.7, News-3.23.x
+@c German node Neuigkeiten-3.23.6
+@appendixsubsec Änderungen in Release 3.23.6
+
+@itemize @bullet
+@item
+@code{mysqld}-Option @code{-O lower_case_tables=@{0|1@}} hinzugefügt, damit
+Benutzer Tabellennamen to Kleinschreibung erzwingen können.
+@item
+@code{SELECT ... INTO DUMPFILE} hinzugefügt.
+@item
+@code{mysqld}-Option @code{--ansi} hinzugefügt, um einige Funktionen
+@code{ANSI-SQL}-kompatibler zu machen.
+@item
+Temporäre Tabellen fangen jetzt mit @code{#sql} an.
+@item
+Quoten von Bezeichnern mit @code{`} (@code{"} im @code{--ansi}-Modus).
+@item
+Jetzt wird snprintf() bei der Ausgabe von Fließkommazahlen benutzt, um
+einige Puffer-Überläufe unter FreeBSD zu vermeiden.
+@item
+@code{[floor()} überlaufsicher unter FreeBSD gemacht.
+@item
+Option @code{--quote-names} für @code{mysqldump} hinzugefügt.
+@item
+Bug behoben, dass man einen Teil eines @code{PRIMARY KEY NOT NULL} machen
+konnte.
+@item
+@code{encrypt()} in Ordnung gebracht, um Thread-sicher zu sein und Puffer
+nicht erneut zu benutzen.
+@item
+@code{mysql_odbc_escape_string()}-Funktion zur Unterstützung von
+big5-Zeichen in MyODBC hinzugefügt.
+@item
+Die Tabellen-Handler wurden umgeschrieben und benutzen jetzt Klassen.
+Hierdurch wird viel neuer Code eingeführt, aber die Tabellenhandhabung wird
+schneller und besser.
+@item
+Patch von Sasha für benutzerdefinierte Variablen angewandt.
+@item
+@code{FLOAT} und @code{DOUBLE} (ohne jeden Längen-Modifikator) sind jetzt
+keine festen Dezimalpunkt-Zahlen mehr.
+@item
+Die Bedeutung von @code{FLOAT(X)} wurde geändert: Jetzt ist das dasselbe
+wie @code{FLOAT}, wenn X <= 24, und @code{DOUBLE}, wenn 24 < X <= 53.
+@item
+@code{DECIMAL(X)} ist jetzt ein Alias für @code{DECIMAL(X,0)}, und
+@code{DECIMAL} ist jetzt ein Alias für @code{DECIMAL(10,0)}. Dasselbe gilt
+für @code{NUMERIC}.
+@item
+Option @code{ROW_FORMAT=@{default | dynamic | static | compressed@}} für
+@code{CREATE_TABLE} hinzugefügt.
+@item
+@code{DELETE FROM tabelle} funktionierte nicht auf temporären Tabellen.
+@item
+Funktion @code{CHAR_LENGTH()} geändert, so dass sie
+Multi-Byte-Zeichen-sicher ist.
+@item
+Funktion @code{ORD(zeichenkette)} hinzugefügt.
+@end itemize
+
+
+@node News-3.23.5, News-3.23.4, News-3.23.6, News-3.23.x
+@c German node Neuigkeiten-3.23.5
+@appendixsubsec Änderungen in Release 3.23.5
+
+@itemize @bullet
+@item
+Einige Jahr-2000-Probleme in der neuen Daten-Handhabung in Version 3.23
+behoben.
+@item
+Problem mit @code{SELECT DISTINCT ... ORDER BY RAND()} behoben.
+@item
+Patches von Sergei A. Golubchik für Textsuche auf MyISAM-Ebene angewandt.
+@item
+Cache-Überlaufproblem bei der Benutzung von Full Joins ohne Schlüssel
+behoben.
+@item
+Einige configure-Probleme bereinigt.
+@item
+Einige kleine Änderungen, um das Parsen schneller zu machen.
+@item
+@code{ALTER TABLE} + Hinzufügen einer Spalte nach dem letzten Feld
+funktionierte nicht.
+@item
+Problem bei der Benutzung einer auto_increment-Spalte in zwei Schlüsseln
+behoben.
+@item
+Bei MyISAM kann man jetzt den auto_increment-Teil als Untermenge haben:
+@code{CREATE TABLE foo (a int not null auto_increment, b char(5), primary
+key (b,a))}
+@item
+Bug in MyISAM mit komprimierten CHAR-Schlüsseln, die @code{NULL} sein
+konnten, behoben.
+@item
+@code{AS} auf Feldname mit @code{CREATE TABLE tabelle SELECT ...}
+funktionierte nicht.
+@item
+Benutzung von @code{NATIONAL} und @code{NCHAR} bei der Definition von
+Zeichenspalten wird zugelassen. Das ist dasselbe, als wenn man
+@code{BINARY} nicht benutzt.
+@item
+Keine @code{NULL}-Spalten in einem @code{PRIMARY KEY} zulassen (nur in
+@code{UNIQUE}-Schlüsseln).
+@item
+@code{LAST_INSERT_ID} wird gelöscht (clear), wenn man diese in ODBC
+benutzt: @code{WHERE auto_increment_spalte IS NULL}. Das scheint einige
+Probleme mit Access zu beheben.
+@item
+@code{SET SQL_AUTO_IS_NULL=0|1} schaltet jetzt die Handhabung von Suchen
+nach der letzten eingefügten Zeile bei @code{WHERE auto_increment_spalte IS
+NULL} aus / an.
+@item
+Neue @code{mysqld}-Variable @code{concurrency} für Solaris hinzugefügt.
+@item
+Option @code{--relative} für @code{mysqladmin} hinzugefügt, um mit
+@code{extended-status} eine bessere Beobachtung von Änderungen zu erzielen.
+@item
+Bug bei der Benutzung von @code{COUNT(DISTINCT ...)} auf eine leere Tabelle
+behoben.
+@item
+Unterstützung für den chinesischen Zeichensatz GBK hinzugefügt.
+@item
+Problem mit @code{LOAD DATA INFILE} und @code{BLOB}-Spalten behoben.
+@item
+Bit-Operator @code{~} (Negation) hinzugefügt.
+@item
+Problem mit @code{UDF}-Funktionen behoben.
+@end itemize
+
+
+@node News-3.23.4, News-3.23.3, News-3.23.5, News-3.23.x
+@c German node Neuigkeiten-3.23.4
+@appendixsubsec Änderungen in Release 3.23.4
+
+@itemize @bullet
+@item
+Einfügen eines @code{DATETIME}-Werts in eine @code{TIME}-Spalte versucht
+jetzt nicht mehr, darin 'Tage' zu speichern.
+@item
+Problem mit der Speicherung von Float / Double auf kleinen Endian-Maschinen
+behoben (das betraf @code{SUM()}).
+@item
+Verbindungs-Zeitüberschreitung (Timeout) auf TCP/IP-Verbindungen
+hinzugefügt.
+@item
+Problem mit @code{LIKE} "%" auf einem Index, der @code{NULL}-Werte
+enthalten darf, behoben.
+@item
+@code{REVOKE ALL PRIVILEGES} widerrief nicht alle Berechtigungen.
+@item
+Erzeugung temporärer Tabellen mit demselben Namen wie die Original-Tabelle
+wird zugelassen.
+@item
+Wenn man einem Benutzer eine Berechtigungsoption (Grant Option) für eine
+Datenbank gewährte, konnte er die Berechtigungen nicht an andere Benutzer
+weitergeben.
+@item
+Neuer Befehl @code{SHOW GRANTS FOR benutzer} hinzugefügt (von Sinisa).
+@item
+Neue @code{date_add}-Syntax @code{date/datetime + INTERVAL # intervall_typ}
+hinzugefügt. Von Joshua Chamas.
+@item
+Berechtigungsüberprüfung für @code{LOAD DATA REPLACE} in Ordnung gebracht.
+@item
+Automatische Reparatur beschädigter Include-Dateien auf Solaris 2.7
+hinzugefügt.
+@item
+Einige configure-Probleme behoben, um Probleme bei der Erkennung großer
+Dateisysteme zu beheben.
+@item
+@code{REGEXP} ist jetzt unabhängig von der verwendeten
+Groß-/Kleinschreibung, wenn Sie nicht binäre Zeichenketten verwenden.
+@end itemize
+
+
+@node News-3.23.3, News-3.23.2, News-3.23.4, News-3.23.x
+@c German node Neuigkeiten-3.23.3
+@appendixsubsec Änderungen in Release 3.23.3
+
+@itemize @bullet
+@item
+Patches für MIT-pThread auf NetBSD angewandt.
+@item
+Bereichs-Bug in MyISAM behoben.
+@item
+@code{ASC} ist jetzt wieder Vorgabe für @code{ORDER BY}.
+@item
+@code{LIMIT} für @code{UPDATE} hinzugefügt.
+@item
+Neue Client-Funktion @code{mysql_change_user()} hinzugefügt.
+@item
+Zeichensatz zu @code{SHOW VARIABLES} hinzugefügt.
+@item
+Unterstützung von @code{--[leerraum]}-Kommentaren hinzugefügt.
+@item
+@code{INSERT into tabelle VALUES ()} wird zugelassen. Das heißt, Sie
+können jetzt eine leere Wertliste angeben, die in eine Zeile eingefügt
+wird, und in der jede Spalte auf ihren Vorgabewert gesetzt wird.
+@item
+@code{SUBSTRING(text FROM position)} geändert, um ANSI-SQL-kompatibel zu
+sein. (Vorher gab dieses Konstrukt das rechteste 'position'-Zeichen
+zurück.)
+@item
+@code{SUM()} mit @code{GROUP BY} gab auf manchen Systemen 0 zurück.
+@item
+Ausgabe bei @code{SHOW TABLE STATUS} geändert.
+@item
+@code{DELAY_KEY_WRITE}-Option für @code{CREATE TABLE} hinzugefügt.
+@item
+@code{AUTO_INCREMENT} wird für jeden beliebigen Schlüsselteil zugelassen.
+@item
+Problem mit @code{YEAR(NOW())} und @code{YEAR(CURDATE())} behoben.
+@item
+@code{CASE}-Konstrukt hinzugefügt.
+@item
+Neue Funktion @code{COALESCE()} hinzugefügt.
+@end itemize
+
+
+@node News-3.23.2, News-3.23.1, News-3.23.3, News-3.23.x
+@c German node Neuigkeiten-3.23.2
+@appendixsubsec Änderungen in Release 3.23.2
+
+@itemize @bullet
+@item
+Bereichsoptimierer-Bug behoben: @code{SELECT * FROM tabelle WHERE
+schluessel_teil1 >= konstante AND (schluessel_teil2 = konstante OR
+schluessel_teil2 = konstante)}. Der Bug bestand darin, dass manche Zeilen
+im Ergebnis doppelt auftauchen konnten.
+@item
+Das Laufenlassen von @code{myisamchk} ohne @code{-a} aktualisierte die
+Index-Verteilung falsch.
+@item
+@code{SET SQL_LOW_PRIORITY_UPDATES=1} gab vorher einen Parser-Fehler.
+@item
+Sie können jetzt Spalten indexieren, die in der @code{WHERE}-Klausel
+benutzt werden. @code{UPDATE tabelle SET KEY=KEY+1 WHERE KEY > 100}
+@item
+Datums-Handhabung sollte jetzt etwas schneller sein.
+@item
+Handhabung von 'fuzzy' Datumsangaben möglich (Datumsangaben, bei denen der
+Tag oder der Monat 0 sind, wie 1999-01-00).
+@item
+Optimierung von @code{SELECT ... WHERE schluessel_teil1=konstante1 AND
+schluessel_teil_2=konstante2 AND schluessel_teil1=konstante4 AND
+schluessel_teil2=konstante4} in Ordnung gebracht. Indextyp sollte
+@code{range} anstelle von @code{ref} sein.
+@item
+@code{egcs}-1.1.2-Optimierer-Bug behoben (bei der Benutzung von
+@code{BLOB}s) auf Linux Alpha.
+@item
+Problem mit @code{LOCK TABLES} in Kombination mit @code{DELETE FROM
+tabelle} behoben.
+@item
+MyISAM-Tabellen lassen jetzt Schlüssel auf @code{NULL} und
+@code{BLOB/TEXT}-Spalten zu.
+@item
+Folgender Join ist jetzt viel schneller: @code{SELECT ... FROM t1 LEFT JOIN
+t2 ON ... WHERE t2.nicht_null_spalte IS NULL}.
+@item
+@code{ORDER BY} und @code{GROUP BY} können jetzt auf Funktionen angewendet
+werden.
+@item
+Handhabung von 'konstante' geändert, um Handhabung von @code{ORDER BY
+RAND()} zu gestatten.
+@item
+Indexe werden jetzt für @code{WHERE schluessel_spalte = funktion} benutzt.
+@item
+Indexe werden jetzt für @code{WHERE schluessel_spalte = spalten_name}
+benutzt, selbst wenn die Spalten nicht identisch komprimiert sind.
+@item
+Indexe werden jetzt für @code{WHERE spalten_name IS NULL} benutzt.
+@item
+HEAP-Tabellen so geändert, dass in der Reihenfolge niedriges Byte zuerst
+gespeichert wird (um es zu erleichtern, MyISAM-Tabellen zu konvertieren).
+@item
+Automatische Änderung temporärer HEAP-Tabellen in MyISAM-Tabellen im Falle
+von 'table is full'-Fehlern.
+@item
+Option @code{--init-file=datei} für @code{mysqld} hinzugefügt.
+@item
+@code{COUNT(DISTINCT wert, [wert, ...])} hinzugefügt.
+@item
+@code{CREATE TEMPORARY TABLE} erzeugt jetzt eine temporäre Tabelle in ihrem
+eigenen Namensraum, die automatisch gelöscht wird, wenn die Verbindung
+beendet wird.
+@item
+Neue reservierte Wörter (erforderlich für @code{CASE}): @code{CASE, THEN,
+WHEN, ELSE und END}.
+@item
+Neue Funktionen @code{EXPORT_SET()} und @code{MD5()} hinzugefügt.
+@item
+Unterstützung für den GB2312 chinesischen Zeichensatz hinzugefügt.
+@end itemize
+
+
+@node News-3.23.1, News-3.23.0, News-3.23.2, News-3.23.x
+@c German node Neuigkeiten-3.23.1
+@appendixsubsec Änderungen in Release 3.23.1
+
+@itemize @bullet
+@item
+Einige Kompilierungsprobleme behoben.
+@end itemize
+
+
+@node News-3.23.0, , News-3.23.1, News-3.23.x
+@c German node Neuigkeiten-3.23.0
+@appendixsubsec Änderungen in Release 3.23.0
+
+@itemize @bullet
+@item
+Eine neue Tabellen-Handler-Bibliothek (@code{MyISAM}) mit vielen neuen
+Features hinzugefügt. @xref{MyISAM}.
+@item
+Sie können @code{HEAP}-Tabellen im Hauptspeicher erzeugen, die zum
+Nachschlagen extrem schnell sind.
+@item
+Unterstützung für große Dateien (63-Bit) auf Systemen, die große Dateien
+unterstützen, hinzugefügt.
+@item
+Neue Funktion @code{LOAD_FILE(datei)} hinzugefügt, um die Inhalte einer
+Datei als Zeichenkettenwert zu erhalten.
+@item
+Neuer Operator @code{<=>} hinzugefügt, der wie @code{=} funktioniert, aber
+WAHR (true) zurückgibt, wenn beide Argumente @code{NULL} sind. Das ist
+nützlich, um Änderungen zwischen Tabellen zu vergleichen.
+@item
+ODBC-3.0-@code{EXTRACT(intervall FROM datetime)}-Funktion hinzugefügt.
+@item
+Spalten, die als @code{FLOAT(X)} definiert sind, werden beim Speichern
+nicht gerundet und dürfen beim Abruf in wissenschaftlicher Notation sein
+(1.0 E+10).
+@item
+@code{REPLACE} ist jetzt schneller als vorher.
+@item
+@code{LIKE}-Zeichenvergleiche geändert, so dass sie sich wie @code{=}
+verhalten. Das heißt, dass @code{'e' LIKE '@'é'} jetzt WAHR (true) ist
+(falls hier etwas nicht richtig angezeigt wird: Das letztgenannte 'e' ist
+das französische 'e' mit Akzent).
+@item
+@code{SHOW TABLE STATUS} gibt eine Menge an Informationen über die Tabellen
+zurück.
+@item
+@code{LIKE} für den @code{SHOW STATUS}-Befehl hinzugefügt.
+@item
+Berechtigungsspalte zu @code{SHOW COLUMNS} hinzugefügt.
+@item
+Spalten @code{packed} und @code{comment} für @code{SHOW INDEX} hinzugefügt.
+@item
+Kommentare zu Tabellen (mit @code{CREATE TABLE ... COMMENT "kommentar"})
+hinzugefügt.
+@item
+@code{UNIQUE}, wie bei @code{CREATE TABLE tabelle (spalte int not null
+UNIQUE)}, hinzugefügt.
+@item
+Neue CREATE-Syntax: @code{CREATE TABLE tabelle SELECT ...}
+@item
+Neue CREATE-Syntax: @code{CREATE TABLE IF NOT EXISTS ...}
+@item
+Die Erzeugung von @code{CHAR(0)}-Spalten wird zugelassen.
+@item
+@code{DATE_FORMAT()} erfordert jetzt @samp{%} vor jeglichem
+Formatierungszeichen.
+@item
+@code{DELAYED} ist jetzt ein reserviertes Wort (tut uns leid :( ).
+@item
+Eine Beispiel-Prozedur wurde hinzugefügt: @code{analyse}, Datei:
+@file{sql_analyse.c}. Diese beschreibt die Daten in Ihrer Anfrage.
+Probieren Sie folgendes:
+@example
+SELECT ... FROM ... WHERE ... prozeduranalyse([max elemente,[max speicher]])
+@end example
+
+Diese Prozedur ist extrem nützlich, wenn Sie die Daten in Ihrer Tabelle
+prüfen wollen!
+@item
+@code{BINARY}-Cast, um zu erzwingen, dass eine Zeichenkette abhängig von
+der verwendeten Groß-/Kleinschreibung verglichen wird.
+@item
+Option @code{--skip-show-database} für @code{mysqld} hinzugefügt.
+@item
+Das Prüfen, ob sich eine Zeile bei einem @code{UPDATE} geändert hat,
+funktioniert jetzt auch bei @code{BLOB}-/@code{TEXT}-Spalten.
+@item
+Die @code{INNER}-Join-Syntax wurde hinzugefügt. @strong{HINWEIS}: Hierdurch
+wurde @code{INNER} zu einem reservierten Wort!
+@item
+Unterstützung für Netmasks zum Hostname in den MySQL-Tabellen hinzugefügt.
+Sie können eine Netmask mit der @code{IP/NETMASK}-Syntax angeben.
+@item
+Wenn Sie eine @code{NOT NULL DATE/DATETIME}-Spalte mit @code{IS NULL}
+vergleichen, wird das zu einem Vergleich auf @code{0} geändert, um einige
+ODBC-Applikationen zufrieden zu stellen (von @email{shreeve@@uci.edu}).
+@item
+@code{NULL IN (...)} gibt jetzt @code{NULL} anstelle von @code{0} zurück.
+Das stellt sicher, dass @code{null_spalte NOT IN (...)} nicht mit
+@code{NULL}-Werten übereinstimmt.
+@item
+Speicherung von Fließkommawerten in @code{TIME}-Spalten in Ordnung
+gebracht.
+@item
+Das Parsen von @code{TIME}-Zeichenketten geändert, so dass es strenger ist.
+Jetzt wird der Bruchteil-Sekunden-Teil erkannt (und momentan noch
+übergangen). Folgende Formate werden unterstützt:
+@table @code
+@item [[DAYS] [H]H:]MM:]SS[.bruchteil]
+@item [[[[[H]H]H]H]MM]SS[.bruchteil]
+@end table
+@item
+Erkennen (und Ignorieren) des zweiten Bruchteil-Anteils von @code{DATETIME}
+hinzugefügt.
+@item
+@code{LOW_PRIORITY}-Attribut für @code{LOAD DATA INFILE} hinzugefügt.
+@item
+Der vorgabemäßige Index-Name benutzt jetzt dieselbe Groß-/Kleinschreibung
+wie der benutzte Spaltenname.
+@item
+Vorgabemäßige Anzahl von Verbindungen auf 100 geändert.
+@item
+Bei der Benutzung von @code{LOAD DATA INFILE} werden größere Puffer
+verwendet.
+@item
+@code{DECIMAL(x,y)} funktioniert jetzt gemäß ANSI-SQL.
+@item
+Aggregat-UDF-Funktionen. Dank an Andreas F. Bobak @email{bobak@@relog.ch}
+hierfür!
+@item
+@code{LAST_INSERT_ID()} wird jetzt bei @code{INSERT INTO ... SELECT}
+aktualisiert.
+@item
+Einige kleinere Änderungen am Join-Tabellenoptimierer, um einige Joins
+schneller zu machen.
+@item
+@code{SELECT DISTINCT} ist viel schneller. Es benutzt die neue
+@code{UNIQUE}-Funktionalität in @code{MyISAM}. Ein Unterschied im Vergleich
+zur MySQL-Version 3.22 besteht darin, dass die Ausgabe von @code{DISTINCT}
+nicht mehr sortiert wird.
+@item
+Alle C-Client-API-Makros sind jetzt Funktionen, um die gemeinsam genutzten
+(shared) Bibliotheken verlässlicher zu machen. Deswegen können Sie nicht
+mehr @code{mysql_num_fields()} auf ein @code{MYSQL}-Objekt aufrufen,
+sondern müssen statt dessen @code{mysql_field_count()} benutzen.
+@item
+Benutzung von @code{LIBEWRAP}; Patch von Henning P. Schmiedehausen.
+@item
+@code{AUTO_INCREMENT} wird nur noch für numerische Spalten zugelassen.
+@item
+Durch die Verwendung von @code{AUTO_INCREMENT} wird die Spalte automatisch
+@code{NOT NULL}.
+@item
+@code{NULL} wird als Vorgabewert für AUTO_INCREMENT-Spalten angezeigt.
+@item
+@code{SQL_BIG_RESULT}; @code{SQL_SMALL_RESULT} ist jetzt Vorgabe.
+@item
+Ein gemeinsam genutztes (shared) Bibliothek-RPM hinzugefügt. Diese
+Verbesserung wurde von David Fox (dsfox@@cogsci.ucsd.edu) beigesteuert.
+@item
+Ein @code{--enable-large-files/--disable-large-files}-Schalter zu
+@code{configure} hinzugefügt. Siehe @file{configure.in} wegen mancher
+Systeme, auf denen dies wegen nicht funktionierender Implementation
+automatisch abgeschaltet ist.
+@item
+@code{readline} für Version 4.0 aktualisiert.
+@item
+Neue @code{CREATE TABLE}-Optionen: @code{PACK_KEYS} und @code{CHECKSUM}.
+@item
+@code{mysqld}-Option @code{--default-table-type} hinzugefügt.
+@end itemize
+
+
+@node Porting, Environment variables, News, Top
+@c German node Portierung
+@appendix Anmerkungen zur Portierung auf andere Systeme
+
+@cindex Portierung, auf andere Systeme
+
+Für den Server wird eine funktionierende Posix-Thread-Bibliothek benötigt.
+Auf Solaris 2.5 benutzen wir Sun PThread (die native Thread-Unterstützung
+in Version 2.4 und früher ist nicht gut genug). Auf Linux benutzen wir
+LinuxThread von Xavier Leroy, @email{Xavier.Leroy@@inria.fr}.
+
+Der schwierige Teil der Portierung auf eine neue Unix-Variante ohne gute
+native Thread-Unterstützung ist wahrscheinlich, MIT-pThread zu portieren.
+Siehe @file{with-pThread/README} und
+@uref{http://www.humanfactor.com/pThread/, POSIX-Thread programmieren}.
+
+Die MySQL-Distribution enthält eine gepatchte Version von Provenzanos
+PThread von MIT (siehe
+@uref{http://www.mit.edu:8001/people/proven/pThread.html,
+MIT-PThread-Website}). Diese kann für einige Betriebssysteme benutzt
+werden, die kein POSIX-Thread haben.
+
+Es ist ebenfalls möglich, ein anderes Thread-Paket auf Benutzerebene namens
+FSU-PThread zu benutzen (siehe
+@uref{http://www.informatik.hu-berlin.de/~mueller/pThread.html,
+FSU-PThread-Homepage}). Diese Implementation wird für die SCO-Portierung
+benutzt.
+
+In den @file{thr_lock.c}- und @file{thr_alarm.c}-Programmen im
+@file{mysys}-Verzeichnis finden Sie einige Tests / Beispiele dieser
+Probleme.
+
+Sowohl Server als auch Client benötigen einen funktionierenden C++-Kompiler
+(wir benutzen @code{gcc} und haben SparcWorks ausprobiert). Ein anderer
+bekanntermaßen funktionierender Compiler ist Irix @code{cc}.
+
+Um nur den Client zu kompilieren, benutzen Sie @code{./configure
+--without-server}.
+
+Es gibt momentan keine Unterstützung, um nur den Server zu kompilieren,
+noch ist es wahrscheinlich, dass eine solche hinzugefügt wird, falls nicht
+jemand einen guten Grund dafür findet.
+
+Wenn Sie irgend welche @file{Makefile} oder das configure-Skript ändern
+wollen / müssen, müssen Sie sich Automake und Autoconf holen. Wir haben die
+@code{automake-1.2}- und @code{autoconf-2.12}-Distributionen benutzt.
+
+Alle Schritte, die notwendig sind, um alles aus den grundlegendsten Dateien
+neu zu machen (make):
+
+@example
+/bin/rm */.deps/*.P
+/bin/rm -f config.cache
+aclocal
+autoheader
+aclocal
+automake
+autoconf
+./configure --with-debug=full --prefix='ihr_installationsverzeichnis'
+
+# Die oben erzeugten makefiles benötigen GNU-make 3.75 oder neuer.
+# (unten gmake genannt)
+gmake clean all install init-db
+@end example
+
+Wenn Sie bei einer neuen Portierung Probleme bekommen, kann es sein, dass
+Sie MySQL etwas debuggen müssen! @xref{Debugging server}.
+
+@strong{HINWEIS:} Bevor Sie mit dem Debuggen von @code{mysqld} anfangen,
+bringen Sie sich zuerst die Testprogramme @code{mysys/thr_alarm} und
+@code{mysys/thr_lock} zum Laufen. Das stellt sicher, dass Ihre
+Thread-Installation zumindest überhaupt eine Chance hat, zu funktionieren!
+
+
+
+@menu
+* Debugging server::
+* Debugging client::
+* The DBUG package::
+* Locking methods::
+* RTS-threads::
+* Thread packages::
+@end menu
+
+@node Debugging server, Debugging client, Porting, Porting
+@c German node Server debuggen
+@appendixsec Einen MySQL-Server debuggen
+
+@cindex Server, debuggen
+@cindex debuggen, Server
+@cindex Absturz
+
+Wenn Sie Funktionalität benutzen, die in MySQL sehr neu ist, können Sie
+versuchen, @code{mysqld} mit der @code{--skip-new}-Option laufen zu lassen
+(die alle sehr neue, potenziell unsichere Funktionalität abschaltet) oder
+mit @code{--safe-mode}, was viel an Optimierung abschaltet, die
+möglicherweise Probleme verursacht. @xref{Crashing}.
+
+Wenn @code{mysqld} nicht starten will, sollten Sie prüfen, ob Sie irgend
+welche @code{my.cnf}-Dateien haben, die mit Ihrer Konfiguration in Konflikt
+kommen! Sie können Ihre @code{my.cnf}-Argumente mit @code{mysqld
+--print-defaults} prüfen und sie vermeiden, indem Sie mit @code{mysqld
+--no-defaults ...} starten.
+
+Wenn @code{mysqld} anfängt, Prozessorleistung oder Speicher zu fressen,
+oder wenn er ``hängt'', können Sie @code{mysqladmin processlist status}
+benutzen, um herauszufinden, ob irgend etwas eine Anfrage ausführt, die
+sehr lange dauert. Es ist eine gute Idee, @code{mysqladmin -i10 processlist
+status} in irgend einem Fenster laufen zu haben, wenn Sie
+Performance-Probleme oder Probleme damit haben, dass sich neue Clients
+nicht verbinden können.
+
+Der Befehl @code{mysqladmin debug} dumpt Informationen über Sperren, die in
+Gebrauch sind, den benutzten Speicher und den Anfragengebrauch in die
+mysql-Log-Datei aus. Das kann helfen, einige Probleme zu lösen. Dieser
+Befehl stellt auch nützliche Informationen zur Verfügung, selbst wenn Sie
+MySQL nicht zum Debuggen kompiliert haben!
+
+Wenn das Problem darin besteht, dass einige Tabellen langsamer und
+langsamer werden, sollten Sie versuchen, die Tabelle mit @code{OPTIMIZE
+TABLE} der @code{myisamchk} zu optimieren.
+@xref{MySQL Database Administration}. Sie sollten langsame Anfragen
+darüber hinaus mit @code{EXPLAIN} überprüfen.
+
+Ebenfalls sollten Sie den Abschnitt über betriebssystemspezifische Dinge in
+diesem Handbuch lesen, weil Sie Probleme haben könnten, die einzigartig für
+Ihre Umgebung sind. @xref{Operating System Specific Notes}.
+
+
+
+@menu
+* Compiling for debugging::
+* Making trace files::
+* Using gdb on mysqld::
+* Using stack trace::
+* Using log files::
+* Reproduceable test case::
+@end menu
+
+@node Compiling for debugging, Making trace files, Debugging server, Debugging server
+@c German node Zum Debuggen kompilieren
+@appendixsubsec MySQL zum Debuggen kompilieren
+
+Wenn Sie sehr spezielle Probleme haben, können Sie immer versuchen, MySQL
+zu debuggen. Dafür müssen Sie MySQL mit der @code{--with-debug}- oder der
+@code{--with-debug=full}-Option kompilieren. Sie können prüfen, ob MySQL
+mit Debuggen kompiliert wurde oder nicht, wenn Sie @code{mysqld --help}
+ausführen. Wenn das @code{--debug}-Flag in den Optionen aufgeführt ist,
+haben Sie Debuggen eingeschaltet. @code{mysqladmin ver} gibt die
+@code{mysqld}-Version in diesem Fall ebenfalls als @code{mysql ... --debug}
+aus.
+
+Wenn Sie gcc oder egcs benutzen, ist die empfohlene configure-Zeile:
+
+@example
+CC=gcc CFLAGS="-O2" CXX=gcc CXXFLAGS="-O2 -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --with-debug --with-extra-charsets=complex
+@end example
+
+Das vermeidet Probleme mit der @code{libstdc++}-Bibliothek und mit
+C++-Ausnahmen (viele Compiler haben Probleme mit C++-Ausnahmen in threaded
+Code) und kompiliert eine MySQL-Version mit Unterstützung für alle
+Zeichensätze.
+
+Wenn Sie einen Speicherüberlauffehler vermuten, können Sie MySQL mit
+@code{--with-debug=full} kompilieren, was zusätzlich einen
+(@code{SAFEMALLOC})-Prüfer für die Speicherzuweisung installiert. Das
+Laufenlassen mit @code{SAFEMALLOC} ist jedoch recht langsam. Wenn Sie daher
+Performance-Probleme bekommen, sollten Sie @code{mysqld} mit der
+@code{--skip-safemalloc}-Option starten. Das schaltet die
+Speicherüberlaufprüfung für jeden Aufruf von @code{malloc} und @code{free}
+ab.
+
+Wenn @code{mysqld} nicht mehr abstürzt, wenn Sie ihn mit
+@code{--with-debug} kompilieren, haben Sie wahrscheinlich einen
+Compiler-Bug oder einen Timing-Bug innerhalb von MySQL gefunden. In diesem
+Fall können Sie versuchen, @code{-g} für die @code{CFLAGS}- und
+@code{CXXFLAGS}-Variablen oben hinzuzufügen und nicht mehr
+@code{--with-debug} zu benutzen. Wenn @code{mysqld} jetzt stirbt, können
+Sie wenigstens mit @code{gdb} mit ihm verbinden oder @code{gdb} auf die
+Core-Datei benutzen, um herauszufinden, was passiert ist.
+
+Wenn Sie MySQL zum Debuggen konfigurieren, können Sie viele zusätzliche
+Sicherheitprüffunktionen hinzufügen, die die Gesundheit von @code{mysqld}
+beobachten. Wenn Sie etwas ``Unerwartetes'' finden, wird ein Eintrag nach
+@code{stderr} geschrieben, den @code{safe_mysqld} in die Fehler-Log-Datei
+leitet! Das heißt auch, dass Sie bei unerwarteten Problemen mit MySQL und
+der Benutzung einer Quelldistribution als erstes MySQL zum Debuggen
+konfigurieren sollten! (Die zweite Sache wäre natürlich, eine E-Mail an
+@email{mysql@@lists.mysql.com} zu schicken und um Hilfe zu bitten. Bitte
+benutzen Sie das @code{mysqlbug}-Skript für alle Bug-Berichte oder Fragen
+hinsichtlich der MySQL-Version, die Sie benutzen!
+
+In der Windows-MySQL-Distribution wird @code{mysqld.exe} vorgabemäßig mit
+Unterstützung für Trace-Dateien kompiliert.
+
+
+@node Making trace files, Using gdb on mysqld, Compiling for debugging, Debugging server
+@c German node Trace-Dateien
+@appendixsubsec Trace-Dateien erzeugen
+
+Wenn der @code{mysqld}-Server nicht startet oder wenn Sie den
+@code{mysqld}-Server schnell zum Absturz bringen können, können Sie
+versuchen, eine Trace-Datei zu erzeugen, um das Problem zu finden.
+
+Hierfür brauchen Sie einen @code{mysqld}, der zum Debuggen kompiliert ist.
+Sie können das mit @code{mysqld -V} prüfen. Wenn die Versionsnummer mit
+@code{-debug} endet, ist Unterstützung für Trace-Dateien einkompiliert.
+
+Starten Sie den @code{mysqld}-Server mit einem Trace-Log in
+@file{/tmp/mysqld.trace} (oder @file{C:\mysqld.trace} unter Windows):
+
+@code{mysqld --debug}
+
+Unter Windows sollten Sie auch den @code{--standalone}-Flag benutzen, um
+@code{mysqld} nicht als Systemdienst zu starten.
+
+Machen Sie folgendes in einem DOS-Fenster:
+
+@example
+mysqld --debug --standalone
+@end example
+
+Danach können Sie das @code{mysql.exe}-Kommandozeilenwerkzeug in einem
+zweiten DOS-Fenster benutzen, um das Problem zu reproduzieren. Sie können
+den obigen @code{mysqld}-Server mit @code{mysqladmin shutdown} herunter
+fahren.
+
+Beachten Sie, dass die Trace-Datei sehr @emph{Groß} wird! Wenn Sie eine
+kleinere Trace-Datei haben wollen, können Sie etwa folgendes tun:
+
+@code{mysqld --debug=d,info,error,query,general,where:O,/tmp/mysqld.trace}
+
+Das gibt nur Informationen für die interessantesten Dinge in
+@file{/tmp/mysqld.trace} aus.
+
+Wenn Sie hierüber einen Bug-Bericht erstellen, schicken Sie bitte nur die
+Zeilen aus der Trace-Datei an die entsprechende Mailing-Liste, in denen
+etwas schief zu gehen scheint! Wenn Sie diese Stelle nicht finden können,
+können Sie die Trace-Datei per FTP einschicken, zusammen mit einem
+kompletten Bug-Bericht, an @uref{ftp://Support.mysql.com/pub/mysql/secret},
+so dass ein MySQL-Entwickler sich das ansehen kann.
+
+Die Trace-Datei wird mit dem @strong{DBUG}-Paket von Fred Fish hergestellt.
+@xref{The DBUG package}.
+
+
+@node Using gdb on mysqld, Using stack trace, Making trace files, Debugging server
+@c German node gdb auf mysqld benutzen
+@appendixsubsec mysqld unter gdb debuggen
+
+@cindex gdb, using
+
+Auf den meisten Systemen können Sie @code{mysqld} von @code{gdb} starten,
+um mehr Informationen zu erhalten, wenn @code{mysqld} abstürzt.
+
+Bei einigen älteren @code{gdb}-Versionen unter Linux müssen Sie @code{run
+--one-thread} benutzen, um den @code{mysqld}-Thread debuggen zu können. In
+diesem Fall können Sie zur gleichen Zeit nur einen Thread aktiv haben.
+
+Wenn Sie @code{mysqld} unter gdb laufen lassen, sollten Sie den Stack-Trace
+mit @code{--skip-stack-trace} abschalten, um Segmentation-Fehler innerhalb
+gdb abfangen zu können.
+
+Es ist sehr schwierig, MySQL unter @code{gdb} zu debuggen, wenn Sie
+permanent viele neue Verbindungen aufbauen, weil @code{gdb} den Speicher
+für den alten Thread nicht freigibt. Sie können dieses Problem vermeiden,
+indem Sie @code{mysqld} mit @code{-O thread_cache_size=
+'maximale_verbindungen +1'} starten. In den meisten Fällen hilft bereits
+schon die Benutzung von @code{-O thread_cache_size=5'} recht viel!
+
+Wenn Sie einen Coredump unter Linux erhalten wollen, wenn @code{mysqld} mit
+einem SIGSEGV-Signal stirbt, können Sie @code{mysqld} mit der
+@code{--core-file}-Option starten. Diese Core-Datei kann benutzt werden, um
+eine Zurückverfolgung (Backtrace) zu machen, die Ihnen helfen kann
+herauszufinden, warum @code{mysqld} starb:
+
+@example
+shell> gdb mysqld core
+gdb> backtrace full
+gdb> exit
+@end example
+
+@xref{Crashing}.
+
+Wenn Sie gdb 4.17.x oder höher unter Linux benutzen, sollten Sie eine
+@file{.gdb}-Datei mit folgenden Informationen in Ihrem aktuellen
+Verzeichnis installieren:
+
+@example
+set print sevenbit off
+handle SIGUSR1 nostop noprint
+handle SIGUSR2 nostop noprint
+handle SIGWAITING nostop noprint
+handle SIGLWP nostop noprint
+handle SIGPIPE nostop
+handle SIGALRM nostop
+handle SIGHUP nostop
+handle SIGTERM nostop noprint
+@end example
+
+Wenn Sie Probleme haben, den Thread mit gdb zu debuggen, sollten Sie gdb
+5.x herunter laden und diesen statt dessen benutzen. Die neue gdb-Version
+hat eine stark verbesserte Thread-Handhabung!
+
+Hier ist ein Beispiel, wie man mysqld debuggt:
+
+@example
+shell> gdb /usr/local/libexec/mysqld
+gdb> run
+...
+backtrace full # Tun Sie das, wenn mysqld abstürzt
+@end example
+
+Schließen Sie die obige Ausgabe in eine Mail ein, die mit @code{mysqlbug}
+erzeugt wurde und schicken Sie sie an @code{mysql@@lists.mysql.com}.
+
+Wenn @code{mysqld} hängen bleibt, können Sie versuchen, einige
+Systemwerkzeuge wie @code{strace} oder @code{/usr/proc/bin/pstack} zu
+benutzen, um herauszufinden, was @code{mysqld} zum Hängen brachte.
+
+@example
+strace /tmp/log libexec/mysqld
+@end example
+
+@findex DBI->trace
+@findex Trace-DBI-Methode
+@tindex DBI_TRACE-Umgebungsvariable
+@tindex Umgebungsvariable, DBI_TRACE
+Wenn Sie die Perl-@code{DBI}-Schnittstelle benutzen, können Sie
+Debug-Informationen anschalten, indem Sie die @code{trace}-Methode benutzen
+oder die @code{DBI_TRACE}-Umgebungsvariable setzen.
+@xref{Perl DBI Class, , Perl @code{DBI} Class}.
+
+
+@node Using stack trace, Using log files, Using gdb on mysqld, Debugging server
+@c German node Stack-Trace benutzen
+@appendixsubsec Einen Stack-Trace benutzen
+
+Auf manchen Betriebssystemen enthält die Fehler-Log-Datei einen
+Stack-Trace, wenn @code{mysqld} unerwartet stirbt. Diese können Sie
+benutzen, um herauszufinden, wo (und vielleicht warum) @code{mysqld} starb.
+@xref{Error log}. Um einen Stack-Trace zu erhalten, sollten Sie
+@code{mysqld} NICHT mit der @code{-fomit-frame-pointer}-Option für gcc
+kompilieren. @xref{Compiling for debugging}.
+
+Wenn die Fehlerdatei etwas wie folgendes enthält:
+
+@example
+mysqld got signal 11;
+The manual section 'debugging a MySQL server' tells you how to use a
+stack trace and/or the core file to produce a readable backtrace that may
+help in finding out why mysqld died
+Attemping backtrace. You can use the following information to find out
+where mysqld died. Wenn you see no messages after this, something went
+terribly wrong
+stack range sanity check, ok, backtrace follows
+0x40077552
+0x81281a0
+0x8128f47
+0x8127be0
+0x8127995
+0x8104947
+0x80ff28f
+0x810131b
+0x80ee4bc
+0x80c3c91
+0x80c6b43
+0x80c1fd9
+0x80c1686
+@end example
+
+Können Sie herausfinden, wo @code{mysqld} starb, indem Sie folgendes tun:
+
+@enumerate
+@item
+Kopieren Sie die obigen Zahlen in eine Datei, zum Beispiel
+@file{mysqld.stack}.
+
+@item
+Machen Sie eine symbolische Datei für den @code{mysqld}-Server:
+@example
+nm -n libexec/mysqld > /tmp/mysqld.sym
+@end example
+
+Beachten Sie, dass viele MySQL-Binärdistributionen die obige Datei namens
+@code{mysqld.sym.gz} enthalten. In diesem Fall müssen Sie sie wie folgt
+entpacken:
+@example
+gunzip < bin/mysqld.sym.gz > /tmp/mysqld.sym
+@end example
+
+@item
+Führen Sie @code{resolve_stack_dump -s /tmp/mysqld.sym -n mysqld.stack}
+aus.
+
+Das gibt aus, wo @code{mysqld} starb. Wenn Ihnen das nicht hilft,
+herauszufinden, warum @code{mysqld} starb, sollten Sie einen Bug-Bericht
+machen und die Ausgabe des obigen Befehls in diesen Bericht einschließen.
+
+Beachten Sie aber, dass es uns in den meisten Fällen nicht weiterhilft, nur
+einen Stack-Trace zu haben, um die Ursache des Problems herauszufinden. Um
+den Bug feststellen oder einen Workaround zur Verfügung stellen zu können,
+müssen wir in den meisten Fällen die Anfrage kennen, die @code{mysqld}
+tötete, und am besten einen Testfall, so dass wir das Problem wiederholen
+können! @xref{Bug reports}.
+@end enumerate
+
+
+@node Using log files, Reproduceable test case, Using stack trace, Debugging server
+@c German node Log-Dateien benutzen
+@appendixsubsec Log-Dateien benutzen, um Gründe für Fehler in mysqld zu finden
+
+Beachten Sie, dass Sie vor dem Start von @code{mysqld} mit @code{--log}
+alle Ihre Tabellen mit @code{myisamchk} prüfen sollten.
+@xref{MySQL Database Administration}.
+
+Wenn @code{mysqld} stirbt oder hängenbleibt, sollten Sie ihn mit
+@code{--log} starten. Wenn @code{mysqld} wieder stirbt, können Sie das Ende
+der Log-Datei nach der Anfrage durchsuchen, die @code{mysqld} tötete.
+
+Wenn Sie @code{--log} ohne einen Dateinamen verwenden, wird das Log im
+Datenbank-Verzeichnis als 'hostname'.log gespeichert. In den meisten Fällen
+ist es die letzte Anfrage in der Log-Datei, die @code{mysqld} tötete, aber
+das sollten Sie falls möglich sicherstellen, indem Sie @code{mysqld} neu
+starten und dieselbe Anfrage mit dem @code{mysql}-Kommandozeilenwerkzeug
+wiederholen. Wenn das funktioniert, sollten Sie ebenfalls alle
+komplizierten Anfragen testen, die nicht beendet wurden.
+
+Sie können auch den Befehl @code{EXPLAIN} auf alle @code{SELECT}-Statements
+ausprobieren, die lange Zeit benötigen, um sicherzustellen, dass
+@code{mysqld} Indexe korrekt benutzt. @xref{EXPLAIN, , @code{EXPLAIN}}.
+
+Sie finden Anfragen, die zur Ausführung lange Zeit benötigen, indem Sie
+@code{mysqld} mit @code{--log-slow-queries} starten.
+@xref{Slow query log}.
+
+Wenn Sie den Text @code{mysqld restarted} in der Fehler-Log-Datei-Datei
+(normalerweise namens @file{hostname.err}) finden, haben Sie wahrscheinlich
+eine Anfrage gefunden, die @code{mysqld} zum Absturz brachte. Wenn das
+passiert, sollten Sie alle Ihre Tabellen mit @code{myisamchk} prüfen
+(@pxref{MySQL Database Administration}) und die Anfragen in den
+MySQL-Log-Dateien untersuchen, um herauszufinden, ob eine nicht
+funktioniert. Wenn Sie eine solche Anfrage finden, versuchen Sie zunächst,
+auf die neueste MySQL-Version zu aktualisieren. Wenn das nicht hilft und Sie
+nichts im @code{mysql}-Mailarchiv finden können, sollten Sie den Bug an
+@email{mysql@@lists.mysql.com} berichten. Links zu Mailarchiven finden Sie
+online auf der @uref{http://www.mysql.com/documentation/,
+MySQL-Dokumentationsseite}.
+
+Wenn Sie @code{mysqld} mit @code{--with-myisam-recover} gestartet haben,
+prüft MySQL automatisch @code{MyISAM}-Tabellen und versucht sie zu
+reparieren, wenn sie als 'nicht korrekt geschlossen' oder 'beschädigt'
+gekennzeichnet sind. Wenn das passiert, schreibt MySQL einen Eintrag in die
+@code{hostname.err}-Datei @code{'Warning: Checking table ...'}, der von
+@code{Warning: Repairing table} gefolgt wird, wenn die Tabelle repariert
+werden muss. Wenn Sie viele solcher Fehler erhalten, ohne dass
+@code{mysqld} direkt davor unerwartet gestorben ist, stimmt etwas nicht und
+muss weiter untersucht werden. @xref{Command-line options}.
+
+Natürlich ist es kein gutes Zeichen, wenn @code{mysqld} unerwartet stirbt,
+doch in diesem Fall sollte man nicht die @code{Checking table...}-Meldungen
+untersuchen, sondern statt dessen versuchen herauszufinden, warum
+@code{mysqld} starb.
+
+
+@node Reproduceable test case, , Using log files, Debugging server
+@c German node Reproduzierbarer Testfall
+@appendixsubsec Einen Testfall herstellen, wenn Sie Tabellenbeschädigung feststellen
+
+Wenn Sie beschädigte Tabellen erhalten oder wenn @code{mysqld} immer nach
+irgend einem Aktualisierungsbefehl fehlschlägt, können Sie mit folgendem
+überprüfen, ob der Bug reproduzierbar ist:
+
+@itemize @bullet
+@item
+Fahren Sie den MySQL-Daemon herunter (mit @code{mysqladmin shutdown}).
+@item
+Machen Sie eine Datensicherung der Tabellen (um dem sehr unwahrscheinlichen
+Fall vorzubeugen, dass die Reparatur etwas Schlechtes macht).
+@item
+Prüfen Sie alle Tabellen mit @code{myisamchk -s Datenbank/*.MYI}.
+Reparieren Sie jegliche beschädigten Tabellen mit @code{myisamchk -r
+datenbank/tabelle.MYI}.
+@item
+Machen Sie eine Datensicherung der Tabellen.
+@item
+Entfernen (oder verschieben) Sie jegliche alten Log-Dateien aus dem
+MySQL-Daten-Verzeichnis, wenn Sie mehr Platz brauchen.
+@item
+Starten Sie @code{mysqld} mit @code{--log-binary}. @xref{Binary log}.
+Wenn Sie eine Anfrage finden wollen, die @code{mysqld} zum Absturz brachte,
+sollten Sie @code{--log --log-binary} benutzen.
+@item
+Wenn Sie eine beschädigte Tabelle erhalten, halten Sie @code{mysqld} an.
+@item
+Stellen Sie die Datensicherung wieder her.
+@item
+Starten Sie den @code{mysqld}-Server neu, @strong{ohne}
+@code{--log-binary}.
+@item
+Führen Sie die Befehle mit @code{mysqlbinlog update-log-file | mysql}
+erneut aus. Die Update-Log-Datei wird im MySQL-Datenbank-Verzeichnis unter
+dem Namen @code{hostname-bin.#} gespeichert.
+@item
+Wenn die Tabellen wieder beschädigt werden oder Sie @code{mysqld} wieder
+dazu bringen können zu sterben, haben Sie einen reproduzierbaren Bug
+gefunden, der sich leicht beheben lassen sollte! Schicken Sie die Tabellen
+und die Binär-Log-Datei an @uref{ftp://support.mysql.com/pub/mysql/secret}
+und schicken Sie eine E-Mail an @email{bugs@@lists.mysql.com} oder (wenn
+Sie ein Support-Kunde sind) an @email{Support@@mysql.com}, und das
+MySQL-Team wird den Bug so schnell wie möglich beheben.
+@end itemize
+
+Sie können auch das Skript @code{mysql_find_rows} benutzen, um einfach
+einige der Aktualisierungs-Statements auszuführen, wenn Sie das Problem
+eingrenzen wollen.
+
+
+@node Debugging client, The DBUG package, Debugging server, Porting
+@c German node Clients debuggen
+@appendixsec Einen MySQL-Client debuggen
+
+@cindex debuggen, Client
+@cindex Clients, debuggen
+
+Um einen MySQL-Client mit dem integrierten Debug-Paket debuggen zu können,
+sollten Sie MySQL mit @code{--with-debug} oder @code{--with-debug=full}
+kompilieren. @xref{configure options}.
+
+@tindex MYSQL_DEBUG-Umgebungsvariable
+@tindex Umgebungsvariable, MYSQL_DEBUG
+Bevor Sie einen Client laufen lassen, sollten Sie die
+@code{MYSQL_DEBUG}-Umgebungsvariable setzen:
+
+@example
+shell> MYSQL_DEBUG=d:t:O,/tmp/client.trace
+shell> export MYSQL_DEBUG
+@end example
+
+Das bringt Clients dazu, eine Trace-Datei in @file{/tmp/client.trace} zu
+erzeugen.
+
+Wenn Sie Probleme mit Ihrem eigenen Client-Code haben, sollten Sie
+versuchen, sich mit dem Server zu verbinden und Ihre Anfragen mit einem
+Client laufen zu lassen, der bekanntermaßen funktioniert. Lassen Sie dabei
+@code{mysql} im Debug-Modus laufen (unter der Annahme, dass Sie MySQL mit
+angeschaltetem Debuggen kompiliert haben):
+
+@example
+shell> mysql --debug=d:t:O,/tmp/client.trace
+@end example
+
+Das stellt nützliche Informationen für den Fall bereit, dass Sie einen
+Bug-Bericht schicken. @xref{Bug reports}.
+
+Wenn Ihr Client bei irgend einem 'zulässigen' Sperr-Code abstürzt, sollten
+Sie sicherstellen, dass Ihre @file{mysql.h}-Include-Datei mit Ihrer
+MySQL-Bibliotheksdatei zusammenpasst. Es ist ein häufiger Fehler, eine alte
+@file{mysql.h}-Datei aus einer alten MySQL-Installation mit einer neuen
+MySQL-Bibliothek zu benutzen.
+
+
+@node The DBUG package, Locking methods, Debugging client, Porting
+@c German node Das DBUG-Paket
+@appendixsec Das DBUG-Paket
+
+@cindex DBUG-Paket
+
+Der MySQL-Server und die meisten MySQL-Clients werden mit dem DBUG-Paket
+kompiliert, das ursprünglich von Fred Fish stammt. Wenn man MySQL zum
+Debuggen kompiliert hat, ermöglicht es dieses Paket, eine Trace-Datei davon
+zu erhalten, was das Programm debuggt. @xref{Making trace files}.
+
+Man benutzt das Debug-Paket durch Aufruf des Programms mit der
+@code{--debug="..."}- oder der @code{-#...}-Option.
+
+Die meisten MySQL-Programme haben eine vorgabemäßige Debug-Zeichenkette,
+die benutzt wird, wenn Sie keine Option für @code{--debug} angeben. Die
+vorgabemäßige Trace-Datei ist üblicherweise
+@code{/tmp/programm_name.trace} unter Unix und @code{\programm_name.trace}
+unter Windows.
+
+Die Debug-Steuerungs-Zeichenkette ist eine Folge durch Doppelpunkte
+getrennter Felder, wie folgt:
+
+@example
+<feld_1>:<feld_2>:...:<feld_N>
+@end example
+
+Jedes Feld besteht aus einem zwingend erforderlichen Flag-Zeichen, gefolgt
+durch ein optionales Komma (",") und eine durch Kommas getrennte Auflistung
+von Modifikatoren:
+
+@example
+flag[,modifikator,modifikator,...,modifikator]
+@end example
+
+Aktuell werden folgende Flag-Zeichen erkannt:
+
+@multitable @columnfractions .1 .9
+@item d
+ @tab Ausgabe von DBUG_<N>-Makros des aktuellen Status ermöglichen.
+Gegebenenfalls gefolgt von einer Auflistung von Schlüsselwörtern, die
+Ausgaben nur für die DBUG-Makros mit diesem Schlüsselwort auswählt. Eine
+leere Auflistung von Schlüsselwörtern bedeutet Ausgabe für alle Makros.
+@item D
+ @tab Nach jeder Debugger-Ausgabezeile verzögern. Das Argument ist die
+Anzahl von Zehntelsekunden der Verzögerung, abhängig von den Fähigkeiten
+der Maschine. @code{-#D,20} bedeutet als eine Verzögerung von 2 Sekunden.
+@item f
+ @tab Debuggen und / oder Tracen und Profilen auf die in der Auflistung
+genannten Funktionen beschränken. Beachten Sie, dass eine leere Liste alle
+Funktionen abschaltet. Die entsprechenden "d"- oder "t"-Flags müssen immer
+noch angegeben werden; dieser Flag beschränkt nur ihre Aktionen, wenn Sie
+angeschaltet sind.
+@item F
+ @tab Den Quell-Dateinamen für jede Zeile der Debug- oder Trace-Ausgabe
+festlegen.
+@item i
+ @tab Den Prozess mit der PID- oder Thread-Kennung für jede Ziele der
+Debug- oder Trace-Ausgabe festlegen.
+@item g @tab Profiling anschalten. Es wird eine Datei namens 'dbugmon.out'
+erzeugt, die Informationen enthält, die benutzt werden können, um das
+Programm zu profilen. Wir gegebenenfalls von einer Auflistung von
+Schlüsselwörter gefolgt, die Profiling nur für die Funktionen in dieser
+Liste auswählen. Eine leere Liste bedeutet, dass alle Funktionen in
+Betracht gezogen werden.
+@item L
+ @tab Die Quell-Datei-Zeilennummer für jede Zeile der Debug- oder
+Trace-Ausgabe festlegen.
+@item n
+ @tab Die aktuelle Funktionsverschachtelungstiefe für jede Zeile der Debug-
+oder Trace-Ausgabe ausgeben.
+@item N
+ @tab Jede Zeile der dbug-Ausgabe nummerieren.
+@item o
+ @tab Die Debugger-Ausgabe in die angegebene Datei umlenken. Die
+vorgabemäßige Ausgabe ist stderr.
+@item O
+ @tab Wie @code{O}, aber die Datei wird nach jedem Schreiben auf die Platte
+zurückgeschrieben (flush). Wenn nötig, wird die Datei geschlossen und
+wieder geöffnet.
+@item p
+ @tab Debugger-Aktionen auf die angegebenen Prozesse beschränken. Ein
+Prozess muss mit dem DBUG_PROCESS-Makro gekennzeichnet sein und mit einer
+der Aktionen in der Liste übereinstimmen, damit Debugger-Aktionen
+durchgeführt werden.
+@item P
+ @tab Den aktuellen Prozessnamen für jede Zeile der Debug- oder
+Trace-Ausgabe ausgeben.
+@item r
+ @tab Wenn ein neuer Zustand gepusht wird, nicht die
+Funktionsverschachtelungsebene des alten Zustands übernehmen (erben).
+Nützlich, wenn die Ausgabe am linken Rand anfangen soll.
+@item S
+ @tab Funktion _sanity(_datei_,_zeile_) bei jeder debuggten Funktion
+ausführen, bis _sanity() etwas anderes als 0 zurückgibt. (Wird meist
+zusammen mit safemalloc benutzt, um Speicherlecks zu finden.)
+@item t
+ @tab Trace-Zeile für Funktionsaufrufen / Funktionsende anschalten. Wird
+gegebenenfalls gefolgt von einer Liste (die nur einen Modifikator enthält), in
+der numerisch eine maximale Trace-Ebene angegeben wird, nach der keine
+Ausgaben mehr erfolgen, weder für Debuggen noch für das Tracen von Makros. Die
+Vorgabe ist eine Kompilierzeit-Option.
+@end multitable
+
+Einige Beispiele von Debug-Steuerungs-Zeichenketten, die auf einer
+Shell-Kommandozeile erscheinen können (das "-#" wird typischerweise
+benutzt, um eine Steuerungs-Zeichenkette für ein Applikationsprogramm
+einzuführen):
+
+@example
+-#d:t
+-#d:f,main,subr1:F:L:t,20
+-#d,input,output,files:n
+-#d:t:i:O,\\mysqld.trace
+@end example
+
+In MySQL werden gebräuchlicherweise (mit der @code{d}-Option) folgende Tags
+ausgegeben: @code{enter}, @code{exit}, @code{error}, @code{warning},
+@code{info} und @code{loop}.
+
+
+@node Locking methods, RTS-threads, The DBUG package, Porting
+@c German node Sperrmethoden
+@appendixsec Sperrmethoden
+
+@cindex Sperrmethoden
+@cindex Methoden, Sperr-
+
+Momentan unterstützt MySQL Tabellensperren nur für @code{ISAM}- /
+@code{MyISAM}- und @code{HEAP}-Tabellen und Sperren auf Seitenebene nur für
+@code{BDB}-Tabellen. @xref{Internal locking}. Bei @code{MyISAM}-Tabellen
+können Sie @code{INSERT} und @code{SELECT} ohne Sperren frei vermischen.
+(@code{Versionierung}).
+
+Ab Version 3.23.33 können Sie die Tabellensperr-Konkurrenz auf Ihrem System
+durch Prüfen der @code{Table_locks_waited}- und
+@code{Table_locks_immediate}-Umgebungsvariablen analysieren.
+
+Einige Datenbankbenutzer behaupten, dass MySQL keine große Anzahl
+gleichzeitiger Benutzer unterstützen kann, weil es kein Sperren auf
+Zeilenebene hat. Das mag bei einigen speziellen Applikationen zutreffen,
+aber nicht allgemein. Wie immer hängt das völlig davon ab, was Ihre
+Applikation macht, und davon, wie das Zugriffs-/Aktualisierungs-Muster der
+Daten aussieht.
+
+Vorteile für Zeilensperren:
+
+@itemize @bullet
+@item
+Weniger Sperrkonflikte beim Zugriff auf unterschiedliche Zeilen in vielen
+Threads.
+@item
+Weniger Änderungen bei Rollbacks.
+@item
+Macht es möglich, eine einzelne Zeile lange zu sperren.
+@end itemize
+
+Nachteile:
+
+@itemize @bullet
+@item
+Benötigt mehr Speicher als Sperren auf Seiten- oder Tabellenebene.
+@item
+Ist langsamer als Sperren auf Seiten- oder Tabellenebene, wenn es einen
+großen Teil der Tabelle betrifft, weil man viel mehr Sperren durchführen
+muss.
+@item
+Ist definitiv viel schlechter als andere Sperren, wenn Sie oft @code{GROUP
+BY} auf einen großen Teil der Daten ausführen oder wenn man die gesamte
+Tabelle oft scannen muss.
+@item
+Bei Sperren auf höherer Ebene kann man einfacher Sperren unterschiedlichen
+Typs unterstützen, um die Applikation zu optimieren, weil der
+Sperr-Overhead sich weniger als bei Sperren auf Zeilenebene bemerkbar
+macht.
+@end itemize
+
+Tabellensperren sind Seiten- oder Zeilensperren in folgenden Fällen
+überlegen:
+
+@itemize @bullet
+@item
+Wenn man meist liest.
+@item
+Wenn Lese- und Aktualisierungsoperationen auf strengen Schlüsseln erfolgen.
+Das ist dann der Fall, wenn man eine Zeile aktualisiert oder löscht, die
+mit einem Schlüssel-Lesen geholt werden kann:
+@example
+UPDATE tabelle SET spalte=wert WHERE eindeutige_schluessel_nummer
+DELETE FROM tabelle WHERE eindeutiger_schluessel=#
+@end example
+@item
+@code{SELECT} in Kombination mit @code{INSERT} (und sehr wenigen
+@code{UPDATE}'s und @code{DELETE}'s).
+@item
+Viele Scans / @code{GROUP BY} auf die gesamte Tabelle ohne irgend welche
+Schreibvorgänge.
+@end itemize
+
+Andere Optionen als Sperren auf Zeilen- / Seiten-Ebene:
+
+Versionierung (wie die, die wir bei MySQL für gleichzeitige Einfügevorgänge
+nutzen), bei der man gleichzeitig einen Schreibvorgang haben kann, während
+viele Lesevorgänge stattfinden. Das heißt, dass die Datenbank / Tabelle
+verschiedene Sichten der Daten unterstützt, abhängig davon, wann man
+anfing, darauf zuzugreifen. Andere Namen hierfür sind Zeitreisen, Kopieren
+beim Schreiben (Copy on Write) oder Kopieren bei Bedarf (Copy on Demand).
+
+Kopieren bei Bedarf ist in vielen Fällen viel besser als Sperren auf
+Seiten- oder Zeilenebene. Im schlimmsten Fall wird jedoch viel mehr
+Speicher verbraucht als bei der Benutzung normaler Sperren.
+
+Anstelle von Zeilen-Sperren kann man Sperren auf Applikationsebene
+benutzen (wie get_lock/release_lock in MySQL). Das funktioniert natürlich
+nur bei 'wohl erzogenen' Applikationen.
+
+In vielen Fällen kann man auf fortgeschrittene Art raten, welcher Sperrtyp
+der beste für die Applikation ist, aber allgemein ist es sehr schwer zu
+sagen, dass ein bestimmter Sperrtyp besser ist als ein anderer. Alles hängt
+von der Applikation ab, und verschiedene Teile der Applikation können nach
+unterschiedlichen Sperrtypen verlangen.
+
+Hier sind einige Tipps zu Sperren in MySQL:
+
+Bei Web-Applikation führen die meisten Applikationen viele SELECTs aus,
+sehr wenige DELETEs, UPDATEs hauptsächlich auf Schlüssel und INSERTs in
+einigen bestimmten Tabellen. Die grundlegende Einrichtung von MySQL ist
+hierfür BESTENS optimiert.
+
+Gleichzeitige Benutzer sind kein Problem, solange man UPDATEs und SELECTs
+nicht vermischt, die beide gleichzeitig viele Zeilen in derselben Tabelle
+untersuchen müssen.
+
+Wenn man INSERTs und DELETEs auf dieselbe Tabelle mischt, kann @code{INSERT
+DELAYED} eine große Hilfe sein.
+
+Man kann auch @code{LOCK TABLES} benutzen, um Dinge zu beschleunigen (viele
+UPDATEs innerhalb einer einzelnen Sperre sind viel schneller als UPDATEs
+ohne Sperren). Daten in unterschiedliche Tabellen aufteilen hilft hierbei
+auch.
+
+Wenn Sie Geschwindigkeitsprobleme mit den Tabellensperren in MySQL
+bekommen, können Sie diese eventuell dadurch lösen, dass Sie Ihre Tabellen
+in @code{BDB}-Tabellen umwandeln.
+@xref{BDB}.
+
+Der Optimierungsabschnitt dieses Handbuchs behandelt viele verschiedene
+Aspekte dessen, wie man seine Applikationen optimieren kann. @xref{Tips}.
+
+
+@node RTS-threads, Thread packages, Locking methods, Porting
+@c German node RTS-Thread
+@appendixsec Anmerkungen zu RTS-Thread
+
+@cindex RTS-Thread
+@cindex Thread, RTS
+
+Ich habe versucht, die RTS-Thread-Pakete bei MySQL zu benutzen, bin aber
+über folgende Probleme gestolpert:
+
+Sie benutzen die alte Version vieler POSIX-Aufrufe und es ist sehr mühsam,
+Wrapper für alle Funktionen zu schreiben. Ich neige dazu zu denken, dass es
+leichter ist, die Thread-Bibliotheken auf die neueste POSIX-Spezifikation
+zu ändern.
+
+Einige Wrapper sind bereits geschrieben. Siehe @file{mysys/my_pThread.c}
+wegen weiterer Informationen.
+
+Zumindest folgendes sollte geändert werden:
+
+@code{pthread_get_specific} sollte ein Argument benutzen.
+@code{sigwait} sollte zwei Argumente entgegennehmen.
+Viele Funktionen (zumindest @code{pthread_cond_wait} und
+@code{pthread_cond_timedwait}) sollten bei einem Fehler den Fehler-Code
+zurückgeben. Momentan geben sie -1 zurück und setzen @code{errno}.
+
+Ein weiteres Problem ist, dass Threads auf Benutzerebene das
+@code{ALRM}-Signal benutzen und dass dieses viele Funktionen abbricht
+(@code{read}, @code{write}, @code{open}, ...). MySQL sollte versuchen, nach
+der Unterbrechung all dieser Funktionen weiterzumachen, aber das ist nicht
+einfach zu verifizieren.
+
+Das größte ungelöste Problem ist folgendes:
+
+Um Alarme auf Thread-Ebene zu erhalten, änderte ich
+@file{mysys/thr_alarm.c} in der Art, dass es zwischen Alarmen wartet, mit
+@code{pthread_cond_timedwait()}, aber das bricht mit Fehler @code{EINTR}
+ab. Ich versuchte, die Thread-Bibliothek zu debuggen, um den Grund
+herauszufinden, konnte aber keine einfache Lösung finden.
+
+Wenn jemand MySQL mit RTS-Thread ausprobieren möchte, schlage ich folgendes
+vor:
+
+@itemize @bullet
+@item
+Funktionen, die MySQL benutzt, von der Thread-Bibliothek zu POSIX ändern.
+Das sollte nicht lange dauern.
+@item
+Alle Bibliotheken mit @code{-DHAVE_rts_thread} kompilieren.
+@item
+@code{thr_alarm} kompilieren.
+@item
+Wenn es kleine Unterschiede in der Implementation gibt, können diese
+behoben werden, indem man @file{my_pThread.h} und @file{my_pThread.c}
+ändert.
+@item
+@code{thr_alarm} laufen lassen. Wenn es ohne irgend welche ``warning''-,
+``error''- oder ``aborted''-Meldungen läuft, sind Sie auf dem richtigen
+Weg. Hier ist ein erfolgreiches Laufenlassen unter Solaris:
+@example
+Main Thread: 1
+Thread 0 (5) started
+Thread: 5 Waiting
+process_alarm
+Thread 1 (6) started
+Thread: 6 Waiting
+process_alarm
+process_alarm
+thread_alarm
+Thread: 6 Slept for 1 (1) sec
+Thread: 6 Waiting
+process_alarm
+process_alarm
+thread_alarm
+Thread: 6 Slept for 2 (2) sec
+Thread: 6 Simulation of no alarm needed
+Thread: 6 Slept for 0 (3) sec
+Thread: 6 Waiting
+process_alarm
+process_alarm
+thread_alarm
+Thread: 6 Slept for 4 (4) sec
+Thread: 6 Waiting
+process_alarm
+thread_alarm
+Thread: 5 Slept for 10 (10) sec
+Thread: 5 Waiting
+process_alarm
+process_alarm
+thread_alarm
+Thread: 6 Slept for 5 (5) sec
+Thread: 6 Waiting
+process_alarm
+process_alarm
+
+...
+thread_alarm
+Thread: 5 Slept for 0 (1) sec
+end
+@end example
+@end itemize
+
+
+@node Thread packages, , RTS-threads, Porting
+@c German node Thread-Pakete
+@appendixsec Unterschiede zwischen verschiedenen Thread-Paketen
+
+@cindex Thread-Pakete, Unterschiede
+
+MySQL ist sehr abhängig vom verwendeten Thread-Paket. Wenn Sie daher eine
+gute Plattform für MySQL auswählen, ist das Thread-Paket sehr wichtig.
+
+Es gibt mindestens drei Typen von Thread-Paketen:
+
+@itemize @bullet
+@item
+Benutzer-Thread in einem einzelnen Prozess. Das Thread-Umschalten wird mit
+Alarmen gemacht und die Thread-Bibliothek verwaltet alle nicht
+Thread-sicheren Funktionen mit Sperren. Lese-, Schreib- und
+Auswahl-Operationen werden üblicherweise mit einer Thread-spezifischen
+Auswahl verwaltet, die auf einen anderen Thread umschaltet, wenn der
+laufende Thread auf Daten warten muss.
+Wenn die Benutzer-Thread-Pakete in die Standard-Bibliotheken integriert
+sind (FreeBSD- und BSDI-Thread), erfordert das Thread-Paket weniger
+Overhead als Thread-Pakete, die alle unsicheren Aufrufen mappen müssen
+(MIT-pThread, FSU-PThread und RTS-Thread). In einigen Umgebungen
+(beispielsweise SCO) sind alle Systemaufrufe Thread-sicher, weshalb das
+Mapping sehr leicht durchgeführt werden kann (FSU-PThread unter SCO).
+Nachteil: Alle gemappten Aufrufe benötigen etwas Zeit und es ist sehr
+verzwickt, alle Situationen handhaben zu können. Üblicherweise gibt es auch
+einige Systemaufrufe, die vom Thread-Paket nicht gehandhabt werden (wie
+MIT-pThread und Sockets). Thread-Scheduling ist nicht immer optimal.
+@item
+Benutzer-Thread in separaten Prozessen. Das Thread-Umschalten wird vom
+Kernel durchgeführt und alle Daten werden zwischen den Threads geteilt. Das
+Thread-Paket verwaltet die Standard-Thread-Aufrufe, so dass diese Daten
+zwischen Threads teilen können. LinuxThread benutzt diese Methode.
+Nachteil: viele Prozesse. Die Erzeugung von Threads ist langsam. Wenn ein
+Thread stirbt, bleiben die übrigen üblicherweise hängen, und Sie müssen
+alle töten, bevor Sie neu starten können. Man kann sagen, dass die
+Thread-Umschaltung ziemlich viel kostet.
+@item
+Kernel-Thread. Das Thread-Umschalten wird von der Thread-Bibliothek oder
+dem Kernel durchgeführt und ist sehr schnell. Alles wird in einem Prozess
+gemacht, aber auch manchen Systemen zeigt @code{ps} die verschiedenen
+Threads. Wenn ein Thread abbricht, bricht der gesamte Prozess ab. Die
+meisten Systemaufrufe sind Thread-sicher und sollten sehr wenig Overhead
+beanspruchen. Solaris, HP-UX, AIX und OSF1 haben Kernel-Thread.
+@end itemize
+
+Auf manchen Systemen wird Kernel-Thread gehandhabt, indem
+Benutzerebenen-Thread in die Systembibliotheken integriert wird. In solchen
+Fällen kann das Umschalten nur von der Thread-Bibliothek durchgeführt
+werden und der Kernel ist sich nicht wirklich ``der Threads bewusst''.
+
+
+
+
+@node Environment variables, Regexp, Porting, Top
+@c German node Umgebungsvariablen
+@appendix Umgebungsvariablen
+
+@cindex Umgebungsvariablen, Auflistung
+
+Hier ist eine Auflistung aller Umgebungsvariablen, die direkt oder indirekt
+von MySQL benutzt werden. Die meisten von ihnen finden sich auch an anderen
+Stellen dieses Handbuchs.
+
+Beachten Sie, dass jegliche Optionen auf der Kommandozeile vorrangig vor
+Werten, die in Konfigurationsdateien und Umgebungsvariablen angegeben sind,
+und Werte in Konfigurationsdateien vorrangig vor Werten in
+Umgebungsvariablen sind.
+
+In vielen Fällen ist es vorzuziehen, eine configure-Datei anstelle von
+Umgebungsvariablen zu verwenden, um das Verhalten von MySQL zu
+beeinflussen. @xref{Option files}.
+
+@tindex CCX-Umgebungsvariable
+@tindex Umgebungsvariable, CCX
+@tindex CC-Umgebungsvariable
+@tindex Umgebungsvariable, CC
+@tindex CFLAGS-Umgebungsvariable
+@tindex Umgebungsvariable, CFLAGS
+@tindex CXXFLAGS-Umgebungsvariable
+@tindex Umgebungsvariable, CXXFLAGS
+@tindex DBI_USER-Umgebungsvariable
+@tindex Umgebungsvariable, DBI_USER
+@tindex DBI_TRACE-Umgebungsvariable
+@tindex Umgebungsvariable, DBI_TRACE
+@tindex HOME-Umgebungsvariable
+@tindex Umgebungsvariable, HOME
+@tindex LD_RUN_PATH-Umgebungsvariable
+@tindex Umgebungsvariable, LD_RUN_PATH
+@tindex MYSQL_DEBUG-Umgebungsvariable
+@tindex Umgebungsvariable, MYSQL_DEBUG
+@tindex MYSQL_HISTFILE-Umgebungsvariable
+@tindex Umgebungsvariable, MYSQL_HISTFILE
+@tindex MYSQL_HOST-Umgebungsvariable
+@tindex Umgebungsvariable, MYSQL_HOST
+@tindex MYSQL_PWD-Umgebungsvariable
+@tindex Umgebungsvariable, MYSQL_PWD
+@tindex MYSQL_TCP_PORT-Umgebungsvariable
+@tindex Umgebungsvariable, MYSQL_TCP_PORT
+@tindex MYSQL_UNIX_PORT-Umgebungsvariable
+@tindex Umgebungsvariable, MYSQL_UNIX_PORT
+@tindex PATH-Umgebungsvariable
+@tindex Umgebungsvariable, PATH
+@tindex TMPDIR-Umgebungsvariable
+@tindex Umgebungsvariable, TMPDIR
+@tindex TZ-Umgebungsvariable
+@tindex Umgebungsvariable, TZ
+@tindex UMASK_DIR-Umgebungsvariable
+@tindex Umgebungsvariable, UMASK_DIR
+@tindex UMASK-Umgebungsvariable
+@tindex Umgebungsvariable, UMASK
+@tindex USER-Umgebungsvariable
+@tindex Umgebungsvariable, USER
+
+@multitable @columnfractions .2 .8
+@item @code{CCX} @tab Setzen Sie diese für Ihren C++-Kompiler, wenn Sie
+configure laufen lassen.
+@item @code{CC} @tab Setzen Sie diese für Ihren C-Kompiler, wenn Sie
+configure laufen lassen.
+@item @code{CFLAGS} @tab Flags für Ihren C-Kompiler, wenn Sie
+configure laufen lassen.
+@item @code{CXXFLAGS} @tab Flags für Ihren C++-Kompiler wenn Sie
+configure laufen lassen.
+@item @code{DBI_USER} @tab Der vorgabemäßige Benutzername für Perl-DBI.
+@item @code{DBI_TRACE} @tab Beim Tracen in Perl-DBI benutzt.
+@item @code{HOME} @tab Der vorgabemäßige Pfad für die
+@code{mysql}-History-Datei ist @file{$HOME/.mysql_history}.
+@item @code{LD_RUN_PATH} @tab Wird benutzt um anzugeben, wo Ihr
+@code{libmysqlclient.so} ist.
+@item @code{MYSQL_DEBUG} @tab Debug-Trace-Optionen beim Debuggen.
+@item @code{MYSQL_HISTFILE} @tab Der Pfad zur @code{mysql}-History-Datei.
+@item @code{MYSQL_HOST} @tab Vorgabemäßiger Hostname, der von der
+@code{mysql}-Befehlszeilenaufforderung benutzt wird.
+@item @code{MYSQL_PWD} @tab Das vorgabemäßige Passwort bei der Verbindung
+mit @code{mysqld}. Beachten Sie, dass die Benutzung dieser
+Umgebungsvariablen unsicher ist!
+@item @code{MYSQL_TCP_PORT} @tab Der vorgabemäßige TCP/IP-Port.
+@item @code{MYSQL_UNIX_PORT} @tab Der vorgabemäßige Socket; benutzt für
+Verbindungen nach @code{localhost}.
+@item @code{PATH} @tab Wird von der Shell benutzt, um die MySQL-Programme
+zu finden.
+@item @code{TMPDIR} @tab Das Verzeichnis, in dem temporäre Tabellen /
+Dateien erzeugt werden.
+@item @code{TZ} @tab Diese Variable sollte auf Ihre lokale Zeitzone gesetzt
+sein. @xref{Timezone problems}.
+@item @code{UMASK_DIR} @tab Die Erzeugungsmaske (Creation Mask) des
+Benutzer-Verzeichnisses, wenn Verzeichnisse angelegt werden. Beachten Sie,
+dass diese mit @code{UMASK} mit einem logischen UND verknüpft wird!
+@item @code{UMASK} @tab Die Erzeugungsmaske (Creation Mask) bei der
+Erzeugung von Dateien.
+@item @code{USER} @tab Der vorgabemäßige Benutzer unter Windows, der beim
+Verbinden mit @code{mysqld} benutzt wird.
+@end multitable
+
+
+
+
+@node Regexp, GPL license, Environment variables, Top
+@c German node Reguläre Ausdrücke
+@appendix Beschreibung der MySQL-Syntax für reguläre Ausdrücke
+
+@cindex regex
+@cindex Syntax regulärer Ausdrücke, Beschreibung
+@cindex Syntax, reguläre Ausdrücke
+
+Ein regulärer Ausdruck (regex) ist eine mächtige Möglichkeit, eine komplexe
+Suche zu formulieren.
+
+MySQL benutzt Henry Spencers Implementation regulärer Ausdrücke, die
+anstrebt, POSIX-1003.2-konform zu sein. MySQL benutzt die erweiterte
+Version.
+
+Die vorliegende vereinfachte Referenz überspringt die Details. Um genauere
+Informationen zu erhalten, sehen Sie sich Henry Spencers
+@code{regex(7)}-Handbuchseite an, die in der Quelldistribution enthalten
+ist. @xref{Credits}.
+
+Ein regulärer Ausdruck beschreibt einen Satz von Zeichenketten. Der
+einfachste regexp ist einer, der keine Sonderzeichen enthält. Der regexp
+@code{hello} beispielsweise stimmt mit @code{hello} und sonst nichts
+überein.
+
+Nicht triviale reguläre Ausdrücke benutzen bestimmte spezielle Konstrukte,
+so dass sie mit mehr als einer Zeichenkette übereinstimmen können. Der
+regexp @code{hallo|stefan} beispielsweise stimmt entweder mit der
+Zeichenkette @code{hallo} oder der Zeichenkette @code{stefan} überein.
+
+Um ein komplexeres Beispiel zu geben, stimmt der regexp @code{B[an]*s} mit
+jeder der Zeichenketten @code{Bananas}, @code{Baaaaas}, @code{Bs} und jeder
+anderen Zeichenkette überein, die mit einem @code{B} anfängt, mit einem
+@code{s} aufhört und jede beliebige Anzahl von @code{a}- oder
+@code{n}-Zeichen dazwischen enthält.
+
+Ein regulärer Ausdruck kann jedes der folgenden Sonderzeichen bzw.
+Konstrukte benutzen (0 = keine Übereinstimmung):
+@table @code
+@item ^
+Stimmt mit dem Anfang einer Zeichenkette überein.
+@example
+mysql> select "fo\nfo" REGEXP "^fo$"; -> 0
+mysql> select "fofo" REGEXP "^fo"; -> 1
+@end example
+@item $
+Stimmt mit dem Ende einer Zeichenkette überein.
+@example
+mysql> select "fo\no" REGEXP "^fo\no$"; -> 1
+mysql> select "fo\no" REGEXP "^fo$"; -> 0
+@end example
+@item .
+Stimmt mit jedem Zeichen überein (inklusive neue Zeile).
+@example
+mysql> select "fofo" REGEXP "^f.*"; -> 1
+mysql> select "fo\nfo" REGEXP "^f.*"; -> 1
+@end example
+@item a*
+Stimmt mit jeder Folge von 0 oder mehr @code{a}-Zeichen überein.
+@example
+mysql> select "Ban" REGEXP "^Ba*n"; -> 1
+mysql> select "Baaan" REGEXP "^Ba*n"; -> 1
+mysql> select "Bn" REGEXP "^Ba*n"; -> 1
+@end example
+@item a+
+Stimmt mit jeder Folge von einem oder mehr @code{a}-Zeichen überein.
+@example
+mysql> select "Ban" REGEXP "^Ba+n"; -> 1
+mysql> select "Bn" REGEXP "^Ba+n"; -> 0
+@end example
+@item a?
+Stimmt mit 0 oder einem @code{a}-Zeichen überein.
+@example
+mysql> select "Bn" REGEXP "^Ba?n"; -> 1
+mysql> select "Ban" REGEXP "^Ba?n"; -> 1
+mysql> select "Baan" REGEXP "^Ba?n"; -> 0
+@end example
+@item de|abc
+Stimmt mit den Zeichenfolgen @code{de} oder @code{abc} überein.
+@example
+mysql> select "pi" REGEXP "pi|apa"; -> 1
+mysql> select "axe" REGEXP "pi|apa"; -> 0
+mysql> select "apa" REGEXP "pi|apa"; -> 1
+mysql> select "apa" REGEXP "^(pi|apa)$"; -> 1
+mysql> select "pi" REGEXP "^(pi|apa)$"; -> 1
+mysql> select "pix" REGEXP "^(pi|apa)$"; -> 0
+@end example
+@item (abc)*
+Stimmt mit 0 oder mehr Instanzen der Folge @code{abc} überein.
+@example
+mysql> select "pi" REGEXP "^(pi)*$"; -> 1
+mysql> select "pip" REGEXP "^(pi)*$"; -> 0
+mysql> select "pipi" REGEXP "^(pi)*$"; -> 1
+@end example
+@item @{1@}
+@itemx @{2,3@}
+Es gibt eine allgemeinere Schreibweise für regexps, die mit vielen
+Vorkommen des vorherigen Atoms übereinstimmen.
+@table @code
+@item a*
+Kann als @code{a@{0,@}} geschrieben werden.
+@item a+
+Kann als @code{a@{1,@}} geschrieben werden.
+@item a?
+Kann als @code{a@{0,1@}} geschrieben werden.
+@end table
+
+Um genauer zu sein, stimmt ein Atom, gefolgt von einer Begrenzung, die eine
+Ganzzahl @code{i} und keine Kommas enthält, mit einer Folge von genau
+@code{i} Übereinstimmungen des Atoms überein. Ein Atom gefolgt von einer
+Begrenzung, die eine Ganzzahl @code{i} und ein Komma enthält, stimmt mit
+einer Folge von @code{i} oder mehr Übereinstimmungen des Atoms überein. Ein
+Atom, gefolgt von einer Begrenzung, die zwei Ganzzahlen @code{i} und
+@code{j} Übereinstimmungen enthält, stimmt mit einer Folge von @code{i} bis
+@code{j} (inklusive) Übereinstimmungen des Atoms überein.
+
+Beide Argumente müssen im Bereich von @code{0} bis @code{RE_DUP_MAX}
+(Vorgabe 255) inklusive sein. Wenn es zwei Argumente gibt, muss das zweite
+größer oder gleich dem ersten sein.
+@item [a-dX]
+@itemx [^a-dX]
+Stimmt mit jedem Zeichen überein, was entweder @code{a}, @code{b},
+@code{c}, @code{d} oder @code{X} ist (oder nicht ist, wenn ^ benutzt wird).
+Um ein literales @code{]}-Zeichen einzuschließen, muss es unmittelbar der
+öffnenden Klammer @code{[} folgen. Um ein literales @code{-}-Zeichen
+einzuschließen, muss es zuerst oder zuletzt geschrieben werden. Daher
+stimmt @code{[0-9]} mit jeder Dezimalziffer überein. Alle Zeichen, die
+innerhalb eines @code{[]}-Paars keine definierte Bedeutung haben, haben
+keine spezielle Bedeutung und stimmen nur mit sich selbst überein.
+@example
+mysql> select "aXbc" REGEXP "[a-dXYZ]"; -> 1
+mysql> select "aXbc" REGEXP "^[a-dXYZ]$"; -> 0
+mysql> select "aXbc" REGEXP "^[a-dXYZ]+$"; -> 1
+mysql> select "aXbc" REGEXP "^[^a-dXYZ]+$"; -> 0
+mysql> select "gheis" REGEXP "^[^a-dXYZ]+$"; -> 1
+mysql> select "gheisa" REGEXP "^[^a-dXYZ]+$"; -> 0
+@end example
+@item [[.zeichen.]]
+Die Zeichenfolge des vereinigten Elements. Die Folge ist ein einzelnes
+Element der Ausdrucksliste in der Klammer. Ein Klammerausdruck, der ein
+Mehrzeichen-Vereinigungselement enthält, kann daher mit mehr als einem
+Zeichen übereinstimmen. Wenn die Vereinigungsfolge zum Beispiel ein
+@code{ch}-Vereinigungselement enthält, stimmt der reguläre Ausdruck
+@code{[[.ch.]]*c} mit den ersten fünf Zeichen von @code{chchcc} überein.
+
+@item [=zeichen_klasse=]
+Eine Äquivalenzklasse, die für Zeichenfolgen aller Vereinigungselemente
+dieser steht, inklusive sich selbst.
+
+Wenn zum Beispiel @code{o} und @code{(+)} die Mitglieder einer
+Äquivalenzklasse sind, sind @code{[[=o=]]}, @code{[[=(+)=]]} und
+@code{[o(+)]} allesamt Synonyme. Eine Äquivalenzklasse darf kein Endpunkt
+eines Bereichs sein.
+
+@item [:zeichen_klasse:]
+Innerhalb eines Klammerausdrucks steht der Name einer Zeichenklasse, die in
+@code{[:} und @code{:]} eingeschlossen ist, für die Auflistung aller
+Zeichen, die zu dieser Klasse gehören. Standard-Zeichenklassennamen sind:
+
+@multitable @columnfractions .33 .33 .33
+@item alnum @tab digit @tab punct
+@item alpha @tab graph @tab space
+@item empty @tab lower @tab upper
+@item cntrl @tab print @tab xdigit
+@end multitable
+
+Diese stehen für die Zeichenklassen, die auf der
+@code{ctype(3)}-Handbuchseite definiert sind. Ein Locale darf andere zur
+Verfügung stellen. Eine Zeichenklasse darf nicht als Endpunkt eines
+Bereichs benutzt werden.
+@example
+mysql> select "justalnums" REGEXP "[[:alnum:]]+"; -> 1
+mysql> select "!!" REGEXP "[[:alnum:]]+"; -> 0
+@end example
+
+@item [[:<:]]
+@itemx [[:>:]]
+Diese stimmen mit der Null-Zeichenkette am Anfang bzw. am Ende eines Worts
+überein. Ein Wort ist definiert als Folge von Wort-Zeichen, dem weder
+Wortzeichen vorangestellt sind noch darauf folgen. Ein Wortzeichen ist ein
+alnum-Zeichen (wie in @code{ctype(3)} definiert) oder ein Unterstrich
+(@code{_}).
+@example
+mysql> select "a word a" REGEXP "[[:<:]]word[[:>:]]"; -> 1
+mysql> select "a xword a" REGEXP "[[:<:]]word[[:>:]]"; -> 0
+@end example
+@end table
+
+@example
+mysql> select "weeknights" REGEXP "^(wee|week)(knights|nights)$"; -> 1
+@end example
+
+
+@page
+@c This node name ist special
+
+
+
+@node GPL license, LGPL license, Regexp, Top
+@c German node GPL-Lizenz
+@appendix GNU GENERAL PUBLIC LICENSE
+
+@cindex GPL, General Public License
+@cindex GPL, GNU General Public License
+
+@center Version 2, Juni 1991
+
+@display
+Copyright @copyright{} 1989, 1991 Free Software Foundation, Inc.
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+
+Jeder hat das Recht, diese Lizenzurkunde zu vervielfältigen und
+unveränderte Kopien zu verbreiten; Änderungen sind jedoch nicht gestattet.
+@end display
+
+@appendixsec Vorwort
+
+Die meisten Softwarelizenzen sind daraufhin entworfen worden, Ihnen die
+Freiheit zu nehmen, die Software weiterzugeben und zu verändern.
+Im Gegensatz dazu soll Ihnen die GNU General Public License, die
+allgemeine öffentliche GNU-Lizenz, ebendiese Freiheit garantieren.
+Sie soll sicherstellen, dass die Software für alle Benutzer frei ist.
+Diese Lizenz gilt für den Großteil der von der Free Software Foundation
+herausgegebenen Software und für alle anderen Programme, deren Autoren
+ihr Werk dieser Lizenz unterstellt haben. Auch Sie können diese
+Möglichkeit der Lizenzierung für Ihre Programme anwenden.
+(Ein anderer Teil der Software der Free Software Foundation unterliegt
+stattdessen der GNU Library General Public License, der allgemeinen
+öffentlichen GNU-Lizenz für Bibliotheken.)
+
+Die Bezeichnung "freie" Software bezieht sich auf Freiheit, nicht auf
+den Preis. Unsere Lizenzen sollen Ihnen die Freiheit garantieren,
+Kopien freier Software zu verbreiten (und etwas für diesen Service zu
+berechnen, wenn Sie möchten), die Möglichkeit, die Software im Quelltext
+zu erhalten oder den Quelltext auf Wunsch zu bekommen. Die Lizenzen
+sollen garantieren, dass Sie die Software ändern oder Teile davon in
+neuen freien Programmen verwenden dürfen - und dass Sie wissen, dass
+Sie dies alles tun dürfen.
+
+Um Ihre Rechte zu schützen, müssen wir Einschränkungen machen, die es
+jedem verbieten, Ihnen diese Rechte zu verweigern oder Sie aufzufordern,
+auf diese Rechte zu verzichten. Aus diesen Einschränkungen folgen
+bestimmte Verantwortlichkeiten für Sie, wenn Sie Kopien der Software
+verbreiten oder sie verändern.
+
+Beispielsweise müssen Sie den Empfängern alle Rechte gewähren, die
+Sie selbst haben, wenn Sie - kostenlos oder gegen Bezahlung - Kopien
+eines solchen Programms verbreiten. Sie müssen sicherstellen, dass auch
+sie den Quelltext erhalten bzw. erhalten können. Und Sie müssen ihnen
+diese Bedingungen zeigen, damit sie Ihre Rechte kennen.
+
+Wir schützen Ihre Rechte in zwei Schritten: (1) Wir stellen die Software
+unter ein Urheberrecht (Copyright), und (2) wir bieten Ihnen diese Lizenz
+an, die Ihnen das Recht gibt, die Software zu vervielfältigen, zu
+verbreiten und/oder zu verändern.
+
+Um die Autoren und uns zu schützen, wollen wir darüberhinaus sicherstellen,
+dass jeder erfährt, dass für diese freie Software keinerlei Garantie besteht.
+Wenn die Software von jemand anderem modifiziert und weitergegeben wird,
+möchten wir, dass die Empfänger wissen, dass sie nicht das Original erhalten
+haben, damit von anderen verursachte Probleme nicht den Ruf des
+ursprünglichen Autors schädigen.
+
+Schließlich und endlich ist jedes freie Programm permanent durch
+Software-Patente bedroht. Wir möchten die Gefahr ausschließen, dass
+Distributoren eines freien Programms individuell Patente lizensieren
+ - mit dem Ergebnis, dass das Programm proprietär würde. Um dies zu
+ verhindern, haben wir klargestellt, dass jedes Patent entweder für freie
+Benutzung durch jedermann lizenziert werden muss oder überhaupt nicht
+lizenziert werden darf.
+
+Es folgen die genauen Bedingungen für die Vervielfältigung,
+Verbreitung und Bearbeitung:
+
+@iftex
+@appendixsec Bedingungen für die Vervielfältigung,
+Verbreitung und Bearbeitung
+@end iftex
+@ifinfo
+@center GNU GENERAL PUBLIC LICENSE
+@center Bedingungen für die Vervielfältigung, Verbreitung
+und Bearbeitung
+@end ifinfo
+
+@enumerate 0
+@item
+Diese Lizenz gilt für jedes Programm und jedes andere Werk, in dem
+ein entsprechender Vermerk des Copyright-Inhabers darauf hinweist,
+dass das Werk unter den Bestimmungen dieser General Public License
+verbreitet werden darf. Im folgenden wird jedes derartige Programm
+oder Werk als "das Programm" bezeichnet; die Formulierung "auf dem
+Programm basierendes Werk" bezeichnet das Programm sowie jegliche
+Bearbeitung des Programms im urheberrechtlichen Sinne, also ein Werk,
+welches das Programm, auch auszugsweise, sei es unverändert oder
+verändert und/oder in eine andere Sprache übersetzt, enthält.
+(Im folgenden wird die Übersetzung ohne Einschränkung als
+"Bearbeitung" eingestuft.) Jeder Lizenznehmer wird im folgenden
+als "Sie" angesprochen.
+
+Andere Handlungen als Vervielfältigung, Verbreitung und Bearbeitung
+werden von dieser Lizenz nicht berührt; sie fallen nicht in Ihren
+Anwendungsbereich. Der Vorgang der Ausführung des Programms wird
+nicht eingeschränkt, und die Ausgaben des Programms unterliegen
+dieser Lizenz nur, wenn der Inhalt ein auf dem Programm basierendes
+Werk darstellt (unabhängig davon, dass die Ausgabe durch die
+Ausführung des Programmes erfolgte). Ob dies zutrifft, hängt von den
+Funktionen des Programms ab.
+
+@item
+Sie dürfen auf beliebigen Medien unveränderte Kopien des Quelltextes
+des Programms, wie sie ihn erhalten haben, anfertigen und verbreiten.
+Voraussetzung hierfür ist, dass Sie mit jeder Kopie einen entsprechenden
+Copyright-Vermerk sowie einen Haftungsausschluss veröffentlichen, alle
+Vermerke, die sich auf diese Lizenz und das Fehlen einer Garantie
+beziehen, unverändert lassen und desweiteren allen anderen Empfängern
+des Programms zusammen mit dem Programm eine Kopie dieser Lizenz
+zukommen lassen.
+
+Sie dürfen für den eigentlichen Kopiervorgang eine Gebühr verlangen.
+Wenn Sie es wünschen, dürfen Sie auch gegen Entgelt eine Garantie
+für das Programm anbieten.
+
+@item
+Sie dürfen Ihre Kopie(n) des Programms oder eines Teils davon
+verändern, wodurch ein auf dem Programm basierendes Werk entsteht;
+Sie dürfen derartige Bearbeitungen unter den Bestimmungen von
+Paragraph 1 vervielfältigen und verbreiten, vorausgesetzt, dass
+zusätzlich alle folgenden Bedingungen erfüllt werden:
+
+@enumerate a
+@item
+Sie müssen die veränderten Dateien mit einem auffälligen Vermerk
+versehen, der auf die von Ihnen vorgenommene Modifizierung und
+das Datum jeder Änderung hinweist.
+
+@item
+Sie müssen dafür sorgen, dass jede von Ihnen verbreitete oder
+veröffentlichte Arbeit, die ganz oder teilweise von dem Programm
+oder Teilen davon abgeleitet ist, Dritten gegenüber als Ganzes
+unter den Bedingungen dieser Lizenz ohne Lizenzgebühren zur
+Verfügung gestellt wird.
+
+@item
+Wenn das veränderte Programm normalerweise bei der Ausführung
+interaktiv Kommandos einliest, müssen Sie dafür sorgen, dass es,
+wenn es auf dem üblichsten Wege für solche interaktive Nutzung
+gestartet wird, eine Meldung ausgibt oder ausdruckt, die einen
+geeigneten Copyright-Vermerk enthält sowie einen Hinweis, dass es
+keine Gewährleistung gibt (oder anderenfalls, dass Sie Garantie
+leisten), und dass die Benutzer das Programm unter diesen
+Bedingungen weiter verbreiten dürfen. Auch muss der Benutzer darauf
+hingewiesen werden, wie er eine Kopie dieser Lizenz ansehen kann.
+(Ausnahme: Wenn das Programm selbst interaktiv arbeitet, aber
+normalerweise keine derartige Meldung ausgibt, muss Ihr auf dem
+Programm basierendes Werk auch keine solche Meldung ausgeben).
+@end enumerate
+
+Diese Anforderungen betreffen das veränderte Werk als Ganzes.
+Wenn identifizierbare Abschnitte des Werkes nicht von dem
+Programm abgeleitet sind und vernünftigerweise selbst als
+unabhängige und eigenständige Werke betrachtet werden können, dann
+erstrecken sich diese Lizenz und Ihre Bedingungen nicht auf
+diese Abschnitte, wenn sie als eigenständige Werke verbreitet
+werden. Wenn Sie jedoch dieselben Abschnitte als Teil eines
+Ganzen verbreiten, dass ein auf dem Programm basierendes Werk
+darstellt, dann muss die Verbreitung des Ganzen nach den
+Bedingungen dieser Lizenz erfolgen, deren Bedingungen für
+weitere Lizenznehmer somit auf die Gesamtheit ausgedehnt werden
+- und damit auf jeden einzelnen Teil, unabhängig vom jeweiligen Autor.
+
+Somit ist es nicht die Absicht dieses Abschnittes, Rechte für
+Werke in Anspruch zu nehmen oder zu beschneiden, die komplett
+von Ihnen geschrieben wurden; vielmehr ist es die Absicht,
+die Rechte zur Kontrolle der Verbreitung von Werken, die auf
+dem Programm basieren oder unter seiner auszugsweisen
+Verwendung zusammengestellt worden sind, auszuüben.
+
+Ferner bringt ein einfaches Zusammenstellen eines anderen Werkes,
+das nicht auf dem Programm basiert, zusammen mit dem Programm
+oder einem auf dem Programm basierenden Werk auf ein- und
+demselben Speicher- oder Vertriebsmedium das andere Werk nicht in
+den Anwendungsbereich dieser Lizenz.
+
+@item
+Sie dürfen das Programm (oder ein darauf basierendes Werk gemäß
+Paragraph 2) als Objectcode oder in ausführbarer Form unter den
+Bedingungen von Paragraph 1 und 2 vervielfältigen und verbreiten
+- vorausgesetzt, dass Sie außerdem eine der folgenden Leistungen
+erbringen:
+
+@enumerate a
+@item
+Liefern Sie das Programm zusammen mit dem vollständigen
+zugehörigen maschinenlesbaren Quelltext auf einem für den
+Datenaustausch üblichen Medium aus, wobei die Verteilung unter den
+Bedingungen der Paragraphen 1 und 2 erfolgen muß. Oder:
+
+@item
+Liefern Sie das Programm zusammen mit einem mindestens drei
+Jahre lang gültigen schriftlichen Angebot aus, jedem Dritten
+eine vollständige maschinenlesbare Kopie des Quelltextes zur
+Verfügung zu stellen - zu nicht höheren Kosten als denen, die
+durch den physikalischen Kopiervorgang anfallen -, wobei der
+Quelltext unter den Bedingungen der Paragraphen 1 und 2 auf
+einem für den Datenaustausch üblichen Medium weitergegeben
+wird. Oder:
+
+@item
+Liefern Sie das Programm zusammen mit dem schriftlichen An-
+gebot der Zurverfügungstellung des Quelltextes aus, das Sie
+selbst erhalten haben. (Diese Alternative ist nur für
+nicht-kommerzielle Verbreitung zulässig und nur, wenn Sie
+das Programm als Objectcode oder in ausführbarer Form mit
+einem entsprechenden Angebot gemäß Absatz b erhalten haben.)
+@end enumerate
+
+Unter dem Quelltext eines Werkes wird diejenige Form des Werkes
+verstanden, die für Bearbeitungen vorzugsweise verwendet wird.
+Für ein ausführbares Programm bedeutet "der komplette Quell-
+text": Der Quelltext aller im Programm enthaltenen Module ein-
+schließlich aller zugehörigen Modulschnittstellen-Definitions-
+dateien sowie der zur Compilation und Installation verwendeten
+Skripte. Als besondere Ausnahme jedoch braucht der verteilte
+Quelltext nichts von dem zu enthalten, was üblicherweise
+(entweder als Quelltext oder in binärer Form) zusammen mit den
+Hauptkomponenten des Betriebssystems (Kernel, Compiler usw.)
+geliefert wird, unter dem das Programm läuft - es sei denn,
+diese Komponente selbst gehört zum ausführbaren Programm.
+
+Wenn die Verbreitung eines ausführbaren Programms oder des
+Objectcodes dadurch erfolgt, dass der Kopierzugriff auf eine
+dafür vorgesehene Stelle gewährt wird, so gilt die Gewährung
+eines gleichwertigen Zugriffs auf den Quelltext als Verbreitung
+des Quelltextes, auch wenn Dritte nicht dazu gezwungen sind,
+den Quelltext zusammen mit dem Objectcode zu kopieren.
+
+@item
+Sie dürfen das Programm nicht vervielfältigen, verändern, weiter
+lizenzieren oder verbreiten, sofern es nicht durch diese Lizenz
+ausdrücklich gestattet ist. Jeder anderweitige Versuch der
+Vervielfältigung, Modifizierung, Weiterlizenzierung und Verbreitung
+ist nichtig und beendet automatisch Ihre Rechte unter dieser
+Lizenz. Jedoch werden die Lizenzen Dritter, die von Ihnen Kopien
+oder Rechte unter dieser Lizenz erhalten haben, nicht beendet,
+solange diese die Lizenz voll anerkennen und befolgen.
+
+@item
+Sie sind nicht verpflichtet, diese Lizenz anzunehmen, da Sie sie
+nicht unterzeichnet haben. Jedoch gibt Ihnen nichts anderes die
+Erlaubnis, das Programm oder von ihm abgeleitete Werke zu
+verändern oder zu verbreiten. Diese Handlungen sind gesetzlich
+verboten, wenn Sie diese Lizenz nicht anerkennen. Indem Sie das
+Programm (oder ein darauf basierendes Werk) verändern oder
+verbreiten, erklären Sie Ihr Einverständnis mit dieser Lizenz und
+mit allen Ihren Bedingungen bezüglich der Vervielfältigung,
+Verbreitung und Veränderung des Programms oder eines darauf
+basierenden Werkes.
+
+@item
+Jedesmal, wenn Sie das Programm (oder ein auf dem Programm
+basierendes Werk) weitergeben, erhält der Empfänger automatisch
+vom ursprünglichen Lizenzgeber die Lizenz, das Programm
+entsprechend den hier festgelegten Bestimmungen zu vervielfältigen,
+zu verbreiten und zu verändern. Sie dürfen keine weiteren
+Einschränkungen der Durchsetzung der hierin zugestandenen Rechte
+des Empfängers vornehmen. Sie sind nicht dafür verantwortlich,
+die Einhaltung dieser Lizenz durch Dritte durchzusetzen.
+
+@item
+Sollten Ihnen infolge eines Gerichtsurteils, des Vorwurfs einer
+Patentverletzung oder aus einem anderen Grunde (nicht auf Patent
+fragen begrenzt) Bedingungen (durch Gerichtsbeschluß, Vergleich
+oder anderweitig) auferlegt werden, die den Bedingungen dieser
+Lizenz widersprechen, so befreien Sie diese Umstände nicht von
+den Bestimmungen dieser Lizenz. Wenn es Ihnen nicht möglich ist,
+das Programm unter gleichzeitiger Beachtung der Bedingungen in
+dieser Lizenz und Ihrer anderweitigen Verpflichtungen zu ver-
+breiten, dann dürfen Sie als Folge das Programm überhaupt nicht
+verbreiten. Wenn zum Beispiel ein Patent nicht die gebührenfreie
+Weiterverbreitung des Programms durch diejenigen erlaubt, die das
+Programm direkt oder indirekt von Ihnen erhalten haben, dann
+besteht der einzige Weg, sowohl das Patentrecht als auch diese
+Lizenz zu befolgen, darin, ganz auf die Verbreitung des Programms
+zu verzichten.
+
+Sollte sich ein Teil dieses Paragraphen als ungültig oder unter
+bestimmten Umständen nicht durchsetzbar erweisen, so soll dieser
+Paragraph seinem Sinne nach angewandt werden; im übrigen soll
+dieser Paragraph als Ganzes gelten.
+
+Zweck dieses Paragraphen ist nicht, Sie dazu zu bringen,
+irgendwelche Patente oder andere Eigentumsansprüche zu verletzen oder
+die Gültigkeit solcher Ansprüche zu bestreiten; dieser Paragraph
+hat einzig den Zweck, die Integrität des Verbreitungssystems der
+freien Software zu schützen, das durch die Praxis öffentlicher
+Lizenzen verwirklicht wird. Viele Leute haben großzügige Beiträge
+zu dem großen Angebot der mit diesem System verbreiteten Software
+im Vertrauen auf die konsistente Anwendung dieses Systems
+geleistet; es liegt am Autor/Geber, zu entscheiden, ob er die
+Software mittels irgendeines anderen Systems verbreiten will; ein
+Lizenznehmer hat auf diese Entscheidung keinen Einfluss.
+
+Dieser Paragraph ist dazu gedacht, deutlich klarzustellen, was als
+Konsequenz aus dem Rest dieser Lizenz betrachtet wird.
+
+@item
+Wenn die Verbreitung und/oder die Benutzung des Programms in be-
+stimmten Staaten entweder durch Patente oder durch urheberrechtlich
+geschützte Schnittstellen eingeschränkt ist, kann der Urheberrechts-
+inhaber, der das Programm unter diese Lizenz gestellt hat, eine
+explizite geographische Beschränkung der Verbreitung angeben, in der
+diese Staaten ausgeschlossen werden, so dass die Verbreitung nur
+innerhalb und zwischen den Staaten erlaubt ist, die nicht ausge-
+schlossen sind. In einem solchen Fall beinhaltet diese Lizenz die
+Beschränkung, als wäre sie in diesem Text niedergeschrieben.
+
+@item
+Die Free Software Foundation kann von Zeit zu Zeit überarbeitete
+und/oder neue Versionen der General Public License veröffentlichen.
+Solche neuen Versionen werden vom Grundprinzip her der gegenwärtigen
+entsprechen, können aber im Detail abweichen, um neuen Problemen und
+Anforderungen gerecht zu werden.
+
+Jede Version dieser Lizenz hat eine eindeutige Versionsnummer.
+Wenn in einem Programm angegeben wird, dass es dieser Lizenz in einer
+bestimmten Versionsnummer oder "jeder späteren Version" ("any later
+version") unterliegt, so haben Sie die Wahl, entweder den Bestimmungen
+der genannten Version zu folgen oder denen jeder beliebigen späteren
+Version, die von der Free Software Foundation veröffentlicht wurde.
+Wenn das Programm keine Versionsnummer angibt, können Sie eine beliebige
+Version wählen, die je von der Free Software Foundation veröffentlicht
+wurde.
+
+@item
+Wenn Sie den Wunsch haben, Teile des Programms in anderen freien Programmen
+zu verwenden, deren Bedingungen für die Verbreitung anders sind, schreiben
+Sie an den Autor, um ihn um die Erlaubnis zu bitten. Für Software, die unter
+dem Copyright der Free Software Foundation steht, schreiben Sie an die Free
+Software Foundation; wir machen zu diesem Zweck gelegentlich Ausnahmen.
+Unsere Entscheidung wird von den beiden Zielen geleitet werden, zum einen
+den freien Status aller von unserer freien Software abgeleiteten Werke zu
+erhalten und zum anderen das gemeinschaftliche Nutzen und Wiederverwenden
+von Software im allgemeinen zu fördern
+
+@iftex
+@heading Keine Gewährleistung
+@end iftex
+@ifinfo
+@center Keine Gewährleistung
+@end ifinfo
+
+@item
+Da das Programm ohne jegliche Kosten lizenziert wird, besteht keinerlei
+Gewährleistung für das Programm, soweit dies gesetzlich zulässig ist.
+Sofern nicht anderweitig schriftlich bestätigt, stellen die Copyright-Inhaber
+und/oder Dritte das Programm so zur Verfügung, "wie es ist", ohne irgendeine
+Gewährleistung, weder ausdrücklich noch implizit, einschließlich - aber nicht
+begrenzt auf - Marktreife oder Verwendbarkeit für einen bestimmten Zweck.
+Das volle Risiko bezüglich Qualität und Leistungsfähigkeit des Programms
+liegt bei Ihnen. Sollte sich das Programm als fehlerhaft herausstellen,
+liegen die Kosten für notwendigen Service, Reparatur oder Korrektur bei Ihnen.
+
+@item
+In keinem Fall, außer wenn durch geltendes Recht gefordert oder schriftlich
+zugesichert, ist irgendein Copyright-Inhaber oder irgendein Dritter, der das
+Programm wie oben erlaubt modifiziert oder verbreitet hat, Ihnen gegenüber
+für irgendwelche Schäden haftbar, einschließlich jeglicher allgemeiner oder
+spezieller Schäden, Schäden durch Seiteneffekte (Nebenwirkungen) oder
+Folgeschäden, die aus der Benutzung des Programms oder der Unbenutzbarkeit des
+Programms folgen (einschließlich - aber nicht beschränkt auf - Datenverluste,
+fehlerhafte Verarbeitung von Daten, Verluste, die von Ihnen oder anderen
+getragen werden müssen oder dem Unvermögen des Programms, mit irgendeinem
+anderen Programm zusammenzuarbeiten), selbst wenn ein Copyright-Inhaber
+oder Dritter über die Möglichkeit solcher Schäden unterrichtet worden war.
+@end enumerate
+
+@iftex
+@heading Ende der Bedingungen
+@end iftex
+@ifinfo
+@center Ende der Bedingungen
+@end ifinfo
+
+@page
+@appendixsec Anhang: Wie Sie diese Bedingungen auf Ihre neuen Programme anwendbar machen
+
+Wenn Sie ein neues Programm entwickeln und wollen, dass es von größtmöglichem
+Nutzen für die Allgemeinheit ist, dann erreichen Sie das am besten, indem
+Sie es zu freier Software machen, die jeder unter diesen Bestimmungen
+weiterverbreiten und verändern kann.
+
+Um dies zu erreichen, fügen Sie die folgenden Anmerkungen zu Ihrem Programm
+hinzu. Am sichersten ist es, sie an den Anfang einer jeden Quelldatei zu
+stellen, um den Gewährleistungsausschluß möglichst deutlich darzustellen;
+außerdem sollte jede Datei mindestens eine "Copyright"-Zeile besitzen sowie
+einen kurzen Hinweis darauf, wo die vollständige Lizenz gefunden werden kann.
+
+@smallexample
+@var{eine Zeile mit dem Programmnamen und einer kurzen Beschreibung}
+Copyright (C) @var{yyyy} @var{Name des Autors}
+
+This Programm ist free Software; you can redistribute it und / oder modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License oder
+(at your option) any later version.
+
+This Programm ist distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; ohne even the implied warranty of
+MERCHANTABILITY oder FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License für mehr details.
+
+You should have received a copy of the GNU General Public License
+along mit this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+@end smallexample
+
+Also add information on how to contact you von electronic und paper mail.
+
+@smallexample auf deutsch
+@var{eine Zeile mit dem Programmnamen und einer kurzen Beschreibung}
+Copyright (C) @var{yyyy} @var{Name des Autors}
+
+ Dieses Programm ist freie Software. Sie können es unter
+ den Bedingungen der GNU General Public License, wie von der
+ Free Software Foundation herausgegeben, weitergeben und/oder
+ modifizieren, entweder unter Version 2 der Lizenz oder (wenn
+ Sie es wünschen) jeder späteren Version.
+
+ Die Veröffentlichung dieses Programms erfolgt in der
+ Hoffnung, dass es Ihnen von Nutzen sein wird, aber OHNE JEDE
+ GEWÄHRLEISTUNG - sogar ohne die implizite Gewährleistung
+ der MARKTREIFE oder der EIGNUNG FÜR EINEN BESTIMMTEN ZWECK.
+ Details finden Sie in der GNU General Public License.
+
+ Sie sollten eine Kopie der GNU General Public License zusammen
+ mit diesem Programm erhalten haben. Falls nicht, schreiben Sie
+ an die Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
+ MA 02139, USA.
+@end smallexample
+
+
+Wenn Ihr Programm interaktiv ist, sorgen Sie dafür, dass es nach dem
+Start einen kurzen Vermerk ausgibt:
+
+@smallexample
+Gnomovision version 69, Copyright (C) 19@var{yy} @var{name of author}
+Gnomovision comes mit ABSOLUTELY NO WARRANTY; für details type `show w'.
+Das ist free Software und you are welcome to redistribute it
+under certain conditions; type `show c' für details.
+@end smallexample
+
+@smallexample auf deutsch
+ Gnomovision Version 69, Copyright (C) 19[jj] [Name des Autors]
+ Für Gnomovision besteht KEINERLEI GARANTIE; geben Sie `show w'
+ für Details ein. Gnomovision ist freie Software, die Sie unter
+ bestimmten Bedingungen weitergeben dürfen; geben Sie `show c'
+ für Details ein.
+@end smallexample
+
+Die hypothetischen Kommandos `show w' und `show c' sollten die
+entsprechenden Teile der GNU-GPL anzeigen. Natürlich können die von
+Ihnen verwendeten Kommandos anders heißen als `show w' und `show c';
+es könnten auch Mausklicks oder Menüpunkte sein - was immer am besten
+in Ihr Programm passt.
+
+Soweit vorhanden, sollten Sie auch Ihren Arbeitgeber (wenn Sie als
+Programmierer arbeiten) oder Ihre Schule einen Copyright-Verzicht
+für das Programm unterschreiben lassen. Hier ein Beispiel;
+ändern Sie bitte die Namen:
+
+@example
+Yoyodyne, Inc., herefrom disclaims all copyright interest in the program
+`Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+@var{signature of Ty Coon}, 1 April 1989
+Ty Coon, President of Vice
+@end example
+
+@example auf deutsch
+Die Yoyodyne GmbH erhebt keinerlei urheberrechtlichen Anspruch auf das
+Programm "Gnomovision" (einem Schrittmacher für Compiler),
+geschrieben von James Hacker.
+
+@var{Unterschrift von Ty Coon}, 1 April 1989
+Ty Coon, Vizepräsident
+@end example
+
+Diese General Public License gestattet nicht die Einbindung des Programms
+in proprietäre Programme. Ist Ihr Programm eine Funktionsbibliothek, so
+kann es sinnvoller sein, das Linken proprietärer Programme mit dieser
+Bibliothek zu gestatten. Wenn Sie dies tun wollen, sollten Sie die
+GNU Library General Public License anstelle dieser Lizenz verwenden.
+
+@display
+@c German FIX added @@ in e-mail addresses
+Erstellt im Auftrag der S.u.S.E. GmbH [suse@@suse.de]
+von Katja Lachmann Übersetzungen [na194@@fim.uni-erlangen.de],
+überarbeitet von Peter Gerwinski [peter.gerwinski@@uni-essen.de] (31. Oktober 1996)
+
+Diese Übersetzung wird mit der Absicht angeboten, das Verständnis der
+GNU General Public License (GNU-GPL) zu erleichtern. Es handelt sich jedoch
+nicht um eine offizielle oder im rechtlichen Sinne anerkannte Übersetzung.
+
+Die Free Software Foundation (FSF) ist nicht der Herausgeber dieser Übersetzung,
+und sie hat diese Übersetzung auch nicht als rechtskräftigen Ersatz für die
+Original-GNU-GPL anerkannt. Da die Übersetzung nicht sorgfältig von Anwälten
+überprüft wurde, können die Übersetzer nicht garantieren, dass die Übersetzung
+die rechtlichen Aussagen der GNU-GPL exakt wiedergibt. Wenn Sie sichergehen
+wollen, dass von Ihnen geplante Aktivitäten im Sinne der GNU-GPL gestattet sind,
+halten Sie sich bitte an die englischsprachige Originalversion.
+
+Die Free Software Foundation möchte Sie darum bitten, diese Übersetzung
+nicht als offizielle Lizenzbedingungen für von Ihnen geschriebene Programme
+zu verwenden. Bitte benutzen Sie hierfür stattdessen die von der
+Free Software Foundation herausgegebene englischsprachige Originalversion.
+@end display
+
+@page
+
+
+
+
+@node LGPL license, Function Index, GPL license, Top
+@c German node LGPL-Lizenz
+@appendix GNU LESSER GENERAL PUBLIC LICENSE
+
+@cindex LGPL, Lesser General Public License
+@cindex LGPL, GNU Library General Public License
+
+@center Version 2.1, Februar 1999
+
+@display
+Copyright @copyright{} 1991, 1999 Free Software Foundation, Inc.
+59 Temple Place -- Suite 330, Boston, MA 02111-1307, USA
+
+Es ist jedermann gestattet, diese Lizenzurkunde zu vervielfältigen
+und unveränderte Kopien zu verbreiten. Änderungen sind jedoch nicht erlaubt.
+
+[Dies ist die erste freigegebene Version der Lesser GPL.
+Sie ist als Nachfolgerin der GNU Library Public License zu betrachten und
+erhielt daher die Versionsnummer 2.1.]
+@end display
+
+Diese Übersetzung ist kein rechtskräftiger Ersatz für die
+englischsprachige Originalversion!
+
+@appendixsec Vorwort
+
+Die meisten Softwarelizenzen sind daraufhin entworfen worden, Ihnen die
+Freiheit zu nehmen, die Software weiterzugeben und zu verändern.
+Im Gegensatz dazu sollen Ihnen die GNU General Public Licenses,
+die Allgemeinen Öffentlichen GNU-Lizenzen, ebendiese Freiheit des
+Weitergebens und Veränderns garantieren und somit sicherstellen, dass diese
+Software für alle Benutzer frei ist.
+
+Diese Lizenz, die Kleine Allgemeine Öffentliche Lizenz
+(Lesser General Public License), gilt für einige besonders bezeichnete
+Software-Pakete - typischerweise Programmbibliotheken - von der
+Free Software Foundation und anderen Autoren, die beschließen,
+diese Lizenz zu verwenden. Auch Sie können sie verwenden; wir empfehlen
+aber, vorher gründlich darüber nachzudenken, ob diese Lizenz (LGPL)
+oder aber die gewöhnliche Allgemeine Öffentliche Lizenz (GPL) die
+bessere Strategie zur Anwendung im jeweiligen speziellen Fall ist.
+Dabei bieten Ihnen die untenstehenden Erläuterungen eine Grundlage
+für Ihre Entscheidung.
+
+Die Bezeichnung ,,freie`` Software bezieht sich auf Freiheit der Nutzung,
+nicht auf den Preis. Unsere Allgemeinen Öffentlichen Lizenzen sollen
+sicherstellen, dass Sie die Freiheit haben, Kopien freier Software zu
+verbreiten (und etwas für diesen Service zu berechnen, wenn Sie möchten),
+dass Sie die Software im Quelltext erhalten oder den Quelltext auf Wunsch
+bekommen können, dass Sie die Software ändern oder Teile davon in neuen
+freien Programmen verwenden dürfen, und dass Sie darüber informiert sind,
+dass Sie dies alles tun dürfen.
+
+Um Ihre Rechte zu schützen, müssen wir Einschränkungen machen, die es jedem,
+der die Software weitergibt, verbieten, Ihnen diese Rechte zu verweigern
+oder Sie zum Verzicht auf diese Rechte aufzufordern. Aus diesen
+Einschränkungen ergeben sich bestimmte Verantwortlichkeiten für Sie, wenn Sie
+Kopien der Bibliothek verbreiten oder sie verändern.
+
+Beispielsweise müssen Sie den Empfängern alle Rechte gewähren, die wir Ihnen
+eingeräumt haben, wenn Sie - kostenlos oder gegen Bezahlung - Kopien der
+Bibliothek verbreiten. Sie müssen sicherstellen, dass auch die Empfänger
+den Quelltext erhalten bzw. erhalten können. Wenn Sie einen anderen Code
+mit der Bibliothek linken, müssen Sie den Empfängern die vollständigen
+Objekt-Dateien zukommen lassen, so dass sie selbst diesen Code mit der
+Bibliothek neu linken können, auch nachdem sie Veränderungen an der
+Bibliothek vorgenommen und sie neu compiliert haben. Und Sie müssen ihnen
+diese Bedingungen zeigen, damit sie Ihre Rechte kennen.
+
+Wir schützen Ihre Rechte in zwei Schritten: (1) Wir stellen die Bibliothek
+unter ein Urheberrecht (Copyright), und (2) wir bieten Ihnen diese Lizenz
+an, die Ihnen das Recht gibt, die Bibliothek zu vervielfältigen, zu
+verbreiten und/oder zu verändern.
+
+Um jeden, der die Software weitergibt, zu schützen, wollen wir darüber
+hinaus vollkommen klarstellen, dass für diese freie Bibliothek keinerlei
+Garantie besteht. Auch sollten, falls die Software von jemand anderem
+modifiziert und weitergegeben wird, die Empfänger wissen, dass sie nicht
+das Original erhalten haben, damit irgendwelche von anderen verursachte
+Probleme nicht den Ruf des ursprünglichen Autors schädigen.
+
+Schließlich und endlich stellen Software-Patente für die Existenz jedes
+freien Programms eine ständige Bedrohung dar. Wir möchten sicherstellen,
+dass keine Firma den Benutzern eines freien Programms Einschränkungen
+auferlegen kann, indem sie von einem Patentinhaber eine die freie Nutzung
+einschränkende Lizenz erwirbt. Deshalb bestehen wir darauf, dass jegliche
+für eine Version der Bibliothek erworbene Patentlizenz mit der in dieser
+Lizenz (also der LGPL) im einzelnen angegebenen Nutzungsfreiheit voll
+vereinbar sein muß.
+
+Die meiste GNU-Software einschließlich einiger Bibliotheken fällt unter
+die gewöhnliche Allgemeine Öffentliche GNU-Lizenz (GNU-GPL).
+Die vorliegende Lizenz, also die GNU-LGPL, gilt für gewisse näher
+bezeichnete Bibliotheken. Sie unterscheidet sich wesentlich von der
+gewöhnlichen Allgemeinen Öffentlichen Lizenz (GNU-GPL). Wir benutzen
+diese Lizenz für gewisse Bibliotheken, um das Linken (d.h. die Verknüpfung
+von Bibliotheken und anderen Programmteilen zu einem lauffähigen
+Programm - Anmerkung der Übersetzer) von Programmen, die nicht frei
+sind, mit diesen Bibliotheken zu gestatten.
+
+Wenn ein Programm mit einer Bibliothek gelinkt wurde, sei es nun statisch
+oder dynamisch, so ist die Kombination der beiden, rechtlich gesehen,
+ein ,,kombiniertes Datenwerk``, also eine abgeleitete Version der
+Orginal-Bibliothek. Die gewöhnliche GPL erlaubt ein solches Linken nur
+dann, wenn die ganze Kombination die Kriterien für freie Software erfüllt.
+Die LGPL erlaubt dagegen weniger strenge Kriterien für das Linken von
+irgendeiner anderen Software mit der Bibliothek.
+
+Wir nennen diese Lizenz die "Kleine" Allgemeine Öffentliche Lizenz
+@dfn{Lesser} General Public License weil sie weniger @emph{Less} dazu beiträgt,
+die Freiheit des Benutzers zu schützen, als die gewöhnliche Allgemeine
+Öffentliche Lizenz (GPL). Sie verschafft auch anderen Entwicklern freier
+Software ein "Weniger" an Vorteil gegenüber konkurrierenden nichtfreien Programmen.
+Diese Nachteile sind ein Grund dafür, dass wir die gewöhnliche GPL für viele
+Bibliotheken benutzen. Die "kleine" Lizenz (LGPL) bietet aber unter bestimmten
+besonderen Umständen doch Vorteile.
+
+So kann, wenn auch nur bei seltenen Gelegenheiten, eine besondere Notwendigkeit
+bestehen, einen Anreiz zur möglichst weitgehenden Benutzung einer bestimmten
+Bibliothek zu schaffen, so dass diese dann ein De-facto-Standard wird. Um dies
+zu erreichen, müssen nichtfreie Programme die Bibliothek benutzen dürfen.
+Ein häufigerer Fall ist der, dass eine freie Bibliothek dasselbe leistet wie
+weithin benutzte nichtfreie Bibliotheken. In diesem Falle bringt es wenig
+Nutzen, die freie Bibliothek allein auf freie Software zu beschränken, und
+dann benutzen wir eben die LGPL.
+
+In anderen Fällen ermöglicht die Erlaubnis zur Benutzung einer speziellen
+Bibliothek in nichtfreien Programmen viel mehr Leuten, eine umfangreiche
+Sammlung freier Software zu nutzen. So ermöglicht z.B. die Erlaubnis zur
+Benutzung der GNU-C-Bibliothek in nichtfreien Programmen einer viel größeren
+Zahl von Leuten, das ganze GNU-Betriebssystem ebenso wie seine Variante, das
+Betriebssystem GNU/Linux, zu benutzen.
+
+Obwohl die LGPL die Freiheit des Benutzers weniger schützt, stellt sie doch
+sicher, dass der Benutzer eines Programms, das mit der Bibliothek gelinkt wurde,
+die Freiheit und die erforderlichen Mittel hat, das Programm unter Benutzung
+einer abgeänderten Version der Bibliothek zu betreiben.
+
+Die genauen Bedingungen für das Kopieren, Weitergeben und Abändern finden Sie
+im nachstehenden Kapitel. Achten Sie genau auf den Unterschied zwischen
+"work Basiert auf the library", d.h. "Datenwerk, das auf der Bibliothek basiert"
+und "work that uses the library" d.h. "Datenwerk, das die Bibliothek benutzt".
+Ersteres enthält Code, der von der Bibliothek abgeleitet ist, während letzteres
+lediglich mit der Bibliothek kombiniert werden muß, um betriebsfähig zu sein.
+
+@iftex
+@appendixsec TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+@end iftex
+@ifinfo
+@center GNU LESSER GENERAL PUBLIC LICENSE
+@center Bedingungen für die Vervielfältigung, Verbreitung und Bearbeitung
+
+@end ifinfo
+
+@enumerate 0
+@item
+Diese Lizenz gilt für jedes Programm und jedes andere Datenwerk, in dem
+ein entsprechender Vermerk des Copyright-Inhabers oder eines anderen dazu
+Befugten darauf hinweist, dass das Datenwerk unter den Bestimmungen dieser
+Lesser General Public License (im weiteren auch als "diese Lizenz"
+bezeichnet) verbreitet werden darf. Jeder Lizenznehmer wird hierin
+einfach als "Sie" angesprochen.
+
+Eine "Bibliothek" bedeutet eine Zusammenstellung von Software-Funktionen
+und/oder Daten, die so vorbereitet ist, dass sie sich bequem mit
+Anwendungsprogrammen (welche einige dieser Funktionen und Daten benutzen) zum Bilden
+von ausführbaren Programmen linken (d.h. verbinden, kombinieren) läßt.
+
+Der Begriff "Bibliothek" bezieht sich im weiteren immer nur auf solche
+Software-Bibliotheken und solche Datenwerke, die unter diesen Bedingungen
+der Lesser-GPL-Lizenz verbreitet worden sind. Ein "auf der Bibliothek
+basierendes Datenwerk" bezeichnet die betreffende Bibliothek selbst
+sowie jegliche davon abgeleitete Bearbeitung im urheberrechtlichen Sinne,
+also ein Datenwerk, welches die Bibliothek oder einen Teil davon, sei
+es unverändert oder verändert und/oder direkt in eine andere Sprache
+übersetzt, enthält. (Im folgenden wird die Übersetzung ohne
+Einschränkung als "Bearbeitung" eingestuft.)
+
+Unter dem "Quelltext" eines Datenwerks ist seine für das Vornehmen
+von Veränderungen bevorzugte Form zu verstehen. Für eine Bibliothek
+bedeutet "vollständiger Quelltext" den gesamten Quelltext für alle in
+ihr enthaltenen Bestandteile, für jegliche zu ihr gehörenden Dateien
+zur Definition von Schnittstellen und schließlich auch für die Skripte,
+die zur Steuerung der Compilation und Installation der Bibliothek
+benutzt werden.
+
+Andere Handlungen als Vervielfältigung, Verbreitung und Bearbeitung
+werden von dieser Lizenz nicht berührt; sie fallen nicht in Ihren
+Anwendungsbereich. Das Ausführen eines Programms unter Benutzung der
+Bibliothek wird nicht eingeschränkt, und die Ausgaben des Programms
+unterliegen dieser Lizenz nur dann, wenn der Inhalt ein auf der
+Bibliothek basierendes Datenwerk darstellt (unabhängig davon, dass die
+Bibliothek in einem Werkzeug zum Schreiben dieses Programms benutzt
+wurde). Ob dies zutrifft, hängt davon ab, was die Bibliothek bewirkt
+und was das Programm, das die Bibliothek nutzt, bewirkt.
+
+@item
+Sie dürfen auf beliebigen Medien unveränderte Kopien des vollständigen
+Quelltextes des Programms so, wie sie ihn erhalten haben, anfertigen
+und verbreiten. Voraussetzung hierfür ist, dass Sie mit jeder Kopie
+deutlich erkennbar und in angemessener Form einen entsprechenden
+Copyright-Vermerk sowie einen Haftungsausschluss veröffentlichen, alle
+Vermerke, die sich auf diese Lizenz und das Fehlen einer Garantie
+beziehen, unverändert lassen und zusammen mit der Bibliothek jeweils
+eine Kopie dieser Lizenz weitergeben.
+
+Sie dürfen für den eigentlichen Kopier- und Versandvorgang eine Gebühr
+verlangen. Wenn Sie es wünschen, dürfen Sie auch gegen Entgelt eine
+Garantie anbieten.
+
+@item
+Sie dürfen Ihre Kopie(n) der Bibliothek oder irgendeines Teils davon
+verändern, wodurch ein auf der Bibliothek basierendes Datenwerk
+entsteht, und Sie dürfen derartige Bearbeitungen unter den Bestimmungen
+von Paragraph 1 vervielfältigen und verbreiten, vorausgesetzt, dass
+zusätzlich alle im folgenden genannten Bedingungen erfüllt werden:
+
+@enumerate a
+@item
+Das Bearbeitungsergebnis muss selbst wieder eine Software-Bibliothek sein.
+
+@item
+Sie müssen die veränderten Dateien mit einem auffälligen Vermerk
+versehen, der auf die von Ihnen vorgenommene Modifizierung der
+Dateien hinweist und das Datum jeder Änderung angibt.
+
+@item
+Sie müssen dafür sorgen, dass das Datenwerk als Ganzes Dritten unter
+den Bedingungen dieser Lizenz ohne Lizenzgebühren zur Verfügung
+gestellt wird.
+
+@item
+Wenn sich eine Funktionseinheit der bearbeiteten Bibliothek auf eine
+Funktion oder Datentabelle stützt, die von einem die Funktionseinheit
+nutzenden Anwendungsprogramm bereitgestellt werden muß, ohne dass sie
+als Argument übergeben werden muß, wenn die Funktionseinheit angesprochen
+wird, dann müssen Sie sich nach bestem Wissen und Gewissen bemühen,
+sicherzustellen, dass die betreffende Funktionseinheit auch dann noch
+funktioniert, wenn die Anwendung eine solche Funktion oder Datentabelle
+nicht bietet, und dass sie den sinnvoll bleibenden Teil Ihres
+Bestimmungszwecks noch ausführt.
+
+(So hat z.B. eine Funktion zum Berechnen von Quadratwurzeln einen von
+der Anwendung unabhängigen genau definierten Zweck. Deshalb verlangt
+§2 Absatz d, dass jede von der Anwendung bereitgestellte Funktion oder
+von dieser Funktion benutzte Tabelle optional sein muß: Auch wenn die
+Anwendung sie nicht bereitstellt, muss die Quadratwurzelfunktion trotzdem
+noch Quadratwurzeln berechnen).
+@end enumerate
+
+Diese Anforderungen gelten für das bearbeitete Datenwerk als Ganzes.
+Wenn identifizierbare Teile davon nicht von der Bibliothek stammen und
+vernünftigerweise als unabhängige und gesonderte Datenwerke für sich selbst
+zu betrachten sind, dann gelten diese Lizenz und Ihre Bedingungen nicht
+für die betreffenden Teile, wenn Sie diese als gesonderte Datenwerke
+weitergeben. Wenn Sie jedoch dieselben Teile als Teil eines Ganzen
+weitergeben, dass ein auf der Bibliothek basierendes Datenwerk darstellt,
+dann muss die Weitergabe dieses Ganzen nach den Bedingungen dieser Lizenz
+erfolgen, deren Bedingungen für weitere Lizenznehmer somit auf das
+gesamte Ganze ausgedehnt werden - und somit auf jeden einzelnen Teil,
+unabhängig vom jeweiligen Autor.
+
+Somit ist es nicht die Absicht dieses Abschnittes, Rechte für Datenwerke
+in Anspruch zu nehmen oder Ihnen Rechte für Datenwerke streitig zu
+machen, die komplett von Ihnen geschrieben wurden; vielmehr ist es die
+Absicht, die Rechte zur Kontrolle der Verbreitung von Datenwerken, die
+auf der Bibliothek basieren oder unter Ihrer auszugsweisen Verwendung
+zusammengestellt worden sind, auszuüben.
+
+Ferner bringt auch dass einfache Zusammenlegen eines anderen Datenwerkes,
+das nicht auf der Bibliothek basiert, mit der Bibliothek oder mit
+einem auf der Bibliothek basierenden Datenwerk auf ein- und demselben
+Speicher- oder Vertriebsmedium dieses andere Datenwerk nicht in den
+Anwendungsbereich dieser Lizenz.
+
+@item
+Sie können sich für die Anwendung der Bedingungen der gewöhnlichen
+Allgemeinen Öffentlichen GNU-Lizenz (GNU-GPL) statt dieser Lizenz
+auf eine gegebene Kopie der Bibliothek entscheiden. Um dies zu tun,
+müssen Sie alle Eintragungen, die sich auf diese Lizenz beziehen,
+ändern, so dass sie nun für die gewöhnliche GNU-GPL, Version 2,
+statt für diese Lizenz (LGPL) gelten. (Wenn eine neuere Version
+als Version 2 der gewöhnlichen GNU-GPL erschienen ist, können Sie
+diese angeben, wenn Sie das wünschen.) Nehmen Sie keine anderen
+Veränderungen in diesen Eintragungen vor.
+
+Wenn diese Veränderung in einer gegebenen Kopie einmal vorgenommen
+ist, dann ist sie für diese Kopie nicht mehr zurücknehmbar, und
+somit gilt dann die gewöhnliche GNU-GPL für alle nachfolgenden Kopien
+und abgeleiteten Datenwerke, die von dieser Kopie gemacht worden sind.
+
+Diese Option ist nützlich, wenn Sie einen Teil des Codes der Bibliothek
+in ein Programm kopieren wollen, das keine Bibliothek ist.
+
+@item
+Sie können die Bibliothek (oder einen Teil oder eine Ableitung von ihr,
+gemäß Paragraph 2) in Objektcode-Form oder in ausführbarer Form unter
+den Bedingungen der obigen Paragraphen 1 und 2 kopieren und weitergeben,
+sofern Sie den vollständigen entsprechenden maschinenlesbaren Quelltext
+beifügen, der unter den Bedingungen der obigen Paragraphen 1 und 2
+auf einem Medium weitergegeben werden muß, das üblicherweise zum
+Austausch von Software benutzt wird.
+
+Wenn die Weitergabe von Objektcode durch das Angebot eines Zugangs zum
+Kopienabruf von einem angegebenen Ort erfolgt, dann erfüllt das Angebot
+eines gleichwertigen Zugangs zum Kopieren des Quelltextes von demselben
+Ort die Anforderung, auch den Quelltext weiterzugeben, obwohl Dritte
+nicht verplichtet sind, den Quelltext zusammen mit dem Objektcode zu
+kopieren.
+
+@item
+Ein Programm, das nichts von irgendeinem Teil der Bibliothek
+Abgeleitetes enthält, aber darauf ausgelegt ist, mit der Bibliothek
+zusammenzuarbeiten, indem es mit ihr compiliert oder gelinkt wird,
+nennt man ein "Datenwerk, das die Bibliothek nutzt". Solch ein
+Datenwerk, für sich allein genommen, ist kein von der Bibliothek abgelei
+tetes Datenwerk und fällt daher nicht unter diese Lizenz.
+
+Wird jedoch ein "Datenwerk, das die Bibliothek nutzt", mit der
+Bibliothek gelinkt, so entsteht ein ausführbares Programm, dass ein
+von der Bibliothek abgeleitetes Datenwerk (weil es Teile der Bibliothek
+enthält) und kein "Datenwerk, das die Bibliothek nutzt" ist.
+Das ausführbare Programm fällt daher unter diese Lizenz.
+Paragraph 6 gibt die Bedingungen für die Weitergabe solcher
+ausführbarer Programme an.
+
+Wenn ein "Datenwerk, das die Bibliothek nutzt", Material aus einer
+Header-Datei verwendet, die Teil der Bibliothek ist, dann kann der
+Objektcode für das Datenwerk ein von der Bibliothek abgeleitetes
+Datenwerk sein, selbst wenn der Quelltext dies nicht ist. Ob dies
+jeweils zutrifft, ist besonders dann von Bedeutung, wenn das Datenwerk
+ohne die Bibliothek gelinkt werden kann oder wenn das Datenwerk selbst
+eine Bibliothek ist. Die genaue Grenze, von der an dies zutrifft,
+ist rechtlich nicht genau definiert.
+
+Wenn solch eine Objektdatei nur numerische Parameter, Daten-
+struktur-Layouts und Zugriffsfunktionen sowie kleine Makros und kleine
+Inlinefunktionen (zehn Zeilen lang oder kürzer) benutzt, dann
+unterliegt die Benutzung der Objektdatei keinen Beschränkungen, ohne
+Rücksicht darauf, ob es rechtlich gesehen ein abgeleitetes Datenwerk ist.
+(Ausführbare Programme, welche diesen Objektcode plus Teile der
+Bibliothek enthalten, fallen jedoch weiterhin unter die Bestimmungen
+von Paragraph 6).
+
+Ansonsten können Sie, wenn das Datenwerk ein von der Bibliothek
+abgeleitetes ist, den Objektcode für das Datenwerk unter den Bedingungen
+von Paragraph 6 weitergeben. Alle ausführbaren Programme, welche
+dieses Datenwerk enthalten, fallen ebenfalls unter Paragraph 6,
+gleichgültig, ob sie direkt mit der Bibliothek selbst gelinkt sind
+oder nicht.
+
+@item
+Als Ausnahme von den Bestimmungen der vorstehenden fünf Paragraphen
+dürfen Sie auch ein "Datenwerk, das die Bibliothek nutzt", mit der
+Bibliothek kombinieren oder linken, um ein Datenwerk zu erzeugen,
+das Teile der Bibliothek enthält, und dieses unter Bedingungen Ihrer
+eigenen Wahl weitergeben, sofern diese Bedingungen Bearbeitungen
+für den eigenen Gebrauch des Empfängers und ein Rückbilden
+("reverse engineering") zum Beheben von Mängeln solcher Bearbeitungen
+gestatten.
+
+Sie müssen bei jeder Kopie des Datenwerks deutlich erkennbar angeben,
+dass die Bibliothek darin genutzt wird und dass die Bibliothek und Ihre
+Benutzung durch die Lizenz abgedeckt sind. Sie müssen eine Kopie
+dieser Lizenz mitgeben. Wenn das Datenwerk bei seiner Ausführung
+Copyright-Vermerke anzeigt, müssen Sie den Copyright-Vermerk für
+die Bibliothek mit anzeigen lassen und dem Benutzer einen Hinweis
+geben, der ihn zu einer Kopie dieser Lizenz führt. Ferner müssen Sie
+eines der nachfolgend genannten fünf Dinge tun:
+
+@enumerate a
+@item
+Liefern Sie das Datenwerk zusammen mit dem vollständigen zugehörigen
+maschinenlesbaren Quelltext der Bibliothek aus, und zwar
+einschließlich jeglicher in dem Datenwerk angewandter Änderungen (wobei
+dessen Weitergabe gemäß den Bedingungen der Paragraphen 1 und 2
+erfolgen muß); und wenn das Datenwerk ein ausführbares, mit der
+Bibliothek gelinktes Programm ist, dann liefern Sie es zusammen
+mit dem vollständigen maschinenlesbaren "Datenwerk, das die
+Bibliothek nutzt, in Form von Objektcode und/oder Quelltext, so dass
+der Benutzer die Bibliothek verändern und dann erneut linken kann,
+um ein verändertes ausführbares Programm zu erzeugen, das die
+veränderte Bibliothek enthält. (Es versteht sich, dass der Benutzer,
+der die Inhalte von Definitionsdateien in der veränderten Bibliothek
+verändert, nicht notwendigerweise in der Lage sein wird, die Anwendung
+neu zu compilieren, um die veränderten Definitionen zu benutzen.)
+
+@item
+Benutzen Sie einen geeigneten ,,shared-library-Mechanismus`` zum
+Linken mit der Bibliothek. Geeignet ist ein solcher Mechanismus,
+der erstens während der Laufzeit eine im Computersystem des Benutzers
+bereits vorhandene Kopie der Bibliothek benutzt, anstatt
+Bibliotheksfunktionen in das ausführbare Programm zu kopieren, und der zweitens
+auch mit einer veränderten Version der Bibliothek, wenn der Benutzer
+eine solche installiert, richtig funktioniert, solange die veränderte
+Version schnittstellenkompatibel mit der Version ist, mit der das
+Datenwerk erstellt wurde.
+
+@item
+Liefern Sie das Datenwerk zusammen mit einem mindestens drei Jahre
+lang gültigen schriftlichen Angebot, demselben Benutzer die oben in
+Paragraph 6, Absatz (a) genannten Materialien zu Kosten, welche die
+reinen Weitergabekosten nicht übersteigen, zur Verfügung zu stellen.
+
+@item
+Wenn die Weitergabe des Datenwerks dadurch erfolgt, dass die
+Möglichkeit des Abrufens einer Kopie von einem bestimmten Ort
+angeboten wird, bieten Sie gleichwertigen Zugang zum Kopieren der
+oben angegebenen Materialien von dem gleichen Ort an.
+
+@item
+Sie vergewissern sich, dass der Benutzer bereits eine Kopie dieser
+Materialien erhalten hat oder dass Sie diesem Benutzer bereits eine
+Kopie geschickt haben.
+@end enumerate
+
+Für ein ausführbares Programm muss die verlangte Form des
+"Datenwerks, das die Bibliothek nutzt" alle Daten und Hilfsprogramme
+mit einschließen, die man braucht, um daraus das ausführbare Programm
+zu reproduzieren. Doch gilt eine spezielle Ausnahme: Die
+weiterzugebenden Materialien brauchen nicht alles das zu enthalten, was
+normalerweise (in Quelltext-Form oder in binärer Form) mit den
+Hauptbestandteilen (Compiler, Kern usw.) des Betriebssystems,
+auf denen das ausführbare Programm läuft, weitergegeben wird, es
+sei denn, das ausführbare Programm gehört selbst zu diesem
+Hauptbestandteil.
+
+Es kann vorkommen, dass diese Anforderung im Widerspruch zu
+Lizenzbeschränkungen anderer, proprietärer Bibliotheken steht, die
+normalerweise nicht zum Betriebssystem gehören. Ein solcher
+Widerspruch bedeutet, dass Sie nicht gleichzeitig jene proprietären
+Bibliotheken und die vorliegende Bibliothek zusammen in einem
+ausführbaren Programm, das Sie weitergeben, verwenden dürfen.
+
+@item
+Sie dürfen Bibliotheks-Funktionseinheiten, die ein auf der Bibliothek
+basierendes Datenwerk darstellen, zusammen mit anderen, nicht unter
+diese Lizenz fallenden Funktionseinheiten in eine einzelne Bibliothek
+einbauen und eine solche kombinierte Bibliothek weitergeben,
+vorausgesetzt, dass die gesonderte Weitergabe des auf der Bibliothek
+basierenden Datenwerks einerseits und der anderen Funktionseinheiten
+andererseits ansonsten gestattet ist, und vorausgesetzt, dass Sie
+folgende zwei Dinge tun:
+
+@enumerate a
+@item
+Geben Sie zusammen mit der kombinierten Bibliothek auch eine Kopie
+desselben auf der Bibliothek basierenden Datenwerks mit, die nicht
+mit irgendwelchen anderen Funktionseinheiten kombiniert ist.
+Dieses Datenwerk muss unter den Bedingungen der obigen Paragraphen
+weitergegeben werden.
+
+@item
+Weisen Sie bei der kombinierten Bibliothek an prominenter Stelle
+auf die Tatsache hin, dass ein Teil davon ein auf der Bibliothek
+basierendes Datenwerk ist, und erklären Sie, wo man die mitgegebene
+unkombinierte Form desselben Datenwerks finden kann.
+@end enumerate
+
+@item
+Sie dürfen die Bibliothek nicht vervielfältigen, verändern, weiter
+lizenzieren oder verbreiten oder mit ihr linken, sofern es nicht durch
+diese Lizenz ausdrücklich gestattet ist. Jeder anderweitige Versuch
+der Vervielfältigung, Modifizierung, Weiterlizenzierung und
+Verbreitung sowie des Linkens mit der Bibliothek ist unzulässig und
+beendet automatisch Ihre Rechte unter dieser Lizenz. Doch werden
+die Lizenzen Dritter, die von Ihnen Kopien oder Rechte unter dieser
+Lizenz erhalten haben, nicht beendet, solange diese Dritten die Lizenz
+voll anerkennen und befolgen.
+
+@item
+Sie sind nicht verpflichtet, diese Lizenz anzunehmen, da Sie diese
+nicht unterzeichnet haben. Doch gibt Ihnen sonst nichts die Erlaubnis,
+die Bibliothek oder von ihr abgeleitete Datenwerke zu verändern oder
+zu verbreiten. Diese Handlungen sind gesetzlich verboten, wenn Sie
+diese Lizenz nicht annehmen. Indem Sie die Bibliothek (oder ein darauf
+basierendes Datenwerk) verändern oder verbreiten, erklären Sie Ihr
+Einverständnis mit dieser Lizenz, die Ihnen das erlaubt, mit allen
+Ihren Bedingungen bezüglich der Vervielfältigung, Verbreitung und
+Veränderung der Bibliothek oder eines darauf basierenden Datenwerks.
+
+@item
+Jedesmal, wenn Sie die Bibliothek (oder irgendein auf der Bibliothek
+basierendes Datenwerk) weitergeben, erhält der Empfänger automatisch
+vom ursprünglichen Lizenzgeber die Lizenz, die Bibliothek entsprechend
+den hier festgelegten Bestimmungen zu vervielfältigen, zu verbreiten
+und zu verändern und mit ihr zu linken. Sie dürfen keine weiteren
+Einschränkungen der Ausübung der hierin zugestandenen Rechte des
+Empfängers vornehmen. Sie sind nicht dafür verantwortlich, die
+Einhaltung dieser Lizenz durch Dritte durchzusetzen.
+
+@item
+Sollten Ihnen infolge eines Gerichtsurteils, des Vorwurfs einer
+Patentverletzung oder aus einem anderen Grunde (nicht auf
+Patentfragen begrenzt) Bedingungen (durch Gerichtsbeschluss,
+Vergleich oder anderweitig) auferlegt werden, die den Bedingungen
+dieser Lizenz widersprechen, so befreien diese Umstände Sie nicht
+von den Bestimmungen dieser Lizenz. Wenn es Ihnen nicht möglich ist,
+die Bibliothek unter gleichzeitiger Beachtung der Bedingungen in
+dieser Lizenz und Ihrer anderweitigen Verpflichtungen zu verbreiten,
+dann dürfen Sie als Folge davon die Bibliothek überhaupt nicht
+verbreiten. Wenn zum Beispiel ein Patent nicht die gebührenfreie
+Weiterverbreitung der Bibliothek durch diejenigen erlaubt, welche
+die Bibliothek direkt oder indirekt von Ihnen erhalten haben, dann
+besteht der einzige Weg, sowohl dem Patentrecht als auch dieser
+Lizenz zu genügen, darin, ganz auf die Verbreitung der Bibliothek
+zu verzichten.
+
+Sollte sich ein Teil dieses Paragraphen als ungültig oder unter
+bestimmten Umständen nicht durchsetzbar erweisen, so soll dieser
+Paragraph seinem Sinne nach angewandt werden; im übrigen soll
+dieser Paragraph als Ganzes gelten.
+
+Zweck dieses Paragraphen ist nicht, Sie dazu zu bringen, irgendwelche
+Patente oder andere Eigentumsansprüche zu verletzen oder die Gültigkeit
+solcher Ansprüche zu bestreiten; dieser Paragraph hat vielmehr einzig
+den Zweck, die Integrität des Verbreitungssystems der freien Software
+zu schützen, das durch die Praxis öffentlicher Lizenzen verwirklicht
+wird. Viele Leute haben großzügige Beiträge zu dem weitreichenden
+Angebot der durch dieses System verbreiteten Software im Vertrauen
+auf die konsistente Anwendung dieses Systems geleistet; es obliegt
+dem Autor bzw. Geber, zu entscheiden, ob er die Software mittels
+irgendeines anderen Systems verbreiten will; ein Lizenznehmer jedoch
+darf darüber nicht entscheiden.
+
+Dieser Paragraph ist dazu gedacht, deutlich klarzustellen, was als
+Konsequenz aus den übrigen Bestimmungen dieser Lizenz zu betrachten
+ist.
+
+@item
+Wenn die Verbreitung und/oder die Benutzung der Bibliothek in
+bestimmten Staaten entweder durch Patente oder durch urheberrechtlich
+geschützte Schnittstellen eingeschränkt ist, kann der
+Urheberrechtsinhaber, der die Bibliothek unter diese Lizenz gestellt
+hat, eine explizite geographische Beschränkung der Verbreitung angeben,
+in der diese Staaten ausgeschlossen werden, so dass die Verbreitung nur
+innerhalb und zwischen den Staaten erlaubt ist, die nicht demgemäß
+ausgeschlossen sind. In einem solchen Fall beinhaltet diese Lizenz
+die Beschränkung, als wäre sie in diesem Text niedergeschrieben.
+
+@item
+Die Free Software Foundation kann von Zeit zu Zeit überarbeitete
+und/oder neue Versionen der Lesser General Public License
+veröffentlichen. Solche neuen Versionen werden vom Grundprinzip her
+der gegenwärtigen entsprechen, können aber im Detail abweichen, um
+neuen Problemen und Anforderungen gerecht zu werden.
+
+Jede Version dieser Lizenz hat eine eindeutige Versionsnummer.
+Wenn in einem Programm angegeben wird, dass es dieser Lizenz in einer
+bestimmten Versionsnummer oder "jeder späteren Version" ("any later
+version") unterliegt, so haben Sie die Wahl, entweder den Bestimmungen
+der genannten Version zu folgen oder denen jeder beliebigen späteren
+Version, die von der Free Software Foundation veröffentlicht wurde.
+Wenn die Bibliothek keine Lizenz-Versionsnummer angibt, können Sie
+eine beliebige Version wählen, die jemals von der Free Software
+Foundation veröffentlicht wurde.
+
+@item
+Wenn Sie den Wunsch haben, Teile der Bibliothek in anderen
+freien Programmen zu verwenden, deren Bedingungen für die Verbreitung
+anders sind, schreiben Sie an den Autor der Bibliothek, um ihn um die
+Erlaubnis zu bitten. Für Software, die unter dem Copyright der Free
+Software Foundation steht, schreiben Sie an die Free Software
+Foundation; wir machen zu diesem Zweck gelegentlich Ausnahmen.
+Unsere Entscheidung wird von den beiden Zielen geleitet werden,
+zum einen den freien Status aller von unserer freien Software
+abgeleiteten Datenwerke zu erhalten und zum anderen das
+gemeinschaftliche Nutzen und Wiederverwenden von Software im
+allgemeinen zu fördern.
+
+@iftex
+@heading Keine Gewährleistung
+@end iftex
+@ifinfo
+@center Keine Gewährleistung
+@end ifinfo
+
+@item
+Da die Bibliothek ohne jegliche Gebühren lizenziert wird, besteht
+keinerlei Gewährleistung für die Bibliothek, soweit dies gesetzlich
+zulässig ist. Sofern nicht anderweitig schriftlich bestätigt, stellen
+die Copyright-Inhaber und/oder Dritte die Bibliothek "so, wie sie ist"
+zur Verfügung, ohne Gewährleistung irgendeiner Art, weder ausdrücklich
+noch implizit. Dieser Garantieausschluss gilt auch - ohne darauf
+beschränkt zu sein - für Marktreife oder Verwendbarkeit für einen
+bestimmten Zweck. Das volle Risiko bezüglich Qualität und Leistungs-
+fähigkeit der Bibliothek liegt bei Ihnen. Sollte sich die Bibliothek
+als fehlerhaft herausstellen, liegen die Kosten für notwendigen
+Service, Reparatur oder Korrektur sämtlich bei Ihnen.
+
+@item
+In keinem Fall, außer wenn dies durch geltendes Recht gefordert
+wird oder schriftlich zugesichert wurde, ist irgendein
+Copyright-Inhaber oder irgendein Dritter, der die Bibliothek wie oben
+erlaubt modifiziert oder verbreitet hat, Ihnen gegenüber für
+irgendwelche Schäden haftbar. Dies gilt auch für jegliche allgemeine
+oder spezielle Schäden, für Schäden durch Nebenwirkungen oder
+Folgeschäden, die sich aus der Benutzung oder der Unbenutzbarkeit
+der Bibliothek ergeben (das gilt insbesondere - ohne darauf
+beschränkt zu sein - für Datenverluste, das Hineinbringen von
+Ungenauigkeiten in irgendwelche Daten, für Verluste, die Sie oder
+Dritte erlitten haben oder für ein Unvermögen der Bibliothek,
+mit irgendeiner anderen Software zusammenzuarbeiten), und zwar
+auch dann, wenn ein Copyright-Inhaber oder ein Dritter über die
+Möglichkeit solcher Schäden informiert worden ist.
+
+@end enumerate
+
+@iftex
+@heading Ende der Bedingungen
+@end iftex
+@ifinfo
+@center Ende der Bedingungen
+@end ifinfo
+
+@appendixsec Anhang: Wie Sie diese Bedingungen auf Ihre eigenen, neuen Bibliotheken anwenden können
+
+Wenn Sie eine neue Bibliothek entwickeln und wünschen, dass sie
+von größtmöglichem Nutzen für die Allgemeinheit ist, dann empfehlen
+wir Ihnen, sie zu einer freien Software zu machen, die jedermann
+weiterverteilen und verändern kann. Dies können sie tun, indem Sie
+eine Weiterverteilung unter den Bedingungen dieser Lizenz, also
+der Lesser GPL erlauben (oder - als Alternative - unter den Bedingungen
+der gewöhnlichen Allgemeinen Öffentlichen GNU-Lizenz, der GPL).
+
+Zur Anwendung dieser Bedingungen fügen Sie zu der Bibliothek die
+unten angegebenen Vermerke hinzu. Es ist am sichersten, sie an
+den Start jeder Quelldatei anzufügen, um so am wirksamsten den
+Garantieausschluß bekannt zu machen; zumindest aber sollte jede
+Datei die Copyright-Zeile und eine Angabe enthalten, wo die
+vollständigen Vermerke zu finden sind.
+
+
+
+@smallexample
+@var{eine Zeile mit dem Namen der Bibliothek und einer kurzen
+Beschreibung Ihres Zwecks}
+Copyright (C) @var{yyyy} @var{Name des Autors}
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public License
+as published by the Free Software Foundation; either version 2.1
+of the License oder (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but ohne ANY WARRANTY; ohne even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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
+
+Auf Deutsch:
+
+Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen
+der GNU Lesser General Public License, wie von der Free Software
+Foundation veröffentlicht, weiterverteilen und/oder modifizieren;
+entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option)
+jeder späteren Version.
+
+Diese Bibliothek wird in der Hoffnung weiterverbreitet, dass sie
+nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne
+die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT
+FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der
+GNU Lesser General Public License.
+
+Sie sollten eine Kopie der GNU Lesser General Public License
+zusammen mit dieser Bibliothek erhalten haben; falls nicht,
+schreiben Sie an die
+Free Software Foundation, Inc.,
+59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+@end smallexample
+
+Fügen Sie auch einen kurzen Hinweis hinzu, wie Sie elektronisch
+und per Brief erreichbar sind.
+
+@smallexample
+Soweit vorhanden, sollten Sie auch Ihren Arbeitgeber
+(wenn Sie als Programmierer arbeiten) oder Ihre Schule einen
+Copyright-Verzicht für die Bibliothek unterschreiben lassen.
+Hier ein Beispiel. Die Namen müssen Sie natürlich ändern.
+
+Yoyodyne, Inc., hereby disclaims all copyright interest
+in the library "Frob" (a library for tweaking knobs)
+written by James Random Hacker.
+
+
+Unterschrift von Ty Coon , 1 April 1990
+Ty Coon, President of Vice
+
+Auf Deutsch:
+
+DIe Yoyodyne GmbH erhebt keinen urheberechtlichen Anspruch
+auf die von James Random Hacker geschriebene Bibliothek "Frob"
+(eine Bibliothek für das Zwicken von Knöpfen).
+
+
+Unterschrift von Ty Coon, 1. April 1990
+Ty Coon, Vizepräsident
+@end smallexample
+
+Das war schon alles!
+
+
+
+@c German FIX this node entry and section header were missing!
+@c I made a guess as to what the German section title should be like ;-)
+@node Function Index, Concept Index, LGPL license, Top
+@c German node Function Index
+@unnumbered SQL Command, Typ und Funktion Index
+
+@printindex fn
+
+@page
+
+
+@node Concept Index, , Function Index, Top
+@c German node Concept Index
+@unnumbered Concept Index
+
+@printindex cp
+
+
+
+
+
+@bye
diff --git a/Docs/manual.ja.texi b/Docs/manual.ja.texi
index d3ee43acd29..dea7046b538 100644
--- a/Docs/manual.ja.texi
+++ b/Docs/manual.ja.texi
@@ -3187,7 +3187,7 @@ encounter per year, but we are as always very flexible towards our customers!
@c @image{Flags/estonia} Estonia [Tradenet] @
@c @uref{http://mysql.tradenet.ee, WWW}
@item
-@c EMAIL: tonu@spamm.ee (Tonu Samuel)
+@c EMAIL: tonu@spam.ee (Tonu Samuel)
@image{Flags/estonia} Estonia [OKinteractive] @
@uref{http://mysql.mirror.ok.ee, WWW}
@item
diff --git a/Docs/manual.texi b/Docs/manual.texi
index 107f26b2fa5..20e0315b3bc 100644
--- a/Docs/manual.texi
+++ b/Docs/manual.texi
@@ -1,15 +1,27 @@
\input texinfo @c -*-texinfo-*-
-@c Copyright 1997-2001 TcX AB, Detron HB and MySQL Finland AB
+@c Copyright 1997-2002 TcX AB, Detron HB and MySQL Finland AB
+@c
+@c This manual is NOT distributed under a GPL style license.
+@c Use of the manual is subject to the following terms:
+@c - Conversion to other formats is allowed, but the actual
+@c content may not be altered or edited in any way.
+@c - You may create a printed copy for your own personal use.
+@c - For all other uses, such as selling printed copies or
+@c using (parts of) the manual in another publication,
+@c prior written agreement from MySQL AB is required.
+@c
+@c Please e-mail docs@mysql.com for more information or if
+@c you are interested in doing a translation.
@c
@c *********************************************************
-@c Note that @node names are used on our Website.
+@c Note that @node names are used on our web site.
@c So do not change node names without checking
@c Makefile.am and SitePages first.
@c *********************************************************
@c
@c %**start of header
-@c there's a better way to do this.. i just don't know it yet
+@c there's a better way to do this... i just don't know it yet
@c sed will remove the "@c ifnusphere " to make this valid
@c ifnusphere @set nusphere 1
@@ -66,7 +78,7 @@ END-INFO-DIR-ENTRY
@sp 10
@center @titlefont{MySQL Reference Manual}
@sp 10
-@center Copyright @copyright{} 1997-2001 MySQL AB
+@center Copyright @copyright{} 1997-2002 MySQL AB
@c blank page after title page makes page 1 be a page front.
@c also makes the back of the title page blank.
@page
@@ -95,16 +107,12 @@ END-INFO-DIR-ENTRY
@node Top, Introduction, (dir), (dir)
-@c @ifhtml
-@c <IMG SRC="Images/mysql-logo.gif">
-@c <!--Image doesn't exist. Can't find suitable replacement. (Matt) -->
-@c @end ifhtml
-
@ifinfo
-This is a manual for MySQL. This version is about the
-@value{mysql_version} version of MySQL. You can find a manual
-about any older version of MySQL in the binary or source
-distribution for that version.
+This is a manual for the @code{MySQL Database System}.
+This version is about the @value{mysql_version} version of
+@code{MySQL Server}. You can find a specific manual for any older
+version of @code{MySQL Server} in the binary or source distribution
+for that version.
@end ifinfo
@menu
@@ -112,85 +120,82 @@ distribution for that version.
* Installing:: Installing MySQL
* Tutorial:: MySQL Tutorial
* MySQL Database Administration:: MySQL Database Administration
-* MySQL Optimization:: MySQL Optimization
-* Reference:: MySQL language reference
-* Table types:: MySQL table types
-* Clients:: MySQL client tools and APIs
+* MySQL Optimisation:: MySQL Optimisation
+* Reference:: MySQL Language Reference
+* Table types:: MySQL Table Types
+* Clients:: MySQL Client Tools and APIs
* Extending MySQL:: Extending MySQL
* Problems:: Problems
-* Users:: Some MySQL users
-* MySQL customer usage:: MySQL customer usage
-* Contrib:: Contributed programs
+* Contrib:: Contributed Programs
* Credits:: Contributors to MySQL
-* News:: MySQL change history
-* Porting:: Comments on porting to other systems
+* News:: MySQL Change History
+* Porting:: Porting to Other Systems
* Environment variables:: MySQL environment variables
-* Regexp:: Description of MySQL regular expression syntax
-* Unireg:: What is Unireg?
+* Regexp:: MySQL Regular Expression Syntax
* GPL license:: GNU General Public License
-* LGPL license:: GNU Library General Public License
-* Placeholder:: Pieces of the manual in transit
-* Function Index:: SQL command, type and function index
+* LGPL license:: GNU Lesser General Public License
+* Function Index:: SQL Command, Type and Function Index
* Concept Index:: Concept Index
@end menu
-
-
@node Introduction, Installing, Top, Top
@chapter General Information About MySQL
@cindex overview
@cindex general information
-@cindex online location of manual
-@cindex manual, online location
-This is the MySQL reference manual; it documents MySQL
-Version @value{mysql_version}. As MySQL is work in progress,
-the manual gets updated frequently. There is a very good chance that
-this version is out of date, unless you are looking at it online. The
-most recent version of this manual is available at
-@uref{http://www.mysql.com/documentation/} in many different formats. If you
-have a hard time finding information in the manual, you can try the
-searchable PHP version at @uref{http://www.mysql.com/documentation/manual.php}.
-
-MySQL is a very fast, multi-threaded, multi-user, and robust SQL
-(Structured Query Language) database server.
-
-MySQL is free software. It is licensed with the @strong{GNU
-GENERAL PUBLIC LICENSE} @uref{http://www.gnu.org/}.
+The @code{MySQL (TM)} software delivers a very fast, multi-threaded,
+multi-user, and robust @code{SQL} (@code{Structured Query Language})
+database server.
+@code{MySQL Server} is intended for mission-critical, heavy load
+production systems as well as for embedding into mass-deployed software.
+@code{MySQL} is a trademark of @code{MySQL AB}.
+
+The @code{MySQL} software has @code{Dual licensing}, you can use
+@code{MySQL Server} free of charge under the
+@code{GNU GENERAL PUBLIC LICENSE} (@uref{http://www.gnu.org/licenses/}).
+You can also purchase commercial @code{MySQL Server} licenses from
+@code{MySQL AB} if you do not wish to be bound by the terms of the
+@code{GPL}.
@xref{Licensing and Support}.
-@uref{http://www.mysql.com/, The MySQL home page}
-provides the latest information about MySQL.
+The @code{MySQL} web site (@uref{http://www.mysql.com/}) provides the
+latest information about the @code{MySQL} software.
The following list describes some useful sections of the manual:
@itemize @bullet
@item
-For information about the company behind MySQL, see
-@ref{What is MySQL AB}.
+For information about the company behind the @code{MySQL Database Server},
+see @ref{What is MySQL AB}.
@item
-For a discussion of MySQL's capabilities, see @ref{Features}.
+For a discussion about the capabilities of the @code{MySQL Database Server},
+see @ref{Features}.
@item
For installation instructions, see @ref{Installing}.
@item
-For tips on porting MySQL to new architectures or operating
-systems, see @ref{Porting}.
+For tips on porting the @code{MySQL Database Software} to new architectures
+or operating systems, see @ref{Porting}.
+
+@item
+For information about upgrading from a Version 3.23 release, see
+@ref{Upgrading-from-3.23}.
@item
For information about upgrading from a Version 3.22 release, see
@ref{Upgrading-from-3.22}.
@item
-For a tutorial introduction to MySQL, see @ref{Tutorial}.
+For a tutorial introduction to the @code{MySQL Database Server},
+see @ref{Tutorial}.
@item
-For examples of SQL and benchmarking information, see the benchmarking
-directory (@file{sql-bench} in the distribution).
+For examples of @code{SQL} and benchmarking information, see the
+benchmarking directory (@file{sql-bench} in the distribution).
@item
For a history of new features and bug fixes, see @ref{News}.
@@ -215,7 +220,7 @@ The @code{mysqlbug} script should be used to generate bug reports.
For source distributions, the @code{mysqlbug} script can be found in the
@file{scripts} directory. For binary distributions, @code{mysqlbug} can
be found in the @file{bin} directory. If you have found a sensitive
-security bug in MySQL, you should send an email to
+security bug in @code{MySQL Server}, you should send an e-mail to
@email{security@@mysql.com}.
@cindex errors, reporting
@@ -223,265 +228,66 @@ security bug in MySQL, you should send an email to
@cindex mailing list address
@cindex @code{mysqlbug} script, location
-If you have any suggestions concerning additions or corrections to this
-manual, please send them to the manual team at @email{docs@@mysql.com}.
-
-This is a reference manual; it does not provide general instruction on SQL
-or relational database concepts. If you want general information about SQL,
-see @ref{General-SQL}. For books that focus more specifically on
-MySQL, see @ref{MySQL-Books}.
-
@menu
-* MySQL and MySQL AB:: MySQL, MySQL AB, and Open Source
+* Manual-info:: About This Manual
+* What-is:: What Is MySQL
+* What is MySQL AB:: What Is MySQL AB
+* Licensing and Support:: MySQL Support and Licensing
+* MySQL 4.0 In A Nutshell:: MySQL 4.0 In A Nutshell
* MySQL Information Sources:: MySQL Information Sources
-* Licensing and Support:: MySQL Licensing and Support
* Compatibility:: How Standards-compatible Is MySQL?
-* Comparisons:: How MySQL Compares to Other Databases
* TODO:: MySQL and the future (The TODO)
+* Comparisons:: How MySQL Compares to Other Open Source Databases
@end menu
-@node MySQL and MySQL AB, MySQL Information Sources, Introduction, Introduction
-@section MySQL, MySQL AB, and Open Source
-
-@menu
-* What-is:: What is MySQL?
-* What is MySQL AB:: What is MySQL AB?
-* Manual-info:: About this manual
-* Manual conventions:: Conventions used in this manual
-* History:: History of MySQL
-* Features:: The main features of MySQL
-* Stability:: How stable is MySQL?
-* Table size:: How Big Can MySQL Tables Be?
-* Year 2000 compliance:: Year 2000 compliance
-@end menu
+@node Manual-info, What-is, Introduction, Introduction
+@section About This Manual
+@cindex online location of manual
+@cindex manual, online location
-@node What-is, What is MySQL AB, MySQL and MySQL AB, MySQL and MySQL AB
-@subsection What Is MySQL
-
-@cindex MySQL, defined
-@cindex MySQL, introduction
-
-MySQL, the most popular Open Source SQL database, is provided
-by MySQL AB. MySQL AB is a commercial company that
-builds its business providing services around the MySQL database.
-@xref{What is MySQL AB}.
-
-@table @asis
-
-@item MySQL is a database management system.
-
-A database is a structured collection of data. It may be anything from a
-simple shopping list to a picture gallery or the vast amounts of
-information in a corporate network. To add, access, and process data
-stored in a computer database, you need a database management system
-such as MySQL. Since computers are very good at handling large
-amounts of data, database management plays a central role in computing,
-as stand-alone utilities, or as parts of other applications.
-
-@cindex databases, defined
-
-@item MySQL is a relational database management system.
-
-A relational database stores data in separate tables rather than putting
-all the data in one big storeroom. This adds speed and flexibility. The
-tables are linked by defined relations making it possible to combine
-data from several tables on request. The SQL part of MySQL
-stands for "Structured Query Language" - the most common standardized
-language used to access databases.
-
-@cindex relational databases, defined
-@cindex SQL, defined
-@item MySQL is Open Source Software.
-
-Open Source means that it is possible for anyone to use and modify.
-Anybody can download MySQL from the Internet and use it
-without paying anything. Anybody so inclined can study the source code
-and change it to fit their needs. MySQL uses the GPL (GNU
-General Public License) @uref{http://www.gnu.org}, to define what you
-may and may not do with the software in different situations. If you
-feel uncomfortable with the GPL or need to embed MySQL into a
-commercial application you can buy a commercially licensed version from
-us.
-
-@cindex open source, defined
-@cindex General Public License
-
-@item Why use MySQL?
-
-MySQL is very fast, reliable, and easy to use. If that is what
-you are looking for, you should give it a try. MySQL also has a
-very practical set of features developed in very close cooperation with
-our users. You can find a performance comparison of MySQL
-to some other database managers on our benchmark page.
-@xref{MySQL Benchmarks}.
-
-MySQL was originally developed to handle very large databases
-much faster than existing solutions and has been successfully used in
-highly demanding production environments for several years. Though
-under constant development, MySQL today offers a rich and very
-useful set of functions. The connectivity, speed, and security make
-MySQL highly suited for accessing databases on the Internet.
-
-@item The technical features of MySQL
-
-For advanced technical information, see @ref{Reference}. MySQL is
-a client/server system that consists of a multi-threaded SQL server
-that supports different backends, several different client programs and
-libraries, administrative tools, and several programming interfaces.
-
-We also provide MySQL as a multi-threaded library which you can
-link into your application to get a smaller, faster, easier to manage
-product.
-
-@item MySQL has a lot of contributed software available.
-
-It is very likely that you will find that your favorite application or
-language already supports MySQL.
-
-@end table
-
-@cindex pronunciation, MySQL
-@cindex MySQL, pronunciation
-@cindex goals of MySQL
-The official way to pronounce MySQL is ``My Ess Que Ell'' (not
-MY-SEQUEL). But we try to avoid correcting people who say MY-SEQUEL.
-
-
-@node What is MySQL AB, Manual-info, What-is, MySQL and MySQL AB
-@subsection What Is MySQL AB
-
-@cindex MySQL AB, defined
-
-MySQL AB is the Swedish company owned and run by the MySQL
-founders and main developers. We are dedicated to developing MySQL
-and spreading our database to new users. MySQL AB owns the copyright
-to the MySQL server source code and the MySQL trademark.
-A significant amount of revenues from our services goes to developing
-MySQL. @xref{What-is}.
-
-MySQL AB has been profitable providing MySQL from the start.
-We don't get any outside funding, but have earned all our money ourselves.
-
-We are searching after partners that would like to support our development
-of MySQL so that we could accelerate the development pace. If you
-are interested in doing this, you can email @email{partner@@mysql.com} about
-this!
-
-MySQL AB has currently 20+ people
-(@uref{http://www.mysql.com/development/team.html}) on its payroll and is growing rapidly.
-
-
-Our main sources of income are:
-
-@itemize @bullet
-@item
-Commercial high quality support for MySQL provided by the
-MySQL developers themselves. If you are interested in purchasing
-a support contract, please visit @uref{https://order.mysql.com/} to view our
-support options or to order support.
-
-@item
-Consulting services. We have developers and consultants in 12 countries
-and partners in many other countries that can help you with almost any
-MySQL related issues. If you need consulting services, please
-email a good description of your needs to @email{info@@mysql.com}! If we
-can't handle this ourselves we can usually find a partner or a developer
-that can help you with your problems.
-
-@item
-We sell licenses for using MySQL as an embedded database.
-@xref{Cost}. If you have a commercial product for which you need a fast,
-high quality database, but you can't afford to make your product Open Source,
-you can buy the right to use the MySQL server under a normal
-commercial copyright. If you are interested in this you can buy
-MySQL licenses at @uref{https://order.mysql.com/} or contact us
-at @email{licensing@@mysql.com}.
-
-@item
-Advertising. @uref{http://www.mysql.com/} is a very popular web site with
-more than 10,000,000 page views per months (January 2001). By putting a
-banner on this you are guaranteed to reach a lot of potential customers
-in the Open source, Linux and database community. If you are interested
-in this email @email{advertising@@mysql.com}.
-
-@item
-We are building a partner program to be able to provide MySQL
-services in every country. If you are interested in becoming a partner
-of MySQL AB please visit
-@uref{http://www.mysql.com/information/partners.html} or email
-@email{partner@@mysql.com}.
-
-@item
-We provide MySQL training through our partner programs. For more
-information, please email @email{info@@mysql.com}.
-
-@item
-The MySQL brand has, since 1995, been associated with speed and
-reliability, and is known to be something you can depend upon. If you are
-interested in using the MySQL trademark in your marketing, you
-can email @email{info@@mysql.com} about this.
-@end itemize
-
-The MySQL core values show our dedication to MySQL and
-Open Source.
-
-We want MySQL to be:
-
-@itemize @bullet
-@item
-The best and the most used database in the world.
-@item
-Available and affordable for all.
-@item
-Easy to use.
-@item
-Continuously improved while remaining fast and safe.
-@item
-Fun to use and improve.
-@item
-Free from bugs.
-@end itemize
-
-MySQL AB and the people of MySQL AB:
+This is the @code{MySQL} reference manual; it documents @code{MySQL}
+Version @value{mysql_version}. Being a reference manual, it does not
+provide general instruction on @code{SQL} or relational database
+concepts.
-@itemize @bullet
-@item
-Promote Open Source Philosophy and support the Open Source Community.
-@item
-Aim to be good citizens.
-@item
-Prefer partners that share our values and mind-set.
-@item
-Answer mail and give support.
-@item
-Are a virtual company, networking with others.
-@item
-Work against software patents.
-@end itemize
+As the @code{MySQL Database Software} is work in progress, the manual
+is also updated frequently.
+The most recent version of this manual is available at
+@uref{http://www.mysql.com/documentation/} in many different formats,
+currently there are Texinfo, plain text, Info, HTML, PostScript, PDF
+and Windows HLP versions.
+The primary document is the Texinfo file.
+The HTML version is produced automatically using a modified version of
+@code{texi2html}.
+The plain text and Info versions are produced with @code{makeinfo}.
+The Postscript version is produced using @code{texi2dvi} and @code{dvips}.
+The PDF version is produced with @code{pdftex}.
-@node Manual-info, Manual conventions, What is MySQL AB, MySQL and MySQL AB
-@subsection About This Manual
+If you have a hard time finding information in the manual, you can try
+our searchable PHP version at @uref{http://www.mysql.com/doc/}.
-This manual is currently available in Texinfo, plain text, Info, HTML,
-PostScript, and PDF versions. The primary document is the Texinfo file.
-The HTML version is produced automatically using a modified version of
-@code{texi2html}. The plain text and Info versions are produced with
-@code{makeinfo}. The Postscript version is produced using @code{texi2dvi}
-and @code{dvips}. The PDF version is produced with @code{pdftex}.
+If you have any suggestions concerning additions or corrections to this
+manual, please send them to the documentation team at @email{docs@@mysql.com}.
@cindex manual, available formats
@cindex Texinfo
This manual is written and maintained by David Axmark, Michael (Monty)
-Widenius, Jeremy Cole, and Paul DuBois. For other contributors,
-see @ref{Credits}.
+Widenius, Jeremy Cole, Arjen Lentz, and Paul DuBois. For other
+contributors, see @ref{Credits}.
+The copyright (2002) to this manual is owned by the Swedish company
+@code{MySQL AB}. @xref{Copyright}.
-@node Manual conventions, History, Manual-info, MySQL and MySQL AB
+@menu
+* Manual conventions:: Conventions Used in This Manual
+@end menu
+
+@node Manual conventions, , Manual-info, Manual-info
@subsection Conventions Used in This Manual
This manual uses certain typographical conventions:
@@ -546,7 +352,7 @@ shell> setenv VARNAME value
shell> some_command
@end example
-Often, database, table, and column names must be substituted into commands. To
+Often database, table, and column names must be substituted into commands. To
indicate that such substitution is necessary, this manual uses
@code{db_name}, @code{tbl_name} and @code{col_name}. For example, you might
see a statement like this:
@@ -606,7 +412,116 @@ alternatives are listed within braces (@samp{@{} and @samp{@}}):
@end example
-@node History, Features, Manual conventions, MySQL and MySQL AB
+@node What-is, What is MySQL AB, Manual-info, Introduction
+@section What Is MySQL
+
+@cindex MySQL, defined
+@cindex MySQL, introduction
+
+@code{MySQL}, the most popular @code{Open Source} SQL database, is
+developed and provided by @code{MySQL AB}. @code{MySQL AB} is a
+commercial company that builds its business providing services around
+the @code{MySQL} database.
+@xref{What is MySQL AB}.
+
+The @code{MySQL} web site (@uref{http://www.mysql.com/})
+provides the latest information about @code{MySQL} software and
+@code{MySQL AB}.
+
+@table @asis
+
+@item @code{MySQL} is a database management system.
+
+A database is a structured collection of data. It may be anything from a
+simple shopping list to a picture gallery or the vast amounts of
+information in a corporate network. To add, access, and process data
+stored in a computer database, you need a database management system
+such as @code{MySQL} Server. Since computers are very good at handling large
+amounts of data, database management plays a central role in computing,
+as stand-alone utilities, or as parts of other applications.
+
+@cindex databases, defined
+
+@item MySQL is a relational database management system.
+
+A relational database stores data in separate tables rather than putting
+all the data in one big storeroom. This adds speed and flexibility.
+The tables are linked by defined relations making it possible to combine
+data from several tables on request. The @code{SQL} part of
+``@code{MySQL}'' stands for ``@code{Structured Query Language}''
+- the most common standardised language used to access databases.
+
+@cindex relational databases, defined
+@cindex SQL, defined
+@item MySQL Software is Open Source.
+
+@code{Open Source} means that it is possible for anyone to use and modify.
+Anybody can download the @code{MySQL} software from the Internet and use it
+without paying anything. Anybody so inclined can study the source code
+and change it to fit their needs. The @code{MySQL} software uses the
+@code{GPL} (@code{GNU General Public License})
+@uref{http://www.gnu.org/licenses/}, to define what you
+may and may not do with the software in different situations.
+If you feel uncomfortable with the @code{GPL} or need to embed
+@code{MySQL} code into a commercial application you can buy a
+commercially licensed version from us.
+@xref{MySQL server licenses}.
+
+@cindex Open Source, defined
+@cindex General Public License
+
+@item Why use the MySQL Database Server?
+
+The @code{MySQL Database Server} is very fast, reliable, and easy to use.
+If that is what you are looking for, you should give it a try.
+@code{MySQL Server} also has a practical set of features developed in
+close cooperation with our users. You can find a performance comparison
+of @code{MySQL Server} to some other database managers on our benchmark page.
+@xref{MySQL Benchmarks}.
+
+@code{MySQL Server} was originally developed to handle large databases
+much faster than existing solutions and has been successfully used in
+highly demanding production environments for several years. Though
+under constant development, @code{MySQL Server} today offers a rich and
+useful set of functions. The connectivity, speed, and security make
+@code{MySQL Server} highly suited for accessing databases on the Internet.
+
+@item The technical features of MySQL Server
+
+For advanced technical information, see @ref{Reference}.
+The @code{MySQL Database Software} is a client/server system that consists
+of a multi-threaded @code{SQL} server that supports different backends,
+several different client programs and libraries, administrative tools,
+and a wide range of programming interfaces (@code{API}s).
+
+We also provide @code{MySQL Server} as a multi-threaded library which you
+can link into your application to get a smaller, faster, easier to manage
+product.
+
+@item There is a lot of contributed MySQL software available.
+
+It is very likely that you will find that your favorite application or
+language already supports the @code{MySQL Database Server}.
+
+@end table
+
+@cindex pronunciation, MySQL
+@cindex MySQL, pronunciation
+@cindex goals of MySQL
+The official way to pronounce @code{MySQL} is ``My Ess Que Ell'' (not
+``my sequel''), but we don't mind if you pronounce it as ``my sequel''
+or in some other localised way.
+
+
+@menu
+* History:: History of MySQL
+* Features:: The Main Features of MySQL
+* Stability:: How Stable Is MySQL?
+* Table size:: How Big Can MySQL Tables Be?
+* Year 2000 compliance:: Year 2000 Compliance
+@end menu
+
+@node History, Features, What-is, What-is
@subsection History of MySQL
@cindex MySQL history
@@ -621,340 +536,273 @@ flexible enough for our needs. This resulted in a new SQL interface to our
database but with almost the same API interface as @code{mSQL}. This API was
chosen to ease porting of third-party code.
-The derivation of the name MySQL is not perfectly clear. Our base
+The derivation of the name @code{MySQL} is not perfectly clear. Our base
directory and a large number of our libraries and tools have had the prefix
``my'' for well over 10 years. However, Monty's daughter (some years younger)
-is also named My. Which of the two gave its name to MySQL is
+is also named My. Which of the two gave its name to @code{MySQL} is
still a mystery, even for us.
-@node Features, Stability, History, MySQL and MySQL AB
+@node Features, Stability, History, What-is
@subsection The Main Features of MySQL
@cindex main features of MySQL
@cindex features of MySQL
The following list describes some of the important characteristics
-of MySQL:
+of the @code{MySQL Database Software}. @xref{MySQL 4.0 In A Nutshell}.
@c This list is too technical and should be divided into one feature
@c list comparable to commercial competition and a very technical on
@c with max limits (from crash-me) and so on.
+@table @asis
+@item Internals and Portability
@itemize @bullet
@item
+Written in C and C++. Tested with a broad range of different compilers.
+@item
+No memory leaks. The @code{MySQL} code has been tested with Purify,
+a commercial memory leakage detector.
+@item
+Works on many different platforms. @xref{Which OS}.
+@item
+Uses GNU Automake (1.4), Autoconf (Ver 2.52 or newer), and Libtool for
+portability.
+@item
+APIs for C, C++, Eiffel, Java, Perl, PHP, Python and Tcl. @xref{Clients}.
+@item
Fully multi-threaded using kernel threads. This means it can easily
use multiple CPUs if available.
-
@item
-C, C++, Eiffel, Java, Perl, PHP, Python and Tcl APIs. @xref{Clients}.
-
+Very fast B-tree disk tables with index compression.
@item
-Works on many different platforms. @xref{Which OS}.
+A very fast thread-based memory allocation system.
+@item
+Very fast joins using an optimised one-sweep multi-join.
+@item
+In-memory hash tables which are used as temporary tables.
+@item
+SQL functions are implemented through a highly optimised class library and
+should be as fast as possible! Usually there isn't any memory allocation
+at all after query initialisation.
+@end itemize
+@item Column Types
+@itemize @bullet
@item
Many column types: signed/unsigned integers 1, 2, 3, 4, and 8 bytes
long, @code{FLOAT}, @code{DOUBLE}, @code{CHAR}, @code{VARCHAR},
@code{TEXT}, @code{BLOB}, @code{DATE}, @code{TIME}, @code{DATETIME},
-@code{TIMESTAMP}, @code{YEAR}, @code{SET}, and @code{ENUM} types.
+@code{TIMESTAMP}, @code{YEAR}, @code{SET}, and @code{ENUM} types.
@xref{Column types}.
-
@item
-Very fast joins using an optimized one-sweep multi-join.
+Fixed-length and variable-length records.
+@item
+@cindex default values
+All columns have default values.
+You can use @code{INSERT} to insert a subset of a table's columns; those
+columns that are not explicitly given values are set to their default
+values.
+@end itemize
+@item Commands and Functions
+@itemize @bullet
@item
Full operator and function support in the @code{SELECT} and @code{WHERE}
parts of queries. For example:
@example
-mysql> SELECT CONCAT(first_name, " ", last_name) FROM tbl_name
- WHERE income/dependents > 10000 AND age > 30;
+mysql> SELECT CONCAT(first_name, " ", last_name)
+ -> FROM tbl_name
+ -> WHERE income/dependents > 10000 AND age > 30;
@end example
@item
-SQL functions are implemented through a highly optimized class library and
-should be as fast as possible! Usually there isn't any memory allocation
-at all after query initialization.
-
-@item
-Full support for SQL @code{GROUP BY} and @code{ORDER BY} clauses. Support
-for group functions (@code{COUNT()}, @code{COUNT(DISTINCT ...)},
+Full support for SQL @code{GROUP BY} and @code{ORDER BY} clauses. Support
+for group functions (@code{COUNT()}, @code{COUNT(DISTINCT ...)},
@code{AVG()}, @code{STD()}, @code{SUM()}, @code{MAX()} and @code{MIN()}).
-
@item
Support for @code{LEFT OUTER JOIN} and @code{RIGHT OUTER JOIN} with ANSI
SQL and ODBC syntax.
-
+@item
+Aliases on tables and columns are allowed as in the SQL92 standard.
+@item
+@code{DELETE}, @code{INSERT}, @code{REPLACE}, and @code{UPDATE} return
+the number of rows that were changed (affected). It is possible to return
+the number of rows matched instead by setting a flag when connecting to the
+server.
+@item
+The @code{MySQL}-specific @code{SHOW} command can be used to retrieve
+information about databases, tables, and indexes. The @code{EXPLAIN} command
+can be used to determine how the optimiser resolves a query.
+@item
+Function names do not clash with table or column names. For example,
+@code{ABS} is a valid column name. The only restriction is that for a
+function call, no spaces are allowed between the function name and the
+@samp{(} that follows it. @xref{Reserved words}.
@item
You can mix tables from different databases in the same query (as of
Version 3.22).
+@end itemize
+@item Security
+@itemize @bullet
@item
A privilege and password system that is very flexible and secure, and
allows host-based verification. Passwords are secure because all
password traffic is encrypted when you connect to a server.
+@end itemize
+@item Scalability and Limits
+@itemize @bullet
@item
-ODBC (Open-DataBase-Connectivity) support for Win32 (with source). All
-ODBC 2.5 functions and many others. For example, you can use MS Access to
-connect to your MySQL server. @xref{ODBC}.
-
-@item
-Very fast B-tree disk tables with index compression.
-
-@item
-Up to 32 indexes per table are allowed. Each index may consist of 1 to 16
-columns or parts of columns. The maximum index length is 500 bytes (this
-may be changed when compiling MySQL). An index may use a prefix
-of a @code{CHAR} or @code{VARCHAR} field.
-
-@item
-Fixed-length and variable-length records.
-
-@item
-In-memory hash tables which are used as temporary tables.
-
-@item
-Handles large databases. We are using MySQL with some
+Handles large databases. We are using @code{MySQL Server} with some
databases that contain 50,000,000 records and we know of users that
-uses MySQL with 60,000 tables and about 5,000,000,000 rows
-
-@item
-All columns have default values. You can use @code{INSERT} to insert a
-subset of a table's columns; those columns that are not explicitly given
-values are set to their default values.
-
-@item
-Uses GNU Automake, Autoconf, and Libtool for portability.
-
+uses @code{MySQL Server} with 60,000 tables and about 5,000,000,000 rows.
@item
-Written in C and C++. Tested with a broad range of different compilers.
+Up to 32 indexes per table are allowed. Each index may consist of 1 to 16
+columns or parts of columns. The maximum index width is 500 bytes
+(this may be changed when compiling @code{MySQL Server}).
+An index may use a prefix of a @code{CHAR} or @code{VARCHAR} field.
+@end itemize
+@item Connectivity
+@itemize @bullet
@item
-A very fast thread-based memory allocation system.
-
+Clients may connect to the @code{MySQL} server using TCP/IP Sockets,
+Unix Sockets (Unix), or Named Pipes (NT).
@item
-No memory leaks. MySQL has been tested with Purify, a commercial
-memory leakage detector.
+@code{ODBC} (Open-DataBase-Connectivity) support for Win32 (with source).
+All ODBC 2.5 functions and many others. For example, you can use
+MS Access to connect to your @code{MySQL} server. @xref{ODBC}.
+@end itemize
+@item Localisation
+@itemize @bullet
@item
-Includes @code{myisamchk}, a very fast utility for table checking,
-optimization, and repair. All of the functionality of @code{myisamchk}
-is also available through the SQL interface as well.
-@xref{MySQL Database Administration}.
-
+The server can provide error messages to clients in many languages.
+@xref{Languages}.
@item
Full support for several different character sets, including
-ISO-8859-1 (Latin1), big5, ujis, and more. For example, the
-Scandinavian characters `@ringaccent{a}', `@"a' and `@"o' are allowed
-in table and column names.
-
+ISO-8859-1 (Latin1), german, big5, ujis, and more. For example,
+the Scandinavian characters 'å', 'ä' and 'ö' are allowed in table
+and column names.
@item
-All data are saved in the chosen character set. All comparisons for normal
+All data is saved in the chosen character set. All comparisons for normal
string columns are case insensitive.
-
@item
Sorting is done according to the chosen character set (the Swedish
-way by default). It is possible to change this when the MySQL server
-is started up. To see an example of very advanced sorting, look at the
-Czech sorting code. MySQL supports many different character sets
-that can be specified at compile and run time.
-
-@item
-Aliases on tables and columns are allowed as in the SQL92 standard.
-
-@item
-@code{DELETE}, @code{INSERT}, @code{REPLACE}, and @code{UPDATE} return
-the number of rows that were changed (affected). It is possible to return
-the number of rows matched instead by setting a flag when connecting to the
-server.
+way by default). It is possible to change this when the @code{MySQL}
+server is started. To see an example of very advanced sorting, look
+at the Czech sorting code. @code{MySQL Server} supports many different
+character sets that can be specified at compile and run time.
+@end itemize
+@item Clients and Tools
+@itemize @bullet
@item
-Function names do not clash with table or column names. For example,
-@code{ABS} is a valid column name. The only restriction is that for a
-function call, no spaces are allowed between the function name and the
-@samp{(} that follows it. @xref{Reserved words}.
-
+Includes @code{myisamchk}, a very fast utility for table checking,
+optimisation, and repair. All of the functionality of @code{myisamchk}
+is also available through the SQL interface as well.
+@xref{MySQL Database Administration}.
@item
-All MySQL programs can be invoked with the @code{--help} or @code{-?}
+All @code{MySQL} programs can be invoked with the @code{--help} or @code{-?}
options to obtain online assistance.
-
-@item
-The server can provide error messages to clients in many languages.
-@xref{Languages}.
-
-@item
-Clients may connect to the MySQL server using TCP/IP Sockets,
-Unix Sockets (Unix), or Named Pipes (NT).
-
-@item
-The MySQL-specific @code{SHOW} command can be used to retrieve
-information about databases, tables, and indexes. The @code{EXPLAIN} command
-can be used to determine how the optimizer resolves a query.
@end itemize
+@end table
+
-@node Stability, Table size, Features, MySQL and MySQL AB
+@node Stability, Table size, Features, What-is
@subsection How Stable Is MySQL?
@cindex stability
-This section addresses the questions ``How stable is MySQL?'' and
-``Can I depend on MySQL in this project?'' We will try to clarify
-some issues and to answer some of the more important questions that seem to
-concern many people. This section has been put together from information
-gathered from the mailing list (which is very active in reporting bugs).
-
-At TcX, MySQL has worked without any problems in our projects since
-mid-1996. When MySQL was released to a wider public, we noticed that
-there were some pieces of ``untested code'' that were quickly found by the
-new users who made queries in a manner different than our own. Each new
-release has had fewer portability problems than the previous one (even though
-each has had many new features).
-
-Each release of MySQL has been usable, and there have been problems
-only when users start to use code from the ``gray zones.'' Naturally, outside
-users don't know what the gray zones are; this section attempts to indicate
-those that are currently known. The descriptions deal with Version 3.23
-of MySQL. All known and reported bugs are fixed in the latest
-version, with the exception of the bugs listed in the bugs section, which
-are things that are design-related. @xref{Bugs}.
-
-MySQL is written in multiple layers and different independent
-modules. These modules are listed below with an indication of how
+This section addresses the questions ``@emph{How stable is MySQL Server?}''
+and ``@emph{Can I depend on MySQL Server in this project?}''
+We will try to clarify these issues and answer some important
+questions that concern many potential users. The information in this
+section is based on data gathered from the mailing list, which is
+very active in identifying problems as well as reporting types of use.
+
+Original code stems back from the early 80s, providing a stable code
+base, and the ISAM table format remains backwards compatible.
+At TcX, the predecessor of @code{MySQL AB}, @code{MySQL} code has worked
+in projects since mid-1996, without any problems.
+When the @code{MySQL Database Software} was released to a wider public,
+we noticed that there were
+some pieces of ``untested code'' that were quickly found by the new
+users who made different types of queries from us. Each new release
+has had fewer portability problems (even though each new release has
+had many new features).
+
+Each release of the @code{MySQL Server} has been usable. There have only
+been problems
+when users try code from the ``gray zones.'' Naturally, new users
+don't know what the gray zones are; this section attempts to indicate
+those that are currently known.
+The descriptions mostly deal with Version 3.23 of @code{MySQL Server}.
+All known and reported bugs are fixed in the latest version, with the
+exception of those listed in the bugs section, which are things that
+are design-related. @xref{Bugs}.
+
+The @code{MySQL Server} design is multi-layered with independent modules.
+Some of the newer modules are listed below with an indication of how
well-tested each of them is:
@cindex modules, list of
@table @strong
-@item The ISAM table handler --- Stable
-This manages storage and retrieval of all data in MySQL Version 3.22
-and earlier. In all MySQL releases there hasn't been a single
-(reported) bug in this code. The only known way to get a corrupted table
-is to kill the server in the middle of an update. Even that is unlikely
-to destroy any data beyond rescue, because all data are flushed to disk
-between each query. There hasn't been a single bug report about lost data
-because of bugs in MySQL.
-
-@cindex ISAM table handler
-@cindex storing, data
-@cindex retrieving, data
-@cindex data, ISAM table handler
-
-@item The MyISAM table handler --- Stable
-This is new in MySQL Version 3.23. It's largely based on the ISAM
-table code but has a lot of new and very useful features.
-
-@item The parser and lexical analyser --- Stable
-There hasn't been a single reported bug in this system for a long time.
-
-@item The C client code --- Stable
-No known problems. In early Version 3.20 releases, there were some limitations
-in the send/receive buffer size. As of Version 3.21, the buffer size is now
-dynamic up to a default of 16M.
-
-@item Standard client programs --- Stable
-These include @code{mysql}, @code{mysqladmin}, @code{mysqlshow},
-@code{mysqldump}, and @code{mysqlimport}.
-
-@item Basic SQL --- Stable
-The basic SQL function system and string classes and dynamic memory
-handling. Not a single reported bug in this system.
-
-@item Query optimizer --- Stable
-
-@item Range optimizer --- Stable
-
-@item Join optimizer --- Stable
-
-@item Locking --- Gamma
+@item Replication -- Gamma
+Large server clusters using replication are in production use, with
+good results. Work on enhanced replication features is continuing
+in @code{MySQL} 4.0.
+
+@item @code{InnoDB} tables -- Stable (in 3.23 from 3.23.49)
+The @code{InnoDB} transactional table handler has now been declared
+stable in the @code{MySQL} 3.23 tree, starting from version 3.23.49.
+@code{InnoDB} is being used in large, heavy load production systems.
+
+@item @code{BDB} tables -- Gamma
+The @code{Berkeley DB} code is very stable, but we are still improving
+the @code{BDB} transactional table handler interface in
+@code{MySQL Server}, so it will take some time before this is as well
+tested as the other table types.
+
+@item @code{FULLTEXT} -- Beta
+Full text search works but is not yet widely used.
+Important enhancements are being implemented for @code{MySQL} 4.0.
+
+@item @code{MyODBC 2.50} (uses ODBC SDK 2.5) -- Gamma
+Increasingly in wide use. Some issues brought up appear to be
+application related and independent of the ODBC driver or underlying
+database server.
+
+@item Automatic recovery of @code{MyISAM} tables -- Gamma
+This status only regards the new code in the @code{MyISAM} table
+handler that checks if the table was closed properly on open and
+executes an automatic check/repair of the table if it wasn't.
+
+@item Bulk-insert -- Alpha
+New feature in @code{MyISAM} tables in @code{MySQL} 4.0 for faster
+insert of many rows.
+
+@item Locking -- Gamma
This is very system-dependent. On some systems there are big problems
-using standard OS locking (@code{fcntl()}). In these cases, you should run the
-MySQL daemon with the @code{--skip-locking} flag. Problems are known
-to occur on some Linux systems, and on SunOS when using NFS-mounted file
-systems.
-
-@item Linux threads --- Stable
-The major problem found has been with the @code{fcntl()} call, which is
-fixed by using the @w{@code{--skip-locking}} option to
-@code{mysqld}. Some people have reported lockup problems with Version 0.5.
-LinuxThreads will need to be recompiled if you plan to use
-1000+ concurrent connections. Although it is possible to run that many
-connections with the default LinuxThreads (however, you will never go
-above 1021), the default stack spacing of 2 MB makes the application
-unstable, and we have been able to reproduce a coredump after creating
-1021 idle connections. @xref{Linux}.
-
-@item Solaris 2.5+ pthreads --- Stable
-We use this for all our production work.
-
-@item MIT-pthreads (Other systems) --- Stable
-There have been no reported bugs since Version 3.20.15 and no known bugs since
-Version 3.20.16. On some systems, there is a ``misfeature'' where some
-operations are quite slow (a 1/20 second sleep is done between each query).
-Of course, MIT-pthreads may slow down everything a bit, but index-based
-@code{SELECT} statements are usually done in one time frame so there shouldn't
-be a mutex locking/thread juggling.
-
-@item Other thread implementions --- Beta - Gamma
-The ports to other systems are still very new and may have bugs, possibly
-in MySQL, but most often in the thread implementation itself.
-
-@item @code{LOAD DATA ...}, @code{INSERT ... SELECT} --- Stable
-Some people thought they had found bugs here, but these usually have
-turned out to be misunderstandings. Please check the manual before reporting
-problems!
-
-@item @code{ALTER TABLE} --- Stable
-Small changes in Version 3.22.12.
-
-@item DBD --- Stable
-Now maintained by Jochen Wiedmann
-(@email{wiedmann@@neckar-alb.de}). Thanks!
-
-@item @code{mysqlaccess} --- Stable
-Written and maintained by Yves Carlier
-(@email{Yves.Carlier@@rug.ac.be}). Thanks!
-
-@item @code{GRANT} --- Stable
-Big changes made in MySQL Version 3.22.12.
-
-@item @strong{MyODBC} (uses ODBC SDK 2.5) --- Gamma
-It seems to work well with some programs.
-
-@item Replication -- Beta / Gamma
-We are still working on replication, so don't expect this to be rock
-solid yet. On the other hand, some MySQL users are already
-using this with good results.
-
-@item BDB Tables -- Beta
-The Berkeley DB code is very stable, but we are still improving the interface
-between MySQL and BDB tables, so it will take some time before this
-is as tested as the other table types.
-
-@item InnoDB Tables -- Beta
-This is a recent addition to @code{MySQL}. They appear to work good and
-can be used after some initial testing.
-
-@item Automatic recovery of MyISAM tables - Beta
-This only affects the new code that checks if the table was closed properly
-on open and executes an automatic check/repair of the table if it wasn't.
-
-@item MERGE tables -- Beta / Gamma
-The usage of keys on @code{MERGE} tables is still not that tested. The
-other part of the @code{MERGE} code is quite well tested.
-
-@item FULLTEXT -- Beta
-Text search seems to work, but is still not widely used.
+using standard OS locking (@code{fcntl()}). In these cases, you should
+run @code{mysqld} with the @code{--skip-locking} flag.
+Problems are known to occur on some Linux systems, and on SunOS when
+using NFS-mounted file systems.
@end table
-MySQL AB provides e-mail support for paying customers, but the
-MySQL mailing list usually provides answers to common questions.
-Bugs are usually fixed right away with a patch; for serious bugs, there is
-almost always a new release.
+@code{MySQL AB} provides high-quality support for paying customers,
+but the @code{MySQL} mailing list usually provides answers to common
+questions. Bugs are usually fixed right away with a patch; for serious
+bugs, there is almost always a new release.
-@node Table size, Year 2000 compliance, Stability, MySQL and MySQL AB
+@node Table size, Year 2000 compliance, Stability, What-is
@subsection How Big Can MySQL Tables Be?
@cindex tables, maximum size
@@ -963,31 +811,31 @@ almost always a new release.
@cindex limits, file size
@cindex files, size limits
-MySQL Version 3.22 has a 4G limit on table size. With the new
-@code{MyISAM} in MySQL Version 3.23 the maximum table size is
-pushed up to 8 million terabytes (2 ^ 63 bytes).
+@code{MySQL} Version 3.22 has a 4G limit on table size. With the new
+@code{MyISAM} table type in @code{MySQL} Version 3.23, the maximum table
+size is pushed up to 8 million terabytes (2 ^ 63 bytes).
Note, however, that operating systems have their own file size
limits. Here are some examples:
-@multitable @columnfractions .5 .5
+@multitable @columnfractions .6 .4
@item @strong{Operating System} @tab @strong{File Size Limit}
@item Linux-Intel 32 bit @tab 2G, 4G or more, depends on Linux version
@item Linux-Alpha @tab 8T (?)
@item Solaris 2.5.1 @tab 2G (possible 4G with patch)
@item Solaris 2.6 @tab 4G
@item Solaris 2.7 Intel @tab 4G
-@item Solaris 2.7 ULTRA-SPARC @tab 8T (?)
+@item Solaris 2.7 ULTRA-SPARC @tab 512G
@end multitable
On Linux 2.2 you can get bigger tables than 2G by using the LFS patch for
the ext2 file system. On Linux 2.4 there exists also patches for ReiserFS
to get support for big files.
-This means that the table size for MySQL is normally limited by
-the operating system.
+This means that the table size for @code{MySQL} databases is normally
+limited by the operating system.
-By default, MySQL tables have a maximum size of about 4G. You can
+By default, @code{MySQL} tables have a maximum size of about 4G. You can
check the maximum table size for a table with the @code{SHOW TABLE STATUS}
command or with the @code{myisamchk -dv table_name}.
@xref{SHOW}.
@@ -1006,39 +854,40 @@ have, in effect, much bigger tables. @xref{myisampack, ,
You can go around the operating system file limit for @code{MyISAM} data
files by using the @code{RAID} option. @xref{CREATE TABLE}.
-Another solution can be the included MERGE library, which allows you to
-handle a collection of identical tables as one. @xref{MERGE, MERGE
-tables}.
+Another solution can be the included @code{MERGE} library, which allows
+you to handle a collection of identical tables as one.
+@xref{MERGE, MERGE tables}.
-@node Year 2000 compliance, , Table size, MySQL and MySQL AB
+@node Year 2000 compliance, , Table size, What-is
@subsection Year 2000 Compliance
@cindex Year 2000 compliance
@cindex compliance, Y2K
@cindex date functions, Y2K compliance
-MySQL itself has no problems with Year 2000 (Y2K) compliance:
+The @code{MySQL Server} itself has no problems with Year 2000 (Y2K)
+compliance:
@itemize @bullet
@item
-MySQL uses Unix time functions and has no problems with dates
+@code{MySQL Server} uses Unix time functions and has no problems with dates
until @code{2069}; all 2-digit years are regarded to be in the range
@code{1970} to @code{2069}, which means that if you store @code{01} in a
-@code{year} column, MySQL treats it as @code{2001}.
+@code{year} column, @code{MySQL Server} treats it as @code{2001}.
@item
-All MySQL date functions are stored in one file @file{sql/time.cc}
+All @code{MySQL} date functions are stored in one file @file{sql/time.cc}
and coded very carefully to be year 2000-safe.
@item
-In MySQL Version 3.22 and later, the new @code{YEAR} column type
-can store years @code{0} and @code{1901} to @code{2155} in 1 byte and display
-them using 2 or 4 digits.
+In @code{MySQL} Version 3.22 and later, the new @code{YEAR} column type
+can store years @code{0} and @code{1901} to @code{2155} in 1 byte and
+display them using 2 or 4 digits.
@end itemize
-You may run into problems with applications that use MySQL in a
-way that is not Y2K-safe. For example, many old applications store
+You may run into problems with applications that use @code{MySQL Server}
+in a way that is not Y2K-safe. For example, many old applications store
or manipulate years using 2-digit values (which are ambiguous) rather than
4-digit values. This problem may be compounded by applications that use
values such as @code{00} or @code{99} as ``missing'' value indicators.
@@ -1047,17 +896,19 @@ Unfortunately, these problems may be difficult to fix, because different
applications may be written by different programmers, each of whom may
use a different set of conventions and date-handling functions.
-Here is a simple demonstration illustrating that MySQL doesn't have
-any problems with dates until the year 2030:
+Here is a simple demonstration illustrating that @code{MySQL Server}
+doesn't have any problems with dates until the year 2030:
@example
mysql> DROP TABLE IF EXISTS y2k;
Query OK, 0 rows affected (0.01 sec)
-mysql> CREATE TABLE y2k (date date, date_time datetime, time_stamp timestamp);
+mysql> CREATE TABLE y2k (date date,
+ -> date_time datetime,
+ -> time_stamp timestamp);
Query OK, 0 rows affected (0.00 sec)
-mysql> INSERT INTO y2k VALUES
+mysql> INSERT INTO y2k VALUES
-> ("1998-12-31","1998-12-31 23:59:59",19981231235959),
-> ("1999-01-01","1999-01-01 00:00:00",19990101000000),
-> ("1999-09-09","1999-09-09 23:59:59",19990909235959),
@@ -1105,1027 +956,1061 @@ range up to only @code{2030-01-01}. @code{TIMESTAMP} has a range of
@code{1970} to @code{2030} on 32-bit machines (signed value). On 64-bit
machines it handles times up to @code{2106} (unsigned value).
-Even though MySQL is Y2K-compliant, it is your responsibility to
-provide unambiguous input. See @ref{Y2K issues} for MySQL's rules
-for dealing with ambiguous date input data (data containing 2-digit year
-values).
+Even though @code{MySQL Server} is Y2K-compliant, it is your responsibility
+to provide unambiguous input. See @ref{Y2K issues} for @code{MySQL Server}'s
+rules for dealing with ambiguous date input data (data containing 2-digit
+year values).
-@node MySQL Information Sources, Licensing and Support, MySQL and MySQL AB, Introduction
-@section MySQL Information Sources
-
-@cindex manuals, about MySQL
-@cindex books, about MySQL
-@menu
-* MySQL-Books:: Books About MySQL
-* General-SQL:: General SQL Information and Tutorials
-* Useful Links:: Useful MySQL-related Links
-* Questions:: MySQL Mailing Lists
-@end menu
+@node What is MySQL AB, Licensing and Support, What-is, Introduction
+@section What Is MySQL AB
+@cindex MySQL AB, defined
-@node MySQL-Books, General-SQL, MySQL Information Sources, MySQL Information Sources
-@subsection Books About MySQL
-
-For the latest book information, with user comments, please visit
-@uref{http://www.mysql.com/portal/books/html/index.html}.
-
-While this manual is still the right place for up to date technical
-information, its primary goal is to contain everything there is to know
-about MySQL. It is sometimes nice to have a bound book to read
-in bed or while you travel. Here is a list of books about MySQL and
-related subjects (in English).
+@code{MySQL AB} is the company of the @code{MySQL} founders and main
+developers. @code{MySQL AB} was originally established in Sweden by
+David Axmark, Allan Larsson and Michael @code{Monty} Widenius.
-By purchasing a book through these hyperlinks provided herein, you are
-contributing to the development of MySQL.
+All the developers of the @code{MySQL} server are employed by the company.
+We are a virtual organisation with people in a dozen countries around
+the world. We communicate extensively over the net every day with each
+other and with our users, supporters and partners.
-@emph{MySQL}
-@multitable @columnfractions .3 .7
-@item Available @tab @uref{http://service.bfast.com/bfast/click?bfmid=2181&sourceid=34233559&bfpid=0735709211&bfmtype=book, Barnes and Noble}
-@item Publisher @tab New Riders
-@item Author @tab Paul DuBois
-@item Pub Date @tab 1st Edition December 1999
-@item ISBN @tab 0735709211
-@item Pages @tab 800
-@item Price @tab $49.99 US
-@item Downloadable examples @tab
- @uref{http://www.kitebird.com/mysql-book/, @code{samp_db} distribution}
-@item Errata @tab
-@uref{http://www.kitebird.com/mysql-book/errata.html, are available here}
-@end multitable
+We are dedicated to developing the @code{MySQL} software and spreading
+our database to new users. @code{MySQL AB} owns the copyright to the
+@code{MySQL} source code, the @code{MySQL} logo and trademark and this
+manual. @xref{What-is}.
-Foreword by Michael ``Monty'' Widenius, MySQL Moderator.
-@*
-
-In @emph{MySQL}, Paul DuBois provides you with a comprehensive guide to
-one of the most popular relational database systems. Paul has
-contributed to the online documentation for MySQL and is an
-active member of the MySQL community. The principal MySQL
-developer, Monty Widenius, and a network of his fellow developers
-reviewed the manuscript, and provided Paul with the kind of insight
-no one else could supply.
-@*
+@menu
+* MySQL AB business model and services:: The Business Model and Services of MySQL AB
+* Contact information:: Contact Information
+@end menu
-Instead of merely giving you a general overview of MySQL, Paul
-teaches you how to make the most of its capabilities. Through two
-sample database applications that run throughout the book, he
-gives you solutions to problems you're sure to face. He helps you
-integrate MySQL efficiently with third-party tools, such as PHP
-and Perl, enabling you to generate dynamic Web pages through
-database queries. He teaches you to write programs that access
-MySQL databases, and also provides a comprehensive set of
-references to column types, operators, functions, SQL syntax,
-MySQL programming, C API, Perl @code{DBI}, and PHP API.
-@emph{MySQL} simply gives you the kind of information you won't find
-anywhere else.
-@*
+The @code{MySQL} core values show our dedication to @code{MySQL} and
+@code{Open Source}.
-If you use MySQL, this book provides you with:
+We want the @code{MySQL Database Software} to be:
@itemize @bullet
@item
-An introduction to MySQL and SQL.
+The best and the most widely used database in the world.
+@item
+Available and affordable for all.
+@item
+Easy to use.
+@item
+Continuously improving while remaining fast and safe.
+@item
+Fun to use and improve.
@item
-Coverage of MySQL's data types and how to use them.
+Free from bugs.
+@end itemize
+
+@code{MySQL AB} and the people at @code{MySQL AB}:
+@itemize @bullet
@item
-Thorough treatment of how to write client programs in C.
+Promote @code{Open Source} Philosophy and support the
+@code{Open Source} Community.
@item
-A guide to using the Perl @code{DBI} and PHP APIs for developing
-command-line and Web-based applications.
+Aim to be good citizens.
@item
-Tips on administrative issues such as user accounts, backup,
-crash recovery, and security.
+Prefer partners that share our values and mind-set.
@item
-Help in choosing an ISP for MySQL access.
+Answer e-mail and provide support.
@item
-A comprehensive reference for MySQL's data types, operators,
-functions, and SQL statements and utilities.
+Are a virtual company, networking with others.
@item
-Complete reference guides for MySQL's C API, the Perl @code{DBI} API,
-and PHP's MySQL-related functions.
+Work against software patents.
@end itemize
-@*
-
-@emph{MySQL & mSQL}
-@multitable @columnfractions .3 .7
-@item Available @tab @uref{http://service.bfast.com/bfast/click?bfmid=2181&sourceid=34233559&bfpid=1565924347&bfmtype=book, Barnes and Noble}
-@item Publisher @tab O'Reilly
-@item Authors @tab Randy Jay Yarger, George Reese & Tim King
-@item Pub Date @tab 1st Edition July 1999
-@item ISBN @tab 1-56592-434-7, Order Number: 4347
-@item Pages @tab 506
-@item Price @tab $34.95
-@end multitable
-
-This book teaches you how to use MySQL and @code{mSQL}, two popular
-and robust database products that support key subsets of SQL on both Linux
-and Unix systems. Anyone who knows basic C, Java, Perl, or Python can
-write a program to interact with a database, either as a stand-alone
-application or through a Web page. This book takes you through the
-whole process, from installation and configuration to programming
-interfaces and basic administration. Includes plenty of tutorial
-material.
-@*
-
-@emph{Sams' Teach Yourself MySQL in 21 Days}
-@multitable @columnfractions .3 .7
-@item Available @tab @uref{http://service.bfast.com/bfast/click?bfmid=2181&sourceid=34233559&bfpid=0672319144&bfmtype=book, Barnes and Noble}
-@item Publisher @tab Sams
-@item Authors @tab Mark Maslakowski and Tony Butcher
-@item Pub Date @tab June 2000
-@item ISBN @tab 0672319144
-@item Pages @tab 650
-@item Price @tab $39.99
-@end multitable
-
-Sams' @emph{Teach Yourself MySQL in 21 Days} is for intermediate Linux users
-who want to move into databases. A large share of the audience is Web
-developers who need a database to store large amounts of information that
-can be retrieved via the Web.
-
-Sams' @emph{Teach Yourself MySQL in 21 Days} is a practical, step-by-step
-tutorial. The reader will learn to design and employ this open source
-database technology into his or her Web site using practical, hands-on
-examples to follow.
-@*
-
-@emph{E-Commerce Solutions with MySQL}
-@multitable @columnfractions .3 .7
-@item Available @tab @uref{http://service.bfast.com/bfast/click?bfmid=2181&sourceid=34233559&bfpid=0761524452&bfmtype=book, Barnes and Noble}
-@item Publisher @tab Prima Communications, Inc.
-@item Authors @tab N/A
-@item Pub Date @tab January 2000
-@item ISBN @tab 0761524452
-@item Pages @tab 500
-@item Price @tab $39.99
-@end multitable
-
-No description available.
-@*
-@emph{MySQL and PHP from Scratch}
-@multitable @columnfractions .3 .7
-@item Available @tab @uref{http://service.bfast.com/bfast/click?bfmid=2181&sourceid=34233559&bfpid=0789724405&bfmtype=book, Barnes and Noble}
-@item Publisher @tab Que
-@item Authors @tab N/A
-@item Pub Date @tab September 2000
-@item ISBN @tab 0789724405
-@item Pages @tab 550
-@item Price @tab $34.99
-@end multitable
-
-This book puts together information on installing, setting up, and
-troubleshooting Apache, MySQL, PHP3, and IMP into one complete
-volume. You also learn how each piece is part of a whole by learning,
-step-by-step, how to create a web-based e-mail system. Learn to run
-the equivalent of Active Server Pages (ASP) using PHP3, set up an
-e-commerce site using a database and the Apache web server, and create
-a data entry system (such as sales, product quality tracking, customer
-preferences, etc) that no installation in the PC.
-@*
-
-@emph{Professional MySQL Programming}
-@multitable @columnfractions .3 .7
-@item Available @tab @uref{http://shop.barnesandnoble.com/bookSearch/isbnInquiry.asp?isbn=1861005164, Barnes and Noble}
-@item Publisher @tab Wrox Press, Inc.
-@item Authors @tab N/A
-@item Pub Date @tab Late 2001
-@item ISBN @tab 1861005164
-@item Pages @tab 1000
-@item Price @tab $49.99
-@end multitable
-
-No description available.
-@*
-
-@emph{Professional Linux Programming}
-@multitable @columnfractions .3 .7
-@item Available @tab @uref{http://service.bfast.com/bfast/click?bfmid=2181&sourceid=34233559&bfpid=1861003013&bfmtype=book, Barnes and Noble}
-@item Publisher @tab Wrox Press, Inc.
-@item Authors @tab N/A
-@item Pub Date @tab September 2000
-@item ISBN @tab 1861003013
-@item Pages @tab 1155
-@item Price @tab $47.99
-@end multitable
-
-In this follow-up to the best-selling @emph{Beginning Linux Programming},
-you will learn from the authors' real-world knowledge and experience of
-developing software for Linux; you'll be taken through the development
-of a sample 'DVD Store' application, with 'theme' chapters addressing
-different aspects of its implementation. Meanwhile, individual
-``take-a-break'' chapters cover important topics that go beyond the
-bounds of the central theme. All focus on the practical aspects of
-programming, showing how crucial it is to choose the right tools for
-the job, use them as they should be used, and get things right first
-time.
-@*
-
-@emph{PHP and MySQL Web Development}
-@multitable @columnfractions .3 .7
-@item Available @tab @uref{http://service.bfast.com/bfast/click?bfmid=2181&sourceid=34233559&bfpid=0672317842&bfmtype=book, Barnes and Noble}
-@item Publisher @tab Sams
-@item Authors @tab Luke Welling, Laura Thomson
-@item Pub Date @tab March 2001
-@item ISBN @tab 0672317842
-@item Pages @tab 700
-@item Price @tab $49.99
-@end multitable
-
-@emph{PHP and MySQL Web Development} introduces you to the advantages
-of implementing both MySQL and PHP. These advantages are detailed
-through the provision of both statistics and several case studies. A
-practical web application is developed throughout the book, providing
-you with the tools necessary to implement a functional online
-database. Each function is developed separately, allowing you the
-choice to incorporate only those parts that you would like to
-implement. Programming concepts of the PHP language are highlighted,
-including functions which tie MySQL support into a PHP script and
-advanced topics regarding table manipulation.
-@*
-
-@strong{Books recommended by the MySQL Developers}
-
-@emph{SQL-99 Complete, Really}
-@multitable @columnfractions .3 .7
-@item Available @tab @uref{http://service.bfast.com/bfast/click?bfmid=2181&sourceid=34233559&bfpid=0879305681&bfmtype=book, Barnes and Noble}
-@item Publisher @tab CMP Books
-@item Authors @tab Peter Gulutzan, Trudy Pelzer
-@item Pub Date @tab April 1999
-@item ISBN @tab 0879305681
-@item Pages @tab 1104
-@item Price @tab $55.96
-@end multitable
-
-This book contains complete descriptions of the new standards for
-syntax, data structures, and retrieval processes of SQL databases. As
-an example-based reference manual, it includes all of the CLI
-functions, information, schema tables, and status codes, as well as a
-working SQL database provided on the companion disk.
-@*
+The @code{MySQL} web site (@uref{http://www.mysql.com/})
+provides the latest information about @code{MySQL} and @code{MySQL AB}.
-@emph{C, A reference manual}
-@multitable @columnfractions .3 .7
-@item Available @tab @uref{http://service.bfast.com/bfast/click?bfmid=2181&sourceid=34233559&bfpid=0133262243&bfmtype=book, Barnes and Noble}
-@item Publisher @tab Prentice Hall
-@item Authors @tab Samuel P. Harbison, Guy L. Steele
-@item Pub Date @tab September 1994
-@item ISBN @tab 0133262243
-@item Pages @tab 480
-@item Price @tab $35.99
-@end multitable
-A new and improved revision of the bestselling C language
-reference. This manual introduces the notion of "Clean C", writing C
-code that can be compiled as a C++ program, C programming style that
-emphasizes correctness, portability, maintainability, and
-incorporates the ISO C Amendment 1 (1994) which specifies new
-facilities for writing portable, international programs in C.
-@*
+@node MySQL AB business model and services, Contact information, What is MySQL AB, What is MySQL AB
+@subsection The Business Model and Services of MySQL AB
-@emph{C++ for Real Programmers}
-@multitable @columnfractions .3 .7
-@item Available @tab @uref{http://service.bfast.com/bfast/click?bfmid=2181&sourceid=34233559&bfpid=0120499428&bfmtype=book, Barnes and Noble}
-@item Publisher @tab Academic Press, Incorporated
-@item Authors @tab Jeff Alger, Jim Keogh
-@item Pub Date @tab February 1998
-@item ISBN @tab 0120499428
-@item Pages @tab 388
-@item Price @tab $39.95
-@end multitable
+One of the most common questions we encounter is:
+``@emph{How can you make a living from something you give away for free?}''
+This is how.
-@emph{C++ For Real Programmers} bridges the gap between C++ as described
-in beginner and intermediate-level books and C++ as it is practiced by
-experts. Numerous valuable techniques are described, organized into
-three simple themes: indirection, class hierarchies, and memory
-management. It also provides in-depth coverage of template creation,
-exception handling, pointers and optimization techniques. The focus of
-the book is on ANSI C++ and, as such, is compiler independent.
-
-@emph{C++ For Real Programmers} is a revision of
-@emph{Secrets of the C++ Masters} and includes a new appendix comparing C++
-with Java. The book comes with a 3.5" disk for Windows with source code.
-@*
+@code{MySQL AB} makes money on support, services, commercial licenses
+and royalties, and we use these revenues to fund product development
+and to expand the @code{MySQL} business.
-@emph{Algorithms in C}
-@multitable @columnfractions .3 .7
-@item Available @tab @uref{http://service.bfast.com/bfast/click?bfmid=2181&sourceid=34233559&bfpid=0201514257&bfmtype=book, Barnes and Noble}
-@item Publisher @tab Addison Wesley Longman, Inc.
-@item Authors @tab Robert Sedgewick
-@item Pub Date @tab April 1990
-@item ISBN @tab 0201514257
-@item Pages @tab 648
-@item Price @tab $45.75
-@end multitable
-
-@emph{Algorithms in C} describes a variety of algorithms in a number of
-areas of interest, including: sorting, searching, string-processing, and
-geometric, graph and mathematical algorithms. The book emphasizes
-fundamental techniques, providing readers with the tools to confidently
-implement, run, and debug useful algorithms.
-@*
-
-@emph{Multithreaded Programming with Pthreads}
-@multitable @columnfractions .3 .7
-@item Available @tab @uref{http://service.bfast.com/bfast/click?bfmid=2181&sourceid=34233559&bfpid=0136807291&bfmtype=book, Barnes and Noble}
-@item Publisher @tab Prentice Hall
-@item Authors @tab Bil Lewis, Daniel J. Berg
-@item Pub Date @tab October 1997
-@item ISBN @tab 0136807291
-@item Pages @tab 432
-@item Price @tab $34.95
-@end multitable
+@menu
+* Business Services Support:: Support
+* Business Services Training:: Training and Certification
+* Business Services Consulting:: Consulting
+* Business Services Commercial licenses:: Commercial Licenses
+* Business Services Partnering:: Partnering
+* Business Services Advertising:: Advertising
+@end menu
-Based on the best-selling @emph{Threads Primer},
-@emph{Multithreaded Programming with Pthreads} gives you a solid
-understanding of Posix threads: what they are, how they work, when to use
-them, and how to optimize them. It retains the clarity and humor of
-@emph{Threads Primer}, but includes expanded comparisons to Win32 and OS/2
-implementations. Code examples tested on all of the major UNIX platforms
-are featured along with detailed explanations of how and why they use threads.
-@*
+The company has been profitable since its inception. In October 2001,
+we accepted venture financing from leading Scandinavian investors and
+a handful of business angels. This investment is used to solidify our
+business model and build a basis for sustainable growth.
-@emph{Programming the PERL DBI: Database Programming with PERL}
-@multitable @columnfractions .3 .7
-@item Available @tab @uref{http://service.bfast.com/bfast/click?bfmid=2181&sourceid=34233559&bfpid=1565926994&bfmtype=book, Barnes and Noble}
-@item Publisher @tab O'Reilly & Associates, Incorporated
-@item Authors @tab Alligator Descartes, Tim Bunce
-@item Pub Date @tab February 2000
-@item ISBN @tab 1565926994
-@item Pages @tab 400
-@item Price @tab $27.96
-@end multitable
-@emph{Programming the Perl DBI} is coauthored by Alligator Descartes, one
-of the most active members of the DBI community, and by Tim Bunce, the
-inventor of DBI. For the uninitiated, the book explains the architecture
-of DBI and shows you how to write DBI-based programs. For the experienced
-DBI dabbler, this book explains DBI's nuances and the peculiarities of each
-individual DBD.
+@node Business Services Support, Business Services Training, MySQL AB business model and services, MySQL AB business model and services
+@subsubsection Support
+@code{MySQL AB} is run and owned by the founders and main developers of
+the @code{MySQL} database. The developers are committed to giving support
+to customers and other users in order to stay in touch with their needs
+and problems. All our support is given by qualified developers. Really
+tricky questions are answered by Michael @code{Monty} Widenius, principal
+author of the @code{MySQL Server}.
+@xref{Support}.
-The book includes:
-@itemize @bullet
-@item
-An introduction to DBI and its design.
-@item
-How to construct queries and bind parameters.
-@item
-Working with database, driver, and statement handles.
-@item
-Debugging techniques.
-@item
-Coverage of each existing DBD.
-@item
-A complete reference to DBI.
-@end itemize
-@*
+To order support at various levels, please visit the order section at
+@uref{https://order.mysql.com/} or contact our sales staff at
+@email{sales@@mysql.com}.
-@node General-SQL, Useful Links, MySQL-Books, MySQL Information Sources
-@subsection General SQL Information and Tutorials
+@node Business Services Training, Business Services Consulting, Business Services Support, MySQL AB business model and services
+@subsubsection Training and Certification
+@cindex training
+@cindex MySQL training
+@cindex certification
+@cindex MySQL certification
+@code{MySQL AB} delivers @code{MySQL} and related training worldwide.
+We offer both open courses and In-House courses tailored to the
+specific needs of your company. @code{MySQL Training} is also available
+through our partners, the @code{Authorised MySQL Training Centers}.
+
+Our training material uses the same example databases as our
+documentation and our sample applications, and it is always updated
+to reflect the latest @code{MySQL} version. Our trainers are backed by
+the development team to guarantee the quality of the training and the
+continuous development of the course material. This also ensures
+that no questions raised during the courses remain unanswered.
+
+Attending our training courses will enable you to achieve your goals
+related to your @code{MySQL} applications. You will also:
+@itemize @bullet
+@item
+Save time.
+@item
+Improve the performance of your application(s).
+@item
+Reduce or eliminate the need for additional hardware, decreasing cost.
+@item
+Enhance security.
+@item
+Increase customers and co-workers satisfaction.
+@item
+Prepare yourself for @code{MySQL Certification}.
+@end itemize
+
+If you are interested in our training as a potential participant or
+as a training partner, please visit the training section at
+@uref{http://www.mysql.com/training/} or contact us at:
+@email{training@@mysql.com}.
+
+We plan to release the @code{MySQL Certification Program} in 2002, for
+details see @uref{http://www.mysql.com/training/certification.html}.
+If you would like to be kept informed about the
+@code{MySQL Certification Program},
+please e-mail @email{certification@@mysql.com}.
+
+
+@node Business Services Consulting, Business Services Commercial licenses, Business Services Training, MySQL AB business model and services
+@subsubsection Consulting
+@cindex consulting
+@cindex MySQL consulting
+@code{MySQL AB} and its @code{Authorised Partners} offer consulting
+services to users of @code{MySQL Server} and to those who embed
+@code{MySQL Server} in their own software, all over the world.
+
+Our consultants can help you design and tune your databases, construct
+efficient queries, tune your platform for optimal performance, resolve
+migration issues, set up replication, build robust transactional
+applications, and more.
+We also help customers embed @code{MySQL Server} in their products and
+applications for large-scale deployment.
+
+Our consultants work in close collaboration with our development team
+which ensures the technical quality of our professional services.
+Consulting assignments range from 2-day power start sessions to
+projects that span weeks and months. Our expertise does not only cover
+@code{MySQL Server}, but extends into programming and scripting
+languages such as PHP, Perl and more.
+
+If you are interested in our consulting services or want to become a
+consulting partner, please visit the consulting section of our web site
+at @uref{http://www.mysql.com/consulting/} or contact our consulting
+staff at @email{consulting@@mysql.com}.
+
+
+@node Business Services Commercial licenses, Business Services Partnering, Business Services Consulting, MySQL AB business model and services
+@subsubsection Commercial Licenses
+The @code{MySQL} database is released under the
+@code{GNU General Public License} (@code{GPL}).
+This means that the @code{MySQL} software can be used free of charge
+under the @code{GPL}. If you do not want to be bound by the @code{GPL}
+terms (like the requirement that your own application becomes @code{GPL}
+as well), you may purchase a commercial license for the same product
+from @code{MySQL AB} at @uref{https://order.mysql.com/}.
+Since @code{MySQL AB} owns the copyright to the @code{MySQL} source code,
+we are able to employ @code{Dual Licensing} which means that the same
+product is available both under @code{GPL} and under a commercial
+license. This does not in any way affect the @code{Open Source}
+commitment of @code{MySQL AB}. For details about when a commercial
+license is required, please see @ref{MySQL server licenses}.
+
+We also sell commercial licenses of third-party @code{Open Source GPL}
+software that adds value to @code{MySQL Server}. A good example is the
+@code{InnoDB} transactional table handler that offers @code{ACID}
+support, row-level locking, crash recovery, multiversioning, foreign
+key support, and more. @xref{InnoDB}.
+
+
+@node Business Services Partnering, Business Services Advertising, Business Services Commercial licenses, MySQL AB business model and services
+@subsubsection Partnering
+@cindex partnering with MySQL AB
+@code{MySQL AB} has a worldwide partner programme that covers training
+courses, Consulting & Support, publications plus reselling and
+distributing @code{MySQL} and related products. @code{MySQL AB Partners}
+get visibility on the @uref{http://www.mysql.com/} web site and the right
+to use special versions of the @code{MySQL} trademarks to identify their
+products and promote their business.
+
+If you are interested in becoming a @code{MySQL AB Partner}, please e-mail
+to @email{partner@@mysql.com}.
+
+The word @code{MySQL} and the @code{MySQL} dolphin logo are trademarks of
+@code{MySQL AB}. @xref{MySQL AB Logos and Trademarks}.
+These trademarks represent a significant value that the @code{MySQL}
+founders have built over the years.
+
+
+@node Business Services Advertising, , Business Services Partnering, MySQL AB business model and services
+@subsubsection Advertising
+The @code{MySQL} web site (@uref{http://www.mysql.com/}) is popular among
+developers and users. In October 2001, we served 10 million page views.
+Our visitors represent a group that makes purchase decisions and
+recommendations for both software and hardware. Twelve per cent of our
+visitors authorise purchase decisions, and only nine per cent are not
+involved in purchase decisions at all. More than 65% have made one or
+more online business purchase within the last half-year, and 70% plan
+to make one in the next months.
+
+If you are interested in placing banner ads on our web site
+@uref{http://www.mysql.com/}, please send an email to
+@email{advertising@@mysql.com}.
+
+
+@node Contact information, , MySQL AB business model and services, What is MySQL AB
+@subsection Contact Information
-The following book has been recommended by several people on the MySQL
-mailing list:
+@cindex contact information
+@cindex employment, contact information
+@cindex licensing, contact information
+@cindex advertising, contact information
+@cindex employment with MySQL
+@cindex jobs at MySQL
-@example
-Judith S. Bowman, Sandra L. Emerson and Marcy Darnovsky
-@emph{The Practical SQL Handbook: Using Structured Query Language}
-Second Edition
-Addison-Wesley
-ISBN 0-201-62623-3
-http://www.awl.com
-@end example
+The @code{MySQL} web site (@uref{http://www.mysql.com/})
+provides the latest information about @code{MySQL} and @code{MySQL AB}.
-The following book has also received some recommendations by MySQL
-users:
-
-@example
-Martin Gruber
-@emph{Understanding SQL}
-ISBN 0-89588-644-8
-Publisher Sybex 510 523 8233
-Alameda, CA USA
-@end example
-
-A SQL tutorial is available on the net at
-http://w3.one.net/~jhoffman/sqltut.htm
+For press service and inquiries not covered in our News releases
+(@uref{http://www.mysql.com/news/}), please e-mail to
+@email{press@@mysql.com}.
+If you have a valid support contract with @code{MySQL AB}; you will
+get timely, precise answers to your technical questions about the
+@code{MySQL} software. For more information, see @ref{Support}.
+You can order your support contract at
+@uref{https://order.mysql.com/}, or send an email to
+@email{sales@@mysql.com}.
-@node Useful Links, Questions, General-SQL, MySQL Information Sources
-@subsection Useful MySQL-related Links
+For information about @code{MySQL} training, please visit the training
+section at @uref{http://www.mysql.com/training/}. If you have
+restricted access to the Internet, please contact the @code{MySQL AB}
+training staff at @email{training@@mysql.com}.
+@xref{Business Services Training}.
+
+For information on the @code{MySQL Certification Program}, please see
+@uref{http://www.mysql.com/training/certification.html}.
+If you would like to be kept informed about the
+@code{MySQL Certification Program}, please e-mail
+@email{certification@@mysql.com}.
+@xref{Business Services Training}.
+
+If you're interested in consulting, please visit the consulting
+section at @uref{http://www.mysql.com/consulting/}. If you have
+restricted access to the Internet, please contact the @code{MySQL AB}
+consulting staff at @email{consulting@@mysql.com}.
+@xref{Business Services Consulting}.
+
+Commercial licenses may be purchased online at
+@uref{https://order.mysql.com/}. There you will also find information
+on how to fax your purchase order to @code{MySQL AB}. If you have
+questions regarding licensing or you want a quote for a high-volume
+license deal, please fill in the contact form on our web site
+(@uref{http://www.mysql.com/}) or send an email
+to @email{licensing@@mysql.com} (for licensing questions) or to
+@email{sales@@mysql.com} (for sales inquiries).
+@xref{MySQL server licenses}.
-Apart from the following links, you can find and download a lot of
-MySQL programs, tools and APIs from the
-@uref{http://www.mysql.com/Downloads/Contrib/, Contrib directory}.
-@cindex @code{Contrib} directory
+If you represent a business that is interested in partnering with
+@code{MySQL AB}, please send e-mail to @email{partner@@mysql.com}.
+@xref{Business Services Partnering}.
+
+If you are interested in placing a banner advertisement on the
+@code{MySQL} web site (@uref{http://www.mysql.com/}), please send
+e-mail to @email{advertising@@mysql.com}.
+@xref{Business Services Advertising}.
+
+For more information on the @code{MySQL} trademark policy, refer to
+@uref{http://www.mysql.com/company/trademark.html} or email
+@email{trademark@@mysql.com}.
+@xref{MySQL AB Logos and Trademarks}.
+
+If you are interested in any of the @code{MySQL AB} jobs listed in our
+jobs section (@uref{http://www.mysql.com/development/jobs/}),
+please send an e-mail to @email{jobs@@mysql.com}.
+Please do not send your CV as an attachment, but rather as plain text
+at the end of your email.
+
+For general discussion amongst our many users, please direct your
+attention to the appropriate mailing list.
+@xref{Questions}.
+
+Reports of errors (often called bugs), as well as questions and
+comments, should be sent to the mailing list at
+@email{mysql@@lists.mysql.com}. If you have found a sensitive
+security bug in the @code{MySQL Server}, you should send an e-mail
+to @email{security@@mysql.com}.
+@xref{Bug reports}.
-@cindex URLs to MySQL information
-@cindex related information URLs
-MySQL
-@subheading Tutorials and Manuals
+If you have benchmark results that we can publish, please
+contact us at @email{benchmarks@@mysql.com}.
-@table @asis
-@item @uref{http://michael.bacarella.com/research/mysqlmyths.html, MySQL Myths Debunked}
-MySQL used in the real world.
+If you have any suggestions concerning additions or corrections to this
+manual, please send them to the manual team at @email{docs@@mysql.com}.
-@item @uref{http://www.4t2.com/mysql}
-Information about the German MySQL mailing list.
+For questions or comments about the workings or content of the
+@code{MySQL} web site (@uref{http://www.mysql.com/}),
+please send e-mail to @email{webmaster@@mysql.com}.
-@item @uref{http://www2.rent-a-database.de/mysql/}
-MySQL handbook in German.
+Questions about the @code{MySQL Portals}
+(@uref{http://www.mysql.com/portal/})
+may be sent to @email{portals@@mysql.com}.
-@item @uref{http://www.bitmover.com:8888//home/bk/mysql}
-Web access to the MySQL BitKeeper repository.
+@code{MySQL AB} has a privacy policy, which can be read at
+@uref{http://www.mysql.com/company/privacy.html}.
+For any queries regarding this policy, please e-mail
+@email{privacy@@mysql.com}.
-@item @uref{http://www.analysisandsolutions.com/code/mybasic.htm}
-Beginners MySQL Tutorial on how to install and set up
-MySQL on a Windows machine.
+For all other inquires, please send e-mail to @email{info@@mysql.com}.
-@item @uref{http://www.devshed.com/Server_Side/MySQL/}
-A lot of MySQL tutorials.
-@item @uref{http://mysql.hitstar.com/}
-MySQL manual in Chinese.
+@node Licensing and Support, MySQL 4.0 In A Nutshell, What is MySQL AB, Introduction
+@section MySQL Support and Licensing
-@item @uref{http://www.linuxplanet.com/linuxplanet/tutorials/1046/1/}
-Setting Up a MySQL-based Web site.
+@cindex licensing terms
+@cindex support terms
-@item @uref{http://www.hotwired.com/webmonkey/backend/tutorials/tutorial1.html}
-MySQL-Perl tutorial.
+This section describes @code{MySQL} support and licensing arrangements:
-@item @uref{http://www.iserver.com/support/contrib/perl5/modules.html}
-Installing new Perl modules that require locally installed modules.
+@menu
+* Support:: Support Offered by MySQL AB
+* Copyright:: Copyrights and Licenses Used by MySQL
+* MySQL server licenses:: MySQL Server Licenses
+* MySQL AB Logos and Trademarks:: MySQL AB Logos and Trademarks
+@end menu
-@item @uref{http://www.hotwired.com/webmonkey/databases/tutorials/tutorial4.html}
-PHP/MySQL Tutorial.
-@item @uref{http://www.useractive.com/}
-Hands on tutorial for MySQL.
-@end table
+@node Support, Copyright, Licensing and Support, Licensing and Support
+@subsection Support Offered by MySQL AB
-@subheading Porting MySQL/Using MySQL on Different Systems
+@cindex support, types
+@cindex types of support
+@cindex commercial support, types
+@cindex costs, support
+@cindex licensing costs
+@cindex support costs
+@cindex prices, support
+
+Technical support from @code{MySQL AB} means individualised answers
+to your unique problems direct from the software engineers who code
+the @code{MySQL} database engine.
+
+We try to take a broad and inclusive view of technical support. Almost
+any problem involving @code{MySQL} software is important to us if it's
+important to you.
+Typically customers seek help on how to get different commands and
+utilities to work, remove performance bottlenecks, restore crashed
+systems, understand operating system or networking impacts on @code{MySQL},
+set-up best practices for backup and recovery, utilise @code{API}s, etc.
+Our support covers only the @code{MySQL} server and our own utilities,
+not third-party products that access the @code{MySQL} server, though we
+try to help with these where we can.
+
+Detailed information about our various support options is given at
+@uref{https://order.mysql.com/} where support contracts can also be
+ordered online. If you have restricted access to the Internet, contact
+our sales staff at @email{sales@@mysql.com}.
+
+Technical support is like life insurance. You can live happily
+without it for years, but when your hour arrives it becomes
+critically important, yet it's too late to buy it!
+If you use @code{MySQL} Server for important applications and encounter
+sudden troubles, it might take too long to figure out all the answers
+yourself. You may need immediate access to the most experienced
+@code{MySQL} troubleshooters available, those employed by @code{MySQL AB}.
+
+
+@node Copyright, MySQL server licenses, Support, Licensing and Support
+@subsection Copyrights and Licenses Used by MySQL
-@table @asis
-@item @uref{http://www.entropy.ch/software/macosx/mysql/}
-Binary of MySQL for Mac OS X Client. Includes information of how to
-build and use MySQL on Mac OS X.
+@cindex copyrights
+@cindex licenses
-@item @uref{http://xclave.macnn.com/MySQL/}
-The Mac OS Xclave. Running MySQL on Mac OS X.
+@code{MySQL AB} owns the copyright to the @code{MySQL} source code,
+the @code{MySQL} logos and trademarks and this manual.
+@xref{What is MySQL AB}.
+There are several different licenses relevant to the @code{MySQL}
+distribution:
-@item @uref{http://www.prnet.de/RegEx/mysql.html}
-MySQL for Mac OS X Server.
+@enumerate
+@item
+The @code{MySQL}-specific source needed to build the @code{mysqlclient}
+library is licensed under the @code{LGPL} and the programs in the
+@file{client} directory are under the @code{GPL}. Each file states
+at the beginning which license it is under.
-@item @uref{http://www.latencyzero.com/macosx/mysql.html}
-Building MySQL for Mac OS X.
+@item
+The client library, and the @code{GNU} @code{getopt} library, are covered
+by the ``GNU LESSER GENERAL PUBLIC LICENSE.'' @xref{LGPL license}.
+The aim of this is to make it possible to add MySQL support (client
+side, i.e. the ability to connect to a @code{MySQL} server) into
+commercial products without a license.
-@item @uref{http://www.essencesw.com/Software/mysqllib.html}
-New Client libraries for the Mac OS Classic (Macintosh).
+@item
+All the source in the server, and the @code{GNU} @code{readline} library,
+are covered by the ``GNU GENERAL PUBLIC LICENSE.'' @xref{GPL license}.
+The text of this license can also be found as the file @file{COPYING}
+in the distributions.
-@item @uref{http://www.lilback.com/macsql/}
-Client libraries for Mac OS Classic (Macintosh).
+@item
+Some parts of the source (the @code{regexp} library) are covered
+by a Berkeley-style copyright.
-@item @uref{http://sixk.maniasys.com/index_en.html}
-MySQL for Amiga
-@end table
+@item
+Older versions of @code{MySQL} (3.22 and earlier) are subject to a
+more strict license
+(@uref{http://www.mysql.com/support/arrangements/mypl.html}).
+See the documentation of the specific version for information.
-@subheading Perl-related Links
+@item
+The manual is @emph{not} distributed under a @code{GPL} style license.
+Use of the manual is subject to the following terms:
+@itemize @bullet
+@item
+Conversion to other formats is allowed, but the actual content
+may not be altered or edited in any way.
+@item
+You may create a printed copy for your own personal use.
+@item
+For all other uses, such as selling printed copies or using
+(parts of) the manual in another publication, prior written
+agreement from @code{MySQL AB} is required.
+@end itemize
+Please e-mail @email{docs@@mysql.com} for more information or
+if you are interested in doing a translation.
+@end enumerate
-@table @asis
-@item @uref{http://dbimysql.photoflux.com/}
-Perl DBI with MySQL FAQ.
-@end table
+For information about how the @code{MySQL} licenses work in practice,
+please refer to @ref{MySQL server licenses}.
+Also see @ref{MySQL AB Logos and Trademarks}.
-@subheading MySQL Discussion Forums
-@table @asis
-@item @uref{http://www.weberdev.com/}
-Examples using MySQL; (check Top 20)
+@node MySQL server licenses, MySQL AB Logos and Trademarks, Copyright, Licensing and Support
+@subsection MySQL Server Licenses
-@item @uref{http://futurerealm.com/forum/futureforum.htm}
-FutureForum Web Discussion Software.
-@end table
+@cindex licensing policy
+@cindex technical support, licensing
+@cindex support, licensing
+@cindex General Public License, MySQL
+@cindex GPL, MySQL
+@cindex licensing, examples
+@cindex selling products
+@cindex products, selling
-@c FIX We should get longer descriptions for things in this category!
-@subheading Commercial Applications that Support MySQL
+The @code{MySQL} server is released under the
+@code{GNU General Public License} (@code{GPL}),
+which probably is the best known @code{Open Source} license.
+The formal terms of the @code{GPL} license can be found at
+@uref{http://www.gnu.org/licenses/}.
+See also @uref{http://www.gnu.org/licenses/gpl-faq.html}.
-@table @asis
-@item @uref{http://www.supportwizard.com/}
-SupportWizard; Interactive helpdesk on the Web (This product includes a
-licensed copy of MySQL.)
-
-@item @uref{http://www.sonork.com/}
-Sonork, Instant Messenger that is not only Internet oriented. It's
-focused on private networks and on small to medium companies. Client
-is free, server is free for up to 5 seats.
-
-@item @uref{http://www.stweb.org/}
-StWeb - Stratos Web and Application server - An easy-to-use, cross
-platform, Internet/Intranet development and deployment system for
-development of web-enabled applications. The standard version of StWeb
-has a native interface to MySQL database.
-
-@item @uref{http://www.rightnowtech.com/}
-Right Now Web; Web automation for customer service.
-
-@item @uref{http://www.icaap.org/Bazaar/}
-Bazaar; Interactive Discussion Forums with Web interface.
-
-@cindex PhoneSweep
-@item @uref{http://www.phonesweep.com/}
-PhoneSweepT is the world's first commercial Telephone Scanner. Many break-ins
-in recent years have come not through the Internet, but through unauthorized
-dial-up modems. PhoneSweep lets you find these modems by repeatedly placing
-phone calls to every phone number that your organization
-controls. PhoneSweep has a built-in expert system that can recognize
-more than 250 different kinds of remote-access programs, including
-Carbon Copy(TM), pcANYWHERE(TM), and Windows NT RAS. All information is stored
-in the SQL database. It then generates a comprehensive report detailing
-which services were discovered on which dial-up numbers in your organization.
-@end table
+Since the @code{MySQL} server is released under the @code{GPL},
+it may often be used for free, but for certain uses you may want
+or need to buy commercial licenses from @code{MySQL AB} at
+@uref{https://order.mysql.com/}.
-@subheading SQL Clients and Report Writers
+Older versions of @code{MySQL} (3.22 and earlier) are subject to a
+more strict license
+(@uref{http://www.mysql.com/support/arrangements/mypl.html}).
+See the documentation of the specific version for information.
-@table @asis
-@item @uref{http://www.urbanresearch.com/software/utils/urbsql/index.html, urSQL}
-SQL Editor and Query Utility. Custom syntax highlighting, editable
-results grid, exportable result-sets, basic MySQL admin functions,
-Etc.. For Windows.
+Please note that the use of the @code{MySQL} server under commercial
+license, @code{GPL} or the old @code{MySQL} license does not
+automatically give you the right to use @code{MySQL AB} trademarks.
+@xref{MySQL AB Logos and Trademarks}.
-@item @uref{http://www.edatanew.com/, MySQL Data Manager}
-MySQL Data Manager * is platform independent web client
-(written in perl) for MySQL server over TCP/IP.
-@item @uref{http://ksql.sourceforge.net/}
-KDE MySQL client.
+@menu
+* Using the MySQL server under a commercial license:: Using the MySQL Server Under a Commercial License
+* Using the MySQL server for free under GPL:: Using the MySQL Server for Free Under GPL
+@end menu
-@item @uref{http://www.ecker-software.de}
-A Windows GUI client by David Ecker.
+@node Using the MySQL server under a commercial license, Using the MySQL server for free under GPL, MySQL server licenses, MySQL server licenses
+@subsubsection Using the MySQL Server Under a Commercial License
-@item @uref{http://www.icaap.org/software/kiosk/}
-Kiosk; a MySQL client for database management. Written in Perl.
-Will be a part of Bazaar.
+The @code{GPL} license is contagious in the sense that when a program
+is linked to a @code{GPL} program the resulting product must also be
+released under @code{GPL} lest you break the license terms and forfeit
+your right to use the @code{GPL} program altogether.
-@item @uref{http://www.casestudio.com/}
-Db design tool that supports MySQL 3.23.
+You need a commercial license:
-@item @uref{http://home.skif.net/~voland/zeos/eng/index.html}
-Zeos - A client that supports MySQL, Interbase and PostgreSQL.
+@itemize @bullet
+@item
+When you link a program with code from the @code{MySQL} server or from
+@code{GPL} released clients and don't want the resulting product to be
+@code{GPL}, maybe because you want to build a commercial product or keep
+the added non-@code{GPL} code closed source for other reasons. When
+purchasing commercial licenses, you are not using the @code{MySQL} server
+under @code{GPL} even though it's the same code.
-@item @uref{http://www.geocities.com/SiliconValley/Ridge/4280/GenericReportWriter/grwhome.html}
-A free report writer in Java
+@item
+When you distribute a non-@code{GPL} application that ONLY works with the
+@code{MySQL} server and ship it with the @code{MySQL} server. This type
+of solution is actually considered to be linking even if it's done over
+a network.
-@item @uref{http://www.javaframework.de}
-MySQLExport - Export of MySQL create statements and data in a lot of
-different formats (SQL, HTML, CVS, text, ZIP, GZIP...)
+@item
+When you distribute copies of the @code{MySQL} server without providing
+the source code as required under the @code{GPL} license.
-@item @uref{http://dlabs.4t2.com}
-M2D, a MySQL Administration client for Windows. M2D supports
-administration of MySQL databases, creation of new databases and
-tables, editing, and more.
+@item
+When you want to support the further development of the @code{MySQL}
+database even if you don't formally need a commercial license.
+Purchasing support directly from @code{MySQL AB} is another good way
+of contributing to the development of the @code{MySQL} software, with
+immediate advantages for you.
+@xref{Support}.
+@end itemize
-@item @uref{http://dlabs.4t2.com}
-Dexter, a small server written in Perl which can be used as a proxy server for
-MySQL or as a database extender.
+If you require a license, you will need one for each installation of the
+@code{MySQL} server. This covers any number of CPUs on a machine, and there
+is no artificial limit on the number of clients that connect to the server
+in any way.
-@item @uref{http://www.scibit.com/Products/Software/Utils/Mascon.asp}
-Mascon is a powerful Win32 GUI for administering MySQL databases.
+To purchase commercial licenses and support, please visit the order section
+of our web site at @uref{https://order.mysql.com/}. If you have restricted
+access to the Internet, please contact our sales staff at
+@email{sales@@mysql.com}.
-@item @uref{http://www.rtlabs.com/}
-MacSQL Monitor. GUI for MySQL, ODBC, and JDBC databases for the Mac OS.
-@end table
-@subheading Distributions that Include MySQL
+@node Using the MySQL server for free under GPL, , Using the MySQL server under a commercial license, MySQL server licenses
+@subsubsection Using the MySQL Server for Free Under GPL
-@c FIX add the rest (at least a couple more Linuxes)
+@cindex licensing, free
+@cindex free licensing
-@table @asis
-@item @uref{http://www.suse.com/}
-SuSE Linux (6.1 and above)
+You can use the @code{MySQL} server for free under the @code{GPL}:
-@item @uref{http://www.redhat.com/}
-RedHat Linux (7.0 and above)
+@itemize @bullet
+@item
+When you link a program with code from the @code{MYSQL} server and
+release the resulting product under @code{GPL}.
-@item @uref{http://distro.conectiva.com.br}
-Conectiva Linux (4.0 and above)
-@end table
+@item
+When you distribute the @code{MySQL} server source code bundled with
+other programs that are not linked to or dependant on @code{MySQL Server}
+for their functionality even if you sell the distribution commercially.
-@subheading Web Development Tools that Support MySQL
+@item
+When using the @code{MySQL} server internally in your company.
-@table @asis
-@item @uref{http://www.php.net/}
-PHP: A server-side HTML-embedded scripting language.
+@item
+When include the @code{MySQL} client code in a commercial program.
+The client part of the @code{MySQL} software is licensed under the
+@code{LGPL} (@code{GNU Lesser General Public License}).
+The formal terms of the @code{LGPL} license can be found at
+@uref{http://www.gnu.org/licenses/}.
-@item @uref{http://www.midgard-project.org}
-The Midgard Application Server; a powerful Web development environment
-based on MySQL and PHP.
+However, the @code{mysql} command-line client does include code
+from the @code{GNU} @code{readline} library that is under the @code{GPL}.
-@item @uref{http://www.smartworker.org}
-SmartWorker is a platform for Web application development.
+@item
+@cindex ISP services
+@cindex services, ISP
+@cindex services, web
+@cindex Internet Service Providers
+When you are an Internet Service Provider (ISPs) offering web
+hosting with @code{MySQL} servers for your customers.
+On the other hand, we do encourage people to use ISPs that have
+@code{MySQL} support, as this will give them the confidence that if
+they have some problem with the @code{MySQL} installation, their ISP
+will in fact have the resources to solve the problem for them.
-@item @uref{http://xsp.lentus.se/}
-XSP: e(X)tendible (S)erver (P)ages and is a HTML embedded tag language
-written in Java (previously known as XTAGS.)
+All ISPs that want to keep themselves up-to-date should subscribe
+to our @code{announce} mailing list so that they can be aware of
+critical issues that may be relevant for their @code{MySQL} installations.
-@cindex dbServ
-@item @uref{http://www.dbServ.de/}
-dbServ is an extension to a web server to integrate database output into
-your HTML code. You may use any HTML function in your output. Only the
-client will stop you. It works as standalone server or as Java servlet.
+Note that even if an ISP does not have a commercial license for
+@code{MySQL} Server, they should at least give their customers read
+access to the source of the @code{MySQL} installation so that the
+customers can verify that it is patched correctly.
-@item @uref{http://www.chilisoft.com/}
-Platform independent ASP from Chili!Soft
+@item
+@cindex web server, running
+@cindex running a web server
+When you use the @code{MySQL} Database Software in conjunction with
+a Web server, you do not need a commercial license. This is true even
+if you run a commercial Web server that uses @code{MySQL} Server, because
+you are not selling an embedded @code{MySQL} version yourself. However,
+in this case we would like you to purchase @code{MySQL} support, because
+the @code{MySQL} software is helping your enterprise.
+@end itemize
+
+If your use of @code{MySQL} database software does not require a commercial
+license, we encourage you to purchase support from @code{MySQL AB} anyway.
+This way you contribute towards @code{MySQL} development and also gain
+immediate advantages for yourself. @xref{Support}.
+
+If you use the @code{MySQL} database software in a commercial context
+such that you profit by its use, we ask that you further the development
+of the @code{MySQL} software by purchasing some level of support. We feel
+that if the @code{MySQL} database helps your business, it is reasonable to
+ask that you help @code{MySQL AB}.
+(Otherwise, if you ask us support questions, you are not only using
+for free something into which we've put a lot a work, you're asking
+us to provide free support, too.)
+
+
+@node MySQL AB Logos and Trademarks, , MySQL server licenses, Licensing and Support
+@subsection MySQL AB Logos and Trademarks
+
+@cindex logos
+@cindex trademarks
+
+Many users of the @code{MySQL} database want to display the
+@code{MySQL AB} dolphin logo on their web sites, on their books or
+boxed products. We welcome and encourage this although it should be
+noted that the word @code{MySQL} and the @code{MySQL} dolphin logo
+are trademarks of @code{MySQL AB} and may only be used as stated in
+our trademark policy at
+@uref{http://www.mysql.com/company/trademark.html}.
-@item @uref{http://www.voicenet.com/~zellert/tjFM}
-A JDBC driver for MySQL.
+@menu
+* The Original MySQL logo:: The Original MySQL Logo
+* MySQL Logos that may be Used Without Written Permission:: MySQL Logos that may be Used Without Written Permission
+* When need MySQL logo permission:: When do you need a Written Permission to use MySQL Logos?
+* MySQL AB Partnership Logos:: MySQL AB Partnership Logos
+* Using MySQL word in presentations:: Using the word @code{MySQL} in Printed Text or Presentations
+* Using MySQL word in company and product names:: Using the word @code{MySQL} in Company and Product Names
+@end menu
-@item @uref{http://www.wernhart.priv.at/php/}
-MySQL + PHP demos.
-@item @uref{http://www.dbwww.com/}
-ForwardSQL: HTML interface to manipulate MySQL databases.
+@node The Original MySQL logo, MySQL Logos that may be Used Without Written Permission, MySQL AB Logos and Trademarks, MySQL AB Logos and Trademarks
+@subsubsection The Original MySQL Logo
-@item @uref{http://www.daa.com.au/~james/www-sql/}
-WWW-SQL: Display database information.
+@c FIX: picture: MySQL logo
-@item @uref{http://www.minivend.com/minivend/}
-Minivend: A Web shopping cart.
+The @code{MySQL} dolphin logo was designed by the Finnish advertising
+agency Priority in 2001. The dolphin was chosen as a suitable symbol
+for the @code{MySQL} database since it is a smart, fast and lean animal,
+effortlessly navigating oceans of data. We also happen to like dolphins.
-@item @uref{http://www.heitml.com/}
-HeiTML: A server-side extension of HTML and a 4GL language at the same time.
+The original @code{MySQL} logo may only be used by representatives of
+@code{MySQL AB} and by those having a written agreement allowing them
+to do so.
-@item @uref{http://www.metahtml.com/}
-Metahtml: A Dynamic Programming Language for WWW Applications.
-@item @uref{http://www.binevolve.com/}
-VelocityGen for Perl and Tcl.
+@node MySQL Logos that may be Used Without Written Permission, When need MySQL logo permission, The Original MySQL logo, MySQL AB Logos and Trademarks
+@subsubsection MySQL Logos that may be Used Without Written Permission
-@item @uref{http://hawkeye.net/}
-Hawkeye Internet Server Suite.
+@c FIX: pictures: powered by, works with, included - logos
-@item @uref{http://www.fastflow.com/}
-Network Database Connection For Linux
+We have designed a set of special @emph{Conditional Use} logos that may be
+downloaded from our web site at
+@uref{http://www.mysql.com/downloads/logos.html}
+and used on third party web sites without written permission from
+@code{MySQL AB}.
+The use of these logos is not entirely unrestricted, but as the name
+implies subject to our trademark policy that is also available on our
+web site. You should read through the trademark policy if you plan to
+use them. The requirements are basically:
-@item @uref{http://www.wdbi.net/}
-WDBI: Web browser as a universal front end to databases which supports
-MySQL well.
+@itemize @bullet
+@item
+Use the logo you need as displayed on the @uref{http://www.mysql.com/}
+site. You may scale it to fit your needs, but not change colours or design,
+or alter the graphics in any way.
-@item @uref{http://www.webgroove.com/}
-WebGroove Script: HTML compiler and server-side scripting language.
+@item
+Make it evident that you, and not @code{MySQL AB}, are the creator and
+owner of the site that displays the @code{MySQL} trademark.
-@item @uref{http://www.ihtml.com/}
-A server-side Web site scripting language.
+@item
+Don't use the trademark in a way that is detrimental to @code{MySQL AB}
+or to the value of @code{MySQL AB} trademarks. We reserve the right to
+revoke the right to use the @code{MySQL AB} trademark.
-@item @uref{ftp://ftp.igc.apc.org/pub/myodbc/README}
-How to use MySQL with ColdFusion on Solaris.
+@item
+If you use the trademark on a web site, make it clickable, leading directly
+to @uref{http://www.mysql.com/}.
-@item @uref{http://calistra.com/MySQL/}
-Calistra's ODBC MySQL Administrator.
+@item
+If you are using the @code{MySQL} database under @code{GPL} in an
+application, your application must (i) be @code{Open Source},
+(ii) be able to connect to a @code{MySQL} server.
+@end itemize
-@cindex Webmerger
-@item @uref{http://www.webmerger.com}
-Webmerger - This CGI tool interprets files and generates dynamic output
-based on a set of simple tags. Ready-to-run drivers for MySQL and
-PostgreSQL through ODBC.
+Contact us at @email{trademark@@mysql.com} to inquire about special
+arrangements to fit your needs.
-@item @uref{http://phpclub.net/}
-PHPclub - Tips and tricks for PHP.
+@node When need MySQL logo permission, MySQL AB Partnership Logos, MySQL Logos that may be Used Without Written Permission, MySQL AB Logos and Trademarks
+@subsubsection When do you need a Written Permission to use MySQL Logos?
-@item @uref{http://www.penguinservices.com/scripts}
-MySQL and Perl Scripts.
+In the following cases you need a written permission from @code{MySQL AB}
+before using @code{MySQL} logos:
-@item @uref{http://www.widgetchuck.com}
-The Widgetchuck; Web Site Tools and Gadgets
+@itemize @bullet
+@item
+When displaying any @code{MySQL AB} logo anywhere except on your web site.
-@item @uref{http://www.adcycle.com/}
-AdCycle - advertising management software.
+@item
+When displaying any @code{MySQL AB} logo except the @emph{Conditional Use}
+logos above on web sites or elsewhere.
+@end itemize
-@cindex pwPage
-@item @uref{http://sourceforge.net/projects/pwpage/}
-pwPage - provides an extremely fast and simple approach to the creation
-of database forms. That is, if a database table exists and an HTML page
-has been constructed using a few simple guidelines, pwPage can be
-immediately used for table data selections, insertions, updates, deletions
-and selectable table content reviewing.
+Out of legal and commercial reasons we have to monitor the use of MySQL
+trademarks on products, books etc. We will usually require a fee for
+displaying @code{MySQL AB} logos on commercial products, since we think
+it is reasonable that some of the revenue is returned to fund further
+development of the @code{MySQL} database.
-@item @uref{http://www.omnis-software.com/products/studio/studio.html}
-OMNIS Studio is a rapid application development (RAD) tool.
-@cindex Web+
-@item @uref{http://www.webplus.com}
-talentsoft Web+ 4.6 - a powerful and comprehensive development language for
-use in creating web-based client/server applications without writing
-complicated, low-level, and time-consuming CGI programs.
-@end table
+@node MySQL AB Partnership Logos, Using MySQL word in presentations, When need MySQL logo permission, MySQL AB Logos and Trademarks
+@subsubsection MySQL AB Partnership Logos
-@subheading Database Design Tools with MySQL Support
+@c FIX: pictures: partnership logos - Bertrand?
-@table @asis
-@item @uref{http://www.mysql.com/documentation/dezign/}
-"DeZign for databases" is a database development tool that uses an
-entity relationship diagram (ERD).
-@end table
+@code{MySQL} partnership logos may only be used by companies and persons
+having a written partnership agreement with @code{MySQL AB}. Partnerships
+include certification as a @code{MySQL} trainer or consultant.
+Please see @ref{Business Services Partnering,,Partnering}.
-@subheading Web Servers with MySQL Tools
-@table @asis
-@item @uref{ftp://ftp.kcilink.com/pub/}
-mod_auth_mysql, An Apache authentication module.
+@node Using MySQL word in presentations, Using MySQL word in company and product names, MySQL AB Partnership Logos, MySQL AB Logos and Trademarks
+@subsubsection Using the word @code{MySQL} in Printed Text or Presentations
-@item @uref{http://www.roxen.com/}
-The Roxen Challenger Web server.
-@end table
+@code{MySQL AB} welcomes references to the @code{MySQL} database, but
+note that the word @code{MySQL} is a trademark of @code{MySQL AB}.
+Because of this, you should append the trademark symbol @code{TM} to
+the first or most prominent use of the word @code{MySQL} in a text and
+where appropriate use a statement that @code{MySQL} is a trademark of
+@code{MySQL AB}. Please refer to our trademark policy at
+@uref{http://www.mysql.com/company/trademark.html} for details.
-@subheading Extensions for Other Programs
-@table @asis
-@item @uref{http://www.seawood.org/msql_bind/}
-MySQL support for BIND (The Internet Domain Name Server).
+@node Using MySQL word in company and product names, , Using MySQL word in presentations, MySQL AB Logos and Trademarks
+@subsubsection Using the word @code{MySQL} in Company and Product Names
-@item @uref{http://www.inet-interactive.com/sendmail/}
-MySQL support for Sendmail and Procmail.
-@end table
+Use of the word @code{MySQL} in product or company names or in Internet
+domain names is not allowed without written permission from @code{MySQL AB}.
-@subheading Using MySQL with Other Programs
-@table @asis
-@item @uref{http://www.iserver.com/support/addonhelp/database/mysql/msaccess.html}
-Using MySQL with Access.
+@node MySQL 4.0 In A Nutshell, MySQL Information Sources, Licensing and Support, Introduction
+@section MySQL 4.0 In A Nutshell
-@item @uref{http://www.iserver.com/support/contrib/perl5/modules.html}
-Installing new Perl modules that require locally installed modules.
-@end table
+Dateline: 16 October 2001, Uppsala, Sweden
-@subheading ODBC-related Links
+Long promised by @code{MySQL AB} and long awaited by our users,
+MySQL Server 4.0 is now available in alpha version for download from
+@uref{http://www.mysql.com/} and our mirrors.
-@table @asis
-@item @uref{http://www.iodbc.org/}
-Popular iODBC Driver Manager (libiodbc) now available as Open Source.
+Main new features of MySQL Server 4.0 are geared towards our existing
+business and community users, enhancing the MySQL database software
+as the solution for mission-critical, heavy load database systems.
+Other new features target the users of embedded databases.
-@item @uref{http://users.ids.net/~bjepson/freeODBC/}
-The FreeODBC Pages.
+@menu
+* Nutshell Stepwise Rollout:: Stepwise Rollout
+* Nutshell Ready for Immediate Development Use:: Ready for Immediate Development Use
+* Nutshell Embedded MySQL:: Embedded MySQL
+* Nutshell Other features:: Other Features Available From MySQL 4.0.0
+* Nutshell Future features:: Future MySQL 4.0 Features
+* Nutshell 4.1 development release:: MySQL 4.1, The Following Development Release
+@end menu
-@item @uref{http://genix.net/unixODBC/}
-The unixODBC Project goals are to develop and promote unixODBC to be the
-definitive standard for ODBC on the Linux platform. This is to include GUI
-support for KDE.
-@item @uref{http://www.sw-soft.com/products/BtrieveODBC/}
-A MySQL-based ODBC driver for Btrieve.
-@end table
+@node Nutshell Stepwise Rollout, Nutshell Ready for Immediate Development Use, MySQL 4.0 In A Nutshell, MySQL 4.0 In A Nutshell
+@subsection Stepwise Rollout
-@subheading @strong{API}-related Links
+The rollout of MySQL Server 4.0 will come in several steps, with
+the first version labelled 4.0.0 already containing most of the
+new features. Additional features will be incorporated into
+MySQL 4.0.1, 4.0.2 onwards; very probably within a couple of months,
+MySQL 4.0 will be labelled beta. Further new features will then
+be added in MySQL 4.1, which is targeted for alpha release
+in early 2002.
-@table @asis
-@item @uref{http://www.jppp.com/}
-Partially implemented TDataset-compatible components for MySQL.
-@item @uref{http://www.riverstyx.net/qpopmysql/}
-qpopmysql - A patch to allow POP3 authentication from a MySQL
-database. There's also a link to Paul Khavkine's patch for Procmail to
-allow any MTA to deliver to users in a MySQL database.
+@node Nutshell Ready for Immediate Development Use, Nutshell Embedded MySQL, Nutshell Stepwise Rollout, MySQL 4.0 In A Nutshell
+@subsection Ready for Immediate Development Use
-@item @uref{http://www.pbc.ottawa.on.ca}
-Visual Basic class generator for Active X.
+Users are not recommended to switch their production systems
+to MySQL Server 4.0 until it is released in beta version.
+However, even the initial release has passed our extensive
+test suite without any errors on any of the platforms we test on.
+Due to the large number of new features, we thus recommend
+MySQL Server 4.0 even in alpha form for development use, with
+the release schedule of MySQL Server 4.0 being such that it will
+reach stable state before the deployment of user applications
+now under development.
-@item @uref{http://www.essencesw.com/Software/mysqllib.html}
-New Client libraries for the Mac OS Classic (Macintosh).
-@item @uref{http://www.lilback.com/macsql/}
-Client libraries for the Macintosh.
+@node Nutshell Embedded MySQL, Nutshell Other features, Nutshell Ready for Immediate Development Use, MySQL 4.0 In A Nutshell
+@subsection Embedded MySQL
-@item @uref{http://www.essencesw.com/Plugins/mysqlplug.html}
-Plugin for REALbasic (for Macintosh)
+@code{libmysqld} makes MySQL Server suitable for a vastly expanded realm of
+applications. Using the embedded MySQL server library, one can
+embed MySQL Server into various applications and electronics devices, where
+the end user has no knowledge of there actually being an underlying
+database. Embedded MySQL Server is ideal for use behind
+the scenes in internet appliances, public kiosks, turn-key
+hardware/ software combination units, high performance internet
+servers, self-contained databases distributed on CD-ROM etc.
-@item @uref{http://www.iis.ee.ethz.ch/~neeri/macintosh/gusi-qa.html}
-A library that emulates BSD sockets and pthreads on Macintosh. This can
-be used if you want to compile the MySQL client library on Mac.
-It could probably even be sued to port MySQL to Macintosh, but we
-don't know of anyone that has tried that.
+Many embedded MySQL users will benefit from the @emph{dual licensing}
+scheme of the MySQL software, where besides the GPL license also commercial
+licensing is available for those not wishing to be bound by the GPL.
+The embedded MySQL library uses the same interface as the normal
+client library, so it is convenient and easy to use. @xref{libmysqld}.
-@cindex SCMDB
-@item @uref{http://www.dedecker.net/jessie/scmdb/}
-SCMDB - an add-on for SCM that ports the MySQL C library to scheme
-(SCM). With this library scheme developers can make connections to a
-MySQL database and use embedded SQL in their programs.
-@end table
-@subheading Other MySQL-related Links
+@node Nutshell Other features, Nutshell Future features, Nutshell Embedded MySQL, MySQL 4.0 In A Nutshell
+@subsection Other Features Available From MySQL 4.0.0
-@table @asis
-@item @uref{http://www.satisoft.com/, SAT}
-The Small Application Toolkit (SAT) is a collection of utilities
-intended to simplify the development of small, multi-user, GUI based
-applications in a (Microsoft -or- X) Windows Client / Unix Server
-environment.
+@itemize @bullet
+@item
+Version 4.0 further increases @emph{the speed of MySQL Server}
+in a number of areas,
+such as bulk @code{INSERT}s, searching on packed indices, creation of
+@code{FULLTEXT} indices as well as @code{COUNT(DISTINCT)}.
-@item @uref{http://www.wix.com/mysql-hosting/}
-Registry of Web providers who support MySQL.
+@item
+The table handler @code{InnoDB} is now offered as a feature of the
+standard MySQL server, including full support for @code{transactions}
+and @code{row-level locking}.
-@item @uref{http://www.softagency.co.jp/mysql/index.en.html}
-Links about using MySQL in Japan/Asia.
+@item
+MySQL Server 4.0 will support secure traffic between the client and the server,
+greatly increasing security against malicious intrusion and unauthorised
+access. Web applications being a cornerstone of MySQL use, web developers
+have been able to use SSL to secure the traffic between the
+the end user browser and the Web application, be it written in
+PHP, Perl, ASP or using any other web development tool. However,
+the traffic between the development tool and the mysqld server
+process has been protected only by virtue of them being processes
+residing on computers within the same firewall. In MySQL Server 4.0,
+the @emph{mysqld} server daemon process can itself use
+@code{Secure Sockets Layer} (@code{SSL}),
+thus enabling secure traffic to MySQL databases from, say, a Windows
+application residing outside the firewall.
-@item @uref{http://abattoir.cc.ndsu.nodak.edu/~nem/mysql/udf/}
-MySQL UDF Registry.
+@item
+Our German, Austrian and Swiss users will note that we have a new character
+set latin_de which corrects the @emph{German sorting order}, placing German
+Umlauts in the same order as German telephone books.
-@item @uref{http://www.open.com.au/products.html}
-Commercial Web defect tracking system.
+@item
+Features to simplify @code{migration} from other database systems to MySQL
+Server include @code{TRUNCATE TABLE} (like in Oracle) and @code{IDENTITY} as a
+synonym for automatically incremented keys (like in Sybase). Many users will
+also be happy to learn that MySQL Server now supports the @code{UNION} statement,
+a long awaited standard SQL feature.
-@item @uref{http://www.stonekeep.com/pts/}
-PTS: Project Tracking System.
+@item
+In the process of building features for new users, we have not forgotten
+requests by the community of loyal users.
+We have multi-table @code{DELETE} statements.
+By adding support for @code{symbolic linking} to @code{MyISAM} on the table
+level (and not just database level as before), as well as by enabling symlink
+handling by default on Windows, we hope to show that we take enhancement
+requests seriously.
+Functions like @code{SQL_CALC_FOUND_ROWS} and @code{FOUND_ROWS()} makes it
+possible to know how many rows a query would have returned without a
+@code{LIMIT} clause.
+@end itemize
-@item @uref{http://tomato.nvgc.vt.edu/~hroberts/mot}
-Job and software tracking system.
-@item @uref{http://www.cynergi.net/exportsql/}
-ExportSQL: A script to export data from Access95+.
+@node Nutshell Future features, Nutshell 4.1 development release, Nutshell Other features, MySQL 4.0 In A Nutshell
+@subsection Future MySQL 4.0 Features
-@item @uref{http://SAL.KachinaTech.COM/H/1/MYSQL.html}
-SAL (Scientific Applications on Linux) MySQL entry.
+For the upcoming MySQL Server 4.0 releases (4.0.1, 4.0.2 and onwards),
+expect the following features now still under development:
-@item @uref{http://www.infotech-nj.com/itech/index.shtml}
-A consulting company which mentions MySQL in the right company.
+@itemize @bullet
+@item
+Mission-critical, heavy-load users of MySQL Server will appreciate
+the additions to our replication system and our online hot backup.
+Later versions of 4.0 will include @code{fail-safe replication};
+already in existing 4.0.0, the @code{LOAD DATA FROM MASTER} command
+will soon automate slave setup. The @code{online backup} will make
+it easy to add a new replication slave without taking down
+the master, and have a very low performance penalty on
+update-heavy systems.
-@item @uref{http://www.pmpcs.com/}
-PMP Computer Solutions. Database developers using MySQL and
-@code{mSQL}.
+@item
+A convenience feature for Database Administrators is that
+@code{mysqld} parameters (startup options) can soon be set without
+taking down the servers.
-@item @uref{http://www.aewa.org/}
-Airborne Early Warning Association.
+@item
+The new @code{FULLTEXT} search properties of MySQL Server 4.0 enables the
+use of @code{FULLTEXT} indexing of large text masses with both binary and
+natural language searching logic. Users can customise minimal word
+length and define their own stop word lists in any human language,
+enabling a new set of applications to be built on MySQL Server.
-@item @uref{http://www.dedserius.com/y2kmatrix/}
-Y2K tester.
-@end table
+@item
+Many read-heavy applications will benefit from
+further increased speed through the rewritten @code{key cache}.
-@subheading SQL and Database Interfaces
+@item
+Many developers will also be happy to see the @code{MySQL command help}
+in the client.
+@end itemize
-@table @asis
-@item @uref{http://java.sun.com/products/jdbc/}
-The JDBC database access API.
-@item @uref{http://www.gagme.com/mysql}
-Patch for @code{mSQL} Tcl.
+@node Nutshell 4.1 development release, , Nutshell Future features, MySQL 4.0 In A Nutshell
+@subsection MySQL 4.1, The Following Development Release
-@item @uref{http://www.amsoft.ru/easysql/}
-EasySQL: An ODBC-like driver manager.
+Internally, through a new .frm file format for table definitions,
+MySQL Server 4.0 lays the foundation for the new features of MySQL Server 4.1,
+such as @code{nested subqueries}, @code{stored procedures}, and
+@code{foreign key integrity rules}, which form the top of the
+wish list for many of our customers. Along with those, we will
+also include simpler additions, such as
+multi-table @code{UPDATE} statements.
-@item @uref{http://www.lightlink.com/hessling/rexxsql.html}
-A REXX interface to SQL databases.
+After those additions, critics of the MySQL Database Server have
+to be more imaginative
+than ever in pointing out deficiencies in the MySQL Database
+Management System. For long already known for its stability,
+speed, and ease of use, MySQL Server will then match the requirement
+checklist of very demanding buyers.
-@item @uref{http://www.mytcl.cx/}
-Tcl interface based on tcl-sql with many bugfixes.
-@item @uref{http://www.binevolve.com/~tdarugar/tcl-sql/}
-Tcl interface.
+@node MySQL Information Sources, Compatibility, MySQL 4.0 In A Nutshell, Introduction
+@section MySQL Information Sources
-@item @uref{http://www.contrib.andrew.cmu.edu/~shadow/sql.html}
-SQL Reference Page with a lot of interesting links.
+@menu
+* Portals:: MySQL Portals
+* Questions:: MySQL Mailing Lists
+@end menu
-@end table
-@subheading Examples of MySQL Use
+@node Portals, Questions, MySQL Information Sources, MySQL Information Sources
+@subsection MySQL Portals
-@table @asis
-@c Added 990601
-@c EMAIL: thuss@little6.com (Todd Huss)
-@item @uref{http://www.little6.com/about/linux/}
-Little6 Inc., An online contract and job finding site that is powered by
-MySQL, PHP3, and Linux.
-
-@c Added 990521
-@c EMAIL: nh@delec.com (Hillbrecht Nicole)
-@item @uref{http://www.delec.com/is/products/prep/examples/BookShelf/index.html}
-DELECis - A tool that makes it very easy to create an automatically generated
-table documentation. They have used MySQL as an example.
-
-@c Added 990521
-@c EMAIL: info@worldrecords.com (Jim Rota)
-@item @uref{http://www.worldrecords.com}
-World Records - A search engine for information about music that uses
-MySQL and PHP.
-
-@item @uref{http://www.webtechniques.com/archives/1998/01/note/}
-A Contact Database using MySQL and PHP.
-
-@item @uref{http://modems.rosenet.net/mysql/}
-Web based interface and Community Calendar with PHP.
+@cindex MySQL Portals
+@cindex manuals, about MySQL
+@cindex books, about MySQL
+@cindex MySQL Testimonials
+@cindex users, of MySQL
+@cindex news sites
+@cindex search engines, web
+@cindex web search engines
+@cindex online magazines
+@cindex magazines, online
+@cindex web sites
+@cindex services
+@cindex PHP, web sites
+@cindex consultants, list of
+@cindex web pages, miscellaneous
+@cindex @code{Contrib} directory
+@cindex URLs to MySQL information
+@cindex MySQL related information URLs
-@item @uref{http://www.odbsoft.com/cook/sources.htm}
-Perl package to generate html from a SQL table structure and for generating
-SQL statements from an html form.
-
-@item @uref{http://www.gusnet.cx/proj/telsql/}
-Basic telephone database using @code{DBI}/@code{DBD}.
-
-@item @uref{http://tecfa.unige.ch/guides/java/staf2x/ex/jdbc/coffee-break}
-JDBC examples by Daniel K. Schneider.
-
-@item @uref{http://www.spade.com/linux/howto/PostgreSQL-HOWTO-41.html}
-SQL BNF
-
-@item @uref{http://www.ooc.com/}
-Object Oriented Concepts Inc; CORBA applications with examples in source.
-
-@item @uref{http://www.pbc.ottawa.on.ca/}
-DBWiz; Includes an example of how to manage cursors in VB.
-
-@cindex Pluribus
-@item @uref{http://keilor.cs.umass.edu/pluribus/}
-Pluribus is a free search engine that learns to improve
-the quality of its results over time. Pluribus works by recording
-which pages a user prefers among those returned for a query. A user
-votes for a page by selecting it; Pluribus then uses that knowledge
-to improve the quality of the results when someone else submits the
-same (or similar) query. Uses PHP and MySQL.
-
-@c EMAIL: paul@sword.damocles.com (Paul Bannister)
-@item @uref{http://www.stopbit.com/}
-Stopbit - A technology news site using MySQL and PHP.
-
-@item @uref{http://www.linuxsupportline.com/~kalendar/}
-KDE based calendar manager - The calendar manager has both single user
-(file based) and multi-user (MySQL database) support.
-
-@item @uref{http://tim.desert.net/~tim/imger/}
-Example of storing/retrieving images with MySQL and CGI.
-
-@item @uref{http://www.penguinservices.com/scripts}
-Online shopping cart system.
-
-@c Added 990928 from editor@city-gallery.com
-@cindex Old Photo Album
-@item @uref{http://www.city-gallery.com/album/}
-Old Photo Album - The album is a collaborative popular history of photography
-project that generates all pages from data stored in a MySQL
-database. Pages are dynamically generated through a php3 interface to the
-database content. Users contribute images and descriptions. Contributed
-images are stored on the web server to avoid storing them in the database
-as BLOBs. All other information is stored on the shared MySQL server.
-@end table
+The @code{MySQL Portals} (@uref{http://www.mysql.com/portal/})
+represent the ultimate resource to find @code{MySQL AB Partners},
+as well as books, or other @code{MySQL} related solutions that you
+may be looking for. Items are categorized and rated in order to
+make it easy for you to locate information.
-@subheading General Database Links
+By registering as a user, you will have the ability to comment and
+rate items presented in portals. You will also receive relevant
+newsletters according to your user profile that you may update at
+any time.
-@table @asis
-@item @uref{http://www.pcslink.com/~ej/dbweb.html}
-Database Jump Site
+Some of the current @code{MySQL Portal} categories:
-@item @uref{http://black.hole-in-the.net/guy/webdb/}
-Homepage of the webdb-l (Web Databases) mailing list.
+@table @strong
+@item Partners
+Find @code{MySQL AB} partners worldwide.
-@item @uref{http://www.symbolstone.org/technology/perl/DBI/index.html}
-Perl @code{DBI}/@code{DBD} modules homepage.
+@item Books
+Comment, vote, and buy books related to @code{MySQL}.
-@item @uref{http://www.student.uni-koeln.de/cygwin/}
-Cygwin tools. Unix on top of Windows.
+@item Development
+Various links to different sites that are using @code{MySQL Server}
+for different purposes, with a description of each site.
+This information can give you an idea of who uses the @code{MySQL}
+database software and how @code{MySQL Server} can fulfill
+requirements.
-@item @uref{http://dbasecentral.com/}
-dbasecentral.com; Development and distribution of powerful and easy-to-use
-database applications and systems.
+Let us know about @emph{your} site or success story, too!
+Visit @uref{http://www.mysql.com/feedback/testimonial.php}.
-@cindex Tek-Tips forums
-@cindex forums, Tek-Tips
-@item @uref{http://www.tek-tips.com/}
-Tek-Tips Forums are 800+ independent peer-to-peer non-commercial support
-forums for Computer Professionals. Features include automatic e-mail
-notification of responses, a links library, and member confidentiality
-guaranteed.
+@item Software
+Find, buy, download several applications and wrappers that make
+use of the @code{MySQL} server.
-@item @uref{http://www.public.asu.edu/~peterjn/btree/}
-B-Trees: Balanced Tree Data Structures.
+@item Distributions
+From here you can find the various Linux distributions and other
+software packages that contain the @code{MySQL} software.
-@item @uref{http://www.fit.qut.edu.au/~maire/baobab/lecture/sld001.htm}
-A lecture about B-Trees.
+@item Service Providers
+Companies providing @code{MySQL}-related services.
@end table
-There are also many Web pages that use MySQL. @xref{Users}.
-Send any additions to this list to @email{webmaster@@mysql.com}. We now
-require that you show a MySQL logo somewhere if you wish your
-site to be added. It is okay to have it on a ``used tools'' page or
-something similar.
-
-@node Questions, , Useful Links, MySQL Information Sources
+@node Questions, , Portals, MySQL Information Sources
@subsection MySQL Mailing Lists
@cindex reporting, errors
+@cindex errors, reporting
@cindex MySQL mailing lists
@menu
-* Mailing-list:: The MySQL mailing lists
-* Asking questions:: Asking questions or reporting bugs
-* Bug reports:: How to report bugs or problems
-* Answering questions:: Guidelines for answering questions on the mailing list
+* Mailing-list:: The MySQL Mailing Lists
+* Asking questions:: Asking Questions or Reporting Bugs
+* Bug reports:: How to Report Bugs or Problems
+* Answering questions:: Guidelines for Answering Questions on the Mailing List
@end menu
This section introduces you to the MySQL mailing lists, and gives
-some guidelines as to how to use them.
+some guidelines as to how to use them. By subscribing to a mailing
+list, you will receive as emails all other postings on the list,
+and you will be able to send in your own questions and answers.
@node Mailing-list, Asking questions, Questions, Questions
@subsubsection The MySQL Mailing Lists
@cindex mailing lists
-@cindex email lists
+@cindex e-mail lists
To subscribe to the main MySQL mailing list, send a message to the
electronic mail address @email{mysql-subscribe@@lists.mysql.com}.
@@ -2136,7 +2021,7 @@ the electronic mail address @email{mysql-unsubscribe@@lists.mysql.com}.
Only the address to which you send your messages is significant. The
subject line and the body of the message are ignored.
-@c the last two addresses in this paragraph are NOT @email because they
+@c the last two addresses in this paragraph are not @email because they
@c shouldn't be live links.
If your reply address is not valid, you can specify your address
explicitly. Adding a hyphen to the subscribe or unsubscribe command
@@ -2148,7 +2033,7 @@ address replaced by a @samp{=}. For example, to subscribe
Mail to @email{mysql-subscribe@@lists.mysql.com} or
@email{mysql-unsubscribe@@lists.mysql.com} is handled automatically by the
ezmlm mailing list processor. Information about ezmlm is available at
-@uref{http://www.ezmlm.org, The ezmlm Website}.
+the ezmlm web site (@uref{http://www.ezmlm.org/}).
To post a message to the list itself, send your message to
@code{mysql@@lists.mysql.com}. However, please @emph{do not} send mail about
@@ -2177,7 +2062,7 @@ subscribe to.
@item @email{mysql-subscribe@@lists.mysql.com} mysql
The main list for general MySQL discussion. Please note that some
-topics are better discussed on the more-specialized lists. If you post to the
+topics are better discussed on the more-specialised lists. If you post to the
wrong list, you may not get an answer!
@item @email{mysql-digest-subscribe@@lists.mysql.com} mysql-digest
@@ -2189,9 +2074,9 @@ On this list you should only post a full, repeatable bug report using
the @code{mysqlbug} script (if you are running on Windows, you should
include a description of the operating system and the MySQL version).
Preferably, you should test the problem using the latest stable or development
-version of MySQL before posting! Anyone should be able to repeat the
-bug by just using @code{mysql test < script} on the included test case. All
-bugs posted on this list will be corrected or documented in the next
+version of MySQL Server before posting! Anyone should be able to repeat the
+bug by just using @code{mysql test < script} on the included test case. All
+bugs posted on this list will be corrected or documented in the next
MySQL release! If there are only small code changes involved, we
will also post a patch that fixes the problem.
@@ -2206,24 +2091,30 @@ can also discuss MySQL development and post patches.
A digest version of the @code{internals} list.
@item @email{java-subscribe@@lists.mysql.com} java
-Discussion about MySQL and Java. Mostly about the JDBC drivers.
+Discussion about the MySQL server and Java. Mostly about the JDBC drivers.
@item @email{java-digest-subscribe@@lists.mysql.com} java-digest
A digest version of the @code{java} list.
@item @email{win32-subscribe@@lists.mysql.com} win32
-All things concerning MySQL on Microsoft operating systems such as
-Win95, Win98, NT, and Win2000.
+All things concerning the MySQL software on Microsoft operating systems
+such as Win95, Win98, NT, and Win2000.
@item @email{win32-digest-subscribe@@lists.mysql.com} win32-digest
A digest version of the @code{win32} list.
@item @email{myodbc-subscribe@@lists.mysql.com} myodbc
-All things about connecting to MySQL with ODBC.
+All things about connecting to the MySQL server with ODBC.
@item @email{myodbc-digest-subscribe@@lists.mysql.com} myodbc-digest
A digest version of the @code{myodbc} list.
+@item @email{mycc-subscribe@@lists.mysql.com} mycc
+All things about the MySQL MyCC graphical client.
+
+@item @email{mycc-digest-subscribe@@lists.mysql.com} mycc-digest
+A digest version of the @code{mycc} list.
+
@item @email{plusplus-subscribe@@lists.mysql.com} plusplus
All things concerning programming with the C++ API to MySQL.
@@ -2231,7 +2122,7 @@ All things concerning programming with the C++ API to MySQL.
A digest version of the @code{plusplus} list.
@item @email{msql-mysql-modules-subscribe@@lists.mysql.com} msql-mysql-modules
-A list about the Perl support in MySQL. msql-mysql-modules
+A list about the Perl support for MySQL with msql-mysql-modules.
@item @email{msql-mysql-modules-digest-subscribe@@lists.mysql.com} msql-mysql-modules-digest
A digest version of the @code{msql-mysql-modules} list.
@@ -2255,15 +2146,15 @@ guarantee the quality on these.
@table @code
@item @email{mysql-france-subscribe@@yahoogroups.com} A French mailing list
@item @email{list@@tinc.net} A Korean mailing list
-Email @code{subscribe mysql your@@email.address} to this list.
+Email @code{subscribe mysql your@@e-mail.address} to this list.
@item @email{mysql-de-request@@lists.4t2.com} A German mailing list
-Email @code{subscribe mysql-de your@@email.address} to this list.
+Email @code{subscribe mysql-de your@@e-mail.address} to this list.
You can find information about this mailing list at
-@uref{http://www.4t2.com/mysql}.
+@uref{http://www.4t2.com/mysql/}.
@item @email{mysql-br-request@@listas.linkway.com.br} A Portugese mailing list
-Email @code{subscribe mysql-br your@@email.address} to this list.
+Email @code{subscribe mysql-br your@@e-mail.address} to this list.
@item @email{mysql-alta@@elistas.net} A Spanish mailing list
-Email @code{subscribe mysql your@@email.address} to this list.
+Email @code{subscribe mysql your@@e-mail.address} to this list.
@end table
@@ -2272,7 +2163,7 @@ Email @code{subscribe mysql your@@email.address} to this list.
@cindex net etiquette
@cindex mailing lists, archive location
-@cindex searching, MySQL webpages
+@cindex searching, MySQL web pages
Before posting a bug report or question, please do the following:
@@ -2280,19 +2171,19 @@ Before posting a bug report or question, please do the following:
@item
Start by searching the MySQL online manual at:
@*
-@uref{http://www.mysql.com/documentation/manual.php}
+@uref{http://www.mysql.com/doc/}
@*
-We try to keep the manual up to date by updating it frequently with
+We try to keep the manual up to date by updating it frequently with
solutions to newly found problems!
@item
Search the MySQL mailing list archives:
@*
-@uref{http://www.mysql.com/documentation/}
+@uref{http://lists.mysql.com/}
@*
@item
You can also use @uref{http://www.mysql.com/search.html} to search all the
-Web pages (including the manual) that are located at
+Web pages (including the manual) that are located at
@uref{http://www.mysql.com/}.
@end itemize
@@ -2333,7 +2224,7 @@ missing, please include it with your message! Please read this section
carefully and make sure that all the information described here is included
in your report.
-@cindex bug reports, email address
+@cindex bug reports, e-mail address
The normal place to report bugs and problems is
@email{mysql@@lists.mysql.com}. If you can make a test case that clearly
demonstrates the bug, you should post it to the @email{bugs@@lists.mysql.com}
@@ -2341,7 +2232,7 @@ list. Note that on this list you should only post a full, repeatable bug
report using the @code{mysqlbug} script. If you are running on Windows,
you should include a description of the operating system and the
MySQL version. Preferably, you should test the problem using
-the latest stable or development version of MySQL before
+the latest stable or development version of MySQL Server before
posting! Anyone should be able to repeat the bug by just using
``@code{mysql test < script}'' on the included test case or run the
shell or perl script that is included in the bug report. All bugs
@@ -2350,6 +2241,9 @@ MySQL release! If there are only small code changes involved
to correct this problem, we will also post a patch that fixes the
problem.
+If you have found a sensitive security bug in MySQL, you should send an
+e-mail to @email{security@@mysql.com}.
+
Remember that it is possible to respond to a message containing too much
information, but not to one containing too little. Often people omit facts
because they think they know the cause of a problem and assume that some
@@ -2361,7 +2255,7 @@ first time.
The most common errors are that people don't indicate the version number of
the MySQL distribution they are using, or don't indicate what
-platform they have MySQL installed on (including the platform
+platform they have the MySQL server installed on (including the platform
version number). This is highly relevant information, and in 99 cases out of
100 the bug report is useless without it! Very often we get questions like,
``Why doesn't this work for me?'' then we find that the feature
@@ -2388,8 +2282,8 @@ problem. @xref{Reproduceable test case}.
If a program produces an error message, it is very important to include the
message in your report! If we try to search for something from the archives
using programs, it is better that the error message reported exactly matches
-the one that the program produces. (Even the case should be observed!)
-You should never try to remember what the error message was; instead, copy
+the one that the program produces. (Even the case should be observed!)
+You should never try to remember what the error message was; instead, copy
and paste the entire message into your report!
If you have a problem with MyODBC, you should try to generate a MyODBC
@@ -2422,12 +2316,12 @@ The operating system name and version. For most operating systems, you can
get this information by executing the Unix command @code{uname -a}.
@item
-Sometimes the amount of memory (real and virtual) is relevant. If in doubt,
+Sometimes the amount of memory (real and virtual) is relevant. If in doubt,
include these values.
@item
-If you are using a source distribution of MySQL, the name and
-version number of the compiler used is needed. If you have a binary
+If you are using a source distribution of the MySQL software, the name and
+version number of the compiler used is needed. If you have a binary
distribution, the distribution name is needed.
@item
@@ -2476,7 +2370,7 @@ mysql> SHOW STATUS;
If a bug or problem occurs while running @strong{mysqld}, try to provide an
input script that will reproduce the anomaly. This script should include any
necessary source files. The more closely the script can reproduce your
-situation, the better. If you can make a repeatable test case, you should
+situation, the better. If you can make a reproduceable test case, you should
post this to @email{bugs@@lists.mysql.com} for a high priority treatment!
If you can't provide a script, you should at least include the output
@@ -2490,12 +2384,12 @@ dump your tables using @code{mysqldump} and create a @file{README} file
that describes your problem.
Create a compressed archive of your files using
-@code{tar} and @code{gzip} or @code{zip}, and use @code{ftp} to transfer the
-archive to @uref{ftp://support.mysql.com/pub/mysql/secret/}. Then send a
+@code{tar} and @code{gzip} or @code{zip}, and use @code{ftp} to transfer the
+archive to @uref{ftp://support.mysql.com/pub/mysql/secret/}. Then send a
short description of the problem to @email{bugs@@lists.mysql.com}.
@item
-If you think that MySQL produces a strange result from a query,
+If you think that the MySQL server produces a strange result from a query,
include not only the result, but also your opinion of what the result
should be, and an account describing the basis for your opinion.
@@ -2504,11 +2398,11 @@ When giving an example of the problem, it's better to use the variable names,
table names, etc., that exist in your actual situation than to come up with
new names. The problem could be related to the name of a variable or table!
These cases are rare, perhaps, but it is better to be safe than sorry.
-After all, it should be easier for you to provide an example that uses your
+After all, it should be easier for you to provide an example that uses your
actual situation, and it is by all means better for us. In case you have data
-you don't want to show to others, you can use @code{ftp} to transfer it to
+you don't want to show to others, you can use @code{ftp} to transfer it to
@uref{ftp://support.mysql.com/pub/mysql/secret/}. If the data are really top
-secret and you don't want to show them even to us, then go ahead and provide
+secret and you don't want to show them even to us, then go ahead and provide
an example using other names, but please regard this as the last choice.
@item
@@ -2554,17 +2448,17 @@ problem yourself.
@item
If you get a @code{parse error}, please check your syntax closely! If
you can't find something wrong with it, it's extremely likely that your
-current version of MySQL doesn't support the query you are
+current version of MySQL Server doesn't support the query you are
using. If you are using the current version and the manual at
-@uref{http://www.mysql.com/documentation/manual.php} doesn't cover the
-syntax you are using, MySQL doesn't support your query. In this
+@uref{http://www.mysql.com/doc/} doesn't cover the
+syntax you are using, MySQL Server doesn't support your query. In this
case, your only options are to implement the syntax yourself or e-mail
@email{mysql-licensing@@mysql.com} and ask for an offer to implement it!
If the manual covers the syntax you are using, but you have an older version
-of MySQL, you should check the MySQL change history to see
-when the syntax was implemented. In this case, you have the option of
-upgrading to a newer version of MySQL. @xref{News}.
+of MySQL Server, you should check the MySQL change history to see
+when the syntax was implemented. In this case, you have the option of
+upgrading to a newer version of MySQL Server. @xref{News}.
@item
If you have a problem such that your data appears corrupt or you get
@@ -2574,20 +2468,20 @@ try repairing your tables with @code{myisamchk} or @code{CHECK TABLE} and
@item
If you often get corrupted tables you should try to find out when and why this
-happens! In this case, the @file{mysql-data-directory/'hostname'.err} file
+happens. In this case, the @file{mysql-data-directory/'hostname'.err} file
may contain some information about what happened. @xref{Error log}. Please
-include any relevant information from this file in your bug report! Normally
-@code{mysqld} should @strong{NEVER} crash a table if nothing killed it in the
+include any relevant information from this file in your bug report. Normally
+@code{mysqld} should @strong{never} crash a table if nothing killed it in the
middle of an update! If you can find the cause of @code{mysqld} dying,
-it's much easier for us to provide you with a fix for the problem!
+it's much easier for us to provide you with a fix for the problem.
@xref{What is crashing}.
@item
-If possible, download and install the most recent version of MySQL
-and check whether or not it solves your problem. All versions of
-MySQL are thoroughly tested and should work without problems! We
-believe in making everything as backward compatible as possible, and you
-should be able to switch MySQL versions in minutes!
+If possible, download and install the most recent version of MySQL Server
+and check whether or not it solves your problem. All versions of
+the MySQL software are thoroughly tested and should work without problems.
+We believe in making everything as backward compatible as possible,
+and you should be able to switch MySQL versions without any hassle.
@xref{Which version}.
@end itemize
@@ -2602,16 +2496,16 @@ perhaps solved) the problem.
For information on reporting bugs in @strong{MyODBC}, see @ref{ODBC Problems}.
-For solutions to some common problems, see @xref{Problems}.
+For solutions to some common problems, see @ref{Problems}.
When answers are sent to you individually and not to the mailing list,
-it is considered good etiquette to summarize the answers and send the
+it is considered good etiquette to summarise the answers and send the
summary to the mailing list so that others may have the benefit of
responses you received that helped you solve your problem!
@node Answering questions, , Bug reports, Questions
-@subsubsection Guidelines for Answering Question on the Mailing List
+@subsubsection Guidelines for Answering Questions on the Mailing List
@cindex net etiquette
@cindex questions, answering
@@ -2624,784 +2518,125 @@ asked. Try to make your answer general enough that people other than the
original poster may benefit from it. When you post to the list, please make
sure that your answer is not a duplication of a previous answer.
-Try to summarize the essential part of the question in your reply; don't feel
+Try to summarise the essential part of the question in your reply; don't feel
obliged to quote the entire original message.
Please don't post mail messages from your browser with HTML mode turned on!
Many users don't read mail with a browser!
-@node Licensing and Support, Compatibility, MySQL Information Sources, Introduction
-@section MySQL Licensing and Support
-
-@cindex licensing terms
-@cindex support terms
-
-@menu
-* Licensing policy:: MySQL licensing policy
-* Copyright:: Copyrights used by MySQL
-* Licensing examples:: Example licensing situations
-* Cost:: MySQL licensing and support costs
-* Support:: Types of commercial support
-@end menu
-
-This section describes MySQL support and licensing
-arrangements:
-
-@itemize @bullet
-
-@item The copyrights under which MySQL is distributed
-(@pxref{Copyright})
-
-@item Sample situations illustrating when a license is required
-(@pxref{Licensing examples})
-
-@item Support costs (@pxref{Cost}) and support benefits
-(@pxref{Support})
-
-@item Commercial licensing costs
-@end itemize
-
-
-@node Licensing policy, Copyright, Licensing and Support, Licensing and Support
-@subsection MySQL Licensing Policy
-
-@cindex licensing policy
-@cindex technical support, licensing
-@cindex support, licensing
-@cindex General Public License, MySQL
-
-The formal terms of the GPL license can be found at @ref{GPL license}.
-Basically, our licensing policy and interpretation of the GPL is as follows:
-
-Note that older versions of MySQL are still using a more
-@uref{http://www.mysql.com/support/arrangements/mypl.html, strict license}.
-See the documentation for that version for more information. If you need a
-commercial MySQL license, because the GPL license doesn't suit your
-application, you can buy one at @uref{https://order.mysql.com/}.
-
-For normal internal use, MySQL costs nothing. You do not have
-to pay us if you do not want to.
-
-A license is required if:
-
-@itemize @minus
-@item
-You link a program, that is not free software, with code from the
-MySQL server or clients that has the GPL copyright. This
-happens for example when you use MySQL as an embedded server
-in your applications or when you add not free extensions to the
-MySQL server. In this case your application/code would also
-become GPL through the GPL license that acts as a virus. By licensing
-MySQL server from MySQL AB under a commercial
-license you will avoid this problem.
-See @uref{http://www.gnu.org/copyleft/gpl-faq.html}.
-@item
-You have a commercial application that ONLY works with MySQL
-and ships the application with the MySQL server. This is
-because we view this as linking even if it is done over the network.
-
-@item
-You have a distribution of MySQL and you don't provide the
-source code for your copy of the MySQL server, as defined in
-the GPL license.
-@end itemize
-
-A license is @strong{NOT} required if:
-
-@itemize @minus
-
-@item
-You do not need a license to include the client code in commercial
-programs. The client part of MySQL licensed with the
-LGPL @code{GNU Library General Public License}. The @code{mysql} command-line
-client includes code from the @code{readline} library that is under
-the @code{GPL}.
-
-@item
-If your use of MySQL does not require a license, but you
-like MySQL and want to encourage further development, you are
-certainly welcome to purchase a license or MySQL support anyway.
-
-@item
-If you use MySQL in a commercial context such that you profit by
-its use, we ask that you further the development of MySQL by
-purchasing some level of support. We feel that if MySQL helps
-your business, it is reasonable to ask that you help MySQL.
-(Otherwise, if you ask us support questions, you are not only using for
-free something into which we've put a lot a work, you're asking us to
-provide free support, too.)
-@end itemize
-
-For circumstances under which a MySQL license is required, you
-need a license per machine that runs the @code{mysqld} server. However,
-a multiple-CPU machine counts as a single machine, and there is no
-restriction on the number of MySQL servers that run on one
-machine, or on the number of clients concurrently connected to a server
-running on that machine!
-
-If you have any questions as to whether or not a license is required for
-your particular use of MySQL, please read this again and then
-contact us. @xref{Contact information}.
-
-If you require a MySQL license, the easiest way to pay for it
-is to use the license form on MySQL's secure server at
-@uref{https://order.mysql.com/}. Other forms of payment are
-discussed in @ref{Payment information}.
-
-
-@node Copyright, Licensing examples, Licensing policy, Licensing and Support
-@subsection Copyrights Used by MySQL
-
-@cindex copyrights
-
-@menu
-* Copyright changes:: Possible future copyright changes
-@end menu
-
-There are several different copyrights on the MySQL distribution:
-
-@enumerate
-@item
-The MySQL-specific source needed to build the
-@code{mysqlclient} library is licensed under the @code{LGPL} and
-programs in the @file{client} directory is GPL. Each file has a header
-that shows which copyright is used for that file.
-
-@item The client library and the (GNU @code{getopt}) library are covered
-by the ``GNU LIBRARY GENERAL PUBLIC LICENSE.'' @xref{LGPL license}.
-
-@item Some parts of the source (the @code{regexp} library) are covered
-by a Berkeley-style copyright.
-
-@item
-All the source in the server and the (GNU @code{readline}) library
-is covered by the ``GNU GENERAL PUBLIC LICENSE.'' @xref{GPL license}.
-This is also available as the file @file{COPYING} in the distributions.
-
-@end enumerate
-
-One goal is that the SQL client library should be free enough that it is
-possible to add MySQL support into commercial products
-without a license. For this reason, we chose the LGPL license for the
-client code.
-@cindex licensing, free
-@cindex free licensing
-
-This means that you can use MySQL for free with any program that uses
-any of the free software licenses. MySQL is also free for any end
-user for his own or company usage.
-
-However, if you use MySQL for something important to you, you may
-want to help secure its development by purchasing licenses or a support
-contract. @xref{Support}.
-
-
-@node Copyright changes, , Copyright, Copyright
-@subsubsection Copyright Changes
-
-Version 3.22 of MySQL is still using a more strict license.
-See the documentation for that version for more information.
-
-
-@node Licensing examples, Cost, Copyright, Licensing and Support
-@subsection Example Licensing Situations
-
-@menu
-* Products that use MySQL:: Selling products that use MySQL
-* ISP:: ISP MySQL services
-* Web server:: Running a web server using MySQL.
-@end menu
-
-@cindex licensing, examples
-@cindex selling products
-@cindex products, selling
-
-This section describes some situations illustrating whether or not you
-must license the MySQL server. Generally these examples
-involve providing MySQL as an integral part of a product.
-
-Note that a single MySQL license covers any number of CPUs and
-@code{mysqld} servers on a machine! There is no artificial limit on the
-number of clients that connect to the server in any way.
-
-
-@node Products that use MySQL, ISP, Licensing examples, Licensing examples
-@subsubsection Selling Products that use MySQL
-
-To determine whether or not you need a MySQL license when
-selling your application, you should ask whether the proper functioning
-of your application is dependent on the use of MySQL and
-whether you include the MySQL server with your product. There
-are several cases to consider:
-
-@itemize @bullet
-@item
-Does your application require MySQL to function properly?
-
-@item
-If your product requires MySQL, you need a license for any
-machine that runs the @code{mysqld} server. For example, if you've
-designed your application around MySQL, then you've really made
-a commercial product that requires the engine, so you need a license.
-
-@item
-If your application does not require MySQL, you do not need to obtain
-a license. For example, if using MySQL just adds some new optional
-features to your product (such as adding logging to a database if
-MySQL is used rather than logging to a text file), it should
-fall within normal use, and a license would not be required.
-
-@item
-In other words, you need a license if you sell a product designed
-specifically for use with MySQL or that requires the
-MySQL server to function at all. This is true whether or not
-you provide MySQL for your client as part of your product
-distribution.
-
-@item
-It also depends on what you're doing for the client. Do you plan to
-provide your client with detailed instructions on installing
-MySQL with your software? Then your product may be contingent
-on the use of MySQL; if so, you need to buy a license. If you
-are simply tying into a database that you expect already to have been
-installed by the time your software is purchased, then you probably
-don't need a license.
-
-@end itemize
-
-
-@node ISP, Web server, Products that use MySQL, Licensing examples
-@subsubsection ISP MySQL Services
-
-@cindex ISP services
-@cindex services, ISP
-@cindex services, web
-@cindex Internet Service Providers
-
-Internet Service Providers (ISPs) often host MySQL servers for
-their customers. With the GPL license this does not require a license.
-
-On the other hand, we do encourage people to use ISPs that have
-MySQL support, as this will give them the confidence that if
-they have some problem with their MySQL installation, their ISP
-will be able to solve the problem for them (in some cases with the help
-from the MySQL development team).
-
-All ISPs that want to keep themselves up-to-date should subscribe
-to our @code{announce} mailing list so that they can be aware of fatal issues
-that may be relevant for their MySQL installations.
-
-Note that if the ISP doesn't have a license for MySQL,
-it should give its customers at least read access to the source of
-the MySQL installation so that its customer can verify that
-it is patched correctly.
-
-
-@node Web server, , ISP, Licensing examples
-@subsubsection Running a Web Server Using MySQL
-
-@cindex web server, running
-@cindex running, a web server
-
-If you use MySQL in conjunction with a Web server on Unix, you
-don't have to pay for a license.
-
-This is true even if you run a commercial Web server that uses
-MySQL, because you are not selling an embedded MySQL
-version yourself. However, in this case we would like you to purchase
-MySQL support, because MySQL is helping your enterprise.
-
-
-@node Cost, Support, Licensing examples, Licensing and Support
-@subsection MySQL Licensing and Support Costs
-
-@cindex costs, licensing and support
-@cindex licensing costs
-@cindex support costs
-@cindex prices, licensing and support
-
-@menu
-* Payment information:: Payment information
-* Contact information:: Contact information
-@end menu
-
-Our current license prices are shown below. To make a purchase, please visit
-@uref{https://order.mysql.com/}.
-
-If you pay by credit card, the currency is EURO (European Union Euro) so the
-prices will differ slightly.
-
-@multitable @columnfractions .3 .3 .3
-@item @strong{Number of licenses} @tab @strong{Per copy}
-@item 1-9 @tab 230 EURO
-@item 10-24 @tab 138 EURO
-@item 25-49 @tab 117 EURO
-@item 50-99 @tab 102 EURO
-@item 100-249 @tab 91 EURO
-@item 250-499 @tab 76 EURO
-@item 500-999 @tab 66 EURO
-@end multitable
-
-For high volume (OEM) purchases, please contact
-@email{sales@@mysql.com}.
-
-For OEM purchases, you must act as the middle-man for eventual problems
-or extension requests from your users. We also require that OEM
-customers have at least an extended e-mail support contract. Note that
-OEM licenses only apply for products where the user doesn't have direct
-access to the MySQL server (embedded system). In other words,
-the MySQL server should only be used with the application
-that was supplied you.
-
-If you have a low-margin, high-volume product, you can always talk to us
-about other terms (for example, a percent of the sale price). If you do,
-please be informative about your product, pricing, market, and any other
-information that may be relevant.
-
-A full-price license is not a support agreement and includes very minimal
-support. This means that we try to answer any relevant questions. If the
-answer is in the documentation, we will direct you to the appropriate
-section. If you have not purchased a license or support, we probably will
-not answer at all.
-
-If you discover what we consider a real bug, we are likely to fix it in
-any case. But if you pay for support we will notify you about the fix
-status instead of just fixing it in a later release.
-
-More comprehensive support is sold separately. Descriptions of what each
-level of support includes are given in @ref{Support}. Costs for the various
-types of commercial support are shown below. Support level prices are in
-EURO (European Union Euro). One EURO is about 1.06 USD.
-
-@multitable @columnfractions .5 .5
-@item @strong{Type of support} @tab @strong{Cost per year}
-@item Basic e-mail support. @xref{Basic email support}. @tab EURO 200
-@item Extended e-mail support @xref{Extended email support}. @tab EURO 1000
-@item Login support @xref{Login support}. @tab EURO 2000
-@item Extended login support @xref{Extended login support}. @tab EURO 5000
-@item Telephone support @xref{Telephone support}. @tab EURO 12000
-@end multitable
-
-You may upgrade from any lower level of support to a higher level of
-support for the difference in price between the two support levels.
-
-We do also provide telephone support (mostly emergency support but also
-24/7 support). This support option doesn't however have a fixed price
-but is negotiated for case to case. If you are interested in this option
-you can email @email{sales@@mysql.com} and tell us about your needs.
-
-Note that as our sales staff is very busy, it may take some time until
-your request is handled. Our support staff does however always answer
-promptly to support questions!
-
-
-@node Payment information, Contact information, Cost, Cost
-@subsubsection Payment information
-
-@cindex payment information
-
-Currently we can take SWIFT payments, checks, or credit cards.
-
-Payment should be made to:
-
-@example
-Postgirot Bank AB
-105 06 STOCKHOLM, SWEDEN
-
-MySQL AB
-BOX 6434
-11382 STOCKHOLM, SWEDEN
-
-SWIFT address: PGSI SESS
-Account number: 96 77 06 - 3
-@end example
-
-Specify: license and/or support and your name and e-mail address.
-
-In Europe and Japan you can use EuroGiro (that should be less expensive) to the
-same account.
-
-If you want to pay by check, make it payable to ``MySQL Finland AB'' and
-mail it to the address below:
-
-@example
-MySQL AB
-BOX 6434, Torsgatan 21
-11382 STOCKHOLM, SWEDEN
-@end example
-
-If you want to pay by credit card over the Internet, you can use
-@uref{https://order.mysql.com/, MySQL AB's secure license form}.
-
-You can also print a copy of the license form, fill it in, and send it by fax
-to:
-
-+46-8-729 69 05
-
-If you want us to bill you, you can use the license form and write ``bill
-us'' in the comment field. You can also mail a message to
-@email{sales@@mysql.com} (@strong{not} @code{mysql@@lists.mysql.com}!)
-with your company information and ask us to bill you.
-
-
-@node Contact information, , Payment information, Cost
-@subsubsection Contact Information
-
-@cindex contact information
-@cindex licensing, contact information
-@cindex advertising, contact information
-@cindex employment, contact information
-@cindex partnering with MySQL
-@cindex employment with MySQL
-@cindex jobs at MySQL
-
-For commercial licensing, please contact the MySQL licensing
-team. The much preferred method is by e-mail to
-@email{licensing@@mysql.com}. Fax is also possible but handling of
-these may take much longer (Fax +46-8-729 69 05).
-
-If you represent a business that is interested in partnering with
-MySQL, please send e-mail to @email{partner@@mysql.com}.
-
-For timely, precise answers to technical questions about MySQL
-you should @uref{https://order.mysql.com/, order} one of our
-@uref{http://www.mysql.com/support/arrangements/types.html, support contracts}.
-MySQL support is provided by the MySQL developers so the
-standard is extremely high.
-
-If you are interested in placing a banner advertisement on our Web site,
-please send e-mail to @email{advertising@@mysql.com}.
-
-If you are interested in any of the jobs listed in our
-@uref{http://www.mysql.com/development/jobs/, jobs} section, please send e-mail
-to @email{jobs@@mysql.com}.
-
-For general discussion amongst our many users, please direct your attention to
-the appropriate @uref{http://www.mysql.com/documentation/lists.html, mailing
-list}.
-
-For general information inquires, please send e-mail to
-@email{info@@mysql.com}.
-
-For questions or comments about the workings or content of the Web site,
-please send e-mail to @email{webmaster@@mysql.com}.
-
+@node Compatibility, TODO, MySQL Information Sources, Introduction
+@section How Standards-compatible Is MySQL?
-@node Support, , Cost, Licensing and Support
-@subsection Types of Commercial Support
+@cindex compatibility, with ANSI SQL
+@cindex standards compatibility
+@cindex extensions, to ANSI SQL
+@cindex ANSI SQL92, extensions to
-@cindex support, types
-@cindex types, of support
-@cindex commercial support, types
+This section describes how MySQL relates to the ANSI SQL standards.
+MySQL Server has many extensions to the ANSI SQL standards, and here you
+will find out what they are, and how to use them. You will also find
+information about functionality missing from MySQL Server, and how to work
+around some differences.
+
+Our goal is to not, without a very good reason, restrict MySQL Server usability
+for any usage. Even if we don't have the resources to do development
+for every possible use, we are always willing to help and offer
+suggestions to people that is trying to use MySQL Server in new territories.
+
+One of our main goals with the product is to continue to work towards
+ANSI 99 compliancy, but without sacrificing speed or reliability.
+We are not afraid to add extensions to SQL or support for non-SQL
+features if this greatly increase the usability of MySQL Server for a big
+part of our users. (The new @code{HANDLER} interface in MySQL Server 4.0
+is an example of this strategy. @xref{HANDLER}.)
+
+We will continue to support transactional and not transactional
+databases to satisfy both heavy web/logging usage and mission critical
+24/7 usage.
+
+MySQL Server was designed from the start to work with medium large databases
+(10-100 million rows / about 100 MB per table) on small computer
+systems. We will continue to extend MySQL Server to both work even better
+with terabyte size databases, but we are also doing work to make it possible
+to compile a reduced MySQL version that is more suitable for hand held
+devices and embedded usage. The compact design of the MySQL server makes both
+of these directions possible without any conflicts in the source tree.
+
+We are currently not targeting real time support or clustered databases
+(even if you can already do a lot of things with our replication
+services).
+
+We don't believe that one should have native XML support in the
+database, but will instead add the XML support our users request from
+us on the client side. We think it's better to keep the main server
+code as ``lean and clean'' as possible and instead develop libraries to
+deal with the complexity on the client side. This is part of the strategy
+mentioned above of not sacrificing speed or reliability in the
+server.
@menu
-* Basic email support:: Basic email support
-* Extended email support:: Extended email support
-* Login support:: Login support
-* Extended login support:: Extended login support
-* Telephone support:: Telephone support
-* Table handler support:: Support for other table handlers
+* Standards:: What Standards Does MySQL Follow?
+* ANSI mode:: Running MySQL in ANSI Mode
+* Extensions to ANSI:: MySQL Extensions to ANSI SQL92
+* Differences from ANSI:: MySQL Differences Compared to ANSI SQL92
+* Bugs:: Known Errors and Design Deficiencies in MySQL
@end menu
-The following is true of all support options:
-
-@itemize @bullet
-@item
-The support is per year.
-@item
-We will fix, or provide a reasonable workaround for any repeatable bug.
-@item
-We will give a reasonable effort to find and fix any other MySQL related bug.
-@item
-The higher level of support contract the more effort we will put into finding
-a solution to your problems.
-@item
-The following is true for all support contracts except Basic email support:
-
-For non-bug related things, like helping you optimize your queries or
-your system, extending MySQL with new functionality, etc., we charge 200
-EURO/hour, which is deducted from your support contract. In other words,
-if you have login support (2000 EURO), you can expect us to work up to
-10 hours to help you with things like this.
-@end itemize
-
-
-@node Basic email support, Extended email support, Support, Support
-@subsubsection Basic E-mail Support
-
-@cindex email, technical support
-@cindex technical support, by email
-
-Basic e-mail support is a very inexpensive support option and should be
-thought of more as a way to support our development of MySQL
-than as a real support option. We at MySQL do give a lot of free
-support in all the different MySQL lists, and the money we get from
-basic e-mail support is largely used to make this possible.
-
-At this support level, the MySQL mailing lists are the preferred
-means of communication. Questions normally should be mailed to the primary
-mailing list (@email{mysql@@lists.mysql.com}) or one of the other regular
-lists (for example, @email{win32@@lists.mysql.com} for Windows-related
-MySQL questions), as someone else already may have experienced and
-solved the problem you have. @xref{Asking questions}.
-
-However, by purchasing basic e-mail support, you also have access to the
-support address @email{mysql-support@@mysql.com}, which is not available
-as part of the minimal support that you get by purchasing a MySQL
-license. This means that for especially critical questions, you can
-cross-post your message to @email{mysql-support@@mysql.com}. (If the
-message contains sensitive data, you should post only to
-@email{mysql-support@@mysql.com}.)
-
-@strong{REMEMBER!} to ALWAYS include your registration number and expiration
-date when you send a message to @email{mysql-support@@mysql.com}.
-
-Note that if you have encountered a critical, repeatable bug, and follow
-the rules outlined in the manual section of how to report bugs and send
-it to @email{bugs@@lists.mysql.com}, we promise to try to fix this as
-soon as possible, regardless of your support level! @xref{Bug reports}.
-
-Basic e-mail support includes the following types of service:
-
-@itemize @bullet
-@item
-If your question is already answered in the manual, we will inform you of the
-correct section in which you can find the answer. If the answer is not in
-the manual, we will point you in the right direction to solve your problem.
-
-@item
-We guarantee a timely answer for your e-mail messages. We can't guarantee
-that we can solve any problem, but at least you will receive an answer if we
-can contact you by e-mail.
-
-@item
-We will help with unexpected problems when you install MySQL from a
-binary distribution on supported platforms. This level of support does not
-cover installing MySQL from a source distribution. Supported
-platforms are those for which MySQL is known to work.
-@xref{Which OS}.
-
-@item
-We will help you with bugs and missing features. Any bugs that are found are
-fixed for the next MySQL release. If the bug is critical for
-you, we will mail you a patch for it as soon the bug is fixed. Critical
-bugs always have the highest priority for us, and we ensure that they are
-fixed as soon as possible.
-
-@item
-Your suggestions for the further development of MySQL will be
-taken into consideration. By taking email support you have already
-helped the further development of MySQL. If you want to have
-more input, upgrade to a higher level of support.
-
-@item
-If you want us to help optimize your system, you must upgrade to a
-higher level of support.
-@end itemize
-
-
-@node Extended email support, Login support, Basic email support, Support
-@subsubsection Extended E-mail Support
-
-@cindex extended email support
-
-Extended e-mail support includes everything in basic e-mail support with
-these additions:
-
-@itemize @bullet
-@item
-Your e-mail will be dealt with before mail from basic e-mail support users and
-non-registered users.
-
-@item
-Your suggestions for the further development of MySQL will
-receive strong consideration. Simple extensions that suit the basic
-goals of MySQL are implemented in a matter of days. By taking
-extended e-mail support you have already helped the further development
-of MySQL.
-
-@item
-Typical situations that are covered by extended e-mail support are:
-
-@itemize @minus
-@item
-We will answer and (within reason) solve questions that relate to possible
-bugs in MySQL. As soon as the bug is found and corrected, we
-will mail a patch for it.
-
-@item
-We will help with unexpected problems when you install MySQL from a
-source or binary distribution on supported platforms.
-
-@item
-We will answer questions about missing features and offer hints how to work
-around them.
-
-@item
-We will provide hints on optimizing @code{mysqld} for your situation.
-@end itemize
-
-@item
-You are allowed to influence the priority of items on the MySQL
-TODO List. @xref{TODO}. This will ensure that the features you really need
-will be implemented sooner than they might be otherwise.
-@end itemize
-
-
-@node Login support, Extended login support, Extended email support, Support
-@subsubsection Login Support
-
-@cindex login support
-
-Login support includes everything in extended e-mail support with
-these additions:
-
-@itemize @bullet
-@item
-Your e-mail will be dealt with even before e-mail from extended e-mail
-support users.
-@item
-Your suggestions for the further development of MySQL will
-be taken into very high consideration. Realistic extensions that can be
-implemented in a couple of hours and that suit the basic goals of
-MySQL will be implemented as soon as possible.
+@node Standards, ANSI mode, Compatibility, Compatibility
+@subsection What Standards Does MySQL Follow?
-@item
-If you have a very specific problem, we can try to log in on your system
-to solve the problem ``in place.''
+Entry level SQL92. ODBC levels 0-3.51.
-@item
-Like any database vendor, we can't guarantee that we can rescue any data from
-crashed tables, but if the worst happens, we will help you rescue as much as
-possible. MySQL has proven itself very reliable, but anything is
-possible due to circumstances beyond our control (for example, if your system
-crashes or someone kills the server by executing a @code{kill -9} command).
+We are aiming towards supporting the full ANSI SQL99 standard,
+but without concessions to speed and quality of the code.
-@item
-We will provide hints on optimizing your system and your queries.
-
-@item
-You are allowed to call a MySQL developer (in moderation) and
-discuss your MySQL-related problems. This option is however
-only to be used as a last result during an emergency after we have
-failed to grasp the total problem with email. To make efficient
-use of our time we need to first get all facts about the problem,
-before talking on phone, to be able to work as efficiently as possible on
-solving the problem.
-@end itemize
+@node ANSI mode, Extensions to ANSI, Standards, Compatibility
+@subsection Running MySQL in ANSI Mode
-@node Extended login support, Telephone support, Login support, Support
-@subsubsection Extended Login Support
+@cindex running, ANSI mode
+@cindex ANSI mode, running
-Extended login support includes everything in login support with these
-additions:
+If you start @code{mysqld} with the @code{--ansi} option, the following
+behavior of MySQL Server changes:
@itemize @bullet
@item
-Your e-mail has the highest possible priority.
-
-@item
-We will actively examine your system and help you optimize it and your
-queries. We may also optimize and/or extend MySQL to better
-suit your needs.
+@code{||} is string concatenation instead of @code{OR}.
@item
-You may also request special extensions just for you. For example:
-@example
-mysql> select MY_FUNC(col1,col2) from table;
-@end example
+You can have any number of spaces between a function name and the @samp{(}.
+This forces all function names to be treated as reserved words.
@item
-We will provide a binary distribution of all important MySQL
-releases for your system, as long as we can get an account on a
-similar system. In the worst case, we may require access to your system
-to be able to create a binary distribution.
+@samp{"} will be an identifier quote character (like the MySQL Server
+@samp{`} quote character) and not a string quote character.
@item
-If you can provide accommodations and pay for traveler fares, you can
-even get a MySQL developer to visit you and offer you help with
-your troubles. Extended login support entitles you to one personal
-encounter per year, but we are always very flexible towards our
-customers! If the visit takes 16 hours or more, the first 8 hours is
-without charge. For the hours above 8 hours, you will be charged with a
-rate that is at least 20 % less than our standard rates.
-@end itemize
-
-
-@node Telephone support, Table handler support, Extended login support, Support
-@subsubsection Telephone Support
-
-Telephone support includes everything in extended login support with
-these additions:
+@code{REAL} will be a synonym for @code{FLOAT} instead of a synonym of
+@code{DOUBLE}.
-@itemize @bullet
-@item
-We will provide you with a dynamic web page showing the current list of
-@code{MySQL} developers that you can phone when you have a critical
-problem.
@item
-For non critical problem, you can request a MySQL developer to
-phone back within 48 hours to discuss @code{MySQL} related issues.
+The default transaction isolation level is @code{SERIALIZABLE}.
+@xref{SET TRANSACTION}.
@end itemize
+This is the same as using
+@code{--sql-mode=REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,
+IGNORE_SPACE,SERIALIZE,ONLY_FULL_GROUP_BY}.
-@node Table handler support, , Telephone support, Support
-@subsubsection Support for other table handlers
-
-@cindex support, BDB Tables
-@cindex support, InnoDB Tables
-
-To get support for @code{BDB} tables, @code{InnoDB} tables you have
-to pay an additional 30% on the standard support price for each of
-the table handlers you would like to have support for.
-
-We at @code{MySQL AB} will help you create a proper bug report for the
-table handler and submit it to the developers for the specific table
-handler. We will also do our best to ensure that you will get a timely
-answer or solution from the developers of the table handler.
-
-Even if we are quite confident that we can solve most problems within a
-timely manner, we can't guarantee a quick solution for any problems you
-can get with the different table handlers. We will however do our best
-to help you get the problem solved.
-
-
-@node Compatibility, Comparisons, Licensing and Support, Introduction
-@section How Standards-compatible Is MySQL?
-@cindex compatibility, with ANSI SQL
-@cindex standards compatibility
-@cindex extensions, to ANSI SQL
-@cindex ANSI SQL92, extensions to
-
-@menu
-* Extensions to ANSI:: MySQL extensions to ANSI SQL92
-* Differences from ANSI:: MySQL differences compared to ANSI SQL92
-* ANSI mode:: Running MySQL in ANSI mode
-* Missing functions:: Functionality missing from MySQL
-* Standards:: What standards does MySQL follow?
-* Commit-rollback:: How to cope without @code{COMMIT}-@code{ROLLBACK}
-* Bugs:: Known errors and design deficiencies in MySQL
-@end menu
-
-This section describes how MySQL relates to the ANSI SQL standards.
-MySQL has many extensions to the ANSI SQL standards, and here you
-will find out what they are, and how to use them. You will also find
-information about functionality missing from MySQL, and how to work
-around some differences.
-
-
-@node Extensions to ANSI, Differences from ANSI, Compatibility, Compatibility
+@node Extensions to ANSI, Differences from ANSI, ANSI mode, Compatibility
@subsection MySQL Extensions to ANSI SQL92
-MySQL includes some extensions that you probably will not find in
+@cindex hints
+MySQL Server includes some extensions that you probably will not find in
other SQL databases. Be warned that if you use them, your code will not be
portable to other SQL servers. In some cases, you can write code that
includes MySQL extensions, but is still portable, by using comments
-of the form @code{/*! ... */}. In this case, MySQL will parse and
+of the form @code{/*! ... */}. In this case, MySQL Server will parse and
execute the code within the comment as it would any other MySQL
statement, but other SQL servers will ignore the extensions. For example:
@@ -3418,7 +2653,7 @@ CREATE /*!32302 TEMPORARY */ TABLE (a int);
@end example
The above means that if you have Version 3.23.02 or newer, then MySQL
-will use the @code{TEMPORARY} keyword.
+Server will use the @code{TEMPORARY} keyword.
MySQL extensions are listed below:
@@ -3440,7 +2675,7 @@ comparisons to be done according to the ASCII order used on the
MySQL server host.
@item
-MySQL maps each database to a directory under the MySQL
+MySQL Server maps each database to a directory under the MySQL
data directory, and tables within a database to filenames in the database
directory.
@@ -3454,7 +2689,7 @@ This has a few implications:
@itemize @minus
@item
-Database names and table names are case sensitive in MySQL on
+Database names and table names are case sensitive in MySQL Server on
operating systems that have case-sensitive filenames (like most Unix
systems). @xref{Name case sensitivity}.
@@ -3472,7 +2707,7 @@ and @file{.frm} files to which the table corresponds.
In SQL statements, you can access tables from different databases
with the @code{db_name.tbl_name} syntax. Some SQL servers provide
the same functionality but call this @code{User space}.
-MySQL doesn't support tablespaces as in:
+MySQL Server doesn't support tablespaces as in:
@code{create table ralph.my_table...IN my_tablespace}.
@item
@@ -3562,18 +2797,18 @@ One can specify @code{ASC} and @code{DESC} with @code{GROUP BY}.
@item
To make it easier for users who come from other SQL environments,
-MySQL supports aliases for many functions. For example, all
+MySQL Server supports aliases for many functions. For example, all
string functions support both ANSI SQL syntax and ODBC syntax.
@item
-MySQL understands the @code{||} and @code{&&} operators to mean
-logical OR and AND, as in the C programming language. In MySQL,
+MySQL Server understands the @code{||} and @code{&&} operators to mean
+logical OR and AND, as in the C programming language. In MySQL Server,
@code{||} and @code{OR} are synonyms, as are @code{&&} and @code{AND}.
-Because of this nice syntax, MySQL doesn't support
+Because of this nice syntax, MySQL Server doesn't support
the ANSI SQL @code{||} operator for string concatenation; use
@code{CONCAT()} instead. Because @code{CONCAT()} takes any number
of arguments, it's easy to convert use of the @code{||} operator to
-MySQL.
+MySQL Server.
@item
@code{CREATE DATABASE} or @code{DROP DATABASE}.
@@ -3606,12 +2841,12 @@ operators.
@item
@code{CONCAT()} or @code{CHAR()} with one argument or more than two
-arguments. (In MySQL, these functions can take any number of
+arguments. (In MySQL Server, these functions can take any number of
arguments.)
@item The @code{BIT_COUNT()}, @code{CASE}, @code{ELT()},
@code{FROM_DAYS()}, @code{FORMAT()}, @code{IF()}, @code{PASSWORD()},
-@code{ENCRYPT()}, @code{md5()}, @code{ENCODE()}, @code{DECODE()},
+@code{ENCRYPT()}, @code{MD5()}, @code{ENCODE()}, @code{DECODE()},
@code{PERIOD_ADD()}, @code{PERIOD_DIFF()}, @code{TO_DAYS()}, or
@code{WEEKDAY()} functions.
@@ -3631,7 +2866,7 @@ Use of @code{REPLACE} instead of @code{DELETE} + @code{INSERT}.
The @code{FLUSH}, @code{RESET} and @code{DO} statements.
@item
-The possibility to set variables in a statement with @code{:=}:
+The ability to set variables in a statement with @code{:=}:
@example
SELECT @@a:=SUM(total),@@b=COUNT(*),@@a/@@b AS avg FROM test_table;
SELECT @@t1:=(@@t2:=1)+@@t3:=4,@@t1,@@t2,@@t3;
@@ -3640,19 +2875,15 @@ SELECT @@t1:=(@@t2:=1)+@@t3:=4,@@t1,@@t2,@@t3;
@end itemize
-@node Differences from ANSI, ANSI mode, Extensions to ANSI, Compatibility
+@node Differences from ANSI, Bugs, Extensions to ANSI, Compatibility
@subsection MySQL Differences Compared to ANSI SQL92
-We try to make MySQL follow the ANSI SQL standard and the
-ODBC SQL standard, but in some cases MySQL does some things
+We try to make MySQL Server follow the ANSI SQL standard and the
+ODBC SQL standard, but in some cases MySQL Server does things
differently:
@itemize @bullet
@item
-@code{--} is only a comment if followed by a white space. @xref{Missing
-comments}.
-
-@item
For @code{VARCHAR} columns, trailing spaces are removed when the value is
stored. @xref{Bugs}.
@@ -3671,74 +2902,33 @@ This is because we don't think it's good to have to evaluate a lot of
extra conditions in this case.
@end itemize
-
-@node ANSI mode, Missing functions, Differences from ANSI, Compatibility
-@subsection Running MySQL in ANSI Mode
-
-@cindex running, ANSI mode
-@cindex ANSI mode, running
-
-If you start @code{mysqld} with the @code{--ansi} option, the following
-behavior of MySQL changes:
-
-@itemize @bullet
-@item
-@code{||} is string concatenation instead of @code{OR}.
-
-@item
-You can have any number of spaces between a function name and the @samp{(}.
-This forces all function names to be treated as reserved words.
-
-@item
-@samp{"} will be an identifier quote character (like the MySQL
-@samp{`} quote character) and not a string quote character.
-
-@item
-@code{REAL} will be a synonym for @code{FLOAT} instead of a synonym of
-@code{DOUBLE}.
-
-@item
-The default transaction isolation level is @code{SERIALIZABLE}.
-@xref{SET TRANSACTION}.
-@end itemize
-
-This is the same as using @code{--sql-mode=REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,SERIALIZE,ONLY_FULL_GROUP_BY}.
-
-@node Missing functions, Standards, ANSI mode, Compatibility
-@subsection Functionality Missing from MySQL
-
-@cindex missing functionality
-@cindex functionality, missing
-
-The following functionality is missing in the current version of
-MySQL. For a prioritized list indicating when new extensions
-may be added to MySQL, you should consult
-@uref{http://www.mysql.com/documentation/manual.php?section=TODO, the
-online MySQL TODO list}. That is the latest version of the TODO
-list in this manual. @xref{TODO}.
-
@menu
-* Missing Sub-selects:: Sub-selects
-* Missing SELECT INTO TABLE:: @code{SELECT INTO TABLE}
-* Missing Transactions:: Transactions
-* Missing Triggers:: Triggers
-* Missing Foreign Keys:: Foreign Keys
-* Broken Foreign KEY:: Reasons NOT to Use Foreign Keys constraints
-* Missing Views:: Views
-* Missing comments:: @samp{--} as the start of a comment
+* ANSI diff Sub-selects:: Sub-@code{SELECT}s
+* ANSI diff SELECT INTO TABLE:: @code{SELECT INTO TABLE}
+* ANSI diff Transactions:: Transactions and Atomic Operations
+* ANSI diff Triggers:: Stored Procedures and Triggers
+* ANSI diff Foreign Keys:: Foreign Keys
+* ANSI diff Views:: Views
+* ANSI diff comments:: @samp{--} as the Start of a Comment
@end menu
+For a prioritised list indicating when new extensions will be added to
+MySQL Server, you should consult the online MySQL TODO list at
+@uref{http://www.mysql.com/documentation/manual.php?section=TODO}.
+That is the latest version of the TODO list in this manual. @xref{TODO}.
+
-@node Missing Sub-selects, Missing SELECT INTO TABLE, Missing functions, Missing functions
-@subsubsection Sub-selects
+@node ANSI diff Sub-selects, ANSI diff SELECT INTO TABLE, Differences from ANSI, Differences from ANSI
+@subsubsection Sub-@code{SELECT}s
@cindex sub-selects
-MySQL currently only supports sub selects of the form @code{INSERT
-... SELECT ...} and @code{REPLACE ... SELECT ...}. You can however use
-the function @code{IN()} in other contexts.
+MySQL Server currently only supports nested queries of the form
+@code{INSERT ... SELECT ...} and @code{REPLACE ... SELECT ...}.
+You can however use the function @code{IN()} in other contexts.
+Sub-selects are scheduled for implementation in Version 4.x.
-In many cases you can rewrite the query without a sub-select:
+Meanwhile, you can often rewrite the query without a sub-select:
@example
SELECT * FROM table1 WHERE id IN (SELECT id FROM table2);
@@ -3753,13 +2943,15 @@ SELECT table1.* FROM table1,table2 WHERE table1.id=table2.id;
The queries:
@example
SELECT * FROM table1 WHERE id NOT IN (SELECT id FROM table2);
-SELECT * FROM table1 WHERE NOT EXISTS (SELECT id FROM table2 where table1.id=table2.id);
+SELECT * FROM table1 WHERE NOT EXISTS (SELECT id FROM table2
+ WHERE table1.id=table2.id);
@end example
Can be rewritten as:
@example
-SELECT table1.* FROM table1 LEFT JOIN table2 ON table1.id=table2.id where table2.id IS NULL
+SELECT table1.* FROM table1 LEFT JOIN table2 ON table1.id=table2.id
+ WHERE table2.id IS NULL;
@end example
For more complicated subqueries you can often create temporary tables
@@ -3767,7 +2959,7 @@ to hold the subquery. In some cases, however this option will not
work. The most frequently encountered of these cases arises with
@code{DELETE} statements, for which standard SQL does not support joins
(except in sub-selects). For this situation there are two options
-available until subqueries are supported by MySQL.
+available until subqueries are supported by MySQL Server.
The first option is to use a procedural programming language (such as
Perl or PHP) to submit a @code{SELECT} query to obtain the primary keys
@@ -3775,7 +2967,7 @@ for the records to be deleted, and then use these values to construct
the @code{DELETE} statement (@code{DELETE FROM ... WHERE ... IN (key1,
key2, ...)}).
-The second option is to use interactive SQL to contruct a set of
+The second option is to use interactive SQL to construct a set of
@code{DELETE} statements automatically, using the MySQL
extension @code{CONCAT()} (in lieu of the standard @code{||} operator).
For example:
@@ -3791,149 +2983,230 @@ the @code{mysql} command-line interpreter, piping its output back to a
second instance of the interpreter:
@example
-prompt> mysql --skip-column-names mydb < myscript.sql | mysql mydb
+shell> mysql --skip-column-names mydb < myscript.sql | mysql mydb
@end example
-MySQL 4.0 supports multi-table deletes that can be used to efficiently
-delete rows based on information from one table or even from many tables
-at the same time.
+MySQL Server 4.0 supports multi-table deletes that can be used to
+efficiently delete rows based on information from one table or even
+from many tables at the same time.
+
-@node Missing SELECT INTO TABLE, Missing Transactions, Missing Sub-selects, Missing functions
+@node ANSI diff SELECT INTO TABLE, ANSI diff Transactions, ANSI diff Sub-selects, Differences from ANSI
@subsubsection @code{SELECT INTO TABLE}
@findex SELECT INTO TABLE
-MySQL doesn't yet support the Oracle SQL extension:
-@code{SELECT ... INTO TABLE ...}. MySQL supports instead the
+MySQL Server doesn't yet support the Oracle SQL extension:
+@code{SELECT ... INTO TABLE ...}. MySQL Server supports instead the
ANSI SQL syntax @code{INSERT INTO ... SELECT ...}, which is basically
the same thing. @xref{INSERT SELECT}.
@example
-INSERT INTO tblTemp2 (fldID) SELECT tblTemp1.fldOrder_ID FROM tblTemp1 WHERE
-tblTemp1.fldOrder_ID > 100;
+INSERT INTO tblTemp2 (fldID) SELECT tblTemp1.fldOrder_ID
+ FROM tblTemp1 WHERE tblTemp1.fldOrder_ID > 100;
@end example
Alternatively, you can use @code{SELECT INTO OUTFILE...} or @code{CREATE
-TABLE ... SELECT} to solve your problem.
+TABLE ... SELECT}.
-@node Missing Transactions, Missing Triggers, Missing SELECT INTO TABLE, Missing functions
-@subsubsection Transactions
+@node ANSI diff Transactions, ANSI diff Triggers, ANSI diff SELECT INTO TABLE, Differences from ANSI
+@subsubsection Transactions and Atomic Operations
+@findex COMMIT
+@findex ROLLBACK
@cindex transactions, support
-
-As MySQL does nowadays support transactions, the following
-discussion is only valid if you are only using the non-transaction-safe
-table types. @xref{COMMIT}.
-
-The question is often asked, by the curious and the critical, ``Why is
-MySQL not a transactional database?'' or ``Why does MySQL
-not support transactions?''
-
-MySQL has made a conscious decision to support another paradigm
-for data integrity, ``atomic operations.'' It is our thinking and
-experience that atomic operations offer equal or even better integrity
-with much better performance. We, nonetheless, appreciate and understand
-the transactional database paradigm and plan, within the next few releases,
-to introduce transaction-safe tables on a per table basis. We will be
-giving our users the possibility to decide if they need the speed of
-atomic operations or if they need to use transactional features in their
-applications.
-
-How does one use the features of MySQL to maintain rigorous integrity
+@cindex transaction-safe tables
+@cindex tables, updating
+@cindex updating, tables
+@cindex @code{InnoDB} tables
+@cindex @code{BDB} tables
+@cindex @code{ACID}
+
+MySQL Server supports transactions with the @code{InnoDB} and @code{BDB}
+@code{Transactional table handlers}. @xref{Table types}.
+@code{InnoDB} provides @code{ACID} compliancy.
+
+However, the non-transactional table types in MySQL Server such as
+@code{MyISAM} follow another paradigm for data integrity called
+``@code{Atomic Operations}.'' Atomic operations often offer equal or
+even better integrity with much better performance.
+With MySQL Server supporting both paradigms, the user is able to decide if
+they need the speed of atomic operations or if they need to use
+transactional features in their applications. This choice can be made
+on a per-table basis.
+
+How does one use the features of MySQL Server to maintain rigorous integrity
and how do these features compare with the transactional paradigm?
-First, in the transactional paradigm, if your applications are written
-in a way that is dependent on the calling of ``rollback'' instead of
-``commit'' in critical situations, then transactions are more
-convenient. Moreover, transactions ensure that unfinished updates or
+@enumerate
+@item
+In the transactional paradigm, if your applications are written in a
+way that is dependent on the calling of @code{ROLLBACK} instead of
+@code{COMMIT} in critical situations, then transactions are more
+convenient. Transactions also ensure that unfinished updates or
corrupting activities are not committed to the database; the server is
given the opportunity to do an automatic rollback and your database is
saved.
-MySQL, in almost all cases, allows you to solve for potential
-problems by including simple checks before updates and by running simple
-scripts that check the databases for inconsistencies and automatically
-repair or warn if such occurs. Note that just by using the
-MySQL log or even adding one extra log, one can normally fix
-tables perfectly with no data integrity loss.
-
-Moreover, fatal transactional updates can be rewritten to be
-atomic. In fact,we will go so far as to say that all integrity problems
-that transactions solve can be done with @code{LOCK TABLES} or atomic updates,
-ensuring that you never will get an automatic abort from the database,
-which is a common problem with transactional databases.
-
-Not even transactions can prevent all loss if the server goes down. In
-such cases even a transactional system can lose data. The difference
-between different systems lies in just how small the time-lap is where
-they could lose data. No system is 100% secure, only ``secure
-enough.'' Even Oracle, reputed to be the safest of transactional
-databases, is reported to sometimes lose data in such situations.
-
-To be safe with MySQL, you only need to have backups and have
-the update logging turned on. With this you can recover from any
-situation that you could with any transactional database. It is, of
-course, always good to have backups, independent of which database you
-use.
+MySQL Server, in almost all cases, allows you to resolve potential problems
+by including simple checks before updates and by running simple scripts
+that check the databases for inconsistencies and automatically repair
+or warn if such an inconsistency occurs. Note that just by using the
+MySQL log or even adding one extra log, one can normally fix tables
+perfectly with no data integrity loss.
+
+@item
+More often than not, fatal transactional updates can be rewritten to be
+atomic. Generally speaking, all integrity problems that transactions
+solve can be done with @code{LOCK TABLES} or atomic updates, ensuring
+that you never will get an automatic abort from the database, which is
+a common problem with transactional databases.
+
+@item
+Even a transactional system can lose data if the server goes down.
+The difference between different systems lies in just how small the
+time-lap is where they could lose data. No system is 100% secure, only
+``secure enough.'' Even Oracle, reputed to be the safest of
+transactional databases, is reported to sometimes lose data in such
+situations.
+
+To be safe with MySQL Server, whether using transactional tables or not, you
+only need to have backups and have the update logging turned on. With
+this you can recover from any situation that you could with any
+other transactional database. It is, of course, always good to have
+backups, independent of which database you use.
+@end enumerate
The transactional paradigm has its benefits and its drawbacks. Many
-users and application developers depend on the ease with which they can
-code around problems where an abort appears to be, or is necessary, and they
-may have to do a little more work with MySQL to either think
-differently or write more. If you are new to the atomic operations
-paradigm, or more familiar or more comfortable with transactions, do not
-jump to the conclusion that MySQL has not addressed these
-issues. Reliability and integrity are foremost in our minds. Recent
-estimates indicate that there are more than 1,000,000 @code{mysqld} servers
-currently running, many of which are in production environments. We
-hear very, very seldom from our users that they have lost any data, and
-in almost all of those cases user error is involved. This is, in our
-opinion, the best proof of MySQL's stability and reliability.
-
-Lastly, in situations where integrity is of highest importance,
-MySQL's current features allow for transaction-level or better
-reliability and integrity. If you lock tables with @code{LOCK TABLES}, all
-updates will stall until any integrity checks are made. If you only obtain
-a read lock (as opposed to a write lock), then reads and inserts are
-still allowed to happen. The new inserted records will not be seen by
-any of the clients that have a @code{READ} lock until they release their read
-locks. With @code{INSERT DELAYED} you can queue inserts into a local queue,
-until the locks are released, without having the client wait for the insert
-to complete. @xref{INSERT DELAYED}.
-
-``Atomic,'' in the sense that we mean it, is nothing magical. It only means
-that you can be sure that while each specific update is running, no other
-user can interfere with it, and there will never be an automatic
-rollback (which can happen on transaction based systems if you are not
-very careful). MySQL also guarantees that there will not be
-any dirty reads. You can find some example of how to write atomic updates
-in the commit-rollback section. @xref{Commit-rollback}.
-
-We have thought quite a bit about integrity and performance, and we
-believe that our atomic operations paradigm allows for both high
-reliability and extremely high performance, on the order of three to
-five times the speed of the fastest and most optimally tuned of
-transactional databases. We didn't leave out transactions because they
-are hard to do. The main reason we went with atomic operations as
-opposed to transactions is that by doing this we could apply many speed
-optimizations that would not otherwise have been possible.
-
-Many of our users who have speed foremost in their minds are not at all
-concerned about transactions. For them transactions are not an
-issue. For those of our users who are concerned with or have wondered
-about transactions vis-a-vis MySQL, there is a ``MySQL
-way'' as we have outlined above. For those where safety is more
-important than speed, we recommend them to use the @code{BDB},
-or @code{InnoDB} tables for all their critical data. @xref{Table types}.
-
-One final note: We are currently working on a safe replication schema
-that we believe to be better than any commercial replication system we
-know of. This system will work most reliably under the atomic
-operations, non-transactional, paradigm. Stay tuned.
-
-
-@node Missing Triggers, Missing Foreign Keys, Missing Transactions, Missing functions
+users and application developers depend on the ease with which they
+can code around problems where an abort appears to be, or is necessary.
+However, even if you are new to the atomic operations paradigm, or more
+familiar with transactions, do consider the speed benefit that
+non-transactional tables can offer, on the order of three to five times
+the speed of the fastest and most optimally tuned transactional tables.
+
+In situations where integrity is of highest importance, MySQL Server offers
+transaction-level or better reliability and integrity even for
+non-transactional tables.
+If you lock tables with @code{LOCK TABLES}, all updates will stall
+until any integrity checks are made. If you only obtain a read lock
+(as opposed to a write lock), then reads and inserts are still allowed
+to happen. The new inserted records will not be seen by any of the
+clients that have a @code{READ} lock until they release their read
+locks. With @code{INSERT DELAYED} you can queue inserts into a local
+queue, until the locks are released, without having the client wait
+for the insert to complete. @xref{INSERT DELAYED}.
+
+``Atomic,'' in the sense that we mean it, is nothing magical. It only
+means that you can be sure that while each specific update is running,
+no other user can interfere with it, and there will never be an
+automatic rollback (which can happen with transactional tables if you
+are not very careful). MySQL Server also guarantees that there will not be
+any dirty reads.
+
+Following are some techniques for working with non-transactional tables:
+
+@itemize @bullet
+@item
+Loops that need transactions normally can be coded with the help of
+@code{LOCK TABLES}, and you don't need cursors when you can update
+records on the fly.
+
+@item
+To avoid using @code{ROLLBACK}, you can use the following strategy:
+
+@enumerate
+@item
+Use @code{LOCK TABLES ...} to lock all the tables you want to access.
+@item
+Test conditions.
+@item
+Update if everything is okay.
+@item
+Use @code{UNLOCK TABLES} to release your locks.
+@end enumerate
+
+This is usually a much faster method than using transactions with
+possible @code{ROLLBACK}s, although not always. The only situation
+this solution doesn't handle is when someone kills the threads in the
+middle of an update. In this case, all locks will be released but some
+of the updates may not have been executed.
+
+@item
+You can also use functions to update records in a single operation.
+You can get a very efficient application by using the following
+techniques:
+
+@itemize @bullet
+@item Modify fields relative to their current value.
+@item Update only those fields that actually have changed.
+@end itemize
+
+For example, when we are doing updates to some customer information, we
+update only the customer data that has changed and test only that none of
+the changed data, or data that depend on the changed data, has changed
+compared to the original row. The test for changed data is done with the
+@code{WHERE} clause in the @code{UPDATE} statement. If the record wasn't
+updated, we give the client a message: "Some of the data you have changed
+have been changed by another user". Then we show the old row versus the new
+row in a window, so the user can decide which version of the customer record
+he should use.
+
+This gives us something that is similar to column locking but is actually
+even better, because we only update some of the columns, using values that
+are relative to their current values. This means that typical @code{UPDATE}
+statements look something like these:
+
+@example
+UPDATE tablename SET pay_back=pay_back+'relative change';
+
+UPDATE customer
+ SET
+ customer_date='current_date',
+ address='new address',
+ phone='new phone',
+ money_he_owes_us=money_he_owes_us+'new_money'
+ WHERE
+ customer_id=id AND address='old address' AND phone='old phone';
+@end example
+
+As you can see, this is very efficient and works even if another client
+has changed the values in the @code{pay_back} or @code{money_he_owes_us}
+columns.
+
+@item
+@findex mysql_insert_id()
+@findex LAST_INSERT_ID()
+In many cases, users have wanted @code{ROLLBACK} and/or @code{LOCK
+TABLES} for the purpose of managing unique identifiers for some tables.
+This can be handled much more efficiently by using an
+@code{AUTO_INCREMENT} column and either the SQL function
+@code{LAST_INSERT_ID()} or the C API function @code{mysql_insert_id()}.
+@xref{mysql_insert_id, , @code{mysql_insert_id()}}.
+
+@cindex rows, locking
+@cindex locking, row-level
+Generally, you can code around row-level locking. Some cases really
+need it, but they are very few. For instance, you can use a flag
+column in the table and do something like this:
+
+@example
+UPDATE tbl_name SET row_flag=1 WHERE id=ID;
+@end example
+
+MySQL returns 1 for the number of affected rows if the row was
+found and @code{row_flag} wasn't already 1 in the original row.
+
+You can think of it as MySQL Server changed the above query to:
+
+@example
+UPDATE tbl_name SET row_flag=1 WHERE id=ID and row_flag <> 1;
+@end example
+@end itemize
+
+
+@node ANSI diff Triggers, ANSI diff Foreign Keys, ANSI diff Transactions, Differences from ANSI
@subsubsection Stored Procedures and Triggers
@cindex stored procedures and triggers, defined
@@ -3953,14 +3226,12 @@ each time a record is deleted from a transaction table and that automatically
deletes the corresponding customer from a customer table when all his
transactions are deleted.
-The planned update language will be able to
-handle stored procedures, but without triggers. Triggers usually slow
-down everything, even queries for which they are not needed.
-
-To see when MySQL might get stored procedures, see @ref{TODO}.
+The planned update language will be able to handle stored procedures.
+Our aim is to have stored procedures implemented in MySQL Server 4.1.
+We are also looking at triggers.
-@node Missing Foreign Keys, Broken Foreign KEY, Missing Triggers, Missing functions
+@node ANSI diff Foreign Keys, ANSI diff Views, ANSI diff Triggers, Differences from ANSI
@subsubsection Foreign Keys
@cindex foreign keys
@@ -3977,151 +3248,135 @@ SELECT * from table1,table2 where table1.id = table2.id;
@xref{JOIN, , @code{JOIN}}. @xref{example-Foreign keys}.
-The @code{FOREIGN KEY} syntax in MySQL exists only for compatibility
-with other SQL vendors' @code{CREATE TABLE} commands; it doesn't do
-anything. The @code{FOREIGN KEY} syntax without @code{ON DELETE ...} is
-mostly used for documentation purposes. Some ODBC applications may use this
-to produce automatic @code{WHERE} clauses, but this is usually easy to
-override. @code{FOREIGN KEY} is sometimes used as a constraint check, but
-this check is unnecessary in practice if rows are inserted into the tables in
-the right order. MySQL only supports these clauses because some
-applications require them to exist (regardless of whether or not they
-work).
-
-In MySQL, you can work around the problem of @code{ON DELETE
-...} not being implemented by adding the appropriate @code{DELETE} statement to
-an application when you delete records from a table that has a foreign key.
-In practice this is as quick (in some cases quicker) and much more portable
-than using foreign keys.
-
-In the near future we will extend the @code{FOREIGN KEY} implementation so
-that at least the information will be saved in the table specification file
-and may be retrieved by @code{mysqldump} and ODBC. At a later stage we will
-implement the foreign key constraints for application that can't easily be
-coded to avoid them.
-
-@menu
-* Broken Foreign KEY:: Reasons NOT to use foreign keys constraints
-@end menu
+In MySQL Server 3.23.44 and up, @code{InnoDB} tables supports checking of
+foreign key constraints. @xref{InnoDB}. For other table types, MySQL Server
+does parse the @code{FOREIGN KEY} syntax in @code{CREATE TABLE}
+commands, but without further action being taken.
+The @code{FOREIGN KEY} syntax without @code{ON DELETE ...} is mostly
+used for documentation purposes. Some ODBC applications may use this
+to produce automatic @code{WHERE} clauses, but this is usually easy to
+override. @code{FOREIGN KEY} is sometimes used as a constraint check,
+but this check is unnecessary in practice if rows are inserted into the
+tables in the right order.
+
+In MySQL Server, you can work around the problem of @code{ON DELETE ...} not
+being implemented by adding the appropriate @code{DELETE} statement to
+an application when you delete records from a table that has a foreign
+key. In practice this is as quick (in some cases quicker) and much more
+portable than using foreign keys.
+
+In MySQL Server 4.0 you can use multi-table delete to delete rows from many
+tables with one command. @xref{DELETE}.
+
+In the near future we will extend the @code{FOREIGN KEY} implementation
+so that the information will be saved in the table specification file
+and may be retrieved by @code{mysqldump} and ODBC. At a later stage we
+will implement the foreign key constraints for applications that can't
+easily be coded to avoid them.
+
+Do keep in mind that foreign keys are often misused, which can cause
+severe problems. Even when used properly, it is not a magic solution for
+the referential integrity problem, although it does make things easier
+in some cases.
-@node Broken Foreign KEY, Missing Views, Missing Foreign Keys, Missing functions
-@subsubsection Reasons NOT to Use Foreign Keys constraints
-
-@cindex foreign keys, reasons not to use
-
-There are so many problems with foreign key constraints that we don't
-know where to start:
+Some advantages of foreign key enforcement:
@itemize @bullet
@item
-Foreign key constraints make life very complicated, because the foreign
-key definitions must be stored in a database and implementing them would
-destroy the whole ``nice approach'' of using files that can be moved,
-copied, and removed.
+Assuming proper design of the relations, foreign key constraints will
+make it more difficult for a programmer to introduce an inconsistency
+into the database.
@item
-The speed impact is terrible for @code{INSERT} and @code{UPDATE}
-statements, and in this case almost all @code{FOREIGN KEY} constraint
-checks are useless because you usually insert records in the right
-tables in the right order, anyway.
+Using cascading updates and deletes can simplify the client code.
@item
-There is also a need to hold locks on many more tables when updating one
-table, because the side effects can cascade through the entire database. It's
-MUCH faster to delete records from one table first and subsequently delete
-them from the other tables.
+Properly designed foreign key rules aid in documenting relations
+between tables.
+@end itemize
-@item
-You can no longer restore a table by doing a full delete from the table
-and then restoring all records (from a new source or from a backup).
+Disadvantages:
+@itemize @bullet
@item
-If you use foreign key constraints you can't dump and restore tables
-unless you do so in a very specific order.
+Mistakes, that are easy to make in designing key relations, can cause
+severe problems, for example, circular rules, or the wrong combination
+of cascading deletes.
@item
-It's very easy to do ``allowed'' circular definitions that make the
-tables impossible to re-create each table with a single create statement,
-even if the definition works and is usable.
+A properly written application will make sure internally that it is
+not violating referential integrity constraints before proceding with
+a query. Thus, additionaly checks on the database level will only slow
+down performance for such application.
@item
-It's very easy to overlook @code{FOREIGN KEY ... ON DELETE} rules when
-one codes an application. It's not unusual that one loses a lot of
-important information just because a wrong or misused @code{ON DELETE} rule.
+It is not uncommon for a DBA to make such a complex topology of
+relations that it becomes very difficult, and in some cases impossible
+to backup or restore individual tables.
@end itemize
-The only nice aspect of @code{FOREIGN KEY} is that it gives ODBC and some
-other client programs the ability to see how a table is connected and to use
-this to show connection diagrams and to help in building applications.
-
-MySQL will soon store @code{FOREIGN KEY} definitions so that a
-client can ask for and receive an answer about how the original
-connection was made. The current @file{.frm} file format does not have
-any place for it. At a later stage we will implement the foreign key
-constraints for application that can't easily be coded to avoid them.
-
-@node Missing Views, Missing comments, Broken Foreign KEY, Missing functions
+@node ANSI diff Views, ANSI diff comments, ANSI diff Foreign Keys, Differences from ANSI
@subsubsection Views
@cindex views
-MySQL doesn't yet support views, but we plan to implement these
-to about 4.1.
+It is planned to implement views in MySQL Server around Version 4.1.
Views are mostly useful for letting users access a set of relations as one
table (in read-only mode). Many SQL databases don't allow one to update
any rows in a view, but you have to do the updates in the separate tables.
-As MySQL is mostly used in applications and on web system where
+As MySQL Server is mostly used in applications and on web system where
the application writer has full control on the database usage, most of
-our users haven't regarded views to be very important. (At least no one
-has been interested enough in this to be prepared to finance the
-implementation of views).
+our users haven't regarded views to be very important.
+(At least no one has been interested enough in this to be prepared to
+finance the implementation of views).
-One doesn't need views in MySQL to restrict access to columns
-as MySQL has a very sophisticated privilege
-system. @xref{Privilege system}.
+One doesn't need views in MySQL Server to restrict access to columns
+as MySQL Server has a very sophisticated privilege system.
+@xref{Privilege system}.
-@node Missing comments, , Missing Views, Missing functions
+@node ANSI diff comments, , ANSI diff Views, Differences from ANSI
@subsubsection @samp{--} as the Start of a Comment
@cindex comments, starting
@cindex starting, comments
-Some other SQL databases use @samp{--} to start comments. MySQL
-has @samp{#} as the start comment character, even if the @code{mysql}
-command-line tool removes all lines that start with @samp{--}.
-You can also use the C comment style @code{/* this is a comment */} with
-MySQL.
+Some other SQL databases use @samp{--} to start comments.
+MySQL Server has @samp{#} as the start comment character. You can also use
+the C comment style @code{/* this is a comment */} with MySQL Server.
@xref{Comments}.
-MySQL Version 3.23.3 and above supports the @samp{--} comment style
-only if the comment is followed by a space. This is because this
-degenerate comment style has caused many problems with automatically
-generated SQL queries that have used something like the following code,
-where we automatically insert the value of the payment for
+MySQL Server Version 3.23.3 and above supports the @samp{--} comment style,
+provided the comment is followed by a space. This is because this
+comment style has caused many problems with automatically generated
+SQL queries that have used something like the following code, where
+we automatically insert the value of the payment for
@code{!payment!}:
@example
UPDATE tbl_name SET credit=credit-!payment!
@end example
-What do you think will happen when the value of @code{payment} is negative?
+Think about what happens if the value of @code{payment} is negative?
+Because @code{1--1} is legal in SQL, the consequences of allowing
+comments to start with @samp{--} are terrible.
+
+Using our implementation of this method of commenting in MySQL Server
+Version 3.23.3 and up, @code{1-- This is a comment} is actually safe.
-Because @code{1--1} is legal in SQL, we think it is terrible that
-@samp{--} means start comment.
+Another safe feature is that the @code{mysql} command-line client
+removes all lines that start with @samp{--}.
-In MySQL Version 3.23 you can, however, use:
-@code{1-- This is a comment}
-The following discussion only concerns you if you are running a MySQL
-version earlier than Version 3.23:
+The following information is only relevant if you are running a
+MySQL version earlier than Version 3.23.3:
-If you have a SQL program in a text file that contains @samp{--} comments
-you should use:
+If you have a SQL program in a text file that contains @samp{--}
+comments you should use:
@example
shell> replace " --" " #" < text-file-with-funny-comments.sql \
@@ -4148,149 +3403,8 @@ shell> replace " #" " --" -- text-file-with-funny-comments.sql
@end example
-@node Standards, Commit-rollback, Missing functions, Compatibility
-@subsection What Standards Does MySQL Follow?
-
-Entry level SQL92. ODBC levels 0-2.
-
-
-@node Commit-rollback, Bugs, Standards, Compatibility
-@subsection How to Cope Without @code{COMMIT}/@code{ROLLBACK}
-
-@findex COMMIT
-@findex ROLLBACK
-@cindex transaction-safe tables
-@cindex tables, updating
-@cindex updating, tables
-@cindex @code{BDB} tables
-@cindex @code{InnoDB} tables
-
-The following mostly applies only for @code{ISAM}, @code{MyISAM}, and
-@code{HEAP} tables. If you only use transaction-safe tables (@code{BDB},
-or @code{InnoDB} tables) in an an update, you can do
-@code{COMMIT} and @code{ROLLBACK} also with MySQL.
-@xref{COMMIT}.
-
-The problem with handling @code{COMMIT}-@code{ROLLBACK} efficiently with
-the above table types would require a completely different table layout
-than MySQL uses today. The table type would also need extra
-threads that do automatic cleanups on the tables, and the disk usage
-would be much higher. This would make these table types about 2-4 times
-slower than they are today.
-
-For the moment, we prefer implementing the SQL server language (something
-like stored procedures). With this you would very seldom really need
-@code{COMMIT}-@code{ROLLBACK.} This would also give much better performance.
-
-Loops that need transactions normally can be coded with the help of
-@code{LOCK TABLES}, and you don't need cursors when you can update records
-on the fly.
-
-We at TcX had a greater need for a real fast database than a 100%
-general database. Whenever we find a way to implement these features without
-any speed loss, we will probably do it. For the moment, there are many more
-important things to do. Check the TODO for how we prioritize things at
-the moment. (Customers with higher levels of support can alter this, so
-things may be reprioritized.)
-
-The current problem is actually @code{ROLLBACK}. Without
-@code{ROLLBACK}, you can do any kind of @code{COMMIT} action with
-@code{LOCK TABLES}. To support @code{ROLLBACK} with the above table
-types, MySQL would have to be changed to store all old records
-that were updated and revert everything back to the starting point if
-@code{ROLLBACK} was issued. For simple cases, this isn't that hard to do
-(the current @code{isamlog} could be used for this purpose), but it
-would be much more difficult to implement @code{ROLLBACK} for
-@code{ALTER/DROP/CREATE TABLE}.
-
-To avoid using @code{ROLLBACK}, you can use the following strategy:
-
-@enumerate
-@item
-Use @code{LOCK TABLES ...} to lock all the tables you want to access.
-@item
-Test conditions.
-@item
-Update if everything is okay.
-@item
-Use @code{UNLOCK TABLES} to release your locks.
-@end enumerate
-
-This is usually a much faster method than using transactions with possible
-@code{ROLLBACK}s, although not always. The only situation this solution
-doesn't handle is when someone kills the threads in the middle of an
-update. In this case, all locks will be released but some of the updates may
-not have been executed.
-
-You can also use functions to update records in a single operation.
-You can get a very efficient application by using the following techniques:
-
-@itemize @bullet
-@item Modify fields relative to their current value.
-@item Update only those fields that actually have changed.
-@end itemize
-
-For example, when we are doing updates to some customer information, we
-update only the customer data that has changed and test only that none of
-the changed data, or data that depend on the changed data, has changed
-compared to the original row. The test for changed data is done with the
-@code{WHERE} clause in the @code{UPDATE} statement. If the record wasn't
-updated, we give the client a message: "Some of the data you have changed
-have been changed by another user". Then we show the old row versus the new
-row in a window, so the user can decide which version of the customer record
-he should use.
-
-This gives us something that is similar to column locking but is actually
-even better, because we only update some of the columns, using values that
-are relative to their current values. This means that typical @code{UPDATE}
-statements look something like these:
-
-@example
-UPDATE tablename SET pay_back=pay_back+'relative change';
-
-UPDATE customer
- SET
- customer_date='current_date',
- address='new address',
- phone='new phone',
- money_he_owes_us=money_he_owes_us+'new_money'
- WHERE
- customer_id=id AND address='old address' AND phone='old phone';
-@end example
-
-As you can see, this is very efficient and works even if another client has
-changed the values in the @code{pay_back} or @code{money_he_owes_us} columns.
-
-@findex mysql_insert_id()
-@findex LAST_INSERT_ID()
-In many cases, users have wanted @code{ROLLBACK} and/or @code{LOCK
-TABLES} for the purpose of managing unique identifiers for some tables. This
-can be handled much more efficiently by using an @code{AUTO_INCREMENT} column
-and either the SQL function @code{LAST_INSERT_ID()} or the C API function
-@code{mysql_insert_id()}. @xref{mysql_insert_id, , @code{mysql_insert_id()}}.
-
-@cindex rows, locking
-At MySQL AB, we have never had any need for row-level locking
-because we have always been able to code around it. Some cases really need
-row locking, but they are very few. If you want row-level locking, you
-can use a flag column in the table and do something like this:
-
-@example
-UPDATE tbl_name SET row_flag=1 WHERE id=ID;
-@end example
-
-MySQL returns 1 for the number of affected rows if the row was
-found and @code{row_flag} wasn't already 1 in the original row.
-
-You can think of it as MySQL changed the above query to:
-
-@example
-UPDATE tbl_name SET row_flag=1 WHERE id=ID and row_flag <> 1;
-@end example
-
-
-@node Bugs, , Commit-rollback, Compatibility
-@subsection Known errors and design deficiencies in MySQL
+@node Bugs, , Differences from ANSI, Compatibility
+@subsection Known Errors and Design Deficiencies in MySQL
@cindex bugs, known
@cindex errors, known
@@ -4320,7 +3434,7 @@ will probably be ignored).
cause problems on tables for which you are using @code{INSERT DELAYED}.
@item
-Doing a @code{LOCK TABLE ..} and @code{FLUSH TABLES ..} doesn't
+Doing a @code{LOCK TABLE ...} and @code{FLUSH TABLES ...} doesn't
guarantee that there isn't a half-finished transaction in progress on the
table.
@@ -4339,8 +3453,6 @@ and line terminator characters of more than 1 character.
The following problems are known and will be fixed in due time:
@itemize @bullet
-@item
-For the moment @code{MATCH} only works with @code{SELECT} statements.
@item
When using @code{SET CHARACTER SET}, one can't use translated
@@ -4349,12 +3461,12 @@ characters in database, table and column names.
@item
@code{DELETE FROM merge_table} used without a @code{WHERE}
will only clear the mapping for the table, not delete everything in the
-mapped tables
+mapped tables.
@item
-You cannot build in another directory when using
+You cannot build the server in another directory when using
MIT-pthreads. Because this requires changes to MIT-pthreads, we are not
-likely to fix this.
+likely to fix this. @xref{MIT-pthreads}.
@item
@code{BLOB} values can't ``reliably'' be used in @code{GROUP BY} or
@@ -4372,12 +3484,13 @@ precision, @code{IF}, and @code{ELT()} with @code{BIGINT} or @code{DOUBLE}
precision and the rest with @code{DOUBLE} precision. One should try to
avoid using bigger unsigned long long values than 63 bits
(9223372036854775807) for anything else than bit fields!
+MySQL Server 4.0 has better @code{BIGINT} handling than 3.23.
@item
All string columns, except @code{BLOB} and @code{TEXT} columns, automatically
have all trailing spaces removed when retrieved. For @code{CHAR} types this
is okay, and may be regarded as a feature according to ANSI SQL92. The bug is
-that in MySQL, @code{VARCHAR} columns are treated the same way.
+that in MySQL Server, @code{VARCHAR} columns are treated the same way.
@item
You can only have up to 255 @code{ENUM} and @code{SET} columns in one table.
@@ -4393,7 +3506,7 @@ easily reclaim the space for the old log by deleting the old one and
executing @code{mysqladmin refresh}.
@item
-In the @code{UPDATE} statement, columns are updated from left to right. If
+In the @code{UPDATE} statement, columns are updated from left to right. If
you refer to an updated column, you will get the updated value instead of the
original value. For example:
@@ -4412,10 +3525,11 @@ select * from temporary_table, temporary_table as t2;
@end example
@item
-@code{RENAME} doesn't work with @code{TEMPORARY} tables.
+@code{RENAME} doesn't work with @code{TEMPORARY} tables or tables used in a
+@code{MERGE} table.
@item
-The optimizer may handle @code{DISTINCT} differently if you are using
+The optimiser may handle @code{DISTINCT} differently if you are using
'hidden' columns in a join or not. In a join, hidden columns are
counted as part of the result (even if they are not shown) while in
normal queries hidden columns doesn't participate in the @code{DISTINCT}
@@ -4425,19 +3539,21 @@ the hidden columns when executing @code{DISTINCT}
An example of this is:
@example
-SELECT DISTINCT mp3id FROM band_downloads WHERE userid = 9 ORDER BY id
-DESC;
+SELECT DISTINCT mp3id FROM band_downloads
+ WHERE userid = 9 ORDER BY id DESC;
@end example
and
@example
-SELECT DISTINCT band_downloads.mp3id, FROM band_downloads,band_mp3
-WHERE band_downloads.userid = 9 AND band_mp3.id = band_downloads.mp3id
-ORDER BY band_downloads.id DESC;
+SELECT DISTINCT band_downloads.mp3id
+ FROM band_downloads,band_mp3
+ WHERE band_downloads.userid = 9
+ AND band_mp3.id = band_downloads.mp3id
+ ORDER BY band_downloads.id DESC;
@end example
-In the second case you may in MySQL 3.23.x get two identical rows
+In the second case you may in MySQL Server 3.23.x get two identical rows
in the result set (because the hidden 'id' column may differ).
Note that the this only happens for queries where you don't have the
@@ -4445,48 +3561,48 @@ ORDER BY columns in the result, something that is you are not allowed
to do in ANSI SQL.
@item
-Because MySQL allows you to work with table types that doesn't
-support transactions (and thus can't @code{rollback} data) some things
-behaves a little different in MySQL than in other SQL servers:
-(This is just to ensure that MySQL never need to do a rollback
-for a SQL command). This may be a little awkward at times as column
-Because MySQL allows you to work with table types that don't
+Because MySQL Server allows you to work with table types that don't
support transactions, and thus can't @code{rollback} data, some things
-behave a little differently in MySQL than in other SQL servers.
-This is just to ensure that MySQL never need to do a rollback
+behave a little differently in MySQL Server than in other SQL servers.
+This is just to ensure that MySQL Server never need to do a rollback
for a SQL command. This may be a little awkward at times as column
values must be checked in the application, but this will actually give
-you a nice speed increase as it allows MySQL to do some
-optimizations that otherwise would be very hard to do.
+you a nice speed increase as it allows MySQL Server to do some
+optimisations that otherwise would be very hard to do.
-If you set a column to an incorrect value, MySQL will, instead of
+If you set a column to an incorrect value, MySQL Server will, instead of
doing a rollback, store the @code{best possible value} in the column:
@itemize @minus
@item
If you try to store a value outside the range in a numerical column,
-MySQL will instead store the smallest or biggest possible value in
+MySQL Server will instead store the smallest or biggest possible value in
the column.
@item
If you try to store a string that doesn't start with a number into a
-numerical column, MySQL will store 0 into it.
+numerical column, MySQL Server will store 0 into it.
@item
If you try to store @code{NULL} into a column that doesn't take
-@code{NULL} values, MySQL will store 0 or @code{''} (empty
+@code{NULL} values, MySQL Server will store 0 or @code{''} (empty
string) in it instead. (This behavior can, however, be changed with the
-DDONT_USE_DEFAULT_FIELDS compile option).
@item
MySQL allows you to store some wrong date values into
@code{DATE} and @code{DATETIME} columns. (Like 2000-02-31 or 2000-02-00).
-If the date is totally wrong, MySQL will store the special
+If the date is totally wrong, MySQL Server will store the special
0000-00-00 date value in the column.
@item
-If you set an @code{enum} to an unsupported value, it will be set to
+If you set an @code{ENUM} column to an unsupported value, it will be set to
the error value 'empty string', with numeric value 0.
+
+@item
+If you set an @code{SET} column to an unsupported value, the value will
+be ignored.
+
@end itemize
@item
@@ -4498,7 +3614,7 @@ Creation of a table of type @code{MERGE} doesn't check if the underlying
tables are of compatible types.
@item
-MySQL can't yet handle @code{NaN}, @code{-Inf} and @code{Inf}
+MySQL Server can't yet handle @code{NaN}, @code{-Inf} and @code{Inf}
values in double. Using these will cause problems when trying to export
and import data. We should as an intermediate solution change @code{NaN} to
@code{NULL} (if possible) and @code{-Inf} and @code{Inf} to the
@@ -4506,6 +3622,7 @@ Minimum respective maximum possible @code{double} value.
@item
@code{LIMIT} on negative numbers are treated as big positive numbers.
+
@item
If you use @code{ALTER TABLE} to first add an @code{UNIQUE} index to a
table used in a @code{MERGE} table and then use @code{ALTER TABLE} to
@@ -4537,7 +3654,7 @@ Delayed insert handler has pending inserts to a table.
@end itemize
@item
-Before MySQL Version 3.23.2 an @code{UPDATE} that updated a key with
+Before MySQL Server Version 3.23.2 an @code{UPDATE} that updated a key with
a @code{WHERE} on the same key may have failed because the key was used to
search for records and the same row may have been found multiple times:
@@ -4551,58 +3668,552 @@ A workaround is to use:
mysql> UPDATE tbl_name SET KEY=KEY+1 WHERE KEY+0 > 100;
@end example
-This will work because MySQL will not use index on expressions in
+This will work because MySQL Server will not use index on expressions in
the @code{WHERE} clause.
@item
-Before MySQL Version 3.23, all numeric types where treated as fixed-point
-fields. That means you had to specify how many decimals a floating-point
-field shall have. All results were returned with the correct number of
-decimals.
+Before MySQL Server Version 3.23, all numeric types where treated as
+fixed-point fields. That means you had to specify how many decimals
+a floating-point field shall have. All results were returned with the
+correct number of decimals.
@end itemize
For platform-specific bugs, see the sections about compiling and porting.
-@node Comparisons, TODO, Compatibility, Introduction
-@section How MySQL Compares to Other Databases
+@node TODO, Comparisons, Compatibility, Introduction
+@section MySQL and The Future (The TODO)
-@cindex databases, MySQL vs. others
-@cindex comparisons, MySQL vs. others
+@cindex ToDo list for MySQL
@menu
-* Compare mSQL:: How MySQL compares to @code{mSQL}
-* Compare PostgreSQL:: How MySQL compares with PostgreSQL
+* TODO MySQL 4.0:: Things That Should be in 4.0
+* TODO MySQL 4.1:: Things That Should be in 4.1
+* TODO future:: Things That Must be Done in the Near Future
+* TODO sometime:: Things That Have to be Done Sometime
+* TODO unplanned:: Things we don't Have any Plans to do
@end menu
-This section compares MySQL to other popular databases.
+This appendix lists the features that we plan to implement in MySQL Server.
+
+Everything in this list is approximately in the order it will be done. If you
+want to affect the priority order, please register a license or support us and
+tell us what you want to have done more quickly. @xref{Licensing and Support}.
+
+The plan is that we in the future will support the full ANSI SQL99
+standard, but with a lot of useful extensions. The challenge is to do
+this without sacrifying the speed or compromise the code.
+
+
+@node TODO MySQL 4.0, TODO MySQL 4.1, TODO, TODO
+@subsection Things That Should be in 4.0
+
+We are now in the final stages one the development of the MySQL Server
+4.0. server. The target is to quickly implement the rest of the
+following features and then shift development to MySQL Server
+4.1. @xref{MySQL 4.0 In A Nutshell}.
+
+The news section for 4.0 includes a list of the features we have already
+implemented in the 4.0 tree. @xref{News-4.0.x}.
+
+This section lists features not yet implemented in the current version
+of MySQL Server 4.0, which will however be implemented in later versions
+of MySQL 4.0. This being very volatile information, please consider this
+list valid only if you are reading it from the MySQL web site
+(@uref{http://www.mysql.com/}).
+
+@itemize @bullet
+@item
+Allow users to change startup options without taking down the server.
+@item
+Better command line argument handling.
+@item
+New key cache, which will give better performance when using many threads.
+@item
+New table definition file format (@code{.frm} files) This will enable us
+to not run out of bits when adding more table options. One will still
+be able to use the old @code{.frm} file format with 4.0. All newly created
+tables will, however, use the new format.
+
+The new file format will enable us to add new column types, more options
+for keys and possible to store and retrieve @code{FOREIGN KEY} definitions.
+@item
+@code{SHOW COLUMNS FROM table_name} (used by @code{mysql} client to allow
+expansions of column names) should not open the table, but only the
+definition file. This will require less memory and be much faster.
+@item
+@code{SET SQL_DEFAULT_TABLE_TYPE=[MyISAM | INNODB | BDB | HEAP]}.
+@end itemize
+
+
+@node TODO MySQL 4.1, TODO future, TODO MySQL 4.0, TODO
+@subsection Things That Should be in 4.1
+
+We will start working on MySQL 4.1 as soon as MySQL 4.0 goes into beta.
-This section has been written by the MySQL developers, so it
-should be read with that in mind. There are no factual errors contained
-in this section that we know of. If you find something which you believe
-to be an error, please contact us about it at @email{docs@@mysql.com}.
+The following features is the ones we plan that should be in MySQL 4.1.
+Note that because we have many developers that are working on different
+projects, there will also be many additional features. There is also a
+small chance that some of these features will be added to MySQL 4.0.
+
+@itemize @bullet
+@item
+Subqueries.
+@code{SELECT id FROM t WHERE grp IN (SELECT grp FROM g WHERE u > 100)}
+@item
+Foreign keys, including cascading delete.
+@item
+Fail safe replication.
+@item
+Replication should work with @code{RAND()} and user variables @code{@@var}.
+@item
+Online backup with very low performance penalty. The online backup will
+make it easy to add a new replication slave without taking down the
+master.
+@item
+Derived tables.
+@example
+SELECT a.col1, b.col2
+ FROM (SELECT MAX(col1) AS col1 FROM root_table) a,
+ other_table b
+ WHERE a.col1=b.col1;
+@end example
-For a list of all supported limits, functions, and types, see the
-@code{crash-me} Web page at
+This could be done by automatically creating temporary tables for the
+derived tables for the duration of the query.
+@item
+Allow @code{DELETE} on @code{MyISAM} tables to use the record cache.
+To do this, we need to update the threads record cache when we update
+the @code{.MYD} file.
+@item
+When using @code{SET CHARACTER SET} we should translate the whole query
+at once and not only strings. This will enable users to use the translated
+characters in database, table and column names.
+@item
+Add @code{record_in_range()} method to @code{MERGE} tables to be
+able to choose the right index when there is many to choose from. We should
+also extend the info interface to get the key distribution for each index,
+if @code{analyze} is run on all sub tables.
+@item
+@code{RENAME TABLE} on a table used in an active @code{MERGE} table may
+corrupt the table.
+@item
+A faster, smaller embedded MySQL library. (Compatible with the old one)
+@item
+Stable openssl support. (MySQL 4.0 supports rudimentary, not 100 % tested
+support for openssl).
+@item
+Add support for sorting on @code{UNICODE}.
+@item
+Character set casts and syntax for handling multiple character sets.
+@item
+When using @code{SET CHARACTER SET} we should translate the whole query
+at once and not only strings. This will enable users to use the translated
+characters in database, table and column names.
+@item
+Help for all commands from the client.
+@item
+New faster client/server protocol which will support prepared statements,
+bound parameters and bound result columns, binary transfer of data,
+warnings...
+@item
+Add database and real table name (in case of alias) to the MYSQL_FIELD
+structure.
+@item
+Add options to the client/server protocol to get progress notes
+for long running commands.
+@item
+Implement @code{RENAME DATABASE}. To make this safe for all table handlers,
+it should work as follows:
+@itemize @bullet
+@item
+Create the new database.
+@item
+For every table do a rename of the table to another database, as
+we do with the @code{RENAME} command.
+@item
+Drop the old database.
+@end itemize
+@item
+Add true @code{VARCHAR} support (There is already support for this in
+@code{MyISAM}).
+@item
+Optimise @code{BIT} type to take 1 bit (now @code{BIT} takes 1 char).
+@item
+New internal file interface change. This will make all file handling much
+more general and make it easier to add extensions like RAID nicely.
+(The current implementation is a hack).
+@item
+Better in-memory (@code{HEAP}) tables:
+@itemize @bullet
+@item
+Support for B-tree indexes
+@item
+Dynamic size rows
+@item
+Faster row handling (less copying)
+@end itemize
+@end itemize
+
+
+@node TODO future, TODO sometime, TODO MySQL 4.1, TODO
+@subsection Things That Must be Done in the Real Near Future
+
+@itemize @bullet
+@item
+Atomic multi-table updates, eg @code{update items,month set
+items.price=month.price where items.id=month.id;};
+@item
+Don't allow more than a defined number of threads to run MyISAM recover
+at the same time.
+@item
+Change @code{INSERT ... SELECT} to optionally use concurrent inserts.
+@item
+Return the original field types() when doing @code{SELECT MIN(column)
+... GROUP BY}.
+@item
+Multiple result sets.
+@item
+Make it possible to specify @code{long_query_time} with a granularity
+in microseconds.
+@item
+Add a configurable prompt to the @code{mysql} command line client, with
+options like database in use, time and date...
+@item
+Link the @code{myisampack} code into the server.
+@item
+Port of the MySQL code to QNX.
+@item
+Port of the MySQL code to BeOS.
+@item
+Port of the MySQL clients to LynxOS.
+@item
+Add a temporary key buffer cache during @code{INSERT/DELETE/UPDATE} so that we
+can gracefully recover if the index file gets full.
+@item
+If you perform an @code{ALTER TABLE} on a table that is symlinked to another
+disk, create temporary tables on this disk.
+@item
+Implement a @code{DATE/DATETIME} type that handles time zone information
+properly, so that dealing with dates in different time zones is easier.
+@item
+FreeBSD and MIT-pthreads; Do sleeping threads take CPU?
+@item
+Check if locked threads take any CPU.
+@item
+Fix configure so that one can compile all libraries (like @code{MyISAM})
+without threads.
+@item
+Add an option to periodically flush key pages for tables with delayed keys
+if they haven't been used in a while.
+@item
+Allow join on key parts (optimisation issue).
+@item
+@code{INSERT SQL_CONCURRENT} and @code{mysqld --concurrent-insert} to do
+a concurrent insert at the end of the file if the file is read-locked.
+@item
+Server side cursors.
+@item
+Check if @code{lockd} works with modern Linux kernels; If not, we have
+to fix @code{lockd}! To test this, start @code{mysqld} with
+@code{--enable-locking} and run the different fork* test suits. They shouldn't
+give any errors if @code{lockd} works.
+@item
+Allow SQL variables in @code{LIMIT}, like in @code{LIMIT @@a,@@b}.
+@item
+Allow update of variables in @code{UPDATE} statements. For example:
+@code{UPDATE TABLE foo SET @@a=a+b,a=@@a, b=@@a+c}
+@item
+Change when user variables are updated so that one can use them with
+@code{GROUP BY}, as in the following example:
+@code{SELECT id, @@a:=count(*), sum(sum_col)/@@a FROM table_name GROUP BY id}.
+@item
+Don't add automatic @code{DEFAULT} values to columns. Give an error when using
+an @code{INSERT} that doesn't contain a column that doesn't have a
+@code{DEFAULT}.
+@item
+Fix @file{libmysql.c} to allow two @code{mysql_query()} commands in a row
+without reading results or give a nice error message when one does this.
+@item
+Check why MIT-pthreads @code{ctime()} doesn't work on some FreeBSD systems.
+@item
+Add an @code{IMAGE} option to @code{LOAD DATA INFILE} to not update
+@code{TIMESTAMP} and @code{AUTO_INCREMENT} fields.
+@item
+Added @code{LOAD DATE INFILE ... UPDATE} syntax.
+@itemize @bullet
+@item
+For tables with primary keys, if the data contains the primary key,
+entries matching that primary key are updated from the remainder of the
+columns. However, columns @strong{missing} from the incoming data feed are not
+touched.
+@item
+For tables tables with primary keys that are missing some part of the key
+in the incoming data stream, or that have no primary key, the feed is
+treated as a @code{LOAD DATA INFILE ... REPLACE INTO} is now.
+@end itemize
+@item
+Make @code{LOAD DATA INFILE} understand syntax like:
+@example
+LOAD DATA INFILE 'file_name.txt' INTO TABLE tbl_name
+ TEXT_FIELDS (text_field1, text_field2, text_field3)
+ SET table_field1=concatenate(text_field1, text_field2),
+ table_field3=23
+ IGNORE text_field3
+@end example
+This can be used to skip over extra columns in the text file,
+or update columns based on expressions of the read data...
+@item
+@code{LOAD DATA INFILE 'file_name' INTO TABLE 'table_name' ERRORS TO err_table_name}
+This would cause any errors and warnings to be logged into the
+@code{err_table_name} table. That table would have a structure like:
+
+@example
+line_number - line number in data file
+error_message - the error/warning message
+and maybe
+data_line - the line from the data file
+@end example
+@item
+Automatic output from @code{mysql} to Netscape.
+@item
+@code{LOCK DATABASES}. (with various options)
+@item
+@code{DECIMAL} and @code{NUMERIC} types can't read exponential numbers;
+@code{Field_decimal::store(const char *from,uint len)} must be recoded
+to fix this.
+@item
+Functions:
+ADD_TO_SET(value,set) and REMOVE_FROM_SET(value,set)
+@item
+Add use of @code{t1 JOIN t2 ON ...} and @code{t1 JOIN t2 USING ...}
+Currently, you can only use this syntax with @code{LEFT JOIN}.
+@item
+Many more variables for @code{show status}. Records reads and
+updated. Selects on 1 table and selects with joins. Mean number of
+tables in select. Number of @code{ORDER BY} and @code{GROUP BY} queries.
+@item
+If you abort @code{mysql} in the middle of a query, you should open
+another connection and kill the old running query.
+Alternatively, an attempt should be made to detect this in the server.
+@item
+Add a handler interface for table information so you can use it as a system
+table. This would be a bit slow if you requested information about all tables,
+but very flexible. @code{SHOW INFO FROM tbl_name} for basic table information
+should be implemented.
+@item
+@code{NATURAL JOIN}.
+@item
+Allow @code{select a from crash_me left join crash_me2 using (a)}; In this
+case @code{a} is assumed to come from the @code{crash_me} table.
+@item
+Fix that @code{ON} and @code{USING} works with the @code{JOIN}
+join type.
+@item
+Oracle like @code{CONNECT BY PRIOR ...} to search hierarchy structures.
+@item
+@code{mysqladmin copy database new-database}; Requires @code{COPY}
+command to be added to @code{mysqld}
+@item
+Processlist should show number of queries/thread.
+@item
+@code{SHOW HOSTS} for printing information about the hostname cache.
+@item
+@code{DELETE} and @code{REPLACE} options to the @code{UPDATE} statement
+(this will delete rows when one gets a duplicate key error while updating).
+@item
+Change the format of @code{DATETIME} to store fractions of seconds.
+@item
+Add all missing ANSI92 and ODBC 3.0 types.
+@item
+Change table names from empty strings to @code{NULL} for calculated columns.
+@item
+Don't use 'Item_copy_string' on numerical values to avoid
+number->string->number conversion in case of:
+@code{SELECT COUNT(*)*(id+0) FROM table_name GROUP BY id}
+@item
+Make it possible to use the new GNU regexp library instead of the current
+one (The GNU library should be much faster than the old one).
+@item
+Change that @code{ALTER TABLE} doesn't abort clients that executes
+@code{INSERT DELAYED}.
+@item
+Fix that when columns referenced in an @code{UPDATE} clause contains the old
+values before the update started.
+@item
+Add simulation of @code{pread()}/@code{pwrite()} on Windows to enable
+concurrent inserts.
+@item
+A logfile analyser that could parsed out information about which tables
+are hit most often, how often multi-table joins are executed, etc. It
+should help users identify areas or table design that could be optimised
+to execute much more efficient queries.
+@item
+Add @code{SUM(DISTINCT)}
+@item
+Add @code{ANY()},@code{EVERY()} and @code{SOME()} group functions. In
+ANSI SQL these only works on boolean columns, but we can extend these to
+work on any columns/expressions by applying: value == 0 -> FALSE and
+value <> 0 -> TRUE.
+@item
+Fix that the type for @code{MAX(column)} is the same as the column type.
+@example
+create table t1 (a DATE);
+insert into t1 values (now());
+create table t2 select MAX(a) from t1;
+show columns from t2;
+@end example
+@item
+Come up with a nice syntax for a statement that will @code{UPDATE} the row
+if it exists and @code{INSERT} a new row if the row didn't exist.
+(Like @code{REPLACE} works with @code{INSERT} / @code{DELETE})
+@end itemize
+
+
+@node TODO sometime, TODO unplanned, TODO future, TODO
+@subsection Things That Have to be Done Sometime
+
+@itemize @bullet
+@item
+Implement function: @code{get_changed_tables(timeout,table1,table2,...)}
+@item
+Change reading through tables to use memmap when possible. Now only
+compressed tables use memmap.
+@item
+Add a new privilege @strong{'Show_priv'} for @code{SHOW} commands.
+@item
+Make the automatic timestamp code nicer. Add timestamps to the update
+log with @code{SET TIMESTAMP=#;}
+@item
+Use read/write mutex in some places to get more speed.
+@item
+Full foreign key support. One probably wants to implement a procedural
+language first.
+@item
+Simple views (first on one table, later on any expression).
+@item
+Automatically close some tables if a table, temporary table or temporary files
+gets error 23 (not enough open files).
+@item
+When one finds a field=#, change all occurrences of field to #. Now this
+is only done for some simple cases.
+@item
+Change all const expressions with calculated expressions if possible.
+@item
+Optimise key = expression. At the moment only key = field or key =
+constant are optimised.
+@item
+Join some of the copy functions for nicer code.
+@item
+Change @file{sql_yacc.yy} to an inline parser to reduce its size and get
+better error messages (5 days).
+@item
+Change the parser to use only one rule per different number of arguments
+in function.
+@item
+Use of full calculation names in the order part. (For ACCESS97)
+@item
+@code{MINUS}, @code{INTERSECT} and @code{FULL OUTER JOIN}.
+(Currently @code{UNION} (in 4.0) and @code{LEFT OUTER JOIN} are supported)
+@item
+@code{SQL_OPTION MAX_SELECT_TIME=#} to put a time limit on a query.
+@item
+Make the update log to a database.
+@item
+Negative @code{LIMIT} to retrieve data from the end.
+@item
+Alarm around client connect/read/write functions.
+@item
+Please note the changes to @code{safe_mysqld}: according to FSSTND (which
+Debian tries to follow) PID files should go into @file{/var/run/<progname>.pid}
+and log files into @file{/var/log}. It would be nice if you could put the
+"DATADIR" in the first declaration of "pidfile" and "log", so the
+placement of these files can be changed with a single statement.
+@item
+Allow a client to request logging.
+@item
+Add use of @code{zlib()} for @code{gzip}-ed files to @code{LOAD DATA INFILE}.
+@item
+Fix sorting and grouping of @code{BLOB} columns (partly solved now).
+@item
+Stored procedures. Triggers are also being looked at.
+@item
+A simple (atomic) update language that
+can be used to write loops and such in the MySQL server.
+@item
+Change to use semaphores when counting threads. One should first implement
+a semaphore library to MIT-pthreads.
+@item
+Don't assign a new @code{AUTO_INCREMENT} value when one sets a column to 0.
+Use @code{NULL} instead.
+@item
+Add full support for @code{JOIN} with parentheses.
+@item
+As an alternative for one thread / connection manage a pool of threads
+to handle the queries.
+@item
+Allow one to get more than one lock with @code{GET_LOCK}. When doing this,
+one must also handle the possible deadlocks this change will introduce.
+@end itemize
+
+Time is given according to amount of work, not real time.
+
+
+@node TODO unplanned, , TODO sometime, TODO
+@subsection Things we don't Have any Plans to do
+
+@itemize @bullet
+@item
+Nothing; We aim towards full ANSI 92 / ANSI 99 compliancy.
+@end itemize
+
+
+@node Comparisons, , TODO, Introduction
+@section How MySQL Compares to Other Databases
+
+@cindex databases, MySQL vs. others
+@cindex comparisons, MySQL vs. others
+
+Our users have successfully run their own benchmarks against a number
+of @code{Open Source} and traditional database servers.
+We are aware of tests against @code{Oracle} server, @code{DB/2} server,
+@code{Microsoft SQL Server} and other commercial products.
+Due to legal reasons we are restricted from publishing some of those
+benchmarks in our reference manual.
+
+This section includes a comparison with @code{mSQL} for historical
+reasons and with @code{PostgreSQL} as it is also an Open Source
+database. If you have benchmark results that we can publish, please
+contact us at @email{benchmarks@@mysql.com}.
+
+For comparative lists of all supported functions and types as well
+as measured operational limits of many different database systems,
+see the @code{crash-me} web page at
@uref{http://www.mysql.com/information/crash-me.php}.
+@menu
+* Compare mSQL:: How MySQL compares to @code{mSQL}
+* Compare PostgreSQL:: How MySQL Compares to @code{PostgreSQL}
+@end menu
+
@node Compare mSQL, Compare PostgreSQL, Comparisons, Comparisons
@subsection How MySQL Compares to @code{mSQL}
+@cindex mSQL, MySQL vs mSQL, overview
@table @strong
@item Performance
For a true comparison of speed, consult the growing MySQL benchmark
suite. @xref{MySQL Benchmarks}.
-Because there is no thread creation overhead, a small parser, few features, and
-simple security, @code{mSQL} should be quicker at:
+Because there is no thread creation overhead, a small parser, few
+features, and simple security, @code{mSQL} should be quicker at:
@itemize @bullet
@item
-Tests that perform repeated connects and disconnects, running a very simple
-query during each connection.
+Tests that perform repeated connects and disconnects, running a very
+simple query during each connection.
@item
@code{INSERT} operations into very simple tables with few columns and keys.
@@ -4615,11 +4226,11 @@ query during each connection.
easy.)
@end itemize
-Because these operations are so simple, it is hard to be better at them when
-you have a higher startup overhead. After the connection is established,
-MySQL should perform much better.
+Because these operations are so simple, it is hard to be better at
+them when you have a higher startup overhead. After the connection
+is established, MySQL Server should perform much better.
-On the other hand, MySQL is much faster than @code{mSQL} (and
+On the other hand, MySQL Server is much faster than @code{mSQL} (and
most other SQL implementations) on the following:
@itemize @bullet
@@ -4627,11 +4238,11 @@ most other SQL implementations) on the following:
Complex @code{SELECT} operations.
@item
-Retrieving large results (MySQL has a better, faster, and safer
+Retrieving large results (MySQL Server has a better, faster, and safer
protocol).
@item
-Tables with variable-length strings, because MySQL has more efficient
+Tables with variable-length strings, because MySQL Server has more efficient
handling and can have indexes on @code{VARCHAR} columns.
@item
@@ -4647,23 +4258,24 @@ Handling tables with large record lengths.
@code{SELECT} on large tables.
@item
-Handling many connections at the same time. MySQL is fully
+Handling many connections at the same time. MySQL Server is fully
multi-threaded. Each connection has its own thread, which means that
no thread has to wait for another (unless a thread is modifying
-a table another thread wants to access). In @code{mSQL}, once one connection
-is established, all others must wait until the first has finished, regardless
-of whether the connection is running a query that is short or long. When the
-first connection terminates, the next can be served, while all the others wait
-again, etc.
+a table another thread wants to access). In @code{mSQL}, once one
+connection is established, all others must wait until the first has
+finished, regardless of whether the connection is running a query
+that is short or long. When the first connection terminates, the
+next can be served, while all the others wait again, etc.
@item
Joins.
-@code{mSQL} can become pathologically slow if you change the order of tables
-in a @code{SELECT}. In the benchmark suite, a time more than 15000 times
-slower than MySQL was seen. This is due to @code{mSQL}'s lack of a
-join optimizer to order tables in the optimal order. However, if you put the
-tables in exactly the right order in @code{mSQL}2 and the @code{WHERE} is
-simple and uses index columns, the join will be relatively fast!
+@code{mSQL} can become pathologically slow if you change the order of
+tables in a @code{SELECT}. In the benchmark suite, a time more than
+15000 times slower than MySQL Server was seen. This is due to @code{mSQL}'s
+lack of a join optimiser to order tables in the optimal order.
+However, if you put the tables in exactly the right order in
+@code{mSQL}2 and the @code{WHERE} is simple and uses index columns,
+the join will be relatively fast!
@xref{MySQL Benchmarks}.
@item
@@ -4681,15 +4293,16 @@ Using @code{TEXT} or @code{BLOB} columns.
@itemize @bullet
@item @code{GROUP BY} and @code{HAVING}.
@code{mSQL} does not support @code{GROUP BY} at all.
-MySQL supports a full @code{GROUP BY} with both @code{HAVING} and
+MySQL Server supports a full @code{GROUP BY} with both @code{HAVING} and
the following functions: @code{COUNT()}, @code{AVG()}, @code{MIN()},
-@code{MAX()}, @code{SUM()}, and @code{STD()}. @code{COUNT(*)} is optimized to
-return very quickly if the @code{SELECT} retrieves from one table, no other
-columns are retrieved, and there is no @code{WHERE} clause. @code{MIN()} and
-@code{MAX()} may take string arguments.
+@code{MAX()}, @code{SUM()}, and @code{STD()}. @code{COUNT(*)} is
+optimised to return very quickly if the @code{SELECT} retrieves from
+one table, no other columns are retrieved, and there is no
+@code{WHERE} clause. @code{MIN()} and @code{MAX()} may take string
+arguments.
@item @code{INSERT} and @code{UPDATE} with calculations.
-MySQL can do calculations in an @code{INSERT} or @code{UPDATE}.
+MySQL Server can do calculations in an @code{INSERT} or @code{UPDATE}.
For example:
@example
@@ -4697,49 +4310,47 @@ mysql> UPDATE SET x=x*10+y WHERE x<20;
@end example
@item Aliasing.
-MySQL has column aliasing.
+MySQL Server has column aliasing.
@item Qualifying column names.
-In MySQL, if a column name is unique among the tables used in a
+In MySQ ServerL, if a column name is unique among the tables used in a
query, you do not have to use the full qualifier.
@item @code{SELECT} with functions.
-MySQL has many functions (too many to list here; see @ref{Functions}).
+MySQL Server has many functions (too many to list here; see @ref{Functions}).
@end itemize
@item Disk Space Efficiency
That is, how small can you make your tables?
-MySQL has very precise types, so you can create tables that take
+MySQ ServerL has very precise types, so you can create tables that take
very little space. An example of a useful MySQL datatype is the
-@code{MEDIUMINT} that is 3 bytes long. If you have 100,000,000 records,
-saving even one byte per record is very important.
+@code{MEDIUMINT} that is 3 bytes long. If you have 100,000,000
+records, saving even one byte per record is very important.
@code{mSQL2} has a more limited set of column types, so it is
more difficult to get small tables.
@item Stability
-This is harder to judge objectively. For a discussion of MySQL
+This is harder to judge objectively. For a discussion of MySQL Server
stability, see @ref{Stability}.
We have no experience with @code{mSQL} stability, so we cannot say
anything about that.
@item Price
-Another important issue is the license. MySQL has a
-more flexible license than @code{mSQL}, and is also less expensive than
-@code{mSQL}. Whichever product you choose to use, remember to at least
-consider paying for a license or e-mail support. (You are required to get
-a license if you include MySQL with a product that you sell,
-of course.)
+Another important issue is the license. MySQL Server has a
+more flexible license than @code{mSQL}, and is also less expensive
+than @code{mSQL}. Whichever product you choose to use, remember to
+at least consider paying for a license or e-mail support.
@item Perl Interfaces
-MySQL has basically the same interfaces to Perl as @code{mSQL} with
+MySQL Server has basically the same interfaces to Perl as @code{mSQL} with
some added features.
@item JDBC (Java)
-MySQL currently has a lot of different JDBC drivers:
+MySQL Server currently has a lot of different JDBC drivers:
@itemize @bullet
@item
@@ -4764,14 +4375,14 @@ and educational use (not supported anymore).
@end itemize
The recommended driver is the mm driver. The Resin driver may also be
-good (at least the benchmarks looks good), but we haven't received that much
-information about this yet.
+good (at least the benchmarks looks good), but we haven't received that
+much information about this yet.
-We know that @code{mSQL} has a JDBC driver, but we have too little experience
-with it to compare.
+We know that @code{mSQL} has a JDBC driver, but we have too little
+experience with it to compare.
@item Rate of Development
-MySQL has a very small team of developers, but we are quite
+MySQL Server has a small core team of developers, but we are quite
used to coding C and C++ very rapidly. Because threads, functions,
@code{GROUP BY}, and so on are still not implemented in @code{mSQL}, it
has a lot of catching up to do. To get some perspective on this, you
@@ -4781,17 +4392,17 @@ compare it with the News section of the MySQL Reference Manual
most rapidly.
@item Utility Programs
-Both @code{mSQL} and MySQL have many interesting third-party
+Both @code{mSQL} and MySQL Server have many interesting third-party
tools. Because it is very easy to port upward (from @code{mSQL} to
-MySQL), almost all the interesting applications that are available for
-@code{mSQL} are also available for MySQL.
+MySQL Server), almost all the interesting applications that are available for
+@code{mSQL} are also available for MySQ ServerL.
-MySQL comes with a simple @code{msql2mysql} program that fixes
-differences in spelling between @code{mSQL} and MySQL for the
+MySQL Server comes with a simple @code{msql2mysql} program that fixes
+differences in spelling between @code{mSQL} and MySQL Server for the
most-used C API functions.
For example, it changes instances of @code{msqlConnect()} to
@code{mysql_connect()}. Converting a client program from @code{mSQL} to
-MySQL usually takes a couple of minutes.
+MySQL Server usually requires only minor effort.
@end table
@menu
@@ -4808,7 +4419,7 @@ MySQL usually takes a couple of minutes.
@cindex converting, tools
@cindex tools, converting
-According to our experience, it would just take a few hours to convert tools
+According to our experience, it doesn't take long to convert tools
such as @code{msql-tcl} and @code{msqljava} that use the
@code{mSQL} C API so that they work with the MySQL C API.
@@ -4816,8 +4427,8 @@ The conversion procedure is:
@enumerate
@item
-Run the shell script @code{msql2mysql} on the source. This requires the
-@code{replace} program, which is distributed with MySQL.
+Run the shell script @code{msql2mysql} on the source. This requires
+the @code{replace} program, which is distributed with MySQL Server.
@item
Compile.
@@ -4830,25 +4441,27 @@ Differences between the @code{mSQL} C API and the MySQL C API are:
@itemize @bullet
@item
-MySQL uses a @code{MYSQL} structure as a connection type (@code{mSQL}
+MySQL Server uses a @code{MYSQL} structure as a connection type (@code{mSQL}
uses an @code{int}).
@item
@code{mysql_connect()} takes a pointer to a @code{MYSQL} structure as a
-parameter. It is easy to define one globally or to use @code{malloc()} to get
-one. @code{mysql_connect()} also takes two parameters for specifying the
-user and password. You may set these to @code{NULL, NULL} for default use.
+parameter. It is easy to define one globally or to use @code{malloc()}
+to get one. @code{mysql_connect()} also takes two parameters for
+specifying the user and password. You may set these to
+@code{NULL, NULL} for default use.
@item
-@code{mysql_error()} takes the @code{MYSQL} structure as a parameter. Just add
-the parameter to your old @code{msql_error()} code if you are porting old code.
+@code{mysql_error()} takes the @code{MYSQL} structure as a parameter.
+Just add the parameter to your old @code{msql_error()} code if you are
+porting old code.
@item
-MySQL returns an error number and a text error message for all
+MySQL Server returns an error number and a text error message for all
errors. @code{mSQL} returns only a text error message.
@item
-Some incompatibilities exist as a result of MySQL supporting
+Some incompatibilities exist as a result of MySQL Server supporting
multiple connections to the server from the same process.
@end itemize
@@ -4857,10 +4470,10 @@ multiple connections to the server from the same process.
@subsubsection How @code{mSQL} and MySQL Client/Server Communications Protocols Differ
@cindex communications protocols
-@cindex mSQL vs. MySQL
+@cindex mSQL vs. MySQL, protocol
-There are enough differences that it is impossible (or at least not easy)
-to support both.
+There are enough differences that it is impossible
+(or at least not easy) to support both.
The most significant ways in which the MySQL protocol differs
from the @code{mSQL} protocol are listed below:
@@ -4871,15 +4484,15 @@ A message buffer may contain many result rows.
@item
The message buffers are dynamically enlarged if the query or the
-result is bigger than the current buffer, up to a configurable server and
-client limit.
+result is bigger than the current buffer, up to a configurable server
+and client limit.
@item
All packets are numbered to catch duplicated or missing packets.
@item
-All column values are sent in ASCII. The lengths of columns and rows are sent
-in packed binary coding (1, 2, or 3 bytes).
+All column values are sent in ASCII. The lengths of columns and rows
+are sent in packed binary coding (1, 2, or 3 bytes).
@item
MySQL can read in the result unbuffered (without having to store the
@@ -4893,10 +4506,6 @@ the connection.
If a connection is idle for 8 hours, the server closes the connection.
@end itemize
-@menu
-* Syntax differences:: How @code{mSQL} 2.0 SQL Syntax Differs from MySQL
-@end menu
-
@node Syntax differences, , Protocol differences, Compare mSQL
@subsubsection How @code{mSQL} 2.0 SQL Syntax Differs from MySQL
@@ -4905,23 +4514,25 @@ If a connection is idle for 8 hours, the server closes the connection.
@strong{Column types}
@table @code
-@item MySQL
+@item MySQL Server
Has the following additional types (among others;
@pxref{CREATE TABLE, , @code{CREATE TABLE}}):
@itemize @bullet
@item
+@c FIX bad lingo, needs rephrasing
@code{ENUM} type for one of a set of strings.
@item
+@c FIX bad lingo, needs rephrasing
@code{SET} type for many of a set of strings.
@item
@code{BIGINT} type for 64-bit integers.
@end itemize
@item
-MySQL also supports
+MySQL Server also supports
the following additional type attributes:
@itemize @bullet
@item
-@code{UNSIGNED} option for integer columns.
+@code{UNSIGNED} option for integer and floating point columns.
@item
@code{ZEROFILL} option for integer columns.
@item
@@ -4951,7 +4562,7 @@ And @code{LIKE} works.
@strong{Index Creation}
@table @code
-@item MySQL
+@item MySQL Server
Indexes may be specified at table creation time with the @code{CREATE TABLE}
statement.
@item mSQL
@@ -4963,7 +4574,7 @@ Indexes must be created after the table has been created, with separate
@strong{To Insert a Unique Identifier into a Table}
@table @code
-@item MySQL
+@item MySQL Server
Use @code{AUTO_INCREMENT} as a column type
specifier.
@xref{mysql_insert_id, , @code{mysql_insert_id()}}.
@@ -4975,7 +4586,7 @@ Create a @code{SEQUENCE} on a table and select the @code{_seq} column.
@strong{To Obtain a Unique Identifier for a Row}
@table @code
-@item MySQL
+@item MySQL Server
Add a @code{PRIMARY KEY} or @code{UNIQUE} key to the table and use this.
New in Version 3.23.11: If the @code{PRIMARY} or @code{UNIQUE} key consists of only one
column and this is of type integer, one can also refer to it as
@@ -4989,7 +4600,7 @@ depending on many factors.
@strong{To Get the Time a Column Was Last Modified}
@table @code
-@item MySQL
+@item MySQL Server
Add a @code{TIMESTAMP} column to the table. This column is automatically set
to the current date and time for @code{INSERT} or @code{UPDATE} statements if
you don't give the column a value or if you give it a @code{NULL} value.
@@ -5002,20 +4613,20 @@ Use the @code{_timestamp} column.
@strong{@code{NULL} Value Comparisons}
@table @code
-@item MySQL
-MySQL follows
+@item MySQL Server
+MySQL Server follows
ANSI SQL, and a comparison with @code{NULL} is always @code{NULL}.
@item mSQL
In @code{mSQL}, @code{NULL = NULL} is TRUE. You
must change @code{=NULL} to @code{IS NULL} and @code{<>NULL} to
-@code{IS NOT NULL} when porting old code from @code{mSQL} to MySQL.
+@code{IS NOT NULL} when porting old code from @code{mSQL} to MySQL Server.
@end table
@noindent
@strong{String Comparisons}
@table @code
-@item MySQL
+@item MySQL Server
Normally, string comparisons are performed in case-independent fashion with
the sort order determined by the current character set (ISO-8859-1 Latin1 by
default). If you don't like this, declare your columns with the
@@ -5030,7 +4641,7 @@ sorting in ASCII order.
@strong{Case-insensitive Searching}
@table @code
-@item MySQL
+@item MySQL Server
@code{LIKE} is a case-insensitive or case-sensitive operator, depending on
the columns involved. If possible, MySQL uses indexes if the
@code{LIKE} argument doesn't start with a wild-card character.
@@ -5042,7 +4653,7 @@ Use @code{CLIKE}.
@strong{Handling of Trailing Spaces}
@table @code
-@item MySQL
+@item MySQL Server
Strips all spaces at the end of @code{CHAR} and @code{VARCHAR}
columns. Use a @code{TEXT} column if this behavior is not desired.
@item mSQL
@@ -5053,20 +4664,20 @@ Retains trailing space.
@strong{@code{WHERE} Clauses}
@table @code
-@item MySQL
-MySQL correctly prioritizes everything (@code{AND} is evaluated
-before @code{OR}). To get @code{mSQL} behavior in MySQL, use
+@item MySQL Server
+MySQL correctly prioritises everything (@code{AND} is evaluated
+before @code{OR}). To get @code{mSQL} behavior in MySQL Server, use
parentheses (as shown in an example below).
@item mSQL
Evaluates everything from left to right. This means that some logical
calculations with more than three arguments cannot be expressed in any
way. It also means you must change some queries when you upgrade to
-MySQL. You do this easily by adding parentheses. Suppose you
+MySQL Server. You do this easily by adding parentheses. Suppose you
have the following @code{mSQL} query:
@example
mysql> SELECT * FROM table WHERE a=1 AND b=2 OR a=3 AND b=4;
@end example
-To make MySQL evaluate this the way that @code{mSQL} would,
+To make MySQL Server evaluate this the way that @code{mSQL} would,
you must add parentheses:
@example
mysql> SELECT * FROM table WHERE (a=1 AND (b=2 OR (a=3 AND (b=4))));
@@ -5077,42 +4688,40 @@ mysql> SELECT * FROM table WHERE (a=1 AND (b=2 OR (a=3 AND (b=4))));
@strong{Access Control}
@table @code
-@item MySQL
+@item MySQL Server
Has tables to store grant (permission) options per user, host, and
database. @xref{Privileges}.
@item mSQL
Has a file @file{mSQL.acl} in which you can grant read/write privileges for
users.
-@item
@end table
@node Compare PostgreSQL, , Compare mSQL, Comparisons
-@subsection How MySQL Compares to PostgreSQL
+@subsection How MySQL Compares to @code{PostgreSQL}
@cindex PostgreSQL vs. MySQL, overview
When reading the following, please note that both products are continually
evolving. We at MySQL AB and the PostgreSQL developers are both working
-on making our respective database as good as possible, so we are both a
-serious choice to any commercial database.
+on making our respective database as good as possible, so we are both a
+serious alternative to any commercial database.
The following comparison is made by us at MySQL AB. We have tried to be
-as accurate and fair as possible, but because we don't have a full
-knowledge of all PostgreSQL features while we know MySQL througly, we
-may have got some things wrong. We will however correct these when they
-come to our attention.
-
-We would first like to note that PostgreSQL and MySQL are both widely used
-products, but with different design goals, even if we are both striving to
-be ANSI SQL compatible. This means that for some applications MySQL is
-more suited, while for others PostgreSQL is more suited. When choosing
+as accurate and fair as possible, but because while we know MySQL Server thorougly
+we don't have a full knowledge of all PostgreSQL features, so we may have
+got some things wrong. We will however correct these when they come to our
+attention.
+
+We would first like to note that PostgreSQL and MySQL Server are both widely used
+products, but with different design goals, even if we are both striving
+towards ANSI SQL compliancy. This means that for some applications MySQL Server
+is more suited, while for others PostgreSQL is more suited. When choosing
which database to use, you should first check if the database's feature set
-satisfies your application. If you need raw speed, MySQL is probably your
+satisfies your application. If you need raw speed, MySQL Server is probably your
best choice. If you need some of the extra features that only PostgreSQL
can offer, you should use @code{PostgreSQL}.
-@cindex PostgreSQL/MySQL, strategies
@menu
* MySQL-PostgreSQL goals:: MySQL and PostgreSQL development strategies
* MySQL-PostgreSQL features:: Featurewise Comparison of MySQL and PostgreSQL
@@ -5123,7 +4732,8 @@ can offer, you should use @code{PostgreSQL}.
@node MySQL-PostgreSQL goals, MySQL-PostgreSQL features, Compare PostgreSQL, Compare PostgreSQL
@subsubsection MySQL and PostgreSQL development strategies
-When adding things to MySQL we take pride to do an optimal, definite
+@cindex PostgreSQL vs. MySQL, strategies
+When adding things to MySQL Server we take pride to do an optimal, definite
solution. The code should be so good that we shouldn't have any need to
change it in the foreseeable future. We also do not like to sacrifice
speed for features but instead will do our utmost to find a solution
@@ -5139,11 +4749,11 @@ about every three weeks, and a major branch every year. All releases are
throughly tested with our testing tools on a lot of different platforms.
PostgreSQL is based on a kernel with lots of contributors. In this setup
-it makes sense to prioritize adding a lot of new features, instead of
-implementing them optimally, because one can always optimize things
+it makes sense to prioritise adding a lot of new features, instead of
+implementing them optimally, because one can always optimise things
later if there arises a need for this.
-Another big difference between MySQL and PostgreSQL is that
+Another big difference between MySQL Server and PostgreSQL is that
nearly all of the code in the MySQL server are coded by developers that
are employed by MySQL AB and are still working on the server code. The
exceptions are the transaction engines, and the regexp library.
@@ -5154,7 +4764,7 @@ It was only recently that the PostgreSQL developers announced that their
current developer group had finally had time to take a look at all
the code in the current PostgreSQL release.
-Both of the above development methods has it's own merits and drawbacks.
+Both of the above development methods have their own merits and drawbacks.
We here at MySQL AB think of course that our model is better because our
model gives better code consistency, more optimal and reusable code, and
in our opinion, fewer bugs. Because we are the authors of the MySQL server
@@ -5164,100 +4774,103 @@ code, we are better able to coordinate new features and releases.
@node MySQL-PostgreSQL features, MySQL-PostgreSQL benchmarks, MySQL-PostgreSQL goals, Compare PostgreSQL
@subsubsection Featurewise Comparison of MySQL and PostgreSQL
-@cindex PostgreSQL/MySQL, features
+@cindex PostgreSQL vs. MySQL, features
-On the @uref{http://www.mysql.com/information/crash-me.php, crash-me}
-page you can find a list of those database constructs and limits that
+On the crash-me page
+(@uref{http://www.mysql.com/information/crash-me.php})
+you can find a list of those database constructs and limits that
one can detect automatically with a program. Note however that a lot of
the numerical limits may be changed with startup options for respective
database. The above web page is however extremely useful when you want to
ensure that your applications works with many different databases or
-when you want to convert your application from one datbase to another.
+when you want to convert your application from one database to another.
-MySQL offers the following advantages over PostgreSQL:
+MySQL Server offers the following advantages over PostgreSQL:
@itemize @bullet
@item
-@code{MySQL} is generally much faster than PostgreSQL.
-@xref{MySQL-PostgreSQL benchmarks}.
+@code{MySQL} Server is generally much faster than PostgreSQL. MySQL
+4.0.1 has also a query cache that can boost up the query speed for
+mostly-read-only sites many times.
@item
-MySQL has a much larger user base than PostgreSQL, therefor the
-code is more tested and has historically been more stable than
-PostgreSQL. MySQL is the much more used in production
-environments than PostgreSQL, mostly thanks to that MySQL AB,
-formerly TCX DataKonsult AB, has provided top quality commercial support
-for MySQL from the day it was released, whereas until recently
-PostgreSQL was unsupported.
+MySQL has a much larger user base than PostgreSQL, therefore the code is
+more tested and has historically proven more stable than PostgreSQL.
+MySQL Server is more used in production environments than PostgreSQL,
+mostly thanks to that MySQL AB, formerly TCX DataKonsult AB, has
+provided top quality commercial support for MySQL Server from the day it
+was released, whereas until recently PostgreSQL was unsupported.
@item
-MySQL works better on Windows than PostgreSQL does. MySQL runs as a
-native Windows application (a service on NT/Win2000/WinXP), while
-PostgreSQL is run under the cygwin emulation. We have heard that
-PostgreSQL is not yet that stable on Windows but we haven't been able to
-verify this ourselves.
+MySQL Server works better on Windows than PostgreSQL does. MySQL Server
+runs as a native Windows application (a service on NT/Win2000/WinXP),
+while PostgreSQL is run under the @code{Cygwin} emulation. We have
+heard that PostgreSQL is not yet that stable on Windows but we haven't
+been able to verify this ourselves.
@item
MySQL has more APIs to other languages and is supported by more
existing programs than PostgreSQL. @xref{Contrib}.
@item
-MySQL works on 24/7 heavy duty systems. In most circumstances
-you never have to run any cleanups on MySQL. PostgreSQL doesn't
-yet support 24/7 systems because you have to run @code{VACUUM()}
+MySQL Server works on 24/7 heavy duty systems. In most circumstances
+you never have to run any cleanups on MySQL Server. PostgreSQL doesn't
+yet support 24/7 systems because you have to run @code{VACUUM}
once in a while to reclaim space from @code{UPDATE} and @code{DELETE}
-commands and to perform statistics analyzes that are critical to get
-good performance with PostgreSQL. @code{VACUUM()} is also needed after
+commands and to perform statistics analyses that are critical to get
+good performance with PostgreSQL. @code{VACUUM} is also needed after
adding a lot of new rows to a table. On a busy system with lots of changes,
-@code{VACUUM()} must be run very frequently, in the worst cases even
-many times a day. During the @code{VACUUM()} run, which may take hours
+@code{VACUUM} must be run very frequently, in the worst cases even
+many times a day. During the @code{VACUUM} run, which may take hours
if the database is big, the database is from a production standpoint,
-practically dead. The PostgreSQL team has fixing this on their TODO,
-but we assume that this is not an easy thing to fix permanently.
+practically dead. Please note: In PostgreSQL version 7.2, basic vacuuming
+no longer locks tables, thus allowing normal user access during the vacuum.
+A new @code{VACUUM FULL} command does old-style vacuum by locking the table
+and shrinking the on-disk copy of the table.
@item
-A working, tested replication feature used by sites like:
+MySQL replication has been thoroughly tested, and is used by sites like:
@itemize @minus
-@item Yahoo Finance (@uref{http://finance.yahoo.com})
+@item Yahoo Finance (@uref{http://finance.yahoo.com/})
@item Mobile.de (@uref{http://www.mobile.de/})
-@item Slashdot (@uref{http://www.slashdot.org})
+@item Slashdot (@uref{http://www.slashdot.org/})
@end itemize
@item
-Included in the MySQL distribution are two different testing suites,
-@file{mysql-test-run} and
-@uref{http://www.mysql.com/information/crash-me.php,crash-me}, as well
+Included in the MySQL distribution are two different testing suites,
+@file{mysql-test-run} and crash-me
+(@uref{http://www.mysql.com/information/crash-me.php}), as well
as a benchmark suite. The test system is actively updated with code to
-test each new feature and almost all repeatable bugs that have come to
-our attention. We test MySQL with these on a lot of platforms before
-every release. These tests are more sophisticated than anything we have
-seen from PostgreSQL, and they ensures that the MySQL is kept to a high
+test each new feature and almost all reproduceable bugs that have come to
+our attention. We test MySQL Server with these on a lot of platforms before
+every release. These tests are more sophisticated than anything we have
+seen from PostgreSQL, and they ensures that the MySQL Server is kept to a high
standard.
@item
-There are far more books in print about MySQL than about PostgreSQL.
-O'Reilly, Sams, Que, and New Riders are all major publishers with books
+There are far more books in print about MySQL Server than about PostgreSQL.
+O'Reilly, SAMS, Que, and New Riders are all major publishers with books
about MySQL. All MySQL features are also documented in the MySQL on-line
-manual, because when a new feature is implemented, the MySQL developers
+manual, because when a new feature is implemented, the MySQL developers
are required to document it before it's included in the source.
@item
-MySQL supports more of the standard ODBC functions than @code{PostgreSQL}.
+MySQL Server supports more of the standard ODBC functions than @code{PostgreSQL}.
@item
-MySQL has a much more sophisticated @code{ALTER TABLE}.
+MySQL Server has a much more sophisticated @code{ALTER TABLE}.
@item
-MySQL has support for tables without transactions for applications that
+MySQL Server has support for tables without transactions for applications that
need all speed they can get. The tables may be memory based, @code{HEAP}
tables or disk based @code{MyISAM}. @xref{Table types}.
@item
-MySQL has support for two different table handlers that support
-transactions, @code{BerkeleyDB} and @code{InnoDB}. Because every
-transaction engine performs differently under different conditions, this
+MySQL Server has support for two different table handlers that support
+transactions, @code{InnoDB} and @code{BerkeleyDB}. Because every
+transaction engine performs differently under different conditions, this
gives the application writer more options to find an optimal solution for
-his or her setup. @xref{Table types}.
+his or her setup, if need be per individual table. @xref{Table types}.
@item
@code{MERGE} tables gives you a unique way to instantly make a view over
@@ -5267,41 +4880,43 @@ systems where you have log files that you order for example by month.
@item
The option to compress read-only tables, but still have direct access to
-the rows in the table, gives you better performance by minimizing disk
+the rows in the table, gives you better performance by minimising disk
reads. This is very useful when you are archiving things.
@xref{myisampack}.
@item
-MySQL has internal support for fulltext search. @xref{Fulltext Search}.
+MySQL Server has internal support for fulltext search. @xref{Fulltext Search}.
@item
You can access many databases from the same connection (depending of course
on your privileges).
@item
-MySQL is coded from the start to be multi-threaded while PostgreSQL uses
-processes. Context switching and access to common storage areas is much
-faster between threads than between separate processes, this gives MySQL
-a big speed advantage in multi-user applications and also makes it easier
-for MySQL to take full advantage of symmetric multiprocessor (SMP) systems.
+MySQL Server is coded from the start to be multi-threaded while
+PostgreSQL uses processes. Context switching and access to common
+storage areas is much faster between threads than between separate
+processes, this gives MySQL Server a big speed advantage in multi-user
+applications and also makes it easier for MySQL Server to take full
+advantage of symmetric multiprocessor (SMP) systems.
@item
-MySQL has a much more sophisticated privilege system than PostgreSQL.
-While PostgreSQL only supports @code{INSERT}, @code{SELECT}, and
-@code{UPDATE/DELETE} grants per user on a database or a table, MySQL allows
-you to define a full set of different privileges on database, table and
-column level. MySQL also allows you to specify the privilege on host and
-user combinations. @xref{GRANT}.
+MySQL Server has a much more sophisticated privilege system than
+PostgreSQL. While PostgreSQL only supports @code{INSERT},
+@code{SELECT}, and @code{UPDATE/DELETE} grants per user on a database or
+a table, MySQL Server allows you to define a full set of different
+privileges on database, table and column level. MySQL Server also
+allows you to specify the privilege on host and user combinations.
+@xref{GRANT}.
@item
-MySQL supports a compressed client/server protocol which improves
+MySQL Server supports a compressed client/server protocol which improves
performance over slow links.
@item
-MySQL employs a ``table handler'' concept, and is the only relational
-database we know of built around this concept. This allows different
-low-level table types to be swapped into the SQL engine, and each table
-type can be optimized for different performance characteristics.
+MySQL Server employs a ``table handler'' concept, and is the only relational
+database we know of built around this concept. This allows different
+low-level table types to be called from the SQL engine, and each table
+type can be optimised for different performance characteristics.
@item
All MySQL table types (except @strong{InnoDB}) are implemented as files
@@ -5309,26 +4924,27 @@ All MySQL table types (except @strong{InnoDB}) are implemented as files
and even symlink databases and tables, even when the server is down.
@item
-Tools to repair and optimize @strong{MyISAM} tables (the most common
+Tools to repair and optimise @strong{MyISAM} tables (the most common
MySQL table type). A repair tool is only needed when a physical corruption
-of a data file happens, usually from a hardware failure. It allows a
+of a data file happens, usually from a hardware failure. It allows a
majority of the data to be recovered.
@item
-Upgrading MySQL is painless. When you are upgrading MySQL, you don't need
-to dump/restore your data, as you have to do with most PostgreSQL upgrades.
+Upgrading MySQL Server is painless. When you are upgrading MySQL
+Server, you don't need to dump/restore your data, as you have to do with
+most PostgreSQL upgrades.
@end itemize
-Drawbacks with MySQL compared to PostgreSQL:
+Drawbacks with MySQL Server compared to PostgreSQL:
@itemize @bullet
@item
-The transaction support in MySQL is not yet as well tested as PostgreSQL's
-system.
+The transaction support in MySQL Server is not yet as well tested as
+PostgreSQL's system.
@item
-Because MySQL uses threads, which are not yet flawless on many OSes, one
-must either use binaries from @uref{http://www.mysql.com/downloads}, or
+Because MySQL Server uses threads, which are not yet flawless on many OSes, one
+must either use binaries from @uref{http://www.mysql.com/downloads/}, or
carefully follow our instructions on
@uref{http://www.mysql.com/doc/I/n/Installing_source.html} to get an
optimal binary that works in all cases.
@@ -5338,27 +4954,28 @@ Table locking, as used by the non-transactional @code{MyISAM} tables, is
in many cases faster than page locks, row locks or versioning. The
drawback however is that if one doesn't take into account how table
locks work, a single long-running query can block a table for updates
-for a long time. This can usable be avoided when designing the
+for a long time. This can usually be avoided when designing the
application. If not, one can always switch the trouble table to use one
of the transactional table types. @xref{Table locking}.
@item
-With UDF (user defined functions) one can extend MySQL with both normal
+With UDF (user defined functions) one can extend MySQL Server with both normal
SQL functions and aggregates, but this is not yet as easy or as flexible
as in PostgreSQL. @xref{Adding functions}.
@item
-Updates and deletes that run over multiple tables is harder to do in
-MySQL. This will, hoever, be fixed in MySQL 4.0 with multi-table
-@code{DELETE} and multi-table @code{UPDATE} and in MySQL 4.1
-with subselects.
+Updates that run over multiple tables is harder to do in MySQL Server.
+This will, however, be fixed in MySQL Server 4.0.2 with multi-table
+@code{UPDATE} and in MySQL Server 4.1 with subselects. In MySQL Server
+4.0 one can use multi-table deletes to delete from many tables at the
+same time. @xref{DELETE}.
@end itemize
-PostgreSQL currently offers the following advantages over MySQL:
+PostgreSQL currently offers the following advantages over MySQL Server:
Note that because we know the MySQL road map, we have included in the
-following table the version when MySQL should support this feature.
-Unfortunately we couldn't do this for previous comparison, because we
+following table the version when MySQL Server should support this feature.
+Unfortunately we couldn't do this for previous comparison, because we
don't know the PostgreSQL roadmap.
@multitable @columnfractions .70 .30
@@ -5371,13 +4988,13 @@ don't know the PostgreSQL roadmap.
@item Unions @tab 4.0
@item Full join @tab 4.0 or 4.1
@item Triggers @tab 4.1
-@item Constrainst @tab 4.1
+@item Constraints @tab 4.1
@item Cursors @tab 4.1 or 4.2
@item Extensible index types like R-trees @tab R-trees are planned for 4.2
@item Inherited tables @tab Not planned
@end multitable
-Other reasons to use PostgreSQL:
+Other reasons someone may consider for using PostgreSQL:
@itemize @bullet
@item
@@ -5387,14 +5004,26 @@ Standard usage in PostgreSQL is closer to ANSI SQL in some cases.
One can speed up PostgreSQL by coding things as stored procedures.
@item
+For geographical data, R-TREES makes PostgreSQL better than MySQL Server.
+
+@item
+The PostgreSQL optimiser can do some optimisation that the current MySQL
+optimiser can't do. Most notable is doing joins when you don't have the
+proper keys in place and doing a join where you are using different keys
+combined with OR. The MySQL benchmark suite at
+@uref{http://www.mysql.com/information/benchmarks.html} shows you what
+kind of constructs you should watch out for when using different
+databases.
+
+@item
PostgreSQL has a bigger team of developers that contribute to the server.
@end itemize
-Drawbacks with PostgreSQL compared to MySQL:
+Drawbacks with PostgreSQL compared to MySQL Server:
@itemize @bullet
@item
-@code{VACUUM()} makes PostgreSQL hard to use in a 24/7 environment.
+@code{VACUUM} makes PostgreSQL hard to use in a 24/7 environment.
@item
Only transactional tables.
@@ -5406,10 +5035,6 @@ Much slower @code{INSERT}, @code{DELETE}, and @code{UPDATE}.
For a complete list of drawbacks, you should also examine the first table
in this section.
-@menu
-* MySQL-PostgreSQL benchmarks:: Benchmarking MySQL and PostgreSQL
-@end menu
-
@node MySQL-PostgreSQL benchmarks, , MySQL-PostgreSQL features, Compare PostgreSQL
@subsubsection Benchmarking MySQL and PostgreSQL
@@ -5417,7 +5042,7 @@ in this section.
@cindex PostgreSQL vs. MySQL, benchmarks
The only open source benchmark that we know of that can be used to
-benchmark MySQL and PostgreSQL (and other databases) is our own. It can
+benchmark MySQL Server and PostgreSQL (and other databases) is our own. It can
be found at @uref{http://www.mysql.com/information/benchmarks.html}.
We have many times asked the PostgreSQL developers and some PostgreSQL
@@ -5425,53 +5050,53 @@ users to help us extend this benchmark to make it the definitive benchmark
for databases, but unfortunately we haven't gotten any feedback for this.
We the MySQL developers have, because of this, spent a lot of hours to get
-maximum performance from PostgreSQL for the benchmarks, but because we
-don't know PostgreSQL intimately, we are sure that there are things that
-we have missed. We have on the benchmark page documented exactly how we
+maximum performance from PostgreSQL for the benchmarks, but because we
+don't know PostgreSQL intimately, we are sure that there are things that
+we have missed. We have on the benchmark page documented exactly how we
did run the benchmark so that it should be easy for anyone to repeat and
verify our results.
The benchmarks are usually run with and without the @code{--fast} option.
When run with @code{--fast} we are trying to use every trick the server can
do to get the code to execute as fast as possible. The idea is that the
-normal run should show how the server would work in a default setup and
-the @code{--fast} run shows how the server would do if the application
+normal run should show how the server would work in a default setup and
+the @code{--fast} run shows how the server would do if the application
developer would use extensions in the server to make his application run
faster.
-When running with PostgreSQL and @code{--fast} we do a @code{VACUUM()}
+When running with PostgreSQL and @code{--fast} we do a @code{VACUUM}
after every major table @code{UPDATE} and @code{DROP TABLE} to make the
database in perfect shape for the following @code{SELECT}s. The time for
-@code{VACUUM()} is measured separately.
+@code{VACUUM} is measured separately.
When running with PostgreSQL 7.1.1 we could, however, not run with
@code{--fast} because during the @code{INSERT} test, the postmaster (the
PostgreSQL deamon) died and the database was so corrupted that it was
impossible to restart postmaster. After this happened twice, we decided
-to postpone the @code{--fast} test until next PostgreSQL release. The
-details about the machine we run the benchmark can be found on the
+to postpone the @code{--fast} test until next PostgreSQL release. The
+details about the machine we run the benchmark can be found on the
benchmark page.
Before going to the other benchmarks we know of, we would like to give
some background on benchmarks:
-It's very easy to write a test that shows ANY database to be best
+It's very easy to write a test that shows @strong{any} database to be the best
database in the world, by just restricting the test to something the
-database is very good at and not test anything that the database is not
-good at. If one after this publishes the result with a single figure,
-things are even easier.
+database is very good at and not testing anything that the database is
+not good at. If one, after doing this, summarises the result with as
+a single figure, things are even easier.
-This would be like us measuring the speed of MySQL compared to PostgreSQL
+This would be like us measuring the speed of MySQL Server compared to PostgreSQL
by looking at the summary time of the MySQL benchmarks on our web page.
-Based on this MySQL would be more than 40 times faster than PostgreSQL,
-something that is of course not true. We could make things even worse
-by just taking the test where PostgreSQL performs worst and claim that
-MySQL is more than 2000 times faster than PostgreSQL.
+Based on this MySQL Server would be more than 40 times faster than PostgreSQL,
+something that is of course not true. We could make things even worse
+by just taking the test where PostgreSQL performs worst and claim that
+MySQL Server is more than 2000 times faster than PostgreSQL.
-The case is that MySQL does a lot of optimizations that PostgreSQL
+The case is that MySQL does a lot of optimisations that PostgreSQL
doesn't do. This is of course also true the other way around. An SQL
-optimizer is a very complex thing, and a company could spend years on
-just making the optimizer faster and faster.
+optimiser is a very complex thing, and a company could spend years on
+just making the optimiser faster and faster.
When looking at the benchmark results you should look for things that
you do in your application and just use these results to decide which
@@ -5480,25 +5105,25 @@ results also shows things a particular database is not good at and should
give you a notion about things to avoid and what you may have to do in
other ways.
-We know of two benchmark tests that claims that PostgreSQL performs better
-than MySQL. These both where multi-user tests, a test that we here at
-MySQL AB haven't had time to write and include in the benchmark suite,
+We know of two benchmark tests that claims that PostgreSQL performs better
+than MySQL Server. These both where multi-user tests, a test that we here at
+MySQL AB haven't had time to write and include in the benchmark suite,
mainly because it's a big task to do this in a manner that is fair against
all databases.
-One is the benchmark paid for by Great Bridge, which you can read about at:
-@uref{http://www.greatbridge.com/about/press.php?content_id=4}.
-
-This is the probably worst benchmark we have ever seen anyone conduct. This
-was not only tuned to only test what PostgreSQL is absolutely best at, it
-was also totally unfair against every other database involved in the test.
+One is the benchmark paid for by Great Bridge, the company that for 16 months
+attempted to build a business based on PostgreSQL but now has ceased
+operations. This is the probably worst benchmark we have ever seen anyone
+conduct. This was not only tuned to only test what PostgreSQL is absolutely
+best at, it was also totally unfair against every other database involved in
+the test.
-@strong{NOTE}: We know that not even some of the main PostgreSQL
-developers did like the way Great Bridge conducted the benchmark, so we
-don't blame them for the way the benchmark was made.
+@strong{Note}: We know that even some of the main PostgreSQL
+developers did not like the way Great Bridge conducted the benchmark, so we
+don't blame the PostgreSQL team for the way the benchmark was done.
This benchmark has been condemned in a lot of postings and newsgroups so
-we will here just shortly repeat some things that where wrong with it.
+we will here just shortly repeat some things that were wrong with it.
@itemize @bullet
@item
@@ -5509,25 +5134,25 @@ a true benchmark tool, but an application/setup testing tool. To refer
this as a ``standard'' benchmark tool is to stretch the truth a long way.
@item
-Great Bridge admitted that they had optimized the PostgreSQL database
-(with @code{VACUUM()} before the test) and tuned the startup for the tests,
+Great Bridge admitted that they had optimised the PostgreSQL database
+(with @code{VACUUM} before the test) and tuned the startup for the tests,
something they hadn't done for any of the other databases involved. To
-say ``This process optimizes indexes and frees up disk space a bit. The
-optimized indexes boost performance by some margin.'' Our benchmarks
+say ``This process optimises indexes and frees up disk space a bit. The
+optimised indexes boost performance by some margin.'' Our benchmarks
clearly indicate that the difference in running a lot of selects on a
-database with and without @code{VACUUM()} can easily differ by a factor
+database with and without @code{VACUUM} can easily differ by a factor
of ten.
@item
The test results were also strange. The AS3AP test documentation
-mentions that the test does ``selections, simple joins, projections,
+mentions that the test does ``selections, simple joins, projections,
aggregates, one-tuple updates, and bulk updates''.
-PostgreSQL is good at doing @code{SELECT}s and @code{JOIN}s (especially
-after a @code{VACUUM()}), but doesn't perform as well on @code{INSERT}s or
-@code{UPDATE}s. The benchmarks seem to indicate that only @code{SELECT}s
+PostgreSQL is good at doing @code{SELECT}s and @code{JOIN}s (especially
+after a @code{VACUUM}, but doesn't perform as well on @code{INSERT}s or
+@code{UPDATE}s. The benchmarks seem to indicate that only @code{SELECT}s
were done (or very few updates). This could easily explain they good results
-for PostgreSQL in this test. The bad results for MySQL will be obvious a
+for PostgreSQL in this test. The bad results for MySQL will be obvious a
bit down in this document.
@item
@@ -5539,9 +5164,9 @@ database itself.
@item
When running the database against Oracle and MS-SQL (Great Bridge has
-indirectly indicated that the databases they used in the test), they
-didn't use the native protocol but instead ODBC. Anyone that has ever
-used Oracle knows that all real application uses the native interface
+indirectly indicated the databases they used in the test), they
+didn't use the native protocol but instead ODBC. Anyone that has ever
+used Oracle knows that all real application uses the native interface
instead of ODBC. Doing a test through ODBC and claiming that the results
had anything to do with using the database in a real-world situation can't
be regarded as fair. They should have done two tests with and without ODBC
@@ -5552,34 +5177,34 @@ databases of course).
They refer to the TPC-C tests, but they don't mention anywhere that the
test they did was not a true TPC-C test and they were not even allowed to
call it a TPC-C test. A TPC-C test can only be conducted by the rules
-approved by the TPC Council (@uref{http://www.tpc.org}). Great Bridge
+approved by the TPC Council (@uref{http://www.tpc.org/}). Great Bridge
didn't do that. By doing this they have both violated the TPC trademark
-and miscredited their own benchmarks. The rules set by the TPC Council
+and miscredited their own benchmarks. The rules set by the TPC Council
are very strict to ensure that no one can produce false results or make
-unprovable statements. Apparently Great Bridge wasn't interested in
+unprovable statements. Apparently Great Bridge wasn't interested in
doing this.
@item
After the first test, we contacted Great Bridge and mentioned to them
-some of the obvious mistakes they had done with MySQL:
+some of the obvious mistakes they had done with MySQL Server:
@itemize @minus
@item
Running with a debug version of our ODBC driver
@item
-Running on a Linux system that wasn't optimized for threads
+Running on a Linux system that wasn't optimised for threads
@item
Using an old MySQL version when there was a recommended newer one available
@item
-Not starting MySQL with the right options for heavy multi-user use (the
-default installation of MySQL is tuned for minimal resource use).
+Not starting MySQL Server with the right options for heavy multi-user use (the
+default installation of MySQL Server is tuned for minimal resource use).
@end itemize
-Great Bridge did run a new test, with our optimized ODBC driver and with
-better startup options for MySQL, but refused to either use our updated
+Great Bridge did run a new test, with our optimised ODBC driver and with
+better startup options for MySQL Server, but refused to either use our updated
glibc library or our standard binary (used by 80% of our users), which was
statically linked with a fixed glibc library.
@@ -5594,18 +5219,18 @@ only partial, chosen results (instead of publishing it all).
@end itemize
Tim Perdue, a long time PostgreSQL fan and a reluctant MySQL user
-published a comparison on
-@uref{http://www.phpbuilder.com/columns/tim20001112.php3,phpbuider}.
+published a comparison on PHPbuilder
+(@uref{http://www.phpbuilder.com/columns/tim20001112.php3}).
When we became aware of the comparison, we phoned Tim Perdue about this
because there were a lot of strange things in his results. For example,
-he claimed that MySQL had a problem with five users in his tests, when we
+he claimed that MySQL Server had a problem with five users in his tests, when we
know that there are users with similar machines as his that are using
-MySQL with 2000 simultaneous connections doing 400 queries per second.
+MySQL Server with 2000 simultaneous connections doing 400 queries per second.
(In this case the limit was the web bandwidth, not the database.)
It sounded like he was using a Linux kernel that either had some
-problems with many threads, such as kernels before 2.4, which had a problem
+problems with many threads, such as kernels before 2.4, which had a problem
with many threads on multi-CPU machines. We have documented in this manual
how to fix this and Tim should be aware of this problem.
@@ -5623,10 +5248,10 @@ He has not done that yet.
Because of this we can't put any trust in this benchmark either :(
Over time things also changes and the above benchmarks are not that
-relevant anymore. MySQL now have a couple of different table handlers
+relevant anymore. MySQL Server now has a couple of different table handlers
with different speed/concurrency tradeoffs. @xref{Table types}. It
would be interesting to see how the above tests would run with the
-different transactional table types in MySQL. PostgreSQL has of course
+different transactional table types in MySQL Server. PostgreSQL has of course
also got new features since the test was made. As the above test are
not publicly available there is no way for us to know how the
database would preform in the same tests today.
@@ -5635,9 +5260,10 @@ database would preform in the same tests today.
Conclusion:
The only benchmarks that exist today that anyone can download and run
-against MySQL and PostgreSQL is the MySQL benchmarks. We here at MySQL
+against MySQL Server and PostgreSQL is the MySQL benchmarks.
+We here at MySQL AB
believe that open source databases should be tested with open source tools!
-This is the only way to ensure that no one does tests that nobody can
+This is the only way to ensure that no one does tests that nobody can
reproduce and use this to claim that a database is better than another.
Without knowing all the facts it's impossible to answer the claims of the
tester.
@@ -5646,510 +5272,17 @@ The thing we find strange is that every test we have seen about
PostgreSQL, that is impossible to reproduce, claims that PostgreSQL is
better in most cases while our tests, which anyone can reproduce,
clearly shows otherwise. With this we don't want to say that PostgreSQL
-isn't good at many things (it is!) or that it isn't faster than MySQL
+isn't good at many things (it is!) or that it isn't faster than MySQL Server
under certain conditions. We would just like to see a fair test where
they are very good so that we could get some friendly competition going!
-For more information about our benchmarks suite @xref{MySQL Benchmarks}.
+For more information about our benchmarks suite, see @ref{MySQL Benchmarks}.
We are working on an even better benchmark suite, including multi user
tests, and a better documentation of what the individual tests really
do and how to add more tests to the suite.
-@node TODO, , Comparisons, Introduction
-@section MySQL and the future (The TODO)
-
-@cindex ToDo list for MySQL
-
-@menu
-* TODO MySQL 4.0:: Things that should be in Version 4.0
-* TODO future:: Things that must be done in the near future
-* TODO sometime:: Things that have to be done sometime
-* TODO unplanned:: Some things we don't have any plans to do
-@end menu
-
-This appendix lists the features that we plan to implement in MySQL.
-
-Everything in this list is approximately in the order it will be done. If you
-want to affect the priority order, please register a license or support us and
-tell us what you want to have done more quickly. @xref{Licensing and Support}.
-
-The plan is that we in the future will support the full ANSI SQL99
-standard, but with a lot of useful extensions. The challenge is to do
-this without sacrifying the speed or compromise the code.
-
-
-@node TODO MySQL 4.0, TODO future, TODO, TODO
-@subsection Things that should be in 4.0
-
-We plan to make MySQL Version 4.0 a ``quick'' release where we only
-add some new stuff to enable others to help us with developing new features
-into Version 4.1. The MySQL 4.0 version should only take us about
-a month to make after which we want to stabilize it and start working on
-Version 4.1. Version 4.0 should have the following new features:
-
-The news section for 4.0 includes a list of the features we have already
-implemented in the 4.0 tree. @xref{News-4.0.x}.
-
-@itemize @bullet
-@item
-New table definition file format (@code{.frm} files) This will enable us
-to not run out of bits when adding more table options. One will still
-be able to use the old @code{.frm} file format with 4.0. All newly created
-tables will, however, use the new format.
-
-The new file format will enable us to add new column types, more options
-for keys and @code{FOREIGN KEY} support.
-@item
-@code{mysqld} as a library. This will have the same interface as the
-standard MySQL client (with an extra function to just set up
-startup parameters) but will be faster (no TCP/IP or socket overhead),
-smaller and much easier to use for embedded products.
-
-One will be able to define at link time if one wants to use the
-client/server model or a stand-alone application just by defining which
-library to link with.
-
-The @code{mysqld} will support all standard MySQL features and
-one can use it in a threaded client to run different queries in each
-thread.
-@item
-Replication should work with @code{RAND()} and user variables @code{@@var}.
-@item
-Online backup with very low performance penalty. The online backup will
-make it easy to add a new replication slave without taking down the
-master.
-@item
-@code{DELETE FROM table_name} will return the number of deleted rows. For
-fast execution one should use @code{TRUNCATE table_name}.
-@item
-Allow @code{DELETE} on @code{MyISAM} tables to use the record cache.
-To do this, we need to update the threads record cache when we update
-the @code{.MYD} file.
-@item
-Better replication.
-@item
-More functions for full-text search.
-@xref{Fulltext Features to Appear in MySQL 4.0}.
-@item
-Character set casts and syntax for handling multiple character sets.
-@item
-Allow users to change startup options without taking down the server.
-@item
-Help for all commands from the client.
-@item
-Secure connections (with SSL).
-@item
-Extend the optimizer to be able to optimize some @code{ORDER BY key_name DESC}
-queries.
-@item
-@code{SHOW COLUMNS FROM table_name} (used by @code{mysql} client to allow
-expansions of column names) should not open the table, but only the
-definition file. This will require less memory and be much faster.
-@item
-New key cache
-@item
-When using @code{SET CHARACTER SET} we should translate the whole query
-at once and not only strings. This will enable users to use the translated
-characters in database, table and column names.
-@item
-Add a portable interface over @code{gethostbyaddr_r()} so that we can change
-@code{ip_to_hostname()} to not block other threads while doing DNS lookups.
-@item
-Add @code{record_in_range()} method to @code{MERGE} tables to be
-able to choose the right index when there is many to choose from. We should
-also extend the info interface to get the key distribution for each index,
-of @code{analyze} is run on all sub tables.
-@item
-@code{SET SQL_DEFAULT_TABLE_TYPE=[MyISAM | INNODB | BDB | HEAP]}.
-@end itemize
-
-
-@node TODO future, TODO sometime, TODO MySQL 4.0, TODO
-@subsection Things that must be done in the real near future
-
-@itemize @bullet
-@item
-Fail safe replication.
-@item
-Subqueries.
-@code{select id from t where grp in (select grp from g where u > 100)}
-@item
-Derived tables.
-@example
-select a.col1, b.col2 from (select max(col1) as col1 from root_table ) a,
-other_table b where a.col1=b.col1
-@end example
-
-This could be done by automatically creating temporary tables for the
-derived tables for the duration of the query.
-@item
-Add @code{PREPARE} of statements and sending of parameters to @code{mysqld}.
-@item
-Extend the server/client protocol to support warnings.
-@item
-Add options to the server/protocol protocol to get progress notes
-for long running commands.
-@item
-Add database and real table name (in case of alias) to the MYSQL_FIELD
-structure.
-@item
-Don't allow more than a defined number of threads to run MyISAM recover
-at the same time.
-@item
-Change @code{INSERT ... SELECT} to optionally use concurrent inserts.
-@item
-Implement @code{RENAME DATABASE}. To make this safe for all table handlers,
-it should work as follows:
-@itemize @bullet
-@item
-Create the new database.
-@item
-For every table do a rename of the table to another database, as
-we do with the @code{RENAME} command.
-@item
-Drop the old database.
-@end itemize
-@item
-Return the original field types() when doing @code{SELECT MIN(column)
-... GROUP BY}.
-@item
-Multiple result sets.
-@item
-Change the protocol to allow binary transfer of values. To do this
-efficiently, we need to add an API to allow binding of variables.
-@item
-Make it possible to specify @code{long_query_time} with a granularity
-in microseconds.
-@item
-Add a configurable prompt to the @code{mysql} command line client, with
-options like database in use, time and date...
-@item
-Add range checking to @code{MERGE} tables.
-@item
-Link the @code{myisampack} code into the server.
-@item
-Port of MySQL to BeOS.
-@item
-Port of the MySQL clients to LynxOS.
-@item
-Add a temporary key buffer cache during @code{INSERT/DELETE/UPDATE} so that we
-can gracefully recover if the index file gets full.
-@item
-If you perform an @code{ALTER TABLE} on a table that is symlinked to another
-disk, create temporary tables on this disk.
-@item
-Implement a @code{DATE/DATETIME} type that handles time zone information
-properly, so that dealing with dates in different time zones is easier.
-@item
-FreeBSD and MIT-pthreads; Do sleeping threads take CPU?
-@item
-Check if locked threads take any CPU.
-@item
-Fix configure so that one can compile all libraries (like @code{MyISAM})
-without threads.
-@item
-Add an option to periodically flush key pages for tables with delayed keys
-if they haven't been used in a while.
-@item
-Allow join on key parts (optimization issue).
-@item
-@code{INSERT SQL_CONCURRENT} and @code{mysqld --concurrent-insert} to do
-a concurrent insert at the end of the file if the file is read-locked.
-@item
-Remember @code{FOREIGN} key definitions in the @file{.frm} file.
-@item
-Cascading @code{DELETE}
-@item
-Server side cursors.
-@item
-Check if @code{lockd} works with modern Linux kernels; If not, we have
-to fix @code{lockd}! To test this, start @code{mysqld} with
-@code{--enable-locking} and run the different fork* test suits. They shouldn't
-give any errors if @code{lockd} works.
-@item
-Allow SQL variables in @code{LIMIT}, like in @code{LIMIT @@a,@@b}.
-@item
-Allow update of variables in @code{UPDATE} statements. For example:
-@code{UPDATE TABLE foo SET @@a=a+b,a=@@a, b=@@a+c}
-@item
-Change when user variables are updated so that one can use them with
-@code{GROUP BY}, as in the following example:
-@code{SELECT id, @@a:=count(*), sum(sum_col)/@@a FROM table_name GROUP BY id}.
-@item
-Don't add automatic @code{DEFAULT} values to columns. Give an error when using
-an @code{INSERT} that doesn't contain a column that doesn't have a
-@code{DEFAULT}.
-@item
-Caching of queries and results. This should be done as a separated
-module that examines each query and if this is query is in the cache
-the cached result should be returned. When one updates a table one
-should remove as few queries as possible from the cache.
-This should give a big speed bost on machines with much RAM where
-queries are often repeated (like WWW applications).
-One idea would be to only cache queries of type:
-@code{SELECT CACHED ...}
-@item
-Fix @file{libmysql.c} to allow two @code{mysql_query()} commands in a row
-without reading results or give a nice error message when one does this.
-@item
-Optimize @code{BIT} type to take 1 bit (now @code{BIT} takes 1 char).
-@item
-Check why MIT-pthreads @code{ctime()} doesn't work on some FreeBSD systems.
-@item
-Add an @code{IMAGE} option to @code{LOAD DATA INFILE} to not update
-@code{TIMESTAMP} and @code{AUTO_INCREMENT} fields.
-@item
-Added @code{LOAD DATE INFILE.. UPDATE} syntax.
-@itemize @bullet
-@item
-For tables with primary keys, if the data contains the primary key,
-entries matching that primary key are updated from the remainder of the
-columns. However, columns MISSING from the incoming data feed are not
-touched.
-@item
-For tables tables with primary keys that are missing some part of the key
-in the incoming data stream, or that have no primary key, the feed is
-treated as a @code{LOAD DATA INFILE ... REPLACE INTO} is now.
-@end itemize
-@item
-Make @code{LOAD DATA INFILE} understand syntax like:
-@example
-LOAD DATA INFILE 'file_name.txt' INTO TABLE tbl_name
-TEXT_FIELDS (text_field1, text_field2, text_field3)
-SET table_field1=concatenate(text_field1, text_field2), table_field3=23
-IGNORE text_field3
-
-This can be used to skip over extra columns in the text file, or update columns
-based on expressions of the read data...
-@end example
-@item
-@code{LOAD DATA INFILE 'file_name' INTO TABLE 'table_name' ERRORS TO err_table_name}
-This would cause any errors and warnings to be logged into the err_table_name
-table. That table would have a structure like:
-
-@example
-line_number - line number in data file
-error_message - the error/warning message
-and maybe
-data_line - the line from the data file
-@end example
-@item
-Add true @code{VARCHAR} support (There is already support for this in MyISAM).
-@item
-Automatic output from @code{mysql} to netscape.
-@item
-@code{LOCK DATABASES}. (with various options)
-@item
-Change sort to allocate memory in ``hunks'' to get better memory utilization.
-@item
-@code{DECIMAL} and @code{NUMERIC} types can't read exponential numbers;
-@code{Field_decimal::store(const char *from,uint len)} must be recoded
-to fix this.
-@item
-Functions:
-ADD_TO_SET(value,set) and REMOVE_FROM_SET(value,set)
-@item
-Add use of @code{t1 JOIN t2 ON ...} and @code{t1 JOIN t2 USING ...}
-Currently, you can only use this syntax with @code{LEFT JOIN}.
-@item
-Add full support for @code{unsigned long long} type.
-@item
-Many more variables for @code{show status}. Counts for:
-@code{INSERT}/@code{DELETE}/@code{UPDATE} statements. Records reads and
-updated. Selects on 1 table and selects with joins. Mean number of
-tables in select. Number of @code{ORDER BY} and @code{GROUP BY} queries.
-@item
-If you abort @code{mysql} in the middle of a query, you should open
-another connection and kill the old running query.
-Alternatively, an attempt should be made to detect this in the server.
-@item
-Add a handler interface for table information so you can use it as a system
-table. This would be a bit slow if you requested information about all tables,
-but very flexible. @code{SHOW INFO FROM tbl_name} for basic table information
-should be implemented.
-@item
-Add support for UNICODE.
-@item
-@code{NATURAL JOIN} and @code{UNION JOIN}
-@item
-Allow @code{select a from crash_me left join crash_me2 using (a)}; In this
-case a is assumed to come from the crash_me table.
-@item
-Fix that @code{ON} and @code{USING} works with the @code{JOIN}
-join type.
-@item
-Oracle like @code{CONNECT BY PRIOR ...} to search hierarchy structures.
-@item
-@code{mysqladmin copy database new-database}. -- Requires COPY command to be
-added to @code{mysqld}
-@item
-Processlist should show number of queries/thread.
-@item
-@code{SHOW HOSTS} for printing information about the hostname cache.
-@item
-@code{DELETE} and @code{REPLACE} options to the @code{UPDATE} statement
-(this will delete rows when one gets a duplicate key error while updating).
-@item
-Change the format of @code{DATETIME} to store fractions of seconds.
-@item
-Add all missing ANSI92 and ODBC 3.0 types.
-@item
-Change table names from empty strings to @code{NULL} for calculated columns.
-@item
-Don't use 'Item_copy_string' on numerical values to avoid
-number->string->number conversion in case of:
-@code{SELECT COUNT(*)*(id+0) FROM table_name GROUP BY id}
-@item
-Make it possible to use the new GNU regexp library instead of the current
-one (The GNU library should be much faster than the old one).
-@item
-Change that @code{ALTER TABLE} doesn't abort clients that executes
-@code{INSERT DELAYED}.
-@item
-Fix that when columns referenced in an @code{UPDATE} clause contains the old
-values before the update started.
-@item
-@code{myisamchk}, @code{REPAIR} and @code{OPTIMIZE TABLE} should be able
-to handle cases where the data and/or index files are symbolic links.
-@item
-Add simulation of @code{pread()}/@code{pwrite()} on Windows to enable
-concurrent inserts.
-@item
-A logfile analyzer that could parsed out information about which tables
-are hit most often, how often multi-table joins are executed, etc. It
-should help users identify areas or table design that could be optimized
-to execute much more efficient queries.
-@item
-Add @code{SUM(DISTINCT)}
-@item
-Add @code{ANY()},@code{EVERY()} and @code{SOME()} group functions. In
-ANSI SQL these only works on boolean columns, but we can extend these to
-work on any columns/expressions by applying: value == 0 -> FALSE and
-value <> 0 -> TRUE.
-@item
-Fix that the type for @code{MAX(column)} is the same as the column type.
-@example
-create table t1 (a DATE);
-insert into t1 values (now());
-create table t2 select max(a) from t1;
-show columns from t2;
-@end example
-@item
-Come up with a nice syntax for a statement that will @code{UPDATE} the row
-if it exists and @code{INSERT} a new row if the row didn't exist.
-(Like @code{REPLACE} works with @code{INSERT} / @code{DELETE})
-@end itemize
-
-
-@node TODO sometime, TODO unplanned, TODO future, TODO
-@subsection Things that have to be done sometime
-
-@itemize @bullet
-@item
-Implement function: @code{get_changed_tables(timeout,table1,table2,...)}
-@item
-Atomic multi-table updates, eg @code{update items,month set
-items.price=month.price where items.id=month.id;};
-@item
-Change reading through tables to use memmap when possible. Now only
-compressed tables use memmap.
-@item
-Add a new privilege @strong{'Show_priv'} for @code{SHOW} commands.
-@item
-Make the automatic timestamp code nicer. Add timestamps to the update
-log with @code{SET TIMESTAMP=#;}
-@item
-Use read/write mutex in some places to get more speed.
-@item
-Full foreign key support. One probably wants to implement a procedural
-language first.
-@item
-Simple views (first on one table, later on any expression).
-@item
-Automatically close some tables if a table, temporary table or temporary files
-gets error 23 (not enough open files).
-@item
-When one finds a field=#, change all occurrences of field to #. Now this
-is only done for some simple cases.
-@item
-Change all const expressions with calculated expressions if possible.
-@item
-Optimize key = expression. At the moment only key = field or key =
-constant are optimized.
-@item
-Join some of the copy functions for nicer code.
-@item
-Change @file{sql_yacc.yy} to an inline parser to reduce its size and get
-better error messages (5 days).
-@item
-Change the parser to use only one rule per different number of arguments
-in function.
-@item
-Use of full calculation names in the order part. (For ACCESS97)
-@item
-@code{UNION}, @code{MINUS}, @code{INTERSECT} and @code{FULL OUTER JOIN}.
-(Currently only @code{LEFT OUTER JOIN} is supported)
-@item
-Allow @code{UNIQUE} on fields that can be @code{NULL}.
-@item
-@code{SQL_OPTION MAX_SELECT_TIME=#} to put a time limit on a query.
-@item
-Make the update log to a database.
-@item
-Negative @code{LIMIT} to retrieve data from the end.
-@item
-Alarm around client connect/read/write functions.
-@item
-Please note the changes to @code{safe_mysqld}: according to FSSTND (which
-Debian tries to follow) PID files should go into @file{/var/run/<progname>.pid}
-and log files into @file{/var/log}. It would be nice if you could put the
-"DATADIR" in the first declaration of "pidfile" and "log", so the
-placement of these files can be changed with a single statement.
-@item
-Allow a client to request logging.
-@item
-Add use of @code{zlib()} for @code{gzip}-ed files to @code{LOAD DATA INFILE}.
-@item
-Fix sorting and grouping of @code{BLOB} columns (partly solved now).
-@item
-Stored procedures. This is currently not regarded to be very
-important as stored procedures are not very standardized yet.
-Another problem is that true stored procedures make it much harder for
-the optimizer and in many cases the result is slower than before
-We will, on the other hand, add a simple (atomic) update language that
-can be used to write loops and such in the MySQL server.
-@item
-Change to use semaphores when counting threads. One should first implement
-a semaphore library to MIT-pthreads.
-@item
-Don't assign a new @code{AUTO_INCREMENT} value when one sets a column to 0.
-Use @code{NULL} instead.
-@item
-Add full support for @code{JOIN} with parentheses.
-@item
-As an alternative for one thread / connection manage a pool of threads
-to handle the queries.
-@item
-Allow one to get more than one lock with @code{GET_LOCK}. When doing this,
-one must also handle the possible deadlocks this change will introduce.
-@end itemize
-
-Time is given according to amount of work, not real time.
-
-
-@node TODO unplanned, , TODO sometime, TODO
-@subsection Some things we don't have any plans to do
-
-@itemize @bullet
-@item
-Nothing; In the long run we plan to be fully ANSI 92 / ANSI 99 compliant.
-@end itemize
-
-
-
-
@node Installing, Tutorial, Introduction, Top
@chapter MySQL Installation
@@ -6162,6 +5295,7 @@ Nothing; In the long run we plan to be fully ANSI 92 / ANSI 99 compliant.
* Post-installation:: Post-installation setup and testing
* Upgrade:: Upgrading/Downgrading MySQL
* Operating System Specific Notes:: Operating System Specific Notes
+* Perl support:: Perl Installation Comments
@end menu
This chapter describes how to obtain and install MySQL:
@@ -6174,7 +5308,7 @@ For a list of sites from which you can obtain MySQL, see
@item
To see which platforms are supported, see @ref{Which OS}. Please note that
not all supported system are equally good for running MySQL on them.
-On some it is much more robust and efficient than others - see @ref{Which OS}
+On some it is much more robust and efficient than others - see @ref{Which OS}
for details.
@item
@@ -6287,909 +5421,277 @@ installation chapter. @xref{Installing binary}.
@node Windows installation, , Linux-RPM, Quick Standard Installation
@subsection Installing MySQL on Windows
-The following instructions apply to precompiled binary distributions.
-If you download a source distribution, you will have to compile and install
-it yourself.
-
-If you don't have a copy of the MySQL distribution, you should
-first download one from @uref{http://www.mysql.com/downloads/mysql-3.23.html}.
-
-If you plan to connect to MySQL from some other program, you will
-probably also need the @strong{MyODBC} driver. You can find this at the
-@strong{MyODBC} download page
-(@uref{http://www.mysql.com/downloads/api-myodbc.html}).
-
-To install either distribution, unzip it in some empty directory and run the
-@code{Setup.exe} program.
-
-By default, MySQL-Windows is configured to be installed in
-@file{C:\mysql}. If you want to install MySQL elsewhere,
-install it in @file{C:\mysql} first, then move the installation to
-where you want it. If you do move MySQL, you must indicate
-where everything is located by supplying a @code{--basedir} option when
-you start the server. For example, if you have moved the MySQL
-distribution to @file{D:\programs\mysql}, you must start @code{mysqld}
-like this:
-
-@example
-C:\> D:\programs\mysql\bin\mysqld --basedir D:\programs\mysql
-@end example
-
-Use @code{mysqld --help} to display all the options that @code{mysqld}
-understands!
-
-With all newer MySQL versions, you can also create a
-@file{C:\my.cnf} file that holds any default options for the
-MySQL server. Copy the file @file{\mysql\my-xxxxx.cnf} to
-@file{C:\my.cnf} and edit it to suit your setup. Note that you should
-specify all paths with @samp{/} instead of @samp{\}. If you use
-@samp{\}, you need to specify it twice, because @samp{\} is the escape
-character in MySQL. @xref{Option files}.
-
-Starting with MySQL 3.23.38, the Windows distribution includes
-both the normal and the @strong{MySQL-Max} binaries. The main benefit
-of using the normal @code{mysqld.exe} binary is that it's a little
-faster and uses less resources.
-
-Here is a list of the different MySQL servers you can use:
-
-@multitable @columnfractions .25 .75
-@item @code{mysqld} @tab
-Compiled with full debugging and automatic memory allocation checking,
-symbolic links, BDB and InnoDB tables.
-@item @code{mysqld-opt} @tab
-Optimized binary with no support for transactional tables.
-@item @code{mysqld-nt} @tab
-Optimized binary for NT with support for named pipes. You can run this
-version on Win98, but in this case no named pipes are created and you must
-have TCP/IP installed.
-@item @code{mysqld-max} @tab
-Optimized binary with support for symbolic links, BDB and InnoDB tables.
-@item @code{mysqld-max-nt} @tab
-Like @code{mysqld-max}, but compiled with support for named pipes.
-@end multitable
-
-Starting from 3.23.50, named pipes are only enabled if start mysqld with
-@code{--enable-named-pipe}.
-
-All of the above binaries are optimized for the Pentium Pro processor but
-should work on any Intel processor >= i386.
-
-NOTE: If you want to use InnoDB tables, there are certain startup
-options that must be specified in your @file{my.ini} file! @xref{InnoDB start}.
-
-
-@node General Installation Issues, Installing source, Quick Standard Installation, Installing
-@section General Installation Issues
-
-@c @node Methods of Installation, , ,
-@c @subsection Methods of Installation
-
-@c FIX: this needs to be written?
-
-@menu
-* Getting MySQL:: How to Get MySQL
-* Which OS:: Operating Systems Supported by MySQL
-* Which version:: Which MySQL Version to Use
-* Installation layouts:: Installation Layouts
-* Many versions:: How and When Updates Are Released
-* MySQL binaries:: MySQL Binaries Compiled by MySQL AB
-@end menu
-
-
-@node Getting MySQL, Which OS, General Installation Issues, General Installation Issues
-@subsection How to Get MySQL
-
-@cindex downloading
-@cindex MySQL version
-@cindex version, latest
-@cindex getting MySQL
-@cindex mirror sites
-@cindex URLS for downloading MySQL
-
-Check the @uref{http://www.mysql.com/, MySQL home page} for
-information about the current version and for downloading instructions.
-
-Our main download mirror is located at:
-
-@uref{http://download.sourceforge.net/mirrors/mysql/}
-
-If you are interested in becoming a MySQL mirror site, you may
-anonymously rsync with: @code{rsync://download.sourceforge.net/mysql/}. Please
-send e-mail to @email{webmaster@@mysql.com} notifying us of your mirror to be
-added to the list below.
-
-If you have problems downloading from our main site, try using one of the
-mirrors listed below.
-
-Please report bad or out-of-date mirrors to @email{webmaster@@mysql.com}.
-
-@c START_OF_MIRROR_LISTING
-
-@strong{Europe:}
-
-@itemize @bullet
-
-@item
-@c EMAIL: sl@iuinfo.tuwien.ac.at (Tony Sprinzl)
-@image{Flags/austria} Austria [Univ. of Technology/Vienna] @
-@uref{http://gd.tuwien.ac.at/db/mysql/, WWW}
-@uref{ftp://gd.tuwien.ac.at/db/mysql/, FTP}
-
-@c @item
-@c Not ok 20000919; Old site (Matt)
-@c EMAIL: delian@naturella.com (Delian Delchev)
-@c @image{Flags/bulgaria} Bulgaria [Naturella] @
-@c @uref{http://archive.nat.bg/pub/mirror/mysql/, WWW}
-@c @uref{ftp://ftp.ntrl.net/pub/mirror/mysql/, FTP}
-
-@item
-@c EMAIL: salle@online.bg (Admin)
-@image{Flags/bulgaria} Bulgaria [online.bg/Sofia] @
-@uref{http://mysql.online.bg/, WWW}
-@uref{ftp://mysql.online.bg/, FTP}
-
-@c @item
-@c Added: 990614
-@c Not ok 20000919; Out of date (Matt)
-@c EMAIL: vuksan@veus.hr (Vladimir Vuksan)
-@c @image{Flags/croatia} Croatia [HULK] @
-@c @uref{http://ftp.linux.hr/pub/mysql/, WWW}
-@c @uref{ftp://ftp.linux.hr/pub/mysql/, FTP}
-
-@item
-@c Added: 990614
-@c EMAIL: kas@informatics.muni.cz (Jan Kasprzak)
-@image{Flags/czech-republic} Czech Republic [Masaryk University in Brno] @
-@uref{http://mysql.linux.cz/index.html, WWW}
-@uref{ftp://ftp.fi.muni.cz/pub/mysql/, FTP}
-
-@item
-@c Added: 990920
-@c EMAIL: radek@sopik.cz (Radek Libovicky)
-@image{Flags/czech-republic} Czech Republic [www.sopik.cz] @
-@uref{http://www.mysql.cz/, WWW}
-
-@item
-@c Added: 000418
-@c EMAIL: feela@ipex.cz (Ondrej Feela Filip)
-@image{Flags/czech-republic} Czech Republic [www.gin.cz] @
-@uref{http://mysql.gin.cz/, WWW}
-@uref{ftp://ftp.gin.cz/pub/MIRRORS/www.mysql.com/, FTP}
-
-@item
-@c removed 991020 (no DNS entry). New name 991026. Added 991121
-@c Statistics at http://mirror.borsen.dk/
-@c EMAIL: guru@borsen.dk (Jesper Angelo)
-@image{Flags/denmark} Denmark [Borsen] @
-@uref{ http://mysql.borsen.dk/, WWW}
-
-@item
-@c EMAIL: mkp@socsci.auc.dk (Martin Kasper Petersen)
-@image{Flags/denmark} Denmark [SunSITE] @
-@uref{http://mirrors.sunsite.dk/mysql/, WWW}
-@uref{ftp://sunsite.dk/mirrors/mysql/, FTP}
-
-@c @item
-@c Tõnu does not work there anymore :-) 990720
-@c EMAIL: tonu@tradenet.ee (Tõnu Samuel)
-@c @image{Flags/estonia} Estonia [Tradenet] @
-@c @uref{http://mysql.tradenet.ee, WWW}
-
-@item
-@c EMAIL: tonu@spam.ee (Tõnu Samuel)
-@image{Flags/estonia} Estonia [OKinteractive] @
-@uref{http://mysql.mirror.ok.ee, WWW}
-
-@c @item
-@c Changed 990531
-@c Not ok 20000919; Old site (Matt)
-@c EMAIL: Steeve.Devergne@minet.net (Steeve Devergne)
-@c @image{Flags/france} France [minet] @
-@c @uref{http://www.minet.net/devel/mysql/, WWW}
-
-@item
-@c EMAIL: alex@mtesa.net (Alexandre Dupouy)
-@image{Flags/france} France [mtesa.net] @
-@uref{http://mysql.mtesa.net/, WWW}
-
-@item
-@c EMAIL: mrjack@fastorama.com (MrJacK)
-@image{Flags/france} France [fastorama.com, Chatenois] @
-@uref{http://mysql.fastorama.com/, WWW}
-@uref{ftp://ftp.fastorama.com/unix/mysql/, FTP}
-
-@c @item
-@c Not ok 20000919; Old site (Matt)
-@c EMAIL: Jaakko.Hyvatti@eunet.fi
-@c @image{Flags/finland} Finland [EUnet] @
-@c @uref{http://mysql.eunet.fi/, WWW}
-
-@c @item
-@c Added 990829
-@c Not ok 20000919; Non-existent (Matt)
-@c EMAIL: tomi.hakala@clinet.fi (Tomi Hakala)
-@c @image{Flags/finland} Finland [clinet] @
-@c @uref{ftp://ftp.clinet.fi/mirrors/ftp.mysql.org/pub/mysql/, FTP}
-
-@item
-@c Added 20001019
-@c EMAIL: d@d.tj (Dominique L . Bouix)
-@image{Flags/finland} Finland [tonnikala.net] @
-@uref{http://mysql.tonnikala.org/, WWW}
-
-@item
-@c Added 981208
-@c EMAIL: noel@uni-bonn.de (Noel Koethe)
-@image{Flags/germany} Germany [Kernelnotes.de, Bonn] @
-@uref{http://www.kernelnotes.de/mysql/, WWW}
-@uref{ftp://ftp.kernelnotes.de/pub/mirror/mysql.org/, FTP}
-
-@item
-@c EMAIL: th@rz.fh-wolfenbuettel.de (Thorsten Ludewig)
-@image{Flags/germany} Germany [Wolfenbuettel] @
-@uref{http://www.fh-wolfenbuettel.de/ftp/pub/database/mysql/, WWW}
-@uref{ftp://ftp.fh-wolfenbuettel.de/pub/database/mysql/, FTP}
-
-@c @item
-@c Ok 980114. Removed 981208 (down > 3 days) ok 981214
-@c Not ok 20000919; Non-existent (Matt)
-@c EMAIL: straub@gks.de (Hans-Peter Straub)
-@c @image{Flags/germany} Germany [Staufen] @
-@c @uref{http://mysql.staufen.de/, WWW}
-
-@c @item
-@c Added 990614
-@c Not ok 20000919; Non-existent (Matt)
-@c EMAIL: thomas.rohde@ecrc.de (Thomas Rohde)
-@c @image{Flags/germany} Germany [Cable & Wireless] @
-@c @uref{ftp://ftp.ecrc.net/pub/database/mysql/, FTP}
-
-@item
-@c Added 981208
-@c EMAIL: christias@noc.ntua.gr (Panagiotis Christias)
-@image{Flags/greece} Greece [NTUA, Athens] @
-@uref{http://www.ntua.gr/mysql/, WWW}
-@uref{ftp://ftp.ntua.gr/pub/databases/mysql/, FTP}
-
-@item
-@c EMAIL: torlasz@xenia.sote.hu (Laszlo L. Tornoc)
-@image{Flags/hungary} Hungary [Xenia] @
-@uref{http://mysql.sote.hu/, WWW}
-@uref{ftp://xenia.sote.hu/pub/mirrors/www.mysql.com/, FTP}
-
-@item
-@c EMAIL: hendlein@tiszanet.hu (Hendlein Peter)
-@image{Flags/hungary} Hungary [TiszaneT] @
-@uref{http://mysql.tiszanet.hu/, WWW}
-@uref{ftp://mysql.tiszanet.hu/pub/mirrors/mysql/, FTP}
-
-@item
-@c EMAIL: i.habencius@telnet.hu (Habencius Istvan)
-@image{Flags/hungary} Hungary [stop.hu] @
-@uref{http://mysql.mirror.stop.hu/, WWW}
-
-@item
-@c EMAIL: mirrors@gm.is (Tomas Edwardsson)
-@image{Flags/iceland} Iceland [GM] @
-@uref{http://mysql.gm.is/, WWW}
-@uref{ftp://ftp.gm.is/pub/mysql/, FTP}
-
-@c @item
-@c Out of date 990906
-@c EMAIL: bourbon@netvision.net.il (Zeev Suraski)
-@c @image{Flags/israel} Israel [Netvision] @
-@c @uref{http://mysql.netvision.net.il/, WWW}
-
-@c @item
-@c Not working 99.03.06
-@c EMAIL: maruzz@matrice.it (Giovanni Maruzzelli)
-@c @image{Flags/italy} Italy [Matrice] @
-@c @uref{http://www.matrice.it/risorse/mysql/, WWW}
-
-@item
-@c EMAIL: gabriele@feelinglinux.com (Giansante Gabriele)
-@image{Flags/italy} Italy [feelinglinux.com] @
-@uref{http://mysql.feelinglinux.com/, WWW}
-
+The MySQL server for Windows is available in two distribution types:
+@enumerate
@item
-@c EMAIL: irena@yacc.it
-@image{Flags/italy} Italy [Teta Srl] @
-@uref{http://www.teta.it/mysql/, WWW}
-
+The binary distribution contains a setup program which installs
+everything you need so you can start the server immediately.
@item
-@c EMAIL: rudy@comm2000.it (Rudy)
-@image{Flags/italy} Italy [tzone.it] @
-@uref{http://mysql.tzone.it/, WWW}
-
-@c @item
-@c Added 991121
-@c Not ok 20000919; Old site (Matt)
-@c EMAIL: nick@iol.ie (Nick Hilliard)
-@c @image{Flags/ireland} Ireland [Ireland On-Line/Dublin] @
-@c @uref{http://mysql.iol.ie, WWW}
-@c @uref{ftp://ftp.iol.ie/pub/mysql, FTP}
+The source distribution contains all the code and support files
+for building the executables using the VC++ 6.0 compiler.
+@xref{Windows source build}.
+@end enumerate
-@item
-@c Added 20001031
-@c EMAIL: dave@esat.net (Dave Rynne)
-@image{Flags/ireland} Ireland [Esat Net] @
-@uref{http://ftp.esat.net/mirrors/download.sourceforge.net/pub/mirrors/mysql/, WWW}
-@uref{ftp://ftp.esat.net/mirrors/download.sourceforge.net/pub/mirrors/mysql/, FTP}
+Generally speaking, you should use the binary distribution.
+You will need the following:
+@itemize @bullet
@item
-@c Added 20010524
-@c EMAIL: arvids@parks.lv (Arvids)
-@image{Flags/latvia} Latvia [linux.lv] @
-@uref{ftp://ftp.linux.lv/pub/software/mysql/, FTP}
+A Windows 32 bits Operational System of the family Win9x, ME,
+NT and Win 2000. The NT family permits running the MySQL server
+as a service. @xref{NT start}.
+If you want to use tables bigger than 4G, you should install MySQL
+on NTFS or newer file system. Don't forget to use @code{MAX_ROWS} and
+@code{AVG_ROW_LENGTH} when you create the table. @xref{CREATE TABLE}.
@item
-@c Added 20001125
-@c EMAIL: mleicher@silverpoint.nl (Marcel Leicher)
-@image{Flags/netherlands} Netherlands [Silverpoint] @
-@uref{http://mysql.silverpoint.nl/, WWW}
-
+TCP/IP protocol support.
@item
-@c EMAIL: mysql@widexs.nl (Wouter de Jong)
-@image{Flags/netherlands} Netherlands [Widexs BV] @
-@uref{http://mysql.widexs.nl/, WWW}
-@uref{ftp://mysql.widexs.nl/pub/mysql/, FTP}
+A copy of the MySQL binary or distribution for Windows, which
+can be downloaded from @uref{http://www.mysql.com/downloads/}.
+Note: The distribution files are supplied with a zipped format
+and we recommended the use of an adequate FTP client with resume
+feature to avoid corruption of files during the download process.
@item
-@c EMAIL: peter@proserve.nl (ProServe - Peter Batenburg)
-@image{Flags/netherlands} Netherlands [ProServe] @
-@uref{http://mysql.proserve.nl/, WWW}
-
+A @code{ZIP} program to unpacked the distribution file.
@item
-@c EMAIL: W.Sylwestrzak@icm.edu.pl (Wojtek Sylwestrzak)
-@c mirroring nightly at 05:25
-@image{Flags/poland} Poland [Sunsite] @
-@uref{http://sunsite.icm.edu.pl/mysql/, WWW}
-@uref{ftp://sunsite.icm.edu.pl/pub/unix/mysql/, FTP}
-
+Enough space on the hard drive to unpack, install and to create the
+databases in accorandance with your requirements.
@item
-@c EMAIL: admin@net.ncservice.com.pl (Marian Witkowski)
-@image{Flags/poland} Poland [ncservice.com/Gdansk] @
-@uref{http://mysql.service.net.pl/, WWW}
+If you plan to connect to the MySQL server via @code{ODBC}, you
+will also need the @code{MyODBC} driver. @xref{ODBC}.
+@end itemize
-@c @item
-@c EMAIL: melo@co.telenet.pt (Pedro Melo)
-@c Temp out of service (email from Pedro)
-@c @image{Flags/portugal} Portugal [IP] @
-@c @uref{http://mysql.ip.pt, WWW}
-@c @item
-@c Not ok 20000919; Non-existent (Matt)
-@c EMAIL: support@leirianet.pt (Equipa de suporte do Leirianet)
-@c @image{Flags/portugal} Portugal [lerianet] @
-@c @uref{http://mysql.leirianet.pt, WWW}
-@c @uref{ftp://ftp.leirianet.pt/pub/mysql/,FTP}
+@menu
+* Windows binary installation:: Installing the Binaries
+* Windows prepare environment:: Preparing the Windows MySQL Environment
+* Windows server first start:: Starting the Server for the First Time
+@end menu
-@item
-@c Added 20001031
-@c bofh@netc.pt (Bruno Rodrigues)
-@image{Flags/portugal} Portugal [Netc] @
-@uref{http://ftp.netc.pt/pub/mysql/, WWW}
-@uref{ftp://ftp.netc.pt/pub/mysql/, FTP}
-
-@item
-@c EMAIL: keeper@roedu.net (Mihai RUSU)
-@image{Flags/romania} Romania [roedu.net/Bucharest] @
-@uref{ftp://ftp.roedu.net/pub/mirrors/ftp.mysql.com/, FTP}
+@node Windows binary installation, Windows prepare environment, Windows installation, Windows installation
+@subsubsection Installing the Binaries
+@enumerate
@item
-@c EMAIL: kuzmin@dn.ru (Roma Kuzmin)
-@image{Flags/russia} Russia [DirectNet] @
-@uref{http://mysql.directnet.ru/, WWW}
-@uref{ftp://ftp.dn.ru/pub/MySQL/, FTP}
-
-@c @item
-@c down 990113
-@c EMAIL: nikkic@cityline.ru (Nikki Chumakov)
-@c @image{Flags/russia} Russia [Cityline] @
-@c @uref{ftp://mysql.cityline.ru/pub/mysql, FTP}
-@c @uref{http://mysql.cityline.ru, WWW}
-@c EMAIL: bar@izhcom.ru (Alexander I Barkov)
-
-@c @item
-@c Not ok 20000919; Non-existent (Matt)
-@c @image{Flags/russia} Russia [IZHCOM] @
-@c @uref{http://mysql.udm.net/, WWW}
-@c @uref{ftp://ftp.izhcom.ru/pub/mysql/,FTP}
-
+If you are working on an NT or Win2000 server, logon as a user with
+with administrator privileges.
@item
-@c Added 990507
-@c EMAIL: demon@gpad.ac.ru (Dima Sivachenko)
-@image{Flags/russia} Russia [Scientific Center/Chernogolovka] @
-@uref{ftp://ftp.chg.ru/pub/databases/mysql/, FTP}
-
-@c @item
-@c Not ok 20000919; Old site (Matt)
-@c EMAIL: sebi@dnttm.ro (Sebastian DEAC)
-@c @image{Flags/romania} Romania [Timisoara] @
-@c @uref{http://download.dnttm.ro/mysql, WWW}
-@c @uref{ftp://ftp.dnttm.ro/pub/mysql, FTP}
+If you are doing an upgrade of an earlier MySQL installation,
+it is necessary to stop the server. If you are running the server
+as a service, use:
-@c @item
-@c Not ok 20001123; Non-existent (Matt)
-@c EMAIL: tim@lbi.ro (Bogdan Surdu)
-@c @image{Flags/romania}
-@c Romania [Bucharest] @
-@c @uref{http://www.lbi.ro/MySQL/, WWW}
-@c @uref{ftp://ftp.lbi.ro/mirrors/ftp.tcx.se, FTP}
+@example
+C:\> NET STOP MySQL
+@end example
-@c @item
-@c Removed 20000521 because there is no mirror here.
-@c EMAIL: jips@masterd.es (Juan Ignacio Pérez Sacristán)
-@c @image{Flags/spain} Spain [MasterD]
-@c @uref{http://mysql.masterd.es, WWW}
+Otherwise, use:
-@item
-@c EMAIL: Patrik.Karen@sdi.slu.se (Patrik Karen)
-@c ftp -> remove old files
-@image{Flags/sweden} Sweden [Sunet] @
-@uref{http://ftp.sunet.se/pub/unix/databases/relational/mysql/, WWW}
-@uref{ftp://ftp.sunet.se/pub/unix/databases/relational/mysql/, FTP}
+@example
+C:\mysql\bin> mysqladmin -u root shutdown
+@end example
@item
-@c EMAIL: archive@sunsite.cnlab-switch.ch (Thomas Lenggenhager)
-@image{Flags/switzerland} Switzerland [Sunsite] @
-@uref{http://sunsite.cnlab-switch.ch/ftp/mirror/mysql/, WWW}
-@uref{ftp://sunsite.cnlab-switch.ch/mirror/mysql/, FTP}
+On NT/Win2000 machines, if you want to change the server executable
+(e.g. -max or -nt), it is also necessary to remove the service:
-@c @item
-@c Not ok 20000919; Non-existent (Matt)
-@c simon@oyster.co.uk (Simon Gornall)
-@c @image{Flags/great-britain} UK [Oyster/UK] @
-@c @uref{ftp://ftp.oyster.co.uk/pub/mysql, FTP}
-
-@item
-@c EMAIL: keet@mordor.plig.net (Christiaan Keet)
-@image{Flags/great-britain} UK [PLiG/UK] @
-@uref{http://ftp.plig.org/pub/mysql/, WWW}
-@uref{ftp://ftp.plig.org/pub/mysql/, FTP}
-
-@c @item
-@c Not ok 20010808; Non-existent (Matt)
-@c EMAIL: sean@telekon.co.uk (Sean Gibson)
-@c @image{Flags/great-britain} UK [Telekon Internet/UK] @
-@c @uref{ftp://ftp.telekon.co.uk/pub/mysql/, FTP}
-
-@c @item
-@c lance@uklinux.net (Lance)
-@c @image{Flags/great-britain} UK [uklinux.net] @
-@c @uref{http://mirror.uklinux.net/mysql/, WWW}
-@c @uref{ftp://mirror.uklinux.net/pub/mysql/, FTP}
-
-@c @item
-@c unknown
-@c @image{Flags/great-britain} UK [MicroMuse] @
-@c @uref{ftp://ftp.micromuse.co.uk/pub/packages/unix/databases/mysql/, FTP}
-
-@c @item
-@c Not ok 20000919; Old site (Matt)
-@c lmjm@icparc.ic.ac.uk (Lee McLoughlin)
-@c @image{Flags/great-britain} UK [SunSITE] @
-@c @uref{http://sunsite.org.uk/packages/mysql/, WWW}
-@c @uref{ftp://sunsite.org.uk/packages/mysql/, FTP}
-
-@item
-@c EMAIL: sander@paco.net (Alexander Ivanov)
-@image{Flags/ukraine} Ukraine [PACO] @
-@uref{http://mysql.paco.net.ua, WWW}
-@uref{ftp://mysql.paco.net.ua/, FTP}
-
-@item
-@c EMAIL: mizi@alkar.net (Alexander Ryumshin)
-@image{Flags/ukraine} Ukraine [ISP Alkar Teleport/Dnepropetrovsk] @
-@uref{http://mysql.dp.ua/, WWW}
-
-@item
-@c EMAIL: bole@bolex.bolex.co.yu (Bosko Radivojevic)
-@image{Flags/yugoslavia} Yugoslavia [bolex.co.yu] @
-@uref{http://mysql.boa.org.yu/, WWW}
-@uref{ftp://ftp.linux.org.yu/pub/MySQL/, FTP}
-
-@end itemize
-
-@strong{North America:}
-
-@itemize @bullet
-@c @item
-@c Not ok 990101 (only to 981007)
-@c EMAIL: sysop@polarcom.com (Seamus Venasse)
-@c @image{Flags/canada} Canada [Polaris Computing] @
-@c @uref{http://mysql.polaris.ca/, WWW}
-
-@item
-@c Ok 980109
-@c EMAIL: wojtek@tryc.on.ca (Wojtjeck Tryc)
-@image{Flags/canada} Canada [Tryc] @
-@uref{http://web.tryc.on.ca/mysql/, WWW}
-
-@c @item
-@c not updated 990218. Added again 990918
-@c Not ok 20000919; Non-existent (Matt)
-@c EMAIL: rhooper@cyberus.ca (Roy Hooper)
-@c @image{Flags/canada} Canada [Cyberus] @
-@c @uref{http://mysql.cyberus.ca/, WWW}
-@c @uref{ftp://mysql.cyberus.ca/, FTP}
-
-@item
-@c EMAIL: mleber@he.net (Mike Leber)
-@c Added 980312
-@image{Flags/usa} USA [Hurricane Electric/San Jose] @
-@uref{http://mysql.he.net/, WWW}
+@example
+C:\mysql\bin> mysqld-max-nt --remove
+@end example
@item
-@c EMAIL: ask@valueclick.com (Ask Bjoern Hansen)
-@c Added 20000925
-@image{Flags/usa} USA [ValueClick, Los Angeles CA] @
-@uref{http://mysql.valueclick.com/, WWW}
-@uref{ftp://mysql.valueclick.com/pub/mysql/Downloads/, FTP}
-
-@c @item
-@c Not ok 20000919; Non-existent (Matt)
-@c EMAIL: meltzer@icsnet.com (Jeffrey Meltzer)
-@c Added 000108
-@c @image{Flags/usa} USA [Meltzer/New York State] @
-@c @uref{ftp://ftp.meltzer.org/pub/mysql/, FTP}
-
-@c @item
-@c No such directory 990830
-@c EMAIL: tps@users.buoy.com (Tim Sailer)
-@c @image{Flags/usa} USA [Buoy/New York] @
-@c @uref{http://www.buoy.com/mysql/, WWW}
-
-@c @item
-@c EMAIL: db@hpnc.com (Douglas Bowyer)
-@c Added 980107, removed 981124 because of 'file not found'
-@c @image{Flags/usa} USA [Hypernet Communications/Dallas] @
-@c @uref{http://epsilon.hpnc.com/mysql, WWW}
-
-@c @item @c **********************************
-@c Not updated 980106
-@c EX: twh@iquest.net (Thomas Holt) who no longer works there
-@c @image{Flags/usa} USA [IQuest/Indiana] @
-@c @uref{http://mirrors.iquest.net/mysql/, WWW}
-
-@c @item @c **********************************
-@c Only a partial mirror so we exclude it from the list
-@c EX: lindberg@id.wustl.edu (Fred Lindberg)
-@c @image{Flags/usa} USA [Washington University/St. Louis] @
-@c @uref{ftp://ftp.id.wustl.edu/pub/database/mysql/, FTP}
-
-@c removed 991111 -> no answer
-@c @item
-@c EMAIL: andrew@netcasting.net (Andrew Sawyers)
-@c @image{Flags/usa} USA [Netcasting/West Coast] @
-@c @uref{ftp://ftp.netcasting.net/pub/mysql/, FTP}
-
-@c @item
-@c No mirror! 980809 David
-@c EMAIL: savages@savages.com (Shaun Savage)
-@c @image{Flags/usa} USA [Savages/Oregon] @
-@c @uref{http://mysql.savages.com, WWW}
-
-@c @item
-@c Not ok 20000919; Non-existent (Matt)
-@c EMAIL: paul@gina.net (Paul Vining)
-@c mirrors ftp.sunet.se
-@c @image{Flags/usa} USA [Gina net/Florida] @
-@c @uref{http://www.gina.net/mysql/, WWW}
-
-@c Out of date 2000-01-08 (Not updated since 1999-10)
-@c @item
-@c EMAIL: wswanson@pingzero.net (Wylie Swanson)
-@c mirrors mysql.org
-@c @image{Flags/usa} USA [pingzero/Los Angeles] @
-@c @uref{http://mysql.pingzero.net/, WWW}
-
+Unzip the distribution file to a temporary directory.
@item
-@c EMAIL: ftpkeeper@mirror.sit.wisc.edu
-@image{Flags/usa} USA [Wisconsin University/Wisconsin] @
-@uref{http://mirror.sit.wisc.edu/mysql/, WWW}
-@uref{ftp://mirror.sit.wisc.edu/mirrors/mysql/, FTP}
-
-@c @item
-@c Not ok 20000919; Out of date (Matt)
-@c EMAIL: ftp-admin@digex.net
-@c @image{Flags/usa} USA [DIGEX] @
-@c @uref{ftp://ftp.digex.net/pub/packages/database/mysql/, FTP}
-
+Run the @file{setup.exe} file to begin the installation process.
+If you want to install into another directory than the default
+@file{c:\mysql}, use the @code{Browse} button to specify your
+preferred directory.
@item
-@c EMAIL: andrew.sawyers@thelinuxstore.com
-@image{Flags/usa} USA [LinuxWired/Scottsdale, AZ] @
-@uref{http://mysql.linuxwired.net/, WWW}
-@uref{ftp://ftp.linuxwired.net/pub/mirrors/mysql/, FTP}
+Finish the install process.
+@end enumerate
-@c @item
-@c EMAIL: dan@surfsouth.com (Dan Muntz)
-@c @image{Flags/usa} USA [Venoma.Org/Valdosta, GA] @
-@c @uref{http://mysql.venoma.org/, WWW}
-@item
-@c EMAIL: hkind@adgrafix.com (Hans Kind)
-@image{Flags/usa} USA [adgrafix.com/Boston, MA] @
-@uref{http://mysql.adgrafix.com/, WWW}
+@node Windows prepare environment, Windows server first start, Windows binary installation, Windows installation
+@subsubsection Preparing the Windows MySQL Environment
-@item
-@c EMAIL: Pjacob@netnumina.com (Philip Jacob)
-@image{Flags/usa} USA [netNumina/Cambridge, MA] @
-@uref{http://mysql.mirrors.netnumina.com/, WWW}
+Starting with MySQL 3.23.38, the Windows distribution includes
+both the normal and the @strong{MySQL-Max} server binaries.
+Here is a list of the different MySQL servers you can use:
-@item
-@c EMAIL: hagler@ahaza.com (Mark Hagler)
-@image{Flags/usa} USA [Ahaza Systems/Seattle, WA] @
-@uref{http://mysql.mirrortree.com/, WWW}
-@uref{ftp://mysql.mirrortree.com/pub/mysql/, FTP}
+@multitable @columnfractions .25 .75
+@item @strong{Binary} @tab @strong{Description}
+@item @code{mysqld} @tab
+Compiled with full debugging and automatic memory allocation
+checking, symbolic links, InnoDB and BDB tables.
+@item @code{mysqld-opt} @tab
+Optimised binary with no support for transactional tables.
+@item @code{mysqld-nt} @tab
+Optimised binary for NT with support for named pipes. You can
+run this version on Win98, but in this case no named pipes are
+created and you must have TCP/IP installed.
+@item @code{mysqld-max} @tab
+Optimised binary with support for symbolic links,
+InnoDB and BDB tables.
+@item @code{mysqld-max-nt} @tab
+Like @code{mysqld-max}, but compiled with support for named pipes.
+@end multitable
-@end itemize
+Starting from 3.23.50, named pipes are only enabled if one starts mysqld with
+@code{--enable-named-pipe}.
-@strong{South America:}
+All of the above binaries are optimised for the Pentium Pro
+processor but should work on any Intel processor >= i386.
+In the following circumstances you will need to use the MySQL
+configuration file:
@itemize @bullet
-
-@item
-@c Added 20001102
-@c EMAIL: nico@bannerlandia.com (Nicolas Moldavsky)
-@image{Flags/argentina} Argentina [bannerlandia.com] @
-@uref{http://mysql.bannerlandia.com.ar/, WWW}
-@uref{ftp://mysql.bannerlandia.com.ar/mirrors/mysql/, FTP}
-
-@c @item
-@c Not ok 20000919; Non-existent (Matt)
-@c EMAIL: gaiser@matrix.com.br (Roberto Gaiser)
-@c @image{Flags/brazil} Brazil [Matrix] @
-@c @uref{http://mysql.matrix.com.br, WWW}
-
-@item
-@c jpabuyer@vision.cl
-@image{Flags/chile} Chile [Vision] @
-@uref{http://mysql.vision.cl/, WWW}
-
@item
-@c EMAIL: bartschm@psi.com (Marcelo Bartsch)
-@image{Flags/chile} Chile [PSINet] @
-@uref{http://mysql.psinet.cl/, WWW}
-@uref{ftp://ftp.psinet.cl/pub/database/mysql/, FTP}
-
+The install/data directories are different than the default
+@file{c:\mysql} and @file{c:\mysql\data}.
@item
-@c EMAIL: jpabuyer@tecnoera.com (Juan Pablo Abuyeres)
-@image{Flags/chile} Chile [Tecnoera] @
-@uref{http://mysql.tecnoera.com/, WWW}
-
-@c @item
-@c Removed 990730
-@c @c EMAIL: dan@amerikanclaris.com (Danilo Lotina F.)
-@c @image{Flags/chile} Chile [Amerikanclaris] @
-@c @uref{http://www.labs.amerikanclaris.cl/mysql, WWW}
-@c @uref{ftp://ftp.amerikanclaris.cl/pub/mysql, FTP}
-@end itemize
-
-@strong{Asia:}
-
+If you want to use one of the these servers:
@itemize @bullet
-@c @item
-@c Host cannot be resolved for last week at least 20010809 Tonu
-@c EMAIL: mirnshi@263.net (Meng Lingbo)
-@c @image{Flags/china} China [Freecode] @
-@c @uref{http://www.freecode.net.cn/mirror/mysql/, WWW}
-
+@item mysqld.exe
+@item mysqld-max.exe
+@item mysqld-max-nt.exe
+@end itemize
@item
-@c EMAIL: yusun@atwell.co.jp (yu sun)
-@image{Flags/china} China [linuxforum.net] @
-@uref{http://www2.linuxforum.net/mirror/mysql/, WWW}
+If you need to tune the server settings.
+@end itemize
-@item
-@c EMAIL: vfong@hklpg.org (Vincent Fong)
-@image{Flags/china} China [HKLPG/Hong Kong] @
-@uref{http://mysql.hklpg.org, WWW}
+Normally you can use the @code{WinMySQLAdmin} tool to edit the
+configuration file @code{my.ini}. In this case you don't have to worry
+about the following section.
-@item
-@c EMAIL: jason-wong@gremlins.com.hk (Gremlins Jason Wong)
-@image{Flags/china} China [Gremlins/Hong Kong] @
-@uref{http://mysql.gremlins.com.hk/, WWW}
-@uref{ftp://ftp.mirrors.gremlins.com.hk/mysql/, FTP}
+There are two configuration files with the same function: @file{my.cnf}
+and @file{my.ini} file, however please note that only of one these
+should be used to avoid confusion. Both files are plain text. The
+@file{my.cnf} file , if used, should be created in the root directory of
+drive C and the @file{my.ini} file on the WinDir directory e.g:
+@file{C:\WINDOWS} or @file{C:\WINNT}. MySQL will first read the
+@code{my.ini} file, followed by the @code{my.cnf} file.
-@item
-@c EMAIL: shell@linux.org.hk (Shell Hung)
-@image{Flags/china} China [shellhung.org/Hong Kong] @
-@uref{http://mysql.shellhung.org/, WWW}
-@uref{ftp://ftp.shellhung.org/pub/Mirror/mysql/, FTP}
+If your PC uses a boot loader where the C drive isn't the boot drive,
+then your only option is to use the @file{my.ini} file. Also note that
+if you use the @code{WinMySQLAdmin} tool, only the @file{my.ini} file is
+used by this tool. The @file{\mysql\bin} directory contains a help file
+with instructions for using this tool.
-@c @item
-@c Not ok 20010308; Other content! (Tonu)
-@c EMAIL: xcyber@yahoo.com (xcyber)
-@c @image{Flags/china} China [xcyber.org/Hong Kong] @
-@c @uref{http://mysql.xcyber.org/, WWW}
+Using @code{notepad.exe}, create the configuration file and
+edit the base section and keys:
-@c @item
-@c Not ok 20010330; Non-existent! (Matt)
-@c EMAIL: marquischan@hotmail.com (Marquis Chan)
-@c @image{Flags/china} China [TraLand.com/Hong Kong] @
-@c @uref{http://www.traland.com/mysql/, WWW}
+@example
+[mysqld]
+basedir=the_install_path #e.g. c:/mysql
+datadir=the_data_path #e.g. c:/mysql/data or d:/mydata/data
+@end example
-@c @item
-@c Not ok 20000919; Non-existent (Matt)
-@c EMAIL: george@netfirm.net (Hongsheng Zhu)
-@c @image{Flags/china} China [Netfirm] @
-@c @uref{http://mysql.netfirm.net, WWW}
+If the data directory is other than the default
+@file{c:\mysql\data}, you must cut the whole @file{\data\mysql}
+directory and paste it on the your option new directory,
+e.g.: @file{d:\mydata\mysql}.
-@item
-@c EMAIL: dnata@incaf.net (Denie Nataprawira)
-@image{Flags/indonesia} Indonesia [incaf.net] @
-@uref{http://mysql.incaf.net/, WWW}
+If you want to use the @code{InnoDB} transactional tables, you
+need to manually create two new directories to hold the InnoDB
+data and log files, e.g. @file{c:\ibdata} and @file{c:\iblogs}.
+You will also need to add some extra lines to the configuration
+file. @xref{InnoDB start}.
-@item
-@c EMAIL: andika@piksi.itb.ac.id (Andika Triwidada)
-@image{Flags/indonesia} Indonesia [web.id] @
-@uref{http://mysql.itb.web.id/, WWW}
-@uref{ftp://mysql.itb.web.id/pub/MySQL/, FTP}
+If you don't want to use @code{InnoDB} tables, add the
+@code{skip-innodb} option to the configuration file.
-@item
-@c Ok 980805
-@c EMAIL: takeshi@SoftAgency.co.jp
-@image{Flags/japan} Japan [Soft Agency] @
-@uref{http://www.softagency.co.jp/MySQL, WWW}
+Now you are ready to test starting the server.
-@item
-@c EMAIL: takafumi@u-aizu.ac.jp (Takafumi Hayashi)
-@image{Flags/japan} Japan [u-aizu.ac.jp/Aizu] @
-@uref{ftp://ftp.u-aizu.ac.jp/ftp/pub/dbms/mysql/mysql.com, FTP}
-@c @item
-@c Ok 980109 Removed 990730
-@c EMAIL: satoshi@HappySize.co.jp (Satoshi TATSUOKA)
-@c @image{Flags/japan} Japan [HappySize] @
-@c @uref{http://www.happysize.co.jp/mysql/, WWW}
-@c @uref{ftp://ftp.happysize.co.jp/pub/mysql/, FTP}
+@node Windows server first start, , Windows prepare environment, Windows installation
+@subsubsection Starting the Server for the First Time
-@c @item
-@c Ok 981204
-@c Not ok 20000919; Old site (Matt)
-@c EMAIL: hiroyuki@nucba.ac.jp (hiroyuki kurimoto)
-@c @image{Flags/japan} Japan [Nagoya Syouka University] @
-@c @uref{http://mirror.nucba.ac.jp/mirror/mysql, WWW}
-@c @uref{ftp://mirror.nucba.ac.jp/mirror/mysql, FTP}
+Testing from a DOS command prompt is the best thing to do because
+the server prints messages, so if something is wrong with your
+configuration you will see a more accurate error message which
+will make it easier for you to identify and fix any problems.
-@c @item
-@c Not ok 20000919; Old site (Matt)
-@c EMAIL: ahmlhs@nmsvr.chosun.com (Ho-sun Lee)
-@c @image{Flags/south-korea} South Korea [KREONet] @
-@c @uref{http://linux.kreonet.re.kr/mysql/, WWW}
+Make sure you are in the right directory, then enter:
-@item
-@c EMAIL: jasper@webiiz.com (Kang, Tae-jin)
-@image{Flags/south-korea} South Korea [Webiiz] @
-@uref{http://mysql.webiiz.com/, WWW}
+@example
+C:\mysql\bin> mysqld-max --standalone
+@end example
-@item
-@c EMAIL: hollywar@holywar.net (Oh Junseon)
-@image{Flags/south-korea} South Korea [PanworldNet] @
-@uref{http://mysql.holywar.net/, WWW}
-
-@c @item
-@c ftp -> remove old files
-@c EX: ahmlhs@nmsvr.chosun.com (Ho-sun Lee)
-@c @image{Flags/south-korea} South Korea [KREONet] @
-@c @uref{ftp://linux.kreonet.re.kr/pub/tools/db/mysql/, FTP}
-
-@c @item
-@c Removed 990308
-@c EMAIL: terence@com5.net (Terence Chan)
-@c @image{Flags/singapore} Singapore [Com5 Productions] @
-@c @uref{http://mysql.com5.net, WWW}
-@c @uref{ftp://ftp.com5.net/pub/mysql, FTP}
-
-@item
-@c EMAIL: csy@hjc.edu.sg
-@image{Flags/singapore} Singapore [HJC] @
-@uref{http://mysql.hjc.edu.sg, WWW}
-@uref{ftp://ftp.hjc.edu.sg/mysql, FTP}
-
-@c @item
-@c Not ok 20000919; Old site (Matt)
-@c 991118: Removed because a user complained about that the page contains
-@c nothing about MySQL. 991119: Added again because it is a mirror again
-@c EMAIL: dean@ht.net.tw (Dean Lin)
-@c @image{Flags/taiwan} Taiwan [HT] @
-@c @uref{http://mysql.ht.net.tw, WWW}
+You should see the below print messages:
-@item
-@c EMAIL: linda@ttn.com.tw (Linda Hu)
-@image{Flags/taiwan} Taiwan [TTN] @
-@uref{http://mysql.ttn.net, WWW}
+@example
+InnoDB: The first specified data file c:\ibdata\ibdata1 did not exist:
+InnoDB: a new database to be created!
+InnoDB: Setting file c:\ibdata\ibdata1 size to 209715200
+InnoDB: Database physically writes the file full: wait...
+InnoDB: Log file c:\iblogs\ib_logfile0 did not exist: new to be created
+InnoDB: Setting log file c:\iblogs\ib_logfile0 size to 31457280
+InnoDB: Log file c:\iblogs\ib_logfile1 did not exist: new to be created
+InnoDB: Setting log file c:\iblogs\ib_logfile1 size to 31457280
+InnoDB: Log file c:\iblogs\ib_logfile2 did not exist: new to be created
+InnoDB: Setting log file c:\iblogs\ib_logfile2 size to 31457280
+InnoDB: Doublewrite buffer not found: creating new
+InnoDB: Doublewrite buffer created
+InnoDB: creating foreign key constraint system tables
+InnoDB: foreign key constraint system tables created
+011024 10:58:25 InnoDB: Started
+@end example
+
+For further information about running MySQL on Windows,
+see @ref{Windows}.
-@c @item
-@c Ok 980321 No connect -> removed 990730
-@c EMAIL: tby@ccca.nctu.edu.tw (Bao-Yi Tuang)
-@c @image{Flags/taiwan} Taiwan [NCTU] @
-@c @uref{http://mysql.taconet.com.tw, WWW}
-@c @item
-@c Out of date 990905 (~2 months)
-@c @item @c **********************************
-@c Error 980106
-@c EX: WolfySu@acer.net (Wolfy Su)
-@c @image{Flags/taiwan} Taiwan [Acer] @
-@c @uref{http://mysql.acer.net/, WWW}
+@node General Installation Issues, Installing source, Quick Standard Installation, Installing
+@section General Installation Issues
-@c @item @c **********************************
-@c files to delete
-@c EX: service@wownet.net
-@c @image{Flags/taiwan} Taiwan [Wownet] @
-@c @uref{ftp://ftp.wownet.net/mysql/, FTP}
+@c @node Methods of Installation, , ,
+@c @subsection Methods of Installation
-@c @item @c **********************************
-@c No contact 980106
-@c EX: serge@oneway.net
-@c @image{Flags/taiwan} Taiwan [Oneway] @
-@c @uref{ftp://ftp.oneway.com.tw/pub/mysql/, FTP}
+@c FIX: this needs to be written?
-@item
-@c Added 20001031
-@c EMAIL: ijliao@php.nctu.edu.tw (Ying-Chieh Liao)
-@image{Flags/taiwan} Taiwan [nctu.edu/HsinChu] @
-@uref{http://mysql.nctu.edu.tw/, WWW}
+@menu
+* Getting MySQL:: How to Get MySQL
+* Which OS:: Operating Systems Supported by MySQL
+* Which version:: Which MySQL Version to Use
+* Installation layouts:: Installation Layouts
+* Many versions:: How and When Updates Are Released
+* MySQL binaries:: MySQL Binaries Compiled by MySQL AB
+* Installing binary:: Installing a MySQL Binary Distribution
+@end menu
-@end itemize
-
-@c @strong{Australia:}
-@c @itemize @bullet
-@c @item
-@c Added 980610
-@c EMAIL: jason@dstc.edu.au (Jason Andrade)
-@c @image{Flags/australia} Australia [AARNet/Queensland] @
-@c @uref{http://mysql.mirror.aarnet.edu.au/, WWW}
-@c @uref{ftp://mysql.mirror.aarnet.edu.au/, FTP}
+@node Getting MySQL, Which OS, General Installation Issues, General Installation Issues
+@subsection How to Get MySQL
-@c @item
-@c Added 980805. Removed 000102 'no such directory'
-@c EMAIL: sdd@ntccc.tas.gov.au (Scott Donovan)
-@c @image{Flags/australia} Australia [Tas] @
-@c @uref{http://ftp.tas.gov.au/mysql, WWW}
-@c @uref{ftp://ftp.tas.gov.au/pub/mysql, FTP}
+@cindex downloading
+@cindex MySQL version
+@cindex version, latest
+@cindex getting MySQL
+@cindex mirror sites
+@cindex URLS for downloading MySQL
-@c @item
-@c Ok 980623
-@c Not ok 20000919; Old site (Matt)
-@c EMAIL: samh@bluep.com (Sam Hadzajlic)
-@c @image{Flags/australia} Australia [Blue Planet/Melbourne] @
-@c @uref{http://mysql.bluep.com/, WWW}
-@c removed because ftp was not working 990729 & 30
-@c @uref{ftp://mysql.bluep.com/pub/mirror1/mysql/, FTP}
+Check the MySQL homepage (@uref{http://www.mysql.com/}) for
+information about the current version and for downloading instructions.
-@c @item
-@c Added 990531
-@c EMAIL: gavin@itworks.com.au (Gavin Cameron)
-@c @image{Flags/australia} Australia [ITworks Consulting/Victoria] @
-@c @uref{http://mysql.itworks.com.au, WWW}
+Our main download mirror is located at:
-@c @item
-@c 980610 Only the toplevel dir!
-@c EMAIL: lucifer@maths.uq.edu.au (David Conran)
-@c @image{Flags/australia} Australia FTP @
-@c @uref{ftp://ftp.sage-au.org.au/pub/database/mysql, [Sage]}
-@c @end itemize
+@uref{http://mirrors.sunsite.dk/mysql/}
-@strong{Africa:}
+If you are interested in becoming a MySQL mirror site, you may
+anonymously rsync with: @code{rsync://sunsite.dk/ftp/mirrors/mysql/}. Please
+send e-mail to @email{webmaster@@mysql.com} notifying us of your mirror to be
+added to the list below.
-@itemize @bullet
+If you have problems downloading from our main site, try using one of the
+mirrors listed below.
-@item
-@c EMAIL: ftp-admin@mweb.com (Warren Baker)
-@image{Flags/south-africa1} South-Africa [Mweb] @
-@uref{http://www.mysql.mweb.co.za/, WWW}
+Please report bad or out-of-date mirrors to @email{webmaster@@mysql.com}.
-@item
-@c Ok 981010
-@c EMAIL: oskar@is.co.za (Oskar Pearson)
-@image{Flags/south-africa1} South Africa [The Internet Solution/Johannesburg] @
-@uref{ftp://ftp.is.co.za/linux/mysql/, FTP}
+@c START_OF_MIRROR_LISTING
-@end itemize
+@c Mirrors list is created by PHP script (that really needs to be documented!) from database (tfr@mysql.com)
+@include mirrors.texi
@c END_OF_MIRROR_LISTING
@@ -7250,9 +5752,10 @@ Solaris 2.5 and above with native threads on SPARC and x86. @xref{Solaris}.
@item
SunOS 4.x with the included MIT-pthreads package. @xref{Solaris}.
@item
-SCO OpenServer with a recent port of the FSU Pthreads package. @xref{SCO}.
+Caldera (SCO) OpenServer with a recent port of the FSU Pthreads package.
+@xref{Caldera}.
@item
-SCO UnixWare 7.0.1. @xref{SCO Unixware}.
+Caldera (SCO) UnixWare 7.0.1. @xref{Caldera Unixware}.
@item
Tru64 Unix
@item
@@ -7294,7 +5797,7 @@ efficiently, if your tables are big.
@item
Our level of expertise here at MySQL AB with the platform. If we know
-a platform well, we introduce platform-specific optimizations/fixes enabled at
+a platform well, we introduce platform-specific optimisations/fixes enabled at
compile time. We can also provide advice on configuring your system optimally
for MySQL.
@@ -7313,7 +5816,7 @@ ReiserFS (or any similar Linux distribution) and Sparc with Solaris 2.7
or 2.8. FreeBSD comes third, but we really hope it will join the top
club once the thread library is improved. We also hope that at some
point we will be able to include all other platforms on which
-MySQL compiles, runs ok, but not quite with the same level of
+MySQL compiles, runs okay, but not quite with the same level of
stability and performance, into the top category. This will require some
effort on our part in cooperation with the developers of the OS/library
components MySQL depends upon. If you are interested in making
@@ -7328,7 +5831,7 @@ for a dedicated purpose - running MySQL, and compare platforms in that
regard only. With this in mind, the result of this comparison
would be different if we included more issues into it. And in some cases,
the reason one OS is better than the other could simply be that we have put
-forth more effort into testing on and optimizing for that particular platform.
+forth more effort into testing on and optimising for that particular platform.
We are just stating our observations to help you make a
decision on which platform to use MySQL on in your setup.
@@ -7347,12 +5850,12 @@ release or the last stable release:
@itemize @bullet
@item
-Normally, if you are beginning to use MySQL for the first time
-or trying to port it to some system for which there is no binary
-distribution, we recommend going with the stable release (currently
-Version @value{mysql_version}. Note that all MySQL releases are
-checked with the MySQL benchmarks and an extensive test suite
-before each release.
+Normally, if you are beginning to use MySQL for the first time or trying
+to port it to some system for which there is no binary distribution, we
+recommend going with the stable release (currently Version 3.23. Note
+that all MySQL releases are checked with the MySQL benchmarks and an
+extensive test suite before each release (even the development
+releases).
@item
Otherwise, if you are running an old system and want to upgrade, but
@@ -7392,13 +5895,13 @@ If you want to use the @code{MySQL-Max} RPM, you must first
install the standard @code{MySQL} RPM.
@item
-If you want to configure @code{mysqld} with some extra features that are
-NOT in the standard binary distributions. Here is a list of the most
+If you want to configure @code{mysqld} with some extra features that are
+not in the standard binary distributions. Here is a list of the most
common extra options that you may want to use:
@itemize @bullet
-@item @code{--with-berkeley-db}
@item @code{--with-innodb}
+@item @code{--with-berkeley-db}
@item @code{--with-raid}
@item @code{--with-libwrap}
@item @code{--with-named-z-lib (This is done for some of the binaries)}
@@ -7412,7 +5915,7 @@ the same processor family.
If you want a faster MySQL server you may want to recompile it
with support for only the character sets you need, use a better compiler
-(like @code{pgcc}) or use compiler options that are better optimized for your
+(like @code{pgcc}) or use compiler options that are better optimised for your
processor.
@item
@@ -7436,7 +5939,7 @@ numbers and a suffix. For example, a release name like
@itemize @bullet
@item
-The first number (@code{3}) describes the file format. All Version 3
+The first number (@code{3}) describes the file format. All Version 3
releases have the same file format.
@item
@@ -7456,7 +5959,7 @@ The suffix (@code{beta}) indicates the stability level of the release.
The possible suffixes are:
@itemize @minus
-@item
+@item
@code{alpha} indicates that the release contains some large section of
new code that hasn't been 100% tested. Known bugs (usually there are none)
should be documented in the News section. @xref{News}. There are also new
@@ -7502,7 +6005,7 @@ hundreds of megabytes of data.
@item The MySQL benchmark suite
This runs a range of common queries. It is also a test to see whether the
-latest batch of optimizations actually made the code faster.
+latest batch of optimisations actually made the code faster.
@xref{MySQL Benchmarks}.
@item The @code{crash-me} test
@@ -7613,7 +6116,8 @@ Stable tested releases are meant to appear about 1-2 times a year, but
if small bugs are found, a release with only bug fixes will be released.
@item
-Working releases are meant to appear about every 1-8 weeks.
+Working releases/bug fixes to old releases are meant to appear about
+every 1-8 weeks.
@item
Binary distributions for some platforms will be made by us for major releases.
@@ -7622,12 +6126,12 @@ less frequently.
@item
We usually make patches available as soon as we have located and fixed
-small bugs.
+small bugs. They are posted to @email{bugs@@lists.mysql.com} and will
+be added to the next release.
@item
-For non-critical but annoying bugs, we will make patches available if they
-are sent to us. Otherwise we will combine many of them into a larger
-patch.
+For non-critical but annoying bugs, we will add them the MySQL source
+repository and they will be fixed in the next release.
@item
If there is, by any chance, a fatal bug in a release we will make a new
@@ -7642,8 +6146,12 @@ and things that ``must be done.'' ``Somewhat frozen'' means that we may
add small things that ``almost surely will not affect anything that's
already working.''
+MySQL uses a little different naming scheme that most other products.
+In general it's relatively safe to use any version that has been out for
+a couple of weeks without being replaced with a new version.
+@xref{Which version}.
-@node MySQL binaries, , Many versions, General Installation Issues
+@node MySQL binaries, Installing binary, Many versions, General Installation Issues
@subsection MySQL Binaries Compiled by MySQL AB
@cindex binary distributions
@@ -7695,13 +6203,233 @@ above can always mail them to the developer's mailing list at
@email{internals@@lists.mysql.com}.
RPM distributions prior to MySQL Version 3.22 are user-contributed.
-Beginning with Version 3.22, the RPMs are generated by us at
+Beginning with Version 3.22, the RPMs are generated by us at
MySQL AB.
If you want to compile a debug version of MySQL, you should add
@code{--with-debug} or @code{--with-debug=full} to the above configure lines
and remove any @code{-fomit-frame-pointer} options.
+For the Windows distribution, please see @ref{Windows installation}.
+
+
+@node Installing binary, , MySQL binaries, General Installation Issues
+@subsection Installing a MySQL Binary Distribution
+
+@cindex installing, binary distribution
+@cindex binary distributions, installing
+
+See also @ref{Windows binary installation},
+@ref{Linux-RPM}, and @ref{Building clients}.
+
+You need the following tools to install a MySQL binary distribution:
+
+@itemize @bullet
+@item
+GNU @code{gunzip} to uncompress the distribution.
+
+@item
+A reasonable @code{tar} to unpack the distribution. GNU @code{tar} is
+known to work. Sun @code{tar} is known to have problems.
+@end itemize
+
+@cindex RPM, defined
+@cindex RedHat Package Manager
+An alternative installation method under Linux is to use RPM (RedHat Package
+Manager) distributions. @xref{Linux-RPM}.
+
+@c texi2html fails to split chapters if I use strong for all of this.
+If you run into problems, @strong{please always use @code{mysqlbug}} when
+posting questions to @email{mysql@@lists.mysql.com}. Even if the problem
+isn't a bug, @code{mysqlbug} gathers system information that will help others
+solve your problem. By not using @code{mysqlbug}, you lessen the likelihood
+of getting a solution to your problem! You will find @code{mysqlbug} in the
+@file{bin} directory after you unpack the distribution. @xref{Bug reports}.
+
+@cindex commands, for binary distribution
+The basic commands you must execute to install and use a MySQL
+binary distribution are:
+
+@example
+shell> groupadd mysql
+shell> useradd -g mysql mysql
+shell> cd /usr/local
+shell> gunzip < /path/to/mysql-VERSION-OS.tar.gz | tar xvf -
+shell> ln -s full-path-to-mysql-VERSION-OS mysql
+shell> cd mysql
+shell> scripts/mysql_install_db
+shell> chown -R root .
+shell> chown -R mysql ./data
+shell> chgrp -R mysql .
+shell> chown -R root ./bin
+shell> bin/safe_mysqld --user=mysql &
+or
+shell> bin/mysqld_safe --user=mysql &
+if you are running MySQL 4.x
+@end example
+
+@cindex adding, new users
+@cindex new users, adding
+@cindex users, adding
+
+You can add new users using the @code{bin/mysql_setpermission} script if
+you install the @code{DBI} and @code{Msql-Mysql-modules} Perl modules.
+
+A more detailed description follows.
+
+To install a binary distribution, follow the steps below, then proceed
+to @ref{Post-installation}, for post-installation setup and testing:
+
+@enumerate
+@item
+Pick the directory under which you want to unpack the distribution, and move
+into it. In the example below, we unpack the distribution under
+@file{/usr/local} and create a directory @file{/usr/local/mysql} into which
+MySQL is installed. (The following instructions therefore assume
+you have permission to create files in @file{/usr/local}. If that directory
+is protected, you will need to perform the installation as @code{root}.)
+
+@item
+Obtain a distribution file from one of the sites listed in
+@ref{Getting MySQL, , Getting MySQL}.
+
+MySQL binary distributions are provided as compressed @code{tar}
+archives and have names like @file{mysql-VERSION-OS.tar.gz}, where
+@code{VERSION} is a number (for example, @code{3.21.15}), and @code{OS}
+indicates the type of operating system for which the distribution is intended
+(for example, @code{pc-linux-gnu-i586}).
+
+@item
+If you see a binary distribution marked with the @code{-max} prefix, this
+means that the binary has support for transaction-safe tables and other
+features. @xref{mysqld-max, , @code{mysqld-max}}. Note that all binaries
+are built from the same MySQL source distribution.
+
+@item
+Add a user and group for @code{mysqld} to run as:
+
+@example
+shell> groupadd mysql
+shell> useradd -g mysql mysql
+@end example
+
+These commands add the @code{mysql} group and the @code{mysql} user. The
+syntax for @code{useradd} and @code{groupadd} may differ slightly on different
+versions of Unix. They may also be called @code{adduser} and @code{addgroup}.
+You may wish to call the user and group something else instead of @code{mysql}.
+
+@item
+Change into the intended installation directory:
+
+@example
+shell> cd /usr/local
+@end example
+
+@item
+Unpack the distribution and create the installation directory:
+
+@example
+shell> gunzip < /path/to/mysql-VERSION-OS.tar.gz | tar xvf -
+shell> ln -s full-path-to-mysql-VERSION-OS mysql
+@end example
+
+The first command creates a directory named @file{mysql-VERSION-OS}. The
+second command makes a symbolic link to that directory. This lets you refer
+more easily to the installation directory as @file{/usr/local/mysql}.
+
+@item
+Change into the installation directory:
+
+@example
+shell> cd mysql
+@end example
+
+You will find several files and subdirectories in the @code{mysql} directory.
+The most important for installation purposes are the @file{bin} and
+@file{scripts} subdirectories.
+
+@table @file
+@item bin
+@tindex PATH environment variable
+@tindex environment variable, PATH
+This directory contains client programs and the server
+You should add the full pathname of this directory to your
+@code{PATH} environment variable so that your shell finds the MySQL
+programs properly. @xref{Environment variables}.
+
+@item scripts
+This directory contains the @code{mysql_install_db} script used to initialise
+the @code{mysql} database containing the grant tables that store the server
+access permissions.
+@end table
+
+@item
+If you would like to use @code{mysqlaccess} and have the MySQL
+distribution in some non-standard place, you must change the location where
+@code{mysqlaccess} expects to find the @code{mysql} client. Edit the
+@file{bin/mysqlaccess} script at approximately line 18. Search for a line
+that looks like this:
+
+@example
+$MYSQL = '/usr/local/bin/mysql'; # path to mysql executable
+@end example
+
+Change the path to reflect the location where @code{mysql} actually is
+stored on your system. If you do not do this, you will get a @code{Broken
+pipe} error when you run @code{mysqlaccess}.
+
+@item
+Create the MySQL grant tables (necessary only if you haven't
+installed MySQL before):
+@example
+shell> scripts/mysql_install_db
+@end example
+
+Note that MySQL versions older than Version 3.22.10 started the
+MySQL server when you run @code{mysql_install_db}. This is no
+longer true!
+
+@item
+Change ownership of binaries to @code{root} and ownership of the data
+directory to the user that you will run @code{mysqld} as:
+
+@example
+shell> chown -R root /usr/local/mysql
+shell> chown -R mysql /usr/local/mysql/data
+shell> chgrp -R mysql /usr/local/mysql
+@end example
+
+The first command changes the @code{owner} attribute of the files to the
+@code{root} user, the second one changes the @code{owner} attribute of the
+data directory to the @code{mysql} user, and the third one changes the
+@code{group} attribute to the @code{mysql} group.
+
+@item
+If you want to install support for the Perl @code{DBI}/@code{DBD} interface,
+see @ref{Perl support}.
+
+@item
+If you would like MySQL to start automatically when you boot your
+machine, you can copy @code{support-files/mysql.server} to the location where
+your system has its startup files. More information can be found in the
+@code{support-files/mysql.server} script itself and in
+@ref{Automatic start}.
+
+@end enumerate
+
+After everything has been unpacked and installed, you should initialise
+and test your distribution.
+
+You can start the MySQL server with the following command:
+
+@example
+shell> bin/safe_mysqld --user=mysql &
+@end example
+
+@xref{safe_mysqld, , @code{safe_mysqld}}.
+
+@xref{Post-installation}.
+
@node Installing source, Post-installation, General Installation Issues, Installing
@section Installing a MySQL Source Distribution
@@ -7711,7 +6439,7 @@ and remove any @code{-fomit-frame-pointer} options.
@cindex installation overview
Before you proceed with the source installation, check first to see if our
-binary is available for your platform and if it will work for you. We
+binary is available for your platform and if it will work for you. We
put in a lot of effort into making sure that our binaries are built with the
best possible options.
@@ -7746,26 +6474,28 @@ sometimes required. If you have problems, we recommend trying GNU
@end itemize
If you are using a recent version of @strong{gcc}, recent enough to understand
-@code{-fno-exceptions} option, it is @strong{VERY IMPORTANT} that you use
+@code{-fno-exceptions} option, it is @strong{very important} that you use
it. Otherwise, you may compile a binary that crashes randomly. We also
-recommend that you use @code{-felide-contructors} and @code{-fno-rtti} along
+recommend that you use @code{-felide-constructors} and @code{-fno-rtti} along
with @code{-fno-exceptions}. When in doubt, do the following:
@example
-CFLAGS="-O3" CXX=gcc CXXFLAGS="-O3 -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --enable-assembler --with-mysqld-ldflags=-all-static
+CFLAGS="-O3" CXX=gcc CXXFLAGS="-O3 -felide-constructors -fno-exceptions \
+ -fno-rtti" ./configure --prefix=/usr/local/mysql --enable-assembler \
+ --with-mysqld-ldflags=-all-static
@end example
On most systems this will give you a fast and stable binary.
@c texi2html fails to split chapters if I use strong for all of this.
-If you run into problems, @strong{PLEASE ALWAYS USE @code{mysqlbug}} when
+If you run into problems, @strong{please always use @code{mysqlbug}} when
posting questions to @email{mysql@@lists.mysql.com}. Even if the problem
isn't a bug, @code{mysqlbug} gathers system information that will help others
solve your problem. By not using @code{mysqlbug}, you lessen the likelihood
of getting a solution to your problem! You will find @code{mysqlbug} in the
-@file{scripts} directory after you unpack the distribution.
+@file{scripts} directory after you unpack the distribution.
@xref{Bug reports}.
@menu
@@ -7775,6 +6505,7 @@ of getting a solution to your problem! You will find @code{mysqlbug} in the
* Installing source tree:: Installing from the Development Source Tree
* Compilation problems:: Problems Compiling?
* MIT-pthreads:: MIT-pthreads Notes
+* Windows source build:: Windows Source Distribution
@end menu
@@ -7798,6 +6529,9 @@ shell> chown -R mysql /usr/local/mysql/var
shell> chgrp -R mysql /usr/local/mysql
shell> cp support-files/my-medium.cnf /etc/my.cnf
shell> /usr/local/mysql/bin/safe_mysqld --user=mysql &
+or
+shell> /usr/local/mysql/bin/mysqld_safe --user=mysql &
+if you are running MySQL 4.x.
@end example
If you want have support for InnoDB tables, you should edit the
@@ -7819,7 +6553,7 @@ you install the @code{DBI} and @code{Msql-Mysql-modules} Perl modules.
A more detailed description follows.
To install a source distribution, follow the steps below, then proceed
-to @ref{Post-installation}, for post-installation initialization and testing:
+to @ref{Post-installation}, for post-installation initialisation and testing:
@enumerate
@item
@@ -7917,7 +6651,7 @@ MySQL server when you run @code{mysql_install_db}. This is no
longer true!
@item
-Change ownership of binaries to @code{root} and ownership of the data
+Change ownership of binaries to @code{root} and ownership of the data
directory to the user that you will run @code{mysqld} as:
@example
@@ -7927,7 +6661,7 @@ shell> chgrp -R mysql /usr/local/mysql
@end example
The first command changes the @code{owner} attribute of the files to the
-@code{root} user, the second one changes the @code{owner} attribute of the
+@code{root} user, the second one changes the @code{owner} attribute of the
data directory to the @code{mysql} user, and the third one changes the
@code{group} attribute to the @code{mysql} group.
@@ -7939,11 +6673,11 @@ see @ref{Perl support}.
If you would like MySQL to start automatically when you boot your
machine, you can copy @code{support-files/mysql.server} to the location where
your system has its startup files. More information can be found in the
-@code{support-files/mysql.server} script itself and in
+@code{support-files/mysql.server} script itself and in
@ref{Automatic start}.
@end enumerate
-After everything has been installed, you should initialize and test your
+After everything has been installed, you should initialise and test your
distribution:
@example
@@ -7952,7 +6686,7 @@ shell> /usr/local/mysql/bin/safe_mysqld --user=mysql &
If that command fails immediately with @code{mysqld daemon ended} then you can
find some information in the file @file{mysql-data-directory/'hostname'.err}.
-The likely reason is that you already have another @code{mysqld} server
+The likely reason is that you already have another @code{mysqld} server
running. @xref{Multiple servers}.
@xref{Post-installation}.
@@ -7965,8 +6699,8 @@ running. @xref{Multiple servers}.
@cindex applying, patches
Sometimes patches appear on the mailing list or are placed in the
-@uref{http://www.mysql.com/Downloads/Patches, patches area} of the
-MySQL Web site.
+patches area of the MySQL web site
+(@uref{http://www.mysql.com/Downloads/Patches/}).
To apply a patch from the mailing list, save the message in which the patch
appears in a file, change into the top-level directory of your MySQL
@@ -8043,6 +6777,10 @@ warnings about @file{mysql.cc}. (If @code{make} stops, try @code{make -k}
to tell it to continue with the rest of the build even if errors occur.)
@item
+If you want to get a embedded MySQL library (@code{libmysqld.a}) you should
+use the @code{--with-embedded-server} option.
+
+@item
If you don't want your log files and database directories located under
@file{/usr/local/var}, use a @code{configure} command, something like one
of these:
@@ -8058,7 +6796,8 @@ installed under @file{/usr/local/mysql} rather than the default of
@file{/usr/local}. The second command preserves the default installation
prefix, but overrides the default location for database directories
(normally @file{/usr/local/var}) and changes it to
-@code{/usr/local/mysql/data}.
+@code{/usr/local/mysql/data}. After you have compiled MySQL, you can
+change these options with option files. @xref{Option files}.
@cindex changing socket location
@cindex socket location, changing
@@ -8073,7 +6812,7 @@ shell> ./configure --with-unix-socket-path=/usr/local/mysql/tmp/mysql.sock
@end example
Note that the given file must be an absolute pathname!
-You can also later change the location @file{mysql.sock} by using the MySQL
+You can also later change the location @file{mysql.sock} by using the MySQL
option files. @xref{Problems with mysql.sock}.
@cindex compiling, statically
@@ -8115,33 +6854,41 @@ the compiler you are using:
@tindex CXXFLAGS environment variable
@tindex environment variable, CXXFLAGS
@multitable @columnfractions .20 .80
+@item @strong{Compiler} @tab @strong{Recommended options}
@item gcc 2.7.2.1 @tab
CC=gcc CXX=gcc CXXFLAGS="-O3 -felide-constructors"
@item egcs 1.0.3a @tab
CC=gcc CXX=gcc CXXFLAGS="-O3 -felide-constructors -fno-exceptions -fno-rtti"
@item gcc 2.95.2 @tab
-CFLAGS="-O3 -mpentiumpro" CXX=gcc CXXFLAGS="-O3 -mpentiumpro -felide-constructors -fno-exceptions -fno-rtti"
+CFLAGS="-O3 -mpentiumpro" CXX=gcc CXXFLAGS="-O3 -mpentiumpro \
+-felide-constructors -fno-exceptions -fno-rtti"
@item pgcc 2.90.29 or newer @tab
-CFLAGS="-O3 -mpentiumpro -mstack-align-double" CXX=gcc CXXFLAGS="-O3 -mpentiumpro -mstack-align-double -felide-constructors -fno-exceptions -fno-rtti"
+CFLAGS="-O3 -mpentiumpro -mstack-align-double" CXX=gcc \
+CXXFLAGS="-O3 -mpentiumpro -mstack-align-double -felide-constructors \
+-fno-exceptions -fno-rtti"
@end multitable
In most cases you can get a reasonably optimal MySQL binary by
using the options from the above and adding the following options to the
-configure line:
+configure line:
@example
---prefix=/usr/local/mysql --enable-assembler --with-mysqld-ldflags=-all-static
+--prefix=/usr/local/mysql --enable-assembler \
+--with-mysqld-ldflags=-all-static
@end example
The full configure line would in other words be something like the
following for all recent gcc versions:
@example
-CFLAGS="-O3 -mpentiumpro" CXX=gcc CXXFLAGS="-O3 -mpentiumpro -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --enable-assembler --with-mysqld-ldflags=-all-static
+CFLAGS="-O3 -mpentiumpro" CXX=gcc CXXFLAGS="-O3 -mpentiumpro \
+-felide-constructors -fno-exceptions -fno-rtti" ./configure \
+--prefix=/usr/local/mysql --enable-assembler \
+--with-mysqld-ldflags=-all-static
@end example
-The binaries we provide on the MySQL Web site at
-@uref{http://www.mysql.com} are all compiled with full optimization and
+The binaries we provide on the MySQL web site at
+@uref{http://www.mysql.com/} are all compiled with full optimisation and
should be perfect for most users. @xref{MySQL binaries}. There are some
things you can tweak to make an even faster binary, but this is only for
advanced users. @xref{Compile and link options}.
@@ -8222,7 +6969,7 @@ applications. @xref{Threaded clients}.
@item
Options that pertain to particular systems can be found in the
-system-specific section of this manual.
+system-specific section of this manual.
@xref{Operating System Specific Notes}.
@end itemize
@@ -8234,7 +6981,7 @@ system-specific section of this manual.
@cindex BitKeeper tree
@cindex cvs tree
-@strong{CAUTION:} You should read this section only if you are interested
+@strong{Caution:} You should read this section only if you are interested
in helping us test our new code. If you just want to get MySQL up
and running on your system, you should use a standard release distribution
(either a source or binary distribution will do).
@@ -8251,7 +6998,8 @@ Download @strong{BitKeeper} from
Follow the instructions to install it.
@item
-After @strong{BitKeeper} is installed, use this command if you want to clone
+After @strong{BitKeeper} is installed, first go to the directory you
+want to work from, and then use this command if you want to clone
the MySQL 3.23 branch:
@example
@@ -8264,12 +7012,18 @@ To clone the 4.0 branch, use this command instead:
shell> bk clone bk://work.mysql.com:7001 mysql-4.0
@end example
+In the above examples the source tree will be set up in the @file{mysql/}
+or @file{mysql-4.0/} subdirectory of your current directory.
+
The initial download of the source tree may take a while, depending on the
speed of your connection; be patient.
@item
-You will need GNU @code{autoconf}, @code{automake}, @code{libtool}, and
-@code{m4} to run the next set of commands.
+You will need GNU @code{autoconf 2.52}, @code{automake 1.4},
+@code{libtool}, and @code{m4} to run the next set of commands.
+
+@code{automake} (1.5) doesn't yet work.
+
If you get some strange error during this stage, check that you really
have @code{libtool} installed!
@@ -8317,7 +7071,7 @@ You can examine the change history for the tree with all the diffs by using
@code{bk sccstool}. If you see some funny diffs or code that you have a
question about, do not hesitate to send e-mail to
@email{internals@@lists.mysql.com}. Also, if you think you have a better idea
-on how to do something, send an email to the same address with a patch.
+on how to do something, send an e-mail to the same address with a patch.
@code{bk diffs} will produce a patch for you after you have made changes
to the source. If you do not have the time to code your idea, just send
a description.
@@ -8551,7 +7305,7 @@ link your clients with the new client library. @xref{Debugging client}.
@end itemize
-@node MIT-pthreads, , Compilation problems, Installing source
+@node MIT-pthreads, Windows source build, Compilation problems, Installing source
@subsection MIT-pthreads Notes
@cindex MIT-pthreads
@@ -8577,7 +7331,7 @@ shell> ./configure --with-mit-threads
@end example
Building in a non-source directory is not supported when using
-MIT-pthreads, because we want to minimize our changes to this code.
+MIT-pthreads, because we want to minimise our changes to this code.
@item
The checks that determine whether or not to use MIT-pthreads occur only
@@ -8610,7 +7364,7 @@ a restart immediately.
@item
With MIT-pthreads, the @code{sleep()} system call isn't interruptible with
-@code{SIGINT} (break). This is only noticeable when you run
+@code{SIGINT} (break). This is only noticeable when you run
@code{mysqladmin --sleep}. You must wait for the @code{sleep()} call to
terminate before the interrupt is served and the process stops.
@@ -8643,6 +7397,75 @@ needed, but may be interesting for someone.)
@end itemize
+@node Windows source build, , MIT-pthreads, Installing source
+@subsection Windows Source Distribution
+
+You will need the following:
+
+@itemize @bullet
+@item
+VC++ 6.0 compiler (updated with 4 or 5 SP and Pre-processor package)
+The Pre-processor package is necessary for the macro assembler.
+More details at:
+@uref{http://msdn.microsoft.com/vstudio/sp/vs6sp5/faq.asp}.
+@item
+The MySQL source distribution for Windows, which can be downloaded
+from @uref{http://www.mysql.com/downloads/}.
+@end itemize
+
+Building MySQL
+
+@enumerate
+@item
+Create a work directory (e.g.: workdir).
+@item
+Unpack the source distribution in the above directory.
+@item
+Start the VC++ 6.0 compiler.
+@item
+In the @code{File} menu, select @code{Open Workspace}.
+@item
+Open the @file{mysql.dsw} workspace you find on the work directory.
+@item
+From the @code{Build} menu,
+select the @code{Set Active Configuration} menu.
+@item
+Click over the screen selecting @code{mysqld - Win32 Debug}
+and click OK.
+@item
+Press @code{F7} to begin the build of the debug server, libs and
+some client applications.
+@item
+When the compilation finishes, copy the libs and the executables
+to a separate directory.
+@item
+Compile the release versions that you want, in the same way.
+@item
+Create the directory for the MySQL stuff: e.g. @file{c:\mysql}
+@item
+From the workdir directory copy for the c:\mysql directory the
+following directories:
+
+@itemize @bullet
+@item Data
+@item Docs
+@item Share
+@end itemize
+
+@item
+Create the directory @file{c:\mysql\bin} and copy all the servers
+and clients that you compiled previously.
+@item
+If you want, also create the @file{lib} directory and copy the
+libs that you compiled previously.
+@item
+Do a clean using Visual Studio.
+@end enumerate
+
+Set up and start the server in the same way as for the binary
+Windows distribution. @xref{Windows prepare environment}.
+
+
@node Post-installation, Upgrade, Installing source, Installing
@section Post-installation Setup and Testing
@@ -8657,7 +7480,7 @@ needed, but may be interesting for someone.)
@end menu
Once you've installed MySQL (from either a binary or source
-distribution), you need to initialize the grant tables, start the server,
+distribution), you need to initialise the grant tables, start the server,
and make sure that the server works okay. You may also wish to arrange
for the server to be started and stopped automatically when your system
starts up and shuts down.
@@ -8764,10 +7587,10 @@ script as it is provided in the MySQL distribution:
@itemize @bullet
@item
-You may want to edit @code{mysql_install_db} before running it, to change
-the initial privileges that are installed into the grant tables. This is
-useful if you want to install MySQL on a lot of machines with the
-same privileges. In this case you probably should need only to add a few
+You may want to edit @code{mysql_install_db} before running it, to change
+the initial privileges that are installed into the grant tables. This is
+useful if you want to install MySQL on a lot of machines with the
+same privileges. In this case you probably should need only to add a few
extra @code{INSERT} statements to the @code{mysql.user} and @code{mysql.db}
tables!
@@ -8824,7 +7647,10 @@ TCP port 3306
UNIX socket /tmp/mysql.sock
Uptime: 16 sec
-Threads: 1 Questions: 9 Slow queries: 0 Opens: 7 Flush tables: 2 Open tables: 0 Queries per second avg: 0.000 Memory in use: 132K Max memory used: 16773K
+Threads: 1 Questions: 9 Slow queries: 0
+Opens: 7 Flush tables: 2 Open tables: 0
+Queries per second avg: 0.000
+Memory in use: 132K Max memory used: 16773K
@end example
To get a feeling for what else you can do with @code{BINDIR/mysqladmin},
@@ -9015,7 +7841,7 @@ If you are running RedHat Version 5.0 with a version of @code{glibc} older than
2.0.7-5, you should make sure you have installed all @code{glibc} patches!
There is a lot of information about this in the MySQL mail
archives. Links to the mail archives are available online at
-@uref{http://www.mysql.com/documentation/}.
+@uref{http://lists.mysql.com/}.
Also, see @ref{Linux}.
You can also start @code{mysqld} manually using the @code{--skip-grant-tables}
@@ -9038,11 +7864,11 @@ reload the grant tables.
@cindex server, starting problems
@cindex problems, starting the server
-If you are going to use tables that support transactions (BDB, InnoDB),
+If you are going to use tables that support transactions (InnoDB, BDB),
you should first create a my.cnf file and set startup options
for the table types you plan to use. @xref{Table types}.
-Generally, you start the @code{mysqld} server in one of three ways:
+Generally, you start the @code{mysqld} server in one of these ways:
@itemize @bullet
@item
@@ -9056,23 +7882,7 @@ for @code{mysqld} and then runs it with those options. @xref{safe_mysqld, ,
@code{safe_mysqld}}.
@item
-On NT you should install @code{mysqld} as a service as follows:
-@example
-bin\mysqld-nt --install # Install MySQL as a service
-@end example
-
-You can now start/stop @code{mysqld} as follows:
-@example
-NET START mysql
-NET STOP mysql
-@end example
-
-Note that in this case you can't use any other options for @code{mysqld}!
-
-You can remove the service as follows:
-@example
-bin\mysqld-nt --remove # remove MySQL as a service
-@end example
+For Windows NT/2000, please see @ref{NT start}.
@item
By invoking @code{mysqld} directly.
@@ -9109,7 +7919,7 @@ correctly, check the log file to see if you can find out why. Log files
are located in the data directory (typically
@file{/usr/local/mysql/data} for a binary distribution,
@file{/usr/local/var} for a source distribution,
-@file{\mysql\data\mysql.err} on Windows.) Look in the data directory for
+@file{\mysql\data\mysql.err} on Windows). Look in the data directory for
files with names of the form @file{host_name.err} and
@file{host_name.log} where @code{host_name} is the name of your server
host. Then check the last few lines of these files:
@@ -9153,7 +7963,7 @@ Can't start server : Bind on unix socket...
Use @code{ps} to make sure that you don't have another @code{mysqld} server
running. If you can't find another server running, you can try to execute
the command @code{telnet your-host-name tcp-ip-port-number} and press
-@code{RETURN} a couple of times. If you don't get an error message like
+Enter a couple of times. If you don't get an error message like
@code{telnet: Unable to connect to remote host: Connection refused},
something is using the TCP/IP port @code{mysqld} is trying to use.
See @ref{mysql_install_db} and @ref{Multiple servers}.
@@ -9171,6 +7981,13 @@ or
shell> mysqladmin -h 'your-host-name' variables
@end example
+If you get @code{Errcode 13}, which means @code{Permission denied}, when
+starting @code{mysqld} this means that you didn't have the right to
+read/create files in the MySQL database or log directory. In this case
+you should either start @code{mysqld} as the root user or change the
+permissions for the involved files and directories so that you have the
+right to use them.
+
If @code{safe_mysqld} starts the server but you can't connect to it,
you should make sure you have an entry in @file{/etc/hosts} that looks like
this:
@@ -9188,7 +8005,7 @@ to find the problem. @xref{Making trace files}.
If you are using InnoDB tables, refer to the InnoDB-specific startup
options. @xref{InnoDB start}.
-If you are using BDB (Berkeley DB) tables, you should familiarize
+If you are using BDB (Berkeley DB) tables, you should familiarise
yourself with the different BDB specific startup options. @xref{BDB start}.
@@ -9218,7 +8035,7 @@ directory of the MySQL source tree.
Before @code{mysql.server} starts the server, it changes directory to
the MySQL installation directory, then invokes @code{safe_mysqld}.
You might need to edit @code{mysql.server} if you have a binary distribution
-that you've installed in a non-standard location. Modify it to @code{cd}
+that you've installed in a non-standard location. Modify it to @code{cd}
into the proper directory before it runs @code{safe_mysqld}. If you want the
server to run as some specific user, add an appropriate @code{user} line
to the @file{/etc/my.cnf} file, as shown later in this section.
@@ -9310,14 +8127,112 @@ particularly if you notice symptoms such as all your @code{DBI} scripts
dumping core after you upgrade MySQL.
@menu
+* Upgrading-from-3.23:: Upgrading from a 3.23 version to 4.0
* Upgrading-from-3.22:: Upgrading from a 3.22 version to 3.23
* Upgrading-from-3.21:: Upgrading from a 3.21 version to 3.22
* Upgrading-from-3.20:: Upgrading from a 3.20 version to 3.21
* Upgrading-to-arch:: Upgrading to another architecture
@end menu
+@cindex compatibility, between MySQL versions
+@cindex upgrading, 3.23 to 4.0
+@node Upgrading-from-3.23, Upgrading-from-3.22, Upgrade, Upgrade
+@subsection Upgrading From Version 3.23 to Version 4.0
-@node Upgrading-from-3.22, Upgrading-from-3.21, Upgrade, Upgrade
+You can use your old data files without any modification with Version 4.0.
+If you want to move your data from a MySQL 4.0 server to an older server,
+you have to use @code{mysqldump}.
+
+Old clients should work with a Version 4.0 server without any problems.
+
+The following lists tell what you have to watch out for when upgrading to
+version 4.0;
+
+@itemize @bullet
+@item
+@code{DOUBLE} and @code{FLOAT} columns are now honoring the
+@code{UNSIGNED} flag on storage (before @code{UNSIGNED} was ignored for
+these columns).
+@item
+Use @code{ORDER BY column DESC} now always sorts @code{NULL} values
+first; In 3.23 this was not always consistent.
+@item
+@code{SHOW INDEX} has 2 columns more (@code{Null} and @code{Index_type})
+than it had in 3.23.
+@item
+@code{SIGNED} is a reserved word.
+@item
+The result of all bitwise operators @code{|}, @code{&}, @code{<<},
+@code{>>} and @code{~} is now unsigned. This may cause problems if you
+are using them in a context where you want a signed result.
+@xref{Cast Functions}.
+@item
+@strong{NOTE:} When you use subtraction between integer values where
+one is of type @code{UNSIGNED}, the result will be unsigned! In other
+words, before upgrading to MySQL 4.0, you should check your application
+for cases where you are subtracting a value from an unsigned entity and
+want a negative answer or subtracting an unsigned value from an
+integer column. You can disable this behaviour by using the
+@code{--sql-mode=NO_UNSIGNED_SUBTRACTION} option when starting
+@code{mysqld}. @xref{Cast Functions}.
+@item
+To use @code{MATCH ... AGAINST (... IN BOOLEAN MODE)} with your tables,
+you need to rebuild them with @code{ALTER TABLE table_name TYPE=MyISAM},
+@strong{even} if they are of @code{MyISAM} type.
+@item
+@code{LOCATE()} and @code{INSTR()} are case sensitive if one of the
+arguments is a binary string.
+@item
+@code{STRCMP()} now uses the current character set when doing comparison,
+which means that the default comparison is case insensitive.
+@item
+@code{HEX(string)} now returns the characters in string converted to
+hexadecimal. If you want to convert a number to hexadecimal, you should
+ensure that you call @code{HEX()} with a numeric argument.
+@item
+In 3.23, @code{INSERT INTO ... SELECT} always had @code{IGNORE} enabled.
+In 4.0.1, MySQL will stop (and possibly roll back) in case of an error if you
+don't specify @code{IGNORE}.
+@item
+@file{safe_mysqld} is renamed to @file{mysqld_safe}.
+@item
+The old C API functions @code{mysql_drop_db}, @code{mysql_create_db} and
+@code{mysql_connect} are not supported anymore, unless you compile
+MySQL with @code{CFLAGS=-DUSE_OLD_FUNCTIONS}. Instead of doing this,
+it is preferable to change the client to use the new 4.0 API.
+@item
+In the @code{MYSQL_FIELD} structure, @code{length} and @code{max_length} has
+changed from @code{unsigned int} to @code{unsigned long}. This should not
+cause any other problems than some warnings if you use these to
+@code{printf()} type function.
+@item
+You should use @code{TRUNCATE TABLE} when you want to delete all rows
+from a table and you don't care of how many rows where deleted.
+(Because @code{TRUNCATE TABLE} is faster than @code{DELETE FROM table_name}).
+@item
+You will get an error if you have an active @code{LOCK TABLES} or
+transaction when trying to execute @code{TRUNCATE TABLE} or @code{DROP
+DATABASE}.
+@item
+You should use integers to store values in BIGINT columns (instead of using
+strings as you did in MySQL 3.23). Using strings will still work, but using
+integers is more efficient.
+@item
+Format of @code{SHOW OPEN TABLE} has changed.
+@item
+Multithreaded clients should use @code{mysql_thread_init()} and
+@code{mysql_thread_end()}. @xref{Threaded clients}.
+@item
+If you want to recompile the Perl DBD::mysql module, you must get
+Msql-Mysql-modules version 1.2218 or newer, because the older DBD modules
+used the deprecated @code{drop_db()} call.
+@item
+@code{RAND(seed)} returns a different random number series in 4.0 than in
+3.23; This was done to get @code{RAND(seed)} and @code{RAND(seed+1)} more
+different.
+@end itemize
+
+@node Upgrading-from-3.22, Upgrading-from-3.21, Upgrading-from-3.23, Upgrade
@subsection Upgrading From Version 3.22 to Version 3.23
@cindex compatibility, between MySQL versions
@@ -9349,7 +8264,7 @@ because configure didn't detect the @code{readlink} system call).
@item
@code{OPTIMIZE TABLE} now only works for @strong{MyISAM} tables.
-For other table types, you can use @code{ALTER TABLE} to optimize the table.
+For other table types, you can use @code{ALTER TABLE} to optimise the table.
During @code{OPTIMIZE TABLE} the table is now locked from other threads.
@item
@@ -9360,6 +8275,10 @@ some cases, for example in SQL scripts that use named commands without a
semicolon! Long format commands still work from the first line.
@item
+Date functions that work on part of dates (like @code{MONTH()}) will now
+return 0 for @code{0000-00-00} dates. (MySQL 3.22 returned @code{NULL}).
+
+@item
If you are using the @code{german} character sort order, you must repair
all your tables with @code{isamchk -r}, as we have made some changes in
the sort order!
@@ -9368,49 +8287,49 @@ the sort order!
The default return type of @code{IF} will now depend on both arguments
and not only the first argument.
-@item
+@item
@code{AUTO_INCREMENT} will not work with negative numbers. The reason
for this is that negative numbers caused problems when wrapping from -1 to 0.
@code{AUTO_INCREMENT} is now for MyISAM tables handled at a lower level and
is much faster than before. For MyISAM tables old numbers are also not reused
anymore, even if you delete some rows from the table.
-@item
-@code{CASE}, @code{DELAYED}, @code{ELSE}, @code{END}, @code{FULLTEXT},
+@item
+@code{CASE}, @code{DELAYED}, @code{ELSE}, @code{END}, @code{FULLTEXT},
@code{INNER}, @code{RIGHT}, @code{THEN} and @code{WHEN} are now reserved words.
-@item
-@code{FLOAT(X)} is now a true floating-point type and not a value with a
+@item
+@code{FLOAT(X)} is now a true floating-point type and not a value with a
fixed number of decimals.
-@item
-When declaring @code{DECIMAL(length,dec)} the length argument no longer
+@item
+When declaring @code{DECIMAL(length,dec)} the length argument no longer
includes a place for the sign or the decimal point.
-@item
+@item
A @code{TIME} string must now be of one of the following formats:
@code{[[[DAYS] [H]H:]MM:]SS[.fraction]} or
@code{[[[[[H]H]H]H]MM]SS[.fraction]}
-@item
-@code{LIKE} now compares strings using the same character comparison rules
-as @code{'='}. If you require the old behavior, you can compile
+@item
+@code{LIKE} now compares strings using the same character comparison rules
+as @code{'='}. If you require the old behavior, you can compile
MySQL with the @code{CXXFLAGS=-DLIKE_CMP_TOUPPER} flag.
-@item
+@item
@code{REGEXP} is now case insensitive for normal (not binary) strings.
-@item
+@item
When you check/repair tables you should use @code{CHECK TABLE}
or @code{myisamchk} for @code{MyISAM} tables (@code{.MYI}) and
@code{isamchk} for ISAM (@code{.ISM}) tables.
-@item
+@item
If you want your @code{mysqldump} files to be compatible between
MySQL Version 3.22 and Version 3.23, you should not use the
@code{--opt} or @code{--full} option to @code{mysqldump}.
-@item
+@item
Check all your calls to @code{DATE_FORMAT()} to make sure there is a
@samp{%} before each format character. (Later MySQL Version 3.22
did allow this syntax.)
@@ -9490,7 +8409,7 @@ return any server error, only @code{CR_UNKNOWN_ERROR} (but it
works for client errors), and the server uses the old @code{password()}
checking rather than the new one.
-If you are @strong{NOT} using the @code{--old-protocol} option to
+If you are @strong{not} using the @code{--old-protocol} option to
@code{mysqld}, you will need to make the following changes:
@itemize @bullet
@@ -9642,7 +8561,7 @@ After you import the @code{mysql} database on the new machine, execute
information.
-@node Operating System Specific Notes, , Upgrade, Installing
+@node Operating System Specific Notes, Perl support, Upgrade, Installing
@section Operating System Specific Notes
@menu
@@ -9683,17 +8602,17 @@ worry about your own build only after you have discovered that our binary is
not good enough. In that case, we would appreciate a note about it, so we
can build a better binary next time. For a typical user, even for setups with
a lot of concurrent connections and/or tables exceeding 2GB limit, our
-binary in most cases is the best choice.
+binary in most cases is the best choice.
MySQL uses LinuxThreads on Linux. If you are using an old
Linux version that doesn't have @code{glibc2}, you must install
-LinuxThreads before trying to compile MySQL. You can get
-LinuxThreads at @uref{http://www.mysql.com/Downloads/Linux}.
+LinuxThreads before trying to compile MySQL. You can get
+LinuxThreads at @uref{http://www.mysql.com/Downloads/Linux/}.
-@strong{NOTE:} We have seen some strange problems with Linux 2.2.14 and
+@strong{Note:} We have seen some strange problems with Linux 2.2.14 and
MySQL on SMP systems; If you have a SMP system, we recommend
-you to upgrade to Linux 2.4 ASAP! Your system will be faster and more
-stable by doing this!
+you to upgrade to Linux 2.4 as soon as possible! Your system will be
+faster and more stable by doing this!
Note that @code{glibc} versions before and including Version 2.1.1 have
a fatal bug in @code{pthread_mutex_timedwait} handling, which is used
@@ -9705,8 +8624,8 @@ some changes to LinuxThreads, recompile it, and relink MySQL against
the new @file{libpthread.a}. Increase @code{PTHREAD_THREADS_MAX} in
@file{sysdeps/unix/sysv/linux/bits/local_lim.h} to 4096 and decrease
@code{STACK_SIZE} in @file{linuxthreads/internals.h} to 256 KB. The paths are
-relative to the root of @code{glibc} Note that MySQL will not be
-stable with around 600-1000 connections if @code{STACK_SIZE} is the default
+relative to the root of @code{glibc} Note that MySQL will not be
+stable with around 600-1000 connections if @code{STACK_SIZE} is the default
of 2 MB.
If you have a problem with that MySQL can't open enough files,
@@ -9718,7 +8637,7 @@ file handlers by doing:
@example
cat /proc/sys/fs/file-max
-cat /proc/sys/fs/dquot-max
+cat /proc/sys/fs/dquot-max
cat /proc/sys/fs/super-max
@end example
@@ -9751,26 +8670,26 @@ data. Unfortunately, the Linux implementation of @code{mmap()}, as we have
experimentally discovered, will successfully unmap an already mapped region
if you ask it to map out an address already in use, zeroing out the data
on the entire page, instead of returning an error. So, the safety of
-@code{mysqld} or any other threaded application depends on the "gentleman"
-behavior of the code that creates threads. The user must take measures to
-make sure the number of running threads at any time is sufficiently low for
-thread stacks to stay away from the global heap. With @code{mysqld}, you
-should enforce this "gentleman" behavior by setting a reasonable value for
+@code{mysqld} or any other threaded application depends on the "gentleman"
+behavior of the code that creates threads. The user must take measures to
+make sure the number of running threads at any time is sufficiently low for
+thread stacks to stay away from the global heap. With @code{mysqld}, you
+should enforce this "gentleman" behavior by setting a reasonable value for
the @code{max_connections} variable.
If you build MySQL yourself and do not want to mess with patching
-LinuxThreads, you should set @code{max_connections} to a value no higher
-than 500. It should be even less if you have a large key buffer, large
-heap tables, or some other things that make @code{mysqld} allocate a lot
-of memory or if you are running a 2.2 kernel with a 2GB patch. If you are
+LinuxThreads, you should set @code{max_connections} to a value no higher
+than 500. It should be even less if you have a large key buffer, large
+heap tables, or some other things that make @code{mysqld} allocate a lot
+of memory or if you are running a 2.2 kernel with a 2GB patch. If you are
using our binary or RPM version 3.23.25 or later, you can safely set
-@code{max_connections} at 1500, assuming no large key buffer or heap tables
-with lots of data. The more you reduce @code{STACK_SIZE} in LinuxThreads
-the more threads you can safely create. We recommend the values between
+@code{max_connections} at 1500, assuming no large key buffer or heap tables
+with lots of data. The more you reduce @code{STACK_SIZE} in LinuxThreads
+the more threads you can safely create. We recommend the values between
128K and 256K.
-If you use a lot of concurrent connections, you may suffer from a "feature"
-in the 2.2 kernel that penalizes a process for forking or cloning a child
+If you use a lot of concurrent connections, you may suffer from a "feature"
+in the 2.2 kernel that penalises a process for forking or cloning a child
in an attempt to prevent a fork bomb attack. This will cause MySQL
not to scale well as you increase the number of concurrent clients. On
single CPU systems, we have seen this manifested in a very slow thread
@@ -9820,9 +8739,9 @@ threads that only
hold the mutex for a short time. On an SMP system, ironic as it is, if
you link MySQL against unmodified @strong{LinuxThreads},
removing processors from the machine improves MySQL performance
-in many cases. We have made a patch available for @strong{glibc 2.1.3},
-@uref{http://www.mysql.com/Downloads/Linux/linuxthreads-2.1-patch,linuxthreads-2.1-patch}
-to correct this behavior.
+in many cases. We have made a patch available for @strong{glibc 2.1.3}
+to correct this behavior
+(@uref{http://www.mysql.com/Downloads/Linux/linuxthreads-2.1-patch}).
With @strong{glibc-2.2.2}
MySQL version 3.23.36 will use the adaptive mutex, which is much
@@ -9831,7 +8750,9 @@ that under some conditions, the current mutex code in @strong{glibc-2.2.2}
overspins, which hurts MySQL performance. The chance of this
condition can be reduced by renicing @code{mysqld} process to the highest
priority. We have also been able to correct the overspin behavior with
-a patch, available @uref{http://www.mysql.com/Downloads/Linux/linuxthreads-2.2.2.patch,here}. It combines the correction of overspin, maximum number of
+a patch, available at
+@uref{http://www.mysql.com/Downloads/Linux/linuxthreads-2.2.2.patch}.
+It combines the correction of overspin, maximum number of
threads, and stack spacing all in one. You will need to apply it in the
@code{linuxthreads} directory with
@code{patch -p0 </tmp/linuxthreads-2.2.2.patch}.
@@ -9877,16 +8798,18 @@ If you see a dead @code{mysqld} daemon process with @code{ps}, this usually
means that you have found a bug in MySQL or you have a corrupted
table. @xref{Crashing}.
-To get a core dump on Linux if @code{mysqld} dies with a SIGSEGV
-signal, you can start @code{mysqld} with the @code{--core-file} option. Note
+To get a core dump on Linux if @code{mysqld} dies with a SIGSEGV signal,
+you can start @code{mysqld} with the @code{--core-file} option. Note
that you also probably need to raise the @code{core file size} by adding
-@code{ulimit -c 1000000} to @code{safe_mysqld} or starting @code{safe_mysqld}
-with @code{--core-file-sizes=1000000}. @xref{safe_mysqld, , @code{safe_mysqld}}.
+@code{ulimit -c 1000000} to @code{safe_mysqld} or starting
+@code{safe_mysqld} with @code{--core-file-sizes=1000000}.
+@xref{safe_mysqld, , @code{safe_mysqld}}.
If you are linking your own MySQL client and get the error:
@example
-ld.so.1: ./my: fatal: libmysqlclient.so.4: open failed: No such file or directory
+ld.so.1: ./my: fatal: libmysqlclient.so.4:
+open failed: No such file or directory
@end example
When executing them, the problem can be avoided by one of the following
@@ -9914,7 +8837,13 @@ some problems compiling MySQL because the Linux header files are very
The following @code{configure} line should work with @code{fcc/FCC}:
@example
-CC=fcc CFLAGS="-O -K fast -K lib -K omitfp -Kpreex -D_GNU_SOURCE -DCONST=const -DNO_STRTOLL_PROTO" CXX=FCC CXXFLAGS="-O -K fast -K lib -K omitfp -K preex --no_exceptions --no_rtti -D_GNU_SOURCE -DCONST=const -Dalloca=__builtin_alloca -DNO_STRTOLL_PROTO '-D_EXTERN_INLINE=static __inline'" ./configure --prefix=/usr/local/mysql --enable-assembler --with-mysqld-ldflags=-all-static --disable-shared --with-low-memory
+CC=fcc CFLAGS="-O -K fast -K lib -K omitfp -Kpreex -D_GNU_SOURCE \
+-DCONST=const -DNO_STRTOLL_PROTO" CXX=FCC CXXFLAGS="-O -K fast -K lib \
+-K omitfp -K preex --no_exceptions --no_rtti -D_GNU_SOURCE -DCONST=const \
+-Dalloca=__builtin_alloca -DNO_STRTOLL_PROTO \
+'-D_EXTERN_INLINE=static __inline'" ./configure --prefix=/usr/local/mysql \
+--enable-assembler --with-mysqld-ldflags=-all-static --disable-shared \
+--with-low-memory
@end example
@@ -9926,6 +8855,13 @@ CC=fcc CFLAGS="-O -K fast -K lib -K omitfp -Kpreex -D_GNU_SOURCE -DCONST=const -
MySQL needs at least Linux Version 2.0.
+@strong{WARNING}:
+We have have reports from some MySQL users that they have got serious
+stability problems with MySQL with Linux kernel 2.2.14. If you are
+using this kernel you should upgrade to 2.2.19 (or newer) or to a 2.4
+kernel. If you have a multi-cpu box, then you should seriously consider
+using 2.4 as this will give you a significant speed boost.
+
The binary release is linked with @code{-static}, which means you do not
normally need to worry about which version of the system libraries you
have. You need not install LinuxThreads, either. A program linked with
@@ -10007,6 +8943,11 @@ also work. There have been some problems with the @code{glibc} RPMs from
RedHat, so if you have problems, check whether or not there are any updates!
The @code{glibc} 2.0.7-19 and 2.0.7-29 RPMs are known to work.
+If you are using gcc 3.0 and above to compile MySQL, you must install
+the @code{libstdc++v3} library before compiling MySQL; If you don't do
+this you will get an error about a missing @code{__cxa_pure_virtual}
+symbol during linking!
+
On some older Linux distributions, @code{configure} may produce an error
like this:
@@ -10023,9 +8964,11 @@ You may get some warnings when compiling; those shown below can be ignored:
@example
mysqld.cc -o objs-thread/mysqld.o
mysqld.cc: In function `void init_signals()':
-mysqld.cc:315: warning: assignment of negative value `-1' to `long unsigned int'
+mysqld.cc:315: warning: assignment of negative value `-1' to
+`long unsigned int'
mysqld.cc: In function `void * signal_hand(void *)':
-mysqld.cc:346: warning: assignment of negative value `-1' to `long unsigned int'
+mysqld.cc:346: warning: assignment of negative value `-1' to
+`long unsigned int'
@end example
In Debian GNU/Linux, if you want MySQL to start automatically when
@@ -10059,13 +9002,15 @@ You can avoid using @file{libg++.a} by running @code{configure} like this:
shell> CXX=gcc ./configure
@end example
+If you are running gcc 3.0 and above, you can't use the above trick with
+setting to CXX=gcc.
@node Linux-SPARC, Linux-Alpha, Linux-x86, Linux
@subsubsection Linux SPARC Notes
In some implementations, @code{readdir_r()} is broken. The symptom is that
-@code{SHOW DATABASES} always returns an empty set. This can be fixed by
-removing @code{HAVE_READDIR_R} from @file{config.h} after configuring and
+@code{SHOW DATABASES} always returns an empty set. This can be fixed by
+removing @code{HAVE_READDIR_R} from @file{config.h} after configuring and
before compiling.
Some problems will require patching your Linux installation. The patch can
@@ -10073,7 +9018,7 @@ be found at
@uref{http://www.mysql.com/Downloads/patches/Linux-sparc-2.0.30.diff}.
This patch is against the Linux distribution @file{sparclinux-2.0.30.tar.gz}
that is available at @code{vger.rutgers.edu} (a version of Linux that was
-never merged with the official 2.0.30). You must also install LinuxThreads
+never merged with the official 2.0.30). You must also install LinuxThreads
Version 0.6 or newer.
@@ -10081,7 +9026,7 @@ Version 0.6 or newer.
@subsubsection Linux Alpha Notes
MySQL Version 3.23.12 is the first MySQL version that is
-tested on Linux-Alpha. If you plan to use MySQL on Linux-Alpha,
+tested on Linux-Alpha. If you plan to use MySQL on Linux-Alpha,
you should ensure that you have this version or newer.
We have tested MySQL on Alpha with our benchmarks and test suite,
@@ -10092,22 +9037,28 @@ When we compiled the standard MySQL binary we are using SuSE 6.4,
kernel 2.2.13-SMP, Compaq C compiler (V6.2-504) and Compaq C++ compiler
(V6.3-005) on a Comaq DS20 machine with an Alpha EV6 processor.
-You can find the above compilers at
-@uref{http://www.support.compaq.com/alpha-tools}). By using these compilers,
+You can find the above compilers at
+@uref{http://www.support.compaq.com/alpha-tools/}). By using these compilers,
instead of gcc, we get about 9-14 % better performance with MySQL.
-Note that the configure line optimized the binary for the current CPU; This
+Note that the configure line optimised the binary for the current CPU; This
means you can only use our binary if you have an Alpha EV6 processor. We also
compile statically to avoid library problems.
@example
-CC=ccc CFLAGS="-fast" CXX=cxx CXXFLAGS="-fast -noexceptions -nortti" ./configure --prefix=/usr/local/mysql --disable-shared --with-extra-charsets=complex --enable-thread-safe-client --with-mysqld-ldflags=-non_shared --with-client-ldflags=-non_shared
+CC=ccc CFLAGS="-fast" CXX=cxx CXXFLAGS="-fast -noexceptions -nortti" \
+./configure --prefix=/usr/local/mysql --disable-shared \
+--with-extra-charsets=complex --enable-thread-safe-client \
+--with-mysqld-ldflags=-non_shared --with-client-ldflags=-non_shared
@end example
If you want to use egcs the following configure line worked for us:
@example
-CFLAGS="-O3 -fomit-frame-pointer" CXX=gcc CXXFLAGS="-O3 -fomit-frame-pointer -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --disable-shared
+CFLAGS="-O3 -fomit-frame-pointer" CXX=gcc \
+CXXFLAGS="-O3 -fomit-frame-pointer -felide-constructors \
+-fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql \
+--disable-shared
@end example
Some known problems when running MySQL on Linux-Alpha:
@@ -10115,11 +9066,11 @@ Some known problems when running MySQL on Linux-Alpha:
@itemize @bullet
@item
Debugging threaded applications like MySQL will not work with
-@code{gdb 4.18}. You should download and use gdb 5.0 instead!
+@code{gdb 4.18}. You should download and use gdb 5.1 instead!
@item
If you try linking @code{mysqld} statically when using @code{gcc}, the
-resulting image will core dump at start. In other words, @strong{DON'T}
+resulting image will core dump at start. In other words, @strong{don't}
use @code{--with-mysqld-ldflags=-all-static} with @code{gcc}.
@end itemize
@@ -10147,7 +9098,10 @@ To get MySQL to compile on Linux Ia64, we use the following compile line:
Using @code{gcc-2.96}:
@example
-CC=gcc CFLAGS="-O3 -fno-omit-frame-pointer" CXX=gcc CXXFLAGS="-O3 -fno-omit-frame-pointer -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql "--with-comment=Official MySQL binary" --with-extra-charsets=complex
+CC=gcc CFLAGS="-O3 -fno-omit-frame-pointer" CXX=gcc \
+CXXFLAGS="-O3 -fno-omit-frame-pointer -felide-constructors \
+-fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql \
+"--with-comment=Official MySQL binary" --with-extra-charsets=complex
@end example
On Ia64 the MySQL client binaries are using shared libraries. This means
@@ -10161,9 +9115,9 @@ to the @code{LD_LIBRARY_PATH} environment variable.
@node Windows, Solaris, Linux, Operating System Specific Notes
@subsection Windows Notes
-This section describes installation and use of MySQL on Windows.
-This information is also provided in the @file{README} file that comes
-with the MySQL Windows distribution.
+This section describes using MySQL on Windows. This information
+is also provided in the @file{README} file that comes with the
+MySQL Windows distribution. @xref{Windows installation}.
@menu
* Win95 start:: Starting MySQL on Win95 / Win98
@@ -10171,7 +9125,7 @@ with the MySQL Windows distribution.
* Windows running:: Running MySQL on Windows
* Windows and SSH:: Connecting to a remote MySQL from Windows with SSH
* Windows symbolic links:: Splitting data across different disks under Win32
-* Windows compiling:: Compiling MySQL clients on Windows.
+* Windows client compiling:: Compiling MySQL clients on Windows.
* Windows vs Unix:: MySQL-Windows compared to Unix MySQL
@end menu
@@ -10181,16 +9135,18 @@ with the MySQL Windows distribution.
MySQL uses TCP/IP to connect a client to a server. (This will
allow any machine on your network to connect to your MySQL
-server.) Because of this, you must install TCP/IP on your machine before
-starting MySQL. You can find TCP/IP on your Windows CD-ROM.
+server.) Because of this, you must install TCP/IP on your
+machine before starting MySQL. You can find TCP/IP on your
+Windows CD-ROM.
-Note that if you are using an old Win95 release (for example OSR2), it's
-likely that you have an old Winsock package! MySQL requires
-Winsock 2! You can get the newest Winsock from
-@uref{http://www.microsoft.com/}. Win98 has the new Winsock 2 library, so
-the above doesn't apply for Win98.
+Note that if you are using an old Win95 release (for example
+OSR2), it's likely that you have an old Winsock package;
+MySQL requires Winsock 2! You can get the newest Winsock from
+@uref{http://www.microsoft.com/}. Win98 has the new Winsock 2
+library, so the above doesn't apply for Win98.
-To start the @code{mysqld} server, you should start an MS-DOS window and type:
+To start the @code{mysqld} server, you should start an MS-DOS
+window and type:
@example
C:\> C:\mysql\bin\mysqld
@@ -10204,104 +9160,130 @@ You can kill the MySQL server by executing:
C:\> C:\mysql\bin\mysqladmin -u root shutdown
@end example
+This calls the MySQL administation utility as user `root', which
+is the default Administrator in the MySQL grant system. Please
+note that the MySQL grant system is wholly independent from any
+login users under Windows.
+
Note that Win95 and Win98 don't support creation of named pipes.
On Win95 and Win98, you can only use named pipes to connect to a
-remote MySQL server running on a Windows NT server host.
-(The MySQL server must also support named pipes, of
-course. For example, using @code{mysqld-opt} under NT will not allow
-named pipe connections. You should use either @code{mysqld-nt} or
-@code{mysqld-max-nt}.)
+remote MySQL server running on a Windows NT/2000 server host.
+(The MySQL server must also support named pipes, of course.
+For example, using @code{mysqld-opt} under NT/2000 will not
+allow named pipe connections. You should use either
+@code{mysqld-nt} or @code{mysqld-max-nt}.)
If @code{mysqld} doesn't start, please check the
-@file{\mysql\data\mysql.err} file to see if the server wrote any message
-there to indicate the cause of the problem. You can also try to start
-the server with @code{mysqld --standalone}; In this case, you may get
-some useful information on the screen that may help solve the problem.
+@file{\mysql\data\mysql.err} file to see if the server wrote any
+message there to indicate the cause of the problem. You can also
+try to start the server with @code{mysqld --standalone}; In this
+case, you may get some useful information on the screen that may
+help solve the problem.
-The last option is to start @code{mysqld} with @code{--standalone
---debug}. In this case @code{mysqld} will write a log file
-@file{C:\mysqld.trace} that should contain the reason why @code{mysqld}
-doesn't start. @xref{Making trace files}.
+The last option is to start @code{mysqld} with
+@code{--standalone --debug}.
+In this case @code{mysqld} will write a log file
+@file{C:\mysqld.trace} that should contain the reason why
+@code{mysqld} doesn't start. @xref{Making trace files}.
+
+Use @code{mysqld --help} to display all the options that
+@code{mysqld} understands!
@node NT start, Windows running, Win95 start, Windows
@subsubsection Starting MySQL on Windows NT or Windows 2000
-The Win95/Win98 section also applies to MySQL on NT/Win2000, with
-the following differences:
-
-To get MySQL to work with TCP/IP on NT, you must install
+To get MySQL to work with TCP/IP on Windows NT 4, you must install
service pack 3 (or newer)!
-Note that everything in the following that applies for NT also applies
-for Win2000!
-
-For NT/Win2000, the server name is @code{mysqld-nt}. Normally you
-should install MySQL as a service on NT/Win2000:
+Normally you should install MySQL as a service on NT/Win2000.
+In case the server was already running, first stop it using
+the following command:
@example
-C:\> C:\mysql\bin\mysqld-nt --install
+C:\mysql\bin> mysqladmin -u root shutdown
@end example
-or
+This calls the MySQL administation utility as user `@code{root}',
+which is the default @code{Administrator} in the MySQL grant system.
+Please note that the MySQL grant system is wholly independent from
+any login users under Windows.
+
+Now install the server service:
@example
-C:\> C:\mysql\bin\mysqld-max-nt --install
+C:\mysql\bin> mysqld-max-nt --install
@end example
-(Under Windows NT, you can actually install any of the server binaries
-as a service, but only those having names that end with @code{-nt.exe}
-provide support for named pipes.)
+If any options are required, they must be specified as
+``@code{Start parameters}'' in the Windows @code{Services}
+utility before you start the MySQL service.
-You can start and stop the MySQL service with these commands:
+The @code{Services} utility
+(@code{Windows Service Control Manager}) can be found in the
+@code{Windows Control Panel} (under @code{Administrative Tools}
+on Windows 2000). It is advisable to close the Services utility
+while performing the @code{--install} or @code{--remove}
+operations, this prevents some odd errors.
+
+For information about which server binary to run, see
+@ref{Windows prepare environment}.
+
+Please note that from MySQL version 3.23.44, you have the choice
+of set up the service as @code{Manual} instead (if you don't wish
+the service to be started automatically during the boot process):
@example
-C:\> NET START mysql
-C:\> NET STOP mysql
+C:\mysql\bin> mysqld-max-nt --install-manual
@end example
-Note that in this case you can't use any other options for @code{mysqld-nt}!
+The service is installed with the name @code{MySQL}. Once
+installed, it can be immediately started from the @code{Services}
+utility, or by using the command @code{NET START MySQL}.
-You can also run @code{mysqld-nt} as a stand-alone program on NT if you need
-to start @code{mysqld-nt} with any options! If you start @code{mysqld-nt}
-without options on NT, @code{mysqld-nt} tries to start itself as a service
-with the default service options. If you have stopped @code{mysqld-nt}, you
-have to start it with @code{NET START mysql}.
+Once running, @code{mysqld-max-nt} can be stopped using
+@code{mysqladmin}, from the Services utility or by using the
+command @code{NET STOP MySQL}.
-The service is installed with the name @code{MySQL}. Once installed, it must
-be started using the Services Control Manager (SCM) Utility found in the
-Control Panel, or by using the @code{NET START MySQL} command. If any options
-are desired, they must be specified as ``Startup parameters'' in the SCM utility
-before you start the MySQL service. Once running, @code{mysqld-nt}
-can be stopped using @code{mysqladmin}, or from the SCM utility or by using
-the command @code{NET STOP MySQL}. If you use SCM to stop @code{mysqld-nt},
-there is a strange message from SCM about @code{mysqld shutdown normally}.
-When run as a service, @code{mysqld-nt} has no access to a console and so no
-messages can be seen.
+When running as a service, the operating system will automatically stop
+the MySQL service on computer shutdown. In MySQL versions < 3.23.47,
+Windows only waited for a few seconds for the shutdown to complete, and
+killed the database server process if the time limit was exceeded
+(potentially causing problems). For instance, at the next startup the
+@code{InnoDB} table handler had to do crash recovery. Starting from
+MySQL version 3.23.48, the Windows will wait longer for the MySQL server
+shutdown to complete. If you notice this is not enough for your
+intallation, it is safest to run the MySQL server not as a service, but
+from the Command prompt, and shut it down with @code{mysqladmin shutdown}.
-On NT you can get the following service error messages:
+There is a problem that Windows NT (but not Windows 2000) by default only
+waits 20 seconds for a service to shut down, and after that kills the
+service process. You can increase this default by opening the Registry
+Editor @file{\winnt\system32\regedt32.exe} and editing the value of
+@code{WaitToKillServiceTimeout} at
+@file{HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control}
+in the Registry tree. Specify the new larger value in milliseconds,
+for example 120000 to have Windows NT wait upto 120 seconds.
-@multitable @columnfractions .3 .7
-@item Permission Denied @tab Means that it cannot find @code{mysqld-nt.exe}.
-@item Cannot Register @tab Means that the path is incorrect.
-@item Failed to install service. @tab Means that the service is already installed or that the Service Control Manager is in bad state.
-@end multitable
+Please note that when run as a service, @code{mysqld-max-nt}
+has no access to a console and so no messages can be seen.
+Errors can be checked in @file{c:\mysql\data\mysql.err}.
-If you have problems installing @code{mysqld-nt} as a service, try starting
-it with the full path:
+If you have problems installing @code{mysqld-max-nt} as a
+service, try starting it with the full path:
@example
-C:\> C:\mysql\bin\mysqld-nt --install
+C:\> C:\mysql\bin\mysqld-max-nt --install
@end example
-If this doesn't work, you can get @code{mysqld-nt} to start properly by fixing
-the path in the registry!
+If this doesn't work, you can get @code{mysqld-max-nt} to
+start properly by fixing the path in the registry!
-If you don't want to start @code{mysqld-nt} as a service, you can start it as
-follows:
+If you don't want to start @code{mysqld-max-nt} as a service,
+you can start it as follows:
@example
-C:\> C:\mysql\bin\mysqld-nt --standalone
+C:\> C:\mysql\bin\mysqld-max-nt --standalone
@end example
or
@@ -10310,8 +9292,8 @@ or
C:\> C:\mysql\bin\mysqld --standalone --debug
@end example
-The last version gives you a debug trace in @file{C:\mysqld.trace}.
-@xref{Making trace files}.
+The last method gives you a debug trace in
+@file{C:\mysqld.trace}. @xref{Making trace files}.
@node Windows running, Windows and SSH, NT start, Windows
@@ -10320,21 +9302,25 @@ The last version gives you a debug trace in @file{C:\mysqld.trace}.
@cindex TCP/IP
@cindex named pipes
-MySQL supports TCP/IP on all Windows platforms and named pipes on NT.
-The default is to use named pipes for local connections on NT and TCP/IP for
-all other cases if the client has TCP/IP installed. The host name specifies
-which protocol is used:
+MySQL supports TCP/IP on all Windows platforms and named pipes on
+NT/2000. The default is to use named pipes for local connections
+on NT/2000 and TCP/IP for all other cases if the client has TCP/IP
+installed. The host name specifies which protocol is used:
@multitable @columnfractions .3 .7
-@strong{Host name} @tab @strong{Protocol}
-@item NULL (none) @tab On NT, try named pipes first; if that doesn't work, use TCP/IP. On Win95/Win98, TCP/IP is used.
+@item @strong{Host name} @tab @strong{Protocol}
+@item NULL (none) @tab
+On NT/2000, try named pipes first; if that doesn't work, use TCP/IP.
+On Win95/Win98, TCP/IP is used.
@item . @tab Named pipes
-@item localhost @tab TCP/IP to current host
-@item hostname @tab TCP/IP
+@item localhost @tab
+TCP/IP to current host
+@item hostname @tab
+TCP/IP
@end multitable
You can force a MySQL client to use named pipes by specifying the
-@code{--pipe} option or by specifying @code{.} as the host name. Use the
+@code{--pipe} option or by specifying @code{.} as the host name. Use the
@code{--socket} option to specify the name of the pipe.
Note that starting from 3.23.50, named pipes are only enabled if start
@@ -10362,6 +9348,7 @@ MySQL clients.
There are two versions of the MySQL command-line tool:
@multitable @columnfractions .25 .75
+@item @strong{Binary} @tab @strong{Description}
@item @code{mysql} @tab Compiled on native Windows, which offers very limited text editing capabilities.
@item @code{mysqlc} @tab Compiled with the Cygnus GNU compiler and libraries, which offers @code{readline} editing.
@end multitable
@@ -10376,7 +9363,7 @@ more secure, you should set a password for all users and remove the row in
the @code{mysql.user} table that has @code{Host='localhost'} and
@code{User=''}.
-You should also add a password for the @code{root} user. The following
+You should also add a password for the @code{root} user. The following
example starts by removing the anonymous user that can be used by anyone
to access the @code{test} database, then sets a @code{root} user password:
@@ -10413,7 +9400,7 @@ and change privileges with @code{GRANT} and @code{REVOKE} commands.
@cindex SSH
@cindex connecting, remotely with SSH
-Here is a note about how to connect to get a secure connection to remote
+Here is a note about how to connect to get a secure connection to remote
MySQL server with SSH (by David Carlson @email{dcarlson@@mplcomm.com}):
@itemize @bullet
@@ -10425,8 +9412,8 @@ can also find some free ones on @strong{Google} at
@uref{http://directory.google.com/Top/Computers/Security/Products_and_Tools/Cryptography/SSH/Clients/Windows/}.
@item
-Start your Windows SSH client.
-Set @code{Host_Name = yourmysqlserver_URL_or_IP}.
+Start your Windows SSH client.
+Set @code{Host_Name = yourmysqlserver_URL_or_IP}.
Set @code{userid=your_userid} to log in to your server (probably not the same
as your MySQL login/password.
@@ -10445,14 +9432,14 @@ On your Windows machine, start some ODBC application (such as Access).
@item
Create a new file in Windows and link to MySQL using the ODBC
-driver the same way you normally do, EXCEPT type in @code{localhost}
+driver the same way you normally do, except type in @code{localhost}
for the MySQL host server --- not @code{yourmysqlservername}.
@end itemize
-You should now have an ODBC connection to MySQL, encrypted using SSH.
+You should now have an ODBC connection to MySQL, encrypted using SSH.
-@node Windows symbolic links, Windows compiling, Windows and SSH, Windows
+@node Windows symbolic links, Windows client compiling, Windows and SSH, Windows
@subsubsection Splitting Data Across Different Disks on Windows
@cindex symbolic links
@@ -10492,7 +9479,7 @@ should instead use the @code{skip-symlink} option if you want to
disable this.
-@node Windows compiling, Windows vs Unix, Windows symbolic links, Windows
+@node Windows client compiling, Windows vs Unix, Windows symbolic links, Windows
@subsubsection Compiling MySQL Clients on Windows
@cindex compiling, on Windows
@@ -10516,7 +9503,7 @@ Note that as the mysqlclient libraries are compiled as threaded libraries,
you should also compile your code to be multi-threaded!
-@node Windows vs Unix, , Windows compiling, Windows
+@node Windows vs Unix, , Windows client compiling, Windows
@subsubsection MySQL-Windows Compared to Unix MySQL
@cindex Windows, versus Unix
@@ -10567,10 +9554,6 @@ connections.
We plan to fix this problem when our Windows developers have figured out a
nice workaround.
-@item UDF functions
-For the moment, MySQL-Windows does not support user-definable
-functions.
-
@item @code{DROP DATABASE}
You can't drop a database that is in use by some thread.
@@ -10611,8 +9594,8 @@ error 2017: can't open named pipe to host: . pipe...
@end example
@tindex .my.cnf file
-This is because the release version of MySQL uses named pipes on NT
-by default. You can avoid this error by using the @code{--host=localhost}
+This is because the release version of MySQL uses named pipes on NT
+by default. You can avoid this error by using the @code{--host=localhost}
option to the new MySQL clients or create an option file
@file{C:\my.cnf} that contains the following information:
@@ -10643,12 +9626,18 @@ from usage by other threads. This has to do with the fact that on Windows,
you can't delete a file that is in use by another threads. (In the future,
we may find some way to work around this problem.)
-@item @code{DROP TABLE} on a table that is in use by a @code{MERGE} table will not work
-The @code{MERGE} handler does its table mapping hidden from MySQL.
-Because Windows doesn't allow you to drop files that are open, you first
-must flush all @code{MERGE} tables (with @code{FLUSH TABLES}) or drop the
-@code{MERGE} table before dropping the table. We will fix this at the same
-time we introduce @code{VIEW}s.
+@item
+@code{DROP TABLE} on a table that is in use by a @code{MERGE} table will
+not work on Windows because @code{MERGE} handler does the table mapping
+hidden from the upper layer of MySQL. Because Windows doesn't allow you
+to drop files that are open, you first must flush all @code{MERGE}
+tables (with @code{FLUSH TABLES}) or drop the @code{MERGE} table before
+dropping the table. We will fix this at the same time we introduce
+@code{VIEW}s.
+@item
+@code{DATA DIRECTORY} and @code{INDEX DIRECTORY} directives in
+@code{CREATE TABLE} is ignored on Windows, because Windows doesn't support
+symbolic links.
@end table
Here are some open issues for anyone who might want to help us with the Windows
@@ -10667,13 +9656,6 @@ client/server and don't need to access the server from other hosts.
Add some nice start and shutdown icons to the MySQL installation.
@item
-Create a tool to manage registry entries for the MySQL startup
-options. The registry entry reading is already coded into @file{mysqld.cc},
-but it should be recoded to be more parameter oriented. The tool should
-also be able to update the @file{C:\my.cnf} option file if the user prefers
-to use that instead of the registry.
-
-@item
When registering @code{mysqld} as a service with @code{--install} (on NT)
it would be nice if you could also add default options on the command line.
For the moment, the workaround is to list the parameters in the
@@ -10692,7 +9674,7 @@ GUI versions of the standard MySQL clients (@code{mysql},
@item
It would be nice if the socket read and write functions in @file{net.c} were
-interruptible. This would make it possible to kill open threads with
+interruptible. This would make it possible to kill open threads with
@code{mysqladmin kill} on Windows.
@item
@@ -10700,12 +9682,8 @@ interruptible. This would make it possible to kill open threads with
We would like to have @code{mysqld} use the current locale for the sort order.
@item
-Implement UDF functions with @code{.DLL}s.
-
-@item
Add macros to use the faster thread-safe increment/decrement methods
provided by Windows.
-
@end itemize
Other Windows-specific issues are described in the @file{README} file that
@@ -10726,7 +9704,8 @@ distribution unpacked! Solaris @code{tar} can't handle long file names, so
you may see an error like this when you unpack MySQL:
@example
-x mysql-3.22.12-beta/bench/Results/ATIS-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase, 0 bytes, 0 tape blocks
+x mysql-3.22.12-beta/bench/Results/ATIS-mysql_odbc-NT_4.0-cmp-db2,\
+informix,ms-sql,mysql,oracle,solid,sybase, 0 bytes, 0 tape blocks
tar: directory checksum error
@end example
@@ -10814,6 +9793,14 @@ libc internal error: _rmutex_unlock: rmutex not held
Add @code{-mt} to @code{CFLAGS} and @code{CXXFLAGS} and try again.
+If you are using the SFW version of gcc (which comes with Solaris 8),
+you must add @file{/opt/sfw/lib} to the environment variable
+@code{LD_LIBRARY_PATH} before running configure.
+
+If you are using the gcc available from @code{sunfreeware.com}, you may
+have many problems. You should recompile gcc and GNU binutils on the
+machine you will be running them from to avoid any problems.
+
If you get the following error when compiling MySQL with @code{gcc},
it means that your @code{gcc} is not configured for your version of Solaris:
@@ -10859,7 +9846,8 @@ If you are linking your own MySQL client, you might get the
following error when you try to execute it:
@example
-ld.so.1: ./my: fatal: libmysqlclient.so.#: open failed: No such file or directory
+ld.so.1: ./my: fatal: libmysqlclient.so.#:
+open failed: No such file or directory
@end example
The problem can be avoided by one of the following methods:
@@ -10879,13 +9867,6 @@ Add the pathname of the directory where @file{libmysqlclient.so} is located
to the @code{LD_RUN_PATH} environment variable before running your client.
@end itemize
-When using the @code{--with-libwrap} configure option, you must also
-include the libraries that @file{libwrap.a} needs:
-
-@example
---with-libwrap="/opt/NUtcpwrapper-7.6/lib/libwrap.a -lnsl -lsocket
-@end example
-
If you have problems with configure trying to link with @code{-lz} and
you don't have @code{zlib} installed, you have two options:
@@ -10906,6 +9887,9 @@ If you would like MySQL to start automatically, you can copy
@file{support-files/mysql.server} to @file{/etc/init.d} and create a
symbolic link to it named @file{/etc/rc3.d/S99mysql.server}.
+As Solaris doesn't support core files for @code{setuid()} applications,
+you can't get a core file from @code{mysqld} if you are using the
+@code{--user} option.
@menu
* Solaris 2.7:: Solaris 2.7/2.8 Notes
@@ -11006,7 +9990,8 @@ following @code{configure} command:
@example
CC=gcc CFLAGS="-O3 -fomit-frame-pointer -DHAVE_CURSES_H" \
CXX=gcc \
-CXXFLAGS="-O3 -fomit-frame-pointer -felide-constructors -fno-exceptions -fno-rtti -DHAVE_CURSES_H" \
+CXXFLAGS="-O3 -fomit-frame-pointer -felide-constructors -fno-exceptions \
+-fno-rtti -DHAVE_CURSES_H" \
./configure --prefix=/usr/local/mysql
@end example
@@ -11020,14 +10005,15 @@ it with a trace file or under @code{gdb}. @xref{Using gdb on mysqld}.
@node BSD Notes, Mac OS X, Solaris, Operating System Specific Notes
@subsection BSD Notes
+This section provides information for the various BSD flavours,
+as well as specific versions within those.
+
@menu
* FreeBSD:: FreeBSD Notes
* NetBSD:: NetBSD notes
-* OpenBSD:: OpenBSD Notes
-* OpenBSD 2.5:: OpenBSD 2.5 Notes
+* OpenBSD:: OpenBSD 2.5 Notes
* OpenBSD 2.8:: OpenBSD 2.8 Notes
-* BSDI:: BSD/OS Notes
-* BSDI2:: BSD/OS Version 2.x Notes
+* BSDI:: BSD/OS Version 2.x Notes
* BSDI3:: BSD/OS Version 3.x Notes
* BSDI4:: BSD/OS Version 4.x Notes
@end menu
@@ -11039,13 +10025,14 @@ it with a trace file or under @code{gdb}. @xref{Using gdb on mysqld}.
FreeBSD 3.x is recommended for running MySQL since the thread package
is much more integrated.
-The easiest and therefor the preferred way to install is to use the
-mysql-server and mysql-client ports available on @uref{http://www.freebsd.org}.
+The easiest and therefor the preferred way to install is to use the
+mysql-server and mysql-client ports available on
+@uref{http://www.freebsd.org/}.
Using these gives you:
@itemize @bullet
@item
-A working MySQL with all optimizations known to work on your version
+A working MySQL with all optimisations known to work on your version
of FreeBSD enabled.
@item
@@ -11078,6 +10065,21 @@ correct (otherwise you will have problems connecting to the database). The
127.0.0.1 localhost localhost.your.domain
@end example
+The recommended way to compile and install MySQL on FreeBSD with
+gcc (2.95.2 and up) is:
+
+@example
+CC=gcc CFLAGS="-O2 -fno-strength-reduce" \
+CXX=gcc CXXFLAGS="-O2 -fno-rtti -fno-exceptions -felide-constructors \
+-fno-strength-reduce" \
+./configure --prefix=/usr/local/mysql --enable-assembler
+gmake
+gmake install
+./scripts/mysql_install_db
+cd /usr/local/mysql
+./bin/mysqld_safe &
+@end example
+
If you notice that @code{configure} will use MIT-pthreads, you should read
the MIT-pthreads notes. @xref{MIT-pthreads}.
@@ -11098,30 +10100,26 @@ appropriate class for this user in the password file if you are not
using the default (use: chpass mysqld-user-name). @xref{safe_mysqld, ,
@code{safe_mysqld}}.
+If you have a lot of memory you should consider rebuilding
+the kernel to allow MySQL to take more than 512M of RAM.
+Take a look at @code{option MAXDSIZ} in the LINT config
+file for more info.
+
If you get problems with the current date in MySQL, setting the
@code{TZ} variable will probably help. @xref{Environment variables}.
To get a secure and stable system you should only use FreeBSD kernels
-that are marked @code{-STABLE}.
+that are marked @code{-RELEASE}.
@node NetBSD, OpenBSD, FreeBSD, BSD Notes
@subsubsection NetBSD notes
-To compile on NetBSD you need GNU @code{make}. Otherwise the compile will
+To compile on NetBSD you need GNU @code{make}. Otherwise the compile will
crash when @code{make} tries to run @code{lint} on C++ files.
-@node OpenBSD, OpenBSD 2.5, NetBSD, BSD Notes
-@subsubsection OpenBSD Notes
-
-@menu
-* OpenBSD 2.5:: OpenBSD 2.5 Notes
-* OpenBSD 2.8:: OpenBSD 2.8 Notes
-@end menu
-
-
-@node OpenBSD 2.5, OpenBSD 2.8, OpenBSD, BSD Notes
+@node OpenBSD, OpenBSD 2.8, NetBSD, BSD Notes
@subsubsection OpenBSD 2.5 Notes
On OpenBSD Version 2.5, you can compile MySQL with native threads
@@ -11132,7 +10130,7 @@ CFLAGS=-pthread CXXFLAGS=-pthread ./configure --with-mit-threads=no
@end example
-@node OpenBSD 2.8, BSDI, OpenBSD 2.5, BSD Notes
+@node OpenBSD 2.8, BSDI, OpenBSD, BSD Notes
@subsubsection OpenBSD 2.8 Notes
Our users have reported that OpenBSD 2.8 has a threading bug which causes
@@ -11141,18 +10139,16 @@ but as of January 25th, 2001, it's only available in the ``-current'' branch.
The symptoms of this threading bug are: slow response, high load, high CPU
usage, and crashes.
+If you get an error like @code{Error in accept:: Bad file descriptor} or
+error 9 when trying to open tables or directories, the problem is probably
+that you haven't allocated enough file descriptors for MySQL.
-@node BSDI, BSDI2, OpenBSD 2.8, BSD Notes
-@subsubsection BSD/OS Notes
-
-@menu
-* BSDI2:: BSD/OS 2.x notes
-* BSDI3:: BSD/OS 3.x notes
-* BSDI4:: BSD/OS 4.x notes
-@end menu
+In this case try starting @code{safe_mysqld} as root with the following
+options:
+@code{--user=mysql --open-files-limit=2048}
-@node BSDI2, BSDI3, BSDI, BSD Notes
+@node BSDI, BSDI3, OpenBSD 2.8, BSD Notes
@subsubsection BSD/OS Version 2.x Notes
If you get the following error when compiling MySQL, your
@@ -11177,7 +10173,7 @@ If you get problems with the current date in MySQL, setting the
@code{TZ} variable will probably help. @xref{Environment variables}.
-@node BSDI3, BSDI4, BSDI2, BSD Notes
+@node BSDI3, BSDI4, BSDI, BSD Notes
@subsubsection BSD/OS Version 3.x Notes
Upgrade to BSD/OS Version 3.1. If that is not possible, install
@@ -11241,7 +10237,7 @@ before running make.
Note that the above means that you can't symbolic link a database directories
to another database directory or symbolic link a table to another database
-on BSDI! (Making a symbolic link to another disk is ok).
+on BSDI! (Making a symbolic link to another disk is okay).
@node Mac OS X, Other Unix Notes, BSD Notes, Operating System Specific Notes
@@ -11271,7 +10267,10 @@ Our binary for Mac OS X is compiled on Rhapsody 5.5 with the following
configure line:
@example
-CC=gcc CFLAGS="-O2 -fomit-frame-pointer" CXX=gcc CXXFLAGS="-O2 -fomit-frame-pointer" ./configure --prefix=/usr/local/mysql "--with-comment=Official MySQL binary" --with-extra-charsets=complex --disable-shared
+CC=gcc CFLAGS="-O2 -fomit-frame-pointer" CXX=gcc CXXFLAGS="-O2 \
+-fomit-frame-pointer" ./configure --prefix=/usr/local/mysql \
+"--with-comment=Official MySQL binary" --with-extra-charsets=complex \
+--disable-shared
@end example
You might want to also add aliases to your shell's resource file to
@@ -11295,8 +10294,8 @@ alias mysqladmin '/usr/local/mysql/bin/mysqladmin'
* Alpha-DEC-UNIX:: Alpha-DEC-UNIX Notes (Tru64)
* Alpha-DEC-OSF1:: Alpha-DEC-OSF1 Notes
* SGI-Irix:: SGI Irix Notes
-* SCO:: SCO Notes
-* SCO Unixware:: SCO Unixware Version 7.0 Notes
+* Caldera:: Caldera Notes
+* Caldera Unixware:: Caldera Unixware Version 7.0 Notes
@end menu
@@ -11312,8 +10311,8 @@ file you must be running at least HP-UX 10.x to have access to HP's
software depot tools.
The HP version of MySQL was compiled on an HP 9000/8xx server
-under HP-UX 10.20, and uses MIT-pthreads. It is known to work well under
-this configuration. MySQL Version 3.22.26 and newer can also be
+under HP-UX 10.20, and uses MIT-pthreads. It is known to work well under
+this configuration. MySQL Version 3.22.26 and newer can also be
built with HP's native thread package.
Other configurations that may work:
@@ -11383,7 +10382,7 @@ There are a couple of small problems when compiling MySQL on
HP-UX. We recommend that you use @code{gcc} instead of the HP-UX native
compiler, because @code{gcc} produces better code!
-We recommend using gcc 2.95 on HP-UX. Don't use high optimization
+We recommend using gcc 2.95 on HP-UX. Don't use high optimisation
flags (like -O6) as this may not be safe on HP-UX.
Note that MIT-pthreads can't be compiled with the HP-UX compiler
@@ -11392,7 +10391,10 @@ because it can't compile @code{.S} (assembler) files.
The following configure line should work:
@example
-CFLAGS="-DHPUX -I/opt/dce/include" CXXFLAGS="-DHPUX -I/opt/dce/include -felide-constructors -fno-exceptions -fno-rtti" CXX=gcc ./configure --with-pthread --with-named-thread-libs='-ldce' --prefix=/usr/local/mysql --disable-shared
+CFLAGS="-DHPUX -I/opt/dce/include -fpic" \
+CXXFLAGS="-DHPUX -I/opt/dce/include -felide-constructors -fno-exceptions \
+-fno-rtti" CXX=gcc ./configure --with-pthread \
+--with-named-thread-libs='-ldce' --prefix=/usr/local/mysql --disable-shared
@end example
If you are compiling @code{gcc} 2.95 yourself, you should NOT link it with
@@ -11415,7 +10417,7 @@ PHKL_22840 Streams cumulative
PHNE_22397 ARPA cumulative
@end example
-This will solve a problem that one gets @code{EWOULDBLOCK} from @code{recv()}
+This will solve a problem that one gets @code{EWOULDBLOCK} from @code{recv()}
and @code{EBADF} from @code{accept()} in threaded applications.
If you are using @code{gcc} 2.95.1 on an unpatched HP-UX 11.x system,
@@ -11454,7 +10456,9 @@ the definition in @file{pthread.h}. Here's the diff:
After this, the following configure line should work:
@example
-CFLAGS="-fomit-frame-pointer -O3 -fpic" CXX=gcc CXXFLAGS="-felide-constructors -fno-exceptions -fno-rtti -O3" ./configure --prefix=/usr/local/mysql --disable-shared
+CFLAGS="-fomit-frame-pointer -O3 -fpic" CXX=gcc \
+CXXFLAGS="-felide-constructors -fno-exceptions -fno-rtti -O3" \
+./configure --prefix=/usr/local/mysql --disable-shared
@end example
Here is some information that a HP-UX Version 11.x user sent us about compiling
@@ -11494,13 +10498,13 @@ MySQL with HP-UX:x compiler:
@itemize @bullet
@item
-I had to use the compile-time flag @code{-D_REENTRANT} to get the compiler
-to recognize the prototype for @code{localtime_r}. Alternatively I could have
-supplied the prototype for @code{localtime_r}. But I wanted to catch other
+I had to use the compile-time flag @code{-D_REENTRANT} to get the compiler
+to recognise the prototype for @code{localtime_r}. Alternatively I could have
+supplied the prototype for @code{localtime_r}. But I wanted to catch other
bugs without needing to run into them. I wasn't sure where I needed it, so I
added it to all flags.
@item
-The optimization flags used by MySQL (-O3) are not recognized by HP's
+The optimisation flags used by MySQL (-O3) are not recognised by HP's
compilers. I did not change the flags.
@end itemize
@@ -11508,7 +10512,8 @@ If you get the following error from @code{configure}
@example
checking for cc option to accept ANSI C... no
-configure: error: MySQL requires a ANSI C compiler (and a C++ compiler). Try gcc. See the Installation chapter in the Reference Manual.
+configure: error: MySQL requires a ANSI C compiler (and a C++ compiler).
+Try gcc. See the Installation chapter in the Reference Manual.
@end example
Check that you don't have the path to the K&R compiler before the path
@@ -11549,9 +10554,9 @@ you must also remove the @code{-qstrict} option (this is a limitation in
the IBM C compiler).
If you are using @code{gcc} or @code{egcs} to compile MySQL, you
-@strong{MUST} use the @code{-fno-exceptions} flag, as the exception
+@strong{must} use the @code{-fno-exceptions} flag, as the exception
handling in @code{gcc}/@code{egcs} is not thread safe! (This is tested with
-@code{egcs} 1.1.). There are also some known problems with IBM's assembler,
+@code{egcs} 1.1.) There are also some known problems with IBM's assembler,
which may cause it to generate bad code when used with gcc.
We recommend the following @code{configure} line with @code{egcs} and
@@ -11566,9 +10571,9 @@ CXXFLAGS="-felide-constructors -fno-exceptions -fno-rtti" \
The @code{-Wa,-many} is necessary for the compile to be successful. IBM is
aware of this problem but is in to hurry to fix it because of the workaround
-available. We don't know if the @code{-fno-exceptions} is required with
-@code{gcc 2.95}, but as MySQL doesn't use exceptions and the above
-option generates faster code, we recommend that you should always use this
+available. We don't know if the @code{-fno-exceptions} is required with
+@code{gcc 2.95}, but as MySQL doesn't use exceptions and the above
+option generates faster code, we recommend that you should always use this
option with @code{egcs / gcc}.
If you get a problem with assembler code try changing the -mcpu=xxx to
@@ -11593,7 +10598,8 @@ configuring with:
@example
shell> CFLAGS=-DDONT_USE_THR_ALARM CXX=gcc \
- CXXFLAGS="-felide-constructors -fno-exceptions -fno-rtti -DDONT_USE_THR_ALARM" \
+ CXXFLAGS="-felide-constructors -fno-exceptions -fno-rtti \
+ -DDONT_USE_THR_ALARM" \
./configure --prefix=/usr/local/mysql --with-debug --with-low-memory
@end example
@@ -11700,7 +10706,8 @@ work:
CC="cc -pthread"
CFLAGS="-O4 -ansi_alias -ansi_args -fast -inline speed all -arch host"
CXX="cxx -pthread"
-CXXFLAGS="-O4 -ansi_alias -ansi_args -fast -inline speed all -arch host"
+CXXFLAGS="-O4 -ansi_alias -ansi_args -fast -inline speed all -arch host \
+-noexceptions -nortti"
export CC CFLAGS CXX CXXFLAGS
./configure \
--prefix=/usr/local/mysql \
@@ -11770,11 +10777,14 @@ With the Digital compiler "C++ V6.1-029", the following should work:
@example
CC=cc -pthread
-CFLAGS=-O4 -ansi_alias -ansi_args -fast -inline speed -speculate all -arch host
+CFLAGS=-O4 -ansi_alias -ansi_args -fast -inline speed -speculate all \
+ -arch host
CXX=cxx -pthread
-CXXFLAGS=-O4 -ansi_alias -ansi_args -fast -inline speed -speculate all -arch host -noexceptions -nortti
+CXXFLAGS=-O4 -ansi_alias -ansi_args -fast -inline speed -speculate all \
+ -arch host -noexceptions -nortti
export CC CFLAGS CXX CXXFLAGS
-./configure --prefix=/usr/mysql/mysql --with-mysqld-ldflags=-all-static --disable-shared --with-named-thread-libs="-lmach -lexc -lc"
+./configure --prefix=/usr/mysql/mysql --with-mysqld-ldflags=-all-static \
+ --disable-shared --with-named-thread-libs="-lmach -lexc -lc"
@end example
In some versions of OSF1, the @code{alloca()} function is broken. Fix
@@ -11789,7 +10799,7 @@ The @code{alloca()} function also may have an incorrect prototype in
When using @code{gcc}, you can also try running @code{configure} like this:
@example
-shell> CFLAGS=-D_PTHREAD_USE_D4 CXX=gcc CXXFLAGS=-O3 ./configure ....
+shell> CFLAGS=-D_PTHREAD_USE_D4 CXX=gcc CXXFLAGS=-O3 ./configure ...
@end example
If you have problems with signals (MySQL dies unexpectedly
@@ -11818,12 +10828,12 @@ Please submit a full bug report.
To fix this you should change to the @code{sql} directory and do a ``cut
and paste'' of the last @code{gcc} line, but change @code{-O3} to
@code{-O0} (or add @code{-O0} immediately after @code{gcc} if you don't
-have any @code{-O} option on your compile line.) After this is done you
+have any @code{-O} option on your compile line). After this is done you
can just change back to the top-level directly and run @code{make}
again.
-@node SGI-Irix, SCO, Alpha-DEC-OSF1, Other Unix Notes
+@node SGI-Irix, Caldera, Alpha-DEC-OSF1, Other Unix Notes
@subsubsection SGI Irix Notes
If you are using Irix Version 6.5.3 or newer @code{mysqld} will only be able to
@@ -11842,11 +10852,11 @@ In some Irix implementations, the @code{alloca()} function is broken. If the
@code{mysqld} server dies on some @code{SELECT} statements, remove the lines
from @file{config.h} that define @code{HAVE_ALLOC} and @code{HAVE_ALLOCA_H}.
If @code{mysqladmin create} doesn't work, remove the line from @file{config.h}
-that defines @code{HAVE_READDIR_R}. You may have to remove the
+that defines @code{HAVE_READDIR_R}. You may have to remove the
@code{HAVE_TERM_H} line as well.
SGI recommends that you install all of the patches on this page as a set:
-http://support.sgi.com/surfzone/patches/patchset/6.2_indigo.rps.html
+@uref{http://support.sgi.com/surfzone/patches/patchset/6.2_indigo.rps.html}
At the very minimum, you should install the latest kernel rollup, the
latest @code{rld} rollup, and the latest @code{libc} rollup.
@@ -11866,12 +10876,13 @@ Type the following in the top-level directory of your MySQL source
tree:
@example
-shell> extra/replace bool curses_bool < /usr/include/curses.h > include/curses.h
+shell> extra/replace bool curses_bool < /usr/include/curses.h \
+> include/curses.h
shell> make
@end example
There have also been reports of scheduling problems. If only one thread is
-running, things go slow. Avoid this by starting another client. This may
+running, things go slow. Avoid this by starting another client. This may
lead to a 2-to-10-fold increase in execution speed thereafter for the other
thread. This is a poorly understood problem with Irix threads; you may have
to improvise to find solutions until this can be fixed.
@@ -11881,7 +10892,8 @@ If you are compiling with @code{gcc}, you can use the following
@example
CC=gcc CXX=gcc CXXFLAGS=-O3 \
-./configure --prefix=/usr/local/mysql --enable-thread-safe-client --with-named-thread-libs=-lpthread
+./configure --prefix=/usr/local/mysql --enable-thread-safe-client \
+--with-named-thread-libs=-lpthread
@end example
On Irix 6.5.11 with native Irix C and C++ compilers ver. 7.3.1.2, the
@@ -11890,14 +10902,15 @@ following is reported to work
@example
CC=cc CXX=CC CFLAGS='-O3 -n32 -TARG:platform=IP22 -I/usr/local/include \
-L/usr/local/lib' CXXFLAGS='-O3 -n32 -TARG:platform=IP22 \
--I/usr/local/include -L/usr/local/lib' ./configure --prefix=/usr/local/mysql \
---with-berkeley-db --with-innodb \
---with-libwrap=/usr/local --with-named-curses-libs=/usr/local/lib/libncurses.a
+-I/usr/local/include -L/usr/local/lib' ./configure \
+--prefix=/usr/local/mysql --with-innodb --with-berkeley-db \
+--with-libwrap=/usr/local \
+--with-named-curses-libs=/usr/local/lib/libncurses.a
@end example
-@node SCO, SCO Unixware, SGI-Irix, Other Unix Notes
-@subsubsection SCO Notes
+@node Caldera, Caldera Unixware, SGI-Irix, Other Unix Notes
+@subsubsection Caldera (SCO) Notes
The current port is tested only on a ``sco3.2v5.0.4'' and
``sco3.2v5.0.5'' system. There has also been a lot of progress on a
@@ -11919,12 +10932,13 @@ GNU @code{as}. You can also use @code{egcs} 1.1.2 or newer
to execute the following command:
@example
-shell> cp -p /usr/include/pthread/stdtypes.h /usr/local/lib/gcc-lib/i386-pc-sco3.2v5.0.5/egcs-2.91.66/include/pthread/
+shell> cp -p /usr/include/pthread/stdtypes.h \
+/usr/local/lib/gcc-lib/i386-pc-sco3.2v5.0.5/egcs-2.91.66/include/pthread/
@end example
@item
You need the port of GCC 2.5.x for this product and the Development
-system. They are required on this version of SCO Unix. You cannot
+system. They are required on this version of Caldera (SCO) Unix. You cannot
just use the GCC Dev system.
@item
@@ -11935,8 +10949,8 @@ You can also get a precompiled package from
@uref{http://www.mysql.com/Downloads/SCO/FSU-threads-3.5c.tar.gz}.
@item
-FSU Pthreads can be compiled with SCO Unix 4.2 with tcpip. Or
-OpenServer 3.0 or Open Desktop 3.0 (OS 3.0 ODT 3.0), with the SCO
+FSU Pthreads can be compiled with Caldera (SCO) Unix 4.2 with tcpip. Or
+OpenServer 3.0 or Open Desktop 3.0 (OS 3.0 ODT 3.0), with the Caldera (SCO)
Development System installed using a good port of GCC 2.5.x ODT or OS
3.0 you will need a good port of GCC 2.5.x There are a lot of problems
without a good port. The port for this product requires the SCO Unix
@@ -11994,11 +11008,11 @@ shell> CFLAGS="-D_XOPEN_XPG4" CXX=gcc CXXFLAGS="-D_XOPEN_XPG4" \
You may get some problems with some include files. In this case, you can
find new SCO-specific include files at
@uref{http://www.mysql.com/Downloads/SCO/SCO-3.2v4.2-includes.tar.gz}.
-You should unpack this file in the @file{include} directory of your
+You should unpack this file in the @file{include} directory of your
MySQL source tree.
@end enumerate
-SCO development notes:
+Caldera (SCO) development notes:
@itemize @bullet
@item
@@ -12006,15 +11020,16 @@ MySQL should automatically detect FSU Pthreads and link @code{mysqld}
with @code{-lgthreads -lsocket -lgthreads}.
@item
-The SCO development libraries are re-entrant in FSU Pthreads. SCO claims
-that its libraries' functions are re-entrant, so they must be reentrant with
-FSU Pthreads. FSU Pthreads on OpenServer tries to use the SCO scheme to
-make re-entrant libraries.
+
+The Caldera (SCO) development libraries are re-entrant in FSU Pthreads.
+Caldera claim sthat its libraries' functions are re-entrant, so they must
+be reentrant with FSU Pthreads. FSU Pthreads on OpenServer tries to use
+the SCO scheme to make re-entrant libraries.
@item
-FSU Pthreads (at least the version at @uref{http://www.mysql.com/}) comes
-linked with GNU @code{malloc}. If you encounter problems with memory usage,
-make sure that @file{gmalloc.o} is included in @file{libgthreads.a} and
+FSU Pthreads (at least the version at @uref{http://www.mysql.com/}) comes
+linked with GNU @code{malloc}. If you encounter problems with memory usage,
+make sure that @file{gmalloc.o} is included in @file{libgthreads.a} and
@file{libgthreads.so}.
@item
@@ -12029,8 +11044,8 @@ makes mysqld instable. You have to remove this one if you want to run
mysqld on an OpenServer 5.0.6 machine.
@end itemize
-If you want to install DBI on SCO, you have to edit the @file{Makefile} in
-DBI-xxx and each subdirectory.
+If you want to install DBI on Caldera (SCO), you have to edit the
+@file{Makefile} in DBI-xxx and each subdirectory.
Note that the following assumes gcc 2.95.2 or newer:
@@ -12060,8 +11075,8 @@ if they were compiled with @code{icc} or @code{cc}.
Perl works best when compiled with @code{cc}.
-@node SCO Unixware, , SCO, Other Unix Notes
-@subsubsection SCO Unixware Version 7.0 Notes
+@node Caldera Unixware, , Caldera, Other Unix Notes
+@subsubsection Caldera (SCO) Unixware Version 7.0 Notes
You must use a version of MySQL at least as recent as Version 3.22.13
because that version fixes some portability problems under Unixware.
@@ -12075,12 +11090,6 @@ CC=cc CXX=CC ./configure --prefix=/usr/local/mysql
If you want to use @code{gcc}, you must use @code{gcc} 2.95.2 or newer.
-
-@menu
-* OS/2:: OS/2 Notes
-@end menu
-
-
@node OS/2, BeOS, Other Unix Notes, Operating System Specific Notes
@subsection OS/2 Notes
@@ -12143,7 +11152,7 @@ mysql> CREATE FUNCTION metaphon RETURNS STRING SONAME "example";
@subsection BeOS Notes
We are really interested in getting MySQL to work on BeOS, but
-unfortunately we don't have any person who knows BeOS or has time to do
+unfortunately we don't have any person who knows BeOS or has time to do
a port.
We are interested in finding someone to do a port, and we will help them
@@ -12158,7 +11167,7 @@ in a while.
@subsection Novell Netware Notes
We are really interested in getting MySQL to work on Netware, but
-unfortunately we don't have any person who knows Netware or has time to do
+unfortunately we don't have any person who knows Netware or has time to do
a port.
We are interested in finding someone to do a port, and we will help them
@@ -12166,9 +11175,312 @@ with any technical questions they may have while doing the port.
+@node Perl support, , Operating System Specific Notes, Installing
+@section Perl Installation Comments
+
+@cindex Perl, installing
+@cindex installing, Perl
+
+@menu
+* Perl installation:: Installing Perl on Unix
+* ActiveState Perl:: Installing ActiveState Perl on Windows
+* Windows Perl:: Installing the MySQL Perl distribution on Windows
+* Perl support problems:: Problems using the Perl @code{DBI}/@code{DBD} interface
+@end menu
+
+
+@node Perl installation, ActiveState Perl, Perl support, Perl support
+@subsection Installing Perl on Unix
+
+Perl support for MySQL is provided by means of the
+@code{DBI}/@code{DBD} client interface. @xref{Perl}. The Perl
+@code{DBD}/@code{DBI} client code requires Perl Version 5.004 or later. The
+interface @strong{will not work} if you have an older version of Perl.
+
+MySQL Perl support also requires that you've installed
+MySQL client programming support. If you installed MySQL
+from RPM files, client programs are in the client RPM, but client programming
+support is in the developer RPM. Make sure you've installed the latter RPM.
+
+As of Version 3.22.8, Perl support is distributed separately from the main
+MySQL distribution. If you want to install Perl support, the files
+you will need can be obtained from
+@uref{http://www.mysql.com/Downloads/Contrib/}.
+
+The Perl distributions are provided as compressed @code{tar} archives and
+have names like @file{MODULE-VERSION.tar.gz}, where @code{MODULE} is the
+module name and @code{VERSION} is the version number. You should get the
+@code{Data-Dumper}, @code{DBI}, and @code{Msql-Mysql-modules} distributions
+and install them in that order. The installation procedure is shown below.
+The example shown is for the @code{Data-Dumper} module, but the procedure is
+the same for all three distributions:
+
+@enumerate
+@item
+Unpack the distribution into the current directory:
+@example
+shell> gunzip < Data-Dumper-VERSION.tar.gz | tar xvf -
+@end example
+This command creates a directory named @file{Data-Dumper-VERSION}.
+
+@item
+Change into the top-level directory of the unpacked distribution:
+@example
+shell> cd Data-Dumper-VERSION
+@end example
+
+@item
+Build the distribution and compile everything:
+@example
+shell> perl Makefile.PL
+shell> make
+shell> make test
+shell> make install
+@end example
+@end enumerate
+
+The @code{make test} command is important because it verifies that the
+module is working. Note that when you run that command during the
+@code{Msql-Mysql-modules} installation to exercise the interface code, the
+MySQL server must be running or the test will fail.
+
+It is a good idea to rebuild and reinstall the @code{Msql-Mysql-modules}
+distribution whenever you install a new release of MySQL,
+particularly if you notice symptoms such as all your @code{DBI} scripts
+dumping core after you upgrade MySQL.
+
+If you don't have the right to install Perl modules in the system directory
+or if you to install local Perl modules, the following reference may help
+you:
+
+@example
+@uref{http://www.iserver.com/support/contrib/perl5/modules.html}
+@end example
+
+Look under the heading
+@code{Installing New Modules that Require Locally Installed Modules}.
+
+
+@node ActiveState Perl, Windows Perl, Perl installation, Perl support
+@subsection Installing ActiveState Perl on Windows
+
+@cindex installing, Perl on Windows
+@cindex Perl, installing on Windows
+@cindex ActiveState Perl
+
+To install the MySQL @code{DBD} module with ActiveState Perl on
+Windows, you should do the following:
+
+@itemize @bullet
+@item
+Get ActiveState Perl from
+@uref{http://www.activestate.com/Products/ActivePerl/}
+and install it.
+
+@item
+Open a DOS shell.
+
+@item
+If required, set the HTTP_proxy variable. For example, you might try:
+
+@example
+set HTTP_proxy=my.proxy.com:3128
+@end example
+
+@item
+Start the PPM program:
+
+@example
+C:\> c:\perl\bin\ppm.pl
+@end example
+
+@item
+If you have not already done so, install @code{DBI}:
+
+@example
+ppm> install DBI
+@end example
+
+@item
+If this succeeds, run the following command:
+
+@example
+install \
+ftp://ftp.de.uu.net/pub/CPAN/authors/id/JWIED/DBD-mysql-1.2212.x86.ppd
+@end example
+@end itemize
+
+The above should work at least with ActiveState Perl Version 5.6.
+
+If you can't get the above to work, you should instead install the
+@strong{MyODBC} driver and connect to MySQL server through
+ODBC:
+
+@example
+use DBI;
+$dbh= DBI->connect("DBI:ODBC:$dsn","$user","$password") ||
+ die "Got error $DBI::errstr when connecting to $dsn\n";
+@end example
+
+
+@node Windows Perl, Perl support problems, ActiveState Perl, Perl support
+@subsection Installing the MySQL Perl Distribution on Windows
+
+The MySQL Perl distribution contains @code{DBI},
+@code{DBD:MySQL} and @code{DBD:ODBC}.
+
+@itemize @bullet
+@item
+Get the Perl distribution for Windows from
+@uref{http://www.mysql.com/download.html}.
+
+@item
+Unzip the distribution in @code{C:} so that you get a @file{C:\PERL} directory.
+
+@item
+Add the directory @file{C:\PERL\BIN} to your path.
+
+@item
+Add the directory @file{C:\PERL\BIN\MSWIN32-x86-thread} or
+@file{C:\PERL\BIN\MSWIN32-x86} to your path.
+
+@item
+Test that @code{perl} works by executing @code{perl -v} in a DOS shell.
+@end itemize
+
+
+@node Perl support problems, , Windows Perl, Perl support
+@subsection Problems Using the Perl @code{DBI}/@code{DBD} Interface
+
+@cindex problems, installing Perl
+@cindex Perl DBI/DBD, installation problems
+
+If Perl reports that it can't find the @file{../mysql/mysql.so} module,
+then the problem is probably that Perl can't locate the shared library
+@file{libmysqlclient.so}.
+
+You can fix this by any of the following methods:
+
+@itemize @bullet
+@item
+Compile the @code{Msql-Mysql-modules} distribution with @code{perl
+Makefile.PL -static -config} rather than @code{perl Makefile.PL}.
+
+@item
+Copy @code{libmysqlclient.so} to the directory where your other shared
+libraries are located (probably @file{/usr/lib} or @file{/lib}).
+
+@item
+On Linux you can add the pathname of the directory where
+@file{libmysqlclient.so} is located to the @file{/etc/ld.so.conf} file.
+
+@tindex LD_RUN_PATH environment variable
+@tindex Environment variable, LD_RUN_PATH
+@item
+Add the pathname of the directory where @file{libmysqlclient.so} is located
+to the @code{LD_RUN_PATH} environment variable.
+@end itemize
+
+If you get the following errors from @code{DBD-mysql},
+you are probably using @code{gcc} (or using an old binary compiled with
+@code{gcc}):
+
+@example
+/usr/bin/perl: can't resolve symbol '__moddi3'
+/usr/bin/perl: can't resolve symbol '__divdi3'
+@end example
+
+Add @code{-L/usr/lib/gcc-lib/... -lgcc} to the link command when the
+@file{mysql.so} library gets built (check the output from @code{make} for
+@file{mysql.so} when you compile the Perl client). The @code{-L} option
+should specify the pathname of the directory where @file{libgcc.a} is located
+on your system.
+
+Another cause of this problem may be that Perl and MySQL aren't both
+compiled with @code{gcc}. In this case, you can solve the mismatch by
+compiling both with @code{gcc}.
+
+If you get the following error from @code{Msql-Mysql-modules}
+when you run the tests:
+
+@example
+t/00base............install_driver(mysql) failed:
+Can't load '../blib/arch/auto/DBD/mysql/mysql.so' for module DBD::mysql:
+../blib/arch/auto/DBD/mysql/mysql.so: undefined symbol:
+uncompress at /usr/lib/perl5/5.00503/i586-linux/DynaLoader.pm line 169.
+@end example
+
+it means that you need to include the compression library, -lz, to the
+link line. This can be doing the following change in the file
+@file{lib/DBD/mysql/Install.pm}:
+
+@example
+$sysliblist .= " -lm";
+
+to
+
+$sysliblist .= " -lm -lz";
+@end example
+
+After this, you @strong{must} run 'make realclean' and then proceed with the
+installation from the beginning.
+
+If you want to use the Perl module on a system that doesn't support
+dynamic linking (like Caldera/SCO) you can generate a static version of
+Perl that includes @code{DBI} and @code{DBD-mysql}. The way this works
+is that you generate a version of Perl with the @code{DBI} code linked
+in and install it on top of your current Perl. Then you use that to
+build a version of Perl that additionally has the @code{DBD} code linked
+in, and install that.
+
+On Caldera (SCO), you must have the following environment variables set:
+
+@example
+shell> LD_LIBRARY_PATH=/lib:/usr/lib:/usr/local/lib:/usr/progressive/lib
+or
+shell> LD_LIBRARY_PATH=/usr/lib:/lib:/usr/local/lib:/usr/ccs/lib:\
+/usr/progressive/lib:/usr/skunk/lib
+shell> LIBPATH=/usr/lib:/lib:/usr/local/lib:/usr/ccs/lib:\
+/usr/progressive/lib:/usr/skunk/lib
+shell> MANPATH=scohelp:/usr/man:/usr/local1/man:/usr/local/man:\
+/usr/skunk/man:
+@end example
+
+First, create a Perl that includes a statically linked @code{DBI} by running
+these commands in the directory where your @code{DBI} distribution is
+located:
+
+@example
+shell> perl Makefile.PL -static -config
+shell> make
+shell> make install
+shell> make perl
+@end example
+
+Then you must install the new Perl. The output of @code{make perl} will
+indicate the exact @code{make} command you will need to execute to perform
+the installation. On Caldera (SCO), this is
+@code{make -f Makefile.aperl inst_perl MAP_TARGET=perl}.
+
+Next, use the just-created Perl to create another Perl that also includes a
+statically-linked @code{DBD::mysql} by running these commands in the
+directory where your @code{Msql-Mysql-modules} distribution is located:
+
+@example
+shell> perl Makefile.PL -static -config
+shell> make
+shell> make install
+shell> make perl
+@end example
+
+Finally, you should install this new Perl. Again, the output of @code{make
+perl} indicates the command to use.
+
+
+
@node Tutorial, MySQL Database Administration, Installing, Top
-@chapter Introduction to MySQL: A MySQL Tutorial
+@chapter Tutorial Introduction to MySQL
@cindex tutorial
@cindex terminal monitor, defined
@@ -12294,11 +11606,11 @@ that's okay. At this point, it's more important to find out a little about
how to issue queries than to jump right in creating tables, loading data
into them, and retrieving data from them. This section describes the basic
principles of entering commands, using several queries you can try out to
-familiarize yourself with how @code{mysql} works.
+familiarise yourself with how @code{mysql} works.
Here's a simple command that asks the server to tell you its version number
and the current date. Type it in as shown below following the @code{mysql>}
-prompt and hit the RETURN key:
+prompt and press Enter:
@example
mysql> SELECT VERSION(), CURRENT_DATE;
@@ -12423,7 +11735,7 @@ Here, too, notice the prompt. It switches back to @code{mysql>} after you
type @code{\c}, providing feedback to indicate that @code{mysql} is ready
for a new command.
-The following table shows each of the prompts you may see and summarizes what
+The following table shows each of the prompts you may see and summarises what
they mean about the state that @code{mysql} is in:
@cindex prompts, meanings
@@ -12449,7 +11761,7 @@ mysql> SELECT USER()
If this happens to you (you think you've entered a statement but the only
response is a @code{->} prompt), most likely @code{mysql} is waiting for the
semicolon. If you don't notice what the prompt is telling you, you might sit
-there for a while before realizing what you need to do. Enter a semicolon to
+there for a while before realising what you need to do. Enter a semicolon to
complete the statement, and @code{mysql} will execute it:
@example
@@ -12478,7 +11790,7 @@ mysql> SELECT * FROM my_table WHERE name = "Smith AND age < 30;
">
@end example
-If you enter this @code{SELECT} statement, then hit RETURN and wait for the
+If you enter this @code{SELECT} statement, then press Enter and wait for the
result, nothing will happen. Instead of wondering why this
query takes so long, notice the clue provided by the @code{">} prompt. It
tells you that @code{mysql} expects to see the rest of an unterminated
@@ -12548,11 +11860,11 @@ to think of real-world situations in which a similar type of database might
be used. For example, a database like this could be used by a farmer to keep
track of livestock, or by a veterinarian to keep track of patient records.
A menagerie distribution containing some of the queries and sample data used
-in the following sections can be obtained from the MySQL Web site.
-It's available in either
-@uref{http://www.mysql.com/Downloads/Contrib/Examples/menagerie.tar.gz,compressed @code{tar} format}
-or
-@uref{http://www.mysql.com/Downloads/Contrib/Examples/menagerie.zip,Zip format}.
+in the following sections can be obtained from the MySQL web site.
+It's available in either compressed @code{tar} format
+(@uref{http://www.mysql.com/Downloads/Contrib/Examples/menagerie.tar.gz})
+or Zip format
+(@uref{http://www.mysql.com/Downloads/Contrib/Examples/menagerie.zip}).
Use the @code{SHOW} statement to find out what databases currently exist
on the server:
@@ -12795,6 +12107,7 @@ use @code{NULL} values. To represent these in your text file, use
this (where the whitespace between values is a single tab character):
@multitable @columnfractions .15 .15 .15 .15 .25 .15
+@item @strong{name} @tab @strong{owner} @tab @strong{species} @tab @strong{sex} @tab @strong{birth} @tab @strong{death}
@item @code{Whistler} @tab @code{Gwen} @tab @code{bird} @tab @code{\N} @tab @code{1997-12-09} @tab @code{\N}
@end multitable
@@ -13054,7 +12367,7 @@ mysql> SELECT owner FROM pet;
@findex DISTINCT
However, notice that the query simply retrieves the @code{owner} field from
-each record, and some of them appear more than once. To minimize the output,
+each record, and some of them appear more than once. To minimise the output,
retrieve each unique output record just once by adding the keyword
@code{DISTINCT}:
@@ -13282,7 +12595,7 @@ mysql> SELECT name, birth, death,
+--------+------------+------------+------+
@end example
-The query uses @code{death IS NOT NULL} rather than @code{death != NULL}
+The query uses @code{death IS NOT NULL} rather than @code{death <> NULL}
because @code{NULL} is a special value. This is explained later.
@xref{Working with NULL, , Working with @code{NULL}}.
@@ -13367,12 +12680,12 @@ The @code{NULL} value can be surprising until you get used to it.
Conceptually, @code{NULL} means missing value or unknown value and it
is treated somewhat differently than other values. To test for @code{NULL},
you cannot use the arithmetic comparison operators such as @code{=}, @code{<},
-or @code{!=}. To demonstrate this for yourself, try the following query:
+or @code{<>}. To demonstrate this for yourself, try the following query:
@example
-mysql> SELECT 1 = NULL, 1 != NULL, 1 < NULL, 1 > NULL;
+mysql> SELECT 1 = NULL, 1 <> NULL, 1 < NULL, 1 > NULL;
+----------+-----------+----------+----------+
-| 1 = NULL | 1 != NULL | 1 < NULL | 1 > NULL |
+| 1 = NULL | 1 <> NULL | 1 < NULL | 1 > NULL |
+----------+-----------+----------+----------+
| NULL | NULL | NULL | NULL |
+----------+-----------+----------+----------+
@@ -13390,12 +12703,18 @@ mysql> SELECT 1 IS NULL, 1 IS NOT NULL;
+-----------+---------------+
@end example
+Note that two @code{NULL} are compared as equal is when you do an
+@code{GROUP BY}.
+
In MySQL, 0 or @code{NULL} means false and anything else means true.
The default truth value from a boolean operation is 1.
+When doing an @code{ORDER BY}, @code{NULL} values are always sorted first,
+even if you are using @code{DESC}.
+
This special treatment of @code{NULL} is why, in the previous section, it
was necessary to determine which animals are no longer alive using
-@code{death IS NOT NULL} instead of @code{death != NULL}.
+@code{death IS NOT NULL} instead of @code{death <> NULL}.
@node Pattern matching, Counting rows, Working with NULL, Retrieving data
@@ -13413,7 +12732,7 @@ SQL pattern matching allows you to use @samp{_} to match any single
character and @samp{%} to match an arbitrary number of characters (including
zero characters). In MySQL, SQL patterns are case insensitive by
default. Some examples are shown below. Note that you do not use @code{=}
-or @code{!=} when you use SQL patterns; use the @code{LIKE} or @code{NOT
+or @code{<>} when you use SQL patterns; use the @code{LIKE} or @code{NOT
LIKE} comparison operators instead.
To find names beginning with @samp{b}:
@@ -13521,8 +12840,8 @@ mysql> SELECT * FROM pet WHERE name REGEXP "^b";
+--------+--------+---------+------+------------+------------+
@end example
-Prior to MySQL Version 3.23.4, @code{REGEXP} is case sensitive,
-and the previous query will return no rows. To match either lowercase or
+Prior to MySQL Version 3.23.4, @code{REGEXP} is case sensitive,
+and the previous query will return no rows. To match either lowercase or
uppercase @samp{b}, use this query instead:
@example
@@ -13647,7 +12966,7 @@ ERROR 1140 at line 1: Mixing of GROUP columns (MIN(),MAX(),COUNT()...)
with no GROUP columns is illegal if there is no GROUP BY clause
@end example
-@code{COUNT()} and @code{GROUP BY} are useful for characterizing your
+@code{COUNT()} and @code{GROUP BY} are useful for characterising your
data in various ways. The following examples show different ways to
perform animal census operations.
@@ -13759,7 +13078,7 @@ A date so you know when the event occurred.
A field to describe the event.
@item
-An event type field, if you want to be able to categorize events.
+An event type field, if you want to be able to categorise events.
@end itemize
Given these considerations, the @code{CREATE TABLE} statement for the
@@ -13774,13 +13093,14 @@ As with the @code{pet} table, it's easiest to load the initial records
by creating a tab-delimited text file containing the information:
@multitable @columnfractions .15 .15 .15 .55
+@item @strong{name} @tab @strong{date} @tab @strong{type} @tab @strong{remark}
@item Fluffy @tab 1995-05-15 @tab litter @tab 4 kittens, 3 female, 1 male
@item Buffy @tab 1993-06-23 @tab litter @tab 5 puppies, 2 female, 3 male
@item Buffy @tab 1994-06-19 @tab litter @tab 3 puppies, 3 female
@item Chirpy @tab 1999-03-21 @tab vet @tab needed beak straightened
@item Slim @tab 1997-08-03 @tab vet @tab broken rib
-@item Bowser @tab 1991-10-12 @tab kennel
-@item Fang @tab 1991-10-12 @tab kennel
+@item Bowser @tab 1991-10-12 @tab kennel @tab
+@item Fang @tab 1991-10-12 @tab kennel @tab
@item Fang @tab 1998-08-28 @tab birthday @tab Gave him a new chew toy
@item Claws @tab 1998-03-17 @tab birthday @tab Gave him a new flea collar
@item Whistler @tab 1998-12-09 @tab birthday @tab First birthday
@@ -13803,7 +13123,9 @@ calculate the age of the mother, you need her birth date. Because that is
stored in the @code{pet} table, you need both tables for the query:
@example
-mysql> SELECT pet.name, (TO_DAYS(date) - TO_DAYS(birth))/365 AS age, remark
+mysql> SELECT pet.name,
+ -> (TO_DAYS(date) - TO_DAYS(birth))/365 AS age,
+ -> remark
-> FROM pet, event
-> WHERE pet.name = event.name AND type = "litter";
+--------+------+-----------------------------+
@@ -13917,7 +13239,7 @@ mysql> DESCRIBE pet;
@end example
@code{Field} indicates the column name, @code{Type} is the data type for
-the column, @code{Null} indicates whether or not the column can contain
+the column, @code{NULL} indicates whether or not the column can contain
@code{NULL} values, @code{Key} indicates whether or not the column is
indexed, and @code{Default} specifies the column's default value.
@@ -13988,6 +13310,7 @@ mysql> SELECT * FROM shop;
* example-Foreign keys:: Using foreign keys
* Searching on two keys:: Searching on Two Keys
* Calculating days:: Calculating visits per day
+* example-AUTO_INCREMENT:: Using AUTO_INCREMENT
@end menu
@@ -14171,22 +13494,26 @@ select * from shop where price=@@min_price or price=@@max_price;
@cindex foreign keys
@cindex keys, foreign
-You don't need foreign keys to join 2 tables.
+In MySQL 3.23.44 and up, @code{InnoDB} tables supports checking of
+foreign key constraints. @xref{InnoDB}.
+See also @ref{ANSI diff Foreign Keys}.
-The only thing MySQL doesn't do is @code{CHECK} to make sure that
-the keys you use really exist in the table(s) you're referencing and it
-doesn't automatically delete rows from table with a foreign key
+You don't actually need foreign keys to join 2 tables.
+The only thing MySQL currently doesn't do (in type types other than
+@code{InnoDB}), is @code{CHECK} to make sure that the keys you use
+really exist in the table(s) you're referencing and it
+doesn't automatically delete rows from a table with a foreign key
definition. If you use your keys like normal, it'll work just fine:
@example
-CREATE TABLE persons (
+CREATE TABLE person (
id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
name CHAR(60) NOT NULL,
PRIMARY KEY (id)
);
-CREATE TABLE shirts (
+CREATE TABLE shirt (
id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
style ENUM('t-shirt', 'polo', 'dress') NOT NULL,
color ENUM('red', 'blue', 'orange', 'white', 'black') NOT NULL,
@@ -14195,24 +13522,24 @@ CREATE TABLE shirts (
);
-INSERT INTO persons VALUES (NULL, 'Antonio Paz');
+INSERT INTO person VALUES (NULL, 'Antonio Paz');
-INSERT INTO shirts VALUES
+INSERT INTO shirt VALUES
(NULL, 'polo', 'blue', LAST_INSERT_ID()),
(NULL, 'dress', 'white', LAST_INSERT_ID()),
(NULL, 't-shirt', 'blue', LAST_INSERT_ID());
-INSERT INTO persons VALUES (NULL, 'Lilliana Angelovska');
+INSERT INTO person VALUES (NULL, 'Lilliana Angelovska');
-INSERT INTO shirts VALUES
+INSERT INTO shirt VALUES
(NULL, 'dress', 'orange', LAST_INSERT_ID()),
(NULL, 'polo', 'red', LAST_INSERT_ID()),
(NULL, 'dress', 'blue', LAST_INSERT_ID()),
(NULL, 't-shirt', 'white', LAST_INSERT_ID());
-SELECT * FROM persons;
+SELECT * FROM person;
+----+---------------------+
| id | name |
+----+---------------------+
@@ -14220,7 +13547,7 @@ SELECT * FROM persons;
| 2 | Lilliana Angelovska |
+----+---------------------+
-SELECT * FROM shirts;
+SELECT * FROM shirt;
+----+---------+--------+-------+
| id | style | color | owner |
+----+---------+--------+-------+
@@ -14234,7 +13561,7 @@ SELECT * FROM shirts;
+----+---------+--------+-------+
-SELECT s.* FROM persons p, shirts s
+SELECT s.* FROM person p, shirt s
WHERE p.name LIKE 'Lilliana%'
AND s.owner = p.id
AND s.color <> 'white';
@@ -14256,9 +13583,9 @@ SELECT s.* FROM persons p, shirts s
@cindex searching, two keys
@cindex keys, searching on two
-MySQL doesn't yet optimize when you search on two different
-keys combined with @code{OR} (Searching on one key with different @code{OR}
-parts is optimized quite good):
+MySQL doesn't yet optimise when you search on two different
+keys combined with @code{OR} (searching on one key with different @code{OR}
+parts is optimised quite well):
@example
SELECT field1_index, field2_index FROM test_table WHERE field1_index = '1'
@@ -14267,12 +13594,12 @@ OR field2_index = '1'
The reason is that we haven't yet had time to come up with an efficient
way to handle this in the general case. (The @code{AND} handling is,
-in comparison, now completely general and works very well).
+in comparison, now completely general and works very well.)
For the moment you can solve this very efficiently by using a
-@code{TEMPORARY} table. This type of optimization is also very good if
+@code{TEMPORARY} table. This type of optimisation is also very good if
you are using very complicated queries where the SQL server does the
-optimizations in the wrong order.
+optimisations in the wrong order.
@example
CREATE TEMPORARY TABLE tmp
@@ -14283,10 +13610,10 @@ SELECT * from tmp;
DROP TABLE tmp;
@end example
-The above way to solve this query is in effect an @code{UNION} of two queries.
-
+The above way to solve this query is in effect a @code{UNION} of two queries.
+@xref{UNION}.
-@node Calculating days, , Searching on two keys, Examples
+@node Calculating days, example-AUTO_INCREMENT, Searching on two keys, Examples
@subsection Calculating visits per day
@findex BIT_OR
@@ -14298,10 +13625,12 @@ The following shows an idea of how you can use the bit group functions
to calculate the number of days per month a user has visited a web page.
@example
-CREATE TABLE t1 (year YEAR(4), month INT(2) UNSIGNED ZEROFILL, day INT(2) UNSIGNED ZEROFILL);
-INSERT INTO t1 VALUES(2000,1,1),(2000,1,20),(2000,1,30),(2000,2,2),(2000,2,23),(2000,2,23);
-
-SELECT year,month,BIT_COUNT(BIT_OR(1<<day)) AS days FROM t1 GROUP BY year,month;
+CREATE TABLE t1 (year YEAR(4), month INT(2) UNSIGNED ZEROFILL,
+ day INT(2) UNSIGNED ZEROFILL);
+INSERT INTO t1 VALUES(2000,1,1),(2000,1,20),(2000,1,30),(2000,2,2),
+ (2000,2,23),(2000,2,23);
+SELECT year,month,BIT_COUNT(BIT_OR(1<<day)) AS days FROM t1
+ GROUP BY year,month;
Which returns:
@@ -14317,6 +13646,67 @@ The above calculates how many different days was used for a given
year/month combination, with automatic removal of duplicate entries.
+@node example-AUTO_INCREMENT, , Calculating days, Examples
+@subsection Using AUTO_INCREMENT
+
+@cindex AUTO_INCREMENT
+The @code{AUTO_INCREMENT} attribute can be used to generate an unique
+identity for new rows:
+
+@example
+CREATE TABLE animals (id MEDIUMINT NOT NULL AUTO_INCREMENT,
+name CHAR(30) NOT NULL, PRIMARY KEY (id));
+INSERT INTO animals (name) VALUES ("dog"),("cat"),("penguin"),
+("lax"),("whale");
+SELECT * FROM animals;
+
+Which returns:
+
++----+---------+
+| id | name |
++----+---------+
+| 1 | dog |
+| 2 | cat |
+| 3 | penguin |
+| 4 | lax |
+| 5 | whale |
++----+---------+
+@end example
+
+For MyISAM and BDB tables you can specify @code{AUTO_INCREMENT} on
+secondary column in a multi-column key. In this case the generated
+value for the autoincrement column is calculated as
+@code{MAX(auto_increment_column)+1) WHERE prefix=given-prefix}. This is
+useful when you want to put data into ordered groups.
+
+@example
+CREATE TABLE animals (grp ENUM('fish','mammal','bird') NOT NULL,
+ id MEDIUMINT NOT NULL AUTO_INCREMENT
+ PRIMARY KEY (grp,id));
+INSERT INTO animals (grp,name) VALUES("mammal","dog"),("mammal","cat"),
+ ("bird","penguin"),("fish","lax"),("mammal","whale");
+SELECT * FROM animals ORDER BY grp,id;
+
+Which returns:
+
++--------+----+---------+
+| grp | id | name |
++--------+----+---------+
+| fish | 1 | lax |
+| mammal | 1 | dog |
+| mammal | 2 | cat |
+| mammal | 3 | whale |
+| bird | 1 | penguin |
++--------+----+---------+
+@end example
+
+Note that in this case, the auto_increment value will be reused if you
+delete the row with the biggest auto_increment value in any group.
+
+You can get the used @code{AUTO_INCREMENT} key with the
+@code{LAST_INSERT_ID()} SQL function or the @code{mysql_insert_id()} API
+function.
+
@node Batch mode, Twin, Examples, Tutorial
@section Using @code{mysql} in Batch Mode
@@ -14335,6 +13725,13 @@ tell @code{mysql} to read its input from the file:
shell> mysql < batch-file
@end example
+If you are running @code{mysql} under windows and have some special
+characters in the file that causes problems, you can do:
+
+@example
+dos> mysql -e "source batch-file"
+@end example
+
If you need to specify connection parameters on the command line, the
command might look like this:
@@ -14346,6 +13743,9 @@ Enter password: ********
When you use @code{mysql} this way, you are creating a script file, then
executing the script.
+If you want the script to continue even if you have errors, you should
+use the @code{--force} command line option.
+
Why use a script? Here are a few reasons:
@itemize @bullet
@@ -14419,6 +13819,12 @@ If you want to get the interactive output format in batch mode, use
@code{mysql -t}. To echo to the output the commands that are executed, use
@code{mysql -vvv}.
+You can also use scripts in the @code{mysql} command line prompt by
+using the @code{source} command:
+
+@example
+mysql> source filename
+@end example
@node Twin, Apache, Batch mode, Tutorial
@section Queries from Twin Project
@@ -14442,10 +13848,7 @@ history collection. In addition, data are collected on medical and
environmental risk factors.
More information about Twin studies can be found at:
-
-@example
-@url{http://www.imm.ki.se/TWIN/TWINUKW.HTM}
-@end example
+@uref{http://www.imm.ki.se/TWIN/TWINUKW.HTM}
The latter part of the project is administered with a Web interface
written using Perl and MySQL.
@@ -14491,15 +13894,23 @@ select
from
twin_project as tp
/* For Twin 1 */
- left join twin_data as td on tp.id = td.id and tp.tvab = td.tvab
- left join informant_data as id on tp.id = id.id and tp.tvab = id.tvab
- left join harmony as h on tp.id = h.id and tp.tvab = h.tvab
- left join lentus as l on tp.id = l.id and tp.tvab = l.tvab
+ left join twin_data as td on tp.id = td.id
+ and tp.tvab = td.tvab
+ left join informant_data as id on tp.id = id.id
+ and tp.tvab = id.tvab
+ left join harmony as h on tp.id = h.id
+ and tp.tvab = h.tvab
+ left join lentus as l on tp.id = l.id
+ and tp.tvab = l.tvab
/* For Twin 2 */
- left join twin_data as td2 on p2.id = td2.id and p2.tvab = td2.tvab
- left join informant_data as id2 on p2.id = id2.id and p2.tvab = id2.tvab
- left join harmony as h2 on p2.id = h2.id and p2.tvab = h2.tvab
- left join lentus as l2 on p2.id = l2.id and p2.tvab = l2.tvab,
+ left join twin_data as td2 on p2.id = td2.id
+ and p2.tvab = td2.tvab
+ left join informant_data as id2 on p2.id = id2.id
+ and p2.tvab = id2.tvab
+ left join harmony as h2 on p2.id = h2.id
+ and p2.tvab = h2.tvab
+ left join lentus as l2 on p2.id = l2.id
+ and p2.tvab = l2.tvab,
person_data as p1,
person_data as p2,
postal_groups as pg
@@ -14521,14 +13932,17 @@ where
/* Twin is suspect */
(td.future_contact = 'Yes' and td.suspect = 2) or
/* Twin is suspect - Informant is Blessed */
- (td.future_contact = 'Yes' and td.suspect = 1 and id.suspect = 1) or
+ (td.future_contact = 'Yes' and td.suspect = 1
+ and id.suspect = 1) or
/* No twin - Informant is Blessed */
- (ISNULL(td.suspect) and id.suspect = 1 and id.future_contact = 'Yes') or
+ (ISNULL(td.suspect) and id.suspect = 1
+ and id.future_contact = 'Yes') or
/* Twin broken off - Informant is Blessed */
(td.participation = 'Aborted'
and id.suspect = 1 and id.future_contact = 'Yes') or
/* Twin broken off - No inform - Have partner */
- (td.participation = 'Aborted' and ISNULL(id.suspect) and p2.dead = 0))
+ (td.participation = 'Aborted' and ISNULL(id.suspect)
+ and p2.dead = 0))
and
l.event = 'Finished'
/* Get at area code */
@@ -14555,7 +13969,7 @@ This identifies a twin in a pair. It has a value of @code{1} or @code{2}.
@item column @code{ptvab}
This is an inverse of @code{tvab}. When @code{tvab} is @code{1} this is
@code{2}, and vice versa. It exists to save typing and to make it easier for
-MySQL to optimize the query.
+MySQL to optimise the query.
@end table
This query demonstrates, among other things, how to do lookups on a
@@ -14620,9 +14034,9 @@ group by
@cindex Apache
-The Contrib section includes programs that let you authenticate your
-users from a MySQL database and also let you log your log files
-into a MySQL table. @xref{Contrib}.
+There are programs that let you authenticate your users from a MySQL
+database and also let you log your log files into a MySQL table.
+@xref{Portals}.
You can change the Apache logging format to be easily readable by
MySQL by putting the following into the Apache configuration file:
@@ -14643,7 +14057,7 @@ FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ESCAPED BY '\\'
-@node MySQL Database Administration, MySQL Optimization, Tutorial, Top
+@node MySQL Database Administration, MySQL Optimisation, Tutorial, Top
@chapter MySQL Database Administration
@menu
@@ -14652,7 +14066,7 @@ FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ESCAPED BY '\\'
* User Account Management:: MySQL User Account Management
* Disaster Prevention:: Disaster Prevention and Recovery
* Database Administration:: Database Administration Language Reference
-* Localization:: MySQL Localization and International Usage
+* Localisation:: MySQL Localisation and International Usage
* Server-Side Scripts:: MySQL Server-Side Scripts and Utilities
* Client-Side Scripts:: MySQL Client-Side Scripts and Utilities
* Log Files:: The MySQL Log Files
@@ -14663,6 +14077,8 @@ FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ESCAPED BY '\\'
@node Configuring MySQL, Privilege system, MySQL Database Administration, MySQL Database Administration
@section Configuring MySQL
+@c FIX: add section intro
+
@menu
* Command-line options:: mysqld Command-line Options
@@ -14679,6 +14095,17 @@ FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ESCAPED BY '\\'
@cindex options, command-line
@cindex mysqld options
+In most cases you should manage mysqld options through option files.
+@xref{Option files}.
+
+@code{mysqld} and @code{mysqld.server} reads options from the
+@code{mysqld} and @code{server} groups. @code{mysqld_safe} read options
+from the @code{mysqld}, @code{server}, @code{mysqld_safe} and
+@code{safe_mysqld} groups. An embedded MySQL server usually reads
+options from the @code{server}, @code{embedded} and
+@code{xxxxx_SERVER}, where @code{xxxxx} is the name of the application.
+
+
@code{mysqld} accepts the following command-line options:
@table @code
@@ -14686,7 +14113,7 @@ FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ESCAPED BY '\\'
Use ANSI SQL syntax instead of MySQL syntax. @xref{ANSI mode}.
@item -b, --basedir=path
-Path to installation directory. All paths are usually resolved relative to
+Path to installation directory. All paths are usually resolved relative to
this.
@item --big-tables
@@ -14704,32 +14131,37 @@ Directory where character sets are. @xref{Character sets}.
@item --chroot=path
Chroot @code{mysqld} daemon during startup. Recommended security measure. It will
-somewhat limit @code{LOAD DATA INFILE} and @code{SELECT ... INTO OUTFILE}
+somewhat limit @code{LOAD DATA INFILE} and @code{SELECT ... INTO OUTFILE}
though.
@item --core-file
Write a core file if @code{mysqld} dies. For some systems you must also
specify @code{--core-file-size} to @code{safe_mysqld}. @xref{safe_mysqld, ,
-@code{safe_mysqld}}.
+@code{safe_mysqld}}. Note that on some system like Solaris, you will
+not get a core file if you are also using the @code{--user} option.
@item -h, --datadir=path
Path to the database root.
+@item --debug[...]=
+If MySQL is configured with @code{--with-debug}, you can use this
+option to get a trace file of what @code{mysqld} is doing.
+@xref{Making trace files}.
+
@item --default-character-set=charset
Set the default character set. @xref{Character sets}.
@item --default-table-type=type
Set the default table type for tables. @xref{Table types}.
-@item --debug[...]=
-If MySQL is configured with @code{--with-debug}, you can use this
-option to get a trace file of what @code{mysqld} is doing.
-@xref{Making trace files}.
-
@item --delay-key-write-for-all-tables
Don't flush key buffers between writes for any @code{MyISAM} table.
@xref{Server parameters}.
+@item --des-key-file=filename
+Read the default keys used by @code{des_encrypt()} and @code{des_decrypt()}
+from this file.
+
@item --enable-locking
Enable system locking. Note that if you use this option on a system
which a not fully working lockd() (as on Linux) you will easily get
@@ -14781,8 +14213,8 @@ to the slow query log.
@item --low-priority-updates
Table-modifying operations (@code{INSERT}/@code{DELETE}/@code{UPDATE})
-will have lower priority than selects. It can also be done via
-@code{@{INSERT | REPLACE | UPDATE | DELETE@} LOW_PRIORITY ...} to lower
+will have lower priority than selects. It can also be done via
+@code{@{INSERT | REPLACE | UPDATE | DELETE@} LOW_PRIORITY ...} to lower
the priority of only one query, or by
@code{SET OPTION SQL_LOW_PRIORITY_UPDATES=1} to change the priority in one
thread. @xref{Table locking}.
@@ -14799,19 +14231,20 @@ also set this explicitely to @code{""} if you want to disable this
option. If this option is used, @code{mysqld} will on open check if the
table is marked as crashed or if if the table wasn't closed properly.
(The last option only works if you are running with
-@code{--skip-locking}). If this is the case @code{mysqld} will run
+@code{--skip-locking}.) If this is the case @code{mysqld} will run
check on the table. If the table was corrupted, @code{mysqld} will
attempt to repair it.
The following options affects how the repair works.
@multitable @columnfractions .3 .7
-@item DEFAULT @tab The same as not giving any option to
+@item @strong{Option} @tab @strong{Description}
+@item DEFAULT @tab The same as not giving any option to
@code{--myisam-recover}.
-@item BACKUP @tab If the data table was changed during recover, save a
- backup of the @file{table_name.MYD} data file as
+@item BACKUP @tab If the data table was changed during recover, save a
+ backup of the @file{table_name.MYD} data file as
@file{table_name-datetime.BAK}.
-@item FORCE @tab Run recover even if we will loose more than one row
+@item FORCE @tab Run recover even if we will loose more than one row
from the .MYD file.
@item QUICK @tab Don't check the rows in the table if there isn't any
delete blocks.
@@ -14841,10 +14274,10 @@ Only use one thread (for debugging under Linux). @xref{Debugging server}.
Give a variable a value. @code{--help} lists variables. You can find a full
description for all variables in the @code{SHOW VARIABLES} section in this
manual. @xref{SHOW VARIABLES}. The tuning server parameters section includes
-information of how to optimize these. @xref{Server parameters}.
+information of how to optimise these. @xref{Server parameters}.
@item --safe-mode
-Skip some optimize stages. Implies @code{--skip-delay-key-write}.
+Skip some optimise stages. Implies @code{--skip-delay-key-write}.
@item --safe-show-database
Don't show databases for which the user doesn't have any privileges.
@@ -14857,7 +14290,7 @@ command, if the user doesn't have @code{INSERT} privilege to the
@item --skip-concurrent-insert
Turn off the ability to select and insert at the same time on @code{MyISAM}
tables. (This is only to be used if you think you have found a bug in this
-feature).
+feature.)
@item --skip-delay-key-write
Ignore the @code{delay_key_write} option for all tables.
@@ -14884,8 +14317,8 @@ Hostnames are not resolved. All @code{Host} column values in the grant tables
must be IP numbers or @code{localhost}. @xref{DNS}.
@item --skip-networking
-Don't listen for TCP/IP connections at all. All interaction with
-@code{mysqld} must be made via Unix sockets. This option is highly
+Don't listen for TCP/IP connections at all. All interaction with
+@code{mysqld} must be made via Unix sockets. This option is highly
recommended for systems where only local requests are allowed. @xref{DNS}.
@item --skip-new
@@ -14933,9 +14366,9 @@ Sets the default transaction isolation level. @xref{SET TRANSACTION}.
Path for temporary files. It may be useful if your default @code{/tmp}
directory resides on a partition too small to hold temporary tables.
-@item -u, --user=user_name
-Run @code{mysqld} daemon as user @code{user_name}. This option is
-@emph{mandatory} when starting @code{mysqld} as root.
+@item -u, --user= [user_name | userid]
+Run @code{mysqld} daemon as user @code{user_name} or @code{userid} (numeric).
+This option is @emph{mandatory} when starting @code{mysqld} as root.
@item -V, --version
Output version information and exit.
@@ -14982,7 +14415,6 @@ MySQL reads default options from the following files on Windows:
@item @strong{Filename} @tab @strong{Purpose}
@item @code{windows-system-directory\my.ini} @tab Global options
@item @code{C:\my.cnf} @tab Global options
-@item @code{C:\mysql\data\my.cnf} @tab Server-specific options
@end multitable
Note that on Windows, you should specify all paths with @code{/} instead of
@@ -14999,11 +14431,13 @@ Options specified on the command line or in option files take precedence over
environment variable values. @xref{Environment variables}.
The following programs support option files: @code{mysql},
-@code{mysqladmin}, @code{mysqld}, @code{mysqldump}, @code{mysqlimport},
-@code{mysql.server}, @code{myisamchk}, and @code{myisampack}.
+@code{mysqladmin}, @code{mysqld}, @code{mysqld_safe}, @code{mysql.server},
+@code{mysqldump}, @code{mysqlimport}, @code{mysqlshow}, @code{mysqlcheck},
+@code{myisamchk}, and @code{myisampack}.
-You can use option files to specify any long option that a program supports!
-Run the program with @code{--help} to get a list of available options.
+Any long option that may be given on the command line when running a MySQL
+program can be given in an option file as well (without the leading double
+dash). Run the program with @code{--help} to get a list of available options.
An option file can contain lines of the following forms:
@@ -15085,6 +14519,7 @@ All MySQL clients that support option files support the
following options:
@multitable @columnfractions .40 .60
+@item @strong{Option} @tab @strong{Description}
@item --no-defaults @tab Don't read any option files.
@item --print-defaults @tab Print the program name and all options that it will get.
@item --defaults-file=full-path-to-default-file @tab Only use the given configuration file.
@@ -15162,28 +14597,28 @@ servers:
At least the following options should be different per server:
-@table @code
+@itemize
@item port=#
@item socket=path
@item pid-file=path
-@end table
+@end itemize
The following options should be different, if they are used:
-@table @code
+@itemize
@item log=path
@item log-bin=path
@item log-update=path
@item log-isam=path
@item bdb-logdir=path
-@end table
+@end itemize
If you want more performance, you can also specify the following differently:
-@table @code
+@itemize
@item tmpdir=path
@item bdb-tmpdir=path
-@end table
+@end itemize
@xref{Command-line options}.
@@ -15192,11 +14627,7 @@ start them with @code{./bin/safe_mysqld} then in most cases the only
option you need to add/change is the @code{socket} and @code{port}
argument to @code{safe_mysqld}.
-
-@menu
-* Multiple servers:: Running Multiple MySQL Servers on the Same Machine
-@end menu
-
+@xref{Multiple servers, ,Running Multiple MySQL Servers on the Same Machine}.
@node Multiple servers, , Installing many servers, Configuring MySQL
@subsection Running Multiple MySQL Servers on the Same Machine
@@ -15263,16 +14694,16 @@ files to @code{safe_mysqld} with @code{--log}, @code{--log-update}, or
@code{--log-slow-queries}. Otherwise, both servers may be trying to
write to the same log file.
-@strong{WARNING}: Normally you should never have two servers that update
+@strong{Warning}: Normally you should never have two servers that update
data in the same database! If your OS doesn't support fault-free system
locking, this may lead to unpleasant surprises!
If you want to use another database directory for the second server, you
can use the @code{--datadir=path} option to @code{safe_mysqld}.
-@strong{NOTE} also that starting several MySQL servers
+@strong{Note} also that starting several MySQL servers
(@code{mysqlds}) in different machines and letting them access one data
-directory over @code{NFS} is generally a @strong{BAD IDEA}! The problem
+directory over @code{NFS} is generally a @strong{bad idea}! The problem
is that the @code{NFS} will become the bottleneck with the speed. It is
not meant for such use. And last but not least, you would still have to
come up with a solution how to make sure that two or more @code{mysqlds}
@@ -15304,7 +14735,8 @@ If your are using the Perl @code{DBD::mysql} module you can read the options
from the MySQL option files. @xref{Option files}.
@example
-$dsn = "DBI:mysql:test;mysql_read_default_group=client;mysql_read_default_file=/usr/local/mysql/data/my.cnf"
+$dsn = "DBI:mysql:test;mysql_read_default_group=client;
+ mysql_read_default_file=/usr/local/mysql/data/my.cnf"
$dbh = DBI->connect($dsn, $user, $password);
@end example
@@ -15342,6 +14774,7 @@ system. This section describes how it works.
* General security:: General security
* Security:: How to make MySQL secure against crackers
* Privileges options:: Startup Options for @code{mysqld} Concerning Security
+* LOAD DATA LOCAL::
* What Privileges:: What the privilege system does
* Privileges:: How the privilege system works
* Privileges provided:: Privileges provided by MySQL
@@ -15375,11 +14808,12 @@ When running MySQL, follow these guidelines whenever possible:
@itemize @bullet
@item
-DON'T EVER GIVE ANYONE (EXCEPT THE MySQL ROOT USER) ACCESS TO THE
-@code{user} TABLE IN THE @code{mysql} DATABASE! The encrypted password
-is the real password in MySQL. If you know the password listed in
-the @code{user} table for a given user, you can easily log in as that
-user if you have access to the host listed for that account.
+@strong{Do not ever give anyone (except the mysql root user) access to the
+@code{user} table in the @code{mysql} database!} This is critical.
+@strong{The encrypted password is the real password in MySQL.}
+Anyone who knows the password which is listed in the @code{user} table
+and has access to the host listed for the account @strong{can easily log
+in as that user}.
@item
Learn the MySQL access privilege system. The @code{GRANT} and
@@ -15418,7 +14852,7 @@ for someone who does not know it.
@item
Invest in a firewall. This protects you from at least 50% of all types of
exploits in any software. Put MySQL behind the firewall or in
-a demilitarized zone (DMZ).
+a demilitarised zone (DMZ).
Checklist:
@itemize @minus
@@ -15519,7 +14953,7 @@ Users of Java JDBC:
Do not transmit plain (unencrypted) data over the Internet. These data are
accessible to everyone who has the time and ability to intercept it and use
it for their own purposes. Instead, use an encrypted protocol such as SSL or
-SSH. MySQL supports internal SSL connections as of Version 3.23.9.
+SSH. MySQL supports internal SSL connections as of Version 4.0.0.
SSH port-forwarding can be used to create an encrypted (and compressed)
tunnel for the communication.
@item
@@ -15532,7 +14966,7 @@ shell> tcpdump -l -i eth0 -w - src or dst port 3306 | strings
@end example
(This works under Linux and should work with small modifications under
-other systems). Warning: If you do not see data this doesn't always
+other systems.) Warning: If you do not see data this doesn't always
actually mean that it is encrypted. If you need high security, you should
consult with a security expert.
@end itemize
@@ -15556,12 +14990,15 @@ communication.
All other information is transferred as text that can be read by anyone
who is able to watch the connection. If you are concerned about this,
you can use the compressed protocol (in MySQL Version 3.22 and above)
-to make things much harder. To make things even more secure you should use
-@code{ssh}. You can find an open source @code{ssh} client at
-@uref{http://www.openssh.org}, and a commercial @code{ssh} client at
-@uref{http://www.ssh.com}. With this, you can get an encrypted TCP/IP
+to make things much harder. To make things even more secure you should use
+@code{ssh}. You can find an Open Source @code{ssh} client at
+@uref{http://www.openssh.org/}, and a commercial @code{ssh} client at
+@uref{http://www.ssh.com/}. With this, you can get an encrypted TCP/IP
connection between a MySQL server and a MySQL client.
+If you are using MySQL 4.0, you can also use internal openssl support.
+@xref{Secure connections}.
+
To make a MySQL system secure, you should strongly consider the
following suggestions:
@@ -15578,7 +15015,7 @@ this:
@example
shell> mysql -u root mysql
mysql> UPDATE user SET Password=PASSWORD('new_password')
- WHERE user='root';
+ -> WHERE user='root';
mysql> FLUSH PRIVILEGES;
@end example
@@ -15606,12 +15043,11 @@ user=mysql
This will cause the server to start as the designated user whether you
start it manually or by using @code{safe_mysqld} or @code{mysql.server}.
-For more details, see @ref{Changing MySQL user, , Changing MySQL
-user}.
+For more details, see @ref{Changing MySQL user}.
@item
-Don't support symlinks to tables (This can be disabled with the
-@code{--skip-symlink} option. This is especially important if you run
+Don't support symlinks to tables (this can be disabled with the
+@code{--skip-symlink} option). This is especially important if you run
@code{mysqld} as root as anyone that has write access to the mysqld data
directories could then delete any file in the system!
@xref{Symbolic links to tables}.
@@ -15657,13 +15093,16 @@ can do this by setting the @code{max_user_connections} variable in
@end itemize
-
-@node Privileges options, What Privileges, Security, Privilege system
+@node Privileges options, LOAD DATA LOCAL, Security, Privilege system
@subsection Startup Options for @code{mysqld} Concerning Security
The following @code{mysqld} options affect security:
@table @code
+@item --local-infile[=(0|1)]
+If one uses @code{--local-infile=0} then one can't use @code{LOAD DATA LOCAL
+INFILE}.
+
@item --safe-show-database
With this option,
@code{SHOW DATABASES} returns only those databases for which the user has
@@ -15677,7 +15116,7 @@ new users with those privileges that the user has right to grant, you should
give the user the following privilege:
@example
-GRANT INSERT(user) on mysql.user to 'user'@'hostname';
+GRANT INSERT(user) on mysql.user to 'user'@@'hostname';
@end example
This will ensure that the user can't change any privilege columns directly,
@@ -15705,8 +15144,50 @@ With this option, the
@end table
+@node LOAD DATA LOCAL, What Privileges, Privileges options, Privilege system
+@subsection Security issues with LOAD DATA LOCAL
+
+In MySQL 3.23.49 and MySQL 4.0.2 we added some new options to deal with
+possible security issues when it comes to @code{LOAD DATA LOCAL}.
+
+There are two possible problems with supporting this command:
+
+As the reading of the file is initiated from the server, one could
+theoretically create a patched MySQL server that could read any file one
+the client machine, for which the current user have read privilege, when
+the client issues a query against the table.
+
+In a web environment where the clients are connection from a web
+server, a user could use @code{LOAD DATA LOCAL} to read any files for
+which the web server process have read access to (assuming a user could
+run any command against the SQL server).
+
+There are two separte fixes for this:
-@node What Privileges, Privileges, Privileges options, Privilege system
+If one doesn't configure with @code{--enable-local-infile} then
+@code{LOAD DATA LOCAL} will be disabled by all clients, unless one
+calls @code{mysql_options(... MYSQL_OPT_LOCAL_INFILE, 0)} in the client.
+@xref{mysql_options, , @code{mysql_options()}}.
+
+One can enable this command in the @code{mysql} command line client by
+specify the option @code{--local-infile[=1]} and disable it with
+@code{--local-infile=0}.
+
+By default all MySQL clients and libraries are compiled with
+@code{--enable-local-infile}, to be compatible with MySQL 3.23.48 and
+before.
+
+One can disable all @code{LOAD DATA LOCAL} commands in the MySQL server
+by starting @code{mysqld} with @code{--local-infile=0}.
+
+In the case of that @code{LOAD DATA INFILE} is disabled in the server or
+the client, you will get the error message (1148):
+
+@example
+The used command is not allowed with this MySQL version
+@end example
+
+@node What Privileges, Privileges, LOAD DATA LOCAL, Privilege system
@subsection What the Privilege System Does
@cindex system, privilege
@@ -15737,12 +15218,12 @@ privileges according to your identity and @strong{what you want to do}.
MySQL considers both your hostname and user name in identifying you
because there is little reason to assume that a given user name belongs to
the same person everywhere on the Internet. For example, the user
-@code{bill} who connects from @code{whitehouse.gov} need not be the same
-person as the user @code{bill} who connects from @code{microsoft.com}.
+@code{joe} who connects from @code{office.com} need not be the same
+person as the user @code{joe} who connects from @code{elsewhere.com}.
MySQL handles this by allowing you to distinguish users on different
-hosts that happen to have the same name: you can grant @code{bill} one set
-of privileges for connections from @code{whitehouse.gov}, and a different set
-of privileges for connections from @code{microsoft.com}.
+hosts that happen to have the same name: you can grant @code{joe} one set
+of privileges for connections from @code{office.com}, and a different set
+of privileges for connections from @code{elsewhere.com}.
MySQL access control involves two stages:
@@ -15763,26 +15244,26 @@ The server uses the @code{user}, @code{db}, and @code{host} tables in the
grant tables are shown below:
@multitable @columnfractions .2 .25 .25 .25
-@item @strong{Table name} @tab @code{user} @tab @code{db} @tab @code{host}
+@item @strong{Table name} @tab @code{user} @tab @code{db} @tab @code{host}
-@item @strong{Scope fields} @tab @code{Host} @tab @code{Host} @tab @code{Host}
-@item @tab @code{User} @tab @code{Db} @tab @code{Db}
-@item @tab @code{Password} @tab @code{User} @tab
+@item @strong{Scope fields} @tab @code{Host} @tab @code{Host} @tab @code{Host}
+@item @tab @code{User} @tab @code{Db} @tab @code{Db}
+@item @tab @code{Password} @tab @code{User} @tab
@item @strong{Privilege fields} @tab @code{Select_priv} @tab @code{Select_priv} @tab @code{Select_priv}
-@item @tab @code{Insert_priv} @tab @code{Insert_priv} @tab @code{Insert_priv}
-@item @tab @code{Update_priv} @tab @code{Update_priv} @tab @code{Update_priv}
-@item @tab @code{Delete_priv} @tab @code{Delete_priv} @tab @code{Delete_priv}
-@item @tab @code{Index_priv} @tab @code{Index_priv} @tab @code{Index_priv}
-@item @tab @code{Alter_priv} @tab @code{Alter_priv} @tab @code{Alter_priv}
-@item @tab @code{Create_priv} @tab @code{Create_priv} @tab @code{Create_priv}
-@item @tab @code{Drop_priv} @tab @code{Drop_priv} @tab @code{Drop_priv}
-@item @tab @code{Grant_priv} @tab @code{Grant_priv} @tab @code{Grant_priv}
-@item @tab @code{References_priv} @tab @tab
-@item @tab @code{Reload_priv} @tab @tab
-@item @tab @code{Shutdown_priv} @tab @tab
-@item @tab @code{Process_priv} @tab @tab
-@item @tab @code{File_priv} @tab @tab
+@item @tab @code{Insert_priv} @tab @code{Insert_priv} @tab @code{Insert_priv}
+@item @tab @code{Update_priv} @tab @code{Update_priv} @tab @code{Update_priv}
+@item @tab @code{Delete_priv} @tab @code{Delete_priv} @tab @code{Delete_priv}
+@item @tab @code{Index_priv} @tab @code{Index_priv} @tab @code{Index_priv}
+@item @tab @code{Alter_priv} @tab @code{Alter_priv} @tab @code{Alter_priv}
+@item @tab @code{Create_priv} @tab @code{Create_priv} @tab @code{Create_priv}
+@item @tab @code{Drop_priv} @tab @code{Drop_priv} @tab @code{Drop_priv}
+@item @tab @code{Grant_priv} @tab @code{Grant_priv} @tab @code{Grant_priv}
+@item @tab @code{References_priv} @tab @tab
+@item @tab @code{Reload_priv} @tab @tab
+@item @tab @code{Shutdown_priv} @tab @tab
+@item @tab @code{Process_priv} @tab @tab
+@item @tab @code{File_priv} @tab @tab
@end multitable
For the second stage of access control (request verification), the server
@@ -15836,14 +15317,14 @@ Scope fields are strings, declared as shown below; the default value for
each is the empty string:
@multitable @columnfractions .15 .15 .7
-@item @strong{Field name} @tab @strong{Type}
-@item @code{Host} @tab @code{CHAR(60)}
-@item @code{User} @tab @code{CHAR(16)}
-@item @code{Password} @tab @code{CHAR(16)}
-@item @code{Db} @tab @code{CHAR(64)} @tab (@code{CHAR(60)} for the
+@item @strong{Field name} @tab @strong{Type} @tab @strong{Notes}
+@item @code{Host} @tab @code{CHAR(60)} @tab
+@item @code{User} @tab @code{CHAR(16)} @tab
+@item @code{Password} @tab @code{CHAR(16)} @tab
+@item @code{Db} @tab @code{CHAR(64)} @tab (@code{CHAR(60)} for the
@code{tables_priv} and @code{columns_priv} tables)
-@item @code{Table_name} @tab @code{CHAR(60)}
-@item @code{Column_name} @tab @code{CHAR(60)}
+@item @code{Table_name} @tab @code{CHAR(60)} @tab
+@item @code{Column_name} @tab @code{CHAR(60)} @tab
@end multitable
In the @code{user}, @code{db} and @code{host} tables,
@@ -15854,13 +15335,18 @@ In the @code{tables_priv} and @code{columns_priv} tables, the privilege
fields are declared as @code{SET} fields:
@multitable @columnfractions .2 .2 .6
-@item @strong{Table name} @tab @strong{Field name} @tab @strong{Possible set elements}
-@item @code{tables_priv} @tab @code{Table_priv} @tab @code{'Select', 'Insert',
-'Update', 'Delete', 'Create', 'Drop', 'Grant', 'References', 'Index', 'Alter'}
-@item @code{tables_priv} @tab @code{Column_priv} @tab @code{'Select', 'Insert',
-'Update', 'References'}
-@item @code{columns_priv} @tab @code{Column_priv} @tab @code{'Select', 'Insert',
-'Update', 'References'}
+@item @strong{Table name}
+ @tab @strong{Field name}
+ @tab @strong{Possible set elements}
+@item @code{tables_priv}
+ @tab @code{Table_priv}
+ @tab @code{'Select', 'Insert', 'Update', 'Delete', 'Create', 'Drop', 'Grant', 'References', 'Index', 'Alter'}
+@item @code{tables_priv}
+ @tab @code{Column_priv}
+ @tab @code{'Select', 'Insert', 'Update', 'References'}
+@item @code{columns_priv}
+ @tab @code{Column_priv}
+ @tab @code{'Select', 'Insert', 'Update', 'References'}
@end multitable
Briefly, the server uses the grant tables like this:
@@ -15916,7 +15402,7 @@ starts up. Changes to the grant tables take effect as indicated in
When you modify the contents of the grant tables, it is a good idea to make
sure that your changes set up privileges the way you want. For help in
diagnosing problems, see @ref{Access denied}. For advice on security issues,
-@pxref{Security}.
+see @ref{Security}.
A useful
diagnostic tool is the @code{mysqlaccess} script, which Yves Carlier has
@@ -16057,7 +15543,7 @@ currently executing queries, including queries that set or change passwords.
Privileges on the @code{mysql} database can be used to change passwords
and other access privilege information. (Passwords are stored
encrypted, so a malicious user cannot simply read them to know the plain
-text password). If they can access the @code{mysql.user} password
+text password.) If they can access the @code{mysql.user} password
column, they can use it to log into the MySQL server
for the given user. (With sufficient privileges, the same user can
replace a password with a different one.)
@@ -16100,7 +15586,7 @@ Alternate forms of the @code{-h}, @code{-u}, and @code{-p} options are
@code{--password=your_pass}. Note that there is @emph{no space} between
@code{-p} or @code{--password=} and the password following it.
-@strong{NOTE:} Specifying a password on the command line is not secure!
+@strong{Note:} Specifying a password on the command line is not secure!
Any user on your system may then find out your password by typing a command
like: @code{ps auxww}. @xref{Option files}.
@@ -16215,8 +15701,8 @@ You can find more information about this in the next chapter.
@cindex netmask notation, in @code{mysql.user} table
@item
-As of MySQL Version 3.23, for @code{Host} values specified as
-IP numbers, you can specify a netmask indicating how many address bits to
+As of MySQL Version 3.23, for @code{Host} values specified as
+IP numbers, you can specify a netmask indicating how many address bits to
use for the network number. For example:
@example
@@ -16253,7 +15739,7 @@ MySQL does not store passwords in plaintext form for anyone to
see. Rather, the password supplied by a user who is attempting to
connect is encrypted (using the @code{PASSWORD()} function). The
encrypted password is then used when the client/server is checking if
-the password is correct (This is done without the encrypted password
+the password is correct. (This is done without the encrypted password
ever traveling over the connection.) Note that from MySQL's
point of view the encrypted password is the REAL password, so you should
not give anyone access to it! In particular, don't give normal users
@@ -16517,7 +16003,7 @@ tables and adds those to the user's privileges. Access is allowed or denied
based on the result.
Expressed in boolean terms, the preceding description of how a user's
-privileges are calculated may be summarized like this:
+privileges are calculated may be summarised like this:
@example
global privileges
@@ -16736,7 +16222,7 @@ hostname is an IP, even if you try to connect with a hostname:
@example
shell> mysqladmin -u root -pxxxx -h some-hostname ver
-Access denied for user: 'root@' (Using password: YES)
+Access denied for user: 'root@@' (Using password: YES)
@end example
This means that MySQL got some error when trying to resolve the
@@ -16859,7 +16345,7 @@ connect to the server with @code{mysql -u user_name db_name} or @code{mysql
@code{mysql} client, there is a problem with your program and not with the
access privileges. (Note that there is no space between @code{-p} and the
password; you can also use the @code{--password=your_pass} syntax to specify
-the password. If you use the @code{-p} option alone, MySQL will
+the password. If you use the @code{-p} option alone, MySQL will
prompt you for the password.)
@item
@@ -16893,6 +16379,8 @@ to restart @code{mysqld} with @code{--skip-grant-tables} to run
@node User Account Management, Disaster Prevention, Privilege system, MySQL Database Administration
@section MySQL User Account Management
+@c FIX: add section intro
+
@menu
* GRANT:: @code{GRANT} and @code{REVOKE} Syntax
* User names:: MySQL User Names and Passwords
@@ -16901,6 +16389,7 @@ to restart @code{mysqld} with @code{--skip-grant-tables} to run
* Adding users:: Adding New Users to MySQL
* Passwords:: Setting Up Passwords
* Password security:: Keeping Your Password Secure
+* Secure connections:: Using Secure Connections
@end menu
@@ -16919,9 +16408,14 @@ to restart @code{mysqld} with @code{--skip-grant-tables} to run
@example
GRANT priv_type [(column_list)] [, priv_type [(column_list)] ...]
ON @{tbl_name | * | *.* | db_name.*@}
- TO user_name [IDENTIFIED BY 'password']
+ TO user_name [IDENTIFIED BY [PASSWORD] 'password']
[, user_name [IDENTIFIED BY 'password'] ...]
- [WITH GRANT OPTION]
+ [REQUIRE
+ [@{SSL| X509@}]
+ [CIPHER cipher [AND]]
+ [ISSUER issuer [AND]]
+ [SUBJECT subject]]
+ [WITH [GRANT OPTION | MAX_QUERIES_PER_HOUR=#]]
REVOKE priv_type [(column_list)] [, priv_type [(column_list)] ...]
ON @{tbl_name | * | *.* | db_name.*@}
@@ -16989,7 +16483,7 @@ you use a @code{column_list} clause) are @code{SELECT}, @code{INSERT}, and
You can set global privileges by using @code{ON *.*} syntax. You can set
database privileges by using @code{ON db_name.*} syntax. If you specify
@code{ON *} and you have a current database, you will set the privileges for
-that database. (@strong{WARNING:} If you specify @code{ON *} and you
+that database. (@strong{Warning:} If you specify @code{ON *} and you
@emph{don't} have a current database, you will affect the global privileges!)
In order to accommodate granting rights to users from arbitrary hosts,
@@ -17005,14 +16499,19 @@ You can specify wild cards in the hostname. For example,
for any host in the @code{144.155.166} class C subnet.
The simple form @code{user} is a synonym for @code{user@@"%"}.
-@strong{NOTE:} If you allow anonymous users to connect to the MySQL
-server (which is the default), you should also add all local users as
-@code{user@@localhost} because otherwise the anonymous user entry for the
-local host in the @code{mysql.user} table will be used when the user tries to
-log into the MySQL server from the local machine! Anonymous users
-are defined by inserting entries with @code{User=''} into the
-@code{mysql.user} table. You can verify if this applies to you by executing
-this query:
+
+MySQL doesn't support wildcards in user names. Anonymous users are
+defined by inserting entries with @code{User=''} into the
+@code{mysql.user} table or creating an user with an empty name with the
+@code{GRANT} command.
+
+@strong{Note:} If you allow anonymous users to connect to the MySQL
+server, you should also grant privileges to all local users as
+@code{user@@localhost} because otherwise the anonymous user entry for
+the local host in the @code{mysql.user} table will be used when the user
+tries to log into the MySQL server from the local machine!
+
+You can verify if this applies to you by executing this query:
@example
mysql> SELECT Host,User FROM mysql.user WHERE User='';
@@ -17055,7 +16554,12 @@ password will be set to the password specified by the @code{IDENTIFIED BY}
clause, if one is given. If the user already had a password, it is replaced
by the new one.
-@strong{WARNING:} If you create a new user but do not specify an
+If you don't want to send the password in clear text you can use the
+@code{PASSWORD} option followed by a scrambled password from SQL
+function @code{PASSWORD()} or the C API function
+@code{make_scrambled_password(char *to, const char *password)}.
+
+@strong{Warning:} If you create a new user but do not specify an
@code{IDENTIFIED BY} clause, the user has no password. This is insecure.
Passwords can also be set with the @code{SET PASSWORD} command.
@@ -17074,6 +16578,12 @@ to other users any privileges the user has at the specified privilege level.
You should be careful to whom you give the @strong{grant} privilege, as two
users with different privileges may be able to join privileges!
+@code{MAX_QUERIES_PER_HOUR=#} limits the number of queries the user can
+do during one hour. If @code{#} is 0, then this means that there is no
+limit of the number of queries. This works by MySQL resetting a user
+specific query counter to 0, after it has gone more than one hour
+since the counter started incrementing.
+
You cannot grant another user a privilege you don't have yourself;
the @strong{grant} privilege allows you to give away only those privileges
you possess.
@@ -17143,6 +16653,7 @@ dropped only with explicit @code{REVOKE} commands or by manipulating the
MySQL grant tables.
@end itemize
+For a description of using @code{REQUIRE}, see @ref{Secure connections}.
@node User names, Privilege changes, GRANT, User Account Management
@subsection MySQL User Names and Passwords
@@ -17207,7 +16718,7 @@ or the short form:
mysql -u monty -p database_name
@end example
-Note that in the last example the password is @strong{NOT} 'database_name'.
+Note that in the last example the password is @strong{not} 'database_name'.
If you want to use the @code{-p} option to supply a password you should do so
like this:
@@ -17270,7 +16781,7 @@ After installing MySQL, you set up the initial access privileges by
running @code{scripts/mysql_install_db}.
@xref{Quick install}.
The @code{mysql_install_db} script starts up the @code{mysqld}
-server, then initializes the grant tables to contain the following set
+server, then initialises the grant tables to contain the following set
of privileges:
@itemize @bullet
@@ -17278,7 +16789,7 @@ of privileges:
The MySQL @code{root} user is created as a superuser who can do
anything. Connections must be made from the local host.
-@strong{NOTE:}
+@strong{Note:}
The initial @code{root} password is empty, so anyone can connect as @code{root}
@emph{without a password} and be granted all privileges.
@@ -17294,7 +16805,7 @@ Other privileges are denied. For example, normal users can't use
@code{mysqladmin shutdown} or @code{mysqladmin processlist}.
@end itemize
-@strong{NOTE:} The default privileges are different for Windows.
+@strong{Note:} The default privileges are different for Windows.
@xref{Windows running}.
Because your installation is initially wide open, one of the first things you
@@ -17304,17 +16815,17 @@ password using the @code{PASSWORD()} function):
@example
shell> mysql -u root mysql
-mysql> UPDATE user SET Password=PASSWORD('new_password')
- WHERE user='root';
-mysql> FLUSH PRIVILEGES;
+mysql> SET PASSWORD FOR root@@localhost=PASSWORD('new_password');
@end example
-You can, in MySQL Version 3.22 and above, use the @code{SET PASSWORD}
-statement:
+If you know what you are doing, you can also directly manipulate the
+privilege tables:
@example
shell> mysql -u root mysql
-mysql> SET PASSWORD FOR root=PASSWORD('new_password');
+mysql> UPDATE user SET Password=PASSWORD('new_password')
+ -> WHERE user='root';
+mysql> FLUSH PRIVILEGES;
@end example
Another way to set the password is by using the @code{mysqladmin} command:
@@ -17355,8 +16866,8 @@ the database directory, which is listed when you run @code{mysqld
--help}.) Then run the @code{mysql_install_db} script, possibly after
editing it first to have the privileges you want.
-@strong{NOTE:} For MySQL versions older than Version 3.22.10,
-you should NOT delete the @file{.frm} files. If you accidentally do this,
+@strong{Note:} For MySQL versions older than Version 3.22.10,
+you should not delete the @file{.frm} files. If you accidentally do this,
you should copy them back from your MySQL distribution before
running @code{mysql_install_db}.
@@ -17376,8 +16887,8 @@ or by manipulating the MySQL grant tables directly. The
preferred method is to use @code{GRANT} statements, because they are
more concise and less error-prone. @xref{GRANT}.
-There is also a lot of contributed programs like @code{phpmyadmin} that
-can be used to create and administrate users. @xref{Contrib}.
+There are also a lot of contributed programs like @code{phpmyadmin}
+that can be used to create and administrate users. @xref{Portals}.
The examples below show how to use the @code{mysql} client to set up new
users. These examples assume that privileges are set up according to the
@@ -17394,9 +16905,9 @@ You can add new users by issuing @code{GRANT} statements:
@example
shell> mysql --user=root mysql
mysql> GRANT ALL PRIVILEGES ON *.* TO monty@@localhost
- IDENTIFIED BY 'some_pass' WITH GRANT OPTION;
+ -> IDENTIFIED BY 'some_pass' WITH GRANT OPTION;
mysql> GRANT ALL PRIVILEGES ON *.* TO monty@@"%"
- IDENTIFIED BY 'some_pass' WITH GRANT OPTION;
+ -> IDENTIFIED BY 'some_pass' WITH GRANT OPTION;
mysql> GRANT RELOAD,PROCESS ON *.* TO admin@@localhost;
mysql> GRANT USAGE ON *.* TO dummy@@localhost;
@end example
@@ -17438,13 +16949,13 @@ tables:
@example
shell> mysql --user=root mysql
mysql> INSERT INTO user VALUES('localhost','monty',PASSWORD('some_pass'),
- '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','Y','Y');
mysql> INSERT INTO user VALUES('%','monty',PASSWORD('some_pass'),
- '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','Y','Y');
mysql> INSERT INTO user SET Host='localhost',User='admin',
- Reload_priv='Y', Process_priv='Y';
+ -> Reload_priv='Y', Process_priv='Y';
mysql> INSERT INTO user (Host,User,Password)
- VALUES('localhost','dummy','');
+ -> VALUES('localhost','dummy','');
mysql> FLUSH PRIVILEGES;
@end example
@@ -17475,17 +16986,17 @@ commands:
@example
shell> mysql --user=root mysql
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
- ON bankaccount.*
- TO custom@@localhost
- IDENTIFIED BY 'stupid';
+ -> ON bankaccount.*
+ -> TO custom@@localhost
+ -> IDENTIFIED BY 'stupid';
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
- ON expenses.*
- TO custom@@whitehouse.gov
- IDENTIFIED BY 'stupid';
+ -> ON expenses.*
+ -> TO custom@@whitehouse.gov
+ -> IDENTIFIED BY 'stupid';
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
- ON customer.*
- TO custom@@'%'
- IDENTIFIED BY 'stupid';
+ -> ON customer.*
+ -> TO custom@@'%'
+ -> IDENTIFIED BY 'stupid';
@end example
The reason that we do to grant statements for the user 'custom' is that
@@ -17499,25 +17010,25 @@ run these commands (note the @code{FLUSH PRIVILEGES} at the end):
@example
shell> mysql --user=root mysql
mysql> INSERT INTO user (Host,User,Password)
- VALUES('localhost','custom',PASSWORD('stupid'));
+ -> VALUES('localhost','custom',PASSWORD('stupid'));
mysql> INSERT INTO user (Host,User,Password)
- VALUES('server.domain','custom',PASSWORD('stupid'));
+ -> VALUES('server.domain','custom',PASSWORD('stupid'));
mysql> INSERT INTO user (Host,User,Password)
- VALUES('whitehouse.gov','custom',PASSWORD('stupid'));
+ -> VALUES('whitehouse.gov','custom',PASSWORD('stupid'));
mysql> INSERT INTO db
- (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
- Create_priv,Drop_priv)
- VALUES
- ('localhost','bankaccount','custom','Y','Y','Y','Y','Y','Y');
+ -> (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
+ -> Create_priv,Drop_priv)
+ -> VALUES
+ -> ('localhost','bankaccount','custom','Y','Y','Y','Y','Y','Y');
mysql> INSERT INTO db
- (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
- Create_priv,Drop_priv)
- VALUES
- ('whitehouse.gov','expenses','custom','Y','Y','Y','Y','Y','Y');
+ -> (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
+ -> Create_priv,Drop_priv)
+ -> VALUES
+ -> ('whitehouse.gov','expenses','custom','Y','Y','Y','Y','Y','Y');
mysql> INSERT INTO db
- (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
- Create_priv,Drop_priv)
- VALUES('%','customer','custom','Y','Y','Y','Y','Y','Y');
+ -> (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
+ -> Create_priv,Drop_priv)
+ -> VALUES('%','customer','custom','Y','Y','Y','Y','Y','Y');
mysql> FLUSH PRIVILEGES;
@end example
@@ -17536,24 +17047,23 @@ domain, you can issue a @code{GRANT} statement like the following:
@example
mysql> GRANT ...
- ON *.*
- TO myusername@@"%.mydomainname.com"
- IDENTIFIED BY 'mypassword';
+ -> ON *.*
+ -> TO myusername@@"%.mydomainname.com"
+ -> IDENTIFIED BY 'mypassword';
@end example
To do the same thing by modifying the grant tables directly, do this:
@example
mysql> INSERT INTO user VALUES ('%.mydomainname.com', 'myusername',
- PASSWORD('mypassword'),...);
+ -> PASSWORD('mypassword'),...);
mysql> FLUSH PRIVILEGES;
@end example
You can also use @code{xmysqladmin}, @code{mysql_webadmin}, and even
@code{xmysql} to insert, change, and update values in the grant tables.
-You can find these utilities in the
-@uref{http://www.mysql.com/Downloads/Contrib/,Contrib directory of the MySQL
-Website}.
+You can find these utilities in the Contrib directory of the
+MySQL web site (@uref{http://www.mysql.com/Downloads/Contrib/}).
@node Passwords, Password security, Adding users, User Account Management
@@ -17578,7 +17088,7 @@ passwords like this:
@example
shell> mysql -u root mysql
mysql> INSERT INTO user (Host,User,Password)
- VALUES('%','jeffrey','biscuit');
+ -> VALUES('%','jeffrey','biscuit');
mysql> FLUSH PRIVILEGES;
@end example
@@ -17605,7 +17115,7 @@ instead:
@example
mysql> INSERT INTO user (Host,User,Password)
- VALUES('%','jeffrey',PASSWORD('biscuit'));
+ -> VALUES('%','jeffrey',PASSWORD('biscuit'));
@end example
You must also use the @code{PASSWORD()} function when you use @code{SET
@@ -17637,7 +17147,7 @@ your Unix password and your MySQL password are the same, that
Unix password file. @xref{User names}.
-@node Password security, , Passwords, User Account Management
+@node Password security, Secure connections, Passwords, User Account Management
@subsection Keeping Your Password Secure
It is inadvisable to specify your password in a way that exposes it to
@@ -17658,7 +17168,7 @@ Use a @code{-pyour_pass} or @code{--password=your_pass} option on the command
line. This is convenient but insecure, because your password becomes visible
to system status programs (such as @code{ps}) that may be invoked by other
users to display command lines. (MySQL clients typically overwrite
-the command-line argument with zeroes during their initialization sequence,
+the command-line argument with zeroes during their initialisation sequence,
but there is still a brief interval during which the value is visible.)
@item
@@ -17713,10 +17223,187 @@ All in all, the safest methods are to have the client program prompt for the
password or to specify the password in a properly protected @file{.my.cnf}
file.
+@node Secure connections, , Password security, User Account Management
+@subsection Using Secure Connections
+
+@cindex openssl
+@cindex SSL and X509 Basics
+
+@menu
+* Secure basics:: Basics
+* Secure requirements:: Requirements
+* Secure GRANT:: GRANT OPTIONS
+@end menu
+
+@node Secure basics, Secure requirements, Secure connections, Secure connections
+@subsubsection Basics
+
+MySQL has support for SSL encrypted connections. To understand how MySQL
+uses SSL, we need to explain some basics about SSL and X509. People who
+are already aware of it can skip this part.
+
+By default, MySQL uses unencrypted connections between client and
+server. This means that someone could watch all your traffic and look at
+the data being sent/received. Actually, they could even change the data
+while it is in transit between client and server. Sometimes you need to
+move really secret data over public networks and in such a case using an
+unencrypted connection is unacceptable.
+
+SSL is a protocol which uses different encryption algorithms to ensure
+that data which comes from public network can be trusted. It has
+mechanisms to detect any change, loss or replay of data. SSL also
+incorpores algorithms to recognise and provide identity verification
+using the X509 standard.
+
+@cindex What is encryption
+Encryption is the way to make any kind of data unreadable. In fact,
+today's practice requires many additional security elements from
+encryption algorithms. They should resist many kind of known attacks
+like just messing with order of encrypted messages or replaying data
+twice.
+
+@cindex What is X509/Certificate?
+X509 is a standard that makes it possible to identify someone in the
+Internet. It is most commonly used in e-commerce applications. In basic
+terms, there should be some company called "Certificate Authority" which
+assigns electronic certificates to anyone who needs them. Certificates
+rely on asymmetric encryption algorithms which have two encryption keys
+- public and secret. A certificate owner can prove his identity by
+showing his certificate to other party. A certificate consists of his
+owner's public key. Any data encrypted with this public key can only be
+decrypted using the corresponding secret key, which is held by the owner
+of the certificate.
+
+MySQL doesn't use encrypted on connections by default, because this
+would make the client/server protocol much slower. Any kind of
+additional functionality requires computer to do additional work and
+encrypting data is CPU-intensive operation require time and can delay
+MySQL main tasks. By default MySQL is tuned to be fast as possible.
+
+If you need more information about SSL/X509/encryption, you should use
+your favourite internet search engine and search for keywords you are
+interested in.
+
+@node Secure requirements, Secure GRANT, Secure basics, Secure connections
+@subsubsection Requirements
+
+To get secure connections to work with MySQL you must do the following:
+
+@enumerate
+@item
+Install the openssl library. We have tested MySQL with openssl 0.9.6.
+@uref{http://www.openssl.org/}.
+@item
+Configure MySQL with @code{--with-vio --with-openssl}.
+@item
+If you are using an old MySQL installation, you have to update your
+@code{mysql.user} table with some new columns. You can do this by
+running the @code{mysql_fix_privilege_tables.sh} script.
+@item
+You can check if a running mysqld server supports @code{openssl} by
+examining if @code{SHOW VARIABLES LIKE 'have_openssl'} returns @code{YES}.
+@end enumerate
+
+
+@node Secure GRANT, , Secure requirements, Secure connections
+@subsubsection GRANT options
+
+@cindex SSL related options
+@findex REQUIRE GRANT option
+@findex GRANT statemenet
+
+MySQL can check X509 certificate attributes in addition to the
+normal username/password scheme. All the usual options are still
+required (username, password, IP address mask, database/table name).
+
+There are different possibilities to limit connections:
+
+@itemize @bullet
+@item
+Without any SSL/X509 options, all kind of encrypted/unencrypted
+connections are allowed if username and password are valid.
+
+@item
+@code{REQUIRE SSL} option limits the server to allow only SSL
+encrypted connections. Note that this option can be omitted
+if there are any ACL records which allow non-SSL connections.
+
+@example
+GRANT ALL PRIVILEGES ON test.* TO root@@localhost
+IDENTIFIED BY "goodsecret" REQUIRE SSL
+@end example
+
+@item
+@code{REQUIRE X509} means that client should have valid certificate
+but we do not care about the exact certificate, issuer or subject.
+The only restriction is that it should be possible to verify its
+signature with one of the CA certificates.
+
+@example
+GRANT ALL PRIVILEGES ON test.* TO root@@localhost
+IDENTIFIED BY "goodsecret" REQUIRE X509
+@end example
+
+@item
+@code{REQUIRE ISSUER issuer} makes connection more restrictive: now
+client must present a valid X509 certificate issued by CA "issuer".
+Using X509 certificates always implies encryption, so the option "SSL"
+is not neccessary anymore.
+
+@example
+GRANT ALL PRIVILEGES ON test.* TO root@@localhost
+IDENTIFIED BY "goodsecret"
+REQUIRE ISSUER "C=FI, ST=Some-State, L=Helsinki,
+O=MySQL Finland AB, CN=Tonu Samuel/Email=tonu@@mysql.com"
+@end example
+
+@item
+@code{REQUIRE SUBJECT subject} requires clients to have valid X509
+certificate with subject "subject" on it. If client have valid
+certificate but having different "subject" then the connection is
+still not allowed.
+
+@example
+GRANT ALL PRIVILEGES ON test.* TO root@@localhost
+IDENTIFIED BY "goodsecret"
+REQUIRE SUBJECT "C=EE, ST=Some-State, L=Tallinn,
+O=MySQL demo client certificate, CN=Tonu Samuel/Email=tonu@@mysql.com"
+@end example
+
+@item
+@code{REQUIRE CIPHER cipher} is needed to assure enough strong ciphers
+and keylengths will be used. SSL itself can be weak if old algorithms
+with short encryption keys are used. Using this option, we can ask for
+some exact cipher method to allow a connection.
+
+@example
+GRANT ALL PRIVILEGES ON test.* TO root@@localhost
+IDENTIFIED BY "goodsecret"
+REQUIRE CIPHER "EDH-RSA-DES-CBC3-SHA"
+@end example
+
+Also it is allowed to combine these options with each other like this:
+
+@example
+GRANT ALL PRIVILEGES ON test.* TO root@@localhost
+IDENTIFIED BY "goodsecret"
+REQUIRE SUBJECT "C=EE, ST=Some-State, L=Tallinn,
+O=MySQL demo client certificate, CN=Tonu Samuel/Email=tonu@@mysql.com"
+AND ISSUER "C=FI, ST=Some-State, L=Helsinki,
+O=MySQL Finland AB, CN=Tonu Samuel/Email=tonu@@mysql.com"
+AND CIPHER "EDH-RSA-DES-CBC3-SHA"
+@end example
+
+But it is not allowed to use any of options twice. Only different
+options can be mixed.
+@end itemize
+
@node Disaster Prevention, Database Administration, User Account Management, MySQL Database Administration
@section Disaster Prevention and Recovery
+@c FIX: add section intro
+
@menu
* Backup:: Database Backups
* BACKUP TABLE:: @code{BACKUP TABLE} Syntax
@@ -17781,8 +17468,8 @@ you executed @code{mysqldump}.
If you have to restore something, try to recover your tables using
@code{REPAIR TABLE} or @code{myisamchk -r} first. That should work in
99.9% of all cases. If @code{myisamchk} fails, try the following
-procedure: (This will only work if you have started MySQL with
-@code{--log-update}. @xref{Update log}.):
+procedure (this will only work if you have started MySQL with
+@code{--log-update}, @pxref{Update log}):
@enumerate
@item
@@ -17817,7 +17504,7 @@ instead of on the master. @xref{Replication Intro}.
If you are using a Veritas file system, you can do:
@enumerate
-@item
+@item
Execute in a client (perl ?) @code{FLUSH TABLES WITH READ LOCK}
@item
@@ -17850,7 +17537,7 @@ minimum needed to restore it. Currenlty only works for @code{MyISAM}
tables. For @code{MyISAM} table, copies @code{.frm} (definition) and
@code{.MYD} (data) files. The index file can be rebuilt from those two.
-Before using this command, please see @xref{Backup}.
+Before using this command, please see @ref{Backup}.
During the backup, read lock will be held for each table, one at time,
as they are being backed up. If you want to backup several tables as
@@ -17910,7 +17597,7 @@ CHECK TABLE tbl_name[,tbl_name...] [option [option...]]
option = QUICK | FAST | MEDIUM | EXTENDED | CHANGED
@end example
-@code{CHECK TABLE} only works on @code{MyISAM} tables. On
+@code{CHECK TABLE} only works on @code{MyISAM} and @code{InnoDB} tables. On
@code{MyISAM} tables it's the same thing as running @code{myisamchk -m
table_name} on the table.
@@ -17941,12 +17628,12 @@ The different check types stand for the following:
@item @code{QUICK} @tab Don't scan the rows to check for wrong links.
@item @code{FAST} @tab Only check tables which haven't been closed properly.
@item @code{CHANGED} @tab Only check tables which have been changed since last check or haven't been closed properly.
-@item @code{MEDIUM} @tab Scan rows to verify that deleted links are ok. This also calculates a key checksum for the rows and verifies this with a calcualted checksum for the keys.
+@item @code{MEDIUM} @tab Scan rows to verify that deleted links are okay. This also calculates a key checksum for the rows and verifies this with a calcualted checksum for the keys.
@item @code{EXTENDED} @tab Do a full key lookup for all keys for each row. This ensures that the table is 100 % consistent, but will take a long time!
@end multitable
For dynamic sized @code{MyISAM} tables a started check will always
-do a @code{MEDIUM} check. For static size rows we skip the row scan
+do a @code{MEDIUM} check. For static size rows we skip the row scan
for @code{QUICK} and @code{FAST} as the rows are very seldom corrupted.
You can combine check options as in:
@@ -17957,32 +17644,32 @@ CHECK TABLE test_table FAST QUICK;
Which only would do a quick check on the table if it wasn't closed properly.
-@strong{NOTE:} that in some case @code{CHECK TABLE} will change the
+@strong{Note:} that in some case @code{CHECK TABLE} will change the
table! This happens if the table is marked as 'corrupted' or 'not
closed properly' but @code{CHECK TABLE} didn't find any problems in the
-table. In this case @code{CHECK TABLE} will mark the table as ok.
+table. In this case @code{CHECK TABLE} will mark the table as okay.
If a table is corrupted, then it's most likely that the problem is in
the indexes and not in the data part. All of the above check types
checks the indexes throughly and should thus find most errors.
-If you just want to check a table that you assume is ok, you should use
-no check options or the @code{QUICK} option. The later should be used
+If you just want to check a table that you assume is okay, you should use
+no check options or the @code{QUICK} option. The latter should be used
when you are in a hurry and can take the very small risk that
-@code{QUICK} didn't find an error in the data file (In most cases
+@code{QUICK} didn't find an error in the data file. (In most cases
MySQL should find, under normal usage, any error in the data
file. If this happens then the table will be marked as 'corrupted',
-in which case the table can't be used until it's repaired).
+in which case the table can't be used until it's repaired.)
@code{FAST} and @code{CHANGED} are mostly intended to be used from a
script (for example to be executed from cron) if you want to check your
table from time to time. In most cases you @code{FAST} is to be prefered
over @code{CHANGED}. (The only case when it isn't is when you suspect a
-bug you have found a bug in the @code{MyISAM} code.).
+bug you have found a bug in the @code{MyISAM} code.)
@code{EXTENDED} is only to be used after you have run a normal check but
still get strange errors from a table when MySQL tries to
-update a row or find a row by key (this is VERY unlikely to happen if a
+update a row or find a row by key (this is very unlikely if a
normal check has succeeded!).
Some things reported by check table, can't be corrected automatically:
@@ -18067,13 +17754,13 @@ In the following text we will talk about @code{myisamchk}, but everything
also applies to the old @code{isamchk}.
You can use the @code{myisamchk} utility to get information about your
-database tables, check and repair them, or optimize them. The following
+database tables, check and repair them, or optimise them. The following
sections describe how to invoke @code{myisamchk} (including a
description of its options), how to set up a table maintenance schedule,
and how to use @code{myisamchk} to perform its various functions.
You can, in most cases, also use the command @code{OPTIMIZE TABLES} to
-optimize and repair tables, but this is not as fast or reliable (in case
+optimise and repair tables, but this is not as fast or reliable (in case
of real fatal errors) as @code{myisamchk}. On the other hand,
@code{OPTIMIZE TABLE} is easier to use and you don't have to worry about
flushing tables.
@@ -18093,7 +17780,7 @@ make a lot of changes to a table)
* Crash recovery:: Using @code{myisamchk} for Crash Recovery
* Check:: How to Check Tables for Errors
* Repair:: How to Repair Tables
-* Optimization:: Table Optimization
+* Optimisation:: Table Optimisation
@end menu
@@ -18156,8 +17843,11 @@ If you want to check all tables and repair all tables that are corrupted,
you can use the following line:
@example
-myisamchk --silent --force --fast --update-state -O key_buffer=64M -O sort_buffer=64M -O read_buffer=1M -O write_buffer=1M /path/to/datadir/*/*.MYI
-isamchk --silent --force -O key_buffer=64M -O sort_buffer=64M -O read_buffer=1M -O write_buffer=1M /path/to/datadir/*/*.ISM
+myisamchk --silent --force --fast --update-state -O key_buffer=64M \
+ -O sort_buffer=64M -O read_buffer=1M -O write_buffer=1M \
+ /path/to/datadir/*/*.MYI
+isamchk --silent --force -O key_buffer=64M -O sort_buffer=64M \
+ -O read_buffer=1M -O write_buffer=1M /path/to/datadir/*/*.ISM
@end example
The above assumes that you have more than 64 M free.
@@ -18178,14 +17868,6 @@ tables while you are running @code{myisamchk}. In MySQL Version 3.23
the easiest way to avoid this problem is to use @code{CHECK TABLE}
instead of @code{myisamchk} to check tables.
-@menu
-* myisamchk general options:: General Options for @code{myisamchk}
-* myisamchk check options:: Check Options for @code{myisamchk}
-* myisamchk repair options:: Repair Options for myisamchk
-* myisamchk other options:: Other Options for @code{myisamchk}
-@end menu
-
-
@node myisamchk general options, myisamchk check options, myisamchk syntax, Table maintenance
@subsubsection General Options for @code{myisamchk}
@@ -18204,6 +17886,7 @@ Display a help message and exit.
Set the value of a variable. The possible variables and their default values
for myisamchk can be examined with @code{myisamchk --help}:
@multitable @columnfractions .3 .7
+@item @strong{Variable} @tab @strong{Value}
@item key_buffer_size @tab 523264
@item read_buffer_size @tab 262136
@item write_buffer_size @tab 262136
@@ -18224,8 +17907,6 @@ through the key buffer is used in the following cases:
@item
If you use @code{--safe-recover}.
@item
-If you are using a @code{FULLTEXT} index.
-@item
If the temporary files needed to sort the keys would be more than twice
as big as when creating the key file directly. This is often the case
when you have big @code{CHAR}, @code{VARCHAR} or @code{TEXT} keys as the
@@ -18270,7 +17951,7 @@ Check table for errors. This is the default operation if you are not
giving @code{myisamchk} any options that override this.
@item -e or --extend-check
-Check the table VERY thoroughly (which is quite slow if you have many
+Check the table very thoroughly (which is quite slow if you have many
indexes). This option should only be used in extreme cases. Normally,
@code{myisamchk} or @code{myisamchk --medium-check} should, in most
cases, be able to find out if there are any errors in the table.
@@ -18377,8 +18058,8 @@ Other actions that @code{myisamchk} can do, besides repair and check tables:
@table @code
@item -a or --analyze
-Analyze the distribution of keys. This improves join performance by
-enabling the join optimizer to better choose in which order it should
+Analyse the distribution of keys. This improves join performance by
+enabling the join optimiser to better choose in which order it should
join the tables and which keys it should use:
@code{myisamchk --describe --verbose table_name'} or using @code{SHOW KEYS} in
MySQL.
@@ -18390,11 +18071,11 @@ given, then sets the next auto_increment value to the highest used value
for the auto key + 1.
@item -S or --sort-index
Sort the index tree blocks in high-low order.
-This will optimize seeks and will make table scanning by key faster.
+This will optimise seeks and will make table scanning by key faster.
@item -R or --sort-records=#
-Sorts records according to an index. This makes your data much more localized
+Sorts records according to an index. This makes your data much more localised
and may speed up ranged @code{SELECT} and @code{ORDER BY} operations on
-this index. (It may be VERY slow to do a sort the first time!)
+this index. (It may be very slow to do a sort the first time!)
To find out a table's index numbers, use @code{SHOW INDEX}, which shows a
table's indexes in the same order that @code{myisamchk} sees them. Indexes are
numbered beginning with 1.
@@ -18440,7 +18121,7 @@ index file is truncated at start, so one usually ignore this space.
This space is needed on the same disk as the original index file!
@item
When using @code{--recover} or @code{--sort-recover}
-(but not when using @code{--safe-recover}, you will need space for a
+(but not when using @code{--safe-recover}), you will need space for a
sort buffer for:
@code{(largest_key + row_pointer_length)*number_of_rows * 2}.
You can check the length of the keys and the row_pointer_length with
@@ -18475,14 +18156,16 @@ to check tables at any time. While you do this, all clients that try
to update the table will wait until @code{myisamchk} is ready before
continuing.
-If you use @code{myisamchk} to repair or optimize tables, you
-@strong{MUST} always ensure that the @code{mysqld} server is not using
+If you use @code{myisamchk} to repair or optimise tables, you
+@strong{must} always ensure that the @code{mysqld} server is not using
the table (this also applies if you are using @code{--skip-locking}).
If you don't take down @code{mysqld} you should at least do a
@code{mysqladmin flush-tables} before you run @code{myisamchk}.
+Your tables @strong{may be corrupted} if the server and @code{myisamchk}
+access the tables simultaneously.
This chapter describes how to check for and deal with data corruption
-in MySQL databases. If your tables get corrupted a lot you should
+in MySQL databases. If your tables get corrupted frequently you should
try to find the reason for this! @xref{Crashing}.
The @code{MyISAM} table section contains reason for why a table could be
@@ -18530,7 +18213,7 @@ To check a MyISAM table, use the following commands:
@table @code
@item myisamchk tbl_name
This finds 99.99% of all errors. What it can't find is corruption that
-involves @strong{ONLY} the data file (which is very unusual). If you want
+involves @strong{only} the data file (which is very unusual). If you want
to check a table, you should normally run @code{myisamchk} without options or
with either the @code{-s} or @code{--silent} option.
@@ -18543,7 +18226,7 @@ in the index tree.
@item myisamchk -e tbl_name
This does a complete and thorough check of all data (@code{-e} means
``extended check''). It does a check-read of every key for each row to verify
-that they indeed point to the correct row. This may take a LONG time on a
+that they indeed point to the correct row. This may take a long time on a
big table with many keys. @code{myisamchk} will normally stop after the first
error it finds. If you want to obtain more information, you can add the
@code{--verbose} (@code{-v}) option. This causes @code{myisamchk} to keep
@@ -18556,7 +18239,7 @@ print some informational statistics, too.
@end table
-@node Repair, Optimization, Check, Table maintenance
+@node Repair, Optimisation, Check, Table maintenance
@subsubsection How to Repair Tables
@cindex tables, repairing
@@ -18585,7 +18268,7 @@ Record file is crashed
@item
Got error ### from table handler
-To get more information about the error you can run @code{perror ###}. Here
+To get more information about the error you can run @code{perror ###}. Here
is the most common errors that indicates a problem with the table:
@example
@@ -18620,8 +18303,8 @@ that @code{mysqld} runs as (and to you, because you need to access the files
you are checking). If it turns out you need to modify files, they must also
be writable by you.
-If you are using MySQL Version 3.23.16 and above, you can (and
-should) use the @code{CHECK} and @code{REPAIR} commands to check and repair
+If you are using MySQL Version 3.23.16 and above, you can (and
+should) use the @code{CHECK} and @code{REPAIR} commands to check and repair
@code{MyISAM} tables. @xref{CHECK TABLE}. @xref{REPAIR TABLE}.
The manual section about table maintenance includes the options to
@@ -18655,7 +18338,7 @@ memory} errors), or if @code{myisamchk} crashes, go to Stage 3.
@noindent
@strong{Stage 2: Easy safe repair}
-NOTE: If you want repairing to go much faster, you should add: @code{-O
+Note: If you want repairing to go much faster, you should add: @code{-O
sort_buffer=# -O key_buffer=#} (where # is about 1/4 of the available
memory) to all @code{isamchk/myisamchk} commands.
@@ -18741,11 +18424,11 @@ the index file.
@end enumerate
-@node Optimization, , Repair, Table maintenance
-@subsubsection Table Optimization
+@node Optimisation, , Repair, Table maintenance
+@subsubsection Table Optimisation
-@cindex tables, optimizing
-@cindex optimizing, tables
+@cindex tables, optimising
+@cindex optimising, tables
To coalesce fragmented records and eliminate wasted space resulting from
deleting or updating records, run @code{myisamchk} in recovery mode:
@@ -18754,9 +18437,9 @@ deleting or updating records, run @code{myisamchk} in recovery mode:
shell> myisamchk -r tbl_name
@end example
-You can optimize a table in the same way using the SQL @code{OPTIMIZE TABLE}
+You can optimise a table in the same way using the SQL @code{OPTIMIZE TABLE}
statement. @code{OPTIMIZE TABLE} does a repair of the table, a key
-analyzes and also sorts the index tree to give faster key lookups.
+analyses and also sorts the index tree to give faster key lookups.
There is also no possibility of unwanted interaction between a utility
and the server, because the server does all the work when you use
@code{OPTIMIZE TABLE}. @xref{OPTIMIZE TABLE}.
@@ -18764,11 +18447,11 @@ and the server, because the server does all the work when you use
@code{myisamchk} also has a number of other options you can use to improve
the performance of a table:
-@table @code
+@itemize
@item -S, --sort-index
@item -R index_num, --sort-records=index_num
@item -a, --analyze
-@end table
+@end itemize
For a full description of the option. @xref{myisamchk syntax}.
@@ -18826,7 +18509,7 @@ night on all tables that have been updated during the last 24 hours,
until you come to trust MySQL as much as we do.
@cindex tables, defragment
-Normally you don't need to maintain MySQL tables that much. If
+Normally you don't need to maintain MySQL tables that much. If
you are changing tables with dynamic size rows (tables with @code{VARCHAR},
@code{BLOB} or @code{TEXT} columns) or have tables with many deleted rows
you may want to from time to time (once a month?) defragment/reclaim space
@@ -18849,7 +18532,7 @@ myisamchk -r --silent --sort-index -O sort_buffer_size=16M */*.MYI
To get a description of a table or statistics about it, use the commands shown
below. We explain some of the information in more detail later:
-@table @code
+@itemize @bullet
@item myisamchk -d tbl_name
Runs @code{myisamchk} in ``describe mode'' to produce a description of
your table. If you start the MySQL server using the
@@ -18868,7 +18551,7 @@ must read the whole table.
@item myisamchk -eiv tbl_name
This is like @code{-eis}, but tells you what is being done.
-@end table
+@end itemize
@cindex examples, @code{myisamchk} output
@cindex @code{myisamchk}, example output
@@ -18935,8 +18618,10 @@ Key: 8: Keyblocks used: 99% Packed: 0% Max levels: 3
Key: 9: Keyblocks used: 98% Packed: 0% Max levels: 4
Total: Keyblocks used: 98% Packed: 17%
-Records: 1403698 M.recordlength: 226 Packed: 0%
-Recordspace used: 100% Empty space: 0% Blocks/Record: 1.00
+Records: 1403698 M.recordlength: 226
+Packed: 0%
+Recordspace used: 100% Empty space: 0%
+Blocks/Record: 1.00
Record blocks: 1403698 Delete blocks: 0
Recorddata: 317235748 Deleted data: 0
Lost space: 0 Linkdata: 0
@@ -19014,7 +18699,7 @@ Explanations for the types of information @code{myisamchk} produces are
given below. The ``keyfile'' is the index file. ``Record'' and ``row''
are synonymous:
-@table @code
+@itemize @bullet
@item ISAM file
Name of the ISAM (index) file.
@@ -19032,18 +18717,18 @@ How many records are in the table.
@item Deleted blocks
How many deleted blocks still have reserved space.
-You can optimize your table to minimize this space.
-@xref{Optimization}.
+You can optimise your table to minimise this space.
+@xref{Optimisation}.
@item Datafile: Parts
For dynamic record format, this indicates how many data blocks there are. For
-an optimized table without fragmented records, this is the same as @code{Data
+an optimised table without fragmented records, this is the same as @code{Data
records}.
@item Deleted data
How many bytes of non-reclaimed deleted data there are.
-You can optimize your table to minimize this space.
-@xref{Optimization}.
+You can optimise your table to minimise this space.
+@xref{Optimisation}.
@item Datafile pointer
The size of the data file pointer, in bytes. It is usually 2, 3, 4, or 5
@@ -19074,7 +18759,7 @@ Other possible values are @code{Compressed} and @code{Packed}.
A list of all keys in the table. For each key, some low-level information
is presented:
-@table @code
+@itemize @minus
@item Key
This key's number.
@@ -19103,19 +18788,19 @@ The size of each index block. By default this is 1024, but the value may be
changed at compile time.
@item Rec/key
-This is a statistical value used by the optimizer. It tells how many
+This is a statistical value used by the optimiser. It tells how many
records there are per value for this key. A unique key always has a
value of 1. This may be updated after a table is loaded (or greatly
changed) with @code{myisamchk -a}. If this is not updated at all, a default
value of 30 is given.
-@end table
+@end itemize
@item
In the first example above, the 9th key is a multi-part key with two parts.
@item Keyblocks used
What percentage of the keyblocks are used. Because the table used in the
-examples had just been reorganized with @code{myisamchk}, the values are very
+examples had just been reorganised with @code{myisamchk}, the values are very
high (very near the theoretical maximum).
@item Packed
@@ -19150,8 +18835,8 @@ What percentage of the data file is unused.
Average number of blocks per record (that is, how many links a fragmented
record is composed of). This is always 1 for fixed-format tables. This value
should stay as close to 1.0 as possible. If it gets too big, you can
-reorganize the table with @code{myisamchk}.
-@xref{Optimization}.
+reorganise the table with @code{myisamchk}.
+@xref{Optimisation}.
@item Recordblocks
How many blocks (links) are used. For fixed format, this is the same as the number
@@ -19174,7 +18859,7 @@ the sum of all such losses, in bytes.
When the dynamic table format is used, record fragments are linked with
pointers (4 to 7 bytes each). @code{Linkdata} is the sum of the amount of
storage used by all such pointers.
-@end table
+@end itemize
If a table has been compressed with @code{myisampack}, @code{myisamchk
-d} prints additional information about each table column. See
@@ -19182,7 +18867,7 @@ If a table has been compressed with @code{myisampack}, @code{myisamchk
information and a description of what it means.
-@node Database Administration, Localization, Disaster Prevention, MySQL Database Administration
+@node Database Administration, Localisation, Disaster Prevention, MySQL Database Administration
@section Database Administration Language Reference
@@ -19190,6 +18875,7 @@ information and a description of what it means.
* OPTIMIZE TABLE:: @code{OPTIMIZE TABLE} Syntax
* ANALYZE TABLE:: @code{ANALYZE TABLE} Syntax
* FLUSH:: @code{FLUSH} Syntax
+* RESET:: @code{RESET} Syntax
* KILL:: @code{KILL} Syntax
* SHOW:: @code{SHOW} Syntax
@end menu
@@ -19218,7 +18904,7 @@ For the moment @code{OPTIMIZE TABLE} only works on @strong{MyISAM} and
@code{BDB} tables. For @code{BDB} tables, @code{OPTIMIZE TABLE} is
currently mapped to @code{ANALYZE TABLE}. @xref{ANALYZE TABLE}.
-You can get optimize table to work on other table types by starting
+You can get optimise table to work on other table types by starting
@code{mysqld} with @code{--skip-new} or @code{--safe-mode}, but in this
case @code{OPTIMIZE TABLE} is just mapped to @code{ALTER TABLE}.
@@ -19250,8 +18936,8 @@ running!
ANALYZE TABLE tbl_name[,tbl_name...]
@end example
-Analyze and store the key distribution for the table. During the
-analyze the table is locked with a read lock. This works on
+Analyse and store the key distribution for the table. During the
+analyse the table is locked with a read lock. This works on
@code{MyISAM} and @code{BDB} tables.
This is equivalent to running @code{myisamchk -a} on the table.
@@ -19274,10 +18960,10 @@ You can check the stored key distribution with the @code{SHOW INDEX} command.
@xref{SHOW DATABASE INFO}.
If the table hasn't changed since the last @code{ANALYZE TABLE} command,
-the table will not be analyzed again.
+the table will not be analysed again.
-@node FLUSH, KILL, ANALYZE TABLE, Database Administration
+@node FLUSH, RESET, ANALYZE TABLE, Database Administration
@subsection @code{FLUSH} Syntax
@findex FLUSH
@@ -19297,6 +18983,8 @@ the @strong{RELOAD} privilege.
@code{flush_option} can be any of the following:
@multitable @columnfractions .15 .85
+@item @strong{Option} @tab @strong{Description}
+
@item @code{HOSTS} @tab Empties the host cache tables. You should flush the
host tables if some of your hosts change IP number or if you get the
error message @code{Host ... is blocked}. When more than
@@ -19304,9 +18992,11 @@ error message @code{Host ... is blocked}. When more than
connection to the MySQL server, MySQL assumes
something is wrong and blocks the host from further connection requests.
Flushing the host tables allows the host to attempt to connect
-again. @xref{Blocked host}.) You can start @code{mysqld} with
+again. @xref{Blocked host}. You can start @code{mysqld} with
@code{-O max_connection_errors=999999999} to avoid this error message.
+@item @code{DES_KEY_FILE} @tab Reloads the des keys from the file specified with @code{--des-key-file}.
+
@item @code{LOGS} @tab Closes and reopens all log files.
If you have specified the update log file or a binary log file without
an extension, the extension number of the log file will be incremented
@@ -19318,7 +19008,9 @@ signal to the @code{mysqld} server.
@item @code{PRIVILEGES} @tab Reloads the privileges from the grant tables in
the @code{mysql} database.
-@item @code{TABLES} @tab Closes all open tables and force all tables in use to be closed.
+@item @code{QUERY CACHE} @tab Defragment the query cache to better utilise its memory. This command will not remove any queries from the cache.
+
+@item @code{TABLES} @tab Closes all open tables and force all tables in use to be closed. This also flushes the query cache.
@item @code{[TABLE | TABLES] table_name [,table_name...]} @tab Flushes only the given tables.
@@ -19331,12 +19023,36 @@ You can also access each of the commands shown above with the @code{mysqladmin}
utility, using the @code{flush-hosts}, @code{flush-logs}, @code{reload},
or @code{flush-tables} commands.
-Take also a look at the @code{RESET} command used with
-replication. @xref{Replication SQL}.
+Take also a look at the @code{RESET} command used with replication.
+@xref{RESET}.
+@node RESET, KILL, FLUSH, Database Administration
+@subsection @code{RESET} Syntax
+@example
+FLUSH flush_option [,flush_option]
+@end example
+
+The @code{RESET} command is used to clear things. It also acts as an stronger
+version of the @code{FLUSH} command. @xref{FLUSH}.
+
+@multitable @columnfractions .15 .85
+@item @strong{Option} @tab @strong{Description}
-@node KILL, SHOW, FLUSH, Database Administration
+@item @code{MASTER}
+@tab Deletes all binary logs listed in the index file, resetting the binlog
+index file to be empty. In pre-3.23.26 versions, @code{FLUSH MASTER} (Master)
+
+@item @code{SLAVE}
+@tab Makes the slave forget its replication position in the master
+logs. In pre 3.23.26 versions the command was called
+@code{FLUSH SLAVE}(Slave)
+
+@item @code{QUERY CACHE}
+@tab Removes all query results from the query cache.
+@end multitable
+
+@node KILL, SHOW, RESET, Database Administration
@subsection @code{KILL} Syntax
@findex KILL
@@ -19390,12 +19106,6 @@ If the thread is waiting for free disk space in a @code{write} call, the
write is aborted with an disk full error message.
@end itemize
-
-@menu
-* SHOW:: @code{SHOW} Syntax
-@end menu
-
-
@node SHOW, , KILL, Database Administration
@subsection @code{SHOW} Syntax
@@ -19471,7 +19181,7 @@ host. You can also get this list using the @code{mysqlshow} command.
@code{SHOW TABLES} lists the tables in a given database. You can also
get this list using the @code{mysqlshow db_name} command.
-@strong{NOTE:} If a user doesn't have any privileges for a table, the table
+@strong{Note:} If a user doesn't have any privileges for a table, the table
will not show up in the output from @code{SHOW TABLES} or @code{mysqlshow
db_name}.
@@ -19503,7 +19213,7 @@ are returned:
@item @code{Table} @tab Name of the table.
@item @code{Non_unique} @tab 0 if the index can't contain duplicates.
@item @code{Key_name} @tab Name of the index.
-@item @code{Seq_in_index} @tab Column sequence number in index,
+@item @code{Seq_in_index} @tab Column sequence number in index,
starting with 1.
@item @code{Column_name} @tab Column name.
@item @code{Collation} @tab How the column is sorted in the index.
@@ -19511,18 +19221,21 @@ are returned:
@samp{A} (Ascending) or @code{NULL} (Not
sorted).
@item @code{Cardinality} @tab Number of unique values in the index.
- This is updated by running
+ This is updated by running
@code{isamchk -a}.
-@item @code{Sub_part} @tab Number of indexed characters if the
- column is only partly indexed.
+@item @code{Sub_part} @tab Number of indexed characters if the
+ column is only partly indexed.
@code{NULL} if the entire key is indexed.
-@item @code{Comment} @tab Various remarks. For now, it tells
- whether index is FULLTEXT or not.
+@item @code{Null} $tab Contains 'YES' if the column may contain @code{NULL}.
+@item @code{Index_type} @tab Index method used.
+@item @code{Comment} @tab Various remarks. For now, it tells
+in MySQL < 4.0.2 whether index is @code{FULLTEXT} or not.
@end multitable
Note that as the @code{Cardinality} is counted based on statistics
stored as integers, it's not necessarily accurate for small tables.
+The @code{Null} and @code{Index_type} columns were added in MySQL 4.0.2.
@node SHOW TABLE STATUS, SHOW STATUS, SHOW DATABASE INFO, SHOW
@subsubsection @code{SHOW TABLE STATUS}
@@ -19697,7 +19410,7 @@ open by the slave thread
acquired immediately. Available after 3.23.33.
@item @code{Table_locks_waited} @tab Number of times a table lock could not
be acquired immediately and a wait was needed. If this is high, and you
-have performance problems, you should first optimize your queries, and then
+have performance problems, you should first optimise your queries, and then
either split your table(s) or use replication. Available after 3.23.33.
@item @code{Threads_cached} @tab Number of threads in the thread cache.
@item @code{Threads_connected} @tab Number of currently open connections.
@@ -19722,7 +19435,12 @@ queries that require MySQL to scan whole tables or you have
joins that don't use keys properly.
@item
If @code{Threads_created} is big, you may want to increase the
-@code{thread_cache_size} variable.
+@code{thread_cache_size} variable. The cache hit rate can be calculated
+with @code{Threads_created}/@code{Connections}.
+@item
+If @code{Created_tmp_disk_tables} is big, you may want to increase the
+@code{tmp_table_size} variable to get the temporary tables memory based
+instead of disk based.
@end itemize
@@ -19743,85 +19461,93 @@ The output resembles that shown below, though the format and numbers may
differ somewhat:
@example
-+-------------------------+---------------------------+
-| Variable_name | Value |
-+-------------------------+---------------------------+
-| ansi_mode | OFF |
-| back_log | 50 |
-| basedir | /my/monty/ |
-| bdb_cache_size | 16777216 |
-| bdb_log_buffer_size | 32768 |
-| bdb_home | /my/monty/data/ |
-| bdb_max_lock | 10000 |
-| bdb_logdir | |
-| bdb_shared_data | OFF |
-| bdb_tmpdir | /tmp/ |
-| binlog_cache_size | 32768 |
-| concurrent_insert | ON |
-| connect_timeout | 5 |
-| datadir | /my/monty/data/ |
-| delay_key_write | ON |
-| delayed_insert_limit | 100 |
-| delayed_insert_timeout | 300 |
-| delayed_queue_size | 1000 |
-| flush | OFF |
-| flush_time | 0 |
-| have_bdb | YES |
-| have_innodb | YES |
-| have_raid | YES |
-| have_ssl | NO |
-| init_file | |
-| interactive_timeout | 28800 |
-| join_buffer_size | 131072 |
-| key_buffer_size | 16776192 |
-| language | /my/monty/share/english/ |
-| large_files_support | ON |
-| log | OFF |
-| log_update | OFF |
-| log_bin | OFF |
-| log_slave_updates | OFF |
-| long_query_time | 10 |
-| low_priority_updates | OFF |
-| lower_case_table_names | 0 |
-| max_allowed_packet | 1048576 |
-| max_binlog_cache_size | 4294967295 |
-| max_connections | 100 |
-| max_connect_errors | 10 |
-| max_delayed_threads | 20 |
-| max_heap_table_size | 16777216 |
-| max_join_size | 4294967295 |
-| max_sort_length | 1024 |
-| max_tmp_tables | 32 |
-| max_write_lock_count | 4294967295 |
-| myisam_recover_options | DEFAULT |
-| myisam_sort_buffer_size | 8388608 |
-| net_buffer_length | 16384 |
-| net_read_timeout | 30 |
-| net_retry_count | 10 |
-| net_write_timeout | 60 |
-| open_files_limit | 0 |
-| pid_file | /my/monty/data/donna.pid |
-| port | 3306 |
-| protocol_version | 10 |
-| record_buffer | 131072 |
-| query_buffer_size | 0 |
-| safe_show_database | OFF |
-| server_id | 0 |
-| skip_locking | ON |
-| skip_networking | OFF |
-| skip_show_database | OFF |
-| slow_launch_time | 2 |
-| socket | /tmp/mysql.sock |
-| sort_buffer | 2097116 |
-| table_cache | 64 |
-| table_type | MYISAM |
-| thread_cache_size | 4 |
-| thread_stack | 65536 |
-| tmp_table_size | 1048576 |
-| tmpdir | /tmp/ |
-| version | 3.23.29a-gamma-debug |
-| wait_timeout | 28800 |
-+-------------------------+---------------------------+
++------------------------------+---------------------------+
+| Variable_name | Value |
++------------------------------+---------------------------+
+| ansi_mode | OFF |
+| back_log | 50 |
+| basedir | /my/monty/ |
+| bdb_cache_size | 16777216 |
+| bdb_log_buffer_size | 32768 |
+| bdb_home | /my/monty/data/ |
+| bdb_max_lock | 10000 |
+| bdb_logdir | |
+| bdb_shared_data | OFF |
+| bdb_tmpdir | /tmp/ |
+| binlog_cache_size | 32768 |
+| concurrent_insert | ON |
+| connect_timeout | 5 |
+| datadir | /my/monty/data/ |
+| delay_key_write | ON |
+| delayed_insert_limit | 100 |
+| delayed_insert_timeout | 300 |
+| delayed_queue_size | 1000 |
+| flush | OFF |
+| flush_time | 0 |
+| ft_min_word_len | 4 |
+| ft_max_word_len | 254 |
+| ft_max_word_len_for_sort | 20 |
+| ft_boolean_syntax | + -><()~* |
+| have_bdb | YES |
+| have_innodb | YES |
+| have_raid | YES |
+| have_openssl | NO |
+| init_file | |
+| interactive_timeout | 28800 |
+| join_buffer_size | 131072 |
+| key_buffer_size | 16776192 |
+| language | /my/monty/share/english/ |
+| large_files_support | ON |
+| log | OFF |
+| log_update | OFF |
+| log_bin | OFF |
+| log_slave_updates | OFF |
+| long_query_time | 10 |
+| low_priority_updates | OFF |
+| lower_case_table_names | 0 |
+| max_allowed_packet | 1048576 |
+| max_binlog_cache_size | 4294967295 |
+| max_connections | 100 |
+| max_connect_errors | 10 |
+| max_delayed_threads | 20 |
+| max_heap_table_size | 16777216 |
+| max_join_size | 4294967295 |
+| max_sort_length | 1024 |
+| max_tmp_tables | 32 |
+| max_write_lock_count | 4294967295 |
+| myisam_bulk_insert_tree_size | 8388608 |
+| myisam_recover_options | DEFAULT |
+| myisam_sort_buffer_size | 8388608 |
+| net_buffer_length | 16384 |
+| net_read_timeout | 30 |
+| net_retry_count | 10 |
+| net_write_timeout | 60 |
+| open_files_limit | 0 |
+| pid_file | /my/monty/data/donna.pid |
+| port | 3306 |
+| protocol_version | 10 |
+| record_buffer | 131072 |
+| query_buffer_size | 0 |
+| query_cache_limit | 1048576 |
+| query_cache_size | 16768060 |
+| query_cache_startup_type | 1 |
+| safe_show_database | OFF |
+| server_id | 0 |
+| skip_locking | ON |
+| skip_networking | OFF |
+| skip_show_database | OFF |
+| slow_launch_time | 2 |
+| socket | /tmp/mysql.sock |
+| sort_buffer | 2097116 |
+| table_cache | 64 |
+| table_type | MYISAM |
+| thread_cache_size | 4 |
+| thread_stack | 65536 |
+| tmp_table_size | 1048576 |
+| tmpdir | /tmp/ |
+| version | 3.23.29a-gamma-debug |
+| wait_timeout | 28800 |
++------------------------------+---------------------------+
@end example
Each option is described below. Values for buffer sizes, lengths, and stack
@@ -19831,14 +19557,14 @@ indicates 16 megabytes. The case of suffix letters does not matter;
@code{16M} and @code{16m} are equivalent:
@cindex variables, values
-@table @code
+@itemize
@item @code{ansi_mode}.
Is @code{ON} if @code{mysqld} was started with @code{--ansi}.
@xref{ANSI mode}.
@item @code{back_log}
The number of outstanding connection requests MySQL can have. This
-comes into play when the main MySQL thread gets @strong{VERY}
+comes into play when the main MySQL thread gets @strong{very}
many connection requests in a very short time. It then takes some time
(although very little) for the main thread to check the connection and start
a new thread. The @code{back_log} value indicates how many requests can be
@@ -19899,10 +19625,10 @@ The default character set.
The supported character sets.
@item @code{concurrent_inserts}
-If @code{ON} (the default), MySQL will allow you to use @code{INSERT}
-on @code{MyISAM} tables at the same time as you run @code{SELECT} queries
-on them. You can turn this option off by starting @code{mysqld} with @code{--safe}
-or @code{--skip-new}.
+If @code{ON} (the default), MySQL will allow you to use @code{INSERT} on
+@code{MyISAM} tables at the same time as you run @code{SELECT} queries
+on them. You can turn this option off by starting @code{mysqld} with
+@code{--safe} or @code{--skip-new}.
@cindex timeout
@item @code{connect_timeout}
@@ -19948,15 +19674,42 @@ tables will be closed (to free up resources and sync things to disk). We
only recommend this option on Win95, Win98, or on systems where you have
very little resources.
-@item @code{have_bdb}
-@code{YES} if @code{mysqld} supports Berkeley DB tables. @code{DISABLED}
-if @code{--skip-bdb} is used.
+@item @code{ft_min_word_len}
+The minimum length of the word to be included in a @code{FULLTEXT} index.
+@strong{Note: @code{FULLTEXT} index have to be rebuilt after changing
+this variable.}
+
+@item @code{ft_max_word_len}
+The maximum length of the word to be included in a @code{FULLTEXT} index.
+@strong{Note: @code{FULLTEXT} index have to be rebuilt after changing
+this variable.}
+
+@item @code{ft_max_word_len_sort}
+The maximum length of the word in a @code{FULLTEXT} index
+to be used in fast index recreation method in @code{REPAIR},
+@code{CREATE INDEX}, or @code{ALTER TABLE}. Longer words are inserted the
+slow way. The rule of the thumb is as follows: with
+@code{ft_max_word_len_sort} increasing, @strong{MySQL} will create bigger
+temporary files (thus slowing the process down, due to disk I/O), and will put
+fewer keys in one sort block (againg, decreasing the efficiency). When
+@code{ft_max_word_len_sort} is too small, instead, @strong{MySQL} will insert a
+lot of words into index the slow way - but short words will be inserted very
+fast. It applies only to index recreation during @code{REPAIR},
+@code{CREATE INDEX}, or @code{ALTER TABLE}.
+
+@item @code{ft_boolean_syntax}
+List of operators supported by @code{MATCH ... AGAINST(... IN BOOLEAN MODE)}.
+@xref{Fulltext Search}.
+
@item @code{have_innodb}
@code{YES} if @code{mysqld} supports InnoDB tables. @code{DISABLED}
if @code{--skip-innodb} is used.
+@item @code{have_bdb}
+@code{YES} if @code{mysqld} supports Berkeley DB tables. @code{DISABLED}
+if @code{--skip-bdb} is used.
@item @code{have_raid}
@code{YES} if @code{mysqld} supports the @code{RAID} option.
-@item @code{have_ssl}
+@item @code{have_openssl}
@code{YES} if @code{mysqld} supports SSL (encryption) on the client/server
protocol.
@@ -19989,7 +19742,7 @@ Increase this to get better index handling (for all reads and multiple
writes) to as much as you can afford; 64M on a 256M machine that mainly
runs MySQL is quite common. If you, however, make this too big
(more than 50% of your total memory?) your system may start to page and
-become REALLY slow. Remember that because MySQL does not cache
+become extremely slow. Remember that because MySQL does not cache
data read, that you will have to leave some room for the OS filesystem
cache.
@@ -20037,12 +19790,13 @@ names will be case-insensitive.
@xref{Name case sensitivity}.
@item @code{max_allowed_packet}
-The maximum size of one packet. The message buffer is initialized to
+The maximum size of one packet. The message buffer is initialised to
@code{net_buffer_length} bytes, but can grow up to @code{max_allowed_packet}
bytes when needed. This value by default is small, to catch big (possibly
wrong) packets. You must increase this value if you are using big
@code{BLOB} columns. It should be as big as the biggest @code{BLOB} you want
-to use. The current protocol limits @code{max_allowed_packet} to 16M.
+to use. The protocol limits for @code{max_allowed_packet} is 16M in MySQL
+3.23 and 2G in MySQL 4.0.
@item @code{max_binlog_cache_size}
If a multi-statement transaction requires more than this amount of memory,
@@ -20050,8 +19804,8 @@ one will get the error "Multi-statement transaction required more than
'max_binlog_cache_size' bytes of storage".
@item @code{max_binlog_size}
-Available after 3.23.33. If a write to the binary (replication) log exceeds
-the given value, rotate the logs. You cannot set it to less than 1024 bytes,
+Available after 3.23.33. If a write to the binary (replication) log exceeds
+the given value, rotate the logs. You cannot set it to less than 1024 bytes,
or more than 1 GB. Default is 1 GB.
@item @code{max_connections}
@@ -20094,6 +19848,15 @@ Maximum number of temporary tables a client can keep open at the same time.
@item @code{max_write_lock_count}
After this many write locks, allow some read locks to run in between.
+@item @code{myisam_bulk_insert_tree_size}
+MySQL uses special tree-like cache to make bulk inserts (that is,
+@code{INSERT ... SELECT}, @code{INSERT ... VALUES (...), (...), ...}, and
+@code{LOAD DATA INFILE}) faster. This variable limits
+the size of the cache tree in bytes per thread. Setting it to 0
+will disable this optimization.
+@strong{Note:} This cache is only used when adding data to non-empty table.
+Default value is 8 MB.
+
@item @code{myisam_recover_options}
The value of the @code{--myisam-recover} option.
@@ -20168,6 +19931,22 @@ buffer to avoid a disk seeks. If not set, then it's set to the value of
The initial allocation of the query buffer. If most of your queries are
long (like when inserting blobs), you should increase this!
+@item @code{query_cache_limit}
+Don't cache results that are bigger than this. (Default 1M).
+
+@item @code{query_cache_size}
+The memory allocated to store results from old queries.
+If this is 0, the query cache is disabled (default).
+
+@item @code{query_cache_startup_type}
+This may be set (only numeric) to
+@multitable @columnfractions .1 .2 .7
+@item @strong{Value} @tab @strong{Alias} @tab @strong{Comment}
+@item 0 @tab OFF @tab Don't cache or retrieve results.
+@item 1 @tab ON @tab Cache all results except @code{SELECT SQL_NO_CACHE ...} queries.
+@item 2 @tab DEMAND @tab Cache only @code{SELECT SQL_CACHE ...} queries.
+@end multitable
+
@item @code{safe_show_databases}
Don't show databases for which the user doesn't have any database or
table privileges. This can improve security if you're concerned about
@@ -20209,19 +19988,13 @@ operations.
@item @code{table_cache}
The number of open tables for all threads. Increasing this value
increases the number of file descriptors that @code{mysqld} requires.
-MySQL needs two file descriptors for each unique open table.
-See below for comments on file descriptor limits. You can check if you
-need to increase the table cache by checking the @code{Opened_tables}
-variable. @xref{SHOW}. If this variable is big and you don't do
-@code{FLUSH TABLES} a lot (which just forces all tables to be closed and
-reopenend), then you should increase the value of this variable.
-
-Make sure that your operating system can handle the number of open file
-descriptors implied by the @code{table_cache} setting. If @code{table_cache}
-is set too high, MySQL may run out of file descriptors and refuse
-connections, fail to perform queries, and be very unreliable.
+You can check if you need to increase the table cache by checking the
+@code{Opened_tables} variable. @xref{SHOW}. If this variable is big and
+you don't do @code{FLUSH TABLES} a lot (which just forces all tables to
+be closed and reopenend), then you should increase the value of this
+variable.
-For information about how the table cache works, see @ref{Table cache}.
+For more information about the table cache, see @ref{Table cache}.
@item @code{table_type}
The default table type
@@ -20267,7 +20040,7 @@ The version number for the server.
@item @code{wait_timeout}
The number of seconds the server waits for activity on a connection before
closing it. See also @code{interactive_timeout}.
-@end table
+@end itemize
The manual section that describes tuning MySQL contains some
information of how to tune the above variables. @xref{Server parameters}.
@@ -20299,7 +20072,7 @@ subsystem)
@cindex threads, display
@cindex processes, display
-@code{SHOW PROCESSLIST} shows you which threads are running. You can
+@code{SHOW [FULL] PROCESSLIST} shows you which threads are running. You can
also get this information using the @code{mysqladmin processlist}
command. If you have the @strong{process} privilege, you can see all
threads. Otherwise, you can see only your own threads. @xref{KILL, ,
@@ -20312,6 +20085,105 @@ one extra connection for a client with the @code{Process_priv} privilege
to ensure that you should always be able to login and check the system
(assuming you are not giving this privilege to all your users).
+Some frequently states in @code{mysqladmin processlist}
+
+@itemize @bullet
+@item @code{Checking table}
+The thread doing an [automatic ?] checking of the table.
+@item @code{Closing tables}
+Means that the thread is flushing the changed table data to disk and
+closing the used tables. This should be a fast operation. If not, then
+you should check that you don't have a full disk or that the disk is not
+in very heavy use.
+@item @code{Connect Out}
+Slave connecting to master.
+@item @code{Copying to tmp table on disk}
+The temporary result set was larger than @code{tmp_table_size} and the
+thread is now changing the in memory based temporary table to a disk
+based one to save memory.
+@item @code{Creating tmp table}
+The thread is creating a temporary table to hold a part of the result for
+the query.
+@item @code{deleting from main table}
+When executing the first part of a multi-table delete and we are only
+deleting from the first table.
+@item @code{deleting from reference tables}
+When executing the second part of a multi-table delete and we are deleting
+the matched rows from the other tables.
+@item @code{Flushing tables}
+The thread is executing @code{FLUSH TABLES} and is waiting for all
+threads to close their tables.
+@item @code{Killed}
+Someone has sent a kill to the thread and it should abort next time it
+checks the kill flag. The flag is checked in each major loop in MySQL,
+but in some cases it may still take a short time for the thread to die.
+If the thread is locked by some other thread, the kill will take affect
+as soon as the other thread releases it's lock.
+@item @code{Sending data}
+The thread is processing rows for a @code{SELECT} statement and is
+also sending data to the client.
+@item @code{Sorting for group}
+The thread is doing a sort to satsify a @code{GROUP BY}.
+@item @code{Sorting for order}
+The thread is doing a sort to satsify a @code{ORDER BY}.
+@item @code{Opening tables}
+This simply means that the thread is trying to open a table. This is
+should be very fast procedure, unless something prevents opening. For
+example an @code{ALTER TABLE} or a @code{LOCK TABLE} can prevent opening
+a table until the command is finished.
+@item @code{Removing duplicates}
+The query was using @code{SELECT DISTINCT} in such a way that MySQL
+couldn't optimize that distinct away at an early stage. Because of this
+MySQL has to do an extra stage to remove all duplicated rows before
+sending the result to the client.
+@item @code{Reopen table}
+The thread got a lock for the table, but noticed after getting the lock
+that the underlying table structure changed. It has freed the lock,
+closed the table and is now trying to reopen it.
+@item @code{Repair by sorting}
+The repair code is using sorting to create indexes.
+@item @code{Repair with keycache}
+The repair code is using creating keys one by one through the key cache.
+This is much slower than @code{Repair by sorting}.
+@item @code{Searching rows for update}
+The thread is doing a first phase to find all matching rows before
+updating them. This has to be done if the @code{UPDATE} is changing
+the index that is used to find the involved rows.
+@item @code{Sleeping}
+The thread is wating for the client to send a new command to it.
+@item @code{System lock}
+The thread is waiting for getting to get a external system lock for the
+table. If you are not using multiple mysqld servers that are accessing
+the same tables, you can disable system locks with the
+@code{--skip-locking} option.
+@item @code{Upgrading lock}
+The @code{INSERT DELAYED} handler is trying to get a lock for the table
+to insert rows.
+@item @code{Updating}
+The thread is searching for rows to update and updating them.
+@item @code{User Lock}
+The thread is waiting on a @code{GET_LOCK()}.
+@item @code{Waiting for tables}
+The thread got a notification that the underlying structure for a table
+has changed and it needs to reopen the table to get the new structure.
+To be able to reopen the table it must however wait until all other
+threads have closed the table in question.
+
+This notification happens if another thread has used @code{FLUSH TABLES}
+or one of the following commands on the table in question: @code{FLUSH
+TABLES table_name}, @code{ALTER TABLE}, @code{RENAME TABLE},
+@code{REPAIR TABLE}, @code{ANALYZE TABLE} or @code{OPTIMIZE TABLE}.
+@item @code{waiting for handler insert}
+The @code{INSERT DELAYED} handler has processed all inserts and are
+waiting to get new ones.
+@end itemize
+
+Most states are very quick operations. If threads last in any of these
+states for many seconds, there may be a problem around that needs to be
+investigated.
+
+There are some other states that are not mentioned above, but most of
+these are only useful to find bugs in @code{mysqld}.
@node SHOW GRANTS, SHOW CREATE TABLE, SHOW PROCESSLIST, SHOW
@subsubsection @code{SHOW GRANTS}
@@ -20353,8 +20225,8 @@ Create Table: CREATE TABLE t (
@ref{SET OPTION, , @code{SET OPTION SQL_QUOTE_SHOW_CREATE}}.
-@node Localization, Server-Side Scripts, Database Administration, MySQL Database Administration
-@section MySQL Localization and International Usage
+@node Localisation, Server-Side Scripts, Database Administration, MySQL Database Administration
+@section MySQL Localisation and International Usage
@menu
* Character sets:: The Character Set Used for Data and Sorting
@@ -20363,10 +20235,11 @@ Create Table: CREATE TABLE t (
* Character arrays:: The character definition arrays
* String collating:: String Collating Support
* Multi-byte characters:: Multi-byte Character Support
+* Problems with character sets:: Problems With Character Sets
@end menu
-@node Character sets, Languages, Localization, Localization
+@node Character sets, Languages, Localisation, Localisation
@subsection The Character Set Used for Data and Sorting
@cindex character sets
@@ -20404,7 +20277,7 @@ use this character set for this connection.
One should use @code{mysql_real_escape_string()} when escaping strings
for a SQL query. @code{mysql_real_escape_string()} is identical to the
-old @code{mysql_escape_string()} function, except that it takes the MYSQL
+old @code{mysql_escape_string()} function, except that it takes the @code{MYSQL}
connection handle as the first parameter.
If the client is compiled with different paths than where the server is
@@ -20432,8 +20305,37 @@ default-character-set=character-set-name
but normally this is never needed.
+@menu
+* German character set:: German character set
+@end menu
+
+@node German character set, , Character sets, Character sets
+@subsubsection German character set
-@node Languages, Adding character set, Character sets, Localization
+To get German sorting order, you should start @code{mysqld} with
+@code{--default-character-set=latin_de}. This will give you the following
+characteristics.
+
+When sorting and comparing string's the following mapping is done on the
+strings before doing the comparison:
+
+@example
+ä -> ae
+ö -> oe
+ü -> ue
+ß -> ss
+@end example
+
+All accented characters, are converted to their un-accented uppercase
+counterpart. All letters are converted to uppercase.
+
+When comparing strings with @code{LIKE} the one -> two character mapping
+is not done. All letters are converted to uppercase. Accent are removed
+from all letters except: @code{Ü}, @code{ü}, @code{Ö}, @code{ö},
+@code{Ä} and @code{ä}.
+
+
+@node Languages, Adding character set, Character sets, Localisation
@subsection Non-English Error Messages
@cindex error messages, languages
@@ -20475,7 +20377,7 @@ If you upgrade to a newer version of MySQL, remember to repeat
your changes with the new @file{errmsg.txt} file.
-@node Adding character set, Character arrays, Languages, Localization
+@node Adding character set, Character arrays, Languages, Localisation
@subsection Adding a New Character Set
@cindex character sets, adding
@@ -20503,7 +20405,7 @@ Assign an unique number to it.
@item
Create the file @file{sql/share/charsets/MYSET.conf}.
-(You can use @file{sql/share/charsets/latin1.conf} as a base for this).
+(You can use @file{sql/share/charsets/latin1.conf} as a base for this.)
The syntax for the file very simple:
@@ -20599,7 +20501,7 @@ If you want to have the character set included in the MySQL
distribution, mail a patch to @email{internals@@lists.mysql.com}.
-@node Character arrays, String collating, Adding character set, Localization
+@node Character arrays, String collating, Adding character set, Localisation
@subsection The character definition arrays
@code{to_lower[]} and @code{to_upper[]} are simple arrays that hold the
@@ -20621,7 +20523,7 @@ the discussion of string collating below. @xref{String collating}.
@code{ctype[]} is an array of bit values, with one element for one character.
(Note that @code{to_lower[]}, @code{to_upper[]}, and @code{sort_order[]}
are indexed by character value, but @code{ctype[]} is indexed by character
-value + 1. This is an old legacy to be able to handle EOF.)
+value + 1. This is an old legacy to be able to handle @code{EOF}.)
You can find the following bitmask definitions in @file{m_ctype.h}:
@@ -20647,7 +20549,7 @@ _U + _X = 01 + 0200 = 0201
@end example
-@node String collating, Multi-byte characters, Character arrays, Localization
+@node String collating, Multi-byte characters, Character arrays, Localisation
@subsection String Collating Support
@cindex collating, strings
@@ -20667,7 +20569,7 @@ the maximum ratio the strings may grow during @code{my_strxfrm_MYSET} (it
must be a positive integer).
-@node Multi-byte characters, , String collating, Localization
+@node Multi-byte characters, Problems with character sets, String collating, Localisation
@subsection Multi-byte Character Support
@cindex characters, multi-byte
@@ -20686,8 +20588,43 @@ You must specify the @code{mbmaxlen_MYSET=N} value in the special
comment at the top of the source file. @code{N} should be set to the
size in bytes of the largest character in the set.
+@node Problems with character sets, , Multi-byte characters, Localisation
+@subsection Problems With Character Sets
+
+If you try to use a character set that is not compiled into your binary,
+you can run into a couple of different problems:
-@node Server-Side Scripts, Client-Side Scripts, Localization, MySQL Database Administration
+@itemize @bullet
+@item
+Your program has a wrong path to where the character sets are stored.
+(Default @file{/usr/local/mysql/share/mysql/charsets}).
+This can be fixed by using the @code{--character-sets-dir}
+option to the program in question.
+@item
+The character set is a multi-byte-character set that can't be loaded
+dynamically. In this case you have to recompile the program with the
+support for the character set.
+@item
+The character set is a dynamic character set, but you don't have a
+configure file for it. In this case you should install the configure
+file for the character set from a new MySQL distribution.
+@item
+Your @file{Index} file doesn't contain the name for the character set.
+
+@example
+ERROR 1105: File '/usr/local/share/mysql/charsets/?.conf' not found
+(Errcode: 2)
+@end example
+
+In this case you should either get a new @code{Index} file or add
+by hand the name of any missing character sets.
+@end itemize
+
+For MyISAM tables, you can check the character set name and number for a
+table with @code{myisamchk -dvv table_name}.
+
+
+@node Server-Side Scripts, Client-Side Scripts, Localisation, MySQL Database Administration
@section MySQL Server-Side Scripts and Utilities
@menu
@@ -20754,7 +20691,7 @@ The list below briefly describes the MySQL programs:
@cindex @code{myisamchk}
@item myisamchk
-Utility to describe, check, optimize, and repair MySQL tables.
+Utility to describe, check, optimise, and repair MySQL tables.
Because @code{myisamchk} has many functions, it is described in its own
chapter. @xref{MySQL Database Administration}.
@@ -20861,7 +20798,7 @@ Most of the options to @code{safe_mysqld} are the same as the options to
@code{safe_mysqld} supports the following options:
-@table @code
+@itemize
@item --basedir=path
@item --core-file-size=#
Size of the core file @code{mysqld} should be able to create. Passed to @code{ulimit -c}.
@@ -20888,7 +20825,7 @@ Number of files @code{mysqld} should be able to open. Passed to @code{ulimit -n}
@item --timezone=#
Set the timezone (the @code{TZ}) variable to the value of this parameter.
@item --user=#
-@end table
+@end itemize
The @code{safe_mysqld} script is written so that it normally is able to start
a server that was installed from either a source or a binary version of
@@ -20941,7 +20878,7 @@ edited version that you can reinstall.
@cindex @code{mysqld_multi}
@code{mysqld_multi} is meant for managing several @code{mysqld}
-processes running in different UNIX sockets and TCP/IP ports.
+processes running in different Unix sockets and TCP/IP ports.
The program will search for group(s) named [mysqld#] from my.cnf (or the
given --config-file=...), where # can be any positive number starting
@@ -20968,10 +20905,10 @@ list. Anything after a white space is ignored.
@code{mysqld_multi} supports the following options:
-@table @code
+@itemize
@cindex config-file option
@item --config-file=...
-Alternative config file. NOTE: This will not affect this program's own
+Alternative config file. Note: This will not affect this program's own
options (group @code{[mysqld_multi]}), but only groups
[mysqld#]. Without this option everything will be searched from the
ordinary my.cnf file.
@@ -20983,7 +20920,7 @@ Give an example of a config file.
Print this help and exit.
@cindex log option
@item --log=...
-Log file. Full path to and the name for the log file. NOTE: If the file
+Log file. Full path to and the name for the log file. Note: If the file
exists, everything will be appended.
@cindex mysqladmin option
@item --mysqladmin=...
@@ -21004,16 +20941,16 @@ Password for user for @code{mysqladmin}.
@cindex tcp-ip option
@item --tcp-ip
Connect to the MySQL server(s) via the TCP/IP port instead of
-the UNIX socket. This affects stopping and reporting. If a socket file
+the Unix socket. This affects stopping and reporting. If a socket file
is missing, the server may still be running, but can be accessed only
-via the TCP/IP port. By default connecting is done via the UNIX socket.
+via the TCP/IP port. By default connecting is done via the Unix socket.
@cindex user option
@item --user=...
MySQL user for @code{mysqladmin}.
@cindex version option
@item --version
Print the version number and exit.
-@end table
+@end itemize
Some notes about @code{mysqld_multi}:
@@ -21033,7 +20970,7 @@ shell> mysql -u root -S /tmp/mysql.sock -proot_password -e
@xref{Privileges}.
@end example
You will have to do the above for each @code{mysqld} running in each
-data directory, that you have (just change the socket, -S=...)
+data directory, that you have (just change the socket, -S=...).
@item
@code{pid-file} is very important, if you are using @code{safe_mysqld}
to start @code{mysqld} (e.g. --mysqld=safe_mysqld) Every @code{mysqld}
@@ -21043,7 +20980,7 @@ should have its own @code{pid-file}. The advantage using
it, if a @code{mysqld} process fails due to signal kill -9, or
similar. (Like segmentation fault, which MySQL should never do,
of course ;) Please note that @code{safe_mysqld} script may require that
-you start it from a certain place. This means that you may have to CD to
+you start it from a certain place. This means that you may have to @code{cd} to
a certain directory, before you start the @code{mysqld_multi}. If
you have problems starting, please see the @code{safe_mysqld}
script. Check especially the lines:
@@ -21058,7 +20995,7 @@ release) if test -d /data/mysql -a -f ./share/mysql/english/errmsg.sys
The above test should be successful, or you may encounter problems.
@item
Beware of the dangers starting multiple @code{mysqlds} in the same data
-directory. Use separate data directories, unless you @strong{KNOW} what
+directory. Use separate data directories, unless you @strong{know} what
you are doing!
@item
The socket file and the TCP/IP port must be different for every @code{mysqld}.
@@ -21069,23 +21006,23 @@ more flexibility. The order in which the @code{mysqlds} are started or
stopped depends on the order in which they appear in the config file.
@item
When you want to refer to a certain group using GNR with this program,
-just use the number in the end of the group name ( [mysqld# <== ).
+just use the number in the end of the group name ([mysqld# <== ).
@item
You may want to use option '--user' for @code{mysqld}, but in order to
do this you need to be root when you start the @code{mysqld_multi}
script. Having the option in the config file doesn't matter; you will
just get a warning, if you are not the superuser and the @code{mysqlds}
-are started under @strong{YOUR} UNIX account. @strong{IMPORTANT}: Make
+are started under @strong{your} Unix account. @strong{Important}: Make
sure that the @code{pid-file} and the data directory are
-read+write(+execute for the latter one) accessible for @strong{THAT}
-UNIX user, who the specific @code{mysqld} process is started
-as. @strong{DON'T} use the UNIX root account for this, unless you
-@strong{KNOW} what you are doing!
-@item
-@strong{MOST IMPORTANT}: Make sure that you understand the meanings of
-the options that are passed to the @code{mysqlds} and why @strong{WOULD
-YOU WANT} to have separate @code{mysqld} processes. Starting multiple
-@code{mysqlds} in one data directory @strong{WILL NOT} give you extra
+read+write(+execute for the latter one) accessible for @strong{that}
+Unix user, who the specific @code{mysqld} process is started
+as. @strong{Do not} use the Unix root account for this, unless you
+@strong{know} what you are doing!
+@item
+@strong{Most important}: Make sure that you understand the meanings of
+the options that are passed to the @code{mysqld}s and @strong{why one
+would want} to have separate @code{mysqld} processes. Starting multiple
+@code{mysqld}s in one data directory @strong{will not} give you extra
performance in a threaded system!
@end itemize
@@ -21186,7 +21123,7 @@ file. It is permissible to omit the @file{.MYI} extension.
@code{myisampack} supports the following options:
-@table @code
+@itemize @bullet
@item -b, --backup
Make a backup of the table as @code{tbl_name.OLD}.
@@ -21208,7 +21145,7 @@ Display a help message and exit.
@item -j big_tbl_name, --join=big_tbl_name
Join all tables named on the command line into a single table
@code{big_tbl_name}. All tables that are to be combined
-MUST be identical (same column names and types, same indexes, etc.).
+@strong{must} be identical (same column names and types, same indexes, etc.).
@item -p #, --packlength=#
Specify the record length storage size, in bytes. The value should be 1, 2,
@@ -21240,7 +21177,7 @@ Wait and retry if table is in use. If the @code{mysqld} server was
invoked with the @code{--skip-locking} option, it is not a good idea to
invoke @code{myisampack} if the table might be updated during the
packing process.
-@end table
+@end itemize
@cindex examples, compressed tables
The sequence of commands shown below illustrates a typical table compression
@@ -21508,7 +21445,7 @@ The number of bits used in the Huffman tree.
After you have run @code{pack_isam}/@code{myisampack} you must run
@code{isamchk}/@code{myisamchk} to re-create the index. At this time you
can also sort the index blocks and create statistics needed for
-the MySQL optimizer to work more efficiently:
+the MySQL optimiser to work more efficiently:
@example
myisamchk -rq --analyze --sort-index table_name.MYI
@@ -21534,20 +21471,20 @@ the following configure options:
@multitable @columnfractions .3 .7
@item @strong{Option} @tab @strong{Comment}
@item --with-server-suffix=-max @tab Add a suffix to the @code{mysqld} version string.
-@item --with-bdb @tab Support for Berkeley DB (BDB) tables
@item --with-innodb @tab Support for InnoDB tables.
+@item --with-bdb @tab Support for Berkeley DB (BDB) tables
@item CFLAGS=-DUSE_SYMDIR @tab Symbolic links support for Windows.
@end multitable
You can find the MySQL-max binaries at
@uref{http://www.mysql.com/downloads/mysql-max-3.23.html}.
-The Windows MySQL 3.23 binary distribution includes both the
+The Windows MySQL binary distributions includes both the
standard @code{mysqld.exe} binary and the @code{mysqld-max.exe} binary.
@uref{http://www.mysql.com/downloads/mysql-3.23.html}.
@xref{Windows installation}.
-Note that as Berkeley DB and InnoDB are not available for all platforms,
+Note that as InnoDB and Berkeley DB are not available for all platforms,
some of the @code{Max} binaries may not have support for both of these.
You can check which table types are supported by doing the following
query:
@@ -21561,7 +21498,7 @@ mysql> show variables like "have_%";
| have_innodb | NO |
| have_isam | YES |
| have_raid | NO |
-| have_ssl | NO |
+| have_openssl | NO |
+---------------+-------+
@end example
@@ -21569,12 +21506,12 @@ The meaning of the values are:
@multitable @columnfractions .3 .7
@item @strong{Value} @tab @strong{Meaning}.
-@item YES @tab The option is activated and usable.
-@item NO @tab MySQL is not compiled with support for this option.
-@item DISABLED @tab The xxxx option is disabled because one started @code{mysqld} with @code{--skip-xxxx} or because one didn't start @code{mysqld} with all needed options to enable the option. In this case the @code{hostname.err} file should contain a reason for why the option is disabled.
+@item @code{YES} @tab The option is activated and usable.
+@item @code{NO} @tab MySQL is not compiled with support for this option.
+@item @code{DISABLED} @tab The xxxx option is disabled because one started @code{mysqld} with @code{--skip-xxxx} or because one didn't start @code{mysqld} with all needed options to enable the option. In this case the @code{hostname.err} file should contain a reason for why the option is disabled.
@end multitable
-@strong{NOTE}: To be able to create InnoDB tables you @strong{MUST} edit
+@strong{Note}: To be able to create InnoDB tables you @strong{must} edit
your startup options to include at least the @code{innodb_data_file_path}
option. @xref{InnoDB start}.
@@ -21605,7 +21542,7 @@ binaries includes:
@item Linux-Ia64 @tab N @tab Y
@item Solaris-intel @tab N @tab Y
@item Solaris-sparc @tab Y @tab Y
-@item SCO OSR5 @tab Y @tab Y
+@item Caldera (SCO) OSR5 @tab Y @tab Y
@item UnixWare @tab Y @tab Y
@item Windows/NT @tab Y @tab Y
@end multitable
@@ -21683,7 +21620,7 @@ The list below briefly describes the MySQL programs:
@cindex @code{myisamchk}
@item myisamchk
-Utility to describe, check, optimize, and repair MySQL tables.
+Utility to describe, check, optimise, and repair MySQL tables.
Because @code{myisamchk} has many functions, it is described in its own
chapter. @xref{MySQL Database Administration}.
@@ -21781,7 +21718,7 @@ retrieve the result set.
Using @code{mysql} is very easy. Just start it as follows:
@code{mysql database} or @code{mysql --user=user_name --password=your_password database}. Type a SQL statement, end it with @samp{;}, @samp{\g}, or @samp{\G}
-and press RETURN/ENTER.
+and press Enter.
@cindex @code{mysql} command line options
@cindex command line options, @code{mysql}
@@ -21840,8 +21777,8 @@ Continue even if we get a SQL error.
@cindex @code{no-named-commands}, @code{mysql} option
@item -g, --no-named-commands
Named commands are disabled. Use \* form only, or use named commands
-only in the beginning of a line ending with a semicolon (;). Since
-Version 10.9, the client now starts with this option ENABLED by default!
+only in the beginning of a line ending with a semicolon (@samp{;}). Since
+Version 10.9, the client now starts with this option @strong{enabled} by default!
With the -g option, long format commands will still work from the first
line, however.
@@ -21896,7 +21833,7 @@ other database in the update log.
@item @code{--pager[=...]}
Output type. Default is your @code{ENV} variable @code{PAGER}. Valid
pagers are less, more, cat [> filename], etc. See interactive help (\h)
-also. This option does not work in batch mode. Pager works only in UNIX.
+also. This option does not work in batch mode. Pager works only in Unix.
@cindex @code{password}, @code{mysql} option
@item -p[password], --password[=...]
@@ -21972,7 +21909,7 @@ You can also set the following variables with @code{-O} or
@cindex @code{select_limit}
@cindex @code{max_join_size}
@multitable @columnfractions .3 .2 .5
-@item Variable Name @tab Default @tab Description
+@item @strong{Variable Name} @tab @strong{Default} @tab @strong{Description}
@item connect_timeout @tab 0 @tab Number of seconds before timeout connection.
@item max_allowed_packet @tab 16777216 @tab Max packetlength to send/receive from to server
@item net_buffer_length @tab 16384 @tab Buffer for TCP/IP and socket communication
@@ -21991,24 +21928,30 @@ MySQL commands:
help (\h) Display this text.
? (\h) Synonym for `help'.
clear (\c) Clear command.
-connect (\r) Reconnect to the server. Optional arguments are db and host.
+connect (\r) Reconnect to the server.
+ Optional arguments are db and host.
edit (\e) Edit command with $EDITOR.
-ego (\G) Send command to mysql server, display result vertically.
+ego (\G) Send command to mysql server,
+ display result vertically.
exit (\q) Exit mysql. Same as quit.
go (\g) Send command to mysql server.
nopager (\n) Disable pager, print to stdout.
notee (\t) Don't write into outfile.
-pager (\P) Set PAGER [to_pager]. Print the query results via PAGER.
+pager (\P) Set PAGER [to_pager].
+ Print the query results via PAGER.
print (\p) Print current command.
quit (\q) Quit mysql.
rehash (\#) Rebuild completion hash.
-source (\.) Execute a SQL script file. Takes a file name as an argument.
+source (\.) Execute a SQL script file.
+ Takes a file name as an argument.
status (\s) Get status information from the server.
-tee (\T) Set outfile [to_outfile]. Append everything into given outfile.
-use (\u) Use another database. Takes database name as argument.
+tee (\T) Set outfile [to_outfile].
+ Append everything into given outfile.
+use (\u) Use another database.
+ Takes database name as argument.
@end example
-From the above, pager only works in UNIX.
+From the above, pager only works in Unix.
@cindex status command
The @code{status} command gives you some information about the
@@ -22095,7 +22038,7 @@ each command, just before the command line appears again waiting for the
next command.
@item
-Browsing, or searching the results in the interactive mode in UNIX less,
+Browsing, or searching the results in the interactive mode in Unix less,
more, or any other similar program, is now possible with option
@code{--pager[=...]}. Without argument, @code{mysql} client will look
for environment variable PAGER and set @code{pager} to that.
@@ -22104,7 +22047,7 @@ command @code{pager} and disabled with command @code{nopager}. The
command takes an argument optionally and the @code{pager} will be set to
that. Command @code{pager} can be called without an argument, but this
requires that the option @code{--pager} was used, or the @code{pager}
-will default to stdout. @code{pager} works only in UNIX, since it uses
+will default to stdout. @code{pager} works only in Unix, since it uses
the popen() function, which doesn't exist in Windows. In Windows, the
@code{tee} option can be used instead, although it may not be as handy
as @code{pager} can be in some situations.
@@ -22136,18 +22079,19 @@ following would send the results to two files in two different
directories, on two different hard-disks mounted on /dr1 and /dr2, yet
let the results still be seen on the screen via less:
@example
-mysql> pager cat | tee /dr1/tmp/res.txt | tee /dr2/tmp/res2.txt | less -n -i -S
+mysql> pager cat | tee /dr1/tmp/res.txt | \
+tee /dr2/tmp/res2.txt | less -n -i -S
@end example
@item
You can also combine the two functions above; have the @code{tee}
enabled, @code{pager} set to 'less' and you will be able to browse the
results in unix 'less' and still have everything appended into a file
-the same time. The difference between @code{UNIX tee} used with the
+the same time. The difference between Unix @code{tee} used with the
@code{pager} and the @code{mysql} client in-built @code{tee}, is that
-the in-built @code{tee} works even if you don't have the @code{UNIX tee}
+the in-built @code{tee} works even if you don't have the Unix @code{tee}
available. The in-built @code{tee} also logs everything that is printed
-on the screen, where the @code{UNIX tee} used with @code{pager} doesn't
+on the screen, where the Unix @code{tee} used with @code{pager} doesn't
log quite that much. Last, but not least, the interactive @code{tee} is
more handy to switch on and off, when you want to log something into a
file, but want to be able to turn the feature off sometimes.
@@ -22240,7 +22184,9 @@ shell> mysqladmin proc stat
+----+-------+-----------+----+-------------+------+-------+------+
| 6 | monty | localhost | | Processlist | 0 | | |
+----+-------+-----------+----+-------------+------+-------+------+
-Uptime: 10077 Threads: 1 Questions: 9 Slow queries: 0 Opens: 6 Flush tables: 1 Open tables: 2 Memory in use: 1092K Max memory used: 1116K
+Uptime: 10077 Threads: 1 Questions: 9 Slow queries: 0
+Opens: 6 Flush tables: 1 Open tables: 2
+Memory in use: 1092K Max memory used: 1116K
@end example
@cindex status command, results
@@ -22248,6 +22194,7 @@ The @code{mysqladmin status} command result has the following columns:
@cindex uptime
@multitable @columnfractions .3 .7
+@item @strong{Column} @tab @strong{Description}
@item Uptime @tab Number of seconds the MySQL server has been up.
@cindex threads
@item Threads @tab Number of active threads (clients).
@@ -22329,7 +22276,7 @@ Instead of making one query for each table, execute all queries in 1
query separately for each database. Table names will be in a comma
separated list.
@item -a, --analyze
-Analyze given tables.
+Analyse given tables.
@item --auto-repair
If a checked table is corrupted, automatically fix it. Repairing will be
done after all tables have been checked, if corrupted ones were found.
@@ -22368,7 +22315,7 @@ Connect to host.
Faster than extended-check, but only finds 99.99 percent of all
errors. Should be good enough for most cases.
@item -o, --optimize
-Optimize table
+Optimise table
@item -p, --password[=...]
Password to use when connecting to server. If password is not given
it's solicited on the tty.
@@ -22489,12 +22436,16 @@ is @code{localhost}.
Lock all tables before starting the dump. The tables are locked with
@code{READ LOCAL} to allow concurrent inserts in the case of @code{MyISAM}
tables.
+@item -K, --disable-keys
+@code{/*!40000 ALTER TABLE tb_name DISABLE KEYS */;} and
+@code{/*!40000 ALTER TABLE tb_name ENABLE KEYS */;}
+will be put in the output.
@item -n, --no-create-db
-'CREATE DATABASE /*!32312 IF NOT EXISTS*/ db_name;' will not be put in the
+@code{CREATE DATABASE /*!32312 IF NOT EXISTS*/ db_name;} will not be put in the
output. The above line will be added otherwise, if --databases or
--all-databases option was given.
@item -t, --no-create-info
-Don't write table creation information (The @code{CREATE TABLE} statement.)
+Don't write table creation information (the @code{CREATE TABLE} statement).
@item -d, --no-data
Don't write any row information for the table. This is very useful if you
just want to get a dump of the structure for a table!
@@ -22538,7 +22489,11 @@ Verbose mode. Print out more information on what the program does.
@item -V, --version
Print version information and exit.
@item -w, --where='where-condition'
-Dump only selected records. Note that QUOTES are mandatory:
+Dump only selected records. Note that quotes are mandatory:
+@item -X, --xml
+Dumps a database as well formed XML
+@item -x, --first-slave
+Locks all tables across all databases.
@example
"--where=user='jimf'" "-wuserid>1" "-wuserid<1"
@@ -22581,7 +22536,7 @@ mysqldump --opt database | mysql ---host=remote-host -C database
It is possible to dump several databases with one command:
@example
-mysqldump --databases database1 [database2 database3...] > my_databases.sql
+mysqldump --databases database1 [database2 ...] > my_databases.sql
@end example
If all the databases are wanted, one can use:
@@ -22618,11 +22573,11 @@ mysqlhotcopy db_name./regex/
@table @code
@item -?, --help
Display a help screen and exit
-@item -u, --user=#
+@item -u, --user=#
User for database login
@item -p, --password=#
Password to use when connecting to server
-@item -P, --port=#
+@item -P, --port=#
Port to use when connecting to local server
@item -S, --socket=#
Socket to use when connecting to local server
@@ -22682,7 +22637,7 @@ directly to the same options to @code{LOAD DATA INFILE}.
@code{mysqlimport} is invoked like this:
@example
-shell> mysqlimport [options] database textfile1 [textfile2....]
+shell> mysqlimport [options] database textfile1 [textfile2 ...]
@end example
For each text file named on the command line,
@@ -22733,8 +22688,8 @@ is @code{localhost}.
See the description for the @code{--replace} option.
@item -l, --lock-tables
-Lock @strong{ALL} tables for writing before processing any text files. This
-ensures that all tables are synchronized on the server.
+Lock @strong{all} tables for writing before processing any text files. This
+ensures that all tables are synchronised on the server.
@item -L, --local
Read input files from the client. By default, text files are assumed to be on
@@ -22858,22 +22813,32 @@ argument).
@cindex error messages, displaying
@cindex perror
-@code{perror} can be used to print error message(s). @code{perror} can
-be invoked like this:
+@cindex errno
+@cindex Errcode
+
+For most system errors MySQL will, in addition to a internal text message,
+also print the system error code in one of the following styles:
+@code{message ... (errno: #)} or @code{message ... (Errcode: #)}.
+
+You can find out what the error code means by either examining the
+documentation for your system or use the @code{perror} utility.
+
+@code{perror} prints a description for a system error code, or an MyISAM/ISAM
+table handler error code.
+
+@code{perror} is invoked like this:
@example
shell> perror [OPTIONS] [ERRORCODE [ERRORCODE...]]
-For example:
+Example:
-shell> perror 64 79
+shell> perror 13 64
+Error code 13: Permission denied
Error code 64: Machine is not on the network
-Error code 79: Can not access a needed shared library
@end example
-@code{perror} can be used to display a description for a system error
-code, or an MyISAM/ISAM table handler error code. The error messages
-are mostly system dependent.
+Note that the error messages are mostly system dependent!
@node Batch Commands, , perror, Client-Side Scripts
@@ -22916,6 +22881,7 @@ MySQL has several different log files that can help you find
out what's going on inside @code{mysqld}:
@multitable @columnfractions .3 .7
+@item @strong{Log file} @tab @strong{Description}
@item The error log @tab Problems encountering starting, running or stopping @code{mysqld}.
@item The isam log @tab Logs all changes to the ISAM tables. Used only for debugging the isam code.
@item The query log @tab Established connections and executed queries.
@@ -22944,7 +22910,7 @@ switch to a new log) by executing @code{FLUSH LOGS}. @xref{FLUSH}.
@code{mysqld} writes all errors to the stderr, which the
@code{safe_mysqld} script redirects to a file called
@code{'hostname'.err}. (On Windows, @code{mysqld} writes this directly
-to @file{\mysql\data\mysql.err}).
+to @file{\mysql\data\mysql.err}.)
This contains information indicating when @code{mysqld} was started and
stopped and also any critical errors found when running. If @code{mysqld}
@@ -22988,7 +22954,7 @@ after the query is executed, but before any locks are released.
@cindex update log
@cindex files, update log
-@strong{NOTE}: The update log is replaced by the binary
+@strong{Note}: The update log is replaced by the binary
log. @xref{Binary log}. With this you can do anything that you can do
with the update log.
@@ -23002,7 +22968,7 @@ extension, @code{mysqld} will create log file names like so:
time you execute @code{mysqladmin refresh}, execute @code{mysqladmin
flush-logs}, execute the @code{FLUSH LOGS} statement, or restart the server.
-@strong{NOTE:} For the above scheme to work, you should NOT create
+@strong{Note:} For the above scheme to work, you must not create
your own files with the same filename as the update log + some extensions
that may be regarded as a number, in the directory used by the update log!
@@ -23067,15 +23033,20 @@ file is written in the data directory.
If you supply an extension to @code{--log-bin=filename.extension}, the
extension will be silenty removed.
-To the binary log filename @code{mysqld} will append an extension that is a
-number that is incremented each time you execute @code{mysqladmin
-refresh}, execute @code{mysqladmin flush-logs}, execute the @code{FLUSH LOGS}
-statement or restart the server.
+To the binary log filename @code{mysqld} will append an extension that
+is a number that is incremented each time you execute @code{mysqladmin
+refresh}, execute @code{mysqladmin flush-logs}, execute the @code{FLUSH
+LOGS} statement or restart the server. A new binary log will also
+automaticly be created when it reaches @code{max_bin_log_size}. You can
+delete all not active binary log files with the @code{RESET MASTER}
+command. @xref{RESET}.
You can use the following options to @code{mysqld} to affect what is logged
to the binary log:
@multitable @columnfractions .4 .6
+@item @strong{Option} @tab @strong{Description}
+
@item @code{binlog-do-db=database_name} @tab
Tells the master it should log updates for the specified database, and
exclude all others not explicitly mentioned.
@@ -23156,7 +23127,7 @@ suffixed with @code{-slow.log}. If a filename is given, but doesn't
contain a path, the file is written in the data directory.
The slow query log can be used to find queries that take a long time to
-execute and are thus candidates for optimization. With a large log, that
+execute and are thus candidates for optimisation. With a large log, that
can become a difficult task. You can pipe the slow query log through the
@code{mysqldumpslow} command to get a summary of the queries which
appear in the log.
@@ -23199,7 +23170,7 @@ The above command does the following:
@itemize @bullet
@item
If standard logging (@code{--log}) or slow query logging
-(@code{--log-slow-queries}) is used, closes and reopens the log file.
+(@code{--log-slow-queries}) is used, closes and reopens the log file
(@file{mysql.log} and @file{`hostname`-slow.log} as default).
@item
If update logging (@code{--log-update}) is used, closes the update log and
@@ -23238,12 +23209,16 @@ and then take a backup and remove @file{mysql.old}.
* Replication Problems:: Troubleshooting Replication
@end menu
-This chapter describes the various replication features in MySQL.
+This section describes the various replication features in MySQL.
It serves as a reference to the options available with replication.
-You will be introduced to replication and learn how to implement it.
-Towards the end, there are some frequently asked questions and descriptions
+You will be introduced to replication and learn how to implement it.
+Towards the end, there are some frequently asked questions and descriptions
of problems and how to solve them.
+We suggest that you visit our website at @uref{http://www.mysql.com/}
+often and read updates to this section. Replication is constantly being
+improved, and we update the manual frequently with the most current
+information.
@node Replication Intro, Replication Implementation, Replication, Replication
@subsection Introduction
@@ -23259,7 +23234,7 @@ Starting in Version 3.23.15, MySQL supports one-way replication
internally. One server acts as the master, while the other acts as the
slave. Note that one server could play the roles of master in one pair
and slave in the other. The master server keeps a binary log of updates
-(@xref{Binary log}.) and an index file to binary logs to keep track of
+(@pxref{Binary log}) and an index file to binary logs to keep track of
log rotation. The slave, upon connecting, informs the master where it
left off since the last successfully propagated update, catches up on
the updates, and then blocks and waits for the master to notify it of
@@ -23280,11 +23255,11 @@ master. @xref{Backup}.
MySQL replication is based on the server keeping track of all
changes to your database (updates, deletes, etc) in the binary
-log. (@xref{Binary log}.) and the slave server(s) reading the saved
+log (@pxref{Binary log}) and the slave server(s) reading the saved
queries from the master server's binary log so that the slave can
execute the same queries on its copy of the data.
-It is @strong{very important} to realize that the binary log is simply a
+It is @strong{very important} to realise that the binary log is simply a
record starting from a fixed point in time (the moment you enable binary
logging). Any slaves which you set up will need copies of all the data
from your master as it existed the moment that you enabled binary
@@ -23292,11 +23267,29 @@ logging on the master. If you start your slaves with data that doesn't
agree with what was on the master @strong{when the binary log was
started}, your slaves may fail.
-A future version (4.0) of MySQL will remove the need to keep a
-(possibly large) snapshot of data for new slaves that you might wish to
-set up through the live backup functionality with no locking required.
-However, at this time, it is necessary to block all writes either with a
-global read lock or by shutting down the master while taking a snapshot.
+Starting in 4.0.0, one can use @code{LOAD DATA FROM MASTER} to set up
+a slave. Note that 4.0.0 slaves cannot communicate with 3.23 masters, but 4.0.1
+and later version slaves can. 3.23 slave cannot talk to 4.0 master.
+
+You must also be aware that @code{LOAD DATA FROM MASTER} currently works only
+if all the tables on the master are @code{MyISAM} type, and will acuire a
+global read lock, so no writes are possible while the tables are being
+transferred from the master. This limitation is of a temporary nature, and is
+due to the fact that we have not yet implemented hot lock-free table backup.
+It will be removed in the future 4.0 branch versions once we implemented hot
+backup enabling @code{LOAD DATA FROM MASTER} to work without blocking master
+updates.
+
+Due to the above limitation, we recommend that at this point you use
+@code{LOAD DATA FROM MASTER} only if the dataset on the master is relatively
+small, or if a prolonged read lock on the master is acceptable. While the
+actual speed of @code{LOAD DATA FROM MASTER} may vary from system to system,
+a good rule for a rough estimate of how long it is going to take is 1 second
+per 1 MB of the data file. You will get close to the estimate if both master
+and slave are equivalent to 700 MHz Pentium, are connected through
+100 MBit/s network, and your index file is about half the size of your data
+file. Of course, your mileage will vary from system to system, the above rule
+just gives you a rough order of magnitude estimate.
Once a slave is properly configured and running, it will simply connect
to the master and wait for updates to process. If the master goes away
@@ -23320,6 +23313,19 @@ your databases and have not configured replication before. You will need
to shutdown your master server briefly to complete the steps outlined
below.
+While the above method is the most straightforward way to set up a slave,
+it is not the only one. For example, if you already have a snapshot
+of the master, and
+the master already has server id set and binary logging enabled, one can
+set up a slave without shutting the master down or even blocking the updates.
+For more details, please see @ref{Replication FAQ}.
+
+If you want to become a real MySQL replication guru, we suggest that you
+begin with studing, pondering, and trying all commands
+mentioned in @ref{Replication SQL}. You should also familiarize yourself
+with replication startup options in @code{my.cnf} in
+@xref{Replication Options}.
+
@enumerate
@item
Make sure you have a recent version of MySQL installed on the master
@@ -23437,16 +23443,6 @@ of the master's binary log is has processed. @strong{Do not} remove or
edit the file, unless you really know what you are doing. Even in that case,
it is preferred that you use @code{CHANGE MASTER TO} command.
-
-@menu
-* Replication Features:: Replication Features and Known Problems
-* Replication Options:: Replication Options in my.cnf
-* Replication SQL:: SQL Commands Related to Replication
-* Replication FAQ:: Replication FAQ
-* Replication Problems:: Troubleshooting Replication
-@end menu
-
-
@node Replication Features, Replication Options, Replication HOWTO, Replication
@subsection Replication Features and Known Problems
@@ -23459,7 +23455,7 @@ Below is an explanation of what is supported and what is not:
@itemize @bullet
@item
Replication will be done correctly with @code{AUTO_INCREMENT},
-@code{LAST_INSERT_ID}, and @code{TIMESTAMP} values.
+@code{LAST_INSERT_ID()}, and @code{TIMESTAMP} values.
@item
@code{RAND()} in updates does not replicate properly. Use
@code{RAND(some_non_rand_expr)} if you are replicating updates with
@@ -23471,9 +23467,11 @@ on the master and the slave. If not, you may get duplicate key errors on
the slave, because a key that is regarded as unique on the master may
not be that in the other character set.
@item
-@code{LOAD DATA INFILE} will be handled properly as long as the file
+In 3.23, @code{LOAD DATA INFILE} will be handled properly as long as the file
still resides on the master server at the time of update
-propagation. @code{LOAD LOCAL DATA INFILE} will be skipped.
+propagation. @code{LOAD LOCAL DATA INFILE} will be skipped. In 4.0, this
+limitation is not present - all forms of @code{LOAD DATA INFILE} are properly
+replicated.
@item
Update queries that use user variables are not replication-safe (yet).
@item
@@ -23494,7 +23492,7 @@ check @code{Slave_open_temp_tables} variable to see if it is 0, then issue
with @code{SLAVE START} and see
if you have better luck next time. There will be a cleaner solution, but it
has to wait until version 4.0.
-In earlier versions temporary tables are not being replicated properly - we
+In earlier versions temporary tables are not replicated properly - we
recommend that you either upgrade, or execute @code{SET SQL_LOG_BIN=0} on
your clients before all queries with temp tables.
@item
@@ -23568,11 +23566,6 @@ what they do. The old @code{FLUSH} variants still work, though, for
compatibility.
@item
-Starting in Version 3.23.21, you can use @code{LOAD TABLE FROM MASTER} for
-network backup and to set up replication initially. We have recently
-received a number of bug reports concerning it that we are investigating, so
-we recommend that you use it only in testing until we make it more stable.
-@item
Starting in Version 3.23.23, you can change masters and adjust log position
with @code{CHANGE MASTER TO}.
@item
@@ -23585,6 +23578,39 @@ with a different name on the slave.
@item
Starting in Version 3.23.28, you can use @code{PURGE MASTER LOGS TO 'log-name'}
to get rid of old logs while the slave is running.
+@item
+Due to the non-transactional nature of MyISAM tables, it is possible to have
+a query that will only partially update a table and return an error code. This
+can happen, for example, on a multi-row insert that has one row violating a
+key constraint, or if a long update query is killed after updating some of the
+rows. If that happens on the master, the slave thread will exit and wait for
+the DBA to decide what to do about it unless the error code is legitimate and
+the query execution results in the same error code. If this error code
+validation behaviour is not desirable, some ( or all) errors could be masked
+out with @code{slave-skip-errors} option starting in Version 3.23.47.
+@item
+While individual tables can be excluded from replication with
+@code{replicate-do-table}/@code{replicate-ignore-table} or
+@code{replicate-wild-do-table}/@code{replicate-wild-ignore-table}, there
+are currently some design deficiencies that in some rather rare cases
+produce unexpected results. The replication protocol does not inform the
+slave explicitly which tables are going to be modified by the query - so
+the slave has to parse the query to know this. To avoid redundant
+parsing for queries that will end up actually being executed, table
+exclusion is currently implemented by sending the query to the standard
+MySQL parser, which will short-circuit the query and report success if
+it detects that the table should be ignored. In addition to several
+inefficiencies, this approach is also more bug prone, and there are two
+known bugs as of Version 3.23.49 - because the parser automatically opens
+the table when parsing some queries the ignored table has to exist on
+the slave. The other bug is that if the ignored table gets partially
+updated, the slave thread will not notice that the table actually should
+have been ignored and will suspend the replication process. While the
+above bugs are conceptually very simple to fix, we have not yet found a way
+to do this without a sigficant code change that would compromize the stability
+status of 3.23 branch. There exists a workaround for both if in the rare case
+it happens to affect your application - use @code{slave-skip-errors}.
+
@end itemize
@@ -23593,7 +23619,17 @@ to get rid of old logs while the slave is running.
If you are using replication, we recommend you to use MySQL Version
3.23.30 or later. Older versions work, but they do have some bugs and are
-missing some features.
+missing some features. Some of the options below may not be available in
+your version if it is not the most recent one. For all options specific to
+the 4.0 branch, there is a note indicating so. Otherwise, if you discover
+that the option you are interested in is not available in your 3.23 version,
+and you really need it, please upgrade to the most recent 3.23 branch.
+
+Please be aware that 4.0 branch is still in alpha, so some things may not be
+working as smoothly as you would like. If you really would like to try
+the new features of 4.0, we recommend you do it in such a way that in
+case there is a problem your mission critical applications will not be
+disrupted.
On both master and slave you need to use the @code{server-id} option.
This sets an unique replication id. You should pick a unique value in the
@@ -23603,8 +23639,8 @@ Example: @code{server-id=3}
The following table has the options you can use for the @strong{MASTER}:
@multitable @columnfractions .3 .7
-
@item @strong{Option} @tab @strong{Description}
+
@item @code{log-bin=filename} @tab
Write to a binary update log to the specified location. Note that if you
give it a parameter with an extension (for example,
@@ -23635,7 +23671,7 @@ current database is 'database_name'. All others database are ignored.
Note that if you use this you should ensure that you only do updates in
the current database.
-Example: @code{binlog-do-db=some_database}.
+Example: @code{binlog-do-db=sales}.
@item @code{binlog-ignore-db=database_name} @tab
Tells the master that updates where the current database is
@@ -23643,47 +23679,72 @@ Tells the master that updates where the current database is
you use this you should ensure that you only do updates in the current
database.
-Example: @code{binlog-ignore-db=some_database}
+Example: @code{binlog-ignore-db=accounting}
@end multitable
The following table has the options you can use for the @strong{SLAVE}:
@multitable @columnfractions .3 .7
-
@item @strong{Option} @tab @strong{Description}
+
@item @code{master-host=host} @tab
Master hostname or IP address for replication. If not set, the slave
-thread will not be started.
+thread will not be started. Note that the setting of @code{master-host}
+will be ignored if there exists a valid @code{master.info} file. Probably a
+better name for this options would have been something like
+@code{bootstrap-master-host}, but it is too late to change now.
Example: @code{master-host=db-master.mycompany.com}.
@item @code{master-user=username} @tab
-The user the slave thread will us for authentication when connecting to
+The username the slave thread will use for authentication when connecting to
the master. The user must have @code{FILE} privilege. If the master user
-is not set, user @code{test} is assumed.
+is not set, user @code{test} is assumed. The value in @code{master.info} will
+take precedence if it can be read.
Example: @code{master-user=scott}.
@item @code{master-password=password} @tab
The password the slave thread will authenticate with when connecting to
-the master. If not set, an empty password is assumed.
+the master. If not set, an empty password is assumed.The value in
+@code{master.info} will take precedence if it can be read.
Example: @code{master-password=tiger}.
@item @code{master-port=portnumber} @tab
The port the master is listening on. If not set, the compiled setting of
@code{MYSQL_PORT} is assumed. If you have not tinkered with
-@code{configure} options, this should be 3306.
+@code{configure} options, this should be 3306. The value in
+@code{master.info} will take precedence if it can be read.
Example: @code{master-port=3306}.
@item @code{master-connect-retry=seconds} @tab
The number of seconds the slave thread will sleep before retrying to
connect to the master in case the master goes down or the connection is
-lost. Default is 60.
+lost. Default is 60.
Example: @code{master-connect-retry=60}.
+@item @code{master-ssl} @tab
+Available after 4.0.0. Turn SSL on for replication. Be warned that is
+this is a relatively new feature.
+
+Example: @code{master-ssl}.
+
+@item @code{master-ssl-key} @tab
+Available after 4.0.0. Master SSL keyfile name. Only applies if you have
+enabled @code{master-ssl}.
+
+Example: @code{master-ssl-key=SSL/master-key.pem}.
+
+@item @code{master-ssl-cert} @tab
+Available after 4.0.0. Master SSL certificate file name. Only applies if
+you have enabled @code{master-ssl}.
+
+
+Example: @code{master-ssl-key=SSL/master-cert.pem}.
+
@item @code{master-info-file=filename} @tab
The location of the file that remembers where we left off on the master
during the replication process. The default is master.info in the data
@@ -23692,6 +23753,23 @@ is the desire to be rebelious.
Example: @code{master-info-file=master.info}.
+@item @code{report-host} @tab
+Available after 4.0.0. Hostname or IP of the slave to be reported to to
+the master during slave registration. Will appear in the output of
+@code{SHOW SLAVE HOSTS}. Leave unset if you do not want the slave to
+register itself with the master. Note that it is not sufficient for the
+master to simply read the IP of the slave off the socket once the slave
+connects. Due to @code{NAT} and other routing issues, that IP may not be
+valid for connecting to the slave from the master or other hosts.
+
+Example: @code{report-host=slave1.mycompany.com}
+
+@item @code{report-port} @tab
+Available after 4.0.0. Port for connecting to slave reported to the
+master during slave registration. Set it only if the slave is listening
+on a non-default port or if you have a special tunnel from the master or
+other clients to the slave. If not sure, leave this option unset.
+
@item @code{replicate-do-table=db_name.table_name} @tab
Tells the slave thread to restrict replication to the specified table.
To specify more than one table, use the directive multiple times, once
@@ -23760,13 +23838,13 @@ Updates to a database with a different name than the original
Example: @code{replicate-rewrite-db=master_db_name->slave_db_name}.
-@item @code{slave-skip-errors=err_code1,err_code2,..} @tab
+@item @code{slave-skip-errors=err_code1,err_code2,...} @tab
Available only in 3.23.47 and later. Tells the slave thread to continue
replication when a query returns an error from the provided
list. Normally, replication will discontinue when an error is
encountered giving the user a chance to resolve the inconsistency in the
data manually. Do not use this option unless you fully understand why
-you are getting the errors. If there are no bugs in your
+you are getting the errors. If there are no bugs in your
replication setup and client programs, and no bugs in MySQL itself, you
should never get an abort with error.Indiscriminate use of this option
will result in slaves being hopelessly out of sync with the master and
@@ -23839,7 +23917,21 @@ logs. In pre 3.23.26 versions the command was called
@code{FLUSH SLAVE}(Slave)
@item @code{LOAD TABLE tblname FROM MASTER}
- @tab Downloads a copy of the table from master to the slave. (Slave)
+ @tab Downloads a copy of the table from master to the slave. Implemented
+ mainly for debugging of @code{LOAD DATA FROM MASTER}, but some "gourmet"
+ users might find it useful for other things. Do not use it if you consider
+ yourself the average "non-hacker" type user. (Slave)
+
+@item @code{LOAD DATA FROM MASTER} @tab
+Available starting in 4.0.0. Takes a snapshot of the master and copies
+it to the slave. Updates the values of @code{MASTER_LOG_FILE} and
+@code{MASTER_LOG_POS} so that the slave will start replicating from the
+correct position. Will honor table and database exclusion rules
+specified with @code{replicate-*} options. So far works only with
+@code{MyISAM} tables and acquires a global read lock on the master while
+taking the snapshot. In the future it is planned to make it work with
+@code{InnoDB} tables and to remove the need for global read lock using
+the non-blocking online backup feature.
@item @code{CHANGE MASTER TO master_def_list}
@tab Changes the master parameters to the values specified in
@@ -23847,10 +23939,9 @@ logs. In pre 3.23.26 versions the command was called
is a comma-separated list of @code{master_def} where @code{master_def} is
one of the following: @code{MASTER_HOST}, @code{MASTER_USER},
@code{MASTER_PASSWORD}, @code{MASTER_PORT}, @code{MASTER_CONNECT_RETRY},
-@code{MASTER_LOG_FILE}, @code{MASTER_LOG_POS}. Example:
+@code{MASTER_LOG_FILE}, @code{MASTER_LOG_POS}. For example:
@example
-
CHANGE MASTER TO
MASTER_HOST='master2.mycompany.com',
MASTER_USER='replication',
@@ -23858,7 +23949,6 @@ CHANGE MASTER TO
MASTER_PORT=3306,
MASTER_LOG_FILE='master2-bin.001',
MASTER_LOG_POS=4;
-
@end example
You only need to specify the values that need to be changed. The values that
@@ -23870,12 +23960,46 @@ automatically be reset to an empty string and 0, respectively (the start
values). Note that if you restart the slave, it will remember its last master.
If this is not desirable, you should delete the @file{master.info} file before
restarting, and the slave will read its master from @code{my.cnf} or the
-command line. (Slave)
+command line.
+
+This command is useful for setting up a slave when you have the snapshot of
+the master and have record the log and the offset on the master that the
+snapshot corresponds to. You can run
+ @code{CHANGE MASTER TO MASTER_LOG_FILE='log_name_on_master',
+ MASTER_LOG_POS=log_offset_on_master} on the slave after restoring the
+snapshot.
+
+(Slave)
@item @code{SHOW MASTER STATUS} @tab Provides status information on the binlog of the master. (Master)
+@item @code{SHOW SLAVE HOSTS} @tab Available after 4.0.0. Gives a
+listing of slaves currently registered with the master (Master)
+
@item @code{SHOW SLAVE STATUS} @tab Provides status information on essential parameters of the slave thread. (Slave)
-@item @code{SHOW MASTER LOGS} @tab Only available starting in Version 3.23.28. Lists the binary logs on the master. You should use this command prior to @code{PURGE MASTER LOGS TO} to find out how far you should go.
+
+@item @code{SHOW MASTER LOGS} @tab Only available starting in Version
+3.23.28. Lists the binary logs on the master. You should use this
+command prior to @code{PURGE MASTER LOGS TO} to find out how far you
+should go. (Master)
+
+@item @code{SHOW BINLOG EVENTS [ IN 'logname' ] [ FROM pos ]
+ [ LIMIT [offset,] rows ] } @tab
+Shows the events in the binary update log. Primarily used for
+testing/debugging, but can also be used by regular clients that for some
+reason need to read the binary log contents. (Master)
+
+@item @code{SHOW NEW MASTER FOR SLAVE WITH MASTER_LOG_FILE='logfile' AND
+ MASTER_LOG_POS=pos AND
+MASTER_LOG_SEQ=log_seq AND MASTER_SERVER_ID=server_id} @tab
+This command is used when a slave of a possibly dead/unavailable master
+needs to be switched to replicate off another slave that has been
+replicating the same master. The command will return recalculated
+replication coordinates, and the output can be used in a subsequent
+@code{CHANGE MASTER TO} command. Normal users should never need to run
+this command. It is primarily reserved for internal use by the fail-safe
+replication code. We may later change the syntax if we find a more
+intuitive way to describe this operation.
@item @code{PURGE MASTER LOGS TO 'logname'}
@tab Available starting in Version 3.23.28. Deletes all the
@@ -23907,6 +24031,87 @@ last log on the list), backup all the logs you are about to delete
@node Replication FAQ, Replication Problems, Replication SQL, Replication
@subsection Replication FAQ
+@strong{Q}: How do I configure a slave if the master is already running
+and I do not want to stop it?
+
+@strong{A}: There are several options. If you have taken a backup of the
+master at some point and recorded the binlog name and offset ( from the
+output of @code{SHOW MASTER STATUS} ) corresponding to the snapshot, do
+the following:
+
+@itemize @bullet
+@item
+Make sure unique server id is assigned to the slave.
+@item
+Execute @code{CHANGE MASTER TO MASTER_HOST='master-host-name',
+ MASTER_USER='master-user-name', MASTER_PASSWORD='master-pass',
+ MASTER_LOG_FILE='recorded-log-name', MASTER_LOG_POS=recorded_log_pos}
+@item
+Execute @code{SLAVE START}
+@end itemize
+
+If you do not have a backup of the master already, here is a quick way to
+do it consistently:
+
+@itemize @bullet
+@item
+@code{FLUSH TABLES WITH READ LOCK}
+@item
+@code{gtar zcf /tmp/backup.tar.gz /var/lib/mysql} ( or a variation of this)
+@item
+@code{SHOW MASTER STATUS} - make sure to record the output - you will need it
+later
+@item
+@code{UNLOCK TABLES}
+@end itemize
+
+Afterwards, follow the instructions for the case when you have a snapshot and
+have records the log name and offset. You can use the same snapshot to set up
+several slaves. As long as the binary logs of the master are left intact, you
+can wait as long as several days or in some cases maybe a month to set up a
+slave once you have the snapshot of the master. In theory the waiting gap can
+be infinite. The two practical limitations is the diskspace of the master
+getting filled with old logs, and the amount of time it will take the slave to
+catch up.
+
+In version 4.0.0 and newer, you can also use @code{LOAD DATA FROM
+MASTER}. This is a convenient command that will take a snapshot,
+restore it to the slave, and adjust the log name and offset on the slave
+all at once. In the future, @code{LOAD DATA FROM MASTER} will be the
+recommended way to set up a slave. Be warned, howerver, that the read
+lock may be held for a long time if you use this command. It is not yet
+implemented as efficiently as we would like to have it. If you have
+large tables, the preferred method at this time is still with a local
+@code{tar} snapshot after executing @code{FLUSH TABLES WITH READ LOCK}.
+
+@strong{Q}: Does the slave need to be connected to the master all the time?
+
+@strong{A}: No, it does not. You can have the slave go down or stay
+disconnected for hours or even days, then reconnect, catch up on the
+updates, and then disconnect or go down for a while again. So you can,
+for example, use master-slave setup over a dial-up link that is up only
+for short periods of time. The implications of that are that at any
+given time the slave is not guaranteed to be in sync with the master
+unless you take some special measures. In the future, we will have the
+option to block the master until at least one slave is in sync.
+
+@strong{Q}: How do I force the master to block updates until the slave catches
+up?
+
+@strong{A}: Execute the following commands:
+
+@itemize @bullet
+@item
+Master: @code{FLUSH TABLES WITH READ LOCK}
+@item
+Master: @code{SHOW MASTER STATUS} - record the log name and the offset
+@item
+Slave: @code{SELECT MASTER_POS_WAIT('recorded_log_name', recorded_log_offset)}
+When the select returns, the slave is currently in sync with the master
+@item
+Master: @code{UNLOCK TABLES} - now the master will continue updates.
+@end itemize
+
@cindex @code{Binlog_Dump}
@strong{Q}: Why do I sometimes see more than one @code{Binlog_Dump} thread on
the master after I have restarted the slave?
@@ -23964,7 +24169,7 @@ can connect.
After 3.23.26, we have locked the replication protocol for modifications, so
you can upgrade masters and slave on the fly to a newer 3.23 version and you
can have different versions of MySQL running on the slave and the
-master, as long as they are both newer than 3.23.26.
+master, as long as they are both newer than 3.23.26.
@cindex replication, two-way
@strong{Q}: What issues should I be aware of when setting up two-way
@@ -23985,12 +24190,12 @@ can safely happen in any order, or unless you take care of mis-ordered
updates somehow in the client code.
-You must also realize that two-way replication actually does not improve
+You must also realise that two-way replication actually does not improve
performance very much, if at all, as far as updates are concerned. Both
servers need to do the same amount of updates each, as you would have
one server do. The only difference is that there will be a little less
lock contention, because the updates originating on another server will
-be serialized in one slave thread. This benefit, though, might be
+be serialised in one slave thread. This benefit, though, might be
offset by network delays.
@cindex performance, improving
@@ -24011,7 +24216,7 @@ performance-enhancing replication?
@strong{A}:
If the part of your code that is responsible for database access has
-been properly abstracted/modularized, converting it to run with the
+been properly abstracted/modularised, converting it to run with the
replicated setup should be very smooth and easy - just change the
implementation of your database access to read from some slave or the
master, and to always write to the master. If your code does not have
@@ -24042,13 +24247,13 @@ able to take advantage of one-master/many slaves solution. The
code will be a lot easier to maintain, and adding troubleshooting
options will be trivial. You will just need to modify one or two
functions, for example, to log how long each query took, or which
-query, among your many thousands, gave you an error. If you have written a lot of code already,
-you may want to automate the conversion task by using Monty's
-@code{replace} utility, which comes with the standard distribution of
-MySQL, or just write your own Perl script. Hopefully, your
-code follows some recognizable pattern. If not, then you are probably
-better off re-writing it anyway, or at least going through and manually
-beating it into a pattern.
+query, among your many thousands, gave you an error. If you have
+written a lot of code already, you may want to automate the conversion
+task by using Monty's @code{replace} utility, which comes with the
+standard distribution of MySQL, or just write your own Perl script.
+Hopefully, your code follows some recognisable pattern. If not, then
+you are probably better off re-writing it anyway, or at least going
+through and manually beating it into a pattern.
Note that, of course, you can use different names for the
functions. What is important is having unified interface for connecting
@@ -24180,7 +24385,7 @@ If the slave is running, did it establish connection with the master? Do
@code{State} column. If it says @code{connecting to master}, verify the
privileges for the replication user on the master, master host name, your
DNS setup, whether the master is actually running, whether it is reachable
-from the slave, and if all that seems ok, read the error logs.
+from the slave, and if all that seems okay, read the error logs.
@item
If the slave was running, but then stopped, look at SHOW SLAVE STATUS
output and check the error logs. It usually
@@ -24287,33 +24492,33 @@ isolate it into a separate test case first. Then report the problem to
-@node MySQL Optimization, Reference, MySQL Database Administration, Top
-@chapter MySQL Optimization
+@node MySQL Optimisation, Reference, MySQL Database Administration, Top
+@chapter MySQL Optimisation
@menu
-* Optimize Overview:: Optimization Overview
-* Query Speed:: Optimizing @code{SELECT}s and Other Queries
+* Optimise Overview:: Optimisation Overview
+* Query Speed:: Optimising @code{SELECT}s and Other Queries
* Locking Issues:: Locking Issues
-* Optimizing Database Structure:: Optimizing Database Structure
-* Optimizing the Server:: Optimizing the MySQL Server
+* Optimising Database Structure:: Optimising Database Structure
+* Optimising the Server:: Optimising the MySQL Server
* Disk issues:: Disk Issues
@end menu
-Optimization is a complicated task because it ultimately requires
+Optimisation is a complicated task because it ultimately requires
understanding of the whole system. While it may be possible to do some
-local optimizations with small knowledge of your system or application,
+local optimisations with small knowledge of your system or application,
the more optimal you want your system to become the more you will have
to know about it.
This chapter will try to explain and give some examples of different
-ways to optimize MySQL. Remember, however, that there are
+ways to optimise MySQL. Remember, however, that there are
always some (increasingly harder) additional ways to make the system
even faster.
-@node Optimize Overview, Query Speed, MySQL Optimization, MySQL Optimization
-@section Optimization Overview
+@node Optimise Overview, Query Speed, MySQL Optimisation, MySQL Optimisation
+@section Optimisation Overview
The most important part for getting a system fast is of course the basic
design. You also need to know what kinds of things your system will be
@@ -24324,14 +24529,14 @@ The most common bottlenecks are:
@item Disk seeks.
It takes time for the disk to find a piece of data. With modern disks in
1999, the mean time for this is usually lower than 10ms, so we can in
-theory do about 1000 seeks a second. This time improves slowly with new
-disks and is very hard to optimize for a single table. The way to
-optimize this is to spread the data on more than one disk.
+theory do about 100 seeks a second. This time improves slowly with new
+disks and is very hard to optimise for a single table. The way to
+optimise this is to spread the data on more than one disk.
@item Disk reading/writing.
When the disk is at the correct position we need to read the data. With
-modern disks in 1999, one disk delivers something like 10-20Mb/s. This
-is easier to optimize than seeks because you can read in parallel from
+modern disks in 1999, one disk delivers something like 10-20MB/s. This
+is easier to optimise than seeks because you can read in parallel from
multiple disks.
@item CPU cycles.
@@ -24356,26 +24561,51 @@ for most systems, but one should be aware of it.
@end menu
-@node Design Limitations, Portability, Optimize Overview, Optimize Overview
+@node Design Limitations, Portability, Optimise Overview, Optimise Overview
@subsection MySQL Design Limitations/Tradeoffs
@cindex design, limitations
@cindex limitations, design
-Because MySQL uses extremely fast table locking (multiple readers /
-single writers) the biggest remaining problem is a mix of a steady stream of
-inserts and slow selects on the same table.
+When using the MyISAM table handler, MySQL uses extremely fast table
+locking (multiple readers / single writers). The biggest problem with
+this table type is a if you have a mix of a steady stream of updates and
+slow selects on the same table. If this is a problem with some tables,
+you can use another table type for these. @xref{Table types}.
-We believe that for a huge number of systems the extremely fast
-performance in other cases make this choice a win. This case is usually
-also possible to solve by having multiple copies of the table, but it
-takes more effort and hardware.
+MySQL can work with both transactional and not transactional tables. To
+be able to work smoothly with not transactional tables (which can't
+rollback if something goes wrong), MySQL has the following rules:
-We are also working on some extensions to solve this problem for some
-common application niches.
+@cindex default values
+@itemize @bullet
+@item
+All columns has default values.
+@item
+If you insert a 'wrong' value in a column like a @code{NULL} in a
+@code{NOT NULL} column or a too big numerical value in a numerical
+column, MySQL will instead of giving an error instead set the column to
+the 'best possible value'. For numerical values this is 0, the smallest
+possible values or the largest possible value. For strings this is
+either the empty string or the longest possible string that can be in
+the column.
+@item
+All calculated expressions returns a value that can be used instead of
+signaling an error condition. For example 1/0 returns @code{NULL}
+@end itemize
+
+The reason for the above rules is that we can't check these conditions
+before the query starts to execute. If we encounter a problem after
+updating a few rows, we can't just rollback as the table type may not
+support this. We can't stop because in that case the update would be
+'half done' which is probably the worst possible scenario. In this case
+it's better to 'do the best you can' and then continue as if nothing
+happened.
+The above means that one should not use MySQL to check fields content,
+but one should do this in the application.
-@node Portability, Internal use, Design Limitations, Optimize Overview
+@node Portability, Internal use, Design Limitations, Optimise Overview
@subsection Portability
@cindex portability
@@ -24415,7 +24645,7 @@ is, they have different design compromises that lead to different
behavior.
If you strive for database independence, you need to get a good feeling
-for each SQL server's bottlenecks. MySQL is VERY fast in
+for each SQL server's bottlenecks. MySQL is very fast in
retrieving and updating things, but will have a problem in mixing slow
readers/writers on the same table. Oracle, on the other hand, has a big
problem when you try to access rows that you have recently updated
@@ -24436,11 +24666,11 @@ MySQL-specific keywords to a query. The code inside
@code{/**/} will be treated as a comment (ignored) by most other SQL
servers.
-If REAL high performance is more important than exactness, as in some
-Web applications, a possibility is to create an application layer that
+If high performance is more important than exactness, as in some
+Web applications, it is possibile to create an application layer that
caches all results to give you even higher performance. By letting
old results 'expire' after a while, you can keep the cache reasonably
-fresh. This is quite nice in case of extremely high load, in which case
+fresh. This provides a method to handle high load spikes, in which case
you can dynamically increase the cache and set the expire timeout higher
until things get back to normal.
@@ -24449,7 +24679,7 @@ of the initial size of the cache and how often the table should normally
be refreshed.
-@node Internal use, MySQL Benchmarks, Portability, Optimize Overview
+@node Internal use, MySQL Benchmarks, Portability, Optimise Overview
@subsection What Have We Used MySQL For?
@cindex uses, of MySQL
@@ -24514,7 +24744,7 @@ makes the machine feel very slow and unresponsive while big batches are
going. Hopefully this will be better handled in future Linux Kernels.
-@node MySQL Benchmarks, Custom Benchmarks, Internal use, Optimize Overview
+@node MySQL Benchmarks, Custom Benchmarks, Internal use, Optimise Overview
@subsection The MySQL Benchmark Suite
@cindex benchmark suite
@@ -24536,27 +24766,27 @@ multi-threaded tests to the benchmark suite.
For example, (run on the same NT 4.0 machine):
@multitable @columnfractions .6 .2 .2
-@strong{Reading 2000000 rows by index} @tab @strong{Seconds} @tab @strong{Seconds}
-@item mysql @tab 367 @tab 249
-@item mysql_odbc @tab 464
-@item db2_odbc @tab 1206
-@item informix_odbc @tab 121126
-@item ms-sql_odbc @tab 1634
-@item oracle_odbc @tab 20800
-@item solid_odbc @tab 877
-@item sybase_odbc @tab 17614
+@item @strong{Reading 2000000 rows by index} @tab @strong{Seconds} @tab @strong{Seconds}
+@item mysql @tab 367 @tab 249
+@item mysql_odbc @tab 464 @tab
+@item db2_odbc @tab 1206 @tab
+@item informix_odbc @tab 121126 @tab
+@item ms-sql_odbc @tab 1634 @tab
+@item oracle_odbc @tab 20800 @tab
+@item solid_odbc @tab 877 @tab
+@item sybase_odbc @tab 17614 @tab
@end multitable
@multitable @columnfractions .6 .2 .2
-@strong{Inserting (350768) rows} @tab @strong{Seconds} @tab @strong{Seconds}
-@item mysql @tab 381 @tab 206
-@item mysql_odbc @tab 619
-@item db2_odbc @tab 3460
-@item informix_odbc @tab 2692
-@item ms-sql_odbc @tab 4012
-@item oracle_odbc @tab 11291
-@item solid_odbc @tab 1801
-@item sybase_odbc @tab 4802
+@item @strong{Inserting (350768) rows} @tab @strong{Seconds} @tab @strong{Seconds}
+@item mysql @tab 381 @tab 206
+@item mysql_odbc @tab 619 @tab
+@item db2_odbc @tab 3460 @tab
+@item informix_odbc @tab 2692 @tab
+@item ms-sql_odbc @tab 4012 @tab
+@item oracle_odbc @tab 11291 @tab
+@item solid_odbc @tab 1801 @tab
+@item sybase_odbc @tab 4802 @tab
@end multitable
In the above test MySQL was run with a 8M index cache.
@@ -24566,7 +24796,7 @@ We have gather some more benchmark results at
Note that Oracle is not included because they asked to be removed. All
Oracle benchmarks have to be passed by Oracle! We believe that makes
-Oracle benchmarks @strong{VERY} biased because the above benchmarks are
+Oracle benchmarks @strong{very} biased because the above benchmarks are
supposed to show what a standard installation can do for a single
client.
@@ -24604,7 +24834,7 @@ We can find the result from crash-me on a lot of different databases at
@uref{http://www.mysql.com/information/crash-me.php}.
-@node Custom Benchmarks, , MySQL Benchmarks, Optimize Overview
+@node Custom Benchmarks, , MySQL Benchmarks, Optimise Overview
@subsection Using Your Own Benchmarks
@cindex benchmarks
@@ -24628,8 +24858,8 @@ It is very common that some problems only occur when the system is very
heavily loaded. We have had many customers who contact us when they
have a (tested) system in production and have encountered load problems. In
every one of these cases so far, it has been problems with basic design
-(table scans are NOT good at high load) or OS/Library issues. Most of
-this would be a @strong{LOT} easier to fix if the systems were not
+(table scans are @strong{not good} at high load) or OS/Library issues. Most of
+this would be a @strong{lot} easier to fix if the systems were not
already in production.
To avoid problems like this, you should put some effort into benchmarking
@@ -24640,8 +24870,8 @@ As the name suggests, it can bring your system down to its knees if you ask it,
so make sure to use it only on your development systems.
-@node Query Speed, Locking Issues, Optimize Overview, MySQL Optimization
-@section Optimizing @code{SELECT}s and Other Queries
+@node Query Speed, Locking Issues, Optimise Overview, MySQL Optimisation
+@section Optimising @code{SELECT}s and Other Queries
@cindex queries, speed of
@cindex permission checks, effect on speed
@@ -24651,7 +24881,7 @@ First, one thing that affects all queries: The more complex permission
system setup you have, the more overhead you get.
If you do not have any @code{GRANT} statements done, MySQL will
-optimize the permission checking somewhat. So if you have a very high
+optimise the permission checking somewhat. So if you have a very high
volume it may be worth the time to avoid grants. Otherwise more
permission check results in a larger overhead.
@@ -24671,7 +24901,7 @@ mysql> select benchmark(1000000,1+1);
The above shows that MySQL can execute 1,000,000 @code{+}
expressions in 0.32 seconds on a @code{PentiumII 400MHz}.
-All MySQL functions should be very optimized, but there may be
+All MySQL functions should be very optimised, but there may be
some exceptions, and the @code{benchmark(loop_count,expression)} is a
great tool to find out if this is a problem with your query.
@@ -24679,14 +24909,15 @@ great tool to find out if this is a problem with your query.
* EXPLAIN:: @code{EXPLAIN} Syntax (Get Information About a @code{SELECT})
* Estimating performance:: Estimating query performance
* SELECT speed:: Speed of @code{SELECT} queries
-* Where optimizations:: How MySQL optimizes @code{WHERE} clauses
-* DISTINCT optimization:: How MySQL Optimizes @code{DISTINCT}
-* LEFT JOIN optimization:: How MySQL optimizes @code{LEFT JOIN}
-* LIMIT optimization:: How MySQL optimizes @code{LIMIT}
+* Where optimisations:: How MySQL optimises @code{WHERE} clauses
+* DISTINCT optimisation:: How MySQL Optimises @code{DISTINCT}
+* LEFT JOIN optimisation:: How MySQL optimises @code{LEFT JOIN}
+* ORDER BY optimisation:: How MySQL Optimises @code{ORDER BY}
+* LIMIT optimisation:: How MySQL optimises @code{LIMIT}
* Insert speed:: Speed of @code{INSERT} queries
* Update speed:: Speed of @code{UPDATE} queries
* Delete speed:: Speed of @code{DELETE} queries
-* Tips:: Other Optimization Tips
+* Tips:: Other Optimisation Tips
@end menu
@@ -24694,7 +24925,7 @@ great tool to find out if this is a problem with your query.
@subsection @code{EXPLAIN} Syntax (Get Information About a @code{SELECT})
@findex EXPLAIN
-@findex SELECT, optimizing
+@findex SELECT, optimising
@example
EXPLAIN tbl_name
@@ -24710,8 +24941,8 @@ information about how tables are joined and in which order.
With the help of @code{EXPLAIN}, you can see when you must add indexes
to tables to get a faster @code{SELECT} that uses indexes to find the
-records. You can also see if the optimizer joins the tables in an optimal
-order. To force the optimizer to use a specific join order for a
+records. You can also see if the optimiser joins the tables in an optimal
+order. To force the optimiser to use a specific join order for a
@code{SELECT} statement, add a @code{STRAIGHT_JOIN} clause.
For non-simple joins, @code{EXPLAIN} returns a row of information for each
@@ -24749,12 +24980,12 @@ and check the query with @code{EXPLAIN} again. @xref{ALTER TABLE}.
To see what indexes a table has, use @code{SHOW INDEX FROM tbl_name}.
@item key
-The @code{key} column indicates the key that MySQL actually
+The @code{key} column indicates the key (index) that MySQL actually
decided to use. The key is @code{NULL} if no index was chosen. If
MySQL chooses the wrong index, you can probably force
MySQL to use another index by using @code{myisamchk --analyze},
@xref{myisamchk syntax}, or by using @code{USE INDEX/IGNORE INDEX}.
-@xref{JOIN}.
+@xref{SELECT}.
@item key_len
The @code{key_len} column indicates the length of the key that
@@ -24781,7 +25012,7 @@ MySQL will not continue searching for more rows for the current row
combination after it has found the first matching row.
@item Not exists
-MySQL was able to do a @code{LEFT JOIN} optimization on the
+MySQL was able to do a @code{LEFT JOIN} optimisation on the
query and will not examine more rows in this table for the previous row
combination after it finds one row that matches the @code{LEFT JOIN} criteria.
@@ -24853,7 +25084,7 @@ the @code{const} join type.
The table has at most one matching row, which will be read at the start
of the query. Because there is only one row, values from the column in
this row can be regarded as constants by the rest of the
-optimizer. @code{const} tables are very fast as they are read only once!
+optimiser. @code{const} tables are very fast as they are read only once!
@item eq_ref
One row will be read from this table for each combination of rows from
@@ -24896,7 +25127,7 @@ number is also used when you restrict queries with the @code{max_join_size}
variable.
@xref{Server parameters}.
-The following example shows how a @code{JOIN} can be optimized progressively
+The following example shows how a @code{JOIN} can be optimised progressively
using the information provided by @code{EXPLAIN}.
Suppose you have the @code{SELECT} statement shown below, that you examine
@@ -24948,7 +25179,7 @@ The tables have the indexes shown below:
The @code{tt.ActualPC} values aren't evenly distributed.
@end itemize
-Initially, before any optimizations have been performed, the @code{EXPLAIN}
+Initially, before any optimisations have been performed, the @code{EXPLAIN}
statement produces the following information:
@example
@@ -25004,17 +25235,19 @@ do.CUSTNMBR} comparisons:
@example
mysql> ALTER TABLE tt MODIFY AssignedPC VARCHAR(15),
- MODIFY ClientID VARCHAR(15);
+ -> MODIFY ClientID VARCHAR(15);
@end example
Now @code{EXPLAIN} produces the output shown below:
@example
-table type possible_keys key key_len ref rows Extra
-et ALL PRIMARY NULL NULL NULL 74
-tt ref AssignedPC,ClientID,ActualPC ActualPC 15 et.EMPLOYID 52 where used
-et_1 eq_ref PRIMARY PRIMARY 15 tt.AssignedPC 1
-do eq_ref PRIMARY PRIMARY 15 tt.ClientID 1
+table type possible_keys key key_len ref rows Extra
+et ALL PRIMARY NULL NULL NULL 74
+tt ref AssignedPC, ActualPC 15 et.EMPLOYID 52 where used
+ ClientID,
+ ActualPC
+et_1 eq_ref PRIMARY PRIMARY 15 tt.AssignedPC 1
+do eq_ref PRIMARY PRIMARY 15 tt.ClientID 1
@end example
This is almost as good as it can get.
@@ -25032,15 +25265,17 @@ shell> mysqladmin refresh
Now the join is perfect, and @code{EXPLAIN} produces this result:
@example
-table type possible_keys key key_len ref rows Extra
-tt ALL AssignedPC,ClientID,ActualPC NULL NULL NULL 3872 where used
-et eq_ref PRIMARY PRIMARY 15 tt.ActualPC 1
-et_1 eq_ref PRIMARY PRIMARY 15 tt.AssignedPC 1
-do eq_ref PRIMARY PRIMARY 15 tt.ClientID 1
+table type possible_keys key key_len ref rows Extra
+tt ALL AssignedPC NULL NULL NULL 3872 where used
+ ClientID,
+ ActualPC
+et eq_ref PRIMARY PRIMARY 15 tt.ActualPC 1
+et_1 eq_ref PRIMARY PRIMARY 15 tt.AssignedPC 1
+do eq_ref PRIMARY PRIMARY 15 tt.ClientID 1
@end example
Note that the @code{rows} column in the output from @code{EXPLAIN} is an
-educated guess from the MySQL join optimizer. To optimize a
+educated guess from the MySQL join optimiser. To optimise a
query, you should check if the numbers are even close to the truth. If not,
you may get better performance by using @code{STRAIGHT_JOIN} in your
@code{SELECT} statement and trying to list the tables in a different order in
@@ -25084,7 +25319,7 @@ go much slower until your applications is only bound by disk-seeks
the data grows. @xref{Server parameters}.
-@node SELECT speed, Where optimizations, Estimating performance, Query Speed
+@node SELECT speed, Where optimisations, Estimating performance, Query Speed
@subsection Speed of @code{SELECT} Queries
@findex SELECT speed
@@ -25102,11 +25337,11 @@ Some general tips:
@itemize @bullet
@item
-To help MySQL optimize queries better, run @code{myisamchk
+To help MySQL optimise queries better, run @code{myisamchk
--analyze} on a table after it has been loaded with relevant data. This
updates a value for each index part that indicates the average number of
rows that have the same value. (For unique indexes, this is always 1,
-of course.). MySQL will use this to decide which index to
+of course.) MySQL will use this to decide which index to
choose when you connect two tables with 'a non-constant expression'.
You can check the result from the @code{analyze} run by doing @code{SHOW
INDEX FROM table_name} and examining the @code{Cardinality} column.
@@ -25121,21 +25356,21 @@ time for a large table!
@end itemize
-@node Where optimizations, DISTINCT optimization, SELECT speed, Query Speed
-@subsection How MySQL Optimizes @code{WHERE} Clauses
+@node Where optimisations, DISTINCT optimisation, SELECT speed, Query Speed
+@subsection How MySQL Optimises @code{WHERE} Clauses
@findex WHERE
-@cindex optimizations
+@cindex optimisations
-The @code{WHERE} optimizations are put in the @code{SELECT} part here because
-they are mostly used with @code{SELECT}, but the same optimizations apply for
+The @code{WHERE} optimisations are put in the @code{SELECT} part here because
+they are mostly used with @code{SELECT}, but the same optimisations apply for
@code{WHERE} in @code{DELETE} and @code{UPDATE} statements.
Also note that this section is incomplete. MySQL does many
-optimizations, and we have not had time to document them all.
+optimisations, and we have not had time to document them all.
-Some of the optimizations performed by MySQL are listed below:
+Some of the optimisations performed by MySQL are listed below:
@itemize @bullet
@item
@@ -25160,8 +25395,8 @@ Constant condition removal (needed because of constant folding):
Constant expressions used by indexes are evaluated only once.
@item
@code{COUNT(*)} on a single table without a @code{WHERE} is retrieved
-directly from the table information. This is also done for any @code{NOT NULL}
-expression when used with only one table.
+directly from the table information for MyISAM and HEAP tables. This is
+also done for any @code{NOT NULL} expression when used with only one table.
@item
Early detection of invalid constant expressions. MySQL quickly
detects that some @code{SELECT} statements are impossible and returns no rows.
@@ -25189,7 +25424,7 @@ All the following tables are used as constant tables:
@example
mysql> SELECT * FROM t WHERE primary_key=1;
mysql> SELECT * FROM t1,t2
- WHERE t1.primary_key=1 AND t2.primary_key=t1.id;
+ -> WHERE t1.primary_key=1 AND t2.primary_key=t1.id;
@end example
@item
@@ -25223,11 +25458,11 @@ Some examples of queries that are very fast:
mysql> SELECT COUNT(*) FROM tbl_name;
mysql> SELECT MIN(key_part1),MAX(key_part1) FROM tbl_name;
mysql> SELECT MAX(key_part2) FROM tbl_name
- WHERE key_part_1=constant;
+ -> WHERE key_part_1=constant;
mysql> SELECT ... FROM tbl_name
- ORDER BY key_part1,key_part2,... LIMIT 10;
+ -> ORDER BY key_part1,key_part2,... LIMIT 10;
mysql> SELECT ... FROM tbl_name
- ORDER BY key_part1 DESC,key_part2 DESC,... LIMIT 10;
+ -> ORDER BY key_part1 DESC,key_part2 DESC,... LIMIT 10;
@end example
The following queries are resolved using only the index tree (assuming
@@ -25236,7 +25471,7 @@ the indexed columns are numeric):
@example
mysql> SELECT key_part1,key_part2 FROM tbl_name WHERE key_part1=val;
mysql> SELECT COUNT(*) FROM tbl_name
- WHERE key_part1=val1 AND key_part2=val2;
+ -> WHERE key_part1=val1 AND key_part2=val2;
mysql> SELECT key_part2 FROM tbl_name GROUP BY key_part1;
@end example
@@ -25244,17 +25479,19 @@ The following queries use indexing to retrieve the rows in sorted
order without a separate sorting pass:
@example
-mysql> SELECT ... FROM tbl_name ORDER BY key_part1,key_part2,... ;
-mysql> SELECT ... FROM tbl_name ORDER BY key_part1 DESC,key_part2 DESC,... ;
+mysql> SELECT ... FROM tbl_name
+ -> ORDER BY key_part1,key_part2,... ;
+mysql> SELECT ... FROM tbl_name
+ -> ORDER BY key_part1 DESC,key_part2 DESC,... ;
@end example
-@node DISTINCT optimization, LEFT JOIN optimization, Where optimizations, Query Speed
-@subsection How MySQL Optimizes @code{DISTINCT}
+@node DISTINCT optimisation, LEFT JOIN optimisation, Where optimisations, Query Speed
+@subsection How MySQL Optimises @code{DISTINCT}
@findex DISTINCT
-@cindex optimizing, DISTINCT
+@cindex optimising, DISTINCT
@code{DISTINCT} is converted to a @code{GROUP BY} on all columns,
@code{DISTINCT} combined with @code{ORDER BY} will in many cases also
@@ -25275,12 +25512,12 @@ MySQL will stop reading from t2 (for that particular row in t1)
when the first row in t2 is found.
-@node LEFT JOIN optimization, LIMIT optimization, DISTINCT optimization, Query Speed
-@subsection How MySQL Optimizes @code{LEFT JOIN} and @code{RIGHT JOIN}
+@node LEFT JOIN optimisation, ORDER BY optimisation, DISTINCT optimisation, Query Speed
+@subsection How MySQL Optimises @code{LEFT JOIN} and @code{RIGHT JOIN}
@findex LEFT JOIN
-@cindex optimizing, LEFT JOIN
+@cindex optimising, LEFT JOIN
@code{A LEFT JOIN B} in MySQL is implemented as follows:
@@ -25297,12 +25534,12 @@ that are used in the @code{LEFT JOIN} condition.
All @code{LEFT JOIN} conditions are moved to the @code{WHERE} clause.
@item
-All standard join optimizations are done, with the exception that a table is
+All standard join optimisations are done, with the exception that a table is
always read after all tables it is dependent on. If there is a circular
dependence then MySQL will issue an error.
@item
-All standard @code{WHERE} optimizations are done.
+All standard @code{WHERE} optimisations are done.
@item
If there is a row in @code{A} that matches the @code{WHERE} clause, but there
@@ -25321,32 +25558,152 @@ matches the @code{LEFT JOIN} condition.
@code{RIGHT JOIN} is implemented analogously as @code{LEFT JOIN}.
The table read order forced by @code{LEFT JOIN} and @code{STRAIGHT JOIN}
-will help the join optimizer (which calculates in which order tables
+will help the join optimiser (which calculates in which order tables
should be joined) to do its work much more quickly, as there are fewer
table permutations to check.
Note that the above means that if you do a query of type:
@example
-SELECT * FROM a,b LEFT JOIN c ON (c.key=a.key) LEFT JOIN d (d.key=a.key) WHERE b.key=d.key
+SELECT * FROM a,b LEFT JOIN c ON (c.key=a.key) LEFT JOIN d (d.key=a.key)
+ WHERE b.key=d.key
@end example
-MySQL will do a full scan on @code{b} as the @code{LEFT JOIN} will force
+MySQL will do a full scan on @code{b} as the @code{LEFT JOIN} will force
it to be read before @code{d}.
The fix in this case is to change the query to:
@example
-SELECT * FROM b,a LEFT JOIN c ON (c.key=a.key) LEFT JOIN d (d.key=a.key) WHERE b.key=d.key
+SELECT * FROM b,a LEFT JOIN c ON (c.key=a.key) LEFT JOIN d (d.key=a.key)
+ WHERE b.key=d.key
+@end example
+
+
+@node ORDER BY optimisation, LIMIT optimisation, LEFT JOIN optimisation, Query Speed
+@subsection How MySQL Optimises @code{ORDER BY}
+
+In some cases MySQL can uses index to satisfy an @code{ORDER BY} or
+@code{GROUP BY} request without doing any extra sorting.
+
+The index can also be used even if the @code{ORDER BY} doesn't match the
+index exactly, as long as all the unused index parts and all the extra
+are @code{ORDER BY} columns are constants in the @code{WHERE}
+clause. The following queries will use the index to resolve the
+@code{ORDER BY} / @code{GROUP BY} part:
+
+@example
+SELECT * FROM t1 ORDER BY key_part1,key_part2,...
+SELECT * FROM t1 WHERE key_part1=constant ORDER BY key_part2
+SELECT * FROM t1 WHERE key_part1=constant GROUP BY key_part2
+SELECT * FROM t1 ORDER BY key_part1 DESC,key_part2 DESC
+SELECT * FROM t1 WHERE key_part1=1 ORDER BY key_part1 DESC,key_part2 DESC
@end example
+Some cases where MySQL can NOT use indexes to resolve the @code{ORDER
+BY}: (Note that MySQL will still use indexes to find the rows that
+matches the where clause):
+
+@itemize @bullet
+@item
+You are doing an @code{ORDER BY} on different keys:
+
+@code{SELECT * FROM t1 ORDER BY key1,key2}
+@item
+You are doing an @code{ORDER BY} on not following key parts.
+
+@code{SELECT * FROM t1 WHERE key2=constant ORDER BY key_part2}
+
+@item
+You are mixing @code{ASC} and @code{DESC}.
+
+@code{SELECT * FROM t1 ORDER BY key_part1 DESC,key_part2 ASC}
+
+@item
+The key used to fetch the rows are not the same one that is used to
+do the @code{ORDER BY}:
+
+@code{SELECT * FROM t1 WHERE key2=constant ORDER BY key1}
+
+@item
+You are joining many tables and the columns you are doing an @code{ORDER
+BY} on are not all from the first not-const table that is used to
+retrieve rows (This is the first table in the @code{EXPLAIN} output which
+doesn't use a @code{const} row fetch method).
+
+@item
+You have different @code{ORDER BY} and @code{GROUP BY} expressions.
+
+@item
+The used table index is an index type that doesn't store rows in order.
+(Like the @code{HASH} index in @code{HEAP} tables).
+
+@item
+The index colum may contain @code{NULL} values and one is using
+@code{ORDER BY ... DESC}. This is because in SQL @code{NULL} values is
+always sorted before normal values, independent of you are using
+@code{DESC} or not.
+@end itemize
+
+
+In the cases where MySQL have to sort the result, it uses the following
+algorithm:
+
+@itemize @bullet
+@item
+Read all rows according to key or by table scanning.
+Rows that doesn't match the WHERE clause are skipped.
+@item
+Store the sort-key in a buffer (of size @code{sort_buffer}).
+@item
+When the buffer gets full, run a qsort on it and store the result
+in a temporary file. Save a pointer to the sorted block.
+(In the case where all rows fits into the sort buffer, no temporary
+file is created)
+@item
+Repeat the above until all rows have been read.
+@item
+Do a multi-merge of up to @code{MERGEBUFF} (7) regions to one block in
+another temporary file. Repeat until all blocks from the first file
+are in the second file.
+@item
+Repeat the following until there is less than @code{MERGEBUFF2} (15)
+blocks left.
+@item
+On the last multi-merge, only the pointer to the row (last part of
+the sort-key) is written to a result file.
+@item
+Now the code in @file{sql/records.cc} will be used to read through them
+in sorted order by using the row pointers in the result file. To
+optimize this, we read in a big block of row pointers, sort these and
+then we read the rows in the sorted order into a row buffer
+(@code{record_rnd_buffer}) .
+@end itemize
-@node LIMIT optimization, Insert speed, LEFT JOIN optimization, Query Speed
-@subsection How MySQL Optimizes @code{LIMIT}
+You can with @code{EXPLAIN SELECT ... ORDER BY} check if MySQL can use
+indexes to resolve the query. If you get @code{Using filesort} in the
+@code{extra} column, then MySQL can't use indexes to resolve the
+@code{ORDER BY}. @xref{EXPLAIN}.
+
+If you want to have a higher @code{ORDER BY} speed, you should first
+see if you can get MySQL to use indexes instead of having to do an extra
+sorting phase. If this is not possible, then you can do:
+
+@itemize @bullet
+@item
+Increase the size of the @code{sort_buffer} variable.
+@item
+Increase the size of the @code{record_rnd_buffer} variable.
+@item
+Change @code{tmpdir} to point to a dedicated disk with lots of empty space.
+@end itemize
+
+@node LIMIT optimisation, Insert speed, ORDER BY optimisation, Query Speed
+@subsection How MySQL Optimises @code{LIMIT}
@findex LIMIT
-@cindex optimizing, LIMIT
+@cindex optimising, LIMIT
In some cases MySQL will handle the query differently when you are
using @code{LIMIT #} and not using @code{HAVING}:
@@ -25370,7 +25727,7 @@ key value changes. In this case @code{LIMIT #} will not calculate any
unnecessary @code{GROUP BY}'s.
@item
As soon as MySQL has sent the first @code{#} rows to the client, it
-will abort the query.
+will abort the query (If you are not using @code{SQL_CALC_FOUND_ROWS}).
@item
@code{LIMIT 0} will always quickly return an empty set. This is useful
to check the query and to get the column types of the result columns.
@@ -25380,7 +25737,7 @@ space is needed to resolve the query.
@end itemize
-@node Insert speed, Update speed, LIMIT optimization, Query Speed
+@node Insert speed, Update speed, LIMIT optimisation, Query Speed
@subsection Speed of @code{INSERT} Queries
@findex INSERT
@@ -25417,14 +25774,16 @@ Some ways to speed up inserts:
@itemize @bullet
@item
If you are inserting many rows from the same client at the same time, use
-multiple value lists @code{INSERT} statements. This is much faster (many
-times in some cases) than using separate @code{INSERT} statements.
+multiple value lists @code{INSERT} statements. This is much faster (many times
+in some cases) than using separate @code{INSERT} statements. If you are adding
+data to non-empty table, you may tune up @code{myisam_bulk_insert_tree_size}
+variable to make it even faster. @xref{SHOW VARIABLES}.
@item
If you are inserting a lot of rows from different clients, you can get
higher speed by using the @code{INSERT DELAYED} statement. @xref{INSERT,
, @code{INSERT}}.
@item
-Note that with @code{MyISAM} you can insert rows at the same time
+Note that with @code{MyISAM} tables you can insert rows at the same time
@code{SELECT}s are running if there are no deleted rows in the tables.
@item
When loading a table from a text file, use @code{LOAD DATA INFILE}. This
@@ -25466,10 +25825,21 @@ Execute a @code{FLUSH TABLES} statement or the shell command @code{mysqladmin
flush-tables}.
@end enumerate
-This procedure will be built into @code{LOAD DATA INFILE} in some future
-version of MySQL.
+Note that @code{LOAD DATA INFILE} also does the above optimization if
+you insert into an empty table; The main difference with the above
+procedure is that you can let myisamchk allocate much more temporary
+memory for the index creation that you may want MySQL to allocate for
+every index recreation.
+
+Since @strong{MySQL 4.0} you can also use
+@code{ALTER TABLE tbl_name DISABLE KEYS} instead of
+@code{myisamchk --keys-used=0 -rq /path/to/db/tbl_name} and
+@code{ALTER TABLE tbl_name ENABLE KEYS} instead of
+@code{myisamchk -r -q /path/to/db/tbl_name}. This way you can also skip
+@code{FLUSH TABLES} steps.
@item
-You can speed up insertions by locking your tables:
+You can speed up insertions that is done over multiple statements by
+locking your tables:
@example
mysql> LOCK TABLES a WRITE;
@@ -25484,6 +25854,9 @@ be as many index buffer flushes as there are different @code{INSERT}
statements. Locking is not needed if you can insert all rows with a single
statement.
+For transactional tables, you should use @code{BEGIN/COMMIT} instead of
+@code{LOCK TABLES} to get a speedup.
+
Locking will also lower the total time of multi-connection tests, but the
maximum wait time for some threads will go up (because they wait for
locks). For example:
@@ -25516,7 +25889,7 @@ To get some more speed for both @code{LOAD DATA INFILE} and
@node Update speed, Delete speed, Insert speed, Query Speed
@subsection Speed of @code{UPDATE} Queries
-Update queries are optimized as a @code{SELECT} query with the additional
+Update queries are optimised as a @code{SELECT} query with the additional
overhead of a write. The speed of the write is dependent on the size of
the data that is being updated and the number of indexes that are
updated. Indexes that are not changed will not be updated.
@@ -25543,10 +25916,10 @@ the index cache. @xref{Server parameters}.
@node Tips, , Delete speed, Query Speed
-@subsection Other Optimization Tips
+@subsection Other Optimisation Tips
-@cindex optimization, tips
-@cindex tips, optimization
+@cindex optimisation, tips
+@cindex tips, optimisation
Unsorted tips for faster systems:
@@ -25561,7 +25934,7 @@ Always check that all your queries really use the indexes you have created
in the tables. In MySQL you can do this with the @code{EXPLAIN}
command. @xref{EXPLAIN, Explain, Explain, manual}.
@item
-Try to avoid complex @code{SELECT} queries on tables that are updated a
+Try to avoid complex @code{SELECT} queries on MyISAM tables that are updated a
lot. This is to avoid problems with table locking.
@item
The new @code{MyISAM} tables can insert rows in a table without deleted
@@ -25570,7 +25943,7 @@ for you, you should consider methods where you don't have to delete rows
or run @code{OPTIMIZE TABLE} after you have deleted a lot of rows.
@item
Use @code{ALTER TABLE ... ORDER BY expr1,expr2...} if you mostly
-retrieve rows in expr1,expr2.. order. By using this option after big
+retrieve rows in expr1,expr2... order. By using this option after big
changes to the table, you may be able to get higher performance.
@item
In some cases it may make sense to introduce a column that is 'hashed'
@@ -25688,7 +26061,7 @@ Try to keep the names simple (use @code{name} instead of
@code{customer_name} in the customer table). To make your names portable
to other SQL servers you should keep them shorter than 18 characters.
@item
-If you need REALLY high speed, you should take a look at the low-level
+If you need really high speed, you should take a look at the low-level
interfaces for data storage that the different SQL servers support! For
example, by accessing the MySQL @code{MyISAM} directly, you could
get a speed increase of 2-5 times compared to using the SQL interface.
@@ -25698,7 +26071,7 @@ the application, and usually it should only be accessed by one process
above problems by introducing low-level @code{MyISAM} commands in the
MySQL server (this could be one easy way to get more
performance if needed). By carefully designing the database interface,
-it should be quite easy to support this types of optimization.
+it should be quite easy to support this types of optimisation.
@item
In many cases it's faster to access data from a database (using a live
connection) than accessing a text file, just because the database is
@@ -25718,7 +26091,7 @@ from the data, you should not lose anything by using @code{DELAY_KEY_WRITE}.
@end itemize
-@node Locking Issues, Optimizing Database Structure, Query Speed, MySQL Optimization
+@node Locking Issues, Optimising Database Structure, Query Speed, MySQL Optimisation
@section Locking Issues
@@ -25738,10 +26111,17 @@ from the data, you should not lose anything by using @code{DELAY_KEY_WRITE}.
You can find a discussion about different locking methods in the appendix.
@xref{Locking methods}.
-All locking in MySQL is deadlock-free. This is managed by always
+All locking in MySQL is deadlock-free, except for @code{InnoDB} and
+@code{BDB} type tables.
+This is managed by always
requesting all needed locks at once at the beginning of a query and always
locking the tables in the same order.
+@code{InnoDB} type tables automatically acquire their row locks and
+@code{BDB} type tables
+their page locks during the processing of SQL statements, not at the start
+of the transaction.
+
The locking method MySQL uses for @code{WRITE} locks works as follows:
@itemize @bullet
@@ -25781,7 +26161,7 @@ mysql> UNLOCK TABLES;
You can use the @code{LOW_PRIORITY} options with @code{INSERT},
@code{UPDATE} or @code{DELETE} or @code{HIGH_PRIORITY} with
-@code{SELECT} if you want to prioritize retrieval in some specific
+@code{SELECT} if you want to prioritise retrieval in some specific
cases. You can also start @code{mysqld} with @code{--low-priority-updates}
to get the same behaveour.
@@ -25801,16 +26181,18 @@ priority, which might help some applications.
The table locking code in MySQL is deadlock free.
MySQL uses table locking (instead of row locking or column
-locking) on all table types, except @code{BDB} tables, to achieve a very
-high lock speed. For large tables, table locking is MUCH better than
+locking) on all table types, except @code{InnoDB} and @code{BDB} tables,
+to achieve a very
+high lock speed. For large tables, table locking is much better than
row locking for most applications, but there are, of course, some
pitfalls.
-For @code{BDB} and @code{InnoDB} tables, MySQL only uses table
-locking if you explicitely lock the table with @code{LOCK TABLES} or
-execute a command that will modify every row in the table, like
-@code{ALTER TABLE}. For these table types we recommend you to not use
-@code{LOCK TABLES} at all.
+For @code{InnoDB} and @code{BDB} tables, MySQL only uses table
+locking if you explicitly lock the table with @code{LOCK TABLES}.
+For these table types we recommend you to not use
+@code{LOCK TABLES} at all, because @code{InnoDB} uses automatic
+row level locking and @code{BDB} uses page level locking to
+ensure transaction isolation.
In MySQL Version 3.23.7 and above, you can insert rows into
@code{MyISAM} tables at the same time other threads are reading from the
@@ -25902,8 +26284,8 @@ option to @code{DELETE} may help. @xref{DELETE, , @code{DELETE}}.
@end itemize
-@node Optimizing Database Structure, Optimizing the Server, Locking Issues, MySQL Optimization
-@section Optimizing Database Structure
+@node Optimising Database Structure, Optimising the Server, Locking Issues, MySQL Optimisation
+@section Optimising Database Structure
@menu
@@ -25912,13 +26294,13 @@ option to @code{DELETE} may help. @xref{DELETE, , @code{DELETE}}.
* MySQL indexes:: How MySQL Uses Indexes
* Indexes:: Column Indexes
* Multiple-column indexes:: Multiple-Column Indexes
+* Open tables:: Why So Many Open tables?
* Table cache:: How MySQL Opens and Closes Tables
* Creating many tables:: Drawbacks to Creating Large Numbers of Tables in the Same Database
-* Open tables:: Why So Many Open tables?
@end menu
-@node Design, Data size, Optimizing Database Structure, Optimizing Database Structure
+@node Design, Data size, Optimising Database Structure, Optimising Database Structure
@subsection Design Choices
@cindex design, choices
@@ -25954,20 +26336,20 @@ You lose a lot of space, as you must duplicate indexes from the nodes
Deletes will degenerate the table over time (as indexes in nodes are
usually not updated on delete).
@item
-It's harder to cache ONLY the index data.
+It's harder to cache only the index data.
@end itemize
-@node Data size, MySQL indexes, Design, Optimizing Database Structure
+@node Data size, MySQL indexes, Design, Optimising Database Structure
@subsection Get Your Data as Small as Possible
@cindex data, size
@cindex reducing, data size
-@cindex storage space, minimizing
+@cindex storage space, minimising
@cindex tables, improving performance
@cindex performance, improving
-One of the most basic optimization is to get your data (and indexes) to
+One of the most basic optimisation is to get your data (and indexes) to
take as little space on the disk (and in memory) as possible. This can
give huge improvements because disk reads are faster and normally less
main memory will be used. Indexing also takes less resources if
@@ -25977,13 +26359,13 @@ MySQL supports a lot of different table types and row formats.
Choosing the right table format may give you a big performance gain.
@xref{Table types}.
-You can get better performance on a table and minimize storage space
+You can get better performance on a table and minimise storage space
using the techniques listed below:
@itemize @bullet
@item
Use the most efficient (smallest) types possible. MySQL has
-many specialized types that save disk space and memory.
+many specialised types that save disk space and memory.
@item
Use the smaller integer types if possible to get smaller tables. For
@@ -26014,7 +26396,7 @@ Only create the indexes that you really need. Indexes are good for
retrieval but bad when you need to store things fast. If you mostly
access a table by searching on a combination of columns, make an index
on them. The first index part should be the most used column. If you are
-ALWAYS using many columns, you should use the column with more duplicates
+@strong{always} using many columns, you should use the column with more duplicates
first to get better compression of the index.
@item
@@ -26033,7 +26415,7 @@ can be used to find the relevant rows when scanning the table.
@end itemize
-@node MySQL indexes, Indexes, Data size, Optimizing Database Structure
+@node MySQL indexes, Indexes, Data size, Optimising Database Structure
@subsection How MySQL Uses Indexes
@cindex indexes, use of
@@ -26062,7 +26444,7 @@ Retrieve rows from other tables when performing joins.
@item
Find the @code{MAX()} or @code{MIN()} value for a specific indexed
-column. This is optimized by a preprocessor that checks if you are
+column. This is optimised by a preprocessor that checks if you are
using @code{WHERE} key_part_# = constant on all key parts < N. In this case
MySQL will do a single key lookup and replace the @code{MIN()}
expression with a constant. If all expressions are replaced with
@@ -26074,22 +26456,12 @@ SELECT MIN(key_part2),MAX(key_part2) FROM table_name where key_part1=10
@item
Sort or group a table if the sorting or grouping is done on a leftmost
-prefix of a usable key (for example, @code{ORDER BY key_part_1,key_part_2 }). The
-key is read in reverse order if all key parts are followed by @code{DESC}.
-
-The index can also be used even if the @code{ORDER BY} doesn't match the index
-exactly, as long as all the unused index parts and all the extra
-are @code{ORDER BY} columns are constants in the @code{WHERE} clause. The
-following queries will use the index to resolve the @code{ORDER BY} part:
-
-@example
-SELECT * FROM foo ORDER BY key_part1,key_part2,key_part3;
-SELECT * FROM foo WHERE column=constant ORDER BY column, key_part1;
-SELECT * FROM foo WHERE key_part1=const GROUP BY key_part2;
-@end example
+prefix of a usable key (for example, @code{ORDER BY
+key_part_1,key_part_2 }). The key is read in reverse order if all key
+parts are followed by @code{DESC}. @xref{ORDER BY optimisation}.
@item
-In some cases a query can be optimized to retrieve values without
+In some cases a query can be optimised to retrieve values without
consulting the data file. If all used columns for some table are numeric
and form a leftmost prefix for some key, the values may be retrieved
from the index tree for greater speed:
@@ -26108,14 +26480,14 @@ mysql> SELECT * FROM tbl_name WHERE col1=val1 AND col2=val2;
If a multiple-column index exists on @code{col1} and @code{col2}, the
appropriate rows can be fetched directly. If separate single-column
-indexes exist on @code{col1} and @code{col2}, the optimizer tries to
+indexes exist on @code{col1} and @code{col2}, the optimiser tries to
find the most restrictive index by deciding which index will find fewer
rows and using that index to fetch the rows.
@cindex indexes, leftmost prefix of
@cindex leftmost prefix of indexes
If the table has a multiple-column index, any leftmost prefix of the
-index can be used by the optimizer to find rows. For example, if you
+index can be used by the optimiser to find rows. For example, if you
have a three-column index on @code{(col1,col2,col3)}, you have indexed
search capabilities on @code{(col1)}, @code{(col1,col2)}, and
@code{(col1,col2,col3)}.
@@ -26173,7 +26545,7 @@ index is used for columns that you compare with the following operators:
@code{LIKE} with a non-wild-card prefix like @code{'something%'}.
Any index that doesn't span all @code{AND} levels in the @code{WHERE} clause
-is not used to optimize the query. In other words: To be able to use an
+is not used to optimise the query. In other words: To be able to use an
index, a prefix of the index must be used in every @code{AND} group.
The following @code{WHERE} clauses use indexes:
@@ -26181,7 +26553,7 @@ The following @code{WHERE} clauses use indexes:
... WHERE index_part1=1 AND index_part2=2 AND other_column=3
... WHERE index=1 OR A=10 AND index=2 /* index = 1 OR index = 2 */
... WHERE index_part1='hello' AND index_part_3=5
- /* optimized like "index_part1='hello'" */
+ /* optimised like "index_part1='hello'" */
... WHERE index1=1 and index2=2 or index1=3 and index3=3;
/* Can use index on index1 but not on index2 or index 3 */
@end example
@@ -26189,8 +26561,9 @@ The following @code{WHERE} clauses use indexes:
These @code{WHERE} clauses do @strong{NOT} use indexes:
@example
... WHERE index_part2=1 AND index_part3=2 /* index_part_1 is not used */
-... WHERE index=1 OR A=10 /* Index is not used in both AND parts */
-... WHERE index_part1=1 OR index_part2=10 /* No index spans all rows */
+... WHERE index=1 OR A=10 /* Index is not used in
+ both AND parts */
+... WHERE index_part1=1 OR index_part2=10 /* No index spans all rows */
@end example
Note that in some cases MySQL will not use an index, even if one
@@ -26200,23 +26573,16 @@ would be available. Some of the cases where this happens are:
@item
If the use of the index would require MySQL to access more
than 30 % of the rows in the table. (In this case a table scan is
-probably much faster, as this will require us to do much fewer seeks).
+probably much faster, as this will require us to do much fewer seeks.)
Note that if such a query uses @code{LIMIT} to only retrieve
part of the rows, MySQL will use an index anyway, as it can
much more quickly find the few rows to return in the result.
+@item
+If the index range may contain @code{NULL} values and you are using
+@code{ORDER BY ... DESC}
@end itemize
-
-@menu
-* Indexes:: Column Indexes
-* Multiple-column indexes:: Multiple-Column Indexes
-* Table cache:: How MySQL Opens and Closes Tables
-* Creating many tables:: Drawbacks to Creating Large Numbers of Tables in the Same Database
-* Open tables:: Why So Many Open tables?
-@end menu
-
-
-@node Indexes, Multiple-column indexes, MySQL indexes, Optimizing Database Structure
+@node Indexes, Multiple-column indexes, MySQL indexes, Optimising Database Structure
@subsection Column Indexes
@cindex indexes, columns
@@ -26245,8 +26611,8 @@ The example below creates an index for the first 10 characters of the
@example
mysql> CREATE TABLE test (
- name CHAR(200) NOT NULL,
- KEY index_name (name(10)));
+ -> name CHAR(200) NOT NULL,
+ -> KEY index_name (name(10)));
@end example
For @code{BLOB} and @code{TEXT} columns, you must index a prefix of the
@@ -26259,7 +26625,7 @@ created only from @code{VARCHAR} and @code{TEXT} columns.
Indexing always happens over the entire column and partial indexing is not
supported. See @ref{Fulltext Search} for details.
-@node Multiple-column indexes, Table cache, Indexes, Optimizing Database Structure
+@node Multiple-column indexes, Open tables, Indexes, Optimising Database Structure
@subsection Multiple-Column Indexes
@cindex multi-column indexes
@@ -26268,7 +26634,7 @@ supported. See @ref{Fulltext Search} for details.
MySQL can create indexes on multiple columns. An index may
consist of up to 15 columns. (On @code{CHAR} and @code{VARCHAR} columns you
-can also use a prefix of the column as a part of an index).
+can also use a prefix of the column as a part of an index.)
A multiple-column index can be considered a sorted array containing values
that are created by concatenating the values of the indexed columns.
@@ -26281,11 +26647,11 @@ Suppose a table is created using the following specification:
@example
mysql> CREATE TABLE test (
- id INT NOT NULL,
- last_name CHAR(30) NOT NULL,
- first_name CHAR(30) NOT NULL,
- PRIMARY KEY (id),
- INDEX name (last_name,first_name));
+ -> id INT NOT NULL,
+ -> last_name CHAR(30) NOT NULL,
+ -> first_name CHAR(30) NOT NULL,
+ -> PRIMARY KEY (id),
+ -> INDEX name (last_name,first_name));
@end example
Then the index @code{name} is an index over @code{last_name} and
@@ -26298,13 +26664,13 @@ Therefore, the @code{name} index will be used in the following queries:
mysql> SELECT * FROM test WHERE last_name="Widenius";
mysql> SELECT * FROM test WHERE last_name="Widenius"
- AND first_name="Michael";
+ -> AND first_name="Michael";
mysql> SELECT * FROM test WHERE last_name="Widenius"
- AND (first_name="Michael" OR first_name="Monty");
+ -> AND (first_name="Michael" OR first_name="Monty");
mysql> SELECT * FROM test WHERE last_name="Widenius"
- AND first_name >="M" AND first_name < "N";
+ -> AND first_name >="M" AND first_name < "N";
@end example
However, the @code{name} index will NOT be used in the following queries:
@@ -26313,15 +26679,38 @@ However, the @code{name} index will NOT be used in the following queries:
mysql> SELECT * FROM test WHERE first_name="Michael";
mysql> SELECT * FROM test WHERE last_name="Widenius"
- OR first_name="Michael";
+ -> OR first_name="Michael";
@end example
For more information on the manner in which MySQL uses indexes to
improve query performance, see @ref{MySQL indexes, , MySQL
indexes}.
+@node Open tables, Table cache, Multiple-column indexes, Optimising Database Structure
+@subsection Why So Many Open tables?
+
+@cindex tables, open
+@cindex open tables
-@node Table cache, Creating many tables, Multiple-column indexes, Optimizing Database Structure
+When you run @code{mysqladmin status}, you'll see something like this:
+
+@example
+Uptime: 426 Running threads: 1 Questions: 11082 Reloads: 1 Open tables: 12
+@end example
+
+This can be somewhat perplexing if you only have 6 tables.
+
+MySQL is multithreaded, so it may have many queries on the same table
+simultaneously. To minimise the problem with two threads having
+different states on the same file, the table is opened independently by
+each concurrent thread. This takes some memory but will normaly increase
+performance. Wth ISAM and MyISAM tables this also requires one extra file
+descriptor for the data file. With these table types the index file
+descriptor is shared between all threads.
+
+You can read more about this topic in the next section. @xref{Table cache}.
+
+@node Table cache, Creating many tables, Open tables, Optimising Database Structure
@subsection How MySQL Opens and Closes Tables
@findex table_cache
@@ -26346,11 +26735,37 @@ at least @code{200 * n}, where @code{n} is the maximum number of tables
in a join. You also need to reserve some extra file descriptors for
temporary tables and files.
-The cache of open tables can grow to a maximum of @code{table_cache}
-(default 64; this can be changed with the @code{-O table_cache=#}
-option to @code{mysqld}). A table is never closed, except when the
-cache is full and another thread tries to open a table or if you use
-@code{mysqladmin refresh} or @code{mysqladmin flush-tables}.
+Make sure that your operating system can handle the number of open file
+descriptors implied by the @code{table_cache} setting. If
+@code{table_cache} is set too high, MySQL may run out of file
+descriptors and refuse connections, fail to perform queries, and be very
+unreliable. You also have to take into account that the MyISAM table
+handler needs two file descriptors for each unique open table. You can
+in increase the number of file descriptors available for MySQL with
+the @code{--open-files-limit=#} startup option. @xref{Not enough file
+handles}.
+
+The cache of open tables will be keept at a level of @code{table_cache}
+entries (default 64; this can be changed with the @code{-O
+table_cache=#} option to @code{mysqld}). Note that in MySQL may
+temporarly open even more tables to be able to execute queries.
+
+A not used table is closed and removed from the table cache under the
+following circumstances:
+
+@itemize @bullet
+@item
+When the cache is full and a thread tries to open a table that is not in
+the cache.
+@item
+When the cache contains more than @code{table_cache} entries and
+a thread is no longer using a table.
+@item
+When someone executes @code{mysqladmin refresh} or
+@code{mysqladmin flush-tables}.
+@item
+When someone executes 'FLUSH TABLES'
+@end itemize
When the table cache fills up, the server uses the following procedure
to locate a cache entry to use:
@@ -26377,13 +26792,20 @@ use of the table takes only one file descriptor. The extra descriptor
for the first open is used for the index file; this descriptor is shared
among all threads.
+If you are opening a table with the @code{HANDLER table_name OPEN}
+statement, a dedicated table object is allocated for the thread.
+This table object is not shared by other threads an will not be closed
+until the thread calls @code{HANDLER table_name CLOSE} or the thread dies.
+@xref{HANDLER}. When this happens, the table is put back in the table_cache
+(if it isn't full).
+
You can check if your table cache is too small by checking the mysqld
-variable @code{opened_tables}. If this is quite big, even if you
+variable @code{Opened_tables}. If this is quite big, even if you
haven't done a lot of @code{FLUSH TABLES}, you should increase your table
cache. @xref{SHOW STATUS}.
-@node Creating many tables, Open tables, Table cache, Optimizing Database Structure
+@node Creating many tables, , Table cache, Optimising Database Structure
@subsection Drawbacks to Creating Large Numbers of Tables in the Same Database
@cindex tables, too many
@@ -26395,30 +26817,8 @@ every table that has to be opened, another must be closed. You can reduce
this overhead by making the table cache larger.
-@node Open tables, , Creating many tables, Optimizing Database Structure
-@subsection Why So Many Open tables?
-
-@cindex tables, open
-@cindex open tables
-
-When you run @code{mysqladmin status}, you'll see something like this:
-
-@example
-Uptime: 426 Running threads: 1 Questions: 11082 Reloads: 1 Open tables: 12
-@end example
-
-This can be somewhat perplexing if you only have 6 tables.
-
-MySQL is multithreaded, so it may have many queries on the same
-table simultaneously. To minimize the problem with two threads having
-different states on the same file, the table is opened independently by
-each concurrent thread. This takes some memory and one extra file
-descriptor for the data file. The index file descriptor is shared
-between all threads.
-
-
-@node Optimizing the Server, Disk issues, Optimizing Database Structure, MySQL Optimization
-@section Optimizing the MySQL Server
+@node Optimising the Server, Disk issues, Optimising Database Structure, MySQL Optimisation
+@section Optimising the MySQL Server
@menu
@@ -26431,11 +26831,11 @@ between all threads.
@end menu
-@node System, Server parameters, Optimizing the Server, Optimizing the Server
+@node System, Server parameters, Optimising the Server, Optimising the Server
@subsection System/Compile Time and Startup Parameter Tuning
-@cindex compiling, optimizing
-@cindex system optimization
+@cindex compiling, optimising
+@cindex system optimisation
@cindex startup parameters, tuning
We start with the system level things since some of these decisions have
@@ -26486,7 +26886,7 @@ are using @code{--skip-locking}
@end itemize
-@node Server parameters, Compile and link options, System, Optimizing the Server
+@node Server parameters, Compile and link options, System, Optimising the Server
@subsection Tuning Server Parameters
@cindex parameters, server
@@ -26608,7 +27008,7 @@ is done.
When you have installed MySQL, the @file{support-files} directory will
contain some different @code{my.cnf} example files, @file{my-huge.cnf},
@file{my-large.cnf}, @file{my-medium.cnf}, and @file{my-small.cnf}, you can
-use as a base to optimize your system.
+use as a base to optimise your system.
If there are very many connections, ``swapping problems'' may occur unless
@code{mysqld} has been configured to use very little memory for each
@@ -26629,7 +27029,7 @@ options listed after it on the command line will not be reflected in the
output.
-@node Compile and link options, Memory use, Server parameters, Optimizing the Server
+@node Compile and link options, Memory use, Server parameters, Optimising the Server
@subsection How Compiling and Linking Affects the Speed of MySQL
@cindex linking, speed
@@ -26659,10 +27059,10 @@ important if you compile the SQL server yourself!
We have tested both the Cygnus CodeFusion and Fujitsu compilers, but
when we tested them, neither was sufficiently bug free to allow
-MySQL to be compiled with optimizations on.
+MySQL to be compiled with optimisations on.
When you compile MySQL you should only include support for the
-character sets that you are going to use. (Option @code{--with-charset=xxx}).
+character sets that you are going to use. (Option @code{--with-charset=xxx}.)
The standard MySQL binary distributions are compiled with support
for all character sets.
@@ -26685,7 +27085,7 @@ the resulting binary can be up to 4 % faster.
@item
If you connect using TCP/IP rather than Unix sockets, the result is 7.5%
slower on the same computer. (If you are connection to @code{localhost},
-MySQL will, by default, use sockets).
+MySQL will, by default, use sockets.)
@item
If you connect using TCP/IP from another computer over a 100M Ethernet,
@@ -26730,7 +27130,7 @@ binary by compiling with @code{pgcc}. The standard MySQL
Linux binary is linked statically to get it faster and more portable.
-@node Memory use, DNS, Compile and link options, Optimizing the Server
+@node Memory use, DNS, Compile and link options, Optimising the Server
@subsection How MySQL Uses Memory
@cindex memory use
@@ -26839,7 +27239,7 @@ checking available swap with @code{swap -s}. We have tested
be no memory leaks.
-@node DNS, SET OPTION, Memory use, Optimizing the Server
+@node DNS, SET OPTION, Memory use, Optimising the Server
@subsection How MySQL uses DNS
@cindex DNS
@@ -26874,7 +27274,7 @@ If you don't want to allow connections over @code{TCP/IP}, you can do this
by starting @code{mysqld} with @code{--skip-networking}.
-@node SET OPTION, , DNS, Optimizing the Server
+@node SET OPTION, , DNS, Optimising the Server
@subsection @code{SET} Syntax
@findex SET OPTION
@@ -26918,7 +27318,8 @@ mysql> SET PASSWORD FOR bob@@"%.loc.gov" = PASSWORD("newpass");
or
-mysql> UPDATE mysql.user SET password=PASSWORD("newpass") where user="bob' and host="%.loc.gov";
+mysql> UPDATE mysql.user SET password=PASSWORD("newpass")
+ -> WHERE user="bob' AND host="%.loc.gov";
@end example
@item SQL_AUTO_IS_NULL = 0 | 1
@@ -26973,6 +27374,16 @@ flag again, the @code{SQL_MAX_JOIN_SIZE} variable will be ignored.
You can set a default value for this variable by starting @code{mysqld} with
@code{-O max_join_size=#}.
+@item SQL_QUERY_CACHE_TYPE = OFF | ON | DEMAND
+@item SQL_QUERY_CACHE_TYPE = 0 | 1 | 2
+Set query cache setting for this thread.
+@multitable @columnfractions .3 .7
+@item @strong{Option} @tab @strong{Description}
+@item 0 or OFF @tab Don't cache or retrieve results.
+@item 1 or ON @tab Cache all results except @code{SELECT SQL_NO_CACHE ...} queries.
+@item 2 or DEMAND @tab Cache only @code{SELECT SQL_CACHE ...} queries.
+@end multitable
+
@item SQL_SAFE_UPDATES = 0 | 1
If set to @code{1}, MySQL will abort if an @code{UPDATE} or
@code{DELETE} is attempted that doesn't use a key or @code{LIMIT} in the
@@ -27005,7 +27416,7 @@ for replication of tables with fancy column names to work.
@item TIMESTAMP = timestamp_value | DEFAULT
Set the time for this client. This is used to get the original timestamp if
you use the update log to restore rows. @code{timestamp_value} should be a
-UNIX Epoch timestamp, not a MySQL timestamp.
+Unix epoch timestamp, not a MySQL timestamp.
@item LAST_INSERT_ID = #
Set the value to be returned from @code{LAST_INSERT_ID()}. This is stored in
@@ -27018,15 +27429,9 @@ command when inserting an @code{AUTO_INCREMENT} value. This is mainly used
with the update log.
@end table
+@xref{SET TRANSACTION}.
-@menu
-* SET TRANSACTION:: @code{SET TRANSACTION} Syntax
-@end menu
-
-
-
-
-@node Disk issues, , Optimizing the Server, MySQL Optimization
+@node Disk issues, , Optimising the Server, MySQL Optimisation
@section Disk Issues
@cindex disk issues
@@ -27039,7 +27444,7 @@ problems gets more and more apparent when the data starts to grow so
large that effective caching becomes impossible. For large databases,
where you access data more or less randomly, you can be sure that you
will need at least one disk seek to read and a couple of disk seeks to
-write things. To minimize this problem, use disks with low seek times.
+write things. To minimise this problem, use disks with low seek times.
@item
Increase the number of available disk spindles (and thereby reduce
@@ -27066,7 +27471,7 @@ stripe-sizes. @xref{Custom Benchmarks}.
Note that the speed difference for striping is @strong{very} dependent
on the parameters. Depending on how you set the striping parameters and
number of disks you may get a difference in orders of magnitude. Note that
-you have to choose to optimize for random or sequential access.
+you have to choose to optimise for random or sequential access.
@end table
@item
@@ -27133,8 +27538,8 @@ You might want to do this, for example, to move a database to a file
system with more free space or increase the speed of your system by
spreading your tables to different disk.
-The recommended may to do this, is to just symlink databases to different
-disk and only symlink tables as a last resort.
+The recommended way to do this, is to just symlink databases to a
+different disk and only symlink tables as a last resort.
@cindex databases, symbolic links
@menu
@@ -27194,18 +27599,18 @@ databases on different disks. @xref{Windows symbolic links}.
@cindex databases, symbolic links
Before MySQL 4.0 you should not symlink tables, if you are not
-very carefully with them. The problem is that if you run @code{ALTER
+very careful with them. The problem is that if you run @code{ALTER
TABLE}, @code{REPAIR TABLE} or @code{OPTIMIZE TABLE} on a symlinked
table, the symlinks will be removed and replaced by the original
files. This happens because the above command works by creating a
temporary file in the database directory and when the command is
complete, replace the original file with the temporary file.
-You should not symlink tables on system that doesn't have a fully
+You should not symlink tables on systems that don't have a fully
working @code{realpath()} call. (At least Linux and Solaris support
@code{realpath()})
-In MySQL 4.0 symlinks is only fully supported for @code{MyISAM}
+In MySQL 4.0 symlinks are only fully supported for @code{MyISAM}
tables. For other table types you will probably get strange problems
when doing any of the above mentioned commands.
@@ -27234,7 +27639,7 @@ will be created in the same directory where the data/index file is.
@item
When you drop a table that is using symlinks, both the symlink and the
file the symlink points to is dropped. This is a good reason to why you
-should NOT run @code{mysqld} as root and not allow persons to have write
+should @strong{not} run @code{mysqld} as root and not allow persons to have write
access to the MySQL database directories.
@item
@@ -27268,11 +27673,16 @@ Things that are not yet supported:
@end itemize
-
-
-@node Reference, Table types, MySQL Optimization, Top
+@node Reference, Table types, MySQL Optimisation, Top
@chapter MySQL Language Reference
+MySQL has a very complex, but intuitive and easy to learn SQL
+interface. This chapter describes the various commands, types, and functions
+you will need to know in order to use MySQL efficiently and
+effectively. This chapter also serves as a reference to all functionality
+included in MySQL. In order to use this chapter effectively, you
+may find it useful to refer to the various indexes.
+
@menu
* Language Structure:: Language Structure
* Column types:: Column types
@@ -27282,15 +27692,9 @@ Things that are not yet supported:
* Basic User Commands:: Basic MySQL User Utility Commands
* Transactional Commands:: MySQL Transactional and Locking Commands
* Fulltext Search:: MySQL Full-text Search
+* Query Cache:: MySQL Query Cache
@end menu
-MySQL has a very complex, but intuitive and easy to learn SQL
-interface. This chapter describes the various commands, types, and functions
-you will need to know in order to use MySQL efficiently and
-effectively. This chapter also serves as a reference to all functionality
-included in MySQL. In order to use this chapter effectively, you
-may find it useful to refer to the various indexes.
-
@node Language Structure, Column types, Reference, Reference
@section Language Structure
@@ -27341,7 +27745,7 @@ if you run in ANSI mode). Examples:
Within a string, certain sequences have special meaning. Each of these
sequences begins with a backslash (@samp{\}), known as the @emph{escape
-character}. MySQL recognizes the following escape sequences:
+character}. MySQL recognises the following escape sequences:
@c these aren't really functions, but that's probably the most reasonable index
@table @code
@@ -27387,7 +27791,7 @@ A tab character.
ASCII(26) (Control-Z). This character can be encoded to allow you to
go around the problem that ASCII(26) stands for END-OF-FILE on Windows.
(ASCII(26) will cause problems if you try to use
-@code{mysql database < filename}).
+@code{mysql database < filename}.)
@findex \\ (escape)
@findex escape (\\)
@@ -27529,14 +27933,19 @@ like an integer (64-bit precision). In string context these act like a binary
string where each pair of hex digits is converted to a character:
@example
+mysql> SELECT x'FF'
+ -> 255
mysql> SELECT 0xa+0;
- -> 10
+ -> 10
mysql> select 0x5061756c;
- -> Paul
+ -> Paul
@end example
+The x'hexstring' syntax (new in 4.0) is based on ANSI SQL and the 0x
+syntax is based on ODBC.
Hexadecimal strings are often used by ODBC to give values for BLOB columns.
-
+You can convert a string or a number to hexadecimal with the @code{HEX()}
+function.
@node NULL values, , Hexadecimal values, Literals
@subsubsection @code{NULL} Values
@@ -27563,11 +27972,6 @@ or export formats (@code{LOAD DATA INFILE}, @code{SELECT ... INTO OUTFILE}).
@cindex columns, names
@cindex aliases, names
-@menu
-* Name case sensitivity:: Case sensitivity in names
-@end menu
-
-
Database, table, index, column, and alias names all follow the same rules in
MySQL.
@@ -27687,7 +28091,7 @@ because it refers to the alias both as @code{a} and as @code{A}:
@example
mysql> SELECT col_name FROM tbl_name AS a
- WHERE a.col_name = 1 OR A.col_name = 2;
+ -> WHERE a.col_name = 1 OR A.col_name = 2;
@end example
Aliases on columns are case insensitive.
@@ -27721,7 +28125,7 @@ ISO-8859-1 Latin1; this may be changed with the
@code{--default-character-set} option to @code{mysqld}. @xref{Character
sets}.
-Variables don't have to be initialized. They contain @code{NULL} by default
+Variables don't have to be initialised. They contain @code{NULL} by default
and can store an integer, real, or string value. All variables for
a thread are automatically freed when the thread exits.
@@ -27765,12 +28169,6 @@ SELECT (@@aa:=id) AS a, (@@aa+3) AS b FROM table_name HAVING b=5;
The reason is that @code{@@aa} will not contain the value of the current
row, but the value of @code{id} for the previous accepted row.
-
-@menu
-* Comments:: Comment Syntax
-* Reserved words:: Is MySQL Picky About Reserved Words?
-@end menu
-
@node Comments, Reserved words, Variables, Language Structure
@subsection Comment Syntax
@@ -27805,7 +28203,7 @@ parses @code{/* ... */} comments:
@item
Single-quote and double-quote characters are taken to indicate the beginning
of a quoted string, even within a comment. If the quote is not matched by a
-second quote within the comment, the parser doesn't realize the comment has
+second quote within the comment, the parser doesn't realise the comment has
ended. If you are running @code{mysql} interactively, you can tell that it
has gotten confused like this because the prompt changes from @code{mysql>}
to @code{'>} or @code{">}.
@@ -27819,8 +28217,8 @@ These limitations apply both when you run @code{mysql} interactively
and when you put commands in a file and tell @code{mysql} to read its
input from that file with @code{mysql < some-file}.
-MySQL doesn't support the @samp{--} ANSI SQL comment style.
-@xref{Missing comments}.
+MySQL only supports the @samp{--} ANSI SQL comment style if it is
+followed by a space. @xref{ANSI diff comments}.
@node Reserved words, , Comments, Language Structure
@@ -27842,84 +28240,110 @@ them are forbidden by ANSI SQL92 as column and/or table names
A few are reserved because MySQL needs them and is
(currently) using a @code{yacc} parser:
-@c This is fixed by including the symbols table from lex.h here and then running
-@c fix-mysql-reserved-words in emacs (or let David do it):
-@c (defun fix-mysql-reserved-words ()
-@c (interactive)
-@c (let ((cnt 0))
-@c (insert "\n@item ")
-@c (while (looking-at "[ \t]*{ +\"\\([^\"]+\\)\"[ \t]*,.*\n")
-@c (replace-match "@code{\\1}")
-@c (incf cnt)
-@c (if (> cnt 3)
-@c (progn
-@c (setf cnt 0)
-@c (insert "\n@item "))
-@c (insert " @tab ")))))
-@c But remove the non alphanumeric entries by hand first.
-@c Updated after 3.23.4 990928 by David
+@c START_OF_RESERVED_WORDS
@multitable @columnfractions .25 .25 .25 .25
-@item @code{action} @tab @code{add} @tab @code{aggregate} @tab @code{all}
-@item @code{alter} @tab @code{after} @tab @code{and} @tab @code{as}
-@item @code{asc} @tab @code{avg} @tab @code{avg_row_length} @tab @code{auto_increment}
-@item @code{between} @tab @code{bigint} @tab @code{bit} @tab @code{binary}
-@item @code{blob} @tab @code{bool} @tab @code{both} @tab @code{by}
-@item @code{cascade} @tab @code{case} @tab @code{char} @tab @code{character}
-@item @code{change} @tab @code{check} @tab @code{checksum} @tab @code{column}
-@item @code{columns} @tab @code{comment} @tab @code{constraint} @tab @code{create}
-@item @code{cross} @tab @code{current_date} @tab @code{current_time} @tab @code{current_timestamp}
-@item @code{data} @tab @code{database} @tab @code{databases} @tab @code{date}
-@item @code{datetime} @tab @code{day} @tab @code{day_hour} @tab @code{day_minute}
-@item @code{day_second} @tab @code{dayofmonth} @tab @code{dayofweek} @tab @code{dayofyear}
-@item @code{dec} @tab @code{decimal} @tab @code{default} @tab @code{delayed}
-@item @code{delay_key_write} @tab @code{delete} @tab @code{desc} @tab @code{describe}
-@item @code{distinct} @tab @code{distinctrow} @tab @code{double} @tab @code{drop}
-@item @code{end} @tab @code{else} @tab @code{escape} @tab @code{escaped}
-@item @code{enclosed} @tab @code{enum} @tab @code{explain} @tab @code{exists}
-@item @code{fields} @tab @code{file} @tab @code{first} @tab @code{float}
-@item @code{float4} @tab @code{float8} @tab @code{flush} @tab @code{foreign}
-@item @code{from} @tab @code{for} @tab @code{full} @tab @code{function}
-@item @code{global} @tab @code{grant} @tab @code{grants} @tab @code{group}
-@item @code{having} @tab @code{heap} @tab @code{high_priority} @tab @code{hour}
-@item @code{hour_minute} @tab @code{hour_second} @tab @code{hosts} @tab @code{identified}
-@item @code{ignore} @tab @code{in} @tab @code{index} @tab @code{infile}
-@item @code{inner} @tab @code{insert} @tab @code{insert_id} @tab @code{int}
-@item @code{integer} @tab @code{interval} @tab @code{int1} @tab @code{int2}
-@item @code{int3} @tab @code{int4} @tab @code{int8} @tab @code{into}
-@item @code{if} @tab @code{is} @tab @code{isam} @tab @code{join}
-@item @code{key} @tab @code{keys} @tab @code{kill} @tab @code{last_insert_id}
-@item @code{leading} @tab @code{left} @tab @code{length} @tab @code{like}
-@item @code{lines} @tab @code{limit} @tab @code{load} @tab @code{local}
-@item @code{lock} @tab @code{logs} @tab @code{long} @tab @code{longblob}
-@item @code{longtext} @tab @code{low_priority} @tab @code{max} @tab @code{max_rows}
-@item @code{match} @tab @code{mediumblob} @tab @code{mediumtext} @tab @code{mediumint}
-@item @code{middleint} @tab @code{min_rows} @tab @code{minute} @tab @code{minute_second}
-@item @code{modify} @tab @code{month} @tab @code{monthname} @tab @code{myisam}
-@item @code{natural} @tab @code{numeric} @tab @code{no} @tab @code{not}
-@item @code{null} @tab @code{on} @tab @code{optimize} @tab @code{option}
-@item @code{optionally} @tab @code{or} @tab @code{order} @tab @code{outer}
-@item @code{outfile} @tab @code{pack_keys} @tab @code{partial} @tab @code{password}
-@item @code{precision} @tab @code{primary} @tab @code{procedure} @tab @code{process}
-@item @code{processlist} @tab @code{privileges} @tab @code{read} @tab @code{real}
-@item @code{references} @tab @code{reload} @tab @code{regexp} @tab @code{rename}
-@item @code{replace} @tab @code{restrict} @tab @code{returns} @tab @code{revoke}
-@item @code{rlike} @tab @code{row} @tab @code{rows} @tab @code{second}
-@item @code{select} @tab @code{set} @tab @code{show} @tab @code{shutdown}
-@item @code{smallint} @tab @code{soname} @tab @code{sql_big_tables} @tab @code{sql_big_selects}
-@item @code{sql_low_priority_updates} @tab @code{sql_log_off} @tab @code{sql_log_update} @tab @code{sql_select_limit}
-@item @code{sql_small_result} @tab @code{sql_big_result} @tab @code{sql_warnings} @tab @code{straight_join}
-@item @code{starting} @tab @code{status} @tab @code{string} @tab @code{table}
-@item @code{tables} @tab @code{temporary} @tab @code{terminated} @tab @code{text}
-@item @code{then} @tab @code{time} @tab @code{timestamp} @tab @code{tinyblob}
-@item @code{tinytext} @tab @code{tinyint} @tab @code{trailing} @tab @code{to}
-@item @code{type} @tab @code{use} @tab @code{using} @tab @code{unique}
-@item @code{unlock} @tab @code{unsigned} @tab @code{update} @tab @code{usage}
-@item @code{values} @tab @code{varchar} @tab @code{variables} @tab @code{varying}
-@item @code{varbinary} @tab @code{with} @tab @code{write} @tab @code{when}
-@item @code{where} @tab @code{year} @tab @code{year_month} @tab @code{zerofill}
+@item @strong{Word} @tab @strong{Word} @tab @strong{Word} @tab @strong{Word}
+@c Reserved word list updated Fri Dec 7 10:49:17 2001 by arjen.
+@c To regenerate, use Support/update-reserved-words.pl.
+
+@item @code{ADD} @tab @code{ALL}
+ @tab @code{ALTER} @tab @code{ANALYZE}
+@item @code{AND} @tab @code{AS}
+ @tab @code{ASC} @tab @code{AUTO_INCREMENT}
+@item @code{BDB} @tab @code{BERKELEYDB}
+ @tab @code{BETWEEN} @tab @code{BIGINT}
+@item @code{BINARY} @tab @code{BLOB}
+ @tab @code{BOTH} @tab @code{BY}
+@item @code{CASCADE} @tab @code{CASE}
+ @tab @code{CHANGE} @tab @code{CHAR}
+@item @code{CHARACTER} @tab @code{COLUMN}
+ @tab @code{COLUMNS} @tab @code{CONSTRAINT}
+@item @code{CREATE} @tab @code{CROSS}
+ @tab @code{CURRENT_DATE} @tab @code{CURRENT_TIME}
+@item @code{CURRENT_TIMESTAMP} @tab @code{DATABASE}
+ @tab @code{DATABASES} @tab @code{DAY_HOUR}
+@item @code{DAY_MINUTE} @tab @code{DAY_SECOND}
+ @tab @code{DEC} @tab @code{DECIMAL}
+@item @code{DEFAULT} @tab @code{DELAYED}
+ @tab @code{DELETE} @tab @code{DESC}
+@item @code{DESCRIBE} @tab @code{DISTINCT}
+ @tab @code{DISTINCTROW} @tab @code{DOUBLE}
+@item @code{DROP} @tab @code{ELSE}
+ @tab @code{ENCLOSED} @tab @code{ESCAPED}
+@item @code{EXISTS} @tab @code{EXPLAIN}
+ @tab @code{FIELDS} @tab @code{FLOAT}
+@item @code{FOR} @tab @code{FOREIGN}
+ @tab @code{FROM} @tab @code{FULLTEXT}
+@item @code{FUNCTION} @tab @code{GRANT}
+ @tab @code{GROUP} @tab @code{HAVING}
+@item @code{HIGH_PRIORITY} @tab @code{HOUR_MINUTE}
+ @tab @code{HOUR_SECOND} @tab @code{IF}
+@item @code{IGNORE} @tab @code{IN}
+ @tab @code{INDEX} @tab @code{INFILE}
+@item @code{INNER} @tab @code{INNODB}
+ @tab @code{INSERT} @tab @code{INSERT_ID}
+@item @code{INT} @tab @code{INTEGER}
+ @tab @code{INTERVAL} @tab @code{INTO}
+@item @code{IS} @tab @code{JOIN}
+ @tab @code{KEY} @tab @code{KEYS}
+@item @code{KILL} @tab @code{LAST_INSERT_ID}
+ @tab @code{LEADING} @tab @code{LEFT}
+@item @code{LIKE} @tab @code{LIMIT}
+ @tab @code{LINES} @tab @code{LOAD}
+@item @code{LOCK} @tab @code{LONG}
+ @tab @code{LONGBLOB} @tab @code{LONGTEXT}
+@item @code{LOW_PRIORITY} @tab @code{MASTER_LOG_SEQ}
+ @tab @code{MASTER_SERVER_ID} @tab @code{MATCH}
+@item @code{MEDIUMBLOB} @tab @code{MEDIUMINT}
+ @tab @code{MEDIUMTEXT} @tab @code{MIDDLEINT}
+@item @code{MINUTE_SECOND} @tab @code{MRG_MYISAM}
+ @tab @code{NATURAL} @tab @code{NOT}
+@item @code{NULL} @tab @code{NUMERIC}
+ @tab @code{ON} @tab @code{OPTIMIZE}
+@item @code{OPTION} @tab @code{OPTIONALLY}
+ @tab @code{OR} @tab @code{ORDER}
+@item @code{OUTER} @tab @code{OUTFILE}
+ @tab @code{PARTIAL} @tab @code{PRECISION}
+@item @code{PRIMARY} @tab @code{PRIVILEGES}
+ @tab @code{PROCEDURE} @tab @code{PURGE}
+@item @code{READ} @tab @code{REAL}
+ @tab @code{REFERENCES} @tab @code{REGEXP}
+@item @code{RENAME} @tab @code{REPLACE}
+ @tab @code{REQUIRE} @tab @code{RESTRICT}
+@item @code{RETURNS} @tab @code{REVOKE}
+ @tab @code{RIGHT} @tab @code{RLIKE}
+@item @code{SELECT} @tab @code{SET}
+ @tab @code{SHOW} @tab @code{SMALLINT}
+@item @code{SONAME} @tab @code{SQL_AUTO_IS_NULL}
+ @tab @code{SQL_BIG_RESULT} @tab @code{SQL_BIG_SELECTS}
+@item @code{SQL_BIG_TABLES} @tab @code{SQL_BUFFER_RESULT}
+ @tab @code{SQL_CALC_FOUND_ROWS} @tab @code{SQL_LOG_BIN}
+@item @code{SQL_LOG_OFF} @tab @code{SQL_LOG_UPDATE}
+ @tab @code{SQL_LOW_PRIORITY_UPDATES} @tab @code{SQL_MAX_JOIN_SIZE}
+@item @code{SQL_QUOTE_SHOW_CREATE} @tab @code{SQL_SAFE_UPDATES}
+ @tab @code{SQL_SELECT_LIMIT} @tab @code{SQL_SLAVE_SKIP_COUNTER}
+@item @code{SQL_SMALL_RESULT} @tab @code{SQL_WARNINGS}
+ @tab @code{SSL} @tab @code{STARTING}
+@item @code{STRAIGHT_JOIN} @tab @code{STRIPED}
+ @tab @code{TABLE} @tab @code{TABLES}
+@item @code{TERMINATED} @tab @code{THEN}
+ @tab @code{TINYBLOB} @tab @code{TINYINT}
+@item @code{TINYTEXT} @tab @code{TO}
+ @tab @code{TRAILING} @tab @code{UNION}
+@item @code{UNIQUE} @tab @code{UNLOCK}
+ @tab @code{UNSIGNED} @tab @code{UPDATE}
+@item @code{USAGE} @tab @code{USE}
+ @tab @code{USING} @tab @code{VALUES}
+@item @code{VARBINARY} @tab @code{VARCHAR}
+ @tab @code{VARYING} @tab @code{WHEN}
+@item @code{WHERE} @tab @code{WITH}
+ @tab @code{WRITE} @tab @code{YEAR_MONTH}
+@item @code{ZEROFILL}
@end multitable
+@c END_OF_RESERVED_WORDS
+
The following symbols (from the table above) are disallowed by ANSI SQL
but allowed by MySQL as column/table names. This is because some
of these names are very natural names and a lot of people have already
@@ -27946,7 +28370,7 @@ used them.
MySQL supports a number of column types, which may be grouped into
three categories: numeric types, date and time types, and string (character)
types. This section first gives an overview of the types available and
-summarizes the storage requirements for each column type, then provides a
+summarises the storage requirements for each column type, then provides a
more detailed description of the properties of the types in each category.
The overview is intentionally brief. The more detailed descriptions should
be consulted for additional information about particular column types, such
@@ -27982,6 +28406,10 @@ that are optional.
Note that if you specify @code{ZEROFILL} for a column, MySQL will
automatically add the @code{UNSIGNED} attribute to the column.
+@strong{Warning:} You should be aware that when you use subtraction
+between integers values where one is of type @code{UNSIGNED}, the result
+will be unsigned! @xref{Cast Functions}.
+
@table @code
@tindex TINYINT
@item TINYINT[(M)] [UNSIGNED] [ZEROFILL]
@@ -28029,6 +28457,18 @@ values, so you shouldn't use unsigned big integers larger than
@code{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 the @code{BIGINT} to a @code{DOUBLE}.
+
+MySQL 4.0 can handle @code{BIGINT} in the following cases:
+@itemize @bullet
+@item
+Use integers to store big unsigned values in a @code{BIGINT} column.
+@item
+In @code{MIN(big_int_column)} and @code{MAX(big_int_column)}.
+@item
+When using operators (@code{+}, @code{-}, @code{*} etc) where
+both operands are integers.
+@end itemize
+
@item
You can always store an exact integer value in a @code{BIGINT} column by
storing it as a string, as there is in this case there will be no
@@ -28174,7 +28614,7 @@ are @code{1901} to @code{2155}, @code{0000} in the 4-digit year format,
and 1970-2069 if you use the 2-digit format (70-69). MySQL displays
@code{YEAR} values in @code{YYYY} format, but allows you to assign values to
@code{YEAR} columns using either strings or numbers. (The @code{YEAR} type is
-new in MySQL Version 3.22.). @xref{YEAR}.
+new in MySQL Version 3.22.) @xref{YEAR}.
@tindex NATIONAL CHAR
@tindex NCHAR
@@ -28214,7 +28654,7 @@ These three are synonyms for @code{CHAR(1)}.
@tindex VARCHAR
@item [NATIONAL] VARCHAR(M) [BINARY]
-A variable-length string. @strong{NOTE:} Trailing spaces are removed when
+A variable-length string. @strong{Note:} Trailing spaces are removed when
the value is stored (this differs from the ANSI SQL specification). The range
of @code{M} is 1 to 255 characters. @code{VARCHAR} values are sorted and
compared in case-insensitive fashion unless the @code{BINARY} keyword is
@@ -28311,7 +28751,7 @@ significant decimal digits that will be stored for values, and @code{2}
(@code{scale}) represents the number of digits that will be stored
following the decimal point. In this case, therefore, the range of
values that can be stored in the @code{salary} column is from
-@code{-9999999.99} to @code{9999999.99}.
+@code{-9999999.99} to @code{9999999.99}.
(MySQL can actually store numbers up to @code{9999999.99} in this column
because it doesn't have to store the sign for positive numbers)
@@ -28386,7 +28826,7 @@ digits when the value is stored.
The @code{REAL} and @code{DOUBLE PRECISION} types do not accept
precision specifications. As an extension to the ANSI/ISO SQL92
-standard, MySQL recognizes @code{DOUBLE} as a synonym for the
+standard, MySQL recognises @code{DOUBLE} as a synonym for the
@code{DOUBLE PRECISION} type. In contrast with the standard's
requirement that the precision for @code{REAL} be smaller than that used
for @code{DOUBLE PRECISION}, MySQL implements both as 8-byte
@@ -28595,7 +29035,7 @@ later:
@itemize @bullet
@item
Let MySQL set the column when the row is created.
-This will initialize it to the current date and time.
+This will initialise it to the current date and time.
@item
When you perform subsequent updates to other columns in the row, set
@@ -28603,7 +29043,7 @@ the @code{TIMESTAMP} column explicitly to its current value.
@end itemize
On the other hand, you may find it just as easy to use a @code{DATETIME}
-column that you initialize to @code{NOW()} when the row is created and
+column that you initialise to @code{NOW()} when the row is created and
leave alone for subsequent updates.
@code{TIMESTAMP} values may range from the beginning of 1970 to sometime in
@@ -28818,7 +29258,7 @@ You can specify @code{TIME} values in a variety of formats:
@itemize @bullet
@item
As a string in @code{'D HH:MM:SS.fraction'} format. (Note that
-MySQL doesn't yet store the fraction for the time column). One
+MySQL doesn't yet store the fraction for the time column.) One
can also use one of the following ``relaxed'' syntax:
@code{HH:MM:SS.fraction}, @code{HH:MM:SS}, @code{HH:MM}, @code{D HH:MM:SS},
@@ -28848,14 +29288,14 @@ seconds values that are less than @code{10}. @code{'8:3:2'} is the same as
@code{'08:03:02'}.
Be careful about assigning ``short'' @code{TIME} values to a @code{TIME}
-column. Without semicolon, MySQL interprets values using the
-assumption that the rightmost digits represent seconds. (MySQL
-interprets @code{TIME} values as elapsed time rather than as time of
-day.) For example, you might think of @code{'1112'} and @code{1112} as
+column. Without colons, MySQL interprets values using the
+assumption that the rightmost digits represent seconds. (MySQL
+interprets @code{TIME} values as elapsed time rather than as time of
+day.) For example, you might think of @code{'1112'} and @code{1112} as
meaning @code{'11:12:00'} (12 minutes after 11 o'clock), but
MySQL interprets them as @code{'00:11:12'} (11 minutes, 12 seconds).
Similarly, @code{'12'} and @code{12} are interpreted as @code{'00:00:12'}.
-@code{TIME} values with semicolon, instead, are always treated as
+@code{TIME} values with colons, by contrast, are always treated as
time of the day. That is @code{'11:12'} will mean @code{'11:12:00'},
not @code{'00:11:12'}.
@@ -29054,8 +29494,8 @@ object. The standard way to do this is with the @code{SUBSTRING}
function. For example:
@example
-mysql> select comment from tbl_name,substring(comment,20) as substr
- ORDER BY substr;
+mysql> SELECT comment FROM tbl_name,substring(comment,20) AS substr
+ -> ORDER BY substr;
@end example
If you don't do this, only the first @code{max_sort_length} bytes of the
@@ -29065,10 +29505,8 @@ column are used when sorting. The default value of @code{max_sort_length} is
@code{TEXT} values by specifying the column position or by using an alias:
@example
-mysql> select id,substring(blob_col,1,100) from tbl_name
- GROUP BY 2;
-mysql> select id,substring(blob_col,1,100) as b from tbl_name
- GROUP BY b;
+mysql> SELECT id,substring(blob_col,1,100) FROM tbl_name GROUP BY 2;
+mysql> SELECT id,substring(blob_col,1,100) AS b FROM tbl_name GROUP BY b;
@end example
@item
@@ -29101,7 +29539,9 @@ certain circumstances:
@item
If you insert an invalid value into an @code{ENUM} (that is, a string not
present in the list of allowed values), the empty string is inserted
-instead as a special error value.
+instead as a special error value. This string can be distinguished from a
+'normal' empty string by the fact that this string has the numerical value
+0. More about this later.
@item
If an @code{ENUM} is declared @code{NULL}, @code{NULL} is also a legal value
@@ -29235,6 +29675,9 @@ specified at table creation time. For example, if a column is specified as
@code{SET("a","b","c","d")}, then @code{"a,d"}, @code{"d,a"}, and
@code{"d,a,a,d,d"} will all appear as @code{"a,d"} when retrieved.
+If you set a @code{SET} column to an unsupported value, the value will
+be ignored.
+
@code{SET} values are sorted numerically. @code{NULL} values sort before
non-@code{NULL} @code{SET} values.
@@ -29431,7 +29874,7 @@ An expression that contains @code{NULL} always produces a @code{NULL} value
unless otherwise indicated in the documentation for the operators and
functions involved in the expression.
-@strong{NOTE:} There must be no whitespace between a function name and the
+@strong{Note:} There must be no whitespace between a function name and the
parenthesis following it. This helps the MySQL parser distinguish
between function calls and references to tables or columns that happen to
have the same name as a function. Spaces around arguments are permitted,
@@ -29447,7 +29890,7 @@ For the sake of brevity, examples display the output from the @code{mysql}
program in abbreviated form. So this:
@example
-mysql> select MOD(29,9);
+mysql> SELECT MOD(29,9);
1 rows in set (0.00 sec)
+-----------+
@@ -29460,7 +29903,7 @@ mysql> select MOD(29,9);
is displayed like this:
@example
-mysql> select MOD(29,9);
+mysql> SELECT MOD(29,9);
-> 2
@end example
@@ -29469,7 +29912,9 @@ mysql> select MOD(29,9);
* String functions:: String functions
* Numeric Functions:: Numeric Functions
* Date and time functions:: Date and time functions
+* Cast Functions:: Cast Functions
* Other Functions:: Other Functions
+* Group by functions:: Functions for Use with @code{GROUP BY} Clauses
@end menu
@@ -29497,13 +29942,13 @@ mysql> select MOD(29,9);
( ... )
@end example
-Use parenthesis to force the order of evaluation in an expression. For
+Use parenthesis to force the order of evaluation in an expression. For
example:
@example
-mysql> select 1+2*3;
+mysql> SELECT 1+2*3;
-> 7
-mysql> select (1+2)*3;
+mysql> SELECT (1+2)*3;
-> 9
@end example
@@ -29644,7 +30089,7 @@ mysql> select 2 > 2;
@cindex @code{NULL}, testing for null
@findex <=> (Equal to)
@item <=>
-Null safe equal:
+NULL safe equal:
@example
mysql> select 1 <=> 1, NULL <=> NULL, 1 <=> NULL;
-> 1 1 0
@@ -29663,6 +30108,32 @@ mysql> select 1 IS NOT NULL, 0 IS NOT NULL, NULL IS NOT NULL;
-> 1 1 0
@end example
+@cindex ODBC compatibility
+@cindex compatibility, with ODBC
+To be able to work good with other programs, MySQL supports the following
+extra features when using @code{IS NULL}:
+
+@itemize @bullet
+@item
+You can find the last inserted row with:
+
+@example
+SELECT * FROM tbl_name WHERE auto_col IS NULL
+@end example
+
+This can be disabled by setting @code{SQL_AUTO_IS_NULL=0}. @xref{SET OPTION}.
+@item
+For @code{NOT NULL} @code{DATE} and @code{DATETIME} columns you can find
+the special date @code{0000-00-00} by using:
+
+@example
+SELECT * FROM tbl_name WHERE date_column IS NULL
+@end example
+
+This is needed to get some ODBC applications to work (as ODBC doesn't
+support a @code{0000-00-00} date)
+@end itemize
+
@findex BETWEEN ... AND
@item expr BETWEEN min AND max
If @code{expr} is greater than or equal to @code{min} and @code{expr} is
@@ -30032,14 +30503,23 @@ mysql> select OCT(12);
@end example
@findex HEX()
-@item HEX(N)
-Returns a string representation of the hexadecimal value of @code{N}, where
-@code{N} is a longlong (@code{BIGINT}) number. This is equivalent to
-@code{CONV(N,10,16)}. Returns @code{NULL} if @code{N} is @code{NULL}:
+@item HEX(N_or_S)
+
+If N_OR_S is a number, returns a string representation of the hexadecimal
+value of @code{N}, where @code{N} is a longlong (@code{BIGINT}) number.
+This is equivalent to @code{CONV(N,10,16)}.
+
+If N_OR_S is a string, returns a hexadecimal string of N_OR_S where each
+character in N_OR_S is converted to 2 hexadecimal digits. This is the
+invers of the @code{0xff} strings.
@example
mysql> select HEX(255);
-> 'FF'
+mysql> select HEX("abc");
+ -> 616263
+mysql> select 0x616263;
+ -> "abc"
@end example
@findex CHAR()
@@ -30108,6 +30588,15 @@ mysql> select OCTET_LENGTH('text');
Note that for @code{CHAR_LENGTH()}, multi-byte characters are only counted
once.
+@findex BIT_LENGTH()
+@item BIT_LENGTH(str)
+Returns the length of the string @code{str} in bits:
+
+@example
+mysql> select BIT_LENGTH('text');
+ -> 32
+@end example
+
@findex LOCATE()
@findex POSITION()
@item LOCATE(substr,str)
@@ -30122,7 +30611,9 @@ mysql> select LOCATE('xbar', 'foobar');
-> 0
@end example
-This function is multi-byte safe.
+This function is multi-byte safe. In MySQL 3.23 this function is case
+insensitive, while in 4.0 it's only case insensitive if either argument is
+a binary string.
@findex LOCATE()
@item LOCATE(substr,str,pos)
@@ -30135,7 +30626,9 @@ mysql> select LOCATE('bar', 'foobarbar',5);
-> 7
@end example
-This function is multi-byte safe.
+This function is multi-byte safe. In MySQL 3.23 this function is case
+insensitive, while in 4.0 it's only case insensitive if either argument is
+a binary string.
@findex INSTR()
@item INSTR(str,substr)
@@ -30150,7 +30643,9 @@ mysql> select INSTR('xbar', 'foobar');
-> 0
@end example
-This function is multi-byte safe.
+This function is multi-byte safe. In MySQL 3.23 this function is case
+insensitive, while in 4.0 it's only case insensitive if either argument is
+a binary string.
@findex LPAD()
@item LPAD(str,len,padstr)
@@ -30392,7 +30887,7 @@ Returns a value @code{1} to @code{N} if the string @code{str} is in the list
@code{strlist} consisting of @code{N} substrings. A string list is a string
composed of substrings separated by @samp{,} characters. If the first
argument is a constant string and the second is a column of type @code{SET},
-the @code{FIND_IN_SET()} function is optimized to use bit arithmetic!
+the @code{FIND_IN_SET()} function is optimised to use bit arithmetic!
Returns @code{0} if @code{str} is not in @code{strlist} or if @code{strlist}
is the empty string. Returns @code{NULL} if either argument is @code{NULL}.
This function will not work properly if the first argument contains a
@@ -30530,6 +31025,7 @@ SQL simple regular expression comparison. Returns @code{1} (TRUE) or @code{0}
in the pattern:
@multitable @columnfractions .1 .9
+@item @strong{Char} @tab @strong{Description}
@item @code{%} @tab Matches any number of characters, even zero characters
@item @code{_} @tab Matches exactly one character
@end multitable
@@ -30546,6 +31042,7 @@ with the escape character. If you don't specify the @code{ESCAPE} character,
@samp{\} is assumed:
@multitable @columnfractions .1 .9
+@item @strong{String} @tab @strong{Description}
@item @code{\%} @tab Matches one @code{%} character
@item @code{\_} @tab Matches one @code{_} character
@end multitable
@@ -30648,18 +31145,16 @@ mysql> select STRCMP('text', 'text');
@findex MATCH ... AGAINST()
@item MATCH (col1,col2,...) AGAINST (expr)
+@itemx MATCH (col1,col2,...) AGAINST (expr IN BOOLEAN MODE)
@code{MATCH ... AGAINST()} is used for full-text search and returns
relevance - similarity measure between the text in columns
@code{(col1,col2,...)} and the query @code{expr}. Relevance is a
positive floating-point number. Zero relevance means no similarity.
-For @code{MATCH ... AGAINST()} to work, a @strong{FULLTEXT} index
-must be created first. @xref{CREATE TABLE, , @code{CREATE TABLE}}.
-@code{MATCH ... AGAINST()} is available in MySQL Version
-3.23.23 or later. For details and usage examples
-@pxref{Fulltext Search}.
+@code{MATCH ... AGAINST()} is available in MySQL version
+3.23.23 or later. @code{IN BOOLEAN MODE} extension was added in version
+4.0.1. For details and usage examples, see @ref{Fulltext Search}.
@end table
-
@node Case Sensitivity Operators, , String comparison functions, String functions
@subsubsection Case Sensitivity
@@ -30681,6 +31176,8 @@ mysql> select BINARY "a" = "A";
-> 0
@end example
+@code{BINARY string} is a shorthand for @code{CAST(string AS BINARY)}.
+@xref{Cast Functions}.
@code{BINARY} was introduced in MySQL Version 3.23.0.
Note that in some context MySQL will not be able to use the
@@ -30710,9 +31207,13 @@ make string comparison even more flexible.
@node Arithmetic functions, Mathematical functions, Numeric Functions, Numeric Functions
@subsubsection Arithmetic Operations
+@cindex operators, cast
The usual arithmetic operators are available. Note that in the case of
@samp{-}, @samp{+}, and @samp{*}, the result is calculated with
@code{BIGINT} (64-bit) precision if both arguments are integers!
+If one of the argument is an unsigned integer, and the other argument
+is also an integer, the result will be an unsigned integer.
+@xref{Cast Functions}.
@cindex operations, arithmetic
@cindex arithmetic expressions
@@ -30748,8 +31249,9 @@ mysql> select 18014398509481984*18014398509481984;
-> 0
@end example
-The result of the last expression is incorrect because the result of the integer
-multiplication exceeds the 64-bit range of @code{BIGINT} calculations.
+The result of the last expression is incorrect because the result of the
+integer multiplication exceeds the 64-bit range of @code{BIGINT}
+calculations.
@findex / (division)
@findex division (/)
@@ -31052,16 +31554,17 @@ Returns a random floating-point value in the range @code{0} to @code{1.0}.
If an integer argument @code{N} is specified, it is used as the seed value:
@example
mysql> select RAND();
- -> 0.5925
+ -> 0.9233482386203
mysql> select RAND(20);
- -> 0.1811
+ -> 0.15888261251047
mysql> select RAND(20);
- -> 0.1811
+ -> 0.15888261251047
mysql> select RAND();
- -> 0.2079
+ -> 0.63553050033332
mysql> select RAND();
- -> 0.7888
+ -> 0.70100469486881
@end example
+
You can't use a column with @code{RAND()} values in an @code{ORDER BY}
clause, because @code{ORDER BY} would evaluate the column multiple times.
In MySQL Version 3.23, you can, however, do:
@@ -31073,6 +31576,10 @@ table1,table2 WHERE a=b AND c<d ORDER BY RAND() LIMIT 1000}.
Note that a @code{RAND()} in a @code{WHERE} clause will be re-evaluated
every time the @code{WHERE} is executed.
+@code{RAND()} is not meant to be a perfect random generator, but instead a
+fast way to generate add-hook random numbers that will be portable between
+platforms for the same MySQL version.
+
@findex LEAST()
@item LEAST(X,Y,...)
With two or more arguments, returns the smallest (minimum-valued) argument.
@@ -31160,12 +31667,11 @@ mysql> select TRUNCATE(10.28*100,0);
-> 1027
@end example
-The above happens because 10.28 is actually stored as something like
+The above happens because 10.28 is actually stored as something like
10.2799999999999999.
@end table
-
-@node Date and time functions, Other Functions, Numeric Functions, Functions
+@node Date and time functions, Cast Functions, Numeric Functions, Functions
@subsection Date and Time Functions
@findex date and time functions
@@ -31287,6 +31793,9 @@ mysql> select WEEK('1998-12-31',1);
-> 53
@end example
+Note: in Version 4.0, @code{WEEK(#,0)} was changed to match the
+calendar in the USA.
+
@findex YEAR()
@item YEAR(date)
Returns the year for @code{date}, in the range @code{1000} to @code{9999}:
@@ -31422,19 +31931,19 @@ mysql> SELECT INTERVAL 1 DAY + "1997-12-31";
mysql> SELECT "1998-01-01" - INTERVAL 1 SECOND;
-> 1997-12-31 23:59:59
mysql> SELECT DATE_ADD("1997-12-31 23:59:59",
- INTERVAL 1 SECOND);
+ -> INTERVAL 1 SECOND);
-> 1998-01-01 00:00:00
mysql> SELECT DATE_ADD("1997-12-31 23:59:59",
- INTERVAL 1 DAY);
+ -> INTERVAL 1 DAY);
-> 1998-01-01 23:59:59
mysql> SELECT DATE_ADD("1997-12-31 23:59:59",
- INTERVAL "1:1" MINUTE_SECOND);
+ -> INTERVAL "1:1" MINUTE_SECOND);
-> 1998-01-01 00:01:00
mysql> SELECT DATE_SUB("1998-01-01 00:00:00",
- INTERVAL "1 1:1:1" DAY_SECOND);
+ -> INTERVAL "1 1:1:1" DAY_SECOND);
-> 1997-12-30 22:58:59
mysql> SELECT DATE_ADD("1998-01-01 00:00:00",
- INTERVAL "-1 10" DAY_HOUR);
+ -> INTERVAL "-1 10" DAY_HOUR);
-> 1997-12-30 14:00:00
mysql> SELECT DATE_SUB("1998-01-02", INTERVAL 31 DAY);
-> 1997-12-02
@@ -31526,6 +32035,7 @@ the days that were lost when the calendar was changed.
Formats the @code{date} value according to the @code{format} string. The
following specifiers may be used in the @code{format} string:
@multitable @columnfractions .1 .6
+@item @strong{Specifier} @tab @strong{Description}
@item @code{%M} @tab Month name (@code{January}..@code{December})
@item @code{%W} @tab Weekday name (@code{Sunday}..@code{Saturday})
@item @code{%D} @tab Day of the month with English suffix (@code{1st}, @code{2nd}, @code{3rd}, etc.)
@@ -31638,10 +32148,11 @@ mysql> select NOW() + 0;
@item UNIX_TIMESTAMP()
@itemx UNIX_TIMESTAMP(date)
If called with no argument, returns a Unix timestamp (seconds since
-@code{'1970-01-01 00:00:00'} GMT). If @code{UNIX_TIMESTAMP()} is called with
-a @code{date} argument, it returns the value of the argument as seconds since
-@code{'1970-01-01 00:00:00'} GMT. @code{date} may be a @code{DATE} string,
-a @code{DATETIME} string, a @code{TIMESTAMP}, or a number in the format
+@code{'1970-01-01 00:00:00'} GMT) as an unsigned integer. If
+@code{UNIX_TIMESTAMP()} is called with a @code{date} argument, it
+returns the value of the argument as seconds since @code{'1970-01-01
+00:00:00'} GMT. @code{date} may be a @code{DATE} string, a
+@code{DATETIME} string, a @code{TIMESTAMP}, or a number in the format
@code{YYMMDD} or @code{YYYYMMDD} in local time:
@example
@@ -31652,11 +32163,14 @@ mysql> select UNIX_TIMESTAMP('1997-10-04 22:23:00');
@end example
When @code{UNIX_TIMESTAMP} is used on a @code{TIMESTAMP} column, the function
-will receive the value directly, with no implicit
+will return the internal timestamp value directly, with no implicit
``string-to-unix-timestamp'' conversion.
If you give @code{UNIX_TIMESTAMP()} a wrong or out-of-range date, it will
return 0.
+If you want to subtract @code{UNIX_TIMESTAMP()} columns, you may want to
+cast the result to signed integers. @xref{Cast Functions}.
+
@findex FROM_UNIXTIME()
@item FROM_UNIXTIME(unix_timestamp)
Returns a representation of the @code{unix_timestamp} argument as a value in
@@ -31679,7 +32193,7 @@ those listed in the entry for the @code{DATE_FORMAT()} function:
@example
mysql> select FROM_UNIXTIME(UNIX_TIMESTAMP(),
'%Y %D %M %h:%i:%s %x');
- -> '1997 23rd December 03:43:30 x'
+ -> '1997 23rd December 03:43:30 1997'
@end example
@findex SEC_TO_TIME()
@@ -31707,8 +32221,105 @@ mysql> select TIME_TO_SEC('00:39:38');
@end example
@end table
+@node Cast Functions, Other Functions, Date and time functions, Functions
+@subsection Cast Functions
+
+The syntax of the @code{CAST} function is:
+
+@findex CAST
+@findex CONVERT
+
+@example
+CAST(expression AS type)
+
+or
+
+CONVERT(expression,type)
+@end example
+
+Where type is one of:
+@itemize @bullet
+@item
+@code{BINARY}
+@item
+@code{DATE}
+@item
+@code{DATETIME}
+@item
+@code{SIGNED @{INTEGER@}}
+@item
+@code{TIME}
+@item
+@code{UNSIGNED @{INTEGER@}}
+@end itemize
+
+@code{CAST()} is ANSI SQL99 syntax and @code{CONVERT()} is ODBC syntax.
+
+The cast function is mainly useful when you want to create a column with
+a specific type in a @code{CREATE ... SELECT}:
+
+@example
+CREATE TABLE new_table SELECT CAST('2000-01-01' AS DATE);
+@end example
+
+@code{CAST(string AS BINARY} is the same thing as @code{BINARY string}.
+
+To cast a string to a numeric value, you don't normally have to do
+anything; Just use the string value as it would be a number:
+
+@example
+mysql> select 1+'1';
+ -> 2
+@end example
+
+MySQL supports arithmetic with both signed and unsigned 64 bit values.
+If you are using an numerical operations (like @code{+}) and one of the
+operands are @code{unsigned integer}, then the result will be unsigned.
+You can override this by using the @code{SIGNED} and @code{UNSIGNED}
+cast operators, which will cast the operation to signed respective
+unsigned 64 bit integer.
+
+@example
+mysql> select CAST(1-2 AS UNSIGNED)
+ -> 18446744073709551615
+mysql select CAST(CAST(1-2 AS UNSIGNED) AS SIGNED);
+ -> -1
+@end example
+
+Note that if either operation is a floating point value (In this context
+@code{DECIMAL()} is regarded as a floating point value) the result will
+be a floating point value and is not affected by the above rule.
+
+@example
+mysql> select CAST(1 AS UNSIGNED) -2.0
+ -> -1.0
+@end example
+
+If you are using a string in an arithmetic operation, this is converted
+to a floating point number.
+
+The @code{CAST()} and @code{CONVERT()} functions were added in MySQL 4.0.2.
+
+The handing of unsigned values was changed in MySQL 4.0 to be able to
+support @code{BIGINT} values properly. If you have some code that you
+want to run in both MySQL 4.0 and 3.23 (in which case you probably can't
+use the CAST function), you can use the following trick to get a signed
+result when subtracting two unsigned integer columns:
+
+@example
+SELECT (unsigned_column_1+0.0)-(unsigned_column_2+0.0);
+@end example
+
+The idea is that the columns are converted to floating point before doing
+the subtraction.
-@node Other Functions, , Date and time functions, Functions
+If you get a problem with @code{UNSIGNED} columns in your old MySQL
+application when porting to MySQL 4.0, you can use the
+@code{--sql-mode=NO_UNSIGNED_SUBTRACTION} option when starting
+@code{mysqld}. Note however that as long as you use this, you will not
+be able to make efficient use of the @code{UNSIGNED BIGINT} column type.
+
+@node Other Functions, Group by functions, Cast Functions, Functions
@subsection Other Functions
@menu
@@ -31732,12 +32343,14 @@ these operators have a maximum range of 64 bits.
@findex | (bitwise OR)
@findex OR, bitwise
@item |
-Bitwise OR:
+Bitwise OR
@example
mysql> select 29 | 15;
-> 31
@end example
+The result is an unsigned 64 bit integer.
+
@findex & (bitwise AND)
@findex AND, bitwise
@item &
@@ -31747,6 +32360,8 @@ mysql> select 29 & 15;
-> 13
@end example
+The result is an unsigned 64 bit integer.
+
@findex << (left shift)
@item <<
Shifts a longlong (@code{BIGINT}) number to the left:
@@ -31755,6 +32370,8 @@ mysql> select 1 << 2;
-> 4
@end example
+The result is an unsigned 64 bit integer.
+
@findex >> (right shift)
@item >>
Shifts a longlong (@code{BIGINT}) number to the right:
@@ -31763,6 +32380,8 @@ mysql> select 4 >> 2;
-> 1
@end example
+The result is an unsigned 64 bit integer.
+
@findex ~
@item ~
Invert all bits:
@@ -31771,6 +32390,8 @@ mysql> select 5 & ~1;
-> 4
@end example
+The result is an unsigned 64 bit integer.
+
@findex BIT_COUNT()
@item BIT_COUNT(N)
Returns the number of bits that are set in the argument @code{N}:
@@ -31885,6 +32506,83 @@ mysql> select MD5("testing");
This is an "RSA Data Security, Inc. MD5 Message-Digest Algorithm".
+@findex des_encrypt()
+@item des_encrypt(string_to_encrypt, flag, [, (key_number | key_string) ] )
+
+Encrypts the string with the given key using the DES algorithm, which
+provides strong encryption.
+
+Note that this function only works if you have configured MySQL with
+SSL support. @xref{Secure connections}.
+
+The encryption key to use is chosen the following way:
+
+@multitable @columnfractions .2 .8
+@item @strong{Argument} @tab @strong{Description}
+@item Only one argument @tab
+The first key from @code{des-key-file} is used.
+@item key number @tab
+The given key (0-9) from the @code{des-key-file} is used.
+@item string @tab
+The given @code{key_string} will be used to crypt @code{string_to_encrypt}.
+@end multitable
+
+The return string will be a binary string where the first character
+will be @code{CHAR(128 | key-number)}.
+
+The 128 is added to make it easier to recognize a crypted key.
+If one uses a string key, @code{key-number} will be 127.
+
+On error, this function returns NULL.
+
+The string length for the result will be
+@code{new_length= org_length + (8-(org_length % 8))+1}.
+
+The @code{des-key-file} has the following format:
+
+@example
+key-number key-string
+key-number key-string
+@end example
+
+The @code{key-number} must be a number between 0-9. The numbers may be
+in any order. @code{des-key-string} is string that will be used to
+crypt the message. Between the number and the key there should be at
+least one space. The first key is the default key that will be used
+if one doesn't specify a key to @code{des_encrypt()}
+
+You can tell MySQL to read new key values from the key file with the
+@code{FLUSH DES_KEY_FILE} command.
+
+One benefit with having a set of default keys on can use is that it
+gives applications a way to check for existence of crypted column,
+without giving the end user the right to uncrypt the data.
+
+@example
+SELECT customer_address FROM customer_table WHERE
+crypted_credit_card = DES_ENCRYPT("credit_card_number");
+@end example
+
+@findex des_decrypt()
+@item des_decrypt(string_to_decrypt [, key_string])
+
+Decrypts a string crypted with @code{des_encrypt()}.
+
+Note that this function only works if you have configured MySQL with
+SSL support. @xref{Secure connections}.
+
+If one only gives this a string argument, then it will use the right key
+from the @code{des-key-file} to decrypt the message. For this to work
+the user must have the @code{PROCESS_PRIV} privilege.
+
+If one calls this function with 2 arguments, the second argument is
+used to decrypt the message.
+
+If the @code{string_to_decrypt} doesn't look like a crypted string MySQL will
+return the given @code{string_to_decrypt}.
+
+On error, this function returns NULL.
+
@findex LAST_INSERT_ID([expr])
@item LAST_INSERT_ID([expr])
Returns the last automatically generated value that was inserted into an
@@ -32064,16 +32762,193 @@ above number is calculated as @code{209*256^3 + 207*256^2 + 224*256 +40}.
@findex MASTER_POS_WAIT()
@item MASTER_POS_WAIT(log_name, log_pos)
Blocks until the slave reaches the specified position in the master log during
-replication. If master information is not initialized, returns NULL. If the
+replication. If master information is not initialised, returns NULL. If the
slave is not running, will block and wait until it is started and goes to or
past
the specified position. If the slave is already past the specified position,
returns immediately. The return value is the number of log events it had to
wait to get to the specified position, or NULL in case of error. Useful for
-control of master-slave synchronization, but was originally written to
+control of master-slave synchronisation, but was originally written to
facilitate replication testing.
+
+@findex FOUND_ROWS()
+@findex LIMIT
+@item FOUND_ROWS()
+Returns the number of rows that the last @code{SELECT SQL_CALC_FOUND_ROWS ...}
+command would have returned, if wasn't restricted with @code{LIMIT}.
+
+@example
+SELECT SQL_CALC_FOUND_ROWS * FROM table_name WHERE id > 100 LIMIT 10;
+SELECT FOUND_ROWS();
+@end example
+
+The second select will return how many rows the SELECT should have
+returned if we would remove the @code{LIMIT} clause.
+
+Note that if you are using @code{SELECT SQL_CALC_FOUND_ROWS ...} MySQL has
+to calculate all rows in the result set. This is however faster than
+if you would not use @code{LIMIT} as the result set doesn't have to be sent
+to the client.
+@end table
+
+
+@node Group by functions, , Other Functions, Functions
+@subsection Functions for Use with @code{GROUP BY} Clauses
+
+@findex GROUP BY functions
+@findex functions, GROUP BY
+
+If you use a group function in a statement containing no @code{GROUP BY}
+clause, it is equivalent to grouping on all rows.
+
+@table @code
+@findex COUNT()
+@item COUNT(expr)
+Returns a count of the number of non-@code{NULL} values in the rows
+retrieved by a @code{SELECT} statement:
+
+@example
+mysql> SELECT student.student_name,COUNT(*)
+ -> FROM student,course
+ -> WHERE student.student_id=course.student_id
+ -> GROUP BY student_name;
+
+@end example
+
+@code{COUNT(*)} is somewhat different in that it returns a count of
+the number of rows retrieved, whether or not they contain @code{NULL}
+values.
+
+@code{COUNT(*)} is optimised to
+return very quickly if the @code{SELECT} retrieves from one table, no
+other columns are retrieved, and there is no @code{WHERE} clause.
+For example:
+
+@example
+mysql> select COUNT(*) from student;
+@end example
+
+@findex COUNT(DISTINCT)
+@findex DISTINCT
+@item COUNT(DISTINCT expr,[expr...])
+Returns a count of the number of different non-@code{NULL} values:
+
+@example
+mysql> select COUNT(DISTINCT results) from student;
+@end example
+
+In MySQL you can get the number of distinct expression
+combinations that don't contain NULL by giving a list of expressions.
+In ANSI SQL you would have to do a concatenation of all expressions
+inside @code{CODE(DISTINCT ...)}.
+
+@findex AVG()
+@item AVG(expr)
+Returns the average value of @code{expr}:
+
+@example
+mysql> select student_name, AVG(test_score)
+ -> from student
+ -> GROUP BY student_name;
+@end example
+
+@findex MIN()
+@findex MAX()
+@item MIN(expr)
+@itemx MAX(expr)
+Returns the minimum or maximum value of @code{expr}. @code{MIN()} and
+@code{MAX()} may take a string argument; in such cases they return the
+minimum or maximum string value. @xref{MySQL indexes}.
+
+@example
+mysql> select student_name, MIN(test_score), MAX(test_score)
+ -> from student
+ -> GROUP BY student_name;
+@end example
+
+@findex SUM()
+@item SUM(expr)
+Returns the sum of @code{expr}. Note that if the return set has no rows,
+it returns NULL!
+
+@findex STD()
+@findex STDDEV()
+@cindex Oracle compatibility
+@cindex compatibility, with Oracle
+@item STD(expr)
+@itemx STDDEV(expr)
+Returns the standard deviation of @code{expr}. This is an extension to
+ANSI SQL. The @code{STDDEV()} form of this function is provided for Oracle
+compatibility.
+
+@findex BIT_OR()
+@item BIT_OR(expr)
+Returns the bitwise @code{OR} of all bits in @code{expr}. The calculation is
+performed with 64-bit (@code{BIGINT}) precision.
+
+@findex BIT_AND()
+@item BIT_AND(expr)
+Returns the bitwise @code{AND} of all bits in @code{expr}. The calculation is
+performed with 64-bit (@code{BIGINT}) precision.
@end table
+@cindex @code{GROUP BY}, extensions to ANSI SQL
+MySQL has extended the use of @code{GROUP BY}. You can use columns or
+calculations in the @code{SELECT} expressions that don't appear in
+the @code{GROUP BY} part. This stands for @emph{any possible value for this
+group}. You can use this to get better performance by avoiding sorting and
+grouping on unnecessary items. For example, you don't need to group on
+@code{customer.name} in the following query:
+
+@example
+mysql> select order.custid,customer.name,max(payments)
+ -> from order,customer
+ -> where order.custid = customer.custid
+ -> GROUP BY order.custid;
+@end example
+
+In ANSI SQL, you would have to add @code{customer.name} to the @code{GROUP
+BY} clause. In MySQL, the name is redundant if you don't run in
+ANSI mode.
+
+@strong{Don't use this feature} if the columns you omit from the
+@code{GROUP BY} part aren't unique in the group! You will get
+unpredictable results.
+
+In some cases, you can use @code{MIN()} and @code{MAX()} to obtain a specific
+column value even if it isn't unique. The following gives the value of
+@code{column} from the row containing the smallest value in the @code{sort}
+column:
+
+@example
+substr(MIN(concat(rpad(sort,6,' '),column)),7)
+@end example
+
+@xref{example-Maximum-column-group-row}.
+
+@cindex @code{ORDER BY}, aliases in
+@cindex aliases, in @code{ORDER BY} clauses
+@cindex @code{GROUP BY}, aliases in
+@cindex aliases, in @code{GROUP BY} clauses
+@cindex expression aliases
+@cindex aliases, for expressions
+Note that if you are using MySQL Version 3.22 (or earlier) or if
+you are trying to follow ANSI SQL, you can't use expressions in @code{GROUP
+BY} or @code{ORDER BY} clauses. You can work around this limitation by
+using an alias for the expression:
+
+@example
+mysql> SELECT id,FLOOR(value/100) AS val FROM tbl_name
+ -> GROUP BY id,val ORDER BY val;
+@end example
+
+In MySQL Version 3.23 you can do:
+
+@example
+mysql> SELECT id,FLOOR(value/100) FROM tbl_name ORDER BY RAND();
+@end example
+
+
@node Data Manipulation, Data Definition, Functions, Reference
@section Data Manipulation: @code{SELECT}, @code{INSERT}, @code{UPDATE}, @code{DELETE}
@@ -32081,8 +32956,9 @@ facilitate replication testing.
@menu
* SELECT:: @code{SELECT} Syntax
+* HANDLER:: @code{HANDLER} Syntax
* INSERT:: @code{INSERT} Syntax
-* INSERT DELAYED:: @code{INSERT DELAYED} syntax
+* INSERT DELAYED:: @code{INSERT DELAYED} Syntax
* UPDATE:: @code{UPDATE} Syntax
* DELETE:: @code{DELETE} Syntax
* TRUNCATE:: @code{TRUNCATE} Syntax
@@ -32091,26 +32967,27 @@ facilitate replication testing.
* DO:: @code{DO} Syntax
@end menu
-@node SELECT, INSERT, Data Manipulation, Data Manipulation
+@node SELECT, HANDLER, Data Manipulation, Data Manipulation
@subsection @code{SELECT} Syntax
@findex SELECT
@c help SELECT
@example
-SELECT [STRAIGHT_JOIN] [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
- [HIGH_PRIORITY]
+SELECT [STRAIGHT_JOIN]
+ [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
+ [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS] [HIGH_PRIORITY]
[DISTINCT | DISTINCTROW | ALL]
select_expression,...
[INTO @{OUTFILE | DUMPFILE@} 'file_name' export_options]
[FROM table_references
- [WHERE where_definition]
- [GROUP BY @{unsigned_integer | col_name | formula@} [ASC | DESC], ...]
- [HAVING where_definition]
- [ORDER BY @{unsigned_integer | col_name | formula@} [ASC | DESC] ,...]
- [LIMIT [offset,] rows]
- [PROCEDURE procedure_name]
- [FOR UPDATE | LOCK IN SHARE MODE]]
+ [WHERE where_definition]
+ [GROUP BY @{unsigned_integer | col_name | formula@} [ASC | DESC], ...]
+ [HAVING where_definition]
+ [ORDER BY @{unsigned_integer | col_name | formula@} [ASC | DESC] ,...]
+ [LIMIT [offset,] rows]
+ [PROCEDURE procedure_name]
+ [FOR UPDATE | LOCK IN SHARE MODE]]
@end example
@c help end
@@ -32143,9 +33020,33 @@ mysql> select concat(last_name,', ',first_name) AS full_name
@end example
@item
+It is not allowed to use a column alias in a @code{WHERE} clause,
+because the column value may not yet be determined when the
+@code{WHERE} clause is executed.
+@xref{Problems with alias}.
+
+@item
+@findex AS
+@findex USE INDEX
+@findex IGNORE INDEX
+@findex USE KEY
+@findex IGNORE KEY
The @code{FROM table_references} clause indicates the tables from which to
retrieve rows. If you name more than one table, you are performing a
join. For information on join syntax, see @ref{JOIN, , @code{JOIN}}.
+For each table specified, you may optionally specify an alias.
+@example
+table_name [[AS] alias] [USE INDEX (key_list)] [IGNORE INDEX (key_list)]
+@end example
+As of MySQL Version 3.23.12, you can give hints about which
+index MySQL should use when retrieving information from a
+table. This is useful if @code{EXPLAIN} shows that MySQL is
+using the wrong index. By specifying @code{USE INDEX (key_list)}, you
+can tell MySQL to use only one of the specified indexes to
+find rows in the table. The alternative syntax @code{IGNORE INDEX
+(key_list)} can be used to tell MySQL to not use some
+particular index.
+@code{USE/IGNORE KEY} are synonyms for @code{USE/IGNORE INDEX}.
@item
You can refer to a column as @code{col_name}, @code{tbl_name.col_name}, or
@@ -32162,9 +33063,9 @@ A table reference may be aliased using @code{tbl_name [AS] alias_name}:
@example
mysql> select t1.name, t2.salary from employee AS t1, info AS t2
- where t1.name = t2.name;
+ -> where t1.name = t2.name;
mysql> select t1.name, t2.salary from employee t1, info t2
- where t1.name = t2.name;
+ -> where t1.name = t2.name;
@end example
@item
@@ -32174,11 +33075,11 @@ positions. Column positions begin with 1:
@example
mysql> select college, region, seed from tournament
- ORDER BY region, seed;
+ -> ORDER BY region, seed;
mysql> select college, region AS r, seed AS s from tournament
- ORDER BY r, s;
+ -> ORDER BY r, s;
mysql> select college, region, seed from tournament
- ORDER BY 2, 3;
+ -> ORDER BY 2, 3;
@end example
To sort in reverse order, add the @code{DESC} (descending) keyword to the
@@ -32193,7 +33094,7 @@ MySQL support. @xref{Functions}.
@item
The @code{HAVING} clause can refer to any column or alias named in the
@code{select_expression}. It is applied last, just before items are sent to
-the client, with no optimization. Don't use @code{HAVING} for items that
+the client, with no optimisation. Don't use @code{HAVING} for items that
should be in the @code{WHERE} clause. For example, do not write this:
@example
@@ -32210,20 +33111,19 @@ In MySQL Version 3.22.5 or later, you can also write queries like this:
@example
mysql> select user,max(salary) from users
- group by user HAVING max(salary)>10;
+ -> group by user HAVING max(salary)>10;
@end example
In older MySQL versions, you can write this instead:
@example
mysql> select user,max(salary) AS sum from users
- group by user HAVING sum>10;
+ -> group by user HAVING sum>10;
@end example
@item
-@code{SQL_SMALL_RESULT}, @code{SQL_BIG_RESULT}, @code{SQL_BUFFER_RESULT},
-@code{STRAIGHT_JOIN}, and @code{HIGH_PRIORITY} are MySQL extensions
-to ANSI SQL92.
+All options beginning with @code{SQL_}, @code{STRAIGHT_JOIN}, and
+@code{HIGH_PRIORITY} are MySQL extensions to ANSI SQL.
@item
@code{HIGH_PRIORITY} will give the @code{SELECT} higher priority than
@@ -32234,7 +33134,7 @@ statement that is waiting for the table to be free.
@item
@code{SQL_BIG_RESULT} can be used with @code{GROUP BY} or @code{DISTINCT}
-to tell the optimizer that the result set will have many rows. In this case,
+to tell the optimiser that the result set will have many rows. In this case,
MySQL will directly use disk-based temporary tables if needed.
MySQL will also, in this case, prefer sorting to doing a
temporary table with a key on the @code{GROUP BY} elements.
@@ -32246,12 +33146,27 @@ in cases where it takes a long time to send the result set to the client.
@item
@code{SQL_SMALL_RESULT}, a MySQL-specific option, can be used
-with @code{GROUP BY} or @code{DISTINCT} to tell the optimizer that the
+with @code{GROUP BY} or @code{DISTINCT} to tell the optimiser that the
result set will be small. In this case, MySQL will use fast
temporary tables to store the resulting table instead of using sorting. In
MySQL Version 3.23 this shouldn't normally be needed.
@item
+@code{SQL_CALC_FOUND_ROWS} tells MySQL to calculate how many rows there
+would be in the result, disregarding any @code{LIMIT} clause. The number
+of rows can be obtained with @code{SELECT
+FOUND_ROWS()}. @xref{Miscellaneous functions}.
+
+@item
+@code{SQL_CACHE} tells MySQL to store the query result in the query cache
+if you are using @code{SQL_QUERY_CACHE_TYPE=2} (@code{DEMAND}).
+@xref{Query Cache}.
+
+@item
+@code{SQL_NO_CACHE} tells MySQL to not allow the query result to be stored
+in the query cache. @xref{Query Cache}.
+
+@item
@cindex @code{GROUP BY}, extensions to ANSI SQL
If you use @code{GROUP BY}, the output rows will be sorted according to the
@code{GROUP BY} as if you would have had an @code{ORDER BY} over all the fields
@@ -32270,9 +33185,24 @@ read the @code{GROUP BY} description.
@xref{Group by functions}.
@item
-@code{STRAIGHT_JOIN} forces the optimizer to join the tables in the order in
+@cindex hints
+@code{SQL_BUFFER_RESULT} will force the result to be put into a temporary
+table. This will help MySQL free the table locks early and will help
+in cases where it takes a long time to send the result set to the client.
+
+@item
+@cindex hints
+@code{SQL_SMALL_RESULT}, a MySQL-specific option, can be used
+with @code{GROUP BY} or @code{DISTINCT} to tell the optimiser that the
+result set will be small. In this case, MySQL will use fast
+temporary tables to store the resulting table instead of using sorting. In
+MySQL Version 3.23 this shouldn't normally be needed.
+
+@item
+@cindex hints
+@code{STRAIGHT_JOIN} forces the optimiser to join the tables in the order in
which they are listed in the @code{FROM} clause. You can use this to speed up
-a query if the optimizer joins the tables in non-optimal order.
+a query if the optimiser joins the tables in non-optimal order.
@xref{EXPLAIN, , @code{EXPLAIN}}.
@item
@@ -32329,7 +33259,7 @@ the @code{ESCAPED BY} character:
Additionally, @code{ASCII 0} is converted to @code{ESCAPED BY} followed by 0
(@code{ASCII 48}).
-The reason for the above is that you MUST escape any @code{FIELDS
+The reason for the above is that you @strong{must} escape any @code{FIELDS
TERMINATED BY}, @code{ESCAPED BY}, or @code{LINES TERMINATED BY}
characters to reliably be able to read the file back. @code{ASCII 0} is
escaped to make it easier to view with some pagers.
@@ -32369,9 +33299,10 @@ the examined rows will be write locked.
@menu
* JOIN:: @code{JOIN} Syntax
+* UNION:: @code{UNION} Syntax
@end menu
-@node JOIN, , SELECT, SELECT
+@node JOIN, UNION, SELECT, SELECT
@subsubsection @code{JOIN} Syntax
@findex JOIN
@@ -32405,6 +33336,7 @@ table_reference NATURAL [RIGHT [OUTER]] JOIN table_reference
@end example
Where @code{table_reference} is defined as:
+@findex AS
@example
table_name [[AS] alias] [USE INDEX (key_list)] [IGNORE INDEX (key_list)]
@end example
@@ -32436,7 +33368,7 @@ A table reference may be aliased using @code{tbl_name AS alias_name} or
@example
mysql> select t1.name, t2.salary from employee AS t1, info AS t2
- where t1.name = t2.name;
+ -> where t1.name = t2.name;
@end example
@item
@@ -32451,14 +33383,14 @@ records in a table that have no counterpart in another table:
@example
mysql> select table1.* from table1
- LEFT JOIN table2 ON table1.id=table2.id
- where table2.id is NULL;
+ -> LEFT JOIN table2 ON table1.id=table2.id
+ -> where table2.id is NULL;
@end example
This example finds all rows in @code{table1} with an @code{id} value that is
not present in @code{table2} (that is, all rows in @code{table1} with no
corresponding row in @code{table2}). This assumes that @code{table2.id} is
-declared @code{NOT NULL}, of course. @xref{LEFT JOIN optimization}.
+declared @code{NOT NULL}, of course. @xref{LEFT JOIN optimisation}.
@item
The @code{USING} @code{(column_list)} clause names a list of columns that must
@@ -32482,16 +33414,26 @@ with a @code{USING} clause that names all columns that exist in both
tables.
@item
+@cindex hints
+@code{INNER JOIN} and @code{,} (comma) are semantically equivalent.
+Both do a full join between the tables used. Normally, you specify
+how the tables should be linked in the WHERE condition.
+
+@item
@code{RIGHT JOIN} works analogously as @code{LEFT JOIN}. To keep code
portable across databases, it's recommended to use @code{LEFT JOIN}
instead of @code{RIGHT JOIN}.
@item
+@cindex hints
@code{STRAIGHT_JOIN} is identical to @code{JOIN}, except that the left table
is always read before the right table. This can be used for those (few)
-cases where the join optimizer puts the tables in the wrong order.
+cases where the join optimiser puts the tables in the wrong order.
@item
+@cindex hints
+@findex USE INDEX
+@findex IGNORE INDEX
As of MySQL Version 3.23.12, you can give hints about which
index MySQL should use when retrieving information from a
table. This is useful if @code{EXPLAIN} shows that MySQL is
@@ -32500,26 +33442,112 @@ can tell MySQL to use only one of the specified indexes to
find rows in the table. The alternative syntax @code{IGNORE INDEX
(key_list)} can be used to tell MySQL to not use some
particular index.
+@findex USE KEY
+@findex IGNORE KEY
+@code{USE/IGNORE KEY} are synonyms for @code{USE/IGNORE INDEX}.
@end itemize
Some examples:
@example
-mysql> select * from table1,table2 where table1.id=table2.id;
-mysql> select * from table1 LEFT JOIN table2 ON table1.id=table2.id;
-mysql> select * from table1 LEFT JOIN table2 USING (id);
-mysql> select * from table1 LEFT JOIN table2 ON table1.id=table2.id
- LEFT JOIN table3 ON table2.id=table3.id;
-mysql> select * from table1 USE INDEX (key1,key2) WHERE key1=1 and key2=2 AND
- key3=3;
-mysql> select * from table1 IGNORE INDEX (key3) WHERE key1=1 and key2=2 AND
- key3=3;
+mysql> SELECT * FROM table1,table2 WHERE table1.id=table2.id;
+mysql> SELECT * FROM table1 LEFT JOIN table2 ON table1.id=table2.id;
+mysql> SELECT * FROM table1 LEFT JOIN table2 USING (id);
+mysql> SELECT * FROM table1 LEFT JOIN table2 ON table1.id=table2.id
+ -> LEFT JOIN table3 ON table2.id=table3.id;
+mysql> SELECT * FROM table1 USE INDEX (key1,key2)
+ -> WHERE key1=1 AND key2=2 AND key3=3;
+mysql> SELECT * FROM table1 IGNORE INDEX (key3)
+ -> WHERE key1=1 AND key2=2 AND key3=3;
@end example
-@xref{LEFT JOIN optimization, , @code{LEFT JOIN} optimization}.
+@xref{LEFT JOIN optimisation, , @code{LEFT JOIN} optimisation}.
-@node INSERT, INSERT DELAYED, SELECT, Data Manipulation
+@node UNION, , JOIN, SELECT
+@subsubsection @code{UNION} Syntax
+
+@findex UNION
+
+@example
+SELECT ...
+UNION [ALL]
+SELECT ...
+ [UNION
+ SELECT ...]
+@end example
+
+@code{UNION} is implemented in MySQL 4.0.0.
+
+@code{UNION} is used to combine the result from many @code{SELECT}
+statements into one result set.
+
+The @code{SELECT} commands are normal select commands, but with the following
+restrictions:
+
+@itemize @bullet
+@item
+Only the last @code{SELECT} command can have @code{INTO OUTFILE}.
+@end itemize
+
+If you don't use the keyword @code{ALL} for the @code{UNION}, all
+returned rows will be unique, like if you had done a @code{DISTINCT} for
+the total result set. If you specify @code{ALL}, then you will get all
+matching rows from all the used @code{SELECT} statements.
+
+If you want to use an @code{ORDER BY} for the total @code{UNION} result,
+you should use parentheses:
+
+@example
+(SELECT a FROM table_name WHERE a=10 AND B=1 ORDER BY a LIMIT 10) UNION
+(SELECT a FROM table_name WHERE a=11 AND B=2 ORDER BY a LIMIT 10) ORDER BY a;
+@end example
+
+@findex HANDLER
+@node HANDLER, INSERT, SELECT, Data Manipulation
+@subsection @code{HANDLER} Syntax
+
+@example
+HANDLER table OPEN [ AS alias ]
+HANDLER table READ index @{ = | >= | <= | < @} (value1, value2, ... ) [ WHERE ... ] [LIMIT ... ]
+HANDLER table READ index @{ FIRST | NEXT | PREV | LAST @} [ WHERE ... ] [LIMIT ... ]
+HANDLER table READ @{ FIRST | NEXT @} [ WHERE ... ] [LIMIT ... ]
+HANDLER table CLOSE
+@end example
+
+The @code{HANDLER} statement provides direct access to MySQL table
+interface, bypassing SQL optimiser. Thus, it is faster then SELECT.
+
+The first form of @code{HANDLER} statement opens a table, making
+in accessible via the following @code{HANDLER ... READ} routines.
+This table object is not shared by other threads an will not be closed
+until the thread calls @code{HANDLER table_name CLOSE} or the thread dies.
+
+The second form fetches one (or, specified by @code{LIMIT} clause) row
+where the index specified complies to the condition and @code{WHERE}
+condition is met. If the index consists of several parts (spans over
+several columns) the values are specified in comma-separated list,
+providing values only for few first columns is possible.
+
+The third form fetches one (or, specified by @code{LIMIT} clause) row
+from the table in index order, matching @code{WHERE} condition.
+
+The fourth form (without index specification) fetches one (or, specified
+by @code{LIMIT} clause) row from the table in natural row order (as stored
+in data file) matching @code{WHERE} condition. It is faster than
+@code{HANDLER table READ index} when full table scan is desired.
+
+The last form closes the table, opened with @code{HANDLER ... OPEN}.
+
+@code{HANDLER} is somewhat low-level statement, for example it does not
+provide consistency. That is @code{HANDLER ... OPEN} does @strong{NOT}
+takes a snapshot of the table, and does @strong{NOT} locks the table. The
+above means, that after @code{HANDLER ... OPEN} table data can be
+modified (by this or other thread) and these modifications may appear only
+partially in @code{HANDLER ... NEXT} or @code{HANDLER ... PREV} scans.
+
+
+@node INSERT, INSERT DELAYED, HANDLER, Data Manipulation
@subsection @code{INSERT} Syntax
@findex INSERT
@@ -32557,11 +33585,18 @@ If you specify no column list for @code{INSERT ... VALUES} or @code{INSERT
the columns in the table, use @code{DESCRIBE tbl_name} to find out.
@item
+@cindex default values
Any column not explicitly given a value is set to its default value. For
example, if you specify a column list that doesn't name all the columns in
the table, unnamed columns are set to their default values. Default value
assignment is described in @ref{CREATE TABLE, , @code{CREATE TABLE}}.
+MySQL always has a default value for all fields. This is something
+that is imposed on MySQL to be able to work with both transactional
+and not transactional tables.
+
+Our view is that checking of fields content should be done in the
+application and not in the database server.
@item
An @code{expression} may refer to any column that was set earlier in a value
list. For example, you can say this:
@@ -32690,7 +33725,7 @@ the query. @xref{INSERT}.
@item
To ensure that the update log/binary log can be used to re-create the
original tables, MySQL will not allow concurrent inserts during
-@code{INSERT .... SELECT}.
+@code{INSERT ... SELECT}.
@end itemize
You can of course also use @code{REPLACE} instead of @code{INSERT} to
@@ -32698,7 +33733,7 @@ overwrite old rows.
@node INSERT DELAYED, UPDATE, INSERT, Data Manipulation
-@subsection @code{INSERT DELAYED} syntax
+@subsection @code{INSERT DELAYED} Syntax
@findex INSERT DELAYED
@findex DELAYED
@@ -32891,40 +33926,95 @@ only a given number of rows are changed.
@findex DELETE
@example
-DELETE [LOW_PRIORITY] FROM tbl_name
- [WHERE where_definition]
- [LIMIT rows]
+DELETE [LOW_PRIORITY | QUICK] FROM table_name
+ [WHERE where_definition]
+ [ORDER BY ...]
+ [LIMIT rows]
+
+or
+
+DELETE [LOW_PRIORITY | QUICK] table_name[.*] [,table_name[.*] ...]
+ FROM table-references
+ [WHERE where_definition]
+
+or
+
+DELETE [LOW_PRIORITY | QUICK]
+ FROM table_name[.*], [table_name[.*] ...]
+ USING table-references
+ [WHERE where_definition]
@end example
-@code{DELETE} deletes rows from @code{tbl_name} that satisfy the condition
+@code{DELETE} deletes rows from @code{table_name} that satisfy the condition
given by @code{where_definition}, and returns the number of records deleted.
If you issue a @code{DELETE} with no @code{WHERE} clause, all rows are
deleted. If you do this in @code{AUTOCOMMIT} mode, this works as
-@code{TRUNCATE}. @xref{TRUNCATE}. One problem with this is that
-@code{DELETE} will return zero as the number of affected records, but
-this will be fixed in 4.0.
+@code{TRUNCATE}. @xref{TRUNCATE}. In MySQL 3.23 @code{DELETE} without a
+@code{WHERE} clause will return zero as the number of affected records.
If you really want to know how many records are deleted when you are deleting
all rows, and are willing to suffer a speed penalty, you can use a
@code{DELETE} statement of this form:
@example
-mysql> DELETE FROM tbl_name WHERE 1>0;
+mysql> DELETE FROM table_name WHERE 1>0;
@end example
-Note that this is MUCH slower than @code{DELETE FROM tbl_name} with no
+Note that this is much slower than @code{DELETE FROM table_name} with no
@code{WHERE} clause, because it deletes rows one at a time.
If you specify the keyword @code{LOW_PRIORITY}, execution of the
@code{DELETE} is delayed until no other clients are reading from the table.
-Deleted records are maintained in a linked list and subsequent @code{INSERT}
-operations reuse old record positions. To reclaim unused space and reduce
-file sizes, use the @code{OPTIMIZE TABLE} statement or the @code{myisamchk}
-utility to reorganize tables. @code{OPTIMIZE TABLE} is easier, but
-@code{myisamchk} is faster.
-See @ref{OPTIMIZE TABLE, , @code{OPTIMIZE TABLE}} and @ref{Optimization}.
+If you specify the word @code{QUICK} then the table handler will not
+merge index leafs during delete, which may speed up certain kind of
+deletes.
+
+In MyISAM tables deleted records are maintained in a linked list and
+subsequent @code{INSERT} operations reuse old record positions. To
+reclaim unused space and reduce file sizes, use the @code{OPTIMIZE
+TABLE} statement or the @code{myisamchk} utility to reorganise tables.
+@code{OPTIMIZE TABLE} is easier, but @code{myisamchk} is faster. See
+@ref{OPTIMIZE TABLE, , @code{OPTIMIZE TABLE}} and @ref{Optimisation}.
+
+The first multi table delete format is supported starting from MySQL 4.0.0.
+The second multi table delete format is supported starting from MySQL 4.0.2.
+
+The idea is that only matching rows from the tables listed
+@strong{before} the @code{FROM} or before the @code{USING} clause is
+deleted. The effect is that you can delete rows from many tables at the
+same time and also have additional tables that are used for searching.
+
+The @code{.*} after the table names is there just to be compatible with
+@code{Access}:
+
+@example
+DELETE t1,t2 FROM t1,t2,t3 WHERE t1.id=t2.id AND t2.id=t3.id
+
+or
+
+DELETE FROM t1,t2 USING t1,t2,t3 WHERE t1.id=t2.id AND t2.id=t3.id
+@end example
+
+In the above case we delete matching rows just from tables @code{t1} and
+@code{t2}.
+
+@code{ORDER BY} and using multiple tables in the DELETE is supported in
+MySQL 4.0.
+
+If an @code{ORDER BY} clause is used, the rows will be deleted in that order.
+This is really only useful in conjunction with @code{LIMIT}. For example:
+
+@example
+DELETE FROM somelog
+WHERE user = 'jcole'
+ORDER BY timestamp
+LIMIT 1
+@end example
+
+This will delete the oldest entry (by @code{timestamp}) where the row matches
+the @code{WHERE} clause.
The MySQL-specific @code{LIMIT rows} option to @code{DELETE} tells
the server the maximum number of rows to be deleted before control is
@@ -32943,16 +34033,19 @@ the @code{LIMIT} value.
TRUNCATE TABLE table_name
@end example
-Is in 3.23 and the same thing as @code{DELETE FROM table_name}. @xref{DELETE}.
-The differences are:
+In 3.23 @code{TRUNCATE TABLE} is mapped to
+@code{COMMIT ; DELETE FROM table_name}. @xref{DELETE}.
+
+The differences between @code{TRUNCATE TABLE} and @code{DELETE FROM ...}
+are:
@itemize @bullet
@item
-Implemented as a drop and re-create of the table, which makes this
-much faster when deleting many rows.
+Truncates does a drop and re-create of the table, which is much faster
+than deleting rows one by one.
@item
-Not transaction-safe; @code{TRUNCATE TABLE} will automatically end the current
-transaction as if @code{COMMIT} would have been called.
+Not transaction-safe; You will get an error if you have an active
+transaction or an active table lock.
@item
Doesn't return the number of deleted rows.
@item
@@ -32963,7 +34056,6 @@ files have become corrupted.
@code{TRUNCATE} is an Oracle SQL extension.
-
@node REPLACE, LOAD DATA, TRUNCATE, Data Manipulation
@subsection @code{REPLACE} Syntax
@@ -33029,6 +34121,10 @@ Also, to use @code{LOAD DATA INFILE} on server files, you must have the
@strong{file} privilege on the server host.
@xref{Privileges provided}.
+In MySQL 3.23.49 and MySQL 4.0.2 @code{LOCAL} will only work if you have
+not started @code{mysqld} with @code{--local-infile=0} or if you
+have not enabled your client to support @code{LOCAL}. @xref{LOAD DATA LOCAL}.
+
If you specify the keyword @code{LOW_PRIORITY}, execution of the
@code{LOAD DATA} statement is delayed until no other clients are reading
from the table.
@@ -33186,15 +34282,15 @@ fields delimited by commas:
@example
mysql> SELECT * INTO OUTFILE 'data.txt'
- FIELDS TERMINATED BY ','
- FROM ...;
+ -> FIELDS TERMINATED BY ','
+ -> FROM ...;
@end example
To read the comma-delimited file back in, the correct statement would be:
@example
mysql> LOAD DATA INFILE 'data.txt' INTO TABLE table2
- FIELDS TERMINATED BY ',';
+ -> FIELDS TERMINATED BY ',';
@end example
If instead you tried to read in the file with the statement shown below, it
@@ -33203,7 +34299,7 @@ tabs between fields:
@example
mysql> LOAD DATA INFILE 'data.txt' INTO TABLE table2
- FIELDS TERMINATED BY '\t';
+ -> FIELDS TERMINATED BY '\t';
@end example
The likely result is that each input line would be interpreted as
@@ -33218,8 +34314,8 @@ the file:
@example
mysql> LOAD DATA INFILE 'data.txt' INTO TABLE tbl_name
- FIELDS TERMINATED BY ',' ENCLOSED BY '"'
- LINES TERMINATED BY '\n';
+ -> FIELDS TERMINATED BY ',' ENCLOSED BY '"'
+ -> LINES TERMINATED BY '\n';
@end example
Any of the field or line handling options may specify an empty string
@@ -33414,7 +34510,7 @@ If you wish to load only some of a table's columns, specify a field list:
@example
mysql> LOAD DATA INFILE 'persondata.txt'
- INTO TABLE persondata (col1,col2,...);
+ -> INTO TABLE persondata (col1,col2,...);
@end example
You must also specify a field list if the order of the fields in the input
@@ -33572,9 +34668,10 @@ The @code{DROP DATABASE} command removes from the given database
directory all files with the following extensions:
@multitable @columnfractions .25 .25 .25 .25
-@item .BAK @tab .DAT @tab .HSH @tab .ISD
-@item .ISM @tab .ISM @tab .MRG @tab .MYD
-@item .MYI @tab .db @tab .frm
+@item @strong{Ext} @tab @strong{Ext} @tab @strong{Ext} @tab @strong{Ext}
+@item .BAK @tab .DAT @tab .HSH @tab .ISD
+@item .ISM @tab .ISM @tab .MRG @tab .MYD
+@item .MYI @tab .db @tab .frm @tab
@end multitable
All subdirectories that consists of 2 digits (@code{RAID} directories)
@@ -33587,16 +34684,6 @@ exist.
@cindex @code{mysqladmin}
You can also drop databases with @code{mysqladmin}. @xref{Client-Side Scripts}.
-
-@menu
-* CREATE TABLE:: @code{CREATE TABLE} Syntax
-* ALTER TABLE:: @code{ALTER TABLE} Syntax
-* RENAME TABLE:: @code{RENAME TABLE} Syntax
-* DROP TABLE:: @code{DROP TABLE} Syntax
-* CREATE INDEX:: @code{CREATE INDEX} Syntax
-* DROP INDEX:: @code{DROP INDEX} Syntax
-@end menu
-
@node CREATE TABLE, ALTER TABLE, DROP DATABASE, Data Definition
@subsection @code{CREATE TABLE} Syntax
@@ -33618,7 +34705,7 @@ create_definition:
or INDEX [index_name] (index_col_name,...)
or UNIQUE [INDEX] [index_name] (index_col_name,...)
or FULLTEXT [INDEX] [index_name] (index_col_name,...)
- or [CONSTRAINT symbol] FOREIGN KEY index_name (index_col_name,...)
+ or [CONSTRAINT symbol] FOREIGN KEY [index_name] (index_col_name,...)
[reference_definition]
or CHECK (expr)
@@ -33664,21 +34751,22 @@ reference_option:
RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT
table_options:
- TYPE = @{BDB | HEAP | ISAM | InnoDB | MERGE | MYISAM @}
+ TYPE = @{BDB | HEAP | ISAM | InnoDB | MERGE | MRG_MYISAM | MYISAM @}
or AUTO_INCREMENT = #
or AVG_ROW_LENGTH = #
or CHECKSUM = @{0 | 1@}
or COMMENT = "string"
or MAX_ROWS = #
or MIN_ROWS = #
-or PACK_KEYS = @{0 | 1@}
+or PACK_KEYS = @{0 | 1 | DEFAULT@}
or PASSWORD = "string"
or DELAY_KEY_WRITE = @{0 | 1@}
or ROW_FORMAT= @{ default | dynamic | fixed | compressed @}
or RAID_TYPE= @{1 | STRIPED | RAID0 @} RAID_CHUNKS=# RAID_CHUNKSIZE=#
or UNION = (table_name,[table_name...])
-or DATA DIRECTORY="directory"
-or INDEX DIRECTORY="directory"
+or INSERT_METHOD= @{NO | FIRST | LAST @}
+or DATA DIRECTORY="absolute path to directory"
+or INDEX DIRECTORY="absolute path to directory"
select_statement:
[IGNORE | REPLACE] SELECT ... (Some legal select statement)
@@ -33698,7 +34786,7 @@ you create a table. A temporary table will automatically be deleted if a
connection dies and the name is per connection. This means that two different
connections can both use the same temporary table name without conflicting
with each other or with an existing table of the same name. (The existing table
-is hidden until the temporary table is deleted).
+is hidden until the temporary table is deleted.)
In MySQL Version 3.23 or later, you can use the keywords
@code{IF NOT EXISTS} so that an error does not occur if the table already
@@ -33746,6 +34834,9 @@ positive number. This is done to avoid precision problems when
numbers 'wrap' over from positive to negative and also to ensure that one
doesn't accidentally get an auto_increment column that contains 0.
+In MyISAM and BDB tables you can specify @code{AUTO_INCREMENT} secondary
+column in a multi-column key. @xref{example-AUTO_INCREMENT}.
+
@cindex ODBC compatibility
@cindex compatibility, with ODBC
To make MySQL compatible with some ODBC applications, you can find
@@ -33774,6 +34865,7 @@ as setting it to @code{NULL}, because @code{0} is a valid @code{TIMESTAMP}
value.
@item
+@cindex default values
If no @code{DEFAULT} value is specified for a column, MySQL
automatically assigns one.
@@ -33796,8 +34888,10 @@ column in a table, the default value is the current date and time.
@xref{Date and time types}.
@item
-For string types other than @code{ENUM}, the default value is the empty string.
-For @code{ENUM}, the default is the first enumeration value.
+For string types other than @code{ENUM}, the default value is the empty
+string. For @code{ENUM}, the default is the first enumeration value (if
+you haven't explicitely specified another default value with the
+@code{DEFAULT} directive).
@end itemize
Default values must be constants. This means, for example, that you cannot
@@ -33843,7 +34937,7 @@ table using @code{SHOW INDEX FROM tbl_name}.
@item
@cindex @code{NULL} values, and indexes
@cindex indexes, and @code{NULL} values
-Only the @code{MyISAM} table type supports indexes on columns that can have
+Only the @code{MyISAM}, @code{InnoDB}, and @code{BDB} table types support indexes on columns that can have
@code{NULL} values. In other cases you must declare such columns
@code{NOT NULL} or an error results.
@@ -33883,7 +34977,7 @@ The @code{FOREIGN KEY}, @code{CHECK}, and @code{REFERENCES} clauses don't
actually do anything. The syntax for them is provided only for compatibility,
to make it easier to port code from other SQL servers and to run applications
that create tables with references.
-@xref{Missing functions}.
+@xref{Differences from ANSI}.
@item
Each @code{NULL} column takes one bit extra, rounded up to the nearest byte.
@@ -33905,11 +34999,13 @@ implemented in MySQL Version 3.23 and above.
The different table types are:
@multitable @columnfractions .20 .80
+@item @strong{Table type} @tab @strong{Description}
@item BDB or Berkeley_db @tab Transaction-safe tables with page locking. @xref{BDB}.
@item HEAP @tab The data for this table is only stored in memory. @xref{HEAP}.
@item ISAM @tab The original table handler. @xref{ISAM}.
@item InnoDB @tab Transaction-safe tables with row locking. @xref{InnoDB}.
@item MERGE @tab A collection of MyISAM tables used as one table. @xref{MERGE}.
+@item MRG_MyISAM @tab An alias for MERGE tables
@item MyISAM @tab The new binary portable table handler that is replacing ISAM. @xref{MyISAM}.
@end multitable
@xref{Table types}.
@@ -33920,21 +35016,22 @@ specified. For example, if @code{TYPE=BDB} is specified, and that distribution
of MySQL does not support @code{BDB} tables, the table will be created
as @code{MyISAM} instead.
-The other table options are used to optimize the behavior of the
+The other table options are used to optimise the behavior of the
table. In most cases, you don't have to specify any of them.
The options work for all table types, if not otherwise indicated:
@multitable @columnfractions .20 .80
+@item @strong{Option} @tab @strong{Description}
@item @code{AUTO_INCREMENT} @tab The next auto_increment value you want to set for your table (MyISAM).
@item @code{AVG_ROW_LENGTH} @tab An approximation of the average row length for your table. You only need to set this for large tables with variable size records.
@item @code{CHECKSUM} @tab Set this to 1 if you want MySQL to maintain a checksum for all rows (makes the table a little slower to update but makes it easier to find corrupted tables) (MyISAM).
@item @code{COMMENT} @tab A 60-character comment for your table.
@item @code{MAX_ROWS} @tab Max number of rows you plan to store in the table.
@item @code{MIN_ROWS} @tab Minimum number of rows you plan to store in the table.
-@item @code{PACK_KEYS} @tab Set this to 1 if you want to have a smaller index. This usually makes updates slower and reads faster (MyISAM, ISAM).
+@item @code{PACK_KEYS} @tab Set this to 1 if you want to have a smaller index. This usually makes updates slower and reads faster (MyISAM, ISAM). Setting this to 0 will disable all packing of keys. Setting this to @code{DEFAULT} (MySQL 4.0) will tell the table handler to only pack long @code{CHAR}/@code{VARCHAR} columns.
@item @code{PASSWORD} @tab Encrypt the @code{.frm} file with a password. This option doesn't do anything in the standard MySQL version.
@item @code{DELAY_KEY_WRITE} @tab Set this to 1 if want to delay key table updates until the table is closed (MyISAM).
-@item @code{ROW_FORMAT} @tab Defines how the rows should be stored. Currently you can only use the DYNAMIC and STATIC options for MyISAM tables.
+@item @code{ROW_FORMAT} @tab Defines how the rows should be stored. Currently this option only works with MyISAM tables, which supports the @code{DYNAMIC} and @code{FIXED} row formats. @xref{MyISAM table formats}.
@end multitable
When you use a @code{MyISAM} table, MySQL uses the product of
@@ -33953,13 +35050,13 @@ many numbers that are the same. Prefix compression means that every
key needs one extra byte to indicate how many bytes of the previous key are
the same for the next key (note that the pointer to the row is stored
in high-byte-first-order directly after the key, to improve
-compression.) This means that if you have many equal keys on two rows
+compression). This means that if you have many equal keys on two rows
in a row, all following 'same' keys will usually only take 2 bytes
(including the pointer to the row). Compare this to the ordinary case
where the following keys will take storage_size_for_key +
pointer_size (usually 4). On the other hand, if all keys are
totally different, you will lose 1 byte per key, if the key isn't a
-key that can have @code{NULL} values (In this case the packed key length will
+key that can have @code{NULL} values. (In this case the packed key length will
be stored in the same byte that is used to mark if a key is @code{NULL}.)
@item
@@ -33969,8 +35066,8 @@ MySQL will create new fields for all elements in the
@example
mysql> CREATE TABLE test (a int not null auto_increment,
- primary key (a), key(b))
- TYPE=MyISAM SELECT b,c from test2;
+ -> primary key (a), key(b))
+ -> TYPE=MyISAM SELECT b,c from test2;
@end example
This will create a @code{MyISAM} table with three columns, a, b, and c.
@@ -33984,19 +35081,19 @@ mysql> select * from foo;
| n |
+---+
| 1 |
-+---+
++---+
mysql> create table bar (m int) select n from foo;
Query OK, 1 row affected (0.02 sec)
Records: 1 Duplicates: 0 Warnings: 0
-
+
mysql> select * from bar;
+------+---+
| m | n |
+------+---+
| NULL | 1 |
+------+---+
-1 row in set (0.00 sec)
+1 row in set (0.00 sec)
@end example
For each row in table @code{foo}, a row is inserted in @code{bar} with
@@ -34011,21 +35108,23 @@ specify these before the @code{SELECT} statement:
mysql> create table bar (unique (n)) select n from foo;
@end example
-If any errors occur while copying the data to the table, it will
-automatically be deleted.
+If any errors occur while copying the data to the table, it will
+automatically be deleted.
To ensure that the update log/binary log can be used to re-create the
original tables, MySQL will not allow concurrent inserts during
-@code{CREATE TABLE .... SELECT}.
+@code{CREATE TABLE ... SELECT}.
@item
The @code{RAID_TYPE} option will help you to break the 2G/4G limit for
-the MyISAM data file (not the index file) on
-operating systems that don't support big files. You can get also more speed
-from the I/O bottleneck by putting @code{RAID} directories on different
-physical disks. @code{RAID_TYPE} will work on any OS, as long as you have
-configured MySQL with @code{--with-raid}. For now the only allowed
-@code{RAID_TYPE} is @code{STRIPED} (@code{1} and @code{RAID0} are aliases
-for this).
+the MyISAM data file (not the index file) on operating systems that
+don't support big files. Note that this option is not recommended for
+file system that supports big files!
+
+You can get more speed from the I/O bottleneck by putting @code{RAID}
+directories on different physical disks. @code{RAID_TYPE} will work on
+any OS, as long as you have configured MySQL with @code{--with-raid}.
+For now the only allowed @code{RAID_TYPE} is @code{STRIPED} (@code{1}
+and @code{RAID0} are aliases for this).
If you specify @code{RAID_TYPE=STRIPED} for a @code{MyISAM} table,
@code{MyISAM} will create @code{RAID_CHUNKS} subdirectories named 00,
@@ -34041,19 +35140,27 @@ tables as one. This only works with MERGE tables. @xref{MERGE}.
For the moment you need to have @code{SELECT}, @code{UPDATE}, and
@code{DELETE} privileges on the tables you map to a @code{MERGE} table.
All mapped tables must be in the same database as the @code{MERGE} table.
+
+@item
+If you want to insert data in a @code{MERGE} table, you have to specify with
+@code{INSERT_METHOD} into with table the row should be inserted.
+@xref{MERGE}. This option was introduced in MySQL 4.0.0.
+
@item
In the created table the @code{PRIMARY} key will be placed first, followed
by all @code{UNIQUE} keys and then the normal keys. This helps the
-MySQL optimizer to prioritize which key to use and also more quickly
+MySQL optimiser to prioritise which key to use and also more quickly
detect duplicated @code{UNIQUE} keys.
@item
By using @code{DATA DIRECTORY="directory"} or @code{INDEX
DIRECTORY="directory"} you can specify where the table handler should
-put it's table and index files. This only works for @code{MyISAM} tables
-in @code{MySQL} 4.0, when you are not using the @code{--skip-symlink}
-option. @xref{Symbolic links to tables}.
+put it's table and index files. Note that the directory should be a full
+path to the directory (not relative path).
+This only works for @code{MyISAM} tables in @code{MySQL} 4.0, when you
+are not using the @code{--skip-symlink} option. @xref{Symbolic links to
+tables}.
@end itemize
@@ -34128,10 +35235,13 @@ alter_specification:
[reference_definition]
or ALTER [COLUMN] col_name @{SET DEFAULT literal | DROP DEFAULT@}
or CHANGE [COLUMN] old_col_name create_definition
- or MODIFY [COLUMN] create_definition
+ [FIRST | AFTER column_name]
+ or MODIFY [COLUMN] create_definition [FIRST | AFTER column_name]
or DROP [COLUMN] col_name
or DROP PRIMARY KEY
or DROP INDEX index_name
+ or DISABLE KEYS
+ or ENABLE KEYS
or RENAME [TO] new_tbl_name
or ORDER BY col
or table_options
@@ -34299,6 +35409,15 @@ indexes are created in a separate batch (like in @code{REPAIR}).
This should make @code{ALTER TABLE} much faster when you have many indexes.
@item
+Since @strong{MySQL 4.0} the above feature can be activated explicitly.
+@code{ALTER TABLE ... DISABLE KEYS} makes MySQL to stop updating
+non-unique indexes for @code{MyISAM} table.
+@code{ALTER TABLE ... ENABLE KEYS} then should be used to recreate missing
+indexes. As MySQL does it with special algorithm which is much
+faster then inserting keys one by one, disabling keys could give a
+considerable speedup on bulk inserts.
+
+@item
@findex mysql_info()
With the C API function @code{mysql_info()}, you can find out how many
records were copied, and (when @code{IGNORE} is used) how many records were
@@ -34311,7 +35430,7 @@ The @code{FOREIGN KEY}, @code{CHECK}, and @code{REFERENCES} clauses don't
actually do anything. The syntax for them is provided only for compatibility,
to make it easier to port code from other SQL servers and to run applications
that create tables with references.
-@xref{Missing functions}.
+@xref{Differences from ANSI}.
@end itemize
Here is an example that shows some of the uses of @code{ALTER TABLE}. We
@@ -34422,6 +35541,7 @@ If MySQL encounters any errors in a multiple table rename, it
will do a reverse rename for all renamed tables to get everything back
to the original state.
+@code{RENAME TABLE} was added in MySQL 3.23.23.
@node DROP TABLE, CREATE INDEX, RENAME TABLE, Data Definition
@subsection @code{DROP TABLE} Syntax
@@ -34442,8 +35562,8 @@ exist.
@code{RESTRICT} and @code{CASCADE} are allowed to make porting easier.
For the moment they don't do anything.
-@strong{NOTE}: @code{DROP TABLE} is not transaction-safe and will
-automatically commit any active transactions.
+@strong{Note}: @code{DROP TABLE} will
+automatically commit current active transaction.
@node CREATE INDEX, DROP INDEX, DROP TABLE, Data Definition
@@ -34456,7 +35576,8 @@ automatically commit any active transactions.
@cindex multi-part index
@example
-CREATE [UNIQUE|FULLTEXT] INDEX index_name ON tbl_name (col_name[(length)],... )
+CREATE [UNIQUE|FULLTEXT] INDEX index_name
+ ON tbl_name (col_name[(length)],... )
@end example
The @code{CREATE INDEX} statement doesn't do anything in MySQL prior
@@ -34475,7 +35596,7 @@ columns.
For @code{CHAR} and @code{VARCHAR} columns, indexes can be created that
use only part of a column, using @code{col_name(length)} syntax. (On
-@code{BLOB} and @code{TEXT} columns the length is required). The
+@code{BLOB} and @code{TEXT} columns the length is required.) The
statement shown below creates an index using the first 10 characters of
the @code{name} column:
@@ -34557,7 +35678,7 @@ below accesses the @code{author} table from the @code{db1} database and the
@example
mysql> USE db1;
mysql> SELECT author_name,editor_name FROM author,db2.editor
- WHERE author.editor_id = db2.editor.editor_id;
+ -> WHERE author.editor_id = db2.editor.editor_id;
@end example
@cindex Sybase compatibility
@@ -34615,8 +35736,8 @@ By default, MySQL runs in @code{autocommit} mode. This means that
as soon as you execute an update, MySQL will store the update on
disk.
-If you are using transactions safe tables (like @code{BDB},
-@code{InnoDB}, you can put MySQL into
+If you are using transactions safe tables (like @code{InnoDB},
+@code{BDB}, you can put MySQL into
non-@code{autocommit} mode with the following command:
@example
@@ -34655,9 +35776,10 @@ The following commands automatically end a transaction (as if you had done
a @code{COMMIT} before executing the command):
@multitable @columnfractions .33 .33 .33
-@item @code{ALTER TABLE} @tab @code{BEGIN} @tab @code{CREATE INDEX}
-@item @code{DROP DATABASE} @tab @code{DROP TABLE} @tab @code{RENAME TABLE}
-@item @code{TRUNCATE}
+@item @strong{Command} @tab @strong{Command} @tab @strong{Command}
+@item @code{ALTER TABLE} @tab @code{BEGIN} @tab @code{CREATE INDEX}
+@item @code{DROP DATABASE} @tab @code{DROP TABLE} @tab @code{RENAME TABLE}
+@item @code{TRUNCATE} @tab @tab
@end multitable
You can change the isolation level for transactions with
@@ -34740,7 +35862,7 @@ tables to transactions safe tables.
You can safely kill a thread that is waiting for a table lock with
@code{KILL}. @xref{KILL}.
-Note that you should @strong{NOT} lock any tables that you are using with
+Note that you should @strong{not} lock any tables that you are using with
@code{INSERT DELAYED}. This is because that in this case the @code{INSERT}
is done by a separate thread.
@@ -34762,16 +35884,16 @@ MySQL will not flush the key cache for the locked tables until
each SQL statement). This speeds up inserting/updateing/deletes on
@code{MyISAM} tables.
@item
-If you are using a table handler in MySQL that doesn't support
-transactions, you must use @code{LOCK TABLES} if you want to ensure that
-no other thread comes between a @code{SELECT} and an @code{UPDATE}. The
+If you are using a table handler in MySQL that doesn't support
+transactions, you must use @code{LOCK TABLES} if you want to ensure that
+no other thread comes between a @code{SELECT} and an @code{UPDATE}. The
example shown below requires @code{LOCK TABLES} in order to execute safely:
@example
mysql> LOCK TABLES trans READ, customer WRITE;
mysql> select sum(value) from trans where customer_id= some_id;
mysql> update customer set total_value=sum_from_previous_statement
- where customer_id=some_id;
+ -> where customer_id=some_id;
mysql> UNLOCK TABLES;
@end example
@@ -34827,8 +35949,7 @@ future transactions.
You can set the default isolation level for @code{mysqld} with
@code{--transaction-isolation=...}. @xref{Command-line options}.
-
-@node Fulltext Search, , Transactional Commands, Reference
+@node Fulltext Search, Query Cache, Transactional Commands, Reference
@section MySQL Full-text Search
@cindex searching, full-text
@@ -34836,19 +35957,19 @@ You can set the default isolation level for @code{mysqld} with
@cindex FULLTEXT
Since Version 3.23.23, MySQL has support for full-text indexing
-and searching. Full-text indexes in MySQL are an index of type
-@code{FULLTEXT}. @code{FULLTEXT} indexes can be created from @code{VARCHAR}
-and @code{TEXT} columns at @code{CREATE TABLE} time or added later with
-@code{ALTER TABLE} or @code{CREATE INDEX}. For large datasets, adding
-@code{FULLTEXT} index with @code{ALTER TABLE} (or @code{CREATE INDEX}) would
-be much faster than inserting rows into the empty table with a @code{FULLTEXT}
-index.
+and searching. Full-text indexes in MySQL are an index of type
+@code{FULLTEXT}. @code{FULLTEXT} indexes can be created from @code{VARCHAR}
+and @code{TEXT} columns at @code{CREATE TABLE} time or added later with
+@code{ALTER TABLE} or @code{CREATE INDEX}. For large datasets, adding
+@code{FULLTEXT} index with @code{ALTER TABLE} (or @code{CREATE INDEX})
+would be much faster than inserting rows into the empty table that has
+a @code{FULLTEXT} index.
Full-text search is performed with the @code{MATCH} function.
@example
mysql> CREATE TABLE articles (
- -> id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
+ -> id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
-> title VARCHAR(200),
-> body TEXT,
-> FULLTEXT (title,body)
@@ -34856,42 +35977,44 @@ mysql> CREATE TABLE articles (
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO articles VALUES
- -> (0,'MySQL Tutorial', 'DBMS stands for DataBase Management ...'),
+ -> (0,'MySQL Tutorial', 'DBMS stands for DataBase ...'),
-> (0,'How To Use MySQL Efficiently', 'After you went through a ...'),
- -> (0,'Optimizing MySQL','In this tutorial we will show how to ...'),
- -> (0,'1001 MySQL Trick','1. Never run mysqld as root. 2. Normalize ...'),
- -> (0,'MySQL vs. YourSQL', 'In the following database comparison we ...'),
- -> (0,'MySQL Security', 'When configured properly, MySQL could be ...');
-Query OK, 5 rows affected (0.00 sec)
-Records: 5 Duplicates: 0 Warnings: 0
-
-mysql> SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('database');
-+----+-------------------+---------------------------------------------+
-| id | title | body |
-+----+-------------------+---------------------------------------------+
-| 5 | MySQL vs. YourSQL | In the following database comparison we ... |
-| 1 | MySQL Tutorial | DBMS stands for DataBase Management ... |
-+----+-------------------+---------------------------------------------+
+ -> (0,'Optimising MySQL','In this tutorial we will show ...'),
+ -> (0,'1001 MySQL Trick','1. Never run mysqld as root. 2. ...'),
+ -> (0,'MySQL vs. YourSQL', 'In the following database comparison ...'),
+ -> (0,'MySQL Security', 'When configured properly, MySQL ...');
+Query OK, 6 rows affected (0.00 sec)
+Records: 6 Duplicates: 0 Warnings: 0
+
+mysql> SELECT * FROM articles
+ -> WHERE MATCH (title,body) AGAINST ('database');
++----+-------------------+------------------------------------------+
+| id | title | body |
++----+-------------------+------------------------------------------+
+| 5 | MySQL vs. YourSQL | In the following database comparison ... |
+| 1 | MySQL Tutorial | DBMS stands for DataBase ... |
++----+-------------------+------------------------------------------+
2 rows in set (0.00 sec)
@end example
-The function @code{MATCH} matches a natural language query @code{AGAINST}
-a text collection (which is simply the set of columns covered by a
-@code{FULLTEXT} index). For every row in a table it returns relevance -
-a similarity measure between the text in that row (in the columns that are
-part of the collection) and the query. When it is used in a @code{WHERE}
-clause (see example above) the rows returned are automatically sorted with
-relevance decreasing. Relevance is a non-negative floating-point number.
-Zero relevance means no similarity. Relevance is computed based on the
-number of words in the row, the number of unique words in that row, the
-total number of words in the collection, and the number of documents (rows)
+The function @code{MATCH} matches a natural language (or boolean,
+see below) query in case-insensitive fashion @code{AGAINST}
+a text collection (which is simply the set of columns covered by a
+@code{FULLTEXT} index). For every row in a table it returns relevance -
+a similarity measure between the text in that row (in the columns that are
+part of the collection) and the query. When it is used in a @code{WHERE}
+clause (see example above) the rows returned are automatically sorted with
+relevance decreasing. Relevance is a non-negative floating-point number.
+Zero relevance means no similarity. Relevance is computed based on the
+number of words in the row, the number of unique words in that row, the
+total number of words in the collection, and the number of documents (rows)
that contain a particular word.
The above is a basic example of using @code{MATCH} function. Rows are
returned with relevance decreasing.
@example
-mysql> SELECT id,MATCH (title,body) AGAINST ('Tutorial') FROM articles;
+mysql> SELECT id,MATCH title,body AGAINST ('Tutorial') FROM articles;
+----+-----------------------------------------+
| id | MATCH (title,body) AGAINST ('Tutorial') |
+----+-----------------------------------------+
@@ -34902,30 +36025,30 @@ mysql> SELECT id,MATCH (title,body) AGAINST ('Tutorial') FROM articles;
| 5 | 0 |
| 6 | 0 |
+----+-----------------------------------------+
-5 rows in set (0.00 sec)
+6 rows in set (0.00 sec)
@end example
This example shows how to retrieve the relevances. As neither @code{WHERE}
nor @code{ORDER BY} clauses are present, returned rows are not ordered.
@example
-mysql> SELECT id, body, MATCH (title,body) AGAINST (
+mysql> SELECT id, body, MATCH title,body AGAINST (
-> 'Security implications of running MySQL as root') AS score
-> FROM articles WHERE MATCH (title,body) AGAINST
-> ('Security implications of running MySQL as root');
-+----+-----------------------------------------------+-----------------+
-| id | body | score |
-+----+-----------------------------------------------+-----------------+
-| 4 | 1. Never run mysqld as root. 2. Normalize ... | 1.5055546709332 |
-| 6 | When configured properly, MySQL could be ... | 1.31140957288 |
-+----+-----------------------------------------------+-----------------+
++----+-------------------------------------+-----------------+
+| id | body | score |
++----+-------------------------------------+-----------------+
+| 4 | 1. Never run mysqld as root. 2. ... | 1.5055546709332 |
+| 6 | When configured properly, MySQL ... | 1.31140957288 |
++----+-------------------------------------+-----------------+
2 rows in set (0.00 sec)
@end example
This is more complex example - the query returns the relevance and still
sorts the rows with relevance decreasing. To achieve it one should specify
@code{MATCH} twice. Note, that this will cause no additional overhead, as
-MySQL optimizer will notice that these two @code{MATCH} calls are
+MySQL optimiser will notice that these two @code{MATCH} calls are
identical and will call full-text search code only once.
MySQL uses a very simple parser to split text into words. A
@@ -34944,7 +36067,7 @@ relevance of the row.
Such a technique works best with large collections (in fact, it was
carefully tuned this way). For very small tables, word distribution
does not reflect adequately their semantical value, and this model
-may sometimes produce bizarre results.
+may sometimes produce bisarre results.
@example
mysql> SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('MySQL');
@@ -34953,43 +36076,116 @@ Empty set (0.00 sec)
Search for the word @code{MySQL} produces no results in the above example.
Word @code{MySQL} is present in more than half of rows, and as such, is
-effectively treated as a stopword (that is, with semantical value zero).
+effectively treated as a stopword (that is, with semantical value zero).
It is, really, the desired behavior - a natural language query should not
return every second row in 1GB table.
A word that matches half of rows in a table is less likely to locate relevant
documents. In fact, it will most likely find plenty of irrelevant documents.
We all know this happens far too often when we are trying to find something on
-the Internet with a search engine. It is with this reasoning that such rows
+the Internet with a search engine. It is with this reasoning that such rows
have been assigned a low semantical value in @strong{this particular dataset}.
+Since version 4.0.1 MySQL can also perform boolean fulltext searches using
+@code{IN BOOLEAN MODE} modifier.
+
+@example
+mysql> SELECT * FROM articles WHERE MATCH (title,body)
+ -> AGAINST ('+MySQL -YourSQL' IN BOOLEAN MODE);
++----+------------------------------+-------------------------------------+
+| id | title | body |
++----+------------------------------+-------------------------------------+
+| 1 | MySQL Tutorial | DBMS stands for DataBase ... |
+| 2 | How To Use MySQL Efficiently | After you went through a ... |
+| 3 | Optimising MySQL | In this tutorial we will show ... |
+| 4 | 1001 MySQL Trick | 1. Never run mysqld as root. 2. ... |
+| 6 | MySQL Security | When configured properly, MySQL ... |
++----+------------------------------+-------------------------------------+
+@end example
+
+This query retrieved all the rows that contain the word @code{MySQL}
+(note: 50% threshold is gone), but does @strong{not} contain the word
+@code{YourSQL}. Note, that it does not auto-magically sort rows in
+decreasing relevance order (the last row has the highest relevance,
+as it contains @code{MySQL} twice). Boolean fulltext search can also
+work even without @code{FULLTEXT} index, but it would be @strong{slow}.
+
+Boolean fulltext search supports the following operators:
+
+@table @code
+@item +
+A plus sign prepended to a word indicates that this word @strong{must be}
+present in every row returned.
+@item -
+A minus sign prepended to a word indicates that this word @strong{must not}
+be present in the rows returned.
+@item
+By default - without plus or minus - the word is optional, but the rows that
+contain it will be rated higher. This mimicks the behaviour of
+@code{MATCH ... AGAINST()} without @code{IN BOOLEAN MODE} modifier.
+@item < >
+These two operators are used to increase and decrease word's contribution
+to the relevance value, assigned to a row. See an example below.
+@item ( )
+Parentheses are used - as usual - to group words into subexpressions.
+@item ~
+This is negation operator. It makes word's contribution to the row
+relevance negative. It's useful for marking noise words. A row that has
+such a word will be rated lower than others, but will not be excluded
+altogether, as with @code{-} operator.
+@item *
+This is truncation operator. Unlike others it should be @strong{appended}
+to the word, not prepended.
+@end table
+
+And here are some examples:
+
+@table @code
+@item apple banana
+find rows that contain at least one of these words.
+@item +apple +juice
+... both words
+@item +apple macintosh
+... word ``apple'', but rank it higher if it also contain ``macintosh''
+@item +apple -macintosh
+... word ``apple'' but not ``macintosh''
+@item +apple +(>pie <strudel)
+... ``apple'' and ``pie'', or ``apple'' and ``strudel'' (in any
+order), but rank ``apple pie'' higher than ``apple strudel''.
+@item apple*
+... ``apple'', ``apples'', ``applesauce'', and ``applet''
+@end table
+
@menu
-* Fulltext restrictions:: Fulltext restrictions
+* Fulltext Restrictions:: Fulltext Restrictions
* Fulltext Fine-tuning:: Fine-tuning MySQL Full-text Search
-* Fulltext Features to Appear in MySQL 4.0:: New Features of Full-text Search to Appear in MySQL 4.0
* Fulltext TODO:: Full-text Search TODO
@end menu
-
-@node Fulltext restrictions, Fulltext Fine-tuning, Fulltext Search, Fulltext Search
-@subsection Fulltext restrictions
+@node Fulltext Restrictions, Fulltext Fine-tuning, Fulltext Search, Fulltext Search
+@subsection Fulltext Restrictions
@itemize @bullet
@item
All parameters to the @code{MATCH} function must be columns from the
-same table that is part of the same fulltext index.
+same table that is part of the same fulltext index, unless this
+@code{MATCH} is @code{IN BOOLEAN MODE}.
+@item
+Column list between @code{MATCH} and @code{AGAINST} must match exactly
+a column list in the @code{FULLTEXT} index definition, unless this
+@code{MATCH} is @code{IN BOOLEAN MODE}.
@item
The argument to @code{AGAINST} must be a constant string.
@end itemize
-@node Fulltext Fine-tuning, Fulltext Features to Appear in MySQL 4.0, Fulltext restrictions, Fulltext Search
+@node Fulltext Fine-tuning, Fulltext TODO, Fulltext Restrictions, Fulltext Search
@subsection Fine-tuning MySQL Full-text Search
-Unfortunately, full-text search has no user-tunable parameters yet,
-although adding some is very high on the TODO. However, if you have a
-MySQL source distribution (@xref{Installing source}.), you can
-somewhat alter the full-text search behavior.
+Unfortunately, full-text search has few user-tunable parameters yet,
+although adding some is very high on the TODO. If you have a
+MySQL source distribution (@pxref{Installing source}), you can
+more control on the full-text search behavior.
Note that full-text search was carefully tuned for the best searching
effectiveness. Modifying the default behavior will, in most cases,
@@ -34999,22 +36195,19 @@ unless you know what you are doing!
@itemize @bullet
@item
-Minimal length of word to be indexed is defined in
-@code{myisam/ftdefs.h} file by the line
-@example
-#define MIN_WORD_LEN 4
-@end example
-Change it to the value you prefer, recompile MySQL, and rebuild
+Minimal length of word to be indexed is defined by MySQL
+variable @code{ft_min_word_length}. @xref{SHOW VARIABLES}.
+Change it to the value you prefer, and rebuild
your @code{FULLTEXT} indexes.
@item
-The stopword list is defined in @code{myisam/ft_static.c}
+The stopword list is defined in @file{myisam/ft_static.c}
Modify it to your taste, recompile MySQL and rebuild
your @code{FULLTEXT} indexes.
@item
-The 50% threshold is caused by the particular weighting scheme chosen. To
-disable it, change the following line in @code{myisam/ftdefs.h}:
+The 50% threshold is caused by the particular weighting scheme chosen. To
+disable it, change the following line in @file{myisam/ftdefs.h}:
@example
#define GWS_IN_USE GWS_PROB
@end example
@@ -35024,55 +36217,26 @@ to
@end example
and recompile MySQL.
There is no need to rebuild the indexes in this case.
+@strong{Note:} by doing this you @strong{severely} decrease MySQL ability
+to provide adequate relevance values by @code{MATCH} function.
+It means, that if you really need to search for such a common words,
+then you should rather search @code{IN BOOLEAN MODE}, which does not
+has 50% threshold.
-@end itemize
-
-
-@node Fulltext Features to Appear in MySQL 4.0, Fulltext TODO, Fulltext Fine-tuning, Fulltext Search
-@subsection New Features of Full-text Search to Appear in MySQL 4.0
-
-This section includes a list of the fulltext features that are already
-implemented in the 4.0 tree. It explains
-@strong{More functions for full-text search} entry of @ref{TODO MySQL 4.0}.
-
-@itemize @bullet
-@item @code{REPAIR TABLE} with @code{FULLTEXT} indexes,
-@code{ALTER TABLE} with @code{FULLTEXT} indexes, and
-@code{OPTIMIZE TABLE} with @code{FULLTEXT} indexes are now
-up to 100 times faster.
-
-@item @code{MATCH ... AGAINST} is going to supports the following
-@strong{boolean operators}:
-
-@itemize @bullet
-@item @code{+}word means the that word @strong{must} be present in every
-row returned.
-@item @code{-}word means the that word @strong{must not} be present in every
-row returned.
-@item @code{<} and @code{>} can be used to decrease and increase word
-weight in the query.
-@item @code{~} can be used to assign a @strong{negative} weight to a noise
-word.
-@item @code{*} is a truncation operator.
-@end itemize
-
-Boolean search utilizes a more simplistic way of calculating the relevance,
-that does not have a 50% threshold.
-
-@item Searches are now up to 2 times faster due to optimized search algorithm.
-
-@item Utility program @code{ft_dump} added for low-level @code{FULLTEXT}
-index operations (querying/dumping/statistics).
+@item
+Sometimes search engine maintaner would like to change operators used
+for boolean fulltext search. They are defined by a
+@code{ft_boolean_syntax} variable. @xref{SHOW VARIABLES}.
+Still, this variable is read-only, its value is set in
+@file{myisam/ft_static.c}.
@end itemize
-
-@node Fulltext TODO, , Fulltext Features to Appear in MySQL 4.0, Fulltext Search
+@node Fulltext TODO, , Fulltext Fine-tuning, Fulltext Search
@subsection Full-text Search TODO
@itemize @bullet
@item Make all operations with @code{FULLTEXT} index @strong{faster}.
-@item Support for braces @code{()} in boolean full-text search.
@item Phrase search, proximity operators
@item Boolean search can work without @code{FULLTEXT} index
(yes, @strong{very} slow).
@@ -35088,6 +36252,229 @@ parameters to @code{FULLTEXT} in @code{CREATE/ALTER TABLE}).
@end itemize
+@node Query Cache, , Fulltext Search, Reference
+@section MySQL Query Cache
+
+@cindex Query Cache
+@cindex @code{SELECT}, Query Cache
+
+From version 4.0.1, @code{MySQL server} features a @code{Query Cache}.
+When in use, the query cache stores the text of a @code{SELECT} query
+together with the corresponding result that is sent to a client.
+If another identical query is received, the server can then retrieve
+the results from the query cache rather than parsing and executing the
+same query again.
+
+The query cache is extremely useful in an environment where (some)
+tables don't change very often and you have a lot of identical queries.
+This is a typical situation for many web servers that use a lot of
+dynamic content.
+
+Following are some performance data for the query cache
+(We got these by running the MySQL benchmark suite on a Linux Alpha
+2x500 MHz with 2GB RAM and a 64MB query cache):
+
+@itemize @bullet
+@item
+If you want to disable the query cache code set @code{query_cache_size=0}.
+By disabling the query cache code there is no noticeable overhead.
+@item
+If all of the queries you're preforming are simple (such as selecting a
+row from a table with one row); but still differ so that the queries can
+not be cached, the overhead for having the query cache active is 13%.
+This could be regarded as the worst case scenario. However, in real life,
+queries are much more complicated than our simple example so the overhead
+is normally significantly lower.
+@item
+Searches after one row in a one row table is 238% faster.
+This can be regarded as close to the minimum speedup to be expected for
+a query that is cached.
+@end itemize
+
+@menu
+* Query Cache How:: How The Query Cache Operates
+* Query Cache Configuration:: Query Cache Configuration
+* Query Cache in SELECT:: Query Cache Options in @code{SELECT}
+* Query Cache Status and Maintenance:: Query Cache Status and Maintenance
+@end menu
+
+
+@node Query Cache How, Query Cache Configuration, Query Cache, Query Cache
+@subsection How The Query Cache Operates
+
+Queries are compared before parsing, thus
+
+@example
+SELECT * FROM TABLE
+@end example
+
+and
+
+@example
+Select * from table
+@end example
+
+are regarded as different queries for query cache, so queries need
+to be exactly the same (byte for byte) to be seen as identical.
+In addition, a query may be seen as different if for instance one
+client is using a new communication protocol format or another
+character set than another client.
+
+Queries that uses different databases, uses different protocol versions
+or the uses different default character sets are considered different
+queries and cached separately.
+
+The cache does work for @code{SELECT CALC_ROWS ...} and
+@code{SELECT FOUND_ROWS() ...} type queries because the number of
+found rows is also stored in the cache.
+
+If a table changes (@code{INSERT}, @code{UPDATE}, @code{DELETE},
+@code{TRUNCATE}, @code{ALTER} or @code{DROP TABLE|DATABASE}),
+then all cached queries that used this table (possibly through a
+@code{MRG_MyISAM} table!) become invalid and are removed from the cache.
+
+Currently all @code{InnoDB} tables are invalidated on @code{COMMIT},
+in the future this will be changed so only tables changed in the
+transaction cause the corresponding cache entries to be invalidated.
+
+A query cannot be cached if it contains one of the functions:
+@multitable @columnfractions .25 .25 .25 .25
+@item @strong{Function} @tab @strong{Function}
+ @tab @strong{Function} @tab @strong{Function}
+@item @code{User Defined Functions} @tab @code{CONNECTION_ID}
+ @tab @code{FOUND_ROWS} @tab @code{GET_LOCK}
+@item @code{RELEASE_LOCK} @tab @code{LOAD_FILE}
+ @tab @code{MASTER_POS_WAIT} @tab @code{NOW}
+@item @code{SYSDATE} @tab @code{CURRENT_TIMESTAMP}
+ @tab @code{CURDATE} @tab @code{CURRENT_DATE}
+@item @code{CURTIME} @tab @code{CURRENT_TIME}
+ @tab @code{DATABASE} @tab @code{ENCRYPT} (with one parameter)
+@item @code{LAST_INSERT_ID} @tab @code{RAND}
+ @tab @code{UNIX_TIMESTAMP} (without parameters) @tab @code{USER}
+@item @code{BENCHMARK}
+@end multitable
+
+Nor can a query be cached if it contains user variables,
+if it is of the form @code{SELECT ... IN SHARE MODE} or
+of the form @code{SELECT * FROM AUTOINCREMENT_FIELD IS NULL}
+(to retrieve last insert id - ODBC work around).
+
+However, @code{FOUND ROWS()} will return the correct value,
+even if the preceding query was fetched from the cache.
+
+Queries that don't use any tables or if the user has a column privilege for
+any of the involved tables are not cached.
+
+Before a query is fetched from the query cache, MySQL will check that
+the user has SELECT privilege to all the involved databases and
+tables. If this is not the case, the cached result will not be used.
+
+@node Query Cache Configuration, Query Cache in SELECT, Query Cache How, Query Cache
+@subsection Query Cache Configuration
+
+The query cache adds a few @code{MySQL} system variables for
+@code{mysqld} which may be set in a configuration file, on the
+command line when starting @code{mysqld}.
+
+@itemize
+@item @code{query_cache_limit}
+Don't cache results that are bigger than this. (Default 1M).
+
+@item @code{query_cache_size}
+The memory allocated to store results from old queries.
+If this is 0, the query cache is disabled (default).
+
+@item @code{query_cache_startup_type}
+This may be set (only numeric) to
+@multitable @columnfractions .3 .7
+@item @strong{Option} @tab @strong{Description}
+@item 0 @tab (OFF, don't cache or retrieve results)
+@item 1 @tab (ON, cache all results except @code{SELECT SQL_NO_CACHE ...} queries)
+@item 2 @tab (DEMAND, cache only @code{SELECT SQL_CACHE ...} queries)
+@end multitable
+@end itemize
+
+
+Inside a thread (connection), the behaviour of the query cache can be
+changed from the default. The syntax is as follows:
+
+@code{SQL_QUERY_CACHE_TYPE = OFF | ON | DEMAND}
+@code{SQL_QUERY_CACHE_TYPE = 0 | 1 | 2}
+
+@multitable @columnfractions .3 .7
+@item @strong{Option} @tab @strong{Description}
+@item 0 or OFF @tab Don't cache or retrieve results.
+@item 1 or ON @tab Cache all results except @code{SELECT SQL_NO_CACHE ...} queries.
+@item 2 or DEMAND @tab Cache only @code{SELECT SQL_CACHE ...} queries.
+@end multitable
+
+By default @code{SQL_QUERY_CACHE_TYPE} depends on the value of
+@code{query_cache_startup_type} when the thread was created.
+
+
+@node Query Cache in SELECT, Query Cache Status and Maintenance, Query Cache Configuration, Query Cache
+@subsection Query Cache Options in @code{SELECT}
+
+There are two possible query cache related parameters that may be
+specified in a @code{SELECT} query:
+
+@findex SQL_CACHE
+@findex SQL_NO_CACHE
+
+@multitable @columnfractions .3 .7
+@item @strong{Option} @tab @strong{Description}
+@item @code{SQL_CACHE}
+ @tab If @code{SQL_QUERY_CACHE_TYPE} is @code{DEMAND}, allow the query to be cached.
+ If @code{SQL_QUERY_CACHE_TYPE} is @code{ON}, this is the default.
+ If @code{SQL_QUERY_CACHE_TYPE} is @code{OFF}, do nothing.
+@item @code{SQL_NO_CACHE}
+ @tab Make this query non-cachable, don't allow this query to be stored in the cache.
+@end multitable
+
+
+@node Query Cache Status and Maintenance, , Query Cache in SELECT, Query Cache
+@subsection Query Cache Status and Maintenance
+
+With the @code{FLUSH QUERY CACHE} command you can defragment the query
+cache to better utilise its memory. This command will not remove any
+queries from the cache.
+@code{FLUSH TABLES} also flushes the query cache.
+
+The @code{RESET QUERY CACHE} command removes all query results from the
+query cache.
+
+You can monitor query cache performance in @code{SHOW STATUS}:
+
+@multitable @columnfractions .3 .7
+@item @strong{Variable} @tab @strong{Description}
+@item @code{Qcache_queries_in_cache}
+ @tab Number of queries registered in the cache.
+@item @code{Qcache_inserts}
+ @tab Number of queries added to the cache.
+@item @code{Qcache_hits}
+ @tab Number of cache hits.
+@item @code{Qcache_not_cached}
+ @tab Number of non-cached queries
+ (not cachable, or due to @code{SQL_QUERY_CACHE_TYPE}).
+@item @code{Qcache_free_memory}
+ @tab Amount of free memory for query cache.
+@item @code{Qcache_total_blocks}
+ @tab Total number of blocks in query cache.
+@item @code{Qcache_free_blocks}
+ @tab Number of free memory blocks in query cache.
+@end multitable
+
+Total number of queries =
+@code{Qcache_inserts} + @code{Qcache_hits} + @code{Qcache_not_cached}.
+
+The query cache uses variable length blocks, so @code{Qcache_total_blocks}
+and @code{Qcache_free_blocks} may indicate query cache memory fragmentation.
+After @code{FLUSH QUERY CACHE} only a single (big) free block remains.
+
+Note: Every query needs a minimum of two blocks (one for the query text
+and one or more for the query results). Also, every table that is used
+by a query needs one block, but if two or more queries use same table
+only one block needs to be allocated.
@node Table types, Clients, Reference, Top
@@ -35106,9 +36493,9 @@ parameters to @code{FULLTEXT} in @code{CREATE/ALTER TABLE}).
As of MySQL Version 3.23.6, you can choose between three basic
table formats (@code{ISAM}, @code{HEAP} and @code{MyISAM}. Newer
-MySQL may support additional table type (@code{BDB},
-or @code{InnoDB}), depending on how you compile it.
-
+MySQL may support additional table type (@code{InnoDB},
+or @code{BDB}), depending on how you compile it.
+
When you create a new table, you can tell MySQL which table
type it should use for the table. MySQL will always create a
@code{.frm} file to hold the table and column definitions. Depending on
@@ -35122,7 +36509,7 @@ trying to use a table type that is not compiled-in or activated,
MySQL will instead create a table of type @code{MyISAM}. This
is a very useful feature when you want to copy tables between different
SQL servers that supports different table types (like copying tables to
-a slave that is optimized for speed by not having transactional tables).
+a slave that is optimised for speed by not having transactional tables).
This automatic table changing can however also be very confusing for new
MySQL users. We plan to fix this by introducing warnings in
MySQL 4.0 and giving a warning when a table type is automatically
@@ -35132,7 +36519,7 @@ You can convert tables between different types with the @code{ALTER
TABLE} statement. @xref{ALTER TABLE, , @code{ALTER TABLE}}.
Note that MySQL supports two different kinds of
-tables. Transaction-safe tables (@code{BDB}, @code{InnoDB}
+tables: transaction-safe tables (@code{InnoDB} and @code{BDB})
and not transaction-safe tables (@code{HEAP}, @code{ISAM},
@code{MERGE}, and @code{MyISAM}).
@@ -35173,8 +36560,8 @@ of both worlds.
* MERGE:: MERGE tables
* ISAM:: ISAM tables
* HEAP:: HEAP tables
-* BDB:: BDB or Berkeley_db tables
* InnoDB:: InnoDB tables
+* BDB:: BDB or Berkeley_db tables
@end menu
@@ -35187,7 +36574,7 @@ based on the @code{ISAM} code and has a lot of useful extensions.
The index is stored in a file with the @code{.MYI} (MYIndex) extension,
and the data is stored in a file with the @code{.MYD} (MYData) extension.
You can check/repair @code{MyISAM} tables with the @code{myisamchk}
-utility. @xref{Crash recovery}. You can compress @code{MyISAM} tables with
+utility. @xref{Crash recovery}. You can compress @code{MyISAM} tables with
@code{myisampack} to take up much less space. @xref{myisampack}.
The following is new in @code{MyISAM}:
@@ -35236,7 +36623,7 @@ behavior is still present.
@item
When inserted in sorted order (as when you are using an @code{AUTO_INCREMENT}
column) the key tree will be split so that the high node only contains one
-key. This will improve the space utilization in the key tree.
+key. This will improve the space utilisation in the key tree.
@item
@code{BLOB} and @code{TEXT} columns can be indexed.
@item
@@ -35247,7 +36634,7 @@ Maximum key length is 500 bytes by default (can be changed by
recompiling). In cases of keys longer than 250 bytes, a bigger key
block size than the default of 1024 bytes is used for this key.
@item
-Maximum number of keys/table is 32 as default. This can be enlarged to 64
+Maximum number of keys/table is 32 as default. This can be enlarged to 64
without having to recompile @code{myisamchk}.
@item
@code{myisamchk} will mark tables as checked if one runs it with
@@ -35296,13 +36683,13 @@ The following options to @code{mysqld} can be used to change the behavior of
@code{MyISAM} tables. @xref{SHOW VARIABLES}.
@multitable @columnfractions .40 .60
-@item @strong{Option} @tab @strong{Meaning}
+@item @strong{Option} @tab @strong{Description}
@item @code{--myisam-recover=#} @tab Automatic recover of crashed tables.
@item @code{-O myisam_sort_buffer_size=#} @tab Buffer used when recovering tables.
@item @code{--delay-key-write-for-all-tables} @tab Don't flush key buffers between writes for any MyISAM table
-@item @code{-O myisam_max_extra_sort_file_size=#} @tab Used to help MySQL to decide when to use the slow but safe key cache index create method. @strong{NOTE} that this parameter is given in megabytes!
-@item @code{-O myisam_max_sort_file_size=#} @tab Don't use the fast sort index method to created index if the temporary file would get bigger than this.
-@strong{NOTE} that this paramter is given in megabytes!
+@item @code{-O myisam_max_extra_sort_file_size=#} @tab Used to help MySQL to decide when to use the slow but safe key cache index create method. @strong{Note} that this parameter is given in megabytes!
+@item @code{-O myisam_max_sort_file_size=#} @tab Don't use the fast sort index method to created index if the temporary file would get bigger than this. @strong{Note} that this paramter is given in megabytes!
+@item @code{-O myisam_bulk_insert_tree_size=#} @tab Size of tree cache used in bulk insert optimisation. @strong{Note} that this is a limit @strong{per thread}!
@end multitable
The automatic recovery is activated if you start @code{mysqld} with
@@ -35388,6 +36775,13 @@ high-byte first.
automatically depending on the type of columns you are using. The third,
compressed tables, can only be created with the @code{myisampack} tool.
+When you @code{CREATE} or @code{ALTER} a table you can for tables that
+doesn't have @code{BLOB}'s force the table format to @code{DYNAMIC} or
+@code{FIXED} with the @code{ROW_FORMAT=#} table option. In the future
+you will be able to compress/decompress tables by specifying
+@code{ROW_FORMAT=compressed | default} to @code{ALTER TABLE}.
+@xref{CREATE TABLE}.
+
@menu
* Static format:: Static (Fixed-length) table characteristics
* Dynamic format:: Dynamic table characteristics
@@ -35427,7 +36821,7 @@ Easy to cache.
Easy to reconstruct after a crash, because records are located in fixed
positions.
@item
-Doesn't have to be reorganized (with @code{myisamchk}) unless a huge number of
+Doesn't have to be reorganised (with @code{myisamchk}) unless a huge number of
records are deleted and you want to return free disk space to the operating
system.
@item
@@ -35514,7 +36908,7 @@ This is a read-only type that is generated with the optional
All MySQL distributions, even those that existed before MySQL
went GPL, can read tables that were compressed with @code{myisampack}.
@item
-Compressed tables take very little disk space. This minimizes disk usage, which
+Compressed tables take very little disk space. This minimises disk usage, which
is very nice when using slow disks (like CD-ROMs).
@item
Each record is compressed separately (very little access overhead). The
@@ -35542,8 +36936,7 @@ converted to @code{ENUM}.
A column may use a combination of the above compressions.
@end itemize
@item
-Can handle fixed- or dynamic-length records, but not @code{BLOB} or @code{TEXT}
-columns.
+Can handle fixed- or dynamic-length records.
@item
Can be uncompressed with @code{myisamchk}.
@end itemize
@@ -35601,7 +36994,7 @@ You can also repair a table, when @code{mysqld} is not running with
the @code{myisamchk} command. @code{myisamchk syntax}.
If your tables get corrupted a lot you should try to find the reason for
-this! @xref{Crashing}.
+this! @xref{Crashing}.
In this case the most important thing to know is if the table got
corrupted if the @code{mysqld} died (one can easily verify this by
@@ -35624,7 +37017,7 @@ If you get the following warning from @code{CHECK TABLE} or @code{myisamchk}:
this means that this counter has come out of sync. This doesn't mean
that the table is corrupted, but means that you should at least do a
-check on the table to verify that it's ok.
+check on the table to verify that it's okay.
The counter works as follows:
@@ -35639,7 +37032,7 @@ When the last instance of a table is closed (because of a @code{FLUSH} or
because there isn't room in the table cache) the counter is
decremented if the table has been updated at any point.
@item
-When you repair the table or check the table and it was ok,
+When you repair the table or check the table and it was okay,
the counter is reset to 0.
@item
To avoid problems with interaction with other processes that may do a
@@ -35653,9 +37046,9 @@ In other words, the only ways this can go out of sync are:
The @code{MyISAM} tables are copied without a @code{LOCK} and
@code{FLUSH TABLES}.
@item
-MySQL has crashed between an update and the final close
-(Note that the table may still be ok, as MySQL always issues writes
-for everything between each statement).
+MySQL has crashed between an update and the final close.
+(Note that the table may still be okay, as MySQL always issues writes
+for everything between each statement.)
@item
Someone has done a @code{myisamchk --repair} or @code{myisamchk
--update-state}on a table that was in use by @code{mysqld}.
@@ -35678,15 +37071,15 @@ is not signaled to the other servers.
@code{MERGE} tables are new in MySQL Version 3.23.25. The code
is still in gamma, but should be resonable stable.
-A @code{MERGE} table is a collection of identical @code{MyISAM} tables
-that can be used as one. You can only @code{SELECT}, @code{DELETE}, and
-@code{UPDATE} from the collection of tables. If you @code{DROP} the
-@code{MERGE} table, you are only dropping the @code{MERGE}
-specification.
+A @code{MERGE} table (also known as a @code{MRG_MyISAM} table) is a
+collection of identical @code{MyISAM} tables that can be used as one.
+You can only @code{SELECT}, @code{DELETE}, and @code{UPDATE} from the
+collection of tables. If you @code{DROP} the @code{MERGE} table, you
+are only dropping the @code{MERGE} specification.
Note that @code{DELETE FROM merge_table} used without a @code{WHERE}
will only clear the mapping for the table, not delete everything in the
-mapped tables. (We plan to fix this in 4.0).
+mapped tables. (We plan to fix this in 4.1).
With identical tables we mean that all tables are created with identical
column and key information. You can't put a MERGE over tables where the
@@ -35746,11 +37139,12 @@ The disadvantages with @code{MERGE} tables are:
@itemize @bullet
@item
-You can't use @code{INSERT} on @code{MERGE} tables, as MySQL
-can't know in which of the tables we should insert the row.
-@item
You can only use identical @code{MyISAM} tables for a @code{MERGE} table.
@item
+@code{AUTO_INCREMENT} columns are not automatically updated on @code{INSERT}.
+@item
+@code{REPLACE} doesn't work.
+@item
@code{MERGE} tables uses more file descriptors. If you are using a
@strong{MERGE} that maps over 10 tables and 10 users are using this, you
are using 10*10 + 10 file descriptors. (10 data files for 10 users
@@ -35772,6 +37166,14 @@ mapped by a @code{MERGE} table that is 'open'. If you do this, the
get unexpected results.
@end itemize
+When you create a @code{MERGE} table you have to specify with
+@code{UNION(list-of-tables)} which tables you want to use as
+one. Optionally you can specify with @code{INSERT_METHOD} if you want
+insert for the @code{MERGE} table to happen in the first or last table
+in the @code{UNION} list. If you don't specify @code{INSERT_METHOD} or
+specify @code{NO}, then all @code{INSERT} commands on the @code{MERGE}
+table will return an error.
+
The following example shows you how to use @code{MERGE} tables:
@example
@@ -35779,7 +37181,8 @@ CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY, message CHAR(20));
CREATE TABLE t2 (a INT AUTO_INCREMENT PRIMARY KEY, message CHAR(20));
INSERT INTO t1 (message) VALUES ("Testing"),("table"),("t1");
INSERT INTO t2 (message) VALUES ("Testing"),("table"),("t2");
-CREATE TABLE total (a INT NOT NULL, message CHAR(20), KEY(a)) TYPE=MERGE UNION=(t1,t2);
+CREATE TABLE total (a INT NOT NULL, message CHAR(20), KEY(a))
+ TYPE=MERGE UNION=(t1,t2) INSERT_METHOD=LAST;
@end example
Note that we didn't create a @code{UNIQUE} or @code{PRIMARY KEY} in the
@@ -35824,17 +37227,64 @@ Change the @code{.MRG} file and issue a @code{FLUSH TABLE} on the
read the new definition file.
@end itemize
+@menu
+* MERGE table problems:: MERGE table problems.
+@end menu
+
+@node MERGE table problems, , MERGE, MERGE
+@subsection MERGE table problems.
+
+The following are the known problems with @code{MERGE} tables:
+
+@itemize @bullet
+@item
+@code{MERGE} table cannot maintain UNIQUE constraints over the whole
+table. When you do INSERT, the data goes into the first or last table
+(according to @code{INSERT_METHOD=xxx}) and this MyISAM table ensures
+that the data are unique, but it knows nothing about the first MyISAM table.
+@item
+@code{DELETE FROM merge_table} used without a @code{WHERE}
+will only clear the mapping for the table, not delete everything in the
+mapped tables.
+@item
+@code{RENAME TABLE} on a table used in an active @code{MERGE} table may
+corrupt the table. This will be fixed in MySQL 4.0.x.
+@item
+Creation of a table of type @code{MERGE} doesn't check if the underlying
+tables are of compatible types. If you use @code{MERGE} tables in this
+fashion, you are very likely to run into strange problems.
+@item
+If you use @code{ALTER TABLE} to first add an @code{UNIQUE} index to a
+table used in a @code{MERGE} table and then use @code{ALTER TABLE} to
+add a normal index on the @code{MERGE} table, the key order will be
+different for the tables if there was an old non-unique key in the
+table. This is because @code{ALTER TABLE} puts @code{UNIQUE} keys before
+normal keys to be able to detect duplicate keys as early as possible.
+@item
+The range optimizer can't yet use @code{MERGE} table efficiently and may
+sometimes produce non-optimal joins. This will be fixed in MySQL 4.0.x.
+@item
+@code{DROP TABLE} on a table that is in use by a @code{MERGE} table will
+not work on Windows because the @code{MERGE} handler does the table mapping
+hidden from the upper layer of MySQL. Because Windows doesn't allow you
+to drop files that are open, you first must flush all @code{MERGE}
+tables (with @code{FLUSH TABLES}) or drop the @code{MERGE} table before
+dropping the table. We will fix this at the same time we introduce
+@code{VIEW}s.
+@end itemize
+
@node ISAM, HEAP, MERGE, Table types
@section ISAM Tables
@cindex tables, ISAM
-You can also use the deprecated ISAM table type. This will disappear
-rather soon because @code{MyISAM} is a better implementation of the same
-thing. ISAM uses a @code{B-tree} index. The index is stored in a file
-with the @code{.ISM} extension, and the data is stored in a file with the
-@code{.ISD} extension. You can check/repair ISAM tables with the
-@code{isamchk} utility. @xref{Crash recovery}.
+You can also use the deprecated @code{ISAM} table type. This will disappear
+rather soon (probably in MySQL 4.1) because @code{MyISAM} is a better
+implementation of the same thing. @code{ISAM} uses a @code{B-tree} index. The
+index is stored in a file with the @code{.ISM} extension, and the data
+is stored in a file with the @code{.ISD} extension. You can
+check/repair @code{ISAM} tables with the @code{isamchk} utility. @xref{Crash
+recovery}.
@code{ISAM} has the following features/properties:
@@ -35851,7 +37301,7 @@ tables. @xref{MyISAM}. The major differences compared to @code{MyISAM}
tables are:
@itemize @bullet
-@item ISAM tables are not binary portable across OS/Platforms.
+@item @code{ISAM} tables are not binary portable across OS/Platforms.
@item Can't handle tables > 4G.
@item Only support prefix compression on strings.
@item Smaller key limits.
@@ -35867,8 +37317,9 @@ TABLE} statement:
mysql> ALTER TABLE tbl_name TYPE = MYISAM;
@end example
+The embedded MySQL versions doesn't support @code{ISAM} tables.
-@node HEAP, BDB, ISAM, Table types
+@node HEAP, InnoDB, ISAM, Table types
@section HEAP Tables
@cindex tables, @code{HEAP}
@@ -35877,14 +37328,14 @@ mysql> ALTER TABLE tbl_name TYPE = MYISAM;
makes them very fast, but if MySQL crashes you will lose all
data stored in them. @code{HEAP} is very useful for temporary tables!
-The MySQL internal HEAP tables use 100% dynamic hashing
+The MySQL internal @code{HEAP} tables use 100% dynamic hashing
without overflow areas. There is no extra space needed for free lists.
@code{HEAP} tables also don't have problems with delete + inserts, which
normally is common with hashed tables:
@example
mysql> CREATE TABLE test TYPE=HEAP SELECT ip,SUM(downloads) as down
- FROM log_table GROUP BY ip;
+ -> FROM log_table GROUP BY ip;
mysql> SELECT COUNT(ip),AVG(down) FROM test;
mysql> DROP TABLE test;
@end example
@@ -35930,7 +37381,7 @@ To free memory, you should execute @code{DELETE FROM heap_table},
@code{TRUNCATE heap_table} or @code{DROP TABLE heap_table}.
@item
MySQL cannot find out approximately how many rows there
-are between two values (this is used by the range optimizer to decide which
+are between two values (this is used by the range optimiser to decide which
index to use). This may affect some queries if you change a @code{MyISAM}
table to a @code{HEAP} table.
@item
@@ -35948,336 +37399,93 @@ SUM_OVER_ALL_KEYS(max_length_of_key + sizeof(char*) * 2)
@code{sizeof(char*)} is 4 on 32-bit machines and 8 on 64-bit machines.
-@node BDB, InnoDB, HEAP, Table types
-@section BDB or Berkeley_DB Tables
-
-@cindex tables, @code{BDB}
-@cindex tables, @code{Berkeley DB}
+@node InnoDB, BDB, HEAP, Table types
+@section InnoDB Tables
@menu
-* BDB overview:: Overview of BDB Tables
-* BDB install:: Installing BDB
-* BDB start:: BDB startup options
-* BDB characteristic:: Some characteristic of @code{BDB} tables:
-* BDB TODO:: Some things we need to fix for BDB in the near future:
-* BDB portability:: Operating systems supported by @strong{BDB}
-* BDB errors:: Errors You May Get When Using BDB Tables
+* InnoDB overview:: InnoDB Tables Overview
+* InnoDB start:: InnoDB Startup Options
+* InnoDB init:: Creating InnoDB Tablespace
+* Using InnoDB tables:: Creating InnoDB Tables
+* Adding and removing:: Adding and Removing InnoDB Data and Log Files
+* Backing up:: Backing up and Recovering an InnoDB Database
+* Moving:: Moving an InnoDB Database to Another Machine
+* InnoDB transaction model:: InnoDB Transaction Model.
+* Implementation:: Implementation of Multiversioning
+* Table and index:: Table and Index Structures
+* File space management:: File Space Management and Disk i/o
+* Error handling:: Error Handling
+* InnoDB restrictions:: Restrictions on InnoDB Tables
+* InnoDB contact information:: InnoDB Contact Information.
@end menu
-@node BDB overview, BDB install, BDB, BDB
-@subsection Overview of BDB Tables
-
-Support for BDB tables is included in the MySQL source distribution
-starting from Version 3.23.34 and is activated in the MySQL-Max
-binary.
-
-BerkeleyDB, available at @uref{http://www.sleepycat.com/} has provided
-MySQL with a transactional table handler. By using BerkeleyDB
-tables, your tables may have a greater chance of surviving crashes, and also
-provides @code{COMMIT} and @code{ROLLBACK} on transactions. The
-MySQL source distribution comes with a BDB distribution that has a
-couple of small patches to make it work more smoothly with MySQL.
-You can't use a non-patched @code{BDB} version with MySQL.
-
-We at MySQL AB are working in close cooperation with Sleepycat to
-keep the quality of the MySQL/BDB interface high.
-
-When it comes to supporting BDB tables, we are committed to help our
-users to locate the problem and help creating a reproducable test case
-for any problems involving BDB tables. Any such test case will be
-forwarded to Sleepycat who in turn will help us find and fix the
-problem. As this is a two stage operation, any problems with BDB tables
-may take a little longer for us to fix than for other table handlers.
-However, as the BerkeleyDB code itself has been used by many other
-applications than MySQL, we don't envision any big problems with
-this. @xref{Table handler support}.
-
-
-@node BDB install, BDB start, BDB overview, BDB
-@subsection Installing BDB
-
-If you have downloaded a binary version of MySQL that includes
-support for BerkeleyDB, simply follow the instructions for installing a
-binary version of MySQL.
-@xref{Installing binary}. @xref{mysqld-max, , @code{mysqld-max}}.
-
-To compile MySQL with Berkeley DB support, download MySQL
-Version 3.23.34 or newer and configure @code{MySQL} with the
-@code{--with-berkeley-db} option. @xref{Installing source}.
-
-@example
-cd /path/to/source/of/mysql-3.23.34
-./configure --with-berkeley-db
-@end example
-
-Please refer to the manual provided with the @code{BDB} distribution for
-more updated information.
-
-Even though Berkeley DB is in itself very tested and reliable,
-the MySQL interface is still considered beta quality.
-We are actively improving and optimizing it to get it stable very
-soon.
-
-
-@node BDB start, BDB characteristic, BDB install, BDB
-@subsection BDB startup options
-
-If you are running with @code{AUTOCOMMIT=0} then your changes in @code{BDB}
-tables will not be updated until you execute @code{COMMIT}. Instead of commit
-you can execute @code{ROLLBACK} to forget your changes. @xref{COMMIT}.
-
-If you are running with @code{AUTOCOMMIT=1} (the default), your changes
-will be committed immediately. You can start an extended transaction with
-the @code{BEGIN WORK} SQL command, after which your changes will not be
-committed until you execute @code{COMMIT} (or decide to @code{ROLLBACK}
-the changes).
-
-The following options to @code{mysqld} can be used to change the behavior of
-BDB tables:
-
-@multitable @columnfractions .30 .70
-@item @strong{Option} @tab @strong{Meaning}
-@item @code{--bdb-home=directory} @tab Base directory for BDB tables. This should be the same directory you use for --datadir.
-@item @code{--bdb-lock-detect=#} @tab Berkeley lock detect. One of (DEFAULT, OLDEST, RANDOM, or YOUNGEST).
-@item @code{--bdb-logdir=directory} @tab Berkeley DB log file directory.
-@item @code{--bdb-no-sync} @tab Don't synchronously flush logs.
-@item @code{--bdb-no-recover} @tab Don't start Berkeley DB in recover mode.
-@item @code{--bdb-shared-data} @tab Start Berkeley DB in multi-process mode (Don't use @code{DB_PRIVATE} when initializing Berkeley DB)
-@item @code{--bdb-tmpdir=directory} @tab Berkeley DB tempfile name.
-@item @code{--skip-bdb} @tab Don't use berkeley db.
-@item @code{-O bdb_max_lock=1000} @tab Set the maximum number of locks possible. @xref{SHOW VARIABLES}.
-@end multitable
-
-If you use @code{--skip-bdb}, MySQL will not initialize the
-Berkeley DB library and this will save a lot of memory. Of course,
-you cannot use @code{BDB} tables if you are using this option.
-
-Normally you should start @code{mysqld} without @code{--bdb-no-recover} if you
-intend to use BDB tables. This may, however, give you problems when you
-try to start @code{mysqld} if the BDB log files are corrupted. @xref{Starting
-server}.
-
-With @code{bdb_max_lock} you can specify the maximum number of locks
-(10000 by default) you can have active on a BDB table. You should
-increase this if you get errors of type @code{bdb: Lock table is out of
-available locks} or @code{Got error 12 from ...} when you have do long
-transactions or when @code{mysqld} has to examine a lot of rows to
-calculate the query.
-
-You may also want to change @code{binlog_cache_size} and
-@code{max_binlog_cache_size} if you are using big multi-line transactions.
-@xref{COMMIT}.
-
-
-@node BDB characteristic, BDB TODO, BDB start, BDB
-@subsection Some characteristic of @code{BDB} tables:
-
-@itemize @bullet
-@item
-To be able to rollback transactions BDB maintain log files. For maximum
-performance you should place these on another disk than your databases
-by using the @code{--bdb_log_dir} options.
-@item
-MySQL performs a checkpoint each time a new BDB log
-file is started, and removes any log files that are not needed for
-current transactions. One can also run @code{FLUSH LOGS} at any time
-to checkpoint the Berkeley DB tables.
-
-For disaster recovery, one should use table backups plus
-MySQL's binary log. @xref{Backup}.
-
-@strong{Warning}: If you delete old log files that are in use, BDB will
-not be able to do recovery at all and you may lose data if something
-goes wrong.
-@item
-MySQL requires a @code{PRIMARY KEY} in each BDB table to be
-able to refer to previously read rows. If you don't create one,
-MySQL will create an maintain a hidden @code{PRIMARY KEY} for
-you. The hidden key has a length of 5 bytes and is incremented for each
-insert attempt.
-@item
-If all columns you access in a @code{BDB} table are part of the same index or
-part of the primary key, then MySQL can execute the query
-without having to access the actual row. In a @code{MyISAM} table the
-above holds only if the columns are part of the same index.
-@item
-The @code{PRIMARY KEY} will be faster than any other key, as the
-@code{PRIMARY KEY} is stored together with the row data. As the other keys are
-stored as the key data + the @code{PRIMARY KEY}, it's important to keep the
-@code{PRIMARY KEY} as short as possible to save disk and get better speed.
-@item
-@code{LOCK TABLES} works on @code{BDB} tables as with other tables. If
-you don't use @code{LOCK TABLE}, MYSQL will issue an internal
-multiple-write lock on the table to ensure that the table will be
-properly locked if another thread issues a table lock.
-@item
-Internal locking in @code{BDB} tables is done on page level.
-@item
-@code{SELECT COUNT(*) FROM table_name} is slow as @code{BDB} tables doesn't
-maintain a count of the number of rows in the table.
-@item
-Scanning is slower than with @code{MyISAM} tables as one has data in BDB
-tables stored in B-trees and not in a separate data file.
-@item
-The application must always be prepared to handle cases where
-any change of a @code{BDB} table may make an automatic rollback and any
-read may fail with a deadlock error.
-@item
-Keys are not compressed to previous keys as with ISAM or MyISAM
-tables. In other words, the key information will take a little more
-space in @code{BDB} tables compared to MyISAM tables which don't use
-@code{PACK_KEYS=0}.
-@item
-There is often holes in the BDB table to allow you to insert new rows in
-the middle of the key tree. This makes BDB tables somewhat larger than
-MyISAM tables.
-@item
-The optimizer needs to know an approximation of the number of rows in
-the table. MySQL solves this by counting inserts and
-maintaining this in a separate segment in each BDB table. If you don't
-do a lot of @code{DELETE} or @code{ROLLBACK}:s this number should be
-accurate enough for the MySQL optimizer, but as MySQL
-only store the number on close, it may be wrong if MySQL dies
-unexpectedly. It should not be fatal even if this number is not 100 %
-correct. One can update the number of rows by executing @code{ANALYZE
-TABLE} or @code{OPTIMIZE TABLE}. @xref{ANALYZE TABLE} . @xref{OPTIMIZE
-TABLE}.
-@item
-If you get full disk with a @code{BDB} table, you will get an error
-(probably error 28) and the transaction should roll back. This is in
-contrast with @code{MyISAM} and @code{ISAM} tables where @code{mysqld} will
-wait for enough free disk before continuing.
-@end itemize
-
-
-@node BDB TODO, BDB portability, BDB characteristic, BDB
-@subsection Some things we need to fix for BDB in the near future:
-
-@itemize @bullet
-@item
-It's very slow to open many BDB tables at the same time. If you are
-going to use BDB tables, you should not have a very big table cache (>
-256 ?) and you should use @code{--no-auto-rehash} with the @code{mysql}
-client. We plan to partly fix this in 4.0.
-@item
-@code{SHOW TABLE STATUS} doesn't yet provide that much information for BDB
-tables.
-@item
-Optimize performance.
-@item
-Change to not use page locks at all when we are scanning tables.
-@end itemize
-
-
-@node BDB portability, BDB errors, BDB TODO, BDB
-@subsection Operating systems supported by @strong{BDB}
-If you after having built MySQL with support for BDB tables get
-the following error in the log file when you start @code{mysqld}:
-
-@example
-bdb: architecture lacks fast mutexes: applications cannot be threaded
-Can't init dtabases
-@end example
-
-This means that @code{BDB} tables are not supported for your architecture.
-In this case you have to rebuild MySQL without BDB table support.
-
-NOTE: The following list is not complete; We will update this as we get
-more information about this.
-
-Currently we know that BDB tables works with the following operating
-system.
-
-@itemize @bullet
-@item
-Linux 2.x intel
-@item
-Solaris sparc
-@item
-SCO OpenServer
-@item
-SCO UnixWare 7.0.1
-@end itemize
-
-It doesn't work with the following operating systems:
-
-@itemize @bullet
-@item
-Linux 2.x Alpha
-@item
-Max OS X
-@end itemize
-
-
-@node BDB errors, , BDB portability, BDB
-@subsection Errors You May Get When Using BDB Tables
-
-@itemize @bullet
-@item
-If you get the following error in the @code{hostname.err log} when
-starting @code{mysqld}:
-
-@example
-bdb: Ignoring log file: .../log.XXXXXXXXXX: unsupported log version #
-@end example
-it means that the new @code{BDB} version doesn't support the old log
-file format. In this case you have to delete all @code{BDB} log BDB
-from your database directory (the files that has the format
-@code{log.XXXXXXXXXX} ) and restart @code{mysqld}. We would also
-recommend you to do a @code{mysqldump --opt} of your old @code{BDB}
-tables, delete the old table and restore the dump.
-@item
-If you are running in not @code{auto_commit} mode and delete a table you
-are using by another thread you may get the following error messages in
-the MySQL error file:
-
-@example
-001119 23:43:56 bdb: Missing log fileid entry
-001119 23:43:56 bdb: txn_abort: Log undo failed for LSN: 1 3644744: Invalid
-@end example
-
-This is not fatal but we don't recommend that you delete tables if you are
-not in @code{auto_commit} mode, until this problem is fixed (the fix is
-not trivial).
-@end itemize
+@node InnoDB overview, InnoDB start, InnoDB, InnoDB
+@subsection InnoDB Tables Overview
+@cindex transactions, support
+@cindex transaction-safe tables
+@cindex ACID
+
+InnoDB provides MySQL with a transaction-safe (@code{ACID} compliant)
+table handler with commit, rollback, and crash recovery capabilities.
+InnoDB does locking on row level and also provides an Oracle-style
+consistent
+non-locking read in @code{SELECT}s. These features increase
+multiuser concurrency and performance. There is no need for
+lock escalation in InnoDB,
+because row level locks in InnoDB fit in very small space.
+InnoDB tables support @code{FOREIGN KEY} constraints
+as the first table type in MySQL.
-@node InnoDB, , BDB, Table types
-@section InnoDB Tables
+InnoDB has been designed for maximum performance
+when processing
+large data volumes. Its CPU efficiency is probably not
+matched by any other disk-based relational database engine.
-@menu
-* InnoDB overview:: InnoDB tables overview
-* InnoDB start:: InnoDB startup options
-* InnoDB init:: Creating InnoDB table space.
-* Using InnoDB tables:: Creating InnoDB tables
-* Adding and removing:: Adding and removing InnoDB data and log files
-* Backing up:: Backing up and recovering an InnoDB database
-* Moving:: Moving an InnoDB database to another machine
-* InnoDB transaction model:: InnoDB transaction model.
-* Implementation:: Implementation of multiversioning
-* Table and index:: Table and index structures
-* File space management:: File space management and disk i/o
-* Error handling:: Error handling
-* InnoDB restrictions:: Some restrictions on InnoDB tables
-* InnoDB contact information:: InnoDB contact information.
-@end menu
+Technically, InnoDB is a complete database backend placed under MySQL.
+InnoDB has its own buffer pool for caching data and indexes in main
+memory. InnoDB stores its tables and indexes in a tablespace, which
+may consist of several files. This is different from, for example,
+MyISAM tables where each table is stored as a separate file.
+InnoDB tables can be of any size also on those operating
+systems where file size is limited to 2 GB.
+You can find the latest information about InnoDB at
+@uref{http://www.innodb.com/}. The most up-to-date version of the
+InnoDB manual is always placed there, and you can also order
+commercial licenses and support for InnoDB.
-@node InnoDB overview, InnoDB start, InnoDB, InnoDB
-@subsection InnoDB tables overview
+InnoDB is currently (October 2001) used in production at
+several large database sites requiring high performance.
+The famous Internet news site Slashdot.org runs on
+InnoDB. Mytrix, Inc. stores over 1 TB of data in
+InnoDB, and another site handles an average
+load of 800 inserts/updates per second in InnoDB.
InnoDB tables are included in the MySQL source distribution
-starting from 3.23.34a and are activated in the @strong{MySQL -max}
-binary.
+starting from 3.23.34a and are activated in the MySQL -Max
+binary. For Windows the -Max binaries are contained in the
+standard distribution.
If you have downloaded a binary version of MySQL that includes
-support for InnoDB (mysqld-max), simply follow the instructions for
-installing a binary version of MySQL. @xref{Installing binary}.
+support for InnoDB, simply follow the instructions of the
+MySQL manual
+for installing a binary version of MySQL. If you already have
+MySQL-3.23 installed, then the simplest way to install
+MySQL -Max is to replace the server executable @file{mysqld}
+with the corresponding executable in the -Max distribution.
+MySQL and MySQL -Max differ only in the server executable.
+@xref{Installing binary}.
@xref{mysqld-max, , @code{mysqld-max}}.
-To compile MySQL with InnoDB support, download MySQL-3.23.37 or newer
-and configure MySQL with the @code{--with-innodb} option.
+To compile MySQL with InnoDB support,
+download MySQL-3.23.34a or newer version from
+@uref{http://www.mysql.com/}
+and configure MySQL with the
+@code{--with-innodb} option. See the
+MySQL manual
+about installing a MySQL source distribution.
@xref{Installing source}.
@example
@@ -36285,103 +37493,175 @@ cd /path/to/source/of/mysql-3.23.37
./configure --with-innodb
@end example
-To get InnoDB to work you have to specify where the data for InnoDB
-tables should be stored by specifying the @code{innodb_data_file_path}
-option on the command line or in an MySQL option file. @xref{InnoDB
-start}. If you have configured MySQL for InnoDB but you have not
-specified the above option, @code{mysqld} will print at start:
+To use InnoDB you have to specify InnoDB startup options in
+your @file{my.cnf} or @file{my.ini} file. The minimal way
+to modify it is to add to the @code{[mysqld]} section the line
@example
-Can't initialize InnoDB as 'innodb_data_file_path' is not set
+innodb_data_file_path=ibdata:30M
@end example
-InnoDB provides MySQL with a transaction-safe table handler with
-commit, rollback, and crash recovery capabilities. InnoDB does
-locking on row level, and also provides an Oracle-style consistent
-non-locking read in @code{SELECTS}, which increases transaction
-concurrency. There is not need for lock escalation in InnoDB,
-because row level locks in InnoDB fit in very small space.
-
-InnoDB has been designed for maximum performance when processing
-large data volumes. Its CPU efficiency is probably not
-matched by any other disk-based relational database engine.
-
-You can find the latest information about InnoDB at
-@uref{http://www.innodb.com}. The most up-to-date version of the
-InnoDB manual is always placed there, and you can also order commercial
-support for InnoDB.
-
-Technically, InnoDB is a database backend placed under MySQL. InnoDB
-has its own buffer pool for caching data and indexes in main
-memory. InnoDB stores its tables and indexes in a tablespace, which
-may consist of several files. This is different from, for example,
-@code{MyISAM} tables where each table is stored as a separate file.
+but to get good performance it is best that you specify options
+like recommended below in the section 'InnoDB startup options'.
InnoDB is distributed under the GNU GPL License Version 2 (of June 1991).
In the source distribution of MySQL, InnoDB appears as a subdirectory.
@node InnoDB start, InnoDB init, InnoDB overview, InnoDB
-@subsection InnoDB startup options
-
-Beginning from MySQL-3.23.37 the prefix of the options is changed
-from @code{innobase_...} to @code{innodb_...}.
+@subsection InnoDB Startup Options
-To use InnoDB tables you @strong{MUST} specify configuration parameters
+To use InnoDB tables in MySQL-Max-3.23
+you @strong{MUST} specify configuration parameters
in the MySQL configuration file in the @code{[mysqld]} section of
the configuration file @file{my.cnf}. @xref{Option files}.
-The only required parameter to use InnoDB is @code{innodb_data_file_path},
-but you should set others if you want to get a better performance.
+The only required parameter to use InnoDB in MySQL-Max-3.23
+is @code{innodb_data_file_path}.
+In MySQL-4.0 you do not need to specify even
+@code{innodb_data_file_path}. The default is to create a 64 MB
+data file @file{ibdata1} to the @code{datadir} of MySQL.
+
+But to get good performance you MUST explicitly set the InnoDB parameters
+listed below in examples.
Suppose you have a Windows NT machine with 128 MB RAM and a single 10 GB
-hard disk. Below is an example of possible configuration parameters in
+hard disk. Below is an example of possible configuration parameters in
@file{my.cnf} for InnoDB:
@example
-innodb_data_file_path = ibdata1:2000M;ibdata2:2000M
+[mysqld]
+# You can write your other MySQL server options here
+# ...
+#
innodb_data_home_dir = c:\ibdata
-set-variable = innodb_mirrored_log_groups=1
+# Data files must be able to
+# hold your data and indexes
+innodb_data_file_path = ibdata1:2000M;ibdata2:2000M
+# Set buffer pool size to 50 - 80 %
+# of your computer's memory
+set-variable = innodb_buffer_pool_size=70M
+set-variable = innodb_additional_mem_pool_size=10M
innodb_log_group_home_dir = c:\iblogs
+# .._log_arch_dir must be the same
+# as .._log_group_home_dir
+innodb_log_arch_dir = c:\iblogs
+innodb_log_archive=0
set-variable = innodb_log_files_in_group=3
-set-variable = innodb_log_file_size=30M
+# Set the log file size to about
+# 15 % of the buffer pool size
+set-variable = innodb_log_file_size=10M
set-variable = innodb_log_buffer_size=8M
+# Set ..flush_log_at_trx_commit to
+# 0 if you can afford losing
+# a few last transactions
innodb_flush_log_at_trx_commit=1
-innodb_log_arch_dir = c:\iblogs
-innodb_log_archive=0
-set-variable = innodb_buffer_pool_size=80M
-set-variable = innodb_additional_mem_pool_size=10M
set-variable = innodb_file_io_threads=4
set-variable = innodb_lock_wait_timeout=50
@end example
-Note that data files must be < 4G, and < 2G on
+Note that @strong{InnoDB does not create directories:
+you have to create them yourself.}
+Check also that the MySQL server
+has the @strong{rights to create files in the directories} you specify.
+
+Note that data files must be < 2G in
some file systems! The total size of data files has
-to be >= 10 MB.
-InnoDB does not create directories:
-you have to create them yourself.
+to be >= 10 MB. The combined size of log files MUST be < 4G
+in 32-bit computers.
+
+The default value for @code{innodb_data_home_dir} is the @code{datadir}
+of MySQL. If you do not specify @code{innodb_data_home_dir}, then
+you cannot use absolute paths in @code{innodb_data_file_path}.
+
+When you the first time create an InnoDB database, it
+is best that you start the MySQL server from the command
+prompt. Then InnoDB will print the information about the
+database creation to the screen, and you see what is
+happening. See below in section 3 what the printout
+should look like.
+For example, in Windows you can start @file{mysqld-max.exe} with:
+@example
+your-path-to-mysqld>mysqld-max --standalone --console
+@end example
+
+@strong{Where to put my.cnf or my.ini in Windows?}
+The rules for Windows are the following:
+
+@itemize @bullet
+@item Only one of @file{my.cnf} or @file{my.ini} should be created.
+@item The @file{my.cnf} file should be placed in the root
+directory of the drive @file{C:}.
+@item The @file{my.ini} file should be placed in the WINDIR directory, e.g,
+@file{C:\WINDOWS} or @file{C:\WINNT}. You can use the @code{SET}
+command of MS-DOS to print the value of WINDIR.
+@item If your PC uses a boot loader where the @file{C:} drive
+is not the boot drive, then your only option is to use the @file{my.ini} file.
+@end itemize
+
+@strong{Where to specify options in Unix?}
+On Unix @file{mysqld} reads options from the following files, if they exist,
+in the following order:
+
+@itemize @bullet
+@item @file{/etc/my.cnf} Global options.
+@item @file{COMPILATION_DATADIR/my.cnf} Server-specific options.
+@item @file{defaults-extra-file} The file specified with
+@code{--defaults-extra-file=...}.
+@item @file{~/.my.cnf} User-specific options.
+@end itemize
+
+@code{COMPILATION_DATADIR} is the MySQL data directory which was
+specified as a @code{./configure} option when @file{mysqld}
+was compiled
+(typically @file{/usr/local/mysql/data} for a
+binary installation or @file{/usr/local/var}
+for a source installation).
+
+If you are not sure from where @file{mysqld} reads its @file{my.cnf}
+or @file{my.ini}, you can give the path as a command-line option:
+@code{--defaults-file=your_path_to_my_cnf}.
-Suppose you have a Linux machine with 512 MB RAM and
+Suppose you have a Linux computer with 512 MB RAM and
three 20 GB hard disks (at directory paths @file{/},
@file{/dr2} and @file{/dr3}).
Below is an example of possible configuration parameters in @file{my.cnf} for
InnoDB:
@example
-innodb_data_file_path = ibdata/ibdata1:2000M;dr2/ibdata/ibdata2:2000M
+[mysqld]
+# You can write your other MySQL server options here
+# ...
+#
innodb_data_home_dir = /
-set-variable = innodb_mirrored_log_groups=1
-innodb_log_group_home_dir = /dr3
+# Data files must be able to
+# hold your data and indexes
+innodb_data_file_path = ibdata/ibdata1:2000M;dr2/ibdata/ibdata2:2000M
+# Set buffer pool size to 50 - 80 %
+# of your computer's memory, but
+# make sure on Linux x86 the total
+# memory usage is < 2 GB
+set-variable = innodb_buffer_pool_size=350M
+set-variable = innodb_additional_mem_pool_size=20M
+innodb_log_group_home_dir = /dr3/iblogs
+# .._log_arch_dir must be the same
+# as .._log_group_home_dir
+innodb_log_arch_dir = /dr3/iblogs
+innodb_log_archive=0
set-variable = innodb_log_files_in_group=3
+# Set the log file size to about
+# 15 % of the buffer pool size
set-variable = innodb_log_file_size=50M
set-variable = innodb_log_buffer_size=8M
+# Set ..flush_log_at_trx_commit to
+# 0 if you can afford losing
+# a few last transactions
innodb_flush_log_at_trx_commit=1
-innodb_log_arch_dir = /dr3/iblogs
-innodb_log_archive=0
-set-variable = innodb_buffer_pool_size=400M
-set-variable = innodb_additional_mem_pool_size=20M
set-variable = innodb_file_io_threads=4
set-variable = innodb_lock_wait_timeout=50
+#innodb_flush_method=fdatasync
+#innodb_fast_shutdown=1
+#set-variable = innodb_thread_concurrency=5
@end example
Note that we have placed the two data files on different disks.
@@ -36395,71 +37675,92 @@ improve the performance of the database if all data is not placed
on the same physical disk. Putting log files on a different disk from
data is very often beneficial for performance.
+@strong{Warning:} on Linux x86 you must be careful you
+@strong{do not set memory usage
+too high}. glibc will allow the process heap to grow over thread stacks,
+which will crash your server. Make sure
+@example
+innodb_buffer_pool_size + key_buffer +
+max_connections * (sort_buffer + record_buffer) + max_connections * 1 MB
+@end example
+is significantly smaller than 2 GB. Each thread will use a stack
+(often 1 MB) and in the worst case also
+@code{sort_buffer + record_buff}
+additional memory.
+
The meanings of the configuration parameters are the following:
@multitable @columnfractions .30 .70
-@item @code{innodb_data_home_dir} @tab
+@item @strong{Option} @tab @strong{Description}
+@item @code{innodb_data_home_dir} @tab
The common part of the directory path for all InnoDB data files.
-@item @code{innodb_data_file_path} @tab
+The default for this parameter is the @code{datadir} of MySQL.
+@item @code{innodb_data_file_path} @tab
Paths to individual data files and their sizes. The full directory path
to each data file is acquired by concatenating innodb_data_home_dir to
the paths specified here. The file sizes are specified in megabytes,
-hence the 'M' after the size specification above. Do not set a file size
-bigger than 4000M, and on most operating systems not bigger than 2000M.
+hence the 'M' after the size specification above.
InnoDB also understands the abbreviation 'G', 1G meaning 1024M.
+Starting from
+3.23.44 you can set the file size bigger than 4 GB on those
+operating systems which support big files.
+On some operating systems files must be < 2 GB.
The sum of the sizes of the files must be at least 10 MB.
-@item @code{innodb_mirrored_log_groups} @tab
+@item @code{innodb_mirrored_log_groups} @tab
Number of identical copies of log groups we
keep for the database. Currently this should be set to 1.
-@item @code{innodb_log_group_home_dir} @tab
+@item @code{innodb_log_group_home_dir} @tab
Directory path to InnoDB log files.
-@item @code{innodb_log_files_in_group} @tab
+@item @code{innodb_log_files_in_group} @tab
Number of log files in the log group. InnoDB writes to the files in a
circular fashion. Value 3 is recommended here.
-@item @code{innodb_log_file_size} @tab
+@item @code{innodb_log_file_size} @tab
Size of each log file in a log group in megabytes. Sensible values range
-from 1M to the size of the buffer pool specified below. The bigger the
-value, the less checkpoint flush activity is needed in the buffer pool,
+from 1M to 1/nth of the size of the buffer pool specified below,
+where n is the number of log files in the group. The
+bigger the value,
+the less checkpoint flush activity is needed in the buffer pool,
saving disk i/o. But bigger log files also mean that recovery will be
-slower in case of a crash. File size restriction as for a data file.
-@item @code{innodb_log_buffer_size} @tab
+slower in case of a crash. The combined size of log files must
+be < 4 GB on 32-bit computers.
+@item @code{innodb_log_buffer_size} @tab
The size of the buffer which InnoDB uses to write log to the log files
on disk. Sensible values range from 1M to half the combined size of log
files. A big log buffer allows large transactions to run without a need
to write the log to disk until the transaction commit. Thus, if you have
big transactions, making the log buffer big will save disk i/o.
-@item @code{innodb_flush_log_at_trx_commit} @tab
+@item @code{innodb_flush_log_at_trx_commit} @tab
Normally this is set to 1, meaning that at a transaction commit the log
is flushed to disk, and the modifications made by the transaction become
permanent, and survive a database crash. If you are willing to
compromise this safety, and you are running small transactions, you may
set this to 0 to reduce disk i/o to the logs.
-@item @code{innodb_log_arch_dir} @tab
+@item @code{innodb_log_arch_dir} @tab
The directory where fully written log files would be archived if we used
log archiving. The value of this parameter should currently be set the
same as @code{innodb_log_group_home_dir}.
-@item @code{innodb_log_archive} @tab
+@item @code{innodb_log_archive} @tab
This value should currently be set to 0. As recovery from a backup is
done by MySQL using its own log files, there is currently no need to
archive InnoDB log files.
-@item @code{innodb_buffer_pool_size} @tab
+@item @code{innodb_buffer_pool_size} @tab
The size of the memory buffer InnoDB uses to cache data and indexes of
its tables. The bigger you set this the less disk i/o is needed to
access data in tables. On a dedicated database server you may set this
-parameter up to 90 % of the machine physical memory size. Do not set it
+parameter up to 80 % of the machine physical memory size. Do not set it
too large, though, because competition of the physical memory may cause
paging in the operating system.
-@item @code{innodb_additional_mem_pool_size} @tab
+@item @code{innodb_additional_mem_pool_size} @tab
Size of a memory pool InnoDB uses to store data dictionary information
and other internal data structures. A sensible value for this might be
2M, but the more tables you have in your application the more you will
need to allocate here. If InnoDB runs out of memory in this pool, it
will start to allocate memory from the operating system, and write
warning messages to the MySQL error log.
-@item @code{innodb_file_io_threads} @tab
+@item @code{innodb_file_io_threads} @tab
Number of file i/o threads in InnoDB. Normally, this should be 4, but
-on Windows NT disk i/o may benefit from a larger number.
-@item @code{innodb_lock_wait_timeout} @tab
+on Windows disk i/o may benefit from a larger number.
+@item @code{innodb_lock_wait_timeout} @tab
Timeout in seconds an InnoDB transaction may wait for a lock before
being rolled back. InnoDB automatically detects transaction deadlocks
in its own lock table and rolls back the transaction. If you use
@@ -36472,10 +37773,10 @@ resolve the situation.
The default value for this is @code{fdatasync}.
Another option is @code{O_DSYNC}.
@end multitable
-
+
@node InnoDB init, Using InnoDB tables, InnoDB start, InnoDB
-@subsection Creating InnoDB table space
+@subsection Creating InnoDB Tablespace
Suppose you have installed MySQL and have edited @file{my.cnf} so that
it contains the necessary InnoDB configuration parameters.
@@ -36490,21 +37791,23 @@ and log files. InnoDB will print something like the following:
@example
~/mysqlm/sql > mysqld
-InnoDB: The first specified data file /home/heikki/data/ibdata1 did not exist:
+InnoDB: The first specified data file /home/heikki/data/ibdata1
+did not exist:
InnoDB: a new database to be created!
InnoDB: Setting file /home/heikki/data/ibdata1 size to 134217728
InnoDB: Database physically writes the file full: wait...
-InnoDB: Data file /home/heikki/data/ibdata2 did not exist: new to be created
+InnoDB: Data file /home/heikki/data/ibdata2 did not exist:
+new to be created
InnoDB: Setting file /home/heikki/data/ibdata2 size to 262144000
InnoDB: Database physically writes the file full: wait...
-InnoDB: Log file /home/heikki/data/logs/ib_logfile0 did not exist: new to be c
-reated
+InnoDB: Log file /home/heikki/data/logs/ib_logfile0 did not exist:
+new to be created
InnoDB: Setting log file /home/heikki/data/logs/ib_logfile0 size to 5242880
-InnoDB: Log file /home/heikki/data/logs/ib_logfile1 did not exist: new to be c
-reated
+InnoDB: Log file /home/heikki/data/logs/ib_logfile1 did not exist:
+new to be created
InnoDB: Setting log file /home/heikki/data/logs/ib_logfile1 size to 5242880
-InnoDB: Log file /home/heikki/data/logs/ib_logfile2 did not exist: new to be c
-reated
+InnoDB: Log file /home/heikki/data/logs/ib_logfile2 did not exist:
+new to be created
InnoDB: Setting log file /home/heikki/data/logs/ib_logfile2 size to 5242880
InnoDB: Started
mysqld: ready for connections
@@ -36541,7 +37844,23 @@ mysqld: ready for connections
@node Error creating InnoDB, , InnoDB init, InnoDB init
-@subsubsection If something goes wrong in database creation
+@subsubsection If Something Goes Wrong in Database Creation
+
+If InnoDB prints an operating system error in a file operation,
+usually the problem is one of the following:
+
+@itemize @bullet
+@item You did not create InnoDB data or log directories.
+@item @file{mysqld} does not have the rights to create files in those
+directories.
+@item @file{mysqld} does not read the right @file{my.cnf} or @file{my.ini}
+file, and consequently does not see the options you specified.
+@item The disk is full or a disk quota is exceeded.
+@item You have created a subdirectory whose name is equal to a data file
+you specified.
+@item There is a syntax error in @code{innodb_data_home_dir}
+or @code{innodb_data_file_path}.
+@end itemize
If something goes wrong in an InnoDB database creation, you should
delete all files created by InnoDB. This means all data files, all log
@@ -36552,7 +37871,7 @@ directories. Then you can try the InnoDB database creation again.
@node Using InnoDB tables, Adding and removing, InnoDB init, InnoDB
-@subsection Creating InnoDB tables
+@subsection Creating InnoDB Tables
Suppose you have started the MySQL client with the command
@code{mysql test}.
@@ -36583,20 +37902,12 @@ SHOW TABLE STATUS FROM test LIKE 'CUSTOMER'
@end example
Note that the statistics @code{SHOW} gives about InnoDB tables
-are only approximate: they are used in SQL optimization. Table and
+are only approximate: they are used in SQL optimisation. Table and
index reserved sizes in bytes are accurate, though.
-NOTE: @code{DROP DATABASE} does not currently work for InnoDB tables!
-You must drop the tables individually. Also take care not to delete or
-add @file{.frm} files to your InnoDB database manually: use
-@code{CREATE TABLE} and @code{DROP TABLE} commands.
-InnoDB has its own internal data dictionary, and you will get problems
-if the MySQL @file{.frm} files are out of 'sync' with the InnoDB
-internal data dictionary.
+@subsubsection Converting MyISAM Tables to InnoDB
-@subsubsection Converting MyISAM tables to InnoDB
-
-InnoDB does not have a special optimization for separate index creation.
+InnoDB does not have a special optimisation for separate index creation.
Therefore it does not pay to export and import the table and create indexes
afterwards.
The fastest way to alter a table to InnoDB is to do the inserts
@@ -36615,7 +37926,7 @@ INSERT INTO newtable SELECT * FROM oldtable WHERE yourkey > something
After all data has been inserted you can rename the tables.
During the conversion of big tables you should set the InnoDB
-buffer pool size big
+buffer pool size big
to reduce disk i/o. Not bigger than 80 % of the physical memory, though.
You should set InnoDB log files big, and also the log buffer large.
@@ -36634,9 +37945,64 @@ it is better that you kill the database process and delete all InnoDB data
and log files and all InnoDB table @file{.frm} files, and start
your job again, rather than wait for millions of disk i/os to complete.
+@subsubsection Foreign Key Constraints
+
+InnoDB version 3.23.44 features foreign key constraints. InnoDB is the
+first MySQL table type which allows you to define foreign key
+constraints to guard the integrity of your data.
+
+The syntax of a foreign key constraint definition in InnoDB:
+@example
+FOREIGN KEY (index_col_name, ...)
+ REFERENCES table_name (index_col_name, ...)
+@end example
+
+An example:
+
+@example
+CREATE TABLE parent(id INT NOT NULL, PRIMARY KEY (id)) TYPE=INNODB;
+CREATE TABLE child(id INT, parent_id INT, INDEX par_ind (parent_id),
+ FOREIGN KEY (parent_id) REFERENCES parent(id)) TYPE=INNODB;
+@end example
+
+Both tables have to be InnoDB type and there must be an index
+where the foreign key and the referenced key are listed as the first
+columns. Any @code{ALTER TABLE} currently removes all foreign key
+constrainst defined for the table, but not the constraints
+that reference the table. Corresponding columns in the foreign key
+and the referenced key have to have similar internal data types
+inside InnoDB so that they can be compared without a type
+conversion. The length of string types need not be the same.
+The size and the signedness of integer types has to be same.
+
+When doing foreign key checks InnoDB sets shared row
+level locks on child or parent records it has to look at.
+InnoDB checks foreign key constraints immediately: the check
+is not deferred to transaction commit.
+
+InnoDB allows you to drop any table even though that
+would break the foreign key constraints which reference
+the table. When you drop a table the constraints which
+were defined in its create statement are also dropped.
+
+If you recreate a table which was dropped, it has to have
+a definition which conforms to the foreign key constraints
+referencing it. It must have the right column names and types,
+and it must have indexes on the referenced keys, as stated above.
+
+You can list the foreign key constraints for a table
+@code{T} with
+@example
+SHOW TABLE STATUS FROM yourdatabasename LIKE 'T';
+@end example
+The foreign key constraints are listed in the table comment of
+the output.
+
+InnoDB does not yet support @code{CASCADE ON DELETE}
+or other special options on the constraints.
@node Adding and removing, Backing up, Using InnoDB tables, InnoDB
-@subsection Adding and removing InnoDB data and log files
+@subsection Adding and Removing InnoDB Data and Log Files
You cannot increase the size of an InnoDB data file. To add more into
your tablespace you have to add a new data file. To do this you have to
@@ -36645,7 +38011,7 @@ new file to @code{innodb_data_file_path}, and then start MySQL
again.
Currently you cannot remove a data file from InnoDB. To decrease the
-size of your database you have to use @code{mysqldump} to dump
+size of your database you have to use @file{mysqldump} to dump
all your tables, create a new database, and import your tables to the
new database.
@@ -36659,10 +38025,22 @@ you at the startup that it is creating new log files.
@node Backing up, Moving, Adding and removing, InnoDB
-@subsection Backing up and recovering an InnoDB database
+@subsection Backing up and Recovering an InnoDB Database
The key to safe database management is taking regular backups.
-To take a 'binary' backup of your database you have to do the following:
+
+InnoDB Hot Backup is an online backup tool you can use to
+backup your InnoDB database while it is running. InnoDB
+Hot Backup does not require you to shut down your database
+and it does not set any locks or disturb your normal
+database processing. InnoDB Hot Backup is a non-free
+additional tool which is not included in the standard
+MySQL distribution. See the InnoDB Hot Backup homepage
+@uref{http://www.innodb.com/hotbackup.html}
+for detailed information and screenshots.
+
+If you are able to shut down your MySQL server, then to take
+a 'binary' backup of your database you have to do the following:
@itemize @bullet
@item
@@ -36694,7 +38072,7 @@ A good idea is to take the dumps at the same time you take a binary
backup of your database. You have to shut out all clients from your
database to get a consistent snapshot of all your tables into your
dumps. Then you can take the binary backup, and you will then have
-a consistent snapshot of your database in two formats.
+a consistent snapshot of your database in two formats.
To be able to recover your InnoDB database to the present from the
binary backup described above, you have to run your MySQL database
@@ -36778,7 +38156,7 @@ because there will be more log to apply to the database.
@node Moving, InnoDB transaction model, Backing up, InnoDB
-@subsection Moving an InnoDB database to another machine
+@subsection Moving an InnoDB Database to Another Machine
InnoDB data and log files are binary-compatible on all platforms
if the floating point number format on the machines is the same.
@@ -36799,10 +38177,10 @@ a table.
@node InnoDB transaction model, Implementation, Moving, InnoDB
-@subsection InnoDB transaction model
+@subsection InnoDB Transaction Model
In the InnoDB transaction model the goal has been to combine the best
-sides of a multiversioning database to traditional two-phase locking.
+properties of a multiversioning database to traditional two-phase locking.
InnoDB does locking on row level and runs queries by default
as non-locking consistent reads, in the style of Oracle.
The lock table in InnoDB is stored so space-efficiently that lock
@@ -36811,7 +38189,7 @@ to lock every row in the database, or any random subset of the rows,
without InnoDB running out of memory.
In InnoDB all user activity happens inside transactions. If the
-auto commit mode is used in MySQL, then each SQL statement
+auto-commit mode is used in MySQL, then each SQL statement
will form a single transaction. If the auto commit mode is
switched off, then we can think that a user always has a transaction
open. If he issues
@@ -36825,17 +38203,17 @@ on the other hand cancels all modifications made by the current
transaction.
@menu
-* InnoDB consistent read:: Consistent read
-* InnoDB locking reads:: Locking reads
-* InnoDB Next-key locking:: Next-key locking: avoiding the phantom problem
-* InnoDB Locks set:: Locks set by different SQL statements in InnoDB
-* InnoDB Deadlock detection:: Deadlock detection and rollback
-* InnoDB Consistent read example:: An example of how the consistent read works in InnoDB
+* InnoDB consistent read:: Consistent Read
+* InnoDB locking reads:: Locking Reads
+* InnoDB Next-key locking:: Next-key Locking: Avoiding the Phantom Problem
+* InnoDB Locks set:: Locks Set by Different SQL Statements in InnoDB
+* InnoDB Deadlock detection:: Deadlock Detection and Rollback
+* InnoDB Consistent read example:: An Example of How the Consistent Read Works in InnoDB
@end menu
@node InnoDB consistent read, InnoDB locking reads, InnoDB transaction model, InnoDB transaction model
-@subsubsection Consistent read
+@subsubsection Consistent Read
A consistent read means that InnoDB uses its multiversioning to
present to a query a snapshot of the database at a point in time.
@@ -36861,7 +38239,7 @@ on the table.
@node InnoDB locking reads, InnoDB Next-key locking, InnoDB consistent read, InnoDB transaction model
-@subsubsection Locking reads
+@subsubsection Locking Reads
A consistent read is not convenient in some circumstances.
Suppose you want to add a new row into your table @code{CHILD},
@@ -36919,7 +38297,7 @@ on the rows.
@node InnoDB Next-key locking, InnoDB Locks set, InnoDB locking reads, InnoDB transaction model
-@subsubsection Next-key locking: avoiding the phantom problem
+@subsubsection Next-key Locking: Avoiding the Phantom Problem
In row level locking InnoDB uses an algorithm called next-key locking.
InnoDB does the row level locking so that when it searches or
@@ -36963,7 +38341,7 @@ after the last record in the index. Just that happens in the previous
example: the locks set by InnoDB will prevent any insert to
the table where @code{ID} would be bigger than 100.
-You can use the next-key locking to implement a uniqueness
+You can use next-key locking to implement a uniqueness
check in your application: if you read your data in share mode
and do not see a duplicate for a row you are going to insert,
then you can safely insert your row and know that the next-key
@@ -36972,9 +38350,8 @@ anyone meanwhile inserting a duplicate for your row. Thus the next-key
locking allows you to 'lock' the non-existence of something in your
table.
-
@node InnoDB Locks set, InnoDB Deadlock detection, InnoDB Next-key locking, InnoDB transaction model
-@subsubsection Locks set by different SQL statements in InnoDB
+@subsubsection Locks Set by Different SQL Statements in InnoDB
@itemize @bullet
@item
@@ -37015,6 +38392,12 @@ lock on every record the search encounters.
@code{DELETE FROM ... WHERE ...} : sets an exclusive next-key
lock on every record the search encounters.
@item
+If a @code{FOREIGN KEY} constraint is defined on a table,
+any insert, update, or delete which requires checking of the constraint
+condition sets shared record level locks on the records it
+looks at to check the constraint. Also in the case where the
+constraint fails, InnoDB sets these locks.
+@item
@code{LOCK TABLES ... } : sets table locks. In the implementation
the MySQL layer of code sets these locks. The automatic deadlock detection
of InnoDB cannot detect deadlocks where such table locks are involved:
@@ -37027,7 +38410,7 @@ locks. But that does not put transaction integerity into danger.
@node InnoDB Deadlock detection, InnoDB Consistent read example, InnoDB Locks set, InnoDB transaction model
-@subsubsection Deadlock detection and rollback
+@subsubsection Deadlock Detection and Rollback
InnoDB automatically detects a deadlock of transactions and rolls
back the transaction whose lock request was the last one to build
@@ -37046,7 +38429,7 @@ stores row locks in a format where it cannot afterwards know which was
set by which SQL statement.
@node InnoDB Consistent read example, , InnoDB Deadlock detection, InnoDB transaction model
-@subsubsection An example of how the consistent read works in InnoDB
+@subsubsection An Example of How the Consistent Read Works in InnoDB
When you issue a consistent read, that is, an ordinary @code{SELECT}
statement, InnoDB will give your transaction a timepoint according
@@ -37078,9 +38461,9 @@ v SELECT * FROM t;
COMMIT;
SELECT * FROM t;
- ----------------------
- | 1 | 2 |
- ----------------------
+ ---------------------
+ | 1 | 2 |
+ ---------------------
@end example
Thus user A sees the row inserted by B only when B has committed the
@@ -37095,7 +38478,7 @@ SELECT * FROM t LOCK IN SHARE MODE;
@end example
-@subsection Performance tuning tips
+@subsection Performance Tuning Tips
@strong{1.}
If the Unix @file{top} or the Windows @file{Task Manager} shows that
@@ -37168,9 +38551,8 @@ InnoDB database.
@strong{9.}
Beware also of other big disk-bound operations.
-Use @code{DROP TABLE}
-or @code{TRUNCATE} (from MySQL-4.0 up) to empty a table, not
-@code{DELETE FROM yourtable}.
+Use @code{DROP TABLE} or @code{TRUNCATE} (from MySQL-4.0 up) to empty a
+table, not @code{DELETE FROM yourtable}.
@strong{10.}
Use the multi-line @code{INSERT} to reduce
@@ -37188,15 +38570,24 @@ This tip is of course valid for inserts into any table type, not just InnoDB.
Starting from version 3.23.41 InnoDB includes the InnoDB
Monitor which prints information on the InnoDB internal state.
When swithed on, InnoDB Monitor
-will make the MySQL server to print data to the standard
-output about once every 10 seconds. This data is useful in
+will make the MySQL server @file{mysqld} to print data
+(note: the MySQL client will not print anything)
+to the standard
+output about once every 15 seconds. This data is useful in
performance tuning.
+On Windows you must start @code{mysqld-max}
+from a MS-DOS prompt
+with the @code{--standalone --console}
+options to direct the output to the MS-DOS prompt
+window.
+
+There is a separate @code{innodb_lock_monitor} which
+prints the same information as @code{innodb_monitor}
+plus information on locks set by each transaction.
The printed information includes data on:
@itemize @bullet
@item
-table and record locks held by each active transaction,
-@item
lock waits of a transactions,
@item
semaphore waits of threads,
@@ -37250,8 +38641,8 @@ RECORD LOCKS space id 0 page no 12758 n bits 104 table test/mytable index
PRIMARY trx id 0 582333343 lock_mode X
Record lock, heap no 2 PHYSICAL RECORD: n_fields 74; 1-byte offs FALSE;
info bits 0
- 0: len 4; hex 0001a801; asc ;; 1: len 6; hex 000022b5b39f; asc ";; 2: len 7;
-hex 000002001e03ec; asc ;; 3: len 4; hex 00000001;
+ 0: len 4; hex 0001a801; asc ;; 1: len 6; hex 000022b5b39f; asc ";;
+ 2: len 7; hex 000002001e03ec; asc ;; 3: len 4; hex 00000001;
...
-----------------------------------------------
CURRENT SEMAPHORES RESERVED AND SEMAPHORE WAITS
@@ -37261,8 +38652,9 @@ Sorry, cannot give mutex list info in non-debug version!
Sorry, cannot give rw-lock list info in non-debug version!
-----------------------------------------------------
SYNC ARRAY INFO: reservation count 6041054, signal count 2913432
-4a239430 waited for by thread 49627477 op. S-LOCK file NOT KNOWN line 0
-Mut ex 0 sp 5530989 r 62038708 sys 2155035; rws 0 8257574 8025336; rwx 0 1121090 1848344
+4a239430 waited for by thread 49627477 op. S-LOCK file NOT KNOWN line 0
+Mut ex 0 sp 5530989 r 62038708 sys 2155035;
+rws 0 8257574 8025336; rwx 0 1121090 1848344
-----------------------------------------------------
CURRENT PENDING FILE I/O'S
--------------------------
@@ -37285,11 +38677,11 @@ Total of 0 reserved aio slots
-----------
BUFFER POOL
-----------
-LRU list length 8034
-Free list length 0
-Flush list length 999
+LRU list length 8034
+Free list length 0
+Flush list length 999
Buffer pool size in pages 8192
-Pending reads 39
+Pending reads 39
Pending writes: LRU 0, flush list 0, single page 0
Pages read 31383918, created 51310, written 2985115
----------------------------
@@ -37309,8 +38701,8 @@ may have lock contention. The output can also help to
trace reasons for transaction deadlocks.
@item
Section SYNC INFO will report reserved semaphores
-if you compile InnoDB with <code>UNIV_SYNC_DEBUG</code>
-defined in <tt>univ.i</tt>.
+if you compile InnoDB with @code{UNIV_SYNC_DEBUG}
+defined in @file{univ.i}.
@item
Section SYNC ARRAY INFO reports threads waiting
for a semaphore and statistics on how many times
@@ -37332,7 +38724,7 @@ currently doing.
@end itemize
@node Implementation, Table and index, InnoDB transaction model, InnoDB
-@subsection Implementation of multiversioning
+@subsection Implementation of Multiversioning
Since InnoDB is a multiversioned database, it must keep information
of old versions of rows in the tablespace. This information is stored
@@ -37363,7 +38755,9 @@ a snapshot that in a consistent read could need the information
in the update undo log to build an earlier version of a database
row.
-You must remember to commit your transactions regularly. Otherwise
+You must remember to commit your transactions regularly,
+also those transactions which only issue consistent reads.
+Otherwise
InnoDB cannot discard data from the update undo logs, and the
rollback segment may grow too big, filling up your tablespace.
@@ -37382,7 +38776,19 @@ time as the SQL statement which did the deletion.
@node Table and index, File space management, Implementation, InnoDB
-@subsection Table and index structures
+@subsection Table and Index Structures
+
+MySQL stores its data dictionary information of tables
+in @file{.frm}
+files in database directories. But every InnoDB type table
+also has its own entry in InnoDB internal data dictionaries
+inside the tablespace. When MySQL drops a table or a database,
+it has to delete both a @file{.frm} file or files, and
+the corresponding entries inside the InnoDB data dictionary.
+This is the reason why you cannot move InnoDB tables between
+databases simply by moving the @file{.frm} files, and why
+@code{DROP DATABASE} did not work for InnoDB type tables
+in MySQL versions <= 3.23.43.
Every InnoDB table has a special index called the clustered index
where the data of the rows is stored. If you define a
@@ -37410,15 +38816,15 @@ index. Note that if the primary key is long, the secondary indexes
will use more space.
@menu
-* InnoDB physical structure:: Physical structure of an index
-* InnoDB Insert buffering:: Insert buffering
-* InnoDB Adaptive hash:: Adaptive hash indexes
-* InnoDB Physical record:: Physical record structure
+* InnoDB physical structure:: Physical Structure of an Index
+* InnoDB Insert buffering:: Insert Buffering
+* InnoDB Adaptive hash:: Adaptive Hash Indexes
+* InnoDB Physical record:: Physical Record Structure
@end menu
@node InnoDB physical structure, InnoDB Insert buffering, Table and index, Table and index
-@subsubsection Physical structure of an index
+@subsubsection Physical Structure of an Index
All indexes in InnoDB are B-trees where the index records are
stored in the leaf pages of the tree. The default size of an index
@@ -37434,7 +38840,7 @@ InnoDB will try to contract the index tree to free the page.
@node InnoDB Insert buffering, InnoDB Adaptive hash, InnoDB physical structure, Table and index
-@subsubsection Insert buffering
+@subsubsection Insert Buffering
It is a common situation in a database application that the
primary key is a unique identifier and new rows are inserted in the
@@ -37462,7 +38868,7 @@ to a table up to 15 times.
@node InnoDB Adaptive hash, InnoDB Physical record, InnoDB Insert buffering, Table and index
-@subsubsection Adaptive hash indexes
+@subsubsection Adaptive Hash Indexes
If a database fits almost entirely in main memory, then the fastest way
to perform queries on it is to use hash indexes. InnoDB has an
@@ -37486,7 +38892,7 @@ databases.
@node InnoDB Physical record, , InnoDB Adaptive hash, Table and index
-@subsubsection Physical record structure
+@subsubsection Physical Record Structure
@itemize @bullet
@item
@@ -37509,7 +38915,7 @@ If the total length of the fields in a record is < 128 bytes, then
the pointer is 1 byte, else 2 bytes.
@end itemize
-@subsubsection How an auto-increment column works in InnoDB
+@subsubsection How an Auto-increment Column Works in InnoDB
After a database startup, when a user first does an insert to a
table @code{T}
@@ -37544,12 +38950,12 @@ integer that can be stored in the specified integer type.
@node File space management, Error handling, Table and index, InnoDB
-@subsection File space management and disk i/o
+@subsection File Space Management and Disk i/o
@menu
* InnoDB Disk i/o:: Disk i/o
-* InnoDB File space:: File space management
-* InnoDB File Defragmenting:: Defragmenting a table
+* InnoDB File space:: File Space Management
+* InnoDB File Defragmenting:: Defragmenting a Table
@end menu
@@ -37592,18 +38998,18 @@ file size in @code{innodb_data_file_path}. The partition must be
1000 000 bytes.
@example
-innodb_data_file_path=hdd1:3Gnewraw;hdd2:2Gnewraw
+innodb_data_file_path=hdd1:5Gnewraw;hdd2:2Gnewraw
@end example
-When you start the database again you MUST change the keyword
+When you start the database again you @strong{must} change the keyword
to @code{raw}. Otherwise InnoDB will write over your
partition!
@example
-innodb_data_file_path=hdd1:3Graw;hdd2:2Graw
+innodb_data_file_path=hdd1:5Graw;hdd2:2Graw
@end example
-Using a raw disk you can on some Unixes perform non-buffered i/o.
+By using a raw disk you can on some Unixes perform unbuffered i/o.
There are two read-ahead heuristics in InnoDB: sequential read-ahead
and random read-ahead. In sequential read-ahead InnoDB notices that
@@ -37616,7 +39022,7 @@ reads to the i/o system.
@node InnoDB File space, InnoDB File Defragmenting, InnoDB Disk i/o, File space management
-@subsubsection File space management
+@subsubsection File Space Management
The data files you define in the configuration file form the tablespace
of InnoDB. The files are simply catenated to form the tablespace,
@@ -37664,7 +39070,7 @@ consistent read.
@node InnoDB File Defragmenting, , InnoDB File space, File space management
-@subsubsection Defragmenting a table
+@subsubsection Defragmenting a Table
If there are random insertions or deletions
in the indexes of a table, the indexes
@@ -37688,13 +39094,13 @@ not occur.
@node Error handling, InnoDB restrictions, File space management, InnoDB
-@subsection Error handling
+@subsection Error Handling
The error handling in InnoDB is not always the same as
specified in the ANSI SQL standards. According to the ANSI
standard, any error during an SQL statement should cause the
rollback of that statement. InnoDB sometimes rolls back only
-part of the statement.
+part of the statement, or the whole transaction.
The following list specifies the error handling of InnoDB.
@itemize @bullet
@@ -37703,9 +39109,9 @@ If you run out of file space in the tablespace,
you will get the MySQL @code{'Table is full'} error
and InnoDB rolls back the SQL statement.
@item
-A transaction deadlock or a timeout in a lock wait will give
-@code{'Table handler error 1000000'} and InnoDB rolls back
-the SQL statement.
+A transaction deadlock or a timeout in a lock wait make InnoDB
+to roll back
+the whole transaction.
@item
A duplicate key error only rolls back the insert of that particular row,
even in a statement like @code{INSERT INTO ... SELECT ...}.
@@ -37721,13 +39127,20 @@ they roll back the corresponding SQL statement.
@node InnoDB restrictions, InnoDB contact information, Error handling, InnoDB
-@subsection Some restrictions on InnoDB tables
+@subsection Restrictions on InnoDB Tables
@itemize @bullet
-@item @code{SHOW TABLE STATUS} does not give accurate statistics
+@item
+@strong{WARNING:} Do @strong{NOT} convert MySQL system tables from
+MyISAM TO InnoDB tables! This is not supported; If you do this MySQL
+will not restart until you restore the old system tables from a backup
+or re-generate them with the mysql_install_db script.
+
+@item
+@code{SHOW TABLE STATUS} does not give accurate statistics
on InnoDB tables, except for the physical size reserved by the table.
-The row count is only a rough estimate used in SQL optimization.
+The row count is only a rough estimate used in SQL optimisation.
@item
If you try to create an unique index on a prefix of a column you will get an
@@ -37737,7 +39150,7 @@ error:
CREATE TABLE T (A CHAR(20), B INT, UNIQUE (A(5))) TYPE = InnoDB;
@end example
-If you create a non unique index on a prefix of a column, InnoDB will
+If you create a non-unique index on a prefix of a column, InnoDB will
create an index over the whole column.
@item
@code{INSERT DELAYED} is not supported for InnoDB tables.
@@ -37749,7 +39162,7 @@ of other users which have row level locks on the same table. Thus
your operations on the table may have to wait if they collide with
these locks of other users. Also a deadlock is possible. However,
this does not endanger transaction integrity, because the row level
-locks set by InnoDB will always take care of the integrity.
+locks set by InnoDB will always take care of the integrity.
Also, a table lock prevents other transactions from acquiring more
row level locks (in a conflicting lock mode) on the table.
@item
@@ -37761,23 +39174,19 @@ A table cannot contain more than 1000 columns.
deletes all rows, one by one, which is not that fast. In future versions
of MySQL you can use @code{TRUNCATE} which is fast.
@item
-Before dropping a database with InnoDB tables one has to drop
-the individual InnoDB tables first.
-@item
The default database page size in InnoDB is 16 kB. By recompiling the
code one can set it from 8 kB to 64 kB.
The maximun row length is slightly less than half of a database page
in versions <= 3.23.40 of InnoDB. Starting from source
release 3.23.41 BLOB and
TEXT columns are allowed to be < 4 GB, the total row length must also be
-< 4 GB. InnoDB does not store fields whose size is <= 30 bytes on separate
+< 4 GB. InnoDB does not store fields whose size is <= 128 bytes on separate
pages. After InnoDB has modified the row by storing long fields on
-separate pages, the remaining length of the row must be slightly less
-than half a database page.
+separate pages, the remaining length of the row must be less
+than half a database page. The maximun key length is 7000 bytes.
@item
-The maximum data or log file size is 2 GB or 4 GB depending on how large
-files your operating system supports. Support for > 4 GB files will
-be added to InnoDB in a future version.
+On some operating systems data files must be < 2 GB. The combined
+size of log files must be < 4 GB on 32-bit computers.
@item
The maximum tablespace size is 4 billion database pages. This is also
the maximum size for a table. The minimum tablespace size is 10 MB.
@@ -37785,15 +39194,15 @@ the maximum size for a table. The minimum tablespace size is 10 MB.
@node InnoDB contact information, , InnoDB restrictions, InnoDB
-@subsection InnoDB contact information
+@subsection InnoDB Contact Information
Contact information of Innobase Oy, producer of the InnoDB engine.
-Website: @uref{http://www.innodb.com}. Email:
-@email{Heikki.Tuuri@@innodb.com}
+Web site: @uref{http://www.innodb.com/}.
+Email: @email{Heikki.Tuuri@@innodb.com}
@example
phone: 358-9-6969 3250 (office) 358-40-5617367 (mobile)
-InnoDB Oy Inc.
+Innobase Oy Inc.
World Trade Center Helsinki
Aleksanterinkatu 17
P.O.Box 800
@@ -37802,6 +39211,323 @@ Finland
@end example
+@node BDB, , InnoDB, Table types
+@section BDB or Berkeley_DB Tables
+
+@cindex tables, @code{BDB}
+@cindex tables, @code{Berkeley DB}
+
+@menu
+* BDB overview:: Overview of BDB Tables
+* BDB install:: Installing BDB
+* BDB start:: BDB startup options
+* BDB characteristics:: Characteristics of @code{BDB} tables:
+* BDB TODO:: Things we need to fix for BDB in the near future:
+* BDB portability:: Operating systems supported by @strong{BDB}
+* BDB restrictions:: Restrictions on BDB Tables
+* BDB errors:: Errors That May Occur When Using BDB Tables
+@end menu
+
+@node BDB overview, BDB install, BDB, BDB
+@subsection Overview of BDB Tables
+
+Support for BDB tables is included in the MySQL source distribution
+starting from Version 3.23.34 and is activated in the MySQL-Max
+binary.
+
+BerkeleyDB, available at @uref{http://www.sleepycat.com/} has provided
+MySQL with a transactional table handler. By using BerkeleyDB
+tables, your tables may have a greater chance of surviving crashes, and also
+provides @code{COMMIT} and @code{ROLLBACK} on transactions. The
+MySQL source distribution comes with a BDB distribution that has a
+couple of small patches to make it work more smoothly with MySQL.
+You can't use a non-patched @code{BDB} version with MySQL.
+
+We at MySQL AB are working in close cooperation with Sleepycat to
+keep the quality of the MySQL/BDB interface high.
+
+When it comes to supporting BDB tables, we are committed to help our
+users to locate the problem and help creating a reproducable test case
+for any problems involving BDB tables. Any such test case will be
+forwarded to Sleepycat who in turn will help us find and fix the
+problem. As this is a two stage operation, any problems with BDB tables
+may take a little longer for us to fix than for other table handlers.
+However, as the BerkeleyDB code itself has been used by many other
+applications than MySQL, we don't envision any big problems with
+this. @xref{Support}.
+
+
+@node BDB install, BDB start, BDB overview, BDB
+@subsection Installing BDB
+
+If you have downloaded a binary version of MySQL that includes
+support for BerkeleyDB, simply follow the instructions for installing a
+binary version of MySQL.
+@xref{Installing binary}. @xref{mysqld-max, , @code{mysqld-max}}.
+
+To compile MySQL with Berkeley DB support, download MySQL
+Version 3.23.34 or newer and configure @code{MySQL} with the
+@code{--with-berkeley-db} option. @xref{Installing source}.
+
+@example
+cd /path/to/source/of/mysql-3.23.34
+./configure --with-berkeley-db
+@end example
+
+Please refer to the manual provided with the @code{BDB} distribution for
+more updated information.
+
+Even though Berkeley DB is in itself very tested and reliable,
+the MySQL interface is still considered beta quality.
+We are actively improving and optimising it to get it stable very
+soon.
+
+
+@node BDB start, BDB characteristics, BDB install, BDB
+@subsection BDB startup options
+
+If you are running with @code{AUTOCOMMIT=0} then your changes in @code{BDB}
+tables will not be updated until you execute @code{COMMIT}. Instead of commit
+you can execute @code{ROLLBACK} to forget your changes. @xref{COMMIT}.
+
+If you are running with @code{AUTOCOMMIT=1} (the default), your changes
+will be committed immediately. You can start an extended transaction with
+the @code{BEGIN WORK} SQL command, after which your changes will not be
+committed until you execute @code{COMMIT} (or decide to @code{ROLLBACK}
+the changes).
+
+The following options to @code{mysqld} can be used to change the behavior of
+BDB tables:
+
+@multitable @columnfractions .30 .70
+@item @strong{Option} @tab @strong{Description}
+@item @code{--bdb-home=directory} @tab Base directory for BDB tables. This should be the same directory you use for --datadir.
+@item @code{--bdb-lock-detect=#} @tab Berkeley lock detect. One of (DEFAULT, OLDEST, RANDOM, or YOUNGEST).
+@item @code{--bdb-logdir=directory} @tab Berkeley DB log file directory.
+@item @code{--bdb-no-sync} @tab Don't synchronously flush logs.
+@item @code{--bdb-no-recover} @tab Don't start Berkeley DB in recover mode.
+@item @code{--bdb-shared-data} @tab Start Berkeley DB in multi-process mode (Don't use @code{DB_PRIVATE} when initialising Berkeley DB)
+@item @code{--bdb-tmpdir=directory} @tab Berkeley DB tempfile name.
+@item @code{--skip-bdb} @tab Don't use berkeley db.
+@item @code{-O bdb_max_lock=1000} @tab Set the maximum number of locks possible. @xref{SHOW VARIABLES}.
+@end multitable
+
+If you use @code{--skip-bdb}, MySQL will not initialise the
+Berkeley DB library and this will save a lot of memory. Of course,
+you cannot use @code{BDB} tables if you are using this option.
+
+Normally you should start @code{mysqld} without @code{--bdb-no-recover} if you
+intend to use BDB tables. This may, however, give you problems when you
+try to start @code{mysqld} if the BDB log files are corrupted. @xref{Starting
+server}.
+
+With @code{bdb_max_lock} you can specify the maximum number of locks
+(10000 by default) you can have active on a BDB table. You should
+increase this if you get errors of type @code{bdb: Lock table is out of
+available locks} or @code{Got error 12 from ...} when you have do long
+transactions or when @code{mysqld} has to examine a lot of rows to
+calculate the query.
+
+You may also want to change @code{binlog_cache_size} and
+@code{max_binlog_cache_size} if you are using big multi-line transactions.
+@xref{COMMIT}.
+
+
+@node BDB characteristics, BDB TODO, BDB start, BDB
+@subsection Characteristics of @code{BDB} tables:
+
+@itemize @bullet
+@item
+To be able to rollback transactions BDB maintain log files. For maximum
+performance you should place these on another disk than your databases
+by using the @code{--bdb_log_dir} options.
+@item
+MySQL performs a checkpoint each time a new BDB log
+file is started, and removes any log files that are not needed for
+current transactions. One can also run @code{FLUSH LOGS} at any time
+to checkpoint the Berkeley DB tables.
+
+For disaster recovery, one should use table backups plus
+MySQL's binary log. @xref{Backup}.
+
+@strong{Warning}: If you delete old log files that are in use, BDB will
+not be able to do recovery at all and you may lose data if something
+goes wrong.
+@item
+MySQL requires a @code{PRIMARY KEY} in each BDB table to be
+able to refer to previously read rows. If you don't create one,
+MySQL will create an maintain a hidden @code{PRIMARY KEY} for
+you. The hidden key has a length of 5 bytes and is incremented for each
+insert attempt.
+@item
+If all columns you access in a @code{BDB} table are part of the same index or
+part of the primary key, then MySQL can execute the query
+without having to access the actual row. In a @code{MyISAM} table the
+above holds only if the columns are part of the same index.
+@item
+The @code{PRIMARY KEY} will be faster than any other key, as the
+@code{PRIMARY KEY} is stored together with the row data. As the other keys are
+stored as the key data + the @code{PRIMARY KEY}, it's important to keep the
+@code{PRIMARY KEY} as short as possible to save disk and get better speed.
+@item
+@code{LOCK TABLES} works on @code{BDB} tables as with other tables. If
+you don't use @code{LOCK TABLE}, MySQL will issue an internal
+multiple-write lock on the table to ensure that the table will be
+properly locked if another thread issues a table lock.
+@item
+Internal locking in @code{BDB} tables is done on page level.
+@item
+@code{SELECT COUNT(*) FROM table_name} is slow as @code{BDB} tables doesn't
+maintain a count of the number of rows in the table.
+@item
+Scanning is slower than with @code{MyISAM} tables as one has data in BDB
+tables stored in B-trees and not in a separate data file.
+@item
+The application must always be prepared to handle cases where
+any change of a @code{BDB} table may make an automatic rollback and any
+read may fail with a deadlock error.
+@item
+Keys are not compressed to previous keys as with ISAM or MyISAM
+tables. In other words, the key information will take a little more
+space in @code{BDB} tables compared to MyISAM tables which don't use
+@code{PACK_KEYS=0}.
+@item
+There is often holes in the BDB table to allow you to insert new rows in
+the middle of the key tree. This makes BDB tables somewhat larger than
+MyISAM tables.
+@item
+The optimiser needs to know an approximation of the number of rows in
+the table. MySQL solves this by counting inserts and
+maintaining this in a separate segment in each BDB table. If you don't
+do a lot of @code{DELETE} or @code{ROLLBACK}:s this number should be
+accurate enough for the MySQL optimiser, but as MySQL
+only store the number on close, it may be wrong if MySQL dies
+unexpectedly. It should not be fatal even if this number is not 100 %
+correct. One can update the number of rows by executing @code{ANALYZE
+TABLE} or @code{OPTIMIZE TABLE}. @xref{ANALYZE TABLE} . @xref{OPTIMIZE
+TABLE}.
+@item
+If you get full disk with a @code{BDB} table, you will get an error
+(probably error 28) and the transaction should roll back. This is in
+contrast with @code{MyISAM} and @code{ISAM} tables where @code{mysqld} will
+wait for enough free disk before continuing.
+@end itemize
+
+
+@node BDB TODO, BDB portability, BDB characteristics, BDB
+@subsection Things we need to fix for BDB in the near future:
+
+@itemize @bullet
+@item
+It's very slow to open many BDB tables at the same time. If you are
+going to use BDB tables, you should not have a very big table cache (>
+256 ?) and you should use @code{--no-auto-rehash} with the @code{mysql}
+client. We plan to partly fix this in 4.0.
+@item
+@code{SHOW TABLE STATUS} doesn't yet provide that much information for BDB
+tables.
+@item
+Optimise performance.
+@item
+Change to not use page locks at all when we are scanning tables.
+@end itemize
+
+
+@node BDB portability, BDB restrictions, BDB TODO, BDB
+@subsection Operating systems supported by @strong{BDB}
+
+If you after having built MySQL with support for BDB tables get
+the following error in the log file when you start @code{mysqld}:
+
+@example
+bdb: architecture lacks fast mutexes: applications cannot be threaded
+Can't init dtabases
+@end example
+
+This means that @code{BDB} tables are not supported for your architecture.
+In this case you have to rebuild MySQL without BDB table support.
+
+NOTE: The following list is not complete; We will update this as we get
+more information about this.
+
+Currently we know that BDB tables works with the following operating
+system.
+
+@itemize @bullet
+@item
+Linux 2.x intel
+@item
+Solaris sparc
+@item
+Caldera (SCO) OpenServer
+@item
+Caldera (SCO) UnixWare 7.0.1
+@end itemize
+
+It doesn't work with the following operating systems:
+
+@itemize @bullet
+@item
+Linux 2.x Alpha
+@item
+Max OS X
+@end itemize
+
+@node BDB restrictions, BDB errors, BDB portability, BDB
+@subsection Restrictions on BDB Tables
+
+Here follows the restrictions you have when using BDB tables:
+
+@itemize @bullet
+@item
+BDB tables store in the .db file the path to the file as it was created
+(My guess is that this is to be able to detect locks in a multi-user
+environment that supports symlinks).
+
+The effect of this is that BDB tables are not movable between directories!
+@item
+When taking backups of BDB tables, you have to either use
+@code{mysqldump} or take a backup of all @code{table_name.db} files and
+the BDB log files. The BDB log files are the files in the base data
+directory named @code{log.XXXXXX} (6 digits);
+The BDB table handler stores unfinished transactions in the log files
+and requires these to be present when @code{mysqld} starts.
+@end itemize
+
+@node BDB errors, , BDB restrictions, BDB
+@subsection Errors That May Occur When Using BDB Tables
+
+@itemize @bullet
+@item
+If you get the following error in the @code{hostname.err log} when
+starting @code{mysqld}:
+
+@example
+bdb: Ignoring log file: .../log.XXXXXXXXXX: unsupported log version #
+@end example
+it means that the new @code{BDB} version doesn't support the old log
+file format. In this case you have to delete all @code{BDB} log BDB
+from your database directory (the files that has the format
+@code{log.XXXXXXXXXX} ) and restart @code{mysqld}. We would also
+recommend you to do a @code{mysqldump --opt} of your old @code{BDB}
+tables, delete the old table and restore the dump.
+@item
+If you are running in not @code{auto_commit} mode and delete a table you
+are using by another thread you may get the following error messages in
+the MySQL error file:
+
+@example
+001119 23:43:56 bdb: Missing log fileid entry
+001119 23:43:56 bdb: txn_abort: Log undo failed for LSN:
+ 1 3644744: Invalid
+@end example
+
+This is not fatal but we don't recommend that you delete tables if you are
+not in @code{auto_commit} mode, until this problem is fixed (the fix is
+not trivial).
+@end itemize
+
+
@node Clients, Extending MySQL, Table types, Top
@@ -37827,7 +39553,7 @@ Finland
This chapter describes the APIs available for MySQL, where to get
them, and how to use them. The C API is the most extensively covered, as it
-was developed by the MySQL team, and is the basis for most of the
+was developed by the MySQL team, and is the basis for most of the
other APIs.
@@ -37841,8 +39567,8 @@ create dynamic Web pages. It contains support for accessing several
databases, including MySQL. PHP may be run as a separate program
or compiled as a module for use with the Apache Web server.
-The distribution and documentation are available at the
-@uref{http://www.php.net/, PHP web site}.
+The distribution and documentation are available at the PHP web site
+(@uref{http://www.php.net/}).
@menu
* PHP problems:: Common problems with MySQL and PHP
@@ -37901,7 +39627,7 @@ database type. For MySQL, this driver is called
For more information on the Perl5 DBI, please visit the @code{DBI} Web
page and read the documentation:
@example
-@uref{http://www.symbolstone.org/technology/perl/DBI/index.html}
+@uref{http://www.symbolstone.org/technology/perl/DBI/}
@end example
For more information on Object Oriented Programming
(OOP) as defined in Perl5, see the Perl OOP page:
@@ -37925,6 +39651,7 @@ Installation instructions for MySQL Perl support are given in
@strong{Portable DBI Methods}
@multitable @columnfractions .3 .7
+@item @strong{Method} @tab @strong{Description}
@item @code{connect} @tab Establishes a connection to a database server.
@item @code{disconnect} @tab Disconnects from the database server.
@item @code{prepare} @tab Prepares a SQL statement for execution.
@@ -37948,6 +39675,7 @@ Installation instructions for MySQL Perl support are given in
@strong{MySQL-specific Methods}
@multitable @columnfractions .3 .7
+@item @strong{Method} @tab @strong{Description}
@item @code{insertid} @tab The latest @code{AUTO_INCREMENT} value.
@item @code{is_blob} @tab Which columns are @code{BLOB} values.
@item @code{is_key} @tab Which columns are keys.
@@ -38104,7 +39832,7 @@ $rv = $dbh->do($statement)
or die "Can't execute $statement: $dbh- >errstr\n";
@end example
-Generally the 'do' statement is MUCH faster (and is preferable)
+Generally the 'do' statement is much faster (and is preferable)
than prepare/execute for statements that don't contain parameters.
@findex DBI->quote()
@@ -38413,7 +40141,7 @@ translate to other formats.
You can find the latest @code{DBI} information at
the @code{DBI} Web page:
@example
-@uref{http://www.symbolstone.org/technology/perl/DBI/index.html}
+@uref{http://www.symbolstone.org/technology/perl/DBI/}
@end example
@@ -38444,17 +40172,16 @@ are known to work with @strong{MyODBC}.
@node Installing MyODBC, ODBC administrator, ODBC, ODBC
@subsection How To Install MyODBC
-@strong{MyODBC} is a 32-bit ODBC (2.50) level 0 (with level 1 and level
-2 features) driver for connecting an ODBC-aware application to
-MySQL. @strong{MyODBC} works on Windows95, Windows98, NT, and
-on most Unix platforms.
+@strong{MyODBC} is a 32-bit ODBC (2.50) level 0 (with level 1 and
+level 2 features) driver for connecting an ODBC-aware application
+to MySQL. @strong{MyODBC} works on Windows95, Windows98, NT, 2000
+and on most Unix platforms.
-@strong{MyODBC} is in public domain, and you can find the newest version
-at @uref{http://www.mysql.com/downloads/api-myodbc.html}.
+@strong{MyODBC} is in public domain, and you can find the newest
+version at @uref{http://www.mysql.com/downloads/api-myodbc.html}.
If you have problem with @strong{MyODBC} and your program also works
-with OLEDB, you should try the OLEDB driver that you can find in the
-Contrib section. @xref{Contrib}.
+with OLEDB, you should try the OLEDB driver.
Normally you only need to install @strong{MyODBC} on Windows machines.
You only need @strong{MyODBC} for Unix if you have a program like
@@ -38463,9 +40190,7 @@ to the databases.
If you want to install @strong{MyODBC} on a Unix box, you will also need
an @strong{ODBC} manager. @strong{MyODBC} is known to work with
-most of the Unix ODBC managers. You can find a list at these in the
-@strong{ODBC}-related links section on the MySQL useful links page.
-@xref{Useful Links}.
+most of the Unix ODBC managers. @xref{Portals}.
To install @strong{MyODBC} on Windows, you should download the
appropriate @strong{MyODBC} .zip file (for Windows or NT/Win2000),
@@ -38584,7 +40309,7 @@ is used.
If you specify the option @code{Read options from C:\my.cnf}, the groups
@code{client} and @code{odbc} will be read from the @file{C:\my.cnf} file.
You can use all options that are usable by @code{mysql_options()}.
-@xref{mysql_options, , @code{mysql_options}}.
+@xref{mysql_options, , @code{mysql_options()}}.
@node MyODBC connect parameters, ODBC Problems, ODBC administrator, ODBC
@@ -38614,7 +40339,7 @@ set this in the opton argument. The following options are listed in the
same order as they appear in the @strong{MyODBC} connect screen:
@multitable @columnfractions .1 .9
-@item @strong{Bit} @tab @strong{Meaning}
+@item @strong{Bit} @tab @strong{Description}
@item 1 @tab The client can't handle that @strong{MyODBC} returns the real width of a column.
@item 2 @tab The client can't handle that MySQL returns the true value of affected rows. If this flag is set then MySQL returns 'found rows' instead. One must have MySQL 3.21.14 or newer to get this to work.
@item 4 @tab Make a debug log in c:\myodbc.log. This is the same as putting @code{MYSQL_DEBUG=d:t:O,c::\myodbc.log} in @file{AUTOEXEC.BAT}
@@ -38623,15 +40348,15 @@ same order as they appear in the @strong{MyODBC} connect screen:
@item 32 @tab Simulate a ODBC 1.0 driver in some context.
@item 64 @tab Ignore use of database name in 'database.table.column'.
@item 128 @tab Force use of ODBC manager cursors (experimental).
-@item 256 @tab Disable the use of extended fetch (experimental)
+@item 256 @tab Disable the use of extended fetch (experimental).
@item 512 @tab Pad CHAR fields to full column length.
@item 1024 @tab SQLDescribeCol() will return fully qualifed column names
@item 2048 @tab Use the compressed server/client protocol
@item 4096 @tab Tell server to ignore space after function name and before @code{'('} (needed by PowerBuilder). This will make all function names keywords!
@item 8192 @tab Connect with named pipes to a @code{mysqld} server running on NT.
-@item 16384 @tab Change LONGLONG columns to INT columns (Some applications can't handle LONGLONG).
+@item 16384 @tab Change LONGLONG columns to INT columns (some applications can't handle LONGLONG).
@item 32768 @tab Return 'user' as Table_qualifier and Table_owner from SQLTables (experimental)
-@item 65536 @tab Read parameters from the @code{client} and @code{odbc} groups from @file{my.cnf}
+@item 65536 @tab Read parameters from the @code{client} and @code{odbc} groups from @file{my.cnf}
@item 131072 @tab Add some extra safety checks (should not bee needed but...)
@end multitable
@@ -38694,7 +40419,7 @@ To make Access work:
@item
If you are using Access 2000, you should get and install the newest
(version 2.6 or above) Microsoft MDAC (@code{Microsoft Data Access
-Components}) from @uref{http://www.microsoft.com/data}. This will fix
+Components}) from @uref{http://www.microsoft.com/data/}. This will fix
the following bug in Access: when you export data to MySQL, the
table and column names aren't specified. Another way to around this bug
is to upgrade to MyODBC Version 2.50.33 and MySQL Version
@@ -38710,19 +40435,37 @@ Note that if you are using MySQL Version 3.22, you must to apply the
MDAC patch and use MyODBC 2.50.32 or 2.50.34 and above to go around
this problem.
@item
-Set the ``Return matching rows'' MyODBC option field when connecting to
-MySQL.
-@item
-You should have a primary key in the table. If not, new or updated rows
-may show up as @code{#Deleted#}.
+For all Access versions, you should enable the MyODBC option flag
+@code{Return matching rows}. For Access 2.0, you should additionally enable
+@code{Simulate ODBC 1.0}.
@item
You should have a timestamp in all tables you want to be able to update.
For maximum portability @code{TIMESTAMP(14)} or simple @code{TIMESTAMP}
is recommended instead of other @code{TIMESTAMP(X)} variations.
@item
-Only use double float fields. Access fails when comparing with single floats.
-The symptom usually is that new or updated rows may show up as @code{#Deleted#}
-or that you can't find or update rows.
+You should have a primary key in the table. If not, new or updated rows
+may show up as @code{#DELETED#}.
+@item
+Only use @code{DOUBLE} float fields. Access fails when comparing with
+single floats. The symptom usually is that new or updated rows may show
+up as @code{#DELETED#} or that you can't find or update rows.
+@item
+If you are linking a table through MyODBC, which has @code{BIGINT} as
+one of the column, then the results will be displayed as @code{#DELETED}. The
+work around solution is:
+@itemize @bullet
+@item
+Have one more dummy column with @code{TIMESTAMP} as the data type, preferably
+@code{TIMESTAMP(14)}.
+@item
+Check the @code{'Change BIGINT columns to INT'} in connection options dialog in
+ODBC DSN Administrator
+@item
+Delete the table link from access and re-create it.
+@end itemize
+
+It still displays the previous records as @code{#DELETED#}, but newly
+added/updated records will be displayed properly.
@item
If you still get the error @code{Another user has changed your data} after
adding a @code{TIMESTAMP} column, the following trick may help you:
@@ -38733,6 +40476,10 @@ set the @code{DefaultValue} property for the @code{TIMESTAMP} column to
@code{NOW()}. It may be a good idea to hide the @code{TIMESTAMP} column
from view so your users are not confused.
@item
+In some cases, Access may generate illegal SQL queries that
+MySQL can't understand. You can fix this by selecting
+@code{"Query|SQLSpecific|Pass-Through"} from the Access menu.
+@item
Access on NT will report @code{BLOB} columns as @code{OLE OBJECTS}. If
you want to have @code{MEMO} columns instead, you should change the
column to @code{TEXT} with @code{ALTER TABLE}.
@@ -38740,19 +40487,9 @@ column to @code{TEXT} with @code{ALTER TABLE}.
Access can't always handle @code{DATE} columns properly. If you have a problem
with these, change the columns to @code{DATETIME}.
@item
-In some cases, Access may generate illegal SQL queries that
-MySQL can't understand. You can fix this by selecting
-@code{"Query|SQLSpecific|Pass-Through"} from the Access menu.
-@item
-If you have in Access a column defined as BYTE, Access will try to export this
-as @code{TINYINT} instead of @code{TINYINT UNSIGNED}. This will give you
-problems if you have values > 127 in the column!
-@item
-If you are using Access 7.0, You should use the option flag @code{Return
-matching rows}.
-@item
-If you are using Access 2.0, You should use the option flags @code{Return
-matching rows} and @code{Simulate ODBC 1.0}.
+If you have in Access a column defined as @code{BYTE}, Access will try
+to export this as @code{TINYINT} instead of @code{TINYINT UNSIGNED}.
+This will give you problems if you have values > 127 in the column!
@end itemize
@cindex ADO program
@@ -38826,7 +40563,7 @@ You have to change it to output @code{VARCHAR} rather than @code{ENUM}, as
it exports the latter in a manner that causes MySQL grief.
@cindex Excel
@item Excel
-Works. Some tips:
+Works. A few tips:
@itemize @bullet
@item
If you have problems with dates, try to select them as strings using the
@@ -38835,7 +40572,7 @@ If you have problems with dates, try to select them as strings using the
select CONCAT(rise_time), CONCAT(set_time)
from sunrise_sunset;
@end example
-Values retrieved as strings this way should be correctly recognized
+Values retrieved as strings this way should be correctly recognised
as time values by Excel97.
The purpose of @code{CONCAT()} in this example is to fool ODBC into thinking
@@ -38895,7 +40632,7 @@ Click OK and you see the rows in your Word document.
Test program for ODBC.
@cindex Delphi program
@item Delphi
-You must use BDE Version 3.2 or newer. Set the `Don't optimize column width'
+You must use BDE Version 3.2 or newer. Set the @code{Don't optimize column width}
option field when connecting to MySQL.
Also, here is some potentially useful Delphi code that sets up both an
@@ -38944,7 +40681,7 @@ fReg:= TRegistry.Create;
@item C++ Builder
Tested with BDE Version 3.0. The only known problem is that when the table
schema changes, query fields are not updated. BDE, however, does not seem
-to recognize primary keys, only the index PRIMARY, though this has not
+to recognise primary keys, only the index PRIMARY, though this has not
been a problem.
@item Vision
@@ -39048,7 +40785,7 @@ send the whole MyODBC or ODBC log file!
If you are unable to find out what's wrong, the last option is to
make an archive (tar or zip) that contains a MyODBC trace file, the ODBC
log file, and a README file that explains the problem. You can send this
-to @uref{ftp://support.mysql.com/pub/mysql/secret}. Only we at
+to @uref{ftp://support.mysql.com/pub/mysql/secret/}. Only we at
MySQL AB will have access to the files you upload, and we will
be very discrete with the data!
@@ -39072,10 +40809,12 @@ likely it is that we can fix the problem!
* C API datatypes:: C API Datatypes
* C API function overview:: C API Function Overview
* C API functions:: C API Function Descriptions
-* C Thread functions::
+* C Thread functions:: C Thread Functions
+* C Embedded Server func:: C Embedded Server Function Descriptions
* C API problems:: Common questions and problems when using the C API
* Building clients:: Building Client Programs
* Threaded clients:: How to Make a Threaded Client
+* libmysqld:: libmysqld, the Embedded MySQL Server Library
@end menu
The C API code is distributed with MySQL. It is included in the
@@ -39115,8 +40854,10 @@ The MySQL server shrinks each communication buffer to
the buffer associated with a connection is not decreased until the connection
is closed, at which time client memory is reclaimed.
-For programming with threads, consult the 'how to make a thread-safe
-client' chapter. @xref{Threaded clients}.
+For programming with threads, see @ref{Threaded clients}.
+For creating a stand-alone application which includes the
+"server" and "client" in the same program (and does not
+communicate with an external MySQL server), see @ref{libmysqld}.
@node C API datatypes, C API function overview, C, C
@@ -39193,7 +40934,7 @@ The type of the field.
The @code{type} value may be one of the following:
@multitable @columnfractions .3 .55
-@item @strong{Type value} @tab @strong{Type meaning}
+@item @strong{Type value} @tab @strong{Type description}
@item @code{FIELD_TYPE_TINY} @tab @code{TINYINT} field
@item @code{FIELD_TYPE_SHORT} @tab @code{SMALLINT} field
@item @code{FIELD_TYPE_LONG} @tab @code{INTEGER} field
@@ -39239,7 +40980,7 @@ Different bit-flags for the field. The @code{flags} value may have zero
or more of the following bits set:
@multitable @columnfractions .3 .55
-@item @strong{Flag value} @tab @strong{Flag meaning}
+@item @strong{Flag value} @tab @strong{Flag description}
@item @code{NOT_NULL_FLAG} @tab Field can't be @code{NULL}
@item @code{PRI_KEY_FLAG} @tab Field is part of a primary key
@item @code{UNIQUE_KEY_FLAG} @tab Field is part of a unique key
@@ -39272,6 +41013,7 @@ You may use the following convenience macros to determine the boolean
status of the @code{flags} value:
@multitable @columnfractions .3 .5
+@item @strong{Flag status} @tab @strong{Description}
@item @code{IS_NOT_NULL(flags)} @tab True if this field is defined as @code{NOT NULL}
@item @code{IS_PRI_KEY(flags)} @tab True if this field is a primary key
@item @code{IS_BLOB(flags)} @tab True if this field is a @code{BLOB} or @code{TEXT} (deprecated; test @code{field->type} instead)
@@ -39293,10 +41035,18 @@ greater detail in the next section.
@xref{C API functions}.
@multitable @columnfractions .3 .7
+@item @strong{Function} @tab @strong{Description}
+
@item @strong{mysql_affected_rows()} @tab
Returns the number of rows changed/deleted/inserted by the last @code{UPDATE},
@code{DELETE}, or @code{INSERT} query.
+@item @strong{mysql_change_user()} @tab
+Changes user and database on an open connection.
+
+@item @strong{mysql_character_set_name()} @tab
+Returns the name of the default character set for the connection.
+
@item @strong{mysql_close()} @tab
Closes a server connection.
@@ -39304,12 +41054,6 @@ Closes a server connection.
Connects to a MySQL server. This function is deprecated; use
@code{mysql_real_connect()} instead.
-@item @strong{mysql_change_user()} @tab
-Changes user and database on an open connection.
-
-@item @strong{mysql_character_set_name()} @tab
-Returns the name of the default character set for the connection.
-
@item @strong{mysql_create_db()} @tab
Creates a database. This function is deprecated; use the SQL command
@code{CREATE DATABASE} instead.
@@ -39338,10 +41082,6 @@ Returns the error number for the most recently invoked MySQL function.
@item @strong{mysql_error()} @tab
Returns the error message for the most recently invoked MySQL function.
-@item @strong{mysql_real_escape_string()} @tab
-Escapes special characters in a string for use in a SQL statement taking
-into account the current charset of the connection.
-
@item @strong{mysql_escape_string()} @tab
Escapes special characters in a string for use in a SQL statement.
@@ -39389,7 +41129,7 @@ Returns the server version number.
Returns information about the most recently executed query.
@item @strong{mysql_init()} @tab
-Gets or initializes a @code{MYSQL} structure.
+Gets or initialises a @code{MYSQL} structure.
@item @strong{mysql_insert_id()} @tab
Returns the ID generated for an @code{AUTO_INCREMENT} column by the previous
@@ -39429,6 +41169,10 @@ Executes a SQL query specified as a null-terminated string.
@item @strong{mysql_real_connect()} @tab
Connects to a MySQL server.
+@item @strong{mysql_real_escape_string()} @tab
+Escapes special characters in a string for use in a SQL statement, taking
+into account the current charset of the connection.
+
@item @strong{mysql_real_query()} @tab
Executes a SQL query specified as a counted string.
@@ -39457,14 +41201,14 @@ Retrieves a complete result set to the client.
@item @strong{mysql_thread_id()} @tab
Returns the current thread ID.
-@item @strong{mysql_thread_save()} @tab
-Returns 1 if the clients are compiled as thread-safe.
+@item @strong{mysql_thread_safe()} @tab
+Returns 1 if the clients are compiled as thread safe.
@item @strong{mysql_use_result()} @tab
Initiates a row-by-row result set retrieval.
@end multitable
-To connect to the server, call @code{mysql_init()} to initialize a
+To connect to the server, call @code{mysql_init()} to initialise a
connection handler, then call @code{mysql_real_connect()} with that
handler (along with other information such as the hostname, user name,
and password). Upon connection, @code{mysql_real_connect()} sets the
@@ -39495,7 +41239,7 @@ retrieve the entire result set all at once by calling
@code{mysql_store_result()}. This function acquires from the server all the
rows returned by the query and stores them in the client. The second way is
for the client to initiate a row-by-row result set retrieval by calling
-@code{mysql_use_result()}. This function initializes the retrieval, but does
+@code{mysql_use_result()}. This function initialises the retrieval, but does
not actually get any rows from the server.
In both cases, you access rows by calling @code{mysql_fetch_row()}. With
@@ -39569,10 +41313,10 @@ when an error occurred and what it was.
@menu
* mysql_affected_rows:: @code{mysql_affected_rows()}
-* mysql_close:: @code{mysql_close()}
-* mysql_connect:: @code{mysql_connect()}
* mysql_change_user:: @code{mysql_change_user()}
* mysql_character_set_name:: @code{mysql_character_set_name()}
+* mysql_close:: @code{mysql_close()}
+* mysql_connect:: @code{mysql_connect()}
* mysql_create_db:: @code{mysql_create_db()}
* mysql_data_seek:: @code{mysql_data_seek()}
* mysql_debug:: @code{mysql_debug()}
@@ -39652,7 +41396,7 @@ A string representation of the error may be obtained by calling
@code{mysql_error()}.
-@node mysql_affected_rows, mysql_close, C API functions, C API functions
+@node mysql_affected_rows, mysql_change_user, C API functions, C API functions
@subsubsection @code{mysql_affected_rows()}
@findex @code{mysql_affected_rows()}
@@ -39699,63 +41443,7 @@ old row. This is because in this case one row was inserted and then the
duplicate was deleted.
-@node mysql_close, mysql_connect, mysql_affected_rows, C API functions
-@subsubsection @code{mysql_close()}
-
-@findex @code{mysql_close()}
-
-@code{void mysql_close(MYSQL *mysql)}
-
-@subsubheading Description
-Closes a previously opened connection. @code{mysql_close()} also deallocates
-the connection handle pointed to by @code{mysql} if the handle was allocated
-automatically by @code{mysql_init()} or @code{mysql_connect()}.
-
-@subsubheading Return Values
-
-None.
-
-@subsubheading Errors
-
-None.
-
-
-@node mysql_connect, mysql_change_user, mysql_close, C API functions
-@subsubsection @code{mysql_connect()}
-
-@findex @code{mysql_connect()}
-
-@code{MYSQL *mysql_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd)}
-
-@subsubheading Description
-
-This function is deprecated. It is preferable to use
-@code{mysql_real_connect()} instead.
-
-@code{mysql_connect()} attempts to establish a connection to a MySQL
-database engine running on @code{host}. @code{mysql_connect()} must complete
-successfully before you can execute any of the other API functions, with the
-exception of @code{mysql_get_client_info()}.
-
-The meanings of the parameters are the same as for the corresponding
-parameters for @code{mysql_real_connect()} with the difference that the
-connection parameter may be @code{NULL}. In this case the C API
-allocates memory for the connection structure automatically and frees it
-when you call @code{mysql_close()}. The disadvantage of this approach is
-that you can't retrieve an error message if the connection fails. (To
-get error information from @code{mysql_errno()} or @code{mysql_error()},
-you must provide a valid @code{MYSQL} pointer.)
-
-@subsubheading Return Values
-
-Same as for @code{mysql_real_connect()}.
-
-@subsubheading Errors
-
-Same as for @code{mysql_real_connect()}.
-
-
-@node mysql_change_user, mysql_character_set_name, mysql_connect, C API functions
+@node mysql_change_user, mysql_character_set_name, mysql_affected_rows, C API functions
@subsubsection @code{mysql_change_user()}
@findex @code{mysql_change_user()}
@@ -39779,7 +41467,7 @@ this case the user and database are not changed
The @code{db} parameter may be set to @code{NULL} if you don't want to have a
default database.
-@subsubheading Return values
+@subsubheading Return Values
Zero for success. Non-zero if an error occurred.
@@ -39819,7 +41507,7 @@ if (mysql_change_user(&mysql, "user", "password", "new_database"))
@end example
-@node mysql_character_set_name, mysql_create_db, mysql_change_user, C API functions
+@node mysql_character_set_name, mysql_close, mysql_change_user, C API functions
@subsubsection @code{mysql_character_set_name()}
@findex @code{mysql_character_set_name()}
@@ -39838,7 +41526,63 @@ The default character set
None.
-@node mysql_create_db, mysql_data_seek, mysql_character_set_name, C API functions
+@node mysql_close, mysql_connect, mysql_character_set_name, C API functions
+@subsubsection @code{mysql_close()}
+
+@findex @code{mysql_close()}
+
+@code{void mysql_close(MYSQL *mysql)}
+
+@subsubheading Description
+Closes a previously opened connection. @code{mysql_close()} also deallocates
+the connection handle pointed to by @code{mysql} if the handle was allocated
+automatically by @code{mysql_init()} or @code{mysql_connect()}.
+
+@subsubheading Return Values
+
+None.
+
+@subsubheading Errors
+
+None.
+
+
+@node mysql_connect, mysql_create_db, mysql_close, C API functions
+@subsubsection @code{mysql_connect()}
+
+@findex @code{mysql_connect()}
+
+@code{MYSQL *mysql_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd)}
+
+@subsubheading Description
+
+This function is deprecated. It is preferable to use
+@code{mysql_real_connect()} instead.
+
+@code{mysql_connect()} attempts to establish a connection to a MySQL
+database engine running on @code{host}. @code{mysql_connect()} must complete
+successfully before you can execute any of the other API functions, with the
+exception of @code{mysql_get_client_info()}.
+
+The meanings of the parameters are the same as for the corresponding
+parameters for @code{mysql_real_connect()} with the difference that the
+connection parameter may be @code{NULL}. In this case the C API
+allocates memory for the connection structure automatically and frees it
+when you call @code{mysql_close()}. The disadvantage of this approach is
+that you can't retrieve an error message if the connection fails. (To
+get error information from @code{mysql_errno()} or @code{mysql_error()},
+you must provide a valid @code{MYSQL} pointer.)
+
+@subsubheading Return Values
+
+Same as for @code{mysql_real_connect()}.
+
+@subsubheading Errors
+
+Same as for @code{mysql_real_connect()}.
+
+
+@node mysql_create_db, mysql_data_seek, mysql_connect, C API functions
@subsubsection @code{mysql_create_db()}
@findex @code{mysql_create_db()}
@@ -39888,7 +41632,7 @@ if(mysql_create_db(&mysql, "my_database"))
@findex @code{mysql_data_seek()}
-@code{void mysql_data_seek(MYSQL_RES *result, unsigned long long offset)}
+@code{void mysql_data_seek(MYSQL_RES *result, my_ulonglong long offset)}
@subsubheading Description
Seeks to an arbitrary row in a query result set. This requires that the
@@ -39912,7 +41656,7 @@ None.
@findex @code{mysql_debug()}
-@code{void mysql_debug(char *debug)}
+@code{void mysql_debug(const char *debug)}
@subsubheading Description
Does a @code{DBUG_PUSH} with the given string. @code{mysql_debug()} uses the
@@ -39989,7 +41733,7 @@ if(mysql_drop_db(&mysql, "my_database"))
Instructs the server to write some debug information to the log. The
connected user must have the @strong{process} privilege for this to work.
-@subsubheading Return values
+@subsubheading Return Values
Zero if the command was successful. Non-zero if an error occurred.
@@ -40023,9 +41767,11 @@ set has been read.
If you acquire a result set from a successful call to
@code{mysql_store_result()}, the client receives the entire set in one
-operation. In this case, a @code{NULL} return from @code{mysql_fetch_row()}
-always means the end of the result set has been reached and it is
-unnecessary to call @code{mysql_eof()}.
+operation. In this case, a @code{NULL} return from
+@code{mysql_fetch_row()} always means the end of the result set has been
+reached and it is unnecessary to call @code{mysql_eof()}. When used
+with @code{mysql_store_result()}, @code{mysql_eof()} will always return
+true.
On the other hand, if you use @code{mysql_use_result()} to initiate a result
set retrieval, the rows of the set are obtained from the server one by one as
@@ -40157,12 +41903,11 @@ None.
You should use @code{mysql_real_escape_string()} instead!
-This is identical to @code{mysql_real_escape_string()} except that it
-takes the connection as the first
-argument. @code{mysql_real_escape_string()} will escape the string
-according to the current character set while
-@code{mysql_escape_string()} does not respect the current charset
-setting.
+This function is identical to @code{mysql_real_escape_string()} except
+that @code{mysql_real_escape_string()} takes a connection handler as
+its first argument and escapes the string according to the current
+character set. @code{mysql_escape_string()} does not take a connection
+argument and does not respect the current charset setting.
@node mysql_fetch_field, mysql_fetch_fields, mysql_escape_string, C API functions
@@ -40298,7 +42043,7 @@ for(i = 0; i < num_fields; i++)
Returns the lengths of the columns of the current row within a result set.
If you plan to copy field values, this length information is also useful for
-optimization, because you can avoid calling @code{strlen()}. In addition, if
+optimisation, because you can avoid calling @code{strlen()}. In addition, if
the result set contains binary data, you @emph{must} use this function to
determine the size of the data, because @code{strlen()} returns incorrect
results for any field containing null characters.
@@ -40482,7 +42227,6 @@ of @code{mysql_field_count()} whether or not the statement was a
@code{MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET offset)}
-* Threaded clients:: How to Make a Threaded Client
@subsubheading Description
Sets the field cursor to the given offset. The next call to
@@ -40671,16 +42415,16 @@ None.
@subsubheading Description
-Allocates or initializes a @code{MYSQL} object suitable for
+Allocates or initialises a @code{MYSQL} object suitable for
@code{mysql_real_connect()}. If @code{mysql} is a @code{NULL} pointer, the
-function allocates, initializes, and returns a new object. Otherwise the
-object is initialized and the address of the object is returned. If
+function allocates, initialises, and returns a new object. Otherwise the
+object is initialised and the address of the object is returned. If
@code{mysql_init()} allocates a new object, it will be freed when
@code{mysql_close()} is called to close the connection.
@subsubheading Return Values
-An initialized @code{MYSQL*} handle. @code{NULL} if there was
+An initialised @code{MYSQL*} handle. @code{NULL} if there was
insufficient memory to allocate a new object.
@subsubheading Errors
@@ -40974,7 +42718,7 @@ else // query succeeded, process any data returned by it
@}
@end example
-An alternative (if you KNOW that your query should have returned a result set)
+An alternative (if you know that your query should have returned a result set)
is to replace the @code{mysql_errno(&mysql)} call with a check if
@code{mysql_field_count(&mysql)} is = 0. This will only happen if something
went wrong.
@@ -41031,6 +42775,7 @@ Possible options values:
@item @strong{Option} @tab @strong{Argument type} @tab @strong{Function}
@item @code{MYSQL_OPT_CONNECT_TIMEOUT} @tab @code{unsigned int *} @tab Connect timeout in seconds.
@item @code{MYSQL_OPT_COMPRESS} @tab Not used @tab Use the compressed client/server protocol.
+@item @code{MYSQL_OPT_LOCAL_INFILE} @tab optional pointer to uint @tab If no pointer is given or if pointer points to an @code{unsigned int != 0} the command @code{LOAD LOCAL INFILE} is enabled.
@item @code{MYSQL_OPT_NAMED_PIPE} @tab Not used @tab Use named pipes to connect to a MySQL server on NT.
@item @code{MYSQL_INIT_COMMAND} @tab @code{char *} @tab Command to execute when connecting to the MySQL server. Will automatically be re-executed when reconnecting.
@item @code{MYSQL_READ_DEFAULT_FILE} @tab @code{char *} @tab Read options from the named option file instead of from @file{my.cnf}.
@@ -41043,19 +42788,21 @@ Note that the group @code{client} is always read if you use
The specified group in the option file may contain the following options:
@multitable @columnfractions .3 .7
+@item @strong{Option} @tab @strong{Description}
@item @code{connect_timeout} @tab Connect timeout in seconds. On Linux this timeout is also used for waiting for the first answer from the server.
@item @code{compress} @tab Use the compressed client/server protocol.
@item @code{database} @tab Connect to this database if no database was specified in the connect command.
@item @code{debug} @tab Debug options.
+@item @code{disable-local-infile} @tab Disable use of @code{LOAD DATA LOCAL}.
@item @code{host} @tab Default host name.
@item @code{init-command} @tab Command to execute when connecting to MySQL server. Will automatically be re-executed when reconnecting.
@item @code{interactive-timeout} @tab Same as specifying @code{CLIENT_INTERACTIVE} to @code{mysql_real_connect()}. @xref{mysql_real_connect}.
+@item @code{local-infile[(=0|1)]} @tab If no argument or argument != 0 then enable use of @code{LOAD DATA LOCAL}.
@item @code{password} @tab Default password.
@item @code{pipe} @tab Use named pipes to connect to a MySQL server on NT.
@item @code{port} @tab Default port number.
@item @code{return-found-rows} @tab Tell @code{mysql_info()} to return found rows instead of updated rows when using @code{UPDATE}.
@item @code{socket} @tab Default socket number.
-@item
@item @code{user} @tab Default user.
@end multitable
@@ -41139,7 +42886,7 @@ query string.)
If you want to know if the query should return a result set or not, you can
use @code{mysql_field_count()} to check for this.
-@xref{mysql_field_count, , @code{mysql_field_count}}.
+@xref{mysql_field_count, , @code{mysql_field_count()}}.
@subsubheading Return Values
@@ -41165,9 +42912,9 @@ An unknown error occurred.
@findex @code{mysql_real_connect()}
@code{MYSQL *mysql_real_connect(MYSQL *mysql, const char *host,
- const char *user, const char *passwd, const char *db,
- unsigned int port, const char *unix_socket,
- unsigned int client_flag)}
+ const char *user, const char *passwd, const char *db,
+ unsigned int port, const char *unix_socket,
+ unsigned int client_flag)}
@subsubheading Description
@@ -41183,9 +42930,9 @@ The parameters are specified as follows:
@item
The first parameter should be the address of an existing @code{MYSQL}
structure. Before calling @code{mysql_real_connect()} you must call
-@code{mysql_init()} to initialize the @code{MYSQL} structure. You can
+@code{mysql_init()} to initialise the @code{MYSQL} structure. You can
change a lot of connect options with the @code{mysql_options()}
-call. @xref{mysql_options}.
+call. @xref{mysql_options, @code{mysql_options()}}.
@item
The value of @code{host} may be either a hostname or an IP address. If
@@ -41232,14 +42979,13 @@ The value of @code{client_flag} is usually 0, but can be set to a combination
of the following flags in very special circumstances:
@multitable @columnfractions .25 .7
-@item @strong{Flag name} @tab @strong{Flag meaning}
-@code{mysqld} to be more ODBC-friendly.
+@item @strong{Flag name} @tab @strong{Flag description}
@item @code{CLIENT_COMPRESS} @tab Use compression protocol.
@item @code{CLIENT_FOUND_ROWS} @tab Return the number of found (matched) rows, not the number of affected rows.
@item @code{CLIENT_IGNORE_SPACE} @tab Allow spaces after function names. Makes all functions names reserved words.
@item @code{CLIENT_INTERACTIVE} @tab Allow @code{interactive_timeout} seconds (instead of @code{wait_timeout} seconds) of inactivity before closing the connection.
@item @code{CLIENT_NO_SCHEMA} @tab Don't allow the @code{db_name.tbl_name.col_name} syntax. This is for ODBC. It causes the parser to generate an error if you use that syntax, which is useful for trapping bugs in some ODBC programs.
-@item @code{CLIENT_ODBC} @tab The client is an ODBC client. This changes
+@item @code{CLIENT_ODBC} @tab The client is an ODBC client. This changes @code{mysqld} to be more ODBC-friendly.
@item @code{CLIENT_SSL} @tab Use SSL (encrypted protocol).
@end multitable
@end itemize
@@ -41401,7 +43147,7 @@ the query string.
If you want to know if the query should return a result set or not, you can
use @code{mysql_field_count()} to check for this.
-@xref{mysql_field_count, @code{mysql_field_count}}.
+@xref{mysql_field_count, @code{mysql_field_count()}}.
@subsubheading Return Values
@@ -41623,16 +43369,16 @@ checking if @code{mysql_store_result()} returns 0 (more about this later one).
If you want to know if the query should return a result set or not, you can
use @code{mysql_field_count()} to check for this.
-@xref{mysql_field_count, @code{mysql_field_count}}.
+@xref{mysql_field_count, @code{mysql_field_count()}}.
@code{mysql_store_result()} reads the entire result of a query to the client,
allocates a @code{MYSQL_RES} structure, and places the result into this
structure.
-@code{mysql_store_results()} returns a null pointer if the query didn't return
+@code{mysql_store_result()} returns a null pointer if the query didn't return
a result set (if the query was, for example, an @code{INSERT} statement).
-@code{mysql_store_results()} also returns a null pointer if reading of the
+@code{mysql_store_result()} also returns a null pointer if reading of the
result set failed. You can check if you got an error by checking if
@code{mysql_error()} doesn't return a null pointer, if
@code{mysql_errno()} returns <> 0, or if @code{mysql_field_count()}
@@ -41763,78 +43509,179 @@ The connection to the server was lost during the query.
An unknown error occurred.
@end table
-@node C Thread functions, C API problems, C API functions, C
+@node C Thread functions, C Embedded Server func, C API functions, C
@subsection C Threaded Function Descriptions
You need to use the following functions when you want to create a
threaded client. @xref{Threaded clients}.
@menu
-* my_init::
-* my_thread_init()::
-* my_thread_end()::
+* my_init:: @code{my_init()}
+* mysql_thread_init:: @code{mysql_thread_init()}
+* mysql_thread_end:: @code{mysql_thread_end()}
@end menu
-@node my_init, my_thread_init(), C Thread functions, C Thread functions
+@node my_init, mysql_thread_init, C Thread functions, C Thread functions
@subsubsection @code{my_init()}
@findex @code{my_init()}
+@code{void my_init(void)}
+
@subsubheading Description
This function needs to be called once in the program before calling any
-MySQL function. This initializes some global variables that MySQL
-needs. If you are using a thread safe client library, this will also
-call @code{my_thread_init()} for this thread.
+MySQL function. This initialises some global variables that MySQL
+needs. If you are using a thread-safe client library, this will also
+call @code{mysql_thread_init()} for this thread.
-This is automatically called by @code{mysql_init()}
-and @code{mysql_connect()}.
+This is automatically called by @code{mysql_init()},
+@code{mysql_server_init()} and @code{mysql_connect()}.
@subsubheading Return Values
-none.
+None.
+
+@node mysql_thread_init, mysql_thread_end, my_init, C Thread functions
+@subsubsection @code{mysql_thread_init()}
-@node my_thread_init(), my_thread_end(), my_init, C Thread functions
-@subsubsection @code{my_thread_init()}
+@findex @code{mysql_thread_init()}
-@findex @code{my_thread_init()}
+@code{my_bool mysql_thread_init(void)}
@subsubheading Description
-This function needs to be called for each created thread to initialize
+This function needs to be called for each created thread to initialise
thread specific variables.
This is automatically called by @code{my_init()} and @code{mysql_connect()}.
@subsubheading Return Values
-none.
+None.
+
+@node mysql_thread_end, , mysql_thread_init, C Thread functions
+@subsubsection @code{mysql_thread_end()}
-@node my_thread_end(), , my_thread_init(), C Thread functions
-@subsubsection @code{my_thread_end()}
+@findex @code{mysql_thread_end()}
-@findex @code{my_thread_end()}
+@code{void mysql_thread_end(void)}
@subsubheading Description
This function needs to be called before calling @code{pthread_exit()} to
-freed memory allocated by @code{my_thread_init()}.
+free memory allocated by @code{mysql_thread_init()}.
+
+Note that this function @strong{is not invoked automatically} by the client
+library. It must be called explicitly to avoid a memory leak.
+
+@subsubheading Return Values
+
+None.
+
+@node C Embedded Server func, C API problems, C Thread functions, C
+@subsection C Embedded Server Function Descriptions
+
+You must use the following functions if you want to allow your
+application to be linked against the embedded MySQL server library.
+@xref{libmysqld}.
+
+If the program is linked with @code{-lmysqlclient} instead of
+@code{-lmysqld}, these functions do nothing. This makes it
+possible to choose between using the embedded MySQL server and
+a stand-alone server without modifying any code.
+
+@menu
+* mysql_server_init:: @code{mysql_server_init()}
+* mysql_server_end:: @code{mysql_server_end()}
+@end menu
+
+@node mysql_server_init, mysql_server_end, C Embedded Server func, C Embedded Server func
+@subsubsection @code{mysql_server_init()}
+
+@findex @code{mysql_server_init()}
+
+@code{int mysql_server_init(int argc, char **argv, char **groups)}
+
+@subsubheading Description
+
+This function @strong{must} be called once in the program before
+calling any other MySQL function. It starts up the server and
+initialises any subsystems (@code{mysys}, InnoDB, etc.) that the
+server uses. If this function is not called, the program will
+crash. If you are using the DBUG package that comes with MySQL,
+you should call this after you have called @code{MY_INIT()}.
+
+The @code{argc} and @code{argv} arguments are analogous to the
+arguments to @code{main()}. The first element of @code{argv}
+is ignored (it typically contains the program name). For
+convenience, @code{argc} may be @code{0} (zero) if there are no
+command-line arguments for the server.
+
+The @code{NULL}-terminated list of strings in @code{groups}
+selects which groups in the option files will be active.
+@xref{Option files}. For convenience, @code{groups} may be
+@code{NULL}, in which case the @code{[server]} and @code{[emedded]} groups
+will be active.
+
+@subsubheading Example
+
+@example
+#include <mysql.h>
+#include <stdlib.h>
+
+static char *server_args[] = @{
+ "this_program", /* this string is not used */
+ "--datadir=.",
+ "--set-variable=key_buffer_size=32M"
+@};
+static char *server_groups[] = @{
+ "embedded",
+ "server",
+ "this_program_SERVER",
+ (char *)NULL
+@};
+
+int main(void) @{
+ mysql_server_init(sizeof(server_args) / sizeof(char *),
+ server_args, server_groups);
+
+ /* Use any MySQL API functions here */
+
+ mysql_server_end();
+
+ return EXIT_SUCCESS;
+@}
+@end example
+
+@subsubheading Return Values
+
+0 if okay, 1 if an error occurred.
+
+@node mysql_server_end, , mysql_server_init, C Embedded Server func
+@subsubsection @code{mysql_server_end()}
+
+@findex @code{mysql_server_end()}
+
+@code{void mysql_server_end(void)}
+
+@subsubheading Description
-Note that this function is NOT invoked automatically by the client
-library!
+This function @strong{must} be called once in the program after
+all other MySQL functions. It shuts down the embedded server.
@subsubheading Return Values
-none.
+None.
-@node C API problems, Building clients, C Thread functions, C
+@node C API problems, Building clients, C Embedded Server func, C
@subsection Common questions and problems when using the C API
@tindex @code{mysql_query()}
@tindex @code{mysql_store_result()}
@menu
-* NULL mysql_store_result:: Why Is It that After @code{mysql_query()} Returns Success, @code{mysql_store_result()} Sometimes Returns @code{NULL?}
+* NULL mysql_store_result:: Why Is It that After @code{mysql_query()} Returns Success, @code{mysql_store_result()} Sometimes Returns @code{NULL}?
* Query results:: What Results Can I Get From a Query?
* Getting unique ID:: How Can I Get the Unique ID for the Last Inserted Row?
* C API linking problems:: Problems Linking with the C API
@@ -41842,7 +43689,7 @@ none.
@node NULL mysql_store_result, Query results, C API problems, C API problems
-@subsubsection Why Is It that After @code{mysql_query()} Returns Success, @code{mysql_store_result()} Sometimes Returns @code{NULL?}
+@subsubsection Why Is It that After @code{mysql_query()} Returns Success, @code{mysql_store_result()} Sometimes Returns @code{NULL}?
It is possible for @code{mysql_store_result()} to return @code{NULL}
following a successful call to @code{mysql_query()}. When this happens, it
@@ -41873,14 +43720,6 @@ example.
You can test for an error by calling @code{mysql_error()} or
@code{mysql_errno()}.
-@cindex queries, C API results
-@menu
-* Query results:: What Results Can I Get From a Query?
-* Getting unique ID:: How Can I Get the Unique ID for the Last Inserted Row?
-* C API linking problems:: Problems Linking with the C API
-@end menu
-
-
@node Query results, Getting unique ID, NULL mysql_store_result, C API problems
@subsubsection What Results Can I Get From a Query?
@@ -42003,7 +43842,7 @@ For clients that use MySQL header files, you may need to specify a
files.
-@node Threaded clients, , Building clients, C
+@node Threaded clients, libmysqld, Building clients, C
@subsection How to Make a Threaded Client
@cindex clients, threaded
@@ -42016,11 +43855,11 @@ have your own alarm that can break a long read to a server. If you
install interrupt handlers for the @code{SIGPIPE} interrupt,
the socket handling should be thread safe.
-In the older binaries we distribute on our Web site, the client
-libraries are not normally compiled with the thread-safe option (the
-Windows binaries are by default compiled to be thread safe).
-Newer binary distributions should have both a normal and a
-thread-safe client library.
+In the older binaries we distribute on our web site
+(@uref{http://www.mysql.com/}), the client libraries are not normally
+compiled with the thread-safe option (the Windows binaries are by
+default compiled to be thread safe). Newer binary distributions should
+have both a normal and a thread-safe client library.
To get a threaded client where you can interrupt the client from other
threads and set timeouts when talking with the MySQL server, you should
@@ -42039,7 +43878,7 @@ interrupts, you can make great use of the routines in the
@code{my_init()} first! @xref{C Thread functions}.
All functions except @code{mysql_real_connect()} are by default
-thread safe. The following notes describe how to compile a thread safe
+thread safe. The following notes describe how to compile a thread-safe
client library and use it in a thread-safe manner. (The notes below for
@code{mysql_real_connect()} actually apply to @code{mysql_connect()} as
well, but because @code{mysql_connect()} is deprecated, you should be
@@ -42054,12 +43893,12 @@ shell> ./configure --enable-thread-safe-client
This will create a thread-safe client library @code{libmysqlclient_r}.
@code{--enable-thread-safe-client}. This library is thread safe per
-connection. You can let two threads share the same connection as long
-as you do the following:
+connection. You can let two threads share the same connection with
+the following caveats:
@itemize @bullet
@item
-Two threads can't send a query to the MySQL at the same time on
+Two threads can't send a query to the MySQL server at the same time on
the same connection. In particular, you have to ensure that between a
@code{mysql_query()} and @code{mysql_store_result()} no other thread is using
the same connection.
@@ -42068,9 +43907,9 @@ Many threads can access different result sets that are retrieved with
@code{mysql_store_result()}.
@item
If you use @code{mysql_use_result}, you have to ensure that no other thread
-is asking anything on the same connection until the result set is closed.
+is using the same connection until the result set is closed.
However, it really is best for threaded clients that share the same
-connection to use @code{mysql_use_result()}.
+connection to use @code{mysql_store_result()}.
@item
If you want to use multiple threads on the same connection, you must
have a mutex lock around your @code{mysql_query()} and
@@ -42084,18 +43923,18 @@ establish and release a mutex lock.
@end itemize
You need to know the following if you have a thread that is calling
-MySQL functions, but that thread has not created the connection to the
+MySQL functions which did not create the connection to the
MySQL database:
When you call @code{mysql_init()} or @code{mysql_connect()}, MySQL will
create a thread specific variable for the thread that is used by the
debug library (among other things).
-If you have in a thread call a MySQL function, before a thread has
+If you call a MySQL function, before the thread has
called @code{mysql_init()} or @code{mysql_connect()}, the thread will
not have the necessary thread specific variables in place and you are
likely to end up with a core dump sooner or later.
-
+
The get things to work smoothly you have to do the following:
@enumerate
@@ -42103,18 +43942,350 @@ The get things to work smoothly you have to do the following:
Call @code{my_init()} at the start of your program if it calls
any other MySQL function before calling @code{mysql_real_connect()}.
@item
-Call @code{my_thread_init()} in the thread handler before calling
+Call @code{mysql_thread_init()} in the thread handler before calling
any MySQL function.
@item
-In the thread, call @code{my_thread_end()} before calling
+In the thread, call @code{mysql_thread_end()} before calling
@code{pthread_exit()}. This will free the memory used by MySQL thread
specific variables.
@end enumerate
You may get some errors because of undefined symbols when linking your
-client with @code{mysqlclient_r}. In most cases this is because you haven't
+client with @code{libmysqlclient_r}. In most cases this is because you haven't
included the thread libraries on the link/compile line.
+@node libmysqld, , Threaded clients, C
+@subsection libmysqld, the Embedded MySQL Server Library
+
+@cindex libmysqld
+@cindex embedded MySQL server library
+
+@menu
+* libmysqld overview:: Overview of the Embedded MySQL Server Library
+* libmysqld compiling:: Compiling Programs with @code{libmysqld}
+* libmysqld restrictions:: Restrictions when Using the Embedded MySQL Server
+* libmysqld options:: Using Option Files with the Embedded Server
+* libmysqld TODO:: Things left to do in Embedded Server (TODO)
+* libmysqld example:: A Simple Embedded Server Example
+* libmysqld licensing:: Licensing the Embedded Server
+@end menu
+
+@node libmysqld overview, libmysqld compiling, libmysqld, libmysqld
+@subsubsection Overview of the Embedded MySQL Server Library
+
+The embedded MySQL server library makes it possible to run a
+full-featured MySQL server inside the client application. The
+main benefits are increased speed and more simple management for
+embedded applications.
+
+The API is identical for the embedded MySQL version and the
+client/server version. To change an old threaded application to use the
+embedded library, you normally only have to add calls to the following
+functions:
+
+@multitable @columnfractions .25 .7
+@item @strong{Function} @tab @strong{When to call}
+@item @code{mysql_server_init()} @tab Should be called before any other other MySQL function is called, preferably early in the @code{main()} function.
+@item @code{mysql_server_end()} @tab Should be called before your program exits.
+@item @code{mysql_thread_init()} @tab Should be called in each thread you create that will access MySQL.
+@item @code{mysql_thread_end()} @tab Should be called before calling @code{pthread_exit()}
+@end multitable
+
+Then you must link your code with @code{libmysqld.a} instead of @code{libmysqlclient.a}.
+
+The above @code{mysql_server_xxx} functions are also included in
+@code{libmysqlclient.a} to allow you to change between the embedded and the
+client/server version by just linking your application with the right
+library. @xref{mysql_server_init}.
+
+
+@node libmysqld compiling, libmysqld restrictions, libmysqld overview, libmysqld
+@subsubsection Compiling Programs with @code{libmysqld}
+
+To get a @code{libmysqld} library you should configure MySQL with the
+@code{--with-embedded-server} option.
+
+When you link your program with @code{libmysqld}, you must also include
+the system-specific @code{pthread} libraries and some libraries that
+the MySQL server uses. You can get the full list of libraries by executing
+@code{mysql_config --libmysqld-libs}.
+
+The correct flags for compiling and linking a threaded program
+must be used, even if you do not directly call any thread
+functions in your code.
+
+@node libmysqld restrictions, libmysqld options, libmysqld compiling, libmysqld
+@subsubsection Restrictions when using the Embedded MySQL Server
+
+The embedded server has the following limitations:
+
+@itemize @bullet
+@item
+No support for ISAM tables. (This is mainly done to make the library smaller)
+@item
+No UDF functions.
+@item
+No stack trace on core dump.
+@item
+No internal RAID support. (This is not normally needed as most OS has
+nowadays support for big files).
+@item
+You can set this up as a server or a master (no replication).
+@item
+You can't connect to the embedded server from an outside process with
+sockets or TCP/IP.
+@end itemize
+
+Some of these limitations can be changed by editing the @file{mysql_embed.h}
+include file and recompiling MySQL.
+
+@node libmysqld options, libmysqld TODO, libmysqld restrictions, libmysqld
+@subsubsection Using Option Files with the Embedded Server
+
+@cindex defaults, embedded
+
+The following is the recommended way to use option files to make it easy
+to switch between a client/server application and one where MySQL is
+embedded. @xref{Option files}.
+
+@itemize @bullet
+@item
+Put common options in the @code{[server]} section. These will be read by
+both MySQL versions.
+@item
+Put client/server specific options in the @code{[mysqld]} section.
+@item
+Put embedded MySQL specific options in the @code{[embedded]} section.
+@item
+Put application specific options in a @code{[ApplicationName_SERVER]}
+section.
+@end itemize
+
+@node libmysqld TODO, libmysqld example, libmysqld options, libmysqld
+@subsubsection Things left to do in Embedded Server (TODO)
+
+@cindex TODO, embedded server
+
+@itemize @bullet
+@item
+Currently we only provide a static version of the @code{mysqld} library,
+in the future we will also provide a shared library for this.
+@item
+We are going to provide options to leave out some parts of MySQL to make
+the library smaller.
+@item
+There is still a lot of speed optimisation to do.
+@item
+Errors are written to stderr. We will add an option to specify a
+filename for these.
+@item
+We have to change InnoDB to not be so verbose when using in the embedded
+version.
+@end itemize
+
+
+@node libmysqld example, libmysqld licensing, libmysqld TODO, libmysqld
+@subsubsection A Simple Embedded Server Example
+
+This example program and makefile should work without any
+changes on a Linux or FreeBSD system. For other operating
+systems, minor changes will be needed. This example is
+designed to give enough details to understand the problem,
+without the clutter that is a necessary part of a real
+application.
+
+To try out the example, create an @file{test_libmysqld} directory
+at the same level as the mysql-4.0 source directory. Save
+the @file{test_libmysqld.c} source and the @file{GNUmakefile} in the
+directory, and run GNU @file{make} from inside the @file{test_libmysqld}
+directory.
+
+@file{test_libmysqld.c}
+@example
+/*
+ * A simple example client, using the embedded MySQL server library
+ */
+
+#include <mysql.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+MYSQL *db_connect(const char *dbname);
+void db_disconnect(MYSQL *db);
+void db_do_query(MYSQL *db, const char *query);
+
+const char *server_groups[] = @{
+ "test_libmysqld_SERVER", "embedded", "server", NULL
+@};
+
+int
+main(int argc, char **argv)
+@{
+ MYSQL *one, *two;
+
+ /* mysql_server_init() must be called before any other mysql
+ * functions.
+ *
+ * You can use mysql_server_init(0, NULL, NULL), and it will
+ * initialise the server using groups = @{
+ * "server", "embedded", NULL
+ * @}.
+ *
+ * In your $HOME/.my.cnf file, you probably want to put:
+
+[test_libmysqld_SERVER]
+language = /path/to/source/of/mysql/sql/share/english
+
+ * You could, of course, modify argc and argv before passing
+ * them to this function. Or you could create new ones in any
+ * way you like. But all of the arguments in argv (except for
+ * argv[0], which is the program name) should be valid options
+ * for the MySQL server.
+ *
+ * If you link this client against the normal mysqlclient
+ * library, this function is just a stub that does nothing.
+ */
+ mysql_server_init(argc, argv, (char **)server_groups);
+
+ one = db_connect("test");
+ two = db_connect(NULL);
+
+ db_do_query(one, "show table status");
+ db_do_query(two, "show databases");
+
+ mysql_close(two);
+ mysql_close(one);
+
+ /* This must be called after all other mysql functions */
+ mysql_server_end();
+
+ exit(EXIT_SUCCESS);
+@}
+
+static void
+die(MYSQL *db, char *fmt, ...)
+@{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ (void)putc('\n', stderr);
+ if (db)
+ db_disconnect(db);
+ exit(EXIT_FAILURE);
+@}
+
+MYSQL *
+db_connect(const char *dbname)
+@{
+ MYSQL *db = mysql_init(NULL);
+ if (!db)
+ die(db, "mysql_init failed: no memory");
+ /*
+ * Notice that the client and server use separate group names.
+ * This is critical, because the server will not accept the
+ * client's options, and vice versa.
+ */
+ mysql_options(db, MYSQL_READ_DEFAULT_GROUP, "test_libmysqld_CLIENT");
+ if (!mysql_real_connect(db, NULL, NULL, NULL, dbname, 0, NULL, 0))
+ die(db, "mysql_real_connect failed: %s", mysql_error(db));
+
+ return db;
+@}
+
+void
+db_disconnect(MYSQL *db)
+@{
+ mysql_close(db);
+@}
+
+void
+db_do_query(MYSQL *db, const char *query)
+@{
+ if (mysql_query(db, query) != 0)
+ goto err;
+
+ if (mysql_field_count(db) > 0)
+ @{
+ MYSQL_RES *res;
+ MYSQL_ROW row, end_row;
+ int num_fields;
+
+ if (!(res = mysql_store_result(db)))
+ goto err;
+ num_fields = mysql_num_fields(res);
+ while ((row = mysql_fetch_row(res)))
+ @{
+ (void)fputs(">> ", stdout);
+ for (end_row = row + num_fields; row < end_row; ++row)
+ (void)printf("%s\t", row ? (char*)*row : "NULL");
+ (void)fputc('\n', stdout);
+ @}
+ (void)fputc('\n', stdout);
+ @}
+ else
+ (void)printf("Affected rows: %lld\n", mysql_affected_rows(db));
+
+ return;
+
+err:
+ die(db, "db_do_query failed: %s [%s]", mysql_error(db), query);
+@}
+@end example
+
+@file{GNUmakefile}
+@example
+# This assumes the MySQL software is installed in /usr/local/mysql
+inc := /usr/local/mysql/include/mysql
+lib := /usr/local/mysql/lib
+
+# If you have not installed the MySQL software yet, try this instead
+#inc := $(HOME)/mysql-4.0/include
+#lib := $(HOME)/mysql-4.0/libmysqld
+
+CC := gcc
+CPPFLAGS := -I$(inc) -D_THREAD_SAFE -D_REENTRANT
+CFLAGS := -g -W -Wall
+LDFLAGS := -static
+# You can change -lmysqld to -lmysqlclient to use the
+# client/server library
+LDLIBS = -L$(lib) -lmysqld -lz -lm -lcrypt
+
+ifneq (,$(shell grep FreeBSD /COPYRIGHT 2>/dev/null))
+# FreeBSD
+LDFLAGS += -pthread
+else
+# Assume Linux
+LDLIBS += -lpthread
+endif
+
+# This works for simple one-file test programs
+sources := $(wildcard *.c)
+objects := $(patsubst %c,%o,$(sources))
+targets := $(basename $(sources))
+
+all: $(targets)
+
+clean:
+ rm -f $(targets) $(objects) *.core
+@end example
+
+@node libmysqld licensing, , libmysqld example, libmysqld
+@subsubsection Licensing the Embedded Server
+
+The MySQL source code is covered by the GNU GPL license
+(@pxref{GPL license}). One result of this is that any program
+which includes, by linking with @code{libmysqld}, the MySQL
+source code must be released as free software (under a license
+compatible with the GPL).
+
+We encourage everyone to promote free software by releasing
+code under the GPL or a compatible license. For those who
+are not able to do this, another option is to purchase the
+MySQL code from MySQL AB under a looser license. For details
+concerning this issue, please see @ref{MySQL server licenses}.
+
@node Cplusplus, Java, C, Clients
@section MySQL C++ APIs
@@ -42125,8 +44296,8 @@ included the thread libraries on the link/compile line.
@cindex C++ APIs
-Two APIs are available in the MySQL
-@uref{http://www.mysql.com/Downloads/Contrib/,Contrib directory}.
+Two APIs are available in the MySQL Contrib directory
+(@uref{http://www.mysql.com/Downloads/Contrib/}).
@node Borland C++, , Cplusplus, Cplusplus
@@ -42136,7 +44307,7 @@ Two APIs are available in the MySQL
You can compile the MySQL Windows source with Borland C++ 5.02.
(The Windows source includes only projects for Microsoft VC++, for
-Borland C++ you have to do the project files yourself).
+Borland C++ you have to do the project files yourself.)
One known problem with Borland C++ is that it uses a different structure
alignment than VC++. This means that you will run into problems if you
@@ -42174,22 +44345,19 @@ documentation for MySQL-specific features.
@cindex Python APIs
-The MySQL @uref{http://www.mysql.com/Downloads/Contrib/,Contrib directory}
+The MySQL Contrib directory
+(@uref{http://www.mysql.com/Downloads/Contrib/})
contains a Python interface written by Joseph Skinner.
-You can also use the Python interface to iODBC to access a
-MySQL server.
-@uref{http://starship.skyport.net/~lemburg/,mxODBC}
-
@node Tcl, Eiffel, Python, Clients
@section MySQL Tcl APIs
@cindex Tcl APIs
-@uref{http://www.binevolve.com/~tdarugar/tcl-sql/, Tcl at binevolve}.
-The
-@uref{http://www.mysql.com/Downloads/Contrib,Contrib directory} contains a Tcl
+@uref{http://www.binevolve.com/~tdarugar/tcl-sql/} (Tcl at binevolve).
+The Contrib directory
+(@uref{http://www.mysql.com/Downloads/Contrib/}) contains a Tcl
interface that is based on msqltcl 1.50.
@@ -42199,26 +44367,310 @@ interface that is based on msqltcl 1.50.
@cindex Eiffel Wrapper
@cindex wrappers, Eiffel
-The MySQL @uref{http://www.mysql.com/Downloads/Contrib/,Contrib directory}
+The MySQL Contrib directory
+(@uref{http://www.mysql.com/Downloads/Contrib/})
contains an Eiffel wrapper written by Michael Ravits.
-You can also find this at:
-@url{http://www.netpedia.net/hosting/newplayer/}
-
-
-
@node Extending MySQL, Problems, Clients, Top
@chapter Extending MySQL
@menu
+* MySQL internals:: MySQL Internals
* Adding functions:: Adding New Functions to MySQL
* Adding procedures:: Adding New Procedures to MySQL
-* MySQL internals:: MySQL Internals
@end menu
-@node Adding functions, Adding procedures, Extending MySQL, Extending MySQL
+@node MySQL internals, Adding functions, Extending MySQL, Extending MySQL
+@section MySQL Internals
+
+@cindex internals
+@cindex threads
+
+This chapter describes a lot of things that you need to know when
+working on the MySQL code. If you plan to contribute to MySQL
+development, want to have access to the bleeding-edge in-between
+versions code, or just want to keep track of development, follow the
+instructions in @ref{Installing source tree}.
+If you are interested in MySQL internals, you should also subscribe
+to our @code{internals} mailing list. This list is relatively low
+traffic. For details on how to subscribe, please see
+@ref{Mailing-list}.
+All developers at MySQL AB are on the @code{internals} list and we
+help other people who are working on the MySQL code. Feel free to
+use this list both to ask questions about the code and to send
+patches that you would like to contribute to the MySQL project!
+
+@menu
+* MySQL threads:: MySQL threads
+* MySQL test suite:: MySQL test suite
+@end menu
+
+
+@node MySQL threads, MySQL test suite, MySQL internals, MySQL internals
+@subsection MySQL Threads
+
+The MySQL server creates the following threads:
+
+@itemize @bullet
+
+@item
+The TCP/IP connection thread handles all connection requests and
+creates a new dedicated thread to handle the authentication and
+and SQL query processing for each connection.
+
+@item
+On Windows NT there is a named pipe handler thread that does the same work as
+the TCP/IP connection thread on named pipe connect requests.
+
+@item
+The signal thread handles all signals. This thread also normally handles
+alarms and calls @code{process_alarm()} to force timeouts on connections
+that have been idle too long.
+
+@item
+If @code{mysqld} is compiled with @code{-DUSE_ALARM_THREAD}, a dedicated
+thread that handles alarms is created. This is only used on some systems where
+there are problems with @code{sigwait()} or if one wants to use the
+@code{thr_alarm()} code in ones application without a dedicated signal
+handling thread.
+
+@item
+If one uses the @code{--flush_time=#} option, a dedicated thread is created
+to flush all tables at the given interval.
+
+@item
+Every connection has its own thread.
+
+@item
+Every different table on which one uses @code{INSERT DELAYED} gets its
+own thread.
+
+@item
+If you use @code{--master-host}, a slave replication thread will be
+started to read and apply updates from the master.
+@end itemize
+
+@code{mysqladmin processlist} only shows the connection, @code{INSERT DELAYED},
+and replication threads.
+
+
+@node MySQL test suite, , MySQL threads, MySQL internals
+@subsection MySQL Test Suite
+
+@cindex mysqltest, MySQL Test Suite
+@cindex testing mysqld, mysqltest
+
+Until recently, our main full-coverage test suite was based on proprietary
+customer data and for that reason has not been publicly available. The only
+publicly available part of our testing process consisted of the @code{crash-me}
+test, a Perl DBI/DBD benchmark found in the @code{sql-bench} directory, and
+miscellaneous tests located in @code{tests} directory. The lack of a
+standardised publicly available test suite has made it difficult for our users,
+as well developers, to do regression tests on the MySQL code. To
+address this problem, we have created a new test system that is included in
+the source and binary distributions starting in Version 3.23.29.
+
+The current set of test cases doesn't test everything in MySQL, but it
+should catch most obvious bugs in the SQL processing code, OS/library
+issues, and is quite thorough in testing replication. Our eventual goal
+is to have the tests cover 100% of the code. We welcome contributions
+to our test suite. You may especially want to contribute tests that
+examine the functionality critical to your system, as this will ensure
+that all future MySQL releases will work well with your
+applications.
+
+@menu
+* running mysqltest:: Running the MySQL Test Suite
+* extending mysqltest:: Extending the MySQL Test Suite
+* Reporting mysqltest bugs:: Reporting Bugs in the MySQL Test Suite
+@end menu
+
+
+@node running mysqltest, extending mysqltest, MySQL test suite, MySQL test suite
+@subsubsection Running the MySQL Test Suite
+
+The test system consist of a test language interpreter
+(@code{mysqltest}), a shell script to run all
+tests(@code{mysql-test-run}), the actual test cases written in a special
+test language, and their expected results. To run the test suite on
+your system after a build, type @code{make test} or
+@code{mysql-test/mysql-test-run} from the source root. If you have
+installed a binary distribution, @code{cd} to the install root
+(eg. @code{/usr/local/mysql}), and do @code{scripts/mysql-test-run}.
+All tests should succeed. If not, you should try to find out why and
+report the problem if this is a bug in MySQL.
+@xref{Reporting mysqltest bugs}.
+
+If you have a copy of @code{mysqld} running on the machine where you want to
+run the test suite you do not have to stop it, as long as it is not using
+ports @code{9306} and @code{9307}. If one of those ports is taken, you should
+edit @code{mysql-test-run} and change the values of the master and/or slave
+port to one that is available.
+
+You can run one individual test case with
+@code{mysql-test/mysql-test-run test_name}.
+
+If one test fails, you should test running @code{mysql-test-run} with
+the @code{--force} option to check if any other tests fails.
+
+
+@node extending mysqltest, Reporting mysqltest bugs, running mysqltest, MySQL test suite
+@subsubsection Extending the MySQL Test Suite
+
+You can use the @code{mysqltest} language to write your own test cases.
+Unfortunately, we have not yet written full documentation for it - we plan to
+do this shortly. You can, however, look at our current test cases and use
+them as an example. The following points should help you get started:
+
+@itemize @bullet
+@item
+The tests are located in @code{mysql-test/t/*.test}
+
+@item
+A test case consists of @code{;} terminated statements and is similar to the
+input of @code{mysql} command line client. A statement by default is a query
+to be sent to MySQL server, unless it is recognised as internal
+command (eg. @code{sleep}).
+
+@item
+All queries that produce results, e.g. @code{SELECT}, @code{SHOW},
+@code{EXPLAIN}, etc., must be preceded with @code{@@/path/to/result/file}. The
+file must contain the expected results. An easy way to generate the result
+file is to run @code{mysqltest -r < t/test-case-name.test} from
+@code{mysql-test} directory, and then edit the generated result files, if
+needed, to adjust them to the expected output. In that case, be very careful
+about not adding or deleting any invisible characters - make sure to only
+change the text and/or delete lines. If you have to insert a line, make sure
+the fields are separated with a hard tab, and there is a hard tab at the end.
+You may want to use @code{od -c} to make sure your text editor has not messed
+anything up during edit. We, of course, hope that you will never have to edit
+the output of @code{mysqltest -r} as you only have to do it when you find a
+bug.
+
+@item
+To be consistent with our setup, you should put your result files in
+@code{mysql-test/r} directory and name them @code{test_name.result}. If the
+test produces more than one result, you should use @code{test_name.a.result},
+@code{test_name.b.result}, etc.
+
+@item
+If a statement returns an error, you should on the line before the statement
+specify with the @code{--error error-number}. The error number can be
+a list of possible error numbers separated with @code{','}.
+
+@item
+If you are writing a replication test case, you should on the first line of
+the test file, put @code{source include/master-slave.inc;}. To switch between
+master and slave, use @code{connection master;} and @code{connection slave;}.
+If you need to do something on an alternate connection, you can do
+@code{connection master1;} for the master, and @code{connection slave1;} for
+the slave.
+
+@item
+If you need to do something in a loop, you can use something like this:
+@example
+let $1=1000;
+while ($1)
+@{
+ # do your queries here
+ dec $1;
+@}
+@end example
+
+@item
+To sleep between queries, use the @code{sleep} command. It supports fractions
+of a second, so you can do @code{sleep 1.3;}, for example, to sleep 1.3
+seconds.
+
+@item
+To run the slave with additional options for your test case, put them
+in the command-line format in @code{mysql-test/t/test_name-slave.opt}. For
+the master, put them in @code{mysql-test/t/test_name-master.opt}.
+
+@item
+If you have a question about the test suite, or have a test case to contribute,
+e-mail to @email{internals@@lists.mysql.com}. As the list does not accept
+attachments, you should ftp all the relevant files to:
+@uref{ftp://support.mysql.com/pub/mysql/Incoming/}
+
+@end itemize
+
+
+@node Reporting mysqltest bugs, , extending mysqltest, MySQL test suite
+@subsubsection Reporting Bugs in the MySQL Test Suite
+
+If your MySQL version doesn't pass the test suite you should
+do the following:
+
+@itemize @bullet
+@item
+Don't send a bug report before you have found out as much as possible of
+what when wrong! When you do it, please use the @code{mysqlbug} script
+so that we can get information about your system and @code{MySQL}
+version. @xref{Bug reports}.
+@item
+Make sure to include the output of @code{mysql-test-run}, as well as
+contents of all @code{.reject} files in @code{mysql-test/r} directory.
+@item
+If a test in the test suite fails, check if the test fails also when run
+by its own:
+
+@example
+cd mysql-test
+mysql-test-run --local test-name
+@end example
+
+If this fails, then you should configure MySQL with
+@code{--with-debug} and run @code{mysql-test-run} with the
+@code{--debug} option. If this also fails send the trace file
+@file{var/tmp/master.trace} to ftp://support.mysql.com/pub/mysql/secret
+so that we can examine it. Please remember to also include a full
+description of your system, the version of the mysqld binary and how you
+compiled it.
+
+@item
+Try also to run @code{mysql-test-run} with the @code{--force} option to
+see if there is any other test that fails.
+
+@item
+If you have compiled MySQL yourself, check our manual for how
+to compile MySQL on your platform or, preferable, use one of
+the binaries we have compiled for you at
+@uref{http://www.mysql.com/downloads/}. All our standard binaries should
+pass the test suite !
+
+@item
+If you get an error, like @code{Result length mismatch} or @code{Result
+content mismatch} it means that the output of the test didn't match
+exactly the expected output. This could be a bug in MySQL or
+that your mysqld version produces slight different results under some
+circumstances.
+
+Failed test results are put in a file with the same base name as the
+result file with the @code{.reject} extension. If your test case is
+failing, you should do a diff on the two files. If you cannot see how
+they are different, examine both with @code{od -c} and also check their
+lengths.
+
+@item
+If a test fails totally, you should check the logs file in the
+@code{mysql-test/var/log} directory for hints of what went wrong.
+
+@item
+If you have compiled MySQL with debugging you can try to debug this
+by running @code{mysql-test-run} with the @code{--gdb} and/or @code{--debug}
+options.
+@xref{Making trace files}.
+
+If you have not compiled MySQL for debugging you should probably
+do that. Just specify the @code{--with-debug} options to @code{configure}!
+@xref{Installing source}.
+@end itemize
+
+
+@node Adding functions, Adding procedures, MySQL internals, Extending MySQL
@section Adding New Functions to MySQL
@cindex functions, new
@@ -42297,7 +44749,7 @@ to create and drop functions.
All active functions are reloaded each time the server starts, unless
you start @code{mysqld} with the @code{--skip-grant-tables} option. In
-this case, UDF initialization is skipped and UDFs are unavailable.
+this case, UDF initialisation is skipped and UDFs are unavailable.
(An active function is one that has been loaded with @code{CREATE FUNCTION}
and not removed with @code{DROP FUNCTION}.)
@@ -42306,6 +44758,10 @@ functions}. For the UDF mechanism to work, functions must be written in C or
C++, your operating system must support dynamic loading and you must have
compiled @code{mysqld} dynamically (not statically).
+Note that to make @code{AGGREGATE} work, you must have a
+@code{mysql.func} table that contains the column @code{type}. If this
+is not the case, you should run the script
+@code{mysql_fix_privilege_tables} to get this fixed.
@node Adding UDF, Adding native function, CREATE FUNCTION, Adding functions
@@ -42316,10 +44772,11 @@ compiled @code{mysqld} dynamically (not statically).
@cindex functions, user-definable, adding
@menu
-* UDF calling sequences:: UDF calling sequences
-* UDF arguments:: Argument processing
-* UDF return values:: Return values and error handling
-* UDF compiling:: Compiling and installing user-definable functions
+* UDF calling:: UDF Calling Sequences
+* UDF aggr. calling :: UDF Calling Sequences for aggregate functions
+* UDF arguments:: Argument Processing
+* UDF return values:: Return Values and Error Handling
+* UDF compiling:: Compiling and Installing User-definable Functions
@end menu
@@ -42336,7 +44793,7 @@ you are using @code{--with-mysqld-ldflags=-all-static} If you want to
use an UDF that needs to access symbols from @code{mysqld} (like the
@code{methaphone} example in @file{sql/udf_example.cc} that uses
@code{default_charset_info}), you must link the program with
-@code{-rdynamic}. (see @code{man dlopen}).
+@code{-rdynamic} (see @code{man dlopen}).
For each function that you want to use in SQL statements, you should define
corresponding C (or C++) functions. In the discussion below, the name
@@ -42361,7 +44818,7 @@ function is shown below:
@end multitable
@item @code{xxx_init()} (optional)
-The initialization function for @code{xxx()}. It can be used to:
+The initialisation function for @code{xxx()}. It can be used to:
@itemize @bullet
@item
@@ -42381,30 +44838,62 @@ Specify whether or not the result can be @code{NULL}.
@end itemize
@item @code{xxx_deinit()} (optional)
-The deinitialization function for @code{xxx()}. It should deallocate any
-memory allocated by the initialization function.
+The deinitialisation function for @code{xxx()}. It should deallocate any
+memory allocated by the initialisation function.
@end table
When a SQL statement invokes @code{XXX()}, MySQL calls the
-initialization function @code{xxx_init()} to let it perform any required
+initialisation function @code{xxx_init()} to let it perform any required
setup, such as argument checking or memory allocation. If @code{xxx_init()}
returns an error, the SQL statement is aborted with an error message and the
-main and deinitialization functions are not called. Otherwise, the main
+main and deinitialisation functions are not called. Otherwise, the main
function @code{xxx()} is called once for each row. After all rows have been
-processed, the deinitialization function @code{xxx_deinit()} is called so it
+processed, the deinitialisation function @code{xxx_deinit()} is called so it
can perform any required cleanup.
+For aggregate functions (like @code{SUM()}), you must also provide the
+following functions:
+
+@table @asis
+@item @code{xxx_reset()} (required)
+Reset sum and insert the argument as the initial value for a new group.
+@item @code{xxx_add()} (required)
+Add the argument to the old sum.
+@end table
+
+When using aggregate UDF functions MySQL works the following way:
+
+@enumerate
+@item
+Call @code{xxx_init()} to let the aggregate function allocate the memory it
+will need to store results.
+@item
+Sort the table according to the @code{GROUP BY} expression.
+@item
+For the first row in a new group, call the @code{xxx_reset()} function.
+@item
+For each new row that belongs in the same group, call the
+@code{xxx_add()} function.
+@item
+When the group changes or after the last row has been processed,
+call @code{xxx()} to get the result for the aggregate.
+@item
+Repeat 3-5 until all rows has been processed
+@item
+Call @code{xxx_deinit()} to let the UDF free any memory it has allocated.
+@end enumerate
+
All functions must be thread safe (not just the main function,
-but the initialization and deinitialization functions as well). This means
+but the initialisation and deinitialisation functions as well). This means
that you are not allowed to allocate any global or static variables that
change! If you need memory, you should allocate it in @code{xxx_init()}
and free it in @code{xxx_deinit()}.
-@node UDF calling sequences, UDF arguments, Adding UDF, Adding UDF
-@subsubsection UDF Calling Sequences
+@node UDF calling, UDF aggr. calling , Adding UDF, Adding UDF
+@subsubsection UDF Calling Sequences for simple functions
-@cindex calling sequences, UDF
+@cindex calling sequences for simple functions, UDF
The main function should be declared as shown below. Note that the return
type and parameters differ, depending on whether you will declare the SQL
@@ -42416,8 +44905,8 @@ For @code{STRING} functions:
@example
char *xxx(UDF_INIT *initid, UDF_ARGS *args,
- char *result, unsigned long *length,
- char *is_null, char *error);
+ char *result, unsigned long *length,
+ char *is_null, char *error);
@end example
@noindent
@@ -42436,7 +44925,7 @@ double xxx(UDF_INIT *initid, UDF_ARGS *args,
char *is_null, char *error);
@end example
-The initialization and deinitialization functions are declared like this:
+The initialisation and deinitialisation functions are declared like this:
@example
my_bool xxx_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
@@ -42447,7 +44936,7 @@ void xxx_deinit(UDF_INIT *initid);
The @code{initid} parameter is passed to all three functions. It points to a
@code{UDF_INIT} structure that is used to communicate information between
functions. The @code{UDF_INIT} structure members are listed below. The
-initialization function should fill in any members that it wishes to change.
+initialisation function should fill in any members that it wishes to change.
(To use the default for a member, leave it unchanged.):
@table @code
@@ -42470,6 +44959,10 @@ digits. For real functions, the default is 13 plus the number of decimals
indicated by @code{initid->decimals}. (For numeric functions, the length
includes any sign or decimal point characters.)
+If you want to return a blob, you can set this to 65K or 16M; This
+memory is not allocated but used to decide which column type to use if
+there is a need to temporary store the data.
+
@item char *ptr
A pointer that the function can use for its own purposes. For example,
functions can use @code{initid->ptr} to communicate allocated memory
@@ -42485,18 +44978,73 @@ or deallocate the memory.
@end table
-@node UDF arguments, UDF return values, UDF calling sequences, Adding UDF
+@node UDF aggr. calling , UDF arguments, UDF calling, Adding UDF
+@subsubsection UDF Calling Sequences for aggregate functions
+
+@cindex calling sequences for aggregate functions, UDF
+
+Here follows a description of the different functions you need to define
+when you want to create an aggregate UDF function.
+
+@example
+char *xxx_reset(UDF_INIT *initid, UDF_ARGS *args,
+ char *is_null, char *error);
+@end example
+
+This function is called when MySQL finds the first row in a new group.
+In the function you should reset any internal summary variables and then set
+the given argument as the first argument in the group.
+
+In many cases this is implemented internally by reseting all variables
+and then calling @code{xxx_add()}.
+
+@example
+char *xxx_add(UDF_INIT *initid, UDF_ARGS *args,
+ char *is_null, char *error);
+@end example
+
+This function is called for all rows that belongs to the same group,
+except for the first row. In this you should add the value in UDF_ARGS
+to your internal summary variable.
+
+The @code{xxx()} function should be declared identical as when you
+define a simple UDF function. @xref{UDF calling}.
+
+This function is called when all rows in the group has been processed.
+You should normally never access the @code{args} variable here but
+return your value based on your internal summary variables.
+
+All argument processing in @code{xxx_reset()} and @code{xxx_add()}
+should be done identically as for normal UDF functions. @xref{UDF
+arguments}.
+
+The return value handling in @code{xxx()} should be done identically as
+for a normal UDF. @xref{UDF return values}.
+
+The pointer argument to @code{is_null} and @code{error} is the same for
+all calls to @code{xxx_reset()}, @code{xxx_add()} and @code{xxx()}.
+You can use this to remember that you got an error or if the @code{xxx()}
+function should return @code{NULL}. Note that you should not store a string
+into @code{*error}! This is just a 1 byte flag!
+
+@code{is_null} is reset for each group (before calling @code{xxx_reset()}.
+@code{error} is never reset.
+
+If @code{isnull} or @code{error} are set after @code{xxx()} then MySQL
+will return @code{NULL} as the result for the group function.
+
+@node UDF arguments, UDF return values, UDF aggr. calling , Adding UDF
@subsubsection Argument Processing
@cindex argument processing
@cindex processing, arguments
-The @code{args} parameter points to a @code{UDF_ARGS} structure that thas the
+The @code{args} parameter points to a @code{UDF_ARGS} structure that has the
members listed below:
@table @code
@item unsigned int arg_count
-The number of arguments. Check this value in the initialization function
+The number of arguments. Check this value in the initialisation function
if you want your function to be called with a particular number of arguments.
For example:
@@ -42514,7 +45062,7 @@ The types for each argument. The possible type values are
@code{STRING_RESULT}, @code{INT_RESULT}, and @code{REAL_RESULT}.
To make sure that arguments are of a given type and return an
-error if they are not, check the @code{arg_type} array in the initialization
+error if they are not, check the @code{arg_type} array in the initialisation
function. For example:
@example
@@ -42527,7 +45075,7 @@ if (args->arg_type[0] != STRING_RESULT ||
@end example
As an alternative to requiring your function's arguments to be of particular
-types, you can use the initialization function to set the @code{arg_type}
+types, you can use the initialisation function to set the @code{arg_type}
elements to the types you want. This causes MySQL to coerce
arguments to those types for each call to @code{xxx()}. For example, to
specify coercion of the first two arguments to string and integer, do this in
@@ -42539,7 +45087,7 @@ args->arg_type[1] = INT_RESULT;
@end example
@item char **args
-@code{args->args} communicates information to the initialization function
+@code{args->args} communicates information to the initialisation function
about the general nature of the arguments your function was called with. For a
constant argument @code{i}, @code{args->args[i]} points to the argument
value. (See below for instructions on how to access the value properly.)
@@ -42582,12 +45130,13 @@ real_val = *((double*) args->args[i]);
@end itemize
@item unsigned long *lengths
-For the initialization function, the @code{lengths} array indicates the
-maximum string length for each argument. For each invocation of the main
-function, @code{lengths} contains the actual lengths of any string arguments
-that are passed for the row currently being processed. For arguments of
-types @code{INT_RESULT} or @code{REAL_RESULT}, @code{lengths} still contains
-the maximum length of the argument (as for the initialization function).
+For the initialisation function, the @code{lengths} array indicates the
+maximum string length for each argument. You should not change these.
+For each invocation of the main function, @code{lengths} contains the
+actual lengths of any string arguments that are passed for the row
+currently being processed. For arguments of types @code{INT_RESULT} or
+@code{REAL_RESULT}, @code{lengths} still contains the maximum length of
+the argument (as for the initialisation function).
@end table
@@ -42599,7 +45148,7 @@ the maximum length of the argument (as for the initialization function).
@cindex errors, handling for UDFs
@cindex handling, errors
-The initialization function should return @code{0} if no error occurred and
+The initialisation function should return @code{0} if no error occurred and
@code{1} otherwise. If an error occurs, @code{xxx_init()} should store a
null-terminated error message in the @code{message} parameter. The message
will be returned to the client. The message buffer is
@@ -42610,7 +45159,8 @@ terminal screen.
The return value of the main function @code{xxx()} is the function value, for
@code{long long} and @code{double} functions. A string functions should
return a pointer to the result and store the length of the string in the
-@code{length} arguments. @code{result} is a buffer at least 255 bytes long.
+@code{length} arguments.
+
Set these to the contents and length of the return value. For example:
@example
@@ -42618,12 +45168,16 @@ memcpy(result, "result string", 13);
*length = 13;
@end example
-If your string functions that needs to return a string longer than 255
-bytes, you must allocate the space for it with @code{malloc()} in your
+The @code{result} buffer that is passed to the calc function is 255 byte
+big. If your result fits in this, you don't have to worry about memory
+allocation for results.
+
+If your string function needs to return a string longer than 255 bytes,
+you must allocate the space for it with @code{malloc()} in your
@code{xxx_init()} function or your @code{xxx()} function and free it in
your @code{xxx_deinit()} function. You can store the allocated memory
in the @code{ptr} slot in the @code{UDF_INIT} structure for reuse by
-future @code{xxx()} calls. @xref{UDF calling sequences}.
+future @code{xxx()} calls. @xref{UDF calling}.
To indicate a return value of @code{NULL} in the main function, set
@code{is_null} to @code{1}:
@@ -42642,7 +45196,7 @@ parameter to @code{1}:
If @code{xxx()} sets @code{*error} to @code{1} for any row, the function
value is @code{NULL} for the current row and for any subsequent rows
processed by the statement in which @code{XXX()} was invoked. (@code{xxx()}
-will not even be called for subsequent rows.) @strong{NOTE:} In
+will not even be called for subsequent rows.) @strong{Note:} In
MySQL versions prior to 3.22.10, you should set both @code{*error}
and @code{*is_null}:
@@ -42723,7 +45277,10 @@ mysql> CREATE FUNCTION metaphon RETURNS STRING SONAME "udf_example.so";
mysql> CREATE FUNCTION myfunc_double RETURNS REAL SONAME "udf_example.so";
mysql> CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME "udf_example.so";
mysql> CREATE FUNCTION lookup RETURNS STRING SONAME "udf_example.so";
-mysql> CREATE FUNCTION reverse_lookup RETURNS STRING SONAME "udf_example.so";
+mysql> CREATE FUNCTION reverse_lookup
+ -> RETURNS STRING SONAME "udf_example.so";
+mysql> CREATE AGGREGATE FUNCTION avgcost
+ -> RETURNS REAL SONAME "udf_example.so";
@end example
Functions can be deleted using @code{DROP FUNCTION}:
@@ -42734,6 +45291,7 @@ mysql> DROP FUNCTION myfunc_double;
mysql> DROP FUNCTION myfunc_int;
mysql> DROP FUNCTION lookup;
mysql> DROP FUNCTION reverse_lookup;
+mysql> DROP FUNCTION avgcost;
@end example
The @code{CREATE FUNCTION} and @code{DROP FUNCTION} statements update the
@@ -42751,7 +45309,7 @@ will continue to use the old version.
Active functions are reloaded each time the server starts, unless you start
@code{mysqld} with the @code{--skip-grant-tables} option. In this case, UDF
-initialization is skipped and UDFs are unavailable. (An active function is
+initialisation is skipped and UDFs are unavailable. (An active function is
one that has been loaded with @code{CREATE FUNCTION} and not removed with
@code{DROP FUNCTION}.)
@@ -42826,7 +45384,7 @@ can take a look at @code{Item_func_mod::fix_length_and_dec} for a
typical example of how to do this.
@end enumerate
-All functions must be thread safe (In other words, don't use any global or
+All functions must be thread safe (in other words, don't use any global or
static variables in the functions without protecting them with mutexes).
If you want to return @code{NULL}, from @code{::val()}, @code{::val_int()}
@@ -42849,7 +45407,7 @@ absolutely necessary!
@end itemize
-@node Adding procedures, MySQL internals, Adding functions, Extending MySQL
+@node Adding procedures, , Adding functions, Extending MySQL
@section Adding New Procedures to MySQL
@cindex procedures, adding
@@ -42863,8 +45421,9 @@ can be done on row-by-row or @code{GROUP BY} level.
We have created an example procedure in MySQL Version 3.23 to
show you what can be done.
-Additionally we recommend you to take a look at 'mylua', which you can find in the Contrib directory. @xref{Contrib}. Which this you can use the LUA
-language to load a procedure at runtime into @code{mysqld}.
+Additionally we recommend you to take a look at @code{mylua}.
+With this you can use the LUA language to load a procedure at
+runtime into @code{mysqld}.
@menu
* procedure analyse:: Procedure analyse
@@ -42911,292 +45470,7 @@ You can find all information about procedures by examining the following files:
@end itemize
-@node MySQL internals, , Adding procedures, Extending MySQL
-@section MySQL Internals
-
-@cindex internals
-@cindex threads
-
-This chapter describes a lot of things that you need to know when
-working on the MySQL code. If you plan to contribute to MySQL
-development, want to have access to the bleeding-edge in-between
-versions code, or just want to keep track of development, follow the
-instructions in @xref{Installing source tree}. If you are interested in MySQL
-internals, you should also subscribe to @email{internals@@lists.mysql.com}.
-This is a relatively low traffic list, in comparison with
-@email{mysql@@lists.mysql.com}.
-
-@menu
-* MySQL threads:: MySQL threads
-* MySQL test suite:: MySQL test suite
-@end menu
-
-
-@node MySQL threads, MySQL test suite, MySQL internals, MySQL internals
-@subsection MySQL Threads
-
-The MySQL server creates the following threads:
-
-@itemize @bullet
-
-@item
-The TCP/IP connection thread handles all connection requests and
-creates a new dedicated thread to handle the authentication and
-and SQL query processing for each connection.
-
-@item
-On Windows NT there is a named pipe handler thread that does the same work as
-the TCP/IP connection thread on named pipe connect requests.
-
-@item
-The signal thread handles all signals. This thread also normally handles
-alarms and calls @code{process_alarm()} to force timeouts on connections
-that have been idle too long.
-
-@item
-If @code{mysqld} is compiled with @code{-DUSE_ALARM_THREAD}, a dedicated
-thread that handles alarms is created. This is only used on some systems where
-there are problems with @code{sigwait()} or if one wants to use the
-@code{thr_alarm()} code in ones application without a dedicated signal
-handling thread.
-
-@item
-If one uses the @code{--flush_time=#} option, a dedicated thread is created
-to flush all tables at the given interval.
-
-@item
-Every connection has its own thread.
-
-@item
-Every different table on which one uses @code{INSERT DELAYED} gets its
-own thread.
-
-@item
-If you use @code{--master-host}, a slave replication thread will be
-started to read and apply updates from the master.
-@end itemize
-
-@code{mysqladmin processlist} only shows the connection, @code{INSERT DELAYED},
-and replication threads.
-
-
-@node MySQL test suite, , MySQL threads, MySQL internals
-@subsection MySQL Test Suite
-
-@cindex mysqltest, MySQL Test Suite
-@cindex testing mysqld, mysqltest
-
-Until recently, our main full-coverage test suite was based on proprietary
-customer data and for that reason has not been publicly available. The only
-publicly available part of our testing process consisted of the @code{crash-me}
-test, a Perl DBI/DBD benchmark found in the @code{sql-bench} directory, and
-miscellaneous tests located in @code{tests} directory. The lack of a
-standardized publicly available test suite has made it difficult for our users,
-as well developers, to do regression tests on the MySQL code. To
-address this problem, we have created a new test system that is included in
-the source and binary distributions starting in Version 3.23.29.
-
-The current set of test cases doesn't test everything in MySQL, but it
-should catch most obvious bugs in the SQL processing code, OS/library
-issues, and is quite thorough in testing replication. Our eventual goal
-is to have the tests cover 100% of the code. We welcome contributions
-to our test suite. You may especially want to contribute tests that
-examine the functionality critical to your system, as this will ensure
-that all future MySQL releases will work well with your
-applications.
-
-@menu
-* running mysqltest:: Running the MySQL Test Suite
-* extending mysqltest:: Extending the MySQL Test Suite
-* Reporting mysqltest bugs:: Reporting Bugs in the MySQL Test Suite
-@end menu
-
-
-@node running mysqltest, extending mysqltest, MySQL test suite, MySQL test suite
-@subsubsection Running the MySQL Test Suite
-
-The test system consist of a test language interpreter
-(@code{mysqltest}), a shell script to run all
-tests(@code{mysql-test-run}), the actual test cases written in a special
-test language, and their expected results. To run the test suite on
-your system after a build, type @code{make test} or
-@code{mysql-test/mysql-test-run} from the source root. If you have
-installed a binary distribution, @code{cd} to the install root
-(eg. @code{/usr/local/mysql}), and do @code{scripts/mysql-test-run}.
-All tests should succeed. If not, you should try to find out why and
-report the problem if this is a bug in MySQL.
-@xref{Reporting mysqltest bugs}.
-
-If you have a copy of @code{mysqld} running on the machine where you want to
-run the test suite you do not have to stop it, as long as it is not using
-ports @code{9306} and @code{9307}. If one of those ports is taken, you should
-edit @code{mysql-test-run} and change the values of the master and/or slave
-port to one that is available.
-
-You can run one individual test case with
-@code{mysql-test/mysql-test-run test_name}.
-
-If one test fails, you should test running @code{mysql-test-run} with
-the @code{--force} option to check if any other tests fails.
-
-
-@node extending mysqltest, Reporting mysqltest bugs, running mysqltest, MySQL test suite
-@subsubsection Extending the MySQL Test Suite
-
-You can use the @code{mysqltest} language to write your own test cases.
-Unfortunately, we have not yet written full documentation for it - we plan to
-do this shortly. You can, however, look at our current test cases and use
-them as an example. The following points should help you get started:
-
-@itemize @bullet
-@item
-The tests are located in @code{mysql-test/t/*.test}
-
-@item
-A test case consists of @code{;} terminated statements and is similar to the
-input of @code{mysql} command line client. A statement by default is a query
-to be sent to MySQL server, unless it is recognized as internal
-command ( eg. @code{sleep} ).
-
-@item
-All queries that produce results, e.g. @code{SELECT}, @code{SHOW},
-@code{EXPLAIN}, etc., must be preceded with @code{@@/path/to/result/file}. The
-file must contain the expected results. An easy way to generate the result
-file is to run @code{mysqltest -r < t/test-case-name.test} from
-@code{mysql-test} directory, and then edit the generated result files, if
-needed, to adjust them to the expected output. In that case, be very careful
-about not adding or deleting any invisible characters - make sure to only
-change the text and/or delete lines. If you have to insert a line, make sure
-the fields are separated with a hard tab, and there is a hard tab at the end.
-You may want to use @code{od -c} to make sure your text editor has not messed
-anything up during edit. We, of course, hope that you will never have to edit
-the output of @code{mysqltest -r} as you only have to do it when you find a
-bug.
-
-@item
-To be consistent with our setup, you should put your result files in
-@code{mysql-test/r} directory and name them @code{test_name.result}. If the
-test produces more than one result, you should use @code{test_name.a.result},
-@code{test_name.b.result}, etc.
-
-@item
-If a statement returns an error, you should on the line before the statement
-specify with the @code{--error error-number}. The error number can be
-a list of possible error numbers separated with @code{','}.
-
-@item
-If you are writing a replication test case, you should on the first line of
-the test file, put @code{source include/master-slave.inc;}. To switch between
-master and slave, use @code{connection master;} and @code{connection slave;}.
-If you need to do something on an alternate connection, you can do
-@code{connection master1;} for the master, and @code{connection slave1;} for
-the slave.
-
-@item
-If you need to do something in a loop, you can use something like this:
-@example
-let $1=1000;
-while ($1)
-@{
- # do your queries here
- dec $1;
-@}
-@end example
-
-@item
-To sleep between queries, use the @code{sleep} command. It supports fractions
-of a second, so you can do @code{sleep 1.3;}, for example, to sleep 1.3
-seconds.
-
-@item
-To run the slave with additional options for your test case, put them
-in the command-line format in @code{mysql-test/t/test_name-slave.opt}. For
-the master, put them in @code{mysql-test/t/test_name-master.opt}.
-
-@item
-If you have a question about the test suite, or have a test case to contribute,
-e-mail to @email{internals@@lists.mysql.com}. As the list does not accept
-attachments, you should ftp all the relevant files to:
-@url{ftp://support.mysql.com/pub/mysql/Incoming}
-
-@end itemize
-
-
-@node Reporting mysqltest bugs, , extending mysqltest, MySQL test suite
-@subsubsection Reporting Bugs in the MySQL Test Suite
-
-If your MySQL version doesn't pass the test suite you should
-do the following:
-
-@itemize @bullet
-@item
-Don't send a bug report before you have found out as much as possible of
-what when wrong! When you do it, please use the @code{mysqlbug} script
-so that we can get information about your system and @code{MySQL}
-version. @xref{Bug reports}.
-@item
-Make sure to include the output of @code{mysql-test-run}, as well as
-contents of all @code{.reject} files in @code{mysql-test/r} directory.
-@item
-If a test in the test suite fails, check if the test fails also when run
-by its own:
-
-@example
-cd mysql-test
-mysql-test-run --local test-name
-@end example
-
-If this fails, then you should configure MySQL with
-@code{--with-debug} and run @code{mysql-test-run} with the
-@code{--debug} option. If this also fails send the trace file
-@file{var/tmp/master.trace} to ftp://support.mysql.com/pub/mysql/secret
-so that we can examine it. Please remember to also include a full
-description of your system, the version of the mysqld binary and how you
-compiled it.
-
-@item
-Try also to run @code{mysql-test-run} with the @code{--force} option to
-see if there is any other test that fails.
-
-@item
-If you have compiled MySQL yourself, check our manual for how
-to compile MySQL on your platform or, preferable, use one of
-the binaries we have compiled for you at
-@uref{http://www.mysql.com/downloads/}. All our standard binaries should
-pass the test suite !
-
-@item
-If you get an error, like @code{Result length mismatch} or @code{Result
-content mismatch} it means that the output of the test didn't match
-exactly the expected output. This could be a bug in MySQL or
-that your mysqld version produces slight different results under some
-circumstances.
-
-Failed test results are put in a file with the same base name as the
-result file with the @code{.reject} extension. If your test case is
-failing, you should do a diff on the two files. If you cannot see how
-they are different, examine both with @code{od -c} and also check their
-lengths.
-
-@item
-If a test fails totally, you should check the logs file in the
-@code{mysql-test/var/log} directory for hints of what went wrong.
-
-@item
-If you have compiled MySQL with debugging you can try to debug this
-by running @code{mysql-test-run} with the @code{--gdb} and/or @code{--debug}
-options.
-@xref{Making trace files}.
-
-If you have not compiled MySQL for debugging you should probably
-do that. Just specify the @code{--with-debug} options to @code{configure}!
-@xref{Installing source}.
-@end itemize
-
-
-
-
-@node Problems, Users, Extending MySQL, Top
+@node Problems, Contrib, Extending MySQL, Top
@appendix Problems and Common Errors
@cindex problems, common errors
@@ -43204,7 +45478,7 @@ do that. Just specify the @code{--with-debug} options to @code{configure}!
@menu
* What is crashing:: How to determine what is causing problems
-* Common errors:: Some common errors when using MySQL
+* Common errors:: Common Errors When Using MySQL
* Installation Issues:: Installation Related Issues
* Administration Issues:: Administration Related Issues
* Query Issues:: Query Related Issues
@@ -43241,7 +45515,7 @@ The machine doesn't answer to a remote machine's pings.
Different, unrelated programs don't behave correctly.
@item
If your system rebooted unexpectedly (a faulty user level program should
-NEVER be able to take down your system).
+@strong{never} be able to take down your system).
@end itemize
In this case you should start by checking all your cables and run some
@@ -43316,7 +45590,7 @@ described in this manual. @xref{Asking questions}.
@node Common errors, Installation Issues, What is crashing, Problems
-@appendixsec Some Common Errors When Using MySQL
+@appendixsec Common Errors When Using MySQL
@cindex errors, list of
@@ -43335,12 +45609,12 @@ described in this manual. @xref{Asking questions}.
* Commands out of sync:: @code{Commands out of sync} error in client
* Ignoring user:: @code{Ignoring user} error
* Cannot find table:: @code{Table 'xxx' doesn't exist} error
-* Cannot initialize character set:: @code{Can@'t initialize character set xxx} error.
+* Cannot initialize character set:: @code{Can't initialize character set xxx} error
* Not enough file handles:: File Not Found
@end menu
-This section lists some errors that users frequently get. You will find
+This section lists some errors that users frequently get. You will find
descriptions of the errors, and how to solve the problem here.
@@ -43380,6 +45654,7 @@ You normally can get the following error codes in this case
(which one you get is OS-dependent):
@multitable @columnfractions .3 .7
+@item @strong{Error code} @tab @strong{Description}
@item @code{CR_SERVER_GONE_ERROR} @tab The client couldn't send a question to the
server.
@item @code{CR_SERVER_LOST} @tab The client didn't get an error when writing
@@ -43398,7 +45673,7 @@ return a big result row!
@node Can not connect to server, Blocked host, Gone away, Common errors
-@appendixsubsec @code{Can't connect to [local] MySQL server} error
+@appendixsubsec @code{Can't connect to [local] MySQL server} Error
A MySQL client on Unix can connect to the @code{mysqld} server in two
different ways: Unix sockets, which connect through a file in the file
@@ -43495,7 +45770,7 @@ problem is :
@itemize @bullet
@item
Check if the server is up by doing @code{telnet your-host-name
-tcp-ip-port-number} and press @code{RETURN} a couple of times. If there
+tcp-ip-port-number} and press Enter a couple of times. If there
is a MySQL server running on this port you should get a
responses that includes the version number of the running MySQL
server. If you get an error like @code{telnet: Unable to connect to
@@ -43620,16 +45895,36 @@ When a MySQL client or the @code{mysqld} server gets a packet bigger
than @code{max_allowed_packet} bytes, it issues a @code{Packet too large}
error and closes the connection.
-If you are using the @code{mysql} client, you may specify a bigger buffer by
-starting the client with @code{mysql --set-variable=max_allowed_packet=8M}.
+In MySQL 3.23 the biggest possible packet is 16M (due to limits in the
+client/server protocol). In MySQL 4.0.1 and up, this is only limited by
+the amount on memory you have on your server (up to a theoretical
+maximum of 2G).
-If you are using other clients that do not allow you to specify the maximum
-packet size (such as @code{DBI}), you need to set the packet size when you
-start the server. You cau use a command-line option to @code{mysqld} to set
-@code{max_allowed_packet} to a larger size. For example, if you are
-expecting to store the full length of a @code{BLOB} into a table, you'll need
-to start the server with the @code{--set-variable=max_allowed_packet=16M}
-option.
+A communication packet is a single SQL statement sent to the MySQL server
+or a single row that is sent to the client.
+
+When a MySQL client or the @code{mysqld} server gets a packet bigger
+than @code{max_allowed_packet} bytes, it issues a @code{Packet too
+large} error and closes the connection. With some clients, you may also
+get @code{Lost connection to MySQL server during query} error if the
+communication packet is too big.
+
+Note that both the client and the server has it's own
+@code{max_allowed_packet} variable. If you want to handle big packets,
+you have to increase this variable both in the client and in the server.
+
+It's safe to increase this variable as memory is only allocated when
+needed; This variable is more a precaution to catch wrong packets
+between the client/server and also to ensure that you don't accidently
+use big packets so that you run out of memory.
+
+If you are using the @code{mysql} client, you may specify a bigger
+buffer by starting the client with @code{mysql --set-variable=max_allowed_packet=8M}. Other clients have different methods to set this variable.
+
+You can use the option file to set @code{max_allowed_packet} to a larger
+size in @code{mysqld}. For example, if you are expecting to store the
+full length of a @code{MEDIUMBLOB} into a table, you'll need to start
+the server with the @code{set-variable=max_allowed_packet=16M} option.
You can also get strange problems with large packets if you are using
big blobs, but you haven't given @code{mysqld} access to enough memory
@@ -43817,7 +46112,7 @@ function:
@example
mysql> update user set password=PASSWORD('your password')
- where user='XXX';
+ -> where user='XXX';
@end example
@end itemize
@@ -43839,7 +46134,7 @@ You can check which tables you have in the current database with
@node Cannot initialize character set, Not enough file handles, Cannot find table, Common errors
-@appendixsubsec @code{Can@'t initialize character set xxx} error.
+@appendixsubsec @code{Can't initialize character set xxx} error
@cindex multibyte character sets
@@ -43931,8 +46226,8 @@ number 256 to affect the number of file descriptors available to
@code{ulimit} (and @code{open-files-limit}) can increase the number of
file descriptors, but only up to the limit imposed by the operating
system. There is also a 'hard' limit that can only be overrided if you
-start @code{safe_mysqld} or @code{mysqld} as root (Just remember that
-you need to also use the @code{--user=..} option in this case). If you
+start @code{safe_mysqld} or @code{mysqld} as root (just remember that
+you need to also use the @code{--user=...} option in this case). If you
need to increase the OS limit on the number of file descriptors
available to each process, consult the documentation for your operating
system.
@@ -43972,10 +46267,10 @@ symbols that start with @code{mysql_}, like the following:
@end example
you should be able to solve this by adding @code{-Lpath-to-the-mysql-library
--lmysqlclient} @strong{LAST} on your link line.
+-lmysqlclient} @strong{last} on your link line.
If you get @code{undefined reference} errors for the @code{uncompress}
-or @code{compress} function, add @code{-lz} @strong{LAST} on your link
+or @code{compress} function, add @code{-lz} @strong{last} on your link
line and try again!
If you get @code{undefined reference} errors for functions that should
@@ -44463,7 +46758,7 @@ the original table.
@node Problems with mysql.sock, Timezone problems, Temporary files, Administration Issues
-@appendixsubsec How to Protect or change the MySQL socket file @file{/tmp/mysql.sock}
+@appendixsubsec How to Protect or Change the MySQL Socket File @file{/tmp/mysql.sock}
@cindex @code{mysql.sock}, protection
@cindex deletion, @code{mysql.sock}
@@ -44545,6 +46840,7 @@ the server runs, for example, in @code{safe_mysqld} or @code{mysql.server}.
* Problems with alias:: Problems with @code{alias}
* Deleting from related tables:: Deleting Rows from Related Tables
* No matching rows:: Solving Problems with No Matching Rows
+* Problems with float:: Problems with floating point comparison
@end menu
@node Case sensitivity, Using DATE, Query Issues, Query Issues
@@ -44787,7 +47083,7 @@ id's per query if the @code{related_column} is an index. If the
number of arguments in the @code{IN} clause.
-@node No matching rows, , Deleting from related tables, Query Issues
+@node No matching rows, Problems with float, Deleting from related tables, Query Issues
@appendixsubsec Solving Problems with No Matching Rows
@cindex no matching rows
@@ -44815,16 +47111,10 @@ the table that was last removed from the query.
@item
If you are comparing @code{FLOAT} or @code{DOUBLE} columns with numbers that
-have decimals, you can't use @code{=}! This problem is common in most
-computer languages because floating-point values are not exact values:
-
-@example
-mysql> SELECT * FROM table_name WHERE float_column=3.5;
- ->
-mysql> SELECT * FROM table_name WHERE float_column between 3.45 and 3.55;
-@end example
-
-In most cases, changing the @code{FLOAT} to a @code{DOUBLE} will fix this!
+have decimals, you can't use @code{'='}. This problem is common in most
+computer languages because floating-point values are not exact values.
+In most cases, changing the @code{FLOAT} to a @code{DOUBLE} will fix this.
+@xref{Problems with float}.
@item
If you still can't figure out what's wrong, create a minimal test that can
@@ -44842,6 +47132,134 @@ shell> mysql test2 < query.sql
Post the test file using @code{mysqlbug} to @email{mysql@@lists.mysql.com}.
@end enumerate
+@node Problems with float, , No matching rows, Query Issues
+@appendixsubsec Problems with Floating Point Comparison
+
+Floating point numbers cause confusion sometimes, because these numbers
+are not stored as exact values inside computer architecture. What one
+can see on the screen usually is not the exact value of the number.
+
+Field types @code{FLOAT}, @code{DOUBLE} and @code{DECIMAL} are such.
+
+@example
+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);
+
+mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b
+ -> FROM t1 GROUP BY i HAVING a <> b;
++------+--------+-------+
+| i | a | b |
++------+--------+-------+
+| 1 | 21.40 | 21.40 |
+| 2 | 76.80 | 76.80 |
+| 3 | 7.40 | 7.40 |
+| 4 | 15.40 | 15.40 |
+| 5 | 7.20 | 7.20 |
+| 6 | -51.40 | 0.00 |
++------+--------+-------+
+@end example
+
+The result is correct. Although the first five records look like they
+shouldn't pass the comparison test, they may do so because the
+difference between the numbers show up around tenth decimal, or so
+depending on computer architecture.
+
+The problem cannot be solved by using ROUND() (or similar function),
+because the result is still a floating point number. Example:
+
+@example
+mysql> 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 |
++------+--------+-------+
+| 1 | 21.40 | 21.40 |
+| 2 | 76.80 | 76.80 |
+| 3 | 7.40 | 7.40 |
+| 4 | 15.40 | 15.40 |
+| 5 | 7.20 | 7.20 |
+| 6 | -51.40 | 0.00 |
++------+--------+-------+
+@end example
+
+This is what the numbers in row 'a' look like:
+@example
+mysql> SELECT i, ROUND(SUM(d1), 2)*1.0000000000000000 AS a,
+ -> ROUND(SUM(d2), 2) AS b FROM t1 GROUP BY i HAVING a <> b;
++------+----------------------+-------+
+| i | a | b |
++------+----------------------+-------+
+| 1 | 21.3999999999999986 | 21.40 |
+| 2 | 76.7999999999999972 | 76.80 |
+| 3 | 7.4000000000000004 | 7.40 |
+| 4 | 15.4000000000000004 | 15.40 |
+| 5 | 7.2000000000000002 | 7.20 |
+| 6 | -51.3999999999999986 | 0.00 |
++------+----------------------+-------+
+@end example
+
+Depending on the computer architecture you may or may not see similar results.
+Each CPU may evaluate floating point numbers differently. For example in
+some machines you may get 'right' results by multiplaying both arguments
+with 1, an example follows.
+
+@strong{WARNING: NEVER TRUST THIS METHOD IN YOUR APPLICATION, THIS IS
+AN EXAMPLE OF A WRONG METHOD!!!}
+
+@example
+mysql> SELECT i, ROUND(SUM(d1), 2)*1 AS a, ROUND(SUM(d2), 2)*1 AS b
+ -> FROM t1 GROUP BY i HAVING a <> b;
++------+--------+------+
+| i | a | b |
++------+--------+------+
+| 6 | -51.40 | 0.00 |
++------+--------+------+
+@end example
+
+The reason why the above example seems to be working is that on the
+particular machine where the test was done, the CPU floating point
+arithmetics happens to round the numbers to same, but there is no
+rule that any CPU should do so, so it cannot be trusted.
+
+The correct way to do floating point number comparison is to first
+decide on what is the wanted tolerance between the numbers and then do
+the comparsion against the tolerance number. For example, if we agree on
+that floating point numbers should be regarded the same, if they are
+same with precision of one of ten thousand (0.0001), the comparsion
+should be done like this:
+
+@example
+mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1
+ -> GROUP BY i HAVING ABS(a - b) > 0.0001;
++------+--------+------+
+| i | a | b |
++------+--------+------+
+| 6 | -51.40 | 0.00 |
++------+--------+------+
+1 row in set (0.00 sec)
+@end example
+
+And vice versa, if we wanted to get rows where the numbers are the same,
+the test would be:
+
+@example
+mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1
+ -> GROUP BY i HAVING ABS(a - b) < 0.0001;
++------+-------+-------+
+| i | a | b |
++------+-------+-------+
+| 1 | 21.40 | 21.40 |
+| 2 | 76.80 | 76.80 |
+| 3 | 7.40 | 7.40 |
+| 4 | 15.40 | 15.40 |
+| 5 | 7.20 | 7.20 |
++------+-------+-------+
+@end example
@node Table Definition Issues, , Query Issues, Problems
@appendixsec Table Definition Related Issues
@@ -44916,9 +47334,9 @@ SELECT col_name1, col_name3, col_name2 FROM tbl_name;
will return columns in the order @code{col_name1}, @code{col_name3}, @code{col_name2}.
-You should @strong{NEVER}, in an application, use @code{SELECT *} and
+You should @strong{never}, in an application, use @code{SELECT *} and
retrieve the columns based on their position, because the order in which
-columns are returned @strong{CANNOT} be guaranteed over time. A simple
+columns are returned @strong{cannot} be guaranteed over time. A simple
change to your database may cause your application to fail rather
dramatically.
@@ -44967,469 +47385,7 @@ We plan to fix the above in 4.0.
-@node Users, MySQL customer usage, Problems, Top
-@appendix Some MySQL Users
-
-@cindex users, of MySQL
-@cindex news sites
-
-This appendix lists some users of MySQL that have given us permission
-to list them in our documentation. It is by far not a complete list, but
-should give you a general idea of who uses MySQL and what it can
-be used for.
-
-@appendixsec General News Sites
-
-@itemize @bullet
-
-@item @uref{http://www.yahoo.com/, Yahoo!}
-
-@item @uref{http://slashdot.org/, Slashdot: A pro-Linux/tech news and comment/discussion site}
-
-@item @uref{http://www.linux.com/, All about Linux}
-
-@item @uref{http://www.linuxtoday.com/, Linuxtoday}
-
-@item @uref{http://www.32bitsonline.com/, 32Bits Online: because there's
-more than one way to compute}
-
-@item @uref{http://www.freshmeat.net/, Freshmeat: News about new versions of computer-related stuff}
-
-@end itemize
-
-@cindex search engines, web
-@cindex web search engines
-@appendixsec Some Web Search Engines
-
-@itemize @bullet
-
-@item @uref{http://www.aaa.com.au, AAA Matilda Web Search}
-
-@item @uref{http://www.whatsnu.com/, What's New}
-
-@item @uref{http://www.aladin.de/, Aladin}
-
-@item @uref{http://www.columbus-finder.de/, Columbus Finder}
-
-@item @uref{http://www.spider.de/, Spider}
-
-@item @uref{http://www.blitzsuche.de/, Blitzsuche}
-
-@item @uref{http://www.indoseek.co.id, Indoseek Indonesia}
-
-@item @uref{http://www.yaboo.dk/, Yaboo - Yet Another BOOkmarker}
-
-
-@item @uref{http://www.ozsearch.com.au, OzSearch Internet Guide}
-
-@item @uref{http://www.splatsearch.com/, Splat! Search}
-
-@item @uref{http://osdls.library.arizona.edu/, The Open Source Digital Library System Project}
-@end itemize
-
-@appendixsec Some Information Search Engines Concentrated on Some Area
-
-@itemize @bullet
-
-@item @uref{http://www.spylog.ru/, SpyLOG ; A very popular Web counter site}
-
-@item @uref{http://www.tucows.com/, TuCows Network; Free Software archive}
-
-@item @uref{http://www.jobvertise.com,Jobvertise: Post and search for jobs}
-
-@item @uref{http://www.musicdatabase.com, The Music Database}
-
-@item @uref{http://www.soccersearch.com, Football (Soccer) search page}
-
-@item @uref{http://www.headrush.net/takedown, TAKEDOWN - wrestling}
-
-@item @uref{http://www.lyrics.net, The International Lyrics Network}
-
-@item @uref{http://TheMatrix.com/~matrix/band_search.phtml, Musicians looking for other musicians (Free Service)}
-
-@item @uref{http://www.addall.com/AddBooks/Stores.html,AddALL books searching and price comparison}
-
-@item @uref{http://www.herbaria.harvard.edu/Data/Gray/gray.html,Harvard's Gray Herbarium Index of Plant Names}
-
-@item @uref{http://www.game-developer.com/,The Game Development Search Engine}
-
-@item @uref{www.theinnkeeper.com, The Innkeeper Vacation Guides}
-
-@item @uref{http://www.macgamedatabase.com/, The Mac Game Database uses PHP and MySQL}
-@c From: Marc Antony Vose <suzerain@suzerain.com>
-
-@item @uref{http://www.csse.monash.edu.au/publications/, Research
-Publications at Monash University in Australia}
-
-@item @uref{http://www.ipielle.emr.it/bts/index.html,
-Occupational Health & Safety Web site database (a project for the ECC)}
-@c c.presutti@ipielle.emr.it
-
-@item @uref{http://data.mch.mcgill.ca/, Bioinformatics databases at the
-Montreal Children's Hospital using MySQL}
-@c saeed@www.debelle.mcgill.ca
-@end itemize
-
-@cindex online magazines
-@cindex magazines, online
-@appendixsec Online Magazines
-
-@itemize @bullet
-@item @uref{http://www.spoiler.com, Spoiler Webzine}.
-An online magazine featuring music, literature, arts, and design content.
-@item @uref{http://www.linux-magazin.de/newsflash/, Daily news about Linux in German language}
-@item @uref{http://www.betazine.com,Betazine - The Ultimate Online Beta Tester's Magazine}
-@item @uref{http://www.currents.net/ccinfo/aboutcc.html,Computer Currents Magazine}
-@end itemize
-
-@cindex web sites
-@appendixsec Web Sites that Use MySQL as a Backend
-
-@itemize @bullet
-
-@item @uref{http://liftoff.msfc.nasa.gov, NASA}
-@item @uref{http://kids.msfc.nasa.gov, NASA KIDS}
-@item @uref{http://science.nasa.gov, Sience@@NASA}
-
-@item @uref{http://www.handy.de/, handy.de}
-
-@item @uref{http://lindev.jmc.tju.edu/qwor, Qt Widget and Object Repository}
-
-@item @uref{http://www.samba-choro.com.br, Brazilian samba site (in Portuguese)}
-
-@item @uref{http://pgss.iss.uw.edu.pl/en_index.ISS, Polish General Social Survey}
-
-@item @uref{http://www.expo2000.com, Expo2000} World-wide distribution of
-tickets for this event is implemented using MySQL and tcl/tk. More than
-5000 travel agencies all over the world have access to it.
-
-@item @uref{http://www.freevote.com/, FreeVote.com is a free voting
-service with millions of users.}
-
-@item @uref{http://f1.tauzero.se, Forza Motorsport}
-
-@item @uref{http://www.dreamhost.com/, DreamHost Web Hosting}
-
-@end itemize
-
-@cindex services
-@appendixsec Some Domain/Internet/Web and Related Services
-
-@itemize @bullet
-
-@item @uref{http://www.wix.com/mysql-hosting, Registry of Web providers that
-support MySQL}
-
-@item @uref{http://www.yi.org/, Dynamic DNS Services}
-
-@item @uref{http://www.dynodns.net/, Dynamic domain name service}
-
-@item @uref{http://www.ods.org/, Open DNS Project; free dynamic DNS service}
-
-@c @item @uref{http://dynodns.net, Free dynamic DNS implementation}
-@c EMAIL: A Moore <amoore@mooresystems.com>
-
-@item @uref{http://www.hn.org/, Hammernode; Public DNS Servers}
-
-@item @uref{http://www.fdns.net/, Free 3rd level domains}
-
-@item @uref{http://worldcommunity.com/, Online Database}
-
-@item @uref{http://www.bigbiz.com, BigBiz Internet Services}
-
-@item @uref{http://virt.circle.net, The Virt Gazette}
-
-@item @uref{http://www.california.com, Global InfoNet Inc}
-
-@item @uref{http://www.webhosters.com, WebHosters - A Guide to WWW Providers}
-
-@item @uref{http://online.dn.ru, Internet information server}
-
-@item @uref{http://www.stopbit.com, A technology news site}
-
-@item @uref{http://www.worldnetla.net, WorldNet Communications - An Internet Services Provider}
-
-@item @uref{http://www.netizen.com.au/, Netizen: Australian-based Web consultancy}
-
-@item @uref{http://www.trainingpages.co.uk, Search site for training courses in the UK}
-
-@item @uref{http://chat.nitco.com, Gannon Chat (GPL). Written in Perl and Javascript}
-
-@item @uref{http://www.addurls.com/,A general links directory}
-
-@item @uref{http://www.bookmarktracker.com, A Web-based bookmark management service}
-
-@item @uref{http://www.cdrom.com,Walnut Creek CDROM}
-
-@item @uref{http://www.wwwthreads.org/, WWWThreads; Interactive discussion Forums}
-
-@item @uref{http://pvmon.portici.enea.it/Meteo, In Italian; Storage data from meteo station}
-
-@item @uref{http://www.buysell.net/, Online "Person To Person" Auction}
-
-@item @uref{http://tips.pair.com,Tips on Web development}
-
-@item @uref{http://www.mailfriends.com, Mailfriends.com is a FREE service for
-everybody who wants to find friends over the internet.}
-
-@item @uref{http://www.uninova.com/cgi-bin/wctelnets?list, Web Page Telnet BBS List}
-
-@item @uref{http://www.uninova.com/cnc.html,UniNova Digital Postcards}
-
-@c @item @uref{http://cabinboy.powersurfr.com, An Internet RFC search engine}
-
-@item @uref{http://www.dslreports.com, DSL-provider search with reviews}.
-Made with MySQL and Modperl, all pages are generated dynamically out of
-the MySQL database
-@end itemize
-
-@cindex PHP, web sites
-@appendixsec Web Sites that Use @code{PHP} and MySQL
-
-@itemize @bullet
-@c @item @uref{http://www.wh200th.com, White House 200th Anniversary site}
-
-@item @uref{http://support.jgaa.com/, Jgaa's Internet - Official Support Site}
-
-@item @uref{http://io.incluso.com, Ionline - online publication:} MySQL,
-PHP, Java, Web programming, DB development
-
-@item @uref{http://www.baboo.com, BaBoo(Browse and bookmark). Free Web-based bookmark manager and Calendar}
-
-@item @uref{http://www.courses.pjc.cc.fl.us/Schedule/index.php, Course
-Schedule System at Pensacola Junior College}
-
-@item @uref{http://www.fccj.org, Florida Community College at Jacksonville}
-
-@item @uref{http://www.32bit.com/, 32bit.com; An extensive shareware / freeware archive}
-
-@item @uref{http://www.jokes2000.com/, Jokes 2000}
-@c Added 990604; EMAIL: ah@dybdahl.dk
-
-
-@item @uref{http://www.burken.nu/ , Burken.NU} Burken is a webhotel that
-provides scripts, among other things, for remote users, like counters,
-guestbooks etc.
-@c Added 990608; EMAIL: spacedmp@SpaceDump.Burken.NU (Anders Olausson)
-
-@item @uref{http://tips.pair.com, tips.pair.com} Contains tips on html,
-javascript, 2d/3d graphics, and PHP3/MySQL. All pages are generated from
-a database.
-@c Added 990614; EMAIL: downey@image.dk (Rune Madsen)
-
-@item @uref{http://www.softwarezrus.com/, Softwarezrus.com}
-Ecommerce site that is selling computers.
-@end itemize
-
-@cindex consultants, list of
-@appendixsec Some MySQL Consultants
-
-@itemize @bullet
-
-@item @uref{http://www.ayni.com, Ayni AG}
-
-@item @uref{http://worldcommunity.com/, Online Database}
-
-@item @uref{http://www2.dataguard.no/,DataGuard (Uses MySQL and PHP)}
-
-@item @uref{http://wwits.net/programs/mysql.phtml, WWITS (Uses MySQL and PHP)}
-
-@item @uref{http://www.worldcommunity.com/, WCN - The World Community Network}
-
-@item @uref{http://www.chipcastle.com, Chip Castle Dot Com Inc}
-@c Added 990603 EMAIL: chip@chipcastle.com (Chip Castle)
-
-@item @uref{http://www.cyber.com.au/, Cybersource Pty. Ltd}
-
-@item @uref{http://www.spring.de, Spring infotainment gmbh & co. kg}
-@c added 990905 "Oliver Pischke" <opischke@spring.de>
-
-@item @uref{http://www.wamdesign.com/, Develops Web sites using MySQL}
-@c Added 990905; max@wamdesign.com
-
-@item @uref{http://www.berkeleyconsultants.com, Berkeley Consultants Group}
-
-@item @uref{http://www.jammconsulting.com/, JAMM Consulting Inc.}
-
-@end itemize
-
-@appendixsec Programming
-
-@cindex web pages, miscellaneous
-@appendixsec Uncategorized Pages
-
-@itemize @bullet
-
-@item @uref{http://www.feature-showcase.com/htmls/demo_mysql.sql,
-AZC.COM's Feature Showcase}
-
-@item @uref{http://www.teach.org.uk/subjects/trainingcourse/g.html, Course Search}
-
-@item @uref{http://www.northerbys.com, Northerbys Online Auctions}
-
-@item @uref{http://www.schiphol.nl/flights/home.htm, Amsterdam Airport Schiphol}
-
-@item @uref{http://TheMatrix.com/seventhsin/query.phtml, CD database}
-
-@item @uref{http://TheMatrix.com/~flmm/GEAR.html, Used Audio Gear Database}
-
-@item @uref{http://www.kiss.de/musik-mueller, Musical note-sheets}
-
-@item @uref{http://www.bagism.com, Bagism - A John Lennon fan page}
-
-@item @uref{http://www.selftaught.com/, US Folk art broker}
-
-@item @uref{http://organizer.net/, Mail reading on the Web}
-
-@item @uref{http://www.mypage.org/, Free home pages on www.somecoolname.mypage.org}
-
-@item @uref{http://www.schulweb.de/, Der Server f@"ur Schulen im Web (In German)}
-
-@item @uref{http://www.ald.net/, Auldhaefen Online Services}
-
-@item @uref{http://www.cary.net/, CaryNET Information Center}
-
-@item @uref{http://www.dataden.com/, Dataden Computer Systems}
-
-@item @uref{http://andree.grm.se/, Andr@'emuseet (In Swedish)}
-
-@item @uref{http://www.him.net/, HOMESITE Internet Marketing}
-
-@item @uref{http://www.jade-v.com/techinfo.html, Jade-V Network Services }
-
-@item @uref{http://ww2010.atmos.uiuc.edu/(Gl)/abt/aknw/tech.rxml,
-Weather World 2010 Technical Credits} @*
-
-@item @uref{http://gimp.foebud.org/registry/doc/, About The Gimp plugin registry}
-
-@item @uref{http://www.fast-inc.com/Products/Archiver/database.html, Java tool
-Archiver technical detail (Slightly optimistic about MySQL
-ANSI-92 compliance)}
-
-@item @uref{http://www.gamesdomain.com/cheats/usrcheat.phtml, Games Domain Cheats Database}
-
-@item @uref{http://www.kcilink.com/poweredby/, The "Powered By" Page (Kcilink)}
-
-@item @uref{http://www.netcasting.net/index.whtml, Netcasting}
-
-@item @uref{http://homepages.tig.com.au/~mjj/nbltips, NBL (Australian National Basketball League) tipping}
-
-@item @uref{http://www.cgishop.com/, CGI shop}
-
-@item @uref{http://www.whirlycott.com/, Whirlycott: Website Design}
-
-@item @uref{http://www.mtp.dk, Museum Tusculanum Press}
-
-@item @uref{http://csdgi.historie.ku.dk/biblio, Centro Siciliano di Documentazione}
-
-@item @uref{http://caribou.dyn.ml.org:8000, Quake statistics database}
-
-@item @uref{http://www.astroforum.ch, Astroforum: Astrologie and related things (in German)}
-
-@item @uref{http://www.opendebate.com, OpenDebate - Interactive Polls & Open Discussion}
-
-@item @uref{http://vermeer.organik.uni-erlangen.de/dissertationen/, Online chemical dissertation server}
-
-@item @uref{http://www.freschinfo.com, FreSch! The Free Scholarship Search Service}
-
-@item @uref{http://www.nada.kth.se/~staffanu/pinball, Stockholm Pinball Locator}
-
-@item @uref{http://www.hek.com, HEK A construction company}
-
-@item @uref{http://www.nbi.nl, Elsevier Bussines Information}
-
-@item @uref{http://vaccination.medicallink.se/, Medical Links (Using ColdFusion and MySQL)}
-
-@item @uref{http://www.joblink-usa.com, Search for jobs & people at JobLink-USA}
-
-@item @uref{http://www.skydive.net/competfs, Competition Formation Skydiving}
-
-@item @uref{http://www.galaxy-net.net/Galaxy-NET Telecommunications, E-commerce and internal accounting}
-
-@item @uref{http://www.borsen.dk/, Denmark's leading business daily newspaper B@o{}rsen}
-
-@item @uref{http://tmmm.simplenet.com/indb/, The Internet NES Database}
-
-@item @uref{http://www.russia.cz, Travel agency in Prague in 3 languages}
-
-@item @uref{http://www.linkstation.de, Linkstation}
-
-@item @uref{http://www.peoplestaff.com, Searchable online database at Peoplestaff}
-
-@item @uref{http://www.dreamhorse.com, A searchable database system for horse classified ads}
-
-@item @uref{http://pootpoot.com/,The Poot site}
-
-@item @uref{http://grateful.net/hw_html/,"Playin' in the LAN"; a network monitoring suite}
-
-@c Update from Christopher Milton <cmilton@bwn.net> 1999-12-21
-@item @uref{http://www.usapa.army.mil,U.S. Army Publishing Agency}
-
-@item @uref{http://www.nekretnine.co.yu/,Realestate handling in Yugoslavia}
-
-@item @uref{http://demo.cpsoft.com/pims/devFAQ.html, PIMS; a Patient Information Management System}
-
-@item @uref{http://cpsoft.com,Pilkington Software Inc}
-
-@item @uref{http://www.no-quarter.org/,A Vietnam Veteran's Memorial (The Wall) database}
-
-@item @uref{http://www.gamers-union.com/,Gamer's Union specializes in auctions of used & out-of-print gaming material}
-
-@item @uref{http://www.montereyhigh.com/office/dbul.php3, A daily bulletin at Monterey High school}
-
-@item @uref{http://www.myEastside.com,Community-owned site serving Lake
-Washington's Eastside residents and businesses}
-
-@item @uref{http://bowling-france.net/,French bowling site}
-@end itemize
-
-Send any additions to this list to @email{webmaster@@mysql.com}.
-
-@page
-
-
-
-
-@node MySQL customer usage, Contrib, Users, Top
-@appendix MySQL customer usage
-
-@cindex MySQL usage
-
-The section 'Some MySQL Users' contains a lot of different links to
-MySQL users but doesn't provide that much information about how
-they are using MySQL. @xref{Users}. This manual section is to
-give you an idea of how other MySQL users are using
-MySQL to solve their problems.
-
-This manual section is very new and we plan to add more stories here
-shortly. If you are interested in contributing of how you use
-MySQL in a unique environment or have success store about how you
-use MySQL, you can write to @code{docs@@mysql.com} with
-subject @code{Success:}. Note that as we are very busy it may take some
-time before you get some feedback for your story.
-
-@itemize @bullet
-@item
-@strong{Peter Zaitsev of Spylog.ru} writes:
-I think you might be interested in my database size. The whole database
-is currently on 15 servers and I think it's about 60.000 of tables
-containing about 5.000.000.000 of rows. My mostly loaded server
-currently holds about 10.000 of tables with 1.000.000.000 of rows in it.
-Hugest tables have about 50.000.000 of rows, and this value will raise
-as soon as I'll move to 2.4 kernel with large files. Currently I have to
-delete much of logs for large sites to hold table sizes in 2Gb.
-
-@item
-@strong{Texas Instruments} is using MySQL for handling tables
-that contain up to 2,000 million rows in a validation regression database.
-@end itemize
-
-@page
-
-
-
-
-@node Contrib, Credits, MySQL customer usage, Top
+@node Contrib, Credits, Problems, Top
@appendix Contributed Programs
@cindex contributed programs
@@ -45438,14 +47394,24 @@ that contain up to 2,000 million rows in a validation regression database.
Many users of MySQL have contributed @emph{very} useful support
tools and add-ons.
-@ifclear web
-A list of what is available at @uref{http://www.mysql.com/Downloads/Contrib/}
+A list of what is available at
+@uref{http://www.mysql.com/Downloads/Contrib/}
(or any mirror) is shown below.
+
+Please visit our Software Portal at
+@uref{http://www.mysql.com/portal/software/}.
+The community facilities there also allow for your input!
+
If you want to build MySQL support for the Perl @code{DBI}/@code{DBD}
interface, you should fetch the @code{Data-Dumper}, @code{DBI}, and
@code{Msql-Mysql-modules} files and install them.
@xref{Perl support}.
-@end ifclear
+
+Note: The programs listed here can be freely downloaded and used.
+They are copyrighted by their respective owners.
+Please see each product documentation for more details on licensing and terms.
+MySQL AB assumes no liability for the correctness of the information in this
+chapter or for the proper operation of the programs listed herein.
@appendixsec APIs
@@ -45453,26 +47419,26 @@ interface, you should fetch the @code{Data-Dumper}, @code{DBI}, and
@itemize @bullet
@item Perl Modules
@itemize @minus
-@item @uref{http://www.mysql.com/Downloads/Contrib/Data-Dumper-2.101.tar.gz, Data-Dumper-2.101.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/Data-Dumper-2.101.tar.gz}
Perl @code{Data-Dumper} module. Useful with @code{DBI}/@code{DBD} support for
older Perl installations.
-@item @uref{http://www.mysql.com/Downloads/Contrib/DBI-1.15.tar.gz, DBI-1.15.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/DBI-1.18.tar.gz}
Perl @code{DBI} module.
-@item @uref{http://www.mysql.com/Downloads/Contrib/KAMXbase1.2.tar.gz,KAMXbase1.2.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/KAMXbase1.2.tar.gz}
Convert between @file{.dbf} files and MySQL tables. Perl
module written by Pratap Pereira @email{pereira@@ee.eng.ohio-state.edu},
extended by Kevin A. McGrail @email{kmcgrail@@digital1.peregrinehw.com}.
This converter can handle MEMO fields.
-@item @uref{http://www.mysql.com/Downloads/Contrib/Msql-Mysql-modules-1.2216.tar.gz, Msql-Mysql-modules-1.2216.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/Msql-Mysql-modules-1.2218.tar.gz}
Perl @code{DBD} module to access mSQL and MySQL databases.
-@item @uref{http://www.mysql.com/Downloads/Contrib/Data-ShowTable-3.3.tar.gz, Data-ShowTable-3.3.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/Data-ShowTable-3.3.tar.gz}
Perl @code{Data-ShowTable} module. Useful with @code{DBI}/@code{DBD} support.
-@item @uref{http://www.mysql.com/Downloads/Contrib/HandySQL-1.1.tar.gz, HandySQL-1.1.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/HandySQL-1.1.tar.gz}
HandySQL is a MySQL access module. It offers a C interface embedded in Perl and is
approximately 20% faster than regular DBI.
@@ -45481,12 +47447,12 @@ approximately 20% faster than regular DBI.
@cindex JDBC
@item JDBC
@itemize @bullet
-@item @uref{http://www.mysql.com/Downloads/Contrib/mm.mysql.jdbc-1.2c.tar.gz, mm.mysql.jdbc-1.2c.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mm.mysql.jdbc-1.2c.tar.gz}
The mm JDBC driver for MySQL. This is a production release
and is actively developed. By Mark Matthews
(@email{mmatthew@@ecn.purdue.edu}).
-@item @uref{http://www.mysql.com/Downloads/Contrib/mm.mysql.jdbc-2.0pre5.tar.gz, mm.mysql.jdbc-2.0pre5.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mm.mysql.jdbc-2.0pre5.tar.gz}
The mm JDBC driver for MySQL. This is a pre-release beta version
and is actively developed. By Mark Matthews
(@email{mmatthew@@ecn.purdue.edu}).
@@ -45495,17 +47461,17 @@ license. Please check @uref{http://www.worldserver.com/mm.mysql/} for
the latest drivers (and other JDBC information) because these drivers may be out of date.
@item @uref{http://www.caucho.com/projects/jdbc-mysql/index.xtp}
-The Resin commercial JDBC driver, which is released under open source.
+The Resin commercial JDBC driver, which is released under Open Source.
It claims to be faster than the mm driver, but we haven't received that much
information about this yet.
-@item @uref{http://www.mysql.com/Downloads/Contrib/twz1jdbcForMysql-1.0.4-GA.tar.gz, twz1jdbcForMysql-1.0.4-GA.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/twz1jdbcForMysql-1.0.4-GA.tar.gz}
The twz driver: A type 4 JDBC driver by Terrence W. Zellers
@email{zellert@@voicenet.com}. This is commercial but is free for
private and educational use. (Not supported anymore.)
@c no answer from server 990830
@c You can always find the latest driver at @uref{http://www.voicenet.com/~zellert/tjFM/}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/pmdamysql.tgz,pmdamysql.tgz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/pmdamysql.tgz}
A MySQL PMDA. Provides MySQL server status and configuration
variables.
@end itemize
@@ -45513,15 +47479,15 @@ variables.
@cindex OLEDB
@item OLEDB
@itemize @bullet
-@item @uref{http://www.mysql.com/Downloads/Win32/MyOLEDB.exe, MyOLEDB.exe}
-OLEDB handler for MySQL. By SWsoft.
-@item @uref{http://www.mysql.com/Downloads/Win32/MySamples.zip, MySamples.zip}
-Examples and documentation for MyOLEDB. By SWsoft.
-@item @uref{http://www.mysql.com/Downloads/Win32/Myoledb.zip, Myoledb.zip}
-Source for MyOLEDB. By SWsoft.
-@item @uref{http://www.mysql.com/Downloads/Win32/MyOLEDB.chm, MyOLEDB.chm}
+@item @uref{http://www.mysql.com/Downloads/Win32/MyOLEDB3.exe}
+MyOLEDB 3.0 installation package from SWSoft.
+@item @uref{http://www.mysql.com/Downloads/Win32/mysql-oledb-3.0.0.zip}
+Source for MyOLEDB 3.0.
+@item @uref{http://www.mysql.com/Downloads/Win32/MySamples.zip}
+Examples and documentation for MyOLEDB.
+@item @uref{http://www.mysql.com/Downloads/Win32/MyOLEDB.chm}
Help files for MyOLEDB.
-@item @uref{http://www.mysql.com/Downloads/Win32/libmyodbc.zip, libmyodbc.zip}
+@item @uref{http://www.mysql.com/Downloads/Win32/libmyodbc.zip}
Static MyODBC library used for build MyOLEDB. Based on MyODBC code.
@end itemize
@@ -45529,83 +47495,83 @@ Static MyODBC library used for build MyOLEDB. Based on MyODBC code.
@item C++
@itemize @bullet
-@item @uref{http://www.mysql.com/Downloads/Contrib/mysql-c++-0.02.tar.gz, mysql-c++-0.02.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql-c++-0.02.tar.gz}
MySQL C++ wrapper library. By Roland Haenel,
@email{rh@@ginster.net}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/MyDAO.tar.gz, MyDAO}
+@item @uref{http://www.mysql.com/Downloads/Contrib/MyDAO.tar.gz}
MySQL C++ API. By Satish @email{spitfire@@pn3.vsnl.net.in}. Inspired
by Roland Haenel's C++ API and Ed Carp's MyC library.
-@item @uref{http://www.mysql.com/download_mysql++.html, mysql++}
-MySQL C++ API (More than just a wrapper library.) Originally by
+@item @uref{http://www.mysql.com/download_mysql++.html}
+MySQL C++ API (more than just a wrapper library). Originally by
@email{kevina@@clark.net}. Nowadays maintained by Sinisa at MySQL AB.
-@item @uref{http://nelsonjr.homepage.com/NJrAPI,NJrAPI}
+@item @uref{http://nelsonjr.homepage.com/NJrAPI/}
A C++ database independent library that supports MySQL.
@end itemize
@cindex Delphi
@item Delphi
@itemize @bullet
-@item @uref{http://www.mysql.com/Downloads/Contrib/delphi-interface.gz, delphi-interface.gz}
-Delphi interface to @code{libmysql.dll}, by Blestan Tabakov,
-@email{root@@tdg.bis.bg}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/DelphiMySQL2.zip, DelphiMySQL2.zip}
+@item @uref{http://www.mysql.com/Downloads/Contrib/DelphiMySQL2.zip}
Delphi interface to @code{libmysql.dll}, by @email{bsilva@@umesd.k12.or.us}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/Udmysel.pas, Udmysql.pas}
+@item @uref{http://www.mysql.com/Downloads/Contrib/Udmysql.pas}
A wrapper for libmysql.dll for usage in Delphi. By Reiner Sombrowsky.
-@item @uref{http://www.fichtner.net/delphi/mysql.delphi.phtml, A Delphi interface to MySQL.}
-With source code. By Matthias Fichtner.
+@item @uref{http://www.fichtner.net/delphi/mysql.delphi.phtml}
+A Delphi Interface to MySQL, with source code. By Matthias Fichtner.
-@item @uref{http://www.productivity.org/projects/tmysql/, @strong{TmySQL}
-A library to use MySQL with Delphi}.
+@item @uref{http://www.productivity.org/projects/tmysql/}
+@code{TmySQL}, a library to use MySQL with Delphi.
-@item @uref{http://www.geocities.com/CapeCanaveral/2064/mysql.html, Delphi TDataset-component}.
-@item
-@item @uref{http://www.mysql.com/Downloads/Contrib/Win32/SBMySQL50Share.exe, Delphi 5 Shareware MySQL Dataset Components}
+@item @uref{https://sourceforge.net/projects/zeoslib/}
+Zeos Library is a set of delphi native datasets and database
+components for MySql, PostgreSql, Interbase, MS SQL, Oracle,
+DB/2. Also it includes development tools such as Database
+Explorer and Database Designer.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/Win32/SBMySQL50Share.exe}
+Delphi 5 Shareware MySQL Dataset Components.
@end itemize
-@item @uref{http://www.mysql.com/Downloads/Contrib/mysql-ruby-2.2.0.tar.gz, mysql-ruby-2.2.0.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql-ruby-2.2.0.tar.gz}
MySQL Ruby module. By TOMITA Masahiro @email{tommy@@tmtm.org}
-@uref{http://www.netlab.co.jp/ruby/. Ruby} is an Object-Oriented Interpreter Language.
+Ruby is an Object-Oriented Interpreter Language
+(@uref{http://www.netlab.co.jp/ruby/}).
-@item @uref{http://www.mysql.com/Downloads/Contrib/JdmMysqlDriver-0.1.0.tar.gz,JdmMysqlDriver-0.1.0.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/JdmMysqlDriver-0.1.0.tar.gz}
A VisualWorks 3.0 Smalltalk driver for MySQL. By
@email{joshmiller@@earthlink.net}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/Db.py, Db.py}
+@item @uref{http://www.mysql.com/Downloads/Contrib/Db.py}
Python module with caching. By @email{gandalf@@rosmail.com}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/MySQLmodule-1.4.tar.gz, MySQLmodule-1.4.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/MySQLmodule-1.4.tar.gz}
Python interface for MySQL. By Joseph Skinner @email{joe@@earthlight.co.nz}. Modified by Joerg Senekowitsch @email{senekow@@ibm.net}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/MySQL-python-0.3.0.tar.gz, MySQL-python-0.3.0.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/MySQL-python-0.3.0.tar.gz}
MySQLdb Python is an DB-API v2.0-compliant interface to MySQL. Transactions
are supported if the server and tables support them. It is
-thread-safe, and contains a compatibility module for older code
+thread safe, and contains a compatibility module for older code
written for the no-longer-maintained MySQLmodule interface.
-@item @uref{http://www.mysql.com/Downloads/Contrib/mysql_mex_12.tar.gz, mysql_mex_1_12.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql_mex_12.tar.gz}
An interface program for the Matlab program by MathWorks. The interface
is done by Kimmo Uutela and John Fisher (not by Mathworks).
-Check @uref{http://boojum.hut.fi/~kuutela/mysqlmex.html,mysqlmex.html}
+Check @uref{http://boojum.hut.fi/~kuutela/mysqlmex.html}
for more information.
-@item @uref{http://www.mysql.com/Downloads/Contrib/mysqltcl-1.53.tar.gz, mysqltcl-1.53.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysqltcl-1.53.tar.gz}
Tcl interface for MySQL. Based on @file{msqltcl-1.50.tar.gz}.
Updated by Tobias Ritzau, @email{tobri@@ida.liu.se}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/MyC-0.1.tar.gz, MyC-0.1.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/MyC-0.1.tar.gz}
A Visual Basic-like API, by Ed Carp.
-@item @uref{http://www.mysql.com/Downloads/Contrib/sqlscreens-1.0.1.tar.gz, sqlscreens-1.0.1.tar.gz}
-Tcl/Tk code to generate database screens. By Jean-Francois Dockes.
-
-@item @uref{http://www.mysql.com/Downloads/Contrib/Vdb-dflts-2.1.tar.gz, Vdb-dflts-2.1.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/Vdb-dflts-2.1.tar.gz}
This is a new version of a set of library utilities intended
to provide a generic interface to SQL database engines such that your
application becomes a 3-tiered application. The advantage is that you
@@ -45613,60 +47579,60 @@ can easily switch between and move to other database engines by
implementing one file for the new backend without making any
changes to your applications. By @email{damian@@cablenet.net}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/DbFramework-1.10.tar.gz, DbFramework-1.10.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/DbFramework-1.10.tar.gz}
DbFramework is a collection of classes for manipulating MySQL
databases. The classes are loosely based on the CDIF Data Model
Subject Area. By Paul Sharpe @email{paul@@miraclefish.com}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/pike-mysql-1.4.tar.gz, pike-mysql-1.4.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/pike-mysql-1.4.tar.gz}
MySQL module for pike. For use with the Roxen web server.
-@item @uref{http://www.mysql.com/Downloads/Contrib/squile.tar.gz, squile.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/squile.tar.gz}
Module for @code{guile} that allows @code{guile} to interact with SQL
databases. By Hal Roberts.
-@item @uref{http://www.mysql.com/Downloads/Contrib/stk-mysql.tar.gz, stk-mysql.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/stk-mysql.tar.gz}
Interface for Stk. Stk is the Tk widgets with Scheme underneath instead of Tcl.
By Terry Jones.
-@item @uref{http://www.mysql.com/Downloads/Contrib/eiffel-wrapper-1.0.tar.gz,eiffel-wrapper-1.0.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/eiffel-wrapper-1.0.tar.gz}
Eiffel wrapper by Michael Ravits.
-@item @uref{http://www.mysql.com/Downloads/Contrib/SQLmy0.06.tgz,SQLmy0.06.tgz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/SQLmy0.06.tgz}
FlagShip Replaceable Database Driver (RDD) for MySQL. By Alejandro
Fernandez Herrero.
-@uref{http://www.fship.com/rdds.html, Flagship RDD home page}
+The Flagship RDD homepage is at @uref{http://www.fship.com/rdds.html}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/mydsn-1.0.zip,mydsn-1.0.zip}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mydsn-1.0.zip}
Binary and source for @code{mydsn.dll}. mydsn should be used to build
and remove the DSN registry file for the MyODBC driver in Coldfusion
applications. By Miguel Angel Solórzano.
-@item @uref{http://www.mysql.com/Downloads/Contrib/MySQL-ADA95_API.zip, MySQL-ADA95_API.zip}
+@item @uref{http://www.mysql.com/Downloads/Contrib/MySQL-ADA95_API.zip}
An ADA95 interface to the MySQL API. By Francois Fabien.
-@item @uref{http://www.mysql.com/Downloads/Contrib/MyTool-DLL_for_VB_and_MySQL.zip, MyTool-DLL_for_VB_and_MySQL.zip}
-A DLL with MySQL C API for Visual Basic.
+@item @uref{http://www.mysql.com/Downloads/Contrib/MyTool-DLL_for_VB_and_MySQL.zip}
+A DLL with MySQL C API for Visual Basic.
By Ken Menzel @email{kenm@@icarz.com}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/MYSQLX.EXE, MYSQL.EXE}
+@item @uref{http://www.mysql.com/Downloads/Contrib/MYSQLX.EXE}
MySQL ActiveX Object for directly accessing your MySQL
-servers from IIS/ASP, VB, VC++ skipping the slower ODBC methods. Fully
-updatable, multithreaded with full support for all MySQL fieldtypes
+servers from IIS/ASP, VB, VC++ skipping the slower ODBC methods. Fully
+updatable, multithreaded with full support for all MySQL fieldtypes
(version 2001.1.1). By SciBit @uref{http://www.scibit.com/}.
-@item @uref{http://www.fastflow.it/mylua/, MyLUA home page}
-How to use the LUA language to write MySQL @code{PROCEDURE} that can
-be loaded runtime.
+@item @uref{http://www.fastflow.it/mylua/}
+MyLUA home page; how to use the LUA language to write MySQL
+@code{PROCEDURE} that can be loaded runtime.
@itemize @bullet
-@item @uref{http://www.mysql.com/Downloads/Contrib/lua-4.0.tar.gz, Lua 4.0}
+@item @uref{http://www.mysql.com/Downloads/Contrib/lua-4.0.tar.gz}
LUA 4.0
-@item @uref{http://www.mysql.com/Downloads/Contrib/mylua-3.23.32.1.tar.gz, mylua-3.23.32.1.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mylua-3.23.32.1.tar.gz}
Patch for MySQL 3.23.32 to use LUA 4.0. By Cristian Giussani.
@end itemize
-@item @uref{http://www.mysql.com/Downloads/Contrib/patched_myodbc.zip, patched_myodbc.zip}
+@item @uref{http://www.mysql.com/Downloads/Contrib/patched_myodbc.zip}
Patch (for Omniform 4.0 support) to the MyODBC driver.
By Thomas Thaele @email{tthaele@@papenmeier.de}
@@ -45677,59 +47643,61 @@ By Thomas Thaele @email{tthaele@@papenmeier.de}
@itemize @bullet
@item Graphical clients
@itemize @minus
-@item @uref{http://www.ideit.com/products/dbvis/, DbVisualizer}.
-Freeware JDBC client to graphically visualize the data and structure
-of several databases simultaneously. By Innovative-IT Development AB.
+@item @uref{http://www.ideit.com/products/dbvis/}
+DbVisualizer, a freeware JDBC client to graphically visualise
+the data and structure of several databases simultaneously.
+By Innovative-IT Development AB.
-@item @uref{http://www.mysql.com/downloads/gui-clients.html, MySQLGUI}
-The MySQL GUI client homepage. By Sinisa at MySQL AB.
+@item @uref{http://www.mysql.com/downloads/gui-clients.html}
+MySQLGUI, the MySQL GUI client homepage. By Sinisa at MySQL AB.
-@item @uref{http://www.mysql.com/Downloads/Contrib/mysql_navigator_0.9.0.tar.gz, MySQL navigator 0.9}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql_navigator_0.9.0.tar.gz}
MySQL Navigator is a MySQL database server GUI client program. The purpose
of MySQL Navigator is to provide a useful client interface to MySQL
database servers, whilst supporting multiple operating systems and
languages. You can currently import/export database, enter queries, get
result sets, edit scripts, run scripts, add, alter, and delete users,
and retrieve client and server information. Uses QT 2.2. GPL
-@uref{http://sql.kldp.org/mysql, Home page for MySQL Navigator}.
+The homepage for MySQL Navigator is at @uref{http://sql.kldp.org/mysql/}.
-@item @uref{http://www.mysql.com/Downloads/Win32/secman.zip, MySQL Security GUI}
-A user and security management GUI for MySQL on Windows.
+@item @uref{http://www.mysql.com/Downloads/Win32/secman.zip}
+A user and security management GUI for MySQL on Windows.
By Martin Jeremic.
-@uref{http://jsoft.webjump.com/, Home page for MySQL Security GUI}.
+The homepage for MySQL Security GUI is at @uref{http://jsoft.webjump.com/}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/kmysqladmin-0.4.1.tar.gz, kmysqladmin-0.4.1.tar.gz}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/kmysqladmin-0.4.1-1.src.rpm, kmysqladmin-0.4.1-1.src.rpm}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/kmysqladmin-0.4.1-1.i386.rpm, kmysqladmin-0.4.1-1.i386.rpm}
+@item @uref{http://www.mysql.com/Downloads/Contrib/kmysqladmin-0.4.1.tar.gz}.
+@item @uref{http://www.mysql.com/Downloads/Contrib/kmysqladmin-0.4.1-1.src.rpm}.
+@item @uref{http://www.mysql.com/Downloads/Contrib/kmysqladmin-0.4.1-1.i386.rpm}
An administration tool for the MySQL server using QT / KDE. Tested
only on Linux.
-@item @uref{http://www.mysql.com/Downloads/Contrib/mysql-admin-using-java+swing.tar.gz, Java client using Swing} By Fredy Fischer, @email{se-afs@@dial.eunet.ch}.
-You can always find the latest version
-@uref{http://www.trash.net/~ffischer/admin/index.html, here}.
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql-admin-using-java+swing.tar.gz}
+Java client using Swing, by Fredy Fischer (@email{se-afs@@dial.eunet.ch}).
+You can always find the latest version at
+@uref{http://www.trash.net/~ffischer/admin/}.
-@item @uref{http://www.mysql.com/Downloads/Win32/MySQL-Maker-1.0.zip,MySQL-Maker 1.0}.
+@item @uref{http://www.mysql.com/Downloads/Win32/MySQL-Maker-1.0.zip}.
Shareware MySQL client for Windows. It's a WYSIWYG tool which allows
you to create, change and delete databases and tables.
You can change field - structure and add, change and delete data in
these tables directly without ODBC-driver.
-@uref{http://www.presult.de/presult/frames/fs_mysqlmaker.html, MySQL Maker homepage}
+The MySQL Maker homepage is at @uref{http://www.presult.de/presult/frames/fs_mysqlmaker.html}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/mysqlwinadmn.zip, mysqlwinadmn.zip}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysqlwinadmn.zip}
Windows GUI (binary only) to administrate a database, by David B. Mansel,
@email{david@@zhadum.org}.
-@item @uref{http://home.online.no/~runeberg/myqa, MyQA}
-is a Linux-based query client for the MySQL database server. MyQA
+@item @uref{http://home.online.no/~runeberg/myqa/}
+MyQA is a Linux-based query client for the MySQL database server. MyQA
lets you enter SQL queries, execute them, and view the results, all in a
graphical user interface. The GUI is roughly similar to that of the
'Query Analyzer' client that comes with MS SQL Server.
-@item @uref{http://members.xoom.com/_opex_/mysqlmanager/index.html, MySQL Manager}
-a graphical MySQL server manager for MySQL server written in Java, for Windows
-
+@item @uref{http://www.opex.atnet.ru/mysqlmanager/}
+MySQL Manager is a graphical MySQL server manager for MySQL server
+written in Java.
-@item @uref{http://www.mysql.com/Downloads/Win32/netadmin.zip, netadmin.zip}
+@item @uref{http://www.mysql.com/Downloads/Win32/netadmin.zip}
An administrator tool for MySQL on Windows 95/98 and Windows NT
4.0. Only tested with MySQL Versions 3.23.5 - 3.23.7. Written
using the Tmysql components.
@@ -45738,68 +47706,74 @@ You can write queries and show tables, indexes, table syntax, and
administrate user, host, and database and so on. This is beta and
still has some bugs. You can test the program with all features. Please
send bugs and hints to Marco Suess @email{ms@@it-netservice.de}. Original
-URL @url{http://www.it-netservice.de/pages/software/index.html}.
+URL @uref{http://www.it-netservice.de/pages/software/}.
-@item @uref{http://www.mysql.com/Downloads/Win32/netadmin2.zip, netadmin2.zip}
+@item @uref{http://www.mysql.com/Downloads/Win32/netadmin2.zip}
New version of netadmin. See above for details.
-@item @uref{http://www.mysql.com/Downloads/Win32/ARTADMIN203.EXE,Atronic's MySQL client for Windows 2.0.3.0}.
-Home page for this can be found at: @uref{http://www.artronic.hr}.
+@item @uref{http://www.mysql.com/Downloads/Win32/ARTADMIN203.EXE}
+Atronic's MySQL client for Windows 2.0.3.0.
+The home page for this can be found at @uref{http://www.artronic.hr/}.
-@item @uref{http://www.mysql.com/Downloads/Win32/mysqlfront.zip, mysqlfront}
-Home page: @uref{http://www.mysqlfront.de/}.
-Win32-Client for accessing and managing dbs, tables, table-data, indexes,
-import-/export-files. (Freeware). By Ansgar Becker.
+@item @uref{http://www.mysql.com/Downloads/Win32/W9xstop.zip}
+Utility from Artronic to stop MySQL on win9x.
-@item @uref{http://www.mysql.com/Downloads/Win32/W9xstop.zip,Utility from Artronic to stop MySQL on win9x}.
+@item @uref{http://bardo.hyperlink.cz/mysqlmon/}
+A light weight GUI client for Windows.
-@item @uref{http://bardo.hyperlink.cz/mysqlmon,a light weight GUI client for Windows}.
+@item @uref{http://www.mysqlfront.de/}
+MySQLfront is a very nice Windows client with lots of useful features.
+By Angsar Becker.
-@item @uref{http://dbtools.vila.bol.com.br/, Dbtools}
-A tool to manage MySQL databases. Currently only for Windows.
+@item @uref{http://www.dbtools.com.br/}
+Dbtools, a tool to manage MySQL databases. Currently only for Windows.
Some features:
@itemize @bullet
@item Manage servers, databases, tables, columns, indexes, and users
@item Import wizard to import structure and data from MS Access, MS Excel, Dbase, FoxPro, Paradox, and ODBC Databases.
-@item @uref{http://www.mysql.com/Downloads/Contrib/KMYENG113.zip,KMYENG113.zip}
-An administrator GUI for MySQL. Works only on windows, no source.
+@item @uref{http://www.mysql.com/Downloads/Contrib/KMYENG113.zip}
+An administrator GUI for MySQL. Works only on Windows, no source.
Available in English and Japanese. By Mitunobu Kaneko.
Home page: @uref{http://sql.jnts.ne.jp/}
@end itemize
-@item @uref{http://www.mysql.com/Downloads/Contrib/xmysqladmin-1.0.tar.gz, xmysqladmin-1.0.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/xmysqladmin-1.0.tar.gz}
An X-based front end to the MySQL database engine. It allows reloads,
status check, process control, myisamchk, grant/revoke privileges,
creating databases, dropping databases, create, alter, browse, and drop
tables. Originally by Gilbert Therrien, @email{gilbert@@ican.net} but
now in public domain and supported by MySQL AB.
-@item @uref{http://www.mysql.com/Downloads/Contrib/xmysql-1.9.tar.gz, xmysql-1.9.tar.gz}.
-@item @uref{http://web.wt.net/~dblhack, xmysql home page}
-A front end to the MySQL database engine. It allows for simple
+@item @uref{http://www.mysql.com/Downloads/Contrib/xmysql-1.9.tar.gz}.
+xmysqlA front end to the MySQL database engine. It allows for simple
queries and table maintenance, as well as batch queries. By Rick
Mehalick, @email{dblhack@@wt.net}.
-Requires @uref{http://bragg.phys.uwm.edu/xforms,xforms 0.88} to work.
-@item @uref{http://www.tamos.net/sw/dbMetrix,dbMetrix}
-An open source client for exploring databases and executing SQL. Supports
-MySQL, Oracle, PostgreSQL, and mSQL.
-@item @uref{http://www.multimania.com/bbrox/GtkSQL,GtkSQL}
-A query tool for MySQL and PostgreSQL.
-@item @uref{http://dbman.linux.cz/,dbMan}
-A query tool written in Perl. Uses DBI and Tk.
-@item @uref{http://www.mysql.com/Downloads/Win32/Msc201.EXE, Mascon 202}
-@item @uref{http://www.mysql.com/Downloads/Win32/FrMsc202.EXE, Free Mascon 202}
+The xmysql homepage is at @uref{http://web.wt.net/~dblhack/}
+Requires @uref{http://bragg.phys.uwm.edu/xforms/} (xforms 0.88) to work.
+
+@item @uref{http://www.tamos.net/sw/dbMetrix/}
+dbMatrix is an Open Source client for exploring databases and executing
+SQL. Supports MySQL, Oracle, PostgreSQL, and mSQL.
+
+@item @uref{http://www.multimania.com/bbrox/GtkSQL/}
+GtkSQL is a query tool for MySQL and PostgreSQL.
+
+@item @uref{http://dbman.linux.cz/}
+dbMan is a query tool written in Perl. Uses DBI and Tk.
+
+@item @uref{http://www.mysql.com/Downloads/Win32/Msc201.EXE} (Mascon 202)
+@item @uref{http://www.mysql.com/Downloads/Win32/FrMsc202.EXE} (Free Mascon 202)
Mascon is a powerful Win32 GUI for the administering MySQL server
databases. Mascon's features include visual table design, connections to
multiple servers, data and blob editing of tables, security setting, SQL
color coding, dump functionality and much more.
-@uref{http://www.scibit.com/Products/Software/Utils/Mascon.asp,Mascon home page}.
-@item @uref{http://www.virtualbeer.net/dbui/,DBUI}
+The Mascon homepage is at @uref{http://www.scibit.com/Products/Software/Utils/Mascon.asp}.
+@item @uref{http://www.virtualbeer.net/dbui/}
DBUI is a Gtk graphical database editor.
-@item @uref{http://www.rtlabs.com/, MacSQL}
-GUI for MySQL, ODBC, and JDBC databases for the Mac OS.
-@item @uref{http://www.caleb.com.au/, JRetriever}
+@item @uref{http://www.rtlabs.com/}
+MacSQL is a GUI for MySQL, ODBC, and JDBC databases for the Mac OS.
+@item @uref{http://www.caleb.com.au/}
JRetriever is a generic database front-end tool for JDBC compliant
databases written with Java 2. JRetriever displays database
tables/views in a Windows explorer-like front end. Users can retrieve
@@ -45807,18 +47781,18 @@ data either by clicking on the table folder or by composing their own SQL
statements with our built-in SQL editor. The tool has been tested with
Oracle 8 and MySQL as the back-end databases. It requires JDK 1.3 from
JavaSoft.
-@item @uref{http://www.jetools.com/products/databrowser/, DataBrowser}
+@item @uref{http://www.jetools.com/products/databrowser/}
The DataBrowser is a cross-database, cross-platform data access tool. It is more
user friendly than tools like SQL Plus, psql (command line based tools). It is more
flexible than TOAD, ISQL, PGAccess which are GUI's that are limitied to a single
platform or database.
-@item @uref{http://www.intrex.net/amit/software/, SQLC}
+@item @uref{http://www.intrex.net/amit/software/}
The SQL Console is a standalone java application that allows you to connect to a
SQL database system and issue SQL queries and updates. It has an easy-to use
graphical user interface. The SQL Console uses JDBC to connect to the database
systems and, therefore, with proper JDBC drivers, you can use this utility to
-connect to some of the most popular database systems.
-@item @uref{http://www.mysql.com/Downloads/Contrib/mysql_mmc.zip, MySQL MMC}
+connect to some of the most popular database systems.
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql_mmc.zip}
MySQL MMC is a GUI Management Tool developed using kdevelop
with a very good interface completely like Microsoft
Enterprise Tool (for SQL Server) or Sybase Central. We
@@ -45830,52 +47804,52 @@ by Query Analysis.
@cindex Web clients
@item Web Clients
@itemize @minus
-@item @uref{http://www.mysql.com/Downloads/Contrib/mysqladmin-atif-1.0.tar.gz, mysqladmin-atif-1.0.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysqladmin-atif-1.0.tar.gz}
WWW MySQL administrator for the @code{user,} @code{db} and
@code{host} tables. By Tim Sailer, modified by Atif Ghaffar
@email{aghaffar@@artemedia.ch}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/mysql-webadmin-1.0a8-rz.tar.gz, mysql-webadmin-1.0a8-rz.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql-webadmin-1.0a8-rz.tar.gz}
A tool written in PHP-FI to administrate MySQL databases
remotely over the web within a Web-Browser. By Peter Kuppelwieser,
@email{peter.kuppelwieser@@kantea.it}. Updated by Wim Bonis,
@email{bonis@@kiss.de}. Not maintained anymore!
-@item @uref{http://www.mysql.com/Downloads/Contrib/mysqladm.tar.gz, mysqladm.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysqladm.tar.gz}
MySQL Web Database Administration written in Perl. By Tim Sailer.
-@item @uref{http://www.mysql.com/Downloads/Contrib/mysqladm-2.tar.gz, mysqladm-2.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysqladm-2.tar.gz}
Updated version of @file{mysqladm.tar.gz}, by High Tide.
-@item @uref{http://www.mysql.com/Downloads/Contrib/billowmysql.zip, billowmysql.zip}
+@item @uref{http://www.mysql.com/Downloads/Contrib/billowmysql.zip}
Updated version of @file{mysqladm.tar.gz}, by Ying Gao. You can get the
-newest version from @uref{http://civeng.com/sqldemo/, the home site}.
+newest version from @uref{http://civeng.com/sqldemo/} (the home site).
-@item @uref{http://www.mysql.com/Downloads/Contrib/myadmin-0.4.tar.gz, myadmin-0.4.tar.gz}.
-@item @uref{http://myadmin.cheapnet.net/, MyAdmin home page}
-A Web-based MySQL administrator by Mike Machado.
+@item @uref{http://www.mysql.com/Downloads/Contrib/myadmin-0.4.tar.gz}.
+MyAdmin is a web-based MySQL administrator by Mike Machado.
+TheMyAdmin homepage is at @uref{http://myadmin.cheapnet.net/}
-@item @uref{http://www.mysql.com/Downloads/Contrib/phpMyAdmin_2.0.1.tar.gz,phpMyAdmin_2.0.1.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/phpMyAdmin_2.2.0.tar.gz}
A set of PHP3-scripts to adminstrate MySQL over the WWW.
-@item @uref{http://www.phpwizard.net/projects/phpMyAdmin/, phpMyAdmin home page}
-A PHP3 tool in the spirit of mysql-webadmin, by Tobias Ratschiller, tobias@@dnet.it.
+@item @uref{http://www.phpwizard.net/projects/phpMyAdmin/}
+phpMyAdmin is a PHP3 tool in the spirit of mysql-webadmin, by Tobias Ratschiller, tobias@@dnet.it.
-@item @uref{http://www.mysql.com/Downloads/Contrib/useradm.tar.gz, useradm.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/useradm.tar.gz}
MySQL administrator in PHP. By Ofni Thomas
@email{othomas@@vaidsystems.com}.
-@item @uref{http://gossamer-threads.com/perl/mysqlman/mysql.cgi, MySQLMan}
-Similar functionality as phpmyadmin, but written with Perl and using
-html templates. By Alex Krohn.
+@item @uref{http://gossamer-threads.com/perl/mysqlman/mysql.cgi}
+MySQLMan has similar functionality to phpmyadmin, but written with
+Perl and using html templates. By Alex Krohn.
@end itemize
-@item @uref{http://www.mysql.com/Downloads/Contrib/mysql-editor.tar.gz,mysql-editor.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql-editor.tar.gz}
This cgi scripts in Perl enables you to edit content of Mysql
database. By Tomas Zeman.
-@item
-@uref{http://worldcommunity.com/opensource/futuresql, FutureSQL Web Database Administration Tool}.
-FutureSQL by Peter F. Brown, is a free, open source rapid application
+
+@item @uref{http://worldcommunity.com/opensource/futuresql/}
+FutureSQL by Peter F. Brown, is a free, Open Source rapid application
development Web database administration tool, written in Perl,
using MySQL. It uses @code{DBI:DBD} and @code{CGI.pm}.
@@ -45891,12 +47865,13 @@ and "post-processing" on both fields, records, and operations.
@itemize @bullet
-@item @uref{http://www.mysql.com/Downloads/Contrib/mod_mysql_include_1.0.tar.gz, mod_mysql_include_1.0.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mod_mysql_include_1.0.tar.gz}
Apache module to include HTML from MySQL queries into your pages,
and run update queries. Originally written to implement a simple fast
low-overhead banner-rotation system. By Sasha Pachev.
-@item @uref{http://htcheck.sourceforge.net, htCheck} - URL checker with
+@item @uref{http://htcheck.sourceforge.net/}
+htCheck is a URL checker with
MySQL backend. Spidered URLs can later be queried using SQL to retrieve
various kinds of information, eg. broken links. Written by Gabriele Bartolini.
@@ -45907,35 +47882,35 @@ Update, Delete) from an html form. You can build a complete forms
interface to a SQL database (query, add, update, delete) without any
programming! By Marc Beneteau, @email{marc@@odbsoft.com}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/sqlhtml.tar.gz, sqlhtml.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/sqlhtml.tar.gz}
SQL/HTML is an HTML database manager for MySQL using @code{DBI} 1.06.
-@item @uref{http://www.mysql.com/Downloads/Contrib/udmsearch-3.0.23.tar.gz, UdmSearch 3.0.23 (stable version)}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/mnogosearch-3.1.12.tar.gz, mnogosearch 3.1.12 (development but recommended version)}.
-@item @uref{http://search.mnoGo.ru, UdmSearch home page}
+@item @uref{http://www.mysql.com/Downloads/Contrib/udmsearch-3.0.23.tar.gz} (UdmSearch 3.0.23, stable version).
+@item @uref{http://www.mysql.com/Downloads/Contrib/mnogosearch-3.1.12.tar.gz} (mnogosearch 3.1.12, development but recommended version)
+@item @uref{http://search.mnoGo.ru/} (UdmSearch home page)
A SQL-based search engine for Internet. By
Alexander I. Barkov @email{bar@@izhcom.ru}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/wmtcl.doc, wmtcl.doc}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/wmtcl.lex, wmtcl.lex}
+@item @uref{http://www.mysql.com/Downloads/Contrib/wmtcl.doc}
+@item @uref{http://www.mysql.com/Downloads/Contrib/wmtcl.lex}
With this you can write HTML files with inclusions of Tcl code. By
@email{vvs@@scil.npi.msu.su}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/www-sql-0.5.7.lsm, www-sql-0.5.7.lsm}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/www-sql-0.5.7.tar.gz, www-sql-0.5.7.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/www-sql-0.5.7.lsm}
+@item @uref{http://www.mysql.com/Downloads/Contrib/www-sql-0.5.7.tar.gz}
A CGI program that parses an HTML file containing special tags, parses
them, and inserts data from a MySQL database.
-@item @uref{http://www.mysql.com/Downloads/Contrib/genquery.zip, genquery.zip}
+@item @uref{http://www.mysql.com/Downloads/Contrib/genquery.zip}
Perl SQL database interface package for html.
-@item @uref{http://www.mysql.com/Downloads/Contrib/cgi++-0.8.tar.gz, cgi++-0.8.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/cgi++-0.8.tar.gz}
A macro-processor to simply writing CGI/Database programs in C++ by Sasha Pachev.
-@item @uref{http://www.mysql.com/Downloads/Contrib/webboard-1.0.zip, WebBoard 1.0}
-EU-Industries Internet-Message-Board.
+@item @uref{http://www.mysql.com/Downloads/Contrib/webboard-1.0.zip}
+WebBoard 1.0, EU-Industries Internet-Message-Board.
-@item @uref{http://www.mysql.com/Downloads/Contrib/DBIx-TextIndex-0.02.tar.gz, DBIx-TextIndex-0.02.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/DBIx-TextIndex-0.02.tar.gz}
Full-text searching with Perl on @code{BLOB}/@code{TEXT} columns by Daniel Koch.
@end itemize
@@ -45944,9 +47919,8 @@ Full-text searching with Perl on @code{BLOB}/@code{TEXT} columns by Daniel Koch.
@appendixsec Performance Benchmarking Tools
@itemize @bullet
-@item @uref{http://www.mysql.com/Downloads/super-smack/super-smack-1.0.tar.gz,
- super-smack}
-Multi-threaded benchmarking tool for MySQL and
+@item @uref{http://www.mysql.com/Downloads/super-smack/super-smack-1.0.tar.gz}
+super-smack is a multi-threaded benchmarking tool for MySQL and
@strong{PostgreSQL}. Written in C++. Easy to extend to support other
databases that have C/C++ client libraries. By Sasha Pachev.
@end itemize
@@ -45956,61 +47930,56 @@ databases that have C/C++ client libraries. By Sasha Pachev.
@appendixsec Authentication Tools
@itemize @bullet
-@item @uref{http://www.mysql.com/Downloads/Contrib/ascend-radius-mysql-0.7.2.patch.gz,ascend-radius-mysql-0.7.2.patch.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/ascend-radius-mysql-0.7.2.patch.gz}
This is an authentication and logging patch using MySQL for
Ascend-Radius. By @email{takeshi@@SoftAgency.co.jp}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/icradius-0.10.tar.gz, icradius 0.10}
-@uref{http://www.mysql.com/Downloads/Contrib/icradius.README, icradius readme file}.
+@item @uref{http://www.mysql.com/Downloads/Contrib/icradius-0.10.tar.gz} (icradius 0.10)
+@uref{http://www.mysql.com/Downloads/Contrib/icradius.README} (icradius readme)
-@item @uref{http://www.mysql.com/Downloads/Contrib/checkpassword-0.81-mysql-0.6.6.patch.gz,
-checkpassword-0.81-mysql-0.6.6.patch.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/checkpassword-0.81-mysql-0.6.6.patch.gz}
MySQL authentication patch for QMAIL and checkpassword. These are
useful for management user (mail, pop account) by MySQL.
By @email{takeshi@@SoftAgency.co.jp}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/jradius-diff.gz, jradius-diff.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/jradius-diff.gz}
MySQL support for Livingston's Radius 2.01. Authentication and
Accounting. By Jose de Leon, @email{jdl@@thevision.net}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/mod_auth_mysql-2.20.tar.gz, mod_auth_mysql-2.20.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mod_auth_mysql-2.20.tar.gz}
Apache authentication module for MySQL. By Zeev Suraski,
@email{bourbon@@netvision.net.il}.
@c @strong{Please} register this module at:
-@c @url{http://bourbon.netvision.net.il/mysql/mod_auth_mysql/register.html}. The
+@c @uref{http://bourbon.netvision.net.il/mysql/mod_auth_mysql/register.html}. The
@c registering information is only used for statistical purposes and will
@c encourage further development of this module!
-@item @uref{http://www.mysql.com/Downloads/Contrib/mod_log_mysql-1.05.tar.gz, mod_log_mysql-1.05.tar.gz}
-MySQL logging module for Apache. By Zeev Suraski,
-@email{bourbon@@netvision.net.il}.
-
-@item @uref{http://www.mysql.com/Downloads/Contrib/mypasswd-2.0.tar.gz, mypasswd-2.0.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mypasswd-2.0.tar.gz}
Extra for @code{mod_auth_mysql}. This is a little tool that allows you
to add/change user records storing group and/or password entries in
MySQL tables. By Harry Brueckner, @email{brueckner@@respublica.de}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/mysql-passwd.README, mysql-passwd.README}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/mysql-passwd-1.2.tar.gz, mysql-passwd-1.2.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql-passwd.README}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql-passwd-1.2.tar.gz}
Extra for @code{mod_auth_mysql}. This is a two-part system for use with
@code{mod_auth_mysql}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/pam_mysql.tar.gz, pam_mysql.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/pam_mysql.tar.gz}
This module authenticates users via @code{pam}, using MySQL.
-@item @uref{http://www.mysql.com/Downloads/Contrib/nsapi_auth_mysql.tar, nsapi_auth_mysql.tar}
+@item @uref{http://www.mysql.com/Downloads/Contrib/nsapi_auth_mysql.tar}
Netscape Web Server API (NSAPI) functions to authenticate (BASIC) users
against MySQL tables. By Yuan John Jiang.
-@item @uref{http://www.mysql.com/Downloads/Contrib/qmail-1.03-mysql-0.6.6.patch.gz,qmail-1.03-mysql-0.6.6.patch.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/qmail-1.03-mysql-0.6.6.patch.gz}
Patch for qmail to authenticate users from a MySQL table.
By @email{takeshi@@SoftAgency.co.jp}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/proftpd-1.2.0rc2-fix-mysql.patch, proftpd-1.2.0rc2-fix-mysql.patch}
+@item @uref{http://www.mysql.com/Downloads/Contrib/proftpd-1.2.0rc2-fix-mysql.patch}
Patch for proftpd1.2.0rc2. By @email{takeshi@@SoftAgency.co.jp}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/pwcheck_mysql-0.1.tar.gz,pwcheck_mysql-0.1.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/pwcheck_mysql-0.1.tar.gz}
An authentication module for the Cyrus IMAP server. By Aaron Newsome.
@@ -46020,34 +47989,35 @@ An authentication module for the Cyrus IMAP server. By Aaron Newsome.
@appendixsec Converters
@itemize @bullet
-@item @uref{http://www.mysql.com/Downloads/Contrib/mssql2mysql.txt, mssql2mysql.txt}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mssql2mysql.txt}
Converter from MS-SQL to MySQL. By Michael Kofler.
-@uref{http://www.kofler.cc/mysql/mssql2mysql.html, mssql2mysql home page}.
+The mssql2mysql home page is at
+@uref{http://www.kofler.cc/mysql/mssql2mysql.html}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/dbf2mysql-1.14.tar.gz, dbf2mysql-1.14.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/dbf2mysql-1.14.tar.gz}
Convert between @file{.dbf} files and MySQL tables. By Maarten
Boekhold (@email{boekhold@@cindy.et.tudelft.nl}), William Volkman, and
Michael Widenius. This converter includes rudimentary read-only support
for MEMO fields.
-@item @uref{http://www.mysql.com/Downloads/Contrib/dbf2mysql-1.13.tgz, dbf2mysql-1.13.tgz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/dbf2mysql-1.13.tgz}
Convert between @file{.dbf} files and MySQL tables. By Maarten
Boekhold, @email{boekhold@@cindy.et.tudelft.nl}, and Michael Widenius.
This converter can't handle MEMO fields.
-@item @uref{http://www.mysql.com/Downloads/Contrib/dbf2mysql.zip, dbf2mysql.zip}
+@item @uref{http://www.mysql.com/Downloads/Contrib/dbf2mysql.zip}
Convert between FoxPro @file{.dbf} files and MySQL tables on Windows.
By Alexander Eltsyn, @email{ae@@nica.ru} or @email{ae@@usa.net}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/dbf2sql.zip, dbf2sql.zip}
+@item @uref{http://www.mysql.com/Downloads/Contrib/dbf2sql.zip}
Short and simple prg that can help you transport your data from foxpro
table into MySQL table. By Danko Josic.
-@item @uref{http://www.mysql.com/Downloads/Contrib/dump2h-1.20.gz, dump2h-1.20.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/dump2h-1.20.gz}
Convert from @code{mysqldump} output to a C header file. By Harry Brueckner,
@email{brueckner@@mail.respublica.de}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/exportsql.txt, exportsql.txt}
+@item @uref{http://www.mysql.com/Downloads/Contrib/exportsql.txt}
A script that is similar to @code{access_to_mysql.txt}, except that this
one is fully configurable, has better type conversion (including
detection of @code{TIMESTAMP} fields), provides warnings and suggestions
@@ -46057,28 +48027,29 @@ and is free of charge for anyone. See
@uref{http://www.cynergi.net/exportsql/} for the latest version. By
Pedro Freire, @email{support@@cynergi.net}. NOTE: Doesn't work with
Access2!
-@item @uref{http://www.mysql.com/Downloads/Contrib/access_to_mysql.txt, access_to_mysql.txt}
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/access_to_mysql.txt}
Paste this function into an Access module of a database that has the
tables you want to export. See also @code{exportsql}. By Brian Andrews.
NOTE: Doesn't work with Access2!
-@item @uref{http://www.mysql.com/Downloads/Contrib/importsql.txt, importsql.txt}
+@item @uref{http://www.mysql.com/Downloads/Contrib/importsql.txt}
A script that does the exact reverse of @code{exportsql.txt}. That is,
it imports data from MySQL into an Access database via
ODBC. This is very handy when combined with exportsql, because it lets you
-use Access for all DB design and administration, and synchronize with
+use Access for all DB design and administration, and synchronise with
your actual MySQL server either way. Free of charge. See
@uref{http://www.netdive.com/freebies/importsql/} for any updates.
Created by Laurent Bossavit of NetDIVE.
@strong{NOTE:} Doesn't work with Access2!
-@item @uref{http://www.mysql.com/Downloads/Contrib/mdb2sql.bas, mdb2sql.bas}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mdb2sql.bas}
Converter from Access97 to MySQL by Moshe Gurvich.
-@item @uref{http://www.mysql.com/Downloads/Contrib/msql2mysqlWrapper-1.0.tgz, msql2mysqlWrapper 1.0}
+@item @uref{http://www.mysql.com/Downloads/Contrib/msql2mysqlWrapper-1.0.tgz}
A C wrapper from @code{mSQL} to MySQL. By @email{alfred@@sb.net}
-@item @uref{http://www.mysql.com/Downloads/Contrib/sqlconv.pl, sqlconv.pl}
+@item @uref{http://www.mysql.com/Downloads/Contrib/sqlconv.pl}
A simple script that can be used to copy fields from one MySQL table
to another in bulk. Basically, you can run @code{mysqldump} and pipe it to
the @code{sqlconv.pl} script. The script will parse through the
@@ -46087,14 +48058,14 @@ inserted into a new table. An example is when you want to create a new
table for a different site you are working on, but the table is just a
bit different (that is - fields in different order, etc.).
By Steve Shreeve.
-@item @uref{http://www.mysql.com/Downloads/Contrib/oracledump, oracledump}
+@item @uref{http://www.mysql.com/Downloads/Contrib/oracledump}
Perl program to convert Oracle databases to MySQL. Has same
output format as mysqldump. By Johan Andersson.
-@item @uref{http://www.mysql.com/Downloads/Contrib/excel2mysql.pl, excel2mysql.pl}
+@item @uref{http://www.mysql.com/Downloads/Contrib/excel2mysql.pl}
Perl program to import Excel spreadsheets into a MySQL database. By Stephen Hurd @email{shurd@@sk.sympatico.ca}
-@item @uref{http://www.mysql.com/Downloads/Contrib/T2S_100.ZIP, T2S_100.ZIP}.
+@item @uref{http://www.mysql.com/Downloads/Contrib/T2S_100.ZIP}.
Windows program to convert text files to MySQL databases. By
Asaf Azulay.
@@ -46103,15 +48074,15 @@ Asaf Azulay.
@appendixsec Using MySQL with Other Products
@itemize @bullet
-@item @uref{http://www.mysql.com/Downloads/Contrib/emacs-sql-mode.tar.gz, emacs-sql-mode.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/emacs-sql-mode.tar.gz}
Raw port of a SQL mode for XEmacs. Supports completion. Original by
Peter D. Pezaris @email{pez@@atlantic2.sbi.com} and partial
MySQL port by David Axmark.
-@item @uref{http://www.mysql.com/Downloads/Win32/myaccess97_1_4.zip, MyAccess97 1.4}.
-@item @uref{http://www.mysql.com/Downloads/Win32/myaccess2000_1_4.zip, MyAccess2000 1.4}.
+@item @uref{http://www.mysql.com/Downloads/Win32/myaccess97_1_4.zip} (MyAccess97 1.4)
+@item @uref{http://www.mysql.com/Downloads/Win32/myaccess2000_1_4.zip} (MyAccess2000 1.4)
-MyAccess is an AddIn for MS Access 97/2000 that allows you to manage
+MyAccess is an AddIn for MS Access 97/2000 that allows you to manage
MySQL databases from within Access. Main functions are:
@itemize @minus
@item Create/Modify Tables
@@ -46122,67 +48093,66 @@ MySQL databases from within Access. Main functions are:
@item Show a "Database Definition Report
@end itemize
-Written by Hubertus Hiden. @uref{http://www.accessmysql.com, MyAccess homepage}.
+Written by Hubertus Hiden.
+The MyAccess homepage is at @uref{http://www.accessmysql.com/}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/radius-0.3.tar.gz, radius-0.3.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/radius-0.3.tar.gz}
Patches for @code{radiusd} to make it support MySQL. By Wim Bonis,
@email{bonis@@kiss.de}.
@end itemize
-@cindex tools, useful
-@appendixsec Useful Tools
+@cindex utilities
+@appendixsec Utilities
@itemize @bullet
-@item @uref{http://worldcommunity.com/opensource/utilities/mysql_backup.html, MySQL Backup}.
-
-A backup script for MySQL. By Peter F. Brown.
+@item @uref{http://worldcommunity.com/opensource/utilities/mysql_backup.html}
+MySQL Backup is a backup script for MySQL. By Peter F. Brown.
-@item @uref{http://www.mysql.com/Downloads/Contrib/mytop, mytop}
-@item @uref{http://public.yahoo.com/~jzawodn/mytop/, mytop home page}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mytop}
+@item @uref{http://public.yahoo.com/~jzawodn/mytop/} (mytop home page)
mytop is a Perl program that allows you to monitor MySQL servers by
viewing active threads, queries, and overall server performance
numbers. By Jeremy D. Zawodny.
-@item @uref{http://www.mysql.com/Downloads/Contrib/mysql_watchdog.pl, mysql_watchdog.pl}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql_watchdog.pl}
Monitor the MySQL daemon for possible lockups. By Yermo Lamers,
@email{yml@@yml.com}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/mysqltop.tar.gz, mysqltop.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysqltop.tar.gz}
Sends a query in a fixed time interval to the server and shows the
resulting table. By Thomas Wana.
-@item @uref{http://www.mysql.com/Downloads/Contrib/mysql_structure_dumper.tar.gz,mysql_structure_dumper.tar.gz}
-Prints out the structure of the all tables in a database. By Thomas Wana.
-@item @uref{http://www.mysql.com/Downloads/Contrib/mysql_structure_dumper.tgz, structure_dumper.tgz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql_structure_dumper.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql_structure_dumper.tgz}
Prints the structure of every table in a database. By Thomas Wana.
-@item @uref{http://www.mysql.com/Downloads/Contrib/mysqlsync, mysqlsync-1.0-alpha.tar.gz}.
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysqlsync}.
A Perl script to keep remote copies of a MySQL database in sync with a
central master copy. By Mark Jeftovic. @email{markjr@@easydns.com}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/MySQLTutor-0.2.tar.gz, MySQLTutor}.
+@item @uref{http://www.mysql.com/Downloads/Contrib/MySQLTutor-0.2.tar.gz}.
MySQLTutor. A MySQL tutorial for beginners.
-@item @uref{http://www.mysql.com/Downloads/Contrib/MySQLDB.zip, MySQLDB.zip}
+@item @uref{http://www.mysql.com/Downloads/Contrib/MySQLDB.zip}
+@item @uref{http://www.mysql.com/Downloads/Contrib/MySQLDB-readme.html}.
A COM library for MySQL by Alok Singh.
-@item @uref{http://www.mysql.com/Downloads/Contrib/MySQLDB-readme.html, MySQLDB-readme.html}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/mysql_replicate.pl, mysql_replicate.pl}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql_replicate.pl}
Perl program that handles replication. By @email{elble@@icculus.nsg.nwu.edu}
-@item @uref{http://www.mysql.com/Downloads/Contrib/DBIx-TextIndex-0.02.tar.gz, DBIx-TextIndex-0.02.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/DBIx-TextIndex-0.02.tar.gz}
Perl script that uses reverse indexing to handle text searching.
By Daniel Koch.
-@item @uref{http://www.mysql.com/Downloads/Contrib/dbcheck, dbcheck}
+@item @uref{http://www.mysql.com/Downloads/Contrib/dbcheck}
Perl script that takes a backup of tables before running isamchk on them.
By Elizabeth.
@item @uref{http://www.mysql.com/Downloads/Contrib/mybackup}.
-@item @uref{http://www.mswanson.com/mybackup, mybackup home page}
+@item @uref{http://www.mswanson.com/mybackup} (mybackup home page)
Wrapper for mysqldump to backup all databases. By Marc Swanson.
-@item @uref{http://www.mysql.com/Downloads/Contrib/mdu.pl.gz,mdu.pl.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mdu.pl.gz}
Prints the storage usage of a MySQL database.
@end itemize
@@ -46191,55 +48161,55 @@ Prints the storage usage of a MySQL database.
@appendixsec RPMs for Common Tools (Most Are for RedHat 6.1)
@itemize @bullet
-@item @uref{http://www.mysql.com/Downloads/Contrib/perl-Data-ShowTable-3.3-2.i386.rpm,perl-Data-ShowTable-3.3-2.i386.rpm}
-@item @uref{http://www.mysql.com/Downloads/Contrib/perl-Msql-Mysql-modules-1.2210-2.i386.rpm,perl-Msql-Mysql-modules-1.2210-2.i386.rpm}
-@item @uref{http://www.mysql.com/Downloads/Contrib/php-pg-3.0.13-1.i386.rpm,php-pg-3.0.13-1.i386.rpm}
-@item @uref{http://www.mysql.com/Downloads/Contrib/php-pg-manual-3.0.13-1.i386.rpm,php-pg-manual-3.0.13-1.i386.rpm}
-@item @uref{http://www.mysql.com/Downloads/Contrib/php-pg-mysql-3.0.13-1.i386.rpm,php-pg-mysql-3.0.13-1.i386.rpm}
-@item @uref{http://www.mysql.com/Downloads/Contrib/phpMyAdmin-2.0.5-1.noarch.rpm,phpMyAdmin-2.0.5-1.noarch.rpm}
+@item @uref{http://www.mysql.com/Downloads/Contrib/perl-Data-ShowTable-3.3-2.i386.rpm}
+@item @uref{http://www.mysql.com/Downloads/Contrib/perl-Msql-Mysql-modules-1.2210-2.i386.rpm}
+@item @uref{http://www.mysql.com/Downloads/Contrib/php-pg-3.0.13-1.i386.rpm}
+@item @uref{http://www.mysql.com/Downloads/Contrib/php-pg-manual-3.0.13-1.i386.rpm}
+@item @uref{http://www.mysql.com/Downloads/Contrib/php-pg-mysql-3.0.13-1.i386.rpm}
+@item @uref{http://www.mysql.com/Downloads/Contrib/phpMyAdmin-2.0.5-1.noarch.rpm}
@end itemize
@cindex functions, useful
@appendixsec Useful Functions
@itemize @bullet
-@item @uref{http://www.mysql.com/Downloads/Contrib/mysnprintf.c,mysnprintf.c}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysnprintf.c}
sprintf() function for SQL queries that can escape blobs. By Chunhua Liu.
@end itemize
-@appendixsec Windows programs
+@appendixsec Windows Programs
@itemize @bullet
-@item @uref{http://www.mysql.com/Downloads/Contrib/LaunchMySQL.zip, LaunchMySQL.zip}
+@item @uref{http://www.mysql.com/Downloads/Contrib/LaunchMySQL.zip}
The program launches the MySQL server, shuts it down, and
display status information. By Bill Thompson
@end itemize
-@appendixsec Uncategorized
+@appendixsec Uncategorised
@itemize @bullet
-@item @uref{http://www.mysql.com/Downloads/Contrib/findres.pl, findres.pl}
+@item @uref{http://www.mysql.com/Downloads/Contrib/findres.pl}
Find reserved words in tables. By Nem W Schlecht.
-@item @uref{http://www.mysql.com/Downloads/Contrib/handicap.tar.gz, handicap.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/handicap.tar.gz}
Performance handicapping system for yachts. Uses PHP. By
@email{rhill@@stobyn.ml.org}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/hylalog-1.0.tar.gz, hylalog-1.0.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/hylalog-1.0.tar.gz}
Store @code{hylafax} outgoing faxes in a MySQL database. By Sinisa
Milivojevic, @email{sinisa@@mysql.com}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/mrtg-mysql-1.0.tar.gz, mrtg-mysql-1.0.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mrtg-mysql-1.0.tar.gz}
MySQL status plotting with MRTG, by Luuk de Boer, @email{luuk@@wxs.nl}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/wuftpd-2.4.2.18-mysql_support.2.tar.gz, wuftpd-2.4.2.18-mysql_support.2.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/wuftpd-2.4.2.18-mysql_support.2.tar.gz}
Patches to add logging to MySQL for WU-ftpd. By Zeev Suraski,
@email{bourbon@@netvision.net.il}.
-@item @uref{http://www.mysql.com/Downloads/Contrib/wu-ftpd-2.6.0-mysql.4.tar.gz,wu-ftpd-2.6.0-mysql.4.tar.gz}
+@item @uref{http://www.mysql.com/Downloads/Contrib/wu-ftpd-2.6.0-mysql.4.tar.gz}
Patches to add logging to MySQL for WU-ftpd 2.6.0. By
@email{takeshi@@SoftAgency.co.jp}, based on Zeev Suraski wuftpd patches.
-@item @uref{http://www.mysql.com/Downloads/Contrib/Old-Versions, Old-Versions}
+@item @uref{http://www.mysql.com/Downloads/Contrib/Old-Versions}
Previous versions of things found here that you probably won't be
interested in.
@end itemize
@@ -46266,14 +48236,15 @@ helped to make MySQL what it is today.
@node Developers, Contributors, Credits, Credits
@appendixsec Developers at MySQL AB
-These are the developers that are or have been employed by MySQL AB
-to work on MySQL, roughly in the order they started to work with us.
-Following each developer is a small list of the tasks that the developer is
-responsible for, or the accomplishments they have made.
+These are the developers that are or have been employed by @code{MySQL AB}
+to work on the @code{MySQL} database software, roughly in the order they
+started to work with us. Following each developer is a small list of the
+tasks that the developer is responsible for, or the accomplishments they
+have made.
@table @asis
@item Michael (Monty) Widenius
-Has written the following parts of MySQL:
+Has written the following parts of the MySQL database software:
@itemize @bullet
@item
All the main code in @code{mysqld}.
@@ -46288,11 +48259,11 @@ handlers with index compression and different record formats).
The @code{HEAP} library. A memory table system with our superior full dynamic
hashing. In use since 1981 and published around 1984.
@item
-The @code{replace} program (look into it, it's COOL!).
+The @code{replace} program (take a look at it, it's @strong{COOL}!).
@item
@strong{MyODBC}, the ODBC driver for Windows95.
@item
-Fixing bugs in MIT-pthreads to get it to work for MySQL. And
+Fixing bugs in MIT-pthreads to get it to work for MySQL Server. And
also Unireg, a curses-based application tool with many utilities.
@item
Porting of @code{mSQL} tools like @code{msqlperl}, @code{DBD}/@code{DBI}, and
@@ -46307,7 +48278,7 @@ Most of crash-me and the foundation for the MySQL benchmarks.
Coordinator and initial main writer of the @strong{Reference Manual},
including enhancements to @code{texi2html}.
@item
-Automatic Web site updating from the manual.
+Automatic web site updating from the manual.
@item
Initial Autoconf, Automake, and Libtool support.
@item
@@ -46320,7 +48291,7 @@ Lots of testing of new features.
@item
Our in-house ``free'' software lawyer.
@item
-Mailing list maintainer (who never has the time to do it right...)
+Mailing list maintainer (who never has the time to do it right...).
@item
Our original portability code (more than 10 years old now). Nowadays
only some parts of @code{mysys} are left.
@@ -46336,7 +48307,7 @@ that new feature to work.
@item
A lot of extensions to the @code{mysql} client.
@item
-@code{procedure analyse()}
+@code{PROCEDURE ANALYSE()}
@end itemize
@item Sinisa Milivojevic
@@ -46344,11 +48315,31 @@ A lot of extensions to the @code{mysql} client.
@item
Compression (with @code{zlib}) in the client/server protocol.
@item
-Perfect hashing for the lexical analyzer phase.
+Perfect hashing for the lexical analyser phase.
@item
-The MySQLGUI client.
+Multi-row @code{INSERT}
@item
-Maintainer of mysql++.
+@code{mysqldump} -e option
+@item
+@code{LOAD DATA INFILE LOCAL}
+@item
+@code{SQL_CALC_FOUND_ROWS} @code{SELECT} option
+@item
+@code{--max-user-connections=...} option
+@item
+@code{net_read} and @code{net_write_timeout}
+@item
+@code{GRANT}/@code{REVOKE} and @code{SHOW GRANTS FOR}
+@item
+New client-server protocol for 4.0
+@item
+@code{UNION}.
+@item
+Multi-table @code{DELETE}/@code{UPDATE}
+@item
+The @code{MySQLGUI} client.
+@item
+Maintainer of @code{MySQL++}.
@end itemize
@item Tonu Samuel
@@ -46356,9 +48347,9 @@ Maintainer of mysql++.
@item
Our security expert.
@item
-Vio interface (The foundation for the encrypted client/server protocol).
+Vio interface (the foundation for the encrypted client/server protocol).
@item
-MySQL Filesystem (A way to use MySQL databases as files
+MySQL Filesystem (a way to use MySQL databases as files
and directories).
@item
The CASE Expression.
@@ -46393,6 +48384,8 @@ Our webmaster.
@item Miguel Solorzano
@itemize @bullet
@item
+Win32 development.
+@item
Winmysqladmin.
@end itemize
@@ -46424,32 +48417,21 @@ Proofreading and editing this fine manual.
@code{DELETE ... ORDER BY ...}.
@end itemize
-@item John Dean
-@itemize @bullet
-@item
-The new MySQL GUI client.
-@end itemize
-
@item Indrek Siitan
@itemize @bullet
@item
Designer/programmer of our web interface.
@end itemize
-@end table
-The following non-developers are also working in/with MySQL AB:
-
-@table @asis
-@item
-Hans Kierkegaard - Responsible for MySQL license handling.
-@item
-Antti Halonen - Sales manager.
+@item Jorge del Conde
+@itemize @bullet
@item
-Jonas Norrman - Handles licensing questions sent to @email{info@@mysql.com}.
+@code{MyCC} @code{MySQL Control Center}.
@item
-Erik Granberg - Handles MySQL partners (and a lot of other stuff).
+Web portals.
@item
-Allan Larsson (The BOSS for TCX DataKonsult AB).
+Win32 development.
+@end itemize
@end table
@@ -46458,8 +48440,10 @@ Allan Larsson (The BOSS for TCX DataKonsult AB).
@cindex contributors, list of
-Contributors to the MySQL distribution are listed here, in
-somewhat random order:
+While @code{MySQL AB} owns all copyrights in the @code{MySQL server}
+and the @code{MySQL manual}, we wish to recognise those who have made
+contributions of one kind or another to the @code{MySQL distribution}.
+Contributors are listed here, in somewhat random order:
@table @asis
@item Paul DuBois
@@ -46478,18 +48462,19 @@ record format.
Win32 port with Borland compiler. @code{mysqlshutdown.exe} and
@code{mysqlwatch.exe}
@item David J. Hughes
-For the effort to make a shareware SQL database. We at TcX started with
-@code{mSQL}, but found that it couldn't satisfy our purposes so instead we
-wrote a SQL interface to our application builder Unireg. @code{mysqladmin}
-and @code{mysql} are programs that were largely influenced by their
-@code{mSQL} counterparts. We have put a lot of effort into making the
-MySQL syntax a superset of @code{mSQL}. Many of the API's ideas are
-borrowed from @code{mSQL} to make it easy to port free @code{mSQL} programs
-to MySQL. MySQL doesn't contain any code from @code{mSQL}.
+For the effort to make a shareware SQL database. At TcX, the predecessor
+of MySQL AB, we started with @code{mSQL}, but found that it couldn't
+satisfy our purposes so instead we wrote a SQL interface to our
+application builder Unireg. @code{mysqladmin} and @code{mysql} client are
+programs that were largely influenced by their @code{mSQL} counterparts.
+We have put a lot of effort into making the MySQL syntax a superset of
+@code{mSQL}. Many of the API's ideas are borrowed from @code{mSQL} to
+make it easy to port free @code{mSQL} programs to the MySQL API.
+The MySQL software doesn't contain any code from @code{mSQL}.
Two files in the distribution (@file{client/insert_test.c} and
@file{client/select_test.c}) are based on the corresponding (non-copyrighted)
files in the @code{mSQL} distribution, but are modified as examples showing
-the changes necessary to convert code from @code{mSQL} to MySQL.
+the changes necessary to convert code from @code{mSQL} to MySQL Server.
(@code{mSQL} is copyrighted David J. Hughes.)
@item Fred Fish
For his excellent C debugging and trace library. Monty has made a number
@@ -46504,9 +48489,9 @@ From whom we got an excellent compiler (@code{gcc}), the @code{libc} library
and the @code{readline} library (for the @code{mysql} client).
@item Free Software Foundation & The XEmacs development team
For a really great editor/environment used by almost everybody at
-TcX/MySQL AB/detron.
+MySQL AB/TcX/detron.
@item Patrick Lynch
-For helping us acquire @code{http://www.mysql.com/}.
+For helping us acquire @uref{http://www.mysql.com/}.
@item Fred Lindberg
For setting up qmail to handle the MySQL mailing list and for the
incredible help we got in managing the MySQL mailing lists.
@@ -46520,9 +48505,9 @@ For the @code{DBD} (Perl) interface.
@item Tim Bunce
Author of @code{mysqlhotcopy}.
@item Andreas Koenig @email{a.koenig@@mind.de}
-For the Perl interface to MySQL.
+For the Perl interface for MySQL Server.
@item Eugene Chan @email{eugene@@acenet.com.sg}
-For porting PHP to MySQL.
+For porting PHP for MySQL Server.
@item Michael J. Miller Jr. @email{mke@@terrapin.turbolift.com}
For the first MySQL manual. And a lot of spelling/language
fixes for the FAQ (that turned into the MySQL manual a long
@@ -46530,7 +48515,7 @@ time ago).
@item Yan Cailin
First translator of the MySQL Reference Manual into simplified
chinese in early 2000 on which the Big5 and HK coded
-(@uref{http://mysql.hitstar.com, mysql.hitstar.com}) versions were
+(@uref{http://mysql.hitstar.com/}) versions were
based. @uref{http://linuxdb.yeah.net, Personal home page at
linuxdb.yeah.net}.
@item Giovanni Maruzzelli @email{maruzz@@matrice.it}
@@ -46541,7 +48526,7 @@ software developed by Chris Provenzano, the University of California,
Berkeley, and contributors. We are currently using version 1_60_beta6
patched by Monty (see @file{mit-pthreads/Changes-mysql}).
@item Xavier Leroy @email{Xavier.Leroy@@inria.fr}
-The author of LinuxThreads (used by MySQL on Linux).
+The author of LinuxThreads (used by the MySQL Server on Linux).
@item Zarko Mocnik @email{zarko.mocnik@@dem.si}
Sorting for Slovenian language and the @file{cset.tar.gz} module that makes
it easier to add other character sets.
@@ -46553,15 +48538,14 @@ answering on the MySQL mailing list.
@item Yves Carlier @email{Yves.Carlier@@rug.ac.be}
@code{mysqlaccess}, a program to show the access rights for a user.
@item Rhys Jones @email{rhys@@wales.com} (And GWE Technologies Limited)
-For the JDBC, a module to extract data from MySQL with a Java
-client.
+For the JDBC, a module to extract data from a MySQL Database with a Java client.
@item Dr Xiaokun Kelvin ZHU @email{X.Zhu@@brad.ac.uk}
Further development of the JDBC driver and other MySQL-related
Java tools.
@item James Cooper @email{pixel@@organic.com}
For setting up a searchable mailing list archive at his site.
@item Rick Mehalick @email{Rick_Mehalick@@i-o.com}
-For @code{xmysql}, a graphical X client for MySQL.
+For @code{xmysql}, a graphical X client for MySQL Server.
@item Doug Sisk @email{sisk@@wix.com}
For providing RPM packages of MySQL for RedHat Linux.
@item Diemand Alexander V. @email{axeld@@vial.ethz.ch}
@@ -46585,7 +48569,7 @@ Spanish error messages.
Norwegian error messages and testing of Version 3.21.#.
@item Timur I. Bakeyev @email{root@@timur.tatarstan.ru}
Russian error messages.
-@item @email{brenno@@dewinter.com} && Filippo Grassilli @email{phil@@hyppo.com}
+@item @email{brenno@@dewinter.com} & Filippo Grassilli @email{phil@@hyppo.com}
Italian error messages.
@item Dirk Munzinger @email{dirk@@trinity.saar.de}
German error messages.
@@ -46627,11 +48611,11 @@ Help to set up InstallShield for MySQL-Win32.
@item Jethro Wright III @email{jetman@@li.net}
The @file{libmysql.dll} library.
@item James Pereria @email{jpereira@@iafrica.com}
-Mysqlmanager, a Win32 GUI tool for administrating MySQL.
+Mysqlmanager, a Win32 GUI tool for administrating MySQL Server.
@item Curt Sampson @email{cjs@@portal.ca}
Porting of MIT-pthreads to NetBSD/Alpha and NetBSD 1.3/i386.
@item Antony T. Curtis @email{antony.curtis@@olcs.net}
-Porting of MySQL to OS/2.
+Porting of the MySQL Database software to OS/2.
@item Martin Ramsch @email{m.ramsch@@computer.org}
Examples in the MySQL Tutorial.
@item Steve Harvey
@@ -46644,6 +48628,9 @@ Configure updates for Tru64, large file support and better TCP wrappers
support.
@item John Birrell
Emulation of pthread_mutex() for OS/2.
+@item Benjamin Pflugmann
+Extended @code{MERGE} tables to handle @code{INSERTS}. Active member
+on the MySQL mailing lists.
@end table
Other contributors, bugfinders, and testers: James H. Thompson, Maurizio
@@ -46698,13 +48685,14 @@ ODBC and VisualC++ interface questions.
@cindex contributing companies, list of
-The following companies has helped us finance development of
-MySQL by either paying us for developing a new feature,
-developed a MySQL feature themselves or by giving us hardware for
-MySQL development.
+While @code{MySQL AB} owns all copyrights in the @code{MySQL server}
+and the @code{MySQL manual}, we wish to recognise the following companies,
+which helped us finance the development of the @code{MySQL server},
+such as by paying us for developing a new feature or giving us hardware
+for development of the @code{MySQL server}.
@table @asis
-@item VA Linux / Andover.net
+@item VA Linux / Andover.net
Funded replication.
@item NuSphere
Editing of the MySQL manual.
@@ -46717,14 +48705,14 @@ Contributed to Development on Linux/Alpha.
@item SWSoft
Development on the embedded @code{mysqld} version.
@item FutureQuest
-@code{--skip-show-variables}
+@code{--skip-show-database}
@end table
@node News, Porting, Credits, Top
-@appendix MySQL change history
+@appendix MySQL Change History
@cindex ChangeLog
@cindex changes, log
@@ -46733,10 +48721,10 @@ Development on the embedded @code{mysqld} version.
This appendix lists the changes from version to version in the MySQL
source code.
-Note that we tend to update the manual at the same time we make changes to
+Note that we tend to update the manual at the same time we make changes to
MySQL. If you find a version listed below that you can't
-find on the
-@uref{http://www.mysql.com/downloads/,MySQL download page},
+find on the MySQL download page
+(@uref{http://www.mysql.com/downloads/}),
this means that the version has not yet been released!
@menu
@@ -46752,49 +48740,283 @@ this means that the version has not yet been released!
@node News-4.0.x, News-3.23.x, News, News
@appendixsec Changes in release 4.0.x (Development; Alpha)
-We have now started to work on MySQL 4.0. We will update this
-section as we add new features, so that others can follow our development.
+We are now working actively on MySQL 4.0 and will only provide critical
+bug fixes for MySQL 3.23. We will update this section as we add new
+features, so that others can follow our development.
Our TODO section contains what we plan to have in 4.0. @xref{TODO MySQL 4.0}.
+@cindex changes, version 4.0
+
@menu
+* News-4.0.2:: Changes in release 4.0.2
+* News-4.0.1:: Changes in release 4.0.1
* News-4.0.0:: Changes in release 4.0.0
@end menu
+@node News-4.0.2, News-4.0.1, News-4.0.x, News-4.0.x
+@appendixsubsec Changes in release 4.0.2
-@node News-4.0.0, , News-4.0.x, News-4.0.x
-@appendixsubsec Changes in release 4.0.0
+@itemize @bullet
+@item
+A lot of fixes to @code{UNION}.
+@item
+@code{DOUBLE} and @code{FLOAT} columns are now honoring the
+@code{UNSIGNED} flag on storage.
+@item
+Fixed bug with indexless boolean fulltext search.
+@item
+Fixed bug that sometimes appeared when fulltext search was used
+with ``const'' tables.
+@item
+Fixed wrong error value when doing a @code{SELECT} with an empty HEAP table.
+@item
+Use @code{ORDER BY column DESC} now sorts @code{NULL} values first.
+@item
+Fixed bug in @code{WHERE key_name='constant' ORDER BY key_name DESC}.
+@item
+Fixed bug in @code{SELECT DISTINCT ... ORDER BY DESC} optimization.
+@item
+Fixed bug in @code{... HAVING 'GROUP_FUNCTION'(xxx) IS [NOT] NULL}.
+@item
+Fixed bug in truncation operator for boolean fulltext search.
+@item
+Allow numeric user id to @code{mysqld --user=#}.
+@item
+Fixed a bug where @code{SQL_CALC_ROWS} returned a wrong value when used
+with one table and @code{ORDER BY} and with InnoDB tables.
+@item
+Fixed that @code{SELECT 0 LIMIT 0} doesn't hang thread.
+@item
+Fixed some problems with @code{USE/IGNORE INDEX} when using
+many keys with the same start column.
+@item
+Don't use table scan with BerkeleyDB and InnoDB tables when we can use
+an index that covers the whole row.
+@item
+Optimized InnoDB sort-buffer handling to take less memory.
+@item
+Fixed bug in multi table @code{DELETE} and InnoDB tables.
+@item
+Fixed problem with @code{TRUNCATE} and InnoDB that gave the error
+@code{Can't execute the given command because you have active locked
+tables or an active transaction}.
+@item
+Added sql-mode flag @code{NO_UNSIGNED_SUBTRACTION} to disable unsigned
+arithmetic rules when it comes to subtraction. (This will make MySQL 4.0
+behave more closely to 3.23 with @code{UNSIGNED} columns).
+@item
+Added @code{WITH MAX_QUERIES_PER_HOUR=#} to @code{GRANT} command.
+@item
+The type returned for all bit functions (@code{|}, @code{<<} ...) is now of
+type @code{unsigned integer}.
+@item
+Added detection of @code{nan} values in MyISAM to make it possible to
+repair tables with @code{nan} in float or double columns.
+@item
+Fixed new bug in @code{myisamchk} where it didn't correctly update number of
+``parts'' in the MyISAM index file.
+@item
+Changed to use @code{autoconf} 2.52 (from @code{autoconf} 2.13).
+@item
+Fixed optimization problem where the MySQL Server was in ``preparing'' state
+for a long time when selecting from an empty table which had contained
+a lot of rows.
+@item
+Fixed bug in complicated join with @code{const} tables. This fix also
+improves performance a bit when referring to another table from a
+@code{const} table.
+@item
+First pre-version of multi table @code{UPDATE}s.
+@item
+Fixed bug in multi table @code{DELETE}.
+@item
+Fixed bug in @code{SELECT CONCAT(argument-list) ... GROUP BY 1}.
+@item
+@code{INSERT ... SELECT} did a full rollback in case of an error. Fixed
+so that we only roll back the last statement in the current transaction.
+@item
+Fixed bug with empty expression for boolean fulltext search.
+@item
+Fixed core dump bug in updating fulltext key from/to @code{NULL}.
+@item
+ODBC compatibility: Added @code{BIT_LENGTH()}.
+@item
+Fixed core dump bug in @code{GROUP BY BINARY column}.
+@item
+Added support for @code{NULL} keys in HEAP tables.
+@item
+Use index for @code{ORDER BY} in queries of type:
+@code{SELECT * FROM t WHERE key_part1=1 ORDER BY key_part1 DESC,key_part2 DESC}
+@item
+Fixed bug in @code{FLUSH QUERY CACHE}.
+@item
+Added @code{CAST()} and @code{CONVERT()} functions. The @code{CAST} and
+@code{CONVERT} functions are nearly identical and mainly useful when you
+want to create a column with a specific type in a @code{CREATE ... SELECT}.
+For more information, read @ref{Cast Functions}.
+@item
+@code{CREATE ... SELECT} on @code{DATE} and @code{TIME} functions now
+create columns of the expected type.
+@item
+Changed order in which keys are created in tables.
+@item
+Added a new columns @code{Null} and @code{Index_type} to @code{SHOW INDEX}.
+@end itemize
-@cindex changes, version 4.0
+@node News-4.0.1, News-4.0.0, News-4.0.2, News-4.0.x
+@appendixsubsec Changes in release 4.0.1
@itemize @bullet
@item
-Multi-table @code{DELETE}.
+Fixed bug when @code{HANDLER} was used with some unsupported table type.
@item
-Don't support old client protocols prior to MySQL 3.21 any more.
+@code{mysqldump} now puts @code{ALTER TABLE table_name DISABLE KEYS} and
+@code{ALTER TABLE table_name DISABLE KEYS} in the sql dump.
@item
-Don't include the old C API functions @code{mysql_drop_db},
-@code{mysql_create_db} and @code{mysql_connect}, unless compiled with
-@code{USE_OLD_FUNCTIONS}.
+Added @code{mysql_fix_extensions} script.
@item
-Renamed @code{safe_mysqld} to @code{mysqld_safe}.
+Fixed stack overrun problem @code{LOAD DATA FROM MASTER} on OSF1.
@item
-Allow @code{IN} as a synonym for @code{FROM} in @code{SHOW} commands.
+Fixed shutdown problem on HP-UX.
@item
-@code{SHOW INDEXES} is now a synonym for @code{SHOW INDEX}.
+Added functions @code{des_encrypt()} and @code{des_decrypt()}.
@item
-Added support for symbolic links to @code{MyISAM} tables. Symlink handling is
-now enabled by default for Windows.
+Added statement @code{FLUSH DES_KEY_FILE}.
@item
-@code{LOAD DATA FROM MASTER} ``auto-magically'' sets up a slave.
+Added @code{mysqld} option @code{--des-key-file}.
+@item
+@code{HEX(string)} now returns the characters in string converted to
+hexadecimal.
+@item
+Fixed problem with @code{GRANT} when using @code{lower_case_table_names == 1}.
+@item
+Changed @code{SELECT ... IN SHARE MODE} to
+@code{SELECT ... LOCK IN SHARE MODE} (as in MySQL 3.23).
+@item
+A new query cache to cache results from identical @code{SELECT} queries.
+@item
+Fixed core dump bug on 64-bit machines when it got an incorrect communication
+packet.
+@item
+@code{MATCH ... AGAINST(... IN BOOLEAN MODE)} can now work
+without @code{FULLTEXT} index.
+@item
+Fixed slave to replicate from 3.23 master.
+@item
+Miscellaneous replication fixes/cleanup.
+@item
+Got shutdown to work on Mac OS X.
+@item
+Added @file{myisam/ft_dump} utility for low-level inspection
+of @code{FULLTEXT} indexes.
+@item
+Fixed bug in @code{DELETE ... WHERE ... MATCH ...}.
+@item
+Added support for @code{MATCH ... AGAINST(... IN BOOLEAN MODE)}.
+@strong{Note: you must rebuild your tables with
+@code{ALTER TABLE tablename TYPE=MyISAM} to be
+able to use boolean fulltext search}.
+@item
+@code{LOCATE()} and @code{INSTR()} are now case sensitive if either
+argument is a binary string.
+@item
+Changed @code{RAND()} initialization so that @code{RAND(N)} and
+@code{RAND(N+1)} are more distinct.
+@item
+Fixed core dump bug in @code{UPDATE ... ORDER BY}.
+@item
+Changed @code{INSERT INTO ... SELECT} to stop on errors by default.
+@item
+Ignore @code{DATA DIRECTORY} and @code{INDEX DIRECTORY} directives on Windows.
+@item
+Added boolean fulltext search code. It should be considered early alpha.
+@item
+Extended @code{MODIFY} and @code{CHANGE} in @code{ALTER TABLE} to accept
+the @code{AFTER} keyword.
+@item
+Indexes are now used with @code{ORDER BY} on a whole @code{InnoDB} table.
+@end itemize
+
+@node News-4.0.0, , News-4.0.1, News-4.0.x
+@appendixsubsec Changes in release 4.0.0
+
+@itemize @bullet
+@item
+Added @code{--xml} option to @code{mysql} for producing XML output.
+@item
+Added variables @code{ft_min_word_len}, @code{ft_max_word_len}, and
+@code{ft_max_word_len_for_sort}.
+@item
+Added documentation for @code{libmysqld}, the embedded MySQL server
+library. Also added example programs (a @code{mysql} client and
+@code{mysqltest} test program) which use @code{libmysqld}.
+@item
+Removed all Gemini hooks from MySQL server.
+@item
+Removed @code{my_thread_init()} and @code{my_thread_end()}
+from mysql_com.h, and added @code{mysql_thread_init()} and
+@code{mysql_thread_end()} to mysql.h.
+@item
+Support for communication packets > 16M. In 4.0.1 we will extend MyISAM to
+be able to handle these.
+@item
+Secure connections (with SSL).
+@item
+Unsigned @code{BIGINT} constants now work. @code{MIN()} and @code{MAX()}
+now handle signed and unsigned @code{BIGINT} numbers correctly.
+@item
+New character set @code{latin_de} which provides correct German sorting.
+@item
+@code{STRCMP()} now uses the current character set when doing comparison,
+which means that the default comparison is case insensitive.
+@item
+@code{TRUNCATE TABLE} and @code{DELETE FROM table_name} are now separate
+functions. One bonus is that @code{DELETE FROM table_name} now returns
+the number of deleted rows.
+@item
+@code{DROP DATABASE} now executes a @code{DROP TABLE} on all tables in
+the database, which fixes a problem with @code{InnoDB} tables.
+@item
+Added support for @code{UNION}.
+@item
+@code{DELETE} can now operate on multiple tables.
@item
A new @code{HANDLER} interface to @code{MyISAM} tables.
@item
+Added support for @code{INSERT} on @code{MERGE} tables. Patch from
+Benjamin Pflugmann.
+@item
+Changed @code{WEEK(#,0)} to match the calendar in the USA.
+@item
@code{COUNT(DISTINCT)} is about 30% faster.
@item
-@code{FULLTEXT} index creation now is much faster.
+Speed up all internal list handling.
+@item
+Speed up @code{IS NULL}, @code{ISNULL()} and some other internal primitives.
+@item
+Full text index creation now is much faster.
@item
-Searching on packed (@code{CHAR}/@code{VARCHAR}) keys now is much faster.
+Tree-like cache to speed up bulk inserts and
+@code{myisam_bulk_insert_tree_size} variable.
+@item
+Searching on packed (@code{CHAR}/@code{VARCHAR}) keys is now much faster.
+@item
+Optimised queries of type:
+@code{SELECT DISTINCT * from table_name ORDER by key_part1 LIMIT #}.
+@item
+@code{SHOW CREATE TABLE} now shows all table attributes.
+@item
+@code{ORDER BY ... DESC} can now use keys.
+@item
+@code{LOAD DATA FROM MASTER} ``auto-magically'' sets up a slave.
+@item
+Renamed @code{safe_mysqld} to @code{mysqld_safe}.
+@item
+Added support for symbolic links to @code{MyISAM} tables. Symlink handling is
+now enabled by default for Windows.
+@item
+@code{LOAD DATA FROM MASTER} ``auto-magically'' sets up a slave.
@item
Added @code{SQL_CALC_FOUND_ROWS} and @code{FOUND_ROWS()}. This makes it
possible to know how many rows a query would have returned
@@ -46808,8 +49030,28 @@ Added @code{IDENTITY} as a synonym for @code{AUTO_INCREMENT} (like Sybase).
@item
Added @code{ORDER BY} syntax to @code{UPDATE} and @code{DELETE}.
@item
-Optimized queries of type:
-@code{SELECT DISTINCT * from table_name ORDER by key_part1 LIMIT #}
+@code{SHOW INDEXES} is now a synonym for @code{SHOW INDEX}.
+@item
+Added @code{ALTER TABLE table_name DISABLE KEYS} and
+@code{ALTER TABLE table_name ENABLE KEYS} commands.
+@item
+Allow use of @code{IN} as a synonym for @code{FROM} in @code{SHOW} commands.
+@item
+Implemented ``repair by sort'' for @code{FULLTEXT} indexes.
+@code{REPAIR TABLE}, @code{ALTER TABLE}, and @code{OPTIMIZE TABLE}
+for tables with @code{FULLTEXT} indexes are now up to 100 times faster.
+@item
+Allow ANSI SQL syntax @code{X'hexadecimal-number'}.
+@item
+Cleaned up global lock handling for @code{FLUSH TABLES WITH READ LOCK}.
+@item
+Fixed problem with @code{DATETIME = constant} in @code{WHERE} optimisation.
+@item
+Added options @code{--master-data} and @code{--no-autocommit} to
+@code{mysqldump} (Thanks to Brian Aker for this).
+@item
+Added script @code{mysql_explain_log.sh} to distribution.
+(Thanks to mobile.de).
@end itemize
@@ -46826,8 +49068,8 @@ table types:
@item @strong{MyISAM}
A new ISAM library which is tuned for SQL and supports large files.
@item @strong{BerkeleyDB} or @strong{BDB}
-Uses the Berkeley DB library from Sleepycat Software to implement
-transaction-safe tables.
+Uses the Berkeley DB library from Sleepycat Software to implement
+transaction-safe tables.
@item @strong{InnoDB}
A transaction-safe table handler that supports row level locking, and many
Oracle-like features.
@@ -46835,7 +49077,7 @@ Oracle-like features.
Note that only MyISAM is available in the standard binary distribution.
-The 3.23 release also includes support for database replication between
+The 3.23 release also includes support for database replication between
a master and many slaves, full-text indexing, and much more.
All new features are being developed in the 4.0 version. Only
@@ -46913,6 +49155,9 @@ not yet 100% confident in this code.
@appendixsubsec Changes in release 3.23.50
@itemize @bullet
@item
+Our Linux RPMS and binaries are now compiled with gcc 3.0.4, which should
+make them a bit faster.
+@item
Fixed some buffer overflow problems when reading startup parameters.
@item
Because of problems on shutdown we have now disabled named pipes on
@@ -46973,6 +49218,8 @@ Fixed shutdown problem on NT.
@appendixsubsec Changes in release 3.23.48
@itemize @bullet
@item
+Added @code{--xml} option to @code{mysqldump} for producing XML output.
+@item
Changed to use @code{autoconf} 2.52 (from @code{autoconf} 2.13)
@item
Fixed bug in complicated join with @code{const} tables.
@@ -47026,20 +49273,20 @@ this situation.
@appendixsubsec Changes in release 3.23.47
@itemize @bullet
@item
-Fixed in when using the following construct:
+Fixed bug when using the following construct:
@code{SELECT ... WHERE key=@@var_name OR $key=@@var_name2}
@item
Restrict InnoDB keys to 500 bytes.
@item
InnoDB now supports @code{NULL} in keys.
@item
-Fixed shutdown problem on HPUX. (Introduced in 3.23.46)
+Fixed shutdown problem on HP-UX. (Introduced in 3.23.46)
@item
-Fixed core-dump bug in replication when using SELECT RELEASE_LOCK();
+Fixed core-dump bug in replication when using @code{SELECT RELEASE_LOCK()}.
@item
Added new command: @code{DO expression,[expression]}
@item
-Added @code{slave-skip-errors} option
+Added @code{slave-skip-errors} option.
@item
Added statistics variables for all MySQL commands. (@code{SHOW STATUS} is
now much longer).
@@ -47050,7 +49297,7 @@ Fixed that @code{GROUP BY expr DESC} works.
@item
Fixed bug when using @code{t1 LEFT JOIN t2 ON t2.key=constant}.
@item
-@code{mysql_config} now also work with binary (relocated) distributions.
+@code{mysql_config} now also works with binary (relocated) distributions.
@end itemize
@node News-3.23.46, News-3.23.45, News-3.23.47, News-3.23.x
@@ -47137,7 +49384,7 @@ Fixed problem with sjis character strings used within quoted table names.
Fixed coredump when using @code{CREATE ... FULLTEXT} keys with other table
handlers than MyISAM.
@item
-Don't use @code{signal()} on windows because this appears to not be
+Don't use @code{signal()} on Windows because this appears to not be
100 % reliable.
@item
Fixed bug when doing @code{WHERE column_name=NULL} on an indexed column
@@ -47211,26 +49458,27 @@ Fixed a bug in purge which could cause crashes.
Fixed a bug in @code{INSERT DELAYED} and @code{FLUSH TABLES} introduced
in 3.23.42.
@item
-Fixed unlikely bug, which returned not matching rows, in SELECT with
+Fixed unlikely bug, which returned non-matching rows, in @code{SELECT} with
many tables and multi-column indexes and 'range' type.
@item
-Fixed a unlikely core-dump bug when doing @code{EXPLAIN SELECT} when using
+Fixed an unlikely core-dump bug when doing @code{EXPLAIN SELECT} when using
many tables and @code{ORDER BY}.
@item
Fixed bug in @code{LOAD DATA FROM MASTER} when using table with
@code{CHECKSUM=1}.
@item
Added unique error message when one gets a DEADLOCK during a transaction with
-BDB tables.
+@code{BDB} tables.
@item
Fixed problem with @code{BDB} tables and @code{UNIQUE} columns defined
as @code{NULL}.
@item
-Fixed problem with @code{myisampack} when using pre-space filled CHAR columns.
+Fixed problem with @code{myisampack} when using pre-space filled @code{CHAR}
+columns.
@item
Applied patch from Yuri Dario for OS2.
@item
-Fixed bug in @code{--safe-user-create}
+Fixed bug in @code{--safe-user-create}.
@end itemize
@node News-3.23.42, News-3.23.41, News-3.23.43, News-3.23.x
@@ -47287,7 +49535,7 @@ Don't force everything to lower cases on Windows. (To fix problem
with Windows and @code{ALTER TABLE}). Now @code{--lower_case_names}
also works on Unix.
@item
-Fixed that automatic rollback that is done when thread end doesn't lock
+Fixed that automatic rollback is done when thread end doesn't lock
other threads.
@end itemize
@@ -47319,13 +49567,13 @@ Split @code{record_buffer} to @code{record_buffer} and
versions, if @code{record_rnd_buffer} is not set, then it takes the
value of @code{record_buffer}.
@item
-Fixed optimizing bug in @code{ORDER BY} where some @code{ORDER BY} parts
+Fixed optimising bug in @code{ORDER BY} where some @code{ORDER BY} parts
where wrongly removed.
@item
Fixed overflow bug with @code{ALTER TABLE} and @code{MERGE} tables.
@item
Added prototypes for @code{my_thread_init()} and @code{my_thread_end()} to
-@file{mysql_com.h}
+@file{mysql_com.h}
@item
Added option @code{--safe-user-create} to @code{mysqld}.
@item
@@ -47473,7 +49721,7 @@ Added database name to output for administrative commands like @code{CHECK},
@item
Lots of portability fixes for @code{InnoDB}.
@item
-Changed optimizer so that queries like
+Changed optimiser so that queries like
@code{SELECT * FROM table_name,table_name2 ... ORDER BY key_part1 LIMIT #}
will use index on @code{key_part1} instead of @code{filesort}.
@item
@@ -47535,16 +49783,16 @@ Fixed performance bug where reopened tables (tables that had been
waiting for @code{FLUSH} or @code{REPAIR}) would not use indexes for the
next query.
@item
-Fixed problem with @code{ALTER TABLE} to Innobase tables on FreeBSD.
+Fixed problem with @code{ALTER TABLE} to InnoDB tables on FreeBSD.
@item
Added @code{mysqld} variables @code{myisam_max_sort_file_size} and
@code{myisam_max_extra_sort_file_size}.
@item
-Initialize signals early to avoid problem with signals in Innobase.
+Initialise signals early to avoid problem with signals in InnoDB.
@item
Applied patch for the @code{tis620} character set to make comparisons
case-independent and to fix a bug in @code{LIKE} for this character set.
-@strong{NOTE}: All tables that uses the @code{tis620} character set must be
+@strong{Note}: All tables that uses the @code{tis620} character set must be
fixed with @code{myisamchk -r} or @code{REPAIR TABLE} !
@item
Added @code{--skip-safemalloc} option to @code{mysqld}.
@@ -47560,13 +49808,13 @@ Fixed a bug that allowed you to use database names containing a @samp{.}
character. This fixes a serious security issue when @code{mysqld} is run
as root.
@item
-Fixed bug when thread creation failed (could happen when doing a LOT
+Fixed bug when thread creation failed (could happen when doing a @strong{lot}
of connections in a short time).
@item
Fixed some problems with @code{FLUSH TABLES} and @code{TEMPORARY} tables.
-(Problem with freeing the key cache and error @code{Can't reopen table...}).
+(Problem with freeing the key cache and error @code{Can't reopen table...}.)
@item
-Fixed a problem in Innobase with other character sets than @code{latin1}
+Fixed a problem in InnoDB with other character sets than @code{latin1}
and another problem when using many columns.
@item
Fixed bug that caused a core dump when using a very complex query involving
@@ -47586,7 +49834,7 @@ Fixed a bug in @code{CONCAT_WS()} where it returned wrong results.
@item
Changed @code{CREATE ... INSERT} and @code{INSERT ... SELECT} to not
allow concurrent inserts as this could make the binary log hard to repeat.
-(Concurrent inserts are enabled if you are not using the binary or update log).
+(Concurrent inserts are enabled if you are not using the binary or update log.)
@item
Changed some macros to be able to use fast mutex with glibc 2.2.
@end itemize
@@ -47616,7 +49864,7 @@ Fixed handling of arguments in the benchmark script @file{run-all-tests}.
@itemize @bullet
@item
-Added extra files to the distribution to allow @code{INNOBASE} support
+Added extra files to the distribution to allow @code{INNOBASE} support
to be compiled.
@end itemize
@@ -47631,7 +49879,7 @@ to the MySQL source distribution.
@item
Updated the documentation about @code{GEMINI} tables.
@item
-Fixed a bug in @code{INSERT DELAYED} that caused threads to hang when
+Fixed a bug in @code{INSERT DELAYED} that caused threads to hang when
inserting @code{NULL} into an @code{AUTO_INCREMENT} column.
@item
Fixed a bug in @code{CHECK TABLE} / @code{REPAIR TABLE} that could cause
@@ -47658,7 +49906,7 @@ arbitrary limit of 4 MB.
@item
Allow space around @code{=} in argument to @code{--set-variable}.
@item
-Fixed problem in automatic repair that could leave some threads in state
+Fixed problem in automatic repair that could leave some threads in state
@code{Waiting for table}.
@item
@code{SHOW CREATE TABLE} now dumps the @code{UNION()} for @code{MERGE} tables.
@@ -47672,9 +49920,9 @@ Fixed bug in bidirectional replication.
Fixed bug in the @code{BDB} table handler that occurred when using an index
on multi-part key where a key part may be @code{NULL}.
@item
-Fixed @code{MAX()} optimization on sub-key for @code{BDB} tables.
+Fixed @code{MAX()} optimisation on sub-key for @code{BDB} tables.
@item
-Fixed problem where garbage results were returned when using @code{BDB}
+Fixed problem where garbage results were returned when using @code{BDB}
tables and @code{BLOB} or @code{TEXT} fields when joining many tables.
@item
Fixed a problem with @code{BDB} tables and @code{TEXT} columns.
@@ -47686,12 +49934,12 @@ This ensures that one gets same values for date functions like @code{NOW()}
when using @code{mysqlbinlog} to pipe the queries to another server.
@item
Allow one to use @code{--skip-gemini}, @code{--skip-bdb} and
-@code{--skip-innobase} to @code{mysqld} even if these databases are not
+@code{--skip-innodb} to @code{mysqld} even if these databases are not
compiled in @code{mysqld}.
@item
One can now do @code{GROUP BY ... DESC}.
@item
-Fixed a deadlock in the @code{SET} code, when one ran @code{SET @@foo=bar},
+Fixed a deadlock in the @code{SET} code, when one ran @code{SET @@foo=bar},
where @code{bar} is a column reference, an error was not properly generated.
@end itemize
@@ -47822,7 +50070,7 @@ Fixed coredump when client aborted connection without @code{mysql_close()}.
Fixed a bug in @code{RESTORE TABLE} when trying to restore from a non-existent
directory.
@item
-Fixed a bug which caused a core dump on the slave when replicating
+Fixed a bug which caused a core dump on the slave when replicating
@code{SET PASSWORD}.
@item
Added @code{MASTER_POS_WAIT()}.
@@ -47870,7 +50118,7 @@ Fixed bug when using expression of type:
@example
SELECT ... FROM t1 LEFT JOIN t2 ON (t1.a=t2.a) WHERE t1.a=t2.a
@end example
-In this case the test in the @code{WHERE} clause was wrongly optimized away.
+In this case the test in the @code{WHERE} clause was wrongly optimised away.
@item
Fixed bug in @code{MyISAM} when deleting keys with possible @code{NULL}
values, but the first key-column was not a prefix-compressed text column.
@@ -47913,7 +50161,7 @@ Allow hex constants in the @code{--fields-*-by} and
Added option @code{--safe-show-database} to @code{mysqld}.
@item
Added @code{have_bdb}, @code{have_gemini}, @code{have_innobase},
-@code{have_raid} and @code{have_ssl} to @code{SHOW VARIABLES} to make it
+@code{have_raid} and @code{have_openssl} to @code{SHOW VARIABLES} to make it
easy to test for supported extensions.
@item
Added option @code{--open-files-limit} to @code{mysqld}.
@@ -47921,7 +50169,7 @@ Added option @code{--open-files-limit} to @code{mysqld}.
Changed option @code{--open-files} to @code{--open-files-limit} in
@code{safe_mysqld}.
@item
-Fixed a bug where some rows were not found with @code{HEAP} tables
+Fixed a bug where some rows were not found with @code{HEAP} tables
that had many keys.
@item
Fixed that @code{--bdb-no-sync} works.
@@ -47994,7 +50242,7 @@ Added support for @code{auto_increment} on sub-fields for BDB tables.
@item
Added @code{ANALYZE} of BDB tables.
@item
-In BDB tables, we now store the number of rows; This helps to optimize queries
+In BDB tables, we now store the number of rows; This helps to optimise queries
when we need an approximation of the number of rows.
@item
If we get an error in a multi-row statement, we now only rollback the
@@ -48037,9 +50285,9 @@ Tim Bunce @email{Tim.Bunce@@ig.co.uk} for modifying @file{mysql.server} to
easily handle hosts running many @code{mysqld} processes.
@item
@file{safe_mysqld}, @file{mysql.server}, and @file{mysql_install_db} have
-been modified to use @code{mysql_print_defaults} instead of various hacks
-to read the @file{my.cnf} files. In addition, the handling of various
-paths has been made more consistent with how @code{mysqld} handles them
+been modified to use @code{mysql_print_defaults} instead of various hacks
+to read the @file{my.cnf} files. In addition, the handling of various
+paths has been made more consistent with how @code{mysqld} handles them
by default.
@item
Automatically remove Berkeley DB transaction logs that no longer are in
@@ -48059,7 +50307,7 @@ that caused @code{mysql_install_db} to core dump on some Linux machines.
@item
Changed @code{mi_create()} to use less stack space.
@item
-Fixed bug with optimizer trying to over-optimize @code{MATCH} when used
+Fixed bug with optimiser trying to over-optimise @code{MATCH} when used
with @code{UNIQUE} key.
@item
Changed @code{crash-me} and the MySQL benchmarks to also work
@@ -48091,7 +50339,7 @@ and the interactive help for more information.
Fixed crash when automatic repair of @code{MyISAM} table failed.
@item
Fixed a major performance bug in the table locking code when one
-constantly had a LOT of @code{SELECT}, @code{UPDATE} and @code{INSERT}
+constantly had a lot of @code{SELECT}, @code{UPDATE} and @code{INSERT}
statements running. The symptom was that the @code{UPDATE} and
@code{INSERT} queries were locked for a long time while new @code{SELECT}
statements were executed before the updates.
@@ -48185,7 +50433,7 @@ shortage when compiled @code{--with-debug=full}.
@item
Fixed several coredumps in out-of-memory conditions.
@item
-@code{SHOW SLAVE STATUS} was using an uninitialized mutex if the slave had
+@code{SHOW SLAVE STATUS} was using an uninitialised mutex if the slave had
not been started yet.
@item
Fixed bug in @code{ELT()} and @code{MAKE_SET()} when the query used
@@ -48235,7 +50483,7 @@ if the table exists.
If you don't create a @code{PRIMARY KEY} in a BDB table, a hidden
@code{PRIMARY KEY} will be created.
@item
-Added read-only-key optimization to BDB tables.
+Added read-only-key optimisation to BDB tables.
@item
@code{LEFT JOIN} in some cases preferred a full table scan when there was
no @code{WHERE} clause.
@@ -48273,7 +50521,7 @@ Added @code{--skip-slave-start} option to @code{mysqld}.
Updates that generated an error code (such as @code{INSERT INTO foo(some_key)
values (1),(1)}) erroneously terminated the slave thread.
@item
-Added optimization of queries where @code{DISTINCT} is only used on columns
+Added optimisation of queries where @code{DISTINCT} is only used on columns
from some of the tables.
@item
Allow floating-point numbers where there is no sign after the exponent
@@ -48283,7 +50531,7 @@ Allow floating-point numbers where there is no sign after the exponent
@item
Added @code{--default-extra-file=#} to all MySQL clients.
@item
-Columns referenced in @code{INSERT} statements now are initialized properly.
+Columns referenced in @code{INSERT} statements now are initialised properly.
@item
@code{UPDATE} didn't always work when used with a range on a timestamp that
was part of the key that was used to find rows.
@@ -48431,7 +50679,7 @@ still work from the first line.
Fixed a problem when using many pending @code{DROP TABLE} statements at
the same time.
@item
-Optimizer didn't use keys properly when using @code{LEFT JOIN} on an
+Optimiser didn't use keys properly when using @code{LEFT JOIN} on an
empty table.
@item
Added shorter help text when invoking @code{mysqld} with incorrect options.
@@ -48453,7 +50701,7 @@ that both non-threaded (@code{-lmysqlclient}) and threaded
against a threaded @code{-lmysqlclient} will need to link against
@code{libmysqlclient_r} now.
@item
-Added atomic @code{RENAME} command.
+Added atomic @code{RENAME TABLE} command.
@item
Don't count entries with @code{NULL} in @code{COUNT(DISTINCT ...)}.
@item
@@ -48479,7 +50727,7 @@ that don't have the @code{pthread_rwlock_rdlock} code.
When deleting rows with a non-unique key in a HEAP table, all rows weren't
always deleted.
@item
-Fixed bug in range optimizer for HEAP tables for searches on a part index.
+Fixed bug in range optimiser for HEAP tables for searches on a part index.
@item
Fixed that @code{SELECT} on part keys works with BDB tables.
@item
@@ -48489,7 +50737,7 @@ Fixed @code{INSERT INTO bdb_table ... SELECT} to work with BDB tables.
@item
@code{ANALYZE TABLE} will now only update tables that have been changed
since thee last @code{ANALYZE}. Note that this is a new feature and tables
-will not be marked to be analyzed until they are updated in any way with
+will not be marked to be analysed until they are updated in any way with
3.23.23 or newer. For older tables, you have to do @code{CHECK TABLE}
to update the key distribution.
@item
@@ -48515,8 +50763,8 @@ More variables in @code{SHOW SLAVE STATUS} and @code{SHOW MASTER STATUS}.
@item
@code{SLAVE STOP} now will not return until the slave thread actually exits.
@item
-Full text search via the @code{MATCH} function and @code{FULLTEXT} index type.
-(For MyISAM files). This makes @code{FULLTEXT} a reserved word.
+Full text search via the @code{MATCH} function and @code{FULLTEXT} index type
+(for MyISAM files). This makes @code{FULLTEXT} a reserved word.
@end itemize
@@ -48541,7 +50789,7 @@ Added workaround for a bug in @code{gcc} 2.96 (intel) and @code{gcc} 2.9
Fixed memory leak in the client library when using @code{host=} in the
@code{my.cnf} file.
@item
-Optimized functions that manipulate the hours/minutes/seconds.
+Optimised functions that manipulate the hours/minutes/seconds.
@item
Fixed bug when comparing the result of @code{DATE_ADD()}/@code{DATE_SUB()}
against a number.
@@ -48588,14 +50836,14 @@ Fixed @code{chown} warning in @code{safe_mysqld}.
@item
Fixed a bug in @code{ORDER BY} that was introduced in 3.23.19.
@item
-Only optimize the @code{DELETE FROM tbl_name} to do a drop+create of
-the table if we are in @code{AUTOCOMMIT} mode. (Needed for BDB tables).
+Only optimise the @code{DELETE FROM tbl_name} to do a drop+create of
+the table if we are in @code{AUTOCOMMIT} mode (needed for BDB tables).
@item
Added extra checks to avoid index corruption when the @code{ISAM}/@code{MyISAM}
index files gets full during an @code{INSERT}/@code{UPDATE}.
@item
@code{myisamchk} didn't correctly update row checksum when used with
-@code{-ro} (This only gave an warning in subsequent runs).
+@code{-ro} (this only gave an warning in subsequent runs).
@item
Fixed bug in @code{REPAIR TABLE} so that it works with tables without indexes.
@item
@@ -48698,7 +50946,7 @@ Added 4 sample @code{my.cnf} example files in the @file{support-files}
directory.
@item
Fixed @code{duplicated key} problem when doing big @code{GROUP BY}'s.
-(This bug was probably introduced in 3.23.15).
+(This bug was probably introduced in 3.23.15.)
@item
Changed syntax for @code{INNER JOIN} to match ANSI SQL.
@item
@@ -48829,7 +51077,7 @@ Optimised MyISAM to be faster when inserting keys in sorted order.
@code{EXPLAIN SELECT ...} now also prints out whether MySQL needs to
create a temporary table or use file sorting when resolving the @code{SELECT}.
@item
-Added optimization to skip @code{ORDER BY} parts where the part is a
+Added optimisation to skip @code{ORDER BY} parts where the part is a
constant expression in the @code{WHERE} part. Indexes can now be used
even if the @code{ORDER BY} doesn't match the index exactly, as long as
all the not used index parts and all the extra @code{ORDER BY}
@@ -48849,6 +51097,8 @@ Fixed coredump in LOAD_FILE(NULL).
@itemize @bullet
@item
+Added @code{mysql_real_escape_string()} function to the MySQL C API.
+@item
Fixed a bug in @code{CONCAT()} where one of the arguments was a function
that returned a modified argument.
@item
@@ -48875,7 +51125,7 @@ character sets (you can choose which when starting @code{mysqld}).
@item
Added command @code{REPAIR TABLE}.
@item
-Added C API function @code{mysql_thread_safe()}.
+Added @code{mysql_thread_safe()} function to the MySQL C API.
@item
Added the @code{UMASK_DIR} environment variable.
@item
@@ -48963,7 +51213,7 @@ Fixed bug in @code{net_clear()} which could give the error @code{Aborted
connection} in the MySQL clients.
@item
Added options @code{USE INDEX (key_list)} and @code{IGNORE INDEX (key_list)} as
-join parameters in @code{SELECT}.
+parameters in @code{SELECT}.
@item
@code{DELETE} and @code{RENAME} should now work on @code{RAID} tables.
@end itemize
@@ -48976,7 +51226,7 @@ join parameters in @code{SELECT}.
@item
Allow the @code{ALTER TABLE tbl_name ADD (field_list)} syntax.
@item
-Fixed problem with optimizer that could sometimes use wrong keys.
+Fixed problem with optimiser that could sometimes use wrong keys.
@item
Fixed that @code{GRANT/REVOKE ALL PRIVILEGES} doesn't affect
@code{GRANT OPTION}.
@@ -49001,7 +51251,7 @@ Added variables @code{select_limit} and @code{max_join_size} to @code{mysql}.
Added sql variables: @code{SQL_MAX_JOIN_SIZE} and @code{SQL_SAFE_UPDATES}.
@item
Added @code{READ LOCAL} lock that doesn't lock the table for concurrent
-inserts. (This is used by @code{mysqldump}).
+inserts. (This is used by @code{mysqldump}.)
@item
Changed that @code{LOCK TABLES ... READ} doesn't anymore allow concurrent
inserts.
@@ -49042,10 +51292,10 @@ Fixed that @code{date_column BETWEEN const_date AND const_date} works.
Fixed problem when only changing a 0 to @code{NULL} in a table with
@code{BLOB/TEXT} columns.
@item
-Fixed bug in range optimizer when using many key parts and or on the middle
+Fixed bug in range optimiser when using many key parts and or on the middle
key parts: @code{WHERE K1=1 and K3=2 and (K2=2 and K4=4 or K2=3 and K4=5)}
@item
-Added command @code{source} to @code{mysql} to allow reading of batch files
+Added @code{source} command to @code{mysql} to allow reading of batch files
inside the @code{mysql} client. Original patch by Matthew Vanecek.
@item
Fixed critical problem with the @code{WITH GRANT OPTION} option.
@@ -49056,13 +51306,13 @@ databases in the same query.
Added VIO wrapper (needed for SSL support ; By Andrei Errapart and
Tõnu Samuel).
@item
-Fixed optimizer problem on @code{SELECT} when using many overlapping indexes.
+Fixed optimiser problem on @code{SELECT} when using many overlapping indexes.
MySQL should now be able to choose keys even better when there
is many keys to choose from.
@item
-Changed optimizer to prefer a range key instead of a ref key when the
+Changed optimiser to prefer a range key instead of a ref key when the
range key can uses more columns than the ref key (which only can use
-columns with =). For example, the following type of queries should now
+columns with @code{=}). For example, the following type of queries should now
be faster: @code{SELECT * from key_part_1=const and key_part_2 > const2}
@item
Fixed bug that a change of all @code{VARCHAR} columns to @code{CHAR} columns
@@ -49071,20 +51321,20 @@ didn't change row type from dynamic to fixed.
Disabled floating-point exceptions for FreeBSD to fix core dump when
doing @code{SELECT floor(pow(2,63))}.
@item
-Changed @code{mysqld} startup option @code{--delay-key-write} to
-@code{--delay-key-write-for-all-tables}
+Renamed @code{mysqld} startup option from @code{--delay-key-write} to
+@code{--delay-key-write-for-all-tables}.
@item
Added @code{read-next-on-key} to @code{HEAP} tables. This should fix all
-problems with @code{HEAP} tables when using not @code{UNIQUE} keys.
+problems with @code{HEAP} tables when using non-@code{UNIQUE} keys.
@item
-Added print of default arguments options to all clients.
+Added option to print default arguments to all clients.
@item
Added @code{--log-slow-queries} to @code{mysqld} to log all queries that take a
-long time to a separate log file with a time of how long the query took.
+long time to a separate log file with a time indicating how long the query took.
@item
-Fixed core dump when doing @code{WHERE key_column=RAND(...)}
+Fixed core dump when doing @code{WHERE key_column=RAND(...)}.
@item
-Fixed optimization bug in @code{SELECT ... LEFT JOIN ... key_column IS NULL},
+Fixed optimisation bug in @code{SELECT ... LEFT JOIN ... key_column IS NULL},
when @code{key_column} could contain @code{NULL} values.
@item
Fixed problem with 8-bit characters as separators in @code{LOAD DATA INFILE}.
@@ -49100,7 +51350,7 @@ Fixed problem when handling indexfiles larger than 8G.
@item
Added latest patches to mit-pthreads for NetBSD.
@item
-Fixed problem with timezones that are < GMT -11.
+Fixed problem with timezones that are < GMT - 11.
@item
Fixed a bug when deleting packed keys in @code{NISAM}.
@item
@@ -49119,7 +51369,7 @@ Added function @code{YEARWEEK()} and options @code{x}, @code{X}, @code{v} and
@item
Fixed problem with @code{MAX(indexed_column)} and HEAP tables.
@item
-Fixed problem with @code{BLOB NULL} keys and @code{LIKE} "prefix%".
+Fixed problem with @code{BLOB NULL} keys and @code{LIKE "prefix%"}.
@item
Fixed problem with @code{MyISAM} and fixed-length rows < 5 bytes.
@item
@@ -49147,12 +51397,12 @@ Fixed a bug in @code{MyISAM} with keys > 250 characters.
In @code{MyISAM} one can now do an @code{INSERT} at the same time as other
threads are reading from the table.
@item
-Added variable @code{max_write_lock_count} to @code{mysqld} to force a
+Added @code{max_write_lock_count} variable to @code{mysqld} to force a
@code{READ} lock after a certain number of @code{WRITE} locks.
@item
Inverted flag @code{delayed_key_write} on @code{show variables}.
@item
-Renamed variable @code{concurrency} to @code{thread_concurrency}.
+Renamed @code{concurrency} variable to @code{thread_concurrency}.
@item
The following functions are now multi-byte-safe:
@code{LOCATE(substr,str)}, @code{POSITION(substr IN str)},
@@ -49174,14 +51424,14 @@ Added option @code{FULL} to @code{SHOW PROCESSLIST}.
@item
Added option @code{--verbose} to @code{mysqladmin}.
@item
-Fixed problem when automatically converting HEAP to MyISAM.
+Fixed problem when automatically converting @code{HEAP} to @code{MyISAM}.
@item
-Fixed bug in HEAP tables when doing insert + delete + insert + scan the
+Fixed bug in @code{HEAP} tables when doing insert + delete + insert + scan the
table.
@item
Fixed bugs on Alpha with @code{REPLACE()} and @code{LOAD DATA INFILE}.
@item
-Added @code{mysqld} variable @code{interactive_timeout}.
+Added @code{interactive_timeout} variable to @code{mysqld}.
@item
Changed the argument to @code{mysql_data_seek()} from @code{ulong} to
@code{ulonglong}.
@@ -49193,24 +51443,24 @@ Changed the argument to @code{mysql_data_seek()} from @code{ulong} to
@itemize @bullet
@item
-Added @code{mysqld} option @code{-O lower_case_table_names=@{0|1@}} to allow
+Added @code{-O lower_case_table_names=@{0|1@}} option to @code{mysqld} to allow
users to force table names to lowercase.
@item
Added @code{SELECT ... INTO DUMPFILE}.
@item
-Added @code{mysqld} option @code{--ansi} to make some functions @code{ANSI SQL}
-compatible.
+Added @code{--ansi} option to @code{mysqld} to make some functions
+@code{ANSI SQL} compatible.
@item
-Temporary tables now starts with @code{#sql}.
+Temporary table names now start with @code{#sql}.
@item
Added quoting of identifiers with @code{`} (@code{"} in @code{--ansi} mode).
@item
-Changed to use snprintf() when printing floats to avoid some buffer
+Changed to use @code{snprintf()} when printing floats to avoid some buffer
overflows on FreeBSD.
@item
-Made @code{[floor()} overflow safe on FreeBSD.
+Made @code{floor()} overflow safe on FreeBSD.
@item
-Added option @code{--quote-names} to @code{mysqldump}
+Added @code{--quote-names} option to @code{mysqldump}.
@item
Fixed bug that one could make a part of a @code{PRIMARY KEY NOT NULL}.
@item
@@ -49224,11 +51474,11 @@ but will make table handling faster and better.
@item
Added patch by Sasha for user-defined variables.
@item
-Changed that @code{FLOAT} and @code{DOUBLE} (without any length modifiers) are
-not anymore fixed decimal point numbers.
+Changed that @code{FLOAT} and @code{DOUBLE} (without any length modifiers)
+no longer are fixed decimal point numbers.
@item
Changed the meaning of @code{FLOAT(X)}: Now this is the same as @code{FLOAT} if
-X <= 24 and a @code{DOUBLE} if 24 < X <= 53.
+@code{X} <= 24 and a @code{DOUBLE} if 24 < @code{X} <= 53.
@item
@code{DECIMAL(X)} is now an alias for @code{DECIMAL(X,0)} and @code{DECIMAL}
is now an alias for @code{DECIMAL(10,0)}. The same goes for @code{NUMERIC}.
@@ -49253,7 +51503,8 @@ Fixed some Y2K problems in the new date handling in 3.23.
@item
Fixed problem with @code{SELECT DISTINCT ... ORDER BY RAND()}.
@item
-Added patches by Sergei A. Golubchik for text searching on the MyISAM level.
+Added patches by Sergei A. Golubchik for text searching on the @code{MyISAM}
+level.
@item
Fixed cache overflow problem when using full joins without keys.
@item
@@ -49261,16 +51512,17 @@ Fixed some configure issues.
@item
Some small changes to make parsing faster.
@item
-@code{ALTER TABLE} + adding a column after the last field didn't work.
+Adding a column after the last field with @code{ALTER TABLE} didn't work.
@item
-Fixed problem when using an auto_increment column in two keys
+Fixed problem when using an @code{AUTO_INCREMENT} column in two keys
@item
-One can now with MyISAM have the auto_increment part as a sub part:
+With @code{MyISAM}, you now can have an @code{AUTO_INCREMENT} column as a key
+sub part:
@code{CREATE TABLE foo (a int not null auto_increment, b char(5), primary key (b,a))}
@item
-Fixed bug in MyISAM with packed char keys that could be @code{NULL}.
+Fixed bug in @code{MyISAM} with packed char keys that could be @code{NULL}.
@item
-@code{AS} on fieldname with @code{CREATE TABLE table_name SELECT ...} didn't
+@code{AS} on field name with @code{CREATE TABLE table_name SELECT ...} didn't
work.
@item
Allow use of @code{NATIONAL} and @code{NCHAR} when defining character columns.
@@ -49279,7 +51531,7 @@ This is the same as not using @code{BINARY}.
Don't allow @code{NULL} columns in a @code{PRIMARY KEY} (only in @code{UNIQUE}
keys).
@item
-Clear @code{LAST_INSERT_ID} if one uses this in ODBC:
+Clear @code{LAST_INSERT_ID()} if one uses this in ODBC:
@code{WHERE auto_increment_column IS NULL}. This seems to fix some problems
with Access.
@item
@@ -49287,9 +51539,9 @@ with Access.
searching after the last inserted row with @code{WHERE
auto_increment_column IS NULL}.
@item
-Added new @code{mysqld} variable @code{concurrency} for Solaris.
+Added new variable @code{concurrency} to @code{mysqld} for Solaris.
@item
-Added option @code{--relative} to @code{mysqladmin} to make
+Added @code{--relative} option to @code{mysqladmin} to make
@code{extended-status} more useful to monitor changes.
@item
Fixed bug when using @code{COUNT(DISTINCT ...)} on an empty table.
@@ -49309,7 +51561,7 @@ Fixed problem with @code{UDF} functions.
@itemize @bullet
@item
-Inserting a @code{DATETIME} into a @code{TIME} column will not anymore
+Inserting a @code{DATETIME} into a @code{TIME} column no longer will
try to store 'days' in it.
@item
Fixed problem with storage of float/double on little endian machines.
@@ -49317,13 +51569,13 @@ Fixed problem with storage of float/double on little endian machines.
@item
Added connect timeout on TCP/IP connections.
@item
-Fixed problem with @code{LIKE} "%" on an index that may have @code{NULL} values.
+Fixed problem with @code{LIKE "%"} on an index that may have @code{NULL} values.
@item
@code{REVOKE ALL PRIVILEGES} didn't revoke all privileges.
@item
Allow creation of temporary tables with same name as the original table.
@item
-When granting a user a grant option for a database, he couldn't grant
+When granting a user a @strong{grant} option for a database, he couldn't grant
privileges to other users.
@item
New command: @code{SHOW GRANTS FOR user} (by Sinisa).
@@ -49348,13 +51600,13 @@ Some configure issues to fix problems with big file system detection.
@item
Added patches for MIT-pthreads on NetBSD.
@item
-Fixed range bug in MyISAM.
+Fixed range bug in @code{MyISAM}.
@item
@code{ASC} is now the default again for @code{ORDER BY}.
@item
Added @code{LIMIT} to @code{UPDATE}.
@item
-New client function: @code{mysql_change_user()}.
+Added @code{mysql_change_user()} function to the MySQL C API.
@item
Added character set to @code{SHOW VARIABLES}.
@item
@@ -49365,7 +51617,7 @@ an empty value list to insert a row in which each column is set to its
default value.
@item
Changed @code{SUBSTRING(text FROM pos)} to conform to ANSI SQL. (Before this
-construct returned the rightmost 'pos' characters).
+construct returned the rightmost @code{pos} characters.)
@item
@code{SUM()} with @code{GROUP BY} returned 0 on some systems.
@item
@@ -49388,32 +51640,32 @@ New function @code{COALESCE()}.
@itemize @bullet
@item
-Fixed range optimizer bug: @code{SELECT * FROM table_name WHERE
+Fixed range optimiser bug: @code{SELECT * FROM table_name WHERE
key_part1 >= const AND (key_part2 = const OR key_part2 = const)}. The
bug was that some rows could be duplicated in the result.
@item
Running @code{myisamchk} without @code{-a} updated the index
-distribution wrong.
+distribution incorrectly.
@item
-@code{SET SQL_LOW_PRIORITY_UPDATES=1} gave parse error before.
+@code{SET SQL_LOW_PRIORITY_UPDATES=1} was causing a parse error.
@item
-You can now update indexes columns that are used in the @code{WHERE} clause.
+You can now update index columns that are used in the @code{WHERE} clause.
@code{UPDATE tbl_name SET KEY=KEY+1 WHERE KEY > 100}
@item
Date handling should now be a bit faster.
@item
-Added handling of fuzzy dates (dates where day or month is 0):
-(Like: 1999-01-00)
+Added handling of fuzzy dates (dates where day or month is 0), such as
+1999-01-00.
@item
-Fixed optimization of @code{SELECT ... WHERE key_part1=const1 AND
-key_part_2=const2 AND key_part1=const4 AND key_part2=const4} ; Indextype
+Fixed optimisation of @code{SELECT ... WHERE key_part1=const1 AND
+key_part_2=const2 AND key_part1=const4 AND key_part2=const4}; Indextype
should be @code{range} instead of @code{ref}.
@item
-Fixed @code{egcs} 1.1.2 optimizer bug (when using @code{BLOB}s) on Linux Alpha.
+Fixed @code{egcs} 1.1.2 optimiser bug (when using @code{BLOB}s) on Linux Alpha.
@item
Fixed problem with @code{LOCK TABLES} combined with @code{DELETE FROM table}.
@item
-MyISAM tables now allow keys on @code{NULL} and @code{BLOB/TEXT} columns.
+@code{MyISAM} tables now allow keys on @code{NULL} and @code{BLOB/TEXT} columns.
@item
The following join is now much faster:
@code{SELECT ... FROM t1 LEFT JOIN t2 ON ... WHERE t2.not_null_column IS NULL}.
@@ -49430,14 +51682,14 @@ the columns are not identically packed.
Indexes are now used for @code{WHERE column_name IS NULL}.
@item
Changed heap tables to be stored in low_byte_first order (to make it easy
-to convert to MyISAM tables)
+to convert to @code{MyISAM} tables)
@item
-Automatic change of HEAP temporary tables to MyISAM tables in case of
-'table is full' errors.
+Automatic change of @code{HEAP} temporary tables to @code{MyISAM} tables
+in case of 'table is full' errors.
@item
-Added option @code{--init-file=file_name} to @code{mysqld}.
+Added @code{--init-file=file_name} option to @code{mysqld}.
@item
-@code{COUNT(DISTINCT value, [value, ...])}
+Added @code{COUNT(DISTINCT value, [value, ...])}.
@item
@code{CREATE TEMPORARY TABLE} now creates a temporary table, in its own
namespace, that is automatically deleted if connection is dropped.
@@ -49470,7 +51722,7 @@ A new table handler library (@code{MyISAM}) with a lot of new features.
You can create in-memory @code{HEAP} tables which are extremely fast for
lookups.
@item
-Support for big files (63 bit) on OSes that support big files.
+Support for big files (63-bit) on OSes that support big files.
@item
New function @code{LOAD_FILE(filename)} to get the contents of a file as a
string value.
@@ -49481,22 +51733,22 @@ between tables.
@item
Added the ODBC 3.0 @code{EXTRACT(interval FROM datetime)} function.
@item
-Columns defined as @code{FLOAT(X)} is not rounded on storage and may be
+Columns defined as @code{FLOAT(X)} are not rounded on storage and may be
in scientific notation (1.0 E+10) when retrieved.
@item
@code{REPLACE} is now faster than before.
@item
Changed @code{LIKE} character comparison to behave as @code{=};
-This means that @code{'e' LIKE '@'e'} (if the line doesn't display
-correctly, the latter 'e' means a French 'e' with a dot above) is now true.
+This means that @code{'e' LIKE '@'e'} is now true. (If the line doesn't
+display correctly, the latter 'e' is a French 'e' with a dot above.)
@item
@code{SHOW TABLE STATUS} returns a lot of information about the tables.
@item
Added @code{LIKE} to the @code{SHOW STATUS} command.
@item
-Added privilege column to @code{SHOW COLUMNS}.
+Added @code{Privileges} column to @code{SHOW COLUMNS}.
@item
-Added columns @code{packed} and @code{comment} to @code{SHOW INDEX}.
+Added @code{Packed} and @code{Comment} columns to @code{SHOW INDEX}.
@item
Added comments to tables (with @code{CREATE TABLE ... COMMENT "xxx"}).
@item
@@ -49522,22 +51774,22 @@ SELECT ... FROM ... WHERE ... PROCEDURE ANALYSE([max elements,[max memory]])
This procedure is extremely useful when you want to check the data in your
table!
@item
-@code{BINARY} cast to force a string to be compared case sensitively.
+@code{BINARY} cast to force a string to be compared in case sensitive fashion.
@item
-Added option @code{--skip-show-database} to @code{mysqld}.
+Added @code{--skip-show-database} option to @code{mysqld}.
@item
-Check if a row has changed in an @code{UPDATE} now also works with
-@code{BLOB}/@code{TEXT} columns.
+Check whether or not a row has changed in an @code{UPDATE} now also works
+with @code{BLOB}/@code{TEXT} columns.
@item
Added the @code{INNER} join syntax. @strong{NOTE}: This made @code{INNER}
a reserved word!
@item
-Added support for netmasks to the hostname in the MySQL tables.
+Added support for netmasks to the hostname in the MySQL grant tables.
You can specify a netmask using the @code{IP/NETMASK} syntax.
@item
If you compare a @code{NOT NULL DATE/DATETIME} column with @code{IS
NULL}, this is changed to a compare against @code{0} to satisfy some ODBC
-applications. (By @email{shreeve@@uci.edu}).
+applications. (By @email{shreeve@@uci.edu}.)
@item
@code{NULL IN (...)} now returns @code{NULL} instead of @code{0}. This will
ensure that @code{null_column NOT IN (...)} doesn't match
@@ -49548,16 +51800,17 @@ Fix storage of floating-point values in @code{TIME} columns.
Changed parsing of @code{TIME} strings to be more strict. Now the
fractional second part is detected (and currently skipped). The
following formats are supported:
-@table @code
+@itemize
@item [[DAYS] [H]H:]MM:]SS[.fraction]
@item [[[[[H]H]H]H]MM]SS[.fraction]
-@end table
+@end itemize
@item
-Detect (and ignore) second fraction part from @code{DATETIME}.
+Detect (and ignore) fractional second part from @code{DATETIME}.
@item
Added the @code{LOW_PRIORITY} attribute to @code{LOAD DATA INFILE}.
@item
-The default index name now uses the same case as the used column name.
+The default index name now uses the same case as the column name on which the
+index name is based.
@item
Changed default number of connections to 100.
@item
@@ -49566,11 +51819,11 @@ Use bigger buffers when using @code{LOAD DATA INFILE}.
@code{DECIMAL(x,y)} now works according to ANSI SQL.
@item
Added aggregate UDF functions. Thanks to Andreas F. Bobak
-@email{bobak@@relog.ch} for this!
+(@email{bobak@@relog.ch}) for this!
@item
@code{LAST_INSERT_ID()} is now updated for @code{INSERT INTO ... SELECT}.
@item
-Some small changes to the join table optimizer to make some joins faster.
+Some small changes to the join table optimiser to make some joins faster.
@item
@code{SELECT DISTINCT} is much faster; It uses the new @code{UNIQUE}
functionality in @code{MyISAM}. One difference compared to MySQL Version 3.22
@@ -49587,22 +51840,22 @@ Don't allow @code{AUTO_INCREMENT} for other than numerical columns.
Using @code{AUTO_INCREMENT} will now automatically make the column
@code{NOT NULL}.
@item
-Show @code{NULL} as the default value for AUTO_INCREMENT columns.
+Show @code{NULL} as the default value for @code{AUTO_INCREMENT} columns.
@item
Added @code{SQL_BIG_RESULT}; @code{SQL_SMALL_RESULT} is now default.
@item
Added a shared library RPM. This enhancement was contributed by David
-Fox (dsfox@@cogsci.ucsd.edu).
+Fox (@email{dsfox@@cogsci.ucsd.edu}).
@item
-Added a @code{--enable-large-files/--disable-large-files} switch to
-@code{configure}. See @file{configure.in} for some systems where this is
+Added @code{--enable-large-files} and @code{--disable-large-files} switches
+to @code{configure}. See @file{configure.in} for some systems where this is
automatically turned off because of broken implementations.
@item
Upgraded @code{readline} to 4.0.
@item
New @code{CREATE TABLE} options: @code{PACK_KEYS} and @code{CHECKSUM}.
@item
-Added @code{mysqld} option @code{--default-table-type}.
+Added @code{--default-table-type} option to @code{mysqld}.
@end itemize
@@ -49612,8 +51865,8 @@ Added @code{mysqld} option @code{--default-table-type}.
@cindex changes, version 3.22
The 3.22 version has faster and safer connect code than version 3.21, as well
-as a lot of new nice enhancements. The reason for not including these changes
-As there aren't really any MAJOR changes, upgrading from 3.21 to 3.22 should
+as a lot of new nice enhancements.
+As there aren't really any major changes, upgrading from 3.21 to 3.22 should
be very easy and painless. @xref{Upgrading-from-3.21}.
@menu
@@ -49690,7 +51943,7 @@ compile all relevant files for 3.22.33 :(
@itemize @bullet
@item
-Fixed problems in Windows when locking tables with @code{LOCK TABLE}
+Fixed problems in Windows when locking tables with @code{LOCK TABLE}.
@item
Quicker kill of @code{SELECT DISTINCT} queries.
@end itemize
@@ -49733,7 +51986,7 @@ A few small fixes for the Windows version.
@itemize @bullet
@item
-Fixed optimizer problem on @code{SELECT} when using many overlapping indexes.
+Fixed optimiser problem on @code{SELECT} when using many overlapping indexes.
@item
Disabled floating-point exceptions for FreeBSD to fix core dump when
doing @code{SELECT floor(pow(2,63))}.
@@ -49814,7 +52067,7 @@ Fixed core dump with empty @code{BLOB/TEXT} column to @code{REVERSE()}.
Extended @code{/*! */} with version numbers.
@item
Changed @code{SUBSTRING(text FROM pos)} to conform to ANSI SQL. (Before this
-construct returned the rightmost 'pos' characters).
+construct returned the rightmost 'pos' characters.)
@item
Fixed problem with @code{LOCK TABLES} combined with @code{DELETE FROM table}
@item
@@ -49825,7 +52078,7 @@ Fixed problem that INSERT ... SELECT didn't use SQL_BIG_TABLES.
Password wasn't updated correctly if privileges didn't change on:
@code{GRANT ... IDENTIFIED BY}
@item
-Fixed range optimizer bug in
+Fixed range optimiser bug in
@code{SELECT * FROM table_name WHERE key_part1 >= const AND (key_part2 = const OR key_part2 = const)}
@item
Fixed bug in compression key handling in ISAM.
@@ -49848,7 +52101,7 @@ Fixed some small problems with the installation.
@item
@code{DATA} is not a reserved word anymore.
@item
-Fixed optimizer bug with tables with only one row.
+Fixed optimiser bug with tables with only one row.
@item
Fixed bug when using @code{LOCK TABLES table_name READ; FLUSH TABLES;}
@item
@@ -49935,7 +52188,7 @@ Fixed a problem with @code{Host '...' is not allowed to connect to this MySQL
server} after one had inserted a new MySQL user with a @code{GRANT}
command.
@item
-Changed to use @code{TCP_NODELAY} also on Linux (Should give faster TCP/IP
+Changed to use @code{TCP_NODELAY} also on Linux (should give faster TCP/IP
connections).
@end itemize
@@ -50016,7 +52269,7 @@ rows. Fixed.
Extended @code{ENCRYPT()} to take longer salt strings than 2 characters.
@item
@code{longlong2str} is now much faster than before. For @code{Intel x86}
-platforms, this function is written in optimized assembler.
+platforms, this function is written in optimised assembler.
@item
Added the @code{MODIFY} keyword to @code{ALTER TABLE}.
@end itemize
@@ -50032,7 +52285,7 @@ were flushed.
@item
Name change of some variables in @code{SHOW STATUS}.
@item
-Fixed problem with @code{ORDER BY} with 'only index' optimization when there
+Fixed problem with @code{ORDER BY} with 'only index' optimisation when there
were multiple key definitions for a used column.
@item
@code{DATE} and @code{DATETIME} columns are now up to 5 times faster than
@@ -50152,7 +52405,7 @@ Fix for @code{isamchk} for tables which need big temporary files.
@itemize @bullet
@item
-@strong{IMPORTANT}: You must run the @code{mysql_fix_privilege_tables} script
+@strong{Important}: You must run the @code{mysql_fix_privilege_tables} script
when you upgrade to this version! This is needed because of the new
@code{GRANT} system. If you don't do this, you will get @code{Access
denied} when you try to use @code{ALTER TABLE}, @code{CREATE INDEX} or
@@ -50213,7 +52466,7 @@ Changed @code{+}, @code{-} (sign and minus), @code{*}, @code{/}, @code{%},
Fixed a bug in @code{ALTER TABLE} that caused @code{mysqld} to crash.
@item
MySQL now always reports the conflicting key values when a
-duplicate key entry occurs. (Before this was only reported for @code{INSERT}).
+duplicate key entry occurs. (Before this was only reported for @code{INSERT}.)
@item
New syntax: @code{INSERT INTO tbl_name SET col_name=value, col_name=value, ...}
@item
@@ -50233,7 +52486,7 @@ Added @code{maybe_null} to the UDF structure.
Added option @code{IGNORE} to @code{INSERT} statements with many rows.
@item
Fixed some problems with sorting of the koi8 character sets; Users of koi8
-@strong{MUST} run @code{isamchk -rq} on each table that has an index on
+@strong{must} run @code{isamchk -rq} on each table that has an index on
a @code{CHAR} or @code{VARCHAR} column.
@item
New script @code{mysql_setpermission}, by Luuk de Boer, allows one
@@ -50282,7 +52535,7 @@ Added a lot more output to @code{mysqladmin debug}.
@item
You can now start @code{mysqld} on Windows with the @code{--flush} option.
This will flush all tables to disk after each update. This makes things
-much safer on NT/Win98 but also @strong{MUCH} slower.
+much safer on NT/Win98 but also @strong{much} slower.
@end itemize
@@ -50349,7 +52602,7 @@ Upgraded @code{libtool} to get the configure more portable.
Fixed slow @code{UPDATE} and @code{DELETE} operations when using
@code{DATETIME} or @code{DATE} keys.
@item
-Changed optimizer to make it better at deciding when to do a full join
+Changed optimiser to make it better at deciding when to do a full join
and when using keys.
@item
You can now use @code{mysqladmin proc} to display information about your own
@@ -50369,7 +52622,7 @@ and INSERT_ID's in the update log.
@item
Added @code{--where} option to @code{mysqldump} (patch by Jim Faucette).
@item
-The lexical analyzer now uses ``perfect hashing'' for faster parsing of SQL
+The lexical analyser now uses ``perfect hashing'' for faster parsing of SQL
statements.
@end itemize
@@ -50385,7 +52638,7 @@ For the @code{LOAD DATA INFILE} statement, you can now use the new @code{LOCAL}
keyword to read the file from the client. @code{mysqlimport} will
automatically use @code{LOCAL} when importing with the TCP/IP protocol.
@item
-Fixed small optimize problem when updating keys.
+Fixed small optimise problem when updating keys.
@item
Changed makefiles to support shared libraries.
@item
@@ -50450,7 +52703,7 @@ the @strong{process} privilege to bypass the update log.
@item
Fixed fatal bug in @code{LPAD()}.
@item
-Initialize line buffer in @file{mysql.cc} to make @code{BLOB} reading from
+Initialise line buffer in @file{mysql.cc} to make @code{BLOB} reading from
pipes safer.
@item
Added @code{-O max_connect_errors=#} option to @code{mysqld}.
@@ -50485,13 +52738,13 @@ trailing @samp{;}.
@item
Fix for corrupted fixed-format output generated by @code{SELECT INTO OUTFILE}.
@item
-@strong{WARNING: INCOMPATIBLE CHANGE!!}
+@strong{Warning: Incompatible change!}
Added Oracle @code{GREATEST()} and @code{LEAST()} functions. You must now use
these instead of the @code{MAX()} and @code{MIN()} functions to get the
largest/smallest value from a list of values. These can now handle @code{REAL},
@code{BIGINT} and string (@code{CHAR} or @code{VARCHAR}) values.
@item
-@strong{WARNING: INCOMPATIBLE CHANGE!!}
+@strong{Warning: Incompatible change!}
@code{DAYOFWEEK()} had offset 0 for Sunday. Changed the offset to 1.
@item
Give an error for queries that mix @code{GROUP BY} columns and fields when
@@ -50500,7 +52753,7 @@ there is no @code{GROUP BY} specification.
Added @code{--vertical} option to @code{mysql}, for printing results in
vertical mode.
@item
-Index-only optimization; some queries are now resolved using
+Index-only optimisation; some queries are now resolved using
only indexes. Until MySQL 4.0, this works only for numeric columns.
@xref{MySQL indexes, , MySQL indexes}.
@item
@@ -50541,7 +52794,7 @@ Added function @code{SUBSTRING()} with 2 arguments.
If you created a table with a record length smaller than 5, you couldn't
delete rows from the table.
@item
-Added optimization to remove const reference tables from @code{ORDER BY} and
+Added optimisation to remove const reference tables from @code{ORDER BY} and
@code{GROUP BY}.
@item
@code{mysqld} now automatically disables system locking on Linux and Windows,
@@ -50599,7 +52852,7 @@ a chroot environment (by Nikki Chumakov @email{nikkic@@cityline.ru}).
Trailing spaces are now ignored when comparing case-sensitive strings;
this should fix some problems with ODBC and flag 512!
@item
-Fixed a core-dump bug in the range optimizer.
+Fixed a core-dump bug in the range optimiser.
@item
Added @code{--one-thread} option to @code{mysqld}, for debugging with
LinuxThreads (or @code{glibc}). (This replaces the @code{-T32} flag)
@@ -50730,10 +52983,10 @@ Added @code{-T32} option to @code{mysqld}, for running all queries under the
main thread. This makes it possible to debug @code{mysqld} under Linux with
@code{gdb}!
@item
-Added optimization of @code{not_null_column IS NULL} (needed for some Access
+Added optimisation of @code{not_null_column IS NULL} (needed for some Access
queries).
@item
-Allow @code{STRAIGHT_JOIN} to be used between two tables to force the optimizer
+Allow @code{STRAIGHT_JOIN} to be used between two tables to force the optimiser
to join them in a specific order.
@item
String functions now return @code{VARCHAR} rather than @code{CHAR} and
@@ -50861,7 +53114,7 @@ returned a row in some contexts (bug only in 3.21.31).
@code{GROUP BY} + @code{ORDER BY} returned one empty row when no rows where
found.
@item
-Fixed a bug in the range optimizer that wrote
+Fixed a bug in the range optimiser that wrote
@code{Use_count: Wrong count for ...} in the error log file.
@end itemize
@@ -50948,12 +53201,12 @@ Fixed permission problem with @code{umask()} and creating new databases.
@item
Fixed permission problem on result file with @code{SELECT ... INTO OUTFILE ...}
@item
-Fixed problem in range optimizer (core dump) for a very complex query.
+Fixed problem in range optimiser (core dump) for a very complex query.
@item
Fixed problem when using @code{MIN(integer)} or @code{MAX(integer)} in
@code{GROUP BY}.
@item
-Fixed bug on Alpha when using integer keys. (Other keys worked on Alpha).
+Fixed bug on Alpha when using integer keys. (Other keys worked on Alpha.)
@item
Fixed bug in @code{WEEK("XXXX-xx-01")}.
@end itemize
@@ -50979,12 +53232,12 @@ Fixed bug in record caches; for some queries, you could get
Added user level lock functions @code{GET_LOCK(string,timeout)},
@code{RELEASE_LOCK(string)}.
@item
-Added @code{opened_tables} to @code{show status}.
+Added @code{Opened_tables} to @code{show status}.
@item
Changed connect timeout to 3 seconds to make it somewhat harder
for crackers to kill @code{mysqld} through telnet + TCP/IP.
@item
-Fixed bug in range optimizer when using
+Fixed bug in range optimiser when using
@code{WHERE key_part_1 >= something AND key_part_2 <= something_else}.
@item
Changed @code{configure} for detection of FreeBSD 3.0 9803xx and above
@@ -51023,10 +53276,10 @@ An @code{ENUM} field that is not declared @code{NOT NULL} has @code{NULL} as
the default value.
(Previously, the default value was the first enumeration value.)
@item
-Fixed bug in the join optimizer code when using many part keys
-on the same key: @code{INDEX (Organization,Surname(35),Initials(35))}.
+Fixed bug in the join optimiser code when using many part keys
+on the same key: @code{INDEX (Organisation,Surname(35),Initials(35))}.
@item
-Added some tests to the table order optimizer to get some cases with
+Added some tests to the table order optimiser to get some cases with
@code{SELECT ... FROM many_tables} much faster.
@item
Added a retry loop around @code{accept()} to possibly fix some problems on some
@@ -51064,7 +53317,7 @@ Dynamic loadable functions. Based on source from Alexis Mikhailov.
You couldn't delete from a table if no one had done a @code{SELECT} on the
table.
@item
-Fixed problem with range optimizer with many @code{OR} operators on key parts
+Fixed problem with range optimiser with many @code{OR} operators on key parts
inside each other.
@item
Recoded @code{MIN()} and @code{MAX()} to work properly with strings and
@@ -51079,7 +53332,7 @@ Added Italian error messages from @email{brenno@@dewinter.com}.
@item
@code{configure} now works better on OSF1 (tested on 4.0D).
@item
-Added hooks to allow @code{LIKE} optimization with international character
+Added hooks to allow @code{LIKE} optimisation with international character
support.
@item
Upgraded @code{DBI} to 0.93.
@@ -51100,7 +53353,7 @@ The following symbols are now reserved words:
Setting a @code{TIMESTAMP} to @code{NULL} in @code{LOAD DATA INFILE ...} didn't
set the current time for the @code{TIMESTAMP}.
@item
-Fix @code{BETWEEN} to recognize binary strings. Now @code{BETWEEN} is
+Fix @code{BETWEEN} to recognise binary strings. Now @code{BETWEEN} is
case sensitive.
@item
Added @code{--skip-thread-priority} option to @code{mysqld}, for systems
@@ -51111,7 +53364,7 @@ Added ODBC functions @code{DAYNAME()} and @code{MONTHNAME()}.
Added function @code{TIME_FORMAT()}. This works like @code{DATE_FORMAT()},
but takes a time string (@code{'HH:MM:DD'}) as argument.
@item
-Fixed unlikely(?) key optimizer bug when using @code{OR}s of key parts
+Fixed unlikely(?) key optimiser bug when using @code{OR}s of key parts
inside @code{AND}s.
@item
Added command @code{variables} to @code{mysqladmin}.
@@ -51153,7 +53406,7 @@ Fixed bug that core dumped when using many @code{LEFT OUTER JOIN} clauses.
@item
Fixed bug in @code{ORDER BY} on string formula with possible @code{NULL} values.
@item
-Fixed problem in range optimizer when using <= on sub index.
+Fixed problem in range optimiser when using <= on sub index.
@item
Added functions @code{DAYOFYEAR()}, @code{DAYOFMONTH()}, @code{MONTH()},
@code{YEAR()}, @code{WEEK()}, @code{QUARTER()}, @code{HOUR()}, @code{MINUTE()},
@@ -51192,7 +53445,7 @@ Configure changes for some operating systems.
@itemize @bullet
@item
-Fixed optimizer bug when using
+Fixed optimiser bug when using
@code{WHERE data_field = date_field2 AND date_field2 = constant}.
@item
Added command @code{SHOW STATUS}.
@@ -51297,7 +53550,7 @@ restart if one thread was reading data that another thread modified.
@item
@code{LIMIT offset,count} didn't work in @code{INSERT ... SELECT}.
@item
-Optimized key block caching. This will be quicker than the old algorithm when
+Optimised key block caching. This will be quicker than the old algorithm when
using bigger key caches.
@end itemize
@@ -51311,7 +53564,7 @@ Added ODBC 2.0 & 3.0 functions @code{POWER()}, @code{SPACE()},
@code{COT()}, @code{DEGREES()}, @code{RADIANS()}, @code{ROUND(2 arg)}
and @code{TRUNCATE()}.
@item
-@strong{WARNING: INCOMPATIBLE CHANGE!!} @code{LOCATE()} parameters were
+@strong{Warning: Incompatible change!} @code{LOCATE()} parameters were
swapped according to ODBC standard. Fixed.
@item
Added function @code{TIME_TO_SEC()}.
@@ -51330,14 +53583,14 @@ be compatible with @code{mysqldump}.
@itemize @bullet
@item
-@strong{WARNING: INCOMPATIBLE CHANGE!!} @code{mysqlperl} is now from
+@strong{Warning: Incompatible change!} @code{mysqlperl} is now from
Msql-Mysql-modules. This means that @code{connect()} now takes
@code{host}, @code{database}, @code{user}, @code{password} arguments! The old
version took @code{host}, @code{database}, @code{password}, @code{user}.
@item
Allow @code{DATE '1997-01-01'}, @code{TIME '12:10:10'} and
@code{TIMESTAMP '1997-01-01 12:10:10'} formats required by ANSI SQL.
-@strong{WARNING: INCOMPATIBLE CHANGE!!} This has the unfortunate
+@strong{Warning: Incompatible change!} This has the unfortunate
side-effect that you no longer can have columns named @code{DATE}, @code{TIME}
or @code{TIMESTAMP}. :( Old columns can still be accessed through
@code{tablename.columnname}!)
@@ -51361,7 +53614,7 @@ New portable benchmark suite with @code{DBD}, with test results from
designed to find as many limits as possible in a SQL server. Tested with
@code{mSQL}, PostgreSQL, Solid and MySQL.
@item
-Fixed bug in range-optimizer that crashed MySQL on some queries.
+Fixed bug in range-optimiser that crashed MySQL on some queries.
@item
Table and column name completion for @code{mysql} command line tool, by Zeev
Suraski and Andi Gutmans.
@@ -51603,7 +53856,7 @@ Fixed some @code{configure} issues.
Made the locking code a bit safer. Fixed very unlikely
deadlock situation.
@item
-Fixed a couple of bugs in the range optimizer. Now the new range benchmark
+Fixed a couple of bugs in the range optimiser. Now the new range benchmark
@code{test-select} works.
@end itemize
@@ -51621,7 +53874,7 @@ Fixed bug in range calculation that could return empty
set when searching on multiple key with only one entry (very rare).
@item
Most things ported to FSU Pthreads, which should allow MySQL to
-run on SCO. @xref{SCO}.
+run on Caldera (SCO). @xref{Caldera}.
@end itemize
@@ -51653,7 +53906,7 @@ Fixed bug with @code{GROUP BY} and @code{SELECT} on key with many values.
@code{mysql_use_result()}. This affected at least some cases of
@code{mysqldump --quick}.
@item
-Fixed bug in optimization of @code{WHERE const op field}.
+Fixed bug in optimisation of @code{WHERE const op field}.
@item
Fixed problem when sorting on @code{NULL} fields.
@item
@@ -51663,7 +53916,7 @@ Added @code{--pid-file=#} option to @code{mysqld}.
@item
Added date formatting to @code{FROM_UNIXTIME()}, originally by Zeev Suraski.
@item
-Fixed bug in @code{BETWEEN} in range optimizer (Did only test = of the first
+Fixed bug in @code{BETWEEN} in range optimiser (did only test = of the first
argument).
@item
Added machine-dependent files for MIT-pthreads i386-SCO. There is probably
@@ -51805,7 +54058,7 @@ Changed the default sort buffer size from 2M to 1M.
@itemize @bullet
@item
-The range optimizer is coded, but only 85% tested. It can be enabled with
+The range optimiser is coded, but only 85% tested. It can be enabled with
@code{--new}, but it crashes core a lot yet...
@item
More portable. Should compile on AIX and alpha-digital.
@@ -51857,7 +54110,7 @@ Fixed bug that you couldn't use @code{tbl_name.field_name} in @code{UPDATE}.
Fixed @code{SELECT DISTINCT} when using 'hidden group'. For example:
@example
mysql> SELECT DISTINCT MOD(some_field,10) FROM test
- GROUP BY some_field;
+ -> GROUP BY some_field;
@end example
Note: @code{some_field} is normally in the @code{SELECT} part. ANSI SQL should
require it.
@@ -51882,7 +54135,7 @@ Added @code{--log-update} option to @code{mysqld}, to get a log suitable for
incremental updates.
@item
New command @code{EXPLAIN SELECT ...} to get information about how the
-optimizer will do the join.
+optimiser will do the join.
@item
For easier client code, the client should no longer use
@code{FIELD_TYPE_TINY_BLOB}, @code{FIELD_TYPE_MEDIUM_BLOB},
@@ -51927,12 +54180,12 @@ will also work with @code{NULL} values.
@item
Full @code{WHERE} with expressions.
@item
-New range optimizer that can resolve ranges when some keypart prefix is
+New range optimiser that can resolve ranges when some keypart prefix is
constant. Example:
@example
mysql> SELECT * FROM tbl_name
- WHERE key_part_1="customer"
- AND key_part_2>=10 AND key_part_2<=10;
+ -> WHERE key_part_1="customer"
+ -> AND key_part_2>=10 AND key_part_2<=10;
@end example
@end itemize
@@ -52009,7 +54262,7 @@ Arithmetic error on Sparc-386.
Added @code{--unbuffered} option to @code{mysql}, for new @code{mysqlaccess}.
@item
When using overlapping (unnecessary) keys and join over many tables,
-the optimizer could get confused and return 0 records.
+the optimiser could get confused and return 0 records.
@end itemize
@@ -52041,7 +54294,7 @@ works.
@item
A couple of bugs fixed in @code{SELECT ... GROUP BY}.
@item
-Fixed memory overrun bug in @code{WHERE} with many unoptimizable brace levels.
+Fixed memory overrun bug in @code{WHERE} with many unoptimisable brace levels.
@item
Fixed some small bugs in the grant code.
@item
@@ -52092,7 +54345,7 @@ bugs that appear during the build with it.
Changed @file{libmysql.c} to prefer @code{getpwuid()} instead of
@code{cuserid()}.
@item
-Fixed bug in @code{SELECT} optimizer when using many tables with the same
+Fixed bug in @code{SELECT} optimiser when using many tables with the same
column used as key to different tables.
@item
Added new latin2 and Russian KOI8 character tables.
@@ -52375,10 +54628,10 @@ returns an array of column lengths (of type @code{uint}).
@item
Fixed bug with @code{IS NULL} in @code{WHERE} clause.
@item
-Changed the optimizer a little to get better results when searching on a key
+Changed the optimiser a little to get better results when searching on a key
part.
@item
-Added @code{SELECT} option @code{STRAIGHT_JOIN} to tell the optimizer that
+Added @code{SELECT} option @code{STRAIGHT_JOIN} to tell the optimiser that
it should join tables in the given order.
@item
Added support for comments starting with @code{'--'} in @file{mysql.cc}
@@ -52390,7 +54643,7 @@ lookups. The column that is used should be a constant for each group because
the value is calculated only once for the first row that is found for a group.
@example
mysql> SELECT id,lookup.text,sum(*) FROM test,lookup
- WHERE test.id=lookup.id GROUP BY id;
+ -> WHERE test.id=lookup.id GROUP BY id;
@end example
@item
Fixed bug in @code{SUM(function)} (could cause a core dump).
@@ -52538,7 +54791,7 @@ information is kept here for historical purposes only.
@itemize @bullet
@item
-Some new functions, some more optimization on joins.
+Some new functions, some more optimisation on joins.
@item
Should now compile clean on Linux (2.0.x).
@item
@@ -52606,10 +54859,21 @@ Fixed @code{DISTINCT} with calculated columns.
@node Porting, Environment variables, News, Top
-@appendix Comments on porting to other systems
+@appendix Porting to Other Systems
@cindex porting, to other systems
+This appendix will help you port MySQL to other operationg systems.
+Do check the list of currently supported operating systems first.
+@xref{Which OS}.
+If you have created a new port of MySQL, please let us know so that
+we can list it here and on our web site (@uref{http://www.mysql.com/}),
+recommending it to other users.
+
+Note: If you create a new port of MySQL, you are free to copy and
+distribute it under the GPL license, but it does not make you a
+copyright holder of MySQL.
+
A working Posix thread library is needed for the server. On Solaris 2.5
we use Sun PThreads (the native thread support in 2.4 and earlier
versions are not good enough) and on Linux we use LinuxThreads by Xavier
@@ -52617,13 +54881,13 @@ Leroy, @email{Xavier.Leroy@@inria.fr}.
The hard part of porting to a new Unix variant without good native
thread support is probably to port MIT-pthreads. See
-@file{mit-pthreads/README} and
-@uref{http://www.humanfactor.com/pthreads/, Programming POSIX Threads}.
+@file{mit-pthreads/README} and Programming POSIX Threads
+(@uref{http://www.humanfactor.com/pthreads/}).
The MySQL distribution includes a patched version of
-Provenzano's Pthreads from MIT (see
-@uref{http://www.mit.edu:8001/people/proven/pthreads.html, MIT Pthreads
-web page}). This can be used for some operating systems that do not
+Provenzano's Pthreads from MIT (see the MIT Pthreads web page at
+@uref{http://www.mit.edu:8001/people/proven/pthreads.html}).
+This can be used for some operating systems that do not
have POSIX threads.
It is also possible to use another user level thread package named
@@ -52675,8 +54939,8 @@ will ensure that your thread installation has even a remote chance to work!
@menu
* Debugging server:: Debugging a MySQL server
* Debugging client:: Debugging a MySQL client
-* The DBUG package:: The DBUG package
-* Locking methods:: Locking methods
+* The DBUG package:: The DBUG Package
+* Locking methods:: Locking ethods
* RTS-threads:: Comments about RTS threads
* Thread packages:: Differences between different thread packages
@end menu
@@ -52692,7 +54956,7 @@ will ensure that your thread installation has even a remote chance to work!
If you are using some functionality that is very new in MySQL,
you can try to run @code{mysqld} with the @code{--skip-new} (which will disable all
new, potentially unsafe functionality) or with @code{--safe-mode} which
-disables a lot of optimization that may cause problems.
+disables a lot of optimisation that may cause problems.
@xref{Crashing}.
If @code{mysqld} doesn't want to start, you should check that you don't have
@@ -52712,7 +54976,7 @@ may help solve some problems. This command also provides some useful
information even if you haven't compiled MySQL for debugging!
If the problem is that some tables are getting slower and slower you
-should try to optimize the table with @code{OPTIMIZE TABLE} or
+should try to optimise the table with @code{OPTIMIZE TABLE} or
@code{myisamchk}. @xref{MySQL Database Administration}. You should also
check the slow queries with @code{EXPLAIN}.
@@ -52721,7 +54985,7 @@ problems that may be unique to your environment.
@xref{Operating System Specific Notes}.
@menu
-* Compiling for debugging:: Compiling MYSQL for debugging.
+* Compiling for debugging:: Compiling MYSQL for debugging
* Making trace files:: Creating trace files
* Using gdb on mysqld:: Debugging mysqld under gdb
* Using stack trace:: Using a stack trace
@@ -52731,7 +54995,7 @@ problems that may be unique to your environment.
@node Compiling for debugging, Making trace files, Debugging server, Debugging server
-@appendixsubsec Compiling MYSQL for debugging.
+@appendixsubsec Compiling MYSQL for Debugging
If you have some very specific problem, you can always try to debug
MySQL. To do this you must configure MySQL with the
@@ -52744,7 +55008,9 @@ lists the @code{mysqld} version as @code{mysql ... --debug} in this case.
If you are using gcc or egcs, the recommended configure line is:
@example
-CC=gcc CFLAGS="-O2" CXX=gcc CXXFLAGS="-O2 -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --with-debug --with-extra-charsets=complex
+CC=gcc CFLAGS="-O2" CXX=gcc CXXFLAGS="-O2 -felide-constructors \
+ -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql \
+ --with-debug --with-extra-charsets=complex
@end example
This will avoid problems with the @code{libstdc++} library and with C++
@@ -52783,7 +55049,7 @@ default compiled with support for trace files.
@node Making trace files, Using gdb on mysqld, Compiling for debugging, Debugging server
-@appendixsubsec Creating trace files
+@appendixsubsec Creating Trace Files
If the @code{mysqld} server doesn't start or if you can cause the
@code{mysqld} server to crash quickly, you can try to create a trace
@@ -52811,7 +55077,7 @@ After this you can use the @code{mysql.exe} command line tool in a
second DOS window to reproduce the problem. You can take down the above
@code{mysqld} server with @code{mysqladmin shutdown}.
-Note that the trace file will get very @emph{BIG}!
+Note that the trace file will get @strong{very big}!
If you want to have a smaller trace file, you can use something like:
@code{mysqld --debug=d,info,error,query,general,where:O,/tmp/mysqld.trace}
@@ -52823,7 +55089,7 @@ If you make a bug report about this, please only send the lines from the
trace file to the appropriate mailing list where something seems to go
wrong! If you can't locate the wrong place, you can ftp the trace file,
together with a full bug report, to
-@uref{ftp://support.mysql.com/pub/mysql/secret} so that a MySQL
+@uref{ftp://support.mysql.com/pub/mysql/secret/} so that a MySQL
developer can take a look a this.
The trace file is made with the @strong{DBUG} package by Fred Fish.
@@ -52840,7 +55106,9 @@ more information if @code{mysqld} crashes.
With some older @code{gdb} versions on Linux you must use @code{run
--one-thread} if you want to be able to debug @code{mysqld} threads. In
-this case you can only have one thread active at a time.
+this case you can only have one thread active at a time. We recommend you
+to upgrade to gdb 5.1 ASAP as thread debugging works much better with this
+version!
When running @code{mysqld} under gdb, you should disable the stack trace
with @code{--skip-stack-trace} to be able to catch segfaults within gdb.
@@ -52915,12 +55183,12 @@ setting the @code{DBI_TRACE} environment variable.
@node Using stack trace, Using log files, Using gdb on mysqld, Debugging server
-@appendixsubsec Using a stack trace
+@appendixsubsec Using a Stack Trace
On some operating systems, the error log will contain a stack trace if
@code{mysqld} dies unexpectedly. You can use this to find out where (and
maybe why) @code{mysqld} died. @xref{Error log}. To get a stack trace,
-you should NOT compile @code{mysqld} with the @code{-fomit-frame-pointer}
+you must not compile @code{mysqld} with the @code{-fomit-frame-pointer}
option to gcc. @xref{Compiling for debugging}.
If the error file contains something like the following:
@@ -52984,10 +55252,10 @@ repeat the problem! @xref{Bug reports}.
@node Using log files, Reproduceable test case, Using stack trace, Debugging server
-@appendixsubsec Using log files to find cause of errors in mysqld
+@appendixsubsec Using Log Files to Find Cause of Errors in mysqld
Note that before starting @code{mysqld} with @code{--log} you should
-check all your tables with @code{myisamchk}.
+check all your tables with @code{myisamchk}.
@xref{MySQL Database Administration}.
If @code{mysqld} dies or hangs, you should start @code{mysqld} with
@@ -53013,14 +55281,13 @@ If you find the text @code{mysqld restarted} in the error log file
that causes @code{mysqld} to fail. If this happens you should check all
your tables with @code{myisamchk} (@pxref{MySQL Database Administration}),
and test the queries in the MySQL log files to see if one doesn't
-work. If you find such a query, try first upgrading to the newest
+work. If you find such a query, try first upgrading to the newest
MySQL version. If this doesn't help and you can't find anything
in the @code{mysql} mail archive, you should report the bug to
@email{mysql@@lists.mysql.com}. Links to mail archives are available
-online at the @uref{http://www.mysql.com/documentation/, MySQL
-documentation page}.
+online at @uref{http://lists.mysql.com/}.
-If you have started @code{mysqld} with @code{--with-myisam-recover},
+If you have started @code{mysqld} with @code{myisam-recover},
MySQL will automatically check and try to repair @code{MyISAM}
tables if they are marked as 'not closed properly' or 'crashed'. If
this happens, MySQL will write an entry in the
@@ -53031,12 +55298,12 @@ died unexpectedly just before, then something is wrong and needs to
be investigated further. @xref{Command-line options}.
It's of course not a good sign if @code{mysqld} did died unexpectedly,
-but in this case one shouldn't investigate the @code{Checking table...}
+but in this case one shouldn't investigate the @code{Checking table...}
messages but instead try to find out why @code{mysqld} died.
@node Reproduceable test case, , Using log files, Debugging server
-@appendixsubsec Making a test case when you experience table corruption
+@appendixsubsec Making a Test Case When You Experience Table Corruption
If you get corrupted tables or if @code{mysqld} always fails after some
update commands, you can test if this bug is reproducible by doing the
@@ -53074,7 +55341,7 @@ the name @code{hostname-bin.#}.
If the tables are corrupted again or you can get @code{mysqld} to die with the
above command, you have found reproducible bug that should be easy to
fix! FTP the tables and the binary log to
-@uref{ftp://support.mysql.com/pub/mysql/secret} and send a mail to
+@uref{ftp://support.mysql.com/pub/mysql/secret/} and send a mail to
@email{bugs@@lists.mysql.com} or (if you are a support customer) to
@email{support@@mysql.com} about the problem and the MySQL team
will fix it as soon as possible.
@@ -53091,8 +55358,8 @@ update statements if you want to narrow down the problem.
@cindex clients, debugging
To be able to debug a MySQL client with the integrated debug package,
-you should configure MySQL with @code{--with-debug}.
-@xref{configure options}.
+you should configure MySQL with @code{--with-debug} or
+@code{--with-debug=full}. @xref{configure options}.
@tindex MYSQL_DEBUG environment variable
@tindex Environment variable, MYSQL_DEBUG
@@ -53125,7 +55392,7 @@ MySQL installation with new MySQL library.
@node The DBUG package, Locking methods, Debugging client, Porting
-@appendixsec The DBUG package.
+@appendixsec The DBUG Package
@cindex DBUG package
@@ -53156,9 +55423,10 @@ an optional "," and comma-separated list of modifiers:
flag[,modifier,modifier,...,modifier]
@end example
-The currently recognized flag characters are:
+The currently recognised flag characters are:
@multitable @columnfractions .1 .9
+@item @strong{Flag} @tab @strong{Description}
@item d @tab Enable output from DBUG_<N> macros for the current state. May be followed by a list of keywords which selects output only for the DBUG macros with that keyword. An empty list of keywords implies output for all macros.
@item D @tab Delay after each debugger output line. The argument is the number of tenths of seconds to delay, subject to machine capabilities. That is, @code{-#D,20} is delay two seconds.
@item f @tab Limit debugging and/or tracing, and profiling to the list of named functions. Note that a null list will disable all functions. The appropriate "d" or "t" flags must still be given, this flag only limits their actions if they are enabled.
@@ -53200,12 +55468,14 @@ In MySQL, common tags to print (with the @code{d} option) are:
@cindex methods, locking
Currently MySQL only supports table locking for
-@code{ISAM}/@code{MyISAM} and @code{HEAP} tables and page level locking
-for @code{BDB} tables. @xref{Internal locking}. With @code{MyISAM}
+@code{ISAM}/@code{MyISAM} and @code{HEAP} tables.
+@code{InnoDB} tables use row level locking,
+and @code{BDB} tables page level locking. @xref{Internal locking}.
+With @code{MyISAM}
tables one can freely mix @code{INSERT} and @code{SELECT} without locks
(@code{Versioning}).
-Starting in version 3.23.33, you can analyze the table lock contention
+Starting in version 3.23.33, you can analyse the table lock contention
on your system by checking @code{Table_locks_waited} and
@code{Table_locks_immediate} environment variables.
@@ -53213,7 +55483,7 @@ Some database users claim that MySQL cannot support near the
number of concurrent users because it lacks row-level locking. This
may be true for some specific applications, but is not generally
true. As always this depends totally on what the application does and what
-is the access/update pattern of the data.
+is the access/update pattern of the data.
Pros for row locking:
@@ -53221,7 +55491,7 @@ Pros for row locking:
@item
Fewer lock conflicts when accessing different rows in many threads.
@item
-Less changes for rollbacks.
+Fewer changes for rollbacks.
@item
Makes it possible to lock a single row a long time.
@end itemize
@@ -53275,8 +55545,8 @@ Copy on demand is in many case much better than page or row level
locking; The worst case does, however, use much more memory than
when using normal locks.
-Instead of using row level locks one can use application level locks.
-(Like get_lock/release_lock in MySQL). This works of course
+Instead of using row level locks one can use application level locks
+(like get_lock/release_lock in MySQL). This works of course
only in well-behaved applications.
In many cases one can do an educated guess which locking type is best
@@ -53288,7 +55558,7 @@ Here are some tips about locking in MySQL:
On web application most applications do lots of selects, very few
deletes, updates mainly on keys and inserts in some specific tables.
-The base MySQL setup is VERY tuned for this.
+The base MySQL setup is very well tuned for this.
Concurrent users is not a problem if one doesn't mix updates and selects
that needs to examine many rows in the same table.
@@ -53301,10 +55571,11 @@ a single lock is much faster than updates without locks). Splitting
thing to different tables will also helps.
If you get speed problems with the table locks in MySQL, you
-may be able to solve these to convert some of your tables to @code{BDB} tables.
-@xref{BDB}.
+may be able to solve these by converting some of your tables to @code{InnoDB}
+or @code{BDB} tables.
+@xref{InnoDB}. @xref{BDB}.
-The optimization section in the manual covers a lot of different aspects of
+The optimisation section in the manual covers a lot of different aspects of
how to tune ones application. @xref{Tips}.
@@ -53459,7 +55730,7 @@ really ``thread aware''.
@node Environment variables, Regexp, Porting, Top
-@appendix Environment Variables
+@appendix Environment Variables
@cindex environment variables, list of
@@ -53517,6 +55788,7 @@ variables to modify the behavior of MySQL. @xref{Option files}.
@tindex Environment variable, USER
@multitable @columnfractions .2 .8
+@item @strong{Variable} @tab @strong{Description}
@item @code{CCX} @tab Set this to your C++ compiler when running configure.
@item @code{CC} @tab Set this to your C compiler when running configure.
@item @code{CFLAGS} @tab Flags for your C compiler when running configure.
@@ -53542,8 +55814,8 @@ variables to modify the behavior of MySQL. @xref{Option files}.
-@node Regexp, Unireg, Environment variables, Top
-@appendix Description of MySQL regular expression syntax
+@node Regexp, GPL license, Environment variables, Top
+@appendix MySQL Regular Expression Syntax
@cindex regex
@cindex regular expression syntax, described
@@ -53695,6 +55967,7 @@ Within a bracket expression, the name of a character class enclosed in
to that class. Standard character class names are:
@multitable @columnfractions .33 .33 .33
+@item @strong{Name} @tab @strong{Name} @tab @strong{Name}
@item alnum @tab digit @tab punct
@item alpha @tab graph @tab space
@item blank @tab lower @tab upper
@@ -53729,77 +56002,7 @@ mysql> select "weeknights" REGEXP "^(wee|week)(knights|nights)$"; -> 1
-@node Unireg, GPL license, Regexp, Top
-@appendix What is Unireg?
-
-@cindex Unireg, described
-@cindex interface builder
-
-Unireg is our tty interface builder, but it uses a low-level connection
-to our ISAM (which is used by MySQL) and because of this it is
-very quick. It has existed since 1979 (on Unix in C since ~1986).
-
-Unireg has the following components:
-
-@itemize @bullet
-@item
-One table viewer with updates/browsing.
-@item
-Multi table viewer (with one scrolling region).
-@item
-Table creator. (With lots of column tags you can't create with MySQL)
-This is WYSIWYG (for a tty). You design a screen and Unireg prompts for
-the column specification.
-@item
-Report generator.
-@item
-A lot of utilities (quick import/export of tables to/from text files,
-analysis of table contents...).
-@item
-Powerful multi-table updates (which we use a lot) with a BASIC-like
-language with LOTS of functions.
-@item
-Dynamic languages (at present in Swedish and Finnish). If somebody wants
-an English version there are a few files that would have to be translated.
-@item
-The ability to run updates interactively or in a batch.
-@item
-Emacs-like key definitions with keyboard macros.
-@item
-All this in a binary of 800K.
-@item
-The @code{convform} utility. Converts @file{.frm} and text files between
-different character sets.
-@item
-The @code{myisampack} utility. Packs an ISAM table (makes it 50-80%
-smaller). The table can be read by MySQL like an ordinary
-table. Only one record has to be decompressed per access. Cannot handle
-@code{BLOB} or @code{TEXT} columns or updates (yet).
-@end itemize
-
-We update most of our production databases with the Unireg interface and
-serve web pages through MySQL (and in some extreme cases the Unireg
-report generator).
-
-Unireg takes about 3M of disk space and works on at least the following
-platforms: SunOS 4.x, Solaris, Linux, HP-UX, ICL Unix, DNIX, SCO and
-MS-DOS.
-
-Unireg is currently only available in Swedish and Finnish.
-
-The price tag for Unireg is 10,000 Swedish kr (about $1500 US), but this
-includes support. Unireg is distributed as a binary. (But all the ISAM
-sources can be found in MySQL). Usually we compile the binary for the
-customer at their site.
-
-All new development is concentrated to MySQL.
-
-@page
-@c This node name is special
-
-
-
-@node GPL license, LGPL license, Unireg, Top
+@node GPL license, LGPL license, Regexp, Top
@appendix GNU GENERAL PUBLIC LICENSE
@cindex GPL, General Public License
@@ -54200,11 +56403,13 @@ Public License instead of this License.
-@node LGPL license, Placeholder, GPL license, Top
+@node LGPL license, Function Index, GPL license, Top
@appendix GNU LESSER GENERAL PUBLIC LICENSE
-@cindex LGPL, Lesser General Public License
+@cindex LGPL, Library General Public License
@cindex LGPL, GNU Library General Public License
+@cindex LGPL, Lesser General Public License
+@cindex LGPL, GNU Lesser General Public License
@center Version 2.1, February 1999
@@ -54771,690 +56976,7 @@ That's all there is to it!
-@node Placeholder, Function Index, LGPL license, Top
-@appendix Pieces of the manual in transit
-
-@menu
-* Installing binary:: Installing a MySQL Binary Distribution
-* Perl support:: Perl Installation Comments
-* Group by functions:: Functions for Use with @code{GROUP BY} Clauses
-@end menu
-
-
-@node Installing binary, Perl support, Placeholder, Placeholder
-@appendixsec Installing a MySQL Binary Distribution
-
-@cindex installing, binary distribution
-@cindex binary distributions, installing
-
-@menu
-* Linux-RPM:: Linux RPM files
-* Building clients:: Building client programs
-@end menu
-
-You need the following tools to install a MySQL binary distribution:
-
-@itemize @bullet
-@item
-GNU @code{gunzip} to uncompress the distribution.
-
-@item
-A reasonable @code{tar} to unpack the distribution. GNU @code{tar} is
-known to work. Sun @code{tar} is known to have problems.
-@end itemize
-
-@cindex RPM, defined
-@cindex RedHat Package Manager
-An alternative installation method under Linux is to use RPM (RedHat Package
-Manager) distributions. @xref{Linux-RPM}.
-
-@c texi2html fails to split chapters if I use strong for all of this.
-If you run into problems, @strong{PLEASE ALWAYS USE} @code{mysqlbug} when
-posting questions to @email{mysql@@lists.mysql.com}. Even if the problem
-isn't a bug, @code{mysqlbug} gathers system information that will help others
-solve your problem. By not using @code{mysqlbug}, you lessen the likelihood
-of getting a solution to your problem! You will find @code{mysqlbug} in the
-@file{bin} directory after you unpack the distribution. @xref{Bug reports}.
-
-@cindex commands, for binary distribution
-The basic commands you must execute to install and use a MySQL
-binary distribution are:
-
-@example
-shell> groupadd mysql
-shell> useradd -g mysql mysql
-shell> cd /usr/local
-shell> gunzip < /path/to/mysql-VERSION-OS.tar.gz | tar xvf -
-shell> ln -s mysql-VERSION-OS mysql
-shell> cd mysql
-shell> scripts/mysql_install_db
-shell> chown -R root /usr/local/mysql
-shell> chown -R mysql /usr/local/mysql/data
-shell> chgrp -R mysql /usr/local/mysql
-shell> chown -R root /usr/local/mysql/bin
-shell> bin/safe_mysqld --user=mysql &
-@end example
-
-@cindex adding, new users
-@cindex new users, adding
-@cindex users, adding
-
-You can add new users using the @code{bin/mysql_setpermission} script if
-you install the @code{DBI} and @code{Msql-Mysql-modules} Perl modules.
-
-A more detailed description follows.
-
-To install a binary distribution, follow the steps below, then proceed
-to @ref{Post-installation}, for post-installation setup and testing:
-
-@enumerate
-@item
-Pick the directory under which you want to unpack the distribution, and move
-into it. In the example below, we unpack the distribution under
-@file{/usr/local} and create a directory @file{/usr/local/mysql} into which
-MySQL is installed. (The following instructions therefore assume
-you have permission to create files in @file{/usr/local}. If that directory
-is protected, you will need to perform the installation as @code{root}.)
-
-@item
-Obtain a distribution file from one of the sites listed in
-@ref{Getting MySQL, , Getting MySQL}.
-
-MySQL binary distributions are provided as compressed @code{tar}
-archives and have names like @file{mysql-VERSION-OS.tar.gz}, where
-@code{VERSION} is a number (for example, @code{3.21.15}), and @code{OS}
-indicates the type of operating system for which the distribution is intended
-(for example, @code{pc-linux-gnu-i586}).
-
-@item
-If you see a binary distribution marked with the @code{-max} prefix, this
-means that the binary has support for transaction-safe tables and other
-features. @xref{mysqld-max, , @code{mysqld-max}}. Note that all binaries
-are built from the same MySQL source distribution.
-
-@item
-Add a user and group for @code{mysqld} to run as:
-
-@example
-shell> groupadd mysql
-shell> useradd -g mysql mysql
-@end example
-
-These commands add the @code{mysql} group and the @code{mysql} user. The
-syntax for @code{useradd} and @code{groupadd} may differ slightly on different
-versions of Unix. They may also be called @code{adduser} and @code{addgroup}.
-You may wish to call the user and group something else instead of @code{mysql}.
-
-@item
-Change into the intended installation directory:
-
-@example
-shell> cd /usr/local
-@end example
-
-@item
-Unpack the distribution and create the installation directory:
-
-@example
-shell> gunzip < /path/to/mysql-VERSION-OS.tar.gz | tar xvf -
-shell> ln -s mysql-VERSION-OS mysql
-@end example
-
-The first command creates a directory named @file{mysql-VERSION-OS}. The
-second command makes a symbolic link to that directory. This lets you refer
-more easily to the installation directory as @file{/usr/local/mysql}.
-
-@item
-Change into the installation directory:
-
-@example
-shell> cd mysql
-@end example
-
-You will find several files and subdirectories in the @code{mysql} directory.
-The most important for installation purposes are the @file{bin} and
-@file{scripts} subdirectories.
-
-@table @file
-@item bin
-@tindex PATH environment variable
-@tindex environment variable, PATH
-This directory contains client programs and the server
-You should add the full pathname of this directory to your
-@code{PATH} environment variable so that your shell finds the MySQL
-programs properly. @xref{Environment variables}.
-
-@item scripts
-This directory contains the @code{mysql_install_db} script used to initialize
-the @code{mysql} database containing the grant tables that store the server
-access permissions.
-@end table
-
-@item
-If you would like to use @code{mysqlaccess} and have the MySQL
-distribution in some non-standard place, you must change the location where
-@code{mysqlaccess} expects to find the @code{mysql} client. Edit the
-@file{bin/mysqlaccess} script at approximately line 18. Search for a line
-that looks like this:
-
-@example
-$MYSQL = '/usr/local/bin/mysql'; # path to mysql executable
-@end example
-
-Change the path to reflect the location where @code{mysql} actually is
-stored on your system. If you do not do this, you will get a @code{Broken
-pipe} error when you run @code{mysqlaccess}.
-
-@item
-Create the MySQL grant tables (necessary only if you haven't
-installed MySQL before):
-@example
-shell> scripts/mysql_install_db
-@end example
-
-Note that MySQL versions older than Version 3.22.10 started the
-MySQL server when you run @code{mysql_install_db}. This is no
-longer true!
-
-@item
-Change ownership of binaries to @code{root} and ownership of the data
-directory to the user that you will run @code{mysqld} as:
-
-@example
-shell> chown -R root /usr/local/mysql
-shell> chown -R mysql /usr/local/mysql/data
-shell> chgrp -R mysql /usr/local/mysql
-@end example
-
-The first command changes the @code{owner} attribute of the files to the
-@code{root} user, the second one changes the @code{owner} attribute of the
-data directory to the @code{mysql} user, and the third one changes the
-@code{group} attribute to the @code{mysql} group.
-
-@item
-If you want to install support for the Perl @code{DBI}/@code{DBD} interface,
-see @ref{Perl support}.
-
-@item
-If you would like MySQL to start automatically when you boot your
-machine, you can copy @code{support-files/mysql.server} to the location where
-your system has its startup files. More information can be found in the
-@code{support-files/mysql.server} script itself and in
-@ref{Automatic start}.
-
-@end enumerate
-
-After everything has been unpacked and installed, you should initialize
-and test your distribution.
-
-You can start the MySQL server with the following command:
-
-@example
-shell> bin/safe_mysqld --user=mysql &
-@end example
-
-@xref{safe_mysqld, , @code{safe_mysqld}}.
-
-@xref{Post-installation}.
-
-
-
-
-
-
-
-@node Perl support, Group by functions, Installing binary, Placeholder
-@appendixsec Perl Installation Comments
-
-@cindex Perl, installing
-@cindex installing, Perl
-
-@menu
-* Perl installation:: Installing Perl on Unix
-* ActiveState Perl:: Installing ActiveState Perl on Windows
-* Windows Perl:: Installing the MySQL Perl distribution on Windows
-* Perl support problems:: Problems using the Perl @code{DBI}/@code{DBD} interface
-@end menu
-
-
-@node Perl installation, ActiveState Perl, Perl support, Perl support
-@appendixsubsec Installing Perl on Unix
-
-Perl support for MySQL is provided by means of the
-@code{DBI}/@code{DBD} client interface. @xref{Perl}. The Perl
-@code{DBD}/@code{DBI} client code requires Perl Version 5.004 or later. The
-interface @strong{will not work} if you have an older version of Perl.
-
-MySQL Perl support also requires that you've installed
-MySQL client programming support. If you installed MySQL
-from RPM files, client programs are in the client RPM, but client programming
-support is in the developer RPM. Make sure you've installed the latter RPM.
-
-As of Version 3.22.8, Perl support is distributed separately from the main
-MySQL distribution. If you want to install Perl support, the files
-you will need can be obtained from
-@uref{http://www.mysql.com/Downloads/Contrib/}.
-
-The Perl distributions are provided as compressed @code{tar} archives and
-have names like @file{MODULE-VERSION.tar.gz}, where @code{MODULE} is the
-module name and @code{VERSION} is the version number. You should get the
-@code{Data-Dumper}, @code{DBI}, and @code{Msql-Mysql-modules} distributions
-and install them in that order. The installation procedure is shown below.
-The example shown is for the @code{Data-Dumper} module, but the procedure is
-the same for all three distributions:
-
-@enumerate
-@item
-Unpack the distribution into the current directory:
-@example
-shell> gunzip < Data-Dumper-VERSION.tar.gz | tar xvf -
-@end example
-This command creates a directory named @file{Data-Dumper-VERSION}.
-
-@item
-Change into the top-level directory of the unpacked distribution:
-@example
-shell> cd Data-Dumper-VERSION
-@end example
-
-@item
-Build the distribution and compile everything:
-@example
-shell> perl Makefile.PL
-shell> make
-shell> make test
-shell> make install
-@end example
-@end enumerate
-
-The @code{make test} command is important because it verifies that the
-module is working. Note that when you run that command during the
-@code{Msql-Mysql-modules} installation to exercise the interface code, the
-MySQL server must be running or the test will fail.
-
-It is a good idea to rebuild and reinstall the @code{Msql-Mysql-modules}
-distribution whenever you install a new release of MySQL,
-particularly if you notice symptoms such as all your @code{DBI} scripts
-dumping core after you upgrade MySQL.
-
-If you don't have the right to install Perl modules in the system directory
-or if you to install local Perl modules, the following reference may help
-you:
-
-@example
-@uref{http://www.iserver.com/support/contrib/perl5/modules.html}
-@end example
-
-Look under the heading
-@code{Installing New Modules that Require Locally Installed Modules}.
-
-
-@node ActiveState Perl, Windows Perl, Perl installation, Perl support
-@appendixsubsec Installing ActiveState Perl on Windows
-
-@cindex installing, Perl on Windows
-@cindex Perl, installing on Windows
-@cindex ActiveState Perl
-
-To install the MySQL @code{DBD} module with ActiveState Perl on
-Windows, you should do the following:
-
-@itemize @bullet
-@item
-Get ActiveState Perl from
-@uref{http://www.activestate.com/Products/ActivePerl/index.html}
-and install it.
-
-@item
-Open a DOS shell.
-
-@item
-If required, set the HTTP_proxy variable. For example, you might try:
-
-@example
-set HTTP_proxy=my.proxy.com:3128
-@end example
-
-@item
-Start the PPM program:
-
-@example
-C:\> c:\perl\bin\ppm.pl
-@end example
-
-@item
-If you have not already done so, install @code{DBI}:
-
-@example
-ppm> install DBI
-@end example
-
-@item
-If this succeeds, run the following command:
-
-@example
-install ftp://ftp.de.uu.net/pub/CPAN/authors/id/JWIED/DBD-mysql-1.2212.x86.ppd
-@end example
-@end itemize
-
-The above should work at least with ActiveState Perl Version 5.6.
-
-If you can't get the above to work, you should instead install the
-@strong{MyODBC} driver and connect to MySQL server through
-ODBC:
-
-@example
-use DBI;
-$dbh= DBI->connect("DBI:ODBC:$dsn","$user","$password") ||
- die "Got error $DBI::errstr when connecting to $dsn\n";
-@end example
-
-
-@node Windows Perl, Perl support problems, ActiveState Perl, Perl support
-@appendixsubsec Installing the MySQL Perl Distribution on Windows
-
-The MySQL Perl distribution contains @code{DBI},
-@code{DBD:MySQL} and @code{DBD:ODBC}.
-
-@itemize @bullet
-@item
-Get the Perl distribution for Windows from
-@uref{http://www.mysql.com/download.html}.
-
-@item
-Unzip the distribution in @code{C:} so that you get a @file{C:\PERL} directory.
-
-@item
-Add the directory @file{C:\PERL\BIN} to your path.
-
-@item
-Add the directory @file{C:\PERL\BIN\MSWIN32-x86-thread} or
-@file{C:\PERL\BIN\MSWIN32-x86} to your path.
-
-@item
-Test that @code{perl} works by executing @code{perl -v} in a DOS shell.
-@end itemize
-
-
-@node Perl support problems, , Windows Perl, Perl support
-@appendixsubsec Problems Using the Perl @code{DBI}/@code{DBD} Interface
-
-@cindex problems, installing Perl
-@cindex Perl DBI/DBD, installation problems
-
-If Perl reports that it can't find the @file{../mysql/mysql.so} module,
-then the problem is probably that Perl can't locate the shared library
-@file{libmysqlclient.so}.
-
-You can fix this by any of the following methods:
-
-@itemize @bullet
-@item
-Compile the @code{Msql-Mysql-modules} distribution with @code{perl
-Makefile.PL -static -config} rather than @code{perl Makefile.PL}.
-
-@item
-Copy @code{libmysqlclient.so} to the directory where your other shared
-libraries are located (probably @file{/usr/lib} or @file{/lib}).
-
-@item
-On Linux you can add the pathname of the directory where
-@file{libmysqlclient.so} is located to the @file{/etc/ld.so.conf} file.
-
-@tindex LD_RUN_PATH environment variable
-@tindex Environment variable, LD_RUN_PATH
-@item
-Add the pathname of the directory where @file{libmysqlclient.so} is located
-to the @code{LD_RUN_PATH} environment variable.
-@end itemize
-
-If you get the following errors from @code{DBD-mysql},
-you are probably using @code{gcc} (or using an old binary compiled with
-@code{gcc}):
-
-@example
-/usr/bin/perl: can't resolve symbol '__moddi3'
-/usr/bin/perl: can't resolve symbol '__divdi3'
-@end example
-
-Add @code{-L/usr/lib/gcc-lib/... -lgcc} to the link command when the
-@file{mysql.so} library gets built (check the output from @code{make} for
-@file{mysql.so} when you compile the Perl client). The @code{-L} option
-should specify the pathname of the directory where @file{libgcc.a} is located
-on your system.
-
-Another cause of this problem may be that Perl and MySQL aren't both
-compiled with @code{gcc}. In this case, you can solve the mismatch by
-compiling both with @code{gcc}.
-
-If you get the following error from @code{Msql-Mysql-modules}
-when you run the tests:
-
-@example
-t/00base............install_driver(mysql) failed: Can't load '../blib/arch/auto/DBD/mysql/mysql.so' for module DBD::mysql: ../blib/arch/auto/DBD/mysql/mysql.so: undefined symbol: uncompress at /usr/lib/perl5/5.00503/i586-linux/DynaLoader.pm line 169.
-@end example
-
-it means that you need to include the compression library, -lz, to the
-link line. This can be doing the following change in the file
-@file{lib/DBD/mysql/Install.pm}:
-
-@example
-$sysliblist .= " -lm";
-
-to
-
-$sysliblist .= " -lm -lz";
-@end example
-
-After this, you MUST run 'make realclean' and then proceed with the
-installation from the beginning.
-
-If you want to use the Perl module on a system that doesn't support dynamic
-linking (like SCO) you can generate a static version of Perl that includes
-@code{DBI} and @code{DBD-mysql}. The way this works is that you generate a
-version of Perl with the @code{DBI} code linked in and install it on top of
-your current Perl. Then you use that to build a version of Perl that
-additionally has the @code{DBD} code linked in, and install that.
-
-On SCO, you must have the following environment variables set:
-
-@example
-shell> LD_LIBRARY_PATH=/lib:/usr/lib:/usr/local/lib:/usr/progressive/lib
-or
-shell> LD_LIBRARY_PATH=/usr/lib:/lib:/usr/local/lib:/usr/ccs/lib:/usr/progressive/lib:/usr/skunk/lib
-shell> LIBPATH=/usr/lib:/lib:/usr/local/lib:/usr/ccs/lib:/usr/progressive/lib:/usr/skunk/lib
-shell> MANPATH=scohelp:/usr/man:/usr/local1/man:/usr/local/man:/usr/skunk/man:
-@end example
-
-First, create a Perl that includes a statically linked @code{DBI} by running
-these commands in the directory where your @code{DBI} distribution is
-located:
-
-@example
-shell> perl Makefile.PL -static -config
-shell> make
-shell> make install
-shell> make perl
-@end example
-
-Then you must install the new Perl. The output of @code{make perl} will
-indicate the exact @code{make} command you will need to execute to perform
-the installation. On SCO, this is @code{make -f Makefile.aperl inst_perl
-MAP_TARGET=perl}.
-
-Next, use the just-created Perl to create another Perl that also includes a
-statically-linked @code{DBD::mysql} by running these commands in the
-directory where your @code{Msql-Mysql-modules} distribution is located:
-
-@example
-shell> perl Makefile.PL -static -config
-shell> make
-shell> make install
-shell> make perl
-@end example
-
-Finally, you should install this new Perl. Again, the output of @code{make
-perl} indicates the command to use.
-
-
-@node Group by functions, , Perl support, Placeholder
-@appendixsec Functions for Use with @code{GROUP BY} Clauses
-
-@findex GROUP BY functions
-@findex functions, GROUP BY
-
-If you use a group function in a statement containing no @code{GROUP BY}
-clause, it is equivalent to grouping on all rows.
-
-@table @code
-@findex COUNT()
-@item COUNT(expr)
-Returns a count of the number of non-@code{NULL} values in the rows
-retrieved by a @code{SELECT} statement:
-
-@example
-mysql> select student.student_name,COUNT(*)
- from student,course
- where student.student_id=course.student_id
- GROUP BY student_name;
-
-@end example
-
-@code{COUNT(*)} is somewhat different in that it returns a count of
-the number of rows retrieved, whether or not they contain @code{NULL}
-values.
-
-@code{COUNT(*)} is optimized to
-return very quickly if the @code{SELECT} retrieves from one table, no
-other columns are retrieved, and there is no @code{WHERE} clause.
-For example:
-
-@example
-mysql> select COUNT(*) from student;
-@end example
-
-@findex COUNT(DISTINCT)
-@findex DISTINCT
-@item COUNT(DISTINCT expr,[expr...])
-Returns a count of the number of different non-@code{NULL} values:
-
-@example
-mysql> select COUNT(DISTINCT results) from student;
-@end example
-
-In MySQL you can get the number of distinct expression
-combinations that don't contain NULL by giving a list of expressions.
-In ANSI SQL you would have to do a concatenation of all expressions
-inside @code{CODE(DISTINCT ..)}.
-
-@findex AVG()
-@item AVG(expr)
-Returns the average value of @code{expr}:
-
-@example
-mysql> select student_name, AVG(test_score)
- from student
- GROUP BY student_name;
-@end example
-
-@findex MIN()
-@findex MAX()
-@item MIN(expr)
-@itemx MAX(expr)
-Returns the minimum or maximum value of @code{expr}. @code{MIN()} and
-@code{MAX()} may take a string argument; in such cases they return the
-minimum or maximum string value. @xref{MySQL indexes}.
-
-@example
-mysql> select student_name, MIN(test_score), MAX(test_score)
- from student
- GROUP BY student_name;
-@end example
-
-@findex SUM()
-@item SUM(expr)
-Returns the sum of @code{expr}. Note that if the return set has no rows,
-it returns NULL!
-
-@findex STD()
-@findex STDDEV()
-@cindex Oracle compatibility
-@cindex compatibility, with Oracle
-@item STD(expr)
-@itemx STDDEV(expr)
-Returns the standard deviation of @code{expr}. This is an extension to
-ANSI SQL. The @code{STDDEV()} form of this function is provided for Oracle
-compatibility.
-
-@findex BIT_OR()
-@item BIT_OR(expr)
-Returns the bitwise @code{OR} of all bits in @code{expr}. The calculation is
-performed with 64-bit (@code{BIGINT}) precision.
-
-@findex BIT_AND()
-@item BIT_AND(expr)
-Returns the bitwise @code{AND} of all bits in @code{expr}. The calculation is
-performed with 64-bit (@code{BIGINT}) precision.
-@end table
-
-@cindex @code{GROUP BY}, extensions to ANSI SQL
-MySQL has extended the use of @code{GROUP BY}. You can use columns or
-calculations in the @code{SELECT} expressions that don't appear in
-the @code{GROUP BY} part. This stands for @emph{any possible value for this
-group}. You can use this to get better performance by avoiding sorting and
-grouping on unnecessary items. For example, you don't need to group on
-@code{customer.name} in the following query:
-
-@example
-mysql> select order.custid,customer.name,max(payments)
- from order,customer
- where order.custid = customer.custid
- GROUP BY order.custid;
-@end example
-
-In ANSI SQL, you would have to add @code{customer.name} to the @code{GROUP
-BY} clause. In MySQL, the name is redundant if you don't run in
-ANSI mode.
-
-@strong{Don't use this feature} if the columns you omit from the
-@code{GROUP BY} part aren't unique in the group! You will get
-unpredictable results.
-
-In some cases, you can use @code{MIN()} and @code{MAX()} to obtain a specific
-column value even if it isn't unique. The following gives the value of
-@code{column} from the row containing the smallest value in the @code{sort}
-column:
-
-@example
-substr(MIN(concat(rpad(sort,6,' '),column)),7)
-@end example
-
-@xref{example-Maximum-column-group-row}.
-
-@cindex @code{ORDER BY}, aliases in
-@cindex aliases, in @code{ORDER BY} clauses
-@cindex @code{GROUP BY}, aliases in
-@cindex aliases, in @code{GROUP BY} clauses
-@cindex expression aliases
-@cindex aliases, for expressions
-Note that if you are using MySQL Version 3.22 (or earlier) or if
-you are trying to follow ANSI SQL, you can't use expressions in @code{GROUP
-BY} or @code{ORDER BY} clauses. You can work around this limitation by
-using an alias for the expression:
-
-@example
-mysql> SELECT id,FLOOR(value/100) AS val FROM tbl_name
- GROUP BY id,val ORDER BY val;
-@end example
-
-In MySQL Version 3.23 you can do:
-
-@example
-mysql> SELECT id,FLOOR(value/100) FROM tbl_name ORDER BY RAND();
-@end example
-
-
-@node Function Index, Concept Index, Placeholder, Top
+@node Function Index, Concept Index, LGPL license, Top
@unnumbered SQL command, type and function index
@printindex fn
diff --git a/Docs/mirrors.texi b/Docs/mirrors.texi
new file mode 100644
index 00000000000..aed9668df29
--- /dev/null
+++ b/Docs/mirrors.texi
@@ -0,0 +1,410 @@
+@strong{Europe:}
+
+@itemize @bullet
+
+@item
+@image{Flags/austria} Austria [Univ. of Technology/Vienna] @@
+WWW (@uref{http://gd.tuwien.ac.at/db/mysql/})
+FTP (@uref{ftp://gd.tuwien.ac.at/db/mysql/})
+
+@item
+@image{Flags/belgium} Belgium [BELNET] @@
+WWW (@uref{http://mysql.belnet.be/})
+FTP (@uref{ftp://ftp.belnet.be/mirror/ftp.mysql.com/pub/mysql/})
+
+@item
+@image{Flags/bulgaria} Bulgaria [online.bg/Sofia] @@
+WWW (@uref{http://mysql.online.bg/})
+FTP (@uref{ftp://mysql.online.bg/})
+
+@item
+@image{Flags/czech-republic} Czech Republic [Masaryk University in Brno] @@
+WWW (@uref{http://mysql.linux.cz/})
+FTP (@uref{ftp://ftp.fi.muni.cz/pub/mysql/})
+
+@item
+@image{Flags/czech-republic} Czech Republic [www.gin.cz] @@
+WWW (@uref{http://mysql.gin.cz/})
+FTP (@uref{ftp://ftp.gin.cz/pub/MIRRORS/www.mysql.com/})
+
+@item
+@image{Flags/czech-republic} Czech Republic [www.sopik.cz] @@
+WWW (@uref{http://www.mysql.cz/})
+
+@item
+@image{Flags/denmark} Denmark [Borsen] @@
+WWW (@uref{http://mysql.borsen.dk/})
+
+@item
+@image{Flags/denmark} Denmark [SunSITE] @@
+WWW (@uref{http://mirrors.sunsite.dk/mysql/})
+FTP (@uref{ftp://sunsite.dk/mirrors/mysql/})
+
+@item
+@image{Flags/estonia} Estonia [OK Interactive] @@
+WWW (@uref{http://mysql.mirror.ok.ee/})
+
+@item
+@image{Flags/finland} Finland [KPNQwest] @@
+WWW (@uref{http://mysql.kpnqwest.fi/})
+
+@item
+@image{Flags/finland} Finland [tonnikala.net] @@
+WWW (@uref{http://mysql.tonnikala.org/})
+
+@item
+@image{Flags/france} France [free.fr] @@
+WWW (@uref{http://mysql-mirror.free.fr/})
+FTP (@uref{ftp://ftp.free.fr/pub/MySQL/})
+
+@item
+@image{Flags/france} France [Omegatomic] @@
+WWW (@uref{http://mysql.omegatomic.com/})
+
+@item
+@image{Flags/germany} Germany [GWDG] @@
+WWW (@uref{http://ftp.gwdg.de/pub/misc/mysql/})
+FTP (@uref{ftp://ftp.gwdg.de/pub/misc/mysql/})
+
+@item
+@image{Flags/germany} Germany [SunSITE Central Europe] @@
+WWW (@uref{http://sunsite.informatik.rwth-aachen.de/mysql/})
+FTP (@uref{ftp://sunsite.informatik.rwth-aachen.de/pub/mirror/www.mysql.com/})
+
+@item
+@image{Flags/germany} Germany [Wolfenbuettel] @@
+WWW (@uref{http://www.fh-wolfenbuettel.de/ftp/pub/database/mysql/})
+FTP (@uref{ftp://ftp.fh-wolfenbuettel.de/pub/database/mysql/})
+
+@item
+@image{Flags/greece} Greece [NTUA, Athens] @@
+WWW (@uref{http://www.ntua.gr/mysql/})
+FTP (@uref{ftp://ftp.ntua.gr/pub/databases/mysql/})
+
+@item
+@image{Flags/hungary} Hungary [stop.hu] @@
+WWW (@uref{http://mysql.mirror.stop.hu/})
+
+@item
+@image{Flags/hungary} Hungary [TiszaneT] @@
+WWW (@uref{http://mysql.tiszanet.hu/})
+FTP (@uref{ftp://mysql.tiszanet.hu/pub/mirrors/mysql/})
+
+@item
+@image{Flags/hungary} Hungary [Xenia] @@
+WWW (@uref{http://mysql.sote.hu/})
+FTP (@uref{ftp://xenia.sote.hu/pub/mirrors/www.mysql.com/})
+
+@item
+@image{Flags/iceland} Iceland [GM] @@
+WWW (@uref{http://mysql.gm.is/})
+FTP (@uref{ftp://ftp.gm.is/pub/mysql/})
+
+@item
+@image{Flags/ireland} Ireland [Esat Net] @@
+WWW (@uref{http://ftp.esat.net/mirrors/download.sourceforge.net/pub/mirrors/mysql/})
+FTP (@uref{ftp://ftp.esat.net/mirrors/download.sourceforge.net/pub/mirrors/mysql/})
+
+@item
+@image{Flags/italy} Italy [feelinglinux.com] @@
+WWW (@uref{http://mysql.feelinglinux.com/})
+
+@item
+@image{Flags/italy} Italy [Teta Srl] @@
+WWW (@uref{http://www.teta.it/mysql/})
+
+@item
+@image{Flags/italy} Italy [tzone.it] @@
+WWW (@uref{http://mysql.tzone.it/})
+
+@item
+@image{Flags/latvia} Latvia [linux.lv] @@
+FTP (@uref{ftp://ftp.linux.lv/pub/software/mysql/})
+
+@item
+@image{Flags/netherlands} Netherlands [Compukos] @@
+WWW (@uref{http://mysql.compukos.nl/})
+
+@item
+@image{Flags/netherlands} Netherlands [OMS-Net] @@
+WWW (@uref{http://mysql.oms-net.nl/})
+
+@item
+@image{Flags/netherlands} Netherlands [ProServe] @@
+WWW (@uref{http://mysql.proserve.nl/})
+
+@item
+@image{Flags/netherlands} Netherlands [WideXS BV] @@
+WWW (@uref{http://mysql.mirror.widexs.nl/})
+FTP (@uref{ftp://mirror.widexs.nl/pub/mysql/})
+
+@item
+@image{Flags/norway} Norway [Brainpeddlers AS] @@
+WWW (@uref{http://mysql.brainpeddlers.com/})
+
+@item
+@image{Flags/poland} Poland [ncservice.com/Gdansk] @@
+WWW (@uref{http://mysql.service.net.pl/})
+
+@item
+@image{Flags/poland} Poland [SunSITE] @@
+WWW (@uref{http://sunsite.icm.edu.pl/mysql/})
+FTP (@uref{ftp://sunsite.icm.edu.pl/pub/unix/mysql/})
+
+@item
+@image{Flags/portugal} Portugal [Instituto Supertior Técnico] @@
+WWW (@uref{http://darkstar.ist.utl.pt/mysql/})
+FTP (@uref{ftp://darkstar.ist.utl.pt/pub/mysql/})
+
+@item
+@image{Flags/portugal} Portugal [Netc] @@
+WWW (@uref{http://ftp.netc.pt/pub/mysql/})
+FTP (@uref{ftp://ftp.netc.pt/pub/mysql/})
+
+@item
+@image{Flags/romania} Romania [roedu.net/Bucharest] @@
+FTP (@uref{ftp://ftp.roedu.net/pub/mirrors/ftp.mysql.com/})
+
+@item
+@image{Flags/russia} Russia [DirectNet] @@
+WWW (@uref{http://mysql.directnet.ru/})
+FTP (@uref{ftp://ftp.dn.ru/pub/MySQL/})
+
+@item
+@image{Flags/russia} Russia [Scientific Center/Chernogolovka] @@
+FTP (@uref{ftp://ftp.chg.ru/pub/databases/mysql/})
+
+@item
+@image{Flags/slovenia} Slovenia [ARNES] @@
+WWW (@uref{http://ftp.arnes.si/mysql/})
+FTP (@uref{ftp://ftp.arnes.si/packages/mysql/})
+
+@item
+@image{Flags/spain} Spain [GMC Control Systems] @@
+WWW (@uref{http://mysql.neptuno2000.com/})
+FTP (@uref{ftp://ftp.neptuno2000.com/pub/mysql/})
+
+@item
+@image{Flags/sweden} Sweden [Sunet] @@
+WWW (@uref{http://ftp.sunet.se/pub/unix/databases/relational/mysql/})
+FTP (@uref{ftp://ftp.sunet.se/pub/unix/databases/relational/mysql/})
+
+@item
+@image{Flags/switzerland} Switzerland [SunSITE] @@
+WWW (@uref{http://sunsite.cnlab-switch.ch/ftp/mirror/mysql/})
+FTP (@uref{ftp://sunsite.cnlab-switch.ch/mirror/mysql/})
+
+@item
+@image{Flags/turkey} Turkey [proGEN] @@
+WWW (@uref{http://mysql.progen.com.tr/})
+
+@item
+@image{Flags/great-britain} UK [PLiG/UK] @@
+WWW (@uref{http://ftp.plig.org/pub/mysql/})
+FTP (@uref{ftp://ftp.plig.org/pub/mysql/})
+
+@item
+@image{Flags/ukraine} Ukraine [ISP Alkar Teleport/Dnepropetrovsk] @@
+WWW (@uref{http://mysql.dp.ua/})
+FTP (@uref{ftp://ftp.tlk-l.net/pub/mirrors/mysql.com/})
+
+@item
+@image{Flags/ukraine} Ukraine [PACO] @@
+WWW (@uref{http://mysql.paco.net.ua/})
+FTP (@uref{ftp://mysql.paco.net.ua/})
+
+@item
+@image{Flags/yugoslavia} Yugoslavia [Open Source Network of Yugoslavia] @@
+WWW (@uref{http://mysql.boa.org.yu/})
+FTP (@uref{ftp://ftp.linux.org.yu/pub/MySQL/})
+
+@end itemize
+
+@strong{North America:}
+
+@itemize @bullet
+
+@item
+@image{Flags/canada} Canada [Tryc] @@
+WWW (@uref{http://web.tryc.on.ca/mysql/})
+
+@item
+@image{Flags/mexico} Mexico [UAM] @@
+WWW (@uref{http://mysql.azc.uam.mx/})
+FTP (@uref{ftp://mysql.azc.uam.mx/mirrors/mysql/})
+
+@item
+@image{Flags/mexico} Mexico [UNAM] @@
+WWW (@uref{http://mysql.unam.mx/})
+FTP (@uref{ftp://mysql.unam.mx/pub/mysql/})
+
+@item
+@image{Flags/usa} USA [adgrafix.com / Boston, MA] @@
+WWW (@uref{http://mysql.adgrafix.com/})
+
+@item
+@image{Flags/usa} USA [Ahaza Systems / Seattle, WA] @@
+WWW (@uref{http://mysql.mirrortree.com/})
+FTP (@uref{ftp://mysql.mirrortree.com/pub/mysql/})
+
+@item
+@image{Flags/usa} USA [Hurricane Electric / San Jose, CA] @@
+WWW (@uref{http://mysql.he.net/})
+
+@item
+@image{Flags/usa} USA [netNumina / Cambridge, MA] @@
+WWW (@uref{http://mysql.mirrors.netnumina.com/})
+
+@item
+@image{Flags/usa} USA [NIXC / Vienna, VA] @@
+WWW (@uref{http://mysql.nixc.net/})
+FTP (@uref{ftp://mysql.nixc.net/pub/mysql/})
+
+@item
+@image{Flags/usa} USA [Oregon State University / Corvallis, OR] @@
+WWW (@uref{http://mysql.orst.edu/})
+FTP (@uref{ftp://ftp.orst.edu/pub/mysql/})
+
+@item
+@image{Flags/usa} USA [University of Wisconsin / Wisconsin] @@
+WWW (@uref{http://mirror.sit.wisc.edu/mysql/})
+FTP (@uref{ftp://mirror.sit.wisc.edu/mirrors/mysql/})
+
+@item
+@image{Flags/usa} USA [UUNet] @@
+WWW (@uref{http://mysql.secsup.org/})
+FTP (@uref{ftp://mysql.secsup.org/pub/software/mysql/})
+
+@item
+@image{Flags/usa} USA [ValueClick / Los Angeles, CA] @@
+WWW (@uref{http://mysql.valueclick.com/})
+FTP (@uref{ftp://mysql.valueclick.com/pub/mysql/})
+
+@end itemize
+
+@strong{South America:}
+
+@itemize @bullet
+
+@item
+@image{Flags/argentina} Argentina [bannerlandia.com] @@
+WWW (@uref{http://mysql.bannerlandia.com.ar/})
+FTP (@uref{ftp://mysql.bannerlandia.com.ar/mirrors/mysql/})
+
+@item
+@image{Flags/chile} Chile [PSINet] @@
+WWW (@uref{http://mysql.psinet.cl/})
+FTP (@uref{ftp://ftp.psinet.cl/pub/database/mysql/})
+
+@item
+@image{Flags/chile} Chile [Tecnoera] @@
+WWW (@uref{http://mysql.tecnoera.com/})
+
+@item
+@image{Flags/chile} Chile [Vision] @@
+WWW (@uref{http://mysql.vision.cl/})
+
+@item
+@image{Flags/costa-rica} Costa Rica [Ogmios Communications] @@
+WWW (@uref{http://mysql.ogmios.co.cr/})
+FTP (@uref{ftp://mysql.ogmios.co.cr/pub/mysql/})
+
+@end itemize
+
+@strong{Asia:}
+
+@itemize @bullet
+
+@item
+@image{Flags/china} China [Gremlins/Hong Kong] @@
+WWW (@uref{http://mysql.gremlins.com.hk/})
+FTP (@uref{ftp://ftp.mirrors.gremlins.com.hk/mysql/})
+
+@item
+@image{Flags/china} China [HKLPG/Hong Kong] @@
+WWW (@uref{http://mysql.hklpg.org/})
+
+@item
+@image{Flags/china} China [linuxforum.net] @@
+FTP (@uref{http://www2.linuxforum.net/mirror/mysql/})
+
+@item
+@image{Flags/china} China [shellhung.org/Hong Kong] @@
+WWW (@uref{http://mysql.shellhung.org/})
+FTP (@uref{ftp://ftp.shellhung.org/pub/Mirror/mysql/})
+
+@item
+@image{Flags/indonesia} Indonesia [incaf.net] @@
+WWW (@uref{http://mysql.incaf.net/})
+FTP (@uref{ftp://mysql.incaf.net/})
+
+@item
+@image{Flags/indonesia} Indonesia [M-Web] @@
+WWW (@uref{http://mysql.mweb.net.id/})
+
+@item
+@image{Flags/indonesia} Indonesia [web.id] @@
+WWW (@uref{http://mysql.itb.web.id/})
+FTP (@uref{ftp://mysql.itb.web.id/pub/MySQL/})
+
+@item
+@image{Flags/japan} Japan [Soft Agency] @@
+WWW (@uref{http://www.softagency.co.jp/MySQL/})
+
+@item
+@image{Flags/japan} Japan [u-aizu.ac.jp/Aizu] @@
+FTP (@uref{ftp://ftp.u-aizu.ac.jp/ftp/pub/dbms/mysql/mysql.com/})
+
+@item
+@image{Flags/philippines} Philippines [Ateneo de Zamboanga University] @@
+WWW (@uref{http://mysql.adzu.edu.ph/})
+
+@item
+@image{Flags/singapore} Singapore [HJC] @@
+WWW (@uref{http://mysql.hjc.edu.sg/})
+FTP (@uref{ftp://ftp.hjc.edu.sg/mysql/})
+
+@item
+@image{Flags/south-korea} South Korea [HolyNet] @@
+WWW (@uref{http://mysql.holywar.net/})
+
+@item
+@image{Flags/south-korea} South Korea [Webiiz] @@
+WWW (@uref{http://mysql.webiiz.com/})
+
+@item
+@image{Flags/taiwan} Taiwan [nctu.edu/HsinChu] @@
+WWW (@uref{http://mysql.nctu.edu.tw/})
+
+@item
+@image{Flags/taiwan} Taiwan [TTN] @@
+WWW (@uref{http://mysql.ttn.net/})
+
+@end itemize
+
+@strong{Australia:}
+
+@itemize @bullet
+
+@item
+@image{Flags/australia} Australia [planetmirror.com] @@
+WWW (@uref{http://mysql.planetmirror.com/})
+FTP (@uref{ftp://planetmirror.com/pub/mysql/})
+
+@end itemize
+
+@strong{Africa:}
+
+@itemize @bullet
+
+@item
+@image{Flags/south-africa} South African Republic [Mweb] @@
+WWW (@uref{http://www.mysql.mweb.co.za/})
+
+@item
+@image{Flags/south-africa} South African Republic [The Internet Solution/Johannesburg] @@
+FTP (@uref{ftp://ftp.is.co.za/linux/mysql/})
+
+@end itemize
+
+
diff --git a/Docs/my_sys.txt b/Docs/my_sys.txt
new file mode 100644
index 00000000000..85ffc13ecb4
--- /dev/null
+++ b/Docs/my_sys.txt
@@ -0,0 +1,140 @@
+Functions i mysys: (For flags se my_sys.h)
+
+ int my_copy _A((const char *from,const char *to,myf MyFlags));
+ - Copy file
+
+ int my_delete _A((const char *name,myf MyFlags));
+ - Delete file
+
+ int my_getwd _A((string buf,uint size,myf MyFlags));
+ int my_setwd _A((const char *dir,myf MyFlags));
+ - Get and set working directory
+
+ string my_tempnam _A((const char *pfx,myf MyFlags));
+ - Make a uniq temp file name by using dir and adding something after
+ pfx to make name uniq. Name is made by adding a uniq 6 length-string
+ and TMP_EXT after pfx.
+ Returns pointer to malloced area for filename. Should be freed by
+ free().
+
+ File my_open _A((const char *FileName,int Flags,myf MyFlags));
+ File my_create _A((const char *FileName,int CreateFlags,
+ int AccsesFlags, myf MyFlags));
+ int my_close _A((File Filedes,myf MyFlags));
+ uint my_read _A((File Filedes,byte *Buffer,uint Count,myf MyFlags));
+ uint my_write _A((File Filedes,const byte *Buffer,uint Count,
+ myf MyFlags));
+ ulong my_seek _A((File fd,ulong pos,int whence,myf MyFlags));
+ ulong my_tell _A((File fd,myf MyFlags));
+ - Use instead of open,open-with-create-flag, close read and write
+ to get automatic error-messages (flag: MYF_WME) and only have
+ to test for != 0 if error (flag: MY_NABP).
+
+ int my_rename _A((const char *from,const char *to,myf MyFlags));
+ - Rename file
+
+ FILE *my_fopen _A((const char *FileName,int Flags,myf MyFlags));
+ FILE *my_fdopen _A((File Filedes,int Flags,myf MyFlags));
+ int my_fclose _A((FILE *fd,myf MyFlags));
+ uint my_fread _A((FILE *stream,byte *Buffer,uint Count,myf MyFlags));
+ uint my_fwrite _A((FILE *stream,const byte *Buffer,uint Count,
+ myf MyFlags));
+ ulong my_fseek _A((FILE *stream,ulong pos,int whence,myf MyFlags));
+ ulong my_ftell _A((FILE *stream,myf MyFlags));
+ - Same read-interface for streams as for files
+
+ gptr _mymalloc _A((uint uSize,const char *sFile,
+ uint uLine, myf MyFlag));
+ gptr _myrealloc _A((string pPtr,uint uSize,const char *sFile,
+ uint uLine, myf MyFlag));
+ void _myfree _A((gptr pPtr,const char *sFile,uint uLine));
+ int _sanity _A((const char *sFile,unsigned int uLine));
+ gptr _myget_copy_of_memory _A((const byte *from,uint length,
+ const char *sFile, uint uLine,
+ myf MyFlag));
+ - malloc(size,myflag) is mapped to this functions if not compiled
+ with -DSAFEMALLOC
+
+ void TERMINATE _A((void));
+ - Writes malloc-info on stdout if compiled with -DSAFEMALLOC.
+
+ int my_chsize _A((File fd,ulong newlength,myf MyFlags));
+ - Change size of file
+
+ void my_error _D((int nr,myf MyFlags, ...));
+ - Writes message using error number (se mysys/errors.h) on
+ stdout or curses if MYSYS_PROGRAM_USES_CURSES() is called.
+
+ void my_message _A((const char *str,myf MyFlags));
+ - Writes message-string on
+ stdout or curses if MYSYS_PROGRAM_USES_CURSES() is called.
+
+ void my_init _A((void ));
+ - Start each program (in main) with this.
+ void my_end _A((int infoflag));
+ - Gives info about program.
+ - If infoflag & MY_CHECK_ERROR prints if some files are left open
+ - If infoflag & MY_GIVE_INFO prints timing info and malloc info
+ about prog.
+
+ int my_redel _A((const char *from, const char *to, int MyFlags));
+ - Delete from before rename of to to from. Copyes state from old
+ file to new file. If MY_COPY_TIME is set sets old time.
+
+ int my_copystat _A((const char *from, const char *to, int MyFlags));
+ - Copye state from old file to new file.
+ If MY_COPY_TIME is set sets copy also time.
+
+ string my_filename _A((File fd));
+ - Give filename of open file.
+
+ int dirname _A((string to,const char *name));
+ - Copy name of directory from filename.
+
+ int test_if_hard_path _A((const char *dir_name));
+ - Test if dirname is a hard path (Starts from root)
+
+ void convert_dirname _A((string name));
+ - Convert dirname acording to system.
+ - In MSDOS changes all caracters to capitals and changes '/' to
+ '\'
+ string fn_ext _A((const char *name));
+ - Returns pointer to extension in filename
+ string fn_format _A((string to,const char *name,const char *dsk,
+ const char *form,int flag));
+ format a filename with replace of library and extension and
+ converts between different systems.
+ params to and name may be identicall
+ function dosn't change name if name != to
+ Flag may be: 1 force replace filnames library with 'dsk'
+ 2 force replace extension with 'form' */
+ 4 force Unpack filename (replace ~ with home)
+ 8 Pack filename as short as possibly for output to
+ user.
+ All open requests should allways use at least:
+ "open(fn_format(temp_buffe,name,"","",4),...)" to unpack home and
+ convert filename to system-form.
+
+ string fn_same _A((string toname,const char *name,int flag));
+ - Copys directory and extension from name to toname if neaded.
+ copy can be forced by same flags that in fn_format.
+
+ int wild_compare _A((const char *str,const char *wildstr));
+ - Compare if str matches wildstr. Wildstr can contain "*" and "?"
+ as match-characters.
+ Returns 0 if match.
+
+ void get_date _A((string to,int timeflag));
+ - Get current date in a form ready for printing.
+
+ void soundex _A((string out_pntr, string in_pntr))
+ - Makes in_pntr to a 5 chars long string. All words that sounds
+ alike have the same string.
+
+ int init_key_cache _A((ulong use_mem,ulong leave_this_much_mem));
+ - Use cacheing of keys in MISAM, PISAM, and ISAM.
+ KEY_CACHE_SIZE is a good size.
+ - Remember to lock databases for optimal cacheing
+
+ void end_key_cache _A((void));
+ - End key-cacheing.
diff --git a/Docs/mysqld_error.txt b/Docs/mysqld_error.txt
index b8f0ba72ba5..7a5b6cf38d0 100644
--- a/Docs/mysqld_error.txt
+++ b/Docs/mysqld_error.txt
@@ -1,355 +1,457 @@
/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
This file is public domain and comes with NO WARRANTY of any kind */
-#define ER_HASHCHK 1000
+#define ER_HASHCHK 0
"hashchk",
-#define ER_NISAMCHK 1001
+#define ER_NISAMCHK 1
"isamchk",
-#define ER_NO 1002
+#define ER_NO 2
"NO",
-#define ER_YES 1003
+#define ER_YES 3
"YES",
-#define ER_CANT_CREATE_FILE 1004
+#define ER_CANT_CREATE_FILE 4
"Can't create file '%-.64s' (errno: %d)",
-#define ER_CANT_CREATE_TABLE 1005
+#define ER_CANT_CREATE_TABLE 5
"Can't create table '%-.64s' (errno: %d)",
-#define ER_CANT_CREATE_DB 1006
+#define ER_CANT_CREATE_DB 6
"Can't create database '%-.64s'. (errno: %d)",
-#define ER_DB_CREATE_EXISTS 1007
+#define ER_DB_CREATE_EXISTS 7
"Can't create database '%-.64s'. Database exists",
-#define ER_DB_DROP_EXISTS 1008
+#define ER_DB_DROP_EXISTS 8
"Can't drop database '%-.64s'. Database doesn't exist",
-#define ER_DB_DROP_DELETE 1009
+#define ER_DB_DROP_DELETE 9
"Error dropping database (can't delete '%-.64s', errno: %d)",
-#define ER_DB_DROP_RMDIR 1010
+#define ER_DB_DROP_RMDIR 10
"Error dropping database (can't rmdir '%-.64s', errno: %d)",
-#define ER_CANT_DELETE_FILE 1011
+#define ER_CANT_DELETE_FILE 11
"Error on delete of '%-.64s' (errno: %d)",
-#define ER_CANT_FIND_SYSTEM_REC 1012
+#define ER_CANT_FIND_SYSTEM_REC 12
"Can't read record in system table",
-#define ER_CANT_GET_STAT 1013
+#define ER_CANT_GET_STAT 13
"Can't get status of '%-.64s' (errno: %d)",
-#define ER_CANT_GET_WD 1014
+#define ER_CANT_GET_WD 14
"Can't get working directory (errno: %d)",
-#define ER_CANT_LOCK 1015
+#define ER_CANT_LOCK 15
"Can't lock file (errno: %d)",
-#define ER_CANT_OPEN_FILE 1016
+#define ER_CANT_OPEN_FILE 16
"Can't open file: '%-.64s'. (errno: %d)",
-#define ER_FILE_NOT_FOUND 1017
+#define ER_FILE_NOT_FOUND 17
"Can't find file: '%-.64s' (errno: %d)",
-#define ER_CANT_READ_DIR 1018
+#define ER_CANT_READ_DIR 18
"Can't read dir of '%-.64s' (errno: %d)",
-#define ER_CANT_SET_WD 1019
+#define ER_CANT_SET_WD 19
"Can't change dir to '%-.64s' (errno: %d)",
-#define ER_CHECKREAD 1020
+#define ER_CHECKREAD 20
"Record has changed since last read in table '%-.64s'",
-#define ER_DISK_FULL 1021
+#define ER_DISK_FULL 21
"Disk full (%s). Waiting for someone to free some space....",
-#define ER_DUP_KEY 1022
+#define ER_DUP_KEY 22
"Can't write, duplicate key in table '%-.64s'",
-#define ER_ERROR_ON_CLOSE 1023
+#define ER_ERROR_ON_CLOSE 23
"Error on close of '%-.64s' (errno: %d)",
-#define ER_ERROR_ON_READ 1024
+#define ER_ERROR_ON_READ 24
"Error reading file '%-.64s' (errno: %d)",
-#define ER_ERROR_ON_RENAME 1025
+#define ER_ERROR_ON_RENAME 25
"Error on rename of '%-.64s' to '%-.64s' (errno: %d)",
-#define ER_ERROR_ON_WRITE 1026
+#define ER_ERROR_ON_WRITE 26
"Error writing file '%-.64s' (errno: %d)",
-#define ER_FILE_USED 1027
+#define ER_FILE_USED 27
"'%-.64s' is locked against change",
-#define ER_FILSORT_ABORT 1028
+#define ER_FILSORT_ABORT 28
"Sort aborted",
-#define ER_FORM_NOT_FOUND 1029
+#define ER_FORM_NOT_FOUND 29
"View '%-.64s' doesn't exist for '%-.64s'",
-#define ER_GET_ERRNO 1030
+#define ER_GET_ERRNO 30
"Got error %d from table handler",
-#define ER_ILLEGAL_HA 1031
+#define ER_ILLEGAL_HA 31
"Table handler for '%-.64s' doesn't have this option",
-#define ER_KEY_NOT_FOUND 1032
+#define ER_KEY_NOT_FOUND 32
"Can't find record in '%-.64s'",
-#define ER_NOT_FORM_FILE 1033
+#define ER_NOT_FORM_FILE 33
"Incorrect information in file: '%-.64s'",
-#define ER_NOT_KEYFILE 1034
+#define ER_NOT_KEYFILE 34
"Incorrect key file for table: '%-.64s'. Try to repair it",
-#define ER_OLD_KEYFILE 1035
+#define ER_OLD_KEYFILE 35
"Old key file for table '%-.64s'; Repair it!",
-#define ER_OPEN_AS_READONLY 1036
+#define ER_OPEN_AS_READONLY 36
"Table '%-.64s' is read only",
-#define ER_OUTOFMEMORY 1037
+#define ER_OUTOFMEMORY 37
"Out of memory. Restart daemon and try again (needed %d bytes)",
-#define ER_OUT_OF_SORTMEMORY 1038
+#define ER_OUT_OF_SORTMEMORY 38
"Out of sort memory. Increase daemon sort buffer size",
-#define ER_UNEXPECTED_EOF 1039
+#define ER_UNEXPECTED_EOF 39
"Unexpected eof found when reading file '%-.64s' (errno: %d)",
-#define ER_CON_COUNT_ERROR 1040
+#define ER_CON_COUNT_ERROR 40
"Too many connections",
-#define ER_OUT_OF_RESOURCES 1041
+#define ER_OUT_OF_RESOURCES 41
"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",
-#define ER_BAD_HOST_ERROR 1042
+#define ER_BAD_HOST_ERROR 42
"Can't get hostname for your address",
-#define ER_HANDSHAKE_ERROR 1043
+#define ER_HANDSHAKE_ERROR 43
"Bad handshake",
-#define ER_DBACCESS_DENIED_ERROR 1044
+#define ER_DBACCESS_DENIED_ERROR 44
"Access denied for user: '%-.32s@%-.64s' to database '%-.64s'",
-#define ER_ACCESS_DENIED_ERROR 1045
+#define ER_ACCESS_DENIED_ERROR 45
"Access denied for user: '%-.32s@%-.64s' (Using password: %s)",
-#define ER_NO_DB_ERROR 1046
+#define ER_NO_DB_ERROR 46
"No Database Selected",
-#define ER_UNKNOWN_COM_ERROR 1047
+#define ER_UNKNOWN_COM_ERROR 47
"Unknown command",
-#define ER_BAD_NULL_ERROR 1048
+#define ER_BAD_NULL_ERROR 48
"Column '%-.64s' cannot be null",
-#define ER_BAD_DB_ERROR 1049
+#define ER_BAD_DB_ERROR 49
"Unknown database '%-.64s'",
-#define ER_TABLE_EXISTS_ERROR 1050
+#define ER_TABLE_EXISTS_ERROR 50
"Table '%-.64s' already exists",
-#define ER_BAD_TABLE_ERROR 1051
+#define ER_BAD_TABLE_ERROR 51
"Unknown table '%-.64s'",
-#define ER_NON_UNIQ_ERROR 1052
+#define ER_NON_UNIQ_ERROR 52
"Column: '%-.64s' in %-.64s is ambiguous",
-#define ER_SERVER_SHUTDOWN 1053
+#define ER_SERVER_SHUTDOWN 53
"Server shutdown in progress",
-#define ER_BAD_FIELD_ERROR 1054
+#define ER_BAD_FIELD_ERROR 54
"Unknown column '%-.64s' in '%-.64s'",
-#define ER_WRONG_FIELD_WITH_GROUP 1055
+#define ER_WRONG_FIELD_WITH_GROUP 55
"'%-.64s' isn't in GROUP BY",
-#define ER_WRONG_GROUP_FIELD 1056
+#define ER_WRONG_GROUP_FIELD 56
"Can't group on '%-.64s'",
-#define ER_WRONG_SUM_SELECT 1057
+#define ER_WRONG_SUM_SELECT 57
"Statement has sum functions and columns in same statement",
-#define ER_WRONG_VALUE_COUNT 1058
+#define ER_WRONG_VALUE_COUNT 58
"Column count doesn't match value count",
-#define ER_TOO_LONG_IDENT 1059
+#define ER_TOO_LONG_IDENT 59
"Identifier name '%-.100s' is too long",
-#define ER_DUP_FIELDNAME 1060
+#define ER_DUP_FIELDNAME 60
"Duplicate column name '%-.64s'",
-#define ER_DUP_KEYNAME 1061
+#define ER_DUP_KEYNAME 61
"Duplicate key name '%-.64s'",
-#define ER_DUP_ENTRY 1062
+#define ER_DUP_ENTRY 62
"Duplicate entry '%-.64s' for key %d",
-#define ER_WRONG_FIELD_SPEC 1063
+#define ER_WRONG_FIELD_SPEC 63
"Incorrect column specifier for column '%-.64s'",
-#define ER_PARSE_ERROR 1064
+#define ER_PARSE_ERROR 64
"%s near '%-.80s' at line %d",
-#define ER_EMPTY_QUERY 1065
+#define ER_EMPTY_QUERY 65
"Query was empty",
-#define ER_NONUNIQ_TABLE 1066
+#define ER_NONUNIQ_TABLE 66
"Not unique table/alias: '%-.64s'",
-#define ER_INVALID_DEFAULT 1067
+#define ER_INVALID_DEFAULT 67
"Invalid default value for '%-.64s'",
-#define ER_MULTIPLE_PRI_KEY 1068
+#define ER_MULTIPLE_PRI_KEY 68
"Multiple primary key defined",
-#define ER_TOO_MANY_KEYS 1069
+#define ER_TOO_MANY_KEYS 69
"Too many keys specified. Max %d keys allowed",
-#define ER_TOO_MANY_KEY_PARTS 1070
+#define ER_TOO_MANY_KEY_PARTS 70
"Too many key parts specified. Max %d parts allowed",
-#define ER_TOO_LONG_KEY 1071
+#define ER_TOO_LONG_KEY 71
"Specified key was too long. Max key length is %d",
-#define ER_KEY_COLUMN_DOES_NOT_EXITS 1072
+#define ER_KEY_COLUMN_DOES_NOT_EXITS 72
"Key column '%-.64s' doesn't exist in table",
-#define ER_BLOB_USED_AS_KEY 1073
+#define ER_BLOB_USED_AS_KEY 73
"BLOB column '%-.64s' can't be used in key specification with the used table type",
-#define ER_TOO_BIG_FIELDLENGTH 1074
+#define ER_TOO_BIG_FIELDLENGTH 74
"Too big column length for column '%-.64s' (max = %d). Use BLOB instead",
-#define ER_WRONG_AUTO_KEY 1075
+#define ER_WRONG_AUTO_KEY 75
"Incorrect table definition; There can only be one auto column and it must be defined as a key",
-#define ER_READY 1076
+#define ER_READY 76
"%s: ready for connections\n",
-#define ER_NORMAL_SHUTDOWN 1077
+#define ER_NORMAL_SHUTDOWN 77
"%s: Normal shutdown\n",
-#define ER_GOT_SIGNAL 1078
+#define ER_GOT_SIGNAL 78
"%s: Got signal %d. Aborting!\n",
-#define ER_SHUTDOWN_COMPLETE 1079
+#define ER_SHUTDOWN_COMPLETE 79
"%s: Shutdown Complete\n",
-#define ER_FORCING_CLOSE 1080
+#define ER_FORCING_CLOSE 80
"%s: Forcing close of thread %ld user: '%-.32s'\n",
-#define ER_IPSOCK_ERROR 1081
+#define ER_IPSOCK_ERROR 81
"Can't create IP socket",
-#define ER_NO_SUCH_INDEX 1082
+#define ER_NO_SUCH_INDEX 82
"Table '%-.64s' has no index like the one used in CREATE INDEX. Recreate the table",
-#define ER_WRONG_FIELD_TERMINATORS 1083
-"Field separator argument is not what is expected. Check the manual","
-#define ER_BLOBS_AND_NO_TERMINATED 1084
+#define ER_WRONG_FIELD_TERMINATORS 83
+"Field separator argument is not what is expected. Check the manual",
+#define ER_BLOBS_AND_NO_TERMINATED 84
"You can't use fixed rowlength with BLOBs. Please use 'fields terminated by'.",
-#define ER_TEXTFILE_NOT_READABLE 1085
+#define ER_TEXTFILE_NOT_READABLE 85
"The file '%-.64s' must be in the database directory or be readable by all",
-#define ER_FILE_EXISTS_ERROR 1086
+#define ER_FILE_EXISTS_ERROR 86
"File '%-.80s' already exists",
-#define ER_LOAD_INFO 1087
+#define ER_LOAD_INFO 87
"Records: %ld Deleted: %ld Skipped: %ld Warnings: %ld",
-#define ER_ALTER_INFO 1088
+#define ER_ALTER_INFO 88
"Records: %ld Duplicates: %ld",
-#define ER_WRONG_SUB_KEY 1089
-"Incorrect sub part key. The used key part isn't a string or the used length is longer than the key part",
-#define ER_CANT_REMOVE_ALL_FIELDS 1090
+#define ER_WRONG_SUB_KEY 89
+"Incorrect sub part key. The used key part isn't a string, the used length is longer than the key part or the table handler doesn't support unique sub keys",
+#define ER_CANT_REMOVE_ALL_FIELDS 90
"You can't delete all columns with ALTER TABLE. Use DROP TABLE instead",
-#define ER_CANT_DROP_FIELD_OR_KEY 1091
+#define ER_CANT_DROP_FIELD_OR_KEY 91
"Can't DROP '%-.64s'. Check that column/key exists",
-#define ER_INSERT_INFO 1092
+#define ER_INSERT_INFO 92
"Records: %ld Duplicates: %ld Warnings: %ld",
-#define ER_INSERT_TABLE_USED 1093
+#define ER_INSERT_TABLE_USED 93
"INSERT TABLE '%-.64s' isn't allowed in FROM table list",
-#define ER_NO_SUCH_THREAD 1094
+#define ER_NO_SUCH_THREAD 94
"Unknown thread id: %lu",
-#define ER_KILL_DENIED_ERROR 1095
+#define ER_KILL_DENIED_ERROR 95
"You are not owner of thread %lu",
-#define ER_NO_TABLES_USED 1096
+#define ER_NO_TABLES_USED 96
"No tables used",
-#define ER_TOO_BIG_SET 1097
+#define ER_TOO_BIG_SET 97
"Too many strings for column %-.64s and SET",
-#define ER_NO_UNIQUE_LOGFILE 1098
+#define ER_NO_UNIQUE_LOGFILE 98
"Can't generate a unique log-filename %-.64s.(1-999)\n",
-#define ER_TABLE_NOT_LOCKED_FOR_WRITE 1099
+#define ER_TABLE_NOT_LOCKED_FOR_WRITE 99
"Table '%-.64s' was locked with a READ lock and can't be updated",
-#define ER_TABLE_NOT_LOCKED 1100
+#define ER_TABLE_NOT_LOCKED 100
"Table '%-.64s' was not locked with LOCK TABLES",
-#define ER_BLOB_CANT_HAVE_DEFAULT 1101
+#define ER_BLOB_CANT_HAVE_DEFAULT 101
"BLOB column '%-.64s' can't have a default value",
-#define ER_WRONG_DB_NAME 1102
+#define ER_WRONG_DB_NAME 102
"Incorrect database name '%-.100s'",
-#define ER_WRONG_TABLE_NAME 1103
+#define ER_WRONG_TABLE_NAME 103
"Incorrect table name '%-.100s'",
-#define ER_TOO_BIG_SELECT 1104
+#define ER_TOO_BIG_SELECT 104
"The SELECT would examine too many records and probably take a very long time. Check your WHERE and use SET OPTION SQL_BIG_SELECTS=1 if the SELECT is ok",
-#define ER_UNKNOWN_ERROR 1105
+#define ER_UNKNOWN_ERROR 105
"Unknown error",
-#define ER_UNKNOWN_PROCEDURE 1106
+#define ER_UNKNOWN_PROCEDURE 106
"Unknown procedure '%-.64s'",
-#define ER_WRONG_PARAMCOUNT_TO_PROCEDURE 1107
+#define ER_WRONG_PARAMCOUNT_TO_PROCEDURE 107
"Incorrect parameter count to procedure '%-.64s'",
-#define ER_WRONG_PARAMETERS_TO_PROCEDURE 1108
+#define ER_WRONG_PARAMETERS_TO_PROCEDURE 108
"Incorrect parameters to procedure '%-.64s'",
-#define ER_UNKNOWN_TABLE 1109
+#define ER_UNKNOWN_TABLE 109
"Unknown table '%-.64s' in %-.32s",
-#define ER_FIELD_SPECIFIED_TWICE 1110
+#define ER_FIELD_SPECIFIED_TWICE 110
"Column '%-.64s' specified twice",
-#define ER_INVALID_GROUP_FUNC_USE 1111
+#define ER_INVALID_GROUP_FUNC_USE 111
"Invalid use of group function",
-#define ER_UNSUPPORTED_EXTENSION 1112
+#define ER_UNSUPPORTED_EXTENSION 112
"Table '%-.64s' uses an extension that doesn't exist in this MySQL version",
-#define ER_TABLE_MUST_HAVE_COLUMNS 1113
+#define ER_TABLE_MUST_HAVE_COLUMNS 113
"A table must have at least 1 column",
-#define ER_RECORD_FILE_FULL 1114
+#define ER_RECORD_FILE_FULL 114
"The table '%-.64s' is full",
-#define ER_UNKNOWN_CHARACTER_SET 1115
+#define ER_UNKNOWN_CHARACTER_SET 115
"Unknown character set: '%-.64s'",
-#define ER_TOO_MANY_TABLES 1116
+#define ER_TOO_MANY_TABLES 116
"Too many tables. MySQL can only use %d tables in a join",
-#define ER_TOO_MANY_FIELDS 1117
+#define ER_TOO_MANY_FIELDS 117
"Too many columns",
-#define ER_TOO_BIG_ROWSIZE 1118
+#define ER_TOO_BIG_ROWSIZE 118
"Too big row size. The maximum row size, not counting BLOBs, is %d. You have to change some fields to BLOBs",
-#define ER_STACK_OVERRUN 1119
+#define ER_STACK_OVERRUN 119
"Thread stack overrun: Used: %ld of a %ld stack. Use 'mysqld -O thread_stack=#' to specify a bigger stack if needed",
-#define ER_WRONG_OUTER_JOIN 1120
+#define ER_WRONG_OUTER_JOIN 120
"Cross dependency found in OUTER JOIN. Examine your ON conditions",
-#define ER_NULL_COLUMN_IN_INDEX 1121
+#define ER_NULL_COLUMN_IN_INDEX 121
"Column '%-.64s' is used with UNIQUE or INDEX but is not defined as NOT NULL",
-#define ER_CANT_FIND_UDF 1122
+#define ER_CANT_FIND_UDF 122
"Can't load function '%-.64s'",
-#define ER_CANT_INITIALIZE_UDF 1123
+#define ER_CANT_INITIALIZE_UDF 123
"Can't initialize function '%-.64s'; %-.80s",
-#define ER_UDF_NO_PATHS 1124
+#define ER_UDF_NO_PATHS 124
"No paths allowed for shared library",
-#define ER_UDF_EXISTS 1125
+#define ER_UDF_EXISTS 125
"Function '%-.64s' already exist",
-#define ER_CANT_OPEN_LIBRARY 1126
+#define ER_CANT_OPEN_LIBRARY 126
"Can't open shared library '%-.64s' (errno: %d %-.64s)",
-#define ER_CANT_FIND_DL_ENTRY 1127
+#define ER_CANT_FIND_DL_ENTRY 127
"Can't find function '%-.64s' in library'",
-#define ER_FUNCTION_NOT_DEFINED 1128
+#define ER_FUNCTION_NOT_DEFINED 128
"Function '%-.64s' is not defined",
-#define ER_HOST_IS_BLOCKED 1129
+#define ER_HOST_IS_BLOCKED 129
"Host '%-.64s' is blocked because of many connection errors. Unblock with 'mysqladmin flush-hosts'",
-#define ER_HOST_NOT_PRIVILEGED 1130
+#define ER_HOST_NOT_PRIVILEGED 130
"Host '%-.64s' is not allowed to connect to this MySQL server",
-#define ER_PASSWORD_ANONYMOUS_USER 1131
+#define ER_PASSWORD_ANONYMOUS_USER 131
"You are using MySQL as an anonymous users and anonymous users are not allowed to change passwords",
-#define ER_PASSWORD_NOT_ALLOWED 1132
+#define ER_PASSWORD_NOT_ALLOWED 132
"You must have privileges to update tables in the mysql database to be able to change passwords for others",
-#define ER_PASSWORD_NO_MATCH 1133
+#define ER_PASSWORD_NO_MATCH 133
"Can't find any matching row in the user table",
-#define ER_UPDATE_INFO 1134
+#define ER_UPDATE_INFO 134
"Rows matched: %ld Changed: %ld Warnings: %ld",
-#define ER_CANT_CREATE_THREAD 1135
+#define ER_CANT_CREATE_THREAD 135
"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",
-#define ER_WRONG_VALUE_COUNT_ON_ROW 1136
+#define ER_WRONG_VALUE_COUNT_ON_ROW 136
"Column count doesn't match value count at row %ld",
-#define ER_CANT_REOPEN_TABLE 1137
+#define ER_CANT_REOPEN_TABLE 137
"Can't reopen table: '%-.64s'",
-#define ER_INVALID_USE_OF_NULL 1138
+#define ER_INVALID_USE_OF_NULL 138
"Invalid use of NULL value",
-#define ER_REGEXP_ERROR 1139
+#define ER_REGEXP_ERROR 139
"Got error '%-.64s' from regexp",
-#define ER_MIX_OF_GROUP_FUNC_AND_FIELDS 1140
+#define ER_MIX_OF_GROUP_FUNC_AND_FIELDS 140
"Mixing of GROUP columns (MIN(),MAX(),COUNT()...) with no GROUP columns is illegal if there is no GROUP BY clause",
-#define ER_NONEXISTING_GRANT 1141
+#define ER_NONEXISTING_GRANT 141
"There is no such grant defined for user '%-.32s' on host '%-.64s'",
-#define ER_TABLEACCESS_DENIED_ERROR 1142
+#define ER_TABLEACCESS_DENIED_ERROR 142
"%-.16s command denied to user: '%-.32s@%-.64s' for table '%-.64s'",
-#define ER_COLUMNACCESS_DENIED_ERROR 1143
+#define ER_COLUMNACCESS_DENIED_ERROR 143
"%-.16s command denied to user: '%-.32s@%-.64s' for column '%-.64s' in table '%-.64s'",
-#define ER_ILLEGAL_GRANT_FOR_TABLE 1144
+#define ER_ILLEGAL_GRANT_FOR_TABLE 144
"Illegal GRANT/REVOKE command. Please consult the manual which privileges can be used.",
-#define ER_GRANT_WRONG_HOST_OR_USER 1145
+#define ER_GRANT_WRONG_HOST_OR_USER 145
"The host or user argument to GRANT is too long",
-#define ER_NO_SUCH_TABLE 1146
+#define ER_NO_SUCH_TABLE 146
"Table '%-.64s.%-.64s' doesn't exist",
-#define ER_NONEXISTING_TABLE_GRANT 1147
+#define ER_NONEXISTING_TABLE_GRANT 147
"There is no such grant defined for user '%-.32s' on host '%-.64s' on table '%-.64s'",
-#define ER_NOT_ALLOWED_COMMAND 1148
+#define ER_NOT_ALLOWED_COMMAND 148
"The used command is not allowed with this MySQL version",
-#define ER_SYNTAX_ERROR 1149
+#define ER_SYNTAX_ERROR 149
"You have an error in your SQL syntax",
-#define ER_DELAYED_CANT_CHANGE_LOCK 1150
+#define ER_DELAYED_CANT_CHANGE_LOCK 150
"Delayed insert thread couldn't get requested lock for table %-.64s",
-#define ER_TOO_MANY_DELAYED_THREADS 1151
+#define ER_TOO_MANY_DELAYED_THREADS 151
"Too many delayed threads in use",
-#define ER_ABORTING_CONNECTION 1152
+#define ER_ABORTING_CONNECTION 152
"Aborted connection %ld to db: '%-.64s' user: '%-.32s' (%-.64s)",
-#define ER_NET_PACKET_TOO_LARGE 1153
+#define ER_NET_PACKET_TOO_LARGE 153
"Got a packet bigger than 'max_allowed_packet'",
-#define ER_NET_READ_ERROR_FROM_PIPE 1154
+#define ER_NET_READ_ERROR_FROM_PIPE 154
"Got a read error from the connection pipe",
-#define ER_NET_FCNTL_ERROR 1155
+#define ER_NET_FCNTL_ERROR 155
"Got an error from fcntl()",
-#define ER_NET_PACKETS_OUT_OF_ORDER 1156
+#define ER_NET_PACKETS_OUT_OF_ORDER 156
"Got packets out of order",
-#define ER_NET_UNCOMPRESS_ERROR 1157
+#define ER_NET_UNCOMPRESS_ERROR 157
"Couldn't uncompress communication packet",
-#define ER_NET_READ_ERROR 1158
+#define ER_NET_READ_ERROR 158
"Got an error reading communication packets",
-#define ER_NET_READ_INTERRUPTED 1159
+#define ER_NET_READ_INTERRUPTED 159
"Got timeout reading communication packets",
-#define ER_NET_ERROR_ON_WRITE 1160
+#define ER_NET_ERROR_ON_WRITE 160
"Got an error writing communication packets",
-#define ER_NET_WRITE_INTERRUPTED 1161
+#define ER_NET_WRITE_INTERRUPTED 161
"Got timeout writing communication packets",
-#define ER_TOO_LONG_STRING 1162
+#define ER_TOO_LONG_STRING 162
"Result string is longer than max_allowed_packet",
-#define ER_TABLE_CANT_HANDLE_BLOB 1163
+#define ER_TABLE_CANT_HANDLE_BLOB 163
"The used table type doesn't support BLOB/TEXT columns",
-#define ER_TABLE_CANT_HANDLE_AUTO_INCREMENT 1164
+#define ER_TABLE_CANT_HANDLE_AUTO_INCREMENT 164
"The used table type doesn't support AUTO_INCREMENT columns",
-#define ER_DELAYED_INSERT_TABLE_LOCKED 1165
+#define ER_DELAYED_INSERT_TABLE_LOCKED 165
"INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES",
-#define ER_WRONG_COLUMN_NAME 1166
+#define ER_WRONG_COLUMN_NAME 166
"Incorrect column name '%-.100s'",
-#define ER_WRONG_KEY_COLUMN 1167
+#define ER_WRONG_KEY_COLUMN 167
"The used table handler can't index column '%-.64s'",
-#define ER_WRONG_MRG_TABLE 1168
+#define ER_WRONG_MRG_TABLE 168
"All tables in the MERGE table are not identically defined",
-#define ER_DUP_UNIQUE 1169
+#define ER_DUP_UNIQUE 169
"Can't write, because of unique constraint, to table '%-.64s'",
-#define ER_BLOB_KEY_WITHOUT_LENGTH 1170
+#define ER_BLOB_KEY_WITHOUT_LENGTH 170
"BLOB column '%-.64s' used in key specification without a key length",
-#define ER_PRIMARY_CANT_HAVE_NULL 1171
+#define ER_PRIMARY_CANT_HAVE_NULL 171
"All parts of a PRIMARY KEY must be NOT NULL; If you need NULL in a key, use UNIQUE instead",
-#define ER_TOO_MANY_ROWS 1172
+#define ER_TOO_MANY_ROWS 172
"Result consisted of more than one row",
-#define ER_REQUIRES_PRIMARY_KEY 1173
+#define ER_REQUIRES_PRIMARY_KEY 173
"This table type requires a primary key",
-#define ER_NO_RAID_COMPILED 1174
+#define ER_NO_RAID_COMPILED 174
"This version of MySQL is not compiled with RAID support",
-#define ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE 1175
+#define ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE 175
"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
+#define ER_KEY_DOES_NOT_EXITS 176
+"Key '%-.64s' doesn't exist in table '%-.64s'",
+#define ER_CHECK_NO_SUCH_TABLE 177
+"Can't open table",
+#define ER_CHECK_NOT_IMPLEMENTED 178
+"The handler for the table doesn't support check/repair",
+#define ER_CANT_DO_THIS_DURING_AN_TRANSACTION 179
+"You are not allowed to execute this command in a transaction",
+#define ER_ERROR_DURING_COMMIT 180
+"Got error %d during COMMIT",
+#define ER_ERROR_DURING_ROLLBACK 181
+"Got error %d during ROLLBACK",
+#define ER_ERROR_DURING_FLUSH_LOGS 182
+"Got error %d during FLUSH_LOGS",
+#define ER_ERROR_DURING_CHECKPOINT 183
+"Got error %d during CHECKPOINT",
+#define ER_NEW_ABORTING_CONNECTION 184
+"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
+#define ER_DUMP_NOT_IMPLEMENTED 185
+"The handler for the table does not support binary table dump",
+#define ER_FLUSH_MASTER_BINLOG_CLOSED 186
+"Binlog closed, cannot RESET MASTER",
+#define ER_INDEX_REBUILD 187
+"Failed rebuilding the index of dumped table '%-.64s'",
+#define ER_MASTER 188
+"Error from master: '%-.64s'",
+#define ER_MASTER_NET_READ 189
+"Net error reading from master",
+#define ER_MASTER_NET_WRITE 190
+"Net error writing to master",
+#define ER_FT_MATCHING_KEY_NOT_FOUND 191
+"Can't find FULLTEXT index matching the column list",
+#define ER_LOCK_OR_ACTIVE_TRANSACTION 192
+"Can't execute the given command because you have active locked tables or an active transaction",
+#define ER_UNKNOWN_SYSTEM_VARIABLE 193
+"Unknown system variable '%-.64'",
+#define ER_CRASHED_ON_USAGE 194
+"Table '%-.64s' is marked as crashed and should be repaired",
+#define ER_CRASHED_ON_REPAIR 195
+"Table '%-.64s' is marked as crashed and last (automatic?) repair failed",
+#define ER_WARNING_NOT_COMPLETE_ROLLBACK 196
+"Warning: Some non-transactional changed tables couldn't be rolled back",
+#define ER_TRANS_CACHE_FULL 197
+"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again',
+#define ER_SLAVE_MUST_STOP 198
+"This operation cannot be performed with a running slave, run SLAVE STOP first",
+#define ER_SLAVE_NOT_RUNNING 199
+"This operation requires a running slave, configure slave and do SLAVE START",
+#define ER_BAD_SLAVE 200
+"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
+#define ER_MASTER_INFO 201
+"Could not initialize master info structure, check permisions on master.info",
+#define ER_SLAVE_THREAD 202
+"Could not create slave thread, check system resources",
+#define ER_TOO_MANY_USER_CONNECTIONS 203
+"User %-.64s has already more than 'max_user_connections' active connections",
+#define ER_SET_CONSTANTS_ONLY 204
+"You may only use constant expressions with SET",
+#define ER_LOCK_WAIT_TIMEOUT 205
+"Lock wait timeout exceeded; Try restarting transaction",
+#define ER_LOCK_TABLE_FULL 206
+"The total number of locks exceeds the lock table size",
+#define ER_READ_ONLY_TRANSACTION 207
+"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
+#define ER_DROP_DB_WITH_READ_LOCK 208
+"DROP DATABASE not allowed while thread is holding global read lock",
+#define ER_CREATE_DB_WITH_READ_LOCK 209
+"CREATE DATABASE not allowed while thread is holding global read lock",
+#define ER_WRONG_ARGUMENTS 210
+"Wrong arguments to %s",
+#define ER_NO_PERMISSION_TO_CREATE_USER 211
+"%-.32s@%-.64s is not allowed to create new users",
+#define ER_UNION_TABLES_IN_DIFFERENT_DIR 212
+"Incorrect table definition; All MERGE tables must be in the same database",
+#define ER_LOCK_DEADLOCK 213
+"Deadlock found when trying to get lock; Try restarting transaction",
+#define ER_TABLE_CANT_HANDLE_FULLTEXT 214
+"The used table type doesn't support FULLTEXT indexes",
+#define ER_CANNOT_ADD_FOREIGN 215
+"Cannot add foreign key constraint",
+#define ER_NO_REFERENCED_ROW 216
+"Cannot add a child row: a foreign key constraint fails",
+#define ER_ROW_IS_REFERENCED 217
+"Cannot delete a parent row: a foreign key constraint fails",
+#define ER_CONNECT_TO_MASTER 218
+"Error connecting to master: %-.128s",
+#define ER_QUERY_ON_MASTER 219
+"Error running query on master: %-.128s",
+#define ER_ERROR_WHEN_EXECUTING_COMMAND 220
+"Error when executing command %s: %-.128s",
+#define ER_WRONG_USAGE 221
+"Wrong usage of %s and %s",
+#define ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT 222
+"The used SELECT statements have a different number of columns",
+#define ER_CANT_UPDATE_WITH_READLOCK 223
+"Can't execute the query because you have a conflicting read lock",
+#define ER_MIXING_NOT_ALLOWED 224
+"Mixing of transactional and non-transactional tables is disabled",
+#define ER_DUP_ARGUMENT 225
+"Option '%s' used twice in statement",
+#define ER_TOO_MANY_USER_CONNECTIONS 203
+"User %-.64s has already more than 'max_user_connections' active connections",
diff --git a/Docs/section.Infolinks.texi b/Docs/section.Infolinks.texi
new file mode 100644
index 00000000000..828722e0e56
--- /dev/null
+++ b/Docs/section.Infolinks.texi
@@ -0,0 +1,880 @@
+@c FIX AGL 20011108 Extracted from manual.texi.
+@c Contains links to MySQL related info (books, articles). To web portals!
+
+
+@node MySQL-Books, General-SQL, Questions, MySQL Information Sources
+@subsection Books About MySQL
+
+For the latest book information, with user comments, please visit
+@uref{http://www.mysql.com/portal/books/html/}.
+
+While this manual is still the right place for up to date technical
+information, its primary goal is to contain everything there is to know
+about MySQL. It is sometimes nice to have a bound book to read
+in bed or while you travel. Here is a list of books about MySQL and
+related subjects (in English).
+
+By purchasing a book through these hyperlinks provided herein, you are
+contributing to the development of MySQL.
+
+@emph{MySQL}
+@multitable @columnfractions .3 .7
+@item Available @tab @uref{http://service.bfast.com/bfast/click?bfmid=2181&sourceid=34233559&bfpid=0735709211&bfmtype=book} (Barnes and Noble)
+@item Publisher @tab New Riders
+@item Author @tab Paul DuBois
+@item Pub Date @tab 1st Edition December 1999
+@item ISBN @tab 0735709211
+@item Pages @tab 800
+@item Price @tab $49.99 US
+@item Downloadable examples @tab
+ @uref{http://www.kitebird.com/mysql-book/} (@code{samp_db} distribution)
+@item Errata @tab
+@uref{http://www.kitebird.com/mysql-book/errata.html}
+@end multitable
+
+Foreword by Michael ``Monty'' Widenius, MySQL Moderator.
+@*
+
+In @emph{MySQL}, Paul DuBois provides you with a comprehensive guide to
+one of the most popular relational database systems. Paul has
+contributed to the online documentation for MySQL and is an
+active member of the MySQL community. The principal MySQL
+developer, Monty Widenius, and a network of his fellow developers
+reviewed the manuscript, and provided Paul with the kind of insight
+no one else could supply.
+@*
+
+Instead of merely giving you a general overview of MySQL, Paul
+teaches you how to make the most of its capabilities. Through two
+sample database applications that run throughout the book, he
+gives you solutions to problems you're sure to face. He helps you
+integrate MySQL efficiently with third-party tools, such as PHP
+and Perl, enabling you to generate dynamic Web pages through
+database queries. He teaches you to write programs that access
+MySQL databases, and also provides a comprehensive set of
+references to column types, operators, functions, SQL syntax,
+MySQL programming, C API, Perl @code{DBI}, and PHP API.
+@emph{MySQL} simply gives you the kind of information you won't find
+anywhere else.
+@*
+
+If you use MySQL, this book provides you with:
+@itemize @bullet
+@item
+An introduction to MySQL and SQL.
+@item
+Coverage of MySQL's data types and how to use them.
+@item
+Thorough treatment of how to write client programs in C.
+@item
+A guide to using the Perl @code{DBI} and PHP APIs for developing
+command-line and Web-based applications.
+@item
+Tips on administrative issues such as user accounts, backup,
+crash recovery, and security.
+@item
+Help in choosing an ISP for MySQL access.
+@item
+A comprehensive reference for MySQL's data types, operators,
+functions, and SQL statements and utilities.
+@item
+Complete reference guides for MySQL's C API, the Perl @code{DBI} API,
+and PHP's MySQL-related functions.
+@end itemize
+@*
+
+@emph{MySQL & mSQL}
+@multitable @columnfractions .3 .7
+@item Available @tab @uref{http://service.bfast.com/bfast/click?bfmid=2181&sourceid=34233559&bfpid=1565924347&bfmtype=book} (Barnes and Noble)
+@item Publisher @tab O'Reilly
+@item Authors @tab Randy Jay Yarger, George Reese & Tim King
+@item Pub Date @tab 1st Edition July 1999
+@item ISBN @tab 1-56592-434-7, Order Number: 4347
+@item Pages @tab 506
+@item Price @tab $34.95
+@end multitable
+
+This book teaches you how to use MySQL and @code{mSQL}, two popular
+and robust database products that support key subsets of SQL on both Linux
+and Unix systems. Anyone who knows basic C, Java, Perl, or Python can
+write a program to interact with a database, either as a stand-alone
+application or through a Web page. This book takes you through the
+whole process, from installation and configuration to programming
+interfaces and basic administration. Includes plenty of tutorial
+material.
+@*
+
+@emph{Sams' Teach Yourself MySQL in 21 Days}
+@multitable @columnfractions .3 .7
+@item Available @tab @uref{http://service.bfast.com/bfast/click?bfmid=2181&sourceid=34233559&bfpid=0672319144&bfmtype=book} (Barnes and Noble)
+@item Publisher @tab Sams
+@item Authors @tab Mark Maslakowski and Tony Butcher
+@item Pub Date @tab June 2000
+@item ISBN @tab 0672319144
+@item Pages @tab 650
+@item Price @tab $39.99
+@end multitable
+
+Sams' @emph{Teach Yourself MySQL in 21 Days} is for intermediate Linux users
+who want to move into databases. A large share of the audience is Web
+developers who need a database to store large amounts of information that
+can be retrieved via the Web.
+
+Sams' @emph{Teach Yourself MySQL in 21 Days} is a practical, step-by-step
+tutorial. The reader will learn to design and employ this open source
+database technology into his or her website using practical, hands-on
+examples to follow.
+@*
+
+@emph{E-Commerce Solutions with MySQL}
+@multitable @columnfractions .3 .7
+@item Available @tab @uref{http://service.bfast.com/bfast/click?bfmid=2181&sourceid=34233559&bfpid=0761524452&bfmtype=book} (Barnes and Noble)
+@item Publisher @tab Prima Communications, Inc.
+@item Authors @tab N/A
+@item Pub Date @tab January 2000
+@item ISBN @tab 0761524452
+@item Pages @tab 500
+@item Price @tab $39.99
+@end multitable
+
+No description available.
+@*
+
+@emph{MySQL and PHP from Scratch}
+@multitable @columnfractions .3 .7
+@item Available @tab @uref{http://service.bfast.com/bfast/click?bfmid=2181&sourceid=34233559&bfpid=0789724405&bfmtype=book} (Barnes and Noble)
+@item Publisher @tab Que
+@item Authors @tab N/A
+@item Pub Date @tab September 2000
+@item ISBN @tab 0789724405
+@item Pages @tab 550
+@item Price @tab $34.99
+@end multitable
+
+This book puts together information on installing, setting up, and
+troubleshooting Apache, MySQL, PHP3, and IMP into one complete
+volume. You also learn how each piece is part of a whole by learning,
+step-by-step, how to create a web-based e-mail system. Learn to run
+the equivalent of Active Server Pages (ASP) using PHP3, set up an
+e-commerce site using a database and the Apache web server, and create
+a data entry system (such as sales, product quality tracking, customer
+preferences, etc) that no installation in the PC.
+@*
+
+@emph{Professional MySQL Programming}
+@multitable @columnfractions .3 .7
+@item Available @tab @uref{http://shop.barnesandnoble.com/bookSearch/isbnInquiry.asp?isbn=1861005164} (Barnes and Noble)
+@item Publisher @tab Wrox Press, Inc.
+@item Authors @tab N/A
+@item Pub Date @tab Late 2001
+@item ISBN @tab 1861005164
+@item Pages @tab 1000
+@item Price @tab $49.99
+@end multitable
+
+No description available.
+@*
+
+@emph{Professional Linux Programming}
+@multitable @columnfractions .3 .7
+@item Available @tab @uref{http://service.bfast.com/bfast/click?bfmid=2181&sourceid=34233559&bfpid=1861003013&bfmtype=book} (Barnes and Noble)
+@item Publisher @tab Wrox Press, Inc.
+@item Authors @tab N/A
+@item Pub Date @tab September 2000
+@item ISBN @tab 1861003013
+@item Pages @tab 1155
+@item Price @tab $47.99
+@end multitable
+
+In this follow-up to the best-selling @emph{Beginning Linux Programming},
+you will learn from the authors' real-world knowledge and experience of
+developing software for Linux; you'll be taken through the development
+of a sample 'DVD Store' application, with 'theme' chapters addressing
+different aspects of its implementation. Meanwhile, individual
+``take-a-break'' chapters cover important topics that go beyond the
+bounds of the central theme. All focus on the practical aspects of
+programming, showing how crucial it is to choose the right tools for
+the job, use them as they should be used, and get things right first
+time.
+@*
+
+@emph{PHP and MySQL Web Development}
+@multitable @columnfractions .3 .7
+@item Available @tab @uref{http://service.bfast.com/bfast/click?bfmid=2181&sourceid=34233559&bfpid=0672317842&bfmtype=book} (Barnes and Noble)
+@item Publisher @tab Sams
+@item Authors @tab Luke Welling, Laura Thomson
+@item Pub Date @tab March 2001
+@item ISBN @tab 0672317842
+@item Pages @tab 700
+@item Price @tab $49.99
+@end multitable
+
+@emph{PHP and MySQL Web Development} introduces you to the advantages
+of implementing both MySQL and PHP. These advantages are detailed
+through the provision of both statistics and several case studies. A
+practical web application is developed throughout the book, providing
+you with the tools necessary to implement a functional online
+database. Each function is developed separately, allowing you the
+choice to incorporate only those parts that you would like to
+implement. Programming concepts of the PHP language are highlighted,
+including functions which tie MySQL support into a PHP script and
+advanced topics regarding table manipulation.
+@*
+
+@strong{Books recommended by the MySQL Developers}
+
+@emph{SQL-99 Complete, Really}
+@multitable @columnfractions .3 .7
+@item Available @tab @uref{http://service.bfast.com/bfast/click?bfmid=2181&sourceid=34233559&bfpid=0879305681&bfmtype=book} (Barnes and Noble)
+@item Publisher @tab CMP Books
+@item Authors @tab Peter Gulutzan, Trudy Pelzer
+@item Pub Date @tab April 1999
+@item ISBN @tab 0879305681
+@item Pages @tab 1104
+@item Price @tab $55.96
+@end multitable
+
+This book contains complete descriptions of the new standards for
+syntax, data structures, and retrieval processes of SQL databases. As
+an example-based reference manual, it includes all of the CLI
+functions, information, schema tables, and status codes, as well as a
+working SQL database provided on the companion disk.
+@*
+
+@emph{C, A reference manual}
+@multitable @columnfractions .3 .7
+@item Available @tab @uref{http://service.bfast.com/bfast/click?bfmid=2181&sourceid=34233559&bfpid=0133262243&bfmtype=book} (Barnes and Noble)
+@item Publisher @tab Prentice Hall
+@item Authors @tab Samuel P. Harbison, Guy L. Steele
+@item Pub Date @tab September 1994
+@item ISBN @tab 0133262243
+@item Pages @tab 480
+@item Price @tab $35.99
+@end multitable
+
+A new and improved revision of the bestselling C language
+reference. This manual introduces the notion of "Clean C", writing C
+code that can be compiled as a C++ program, C programming style that
+emphasizes correctness, portability, maintainability, and
+incorporates the ISO C Amendment 1 (1994) which specifies new
+facilities for writing portable, international programs in C.
+@*
+
+@emph{C++ for Real Programmers}
+@multitable @columnfractions .3 .7
+@item Available @tab @uref{http://service.bfast.com/bfast/click?bfmid=2181&sourceid=34233559&bfpid=0120499428&bfmtype=book} (Barnes and Noble)
+@item Publisher @tab Academic Press, Incorporated
+@item Authors @tab Jeff Alger, Jim Keogh
+@item Pub Date @tab February 1998
+@item ISBN @tab 0120499428
+@item Pages @tab 388
+@item Price @tab $39.95
+@end multitable
+
+@emph{C++ For Real Programmers} bridges the gap between C++ as described
+in beginner and intermediate-level books and C++ as it is practiced by
+experts. Numerous valuable techniques are described, organised into
+three simple themes: indirection, class hierarchies, and memory
+management. It also provides in-depth coverage of template creation,
+exception handling, pointers and optimisation techniques. The focus of
+the book is on ANSI C++ and, as such, is compiler independent.
+
+@emph{C++ For Real Programmers} is a revision of
+@emph{Secrets of the C++ Masters} and includes a new appendix comparing C++
+with Java. The book comes with a 3.5" disk for Windows with source code.
+@*
+
+@emph{Algorithms in C}
+@multitable @columnfractions .3 .7
+@item Available @tab @uref{http://service.bfast.com/bfast/click?bfmid=2181&sourceid=34233559&bfpid=0201514257&bfmtype=book} (Barnes and Noble)
+@item Publisher @tab Addison Wesley Longman, Inc.
+@item Authors @tab Robert Sedgewick
+@item Pub Date @tab April 1990
+@item ISBN @tab 0201514257
+@item Pages @tab 648
+@item Price @tab $45.75
+@end multitable
+
+@emph{Algorithms in C} describes a variety of algorithms in a number of
+areas of interest, including: sorting, searching, string-processing, and
+geometric, graph and mathematical algorithms. The book emphasizes
+fundamental techniques, providing readers with the tools to confidently
+implement, run, and debug useful algorithms.
+@*
+
+@emph{Multithreaded Programming with Pthreads}
+@multitable @columnfractions .3 .7
+@item Available @tab @uref{http://service.bfast.com/bfast/click?bfmid=2181&sourceid=34233559&bfpid=0136807291&bfmtype=book} (Barnes and Noble)
+@item Publisher @tab Prentice Hall
+@item Authors @tab Bil Lewis, Daniel J. Berg
+@item Pub Date @tab October 1997
+@item ISBN @tab 0136807291
+@item Pages @tab 432
+@item Price @tab $34.95
+@end multitable
+
+Based on the best-selling @emph{Threads Primer},
+@emph{Multithreaded Programming with Pthreads} gives you a solid
+understanding of Posix threads: what they are, how they work, when to use
+them, and how to optimise them. It retains the clarity and humor of
+@emph{Threads Primer}, but includes expanded comparisons to Win32 and OS/2
+implementations. Code examples tested on all of the major UNIX platforms
+are featured along with detailed explanations of how and why they use threads.
+@*
+
+@emph{Programming the PERL DBI: Database Programming with PERL}
+@multitable @columnfractions .3 .7
+@item Available @tab @uref{http://service.bfast.com/bfast/click?bfmid=2181&sourceid=34233559&bfpid=1565926994&bfmtype=book} (Barnes and Noble)
+@item Publisher @tab O'Reilly & Associates, Incorporated
+@item Authors @tab Alligator Descartes, Tim Bunce
+@item Pub Date @tab February 2000
+@item ISBN @tab 1565926994
+@item Pages @tab 400
+@item Price @tab $27.96
+@end multitable
+
+@emph{Programming the Perl DBI} is coauthored by Alligator Descartes, one
+of the most active members of the DBI community, and by Tim Bunce, the
+inventor of DBI. For the uninitiated, the book explains the architecture
+of DBI and shows you how to write DBI-based programs. For the experienced
+DBI dabbler, this book explains DBI's nuances and the peculiarities of each
+individual DBD.
+
+The book includes:
+@itemize @bullet
+@item
+An introduction to DBI and its design.
+@item
+How to construct queries and bind parameters.
+@item
+Working with database, driver, and statement handles.
+@item
+Debugging techniques.
+@item
+Coverage of each existing DBD.
+@item
+A complete reference to DBI.
+@end itemize
+@*
+
+
+@node General-SQL, Useful Links, MySQL-Books, MySQL Information Sources
+@subsection General SQL Information and Tutorials
+
+The MySQL book portal is split into different sections to make it easy
+to locate books for various purposes.
+@uref{http://www.mysql.com/portal/books/html/}
+
+Tutorials can be found at:
+@uref{http://www.mysql.com/portal/development/html/development-61-1.html}
+
+@node Useful Links, , General-SQL, MySQL Information Sources
+@subsection Useful MySQL-related Links
+
+The MySQL development portal is the ultimate source of MySQL related
+links. @uref{http://www.mysql.com/portal/development/html/}
+
+Apart from the following links, you can find and download a lot of
+MySQL programs, tools and APIs in the Contrib directory
+(@uref{http://www.mysql.com/Downloads/Contrib/}).
+@cindex @code{Contrib} directory
+
+@cindex URLs to MySQL information
+@cindex MySQL related information URLs
+@subheading Tutorials and Manuals
+
+@table @asis
+@item @uref{http://michael.bacarella.com/research/mysqlmyths.html} (MySQL Myths Debunked)
+MySQL used in the real world.
+
+@item @uref{http://www.4t2.com/mysql/}
+Information about the German MySQL mailing list.
+
+@item @uref{http://www2.rent-a-database.de/mysql/}
+MySQL handbook in German.
+
+@item @uref{http://www.bitmover.com:8888/home/bk/mysql/}
+Web access to the MySQL BitKeeper repository.
+
+@item @uref{http://www.analysisandsolutions.com/code/mybasic.htm}
+Beginners MySQL Tutorial on how to install and set up
+MySQL on a Windows machine.
+
+@item @uref{http://www.devshed.com/Server_Side/MySQL/}
+A lot of MySQL tutorials.
+
+@item @uref{http://mysql.hitstar.com/}
+MySQL manual in Chinese.
+
+@item @uref{http://www.linuxplanet.com/linuxplanet/tutorials/1046/1/}
+Setting Up a MySQL-based website.
+
+@item @uref{http://www.hotwired.com/webmonkey/backend/tutorials/tutorial1.html}
+MySQL-Perl tutorial.
+
+@item @uref{http://www.iserver.com/support/contrib/perl5/modules.html}
+Installing new Perl modules that require locally installed modules.
+
+@item @uref{http://www.hotwired.com/webmonkey/databases/tutorials/tutorial4.html}
+PHP/MySQL Tutorial.
+
+@item @uref{http://www.useractive.com/}
+Hands on tutorial for MySQL.
+@end table
+
+@subheading MySQL Discussion Forums
+
+@table @asis
+@item @uref{http://www.weberdev.com/}
+Examples using MySQL; (check Top 20)
+
+@item @uref{http://futurerealm.com/forum/futureforum.htm}
+FutureForum Web Discussion Software.
+@end table
+
+@subheading Porting MySQL/Using MySQL on Different Systems
+
+@table @asis
+@item @uref{http://www.entropy.ch/software/macosx/mysql/}
+Binary of MySQL for Mac OS X Client. Includes information of how to
+build and use MySQL on Mac OS X.
+
+@item @uref{http://xclave.macnn.com/MySQL/}
+The Mac OS Xclave. Running MySQL on Mac OS X.
+
+@item @uref{http://www.prnet.de/RegEx/mysql.html}
+MySQL for Mac OS X Server.
+
+@item @uref{http://www.latencyzero.com/macosx/mysql.html}
+Building MySQL for Mac OS X.
+
+@item @uref{http://www.essencesw.com/Software/mysqllib.html}
+New Client libraries for the Mac OS Classic (Macintosh).
+
+@item @uref{http://www.lilback.com/macsql/}
+Client libraries for Mac OS Classic (Macintosh).
+
+@item @uref{http://sixk.maniasys.com/index_en.html}
+MySQL for Amiga
+@end table
+
+@subheading Perl-related Links
+
+@table @asis
+@item @uref{http://dbimysql.photoflux.com/}
+Perl DBI with MySQL FAQ.
+@end table
+
+@c FIX We should get longer descriptions for things in this category!
+@subheading Commercial Applications that Support MySQL
+
+@table @asis
+@item @uref{http://www.supportwizard.com/}
+SupportWizard; Interactive helpdesk on the Web. This product includes a
+licensed copy of MySQL.
+
+@item @uref{http://www.sonork.com/}
+Sonork, Instant Messenger that is not only Internet oriented. It's
+focused on private networks and on small to medium companies. Client
+is free, server is free for up to 5 seats.
+
+@item @uref{http://www.stweb.org/}
+StWeb - Stratos Web and Application server - An easy-to-use, cross
+platform, Internet/Intranet development and deployment system for
+development of web-enabled applications. The standard version of StWeb
+has a native interface to MySQL database.
+
+@item @uref{http://www.rightnowtech.com/}
+Right Now Web; Web automation for customer service.
+
+@item @uref{http://www.icaap.org/Bazaar/}
+Bazaar; Interactive Discussion Forums with Web interface.
+
+@cindex PhoneSweep
+@item @uref{http://www.phonesweep.com/}
+PhoneSweepT is the world's first commercial Telephone Scanner. Many break-ins
+in recent years have come not through the Internet, but through unauthorised
+dial-up modems. PhoneSweep lets you find these modems by repeatedly placing
+phone calls to every phone number that your organisation
+controls. PhoneSweep has a built-in expert system that can recognise
+more than 250 different kinds of remote-access programs, including
+Carbon Copy(TM), pcANYWHERE(TM), and Windows NT RAS. All information is stored
+in the SQL database. It then generates a comprehensive report detailing
+which services were discovered on which dial-up numbers in your organisation.
+@end table
+
+@subheading SQL Clients and Report Writers
+
+@table @asis
+@item @uref{http://www.urbanresearch.com/software/utils/urbsql/} (urSQL)
+SQL Editor and Query Utility. Custom syntax highlighting, editable
+results grid, exportable result-sets, basic MySQL admin functions,
+Etc.. For Windows.
+
+@item @uref{http://www.edatanew.com/} (MySQL Data Manager)
+MySQL Data Manager * is platform independent web client
+(written in perl) for MySQL server over TCP/IP.
+
+@item @uref{http://ksql.sourceforge.net/}
+KDE MySQL client.
+
+@item @uref{http://www.ecker-software.de/}
+A Windows GUI client by David Ecker.
+
+@item @uref{http://www.icaap.org/software/kiosk/}
+Kiosk; a MySQL client for database management. Written in Perl.
+Will be a part of Bazaar.
+
+@item @uref{http://www.casestudio.com/}
+Db design tool that supports MySQL 3.23.
+
+@item @uref{http://home.skif.net/~voland/zeos/eng/}
+Zeos - A client that supports MySQL, Interbase and PostgreSQL.
+
+@item @uref{http://www.geocities.com/SiliconValley/Ridge/4280/GenericReportWriter/grwhome.html}
+A free report writer in Java
+
+@item @uref{http://www.javaframework.de/}
+MySQLExport - Export of MySQL create statements and data in a lot of
+different formats (SQL, HTML, CVS, text, ZIP, GZIP...).
+
+@item @uref{http://dlabs.4t2.com/}
+M2D, a MySQL Administration client for Windows. M2D supports
+administration of MySQL databases, creation of new databases and
+tables, editing, and more.
+
+@item @uref{http://dlabs.4t2.com/}
+Dexter, a small server written in Perl which can be used as a proxy server for
+MySQL or as a database extender.
+
+@item @uref{http://www.scibit.com/Products/Software/Utils/Mascon.asp}
+Mascon is a powerful Win32 GUI for administering MySQL databases.
+
+@item @uref{http://www.rtlabs.com/}
+MacSQL Monitor. GUI for MySQL, ODBC, and JDBC databases for the Mac OS.
+@end table
+
+@subheading Distributions that Include MySQL
+
+@c FIX add the rest (at least a couple more Linuxes)
+
+@table @asis
+@item @uref{http://www.suse.com/}
+SuSE Linux (6.1 and above)
+
+@item @uref{http://www.redhat.com/}
+RedHat Linux (7.0 and above)
+
+@item @uref{http://distro.conectiva.com.br/}
+Conectiva Linux (4.0 and above)
+@end table
+
+@subheading Web Development Tools that Support MySQL
+
+@table @asis
+@item @uref{http://www.php.net/}
+PHP: A server-side HTML-embedded scripting language.
+
+@item @uref{http://www.midgard-project.org/}
+The Midgard Application Server; a powerful Web development environment
+based on MySQL and PHP.
+
+@cindex dbServ
+@item @uref{http://www.dbServ.de/}
+dbServ is an extension to a web server to integrate database output into
+your HTML code. You may use any HTML function in your output. Only the
+client will stop you. It works as standalone server or as Java servlet.
+
+@item @uref{http://www.chilisoft.com/}
+Platform independent ASP from Chili!Soft
+
+@item @uref{http://www.voicenet.com/~zellert/tjFM/}
+A JDBC driver for MySQL.
+
+@item @uref{http://www.wernhart.priv.at/php/}
+MySQL + PHP demos.
+
+@item @uref{http://www.dbwww.com/}
+ForwardSQL: HTML interface to manipulate MySQL databases.
+
+@item @uref{http://www.daa.com.au/~james/www-sql/}
+WWW-SQL: Display database information.
+
+@item @uref{http://www.heitml.com/}
+HeiTML: A server-side extension of HTML and a 4GL language at the same time.
+
+@item @uref{http://hawkeye.net/}
+Hawkeye Internet Server Suite.
+
+@item @uref{http://www.webgroove.com/}
+WebGroove Script: HTML compiler and server-side scripting language.
+
+@item @uref{http://www.ihtml.com/}
+A server-side website scripting language.
+
+@item @uref{ftp://ftp.igc.apc.org/pub/myodbc/README}
+How to use MySQL with ColdFusion on Solaris.
+
+@item @uref{http://calistra.com/MySQL/}
+Calistra's ODBC MySQL Administrator.
+
+@item @uref{http://phpclub.net/}
+PHPclub - Tips and tricks for PHP.
+
+@item @uref{http://www.widgetchuck.com/}
+The Widgetchuck; Website Tools and Gadgets
+
+@item @uref{http://www.adcycle.com/}
+AdCycle - advertising management software.
+
+@cindex pwPage
+@item @uref{http://sourceforge.net/projects/pwpage/}
+pwPage - provides an extremely fast and simple approach to the creation
+of database forms. That is, if a database table exists and an HTML page
+has been constructed using a few simple guidelines, pwPage can be
+immediately used for table data selections, insertions, updates, deletions
+and selectable table content reviewing.
+
+@item @uref{http://www.omnis-software.com/products/studio/studio.html}
+OMNIS Studio is a rapid application development (RAD) tool.
+@end table
+
+@subheading Database Design Tools with MySQL Support
+
+@table @asis
+@item @uref{http://www.mysql.com/documentation/dezign/}
+"DeZign for databases" is a database development tool that uses an
+entity relationship diagram (ERD).
+@end table
+
+@subheading Web Servers with MySQL Tools
+
+@table @asis
+@item @uref{ftp://ftp.kcilink.com/pub/}
+mod_auth_mysql, An Apache authentication module.
+
+@item @uref{http://www.roxen.com/}
+The Roxen Challenger Web server.
+@end table
+
+@subheading Extensions for Other Programs
+
+@table @asis
+@item @uref{http://www.seawood.org/msql_bind/}
+MySQL support for BIND (The Internet Domain Name Server).
+
+@item @uref{http://www.inet-interactive.com/sendmail/}
+MySQL support for Sendmail and Procmail.
+@end table
+
+@subheading Using MySQL with Other Programs
+
+@table @asis
+@item @uref{http://www.iserver.com/support/addonhelp/database/mysql/msaccess.html}
+Using MySQL with Access.
+
+@item @uref{http://www.iserver.com/support/contrib/perl5/modules.html}
+Installing new Perl modules that require locally installed modules.
+@end table
+
+@subheading ODBC-related Links
+
+@table @asis
+@item @uref{http://www.iodbc.org/}
+Popular iODBC Driver Manager (libiodbc) now available as Open Source.
+
+@item @uref{http://users.ids.net/~bjepson/freeODBC/}
+The FreeODBC Pages.
+
+@item @uref{http://genix.net/unixODBC/}
+The unixODBC Project goals are to develop and promote unixODBC to be the
+definitive standard for ODBC on the Linux platform. This is to include GUI
+support for KDE.
+
+@item @uref{http://www.sw-soft.com/products/BtrieveODBC/}
+A MySQL-based ODBC driver for Btrieve.
+@end table
+
+@subheading @strong{API}-related Links
+
+@table @asis
+@item @uref{http://www.jppp.com/}
+Partially implemented TDataset-compatible components for MySQL.
+
+@item @uref{http://www.riverstyx.net/qpopmysql/}
+qpopmysql - A patch to allow POP3 authentication from a MySQL
+database. There's also a link to Paul Khavkine's patch for Procmail to
+allow any MTA to deliver to users in a MySQL database.
+
+@item @uref{http://www.essencesw.com/Software/mysqllib.html}
+New Client libraries for the Mac OS Classic (Macintosh).
+
+@item @uref{http://www.lilback.com/macsql/}
+Client libraries for the Macintosh.
+
+@item @uref{http://www.essencesw.com/Plugins/mysqlplug.html}
+Plugin for REALbasic (for Macintosh)
+
+@item @uref{http://www.iis.ee.ethz.ch/~neeri/macintosh/gusi-qa.html}
+A library that emulates BSD sockets and pthreads on Macintosh. This can
+be used if you want to compile the MySQL client library on Mac.
+It could probably even be sued to port MySQL to Macintosh, but we
+don't know of anyone that has tried that.
+
+@cindex SCMDB
+@item @uref{http://www.dedecker.net/jessie/scmdb/}
+SCMDB - an add-on for SCM that ports the MySQL C library to scheme
+(SCM). With this library scheme developers can make connections to a
+MySQL database and use embedded SQL in their programs.
+@end table
+
+@subheading Other MySQL-related Links
+
+@table @asis
+@item @uref{http://www.satisoft.com/} (SAT)
+The Small Application Toolkit (SAT) is a collection of utilities
+intended to simplify the development of small, multi-user, GUI based
+applications in a (Microsoft -or- X) Windows Client / Unix Server
+environment.
+
+@item @uref{http://www.wix.com/mysql-hosting/}
+Registry of Web providers who support MySQL.
+
+@item @uref{http://www.softagency.co.jp/mysql/index.en.html}
+Links about using MySQL in Japan/Asia.
+
+@item @uref{http://abattoir.cc.ndsu.nodak.edu/~nem/mysql/udf/}
+MySQL UDF Registry.
+
+@item @uref{http://www.open.com.au/products.html}
+Commercial Web defect tracking system.
+
+@item @uref{http://www.stonekeep.com/pts/}
+PTS: Project Tracking System.
+
+@item @uref{http://tomato.nvgc.vt.edu/~hroberts/mot/}
+Job and software tracking system.
+
+@item @uref{http://www.cynergi.net/exportsql/}
+ExportSQL: A script to export data from Access95+.
+
+@item @uref{http://SAL.KachinaTech.COM/H/1/MYSQL.html}
+SAL (Scientific Applications on Linux) MySQL entry.
+
+@item @uref{http://www.infotech-nj.com/itech/index.shtml}
+A consulting company which mentions MySQL in the right company.
+
+@item @uref{http://www.pmpcs.com/}
+PMP Computer Solutions. Database developers using MySQL and
+@code{mSQL}.
+
+@item @uref{http://www.dedserius.com/y2kmatrix/}
+Y2K tester.
+@end table
+
+@subheading SQL and Database Interfaces
+
+@table @asis
+@item @uref{http://java.sun.com/products/jdbc/}
+The JDBC database access API.
+
+@item @uref{http://www.gagme.com/mysql/}
+Patch for @code{mSQL} Tcl.
+
+@item @uref{http://www.amsoft.ru/easysql/}
+EasySQL: An ODBC-like driver manager.
+
+@item @uref{http://www.lightlink.com/hessling/rexxsql.html}
+A REXX interface to SQL databases.
+
+@c @item @uref{http://www.mytcl.cx/}
+@c Tcl interface based on tcl-sql with many bugfixes.
+
+@item @uref{http://www.binevolve.com/~tdarugar/tcl-sql/}
+Tcl interface for MySQL.
+
+@item @uref{http://www.contrib.andrew.cmu.edu/~shadow/sql.html}
+SQL Reference Page with a lot of interesting links.
+
+@end table
+
+@subheading Examples of MySQL Use
+
+@table @asis
+@c Added 990601
+@c EMAIL: thuss@little6.com (Todd Huss)
+@item @uref{http://www.little6.com/about/linux/}
+Little6 Inc., An online contract and job finding site that is powered by
+MySQL, PHP3, and Linux.
+
+@c Added 990521
+@c EMAIL: info@worldrecords.com (Jim Rota)
+@item @uref{http://www.worldrecords.com/}
+World Records - A search engine for information about music that uses
+MySQL and PHP.
+
+@item @uref{http://www.webtechniques.com/archives/1998/01/note/}
+A Contact Database using MySQL and PHP.
+
+@item @uref{http://modems.rosenet.net/mysql/}
+Web based interface and Community Calendar with PHP.
+
+@item @uref{http://www.odbsoft.com/cook/sources.htm}
+Perl package to generate html from a SQL table structure and for generating
+SQL statements from an html form.
+
+@item @uref{http://www.gusnet.cx/proj/telsql/}
+Basic telephone database using @code{DBI}/@code{DBD}.
+
+@item @uref{http://tecfa.unige.ch/guides/java/staf2x/ex/jdbc/coffee-break/}
+JDBC examples by Daniel K. Schneider.
+
+@item @uref{http://www.ooc.com/}
+Object Oriented Concepts Inc; CORBA applications with examples in source.
+
+@c EMAIL: paul@sword.damocles.com (Paul Bannister)
+@item @uref{http://www.stopbit.com/}
+Stopbit - A technology news site using MySQL and PHP.
+
+@item @uref{http://www.penguinservices.com/scripts/}
+Online shopping cart system.
+
+@c Added 990928 from editor@city-gallery.com
+@cindex Old Photo Album
+@item @uref{http://www.city-gallery.com/album/}
+Old Photo Album - The album is a collaborative popular history of photography
+project that generates all pages from data stored in a MySQL
+database. Pages are dynamically generated through a php3 interface to the
+database content. Users contribute images and descriptions. Contributed
+images are stored on the web server to avoid storing them in the database
+as BLOBs. All other information is stored on the shared MySQL server.
+@end table
+
+@subheading General Database Links
+
+@table @asis
+@item @uref{http://black.hole-in-the.net/guy/webdb/}
+Homepage of the webdb-l (Web Databases) mailing list.
+
+@item @uref{http://www.symbolstone.org/technology/perl/DBI/}
+Perl @code{DBI}/@code{DBD} modules homepage.
+
+@item @uref{http://www.student.uni-koeln.de/cygwin/}
+Cygwin tools. Unix on top of Windows.
+
+@cindex Tek-Tips forums
+@cindex forums, Tek-Tips
+@item @uref{http://www.tek-tips.com/}
+Tek-Tips Forums are 800+ independent peer-to-peer non-commercial support
+forums for Computer Professionals. Features include automatic e-mail
+notification of responses, a links library, and member confidentiality
+guaranteed.
+
+@item @uref{http://www.public.asu.edu/~peterjn/btree/}
+B-Trees: Balanced Tree Data Structures.
+
+@item @uref{http://www.fit.qut.edu.au/~maire/baobab/lecture/sld001.htm}
+A lecture about B-Trees.
+@end table
+
+
diff --git a/Docs/section.Testimonials.texi b/Docs/section.Testimonials.texi
new file mode 100644
index 00000000000..e757a6a92d0
--- /dev/null
+++ b/Docs/section.Testimonials.texi
@@ -0,0 +1,31 @@
+@c FIX AGL 20011108 Extracted from manual.texi.
+@c Should only be on website with new submits by webform.
+
+
+@node MySQL Testimonials, Contrib, Users, Top
+@appendix MySQL Testimonials
+
+@cindex MySQL Testimonials
+
+The section 'MySQL Users' contains a lot of different links to
+MySQL users but doesn't provide that much information about how
+they are using MySQL. @xref{Users}. This section gives you an idea
+of how other MySQL users are using MySQL to solve their problems.
+
+Please note that all new stories are added on the MySQL website,
+@uref{http://www.mysql.com/}.
+Do let us know about @emph{your} success story too!
+
+@itemize @bullet
+@item
+@strong{Peter Zaitsev of Spylog.ru} writes:
+I think you might be interested in my database size. The whole database
+is currently on 15 servers and I think it's about 60.000 of tables
+containing about 5.000.000.000 of rows. My mostly loaded server
+currently holds about 10.000 of tables with 1.000.000.000 of rows in it.
+Hugest tables have about 50.000.000 of rows, and this value will raise
+as soon as I'll move to 2.4 kernel with large files. Currently I have to
+delete much of logs for large sites to hold table sizes in 2Gb.
+
+@item
+
diff --git a/Docs/section.Users.texi b/Docs/section.Users.texi
new file mode 100644
index 00000000000..3c8d219fa16
--- /dev/null
+++ b/Docs/section.Users.texi
@@ -0,0 +1,414 @@
+@c FIX AGL 20011108 Extracted from manual.texi.
+@c Should only be on website.
+
+
+@node Users, Contrib, Problems, Top
+@appendix MySQL Users
+
+@cindex users, of MySQL
+@cindex news sites
+
+This appendix lists users of MySQL that have given us permission
+to list them in our documentation. It is by far not a complete list, but
+should give you a general idea of who uses MySQL and what it can
+be used for.
+
+@appendixsec General News Sites
+
+@itemize @bullet
+
+@item @uref{http://www.yahoo.com/} (Yahoo!)
+
+@item @uref{http://slashdot.org/} (Slashdot: A pro-Linux/tech news and comment/discussion site)
+
+@item @uref{http://www.linux.com/} (All about Linux)
+
+@item @uref{http://www.linuxtoday.com/} (Linuxtoday)
+
+@item @uref{http://www.32bitsonline.com/} (32Bits Online: because there's
+more than one way to compute)
+
+@item @uref{http://www.freshmeat.net/} (Freshmeat: News about new versions of computer-related stuff)
+
+@end itemize
+
+@cindex search engines, web
+@cindex web search engines
+@appendixsec Web Search Engines
+
+@itemize @bullet
+
+@item @uref{http://www.aaa.com.au/} (AAA Matilda Web Search)
+@item @uref{http://www.whatsnu.com/} (What's New)
+@item @uref{http://www.aladin.de/} (Aladin)
+@item @uref{http://www.columbus-finder.de/} (Columbus Finder)
+@item @uref{http://www.spider.de/} (Spider)
+@item @uref{http://www.blitzsuche.de/} (Blitzsuche)
+@item @uref{http://www.indoseek.co.id/} (Indoseek Indonesia)
+@item @uref{http://www.yaboo.dk/} (Yaboo - Yet Another BOOkmarker)
+@item @uref{http://www.ozsearch.com.au/} (OzSearch Internet Guide)
+@item @uref{http://www.splatsearch.com/} (Splat! Search)
+@item @uref{http://osdls.library.arizona.edu/} (The Open Source Digital Library System Project)
+@end itemize
+
+@appendixsec Information Search Engines Specialising in a Particular Area
+
+@itemize @bullet
+
+@item @uref{http://www.spylog.ru/} (SpyLOG ; A very popular Web counter site)
+
+@item @uref{http://www.tucows.com/} (TuCows Network; Free Software archive)
+
+@item @uref{http://www.jobvertise.com/} (Jobvertise: Post and search for jobs)
+
+@item @uref{http://www.musicdatabase.com/} (The Music Database)
+
+@item @uref{http://www.soccersearch.com/} (Football -Soccer- search page)
+
+@item @uref{http://www.headrush.net/takedown} (TAKEDOWN - wrestling)
+
+@item @uref{http://www.lyrics.net/} (The International Lyrics Network)
+
+@item @uref{http://TheMatrix.com/~matrix/band_search.phtml} (Musicians looking for other musicians; free service)
+
+@item @uref{http://www.addall.com/AddBooks/Stores.html} (AddALL books searching and price comparison)
+
+@item @uref{http://www.herbaria.harvard.edu/Data/Gray/gray.html} (Harvard's Gray Herbarium Index of Plant Names)
+
+@item @uref{http://www.game-developer.com/} (The Game Development Search Engine)
+
+@item @uref{http://www.theinnkeeper.com/} (The Innkeeper Vacation Guides)
+
+@item @uref{http://www.macgamedatabase.com/} (The Mac Game Database uses PHP and MySQL)
+@c From: Marc Antony Vose <suzerain@suzerain.com>
+
+@item @uref{http://www.csse.monash.edu.au/publications/} (Research
+Publications at Monash University in Australia)
+
+@item @uref{http://www.ipielle.emr.it/bts/}
+(Occupational Health & Safety Website database; a project for the ECC)
+@c c.presutti@ipielle.emr.it
+
+@item @uref{http://data.mch.mcgill.ca/} (Bioinformatics databases at the
+Montreal Children's Hospital using MySQL)
+@c saeed@www.debelle.mcgill.ca
+@end itemize
+
+@cindex online magazines
+@cindex magazines, online
+@appendixsec Online Magazines
+
+@itemize @bullet
+@item @uref{http://www.spoiler.com/} (Spoiler Webzine)
+An online magazine featuring music, literature, arts, and design content.
+@item @uref{http://www.linux-magazin.de/newsflash/} (Daily news about Linux in German language)
+@item @uref{http://www.betazine.com/} (Betazine - The Ultimate Online Beta Tester's Magazine)
+@item @uref{http://www.currents.net/ccinfo/aboutcc.html} (Computer Currents Magazine)
+@end itemize
+
+@cindex websites
+@appendixsec Websites that Use MySQL as a Backend
+
+@itemize @bullet
+
+@item @uref{http://liftoff.msfc.nasa.gov/} (NASA)
+@item @uref{http://kids.msfc.nasa.gov/} (NASA KIDS)
+@item @uref{http://science.nasa.gov/} (Sience@@NASA)
+
+@item @uref{http://www.handy.de/} (handy.de)
+
+@item @uref{http://lindev.jmc.tju.edu/qwor/} (Qt Widget and Object Repository)
+
+@item @uref{http://www.samba-choro.com.br/} (Brazilian samba site; in Portuguese)
+
+@item @uref{http://pgss.iss.uw.edu.pl/en_index.ISS} (Polish General Social Survey)
+
+@item @uref{http://www.expo2000.com/} Expo2000 - world-wide distribution of
+tickets for this event is implemented using MySQL and Tcl/Tk. More than
+5000 travel agencies all over the world have access to it.
+
+@item @uref{http://www.freevote.com/} FreeVote.com is a free voting
+service with millions of users.
+
+@item @uref{http://f1.tauzero.se/} (Forza Motorsport)
+
+@item @uref{http://www.dreamhost.com/} (DreamHost Web Hosting)
+
+@end itemize
+
+@cindex services
+@appendixsec Domain/Internet/Web and Related Services
+
+@itemize @bullet
+
+@item @uref{http://www.wix.com/mysql-hosting/} (Registry of Web providers that
+support MySQL)
+
+@item @uref{http://www.yi.org/} (Dynamic DNS Services)
+
+@item @uref{http://www.dynodns.net/} (Dynamic domain name service)
+
+@item @uref{http://www.ods.org/} (Open DNS Project; free dynamic DNS service)
+
+@c @item @uref{http://dynodns.net/} (Free dynamic DNS implementation)
+@c EMAIL: A Moore <amoore@mooresystems.com>
+
+@item @uref{http://www.hn.org/} (Hammernode; Public DNS Servers)
+
+@item @uref{http://www.fdns.net/} (Free 3rd level domains)
+
+@item @uref{http://worldcommunity.com/} (Online Database)
+
+@item @uref{http://www.bigbiz.com/} (BigBiz Internet Services)
+
+@item @uref{http://virt.circle.net/} (The Virt Gazette)
+
+@item @uref{http://www.california.com/} (Global InfoNet Inc)
+
+@item @uref{http://www.webhosters.com/} (WebHosters - A Guide to WWW Providers)
+
+@item @uref{http://online.dn.ru/} (Internet information server)
+
+@item @uref{http://www.worldnetla.net/} (WorldNet Communications - An Internet Services Provider)
+
+@item @uref{http://www.netizen.com.au/} (Netizen: Australian-based Web consultancy)
+
+@item @uref{http://www.trainingpages.co.uk/} (Search site for training courses in the UK)
+
+@item @uref{http://chat.nitco.com/} (Gannon Chat; GPL. Written in Perl and Javascript)
+
+@item @uref{http://www.addurls.com/} (A general links directory)
+
+@item @uref{http://www.bookmarktracker.com/} (A Web-based bookmark management service)
+
+@item @uref{http://www.cdrom.com/} (Walnut Creek CDROM)
+
+@item @uref{http://www.wwwthreads.org/} (WWWThreads; Interactive discussion Forums)
+
+@item @uref{http://pvmon.portici.enea.it/Meteo/} (In Italian; Storage data from meteo station)
+
+@item @uref{http://www.buysell.net/} (Online "Person To Person" Auction)
+
+@item @uref{http://tips.pair.com/} (Tips on Web development)
+
+@item @uref{http://www.mailfriends.com/} (Mailfriends.com is a FREE service for
+everybody who wants to find friends over the internet)
+
+@item @uref{http://www.uninova.com/cgi-bin/wctelnets?list} (Web Page Telnet BBS List)
+
+@item @uref{http://www.uninova.com/cnc.html} (UniNova Digital Postcards)
+
+@c @item @uref{http://cabinboy.powersurfr.com/} (An Internet RFC search engine)
+
+@item @uref{http://www.dslreports.com/} (DSL-provider search with reviews)
+Made with MySQL and Modperl, all pages are generated dynamically out of
+the MySQL database
+@end itemize
+
+@cindex PHP, websites
+@appendixsec Websites that Use @code{PHP} and MySQL
+
+@itemize @bullet
+@c @item @uref{http://www.wh200th.com/} (White House 200th Anniversary site)
+
+@item @uref{http://support.jgaa.com/} (Jgaa's Internet - Official Support Site)
+
+@item @uref{http://io.incluso.com/} (Ionline - online publication) MySQL,
+PHP, Java, Web programming, DB development
+
+@item @uref{http://www.baboo.com/} (BaBoo - Browse and Bookmark. Free Web-based bookmark manager and Calendar)
+
+@item @uref{http://www.courses.pjc.cc.fl.us/Schedule/}
+(Course Schedule System at Pensacola Junior College)
+
+@item @uref{http://www.fccj.org/} (Florida Community College at Jacksonville)
+
+@item @uref{http://www.32bit.com/} (32bit.com; An extensive shareware / freeware archive)
+
+@item @uref{http://www.jokes2000.com/} (Jokes 2000)
+@c Added 990604; EMAIL: ah@dybdahl.dk
+
+@item @uref{http://www.burken.nu/}
+Burken is a webhotel that provides scripts, among other things,
+for remote users, like counters, guestbooks etc.
+@c Added 990608; EMAIL: spacedmp@SpaceDump.Burken.NU (Anders Olausson)
+
+@item @uref{http://tips.pair.com/}
+Contains tips on html, javascript, 2d/3d graphics, and PHP3/MySQL.
+All pages are generated from a database.
+@c Added 990614; EMAIL: downey@image.dk (Rune Madsen)
+
+@item @uref{http://www.softwarezrus.com/}
+Ecommerce site that is selling computers.
+@end itemize
+
+@cindex consultants, list of
+@appendixsec MySQL Consultants
+
+@itemize @bullet
+
+@item @uref{http://www.ayni.com/} (Ayni AG)
+
+@item @uref{http://worldcommunity.com/} (Online Database)
+
+@item @uref{http://www2.dataguard.no/} (DataGuard; Uses MySQL and PHP)
+
+@item @uref{http://wwits.net/programs/mysql.phtml} (WWITS; uses MySQL and PHP)
+
+@item @uref{http://www.worldcommunity.com/} (WCN - The World Community Network)
+
+@item @uref{http://www.chipcastle.com/} (Chip Castle Dot Com Inc)
+@c Added 990603 EMAIL: chip@chipcastle.com (Chip Castle)
+
+@item @uref{http://www.cyber.com.au/} (Cybersource Pty. Ltd)
+
+@item @uref{http://www.spring.de/} (Spring infotainment gmbh & co. kg)
+@c added 990905 "Oliver Pischke" <opischke@spring.de>
+
+@item @uref{http://www.wamdesign.com/} (Wam Design develops websites using MySQL)
+@c Added 990905; max@wamdesign.com
+
+@item @uref{http://www.berkeleyconsultants.com/} (Berkeley Consultants Group)
+
+@item @uref{http://www.jammconsulting.com/} (JAMM Consulting Inc)
+
+@end itemize
+
+@c Commented out by Arjen 011018, section is empty!
+@c appendixsec Programming
+
+@cindex web pages, miscellaneous
+@appendixsec Uncategorised Pages
+
+@itemize @bullet
+
+@item @uref{http://www.feature-showcase.com/htmls/demo_mysql.sql} (AZC.COM's Feature Showcase)
+
+@item @uref{http://www.teach.org.uk/subjects/trainingcourse/g.html} (Course Search)
+
+@item @uref{http://www.northerbys.com/} (Northerbys Online Auctions)
+
+@item @uref{http://www.schiphol.nl/flights/home.htm} (Amsterdam Airport Schiphol)
+
+@item @uref{http://TheMatrix.com/seventhsin/query.phtml} (CD database)
+
+@item @uref{http://TheMatrix.com/~flmm/GEAR.html} (Used Audio Gear Database)
+
+@item @uref{http://www.kiss.de/musik-mueller/} (Musical note-sheets)
+
+@item @uref{http://www.bagism.com/} (Bagism; A John Lennon fan page)
+
+@item @uref{http://www.selftaught.com/} (US Folk art broker)
+
+@item @uref{http://organizer.net/} (Mail reading on the Web)
+
+@item @uref{http://www.mypage.org/} (Free home pages on www.somecoolname.mypage.org)
+
+@item @uref{http://www.schulweb.de/} (Der Server f@"ur Schulen im Web - in German)
+
+@item @uref{http://www.ald.net/} (Auldhaefen Online Services)
+
+@item @uref{http://www.cary.net/} (CaryNET Information Center)
+
+@item @uref{http://www.dataden.com/} (Dataden Computer Systems)
+
+@item @uref{http://andree.grm.se/} (Andr@'emuseet; in Swedish)
+
+@item @uref{http://www.him.net/} (HOMESITE Internet Marketing)
+
+@item @uref{http://www.jade-v.com/techinfo.html} (Jade-V Network Services)
+
+@item @uref{http://ww2010.atmos.uiuc.edu/(Gl)/abt/aknw/tech.rxml}
+Weather World 2010 Technical Credits
+
+@item @uref{http://gimp.foebud.org/registry/doc/}
+About The Gimp plugin registry
+
+@item @uref{http://www.fast-inc.com/Products/Archiver/database.html}
+Java tool; archiver technical detail (Slightly optimistic about MySQL
+ANSI-92 compliance)
+
+@item @uref{http://www.gamesdomain.com/cheats/usrcheat.phtml} (Games Domain Cheats Database)
+
+@item @uref{http://www.kcilink.com/poweredby/} (The "Powered By" Page; Kcilink)
+
+@item @uref{http://www.netcasting.net/index.whtml} (Netcasting)
+
+@item @uref{http://homepages.tig.com.au/~mjj/nbltips} (NBL: Australian National Basketball League; tipping)
+
+@item @uref{http://www.cgishop.com/} (CGI shop)
+
+@item @uref{http://www.whirlycott.com/} (Whirlycott: Website Design)
+
+@item @uref{http://www.mtp.dk/} (Museum Tusculanum Press)
+
+@item @uref{http://csdgi.historie.ku.dk/biblio/} (Centro Siciliano di Documentazione)
+
+@item @uref{http://caribou.dyn.ml.org:8000/} (Quake statistics database)
+
+@item @uref{http://www.astroforum.ch/} (Astroforum: Astrologie and related things; in German)
+
+@item @uref{http://www.opendebate.com/} (OpenDebate - Interactive Polls & Open Discussion)
+
+@item @uref{http://vermeer.organik.uni-erlangen.de/dissertationen/} (Online chemical dissertation server)
+
+@item @uref{http://www.freschinfo.com/} (FreSch! The Free Scholarship Search Service)
+
+@item @uref{http://www.nada.kth.se/~staffanu/pinball/} (Stockholm Pinball Locator)
+
+@item @uref{http://www.hek.com/} (HEK - a construction company)
+
+@item @uref{http://www.ebi.nl/} (Elsevier Business Information)
+
+@item @uref{http://vaccination.medicallink.se/} (Medical Links; using ColdFusion and MySQL)
+
+@item @uref{http://www.joblink-usa.com/} (Search for jobs & people at JobLink-USA)
+
+@item @uref{http://www.skydive.net/competfs/} (Competition Formation Skydiving)
+
+@item @uref{http://www.galaxy-net.net/} (Galaxy-NET Telecommunications; E-commerce and internal accounting)
+
+@item @uref{http://www.borsen.dk/} (Denmark's leading business daily newspaper B@o{}rsen)
+
+@item @uref{http://tmmm.simplenet.com/indb/} (The Internet NES Database)
+
+@item @uref{http://www.russia.cz/} (Travel agency in Prague in 3 languages)
+
+@item @uref{http://www.linkstation.de/} (Linkstation)
+
+@item @uref{http://www.peoplestaff.com/} (Searchable online database at Peoplestaff)
+
+@item @uref{http://www.dreamhorse.com/} (A searchable database system for horse classified ads)
+
+@item @uref{http://pootpoot.com/} (The Poot site)
+
+@item @uref{http://grateful.net/hw_html/} ("Playin' in the LAN"; a network monitoring suite)
+
+@c Update from Christopher Milton <cmilton@bwn.net> 1999-12-21
+@item @uref{http://www.usapa.army.mil/} (U.S. Army Publishing Agency)
+
+@item @uref{http://www.nekretnine.co.yu/} (Realestate handling in Yugoslavia)
+
+@item @uref{http://demo.cpsoft.com/pims/devFAQ.html} (PIMS; a Patient Information Management System)
+
+@item @uref{http://cpsoft.com/} (Pilkington Software Inc)
+
+@item @uref{http://www.no-quarter.org/} (A Vietnam Veteran's Memorial - The Wall - database)
+
+@item @uref{http://www.gamers-union.com/} (Gamer's Union specializes in auctions of used & out-of-print gaming material)
+
+@item @uref{http://www.montereyhigh.com/office/dbul.php3} (A daily bulletin at Monterey High school)
+
+@item @uref{http://www.myEastside.com/} (Community-owned site serving Lake
+Washington's Eastside residents and businesses)
+
+@item @uref{http://bowling-france.net/} (French bowling site)
+@end itemize
+
+Send any additions to this list to @email{webmaster@@mysql.com}.
+
+@page
+
+
+
+
diff --git a/Docs/template.texi b/Docs/template.texi
new file mode 100644
index 00000000000..36633da6269
--- /dev/null
+++ b/Docs/template.texi
@@ -0,0 +1,522 @@
+\input texinfo @c -*-texinfo-*-
+@c Copyright 1995-2002 MySQL AB
+@c
+@c This manual is NOT distributed under a GPL style license.
+@c Use of the manual is subject to the following terms:
+@c - Conversion to other formats is allowed, but the actual
+@c content may not be altered or edited in any way.
+@c - You may create a printed copy for your own personal use.
+@c - For all other uses, such as selling printed copies or
+@c using (parts of) the manual in another publication,
+@c prior written agreement from MySQL AB is required.
+@c
+@c Please e-mail docs@mysql.com for more information or if
+@c you are interested in doing a translation.
+@c
+@c *********************************************************
+@c
+@c %**start of header
+
+@setfilename mysql.info
+
+@c We want the types in the same index
+@syncodeindex tp fn
+
+@c Get version information. This file is generated by the Makefile!!
+@include include.texi
+
+@ifclear tex-debug
+@c This removes the black squares in the right margin
+@finalout
+@end ifclear
+
+@c Set background for HTML
+@set _body_tags BGCOLOR=silver TEXT=#000000 LINK=#101090 VLINK=#7030B0
+@c Set some style elements for the manual in HTML form. 'suggested'
+@c natural language colors: aqua, black, blue, fuchsia, gray, green,
+@c lime, maroon, navy, olive, purple, red, silver, teal, white, and
+@c yellow. From Steeve Buehler <ahr@YogElements.com>
+@set _extra_head <style> code {color:purple} tt {color:green} samp {color:navy} pre {color:maroon} </style>
+
+@settitle MySQL Reference Manual for version @value{mysql_version}.
+
+@c We want single-sided heading format, with chapters on new pages. To
+@c get double-sided format change 'on' below to 'odd'
+@setchapternewpage on
+
+@paragraphindent 0
+
+@c %**end of header
+
+@ifinfo
+@format
+START-INFO-DIR-ENTRY
+* mysql: (mysql). MySQL documentation.
+END-INFO-DIR-ENTRY
+@end format
+@end ifinfo
+
+@titlepage
+@sp 10
+@center @titlefont{MySQL Reference Manual}
+@sp 10
+@center Copyright @copyright{} 1995-2002 MySQL AB
+@c blank page after title page makes page 1 be a page front.
+@c also makes the back of the title page blank.
+@page
+@end titlepage
+
+@c Short contents, blank page, long contents.
+@c until i can figure out the blank page, no short contents.
+@c @shortcontents
+@c @page
+@c @page
+@contents
+
+@c This should be added. The HTML conversion also needs a MySQL version
+@c number somewhere.
+
+@iftex
+@c change this to double if you want formatting for double-sided
+@c printing
+@headings single
+
+@oddheading @thischapter @| @| @thispage
+@evenheading @thispage @| @| MySQL Technical Reference for Version @value{mysql_version}
+
+@end iftex
+
+
+@node Top, Introduction, (dir), (dir)
+
+@ifinfo
+This is a manual for the MySQL Database System.
+This version is about the @value{mysql_version} version of MySQL Server.
+You can find a specific manual for any older version of MySQL Server
+in the binary or source distribution for that version.
+@end ifinfo
+
+@node Introduction, Installing, Top, Top
+@chapter General Information About MySQL
+
+
+
+
+
+@node GPL license, LGPL license, Regexp, Top
+@appendix GNU GENERAL PUBLIC LICENSE
+
+@cindex GPL, General Public License
+@cindex GPL, GNU General Public License
+
+@center Version 2, June 1991
+
+@display
+Copyright @copyright{} 1989, 1991 Free Software Foundation, Inc.
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+@end display
+
+@appendixsec Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software---to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+@iftex
+@appendixsec TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+@end iftex
+@ifinfo
+@center GNU GENERAL PUBLIC LICENSE
+@center TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+@end ifinfo
+
+@enumerate 0
+@item
+This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The ``Program'', below,
+refers to any such program or work, and a ``work based on the Program''
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term ``modification''.) Each licensee is addressed as ``you''.
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+@item
+You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+@item
+You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+@enumerate a
+@item
+You must cause the modified files to carry prominent notices
+stating that you changed the files and the date of any change.
+
+@item
+You must cause any work that you distribute or publish, that in
+whole or in part contains or is derived from the Program or any
+part thereof, to be licensed as a whole at no charge to all third
+parties under the terms of this License.
+
+@item
+If the modified program normally reads commands interactively
+when run, you must cause it, when started running for such
+interactive use in the most ordinary way, to print or display an
+announcement including an appropriate copyright notice and a
+notice that there is no warranty (or else, saying that you provide
+a warranty) and that users may redistribute the program under
+these conditions, and telling the user how to view a copy of this
+License. (Exception: if the Program itself is interactive but
+does not normally print such an announcement, your work based on
+the Program is not required to print an announcement.)
+@end enumerate
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+@item
+You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+@enumerate a
+@item
+Accompany it with the complete corresponding machine-readable
+source code, which must be distributed under the terms of Sections
+1 and 2 above on a medium customarily used for software interchange; or,
+
+@item
+Accompany it with a written offer, valid for at least three
+years, to give any third party, for a charge no more than your
+cost of physically performing source distribution, a complete
+machine-readable copy of the corresponding source code, to be
+distributed under the terms of Sections 1 and 2 above on a medium
+customarily used for software interchange; or,
+
+@item
+Accompany it with the information you received as to the offer
+to distribute corresponding source code. (This alternative is
+allowed only for noncommercial distribution and only if you
+received the program in object code or executable form with such
+an offer, in accord with Subsection b above.)
+@end enumerate
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+@item
+You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+@item
+You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+@item
+Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+@item
+If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+@item
+If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+@item
+The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and ``any
+later version'', you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+@item
+If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+@iftex
+@heading NO WARRANTY
+@end iftex
+@ifinfo
+@center NO WARRANTY
+@end ifinfo
+
+@item
+BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM ``AS IS'' WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+@item
+IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+@end enumerate
+
+@iftex
+@heading END OF TERMS AND CONDITIONS
+@end iftex
+@ifinfo
+@center END OF TERMS AND CONDITIONS
+@end ifinfo
+
+@page
+@appendixsec How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the ``copyright'' line and a pointer to where the full notice is found.
+
+@smallexample
+@var{one line to give the program's name and a brief idea of what it does.}
+Copyright (C) @var{yyyy} @var{name of author}
+
+This program is free software; 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.
+@end smallexample
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+@smallexample
+Gnomovision version 69, Copyright (C) 19@var{yy} @var{name of author}
+Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+This is free software, and you are welcome to redistribute it
+under certain conditions; type `show c' for details.
+@end smallexample
+
+The hypothetical commands @samp{show w} and @samp{show c} should show
+the appropriate parts of the General Public License. Of course, the
+commands you use may be called something other than @samp{show w} and
+@samp{show c}; they could even be mouse-clicks or menu items---whatever
+suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a ``copyright disclaimer'' for the program, if
+necessary. Here is a sample; alter the names:
+
+@example
+Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+`Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+@var{signature of Ty Coon}, 1 April 1989
+Ty Coon, President of Vice
+@end example
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
+
+
+@node Function Index, Concept Index, LGPL license, Top
+@unnumbered SQL command, type and function index
+
+@printindex fn
+
+@page
+
+
+@node Concept Index, , Function Index, Top
+@unnumbered Concept Index
+
+@printindex cp
+
+
+
+
+
+@bye
+
diff --git a/Docs/world.sql b/Docs/world.sql
new file mode 100644
index 00000000000..7ddd3787ec6
--- /dev/null
+++ b/Docs/world.sql
@@ -0,0 +1,5386 @@
+-- MySQL dump 8.19
+--
+-- Host: localhost Database: world
+---------------------------------------------------------
+-- Server version 4.0.1-alpha-Max
+
+--
+-- Table structure for table 'City'
+--
+
+CREATE TABLE City (
+ ID int(11) NOT NULL auto_increment,
+ name char(35) NOT NULL default '',
+ Country char(3) NOT NULL default '',
+ District char(20) NOT NULL default '',
+ Population int(11) NOT NULL default '0',
+ PRIMARY KEY (ID)
+) TYPE=MyISAM;
+
+/*!40000 ALTER TABLE City DISABLE KEYS */;
+
+--
+-- Dumping data for table 'City'
+--
+
+
+INSERT INTO City VALUES (1,'Kabul','AFG','Kabol',1780000);
+INSERT INTO City VALUES (2,'Qandahar','AFG','Qandahar',237500);
+INSERT INTO City VALUES (3,'Herat','AFG','Herat',186800);
+INSERT INTO City VALUES (4,'Mazar-e-Sharif','AFG','Balkh',127800);
+INSERT INTO City VALUES (5,'Amsterdam','NLD','Noord-Holland',731200);
+INSERT INTO City VALUES (6,'Rotterdam','NLD','Zuid-Holland',593321);
+INSERT INTO City VALUES (7,'Haag','NLD','Zuid-Holland',440900);
+INSERT INTO City VALUES (8,'Utrecht','NLD','Utrecht',234323);
+INSERT INTO City VALUES (9,'Eindhoven','NLD','Noord-Brabant',201843);
+INSERT INTO City VALUES (10,'Tilburg','NLD','Noord-Brabant',193238);
+INSERT INTO City VALUES (11,'Groningen','NLD','Groningen',172701);
+INSERT INTO City VALUES (12,'Breda','NLD','Noord-Brabant',160398);
+INSERT INTO City VALUES (13,'Apeldoorn','NLD','Gelderland',153491);
+INSERT INTO City VALUES (14,'Nijmegen','NLD','Gelderland',152463);
+INSERT INTO City VALUES (15,'Enschede','NLD','Overijssel',149544);
+INSERT INTO City VALUES (16,'Haarlem','NLD','Noord-Holland',148772);
+INSERT INTO City VALUES (17,'Almere','NLD','Flevoland',142465);
+INSERT INTO City VALUES (18,'Arnhem','NLD','Gelderland',138020);
+INSERT INTO City VALUES (19,'Zaanstad','NLD','Noord-Holland',135621);
+INSERT INTO City VALUES (20,'´s-Hertogenbosch','NLD','Noord-Brabant',129170);
+INSERT INTO City VALUES (21,'Amersfoort','NLD','Utrecht',126270);
+INSERT INTO City VALUES (22,'Maastricht','NLD','Limburg',122087);
+INSERT INTO City VALUES (23,'Dordrecht','NLD','Zuid-Holland',119811);
+INSERT INTO City VALUES (24,'Leiden','NLD','Zuid-Holland',117196);
+INSERT INTO City VALUES (25,'Haarlemmermeer','NLD','Noord-Holland',110722);
+INSERT INTO City VALUES (26,'Zoetermeer','NLD','Zuid-Holland',110214);
+INSERT INTO City VALUES (27,'Emmen','NLD','Drenthe',105853);
+INSERT INTO City VALUES (28,'Zwolle','NLD','Overijssel',105819);
+INSERT INTO City VALUES (29,'Ede','NLD','Gelderland',101574);
+INSERT INTO City VALUES (30,'Delft','NLD','Zuid-Holland',95268);
+INSERT INTO City VALUES (31,'Heerlen','NLD','Limburg',95052);
+INSERT INTO City VALUES (32,'Alkmaar','NLD','Noord-Holland',92713);
+INSERT INTO City VALUES (33,'Willemstad','ANT','Curaçao',2345);
+INSERT INTO City VALUES (34,'Tirana','ALB','Tirana',270000);
+INSERT INTO City VALUES (35,'Alger','DZA','Alger',2168000);
+INSERT INTO City VALUES (36,'Oran','DZA','Oran',609823);
+INSERT INTO City VALUES (37,'Constantine','DZA','Constantine',443727);
+INSERT INTO City VALUES (38,'Annaba','DZA','Annaba',222518);
+INSERT INTO City VALUES (39,'Batna','DZA','Batna',183377);
+INSERT INTO City VALUES (40,'Sétif','DZA','Sétif',179055);
+INSERT INTO City VALUES (41,'Sidi Bel Abbès','DZA','Sidi Bel Abbès',153106);
+INSERT INTO City VALUES (42,'Skikda','DZA','Skikda',128747);
+INSERT INTO City VALUES (43,'Biskra','DZA','Biskra',128281);
+INSERT INTO City VALUES (44,'Blida (el-Boulaida)','DZA','Blida',127284);
+INSERT INTO City VALUES (45,'Béjaïa','DZA','Béjaïa',117162);
+INSERT INTO City VALUES (46,'Mostaganem','DZA','Mostaganem',115212);
+INSERT INTO City VALUES (47,'Tébessa','DZA','Tébessa',112007);
+INSERT INTO City VALUES (48,'Tlemcen (Tilimsen)','DZA','Tlemcen',110242);
+INSERT INTO City VALUES (49,'Béchar','DZA','Béchar',107311);
+INSERT INTO City VALUES (50,'Tiaret','DZA','Tiaret',100118);
+INSERT INTO City VALUES (51,'Ech-Chleff (el-Asnam)','DZA','Chlef',96794);
+INSERT INTO City VALUES (52,'Ghardaïa','DZA','Ghardaïa',89415);
+INSERT INTO City VALUES (53,'Tafuna','ASM','Tutuila',5200);
+INSERT INTO City VALUES (54,'Fagatogo','ASM','Tutuila',2323);
+INSERT INTO City VALUES (55,'Andorra la Vella','AND','Andorra la Vella',21189);
+INSERT INTO City VALUES (56,'Luanda','AGO','Luanda',2022000);
+INSERT INTO City VALUES (57,'Huambo','AGO','Huambo',163100);
+INSERT INTO City VALUES (58,'Lobito','AGO','Benguela',130000);
+INSERT INTO City VALUES (59,'Benguela','AGO','Benguela',128300);
+INSERT INTO City VALUES (60,'Namibe','AGO','Namibe',118200);
+INSERT INTO City VALUES (61,'South Hill','AIA','–',961);
+INSERT INTO City VALUES (62,'The Valley','AIA','–',595);
+INSERT INTO City VALUES (63,'Saint John´s','ATG','St John',24000);
+INSERT INTO City VALUES (64,'Dubai','ARE','Dubai',669181);
+INSERT INTO City VALUES (65,'Abu Dhabi','ARE','Abu Dhabi',398695);
+INSERT INTO City VALUES (66,'Sharja','ARE','Sharja',320095);
+INSERT INTO City VALUES (67,'al-Ayn','ARE','Abu Dhabi',225970);
+INSERT INTO City VALUES (68,'Ajman','ARE','Ajman',114395);
+INSERT INTO City VALUES (69,'Buenos Aires','ARG','Distrito Federal',2982146);
+INSERT INTO City VALUES (70,'La Matanza','ARG','Buenos Aires',1266461);
+INSERT INTO City VALUES (71,'Córdoba','ARG','Córdoba',1157507);
+INSERT INTO City VALUES (72,'Rosario','ARG','Santa Fé',907718);
+INSERT INTO City VALUES (73,'Lomas de Zamora','ARG','Buenos Aires',622013);
+INSERT INTO City VALUES (74,'Quilmes','ARG','Buenos Aires',559249);
+INSERT INTO City VALUES (75,'Almirante Brown','ARG','Buenos Aires',538918);
+INSERT INTO City VALUES (76,'La Plata','ARG','Buenos Aires',521936);
+INSERT INTO City VALUES (77,'Mar del Plata','ARG','Buenos Aires',512880);
+INSERT INTO City VALUES (78,'San Miguel de Tucumán','ARG','Tucumán',470809);
+INSERT INTO City VALUES (79,'Lanús','ARG','Buenos Aires',469735);
+INSERT INTO City VALUES (80,'Merlo','ARG','Buenos Aires',463846);
+INSERT INTO City VALUES (81,'General San Martín','ARG','Buenos Aires',422542);
+INSERT INTO City VALUES (82,'Salta','ARG','Salta',367550);
+INSERT INTO City VALUES (83,'Moreno','ARG','Buenos Aires',356993);
+INSERT INTO City VALUES (84,'Santa Fé','ARG','Santa Fé',353063);
+INSERT INTO City VALUES (85,'Avellaneda','ARG','Buenos Aires',353046);
+INSERT INTO City VALUES (86,'Tres de Febrero','ARG','Buenos Aires',352311);
+INSERT INTO City VALUES (87,'Morón','ARG','Buenos Aires',349246);
+INSERT INTO City VALUES (88,'Florencio Varela','ARG','Buenos Aires',315432);
+INSERT INTO City VALUES (89,'San Isidro','ARG','Buenos Aires',306341);
+INSERT INTO City VALUES (90,'Tigre','ARG','Buenos Aires',296226);
+INSERT INTO City VALUES (91,'Malvinas Argentinas','ARG','Buenos Aires',290335);
+INSERT INTO City VALUES (92,'Vicente López','ARG','Buenos Aires',288341);
+INSERT INTO City VALUES (93,'Berazategui','ARG','Buenos Aires',276916);
+INSERT INTO City VALUES (94,'Corrientes','ARG','Corrientes',258103);
+INSERT INTO City VALUES (95,'San Miguel','ARG','Buenos Aires',248700);
+INSERT INTO City VALUES (96,'Bahía Blanca','ARG','Buenos Aires',239810);
+INSERT INTO City VALUES (97,'Esteban Echeverría','ARG','Buenos Aires',235760);
+INSERT INTO City VALUES (98,'Resistencia','ARG','Chaco',229212);
+INSERT INTO City VALUES (99,'José C. Paz','ARG','Buenos Aires',221754);
+INSERT INTO City VALUES (100,'Paraná','ARG','Entre Rios',207041);
+INSERT INTO City VALUES (101,'Godoy Cruz','ARG','Mendoza',206998);
+INSERT INTO City VALUES (102,'Posadas','ARG','Misiones',201273);
+INSERT INTO City VALUES (103,'Guaymallén','ARG','Mendoza',200595);
+INSERT INTO City VALUES (104,'Santiago del Estero','ARG','Santiago del Estero',189947);
+INSERT INTO City VALUES (105,'San Salvador de Jujuy','ARG','Jujuy',178748);
+INSERT INTO City VALUES (106,'Hurlingham','ARG','Buenos Aires',170028);
+INSERT INTO City VALUES (107,'Neuquén','ARG','Neuquén',167296);
+INSERT INTO City VALUES (108,'Ituzaingó','ARG','Buenos Aires',158197);
+INSERT INTO City VALUES (109,'San Fernando','ARG','Buenos Aires',153036);
+INSERT INTO City VALUES (110,'Formosa','ARG','Formosa',147636);
+INSERT INTO City VALUES (111,'Las Heras','ARG','Mendoza',145823);
+INSERT INTO City VALUES (112,'La Rioja','ARG','La Rioja',138117);
+INSERT INTO City VALUES (113,'San Fernando del Valle de Cata','ARG','Catamarca',134935);
+INSERT INTO City VALUES (114,'Río Cuarto','ARG','Córdoba',134355);
+INSERT INTO City VALUES (115,'Comodoro Rivadavia','ARG','Chubut',124104);
+INSERT INTO City VALUES (116,'Mendoza','ARG','Mendoza',123027);
+INSERT INTO City VALUES (117,'San Nicolás de los Arroyos','ARG','Buenos Aires',119302);
+INSERT INTO City VALUES (118,'San Juan','ARG','San Juan',119152);
+INSERT INTO City VALUES (119,'Escobar','ARG','Buenos Aires',116675);
+INSERT INTO City VALUES (120,'Concordia','ARG','Entre Rios',116485);
+INSERT INTO City VALUES (121,'Pilar','ARG','Buenos Aires',113428);
+INSERT INTO City VALUES (122,'San Luis','ARG','San Luis',110136);
+INSERT INTO City VALUES (123,'Ezeiza','ARG','Buenos Aires',99578);
+INSERT INTO City VALUES (124,'San Rafael','ARG','Mendoza',94651);
+INSERT INTO City VALUES (125,'Tandil','ARG','Buenos Aires',91101);
+INSERT INTO City VALUES (126,'Yerevan','ARM','Yerevan',1248700);
+INSERT INTO City VALUES (127,'Gjumri','ARM','Širak',211700);
+INSERT INTO City VALUES (128,'Vanadzor','ARM','Lori',172700);
+INSERT INTO City VALUES (129,'Oranjestad','ABW','–',29034);
+INSERT INTO City VALUES (130,'Sydney','AUS','New South Wales',3276207);
+INSERT INTO City VALUES (131,'Melbourne','AUS','Victoria',2865329);
+INSERT INTO City VALUES (132,'Brisbane','AUS','Queensland',1291117);
+INSERT INTO City VALUES (133,'Perth','AUS','West Australia',1096829);
+INSERT INTO City VALUES (134,'Adelaide','AUS','South Australia',978100);
+INSERT INTO City VALUES (135,'Canberra','AUS','Capital Region',322723);
+INSERT INTO City VALUES (136,'Gold Coast','AUS','Queensland',311932);
+INSERT INTO City VALUES (137,'Newcastle','AUS','New South Wales',270324);
+INSERT INTO City VALUES (138,'Central Coast','AUS','New South Wales',227657);
+INSERT INTO City VALUES (139,'Wollongong','AUS','New South Wales',219761);
+INSERT INTO City VALUES (140,'Hobart','AUS','Tasmania',126118);
+INSERT INTO City VALUES (141,'Geelong','AUS','Victoria',125382);
+INSERT INTO City VALUES (142,'Townsville','AUS','Queensland',109914);
+INSERT INTO City VALUES (143,'Cairns','AUS','Queensland',92273);
+INSERT INTO City VALUES (144,'Baku','AZE','Baki',1787800);
+INSERT INTO City VALUES (145,'Gäncä','AZE','Gäncä',299300);
+INSERT INTO City VALUES (146,'Sumqayit','AZE','Sumqayit',283000);
+INSERT INTO City VALUES (147,'Mingäçevir','AZE','Mingäçevir',93900);
+INSERT INTO City VALUES (148,'Nassau','BHS','New Providence',172000);
+INSERT INTO City VALUES (149,'al-Manama','BHR','al-Manama',148000);
+INSERT INTO City VALUES (150,'Dhaka','BGD','Dhaka',3612850);
+INSERT INTO City VALUES (151,'Chittagong','BGD','Chittagong',1392860);
+INSERT INTO City VALUES (152,'Khulna','BGD','Khulna',663340);
+INSERT INTO City VALUES (153,'Rajshahi','BGD','Rajshahi',294056);
+INSERT INTO City VALUES (154,'Narayanganj','BGD','Dhaka',202134);
+INSERT INTO City VALUES (155,'Rangpur','BGD','Rajshahi',191398);
+INSERT INTO City VALUES (156,'Mymensingh','BGD','Dhaka',188713);
+INSERT INTO City VALUES (157,'Barisal','BGD','Barisal',170232);
+INSERT INTO City VALUES (158,'Tungi','BGD','Dhaka',168702);
+INSERT INTO City VALUES (159,'Jessore','BGD','Khulna',139710);
+INSERT INTO City VALUES (160,'Comilla','BGD','Chittagong',135313);
+INSERT INTO City VALUES (161,'Nawabganj','BGD','Rajshahi',130577);
+INSERT INTO City VALUES (162,'Dinajpur','BGD','Rajshahi',127815);
+INSERT INTO City VALUES (163,'Bogra','BGD','Rajshahi',120170);
+INSERT INTO City VALUES (164,'Sylhet','BGD','Sylhet',117396);
+INSERT INTO City VALUES (165,'Brahmanbaria','BGD','Chittagong',109032);
+INSERT INTO City VALUES (166,'Tangail','BGD','Dhaka',106004);
+INSERT INTO City VALUES (167,'Jamalpur','BGD','Dhaka',103556);
+INSERT INTO City VALUES (168,'Pabna','BGD','Rajshahi',103277);
+INSERT INTO City VALUES (169,'Naogaon','BGD','Rajshahi',101266);
+INSERT INTO City VALUES (170,'Sirajganj','BGD','Rajshahi',99669);
+INSERT INTO City VALUES (171,'Narsinghdi','BGD','Dhaka',98342);
+INSERT INTO City VALUES (172,'Saidpur','BGD','Rajshahi',96777);
+INSERT INTO City VALUES (173,'Gazipur','BGD','Dhaka',96717);
+INSERT INTO City VALUES (174,'Bridgetown','BRB','St Michael',6070);
+INSERT INTO City VALUES (175,'Antwerpen','BEL','Antwerpen',446525);
+INSERT INTO City VALUES (176,'Gent','BEL','East Flanderi',224180);
+INSERT INTO City VALUES (177,'Charleroi','BEL','Hainaut',200827);
+INSERT INTO City VALUES (178,'Liège','BEL','Liège',185639);
+INSERT INTO City VALUES (179,'Bruxelles [Brussel]','BEL','Bryssel',133859);
+INSERT INTO City VALUES (180,'Brugge','BEL','West Flanderi',116246);
+INSERT INTO City VALUES (181,'Schaerbeek','BEL','Bryssel',105692);
+INSERT INTO City VALUES (182,'Namur','BEL','Namur',105419);
+INSERT INTO City VALUES (183,'Mons','BEL','Hainaut',90935);
+INSERT INTO City VALUES (184,'Belize City','BLZ','Belize City',55810);
+INSERT INTO City VALUES (185,'Belmopan','BLZ','Cayo',7105);
+INSERT INTO City VALUES (186,'Cotonou','BEN','Atlantique',536827);
+INSERT INTO City VALUES (187,'Porto-Novo','BEN','Ouémé',194000);
+INSERT INTO City VALUES (188,'Djougou','BEN','Atacora',134099);
+INSERT INTO City VALUES (189,'Parakou','BEN','Borgou',103577);
+INSERT INTO City VALUES (190,'Saint George','BMU','Saint George´s',1800);
+INSERT INTO City VALUES (191,'Hamilton','BMU','Hamilton',1200);
+INSERT INTO City VALUES (192,'Thimphu','BTN','Thimphu',22000);
+INSERT INTO City VALUES (193,'Santa Cruz de la Sierra','BOL','Santa Cruz',935361);
+INSERT INTO City VALUES (194,'La Paz','BOL','La Paz',758141);
+INSERT INTO City VALUES (195,'El Alto','BOL','La Paz',534466);
+INSERT INTO City VALUES (196,'Cochabamba','BOL','Cochabamba',482800);
+INSERT INTO City VALUES (197,'Oruro','BOL','Oruro',223553);
+INSERT INTO City VALUES (198,'Sucre','BOL','Chuquisaca',178426);
+INSERT INTO City VALUES (199,'Potosí','BOL','Potosí',140642);
+INSERT INTO City VALUES (200,'Tarija','BOL','Tarija',125255);
+INSERT INTO City VALUES (201,'Sarajevo','BIH','Federaatio',360000);
+INSERT INTO City VALUES (202,'Banja Luka','BIH','Republika Srpska',143079);
+INSERT INTO City VALUES (203,'Zenica','BIH','Federaatio',96027);
+INSERT INTO City VALUES (204,'Gaborone','BWA','Gaborone',213017);
+INSERT INTO City VALUES (205,'Francistown','BWA','Francistown',101805);
+INSERT INTO City VALUES (206,'São Paulo','BRA','São Paulo',9968485);
+INSERT INTO City VALUES (207,'Rio de Janeiro','BRA','Rio de Janeiro',5598953);
+INSERT INTO City VALUES (208,'Salvador','BRA','Bahia',2302832);
+INSERT INTO City VALUES (209,'Belo Horizonte','BRA','Minas Gerais',2139125);
+INSERT INTO City VALUES (210,'Fortaleza','BRA','Ceará',2097757);
+INSERT INTO City VALUES (211,'Brasília','BRA','Distrito Federal',1969868);
+INSERT INTO City VALUES (212,'Curitiba','BRA','Paraná',1584232);
+INSERT INTO City VALUES (213,'Recife','BRA','Pernambuco',1378087);
+INSERT INTO City VALUES (214,'Porto Alegre','BRA','Rio Grande do Sul',1314032);
+INSERT INTO City VALUES (215,'Manaus','BRA','Amazonas',1255049);
+INSERT INTO City VALUES (216,'Belém','BRA','Pará',1186926);
+INSERT INTO City VALUES (217,'Guarulhos','BRA','São Paulo',1095874);
+INSERT INTO City VALUES (218,'Goiânia','BRA','Goiás',1056330);
+INSERT INTO City VALUES (219,'Campinas','BRA','São Paulo',950043);
+INSERT INTO City VALUES (220,'São Gonçalo','BRA','Rio de Janeiro',869254);
+INSERT INTO City VALUES (221,'Nova Iguaçu','BRA','Rio de Janeiro',862225);
+INSERT INTO City VALUES (222,'São Luís','BRA','Maranhão',837588);
+INSERT INTO City VALUES (223,'Maceió','BRA','Alagoas',786288);
+INSERT INTO City VALUES (224,'Duque de Caxias','BRA','Rio de Janeiro',746758);
+INSERT INTO City VALUES (225,'São Bernardo do Campo','BRA','São Paulo',723132);
+INSERT INTO City VALUES (226,'Teresina','BRA','Piauí',691942);
+INSERT INTO City VALUES (227,'Natal','BRA','Rio Grande do Norte',688955);
+INSERT INTO City VALUES (228,'Osasco','BRA','São Paulo',659604);
+INSERT INTO City VALUES (229,'Campo Grande','BRA','Mato Grosso do Sul',649593);
+INSERT INTO City VALUES (230,'Santo André','BRA','São Paulo',630073);
+INSERT INTO City VALUES (231,'João Pessoa','BRA','Paraíba',584029);
+INSERT INTO City VALUES (232,'Jaboatão dos Guararapes','BRA','Pernambuco',558680);
+INSERT INTO City VALUES (233,'Contagem','BRA','Minas Gerais',520801);
+INSERT INTO City VALUES (234,'São José dos Campos','BRA','São Paulo',515553);
+INSERT INTO City VALUES (235,'Uberlândia','BRA','Minas Gerais',487222);
+INSERT INTO City VALUES (236,'Feira de Santana','BRA','Bahia',479992);
+INSERT INTO City VALUES (237,'Ribeirão Preto','BRA','São Paulo',473276);
+INSERT INTO City VALUES (238,'Sorocaba','BRA','São Paulo',466823);
+INSERT INTO City VALUES (239,'Niterói','BRA','Rio de Janeiro',459884);
+INSERT INTO City VALUES (240,'Cuiabá','BRA','Mato Grosso',453813);
+INSERT INTO City VALUES (241,'Juiz de Fora','BRA','Minas Gerais',450288);
+INSERT INTO City VALUES (242,'Aracaju','BRA','Sergipe',445555);
+INSERT INTO City VALUES (243,'São João de Meriti','BRA','Rio de Janeiro',440052);
+INSERT INTO City VALUES (244,'Londrina','BRA','Paraná',432257);
+INSERT INTO City VALUES (245,'Joinville','BRA','Santa Catarina',428011);
+INSERT INTO City VALUES (246,'Belford Roxo','BRA','Rio de Janeiro',425194);
+INSERT INTO City VALUES (247,'Santos','BRA','São Paulo',408748);
+INSERT INTO City VALUES (248,'Ananindeua','BRA','Pará',400940);
+INSERT INTO City VALUES (249,'Campos dos Goytacazes','BRA','Rio de Janeiro',398418);
+INSERT INTO City VALUES (250,'Mauá','BRA','São Paulo',375055);
+INSERT INTO City VALUES (251,'Carapicuíba','BRA','São Paulo',357552);
+INSERT INTO City VALUES (252,'Olinda','BRA','Pernambuco',354732);
+INSERT INTO City VALUES (253,'Campina Grande','BRA','Paraíba',352497);
+INSERT INTO City VALUES (254,'São José do Rio Preto','BRA','São Paulo',351944);
+INSERT INTO City VALUES (255,'Caxias do Sul','BRA','Rio Grande do Sul',349581);
+INSERT INTO City VALUES (256,'Moji das Cruzes','BRA','São Paulo',339194);
+INSERT INTO City VALUES (257,'Diadema','BRA','São Paulo',335078);
+INSERT INTO City VALUES (258,'Aparecida de Goiânia','BRA','Goiás',324662);
+INSERT INTO City VALUES (259,'Piracicaba','BRA','São Paulo',319104);
+INSERT INTO City VALUES (260,'Cariacica','BRA','Espírito Santo',319033);
+INSERT INTO City VALUES (261,'Vila Velha','BRA','Espírito Santo',318758);
+INSERT INTO City VALUES (262,'Pelotas','BRA','Rio Grande do Sul',315415);
+INSERT INTO City VALUES (263,'Bauru','BRA','São Paulo',313670);
+INSERT INTO City VALUES (264,'Porto Velho','BRA','Rondônia',309750);
+INSERT INTO City VALUES (265,'Serra','BRA','Espírito Santo',302666);
+INSERT INTO City VALUES (266,'Betim','BRA','Minas Gerais',302108);
+INSERT INTO City VALUES (267,'Jundíaí','BRA','São Paulo',296127);
+INSERT INTO City VALUES (268,'Canoas','BRA','Rio Grande do Sul',294125);
+INSERT INTO City VALUES (269,'Franca','BRA','São Paulo',290139);
+INSERT INTO City VALUES (270,'São Vicente','BRA','São Paulo',286848);
+INSERT INTO City VALUES (271,'Maringá','BRA','Paraná',286461);
+INSERT INTO City VALUES (272,'Montes Claros','BRA','Minas Gerais',286058);
+INSERT INTO City VALUES (273,'Anápolis','BRA','Goiás',282197);
+INSERT INTO City VALUES (274,'Florianópolis','BRA','Santa Catarina',281928);
+INSERT INTO City VALUES (275,'Petrópolis','BRA','Rio de Janeiro',279183);
+INSERT INTO City VALUES (276,'Itaquaquecetuba','BRA','São Paulo',270874);
+INSERT INTO City VALUES (277,'Vitória','BRA','Espírito Santo',270626);
+INSERT INTO City VALUES (278,'Ponta Grossa','BRA','Paraná',268013);
+INSERT INTO City VALUES (279,'Rio Branco','BRA','Acre',259537);
+INSERT INTO City VALUES (280,'Foz do Iguaçu','BRA','Paraná',259425);
+INSERT INTO City VALUES (281,'Macapá','BRA','Amapá',256033);
+INSERT INTO City VALUES (282,'Ilhéus','BRA','Bahia',254970);
+INSERT INTO City VALUES (283,'Vitória da Conquista','BRA','Bahia',253587);
+INSERT INTO City VALUES (284,'Uberaba','BRA','Minas Gerais',249225);
+INSERT INTO City VALUES (285,'Paulista','BRA','Pernambuco',248473);
+INSERT INTO City VALUES (286,'Limeira','BRA','São Paulo',245497);
+INSERT INTO City VALUES (287,'Blumenau','BRA','Santa Catarina',244379);
+INSERT INTO City VALUES (288,'Caruaru','BRA','Pernambuco',244247);
+INSERT INTO City VALUES (289,'Santarém','BRA','Pará',241771);
+INSERT INTO City VALUES (290,'Volta Redonda','BRA','Rio de Janeiro',240315);
+INSERT INTO City VALUES (291,'Novo Hamburgo','BRA','Rio Grande do Sul',239940);
+INSERT INTO City VALUES (292,'Caucaia','BRA','Ceará',238738);
+INSERT INTO City VALUES (293,'Santa Maria','BRA','Rio Grande do Sul',238473);
+INSERT INTO City VALUES (294,'Cascavel','BRA','Paraná',237510);
+INSERT INTO City VALUES (295,'Guarujá','BRA','São Paulo',237206);
+INSERT INTO City VALUES (296,'Ribeirão das Neves','BRA','Minas Gerais',232685);
+INSERT INTO City VALUES (297,'Governador Valadares','BRA','Minas Gerais',231724);
+INSERT INTO City VALUES (298,'Taubaté','BRA','São Paulo',229130);
+INSERT INTO City VALUES (299,'Imperatriz','BRA','Maranhão',224564);
+INSERT INTO City VALUES (300,'Gravataí','BRA','Rio Grande do Sul',223011);
+INSERT INTO City VALUES (301,'Embu','BRA','São Paulo',222223);
+INSERT INTO City VALUES (302,'Mossoró','BRA','Rio Grande do Norte',214901);
+INSERT INTO City VALUES (303,'Várzea Grande','BRA','Mato Grosso',214435);
+INSERT INTO City VALUES (304,'Petrolina','BRA','Pernambuco',210540);
+INSERT INTO City VALUES (305,'Barueri','BRA','São Paulo',208426);
+INSERT INTO City VALUES (306,'Viamão','BRA','Rio Grande do Sul',207557);
+INSERT INTO City VALUES (307,'Ipatinga','BRA','Minas Gerais',206338);
+INSERT INTO City VALUES (308,'Juazeiro','BRA','Bahia',201073);
+INSERT INTO City VALUES (309,'Juazeiro do Norte','BRA','Ceará',199636);
+INSERT INTO City VALUES (310,'Taboão da Serra','BRA','São Paulo',197550);
+INSERT INTO City VALUES (311,'São José dos Pinhais','BRA','Paraná',196884);
+INSERT INTO City VALUES (312,'Magé','BRA','Rio de Janeiro',196147);
+INSERT INTO City VALUES (313,'Suzano','BRA','São Paulo',195434);
+INSERT INTO City VALUES (314,'São Leopoldo','BRA','Rio Grande do Sul',189258);
+INSERT INTO City VALUES (315,'Marília','BRA','São Paulo',188691);
+INSERT INTO City VALUES (316,'São Carlos','BRA','São Paulo',187122);
+INSERT INTO City VALUES (317,'Sumaré','BRA','São Paulo',186205);
+INSERT INTO City VALUES (318,'Presidente Prudente','BRA','São Paulo',185340);
+INSERT INTO City VALUES (319,'Divinópolis','BRA','Minas Gerais',185047);
+INSERT INTO City VALUES (320,'Sete Lagoas','BRA','Minas Gerais',182984);
+INSERT INTO City VALUES (321,'Rio Grande','BRA','Rio Grande do Sul',182222);
+INSERT INTO City VALUES (322,'Itabuna','BRA','Bahia',182148);
+INSERT INTO City VALUES (323,'Jequié','BRA','Bahia',179128);
+INSERT INTO City VALUES (324,'Arapiraca','BRA','Alagoas',178988);
+INSERT INTO City VALUES (325,'Colombo','BRA','Paraná',177764);
+INSERT INTO City VALUES (326,'Americana','BRA','São Paulo',177409);
+INSERT INTO City VALUES (327,'Alvorada','BRA','Rio Grande do Sul',175574);
+INSERT INTO City VALUES (328,'Araraquara','BRA','São Paulo',174381);
+INSERT INTO City VALUES (329,'Itaboraí','BRA','Rio de Janeiro',173977);
+INSERT INTO City VALUES (330,'Santa Bárbara d´Oeste','BRA','São Paulo',171657);
+INSERT INTO City VALUES (331,'Nova Friburgo','BRA','Rio de Janeiro',170697);
+INSERT INTO City VALUES (332,'Jacareí','BRA','São Paulo',170356);
+INSERT INTO City VALUES (333,'Araçatuba','BRA','São Paulo',169303);
+INSERT INTO City VALUES (334,'Barra Mansa','BRA','Rio de Janeiro',168953);
+INSERT INTO City VALUES (335,'Praia Grande','BRA','São Paulo',168434);
+INSERT INTO City VALUES (336,'Marabá','BRA','Pará',167795);
+INSERT INTO City VALUES (337,'Criciúma','BRA','Santa Catarina',167661);
+INSERT INTO City VALUES (338,'Boa Vista','BRA','Roraima',167185);
+INSERT INTO City VALUES (339,'Passo Fundo','BRA','Rio Grande do Sul',166343);
+INSERT INTO City VALUES (340,'Dourados','BRA','Mato Grosso do Sul',164716);
+INSERT INTO City VALUES (341,'Santa Luzia','BRA','Minas Gerais',164704);
+INSERT INTO City VALUES (342,'Rio Claro','BRA','São Paulo',163551);
+INSERT INTO City VALUES (343,'Maracanaú','BRA','Ceará',162022);
+INSERT INTO City VALUES (344,'Guarapuava','BRA','Paraná',160510);
+INSERT INTO City VALUES (345,'Rondonópolis','BRA','Mato Grosso',155115);
+INSERT INTO City VALUES (346,'São José','BRA','Santa Catarina',155105);
+INSERT INTO City VALUES (347,'Cachoeiro de Itapemirim','BRA','Espírito Santo',155024);
+INSERT INTO City VALUES (348,'Nilópolis','BRA','Rio de Janeiro',153383);
+INSERT INTO City VALUES (349,'Itapevi','BRA','São Paulo',150664);
+INSERT INTO City VALUES (350,'Cabo de Santo Agostinho','BRA','Pernambuco',149964);
+INSERT INTO City VALUES (351,'Camaçari','BRA','Bahia',149146);
+INSERT INTO City VALUES (352,'Sobral','BRA','Ceará',146005);
+INSERT INTO City VALUES (353,'Itajaí','BRA','Santa Catarina',145197);
+INSERT INTO City VALUES (354,'Chapecó','BRA','Santa Catarina',144158);
+INSERT INTO City VALUES (355,'Cotia','BRA','São Paulo',140042);
+INSERT INTO City VALUES (356,'Lages','BRA','Santa Catarina',139570);
+INSERT INTO City VALUES (357,'Ferraz de Vasconcelos','BRA','São Paulo',139283);
+INSERT INTO City VALUES (358,'Indaiatuba','BRA','São Paulo',135968);
+INSERT INTO City VALUES (359,'Hortolândia','BRA','São Paulo',135755);
+INSERT INTO City VALUES (360,'Caxias','BRA','Maranhão',133980);
+INSERT INTO City VALUES (361,'São Caetano do Sul','BRA','São Paulo',133321);
+INSERT INTO City VALUES (362,'Itu','BRA','São Paulo',132736);
+INSERT INTO City VALUES (363,'Nossa Senhora do Socorro','BRA','Sergipe',131351);
+INSERT INTO City VALUES (364,'Parnaíba','BRA','Piauí',129756);
+INSERT INTO City VALUES (365,'Poços de Caldas','BRA','Minas Gerais',129683);
+INSERT INTO City VALUES (366,'Teresópolis','BRA','Rio de Janeiro',128079);
+INSERT INTO City VALUES (367,'Barreiras','BRA','Bahia',127801);
+INSERT INTO City VALUES (368,'Castanhal','BRA','Pará',127634);
+INSERT INTO City VALUES (369,'Alagoinhas','BRA','Bahia',126820);
+INSERT INTO City VALUES (370,'Itapecerica da Serra','BRA','São Paulo',126672);
+INSERT INTO City VALUES (371,'Uruguaiana','BRA','Rio Grande do Sul',126305);
+INSERT INTO City VALUES (372,'Paranaguá','BRA','Paraná',126076);
+INSERT INTO City VALUES (373,'Ibirité','BRA','Minas Gerais',125982);
+INSERT INTO City VALUES (374,'Timon','BRA','Maranhão',125812);
+INSERT INTO City VALUES (375,'Luziânia','BRA','Goiás',125597);
+INSERT INTO City VALUES (376,'Macaé','BRA','Rio de Janeiro',125597);
+INSERT INTO City VALUES (377,'Teófilo Otoni','BRA','Minas Gerais',124489);
+INSERT INTO City VALUES (378,'Moji-Guaçu','BRA','São Paulo',123782);
+INSERT INTO City VALUES (379,'Palmas','BRA','Tocantins',121919);
+INSERT INTO City VALUES (380,'Pindamonhangaba','BRA','São Paulo',121904);
+INSERT INTO City VALUES (381,'Francisco Morato','BRA','São Paulo',121197);
+INSERT INTO City VALUES (382,'Bagé','BRA','Rio Grande do Sul',120793);
+INSERT INTO City VALUES (383,'Sapucaia do Sul','BRA','Rio Grande do Sul',120217);
+INSERT INTO City VALUES (384,'Cabo Frio','BRA','Rio de Janeiro',119503);
+INSERT INTO City VALUES (385,'Itapetininga','BRA','São Paulo',119391);
+INSERT INTO City VALUES (386,'Patos de Minas','BRA','Minas Gerais',119262);
+INSERT INTO City VALUES (387,'Camaragibe','BRA','Pernambuco',118968);
+INSERT INTO City VALUES (388,'Bragança Paulista','BRA','São Paulo',116929);
+INSERT INTO City VALUES (389,'Queimados','BRA','Rio de Janeiro',115020);
+INSERT INTO City VALUES (390,'Araguaína','BRA','Tocantins',114948);
+INSERT INTO City VALUES (391,'Garanhuns','BRA','Pernambuco',114603);
+INSERT INTO City VALUES (392,'Vitória de Santo Antão','BRA','Pernambuco',113595);
+INSERT INTO City VALUES (393,'Santa Rita','BRA','Paraíba',113135);
+INSERT INTO City VALUES (394,'Barbacena','BRA','Minas Gerais',113079);
+INSERT INTO City VALUES (395,'Abaetetuba','BRA','Pará',111258);
+INSERT INTO City VALUES (396,'Jaú','BRA','São Paulo',109965);
+INSERT INTO City VALUES (397,'Lauro de Freitas','BRA','Bahia',109236);
+INSERT INTO City VALUES (398,'Franco da Rocha','BRA','São Paulo',108964);
+INSERT INTO City VALUES (399,'Teixeira de Freitas','BRA','Bahia',108441);
+INSERT INTO City VALUES (400,'Varginha','BRA','Minas Gerais',108314);
+INSERT INTO City VALUES (401,'Ribeirão Pires','BRA','São Paulo',108121);
+INSERT INTO City VALUES (402,'Sabará','BRA','Minas Gerais',107781);
+INSERT INTO City VALUES (403,'Catanduva','BRA','São Paulo',107761);
+INSERT INTO City VALUES (404,'Rio Verde','BRA','Goiás',107755);
+INSERT INTO City VALUES (405,'Botucatu','BRA','São Paulo',107663);
+INSERT INTO City VALUES (406,'Colatina','BRA','Espírito Santo',107354);
+INSERT INTO City VALUES (407,'Santa Cruz do Sul','BRA','Rio Grande do Sul',106734);
+INSERT INTO City VALUES (408,'Linhares','BRA','Espírito Santo',106278);
+INSERT INTO City VALUES (409,'Apucarana','BRA','Paraná',105114);
+INSERT INTO City VALUES (410,'Barretos','BRA','São Paulo',104156);
+INSERT INTO City VALUES (411,'Guaratinguetá','BRA','São Paulo',103433);
+INSERT INTO City VALUES (412,'Cachoeirinha','BRA','Rio Grande do Sul',103240);
+INSERT INTO City VALUES (413,'Codó','BRA','Maranhão',103153);
+INSERT INTO City VALUES (414,'Jaraguá do Sul','BRA','Santa Catarina',102580);
+INSERT INTO City VALUES (415,'Cubatão','BRA','São Paulo',102372);
+INSERT INTO City VALUES (416,'Itabira','BRA','Minas Gerais',102217);
+INSERT INTO City VALUES (417,'Itaituba','BRA','Pará',101320);
+INSERT INTO City VALUES (418,'Araras','BRA','São Paulo',101046);
+INSERT INTO City VALUES (419,'Resende','BRA','Rio de Janeiro',100627);
+INSERT INTO City VALUES (420,'Atibaia','BRA','São Paulo',100356);
+INSERT INTO City VALUES (421,'Pouso Alegre','BRA','Minas Gerais',100028);
+INSERT INTO City VALUES (422,'Toledo','BRA','Paraná',99387);
+INSERT INTO City VALUES (423,'Crato','BRA','Ceará',98965);
+INSERT INTO City VALUES (424,'Passos','BRA','Minas Gerais',98570);
+INSERT INTO City VALUES (425,'Araguari','BRA','Minas Gerais',98399);
+INSERT INTO City VALUES (426,'São José de Ribamar','BRA','Maranhão',98318);
+INSERT INTO City VALUES (427,'Pinhais','BRA','Paraná',98198);
+INSERT INTO City VALUES (428,'Sertãozinho','BRA','São Paulo',98140);
+INSERT INTO City VALUES (429,'Conselheiro Lafaiete','BRA','Minas Gerais',97507);
+INSERT INTO City VALUES (430,'Paulo Afonso','BRA','Bahia',97291);
+INSERT INTO City VALUES (431,'Angra dos Reis','BRA','Rio de Janeiro',96864);
+INSERT INTO City VALUES (432,'Eunápolis','BRA','Bahia',96610);
+INSERT INTO City VALUES (433,'Salto','BRA','São Paulo',96348);
+INSERT INTO City VALUES (434,'Ourinhos','BRA','São Paulo',96291);
+INSERT INTO City VALUES (435,'Parnamirim','BRA','Rio Grande do Norte',96210);
+INSERT INTO City VALUES (436,'Jacobina','BRA','Bahia',96131);
+INSERT INTO City VALUES (437,'Coronel Fabriciano','BRA','Minas Gerais',95933);
+INSERT INTO City VALUES (438,'Birigui','BRA','São Paulo',94685);
+INSERT INTO City VALUES (439,'Tatuí','BRA','São Paulo',93897);
+INSERT INTO City VALUES (440,'Ji-Paraná','BRA','Rondônia',93346);
+INSERT INTO City VALUES (441,'Bacabal','BRA','Maranhão',93121);
+INSERT INTO City VALUES (442,'Cametá','BRA','Pará',92779);
+INSERT INTO City VALUES (443,'Guaíba','BRA','Rio Grande do Sul',92224);
+INSERT INTO City VALUES (444,'São Lourenço da Mata','BRA','Pernambuco',91999);
+INSERT INTO City VALUES (445,'Santana do Livramento','BRA','Rio Grande do Sul',91779);
+INSERT INTO City VALUES (446,'Votorantim','BRA','São Paulo',91777);
+INSERT INTO City VALUES (447,'Campo Largo','BRA','Paraná',91203);
+INSERT INTO City VALUES (448,'Patos','BRA','Paraíba',90519);
+INSERT INTO City VALUES (449,'Ituiutaba','BRA','Minas Gerais',90507);
+INSERT INTO City VALUES (450,'Corumbá','BRA','Mato Grosso do Sul',90111);
+INSERT INTO City VALUES (451,'Palhoça','BRA','Santa Catarina',89465);
+INSERT INTO City VALUES (452,'Barra do Piraí','BRA','Rio de Janeiro',89388);
+INSERT INTO City VALUES (453,'Bento Gonçalves','BRA','Rio Grande do Sul',89254);
+INSERT INTO City VALUES (454,'Poá','BRA','São Paulo',89236);
+INSERT INTO City VALUES (455,'Águas Lindas de Goiás','BRA','Goiás',89200);
+INSERT INTO City VALUES (456,'London','GBR','England',7285000);
+INSERT INTO City VALUES (457,'Birmingham','GBR','England',1013000);
+INSERT INTO City VALUES (458,'Glasgow','GBR','Scotland',619680);
+INSERT INTO City VALUES (459,'Liverpool','GBR','England',461000);
+INSERT INTO City VALUES (460,'Edinburgh','GBR','Scotland',450180);
+INSERT INTO City VALUES (461,'Sheffield','GBR','England',431607);
+INSERT INTO City VALUES (462,'Manchester','GBR','England',430000);
+INSERT INTO City VALUES (463,'Leeds','GBR','England',424194);
+INSERT INTO City VALUES (464,'Bristol','GBR','England',402000);
+INSERT INTO City VALUES (465,'Cardiff','GBR','Wales',321000);
+INSERT INTO City VALUES (466,'Coventry','GBR','England',304000);
+INSERT INTO City VALUES (467,'Leicester','GBR','England',294000);
+INSERT INTO City VALUES (468,'Bradford','GBR','England',289376);
+INSERT INTO City VALUES (469,'Belfast','GBR','North Ireland',287500);
+INSERT INTO City VALUES (470,'Nottingham','GBR','England',287000);
+INSERT INTO City VALUES (471,'Kingston upon Hull','GBR','England',262000);
+INSERT INTO City VALUES (472,'Plymouth','GBR','England',253000);
+INSERT INTO City VALUES (473,'Stoke-on-Trent','GBR','England',252000);
+INSERT INTO City VALUES (474,'Wolverhampton','GBR','England',242000);
+INSERT INTO City VALUES (475,'Derby','GBR','England',236000);
+INSERT INTO City VALUES (476,'Swansea','GBR','Wales',230000);
+INSERT INTO City VALUES (477,'Southampton','GBR','England',216000);
+INSERT INTO City VALUES (478,'Aberdeen','GBR','Scotland',213070);
+INSERT INTO City VALUES (479,'Northampton','GBR','England',196000);
+INSERT INTO City VALUES (480,'Dudley','GBR','England',192171);
+INSERT INTO City VALUES (481,'Portsmouth','GBR','England',190000);
+INSERT INTO City VALUES (482,'Newcastle upon Tyne','GBR','England',189150);
+INSERT INTO City VALUES (483,'Sunderland','GBR','England',183310);
+INSERT INTO City VALUES (484,'Luton','GBR','England',183000);
+INSERT INTO City VALUES (485,'Swindon','GBR','England',180000);
+INSERT INTO City VALUES (486,'Southend-on-Sea','GBR','England',176000);
+INSERT INTO City VALUES (487,'Walsall','GBR','England',174739);
+INSERT INTO City VALUES (488,'Bournemouth','GBR','England',162000);
+INSERT INTO City VALUES (489,'Peterborough','GBR','England',156000);
+INSERT INTO City VALUES (490,'Brighton','GBR','England',156124);
+INSERT INTO City VALUES (491,'Blackpool','GBR','England',151000);
+INSERT INTO City VALUES (492,'Dundee','GBR','Scotland',146690);
+INSERT INTO City VALUES (493,'West Bromwich','GBR','England',146386);
+INSERT INTO City VALUES (494,'Reading','GBR','England',148000);
+INSERT INTO City VALUES (495,'Oldbury/Smethwick (Warley)','GBR','England',145542);
+INSERT INTO City VALUES (496,'Middlesbrough','GBR','England',145000);
+INSERT INTO City VALUES (497,'Huddersfield','GBR','England',143726);
+INSERT INTO City VALUES (498,'Oxford','GBR','England',144000);
+INSERT INTO City VALUES (499,'Poole','GBR','England',141000);
+INSERT INTO City VALUES (500,'Bolton','GBR','England',139020);
+INSERT INTO City VALUES (501,'Blackburn','GBR','England',140000);
+INSERT INTO City VALUES (502,'Newport','GBR','Wales',139000);
+INSERT INTO City VALUES (503,'Preston','GBR','England',135000);
+INSERT INTO City VALUES (504,'Stockport','GBR','England',132813);
+INSERT INTO City VALUES (505,'Norwich','GBR','England',124000);
+INSERT INTO City VALUES (506,'Rotherham','GBR','England',121380);
+INSERT INTO City VALUES (507,'Cambridge','GBR','England',121000);
+INSERT INTO City VALUES (508,'Watford','GBR','England',113080);
+INSERT INTO City VALUES (509,'Ipswich','GBR','England',114000);
+INSERT INTO City VALUES (510,'Slough','GBR','England',112000);
+INSERT INTO City VALUES (511,'Exeter','GBR','England',111000);
+INSERT INTO City VALUES (512,'Cheltenham','GBR','England',106000);
+INSERT INTO City VALUES (513,'Gloucester','GBR','England',107000);
+INSERT INTO City VALUES (514,'Saint Helens','GBR','England',106293);
+INSERT INTO City VALUES (515,'Sutton Coldfield','GBR','England',106001);
+INSERT INTO City VALUES (516,'York','GBR','England',104425);
+INSERT INTO City VALUES (517,'Oldham','GBR','England',103931);
+INSERT INTO City VALUES (518,'Basildon','GBR','England',100924);
+INSERT INTO City VALUES (519,'Worthing','GBR','England',100000);
+INSERT INTO City VALUES (520,'Chelmsford','GBR','England',97451);
+INSERT INTO City VALUES (521,'Colchester','GBR','England',96063);
+INSERT INTO City VALUES (522,'Crawley','GBR','England',97000);
+INSERT INTO City VALUES (523,'Gillingham','GBR','England',92000);
+INSERT INTO City VALUES (524,'Solihull','GBR','England',94531);
+INSERT INTO City VALUES (525,'Rochdale','GBR','England',94313);
+INSERT INTO City VALUES (526,'Birkenhead','GBR','England',93087);
+INSERT INTO City VALUES (527,'Worcester','GBR','England',95000);
+INSERT INTO City VALUES (528,'Hartlepool','GBR','England',92000);
+INSERT INTO City VALUES (529,'Halifax','GBR','England',91069);
+INSERT INTO City VALUES (530,'Woking/Byfleet','GBR','England',92000);
+INSERT INTO City VALUES (531,'Southport','GBR','England',90959);
+INSERT INTO City VALUES (532,'Maidstone','GBR','England',90878);
+INSERT INTO City VALUES (533,'Eastbourne','GBR','England',90000);
+INSERT INTO City VALUES (534,'Grimsby','GBR','England',89000);
+INSERT INTO City VALUES (535,'Saint Helier','GBR','Jersey',27523);
+INSERT INTO City VALUES (536,'Douglas','GBR','–',23487);
+INSERT INTO City VALUES (537,'Road Town','VGB','Tortola',8000);
+INSERT INTO City VALUES (538,'Bandar Seri Begawan','BRN','Brunei and Muara',21484);
+INSERT INTO City VALUES (539,'Sofija','BGR','Grad Sofija',1122302);
+INSERT INTO City VALUES (540,'Plovdiv','BGR','Plovdiv',342584);
+INSERT INTO City VALUES (541,'Varna','BGR','Varna',299801);
+INSERT INTO City VALUES (542,'Burgas','BGR','Burgas',195255);
+INSERT INTO City VALUES (543,'Ruse','BGR','Ruse',166467);
+INSERT INTO City VALUES (544,'Stara Zagora','BGR','Haskovo',147939);
+INSERT INTO City VALUES (545,'Pleven','BGR','Lovec',121952);
+INSERT INTO City VALUES (546,'Sliven','BGR','Burgas',105530);
+INSERT INTO City VALUES (547,'Dobric','BGR','Varna',100399);
+INSERT INTO City VALUES (548,'Šumen','BGR','Varna',94686);
+INSERT INTO City VALUES (549,'Ouagadougou','BFA','Kadiogo',824000);
+INSERT INTO City VALUES (550,'Bobo-Dioulasso','BFA','Houet',300000);
+INSERT INTO City VALUES (551,'Koudougou','BFA','Boulkiemdé',105000);
+INSERT INTO City VALUES (552,'Bujumbura','BDI','Bujumbura',300000);
+INSERT INTO City VALUES (553,'George Town','CYM','Grand Cayman',19600);
+INSERT INTO City VALUES (554,'Santiago de Chile','CHL','Santiago',4703954);
+INSERT INTO City VALUES (555,'Puente Alto','CHL','Santiago',386236);
+INSERT INTO City VALUES (556,'Viña del Mar','CHL','Valparaíso',312493);
+INSERT INTO City VALUES (557,'Valparaíso','CHL','Valparaíso',293800);
+INSERT INTO City VALUES (558,'Talcahuano','CHL','Bíobío',277752);
+INSERT INTO City VALUES (559,'Antofagasta','CHL','Antofagasta',251429);
+INSERT INTO City VALUES (560,'San Bernardo','CHL','Santiago',241910);
+INSERT INTO City VALUES (561,'Temuco','CHL','La Araucanía',233041);
+INSERT INTO City VALUES (562,'Concepción','CHL','Bíobío',217664);
+INSERT INTO City VALUES (563,'Rancagua','CHL','O´Higgins',212977);
+INSERT INTO City VALUES (564,'Arica','CHL','Tarapacá',189036);
+INSERT INTO City VALUES (565,'Talca','CHL','Maule',187557);
+INSERT INTO City VALUES (566,'Chillán','CHL','Bíobío',178182);
+INSERT INTO City VALUES (567,'Iquique','CHL','Tarapacá',177892);
+INSERT INTO City VALUES (568,'Los Angeles','CHL','Bíobío',158215);
+INSERT INTO City VALUES (569,'Puerto Montt','CHL','Los Lagos',152194);
+INSERT INTO City VALUES (570,'Coquimbo','CHL','Coquimbo',143353);
+INSERT INTO City VALUES (571,'Osorno','CHL','Los Lagos',141468);
+INSERT INTO City VALUES (572,'La Serena','CHL','Coquimbo',137409);
+INSERT INTO City VALUES (573,'Calama','CHL','Antofagasta',137265);
+INSERT INTO City VALUES (574,'Valdivia','CHL','Los Lagos',133106);
+INSERT INTO City VALUES (575,'Punta Arenas','CHL','Magallanes',125631);
+INSERT INTO City VALUES (576,'Copiapó','CHL','Atacama',120128);
+INSERT INTO City VALUES (577,'Quilpué','CHL','Valparaíso',118857);
+INSERT INTO City VALUES (578,'Curicó','CHL','Maule',115766);
+INSERT INTO City VALUES (579,'Ovalle','CHL','Coquimbo',94854);
+INSERT INTO City VALUES (580,'Coronel','CHL','Bíobío',93061);
+INSERT INTO City VALUES (581,'San Pedro de la Paz','CHL','Bíobío',91684);
+INSERT INTO City VALUES (582,'Melipilla','CHL','Santiago',91056);
+INSERT INTO City VALUES (583,'Avarua','COK','Rarotonga',11900);
+INSERT INTO City VALUES (584,'San José','CRI','San José',339131);
+INSERT INTO City VALUES (585,'Djibouti','DJI','Djibouti',383000);
+INSERT INTO City VALUES (586,'Roseau','DMA','St George',16243);
+INSERT INTO City VALUES (587,'Santo Domingo de Guzmán','DOM','Distrito Nacional',1609966);
+INSERT INTO City VALUES (588,'Santiago de los Caballeros','DOM','Santiago',365463);
+INSERT INTO City VALUES (589,'La Romana','DOM','La Romana',140204);
+INSERT INTO City VALUES (590,'San Pedro de Macorís','DOM','San Pedro de Macorís',124735);
+INSERT INTO City VALUES (591,'San Francisco de Macorís','DOM','Duarte',108485);
+INSERT INTO City VALUES (592,'San Felipe de Puerto Plata','DOM','Puerto Plata',89423);
+INSERT INTO City VALUES (593,'Guayaquil','ECU','Guayas',2070040);
+INSERT INTO City VALUES (594,'Quito','ECU','Pichincha',1573458);
+INSERT INTO City VALUES (595,'Cuenca','ECU','Azuay',270353);
+INSERT INTO City VALUES (596,'Machala','ECU','El Oro',210368);
+INSERT INTO City VALUES (597,'Santo Domingo de los Colorados','ECU','Pichincha',202111);
+INSERT INTO City VALUES (598,'Portoviejo','ECU','Manabí',176413);
+INSERT INTO City VALUES (599,'Ambato','ECU','Tungurahua',169612);
+INSERT INTO City VALUES (600,'Manta','ECU','Manabí',164739);
+INSERT INTO City VALUES (601,'Duran [Eloy Alfaro]','ECU','Guayas',152514);
+INSERT INTO City VALUES (602,'Ibarra','ECU','Imbabura',130643);
+INSERT INTO City VALUES (603,'Quevedo','ECU','Los Ríos',129631);
+INSERT INTO City VALUES (604,'Milagro','ECU','Guayas',124177);
+INSERT INTO City VALUES (605,'Loja','ECU','Loja',123875);
+INSERT INTO City VALUES (606,'Ríobamba','ECU','Chimborazo',123163);
+INSERT INTO City VALUES (607,'Esmeraldas','ECU','Esmeraldas',123045);
+INSERT INTO City VALUES (608,'Cairo','EGY','Kairo',6789479);
+INSERT INTO City VALUES (609,'Alexandria','EGY','Aleksandria',3328196);
+INSERT INTO City VALUES (610,'Giza','EGY','Giza',2221868);
+INSERT INTO City VALUES (611,'Shubra al-Khayma','EGY','al-Qalyubiya',870716);
+INSERT INTO City VALUES (612,'Port Said','EGY','Port Said',469533);
+INSERT INTO City VALUES (613,'Suez','EGY','Suez',417610);
+INSERT INTO City VALUES (614,'al-Mahallat al-Kubra','EGY','al-Gharbiya',395402);
+INSERT INTO City VALUES (615,'Tanta','EGY','al-Gharbiya',371010);
+INSERT INTO City VALUES (616,'al-Mansura','EGY','al-Daqahliya',369621);
+INSERT INTO City VALUES (617,'Luxor','EGY','Luxor',360503);
+INSERT INTO City VALUES (618,'Asyut','EGY','Asyut',343498);
+INSERT INTO City VALUES (619,'Bahtim','EGY','al-Qalyubiya',275807);
+INSERT INTO City VALUES (620,'Zagazig','EGY','al-Sharqiya',267351);
+INSERT INTO City VALUES (621,'al-Faiyum','EGY','al-Faiyum',260964);
+INSERT INTO City VALUES (622,'Ismailia','EGY','Ismailia',254477);
+INSERT INTO City VALUES (623,'Kafr al-Dawwar','EGY','al-Buhayra',231978);
+INSERT INTO City VALUES (624,'Assuan','EGY','Assuan',219017);
+INSERT INTO City VALUES (625,'Damanhur','EGY','al-Buhayra',212203);
+INSERT INTO City VALUES (626,'al-Minya','EGY','al-Minya',201360);
+INSERT INTO City VALUES (627,'Bani Suwayf','EGY','Bani Suwayf',172032);
+INSERT INTO City VALUES (628,'Qina','EGY','Qina',171275);
+INSERT INTO City VALUES (629,'Sawhaj','EGY','Sawhaj',170125);
+INSERT INTO City VALUES (630,'Shibin al-Kawm','EGY','al-Minufiya',159909);
+INSERT INTO City VALUES (631,'Bulaq al-Dakrur','EGY','Giza',148787);
+INSERT INTO City VALUES (632,'Banha','EGY','al-Qalyubiya',145792);
+INSERT INTO City VALUES (633,'Warraq al-Arab','EGY','Giza',127108);
+INSERT INTO City VALUES (634,'Kafr al-Shaykh','EGY','Kafr al-Shaykh',124819);
+INSERT INTO City VALUES (635,'Mallawi','EGY','al-Minya',119283);
+INSERT INTO City VALUES (636,'Bilbays','EGY','al-Sharqiya',113608);
+INSERT INTO City VALUES (637,'Mit Ghamr','EGY','al-Daqahliya',101801);
+INSERT INTO City VALUES (638,'al-Arish','EGY','Shamal Sina',100447);
+INSERT INTO City VALUES (639,'Talkha','EGY','al-Daqahliya',97700);
+INSERT INTO City VALUES (640,'Qalyub','EGY','al-Qalyubiya',97200);
+INSERT INTO City VALUES (641,'Jirja','EGY','Sawhaj',95400);
+INSERT INTO City VALUES (642,'Idfu','EGY','Qina',94200);
+INSERT INTO City VALUES (643,'al-Hawamidiya','EGY','Giza',91700);
+INSERT INTO City VALUES (644,'Disuq','EGY','Kafr al-Shaykh',91300);
+INSERT INTO City VALUES (645,'San Salvador','SLV','San Salvador',415346);
+INSERT INTO City VALUES (646,'Santa Ana','SLV','Santa Ana',139389);
+INSERT INTO City VALUES (647,'Mejicanos','SLV','San Salvador',138800);
+INSERT INTO City VALUES (648,'Soyapango','SLV','San Salvador',129800);
+INSERT INTO City VALUES (649,'San Miguel','SLV','San Miguel',127696);
+INSERT INTO City VALUES (650,'Nueva San Salvador','SLV','La Libertad',98400);
+INSERT INTO City VALUES (651,'Apopa','SLV','San Salvador',88800);
+INSERT INTO City VALUES (652,'Asmara','ERI','Maekel',431000);
+INSERT INTO City VALUES (653,'Madrid','ESP','Madrid',2879052);
+INSERT INTO City VALUES (654,'Barcelona','ESP','Katalonia',1503451);
+INSERT INTO City VALUES (655,'Valencia','ESP','Valencia',739412);
+INSERT INTO City VALUES (656,'Sevilla','ESP','Andalusia',701927);
+INSERT INTO City VALUES (657,'Zaragoza','ESP','Aragonia',603367);
+INSERT INTO City VALUES (658,'Málaga','ESP','Andalusia',530553);
+INSERT INTO City VALUES (659,'Bilbao','ESP','Baskimaa',357589);
+INSERT INTO City VALUES (660,'Las Palmas de Gran Canaria','ESP','Canary Islands',354757);
+INSERT INTO City VALUES (661,'Murcia','ESP','Murcia',353504);
+INSERT INTO City VALUES (662,'Palma de Mallorca','ESP','Balears',326993);
+INSERT INTO City VALUES (663,'Valladolid','ESP','Castilla and León',319998);
+INSERT INTO City VALUES (664,'Córdoba','ESP','Andalusia',311708);
+INSERT INTO City VALUES (665,'Vigo','ESP','Galicia',283670);
+INSERT INTO City VALUES (666,'Alicante [Alacant]','ESP','Valencia',272432);
+INSERT INTO City VALUES (667,'Gijón','ESP','Asturia',267980);
+INSERT INTO City VALUES (668,'L´Hospitalet de Llobregat','ESP','Katalonia',247986);
+INSERT INTO City VALUES (669,'Granada','ESP','Andalusia',244767);
+INSERT INTO City VALUES (670,'A Coruña (La Coruña)','ESP','Galicia',243402);
+INSERT INTO City VALUES (671,'Vitoria-Gasteiz','ESP','Baskimaa',217154);
+INSERT INTO City VALUES (672,'Santa Cruz de Tenerife','ESP','Canary Islands',213050);
+INSERT INTO City VALUES (673,'Badalona','ESP','Katalonia',209635);
+INSERT INTO City VALUES (674,'Oviedo','ESP','Asturia',200453);
+INSERT INTO City VALUES (675,'Móstoles','ESP','Madrid',195351);
+INSERT INTO City VALUES (676,'Elche [Elx]','ESP','Valencia',193174);
+INSERT INTO City VALUES (677,'Sabadell','ESP','Katalonia',184859);
+INSERT INTO City VALUES (678,'Santander','ESP','Cantabria',184165);
+INSERT INTO City VALUES (679,'Jerez de la Frontera','ESP','Andalusia',182660);
+INSERT INTO City VALUES (680,'Pamplona [Iruña]','ESP','Navarra',180483);
+INSERT INTO City VALUES (681,'Donostia-San Sebastián','ESP','Baskimaa',179208);
+INSERT INTO City VALUES (682,'Cartagena','ESP','Murcia',177709);
+INSERT INTO City VALUES (683,'Leganés','ESP','Madrid',173163);
+INSERT INTO City VALUES (684,'Fuenlabrada','ESP','Madrid',171173);
+INSERT INTO City VALUES (685,'Almería','ESP','Andalusia',169027);
+INSERT INTO City VALUES (686,'Terrassa','ESP','Katalonia',168695);
+INSERT INTO City VALUES (687,'Alcalá de Henares','ESP','Madrid',164463);
+INSERT INTO City VALUES (688,'Burgos','ESP','Castilla and León',162802);
+INSERT INTO City VALUES (689,'Salamanca','ESP','Castilla and León',158720);
+INSERT INTO City VALUES (690,'Albacete','ESP','Kastilia-La Mancha',147527);
+INSERT INTO City VALUES (691,'Getafe','ESP','Madrid',145371);
+INSERT INTO City VALUES (692,'Cádiz','ESP','Andalusia',142449);
+INSERT INTO City VALUES (693,'Alcorcón','ESP','Madrid',142048);
+INSERT INTO City VALUES (694,'Huelva','ESP','Andalusia',140583);
+INSERT INTO City VALUES (695,'León','ESP','Castilla and León',139809);
+INSERT INTO City VALUES (696,'Castellón de la Plana [Castell','ESP','Valencia',139712);
+INSERT INTO City VALUES (697,'Badajoz','ESP','Extremadura',136613);
+INSERT INTO City VALUES (698,'[San Cristóbal de] la Laguna','ESP','Canary Islands',127945);
+INSERT INTO City VALUES (699,'Logroño','ESP','La Rioja',127093);
+INSERT INTO City VALUES (700,'Santa Coloma de Gramenet','ESP','Katalonia',120802);
+INSERT INTO City VALUES (701,'Tarragona','ESP','Katalonia',113016);
+INSERT INTO City VALUES (702,'Lleida (Lérida)','ESP','Katalonia',112207);
+INSERT INTO City VALUES (703,'Jaén','ESP','Andalusia',109247);
+INSERT INTO City VALUES (704,'Ourense (Orense)','ESP','Galicia',109120);
+INSERT INTO City VALUES (705,'Mataró','ESP','Katalonia',104095);
+INSERT INTO City VALUES (706,'Algeciras','ESP','Andalusia',103106);
+INSERT INTO City VALUES (707,'Marbella','ESP','Andalusia',101144);
+INSERT INTO City VALUES (708,'Barakaldo','ESP','Baskimaa',98212);
+INSERT INTO City VALUES (709,'Dos Hermanas','ESP','Andalusia',94591);
+INSERT INTO City VALUES (710,'Santiago de Compostela','ESP','Galicia',93745);
+INSERT INTO City VALUES (711,'Torrejón de Ardoz','ESP','Madrid',92262);
+INSERT INTO City VALUES (712,'Cape Town','ZAF','Western Cape',2352121);
+INSERT INTO City VALUES (713,'Soweto','ZAF','Gauteng',904165);
+INSERT INTO City VALUES (714,'Johannesburg','ZAF','Gauteng',756653);
+INSERT INTO City VALUES (715,'Port Elizabeth','ZAF','Eastern Cape',752319);
+INSERT INTO City VALUES (716,'Pretoria','ZAF','Gauteng',658630);
+INSERT INTO City VALUES (717,'Inanda','ZAF','KwaZulu-Natal',634065);
+INSERT INTO City VALUES (718,'Durban','ZAF','KwaZulu-Natal',566120);
+INSERT INTO City VALUES (719,'Vanderbijlpark','ZAF','Gauteng',468931);
+INSERT INTO City VALUES (720,'Kempton Park','ZAF','Gauteng',442633);
+INSERT INTO City VALUES (721,'Alberton','ZAF','Gauteng',410102);
+INSERT INTO City VALUES (722,'Pinetown','ZAF','KwaZulu-Natal',378810);
+INSERT INTO City VALUES (723,'Pietermaritzburg','ZAF','KwaZulu-Natal',370190);
+INSERT INTO City VALUES (724,'Benoni','ZAF','Gauteng',365467);
+INSERT INTO City VALUES (725,'Randburg','ZAF','Gauteng',341288);
+INSERT INTO City VALUES (726,'Umlazi','ZAF','KwaZulu-Natal',339233);
+INSERT INTO City VALUES (727,'Bloemfontein','ZAF','Free State',334341);
+INSERT INTO City VALUES (728,'Vereeniging','ZAF','Gauteng',328535);
+INSERT INTO City VALUES (729,'Wonderboom','ZAF','Gauteng',283289);
+INSERT INTO City VALUES (730,'Roodepoort','ZAF','Gauteng',279340);
+INSERT INTO City VALUES (731,'Boksburg','ZAF','Gauteng',262648);
+INSERT INTO City VALUES (732,'Klerksdorp','ZAF','North West',261911);
+INSERT INTO City VALUES (733,'Soshanguve','ZAF','Gauteng',242727);
+INSERT INTO City VALUES (734,'Newcastle','ZAF','KwaZulu-Natal',222993);
+INSERT INTO City VALUES (735,'East London','ZAF','Eastern Cape',221047);
+INSERT INTO City VALUES (736,'Welkom','ZAF','Free State',203296);
+INSERT INTO City VALUES (737,'Kimberley','ZAF','Northern Cape',197254);
+INSERT INTO City VALUES (738,'Uitenhage','ZAF','Eastern Cape',192120);
+INSERT INTO City VALUES (739,'Chatsworth','ZAF','KwaZulu-Natal',189885);
+INSERT INTO City VALUES (740,'Mdantsane','ZAF','Eastern Cape',182639);
+INSERT INTO City VALUES (741,'Krugersdorp','ZAF','Gauteng',181503);
+INSERT INTO City VALUES (742,'Botshabelo','ZAF','Free State',177971);
+INSERT INTO City VALUES (743,'Brakpan','ZAF','Gauteng',171363);
+INSERT INTO City VALUES (744,'Witbank','ZAF','Mpumalanga',167183);
+INSERT INTO City VALUES (745,'Oberholzer','ZAF','Gauteng',164367);
+INSERT INTO City VALUES (746,'Germiston','ZAF','Gauteng',164252);
+INSERT INTO City VALUES (747,'Springs','ZAF','Gauteng',162072);
+INSERT INTO City VALUES (748,'Westonaria','ZAF','Gauteng',159632);
+INSERT INTO City VALUES (749,'Randfontein','ZAF','Gauteng',120838);
+INSERT INTO City VALUES (750,'Paarl','ZAF','Western Cape',105768);
+INSERT INTO City VALUES (751,'Potchefstroom','ZAF','North West',101817);
+INSERT INTO City VALUES (752,'Rustenburg','ZAF','North West',97008);
+INSERT INTO City VALUES (753,'Nigel','ZAF','Gauteng',96734);
+INSERT INTO City VALUES (754,'George','ZAF','Western Cape',93818);
+INSERT INTO City VALUES (755,'Ladysmith','ZAF','KwaZulu-Natal',89292);
+INSERT INTO City VALUES (756,'Addis Abeba','ETH','Addis Abeba',2495000);
+INSERT INTO City VALUES (757,'Dire Dawa','ETH','Dire Dawa',164851);
+INSERT INTO City VALUES (758,'Nazret','ETH','Oromia',127842);
+INSERT INTO City VALUES (759,'Gonder','ETH','Amhara',112249);
+INSERT INTO City VALUES (760,'Dese','ETH','Amhara',97314);
+INSERT INTO City VALUES (761,'Mekele','ETH','Tigray',96938);
+INSERT INTO City VALUES (762,'Bahir Dar','ETH','Amhara',96140);
+INSERT INTO City VALUES (763,'Stanley','FLK','East Falkland',1636);
+INSERT INTO City VALUES (764,'Suva','FJI','Central',77366);
+INSERT INTO City VALUES (765,'Quezon','PHL','National Capital Reg',2173831);
+INSERT INTO City VALUES (766,'Manila','PHL','National Capital Reg',1581082);
+INSERT INTO City VALUES (767,'Kalookan','PHL','National Capital Reg',1177604);
+INSERT INTO City VALUES (768,'Davao','PHL','Southern Mindanao',1147116);
+INSERT INTO City VALUES (769,'Cebu','PHL','Central Visayas',718821);
+INSERT INTO City VALUES (770,'Zamboanga','PHL','Western Mindanao',601794);
+INSERT INTO City VALUES (771,'Pasig','PHL','National Capital Reg',505058);
+INSERT INTO City VALUES (772,'Valenzuela','PHL','National Capital Reg',485433);
+INSERT INTO City VALUES (773,'Las Piñas','PHL','National Capital Reg',472780);
+INSERT INTO City VALUES (774,'Antipolo','PHL','Southern Tagalog',470866);
+INSERT INTO City VALUES (775,'Taguig','PHL','National Capital Reg',467375);
+INSERT INTO City VALUES (776,'Cagayan de Oro','PHL','Northern Mindanao',461877);
+INSERT INTO City VALUES (777,'Parañaque','PHL','National Capital Reg',449811);
+INSERT INTO City VALUES (778,'Makati','PHL','National Capital Reg',444867);
+INSERT INTO City VALUES (779,'Bacolod','PHL','Western Visayas',429076);
+INSERT INTO City VALUES (780,'General Santos','PHL','Southern Mindanao',411822);
+INSERT INTO City VALUES (781,'Marikina','PHL','National Capital Reg',391170);
+INSERT INTO City VALUES (782,'Dasmariñas','PHL','Southern Tagalog',379520);
+INSERT INTO City VALUES (783,'Muntinlupa','PHL','National Capital Reg',379310);
+INSERT INTO City VALUES (784,'Iloilo','PHL','Western Visayas',365820);
+INSERT INTO City VALUES (785,'Pasay','PHL','National Capital Reg',354908);
+INSERT INTO City VALUES (786,'Malabon','PHL','National Capital Reg',338855);
+INSERT INTO City VALUES (787,'San José del Monte','PHL','Central Luzon',315807);
+INSERT INTO City VALUES (788,'Bacoor','PHL','Southern Tagalog',305699);
+INSERT INTO City VALUES (789,'Iligan','PHL','Central Mindanao',285061);
+INSERT INTO City VALUES (790,'Calamba','PHL','Southern Tagalog',281146);
+INSERT INTO City VALUES (791,'Mandaluyong','PHL','National Capital Reg',278474);
+INSERT INTO City VALUES (792,'Butuan','PHL','Caraga',267279);
+INSERT INTO City VALUES (793,'Angeles','PHL','Central Luzon',263971);
+INSERT INTO City VALUES (794,'Tarlac','PHL','Central Luzon',262481);
+INSERT INTO City VALUES (795,'Mandaue','PHL','Central Visayas',259728);
+INSERT INTO City VALUES (796,'Baguio','PHL','CAR',252386);
+INSERT INTO City VALUES (797,'Batangas','PHL','Southern Tagalog',247588);
+INSERT INTO City VALUES (798,'Cainta','PHL','Southern Tagalog',242511);
+INSERT INTO City VALUES (799,'San Pedro','PHL','Southern Tagalog',231403);
+INSERT INTO City VALUES (800,'Navotas','PHL','National Capital Reg',230403);
+INSERT INTO City VALUES (801,'Cabanatuan','PHL','Central Luzon',222859);
+INSERT INTO City VALUES (802,'San Fernando','PHL','Central Luzon',221857);
+INSERT INTO City VALUES (803,'Lipa','PHL','Southern Tagalog',218447);
+INSERT INTO City VALUES (804,'Lapu-Lapu','PHL','Central Visayas',217019);
+INSERT INTO City VALUES (805,'San Pablo','PHL','Southern Tagalog',207927);
+INSERT INTO City VALUES (806,'Biñan','PHL','Southern Tagalog',201186);
+INSERT INTO City VALUES (807,'Taytay','PHL','Southern Tagalog',198183);
+INSERT INTO City VALUES (808,'Lucena','PHL','Southern Tagalog',196075);
+INSERT INTO City VALUES (809,'Imus','PHL','Southern Tagalog',195482);
+INSERT INTO City VALUES (810,'Olongapo','PHL','Central Luzon',194260);
+INSERT INTO City VALUES (811,'Binangonan','PHL','Southern Tagalog',187691);
+INSERT INTO City VALUES (812,'Santa Rosa','PHL','Southern Tagalog',185633);
+INSERT INTO City VALUES (813,'Tagum','PHL','Southern Mindanao',179531);
+INSERT INTO City VALUES (814,'Tacloban','PHL','Eastern Visayas',178639);
+INSERT INTO City VALUES (815,'Malolos','PHL','Central Luzon',175291);
+INSERT INTO City VALUES (816,'Mabalacat','PHL','Central Luzon',171045);
+INSERT INTO City VALUES (817,'Cotabato','PHL','Central Mindanao',163849);
+INSERT INTO City VALUES (818,'Meycauayan','PHL','Central Luzon',163037);
+INSERT INTO City VALUES (819,'Puerto Princesa','PHL','Southern Tagalog',161912);
+INSERT INTO City VALUES (820,'Legazpi','PHL','Bicol',157010);
+INSERT INTO City VALUES (821,'Silang','PHL','Southern Tagalog',156137);
+INSERT INTO City VALUES (822,'Ormoc','PHL','Eastern Visayas',154297);
+INSERT INTO City VALUES (823,'San Carlos','PHL','Ilocos',154264);
+INSERT INTO City VALUES (824,'Kabankalan','PHL','Western Visayas',149769);
+INSERT INTO City VALUES (825,'Talisay','PHL','Central Visayas',148110);
+INSERT INTO City VALUES (826,'Valencia','PHL','Northern Mindanao',147924);
+INSERT INTO City VALUES (827,'Calbayog','PHL','Eastern Visayas',147187);
+INSERT INTO City VALUES (828,'Santa Maria','PHL','Central Luzon',144282);
+INSERT INTO City VALUES (829,'Pagadian','PHL','Western Mindanao',142515);
+INSERT INTO City VALUES (830,'Cadiz','PHL','Western Visayas',141954);
+INSERT INTO City VALUES (831,'Bago','PHL','Western Visayas',141721);
+INSERT INTO City VALUES (832,'Toledo','PHL','Central Visayas',141174);
+INSERT INTO City VALUES (833,'Naga','PHL','Bicol',137810);
+INSERT INTO City VALUES (834,'San Mateo','PHL','Southern Tagalog',135603);
+INSERT INTO City VALUES (835,'Panabo','PHL','Southern Mindanao',133950);
+INSERT INTO City VALUES (836,'Koronadal','PHL','Southern Mindanao',133786);
+INSERT INTO City VALUES (837,'Marawi','PHL','Central Mindanao',131090);
+INSERT INTO City VALUES (838,'Dagupan','PHL','Ilocos',130328);
+INSERT INTO City VALUES (839,'Sagay','PHL','Western Visayas',129765);
+INSERT INTO City VALUES (840,'Roxas','PHL','Western Visayas',126352);
+INSERT INTO City VALUES (841,'Lubao','PHL','Central Luzon',125699);
+INSERT INTO City VALUES (842,'Digos','PHL','Southern Mindanao',125171);
+INSERT INTO City VALUES (843,'San Miguel','PHL','Central Luzon',123824);
+INSERT INTO City VALUES (844,'Malaybalay','PHL','Northern Mindanao',123672);
+INSERT INTO City VALUES (845,'Tuguegarao','PHL','Cagayan Valley',120645);
+INSERT INTO City VALUES (846,'Ilagan','PHL','Cagayan Valley',119990);
+INSERT INTO City VALUES (847,'Baliuag','PHL','Central Luzon',119675);
+INSERT INTO City VALUES (848,'Surigao','PHL','Caraga',118534);
+INSERT INTO City VALUES (849,'San Carlos','PHL','Western Visayas',118259);
+INSERT INTO City VALUES (850,'San Juan del Monte','PHL','National Capital Reg',117680);
+INSERT INTO City VALUES (851,'Tanauan','PHL','Southern Tagalog',117539);
+INSERT INTO City VALUES (852,'Concepcion','PHL','Central Luzon',115171);
+INSERT INTO City VALUES (853,'Rodriguez (Montalban)','PHL','Southern Tagalog',115167);
+INSERT INTO City VALUES (854,'Sariaya','PHL','Southern Tagalog',114568);
+INSERT INTO City VALUES (855,'Malasiqui','PHL','Ilocos',113190);
+INSERT INTO City VALUES (856,'General Mariano Alvarez','PHL','Southern Tagalog',112446);
+INSERT INTO City VALUES (857,'Urdaneta','PHL','Ilocos',111582);
+INSERT INTO City VALUES (858,'Hagonoy','PHL','Central Luzon',111425);
+INSERT INTO City VALUES (859,'San Jose','PHL','Southern Tagalog',111009);
+INSERT INTO City VALUES (860,'Polomolok','PHL','Southern Mindanao',110709);
+INSERT INTO City VALUES (861,'Santiago','PHL','Cagayan Valley',110531);
+INSERT INTO City VALUES (862,'Tanza','PHL','Southern Tagalog',110517);
+INSERT INTO City VALUES (863,'Ozamis','PHL','Northern Mindanao',110420);
+INSERT INTO City VALUES (864,'Mexico','PHL','Central Luzon',109481);
+INSERT INTO City VALUES (865,'San Jose','PHL','Central Luzon',108254);
+INSERT INTO City VALUES (866,'Silay','PHL','Western Visayas',107722);
+INSERT INTO City VALUES (867,'General Trias','PHL','Southern Tagalog',107691);
+INSERT INTO City VALUES (868,'Tabaco','PHL','Bicol',107166);
+INSERT INTO City VALUES (869,'Cabuyao','PHL','Southern Tagalog',106630);
+INSERT INTO City VALUES (870,'Calapan','PHL','Southern Tagalog',105910);
+INSERT INTO City VALUES (871,'Mati','PHL','Southern Mindanao',105908);
+INSERT INTO City VALUES (872,'Midsayap','PHL','Central Mindanao',105760);
+INSERT INTO City VALUES (873,'Cauayan','PHL','Cagayan Valley',103952);
+INSERT INTO City VALUES (874,'Gingoog','PHL','Northern Mindanao',102379);
+INSERT INTO City VALUES (875,'Dumaguete','PHL','Central Visayas',102265);
+INSERT INTO City VALUES (876,'San Fernando','PHL','Ilocos',102082);
+INSERT INTO City VALUES (877,'Arayat','PHL','Central Luzon',101792);
+INSERT INTO City VALUES (878,'Bayawan (Tulong)','PHL','Central Visayas',101391);
+INSERT INTO City VALUES (879,'Kidapawan','PHL','Central Mindanao',101205);
+INSERT INTO City VALUES (880,'Daraga (Locsin)','PHL','Bicol',101031);
+INSERT INTO City VALUES (881,'Marilao','PHL','Central Luzon',101017);
+INSERT INTO City VALUES (882,'Malita','PHL','Southern Mindanao',100000);
+INSERT INTO City VALUES (883,'Dipolog','PHL','Western Mindanao',99862);
+INSERT INTO City VALUES (884,'Cavite','PHL','Southern Tagalog',99367);
+INSERT INTO City VALUES (885,'Danao','PHL','Central Visayas',98781);
+INSERT INTO City VALUES (886,'Bislig','PHL','Caraga',97860);
+INSERT INTO City VALUES (887,'Talavera','PHL','Central Luzon',97329);
+INSERT INTO City VALUES (888,'Guagua','PHL','Central Luzon',96858);
+INSERT INTO City VALUES (889,'Bayambang','PHL','Ilocos',96609);
+INSERT INTO City VALUES (890,'Nasugbu','PHL','Southern Tagalog',96113);
+INSERT INTO City VALUES (891,'Baybay','PHL','Eastern Visayas',95630);
+INSERT INTO City VALUES (892,'Capas','PHL','Central Luzon',95219);
+INSERT INTO City VALUES (893,'Sultan Kudarat','PHL','ARMM',94861);
+INSERT INTO City VALUES (894,'Laoag','PHL','Ilocos',94466);
+INSERT INTO City VALUES (895,'Bayugan','PHL','Caraga',93623);
+INSERT INTO City VALUES (896,'Malungon','PHL','Southern Mindanao',93232);
+INSERT INTO City VALUES (897,'Santa Cruz','PHL','Southern Tagalog',92694);
+INSERT INTO City VALUES (898,'Sorsogon','PHL','Bicol',92512);
+INSERT INTO City VALUES (899,'Candelaria','PHL','Southern Tagalog',92429);
+INSERT INTO City VALUES (900,'Ligao','PHL','Bicol',90603);
+INSERT INTO City VALUES (901,'Tórshavn','FRO','Streymoyar',14542);
+INSERT INTO City VALUES (902,'Libreville','GAB','Estuaire',419000);
+INSERT INTO City VALUES (903,'Serekunda','GMB','Kombo St Mary',102600);
+INSERT INTO City VALUES (904,'Banjul','GMB','Banjul',42326);
+INSERT INTO City VALUES (905,'Tbilisi','GEO','Tbilisi',1235200);
+INSERT INTO City VALUES (906,'Kutaisi','GEO','Imereti',240900);
+INSERT INTO City VALUES (907,'Rustavi','GEO','Kvemo Kartli',155400);
+INSERT INTO City VALUES (908,'Batumi','GEO','Adzaria [Atšara]',137700);
+INSERT INTO City VALUES (909,'Sohumi','GEO','Abhasia [Aphazeti]',111700);
+INSERT INTO City VALUES (910,'Accra','GHA','Greater Accra',1070000);
+INSERT INTO City VALUES (911,'Kumasi','GHA','Ashanti',385192);
+INSERT INTO City VALUES (912,'Tamale','GHA','Northern',151069);
+INSERT INTO City VALUES (913,'Tema','GHA','Greater Accra',109975);
+INSERT INTO City VALUES (914,'Sekondi-Takoradi','GHA','Western',103653);
+INSERT INTO City VALUES (915,'Gibraltar','GIB','–',27025);
+INSERT INTO City VALUES (916,'Saint George´s','GRD','St George',4621);
+INSERT INTO City VALUES (917,'Nuuk','GRL','Kitaa',13445);
+INSERT INTO City VALUES (918,'Les Abymes','GLP','Grande-Terre',62947);
+INSERT INTO City VALUES (919,'Basse-Terre','GLP','Basse-Terre',12433);
+INSERT INTO City VALUES (920,'Tamuning','GUM','–',9500);
+INSERT INTO City VALUES (921,'Agaña','GUM','–',1139);
+INSERT INTO City VALUES (922,'Ciudad de Guatemala','GTM','Guatemala',823301);
+INSERT INTO City VALUES (923,'Mixco','GTM','Guatemala',209791);
+INSERT INTO City VALUES (924,'Villa Nueva','GTM','Guatemala',101295);
+INSERT INTO City VALUES (925,'Quetzaltenango','GTM','Quetzaltenango',90801);
+INSERT INTO City VALUES (926,'Conakry','GIN','Conakry',1090610);
+INSERT INTO City VALUES (927,'Bissau','GNB','Bissau',241000);
+INSERT INTO City VALUES (928,'Georgetown','GUY','Georgetown',254000);
+INSERT INTO City VALUES (929,'Port-au-Prince','HTI','Ouest',884472);
+INSERT INTO City VALUES (930,'Carrefour','HTI','Ouest',290204);
+INSERT INTO City VALUES (931,'Delmas','HTI','Ouest',240429);
+INSERT INTO City VALUES (932,'Le-Cap-Haïtien','HTI','Nord',102233);
+INSERT INTO City VALUES (933,'Tegucigalpa','HND','Distrito Central',813900);
+INSERT INTO City VALUES (934,'San Pedro Sula','HND','Cortés',383900);
+INSERT INTO City VALUES (935,'La Ceiba','HND','Atlántida',89200);
+INSERT INTO City VALUES (936,'Kowloon and New Kowloon','HKG','Kowloon and New Kowl',1987996);
+INSERT INTO City VALUES (937,'Victoria','HKG','Hongkong',1312637);
+INSERT INTO City VALUES (938,'Longyearbyen','SJM','Länsimaa',1438);
+INSERT INTO City VALUES (939,'Jakarta','IDN','Jakarta Raya',9604900);
+INSERT INTO City VALUES (940,'Surabaya','IDN','East Java',2663820);
+INSERT INTO City VALUES (941,'Bandung','IDN','West Java',2429000);
+INSERT INTO City VALUES (942,'Medan','IDN','Sumatera Utara',1843919);
+INSERT INTO City VALUES (943,'Palembang','IDN','Sumatera Selatan',1222764);
+INSERT INTO City VALUES (944,'Tangerang','IDN','West Java',1198300);
+INSERT INTO City VALUES (945,'Semarang','IDN','Central Java',1104405);
+INSERT INTO City VALUES (946,'Ujung Pandang','IDN','Sulawesi Selatan',1060257);
+INSERT INTO City VALUES (947,'Malang','IDN','East Java',716862);
+INSERT INTO City VALUES (948,'Bandar Lampung','IDN','Lampung',680332);
+INSERT INTO City VALUES (949,'Bekasi','IDN','West Java',644300);
+INSERT INTO City VALUES (950,'Padang','IDN','Sumatera Barat',534474);
+INSERT INTO City VALUES (951,'Surakarta','IDN','Central Java',518600);
+INSERT INTO City VALUES (952,'Banjarmasin','IDN','Kalimantan Selatan',482931);
+INSERT INTO City VALUES (953,'Pekan Baru','IDN','Riau',438638);
+INSERT INTO City VALUES (954,'Denpasar','IDN','Bali',435000);
+INSERT INTO City VALUES (955,'Yogyakarta','IDN','Yogyakarta',418944);
+INSERT INTO City VALUES (956,'Pontianak','IDN','Kalimantan Barat',409632);
+INSERT INTO City VALUES (957,'Samarinda','IDN','Kalimantan Timur',399175);
+INSERT INTO City VALUES (958,'Jambi','IDN','Jambi',385201);
+INSERT INTO City VALUES (959,'Depok','IDN','West Java',365200);
+INSERT INTO City VALUES (960,'Cimahi','IDN','West Java',344600);
+INSERT INTO City VALUES (961,'Balikpapan','IDN','Kalimantan Timur',338752);
+INSERT INTO City VALUES (962,'Manado','IDN','Sulawesi Utara',332288);
+INSERT INTO City VALUES (963,'Mataram','IDN','Nusa Tenggara Barat',306600);
+INSERT INTO City VALUES (964,'Pekalongan','IDN','Central Java',301504);
+INSERT INTO City VALUES (965,'Tegal','IDN','Central Java',289744);
+INSERT INTO City VALUES (966,'Bogor','IDN','West Java',285114);
+INSERT INTO City VALUES (967,'Ciputat','IDN','West Java',270800);
+INSERT INTO City VALUES (968,'Pondokgede','IDN','West Java',263200);
+INSERT INTO City VALUES (969,'Cirebon','IDN','West Java',254406);
+INSERT INTO City VALUES (970,'Kediri','IDN','East Java',253760);
+INSERT INTO City VALUES (971,'Ambon','IDN','Molukit',249312);
+INSERT INTO City VALUES (972,'Jember','IDN','East Java',218500);
+INSERT INTO City VALUES (973,'Cilacap','IDN','Central Java',206900);
+INSERT INTO City VALUES (974,'Cimanggis','IDN','West Java',205100);
+INSERT INTO City VALUES (975,'Pematang Siantar','IDN','Sumatera Utara',203056);
+INSERT INTO City VALUES (976,'Purwokerto','IDN','Central Java',202500);
+INSERT INTO City VALUES (977,'Ciomas','IDN','West Java',187400);
+INSERT INTO City VALUES (978,'Tasikmalaya','IDN','West Java',179800);
+INSERT INTO City VALUES (979,'Madiun','IDN','East Java',171532);
+INSERT INTO City VALUES (980,'Bengkulu','IDN','Bengkulu',146439);
+INSERT INTO City VALUES (981,'Karawang','IDN','West Java',145000);
+INSERT INTO City VALUES (982,'Banda Aceh','IDN','Aceh',143409);
+INSERT INTO City VALUES (983,'Palu','IDN','Sulawesi Tengah',142800);
+INSERT INTO City VALUES (984,'Pasuruan','IDN','East Java',134019);
+INSERT INTO City VALUES (985,'Kupang','IDN','Nusa Tenggara Timur',129300);
+INSERT INTO City VALUES (986,'Tebing Tinggi','IDN','Sumatera Utara',129300);
+INSERT INTO City VALUES (987,'Percut Sei Tuan','IDN','Sumatera Utara',129000);
+INSERT INTO City VALUES (988,'Binjai','IDN','Sumatera Utara',127222);
+INSERT INTO City VALUES (989,'Sukabumi','IDN','West Java',125766);
+INSERT INTO City VALUES (990,'Waru','IDN','East Java',124300);
+INSERT INTO City VALUES (991,'Pangkal Pinang','IDN','Sumatera Selatan',124000);
+INSERT INTO City VALUES (992,'Magelang','IDN','Central Java',123800);
+INSERT INTO City VALUES (993,'Blitar','IDN','East Java',122600);
+INSERT INTO City VALUES (994,'Serang','IDN','West Java',122400);
+INSERT INTO City VALUES (995,'Probolinggo','IDN','East Java',120770);
+INSERT INTO City VALUES (996,'Cilegon','IDN','West Java',117000);
+INSERT INTO City VALUES (997,'Cianjur','IDN','West Java',114300);
+INSERT INTO City VALUES (998,'Ciparay','IDN','West Java',111500);
+INSERT INTO City VALUES (999,'Lhokseumawe','IDN','Aceh',109600);
+INSERT INTO City VALUES (1000,'Taman','IDN','East Java',107000);
+INSERT INTO City VALUES (1001,'Depok','IDN','Yogyakarta',106800);
+INSERT INTO City VALUES (1002,'Citeureup','IDN','West Java',105100);
+INSERT INTO City VALUES (1003,'Pemalang','IDN','Central Java',103500);
+INSERT INTO City VALUES (1004,'Klaten','IDN','Central Java',103300);
+INSERT INTO City VALUES (1005,'Salatiga','IDN','Central Java',103000);
+INSERT INTO City VALUES (1006,'Cibinong','IDN','West Java',101300);
+INSERT INTO City VALUES (1007,'Palangka Raya','IDN','Kalimantan Tengah',99693);
+INSERT INTO City VALUES (1008,'Mojokerto','IDN','East Java',96626);
+INSERT INTO City VALUES (1009,'Purwakarta','IDN','West Java',95900);
+INSERT INTO City VALUES (1010,'Garut','IDN','West Java',95800);
+INSERT INTO City VALUES (1011,'Kudus','IDN','Central Java',95300);
+INSERT INTO City VALUES (1012,'Kendari','IDN','Sulawesi Tenggara',94800);
+INSERT INTO City VALUES (1013,'Jaya Pura','IDN','West Irian',94700);
+INSERT INTO City VALUES (1014,'Gorontalo','IDN','Sulawesi Utara',94058);
+INSERT INTO City VALUES (1015,'Majalaya','IDN','West Java',93200);
+INSERT INTO City VALUES (1016,'Pondok Aren','IDN','West Java',92700);
+INSERT INTO City VALUES (1017,'Jombang','IDN','East Java',92600);
+INSERT INTO City VALUES (1018,'Sunggal','IDN','Sumatera Utara',92300);
+INSERT INTO City VALUES (1019,'Batam','IDN','Riau',91871);
+INSERT INTO City VALUES (1020,'Padang Sidempuan','IDN','Sumatera Utara',91200);
+INSERT INTO City VALUES (1021,'Sawangan','IDN','West Java',91100);
+INSERT INTO City VALUES (1022,'Banyuwangi','IDN','East Java',89900);
+INSERT INTO City VALUES (1023,'Tanjung Pinang','IDN','Riau',89900);
+INSERT INTO City VALUES (1024,'Mumbai (Bombay)','IND','Maharashtra',10500000);
+INSERT INTO City VALUES (1025,'Delhi','IND','Delhi',7206704);
+INSERT INTO City VALUES (1026,'Calcutta [Kolkata]','IND','West Bengali',4399819);
+INSERT INTO City VALUES (1027,'Chennai (Madras)','IND','Tamil Nadu',3841396);
+INSERT INTO City VALUES (1028,'Hyderabad','IND','Andhra Pradesh',2964638);
+INSERT INTO City VALUES (1029,'Ahmedabad','IND','Gujarat',2876710);
+INSERT INTO City VALUES (1030,'Bangalore','IND','Karnataka',2660088);
+INSERT INTO City VALUES (1031,'Kanpur','IND','Uttar Pradesh',1874409);
+INSERT INTO City VALUES (1032,'Nagpur','IND','Maharashtra',1624752);
+INSERT INTO City VALUES (1033,'Lucknow','IND','Uttar Pradesh',1619115);
+INSERT INTO City VALUES (1034,'Pune','IND','Maharashtra',1566651);
+INSERT INTO City VALUES (1035,'Surat','IND','Gujarat',1498817);
+INSERT INTO City VALUES (1036,'Jaipur','IND','Rajasthan',1458483);
+INSERT INTO City VALUES (1037,'Indore','IND','Madhya Pradesh',1091674);
+INSERT INTO City VALUES (1038,'Bhopal','IND','Madhya Pradesh',1062771);
+INSERT INTO City VALUES (1039,'Ludhiana','IND','Punjab',1042740);
+INSERT INTO City VALUES (1040,'Vadodara (Baroda)','IND','Gujarat',1031346);
+INSERT INTO City VALUES (1041,'Kalyan','IND','Maharashtra',1014557);
+INSERT INTO City VALUES (1042,'Madurai','IND','Tamil Nadu',977856);
+INSERT INTO City VALUES (1043,'Haora (Howrah)','IND','West Bengali',950435);
+INSERT INTO City VALUES (1044,'Varanasi (Benares)','IND','Uttar Pradesh',929270);
+INSERT INTO City VALUES (1045,'Patna','IND','Bihar',917243);
+INSERT INTO City VALUES (1046,'Srinagar','IND','Jammu and Kashmir',892506);
+INSERT INTO City VALUES (1047,'Agra','IND','Uttar Pradesh',891790);
+INSERT INTO City VALUES (1048,'Coimbatore','IND','Tamil Nadu',816321);
+INSERT INTO City VALUES (1049,'Thane (Thana)','IND','Maharashtra',803389);
+INSERT INTO City VALUES (1050,'Allahabad','IND','Uttar Pradesh',792858);
+INSERT INTO City VALUES (1051,'Meerut','IND','Uttar Pradesh',753778);
+INSERT INTO City VALUES (1052,'Vishakhapatnam','IND','Andhra Pradesh',752037);
+INSERT INTO City VALUES (1053,'Jabalpur','IND','Madhya Pradesh',741927);
+INSERT INTO City VALUES (1054,'Amritsar','IND','Punjab',708835);
+INSERT INTO City VALUES (1055,'Faridabad','IND','Haryana',703592);
+INSERT INTO City VALUES (1056,'Vijayawada','IND','Andhra Pradesh',701827);
+INSERT INTO City VALUES (1057,'Gwalior','IND','Madhya Pradesh',690765);
+INSERT INTO City VALUES (1058,'Jodhpur','IND','Rajasthan',666279);
+INSERT INTO City VALUES (1059,'Nashik (Nasik)','IND','Maharashtra',656925);
+INSERT INTO City VALUES (1060,'Hubli-Dharwad','IND','Karnataka',648298);
+INSERT INTO City VALUES (1061,'Solapur (Sholapur)','IND','Maharashtra',604215);
+INSERT INTO City VALUES (1062,'Ranchi','IND','Jharkhand',599306);
+INSERT INTO City VALUES (1063,'Bareilly','IND','Uttar Pradesh',587211);
+INSERT INTO City VALUES (1064,'Guwahati (Gauhati)','IND','Assam',584342);
+INSERT INTO City VALUES (1065,'Shambajinagar (Aurangabad)','IND','Maharashtra',573272);
+INSERT INTO City VALUES (1066,'Cochin (Kochi)','IND','Kerala',564589);
+INSERT INTO City VALUES (1067,'Rajkot','IND','Gujarat',559407);
+INSERT INTO City VALUES (1068,'Kota','IND','Rajasthan',537371);
+INSERT INTO City VALUES (1069,'Thiruvananthapuram (Trivandrum','IND','Kerala',524006);
+INSERT INTO City VALUES (1070,'Pimpri-Chinchwad','IND','Maharashtra',517083);
+INSERT INTO City VALUES (1071,'Jalandhar (Jullundur)','IND','Punjab',509510);
+INSERT INTO City VALUES (1072,'Gorakhpur','IND','Uttar Pradesh',505566);
+INSERT INTO City VALUES (1073,'Chandigarh','IND','Chandigarh',504094);
+INSERT INTO City VALUES (1074,'Mysore','IND','Karnataka',480692);
+INSERT INTO City VALUES (1075,'Aligarh','IND','Uttar Pradesh',480520);
+INSERT INTO City VALUES (1076,'Guntur','IND','Andhra Pradesh',471051);
+INSERT INTO City VALUES (1077,'Jamshedpur','IND','Jharkhand',460577);
+INSERT INTO City VALUES (1078,'Ghaziabad','IND','Uttar Pradesh',454156);
+INSERT INTO City VALUES (1079,'Warangal','IND','Andhra Pradesh',447657);
+INSERT INTO City VALUES (1080,'Raipur','IND','Chhatisgarh',438639);
+INSERT INTO City VALUES (1081,'Moradabad','IND','Uttar Pradesh',429214);
+INSERT INTO City VALUES (1082,'Durgapur','IND','West Bengali',425836);
+INSERT INTO City VALUES (1083,'Amravati','IND','Maharashtra',421576);
+INSERT INTO City VALUES (1084,'Calicut (Kozhikode)','IND','Kerala',419831);
+INSERT INTO City VALUES (1085,'Bikaner','IND','Rajasthan',416289);
+INSERT INTO City VALUES (1086,'Bhubaneswar','IND','Orissa',411542);
+INSERT INTO City VALUES (1087,'Kolhapur','IND','Maharashtra',406370);
+INSERT INTO City VALUES (1088,'Kataka (Cuttack)','IND','Orissa',403418);
+INSERT INTO City VALUES (1089,'Ajmer','IND','Rajasthan',402700);
+INSERT INTO City VALUES (1090,'Bhavnagar','IND','Gujarat',402338);
+INSERT INTO City VALUES (1091,'Tiruchirapalli','IND','Tamil Nadu',387223);
+INSERT INTO City VALUES (1092,'Bhilai','IND','Chhatisgarh',386159);
+INSERT INTO City VALUES (1093,'Bhiwandi','IND','Maharashtra',379070);
+INSERT INTO City VALUES (1094,'Saharanpur','IND','Uttar Pradesh',374945);
+INSERT INTO City VALUES (1095,'Ulhasnagar','IND','Maharashtra',369077);
+INSERT INTO City VALUES (1096,'Salem','IND','Tamil Nadu',366712);
+INSERT INTO City VALUES (1097,'Ujjain','IND','Madhya Pradesh',362266);
+INSERT INTO City VALUES (1098,'Malegaon','IND','Maharashtra',342595);
+INSERT INTO City VALUES (1099,'Jamnagar','IND','Gujarat',341637);
+INSERT INTO City VALUES (1100,'Bokaro Steel City','IND','Jharkhand',333683);
+INSERT INTO City VALUES (1101,'Akola','IND','Maharashtra',328034);
+INSERT INTO City VALUES (1102,'Belgaum','IND','Karnataka',326399);
+INSERT INTO City VALUES (1103,'Rajahmundry','IND','Andhra Pradesh',324851);
+INSERT INTO City VALUES (1104,'Nellore','IND','Andhra Pradesh',316606);
+INSERT INTO City VALUES (1105,'Udaipur','IND','Rajasthan',308571);
+INSERT INTO City VALUES (1106,'New Bombay','IND','Maharashtra',307297);
+INSERT INTO City VALUES (1107,'Bhatpara','IND','West Bengali',304952);
+INSERT INTO City VALUES (1108,'Gulbarga','IND','Karnataka',304099);
+INSERT INTO City VALUES (1109,'New Delhi','IND','Delhi',301297);
+INSERT INTO City VALUES (1110,'Jhansi','IND','Uttar Pradesh',300850);
+INSERT INTO City VALUES (1111,'Gaya','IND','Bihar',291675);
+INSERT INTO City VALUES (1112,'Kakinada','IND','Andhra Pradesh',279980);
+INSERT INTO City VALUES (1113,'Dhule (Dhulia)','IND','Maharashtra',278317);
+INSERT INTO City VALUES (1114,'Panihati','IND','West Bengali',275990);
+INSERT INTO City VALUES (1115,'Nanded (Nander)','IND','Maharashtra',275083);
+INSERT INTO City VALUES (1116,'Mangalore','IND','Karnataka',273304);
+INSERT INTO City VALUES (1117,'Dehra Dun','IND','Uttaranchal',270159);
+INSERT INTO City VALUES (1118,'Kamarhati','IND','West Bengali',266889);
+INSERT INTO City VALUES (1119,'Davangere','IND','Karnataka',266082);
+INSERT INTO City VALUES (1120,'Asansol','IND','West Bengali',262188);
+INSERT INTO City VALUES (1121,'Bhagalpur','IND','Bihar',253225);
+INSERT INTO City VALUES (1122,'Bellary','IND','Karnataka',245391);
+INSERT INTO City VALUES (1123,'Barddhaman (Burdwan)','IND','West Bengali',245079);
+INSERT INTO City VALUES (1124,'Rampur','IND','Uttar Pradesh',243742);
+INSERT INTO City VALUES (1125,'Jalgaon','IND','Maharashtra',242193);
+INSERT INTO City VALUES (1126,'Muzaffarpur','IND','Bihar',241107);
+INSERT INTO City VALUES (1127,'Nizamabad','IND','Andhra Pradesh',241034);
+INSERT INTO City VALUES (1128,'Muzaffarnagar','IND','Uttar Pradesh',240609);
+INSERT INTO City VALUES (1129,'Patiala','IND','Punjab',238368);
+INSERT INTO City VALUES (1130,'Shahjahanpur','IND','Uttar Pradesh',237713);
+INSERT INTO City VALUES (1131,'Kurnool','IND','Andhra Pradesh',236800);
+INSERT INTO City VALUES (1132,'Tiruppur (Tirupper)','IND','Tamil Nadu',235661);
+INSERT INTO City VALUES (1133,'Rohtak','IND','Haryana',233400);
+INSERT INTO City VALUES (1134,'South Dum Dum','IND','West Bengali',232811);
+INSERT INTO City VALUES (1135,'Mathura','IND','Uttar Pradesh',226691);
+INSERT INTO City VALUES (1136,'Chandrapur','IND','Maharashtra',226105);
+INSERT INTO City VALUES (1137,'Barahanagar (Baranagar)','IND','West Bengali',224821);
+INSERT INTO City VALUES (1138,'Darbhanga','IND','Bihar',218391);
+INSERT INTO City VALUES (1139,'Siliguri (Shiliguri)','IND','West Bengali',216950);
+INSERT INTO City VALUES (1140,'Raurkela','IND','Orissa',215489);
+INSERT INTO City VALUES (1141,'Ambattur','IND','Tamil Nadu',215424);
+INSERT INTO City VALUES (1142,'Panipat','IND','Haryana',215218);
+INSERT INTO City VALUES (1143,'Firozabad','IND','Uttar Pradesh',215128);
+INSERT INTO City VALUES (1144,'Ichalkaranji','IND','Maharashtra',214950);
+INSERT INTO City VALUES (1145,'Jammu','IND','Jammu and Kashmir',214737);
+INSERT INTO City VALUES (1146,'Ramagundam','IND','Andhra Pradesh',214384);
+INSERT INTO City VALUES (1147,'Eluru','IND','Andhra Pradesh',212866);
+INSERT INTO City VALUES (1148,'Brahmapur','IND','Orissa',210418);
+INSERT INTO City VALUES (1149,'Alwar','IND','Rajasthan',205086);
+INSERT INTO City VALUES (1150,'Pondicherry','IND','Pondicherry',203065);
+INSERT INTO City VALUES (1151,'Thanjavur','IND','Tamil Nadu',202013);
+INSERT INTO City VALUES (1152,'Bihar Sharif','IND','Bihar',201323);
+INSERT INTO City VALUES (1153,'Tuticorin','IND','Tamil Nadu',199854);
+INSERT INTO City VALUES (1154,'Imphal','IND','Manipur',198535);
+INSERT INTO City VALUES (1155,'Latur','IND','Maharashtra',197408);
+INSERT INTO City VALUES (1156,'Sagar','IND','Madhya Pradesh',195346);
+INSERT INTO City VALUES (1157,'Farrukhabad-cum-Fatehgarh','IND','Uttar Pradesh',194567);
+INSERT INTO City VALUES (1158,'Sangli','IND','Maharashtra',193197);
+INSERT INTO City VALUES (1159,'Parbhani','IND','Maharashtra',190255);
+INSERT INTO City VALUES (1160,'Nagar Coil','IND','Tamil Nadu',190084);
+INSERT INTO City VALUES (1161,'Bijapur','IND','Karnataka',186939);
+INSERT INTO City VALUES (1162,'Kukatpalle','IND','Andhra Pradesh',185378);
+INSERT INTO City VALUES (1163,'Bally','IND','West Bengali',184474);
+INSERT INTO City VALUES (1164,'Bhilwara','IND','Rajasthan',183965);
+INSERT INTO City VALUES (1165,'Ratlam','IND','Madhya Pradesh',183375);
+INSERT INTO City VALUES (1166,'Avadi','IND','Tamil Nadu',183215);
+INSERT INTO City VALUES (1167,'Dindigul','IND','Tamil Nadu',182477);
+INSERT INTO City VALUES (1168,'Ahmadnagar','IND','Maharashtra',181339);
+INSERT INTO City VALUES (1169,'Bilaspur','IND','Chhatisgarh',179833);
+INSERT INTO City VALUES (1170,'Shimoga','IND','Karnataka',179258);
+INSERT INTO City VALUES (1171,'Kharagpur','IND','West Bengali',177989);
+INSERT INTO City VALUES (1172,'Mira Bhayandar','IND','Maharashtra',175372);
+INSERT INTO City VALUES (1173,'Vellore','IND','Tamil Nadu',175061);
+INSERT INTO City VALUES (1174,'Jalna','IND','Maharashtra',174985);
+INSERT INTO City VALUES (1175,'Burnpur','IND','West Bengali',174933);
+INSERT INTO City VALUES (1176,'Anantapur','IND','Andhra Pradesh',174924);
+INSERT INTO City VALUES (1177,'Allappuzha (Alleppey)','IND','Kerala',174666);
+INSERT INTO City VALUES (1178,'Tirupati','IND','Andhra Pradesh',174369);
+INSERT INTO City VALUES (1179,'Karnal','IND','Haryana',173751);
+INSERT INTO City VALUES (1180,'Burhanpur','IND','Madhya Pradesh',172710);
+INSERT INTO City VALUES (1181,'Hisar (Hissar)','IND','Haryana',172677);
+INSERT INTO City VALUES (1182,'Tiruvottiyur','IND','Tamil Nadu',172562);
+INSERT INTO City VALUES (1183,'Mirzapur-cum-Vindhyachal','IND','Uttar Pradesh',169336);
+INSERT INTO City VALUES (1184,'Secunderabad','IND','Andhra Pradesh',167461);
+INSERT INTO City VALUES (1185,'Nadiad','IND','Gujarat',167051);
+INSERT INTO City VALUES (1186,'Dewas','IND','Madhya Pradesh',164364);
+INSERT INTO City VALUES (1187,'Murwara (Katni)','IND','Madhya Pradesh',163431);
+INSERT INTO City VALUES (1188,'Ganganagar','IND','Rajasthan',161482);
+INSERT INTO City VALUES (1189,'Vizianagaram','IND','Andhra Pradesh',160359);
+INSERT INTO City VALUES (1190,'Erode','IND','Tamil Nadu',159232);
+INSERT INTO City VALUES (1191,'Machilipatnam (Masulipatam)','IND','Andhra Pradesh',159110);
+INSERT INTO City VALUES (1192,'Bhatinda (Bathinda)','IND','Punjab',159042);
+INSERT INTO City VALUES (1193,'Raichur','IND','Karnataka',157551);
+INSERT INTO City VALUES (1194,'Agartala','IND','Tripura',157358);
+INSERT INTO City VALUES (1195,'Arrah (Ara)','IND','Bihar',157082);
+INSERT INTO City VALUES (1196,'Satna','IND','Madhya Pradesh',156630);
+INSERT INTO City VALUES (1197,'Lalbahadur Nagar','IND','Andhra Pradesh',155500);
+INSERT INTO City VALUES (1198,'Aizawl','IND','Mizoram',155240);
+INSERT INTO City VALUES (1199,'Uluberia','IND','West Bengali',155172);
+INSERT INTO City VALUES (1200,'Katihar','IND','Bihar',154367);
+INSERT INTO City VALUES (1201,'Cuddalore','IND','Tamil Nadu',153086);
+INSERT INTO City VALUES (1202,'Hugli-Chinsurah','IND','West Bengali',151806);
+INSERT INTO City VALUES (1203,'Dhanbad','IND','Jharkhand',151789);
+INSERT INTO City VALUES (1204,'Raiganj','IND','West Bengali',151045);
+INSERT INTO City VALUES (1205,'Sambhal','IND','Uttar Pradesh',150869);
+INSERT INTO City VALUES (1206,'Durg','IND','Chhatisgarh',150645);
+INSERT INTO City VALUES (1207,'Munger (Monghyr)','IND','Bihar',150112);
+INSERT INTO City VALUES (1208,'Kanchipuram','IND','Tamil Nadu',150100);
+INSERT INTO City VALUES (1209,'North Dum Dum','IND','West Bengali',149965);
+INSERT INTO City VALUES (1210,'Karimnagar','IND','Andhra Pradesh',148583);
+INSERT INTO City VALUES (1211,'Bharatpur','IND','Rajasthan',148519);
+INSERT INTO City VALUES (1212,'Sikar','IND','Rajasthan',148272);
+INSERT INTO City VALUES (1213,'Hardwar (Haridwar)','IND','Uttaranchal',147305);
+INSERT INTO City VALUES (1214,'Dabgram','IND','West Bengali',147217);
+INSERT INTO City VALUES (1215,'Morena','IND','Madhya Pradesh',147124);
+INSERT INTO City VALUES (1216,'Noida','IND','Uttar Pradesh',146514);
+INSERT INTO City VALUES (1217,'Hapur','IND','Uttar Pradesh',146262);
+INSERT INTO City VALUES (1218,'Bhusawal','IND','Maharashtra',145143);
+INSERT INTO City VALUES (1219,'Khandwa','IND','Madhya Pradesh',145133);
+INSERT INTO City VALUES (1220,'Yamuna Nagar','IND','Haryana',144346);
+INSERT INTO City VALUES (1221,'Sonipat (Sonepat)','IND','Haryana',143922);
+INSERT INTO City VALUES (1222,'Tenali','IND','Andhra Pradesh',143726);
+INSERT INTO City VALUES (1223,'Raurkela Civil Township','IND','Orissa',140408);
+INSERT INTO City VALUES (1224,'Kollam (Quilon)','IND','Kerala',139852);
+INSERT INTO City VALUES (1225,'Kumbakonam','IND','Tamil Nadu',139483);
+INSERT INTO City VALUES (1226,'Ingraj Bazar (English Bazar)','IND','West Bengali',139204);
+INSERT INTO City VALUES (1227,'Timkur','IND','Karnataka',138903);
+INSERT INTO City VALUES (1228,'Amroha','IND','Uttar Pradesh',137061);
+INSERT INTO City VALUES (1229,'Serampore','IND','West Bengali',137028);
+INSERT INTO City VALUES (1230,'Chapra','IND','Bihar',136877);
+INSERT INTO City VALUES (1231,'Pali','IND','Rajasthan',136842);
+INSERT INTO City VALUES (1232,'Maunath Bhanjan','IND','Uttar Pradesh',136697);
+INSERT INTO City VALUES (1233,'Adoni','IND','Andhra Pradesh',136182);
+INSERT INTO City VALUES (1234,'Jaunpur','IND','Uttar Pradesh',136062);
+INSERT INTO City VALUES (1235,'Tirunelveli','IND','Tamil Nadu',135825);
+INSERT INTO City VALUES (1236,'Bahraich','IND','Uttar Pradesh',135400);
+INSERT INTO City VALUES (1237,'Gadag Betigeri','IND','Karnataka',134051);
+INSERT INTO City VALUES (1238,'Proddatur','IND','Andhra Pradesh',133914);
+INSERT INTO City VALUES (1239,'Chittoor','IND','Andhra Pradesh',133462);
+INSERT INTO City VALUES (1240,'Barrackpur','IND','West Bengali',133265);
+INSERT INTO City VALUES (1241,'Bharuch (Broach)','IND','Gujarat',133102);
+INSERT INTO City VALUES (1242,'Naihati','IND','West Bengali',132701);
+INSERT INTO City VALUES (1243,'Shillong','IND','Meghalaya',131719);
+INSERT INTO City VALUES (1244,'Sambalpur','IND','Orissa',131138);
+INSERT INTO City VALUES (1245,'Junagadh','IND','Gujarat',130484);
+INSERT INTO City VALUES (1246,'Rae Bareli','IND','Uttar Pradesh',129904);
+INSERT INTO City VALUES (1247,'Rewa','IND','Madhya Pradesh',128981);
+INSERT INTO City VALUES (1248,'Gurgaon','IND','Haryana',128608);
+INSERT INTO City VALUES (1249,'Khammam','IND','Andhra Pradesh',127992);
+INSERT INTO City VALUES (1250,'Bulandshahr','IND','Uttar Pradesh',127201);
+INSERT INTO City VALUES (1251,'Navsari','IND','Gujarat',126089);
+INSERT INTO City VALUES (1252,'Malkajgiri','IND','Andhra Pradesh',126066);
+INSERT INTO City VALUES (1253,'Midnapore (Medinipur)','IND','West Bengali',125498);
+INSERT INTO City VALUES (1254,'Miraj','IND','Maharashtra',125407);
+INSERT INTO City VALUES (1255,'Raj Nandgaon','IND','Chhatisgarh',125371);
+INSERT INTO City VALUES (1256,'Alandur','IND','Tamil Nadu',125244);
+INSERT INTO City VALUES (1257,'Puri','IND','Orissa',125199);
+INSERT INTO City VALUES (1258,'Navadwip','IND','West Bengali',125037);
+INSERT INTO City VALUES (1259,'Sirsa','IND','Haryana',125000);
+INSERT INTO City VALUES (1260,'Korba','IND','Chhatisgarh',124501);
+INSERT INTO City VALUES (1261,'Faizabad','IND','Uttar Pradesh',124437);
+INSERT INTO City VALUES (1262,'Etawah','IND','Uttar Pradesh',124072);
+INSERT INTO City VALUES (1263,'Pathankot','IND','Punjab',123930);
+INSERT INTO City VALUES (1264,'Gandhinagar','IND','Gujarat',123359);
+INSERT INTO City VALUES (1265,'Palghat (Palakkad)','IND','Kerala',123289);
+INSERT INTO City VALUES (1266,'Veraval','IND','Gujarat',123000);
+INSERT INTO City VALUES (1267,'Hoshiarpur','IND','Punjab',122705);
+INSERT INTO City VALUES (1268,'Ambala','IND','Haryana',122596);
+INSERT INTO City VALUES (1269,'Sitapur','IND','Uttar Pradesh',121842);
+INSERT INTO City VALUES (1270,'Bhiwani','IND','Haryana',121629);
+INSERT INTO City VALUES (1271,'Cuddapah','IND','Andhra Pradesh',121463);
+INSERT INTO City VALUES (1272,'Bhimavaram','IND','Andhra Pradesh',121314);
+INSERT INTO City VALUES (1273,'Krishnanagar','IND','West Bengali',121110);
+INSERT INTO City VALUES (1274,'Chandannagar','IND','West Bengali',120378);
+INSERT INTO City VALUES (1275,'Mandya','IND','Karnataka',120265);
+INSERT INTO City VALUES (1276,'Dibrugarh','IND','Assam',120127);
+INSERT INTO City VALUES (1277,'Nandyal','IND','Andhra Pradesh',119813);
+INSERT INTO City VALUES (1278,'Balurghat','IND','West Bengali',119796);
+INSERT INTO City VALUES (1279,'Neyveli','IND','Tamil Nadu',118080);
+INSERT INTO City VALUES (1280,'Fatehpur','IND','Uttar Pradesh',117675);
+INSERT INTO City VALUES (1281,'Mahbubnagar','IND','Andhra Pradesh',116833);
+INSERT INTO City VALUES (1282,'Budaun','IND','Uttar Pradesh',116695);
+INSERT INTO City VALUES (1283,'Porbandar','IND','Gujarat',116671);
+INSERT INTO City VALUES (1284,'Silchar','IND','Assam',115483);
+INSERT INTO City VALUES (1285,'Berhampore (Baharampur)','IND','West Bengali',115144);
+INSERT INTO City VALUES (1286,'Purnea (Purnia)','IND','Jharkhand',114912);
+INSERT INTO City VALUES (1287,'Bankura','IND','West Bengali',114876);
+INSERT INTO City VALUES (1288,'Rajapalaiyam','IND','Tamil Nadu',114202);
+INSERT INTO City VALUES (1289,'Titagarh','IND','West Bengali',114085);
+INSERT INTO City VALUES (1290,'Halisahar','IND','West Bengali',114028);
+INSERT INTO City VALUES (1291,'Hathras','IND','Uttar Pradesh',113285);
+INSERT INTO City VALUES (1292,'Bhir (Bid)','IND','Maharashtra',112434);
+INSERT INTO City VALUES (1293,'Pallavaram','IND','Tamil Nadu',111866);
+INSERT INTO City VALUES (1294,'Anand','IND','Gujarat',110266);
+INSERT INTO City VALUES (1295,'Mango','IND','Jharkhand',110024);
+INSERT INTO City VALUES (1296,'Santipur','IND','West Bengali',109956);
+INSERT INTO City VALUES (1297,'Bhind','IND','Madhya Pradesh',109755);
+INSERT INTO City VALUES (1298,'Gondiya','IND','Maharashtra',109470);
+INSERT INTO City VALUES (1299,'Tiruvannamalai','IND','Tamil Nadu',109196);
+INSERT INTO City VALUES (1300,'Yeotmal (Yavatmal)','IND','Maharashtra',108578);
+INSERT INTO City VALUES (1301,'Kulti-Barakar','IND','West Bengali',108518);
+INSERT INTO City VALUES (1302,'Moga','IND','Punjab',108304);
+INSERT INTO City VALUES (1303,'Shivapuri','IND','Madhya Pradesh',108277);
+INSERT INTO City VALUES (1304,'Bidar','IND','Karnataka',108016);
+INSERT INTO City VALUES (1305,'Guntakal','IND','Andhra Pradesh',107592);
+INSERT INTO City VALUES (1306,'Unnao','IND','Uttar Pradesh',107425);
+INSERT INTO City VALUES (1307,'Barasat','IND','West Bengali',107365);
+INSERT INTO City VALUES (1308,'Tambaram','IND','Tamil Nadu',107187);
+INSERT INTO City VALUES (1309,'Abohar','IND','Punjab',107163);
+INSERT INTO City VALUES (1310,'Pilibhit','IND','Uttar Pradesh',106605);
+INSERT INTO City VALUES (1311,'Valparai','IND','Tamil Nadu',106523);
+INSERT INTO City VALUES (1312,'Gonda','IND','Uttar Pradesh',106078);
+INSERT INTO City VALUES (1313,'Surendranagar','IND','Gujarat',105973);
+INSERT INTO City VALUES (1314,'Qutubullapur','IND','Andhra Pradesh',105380);
+INSERT INTO City VALUES (1315,'Beawar','IND','Rajasthan',105363);
+INSERT INTO City VALUES (1316,'Hindupur','IND','Andhra Pradesh',104651);
+INSERT INTO City VALUES (1317,'Gandhidham','IND','Gujarat',104585);
+INSERT INTO City VALUES (1318,'Haldwani-cum-Kathgodam','IND','Uttaranchal',104195);
+INSERT INTO City VALUES (1319,'Tellicherry (Thalassery)','IND','Kerala',103579);
+INSERT INTO City VALUES (1320,'Wardha','IND','Maharashtra',102985);
+INSERT INTO City VALUES (1321,'Rishra','IND','West Bengali',102649);
+INSERT INTO City VALUES (1322,'Bhuj','IND','Gujarat',102176);
+INSERT INTO City VALUES (1323,'Modinagar','IND','Uttar Pradesh',101660);
+INSERT INTO City VALUES (1324,'Gudivada','IND','Andhra Pradesh',101656);
+INSERT INTO City VALUES (1325,'Basirhat','IND','West Bengali',101409);
+INSERT INTO City VALUES (1326,'Uttarpara-Kotrung','IND','West Bengali',100867);
+INSERT INTO City VALUES (1327,'Ongole','IND','Andhra Pradesh',100836);
+INSERT INTO City VALUES (1328,'North Barrackpur','IND','West Bengali',100513);
+INSERT INTO City VALUES (1329,'Guna','IND','Madhya Pradesh',100490);
+INSERT INTO City VALUES (1330,'Haldia','IND','West Bengali',100347);
+INSERT INTO City VALUES (1331,'Habra','IND','West Bengali',100223);
+INSERT INTO City VALUES (1332,'Kanchrapara','IND','West Bengali',100194);
+INSERT INTO City VALUES (1333,'Tonk','IND','Rajasthan',100079);
+INSERT INTO City VALUES (1334,'Champdani','IND','West Bengali',98818);
+INSERT INTO City VALUES (1335,'Orai','IND','Uttar Pradesh',98640);
+INSERT INTO City VALUES (1336,'Pudukkottai','IND','Tamil Nadu',98619);
+INSERT INTO City VALUES (1337,'Sasaram','IND','Bihar',98220);
+INSERT INTO City VALUES (1338,'Hazaribag','IND','Jharkhand',97712);
+INSERT INTO City VALUES (1339,'Palayankottai','IND','Tamil Nadu',97662);
+INSERT INTO City VALUES (1340,'Banda','IND','Uttar Pradesh',97227);
+INSERT INTO City VALUES (1341,'Godhra','IND','Gujarat',96813);
+INSERT INTO City VALUES (1342,'Hospet','IND','Karnataka',96322);
+INSERT INTO City VALUES (1343,'Ashoknagar-Kalyangarh','IND','West Bengali',96315);
+INSERT INTO City VALUES (1344,'Achalpur','IND','Maharashtra',96216);
+INSERT INTO City VALUES (1345,'Patan','IND','Gujarat',96109);
+INSERT INTO City VALUES (1346,'Mandasor','IND','Madhya Pradesh',95758);
+INSERT INTO City VALUES (1347,'Damoh','IND','Madhya Pradesh',95661);
+INSERT INTO City VALUES (1348,'Satara','IND','Maharashtra',95133);
+INSERT INTO City VALUES (1349,'Meerut Cantonment','IND','Uttar Pradesh',94876);
+INSERT INTO City VALUES (1350,'Dehri','IND','Bihar',94526);
+INSERT INTO City VALUES (1351,'Delhi Cantonment','IND','Delhi',94326);
+INSERT INTO City VALUES (1352,'Chhindwara','IND','Madhya Pradesh',93731);
+INSERT INTO City VALUES (1353,'Bansberia','IND','West Bengali',93447);
+INSERT INTO City VALUES (1354,'Nagaon','IND','Assam',93350);
+INSERT INTO City VALUES (1355,'Kanpur Cantonment','IND','Uttar Pradesh',93109);
+INSERT INTO City VALUES (1356,'Vidisha','IND','Madhya Pradesh',92917);
+INSERT INTO City VALUES (1357,'Bettiah','IND','Bihar',92583);
+INSERT INTO City VALUES (1358,'Purulia','IND','Jharkhand',92574);
+INSERT INTO City VALUES (1359,'Hassan','IND','Karnataka',90803);
+INSERT INTO City VALUES (1360,'Ambala Sadar','IND','Haryana',90712);
+INSERT INTO City VALUES (1361,'Baidyabati','IND','West Bengali',90601);
+INSERT INTO City VALUES (1362,'Morvi','IND','Gujarat',90357);
+INSERT INTO City VALUES (1363,'Raigarh','IND','Chhatisgarh',89166);
+INSERT INTO City VALUES (1364,'Vejalpur','IND','Gujarat',89053);
+INSERT INTO City VALUES (1365,'Baghdad','IRQ','Baghdad',4336000);
+INSERT INTO City VALUES (1366,'Mosul','IRQ','Ninawa',879000);
+INSERT INTO City VALUES (1367,'Irbil','IRQ','Irbil',485968);
+INSERT INTO City VALUES (1368,'Kirkuk','IRQ','al-Tamim',418624);
+INSERT INTO City VALUES (1369,'Basra','IRQ','Basra',406296);
+INSERT INTO City VALUES (1370,'al-Sulaymaniya','IRQ','al-Sulaymaniya',364096);
+INSERT INTO City VALUES (1371,'al-Najaf','IRQ','al-Najaf',309010);
+INSERT INTO City VALUES (1372,'Karbala','IRQ','Karbala',296705);
+INSERT INTO City VALUES (1373,'al-Hilla','IRQ','Babil',268834);
+INSERT INTO City VALUES (1374,'al-Nasiriya','IRQ','DhiQar',265937);
+INSERT INTO City VALUES (1375,'al-Amara','IRQ','Maysan',208797);
+INSERT INTO City VALUES (1376,'al-Diwaniya','IRQ','al-Qadisiya',196519);
+INSERT INTO City VALUES (1377,'al-Ramadi','IRQ','al-Anbar',192556);
+INSERT INTO City VALUES (1378,'al-Kut','IRQ','Wasit',183183);
+INSERT INTO City VALUES (1379,'Baquba','IRQ','Diyala',114516);
+INSERT INTO City VALUES (1380,'Teheran','IRN','Teheran',6758845);
+INSERT INTO City VALUES (1381,'Mashhad','IRN','Khorasan',1887405);
+INSERT INTO City VALUES (1382,'Esfahan','IRN','Esfahan',1266072);
+INSERT INTO City VALUES (1383,'Tabriz','IRN','East Azerbaidzan',1191043);
+INSERT INTO City VALUES (1384,'Shiraz','IRN','Fars',1053025);
+INSERT INTO City VALUES (1385,'Karaj','IRN','Teheran',940968);
+INSERT INTO City VALUES (1386,'Ahvaz','IRN','Khuzestan',804980);
+INSERT INTO City VALUES (1387,'Qom','IRN','Qom',777677);
+INSERT INTO City VALUES (1388,'Kermanshah','IRN','Kermanshah',692986);
+INSERT INTO City VALUES (1389,'Urmia','IRN','West Azerbaidzan',435200);
+INSERT INTO City VALUES (1390,'Zahedan','IRN','Sistan va Baluchesta',419518);
+INSERT INTO City VALUES (1391,'Rasht','IRN','Gilan',417748);
+INSERT INTO City VALUES (1392,'Hamadan','IRN','Hamadan',401281);
+INSERT INTO City VALUES (1393,'Kerman','IRN','Kerman',384991);
+INSERT INTO City VALUES (1394,'Arak','IRN','Markazi',380755);
+INSERT INTO City VALUES (1395,'Ardebil','IRN','Ardebil',340386);
+INSERT INTO City VALUES (1396,'Yazd','IRN','Yazd',326776);
+INSERT INTO City VALUES (1397,'Qazvin','IRN','Qazvin',291117);
+INSERT INTO City VALUES (1398,'Zanjan','IRN','Zanjan',286295);
+INSERT INTO City VALUES (1399,'Sanandaj','IRN','Kordestan',277808);
+INSERT INTO City VALUES (1400,'Bandar-e-Abbas','IRN','Hormozgan',273578);
+INSERT INTO City VALUES (1401,'Khorramabad','IRN','Lorestan',272815);
+INSERT INTO City VALUES (1402,'Eslamshahr','IRN','Teheran',265450);
+INSERT INTO City VALUES (1403,'Borujerd','IRN','Lorestan',217804);
+INSERT INTO City VALUES (1404,'Abadan','IRN','Khuzestan',206073);
+INSERT INTO City VALUES (1405,'Dezful','IRN','Khuzestan',202639);
+INSERT INTO City VALUES (1406,'Kashan','IRN','Esfahan',201372);
+INSERT INTO City VALUES (1407,'Sari','IRN','Mazandaran',195882);
+INSERT INTO City VALUES (1408,'Gorgan','IRN','Golestan',188710);
+INSERT INTO City VALUES (1409,'Najafabad','IRN','Esfahan',178498);
+INSERT INTO City VALUES (1410,'Sabzevar','IRN','Khorasan',170738);
+INSERT INTO City VALUES (1411,'Khomeynishahr','IRN','Esfahan',165888);
+INSERT INTO City VALUES (1412,'Amol','IRN','Mazandaran',159092);
+INSERT INTO City VALUES (1413,'Neyshabur','IRN','Khorasan',158847);
+INSERT INTO City VALUES (1414,'Babol','IRN','Mazandaran',158346);
+INSERT INTO City VALUES (1415,'Khoy','IRN','West Azerbaidzan',148944);
+INSERT INTO City VALUES (1416,'Malayer','IRN','Hamadan',144373);
+INSERT INTO City VALUES (1417,'Bushehr','IRN','Bushehr',143641);
+INSERT INTO City VALUES (1418,'Qaemshahr','IRN','Mazandaran',143286);
+INSERT INTO City VALUES (1419,'Qarchak','IRN','Teheran',142690);
+INSERT INTO City VALUES (1420,'Qods','IRN','Teheran',138278);
+INSERT INTO City VALUES (1421,'Sirjan','IRN','Kerman',135024);
+INSERT INTO City VALUES (1422,'Bojnurd','IRN','Khorasan',134835);
+INSERT INTO City VALUES (1423,'Maragheh','IRN','East Azerbaidzan',132318);
+INSERT INTO City VALUES (1424,'Birjand','IRN','Khorasan',127608);
+INSERT INTO City VALUES (1425,'Ilam','IRN','Ilam',126346);
+INSERT INTO City VALUES (1426,'Bukan','IRN','West Azerbaidzan',120020);
+INSERT INTO City VALUES (1427,'Masjed-e-Soleyman','IRN','Khuzestan',116883);
+INSERT INTO City VALUES (1428,'Saqqez','IRN','Kordestan',115394);
+INSERT INTO City VALUES (1429,'Gonbad-e Qabus','IRN','Mazandaran',111253);
+INSERT INTO City VALUES (1430,'Saveh','IRN','Qom',111245);
+INSERT INTO City VALUES (1431,'Mahabad','IRN','West Azerbaidzan',107799);
+INSERT INTO City VALUES (1432,'Varamin','IRN','Teheran',107233);
+INSERT INTO City VALUES (1433,'Andimeshk','IRN','Khuzestan',106923);
+INSERT INTO City VALUES (1434,'Khorramshahr','IRN','Khuzestan',105636);
+INSERT INTO City VALUES (1435,'Shahrud','IRN','Semnan',104765);
+INSERT INTO City VALUES (1436,'Marv Dasht','IRN','Fars',103579);
+INSERT INTO City VALUES (1437,'Zabol','IRN','Sistan va Baluchesta',100887);
+INSERT INTO City VALUES (1438,'Shahr-e Kord','IRN','Chaharmahal va Bakht',100477);
+INSERT INTO City VALUES (1439,'Bandar-e Anzali','IRN','Gilan',98500);
+INSERT INTO City VALUES (1440,'Rafsanjan','IRN','Kerman',98300);
+INSERT INTO City VALUES (1441,'Marand','IRN','East Azerbaidzan',96400);
+INSERT INTO City VALUES (1442,'Torbat-e Heydariyeh','IRN','Khorasan',94600);
+INSERT INTO City VALUES (1443,'Jahrom','IRN','Fars',94200);
+INSERT INTO City VALUES (1444,'Semnan','IRN','Semnan',91045);
+INSERT INTO City VALUES (1445,'Miandoab','IRN','West Azerbaidzan',90100);
+INSERT INTO City VALUES (1446,'Qomsheh','IRN','Esfahan',89800);
+INSERT INTO City VALUES (1447,'Dublin','IRL','Leinster',481854);
+INSERT INTO City VALUES (1448,'Cork','IRL','Munster',127187);
+INSERT INTO City VALUES (1449,'Reykjavík','ISL','Höfuðborgarsvæði',109184);
+INSERT INTO City VALUES (1450,'Jerusalem','ISR','Jerusalem',633700);
+INSERT INTO City VALUES (1451,'Tel Aviv-Jaffa','ISR','Tel Aviv',348100);
+INSERT INTO City VALUES (1452,'Haifa','ISR','Haifa',265700);
+INSERT INTO City VALUES (1453,'Rishon Le Ziyyon','ISR','Ha Merkaz',188200);
+INSERT INTO City VALUES (1454,'Beerseba','ISR','Ha Darom',163700);
+INSERT INTO City VALUES (1455,'Holon','ISR','Tel Aviv',163100);
+INSERT INTO City VALUES (1456,'Petah Tiqwa','ISR','Ha Merkaz',159400);
+INSERT INTO City VALUES (1457,'Ashdod','ISR','Ha Darom',155800);
+INSERT INTO City VALUES (1458,'Netanya','ISR','Ha Merkaz',154900);
+INSERT INTO City VALUES (1459,'Bat Yam','ISR','Tel Aviv',137000);
+INSERT INTO City VALUES (1460,'Bene Beraq','ISR','Tel Aviv',133900);
+INSERT INTO City VALUES (1461,'Ramat Gan','ISR','Tel Aviv',126900);
+INSERT INTO City VALUES (1462,'Ashqelon','ISR','Ha Darom',92300);
+INSERT INTO City VALUES (1463,'Rehovot','ISR','Ha Merkaz',90300);
+INSERT INTO City VALUES (1464,'Roma','ITA','Latium',2643581);
+INSERT INTO City VALUES (1465,'Milano','ITA','Lombardia',1300977);
+INSERT INTO City VALUES (1466,'Napoli','ITA','Campania',1002619);
+INSERT INTO City VALUES (1467,'Torino','ITA','Piemonte',903705);
+INSERT INTO City VALUES (1468,'Palermo','ITA','Sisilia',683794);
+INSERT INTO City VALUES (1469,'Genova','ITA','Liguria',636104);
+INSERT INTO City VALUES (1470,'Bologna','ITA','Emilia-Romagna',381161);
+INSERT INTO City VALUES (1471,'Firenze','ITA','Toscana',376662);
+INSERT INTO City VALUES (1472,'Catania','ITA','Sisilia',337862);
+INSERT INTO City VALUES (1473,'Bari','ITA','Apulia',331848);
+INSERT INTO City VALUES (1474,'Venezia','ITA','Veneto',277305);
+INSERT INTO City VALUES (1475,'Messina','ITA','Sisilia',259156);
+INSERT INTO City VALUES (1476,'Verona','ITA','Veneto',255268);
+INSERT INTO City VALUES (1477,'Trieste','ITA','Friuli-Venezia Giuli',216459);
+INSERT INTO City VALUES (1478,'Padova','ITA','Veneto',211391);
+INSERT INTO City VALUES (1479,'Taranto','ITA','Apulia',208214);
+INSERT INTO City VALUES (1480,'Brescia','ITA','Lombardia',191317);
+INSERT INTO City VALUES (1481,'Reggio di Calabria','ITA','Calabria',179617);
+INSERT INTO City VALUES (1482,'Modena','ITA','Emilia-Romagna',176022);
+INSERT INTO City VALUES (1483,'Prato','ITA','Toscana',172473);
+INSERT INTO City VALUES (1484,'Parma','ITA','Emilia-Romagna',168717);
+INSERT INTO City VALUES (1485,'Cagliari','ITA','Sardinia',165926);
+INSERT INTO City VALUES (1486,'Livorno','ITA','Toscana',161673);
+INSERT INTO City VALUES (1487,'Perugia','ITA','Umbria',156673);
+INSERT INTO City VALUES (1488,'Foggia','ITA','Apulia',154891);
+INSERT INTO City VALUES (1489,'Reggio nell´ Emilia','ITA','Emilia-Romagna',143664);
+INSERT INTO City VALUES (1490,'Salerno','ITA','Campania',142055);
+INSERT INTO City VALUES (1491,'Ravenna','ITA','Emilia-Romagna',138418);
+INSERT INTO City VALUES (1492,'Ferrara','ITA','Emilia-Romagna',132127);
+INSERT INTO City VALUES (1493,'Rimini','ITA','Emilia-Romagna',131062);
+INSERT INTO City VALUES (1494,'Syrakusa','ITA','Sisilia',126282);
+INSERT INTO City VALUES (1495,'Sassari','ITA','Sardinia',120803);
+INSERT INTO City VALUES (1496,'Monza','ITA','Lombardia',119516);
+INSERT INTO City VALUES (1497,'Bergamo','ITA','Lombardia',117837);
+INSERT INTO City VALUES (1498,'Pescara','ITA','Abruzzit',115698);
+INSERT INTO City VALUES (1499,'Latina','ITA','Latium',114099);
+INSERT INTO City VALUES (1500,'Vicenza','ITA','Veneto',109738);
+INSERT INTO City VALUES (1501,'Terni','ITA','Umbria',107770);
+INSERT INTO City VALUES (1502,'Forlì','ITA','Emilia-Romagna',107475);
+INSERT INTO City VALUES (1503,'Trento','ITA','Trentino-Alto Adige',104906);
+INSERT INTO City VALUES (1504,'Novara','ITA','Piemonte',102037);
+INSERT INTO City VALUES (1505,'Piacenza','ITA','Emilia-Romagna',98384);
+INSERT INTO City VALUES (1506,'Ancona','ITA','Marche',98329);
+INSERT INTO City VALUES (1507,'Lecce','ITA','Apulia',98208);
+INSERT INTO City VALUES (1508,'Bolzano','ITA','Trentino-Alto Adige',97232);
+INSERT INTO City VALUES (1509,'Catanzaro','ITA','Calabria',96700);
+INSERT INTO City VALUES (1510,'La Spezia','ITA','Liguria',95504);
+INSERT INTO City VALUES (1511,'Udine','ITA','Friuli-Venezia Giuli',94932);
+INSERT INTO City VALUES (1512,'Torre del Greco','ITA','Campania',94505);
+INSERT INTO City VALUES (1513,'Andria','ITA','Apulia',94443);
+INSERT INTO City VALUES (1514,'Brindisi','ITA','Apulia',93454);
+INSERT INTO City VALUES (1515,'Giugliano in Campania','ITA','Campania',93286);
+INSERT INTO City VALUES (1516,'Pisa','ITA','Toscana',92379);
+INSERT INTO City VALUES (1517,'Barletta','ITA','Apulia',91904);
+INSERT INTO City VALUES (1518,'Arezzo','ITA','Toscana',91729);
+INSERT INTO City VALUES (1519,'Alessandria','ITA','Piemonte',90289);
+INSERT INTO City VALUES (1520,'Cesena','ITA','Emilia-Romagna',89852);
+INSERT INTO City VALUES (1521,'Pesaro','ITA','Marche',88987);
+INSERT INTO City VALUES (1522,'Dili','TMP','Dili',47900);
+INSERT INTO City VALUES (1523,'Wien','AUT','Wien',1608144);
+INSERT INTO City VALUES (1524,'Graz','AUT','Steiermark',240967);
+INSERT INTO City VALUES (1525,'Linz','AUT','North Austria',188022);
+INSERT INTO City VALUES (1526,'Salzburg','AUT','Salzburg',144247);
+INSERT INTO City VALUES (1527,'Innsbruck','AUT','Tiroli',111752);
+INSERT INTO City VALUES (1528,'Klagenfurt','AUT','Kärnten',91141);
+INSERT INTO City VALUES (1529,'Spanish Town','JAM','St. Catherine',110379);
+INSERT INTO City VALUES (1530,'Kingston','JAM','St. Andrew',103962);
+INSERT INTO City VALUES (1531,'Portmore','JAM','St. Andrew',99799);
+INSERT INTO City VALUES (1532,'Tokyo','JPN','Tokyo-to',7980230);
+INSERT INTO City VALUES (1533,'Jokohama [Yokohama]','JPN','Kanagawa',3339594);
+INSERT INTO City VALUES (1534,'Osaka','JPN','Osaka',2595674);
+INSERT INTO City VALUES (1535,'Nagoya','JPN','Aichi',2154376);
+INSERT INTO City VALUES (1536,'Sapporo','JPN','Hokkaido',1790886);
+INSERT INTO City VALUES (1537,'Kioto','JPN','Kyoto',1461974);
+INSERT INTO City VALUES (1538,'Kobe','JPN','Hyogo',1425139);
+INSERT INTO City VALUES (1539,'Fukuoka','JPN','Fukuoka',1308379);
+INSERT INTO City VALUES (1540,'Kawasaki','JPN','Kanagawa',1217359);
+INSERT INTO City VALUES (1541,'Hiroshima','JPN','Hiroshima',1119117);
+INSERT INTO City VALUES (1542,'Kitakyushu','JPN','Fukuoka',1016264);
+INSERT INTO City VALUES (1543,'Sendai','JPN','Miyagi',989975);
+INSERT INTO City VALUES (1544,'Chiba','JPN','Chiba',863930);
+INSERT INTO City VALUES (1545,'Sakai','JPN','Osaka',797735);
+INSERT INTO City VALUES (1546,'Kumamoto','JPN','Kumamoto',656734);
+INSERT INTO City VALUES (1547,'Okayama','JPN','Okayama',624269);
+INSERT INTO City VALUES (1548,'Sagamihara','JPN','Kanagawa',586300);
+INSERT INTO City VALUES (1549,'Hamamatsu','JPN','Shizuoka',568796);
+INSERT INTO City VALUES (1550,'Kagoshima','JPN','Kagoshima',549977);
+INSERT INTO City VALUES (1551,'Funabashi','JPN','Chiba',545299);
+INSERT INTO City VALUES (1552,'Higashiosaka','JPN','Osaka',517785);
+INSERT INTO City VALUES (1553,'Hachioji','JPN','Tokyo-to',513451);
+INSERT INTO City VALUES (1554,'Niigata','JPN','Niigata',497464);
+INSERT INTO City VALUES (1555,'Amagasaki','JPN','Hyogo',481434);
+INSERT INTO City VALUES (1556,'Himeji','JPN','Hyogo',475167);
+INSERT INTO City VALUES (1557,'Shizuoka','JPN','Shizuoka',473854);
+INSERT INTO City VALUES (1558,'Urawa','JPN','Saitama',469675);
+INSERT INTO City VALUES (1559,'Matsuyama','JPN','Ehime',466133);
+INSERT INTO City VALUES (1560,'Matsudo','JPN','Chiba',461126);
+INSERT INTO City VALUES (1561,'Kanazawa','JPN','Ishikawa',455386);
+INSERT INTO City VALUES (1562,'Kawaguchi','JPN','Saitama',452155);
+INSERT INTO City VALUES (1563,'Ichikawa','JPN','Chiba',441893);
+INSERT INTO City VALUES (1564,'Omiya','JPN','Saitama',441649);
+INSERT INTO City VALUES (1565,'Utsunomiya','JPN','Tochigi',440353);
+INSERT INTO City VALUES (1566,'Oita','JPN','Oita',433401);
+INSERT INTO City VALUES (1567,'Nagasaki','JPN','Nagasaki',432759);
+INSERT INTO City VALUES (1568,'Yokosuka','JPN','Kanagawa',430200);
+INSERT INTO City VALUES (1569,'Kurashiki','JPN','Okayama',425103);
+INSERT INTO City VALUES (1570,'Gifu','JPN','Gifu',408007);
+INSERT INTO City VALUES (1571,'Hirakata','JPN','Osaka',403151);
+INSERT INTO City VALUES (1572,'Nishinomiya','JPN','Hyogo',397618);
+INSERT INTO City VALUES (1573,'Toyonaka','JPN','Osaka',396689);
+INSERT INTO City VALUES (1574,'Wakayama','JPN','Wakayama',391233);
+INSERT INTO City VALUES (1575,'Fukuyama','JPN','Hiroshima',376921);
+INSERT INTO City VALUES (1576,'Fujisawa','JPN','Kanagawa',372840);
+INSERT INTO City VALUES (1577,'Asahikawa','JPN','Hokkaido',364813);
+INSERT INTO City VALUES (1578,'Machida','JPN','Tokyo-to',364197);
+INSERT INTO City VALUES (1579,'Nara','JPN','Nara',362812);
+INSERT INTO City VALUES (1580,'Takatsuki','JPN','Osaka',361747);
+INSERT INTO City VALUES (1581,'Iwaki','JPN','Fukushima',361737);
+INSERT INTO City VALUES (1582,'Nagano','JPN','Nagano',361391);
+INSERT INTO City VALUES (1583,'Toyohashi','JPN','Aichi',360066);
+INSERT INTO City VALUES (1584,'Toyota','JPN','Aichi',346090);
+INSERT INTO City VALUES (1585,'Suita','JPN','Osaka',345750);
+INSERT INTO City VALUES (1586,'Takamatsu','JPN','Kagawa',332471);
+INSERT INTO City VALUES (1587,'Koriyama','JPN','Fukushima',330335);
+INSERT INTO City VALUES (1588,'Okazaki','JPN','Aichi',328711);
+INSERT INTO City VALUES (1589,'Kawagoe','JPN','Saitama',327211);
+INSERT INTO City VALUES (1590,'Tokorozawa','JPN','Saitama',325809);
+INSERT INTO City VALUES (1591,'Toyama','JPN','Toyama',325790);
+INSERT INTO City VALUES (1592,'Kochi','JPN','Kochi',324710);
+INSERT INTO City VALUES (1593,'Kashiwa','JPN','Chiba',320296);
+INSERT INTO City VALUES (1594,'Akita','JPN','Akita',314440);
+INSERT INTO City VALUES (1595,'Miyazaki','JPN','Miyazaki',303784);
+INSERT INTO City VALUES (1596,'Koshigaya','JPN','Saitama',301446);
+INSERT INTO City VALUES (1597,'Naha','JPN','Okinawa',299851);
+INSERT INTO City VALUES (1598,'Aomori','JPN','Aomori',295969);
+INSERT INTO City VALUES (1599,'Hakodate','JPN','Hokkaido',294788);
+INSERT INTO City VALUES (1600,'Akashi','JPN','Hyogo',292253);
+INSERT INTO City VALUES (1601,'Yokkaichi','JPN','Mie',288173);
+INSERT INTO City VALUES (1602,'Fukushima','JPN','Fukushima',287525);
+INSERT INTO City VALUES (1603,'Morioka','JPN','Iwate',287353);
+INSERT INTO City VALUES (1604,'Maebashi','JPN','Gumma',284473);
+INSERT INTO City VALUES (1605,'Kasugai','JPN','Aichi',282348);
+INSERT INTO City VALUES (1606,'Otsu','JPN','Shiga',282070);
+INSERT INTO City VALUES (1607,'Ichihara','JPN','Chiba',279280);
+INSERT INTO City VALUES (1608,'Yao','JPN','Osaka',276421);
+INSERT INTO City VALUES (1609,'Ichinomiya','JPN','Aichi',270828);
+INSERT INTO City VALUES (1610,'Tokushima','JPN','Tokushima',269649);
+INSERT INTO City VALUES (1611,'Kakogawa','JPN','Hyogo',266281);
+INSERT INTO City VALUES (1612,'Ibaraki','JPN','Osaka',261020);
+INSERT INTO City VALUES (1613,'Neyagawa','JPN','Osaka',257315);
+INSERT INTO City VALUES (1614,'Shimonoseki','JPN','Yamaguchi',257263);
+INSERT INTO City VALUES (1615,'Yamagata','JPN','Yamagata',255617);
+INSERT INTO City VALUES (1616,'Fukui','JPN','Fukui',254818);
+INSERT INTO City VALUES (1617,'Hiratsuka','JPN','Kanagawa',254207);
+INSERT INTO City VALUES (1618,'Mito','JPN','Ibaragi',246559);
+INSERT INTO City VALUES (1619,'Sasebo','JPN','Nagasaki',244240);
+INSERT INTO City VALUES (1620,'Hachinohe','JPN','Aomori',242979);
+INSERT INTO City VALUES (1621,'Takasaki','JPN','Gumma',239124);
+INSERT INTO City VALUES (1622,'Shimizu','JPN','Shizuoka',239123);
+INSERT INTO City VALUES (1623,'Kurume','JPN','Fukuoka',235611);
+INSERT INTO City VALUES (1624,'Fuji','JPN','Shizuoka',231527);
+INSERT INTO City VALUES (1625,'Soka','JPN','Saitama',222768);
+INSERT INTO City VALUES (1626,'Fuchu','JPN','Tokyo-to',220576);
+INSERT INTO City VALUES (1627,'Chigasaki','JPN','Kanagawa',216015);
+INSERT INTO City VALUES (1628,'Atsugi','JPN','Kanagawa',212407);
+INSERT INTO City VALUES (1629,'Numazu','JPN','Shizuoka',211382);
+INSERT INTO City VALUES (1630,'Ageo','JPN','Saitama',209442);
+INSERT INTO City VALUES (1631,'Yamato','JPN','Kanagawa',208234);
+INSERT INTO City VALUES (1632,'Matsumoto','JPN','Nagano',206801);
+INSERT INTO City VALUES (1633,'Kure','JPN','Hiroshima',206504);
+INSERT INTO City VALUES (1634,'Takarazuka','JPN','Hyogo',205993);
+INSERT INTO City VALUES (1635,'Kasukabe','JPN','Saitama',201838);
+INSERT INTO City VALUES (1636,'Chofu','JPN','Tokyo-to',201585);
+INSERT INTO City VALUES (1637,'Odawara','JPN','Kanagawa',200171);
+INSERT INTO City VALUES (1638,'Kofu','JPN','Yamanashi',199753);
+INSERT INTO City VALUES (1639,'Kushiro','JPN','Hokkaido',197608);
+INSERT INTO City VALUES (1640,'Kishiwada','JPN','Osaka',197276);
+INSERT INTO City VALUES (1641,'Hitachi','JPN','Ibaragi',196622);
+INSERT INTO City VALUES (1642,'Nagaoka','JPN','Niigata',192407);
+INSERT INTO City VALUES (1643,'Itami','JPN','Hyogo',190886);
+INSERT INTO City VALUES (1644,'Uji','JPN','Kyoto',188735);
+INSERT INTO City VALUES (1645,'Suzuka','JPN','Mie',184061);
+INSERT INTO City VALUES (1646,'Hirosaki','JPN','Aomori',177522);
+INSERT INTO City VALUES (1647,'Ube','JPN','Yamaguchi',175206);
+INSERT INTO City VALUES (1648,'Kodaira','JPN','Tokyo-to',174984);
+INSERT INTO City VALUES (1649,'Takaoka','JPN','Toyama',174380);
+INSERT INTO City VALUES (1650,'Obihiro','JPN','Hokkaido',173685);
+INSERT INTO City VALUES (1651,'Tomakomai','JPN','Hokkaido',171958);
+INSERT INTO City VALUES (1652,'Saga','JPN','Saga',170034);
+INSERT INTO City VALUES (1653,'Sakura','JPN','Chiba',168072);
+INSERT INTO City VALUES (1654,'Kamakura','JPN','Kanagawa',167661);
+INSERT INTO City VALUES (1655,'Mitaka','JPN','Tokyo-to',167268);
+INSERT INTO City VALUES (1656,'Izumi','JPN','Osaka',166979);
+INSERT INTO City VALUES (1657,'Hino','JPN','Tokyo-to',166770);
+INSERT INTO City VALUES (1658,'Hadano','JPN','Kanagawa',166512);
+INSERT INTO City VALUES (1659,'Ashikaga','JPN','Tochigi',165243);
+INSERT INTO City VALUES (1660,'Tsu','JPN','Mie',164543);
+INSERT INTO City VALUES (1661,'Sayama','JPN','Saitama',162472);
+INSERT INTO City VALUES (1662,'Yachiyo','JPN','Chiba',161222);
+INSERT INTO City VALUES (1663,'Tsukuba','JPN','Ibaragi',160768);
+INSERT INTO City VALUES (1664,'Tachikawa','JPN','Tokyo-to',159430);
+INSERT INTO City VALUES (1665,'Kumagaya','JPN','Saitama',157171);
+INSERT INTO City VALUES (1666,'Moriguchi','JPN','Osaka',155941);
+INSERT INTO City VALUES (1667,'Otaru','JPN','Hokkaido',155784);
+INSERT INTO City VALUES (1668,'Anjo','JPN','Aichi',153823);
+INSERT INTO City VALUES (1669,'Narashino','JPN','Chiba',152849);
+INSERT INTO City VALUES (1670,'Oyama','JPN','Tochigi',152820);
+INSERT INTO City VALUES (1671,'Ogaki','JPN','Gifu',151758);
+INSERT INTO City VALUES (1672,'Matsue','JPN','Shimane',149821);
+INSERT INTO City VALUES (1673,'Kawanishi','JPN','Hyogo',149794);
+INSERT INTO City VALUES (1674,'Hitachinaka','JPN','Tokyo-to',148006);
+INSERT INTO City VALUES (1675,'Niiza','JPN','Saitama',147744);
+INSERT INTO City VALUES (1676,'Nagareyama','JPN','Chiba',147738);
+INSERT INTO City VALUES (1677,'Tottori','JPN','Tottori',147523);
+INSERT INTO City VALUES (1678,'Tama','JPN','Ibaragi',146712);
+INSERT INTO City VALUES (1679,'Iruma','JPN','Saitama',145922);
+INSERT INTO City VALUES (1680,'Ota','JPN','Gumma',145317);
+INSERT INTO City VALUES (1681,'Omuta','JPN','Fukuoka',142889);
+INSERT INTO City VALUES (1682,'Komaki','JPN','Aichi',139827);
+INSERT INTO City VALUES (1683,'Ome','JPN','Tokyo-to',139216);
+INSERT INTO City VALUES (1684,'Kadoma','JPN','Osaka',138953);
+INSERT INTO City VALUES (1685,'Yamaguchi','JPN','Yamaguchi',138210);
+INSERT INTO City VALUES (1686,'Higashimurayama','JPN','Tokyo-to',136970);
+INSERT INTO City VALUES (1687,'Yonago','JPN','Tottori',136461);
+INSERT INTO City VALUES (1688,'Matsubara','JPN','Osaka',135010);
+INSERT INTO City VALUES (1689,'Musashino','JPN','Tokyo-to',134426);
+INSERT INTO City VALUES (1690,'Tsuchiura','JPN','Ibaragi',134072);
+INSERT INTO City VALUES (1691,'Joetsu','JPN','Niigata',133505);
+INSERT INTO City VALUES (1692,'Miyakonojo','JPN','Miyazaki',133183);
+INSERT INTO City VALUES (1693,'Misato','JPN','Saitama',132957);
+INSERT INTO City VALUES (1694,'Kakamigahara','JPN','Gifu',131831);
+INSERT INTO City VALUES (1695,'Daito','JPN','Osaka',130594);
+INSERT INTO City VALUES (1696,'Seto','JPN','Aichi',130470);
+INSERT INTO City VALUES (1697,'Kariya','JPN','Aichi',127969);
+INSERT INTO City VALUES (1698,'Urayasu','JPN','Chiba',127550);
+INSERT INTO City VALUES (1699,'Beppu','JPN','Oita',127486);
+INSERT INTO City VALUES (1700,'Niihama','JPN','Ehime',127207);
+INSERT INTO City VALUES (1701,'Minoo','JPN','Osaka',127026);
+INSERT INTO City VALUES (1702,'Fujieda','JPN','Shizuoka',126897);
+INSERT INTO City VALUES (1703,'Abiko','JPN','Chiba',126670);
+INSERT INTO City VALUES (1704,'Nobeoka','JPN','Miyazaki',125547);
+INSERT INTO City VALUES (1705,'Tondabayashi','JPN','Osaka',125094);
+INSERT INTO City VALUES (1706,'Ueda','JPN','Nagano',124217);
+INSERT INTO City VALUES (1707,'Kashihara','JPN','Nara',124013);
+INSERT INTO City VALUES (1708,'Matsusaka','JPN','Mie',123582);
+INSERT INTO City VALUES (1709,'Isesaki','JPN','Gumma',123285);
+INSERT INTO City VALUES (1710,'Zama','JPN','Kanagawa',122046);
+INSERT INTO City VALUES (1711,'Kisarazu','JPN','Chiba',121967);
+INSERT INTO City VALUES (1712,'Noda','JPN','Chiba',121030);
+INSERT INTO City VALUES (1713,'Ishinomaki','JPN','Miyagi',120963);
+INSERT INTO City VALUES (1714,'Fujinomiya','JPN','Shizuoka',119714);
+INSERT INTO City VALUES (1715,'Kawachinagano','JPN','Osaka',119666);
+INSERT INTO City VALUES (1716,'Imabari','JPN','Ehime',119357);
+INSERT INTO City VALUES (1717,'Aizuwakamatsu','JPN','Fukushima',119287);
+INSERT INTO City VALUES (1718,'Higashihiroshima','JPN','Hiroshima',119166);
+INSERT INTO City VALUES (1719,'Habikino','JPN','Osaka',118968);
+INSERT INTO City VALUES (1720,'Ebetsu','JPN','Hokkaido',118805);
+INSERT INTO City VALUES (1721,'Hofu','JPN','Yamaguchi',118751);
+INSERT INTO City VALUES (1722,'Kiryu','JPN','Gumma',118326);
+INSERT INTO City VALUES (1723,'Okinawa','JPN','Okinawa',117748);
+INSERT INTO City VALUES (1724,'Yaizu','JPN','Shizuoka',117258);
+INSERT INTO City VALUES (1725,'Toyokawa','JPN','Aichi',115781);
+INSERT INTO City VALUES (1726,'Ebina','JPN','Kanagawa',115571);
+INSERT INTO City VALUES (1727,'Asaka','JPN','Saitama',114815);
+INSERT INTO City VALUES (1728,'Higashikurume','JPN','Tokyo-to',111666);
+INSERT INTO City VALUES (1729,'Ikoma','JPN','Nara',111645);
+INSERT INTO City VALUES (1730,'Kitami','JPN','Hokkaido',111295);
+INSERT INTO City VALUES (1731,'Koganei','JPN','Tokyo-to',110969);
+INSERT INTO City VALUES (1732,'Iwatsuki','JPN','Saitama',110034);
+INSERT INTO City VALUES (1733,'Mishima','JPN','Shizuoka',109699);
+INSERT INTO City VALUES (1734,'Handa','JPN','Aichi',108600);
+INSERT INTO City VALUES (1735,'Muroran','JPN','Hokkaido',108275);
+INSERT INTO City VALUES (1736,'Komatsu','JPN','Ishikawa',107937);
+INSERT INTO City VALUES (1737,'Yatsushiro','JPN','Kumamoto',107661);
+INSERT INTO City VALUES (1738,'Iida','JPN','Nagano',107583);
+INSERT INTO City VALUES (1739,'Tokuyama','JPN','Yamaguchi',107078);
+INSERT INTO City VALUES (1740,'Kokubunji','JPN','Tokyo-to',106996);
+INSERT INTO City VALUES (1741,'Akishima','JPN','Tokyo-to',106914);
+INSERT INTO City VALUES (1742,'Iwakuni','JPN','Yamaguchi',106647);
+INSERT INTO City VALUES (1743,'Kusatsu','JPN','Shiga',106232);
+INSERT INTO City VALUES (1744,'Kuwana','JPN','Mie',106121);
+INSERT INTO City VALUES (1745,'Sanda','JPN','Hyogo',105643);
+INSERT INTO City VALUES (1746,'Hikone','JPN','Shiga',105508);
+INSERT INTO City VALUES (1747,'Toda','JPN','Saitama',103969);
+INSERT INTO City VALUES (1748,'Tajimi','JPN','Gifu',103171);
+INSERT INTO City VALUES (1749,'Ikeda','JPN','Osaka',102710);
+INSERT INTO City VALUES (1750,'Fukaya','JPN','Saitama',102156);
+INSERT INTO City VALUES (1751,'Ise','JPN','Mie',101732);
+INSERT INTO City VALUES (1752,'Sakata','JPN','Yamagata',101651);
+INSERT INTO City VALUES (1753,'Kasuga','JPN','Fukuoka',101344);
+INSERT INTO City VALUES (1754,'Kamagaya','JPN','Chiba',100821);
+INSERT INTO City VALUES (1755,'Tsuruoka','JPN','Yamagata',100713);
+INSERT INTO City VALUES (1756,'Hoya','JPN','Tokyo-to',100313);
+INSERT INTO City VALUES (1757,'Nishio','JPN','Chiba',100032);
+INSERT INTO City VALUES (1758,'Tokai','JPN','Aichi',99738);
+INSERT INTO City VALUES (1759,'Inazawa','JPN','Aichi',98746);
+INSERT INTO City VALUES (1760,'Sakado','JPN','Saitama',98221);
+INSERT INTO City VALUES (1761,'Isehara','JPN','Kanagawa',98123);
+INSERT INTO City VALUES (1762,'Takasago','JPN','Hyogo',97632);
+INSERT INTO City VALUES (1763,'Fujimi','JPN','Saitama',96972);
+INSERT INTO City VALUES (1764,'Urasoe','JPN','Okinawa',96002);
+INSERT INTO City VALUES (1765,'Yonezawa','JPN','Yamagata',95592);
+INSERT INTO City VALUES (1766,'Konan','JPN','Aichi',95521);
+INSERT INTO City VALUES (1767,'Yamatokoriyama','JPN','Nara',95165);
+INSERT INTO City VALUES (1768,'Maizuru','JPN','Kyoto',94784);
+INSERT INTO City VALUES (1769,'Onomichi','JPN','Hiroshima',93756);
+INSERT INTO City VALUES (1770,'Higashimatsuyama','JPN','Saitama',93342);
+INSERT INTO City VALUES (1771,'Kimitsu','JPN','Chiba',93216);
+INSERT INTO City VALUES (1772,'Isahaya','JPN','Nagasaki',93058);
+INSERT INTO City VALUES (1773,'Kanuma','JPN','Tochigi',93053);
+INSERT INTO City VALUES (1774,'Izumisano','JPN','Osaka',92583);
+INSERT INTO City VALUES (1775,'Kameoka','JPN','Kyoto',92398);
+INSERT INTO City VALUES (1776,'Mobara','JPN','Chiba',91664);
+INSERT INTO City VALUES (1777,'Narita','JPN','Chiba',91470);
+INSERT INTO City VALUES (1778,'Kashiwazaki','JPN','Niigata',91229);
+INSERT INTO City VALUES (1779,'Tsuyama','JPN','Okayama',91170);
+INSERT INTO City VALUES (1780,'Sanaa','YEM','Sanaa',503600);
+INSERT INTO City VALUES (1781,'Aden','YEM','Aden',398300);
+INSERT INTO City VALUES (1782,'Taizz','YEM','Taizz',317600);
+INSERT INTO City VALUES (1783,'Hodeida','YEM','Hodeida',298500);
+INSERT INTO City VALUES (1784,'al-Mukalla','YEM','Hadramawt',122400);
+INSERT INTO City VALUES (1785,'Ibb','YEM','Ibb',103300);
+INSERT INTO City VALUES (1786,'Amman','JOR','Amman',1000000);
+INSERT INTO City VALUES (1787,'al-Zarqa','JOR','al-Zarqa',389815);
+INSERT INTO City VALUES (1788,'Irbid','JOR','Irbid',231511);
+INSERT INTO City VALUES (1789,'al-Rusayfa','JOR','al-Zarqa',137247);
+INSERT INTO City VALUES (1790,'Wadi al-Sir','JOR','Amman',89104);
+INSERT INTO City VALUES (1791,'Flying Fish Cove','CXR','–',700);
+INSERT INTO City VALUES (1792,'Beograd','YUG','Central Serbia',1204000);
+INSERT INTO City VALUES (1793,'Novi Sad','YUG','Vojvodina',179626);
+INSERT INTO City VALUES (1794,'Niš','YUG','Central Serbia',175391);
+INSERT INTO City VALUES (1795,'Priština','YUG','Kosovo and Metohija',155496);
+INSERT INTO City VALUES (1796,'Kragujevac','YUG','Central Serbia',147305);
+INSERT INTO City VALUES (1797,'Podgorica','YUG','Montenegro',135000);
+INSERT INTO City VALUES (1798,'Subotica','YUG','Vojvodina',100386);
+INSERT INTO City VALUES (1799,'Prizren','YUG','Kosovo and Metohija',92303);
+INSERT INTO City VALUES (1800,'Phnom Penh','KHM','Phnom Penh',570155);
+INSERT INTO City VALUES (1801,'Battambang','KHM','Battambang',129800);
+INSERT INTO City VALUES (1802,'Siem Reap','KHM','Siem Reap',105100);
+INSERT INTO City VALUES (1803,'Douala','CMR','Littoral',1448300);
+INSERT INTO City VALUES (1804,'Yaoundé','CMR','Centre',1372800);
+INSERT INTO City VALUES (1805,'Garoua','CMR','Nord',177000);
+INSERT INTO City VALUES (1806,'Maroua','CMR','Extrême-Nord',143000);
+INSERT INTO City VALUES (1807,'Bamenda','CMR','Nord-Ouest',138000);
+INSERT INTO City VALUES (1808,'Bafoussam','CMR','Ouest',131000);
+INSERT INTO City VALUES (1809,'Nkongsamba','CMR','Littoral',112454);
+INSERT INTO City VALUES (1810,'Montréal','CAN','Québec',1016376);
+INSERT INTO City VALUES (1811,'Calgary','CAN','Alberta',768082);
+INSERT INTO City VALUES (1812,'Toronto','CAN','Ontario',688275);
+INSERT INTO City VALUES (1813,'North York','CAN','Ontario',622632);
+INSERT INTO City VALUES (1814,'Winnipeg','CAN','Manitoba',618477);
+INSERT INTO City VALUES (1815,'Edmonton','CAN','Alberta',616306);
+INSERT INTO City VALUES (1816,'Mississauga','CAN','Ontario',608072);
+INSERT INTO City VALUES (1817,'Scarborough','CAN','Ontario',594501);
+INSERT INTO City VALUES (1818,'Vancouver','CAN','British Colombia',514008);
+INSERT INTO City VALUES (1819,'Etobicoke','CAN','Ontario',348845);
+INSERT INTO City VALUES (1820,'London','CAN','Ontario',339917);
+INSERT INTO City VALUES (1821,'Hamilton','CAN','Ontario',335614);
+INSERT INTO City VALUES (1822,'Ottawa','CAN','Ontario',335277);
+INSERT INTO City VALUES (1823,'Laval','CAN','Québec',330393);
+INSERT INTO City VALUES (1824,'Surrey','CAN','British Colombia',304477);
+INSERT INTO City VALUES (1825,'Brampton','CAN','Ontario',296711);
+INSERT INTO City VALUES (1826,'Windsor','CAN','Ontario',207588);
+INSERT INTO City VALUES (1827,'Saskatoon','CAN','Saskatchewan',193647);
+INSERT INTO City VALUES (1828,'Kitchener','CAN','Ontario',189959);
+INSERT INTO City VALUES (1829,'Markham','CAN','Ontario',189098);
+INSERT INTO City VALUES (1830,'Regina','CAN','Saskatchewan',180400);
+INSERT INTO City VALUES (1831,'Burnaby','CAN','British Colombia',179209);
+INSERT INTO City VALUES (1832,'Québec','CAN','Québec',167264);
+INSERT INTO City VALUES (1833,'York','CAN','Ontario',154980);
+INSERT INTO City VALUES (1834,'Richmond','CAN','British Colombia',148867);
+INSERT INTO City VALUES (1835,'Vaughan','CAN','Ontario',147889);
+INSERT INTO City VALUES (1836,'Burlington','CAN','Ontario',145150);
+INSERT INTO City VALUES (1837,'Oshawa','CAN','Ontario',140173);
+INSERT INTO City VALUES (1838,'Oakville','CAN','Ontario',139192);
+INSERT INTO City VALUES (1839,'Saint Catharines','CAN','Ontario',136216);
+INSERT INTO City VALUES (1840,'Longueuil','CAN','Québec',127977);
+INSERT INTO City VALUES (1841,'Richmond Hill','CAN','Ontario',116428);
+INSERT INTO City VALUES (1842,'Thunder Bay','CAN','Ontario',115913);
+INSERT INTO City VALUES (1843,'Nepean','CAN','Ontario',115100);
+INSERT INTO City VALUES (1844,'Cape Breton','CAN','Nova Scotia',114733);
+INSERT INTO City VALUES (1845,'East York','CAN','Ontario',114034);
+INSERT INTO City VALUES (1846,'Halifax','CAN','Nova Scotia',113910);
+INSERT INTO City VALUES (1847,'Cambridge','CAN','Ontario',109186);
+INSERT INTO City VALUES (1848,'Gloucester','CAN','Ontario',107314);
+INSERT INTO City VALUES (1849,'Abbotsford','CAN','British Colombia',105403);
+INSERT INTO City VALUES (1850,'Guelph','CAN','Ontario',103593);
+INSERT INTO City VALUES (1851,'Saint John´s','CAN','Newfoundland',101936);
+INSERT INTO City VALUES (1852,'Coquitlam','CAN','British Colombia',101820);
+INSERT INTO City VALUES (1853,'Saanich','CAN','British Colombia',101388);
+INSERT INTO City VALUES (1854,'Gatineau','CAN','Québec',100702);
+INSERT INTO City VALUES (1855,'Delta','CAN','British Colombia',95411);
+INSERT INTO City VALUES (1856,'Sudbury','CAN','Ontario',92686);
+INSERT INTO City VALUES (1857,'Kelowna','CAN','British Colombia',89442);
+INSERT INTO City VALUES (1858,'Barrie','CAN','Ontario',89269);
+INSERT INTO City VALUES (1859,'Praia','CPV','São Tiago',94800);
+INSERT INTO City VALUES (1860,'Almaty','KAZ','Almaty Qalasy',1129400);
+INSERT INTO City VALUES (1861,'Qaraghandy','KAZ','Qaraghandy',436900);
+INSERT INTO City VALUES (1862,'Shymkent','KAZ','South Kazakstan',360100);
+INSERT INTO City VALUES (1863,'Taraz','KAZ','Taraz',330100);
+INSERT INTO City VALUES (1864,'Astana','KAZ','Astana',311200);
+INSERT INTO City VALUES (1865,'Öskemen','KAZ','East Kazakstan',311000);
+INSERT INTO City VALUES (1866,'Pavlodar','KAZ','Pavlodar',300500);
+INSERT INTO City VALUES (1867,'Semey','KAZ','East Kazakstan',269600);
+INSERT INTO City VALUES (1868,'Aqtöbe','KAZ','Aqtöbe',253100);
+INSERT INTO City VALUES (1869,'Qostanay','KAZ','Qostanay',221400);
+INSERT INTO City VALUES (1870,'Petropavl','KAZ','North Kazakstan',203500);
+INSERT INTO City VALUES (1871,'Oral','KAZ','West Kazakstan',195500);
+INSERT INTO City VALUES (1872,'Temirtau','KAZ','Qaraghandy',170500);
+INSERT INTO City VALUES (1873,'Qyzylorda','KAZ','Qyzylorda',157400);
+INSERT INTO City VALUES (1874,'Aqtau','KAZ','Mangghystau',143400);
+INSERT INTO City VALUES (1875,'Atyrau','KAZ','Atyrau',142500);
+INSERT INTO City VALUES (1876,'Ekibastuz','KAZ','Pavlodar',127200);
+INSERT INTO City VALUES (1877,'Kökshetau','KAZ','North Kazakstan',123400);
+INSERT INTO City VALUES (1878,'Rudnyy','KAZ','Qostanay',109500);
+INSERT INTO City VALUES (1879,'Taldyqorghan','KAZ','Almaty',98000);
+INSERT INTO City VALUES (1880,'Zhezqazghan','KAZ','Qaraghandy',90000);
+INSERT INTO City VALUES (1881,'Nairobi','KEN','Nairobi',2290000);
+INSERT INTO City VALUES (1882,'Mombasa','KEN','Coast',461753);
+INSERT INTO City VALUES (1883,'Kisumu','KEN','Nyanza',192733);
+INSERT INTO City VALUES (1884,'Nakuru','KEN','Rift Valley',163927);
+INSERT INTO City VALUES (1885,'Machakos','KEN','Eastern',116293);
+INSERT INTO City VALUES (1886,'Eldoret','KEN','Rift Valley',111882);
+INSERT INTO City VALUES (1887,'Meru','KEN','Eastern',94947);
+INSERT INTO City VALUES (1888,'Nyeri','KEN','Central',91258);
+INSERT INTO City VALUES (1889,'Bangui','CAF','Bangui',524000);
+INSERT INTO City VALUES (1890,'Shanghai','CHN','Shanghai',9696300);
+INSERT INTO City VALUES (1891,'Peking','CHN','Peking',7472000);
+INSERT INTO City VALUES (1892,'Chongqing','CHN','Chongqing',6351600);
+INSERT INTO City VALUES (1893,'Tianjin','CHN','Tianjin',5286800);
+INSERT INTO City VALUES (1894,'Wuhan','CHN','Hubei',4344600);
+INSERT INTO City VALUES (1895,'Harbin','CHN','Heilongjiang',4289800);
+INSERT INTO City VALUES (1896,'Shenyang','CHN','Liaoning',4265200);
+INSERT INTO City VALUES (1897,'Kanton [Guangzhou]','CHN','Guangdong',4256300);
+INSERT INTO City VALUES (1898,'Chengdu','CHN','Sichuan',3361500);
+INSERT INTO City VALUES (1899,'Nanking [Nanjing]','CHN','Jiangsu',2870300);
+INSERT INTO City VALUES (1900,'Changchun','CHN','Jilin',2812000);
+INSERT INTO City VALUES (1901,'Xi´an','CHN','Shaanxi',2761400);
+INSERT INTO City VALUES (1902,'Dalian','CHN','Liaoning',2697000);
+INSERT INTO City VALUES (1903,'Qingdao','CHN','Shandong',2596000);
+INSERT INTO City VALUES (1904,'Jinan','CHN','Shandong',2278100);
+INSERT INTO City VALUES (1905,'Hangzhou','CHN','Zhejiang',2190500);
+INSERT INTO City VALUES (1906,'Zhengzhou','CHN','Henan',2107200);
+INSERT INTO City VALUES (1907,'Shijiazhuang','CHN','Hebei',2041500);
+INSERT INTO City VALUES (1908,'Taiyuan','CHN','Shanxi',1968400);
+INSERT INTO City VALUES (1909,'Kunming','CHN','Yunnan',1829500);
+INSERT INTO City VALUES (1910,'Changsha','CHN','Hunan',1809800);
+INSERT INTO City VALUES (1911,'Nanchang','CHN','Jiangxi',1691600);
+INSERT INTO City VALUES (1912,'Fuzhou','CHN','Fujian',1593800);
+INSERT INTO City VALUES (1913,'Lanzhou','CHN','Gansu',1565800);
+INSERT INTO City VALUES (1914,'Guiyang','CHN','Guizhou',1465200);
+INSERT INTO City VALUES (1915,'Ningbo','CHN','Zhejiang',1371200);
+INSERT INTO City VALUES (1916,'Hefei','CHN','Anhui',1369100);
+INSERT INTO City VALUES (1917,'Urumtši [Ürümqi]','CHN','Xinxiang',1310100);
+INSERT INTO City VALUES (1918,'Anshan','CHN','Liaoning',1200000);
+INSERT INTO City VALUES (1919,'Fushun','CHN','Liaoning',1200000);
+INSERT INTO City VALUES (1920,'Nanning','CHN','Guangxi',1161800);
+INSERT INTO City VALUES (1921,'Zibo','CHN','Shandong',1140000);
+INSERT INTO City VALUES (1922,'Qiqihar','CHN','Heilongjiang',1070000);
+INSERT INTO City VALUES (1923,'Jilin','CHN','Jilin',1040000);
+INSERT INTO City VALUES (1924,'Tangshan','CHN','Hebei',1040000);
+INSERT INTO City VALUES (1925,'Baotou','CHN','Inner Mongolia',980000);
+INSERT INTO City VALUES (1926,'Shenzhen','CHN','Guangdong',950500);
+INSERT INTO City VALUES (1927,'Hohhot','CHN','Inner Mongolia',916700);
+INSERT INTO City VALUES (1928,'Handan','CHN','Hebei',840000);
+INSERT INTO City VALUES (1929,'Wuxi','CHN','Jiangsu',830000);
+INSERT INTO City VALUES (1930,'Xuzhou','CHN','Jiangsu',810000);
+INSERT INTO City VALUES (1931,'Datong','CHN','Shanxi',800000);
+INSERT INTO City VALUES (1932,'Yichun','CHN','Heilongjiang',800000);
+INSERT INTO City VALUES (1933,'Benxi','CHN','Liaoning',770000);
+INSERT INTO City VALUES (1934,'Luoyang','CHN','Henan',760000);
+INSERT INTO City VALUES (1935,'Suzhou','CHN','Jiangsu',710000);
+INSERT INTO City VALUES (1936,'Xining','CHN','Qinghai',700200);
+INSERT INTO City VALUES (1937,'Huainan','CHN','Anhui',700000);
+INSERT INTO City VALUES (1938,'Jixi','CHN','Heilongjiang',683885);
+INSERT INTO City VALUES (1939,'Daqing','CHN','Heilongjiang',660000);
+INSERT INTO City VALUES (1940,'Fuxin','CHN','Liaoning',640000);
+INSERT INTO City VALUES (1941,'Amoy [Xiamen]','CHN','Fujian',627500);
+INSERT INTO City VALUES (1942,'Liuzhou','CHN','Guangxi',610000);
+INSERT INTO City VALUES (1943,'Shantou','CHN','Guangdong',580000);
+INSERT INTO City VALUES (1944,'Jinzhou','CHN','Liaoning',570000);
+INSERT INTO City VALUES (1945,'Mudanjiang','CHN','Heilongjiang',570000);
+INSERT INTO City VALUES (1946,'Yinchuan','CHN','Ningxia',544500);
+INSERT INTO City VALUES (1947,'Changzhou','CHN','Jiangsu',530000);
+INSERT INTO City VALUES (1948,'Zhangjiakou','CHN','Hebei',530000);
+INSERT INTO City VALUES (1949,'Dandong','CHN','Liaoning',520000);
+INSERT INTO City VALUES (1950,'Hegang','CHN','Heilongjiang',520000);
+INSERT INTO City VALUES (1951,'Kaifeng','CHN','Henan',510000);
+INSERT INTO City VALUES (1952,'Jiamusi','CHN','Heilongjiang',493409);
+INSERT INTO City VALUES (1953,'Liaoyang','CHN','Liaoning',492559);
+INSERT INTO City VALUES (1954,'Hengyang','CHN','Hunan',487148);
+INSERT INTO City VALUES (1955,'Baoding','CHN','Hebei',483155);
+INSERT INTO City VALUES (1956,'Hunjiang','CHN','Jilin',482043);
+INSERT INTO City VALUES (1957,'Xinxiang','CHN','Henan',473762);
+INSERT INTO City VALUES (1958,'Huangshi','CHN','Hubei',457601);
+INSERT INTO City VALUES (1959,'Haikou','CHN','Hainan',454300);
+INSERT INTO City VALUES (1960,'Yantai','CHN','Shandong',452127);
+INSERT INTO City VALUES (1961,'Bengbu','CHN','Anhui',449245);
+INSERT INTO City VALUES (1962,'Xiangtan','CHN','Hunan',441968);
+INSERT INTO City VALUES (1963,'Weifang','CHN','Shandong',428522);
+INSERT INTO City VALUES (1964,'Wuhu','CHN','Anhui',425740);
+INSERT INTO City VALUES (1965,'Pingxiang','CHN','Jiangxi',425579);
+INSERT INTO City VALUES (1966,'Yingkou','CHN','Liaoning',421589);
+INSERT INTO City VALUES (1967,'Anyang','CHN','Henan',420332);
+INSERT INTO City VALUES (1968,'Panzhihua','CHN','Sichuan',415466);
+INSERT INTO City VALUES (1969,'Pingdingshan','CHN','Henan',410775);
+INSERT INTO City VALUES (1970,'Xiangfan','CHN','Hubei',410407);
+INSERT INTO City VALUES (1971,'Zhuzhou','CHN','Hunan',409924);
+INSERT INTO City VALUES (1972,'Jiaozuo','CHN','Henan',409100);
+INSERT INTO City VALUES (1973,'Wenzhou','CHN','Zhejiang',401871);
+INSERT INTO City VALUES (1974,'Zhangjiang','CHN','Guangdong',400997);
+INSERT INTO City VALUES (1975,'Zigong','CHN','Sichuan',393184);
+INSERT INTO City VALUES (1976,'Shuangyashan','CHN','Heilongjiang',386081);
+INSERT INTO City VALUES (1977,'Zaozhuang','CHN','Shandong',380846);
+INSERT INTO City VALUES (1978,'Yakeshi','CHN','Inner Mongolia',377869);
+INSERT INTO City VALUES (1979,'Yichang','CHN','Hubei',371601);
+INSERT INTO City VALUES (1980,'Zhenjiang','CHN','Jiangsu',368316);
+INSERT INTO City VALUES (1981,'Huaibei','CHN','Anhui',366549);
+INSERT INTO City VALUES (1982,'Qinhuangdao','CHN','Hebei',364972);
+INSERT INTO City VALUES (1983,'Guilin','CHN','Guangxi',364130);
+INSERT INTO City VALUES (1984,'Liupanshui','CHN','Guizhou',363954);
+INSERT INTO City VALUES (1985,'Panjin','CHN','Liaoning',362773);
+INSERT INTO City VALUES (1986,'Yangquan','CHN','Shanxi',362268);
+INSERT INTO City VALUES (1987,'Jinxi','CHN','Liaoning',357052);
+INSERT INTO City VALUES (1988,'Liaoyuan','CHN','Jilin',354141);
+INSERT INTO City VALUES (1989,'Lianyungang','CHN','Jiangsu',354139);
+INSERT INTO City VALUES (1990,'Xianyang','CHN','Shaanxi',352125);
+INSERT INTO City VALUES (1991,'Tai´an','CHN','Shandong',350696);
+INSERT INTO City VALUES (1992,'Chifeng','CHN','Inner Mongolia',350077);
+INSERT INTO City VALUES (1993,'Shaoguan','CHN','Guangdong',350043);
+INSERT INTO City VALUES (1994,'Nantong','CHN','Jiangsu',343341);
+INSERT INTO City VALUES (1995,'Leshan','CHN','Sichuan',341128);
+INSERT INTO City VALUES (1996,'Baoji','CHN','Shaanxi',337765);
+INSERT INTO City VALUES (1997,'Linyi','CHN','Shandong',324720);
+INSERT INTO City VALUES (1998,'Tonghua','CHN','Jilin',324600);
+INSERT INTO City VALUES (1999,'Siping','CHN','Jilin',317223);
+INSERT INTO City VALUES (2000,'Changzhi','CHN','Shanxi',317144);
+INSERT INTO City VALUES (2001,'Tengzhou','CHN','Shandong',315083);
+INSERT INTO City VALUES (2002,'Chaozhou','CHN','Guangdong',313469);
+INSERT INTO City VALUES (2003,'Yangzhou','CHN','Jiangsu',312892);
+INSERT INTO City VALUES (2004,'Dongwan','CHN','Guangdong',308669);
+INSERT INTO City VALUES (2005,'Ma´anshan','CHN','Anhui',305421);
+INSERT INTO City VALUES (2006,'Foshan','CHN','Guangdong',303160);
+INSERT INTO City VALUES (2007,'Yueyang','CHN','Hunan',302800);
+INSERT INTO City VALUES (2008,'Xingtai','CHN','Hebei',302789);
+INSERT INTO City VALUES (2009,'Changde','CHN','Hunan',301276);
+INSERT INTO City VALUES (2010,'Shihezi','CHN','Xinxiang',299676);
+INSERT INTO City VALUES (2011,'Yancheng','CHN','Jiangsu',296831);
+INSERT INTO City VALUES (2012,'Jiujiang','CHN','Jiangxi',291187);
+INSERT INTO City VALUES (2013,'Dongying','CHN','Shandong',281728);
+INSERT INTO City VALUES (2014,'Shashi','CHN','Hubei',281352);
+INSERT INTO City VALUES (2015,'Xintai','CHN','Shandong',281248);
+INSERT INTO City VALUES (2016,'Jingdezhen','CHN','Jiangxi',281183);
+INSERT INTO City VALUES (2017,'Tongchuan','CHN','Shaanxi',280657);
+INSERT INTO City VALUES (2018,'Zhongshan','CHN','Guangdong',278829);
+INSERT INTO City VALUES (2019,'Shiyan','CHN','Hubei',273786);
+INSERT INTO City VALUES (2020,'Tieli','CHN','Heilongjiang',265683);
+INSERT INTO City VALUES (2021,'Jining','CHN','Shandong',265248);
+INSERT INTO City VALUES (2022,'Wuhai','CHN','Inner Mongolia',264081);
+INSERT INTO City VALUES (2023,'Mianyang','CHN','Sichuan',262947);
+INSERT INTO City VALUES (2024,'Luzhou','CHN','Sichuan',262892);
+INSERT INTO City VALUES (2025,'Zunyi','CHN','Guizhou',261862);
+INSERT INTO City VALUES (2026,'Shizuishan','CHN','Ningxia',257862);
+INSERT INTO City VALUES (2027,'Neijiang','CHN','Sichuan',256012);
+INSERT INTO City VALUES (2028,'Tongliao','CHN','Inner Mongolia',255129);
+INSERT INTO City VALUES (2029,'Tieling','CHN','Liaoning',254842);
+INSERT INTO City VALUES (2030,'Wafangdian','CHN','Liaoning',251733);
+INSERT INTO City VALUES (2031,'Anqing','CHN','Anhui',250718);
+INSERT INTO City VALUES (2032,'Shaoyang','CHN','Hunan',247227);
+INSERT INTO City VALUES (2033,'Laiwu','CHN','Shandong',246833);
+INSERT INTO City VALUES (2034,'Chengde','CHN','Hebei',246799);
+INSERT INTO City VALUES (2035,'Tianshui','CHN','Gansu',244974);
+INSERT INTO City VALUES (2036,'Nanyang','CHN','Henan',243303);
+INSERT INTO City VALUES (2037,'Cangzhou','CHN','Hebei',242708);
+INSERT INTO City VALUES (2038,'Yibin','CHN','Sichuan',241019);
+INSERT INTO City VALUES (2039,'Huaiyin','CHN','Jiangsu',239675);
+INSERT INTO City VALUES (2040,'Dunhua','CHN','Jilin',235100);
+INSERT INTO City VALUES (2041,'Yanji','CHN','Jilin',230892);
+INSERT INTO City VALUES (2042,'Jiangmen','CHN','Guangdong',230587);
+INSERT INTO City VALUES (2043,'Tongling','CHN','Anhui',228017);
+INSERT INTO City VALUES (2044,'Suihua','CHN','Heilongjiang',227881);
+INSERT INTO City VALUES (2045,'Gongziling','CHN','Jilin',226569);
+INSERT INTO City VALUES (2046,'Xiantao','CHN','Hubei',222884);
+INSERT INTO City VALUES (2047,'Chaoyang','CHN','Liaoning',222394);
+INSERT INTO City VALUES (2048,'Ganzhou','CHN','Jiangxi',220129);
+INSERT INTO City VALUES (2049,'Huzhou','CHN','Zhejiang',218071);
+INSERT INTO City VALUES (2050,'Baicheng','CHN','Jilin',217987);
+INSERT INTO City VALUES (2051,'Shangzi','CHN','Heilongjiang',215373);
+INSERT INTO City VALUES (2052,'Yangjiang','CHN','Guangdong',215196);
+INSERT INTO City VALUES (2053,'Qitaihe','CHN','Heilongjiang',214957);
+INSERT INTO City VALUES (2054,'Gejiu','CHN','Yunnan',214294);
+INSERT INTO City VALUES (2055,'Jiangyin','CHN','Jiangsu',213659);
+INSERT INTO City VALUES (2056,'Hebi','CHN','Henan',212976);
+INSERT INTO City VALUES (2057,'Jiaxing','CHN','Zhejiang',211526);
+INSERT INTO City VALUES (2058,'Wuzhou','CHN','Guangxi',210452);
+INSERT INTO City VALUES (2059,'Meihekou','CHN','Jilin',209038);
+INSERT INTO City VALUES (2060,'Xuchang','CHN','Henan',208815);
+INSERT INTO City VALUES (2061,'Liaocheng','CHN','Shandong',207844);
+INSERT INTO City VALUES (2062,'Haicheng','CHN','Liaoning',205560);
+INSERT INTO City VALUES (2063,'Qianjiang','CHN','Hubei',205504);
+INSERT INTO City VALUES (2064,'Baiyin','CHN','Gansu',204970);
+INSERT INTO City VALUES (2065,'Bei´an','CHN','Heilongjiang',204899);
+INSERT INTO City VALUES (2066,'Yixing','CHN','Jiangsu',200824);
+INSERT INTO City VALUES (2067,'Laizhou','CHN','Shandong',198664);
+INSERT INTO City VALUES (2068,'Qaramay','CHN','Xinxiang',197602);
+INSERT INTO City VALUES (2069,'Acheng','CHN','Heilongjiang',197595);
+INSERT INTO City VALUES (2070,'Dezhou','CHN','Shandong',195485);
+INSERT INTO City VALUES (2071,'Nanping','CHN','Fujian',195064);
+INSERT INTO City VALUES (2072,'Zhaoqing','CHN','Guangdong',194784);
+INSERT INTO City VALUES (2073,'Beipiao','CHN','Liaoning',194301);
+INSERT INTO City VALUES (2074,'Fengcheng','CHN','Jiangxi',193784);
+INSERT INTO City VALUES (2075,'Fuyu','CHN','Jilin',192981);
+INSERT INTO City VALUES (2076,'Xinyang','CHN','Henan',192509);
+INSERT INTO City VALUES (2077,'Dongtai','CHN','Jiangsu',192247);
+INSERT INTO City VALUES (2078,'Yuci','CHN','Shanxi',191356);
+INSERT INTO City VALUES (2079,'Honghu','CHN','Hubei',190772);
+INSERT INTO City VALUES (2080,'Ezhou','CHN','Hubei',190123);
+INSERT INTO City VALUES (2081,'Heze','CHN','Shandong',189293);
+INSERT INTO City VALUES (2082,'Daxian','CHN','Sichuan',188101);
+INSERT INTO City VALUES (2083,'Linfen','CHN','Shanxi',187309);
+INSERT INTO City VALUES (2084,'Tianmen','CHN','Hubei',186332);
+INSERT INTO City VALUES (2085,'Yiyang','CHN','Hunan',185818);
+INSERT INTO City VALUES (2086,'Quanzhou','CHN','Fujian',185154);
+INSERT INTO City VALUES (2087,'Rizhao','CHN','Shandong',185048);
+INSERT INTO City VALUES (2088,'Deyang','CHN','Sichuan',182488);
+INSERT INTO City VALUES (2089,'Guangyuan','CHN','Sichuan',182241);
+INSERT INTO City VALUES (2090,'Changshu','CHN','Jiangsu',181805);
+INSERT INTO City VALUES (2091,'Zhangzhou','CHN','Fujian',181424);
+INSERT INTO City VALUES (2092,'Hailar','CHN','Inner Mongolia',180650);
+INSERT INTO City VALUES (2093,'Nanchong','CHN','Sichuan',180273);
+INSERT INTO City VALUES (2094,'Jiutai','CHN','Jilin',180130);
+INSERT INTO City VALUES (2095,'Zhaodong','CHN','Heilongjiang',179976);
+INSERT INTO City VALUES (2096,'Shaoxing','CHN','Zhejiang',179818);
+INSERT INTO City VALUES (2097,'Fuyang','CHN','Anhui',179572);
+INSERT INTO City VALUES (2098,'Maoming','CHN','Guangdong',178683);
+INSERT INTO City VALUES (2099,'Qujing','CHN','Yunnan',178669);
+INSERT INTO City VALUES (2100,'Ghulja','CHN','Xinxiang',177193);
+INSERT INTO City VALUES (2101,'Jiaohe','CHN','Jilin',176367);
+INSERT INTO City VALUES (2102,'Puyang','CHN','Henan',175988);
+INSERT INTO City VALUES (2103,'Huadian','CHN','Jilin',175873);
+INSERT INTO City VALUES (2104,'Jiangyou','CHN','Sichuan',175753);
+INSERT INTO City VALUES (2105,'Qashqar','CHN','Xinxiang',174570);
+INSERT INTO City VALUES (2106,'Anshun','CHN','Guizhou',174142);
+INSERT INTO City VALUES (2107,'Fuling','CHN','Sichuan',173878);
+INSERT INTO City VALUES (2108,'Xinyu','CHN','Jiangxi',173524);
+INSERT INTO City VALUES (2109,'Hanzhong','CHN','Shaanxi',169930);
+INSERT INTO City VALUES (2110,'Danyang','CHN','Jiangsu',169603);
+INSERT INTO City VALUES (2111,'Chenzhou','CHN','Hunan',169400);
+INSERT INTO City VALUES (2112,'Xiaogan','CHN','Hubei',166280);
+INSERT INTO City VALUES (2113,'Shangqiu','CHN','Henan',164880);
+INSERT INTO City VALUES (2114,'Zhuhai','CHN','Guangdong',164747);
+INSERT INTO City VALUES (2115,'Qingyuan','CHN','Guangdong',164641);
+INSERT INTO City VALUES (2116,'Aqsu','CHN','Xinxiang',164092);
+INSERT INTO City VALUES (2117,'Jining','CHN','Inner Mongolia',163552);
+INSERT INTO City VALUES (2118,'Xiaoshan','CHN','Zhejiang',162930);
+INSERT INTO City VALUES (2119,'Zaoyang','CHN','Hubei',162198);
+INSERT INTO City VALUES (2120,'Xinghua','CHN','Jiangsu',161910);
+INSERT INTO City VALUES (2121,'Hami','CHN','Xinxiang',161315);
+INSERT INTO City VALUES (2122,'Huizhou','CHN','Guangdong',161023);
+INSERT INTO City VALUES (2123,'Jinmen','CHN','Hubei',160794);
+INSERT INTO City VALUES (2124,'Sanming','CHN','Fujian',160691);
+INSERT INTO City VALUES (2125,'Ulanhot','CHN','Inner Mongolia',159538);
+INSERT INTO City VALUES (2126,'Korla','CHN','Xinxiang',159344);
+INSERT INTO City VALUES (2127,'Wanxian','CHN','Sichuan',156823);
+INSERT INTO City VALUES (2128,'Rui´an','CHN','Zhejiang',156468);
+INSERT INTO City VALUES (2129,'Zhoushan','CHN','Zhejiang',156317);
+INSERT INTO City VALUES (2130,'Liangcheng','CHN','Shandong',156307);
+INSERT INTO City VALUES (2131,'Jiaozhou','CHN','Shandong',153364);
+INSERT INTO City VALUES (2132,'Taizhou','CHN','Jiangsu',152442);
+INSERT INTO City VALUES (2133,'Suzhou','CHN','Anhui',151862);
+INSERT INTO City VALUES (2134,'Yichun','CHN','Jiangxi',151585);
+INSERT INTO City VALUES (2135,'Taonan','CHN','Jilin',150168);
+INSERT INTO City VALUES (2136,'Pingdu','CHN','Shandong',150123);
+INSERT INTO City VALUES (2137,'Ji´an','CHN','Jiangxi',148583);
+INSERT INTO City VALUES (2138,'Longkou','CHN','Shandong',148362);
+INSERT INTO City VALUES (2139,'Langfang','CHN','Hebei',148105);
+INSERT INTO City VALUES (2140,'Zhoukou','CHN','Henan',146288);
+INSERT INTO City VALUES (2141,'Suining','CHN','Sichuan',146086);
+INSERT INTO City VALUES (2142,'Yulin','CHN','Guangxi',144467);
+INSERT INTO City VALUES (2143,'Jinhua','CHN','Zhejiang',144280);
+INSERT INTO City VALUES (2144,'Liu´an','CHN','Anhui',144248);
+INSERT INTO City VALUES (2145,'Shuangcheng','CHN','Heilongjiang',142659);
+INSERT INTO City VALUES (2146,'Suizhou','CHN','Hubei',142302);
+INSERT INTO City VALUES (2147,'Ankang','CHN','Shaanxi',142170);
+INSERT INTO City VALUES (2148,'Weinan','CHN','Shaanxi',140169);
+INSERT INTO City VALUES (2149,'Longjing','CHN','Jilin',139417);
+INSERT INTO City VALUES (2150,'Da´an','CHN','Jilin',138963);
+INSERT INTO City VALUES (2151,'Lengshuijiang','CHN','Hunan',137994);
+INSERT INTO City VALUES (2152,'Laiyang','CHN','Shandong',137080);
+INSERT INTO City VALUES (2153,'Xianning','CHN','Hubei',136811);
+INSERT INTO City VALUES (2154,'Dali','CHN','Yunnan',136554);
+INSERT INTO City VALUES (2155,'Anda','CHN','Heilongjiang',136446);
+INSERT INTO City VALUES (2156,'Jincheng','CHN','Shanxi',136396);
+INSERT INTO City VALUES (2157,'Longyan','CHN','Fujian',134481);
+INSERT INTO City VALUES (2158,'Xichang','CHN','Sichuan',134419);
+INSERT INTO City VALUES (2159,'Wendeng','CHN','Shandong',133910);
+INSERT INTO City VALUES (2160,'Hailun','CHN','Heilongjiang',133565);
+INSERT INTO City VALUES (2161,'Binzhou','CHN','Shandong',133555);
+INSERT INTO City VALUES (2162,'Linhe','CHN','Inner Mongolia',133183);
+INSERT INTO City VALUES (2163,'Wuwei','CHN','Gansu',133101);
+INSERT INTO City VALUES (2164,'Duyun','CHN','Guizhou',132971);
+INSERT INTO City VALUES (2165,'Mishan','CHN','Heilongjiang',132744);
+INSERT INTO City VALUES (2166,'Shangrao','CHN','Jiangxi',132455);
+INSERT INTO City VALUES (2167,'Changji','CHN','Xinxiang',132260);
+INSERT INTO City VALUES (2168,'Meixian','CHN','Guangdong',132156);
+INSERT INTO City VALUES (2169,'Yushu','CHN','Jilin',131861);
+INSERT INTO City VALUES (2170,'Tiefa','CHN','Liaoning',131807);
+INSERT INTO City VALUES (2171,'Huai´an','CHN','Jiangsu',131149);
+INSERT INTO City VALUES (2172,'Leiyang','CHN','Hunan',130115);
+INSERT INTO City VALUES (2173,'Zalantun','CHN','Inner Mongolia',130031);
+INSERT INTO City VALUES (2174,'Weihai','CHN','Shandong',128888);
+INSERT INTO City VALUES (2175,'Loudi','CHN','Hunan',128418);
+INSERT INTO City VALUES (2176,'Qingzhou','CHN','Shandong',128258);
+INSERT INTO City VALUES (2177,'Qidong','CHN','Jiangsu',126872);
+INSERT INTO City VALUES (2178,'Huaihua','CHN','Hunan',126785);
+INSERT INTO City VALUES (2179,'Luohe','CHN','Henan',126438);
+INSERT INTO City VALUES (2180,'Chuzhou','CHN','Anhui',125341);
+INSERT INTO City VALUES (2181,'Kaiyuan','CHN','Liaoning',124219);
+INSERT INTO City VALUES (2182,'Linqing','CHN','Shandong',123958);
+INSERT INTO City VALUES (2183,'Chaohu','CHN','Anhui',123676);
+INSERT INTO City VALUES (2184,'Laohekou','CHN','Hubei',123366);
+INSERT INTO City VALUES (2185,'Dujiangyan','CHN','Sichuan',123357);
+INSERT INTO City VALUES (2186,'Zhumadian','CHN','Henan',123232);
+INSERT INTO City VALUES (2187,'Linchuan','CHN','Jiangxi',121949);
+INSERT INTO City VALUES (2188,'Jiaonan','CHN','Shandong',121397);
+INSERT INTO City VALUES (2189,'Sanmenxia','CHN','Henan',120523);
+INSERT INTO City VALUES (2190,'Heyuan','CHN','Guangdong',120101);
+INSERT INTO City VALUES (2191,'Manzhouli','CHN','Inner Mongolia',120023);
+INSERT INTO City VALUES (2192,'Lhasa','CHN','Tibet',120000);
+INSERT INTO City VALUES (2193,'Lianyuan','CHN','Hunan',118858);
+INSERT INTO City VALUES (2194,'Kuytun','CHN','Xinxiang',118553);
+INSERT INTO City VALUES (2195,'Puqi','CHN','Hubei',117264);
+INSERT INTO City VALUES (2196,'Hongjiang','CHN','Hunan',116188);
+INSERT INTO City VALUES (2197,'Qinzhou','CHN','Guangxi',114586);
+INSERT INTO City VALUES (2198,'Renqiu','CHN','Hebei',114256);
+INSERT INTO City VALUES (2199,'Yuyao','CHN','Zhejiang',114065);
+INSERT INTO City VALUES (2200,'Guigang','CHN','Guangxi',114025);
+INSERT INTO City VALUES (2201,'Kaili','CHN','Guizhou',113958);
+INSERT INTO City VALUES (2202,'Yan´an','CHN','Shaanxi',113277);
+INSERT INTO City VALUES (2203,'Beihai','CHN','Guangxi',112673);
+INSERT INTO City VALUES (2204,'Xuangzhou','CHN','Anhui',112673);
+INSERT INTO City VALUES (2205,'Quzhou','CHN','Zhejiang',112373);
+INSERT INTO City VALUES (2206,'Yong´an','CHN','Fujian',111762);
+INSERT INTO City VALUES (2207,'Zixing','CHN','Hunan',110048);
+INSERT INTO City VALUES (2208,'Liyang','CHN','Jiangsu',109520);
+INSERT INTO City VALUES (2209,'Yizheng','CHN','Jiangsu',109268);
+INSERT INTO City VALUES (2210,'Yumen','CHN','Gansu',109234);
+INSERT INTO City VALUES (2211,'Liling','CHN','Hunan',108504);
+INSERT INTO City VALUES (2212,'Yuncheng','CHN','Shanxi',108359);
+INSERT INTO City VALUES (2213,'Shanwei','CHN','Guangdong',107847);
+INSERT INTO City VALUES (2214,'Cixi','CHN','Zhejiang',107329);
+INSERT INTO City VALUES (2215,'Yuanjiang','CHN','Hunan',107004);
+INSERT INTO City VALUES (2216,'Bozhou','CHN','Anhui',106346);
+INSERT INTO City VALUES (2217,'Jinchang','CHN','Gansu',105287);
+INSERT INTO City VALUES (2218,'Fu´an','CHN','Fujian',105265);
+INSERT INTO City VALUES (2219,'Suqian','CHN','Jiangsu',105021);
+INSERT INTO City VALUES (2220,'Shishou','CHN','Hubei',104571);
+INSERT INTO City VALUES (2221,'Hengshui','CHN','Hebei',104269);
+INSERT INTO City VALUES (2222,'Danjiangkou','CHN','Hubei',103211);
+INSERT INTO City VALUES (2223,'Fujin','CHN','Heilongjiang',103104);
+INSERT INTO City VALUES (2224,'Sanya','CHN','Hainan',102820);
+INSERT INTO City VALUES (2225,'Guangshui','CHN','Hubei',102770);
+INSERT INTO City VALUES (2226,'Huangshan','CHN','Anhui',102628);
+INSERT INTO City VALUES (2227,'Xingcheng','CHN','Liaoning',102384);
+INSERT INTO City VALUES (2228,'Zhucheng','CHN','Shandong',102134);
+INSERT INTO City VALUES (2229,'Kunshan','CHN','Jiangsu',102052);
+INSERT INTO City VALUES (2230,'Haining','CHN','Zhejiang',100478);
+INSERT INTO City VALUES (2231,'Pingliang','CHN','Gansu',99265);
+INSERT INTO City VALUES (2232,'Fuqing','CHN','Fujian',99193);
+INSERT INTO City VALUES (2233,'Xinzhou','CHN','Shanxi',98667);
+INSERT INTO City VALUES (2234,'Jieyang','CHN','Guangdong',98531);
+INSERT INTO City VALUES (2235,'Zhangjiagang','CHN','Jiangsu',97994);
+INSERT INTO City VALUES (2236,'Tong Xian','CHN','Peking',97168);
+INSERT INTO City VALUES (2237,'Ya´an','CHN','Sichuan',95900);
+INSERT INTO City VALUES (2238,'Jinzhou','CHN','Liaoning',95761);
+INSERT INTO City VALUES (2239,'Emeishan','CHN','Sichuan',94000);
+INSERT INTO City VALUES (2240,'Enshi','CHN','Hubei',93056);
+INSERT INTO City VALUES (2241,'Bose','CHN','Guangxi',93009);
+INSERT INTO City VALUES (2242,'Yuzhou','CHN','Henan',92889);
+INSERT INTO City VALUES (2243,'Kaiyuan','CHN','Yunnan',91999);
+INSERT INTO City VALUES (2244,'Tumen','CHN','Jilin',91471);
+INSERT INTO City VALUES (2245,'Putian','CHN','Fujian',91030);
+INSERT INTO City VALUES (2246,'Linhai','CHN','Zhejiang',90870);
+INSERT INTO City VALUES (2247,'Xilin Hot','CHN','Inner Mongolia',90646);
+INSERT INTO City VALUES (2248,'Shaowu','CHN','Fujian',90286);
+INSERT INTO City VALUES (2249,'Junan','CHN','Shandong',90222);
+INSERT INTO City VALUES (2250,'Huaying','CHN','Sichuan',89400);
+INSERT INTO City VALUES (2251,'Pingyi','CHN','Shandong',89373);
+INSERT INTO City VALUES (2252,'Huangyan','CHN','Zhejiang',89288);
+INSERT INTO City VALUES (2253,'Bishkek','KGZ','Bishkek shaary',589400);
+INSERT INTO City VALUES (2254,'Osh','KGZ','Osh',222700);
+INSERT INTO City VALUES (2255,'Bikenibeu','KIR','South Tarawa',5055);
+INSERT INTO City VALUES (2256,'Bairiki','KIR','South Tarawa',2226);
+INSERT INTO City VALUES (2257,'Santafé de Bogotá','COL','Santafé de Bogotá',6260862);
+INSERT INTO City VALUES (2258,'Cali','COL','Valle',2077386);
+INSERT INTO City VALUES (2259,'Medellín','COL','Antioquia',1861265);
+INSERT INTO City VALUES (2260,'Barranquilla','COL','Atlántico',1223260);
+INSERT INTO City VALUES (2261,'Cartagena','COL','Bolívar',805757);
+INSERT INTO City VALUES (2262,'Cúcuta','COL','Norte de Santander',606932);
+INSERT INTO City VALUES (2263,'Bucaramanga','COL','Santander',515555);
+INSERT INTO City VALUES (2264,'Ibagué','COL','Tolima',393664);
+INSERT INTO City VALUES (2265,'Pereira','COL','Risaralda',381725);
+INSERT INTO City VALUES (2266,'Santa Marta','COL','Magdalena',359147);
+INSERT INTO City VALUES (2267,'Manizales','COL','Caldas',337580);
+INSERT INTO City VALUES (2268,'Bello','COL','Antioquia',333470);
+INSERT INTO City VALUES (2269,'Pasto','COL','Nariño',332396);
+INSERT INTO City VALUES (2270,'Neiva','COL','Huila',300052);
+INSERT INTO City VALUES (2271,'Soledad','COL','Atlántico',295058);
+INSERT INTO City VALUES (2272,'Armenia','COL','Quindío',288977);
+INSERT INTO City VALUES (2273,'Villavicencio','COL','Meta',273140);
+INSERT INTO City VALUES (2274,'Soacha','COL','Cundinamarca',272058);
+INSERT INTO City VALUES (2275,'Valledupar','COL','Cesar',263247);
+INSERT INTO City VALUES (2276,'Montería','COL','Córdoba',248245);
+INSERT INTO City VALUES (2277,'Itagüí','COL','Antioquia',228985);
+INSERT INTO City VALUES (2278,'Palmira','COL','Valle',226509);
+INSERT INTO City VALUES (2279,'Buenaventura','COL','Valle',224336);
+INSERT INTO City VALUES (2280,'Floridablanca','COL','Santander',221913);
+INSERT INTO City VALUES (2281,'Sincelejo','COL','Sucre',220704);
+INSERT INTO City VALUES (2282,'Popayán','COL','Cauca',200719);
+INSERT INTO City VALUES (2283,'Barrancabermeja','COL','Santander',178020);
+INSERT INTO City VALUES (2284,'Dos Quebradas','COL','Risaralda',159363);
+INSERT INTO City VALUES (2285,'Tuluá','COL','Valle',152488);
+INSERT INTO City VALUES (2286,'Envigado','COL','Antioquia',135848);
+INSERT INTO City VALUES (2287,'Cartago','COL','Valle',125884);
+INSERT INTO City VALUES (2288,'Girardot','COL','Cundinamarca',110963);
+INSERT INTO City VALUES (2289,'Buga','COL','Valle',110699);
+INSERT INTO City VALUES (2290,'Tunja','COL','Boyacá',109740);
+INSERT INTO City VALUES (2291,'Florencia','COL','Caquetá',108574);
+INSERT INTO City VALUES (2292,'Maicao','COL','La Guajira',108053);
+INSERT INTO City VALUES (2293,'Sogamoso','COL','Boyacá',107728);
+INSERT INTO City VALUES (2294,'Giron','COL','Santander',90688);
+INSERT INTO City VALUES (2295,'Moroni','COM','Njazidja',36000);
+INSERT INTO City VALUES (2296,'Brazzaville','COG','Brazzaville',950000);
+INSERT INTO City VALUES (2297,'Pointe-Noire','COG','Kouilou',500000);
+INSERT INTO City VALUES (2298,'Kinshasa','COD','Kinshasa',5064000);
+INSERT INTO City VALUES (2299,'Lubumbashi','COD','Shaba',851381);
+INSERT INTO City VALUES (2300,'Mbuji-Mayi','COD','East Kasai',806475);
+INSERT INTO City VALUES (2301,'Kolwezi','COD','Shaba',417810);
+INSERT INTO City VALUES (2302,'Kisangani','COD','Haute-Zaïre',417517);
+INSERT INTO City VALUES (2303,'Kananga','COD','West Kasai',393030);
+INSERT INTO City VALUES (2304,'Likasi','COD','Shaba',299118);
+INSERT INTO City VALUES (2305,'Bukavu','COD','South Kivu',201569);
+INSERT INTO City VALUES (2306,'Kikwit','COD','Bandundu',182142);
+INSERT INTO City VALUES (2307,'Tshikapa','COD','West Kasai',180860);
+INSERT INTO City VALUES (2308,'Matadi','COD','Bas-Zaïre',172730);
+INSERT INTO City VALUES (2309,'Mbandaka','COD','Equateur',169841);
+INSERT INTO City VALUES (2310,'Mwene-Ditu','COD','East Kasai',137459);
+INSERT INTO City VALUES (2311,'Boma','COD','Bas-Zaïre',135284);
+INSERT INTO City VALUES (2312,'Uvira','COD','South Kivu',115590);
+INSERT INTO City VALUES (2313,'Butembo','COD','North Kivu',109406);
+INSERT INTO City VALUES (2314,'Goma','COD','North Kivu',109094);
+INSERT INTO City VALUES (2315,'Kalemie','COD','Shaba',101309);
+INSERT INTO City VALUES (2316,'Bantam','CCK','Home Island',503);
+INSERT INTO City VALUES (2317,'West Island','CCK','West Island',167);
+INSERT INTO City VALUES (2318,'Pyongyang','PRK','Pyongyang-si',2484000);
+INSERT INTO City VALUES (2319,'Hamhung','PRK','Hamgyong N',709730);
+INSERT INTO City VALUES (2320,'Chongjin','PRK','Hamgyong P',582480);
+INSERT INTO City VALUES (2321,'Nampo','PRK','Nampo-si',566200);
+INSERT INTO City VALUES (2322,'Sinuiju','PRK','Pyongan P',326011);
+INSERT INTO City VALUES (2323,'Wonsan','PRK','Kangwon',300148);
+INSERT INTO City VALUES (2324,'Phyongsong','PRK','Pyongan N',272934);
+INSERT INTO City VALUES (2325,'Sariwon','PRK','Hwanghae P',254146);
+INSERT INTO City VALUES (2326,'Haeju','PRK','Hwanghae N',229172);
+INSERT INTO City VALUES (2327,'Kanggye','PRK','Chagang',223410);
+INSERT INTO City VALUES (2328,'Kimchaek','PRK','Hamgyong P',179000);
+INSERT INTO City VALUES (2329,'Hyesan','PRK','Yanggang',178020);
+INSERT INTO City VALUES (2330,'Kaesong','PRK','Kaesong-si',171500);
+INSERT INTO City VALUES (2331,'Seoul','KOR','Seoul',9981619);
+INSERT INTO City VALUES (2332,'Pusan','KOR','Pusan',3804522);
+INSERT INTO City VALUES (2333,'Inchon','KOR','Inchon',2559424);
+INSERT INTO City VALUES (2334,'Taegu','KOR','Taegu',2548568);
+INSERT INTO City VALUES (2335,'Taejon','KOR','Taejon',1425835);
+INSERT INTO City VALUES (2336,'Kwangju','KOR','Kwangju',1368341);
+INSERT INTO City VALUES (2337,'Ulsan','KOR','Kyongsangnam',1084891);
+INSERT INTO City VALUES (2338,'Songnam','KOR','Kyonggi',869094);
+INSERT INTO City VALUES (2339,'Puchon','KOR','Kyonggi',779412);
+INSERT INTO City VALUES (2340,'Suwon','KOR','Kyonggi',755550);
+INSERT INTO City VALUES (2341,'Anyang','KOR','Kyonggi',591106);
+INSERT INTO City VALUES (2342,'Chonju','KOR','Chollabuk',563153);
+INSERT INTO City VALUES (2343,'Chongju','KOR','Chungchongbuk',531376);
+INSERT INTO City VALUES (2344,'Koyang','KOR','Kyonggi',518282);
+INSERT INTO City VALUES (2345,'Ansan','KOR','Kyonggi',510314);
+INSERT INTO City VALUES (2346,'Pohang','KOR','Kyongsangbuk',508899);
+INSERT INTO City VALUES (2347,'Chang-won','KOR','Kyongsangnam',481694);
+INSERT INTO City VALUES (2348,'Masan','KOR','Kyongsangnam',441242);
+INSERT INTO City VALUES (2349,'Kwangmyong','KOR','Kyonggi',350914);
+INSERT INTO City VALUES (2350,'Chonan','KOR','Chungchongnam',330259);
+INSERT INTO City VALUES (2351,'Chinju','KOR','Kyongsangnam',329886);
+INSERT INTO City VALUES (2352,'Iksan','KOR','Chollabuk',322685);
+INSERT INTO City VALUES (2353,'Pyongtaek','KOR','Kyonggi',312927);
+INSERT INTO City VALUES (2354,'Kumi','KOR','Kyongsangbuk',311431);
+INSERT INTO City VALUES (2355,'Uijongbu','KOR','Kyonggi',276111);
+INSERT INTO City VALUES (2356,'Kyongju','KOR','Kyongsangbuk',272968);
+INSERT INTO City VALUES (2357,'Kunsan','KOR','Chollabuk',266569);
+INSERT INTO City VALUES (2358,'Cheju','KOR','Cheju',258511);
+INSERT INTO City VALUES (2359,'Kimhae','KOR','Kyongsangnam',256370);
+INSERT INTO City VALUES (2360,'Sunchon','KOR','Chollanam',249263);
+INSERT INTO City VALUES (2361,'Mokpo','KOR','Chollanam',247452);
+INSERT INTO City VALUES (2362,'Yong-in','KOR','Kyonggi',242643);
+INSERT INTO City VALUES (2363,'Wonju','KOR','Kang-won',237460);
+INSERT INTO City VALUES (2364,'Kunpo','KOR','Kyonggi',235233);
+INSERT INTO City VALUES (2365,'Chunchon','KOR','Kang-won',234528);
+INSERT INTO City VALUES (2366,'Namyangju','KOR','Kyonggi',229060);
+INSERT INTO City VALUES (2367,'Kangnung','KOR','Kang-won',220403);
+INSERT INTO City VALUES (2368,'Chungju','KOR','Chungchongbuk',205206);
+INSERT INTO City VALUES (2369,'Andong','KOR','Kyongsangbuk',188443);
+INSERT INTO City VALUES (2370,'Yosu','KOR','Chollanam',183596);
+INSERT INTO City VALUES (2371,'Kyongsan','KOR','Kyongsangbuk',173746);
+INSERT INTO City VALUES (2372,'Paju','KOR','Kyonggi',163379);
+INSERT INTO City VALUES (2373,'Yangsan','KOR','Kyongsangnam',163351);
+INSERT INTO City VALUES (2374,'Ichon','KOR','Kyonggi',155332);
+INSERT INTO City VALUES (2375,'Asan','KOR','Chungchongnam',154663);
+INSERT INTO City VALUES (2376,'Koje','KOR','Kyongsangnam',147562);
+INSERT INTO City VALUES (2377,'Kimchon','KOR','Kyongsangbuk',147027);
+INSERT INTO City VALUES (2378,'Nonsan','KOR','Chungchongnam',146619);
+INSERT INTO City VALUES (2379,'Kuri','KOR','Kyonggi',142173);
+INSERT INTO City VALUES (2380,'Chong-up','KOR','Chollabuk',139111);
+INSERT INTO City VALUES (2381,'Chechon','KOR','Chungchongbuk',137070);
+INSERT INTO City VALUES (2382,'Sosan','KOR','Chungchongnam',134746);
+INSERT INTO City VALUES (2383,'Shihung','KOR','Kyonggi',133443);
+INSERT INTO City VALUES (2384,'Tong-yong','KOR','Kyongsangnam',131717);
+INSERT INTO City VALUES (2385,'Kongju','KOR','Chungchongnam',131229);
+INSERT INTO City VALUES (2386,'Yongju','KOR','Kyongsangbuk',131097);
+INSERT INTO City VALUES (2387,'Chinhae','KOR','Kyongsangnam',125997);
+INSERT INTO City VALUES (2388,'Sangju','KOR','Kyongsangbuk',124116);
+INSERT INTO City VALUES (2389,'Poryong','KOR','Chungchongnam',122604);
+INSERT INTO City VALUES (2390,'Kwang-yang','KOR','Chollanam',122052);
+INSERT INTO City VALUES (2391,'Miryang','KOR','Kyongsangnam',121501);
+INSERT INTO City VALUES (2392,'Hanam','KOR','Kyonggi',115812);
+INSERT INTO City VALUES (2393,'Kimje','KOR','Chollabuk',115427);
+INSERT INTO City VALUES (2394,'Yongchon','KOR','Kyongsangbuk',113511);
+INSERT INTO City VALUES (2395,'Sachon','KOR','Kyongsangnam',113494);
+INSERT INTO City VALUES (2396,'Uiwang','KOR','Kyonggi',108788);
+INSERT INTO City VALUES (2397,'Naju','KOR','Chollanam',107831);
+INSERT INTO City VALUES (2398,'Namwon','KOR','Chollabuk',103544);
+INSERT INTO City VALUES (2399,'Tonghae','KOR','Kang-won',95472);
+INSERT INTO City VALUES (2400,'Mun-gyong','KOR','Kyongsangbuk',92239);
+INSERT INTO City VALUES (2401,'Athenai','GRC','Attika',772072);
+INSERT INTO City VALUES (2402,'Thessaloniki','GRC','Central Macedonia',383967);
+INSERT INTO City VALUES (2403,'Pireus','GRC','Attika',182671);
+INSERT INTO City VALUES (2404,'Patras','GRC','West Greece',153344);
+INSERT INTO City VALUES (2405,'Peristerion','GRC','Attika',137288);
+INSERT INTO City VALUES (2406,'Herakleion','GRC','Crete',116178);
+INSERT INTO City VALUES (2407,'Kallithea','GRC','Attika',114233);
+INSERT INTO City VALUES (2408,'Larisa','GRC','Thessalia',113090);
+INSERT INTO City VALUES (2409,'Zagreb','HRV','Grad Zagreb',706770);
+INSERT INTO City VALUES (2410,'Split','HRV','Split-Dalmatia',189388);
+INSERT INTO City VALUES (2411,'Rijeka','HRV','Primorje-Gorski Kota',167964);
+INSERT INTO City VALUES (2412,'Osijek','HRV','Osijek-Baranja',104761);
+INSERT INTO City VALUES (2413,'La Habana','CUB','La Habana',2256000);
+INSERT INTO City VALUES (2414,'Santiago de Cuba','CUB','Santiago de Cuba',433180);
+INSERT INTO City VALUES (2415,'Camagüey','CUB','Camagüey',298726);
+INSERT INTO City VALUES (2416,'Holguín','CUB','Holguín',249492);
+INSERT INTO City VALUES (2417,'Santa Clara','CUB','Villa Clara',207350);
+INSERT INTO City VALUES (2418,'Guantánamo','CUB','Guantánamo',205078);
+INSERT INTO City VALUES (2419,'Pinar del Río','CUB','Pinar del Río',142100);
+INSERT INTO City VALUES (2420,'Bayamo','CUB','Granma',141000);
+INSERT INTO City VALUES (2421,'Cienfuegos','CUB','Cienfuegos',132770);
+INSERT INTO City VALUES (2422,'Victoria de las Tunas','CUB','Las Tunas',132350);
+INSERT INTO City VALUES (2423,'Matanzas','CUB','Matanzas',123273);
+INSERT INTO City VALUES (2424,'Manzanillo','CUB','Granma',109350);
+INSERT INTO City VALUES (2425,'Sancti-Spíritus','CUB','Sancti-Spíritus',100751);
+INSERT INTO City VALUES (2426,'Ciego de Ávila','CUB','Ciego de Ávila',98505);
+INSERT INTO City VALUES (2427,'al-Salimiya','KWT','Hawalli',130215);
+INSERT INTO City VALUES (2428,'Jalib al-Shuyukh','KWT','Hawalli',102178);
+INSERT INTO City VALUES (2429,'Kuwait','KWT','al-Asima',28859);
+INSERT INTO City VALUES (2430,'Nicosia','CYP','Nicosia',195000);
+INSERT INTO City VALUES (2431,'Limassol','CYP','Limassol',154400);
+INSERT INTO City VALUES (2432,'Vientiane','LAO','Viangchan',531800);
+INSERT INTO City VALUES (2433,'Savannakhet','LAO','Savannakhet',96652);
+INSERT INTO City VALUES (2434,'Riga','LVA','Riika',764328);
+INSERT INTO City VALUES (2435,'Daugavpils','LVA','Daugavpils',114829);
+INSERT INTO City VALUES (2436,'Liepaja','LVA','Liepaja',89439);
+INSERT INTO City VALUES (2437,'Maseru','LSO','Maseru',297000);
+INSERT INTO City VALUES (2438,'Beirut','LBN','Beirut',1100000);
+INSERT INTO City VALUES (2439,'Tripoli','LBN','al-Shamal',240000);
+INSERT INTO City VALUES (2440,'Monrovia','LBR','Montserrado',850000);
+INSERT INTO City VALUES (2441,'Tripoli','LBY','Tripoli',1682000);
+INSERT INTO City VALUES (2442,'Bengasi','LBY','Bengasi',804000);
+INSERT INTO City VALUES (2443,'Misrata','LBY','Misrata',121669);
+INSERT INTO City VALUES (2444,'al-Zawiya','LBY','al-Zawiya',89338);
+INSERT INTO City VALUES (2445,'Schaan','LIE','Schaan',5346);
+INSERT INTO City VALUES (2446,'Vaduz','LIE','Vaduz',5043);
+INSERT INTO City VALUES (2447,'Vilnius','LTU','Vilna',577969);
+INSERT INTO City VALUES (2448,'Kaunas','LTU','Kaunas',412639);
+INSERT INTO City VALUES (2449,'Klaipeda','LTU','Klaipeda',202451);
+INSERT INTO City VALUES (2450,'Šiauliai','LTU','Šiauliai',146563);
+INSERT INTO City VALUES (2451,'Panevezys','LTU','Panevezys',133695);
+INSERT INTO City VALUES (2452,'Luxembourg [Luxemburg/Lëtzebuerg]','LUX','Luxembourg',80700);
+INSERT INTO City VALUES (2453,'El-Aaiún','ESH','El-Aaiún',169000);
+INSERT INTO City VALUES (2454,'Macao','MAC','Macau',437500);
+INSERT INTO City VALUES (2455,'Antananarivo','MDG','Antananarivo',675669);
+INSERT INTO City VALUES (2456,'Toamasina','MDG','Toamasina',127441);
+INSERT INTO City VALUES (2457,'Antsirabé','MDG','Antananarivo',120239);
+INSERT INTO City VALUES (2458,'Mahajanga','MDG','Mahajanga',100807);
+INSERT INTO City VALUES (2459,'Fianarantsoa','MDG','Fianarantsoa',99005);
+INSERT INTO City VALUES (2460,'Skopje','MKD','Skopje',444299);
+INSERT INTO City VALUES (2461,'Blantyre','MWI','Blantyre',478155);
+INSERT INTO City VALUES (2462,'Lilongwe','MWI','Lilongwe',435964);
+INSERT INTO City VALUES (2463,'Male','MDV','Maale',71000);
+INSERT INTO City VALUES (2464,'Kuala Lumpur','MYS','Wilayah Persekutuan',1297526);
+INSERT INTO City VALUES (2465,'Ipoh','MYS','Perak',382853);
+INSERT INTO City VALUES (2466,'Johor Baharu','MYS','Johor',328436);
+INSERT INTO City VALUES (2467,'Petaling Jaya','MYS','Selangor',254350);
+INSERT INTO City VALUES (2468,'Kelang','MYS','Selangor',243355);
+INSERT INTO City VALUES (2469,'Kuala Terengganu','MYS','Terengganu',228119);
+INSERT INTO City VALUES (2470,'Pinang','MYS','Pulau Pinang',219603);
+INSERT INTO City VALUES (2471,'Kota Bharu','MYS','Kelantan',219582);
+INSERT INTO City VALUES (2472,'Kuantan','MYS','Pahang',199484);
+INSERT INTO City VALUES (2473,'Taiping','MYS','Perak',183261);
+INSERT INTO City VALUES (2474,'Seremban','MYS','Negeri Sembilan',182869);
+INSERT INTO City VALUES (2475,'Kuching','MYS','Sarawak',148059);
+INSERT INTO City VALUES (2476,'Sibu','MYS','Sarawak',126381);
+INSERT INTO City VALUES (2477,'Sandakan','MYS','Sabah',125841);
+INSERT INTO City VALUES (2478,'Alor Setar','MYS','Kedah',124412);
+INSERT INTO City VALUES (2479,'Selayang Baru','MYS','Selangor',124228);
+INSERT INTO City VALUES (2480,'Sungai Petani','MYS','Kedah',114763);
+INSERT INTO City VALUES (2481,'Shah Alam','MYS','Selangor',102019);
+INSERT INTO City VALUES (2482,'Bamako','MLI','Bamako',809552);
+INSERT INTO City VALUES (2483,'Birkirkara','MLT','Outer Harbour',21445);
+INSERT INTO City VALUES (2484,'Valletta','MLT','Inner Harbour',7073);
+INSERT INTO City VALUES (2485,'Casablanca','MAR','Casablanca',2940623);
+INSERT INTO City VALUES (2486,'Rabat','MAR','Rabat-Salé-Zammour-Z',623457);
+INSERT INTO City VALUES (2487,'Marrakech','MAR','Marrakech-Tensift-Al',621914);
+INSERT INTO City VALUES (2488,'Fès','MAR','Fès-Boulemane',541162);
+INSERT INTO City VALUES (2489,'Tanger','MAR','Tanger-Tétouan',521735);
+INSERT INTO City VALUES (2490,'Salé','MAR','Rabat-Salé-Zammour-Z',504420);
+INSERT INTO City VALUES (2491,'Meknès','MAR','Meknès-Tafilalet',460000);
+INSERT INTO City VALUES (2492,'Oujda','MAR','Oriental',365382);
+INSERT INTO City VALUES (2493,'Kénitra','MAR','Gharb-Chrarda-Béni H',292600);
+INSERT INTO City VALUES (2494,'Tétouan','MAR','Tanger-Tétouan',277516);
+INSERT INTO City VALUES (2495,'Safi','MAR','Doukkala-Abda',262300);
+INSERT INTO City VALUES (2496,'Agadir','MAR','Souss Massa-Draâ',155244);
+INSERT INTO City VALUES (2497,'Mohammedia','MAR','Casablanca',154706);
+INSERT INTO City VALUES (2498,'Khouribga','MAR','Chaouia-Ouardigha',152090);
+INSERT INTO City VALUES (2499,'Beni-Mellal','MAR','Tadla-Azilal',140212);
+INSERT INTO City VALUES (2500,'Témara','MAR','Rabat-Salé-Zammour-Z',126303);
+INSERT INTO City VALUES (2501,'El Jadida','MAR','Doukkala-Abda',119083);
+INSERT INTO City VALUES (2502,'Nador','MAR','Oriental',112450);
+INSERT INTO City VALUES (2503,'Ksar el Kebir','MAR','Tanger-Tétouan',107065);
+INSERT INTO City VALUES (2504,'Settat','MAR','Chaouia-Ouardigha',96200);
+INSERT INTO City VALUES (2505,'Taza','MAR','Taza-Al Hoceima-Taou',92700);
+INSERT INTO City VALUES (2506,'El Araich','MAR','Tanger-Tétouan',90400);
+INSERT INTO City VALUES (2507,'Dalap-Uliga-Darrit','MHL','Majuro',28000);
+INSERT INTO City VALUES (2508,'Fort-de-France','MTQ','Fort-de-France',94050);
+INSERT INTO City VALUES (2509,'Nouakchott','MRT','Nouakchott',667300);
+INSERT INTO City VALUES (2510,'Nouâdhibou','MRT','Dakhlet Nouâdhibou',97600);
+INSERT INTO City VALUES (2511,'Port-Louis','MUS','Port-Louis',138200);
+INSERT INTO City VALUES (2512,'Beau Bassin-Rose Hill','MUS','Plaines Wilhelms',100616);
+INSERT INTO City VALUES (2513,'Vacoas-Phoenix','MUS','Plaines Wilhelms',98464);
+INSERT INTO City VALUES (2514,'Mamoutzou','MYT','Mamoutzou',12000);
+INSERT INTO City VALUES (2515,'Ciudad de México','MEX','Distrito Federal',8591309);
+INSERT INTO City VALUES (2516,'Guadalajara','MEX','Jalisco',1647720);
+INSERT INTO City VALUES (2517,'Ecatepec de Morelos','MEX','México',1620303);
+INSERT INTO City VALUES (2518,'Puebla','MEX','Puebla',1346176);
+INSERT INTO City VALUES (2519,'Nezahualcóyotl','MEX','México',1224924);
+INSERT INTO City VALUES (2520,'Juárez','MEX','Chihuahua',1217818);
+INSERT INTO City VALUES (2521,'Tijuana','MEX','Baja California',1212232);
+INSERT INTO City VALUES (2522,'León','MEX','Guanajuato',1133576);
+INSERT INTO City VALUES (2523,'Monterrey','MEX','Nuevo León',1108499);
+INSERT INTO City VALUES (2524,'Zapopan','MEX','Jalisco',1002239);
+INSERT INTO City VALUES (2525,'Naucalpan de Juárez','MEX','México',857511);
+INSERT INTO City VALUES (2526,'Mexicali','MEX','Baja California',764902);
+INSERT INTO City VALUES (2527,'Culiacán','MEX','Sinaloa',744859);
+INSERT INTO City VALUES (2528,'Acapulco de Juárez','MEX','Guerrero',721011);
+INSERT INTO City VALUES (2529,'Tlalnepantla de Baz','MEX','México',720755);
+INSERT INTO City VALUES (2530,'Mérida','MEX','Yucatán',703324);
+INSERT INTO City VALUES (2531,'Chihuahua','MEX','Chihuahua',670208);
+INSERT INTO City VALUES (2532,'San Luis Potosí','MEX','San Luis Potosí',669353);
+INSERT INTO City VALUES (2533,'Guadalupe','MEX','Nuevo León',668780);
+INSERT INTO City VALUES (2534,'Toluca','MEX','México',665617);
+INSERT INTO City VALUES (2535,'Aguascalientes','MEX','Aguascalientes',643360);
+INSERT INTO City VALUES (2536,'Querétaro','MEX','Querétaro de Arteaga',639839);
+INSERT INTO City VALUES (2537,'Morelia','MEX','Michoacán de Ocampo',619958);
+INSERT INTO City VALUES (2538,'Hermosillo','MEX','Sonora',608697);
+INSERT INTO City VALUES (2539,'Saltillo','MEX','Coahuila de Zaragoza',577352);
+INSERT INTO City VALUES (2540,'Torreón','MEX','Coahuila de Zaragoza',529093);
+INSERT INTO City VALUES (2541,'Centro (Villahermosa)','MEX','Tabasco',519873);
+INSERT INTO City VALUES (2542,'San Nicolás de los Garza','MEX','Nuevo León',495540);
+INSERT INTO City VALUES (2543,'Durango','MEX','Durango',490524);
+INSERT INTO City VALUES (2544,'Chimalhuacán','MEX','México',490245);
+INSERT INTO City VALUES (2545,'Tlaquepaque','MEX','Jalisco',475472);
+INSERT INTO City VALUES (2546,'Atizapán de Zaragoza','MEX','México',467262);
+INSERT INTO City VALUES (2547,'Veracruz','MEX','Veracruz',457119);
+INSERT INTO City VALUES (2548,'Cuautitlán Izcalli','MEX','México',452976);
+INSERT INTO City VALUES (2549,'Irapuato','MEX','Guanajuato',440039);
+INSERT INTO City VALUES (2550,'Tuxtla Gutiérrez','MEX','Chiapas',433544);
+INSERT INTO City VALUES (2551,'Tultitlán','MEX','México',432411);
+INSERT INTO City VALUES (2552,'Reynosa','MEX','Tamaulipas',419776);
+INSERT INTO City VALUES (2553,'Benito Juárez','MEX','Quintana Roo',419276);
+INSERT INTO City VALUES (2554,'Matamoros','MEX','Tamaulipas',416428);
+INSERT INTO City VALUES (2555,'Xalapa','MEX','Veracruz',390058);
+INSERT INTO City VALUES (2556,'Celaya','MEX','Guanajuato',382140);
+INSERT INTO City VALUES (2557,'Mazatlán','MEX','Sinaloa',380265);
+INSERT INTO City VALUES (2558,'Ensenada','MEX','Baja California',369573);
+INSERT INTO City VALUES (2559,'Ahome','MEX','Sinaloa',358663);
+INSERT INTO City VALUES (2560,'Cajeme','MEX','Sonora',355679);
+INSERT INTO City VALUES (2561,'Cuernavaca','MEX','Morelos',337966);
+INSERT INTO City VALUES (2562,'Tonalá','MEX','Jalisco',336109);
+INSERT INTO City VALUES (2563,'Valle de Chalco Solidaridad','MEX','México',323113);
+INSERT INTO City VALUES (2564,'Nuevo Laredo','MEX','Tamaulipas',310277);
+INSERT INTO City VALUES (2565,'Tepic','MEX','Nayarit',305025);
+INSERT INTO City VALUES (2566,'Tampico','MEX','Tamaulipas',294789);
+INSERT INTO City VALUES (2567,'Ixtapaluca','MEX','México',293160);
+INSERT INTO City VALUES (2568,'Apodaca','MEX','Nuevo León',282941);
+INSERT INTO City VALUES (2569,'Guasave','MEX','Sinaloa',277201);
+INSERT INTO City VALUES (2570,'Gómez Palacio','MEX','Durango',272806);
+INSERT INTO City VALUES (2571,'Tapachula','MEX','Chiapas',271141);
+INSERT INTO City VALUES (2572,'Nicolás Romero','MEX','México',269393);
+INSERT INTO City VALUES (2573,'Coatzacoalcos','MEX','Veracruz',267037);
+INSERT INTO City VALUES (2574,'Uruapan','MEX','Michoacán de Ocampo',265211);
+INSERT INTO City VALUES (2575,'Victoria','MEX','Tamaulipas',262686);
+INSERT INTO City VALUES (2576,'Oaxaca de Juárez','MEX','Oaxaca',256848);
+INSERT INTO City VALUES (2577,'Coacalco de Berriozábal','MEX','México',252270);
+INSERT INTO City VALUES (2578,'Pachuca de Soto','MEX','Hidalgo',244688);
+INSERT INTO City VALUES (2579,'General Escobedo','MEX','Nuevo León',232961);
+INSERT INTO City VALUES (2580,'Salamanca','MEX','Guanajuato',226864);
+INSERT INTO City VALUES (2581,'Santa Catarina','MEX','Nuevo León',226573);
+INSERT INTO City VALUES (2582,'Tehuacán','MEX','Puebla',225943);
+INSERT INTO City VALUES (2583,'Chalco','MEX','México',222201);
+INSERT INTO City VALUES (2584,'Cárdenas','MEX','Tabasco',216903);
+INSERT INTO City VALUES (2585,'Campeche','MEX','Campeche',216735);
+INSERT INTO City VALUES (2586,'La Paz','MEX','México',213045);
+INSERT INTO City VALUES (2587,'Othón P. Blanco (Chetumal)','MEX','Quintana Roo',208014);
+INSERT INTO City VALUES (2588,'Texcoco','MEX','México',203681);
+INSERT INTO City VALUES (2589,'La Paz','MEX','Baja California Sur',196708);
+INSERT INTO City VALUES (2590,'Metepec','MEX','México',194265);
+INSERT INTO City VALUES (2591,'Monclova','MEX','Coahuila de Zaragoza',193657);
+INSERT INTO City VALUES (2592,'Huixquilucan','MEX','México',193156);
+INSERT INTO City VALUES (2593,'Chilpancingo de los Bravo','MEX','Guerrero',192509);
+INSERT INTO City VALUES (2594,'Puerto Vallarta','MEX','Jalisco',183741);
+INSERT INTO City VALUES (2595,'Fresnillo','MEX','Zacatecas',182744);
+INSERT INTO City VALUES (2596,'Ciudad Madero','MEX','Tamaulipas',182012);
+INSERT INTO City VALUES (2597,'Soledad de Graciano Sánchez','MEX','San Luis Potosí',179956);
+INSERT INTO City VALUES (2598,'San Juan del Río','MEX','Querétaro',179300);
+INSERT INTO City VALUES (2599,'San Felipe del Progreso','MEX','México',177330);
+INSERT INTO City VALUES (2600,'Córdoba','MEX','Veracruz',176952);
+INSERT INTO City VALUES (2601,'Tecámac','MEX','México',172410);
+INSERT INTO City VALUES (2602,'Ocosingo','MEX','Chiapas',171495);
+INSERT INTO City VALUES (2603,'Carmen','MEX','Campeche',171367);
+INSERT INTO City VALUES (2604,'Lázaro Cárdenas','MEX','Michoacán de Ocampo',170878);
+INSERT INTO City VALUES (2605,'Jiutepec','MEX','Morelos',170428);
+INSERT INTO City VALUES (2606,'Papantla','MEX','Veracruz',170123);
+INSERT INTO City VALUES (2607,'Comalcalco','MEX','Tabasco',164640);
+INSERT INTO City VALUES (2608,'Zamora','MEX','Michoacán de Ocampo',161191);
+INSERT INTO City VALUES (2609,'Nogales','MEX','Sonora',159103);
+INSERT INTO City VALUES (2610,'Huimanguillo','MEX','Tabasco',158335);
+INSERT INTO City VALUES (2611,'Cuautla','MEX','Morelos',153132);
+INSERT INTO City VALUES (2612,'Minatitlán','MEX','Veracruz',152983);
+INSERT INTO City VALUES (2613,'Poza Rica de Hidalgo','MEX','Veracruz',152678);
+INSERT INTO City VALUES (2614,'Ciudad Valles','MEX','San Luis Potosí',146411);
+INSERT INTO City VALUES (2615,'Navolato','MEX','Sinaloa',145396);
+INSERT INTO City VALUES (2616,'San Luis Río Colorado','MEX','Sonora',145276);
+INSERT INTO City VALUES (2617,'Pénjamo','MEX','Guanajuato',143927);
+INSERT INTO City VALUES (2618,'San Andrés Tuxtla','MEX','Veracruz',142251);
+INSERT INTO City VALUES (2619,'Guanajuato','MEX','Guanajuato',141215);
+INSERT INTO City VALUES (2620,'Navojoa','MEX','Sonora',140495);
+INSERT INTO City VALUES (2621,'Zitácuaro','MEX','Michoacán de Ocampo',137970);
+INSERT INTO City VALUES (2622,'Boca del Río','MEX','Veracruz-Llave',135721);
+INSERT INTO City VALUES (2623,'Allende','MEX','Guanajuato',134645);
+INSERT INTO City VALUES (2624,'Silao','MEX','Guanajuato',134037);
+INSERT INTO City VALUES (2625,'Macuspana','MEX','Tabasco',133795);
+INSERT INTO City VALUES (2626,'San Juan Bautista Tuxtepec','MEX','Oaxaca',133675);
+INSERT INTO City VALUES (2627,'San Cristóbal de las Casas','MEX','Chiapas',132317);
+INSERT INTO City VALUES (2628,'Valle de Santiago','MEX','Guanajuato',130557);
+INSERT INTO City VALUES (2629,'Guaymas','MEX','Sonora',130108);
+INSERT INTO City VALUES (2630,'Colima','MEX','Colima',129454);
+INSERT INTO City VALUES (2631,'Dolores Hidalgo','MEX','Guanajuato',128675);
+INSERT INTO City VALUES (2632,'Lagos de Moreno','MEX','Jalisco',127949);
+INSERT INTO City VALUES (2633,'Piedras Negras','MEX','Coahuila de Zaragoza',127898);
+INSERT INTO City VALUES (2634,'Altamira','MEX','Tamaulipas',127490);
+INSERT INTO City VALUES (2635,'Túxpam','MEX','Veracruz',126475);
+INSERT INTO City VALUES (2636,'San Pedro Garza García','MEX','Nuevo León',126147);
+INSERT INTO City VALUES (2637,'Cuauhtémoc','MEX','Chihuahua',124279);
+INSERT INTO City VALUES (2638,'Manzanillo','MEX','Colima',124014);
+INSERT INTO City VALUES (2639,'Iguala de la Independencia','MEX','Guerrero',123883);
+INSERT INTO City VALUES (2640,'Zacatecas','MEX','Zacatecas',123700);
+INSERT INTO City VALUES (2641,'Tlajomulco de Zúñiga','MEX','Jalisco',123220);
+INSERT INTO City VALUES (2642,'Tulancingo de Bravo','MEX','Hidalgo',121946);
+INSERT INTO City VALUES (2643,'Zinacantepec','MEX','México',121715);
+INSERT INTO City VALUES (2644,'San Martín Texmelucan','MEX','Puebla',121093);
+INSERT INTO City VALUES (2645,'Tepatitlán de Morelos','MEX','Jalisco',118948);
+INSERT INTO City VALUES (2646,'Martínez de la Torre','MEX','Veracruz',118815);
+INSERT INTO City VALUES (2647,'Orizaba','MEX','Veracruz',118488);
+INSERT INTO City VALUES (2648,'Apatzingán','MEX','Michoacán de Ocampo',117849);
+INSERT INTO City VALUES (2649,'Atlixco','MEX','Puebla',117019);
+INSERT INTO City VALUES (2650,'Delicias','MEX','Chihuahua',116132);
+INSERT INTO City VALUES (2651,'Ixtlahuaca','MEX','México',115548);
+INSERT INTO City VALUES (2652,'El Mante','MEX','Tamaulipas',112453);
+INSERT INTO City VALUES (2653,'Lerdo','MEX','Durango',112272);
+INSERT INTO City VALUES (2654,'Almoloya de Juárez','MEX','México',110550);
+INSERT INTO City VALUES (2655,'Acámbaro','MEX','Guanajuato',110487);
+INSERT INTO City VALUES (2656,'Acuña','MEX','Coahuila de Zaragoza',110388);
+INSERT INTO City VALUES (2657,'Guadalupe','MEX','Zacatecas',108881);
+INSERT INTO City VALUES (2658,'Huejutla de Reyes','MEX','Hidalgo',108017);
+INSERT INTO City VALUES (2659,'Hidalgo','MEX','Michoacán de Ocampo',106198);
+INSERT INTO City VALUES (2660,'Los Cabos','MEX','Baja California Sur',105199);
+INSERT INTO City VALUES (2661,'Comitán de Domínguez','MEX','Chiapas',104986);
+INSERT INTO City VALUES (2662,'Cunduacán','MEX','Tabasco',104164);
+INSERT INTO City VALUES (2663,'Río Bravo','MEX','Tamaulipas',103901);
+INSERT INTO City VALUES (2664,'Temapache','MEX','Veracruz',102824);
+INSERT INTO City VALUES (2665,'Chilapa de Alvarez','MEX','Guerrero',102716);
+INSERT INTO City VALUES (2666,'Hidalgo del Parral','MEX','Chihuahua',100881);
+INSERT INTO City VALUES (2667,'San Francisco del Rincón','MEX','Guanajuato',100149);
+INSERT INTO City VALUES (2668,'Taxco de Alarcón','MEX','Guerrero',99907);
+INSERT INTO City VALUES (2669,'Zumpango','MEX','México',99781);
+INSERT INTO City VALUES (2670,'San Pedro Cholula','MEX','Puebla',99734);
+INSERT INTO City VALUES (2671,'Lerma','MEX','México',99714);
+INSERT INTO City VALUES (2672,'Tecomán','MEX','Colima',99296);
+INSERT INTO City VALUES (2673,'Las Margaritas','MEX','Chiapas',97389);
+INSERT INTO City VALUES (2674,'Cosoleacaque','MEX','Veracruz',97199);
+INSERT INTO City VALUES (2675,'San Luis de la Paz','MEX','Guanajuato',96763);
+INSERT INTO City VALUES (2676,'José Azueta','MEX','Guerrero',95448);
+INSERT INTO City VALUES (2677,'Santiago Ixcuintla','MEX','Nayarit',95311);
+INSERT INTO City VALUES (2678,'San Felipe','MEX','Guanajuato',95305);
+INSERT INTO City VALUES (2679,'Tejupilco','MEX','México',94934);
+INSERT INTO City VALUES (2680,'Tantoyuca','MEX','Veracruz',94709);
+INSERT INTO City VALUES (2681,'Salvatierra','MEX','Guanajuato',94322);
+INSERT INTO City VALUES (2682,'Tultepec','MEX','México',93364);
+INSERT INTO City VALUES (2683,'Temixco','MEX','Morelos',92686);
+INSERT INTO City VALUES (2684,'Matamoros','MEX','Coahuila de Zaragoza',91858);
+INSERT INTO City VALUES (2685,'Pánuco','MEX','Veracruz',90551);
+INSERT INTO City VALUES (2686,'El Fuerte','MEX','Sinaloa',89556);
+INSERT INTO City VALUES (2687,'Tierra Blanca','MEX','Veracruz',89143);
+INSERT INTO City VALUES (2688,'Weno','FSM','Chuuk',22000);
+INSERT INTO City VALUES (2689,'Palikir','FSM','Pohnpei',8600);
+INSERT INTO City VALUES (2690,'Chisinau','MDA','Chisinau',719900);
+INSERT INTO City VALUES (2691,'Tiraspol','MDA','Dnjestria',194300);
+INSERT INTO City VALUES (2692,'Balti','MDA','Balti',153400);
+INSERT INTO City VALUES (2693,'Bender (Tîghina)','MDA','Bender (Tîghina)',125700);
+INSERT INTO City VALUES (2694,'Monte-Carlo','MCO','–',13154);
+INSERT INTO City VALUES (2695,'Monaco-Ville','MCO','–',1234);
+INSERT INTO City VALUES (2696,'Ulan Bator','MNG','Ulaanbaatar',773700);
+INSERT INTO City VALUES (2697,'Plymouth','MSR','Plymouth',2000);
+INSERT INTO City VALUES (2698,'Maputo','MOZ','Maputo',1018938);
+INSERT INTO City VALUES (2699,'Matola','MOZ','Maputo',424662);
+INSERT INTO City VALUES (2700,'Beira','MOZ','Sofala',397368);
+INSERT INTO City VALUES (2701,'Nampula','MOZ','Nampula',303346);
+INSERT INTO City VALUES (2702,'Chimoio','MOZ','Manica',171056);
+INSERT INTO City VALUES (2703,'Naçala-Porto','MOZ','Nampula',158248);
+INSERT INTO City VALUES (2704,'Quelimane','MOZ','Zambézia',150116);
+INSERT INTO City VALUES (2705,'Mocuba','MOZ','Zambézia',124700);
+INSERT INTO City VALUES (2706,'Tete','MOZ','Tete',101984);
+INSERT INTO City VALUES (2707,'Xai-Xai','MOZ','Gaza',99442);
+INSERT INTO City VALUES (2708,'Gurue','MOZ','Zambézia',99300);
+INSERT INTO City VALUES (2709,'Maxixe','MOZ','Inhambane',93985);
+INSERT INTO City VALUES (2710,'Rangoon (Yangon)','MMR','Rangoon [Yangon]',3361700);
+INSERT INTO City VALUES (2711,'Mandalay','MMR','Mandalay',885300);
+INSERT INTO City VALUES (2712,'Moulmein (Mawlamyine)','MMR','Mon',307900);
+INSERT INTO City VALUES (2713,'Pegu (Bago)','MMR','Pegu [Bago]',190900);
+INSERT INTO City VALUES (2714,'Bassein (Pathein)','MMR','Irrawaddy [Ayeyarwad',183900);
+INSERT INTO City VALUES (2715,'Monywa','MMR','Sagaing',138600);
+INSERT INTO City VALUES (2716,'Sittwe (Akyab)','MMR','Rakhine',137600);
+INSERT INTO City VALUES (2717,'Taunggyi (Taunggye)','MMR','Shan',131500);
+INSERT INTO City VALUES (2718,'Meikhtila','MMR','Mandalay',129700);
+INSERT INTO City VALUES (2719,'Mergui (Myeik)','MMR','Tenasserim [Tanintha',122700);
+INSERT INTO City VALUES (2720,'Lashio (Lasho)','MMR','Shan',107600);
+INSERT INTO City VALUES (2721,'Prome (Pyay)','MMR','Pegu [Bago]',105700);
+INSERT INTO City VALUES (2722,'Henzada (Hinthada)','MMR','Irrawaddy [Ayeyarwad',104700);
+INSERT INTO City VALUES (2723,'Myingyan','MMR','Mandalay',103600);
+INSERT INTO City VALUES (2724,'Tavoy (Dawei)','MMR','Tenasserim [Tanintha',96800);
+INSERT INTO City VALUES (2725,'Pagakku (Pakokku)','MMR','Magwe [Magway]',94800);
+INSERT INTO City VALUES (2726,'Windhoek','NAM','Khomas',169000);
+INSERT INTO City VALUES (2727,'Yangor','NRU','–',4050);
+INSERT INTO City VALUES (2728,'Yaren','NRU','–',559);
+INSERT INTO City VALUES (2729,'Kathmandu','NPL','Central',591835);
+INSERT INTO City VALUES (2730,'Biratnagar','NPL','Eastern',157764);
+INSERT INTO City VALUES (2731,'Pokhara','NPL','Western',146318);
+INSERT INTO City VALUES (2732,'Lalitapur','NPL','Central',145847);
+INSERT INTO City VALUES (2733,'Birgunj','NPL','Central',90639);
+INSERT INTO City VALUES (2734,'Managua','NIC','Managua',959000);
+INSERT INTO City VALUES (2735,'León','NIC','León',123865);
+INSERT INTO City VALUES (2736,'Chinandega','NIC','Chinandega',97387);
+INSERT INTO City VALUES (2737,'Masaya','NIC','Masaya',88971);
+INSERT INTO City VALUES (2738,'Niamey','NER','Niamey',420000);
+INSERT INTO City VALUES (2739,'Zinder','NER','Zinder',120892);
+INSERT INTO City VALUES (2740,'Maradi','NER','Maradi',112965);
+INSERT INTO City VALUES (2741,'Lagos','NGA','Lagos',1518000);
+INSERT INTO City VALUES (2742,'Ibadan','NGA','Oyo & Osun',1432000);
+INSERT INTO City VALUES (2743,'Ogbomosho','NGA','Oyo & Osun',730000);
+INSERT INTO City VALUES (2744,'Kano','NGA','Kano & Jigawa',674100);
+INSERT INTO City VALUES (2745,'Oshogbo','NGA','Oyo & Osun',476800);
+INSERT INTO City VALUES (2746,'Ilorin','NGA','Kwara & Kogi',475800);
+INSERT INTO City VALUES (2747,'Abeokuta','NGA','Ogun',427400);
+INSERT INTO City VALUES (2748,'Port Harcourt','NGA','Rivers & Bayelsa',410000);
+INSERT INTO City VALUES (2749,'Zaria','NGA','Kaduna',379200);
+INSERT INTO City VALUES (2750,'Ilesha','NGA','Oyo & Osun',378400);
+INSERT INTO City VALUES (2751,'Onitsha','NGA','Anambra & Enugu & Eb',371900);
+INSERT INTO City VALUES (2752,'Iwo','NGA','Oyo & Osun',362000);
+INSERT INTO City VALUES (2753,'Ado-Ekiti','NGA','Ondo & Ekiti',359400);
+INSERT INTO City VALUES (2754,'Abuja','NGA','Federal Capital Dist',350100);
+INSERT INTO City VALUES (2755,'Kaduna','NGA','Kaduna',342200);
+INSERT INTO City VALUES (2756,'Mushin','NGA','Lagos',333200);
+INSERT INTO City VALUES (2757,'Maiduguri','NGA','Borno & Yobe',320000);
+INSERT INTO City VALUES (2758,'Enugu','NGA','Anambra & Enugu & Eb',316100);
+INSERT INTO City VALUES (2759,'Ede','NGA','Oyo & Osun',307100);
+INSERT INTO City VALUES (2760,'Aba','NGA','Imo & Abia',298900);
+INSERT INTO City VALUES (2761,'Ife','NGA','Oyo & Osun',296800);
+INSERT INTO City VALUES (2762,'Ila','NGA','Oyo & Osun',264000);
+INSERT INTO City VALUES (2763,'Oyo','NGA','Oyo & Osun',256400);
+INSERT INTO City VALUES (2764,'Ikerre','NGA','Ondo & Ekiti',244600);
+INSERT INTO City VALUES (2765,'Benin City','NGA','Edo & Delta',229400);
+INSERT INTO City VALUES (2766,'Iseyin','NGA','Oyo & Osun',217300);
+INSERT INTO City VALUES (2767,'Katsina','NGA','Katsina',206500);
+INSERT INTO City VALUES (2768,'Jos','NGA','Plateau & Nassarawa',206300);
+INSERT INTO City VALUES (2769,'Sokoto','NGA','Sokoto & Kebbi & Zam',204900);
+INSERT INTO City VALUES (2770,'Ilobu','NGA','Oyo & Osun',199000);
+INSERT INTO City VALUES (2771,'Offa','NGA','Kwara & Kogi',197200);
+INSERT INTO City VALUES (2772,'Ikorodu','NGA','Lagos',184900);
+INSERT INTO City VALUES (2773,'Ilawe-Ekiti','NGA','Ondo & Ekiti',184500);
+INSERT INTO City VALUES (2774,'Owo','NGA','Ondo & Ekiti',183500);
+INSERT INTO City VALUES (2775,'Ikirun','NGA','Oyo & Osun',181400);
+INSERT INTO City VALUES (2776,'Shaki','NGA','Oyo & Osun',174500);
+INSERT INTO City VALUES (2777,'Calabar','NGA','Cross River',174400);
+INSERT INTO City VALUES (2778,'Ondo','NGA','Ondo & Ekiti',173600);
+INSERT INTO City VALUES (2779,'Akure','NGA','Ondo & Ekiti',162300);
+INSERT INTO City VALUES (2780,'Gusau','NGA','Sokoto & Kebbi & Zam',158000);
+INSERT INTO City VALUES (2781,'Ijebu-Ode','NGA','Ogun',156400);
+INSERT INTO City VALUES (2782,'Effon-Alaiye','NGA','Oyo & Osun',153100);
+INSERT INTO City VALUES (2783,'Kumo','NGA','Bauchi & Gombe',148000);
+INSERT INTO City VALUES (2784,'Shomolu','NGA','Lagos',147700);
+INSERT INTO City VALUES (2785,'Oka-Akoko','NGA','Ondo & Ekiti',142900);
+INSERT INTO City VALUES (2786,'Ikare','NGA','Ondo & Ekiti',140800);
+INSERT INTO City VALUES (2787,'Sapele','NGA','Edo & Delta',139200);
+INSERT INTO City VALUES (2788,'Deba Habe','NGA','Bauchi & Gombe',138600);
+INSERT INTO City VALUES (2789,'Minna','NGA','Niger',136900);
+INSERT INTO City VALUES (2790,'Warri','NGA','Edo & Delta',126100);
+INSERT INTO City VALUES (2791,'Bida','NGA','Niger',125500);
+INSERT INTO City VALUES (2792,'Ikire','NGA','Oyo & Osun',123300);
+INSERT INTO City VALUES (2793,'Makurdi','NGA','Benue',123100);
+INSERT INTO City VALUES (2794,'Lafia','NGA','Plateau & Nassarawa',122500);
+INSERT INTO City VALUES (2795,'Inisa','NGA','Oyo & Osun',119800);
+INSERT INTO City VALUES (2796,'Shagamu','NGA','Ogun',117200);
+INSERT INTO City VALUES (2797,'Awka','NGA','Anambra & Enugu & Eb',111200);
+INSERT INTO City VALUES (2798,'Gombe','NGA','Bauchi & Gombe',107800);
+INSERT INTO City VALUES (2799,'Igboho','NGA','Oyo & Osun',106800);
+INSERT INTO City VALUES (2800,'Ejigbo','NGA','Oyo & Osun',105900);
+INSERT INTO City VALUES (2801,'Agege','NGA','Lagos',105000);
+INSERT INTO City VALUES (2802,'Ise-Ekiti','NGA','Ondo & Ekiti',103400);
+INSERT INTO City VALUES (2803,'Ugep','NGA','Cross River',102600);
+INSERT INTO City VALUES (2804,'Epe','NGA','Lagos',101000);
+INSERT INTO City VALUES (2805,'Alofi','NIU','–',682);
+INSERT INTO City VALUES (2806,'Kingston','NFK','–',800);
+INSERT INTO City VALUES (2807,'Oslo','NOR','Oslo',508726);
+INSERT INTO City VALUES (2808,'Bergen','NOR','Hordaland',230948);
+INSERT INTO City VALUES (2809,'Trondheim','NOR','Sør-Trøndelag',150166);
+INSERT INTO City VALUES (2810,'Stavanger','NOR','Rogaland',108848);
+INSERT INTO City VALUES (2811,'Bærum','NOR','Akershus',101340);
+INSERT INTO City VALUES (2812,'Abidjan','CIV','Abidjan',2500000);
+INSERT INTO City VALUES (2813,'Bouaké','CIV','Bouaké',329850);
+INSERT INTO City VALUES (2814,'Yamoussoukro','CIV','Yamoussoukro',130000);
+INSERT INTO City VALUES (2815,'Daloa','CIV','Daloa',121842);
+INSERT INTO City VALUES (2816,'Korhogo','CIV','Korhogo',109445);
+INSERT INTO City VALUES (2817,'al-Sib','OMN','Masqat',155000);
+INSERT INTO City VALUES (2818,'Salala','OMN','Zufar',131813);
+INSERT INTO City VALUES (2819,'Bawshar','OMN','Masqat',107500);
+INSERT INTO City VALUES (2820,'Suhar','OMN','al-Batina',90814);
+INSERT INTO City VALUES (2821,'Masqat','OMN','Masqat',51969);
+INSERT INTO City VALUES (2822,'Karachi','PAK','Sindh',9269265);
+INSERT INTO City VALUES (2823,'Lahore','PAK','Punjab',5063499);
+INSERT INTO City VALUES (2824,'Faisalabad','PAK','Punjab',1977246);
+INSERT INTO City VALUES (2825,'Rawalpindi','PAK','Punjab',1406214);
+INSERT INTO City VALUES (2826,'Multan','PAK','Punjab',1182441);
+INSERT INTO City VALUES (2827,'Hyderabad','PAK','Sindh',1151274);
+INSERT INTO City VALUES (2828,'Gujranwala','PAK','Punjab',1124749);
+INSERT INTO City VALUES (2829,'Peshawar','PAK','Nothwest Border Prov',988005);
+INSERT INTO City VALUES (2830,'Quetta','PAK','Baluchistan',560307);
+INSERT INTO City VALUES (2831,'Islamabad','PAK','Islamabad',524500);
+INSERT INTO City VALUES (2832,'Sargodha','PAK','Punjab',455360);
+INSERT INTO City VALUES (2833,'Sialkot','PAK','Punjab',417597);
+INSERT INTO City VALUES (2834,'Bahawalpur','PAK','Punjab',403408);
+INSERT INTO City VALUES (2835,'Sukkur','PAK','Sindh',329176);
+INSERT INTO City VALUES (2836,'Jhang','PAK','Punjab',292214);
+INSERT INTO City VALUES (2837,'Sheikhupura','PAK','Punjab',271875);
+INSERT INTO City VALUES (2838,'Larkana','PAK','Sindh',270366);
+INSERT INTO City VALUES (2839,'Gujrat','PAK','Punjab',250121);
+INSERT INTO City VALUES (2840,'Mardan','PAK','Nothwest Border Prov',244511);
+INSERT INTO City VALUES (2841,'Kasur','PAK','Punjab',241649);
+INSERT INTO City VALUES (2842,'Rahim Yar Khan','PAK','Punjab',228479);
+INSERT INTO City VALUES (2843,'Sahiwal','PAK','Punjab',207388);
+INSERT INTO City VALUES (2844,'Okara','PAK','Punjab',200901);
+INSERT INTO City VALUES (2845,'Wah','PAK','Punjab',198400);
+INSERT INTO City VALUES (2846,'Dera Ghazi Khan','PAK','Punjab',188100);
+INSERT INTO City VALUES (2847,'Mirpur Khas','PAK','Sind',184500);
+INSERT INTO City VALUES (2848,'Nawabshah','PAK','Sind',183100);
+INSERT INTO City VALUES (2849,'Mingora','PAK','Nothwest Border Prov',174500);
+INSERT INTO City VALUES (2850,'Chiniot','PAK','Punjab',169300);
+INSERT INTO City VALUES (2851,'Kamoke','PAK','Punjab',151000);
+INSERT INTO City VALUES (2852,'Mandi Burewala','PAK','Punjab',149900);
+INSERT INTO City VALUES (2853,'Jhelum','PAK','Punjab',145800);
+INSERT INTO City VALUES (2854,'Sadiqabad','PAK','Punjab',141500);
+INSERT INTO City VALUES (2855,'Jacobabad','PAK','Sind',137700);
+INSERT INTO City VALUES (2856,'Shikarpur','PAK','Sind',133300);
+INSERT INTO City VALUES (2857,'Khanewal','PAK','Punjab',133000);
+INSERT INTO City VALUES (2858,'Hafizabad','PAK','Punjab',130200);
+INSERT INTO City VALUES (2859,'Kohat','PAK','Nothwest Border Prov',125300);
+INSERT INTO City VALUES (2860,'Muzaffargarh','PAK','Punjab',121600);
+INSERT INTO City VALUES (2861,'Khanpur','PAK','Punjab',117800);
+INSERT INTO City VALUES (2862,'Gojra','PAK','Punjab',115000);
+INSERT INTO City VALUES (2863,'Bahawalnagar','PAK','Punjab',109600);
+INSERT INTO City VALUES (2864,'Muridke','PAK','Punjab',108600);
+INSERT INTO City VALUES (2865,'Pak Pattan','PAK','Punjab',107800);
+INSERT INTO City VALUES (2866,'Abottabad','PAK','Nothwest Border Prov',106000);
+INSERT INTO City VALUES (2867,'Tando Adam','PAK','Sind',103400);
+INSERT INTO City VALUES (2868,'Jaranwala','PAK','Punjab',103300);
+INSERT INTO City VALUES (2869,'Khairpur','PAK','Sind',102200);
+INSERT INTO City VALUES (2870,'Chishtian Mandi','PAK','Punjab',101700);
+INSERT INTO City VALUES (2871,'Daska','PAK','Punjab',101500);
+INSERT INTO City VALUES (2872,'Dadu','PAK','Sind',98600);
+INSERT INTO City VALUES (2873,'Mandi Bahauddin','PAK','Punjab',97300);
+INSERT INTO City VALUES (2874,'Ahmadpur East','PAK','Punjab',96000);
+INSERT INTO City VALUES (2875,'Kamalia','PAK','Punjab',95300);
+INSERT INTO City VALUES (2876,'Khuzdar','PAK','Baluchistan',93100);
+INSERT INTO City VALUES (2877,'Vihari','PAK','Punjab',92300);
+INSERT INTO City VALUES (2878,'Dera Ismail Khan','PAK','Nothwest Border Prov',90400);
+INSERT INTO City VALUES (2879,'Wazirabad','PAK','Punjab',89700);
+INSERT INTO City VALUES (2880,'Nowshera','PAK','Nothwest Border Prov',89400);
+INSERT INTO City VALUES (2881,'Koror','PLW','Koror',12000);
+INSERT INTO City VALUES (2882,'Ciudad de Panamá','PAN','Panamá',471373);
+INSERT INTO City VALUES (2883,'San Miguelito','PAN','San Miguelito',315382);
+INSERT INTO City VALUES (2884,'Port Moresby','PNG','National Capital Dis',247000);
+INSERT INTO City VALUES (2885,'Asunción','PRY','Asunción',557776);
+INSERT INTO City VALUES (2886,'Ciudad del Este','PRY','Alto Paraná',133881);
+INSERT INTO City VALUES (2887,'San Lorenzo','PRY','Central',133395);
+INSERT INTO City VALUES (2888,'Lambaré','PRY','Central',99681);
+INSERT INTO City VALUES (2889,'Fernando de la Mora','PRY','Central',95287);
+INSERT INTO City VALUES (2890,'Lima','PER','Lima',6464693);
+INSERT INTO City VALUES (2891,'Arequipa','PER','Arequipa',762000);
+INSERT INTO City VALUES (2892,'Trujillo','PER','La Libertad',652000);
+INSERT INTO City VALUES (2893,'Chiclayo','PER','Lambayeque',517000);
+INSERT INTO City VALUES (2894,'Callao','PER','Callao',424294);
+INSERT INTO City VALUES (2895,'Iquitos','PER','Loreto',367000);
+INSERT INTO City VALUES (2896,'Chimbote','PER','Ancash',336000);
+INSERT INTO City VALUES (2897,'Huancayo','PER','Junín',327000);
+INSERT INTO City VALUES (2898,'Piura','PER','Piura',325000);
+INSERT INTO City VALUES (2899,'Cusco','PER','Cusco',291000);
+INSERT INTO City VALUES (2900,'Pucallpa','PER','Ucayali',220866);
+INSERT INTO City VALUES (2901,'Tacna','PER','Tacna',215683);
+INSERT INTO City VALUES (2902,'Ica','PER','Ica',194820);
+INSERT INTO City VALUES (2903,'Sullana','PER','Piura',147361);
+INSERT INTO City VALUES (2904,'Juliaca','PER','Puno',142576);
+INSERT INTO City VALUES (2905,'Huánuco','PER','Huanuco',129688);
+INSERT INTO City VALUES (2906,'Ayacucho','PER','Ayacucho',118960);
+INSERT INTO City VALUES (2907,'Chincha Alta','PER','Ica',110016);
+INSERT INTO City VALUES (2908,'Cajamarca','PER','Cajamarca',108009);
+INSERT INTO City VALUES (2909,'Puno','PER','Puno',101578);
+INSERT INTO City VALUES (2910,'Ventanilla','PER','Callao',101056);
+INSERT INTO City VALUES (2911,'Castilla','PER','Piura',90642);
+INSERT INTO City VALUES (2912,'Adamstown','PCN','–',42);
+INSERT INTO City VALUES (2913,'Garapan','MNP','Saipan',9200);
+INSERT INTO City VALUES (2914,'Lisboa','PRT','Lisboa',563210);
+INSERT INTO City VALUES (2915,'Porto','PRT','Porto',273060);
+INSERT INTO City VALUES (2916,'Amadora','PRT','Lisboa',122106);
+INSERT INTO City VALUES (2917,'Coímbra','PRT','Coímbra',96100);
+INSERT INTO City VALUES (2918,'Braga','PRT','Braga',90535);
+INSERT INTO City VALUES (2919,'San Juan','PRI','San Juan',434374);
+INSERT INTO City VALUES (2920,'Bayamón','PRI','Bayamón',224044);
+INSERT INTO City VALUES (2921,'Ponce','PRI','Ponce',186475);
+INSERT INTO City VALUES (2922,'Carolina','PRI','Carolina',186076);
+INSERT INTO City VALUES (2923,'Caguas','PRI','Caguas',140502);
+INSERT INTO City VALUES (2924,'Arecibo','PRI','Arecibo',100131);
+INSERT INTO City VALUES (2925,'Guaynabo','PRI','Guaynabo',100053);
+INSERT INTO City VALUES (2926,'Mayagüez','PRI','Mayagüez',98434);
+INSERT INTO City VALUES (2927,'Toa Baja','PRI','Toa Baja',94085);
+INSERT INTO City VALUES (2928,'Warszawa','POL','Mazowieckie',1615369);
+INSERT INTO City VALUES (2929,'Lódz','POL','Lodzkie',800110);
+INSERT INTO City VALUES (2930,'Kraków','POL','Malopolskie',738150);
+INSERT INTO City VALUES (2931,'Wroclaw','POL','Dolnoslaskie',636765);
+INSERT INTO City VALUES (2932,'Poznan','POL','Wielkopolskie',576899);
+INSERT INTO City VALUES (2933,'Gdansk','POL','Pomorskie',458988);
+INSERT INTO City VALUES (2934,'Szczecin','POL','Zachodnio-Pomorskie',416988);
+INSERT INTO City VALUES (2935,'Bydgoszcz','POL','Kujawsko-Pomorskie',386855);
+INSERT INTO City VALUES (2936,'Lublin','POL','Lubelskie',356251);
+INSERT INTO City VALUES (2937,'Katowice','POL','Slaskie',345934);
+INSERT INTO City VALUES (2938,'Bialystok','POL','Podlaskie',283937);
+INSERT INTO City VALUES (2939,'Czestochowa','POL','Slaskie',257812);
+INSERT INTO City VALUES (2940,'Gdynia','POL','Pomorskie',253521);
+INSERT INTO City VALUES (2941,'Sosnowiec','POL','Slaskie',244102);
+INSERT INTO City VALUES (2942,'Radom','POL','Mazowieckie',232262);
+INSERT INTO City VALUES (2943,'Kielce','POL','Swietokrzyskie',212383);
+INSERT INTO City VALUES (2944,'Gliwice','POL','Slaskie',212164);
+INSERT INTO City VALUES (2945,'Torun','POL','Kujawsko-Pomorskie',206158);
+INSERT INTO City VALUES (2946,'Bytom','POL','Slaskie',205560);
+INSERT INTO City VALUES (2947,'Zabrze','POL','Slaskie',200177);
+INSERT INTO City VALUES (2948,'Bielsko-Biala','POL','Slaskie',180307);
+INSERT INTO City VALUES (2949,'Olsztyn','POL','Warminsko-Mazurskie',170904);
+INSERT INTO City VALUES (2950,'Rzeszów','POL','Podkarpackie',162049);
+INSERT INTO City VALUES (2951,'Ruda Slaska','POL','Slaskie',159665);
+INSERT INTO City VALUES (2952,'Rybnik','POL','Slaskie',144582);
+INSERT INTO City VALUES (2953,'Walbrzych','POL','Dolnoslaskie',136923);
+INSERT INTO City VALUES (2954,'Tychy','POL','Slaskie',133178);
+INSERT INTO City VALUES (2955,'Dabrowa Górnicza','POL','Slaskie',131037);
+INSERT INTO City VALUES (2956,'Plock','POL','Mazowieckie',131011);
+INSERT INTO City VALUES (2957,'Elblag','POL','Warminsko-Mazurskie',129782);
+INSERT INTO City VALUES (2958,'Opole','POL','Opolskie',129553);
+INSERT INTO City VALUES (2959,'Gorzów Wielkopolski','POL','Lubuskie',126019);
+INSERT INTO City VALUES (2960,'Wloclawek','POL','Kujawsko-Pomorskie',123373);
+INSERT INTO City VALUES (2961,'Chorzów','POL','Slaskie',121708);
+INSERT INTO City VALUES (2962,'Tarnów','POL','Malopolskie',121494);
+INSERT INTO City VALUES (2963,'Zielona Góra','POL','Lubuskie',118182);
+INSERT INTO City VALUES (2964,'Koszalin','POL','Zachodnio-Pomorskie',112375);
+INSERT INTO City VALUES (2965,'Legnica','POL','Dolnoslaskie',109335);
+INSERT INTO City VALUES (2966,'Kalisz','POL','Wielkopolskie',106641);
+INSERT INTO City VALUES (2967,'Grudziadz','POL','Kujawsko-Pomorskie',102434);
+INSERT INTO City VALUES (2968,'Slupsk','POL','Pomorskie',102370);
+INSERT INTO City VALUES (2969,'Jastrzebie-Zdrój','POL','Slaskie',102294);
+INSERT INTO City VALUES (2970,'Jaworzno','POL','Slaskie',97929);
+INSERT INTO City VALUES (2971,'Jelenia Góra','POL','Dolnoslaskie',93901);
+INSERT INTO City VALUES (2972,'Malabo','GNQ','Bioko',40000);
+INSERT INTO City VALUES (2973,'Doha','QAT','Doha',355000);
+INSERT INTO City VALUES (2974,'Paris','FRA','Île-de-France',2125246);
+INSERT INTO City VALUES (2975,'Marseille','FRA','Provence-Alpes-Côte',798430);
+INSERT INTO City VALUES (2976,'Lyon','FRA','Rhône-Alpes',445452);
+INSERT INTO City VALUES (2977,'Toulouse','FRA','Midi-Pyrénées',390350);
+INSERT INTO City VALUES (2978,'Nice','FRA','Provence-Alpes-Côte',342738);
+INSERT INTO City VALUES (2979,'Nantes','FRA','Pays de la Loire',270251);
+INSERT INTO City VALUES (2980,'Strasbourg','FRA','Alsace',264115);
+INSERT INTO City VALUES (2981,'Montpellier','FRA','Languedoc-Roussillon',225392);
+INSERT INTO City VALUES (2982,'Bordeaux','FRA','Aquitaine',215363);
+INSERT INTO City VALUES (2983,'Rennes','FRA','Haute-Normandie',206229);
+INSERT INTO City VALUES (2984,'Le Havre','FRA','Champagne-Ardenne',190905);
+INSERT INTO City VALUES (2985,'Reims','FRA','Nord-Pas-de-Calais',187206);
+INSERT INTO City VALUES (2986,'Lille','FRA','Rhône-Alpes',184657);
+INSERT INTO City VALUES (2987,'St-Étienne','FRA','Bretagne',180210);
+INSERT INTO City VALUES (2988,'Toulon','FRA','Provence-Alpes-Côte',160639);
+INSERT INTO City VALUES (2989,'Grenoble','FRA','Rhône-Alpes',153317);
+INSERT INTO City VALUES (2990,'Angers','FRA','Pays de la Loire',151279);
+INSERT INTO City VALUES (2991,'Dijon','FRA','Bourgogne',149867);
+INSERT INTO City VALUES (2992,'Brest','FRA','Bretagne',149634);
+INSERT INTO City VALUES (2993,'Le Mans','FRA','Pays de la Loire',146105);
+INSERT INTO City VALUES (2994,'Clermont-Ferrand','FRA','Auvergne',137140);
+INSERT INTO City VALUES (2995,'Amiens','FRA','Picardie',135501);
+INSERT INTO City VALUES (2996,'Aix-en-Provence','FRA','Provence-Alpes-Côte',134222);
+INSERT INTO City VALUES (2997,'Limoges','FRA','Limousin',133968);
+INSERT INTO City VALUES (2998,'Nîmes','FRA','Languedoc-Roussillon',133424);
+INSERT INTO City VALUES (2999,'Tours','FRA','Centre',132820);
+INSERT INTO City VALUES (3000,'Villeurbanne','FRA','Rhône-Alpes',124215);
+INSERT INTO City VALUES (3001,'Metz','FRA','Lorraine',123776);
+INSERT INTO City VALUES (3002,'Besançon','FRA','Franche-Comté',117733);
+INSERT INTO City VALUES (3003,'Caen','FRA','Basse-Normandie',113987);
+INSERT INTO City VALUES (3004,'Orléans','FRA','Centre',113126);
+INSERT INTO City VALUES (3005,'Mulhouse','FRA','Alsace',110359);
+INSERT INTO City VALUES (3006,'Rouen','FRA','Haute-Normandie',106592);
+INSERT INTO City VALUES (3007,'Boulogne-Billancourt','FRA','Île-de-France',106367);
+INSERT INTO City VALUES (3008,'Perpignan','FRA','Languedoc-Roussillon',105115);
+INSERT INTO City VALUES (3009,'Nancy','FRA','Lorraine',103605);
+INSERT INTO City VALUES (3010,'Roubaix','FRA','Nord-Pas-de-Calais',96984);
+INSERT INTO City VALUES (3011,'Argenteuil','FRA','Île-de-France',93961);
+INSERT INTO City VALUES (3012,'Tourcoing','FRA','Nord-Pas-de-Calais',93540);
+INSERT INTO City VALUES (3013,'Montreuil','FRA','Île-de-France',90674);
+INSERT INTO City VALUES (3014,'Cayenne','GUF','Cayenne',50699);
+INSERT INTO City VALUES (3015,'Faaa','PYF','Tahiti',25888);
+INSERT INTO City VALUES (3016,'Papeete','PYF','Tahiti',25553);
+INSERT INTO City VALUES (3017,'Saint-Denis','REU','Saint-Denis',131480);
+INSERT INTO City VALUES (3018,'Bucuresti','ROM','Bukarest',2016131);
+INSERT INTO City VALUES (3019,'Iasi','ROM','Iasi',348070);
+INSERT INTO City VALUES (3020,'Constanta','ROM','Constanta',342264);
+INSERT INTO City VALUES (3021,'Cluj-Napoca','ROM','Cluj',332498);
+INSERT INTO City VALUES (3022,'Galati','ROM','Galati',330276);
+INSERT INTO City VALUES (3023,'Timisoara','ROM','Timis',324304);
+INSERT INTO City VALUES (3024,'Brasov','ROM','Brasov',314225);
+INSERT INTO City VALUES (3025,'Craiova','ROM','Dolj',313530);
+INSERT INTO City VALUES (3026,'Ploiesti','ROM','Prahova',251348);
+INSERT INTO City VALUES (3027,'Braila','ROM','Braila',233756);
+INSERT INTO City VALUES (3028,'Oradea','ROM','Bihor',222239);
+INSERT INTO City VALUES (3029,'Bacau','ROM','Bacau',209235);
+INSERT INTO City VALUES (3030,'Pitesti','ROM','Arges',187170);
+INSERT INTO City VALUES (3031,'Arad','ROM','Arad',184408);
+INSERT INTO City VALUES (3032,'Sibiu','ROM','Sibiu',169611);
+INSERT INTO City VALUES (3033,'Târgu Mures','ROM','Mures',165153);
+INSERT INTO City VALUES (3034,'Baia Mare','ROM','Maramures',149665);
+INSERT INTO City VALUES (3035,'Buzau','ROM','Buzau',148372);
+INSERT INTO City VALUES (3036,'Satu Mare','ROM','Satu Mare',130059);
+INSERT INTO City VALUES (3037,'Botosani','ROM','Botosani',128730);
+INSERT INTO City VALUES (3038,'Piatra Neamt','ROM','Neamt',125070);
+INSERT INTO City VALUES (3039,'Râmnicu Vâlcea','ROM','Vâlcea',119741);
+INSERT INTO City VALUES (3040,'Suceava','ROM','Suceava',118549);
+INSERT INTO City VALUES (3041,'Drobeta-Turnu Severin','ROM','Mehedinti',117865);
+INSERT INTO City VALUES (3042,'Târgoviste','ROM','Dâmbovita',98980);
+INSERT INTO City VALUES (3043,'Focsani','ROM','Vrancea',98979);
+INSERT INTO City VALUES (3044,'Târgu Jiu','ROM','Gorj',98524);
+INSERT INTO City VALUES (3045,'Tulcea','ROM','Tulcea',96278);
+INSERT INTO City VALUES (3046,'Resita','ROM','Caras-Severin',93976);
+INSERT INTO City VALUES (3047,'Kigali','RWA','Kigali',286000);
+INSERT INTO City VALUES (3048,'Stockholm','SWE','Lisboa',750348);
+INSERT INTO City VALUES (3049,'Gothenburg [Göteborg]','SWE','West Götanmaan län',466990);
+INSERT INTO City VALUES (3050,'Malmö','SWE','Skåne län',259579);
+INSERT INTO City VALUES (3051,'Uppsala','SWE','Uppsala län',189569);
+INSERT INTO City VALUES (3052,'Linköping','SWE','East Götanmaan län',133168);
+INSERT INTO City VALUES (3053,'Västerås','SWE','Västmanlands län',126328);
+INSERT INTO City VALUES (3054,'Örebro','SWE','Örebros län',124207);
+INSERT INTO City VALUES (3055,'Norrköping','SWE','East Götanmaan län',122199);
+INSERT INTO City VALUES (3056,'Helsingborg','SWE','Skåne län',117737);
+INSERT INTO City VALUES (3057,'Jönköping','SWE','Jönköpings län',117095);
+INSERT INTO City VALUES (3058,'Umeå','SWE','Västerbottens län',104512);
+INSERT INTO City VALUES (3059,'Lund','SWE','Skåne län',98948);
+INSERT INTO City VALUES (3060,'Borås','SWE','West Götanmaan län',96883);
+INSERT INTO City VALUES (3061,'Sundsvall','SWE','Västernorrlands län',93126);
+INSERT INTO City VALUES (3062,'Gävle','SWE','Gävleborgs län',90742);
+INSERT INTO City VALUES (3063,'Jamestown','SHN','Saint Helena',1500);
+INSERT INTO City VALUES (3064,'Basseterre','KNA','St George Basseterre',11600);
+INSERT INTO City VALUES (3065,'Castries','LCA','Castries',2301);
+INSERT INTO City VALUES (3066,'Kingstown','VCT','St George',17100);
+INSERT INTO City VALUES (3067,'Saint-Pierre','SPM','Saint-Pierre',5808);
+INSERT INTO City VALUES (3068,'Berlin','DEU','Berliini',3386667);
+INSERT INTO City VALUES (3069,'Hamburg','DEU','Hamburg',1704735);
+INSERT INTO City VALUES (3070,'Munich [München]','DEU','Baijeri',1194560);
+INSERT INTO City VALUES (3071,'Köln','DEU','Nordrhein-Westfalen',962507);
+INSERT INTO City VALUES (3072,'Frankfurt am Main','DEU','Hessen',643821);
+INSERT INTO City VALUES (3073,'Essen','DEU','Nordrhein-Westfalen',599515);
+INSERT INTO City VALUES (3074,'Dortmund','DEU','Nordrhein-Westfalen',590213);
+INSERT INTO City VALUES (3075,'Stuttgart','DEU','Baden-Württemberg',582443);
+INSERT INTO City VALUES (3076,'Düsseldorf','DEU','Nordrhein-Westfalen',568855);
+INSERT INTO City VALUES (3077,'Bremen','DEU','Bremen',540330);
+INSERT INTO City VALUES (3078,'Duisburg','DEU','Nordrhein-Westfalen',519793);
+INSERT INTO City VALUES (3079,'Hannover','DEU','Niedersachsen',514718);
+INSERT INTO City VALUES (3080,'Leipzig','DEU','Saksi',489532);
+INSERT INTO City VALUES (3081,'Nürnberg','DEU','Baijeri',486628);
+INSERT INTO City VALUES (3082,'Dresden','DEU','Saksi',476668);
+INSERT INTO City VALUES (3083,'Bochum','DEU','Nordrhein-Westfalen',392830);
+INSERT INTO City VALUES (3084,'Wuppertal','DEU','Nordrhein-Westfalen',368993);
+INSERT INTO City VALUES (3085,'Bielefeld','DEU','Nordrhein-Westfalen',321125);
+INSERT INTO City VALUES (3086,'Mannheim','DEU','Baden-Württemberg',307730);
+INSERT INTO City VALUES (3087,'Bonn','DEU','Nordrhein-Westfalen',301048);
+INSERT INTO City VALUES (3088,'Gelsenkirchen','DEU','Nordrhein-Westfalen',281979);
+INSERT INTO City VALUES (3089,'Karlsruhe','DEU','Baden-Württemberg',277204);
+INSERT INTO City VALUES (3090,'Wiesbaden','DEU','Hessen',268716);
+INSERT INTO City VALUES (3091,'Münster','DEU','Nordrhein-Westfalen',264670);
+INSERT INTO City VALUES (3092,'Mönchengladbach','DEU','Nordrhein-Westfalen',263697);
+INSERT INTO City VALUES (3093,'Chemnitz','DEU','Saksi',263222);
+INSERT INTO City VALUES (3094,'Augsburg','DEU','Baijeri',254867);
+INSERT INTO City VALUES (3095,'Halle/Saale','DEU','Anhalt Sachsen',254360);
+INSERT INTO City VALUES (3096,'Braunschweig','DEU','Niedersachsen',246322);
+INSERT INTO City VALUES (3097,'Aachen','DEU','Nordrhein-Westfalen',243825);
+INSERT INTO City VALUES (3098,'Krefeld','DEU','Nordrhein-Westfalen',241769);
+INSERT INTO City VALUES (3099,'Magdeburg','DEU','Anhalt Sachsen',235073);
+INSERT INTO City VALUES (3100,'Kiel','DEU','Schleswig-Holstein',233795);
+INSERT INTO City VALUES (3101,'Oberhausen','DEU','Nordrhein-Westfalen',222349);
+INSERT INTO City VALUES (3102,'Lübeck','DEU','Schleswig-Holstein',213326);
+INSERT INTO City VALUES (3103,'Hagen','DEU','Nordrhein-Westfalen',205201);
+INSERT INTO City VALUES (3104,'Rostock','DEU','Mecklenburg-Vorpomme',203279);
+INSERT INTO City VALUES (3105,'Freiburg im Breisgau','DEU','Baden-Württemberg',202455);
+INSERT INTO City VALUES (3106,'Erfurt','DEU','Thüringen',201267);
+INSERT INTO City VALUES (3107,'Kassel','DEU','Hessen',196211);
+INSERT INTO City VALUES (3108,'Saarbrücken','DEU','Saarland',183836);
+INSERT INTO City VALUES (3109,'Mainz','DEU','Rheinland-Pfalz',183134);
+INSERT INTO City VALUES (3110,'Hamm','DEU','Nordrhein-Westfalen',181804);
+INSERT INTO City VALUES (3111,'Herne','DEU','Nordrhein-Westfalen',175661);
+INSERT INTO City VALUES (3112,'Mülheim an der Ruhr','DEU','Nordrhein-Westfalen',173895);
+INSERT INTO City VALUES (3113,'Solingen','DEU','Nordrhein-Westfalen',165583);
+INSERT INTO City VALUES (3114,'Osnabrück','DEU','Niedersachsen',164539);
+INSERT INTO City VALUES (3115,'Ludwigshafen am Rhein','DEU','Rheinland-Pfalz',163771);
+INSERT INTO City VALUES (3116,'Leverkusen','DEU','Nordrhein-Westfalen',160841);
+INSERT INTO City VALUES (3117,'Oldenburg','DEU','Niedersachsen',154125);
+INSERT INTO City VALUES (3118,'Neuss','DEU','Nordrhein-Westfalen',149702);
+INSERT INTO City VALUES (3119,'Heidelberg','DEU','Baden-Württemberg',139672);
+INSERT INTO City VALUES (3120,'Darmstadt','DEU','Hessen',137776);
+INSERT INTO City VALUES (3121,'Paderborn','DEU','Nordrhein-Westfalen',137647);
+INSERT INTO City VALUES (3122,'Potsdam','DEU','Brandenburg',128983);
+INSERT INTO City VALUES (3123,'Würzburg','DEU','Baijeri',127350);
+INSERT INTO City VALUES (3124,'Regensburg','DEU','Baijeri',125236);
+INSERT INTO City VALUES (3125,'Recklinghausen','DEU','Nordrhein-Westfalen',125022);
+INSERT INTO City VALUES (3126,'Göttingen','DEU','Niedersachsen',124775);
+INSERT INTO City VALUES (3127,'Bremerhaven','DEU','Bremen',122735);
+INSERT INTO City VALUES (3128,'Wolfsburg','DEU','Niedersachsen',121954);
+INSERT INTO City VALUES (3129,'Bottrop','DEU','Nordrhein-Westfalen',121097);
+INSERT INTO City VALUES (3130,'Remscheid','DEU','Nordrhein-Westfalen',120125);
+INSERT INTO City VALUES (3131,'Heilbronn','DEU','Baden-Württemberg',119526);
+INSERT INTO City VALUES (3132,'Pforzheim','DEU','Baden-Württemberg',117227);
+INSERT INTO City VALUES (3133,'Offenbach am Main','DEU','Hessen',116627);
+INSERT INTO City VALUES (3134,'Ulm','DEU','Baden-Württemberg',116103);
+INSERT INTO City VALUES (3135,'Ingolstadt','DEU','Baijeri',114826);
+INSERT INTO City VALUES (3136,'Gera','DEU','Thüringen',114718);
+INSERT INTO City VALUES (3137,'Salzgitter','DEU','Niedersachsen',112934);
+INSERT INTO City VALUES (3138,'Cottbus','DEU','Brandenburg',110894);
+INSERT INTO City VALUES (3139,'Reutlingen','DEU','Baden-Württemberg',110343);
+INSERT INTO City VALUES (3140,'Fürth','DEU','Baijeri',109771);
+INSERT INTO City VALUES (3141,'Siegen','DEU','Nordrhein-Westfalen',109225);
+INSERT INTO City VALUES (3142,'Koblenz','DEU','Rheinland-Pfalz',108003);
+INSERT INTO City VALUES (3143,'Moers','DEU','Nordrhein-Westfalen',106837);
+INSERT INTO City VALUES (3144,'Bergisch Gladbach','DEU','Nordrhein-Westfalen',106150);
+INSERT INTO City VALUES (3145,'Zwickau','DEU','Saksi',104146);
+INSERT INTO City VALUES (3146,'Hildesheim','DEU','Niedersachsen',104013);
+INSERT INTO City VALUES (3147,'Witten','DEU','Nordrhein-Westfalen',103384);
+INSERT INTO City VALUES (3148,'Schwerin','DEU','Mecklenburg-Vorpomme',102878);
+INSERT INTO City VALUES (3149,'Erlangen','DEU','Baijeri',100750);
+INSERT INTO City VALUES (3150,'Kaiserslautern','DEU','Rheinland-Pfalz',100025);
+INSERT INTO City VALUES (3151,'Trier','DEU','Rheinland-Pfalz',99891);
+INSERT INTO City VALUES (3152,'Jena','DEU','Thüringen',99779);
+INSERT INTO City VALUES (3153,'Iserlohn','DEU','Nordrhein-Westfalen',99474);
+INSERT INTO City VALUES (3154,'Gütersloh','DEU','Nordrhein-Westfalen',95028);
+INSERT INTO City VALUES (3155,'Marl','DEU','Nordrhein-Westfalen',93735);
+INSERT INTO City VALUES (3156,'Lünen','DEU','Nordrhein-Westfalen',92044);
+INSERT INTO City VALUES (3157,'Düren','DEU','Nordrhein-Westfalen',91092);
+INSERT INTO City VALUES (3158,'Ratingen','DEU','Nordrhein-Westfalen',90951);
+INSERT INTO City VALUES (3159,'Velbert','DEU','Nordrhein-Westfalen',89881);
+INSERT INTO City VALUES (3160,'Esslingen am Neckar','DEU','Baden-Württemberg',89667);
+INSERT INTO City VALUES (3161,'Honiara','SLB','Honiara',50100);
+INSERT INTO City VALUES (3162,'Lusaka','ZMB','Lusaka',1317000);
+INSERT INTO City VALUES (3163,'Ndola','ZMB','Copperbelt',329200);
+INSERT INTO City VALUES (3164,'Kitwe','ZMB','Copperbelt',288600);
+INSERT INTO City VALUES (3165,'Kabwe','ZMB','Central',154300);
+INSERT INTO City VALUES (3166,'Chingola','ZMB','Copperbelt',142400);
+INSERT INTO City VALUES (3167,'Mufulira','ZMB','Copperbelt',123900);
+INSERT INTO City VALUES (3168,'Luanshya','ZMB','Copperbelt',118100);
+INSERT INTO City VALUES (3169,'Apia','WSM','Upolu',35900);
+INSERT INTO City VALUES (3170,'Serravalle','SMR','Serravalle/Dogano',4802);
+INSERT INTO City VALUES (3171,'San Marino','SMR','San Marino',2294);
+INSERT INTO City VALUES (3172,'São Tomé','STP','Aqua Grande',49541);
+INSERT INTO City VALUES (3173,'Riyadh','SAU','Riyadh',3324000);
+INSERT INTO City VALUES (3174,'Jedda','SAU','Mekka',2046300);
+INSERT INTO City VALUES (3175,'Mekka','SAU','Mekka',965700);
+INSERT INTO City VALUES (3176,'Medina','SAU','Medina',608300);
+INSERT INTO City VALUES (3177,'al-Dammam','SAU','al-Sharqiya',482300);
+INSERT INTO City VALUES (3178,'al-Taif','SAU','Mekka',416100);
+INSERT INTO City VALUES (3179,'Tabuk','SAU','Tabuk',292600);
+INSERT INTO City VALUES (3180,'Burayda','SAU','al-Qasim',248600);
+INSERT INTO City VALUES (3181,'al-Hufuf','SAU','al-Sharqiya',225800);
+INSERT INTO City VALUES (3182,'al-Mubarraz','SAU','al-Sharqiya',219100);
+INSERT INTO City VALUES (3183,'Khamis Mushayt','SAU','Asir',217900);
+INSERT INTO City VALUES (3184,'Hail','SAU','Hail',176800);
+INSERT INTO City VALUES (3185,'al-Kharj','SAU','Riad',152100);
+INSERT INTO City VALUES (3186,'al-Khubar','SAU','al-Sharqiya',141700);
+INSERT INTO City VALUES (3187,'Jubayl','SAU','al-Sharqiya',140800);
+INSERT INTO City VALUES (3188,'Hafar al-Batin','SAU','al-Sharqiya',137800);
+INSERT INTO City VALUES (3189,'al-Tuqba','SAU','al-Sharqiya',125700);
+INSERT INTO City VALUES (3190,'Yanbu','SAU','Medina',119800);
+INSERT INTO City VALUES (3191,'Abha','SAU','Asir',112300);
+INSERT INTO City VALUES (3192,'Ara´ar','SAU','al-Khudud al-Samaliy',108100);
+INSERT INTO City VALUES (3193,'al-Qatif','SAU','al-Sharqiya',98900);
+INSERT INTO City VALUES (3194,'al-Hawiya','SAU','Mekka',93900);
+INSERT INTO City VALUES (3195,'Unayza','SAU','Qasim',91100);
+INSERT INTO City VALUES (3196,'Najran','SAU','Najran',91000);
+INSERT INTO City VALUES (3197,'Pikine','SEN','Cap-Vert',855287);
+INSERT INTO City VALUES (3198,'Dakar','SEN','Cap-Vert',785071);
+INSERT INTO City VALUES (3199,'Thiès','SEN','Thiès',248000);
+INSERT INTO City VALUES (3200,'Kaolack','SEN','Kaolack',199000);
+INSERT INTO City VALUES (3201,'Ziguinchor','SEN','Ziguinchor',192000);
+INSERT INTO City VALUES (3202,'Rufisque','SEN','Cap-Vert',150000);
+INSERT INTO City VALUES (3203,'Saint-Louis','SEN','Saint-Louis',132400);
+INSERT INTO City VALUES (3204,'Mbour','SEN','Thiès',109300);
+INSERT INTO City VALUES (3205,'Diourbel','SEN','Diourbel',99400);
+INSERT INTO City VALUES (3206,'Victoria','SYC','Mahé',41000);
+INSERT INTO City VALUES (3207,'Freetown','SLE','Western',850000);
+INSERT INTO City VALUES (3208,'Singapore','SGP','–',4017733);
+INSERT INTO City VALUES (3209,'Bratislava','SVK','Bratislava',448292);
+INSERT INTO City VALUES (3210,'Košice','SVK','Východné Slovensko',241874);
+INSERT INTO City VALUES (3211,'Prešov','SVK','Východné Slovensko',93977);
+INSERT INTO City VALUES (3212,'Ljubljana','SVN','Osrednjeslovenska',270986);
+INSERT INTO City VALUES (3213,'Maribor','SVN','Podravska',115532);
+INSERT INTO City VALUES (3214,'Mogadishu','SOM','Banaadir',997000);
+INSERT INTO City VALUES (3215,'Hargeysa','SOM','Woqooyi Galbeed',90000);
+INSERT INTO City VALUES (3216,'Kismaayo','SOM','Jubbada Hoose',90000);
+INSERT INTO City VALUES (3217,'Colombo','LKA','Western',645000);
+INSERT INTO City VALUES (3218,'Dehiwala','LKA','Western',203000);
+INSERT INTO City VALUES (3219,'Moratuwa','LKA','Western',190000);
+INSERT INTO City VALUES (3220,'Jaffna','LKA','Northern',149000);
+INSERT INTO City VALUES (3221,'Kandy','LKA','Central',140000);
+INSERT INTO City VALUES (3222,'Sri Jayawardenepura Kotte','LKA','Western',118000);
+INSERT INTO City VALUES (3223,'Negombo','LKA','Western',100000);
+INSERT INTO City VALUES (3224,'Omdurman','SDN','Khartum',1271403);
+INSERT INTO City VALUES (3225,'Khartum','SDN','Khartum',947483);
+INSERT INTO City VALUES (3226,'Sharq al-Nil','SDN','Khartum',700887);
+INSERT INTO City VALUES (3227,'Port Sudan','SDN','al-Bahr al-Ahmar',308195);
+INSERT INTO City VALUES (3228,'Kassala','SDN','Kassala',234622);
+INSERT INTO City VALUES (3229,'Obeid','SDN','Kurdufan al-Shamaliy',229425);
+INSERT INTO City VALUES (3230,'Nyala','SDN','Darfur al-Janubiya',227183);
+INSERT INTO City VALUES (3231,'Wad Madani','SDN','al-Jazira',211362);
+INSERT INTO City VALUES (3232,'al-Qadarif','SDN','al-Qadarif',191164);
+INSERT INTO City VALUES (3233,'Kusti','SDN','al-Bahr al-Abyad',173599);
+INSERT INTO City VALUES (3234,'al-Fashir','SDN','Darfur al-Shamaliya',141884);
+INSERT INTO City VALUES (3235,'Juba','SDN','Bahr al-Jabal',114980);
+INSERT INTO City VALUES (3236,'Helsinki [Helsingfors]','FIN','Newmaa',555474);
+INSERT INTO City VALUES (3237,'Espoo','FIN','Newmaa',213271);
+INSERT INTO City VALUES (3238,'Tampere','FIN','Pirkanmaa',195468);
+INSERT INTO City VALUES (3239,'Vantaa','FIN','Newmaa',178471);
+INSERT INTO City VALUES (3240,'Turku [Åbo]','FIN','Varsinais-Suomi',172561);
+INSERT INTO City VALUES (3241,'Oulu','FIN','Pohjois-Pohjanmaa',120753);
+INSERT INTO City VALUES (3242,'Lahti','FIN','Päijät-Häme',96921);
+INSERT INTO City VALUES (3243,'Paramaribo','SUR','Paramaribo',112000);
+INSERT INTO City VALUES (3244,'Mbabane','SWZ','Hhohho',61000);
+INSERT INTO City VALUES (3245,'Zürich','CHE','Zürich',336800);
+INSERT INTO City VALUES (3246,'Geneve','CHE','Geneve',173500);
+INSERT INTO City VALUES (3247,'Basel','CHE','Basel-Stadt',166700);
+INSERT INTO City VALUES (3248,'Bern','CHE','Bern',122700);
+INSERT INTO City VALUES (3249,'Lausanne','CHE','Vaud',114500);
+INSERT INTO City VALUES (3250,'Damascus','SYR','Damascus',1347000);
+INSERT INTO City VALUES (3251,'Aleppo','SYR','Aleppo',1261983);
+INSERT INTO City VALUES (3252,'Hims','SYR','Hims',507404);
+INSERT INTO City VALUES (3253,'Hama','SYR','Hama',343361);
+INSERT INTO City VALUES (3254,'Latakia','SYR','Latakia',264563);
+INSERT INTO City VALUES (3255,'al-Qamishliya','SYR','al-Hasaka',144286);
+INSERT INTO City VALUES (3256,'Dayr al-Zawr','SYR','Dayr al-Zawr',140459);
+INSERT INTO City VALUES (3257,'Jaramana','SYR','Damaskos',138469);
+INSERT INTO City VALUES (3258,'Duma','SYR','Damaskos',131158);
+INSERT INTO City VALUES (3259,'al-Raqqa','SYR','al-Raqqa',108020);
+INSERT INTO City VALUES (3260,'Idlib','SYR','Idlib',91081);
+INSERT INTO City VALUES (3261,'Dushanbe','TJK','Karotegin',524000);
+INSERT INTO City VALUES (3262,'Khujand','TJK','Khujand',161500);
+INSERT INTO City VALUES (3263,'Taipei','TWN','Taipei',2641312);
+INSERT INTO City VALUES (3264,'Kaohsiung','TWN','Kaohsiung',1475505);
+INSERT INTO City VALUES (3265,'Taichung','TWN','Taichung',940589);
+INSERT INTO City VALUES (3266,'Tainan','TWN','Tainan',728060);
+INSERT INTO City VALUES (3267,'Panchiao','TWN','Taipei',523850);
+INSERT INTO City VALUES (3268,'Chungho','TWN','Taipei',392176);
+INSERT INTO City VALUES (3269,'Keelung (Chilung)','TWN','Keelung',385201);
+INSERT INTO City VALUES (3270,'Sanchung','TWN','Taipei',380084);
+INSERT INTO City VALUES (3271,'Hsinchuang','TWN','Taipei',365048);
+INSERT INTO City VALUES (3272,'Hsinchu','TWN','Hsinchu',361958);
+INSERT INTO City VALUES (3273,'Chungli','TWN','Taoyuan',318649);
+INSERT INTO City VALUES (3274,'Fengshan','TWN','Kaohsiung',318562);
+INSERT INTO City VALUES (3275,'Taoyuan','TWN','Taoyuan',316438);
+INSERT INTO City VALUES (3276,'Chiayi','TWN','Chiayi',265109);
+INSERT INTO City VALUES (3277,'Hsintien','TWN','Taipei',263603);
+INSERT INTO City VALUES (3278,'Changhwa','TWN','Changhwa',227715);
+INSERT INTO City VALUES (3279,'Yungho','TWN','Taipei',227700);
+INSERT INTO City VALUES (3280,'Tucheng','TWN','Taipei',224897);
+INSERT INTO City VALUES (3281,'Pingtung','TWN','Pingtung',214727);
+INSERT INTO City VALUES (3282,'Yungkang','TWN','Tainan',193005);
+INSERT INTO City VALUES (3283,'Pingchen','TWN','Taoyuan',188344);
+INSERT INTO City VALUES (3284,'Tali','TWN','Taichung',171940);
+INSERT INTO City VALUES (3285,'Taiping','TWN','',165524);
+INSERT INTO City VALUES (3286,'Pate','TWN','Taoyuan',161700);
+INSERT INTO City VALUES (3287,'Fengyuan','TWN','Taichung',161032);
+INSERT INTO City VALUES (3288,'Luchou','TWN','Taipei',160516);
+INSERT INTO City VALUES (3289,'Hsichuh','TWN','Taipei',154976);
+INSERT INTO City VALUES (3290,'Shulin','TWN','Taipei',151260);
+INSERT INTO City VALUES (3291,'Yuanlin','TWN','Changhwa',126402);
+INSERT INTO City VALUES (3292,'Yangmei','TWN','Taoyuan',126323);
+INSERT INTO City VALUES (3293,'Taliao','TWN','',115897);
+INSERT INTO City VALUES (3294,'Kueishan','TWN','',112195);
+INSERT INTO City VALUES (3295,'Tanshui','TWN','Taipei',111882);
+INSERT INTO City VALUES (3296,'Taitung','TWN','Taitung',111039);
+INSERT INTO City VALUES (3297,'Hualien','TWN','Hualien',108407);
+INSERT INTO City VALUES (3298,'Nantou','TWN','Nantou',104723);
+INSERT INTO City VALUES (3299,'Lungtan','TWN','Taipei',103088);
+INSERT INTO City VALUES (3300,'Touliu','TWN','Yünlin',98900);
+INSERT INTO City VALUES (3301,'Tsaotun','TWN','Nantou',96800);
+INSERT INTO City VALUES (3302,'Kangshan','TWN','Kaohsiung',92200);
+INSERT INTO City VALUES (3303,'Ilan','TWN','Ilan',92000);
+INSERT INTO City VALUES (3304,'Miaoli','TWN','Miaoli',90000);
+INSERT INTO City VALUES (3305,'Dar es Salaam','TZA','Dar es Salaam',1747000);
+INSERT INTO City VALUES (3306,'Dodoma','TZA','Dodoma',189000);
+INSERT INTO City VALUES (3307,'Mwanza','TZA','Mwanza',172300);
+INSERT INTO City VALUES (3308,'Zanzibar','TZA','Zanzibar West',157634);
+INSERT INTO City VALUES (3309,'Tanga','TZA','Tanga',137400);
+INSERT INTO City VALUES (3310,'Mbeya','TZA','Mbeya',130800);
+INSERT INTO City VALUES (3311,'Morogoro','TZA','Morogoro',117800);
+INSERT INTO City VALUES (3312,'Arusha','TZA','Arusha',102500);
+INSERT INTO City VALUES (3313,'Moshi','TZA','Kilimanjaro',96800);
+INSERT INTO City VALUES (3314,'Tabora','TZA','Tabora',92800);
+INSERT INTO City VALUES (3315,'København','DNK','København',495699);
+INSERT INTO City VALUES (3316,'Århus','DNK','Århus',284846);
+INSERT INTO City VALUES (3317,'Odense','DNK','Fyn',183912);
+INSERT INTO City VALUES (3318,'Aalborg','DNK','Nordjylland',161161);
+INSERT INTO City VALUES (3319,'Frederiksberg','DNK','Frederiksberg',90327);
+INSERT INTO City VALUES (3320,'Bangkok','THA','Bangkok',6320174);
+INSERT INTO City VALUES (3321,'Nonthaburi','THA','Nonthaburi',292100);
+INSERT INTO City VALUES (3322,'Nakhon Ratchasima','THA','Nakhon Ratchasima',181400);
+INSERT INTO City VALUES (3323,'Chiang Mai','THA','Chiang Mai',171100);
+INSERT INTO City VALUES (3324,'Udon Thani','THA','Udon Thani',158100);
+INSERT INTO City VALUES (3325,'Hat Yai','THA','Songkhla',148632);
+INSERT INTO City VALUES (3326,'Khon Kaen','THA','Khon Kaen',126500);
+INSERT INTO City VALUES (3327,'Pak Kret','THA','Nonthaburi',126055);
+INSERT INTO City VALUES (3328,'Nakhon Sawan','THA','Nakhon Sawan',123800);
+INSERT INTO City VALUES (3329,'Ubon Ratchathani','THA','Ubon Ratchathani',116300);
+INSERT INTO City VALUES (3330,'Songkhla','THA','Songkhla',94900);
+INSERT INTO City VALUES (3331,'Nakhon Pathom','THA','Nakhon Pathom',94100);
+INSERT INTO City VALUES (3332,'Lomé','TGO','Maritime',375000);
+INSERT INTO City VALUES (3333,'Fakaofo','TKL','Fakaofo',300);
+INSERT INTO City VALUES (3334,'Nuku´alofa','TON','Tongatapu',22400);
+INSERT INTO City VALUES (3335,'Chaguanas','TTO','Caroni',56601);
+INSERT INTO City VALUES (3336,'Port-of-Spain','TTO','Port-of-Spain',43396);
+INSERT INTO City VALUES (3337,'N´Djaména','TCD','Chari-Baguirmi',530965);
+INSERT INTO City VALUES (3338,'Moundou','TCD','Logone Occidental',99500);
+INSERT INTO City VALUES (3339,'Praha','CZE','Hlavní mesto Praha',1181126);
+INSERT INTO City VALUES (3340,'Brno','CZE','Jizní Morava',381862);
+INSERT INTO City VALUES (3341,'Ostrava','CZE','Severní Morava',320041);
+INSERT INTO City VALUES (3342,'Plzen','CZE','Zapadní Cechy',166759);
+INSERT INTO City VALUES (3343,'Olomouc','CZE','Severní Morava',102702);
+INSERT INTO City VALUES (3344,'Liberec','CZE','Severní Cechy',99155);
+INSERT INTO City VALUES (3345,'Ceské Budejovice','CZE','Jizní Cechy',98186);
+INSERT INTO City VALUES (3346,'Hradec Králové','CZE','Východní Cechy',98080);
+INSERT INTO City VALUES (3347,'Ústí nad Labem','CZE','Severní Cechy',95491);
+INSERT INTO City VALUES (3348,'Pardubice','CZE','Východní Cechy',91309);
+INSERT INTO City VALUES (3349,'Tunis','TUN','Tunis',690600);
+INSERT INTO City VALUES (3350,'Sfax','TUN','Sfax',257800);
+INSERT INTO City VALUES (3351,'Ariana','TUN','Ariana',197000);
+INSERT INTO City VALUES (3352,'Ettadhamen','TUN','Ariana',178600);
+INSERT INTO City VALUES (3353,'Sousse','TUN','Sousse',145900);
+INSERT INTO City VALUES (3354,'Kairouan','TUN','Kairouan',113100);
+INSERT INTO City VALUES (3355,'Biserta','TUN','Biserta',108900);
+INSERT INTO City VALUES (3356,'Gabès','TUN','Gabès',106600);
+INSERT INTO City VALUES (3357,'Istanbul','TUR','Istanbul',8787958);
+INSERT INTO City VALUES (3358,'Ankara','TUR','Ankara',3038159);
+INSERT INTO City VALUES (3359,'Izmir','TUR','Izmir',2130359);
+INSERT INTO City VALUES (3360,'Adana','TUR','Adana',1131198);
+INSERT INTO City VALUES (3361,'Bursa','TUR','Bursa',1095842);
+INSERT INTO City VALUES (3362,'Gaziantep','TUR','Gaziantep',789056);
+INSERT INTO City VALUES (3363,'Konya','TUR','Konya',628364);
+INSERT INTO City VALUES (3364,'Mersin (Içel)','TUR','Içel',587212);
+INSERT INTO City VALUES (3365,'Antalya','TUR','Antalya',564914);
+INSERT INTO City VALUES (3366,'Diyarbakir','TUR','Diyarbakir',479884);
+INSERT INTO City VALUES (3367,'Kayseri','TUR','Kayseri',475657);
+INSERT INTO City VALUES (3368,'Eskisehir','TUR','Eskisehir',470781);
+INSERT INTO City VALUES (3369,'Sanliurfa','TUR','Sanliurfa',405905);
+INSERT INTO City VALUES (3370,'Samsun','TUR','Samsun',339871);
+INSERT INTO City VALUES (3371,'Malatya','TUR','Malatya',330312);
+INSERT INTO City VALUES (3372,'Gebze','TUR','Kocaeli',264170);
+INSERT INTO City VALUES (3373,'Denizli','TUR','Denizli',253848);
+INSERT INTO City VALUES (3374,'Sivas','TUR','Sivas',246642);
+INSERT INTO City VALUES (3375,'Erzurum','TUR','Erzurum',246535);
+INSERT INTO City VALUES (3376,'Tarsus','TUR','Adana',246206);
+INSERT INTO City VALUES (3377,'Kahramanmaras','TUR','Kahramanmaras',245772);
+INSERT INTO City VALUES (3378,'Elâzig','TUR','Elâzig',228815);
+INSERT INTO City VALUES (3379,'Van','TUR','Van',219319);
+INSERT INTO City VALUES (3380,'Sultanbeyli','TUR','Istanbul',211068);
+INSERT INTO City VALUES (3381,'Izmit (Kocaeli)','TUR','Kocaeli',210068);
+INSERT INTO City VALUES (3382,'Manisa','TUR','Manisa',207148);
+INSERT INTO City VALUES (3383,'Batman','TUR','Batman',203793);
+INSERT INTO City VALUES (3384,'Balikesir','TUR','Balikesir',196382);
+INSERT INTO City VALUES (3385,'Sakarya (Adapazari)','TUR','Sakarya',190641);
+INSERT INTO City VALUES (3386,'Iskenderun','TUR','Hatay',153022);
+INSERT INTO City VALUES (3387,'Osmaniye','TUR','Osmaniye',146003);
+INSERT INTO City VALUES (3388,'Çorum','TUR','Çorum',145495);
+INSERT INTO City VALUES (3389,'Kütahya','TUR','Kütahya',144761);
+INSERT INTO City VALUES (3390,'Hatay (Antakya)','TUR','Hatay',143982);
+INSERT INTO City VALUES (3391,'Kirikkale','TUR','Kirikkale',142044);
+INSERT INTO City VALUES (3392,'Adiyaman','TUR','Adiyaman',141529);
+INSERT INTO City VALUES (3393,'Trabzon','TUR','Trabzon',138234);
+INSERT INTO City VALUES (3394,'Ordu','TUR','Ordu',133642);
+INSERT INTO City VALUES (3395,'Aydin','TUR','Aydin',128651);
+INSERT INTO City VALUES (3396,'Usak','TUR','Usak',128162);
+INSERT INTO City VALUES (3397,'Edirne','TUR','Edirne',123383);
+INSERT INTO City VALUES (3398,'Çorlu','TUR','Tekirdag',123300);
+INSERT INTO City VALUES (3399,'Isparta','TUR','Isparta',121911);
+INSERT INTO City VALUES (3400,'Karabük','TUR','Karabük',118285);
+INSERT INTO City VALUES (3401,'Kilis','TUR','Kilis',118245);
+INSERT INTO City VALUES (3402,'Alanya','TUR','Antalya',117300);
+INSERT INTO City VALUES (3403,'Kiziltepe','TUR','Mardin',112000);
+INSERT INTO City VALUES (3404,'Zonguldak','TUR','Zonguldak',111542);
+INSERT INTO City VALUES (3405,'Siirt','TUR','Siirt',107100);
+INSERT INTO City VALUES (3406,'Viransehir','TUR','Sanliurfa',106400);
+INSERT INTO City VALUES (3407,'Tekirdag','TUR','Tekirdag',106077);
+INSERT INTO City VALUES (3408,'Karaman','TUR','Karaman',104200);
+INSERT INTO City VALUES (3409,'Afyon','TUR','Afyon',103984);
+INSERT INTO City VALUES (3410,'Aksaray','TUR','Aksaray',102681);
+INSERT INTO City VALUES (3411,'Ceyhan','TUR','Adana',102412);
+INSERT INTO City VALUES (3412,'Erzincan','TUR','Erzincan',102304);
+INSERT INTO City VALUES (3413,'Bismil','TUR','Diyarbakir',101400);
+INSERT INTO City VALUES (3414,'Nazilli','TUR','Aydin',99900);
+INSERT INTO City VALUES (3415,'Tokat','TUR','Tokat',99500);
+INSERT INTO City VALUES (3416,'Kars','TUR','Kars',93000);
+INSERT INTO City VALUES (3417,'Inegöl','TUR','Bursa',90500);
+INSERT INTO City VALUES (3418,'Bandirma','TUR','Balikesir',90200);
+INSERT INTO City VALUES (3419,'Ashgabat','TKM','Ahal',540600);
+INSERT INTO City VALUES (3420,'Chärjew','TKM','Lebap',189200);
+INSERT INTO City VALUES (3421,'Dashhowuz','TKM','Dashhowuz',141800);
+INSERT INTO City VALUES (3422,'Mary','TKM','Mary',101000);
+INSERT INTO City VALUES (3423,'Cockburn Town','TCA','Grand Turk',4800);
+INSERT INTO City VALUES (3424,'Funafuti','TUV','Funafuti',4600);
+INSERT INTO City VALUES (3425,'Kampala','UGA','Central',890800);
+INSERT INTO City VALUES (3426,'Kyiv','UKR','Kiova',2624000);
+INSERT INTO City VALUES (3427,'Harkova [Harkiv]','UKR','Harkova',1500000);
+INSERT INTO City VALUES (3428,'Dnipropetrovsk','UKR','Dnipropetrovsk',1103000);
+INSERT INTO City VALUES (3429,'Donetsk','UKR','Donetsk',1050000);
+INSERT INTO City VALUES (3430,'Odesa','UKR','Odesa',1011000);
+INSERT INTO City VALUES (3431,'Zaporizzja','UKR','Zaporizzja',848000);
+INSERT INTO City VALUES (3432,'Lviv','UKR','Lviv',788000);
+INSERT INTO City VALUES (3433,'Kryvyi Rig','UKR','Dnipropetrovsk',703000);
+INSERT INTO City VALUES (3434,'Mykolajiv','UKR','Mykolajiv',508000);
+INSERT INTO City VALUES (3435,'Mariupol','UKR','Donetsk',490000);
+INSERT INTO City VALUES (3436,'Lugansk','UKR','Lugansk',469000);
+INSERT INTO City VALUES (3437,'Vinnytsja','UKR','Vinnytsja',391000);
+INSERT INTO City VALUES (3438,'Makijivka','UKR','Donetsk',384000);
+INSERT INTO City VALUES (3439,'Herson','UKR','Herson',353000);
+INSERT INTO City VALUES (3440,'Sevastopol','UKR','Krim',348000);
+INSERT INTO City VALUES (3441,'Simferopol','UKR','Krim',339000);
+INSERT INTO City VALUES (3442,'Pultava [Poltava]','UKR','Pultava',313000);
+INSERT INTO City VALUES (3443,'Tšernigiv','UKR','Tšernigiv',313000);
+INSERT INTO City VALUES (3444,'Tšerkasy','UKR','Tšerkasy',309000);
+INSERT INTO City VALUES (3445,'Gorlivka','UKR','Donetsk',299000);
+INSERT INTO City VALUES (3446,'Zytomyr','UKR','Zytomyr',297000);
+INSERT INTO City VALUES (3447,'Sumy','UKR','Sumy',294000);
+INSERT INTO City VALUES (3448,'Dniprodzerzynsk','UKR','Dnipropetrovsk',270000);
+INSERT INTO City VALUES (3449,'Kirovograd','UKR','Kirovograd',265000);
+INSERT INTO City VALUES (3450,'Hmelnytskyi','UKR','Hmelnytskyi',262000);
+INSERT INTO City VALUES (3451,'Tšernivtsi','UKR','Tšernivtsi',259000);
+INSERT INTO City VALUES (3452,'Rivne','UKR','Rivne',245000);
+INSERT INTO City VALUES (3453,'Krementšuk','UKR','Pultava',239000);
+INSERT INTO City VALUES (3454,'Ivano-Frankivsk','UKR','Ivano-Frankivsk',237000);
+INSERT INTO City VALUES (3455,'Ternopil','UKR','Ternopil',236000);
+INSERT INTO City VALUES (3456,'Lutsk','UKR','Volynia',217000);
+INSERT INTO City VALUES (3457,'Bila Tserkva','UKR','Kiova',215000);
+INSERT INTO City VALUES (3458,'Kramatorsk','UKR','Donetsk',186000);
+INSERT INTO City VALUES (3459,'Melitopol','UKR','Zaporizzja',169000);
+INSERT INTO City VALUES (3460,'Kertš','UKR','Krim',162000);
+INSERT INTO City VALUES (3461,'Nikopol','UKR','Dnipropetrovsk',149000);
+INSERT INTO City VALUES (3462,'Berdjansk','UKR','Zaporizzja',130000);
+INSERT INTO City VALUES (3463,'Pavlograd','UKR','Dnipropetrovsk',127000);
+INSERT INTO City VALUES (3464,'Sjeverodonetsk','UKR','Lugansk',127000);
+INSERT INTO City VALUES (3465,'Slovjansk','UKR','Donetsk',127000);
+INSERT INTO City VALUES (3466,'Uzgorod','UKR','Taka-Karpatia',127000);
+INSERT INTO City VALUES (3467,'Altševsk','UKR','Lugansk',119000);
+INSERT INTO City VALUES (3468,'Lysytšansk','UKR','Lugansk',116000);
+INSERT INTO City VALUES (3469,'Jevpatorija','UKR','Krim',112000);
+INSERT INTO City VALUES (3470,'Kamjanets-Podilskyi','UKR','Hmelnytskyi',109000);
+INSERT INTO City VALUES (3471,'Jenakijeve','UKR','Donetsk',105000);
+INSERT INTO City VALUES (3472,'Krasnyi Lutš','UKR','Lugansk',101000);
+INSERT INTO City VALUES (3473,'Stahanov','UKR','Lugansk',101000);
+INSERT INTO City VALUES (3474,'Oleksandrija','UKR','Kirovograd',99000);
+INSERT INTO City VALUES (3475,'Konotop','UKR','Sumy',96000);
+INSERT INTO City VALUES (3476,'Kostjantynivka','UKR','Donetsk',95000);
+INSERT INTO City VALUES (3477,'Berdytšiv','UKR','Zytomyr',90000);
+INSERT INTO City VALUES (3478,'Izmajil','UKR','Odesa',90000);
+INSERT INTO City VALUES (3479,'Šostka','UKR','Sumy',90000);
+INSERT INTO City VALUES (3480,'Uman','UKR','Tšerkasy',90000);
+INSERT INTO City VALUES (3481,'Brovary','UKR','Kiova',89000);
+INSERT INTO City VALUES (3482,'Mukatševe','UKR','Taka-Karpatia',89000);
+INSERT INTO City VALUES (3483,'Budapest','HUN','Budapest',1811552);
+INSERT INTO City VALUES (3484,'Debrecen','HUN','Hajdú-Bihar',203648);
+INSERT INTO City VALUES (3485,'Miskolc','HUN','Borsod-Abaúj-Zemplén',172357);
+INSERT INTO City VALUES (3486,'Szeged','HUN','Csongrád',158158);
+INSERT INTO City VALUES (3487,'Pécs','HUN','Baranya',157332);
+INSERT INTO City VALUES (3488,'Györ','HUN','Györ-Moson-Sopron',127119);
+INSERT INTO City VALUES (3489,'Nyiregyháza','HUN','Szabolcs-Szatmár-Ber',112419);
+INSERT INTO City VALUES (3490,'Kecskemét','HUN','Bács-Kiskun',105606);
+INSERT INTO City VALUES (3491,'Székesfehérvár','HUN','Fejér',105119);
+INSERT INTO City VALUES (3492,'Montevideo','URY','Montevideo',1236000);
+INSERT INTO City VALUES (3493,'Nouméa','NCL','–',76293);
+INSERT INTO City VALUES (3494,'Auckland','NZL','Auckland',381800);
+INSERT INTO City VALUES (3495,'Christchurch','NZL','Canterbury',324200);
+INSERT INTO City VALUES (3496,'Manukau','NZL','Auckland',281800);
+INSERT INTO City VALUES (3497,'North Shore','NZL','Auckland',187700);
+INSERT INTO City VALUES (3498,'Waitakere','NZL','Auckland',170600);
+INSERT INTO City VALUES (3499,'Wellington','NZL','Wellington',166700);
+INSERT INTO City VALUES (3500,'Dunedin','NZL','Dunedin',119600);
+INSERT INTO City VALUES (3501,'Hamilton','NZL','Hamilton',117100);
+INSERT INTO City VALUES (3502,'Lower Hutt','NZL','Wellington',98100);
+INSERT INTO City VALUES (3503,'Toskent','UZB','Toskent Shahri',2117500);
+INSERT INTO City VALUES (3504,'Namangan','UZB','Namangan',370500);
+INSERT INTO City VALUES (3505,'Samarkand','UZB','Samarkand',361800);
+INSERT INTO City VALUES (3506,'Andijon','UZB','Andijon',318600);
+INSERT INTO City VALUES (3507,'Buhoro','UZB','Buhoro',237100);
+INSERT INTO City VALUES (3508,'Karsi','UZB','Qashqadaryo',194100);
+INSERT INTO City VALUES (3509,'Nukus','UZB','Karakalpakistan',194100);
+INSERT INTO City VALUES (3510,'Kükon','UZB','Fargona',190100);
+INSERT INTO City VALUES (3511,'Fargona','UZB','Fargona',180500);
+INSERT INTO City VALUES (3512,'Circik','UZB','Toskent',146400);
+INSERT INTO City VALUES (3513,'Margilon','UZB','Fargona',140800);
+INSERT INTO City VALUES (3514,'Ürgenc','UZB','Khorazm',138900);
+INSERT INTO City VALUES (3515,'Angren','UZB','Toskent',128000);
+INSERT INTO City VALUES (3516,'Cizah','UZB','Cizah',124800);
+INSERT INTO City VALUES (3517,'Navoi','UZB','Navoi',116300);
+INSERT INTO City VALUES (3518,'Olmalik','UZB','Toskent',114900);
+INSERT INTO City VALUES (3519,'Termiz','UZB','Surkhondaryo',109500);
+INSERT INTO City VALUES (3520,'Minsk','BLR','Horad Minsk',1674000);
+INSERT INTO City VALUES (3521,'Gomel','BLR','Gomel',475000);
+INSERT INTO City VALUES (3522,'Mogiljov','BLR','Mogiljov',356000);
+INSERT INTO City VALUES (3523,'Vitebsk','BLR','Vitebsk',340000);
+INSERT INTO City VALUES (3524,'Grodno','BLR','Grodno',302000);
+INSERT INTO City VALUES (3525,'Brest','BLR','Brest',286000);
+INSERT INTO City VALUES (3526,'Bobruisk','BLR','Mogiljov',221000);
+INSERT INTO City VALUES (3527,'Baranovitši','BLR','Brest',167000);
+INSERT INTO City VALUES (3528,'Borisov','BLR','Minsk',151000);
+INSERT INTO City VALUES (3529,'Pinsk','BLR','Brest',130000);
+INSERT INTO City VALUES (3530,'Orša','BLR','Vitebsk',124000);
+INSERT INTO City VALUES (3531,'Mozyr','BLR','Gomel',110000);
+INSERT INTO City VALUES (3532,'Novopolotsk','BLR','Vitebsk',106000);
+INSERT INTO City VALUES (3533,'Lida','BLR','Grodno',101000);
+INSERT INTO City VALUES (3534,'Soligorsk','BLR','Minsk',101000);
+INSERT INTO City VALUES (3535,'Molodetšno','BLR','Minsk',97000);
+INSERT INTO City VALUES (3536,'Mata-Utu','WLF','Wallis',1137);
+INSERT INTO City VALUES (3537,'Port-Vila','VUT','Shefa',33700);
+INSERT INTO City VALUES (3538,'Città del Vaticano','VAT','–',455);
+INSERT INTO City VALUES (3539,'Caracas','VEN','Distrito Federal',1975294);
+INSERT INTO City VALUES (3540,'Maracaíbo','VEN','Zulia',1304776);
+INSERT INTO City VALUES (3541,'Barquisimeto','VEN','Lara',877239);
+INSERT INTO City VALUES (3542,'Valencia','VEN','Carabobo',794246);
+INSERT INTO City VALUES (3543,'Ciudad Guayana','VEN','Bolívar',663713);
+INSERT INTO City VALUES (3544,'Petare','VEN','Miranda',488868);
+INSERT INTO City VALUES (3545,'Maracay','VEN','Aragua',444443);
+INSERT INTO City VALUES (3546,'Barcelona','VEN','Anzoátegui',322267);
+INSERT INTO City VALUES (3547,'Maturín','VEN','Monagas',319726);
+INSERT INTO City VALUES (3548,'San Cristóbal','VEN','Táchira',319373);
+INSERT INTO City VALUES (3549,'Ciudad Bolívar','VEN','Bolívar',301107);
+INSERT INTO City VALUES (3550,'Cumaná','VEN','Sucre',293105);
+INSERT INTO City VALUES (3551,'Mérida','VEN','Mérida',224887);
+INSERT INTO City VALUES (3552,'Cabimas','VEN','Zulia',221329);
+INSERT INTO City VALUES (3553,'Barinas','VEN','Barinas',217831);
+INSERT INTO City VALUES (3554,'Turmero','VEN','Aragua',217499);
+INSERT INTO City VALUES (3555,'Baruta','VEN','Miranda',207290);
+INSERT INTO City VALUES (3556,'Puerto Cabello','VEN','Carabobo',187722);
+INSERT INTO City VALUES (3557,'Santa Ana de Coro','VEN','Falcón',185766);
+INSERT INTO City VALUES (3558,'Los Teques','VEN','Miranda',178784);
+INSERT INTO City VALUES (3559,'Punto Fijo','VEN','Falcón',167215);
+INSERT INTO City VALUES (3560,'Guarenas','VEN','Miranda',165889);
+INSERT INTO City VALUES (3561,'Acarigua','VEN','Portuguesa',158954);
+INSERT INTO City VALUES (3562,'Puerto La Cruz','VEN','Anzoátegui',155700);
+INSERT INTO City VALUES (3563,'Ciudad Losada','VEN','',134501);
+INSERT INTO City VALUES (3564,'Guacara','VEN','Carabobo',131334);
+INSERT INTO City VALUES (3565,'Valera','VEN','Trujillo',130281);
+INSERT INTO City VALUES (3566,'Guanare','VEN','Portuguesa',125621);
+INSERT INTO City VALUES (3567,'Carúpano','VEN','Sucre',119639);
+INSERT INTO City VALUES (3568,'Catia La Mar','VEN','Distrito Federal',117012);
+INSERT INTO City VALUES (3569,'El Tigre','VEN','Anzoátegui',116256);
+INSERT INTO City VALUES (3570,'Guatire','VEN','Miranda',109121);
+INSERT INTO City VALUES (3571,'Calabozo','VEN','Guárico',107146);
+INSERT INTO City VALUES (3572,'Pozuelos','VEN','Anzoátegui',105690);
+INSERT INTO City VALUES (3573,'Ciudad Ojeda','VEN','Zulia',99354);
+INSERT INTO City VALUES (3574,'Ocumare del Tuy','VEN','Miranda',97168);
+INSERT INTO City VALUES (3575,'Valle de la Pascua','VEN','Guárico',95927);
+INSERT INTO City VALUES (3576,'Araure','VEN','Portuguesa',94269);
+INSERT INTO City VALUES (3577,'San Fernando de Apure','VEN','Apure',93809);
+INSERT INTO City VALUES (3578,'San Felipe','VEN','Yaracuy',90940);
+INSERT INTO City VALUES (3579,'El Limón','VEN','Aragua',90000);
+INSERT INTO City VALUES (3580,'Moscow','RUS','Moscow (City)',8389200);
+INSERT INTO City VALUES (3581,'St Petersburg','RUS','Pietari',4694000);
+INSERT INTO City VALUES (3582,'Novosibirsk','RUS','Novosibirsk',1398800);
+INSERT INTO City VALUES (3583,'Nizni Novgorod','RUS','Nizni Novgorod',1357000);
+INSERT INTO City VALUES (3584,'Jekaterinburg','RUS','Sverdlovsk',1266300);
+INSERT INTO City VALUES (3585,'Samara','RUS','Samara',1156100);
+INSERT INTO City VALUES (3586,'Omsk','RUS','Omsk',1148900);
+INSERT INTO City VALUES (3587,'Kazan','RUS','Tatarstan',1101000);
+INSERT INTO City VALUES (3588,'Ufa','RUS','Baškortostan',1091200);
+INSERT INTO City VALUES (3589,'Tšeljabinsk','RUS','Tšeljabinsk',1083200);
+INSERT INTO City VALUES (3590,'Rostov-na-Donu','RUS','Rostov-na-Donu',1012700);
+INSERT INTO City VALUES (3591,'Perm','RUS','Perm',1009700);
+INSERT INTO City VALUES (3592,'Volgograd','RUS','Volgograd',993400);
+INSERT INTO City VALUES (3593,'Voronez','RUS','Voronez',907700);
+INSERT INTO City VALUES (3594,'Krasnojarsk','RUS','Krasnojarsk',875500);
+INSERT INTO City VALUES (3595,'Saratov','RUS','Saratov',874000);
+INSERT INTO City VALUES (3596,'Toljatti','RUS','Samara',722900);
+INSERT INTO City VALUES (3597,'Uljanovsk','RUS','Uljanovsk',667400);
+INSERT INTO City VALUES (3598,'Izevsk','RUS','Udmurtia',652800);
+INSERT INTO City VALUES (3599,'Krasnodar','RUS','Krasnodar',639000);
+INSERT INTO City VALUES (3600,'Jaroslavl','RUS','Jaroslavl',616700);
+INSERT INTO City VALUES (3601,'Habarovsk','RUS','Habarovsk',609400);
+INSERT INTO City VALUES (3602,'Vladivostok','RUS','Primorje',606200);
+INSERT INTO City VALUES (3603,'Irkutsk','RUS','Irkutsk',593700);
+INSERT INTO City VALUES (3604,'Barnaul','RUS','Altai',580100);
+INSERT INTO City VALUES (3605,'Novokuznetsk','RUS','Kemerovo',561600);
+INSERT INTO City VALUES (3606,'Penza','RUS','Penza',532200);
+INSERT INTO City VALUES (3607,'Rjazan','RUS','Rjazan',529900);
+INSERT INTO City VALUES (3608,'Orenburg','RUS','Orenburg',523600);
+INSERT INTO City VALUES (3609,'Lipetsk','RUS','Lipetsk',521000);
+INSERT INTO City VALUES (3610,'Nabereznyje Tšelny','RUS','Tatarstan',514700);
+INSERT INTO City VALUES (3611,'Tula','RUS','Tula',506100);
+INSERT INTO City VALUES (3612,'Tjumen','RUS','Tjumen',503400);
+INSERT INTO City VALUES (3613,'Kemerovo','RUS','Kemerovo',492700);
+INSERT INTO City VALUES (3614,'Astrahan','RUS','Astrahan',486100);
+INSERT INTO City VALUES (3615,'Tomsk','RUS','Tomsk',482100);
+INSERT INTO City VALUES (3616,'Kirov','RUS','Kirov',466200);
+INSERT INTO City VALUES (3617,'Ivanovo','RUS','Ivanovo',459200);
+INSERT INTO City VALUES (3618,'Tšeboksary','RUS','Tšuvassia',459200);
+INSERT INTO City VALUES (3619,'Brjansk','RUS','Brjansk',457400);
+INSERT INTO City VALUES (3620,'Tver','RUS','Tver',454900);
+INSERT INTO City VALUES (3621,'Kursk','RUS','Kursk',443500);
+INSERT INTO City VALUES (3622,'Magnitogorsk','RUS','Tšeljabinsk',427900);
+INSERT INTO City VALUES (3623,'Kaliningrad','RUS','Kaliningrad',424400);
+INSERT INTO City VALUES (3624,'Nizni Tagil','RUS','Sverdlovsk',390900);
+INSERT INTO City VALUES (3625,'Murmansk','RUS','Murmansk',376300);
+INSERT INTO City VALUES (3626,'Ulan-Ude','RUS','Burjatia',370400);
+INSERT INTO City VALUES (3627,'Kurgan','RUS','Kurgan',364700);
+INSERT INTO City VALUES (3628,'Arkangeli','RUS','Arkangeli',361800);
+INSERT INTO City VALUES (3629,'Sotši','RUS','Krasnodar',358600);
+INSERT INTO City VALUES (3630,'Smolensk','RUS','Smolensk',353400);
+INSERT INTO City VALUES (3631,'Orjol','RUS','Orjol',344500);
+INSERT INTO City VALUES (3632,'Stavropol','RUS','Stavropol',343300);
+INSERT INTO City VALUES (3633,'Belgorod','RUS','Belgorod',342000);
+INSERT INTO City VALUES (3634,'Kaluga','RUS','Kaluga',339300);
+INSERT INTO City VALUES (3635,'Vladimir','RUS','Vladimir',337100);
+INSERT INTO City VALUES (3636,'Mahatškala','RUS','Dagestan',332800);
+INSERT INTO City VALUES (3637,'Tšerepovets','RUS','Vologda',324400);
+INSERT INTO City VALUES (3638,'Saransk','RUS','Mordva',314800);
+INSERT INTO City VALUES (3639,'Tambov','RUS','Tambov',312000);
+INSERT INTO City VALUES (3640,'Vladikavkaz','RUS','North Ossetia-Alania',310100);
+INSERT INTO City VALUES (3641,'Tšita','RUS','Tšita',309900);
+INSERT INTO City VALUES (3642,'Vologda','RUS','Vologda',302500);
+INSERT INTO City VALUES (3643,'Veliki Novgorod','RUS','Novgorod',299500);
+INSERT INTO City VALUES (3644,'Komsomolsk-na-Amure','RUS','Habarovsk',291600);
+INSERT INTO City VALUES (3645,'Kostroma','RUS','Kostroma',288100);
+INSERT INTO City VALUES (3646,'Volzski','RUS','Volgograd',286900);
+INSERT INTO City VALUES (3647,'Taganrog','RUS','Rostov-na-Donu',284400);
+INSERT INTO City VALUES (3648,'Petroskoi','RUS','Karjala',282100);
+INSERT INTO City VALUES (3649,'Bratsk','RUS','Irkutsk',277600);
+INSERT INTO City VALUES (3650,'Dzerzinsk','RUS','Nizni Novgorod',277100);
+INSERT INTO City VALUES (3651,'Surgut','RUS','Hanti-Mansia',274900);
+INSERT INTO City VALUES (3652,'Orsk','RUS','Orenburg',273900);
+INSERT INTO City VALUES (3653,'Sterlitamak','RUS','Baškortostan',265200);
+INSERT INTO City VALUES (3654,'Angarsk','RUS','Irkutsk',264700);
+INSERT INTO City VALUES (3655,'Joškar-Ola','RUS','Marinmaa',249200);
+INSERT INTO City VALUES (3656,'Rybinsk','RUS','Jaroslavl',239600);
+INSERT INTO City VALUES (3657,'Prokopjevsk','RUS','Kemerovo',237300);
+INSERT INTO City VALUES (3658,'Niznevartovsk','RUS','Hanti-Mansia',233900);
+INSERT INTO City VALUES (3659,'Naltšik','RUS','Kabardi-Balkaria',233400);
+INSERT INTO City VALUES (3660,'Syktyvkar','RUS','Komi',229700);
+INSERT INTO City VALUES (3661,'Severodvinsk','RUS','Arkangeli',229300);
+INSERT INTO City VALUES (3662,'Bijsk','RUS','Altai',225000);
+INSERT INTO City VALUES (3663,'Niznekamsk','RUS','Tatarstan',223400);
+INSERT INTO City VALUES (3664,'Blagoveštšensk','RUS','Amur',222000);
+INSERT INTO City VALUES (3665,'Šahty','RUS','Rostov-na-Donu',221800);
+INSERT INTO City VALUES (3666,'Staryi Oskol','RUS','Belgorod',213800);
+INSERT INTO City VALUES (3667,'Zelenograd','RUS','Moscow (City)',207100);
+INSERT INTO City VALUES (3668,'Balakovo','RUS','Saratov',206000);
+INSERT INTO City VALUES (3669,'Novorossijsk','RUS','Krasnodar',203300);
+INSERT INTO City VALUES (3670,'Pihkova','RUS','Pihkova',201500);
+INSERT INTO City VALUES (3671,'Zlatoust','RUS','Tšeljabinsk',196900);
+INSERT INTO City VALUES (3672,'Jakutsk','RUS','Saha (Jakutia)',195400);
+INSERT INTO City VALUES (3673,'Podolsk','RUS','Moskova',194300);
+INSERT INTO City VALUES (3674,'Petropavlovsk-Kamtšatski','RUS','Kamtšatka',194100);
+INSERT INTO City VALUES (3675,'Kamensk-Uralski','RUS','Sverdlovsk',190600);
+INSERT INTO City VALUES (3676,'Engels','RUS','Saratov',189000);
+INSERT INTO City VALUES (3677,'Syzran','RUS','Samara',186900);
+INSERT INTO City VALUES (3678,'Grozny','RUS','Tšetšenia',186000);
+INSERT INTO City VALUES (3679,'Novotšerkassk','RUS','Rostov-na-Donu',184400);
+INSERT INTO City VALUES (3680,'Berezniki','RUS','Perm',181900);
+INSERT INTO City VALUES (3681,'Juzno-Sahalinsk','RUS','Sahalin',179200);
+INSERT INTO City VALUES (3682,'Volgodonsk','RUS','Rostov-na-Donu',178200);
+INSERT INTO City VALUES (3683,'Abakan','RUS','Hakassia',169200);
+INSERT INTO City VALUES (3684,'Maikop','RUS','Adygea',167300);
+INSERT INTO City VALUES (3685,'Miass','RUS','Tšeljabinsk',166200);
+INSERT INTO City VALUES (3686,'Armavir','RUS','Krasnodar',164900);
+INSERT INTO City VALUES (3687,'Ljubertsy','RUS','Moskova',163900);
+INSERT INTO City VALUES (3688,'Rubtsovsk','RUS','Altai',162600);
+INSERT INTO City VALUES (3689,'Kovrov','RUS','Vladimir',159900);
+INSERT INTO City VALUES (3690,'Nahodka','RUS','Primorje',157700);
+INSERT INTO City VALUES (3691,'Ussurijsk','RUS','Primorje',157300);
+INSERT INTO City VALUES (3692,'Salavat','RUS','Baškortostan',156800);
+INSERT INTO City VALUES (3693,'Mytištši','RUS','Moskova',155700);
+INSERT INTO City VALUES (3694,'Kolomna','RUS','Moskova',150700);
+INSERT INTO City VALUES (3695,'Elektrostal','RUS','Moskova',147000);
+INSERT INTO City VALUES (3696,'Murom','RUS','Vladimir',142400);
+INSERT INTO City VALUES (3697,'Kolpino','RUS','Pietari',141200);
+INSERT INTO City VALUES (3698,'Norilsk','RUS','Krasnojarsk',140800);
+INSERT INTO City VALUES (3699,'Almetjevsk','RUS','Tatarstan',140700);
+INSERT INTO City VALUES (3700,'Novomoskovsk','RUS','Tula',138100);
+INSERT INTO City VALUES (3701,'Dimitrovgrad','RUS','Uljanovsk',137000);
+INSERT INTO City VALUES (3702,'Pervouralsk','RUS','Sverdlovsk',136100);
+INSERT INTO City VALUES (3703,'Himki','RUS','Moskova',133700);
+INSERT INTO City VALUES (3704,'Balašiha','RUS','Moskova',132900);
+INSERT INTO City VALUES (3705,'Nevinnomyssk','RUS','Stavropol',132600);
+INSERT INTO City VALUES (3706,'Pjatigorsk','RUS','Stavropol',132500);
+INSERT INTO City VALUES (3707,'Korolev','RUS','Moskova',132400);
+INSERT INTO City VALUES (3708,'Serpuhov','RUS','Moskova',132000);
+INSERT INTO City VALUES (3709,'Odintsovo','RUS','Moskova',127400);
+INSERT INTO City VALUES (3710,'Orehovo-Zujevo','RUS','Moskova',124900);
+INSERT INTO City VALUES (3711,'Kamyšin','RUS','Volgograd',124600);
+INSERT INTO City VALUES (3712,'Novotšeboksarsk','RUS','Tšuvassia',123400);
+INSERT INTO City VALUES (3713,'Tšerkessk','RUS','Karatšai-Tšerkessia',121700);
+INSERT INTO City VALUES (3714,'Atšinsk','RUS','Krasnojarsk',121600);
+INSERT INTO City VALUES (3715,'Magadan','RUS','Magadan',121000);
+INSERT INTO City VALUES (3716,'Mitšurinsk','RUS','Tambov',120700);
+INSERT INTO City VALUES (3717,'Kislovodsk','RUS','Stavropol',120400);
+INSERT INTO City VALUES (3718,'Jelets','RUS','Lipetsk',119400);
+INSERT INTO City VALUES (3719,'Seversk','RUS','Tomsk',118600);
+INSERT INTO City VALUES (3720,'Noginsk','RUS','Moskova',117200);
+INSERT INTO City VALUES (3721,'Velikije Luki','RUS','Pihkova',116300);
+INSERT INTO City VALUES (3722,'Novokuibyševsk','RUS','Samara',116200);
+INSERT INTO City VALUES (3723,'Neftekamsk','RUS','Baškortostan',115700);
+INSERT INTO City VALUES (3724,'Leninsk-Kuznetski','RUS','Kemerovo',113800);
+INSERT INTO City VALUES (3725,'Oktjabrski','RUS','Baškortostan',111500);
+INSERT INTO City VALUES (3726,'Sergijev Posad','RUS','Moskova',111100);
+INSERT INTO City VALUES (3727,'Arzamas','RUS','Nizni Novgorod',110700);
+INSERT INTO City VALUES (3728,'Kiseljovsk','RUS','Kemerovo',110000);
+INSERT INTO City VALUES (3729,'Novotroitsk','RUS','Orenburg',109600);
+INSERT INTO City VALUES (3730,'Obninsk','RUS','Kaluga',108300);
+INSERT INTO City VALUES (3731,'Kansk','RUS','Krasnojarsk',107400);
+INSERT INTO City VALUES (3732,'Glazov','RUS','Udmurtia',106300);
+INSERT INTO City VALUES (3733,'Solikamsk','RUS','Perm',106000);
+INSERT INTO City VALUES (3734,'Sarapul','RUS','Udmurtia',105700);
+INSERT INTO City VALUES (3735,'Ust-Ilimsk','RUS','Irkutsk',105200);
+INSERT INTO City VALUES (3736,'Štšolkovo','RUS','Moskova',104900);
+INSERT INTO City VALUES (3737,'Mezduretšensk','RUS','Kemerovo',104400);
+INSERT INTO City VALUES (3738,'Usolje-Sibirskoje','RUS','Irkutsk',103500);
+INSERT INTO City VALUES (3739,'Elista','RUS','Kalmykia',103300);
+INSERT INTO City VALUES (3740,'Novošahtinsk','RUS','Rostov-na-Donu',101900);
+INSERT INTO City VALUES (3741,'Votkinsk','RUS','Udmurtia',101700);
+INSERT INTO City VALUES (3742,'Kyzyl','RUS','Tyva',101100);
+INSERT INTO City VALUES (3743,'Serov','RUS','Sverdlovsk',100400);
+INSERT INTO City VALUES (3744,'Zelenodolsk','RUS','Tatarstan',100200);
+INSERT INTO City VALUES (3745,'Zeleznodoroznyi','RUS','Moskova',100100);
+INSERT INTO City VALUES (3746,'Kinešma','RUS','Ivanovo',100000);
+INSERT INTO City VALUES (3747,'Kuznetsk','RUS','Penza',98200);
+INSERT INTO City VALUES (3748,'Uhta','RUS','Komi',98000);
+INSERT INTO City VALUES (3749,'Jessentuki','RUS','Stavropol',97900);
+INSERT INTO City VALUES (3750,'Tobolsk','RUS','Tjumen',97600);
+INSERT INTO City VALUES (3751,'Neftejugansk','RUS','Hanti-Mansia',97400);
+INSERT INTO City VALUES (3752,'Bataisk','RUS','Rostov-na-Donu',97300);
+INSERT INTO City VALUES (3753,'Nojabrsk','RUS','Yamalin Nenetsia',97300);
+INSERT INTO City VALUES (3754,'Balašov','RUS','Saratov',97100);
+INSERT INTO City VALUES (3755,'Zeleznogorsk','RUS','Kursk',96900);
+INSERT INTO City VALUES (3756,'Zukovski','RUS','Moskova',96500);
+INSERT INTO City VALUES (3757,'Anzero-Sudzensk','RUS','Kemerovo',96100);
+INSERT INTO City VALUES (3758,'Bugulma','RUS','Tatarstan',94100);
+INSERT INTO City VALUES (3759,'Zeleznogorsk','RUS','Krasnojarsk',94000);
+INSERT INTO City VALUES (3760,'Novouralsk','RUS','Sverdlovsk',93300);
+INSERT INTO City VALUES (3761,'Puškin','RUS','Pietari',92900);
+INSERT INTO City VALUES (3762,'Vorkuta','RUS','Komi',92600);
+INSERT INTO City VALUES (3763,'Derbent','RUS','Dagestan',92300);
+INSERT INTO City VALUES (3764,'Kirovo-Tšepetsk','RUS','Kirov',91600);
+INSERT INTO City VALUES (3765,'Krasnogorsk','RUS','Moskova',91000);
+INSERT INTO City VALUES (3766,'Klin','RUS','Moskova',90000);
+INSERT INTO City VALUES (3767,'Tšaikovski','RUS','Perm',90000);
+INSERT INTO City VALUES (3768,'Novyi Urengoi','RUS','Yamalin Nenetsia',89800);
+INSERT INTO City VALUES (3769,'Ho Chi Minh City','VNM','Ho Chi Minh City',3980000);
+INSERT INTO City VALUES (3770,'Hanoi','VNM','Hanoi',1410000);
+INSERT INTO City VALUES (3771,'Haiphong','VNM','Haiphong',783133);
+INSERT INTO City VALUES (3772,'Da Nang','VNM','Quang Nam-Da Nang',382674);
+INSERT INTO City VALUES (3773,'Biên Hoa','VNM','Dong Nai',282095);
+INSERT INTO City VALUES (3774,'Nha Trang','VNM','Khanh Hoa',221331);
+INSERT INTO City VALUES (3775,'Hue','VNM','Thua Thien-Hue',219149);
+INSERT INTO City VALUES (3776,'Can Tho','VNM','Can Tho',215587);
+INSERT INTO City VALUES (3777,'Cam Pha','VNM','Quang Binh',209086);
+INSERT INTO City VALUES (3778,'Nam Dinh','VNM','Nam Ha',171699);
+INSERT INTO City VALUES (3779,'Quy Nhon','VNM','Binh Dinh',163385);
+INSERT INTO City VALUES (3780,'Vung Tau','VNM','Ba Ria-Vung Tau',145145);
+INSERT INTO City VALUES (3781,'Rach Gia','VNM','Kien Giang',141132);
+INSERT INTO City VALUES (3782,'Long Xuyen','VNM','An Giang',132681);
+INSERT INTO City VALUES (3783,'Thai Nguyen','VNM','Bac Thai',127643);
+INSERT INTO City VALUES (3784,'Hong Gai','VNM','Quang Ninh',127484);
+INSERT INTO City VALUES (3785,'Phan Thiêt','VNM','Binh Thuan',114236);
+INSERT INTO City VALUES (3786,'Cam Ranh','VNM','Khanh Hoa',114041);
+INSERT INTO City VALUES (3787,'Vinh','VNM','Nghe An',112455);
+INSERT INTO City VALUES (3788,'My Tho','VNM','Tien Giang',108404);
+INSERT INTO City VALUES (3789,'Da Lat','VNM','Lam Dong',106409);
+INSERT INTO City VALUES (3790,'Buon Ma Thuot','VNM','Dac Lac',97044);
+INSERT INTO City VALUES (3791,'Tallinn','EST','Harjumaa',403981);
+INSERT INTO City VALUES (3792,'Tartu','EST','Tartumaa',101246);
+INSERT INTO City VALUES (3793,'New York','USA','New York',8008278);
+INSERT INTO City VALUES (3794,'Los Angeles','USA','California',3694820);
+INSERT INTO City VALUES (3795,'Chicago','USA','Illinois',2896016);
+INSERT INTO City VALUES (3796,'Houston','USA','Texas',1953631);
+INSERT INTO City VALUES (3797,'Philadelphia','USA','Pennsylvania',1517550);
+INSERT INTO City VALUES (3798,'Phoenix','USA','Arizona',1321045);
+INSERT INTO City VALUES (3799,'San Diego','USA','California',1223400);
+INSERT INTO City VALUES (3800,'Dallas','USA','Texas',1188580);
+INSERT INTO City VALUES (3801,'San Antonio','USA','Texas',1144646);
+INSERT INTO City VALUES (3802,'Detroit','USA','Michigan',951270);
+INSERT INTO City VALUES (3803,'San Jose','USA','California',894943);
+INSERT INTO City VALUES (3804,'Indianapolis','USA','Indiana',791926);
+INSERT INTO City VALUES (3805,'San Francisco','USA','California',776733);
+INSERT INTO City VALUES (3806,'Jacksonville','USA','Florida',735167);
+INSERT INTO City VALUES (3807,'Columbus','USA','Ohio',711470);
+INSERT INTO City VALUES (3808,'Austin','USA','Texas',656562);
+INSERT INTO City VALUES (3809,'Baltimore','USA','Maryland',651154);
+INSERT INTO City VALUES (3810,'Memphis','USA','Tennessee',650100);
+INSERT INTO City VALUES (3811,'Milwaukee','USA','Wisconsin',596974);
+INSERT INTO City VALUES (3812,'Boston','USA','Massachusetts',589141);
+INSERT INTO City VALUES (3813,'Washington','USA','District of Columbia',572059);
+INSERT INTO City VALUES (3814,'Nashville-Davidson','USA','Tennessee',569891);
+INSERT INTO City VALUES (3815,'El Paso','USA','Texas',563662);
+INSERT INTO City VALUES (3816,'Seattle','USA','Washington',563374);
+INSERT INTO City VALUES (3817,'Denver','USA','Colorado',554636);
+INSERT INTO City VALUES (3818,'Charlotte','USA','North Carolina',540828);
+INSERT INTO City VALUES (3819,'Fort Worth','USA','Texas',534694);
+INSERT INTO City VALUES (3820,'Portland','USA','Oregon',529121);
+INSERT INTO City VALUES (3821,'Oklahoma City','USA','Oklahoma',506132);
+INSERT INTO City VALUES (3822,'Tucson','USA','Arizona',486699);
+INSERT INTO City VALUES (3823,'New Orleans','USA','Louisiana',484674);
+INSERT INTO City VALUES (3824,'Las Vegas','USA','Nevada',478434);
+INSERT INTO City VALUES (3825,'Cleveland','USA','Ohio',478403);
+INSERT INTO City VALUES (3826,'Long Beach','USA','California',461522);
+INSERT INTO City VALUES (3827,'Albuquerque','USA','New Mexico',448607);
+INSERT INTO City VALUES (3828,'Kansas City','USA','Missouri',441545);
+INSERT INTO City VALUES (3829,'Fresno','USA','California',427652);
+INSERT INTO City VALUES (3830,'Virginia Beach','USA','Virginia',425257);
+INSERT INTO City VALUES (3831,'Atlanta','USA','Georgia',416474);
+INSERT INTO City VALUES (3832,'Sacramento','USA','California',407018);
+INSERT INTO City VALUES (3833,'Oakland','USA','California',399484);
+INSERT INTO City VALUES (3834,'Mesa','USA','Arizona',396375);
+INSERT INTO City VALUES (3835,'Tulsa','USA','Oklahoma',393049);
+INSERT INTO City VALUES (3836,'Omaha','USA','Nebraska',390007);
+INSERT INTO City VALUES (3837,'Minneapolis','USA','Minnesota',382618);
+INSERT INTO City VALUES (3838,'Honolulu','USA','Hawaii',371657);
+INSERT INTO City VALUES (3839,'Miami','USA','Florida',362470);
+INSERT INTO City VALUES (3840,'Colorado Springs','USA','Colorado',360890);
+INSERT INTO City VALUES (3841,'Saint Louis','USA','Missouri',348189);
+INSERT INTO City VALUES (3842,'Wichita','USA','Kansas',344284);
+INSERT INTO City VALUES (3843,'Santa Ana','USA','California',337977);
+INSERT INTO City VALUES (3844,'Pittsburgh','USA','Pennsylvania',334563);
+INSERT INTO City VALUES (3845,'Arlington','USA','Texas',332969);
+INSERT INTO City VALUES (3846,'Cincinnati','USA','Ohio',331285);
+INSERT INTO City VALUES (3847,'Anaheim','USA','California',328014);
+INSERT INTO City VALUES (3848,'Toledo','USA','Ohio',313619);
+INSERT INTO City VALUES (3849,'Tampa','USA','Florida',303447);
+INSERT INTO City VALUES (3850,'Buffalo','USA','New York',292648);
+INSERT INTO City VALUES (3851,'Saint Paul','USA','Minnesota',287151);
+INSERT INTO City VALUES (3852,'Corpus Christi','USA','Texas',277454);
+INSERT INTO City VALUES (3853,'Aurora','USA','Colorado',276393);
+INSERT INTO City VALUES (3854,'Raleigh','USA','North Carolina',276093);
+INSERT INTO City VALUES (3855,'Newark','USA','New Jersey',273546);
+INSERT INTO City VALUES (3856,'Lexington-Fayette','USA','Kentucky',260512);
+INSERT INTO City VALUES (3857,'Anchorage','USA','Alaska',260283);
+INSERT INTO City VALUES (3858,'Louisville','USA','Kentucky',256231);
+INSERT INTO City VALUES (3859,'Riverside','USA','California',255166);
+INSERT INTO City VALUES (3860,'Saint Petersburg','USA','Florida',248232);
+INSERT INTO City VALUES (3861,'Bakersfield','USA','California',247057);
+INSERT INTO City VALUES (3862,'Stockton','USA','California',243771);
+INSERT INTO City VALUES (3863,'Birmingham','USA','Alabama',242820);
+INSERT INTO City VALUES (3864,'Jersey City','USA','New Jersey',240055);
+INSERT INTO City VALUES (3865,'Norfolk','USA','Virginia',234403);
+INSERT INTO City VALUES (3866,'Baton Rouge','USA','Louisiana',227818);
+INSERT INTO City VALUES (3867,'Hialeah','USA','Florida',226419);
+INSERT INTO City VALUES (3868,'Lincoln','USA','Nebraska',225581);
+INSERT INTO City VALUES (3869,'Greensboro','USA','North Carolina',223891);
+INSERT INTO City VALUES (3870,'Plano','USA','Texas',222030);
+INSERT INTO City VALUES (3871,'Rochester','USA','New York',219773);
+INSERT INTO City VALUES (3872,'Glendale','USA','Arizona',218812);
+INSERT INTO City VALUES (3873,'Akron','USA','Ohio',217074);
+INSERT INTO City VALUES (3874,'Garland','USA','Texas',215768);
+INSERT INTO City VALUES (3875,'Madison','USA','Wisconsin',208054);
+INSERT INTO City VALUES (3876,'Fort Wayne','USA','Indiana',205727);
+INSERT INTO City VALUES (3877,'Fremont','USA','California',203413);
+INSERT INTO City VALUES (3878,'Scottsdale','USA','Arizona',202705);
+INSERT INTO City VALUES (3879,'Montgomery','USA','Alabama',201568);
+INSERT INTO City VALUES (3880,'Shreveport','USA','Louisiana',200145);
+INSERT INTO City VALUES (3881,'Augusta-Richmond County','USA','Georgia',199775);
+INSERT INTO City VALUES (3882,'Lubbock','USA','Texas',199564);
+INSERT INTO City VALUES (3883,'Chesapeake','USA','Virginia',199184);
+INSERT INTO City VALUES (3884,'Mobile','USA','Alabama',198915);
+INSERT INTO City VALUES (3885,'Des Moines','USA','Iowa',198682);
+INSERT INTO City VALUES (3886,'Grand Rapids','USA','Michigan',197800);
+INSERT INTO City VALUES (3887,'Richmond','USA','Virginia',197790);
+INSERT INTO City VALUES (3888,'Yonkers','USA','New York',196086);
+INSERT INTO City VALUES (3889,'Spokane','USA','Washington',195629);
+INSERT INTO City VALUES (3890,'Glendale','USA','California',194973);
+INSERT INTO City VALUES (3891,'Tacoma','USA','Washington',193556);
+INSERT INTO City VALUES (3892,'Irving','USA','Texas',191615);
+INSERT INTO City VALUES (3893,'Huntington Beach','USA','California',189594);
+INSERT INTO City VALUES (3894,'Modesto','USA','California',188856);
+INSERT INTO City VALUES (3895,'Durham','USA','North Carolina',187035);
+INSERT INTO City VALUES (3896,'Columbus','USA','Georgia',186291);
+INSERT INTO City VALUES (3897,'Orlando','USA','Florida',185951);
+INSERT INTO City VALUES (3898,'Boise City','USA','Idaho',185787);
+INSERT INTO City VALUES (3899,'Winston-Salem','USA','North Carolina',185776);
+INSERT INTO City VALUES (3900,'San Bernardino','USA','California',185401);
+INSERT INTO City VALUES (3901,'Jackson','USA','Mississippi',184256);
+INSERT INTO City VALUES (3902,'Little Rock','USA','Arkansas',183133);
+INSERT INTO City VALUES (3903,'Salt Lake City','USA','Utah',181743);
+INSERT INTO City VALUES (3904,'Reno','USA','Nevada',180480);
+INSERT INTO City VALUES (3905,'Newport News','USA','Virginia',180150);
+INSERT INTO City VALUES (3906,'Chandler','USA','Arizona',176581);
+INSERT INTO City VALUES (3907,'Laredo','USA','Texas',176576);
+INSERT INTO City VALUES (3908,'Henderson','USA','Nevada',175381);
+INSERT INTO City VALUES (3909,'Arlington','USA','Virginia',174838);
+INSERT INTO City VALUES (3910,'Knoxville','USA','Tennessee',173890);
+INSERT INTO City VALUES (3911,'Amarillo','USA','Texas',173627);
+INSERT INTO City VALUES (3912,'Providence','USA','Rhode Island',173618);
+INSERT INTO City VALUES (3913,'Chula Vista','USA','California',173556);
+INSERT INTO City VALUES (3914,'Worcester','USA','Massachusetts',172648);
+INSERT INTO City VALUES (3915,'Oxnard','USA','California',170358);
+INSERT INTO City VALUES (3916,'Dayton','USA','Ohio',166179);
+INSERT INTO City VALUES (3917,'Garden Grove','USA','California',165196);
+INSERT INTO City VALUES (3918,'Oceanside','USA','California',161029);
+INSERT INTO City VALUES (3919,'Tempe','USA','Arizona',158625);
+INSERT INTO City VALUES (3920,'Huntsville','USA','Alabama',158216);
+INSERT INTO City VALUES (3921,'Ontario','USA','California',158007);
+INSERT INTO City VALUES (3922,'Chattanooga','USA','Tennessee',155554);
+INSERT INTO City VALUES (3923,'Fort Lauderdale','USA','Florida',152397);
+INSERT INTO City VALUES (3924,'Springfield','USA','Massachusetts',152082);
+INSERT INTO City VALUES (3925,'Springfield','USA','Missouri',151580);
+INSERT INTO City VALUES (3926,'Santa Clarita','USA','California',151088);
+INSERT INTO City VALUES (3927,'Salinas','USA','California',151060);
+INSERT INTO City VALUES (3928,'Tallahassee','USA','Florida',150624);
+INSERT INTO City VALUES (3929,'Rockford','USA','Illinois',150115);
+INSERT INTO City VALUES (3930,'Pomona','USA','California',149473);
+INSERT INTO City VALUES (3931,'Metairie','USA','Louisiana',149428);
+INSERT INTO City VALUES (3932,'Paterson','USA','New Jersey',149222);
+INSERT INTO City VALUES (3933,'Overland Park','USA','Kansas',149080);
+INSERT INTO City VALUES (3934,'Santa Rosa','USA','California',147595);
+INSERT INTO City VALUES (3935,'Syracuse','USA','New York',147306);
+INSERT INTO City VALUES (3936,'Kansas City','USA','Kansas',146866);
+INSERT INTO City VALUES (3937,'Hampton','USA','Virginia',146437);
+INSERT INTO City VALUES (3938,'Lakewood','USA','Colorado',144126);
+INSERT INTO City VALUES (3939,'Vancouver','USA','Washington',143560);
+INSERT INTO City VALUES (3940,'Irvine','USA','California',143072);
+INSERT INTO City VALUES (3941,'Aurora','USA','Illinois',142990);
+INSERT INTO City VALUES (3942,'Moreno Valley','USA','California',142381);
+INSERT INTO City VALUES (3943,'Pasadena','USA','California',141674);
+INSERT INTO City VALUES (3944,'Hayward','USA','California',140030);
+INSERT INTO City VALUES (3945,'Brownsville','USA','Texas',139722);
+INSERT INTO City VALUES (3946,'Bridgeport','USA','Connecticut',139529);
+INSERT INTO City VALUES (3947,'Hollywood','USA','Florida',139357);
+INSERT INTO City VALUES (3948,'Warren','USA','Michigan',138247);
+INSERT INTO City VALUES (3949,'Torrance','USA','California',137946);
+INSERT INTO City VALUES (3950,'Eugene','USA','Oregon',137893);
+INSERT INTO City VALUES (3951,'Pembroke Pines','USA','Florida',137427);
+INSERT INTO City VALUES (3952,'Salem','USA','Oregon',136924);
+INSERT INTO City VALUES (3953,'Pasadena','USA','Texas',133936);
+INSERT INTO City VALUES (3954,'Escondido','USA','California',133559);
+INSERT INTO City VALUES (3955,'Sunnyvale','USA','California',131760);
+INSERT INTO City VALUES (3956,'Savannah','USA','Georgia',131510);
+INSERT INTO City VALUES (3957,'Fontana','USA','California',128929);
+INSERT INTO City VALUES (3958,'Orange','USA','California',128821);
+INSERT INTO City VALUES (3959,'Naperville','USA','Illinois',128358);
+INSERT INTO City VALUES (3960,'Alexandria','USA','Virginia',128283);
+INSERT INTO City VALUES (3961,'Rancho Cucamonga','USA','California',127743);
+INSERT INTO City VALUES (3962,'Grand Prairie','USA','Texas',127427);
+INSERT INTO City VALUES (3963,'East Los Angeles','USA','California',126379);
+INSERT INTO City VALUES (3964,'Fullerton','USA','California',126003);
+INSERT INTO City VALUES (3965,'Corona','USA','California',124966);
+INSERT INTO City VALUES (3966,'Flint','USA','Michigan',124943);
+INSERT INTO City VALUES (3967,'Paradise','USA','Nevada',124682);
+INSERT INTO City VALUES (3968,'Mesquite','USA','Texas',124523);
+INSERT INTO City VALUES (3969,'Sterling Heights','USA','Michigan',124471);
+INSERT INTO City VALUES (3970,'Sioux Falls','USA','South Dakota',123975);
+INSERT INTO City VALUES (3971,'New Haven','USA','Connecticut',123626);
+INSERT INTO City VALUES (3972,'Topeka','USA','Kansas',122377);
+INSERT INTO City VALUES (3973,'Concord','USA','California',121780);
+INSERT INTO City VALUES (3974,'Evansville','USA','Indiana',121582);
+INSERT INTO City VALUES (3975,'Hartford','USA','Connecticut',121578);
+INSERT INTO City VALUES (3976,'Fayetteville','USA','North Carolina',121015);
+INSERT INTO City VALUES (3977,'Cedar Rapids','USA','Iowa',120758);
+INSERT INTO City VALUES (3978,'Elizabeth','USA','New Jersey',120568);
+INSERT INTO City VALUES (3979,'Lansing','USA','Michigan',119128);
+INSERT INTO City VALUES (3980,'Lancaster','USA','California',118718);
+INSERT INTO City VALUES (3981,'Fort Collins','USA','Colorado',118652);
+INSERT INTO City VALUES (3982,'Coral Springs','USA','Florida',117549);
+INSERT INTO City VALUES (3983,'Stamford','USA','Connecticut',117083);
+INSERT INTO City VALUES (3984,'Thousand Oaks','USA','California',117005);
+INSERT INTO City VALUES (3985,'Vallejo','USA','California',116760);
+INSERT INTO City VALUES (3986,'Palmdale','USA','California',116670);
+INSERT INTO City VALUES (3987,'Columbia','USA','South Carolina',116278);
+INSERT INTO City VALUES (3988,'El Monte','USA','California',115965);
+INSERT INTO City VALUES (3989,'Abilene','USA','Texas',115930);
+INSERT INTO City VALUES (3990,'North Las Vegas','USA','Nevada',115488);
+INSERT INTO City VALUES (3991,'Ann Arbor','USA','Michigan',114024);
+INSERT INTO City VALUES (3992,'Beaumont','USA','Texas',113866);
+INSERT INTO City VALUES (3993,'Waco','USA','Texas',113726);
+INSERT INTO City VALUES (3994,'Macon','USA','Georgia',113336);
+INSERT INTO City VALUES (3995,'Independence','USA','Missouri',113288);
+INSERT INTO City VALUES (3996,'Peoria','USA','Illinois',112936);
+INSERT INTO City VALUES (3997,'Inglewood','USA','California',112580);
+INSERT INTO City VALUES (3998,'Springfield','USA','Illinois',111454);
+INSERT INTO City VALUES (3999,'Simi Valley','USA','California',111351);
+INSERT INTO City VALUES (4000,'Lafayette','USA','Louisiana',110257);
+INSERT INTO City VALUES (4001,'Gilbert','USA','Arizona',109697);
+INSERT INTO City VALUES (4002,'Carrollton','USA','Texas',109576);
+INSERT INTO City VALUES (4003,'Bellevue','USA','Washington',109569);
+INSERT INTO City VALUES (4004,'West Valley City','USA','Utah',108896);
+INSERT INTO City VALUES (4005,'Clarksville','USA','Tennessee',108787);
+INSERT INTO City VALUES (4006,'Costa Mesa','USA','California',108724);
+INSERT INTO City VALUES (4007,'Peoria','USA','Arizona',108364);
+INSERT INTO City VALUES (4008,'South Bend','USA','Indiana',107789);
+INSERT INTO City VALUES (4009,'Downey','USA','California',107323);
+INSERT INTO City VALUES (4010,'Waterbury','USA','Connecticut',107271);
+INSERT INTO City VALUES (4011,'Manchester','USA','New Hampshire',107006);
+INSERT INTO City VALUES (4012,'Allentown','USA','Pennsylvania',106632);
+INSERT INTO City VALUES (4013,'McAllen','USA','Texas',106414);
+INSERT INTO City VALUES (4014,'Joliet','USA','Illinois',106221);
+INSERT INTO City VALUES (4015,'Lowell','USA','Massachusetts',105167);
+INSERT INTO City VALUES (4016,'Provo','USA','Utah',105166);
+INSERT INTO City VALUES (4017,'West Covina','USA','California',105080);
+INSERT INTO City VALUES (4018,'Wichita Falls','USA','Texas',104197);
+INSERT INTO City VALUES (4019,'Erie','USA','Pennsylvania',103717);
+INSERT INTO City VALUES (4020,'Daly City','USA','California',103621);
+INSERT INTO City VALUES (4021,'Citrus Heights','USA','California',103455);
+INSERT INTO City VALUES (4022,'Norwalk','USA','California',103298);
+INSERT INTO City VALUES (4023,'Gary','USA','Indiana',102746);
+INSERT INTO City VALUES (4024,'Berkeley','USA','California',102743);
+INSERT INTO City VALUES (4025,'Santa Clara','USA','California',102361);
+INSERT INTO City VALUES (4026,'Green Bay','USA','Wisconsin',102313);
+INSERT INTO City VALUES (4027,'Cape Coral','USA','Florida',102286);
+INSERT INTO City VALUES (4028,'Arvada','USA','Colorado',102153);
+INSERT INTO City VALUES (4029,'Pueblo','USA','Colorado',102121);
+INSERT INTO City VALUES (4030,'Sandy','USA','Utah',101853);
+INSERT INTO City VALUES (4031,'Athens-Clarke County','USA','Georgia',101489);
+INSERT INTO City VALUES (4032,'Cambridge','USA','Massachusetts',101355);
+INSERT INTO City VALUES (4033,'Westminster','USA','Colorado',100940);
+INSERT INTO City VALUES (4034,'San Buenaventura','USA','California',100916);
+INSERT INTO City VALUES (4035,'Portsmouth','USA','Virginia',100565);
+INSERT INTO City VALUES (4036,'Livonia','USA','Michigan',100545);
+INSERT INTO City VALUES (4037,'Burbank','USA','California',100316);
+INSERT INTO City VALUES (4038,'Clearwater','USA','Florida',99936);
+INSERT INTO City VALUES (4039,'Midland','USA','Texas',98293);
+INSERT INTO City VALUES (4040,'Davenport','USA','Iowa',98256);
+INSERT INTO City VALUES (4041,'Mission Viejo','USA','California',98049);
+INSERT INTO City VALUES (4042,'Miami Beach','USA','Florida',97855);
+INSERT INTO City VALUES (4043,'Sunrise Manor','USA','Nevada',95362);
+INSERT INTO City VALUES (4044,'New Bedford','USA','Massachusetts',94780);
+INSERT INTO City VALUES (4045,'El Cajon','USA','California',94578);
+INSERT INTO City VALUES (4046,'Norman','USA','Oklahoma',94193);
+INSERT INTO City VALUES (4047,'Richmond','USA','California',94100);
+INSERT INTO City VALUES (4048,'Albany','USA','New York',93994);
+INSERT INTO City VALUES (4049,'Brockton','USA','Massachusetts',93653);
+INSERT INTO City VALUES (4050,'Roanoke','USA','Virginia',93357);
+INSERT INTO City VALUES (4051,'Billings','USA','Montana',92988);
+INSERT INTO City VALUES (4052,'Compton','USA','California',92864);
+INSERT INTO City VALUES (4053,'Gainesville','USA','Florida',92291);
+INSERT INTO City VALUES (4054,'Fairfield','USA','California',92256);
+INSERT INTO City VALUES (4055,'Arden-Arcade','USA','California',92040);
+INSERT INTO City VALUES (4056,'San Mateo','USA','California',91799);
+INSERT INTO City VALUES (4057,'Visalia','USA','California',91762);
+INSERT INTO City VALUES (4058,'Boulder','USA','Colorado',91238);
+INSERT INTO City VALUES (4059,'Cary','USA','North Carolina',91213);
+INSERT INTO City VALUES (4060,'Santa Monica','USA','California',91084);
+INSERT INTO City VALUES (4061,'Fall River','USA','Massachusetts',90555);
+INSERT INTO City VALUES (4062,'Kenosha','USA','Wisconsin',89447);
+INSERT INTO City VALUES (4063,'Elgin','USA','Illinois',89408);
+INSERT INTO City VALUES (4064,'Odessa','USA','Texas',89293);
+INSERT INTO City VALUES (4065,'Carson','USA','California',89089);
+INSERT INTO City VALUES (4066,'Charleston','USA','South Carolina',89063);
+INSERT INTO City VALUES (4067,'Charlotte Amalie','VIR','St Thomas',13000);
+INSERT INTO City VALUES (4068,'Harare','ZWE','Harare',1410000);
+INSERT INTO City VALUES (4069,'Bulawayo','ZWE','Bulawayo',621742);
+INSERT INTO City VALUES (4070,'Chitungwiza','ZWE','Harare',274912);
+INSERT INTO City VALUES (4071,'Mount Darwin','ZWE','Harare',164362);
+INSERT INTO City VALUES (4072,'Mutare','ZWE','Manicaland',131367);
+INSERT INTO City VALUES (4073,'Gweru','ZWE','Midlands',128037);
+INSERT INTO City VALUES (4074,'Gaza','PSE','Gaza',353632);
+INSERT INTO City VALUES (4075,'Khan Yunis','PSE','Khan Yunis',123175);
+INSERT INTO City VALUES (4076,'Hebron','PSE','Hebron',119401);
+INSERT INTO City VALUES (4077,'Jabaliya','PSE','North Gaza',113901);
+INSERT INTO City VALUES (4078,'Nablus','PSE','Nablus',100231);
+INSERT INTO City VALUES (4079,'Rafah','PSE','Rafah',92020);
+
+/*!40000 ALTER TABLE City ENABLE KEYS */;
+
+--
+-- Table structure for table 'Country'
+--
+
+CREATE TABLE Country (
+ Code char(3) NOT NULL default '',
+ Name char(52) NOT NULL default '',
+ Continent enum('Asia','Europe','North America','Africa','Oceania','Antarctica','South America') NOT NULL default 'Asia',
+ Region char(26) NOT NULL default '',
+ SurfaceArea float(10,2) NOT NULL default '0.00',
+ IndepYear smallint(6) default NULL,
+ Population int(11) NOT NULL default '0',
+ LifeExpectancy float(3,1) default NULL,
+ GNP float(10,2) default NULL,
+ GNPOld float(10,2) default NULL,
+ LocalName char(45) NOT NULL default '',
+ GovernmentForm char(45) NOT NULL default '',
+ HeadOfState char(60) default NULL,
+ Capital int(11) default NULL,
+ Code2 char(2) NOT NULL default '',
+ PRIMARY KEY (Code)
+) TYPE=MyISAM;
+
+/*!40000 ALTER TABLE Country DISABLE KEYS */;
+
+--
+-- Dumping data for table 'Country'
+--
+
+
+INSERT INTO Country VALUES ('AFG','Afghanistan','Asia','Southern and Central Asia',652090.00,1919,22720000,45.9,5976.00,NULL,'Afganistan/Afqanestan','Islamic Emirate','Mohammad Omar',1,'AF');
+INSERT INTO Country VALUES ('NLD','Netherlands','Europe','Western Europe',41526.00,1581,15864000,78.3,371362.00,360478.00,'Nederland','Constitutional Monarchy','Beatrix',5,'NL');
+INSERT INTO Country VALUES ('ANT','Netherlands Antilles','North America','Caribbean',800.00,0,217000,74.7,1941.00,NULL,'Nederlandse Antillen','Nonmetropolitan Territory of The Netherlands','Beatrix',33,'AN');
+INSERT INTO Country VALUES ('ALB','Albania','Europe','Southern Europe',28748.00,1912,3401200,71.6,3205.00,2500.00,'Shqipëria','Republic','Rexhep Mejdani',34,'AL');
+INSERT INTO Country VALUES ('DZA','Algeria','Africa','Northern Africa',2381741.00,1962,31471000,69.7,49982.00,46966.00,'Al-Jaza’ir/Algérie','Republic','Abdelaziz Bouteflika',35,'DZ');
+INSERT INTO Country VALUES ('ASM','American Samoa','Oceania','Polynesia',199.00,0,68000,75.1,334.00,NULL,'Amerika Samoa','US Territory','George W. Bush',54,'AS');
+INSERT INTO Country VALUES ('AND','Andorra','Europe','Southern Europe',468.00,1278,78000,83.5,1630.00,NULL,'Andorra','Parliamentary Coprincipality','',55,'AD');
+INSERT INTO Country VALUES ('AGO','Angola','Africa','Central Africa',1246700.00,1975,12878000,38.3,6648.00,7984.00,'Angola','Republic','José Eduardo dos Santos',56,'AO');
+INSERT INTO Country VALUES ('AIA','Anguilla','North America','Caribbean',96.00,0,8000,76.1,63.20,NULL,'Anguilla','Dependent Territory of the UK','Elisabeth II',62,'AI');
+INSERT INTO Country VALUES ('ATG','Antigua and Barbuda','North America','Caribbean',442.00,1981,68000,70.5,612.00,584.00,'Antigua and Barbuda','Constitutional Monarchy','Elisabeth II',63,'AG');
+INSERT INTO Country VALUES ('ARE','United Arab Emirates','Asia','Middle East',83600.00,1971,2441000,74.1,37966.00,36846.00,'Al-Imarat al-´Arabiya al-Muttahida','Emirate Federation','Zayid bin Sultan al-Nahayan',65,'AE');
+INSERT INTO Country VALUES ('ARG','Argentina','South America','South America',2780400.00,1816,37032000,75.1,340238.00,323310.00,'Argentina','Federal Republic','Fernando de la Rúa',69,'AR');
+INSERT INTO Country VALUES ('ARM','Armenia','Asia','Middle East',29800.00,1991,3520000,66.4,1813.00,1627.00,'Hajastan','Republic','Robert Kotšarjan',126,'AM');
+INSERT INTO Country VALUES ('ABW','Aruba','North America','Caribbean',193.00,0,103000,78.4,828.00,793.00,'Aruba','Nonmetropolitan Territory of The Netherlands','Beatrix',129,'AW');
+INSERT INTO Country VALUES ('AUS','Australia','Oceania','Australia and New Zealand',7741220.00,1901,18886000,79.8,351182.00,392911.00,'Australia','Constitutional Monarchy, Federation','Elisabeth II',135,'AU');
+INSERT INTO Country VALUES ('AZE','Azerbaijan','Asia','Middle East',86600.00,1991,7734000,62.9,4127.00,4100.00,'Azärbaycan','Federal Republic','Heydär Äliyev',144,'AZ');
+INSERT INTO Country VALUES ('BHS','Bahamas','North America','Caribbean',13878.00,1973,307000,71.1,3527.00,3347.00,'The Bahamas','Constitutional Monarchy','Elisabeth II',148,'BS');
+INSERT INTO Country VALUES ('BHR','Bahrain','Asia','Middle East',694.00,1971,617000,73.0,6366.00,6097.00,'Al-Bahrayn','Monarchy (Emirate)','Hamad ibn Isa al-Khalifa',149,'BH');
+INSERT INTO Country VALUES ('BGD','Bangladesh','Asia','Southern and Central Asia',143998.00,1971,129155000,60.2,32852.00,31966.00,'Bangladesh','Republic','Shahabuddin Ahmad',150,'BD');
+INSERT INTO Country VALUES ('BRB','Barbados','North America','Caribbean',430.00,1966,270000,73.0,2223.00,2186.00,'Barbados','Constitutional Monarchy','Elisabeth II',174,'BB');
+INSERT INTO Country VALUES ('BEL','Belgium','Europe','Western Europe',30518.00,1830,10239000,77.8,249704.00,243948.00,'België/Belgique','Constitutional Monarchy, Federation','Albert II',179,'BE');
+INSERT INTO Country VALUES ('BLZ','Belize','North America','Central America',22696.00,1981,241000,70.9,630.00,616.00,'Belize','Constitutional Monarchy','Elisabeth II',185,'BZ');
+INSERT INTO Country VALUES ('BEN','Benin','Africa','Western Africa',112622.00,1960,6097000,50.2,2357.00,2141.00,'Bénin','Republic','Mathieu Kérékou',187,'BJ');
+INSERT INTO Country VALUES ('BMU','Bermuda','North America','North America',53.00,0,65000,76.9,2328.00,2190.00,'Bermuda','Dependent Territory of the UK','Elisabeth II',191,'BM');
+INSERT INTO Country VALUES ('BTN','Bhutan','Asia','Southern and Central Asia',47000.00,1910,2124000,52.4,372.00,383.00,'Druk-Yul','Monarchy','Jigme Singye Wangchuk',192,'BT');
+INSERT INTO Country VALUES ('BOL','Bolivia','South America','South America',1098581.00,1825,8329000,63.7,8571.00,7967.00,'Bolivia','Republic','Hugo Bánzer Suárez',194,'BO');
+INSERT INTO Country VALUES ('BIH','Bosnia and Herzegovina','Europe','Southern Europe',51197.00,1992,3972000,71.5,2841.00,NULL,'Bosna i Hercegovina','Federal Republic','Ante Jelavic',201,'BA');
+INSERT INTO Country VALUES ('BWA','Botswana','Africa','Southern Africa',581730.00,1966,1622000,39.3,4834.00,4935.00,'Botswana','Republic','Festus G. Mogae',204,'BW');
+INSERT INTO Country VALUES ('BRA','Brazil','South America','South America',8547403.00,1822,170115000,62.9,776739.00,804108.00,'Brasil','Federal Republic','Fernando Henrique Cardoso',211,'BR');
+INSERT INTO Country VALUES ('GBR','United Kingdom','Europe','British Islands',242900.00,1066,59623400,77.7,1378330.00,1296830.00,'United Kingdom','Constitutional Monarchy','Elisabeth II',456,'GB');
+INSERT INTO Country VALUES ('VGB','Virgin Islands, British','North America','Caribbean',151.00,0,21000,75.4,612.00,573.00,'British Virgin Islands','Dependent Territory of the UK','Elisabeth II',537,'VG');
+INSERT INTO Country VALUES ('BRN','Brunei','Asia','Southeast Asia',5765.00,1984,328000,73.6,11705.00,12460.00,'Brunei Darussalam','Monarchy (Sultanate)','Haji Hassan al-Bolkiah',538,'BN');
+INSERT INTO Country VALUES ('BGR','Bulgaria','Europe','Eastern Europe',110994.00,1908,8190900,70.9,12178.00,10169.00,'Balgarija','Republic','Petar Stojanov',539,'BG');
+INSERT INTO Country VALUES ('BFA','Burkina Faso','Africa','Western Africa',274000.00,1960,11937000,46.7,2425.00,2201.00,'Burkina Faso','Republic','Blaise Compaoré',549,'BF');
+INSERT INTO Country VALUES ('BDI','Burundi','Africa','Eastern Africa',27834.00,1962,6695000,46.2,903.00,982.00,'Burundi/Uburundi','Republic','Pierre Buyoya',552,'BI');
+INSERT INTO Country VALUES ('CYM','Cayman Islands','North America','Caribbean',264.00,0,38000,78.9,1263.00,1186.00,'Cayman Islands','Dependent Territory of the UK','Elisabeth II',553,'KY');
+INSERT INTO Country VALUES ('CHL','Chile','South America','South America',756626.00,1810,15211000,75.7,72949.00,75780.00,'Chile','Republic','Ricardo Lagos Escobar',554,'CL');
+INSERT INTO Country VALUES ('COK','Cook Islands','Oceania','Polynesia',236.00,0,20000,71.1,100.00,NULL,'The Cook Islands','Nonmetropolitan Territory of New Zealand','Elisabeth II',583,'CK');
+INSERT INTO Country VALUES ('CRI','Costa Rica','North America','Central America',51100.00,1821,4023000,75.8,10226.00,9757.00,'Costa Rica','Republic','Miguel Ángel Rodríguez Echeverría',584,'CR');
+INSERT INTO Country VALUES ('DJI','Djibouti','Africa','Eastern Africa',23200.00,1977,638000,50.8,382.00,373.00,'Djibouti/Jibuti','Republic','Ismail Omar Guelleh',585,'DJ');
+INSERT INTO Country VALUES ('DMA','Dominica','North America','Caribbean',751.00,1978,71000,73.4,256.00,243.00,'Dominica','Republic','Vernon Shaw',586,'DM');
+INSERT INTO Country VALUES ('DOM','Dominican Republic','North America','Caribbean',48511.00,1844,8495000,73.2,15846.00,15076.00,'República Dominicana','Republic','Hipólito Mejía Domínguez',587,'DO');
+INSERT INTO Country VALUES ('ECU','Ecuador','South America','South America',283561.00,1822,12646000,71.1,19770.00,19769.00,'Ecuador','Republic','Gustavo Noboa Bejarano',594,'EC');
+INSERT INTO Country VALUES ('EGY','Egypt','Africa','Northern Africa',1001449.00,1922,68470000,63.3,82710.00,75617.00,'Misr','Republic','Hosni Mubarak',608,'EG');
+INSERT INTO Country VALUES ('SLV','El Salvador','North America','Central America',21041.00,1841,6276000,69.7,11863.00,11203.00,'El Salvador','Republic','Francisco Guillermo Flores Pérez',645,'SV');
+INSERT INTO Country VALUES ('ERI','Eritrea','Africa','Eastern Africa',117600.00,1993,3850000,55.8,650.00,755.00,'Ertra','Republic','Isayas Afewerki [Isaias Afwerki]',652,'ER');
+INSERT INTO Country VALUES ('ESP','Spain','Europe','Southern Europe',505992.00,1492,39441700,78.8,553233.00,532031.00,'España','Constitutional Monarchy','Juan Carlos I',653,'ES');
+INSERT INTO Country VALUES ('ZAF','South Africa','Africa','Southern Africa',1221037.00,1910,40377000,51.1,116729.00,129092.00,'South Africa','Republic','Thabo Mbeki',716,'ZA');
+INSERT INTO Country VALUES ('ETH','Ethiopia','Africa','Eastern Africa',1104300.00,-1000,62565000,45.2,6353.00,6180.00,'YeItyop´iya','Republic','Negasso Gidada',756,'ET');
+INSERT INTO Country VALUES ('FLK','Falkland Islands','South America','South America',12173.00,0,2000,NULL,0.00,NULL,'Falkland Islands','Dependent Territory of the UK','Elisabeth II',763,'FK');
+INSERT INTO Country VALUES ('FJI','Fiji Islands','Oceania','Melanesia',18274.00,1970,817000,67.9,1536.00,2149.00,'Fiji Islands','Republic','Josefa Iloilo',764,'FJ');
+INSERT INTO Country VALUES ('PHL','Philippines','Asia','Southeast Asia',300000.00,1946,75967000,67.5,65107.00,82239.00,'Pilipinas','Republic','Gloria Macapagal-Arroyo',766,'PH');
+INSERT INTO Country VALUES ('FRO','Faroe Islands','Europe','Nordic Countries',1399.00,0,43000,78.4,0.00,NULL,'Føroyar','Part of Denmark','Margrethe II',901,'FO');
+INSERT INTO Country VALUES ('GAB','Gabon','Africa','Central Africa',267668.00,1960,1226000,50.1,5493.00,5279.00,'Le Gabon','Republic','Omar Bongo',902,'GA');
+INSERT INTO Country VALUES ('GMB','Gambia','Africa','Western Africa',11295.00,1965,1305000,53.2,320.00,325.00,'The Gambia','Republic','Yahya Jammeh',904,'GM');
+INSERT INTO Country VALUES ('GEO','Georgia','Asia','Middle East',69700.00,1991,4968000,64.5,6064.00,5924.00,'Sakartvelo','Republic','Eduard Ševardnadze',905,'GE');
+INSERT INTO Country VALUES ('GHA','Ghana','Africa','Western Africa',238533.00,1957,20212000,57.4,7137.00,6884.00,'Ghana','Republic','John Kufuor',910,'GH');
+INSERT INTO Country VALUES ('GIB','Gibraltar','Europe','Southern Europe',6.00,0,25000,79.0,258.00,NULL,'Gibraltar','Dependent Territory of the UK','Elisabeth II',915,'GI');
+INSERT INTO Country VALUES ('GRD','Grenada','North America','Caribbean',344.00,1974,94000,64.5,318.00,NULL,'Grenada','Constitutional Monarchy','Elisabeth II',916,'GD');
+INSERT INTO Country VALUES ('GRL','Greenland','North America','North America',2166090.00,0,56000,68.1,0.00,NULL,'Kalaallit Nunaat/Grønland','Part of Denmark','Margrethe II',917,'GL');
+INSERT INTO Country VALUES ('GLP','Guadeloupe','North America','Caribbean',1705.00,0,456000,77.0,3501.00,NULL,'Guadeloupe','Overseas Department of France','Jacques Chirac',919,'GP');
+INSERT INTO Country VALUES ('GUM','Guam','Oceania','Micronesia',549.00,0,168000,77.8,1197.00,1136.00,'Guam','US Territory','George W. Bush',921,'GU');
+INSERT INTO Country VALUES ('GTM','Guatemala','North America','Central America',108889.00,1821,11385000,66.2,19008.00,17797.00,'Guatemala','Republic','Alfonso Portillo Cabrera',922,'GT');
+INSERT INTO Country VALUES ('GIN','Guinea','Africa','Western Africa',245857.00,1958,7430000,45.6,2352.00,2383.00,'Guinée','Republic','Lansana Conté',926,'GN');
+INSERT INTO Country VALUES ('GNB','Guinea-Bissau','Africa','Western Africa',36125.00,1974,1213000,49.0,293.00,272.00,'Guiné-Bissau','Republic','Kumba Ialá',927,'GW');
+INSERT INTO Country VALUES ('GUY','Guyana','South America','South America',214969.00,1966,861000,64.0,722.00,743.00,'Guyana','Republic','Bharrat Jagdeo',928,'GY');
+INSERT INTO Country VALUES ('HTI','Haiti','North America','Caribbean',27750.00,1804,8222000,49.2,3459.00,3107.00,'Haïti/Dayti','Republic','Jean-Bertrand Aristide',929,'HT');
+INSERT INTO Country VALUES ('HND','Honduras','North America','Central America',112088.00,1838,6485000,69.9,5333.00,4697.00,'Honduras','Republic','Carlos Roberto Flores Facussé',933,'HN');
+INSERT INTO Country VALUES ('HKG','Hong Kong','Asia','Eastern Asia',1075.00,0,6782000,79.5,166448.00,173610.00,'Xianggang/Hong Kong','Special Administrative Region of China','Jiang Zemin',937,'HK');
+INSERT INTO Country VALUES ('SJM','Svalbard and Jan Mayen','Europe','Nordic Countries',62422.00,0,3200,NULL,0.00,NULL,'Svalbard og Jan Mayen','Dependent Territory of Norway','Harald V',938,'SJ');
+INSERT INTO Country VALUES ('IDN','Indonesia','Asia','Southeast Asia',1904569.00,1945,212107000,68.0,84982.00,215002.00,'Indonesia','Republic','Abdurrahman Wahid',939,'ID');
+INSERT INTO Country VALUES ('IND','India','Asia','Southern and Central Asia',3287263.00,1947,1013662000,62.5,447114.00,430572.00,'Bharat/India','Federal Republic','Kocheril Raman Narayanan',1109,'IN');
+INSERT INTO Country VALUES ('IRQ','Iraq','Asia','Middle East',438317.00,1932,23115000,66.5,11500.00,NULL,'Al-´Iraq','Republic','Saddam Hussein al-Takriti',1365,'IQ');
+INSERT INTO Country VALUES ('IRN','Iran','Asia','Southern and Central Asia',1648195.00,1906,67702000,69.7,195746.00,160151.00,'Iran','Islamic Republic','Ali Mohammad Khatami-Ardakani',1380,'IR');
+INSERT INTO Country VALUES ('IRL','Ireland','Europe','British Islands',70273.00,1921,3775100,76.8,75921.00,73132.00,'Ireland/Éire','Republic','Mary McAleese',1447,'IE');
+INSERT INTO Country VALUES ('ISL','Iceland','Europe','Nordic Countries',103000.00,1944,279000,79.4,8255.00,7474.00,'Ísland','Republic','Ólafur Ragnar Grímsson',1449,'IS');
+INSERT INTO Country VALUES ('ISR','Israel','Asia','Middle East',21056.00,1948,6217000,78.6,97477.00,98577.00,'Yisra’el/Isra’il','Republic','Moshe Katzav',1450,'IL');
+INSERT INTO Country VALUES ('ITA','Italy','Europe','Southern Europe',301316.00,1861,57680000,79.0,1161755.00,1145372.00,'Italia','Republic','Carlo Azeglio Ciampi',1464,'IT');
+INSERT INTO Country VALUES ('TMP','East Timor','Asia','Southeast Asia',14874.00,0,885000,46.0,0.00,NULL,'Timor Timur','Administrated by the UN','José Alexandre Gusmão',1522,'TP');
+INSERT INTO Country VALUES ('AUT','Austria','Europe','Western Europe',83859.00,1918,8091800,77.7,211860.00,206025.00,'Österreich','Federal Republic','Thomas Klestil',1523,'AT');
+INSERT INTO Country VALUES ('JAM','Jamaica','North America','Caribbean',10990.00,1962,2583000,75.2,6871.00,6722.00,'Jamaica','Constitutional Monarchy','Elisabeth II',1530,'JM');
+INSERT INTO Country VALUES ('JPN','Japan','Asia','Eastern Asia',377829.00,-660,126714000,80.7,3787042.00,4192638.00,'Nihon/Nippon','Constitutional Monarchy','Akihito',1532,'JP');
+INSERT INTO Country VALUES ('YEM','Yemen','Asia','Middle East',527968.00,1918,18112000,59.8,6041.00,5729.00,'Al-Yaman','Republic','Ali Abdallah Salih',1780,'YE');
+INSERT INTO Country VALUES ('JOR','Jordan','Asia','Middle East',88946.00,1946,5083000,77.4,7526.00,7051.00,'Al-Urdunn','Constitutional Monarchy','Abdullah II',1786,'JO');
+INSERT INTO Country VALUES ('CXR','Christmas Island','Oceania','Australia and New Zealand',135.00,0,2500,NULL,0.00,NULL,'Christmas Island','Territory of Australia','Elisabeth II',1791,'CX');
+INSERT INTO Country VALUES ('YUG','Yugoslavia','Europe','Southern Europe',102173.00,1918,10640000,72.4,17000.00,NULL,'Jugoslavija','Federal Republic','Vojislav Koštunica',1792,'YU');
+INSERT INTO Country VALUES ('KHM','Cambodia','Asia','Southeast Asia',181035.00,1953,11168000,56.5,5121.00,5670.00,'Kâmpuchéa','Constitutional Monarchy','Norodom Sihanouk',1800,'KH');
+INSERT INTO Country VALUES ('CMR','Cameroon','Africa','Central Africa',475442.00,1960,15085000,54.8,9174.00,8596.00,'Cameroun/Cameroon','Republic','Paul Biya',1804,'CM');
+INSERT INTO Country VALUES ('CAN','Canada','North America','North America',9970610.00,1867,31147000,79.4,598862.00,625626.00,'Canada','Constitutional Monarchy, Federation','Elisabeth II',1822,'CA');
+INSERT INTO Country VALUES ('CPV','Cape Verde','Africa','Western Africa',4033.00,1975,428000,68.9,435.00,420.00,'Cabo Verde','Republic','António Mascarenhas Monteiro',1859,'CV');
+INSERT INTO Country VALUES ('KAZ','Kazakstan','Asia','Southern and Central Asia',2724900.00,1991,16223000,63.2,24375.00,23383.00,'Qazaqstan','Republic','Nursultan Nazarbajev',1864,'KZ');
+INSERT INTO Country VALUES ('KEN','Kenya','Africa','Eastern Africa',580367.00,1963,30080000,48.0,9217.00,10241.00,'Kenya','Republic','Daniel arap Moi',1881,'KE');
+INSERT INTO Country VALUES ('CAF','Central African Republic','Africa','Central Africa',622984.00,1960,3615000,44.0,1054.00,993.00,'Centrafrique/Bê-Afrîka','Republic','Ange-Félix Patassé',1889,'CF');
+INSERT INTO Country VALUES ('CHN','China','Asia','Eastern Asia',9572900.00,-1523,1277558000,71.4,982268.00,917719.00,'Zhongquo','People\'sRepublic','Jiang Zemin',1891,'CN');
+INSERT INTO Country VALUES ('KGZ','Kyrgyzstan','Asia','Southern and Central Asia',199900.00,1991,4699000,63.4,1626.00,1767.00,'Kyrgyzstan','Republic','Askar Akajev',2253,'KG');
+INSERT INTO Country VALUES ('KIR','Kiribati','Oceania','Micronesia',726.00,1979,83000,59.8,40.70,NULL,'Kiribati','Republic','Teburoro Tito',2256,'KI');
+INSERT INTO Country VALUES ('COL','Colombia','South America','South America',1138914.00,1810,42321000,70.3,102896.00,105116.00,'Colombia','Republic','Andrés Pastrana Arango',2257,'CO');
+INSERT INTO Country VALUES ('COM','Comoros','Africa','Eastern Africa',1862.00,1975,578000,60.0,4401.00,4361.00,'Komori/Comores','Republic','Azali Assoumani',2295,'KM');
+INSERT INTO Country VALUES ('COG','Congo','Africa','Central Africa',342000.00,1960,2943000,47.4,2108.00,2287.00,'Congo','Republic','Denis Sassou-Nguesso',2296,'CG');
+INSERT INTO Country VALUES ('COD','Congo, The Democratic Republic of the','Africa','Central Africa',2344858.00,1960,51654000,48.8,6964.00,2474.00,'République Démocratique du Congo','Republic','Joseph Kabila',2298,'CD');
+INSERT INTO Country VALUES ('CCK','Cocos (Keeling) Islands','Oceania','Australia and New Zealand',14.00,0,600,NULL,0.00,NULL,'Cocos (Keeling) Islands','Territory of Australia','Elisabeth II',2317,'CC');
+INSERT INTO Country VALUES ('PRK','North Korea','Asia','Eastern Asia',120538.00,1948,24039000,70.7,5332.00,NULL,'Choson Minjujuui In´min Konghwaguk (Bukhan)','Socialistic Republic','Kim Jong-il',2318,'KP');
+INSERT INTO Country VALUES ('KOR','South Korea','Asia','Eastern Asia',99434.00,1948,46844000,74.4,320749.00,442544.00,'Taehan Min’guk (Namhan)','Republic','Kim Dae-jung',2331,'KR');
+INSERT INTO Country VALUES ('GRC','Greece','Europe','Southern Europe',131626.00,1830,10545700,78.4,120724.00,119946.00,'Elláda','Republic','Kostis Stefanopoulos',2401,'GR');
+INSERT INTO Country VALUES ('HRV','Croatia','Europe','Southern Europe',56538.00,1991,4473000,73.7,20208.00,19300.00,'Hrvatska','Republic','Štipe Mesic',2409,'HR');
+INSERT INTO Country VALUES ('CUB','Cuba','North America','Caribbean',110861.00,1902,11201000,76.2,17843.00,18862.00,'Cuba','Socialistic Republic','Fidel Castro Ruz',2413,'CU');
+INSERT INTO Country VALUES ('KWT','Kuwait','Asia','Middle East',17818.00,1961,1972000,76.1,27037.00,30373.00,'Al-Kuwayt','Constitutional Monarchy (Emirate)','Jabir al-Ahmad al-Jabir al-Sabah',2429,'KW');
+INSERT INTO Country VALUES ('CYP','Cyprus','Asia','Middle East',9251.00,1960,754700,76.7,9333.00,8246.00,'Kýpros/Kibris','Republic','Glafkos Klerides',2430,'CY');
+INSERT INTO Country VALUES ('LAO','Laos','Asia','Southeast Asia',236800.00,1953,5433000,53.1,1292.00,1746.00,'Lao','Republic','Khamtay Siphandone',2432,'LA');
+INSERT INTO Country VALUES ('LVA','Latvia','Europe','Baltic Countries',64589.00,1991,2424200,68.4,6398.00,5639.00,'Latvija','Republic','Vaira Vike-Freiberga',2434,'LV');
+INSERT INTO Country VALUES ('LSO','Lesotho','Africa','Southern Africa',30355.00,1966,2153000,50.8,1061.00,1161.00,'Lesotho','Constitutional Monarchy','Letsie III',2437,'LS');
+INSERT INTO Country VALUES ('LBN','Lebanon','Asia','Middle East',10400.00,1941,3282000,71.3,17121.00,15129.00,'Lubnan','Republic','Émile Lahoud',2438,'LB');
+INSERT INTO Country VALUES ('LBR','Liberia','Africa','Western Africa',111369.00,1847,3154000,51.0,2012.00,NULL,'Liberia','Republic','Charles Taylor',2440,'LR');
+INSERT INTO Country VALUES ('LBY','Libyan Arab Jamahiriya','Africa','Northern Africa',1759540.00,1951,5605000,75.5,44806.00,40562.00,'Libiya','Socialistic State','Muammar al-Qadhafi',2441,'LY');
+INSERT INTO Country VALUES ('LIE','Liechtenstein','Europe','Western Europe',160.00,1806,32300,78.8,1119.00,1084.00,'Liechtenstein','Constitutional Monarchy','Hans-Adam II',2446,'LI');
+INSERT INTO Country VALUES ('LTU','Lithuania','Europe','Baltic Countries',65301.00,1991,3698500,69.1,10692.00,9585.00,'Lietuva','Republic','Valdas Adamkus',2447,'LT');
+INSERT INTO Country VALUES ('LUX','Luxembourg','Europe','Western Europe',2586.00,1867,435700,77.1,16321.00,15519.00,'Luxembourg/Lëtzebuerg','Constitutional Monarchy','Henri',2452,'LU');
+INSERT INTO Country VALUES ('ESH','Western Sahara','Africa','Northern Africa',266000.00,0,293000,49.8,60.00,NULL,'As-Sahrawiya','Occupied by Marocco','Mohammed Abdel Aziz',2453,'EH');
+INSERT INTO Country VALUES ('MAC','Macao','Asia','Eastern Asia',18.00,0,473000,81.6,5749.00,5940.00,'Macau/Aomen','Special Administrative Region of China','Jiang Zemin',2454,'MO');
+INSERT INTO Country VALUES ('MDG','Madagascar','Africa','Eastern Africa',587041.00,1960,15942000,55.0,3750.00,3545.00,'Madagasikara/Madagascar','Federal Republic','Didier Ratsiraka',2455,'MG');
+INSERT INTO Country VALUES ('MKD','Macedonia','Europe','Southern Europe',25713.00,1991,2024000,73.8,1694.00,1915.00,'Makedonija','Republic','Boris Trajkovski',2460,'MK');
+INSERT INTO Country VALUES ('MWI','Malawi','Africa','Eastern Africa',118484.00,1964,10925000,37.6,1687.00,2527.00,'Malawi','Republic','Bakili Muluzi',2462,'MW');
+INSERT INTO Country VALUES ('MDV','Maldives','Asia','Southern and Central Asia',298.00,1965,286000,62.2,199.00,NULL,'Dhivehi Raajje/Maldives','Republic','Maumoon Abdul Gayoom',2463,'MV');
+INSERT INTO Country VALUES ('MYS','Malaysia','Asia','Southeast Asia',329758.00,1957,22244000,70.8,69213.00,97884.00,'Malaysia','Constitutional Monarchy, Federation','Salahuddin Abdul Aziz Shah Alhaj',2464,'MY');
+INSERT INTO Country VALUES ('MLI','Mali','Africa','Western Africa',1240192.00,1960,11234000,46.7,2642.00,2453.00,'Mali','Republic','Alpha Oumar Konaré',2482,'ML');
+INSERT INTO Country VALUES ('MLT','Malta','Europe','Southern Europe',316.00,1964,380200,77.9,3512.00,3338.00,'Malta','Republic','Guido de Marco',2484,'MT');
+INSERT INTO Country VALUES ('MAR','Morocco','Africa','Northern Africa',446550.00,1956,28351000,69.1,36124.00,33514.00,'Al-Maghrib','Constitutional Monarchy','Mohammed VI',2486,'MA');
+INSERT INTO Country VALUES ('MHL','Marshall Islands','Oceania','Micronesia',181.00,1990,64000,65.5,97.00,NULL,'Marshall Islands/Majol','Republic','Kessai Note',2507,'MH');
+INSERT INTO Country VALUES ('MTQ','Martinique','North America','Caribbean',1102.00,0,395000,78.3,2731.00,2559.00,'Martinique','Overseas Department of France','Jacques Chirac',2508,'MQ');
+INSERT INTO Country VALUES ('MRT','Mauritania','Africa','Western Africa',1025520.00,1960,2670000,50.8,998.00,1081.00,'Muritaniya/Mauritanie','Republic','Maaouiya Ould Sid´Ahmad Taya',2509,'MR');
+INSERT INTO Country VALUES ('MUS','Mauritius','Africa','Eastern Africa',2040.00,1968,1158000,71.0,4251.00,4186.00,'Mauritius','Republic','Cassam Uteem',2511,'MU');
+INSERT INTO Country VALUES ('MYT','Mayotte','Africa','Eastern Africa',373.00,0,149000,59.5,0.00,NULL,'Mayotte','Territorial Collectivity of France','Jacques Chirac',2514,'YT');
+INSERT INTO Country VALUES ('MEX','Mexico','North America','Central America',1958201.00,1810,98881000,71.5,414972.00,401461.00,'México','Federal Republic','Vicente Fox Quesada',2515,'MX');
+INSERT INTO Country VALUES ('FSM','Micronesia, Federated States of','Oceania','Micronesia',702.00,1990,119000,68.6,212.00,NULL,'Micronesia','Federal Republic','Leo A. Falcam',2689,'FM');
+INSERT INTO Country VALUES ('MDA','Moldova','Europe','Eastern Europe',33851.00,1991,4380000,64.5,1579.00,1872.00,'Moldova','Republic','Vladimir Voronin',2690,'MD');
+INSERT INTO Country VALUES ('MCO','Monaco','Europe','Western Europe',1.50,1861,34000,78.8,776.00,NULL,'Monaco','Constitutional Monarchy','Rainier III',2695,'MC');
+INSERT INTO Country VALUES ('MNG','Mongolia','Asia','Eastern Asia',1566500.00,1921,2662000,67.3,1043.00,933.00,'Mongol Uls','Republic','Natsagiin Bagabandi',2696,'MN');
+INSERT INTO Country VALUES ('MSR','Montserrat','North America','Caribbean',102.00,0,11000,78.0,109.00,NULL,'Montserrat','Dependent Territory of the UK','Elisabeth II',2697,'MS');
+INSERT INTO Country VALUES ('MOZ','Mozambique','Africa','Eastern Africa',801590.00,1975,19680000,37.5,2891.00,2711.00,'Moçambique','Republic','Joaquím A. Chissano',2698,'MZ');
+INSERT INTO Country VALUES ('MMR','Myanmar','Asia','Southeast Asia',676578.00,1948,45611000,54.9,180375.00,171028.00,'Myanma Pye','Republic','kenraali Than Shwe',2710,'MM');
+INSERT INTO Country VALUES ('NAM','Namibia','Africa','Southern Africa',824292.00,1990,1726000,42.5,3101.00,3384.00,'Namibia','Republic','Sam Nujoma',2726,'NA');
+INSERT INTO Country VALUES ('NRU','Nauru','Oceania','Micronesia',21.00,1968,12000,60.8,197.00,NULL,'Naoero/Nauru','Republic','Bernard Dowiyogo',2728,'NR');
+INSERT INTO Country VALUES ('NPL','Nepal','Asia','Southern and Central Asia',147181.00,1769,23930000,57.8,4768.00,4837.00,'Nepal','Constitutional Monarchy','Gyanendra Bir Bikram',2729,'NP');
+INSERT INTO Country VALUES ('NIC','Nicaragua','North America','Central America',130000.00,1838,5074000,68.7,1988.00,2023.00,'Nicaragua','Republic','Arnoldo Alemán Lacayo',2734,'NI');
+INSERT INTO Country VALUES ('NER','Niger','Africa','Western Africa',1267000.00,1960,10730000,41.3,1706.00,1580.00,'Niger','Republic','Mamadou Tandja',2738,'NE');
+INSERT INTO Country VALUES ('NGA','Nigeria','Africa','Western Africa',923768.00,1960,111506000,51.6,65707.00,58623.00,'Nigeria','Federal Republic','Olusegun Obasanjo',2754,'NG');
+INSERT INTO Country VALUES ('NIU','Niue','Oceania','Polynesia',260.00,0,2000,NULL,0.00,NULL,'Niue','Nonmetropolitan Territory of New Zealand','Elisabeth II',2805,'NU');
+INSERT INTO Country VALUES ('NFK','Norfolk Island','Oceania','Australia and New Zealand',36.00,0,2000,NULL,0.00,NULL,'Norfolk Island','Territory of Australia','Elisabeth II',2806,'NF');
+INSERT INTO Country VALUES ('NOR','Norway','Europe','Nordic Countries',323877.00,1905,4478500,78.7,145895.00,153370.00,'Norge','Constitutional Monarchy','Harald V',2807,'NO');
+INSERT INTO Country VALUES ('CIV','Côte d’Ivoire','Africa','Western Africa',322463.00,1960,14786000,45.2,11345.00,10285.00,'Côte d’Ivoire','Republic','Laurent Gbagbo',2814,'CI');
+INSERT INTO Country VALUES ('OMN','Oman','Asia','Middle East',309500.00,1951,2542000,71.8,16904.00,16153.00,'´Uman','Monarchy (Sultanate)','Qabus ibn Sa´id',2821,'OM');
+INSERT INTO Country VALUES ('PAK','Pakistan','Asia','Southern and Central Asia',796095.00,1947,156483000,61.1,61289.00,58549.00,'Pakistan','Republic','Mohammad Rafiq Tarar',2831,'PK');
+INSERT INTO Country VALUES ('PLW','Palau','Oceania','Micronesia',459.00,1994,19000,68.6,105.00,NULL,'Belau/Palau','Republic','Kuniwo Nakamura',2881,'PW');
+INSERT INTO Country VALUES ('PAN','Panama','North America','Central America',75517.00,1903,2856000,75.5,9131.00,8700.00,'Panamá','Republic','Mireya Elisa Moscoso Rodríguez',2882,'PA');
+INSERT INTO Country VALUES ('PNG','Papua New Guinea','Oceania','Melanesia',462840.00,1975,4807000,63.1,4988.00,6328.00,'Papua New Guinea/Papua Niugini','Constitutional Monarchy','Elisabeth II',2884,'PG');
+INSERT INTO Country VALUES ('PRY','Paraguay','South America','South America',406752.00,1811,5496000,73.7,8444.00,9555.00,'Paraguay','Republic','Luis Ángel González Macchi',2885,'PY');
+INSERT INTO Country VALUES ('PER','Peru','South America','South America',1285216.00,1821,25662000,70.0,64140.00,65186.00,'Perú/Piruw','Republic','Valentin Paniagua Corazao',2890,'PE');
+INSERT INTO Country VALUES ('PCN','Pitcairn','Oceania','Polynesia',49.00,0,50,NULL,0.00,NULL,'Pitcairn','Dependent Territory of the UK','Elisabeth II',2912,'PN');
+INSERT INTO Country VALUES ('MNP','Northern Mariana Islands','Oceania','Micronesia',464.00,0,78000,75.5,0.00,NULL,'Northern Mariana Islands','Commonwealth of the US','George W. Bush',2913,'MP');
+INSERT INTO Country VALUES ('PRT','Portugal','Europe','Southern Europe',91982.00,1143,9997600,75.8,105954.00,102133.00,'Portugal','Republic','Jorge Sampãio',2914,'PT');
+INSERT INTO Country VALUES ('PRI','Puerto Rico','North America','Caribbean',8875.00,0,3869000,75.6,34100.00,32100.00,'Puerto Rico','Commonwealth of the US','George W. Bush',2919,'PR');
+INSERT INTO Country VALUES ('POL','Poland','Europe','Eastern Europe',323250.00,1918,38653600,73.2,151697.00,135636.00,'Polska','Republic','Aleksander Kwasniewski',2928,'PL');
+INSERT INTO Country VALUES ('GNQ','Equatorial Guinea','Africa','Central Africa',28051.00,1968,453000,53.6,283.00,542.00,'Guinea Ecuatorial','Republic','Teodoro Obiang Nguema Mbasogo',2972,'GQ');
+INSERT INTO Country VALUES ('QAT','Qatar','Asia','Middle East',11000.00,1971,599000,72.4,9472.00,8920.00,'Qatar','Monarchy','Hamad ibn Khalifa al-Thani',2973,'QA');
+INSERT INTO Country VALUES ('FRA','France','Europe','Western Europe',551500.00,843,59225700,78.8,1424285.00,1392448.00,'France','Republic','Jacques Chirac',2974,'FR');
+INSERT INTO Country VALUES ('GUF','French Guiana','South America','South America',90000.00,0,181000,76.1,681.00,NULL,'Guyane française','Overseas Department of France','Jacques Chirac',3014,'GF');
+INSERT INTO Country VALUES ('PYF','French Polynesia','Oceania','Polynesia',4000.00,0,235000,74.8,818.00,781.00,'Polynésie française','Nonmetropolitan Territory of France','Jacques Chirac',3016,'PF');
+INSERT INTO Country VALUES ('REU','Réunion','Africa','Eastern Africa',2510.00,0,699000,72.7,8287.00,7988.00,'Réunion','Overseas Department of France','Jacques Chirac',3017,'RE');
+INSERT INTO Country VALUES ('ROM','Romania','Europe','Eastern Europe',238391.00,1878,22455500,69.9,38158.00,34843.00,'România','Republic','Ion Iliescu',3018,'RO');
+INSERT INTO Country VALUES ('RWA','Rwanda','Africa','Eastern Africa',26338.00,1962,7733000,39.3,2036.00,1863.00,'Rwanda/Urwanda','Republic','Paul Kagame',3047,'RW');
+INSERT INTO Country VALUES ('SWE','Sweden','Europe','Nordic Countries',449964.00,836,8861400,79.6,226492.00,227757.00,'Sverige','Constitutional Monarchy','Carl XVI Gustaf',3048,'SE');
+INSERT INTO Country VALUES ('SHN','Saint Helena','Africa','Western Africa',314.00,0,6000,76.8,0.00,NULL,'Saint Helena','Dependent Territory of the UK','Elisabeth II',3063,'SH');
+INSERT INTO Country VALUES ('KNA','Saint Kitts and Nevis','North America','Caribbean',261.00,1983,38000,70.7,299.00,NULL,'Saint Kitts and Nevis','Constitutional Monarchy','Elisabeth II',3064,'KN');
+INSERT INTO Country VALUES ('LCA','Saint Lucia','North America','Caribbean',622.00,1979,154000,72.3,571.00,NULL,'Saint Lucia','Constitutional Monarchy','Elisabeth II',3065,'LC');
+INSERT INTO Country VALUES ('VCT','Saint Vincent and the Grenadines','North America','Caribbean',388.00,1979,114000,72.3,285.00,NULL,'Saint Vincent and the Grenadines','Constitutional Monarchy','Elisabeth II',3066,'VC');
+INSERT INTO Country VALUES ('SPM','Saint Pierre and Miquelon','North America','North America',242.00,0,7000,77.6,0.00,NULL,'Saint-Pierre-et-Miquelon','Territorial Collectivity of France','Jacques Chirac',3067,'PM');
+INSERT INTO Country VALUES ('DEU','Germany','Europe','Western Europe',357022.00,1955,82164700,77.4,2133367.00,2102826.00,'Deutschland','Federal Republic','Johannes Rau',3068,'DE');
+INSERT INTO Country VALUES ('SLB','Solomon Islands','Oceania','Melanesia',28896.00,1978,444000,71.3,182.00,220.00,'Solomon Islands','Constitutional Monarchy','Elisabeth II',3161,'SB');
+INSERT INTO Country VALUES ('ZMB','Zambia','Africa','Eastern Africa',752618.00,1964,9169000,37.2,3377.00,3922.00,'Zambia','Republic','Frederick Chiluba',3162,'ZM');
+INSERT INTO Country VALUES ('WSM','Samoa','Oceania','Polynesia',2831.00,1962,180000,69.2,141.00,157.00,'Samoa','Parlementary Monarchy','Malietoa Tanumafili II',3169,'WS');
+INSERT INTO Country VALUES ('SMR','San Marino','Europe','Southern Europe',61.00,885,27000,81.1,510.00,NULL,'San Marino','Republic',NULL,3171,'SM');
+INSERT INTO Country VALUES ('STP','Sao Tome and Principe','Africa','Central Africa',964.00,1975,147000,65.3,6.00,NULL,'São Tomé e Príncipe','Republic','Miguel Trovoada',3172,'ST');
+INSERT INTO Country VALUES ('SAU','Saudi Arabia','Asia','Middle East',2149690.00,1932,21607000,67.8,137635.00,146171.00,'Al-´Arabiya as-Sa´udiya','Monarchy','Fahd ibn Abdul-Aziz al-Sa´ud',3173,'SA');
+INSERT INTO Country VALUES ('SEN','Senegal','Africa','Western Africa',196722.00,1960,9481000,62.2,4787.00,4542.00,'Sénégal/Sounougal','Republic','Abdoulaye Wade',3198,'SN');
+INSERT INTO Country VALUES ('SYC','Seychelles','Africa','Eastern Africa',455.00,1976,77000,70.4,536.00,539.00,'Sesel/Seychelles','Republic','France-Albert René',3206,'SC');
+INSERT INTO Country VALUES ('SLE','Sierra Leone','Africa','Western Africa',71740.00,1961,4854000,45.3,746.00,858.00,'Sierra Leone','Republic','Ahmed Tejan Kabbah',3207,'SL');
+INSERT INTO Country VALUES ('SGP','Singapore','Asia','Southeast Asia',618.00,1965,3567000,80.1,86503.00,96318.00,'Singapore/Singapura/Xinjiapo/Singapur','Republic','Sellapan Rama Nathan',3208,'SG');
+INSERT INTO Country VALUES ('SVK','Slovakia','Europe','Eastern Europe',49012.00,1993,5398700,73.7,20594.00,19452.00,'Slovensko','Republic','Rudolf Schuster',3209,'SK');
+INSERT INTO Country VALUES ('SVN','Slovenia','Europe','Southern Europe',20256.00,1991,1987800,74.9,19756.00,18202.00,'Slovenija','Republic','Milan Kucan',3212,'SI');
+INSERT INTO Country VALUES ('SOM','Somalia','Africa','Eastern Africa',637657.00,1960,10097000,46.2,935.00,NULL,'Soomaaliya','Republic','Abdiqassim Salad Hassan',3214,'SO');
+INSERT INTO Country VALUES ('LKA','Sri Lanka','Asia','Southern and Central Asia',65610.00,1948,18827000,71.8,15706.00,15091.00,'Sri Lanka/Ilankai','Republic','Chandrika Kumaratunga',3217,'LK');
+INSERT INTO Country VALUES ('SDN','Sudan','Africa','Northern Africa',2505813.00,1956,29490000,56.6,10162.00,NULL,'As-Sudan','Islamic Republic','Omar Hassan Ahmad al-Bashir',3225,'SD');
+INSERT INTO Country VALUES ('FIN','Finland','Europe','Nordic Countries',338145.00,1917,5171300,77.4,121914.00,119833.00,'Suomi','Republic','Tarja Halonen',3236,'FI');
+INSERT INTO Country VALUES ('SUR','Suriname','South America','South America',163265.00,1975,417000,71.4,870.00,706.00,'Suriname','Republic','Ronald Venetiaan',3243,'SR');
+INSERT INTO Country VALUES ('SWZ','Swaziland','Africa','Southern Africa',17364.00,1968,1008000,40.4,1206.00,1312.00,'kaNgwane','Monarchy','Mswati III',3244,'SZ');
+INSERT INTO Country VALUES ('CHE','Switzerland','Europe','Western Europe',41284.00,1499,7160400,79.6,264478.00,256092.00,'Schweiz/Suisse/Svizzera/Svizra','Federation','Adolf Ogi',3248,'CH');
+INSERT INTO Country VALUES ('SYR','Syria','Asia','Middle East',185180.00,1941,16125000,68.5,65984.00,64926.00,'Suriya','Republic','Bashar al-Assad',3250,'SY');
+INSERT INTO Country VALUES ('TJK','Tajikistan','Asia','Southern and Central Asia',143100.00,1991,6188000,64.1,1990.00,1056.00,'Toçikiston','Republic','Emomali Rahmonov',3261,'TJ');
+INSERT INTO Country VALUES ('TWN','Taiwan, Province of China','Asia','Eastern Asia',36188.00,1945,22256000,76.4,256254.00,263451.00,'T’ai-wan','Republic','Chen Shui-bian',3263,'TW');
+INSERT INTO Country VALUES ('TZA','Tanzania','Africa','Eastern Africa',883749.00,1961,33517000,52.3,8005.00,7388.00,'Tanzania','Republic','Benjamin William Mkapa',3306,'TZ');
+INSERT INTO Country VALUES ('DNK','Denmark','Europe','Nordic Countries',43094.00,800,5330000,76.5,174099.00,169264.00,'Danmark','Constitutional Monarchy','Margrethe II',3315,'DK');
+INSERT INTO Country VALUES ('THA','Thailand','Asia','Southeast Asia',513115.00,1350,61399000,68.6,116416.00,153907.00,'Prathet Thai','Constitutional Monarchy','Bhumibol Adulyadej',3320,'TH');
+INSERT INTO Country VALUES ('TGO','Togo','Africa','Western Africa',56785.00,1960,4629000,54.7,1449.00,1400.00,'Togo','Republic','Gnassingbé Eyadéma',3332,'TG');
+INSERT INTO Country VALUES ('TKL','Tokelau','Oceania','Polynesia',12.00,0,2000,NULL,0.00,NULL,'Tokelau','Nonmetropolitan Territory of New Zealand','Elisabeth II',3333,'TK');
+INSERT INTO Country VALUES ('TON','Tonga','Oceania','Polynesia',650.00,1970,99000,67.9,146.00,170.00,'Tonga','Monarchy','Taufa\'ahau Tupou IV',3334,'TO');
+INSERT INTO Country VALUES ('TTO','Trinidad and Tobago','North America','Caribbean',5130.00,1962,1295000,68.0,6232.00,5867.00,'Trinidad and Tobago','Republic','Arthur N. R. Robinson',3336,'TT');
+INSERT INTO Country VALUES ('TCD','Chad','Africa','Central Africa',1284000.00,1960,7651000,50.5,1208.00,1102.00,'Tchad/Tshad','Republic','Idriss Déby',3337,'TD');
+INSERT INTO Country VALUES ('CZE','Czech Republic','Europe','Eastern Europe',78866.00,1993,10278100,74.5,55017.00,52037.00,'¸esko','Republic','Václav Havel',3339,'CZ');
+INSERT INTO Country VALUES ('TUN','Tunisia','Africa','Northern Africa',163610.00,1956,9586000,73.7,20026.00,18898.00,'Tunis/Tunisie','Republic','Zine al-Abidine Ben Ali',3349,'TN');
+INSERT INTO Country VALUES ('TUR','Turkey','Asia','Middle East',774815.00,1923,66591000,71.0,210721.00,189122.00,'Türkiye','Republic','Ahmet Necdet Sezer',3358,'TR');
+INSERT INTO Country VALUES ('TKM','Turkmenistan','Asia','Southern and Central Asia',488100.00,1991,4459000,60.9,4397.00,2000.00,'Türkmenostan','Republic','Saparmurad Nijazov',3419,'TM');
+INSERT INTO Country VALUES ('TCA','Turks and Caicos Islands','North America','Caribbean',430.00,0,17000,73.3,96.00,NULL,'The Turks and Caicos Islands','Dependent Territory of the UK','Elisabeth II',3423,'TC');
+INSERT INTO Country VALUES ('TUV','Tuvalu','Oceania','Polynesia',26.00,1978,12000,66.3,6.00,NULL,'Tuvalu','Constitutional Monarchy','Elisabeth II',3424,'TV');
+INSERT INTO Country VALUES ('UGA','Uganda','Africa','Eastern Africa',241038.00,1962,21778000,42.9,6313.00,6887.00,'Uganda','Republic','Yoweri Museveni',3425,'UG');
+INSERT INTO Country VALUES ('UKR','Ukraine','Europe','Eastern Europe',603700.00,1991,50456000,66.0,42168.00,49677.00,'Ukrajina','Republic','Leonid Kutšma',3426,'UA');
+INSERT INTO Country VALUES ('HUN','Hungary','Europe','Eastern Europe',93030.00,1918,10043200,71.4,48267.00,45914.00,'Magyarország','Republic','Ferenc Mádl',3483,'HU');
+INSERT INTO Country VALUES ('URY','Uruguay','South America','South America',175016.00,1828,3337000,75.2,20831.00,19967.00,'Uruguay','Republic','Jorge Batlle Ibáñez',3492,'UY');
+INSERT INTO Country VALUES ('NCL','New Caledonia','Oceania','Melanesia',18575.00,0,214000,72.8,3563.00,NULL,'Nouvelle-Calédonie','Nonmetropolitan Territory of France','Jacques Chirac',3493,'NC');
+INSERT INTO Country VALUES ('NZL','New Zealand','Oceania','Australia and New Zealand',270534.00,1907,3862000,77.8,54669.00,64960.00,'New Zealand/Aotearoa','Constitutional Monarchy','Elisabeth II',3499,'NZ');
+INSERT INTO Country VALUES ('UZB','Uzbekistan','Asia','Southern and Central Asia',447400.00,1991,24318000,63.7,14194.00,21300.00,'Uzbekiston','Republic','Islam Karimov',3503,'UZ');
+INSERT INTO Country VALUES ('BLR','Belarus','Europe','Eastern Europe',207600.00,1991,10236000,68.0,13714.00,NULL,'Belarus','Republic','Aljaksandr Lukašenka',3520,'BY');
+INSERT INTO Country VALUES ('WLF','Wallis and Futuna','Oceania','Polynesia',200.00,0,15000,NULL,0.00,NULL,'Wallis-et-Futuna','Nonmetropolitan Territory of France','Jacques Chirac',3536,'WF');
+INSERT INTO Country VALUES ('VUT','Vanuatu','Oceania','Melanesia',12189.00,1980,190000,60.6,261.00,246.00,'Vanuatu','Republic','John Bani',3537,'VU');
+INSERT INTO Country VALUES ('VAT','Holy See (Vatican City State)','Europe','Southern Europe',0.40,1929,1000,NULL,9.00,NULL,'Santa Sede/Città del Vaticano','Independent Church State','Johannes Paavali II',3538,'VA');
+INSERT INTO Country VALUES ('VEN','Venezuela','South America','South America',912050.00,1811,24170000,73.1,95023.00,88434.00,'Venezuela','Federal Republic','Hugo Chávez Frías',3539,'VE');
+INSERT INTO Country VALUES ('RUS','Russian Federation','Europe','Eastern Europe',17075400.00,1991,146934000,67.2,276608.00,442989.00,'Rossija','Federal Republic','Vladimir Putin',3580,'RU');
+INSERT INTO Country VALUES ('VNM','Vietnam','Asia','Southeast Asia',331689.00,1945,79832000,69.3,21929.00,22834.00,'Viêt Nam','Socialistic Republic','Trân Duc Luong',3770,'VN');
+INSERT INTO Country VALUES ('EST','Estonia','Europe','Baltic Countries',45227.00,1991,1439200,69.5,5328.00,3371.00,'Eesti','Republic','Lennart Meri',3791,'EE');
+INSERT INTO Country VALUES ('USA','United States','North America','North America',9363520.00,1776,278357000,77.1,8510700.00,8110900.00,'United States','Federal Republic','George W. Bush',3813,'US');
+INSERT INTO Country VALUES ('VIR','Virgin Islands, U.S.','North America','Caribbean',347.00,0,93000,78.1,0.00,NULL,'Virgin Islands of the United States','US Territory','George W. Bush',4067,'VI');
+INSERT INTO Country VALUES ('ZWE','Zimbabwe','Africa','Eastern Africa',390757.00,1980,11669000,37.8,5951.00,8670.00,'Zimbabwe','Republic','Robert G. Mugabe',4068,'ZW');
+INSERT INTO Country VALUES ('PSE','Palestine','Asia','Middle East',6257.00,0,3101000,71.4,4173.00,NULL,'Filastin','Autonomous Area','Yasser (Yasir) Arafat',4074,'PS');
+INSERT INTO Country VALUES ('ATA','Antarctica','Antarctica','Antarctica',13120000.00,0,0,NULL,0.00,NULL,'–','Co-administrated','',NULL,'AQ');
+INSERT INTO Country VALUES ('BVT','Bouvet Island','Antarctica','Antarctica',59.00,0,0,NULL,0.00,NULL,'Bouvetøya','Dependent Territory of Norway','Harald V',NULL,'BV');
+INSERT INTO Country VALUES ('IOT','British Indian Ocean Territory','Africa','Eastern Africa',78.00,0,0,NULL,0.00,NULL,'British Indian Ocean Territory','Dependent Territory of the UK','Elisabeth II',NULL,'IO');
+INSERT INTO Country VALUES ('SGS','South Georgia and the South Sandwich Islands','Antarctica','Antarctica',3903.00,0,0,NULL,0.00,NULL,'South Georgia and the South Sandwich Islands','Dependent Territory of the UK','Elisabeth II',NULL,'GS');
+INSERT INTO Country VALUES ('HMD','Heard Island and McDonald Islands','Antarctica','Antarctica',359.00,0,0,NULL,0.00,NULL,'Heard and McDonald Islands','Territory of Australia','Elisabeth II',NULL,'HM');
+INSERT INTO Country VALUES ('ATF','French Southern territories','Antarctica','Antarctica',7780.00,0,0,NULL,0.00,NULL,'Terres australes françaises','Nonmetropolitan Territory of France','Jacques Chirac',NULL,'TF');
+INSERT INTO Country VALUES ('UMI','United States Minor Outlying Islands','Oceania','Micronesia/Caribbean',16.00,0,0,NULL,0.00,NULL,'United States Minor Outlying Islands','Dependent Territory of the US','George W. Bush',NULL,'UM');
+
+/*!40000 ALTER TABLE Country ENABLE KEYS */;
+
+--
+-- Table structure for table 'CountryLanguage'
+--
+
+CREATE TABLE CountryLanguage (
+ Country char(3) NOT NULL default '',
+ Language char(30) NOT NULL default '',
+ IsOfficial enum('T','F') NOT NULL default 'F',
+ Percentage float(3,1) NOT NULL default '0.0',
+ PRIMARY KEY (Country,Language)
+) TYPE=MyISAM;
+
+/*!40000 ALTER TABLE CountryLanguage DISABLE KEYS */;
+
+--
+-- Dumping data for table 'CountryLanguage'
+--
+
+
+INSERT INTO CountryLanguage VALUES ('AFG','Pashto','T',52.4);
+INSERT INTO CountryLanguage VALUES ('NLD','Dutch','T',95.6);
+INSERT INTO CountryLanguage VALUES ('ANT','Papiamento','T',86.2);
+INSERT INTO CountryLanguage VALUES ('ALB','Albaniana','T',97.9);
+INSERT INTO CountryLanguage VALUES ('DZA','Arabic','T',86.0);
+INSERT INTO CountryLanguage VALUES ('ASM','Samoan','T',90.6);
+INSERT INTO CountryLanguage VALUES ('AND','Spanish','F',44.6);
+INSERT INTO CountryLanguage VALUES ('AGO','Ovimbundu','F',37.2);
+INSERT INTO CountryLanguage VALUES ('AIA','English','T',0.0);
+INSERT INTO CountryLanguage VALUES ('ATG','Creole English','F',95.7);
+INSERT INTO CountryLanguage VALUES ('ARE','Arabic','T',42.0);
+INSERT INTO CountryLanguage VALUES ('ARG','Spanish','T',96.8);
+INSERT INTO CountryLanguage VALUES ('ARM','Armenian','T',93.4);
+INSERT INTO CountryLanguage VALUES ('ABW','Papiamento','F',76.7);
+INSERT INTO CountryLanguage VALUES ('AUS','English','T',81.2);
+INSERT INTO CountryLanguage VALUES ('AZE','Azerbaijani','T',89.0);
+INSERT INTO CountryLanguage VALUES ('BHS','Creole English','F',89.7);
+INSERT INTO CountryLanguage VALUES ('BHR','Arabic','T',67.7);
+INSERT INTO CountryLanguage VALUES ('BGD','Bengali','T',97.7);
+INSERT INTO CountryLanguage VALUES ('BRB','Bajan','F',95.1);
+INSERT INTO CountryLanguage VALUES ('BEL','Dutch','T',59.2);
+INSERT INTO CountryLanguage VALUES ('BLZ','English','T',50.8);
+INSERT INTO CountryLanguage VALUES ('BEN','Fon','F',39.8);
+INSERT INTO CountryLanguage VALUES ('BMU','English','T',100.0);
+INSERT INTO CountryLanguage VALUES ('BTN','Dzongkha','T',50.0);
+INSERT INTO CountryLanguage VALUES ('BOL','Spanish','T',87.7);
+INSERT INTO CountryLanguage VALUES ('BIH','Serbo-Croatian','T',99.2);
+INSERT INTO CountryLanguage VALUES ('BWA','Tswana','F',75.5);
+INSERT INTO CountryLanguage VALUES ('BRA','Portuguese','T',97.5);
+INSERT INTO CountryLanguage VALUES ('GBR','English','T',97.3);
+INSERT INTO CountryLanguage VALUES ('VGB','English','T',0.0);
+INSERT INTO CountryLanguage VALUES ('BRN','Malay','T',45.5);
+INSERT INTO CountryLanguage VALUES ('BGR','Bulgariana','T',83.2);
+INSERT INTO CountryLanguage VALUES ('BFA','Mossi','F',50.2);
+INSERT INTO CountryLanguage VALUES ('BDI','Kirundi','T',98.1);
+INSERT INTO CountryLanguage VALUES ('CYM','English','T',0.0);
+INSERT INTO CountryLanguage VALUES ('CHL','Spanish','T',89.7);
+INSERT INTO CountryLanguage VALUES ('COK','Maori','T',0.0);
+INSERT INTO CountryLanguage VALUES ('CRI','Spanish','T',97.5);
+INSERT INTO CountryLanguage VALUES ('DJI','Somali','F',43.9);
+INSERT INTO CountryLanguage VALUES ('DMA','Creole English','F',100.0);
+INSERT INTO CountryLanguage VALUES ('DOM','Spanish','T',98.0);
+INSERT INTO CountryLanguage VALUES ('ECU','Spanish','T',93.0);
+INSERT INTO CountryLanguage VALUES ('EGY','Arabic','T',98.8);
+INSERT INTO CountryLanguage VALUES ('SLV','Spanish','T',100.0);
+INSERT INTO CountryLanguage VALUES ('ERI','Tigrinja','T',49.1);
+INSERT INTO CountryLanguage VALUES ('ESP','Spanish','T',74.4);
+INSERT INTO CountryLanguage VALUES ('ZAF','Zulu','T',22.7);
+INSERT INTO CountryLanguage VALUES ('ETH','Oromo','F',31.0);
+INSERT INTO CountryLanguage VALUES ('FLK','English','T',0.0);
+INSERT INTO CountryLanguage VALUES ('FJI','Fijian','T',50.8);
+INSERT INTO CountryLanguage VALUES ('PHL','Pilipino','T',29.3);
+INSERT INTO CountryLanguage VALUES ('FRO','Faroese','T',100.0);
+INSERT INTO CountryLanguage VALUES ('GAB','Fang','F',35.8);
+INSERT INTO CountryLanguage VALUES ('GMB','Malinke','F',34.1);
+INSERT INTO CountryLanguage VALUES ('GEO','Georgiana','T',71.7);
+INSERT INTO CountryLanguage VALUES ('GHA','Akan','F',52.4);
+INSERT INTO CountryLanguage VALUES ('GIB','English','T',88.9);
+INSERT INTO CountryLanguage VALUES ('GRD','Creole English','F',100.0);
+INSERT INTO CountryLanguage VALUES ('GRL','Greenlandic','T',87.5);
+INSERT INTO CountryLanguage VALUES ('GLP','Creole French','F',95.0);
+INSERT INTO CountryLanguage VALUES ('GUM','English','T',37.5);
+INSERT INTO CountryLanguage VALUES ('GTM','Spanish','T',64.7);
+INSERT INTO CountryLanguage VALUES ('GIN','Ful','F',38.6);
+INSERT INTO CountryLanguage VALUES ('GNB','Crioulo','F',36.4);
+INSERT INTO CountryLanguage VALUES ('GUY','Creole English','F',96.4);
+INSERT INTO CountryLanguage VALUES ('HTI','Haiti Creole','F',100.0);
+INSERT INTO CountryLanguage VALUES ('HND','Spanish','T',97.2);
+INSERT INTO CountryLanguage VALUES ('HKG','Canton Chinese','F',88.7);
+INSERT INTO CountryLanguage VALUES ('SJM','Norwegian','T',0.0);
+INSERT INTO CountryLanguage VALUES ('IDN','Javanese','F',39.4);
+INSERT INTO CountryLanguage VALUES ('IND','Hindi','T',39.9);
+INSERT INTO CountryLanguage VALUES ('IRQ','Arabic','T',77.2);
+INSERT INTO CountryLanguage VALUES ('IRN','Persian','T',45.7);
+INSERT INTO CountryLanguage VALUES ('IRL','English','T',98.4);
+INSERT INTO CountryLanguage VALUES ('ISL','Icelandic','T',95.7);
+INSERT INTO CountryLanguage VALUES ('ISR','Hebrew','T',63.1);
+INSERT INTO CountryLanguage VALUES ('ITA','Italian','T',94.1);
+INSERT INTO CountryLanguage VALUES ('TMP','Sunda','F',0.0);
+INSERT INTO CountryLanguage VALUES ('AUT','German','T',92.0);
+INSERT INTO CountryLanguage VALUES ('JAM','Creole English','F',94.2);
+INSERT INTO CountryLanguage VALUES ('JPN','Japanese','T',99.1);
+INSERT INTO CountryLanguage VALUES ('YEM','Arabic','T',99.6);
+INSERT INTO CountryLanguage VALUES ('JOR','Arabic','T',97.9);
+INSERT INTO CountryLanguage VALUES ('CXR','Chinese','F',0.0);
+INSERT INTO CountryLanguage VALUES ('YUG','Serbo-Croatian','T',75.2);
+INSERT INTO CountryLanguage VALUES ('KHM','Khmer','T',88.6);
+INSERT INTO CountryLanguage VALUES ('CMR','Fang','F',19.7);
+INSERT INTO CountryLanguage VALUES ('CAN','English','T',60.4);
+INSERT INTO CountryLanguage VALUES ('CPV','Crioulo','F',100.0);
+INSERT INTO CountryLanguage VALUES ('KAZ','Kazakh','T',46.0);
+INSERT INTO CountryLanguage VALUES ('KEN','Kikuyu','F',20.9);
+INSERT INTO CountryLanguage VALUES ('CAF','Gbaya','F',23.8);
+INSERT INTO CountryLanguage VALUES ('CHN','Chinese','T',92.0);
+INSERT INTO CountryLanguage VALUES ('KGZ','Kirgiz','T',59.7);
+INSERT INTO CountryLanguage VALUES ('KIR','Kiribati','T',98.9);
+INSERT INTO CountryLanguage VALUES ('COL','Spanish','T',99.0);
+INSERT INTO CountryLanguage VALUES ('COM','Comorian','T',75.0);
+INSERT INTO CountryLanguage VALUES ('COG','Kongo','F',51.5);
+INSERT INTO CountryLanguage VALUES ('COD','Luba','F',18.0);
+INSERT INTO CountryLanguage VALUES ('CCK','Malay','F',0.0);
+INSERT INTO CountryLanguage VALUES ('PRK','Korean','T',99.9);
+INSERT INTO CountryLanguage VALUES ('KOR','Korean','T',99.9);
+INSERT INTO CountryLanguage VALUES ('GRC','Greek','T',98.5);
+INSERT INTO CountryLanguage VALUES ('HRV','Serbo-Croatian','T',95.9);
+INSERT INTO CountryLanguage VALUES ('CUB','Spanish','T',100.0);
+INSERT INTO CountryLanguage VALUES ('KWT','Arabic','T',78.1);
+INSERT INTO CountryLanguage VALUES ('CYP','Greek','T',74.1);
+INSERT INTO CountryLanguage VALUES ('LAO','Lao','T',67.2);
+INSERT INTO CountryLanguage VALUES ('LVA','Latvian','T',55.1);
+INSERT INTO CountryLanguage VALUES ('LSO','Sotho','T',85.0);
+INSERT INTO CountryLanguage VALUES ('LBN','Arabic','T',93.0);
+INSERT INTO CountryLanguage VALUES ('LBR','Kpelle','F',19.5);
+INSERT INTO CountryLanguage VALUES ('LBY','Arabic','T',96.0);
+INSERT INTO CountryLanguage VALUES ('LIE','German','T',89.0);
+INSERT INTO CountryLanguage VALUES ('LTU','Lithuanian','T',81.6);
+INSERT INTO CountryLanguage VALUES ('LUX','Luxembourgish','T',64.4);
+INSERT INTO CountryLanguage VALUES ('ESH','Arabic','T',100.0);
+INSERT INTO CountryLanguage VALUES ('MAC','Canton Chinese','F',85.6);
+INSERT INTO CountryLanguage VALUES ('MDG','Malagasy','T',98.9);
+INSERT INTO CountryLanguage VALUES ('MKD','Macedonian','T',66.5);
+INSERT INTO CountryLanguage VALUES ('MWI','Chichewa','T',58.3);
+INSERT INTO CountryLanguage VALUES ('MDV','Dhivehi','T',100.0);
+INSERT INTO CountryLanguage VALUES ('MYS','Malay','T',58.4);
+INSERT INTO CountryLanguage VALUES ('MLI','Bambara','F',31.8);
+INSERT INTO CountryLanguage VALUES ('MLT','Maltese','T',95.8);
+INSERT INTO CountryLanguage VALUES ('MAR','Arabic','T',65.0);
+INSERT INTO CountryLanguage VALUES ('MHL','Marshallese','T',96.8);
+INSERT INTO CountryLanguage VALUES ('MTQ','Creole French','F',96.6);
+INSERT INTO CountryLanguage VALUES ('MRT','Hassaniya','F',81.7);
+INSERT INTO CountryLanguage VALUES ('MUS','Creole French','F',70.6);
+INSERT INTO CountryLanguage VALUES ('MYT','Mahoré','F',41.9);
+INSERT INTO CountryLanguage VALUES ('MEX','Spanish','T',92.1);
+INSERT INTO CountryLanguage VALUES ('FSM','Trukese','F',41.6);
+INSERT INTO CountryLanguage VALUES ('MDA','Romanian','T',61.9);
+INSERT INTO CountryLanguage VALUES ('MCO','French','T',41.9);
+INSERT INTO CountryLanguage VALUES ('MNG','Mongolian','T',78.8);
+INSERT INTO CountryLanguage VALUES ('MSR','English','T',0.0);
+INSERT INTO CountryLanguage VALUES ('MOZ','Makua','F',27.8);
+INSERT INTO CountryLanguage VALUES ('MMR','Burmese','T',69.0);
+INSERT INTO CountryLanguage VALUES ('NAM','Ovambo','F',50.7);
+INSERT INTO CountryLanguage VALUES ('NRU','Nauru','T',57.5);
+INSERT INTO CountryLanguage VALUES ('NPL','Nepali','T',50.4);
+INSERT INTO CountryLanguage VALUES ('NIC','Spanish','T',97.6);
+INSERT INTO CountryLanguage VALUES ('NER','Hausa','F',53.1);
+INSERT INTO CountryLanguage VALUES ('NGA','Joruba','F',21.4);
+INSERT INTO CountryLanguage VALUES ('NIU','Niue','F',0.0);
+INSERT INTO CountryLanguage VALUES ('NFK','English','T',0.0);
+INSERT INTO CountryLanguage VALUES ('NOR','Norwegian','T',96.6);
+INSERT INTO CountryLanguage VALUES ('CIV','Akan','F',30.0);
+INSERT INTO CountryLanguage VALUES ('OMN','Arabic','T',76.7);
+INSERT INTO CountryLanguage VALUES ('PAK','Punjabi','F',48.2);
+INSERT INTO CountryLanguage VALUES ('PLW','Palau','T',82.2);
+INSERT INTO CountryLanguage VALUES ('PAN','Spanish','T',76.8);
+INSERT INTO CountryLanguage VALUES ('PNG','Papuan Languages','F',78.1);
+INSERT INTO CountryLanguage VALUES ('PRY','Spanish','T',55.1);
+INSERT INTO CountryLanguage VALUES ('PER','Spanish','T',79.8);
+INSERT INTO CountryLanguage VALUES ('PCN','Pitcairnese','F',0.0);
+INSERT INTO CountryLanguage VALUES ('MNP','Philippene Languages','F',34.1);
+INSERT INTO CountryLanguage VALUES ('PRT','Portuguese','T',99.0);
+INSERT INTO CountryLanguage VALUES ('PRI','Spanish','T',51.3);
+INSERT INTO CountryLanguage VALUES ('POL','Polish','T',97.6);
+INSERT INTO CountryLanguage VALUES ('GNQ','Fang','F',84.8);
+INSERT INTO CountryLanguage VALUES ('QAT','Arabic','T',40.7);
+INSERT INTO CountryLanguage VALUES ('FRA','French','T',93.6);
+INSERT INTO CountryLanguage VALUES ('GUF','Creole French','F',94.3);
+INSERT INTO CountryLanguage VALUES ('PYF','Tahitian','F',46.4);
+INSERT INTO CountryLanguage VALUES ('REU','Creole French','F',91.5);
+INSERT INTO CountryLanguage VALUES ('ROM','Romanian','T',90.7);
+INSERT INTO CountryLanguage VALUES ('RWA','Rwanda','T',100.0);
+INSERT INTO CountryLanguage VALUES ('SWE','Swedish','T',89.5);
+INSERT INTO CountryLanguage VALUES ('SHN','English','T',0.0);
+INSERT INTO CountryLanguage VALUES ('KNA','Creole English','F',100.0);
+INSERT INTO CountryLanguage VALUES ('LCA','Creole French','F',80.0);
+INSERT INTO CountryLanguage VALUES ('VCT','Creole English','F',99.1);
+INSERT INTO CountryLanguage VALUES ('SPM','French','T',0.0);
+INSERT INTO CountryLanguage VALUES ('DEU','German','T',91.3);
+INSERT INTO CountryLanguage VALUES ('SLB','Malenasian Languages','F',85.6);
+INSERT INTO CountryLanguage VALUES ('ZMB','Bemba','F',29.7);
+INSERT INTO CountryLanguage VALUES ('WSM','Samoan-English','F',52.0);
+INSERT INTO CountryLanguage VALUES ('SMR','Italian','T',100.0);
+INSERT INTO CountryLanguage VALUES ('STP','Crioulo','F',86.3);
+INSERT INTO CountryLanguage VALUES ('SAU','Arabic','T',95.0);
+INSERT INTO CountryLanguage VALUES ('SEN','Wolof','T',48.1);
+INSERT INTO CountryLanguage VALUES ('SYC','Seselwa','F',91.3);
+INSERT INTO CountryLanguage VALUES ('SLE','Mende','F',34.8);
+INSERT INTO CountryLanguage VALUES ('SGP','Chinese','T',77.1);
+INSERT INTO CountryLanguage VALUES ('SVK','Slovak','T',85.6);
+INSERT INTO CountryLanguage VALUES ('SVN','Slovene','T',87.9);
+INSERT INTO CountryLanguage VALUES ('SOM','Somali','T',98.3);
+INSERT INTO CountryLanguage VALUES ('LKA','Singali','T',60.3);
+INSERT INTO CountryLanguage VALUES ('SDN','Arabic','T',49.4);
+INSERT INTO CountryLanguage VALUES ('FIN','Finnish','T',92.7);
+INSERT INTO CountryLanguage VALUES ('SUR','Sranantonga','F',81.0);
+INSERT INTO CountryLanguage VALUES ('SWZ','Swazi','T',89.9);
+INSERT INTO CountryLanguage VALUES ('CHE','German','T',63.6);
+INSERT INTO CountryLanguage VALUES ('SYR','Arabic','T',90.0);
+INSERT INTO CountryLanguage VALUES ('TJK','Tadzhik','T',62.2);
+INSERT INTO CountryLanguage VALUES ('TWN','Min','F',66.7);
+INSERT INTO CountryLanguage VALUES ('TZA','Nyamwesi','F',21.1);
+INSERT INTO CountryLanguage VALUES ('DNK','Danish','T',93.5);
+INSERT INTO CountryLanguage VALUES ('THA','Thai','T',52.6);
+INSERT INTO CountryLanguage VALUES ('TGO','Ewe','T',23.2);
+INSERT INTO CountryLanguage VALUES ('TKL','Tokelau','F',0.0);
+INSERT INTO CountryLanguage VALUES ('TON','Tongan','T',98.3);
+INSERT INTO CountryLanguage VALUES ('TTO','English','F',93.5);
+INSERT INTO CountryLanguage VALUES ('TCD','Sara','F',27.7);
+INSERT INTO CountryLanguage VALUES ('CZE','Czech','T',81.2);
+INSERT INTO CountryLanguage VALUES ('TUN','Arabic','T',69.9);
+INSERT INTO CountryLanguage VALUES ('TUR','Turkish','T',87.6);
+INSERT INTO CountryLanguage VALUES ('TKM','Turkmenian','T',76.7);
+INSERT INTO CountryLanguage VALUES ('TCA','English','T',0.0);
+INSERT INTO CountryLanguage VALUES ('TUV','Tuvalu','T',92.5);
+INSERT INTO CountryLanguage VALUES ('UGA','Ganda','F',18.1);
+INSERT INTO CountryLanguage VALUES ('UKR','Ukrainian','T',64.7);
+INSERT INTO CountryLanguage VALUES ('HUN','Hungarian','T',98.5);
+INSERT INTO CountryLanguage VALUES ('URY','Spanish','T',95.7);
+INSERT INTO CountryLanguage VALUES ('NCL','Malenasian Languages','F',45.4);
+INSERT INTO CountryLanguage VALUES ('NZL','English','T',87.0);
+INSERT INTO CountryLanguage VALUES ('UZB','Uzbek','T',72.6);
+INSERT INTO CountryLanguage VALUES ('BLR','Belorussian','T',65.6);
+INSERT INTO CountryLanguage VALUES ('WLF','Wallis','F',0.0);
+INSERT INTO CountryLanguage VALUES ('VUT','Bislama','T',56.6);
+INSERT INTO CountryLanguage VALUES ('VAT','Italian','T',0.0);
+INSERT INTO CountryLanguage VALUES ('VEN','Spanish','T',96.9);
+INSERT INTO CountryLanguage VALUES ('RUS','Russian','T',86.6);
+INSERT INTO CountryLanguage VALUES ('VNM','Vietnamese','T',86.8);
+INSERT INTO CountryLanguage VALUES ('EST','Estonian','T',65.3);
+INSERT INTO CountryLanguage VALUES ('USA','English','T',86.2);
+INSERT INTO CountryLanguage VALUES ('VIR','English','T',81.7);
+INSERT INTO CountryLanguage VALUES ('UMI','English','T',0.0);
+INSERT INTO CountryLanguage VALUES ('ZWE','Shona','F',72.1);
+INSERT INTO CountryLanguage VALUES ('PSE','Arabic','F',95.9);
+INSERT INTO CountryLanguage VALUES ('AFG','Dari','T',32.1);
+INSERT INTO CountryLanguage VALUES ('NLD','Fries','F',3.7);
+INSERT INTO CountryLanguage VALUES ('ANT','English','F',7.8);
+INSERT INTO CountryLanguage VALUES ('ALB','Greek','F',1.8);
+INSERT INTO CountryLanguage VALUES ('DZA','Berberi','F',14.0);
+INSERT INTO CountryLanguage VALUES ('ASM','English','T',3.1);
+INSERT INTO CountryLanguage VALUES ('AND','Catalan','T',32.3);
+INSERT INTO CountryLanguage VALUES ('AGO','Mbundu','F',21.6);
+INSERT INTO CountryLanguage VALUES ('ATG','English','T',0.0);
+INSERT INTO CountryLanguage VALUES ('ARE','Hindi','F',0.0);
+INSERT INTO CountryLanguage VALUES ('ARG','Italian','F',1.7);
+INSERT INTO CountryLanguage VALUES ('ARM','Azerbaijani','F',2.6);
+INSERT INTO CountryLanguage VALUES ('ABW','English','F',9.5);
+INSERT INTO CountryLanguage VALUES ('AUS','Italian','F',2.2);
+INSERT INTO CountryLanguage VALUES ('AZE','Russian','F',3.0);
+INSERT INTO CountryLanguage VALUES ('BHS','Creole French','F',10.3);
+INSERT INTO CountryLanguage VALUES ('BHR','English','F',0.0);
+INSERT INTO CountryLanguage VALUES ('BGD','Chakma','F',0.4);
+INSERT INTO CountryLanguage VALUES ('BRB','English','T',0.0);
+INSERT INTO CountryLanguage VALUES ('BEL','French','T',32.6);
+INSERT INTO CountryLanguage VALUES ('BLZ','Spanish','F',31.6);
+INSERT INTO CountryLanguage VALUES ('BEN','Joruba','F',12.2);
+INSERT INTO CountryLanguage VALUES ('BTN','Nepali','F',34.8);
+INSERT INTO CountryLanguage VALUES ('BOL','Ketšua','T',8.1);
+INSERT INTO CountryLanguage VALUES ('BWA','Shona','F',12.3);
+INSERT INTO CountryLanguage VALUES ('BRA','German','F',0.5);
+INSERT INTO CountryLanguage VALUES ('GBR','Kymri','F',0.9);
+INSERT INTO CountryLanguage VALUES ('BRN','Malay-English','F',28.8);
+INSERT INTO CountryLanguage VALUES ('BGR','Turkish','F',9.4);
+INSERT INTO CountryLanguage VALUES ('BFA','Ful','F',9.7);
+INSERT INTO CountryLanguage VALUES ('BDI','French','T',0.0);
+INSERT INTO CountryLanguage VALUES ('CHL','Araucan','F',9.6);
+INSERT INTO CountryLanguage VALUES ('COK','English','F',0.0);
+INSERT INTO CountryLanguage VALUES ('CRI','Creole English','F',2.0);
+INSERT INTO CountryLanguage VALUES ('DJI','Afar','F',34.8);
+INSERT INTO CountryLanguage VALUES ('DMA','Creole French','F',0.0);
+INSERT INTO CountryLanguage VALUES ('DOM','Creole French','F',2.0);
+INSERT INTO CountryLanguage VALUES ('ECU','Ketšua','F',7.0);
+INSERT INTO CountryLanguage VALUES ('EGY','Sinaberberi','F',0.0);
+INSERT INTO CountryLanguage VALUES ('SLV','Nahua','F',0.0);
+INSERT INTO CountryLanguage VALUES ('ERI','Tigre','F',31.7);
+INSERT INTO CountryLanguage VALUES ('ESP','Catalan','F',16.9);
+INSERT INTO CountryLanguage VALUES ('ZAF','Xhosa','T',17.7);
+INSERT INTO CountryLanguage VALUES ('ETH','Amhara','F',30.0);
+INSERT INTO CountryLanguage VALUES ('FJI','Hindi','F',43.7);
+INSERT INTO CountryLanguage VALUES ('PHL','Cebuano','F',23.3);
+INSERT INTO CountryLanguage VALUES ('FRO','Danish','T',0.0);
+INSERT INTO CountryLanguage VALUES ('GAB','Punu-sira-nzebi','F',17.1);
+INSERT INTO CountryLanguage VALUES ('GMB','Ful','F',16.2);
+INSERT INTO CountryLanguage VALUES ('GEO','Russian','F',8.8);
+INSERT INTO CountryLanguage VALUES ('GHA','Mossi','F',15.8);
+INSERT INTO CountryLanguage VALUES ('GIB','Arabic','F',7.4);
+INSERT INTO CountryLanguage VALUES ('GRL','Danish','T',12.5);
+INSERT INTO CountryLanguage VALUES ('GLP','French','T',0.0);
+INSERT INTO CountryLanguage VALUES ('GUM','Chamorro','T',29.6);
+INSERT INTO CountryLanguage VALUES ('GTM','Quiché','F',10.1);
+INSERT INTO CountryLanguage VALUES ('GIN','Malinke','F',23.2);
+INSERT INTO CountryLanguage VALUES ('GNB','Ful','F',16.6);
+INSERT INTO CountryLanguage VALUES ('GUY','Caribbean','F',2.2);
+INSERT INTO CountryLanguage VALUES ('HTI','French','T',0.0);
+INSERT INTO CountryLanguage VALUES ('HND','Garifuna','F',1.3);
+INSERT INTO CountryLanguage VALUES ('HKG','English','T',2.2);
+INSERT INTO CountryLanguage VALUES ('SJM','Russian','F',0.0);
+INSERT INTO CountryLanguage VALUES ('IDN','Sunda','F',15.8);
+INSERT INTO CountryLanguage VALUES ('IND','Bengali','F',8.2);
+INSERT INTO CountryLanguage VALUES ('IRQ','Kurdish','F',19.0);
+INSERT INTO CountryLanguage VALUES ('IRN','Azerbaijani','F',16.8);
+INSERT INTO CountryLanguage VALUES ('IRL','Irish','T',1.6);
+INSERT INTO CountryLanguage VALUES ('ISL','English','F',0.0);
+INSERT INTO CountryLanguage VALUES ('ISR','Arabic','T',18.0);
+INSERT INTO CountryLanguage VALUES ('ITA','Sardinian','F',2.7);
+INSERT INTO CountryLanguage VALUES ('TMP','Portuguese','T',0.0);
+INSERT INTO CountryLanguage VALUES ('AUT','Serbo-Croatian','F',2.2);
+INSERT INTO CountryLanguage VALUES ('JAM','Hindi','F',1.9);
+INSERT INTO CountryLanguage VALUES ('JPN','Korean','F',0.5);
+INSERT INTO CountryLanguage VALUES ('YEM','Soqutri','F',0.0);
+INSERT INTO CountryLanguage VALUES ('JOR','Circassian','F',1.0);
+INSERT INTO CountryLanguage VALUES ('CXR','English','T',0.0);
+INSERT INTO CountryLanguage VALUES ('YUG','Albaniana','F',16.5);
+INSERT INTO CountryLanguage VALUES ('KHM','Vietnamese','F',5.5);
+INSERT INTO CountryLanguage VALUES ('CMR','Bamileke-bamum','F',18.6);
+INSERT INTO CountryLanguage VALUES ('CAN','French','T',23.4);
+INSERT INTO CountryLanguage VALUES ('CPV','Portuguese','T',0.0);
+INSERT INTO CountryLanguage VALUES ('KAZ','Russian','F',34.7);
+INSERT INTO CountryLanguage VALUES ('KEN','Luhya','F',13.8);
+INSERT INTO CountryLanguage VALUES ('CAF','Banda','F',23.5);
+INSERT INTO CountryLanguage VALUES ('CHN','Zhuang','F',1.4);
+INSERT INTO CountryLanguage VALUES ('KGZ','Russian','T',16.2);
+INSERT INTO CountryLanguage VALUES ('KIR','Tuvalu','F',0.5);
+INSERT INTO CountryLanguage VALUES ('COL','Chibcha','F',0.4);
+INSERT INTO CountryLanguage VALUES ('COM','Comorian-French','F',12.9);
+INSERT INTO CountryLanguage VALUES ('COG','Teke','F',17.3);
+INSERT INTO CountryLanguage VALUES ('COD','Kongo','F',16.0);
+INSERT INTO CountryLanguage VALUES ('CCK','English','T',0.0);
+INSERT INTO CountryLanguage VALUES ('PRK','Chinese','F',0.1);
+INSERT INTO CountryLanguage VALUES ('KOR','Chinese','F',0.1);
+INSERT INTO CountryLanguage VALUES ('GRC','Turkish','F',0.9);
+INSERT INTO CountryLanguage VALUES ('HRV','Slovene','F',0.0);
+INSERT INTO CountryLanguage VALUES ('KWT','English','F',0.0);
+INSERT INTO CountryLanguage VALUES ('CYP','Turkish','T',22.4);
+INSERT INTO CountryLanguage VALUES ('LAO','Mon-khmer','F',16.5);
+INSERT INTO CountryLanguage VALUES ('LVA','Russian','F',32.5);
+INSERT INTO CountryLanguage VALUES ('LSO','Zulu','F',15.0);
+INSERT INTO CountryLanguage VALUES ('LBN','Armenian','F',5.9);
+INSERT INTO CountryLanguage VALUES ('LBR','Bassa','F',13.7);
+INSERT INTO CountryLanguage VALUES ('LBY','Berberi','F',1.0);
+INSERT INTO CountryLanguage VALUES ('LIE','Italian','F',2.5);
+INSERT INTO CountryLanguage VALUES ('LTU','Russian','F',8.1);
+INSERT INTO CountryLanguage VALUES ('LUX','Portuguese','F',13.0);
+INSERT INTO CountryLanguage VALUES ('MAC','Portuguese','T',2.3);
+INSERT INTO CountryLanguage VALUES ('MDG','French','T',0.0);
+INSERT INTO CountryLanguage VALUES ('MKD','Albaniana','F',22.9);
+INSERT INTO CountryLanguage VALUES ('MWI','Lomwe','F',18.4);
+INSERT INTO CountryLanguage VALUES ('MDV','English','F',0.0);
+INSERT INTO CountryLanguage VALUES ('MYS','Chinese','F',9.0);
+INSERT INTO CountryLanguage VALUES ('MLI','Ful','F',13.9);
+INSERT INTO CountryLanguage VALUES ('MLT','English','T',2.1);
+INSERT INTO CountryLanguage VALUES ('MAR','Berberi','F',33.0);
+INSERT INTO CountryLanguage VALUES ('MHL','English','T',0.0);
+INSERT INTO CountryLanguage VALUES ('MTQ','French','T',0.0);
+INSERT INTO CountryLanguage VALUES ('MRT','Wolof','F',6.6);
+INSERT INTO CountryLanguage VALUES ('MUS','Bhojpuri','F',21.1);
+INSERT INTO CountryLanguage VALUES ('MYT','French','T',20.3);
+INSERT INTO CountryLanguage VALUES ('MEX','Náhuatl','F',1.8);
+INSERT INTO CountryLanguage VALUES ('FSM','Pohnpei','F',23.8);
+INSERT INTO CountryLanguage VALUES ('MDA','Russian','F',23.2);
+INSERT INTO CountryLanguage VALUES ('MCO','Monegasque','F',16.1);
+INSERT INTO CountryLanguage VALUES ('MNG','Kazakh','F',5.9);
+INSERT INTO CountryLanguage VALUES ('MOZ','Tsonga','F',12.4);
+INSERT INTO CountryLanguage VALUES ('MMR','Shan','F',8.5);
+INSERT INTO CountryLanguage VALUES ('NAM','Nama','F',12.4);
+INSERT INTO CountryLanguage VALUES ('NRU','Kiribati','F',17.9);
+INSERT INTO CountryLanguage VALUES ('NPL','Maithili','F',11.9);
+INSERT INTO CountryLanguage VALUES ('NIC','Miskito','F',1.6);
+INSERT INTO CountryLanguage VALUES ('NER','Songhai-zerma','F',21.2);
+INSERT INTO CountryLanguage VALUES ('NGA','Hausa','F',21.1);
+INSERT INTO CountryLanguage VALUES ('NIU','English','T',0.0);
+INSERT INTO CountryLanguage VALUES ('NOR','English','F',0.5);
+INSERT INTO CountryLanguage VALUES ('CIV','Gur','F',11.7);
+INSERT INTO CountryLanguage VALUES ('OMN','Balochi','F',0.0);
+INSERT INTO CountryLanguage VALUES ('PAK','Pashto','F',13.1);
+INSERT INTO CountryLanguage VALUES ('PLW','Philippene Languages','F',9.2);
+INSERT INTO CountryLanguage VALUES ('PAN','Creole English','F',14.0);
+INSERT INTO CountryLanguage VALUES ('PNG','Malenasian Languages','F',20.0);
+INSERT INTO CountryLanguage VALUES ('PRY','Guaraní','T',40.1);
+INSERT INTO CountryLanguage VALUES ('PER','Ketšua','T',16.4);
+INSERT INTO CountryLanguage VALUES ('MNP','Chamorro','F',30.0);
+INSERT INTO CountryLanguage VALUES ('PRI','English','F',47.4);
+INSERT INTO CountryLanguage VALUES ('POL','German','F',1.3);
+INSERT INTO CountryLanguage VALUES ('GNQ','Bubi','F',8.7);
+INSERT INTO CountryLanguage VALUES ('QAT','Urdu','F',0.0);
+INSERT INTO CountryLanguage VALUES ('FRA','Arabic','F',2.5);
+INSERT INTO CountryLanguage VALUES ('GUF','Indian Languages','F',1.9);
+INSERT INTO CountryLanguage VALUES ('PYF','French','T',40.8);
+INSERT INTO CountryLanguage VALUES ('REU','Chinese','F',2.8);
+INSERT INTO CountryLanguage VALUES ('ROM','Hungarian','F',7.2);
+INSERT INTO CountryLanguage VALUES ('RWA','French','T',0.0);
+INSERT INTO CountryLanguage VALUES ('SWE','Finnish','F',2.4);
+INSERT INTO CountryLanguage VALUES ('KNA','English','T',0.0);
+INSERT INTO CountryLanguage VALUES ('LCA','English','T',20.0);
+INSERT INTO CountryLanguage VALUES ('VCT','English','T',0.0);
+INSERT INTO CountryLanguage VALUES ('DEU','Turkish','F',2.6);
+INSERT INTO CountryLanguage VALUES ('SLB','Papuan Languages','F',8.6);
+INSERT INTO CountryLanguage VALUES ('ZMB','Tongan','F',11.0);
+INSERT INTO CountryLanguage VALUES ('WSM','Samoan','T',47.5);
+INSERT INTO CountryLanguage VALUES ('STP','French','F',0.7);
+INSERT INTO CountryLanguage VALUES ('SEN','Ful','F',21.7);
+INSERT INTO CountryLanguage VALUES ('SYC','English','T',3.8);
+INSERT INTO CountryLanguage VALUES ('SLE','Temne','F',31.8);
+INSERT INTO CountryLanguage VALUES ('SGP','Malay','T',14.1);
+INSERT INTO CountryLanguage VALUES ('SVK','Hungarian','F',10.5);
+INSERT INTO CountryLanguage VALUES ('SVN','Serbo-Croatian','F',7.9);
+INSERT INTO CountryLanguage VALUES ('SOM','Arabic','T',0.0);
+INSERT INTO CountryLanguage VALUES ('LKA','Tamil','T',19.6);
+INSERT INTO CountryLanguage VALUES ('SDN','Dinka','F',11.5);
+INSERT INTO CountryLanguage VALUES ('FIN','Swedish','T',5.7);
+INSERT INTO CountryLanguage VALUES ('SUR','Hindi','F',0.0);
+INSERT INTO CountryLanguage VALUES ('SWZ','Zulu','F',2.0);
+INSERT INTO CountryLanguage VALUES ('CHE','French','T',19.2);
+INSERT INTO CountryLanguage VALUES ('SYR','Kurdish','F',9.0);
+INSERT INTO CountryLanguage VALUES ('TJK','Uzbek','F',23.2);
+INSERT INTO CountryLanguage VALUES ('TWN','Mandarin Chinese','T',20.1);
+INSERT INTO CountryLanguage VALUES ('TZA','Swahili','T',8.8);
+INSERT INTO CountryLanguage VALUES ('DNK','Turkish','F',0.8);
+INSERT INTO CountryLanguage VALUES ('THA','Lao','F',26.9);
+INSERT INTO CountryLanguage VALUES ('TGO','Kabyé','T',13.8);
+INSERT INTO CountryLanguage VALUES ('TKL','English','T',0.0);
+INSERT INTO CountryLanguage VALUES ('TON','English','T',0.0);
+INSERT INTO CountryLanguage VALUES ('TTO','Hindi','F',3.4);
+INSERT INTO CountryLanguage VALUES ('TCD','Arabic','T',12.3);
+INSERT INTO CountryLanguage VALUES ('CZE','Moravian','F',12.9);
+INSERT INTO CountryLanguage VALUES ('TUN','Arabic-French','F',26.3);
+INSERT INTO CountryLanguage VALUES ('TUR','Kurdish','F',10.6);
+INSERT INTO CountryLanguage VALUES ('TKM','Uzbek','F',9.2);
+INSERT INTO CountryLanguage VALUES ('TUV','Kiribati','F',7.5);
+INSERT INTO CountryLanguage VALUES ('UGA','Nkole','F',10.7);
+INSERT INTO CountryLanguage VALUES ('UKR','Russian','F',32.9);
+INSERT INTO CountryLanguage VALUES ('HUN','Romani','F',0.5);
+INSERT INTO CountryLanguage VALUES ('NCL','French','T',34.3);
+INSERT INTO CountryLanguage VALUES ('NZL','Maori','F',4.3);
+INSERT INTO CountryLanguage VALUES ('UZB','Russian','F',10.9);
+INSERT INTO CountryLanguage VALUES ('BLR','Russian','T',32.0);
+INSERT INTO CountryLanguage VALUES ('WLF','Futuna','F',0.0);
+INSERT INTO CountryLanguage VALUES ('VUT','English','T',28.3);
+INSERT INTO CountryLanguage VALUES ('VEN','Goajiro','F',0.4);
+INSERT INTO CountryLanguage VALUES ('RUS','Tatar','F',3.2);
+INSERT INTO CountryLanguage VALUES ('VNM','Tho','F',1.8);
+INSERT INTO CountryLanguage VALUES ('EST','Russian','F',27.8);
+INSERT INTO CountryLanguage VALUES ('USA','Spanish','F',7.5);
+INSERT INTO CountryLanguage VALUES ('VIR','Spanish','F',13.3);
+INSERT INTO CountryLanguage VALUES ('ZWE','Ndebele','F',16.2);
+INSERT INTO CountryLanguage VALUES ('PSE','Hebrew','F',4.1);
+INSERT INTO CountryLanguage VALUES ('AFG','Uzbek','F',8.8);
+INSERT INTO CountryLanguage VALUES ('NLD','Arabic','F',0.9);
+INSERT INTO CountryLanguage VALUES ('ANT','Dutch','T',0.0);
+INSERT INTO CountryLanguage VALUES ('ALB','Macedonian','F',0.1);
+INSERT INTO CountryLanguage VALUES ('ASM','Tongan','F',3.1);
+INSERT INTO CountryLanguage VALUES ('AND','Portuguese','F',10.8);
+INSERT INTO CountryLanguage VALUES ('AGO','Kongo','F',13.2);
+INSERT INTO CountryLanguage VALUES ('ARG','Indian Languages','F',0.3);
+INSERT INTO CountryLanguage VALUES ('ABW','Spanish','F',7.4);
+INSERT INTO CountryLanguage VALUES ('AUS','Greek','F',1.6);
+INSERT INTO CountryLanguage VALUES ('AZE','Lezgian','F',2.3);
+INSERT INTO CountryLanguage VALUES ('BGD','Marma','F',0.2);
+INSERT INTO CountryLanguage VALUES ('BEL','Italian','F',2.4);
+INSERT INTO CountryLanguage VALUES ('BLZ','Maya Languages','F',9.6);
+INSERT INTO CountryLanguage VALUES ('BEN','Adja','F',11.1);
+INSERT INTO CountryLanguage VALUES ('BTN','Asami','F',15.2);
+INSERT INTO CountryLanguage VALUES ('BOL','Aimará','T',3.2);
+INSERT INTO CountryLanguage VALUES ('BWA','San','F',3.5);
+INSERT INTO CountryLanguage VALUES ('BRA','Italian','F',0.4);
+INSERT INTO CountryLanguage VALUES ('GBR','Gaeli','F',0.1);
+INSERT INTO CountryLanguage VALUES ('BRN','Chinese','F',9.3);
+INSERT INTO CountryLanguage VALUES ('BGR','Romani','F',3.7);
+INSERT INTO CountryLanguage VALUES ('BFA','Gurma','F',5.7);
+INSERT INTO CountryLanguage VALUES ('BDI','Swahili','F',0.0);
+INSERT INTO CountryLanguage VALUES ('CHL','Aimará','F',0.5);
+INSERT INTO CountryLanguage VALUES ('CRI','Chibcha','F',0.3);
+INSERT INTO CountryLanguage VALUES ('DJI','Arabic','T',10.6);
+INSERT INTO CountryLanguage VALUES ('ERI','Afar','F',4.3);
+INSERT INTO CountryLanguage VALUES ('ESP','Galecian','F',6.4);
+INSERT INTO CountryLanguage VALUES ('ZAF','Afrikaans','T',14.3);
+INSERT INTO CountryLanguage VALUES ('ETH','Tigrinja','F',7.2);
+INSERT INTO CountryLanguage VALUES ('PHL','Ilocano','F',9.3);
+INSERT INTO CountryLanguage VALUES ('GAB','Mpongwe','F',14.6);
+INSERT INTO CountryLanguage VALUES ('GMB','Wolof','F',12.6);
+INSERT INTO CountryLanguage VALUES ('GEO','Armenian','F',6.8);
+INSERT INTO CountryLanguage VALUES ('GHA','Ewe','F',11.9);
+INSERT INTO CountryLanguage VALUES ('GUM','Philippene Languages','F',19.7);
+INSERT INTO CountryLanguage VALUES ('GTM','Cakchiquel','F',8.9);
+INSERT INTO CountryLanguage VALUES ('GIN','Susu','F',11.0);
+INSERT INTO CountryLanguage VALUES ('GNB','Balante','F',14.6);
+INSERT INTO CountryLanguage VALUES ('GUY','Arawakan','F',1.4);
+INSERT INTO CountryLanguage VALUES ('HND','Creole English','F',0.2);
+INSERT INTO CountryLanguage VALUES ('HKG','Fukien','F',1.9);
+INSERT INTO CountryLanguage VALUES ('IDN','Malay','T',12.1);
+INSERT INTO CountryLanguage VALUES ('IND','Telugu','F',7.8);
+INSERT INTO CountryLanguage VALUES ('IRQ','Azerbaijani','F',1.7);
+INSERT INTO CountryLanguage VALUES ('IRN','Kurdish','F',9.1);
+INSERT INTO CountryLanguage VALUES ('ISR','Russian','F',8.9);
+INSERT INTO CountryLanguage VALUES ('ITA','Friuli','F',1.2);
+INSERT INTO CountryLanguage VALUES ('AUT','Turkish','F',1.5);
+INSERT INTO CountryLanguage VALUES ('JPN','Chinese','F',0.2);
+INSERT INTO CountryLanguage VALUES ('JOR','Armenian','F',1.0);
+INSERT INTO CountryLanguage VALUES ('YUG','Hungarian','F',3.4);
+INSERT INTO CountryLanguage VALUES ('KHM','Chinese','F',3.1);
+INSERT INTO CountryLanguage VALUES ('CMR','Duala','F',10.9);
+INSERT INTO CountryLanguage VALUES ('CAN','Chinese','F',2.5);
+INSERT INTO CountryLanguage VALUES ('KAZ','Ukrainian','F',5.0);
+INSERT INTO CountryLanguage VALUES ('KEN','Luo','F',12.8);
+INSERT INTO CountryLanguage VALUES ('CAF','Mandjia','F',14.8);
+INSERT INTO CountryLanguage VALUES ('CHN','Mantšu','F',0.9);
+INSERT INTO CountryLanguage VALUES ('KGZ','Uzbek','F',14.1);
+INSERT INTO CountryLanguage VALUES ('COL','Creole English','F',0.1);
+INSERT INTO CountryLanguage VALUES ('COM','Comorian-madagassi','F',5.5);
+INSERT INTO CountryLanguage VALUES ('COG','Mboshi','F',11.4);
+INSERT INTO CountryLanguage VALUES ('COD','Mongo','F',13.5);
+INSERT INTO CountryLanguage VALUES ('LAO','Thai','F',7.8);
+INSERT INTO CountryLanguage VALUES ('LVA','Belorussian','F',4.1);
+INSERT INTO CountryLanguage VALUES ('LSO','English','T',0.0);
+INSERT INTO CountryLanguage VALUES ('LBN','French','F',0.0);
+INSERT INTO CountryLanguage VALUES ('LBR','Grebo','F',8.9);
+INSERT INTO CountryLanguage VALUES ('LIE','Turkish','F',2.5);
+INSERT INTO CountryLanguage VALUES ('LTU','Polish','F',7.0);
+INSERT INTO CountryLanguage VALUES ('LUX','Italian','F',4.6);
+INSERT INTO CountryLanguage VALUES ('MAC','Mandarin Chinese','F',1.2);
+INSERT INTO CountryLanguage VALUES ('MKD','Turkish','F',4.0);
+INSERT INTO CountryLanguage VALUES ('MWI','Yao','F',13.2);
+INSERT INTO CountryLanguage VALUES ('MYS','Tamil','F',3.9);
+INSERT INTO CountryLanguage VALUES ('MLI','Senufo and Minianka','F',12.0);
+INSERT INTO CountryLanguage VALUES ('MRT','Tukulor','F',5.4);
+INSERT INTO CountryLanguage VALUES ('MUS','French','F',3.4);
+INSERT INTO CountryLanguage VALUES ('MYT','Malagasy','F',16.1);
+INSERT INTO CountryLanguage VALUES ('MEX','Yucatec','F',1.1);
+INSERT INTO CountryLanguage VALUES ('FSM','Mortlock','F',7.6);
+INSERT INTO CountryLanguage VALUES ('MDA','Ukrainian','F',8.6);
+INSERT INTO CountryLanguage VALUES ('MCO','Italian','F',16.1);
+INSERT INTO CountryLanguage VALUES ('MNG','Dorbet','F',2.7);
+INSERT INTO CountryLanguage VALUES ('MOZ','Sena','F',9.4);
+INSERT INTO CountryLanguage VALUES ('MMR','Karen','F',6.2);
+INSERT INTO CountryLanguage VALUES ('NAM','Kavango','F',9.7);
+INSERT INTO CountryLanguage VALUES ('NRU','Chinese','F',8.5);
+INSERT INTO CountryLanguage VALUES ('NPL','Bhojpuri','F',7.5);
+INSERT INTO CountryLanguage VALUES ('NIC','Creole English','F',0.5);
+INSERT INTO CountryLanguage VALUES ('NER','Tamashek','F',10.4);
+INSERT INTO CountryLanguage VALUES ('NGA','Ibo','F',18.1);
+INSERT INTO CountryLanguage VALUES ('NOR','Danish','F',0.4);
+INSERT INTO CountryLanguage VALUES ('CIV','Malinke','F',11.4);
+INSERT INTO CountryLanguage VALUES ('PAK','Sindhi','F',11.8);
+INSERT INTO CountryLanguage VALUES ('PLW','English','T',3.2);
+INSERT INTO CountryLanguage VALUES ('PAN','Guaymí','F',5.3);
+INSERT INTO CountryLanguage VALUES ('PRY','Portuguese','F',3.2);
+INSERT INTO CountryLanguage VALUES ('PER','Aimará','T',2.3);
+INSERT INTO CountryLanguage VALUES ('MNP','Chinese','F',7.1);
+INSERT INTO CountryLanguage VALUES ('POL','Ukrainian','F',0.6);
+INSERT INTO CountryLanguage VALUES ('FRA','Portuguese','F',1.2);
+INSERT INTO CountryLanguage VALUES ('PYF','Chinese','F',2.9);
+INSERT INTO CountryLanguage VALUES ('REU','Comorian','F',2.8);
+INSERT INTO CountryLanguage VALUES ('ROM','Romani','T',0.7);
+INSERT INTO CountryLanguage VALUES ('SWE','Southern Slavic Languages','F',1.3);
+INSERT INTO CountryLanguage VALUES ('DEU','Southern Slavic Languages','F',1.4);
+INSERT INTO CountryLanguage VALUES ('SLB','Polynesian Languages','F',3.8);
+INSERT INTO CountryLanguage VALUES ('ZMB','Nyanja','F',7.8);
+INSERT INTO CountryLanguage VALUES ('WSM','English','T',0.6);
+INSERT INTO CountryLanguage VALUES ('SEN','Serer','F',12.5);
+INSERT INTO CountryLanguage VALUES ('SYC','French','T',1.3);
+INSERT INTO CountryLanguage VALUES ('SLE','Limba','F',8.3);
+INSERT INTO CountryLanguage VALUES ('SGP','Tamil','T',7.4);
+INSERT INTO CountryLanguage VALUES ('SVK','Romani','F',1.7);
+INSERT INTO CountryLanguage VALUES ('SVN','Hungarian','F',0.5);
+INSERT INTO CountryLanguage VALUES ('LKA','Mixed Languages','F',19.6);
+INSERT INTO CountryLanguage VALUES ('SDN','Nubian Languages','F',8.1);
+INSERT INTO CountryLanguage VALUES ('FIN','Russian','F',0.4);
+INSERT INTO CountryLanguage VALUES ('CHE','Italian','T',7.7);
+INSERT INTO CountryLanguage VALUES ('TJK','Russian','F',9.7);
+INSERT INTO CountryLanguage VALUES ('TWN','Hakka','F',11.0);
+INSERT INTO CountryLanguage VALUES ('TZA','Hehet','F',6.9);
+INSERT INTO CountryLanguage VALUES ('DNK','Arabic','F',0.7);
+INSERT INTO CountryLanguage VALUES ('THA','Chinese','F',12.1);
+INSERT INTO CountryLanguage VALUES ('TGO','Watyi','F',10.3);
+INSERT INTO CountryLanguage VALUES ('TTO','Creole English','F',2.9);
+INSERT INTO CountryLanguage VALUES ('TCD','Mayo-kebbi','F',11.5);
+INSERT INTO CountryLanguage VALUES ('CZE','Slovak','F',3.1);
+INSERT INTO CountryLanguage VALUES ('TUN','Arabic-French-English','F',3.2);
+INSERT INTO CountryLanguage VALUES ('TUR','Arabic','F',1.4);
+INSERT INTO CountryLanguage VALUES ('TKM','Russian','F',6.7);
+INSERT INTO CountryLanguage VALUES ('TUV','English','T',0.0);
+INSERT INTO CountryLanguage VALUES ('UGA','Kiga','F',8.3);
+INSERT INTO CountryLanguage VALUES ('UKR','Romanian','F',0.7);
+INSERT INTO CountryLanguage VALUES ('HUN','German','F',0.4);
+INSERT INTO CountryLanguage VALUES ('NCL','Polynesian Languages','F',11.6);
+INSERT INTO CountryLanguage VALUES ('UZB','Tadzhik','F',4.4);
+INSERT INTO CountryLanguage VALUES ('BLR','Ukrainian','F',1.3);
+INSERT INTO CountryLanguage VALUES ('VUT','French','T',14.2);
+INSERT INTO CountryLanguage VALUES ('VEN','Warrau','F',0.1);
+INSERT INTO CountryLanguage VALUES ('RUS','Ukrainian','F',1.3);
+INSERT INTO CountryLanguage VALUES ('VNM','Thai','F',1.6);
+INSERT INTO CountryLanguage VALUES ('EST','Ukrainian','F',2.8);
+INSERT INTO CountryLanguage VALUES ('USA','French','F',0.7);
+INSERT INTO CountryLanguage VALUES ('VIR','French','F',2.5);
+INSERT INTO CountryLanguage VALUES ('ZWE','English','T',2.2);
+INSERT INTO CountryLanguage VALUES ('AFG','Turkmenian','F',1.9);
+INSERT INTO CountryLanguage VALUES ('NLD','Turkish','F',0.8);
+INSERT INTO CountryLanguage VALUES ('AND','French','F',6.2);
+INSERT INTO CountryLanguage VALUES ('AGO','Luimbe-nganguela','F',5.4);
+INSERT INTO CountryLanguage VALUES ('ABW','Dutch','T',5.3);
+INSERT INTO CountryLanguage VALUES ('AUS','Canton Chinese','F',1.1);
+INSERT INTO CountryLanguage VALUES ('AZE','Armenian','F',2.0);
+INSERT INTO CountryLanguage VALUES ('BGD','Garo','F',0.1);
+INSERT INTO CountryLanguage VALUES ('BEL','Arabic','F',1.6);
+INSERT INTO CountryLanguage VALUES ('BLZ','Garifuna','F',6.8);
+INSERT INTO CountryLanguage VALUES ('BEN','Aizo','F',8.7);
+INSERT INTO CountryLanguage VALUES ('BOL','Guaraní','F',0.1);
+INSERT INTO CountryLanguage VALUES ('BWA','Khoekhoe','F',2.5);
+INSERT INTO CountryLanguage VALUES ('BRA','Japanese','F',0.4);
+INSERT INTO CountryLanguage VALUES ('BRN','English','F',3.1);
+INSERT INTO CountryLanguage VALUES ('BGR','Macedonian','F',2.6);
+INSERT INTO CountryLanguage VALUES ('BFA','Busansi','F',3.5);
+INSERT INTO CountryLanguage VALUES ('CHL','Rapa nui','F',0.2);
+INSERT INTO CountryLanguage VALUES ('CRI','Chinese','F',0.2);
+INSERT INTO CountryLanguage VALUES ('ERI','Hadareb','F',3.8);
+INSERT INTO CountryLanguage VALUES ('ESP','Basque','F',1.6);
+INSERT INTO CountryLanguage VALUES ('ZAF','Northsotho','F',9.1);
+INSERT INTO CountryLanguage VALUES ('ETH','Gurage','F',4.7);
+INSERT INTO CountryLanguage VALUES ('PHL','Hiligaynon','F',9.1);
+INSERT INTO CountryLanguage VALUES ('GAB','Mbete','F',13.8);
+INSERT INTO CountryLanguage VALUES ('GMB','Diola','F',9.2);
+INSERT INTO CountryLanguage VALUES ('GEO','Azerbaijani','F',5.5);
+INSERT INTO CountryLanguage VALUES ('GHA','Ga-adangme','F',7.8);
+INSERT INTO CountryLanguage VALUES ('GUM','Korean','F',3.3);
+INSERT INTO CountryLanguage VALUES ('GTM','Kekchí','F',4.9);
+INSERT INTO CountryLanguage VALUES ('GIN','Kissi','F',6.0);
+INSERT INTO CountryLanguage VALUES ('GNB','Portuguese','T',8.1);
+INSERT INTO CountryLanguage VALUES ('HND','Miskito','F',0.2);
+INSERT INTO CountryLanguage VALUES ('HKG','Hakka','F',1.6);
+INSERT INTO CountryLanguage VALUES ('IDN','Madura','F',4.3);
+INSERT INTO CountryLanguage VALUES ('IND','Marathi','F',7.4);
+INSERT INTO CountryLanguage VALUES ('IRQ','Assyrian','F',0.8);
+INSERT INTO CountryLanguage VALUES ('IRN','Gilaki','F',5.3);
+INSERT INTO CountryLanguage VALUES ('ITA','French','F',0.5);
+INSERT INTO CountryLanguage VALUES ('AUT','Hungarian','F',0.4);
+INSERT INTO CountryLanguage VALUES ('JPN','English','F',0.1);
+INSERT INTO CountryLanguage VALUES ('YUG','Romani','F',1.4);
+INSERT INTO CountryLanguage VALUES ('KHM','Tšam','F',2.4);
+INSERT INTO CountryLanguage VALUES ('CMR','Ful','F',9.6);
+INSERT INTO CountryLanguage VALUES ('CAN','Italian','F',1.7);
+INSERT INTO CountryLanguage VALUES ('KAZ','German','F',3.1);
+INSERT INTO CountryLanguage VALUES ('KEN','Kamba','F',11.2);
+INSERT INTO CountryLanguage VALUES ('CAF','Ngbaka','F',7.5);
+INSERT INTO CountryLanguage VALUES ('CHN','Hui','F',0.8);
+INSERT INTO CountryLanguage VALUES ('KGZ','Ukrainian','F',1.7);
+INSERT INTO CountryLanguage VALUES ('COL','Arawakan','F',0.1);
+INSERT INTO CountryLanguage VALUES ('COM','Comorian-Arabic','F',1.6);
+INSERT INTO CountryLanguage VALUES ('COG','Mbete','F',4.8);
+INSERT INTO CountryLanguage VALUES ('COD','Rwanda','F',10.3);
+INSERT INTO CountryLanguage VALUES ('LAO','Lao-Soung','F',5.2);
+INSERT INTO CountryLanguage VALUES ('LVA','Ukrainian','F',2.9);
+INSERT INTO CountryLanguage VALUES ('LBR','Gio','F',7.9);
+INSERT INTO CountryLanguage VALUES ('LTU','Belorussian','F',1.4);
+INSERT INTO CountryLanguage VALUES ('LUX','French','T',4.2);
+INSERT INTO CountryLanguage VALUES ('MAC','English','F',0.5);
+INSERT INTO CountryLanguage VALUES ('MKD','Romani','F',2.3);
+INSERT INTO CountryLanguage VALUES ('MWI','Ngoni','F',6.7);
+INSERT INTO CountryLanguage VALUES ('MYS','Iban','F',2.8);
+INSERT INTO CountryLanguage VALUES ('MLI','Soninke','F',8.7);
+INSERT INTO CountryLanguage VALUES ('MRT','Soninke','F',2.7);
+INSERT INTO CountryLanguage VALUES ('MUS','Hindi','F',1.2);
+INSERT INTO CountryLanguage VALUES ('MEX','Zapotec','F',0.6);
+INSERT INTO CountryLanguage VALUES ('FSM','Kosrean','F',7.3);
+INSERT INTO CountryLanguage VALUES ('MDA','Gagauzi','F',3.2);
+INSERT INTO CountryLanguage VALUES ('MCO','English','F',6.5);
+INSERT INTO CountryLanguage VALUES ('MNG','Bajad','F',1.9);
+INSERT INTO CountryLanguage VALUES ('MOZ','Lomwe','F',7.8);
+INSERT INTO CountryLanguage VALUES ('MMR','Rakhine','F',4.5);
+INSERT INTO CountryLanguage VALUES ('NAM','Afrikaans','F',9.5);
+INSERT INTO CountryLanguage VALUES ('NRU','Tuvalu','F',8.5);
+INSERT INTO CountryLanguage VALUES ('NPL','Tharu','F',5.4);
+INSERT INTO CountryLanguage VALUES ('NIC','Sumo','F',0.2);
+INSERT INTO CountryLanguage VALUES ('NER','Ful','F',9.7);
+INSERT INTO CountryLanguage VALUES ('NGA','Ful','F',11.3);
+INSERT INTO CountryLanguage VALUES ('NOR','Swedish','F',0.3);
+INSERT INTO CountryLanguage VALUES ('CIV','Kru','F',10.5);
+INSERT INTO CountryLanguage VALUES ('PAK','Saraiki','F',9.8);
+INSERT INTO CountryLanguage VALUES ('PLW','Chinese','F',1.6);
+INSERT INTO CountryLanguage VALUES ('PAN','Cuna','F',2.0);
+INSERT INTO CountryLanguage VALUES ('PRY','German','F',0.9);
+INSERT INTO CountryLanguage VALUES ('MNP','Korean','F',6.5);
+INSERT INTO CountryLanguage VALUES ('POL','Belorussian','F',0.5);
+INSERT INTO CountryLanguage VALUES ('FRA','Italian','F',0.4);
+INSERT INTO CountryLanguage VALUES ('REU','Malagasy','F',1.4);
+INSERT INTO CountryLanguage VALUES ('ROM','German','F',0.4);
+INSERT INTO CountryLanguage VALUES ('SWE','Arabic','F',0.8);
+INSERT INTO CountryLanguage VALUES ('DEU','Italian','F',0.7);
+INSERT INTO CountryLanguage VALUES ('ZMB','Lozi','F',6.4);
+INSERT INTO CountryLanguage VALUES ('SEN','Diola','F',5.0);
+INSERT INTO CountryLanguage VALUES ('SLE','Kono-vai','F',5.1);
+INSERT INTO CountryLanguage VALUES ('SVK','Czech and Moravian','F',1.1);
+INSERT INTO CountryLanguage VALUES ('SDN','Beja','F',6.4);
+INSERT INTO CountryLanguage VALUES ('FIN','Estonian','F',0.2);
+INSERT INTO CountryLanguage VALUES ('CHE','Romansh','T',0.6);
+INSERT INTO CountryLanguage VALUES ('TWN','Ami','F',0.6);
+INSERT INTO CountryLanguage VALUES ('TZA','Haya','F',5.9);
+INSERT INTO CountryLanguage VALUES ('DNK','German','F',0.5);
+INSERT INTO CountryLanguage VALUES ('THA','Malay','F',3.6);
+INSERT INTO CountryLanguage VALUES ('TGO','Kotokoli','F',5.7);
+INSERT INTO CountryLanguage VALUES ('TCD','Kanem-bornu','F',9.0);
+INSERT INTO CountryLanguage VALUES ('CZE','Polish','F',0.6);
+INSERT INTO CountryLanguage VALUES ('TKM','Kazakh','F',2.0);
+INSERT INTO CountryLanguage VALUES ('UGA','Soga','F',8.2);
+INSERT INTO CountryLanguage VALUES ('UKR','Bulgariana','F',0.3);
+INSERT INTO CountryLanguage VALUES ('HUN','Serbo-Croatian','F',0.2);
+INSERT INTO CountryLanguage VALUES ('UZB','Kazakh','F',3.8);
+INSERT INTO CountryLanguage VALUES ('BLR','Polish','F',0.6);
+INSERT INTO CountryLanguage VALUES ('RUS','Chuvash','F',0.9);
+INSERT INTO CountryLanguage VALUES ('VNM','Muong','F',1.5);
+INSERT INTO CountryLanguage VALUES ('EST','Belorussian','F',1.4);
+INSERT INTO CountryLanguage VALUES ('USA','German','F',0.7);
+INSERT INTO CountryLanguage VALUES ('ZWE','Nyanja','F',2.2);
+INSERT INTO CountryLanguage VALUES ('AFG','Balochi','F',0.9);
+INSERT INTO CountryLanguage VALUES ('AGO','Nyaneka-nkhumbi','F',5.4);
+INSERT INTO CountryLanguage VALUES ('AUS','Arabic','F',1.0);
+INSERT INTO CountryLanguage VALUES ('BGD','Khasi','F',0.1);
+INSERT INTO CountryLanguage VALUES ('BEL','German','T',1.0);
+INSERT INTO CountryLanguage VALUES ('BEN','Bariba','F',8.7);
+INSERT INTO CountryLanguage VALUES ('BWA','Ndebele','F',1.3);
+INSERT INTO CountryLanguage VALUES ('BRA','Indian Languages','F',0.2);
+INSERT INTO CountryLanguage VALUES ('BFA','Dagara','F',3.1);
+INSERT INTO CountryLanguage VALUES ('ERI','Bilin','F',3.0);
+INSERT INTO CountryLanguage VALUES ('ZAF','English','T',8.5);
+INSERT INTO CountryLanguage VALUES ('ETH','Somali','F',4.1);
+INSERT INTO CountryLanguage VALUES ('PHL','Bicol','F',5.7);
+INSERT INTO CountryLanguage VALUES ('GMB','Soninke','F',7.6);
+INSERT INTO CountryLanguage VALUES ('GEO','Osseetti','F',2.4);
+INSERT INTO CountryLanguage VALUES ('GHA','Gurma','F',3.3);
+INSERT INTO CountryLanguage VALUES ('GUM','Japanese','F',2.0);
+INSERT INTO CountryLanguage VALUES ('GTM','Mam','F',2.7);
+INSERT INTO CountryLanguage VALUES ('GIN','Kpelle','F',4.6);
+INSERT INTO CountryLanguage VALUES ('GNB','Malinke','F',6.9);
+INSERT INTO CountryLanguage VALUES ('HKG','Chiu chau','F',1.4);
+INSERT INTO CountryLanguage VALUES ('IDN','Minangkabau','F',2.4);
+INSERT INTO CountryLanguage VALUES ('IND','Tamil','F',6.3);
+INSERT INTO CountryLanguage VALUES ('IRQ','Persian','F',0.8);
+INSERT INTO CountryLanguage VALUES ('IRN','Luri','F',4.3);
+INSERT INTO CountryLanguage VALUES ('ITA','German','F',0.5);
+INSERT INTO CountryLanguage VALUES ('AUT','Slovene','F',0.4);
+INSERT INTO CountryLanguage VALUES ('JPN','Philippene Languages','F',0.1);
+INSERT INTO CountryLanguage VALUES ('YUG','Slovak','F',0.7);
+INSERT INTO CountryLanguage VALUES ('CMR','Tikar','F',7.4);
+INSERT INTO CountryLanguage VALUES ('CAN','German','F',1.6);
+INSERT INTO CountryLanguage VALUES ('KAZ','Uzbek','F',2.3);
+INSERT INTO CountryLanguage VALUES ('KEN','Kalenjin','F',10.8);
+INSERT INTO CountryLanguage VALUES ('CAF','Sara','F',6.4);
+INSERT INTO CountryLanguage VALUES ('CHN','Miao','F',0.7);
+INSERT INTO CountryLanguage VALUES ('KGZ','Tatar','F',1.3);
+INSERT INTO CountryLanguage VALUES ('COL','Caribbean','F',0.1);
+INSERT INTO CountryLanguage VALUES ('COM','Comorian-Swahili','F',0.5);
+INSERT INTO CountryLanguage VALUES ('COG','Punu','F',2.9);
+INSERT INTO CountryLanguage VALUES ('COD','Zande','F',6.1);
+INSERT INTO CountryLanguage VALUES ('LVA','Polish','F',2.1);
+INSERT INTO CountryLanguage VALUES ('LBR','Kru','F',7.2);
+INSERT INTO CountryLanguage VALUES ('LTU','Ukrainian','F',1.1);
+INSERT INTO CountryLanguage VALUES ('LUX','German','T',2.3);
+INSERT INTO CountryLanguage VALUES ('MKD','Serbo-Croatian','F',2.0);
+INSERT INTO CountryLanguage VALUES ('MYS','English','F',1.6);
+INSERT INTO CountryLanguage VALUES ('MLI','Tamashek','F',7.3);
+INSERT INTO CountryLanguage VALUES ('MRT','Ful','F',1.2);
+INSERT INTO CountryLanguage VALUES ('MUS','Tamil','F',0.8);
+INSERT INTO CountryLanguage VALUES ('MEX','Mixtec','F',0.6);
+INSERT INTO CountryLanguage VALUES ('FSM','Yap','F',5.8);
+INSERT INTO CountryLanguage VALUES ('MDA','Bulgariana','F',1.6);
+INSERT INTO CountryLanguage VALUES ('MNG','Buryat','F',1.7);
+INSERT INTO CountryLanguage VALUES ('MOZ','Shona','F',6.5);
+INSERT INTO CountryLanguage VALUES ('MMR','Mon','F',2.4);
+INSERT INTO CountryLanguage VALUES ('NAM','Herero','F',8.0);
+INSERT INTO CountryLanguage VALUES ('NRU','English','T',7.5);
+INSERT INTO CountryLanguage VALUES ('NPL','Tamang','F',4.9);
+INSERT INTO CountryLanguage VALUES ('NER','Kanuri','F',4.4);
+INSERT INTO CountryLanguage VALUES ('NGA','Ibibio','F',5.6);
+INSERT INTO CountryLanguage VALUES ('NOR','Saame','F',0.0);
+INSERT INTO CountryLanguage VALUES ('CIV','[South]Mande','F',7.7);
+INSERT INTO CountryLanguage VALUES ('PAK','Urdu','T',7.6);
+INSERT INTO CountryLanguage VALUES ('PAN','Embera','F',0.6);
+INSERT INTO CountryLanguage VALUES ('MNP','English','T',4.8);
+INSERT INTO CountryLanguage VALUES ('FRA','Spanish','F',0.4);
+INSERT INTO CountryLanguage VALUES ('REU','Tamil','F',0.0);
+INSERT INTO CountryLanguage VALUES ('ROM','Ukrainian','F',0.3);
+INSERT INTO CountryLanguage VALUES ('SWE','Spanish','F',0.6);
+INSERT INTO CountryLanguage VALUES ('DEU','Greek','F',0.4);
+INSERT INTO CountryLanguage VALUES ('ZMB','Chewa','F',5.7);
+INSERT INTO CountryLanguage VALUES ('SEN','Malinke','F',3.8);
+INSERT INTO CountryLanguage VALUES ('SLE','Bullom-sherbro','F',3.8);
+INSERT INTO CountryLanguage VALUES ('SVK','Ukrainian and Russian','F',0.6);
+INSERT INTO CountryLanguage VALUES ('SDN','Nuer','F',4.9);
+INSERT INTO CountryLanguage VALUES ('FIN','Saame','F',0.0);
+INSERT INTO CountryLanguage VALUES ('TWN','Atayal','F',0.4);
+INSERT INTO CountryLanguage VALUES ('TZA','Makonde','F',5.9);
+INSERT INTO CountryLanguage VALUES ('DNK','English','F',0.3);
+INSERT INTO CountryLanguage VALUES ('THA','Khmer','F',1.3);
+INSERT INTO CountryLanguage VALUES ('TGO','Ane','F',5.7);
+INSERT INTO CountryLanguage VALUES ('TCD','Ouaddai','F',8.7);
+INSERT INTO CountryLanguage VALUES ('CZE','German','F',0.5);
+INSERT INTO CountryLanguage VALUES ('UGA','Teso','F',6.0);
+INSERT INTO CountryLanguage VALUES ('UKR','Hungarian','F',0.3);
+INSERT INTO CountryLanguage VALUES ('HUN','Romanian','F',0.1);
+INSERT INTO CountryLanguage VALUES ('UZB','Karakalpak','F',2.0);
+INSERT INTO CountryLanguage VALUES ('RUS','Bashkir','F',0.7);
+INSERT INTO CountryLanguage VALUES ('VNM','Chinese','F',1.4);
+INSERT INTO CountryLanguage VALUES ('EST','Finnish','F',0.7);
+INSERT INTO CountryLanguage VALUES ('USA','Italian','F',0.6);
+INSERT INTO CountryLanguage VALUES ('AGO','Chokwe','F',4.2);
+INSERT INTO CountryLanguage VALUES ('AUS','Vietnamese','F',0.8);
+INSERT INTO CountryLanguage VALUES ('BGD','Santhali','F',0.1);
+INSERT INTO CountryLanguage VALUES ('BEL','Turkish','F',0.9);
+INSERT INTO CountryLanguage VALUES ('BEN','Somba','F',6.7);
+INSERT INTO CountryLanguage VALUES ('BFA','Dyula','F',2.6);
+INSERT INTO CountryLanguage VALUES ('ERI','Saho','F',3.0);
+INSERT INTO CountryLanguage VALUES ('ZAF','Tswana','F',8.1);
+INSERT INTO CountryLanguage VALUES ('ETH','Sidamo','F',3.2);
+INSERT INTO CountryLanguage VALUES ('PHL','Waray-waray','F',3.8);
+INSERT INTO CountryLanguage VALUES ('GEO','Abhyasi','F',1.7);
+INSERT INTO CountryLanguage VALUES ('GHA','Joruba','F',1.3);
+INSERT INTO CountryLanguage VALUES ('GIN','Yalunka','F',2.9);
+INSERT INTO CountryLanguage VALUES ('GNB','Mandyako','F',4.9);
+INSERT INTO CountryLanguage VALUES ('IDN','Batakki','F',2.2);
+INSERT INTO CountryLanguage VALUES ('IND','Urdu','F',5.1);
+INSERT INTO CountryLanguage VALUES ('IRN','Mazandarani','F',3.6);
+INSERT INTO CountryLanguage VALUES ('ITA','Albaniana','F',0.2);
+INSERT INTO CountryLanguage VALUES ('AUT','Polish','F',0.2);
+INSERT INTO CountryLanguage VALUES ('JPN','Ainu','F',0.0);
+INSERT INTO CountryLanguage VALUES ('YUG','Macedonian','F',0.5);
+INSERT INTO CountryLanguage VALUES ('CMR','Mandara','F',5.7);
+INSERT INTO CountryLanguage VALUES ('CAN','Polish','F',0.7);
+INSERT INTO CountryLanguage VALUES ('KAZ','Tatar','F',2.0);
+INSERT INTO CountryLanguage VALUES ('KEN','Gusii','F',6.1);
+INSERT INTO CountryLanguage VALUES ('CAF','Mbum','F',6.4);
+INSERT INTO CountryLanguage VALUES ('CHN','Uighur','F',0.6);
+INSERT INTO CountryLanguage VALUES ('KGZ','Kazakh','F',0.8);
+INSERT INTO CountryLanguage VALUES ('COG','Sango','F',2.6);
+INSERT INTO CountryLanguage VALUES ('COD','Ngala and Bangi','F',5.8);
+INSERT INTO CountryLanguage VALUES ('LVA','Lithuanian','F',1.2);
+INSERT INTO CountryLanguage VALUES ('LBR','Mano','F',7.2);
+INSERT INTO CountryLanguage VALUES ('MYS','Dusun','F',1.1);
+INSERT INTO CountryLanguage VALUES ('MLI','Songhai','F',6.9);
+INSERT INTO CountryLanguage VALUES ('MRT','Zenaga','F',1.2);
+INSERT INTO CountryLanguage VALUES ('MUS','Marathi','F',0.7);
+INSERT INTO CountryLanguage VALUES ('MEX','Otomí','F',0.4);
+INSERT INTO CountryLanguage VALUES ('FSM','Wolea','F',3.7);
+INSERT INTO CountryLanguage VALUES ('MNG','Dariganga','F',1.4);
+INSERT INTO CountryLanguage VALUES ('MOZ','Tswa','F',6.0);
+INSERT INTO CountryLanguage VALUES ('MMR','Chin','F',2.2);
+INSERT INTO CountryLanguage VALUES ('NAM','Caprivi','F',4.7);
+INSERT INTO CountryLanguage VALUES ('NPL','Newari','F',3.7);
+INSERT INTO CountryLanguage VALUES ('NGA','Kanuri','F',4.1);
+INSERT INTO CountryLanguage VALUES ('PAK','Balochi','F',3.0);
+INSERT INTO CountryLanguage VALUES ('PAN','Arabic','F',0.6);
+INSERT INTO CountryLanguage VALUES ('MNP','Carolinian','F',4.8);
+INSERT INTO CountryLanguage VALUES ('FRA','Turkish','F',0.4);
+INSERT INTO CountryLanguage VALUES ('ROM','Serbo-Croatian','F',0.1);
+INSERT INTO CountryLanguage VALUES ('SWE','Norwegian','F',0.5);
+INSERT INTO CountryLanguage VALUES ('DEU','Polish','F',0.3);
+INSERT INTO CountryLanguage VALUES ('ZMB','Nsenga','F',4.3);
+INSERT INTO CountryLanguage VALUES ('SEN','Soninke','F',1.3);
+INSERT INTO CountryLanguage VALUES ('SLE','Ful','F',3.8);
+INSERT INTO CountryLanguage VALUES ('SDN','Zande','F',2.7);
+INSERT INTO CountryLanguage VALUES ('TWN','Paiwan','F',0.3);
+INSERT INTO CountryLanguage VALUES ('TZA','Nyakusa','F',5.4);
+INSERT INTO CountryLanguage VALUES ('DNK','Swedish','F',0.3);
+INSERT INTO CountryLanguage VALUES ('THA','Kuy','F',1.1);
+INSERT INTO CountryLanguage VALUES ('TGO','Moba','F',5.4);
+INSERT INTO CountryLanguage VALUES ('TCD','Hadjarai','F',6.7);
+INSERT INTO CountryLanguage VALUES ('CZE','Silesiana','F',0.4);
+INSERT INTO CountryLanguage VALUES ('UGA','Lango','F',5.9);
+INSERT INTO CountryLanguage VALUES ('UKR','Belorussian','F',0.3);
+INSERT INTO CountryLanguage VALUES ('HUN','Slovak','F',0.1);
+INSERT INTO CountryLanguage VALUES ('UZB','Tatar','F',1.8);
+INSERT INTO CountryLanguage VALUES ('RUS','Chechen','F',0.6);
+INSERT INTO CountryLanguage VALUES ('VNM','Khmer','F',1.4);
+INSERT INTO CountryLanguage VALUES ('USA','Chinese','F',0.6);
+INSERT INTO CountryLanguage VALUES ('AGO','Luvale','F',3.6);
+INSERT INTO CountryLanguage VALUES ('AUS','Serbo-Croatian','F',0.6);
+INSERT INTO CountryLanguage VALUES ('BGD','Tripuri','F',0.1);
+INSERT INTO CountryLanguage VALUES ('BEN','Ful','F',5.6);
+INSERT INTO CountryLanguage VALUES ('ZAF','Southsotho','F',7.6);
+INSERT INTO CountryLanguage VALUES ('ETH','Walaita','F',2.8);
+INSERT INTO CountryLanguage VALUES ('PHL','Pampango','F',3.0);
+INSERT INTO CountryLanguage VALUES ('GIN','Loma','F',2.3);
+INSERT INTO CountryLanguage VALUES ('IDN','Bugi','F',2.2);
+INSERT INTO CountryLanguage VALUES ('IND','Gujarati','F',4.8);
+INSERT INTO CountryLanguage VALUES ('IRN','Balochi','F',2.3);
+INSERT INTO CountryLanguage VALUES ('ITA','Slovene','F',0.2);
+INSERT INTO CountryLanguage VALUES ('AUT','Czech','F',0.2);
+INSERT INTO CountryLanguage VALUES ('CMR','Maka','F',4.9);
+INSERT INTO CountryLanguage VALUES ('CAN','Spanish','F',0.7);
+INSERT INTO CountryLanguage VALUES ('KEN','Meru','F',5.5);
+INSERT INTO CountryLanguage VALUES ('CHN','Yi','F',0.6);
+INSERT INTO CountryLanguage VALUES ('KGZ','Tadzhik','F',0.8);
+INSERT INTO CountryLanguage VALUES ('COD','Rundi','F',3.8);
+INSERT INTO CountryLanguage VALUES ('LBR','Loma','F',5.8);
+INSERT INTO CountryLanguage VALUES ('MOZ','Chuabo','F',5.7);
+INSERT INTO CountryLanguage VALUES ('MMR','Kachin','F',1.4);
+INSERT INTO CountryLanguage VALUES ('NAM','San','F',1.9);
+INSERT INTO CountryLanguage VALUES ('NPL','Hindi','F',3.0);
+INSERT INTO CountryLanguage VALUES ('NGA','Edo','F',3.3);
+INSERT INTO CountryLanguage VALUES ('PAK','Hindko','F',2.4);
+INSERT INTO CountryLanguage VALUES ('SLE','Kuranko','F',3.4);
+INSERT INTO CountryLanguage VALUES ('SDN','Bari','F',2.5);
+INSERT INTO CountryLanguage VALUES ('TZA','Chaga and Pare','F',4.9);
+INSERT INTO CountryLanguage VALUES ('DNK','Norwegian','F',0.3);
+INSERT INTO CountryLanguage VALUES ('TGO','Naudemba','F',4.1);
+INSERT INTO CountryLanguage VALUES ('TCD','Tandjile','F',6.5);
+INSERT INTO CountryLanguage VALUES ('CZE','Romani','F',0.3);
+INSERT INTO CountryLanguage VALUES ('UGA','Lugbara','F',4.7);
+INSERT INTO CountryLanguage VALUES ('UKR','Polish','F',0.1);
+INSERT INTO CountryLanguage VALUES ('RUS','Mordva','F',0.5);
+INSERT INTO CountryLanguage VALUES ('VNM','Nung','F',1.1);
+INSERT INTO CountryLanguage VALUES ('USA','Tagalog','F',0.4);
+INSERT INTO CountryLanguage VALUES ('AGO','Ambo','F',2.4);
+INSERT INTO CountryLanguage VALUES ('AUS','German','F',0.6);
+INSERT INTO CountryLanguage VALUES ('ZAF','Tsonga','F',4.3);
+INSERT INTO CountryLanguage VALUES ('PHL','Pangasinan','F',1.8);
+INSERT INTO CountryLanguage VALUES ('IDN','Banja','F',1.8);
+INSERT INTO CountryLanguage VALUES ('IND','Kannada','F',3.9);
+INSERT INTO CountryLanguage VALUES ('IRN','Arabic','F',2.2);
+INSERT INTO CountryLanguage VALUES ('ITA','Romani','F',0.2);
+INSERT INTO CountryLanguage VALUES ('AUT','Romanian','F',0.2);
+INSERT INTO CountryLanguage VALUES ('CMR','Masana','F',3.9);
+INSERT INTO CountryLanguage VALUES ('CAN','Portuguese','F',0.7);
+INSERT INTO CountryLanguage VALUES ('KEN','Nyika','F',4.8);
+INSERT INTO CountryLanguage VALUES ('CHN','Tujia','F',0.5);
+INSERT INTO CountryLanguage VALUES ('COD','Teke','F',2.7);
+INSERT INTO CountryLanguage VALUES ('LBR','Malinke','F',5.1);
+INSERT INTO CountryLanguage VALUES ('MOZ','Ronga','F',3.7);
+INSERT INTO CountryLanguage VALUES ('MMR','Kayah','F',0.4);
+INSERT INTO CountryLanguage VALUES ('NAM','German','F',0.9);
+INSERT INTO CountryLanguage VALUES ('NGA','Tiv','F',2.3);
+INSERT INTO CountryLanguage VALUES ('PAK','Brahui','F',1.2);
+INSERT INTO CountryLanguage VALUES ('SLE','Yalunka','F',3.4);
+INSERT INTO CountryLanguage VALUES ('SDN','Fur','F',2.1);
+INSERT INTO CountryLanguage VALUES ('TZA','Luguru','F',4.9);
+INSERT INTO CountryLanguage VALUES ('TGO','Gurma','F',3.4);
+INSERT INTO CountryLanguage VALUES ('TCD','Gorane','F',6.2);
+INSERT INTO CountryLanguage VALUES ('CZE','Hungarian','F',0.2);
+INSERT INTO CountryLanguage VALUES ('UGA','Gisu','F',4.5);
+INSERT INTO CountryLanguage VALUES ('RUS','Kazakh','F',0.4);
+INSERT INTO CountryLanguage VALUES ('VNM','Miao','F',0.9);
+INSERT INTO CountryLanguage VALUES ('USA','Polish','F',0.3);
+INSERT INTO CountryLanguage VALUES ('AGO','Luchazi','F',2.4);
+INSERT INTO CountryLanguage VALUES ('ZAF','Swazi','F',2.5);
+INSERT INTO CountryLanguage VALUES ('PHL','Maguindanao','F',1.4);
+INSERT INTO CountryLanguage VALUES ('IDN','Bali','F',1.7);
+INSERT INTO CountryLanguage VALUES ('IND','Malajalam','F',3.6);
+INSERT INTO CountryLanguage VALUES ('IRN','Bakhtyari','F',1.7);
+INSERT INTO CountryLanguage VALUES ('CAN','Punjabi','F',0.7);
+INSERT INTO CountryLanguage VALUES ('KEN','Masai','F',1.6);
+INSERT INTO CountryLanguage VALUES ('CHN','Mongolian','F',0.4);
+INSERT INTO CountryLanguage VALUES ('COD','Boa','F',2.3);
+INSERT INTO CountryLanguage VALUES ('MOZ','Marendje','F',3.5);
+INSERT INTO CountryLanguage VALUES ('NGA','Ijo','F',1.8);
+INSERT INTO CountryLanguage VALUES ('SDN','Chilluk','F',1.7);
+INSERT INTO CountryLanguage VALUES ('TZA','Shambala','F',4.3);
+INSERT INTO CountryLanguage VALUES ('UGA','Acholi','F',4.4);
+INSERT INTO CountryLanguage VALUES ('RUS','Avarian','F',0.4);
+INSERT INTO CountryLanguage VALUES ('VNM','Man','F',0.7);
+INSERT INTO CountryLanguage VALUES ('USA','Korean','F',0.3);
+INSERT INTO CountryLanguage VALUES ('ZAF','Venda','F',2.2);
+INSERT INTO CountryLanguage VALUES ('PHL','Maranao','F',1.3);
+INSERT INTO CountryLanguage VALUES ('IND','Orija','F',3.3);
+INSERT INTO CountryLanguage VALUES ('IRN','Turkmenian','F',1.6);
+INSERT INTO CountryLanguage VALUES ('CAN','Ukrainian','F',0.6);
+INSERT INTO CountryLanguage VALUES ('KEN','Turkana','F',1.4);
+INSERT INTO CountryLanguage VALUES ('CHN','Tibetan','F',0.4);
+INSERT INTO CountryLanguage VALUES ('COD','Chokwe','F',1.8);
+INSERT INTO CountryLanguage VALUES ('MOZ','Nyanja','F',3.3);
+INSERT INTO CountryLanguage VALUES ('NGA','Bura','F',1.6);
+INSERT INTO CountryLanguage VALUES ('SDN','Lotuko','F',1.5);
+INSERT INTO CountryLanguage VALUES ('TZA','Gogo','F',3.9);
+INSERT INTO CountryLanguage VALUES ('UGA','Rwanda','F',3.2);
+INSERT INTO CountryLanguage VALUES ('RUS','Mari','F',0.4);
+INSERT INTO CountryLanguage VALUES ('USA','Vietnamese','F',0.2);
+INSERT INTO CountryLanguage VALUES ('ZAF','Ndebele','F',1.5);
+INSERT INTO CountryLanguage VALUES ('IND','Punjabi','F',2.8);
+INSERT INTO CountryLanguage VALUES ('CAN','Dutch','F',0.5);
+INSERT INTO CountryLanguage VALUES ('CHN','Puyi','F',0.2);
+INSERT INTO CountryLanguage VALUES ('TZA','Ha','F',3.5);
+INSERT INTO CountryLanguage VALUES ('RUS','Udmur','F',0.3);
+INSERT INTO CountryLanguage VALUES ('USA','Japanese','F',0.2);
+INSERT INTO CountryLanguage VALUES ('IND','Asami','F',1.5);
+INSERT INTO CountryLanguage VALUES ('CAN','Eskimo Languages','F',0.1);
+INSERT INTO CountryLanguage VALUES ('CHN','Dong','F',0.2);
+INSERT INTO CountryLanguage VALUES ('RUS','Belorussian','F',0.3);
+INSERT INTO CountryLanguage VALUES ('USA','Portuguese','F',0.2);
+
+/*!40000 ALTER TABLE CountryLanguage ENABLE KEYS */;
+
diff --git a/Makefile.am b/Makefile.am
index 22e066ac9d4..8cb67521a4a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -22,15 +22,21 @@ TAR = gtar
EXTRA_DIST = INSTALL-SOURCE README \
COPYING COPYING.LIB MIRRORS
SUBDIRS = include @docs_dirs@ @readline_dir@ \
- @thread_dirs@ @sql_client_dirs@ \
- @sql_server_dirs@ scripts tests man \
- @bench_dirs@ support-files
+ @thread_dirs@ pstack @sql_client_dirs@ \
+ @sql_server_dirs@ @libmysqld_dirs@ scripts man \
+ tests BUILD \
+ @bench_dirs@ support-files @fs_dirs@ @tools_dirs@
# Relink after clean
-CLEANFILES = linked_client_sources linked_server_sources linked_libmysql_sources linked_libmysql_r_sources linked_include_sources
+linked_sources = linked_client_sources linked_server_sources \
+ linked_libmysql_sources linked_libmysql_r_sources \
+ linked_libmysqld_sources linked_libmysqldex_sources \
+ linked_include_sources
+
+CLEANFILES = $(linked_sources)
# This is just so that the linking is done early.
-config.h: linked_include_sources linked_client_sources linked_server_sources linked_libmysql_sources linked_libmysql_r_sources
+config.h: $(linked_sources)
linked_include_sources:
cd include; $(MAKE) link_sources
@@ -48,6 +54,14 @@ linked_libmysql_r_sources: linked_libmysql_sources
cd libmysql_r; $(MAKE) link_sources
echo timestamp > linked_libmysql_r_sources
+linked_libmysqld_sources:
+ cd libmysqld; $(MAKE) link_sources
+ echo timestamp > linked_libmysqld_sources
+
+linked_libmysqldex_sources:
+ cd libmysqld/examples; $(MAKE) link_sources
+ echo timestamp > linked_libmysqldex_sources
+
#avoid recursive make calls in sql directory
linked_server_sources:
cd sql; rm -f mini_client_errors.c;@LN_CP_F@ ../libmysql/errmsg.c mini_client_errors.c
@@ -60,9 +74,12 @@ init-db: all
bin-dist: all
$(top_builddir)/scripts/make_binary_distribution
+tags:
+ support-files/build-tags
.PHONY: init-db bin-dist
# Test installation
test:
cd mysql-test ; ./mysql-test-run
+
diff --git a/SSL/NOTES b/SSL/NOTES
new file mode 100644
index 00000000000..413c724c583
--- /dev/null
+++ b/SSL/NOTES
@@ -0,0 +1,376 @@
+Quick notes:
+--------------------------------------------
+[tonu@x153 mysql-4.0]$ cat /etc/my.cnf
+[mysqld]
+ssl-ca=SSL/cacert.pem
+ssl-cert=SSL/server-cert.pem
+ssl-key=SSL/server-key.pem
+
+[mysql]
+ssl-ca=SSL/cacert.pem
+ssl-cert=SSL/client-cert.pem
+ssl-key=SSL/client-key.pem
+
+[mysqldump]
+ssl-ca=SSL/cacert.pem
+ssl-cert=SSL/client-cert.pem
+ssl-key=SSL/client-key.pem
+
+[tonu@x153 mysql-4.0]$
+--------------------------------------------
+To remove passwords from keyfiles:
+[tonu@x153 SSL]$ openssl rsa -inform pem < server-req.pem > server-key.pem
+read RSA key
+Enter PEM pass phrase:
+writing RSA key
+[tonu@x153 SSL]$
+--------------------------------------------
+To run server:
+
+sql/mysqld --ssl-ca=SSL/cacert.pem --ssl-cert=SSL/server-cert.pem --ssl-key=SSL/server-key.pem --skip-grant --debug='d:t:O,-' > /tmp/mysqld.trace
+--------------------------------------------
+To run client:
+
+client/mysql --ssl-ca=SSL/cacert.pem --ssl-cert=SSL/server-cert.pem --ssl-key=SSL/server-key.pem --debug='d:t:O,/tmp/client.trace' -h 127.0.0.1
+--------------------------------------------
+openssl s_client -host 127.0.0.1 -port 1111 -debug -verify 1 -cert ../SSL/client-cert.pem -key ../SSL/client-key.pem -CAfile ../SSL/cacert.pem -pause -showcerts -state
+
+--------------------------------------------
+openssl s_server -port 1111 -cert ../SSL/server-cert.pem -key ../SSL/server-key.pem
+
+
+
+
+--------------------------------------------
+
+CA stuff:
+
+[tonu@x153 bin]$ pwd
+/usr/local/ssl/bin
+[tonu@x153 bin]$
+[tonu@x153 bin]$ ./CA.sh
+[tonu@x153 bin]$ ./CA.sh -h
+usage: CA -newcert|-newreq|-newca|-sign|-verify
+[tonu@x153 bin]$
+[root@x153 bin]# ./CA.sh -newca
+CA certificate filename (or enter to create)
+
+Making CA certificate ...
+Using configuration from /usr/lib/ssl/openssl.cnf
+Generating a 1024 bit RSA private key
+.++++++
+................++++++
+writing new private key to './demoCA/private/./cakey.pem'
+Enter PEM pass phrase:
+Verifying password - Enter PEM pass phrase:
+phrase is too short, needs to be at least 4 chars
+Enter PEM pass phrase:
+Verifying password - Enter PEM pass phrase:
+-----
+You are about to be asked to enter information that will be incorporated
+into your certificate request.
+What you are about to enter is what is called a Distinguished Name or a DN.
+There are quite a few fields but you can leave some blank
+For some fields there will be a default value,
+If you enter '.', the field will be left blank.
+-----
+ountry Name (2 letter code) [AU]:FI
+State or Province Name (full name) [Some-State]:
+Locality Name (eg, city) []:Helsinki
+Organization Name (eg, company) [Internet Widgits Pty Ltd]:MySQL Finland AB
+Organizational Unit Name (eg, section) []:
+Common Name (eg, YOUR name) []:Tonu Samuel
+Email Address []:tonu@mysql.com
+[root@x153 bin]#
+[root@x153 bin]# ls -la demoCA/
+total 13
+drwxr-xr-x 6 root root 232 Jun 24 18:50 ./
+drwxr-xr-x 3 root root 2136 Jun 24 18:41 ../
+-rw-r--r-- 1 root root 1241 Jun 24 18:50 cacert.pem
+drwxr-xr-x 2 root root 48 Jun 24 18:41 certs/
+drwxr-xr-x 2 root root 48 Jun 24 18:41 crl/
+-rw-r--r-- 1 root root 0 Jun 24 18:44 index.txt
+drwxr-xr-x 2 root root 48 Jun 24 18:41 newcerts/
+drwxr-xr-x 2 root root 80 Jun 24 18:44 private/
+-rw-r--r-- 1 root root 3 Jun 24 18:44 serial
+[root@x153 bin]#
+[root@x153 bin]# ls -la demoCA/private/
+total 5
+drwxr-xr-x 2 root root 80 Jun 24 18:44 ./
+drwxr-xr-x 6 root root 232 Jun 24 18:50 ../
+-rw-r--r-- 1 root root 963 Jun 24 18:50 cakey.pem
+[root@x153 bin]#
+[root@x153 bin]# ./CA.sh -newreq
+Using configuration from /usr/lib/ssl/openssl.cnf
+Generating a 1024 bit RSA private key
+..................++++++
+........................++++++
+writing new private key to 'newreq.pem'
+Enter PEM pass phrase: <- new key password, not CA
+Verifying password - Enter PEM pass phrase:
+-----
+You are about to be asked to enter information that will be incorporated
+into your certificate request.
+What you are about to enter is what is called a Distinguished Name or a DN.
+There are quite a few fields but you can leave some blank
+For some fields there will be a default value,
+If you enter '.', the field will be left blank.
+-----
+Country Name (2 letter code) [AU]:EE
+State or Province Name (full name) [Some-State]:
+Locality Name (eg, city) []:Tallinn
+Organization Name (eg, company) [Internet Widgits Pty Ltd]:Noname
+Organizational Unit Name (eg, section) []:
+Common Name (eg, YOUR name) []:Mr Noname
+Email Address []:a@b.c
+
+Please enter the following 'extra' attributes
+to be sent with your certificate request
+A challenge password []:
+An optional company name []:
+Request (and private key) is in newreq.pem
+[root@x153 bin]#
+[root@x153 bin]# ls -la newreq.pem
+-rw-r--r-- 1 root root 1623 Jun 24 18:54 newreq.pem
+[root@x153 bin]#
+[root@x153 bin]# ./CA.sh -sign
+Using configuration from /usr/lib/ssl/openssl.cnf
+Enter PEM pass phrase: <- CA's one!
+Check that the request matches the signature
+Signature ok
+The Subjects Distinguished Name is as follows
+countryName :PRINTABLE:'EE'
+stateOrProvinceName :PRINTABLE:'Some-State'
+localityName :PRINTABLE:'Tallinn'
+organizationName :PRINTABLE:'Noname'
+commonName :PRINTABLE:'Mr Noname'
+emailAddress :IA5STRING:'a@b.c'
+Certificate is to be certified until Jun 24 15:50:23 2002 GMT (365 days)
+Sign the certificate? [y/n]:y
+
+
+1 out of 1 certificate requests certified, commit? [y/n]y
+Write out database with 1 new entries
+Data Base Updated
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: md5WithRSAEncryption
+ Issuer: C=FI, ST=Some-State, L=Helsinki, O=MySQL Finland AB, CN=Tonu Samuel/Email=tonu@mysql.com
+ Validity
+ Not Before: Jun 24 15:50:23 2001 GMT
+ Not After : Jun 24 15:50:23 2002 GMT
+ Subject: C=EE, ST=Some-State, L=Tallinn, O=Noname, CN=Mr Noname/Email=a@b.c
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (1024 bit)
+ Modulus (1024 bit):
+ 00:ab:3b:7d:5b:6c:93:f6:46:1a:2c:46:73:6f:89:
+ 8a:99:bb:e9:6b:94:0d:74:aa:aa:c4:5c:a2:61:cf:
+ 56:bb:a1:a9:5a:37:c4:4e:b2:ec:5c:18:3a:a4:8d:
+ af:3d:23:66:7c:85:7f:d1:f2:e3:fc:16:a7:4c:a2:
+ d6:45:06:92:75:d8:a2:3b:f9:aa:77:da:26:b9:87:
+ e0:df:50:54:e4:36:9f:35:87:39:8e:a6:7c:3e:a8:
+ e4:49:1a:76:c2:6f:73:0b:22:93:2a:04:67:0d:7d:
+ ae:34:5c:fe:7c:29:b8:a2:fe:1e:ef:d1:0c:4d:dd:
+ 5b:7a:67:b0:0a:22:88:a0:af
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ Netscape Comment:
+ OpenSSL Generated Certificate
+ X509v3 Subject Key Identifier:
+ 83:D1:0D:52:0F:DE:61:2D:A6:10:20:B8:46:0C:77:D5:D2:D0:BE:20
+ X509v3 Authority Key Identifier:
+ keyid:A5:0A:D6:72:B5:DF:E4:C2:2B:7B:07:5E:D3:4D:52:07:E1:83:6B:7F
+ DirName:/C=FI/ST=Some-State/L=Helsinki/O=MySQL Finland AB/CN=Tonu Samuel/Email=tonu@mysql.com
+ serial:00
+
+ Signature Algorithm: md5WithRSAEncryption
+ 60:85:f7:d0:54:2a:67:88:0e:37:a6:a8:8e:fd:a0:c9:a1:d7:
+ c6:fc:4c:2e:59:8d:88:6d:69:0a:b8:b2:67:5f:81:94:39:0e:
+ ab:67:fc:8b:62:de:85:f6:b3:8c:2d:1a:e3:dc:28:fc:f5:99:
+ 39:f0:3d:50:ca:88:c0:8e:f8:c2:02:5d:34:19:63:9f:c4:a2:
+ f6:a8:81:c9:8d:6d:bd:c4:42:4a:0c:49:5a:cc:24:ea:65:80:
+ dd:79:20:89:9e:ea:6b:80:7a:86:f9:bb:6d:24:3c:80:13:5b:
+ e6:16:fc:3d:8d:f6:16:ea:33:25:c6:90:20:81:a4:b0:15:2e:
+ 9c:1c
+-----BEGIN CERTIFICATE-----
+MIIDfjCCAuegAwIBAgIBATANBgkqhkiG9w0BAQQFADCBhTELMAkGA1UEBhMCRkkx
+EzARBgNVBAgTClNvbWUtU3RhdGUxETAPBgNVBAcTCEhlbHNpbmtpMRkwFwYDVQQK
+ExBNeVNRTCBGaW5sYW5kIEFCMRQwEgYDVQQDEwtUb251IFNhbXVlbDEdMBsGCSqG
+SIb3DQEJARYOdG9udUBteXNxbC5jb20wHhcNMDEwNjI0MTU1MDIzWhcNMDIwNjI0
+MTU1MDIzWjBvMQswCQYDVQQGEwJFRTETMBEGA1UECBMKU29tZS1TdGF0ZTEQMA4G
+A1UEBxMHVGFsbGlubjEPMA0GA1UEChMGTm9uYW1lMRIwEAYDVQQDEwlNciBOb25h
+bWUxFDASBgkqhkiG9w0BCQEWBWFAYi5jMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB
+iQKBgQCrO31bbJP2RhosRnNviYqZu+lrlA10qqrEXKJhz1a7oalaN8ROsuxcGDqk
+ja89I2Z8hX/R8uP8FqdMotZFBpJ12KI7+ap32ia5h+DfUFTkNp81hzmOpnw+qORJ
+GnbCb3MLIpMqBGcNfa40XP58Kbii/h7v0QxN3Vt6Z7AKIoigrwIDAQABo4IBETCC
+AQ0wCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQg
+Q2VydGlmaWNhdGUwHQYDVR0OBBYEFIPRDVIP3mEtphAguEYMd9XS0L4gMIGyBgNV
+HSMEgaowgaeAFKUK1nK13+TCK3sHXtNNUgfhg2t/oYGLpIGIMIGFMQswCQYDVQQG
+EwJGSTETMBEGA1UECBMKU29tZS1TdGF0ZTERMA8GA1UEBxMISGVsc2lua2kxGTAX
+BgNVBAoTEE15U1FMIEZpbmxhbmQgQUIxFDASBgNVBAMTC1RvbnUgU2FtdWVsMR0w
+GwYJKoZIhvcNAQkBFg50b251QG15c3FsLmNvbYIBADANBgkqhkiG9w0BAQQFAAOB
+gQBghffQVCpniA43pqiO/aDJodfG/EwuWY2IbWkKuLJnX4GUOQ6rZ/yLYt6F9rOM
+LRrj3Cj89Zk58D1QyojAjvjCAl00GWOfxKL2qIHJjW29xEJKDElazCTqZYDdeSCJ
+nuprgHqG+bttJDyAE1vmFvw9jfYW6jMlxpAggaSwFS6cHA==
+-----END CERTIFICATE-----
+Signed certificate is in newcert.pem
+[root@x153 bin]# ls -la demoCA/newcerts/
+total 5
+drwxr-xr-x 2 root root 72 Jun 24 18:58 ./
+drwxr-xr-x 6 root root 296 Jun 24 18:58 ../
+-rw-r--r-- 1 root root 3533 Jun 24 18:58 01.pem
+[root@x153 bin]#
+[root@x153 mysql-4.0]# ./sql/mysqld --ssl-cert=SSL/server-cert.pem --ssl-ca=SSL/cacert.pem --ssl-ke
+y=SSL/server-req.pem -L /home/tonu/mysql-4.0/sql/share/english/ -u root
+Enter PEM pass phrase:
+./sql/mysqld: ready for connections
+[tonu@x153 mysql-4.0]$ client/mysql --ssl-key=SSL/client-req.pem --ssl-ca=SSL/cacert.pem --ssl-cert
+=SSL/client-cert.pem
+Enter PEM pass phrase:
+ERROR:
+
+[tonu@x153 mysql-4.0]$
+
+
+
+
+-8<------------------------
+SSL encrypts data between MySQL server and client.
+
+You need openssl (formerly SSLeay) for MySQL SSL support. Development
+and testing was done on openssl version 0.9.3a
+
+To compile MySQL one must do:
+./configure --with-openssl=/usr
+
+or
+
+./configure --with-openssl=yes
+
+There are sample keys and certificates included with MySQL tarball in
+directory ./SSL. They are meant to be for quick start and
+testing only. Using them in production environment means same as not
+using encryption. This is because private keys are publicly
+accessible for everyone. You must use openssl distribution for new key
+and certificate generation for both client and server.
+
+----------- for manual: ---------------------
+*New API calls:*
+
+mysql_ssl_set() - Set SSL properties (key, certificate,
+certificates authority certificate). Must be called before
+mysql_real_connect();
+mysql_ssl_clear() - Clear and free resources occupied by
+mysql_ssl_set() API call.
+char *mysql_ssl_cipher(MYSQL *) - returns cipher in use. For example
+"DES-CDC3-SHA" means that you have combined triple DES symmetric
+algorithm and SHA
+hashing algorithm.
+
+
+*New command line switches:*
+--ssl Use SSL for connection (automatically set with
+other flags. This means one can use encrypted connection without strong
+cryptological authentication. Normally one must use all switches
+together including ssl-key, ssl-cert and ssl-ca and never mind about
+--ssl because this is assumed by defult if any of them (--ssl-...)
+included.
+--ssl-key X509 key in PEM format (implies --ssl)
+--ssl-cert X509 cert in PEM format (implies --ssl)
+--ssl-ca CA file in PEM format (check OpenSSL docs,
+implies --ssl)
+--ssl-capath CA directory (check OpenSSL docs, implies --ssl
+ ----------------
+ This is about using SSL in MySQL privilege system. My idea is to make
+ possible use of x509 certificates and keys instead of MySQL native
+ passwords
+Some basic theory about crypt, SSL and x509:
+x509 is standard for certificates. SSL is standard for secure
+communication. Certificates are issued by someone anyone can trust. This
+trusted party is called "Certificate Authority" or "CA". This is
+someone, we MUST trust. Everyone must have some "fingerprint" of CA (so
+called "CA certificate" or "CA cert") using which one can verify
+authenticity of other
+certificates issued by this CA. CA uses his power to give certificates
+to persons (they can be physical (like "monty") or logical (like some
+process). Person is identified by "subject" like
+"/C=EE/ST=Harjumaa/L=Tallinn/O=MySQL client bogus certificate/CN=Tonu
+Samuel/Email=<EMAIL: PROTECTED>". and signed cryptologically. This sign can be
+verified using CA-cert. So, if we trust CA, then we can trust identity
+of user.
+There can be many CA-s (usually not but who knows). Also there can be
+some users we don`t trust or have different privileges. This means we
+must have one table to hold CA-certs and other table to hold so called
+"subjects" (users). I think it`s a good idea to use existing structure
+of host/user/db/field and add some x509 relationship. Then we can
+use usual simple user/host pair or x509 subject/CA pair.
+So I think user must grant rights using old method GRANT blabla ON
+blabla TO blabla IDENTIFIED BY blabla
+or new way:
+-----------8<---------------------------
+GRANT blabla ON blabla TO blabla
+IDENTIFIED BY X509 SUBJECT "/C=EE/ST=Harjumaa/L=Tallinn/O=MySQL client
+bogus certificate/CN=Tonu Samuel/Email=<EMAIL: PROTECTED>" AND ISSUER
+"/C=EE/ST=Harjumaa/L=Tallinn/O=TCX AB/CN=Tonu
+Samuel/Email=<EMAIL: PROTECTED>";
+-----------8<---------------------------
+Please note the difference in Subject and Issuer. This command requests
+user to authenticate itself with exact subject and exact certificate
+issuer. Next possibility is just have any certificate of some good CA:
+-----------8<---------------------------
+GRANT blabla ON blabla TO blabla IDENTIFIED BY X509 ISSUER
+"/C=EE/ST=Harjumaa/L=Tallinn/O=TCX
+AB/CN=Tonu Samuel/Email=<EMAIL: PROTECTED>";
+-----------8<---------------------------
+or if any registered CA is good enough (usual case when only one CA is
+registered)
+but we care about exact user, then something like:
+-----------8<---------------------------
+GRANT blabla ON blabla TO blabla IDENTIFIED BY X509 SUBJECT
+"/C=EE/ST=Harjumaa/L=Tallinn/O=MySQL client
+bogus certificate/CN=Tonu Samuel/Email=<EMAIL: PROTECTED>";
+-----------8<---------------------------
+And case if user must authenticate itself but we don`t care about exact
+person until he have some certificate issued by CA registered in our
+system:
+-----------8<---------------------------
+GRANT blabla ON blabla TO blabla IDENTIFIED BY X509;
+-----------8<---------------------------
+Then additionally we need one exception. Let`s assume we need SSL
+encryption
+for preventing eavesdropping but we don`t care who it is at all. We need
+privilege to exclude all non-SSL users but we accept anyone using SSL.
+How
+this must be done in GRANT syntax? Maybe:
+-----------8<---------------------------
+GRANT blabla ON blabla TO blabla
+IDENTIFIED BY blabla AND USING SSL
+-----------8<---------------------------
+But maybe we want to add in future possibility to check different
+algorithms and key lengths? Something like:
+-----------8<---------------------------
+GRANT blabla ON blabla TO blabla IDENTIFIED BY blabla AND USING SSL WITH
+CIPHER "DES-CBC3-SHA" OR "DES-CBC3-MD5"
+-----------8<---------------------------
+Also we need some command to include/exclude CA certificates. This must
+be some commands like INSERT/DELETE/UPDATE/REPLACE to do it.
+All examples is given for clarify my problem. I asking for help because
+I don`t know
+any similar command in other SQL-s.
+------------8<------------------------
+
+So, at moment SSL communications is ready and working. I don`t have this
+command iterface at moment yet and this can be changed a lot if someone
+can suggest good idea or reason to change them. We are ready to listen
+every opinion.
+About Kerberos: I just don`t know much about it. I have to read this
+again before I can comment. I never used it itself and forgot most of
+theory. Sorry. Anyway now the problem/need is known and I will put
+thinking about this in personal TODO.
+
+
diff --git a/SSL/cacert.pem b/SSL/cacert.pem
new file mode 100644
index 00000000000..862e07114c5
--- /dev/null
+++ b/SSL/cacert.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDaDCCAtGgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBhTELMAkGA1UEBhMCRkkx
+EzARBgNVBAgTClNvbWUtU3RhdGUxETAPBgNVBAcTCEhlbHNpbmtpMRkwFwYDVQQK
+ExBNeVNRTCBGaW5sYW5kIEFCMRQwEgYDVQQDEwtUb251IFNhbXVlbDEdMBsGCSqG
+SIb3DQEJARYOdG9udUBteXNxbC5jb20wHhcNMDEwNjI0MTU0MzE4WhcNMDIwNjI0
+MTU0MzE4WjCBhTELMAkGA1UEBhMCRkkxEzARBgNVBAgTClNvbWUtU3RhdGUxETAP
+BgNVBAcTCEhlbHNpbmtpMRkwFwYDVQQKExBNeVNRTCBGaW5sYW5kIEFCMRQwEgYD
+VQQDEwtUb251IFNhbXVlbDEdMBsGCSqGSIb3DQEJARYOdG9udUBteXNxbC5jb20w
+gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJz9FCvWX8c+Xr6mxzfZvPainIPT
+ODNsQ0f2kAs0epP+peUn4LHxLybp2dkUHTtJLXyUyk7cXfnUd+0fRazK2/Vz48bZ
+swGwg9Rhg3P02Ku+CMWYulHzN6uVRzfrDUSkDoky2DGL3A6B8P4JRc2qcr+kjhh5
+6r1VJlXs9N3DqeEdAgMBAAGjgeUwgeIwHQYDVR0OBBYEFKUK1nK13+TCK3sHXtNN
+Ugfhg2t/MIGyBgNVHSMEgaowgaeAFKUK1nK13+TCK3sHXtNNUgfhg2t/oYGLpIGI
+MIGFMQswCQYDVQQGEwJGSTETMBEGA1UECBMKU29tZS1TdGF0ZTERMA8GA1UEBxMI
+SGVsc2lua2kxGTAXBgNVBAoTEE15U1FMIEZpbmxhbmQgQUIxFDASBgNVBAMTC1Rv
+bnUgU2FtdWVsMR0wGwYJKoZIhvcNAQkBFg50b251QG15c3FsLmNvbYIBADAMBgNV
+HRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4GBAI+YJKoa+IP3WYr8iLcVk5j7lZ9D
+GS8reuALafnE7VX1xMlXP5EnJjT7YYYmtiB2tYj7+eQ+ajRXWWyY5NtO5ob+dm8z
+OBX43v08C5vNSAFpwZWTutzb0nSd8kOABGJ04MBDJZk8QNkTfU6C7c3ZJ/gW8Guv
+I+cxfz6oCYEfKLBN
+-----END CERTIFICATE-----
diff --git a/SSL/client-cert.pem b/SSL/client-cert.pem
new file mode 100644
index 00000000000..cab2a635d9f
--- /dev/null
+++ b/SSL/client-cert.pem
@@ -0,0 +1,67 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 3 (0x3)
+ Signature Algorithm: md5WithRSAEncryption
+ Issuer: C=FI, ST=Some-State, L=Helsinki, O=MySQL Finland AB, CN=Tonu Samuel/Email=tonu@mysql.com
+ Validity
+ Not Before: Jun 24 16:03:20 2001 GMT
+ Not After : Jun 24 16:03:20 2002 GMT
+ Subject: C=EE, ST=Some-State, L=Tallinn, O=MySQL demo client certificate, CN=Tonu Samuel/Email=tonu@mysql.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (1024 bit)
+ Modulus (1024 bit):
+ 00:e8:d4:52:cd:4e:bb:96:16:3a:f0:89:6b:90:4c:
+ db:e0:30:75:5a:02:72:62:bf:ed:da:be:09:e8:80:
+ db:80:54:30:d6:75:ed:e3:10:a5:15:44:5b:29:91:
+ 12:fe:0c:b7:76:4d:e9:5f:56:5c:45:3c:ad:b2:71:
+ 2d:6a:7a:cb:bc:04:80:08:74:d6:7d:f6:7c:5c:76:
+ db:35:c4:f6:f5:d8:d4:89:9f:9d:cc:3f:4e:3f:73:
+ c1:3e:41:7e:4e:09:bf:ea:1a:d9:a2:13:0d:d1:0c:
+ da:d8:f4:9b:b8:54:21:17:ae:d7:b3:02:61:87:a9:
+ 01:ff:f4:fe:9c:7a:fc:67:43
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ Netscape Comment:
+ OpenSSL Generated Certificate
+ X509v3 Subject Key Identifier:
+ BC:FB:BB:8F:C4:85:BA:5F:A8:F2:C3:3D:C9:0F:DB:16:E7:13:BC:B2
+ X509v3 Authority Key Identifier:
+ keyid:A5:0A:D6:72:B5:DF:E4:C2:2B:7B:07:5E:D3:4D:52:07:E1:83:6B:7F
+ DirName:/C=FI/ST=Some-State/L=Helsinki/O=MySQL Finland AB/CN=Tonu Samuel/Email=tonu@mysql.com
+ serial:00
+
+ Signature Algorithm: md5WithRSAEncryption
+ 1c:e0:87:2c:2f:b3:a4:39:44:7f:96:7b:2f:c9:1f:91:84:0b:
+ 9f:d0:0a:f8:40:70:d0:dd:bd:91:0a:c6:d5:ac:8f:51:77:9c:
+ 35:28:e8:b6:5f:57:9e:5c:b5:9b:ae:5d:3d:7c:05:45:2e:89:
+ 3a:03:e1:f2:00:cb:c1:ed:3e:48:3b:5f:4e:50:d2:b4:a5:36:
+ 0f:1a:dc:79:49:1e:03:2f:27:c1:e4:62:d6:ef:3f:ab:2e:ab:
+ dd:e5:bc:cb:20:a3:dd:ab:81:69:26:9c:03:42:1b:4c:b7:aa:
+ 57:6d:2a:de:c0:5e:6e:74:d0:83:90:ec:ad:bb:ba:f0:cc:cf:
+ 41:3d
+-----BEGIN CERTIFICATE-----
+MIIDoTCCAwqgAwIBAgIBAzANBgkqhkiG9w0BAQQFADCBhTELMAkGA1UEBhMCRkkx
+EzARBgNVBAgTClNvbWUtU3RhdGUxETAPBgNVBAcTCEhlbHNpbmtpMRkwFwYDVQQK
+ExBNeVNRTCBGaW5sYW5kIEFCMRQwEgYDVQQDEwtUb251IFNhbXVlbDEdMBsGCSqG
+SIb3DQEJARYOdG9udUBteXNxbC5jb20wHhcNMDEwNjI0MTYwMzIwWhcNMDIwNjI0
+MTYwMzIwWjCBkTELMAkGA1UEBhMCRUUxEzARBgNVBAgTClNvbWUtU3RhdGUxEDAO
+BgNVBAcTB1RhbGxpbm4xJjAkBgNVBAoTHU15U1FMIGRlbW8gY2xpZW50IGNlcnRp
+ZmljYXRlMRQwEgYDVQQDEwtUb251IFNhbXVlbDEdMBsGCSqGSIb3DQEJARYOdG9u
+dUBteXNxbC5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOjUUs1Ou5YW
+OvCJa5BM2+AwdVoCcmK/7dq+CeiA24BUMNZ17eMQpRVEWymREv4Mt3ZN6V9WXEU8
+rbJxLWp6y7wEgAh01n32fFx22zXE9vXY1Imfncw/Tj9zwT5Bfk4Jv+oa2aITDdEM
+2tj0m7hUIReu17MCYYepAf/0/px6/GdDAgMBAAGjggERMIIBDTAJBgNVHRMEAjAA
+MCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAd
+BgNVHQ4EFgQUvPu7j8SFul+o8sM9yQ/bFucTvLIwgbIGA1UdIwSBqjCBp4AUpQrW
+crXf5MIrewde001SB+GDa3+hgYukgYgwgYUxCzAJBgNVBAYTAkZJMRMwEQYDVQQI
+EwpTb21lLVN0YXRlMREwDwYDVQQHEwhIZWxzaW5raTEZMBcGA1UEChMQTXlTUUwg
+RmlubGFuZCBBQjEUMBIGA1UEAxMLVG9udSBTYW11ZWwxHTAbBgkqhkiG9w0BCQEW
+DnRvbnVAbXlzcWwuY29tggEAMA0GCSqGSIb3DQEBBAUAA4GBABzghywvs6Q5RH+W
+ey/JH5GEC5/QCvhAcNDdvZEKxtWsj1F3nDUo6LZfV55ctZuuXT18BUUuiToD4fIA
+y8HtPkg7X05Q0rSlNg8a3HlJHgMvJ8HkYtbvP6suq93lvMsgo92rgWkmnANCG0y3
+qldtKt7AXm500IOQ7K27uvDMz0E9
+-----END CERTIFICATE-----
diff --git a/SSL/client-key.pem b/SSL/client-key.pem
new file mode 100644
index 00000000000..7672939b60a
--- /dev/null
+++ b/SSL/client-key.pem
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXgIBAAKBgQDo1FLNTruWFjrwiWuQTNvgMHVaAnJiv+3avgnogNuAVDDWde3j
+EKUVRFspkRL+DLd2TelfVlxFPK2ycS1qesu8BIAIdNZ99nxcdts1xPb12NSJn53M
+P04/c8E+QX5OCb/qGtmiEw3RDNrY9Ju4VCEXrtezAmGHqQH/9P6cevxnQwIDAQAB
+AoGBANxd4cUaaOfkQILbvigE5vMpSlkYCcW3XNv1lJEwLREoHlVNpwuL/IPFf/c2
+rWAxDw/1LBYlOg36IXjMMC0g7mRHHoJhdJaFLGdlfclYQvqQ+8JAsAv6UNC63+pn
+B5sZOxOuoj7lYN+D9mFVD4qTo3eTUYEOvvmS1j3hCsD2nNNBAkEA+lJUs7Y3KjCF
+COZ7XQCkC47rVzkdZ5ey1Z+vVw5SrnUvj6n9i0NEax1jX6JPIhPU7+x90KFkt0ki
+pKHd7UQ04wJBAO4caWNnYvmIorCRDy9Q/iAAow5WC6fQlkSlBIe3lRme6Ne8Yxaq
+BzlSGYu1ndPkTGEa9PFNNCJm7RtvCBFx8iECQQCkdUzi2Rc7J69vnoV0H8SnN1mU
+75hLBBZhVU1MY8OcjK8XsvY59ZLQ0PkFzswwtljS3Ev4suBJrsoM4a+9f29DAkEA
+5NTrN3vZc6SrbXLLHBcDUrAqBBIPe4SLlYbdVqzInunILeS/eb2H2b+cC1dMSaHj
+AYONmQUwMEuoXTAUmede4QJARK6jEslg/ev8BtMvITP2b6pRCb1w8lOtT5u5Bwnc
+NpI3suqSQSQPtRSWQYcdyxrKr2TQEZU7h8R9bVB4b0qAmQ==
+-----END RSA PRIVATE KEY-----
diff --git a/SSL/client-req.pem b/SSL/client-req.pem
new file mode 100644
index 00000000000..ef11a22165f
--- /dev/null
+++ b/SSL/client-req.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,8CE2AB38FB50D4B9
+
+rrnYZLUKlzV4U7+wqe5CWzTd4RLJb5h4M77aBRQfuHGejSaRsskN2ffpO8uQEAYM
+WTJSRC+NO+jDMBZhzt1ktWqCs8d6l6azHoBybIrMJsbUhwybm+OiOfp23RrbNoS/
+S4fsgNdAAGhsRvKDdsItCyYvdH8nTzn+g9r/z2V4tOOXd6MYuT42XA6Uz2tis2SZ
+GWEGa7mAweApzSiibE+pzjPS+fdX4E12n6NCVYLhn1JuvzVva/KFSebs4Wh75miC
+WvRgkt/5eDQn+vkV67hE3I6p9pPcLh1+PMfaQ25U8VM/r7ejnVFWm7teGH6GKPKJ
+cU+PYfblyWcgtiO/fwfGMIqSyNtHj/C3VFVie5D1MTJzBopiPGEcfz00LjBccjjh
+j1meTRVN8pMZTgkxlnIFwbU6TPPvx8a9urFVQIJ4z8r2EMvYh5Cqpq87+lH9Pn0C
+vzCl78Tz5QLghXNnMbbdD2aPP0PwPEXgh86iZxo06g85n0l26WUzYJlWzBYD4DrF
+SbnEUAftTujEOm6MqJNLpJN6UPOtq/HvSaHl1bykGK+zU4gqHj0ur03HlF0l4xNg
+OfsoNsJV+O9RUUJ0+D5eqUALJjN8TCV1wNMXOVzr/ue3QCVdlWVfZY4RPffwK9Yp
+Fh52T7a2v+shhqZUQNtFDAg50Ac7deUthSWNmi5N680POnJg9KdtBdMhYLa1j3rP
+D9oasSK0ugevHuQ6wUiD/95CzZlJXE9K4kTTYmaRk5MTWXhFQxdqHZo1v+pGtaNI
+f+/E7q7BiNesSt31U/vkX0Tm3oJ1dgOnS8M2uxiYiKH2mJ/E32tZKw==
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE REQUEST-----
+MIIB0jCCATsCAQAwgZExCzAJBgNVBAYTAkVFMRMwEQYDVQQIEwpTb21lLVN0YXRl
+MRAwDgYDVQQHEwdUYWxsaW5uMSYwJAYDVQQKEx1NeVNRTCBkZW1vIGNsaWVudCBj
+ZXJ0aWZpY2F0ZTEUMBIGA1UEAxMLVG9udSBTYW11ZWwxHTAbBgkqhkiG9w0BCQEW
+DnRvbnVAbXlzcWwuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDo1FLN
+TruWFjrwiWuQTNvgMHVaAnJiv+3avgnogNuAVDDWde3jEKUVRFspkRL+DLd2Telf
+VlxFPK2ycS1qesu8BIAIdNZ99nxcdts1xPb12NSJn53MP04/c8E+QX5OCb/qGtmi
+Ew3RDNrY9Ju4VCEXrtezAmGHqQH/9P6cevxnQwIDAQABoAAwDQYJKoZIhvcNAQEE
+BQADgYEAvENK1JAQfC8xnrFGw2IxfUmUwlRidiRtYTgtVfTr7vA+m4WaaKioni6E
+PQXjcvl6kfyRoxc4qWsGi3T7QM2RnvCtbwR2NGSIKX1cBTS31RMr12NSAeXn6Twz
+ZwSZ55EHj9N2hArTPNlVjxvDQX3D6/ZBi6JnHAxXigzDqhArgjU=
+-----END CERTIFICATE REQUEST-----
diff --git a/SSL/run-client b/SSL/run-client
new file mode 100755
index 00000000000..f3b29eb273b
--- /dev/null
+++ b/SSL/run-client
@@ -0,0 +1,10 @@
+#! /bin/sh
+
+cmd () {
+ echo $*
+ $*
+}
+
+client/mysql --port=4407 --socket=/tmp/test.mysql.sock --ssl-ca=SSL/cacert.pem --ssl-cert=SSL/client-cert.pem --ssl-key=SSL/client-key.pem --debug='d:t:O,/tmp/client.trace' -h 127.0.0.1 -u root
+#--execute="select version();show status"
+
diff --git a/SSL/run-server b/SSL/run-server
new file mode 100755
index 00000000000..e90a7644b83
--- /dev/null
+++ b/SSL/run-server
@@ -0,0 +1,9 @@
+#! /bin/sh
+
+cmd () {
+ echo $*
+ $*
+}
+
+cmd sql/mysqld --port=4407 --socket=/tmp/test.mysql.sock --ssl-ca=SSL/cacert.pem --ssl-cert=SSL/server-cert.pem --ssl-key=SSL/server-key.pem --debug='d:t:O,/tmp/mysqld.trace' -uroot >& /tmp/mysqld.output
+
diff --git a/SSL/server-cert.pem b/SSL/server-cert.pem
new file mode 100644
index 00000000000..069063a9de9
--- /dev/null
+++ b/SSL/server-cert.pem
@@ -0,0 +1,67 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: md5WithRSAEncryption
+ Issuer: C=FI, ST=Some-State, L=Helsinki, O=MySQL Finland AB, CN=Tonu Samuel/Email=tonu@mysql.com
+ Validity
+ Not Before: Jun 24 16:02:28 2001 GMT
+ Not After : Jun 24 16:02:28 2002 GMT
+ Subject: C=EE, ST=Some-State, L=Tallinn, O=MySQL server demo certificate, CN=Tonu Samuel/Email=tonu@mysql.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (1024 bit)
+ Modulus (1024 bit):
+ 00:9e:ac:8d:d8:1d:9c:b2:fd:88:96:2c:ba:42:53:
+ fa:5d:bd:85:8a:e5:ca:d3:0f:c0:01:3c:f2:92:46:
+ 4f:d9:80:ae:2a:89:cf:ef:e8:d4:65:fc:f6:f5:3a:
+ 26:4c:29:db:06:fa:34:a1:87:f3:97:b5:3c:94:f1:
+ 84:05:ac:ad:57:25:d9:02:db:00:71:e0:a9:aa:b4:
+ 1d:29:36:5e:a9:a4:0d:f2:45:b9:83:74:2b:45:f3:
+ e2:23:bc:e7:5c:e6:11:b6:f6:dd:c4:ac:ed:65:42:
+ 2c:39:47:2a:c9:eb:5f:45:03:10:ab:23:bc:ca:5c:
+ 82:9a:b7:b3:6d:67:18:d2:c7
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ Netscape Comment:
+ OpenSSL Generated Certificate
+ X509v3 Subject Key Identifier:
+ 94:68:BF:DA:F6:E2:09:EF:3A:C8:27:AE:D7:B7:02:F0:DC:4B:C1:3B
+ X509v3 Authority Key Identifier:
+ keyid:A5:0A:D6:72:B5:DF:E4:C2:2B:7B:07:5E:D3:4D:52:07:E1:83:6B:7F
+ DirName:/C=FI/ST=Some-State/L=Helsinki/O=MySQL Finland AB/CN=Tonu Samuel/Email=tonu@mysql.com
+ serial:00
+
+ Signature Algorithm: md5WithRSAEncryption
+ 8c:1a:90:70:f6:1a:70:0e:c9:28:93:74:e2:2b:b8:2a:d0:ce:
+ 40:15:e8:af:44:f8:89:16:20:f5:c2:b9:ed:aa:4e:3c:40:e2:
+ 9c:62:aa:48:98:ac:17:84:ef:35:72:59:43:09:35:17:c5:9a:
+ 3e:3d:ef:97:bf:57:f2:2a:f6:56:5d:a4:7c:68:58:b9:d6:9b:
+ 0f:57:0e:55:22:17:b0:b7:77:27:4f:da:b3:88:c1:6d:d6:8f:
+ 31:ec:0d:a2:25:60:66:2f:0f:86:8a:d6:08:b8:71:b1:b5:70:
+ 60:04:56:96:ff:bd:5e:ed:94:bc:44:bd:24:e0:2f:90:e5:23:
+ 51:4e
+-----BEGIN CERTIFICATE-----
+MIIDoTCCAwqgAwIBAgIBAjANBgkqhkiG9w0BAQQFADCBhTELMAkGA1UEBhMCRkkx
+EzARBgNVBAgTClNvbWUtU3RhdGUxETAPBgNVBAcTCEhlbHNpbmtpMRkwFwYDVQQK
+ExBNeVNRTCBGaW5sYW5kIEFCMRQwEgYDVQQDEwtUb251IFNhbXVlbDEdMBsGCSqG
+SIb3DQEJARYOdG9udUBteXNxbC5jb20wHhcNMDEwNjI0MTYwMjI4WhcNMDIwNjI0
+MTYwMjI4WjCBkTELMAkGA1UEBhMCRUUxEzARBgNVBAgTClNvbWUtU3RhdGUxEDAO
+BgNVBAcTB1RhbGxpbm4xJjAkBgNVBAoTHU15U1FMIHNlcnZlciBkZW1vIGNlcnRp
+ZmljYXRlMRQwEgYDVQQDEwtUb251IFNhbXVlbDEdMBsGCSqGSIb3DQEJARYOdG9u
+dUBteXNxbC5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJ6sjdgdnLL9
+iJYsukJT+l29hYrlytMPwAE88pJGT9mAriqJz+/o1GX89vU6Jkwp2wb6NKGH85e1
+PJTxhAWsrVcl2QLbAHHgqaq0HSk2XqmkDfJFuYN0K0Xz4iO851zmEbb23cSs7WVC
+LDlHKsnrX0UDEKsjvMpcgpq3s21nGNLHAgMBAAGjggERMIIBDTAJBgNVHRMEAjAA
+MCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAd
+BgNVHQ4EFgQUlGi/2vbiCe86yCeu17cC8NxLwTswgbIGA1UdIwSBqjCBp4AUpQrW
+crXf5MIrewde001SB+GDa3+hgYukgYgwgYUxCzAJBgNVBAYTAkZJMRMwEQYDVQQI
+EwpTb21lLVN0YXRlMREwDwYDVQQHEwhIZWxzaW5raTEZMBcGA1UEChMQTXlTUUwg
+RmlubGFuZCBBQjEUMBIGA1UEAxMLVG9udSBTYW11ZWwxHTAbBgkqhkiG9w0BCQEW
+DnRvbnVAbXlzcWwuY29tggEAMA0GCSqGSIb3DQEBBAUAA4GBAIwakHD2GnAOySiT
+dOIruCrQzkAV6K9E+IkWIPXCue2qTjxA4pxiqkiYrBeE7zVyWUMJNRfFmj4975e/
+V/Iq9lZdpHxoWLnWmw9XDlUiF7C3dydP2rOIwW3WjzHsDaIlYGYvD4aK1gi4cbG1
+cGAEVpb/vV7tlLxEvSTgL5DlI1FO
+-----END CERTIFICATE-----
diff --git a/SSL/server-key.pem b/SSL/server-key.pem
new file mode 100644
index 00000000000..44137ca1c94
--- /dev/null
+++ b/SSL/server-key.pem
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQCerI3YHZyy/YiWLLpCU/pdvYWK5crTD8ABPPKSRk/ZgK4qic/v
+6NRl/Pb1OiZMKdsG+jShh/OXtTyU8YQFrK1XJdkC2wBx4KmqtB0pNl6ppA3yRbmD
+dCtF8+IjvOdc5hG29t3ErO1lQiw5RyrJ619FAxCrI7zKXIKat7NtZxjSxwIDAQAB
+AoGAA51gudyq1jUKaIlqUNqC6KHJqglkHnzMXfrad9ScOxNAZH2xPADs3cnuglWp
+y7BkaftHOarUNM+PKsF5xXtSk5F9UUV+7h2FtPZYUshUgn5hkGZP12otxJMP0cpg
+Yt6brQxuOIe/r/Kt5r3nKpp4pyFLX2fGWQq7pSjdkgSZSOECQQDJ9MgbCXd81yde
+eo3+YmUPBEQ9d7mivQsyPHMOHLPJKR42N4npdR1zLDBYK5lFzJeQH1y0Uce3O8eL
+hM8hkA1XAkEAySKvNTaosbLhShkRazQyQQJYJg0F/93lkQ33ou4crru7Mvi2OZK9
+B3BGAmNpSv6ZOZYjM0aE8lGlTaoYJ9GQEQJAGJDyFnfcVQ9G9rMpupv1dxIpyuBZ
+cHZWelHoHPtY00txJV80I3Xfkzb42oDTMC5m8V0fRb/870kSSOJq38ZKGQJBAIgq
+wxLzfiFPSNYxQmmhXKRGQgcAqh8eylv5aL0VFrX0wjcvya4QeYifqcXUJ2RuGK2z
+xwDfrQGf5Jk/njrW1QECQAUofd1l9DLDifRP1j9sjUdwz0fvqQ0o6sbt39PBl1ot
+IHdc3nf9z0ft+KOG1CT/M9jYo9SzE9Z6IfwmHxxpY0s=
+-----END RSA PRIVATE KEY-----
diff --git a/SSL/server-req.pem b/SSL/server-req.pem
new file mode 100644
index 00000000000..4cd6610e735
--- /dev/null
+++ b/SSL/server-req.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,6CBD09E71246DC01
+
+byRzq5+j3r8FX2kQerTUZT5Bw/N6zrN3cmH6NHGJcrqD+vcPdtWf+Rk+mpNXgSQn
+ldkfmniU/htzJ0cUV+KE229Qx10Hx9mIJIbf0Y/rBCUBuaXWVrQB36W9w3rkNPFA
+EEuRMkreOJF42RD16+NBJv+RcHIGzGejXecJKUGF5DKlN0U8YHXnkXTQl54kIdr0
+H7rTrvJygwPk9/ik0M9/vmwduAMvTaHDmvgeolpMlJkxwz8vYkbUnFFJZhB6XNCb
+1w3lJ0EmRJicK5BnZmCEmgt8xiv0PAtg00jBbwddQbn1reAyViBtBT9iXdusHXS5
+Po63rSt7r3MO8aetcMQ6FkklH+ChuS/vFoNY57AwrzF4uEI4GSoZP0ESrRC5Ar5W
+Lzg/HrQAWbPCRlb6Jj3db1woRzFS8joOashROsZdeV/5P4Emhc6J7QMTvB1OHAhQ
+ugOJazJtxjg0DN8+9cM1wtHI7N89PLHhOg13LZNLeeehzIlPwKI2JLqXUc6oR407
+i+S7GCqu7wU+if0Enux8Dj7yrvnTUiqVCL2dyKTS3sBq0Cm2UhbecHclor13y6no
+y1o50TKKD6Zig2hZmSpqKznMxGMVIT36BE0aOMQUmk+aVnRuROclwTTL0ZNLzA+g
+QRTRfQ6iNMf34ypqAMdAMPzDGLPycKuFdxVQxFEVaM2/mrdWFwVAqFsLvzyGvdrh
+nkNyRgTWR/pfH9b3mXLqf6gMPNs764WhFIcZIDk9a4XBBUm2YDb2CxDzDCo/EUMA
+jvIiU0Jt132SEHHF/wAka6d2DnwZ3vexRp6Tebv/uy9IlMLPE+68dw==
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE REQUEST-----
+MIIB0jCCATsCAQAwgZExCzAJBgNVBAYTAkVFMRMwEQYDVQQIEwpTb21lLVN0YXRl
+MRAwDgYDVQQHEwdUYWxsaW5uMSYwJAYDVQQKEx1NeVNRTCBzZXJ2ZXIgZGVtbyBj
+ZXJ0aWZpY2F0ZTEUMBIGA1UEAxMLVG9udSBTYW11ZWwxHTAbBgkqhkiG9w0BCQEW
+DnRvbnVAbXlzcWwuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCerI3Y
+HZyy/YiWLLpCU/pdvYWK5crTD8ABPPKSRk/ZgK4qic/v6NRl/Pb1OiZMKdsG+jSh
+h/OXtTyU8YQFrK1XJdkC2wBx4KmqtB0pNl6ppA3yRbmDdCtF8+IjvOdc5hG29t3E
+rO1lQiw5RyrJ619FAxCrI7zKXIKat7NtZxjSxwIDAQABoAAwDQYJKoZIhvcNAQEE
+BQADgYEAlrUnGX4LYIiVjztHA4gUcOSVeEHCci2qEUq+7yY1JhAw54YDa2MLTTwa
+cH+rXLHjN0MTNfv9tRxdSX+trk3pyvhgFjssD100dJkF83RfVv2tKg9kscVOGQp7
+MkwOnJjfAjQBlTbTOQM46BTjv2FgvsppkO3ViryI//YxKvj/628=
+-----END CERTIFICATE REQUEST-----
diff --git a/VC++Files/InstallShield/Script Files/Setup.dbg b/VC++Files/InstallShield/Script Files/Setup.dbg
new file mode 100644
index 00000000000..0c6d4e6b708
--- /dev/null
+++ b/VC++Files/InstallShield/Script Files/Setup.dbg
Binary files differ
diff --git a/VC++Files/InstallShield/Script Files/Setup.ino b/VC++Files/InstallShield/Script Files/Setup.ino
new file mode 100644
index 00000000000..204d8ea0f36
--- /dev/null
+++ b/VC++Files/InstallShield/Script Files/Setup.ino
Binary files differ
diff --git a/VC++Files/InstallShield/Script Files/Setup.ins b/VC++Files/InstallShield/Script Files/Setup.ins
new file mode 100644
index 00000000000..759009b5c84
--- /dev/null
+++ b/VC++Files/InstallShield/Script Files/Setup.ins
Binary files differ
diff --git a/VC++Files/InstallShield/Script Files/Setup.obs b/VC++Files/InstallShield/Script Files/Setup.obs
new file mode 100644
index 00000000000..5fcfcb62c4e
--- /dev/null
+++ b/VC++Files/InstallShield/Script Files/Setup.obs
Binary files differ
diff --git a/VC++Files/InstallShield/Script Files/Setup.rul b/VC++Files/InstallShield/Script Files/Setup.rul
new file mode 100644
index 00000000000..df143b493c4
--- /dev/null
+++ b/VC++Files/InstallShield/Script Files/Setup.rul
@@ -0,0 +1,640 @@
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// IIIIIII SSSSSS
+// II SS InstallShield (R)
+// II SSSSSS (c) 1996-1997, InstallShield Software Corporation
+// II SS (c) 1990-1996, InstallShield Corporation
+// IIIIIII SSSSSS All Rights Reserved.
+//
+//
+// This code is generated as a starting setup template. You should
+// modify it to provide all necessary steps for your setup.
+//
+//
+// File Name: Setup.rul
+//
+// Description: InstallShield script
+//
+// Comments: This template script performs a basic setup on a
+// Windows 95 or Windows NT 4.0 platform. With minor
+// modifications, this template can be adapted to create
+// new, customized setups.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+ // Include header file
+#include "sdlang.h"
+#include "sddialog.h"
+
+////////////////////// string defines ////////////////////////////
+
+#define UNINST_LOGFILE_NAME "Uninst.isu"
+
+//////////////////// installation declarations ///////////////////
+
+ // ----- DLL prototypes -----
+
+
+ // your DLL prototypes
+
+
+ // ---- script prototypes -----
+
+ // generated
+ prototype ShowDialogs();
+ prototype MoveFileData();
+ prototype HandleMoveDataError( NUMBER );
+ prototype ProcessBeforeDataMove();
+ prototype ProcessAfterDataMove();
+ prototype SetupRegistry();
+ prototype SetupFolders();
+ prototype CleanUpInstall();
+ prototype SetupInstall();
+ prototype SetupScreen();
+ prototype CheckRequirements();
+ prototype DialogShowSdWelcome();
+ prototype DialogShowSdShowInfoList();
+ prototype DialogShowSdAskDestPath();
+ prototype DialogShowSdSetupType();
+ prototype DialogShowSdComponentDialog2();
+ prototype DialogShowSdFinishReboot();
+
+ // your prototypes
+
+
+ // ----- global variables ------
+
+ // generated
+ BOOL bWinNT, bIsShellExplorer, bInstallAborted, bIs32BitSetup;
+ STRING svDir;
+ STRING svName, svCompany, svSerial;
+ STRING szAppPath;
+ STRING svSetupType;
+
+
+ // your global variables
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// MAIN PROGRAM
+//
+// The setup begins here by hiding the visible setup
+// window. This is done to allow all the titles, images, etc. to
+// be established before showing the main window. The following
+// logic then performs the setup in a series of steps.
+//
+///////////////////////////////////////////////////////////////////////////////
+program
+ Disable( BACKGROUND );
+
+ CheckRequirements();
+
+ SetupInstall();
+
+ SetupScreen();
+
+ if (ShowDialogs()<0) goto end_install;
+
+ if (ProcessBeforeDataMove()<0) goto end_install;
+
+ if (MoveFileData()<0) goto end_install;
+
+ if (ProcessAfterDataMove()<0) goto end_install;
+
+ if (SetupRegistry()<0) goto end_install;
+
+ if (SetupFolders()<0) goto end_install;
+
+
+ end_install:
+
+ CleanUpInstall();
+
+ // If an unrecoverable error occurred, clean up the partial installation.
+ // Otherwise, exit normally.
+
+ if (bInstallAborted) then
+ abort;
+ endif;
+
+endprogram
+
+///////////////////////////////////////////////////////////////////////////////
+// //
+// Function: ShowDialogs //
+// //
+// Purpose: This function manages the display and navigation //
+// the standard dialogs that exist in a setup. //
+// //
+///////////////////////////////////////////////////////////////////////////////
+function ShowDialogs()
+ NUMBER nResult;
+ begin
+
+ Dlg_Start:
+ // beginning of dialogs label
+
+ Dlg_SdWelcome:
+ nResult = DialogShowSdWelcome();
+ if (nResult = BACK) goto Dlg_Start;
+
+ Dlg_SdShowInfoList:
+ nResult = DialogShowSdShowInfoList();
+ if (nResult = BACK) goto Dlg_SdWelcome;
+
+ Dlg_SdAskDestPath:
+ nResult = DialogShowSdAskDestPath();
+ if (nResult = BACK) goto Dlg_SdShowInfoList;
+
+ Dlg_SdSetupType:
+ nResult = DialogShowSdSetupType();
+ if (nResult = BACK) goto Dlg_SdAskDestPath;
+
+ Dlg_SdComponentDialog2:
+ if ((nResult = BACK) && (svSetupType != "Custom") && (svSetupType != "")) then
+ goto Dlg_SdSetupType;
+ endif;
+ nResult = DialogShowSdComponentDialog2();
+ if (nResult = BACK) goto Dlg_SdSetupType;
+
+ return 0;
+
+ end;
+
+///////////////////////////////////////////////////////////////////////////////
+// //
+// Function: ProcessBeforeDataMove //
+// //
+// Purpose: This function performs any necessary operations prior to the //
+// actual data move operation. //
+// //
+///////////////////////////////////////////////////////////////////////////////
+function ProcessBeforeDataMove()
+ STRING svLogFile;
+ NUMBER nResult;
+ begin
+
+ InstallationInfo( @COMPANY_NAME, @PRODUCT_NAME, @PRODUCT_VERSION, @PRODUCT_KEY );
+
+ svLogFile = UNINST_LOGFILE_NAME;
+
+ nResult = DeinstallStart( svDir, svLogFile, @UNINST_KEY, 0 );
+ if (nResult < 0) then
+ MessageBox( @ERROR_UNINSTSETUP, WARNING );
+ endif;
+
+ szAppPath = TARGETDIR; // TODO : if your application .exe is in a subdir of TARGETDIR then add subdir
+
+ if ((bIs32BitSetup) && (bIsShellExplorer)) then
+ RegDBSetItem( REGDB_APPPATH, szAppPath );
+ RegDBSetItem( REGDB_APPPATH_DEFAULT, szAppPath ^ @PRODUCT_KEY );
+ RegDBSetItem( REGDB_UNINSTALL_NAME, @UNINST_DISPLAY_NAME );
+ endif;
+
+ // TODO : update any items you want to process before moving the data
+ //
+
+ return 0;
+ end;
+
+///////////////////////////////////////////////////////////////////////////////
+// //
+// Function: MoveFileData //
+// //
+// Purpose: This function handles the data movement for //
+// the setup. //
+// //
+///////////////////////////////////////////////////////////////////////////////
+function MoveFileData()
+ NUMBER nResult, nDisk;
+ begin
+
+ nDisk = 1;
+ SetStatusWindow( 0, "" );
+ Disable( DIALOGCACHE );
+ Enable( STATUS );
+ StatusUpdate( ON, 100 );
+ nResult = ComponentMoveData( MEDIA, nDisk, 0 );
+
+ HandleMoveDataError( nResult );
+
+ Disable( STATUS );
+
+ return nResult;
+
+ end;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// //
+// Function: HandleMoveDataError //
+// //
+// Purpose: This function handles the error (if any) during the move data //
+// operation. //
+// //
+///////////////////////////////////////////////////////////////////////////////
+function HandleMoveDataError( nResult )
+ STRING szErrMsg, svComponent , svFileGroup , svFile;
+ begin
+
+ svComponent = "";
+ svFileGroup = "";
+ svFile = "";
+
+ switch (nResult)
+ case 0:
+ return 0;
+ default:
+ ComponentError ( MEDIA , svComponent , svFileGroup , svFile , nResult );
+ szErrMsg = @ERROR_MOVEDATA + "\n\n" +
+ @ERROR_COMPONENT + " " + svComponent + "\n" +
+ @ERROR_FILEGROUP + " " + svFileGroup + "\n" +
+ @ERROR_FILE + " " + svFile;
+ SprintfBox( SEVERE, @TITLE_CAPTIONBAR, szErrMsg, nResult );
+ bInstallAborted = TRUE;
+ return nResult;
+ endswitch;
+
+ end;
+
+///////////////////////////////////////////////////////////////////////////////
+// //
+// Function: ProcessAfterDataMove //
+// //
+// Purpose: This function performs any necessary operations needed after //
+// all data has been moved. //
+// //
+///////////////////////////////////////////////////////////////////////////////
+function ProcessAfterDataMove()
+ begin
+
+ // TODO : update self-registered files and other processes that
+ // should be performed after the data has been moved.
+
+
+ return 0;
+ end;
+
+///////////////////////////////////////////////////////////////////////////////
+// //
+// Function: SetupRegistry //
+// //
+// Purpose: This function makes the registry entries for this setup. //
+// //
+///////////////////////////////////////////////////////////////////////////////
+function SetupRegistry()
+ NUMBER nResult;
+
+ begin
+
+ // TODO : Add all your registry entry keys here
+ //
+ //
+ // RegDBCreateKeyEx, RegDBSetKeyValueEx....
+ //
+
+ nResult = CreateRegistrySet( "" );
+
+ return nResult;
+ end;
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Function: SetupFolders
+//
+// Purpose: This function creates all the folders and shortcuts for the
+// setup. This includes program groups and items for Windows 3.1.
+//
+///////////////////////////////////////////////////////////////////////////////
+function SetupFolders()
+ NUMBER nResult;
+
+ begin
+
+
+ // TODO : Add all your folder (program group) along with shortcuts (program items)
+ //
+ //
+ // CreateProgramFolder, AddFolderIcon....
+ //
+
+ nResult = CreateShellObjects( "" );
+
+ return nResult;
+ end;
+
+///////////////////////////////////////////////////////////////////////////////
+// //
+// Function: CleanUpInstall //
+// //
+// Purpose: This cleans up the setup. Anything that should //
+// be released or deleted at the end of the setup should //
+// be done here. //
+// //
+///////////////////////////////////////////////////////////////////////////////
+function CleanUpInstall()
+ begin
+
+
+ if (bInstallAborted) then
+ return 0;
+ endif;
+
+ DialogShowSdFinishReboot();
+
+ if (BATCH_INSTALL) then // ensure locked files are properly written
+ CommitSharedFiles(0);
+ endif;
+
+ return 0;
+ end;
+
+///////////////////////////////////////////////////////////////////////////////
+// //
+// Function: SetupInstall //
+// //
+// Purpose: This will setup the installation. Any general initialization //
+// needed for the installation should be performed here. //
+// //
+///////////////////////////////////////////////////////////////////////////////
+function SetupInstall()
+ begin
+
+ Enable( CORECOMPONENTHANDLING );
+
+ bInstallAborted = FALSE;
+
+ if (bIs32BitSetup) then
+ svDir = "C:\\mysql"; //PROGRAMFILES ^ @COMPANY_NAME ^ @PRODUCT_NAME;
+ else
+ svDir = "C:\\mysql"; //PROGRAMFILES ^ @COMPANY_NAME16 ^ @PRODUCT_NAME16; // use shorten names
+ endif;
+
+ TARGETDIR = svDir;
+
+ SdProductName( @PRODUCT_NAME );
+
+ Enable( DIALOGCACHE );
+
+ return 0;
+ end;
+
+///////////////////////////////////////////////////////////////////////////////
+// //
+// Function: SetupScreen //
+// //
+// Purpose: This function establishes the screen look. This includes //
+// colors, fonts, and text to be displayed. //
+// //
+///////////////////////////////////////////////////////////////////////////////
+function SetupScreen()
+ begin
+
+ Enable( FULLWINDOWMODE );
+ Enable( INDVFILESTATUS );
+ SetTitle( @TITLE_MAIN, 24, WHITE );
+
+ SetTitle( @TITLE_CAPTIONBAR, 0, BACKGROUNDCAPTION ); // Caption bar text.
+
+ Enable( BACKGROUND );
+
+ Delay( 1 );
+ end;
+
+///////////////////////////////////////////////////////////////////////////////
+// //
+// Function: CheckRequirements //
+// //
+// Purpose: This function checks all minimum requirements for the //
+// application being installed. If any fail, then the user //
+// is informed and the setup is terminated. //
+// //
+///////////////////////////////////////////////////////////////////////////////
+function CheckRequirements()
+ NUMBER nvDx, nvDy, nvResult;
+ STRING svResult;
+
+ begin
+
+ bWinNT = FALSE;
+ bIsShellExplorer = FALSE;
+
+ // Check screen resolution.
+ GetExtents( nvDx, nvDy );
+
+ if (nvDy < 480) then
+ MessageBox( @ERROR_VGARESOLUTION, WARNING );
+ abort;
+ endif;
+
+ // set 'setup' operation mode
+ bIs32BitSetup = TRUE;
+ GetSystemInfo( ISTYPE, nvResult, svResult );
+ if (nvResult = 16) then
+ bIs32BitSetup = FALSE; // running 16-bit setup
+ return 0; // no additional information required
+ endif;
+
+ // --- 32-bit testing after this point ---
+
+ // Determine the target system's operating system.
+ GetSystemInfo( OS, nvResult, svResult );
+
+ if (nvResult = IS_WINDOWSNT) then
+ // Running Windows NT.
+ bWinNT = TRUE;
+
+ // Check to see if the shell being used is EXPLORER shell.
+ if (GetSystemInfo( OSMAJOR, nvResult, svResult ) = 0) then
+ if (nvResult >= 4) then
+ bIsShellExplorer = TRUE;
+ endif;
+ endif;
+
+ elseif (nvResult = IS_WINDOWS95 ) then
+ bIsShellExplorer = TRUE;
+
+ endif;
+
+end;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// //
+// Function: DialogShowSdWelcome //
+// //
+// Purpose: This function handles the standard welcome dialog. //
+// //
+// //
+///////////////////////////////////////////////////////////////////////////////
+function DialogShowSdWelcome()
+ NUMBER nResult;
+ STRING szTitle, szMsg;
+ begin
+
+ szTitle = "";
+ szMsg = "";
+ nResult = SdWelcome( szTitle, szMsg );
+
+ return nResult;
+ end;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// //
+// Function: DialogShowSdShowInfoList //
+// //
+// Purpose: This function displays the general information list dialog. //
+// //
+// //
+///////////////////////////////////////////////////////////////////////////////
+function DialogShowSdShowInfoList()
+ NUMBER nResult;
+ LIST list;
+ STRING szTitle, szMsg, szFile;
+ begin
+
+ szFile = SUPPORTDIR ^ "infolist.txt";
+
+ list = ListCreate( STRINGLIST );
+ ListReadFromFile( list, szFile );
+ szTitle = "";
+ szMsg = " ";
+ nResult = SdShowInfoList( szTitle, szMsg, list );
+
+ ListDestroy( list );
+
+ return nResult;
+ end;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// //
+// Function: DialogShowSdAskDestPath //
+// //
+// Purpose: This function asks the user for the destination directory. //
+// //
+///////////////////////////////////////////////////////////////////////////////
+function DialogShowSdAskDestPath()
+ NUMBER nResult;
+ STRING szTitle, szMsg;
+ begin
+
+ szTitle = "";
+ szMsg = "";
+ nResult = SdAskDestPath( szTitle, szMsg, svDir, 0 );
+
+ TARGETDIR = svDir;
+
+ return nResult;
+ end;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// //
+// Function: DialogShowSdSetupType //
+// //
+// Purpose: This function displays the standard setup type dialog. //
+// //
+///////////////////////////////////////////////////////////////////////////////
+function DialogShowSdSetupType()
+ NUMBER nResult, nType;
+ STRING szTitle, szMsg;
+ begin
+
+ switch (svSetupType)
+ case "Typical":
+ nType = TYPICAL;
+ case "Custom":
+ nType = CUSTOM;
+ case "Compact":
+ nType = COMPACT;
+ case "":
+ svSetupType = "Typical";
+ nType = TYPICAL;
+ endswitch;
+
+ szTitle = "";
+ szMsg = "";
+ nResult = SetupType( szTitle, szMsg, "", nType, 0 );
+
+ switch (nResult)
+ case COMPACT:
+ svSetupType = "Compact";
+ case TYPICAL:
+ svSetupType = "Typical";
+ case CUSTOM:
+ svSetupType = "Custom";
+ endswitch;
+
+ return nResult;
+ end;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// //
+// Function: DialogShowSdComponentDialog2 //
+// //
+// Purpose: This function displays the custom component dialog. //
+// //
+// //
+///////////////////////////////////////////////////////////////////////////////
+function DialogShowSdComponentDialog2()
+ NUMBER nResult;
+ STRING szTitle, szMsg;
+ begin
+
+ if ((svSetupType != "Custom") && (svSetupType != "")) then
+ return 0;
+ endif;
+
+ szTitle = "";
+ szMsg = "";
+ nResult = SdComponentDialog2( szTitle, szMsg, svDir, "" );
+
+ return nResult;
+ end;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// //
+// Function: DialogShowSdFinishReboot //
+// //
+// Purpose: This function will show the last dialog of the product. //
+// It will allow the user to reboot and/or show some readme text. //
+// //
+///////////////////////////////////////////////////////////////////////////////
+function DialogShowSdFinishReboot()
+ NUMBER nResult, nDefOptions;
+ STRING szTitle, szMsg1, szMsg2, szOption1, szOption2;
+ NUMBER bOpt1, bOpt2;
+ begin
+
+ if (!BATCH_INSTALL) then
+ bOpt1 = FALSE;
+ bOpt2 = FALSE;
+ szMsg1 = "";
+ szMsg2 = "";
+ szOption1 = "";
+ szOption2 = "";
+ nResult = SdFinish( szTitle, szMsg1, szMsg2, szOption1, szOption2, bOpt1, bOpt2 );
+ return 0;
+ endif;
+
+ nDefOptions = SYS_BOOTMACHINE;
+ szTitle = "";
+ szMsg1 = "";
+ szMsg2 = "";
+ nResult = SdFinishReboot( szTitle, szMsg1, nDefOptions, szMsg2, 0 );
+
+ return nResult;
+ end;
+
+ // --- include script file section ---
+
+#include "sddialog.rul"
+
+
diff --git a/VC++Files/client/mysql.dsp b/VC++Files/client/mysql.dsp
new file mode 100644
index 00000000000..1cefdd2b67b
--- /dev/null
+++ b/VC++Files/client/mysql.dsp
@@ -0,0 +1,102 @@
+# Microsoft Developer Studio Project File - Name="mysql" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=mysql - 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 "mysql.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 "mysql.mak" CFG="mysql - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mysql - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "mysql - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "mysql - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /WX /O2 /I "../include" /I "../" /D "NDEBUG" /D "DBUG_OFF" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 mysqlclient.lib wsock32.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 /out:"../client_release/mysql.exe" /libpath:"..\lib_release\\"
+# SUBTRACT LINK32 /incremental:yes
+
+!ELSEIF "$(CFG)" == "mysql - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "mysql___"
+# PROP BASE Intermediate_Dir "mysql___"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MTd /W3 /Gm /ZI /Od /I "../include" /I "../" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 mysqlclient.lib wsock32.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 /incremental:no /debug /machine:I386 /out:"../client_debug/mysql.exe" /pdbtype:sept /libpath:"..\lib_debug\\"
+
+!ENDIF
+
+# Begin Target
+
+# Name "mysql - Win32 Release"
+# Name "mysql - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\mysql.cpp
+
+!IF "$(CFG)" == "mysql - Win32 Release"
+
+# ADD CPP /Zi /O2
+
+!ELSEIF "$(CFG)" == "mysql - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# End Target
+# End Project
diff --git a/VC++Files/client/mysqladmin.dsp b/VC++Files/client/mysqladmin.dsp
new file mode 100644
index 00000000000..82794da57cb
--- /dev/null
+++ b/VC++Files/client/mysqladmin.dsp
@@ -0,0 +1,92 @@
+# Microsoft Developer Studio Project File - Name="mysqladmin" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=mysqladmin - 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 "mysqladmin.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 "mysqladmin.mak" CFG="mysqladmin - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mysqladmin - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "mysqladmin - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "mysqladmin - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../" /D "NDEBUG" /D "DBUG_OFF" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 mysqlclient.lib wsock32.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 /out:"../client_release/mysqladmin.exe" /libpath:"..\lib_release\\"
+
+!ELSEIF "$(CFG)" == "mysqladmin - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "mysqladm"
+# PROP BASE Intermediate_Dir "mysqladm"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MTd /W3 /Gm /ZI /Od /I "../include" /I "../" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 mysqlclient.lib wsock32.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 /incremental:no /debug /machine:I386 /out:"../client_debug/mysqladmin.exe" /pdbtype:sept /libpath:"..\lib_debug\\"
+
+!ENDIF
+
+# Begin Target
+
+# Name "mysqladmin - Win32 Release"
+# Name "mysqladmin - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\mysqladmin.c
+# End Source File
+# End Target
+# End Project
diff --git a/VC++Files/client/mysqlclient.dsp b/VC++Files/client/mysqlclient.dsp
new file mode 100644
index 00000000000..376febc6d36
--- /dev/null
+++ b/VC++Files/client/mysqlclient.dsp
@@ -0,0 +1,494 @@
+# Microsoft Developer Studio Project File - Name="mysqlclient" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=mysqlclient - 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 "mysqlclient.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 "mysqlclient.mak" CFG="mysqlclient - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mysqlclient - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "mysqlclient - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "mysqlclient - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "release"
+# PROP Intermediate_Dir "release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../" /D "NDEBUG" /D "DBUG_OFF" /D "_WINDOWS" /D "USE_TLS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_release\mysqlclient.lib"
+
+!ELSEIF "$(CFG)" == "mysqlclient - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "debug"
+# PROP Intermediate_Dir "debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /G6 /MTd /W3 /ZI /Od /I "../include" /I "../" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_WINDOWS" /D "USE_TLS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_debug\mysqlclient.lib"
+
+!ENDIF
+
+# Begin Target
+
+# Name "mysqlclient - Win32 Release"
+# Name "mysqlclient - Win32 Debug"
+# Begin Source File
+
+SOURCE=..\mysys\array.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\bchange.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\bmove.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\bmove_upp.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\charset.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\completion_hash.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\completion_hash.h
+# End Source File
+# Begin Source File
+
+SOURCE="..\strings\ctype-big5.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\strings\ctype-czech.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\strings\ctype-euc_kr.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\strings\ctype-gb2312.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\strings\ctype-gbk.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\strings\ctype-latin1_de.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\strings\ctype-sjis.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\strings\ctype-tis620.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\strings\ctype-ujis.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\ctype.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\dbug\dbug.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\default.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\libmysql\errmsg.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\errors.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\libmysql\get_password.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\getopt.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\getopt1.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\getvar.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\int2str.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\is_prefix.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\libmysql\libmysql.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\list.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\llstr.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\longlong2str.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\mf_cache.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\mf_casecnv.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\mf_dirname.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\mf_fn_ext.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\mf_format.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\mf_iocache.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\mf_loadpath.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\mf_pack.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\mf_path.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\mf_tempfile.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\mf_unixpath.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\mf_wcomp.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\mulalloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_alloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_compress.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_create.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_delete.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_div.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_error.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_fopen.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_fstream.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_getwd.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_init.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_lib.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_malloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_messnc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_net.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_once.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_open.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_pread.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_pthread.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_read.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_realloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_rename.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_seek.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_static.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_symlink.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_symlink2.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_tempnam.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_thr_init.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_wincond.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_winthread.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_write.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mysys_priv.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\libmysql\net.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\libmysql\password.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\readline.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\safemalloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\select_test.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_string.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_string.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\str2int.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\strcend.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\strcont.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\strend.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\strfill.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\string.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\strinstr.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\strmake.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\strmov.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\strnlen.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\strnmov.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\strtoll.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\strtoull.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\strxmov.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\thr_mutex.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\typelib.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\vio\vio.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\vio\viosocket.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\vio\viossl.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\vio\viosslfactories.c
+# End Source File
+# End Target
+# End Project
diff --git a/VC++Files/client/mysqlclient.dsw b/VC++Files/client/mysqlclient.dsw
new file mode 100644
index 00000000000..9c08bbf0407
--- /dev/null
+++ b/VC++Files/client/mysqlclient.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 5.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "mysqlclient"=".\mysqlclient.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/VC++Files/client/mysqldump.dsp b/VC++Files/client/mysqldump.dsp
new file mode 100644
index 00000000000..dcf1c1435a6
--- /dev/null
+++ b/VC++Files/client/mysqldump.dsp
@@ -0,0 +1,102 @@
+# Microsoft Developer Studio Project File - Name="mysqldump" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=mysqldump - 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 "mysqldump.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 "mysqldump.mak" CFG="mysqldump - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mysqldump - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "mysqldump - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "mysqldump - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /GX- /O2 /I "../include" /I "../" /D "NDEBUG" /D "DBUG_OFF" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 mysqlclient.lib wsock32.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 /out:"../client_release/mysqldump.exe" /libpath:"..\lib_release\\"
+
+!ELSEIF "$(CFG)" == "mysqldump - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "mysqldum"
+# PROP BASE Intermediate_Dir "mysqldum"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MTd /W3 /Gm /GX- /ZI /Od /I "../include" /I "../" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 mysqlclient.lib wsock32.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 /out:"../client_debug/mysqldump.exe" /pdbtype:sept /libpath:"..\lib_debug\\"
+
+!ENDIF
+
+# Begin Target
+
+# Name "mysqldump - Win32 Release"
+# Name "mysqldump - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\mysqldump.c
+
+!IF "$(CFG)" == "mysqldump - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldump - Win32 Debug"
+
+# ADD CPP /W3
+# SUBTRACT CPP /YX
+
+!ENDIF
+
+# End Source File
+# End Target
+# End Project
diff --git a/VC++Files/client/mysqlimport.dsp b/VC++Files/client/mysqlimport.dsp
new file mode 100644
index 00000000000..f10c1f90f58
--- /dev/null
+++ b/VC++Files/client/mysqlimport.dsp
@@ -0,0 +1,93 @@
+# Microsoft Developer Studio Project File - Name="mysqlimport" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=mysqlimport - 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 "mysqlimport.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 "mysqlimport.mak" CFG="mysqlimport - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mysqlimport - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "mysqlimport - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "mysqlimport - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /GX- /O2 /I "../include" /I "../" /D "NDEBUG" /D "DBUG_OFF" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 mysqlclient.lib wsock32.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 /out:"../client_release/mysqlimport.exe" /libpath:"..\lib_release\\"
+# SUBTRACT LINK32 /incremental:yes
+
+!ELSEIF "$(CFG)" == "mysqlimport - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "mysqlimp"
+# PROP BASE Intermediate_Dir "mysqlimp"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MTd /W3 /Gm /GX- /ZI /Od /I "../include" /I "../" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 mysqlclient.lib wsock32.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 setargv.obj /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"../client_debug/mysqlimport.exe" /pdbtype:sept /libpath:"..\lib_debug\\"
+
+!ENDIF
+
+# Begin Target
+
+# Name "mysqlimport - Win32 Release"
+# Name "mysqlimport - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\mysqlimport.c
+# End Source File
+# End Target
+# End Project
diff --git a/VC++Files/client/mysqlshow.dsp b/VC++Files/client/mysqlshow.dsp
new file mode 100644
index 00000000000..dd0fc09c70f
--- /dev/null
+++ b/VC++Files/client/mysqlshow.dsp
@@ -0,0 +1,92 @@
+# Microsoft Developer Studio Project File - Name="mysqlshow" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=mysqlshow - 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 "mysqlshow.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 "mysqlshow.mak" CFG="mysqlshow - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mysqlshow - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "mysqlshow - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "mysqlshow - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /GX- /O2 /I "../include" /I "../" /D "NDEBUG" /D "DBUG_OFF" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 mysqlclient.lib wsock32.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 /out:"../client_release/mysqlshow.exe" /libpath:"..\lib_release\\"
+
+!ELSEIF "$(CFG)" == "mysqlshow - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "mysqlsho"
+# PROP BASE Intermediate_Dir "mysqlsho"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MTd /W3 /Gm /GX- /ZI /Od /I "../include" /I "../" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 mysqlclient.lib wsock32.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 /out:"../client_debug/mysqlshow.exe" /pdbtype:sept /libpath:"..\lib_debug\\"
+
+!ENDIF
+
+# Begin Target
+
+# Name "mysqlshow - Win32 Release"
+# Name "mysqlshow - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\mysqlshow.c
+# End Source File
+# End Target
+# End Project
diff --git a/VC++Files/dbug/dbug.dsp b/VC++Files/dbug/dbug.dsp
new file mode 100644
index 00000000000..11721da98d6
--- /dev/null
+++ b/VC++Files/dbug/dbug.dsp
@@ -0,0 +1,98 @@
+# Microsoft Developer Studio Project File - Name="dbug" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=dbug - 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 "dbug.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 "dbug.mak" CFG="dbug - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "dbug - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "dbug - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "dbug - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "release"
+# PROP Intermediate_Dir "release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /D "NDEBUG" /D "DBUG_OFF" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_release\dbug.lib"
+
+!ELSEIF "$(CFG)" == "dbug - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "debug"
+# PROP Intermediate_Dir "debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /G6 /MTd /W3 /Z7 /Od /Gf /I "../include" /D "__WIN32__" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_debug\dbug.lib"
+
+!ENDIF
+
+# Begin Target
+
+# Name "dbug - Win32 Release"
+# Name "dbug - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\dbug.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\factorial.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\sanity.c
+# End Source File
+# End Target
+# End Project
diff --git a/VC++Files/dbug/dbug.dsw b/VC++Files/dbug/dbug.dsw
new file mode 100644
index 00000000000..a0cd4da7891
--- /dev/null
+++ b/VC++Files/dbug/dbug.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 5.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "dbug"=".\dbug.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/VC++Files/heap/heap.dsp b/VC++Files/heap/heap.dsp
new file mode 100644
index 00000000000..c21c3139519
--- /dev/null
+++ b/VC++Files/heap/heap.dsp
@@ -0,0 +1,195 @@
+# Microsoft Developer Studio Project File - Name="heap" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=heap - 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 "heap.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 "heap.mak" CFG="heap - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "heap - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "heap - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "heap - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "release"
+# PROP Intermediate_Dir "release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /D "NDEBUG" /D "DBUG_OFF" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_release\heap.lib"
+
+!ELSEIF "$(CFG)" == "heap - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "debug"
+# PROP Intermediate_Dir "debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /G6 /MTd /W3 /Z7 /Od /Gf /I "../include" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_debug\heap.lib"
+
+!ENDIF
+
+# Begin Target
+
+# Name "heap - Win32 Release"
+# Name "heap - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\_check.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\_rectest.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\heapdef.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\hp_block.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\hp_clear.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\hp_close.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\hp_create.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\hp_delete.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\hp_extra.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\hp_hash.c
+
+!IF "$(CFG)" == "heap - Win32 Release"
+
+!ELSEIF "$(CFG)" == "heap - Win32 Debug"
+
+# SUBTRACT CPP /YX
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\hp_info.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\hp_open.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\hp_panic.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\hp_rename.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\hp_rfirst.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\hp_rkey.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\hp_rlast.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\hp_rnext.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\hp_rprev.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\hp_rrnd.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\hp_rsame.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\hp_scan.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\hp_static.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\hp_update.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\hp_write.c
+# End Source File
+# End Target
+# End Project
diff --git a/VC++Files/innobase/innobase.dsp b/VC++Files/innobase/innobase.dsp
new file mode 100644
index 00000000000..5159d513e87
--- /dev/null
+++ b/VC++Files/innobase/innobase.dsp
@@ -0,0 +1,441 @@
+# Microsoft Developer Studio Project File - Name="innobase" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=innobase - Win32 Max
+!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 "innobase.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 "innobase.mak" CFG="innobase - Win32 Max"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "innobase - Win32 Max" (based on "Win32 (x86) Static Library")
+!MESSAGE "innobase - Win32 Max nt" (based on "Win32 (x86) Static Library")
+!MESSAGE "innobase - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "innobase - Win32 Max"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "innobase___Win32_Max"
+# PROP BASE Intermediate_Dir "innobase___Win32_Max"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "innobase___Win32_Max"
+# PROP Intermediate_Dir "innobase___Win32_Max"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /G6 /MT /W3 /GX /O2 /I "../innobase/include" /D "NDEBUG" /D "_LIB" /D "_WIN32" /D "__NT__" /D "WIN32" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /GX /O2 /I "../innobase/include" /I "../include" /D "NDEBUG" /D "_LIB" /D "_WIN32" /D "WIN32" /D "_MBCS" /D "MYSQL_SERVER" /YX /FD /c
+# ADD BASE RSC /l 0x416 /d "NDEBUG"
+# ADD RSC /l 0x416 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo /out:"..\lib_release\innobase-nt.lib"
+# ADD LIB32 /nologo /out:"..\lib_release\innodb.lib"
+
+!ELSEIF "$(CFG)" == "innobase - Win32 Max nt"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "innobase___Win32_Max_nt"
+# PROP BASE Intermediate_Dir "innobase___Win32_Max_nt"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "innobase___Win32_Max_nt"
+# PROP Intermediate_Dir "innobase___Win32_Max_nt"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /G6 /MT /W3 /GX /O2 /I "../innobase/include" /D "NDEBUG" /D "_LIB" /D "_WIN32" /D "__NT__" /D "WIN32" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /GX /O2 /I "../innobase/include" /I "../include" /D "NDEBUG" /D "_LIB" /D "_WIN32" /D "__NT__" /D "WIN32" /D "_MBCS" /D "MYSQL_SERVER" /YX /FD /c
+# ADD BASE RSC /l 0x416 /d "NDEBUG"
+# ADD RSC /l 0x416 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo /out:"..\lib_release\innobase-nt.lib"
+# ADD LIB32 /nologo /out:"..\lib_release\innodb-nt.lib"
+
+!ELSEIF "$(CFG)" == "innobase - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "innobase___Win32_Debug"
+# PROP BASE Intermediate_Dir "innobase___Win32_Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "innobase___Win32_Debug"
+# PROP Intermediate_Dir "innobase___Win32_Debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /G6 /MT /W3 /GX /O2 /I "../innobase/include" /D "NDEBUG" /D "_LIB" /D "_WIN32" /D "__NT__" /D "WIN32" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MTd /W3 /GX /Z7 /O2 /I "../innobase/include" /I "../include" /D "NDEBUG" /D "_LIB" /D "_WIN32" /D "__NT__" /D "WIN32" /D "_MBCS" /D "MYSQL_SERVER" /YX /FD /c
+# ADD BASE RSC /l 0x416 /d "NDEBUG"
+# ADD RSC /l 0x416 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo /out:"..\lib_release\innobase-nt.lib"
+# ADD LIB32 /nologo /out:"..\lib_debug\innodb.lib"
+
+!ENDIF
+
+# Begin Target
+
+# Name "innobase - Win32 Max"
+# Name "innobase - Win32 Max nt"
+# Name "innobase - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\btr\btr0btr.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\btr\btr0cur.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\btr\btr0pcur.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\btr\btr0sea.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\buf\buf0buf.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\buf\buf0flu.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\buf\buf0lru.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\buf\buf0rea.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\com\com0com.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\com\com0shm.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\data\data0data.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\data\data0type.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\dict\dict0boot.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\dict\dict0crea.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\dict\dict0dict.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\dict\dict0load.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\dict\dict0mem.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\dyn\dyn0dyn.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\eval\eval0eval.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\eval\eval0proc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\fil\fil0fil.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\fsp\fsp0fsp.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\fut\fut0fut.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\fut\fut0lst.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ha\ha0ha.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ha\hash0hash.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ibuf\ibuf0ibuf.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\pars\lexyy.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\lock\lock0lock.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\log\log0log.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\log\log0recv.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mach\mach0data.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mem\mem0mem.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mem\mem0pool.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mtr\mtr0log.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mtr\mtr0mtr.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\odbc\odbc0odbc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\os\os0file.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\os\os0proc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\os\os0shm.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\os\os0sync.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\os\os0thread.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\page\page0cur.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\page\page0page.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\pars\pars0grm.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\pars\pars0opt.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\pars\pars0pars.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\pars\pars0sym.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\que\que0que.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\read\read0read.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rem\rem0cmp.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rem\rem0rec.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\row\row0ins.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\row\row0mysql.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\row\row0purge.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\row\row0row.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\row\row0sel.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\row\row0uins.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\row\row0umod.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\row\row0undo.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\row\row0upd.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\row\row0vers.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\srv\srv0que.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\srv\srv0srv.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\srv\srv0start.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\sync\sync0arr.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\sync\sync0ipm.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\sync\sync0rw.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\sync\sync0sync.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\thr\thr0loc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\trx\trx0purge.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\trx\trx0rec.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\trx\trx0roll.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\trx\trx0rseg.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\trx\trx0sys.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\trx\trx0trx.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\trx\trx0undo.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\usr\usr0sess.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ut\ut0byte.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ut\ut0dbg.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ut\ut0mem.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ut\ut0rnd.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ut\ut0ut.c
+# End Source File
+# End Target
+# End Project
diff --git a/VC++Files/isam/isam.dsp b/VC++Files/isam/isam.dsp
new file mode 100644
index 00000000000..32832919654
--- /dev/null
+++ b/VC++Files/isam/isam.dsp
@@ -0,0 +1,206 @@
+# Microsoft Developer Studio Project File - Name="isam" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=isam - 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 "isam.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 "isam.mak" CFG="isam - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "isam - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "isam - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "isam - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "release"
+# PROP Intermediate_Dir "release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /D "NDEBUG" /D "DBUG_OFF" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_release\isam.lib"
+
+!ELSEIF "$(CFG)" == "isam - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "debug"
+# PROP Intermediate_Dir "debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /G6 /MTd /W3 /Z7 /Od /Gf /I "../include" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_Debug\isam.lib"
+
+!ENDIF
+
+# Begin Target
+
+# Name "isam - Win32 Release"
+# Name "isam - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\_cache.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\_dbug.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\_dynrec.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\_key.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\_locking.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\_packrec.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\_page.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\_search.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\_statrec.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\changed.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\close.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\create.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\delete.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\extra.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\info.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\log.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\open.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\panic.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\range.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rfirst.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rkey.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rlast.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rnext.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rprev.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rrnd.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rsame.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rsamepos.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\static.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\update.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\write.c
+# End Source File
+# End Target
+# End Project
diff --git a/VC++Files/isam/isam.dsw b/VC++Files/isam/isam.dsw
new file mode 100644
index 00000000000..6874c8cf4c3
--- /dev/null
+++ b/VC++Files/isam/isam.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 5.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "isam"=".\isam.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/VC++Files/isamchk/isamchk.dsp b/VC++Files/isamchk/isamchk.dsp
new file mode 100644
index 00000000000..7b9c03f23f4
--- /dev/null
+++ b/VC++Files/isamchk/isamchk.dsp
@@ -0,0 +1,98 @@
+# Microsoft Developer Studio Project File - Name="isamchk" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=isamchk - 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 "isamchk.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 "isamchk.mak" CFG="isamchk - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "isamchk - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "isamchk - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "isamchk - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../isam" /D "NDEBUG" /D "DBUG_OFF" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x41d /d "NDEBUG"
+# ADD RSC /l 0x41d /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 wsock32.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 setargv.obj /nologo /subsystem:console /machine:I386 /out:"../client_release/isamchk.exe"
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "isamchk - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "isamchk_"
+# PROP BASE Intermediate_Dir "isamchk_"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MTd /W3 /Gm /ZI /Od /I "../include" /I "../isam" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /Fr /YX
+# ADD BASE RSC /l 0x41d /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib wsock32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib setargv.obj /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"../client_debug/isamchk.exe" /pdbtype:sept
+# SUBTRACT LINK32 /verbose /pdb:none
+
+!ENDIF
+
+# Begin Target
+
+# Name "isamchk - Win32 Release"
+# Name "isamchk - Win32 Debug"
+# Begin Source File
+
+SOURCE=..\isam\isamchk.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\isam\sort.c
+# End Source File
+# End Target
+# End Project
diff --git a/VC++Files/libmysql/libmySQL.dsp b/VC++Files/libmysql/libmySQL.dsp
new file mode 100644
index 00000000000..9ea68943a97
--- /dev/null
+++ b/VC++Files/libmysql/libmySQL.dsp
@@ -0,0 +1,465 @@
+# Microsoft Developer Studio Project File - Name="libmySQL" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=libmySQL - 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 "libmySQL.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 "libmySQL.mak" CFG="libmySQL - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libmySQL - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "libmySQL - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "libmySQL - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "." /I "..\include" /D "NDEBUG" /D "DBUG_OFF" /D "_WINDOWS" /D "USE_TLS" /FD /c
+# SUBTRACT CPP /YX
+# 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"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 wsock32.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:windows /dll /machine:I386 /def:"libmysql.def" /out:"../lib_release/libmySQL.dll" /libpath:"." /libpath:"..\lib_release"
+# SUBTRACT LINK32 /pdb:none
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PostBuild_Desc=Move DLL export lib
+PostBuild_Cmds=copy release\libmysql.lib ..\lib_release
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "libmySQL - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /G6 /MTd /W3 /Gm /ZI /Od /I "." /I "..\include" /D "_DEBUG" /D "_WINDOWS" /D "SAFE_MUTEX" /D "USE_TLS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 zlib.lib wsock32.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:windows /dll /incremental:no /map /debug /machine:I386 /def:"libmysql.def" /out:"../lib_debug/libmySQL.dll" /pdbtype:sept /libpath:"." /libpath:"..\lib_debug"
+# SUBTRACT LINK32 /pdb:none
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PostBuild_Desc=Move DLL export lib
+PostBuild_Cmds=copy ..\lib_debug\libmysql.dll C:\winnt\system32 copy debug\libmysql.lib ..\lib_debug
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "libmySQL - Win32 Release"
+# Name "libmySQL - Win32 Debug"
+# Begin Source File
+
+SOURCE=..\mysys\array.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\bchange.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\bmove.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\bmove_upp.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\charset.c
+# End Source File
+# Begin Source File
+
+SOURCE="..\strings\ctype-big5.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\strings\ctype-czech.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\strings\ctype-euc_kr.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\strings\ctype-gb2312.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\strings\ctype-gbk.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\strings\ctype-latin1_de.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\strings\ctype-sjis.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\strings\ctype-tis620.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\strings\ctype-ujis.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\ctype.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\dbug\dbug.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\default.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\dll.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\errmsg.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\errors.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\get_password.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\int2str.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\is_prefix.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\libmysql.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\Libmysql.def
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\list.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\llstr.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\longlong2str.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\mf_casecnv.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\mf_dirname.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\mf_fn_ext.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\mf_format.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\mf_loadpath.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\mf_pack.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\mf_unixpath.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\mf_wcomp.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\mulalloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_alloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_compress.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_create.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_delete.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_div.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_error.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_fopen.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_fstream.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_getwd.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_init.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_lib.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_malloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_messnc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_net.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_once.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_open.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_pthread.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_read.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_realloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_rename.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_static.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_symlink.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_symlink2.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_tempnam.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_thr_init.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_wincond.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_winthread.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\my_write.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\client\mysys_priv.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\net.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\password.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\safemalloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\client\select_test.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\client\sql_string.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\client\sql_string.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\str2int.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\strcend.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\strcont.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\strend.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\strfill.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\string.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\strinstr.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\strmake.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\strmov.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\strnlen.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\strnmov.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\strings\strxmov.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\thr_mutex.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mysys\typelib.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\vio\vio.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\vio\viosocket.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\vio\viossl.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\vio\viosslfactories.c
+# End Source File
+# End Target
+# End Project
diff --git a/VC++Files/libmysql/libmysql.dsw b/VC++Files/libmysql/libmysql.dsw
new file mode 100644
index 00000000000..fe121fa65cc
--- /dev/null
+++ b/VC++Files/libmysql/libmysql.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 5.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "libmySQL"=".\libmySQL.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/VC++Files/libmysqltest/myTest.dsp b/VC++Files/libmysqltest/myTest.dsp
new file mode 100644
index 00000000000..fec250e7a40
--- /dev/null
+++ b/VC++Files/libmysqltest/myTest.dsp
@@ -0,0 +1,92 @@
+# Microsoft Developer Studio Project File - Name="myTest" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=myTest - 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 "myTest.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 "myTest.mak" CFG="myTest - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "myTest - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "myTest - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "myTest - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /W3 /O2 /I "..\include" /D "NDEBUG" /D "DBUG_UFF" /D "_CONSOLE" /D "_MBCS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 libmysql.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 /libpath:"..\lib_release"
+
+!ELSEIF "$(CFG)" == "myTest - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MTd /W3 /Gm /ZI /Od /I "..\include" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c
+# SUBTRACT CPP /Fr /YX
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 libmysql.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 /incremental:no /debug /machine:I386 /pdbtype:sept /libpath:"..\lib_debug"
+
+!ENDIF
+
+# Begin Target
+
+# Name "myTest - Win32 Release"
+# Name "myTest - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\Mytest.c
+# End Source File
+# End Target
+# End Project
diff --git a/VC++Files/libmysqltest/mytest.dsw b/VC++Files/libmysqltest/mytest.dsw
new file mode 100644
index 00000000000..621899eb4d0
--- /dev/null
+++ b/VC++Files/libmysqltest/mytest.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 5.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "myTest"=".\myTest.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/VC++Files/merge/merge.dsp b/VC++Files/merge/merge.dsp
new file mode 100644
index 00000000000..cb6042e6b68
--- /dev/null
+++ b/VC++Files/merge/merge.dsp
@@ -0,0 +1,142 @@
+# Microsoft Developer Studio Project File - Name="merge" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=merge - 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 "merge.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 "merge.mak" CFG="merge - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "merge - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "merge - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "merge - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "release"
+# PROP Intermediate_Dir "release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /D "NDEBUG" /D "DBUG_OFF" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_release\merge.lib"
+
+!ELSEIF "$(CFG)" == "merge - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "debug"
+# PROP Intermediate_Dir "debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /G6 /MTd /W3 /Z7 /Od /Gf /I "../include" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_debug\merge.lib"
+
+!ENDIF
+
+# Begin Target
+
+# Name "merge - Win32 Release"
+# Name "merge - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\mrg_close.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mrg_create.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mrg_def.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\mrg_delete.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mrg_extra.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mrg_info.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mrg_locking.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mrg_open.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mrg_panic.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mrg_rrnd.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mrg_rsame.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mrg_static.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mrg_update.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mrgdef.h
+# End Source File
+# End Target
+# End Project
diff --git a/VC++Files/merge/merge.dsw b/VC++Files/merge/merge.dsw
new file mode 100644
index 00000000000..a2d5ccb2ff2
--- /dev/null
+++ b/VC++Files/merge/merge.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 5.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "merge"=".\merge.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/VC++Files/myisam/myisam.dsp b/VC++Files/myisam/myisam.dsp
new file mode 100644
index 00000000000..5c13f5eb206
--- /dev/null
+++ b/VC++Files/myisam/myisam.dsp
@@ -0,0 +1,292 @@
+# Microsoft Developer Studio Project File - Name="myisam" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=myisam - 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 "myisam.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 "myisam.mak" CFG="myisam - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "myisam - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "myisam - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "myisam - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "release"
+# PROP Intermediate_Dir "release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /D "NDEBUG" /D "DBUG_OFF" /D "_WINDOWS" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_release\myisam.lib"
+
+!ELSEIF "$(CFG)" == "myisam - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "debug"
+# PROP Intermediate_Dir "debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /G6 /MTd /W3 /Z7 /Od /Gf /I "../include" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_WINDOWS" /Fo".\Debug/" /Fd".\Debug/" /FD /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_Debug\myisam.lib"
+
+!ENDIF
+
+# Begin Target
+
+# Name "myisam - Win32 Release"
+# Name "myisam - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\ft_boolean_search.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ft_eval.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ft_nlq_search.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ft_parser.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ft_search.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ft_static.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ft_stem.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ft_stopwords.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ft_update.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_cache.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_changed.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_check.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_checksum.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_close.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_create.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_dbug.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_delete.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_delete_all.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_delete_table.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_dynrec.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_extra.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_info.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_key.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_locking.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_log.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_open.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_packrec.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_page.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_panic.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_range.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_rename.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_rfirst.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_rkey.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_rlast.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_rnext.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_rnext_same.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_rprev.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_rrnd.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_rsame.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_rsamepos.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_scan.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_search.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_static.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_statrec.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_unique.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_update.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mi_write.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\sort.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\ft_eval.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\myisamdef.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/VC++Files/myisamchk/myisamchk.dsp b/VC++Files/myisamchk/myisamchk.dsp
new file mode 100644
index 00000000000..7f0459d21d0
--- /dev/null
+++ b/VC++Files/myisamchk/myisamchk.dsp
@@ -0,0 +1,104 @@
+# Microsoft Developer Studio Project File - Name="myisamchk" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=myisamchk - 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 "myisamchk.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 "myisamchk.mak" CFG="myisamchk - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "myisamchk - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "myisamchk - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "myisamchk - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../myisam" /D "NDEBUG" /D "DBUG_OFF" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FR /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib uuid.lib setargv.obj /nologo /subsystem:console /machine:I386 /out:"../client_release/myisamchk.exe"
+
+!ELSEIF "$(CFG)" == "myisamchk - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /G6 /MTd /W3 /Z7 /Od /I "../include" /I "../myisam" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /Fr
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 wsock32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib setargv.obj /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"../client_debug/myisamchk.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "myisamchk - Win32 Release"
+# Name "myisamchk - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\myisam\myisamchk.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/VC++Files/myisamlog/myisamlog.dsp b/VC++Files/myisamlog/myisamlog.dsp
new file mode 100644
index 00000000000..efc43914759
--- /dev/null
+++ b/VC++Files/myisamlog/myisamlog.dsp
@@ -0,0 +1,105 @@
+# Microsoft Developer Studio Project File - Name="myisamlog" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=myisamlog - 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 "myisamlog.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 "myisamlog.mak" CFG="myisamlog - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "myisamlog - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "myisamlog - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "myisamlog - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../myisam" /D "NDEBUG" /D "DBUG_OFF" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FR /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib uuid.lib setargv.obj /nologo /subsystem:console /pdb:"release/myisamchk.pdb" /machine:I386 /out:"../client_release/myisamlog.exe"
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "myisamlog - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /G6 /MTd /W3 /Z7 /Od /I "../include" /I "../myisam" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /Fr
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 wsock32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib setargv.obj /nologo /subsystem:console /incremental:no /pdb:"debug/myisamchk.pdb" /debug /machine:I386 /out:"../client_debug/myisamlog.exe" /pdbtype:sept
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF
+
+# Begin Target
+
+# Name "myisamlog - Win32 Release"
+# Name "myisamlog - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\myisam\myisamlog.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/VC++Files/myisammrg/myisammrg.dsp b/VC++Files/myisammrg/myisammrg.dsp
new file mode 100644
index 00000000000..e91d1f4e696
--- /dev/null
+++ b/VC++Files/myisammrg/myisammrg.dsp
@@ -0,0 +1,173 @@
+# Microsoft Developer Studio Project File - Name="myisammrg" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=myisammrg - 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 "myisammrg.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 "myisammrg.mak" CFG="myisammrg - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "myisammrg - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "myisammrg - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "myisammrg - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "release"
+# PROP Intermediate_Dir "release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /D "NDEBUG" /D "DBUG_OFF" /D "_WINDOWS" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_release\myisammrg.lib"
+
+!ELSEIF "$(CFG)" == "myisammrg - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "debug"
+# PROP Intermediate_Dir "debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /G6 /MTd /W3 /Z7 /Od /Gf /I "../include" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_WINDOWS" /Fo".\Debug/" /Fd".\Debug/" /FD /c
+# SUBTRACT CPP /Fr
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_Debug\myisammrg.lib"
+
+!ENDIF
+
+# Begin Target
+
+# Name "myisammrg - Win32 Release"
+# Name "myisammrg - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\myrg_close.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\myrg_create.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\myrg_delete.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\myrg_extra.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\myrg_info.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\myrg_locking.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\myrg_open.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\myrg_panic.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\myrg_queue.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\myrg_rfirst.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\myrg_rkey.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\myrg_rlast.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\myrg_rnext.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\myrg_rprev.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\myrg_rrnd.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\myrg_rsame.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\myrg_static.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\myrg_update.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\myrg_write.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\mymrgdef.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/VC++Files/myisampack/myisampack.dsp b/VC++Files/myisampack/myisampack.dsp
new file mode 100644
index 00000000000..5ea392e1b41
--- /dev/null
+++ b/VC++Files/myisampack/myisampack.dsp
@@ -0,0 +1,107 @@
+# Microsoft Developer Studio Project File - Name="myisampack" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=myisampack - 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 "myisampack.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 "myisampack.mak" CFG="myisampack - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "myisampack - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "myisampack - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "myisampack - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../myisam" /D "NDEBUG" /D "DBUG_OFF" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FR /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib uuid.lib setargv.obj /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "myisampack - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /G6 /MTd /W3 /Z7 /Od /I "../include" /I "../myisam" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /Fr
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 wsock32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib setargv.obj /nologo /subsystem:console /incremental:no /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "myisampack - Win32 Release"
+# Name "myisampack - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\myisampack.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\myisampack.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/VC++Files/mysql.dsp b/VC++Files/mysql.dsp
new file mode 100644
index 00000000000..41f2538a7e5
--- /dev/null
+++ b/VC++Files/mysql.dsp
@@ -0,0 +1,80 @@
+# Microsoft Developer Studio Project File - Name="mysql" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) External Target" 0x0106
+
+CFG=mysql - 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 "mysql.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 "mysql.mak" CFG="mysql - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mysql - Win32 Release" (based on "Win32 (x86) External Target")
+!MESSAGE "mysql - Win32 Debug" (based on "Win32 (x86) External Target")
+!MESSAGE
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+
+!IF "$(CFG)" == "mysql - Win32 Release"
+
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Cmd_Line "NMAKE /f mysql.mak"
+# PROP BASE Rebuild_Opt "/a"
+# PROP BASE Target_File "mysql.exe"
+# PROP BASE Bsc_Name "mysql.bsc"
+# PROP BASE Target_Dir ""
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Cmd_Line "NMAKE /f mysql.mak"
+# PROP Rebuild_Opt "/a"
+# PROP Target_File "mysql.exe"
+# PROP Bsc_Name "mysql.bsc"
+# PROP Target_Dir ""
+
+!ELSEIF "$(CFG)" == "mysql - Win32 Debug"
+
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Cmd_Line "NMAKE /f mysql.mak"
+# PROP BASE Rebuild_Opt "/a"
+# PROP BASE Target_File "mysql.exe"
+# PROP BASE Bsc_Name "mysql.bsc"
+# PROP BASE Target_Dir ""
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Cmd_Line "NMAKE /f mysql.mak"
+# PROP Rebuild_Opt "/a"
+# PROP Target_File "mysql.exe"
+# PROP Bsc_Name "mysql.bsc"
+# PROP Target_Dir ""
+
+!ENDIF
+
+# Begin Target
+
+# Name "mysql - Win32 Release"
+# Name "mysql - Win32 Debug"
+
+!IF "$(CFG)" == "mysql - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysql - Win32 Debug"
+
+!ENDIF
+
+# End Target
+# End Project
diff --git a/VC++Files/mysql.dsw b/VC++Files/mysql.dsw
new file mode 100644
index 00000000000..7713b28d978
--- /dev/null
+++ b/VC++Files/mysql.dsw
@@ -0,0 +1,656 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+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>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "dbug"=".\dbug\dbug.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "heap"=".\heap\heap.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "innobase"=".\innobase\innobase.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+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>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name zlib
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "merge"=".\merge\merge.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "myTest"=".\libmysqltest\myTest.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libmySQL
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "myisam"=".\myisam\myisam.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "myisamchk"=".\myisamchk\myisamchk.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name dbug
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name myisam
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name mysys
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name strings
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "myisamlog"=".\myisamlog\myisamlog.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name dbug
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name myisam
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name mysys
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name strings
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "myisammrg"=".\myisammrg\myisammrg.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "myisampack"=".\myisampack\myisampack.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name dbug
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name myisam
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name mysys
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name strings
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "mysql"=".\client\mysql.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name mysqlclient
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "mysqladmin"=".\client\mysqladmin.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name mysqlclient
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name zlib
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "mysqlbinlog"=".\mysqlbinlog\mysqlbinlog.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name mysqlclient
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "mysqlcheck"=".\mysqlcheck\mysqlcheck.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name mysqlclient
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "mysqlclient"=".\client\mysqlclient.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name zlib
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "mysqld"=".\sql\mysqld.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ 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
+ Project_Dep_Name regex
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name strings
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name dbug
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name mysql
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name mysqladmin
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name mysqldump
+ End Project Dependency
+ Begin Project Dependency
+ 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
+ Project_Dep_Name myTest
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name thr_test
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name replace
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name zlib
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name myisam
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name myisammrg
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name innobase
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name bdb
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name vio
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "mysqldump"=".\client\mysqldump.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name mysqlclient
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "mysqlimport"=".\client\mysqlimport.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name mysqlclient
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "mysqlshow"=".\client\mysqlshow.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name mysqlclient
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "mysqlshutdown"=".\mysqlshutdown\mysqlshutdown.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "mysqlwatch"=".\mysqlwatch\mysqlwatch.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "mysys"=".\mysys\mysys.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+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>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name dbug
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name mysys
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name strings
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "regex"=".\regex\regex.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "replace"=".\replace\replace.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name dbug
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name mysys
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name strings
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "strings"=".\strings\strings.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "test1"=".\test1\test1.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libmySQL
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "thr_insert_test"=".\thr_insert_test\thr_insert_test.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name mysqlclient
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "thr_test"=".\thr_test\thr_test.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name dbug
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name mysys
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name strings
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "vio"=".\vio\vio.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "zlib"=".\zlib\zlib.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/VC++Files/mysqlbinlog/mysqlbinlog.dsp b/VC++Files/mysqlbinlog/mysqlbinlog.dsp
new file mode 100644
index 00000000000..4145585abc5
--- /dev/null
+++ b/VC++Files/mysqlbinlog/mysqlbinlog.dsp
@@ -0,0 +1,103 @@
+# Microsoft Developer Studio Project File - Name="mysqlbinlog" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=mysqlbinlog - 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 "mysqlbinlog.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 "mysqlbinlog.mak" CFG="mysqlbinlog - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mysqlbinlog - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "mysqlbinlog - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "mysqlbinlog - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../" /D "NDEBUG" /D "DBUG_OFF" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /D "MYSQL_SERVER" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 mysqlclient.lib wsock32.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 /out:"../client_release/mysqlbinlog.exe" /libpath:"..\lib_release\\"
+# SUBTRACT LINK32 /pdb:none /debug
+
+!ELSEIF "$(CFG)" == "mysqlbinlog - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /G6 /MTd /W3 /Gm /ZI /Od /I "../include" /I "../" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /D "MYSQL_SERVER" /FD /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 mysqlclient.lib wsock32.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 /incremental:no /debug /machine:I386 /out:"../client_debug/mysqlbinlog.exe" /pdbtype:sept /libpath:"..\lib_debug\\"
+
+!ENDIF
+
+# Begin Target
+
+# Name "mysqlbinlog - Win32 Release"
+# Name "mysqlbinlog - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\mysqlbinlog.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/VC++Files/mysqlcheck/mysqlcheck.dsp b/VC++Files/mysqlcheck/mysqlcheck.dsp
new file mode 100644
index 00000000000..49c3fc2b702
--- /dev/null
+++ b/VC++Files/mysqlcheck/mysqlcheck.dsp
@@ -0,0 +1,102 @@
+# Microsoft Developer Studio Project File - Name="mysqlcheck" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=mysqlcheck - 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 "mysqlcheck.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 "mysqlcheck.mak" CFG="mysqlcheck - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mysqlcheck - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "mysqlcheck - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "mysqlcheck - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../" /D "NDEBUG" /D "DBUG_OFF" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /D "MYSQL_SERVER" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 mysqlclient.lib wsock32.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 /out:"../client_release/mysqlcheck.exe" /libpath:"..\lib_release\\"
+
+!ELSEIF "$(CFG)" == "mysqlcheck - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /G6 /MTd /W3 /Gm /ZI /Od /I "../include" /I "../" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /D "MYSQL_SERVER" /FD /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 mysqlclient.lib wsock32.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 /incremental:no /debug /machine:I386 /out:"../client_debug/mysqlcheck.exe" /pdbtype:sept /libpath:"..\lib_debug\\"
+
+!ENDIF
+
+# Begin Target
+
+# Name "mysqlcheck - Win32 Release"
+# Name "mysqlcheck - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\client\mysqlcheck.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/VC++Files/mysqlmanager/MySqlManager.dsp b/VC++Files/mysqlmanager/MySqlManager.dsp
new file mode 100644
index 00000000000..60ee700b00c
--- /dev/null
+++ b/VC++Files/mysqlmanager/MySqlManager.dsp
@@ -0,0 +1,253 @@
+# 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=cl.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 /O1 /I "../include" /D "NDEBUG" /D "DBUG_OFF" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /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=link.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 /Gm /GX /ZI /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=link.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=.\MainFrm.cpp
+# 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
new file mode 100644
index 00000000000..02ec9a86dc5
--- /dev/null
+++ b/VC++Files/mysqlmanager/mysqlmanager.dsw
@@ -0,0 +1,29 @@
+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/mysqlshutdown/myshutdown.dsp b/VC++Files/mysqlshutdown/myshutdown.dsp
new file mode 100644
index 00000000000..390921f599c
--- /dev/null
+++ b/VC++Files/mysqlshutdown/myshutdown.dsp
@@ -0,0 +1,101 @@
+# Microsoft Developer Studio Project File - Name="myshutdown" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=myshutdown - 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 "myshutdown.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 "myshutdown.mak" CFG="myshutdown - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "myshutdown - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "myshutdown - Win32 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)" == "myshutdown - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /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 /nologo /subsystem:windows /machine:I386
+
+!ELSEIF "$(CFG)" == "myshutdown - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /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 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "myshutdown - Win32 Release"
+# Name "myshutdown - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/VC++Files/mysqlshutdown/mysqlshutdown.dsp b/VC++Files/mysqlshutdown/mysqlshutdown.dsp
new file mode 100644
index 00000000000..1489a5547ed
--- /dev/null
+++ b/VC++Files/mysqlshutdown/mysqlshutdown.dsp
@@ -0,0 +1,119 @@
+# Microsoft Developer Studio Project File - Name="mysqlshutdown" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=mysqlshutdown - Win32 Release
+!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 "mysqlshutdown.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 "mysqlshutdown.mak" CFG="mysqlshutdown - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mysqlshutdown - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "mysqlshutdown - Win32 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)" == "mysqlshutdown - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /W3 /GX- /O2 /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /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 /nologo /subsystem:windows /machine:I386 /out:"../client_release/mysqlshutdown.exe"
+
+!ELSEIF "$(CFG)" == "mysqlshutdown - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "mysqlshutdown___Win32_Debug"
+# PROP BASE Intermediate_Dir "mysqlshutdown___Win32_Debug"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "debug"
+# PROP Intermediate_Dir "debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /G6 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c
+# SUBTRACT BASE CPP /YX
+# ADD CPP /nologo /G6 /W3 /GX- /O2 /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"../client_release/mysqlshutdown.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 /nologo /subsystem:windows /machine:I386 /out:"../client_debug/mysqlshutdown.exe"
+
+!ENDIF
+
+# Begin Target
+
+# Name "mysqlshutdown - Win32 Release"
+# Name "mysqlshutdown - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\mysqlshutdown.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mysqlshutdown.rc
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\mysql.ico
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/VC++Files/mysqlwatch/mysqlwatch.dsp b/VC++Files/mysqlwatch/mysqlwatch.dsp
new file mode 100644
index 00000000000..004f444e09b
--- /dev/null
+++ b/VC++Files/mysqlwatch/mysqlwatch.dsp
@@ -0,0 +1,70 @@
+# Microsoft Developer Studio Project File - Name="mysqlwatch" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=mysqlwatch - Win32 Release
+!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 "mysqlwatch.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 "mysqlwatch.mak" CFG="mysqlwatch - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mysqlwatch - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /W3 /GX- /O2 /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 /nologo /subsystem:console /machine:I386 /out:"../client_release/mysqlwatch.exe"
+# Begin Target
+
+# Name "mysqlwatch - Win32 Release"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\mysqlwatch.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/VC++Files/mysys/mysys.dsp b/VC++Files/mysys/mysys.dsp
new file mode 100644
index 00000000000..eb467e55892
--- /dev/null
+++ b/VC++Files/mysys/mysys.dsp
@@ -0,0 +1,507 @@
+# Microsoft Developer Studio Project File - Name="mysys" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=mysys - 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 "mysys.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 "mysys.mak" CFG="mysys - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mysys - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "mysys - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE "mysys - Win32 Max" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "mysys - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "release"
+# PROP Intermediate_Dir "release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /D "NDEBUG" /D "DBUG_OFF" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_release\mysys.lib"
+
+!ELSEIF "$(CFG)" == "mysys - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "debug"
+# PROP Intermediate_Dir "debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /G6 /MTd /W3 /ZI /Od /I "../include" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_WINDOWS" /D "USE_SYMDIR" /FD /c
+# SUBTRACT CPP /Fr
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_debug\mysys.lib"
+
+!ELSEIF "$(CFG)" == "mysys - Win32 Max"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "mysys___Win32_Max"
+# PROP BASE Intermediate_Dir "mysys___Win32_Max"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "mysys___Win32_Max"
+# PROP Intermediate_Dir "mysys___Win32_Max"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /G6 /MT /W3 /O2 /I "../include" /D "NDEBUG" /D "DBUG_OFF" /D "_WINDOWS" /FD /c
+# SUBTRACT BASE CPP /YX
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /D "NDEBUG" /D "DBUG_OFF" /D "_WINDOWS" /D "USE_SYMDIR" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo /out:"..\lib_release\mysys.lib"
+# ADD LIB32 /nologo /out:"..\lib_release\mysys-max.lib"
+
+!ENDIF
+
+# Begin Target
+
+# Name "mysys - Win32 Release"
+# Name "mysys - Win32 Debug"
+# Name "mysys - Win32 Max"
+# Begin Source File
+
+SOURCE=.\array.c
+
+!IF "$(CFG)" == "mysys - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysys - Win32 Debug"
+
+# ADD CPP /FR
+
+!ELSEIF "$(CFG)" == "mysys - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\charset.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\checksum.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\default.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\errors.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\getopt.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\getopt1.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\getvar.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\hash.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\list.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mf_brkhant.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mf_cache.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mf_casecnv.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mf_dirname.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mf_fn_ext.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mf_format.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mf_getdate.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mf_iocache.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mf_iocache2.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mf_keycache.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mf_loadpath.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mf_pack.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mf_pack2.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mf_path.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mf_qsort.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mf_qsort2.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mf_radix.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mf_same.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mf_sort.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mf_soundex.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mf_stripp.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mf_tempfile.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mf_wcomp.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mf_wfile.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mulalloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_alarm.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_alloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_append.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_bit.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_bitmap.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_chsize.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_clock.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_compress.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_copy.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_create.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_delete.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_div.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_error.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_fopen.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_fstream.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_getwd.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_init.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_lib.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_lock.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_lockmem.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_lread.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_lwrite.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_malloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_messnc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_mkdir.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_net.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_once.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_open.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_pread.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_pthread.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_quick.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_read.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_realloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_redel.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_rename.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_seek.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_static.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_static.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_symlink.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_symlink2.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_tempnam.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_thr_init.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_vsnprintf.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_wincond.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_winthread.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_write.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mysys_priv.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ptr_cmp.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\queues.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\raid.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\safemalloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\string.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\thr_alarm.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\thr_lock.c
+
+!IF "$(CFG)" == "mysys - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysys - Win32 Debug"
+
+# ADD CPP /D "EXTRA_DEBUG"
+
+!ELSEIF "$(CFG)" == "mysys - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\thr_mutex.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\thr_rwlock.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tree.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\typelib.c
+# End Source File
+# End Target
+# End Project
diff --git a/VC++Files/mysys/mysys.dsw b/VC++Files/mysys/mysys.dsw
new file mode 100644
index 00000000000..d5064051fc9
--- /dev/null
+++ b/VC++Files/mysys/mysys.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 5.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "mysys"=".\mysys.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/VC++Files/pack_isam/pack_isam.dsp b/VC++Files/pack_isam/pack_isam.dsp
new file mode 100644
index 00000000000..20c832c96d0
--- /dev/null
+++ b/VC++Files/pack_isam/pack_isam.dsp
@@ -0,0 +1,103 @@
+# Microsoft Developer Studio Project File - Name="pack_isam" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=pack_isam - 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 "pack_isam.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 "pack_isam.mak" CFG="pack_isam - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "pack_isam - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "pack_isam - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "pack_isam - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../isam" /D "NDEBUG" /D "DBUG_OFF" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 wsock32.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 setargv.obj /nologo /subsystem:console /machine:I386 /out:"../client_release/pack_isam.exe"
+
+!ELSEIF "$(CFG)" == "pack_isam - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /G6 /MTd /W3 /Gm /ZI /Od /I "../include" /I "../isam" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /Fr
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 wsock32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib setargv.obj /nologo /subsystem:console /debug /machine:I386 /out:"../client_debug/pack_isam.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "pack_isam - Win32 Release"
+# Name "pack_isam - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\pack_isam.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/VC++Files/perror/perror.dsp b/VC++Files/perror/perror.dsp
new file mode 100644
index 00000000000..439fcef1547
--- /dev/null
+++ b/VC++Files/perror/perror.dsp
@@ -0,0 +1,109 @@
+# Microsoft Developer Studio Project File - Name="perror" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=perror - 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 "perror.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 "perror.mak" CFG="perror - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "perror - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "perror - Win32 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)" == "perror - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /GX- /O2 /I "../include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 wsock32.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 /out:"../client_release/perror.exe"
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "perror - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /G6 /MTd /W3 /Gm /GX- /ZI /Od /I "../include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib wsock32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /incremental:no /debug /machine:I386 /pdbtype:sept
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF
+
+# Begin Target
+
+# Name "perror - Win32 Release"
+# Name "perror - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\extra\perror.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/VC++Files/regex/regex.dsp b/VC++Files/regex/regex.dsp
new file mode 100644
index 00000000000..5ee617c58b7
--- /dev/null
+++ b/VC++Files/regex/regex.dsp
@@ -0,0 +1,114 @@
+# Microsoft Developer Studio Project File - Name="regex" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=regex - 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 "regex.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 "regex.mak" CFG="regex - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "regex - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "regex - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "regex - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "release"
+# PROP Intermediate_Dir "release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "./" /D "NDEBUG" /D "DBUG_OFF" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_release\regex.lib"
+
+!ELSEIF "$(CFG)" == "regex - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "debug"
+# PROP Intermediate_Dir "debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /G6 /MTd /W3 /Z7 /Od /Gf /I "../include" /I "./" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_debug\regex.lib"
+
+!ENDIF
+
+# Begin Target
+
+# Name "regex - Win32 Release"
+# Name "regex - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\debug.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\regcomp.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\regerror.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\regexec.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\regfree.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\reginit.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\split.c
+# End Source File
+# End Target
+# End Project
diff --git a/VC++Files/regex/regex.dsw b/VC++Files/regex/regex.dsw
new file mode 100644
index 00000000000..102e07af409
--- /dev/null
+++ b/VC++Files/regex/regex.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 5.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "regex"=".\regex.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/VC++Files/replace/replace.dsp b/VC++Files/replace/replace.dsp
new file mode 100644
index 00000000000..011b62d08ec
--- /dev/null
+++ b/VC++Files/replace/replace.dsp
@@ -0,0 +1,93 @@
+# Microsoft Developer Studio Project File - Name="replace" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=replace - 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 "replace.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 "replace.mak" CFG="replace - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "replace - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "replace - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "replace - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /D "NDEBUG" /D "DBUG_OFF" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 wsock32.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 setargv.obj /nologo /subsystem:console /machine:I386 /out:"../client_release/replace.exe"
+
+!ELSEIF "$(CFG)" == "replace - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MTd /W3 /Gm /ZI /Od /I "../include" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib wsock32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib setargv.obj /nologo /subsystem:console /incremental:no /machine:I386 /out:"../client_debug/replace.exe" /pdbtype:sept
+# SUBTRACT LINK32 /debug
+
+!ENDIF
+
+# Begin Target
+
+# Name "replace - Win32 Release"
+# Name "replace - Win32 Debug"
+# Begin Source File
+
+SOURCE=..\extra\replace.c
+# End Source File
+# End Target
+# End Project
diff --git a/VC++Files/sql/mysqld.dsp b/VC++Files/sql/mysqld.dsp
new file mode 100644
index 00000000000..ec4722d7f27
--- /dev/null
+++ b/VC++Files/sql/mysqld.dsp
@@ -0,0 +1,1281 @@
+# Microsoft Developer Studio Project File - Name="mysqld" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=mysqld - Win32 Release
+!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 "mysqld.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 "mysqld.mak" CFG="mysqld - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mysqld - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "mysqld - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE "mysqld - Win32 nt" (based on "Win32 (x86) Console Application")
+!MESSAGE "mysqld - Win32 Max nt" (based on "Win32 (x86) Console Application")
+!MESSAGE "mysqld - Win32 Max" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /D "NDEBUG" /D "DBUG_OFF" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x410 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /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-opt.exe"
+# SUBTRACT LINK32 /debug
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MTd /W3 /Gm /ZI /Od /I "../include" /I "../regex" /I "../bdb/build_win32" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_INNOBASE_DB" /D "HAVE_BERKELEY_DB" /D "USE_SYMDIR" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /FD /c
+# SUBTRACT CPP /Fr /YX
+# ADD BASE RSC /l 0x410 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /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.exe" /pdbtype:sept
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "mysqld__"
+# PROP BASE Intermediate_Dir "mysqld__"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "NT"
+# PROP Intermediate_Dir "NT"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /G5 /MT /W3 /O2 /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "__WIN32__" /D "DBUG_OFF" /FD /c
+# SUBTRACT BASE CPP /YX
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /D "NDEBUG" /D "__NT__" /D "DBUG_OFF" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x410 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Wsock32.lib ..\lib_release\dbug.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\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"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "mysqld___Win32_Max_nt"
+# PROP BASE Intermediate_Dir "mysqld___Win32_Max_nt"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "mysqld___Win32_Max_nt"
+# PROP Intermediate_Dir "mysqld___Win32_Max_nt"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /D "NDEBUG" /D "__NT__" /D "DBUG_OFF" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /FD /c
+# SUBTRACT BASE CPP /YX
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /I "../bdb/build_win32" /D "NDEBUG" /D "__NT__" /D "DBUG_OFF" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "USE_SYMDIR" /D "HAVE_INNOBASE_DB" /D "HAVE_BERKELEY_DB" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 /out:"../client_release/mysqld-nt.exe"
+# 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-nt.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"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "mysqld___Win32_Max"
+# PROP BASE Intermediate_Dir "mysqld___Win32_Max"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "mysqld___Win32_Max"
+# PROP Intermediate_Dir "mysqld___Win32_Max"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /D "NDEBUG" /D "DBUG_OFF" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /FD /c
+# SUBTRACT BASE CPP /YX
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /I "../bdb/build_win32" /D "NDEBUG" /D "DBUG_OFF" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "USE_SYMDIR" /D "HAVE_INNOBASE_DB" /D "HAVE_BERKELEY_DB" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 /out:"../client_release/mysqld-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\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"
+# SUBTRACT LINK32 /debug
+
+!ENDIF
+
+# Begin Target
+
+# Name "mysqld - Win32 Release"
+# Name "mysqld - Win32 Debug"
+# Name "mysqld - Win32 nt"
+# Name "mysqld - Win32 Max nt"
+# Name "mysqld - Win32 Max"
+# Begin Source File
+
+SOURCE=.\convert.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\derror.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\field.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\field_conv.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\filesort.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\ha_berkeley.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ha_heap.cpp
+# End Source File
+# Begin Source File
+
+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
+
+SOURCE=.\ha_myisammrg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\handler.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\hash_filo.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\hash_filo.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\hostname.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\init.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\item.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\item_buff.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\item_cmpfunc.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\item_create.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\item_func.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\item_strfunc.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\item_sum.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\item_timefunc.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\item_uniq.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\key.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\lock.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\log.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\log_event.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\md5.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mf_iocache.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\mini_client.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\mini_client_errors.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mysqld.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\net_pkg.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\net_serv.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\nt_servc.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\nt_servc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\opt_ft.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\opt_range.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\opt_range.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\OPT_SUM.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\password.c
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\procedure.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\records.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\repl_failsafe.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\slave.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_acl.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_analyse.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_base.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_cache.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_class.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_crypt.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_crypt.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_db.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_delete.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_handler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_insert.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_lex.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_list.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_load.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_manager.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_map.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_parse.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_rename.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_repl.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_select.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_show.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_string.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_table.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_test.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_udf.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_union.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_update.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_yacc.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\table.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\thr_malloc.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\time.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\uniques.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\unireg.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# End Target
+# End Project
diff --git a/VC++Files/sql/mysqldmax.dsp b/VC++Files/sql/mysqldmax.dsp
new file mode 100644
index 00000000000..4d24d033c51
--- /dev/null
+++ b/VC++Files/sql/mysqldmax.dsp
@@ -0,0 +1,1003 @@
+# Microsoft Developer Studio Project File - Name="mysqldmax" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=mysqldmax - 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 "mysqldmax.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 "mysqldmax.mak" CFG="mysqldmax - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mysqldmax - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "mysqldmax - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE "mysqldmax - Win32 nt" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /D "NDEBUG" /D "DBUG_OFF" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_BERKELEY_DB" /D "HAVE_INNOBASE_DB" /FD /c
+# ADD BASE RSC /l 0x416 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /G6 /MTd /W3 /Gm /ZI /Od /I "../include" /I "../regex" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_BERKELEY_DB" /D "HAVE_INNOBASE_DB" /FR /FD /c
+# ADD BASE RSC /l 0x416 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "nt"
+# PROP BASE Intermediate_Dir "nt"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "nt"
+# PROP Intermediate_Dir "nt"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /D "NDEBUG" /D "__NT__" /D "DBUG_OFF" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_BERKELEY_DB" /D "HAVE_INNOBASE_DB" /FD /c
+# ADD BASE RSC /l 0x416 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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"
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF
+
+# Begin Target
+
+# Name "mysqldmax - Win32 Release"
+# Name "mysqldmax - Win32 Debug"
+# Name "mysqldmax - Win32 nt"
+# Begin Source File
+
+SOURCE=.\convert.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\derror.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\field.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\field_conv.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\filesort.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\ha_berkeley.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ha_heap.cpp
+# End Source File
+# Begin Source File
+
+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
+
+SOURCE=.\ha_myisammrg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\handler.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\hash_filo.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\hash_filo.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\hostname.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\init.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\item.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\item_buff.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\item_cmpfunc.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\item_create.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\item_func.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\item_strfunc.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\item_sum.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\item_timefunc.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\item_uniq.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\key.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\lock.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\log.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\log_event.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\md5.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mf_iocache.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\mini_client.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\mini_client_errors.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mysqld.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\net_pkg.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\net_serv.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\nt_servc.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\nt_servc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\opt_ft.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\opt_range.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\opt_range.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\opt_sum.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\password.c
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\procedure.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\records.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\slave.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_acl.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_analyse.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_base.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_cache.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_class.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_crypt.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_crypt.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_db.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_delete.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_insert.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_lex.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_list.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_load.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_manager.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_map.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_parse.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_rename.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_repl.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_select.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_show.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_string.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_table.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_test.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_update.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sql_yacc.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\table.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\thr_malloc.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\time.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\unireg.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\violite.c
+# End Source File
+# End Target
+# End Project
diff --git a/VC++Files/sql/old/mysqld.dsw b/VC++Files/sql/old/mysqld.dsw
new file mode 100644
index 00000000000..ed820ed7a90
--- /dev/null
+++ b/VC++Files/sql/old/mysqld.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 5.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "mysqld"=".\mysqld.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/VC++Files/strings/backup/strings.dsp b/VC++Files/strings/backup/strings.dsp
new file mode 100644
index 00000000000..45b22c52e21
--- /dev/null
+++ b/VC++Files/strings/backup/strings.dsp
@@ -0,0 +1,244 @@
+# Microsoft Developer Studio Project File - Name="strings" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=strings - 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 "strings.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 "strings.mak" CFG="strings - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "strings - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "strings - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "strings - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "release"
+# PROP Intermediate_Dir "release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /D "NDEBUG" /D "DBUG_OFF" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_release\strings.lib"
+
+!ELSEIF "$(CFG)" == "strings - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "debug"
+# PROP Intermediate_Dir "debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /G6 /MTd /W3 /Z7 /Od /Gf /I "../include" /D "_DEBUG" /D "SAFEMALLOC" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_debug\strings.lib"
+
+!ENDIF
+
+# Begin Target
+
+# Name "strings - Win32 Release"
+# Name "strings - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\atof.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\bchange.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\bcmp.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\bfill.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\bmove512.c
+# End Source File
+# Begin Source File
+
+SOURCE=".\ctype-big5.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\ctype-czech.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\ctype-euc_kr.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\ctype-gb2312.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\ctype-gbk.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\ctype-sjis.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\ctype-tis620.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\ctype-ujis.c"
+# End Source File
+# Begin Source File
+
+SOURCE=.\ctype.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\int2str.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\llstr.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\longlong2str.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_strinstr.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\str2int.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\Strings.asm
+
+!IF "$(CFG)" == "strings - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\release
+InputPath=.\Strings.asm
+InputName=Strings
+
+"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ C:\masm\masm -Mx -t -DDOS386 -DM_I386 $(InputPath),$(OutDir)\$(InputName).obj,,,
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "strings - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\debug
+InputPath=.\Strings.asm
+InputName=Strings
+
+"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ C:\masm\masm -Mx -t -DDOS386 -DM_I386 $(InputPath),$(Outdir)\$(InputName).obj,,,
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\strtol.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strtoll.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strtoul.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strtoull.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\Strxmov.asm
+
+!IF "$(CFG)" == "strings - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\release
+InputPath=.\Strxmov.asm
+InputName=Strxmov
+
+"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ C:\masm\masm -Mx -t -DDOS386 -DM_I386 $(InputPath),$(OutDir)\$(InputName).obj,,,
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "strings - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\debug
+InputPath=.\Strxmov.asm
+InputName=Strxmov
+
+"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ C:\masm\masm -Mx -t -DDOS386 -DM_I386 $(InputPath),$(Outdir)\$(InputName).obj,,,
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\strxnmov.c
+# End Source File
+# End Target
+# End Project
diff --git a/VC++Files/strings/backup/strings.dsw b/VC++Files/strings/backup/strings.dsw
new file mode 100644
index 00000000000..e3777b8e7d5
--- /dev/null
+++ b/VC++Files/strings/backup/strings.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 5.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "strings"=".\strings.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/VC++Files/strings/noMASM/strings.dsp b/VC++Files/strings/noMASM/strings.dsp
new file mode 100644
index 00000000000..a84fb1b7835
--- /dev/null
+++ b/VC++Files/strings/noMASM/strings.dsp
@@ -0,0 +1,246 @@
+# Microsoft Developer Studio Project File - Name="strings" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=strings - 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 "strings.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 "strings.mak" CFG="strings - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "strings - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "strings - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "strings - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "release"
+# PROP Intermediate_Dir "release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /D "NDEBUG" /D "DBUG_OFF" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_release\strings.lib"
+
+!ELSEIF "$(CFG)" == "strings - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "debug"
+# PROP Intermediate_Dir "debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /G6 /MTd /W3 /Z7 /Od /Gf /I "../include" /D "_DEBUG" /D "SAFEMALLOC" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_debug\strings.lib"
+
+!ENDIF
+
+# Begin Target
+
+# Name "strings - Win32 Release"
+# Name "strings - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\atof.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\bchange.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\bcmp.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\bfill.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\bmove.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\bmove512.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\bmove_upp.c
+# End Source File
+# Begin Source File
+
+SOURCE=".\ctype-big5.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\ctype-czech.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\ctype-euc_kr.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\ctype-gb2312.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\ctype-gbk.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\ctype-latin1_de.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\ctype-sjis.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\ctype-tis620.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\ctype-ujis.c"
+# End Source File
+# Begin Source File
+
+SOURCE=.\ctype.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\int2str.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\is_prefix.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\llstr.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\longlong2str.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_strinstr.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\str2int.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strappend.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strcend.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strcont.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strend.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strfill.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strinstr.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strmake.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strmov.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strnlen.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strnmov.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strstr.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strtol.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strtoll.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strtoul.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strtoull.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strxmov.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strxnmov.c
+# End Source File
+# End Target
+# End Project
diff --git a/VC++Files/strings/strings.dsp b/VC++Files/strings/strings.dsp
new file mode 100644
index 00000000000..52655947790
--- /dev/null
+++ b/VC++Files/strings/strings.dsp
@@ -0,0 +1,248 @@
+# Microsoft Developer Studio Project File - Name="strings" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=strings - 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 "strings.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 "strings.mak" CFG="strings - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "strings - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "strings - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "strings - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "release"
+# PROP Intermediate_Dir "release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /D "NDEBUG" /D "DBUG_OFF" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_release\strings.lib"
+
+!ELSEIF "$(CFG)" == "strings - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "debug"
+# PROP Intermediate_Dir "debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /G6 /MTd /W3 /Z7 /Od /Gf /I "../include" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_debug\strings.lib"
+
+!ENDIF
+
+# Begin Target
+
+# Name "strings - Win32 Release"
+# Name "strings - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\atof.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\bchange.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\bcmp.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\bfill.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\bmove512.c
+# End Source File
+# Begin Source File
+
+SOURCE=".\ctype-big5.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\ctype-czech.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\ctype-euc_kr.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\ctype-gb2312.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\ctype-gbk.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\ctype-latin1_de.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\ctype-sjis.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\ctype-tis620.c"
+# End Source File
+# Begin Source File
+
+SOURCE=".\ctype-ujis.c"
+# End Source File
+# Begin Source File
+
+SOURCE=.\ctype.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\int2str.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\llstr.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\longlong2str.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_strinstr.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\str2int.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\Strings.asm
+
+!IF "$(CFG)" == "strings - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\release
+InputPath=.\Strings.asm
+InputName=Strings
+
+"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml /Cx /nologo /DDOS386 /DM_I386 /Zm /coff /c /Fo $(Outdir)\$(InputName).obj $(InputPath)
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "strings - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\debug
+InputPath=.\Strings.asm
+InputName=Strings
+
+"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml /Cx /nologo /DDOS386 /DM_I386 /Zm /coff /c /Fo $(Outdir)\$(InputName).obj $(InputPath)
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\strtol.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strtoll.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strtoul.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strtoull.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\Strxmov.asm
+
+!IF "$(CFG)" == "strings - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\release
+InputPath=.\Strxmov.asm
+InputName=Strxmov
+
+"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml /Cx /nologo /DDOS386 /DM_I386 /Zm /coff /c /Fo $(Outdir)\$(InputName).obj $(InputPath)
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "strings - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\debug
+InputPath=.\Strxmov.asm
+InputName=Strxmov
+
+"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml /Cx /nologo /DDOS386 /DM_I386 /Zm /coff /c /Fo $(Outdir)\$(InputName).obj $(InputPath)
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\strxnmov.c
+# End Source File
+# End Target
+# End Project
diff --git a/VC++Files/test1/test1.dsp b/VC++Files/test1/test1.dsp
new file mode 100644
index 00000000000..50a165e3e4d
--- /dev/null
+++ b/VC++Files/test1/test1.dsp
@@ -0,0 +1,102 @@
+# Microsoft Developer Studio Project File - Name="test1" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=test1 - 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 "test1.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 "test1.mak" CFG="test1 - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "test1 - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "test1 - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "test1 - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /W3 /O2 /I "../include" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /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 /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "test1 - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MTd /W3 /Gm /ZI /Od /I "../include" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 libmysql.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 /libpath:"..\lib_debug"
+# SUBTRACT LINK32 /incremental:no
+
+!ENDIF
+
+# Begin Target
+
+# Name "test1 - Win32 Release"
+# Name "test1 - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\mysql_thr.c
+
+!IF "$(CFG)" == "test1 - Win32 Release"
+
+# ADD CPP /MT
+
+!ELSEIF "$(CFG)" == "test1 - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# End Target
+# End Project
diff --git a/VC++Files/thr_insert_test/thr_insert_test.dsp b/VC++Files/thr_insert_test/thr_insert_test.dsp
new file mode 100644
index 00000000000..770125ab65b
--- /dev/null
+++ b/VC++Files/thr_insert_test/thr_insert_test.dsp
@@ -0,0 +1,109 @@
+# Microsoft Developer Studio Project File - Name="thr_insert_test" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=thr_insert_test - 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 "thr_insert_test.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 "thr_insert_test.mak" CFG="thr_insert_test - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "thr_insert_test - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "thr_insert_test - Win32 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)" == "thr_insert_test - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /GX- /O2 /I "../include" /I "../" /D "NDEBUG" /D "DBUG_OFF" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 mysqlclient.lib wsock32.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 /out:"../client_release/hr_insert_test.exe" /libpath:"..\lib_release\\"
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "thr_insert_test - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /G6 /MTd /W3 /Gm /GX- /ZI /Od /I "../include" /I "../" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 mysqlclient.lib wsock32.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 /pdb:"debug/mysqldump.pdb" /debug /machine:I386 /out:"../client_debug/thr_insert_test.exe" /pdbtype:sept /libpath:"..\lib_debug\\"
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF
+
+# Begin Target
+
+# Name "thr_insert_test - Win32 Release"
+# Name "thr_insert_test - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\tests\thr_insert_test.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/VC++Files/thr_test/thr_test.dsp b/VC++Files/thr_test/thr_test.dsp
new file mode 100644
index 00000000000..7256f8da2fa
--- /dev/null
+++ b/VC++Files/thr_test/thr_test.dsp
@@ -0,0 +1,104 @@
+# Microsoft Developer Studio Project File - Name="thr_test" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=thr_test - 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 "thr_test.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 "thr_test.mak" CFG="thr_test - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "thr_test - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "thr_test - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "thr_test - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /D "NDEBUG" /D "DBUG_OFF" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /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 /nologo /subsystem:console /machine:I386
+# SUBTRACT LINK32 /nodefaultlib
+
+!ELSEIF "$(CFG)" == "thr_test - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# 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 /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /G6 /MTd /W3 /Gm /ZI /Od /I "../include" /D "__WIN32__" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /Fr /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /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 /nologo /subsystem:console /incremental:no /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "thr_test - Win32 Release"
+# Name "thr_test - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\thr_test.c
+
+!IF "$(CFG)" == "thr_test - Win32 Release"
+
+# ADD CPP /G5
+
+!ELSEIF "$(CFG)" == "thr_test - Win32 Debug"
+
+# ADD CPP /FAcs
+
+!ENDIF
+
+# End Source File
+# End Target
+# End Project
diff --git a/VC++Files/vio/vio.dsp b/VC++Files/vio/vio.dsp
new file mode 100644
index 00000000000..d4b77aad391
--- /dev/null
+++ b/VC++Files/vio/vio.dsp
@@ -0,0 +1,108 @@
+# Microsoft Developer Studio Project File - Name="vio" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=vio - 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 "vio.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 "vio.mak" CFG="vio - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "vio - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "vio - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "vio - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /D "NDEBUG" /D "DBUG_OFF" /D "_WINDOWS" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_release\vio.lib"
+
+!ELSEIF "$(CFG)" == "vio - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /G6 /MTd /W3 /ZI /Od /I "../include" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_WINDOWS" /D "USE_SYMDIR" /FD /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_debug\vio.lib"
+
+!ENDIF
+
+# Begin Target
+
+# Name "vio - Win32 Release"
+# Name "vio - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\vio.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\viosocket.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\viossl.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\viosslfactories.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# End Target
+# End Project
diff --git a/VC++Files/zlib/contrib/asm386/zlibvc.dsp b/VC++Files/zlib/contrib/asm386/zlibvc.dsp
new file mode 100644
index 00000000000..a70d4d4a6b0
--- /dev/null
+++ b/VC++Files/zlib/contrib/asm386/zlibvc.dsp
@@ -0,0 +1,651 @@
+# Microsoft Developer Studio Project File - Name="zlibvc" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+# TARGTYPE "Win32 (ALPHA) Dynamic-Link Library" 0x0602
+
+CFG=zlibvc - Win32 Release
+!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 "zlibvc.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 "zlibvc.mak" CFG="zlibvc - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "zlibvc - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "zlibvc - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "zlibvc - Win32 ReleaseAxp" (based on\
+ "Win32 (ALPHA) Dynamic-Link Library")
+!MESSAGE "zlibvc - Win32 ReleaseWithoutAsm" (based on\
+ "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "zlibvc - Win32 ReleaseWithoutCrtdll" (based on\
+ "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\Release"
+# PROP BASE Intermediate_Dir ".\Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\Release"
+# PROP Intermediate_Dir ".\Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /D "ASMV" /FAcs /FR /FD /c
+# SUBTRACT CPP /YX
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x40c /d "NDEBUG"
+# ADD RSC /l 0x40c /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 gvmat32.obj kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\Release\zlib.dll"
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir ".\Debug"
+# PROP BASE Intermediate_Dir ".\Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ".\Debug"
+# PROP Intermediate_Dir ".\Debug"
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /FD /c
+# SUBTRACT CPP /YX
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x40c /d "_DEBUG"
+# ADD RSC /l 0x40c /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /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 /nologo /subsystem:windows /dll /debug /machine:I386 /out:".\Debug\zlib.dll"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "zlibvc__"
+# PROP BASE Intermediate_Dir "zlibvc__"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "zlibvc__"
+# PROP Intermediate_Dir "zlibvc__"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /FAcs /FR /YX /FD /c
+# ADD CPP /nologo /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /FAcs /FR /FD /c
+# SUBTRACT CPP /YX
+RSC=rc.exe
+# ADD BASE RSC /l 0x40c /d "NDEBUG"
+# ADD RSC /l 0x40c /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 crtdll.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /map /machine:ALPHA /nodefaultlib /out:".\Release\zlib.dll"
+# SUBTRACT BASE LINK32 /pdb:none
+# ADD LINK32 crtdll.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /map /machine:ALPHA /nodefaultlib /out:"zlibvc__\zlib.dll"
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "zlibvc_0"
+# PROP BASE Intermediate_Dir "zlibvc_0"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "zlibvc_0"
+# PROP Intermediate_Dir "zlibvc_0"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /FAcs /FR /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /FAcs /FR /FD /c
+# SUBTRACT CPP /YX
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x40c /d "NDEBUG"
+# ADD RSC /l 0x40c /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\Release\zlib.dll"
+# SUBTRACT BASE LINK32 /pdb:none
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\zlibvc_0\zlib.dll"
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "zlibvc_1"
+# PROP BASE Intermediate_Dir "zlibvc_1"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "zlibvc_1"
+# PROP Intermediate_Dir "zlibvc_1"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /D "ASMV" /FAcs /FR /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /D "ASMV" /FAcs /FR /FD /c
+# SUBTRACT CPP /YX
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x40c /d "NDEBUG"
+# ADD RSC /l 0x40c /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 gvmat32.obj kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\Release\zlib.dll"
+# SUBTRACT BASE LINK32 /pdb:none
+# ADD LINK32 gvmat32.obj kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\zlibvc_1\zlib.dll"
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF
+
+# Begin Target
+
+# Name "zlibvc - Win32 Release"
+# Name "zlibvc - Win32 Debug"
+# Name "zlibvc - Win32 ReleaseAxp"
+# Name "zlibvc - Win32 ReleaseWithoutAsm"
+# Name "zlibvc - Win32 ReleaseWithoutCrtdll"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\adler32.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_ADLER=\
+ ".\zconf.h"\
+ ".\zlib.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\compress.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_COMPR=\
+ ".\zconf.h"\
+ ".\zlib.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\crc32.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_CRC32=\
+ ".\zconf.h"\
+ ".\zlib.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\deflate.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_DEFLA=\
+ ".\deflate.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gvmat32c.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gzio.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_GZIO_=\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\infblock.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFBL=\
+ ".\infblock.h"\
+ ".\infcodes.h"\
+ ".\inftrees.h"\
+ ".\infutil.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\infcodes.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFCO=\
+ ".\infblock.h"\
+ ".\infcodes.h"\
+ ".\inffast.h"\
+ ".\inftrees.h"\
+ ".\infutil.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\inffast.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFFA=\
+ ".\infblock.h"\
+ ".\infcodes.h"\
+ ".\inffast.h"\
+ ".\inftrees.h"\
+ ".\infutil.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\inflate.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFLA=\
+ ".\infblock.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\inftrees.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFTR=\
+ ".\inftrees.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\infutil.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFUT=\
+ ".\infblock.h"\
+ ".\infcodes.h"\
+ ".\inftrees.h"\
+ ".\infutil.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\trees.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_TREES=\
+ ".\deflate.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\uncompr.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_UNCOM=\
+ ".\zconf.h"\
+ ".\zlib.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\unzip.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\zip.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\zlib.rc
+# End Source File
+# Begin Source File
+
+SOURCE=.\zlibvc.def
+# End Source File
+# Begin Source File
+
+SOURCE=.\zutil.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_ZUTIL=\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\deflate.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\infblock.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\infcodes.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\inffast.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\inftrees.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\infutil.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zconf.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zlib.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zutil.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"
+# End Group
+# End Target
+# End Project
diff --git a/VC++Files/zlib/contrib/asm386/zlibvc.dsw b/VC++Files/zlib/contrib/asm386/zlibvc.dsw
new file mode 100644
index 00000000000..493cd870365
--- /dev/null
+++ b/VC++Files/zlib/contrib/asm386/zlibvc.dsw
@@ -0,0 +1,41 @@
+Microsoft Developer Studio Workspace File, Format Version 5.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "zlibstat"=.\zlibstat.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "zlibvc"=.\zlibvc.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/VC++Files/zlib/zlib.dsp b/VC++Files/zlib/zlib.dsp
new file mode 100644
index 00000000000..5a596b41f32
--- /dev/null
+++ b/VC++Files/zlib/zlib.dsp
@@ -0,0 +1,186 @@
+# Microsoft Developer Studio Project File - Name="zlib" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=zlib - 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 "zlib.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 "zlib.mak" CFG="zlib - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "zlib - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "zlib - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "zlib - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "release"
+# PROP Intermediate_Dir "release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /D "NDEBUG" /D "DBUG_OFF" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_release\zlib.lib"
+
+!ELSEIF "$(CFG)" == "zlib - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "debug"
+# PROP Intermediate_Dir "debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /G6 /MTd /W3 /ZI /Od /D "_DEBUG" /D "__WIN32__" /D "_WINDOWS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\lib_debug\zlib.lib"
+
+!ENDIF
+
+# Begin Target
+
+# Name "zlib - Win32 Release"
+# Name "zlib - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\adler32.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\compress.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\crc32.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\deflate.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\deflate.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\gzio.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\infblock.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\infblock.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\infcodes.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\infcodes.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\inffast.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\inffast.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\inffixed.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\inflate.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\inftrees.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\inftrees.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\infutil.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\infutil.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\trees.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\trees.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\uncompr.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\zconf.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zlib.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zutil.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\zutil.h
+# End Source File
+# End Target
+# End Project
diff --git a/acconfig.h b/acconfig.h
index 3cea5bf4b73..02be1ace0c6 100644
--- a/acconfig.h
+++ b/acconfig.h
@@ -91,6 +91,9 @@
/* Using Innobase DB */
#undef HAVE_INNOBASE_DB
+/* Using old ISAM tables */
+#undef HAVE_ISAM
+
/* Define if we have GNU readline */
#undef HAVE_LIBREADLINE
@@ -121,6 +124,9 @@
/* sigwait with one argument */
#undef HAVE_NONPOSIX_SIGWAIT
+/* ORBIT */
+#undef HAVE_ORBIT
+
/* pthread_attr_setscope */
#undef HAVE_PTHREAD_ATTR_SETSCOPE
@@ -170,9 +176,15 @@
/* new UNIXWARE7 threads that are not yet posix */
#undef HAVE_UNIXWARE7_POSIX
+/* OpenSSL */
+#undef HAVE_OPENSSL
+
/* READLINE: */
#undef HAVE_USG_SIGHOLD
+/* Virtual IO */
+#undef HAVE_VIO
+
/* Handling of large files on Solaris 2.6 */
#undef _LARGEFILE_SOURCE
@@ -248,6 +260,9 @@
#undef USE_MB
#undef USE_MB_IDENT
+/* the pstack backtrace library */
+#undef USE_PSTACK
+
/* Use MySQL RAID */
#undef USE_RAID
diff --git a/acinclude.m4 b/acinclude.m4
index b8d46b25db2..85149d64dc7 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -634,6 +634,209 @@ 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)
+ else
+ vio_dir=""
+ vio_libs=""
+ fi
+ AC_SUBST([vio_dir])
+ AC_SUBST([vio_libs])
+])
+
+AC_DEFUN(MYSQL_FIND_OPENSSL, [
+ for d in /usr/ssl/include /usr/local/ssl/include /usr/include/openssl \
+/usr/include/ssl /opt/ssl/include /opt/openssl/include \
+/usr/local/ssl/include/openssl ; do
+ if test -f $d/ssl.h ; then
+ OPENSSL_INCLUDE=$d
+ fi
+ done
+
+ for d in /usr/ssl/lib /usr/local/ssl/lib /usr/lib/openssl \
+/usr/lib /opt/ssl/lib /opt/openssl/lib ; do
+ if test -f $d/libssl.a ; then
+ OPENSSL_LIB=$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 "$IS_LINUX" = "true"; then
+ echo "Looks like you've forgotted 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 Include the OpenSSL support],
+ [openssl="$withval"],
+ [openssl=no])
+
+ openssl_libs=""
+ openssl_includes=""
+ if test "$openssl" = "yes"
+ then
+ MYSQL_FIND_OPENSSL
+ #force VIO use
+ vio_dir="vio"
+ vio_libs="../vio/libvio.la"
+ AC_DEFINE(HAVE_VIO)
+ AC_MSG_RESULT(yes)
+ openssl_libs="-L$OPENSSL_LIB -lssl -lcrypto"
+ openssl_includes="-I$OPENSSL_INCLUDE"
+ AC_DEFINE(HAVE_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
+ AC_MSG_RESULT(no)
+ fi
+ NON_THREADED_CLIENT_LIBS="$NON_THREADED_CLIENT_LIBS $openssl_libs"
+ AC_SUBST(openssl_libs)
+ AC_SUBST(openssl_includes)
+])
+
+
+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"
+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)
+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], [\
+ --without-isam Disable the ISAM table type],
+ [with_isam="$withval"],
+ [with_isam=yes])
+
+ isam_libs=
+ if test X"$with_isam" = X"yes"
+ then
+ AC_DEFINE(HAVE_ISAM)
+ 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
@@ -906,9 +1109,9 @@ dnl ---------------------------------------------------------------------------
AC_DEFUN([MYSQL_CHECK_INNODB], [
AC_ARG_WITH([innodb],
[
- --with-innodb Use Innodb],
+ --without-innodb Do not include the InnoDB table handler],
[innodb="$withval"],
- [innodb=no])
+ [innodb=yes])
AC_MSG_CHECKING([for Innodb])
@@ -979,48 +1182,7 @@ dnl END OF MYSQL_CHECK_INNODB SECTION
dnl ---------------------------------------------------------------------------
dnl ---------------------------------------------------------------------------
-dnl Macro: MYSQL_CHECK_GEMINI
-dnl Sets HAVE_GEMINI_DB if --with-gemini is used
-dnl ---------------------------------------------------------------------------
-
-AC_DEFUN([MYSQL_CHECK_GEMINI], [
- AC_ARG_WITH([gemini],
- [
- --with-gemini[=DIR] Use Gemini DB located in DIR],
- [gemini="$withval"],
- [gemini=no])
-
- AC_MSG_CHECKING([for Gemini DB])
-
-dnl SORT OUT THE SUPPLIED ARGUMENTS TO DETERMINE WHAT TO DO
-dnl echo "DBG_GEM1: gemini='$gemini'"
- have_gemini_db=no
- gemini_includes=
- gemini_libs=
- case "$gemini" in
- no)
- AC_MSG_RESULT([Not using Gemini DB])
- ;;
- yes | default | *)
- have_gemini_db="yes"
- gemini_includes="-I../gemini/incl -I../gemini"
- gemini_libs="\
- ../gemini/api/libapi.a\
- ../gemini/db/libdb.a\
- ../gemini/dbut/libdbut.a"
- AC_MSG_RESULT([Using Gemini DB])
- ;;
- esac
-
- AC_SUBST(gemini_includes)
- AC_SUBST(gemini_libs)
-])
-
-dnl ---------------------------------------------------------------------------
-dnl END OF MYSQL_CHECK_GEMINI SECTION
-dnl ---------------------------------------------------------------------------
-dnl ---------------------------------------------------------------------------
dnl Got this from the GNU tar 1.13.11 distribution
dnl by Paul Eggert <eggert@twinsun.com>
dnl ---------------------------------------------------------------------------
diff --git a/bdb/include/btree_ext.h b/bdb/include/btree_ext.h
deleted file mode 100644
index 8a9866e0b5a..00000000000
--- a/bdb/include/btree_ext.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/* DO NOT EDIT: automatically built by dist/s_include. */
-#ifndef _btree_ext_h_
-#define _btree_ext_h_
-#if defined(__cplusplus)
-extern "C" {
-#endif
-int __bam_cmp __P((DB *, const DBT *, PAGE *,
- u_int32_t, int (*)(DB *, const DBT *, const DBT *), int *));
-int __bam_defcmp __P((DB *, const DBT *, const DBT *));
-size_t __bam_defpfx __P((DB *, const DBT *, const DBT *));
-int __bam_pgin __P((DB_ENV *, db_pgno_t, void *, DBT *));
-int __bam_pgout __P((DB_ENV *, db_pgno_t, void *, DBT *));
-int __bam_mswap __P((PAGE *));
-void __bam_cprint __P((DBC *));
-int __bam_ca_delete __P((DB *, db_pgno_t, u_int32_t, int));
-int __ram_ca_delete __P((DB *, db_pgno_t));
-int __bam_ca_di __P((DBC *, db_pgno_t, u_int32_t, int));
-int __bam_ca_dup __P((DBC *,
- u_int32_t, db_pgno_t, u_int32_t, db_pgno_t, u_int32_t));
-int __bam_ca_undodup __P((DB *,
- u_int32_t, db_pgno_t, u_int32_t, u_int32_t));
-int __bam_ca_rsplit __P((DBC *, db_pgno_t, db_pgno_t));
-int __bam_ca_split __P((DBC *,
- db_pgno_t, db_pgno_t, db_pgno_t, u_int32_t, int));
-void __bam_ca_undosplit __P((DB *,
- db_pgno_t, db_pgno_t, db_pgno_t, u_int32_t));
-int __bam_c_init __P((DBC *, DBTYPE));
-int __bam_c_refresh __P((DBC *));
-int __bam_c_count __P((DBC *, db_recno_t *));
-int __bam_c_dup __P((DBC *, DBC *));
-int __bam_c_rget __P((DBC *, DBT *, u_int32_t));
-int __bam_delete __P((DB *, DB_TXN *, DBT *, u_int32_t));
-int __bam_ditem __P((DBC *, PAGE *, u_int32_t));
-int __bam_adjindx __P((DBC *, PAGE *, u_int32_t, u_int32_t, int));
-int __bam_dpages __P((DBC *, EPG *));
-int __bam_db_create __P((DB *));
-int __bam_db_close __P((DB *));
-int __bam_set_flags __P((DB *, u_int32_t *flagsp));
-int __ram_set_flags __P((DB *, u_int32_t *flagsp));
-int __bam_open __P((DB *, const char *, db_pgno_t, u_int32_t));
-int __bam_metachk __P((DB *, const char *, BTMETA *));
-int __bam_read_root __P((DB *, const char *, db_pgno_t, u_int32_t));
-int __bam_iitem __P((DBC *, DBT *, DBT *, u_int32_t, u_int32_t));
-u_int32_t __bam_partsize __P((u_int32_t, DBT *, PAGE *, u_int32_t));
-int __bam_build __P((DBC *, u_int32_t,
- DBT *, PAGE *, u_int32_t, u_int32_t));
-int __bam_ritem __P((DBC *, PAGE *, u_int32_t, DBT *));
-int __bam_pg_alloc_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __bam_pg_free_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __bam_split_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __bam_rsplit_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __bam_adj_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __bam_cadjust_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __bam_cdel_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __bam_repl_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __bam_root_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __bam_curadj_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __bam_rcuradj_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __bam_reclaim __P((DB *, DB_TXN *));
-int __ram_open __P((DB *, const char *, db_pgno_t, u_int32_t));
-int __ram_c_del __P((DBC *));
-int __ram_c_get
- __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *));
-int __ram_c_put __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *));
-int __ram_ca __P((DBC *, ca_recno_arg));
-int __ram_getno __P((DBC *, const DBT *, db_recno_t *, int));
-int __ram_writeback __P((DB *));
-int __bam_rsearch __P((DBC *, db_recno_t *, u_int32_t, int, int *));
-int __bam_adjust __P((DBC *, int32_t));
-int __bam_nrecs __P((DBC *, db_recno_t *));
-db_recno_t __bam_total __P((PAGE *));
-int __bam_search __P((DBC *,
- const DBT *, u_int32_t, int, db_recno_t *, int *));
-int __bam_stkrel __P((DBC *, u_int32_t));
-int __bam_stkgrow __P((DB_ENV *, BTREE_CURSOR *));
-int __bam_split __P((DBC *, void *));
-int __bam_copy __P((DB *, PAGE *, PAGE *, u_int32_t, u_int32_t));
-int __bam_stat __P((DB *, void *, void *(*)(size_t), u_int32_t));
-int __bam_traverse __P((DBC *, db_lockmode_t,
- db_pgno_t, int (*)(DB *, PAGE *, void *, int *), void *));
-int __bam_stat_callback __P((DB *, PAGE *, void *, int *));
-int __bam_key_range __P((DB *,
- DB_TXN *, DBT *, DB_KEY_RANGE *, u_int32_t));
-int __bam_30_btreemeta __P((DB *, char *, u_int8_t *));
-int __bam_31_btreemeta
- __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *));
-int __bam_31_lbtree
- __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *));
-int __bam_vrfy_meta __P((DB *, VRFY_DBINFO *, BTMETA *,
- db_pgno_t, u_int32_t));
-int __ram_vrfy_leaf __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t,
- u_int32_t));
-int __bam_vrfy __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t,
- u_int32_t));
-int __bam_vrfy_itemorder __P((DB *, VRFY_DBINFO *, PAGE *,
- db_pgno_t, u_int32_t, int, int, u_int32_t));
-int __bam_vrfy_structure __P((DB *, VRFY_DBINFO *, db_pgno_t,
- u_int32_t));
-int __bam_vrfy_subtree __P((DB *, VRFY_DBINFO *, db_pgno_t, void *,
- void *, u_int32_t, u_int32_t *, u_int32_t *, u_int32_t *));
-int __bam_salvage __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t,
- PAGE *, void *, int (*)(void *, const void *), DBT *,
- u_int32_t));
-int __bam_salvage_walkdupint __P((DB *, VRFY_DBINFO *, PAGE *,
- DBT *, void *, int (*)(void *, const void *), u_int32_t));
-int __bam_meta2pgset __P((DB *, VRFY_DBINFO *, BTMETA *,
- u_int32_t, DB *));
-#if defined(__cplusplus)
-}
-#endif
-#endif /* _btree_ext_h_ */
diff --git a/bdb/include/clib_ext.h b/bdb/include/clib_ext.h
deleted file mode 100644
index efd0796afe3..00000000000
--- a/bdb/include/clib_ext.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/* DO NOT EDIT: automatically built by dist/s_include. */
-#ifndef _clib_ext_h_
-#define _clib_ext_h_
-#if defined(__cplusplus)
-extern "C" {
-#endif
-#ifndef HAVE_GETCWD
-char *getcwd __P((char *, size_t));
-#endif
-#ifndef HAVE_GETOPT
-int getopt __P((int, char * const *, const char *));
-#endif
-#ifndef HAVE_MEMCMP
-int memcmp __P((const void *, const void *, size_t));
-#endif
-#ifndef HAVE_MEMCPY
-void *memcpy __P((void *, const void *, size_t));
-#endif
-#ifndef HAVE_MEMMOVE
-void *memmove __P((void *, const void *, size_t));
-#endif
-#ifndef HAVE_RAISE
-int raise __P((int));
-#endif
-#ifndef HAVE_SNPRINTF
-int snprintf __P((char *, size_t, const char *, ...));
-#endif
-int strcasecmp __P((const char *, const char *));
-#ifndef HAVE_STRERROR
-char *strerror __P((int));
-#endif
-#ifndef HAVE_VSNPRINTF
-int vsnprintf();
-#endif
-#if defined(__cplusplus)
-}
-#endif
-#endif /* _clib_ext_h_ */
diff --git a/bdb/include/common_ext.h b/bdb/include/common_ext.h
deleted file mode 100644
index a36d62cac4a..00000000000
--- a/bdb/include/common_ext.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* DO NOT EDIT: automatically built by dist/s_include. */
-#ifndef _common_ext_h_
-#define _common_ext_h_
-#if defined(__cplusplus)
-extern "C" {
-#endif
-int __db_byteorder __P((DB_ENV *, int));
-int __db_fchk __P((DB_ENV *, const char *, u_int32_t, u_int32_t));
-int __db_fcchk
- __P((DB_ENV *, const char *, u_int32_t, u_int32_t, u_int32_t));
-int __db_ferr __P((const DB_ENV *, const char *, int));
-int __db_pgerr __P((DB *, db_pgno_t));
-int __db_pgfmt __P((DB *, db_pgno_t));
-int __db_eopnotsup __P((const DB_ENV *));
-#ifdef DIAGNOSTIC
-void __db_assert __P((const char *, const char *, int));
-#endif
-int __db_panic_msg __P((DB_ENV *));
-int __db_panic __P((DB_ENV *, int));
-void __db_err __P((const DB_ENV *, const char *, ...));
-void __db_real_err
- __P((const DB_ENV *, int, int, int, const char *, va_list));
-void __db_logmsg __P((const DB_ENV *,
- DB_TXN *, const char *, u_int32_t, const char *, ...));
-void __db_real_log __P((const DB_ENV *,
- DB_TXN *, const char *, u_int32_t, const char *, va_list ap));
-int __db_unknown_flag __P((DB_ENV *, char *, u_int32_t));
-int __db_unknown_type __P((DB_ENV *, char *, u_int32_t));
-#ifdef DIAGNOSTIC
-int __db_missing_txn_err __P((DB_ENV *));
-#endif
-int __db_getlong
- __P((DB *, const char *, char *, long, long, long *));
-int __db_getulong
- __P((DB *, const char *, char *, u_long, u_long, u_long *));
-u_int32_t __db_log2 __P((u_int32_t));
-int __db_util_logset __P((const char *, char *));
-void __db_util_siginit __P((void));
-int __db_util_interrupted __P((void));
-void __db_util_sigresend __P((void));
-#if defined(__cplusplus)
-}
-#endif
-#endif /* _common_ext_h_ */
diff --git a/bdb/include/env_ext.h b/bdb/include/env_ext.h
deleted file mode 100644
index 0e7313fde9d..00000000000
--- a/bdb/include/env_ext.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* DO NOT EDIT: automatically built by dist/s_include. */
-#ifndef _env_ext_h_
-#define _env_ext_h_
-#if defined(__cplusplus)
-extern "C" {
-#endif
-void __db_shalloc_init __P((void *, size_t));
-int __db_shalloc_size __P((size_t, size_t));
-int __db_shalloc __P((void *, size_t, size_t, void *));
-void __db_shalloc_free __P((void *, void *));
-size_t __db_shalloc_count __P((void *));
-size_t __db_shsizeof __P((void *));
-void __db_shalloc_dump __P((void *, FILE *));
-int __db_tablesize __P((u_int32_t));
-void __db_hashinit __P((void *, u_int32_t));
-int __dbenv_init __P((DB_ENV *));
-int __db_mi_env __P((DB_ENV *, const char *));
-int __db_mi_open __P((DB_ENV *, const char *, int));
-int __db_env_config __P((DB_ENV *, int));
-int __dbenv_open __P((DB_ENV *, const char *, u_int32_t, int));
-int __dbenv_remove __P((DB_ENV *, const char *, u_int32_t));
-int __dbenv_close __P((DB_ENV *, u_int32_t));
-int __db_appname __P((DB_ENV *, APPNAME,
- const char *, const char *, u_int32_t, DB_FH *, char **));
-int __db_apprec __P((DB_ENV *, u_int32_t));
-int __db_e_attach __P((DB_ENV *, u_int32_t *));
-int __db_e_detach __P((DB_ENV *, int));
-int __db_e_remove __P((DB_ENV *, int));
-int __db_e_stat __P((DB_ENV *, REGENV *, REGION *, int *));
-int __db_r_attach __P((DB_ENV *, REGINFO *, size_t));
-int __db_r_detach __P((DB_ENV *, REGINFO *, int));
-#if defined(__cplusplus)
-}
-#endif
-#endif /* _env_ext_h_ */
diff --git a/bdb/include/hash_ext.h b/bdb/include/hash_ext.h
deleted file mode 100644
index babb77a7902..00000000000
--- a/bdb/include/hash_ext.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/* DO NOT EDIT: automatically built by dist/s_include. */
-#ifndef _hash_ext_h_
-#define _hash_ext_h_
-#if defined(__cplusplus)
-extern "C" {
-#endif
-int __ham_metachk __P((DB *, const char *, HMETA *));
-int __ham_open __P((DB *, const char *, db_pgno_t, u_int32_t));
-int __ham_c_init __P((DBC *));
-int __ham_c_count __P((DBC *, db_recno_t *));
-int __ham_c_dup __P((DBC *, DBC *));
-u_int32_t __ham_call_hash __P((DBC *, u_int8_t *, int32_t));
-int __ham_init_dbt __P((DB_ENV *,
- DBT *, u_int32_t, void **, u_int32_t *));
-int __ham_c_update
- __P((DBC *, u_int32_t, int, int));
-int __ham_get_clist __P((DB *,
- db_pgno_t, u_int32_t, DBC ***));
-int __ham_c_chgpg
- __P((DBC *, db_pgno_t, u_int32_t, db_pgno_t, u_int32_t));
-int __ham_pgin __P((DB_ENV *, db_pgno_t, void *, DBT *));
-int __ham_pgout __P((DB_ENV *, db_pgno_t, void *, DBT *));
-int __ham_mswap __P((void *));
-int __ham_add_dup __P((DBC *, DBT *, u_int32_t, db_pgno_t *));
-int __ham_dup_convert __P((DBC *));
-int __ham_make_dup __P((DB_ENV *,
- const DBT *, DBT *d, void **, u_int32_t *));
-void __ham_move_offpage __P((DBC *, PAGE *, u_int32_t, db_pgno_t));
-void __ham_dsearch __P((DBC *, DBT *, u_int32_t *, int *));
-int __ham_cprint __P((DB *));
-u_int32_t __ham_func2 __P((DB *, const void *, u_int32_t));
-u_int32_t __ham_func3 __P((DB *, const void *, u_int32_t));
-u_int32_t __ham_func4 __P((DB *, const void *, u_int32_t));
-u_int32_t __ham_func5 __P((DB *, const void *, u_int32_t));
-int __ham_get_meta __P((DBC *));
-int __ham_release_meta __P((DBC *));
-int __ham_dirty_meta __P((DBC *));
-int __ham_db_create __P((DB *));
-int __ham_db_close __P((DB *));
-int __ham_item __P((DBC *, db_lockmode_t, db_pgno_t *));
-int __ham_item_reset __P((DBC *));
-void __ham_item_init __P((DBC *));
-int __ham_item_last __P((DBC *, db_lockmode_t, db_pgno_t *));
-int __ham_item_first __P((DBC *, db_lockmode_t, db_pgno_t *));
-int __ham_item_prev __P((DBC *, db_lockmode_t, db_pgno_t *));
-int __ham_item_next __P((DBC *, db_lockmode_t, db_pgno_t *));
-void __ham_putitem __P((PAGE *p, const DBT *, int));
-void __ham_reputpair
- __P((PAGE *p, u_int32_t, u_int32_t, const DBT *, const DBT *));
-int __ham_del_pair __P((DBC *, int));
-int __ham_replpair __P((DBC *, DBT *, u_int32_t));
-void __ham_onpage_replace __P((PAGE *, size_t, u_int32_t, int32_t,
- int32_t, DBT *));
-int __ham_split_page __P((DBC *, u_int32_t, u_int32_t));
-int __ham_add_el __P((DBC *, const DBT *, const DBT *, int));
-void __ham_copy_item __P((size_t, PAGE *, u_int32_t, PAGE *));
-int __ham_add_ovflpage __P((DBC *, PAGE *, int, PAGE **));
-int __ham_get_cpage __P((DBC *, db_lockmode_t));
-int __ham_next_cpage __P((DBC *, db_pgno_t, int));
-int __ham_lock_bucket __P((DBC *, db_lockmode_t));
-void __ham_dpair __P((DB *, PAGE *, u_int32_t));
-int __ham_insdel_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __ham_newpage_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __ham_replace_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __ham_splitdata_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __ham_copypage_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __ham_metagroup_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __ham_groupalloc_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __ham_curadj_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __ham_chgpg_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __ham_reclaim __P((DB *, DB_TXN *txn));
-int __ham_stat __P((DB *, void *, void *(*)(size_t), u_int32_t));
- int __ham_traverse __P((DB *, DBC *, db_lockmode_t,
- int (*)(DB *, PAGE *, void *, int *), void *));
-int __ham_30_hashmeta __P((DB *, char *, u_int8_t *));
-int __ham_30_sizefix __P((DB *, DB_FH *, char *, u_int8_t *));
-int __ham_31_hashmeta
- __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *));
-int __ham_31_hash
- __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *));
-int __ham_vrfy_meta __P((DB *, VRFY_DBINFO *, HMETA *,
- db_pgno_t, u_int32_t));
-int __ham_vrfy __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t,
- u_int32_t));
-int __ham_vrfy_structure __P((DB *, VRFY_DBINFO *, db_pgno_t,
- u_int32_t));
-int __ham_vrfy_hashing __P((DB *,
- u_int32_t, HMETA *, u_int32_t, db_pgno_t, u_int32_t,
- u_int32_t (*) __P((DB *, const void *, u_int32_t))));
-int __ham_salvage __P((DB *, VRFY_DBINFO *, db_pgno_t, PAGE *,
- void *, int (*)(void *, const void *), u_int32_t));
-int __ham_meta2pgset __P((DB *, VRFY_DBINFO *, HMETA *, u_int32_t,
- DB *));
-#if defined(__cplusplus)
-}
-#endif
-#endif /* _hash_ext_h_ */
diff --git a/bdb/include/lock_ext.h b/bdb/include/lock_ext.h
deleted file mode 100644
index 7ed9b1c695b..00000000000
--- a/bdb/include/lock_ext.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/* DO NOT EDIT: automatically built by dist/s_include. */
-#ifndef _lock_ext_h_
-#define _lock_ext_h_
-#if defined(__cplusplus)
-extern "C" {
-#endif
-int __lock_downgrade __P((DB_ENV *,
- DB_LOCK *, db_lockmode_t, u_int32_t));
-int __lock_addfamilylocker __P((DB_ENV *, u_int32_t, u_int32_t));
-int __lock_freefamilylocker __P((DB_LOCKTAB *, u_int32_t));
-void __lock_freelocker __P((DB_LOCKTAB *,
- DB_LOCKREGION *, DB_LOCKER *, u_int32_t));
-int __lock_getlocker __P((DB_LOCKTAB *,
- u_int32_t, u_int32_t, int, DB_LOCKER **));
-int __lock_getobj __P((DB_LOCKTAB *,
- const DBT *, u_int32_t, int, DB_LOCKOBJ **));
-int __lock_promote __P((DB_LOCKTAB *, DB_LOCKOBJ *, int));
-void __lock_printlock __P((DB_LOCKTAB *, struct __db_lock *, int));
-int __lock_set_lk_conflicts __P((DB_ENV *, u_int8_t *, int));
-int __lock_set_lk_detect __P((DB_ENV *, u_int32_t));
-int __lock_set_lk_max __P((DB_ENV *, u_int32_t));
-int __lock_set_lk_max_locks __P((DB_ENV *, u_int32_t));
-int __lock_set_lk_max_lockers __P((DB_ENV *, u_int32_t));
-int __lock_set_lk_max_objects __P((DB_ENV *, u_int32_t));
-void __lock_dbenv_create __P((DB_ENV *));
-void __lock_dbenv_close __P((DB_ENV *));
-int __lock_open __P((DB_ENV *));
-int __lock_close __P((DB_ENV *));
-void __lock_region_destroy __P((DB_ENV *, REGINFO *));
-void __lock_dump_region __P((DB_ENV *, char *, FILE *));
-int __lock_cmp __P((const DBT *, DB_LOCKOBJ *));
-int __lock_locker_cmp __P((u_int32_t, DB_LOCKER *));
-u_int32_t __lock_ohash __P((const DBT *));
-u_int32_t __lock_lhash __P((DB_LOCKOBJ *));
-u_int32_t __lock_locker_hash __P((u_int32_t));
-#if defined(__cplusplus)
-}
-#endif
-#endif /* _lock_ext_h_ */
diff --git a/bdb/include/log_ext.h b/bdb/include/log_ext.h
deleted file mode 100644
index 985c5d7745b..00000000000
--- a/bdb/include/log_ext.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* DO NOT EDIT: automatically built by dist/s_include. */
-#ifndef _log_ext_h_
-#define _log_ext_h_
-#if defined(__cplusplus)
-extern "C" {
-#endif
-int __log_open __P((DB_ENV *));
-int __log_find __P((DB_LOG *, int, int *, logfile_validity *));
-int __log_valid __P((DB_LOG *, u_int32_t, int, logfile_validity *));
-int __log_close __P((DB_ENV *));
-int __log_lastckp __P((DB_ENV *, DB_LSN *));
-int __log_findckp __P((DB_ENV *, DB_LSN *));
-int __log_get __P((DB_LOG *, DB_LSN *, DBT *, u_int32_t, int));
-void __log_dbenv_create __P((DB_ENV *));
-int __log_put __P((DB_ENV *, DB_LSN *, const DBT *, u_int32_t));
-int __log_name __P((DB_LOG *,
- u_int32_t, char **, DB_FH *, u_int32_t));
-int __log_register_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __log_reopen_file __P((DB_ENV *,
- char *, int32_t, u_int8_t *, db_pgno_t));
-int __log_add_logid __P((DB_ENV *, DB_LOG *, DB *, int32_t));
-int __db_fileid_to_db __P((DB_ENV *, DB **, int32_t, int));
-void __log_close_files __P((DB_ENV *));
-void __log_rem_logid __P((DB_LOG *, DB *, int32_t));
-int __log_lid_to_fname __P((DB_LOG *, int32_t, FNAME **));
-int __log_filelist_update
- __P((DB_ENV *, DB *, int32_t, const char *, int *));
-int __log_file_lock __P((DB *));
-#if defined(__cplusplus)
-}
-#endif
-#endif /* _log_ext_h_ */
diff --git a/bdb/include/mp_ext.h b/bdb/include/mp_ext.h
deleted file mode 100644
index 9f2b8c61f45..00000000000
--- a/bdb/include/mp_ext.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* DO NOT EDIT: automatically built by dist/s_include. */
-#ifndef _mp_ext_h_
-#define _mp_ext_h_
-#if defined(__cplusplus)
-extern "C" {
-#endif
-int __memp_alloc __P((DB_MPOOL *,
- REGINFO *, MPOOLFILE *, size_t, roff_t *, void *));
-int __memp_bhwrite
- __P((DB_MPOOL *, MPOOLFILE *, BH *, int *, int *));
-int __memp_pgread __P((DB_MPOOLFILE *, BH *, int));
-int __memp_pgwrite
- __P((DB_MPOOL *, DB_MPOOLFILE *, BH *, int *, int *));
-int __memp_pg __P((DB_MPOOLFILE *, BH *, int));
-void __memp_bhfree __P((DB_MPOOL *, BH *, int));
-void __memp_set_unlink __P((DB_MPOOLFILE *));
-void __memp_clear_unlink __P((DB_MPOOLFILE *));
-int __memp_fopen __P((DB_MPOOL *, MPOOLFILE *, const char *,
- u_int32_t, int, size_t, int, DB_MPOOL_FINFO *, DB_MPOOLFILE **));
-void __memp_mf_discard __P((DB_MPOOL *, MPOOLFILE *));
-int __memp_fremove __P((DB_MPOOLFILE *));
-char * __memp_fn __P((DB_MPOOLFILE *));
-char * __memp_fns __P((DB_MPOOL *, MPOOLFILE *));
-void __memp_dbenv_create __P((DB_ENV *));
-int __memp_open __P((DB_ENV *));
-int __memp_close __P((DB_ENV *));
-void __mpool_region_destroy __P((DB_ENV *, REGINFO *));
-void __memp_dump_region __P((DB_ENV *, char *, FILE *));
-int __mp_xxx_fh __P((DB_MPOOLFILE *, DB_FH **));
-#if defined(__cplusplus)
-}
-#endif
-#endif /* _mp_ext_h_ */
diff --git a/bdb/include/os_ext.h b/bdb/include/os_ext.h
deleted file mode 100644
index ae9e3d304f2..00000000000
--- a/bdb/include/os_ext.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* DO NOT EDIT: automatically built by dist/s_include. */
-#ifndef _os_ext_h_
-#define _os_ext_h_
-#if defined(__cplusplus)
-extern "C" {
-#endif
-int __os_abspath __P((const char *));
-int __os_strdup __P((DB_ENV *, const char *, void *));
-int __os_calloc __P((DB_ENV *, size_t, size_t, void *));
-int __os_malloc __P((DB_ENV *, size_t, void *(*)(size_t), void *));
-int __os_realloc __P((DB_ENV *,
- size_t, void *(*)(void *, size_t), void *));
-void __os_free __P((void *, size_t));
-void __os_freestr __P((void *));
-void *__ua_memcpy __P((void *, const void *, size_t));
-int __os_dirlist __P((DB_ENV *, const char *, char ***, int *));
-void __os_dirfree __P((char **, int));
-int __os_get_errno __P((void));
-void __os_set_errno __P((int));
-int __os_fileid __P((DB_ENV *, const char *, int, u_int8_t *));
-int __os_finit __P((DB_ENV *, DB_FH *, size_t, int));
-int __os_fpinit __P((DB_ENV *, DB_FH *, db_pgno_t, int, int));
-int __os_fsync __P((DB_ENV *, DB_FH *));
-int __os_openhandle __P((DB_ENV *, const char *, int, int, DB_FH *));
-int __os_closehandle __P((DB_FH *));
-int __os_r_sysattach __P((DB_ENV *, REGINFO *, REGION *));
-int __os_r_sysdetach __P((DB_ENV *, REGINFO *, int));
-int __os_mapfile __P((DB_ENV *,
- char *, DB_FH *, size_t, int, void **));
-int __os_unmapfile __P((DB_ENV *, void *, size_t));
-u_int32_t __db_oflags __P((int));
-int __db_omode __P((const char *));
-int __os_open __P((DB_ENV *, const char *, u_int32_t, int, DB_FH *));
-int __os_shmname __P((DB_ENV *, const char *, char **));
-int __os_r_attach __P((DB_ENV *, REGINFO *, REGION *));
-int __os_r_detach __P((DB_ENV *, REGINFO *, int));
-int __os_rename __P((DB_ENV *, const char *, const char *));
-int __os_isroot __P((void));
-char *__db_rpath __P((const char *));
-int __os_io __P((DB_ENV *, DB_IO *, int, size_t *));
-int __os_read __P((DB_ENV *, DB_FH *, void *, size_t, size_t *));
-int __os_write __P((DB_ENV *, DB_FH *, void *, size_t, size_t *));
-int __os_seek __P((DB_ENV *,
- DB_FH *, size_t, db_pgno_t, u_int32_t, int, DB_OS_SEEK));
-int __os_sleep __P((DB_ENV *, u_long, u_long));
-int __os_spin __P((void));
-void __os_yield __P((DB_ENV*, u_long));
-int __os_exists __P((const char *, int *));
-int __os_ioinfo __P((DB_ENV *, const char *,
- DB_FH *, u_int32_t *, u_int32_t *, u_int32_t *));
-int __os_tmpdir __P((DB_ENV *, u_int32_t));
-int __os_unlink __P((DB_ENV *, const char *));
-int __os_region_unlink __P((DB_ENV *, const char *));
-#if defined(DB_WIN32)
-int __os_win32_errno __P((void));
-#endif
-int __os_fpinit __P((DB_ENV *, DB_FH *, db_pgno_t, int, int));
-int __os_is_winnt __P((void));
-#if defined(__cplusplus)
-}
-#endif
-#endif /* _os_ext_h_ */
diff --git a/bdb/include/qam_ext.h b/bdb/include/qam_ext.h
deleted file mode 100644
index f6e95110c0e..00000000000
--- a/bdb/include/qam_ext.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/* DO NOT EDIT: automatically built by dist/s_include. */
-#ifndef _qam_ext_h_
-#define _qam_ext_h_
-#if defined(__cplusplus)
-extern "C" {
-#endif
-int __qam_position
- __P((DBC *, db_recno_t *, qam_position_mode, int *));
-int __qam_pitem
- __P((DBC *, QPAGE *, u_int32_t, db_recno_t, DBT *));
-int __qam_put __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
-int __qam_delete __P((DB *, DB_TXN *, DBT *, u_int32_t));
-int __qam_c_dup __P((DBC *, DBC *));
-int __qam_c_init __P((DBC *));
-int __qam_mswap __P((PAGE *));
-int __qam_pgin_out __P((DB_ENV *, db_pgno_t, void *, DBT *));
-int __qam_fprobe __P((DB *, db_pgno_t, void *, qam_probe_mode, int));
-int __qam_fclose __P((DB *, db_pgno_t));
-int __qam_fremove __P((DB *, db_pgno_t));
-int __qam_sync __P((DB *, u_int32_t));
-int __qam_gen_filelist __P(( DB *, QUEUE_FILELIST **));
-int __qam_db_create __P((DB *));
-int __qam_db_close __P((DB *));
-int __db_prqueue __P((DB *, u_int32_t));
-int __qam_remove __P((DB *, const char *,
- const char *, DB_LSN *, int (**)(DB *, void*), void **));
-int __qam_rename __P((DB *,
- const char *, const char *, const char *));
-int __qam_open __P((DB *, const char *, db_pgno_t, int, u_int32_t));
-int __qam_metachk __P((DB *, const char *, QMETA *));
-int __qam_inc_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __qam_incfirst_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __qam_mvptr_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __qam_del_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __qam_delext_recover __P((DB_ENV *,
- DBT *, DB_LSN *, db_recops, void *));
-int __qam_add_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __qam_delete_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __qam_rename_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __qam_stat __P((DB *, void *, void *(*)(size_t), u_int32_t));
-int __qam_31_qammeta __P((DB *, char *, u_int8_t *));
-int __qam_32_qammeta __P((DB *, char *, u_int8_t *));
-int __qam_vrfy_meta __P((DB *, VRFY_DBINFO *, QMETA *,
- db_pgno_t, u_int32_t));
-int __qam_vrfy_data __P((DB *, VRFY_DBINFO *, QPAGE *,
- db_pgno_t, u_int32_t));
-int __qam_vrfy_structure __P((DB *, VRFY_DBINFO *, u_int32_t));
-#if defined(__cplusplus)
-}
-#endif
-#endif /* _qam_ext_h_ */
diff --git a/bdb/include/tcl_ext.h b/bdb/include/tcl_ext.h
deleted file mode 100644
index 9baf7e4fdcf..00000000000
--- a/bdb/include/tcl_ext.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* DO NOT EDIT: automatically built by dist/s_include. */
-#ifndef _tcl_ext_h_
-#define _tcl_ext_h_
-#if defined(__cplusplus)
-extern "C" {
-#endif
-int bdb_HCommand __P((Tcl_Interp *, int, Tcl_Obj * CONST*));
-#if DB_DBM_HSEARCH != 0
-int bdb_NdbmOpen __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DBM **));
-#endif
-#if DB_DBM_HSEARCH != 0
-int bdb_DbmCommand
- __P((Tcl_Interp *, int, Tcl_Obj * CONST*, int, DBM *));
-#endif
-int ndbm_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*));
-int bdb_RandCommand __P((Tcl_Interp *, int, Tcl_Obj * CONST*));
-int tcl_Mutex __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *,
- DBTCL_INFO *));
-int db_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*));
-int dbc_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*));
-int env_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*));
-int tcl_EnvRemove __P((Tcl_Interp *, int, Tcl_Obj * CONST*,
- DB_ENV *, DBTCL_INFO *));
-int tcl_EnvVerbose __P((Tcl_Interp *, DB_ENV *, Tcl_Obj *,
- Tcl_Obj *));
-int tcl_EnvTest __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *));
-DBTCL_INFO *_NewInfo __P((Tcl_Interp *,
- void *, char *, enum INFOTYPE));
-void *_NameToPtr __P((CONST char *));
-char *_PtrToName __P((CONST void *));
-DBTCL_INFO *_PtrToInfo __P((CONST void *));
-DBTCL_INFO *_NameToInfo __P((CONST char *));
-void _SetInfoData __P((DBTCL_INFO *, void *));
-void _DeleteInfo __P((DBTCL_INFO *));
-int _SetListElem __P((Tcl_Interp *,
- Tcl_Obj *, void *, int, void *, int));
-int _SetListElemInt __P((Tcl_Interp *, Tcl_Obj *, void *, int));
-int _SetListRecnoElem __P((Tcl_Interp *, Tcl_Obj *,
- db_recno_t, u_char *, int));
-int _GetGlobPrefix __P((char *, char **));
-int _ReturnSetup __P((Tcl_Interp *, int, char *));
-int _ErrorSetup __P((Tcl_Interp *, int, char *));
-void _ErrorFunc __P((CONST char *, char *));
-int _GetLsn __P((Tcl_Interp *, Tcl_Obj *, DB_LSN *));
-void _debug_check __P((void));
-int tcl_LockDetect __P((Tcl_Interp *, int,
- Tcl_Obj * CONST*, DB_ENV *));
-int tcl_LockGet __P((Tcl_Interp *, int,
- Tcl_Obj * CONST*, DB_ENV *));
-int tcl_LockStat __P((Tcl_Interp *, int,
- Tcl_Obj * CONST*, DB_ENV *));
-int tcl_LockVec __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *));
-int tcl_LogArchive __P((Tcl_Interp *, int,
- Tcl_Obj * CONST*, DB_ENV *));
-int tcl_LogCompare __P((Tcl_Interp *, int,
- Tcl_Obj * CONST*));
-int tcl_LogFile __P((Tcl_Interp *, int,
- Tcl_Obj * CONST*, DB_ENV *));
-int tcl_LogFlush __P((Tcl_Interp *, int,
- Tcl_Obj * CONST*, DB_ENV *));
-int tcl_LogGet __P((Tcl_Interp *, int,
- Tcl_Obj * CONST*, DB_ENV *));
-int tcl_LogPut __P((Tcl_Interp *, int,
- Tcl_Obj * CONST*, DB_ENV *));
-int tcl_LogRegister __P((Tcl_Interp *, int,
- Tcl_Obj * CONST*, DB_ENV *));
-int tcl_LogStat __P((Tcl_Interp *, int,
- Tcl_Obj * CONST*, DB_ENV *));
-int tcl_LogUnregister __P((Tcl_Interp *, int,
- Tcl_Obj * CONST*, DB_ENV *));
-void _MpInfoDelete __P((Tcl_Interp *, DBTCL_INFO *));
-int tcl_MpSync __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *));
-int tcl_MpTrickle __P((Tcl_Interp *, int,
- Tcl_Obj * CONST*, DB_ENV *));
-int tcl_Mp __P((Tcl_Interp *, int,
- Tcl_Obj * CONST*, DB_ENV *, DBTCL_INFO *));
-int tcl_MpStat __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *));
-void _TxnInfoDelete __P((Tcl_Interp *, DBTCL_INFO *));
-int tcl_TxnCheckpoint __P((Tcl_Interp *, int,
- Tcl_Obj * CONST*, DB_ENV *));
-int tcl_Txn __P((Tcl_Interp *, int,
- Tcl_Obj * CONST*, DB_ENV *, DBTCL_INFO *));
-int tcl_TxnStat __P((Tcl_Interp *, int,
- Tcl_Obj * CONST*, DB_ENV *));
-int txn_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*));
-#if defined(__cplusplus)
-}
-#endif
-#endif /* _tcl_ext_h_ */
diff --git a/bdb/include/txn_ext.h b/bdb/include/txn_ext.h
deleted file mode 100644
index ee6922d701c..00000000000
--- a/bdb/include/txn_ext.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* DO NOT EDIT: automatically built by dist/s_include. */
-#ifndef _txn_ext_h_
-#define _txn_ext_h_
-#if defined(__cplusplus)
-extern "C" {
-#endif
-int __txn_xa_begin __P((DB_ENV *, DB_TXN *));
-int __txn_end __P((DB_TXN *, int));
-int __txn_activekids __P((DB_ENV *, u_int32_t, DB_TXN *));
-int __txn_regop_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __txn_xa_regop_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __txn_ckp_recover
-__P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-int __txn_child_recover
- __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-void __txn_dbenv_create __P((DB_ENV *));
-int __txn_open __P((DB_ENV *));
-int __txn_close __P((DB_ENV *));
-#if defined(__cplusplus)
-}
-#endif
-#endif /* _txn_ext_h_ */
diff --git a/bdb/include/xa_ext.h b/bdb/include/xa_ext.h
deleted file mode 100644
index cc16ba18337..00000000000
--- a/bdb/include/xa_ext.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/* DO NOT EDIT: automatically built by dist/s_include. */
-#ifndef _xa_ext_h_
-#define _xa_ext_h_
-#if defined(__cplusplus)
-extern "C" {
-#endif
-int __db_xa_create __P((DB *));
-int __db_rmid_to_env __P((int rmid, DB_ENV **envp));
-int __db_xid_to_txn __P((DB_ENV *, XID *, size_t *));
-int __db_map_rmid __P((int, DB_ENV *));
-int __db_unmap_rmid __P((int));
-int __db_map_xid __P((DB_ENV *, XID *, size_t));
-void __db_unmap_xid __P((DB_ENV *, XID *, size_t));
-#if defined(__cplusplus)
-}
-#endif
-#endif /* _xa_ext_h_ */
diff --git a/build-tags b/build-tags
deleted file mode 100755
index 90b957eb3bc..00000000000
--- a/build-tags
+++ /dev/null
@@ -1,11 +0,0 @@
-#! /bin/sh
-
-if [ ! -f configure.in ] ; then
- echo "$0 must be run from MySQL source root"
- exit 1
-fi
-
-rm -f TAGS
-find -not -path \*SCCS\* -and \
- \( -name \*.cc -or -name \*.h -or -name \*.yy -or -name \*.c \) \
- -print -exec etags -o TAGS --append {} \;
diff --git a/client/Makefile.am b/client/Makefile.am
index 1710e573d20..cccb612af98 100644
--- a/client/Makefile.am
+++ b/client/Makefile.am
@@ -16,13 +16,13 @@
# This file is public domain and comes with NO WARRANTY of any kind
-INCLUDES = -I$(srcdir)/../include \
+INCLUDES = -I$(srcdir)/../include $(openssl_includes) \
-I../include -I$(srcdir)/.. -I$(top_srcdir) \
-I..
LIBS = @CLIENT_LIBS@
LDADD = @CLIENT_EXTRA_LDFLAGS@ ../libmysql/libmysqlclient.la
bin_PROGRAMS = mysql mysqladmin mysqlcheck mysqlshow \
- mysqldump mysqlimport mysqltest mysqlbinlog
+ mysqldump mysqlimport mysqltest mysqlbinlog mysqlmanagerc mysqlmanager-pwgen
noinst_PROGRAMS = insert_test select_test thread_test
noinst_HEADERS = sql_string.h completion_hash.h my_readline.h \
client_priv.h
@@ -41,6 +41,8 @@ mysqltest_SOURCES= mysqltest.c
mysqltest_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES)
mysqlbinlog_SOURCES = mysqlbinlog.cc
mysqlbinlog_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES)
+mysqlmanagerc_SOURCES = mysqlmanagerc.c
+mysqlmanagerc_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES)
sql_src=log_event.h log_event.cc
# Fix for mit-threads
diff --git a/client/client_priv.h b/client/client_priv.h
index 56eaf311070..e8355e801a2 100644
--- a/client/client_priv.h
+++ b/client/client_priv.h
@@ -1,24 +1,25 @@
/* 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 */
/* Common defines for all clients */
-#include <global.h>
+#include <my_global.h>
#include <my_sys.h>
#include <m_string.h>
+#include <mysql_embed.h>
#include <mysql.h>
#include <errmsg.h>
#include <getopt.h>
diff --git a/client/completion_hash.cc b/client/completion_hash.cc
index 006427f0295..ff5d0b28e41 100644
--- a/client/completion_hash.cc
+++ b/client/completion_hash.cc
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Quick & light hash implementation for tab completion purposes
*
@@ -22,7 +21,7 @@
* Small portability changes by Monty. Changed also to use my_malloc/my_free
*/
-#include <global.h>
+#include <my_global.h>
#include <m_string.h>
#undef SAFEMALLOC // Speed things up
#include <my_sys.h>
@@ -47,10 +46,12 @@ int completion_hash_init(HashTable *ht, uint nSize)
ht->arBuckets = (Bucket **) my_malloc(nSize* sizeof(Bucket *),
MYF(MY_ZEROFILL | MY_WME));
- if (!ht->arBuckets) {
+ if (!ht->arBuckets)
+ {
ht->initialized = 0;
return FAILURE;
}
+ init_alloc_root(&ht->mem_root, 8192, 0);
ht->pHashFunction = hashpjw;
ht->nTableSize = nSize;
ht->initialized = 1;
@@ -78,8 +79,7 @@ int completion_hash_update(HashTable *ht, char *arKey, uint nKeyLength,
if (!memcmp(p->arKey, arKey, nKeyLength)) {
entry *n;
- n = (entry *) my_malloc(sizeof(entry),
- MYF(MY_WME));
+ n = (entry *) alloc_root(&ht->mem_root,sizeof(entry));
n->pNext = p->pData;
n->str = str;
p->pData = n;
@@ -91,20 +91,16 @@ int completion_hash_update(HashTable *ht, char *arKey, uint nKeyLength,
p = p->pNext;
}
- p = (Bucket *) my_malloc(sizeof(Bucket),MYF(MY_WME));
-
- if (!p) {
+ if (!(p = (Bucket *) alloc_root(&ht->mem_root, sizeof(Bucket))))
return FAILURE;
- }
+
p->arKey = arKey;
p->nKeyLength = nKeyLength;
p->h = h;
- p->pData = (entry*) my_malloc(sizeof(entry),MYF(MY_WME));
- if (!p->pData) {
- my_free((gptr) p,MYF(0));
+ if (!(p->pData = (entry*) alloc_root(&ht->mem_root, sizeof(entry))))
return FAILURE;
- }
+
p->pData->str = str;
p->pData->pNext = 0;
p->count = 1;
@@ -209,24 +205,7 @@ Bucket *find_longest_match(HashTable *ht, char *str, uint length,
void completion_hash_clean(HashTable *ht)
{
- uint i;
- entry *e, *t;
- Bucket *b, *tmp;
-
- for (i=0; i<ht->nTableSize; i++) {
- b = ht->arBuckets[i];
- while (b) {
- e = b->pData;
- while (e) {
- t = e;
- e = e->pNext;
- my_free((gptr) t,MYF(0));
- }
- tmp = b;
- b = b->pNext;
- my_free((gptr) tmp,MYF(0));
- }
- }
+ free_root(&ht->mem_root,MYF(0));
bzero((char*) ht->arBuckets,ht->nTableSize*sizeof(Bucket *));
}
@@ -241,9 +220,7 @@ void completion_hash_free(HashTable *ht)
void add_word(HashTable *ht,char *str)
{
int i;
- int length= (int) strlen(str);
-
- for (i=1; i<=length; i++) {
+ char *pos=str;
+ for (i=1; *pos; i++, pos++)
completion_hash_update(ht, str, i, str);
- }
}
diff --git a/client/completion_hash.h b/client/completion_hash.h
index 583a42bbbe5..c0853fddfe7 100644
--- a/client/completion_hash.h
+++ b/client/completion_hash.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
+
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,
@@ -22,26 +22,29 @@
#define FAILURE 1
#include <sys/types.h>
+#include <my_sys.h>
typedef struct _entry {
char *str;
struct _entry *pNext;
} entry;
-typedef struct bucket {
- uint h; /* Used for numeric indexing */
- char *arKey;
- uint nKeyLength;
- uint count;
- entry *pData;
- struct bucket *pNext;
+typedef struct bucket
+{
+ uint h; /* Used for numeric indexing */
+ char *arKey;
+ uint nKeyLength;
+ uint count;
+ entry *pData;
+ struct bucket *pNext;
} Bucket;
typedef struct hashtable {
- uint nTableSize;
- uint initialized;
- uint(*pHashFunction) (char *arKey, uint nKeyLength);
- Bucket **arBuckets;
+ uint nTableSize;
+ uint initialized;
+ MEM_ROOT mem_root;
+ uint(*pHashFunction) (char *arKey, uint nKeyLength);
+ Bucket **arBuckets;
} HashTable;
extern int completion_hash_init(HashTable *ht, uint nSize);
@@ -54,4 +57,4 @@ extern void completion_hash_clean(HashTable *ht);
extern int completion_hash_exists(HashTable *ht, char *arKey, uint nKeyLength);
extern void completion_hash_free(HashTable *ht);
-#endif /* _HASH_ */
+#endif /* _HASH_ */
diff --git a/client/connect_test.c b/client/connect_test.c
index 661d448fdb0..fd81ad635ad 100644
--- a/client/connect_test.c
+++ b/client/connect_test.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <stdio.h>
#include <stdlib.h>
diff --git a/client/errmsg.c b/client/errmsg.c
index 67cfe874f77..6cb28f3f53e 100644
--- a/client/errmsg.c
+++ b/client/errmsg.c
@@ -1,24 +1,23 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Error messages for MySQL clients */
/* error messages for the demon is in share/language/errmsg.sys */
-#include <global.h>
+#include <my_global.h>
#include <my_sys.h>
#include "errmsg.h"
@@ -45,7 +44,13 @@ const char *client_errors[]=
"Kann Named Pipe nicht oeffnen. Host: %-.64s pipe: %-.32s (%lu)",
"Kann den Status der Named Pipe nicht setzen. Host: %-.64s pipe: %-.32s (%lu)",
"Can't initialize character set %-.64s (path: %-.64s)",
- "Got packet bigger than 'max_allowed_packet'"
+ "Got packet bigger than 'max_allowed_packet'",
+ "Embedded server",
+ "Error on SHOW SLAVE STATUS:",
+ "Error on SHOW SLAVE HOSTS:",
+ "Error connecting to slave:",
+ "Error connecting to master:"
+
};
/* Start of code added by Roberto M. Serqueira - martinsc@uol.com.br - 05.24.2001 */
@@ -73,7 +78,12 @@ const char *client_errors[]=
"Não pode abrir 'named pipe' para o 'host' %-.64s - 'pipe' %-.32s (%lu)",
"Não pode estabelecer o estado do 'named pipe' para o 'host' %-.64s - 'pipe' %-.32s (%lu)",
"Não pode inicializar conjunto de caracteres %-.64s (caminho %-.64s)",
- "Obteve pacote maior do que 'max_allowed_packet'"
+ "Obteve pacote maior do que 'max_allowed_packet'",
+ "Embedded server",
+ "Error on SHOW SLAVE STATUS:",
+ "Error on SHOW SLAVE HOSTS:",
+ "Error connecting to slave:",
+ "Error connecting to master:"
};
#else /* ENGLISH */
@@ -99,7 +109,12 @@ const char *client_errors[]=
"Can't open named pipe to host: %-.64s pipe: %-.32s (%lu)",
"Can't set state of named pipe to host: %-.64s pipe: %-.32s (%lu)",
"Can't initialize character set %-.64s (path: %-.64s)",
- "Got packet bigger than 'max_allowed_packet'"
+ "Got packet bigger than 'max_allowed_packet'",
+ "Embedded server",
+ "Error on SHOW SLAVE STATUS:",
+ "Error on SHOW SLAVE HOSTS:",
+ "Error connecting to slave:",
+ "Error connecting to master:"
};
#endif
diff --git a/client/get_password.c b/client/get_password.c
index 25069a14b75..9928d24de32 100644
--- a/client/get_password.c
+++ b/client/get_password.c
@@ -1,25 +1,24 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
** Ask for a password from tty
** This is an own file to avoid conflicts with curses
*/
-#include <global.h>
+#include <my_global.h>
#include <my_sys.h>
#include "mysql.h"
#include <m_string.h>
@@ -72,7 +71,7 @@ char *get_tty_password(char *opt_message)
char *pos=to,*end=to+sizeof(to)-1;
int i=0;
DBUG_ENTER("get_tty_password");
- fprintf(stdout,opt_message ? opt_message : "Enter password: ");
+ fprintf(stderr,opt_message ? opt_message : "Enter password: ");
for (;;)
{
char tmp;
@@ -125,8 +124,8 @@ static void get_password(char *to,uint length,int fd,bool echo)
{
if (echo)
{
- fputs("\b \b",stdout);
- fflush(stdout);
+ fputs("\b \b",stderr);
+ fflush(stderr);
}
pos--;
continue;
@@ -138,8 +137,8 @@ static void get_password(char *to,uint length,int fd,bool echo)
continue;
if (echo)
{
- fputc('*',stdout);
- fflush(stdout);
+ fputc('*',stderr);
+ fflush(stderr);
}
*(pos++) = tmp;
}
@@ -172,10 +171,10 @@ char *get_tty_password(char *opt_message)
memset(passbuff, 0, _PASSWORD_LEN);
#endif
#else
- if (isatty(fileno(stdout)))
+ if (isatty(fileno(stderr)))
{
- fputs(opt_message ? opt_message : "Enter password: ",stdout);
- fflush(stdout);
+ fputs(opt_message ? opt_message : "Enter password: ",stderr);
+ fflush(stderr);
}
#if defined(HAVE_TERMIOS_H)
tcgetattr(fileno(stdin), &org);
@@ -184,7 +183,7 @@ char *get_tty_password(char *opt_message)
tmp.c_cc[VMIN] = 1;
tmp.c_cc[VTIME] = 0;
tcsetattr(fileno(stdin), TCSADRAIN, &tmp);
- get_password(buff, sizeof(buff)-1, fileno(stdin), isatty(fileno(stdout)));
+ get_password(buff, sizeof(buff)-1, fileno(stdin), isatty(fileno(stderr)));
tcsetattr(fileno(stdin), TCSADRAIN, &org);
#elif defined(HAVE_TERMIO_H)
ioctl(fileno(stdin), (int) TCGETA, &org);
@@ -193,7 +192,7 @@ char *get_tty_password(char *opt_message)
tmp.c_cc[VMIN] = 1;
tmp.c_cc[VTIME]= 0;
ioctl(fileno(stdin),(int) TCSETA, &tmp);
- get_password(buff,sizeof(buff)-1,fileno(stdin),isatty(fileno(stdout)));
+ get_password(buff,sizeof(buff)-1,fileno(stdin),isatty(fileno(stderr)));
ioctl(fileno(stdin),(int) TCSETA, &org);
#else
gtty(fileno(stdin), &org);
@@ -201,11 +200,11 @@ char *get_tty_password(char *opt_message)
tmp.sg_flags &= ~ECHO;
tmp.sg_flags |= RAW;
stty(fileno(stdin), &tmp);
- get_password(buff,sizeof(buff)-1,fileno(stdin),isatty(fileno(stdout)));
+ get_password(buff,sizeof(buff)-1,fileno(stdin),isatty(fileno(stderr)));
stty(fileno(stdin), &org);
#endif
- if (isatty(fileno(stdout)))
- fputc('\n',stdout);
+ if (isatty(fileno(stderr)))
+ fputc('\n',stderr);
#endif /* HAVE_GETPASS */
DBUG_RETURN(my_strdup(buff,MYF(MY_FAE)));
diff --git a/client/insert_test.c b/client/insert_test.c
index 640935d63b2..42691df6875 100644
--- a/client/insert_test.c
+++ b/client/insert_test.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <stdio.h>
#include <stdlib.h>
@@ -34,19 +33,13 @@ int main(int argc, char **argv)
exit(1);
}
- if (!(sock = mysql_connect(&mysql,NULL,0,0)))
+ if (!(sock = mysql_real_connect(&mysql,NULL,NULL,NULL,argv[1],0,NULL,0)))
{
fprintf(stderr,"Couldn't connect to engine!\n%s\n",mysql_error(&mysql));
perror("");
exit(1);
}
- if (mysql_select_db(sock,argv[1]))
- {
- fprintf(stderr,"Couldn't select database %s!\n%s\n",argv[1],
- mysql_error(sock));
- }
-
num = atoi(argv[2]);
count = 0;
while (count < num)
diff --git a/client/list_test.c b/client/list_test.c
index 718cc45e012..06bf16d2751 100644
--- a/client/list_test.c
+++ b/client/list_test.c
@@ -1,34 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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 */
+/* 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 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,
+ This program is distributed in the hope that 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 __WIN__
#include <windows.h>
diff --git a/client/my_readline.h b/client/my_readline.h
index 547587bc19d..2e716eec4cf 100644
--- a/client/my_readline.h
+++ b/client/my_readline.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* readline for batch mode */
diff --git a/client/mysql.cc b/client/mysql.cc
index 60e97bff621..13f60fee64f 100644
--- a/client/mysql.cc
+++ b/client/mysql.cc
@@ -1,15 +1,15 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
+/* 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 */
@@ -19,9 +19,12 @@
*
* Written by:
* Michael 'Monty' Widenius
- * Andi Gutmans <andi@zend.com>
+ * Andi Gutmans <andi@zend.com>
* Zeev Suraski <zeev@zend.com>
* Jani Tolonen <jani@mysql.com>
+ * Matt Wagner <matt@mysql.com>
+ * Jeremy Cole <jcole@mysql.com>
+ * Tonu Samuel <tonu@mysql.com>
*
**/
@@ -33,8 +36,9 @@
#endif
#include "my_readline.h"
#include <signal.h>
+#include <violite.h>
-const char *VER="11.17";
+const char *VER="11.21";
/* Don't try to make a nice table if the data is too big */
#define MAX_COLUMN_LENGTH 1024
@@ -71,7 +75,6 @@ extern "C" {
#endif
#undef bcmp // Fix problem with new readline
-#undef bzero
#if defined( __WIN__) || defined(OS2)
#include <conio.h>
#else
@@ -115,7 +118,8 @@ static bool info_flag=0,ignore_errors=0,wait_flag=0,quick=0,
no_rehash=0,skip_updates=0,safe_updates=0,one_database=0,
opt_compress=0, using_opt_local_infile=0,
vertical=0,skip_line_numbers=0,skip_column_names=0,opt_html=0,
- opt_nopager=1, opt_outfile=0, no_named_cmds=1;
+ opt_xml=0,opt_nopager=1, opt_outfile=0, no_named_cmds=1,
+ opt_nobeep=0;
static uint verbose=0,opt_silent=0,opt_mysql_port=0, opt_local_infile=0;
static my_string opt_mysql_unix_port=0;
static int connect_flag=CLIENT_INTERACTIVE;
@@ -126,9 +130,16 @@ static String glob_buffer,old_buffer;
static int wait_time = 5;
static STATUS status;
static ulong select_limit,max_join_size,opt_connect_timeout=0;
+static char mysql_charsets_dir[FN_REFLEN+1];
+static const char *xmlmeta[] = {
+ "&", "&amp;",
+ "<", "&lt;",
+ 0, 0
+};
static char default_pager[FN_REFLEN];
char pager[FN_REFLEN], outfile[FN_REFLEN];
FILE *PAGER, *OUTFILE;
+MEM_ROOT hash_mem_root;
#include "sslopt-vars.h"
@@ -149,7 +160,7 @@ static int com_quit(String *str,char*),
com_connect(String *str,char*), com_status(String *str,char*),
com_use(String *str,char*), com_source(String *str, char*),
com_rehash(String *str, char*), com_tee(String *str, char*),
- com_notee(String *str, char*);
+ com_notee(String *str, char*), com_shell(String *str, char *);
#ifndef __WIN__
static int com_nopager(String *str, char*), com_pager(String *str, char*),
@@ -161,6 +172,7 @@ static int sql_connect(char *host,char *database,char *user,char *password,
uint silent);
static int put_info(const char *str,INFO_TYPE info,uint error=0);
static void safe_put_field(const char *pos,ulong length);
+static void xmlencode_print(const char *src, uint length);
static void init_pager();
static void end_pager();
static void init_tee();
@@ -204,6 +216,9 @@ static COMMANDS commands[] = {
{ "source", '.', com_source, 1,
"Execute a SQL script file. Takes a file name as an argument."},
{ "status", 's', com_status, 0, "Get status information from the server."},
+#ifndef __WIN__
+ { "system", '!', com_shell, 1, "Execute a system shell command."},
+#endif
{ "tee", 'T', com_tee, 1,
"Set outfile [to_outfile]. Append everything into given outfile." },
{ "use", 'u', com_use, 1,
@@ -232,6 +247,8 @@ static COMMANDS commands[] = {
};
static const char *load_default_groups[]= { "mysql","client",0 };
+static const char *server_default_groups[]=
+{ "server", "embedded", "mysql_SERVER", 0 };
#ifdef HAVE_READLINE
extern "C" void add_history(char *command); /* From readline directory */
@@ -245,6 +262,7 @@ static bool add_line(String &buffer,char *line,char *in_string);
static void remove_cntrl(String &buffer);
static void print_table_data(MYSQL_RES *result);
static void print_table_data_html(MYSQL_RES *result);
+static void print_table_data_xml(MYSQL_RES *result);
static void print_tab_data(MYSQL_RES *result);
static void print_table_data_vertically(MYSQL_RES *result);
static ulong start_timer(void);
@@ -288,7 +306,10 @@ int main(int argc,char *argv[])
!(status.line_buff=batch_readline_init(max_allowed_packet+512,stdin)))
exit(1);
glob_buffer.realloc(512);
- completion_hash_init(&ht,50);
+ mysql_server_init(0, NULL, (char**) server_default_groups);
+ completion_hash_init(&ht, 128);
+ init_alloc_root(&hash_mem_root, 16384, 0);
+ bzero((char*) &mysql, sizeof(mysql));
if (sql_connect(current_host,current_db,current_user,opt_password,
opt_silent))
{
@@ -311,9 +332,21 @@ int main(int argc,char *argv[])
mysql_thread_id(&mysql),mysql_get_server_info(&mysql));
put_info((char*) glob_buffer.ptr(),INFO_INFO);
+#ifdef HAVE_OPENSSL
+ if (mysql.net.vio->ssl_ && SSL_get_cipher(mysql.net.vio->ssl_))
+ {
+ sprintf((char*) glob_buffer.ptr(),
+ "SSL cipher in use is %s\n", SSL_get_cipher(mysql.net.vio->ssl_));
+ put_info((char*) glob_buffer.ptr(),INFO_INFO);
+ }
+ else
+ put_info("SSL is not in use\n",INFO_INFO);
+#endif /* HAVE_OPENSSL */
+
+
#ifdef HAVE_READLINE
initialize_readline(my_progname);
- if (!status.batch && !quick && !opt_html)
+ if (!status.batch && !quick && !opt_html && !opt_xml)
{
/*read-history from file, default ~/.mysql_history*/
if (getenv("MYSQL_HISTFILE"))
@@ -348,10 +381,16 @@ int main(int argc,char *argv[])
sig_handler mysql_end(int sig)
{
- if (connected)
- mysql_close(&mysql);
+ mysql_close(&mysql);
+#ifdef HAVE_OPENSSL
+ my_free(opt_ssl_key,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(opt_ssl_cert,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(opt_ssl_ca,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(opt_ssl_capath,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(opt_ssl_cipher,MYF(MY_ALLOW_ZERO_PTR));
+#endif
#ifdef HAVE_READLINE
- if (!status.batch && !quick && ! opt_html)
+ if (!status.batch && !quick && !opt_html && !opt_xml)
{
/* write-history */
if (verbose)
@@ -360,6 +399,8 @@ sig_handler mysql_end(int sig)
}
batch_readline_end(status.line_buff);
completion_hash_free(&ht);
+ free_root(&hash_mem_root,MYF(0));
+
#endif
if (sig >= 0)
put_info(sig ? "Aborted" : "Bye", INFO_RESULT);
@@ -371,6 +412,7 @@ sig_handler mysql_end(int sig)
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));
+ mysql_server_end();
my_end(info_flag ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
exit(status.exit_status);
}
@@ -392,10 +434,12 @@ static struct option long_options[] =
{"force", no_argument, 0, 'f'},
{"help", no_argument, 0, '?'},
{"html", no_argument, 0, 'H'},
+ {"xml", no_argument, 0, 'X'},
{"host", required_argument, 0, 'h'},
{"ignore-spaces", no_argument, 0, 'i'},
{"local-infile", optional_argument, 0, OPT_LOCAL_INFILE},
{"no-auto-rehash",no_argument, 0, 'A'},
+ {"no-beep", no_argument, 0, 'b'},
{"no-named-commands", no_argument, 0, 'g'},
{"no-tee", no_argument, 0, OPT_NOTEE},
#ifndef __WIN__
@@ -436,8 +480,8 @@ static struct option long_options[] =
CHANGEABLE_VAR changeable_vars[] = {
{ "connect_timeout", (long*) &opt_connect_timeout, 0, 0, 3600*12, 0, 1},
{ "max_allowed_packet", (long*) &max_allowed_packet,16*1024L*1024L,4096,
- 24*1024L*1024L, MALLOC_OVERHEAD,1024},
- { "net_buffer_length",(long*) &net_buffer_length,16384,1024,16*1024*1024L,
+ 512*1024L*1024L, MALLOC_OVERHEAD,1024},
+ { "net_buffer_length",(long*) &net_buffer_length,16384,1024,512*1024*1024L,
MALLOC_OVERHEAD,1024},
{ "select_limit", (long*) &select_limit, 1000L, 1, ~0L, 0, 1},
{ "max_join_size", (long*) &max_join_size, 1000000L, 1, ~0L, 0, 1},
@@ -451,14 +495,17 @@ static void usage(int version)
my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE);
if (version)
return;
- puts("Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB");
- 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("\
+Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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] [database]\n", my_progname);
printf("\n\
-?, --help Display this help and exit.\n\
-A, --no-auto-rehash No automatic rehashing. One has to use 'rehash' to\n\
get table and field completion. This gives a quicker\n\
start of mysql and disables rehashing on reconnect.\n\
+ -b, --no-beep Turn off beep on error.\n\
-B, --batch Print results with a tab as separator, each row on\n\
a new line. Doesn't use history file.\n\
--character-sets-dir=...\n\
@@ -466,7 +513,7 @@ static void usage(int version)
-C, --compress Use compression in server/client protocol.\n");
#ifndef DBUG_OFF
printf("\
- -#, --debug[=...] Debug log. Default is '%s'.\n",default_dbug_option);
+ -#, --debug[=...] Debug log. Default is '%s'.\n", default_dbug_option);
#endif
printf("\
-D, --database=.. Database to use.\n\
@@ -487,6 +534,7 @@ static void usage(int version)
-i, --ignore-space Ignore space after function names.\n\
-h, --host=... Connect to host.\n\
-H, --html Produce HTML output.\n\
+ -X, --xml Produce XML output.\n\
--local-infile=[1|0] Enable/disable LOAD DATA LOCAL INFILE\n\
-L, --skip-line-numbers\n\
Don't write line number for errors.\n");
@@ -512,14 +560,16 @@ static void usage(int version)
variable PAGER (%s).\n\
Valid pagers are less, more, cat [> filename], etc.\n\
See interactive help (\\h) also. This option does\n\
- not work in batch mode.\n", getenv("PAGER") ? getenv("PAGER") : "");
+ not work in batch mode.\n",
+ getenv("PAGER") ? getenv("PAGER") : "");
#endif
printf("\
-p[password], --password[=...]\n\
Password to use when connecting to server\n\
If password is not given it's asked from the tty.\n");
#ifdef __WIN__
- puts(" -W, --pipe Use named pipes to connect to server");
+ printf("\
+ -W, --pipe Use named pipes to connect to server");
#endif
printf("\n\
-P, --port=... Port number to use for connection.\n\
@@ -545,6 +595,7 @@ static void usage(int version)
-v, --verbose Write more. (-v -v -v gives the table output format)\n\
-V, --version Output version information and exit.\n\
-w, --wait Wait and retry if connection is down.\n");
+
print_defaults("my",load_default_groups);
printf("\nPossible variables for option --set-variable (-O) are:\n");
@@ -562,15 +613,20 @@ static int get_options(int argc, char **argv)
set_all_changeable_vars(changeable_vars);
while ((c=getopt_long(argc,argv,
- (char*) "?ABCD:LfgGHinNoqrstTU::vVw::WEe:h:O:P:S:u:#::p::",
+ (char*) "?AbBCD:LfgGHXinNoqrstTU::vVw::WEe:h:O:P:S:u:#::p::",
long_options, &option_index)) != EOF)
{
switch(c) {
+ case OPT_CHARSETS_DIR:
+ strmov(mysql_charsets_dir, optarg);
+ charsets_dir = mysql_charsets_dir;
+ break;
case OPT_DEFAULT_CHARSET:
default_charset= optarg;
break;
- case OPT_CHARSETS_DIR:
- charsets_dir= optarg;
+ case OPT_LOCAL_INFILE:
+ using_opt_local_infile=1;
+ opt_local_infile= test(!optarg || atoi(optarg)>0);
break;
case OPT_TEE:
if (!opt_outfile && strlen(optarg))
@@ -605,6 +661,9 @@ static int get_options(int argc, char **argv)
case OPT_NOPAGER:
opt_nopager=1;
break;
+ case 'b':
+ opt_nobeep = 1;
+ break;
case 'D':
my_free(current_db,MYF(MY_ALLOW_ZERO_PTR));
current_db=my_strdup(optarg,MYF(MY_WME));
@@ -659,31 +718,27 @@ static int get_options(int argc, char **argv)
else
tty_password=1;
break;
- case 't':
- output_tables=1;
- break;
- case 'r':
- opt_raw_data=1;
- break;
- case '#':
- DBUG_PUSH(optarg ? optarg : default_dbug_option);
- info_flag=1;
- break;
+ case 't': output_tables=1; break;
+ case 'r': opt_raw_data=1; break;
case 'q': quick=1; break;
case 's': opt_silent++; break;
case 'T': info_flag=1; break;
case 'n': unbuffered=1; break;
case 'v': verbose++; break;
case 'E': vertical=1; break;
- case 'w':
- wait_flag=1;
- if(optarg) wait_time = atoi(optarg) ;
- break;
case 'A': no_rehash=1; break;
case 'G': no_named_cmds=0; break;
case 'g': no_named_cmds=1; break;
case 'H': opt_html=1; break;
+ case 'X': opt_xml=1; break;
case 'i': connect_flag|= CLIENT_IGNORE_SPACE; break;
+ case 'C': opt_compress=1; break;
+ case 'L': skip_line_numbers=1; break;
+ case 'N': skip_column_names=1; break;
+ case 'w':
+ wait_flag=1;
+ if(optarg) wait_time = atoi(optarg) ;
+ break;
case 'B':
if (!status.batch)
{
@@ -692,19 +747,6 @@ static int get_options(int argc, char **argv)
opt_silent++; // more silent
}
break;
- case 'C':
- opt_compress=1;
- break;
- case OPT_LOCAL_INFILE:
- using_opt_local_infile=1;
- opt_local_infile= test(!optarg || atoi(optarg)>0);
- break;
- case 'L':
- skip_line_numbers=1;
- break;
- case 'N':
- skip_column_names=1;
- break;
case 'P':
opt_mysql_port= (unsigned int) atoi(optarg);
break;
@@ -722,6 +764,10 @@ static int get_options(int argc, char **argv)
case '?':
usage(0);
exit(0);
+ case '#':
+ DBUG_PUSH(optarg ? optarg : default_dbug_option);
+ info_flag=1;
+ break;
#include "sslopt-case.h"
default:
tee_fprintf(stderr,"illegal option: -%c\n",opterr);
@@ -1134,7 +1180,8 @@ static char *new_command_generator(char *text,int state)
static void build_completion_hash(bool skip_rehash,bool write_info)
{
COMMANDS *cmd=commands;
- static MYSQL_RES *databases=0,*tables=0,*fields;
+ MYSQL_RES *databases=0,*tables=0;
+ MYSQL_RES *fields;
static char ***field_names= 0;
MYSQL_ROW database_row,table_row;
MYSQL_FIELD *sql_field;
@@ -1145,16 +1192,11 @@ static void build_completion_hash(bool skip_rehash,bool write_info)
if (status.batch || quick || !current_db)
DBUG_VOID_RETURN; // We don't need completion in batches
- completion_hash_clean(&ht);
if (tables)
{
mysql_free_result(tables);
tables=0;
}
- if (databases) {
- mysql_free_result(databases);
- databases=0;
- }
/* hash SQL commands */
while (cmd->name) {
@@ -1164,16 +1206,28 @@ static void build_completion_hash(bool skip_rehash,bool write_info)
if (skip_rehash)
DBUG_VOID_RETURN;
+ /* Free old used memory */
+ if (field_names)
+ field_names=0;
+ completion_hash_clean(&ht);
+ free_root(&hash_mem_root,MYF(0));
+
/* hash MySQL functions (to be implemented) */
/* hash all database names */
- if (mysql_query(&mysql,"show databases")==0) {
+ if (mysql_query(&mysql,"show databases") == 0)
+ {
if (!(databases = mysql_store_result(&mysql)))
put_info(mysql_error(&mysql),INFO_INFO);
else
{
while ((database_row=mysql_fetch_row(databases)))
- add_word(&ht,(char*) database_row[0]);
+ {
+ char *str=strdup_root(&hash_mem_root, (char*) database_row[0]);
+ if (str)
+ add_word(&ht,(char*) str);
+ }
+ mysql_free_result(databases);
}
}
/* hash all table names */
@@ -1191,22 +1245,13 @@ You can turn off this feature to get a quicker startup with -A\n\n");
}
while ((table_row=mysql_fetch_row(tables)))
{
- if (!completion_hash_exists(&ht,(char*) table_row[0],
- (uint) strlen((const char*) table_row[0])))
- add_word(&ht,table_row[0]);
- }
- }
- }
- if (field_names) {
- for (i=0; field_names[i]; i++) {
- for (j=0; field_names[i][j]; j++) {
- my_free(field_names[i][j],MYF(0));
+ char *str=strdup_root(&hash_mem_root, (char*) table_row[0]);
+ if (str &&
+ !completion_hash_exists(&ht,(char*) str, (uint) strlen(str)))
+ add_word(&ht,str);
}
- my_free((gptr) field_names[i],MYF(0));
}
- my_free((gptr) field_names,MYF(0));
}
- field_names=0;
/* hash all field names, both with the table prefix and without it */
if (!tables) /* no tables */
@@ -1214,36 +1259,37 @@ You can turn off this feature to get a quicker startup with -A\n\n");
DBUG_VOID_RETURN;
}
mysql_data_seek(tables,0);
- field_names = (char ***) my_malloc(sizeof(char **) *
- (uint) (mysql_num_rows(tables)+1),
- MYF(MY_WME));
- if (!field_names)
+ if (!(field_names= (char ***) alloc_root(&hash_mem_root,sizeof(char **) *
+ (uint) (mysql_num_rows(tables)+1))))
+ {
+ mysql_free_result(tables);
DBUG_VOID_RETURN;
+ }
i=0;
while ((table_row=mysql_fetch_row(tables)))
{
if ((fields=mysql_list_fields(&mysql,(const char*) table_row[0],NullS)))
{
num_fields=mysql_num_fields(fields);
- field_names[i] = (char **) my_malloc(sizeof(char *)*(num_fields*2+1),
- MYF(0));
- if (!field_names[i])
- {
- continue;
- }
+ if (!(field_names[i] = (char **) alloc_root(&hash_mem_root,
+ sizeof(char *) *
+ (num_fields*2+1))))
+ break;
field_names[i][num_fields*2]='\0';
j=0;
while ((sql_field=mysql_fetch_field(fields)))
{
sprintf(buf,"%s.%s",table_row[0],sql_field->name);
- field_names[i][j] = my_strdup(buf,MYF(0));
+ field_names[i][j] = strdup_root(&hash_mem_root,buf);
add_word(&ht,field_names[i][j]);
- field_names[i][num_fields+j] = my_strdup(sql_field->name,MYF(0));
+ field_names[i][num_fields+j] = strdup_root(&hash_mem_root,
+ sql_field->name);
if (!completion_hash_exists(&ht,field_names[i][num_fields+j],
(uint) strlen(field_names[i][num_fields+j])))
add_word(&ht,field_names[i][num_fields+j]);
j++;
}
+ mysql_free_result(fields);
}
else
{
@@ -1253,6 +1299,7 @@ You can turn off this feature to get a quicker startup with -A\n\n");
}
i++;
}
+ mysql_free_result(tables);
field_names[i]=0; // End pointer
DBUG_VOID_RETURN;
}
@@ -1443,6 +1490,8 @@ com_go(String *buffer,char *line __attribute__((unused)))
init_pager();
if (opt_html)
print_table_data_html(result);
+ else if (opt_xml)
+ print_table_data_xml(result);
else if (vertical)
print_table_data_vertically(result);
else if (opt_silent && verbose <= 2 && !output_tables)
@@ -1645,6 +1694,38 @@ print_table_data_html(MYSQL_RES *result)
}
+static void
+print_table_data_xml(MYSQL_RES *result)
+{
+ MYSQL_ROW cur;
+ MYSQL_FIELD *fields;
+
+ mysql_field_seek(result,0);
+
+ tee_fputs("<?xml version=\"1.0\"?>\n\n<resultset statement=\"", PAGER);
+ xmlencode_print(glob_buffer.ptr(), strlen(glob_buffer.ptr()) - 1);
+ tee_fputs("\">", PAGER);
+
+ fields = mysql_fetch_fields(result);
+ while ((cur = mysql_fetch_row(result)))
+ {
+ (void) tee_fputs("\n <row>\n", PAGER);
+ for (uint i=0; i < mysql_num_fields(result); i++)
+ {
+ ulong *lengths=mysql_fetch_lengths(result);
+ tee_fprintf(PAGER, "\t<%s>", (fields[i].name ?
+ (fields[i].name[0] ? fields[i].name :
+ " &nbsp; ") : "NULL"));
+ xmlencode_print(cur[i], lengths[i]);
+ tee_fprintf(PAGER, "</%s>\n", (fields[i].name ?
+ (fields[i].name[0] ? fields[i].name :
+ " &nbsp; ") : "NULL"));
+ }
+ (void) tee_fputs(" </row>\n", PAGER);
+ }
+ (void) tee_fputs("</resultset>\n", PAGER);
+}
+
static void
print_table_data_vertically(MYSQL_RES *result)
@@ -1677,6 +1758,36 @@ print_table_data_vertically(MYSQL_RES *result)
}
+static const char
+*array_value(const char **array, char key)
+{
+ int x;
+ for (x= 0; array[x]; x+= 2)
+ if (*array[x] == key)
+ return array[x + 1];
+ return 0;
+}
+
+
+static void
+xmlencode_print(const char *src, uint length)
+{
+ if (!src)
+ tee_fputs("NULL", PAGER);
+ else
+ {
+ for (const char *p = src; *p && length; *p++, length--)
+ {
+ const char *t;
+ if ((t = array_value(xmlmeta, *p)))
+ tee_fputs(t, PAGER);
+ else
+ tee_putc(*p, PAGER);
+ }
+ }
+}
+
+
static void
safe_put_field(const char *pos,ulong length)
{
@@ -1706,7 +1817,7 @@ safe_put_field(const char *pos,ulong length)
tee_fputs("\\n", PAGER); // This too
else if (*pos == '\\')
tee_fputs("\\\\", PAGER);
- else
+ else
tee_putc(*pos, PAGER);
}
}
@@ -1766,17 +1877,10 @@ com_tee(String *buffer, char *line __attribute__((unused)))
{
while (isspace(*param))
param++;
- end= strend(param);
+ end=strmake(file_name, param, sizeof(file_name)-1);
while (end > file_name && (isspace(end[-1]) || iscntrl(end[-1])))
end--;
- end[0]= 0;
- if ((*(end - 1) == '"' && *param == '"') ||
- (*(end - 1) == '\'' && *param == '\''))
- {
- *--end= 0;
- param++;
- }
- strmake(file_name, param, sizeof(file_name) - 1);
+ end[0]=0;
strmov(outfile, file_name);
}
if (!strlen(outfile))
@@ -1784,10 +1888,11 @@ com_tee(String *buffer, char *line __attribute__((unused)))
printf("No outfile specified!\n");
return 0;
}
- if (opt_outfile)
- end_tee();
- init_tee();
- opt_outfile= 1;
+ if (!opt_outfile)
+ {
+ init_tee();
+ opt_outfile=1;
+ }
tee_fprintf(stdout, "Logging to file '%s'\n", outfile);
return 0;
}
@@ -1925,6 +2030,29 @@ com_rehash(String *buffer __attribute__((unused)),
return 0;
}
+
+#ifndef __WIN__
+static int
+com_shell(String *buffer, char *line __attribute__((unused)))
+{
+ char *shell_cmd;
+ if (!(shell_cmd = strchr(line, ' ')))
+ {
+ put_info("Usage: \\! shell-command", INFO_ERROR);
+ return -1;
+ }
+ /* The output of the shell command does not
+ get directed to the pager or the outfile */
+ if(system(shell_cmd) == -1)
+ {
+ put_info(strerror(errno), INFO_ERROR, errno);
+ return -1;
+ }
+ return 0;
+}
+#endif
+
+
static int
com_print(String *buffer,char *line __attribute__((unused)))
{
@@ -2092,11 +2220,8 @@ static int
sql_real_connect(char *host,char *database,char *user,char *password,
uint silent)
{
- if (connected)
- { /* if old is open, close it first */
- mysql_close(&mysql);
- connected= 0;
- }
+ mysql_close(&mysql);
+ connected= 0;
mysql_init(&mysql);
if (opt_connect_timeout)
{
@@ -2111,7 +2236,7 @@ sql_real_connect(char *host,char *database,char *user,char *password,
#ifdef HAVE_OPENSSL
if (opt_use_ssl)
mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
- opt_ssl_capath);
+ opt_ssl_capath, opt_ssl_cipher);
#endif
if (safe_updates)
{
@@ -2270,7 +2395,7 @@ static int
put_info(const char *str,INFO_TYPE info_type,uint error)
{
static int inited=0;
-
+
if (status.batch)
{
if (info_type == INFO_ERROR)
@@ -2307,7 +2432,8 @@ put_info(const char *str,INFO_TYPE info_type,uint error)
}
if (info_type == INFO_ERROR)
{
- putchar('\007'); /* This should make a bell */
+ if(!opt_nobeep)
+ putchar('\007'); /* This should make a bell */
vidattr(A_STANDOUT);
if (error)
(void) tee_fprintf(stderr, "ERROR %d: ", error);
@@ -2450,6 +2576,7 @@ static void mysql_end_timer(ulong start_time,char *buff)
strmov(strend(buff),")");
}
+#ifndef EMBEDDED_LIBRARY
/* Keep sql_string library happy */
gptr sql_alloc(unsigned int Size)
@@ -2461,3 +2588,4 @@ void sql_element_free(void *ptr)
{
my_free((gptr) ptr,MYF(0));
}
+#endif /* EMBEDDED_LIBRARY */
diff --git a/client/mysqladmin.c b/client/mysqladmin.c
index 0dd8cfb1bd0..f6ebffea087 100644
--- a/client/mysqladmin.c
+++ b/client/mysqladmin.c
@@ -1,15 +1,15 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
+/* 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 */
@@ -265,7 +265,7 @@ int main(int argc,char *argv[])
#ifdef HAVE_OPENSSL
if (opt_use_ssl)
mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
- opt_ssl_capath);
+ opt_ssl_capath, opt_ssl_cipher);
#endif /* HAVE_OPENSSL */
if (sql_connect(&mysql,host,user,opt_password,option_wait))
error = 1;
@@ -337,7 +337,7 @@ static my_bool sql_connect(MYSQL *mysql,const char *host, const char *user,
}
return 0;
}
-
+
if (!wait)
{
if (!option_silent)
@@ -649,7 +649,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
}
else
print_top(res);
-
+
ex_status_printed = 1; /* From now on the output will be relative */
mysql_free_result(res);
break;
@@ -745,7 +745,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
else
puts("Slave stopped");
break;
-
+
case ADMIN_PING:
mysql->reconnect=0; /* We want to know of reconnects */
if (!mysql_ping(mysql))
@@ -928,7 +928,7 @@ static void print_header(MYSQL_RES *result)
putchar('|');
while ((field = mysql_fetch_field(result)))
{
- printf(" %-*s|",field->max_length+1,field->name);
+ printf(" %-*s|",(int) field->max_length+1,field->name);
}
putchar('\n');
print_top(result);
@@ -983,11 +983,11 @@ static void print_relative_row(MYSQL_RES *result, MYSQL_ROW cur, uint row)
mysql_field_seek(result, 0);
field = mysql_fetch_field(result);
- printf("| %-*s|", field->max_length + 1, cur[0]);
+ printf("| %-*s|", (int) field->max_length + 1, cur[0]);
field = mysql_fetch_field(result);
tmp = cur[1] ? strtoull(cur[1], NULL, 0) : (ulonglong) 0;
- printf(" %-*s|\n", field->max_length + 1,
+ printf(" %-*s|\n", (int) field->max_length + 1,
llstr((tmp - last_values[row]), buff));
last_values[row] = tmp;
}
@@ -1000,7 +1000,7 @@ static void print_relative_row_vert(MYSQL_RES *result __attribute__((unused)),
uint length;
ulonglong tmp;
char buff[22];
-
+
if (!row)
putchar('|');
@@ -1079,7 +1079,7 @@ static void truncate_names()
*ptr++='+';
*ptr=0;
puts(top_line);
-
+
for (i = 0 ; i < ex_var_count; i++)
{
uint sfx=1,j;
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc
index ac2f3e4efda..3d30283d13a 100644
--- a/client/mysqlbinlog.cc
+++ b/client/mysqlbinlog.cc
@@ -1,36 +1,28 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
+/* 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 */
-
#define MYSQL_CLIENT
#undef MYSQL_SERVER
#include "client_priv.h"
#include <time.h>
#include "log_event.h"
-#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES)
+#define PROBE_HEADER_LEN (4+EVENT_LEN_OFFSET+4)
-#ifndef OS2
-extern "C"
-{
- int simple_command(MYSQL *mysql,enum enum_server_command command,
- const char *arg, uint length, my_bool skipp_check);
- uint net_safe_read(MYSQL* mysql);
-}
-#endif
+#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES)
char server_version[SERVER_VERSION_LENGTH];
uint32 server_id = 0;
@@ -110,7 +102,7 @@ static void die(const char* fmt, ...)
static void print_version()
{
- printf("%s Ver 1.6 for %s at %s\n",my_progname,SYSTEM_TYPE, MACHINE_TYPE);
+ printf("%s Ver 1.7 for %s at %s\n",my_progname,SYSTEM_TYPE, MACHINE_TYPE);
}
@@ -205,12 +197,12 @@ static int parse_args(int *argc, char*** argv)
use_remote = 1;
host = my_strdup(optarg, MYF(0));
break;
-
+
case 'P':
use_remote = 1;
port = atoi(optarg);
break;
-
+
case 'p':
use_remote = 1;
pass = my_strdup(optarg, MYF(0));
@@ -276,13 +268,13 @@ static void dump_remote_table(NET* net, const char* db, const char* table)
uint db_len = (uint) strlen(db);
if(table_len + db_len > sizeof(buf) - 2)
die("Buffer overrun");
-
+
*p++ = db_len;
memcpy(p, db, db_len);
p += db_len;
*p++ = table_len;
memcpy(p, table, table_len);
-
+
if(simple_command(mysql, COM_TABLE_DUMP, buf, p - buf + table_len, 1))
die("Error sending the table dump command");
@@ -297,6 +289,52 @@ static void dump_remote_table(NET* net, const char* db, const char* table)
}
}
+static int check_master_version(MYSQL* mysql)
+{
+ 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)))
+ {
+ mysql_close(mysql);
+ die("Error checking master version: %s",
+ mysql_error(mysql));
+ }
+ if (!(row = mysql_fetch_row(res)))
+ {
+ mysql_free_result(res);
+ mysql_close(mysql);
+ die("Master returned no rows for SELECT VERSION()");
+ return 1;
+ }
+ if (!(version = row[0]))
+ {
+ mysql_free_result(res);
+ mysql_close(mysql);
+ die("Master reported NULL for the version");
+ }
+
+ switch (*version)
+ {
+ case '3':
+ old_format = 1;
+ break;
+ case '4':
+ old_format = 0;
+ break;
+ default:
+ sql_print_error("Master reported unrecognized MySQL version '%s'",
+ version);
+ mysql_free_result(res);
+ mysql_close(mysql);
+ return 1;
+ }
+ mysql_free_result(res);
+ return old_format;
+}
static void dump_remote_log_entries(const char* logname)
{
@@ -304,6 +342,9 @@ static void dump_remote_log_entries(const char* logname)
char last_db[FN_REFLEN+1] = "";
uint len;
NET* net = &mysql->net;
+ int old_format;
+ old_format = check_master_version(mysql);
+
if(!position) position = 4; // protect the innocent from spam
if (position < 4)
{
@@ -316,11 +357,12 @@ static void dump_remote_log_entries(const char* logname)
len = (uint) strlen(logname);
int4store(buf + 6, 0);
memcpy(buf + 10, logname,len);
- if(simple_command(mysql, COM_BINLOG_DUMP, buf, len + 10, 1))
+ if (simple_command(mysql, COM_BINLOG_DUMP, buf, len + 10, 1))
die("Error sending the log dump command");
-
+
for(;;)
{
+ const char *error;
len = net_safe_read(mysql);
if (len == packet_error)
die("Error reading packet from server: %s", mysql_error(mysql));
@@ -330,8 +372,8 @@ static void dump_remote_log_entries(const char* logname)
len, net->read_pos[5]));
Log_event * ev = Log_event::read_log_event(
(const char*) net->read_pos + 1 ,
- len - 1);
- if(ev)
+ len - 1, &error, old_format);
+ if (ev)
{
ev->print(result_file, short_form, last_db);
if(ev->get_type_code() == LOAD_EVENT)
@@ -343,12 +385,34 @@ static void dump_remote_log_entries(const char* logname)
}
}
+static int check_header(IO_CACHE* file)
+{
+ byte buf[PROBE_HEADER_LEN];
+ int old_format;
+
+ my_off_t pos = my_b_tell(file);
+ my_b_seek(file, (my_off_t)0);
+ if (my_b_read(file, buf, sizeof(buf)))
+ die("Failed reading header");
+ if (buf[EVENT_TYPE_OFFSET+4] == START_EVENT)
+ {
+ uint event_len;
+ event_len = uint4korr(buf + EVENT_LEN_OFFSET + 4);
+ old_format = (event_len < LOG_EVENT_HEADER_LEN + START_HEADER_LEN);
+ }
+ else
+ old_format = 0;
+ my_b_seek(file, pos);
+ return old_format;
+}
+
static void dump_local_log_entries(const char* logname)
{
File fd = -1;
IO_CACHE cache,*file= &cache;
ulonglong rec_count = 0;
char last_db[FN_REFLEN+1] = "";
+ bool old_format = 0;
if (logname && logname[0] != '-')
{
@@ -357,12 +421,14 @@ static void dump_local_log_entries(const char* logname)
if (init_io_cache(file, fd, 0, READ_CACHE, (my_off_t) position, 0,
MYF(MY_WME | MY_NABP)))
exit(1);
+ old_format = check_header(file);
}
else
{
if (init_io_cache(file, fileno(result_file), 0, READ_CACHE, (my_off_t) 0,
0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE)))
exit(1);
+ old_format = check_header(file);
if (position)
{
/* skip 'position' characters from stdout */
@@ -387,13 +453,13 @@ static void dump_local_log_entries(const char* logname)
if(memcmp(magic, BINLOG_MAGIC, 4))
die("Bad magic number; The file is probably not a MySQL binary log");
}
-
+
for (;;)
{
char llbuff[21];
my_off_t old_off = my_b_tell(file);
- Log_event* ev = Log_event::read_log_event(file);
+ Log_event* ev = Log_event::read_log_event(file, old_format);
if (!ev)
{
if (file->error)
diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c
index 0f7bfb37ecf..eccc08f59ec 100644
--- a/client/mysqlcheck.c
+++ b/client/mysqlcheck.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* 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
@@ -198,7 +198,7 @@ printf("\
print_defaults("my", load_default_groups);
} /* usage */
-
+
static int get_options(int *argc, char ***argv)
{
int c, option_index;
@@ -412,7 +412,7 @@ static int process_selected_tables(char *db, char **table_names, int tables)
for (i = 0; i < tables; i++)
tot_length += strlen(*(table_names + i)) + 1;
-
+
if (!(table_names_comma_sep = (char *)
my_malloc((sizeof(char) * tot_length) + 1, MYF(MY_WME))))
return 1;
@@ -445,7 +445,7 @@ static int process_all_tables_in_db(char *database)
if (!(mysql_query(sock, "SHOW TABLES") ||
(res = mysql_store_result(sock))))
return 1;
-
+
if (opt_all_in_1)
{
char *tables, *end;
@@ -454,7 +454,7 @@ static int process_all_tables_in_db(char *database)
while ((row = mysql_fetch_row(res)))
tot_length += strlen(row[0]) + 1;
mysql_data_seek(res, 0);
-
+
if (!(tables=(char *) my_malloc(sizeof(char)*tot_length+1, MYF(MY_WME))))
{
mysql_free_result(res);
@@ -591,7 +591,7 @@ static int dbConnect(char *host, char *user, char *passwd)
#ifdef HAVE_OPENSSL
if (opt_use_ssl)
mysql_ssl_set(&mysql_connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
- opt_ssl_capath);
+ opt_ssl_capath, opt_ssl_cipher);
#endif
if (!(sock = mysql_real_connect(&mysql_connection, host, user, passwd,
NULL, opt_mysql_port, opt_mysql_unix_port, 0)))
diff --git a/client/mysqldump.c b/client/mysqldump.c
index ba434237580..0b9ff7a6eee 100644
--- a/client/mysqldump.c
+++ b/client/mysqldump.c
@@ -35,7 +35,7 @@
** and adapted to mysqldump 05/11/01 by Jani Tolonen
*/
-#define DUMP_VERSION "8.22"
+#define DUMP_VERSION "8.23"
#include <my_global.h>
#include <my_sys.h>
@@ -147,9 +147,9 @@ static const char *load_default_groups[]= { "mysqldump","client",0 };
CHANGEABLE_VAR md_changeable_vars[] = {
{ "max_allowed_packet", (long*) &max_allowed_packet,24*1024*1024,4096,
- 16*1024L*1024L,MALLOC_OVERHEAD,1024},
+ 512*1024L*1024L,MALLOC_OVERHEAD,1024},
{ "net_buffer_length", (long*) &net_buffer_length,1024*1024L-1025,4096,
- 16*1024L*1024L,MALLOC_OVERHEAD+1024,1024},
+ 16*1024L*1024L,MALLOC_OVERHEAD-1024,1024},
{ 0, 0, 0, 0, 0, 0, 0}
};
@@ -663,8 +663,7 @@ static uint getTableStructure(char *table, char* db)
if (path)
{
char filename[FN_REFLEN], tmp_path[FN_REFLEN];
- strmov(tmp_path,path);
- convert_dirname(tmp_path);
+ 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 */
@@ -741,8 +740,7 @@ static uint getTableStructure(char *table, char* db)
if (path)
{
char filename[FN_REFLEN], tmp_path[FN_REFLEN];
- strmov(tmp_path,path);
- convert_dirname(tmp_path);
+ 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 */
@@ -899,8 +897,6 @@ static uint getTableStructure(char *table, char* db)
fputs(";\n", sql_file);
}
}
- if (opt_disable_keys)
- fprintf(sql_file,"\n/*!40000 ALTER TABLE %s DISABLE KEYS */;\n",table_name);
if (cFlag)
{
strpos=strmov(strpos,") VALUES ");
@@ -980,8 +976,7 @@ static void dumpTable(uint numFields, char *table)
if (path)
{
char filename[FN_REFLEN], tmp_path[FN_REFLEN];
- strmov(tmp_path,path);
- convert_dirname(tmp_path);
+ convert_dirname(tmp_path,path,NullS);
my_load_path(tmp_path, tmp_path, NULL);
fn_format(filename, table, tmp_path, ".txt", 4);
my_delete(filename, MYF(0)); /* 'INTO OUTFILE' doesn't work, if
@@ -1026,7 +1021,7 @@ static void dumpTable(uint numFields, char *table)
strxmov(strend(query), " WHERE ",where,NullS);
}
if (!opt_xml)
- fputs("\n\n", md_result_file);
+ fputs("\n", md_result_file);
if (mysql_query(sock, query))
{
DBerror(sock, "when retrieving data from server");
@@ -1051,6 +1046,9 @@ static void dumpTable(uint numFields, char *table)
return;
}
+ if (opt_disable_keys)
+ fprintf(md_result_file,"/*!40000 ALTER TABLE %s DISABLE KEYS */;\n",
+ quote_name(table, table_buff));
if (opt_lock)
fprintf(md_result_file,"LOCK TABLES %s WRITE;\n",
quote_name(table,table_buff));
@@ -1198,7 +1196,7 @@ static void dumpTable(uint numFields, char *table)
fputs(");\n", md_result_file);
}
- /*XML - close table tag and supress regular output*/
+ /* XML - close table tag and supress regular output */
if (opt_xml)
fprintf(md_result_file, "\t</%s>\n", table);
else if (extended_insert && row_break)
@@ -1216,11 +1214,11 @@ static void dumpTable(uint numFields, char *table)
safe_exit(EX_CONSCHECK);
return;
}
- if (opt_disable_keys)
- fprintf(md_result_file,"\n/*!40000 ALTER TABLE %s ENABLE KEYS */;\n",
- quote_name(table,table_buff));
if (opt_lock)
fputs("UNLOCK TABLES;\n", md_result_file);
+ if (opt_disable_keys)
+ fprintf(md_result_file,"/*!40000 ALTER TABLE %s ENABLE KEYS */;\n",
+ quote_name(table,table_buff));
if (opt_autocommit)
fprintf(md_result_file, "commit;\n");
mysql_free_result(res);
@@ -1301,7 +1299,7 @@ static int dump_databases(char **db_names)
int result=0;
for ( ; *db_names ; db_names++)
{
- /*XML edit - add database element*/
+ /* XML edit - add database element */
if (opt_xml)
fprintf(md_result_file, "<%s>\n", *db_names);
if (dump_all_tables_in_db(*db_names))
diff --git a/client/mysqlmanager-pwgen.c b/client/mysqlmanager-pwgen.c
new file mode 100644
index 00000000000..97eb31eb9c8
--- /dev/null
+++ b/client/mysqlmanager-pwgen.c
@@ -0,0 +1,157 @@
+/* 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 */
+
+#define MANAGER_PWGEN_VERSION "1.0"
+
+#include <my_global.h>
+#include <m_ctype.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include <mysql_version.h>
+#include <errno.h>
+#include <getopt.h>
+#include <md5.h>
+
+const char* outfile=0,*user="root";
+
+struct option long_options[] =
+{
+ {"output-file",required_argument,0,'o'},
+ {"user",required_argument,0,'u'},
+ {"help",no_argument,0,'?'},
+ {"version",no_argument,0,'V'},
+ {0,0,0,0}
+};
+
+static void die(const char* fmt, ...)
+{
+ va_list args;
+ DBUG_ENTER("die");
+ va_start(args, fmt);
+ if (fmt)
+ {
+ fprintf(stderr, "%s: ", my_progname);
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+ fflush(stderr);
+ }
+ va_end(args);
+ exit(1);
+}
+
+static void print_version(void)
+{
+ printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,
+ MANAGER_PWGEN_VERSION,
+ MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
+}
+
+void usage()
+{
+ print_version();
+ printf("MySQL AB, by Sasha\n");
+ printf("This software comes with ABSOLUTELY NO WARRANTY\n\n");
+ printf("Generates a password file to be used by mysqltest.\n\n");
+ printf("Usage: %s [OPTIONS]\n", my_progname);
+ printf("-?,--help Display this message and exit\n\
+-V,--version Display version info\n\
+-u,--user= Put given user in the password file\n\
+-o,--output-file= Write the output to the file with the given name\n");
+}
+
+int parse_args(int argc, char** argv)
+{
+ int c,option_index=0;
+ while ((c=getopt_long(argc,argv,"?Vu:o:",long_options,&option_index))
+ != EOF)
+ {
+ switch (c)
+ {
+ case 'o':
+ outfile=optarg;
+ break;
+ case 'u':
+ user=optarg;
+ break;
+ case '?':
+ usage();
+ exit(0);
+ case 'V':
+ print_version();
+ exit(0);
+ default:
+ usage();
+ exit(1);
+ }
+ }
+ return 0;
+}
+
+void get_pass(char* pw, int len)
+{
+ FILE* fp;
+ char* pw_end=pw+len;
+/* /dev/random is more secure than rand() because the seed is easy to
+ predict, so we resort to rand() only if /dev/random is not available */
+ if ((fp=fopen("/dev/random","r")))
+ {
+ fread(pw,len,1,fp);
+ fclose(fp);
+ while (pw<pw_end)
+ {
+ char tmp= 'a'+((uint)*pw % 26);
+ *pw++= tmp;
+ }
+ }
+ else
+ {
+ srand(time(NULL));
+ while (pw<pw_end)
+ {
+ char tmp= 'a'+((uint)*pw % 26);
+ *pw++= tmp;
+ }
+ }
+ *pw_end=0;
+}
+
+int main(int argc, char** argv)
+{
+ FILE* fp;
+ my_MD5_CTX context;
+ uchar digest[16];
+ char pw[17];
+ uint i;
+
+ MY_INIT(argv[0]);
+ parse_args(argc,argv);
+ if (!outfile)
+ die("Missing --output-file");
+
+ if (!(fp=fopen(outfile,"w")))
+ die("Could not open '%s'(errno=%d)",outfile,errno);
+ get_pass(pw,sizeof(pw)-1);
+ my_MD5Init(&context);
+ my_MD5Update(&context,(uchar*) pw,sizeof(pw)-1);
+ my_MD5Final(digest,&context);
+ fprintf(fp,"%s:",user);
+ for (i=0;i<sizeof(digest);i++)
+ fprintf(fp,"%02x",digest[i]);
+ fprintf(fp,"\n");
+ fclose(fp);
+ printf("%s\n",pw);
+ return 0;
+}
diff --git a/client/mysqlmanagerc.c b/client/mysqlmanagerc.c
new file mode 100644
index 00000000000..a01f6c25f34
--- /dev/null
+++ b/client/mysqlmanagerc.c
@@ -0,0 +1,178 @@
+/* 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 */
+
+#define MANAGER_CLIENT_VERSION "1.1"
+
+#include <my_global.h>
+#include <mysql.h>
+#include <mysql_version.h>
+#include <mysqld_error.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#ifndef MYSQL_MANAGER_PORT
+#define MYSQL_MANAGER_PORT 9305
+#endif
+
+static void die(const char* fmt, ...);
+
+const char* user="root",*host="localhost";
+char* pass=0;
+int quiet=0;
+uint port=MYSQL_MANAGER_PORT;
+static const char *load_default_groups[]= { "mysqlmanagerc",0 };
+char** default_argv;
+MYSQL_MANAGER *manager;
+FILE* fp, *fp_out;
+
+struct option long_options[] =
+{
+ {"host",required_argument,0,'h'},
+ {"user",required_argument,0,'u'},
+ {"password",optional_argument,0,'p',},
+ {"port",required_argument,0,'P'},
+ {"help",no_argument,0,'?'},
+ {"version",no_argument,0,'V'},
+ {"quiet",no_argument,0,'q'},
+ {0,0,0,0}
+};
+
+static void die(const char* fmt, ...)
+{
+ va_list args;
+ DBUG_ENTER("die");
+ va_start(args, fmt);
+ if (fmt)
+ {
+ fprintf(stderr, "%s: ", my_progname);
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+ fflush(stderr);
+ }
+ va_end(args);
+ exit(1);
+}
+
+static void print_version(void)
+{
+ printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,
+ MANAGER_CLIENT_VERSION,
+ MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
+}
+
+void usage()
+{
+ print_version();
+ printf("MySQL AB, by Sasha\n");
+ printf("This software comes with ABSOLUTELY NO WARRANTY\n\n");
+ printf("Command-line client for MySQL manager daemon.\n\n");
+ printf("Usage: %s [OPTIONS] < command_file\n", my_progname);
+ printf("\n\
+ -?, --help Display this help and exit.\n");
+ printf("\
+ -h, --host=... Connect to host.\n\
+ -u, --user=... User for login.\n\
+ -p[password], --password[=...]\n\
+ Password to use when connecting to server.\n\
+ -P, --port=... Port number to use for connection.\n\
+ -q, --quiet, --silent Suppress all normal output.\n\
+ -V, --version Output version information and exit.\n\
+ --no-defaults Don't read default options from any options file.\n\n");
+}
+int parse_args(int argc, char **argv)
+{
+ int c, option_index = 0;
+ my_bool tty_password=0;
+
+ load_defaults("my",load_default_groups,&argc,&argv);
+ default_argv= argv;
+
+ while ((c = getopt_long(argc, argv, "h:p::u:P:?Vq",
+ long_options, &option_index)) != EOF)
+ {
+ switch (c)
+ {
+ case 'h':
+ host=optarg;
+ break;
+ case 'u':
+ user=optarg;
+ break;
+ case 'p':
+ if (optarg)
+ {
+ my_free(pass,MYF(MY_ALLOW_ZERO_PTR));
+ pass=my_strdup(optarg,MYF(MY_FAE));
+ while (*optarg) *optarg++= 'x'; /* Destroy argument */
+ }
+ else
+ tty_password=1;
+ break;
+ case 'P':
+ port=atoi(optarg);
+ break;
+ case 'q':
+ quiet=1;
+ break;
+ case 'V':
+ print_version();
+ exit(0);
+ case '?':
+ usage();
+ exit(0);
+ default:
+ usage();
+ exit(1);
+ }
+ }
+ return 0;
+}
+int main(int argc, char** argv)
+{
+ MY_INIT(argv[0]);
+ fp=stdin;
+ fp_out=stdout;
+ parse_args(argc,argv);
+ if (!(manager=mysql_manager_init(0)))
+ die("Failed in mysql_manager_init()");
+ if (!mysql_manager_connect(manager,host,user,pass,port))
+ die("Could not connect to MySQL manager: %s(%d)",manager->last_error,
+ manager->last_errno);
+ for (;!feof(fp);)
+ {
+ char buf[4096];
+ if (!fgets(buf,sizeof(buf),fp))
+ break;
+ if (!quiet)
+ fprintf(fp_out,"<<%s",buf);
+ if (mysql_manager_command(manager,buf,strlen(buf)))
+ die("Error in command: %s(%d)",manager->last_error,manager->last_errno);
+ while (!manager->eof)
+ {
+ if (mysql_manager_fetch_line(manager,buf,sizeof(buf)))
+ die("Error fetching result line: %s(%d)", manager->last_error,
+ manager->last_errno);
+ if (!quiet)
+ fprintf(fp_out,">>%s\n",buf);
+ }
+ }
+ mysql_manager_close(manager);
+ return 0;
+}
diff --git a/client/mysqlshow.c b/client/mysqlshow.c
index 199318abc2f..e5b7f239f97 100644
--- a/client/mysqlshow.c
+++ b/client/mysqlshow.c
@@ -1,15 +1,15 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
+/* 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 */
@@ -18,7 +18,7 @@
#define SHOW_VERSION "8.3"
-#include <global.h>
+#include <my_global.h>
#include <my_sys.h>
#include <m_string.h>
#include "mysql.h"
@@ -87,7 +87,7 @@ int main(int argc, char **argv)
#ifdef HAVE_OPENSSL
if (opt_use_ssl)
mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
- opt_ssl_capath);
+ opt_ssl_capath, opt_ssl_cipher);
#endif
if (!(mysql_real_connect(&mysql,host,user,opt_password,
argv[0],opt_mysql_port,opt_mysql_unix_port,
@@ -713,7 +713,7 @@ static void print_res_header(MYSQL_RES *result)
putchar('|');
while ((field = mysql_fetch_field(result)))
{
- printf(" %-*s|",field->max_length+1,field->name);
+ printf(" %-*s|",(int) field->max_length+1,field->name);
}
putchar('\n');
print_res_top(result);
diff --git a/client/mysqltest.c b/client/mysqltest.c
index 4288b5d7871..4ae74d129b9 100644
--- a/client/mysqltest.c
+++ b/client/mysqltest.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* 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
@@ -15,7 +15,8 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* mysqltest test tool
- * See man page for more information.
+ * See the manual for more information
+ * TODO: document better how mysqltest works
*
* Written by:
* Sasha Pachev <sasha@mysql.com>
@@ -26,9 +27,6 @@
/**********************************************************************
TODO:
-- Print also the queries that returns a result to the log file; This makes
- it much easier to find out what's wrong.
-
- Do comparison line by line, instead of doing a full comparison of
the text file. This will save space as we don't need to keep many
results in memory. It will also make it possible to do simple
@@ -43,22 +41,18 @@
**********************************************************************/
-#define MTEST_VERSION "1.10"
+#define MTEST_VERSION "1.14"
-#include <global.h>
+#include <my_global.h>
+#include <mysql_embed.h>
#include <my_sys.h>
#include <m_string.h>
#include <mysql.h>
#include <mysql_version.h>
+#include <mysqld_error.h>
#include <m_ctype.h>
-#ifdef OS2
-#include <config-os2.h>
-#else
- #include <my_config.h>
-#endif
#include <my_dir.h>
#include <hash.h>
-#include <mysqld_error.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
@@ -79,17 +73,38 @@
#define MAX_EXPECTED_ERRORS 10
#define QUERY_SEND 1
#define QUERY_REAP 2
-#define CON_RETRY_SLEEP 1 /* how long to sleep before trying to connect again*/
-#define MAX_CON_TRIES 2 /* sometimes in a test the client starts before
- * the server - to solve the problem, we try again
- * after some sleep if connection fails the first
- * time */
+#ifndef MYSQL_MANAGER_PORT
+#define MYSQL_MANAGER_PORT 23546
+#endif
+
+/*
+ Sometimes in a test the client starts before
+ the server - to solve the problem, we try again
+ after some sleep if connection fails the first
+ time
+*/
+#define CON_RETRY_SLEEP 2
+#define MAX_CON_TRIES 5
+
+#ifndef OS2
+#define SLAVE_POLL_INTERVAL 300000 /* 0.3 of a sec */
+#else
+#defile SLAVE_POLL_INTERVAL 0.3
+#endif
+
+enum {OPT_MANAGER_USER=256,OPT_MANAGER_HOST,OPT_MANAGER_PASSWD,
+ OPT_MANAGER_PORT,OPT_MANAGER_WAIT_TIMEOUT};
static int record = 0, verbose = 0, silent = 0, opt_sleep=0;
static char *db = 0, *pass=0;
-const char* user = 0, *host = 0, *unix_sock = 0;
-static int port = 0, opt_big_test=0;
+const char* user = 0, *host = 0, *unix_sock = 0, *opt_basedir="./";
+static int port = 0, opt_big_test=0, opt_compress=0;
static uint start_lineno, *lineno;
+const char* manager_user="root",*manager_host=0;
+char *manager_pass=0;
+int manager_port=MYSQL_MANAGER_PORT;
+int manager_wait_timeout=3;
+MYSQL_MANAGER* manager=0;
static char **default_argv;
static const char *load_default_groups[]= { "mysqltest","client",0 };
@@ -106,7 +121,7 @@ static int block_stack[BLOCK_STACK_DEPTH];
static int block_ok_stack[BLOCK_STACK_DEPTH];
-static uint global_expected_errno[MAX_EXPECTED_ERRORS];
+static uint global_expected_errno[MAX_EXPECTED_ERRORS], global_expected_errors;
DYNAMIC_ARRAY q_lines;
@@ -127,27 +142,31 @@ typedef struct
int read_lines,current_line;
} PARSER;
+MYSQL_RES *last_result=0;
+
PARSER parser;
MASTER_POS master_pos;
-int* block_ok; /* set to 0 if the current block should not be executed */
+int *block_ok; /* set to 0 if the current block should not be executed */
int false_block_depth = 0;
-const char* result_file = 0; /* if set, all results are concated and
- compared against this file*/
+/* if set, all results are concated and compared against this file */
+const char *result_file = 0;
typedef struct
{
- char* name;
+ char *name;
int name_len;
- char* str_val;
+ char *str_val;
int str_val_len;
int int_val;
int alloced_len;
int int_dirty; /* do not update string if int is updated until first read */
+ int alloced;
} VAR;
VAR var_reg[10];
/*Perl/shell-like variable registers */
HASH var_hash;
+int disable_query_log=0, disable_result_log=0;
struct connection cons[MAX_CONS];
struct connection* cur_con, *next_con, *cons_end;
@@ -169,6 +188,11 @@ Q_DIRTY_CLOSE, Q_REPLACE,
Q_PING, Q_EVAL,
Q_RPL_PROBE, Q_ENABLE_RPL_PARSE,
Q_DISABLE_RPL_PARSE, Q_EVAL_RESULT,
+Q_ENABLE_QUERY_LOG, Q_DISABLE_QUERY_LOG,
+Q_ENABLE_RESULT_LOG, Q_DISABLE_RESULT_LOG,
+Q_SERVER_START, Q_SERVER_STOP,Q_REQUIRE_MANAGER,
+Q_WAIT_FOR_SLAVE_TO_STOP,
+Q_REQUIRE_VERSION,
Q_UNKNOWN, /* Unknown command. */
Q_COMMENT, /* Comments, ignored. */
Q_COMMENT_WITH_COMMAND
@@ -181,6 +205,7 @@ struct st_query
int first_word_len;
my_bool abort_on_error, require_file;
uint expected_errno[MAX_EXPECTED_ERRORS];
+ uint expected_errors;
char record_file[FN_REFLEN];
enum enum_commands type;
};
@@ -200,6 +225,11 @@ const char *command_names[] = {
"ping", "eval",
"rpl_probe", "enable_rpl_parse",
"disable_rpl_parse", "eval_result",
+ "enable_query_log", "disable_query_log",
+ "enable_result_log", "disable_result_log",
+ "server_start", "server_stop",
+ "require_manager", "wait_for_slave_to_stop",
+ "require_version",
0
};
@@ -207,21 +237,23 @@ TYPELIB command_typelib= {array_elements(command_names),"",
command_names};
DYNAMIC_STRING ds_res;
-static void die(const char* fmt, ...);
+static void die(const char *fmt, ...);
static void init_var_hash();
static byte* get_var_key(const byte* rec, uint* len,
my_bool __attribute__((unused)) t);
-static VAR* var_init(VAR* v, const char* name, int name_len, const char* val,
+static VAR* var_init(VAR* v, const char *name, int name_len, const char *val,
int val_len);
static void var_free(void* v);
-int dyn_string_cmp(DYNAMIC_STRING* ds, const char* fname);
-void reject_dump(const char* record_file, char* buf, int size);
+int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname);
+void reject_dump(const char *record_file, char *buf, int size);
int close_connection(struct st_query* q);
-VAR* var_get(const char* var_name, const char** var_name_end, int raw);
-int eval_expr(VAR* v, const char* p, const char** p_end);
+VAR* var_get(const char *var_name, const char** var_name_end, my_bool raw,
+ my_bool ignore_not_existing);
+int eval_expr(VAR* v, const char *p, const char** p_end);
+static int read_server_arguments(const char *name);
/* Definitions for replace */
@@ -237,12 +269,14 @@ struct st_replace *init_replace(my_string *from, my_string *to, uint count,
my_string word_end_chars);
uint replace_strings(struct st_replace *rep, my_string *start,
uint *max_length, my_string from);
+void free_replace();
static int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name);
void free_pointer_array(POINTER_ARRAY *pa);
static int initialize_replace_buffer(void);
static void free_replace_buffer(void);
-static void do_eval(DYNAMIC_STRING* query_eval, const char* query);
-void str_to_file(const char* fname, char* str, int size);
+static void do_eval(DYNAMIC_STRING* query_eval, const char *query);
+void str_to_file(const char *fname, char *str, int size);
+int do_server_op(struct st_query* q,const char *op);
struct st_replace *glob_replace;
static char *out_buff;
@@ -250,13 +284,25 @@ static uint out_length;
static int eval_result = 0;
/* Disable functions that only exist in MySQL 4.0 */
-#if MYSQL_VERSION_ID < 40000
-static void mysql_enable_rpl_parse(MYSQL* mysql __attribute__((unused))) {}
-static void mysql_disable_rpl_parse(MYSQL* mysql __attribute__((unused))) {}
-static int mysql_rpl_parse_enabled(MYSQL* mysql __attribute__((unused))) { return 1; }
-static int mysql_rpl_probe(MYSQL *mysql __attribute__((unused))) { return 1; }
+#if MYSQL_VERSION_ID < 40000 || defined(EMBEDDED_LIBRARY)
+void mysql_enable_rpl_parse(MYSQL* mysql __attribute__((unused))) {}
+void mysql_disable_rpl_parse(MYSQL* mysql __attribute__((unused))) {}
+int mysql_rpl_parse_enabled(MYSQL* mysql __attribute__((unused))) { return 1; }
+int mysql_rpl_probe(MYSQL *mysql __attribute__((unused))) { return 1; }
#endif
+#define MAX_SERVER_ARGS 20
+
+static int embedded_server_arg_count=0;
+static char *embedded_server_args[MAX_SERVER_ARGS];
+
+static const char *embedded_server_groups[] = {
+ "server",
+ "embedded",
+ "mysqltest_SERVER",
+ NullS
+};
+
static void do_eval(DYNAMIC_STRING* query_eval, const char* query)
{
@@ -264,7 +310,7 @@ static void do_eval(DYNAMIC_STRING* query_eval, const char* query)
register char c;
register int escaped = 0;
VAR* v;
-
+
for(p = query; (c = *p); ++p)
{
switch(c)
@@ -277,7 +323,7 @@ static void do_eval(DYNAMIC_STRING* query_eval, const char* query)
}
else
{
- if(!(v = var_get(p, &p, 0)))
+ if(!(v = var_get(p, &p, 0, 0)))
die("Bad variable in eval");
dynstr_append_mem(query_eval, v->str_val, v->str_val_len);
}
@@ -301,6 +347,8 @@ static void do_eval(DYNAMIC_STRING* query_eval, const char* query)
static void close_cons()
{
DBUG_ENTER("close_cons");
+ if (last_result)
+ mysql_free_result(last_result);
for (--next_con; next_con >= cons; --next_con)
{
mysql_close(&next_con->mysql);
@@ -311,21 +359,27 @@ static void close_cons()
static void close_files()
{
- do
+ DBUG_ENTER("close_files");
+ for (; cur_file != file_stack ; cur_file--)
{
if (*cur_file != stdin && *cur_file)
my_fclose(*cur_file,MYF(0));
- } while (cur_file-- != file_stack);
+ }
+ DBUG_VOID_RETURN;
}
static void free_used_memory()
{
uint i;
DBUG_ENTER("free_used_memory");
+#ifndef EMBEDDED_LIBRARY
+ if (manager)
+ mysql_manager_close(manager);
+#endif
close_cons();
close_files();
hash_free(&var_hash);
-
+
for (i=0 ; i < q_lines.elements ; i++)
{
struct st_query **q= dynamic_element(&q_lines, i, struct st_query**);
@@ -337,10 +391,13 @@ static void free_used_memory()
if(var_reg[i].alloced_len)
my_free(var_reg[i].str_val, MYF(MY_WME));
}
+ while (embedded_server_arg_count > 1)
+ my_free(embedded_server_args[--embedded_server_arg_count],MYF(0));
delete_dynamic(&q_lines);
dynstr_free(&ds_res);
my_free(pass,MYF(MY_ALLOW_ZERO_PTR));
free_defaults(default_argv);
+ mysql_server_end();
my_end(MY_CHECK_ERROR);
DBUG_VOID_RETURN;
}
@@ -362,6 +419,8 @@ static void die(const char* fmt, ...)
exit(1);
}
+/* Note that we will get some memory leaks when calling this! */
+
static void abort_not_supported_test()
{
DBUG_ENTER("abort_not_supported_test");
@@ -416,13 +475,22 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char* fname)
DYNAMIC_STRING res_ds;
DBUG_ENTER("dyn_string_cmp");
- if (!my_stat(fname, &stat_info, MYF(MY_WME)))
+ if (!test_if_hard_path(fname))
+ {
+ strxmov(eval_file, opt_basedir, fname, NullS);
+ fn_format(eval_file, eval_file,"","",4);
+ }
+ else
+ fn_format(eval_file, fname,"","",4);
+
+ if (!my_stat(eval_file, &stat_info, MYF(MY_WME)))
die(NullS);
if (!eval_result && stat_info.st_size != ds->length)
DBUG_RETURN(2);
if (!(tmp = (char*) my_malloc(stat_info.st_size + 1, MYF(MY_WME))))
die(NullS);
- if ((fd = my_open(fname, O_RDONLY, MYF(MY_WME))) < 0)
+
+ if ((fd = my_open(eval_file, O_RDONLY, MYF(MY_WME))) < 0)
die(NullS);
if (my_read(fd, (byte*)tmp, stat_info.st_size, MYF(MY_WME|MY_NABP)))
die(NullS);
@@ -443,18 +511,18 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char* fname)
res_ptr = tmp;
res_len = stat_info.st_size;
}
-
+
res = (memcmp(res_ptr, ds->str, res_len)) ? 1 : 0;
-
+
err:
if(res && eval_result)
str_to_file(fn_format(eval_file, fname, "", ".eval",2), res_ptr,
res_len);
-
+
my_free((gptr) tmp, MYF(0));
my_close(fd, MYF(MY_WME));
dynstr_free(&res_ds);
-
+
DBUG_RETURN(res);
}
@@ -486,55 +554,58 @@ static int check_result(DYNAMIC_STRING* ds, const char* fname,
return error;
}
-VAR* var_get(const char* var_name, const char** var_name_end, int raw)
+VAR* var_get(const char* var_name, const char** var_name_end, my_bool raw,
+ my_bool ignore_not_existing)
{
int digit;
VAR* v;
- if (*var_name++ != '$')
- {
- --var_name;
+ DBUG_ENTER("var_get");
+ DBUG_PRINT("enter",("var_name: %s",var_name));
+
+ if (*var_name != '$')
goto err;
- }
- digit = *var_name - '0';
+ digit = *++var_name - '0';
if (!(digit < 10 && digit >= 0))
{
const char* save_var_name = var_name, *end;
end = (var_name_end) ? *var_name_end : 0;
- while (isvar(*var_name))
- {
- if(end && var_name == end)
- break;
+ while (isvar(*var_name) && var_name != end)
++var_name;
- }
- if(var_name == save_var_name)
+ if (var_name == save_var_name)
+ {
+ if (ignore_not_existing)
+ DBUG_RETURN(0);
die("Empty variable");
-
- if(!(v = (VAR*)hash_search(&var_hash, save_var_name,
+ }
+
+ if (!(v = (VAR*) hash_search(&var_hash, save_var_name,
var_name - save_var_name)))
- {
- if (end)
- *(char*)end = 0;
- die("Variable '%s' used uninitialized", save_var_name);
- }
- --var_name;
+ {
+ if (ignore_not_existing)
+ DBUG_RETURN(0);
+ if (end)
+ *(char*) end = 0;
+ die("Variable '%s' used uninitialized", save_var_name);
+ }
+ --var_name; /* Point at last character */
}
else
- v = var_reg + digit;
-
+ v = var_reg + digit;
+
if (!raw && v->int_dirty)
{
sprintf(v->str_val, "%d", v->int_val);
v->int_dirty = 0;
v->str_val_len = strlen(v->str_val);
}
- if(var_name_end)
+ if (var_name_end)
*var_name_end = var_name ;
- return v;
+ DBUG_RETURN(v);
err:
if (var_name_end)
*var_name_end = 0;
die("Unsupported variable name: %s", var_name);
- return 0;
+ DBUG_RETURN(0);
}
static VAR* var_obtain(char* name, int len)
@@ -565,15 +636,23 @@ int var_set(char* var_name, char* var_name_end, char* var_val,
}
else
v = var_reg + digit;
-
+
return eval_expr(v, var_val, (const char**)&var_val_end);
}
int open_file(const char* name)
{
+ char buff[FN_REFLEN];
+ if (!test_if_hard_path(name))
+ {
+ strxmov(buff, opt_basedir, name, NullS);
+ name=buff;
+ }
+ fn_format(buff,name,"","",4);
+
if (*cur_file && cur_file == file_stack_end)
die("Source directives are nesting too deep");
- if (!(*(cur_file+1) = my_fopen(name, O_RDONLY, MYF(MY_WME))))
+ if (!(*(cur_file+1) = my_fopen(buff, O_RDONLY, MYF(MY_WME))))
die(NullS);
cur_file++;
*++lineno=1;
@@ -581,6 +660,132 @@ int open_file(const char* name)
return 0;
}
+/* ugly long name, but we are following the convention */
+int do_wait_for_slave_to_stop(struct st_query* __attribute__((unused)) q)
+{
+ MYSQL* mysql = &cur_con->mysql;
+#ifndef OS2
+ struct timeval t;
+#endif
+ for (;;)
+ {
+ MYSQL_RES* res;
+ MYSQL_ROW row;
+ int done;
+ LINT_INIT(res);
+
+ if (mysql_query(mysql,"show status like 'Slave_running'")
+ || !(res=mysql_store_result(mysql)))
+ die("Query failed while probing slave for stop: %s",
+ mysql_error(mysql));
+ if (!(row=mysql_fetch_row(res)) || !row[1])
+ {
+ mysql_free_result(res);
+ die("Strange result from query while probing slave for stop");
+ }
+ done = !strcmp(row[1],"OFF");
+ mysql_free_result(res);
+ if (done)
+ break;
+#ifndef OS2
+ t.tv_sec=0;
+ t.tv_usec=SLAVE_POLL_INTERVAL;
+ select(0,0,0,0,&t); /* sleep */
+#else
+ DosSleep(OS2_SLAVE_POLL_INTERVAL);
+#endif
+ }
+
+ return 0;
+}
+
+int do_require_manager(struct st_query* __attribute__((unused)) q)
+{
+ if (!manager)
+ abort_not_supported_test();
+ return 0;
+}
+
+#ifndef EMBEDDED_LIBRARY
+int do_server_start(struct st_query* q)
+{
+ return do_server_op(q,"start");
+}
+
+int do_server_stop(struct st_query* q)
+{
+ return do_server_op(q,"stop");
+}
+
+int do_server_op(struct st_query* q,const char* op)
+{
+ char* p=q->first_argument;
+ char com_buf[256],*com_p;
+ if (!manager)
+ {
+ die("Manager is not initialized, manager commands are not possible");
+ }
+ com_p=strmov(com_buf,op);
+ com_p=strmov(com_p,"_exec ");
+ if (!*p)
+ die("Missing server name in server_%s\n",op);
+ while (*p && !isspace(*p))
+ {
+ *com_p++=*p++;
+ }
+ *com_p++=' ';
+ com_p=int10_to_str(manager_wait_timeout,com_p,10);
+ *com_p++ = '\n';
+ *com_p=0;
+ if (mysql_manager_command(manager,com_buf,(int)(com_p-com_buf)))
+ die("Error in command: %s(%d)",manager->last_error,manager->last_errno);
+ while (!manager->eof)
+ {
+ if (mysql_manager_fetch_line(manager,com_buf,sizeof(com_buf)))
+ die("Error fetching result line: %s(%d)", manager->last_error,
+ manager->last_errno);
+ }
+
+ return 0;
+}
+#endif
+
+int do_require_version(struct st_query* q)
+{
+ MYSQL* mysql = &cur_con->mysql;
+ MYSQL_RES* res;
+ MYSQL_ROW row;
+ char* p=q->first_argument, *ver_arg;
+ uint ver_arg_len,ver_len;
+ LINT_INIT(res);
+
+ if (!*p)
+ die("Missing version argument in require_version\n");
+ ver_arg = p;
+ while (*p && !isspace(*p))
+ p++;
+ *p = 0;
+ ver_arg_len = p - ver_arg;
+
+ if (mysql_query(mysql, "select version()") ||
+ !(res=mysql_store_result(mysql)))
+ die("Query failed while check server version: %s",
+ mysql_error(mysql));
+ if (!(row=mysql_fetch_row(res)) || !row[0])
+ {
+ mysql_free_result(res);
+ die("Strange result from query while checking version");
+ }
+ ver_len = strlen(row[0]);
+ if (ver_len < ver_arg_len || memcmp(row[0],ver_arg,ver_arg_len))
+ {
+ mysql_free_result(res);
+ abort_not_supported_test();
+ }
+ mysql_free_result(res);
+ return 0;
+}
+
int do_source(struct st_query* q)
{
char* p=q->first_argument, *name;
@@ -601,7 +806,7 @@ int var_query_set(VAR* v, const char* p, const char** p_end)
MYSQL_ROW row;
MYSQL* mysql = &cur_con->mysql;
LINT_INIT(res);
-
+
while (end > p && *end != '`')
--end;
if (p == end)
@@ -624,17 +829,29 @@ int var_query_set(VAR* v, const char* p, const char** p_end)
return 0;
}
+void var_copy(VAR* dest, VAR* src)
+{
+ dest->int_val=src->int_val;
+ dest->int_dirty=src->int_dirty;
+ if (dest->alloced_len < src->alloced_len &&
+ !(dest->str_val=my_realloc(dest->str_val,src->alloced_len+1,
+ MYF(MY_WME))))
+ die("Out of memory");
+ dest->str_val_len=src->str_val_len;
+ memcpy(dest->str_val,src->str_val,src->str_val_len+1);
+}
+
int eval_expr(VAR* v, const char* p, const char** p_end)
{
VAR* vp;
if (*p == '$')
+ {
+ if ((vp = var_get(p,p_end,0,0)))
{
- if ((vp = var_get(p,p_end,0)))
- {
- memcpy(v, vp, sizeof(*v));
- return 0;
- }
+ var_copy(v, vp);
+ return 0;
}
+ }
else if(*p == '`')
{
return var_query_set(v, p, p_end);
@@ -648,9 +865,9 @@ int eval_expr(VAR* v, const char* p, const char** p_end)
v->alloced_len = (new_val_len < MIN_VAR_ALLOC - 1) ?
MIN_VAR_ALLOC : new_val_len + 1;
if (!(v->str_val =
- v->str_val ? my_realloc(v->str_val, v->alloced_len,
+ v->str_val ? my_realloc(v->str_val, v->alloced_len+1,
MYF(MY_WME)) :
- my_malloc(v->alloced_len, MYF(MY_WME))))
+ my_malloc(v->alloced_len+1, MYF(MY_WME))))
die("Out of memory");
}
v->str_val_len = new_val_len;
@@ -671,7 +888,7 @@ int do_inc(struct st_query* q)
{
char* p=q->first_argument;
VAR* v;
- v = var_get(p, 0, 1);
+ v = var_get(p, 0, 1, 0);
v->int_val++;
v->int_dirty = 1;
return 0;
@@ -681,7 +898,7 @@ int do_dec(struct st_query* q)
{
char* p=q->first_argument;
VAR* v;
- v = var_get(p, 0, 1);
+ v = var_get(p, 0, 1, 0);
v->int_val--;
v->int_dirty = 1;
return 0;
@@ -704,6 +921,7 @@ int do_system(struct st_query* q)
if (system(expr_buf) && q->abort_on_error)
die("system command '%s' failed", expr_buf);
}
+ var_free(&v);
return 0;
}
@@ -719,6 +937,7 @@ int do_echo(struct st_query* q)
write(1, v.str_val, v.str_val_len);
}
write(1, "\n", 1);
+ var_free(&v);
return 0;
}
@@ -734,27 +953,26 @@ int do_sync_with_master(struct st_query* q)
rpl_parse = mysql_rpl_parse_enabled(mysql);
mysql_disable_rpl_parse(mysql);
-
+
if(*p)
offset = atoi(p);
-
+
sprintf(query_buf, "select master_pos_wait('%s', %ld)", master_pos.file,
master_pos.pos + offset);
if(mysql_query(mysql, query_buf))
die("At line %u: failed in %s: %d: %s", start_lineno, query_buf,
mysql_errno(mysql), mysql_error(mysql));
- if(!(res = mysql_store_result(mysql)))
+ if(!(last_result = res = mysql_store_result(mysql)))
die("line %u: mysql_store_result() retuned NULL", start_lineno);
if(!(row = mysql_fetch_row(res)))
die("line %u: empty result in %s", start_lineno, query_buf);
if(!row[0])
die("Error on slave while syncing with master");
- mysql_free_result(res);
-
+ mysql_free_result(res); last_result=0;
if(rpl_parse)
mysql_enable_rpl_parse(mysql);
-
+
return 0;
}
@@ -767,22 +985,22 @@ int do_save_master_pos()
rpl_parse = mysql_rpl_parse_enabled(mysql);
mysql_disable_rpl_parse(mysql);
-
+
if(mysql_query(mysql, "show master status"))
die("At line %u: failed in show master status: %d: %s", start_lineno,
mysql_errno(mysql), mysql_error(mysql));
- if(!(res = mysql_store_result(mysql)))
+ if(!(last_result =res = mysql_store_result(mysql)))
die("line %u: mysql_store_result() retuned NULL", start_lineno);
if(!(row = mysql_fetch_row(res)))
die("line %u: empty result in show master status", start_lineno);
strncpy(master_pos.file, row[0], sizeof(master_pos.file));
master_pos.pos = strtoul(row[1], (char**) 0, 10);
- mysql_free_result(res);
-
+ mysql_free_result(res); last_result=0;
+
if(rpl_parse)
mysql_enable_rpl_parse(mysql);
-
+
return 0;
}
@@ -887,10 +1105,11 @@ static void get_file_name(char *filename, struct st_query* q)
}
-static void get_ints(uint *to,struct st_query* q)
+static uint get_ints(uint *to,struct st_query* q)
{
char* p=q->first_argument;
long val;
+ uint count=0;
DBUG_ENTER("get_ints");
if (!*p)
@@ -898,25 +1117,28 @@ static void get_ints(uint *to,struct st_query* q)
for (; (p=str2int(p,10,(long) INT_MIN, (long) INT_MAX, &val)) ; p++)
{
+ count++;
*to++= (uint) val;
if (*p != ',')
break;
}
*to++=0; /* End of data */
- DBUG_VOID_RETURN;
+ DBUG_RETURN(count);
}
/*
Get a string; Return ptr to end of string
Strings may be surrounded by " or '
+
+ If string is a '$variable', return the value of the variable.
*/
-static void get_string(char **to_ptr, char **from_ptr,
- struct st_query* q)
+static char *get_string(char **to_ptr, char **from_ptr,
+ struct st_query* q)
{
reg1 char c,sep;
- char *to= *to_ptr, *from= *from_ptr;
+ char *to= *to_ptr, *from= *from_ptr, *start=to;
DBUG_ENTER("get_string");
/* Find separator */
@@ -966,9 +1188,22 @@ static void get_string(char **to_ptr, char **from_ptr,
while (isspace(*from)) /* Point to next string */
from++;
- *to++ =0; /* End of string marker */
- *to_ptr= to;
+ *to =0; /* End of string marker */
+ *to_ptr= to+1; /* Store pointer to end */
*from_ptr= from;
+
+ /* Check if this was a variable */
+ if (*start == '$')
+ {
+ const char *end= to;
+ VAR *var=var_get(start, &end, 0, 1);
+ if (var && to == (char*) end+1)
+ {
+ DBUG_PRINT("info",("var: %s -> %s", start, var->str_val));
+ DBUG_RETURN(var->str_val); /* return found variable value */
+ }
+ }
+ DBUG_RETURN(start);
}
@@ -976,6 +1211,8 @@ static void get_string(char **to_ptr, char **from_ptr,
Get arguments for replace. The syntax is:
replace from to [from to ...]
Where each argument may be quoted with ' or "
+ A argument may also be a variable, in which case the value of the
+ variable is replaced.
*/
static void get_replace(struct st_query *q)
@@ -987,6 +1224,9 @@ static void get_replace(struct st_query *q)
POINTER_ARRAY to_array,from_array;
DBUG_ENTER("get_replace");
+ if (glob_replace)
+ free_replace();
+
bzero((char*) &to_array,sizeof(to_array));
bzero((char*) &from_array,sizeof(from_array));
if (!*from)
@@ -995,12 +1235,11 @@ static void get_replace(struct st_query *q)
while (*from)
{
char *to=buff;
- get_string(&buff, &from, q);
+ to=get_string(&buff, &from, q);
if (!*from)
die("Wrong number of arguments to replace in %s\n", q->query);
insert_pointer_name(&from_array,to);
- to=buff;
- get_string(&buff, &from, q);
+ to=get_string(&buff, &from, q);
insert_pointer_name(&to_array,to);
}
for (i=1,pos=word_end_chars ; i < 256 ; i++)
@@ -1016,6 +1255,7 @@ static void get_replace(struct st_query *q)
free_pointer_array(&from_array);
free_pointer_array(&to_array);
my_free(start, MYF(0));
+ DBUG_VOID_RETURN;
}
void free_replace()
@@ -1068,19 +1308,19 @@ int close_connection(struct st_query* q)
p++;
*p = 0;
- for(con = cons; con < next_con; con++)
+ for (con = cons; con < next_con; con++)
{
if (!strcmp(con->name, name))
{
- if(q->type == Q_DIRTY_CLOSE)
+ if (q->type == Q_DIRTY_CLOSE)
+ {
+ if (con->mysql.net.vio)
{
- if(con->mysql.net.vio)
- {
- vio_delete(con->mysql.net.vio);
- con->mysql.net.vio = 0;
- }
+ vio_delete(con->mysql.net.vio);
+ con->mysql.net.vio = 0;
}
-
+ }
+
mysql_close(&con->mysql);
DBUG_RETURN(0);
}
@@ -1090,7 +1330,8 @@ int close_connection(struct st_query* q)
}
-/* this one now is a hack - we may want to improve in in the
+/*
+ This one now is a hack - we may want to improve in in the
future to handle quotes. For now we assume that anything that is not
a comma, a space or ) belongs to the argument. space is a chopper, comma or
) are delimiters/terminators
@@ -1112,6 +1353,37 @@ char* safe_get_param(char* str, char** arg, const char* msg)
DBUG_RETURN(str);
}
+#ifndef EMBEDDED_LIBRARY
+void init_manager()
+{
+ if (!(manager=mysql_manager_init(0)))
+ die("Failed in mysql_manager_init()");
+ if (!mysql_manager_connect(manager,manager_host,manager_user,
+ manager_pass,manager_port))
+ die("Could not connect to MySQL manager: %s(%d)",manager->last_error,
+ manager->last_errno);
+
+}
+#endif
+
+int safe_connect(MYSQL* con, const char* host, const char* user,
+ const char* pass,
+ const char* db, int port, const char* sock)
+{
+ int con_error = 1;
+ int i;
+ for (i = 0; i < MAX_CON_TRIES; ++i)
+ {
+ if (mysql_real_connect(con, host,user, pass, db, port, sock, 0))
+ {
+ con_error = 0;
+ break;
+ }
+ sleep(CON_RETRY_SLEEP);
+ }
+ return con_error;
+}
+
int do_connect(struct st_query* q)
{
@@ -1120,8 +1392,9 @@ int do_connect(struct st_query* q)
char* p=q->first_argument;
char buff[FN_REFLEN];
int con_port;
- int i, con_error;
-
+ int con_error;
+ int free_con_sock = 0;
+
DBUG_ENTER("do_connect");
DBUG_PRINT("enter",("connect: %s",p));
@@ -1140,40 +1413,54 @@ int do_connect(struct st_query* q)
}
else
{
+ VAR* var_port, *var_sock;
p = safe_get_param(p, &con_port_str, "missing connection port");
- con_port=atoi(con_port_str);
+ if (*con_port_str == '$')
+ {
+ if (!(var_port = var_get(con_port_str, 0, 0, 0)))
+ die("Unknown variable '%s'", con_port_str+1);
+ con_port = var_port->int_val;
+ }
+ else
+ con_port=atoi(con_port_str);
p = safe_get_param(p, &con_sock, "missing connection socket");
+ if (*con_sock == '$')
+ {
+ if (!(var_sock = var_get(con_sock, 0, 0, 0)))
+ die("Unknown variable '%s'", con_sock+1);
+ if (!(con_sock = (char*)my_malloc(var_sock->str_val_len+1, MYF(0))))
+ die("Out of memory");
+ free_con_sock = 1;
+ memcpy(con_sock, var_sock->str_val, var_sock->str_val_len);
+ con_sock[var_sock->str_val_len] = 0;
+ }
}
+
if (next_con == cons_end)
die("Connection limit exhausted - increase MAX_CONS in mysqltest.c");
if (!mysql_init(&next_con->mysql))
die("Failed on mysql_init()");
- if (con_sock)
+ if (opt_compress)
+ mysql_options(&next_con->mysql,MYSQL_OPT_COMPRESS,NullS);
+ if (con_sock && !free_con_sock && *con_sock && *con_sock != FN_LIBCHAR)
con_sock=fn_format(buff, con_sock, TMPDIR, "",0);
if (!con_db[0])
con_db=db;
- con_error = 1;
- for (i = 0; i < MAX_CON_TRIES; ++i)
- {
- if(mysql_real_connect(&next_con->mysql, con_host,
- con_user, con_pass,
- con_db, con_port, con_sock, 0))
- {
- con_error = 0;
- break;
- }
- sleep(CON_RETRY_SLEEP);
- }
-
- if(con_error)
+ /* Special database to allow one to connect without a database name */
+ if (!strcmp(con_db,"*NO-ONE*"))
+ con_db=0;
+ if ((con_error = 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 (free_con_sock)
+ my_free(con_sock, MYF(MY_WME));
DBUG_RETURN(0);
}
@@ -1187,10 +1474,10 @@ int do_done(struct st_query* q)
parser.current_line = *--cur_block;
}
else
- {
- ++parser.current_line;
- --cur_block;
- }
+ {
+ ++parser.current_line;
+ --cur_block;
+ }
return 0;
}
@@ -1199,7 +1486,6 @@ int do_while(struct st_query* q)
char* p=q->first_argument;
const char* expr_start, *expr_end;
VAR v;
- var_init(&v,0,0,0,0);
if (cur_block == block_stack_end)
die("Nesting too deeply");
if (!*block_ok)
@@ -1209,13 +1495,14 @@ int do_while(struct st_query* q)
*cur_block++ = parser.current_line++;
return 0;
}
-
+
expr_start = strchr(p, '(');
if (!expr_start)
die("missing '(' in while");
expr_end = strrchr(expr_start, ')');
if (!expr_end)
die("missing ')' in while");
+ var_init(&v,0,0,0,0);
eval_expr(&v, ++expr_start, &expr_end);
*cur_block++ = parser.current_line++;
if (!v.int_val)
@@ -1225,6 +1512,7 @@ int do_while(struct st_query* q)
}
else
*++block_ok = 1;
+ var_free(&v);
return 0;
}
@@ -1300,15 +1588,11 @@ int read_line(char* buf, int size)
{
if ((*cur_file) != stdin)
my_fclose(*cur_file,MYF(0));
-
+ cur_file--;
+ lineno--;
if (cur_file == file_stack)
return 1;
- else
- {
- cur_file--;
- lineno--;
- continue;
- }
+ continue;
}
switch(state) {
@@ -1439,8 +1723,11 @@ int read_query(struct st_query** q_ptr)
q->first_word_len = 0;
memcpy((gptr) q->expected_errno, (gptr) global_expected_errno,
sizeof(global_expected_errno));
+ q->expected_errors=global_expected_errors;
q->abort_on_error = global_expected_errno[0] == 0;
bzero((gptr) global_expected_errno,sizeof(global_expected_errno));
+ global_expected_errors=0;
+
q->type = Q_UNKNOWN;
q->query_buf=q->query=0;
if (read_line(read_query_buf, sizeof(read_query_buf)))
@@ -1469,6 +1756,7 @@ int read_query(struct st_query** q_ptr)
expected_errno = expected_errno * 10 + *p - '0';
q->expected_errno[0] = expected_errno;
q->expected_errno[1] = 0;
+ q->expected_errors=1;
}
}
@@ -1497,20 +1785,28 @@ int read_query(struct st_query** q_ptr)
return 0;
}
-
struct option long_options[] =
{
{"debug", optional_argument, 0, '#'},
{"database", required_argument, 0, 'D'},
+ {"basedir", required_argument, 0, 'b'},
{"big-test", no_argument, 0, 'B'},
+ {"compress", no_argument, 0, 'C'},
{"help", no_argument, 0, '?'},
{"host", required_argument, 0, 'h'},
+ {"manager-user",required_argument, 0, OPT_MANAGER_USER},
+ {"manager-host",required_argument, 0, OPT_MANAGER_HOST},
+ {"manager-password",required_argument,0,OPT_MANAGER_PASSWD},
+ {"manager-port",required_argument,0,OPT_MANAGER_PORT},
+ {"manager-wait-timeout",required_argument,0,OPT_MANAGER_WAIT_TIMEOUT},
{"password", optional_argument, 0, 'p'},
{"port", required_argument, 0, 'P'},
- {"quiet", no_argument, 0, 'q'},
+ {"quiet", no_argument, 0, 's'},
{"record", no_argument, 0, 'r'},
{"result-file", required_argument, 0, 'R'},
- {"silent", no_argument, 0, 'q'},
+ {"server-arg", required_argument, 0, 'A'},
+ {"server-file", required_argument, 0, 'F'},
+ {"silent", no_argument, 0, 's'},
{"sleep", required_argument, 0, 'T'},
{"socket", required_argument, 0, 'S'},
{"test-file", required_argument, 0, 'x'},
@@ -1546,9 +1842,14 @@ void usage()
-u, --user=... User for login.\n\
-p[password], --password[=...]\n\
Password to use when connecting to server.\n\
+ -b, --basedir=... Basedir for tests\n\
-B, --big-test Define BIG_TEST to 1\n\
+ -C, --compress Use the compressed server/client protocol\n\
-D, --database=... Database to use.\n\
-P, --port=... Port number to use for connection.\n\
+ --server-arg=... Send enbedded server this as a paramenter\n\
+ --server-file=... Read embedded server arguments from file\n\
+ -s, --silent, --quiet Suppress all normal output.\n\
-S, --socket=... Socket file to use for connection.\n\
-t, --tmpdir=... Temporary directory where sockets are put\n\
-T, --sleep=# Sleep always this many seconds on sleep commands\n\
@@ -1556,7 +1857,6 @@ void usage()
-R, --result-file=... Read/Store result from/in this file.\n\
-x, --test-file=... Read test from/in this file (default stdin).\n\
-v, --verbose Write more.\n\
- -q, --quiet, --silent Suppress all normal output.\n\
-V, --version Output version information and exit.\n\
--no-defaults Don't read default options from any options file.\n\n");
}
@@ -1569,12 +1869,12 @@ int parse_args(int argc, char **argv)
load_defaults("my",load_default_groups,&argc,&argv);
default_argv= argv;
- while((c = getopt_long(argc, argv, "h:p::u:BP:D:S:R:x:t:T:#:?rvVq",
- long_options, &option_index)) != EOF)
+ while ((c = getopt_long(argc, argv, "A:h:p::u:b:BCF:P:D:S:R:x:t:T:#:?rvVs",
+ long_options, &option_index)) != EOF)
{
switch(c) {
case '#':
- DBUG_PUSH(optarg ? optarg : "d:t:O,/tmp/mysqltest.trace");
+ DBUG_PUSH(optarg ? optarg : "d:t:S:i:O,/tmp/mysqltest.trace");
break;
case 'v':
verbose = 1;
@@ -1582,6 +1882,23 @@ int parse_args(int argc, char **argv)
case 'r':
record = 1;
break;
+ case (int)OPT_MANAGER_WAIT_TIMEOUT:
+ manager_wait_timeout=atoi(optarg);
+ break;
+ case (int)OPT_MANAGER_PORT:
+ manager_port=atoi(optarg);
+ break;
+ case (int)OPT_MANAGER_HOST:
+ manager_host=optarg;
+ break;
+ case (int)OPT_MANAGER_USER:
+ manager_user=optarg;
+ break;
+ case (int)OPT_MANAGER_PASSWD:
+ my_free(manager_pass,MYF(MY_ALLOW_ZERO_PTR));
+ manager_pass=my_strdup(optarg,MYF(MY_FAE));
+ while (*optarg) *optarg++= 'x'; /* Destroy argument */
+ break;
case 'u':
user = optarg;
break;
@@ -1589,9 +1906,18 @@ int parse_args(int argc, char **argv)
result_file = optarg;
break;
case 'x':
- if (!(*cur_file = my_fopen(optarg, O_RDONLY, MYF(MY_WME))))
+ {
+ char buff[FN_REFLEN];
+ if (!test_if_hard_path(optarg))
+ {
+ strxmov(buff, opt_basedir, optarg, NullS);
+ optarg=buff;
+ }
+ fn_format(buff,optarg,"","",4);
+ if (!(*++cur_file = my_fopen(buff, O_RDONLY, MYF(MY_WME))))
die("Could not open %s: errno = %d", optarg, errno);
break;
+ }
case 'p':
if (optarg)
{
@@ -1602,9 +1928,15 @@ int parse_args(int argc, char **argv)
else
tty_password=1;
break;
+ case 'b':
+ opt_basedir= optarg;
+ break;
case 'B':
opt_big_test=1;
break;
+ case 'C':
+ opt_compress=1;
+ break;
case 'P':
port = atoi(optarg);
break;
@@ -1617,7 +1949,7 @@ int parse_args(int argc, char **argv)
case 'h':
host = optarg;
break;
- case 'q':
+ case 's':
silent = 1;
break;
case 't':
@@ -1626,6 +1958,24 @@ int parse_args(int argc, char **argv)
case 'T':
opt_sleep=atoi(optarg);
break;
+ case 'A':
+ if (!embedded_server_arg_count)
+ {
+ embedded_server_arg_count=1;
+ embedded_server_args[0]= (char*) "";
+ }
+ embedded_server_args[embedded_server_arg_count++]=
+ my_strdup(optarg,MYF(MY_FAE));
+ if (embedded_server_arg_count == MAX_SERVER_ARGS ||
+ !embedded_server_args[embedded_server_arg_count-1])
+ {
+ die("Can't use server argument");
+ }
+ break;
+ case 'F':
+ if (read_server_arguments(optarg))
+ die(NullS);
+ break;
case 'V':
print_version();
exit(0);
@@ -1633,6 +1983,7 @@ int parse_args(int argc, char **argv)
usage();
exit(1); /* Unknown option */
default:
+ fprintf(stderr,"Unknown option '%c'\n",c);
usage();
exit(1);
}
@@ -1665,9 +2016,17 @@ char* safe_str_append(char* buf, const char* str, int size)
void str_to_file(const char* fname, char* str, int size)
{
int fd;
- if ((fd = my_open(fname, O_WRONLY | O_CREAT | O_TRUNC,
+ char buff[FN_REFLEN];
+ if (!test_if_hard_path(fname))
+ {
+ strxmov(buff, opt_basedir, fname, NullS);
+ fname=buff;
+ }
+ fn_format(buff,fname,"","",4);
+
+ if ((fd = my_open(buff, O_WRONLY | O_CREAT | O_TRUNC,
MYF(MY_WME | MY_FFNF))) < 0)
- die("Could not open %s: errno = %d", fname, errno);
+ die("Could not open %s: errno = %d", buff, errno);
if (my_write(fd, (byte*)str, size, MYF(MY_WME|MY_FNABP)))
die("write failed");
my_close(fd, MYF(0));
@@ -1679,6 +2038,22 @@ void reject_dump(const char* record_file, char* buf, int size)
str_to_file(fn_format(reject_file, record_file,"",".reject",2), buf, size);
}
+
+/* Append the string to ds, with optional replace */
+
+static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, char *val, int len)
+{
+ if (glob_replace)
+ {
+ len=(int) replace_strings(glob_replace, &out_buff, &out_length, val);
+ if (len == -1)
+ die("Out of memory in replace\n");
+ val=out_buff;
+ }
+ dynstr_append_mem(ds, val, len);
+}
+
+
/*
* flags control the phased/stages of query execution to be performed
* if QUERY_SEND bit is on, the query will be sent. If QUERY_REAP is on
@@ -1701,54 +2076,82 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags)
int query_len;
DBUG_ENTER("run_query");
- if(q->type != Q_EVAL)
- {
- query = q->query;
- query_len = strlen(query);
- }
+ if (q->type != Q_EVAL)
+ {
+ query = q->query;
+ query_len = strlen(query);
+ }
else
- {
- init_dynamic_string(&eval_query, "", 16384, 65536);
- do_eval(&eval_query, q->query);
- query = eval_query.str;
- query_len = eval_query.length;
- }
-
- if ( q->record_file[0])
+ {
+ init_dynamic_string(&eval_query, "", 16384, 65536);
+ do_eval(&eval_query, q->query);
+ query = eval_query.str;
+ query_len = eval_query.length;
+ }
+
+ if (q->record_file[0])
{
init_dynamic_string(&ds_tmp, "", 16384, 65536);
ds = &ds_tmp;
}
else
ds= &ds_res;
-
+
if ((flags & QUERY_SEND) && mysql_send_query(mysql, query, query_len))
- die("At line %u: unable to send query '%s'", start_lineno, query);
- if(!(flags & QUERY_REAP))
- return 0;
-
+ die("At line %u: unable to send query '%s'(mysql_errno=%d,errno=%d)",
+ start_lineno, query,
+ mysql_errno(mysql), errno);
+ if ((flags & QUERY_SEND) && !disable_query_log)
+ {
+ replace_dynstr_append_mem(ds,query, query_len);
+ dynstr_append_mem(ds,";\n",2);
+ }
+ if (!(flags & QUERY_REAP))
+ DBUG_RETURN(0);
+
if (mysql_read_query_result(mysql) ||
- (!(res = mysql_store_result(mysql)) && mysql_field_count(mysql)))
+ (!(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 ; q->expected_errno[i] ; i++)
+ for (i=0 ; (uint) i < q->expected_errors ; i++)
{
if ((q->expected_errno[i] == mysql_errno(mysql)))
+ {
+ if (i == 0 && q->expected_errors == 1)
+ {
+ /* Only log error if there is one possible error */
+ 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] != 0)
+ dynstr_append(ds,"Got one of the listed errors\n");
goto end; /* Ok */
+ }
}
if (i)
{
+ replace_dynstr_append_mem(ds, mysql_error(mysql),
+ strlen(mysql_error(mysql)));
+ dynstr_append_mem(ds,"\n",1);
verbose_msg("query '%s' failed with wrong errno %d instead of %d...",
q->query, mysql_errno(mysql), q->expected_errno[0]);
error=1;
goto end;
}
+ replace_dynstr_append_mem(ds,mysql_error(mysql),
+ strlen(mysql_error(mysql)));
+ dynstr_append_mem(ds,"\n",1);
verbose_msg("query '%s' failed: %d: %s", q->query, mysql_errno(mysql),
mysql_error(mysql));
/*
@@ -1773,51 +2176,45 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags)
goto end;
}
- if (!res) goto end;
+ if (!res)
+ goto end;
- fields = mysql_fetch_fields(res);
- num_fields = mysql_num_fields(res);
- for( i = 0; i < num_fields; i++)
+ if (!disable_result_log)
{
- if (i)
- dynstr_append_mem(ds, "\t", 1);
- dynstr_append(ds, fields[i].name);
- }
-
- dynstr_append_mem(ds, "\n", 1);
+ fields = mysql_fetch_fields(res);
+ num_fields = mysql_num_fields(res);
+ for (i = 0; i < num_fields; i++)
+ {
+ if (i)
+ dynstr_append_mem(ds, "\t", 1);
+ dynstr_append(ds, fields[i].name);
+ }
+ dynstr_append_mem(ds, "\n", 1);
- while((row = mysql_fetch_row(res)))
- {
- lengths = mysql_fetch_lengths(res);
- for(i = 0; i < num_fields; i++)
+ while ((row = mysql_fetch_row(res)))
{
- val = (char*)row[i];
- len = lengths[i];
-
- if (!val)
+ lengths = mysql_fetch_lengths(res);
+ for(i = 0; i < num_fields; i++)
{
- val = (char*)"NULL";
- len = 4;
- }
+ val = (char*)row[i];
+ len = lengths[i];
- if (i)
- dynstr_append_mem(ds, "\t", 1);
- if (glob_replace)
- {
- len=(int) replace_strings(glob_replace, &out_buff, &out_length, val);
- if (len == -1)
- die("Out of memory in replace\n");
- val=out_buff;
+ if (!val)
+ {
+ val = (char*)"NULL";
+ len = 4;
+ }
+
+ if (i)
+ dynstr_append_mem(ds, "\t", 1);
+ replace_dynstr_append_mem(ds, val, len);
}
- dynstr_append_mem(ds, val, len);
+ dynstr_append_mem(ds, "\n", 1);
}
-
- dynstr_append_mem(ds, "\n", 1);
+ if (glob_replace)
+ free_replace();
}
- if (glob_replace)
- free_replace();
-
if (record)
{
if (!q->record_file[0] && !result_file)
@@ -1831,7 +2228,9 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags)
}
end:
- if (res) mysql_free_result(res);
+ if (res)
+ mysql_free_result(res);
+ last_result=0;
if (ds == &ds_tmp)
dynstr_free(&ds_tmp);
if(q->type == Q_EVAL)
@@ -1874,23 +2273,27 @@ static VAR* var_init(VAR* v, const char* name, int name_len, const char* val,
{
int val_alloc_len;
VAR* tmp_var;
- if(!name_len && name)
+ if (!name_len && name)
name_len = strlen(name);
- if(!val_len && val)
+ if (!val_len && val)
val_len = strlen(val) ;
val_alloc_len = val_len + 16; /* room to grow */
- if(!(tmp_var=v) && !(tmp_var = (VAR*)my_malloc(sizeof(*tmp_var)
- + name_len, MYF(MY_WME))))
+ if (!(tmp_var=v) && !(tmp_var = (VAR*)my_malloc(sizeof(*tmp_var)
+ + name_len, MYF(MY_WME))))
die("Out of memory");
-
- tmp_var->name = (name) ? (char*)tmp_var + sizeof(*tmp_var) : 0;
- if(!(tmp_var->str_val = my_malloc(val_alloc_len, MYF(MY_WME))))
+ tmp_var->name = (name) ? (char*) tmp_var + sizeof(*tmp_var) : 0;
+ tmp_var->alloced = (v == 0);
+
+ if (!(tmp_var->str_val = my_malloc(val_alloc_len+1, MYF(MY_WME))))
die("Out of memory");
-
+
memcpy(tmp_var->name, name, name_len);
- if(val)
- memcpy(tmp_var->str_val, val, val_len + 1);
+ if (val)
+ {
+ memcpy(tmp_var->str_val, val, val_len);
+ tmp_var->str_val[val_len]=0;
+ }
tmp_var->name_len = name_len;
tmp_var->str_val_len = val_len;
tmp_var->alloced_len = val_alloc_len;
@@ -1902,7 +2305,8 @@ static VAR* var_init(VAR* v, const char* name, int name_len, const char* val,
static void var_free(void* v)
{
my_free(((VAR*) v)->str_val, MYF(MY_WME));
- my_free((char*) v, MYF(MY_WME));
+ if (((VAR*)v)->alloced)
+ my_free((char*) v, MYF(MY_WME));
}
@@ -1910,9 +2314,9 @@ static void var_from_env(const char* name, const char* def_val)
{
const char* tmp;
VAR* v;
- if(!(tmp = getenv(name)))
+ if (!(tmp = getenv(name)))
tmp = def_val;
-
+
v = var_init(0, name, 0, tmp, 0);
hash_insert(&var_hash, (byte*)v);
}
@@ -1920,14 +2324,18 @@ static void var_from_env(const char* name, const char* def_val)
static void init_var_hash()
{
+ VAR* v;
if (hash_init(&var_hash, 1024, 0, 0, get_var_key, var_free, MYF(0)))
die("Variable hash initialization failed");
var_from_env("MASTER_MYPORT", "9306");
var_from_env("SLAVE_MYPORT", "9307");
var_from_env("MYSQL_TEST_DIR", "/tmp");
var_from_env("BIG_TEST", opt_big_test ? "1" : "0");
+ v=var_init(0,"MAX_TABLES", 0, (sizeof(ulong) == 4) ? "31" : "63",0);
+ hash_insert(&var_hash, (byte*)v);
}
+
int main(int argc, char** argv)
{
int error = 0;
@@ -1935,6 +2343,9 @@ int main(int argc, char** argv)
my_bool require_file=0, q_send_flag=0;
char save_file[FN_REFLEN];
MY_INIT(argv[0]);
+ {
+ DBUG_ENTER("main");
+ DBUG_PROCESS(argv[0]);
save_file[0]=0;
TMPDIR[0]=0;
@@ -1942,7 +2353,7 @@ int main(int argc, char** argv)
cons_end = cons + MAX_CONS;
next_con = cons + 1;
cur_con = cons;
-
+
memset(file_stack, 0, sizeof(file_stack));
memset(&master_pos, 0, sizeof(master_pos));
file_stack_end = file_stack + MAX_INCLUDE_DEPTH;
@@ -1959,20 +2370,28 @@ int main(int argc, char** argv)
*block_ok = 1;
init_dynamic_string(&ds_res, "", 0, 65536);
parse_args(argc, argv);
+ if (mysql_server_init(embedded_server_arg_count,
+ embedded_server_args,
+ (char**) embedded_server_groups))
+ die("Can't initialize MySQL server");
init_var_hash();
- if (!*cur_file)
- *cur_file = stdin;
+ if (cur_file == file_stack)
+ *++cur_file = stdin;
*lineno=1;
-
+#ifndef EMBEDDED_LIBRARY
+ if (manager_host)
+ init_manager();
+#endif
if (!( mysql_init(&cur_con->mysql)))
die("Failed in mysql_init()");
+ if (opt_compress)
+ mysql_options(&cur_con->mysql,MYSQL_OPT_COMPRESS,NullS);
cur_con->name = my_strdup("default", MYF(MY_WME));
if (!cur_con->name)
die("Out of memory");
- if (!mysql_real_connect(&cur_con->mysql, host,
- user, pass, db, port, unix_sock,
- 0))
+ if (safe_connect(&cur_con->mysql, host,
+ user, pass, db, port, unix_sock))
die("Failed in mysql_real_connect(): %s", mysql_error(&cur_con->mysql));
while (!read_query(&q))
@@ -1990,10 +2409,21 @@ int main(int argc, char** argv)
case Q_DIRTY_CLOSE:
close_connection(q); break;
case Q_RPL_PROBE: do_rpl_probe(q); break;
- case Q_ENABLE_RPL_PARSE: do_enable_rpl_parse(q); break;
- case Q_DISABLE_RPL_PARSE: do_disable_rpl_parse(q); break;
+ case Q_ENABLE_RPL_PARSE: do_enable_rpl_parse(q); break;
+ case Q_DISABLE_RPL_PARSE: do_disable_rpl_parse(q); break;
+ case Q_ENABLE_QUERY_LOG: disable_query_log=0; break;
+ case Q_DISABLE_QUERY_LOG: disable_query_log=1; break;
+ case Q_ENABLE_RESULT_LOG: disable_result_log=0; break;
+ case Q_DISABLE_RESULT_LOG: disable_result_log=1; break;
case Q_SOURCE: do_source(q); break;
case Q_SLEEP: do_sleep(q); break;
+ case Q_REQUIRE_VERSION: do_require_version(q); break;
+ case Q_WAIT_FOR_SLAVE_TO_STOP: do_wait_for_slave_to_stop(q); break;
+ case Q_REQUIRE_MANAGER: do_require_manager(q); break;
+#ifndef EMBEDDED_LIBRARY
+ case Q_SERVER_START: do_server_start(q); break;
+ case Q_SERVER_STOP: do_server_stop(q); break;
+#endif
case Q_INC: do_inc(q); break;
case Q_DEC: do_dec(q); break;
case Q_ECHO: do_echo(q); break;
@@ -2002,7 +2432,7 @@ int main(int argc, char** argv)
case Q_EVAL_RESULT: eval_result = 1; break;
case Q_EVAL:
if (q->query == q->query_buf)
- q->query += q->first_word_len;
+ q->query= q->first_argument;
/* fall through */
case Q_QUERY:
case Q_REAP:
@@ -2048,7 +2478,7 @@ int main(int argc, char** argv)
require_file=0;
break;
case Q_ERROR:
- get_ints(global_expected_errno,q);
+ global_expected_errors=get_ints(global_expected_errno,q);
break;
case Q_REQUIRE:
get_file_name(save_file,q);
@@ -2092,7 +2522,7 @@ int main(int argc, char** argv)
dynstr_free(&ds_res);
if (!silent) {
- if(error)
+ if (error)
printf("not ok\n");
else
printf("ok\n");
@@ -2101,8 +2531,54 @@ int main(int argc, char** argv)
free_used_memory();
exit(error ? 1 : 0);
return error ? 1 : 0; /* Keep compiler happy */
+ }
}
+/*
+ Read arguments for embedded server and put them into
+ embedded_server_args_count and embedded_server_args[]
+*/
+
+
+static int read_server_arguments(const char* name)
+{
+ char argument[1024],buff[FN_REFLEN], *str=0;
+ FILE *file;
+
+ if (!test_if_hard_path(name))
+ {
+ strxmov(buff, opt_basedir, name, NullS);
+ name=buff;
+ }
+ fn_format(buff,name,"","",4);
+
+ if (!embedded_server_arg_count)
+ {
+ embedded_server_arg_count=1;
+ embedded_server_args[0]= (char*) ""; /* Progname */
+ }
+ if (!(file=my_fopen(buff, O_RDONLY | O_BINARY, MYF(MY_WME))))
+ return 1;
+ while (embedded_server_arg_count < MAX_SERVER_ARGS &&
+ (str=fgets(argument,sizeof(argument), file)))
+ {
+ *(strend(str)-1)=0; /* Remove end newline */
+ if (!(embedded_server_args[embedded_server_arg_count]=
+ (char*) my_strdup(str,MYF(MY_WME))))
+ {
+ my_fclose(file,MYF(0));
+ return 1;
+ }
+ embedded_server_arg_count++;
+ }
+ my_fclose(file,MYF(0));
+ if (str)
+ {
+ fprintf(stderr,"Too many arguments in option file: %s\n",name);
+ return 1;
+ }
+ return 0;
+}
/****************************************************************************
* Handle replacement of strings
diff --git a/client/password.c b/client/password.c
index 0fd5861873a..9b154603b98 100644
--- a/client/password.c
+++ b/client/password.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* password checking routines */
/*****************************************************************************
@@ -35,7 +34,7 @@
This saves a hashed number as a string in the password field.
*****************************************************************************/
-#include <global.h>
+#include <my_global.h>
#include <my_sys.h>
#include <m_string.h>
#include "mysql.h"
diff --git a/client/readline.cc b/client/readline.cc
index f0312b089e5..f5fbfd8cd0c 100644
--- a/client/readline.cc
+++ b/client/readline.cc
@@ -1,23 +1,22 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* readline for batch mode */
-#include <global.h>
+#include <my_global.h>
#include <my_sys.h>
#include <m_string.h>
#include "my_readline.h"
@@ -120,20 +119,11 @@ static bool init_line_buffer_from_string(LINE_BUFFER *buffer,my_string str)
}
-static void free_line_buffer(LINE_BUFFER *buffer)
-{
- if (buffer->buffer)
- {
- my_free((gptr) buffer->buffer,MYF(0));
- buffer->buffer=0;
- }
-}
-
-
-/* Fill the buffer retaining the last n bytes at the beginning of the
- newly filled buffer (for backward context). Returns the number of new
- bytes read from disk. */
-
+/*
+ Fill the buffer retaining the last n bytes at the beginning of the
+ newly filled buffer (for backward context). Returns the number of new
+ bytes read from disk.
+*/
static uint fill_buffer(LINE_BUFFER *buffer)
{
diff --git a/client/select_test.c b/client/select_test.c
index 049f2b908be..ee2a9192865 100644
--- a/client/select_test.c
+++ b/client/select_test.c
@@ -1,20 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
diff --git a/client/showdb_test.c b/client/showdb_test.c
index f4c25999fe5..df2b3037c00 100644
--- a/client/showdb_test.c
+++ b/client/showdb_test.c
@@ -1,34 +1,20 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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 */
+/* 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 */
+
#ifdef __WIN__
#include <windows.h>
#endif
diff --git a/client/sql_string.cc b/client/sql_string.cc
index 4b9ebef21f1..3c5e481eaad 100644
--- a/client/sql_string.cc
+++ b/client/sql_string.cc
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program file 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 originally from the mysql distribution. Coded by monty */
@@ -21,7 +20,7 @@
#pragma implementation // gcc: Class implementation
#endif
-#include <global.h>
+#include <my_global.h>
#include <my_sys.h>
#include <m_string.h>
#include <m_ctype.h>
diff --git a/client/sql_string.h b/client/sql_string.h
index 74dbc4cc6bd..cffe78936a0 100644
--- a/client/sql_string.h
+++ b/client/sql_string.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 originally from the mysql distribution. Coded by monty */
diff --git a/client/ssl_test.c b/client/ssl_test.c
index d1ec1776696..279c1e95fdc 100644
--- a/client/ssl_test.c
+++ b/client/ssl_test.c
@@ -1,34 +1,20 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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 */
+/* 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 */
+
#ifdef __WIN__
#include <windows.h>
#endif
diff --git a/client/thimble.cc b/client/thimble.cc
index 6d1e8a85559..94b75d8fb35 100644
--- a/client/thimble.cc
+++ b/client/thimble.cc
@@ -1,8 +1,24 @@
+/* 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 */
+
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
-#include "my_global.h"
+#include "my_my_global.h"
static void spawn_stern_thread(pthread_t *t);
static int act_goofy(void);
@@ -89,5 +105,3 @@ static void *be_stern(void *v __attribute__((unused)))
fputs("You are NOTHING!\n", stderr);
return NULL;
}
-
-
diff --git a/client/thread_test.c b/client/thread_test.c
index dbe2acee8db..f7e2a6fd32a 100644
--- a/client/thread_test.c
+++ b/client/thread_test.c
@@ -1,25 +1,24 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <global.h>
+#include <my_global.h>
#ifndef THREAD
-int main(void)
+int main(int argc __attribute__((unused)), char **argv __attribute__((unused)))
{
printf("This test must be compiled with multithread support to work\n");
exit(1);
diff --git a/client/violite.c b/client/violite.c
deleted file mode 100644
index 224ba051d82..00000000000
--- a/client/violite.c
+++ /dev/null
@@ -1,394 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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 */
-
-#include <global.h>
-
-#ifndef HAVE_VIO /* is Vio suppored by the Vio lib ? */
-
-#include <errno.h>
-#include <assert.h>
-#include <violite.h>
-#include <my_sys.h>
-#include <my_net.h>
-#include <m_string.h>
-
-#if defined(__EMX__)
-#include <sys/ioctl.h>
-#define ioctlsocket(A,B,C) ioctl((A),(B),(void *)(C),sizeof(*(C)))
-#undef HAVE_FCNTL
-#endif /* defined(__EMX__) */
-
-#if defined(MSDOS) || defined(__WIN__)
-#ifdef __WIN__
-#undef errno
-#undef EINTR
-#undef EAGAIN
-#define errno WSAGetLastError()
-#define EINTR WSAEINTR
-#define EAGAIN WSAEINPROGRESS
-#endif /* __WIN__ */
-#define O_NONBLOCK 1 /* For emulation of fcntl() */
-#endif
-#ifndef EWOULDBLOCK
-#define EWOULDBLOCK EAGAIN
-#endif
-
-#ifndef __WIN__
-#define HANDLE void *
-#endif
-
-struct st_vio
-{
- my_socket sd; /* my_socket - real or imaginary */
- HANDLE hPipe;
- my_bool localhost; /* Are we from localhost? */
- int fcntl_mode; /* Buffered fcntl(sd,F_GETFL) */
- my_bool fcntl_set; /* Have we done any fcntl yet?*/
- struct sockaddr_in local; /* Local internet address */
- struct sockaddr_in remote; /* Remote internet address */
- enum enum_vio_type type; /* Type of connection */
- char desc[30]; /* String description */
-};
-
-typedef void *vio_ptr;
-typedef char *vio_cstring;
-
-/*
- * Helper to fill most of the Vio* with defaults.
- */
-
-static void vio_reset(Vio* vio, enum enum_vio_type type,
- my_socket sd, HANDLE hPipe,
- my_bool localhost)
-{
- bzero((char*) vio, sizeof(*vio));
- vio->type = type;
- vio->sd = sd;
- vio->hPipe = hPipe;
- vio->localhost= localhost;
-}
-
-Vio *vio_new(my_socket sd, enum enum_vio_type type, my_bool localhost)
-{
- Vio *vio;
- DBUG_ENTER("vio_new");
- DBUG_PRINT("enter", ("sd=%d", sd));
- if ((vio = (Vio*) my_malloc(sizeof(*vio),MYF(MY_WME))))
- {
- vio_reset(vio, type, sd, 0, localhost);
- sprintf(vio->desc, "socket (%d)", vio->sd);
- }
- DBUG_RETURN(vio);
-}
-
-
-#ifdef __WIN__
-
-Vio *vio_new_win32pipe(HANDLE hPipe)
-{
- Vio *vio;
- DBUG_ENTER("vio_new_handle");
- if ((vio = (Vio*) my_malloc(sizeof(Vio),MYF(MY_WME))))
- {
- vio_reset(vio, VIO_TYPE_NAMEDPIPE, 0, hPipe, TRUE);
- strmov(vio->desc, "named pipe");
- }
- DBUG_RETURN(vio);
-}
-
-#endif
-
-void vio_delete(Vio * vio)
-{
- /* It must be safe to delete null pointers. */
- /* This matches the semantics of C++'s delete operator. */
- if (vio)
- {
- vio_close(vio);
- my_free((gptr) vio,MYF(0));
- }
-}
-
-int vio_errno(Vio *vio)
-{
- return errno; /* On Win32 this mapped to WSAGetLastError() */
-}
-
-
-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));
- assert(vio->sd >= 0);
-#ifdef __WIN__
- if (vio->type == VIO_TYPE_NAMEDPIPE)
- {
- DWORD length;
- if (!ReadFile(vio->hPipe, buf, size, &length, NULL))
- DBUG_RETURN(-1);
- DBUG_RETURN(length);
- }
- r = recv(vio->sd, buf, size,0);
-#else
- errno=0; /* For linux */
- r = read(vio->sd, buf, size);
-#endif /* __WIN__ */
-#ifndef DBUG_OFF
- if (r < 0)
- {
- DBUG_PRINT("error", ("Got error %d during read",errno));
- }
-#endif /* DBUG_OFF */
- DBUG_PRINT("exit", ("%d", r));
- DBUG_RETURN(r);
-}
-
-
-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));
- assert(vio->sd >= 0);
-#ifdef __WIN__
- if ( vio->type == VIO_TYPE_NAMEDPIPE)
- {
- DWORD length;
- if (!WriteFile(vio->hPipe, (char*) buf, size, &length, NULL))
- DBUG_RETURN(-1);
- DBUG_RETURN(length);
- }
- r = send(vio->sd, buf, size,0);
-#else
- r = write(vio->sd, buf, size);
-#endif /* __WIN__ */
-#ifndef DBUG_OFF
- if (r < 0)
- {
- DBUG_PRINT("error", ("Got error on write: %d",errno));
- }
-#endif /* DBUG_OFF */
- DBUG_PRINT("exit", ("%d", r));
- DBUG_RETURN(r);
-}
-
-
-int vio_blocking(Vio * vio, my_bool set_blocking_mode)
-{
- int r=0;
- DBUG_ENTER("vio_blocking");
- DBUG_PRINT("enter", ("set_blocking_mode: %d", (int) set_blocking_mode));
-
-#if !defined(___WIN__) && !defined(__EMX__)
-#if !defined(NO_FCNTL_NONBLOCK)
-
- if (vio->sd >= 0)
- {
- int old_fcntl=vio->fcntl_mode;
- if (!vio->fcntl_set)
- {
- vio->fcntl_set = TRUE;
- old_fcntl=vio->fcntl_mode = fcntl(vio->sd, F_GETFL);
- }
- if (set_blocking_mode)
- vio->fcntl_mode &= ~O_NONBLOCK; /*clear bit */
- else
- vio->fcntl_mode |= O_NONBLOCK; /*set bit */
- if (old_fcntl != vio->fcntl_mode)
- r = fcntl(vio->sd, F_SETFL, vio->fcntl_mode);
- }
-#endif /* !defined(NO_FCNTL_NONBLOCK) */
-#else /* !defined(__WIN__) && !defined(__EMX__) */
-#ifndef __EMX__
- if (vio->type != VIO_TYPE_NAMEDPIPE)
-#endif
- {
- ulong arg;
- int old_fcntl=vio->fcntl_mode;
- if (!vio->fcntl_set)
- {
- vio->fcntl_set = TRUE;
- old_fnctl=vio->fcntl_mode=0;
- }
- if (set_blocking_mode)
- {
- arg = 0;
- vio->fcntl_mode &= ~O_NONBLOCK; /*clear bit */
- }
- else
- {
- arg = 1;
- vio->fcntl_mode |= O_NONBLOCK; /*set bit */
- }
- if (old_fcntl != vio->fcntl_mode)
- r = ioctlsocket(vio->sd,FIONBIO,(void*) &arg, sizeof(arg));
- }
-#endif /* !defined(__WIN__) && !defined(__EMX__) */
- DBUG_RETURN(r);
-}
-
-my_bool
-vio_is_blocking(Vio * vio)
-{
- my_bool r;
- DBUG_ENTER("vio_is_blocking");
- r = !(vio->fcntl_mode & O_NONBLOCK);
- DBUG_PRINT("exit", ("%d", (int) r));
- DBUG_RETURN(r);
-}
-
-
-int vio_fastsend(Vio * vio, my_bool onoff)
-{
- int r=0;
- DBUG_ENTER("vio_fastsend");
- DBUG_PRINT("enter", ("onoff:%d", (int) onoff));
- assert(vio->sd >= 0);
-
-#ifdef IPTOS_THROUGHPUT
- {
-#ifndef __EMX__
- int tos = IPTOS_THROUGHPUT;
- if (!setsockopt(vio->sd, IPPROTO_IP, IP_TOS, (void *) &tos, sizeof(tos)))
-#endif /* !__EMX__ */
- {
- int nodelay = 1;
- if (setsockopt(vio->sd, IPPROTO_TCP, TCP_NODELAY, (void *) &nodelay,
- sizeof(nodelay))) {
- DBUG_PRINT("warning",
- ("Couldn't set socket option for fast send"));
- r= -1;
- }
- }
- }
-#endif /* IPTOS_THROUGHPUT */
- DBUG_PRINT("exit", ("%d", r));
- DBUG_RETURN(r);
-}
-
-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)
- set_keep_alive));
- if (vio->type != VIO_TYPE_NAMEDPIPE)
- {
- assert(vio->sd >= 0);
- if (set_keep_alive)
- opt = 1;
- r = setsockopt(vio->sd, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt,
- sizeof(opt));
- }
- DBUG_RETURN(r);
-}
-
-
-my_bool
-vio_should_retry(Vio * vio)
-{
- int en = errno;
- return en == EAGAIN || en == EINTR || en == EWOULDBLOCK;
-}
-
-
-int vio_close(Vio * vio)
-{
- int r;
- DBUG_ENTER("vio_close");
- assert(vio->sd >= 0); /* Vill also work on PIPE:s */
-#ifdef __WIN__
- if (vio->type == VIO_TYPE_NAMEDPIPE)
- {
-#if defined(__NT__) && defined(MYSQL_SERVER)
- CancelIO(vio->hPipe);
- DisconnectNamedPipe(vio->hPipe);
-#endif
- r=CloseHandle(vio->hPipe);
- }
- else
-#endif /* __WIN__ */
- {
- r=0;
- if (shutdown(vio->sd,2))
- r= -1;
- if (closesocket(vio->sd))
- r= -1;
- }
- if (r)
- {
- DBUG_PRINT("error", ("close() failed, error: %d",errno));
- /* FIXME: error handling (not critical for MySQL) */
- }
- vio_reset(vio,VIO_CLOSED,-1,0,TRUE); /* For debugging */
- DBUG_RETURN(r);
-}
-
-
-const char *vio_description(Vio * vio)
-{
- return vio->desc;
-}
-
-enum enum_vio_type vio_type(Vio* vio)
-{
- return vio->type;
-}
-
-my_socket vio_fd(Vio* vio)
-{
- return vio->sd;
-}
-
-
-my_bool vio_peer_addr(Vio * vio, char *buf)
-{
- DBUG_ENTER("vio_peer_addr");
- DBUG_PRINT("enter", ("sd=%d", vio->sd));
- if (vio->localhost)
- {
- strmov(buf,"127.0.0.1");
- }
- else
- {
- size_socket addrLen = sizeof(struct sockaddr);
- if (getpeername(vio->sd, (struct sockaddr *) (& (vio->remote)),
- &addrLen) != 0)
- {
- DBUG_PRINT("exit", ("getpeername, error: %d", errno));
- DBUG_RETURN(1);
- }
- my_inet_ntoa(vio->remote.sin_addr,buf);
- }
- DBUG_PRINT("exit", ("addr=%s", buf));
- DBUG_RETURN(0);
-}
-
-
-void vio_in_addr(Vio *vio, struct in_addr *in)
-{
- DBUG_ENTER("vio_in_addr");
- if (vio->localhost)
- bzero((char*) in, sizeof(*in)); /* This should never be executed */
- else
- *in=vio->remote.sin_addr;
- DBUG_VOID_RETURN;
-}
-
-#endif /* HAVE_VIO */
diff --git a/config.guess b/config.guess
index a3369c0f908..7c3ea484210 100755
--- a/config.guess
+++ b/config.guess
@@ -563,6 +563,15 @@ EOF
F301:UNIX_System_V:*:*)
echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'`
exit 0 ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ if test "${UNAME_MACHINE}" = "c86pc"; then
+ UNAME_MACHINE=pc
+ fi
+ echo `uname -p`-${UNAME_MACHINE}-nto-qnx
+ exit 0;;
+ *:QNX:*:*)
+ echo i386-pc-qnx
+ exit 0;;
hp3[0-9][05]:NetBSD:*:*)
echo m68k-hp-netbsd${UNAME_RELEASE}
exit 0 ;;
diff --git a/config.sub b/config.sub
index 70716b4e206..5f082e14a35 100755
--- a/config.sub
+++ b/config.sub
@@ -111,7 +111,7 @@ esac
# Here we must recognize all the valid KERNEL-OS combinations.
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
- linux-gnu*)
+ nto-qnx* | linux-gnu*)
os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
;;
@@ -636,6 +636,20 @@ case $basic_machine in
basic_machine=i960-intel
os=-nindy
;;
+ ntox86)
+ basic_machine=i386${os:--unknown}
+ os=-nto-qnx
+ ;;
+ nto*le | not*be)
+ basic_machine=${basic_machine%%be}
+ basic_machine=${basic_machine%%le}
+ basic_machine=${basic_machine##nto}${os:--unknown}
+ os=-nto-qnx
+ ;;
+ nto*)
+ basic_machine=${basic_machine##nto}${os:--unknown}
+ os=-nto-qnx
+ ;;
mon960)
basic_machine=i960-intel
os=-mon960
diff --git a/configure.in b/configure.in
index b55f1f6f726..758e6bac450 100644
--- a/configure.in
+++ b/configure.in
@@ -4,13 +4,13 @@ dnl Process this file with autoconf to produce a configure script.
AC_INIT(sql/mysqld.cc)
AC_CANONICAL_SYSTEM
# The Docs Makefile.am parses this line!
-AM_INIT_AUTOMAKE(mysql, 3.23.50)
+AM_INIT_AUTOMAKE(mysql, 4.0.2-alpha)
AM_CONFIG_HEADER(config.h)
PROTOCOL_VERSION=10
DOT_FRM_VERSION=6
# See the libtool docs for information on how to do shared lib versions.
-SHARED_LIB_VERSION=10:0:0
+SHARED_LIB_VERSION=11:0:0
# 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
@@ -453,7 +453,6 @@ fi
NOINST_LDFLAGS=
-
AC_ARG_WITH(other-libc,
[ --with-other-libc=/path/to/other/libc/dir Link against libc and other standard libraries installed in the specified non-standard location overriding default. Originally added to be able to link against glibc 2.2 without making the user upgrade the standard libc installation ],
[
@@ -639,7 +638,6 @@ AC_ARG_ENABLE(local-infile,
[ ENABLED_LOCAL_INFILE=$enableval ],
[ ENABLED_LOCAL_INFILE=no ]
)
-
if test "$ENABLED_LOCAL_INFILE" = "yes"
then
AC_MSG_RESULT([yes])
@@ -767,7 +765,46 @@ int main()
if test -z "$atom_ops"; then atom_ops="no"; fi
AC_MSG_RESULT($atom_ops)
+
+ AC_ARG_WITH(pstack,
+ [ --with-pstack Use the pstack backtrace library],
+ [ USE_PSTACK=$withval ],
+ [ USE_PSTACK=no ])
+ pstack_libs=
+ pstack_dirs=
+ if test "$USE_PSTACK" = yes -a "$IS_LINUX" = "true" -a "$BASE_MACHINE_TYPE" = "i386" -a "$with_mit_threads" = "no"
+ then
+ have_libiberty= have_libbfd=
+ my_save_LIBS="$LIBS"
+dnl I have no idea if this is a good test - can not find docs for libiberty
+ AC_CHECK_LIB([iberty], [fdmatch],
+ [have_libiberty=yes
+ AC_CHECK_LIB([bfd], [bfd_openr], [have_libbfd=yes], , [-liberty])])
+ LIBS="$my_save_LIBS"
+
+ if test x"$have_libiberty" = xyes -a x"$have_libbfd" = xyes
+ then
+ pstack_dirs='$(top_srcdir)'/pstack
+ pstack_libs="../pstack/libpstack.a -lbfd -liberty"
+ # We must link staticly when using pstack
+ with_mysqld_ldflags="-all-static"
+ AC_SUBST([pstack_dirs])
+ AC_SUBST([pstack_libs])
+ AC_DEFINE([USE_PSTACK])
+dnl This check isn't needed, but might be nice to give some feedback....
+dnl AC_CHECK_HEADER(libiberty.h,
+dnl have_libiberty_h=yes,
+dnl have_libiberty_h=no)
+ else
+ USE_PSTACK="no"
+ fi
+ else
+ USE_PSTACK="no"
+ fi
fi
+AM_CONDITIONAL(COMPILE_PSTACK, test "$USE_PSTACK" = "yes")
+AC_MSG_CHECKING([if we should use pstack])
+AC_MSG_RESULT([$USE_PSTACK])
# Check for gtty if termio.h doesn't exists
if test "$ac_cv_header_termio_h" = "no" -a "$ac_cv_header_termios_h" = "no"
@@ -949,7 +986,7 @@ then
AC_TRY_COMPILE([#include <sched.h>], [int a = sched_get_priority_min(1);], ,
AC_MSG_ERROR([Syntax error in sched.h. Change _P to __P in the /usr/include/sched.h file. See the Installation chapter in the Reference Manual]))
# RedHat 5.0 does not work with dynamic linking of this. -static also
- # gives a spped increase in linux so it does not hurt on other systems.
+ # gives a speed increase in linux so it does not hurt on other systems.
with_named_thread="-lpthread"
else
AC_MSG_RESULT("Not found")
@@ -965,7 +1002,8 @@ Reference Manual.])
if test -f /usr/shlib/libpthread.so -a -f /usr/lib/libmach.a -a -f /usr/ccs/lib/cmplrs/cc/libexc.a
then
with_named_thread="-lpthread -lmach -lexc"
- #with_named_thread="-lpthread -lmach -lexc -lc"
+ CFLAGS="$CFLAGS -D_REENTRANT"
+ CXXFLAGS="$CXXFLAGS -D_REENTRANT"
AC_DEFINE(HAVE_DEC_THREADS)
AC_MSG_RESULT("yes")
else
@@ -1192,11 +1230,14 @@ then
fi
fi
+TOOLS_LIBS="$NON_THREADED_CLIENT_LIBS"
+
# Should we use named pthread library ?
AC_MSG_CHECKING("named thread libs:")
if test "$with_named_thread" != "no"
then
LIBS="$with_named_thread $LIBS $with_named_thread"
+ TOOLS_LIBS="$with_named_thread $TOOLS_LIBS $with_named_thread"
with_posix_threads="yes"
with_mit_threads="no"
AC_MSG_RESULT("$with_named_thread")
@@ -1215,7 +1256,9 @@ else
then
AC_MSG_CHECKING("for pthread_create in -lpthread");
ac_save_LIBS="$LIBS"
+ ac_save_TOOLS_LIBS="$TOOLS_LIBS"
LIBS="$LIBS -lpthread"
+ TOOLS_LIBS="$TOOLS_LIBS -lpthread"
AC_TRY_LINK(
[#include <pthread.h>],
[ (void) pthread_create((pthread_t*) 0,(pthread_attr_t*) 0, 0, 0); ],
@@ -1224,6 +1267,7 @@ else
if test "$with_posix_threads" = "no"
then
LIBS=" $ac_save_LIBS -lpthreads"
+ TOOLS_LIBS=" $ac_save_TOOLS_LIBS -lpthreads"
AC_MSG_CHECKING("for pthread_create in -lpthreads");
AC_TRY_LINK(
[#include <pthread.h>],
@@ -1234,6 +1278,7 @@ else
then
# This is for FreeBSD
LIBS="$ac_save_LIBS -pthread"
+ TOOLS_LIBS="$ac_save_TOOLS_LIBS -pthread"
AC_MSG_CHECKING("for pthread_create in -pthread");
AC_TRY_LINK(
[#include <pthread.h>],
@@ -1244,6 +1289,7 @@ else
then
with_mit_threads="yes"
LIBS="$ac_save_LIBS"
+ TOOLS_LIBS="$ac_save_TOOLS_LIBS"
fi
fi
fi
@@ -1774,6 +1820,48 @@ AC_ARG_WITH(server,
[with_server=yes]
)
+AC_ARG_WITH(embedded-server,
+ [ --with-embedded-server Build the embedded server (libmysqld).],
+ [with_embedded_server=$withval],
+ [with_embedded_server=no]
+)
+
+AC_ARG_WITH(extra-tools,
+ [ --without-extra-tools Skip building utilites in the tools directory.],
+ [with_tools=$withval],
+ [with_tools=yes]
+)
+
+tools_dirs=""
+if test "$with_tools" = "yes"
+then
+ if test "$THREAD_SAFE_CLIENT" = "no"
+ then
+ echo "Warning: extra-tools disabled because --enable-thread-safe-client wasn't used"
+ else
+ tools_dirs="tools"
+ fi
+fi
+AC_SUBST(tools_dirs)
+
+#MYSQL_CHECK_CPU
+MYSQL_CHECK_MYSQLFS
+MYSQL_CHECK_VIO
+MYSQL_CHECK_OPENSSL
+
+libmysqld_dirs=
+if test "$with_embedded_server" = "yes"
+then
+ libmysqld_dirs=libmysqld
+ # We can't build embedded library without building the server, because
+ # we depend on libmysys, libmystrings, libmyisam, etc.
+ with_server=yes
+fi
+# XXX: We need to add @libmysqld_extra_libs@ (or whatever) so that
+# mysql_config --libmysqld-libs will print out something like
+# -L/path/to/lib/mysql -lmysqld -lmyisam -lmysys -lmystrings -ldbug ...
+AC_SUBST([libmysqld_dirs])
+
# Shall we build the docs?
AC_ARG_WITH(docs,
[ --without-docs Skip building of the documentation.],
@@ -1830,17 +1918,17 @@ 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)
-CHARSETS_AVAILABLE="big5 cp1251 cp1257 croat czech danish dec8 dos estonia euc_kr gb2312 gbk german1 greek hebrew hp8 hungarian koi8_ru koi8_ukr latin1 latin2 latin5 swe7 usa7 win1250 win1251 win1251ukr ujis sjis tis620"
+CHARSETS_AVAILABLE="big5 cp1251 cp1257
+ croat czech danish dec8 dos estonia euc_kr gb2312 gbk
+ german1 greek hebrew hp8 hungarian koi8_ru koi8_ukr
+ latin1 latin1_de latin2 latin5 sjis swe7 tis620 ujis
+ usa7 win1250 win1251ukr"
+CHARSETS_DEPRECATED="win1251"
DEFAULT_CHARSET=latin1
AC_DIVERT_POP
-dnl win1251 is deprecated - it's available, but not listed here in the help
AC_ARG_WITH(charset,
- [ --with-charset=CHARSET Use CHARSET by default (one of: big5 cp1251 cp1257
- croat czech danish dec8 dos estonia euc_kr gb2312 gbk
- german1 greek hebrew hp8 hungarian koi8_ru koi8_ukr
- latin1 latin2 latin5 swe7 usa7 win1250 win1251ukr
- ujis sjis tis620; Default is latin1)],
+ [ --with-charset=CHARSET Use CHARSET by default (one of: $CHARSETS_AVAILABLE; Default is $DEFAULT_CHARSET)],
[default_charset="$withval"],
[default_charset="$DEFAULT_CHARSET"])
@@ -1861,7 +1949,7 @@ elif test "$extra_charsets" = complex; then
CHARSETS=`echo $CHARSETS` # get rid of line breaks
else
if test "$extra_charsets" = all; then
- CHARSETS="$CHARSETS_AVAILABLE"
+ CHARSETS="$CHARSETS_AVAILABLE $CHARSETS_DEPRECATED"
else
CHARSETS=`echo $extra_charsets | sed -e 's/,/ /g'`
fi
@@ -1882,7 +1970,7 @@ CHARSETS=$TMP_CHARSETS
for cs in $CHARSETS
do
charset_okay=0
- for charset in $CHARSETS_AVAILABLE
+ for charset in $CHARSETS_AVAILABLE $CHARSETS_DEPRECATED
do
if test $cs = $charset; then charset_okay=1; fi
done
@@ -2062,9 +2150,9 @@ EOF
AC_MSG_RESULT([default: $default_charset; compiled in: $CHARSETS])
+MYSQL_CHECK_ISAM
MYSQL_CHECK_BDB
MYSQL_CHECK_INNODB
-MYSQL_CHECK_GEMINI
# If we have threads generate some library functions and test programs
sql_server_dirs=
@@ -2095,21 +2183,28 @@ AC_SUBST(linked_client_targets)
if test "$with_server" = "yes" -o "$THREAD_SAFE_CLIENT" != "no"
then
AC_DEFINE(THREAD)
-fi
-
-if test "$with_server" = "yes"
-then
# Avoid _PROGRAMS names
THREAD_LPROGRAMS="test_thr_alarm test_thr_lock"
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)
- sql_server_dirs="strings dbug mysys extra regex isam merge myisam myisammrg heap sql"
- server_scripts="safe_mysqld mysql_install_db"
+ server_scripts="mysqld_safe mysql_install_db"
+ sql_server_dirs="strings dbug mysys extra regex"
+
+
+ #
+ # Configuration for optional table handlers
+ #
+
+ if test X"$have_isam" != Xno
+ then
+ sql_server_dirs="$sql_server_dirs isam merge"
+ fi
+
if test X"$have_berkeley_db" != Xno; then
if test X"$have_berkeley_db" != Xyes; then
# we must build berkeley db from source
- sql_server_dirs="$have_berkeley_db $sql_server_dirs"
+ sql_server_dirs="$sql_server_dirs $have_berkeley_db"
echo "CONFIGURING FOR BERKELEY DB"
bdb_conf_flags=
@@ -2176,7 +2271,7 @@ EOF
if test X"$have_innodb" = Xyes
then
- sql_server_dirs="innobase $sql_server_dirs"
+ sql_server_dirs="$sql_server_dirs innobase"
echo "CONFIGURING FOR INNODB"
if test ! -d "innobase"; then
# This should only happen when doing a VPATH build
@@ -2193,21 +2288,11 @@ EOF
echo "END OF INNODB CONFIGURATION"
fi
+ #
+ # END of configuration for optional table handlers
+ #
+ sql_server_dirs="$sql_server_dirs myisam myisammrg heap vio sql"
- if test "X$have_gemini_db" = "Xyes"; then
- sql_server_dirs="gemini $sql_server_dirs"
- echo "CONFIGURING FOR GEMINI DB"
- (cd gemini && sh ./configure) \
- || AC_MSG_ERROR([could not configure Gemini DB])
-
- echo "END OF GEMINI DB CONFIGURATION"
-
- AC_DEFINE(HAVE_GEMINI_DB)
- fi
-fi
-
-if test "$with_server" = "yes" -o "$THREAD_SAFE_CLIENT" != "no"
-then
if test "$with_posix_threads" = "no" -o "$with_mit_threads" = "yes"
then
# MIT user level threads
@@ -2255,17 +2340,20 @@ AC_SUBST(server_scripts)
# Some usefull subst
AC_SUBST(CC)
AC_SUBST(GXX)
+#Remove TOOLS_LIBS, because this is included in LIBRARIES
+#AC_SUBST(TOOLS_LIBS)
# Output results
AC_OUTPUT(Makefile extra/Makefile mysys/Makefile isam/Makefile \
strings/Makefile regex/Makefile heap/Makefile \
bdb/Makefile \
myisam/Makefile myisammrg/Makefile \
- man/Makefile \
- readline/Makefile libmysql_r/Makefile libmysql/Makefile client/Makefile \
- sql/Makefile sql/share/Makefile \
+ man/Makefile BUILD/Makefile readline/Makefile vio/Makefile \
+ libmysql_r/Makefile libmysqld/Makefile libmysqld/examples/Makefile \
+ libmysql/Makefile client/Makefile \
+ pstack/Makefile pstack/aout/Makefile sql/Makefile sql/share/Makefile \
merge/Makefile dbug/Makefile scripts/Makefile \
- include/Makefile sql-bench/Makefile \
+ include/Makefile sql-bench/Makefile tools/Makefile \
tests/Makefile Docs/Makefile support-files/Makefile \
mysql-test/Makefile \
include/mysql_version.h
diff --git a/dbug/dbug.c b/dbug/dbug.c
index cfe4ca161c6..9e1e51d2404 100644
--- a/dbug/dbug.c
+++ b/dbug/dbug.c
@@ -69,7 +69,7 @@
#ifdef DBUG_OFF
#undef DBUG_OFF
#endif
-#include <global.h>
+#include <my_global.h>
#include <m_string.h>
#include <errno.h>
#if defined(MSDOS) || defined(__WIN__)
@@ -1928,7 +1928,7 @@ static void dbug_flush(CODE_STATE *state)
{
if (!(freopen(stack->name,"a",_db_fp_)))
{
- (void) fprintf(stderr, ERR_OPEN, _db_process_);
+ (void) fprintf(stderr, ERR_OPEN, _db_process_, stack->name);
fflush(stderr);
_db_fp_ = stdout;
stack -> out_file = _db_fp_;
diff --git a/dbug/dbug_analyze.c b/dbug/dbug_analyze.c
index bcee5230527..de228c64aa5 100644
--- a/dbug/dbug_analyze.c
+++ b/dbug/dbug_analyze.c
@@ -49,7 +49,7 @@
* if invoked with -v flag.
*/
-#include <global.h>
+#include <my_global.h>
#include <m_string.h>
static char *my_name;
diff --git a/dbug/example1.c b/dbug/example1.c
index 932e269cc4c..e468f065796 100644
--- a/dbug/example1.c
+++ b/dbug/example1.c
@@ -1,5 +1,5 @@
-#include <global.h>
+#include <my_global.h>
main (argc, argv)
int argc;
diff --git a/dbug/example2.c b/dbug/example2.c
index 482691a8a74..5e5f14f0e7e 100644
--- a/dbug/example2.c
+++ b/dbug/example2.c
@@ -1,5 +1,5 @@
-#include <global.h>
+#include <my_global.h>
int debug = 0;
diff --git a/dbug/example3.c b/dbug/example3.c
index b504edf2e61..f177c07425d 100644
--- a/dbug/example3.c
+++ b/dbug/example3.c
@@ -1,5 +1,5 @@
-#include <global.h>
+#include <my_global.h>
main (argc, argv)
int argc;
diff --git a/dbug/factorial.c b/dbug/factorial.c
index 0dda5c7459e..56197aef29e 100644
--- a/dbug/factorial.c
+++ b/dbug/factorial.c
@@ -2,7 +2,7 @@
#undef DBUG_OFF
#endif
-#include <global.h>
+#include <my_global.h>
int factorial (
register int value)
diff --git a/dbug/main.c b/dbug/main.c
index 863b4d319c2..da56c00feb3 100644
--- a/dbug/main.c
+++ b/dbug/main.c
@@ -2,7 +2,7 @@
#undef DBUG_OFF
#endif
-#include <global.h> /* This includes dbug.h */
+#include <my_global.h> /* This includes dbug.h */
int main (argc, argv)
int argc;
diff --git a/dbug/sanity.c b/dbug/sanity.c
index d287a468028..df43fc14ba9 100644
--- a/dbug/sanity.c
+++ b/dbug/sanity.c
@@ -1,6 +1,6 @@
/* Declarate _sanity() if not declared in main program */
-#include <global.h>
+#include <my_global.h>
extern int _sanity(const char *file,uint line);
diff --git a/div/deadlock_test.c b/div/deadlock_test.c
index be6d940cf1b..65a0df5c215 100644
--- a/div/deadlock_test.c
+++ b/div/deadlock_test.c
@@ -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 */
@@ -126,7 +126,7 @@ static void permute_aux(int *order, int num_queries, int* fixed)
}
/*printf("num_free = %d\n", num_free); */
-
+
if(num_free <= 1)
{
count++;
@@ -156,7 +156,7 @@ static void run_query_batch(int* order, int num_queries)
dump_result(q->mysql, q->query);
}
printf("\n");
-
+
}
static void safe_net_read(NET* net, char* query)
@@ -167,8 +167,8 @@ static void safe_net_read(NET* net, char* query)
die("Error running query '%s'", query);
if(net->read_pos[0] == 255)
die("Error running query '%s'", query);
-}
-
+}
+
static void safe_query(MYSQL* mysql, char* query, int read_ok)
{
@@ -230,7 +230,7 @@ int main()
permute(order, num_queries);
printf("count = %d\n", count);
-
+
mysql_close(&lock);
mysql_close(&sel);
mysql_close(&del_ins);
diff --git a/extra/Makefile.am b/extra/Makefile.am
index ee6c2ba92f2..25633a386e2 100644
--- a/extra/Makefile.am
+++ b/extra/Makefile.am
@@ -18,7 +18,7 @@ INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include -I../include -I..
LDADD = @CLIENT_EXTRA_LDFLAGS@ ../mysys/libmysys.a \
../dbug/libdbug.a ../strings/libmystrings.a
bin_PROGRAMS = replace comp_err perror resolveip my_print_defaults \
-resolve_stack_dump
+resolve_stack_dump mysql_install
OMIT_DEPENDENCIES = pthread.h stdio.h __stdio.h stdlib.h __stdlib.h math.h\
__math.h time.h __time.h unistd.h __unistd.h types.h \
diff --git a/extra/comp_err.c b/extra/comp_err.c
index f7b68ff0891..806fb5052b4 100644
--- a/extra/comp_err.c
+++ b/extra/comp_err.c
@@ -1,23 +1,22 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ 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 */
-#include <global.h>
+#include <my_global.h>
#include <m_ctype.h>
#include <my_sys.h>
#include <m_string.h>
diff --git a/extra/my_print_defaults.c b/extra/my_print_defaults.c
index 316d91ef7b3..70ccb3797e6 100644
--- a/extra/my_print_defaults.c
+++ b/extra/my_print_defaults.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
** print_default.c:
@@ -22,7 +21,7 @@
** Written by Monty
*/
-#include <global.h>
+#include <my_global.h>
#include <my_sys.h>
#include <getopt.h>
@@ -59,7 +58,7 @@ static void usage(my_bool version)
-?, --help Display this help message and exit.\n\
-V, --version Output version information and exit.\n",
config_file);
- printf("\nExample usage: %s --config-file=my client mysql\n",my_progname);
+ printf("\nExample usage:\n%s --config-file=my client mysql\n",my_progname);
}
static int get_options(int *argc,char ***argv)
diff --git a/extra/mysql_install.c b/extra/mysql_install.c
index dfd71895647..1fa62f35b7e 100644
--- a/extra/mysql_install.c
+++ b/extra/mysql_install.c
@@ -21,7 +21,7 @@
#define INSTALL_VERSION "1.0"
#define DONT_USE_RAID
-#include <global.h>
+#include <my_global.h>
#include <m_ctype.h>
#include <my_sys.h>
#include <m_string.h>
@@ -29,13 +29,195 @@
#include <errno.h>
#include <getopt.h>
+#define ANSWERS_CHUNCK 32
+
+int have_gui=0;
+
struct option long_options[] =
{
- {"help", no_argument, 0, 'h'},
+ {"help", no_argument, 0, '?'},
{"version", no_argument, 0, 'V'},
{0, 0,0,0}
};
+/* For now, not much exciting here, but we'll add more once
+ we add GUI support
+ */
+typedef struct
+{
+ FILE* out;
+ FILE* in;
+ const char* question;
+ int default_ind;
+ DYNAMIC_ARRAY answers;
+} QUESTION_WIDGET;
+
+static void usage();
+static void die(const char* fmt, ...);
+static void print_version(void);
+static char get_answer_char(int ans_ind);
+static int ask_user(const char* question,int default_ind, ...);
+static void add_answer(QUESTION_WIDGET* w, const char* ans);
+static void display_question(QUESTION_WIDGET* w);
+static int init_question_widget(QUESTION_WIDGET* w, const char* question,
+ int default_ind);
+static void end_question_widget(QUESTION_WIDGET* w);
+static int get_answer(QUESTION_WIDGET* w);
+static char answer_from_char(char c);
+static void invalid_answer(QUESTION_WIDGET* w);
+
+enum {IMODE_STANDARD=0,IMODE_CUSTOM,IMODE_UPGRAGE} install_mode
+ = IMODE_STANDARD;
+
+static char get_answer_char(int ans_ind)
+{
+ return 'a' + ans_ind;
+}
+
+static void invalid_answer(QUESTION_WIDGET* w)
+{
+ if (!have_gui)
+ {
+ fprintf(w->out, "ERROR: invalid answer, try again...\a\n");
+ }
+}
+
+static char answer_from_char(char c)
+{
+ return c - 'a';
+}
+
+static void die(const char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ fprintf(stderr, "%s: ", my_progname);
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+ va_end(args);
+ exit(1);
+}
+
+static void display_question(QUESTION_WIDGET* w)
+{
+ if (!have_gui)
+ {
+ uint i,num_answers=w->answers.elements;
+ DYNAMIC_ARRAY* answers = &w->answers;
+ fprintf(w->out,"\n%s\n\n",w->question);
+
+ for (i=0; i<num_answers; i++)
+ {
+ char* ans;
+ get_dynamic(answers,(gptr)&ans,i);
+ fprintf(w->out,"%c - %s\n",get_answer_char(i),ans);
+ }
+ fprintf(w->out,"q - Abort Install/Upgrade\n\n");
+ }
+}
+
+static void add_answer(QUESTION_WIDGET* w, const char* ans)
+{
+ insert_dynamic(&w->answers,(gptr)&ans);
+}
+
+static int init_question_widget(QUESTION_WIDGET* w, const char* question,
+ int default_ind)
+{
+ if (have_gui)
+ {
+ w->in = w->out = 0;
+ }
+ else
+ {
+ w->out = stdout;
+ w->in = stdin;
+ }
+ w->question = question;
+ w->default_ind = default_ind;
+ if (init_dynamic_array(&w->answers,sizeof(char*),
+ ANSWERS_CHUNCK,ANSWERS_CHUNCK))
+ die("Out of memory");
+ return 0;
+}
+
+static void end_question_widget(QUESTION_WIDGET* w)
+{
+ delete_dynamic(&w->answers);
+}
+
+static int get_answer(QUESTION_WIDGET* w)
+{
+ if (!have_gui)
+ {
+ char buf[32];
+ int ind;
+ char c;
+ if (!fgets(buf,sizeof(buf),w->in))
+ die("Failed fgets on input stream");
+ switch ((c=tolower(*buf)))
+ {
+ case '\n':
+ return w->default_ind;
+ case 'q':
+ die("Install/Upgrade aborted");
+ default:
+ ind = answer_from_char(c);
+ if (ind >= 0 && ind < (int)w->answers.elements)
+ return ind;
+ }
+ }
+ return -1;
+}
+
+static int ask_user(const char* question,int default_ind, ...)
+{
+ va_list args;
+ char* opt;
+ QUESTION_WIDGET w;
+ int ans;
+
+ va_start(args,default_ind);
+ init_question_widget(&w,question,default_ind);
+ for (;(opt=va_arg(args,char*));)
+ {
+ add_answer(&w,opt);
+ }
+ for (;;)
+ {
+ display_question(&w);
+ if ((ans = get_answer(&w)) >= 0)
+ break;
+ invalid_answer(&w);
+ }
+ end_question_widget(&w);
+ va_end(args);
+ return ans;
+}
+
+static int parse_args(int argc, char **argv)
+{
+ int c, option_index = 0;
+
+ while((c = getopt_long(argc, argv, "?V",
+ long_options, &option_index)) != EOF)
+ {
+ switch(c)
+ {
+ case 'V':
+ print_version();
+ exit(0);
+ case '?':
+ usage();
+ exit(0);
+ default:
+ usage();
+ exit(1);
+ }
+ }
+ return 0;
+}
+
static void print_version(void)
{
printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,INSTALL_VERSION,
@@ -55,6 +237,16 @@ static void usage()
-V, --version Output version information and exit.\n");
}
+int main(int argc, char** argv)
+{
+ MY_INIT(argv[0]);
+ parse_args(argc,argv);
+ install_mode = ask_user("Please select install/upgrade mode",
+ install_mode, "Standard Install",
+ "Custom Install", "Upgrade",0);
+ printf("mode=%d\n", install_mode);
+ return 0;
+}
diff --git a/extra/perror.c b/extra/perror.c
index 6cb86eedf27..aa4ee71c7d1 100644
--- a/extra/perror.c
+++ b/extra/perror.c
@@ -1,25 +1,24 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Return error-text for system error messages and nisam messages */
#define PERROR_VERSION "2.7"
-#include <global.h>
+#include <my_global.h>
#include <my_sys.h>
#include <m_string.h>
#include <errno.h>
@@ -111,7 +110,7 @@ static void usage(void)
-s, --silent Only print the error message\n\
-v, --verbose Print error code and message (default).\n\
-V, --version Displays version information and exits.\n");
-}
+}
static int get_options(int *argc,char ***argv)
@@ -231,4 +230,3 @@ int main(int argc,char *argv[])
exit(error);
return error;
}
-
diff --git a/extra/replace.c b/extra/replace.c
index ef3abda5cc5..41312f5e3d4 100644
--- a/extra/replace.c
+++ b/extra/replace.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Replace strings in textfile
This program replace strings in a file or on stdin/stdout.
@@ -38,7 +37,7 @@
*/
#define DONT_USE_RAID
-#include <global.h>
+#include <my_global.h>
#include <m_ctype.h>
#include <my_sys.h>
#include <m_string.h>
diff --git a/extra/resolve_stack_dump.c b/extra/resolve_stack_dump.c
index fbb5ad5e378..6c2ddf66027 100644
--- a/extra/resolve_stack_dump.c
+++ b/extra/resolve_stack_dump.c
@@ -1,26 +1,25 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Resolve numeric stack dump produced by mysqld 3.23.30 and later
versions into symbolic names. By Sasha Pachev <sasha@mysql.com>
*/
#define DONT_USE_RAID
-#include <global.h>
+#include <my_global.h>
#include <m_ctype.h>
#include <my_sys.h>
#include <m_string.h>
@@ -163,7 +162,7 @@ static void open_files()
{
fp_out = stdout;
fp_dump = stdin;
-
+
if(dump_fname && !(fp_dump = my_fopen(dump_fname, O_RDONLY, MYF(MY_WME))))
die("Could not open %s", dump_fname);
/* if name not given, assume stdin*/
@@ -173,7 +172,7 @@ static void open_files()
trace dump and specify the path to it with -s or --symbols-file");
if(!(fp_sym = my_fopen(sym_fname, O_RDONLY, MYF(MY_WME))))
die("Could not open %s", sym_fname);
-
+
}
static uchar hex_val(char c)
@@ -192,10 +191,10 @@ static my_long_addr_t read_addr(char** buf)
uchar c;
char* p = *buf;
my_long_addr_t addr = 0;
-
+
while((c = hex_val(*p++)) != HEX_INVALID)
addr = (addr << 4) + c;
-
+
*buf = p;
return addr;
}
@@ -209,7 +208,7 @@ static int init_sym_entry(SYM_ENTRY* se, char* buf)
return -1;
while(isspace(*buf++))
/* empty */;
-
+
while(isspace(*buf++))
/* empty - skip more space */;
--buf;
@@ -256,7 +255,7 @@ static void verify_sort()
{
uint i;
uchar* last = 0;
-
+
for(i = 0; i < sym_table.elements; i++)
{
SYM_ENTRY se;
@@ -274,7 +273,7 @@ static SYM_ENTRY* resolve_addr(uchar* addr, SYM_ENTRY* se)
get_dynamic(&sym_table, (gptr)se, 0);
if(addr < se->addr)
return 0;
-
+
for(i = 1; i < sym_table.elements; i++)
{
get_dynamic(&sym_table, (gptr)se, i);
@@ -297,7 +296,7 @@ static void do_resolve()
while(isspace(*p))
++p;
/* skip space */;
-
+
if(*p++ == '0' && *p++ == 'x')
{
SYM_ENTRY se ;
@@ -307,7 +306,7 @@ static void do_resolve()
(int) (addr - se.addr));
else
fprintf(fp_out, "%p (?)\n", addr);
-
+
}
else
{
@@ -327,4 +326,3 @@ int main(int argc, char** argv)
clean_up();
return 0;
}
-
diff --git a/fs/CorbaFS.idl b/fs/CorbaFS.idl
new file mode 100644
index 00000000000..8fe089bd13c
--- /dev/null
+++ b/fs/CorbaFS.idl
@@ -0,0 +1,38 @@
+// -----------------------------------------------------------------------------
+// CorbaDS Module - Implement Kernel functionality in korbit
+// -----------------------------------------------------------------------------
+//
+// Main source of information:
+// http://www.cse.unsw.edu.au/~neilb/oss/linux-commentary/vfs.html
+//
+module CorbaFS {
+
+ struct dirent
+ {
+ long inode; // inode number
+ string name; // file name (null-terminated)
+ };
+
+ typedef sequence<dirent> DirEntSeq;
+ typedef sequence<octet> Buffer;
+
+ interface Inode {
+ void getStatus(out unsigned short mode, out unsigned long uid, out unsigned long gid,
+ out unsigned long size, out unsigned long inodeNum, out unsigned short numLinks,
+ out long atime, out long mtime, out long ctime);
+ void readpage(out Buffer buffer, in long size, in long offset);
+ void release();
+ };
+
+ interface FileSystem {
+ Inode getInode(in string path);
+
+ // DirectoryInode getStatus implementation must have S_IFDIR in the S_IFMT
+ // field of the mode value.
+ DirEntSeq readdir(in string path);
+
+ // SymlinkInode getStatus implementation must have S_IFLNK in the S_IFMT
+ // field of the mode value.
+ string readlink(in string filename);
+ };
+};
diff --git a/fs/Makefile.am b/fs/Makefile.am
new file mode 100644
index 00000000000..33d1acd913d
--- /dev/null
+++ b/fs/Makefile.am
@@ -0,0 +1,93 @@
+# 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
+
+#called from the top level Makefile
+
+CFLAGS = $(ORBIT_CFLAGS) -g
+LFLAGS = $(ORBIT_LIBS)
+orbit_idl = @orbit_idl@
+orbit_includes = @orbit_includes@
+orbit_libs = @orbit_libs@
+
+DISTCLEANFILES = CorbaFS-common.* CorbaFS-stubs.* CorbaFS-skels.* CorbaFS.h
+
+MYSQLDATAdir = $(localstatedir)
+MYSQLSHAREdir = $(pkgdatadir)
+MYSQLBASEdir= $(prefix)
+INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include \
+ -I$(srcdir)/../regex \
+ -I$(srcdir) -I../include -I.. -I. \
+ -I$(srcdir) -I../include -I.. -I. \
+ $(orbit_includes)
+WRAPLIBS= @WRAPLIBS@
+libexec_PROGRAMS = mysqlcorbafsd
+noinst_PROGRAMS =mysqlfs_test
+LDADD = ../libmysql/libmysqlclient.la $(orbit_libs)
+mysqlcorbafsd_LDADD = $(LDADD) $(CXXLDFLAGS)
+noinst_HEADERS =
+mysqlfs_test_SOURCES = mysqlcorbafs_test.c CorbaFS-common.c CorbaFS-stubs.c libmysqlfs.c
+mysqlcorbafsd_SOURCES = mysqlcorbafs.c CorbaFS-skels.c database.c CorbaFS-common.c libmysqlfs.c
+
+DEFS = -DMYSQL_SERVER \
+ -DDEFAULT_MYSQL_HOME="\"$(MYSQLBASEdir)\"" \
+ -DDATADIR="\"$(MYSQLDATAdir)\"" \
+ -DSHAREDIR="\"$(MYSQLSHAREdir)\"" \
+ @DEFS@
+# Don't put lex_hash.h in BUILT_SOURCES as this will give infinite recursion
+BUILT_SOURCES = CorbaFS-common.c CorbaFS-stubs.c CorbaFS-skels.c CorbaFS.h
+EXTRA_DIST = $(BUILT_SOURCES)
+#YFLAGS = -d
+
+OMIT_DEPENDENCIES = pthread.h stdio.h __stdio.h stdlib.h __stdlib.h math.h\
+ __math.h time.h __time.h unistd.h __unistd.h types.h \
+ xtypes.h ac-types.h posix.h string.h __string.h \
+ errno.h socket.h inet.h dirent.h netdb.h \
+ cleanup.h cond.h debug_out.h fd.h kernel.h mutex.h \
+ prio_queue.h pthread_attr.h pthread_once.h queue.h\
+ sleep.h specific.h version.h pwd.h timers.h uio.h \
+ cdefs.h machdep.h signal.h __signal.h util.h lex.h \
+ wait.h
+
+link_sources:
+ rm -f mini_client_errors.c
+ @LN_CP_F@ ../libmysql/errmsg.c mini_client_errors.c
+
+
+# Don't update the files from bitkeeper
+%::SCCS/s.%
+
+idltargets : CorbaFS.idl
+ $(ORBIT_IDL) CorbaFS.idl
+ $(orbit_idl) CorbaFS.idl
+
+# individual rules
+
+CorbaFS-stubs.c : CorbaFS.idl
+ $(orbit_idl) CorbaFS.idl
+
+CorbaFS-common.c : CorbaFS.idl
+ $(orbit_idl) CorbaFS.idl
+
+CorbaFS-skels.c : CorbaFS.idl
+ $(orbit_idl) CorbaFS.idl
+
+#CorbaFS-client.c : CorbaFS.h
+
+#CorbaFS-server.c : CorbaFS.h
+
+CorbaFS.h : CorbaFS.idl
+ $(orbit_idl) CorbaFS.idl
+
diff --git a/fs/README b/fs/README
new file mode 100644
index 00000000000..5d86da3a7e4
--- /dev/null
+++ b/fs/README
@@ -0,0 +1,58 @@
+MySQL Filesystem
+Tõnu Samuel - tonu@mysql.com
+Some additional information is available on http://no.spam.ee/~tonu/mysqlfs.html
+
+WARNING: Experimental code and known to crash computer.
+
+Instructions, how to get this stuff working:
+1. Make sure you have ORBit, includeing development libraries installed. They should be version 0.5.3 or later.
+- I am lazy man and use default ones included with my RedHat:
+ [root@localhost /root]# rpm -qa | grep ORBit
+ ORBit-0.5.3-2
+ ORBit-devel-0.5.3-2
+ [root@localhost /root]#
+
+2. Prepare kernel to include korbit:
+- Get Linux 2.4.1 kernel source. (very possibly this patch works on 2.4.0 without modifications too)
+- unpack it
+- apply patch named "korbit-kernel-2.4.1-patch" on it.
+- make menuconfig
+- In section "Networking options":
+ ...
+ [*] Kernel ORB (EXPERIMENTAL)
+ ...
+ <M> CORBA User-space FileSystem (EXPERIMENTAL)
+ ...
+- make dep ; make bzlilo ; make modules ; make modules_install
+- reboot
+- Execute: insmod /lib/modules/$(uname -r)/kernel/net/korbit/modules/CorbaFS/client/corba-corbafs-client.o
+ You should see "gethostname() = localhost". Look at known bug 3 in the end of this doc.
+
+3. Make sure MySQL server is working on your system
+- On my RedHat 7.0 I execute "/etc/init.d/mysqld start"
+
+4. Prepare MySQL FS daemon
+- Get MySQL 4.0 from repository OR get MySQL FS source from http://no.spam.ee/~tonu/mysqlfs.html
+- unpack it. In MySQL 4.0 source this is located in directory named "fs". cd into it.
+- make
+- Execute command "./RunServer"
+
+5. mount MySQL server to disk tree
+- Execute command "mkdir /mnt/mysql"
+- Execute command "mount -t corbafs -o `cat /tmp/mysqlcorbafs.ior` none /mnt/mysql/"
+- Check you SQL server content by executing "ls -la /mnt/mysql/"
+
+Known bugs:
+
+1. User bugs. fix user ;)
+
+2. MySQL FS daemon will crash or will be stopped when cobrafs is mounted, then there is no way
+to unmount disks anymore. This is korbit business to handle such cases and I had no time to dig
+into korbit code.
+
+3. host name returned by gethostname() should be "localhost" or korbit will crash. Also "localhost"
+must be first string after 127.0.0.1 in /etc/hosts
+
+
+
+
diff --git a/fs/RunServer.sh b/fs/RunServer.sh
new file mode 100755
index 00000000000..22d152bb20b
--- /dev/null
+++ b/fs/RunServer.sh
@@ -0,0 +1,2 @@
+.libs/mysqlcorbafsd -ORBIIOPUSock=0 -ORBIIOPIPv4=1 --debug='d:t:o,~/mysqlfsd.trace' $*
+#.libs/mysqlcorbafsd -ORBIIOPUSock=0 -ORBIIOPIPv4=1 $*
diff --git a/fs/database.c b/fs/database.c
new file mode 100644
index 00000000000..4a328c41618
--- /dev/null
+++ b/fs/database.c
@@ -0,0 +1,628 @@
+/* Copyright (C) 2000 db AB & db 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
+ */
+
+/*
+ * Database functions
+ *
+ * Using these functions we emulate filesystem behaviour on top of SQL
+ * database.
+ * Written by Tõnu Samuel <tonu@please.do.not.remove.this.spam.ee>
+ *
+ * FIXME:
+ * - Direct handling of database handlers without SQL parsing overhead
+ * - connection pool
+ * - configurable function name/file name mappings
+ */
+
+
+#include "libmysqlfs.h"
+#include "mysqlcorbafs.h"
+#include <unistd.h>
+#include <string.h>
+#include <my_sys.h>
+
+DYNAMIC_ARRAY field_array;
+
+/*
+ * ** dbConnect -- connects to the host and selects DB.
+ * ** Also checks whether the tablename is a valid table name.
+ * */
+int db_connect(char *host, char *user,char *passwd)
+{
+ DBUG_ENTER("db_connect");
+ DBUG_PRINT("enter",("host: '%s', user: '%s', passwd: '%s'", host, user, passwd));
+
+ if (verbose)
+ {
+ fprintf(stderr, "# Connecting to %s...\n", host ? host : "localhost");
+ }
+ mysql_init(&connection);
+ if (opt_compress)
+ mysql_options(&connection,MYSQL_OPT_COMPRESS,NullS);
+#ifdef HAVE_OPENSSL
+ if (opt_use_ssl)
+ mysql_ssl_set(&connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
+ opt_ssl_capath);
+#endif
+ if (!(sock= mysql_real_connect(&connection,host,user,passwd,
+ NULL,opt_mysql_port,opt_mysql_unix_port,0)))
+ {
+ DBerror(&connection, "when trying to connect");
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+} /* dbConnect */
+
+
+/*
+ * ** dbDisconnect -- disconnects from the host.
+ * */
+void db_disconnect(char *host)
+{
+ DBUG_ENTER("db_disconnect");
+ DBUG_PRINT("enter",("host: '%s'", host));
+ if (verbose)
+ fprintf(stderr, "# Disconnecting from %s...\n", host ? host : "localhost");
+ mysql_close(sock);
+ DBUG_VOID_RETURN;
+} /* dbDisconnect */
+
+#define OUTPUT(x) strcpy(buffptr,x); buffptr+=strlen(x);
+#define OUTPUT_TOP(x) strcpy(topptr,x); topptr+=strlen(x);
+#define OUTPUT_MIDDLE(x) strcpy(midptr,x); midptr+=strlen(x);
+#define OUTPUT_BOTTOM(x) strcpy(botptr,x); botptr+=strlen(x);
+#define OUTPUT_HEADER(x) strcpy(hdrptr,x); hdrptr+=strlen(x);
+
+void db_show_result(MYSQL* sock, char *b, struct format *f)
+{
+ MYSQL_ROW row;
+ MYSQL_RES *result;
+ MYSQL_FIELD *field;
+ char *buffptr;
+ char topseparator[BUFLEN]="";
+ char middleseparator[BUFLEN]="";
+ char bottomseparator[BUFLEN]="";
+ char header[BUFLEN]="";
+ char *topptr=topseparator;
+ char *midptr=middleseparator;
+ char *botptr=bottomseparator;
+ char *hdrptr=header;
+ uint i,count, length;
+
+ DBUG_ENTER("db_show_result");
+ DBUG_PRINT("enter",("b: '%s', f '%x'", b, f));
+
+ result=mysql_store_result(sock);
+
+ buffptr=b;
+ OUTPUT(f->tablestart)
+
+ OUTPUT_TOP(f->leftuppercorner);
+ OUTPUT_MIDDLE(f->leftcross);
+ OUTPUT_BOTTOM(f->leftdowncorner);
+ OUTPUT_HEADER(f->headerrowstart);
+
+
+ count=mysql_num_fields(result);
+// while ((field = mysql_fetch_field(result)))
+ for(i=0 ; i < count ; ++i)
+ {
+ field = mysql_fetch_field(result);
+ length=(uint) strlen(field->name);
+ OUTPUT_HEADER(f->headercellstart);
+
+ length=max(length,field->max_length);
+ if (length < 4 && !IS_NOT_NULL(field->flags))
+ length=4; // Room for "NULL"
+ field->max_length=length;
+
+ memset(topptr,'=',field->max_length);
+ memset(midptr,'-',field->max_length);
+ memset(botptr,'=',field->max_length);
+
+ sprintf(hdrptr,"%-*s",field->max_length,field->name);
+ //num_flag[off]= IS_NUM(field->type);
+
+ topptr+=field->max_length;
+ midptr+=field->max_length;
+ botptr+=field->max_length;
+ hdrptr+=field->max_length;
+
+ if(i<count-1) {
+ OUTPUT_TOP(f->topcross);
+ OUTPUT_MIDDLE(f->middlecross);
+ OUTPUT_BOTTOM(f->bottomcross);
+ OUTPUT_HEADER(f->headercellseparator);
+ }
+ }
+ OUTPUT_TOP(f->rightuppercorner);
+ OUTPUT_MIDDLE(f->rightcross);
+ OUTPUT_BOTTOM(f->rightdowncorner);
+
+ OUTPUT_HEADER(f->headercellend);
+ OUTPUT_HEADER(f->headerrowend);
+
+ OUTPUT(topseparator);
+ OUTPUT(header);
+ OUTPUT(middleseparator);
+ while(row=mysql_fetch_row(result)) {
+ mysql_field_seek(result,0);
+
+ OUTPUT(f->contentrowstart);
+ for(i=0 ; i < mysql_field_count(sock); ++i) {
+ field = mysql_fetch_field(result);
+ OUTPUT(f->contentcellstart);
+ sprintf(buffptr,"%-*s",field->max_length,row[i]);
+ buffptr+=field->max_length;
+
+ if(i==mysql_field_count(sock))
+ {
+ OUTPUT(f->contentcellend);
+ } else {
+ OUTPUT(f->contentcellseparator);
+ }
+ }
+ OUTPUT(f->contentrowend);
+ }
+ OUTPUT(bottomseparator);
+ OUTPUT(f->tableend);
+
+ mysql_free_result(result);
+ DBUG_VOID_RETURN;
+}
+
+
+int db_function(char *b,const char *server, const char *database,const char *table,const char *field, const char *value, const char* path, struct func_st *function)
+{
+ char buff[BUFLEN];
+ int i;
+ DBUG_ENTER("db_function");
+ DBUG_PRINT("enter",("buffer: '%s', database: '%s', table: '%s', field: '%s', path: '%s'", b, database, table, field,path));
+
+ if(*database) {
+ if (mysql_select_db(sock,database))
+ {
+ printf("error when changing database to'%s'\n",database);
+ DBUG_RETURN(-1);
+ }
+ }
+
+ sprintf(buff,"%s",function->function);
+ search_and_replace("$database",database,buff);
+ search_and_replace("$table",table,buff);
+ search_and_replace("$field",field,buff);
+ search_and_replace("$value",value,buff);
+ DBUG_PRINT("info",("path: '%s'",path));
+ DBUG_PRINT("info",("sum: '%d'",(database[0] ? strlen(database)+1 : 0) +(table[0] ? strlen(table)+1 : 0) +(field[0] ? strlen(field)+1 : 0) +(value[0] ? strlen(value)+1 : 0) +1));
+ search_and_replace("$*",path+
+ (server[0] ? strlen(server)+1 : 0) +
+ (database[0] ? strlen(database)+1 : 0) +
+ (table[0] ? strlen(table)+1 : 0) +
+ (field[0] ? strlen(field)+1 : 0) +
+ (value[0] ? strlen(value)+1 : 0) +
+ function->length +
+ 1,buff);
+ DBUG_PRINT("info",("Executing constructed function query: '%s'", buff));
+ if (mysql_query(sock, buff))
+ {
+ printf("error when executing '%s'\n",buff);
+ sprintf(b,"ERROR %d: %s",mysql_error(sock),mysql_error(sock));
+ DBUG_VOID_RETURN;
+ }
+
+ db_show_result(sock, b, &Human);
+ DBUG_PRINT("info",("Returning: %s", b));
+ DBUG_RETURN(1);
+}
+
+int db_show_field(char *b,const char *database,const char *table, const char *field,const char *value, const char *param)
+{
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+ char buff[BUFLEN];
+ int i=0;
+ my_string *ptr;
+ DBUG_ENTER("db_show_field");
+ DBUG_PRINT("enter",("buffer: '%s', database: '%s', table: '%s', field: '%s' value: '%s'", b, database, table, field, value));
+
+ /* We cant output fields when one of these variables is missing */
+ if (!(database[0] && table[0] && field[0]))
+ DBUG_RETURN(-1);
+
+ init_dynamic_array(&field_array, sizeof(buff), 4096, 1024);
+
+ if (mysql_select_db(sock,database))
+ {
+ printf("error when changing database to'%s'\n",database);
+ delete_dynamic(&field_array);
+ DBUG_RETURN(-1);
+ }
+
+ if(param) {
+ sprintf(buff,"%s",param);
+ } else {
+ sprintf(buff,"select %s from %s where %s='%s' LIMIT 1",field,table,field,value);
+ }
+ if (mysql_query(sock, buff))
+ {
+ printf("error when executing '%s'\n",buff);
+ delete_dynamic(&field_array);
+ DBUG_RETURN(-1);
+ }
+
+
+ db_show_result(sock,b,&Human);
+/* if(result=mysql_use_result(sock)) {
+ while(row=mysql_fetch_row(result))
+ {
+ strcpy(&b[i][BUFLEN],row[0]);
+ DBUG_PRINT("info",("field %s at %x", &b[i*BUFLEN],&b[i*BUFLEN]));
+// ptr = (*dynamic_element(&field_array,i,row[0]));
+ i++;
+ }
+ }
+// fix_filenames((char *)b);
+ mysql_free_result(result);
+ */
+ delete_dynamic(&field_array);
+ DBUG_RETURN(i);
+
+}
+int db_show_fields(char *b,const char *database,const char *table)
+{
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+ MYSQL_FIELD *field;
+ char buff[BUFLEN];
+ int i=0;
+
+ DBUG_ENTER("show_fields");
+ DBUG_PRINT("enter",("buffer: '%s', database: '%s', table: '%s'", b, database, table));
+ if (mysql_select_db(sock,database))
+ {
+ printf("error when changing database to'%s'\n",database);
+ DBUG_RETURN(-1);
+ }
+ if(result=mysql_list_fields(sock,buff,NULL)) {
+
+ while(row=mysql_fetch_row(result))
+ {
+ strcpy(&b[i*BUFLEN],row[0]);
+ DBUG_PRINT("info",("field %s at %x", &b[i*BUFLEN],&b[i*BUFLEN]));
+ i++;
+ }
+ }
+ mysql_free_result(result);
+ DBUG_RETURN(i);
+}
+
+int db_show_primary_keys(char *b,const char *database, const char *table)
+{
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+ char buff[BUFLEN];
+ char buff2[BUFLEN];
+ unsigned int i;
+
+ DBUG_ENTER("db_show_primary_keys");
+ DBUG_PRINT("enter",("buffer: '%s', database: '%s', table: '%s'", b, database, table));
+ if (mysql_select_db(sock,database))
+ {
+ printf("error when changing database to '%s'\n",database);
+ DBUG_RETURN(-1);
+ }
+ sprintf(buff,"show keys from %s",table);
+ if (mysql_query(sock, buff))
+ {
+ printf("error when executing '%s'\n",buff);
+ DBUG_RETURN(0);
+ }
+ buff2[0]='\0';
+ if(result=mysql_use_result(sock)) {
+ while(row=mysql_fetch_row(result)) {
+ if(!strcasecmp(row[2],"PRIMARY")) {
+ strcat(buff2,row[4]);
+ strcat(buff2,",\"_\",");
+ }
+ }
+ buff2[strlen(buff2)-5]='\0';
+ if(!buff2[0])
+ DBUG_RETURN(-1); // No PRIMARY keys in table
+ DBUG_PRINT("info",("Keys: %s<- \n", buff2));
+ } else
+ DBUG_RETURN(-1); // No keys in table
+
+ sprintf(buff,"SELECT CONCAT(%s) AS X FROM %s LIMIT 256",buff2,table);
+ if (mysql_query(sock, buff))
+ {
+ printf("error when executing '%s'\n",buff);
+ DBUG_RETURN(0);
+ }
+ i=0;
+ if(result=mysql_use_result(sock)) {
+ while(row=mysql_fetch_row(result))
+ {
+ strcpy(&b[i*BUFLEN],row[0]);
+ fix_filenames(&b[i*BUFLEN]);
+ DBUG_PRINT("info",("primarykey %s at %x, %i", &b[i*BUFLEN],&b[i*BUFLEN],i));
+ if(i++ >= MAXDIRS)
+ break;
+ }
+ }
+ mysql_free_result(result);
+ DBUG_RETURN(i);
+}
+
+
+int db_show_keys(char *b,const char *database, const char *table)
+{
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+ char buff[BUFLEN];
+ int i=0;
+
+ DBUG_ENTER("show_keys");
+ DBUG_PRINT("enter",("buffer: '%s', database: '%s', table: '%s'", b, database, table));
+ if (mysql_select_db(sock,database))
+ {
+ printf("error when changing database to'%s'\n",database);
+ DBUG_RETURN(-1);
+ }
+ sprintf(buff,"show keys from %s",table);
+ if (mysql_query(sock, buff))
+ {
+ printf("error when executing '%s'\n",buff);
+ DBUG_RETURN(0);
+ }
+ if(result=mysql_use_result(sock)) {
+ while(row=mysql_fetch_row(result))
+ {
+ strcpy(&b[i*BUFLEN],row[0]);
+ DBUG_PRINT("info",("Key %s at %x", &b[i*BUFLEN],&b[i*BUFLEN]));
+ i++;
+ }
+ }
+ mysql_free_result(result);
+ DBUG_RETURN(i);
+}
+
+
+int db_show_tables(char *b,const char *database)
+{
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+ char buff[BUFLEN];
+ int i=0;
+
+ DBUG_ENTER("db_show_tables");
+ DBUG_PRINT("enter",("buffer: '%s', database: '%s'", b, database));
+ if (mysql_select_db(sock,database))
+ {
+ printf("error when changing database to '%s'\n",database);
+ DBUG_RETURN(-1);
+ }
+
+ if(result=mysql_list_tables(sock,NULL)) {
+ while(row=mysql_fetch_row(result))
+ {
+ strcpy(&b[i*BUFLEN],row[0]);
+ DBUG_PRINT("info",("table %s at %x", &b[i*BUFLEN],&b[i*BUFLEN]));
+ i++;
+ }
+ }
+ mysql_free_result(result);
+ DBUG_RETURN(i);
+}
+
+/*
+ * Finds all servers we are connected to
+ * and stores them in array supplied.
+ * returns count of servers
+ */
+int
+db_show_servers(char *b,int size)
+{
+ char* bufptr;
+ char* buff[BUFLEN*2];
+ DBUG_ENTER("db_show_servers");
+ DBUG_PRINT("enter",("buffer: '%s', size: '%d'", b, size));
+ bufptr=mysql_get_host_info(sock);
+ // FIXME: Actually we need to escape prohibited symbols in filenames
+ fix_filenames(bufptr);
+ strcpy(b,bufptr);
+ DBUG_RETURN(1);
+}
+
+/*
+ * Finds all databases in server
+ * and stores them in array supplied.
+ * returns count of databases
+ */
+int
+db_show_databases(char *b,int size)
+{
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+ char buff[BUFLEN];
+ int i=0;
+
+ DBUG_ENTER("db_show_databases");
+ DBUG_PRINT("enter",("buffer: '%s', size: '%d'", b, size));
+ result=mysql_list_dbs(sock,NULL);
+ while(row=mysql_fetch_row(result))
+ {
+ strcpy(&b[i*BUFLEN],row[0]);
+ DBUG_PRINT("info",("database %s at %x", &b[i*BUFLEN],&b[i*BUFLEN]));
+ i++;
+ }
+ mysql_free_result(result);
+ DBUG_RETURN(i);
+}
+
+void db_load_formats()
+{
+
+ /* In future we should read these variables
+ * from configuration file/database here */
+
+ /* HTML output */
+ HTML.tablestart="<table>\n";
+
+ HTML.headerrowstart="<tr>";
+ HTML.headercellstart="<th>";
+ HTML.headercellseparator="</th><th>";
+ HTML.headercellend="</th>";
+ HTML.headerrowend="</tr>\n";
+ HTML.headerformat=0;
+
+ HTML.leftuppercorner="";
+ HTML.rightuppercorner="";
+ HTML.leftdowncorner="";
+ HTML.rightdowncorner="";
+ HTML.topcross="";
+ HTML.middlecross="";
+ HTML.bottomcross="";
+ HTML.leftcross="";
+ HTML.rightcross="";
+ HTML.bottomcross="";
+
+ HTML.contentrowstart="<tr>";
+ HTML.contentcellstart="<td>";
+ HTML.contentcellseparator="</td><td>";
+ HTML.contentcellend="</td>";
+ HTML.contentrowend="</tr>\n";
+ HTML.headerformat=0;
+
+ HTML.footerrowstart="";
+ HTML.footercellstart="";
+ HTML.footercellseparator="";
+ HTML.footercellend="";
+ HTML.footerrowend="\n";
+ HTML.footerformat=0;
+
+ HTML.tableend="</table>\n";
+
+/* Nice to look mysql client like output */
+
+ Human.tablestart="\n";
+
+ Human.headerrowstart="| ";
+ Human.headercellstart="";
+ Human.headercellseparator=" | ";
+ Human.headercellend=" |";
+ Human.headerrowend="\n";
+ Human.headerformat=1;
+
+ Human.leftuppercorner="/=";
+ Human.rightuppercorner="=\\\n";
+ Human.leftdowncorner="\\=";
+ Human.rightdowncorner="=/\n";
+ Human.leftcross="+-";
+ Human.rightcross="-+\n";
+ Human.topcross="=T=";
+ Human.middlecross="-+-";
+ Human.bottomcross="=`=";
+
+ Human.contentrowstart="| ";
+ Human.contentcellstart="";
+ Human.contentcellseparator=" | ";
+ Human.contentcellend=" |";
+ Human.contentrowend="\n";
+ Human.contentformat=1;
+
+ Human.footerrowstart="";
+ Human.footercellstart="";
+ Human.footercellseparator="";
+ Human.footercellend="";
+ Human.footerrowend="\n";
+ Human.footerformat=1;
+
+ Human.tableend="\n";
+
+/* Comma-separated format. For machine reading */
+
+ /* XML */
+
+/*
+ tee_fprintf(PAGER,"<?xml version=\"1.0\"?>\n\n<resultset statement=\"%s\">", statement);
+ (void) tee_fputs("\n <row>\n", PAGER);
+ data=(char*) my_malloc(lengths[i]*5+1, MYF(MY_WME));
+ tee_fprintf(PAGER, "\t<%s>", (fields[i].name ?
+ (fields[i].name[0] ? fields[i].name :
+ " &nbsp; ") : "NULL"));
+ xmlencode(data, cur[i]);
+ tee_fprintf(PAGER, "</%s>\n", (fields[i].name ?
+ (fields[i].name[0] ? fields[i].name :
+ " &nbsp; ") : "NULL"));
+ </row>\n" </resultset>\n*/
+}
+
+gptr db_load_functions()
+{
+ char *functions[]={
+ "database",".tables","SHOW TABLES","0",
+ "table",".status","SHOW TABLE STATUS FROM $table","0",
+ "table",".count","SELECT COUNT(*) FROM $table","0",
+ "table",".table","SELECT * FROM $table","0",
+ "table",".check","CHECK TABLE $table","0",
+ "table",".repair","REPAIR TABLE $table","0",
+ "key",".min","SELECT MIN($key) FROM $table","0",
+ "key",".max","SELECT MAX($key) FROM $table","0",
+ "key",".avg","SELECT AVG($key) FROM $table","0",
+ "server",".uptime","SHOW STATUS like 'Uptime'","0",
+ "server",".version","SELECT VERSION()","0",
+ "server",".execute","$*","1",
+ "root",".connect","CONNECT $*","0",
+ NULL,NULL,NULL,NULL
+ };
+ char buff[BUFLEN];
+ int i=0;
+ struct func_st func;
+ DBUG_ENTER("db_load_functions");
+ init_dynamic_array(&functions_array, sizeof(struct func_st), 4096, 1024);
+ while(functions[i]) {
+ strcpy(func.type_s, functions[i]); /* Type in string: "table"` */
+ strcpy(func.filename, functions[i+1]); /* Name like it appears on FS: "count" */
+ strcpy(func.function, functions[i+2]); /* Query: "SELECT COUNT(*) FROM `%table`" */
+ func.continuous= atoi(functions[i+3]); /* Query: "If command can be continued" */
+
+ if(!strcasecmp(func.type_s,"server"))
+ func.type=SERVER_FUNCTION;
+ else if(!strcasecmp(func.type_s,"table"))
+ func.type=TABLE_FUNCTION;
+ else if(!strcasecmp(func.type_s,"key"))
+ func.type=KEY_FUNCTION;
+ else if(!strcasecmp(func.type_s,"database"))
+ func.type=DATABASE_FUNCTION;
+ else if(!strcasecmp(func.type_s,"field"))
+ func.type=FIELD_FUNCTION;
+ else if(!strcasecmp(func.type_s,"root"))
+ func.type=ROOT_FUNCTION;
+ else func.type=NONE_FUNCTION;
+
+ func.length=strlen(func.filename); /* Filename length */
+ DBUG_PRINT("info",("func.type_s: %s",func.type_s));
+ DBUG_PRINT("info",("func.filename: %s",func.filename));
+ DBUG_PRINT("info",("func.function: %s",func.function));
+ DBUG_PRINT("info",("func.type: %d",func.type));
+ DBUG_PRINT("info",("func.continuous: %d",func.continuous));
+ DBUG_PRINT("info",("i: %d",i));
+ insert_dynamic(&functions_array,(gptr)&func);
+ i+=4;
+ }
+ DBUG_RETURN((gptr)&functions_array);
+}
diff --git a/fs/dump.sql b/fs/dump.sql
new file mode 100644
index 00000000000..c61669cecb5
--- /dev/null
+++ b/fs/dump.sql
@@ -0,0 +1,28 @@
+# MySQL dump 8.12
+#
+# Host: localhost Database: mysqlfs
+#--------------------------------------------------------
+# Server version 3.23.33
+
+#
+# Table structure for table 'functions'
+#
+
+CREATE TABLE functions (
+ type enum('server','database','table','field','key') NOT NULL default 'server',
+ name char(20) NOT NULL default '',
+ sql char(128) NOT NULL default '',
+ PRIMARY KEY (type,name)
+) TYPE=MyISAM;
+
+#
+# Dumping data for table 'functions'
+#
+
+INSERT INTO functions VALUES ('server','uptime','SHOW STATUS like \'Uptime\'');
+INSERT INTO functions VALUES ('server','version','SELECT VERSION()');
+INSERT INTO functions VALUES ('table','count','SELECT COUNT(*) FROM `%table`');
+INSERT INTO functions VALUES ('key','min','SELECT MIN(%key) FROM `%table`');
+INSERT INTO functions VALUES ('key','max','SELECT MAX(%key) FROM `%table`');
+INSERT INTO functions VALUES ('key','avg','SELECT AVG(%key) FROM `%table`');
+
diff --git a/fs/korbit-kernel-2.4.1-patch b/fs/korbit-kernel-2.4.1-patch
new file mode 100644
index 00000000000..d97b1dac344
--- /dev/null
+++ b/fs/korbit-kernel-2.4.1-patch
@@ -0,0 +1,35661 @@
+diff -urN linux-2.4.1/.cvsignore linux-2.4.1-korbit/.cvsignore
+--- linux-2.4.1/.cvsignore Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/.cvsignore Thu Feb 1 11:46:48 2001
+@@ -0,0 +1 @@
++makekorbit.sh
+diff -urN linux-2.4.1/KORBit.Announce linux-2.4.1-korbit/KORBit.Announce
+--- linux-2.4.1/KORBit.Announce Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/KORBit.Announce Thu Feb 1 11:46:48 2001
+@@ -0,0 +1,62 @@
++From sabre@nondot.org Fri Dec 8 15:15:43 2000
++Date: Fri, 8 Dec 2000 17:10:47 -0600 (CST)
++From: Chris Lattner <sabre@nondot.org>
++To: linux-kernel@vger.kernel.org, orbit-list@gnome.org
++Cc: korbit-cvs@lists.sourceforge.net
++Subject: ANNOUNCE: Linux Kernel ORB: kORBit
++
++
++This email is here to announce the availability of a port of ORBit (the
++GNOME ORB) to the Linux kernel. This ORB, named kORBit, is available from
++our sourceforge web site (http://korbit.sourceforge.net/). A kernel ORB
++allows you to write kernel extensions in CORBA and have the kernel call
++into them, or to call into the kernel through CORBA. This opens the door
++to a wide range of experiments/hacks:
++
++* We can now write device drivers in perl, and let them run on the iMAC
++ across the hall from you. :)
++* Through the use of a LD_PRELOAD'd syscall wrapper library, you can
++ forward system calls through CORBA to an arbitrary local/remote machine.
++* CORBA servers are implemented as Linux kernel modules, so they may be
++ dynamically loaded or unloaded from a running system at any time. CORBA
++ servers expose their IOR's through a /proc/corba filesystem.
++* Filesystems may be implemented as remote CORBA objects and mounted on
++ the local machine, by using 'mount -t corbafs -o IOR:... none /mnt/corba'
++
++This are just some of the features available _RIGHT_NOW_ that are
++supported by kORBit. I'm sure that YOU can think of many more.
++
++Implementation:
++We implemented this port by providing a user->kernel mapping layer that
++consists of providing standard system header files for the "user" code to
++#include. In these header files, we do the mapping required. For
++example, we implement a <stdio.h> that #defines printf to printk (as a
++trivial example). Only user level code sees or uses these wrappers... all
++of our modifications to the Linux kernel are contained within the
++linux/net/korbit subdirectory.
++
++This is currently implemented with a 2.4.0test10 kernel, although forward
++porting should be very easy. This project was implemented as a cs423
++semester project by Chris Lattner, Fredrik Vraalsen, Andy Reitz, and Keith
++Wessel at the University of Illinois @ Urbana Champaign.
++
++Unresolved issues:
++* Our poll model is not optimial. Currently we actually do a real poll on
++ a (struct socket *) set. This causes relatively high latencies (on the
++ order 1 second, worst case) for CORBA requests. Our waitqueues are not
++ working quite as well as they should. :)
++* Security is completely unimplemented. Someone could use corba
++ interfaces to read any file on your system, for example (if the
++ CORBA-FileServer module is installed). Thus, this is really more for
++ prototyping and development than actual real world use. :)
++
++If you have any questions or comments, please feel free to contact us at:
++
++Chris Lattner, Fredrik Vraalsen, Andy Reitz, Keith Wessel
++<korbit-cvs@lists.sourceforge.net>
++
++btw, yes we are quite crazy, but what good is it to be normal and
++conformist afterall? :)
++
++
++
+diff -urN linux-2.4.1/Makefile linux-2.4.1-korbit/Makefile
+--- linux-2.4.1/Makefile Tue Jan 30 09:19:26 2001
++++ linux-2.4.1-korbit/Makefile Thu Feb 1 15:48:45 2001
+@@ -70,7 +70,7 @@
+ # images. Uncomment if you want to place them anywhere other than root.
+ #
+
+-#export INSTALL_PATH=/boot
++export INSTALL_PATH=/boot
+
+ #
+ # INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory
+diff -urN linux-2.4.1/README.korbit linux-2.4.1-korbit/README.korbit
+--- linux-2.4.1/README.korbit Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/README.korbit Thu Feb 1 11:46:48 2001
+@@ -0,0 +1,83 @@
++ ====================
++ KORBit: A CORBA ORB
++ For The Linux Kernel
++ ====================
++
++ Submitted as a final project in CS423 by
++ Chris Lattner <lattner@uiuc.edu>,
++ Andy Reitz <areitz@uiuc.edu>,
++ Fredrik Vraalsen <vraalsen@uiuc.edu>, and
++ Keith Wessel <kwessel@uiuc.edu>
++
++ December 8, 2000
++
++
++About:
++======
++KORBit is a port of the CORBA Object Request Broker ORBit to the Linux
++kernel. For more information, see http://korbit.sourceforge.net/
++
++In order to use this code, you need to have ORBit-0.5.3 or later
++installed (including the development environment). The KORBit server
++modules make use of the ORBit IDL Compiler during the build process.
++
++Building The Code:
++==================
++In order to compile and run KORBit you need a recent 2.4.0-test
++version of the Linux kernel (KORBit is developed on 2.4.0-test10).
++
++To obtain a copy of the KORBit source code, see the webpage above.
++Once you have untar'ed the source code, copy the contents of the linux
++subdirectory of KORBit into the Linux root source directory
++(e.g. /usr/src/linux).
++
++Run your favourite configuration option for Linux (e.g. 'make
++menuconfig'). To enable KORBit support in the kernel, go into the
++'Networking options' section of the configuration and enable 'Kernel
++ORB'. Then add the various CORBA services that you wish to run in the
++kernel.
++
++NOTE: The Kernel ORB *must* be compiled statically into the kernel
++(answer 'Y') and CORBA services *must* be compiled as modules (answer
++'M') at the moment.
++
++Then compile and install the Linux kernel in the standard way, e.g.:
++
++make dep ; make clean ; make bzImage ; make modules ; make modules_install
++
++Copy System.map and arch/<i386|whatever>/boot/bzImage to the proper
++places (/boot), edit your lilo.conf, run lilo and reboot.
++
++You should now be able to use CORBA in your Linux kernel! Remember,
++this is *pre-alpha* software! Use on your own risk! Don't come to us
++crying if your machine blows up...
++
++Using Our Example KORBit Objects:
++=================================
++The "CORBA Echo Server" is effectively our "hello world" object. Once
++loaded into the kernel, module will instantiate an object that
++implements the "echoString()" interface. This method allows the client
++to send a string, which will be printed on the system console. Then,
++it will return a random number, which the client will print. Thus,
++after running this test, you will verify that two-way communication is
++working between KORBit and your ORB of choice.
++
++To insert this module into your newly-compiled kernel, type
++
++insmod /lib/modules/2.4.0-test10/kernel/net/korbit/modules/Echo/server/corba-echo-server.o
++
++Next verify that this module is actually loaded, by invoking
++"lsmod". You should see something like this:
++
++ Module Size Used by
++ corba-echo-server 3344 0 (unused)
++
++Now, you can grab the IOR to this object by typing "cat
++/proc/corba/echo-server". Now, you need to build the echo client,
++which will use this IOR in order to connect to the echo server. This
++can be accomplished by simply changing to the
++"/usr/src/linux/net/korbit/modules/Echo/client" directory, and then
++typing "make". Once finished, simply type "./echo-client `cat
++/proc/corba/echo-server`", and then cross your fingers!
++
++
+diff -urN linux-2.4.1/Rules.make linux-2.4.1-korbit/Rules.make
+--- linux-2.4.1/Rules.make Sat Dec 30 00:07:19 2000
++++ linux-2.4.1-korbit/Rules.make Thu Feb 1 15:46:07 2001
+@@ -222,9 +222,9 @@
+
+ $(MODINCL)/%.ver: %.c
+ @if [ ! -r $(MODINCL)/$*.stamp -o $(MODINCL)/$*.stamp -ot $< ]; then \
+- echo '$(CC) $(CFLAGS) -E -D__GENKSYMS__ $<'; \
++ echo '$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -E -D__GENKSYMS__ $<'; \
+ echo '| $(GENKSYMS) $(genksyms_smp_prefix) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) > $@.tmp'; \
+- $(CC) $(CFLAGS) -E -D__GENKSYMS__ $< \
++ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -E -D__GENKSYMS__ $< \
+ | $(GENKSYMS) $(genksyms_smp_prefix) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) > $@.tmp; \
+ if [ -r $@ ] && cmp -s $@ $@.tmp; then echo $@ is unchanged; rm -f $@.tmp; \
+ else echo mv $@.tmp $@; mv -f $@.tmp $@; fi; \
+diff -urN linux-2.4.1/korbit.patch linux-2.4.1-korbit/korbit.patch
+--- linux-2.4.1/korbit.patch Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/korbit.patch Thu Feb 1 11:46:48 2001
+@@ -0,0 +1,43 @@
++--- linux/Rules.make.orig Wed Jan 31 22:50:40 2001
+++++ linux/Rules.make Thu Feb 1 01:39:46 2001
++@@ -222,9 +222,9 @@
++
++ $(MODINCL)/%.ver: %.c
++ @if [ ! -r $(MODINCL)/$*.stamp -o $(MODINCL)/$*.stamp -ot $< ]; then \
++- echo '$(CC) $(CFLAGS) -E -D__GENKSYMS__ $<'; \
+++ echo '$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -E -D__GENKSYMS__ $<'; \
++ echo '| $(GENKSYMS) $(genksyms_smp_prefix) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) > $@.tmp'; \
++- $(CC) $(CFLAGS) -E -D__GENKSYMS__ $< \
+++ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -E -D__GENKSYMS__ $< \
++ | $(GENKSYMS) $(genksyms_smp_prefix) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) > $@.tmp; \
++ if [ -r $@ ] && cmp -s $@ $@.tmp; then echo $@ is unchanged; rm -f $@.tmp; \
++ else echo mv $@.tmp $@; mv -f $@.tmp $@; fi; \
++--- linux/net/Config.in.orig Wed Jan 31 22:39:32 2001
+++++ linux/net/Config.in Thu Feb 1 01:40:02 2001
++@@ -30,6 +30,7 @@
++ fi
++ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
++ source net/khttpd/Config.in
+++ source net/korbit/Config.in
++ fi
++ fi
++ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
++--- linux/net/Makefile.orig Thu Feb 1 01:41:42 2001
+++++ linux/net/Makefile Thu Feb 1 01:41:35 2001
++@@ -7,7 +7,7 @@
++
++ O_TARGET := network.o
++
++-mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda atm netlink sched
+++mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda atm netlink sched korbit
++ export-objs := netsyms.o
++
++ subdir-y := core ethernet
++@@ -27,6 +27,7 @@
++ endif
++
++ subdir-$(CONFIG_KHTTPD) += khttpd
+++subdir-$(CONFIG_KORBIT) += korbit
++ subdir-$(CONFIG_NETLINK) += netlink
++ subdir-$(CONFIG_PACKET) += packet
++ subdir-$(CONFIG_NET_SCHED) += sched
+diff -urN linux-2.4.1/makekorbit.sh linux-2.4.1-korbit/makekorbit.sh
+--- linux-2.4.1/makekorbit.sh Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/makekorbit.sh Thu Feb 1 11:46:48 2001
+@@ -0,0 +1,4 @@
++#!/bin/sh
++
++make CFLAGS="-D__KERNEL__ -I`pwd`/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -march=k6 -DHAVE_CONFIG_H -DHAVE_UNISTD_H -I. -I.. -I../include -nostdinc" -C net/korbit TOPDIR=`pwd`
++
+diff -urN linux-2.4.1/net/CVS/Entries linux-2.4.1-korbit/net/CVS/Entries
+--- linux-2.4.1/net/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/CVS/Entries Thu Feb 1 11:46:49 2001
+@@ -0,0 +1 @@
++D
+diff -urN linux-2.4.1/net/CVS/Entries.Log linux-2.4.1-korbit/net/CVS/Entries.Log
+--- linux-2.4.1/net/CVS/Entries.Log Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/CVS/Entries.Log Thu Feb 1 11:46:49 2001
+@@ -0,0 +1 @@
++A D/korbit////
+diff -urN linux-2.4.1/net/CVS/Repository linux-2.4.1-korbit/net/CVS/Repository
+--- linux-2.4.1/net/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/CVS/Repository Thu Feb 1 11:46:49 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net
+diff -urN linux-2.4.1/net/CVS/Root linux-2.4.1-korbit/net/CVS/Root
+--- linux-2.4.1/net/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/CVS/Root Thu Feb 1 11:46:49 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/Config.in linux-2.4.1-korbit/net/Config.in
+--- linux-2.4.1/net/Config.in Tue Oct 10 19:33:52 2000
++++ linux-2.4.1-korbit/net/Config.in Thu Feb 1 15:46:07 2001
+@@ -30,6 +30,7 @@
+ fi
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ source net/khttpd/Config.in
++ source net/korbit/Config.in
+ fi
+ fi
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+diff -urN linux-2.4.1/net/Makefile linux-2.4.1-korbit/net/Makefile
+--- linux-2.4.1/net/Makefile Sat Dec 30 00:07:24 2000
++++ linux-2.4.1-korbit/net/Makefile Thu Feb 1 15:46:07 2001
+@@ -7,7 +7,7 @@
+
+ O_TARGET := network.o
+
+-mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda atm netlink sched
++mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda atm netlink sched korbit
+ export-objs := netsyms.o
+
+ subdir-y := core ethernet
+@@ -27,6 +27,7 @@
+ endif
+
+ subdir-$(CONFIG_KHTTPD) += khttpd
++subdir-$(CONFIG_KORBIT) += korbit
+ subdir-$(CONFIG_NETLINK) += netlink
+ subdir-$(CONFIG_PACKET) += packet
+ subdir-$(CONFIG_NET_SCHED) += sched
+diff -urN linux-2.4.1/net/korbit/CVS/Entries linux-2.4.1-korbit/net/korbit/CVS/Entries
+--- linux-2.4.1/net/korbit/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/CVS/Entries Thu Feb 1 11:46:49 2001
+@@ -0,0 +1,6 @@
++/Config.in/1.3/Thu Feb 1 09:46:49 2001//
++/Makefile/1.7/Thu Feb 1 09:46:49 2001//
++/config.h/1.2/Thu Feb 1 09:46:49 2001//
++/exported_symbols.c/1.8/Thu Feb 1 09:46:49 2001//
++/korbit.h/1.2/Thu Feb 1 09:46:49 2001//
++D
+diff -urN linux-2.4.1/net/korbit/CVS/Entries.Log linux-2.4.1-korbit/net/korbit/CVS/Entries.Log
+--- linux-2.4.1/net/korbit/CVS/Entries.Log Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/CVS/Entries.Log Thu Feb 1 11:47:15 2001
+@@ -0,0 +1,7 @@
++A D/IIOP////
++A D/ORBitutil////
++A D/include////
++A D/kglib////
++A D/modules////
++A D/orb////
++A D/sup////
+diff -urN linux-2.4.1/net/korbit/CVS/Repository linux-2.4.1-korbit/net/korbit/CVS/Repository
+--- linux-2.4.1/net/korbit/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/CVS/Repository Thu Feb 1 11:46:49 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit
+diff -urN linux-2.4.1/net/korbit/CVS/Root linux-2.4.1-korbit/net/korbit/CVS/Root
+--- linux-2.4.1/net/korbit/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/CVS/Root Thu Feb 1 11:46:49 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/Config.in linux-2.4.1-korbit/net/korbit/Config.in
+--- linux-2.4.1/net/korbit/Config.in Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/Config.in Thu Feb 1 11:46:49 2001
+@@ -0,0 +1,8 @@
++#
++# KORBit
++#
++
++#tristate ' Kernel ORB (EXPERIMENTAL)' CONFIG_KORBIT
++bool ' Kernel ORB (EXPERIMENTAL)' CONFIG_KORBIT
++
++source net/korbit/modules/Config.in
+diff -urN linux-2.4.1/net/korbit/IIOP/CVS/Entries linux-2.4.1-korbit/net/korbit/IIOP/CVS/Entries
+--- linux-2.4.1/net/korbit/IIOP/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/CVS/Entries Thu Feb 1 11:46:51 2001
+@@ -0,0 +1,15 @@
++/IIOP-config.h/1.1.1.1/Thu Feb 1 09:46:50 2001//
++/IIOP-design.txt/1.1.1.1/Thu Feb 1 09:46:50 2001//
++/IIOP-private.h/1.2/Thu Feb 1 09:46:50 2001//
++/IIOP-types.h/1.1.1.1/Thu Feb 1 09:46:50 2001//
++/IIOP.h/1.1.1.1/Thu Feb 1 09:46:50 2001//
++/Makefile/1.4/Thu Feb 1 09:46:51 2001//
++/connection.c/1.19/Thu Feb 1 09:46:51 2001//
++/encoders.c/1.1.1.1/Thu Feb 1 09:46:51 2001//
++/giop-msg-buffer.c/1.12/Thu Feb 1 09:46:51 2001//
++/giop-msg-buffer.h/1.1.1.1/Thu Feb 1 09:46:51 2001//
++/iiop-encoders.h/1.1.1.1/Thu Feb 1 09:46:51 2001//
++/iiop-endian.c/1.1.1.1/Thu Feb 1 09:46:51 2001//
++/iiop-endian.h/1.1.1.1/Thu Feb 1 09:46:51 2001//
++/iiop-endianP.h/1.1.1.1/Thu Feb 1 09:46:51 2001//
++D
+diff -urN linux-2.4.1/net/korbit/IIOP/CVS/Repository linux-2.4.1-korbit/net/korbit/IIOP/CVS/Repository
+--- linux-2.4.1/net/korbit/IIOP/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/CVS/Repository Thu Feb 1 11:46:50 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/IIOP
+diff -urN linux-2.4.1/net/korbit/IIOP/CVS/Root linux-2.4.1-korbit/net/korbit/IIOP/CVS/Root
+--- linux-2.4.1/net/korbit/IIOP/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/CVS/Root Thu Feb 1 11:46:49 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/IIOP/IIOP-config.h linux-2.4.1-korbit/net/korbit/IIOP/IIOP-config.h
+--- linux-2.4.1/net/korbit/IIOP/IIOP-config.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/IIOP-config.h Thu Feb 1 11:46:50 2001
+@@ -0,0 +1,5 @@
++/* The size of the chunks that are used for indirect pieces of messages.
++ Too low, and you'll have a lot of malloc overhead. Too high, and you'll
++ get wasted mem.
++*/
++#define GIOP_INDIRECT_CHUNK_SIZE 1024
+diff -urN linux-2.4.1/net/korbit/IIOP/IIOP-design.txt linux-2.4.1-korbit/net/korbit/IIOP/IIOP-design.txt
+--- linux-2.4.1/net/korbit/IIOP/IIOP-design.txt Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/IIOP-design.txt Thu Feb 1 11:46:50 2001
+@@ -0,0 +1,14 @@
++
++void Hello_hello(CORBA_Object anobj, const char *arg1, CORBA_Environment *ev)
++
++If we're doing a local call (i.e. shared library object activation),
++just do it.
++
++If we're doing a remote call, we need to setup generic header
++(utilfunc), setup request header (utilfunc), encode arguments (stubs),
++send the message headers & body (utilfunc) and wait for a reply (XXX
++define more clearly). When we get the reply, we need to read the
++reply(utilfunc), decode the return value & out/inout arguments(stubs)
++& fill them in (or decode the exception that resulted (utilfunc)), and
++return.
++
+diff -urN linux-2.4.1/net/korbit/IIOP/IIOP-private.h linux-2.4.1-korbit/net/korbit/IIOP/IIOP-private.h
+--- linux-2.4.1/net/korbit/IIOP/IIOP-private.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/IIOP-private.h Thu Feb 1 11:46:50 2001
+@@ -0,0 +1,46 @@
++#ifndef IIOP_PRIVATE_H
++#define IIOP_PRIVATE_H 1
++
++
++#include "config.h"
++
++#if defined(HAVE_POLL) && defined(I_WANT_POLL)
++#define USE_POLL
++#else
++#undef USE_POLL
++#endif
++
++#ifdef HAVE_SYS_POLL_H
++#include <sys/poll.h>
++#endif
++
++#include <sys/time.h>
++#include <sys/types.h>
++#include <unistd.h>
++
++#include <glib.h>
++
++typedef struct {
++ GList *list;
++ gboolean connection_list_changed;
++#ifndef __KORBIT__
++ GPtrArray *fd_to_connection_mapping;
++#else /* __KORBIT__ */
++ GHashTable *fd_to_connection_mapping;
++#endif /* __KORBIT__ */
++# ifdef USE_POLL
++ GArray *pollset;
++# else
++ fd_set selectset_rd, selectset_ex;
++# endif
++ int max_fd;
++} GIOPConnectionList;
++
++extern GIOPConnectionList giop_connection_list;
++
++/* If you get a buffer that you didn't want, add it to the list! */
++void giop_received_list_push(GIOPRecvBuffer *recv_buffer);
++GIOPRecvBuffer *giop_received_list_pop(void);
++
++
++#endif
+diff -urN linux-2.4.1/net/korbit/IIOP/IIOP-types.h linux-2.4.1-korbit/net/korbit/IIOP/IIOP-types.h
+--- linux-2.4.1/net/korbit/IIOP/IIOP-types.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/IIOP-types.h Thu Feb 1 11:46:50 2001
+@@ -0,0 +1,76 @@
++#ifndef IIOP_TYPES_H
++#define IIOP_TYPES_H 1
++
++/* XXX todo sync this up with basic_types.h if needed */
++#include <unistd.h>
++#include <netinet/in.h>
++#include <sys/un.h>
++
++#include <ORBitutil/basic_types.h>
++
++typedef enum {
++ GIOP_CONNECTION_SERVER, /* Not a real connection to any place - just
++ listening */
++ GIOP_CONNECTION_CLIENT
++} GIOPConnectionClass;
++
++typedef struct _GIOPConnection GIOPConnection;
++struct _GIOPConnection {
++ enum { GIOP_CONNECTION_NONE, GIOP_CONNECTION_IIOP } connection_type;
++ void (*destroy_func)(GIOPConnection *connection);
++
++ gint refcount;
++ GIOPConnectionClass connection_class;
++
++ int fd;
++
++ /* You can access these if you wish. */
++ gpointer orb_data;
++ gpointer user_data;
++ /* end accessable stuff */
++
++ guchar is_valid, was_initiated, is_auth;
++
++ gpointer incoming_msg; /* GIOPRecvBuffer */
++};
++
++#define GIOP_CONNECTION(x) ((GIOPConnection *)(x))
++#define GIOP_CONNECTION_GET_FD(x) (GIOP_CONNECTION((x))->fd)
++
++typedef enum { IIOP_IPV4, IIOP_IPV6, IIOP_USOCK } IIOPConnectionType;
++
++typedef struct {
++ GIOPConnection giop_connection;
++
++ gboolean is_serversock;
++ IIOPConnectionType icnxtype;
++ union {
++ struct {
++ char *hostname;
++ struct sockaddr_in location;
++ } ipv4;
++ struct sockaddr_un usock;
++ /* Yes this is a config.h define, and no it doesn't matter,
++ because this structure should only be used internally anyways */
++#ifdef HAVE_IPV6
++ struct {
++ char *hostname;
++ struct sockaddr_in6 location;
++ } ipv6;
++#endif
++ } u;
++} IIOPConnection;
++
++#define IIOP_CONNECTION(x) ((IIOPConnection *)(x))
++
++#if defined(DEBUG_sopwith_connection_refcounting)
++#define giop_connection_ref(x) G_STMT_START{ (GIOP_CONNECTION(x)->refcount++); g_print("! reffing fd %d in " __PRETTY_FUNCTION__ ":%d to %d\n", GIOP_CONNECTION_GET_FD(x), __LINE__, GIOP_CONNECTION(x)->refcount); }G_STMT_END
++
++#define giop_connection_unref(x) G_STMT_START{ GIOP_CONNECTION(x)->refcount--; g_print("! dereffing fd %d in " __PRETTY_FUNCTION__ ":%d to %d\n", GIOP_CONNECTION_GET_FD(x), __LINE__, GIOP_CONNECTION(x)->refcount); if(GIOP_CONNECTION(x)->refcount <= 0) giop_connection_free(x); }G_STMT_END
++#else
++#define giop_connection_ref(x) G_STMT_START{ (GIOP_CONNECTION(x)->refcount++); }G_STMT_END
++
++#define giop_connection_unref(x) G_STMT_START{ GIOP_CONNECTION(x)->refcount--; if(GIOP_CONNECTION(x)->refcount <= 0) giop_connection_free(x); }G_STMT_END
++#endif
++
++#endif /* IIOP_TYPES_H */
+diff -urN linux-2.4.1/net/korbit/IIOP/IIOP.h linux-2.4.1-korbit/net/korbit/IIOP/IIOP.h
+--- linux-2.4.1/net/korbit/IIOP/IIOP.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/IIOP.h Thu Feb 1 16:19:47 2001
+@@ -0,0 +1,52 @@
++#ifndef IIOP_H
++#define IIOP_H 1
++
++#include <unistd.h>
++#include <ORBitutil/util.h>
++#include "IIOP-config.h"
++#include "IIOP-types.h"
++#include "giop-msg-buffer.h"
++#include "iiop-encoders.h"
++#include "iiop-endian.h"
++
++/* We don't speak GIOP 1.0, sosumi */
++#define GIOP_1_1
++
++
++void giop_init(const char *argv0);
++
++/* You use this to get a pointer to a new (or existing) connection
++ that has the specified host/port characteristics */
++IIOPConnection *iiop_connection_get(const char *host, gushort port,
++ gboolean existing_only);
++/* Similar, but for UNIX sockets */
++IIOPConnection *iiop_connection_unix_get(const char *sockpath,
++ gboolean existing_only);
++
++/* gives us a local socket that other people can connect to... */
++IIOPConnection *iiop_connection_server(void);
++IIOPConnection *iiop_connection_server_ipv6(void);
++IIOPConnection *iiop_connection_server_unix(const char *sockpath);
++
++void giop_main_quit(void);
++void giop_main(void); /* main loop for the program if none other is given,
++ and also used while waiting for a reply */
++void giop_main_iterate(gboolean blocking);
++void giop_main_handle_connection(GIOPConnection *connection);
++void giop_main_handle_connection_exception(GIOPConnection *connection);
++GIOPRecvBuffer *giop_main_next_message(gboolean blocking);
++GIOPRecvBuffer *giop_main_next_message_2(gboolean blocking,
++ GIOPConnection *monitor);
++GIOPConnection *giop_check_connections(gboolean block_for_reply);
++
++/* This assumes that the appropriate GIOP_CLOSECONNECTION message
++ has been sent to the peer */
++void giop_connection_free(GIOPConnection *connection);
++
++/* Called when a connection is created */
++extern void (*IIOPAddConnectionHandler)(GIOPConnection *newcnx);
++/* Called when a connection is about to be destroyed */
++extern void (*IIOPRemoveConnectionHandler)(GIOPConnection *oldcnx);
++extern void (*IIOPIncomingMessageHandler)(GIOPRecvBuffer *recv_buffer);
++
++#endif /* IIOP_H */
+diff -urN linux-2.4.1/net/korbit/IIOP/Makefile linux-2.4.1-korbit/net/korbit/IIOP/Makefile
+--- linux-2.4.1/net/korbit/IIOP/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/Makefile Thu Feb 1 11:46:51 2001
+@@ -0,0 +1,18 @@
++#
++# Makefile for KORBit/IIOP
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .o file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++O_TARGET := IIOPlib.o
++
++#obj-m := $(O_TARGET)
++obj-y := connection.o encoders.o giop-msg-buffer.o iiop-endian.o
++
++
++EXTRA_CFLAGS = -D__KORBIT__ -DHAVE_CONFIG_H -I. -I.. -I../include -I../kglib -I../ORBitutil -nostdinc
++
++include $(TOPDIR)/Rules.make
+diff -urN linux-2.4.1/net/korbit/IIOP/connection.c linux-2.4.1-korbit/net/korbit/IIOP/connection.c
+--- linux-2.4.1/net/korbit/IIOP/connection.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/connection.c Thu Feb 1 19:26:07 2001
+@@ -0,0 +1,1565 @@
++#include "config.h"
++
++#if defined(HAVE_POLL) && defined(I_WANT_POLL)
++#define USE_POLL
++#else
++#undef USE_POLL
++#endif
++
++#ifndef _XOPEN_SOURCE_EXTENDED
++# define _XOPEN_SOURCE_EXTENDED 1
++# define WE_DEFINED_XOPEN_SOURCE_EXTENDED 1
++#endif
++#include "iiop-endianP.h"
++#ifdef WE_DEFINED_XOPEN_SOURCE_EXTENDED
++# undef _XOPEN_SOURCE_EXTENDED
++#endif
++#include "IIOP.h"
++#include "IIOP-private.h"
++#include "giop-msg-buffer.h"
++#include <stdlib.h>
++#include <unistd.h>
++#ifdef ORBIT_DEBUG
++#include <errno.h>
++#endif
++#include <sys/types.h>
++#include <fcntl.h>
++#include <sys/socket.h>
++#include <sys/un.h>
++#ifndef _XOPEN_SOURCE_EXTENDED
++# define _XOPEN_SOURCE_EXTENDED 1
++#endif
++#include <arpa/inet.h>
++#include <netdb.h>
++#ifdef WE_DEFINED_XOPEN_SOURCE_EXTENDED
++# undef _XOPEN_SOURCE_EXTENDED
++#endif
++#include <ctype.h>
++#include <string.h>
++#include <sys/time.h>
++#include <sys/ioctl.h>
++#include <signal.h>
++#include <syslog.h>
++#include <stdio.h>
++
++/*
++#ifdef O_NONBLOCK
++#undef O_NONBLOCK
++#endif
++#define O_NONBLOCK 0
++*/
++
++#if defined(HAVE_TCPD_H) && defined(HAVE_HOSTS_ACCESS)
++#include <tcpd.h>
++#endif
++
++#if 0
++#include <malloc.h>
++
++static struct mallinfo mi1, mi2;
++
++#define AM() mi1 = mallinfo();
++#define PM(x) mi2 = mallinfo(); printf(x ": used %d, now %d\n", \
++mi2.uordblks - mi1.uordblks, mi2.uordblks);
++#endif
++
++#ifdef HAVE_POLL
++#include <sys/poll.h>
++#endif
++
++#ifndef SUN_LEN
++/* This system is not POSIX.1g. */
++#define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
++ + strlen ((ptr)->sun_path))
++#endif
++
++void (*IIOPAddConnectionHandler)(GIOPConnection *newcnx) = NULL;
++void (*IIOPRemoveConnectionHandler)(GIOPConnection *oldcnx) = NULL;
++void (*IIOPIncomingMessageHandler)(GIOPRecvBuffer *recv_buffer) = NULL;
++
++static void giop_connection_add_to_list (GIOPConnection *cnx);
++static void giop_connection_remove_from_list (GIOPConnection *cnx);
++
++static void iiop_init (void);
++static void iiop_connection_server_accept (GIOPConnection *connection);
++static void iiop_connection_destroy (IIOPConnection *connection);
++static IIOPConnection *iiop_connection_new (const char *host, gushort port);
++static IIOPConnection *iiop_connection_unix_new (const char *sockpath);
++static void iiop_unlink_unix_sockets (void);
++
++DEFINE_LOCK(giop_connection_list);
++GIOPConnectionList giop_connection_list;
++static GSList *iiop_unix_socket_list = NULL;
++
++#if defined(HAVE_HOSTS_ACCESS) && defined (HAVE_TCPD_H)
++static const char *argv0_val = NULL;
++#endif
++
++struct fd_hash_elem
++{
++ guint fd;
++ GIOPConnection *cnx;
++};
++
++static guint fd_hash_func(gconstpointer key)
++{
++ const guint *key_ptr = (guint *)key;
++ guint result = *key_ptr >> 2;
++ return result;
++}
++
++static gint fd_compare_func(gconstpointer a, gconstpointer b)
++{
++ const guint *a_ptr = (guint *)a;
++ const guint *b_ptr = (guint *)b;
++ return *a_ptr == *b_ptr;
++}
++
++static gboolean fd_hash_clear(gpointer key, gpointer value, gpointer user_data)
++{
++ struct fd_hash_elem *el = (struct fd_hash_elem *)value;
++ g_free(el);
++ return TRUE;
++}
++
++/*
++ * giop_init
++ *
++ * Inputs: None
++ * Outputs: None
++ *
++ * Side effects: Initializes giop_connection_list
++ * Global data structures used: giop_connection_list
++ *
++ * Description: Initializes giop_connection_list. Calls
++ * giop_message_buffer_init() to initialize the
++ * message_buffer subsystem. Calls iiop_init()
++ * to perform IIOP-specific initialization.
++ */
++
++void giop_init(const char *argv0)
++{
++#ifndef __KERNEL__
++ struct sigaction mypipe;
++#endif
++ g_assert(sizeof(GIOPMessageHeader) == 12);
++
++#if defined(HAVE_HOSTS_ACCESS) && defined (HAVE_TCPD_H)
++ argv0_val = g_strdup(g_basename(argv0)); /* For TCP wrappers */
++#endif
++
++#ifndef __KERNEL__
++ memset(&mypipe, '\0', sizeof(mypipe));
++ mypipe.sa_handler = SIG_IGN;
++
++ sigaction(SIGPIPE, &mypipe, NULL);
++#endif
++
++ giop_message_buffer_init();
++
++ INIT_LOCK(giop_connection_list);
++
++ giop_connection_list.list = NULL;
++ giop_connection_list.connection_list_changed = FALSE;
++
++#ifdef USE_POLL
++ giop_connection_list.pollset = g_array_new(FALSE, FALSE,
++ sizeof(struct pollfd));
++#else
++ FD_ZERO(&giop_connection_list.selectset_rd);
++ FD_ZERO(&giop_connection_list.selectset_ex);
++#endif
++
++#ifndef __KORBIT__
++ giop_connection_list.fd_to_connection_mapping = g_ptr_array_new();
++#else
++ giop_connection_list.fd_to_connection_mapping =
++ g_hash_table_new(&fd_hash_func,
++ &fd_compare_func);
++#endif
++
++ /*
++ * This also needs to do any transport-specific initialization
++ * as appropriate
++ */
++ iiop_init();
++}
++
++/*** giop_connection_init
++ *
++ * Inputs: 'giop_connection' - memory region allocated for use as a
++ * GIOPConnection.
++ * 'cnxclass' - the class of connection that will be stored
++ * here (SERVER, CLIENT)
++ *
++ * Outputs: None
++ *
++ * Side effects: Initializes 'giop_connection'.
++ *
++ * Description: Basic setup of a GIOPConnection.
++ * Sets is_valid to FALSE because it is the responsibility of
++ * the transport-specific initialization routine to make
++ * a connection valid.
++ */
++
++static void giop_connection_init(GIOPConnection *giop_connection,
++ GIOPConnectionClass cnxclass)
++{
++ giop_connection->connection_type = GIOP_CONNECTION_NONE;
++ giop_connection->refcount = 0;
++ giop_connection->connection_class = cnxclass;
++ giop_connection->is_valid = FALSE;
++ giop_connection->is_auth = FALSE;
++ giop_connection->was_initiated = FALSE;
++}
++
++/*
++ * giop_connection_free
++ * Inputs: 'connection'
++ * Outputs: None
++ * Side effects: Makes the 'connection' invalid as a GIOPConnection
++ * and as a gpointer.
++ *
++ * Description: Calls giop_connection_remove_from_list() to
++ * stop the connection from being used for incoming.
++ *
++ * If a transport-specific finalization function has
++ * been provided, call it.
++ *
++ * Free the memory block at '*connection'.
++ *
++ */
++void giop_connection_free(GIOPConnection *connection)
++{
++ g_return_if_fail(connection != NULL);
++ giop_connection_remove_from_list(connection);
++
++ if(connection->is_valid && connection->destroy_func)
++ connection->destroy_func(connection);
++
++ connection->is_valid = FALSE;
++
++ if(connection->incoming_msg) {
++ GIOPRecvBuffer *buf;
++
++ buf = connection->incoming_msg;
++ connection->incoming_msg = NULL;
++ giop_recv_buffer_unuse(buf);
++ }
++
++ g_free(connection);
++}
++
++/*
++ * giop_connection_list_recreate
++ *
++ * Inputs: None
++ * Outputs: None
++ *
++ * Side effects: giop_connection_list changes.
++ *
++ * Global data structures used: giop_connection_list
++ *
++ * Description:
++ * When new connections are added to giop_connection_list.list,
++ * the data structures passed to poll() or select() (OS-dependant)
++ * must be recreated to match this list.
++ *
++ * [We do this at add-connection/remove-connection time
++ * instead of every time a poll/select is done in order to
++ * speed things up a little]
++ *
++ * This function reinitializes the OS-specific file
++ * descriptor data structure and then adds all the file
++ * descriptors in the list to it.
++ *
++ * It also regenerates the array that maps file descriptors
++ * into GIOPConnection*'s
++ *
++ */
++static void
++giop_connection_list_recreate(void)
++{
++ int curfd;
++ GList *item;
++ GIOPConnection *cnx;
++#ifdef USE_POLL
++ struct pollfd new_poll;
++
++ new_poll.revents = 0;
++#endif
++
++ giop_connection_list.max_fd = 0;
++ for(item = giop_connection_list.list; item; item = g_list_next(item))
++ {
++ cnx = item->data;
++ curfd = GIOP_CONNECTION_GET_FD(cnx);
++
++ if(curfd > giop_connection_list.max_fd)
++ giop_connection_list.max_fd = curfd;
++ }
++
++#ifndef __KORBIT__
++ g_ptr_array_set_size(giop_connection_list.fd_to_connection_mapping,
++ giop_connection_list.max_fd + 1);
++#else
++ g_hash_table_foreach_remove(giop_connection_list.fd_to_connection_mapping,
++ fd_hash_clear,
++ NULL);
++#endif
++
++#ifdef USE_POLL
++ g_array_set_size(giop_connection_list.pollset, 0);
++#else
++ FD_ZERO(&giop_connection_list.selectset_rd);
++ FD_ZERO(&giop_connection_list.selectset_ex);
++#endif
++
++ for(item = giop_connection_list.list; item; item = g_list_next(item))
++ {
++ struct fd_hash_elem *el;
++
++ cnx = item->data;
++ curfd = GIOP_CONNECTION_GET_FD(cnx);
++
++#ifndef __KORBIT__
++ giop_connection_list.fd_to_connection_mapping->pdata[curfd] = cnx;
++#else
++ el = g_new(struct fd_hash_elem, 1);
++ el->fd = curfd;
++ el->cnx = cnx;
++ g_hash_table_insert(giop_connection_list.fd_to_connection_mapping,
++ &(el->fd),
++ el);
++#endif
++
++# ifdef USE_POLL
++ new_poll.fd = curfd;
++ new_poll.events = POLLIN|POLLPRI;
++ g_array_append_val(giop_connection_list.pollset,
++ new_poll);
++# else
++ FD_SET(curfd, &giop_connection_list.selectset_rd);
++ FD_SET(curfd, &giop_connection_list.selectset_ex);
++# endif
++ }
++}
++
++/*
++ * giop_connection_add_to_list
++ *
++ * Inputs: 'cnx' - a GIOPConnection that the user wishes added to the list
++ * Outputs: None
++ *
++ * Side effects: Modifies giop_connection_list
++ * Global data structures used: giop_connection_list
++ * Bugs: Does not check for duplicate additions.
++ *
++ * Description:
++ * Adds a connection to the list of active connections.
++ */
++static void
++giop_connection_add_to_list(GIOPConnection *cnx)
++{
++ g_return_if_fail(cnx->is_valid == FALSE);
++
++ cnx->is_valid = TRUE;
++
++ GET_LOCK(giop_connection_list);
++ giop_connection_list.list = g_list_prepend(giop_connection_list.list, cnx);
++
++ giop_connection_list_recreate();
++
++ RELEASE_LOCK(giop_connection_list);
++
++ if(IIOPAddConnectionHandler)
++ IIOPAddConnectionHandler(cnx);
++
++ giop_connection_ref(cnx);
++}
++
++/*
++ * giop_connection_remove_from_list
++ *
++ * Inputs: 'cnx' - a GIOPConnection that the user wishes
++ * Outputs: None
++ *
++ * Side effects: Modifies giop_connection_list
++ * Global data structures used: giop_connection_list
++ *
++ * Description:
++ * Removes a connection from the list of active connections.
++ * Calls the library user's "I removed connection" handler if it
++ * exists.
++ *
++ * Bugs: Does not check for duplicate removals. This may not be "bad" though.
++ */
++void
++giop_connection_remove_from_list(GIOPConnection *cnx)
++{
++ GList *link;
++
++ GET_LOCK(giop_connection_list);
++
++ link = g_list_find(giop_connection_list.list, cnx);
++
++ if(!link)
++ goto out;
++
++ if(IIOPRemoveConnectionHandler && cnx->is_valid)
++ IIOPRemoveConnectionHandler(cnx);
++
++ giop_connection_list.list = g_list_remove_link(giop_connection_list.list,
++ link);
++ g_list_free_1(link);
++
++ giop_connection_unref(cnx);
++
++ giop_connection_list_recreate();
++ out:
++ RELEASE_LOCK(giop_connection_list);
++}
++
++/************************************************
++ * Routines specific to the IIOP/IPv4 transport *
++ ************************************************/
++
++/*
++ * iiop_init
++ *
++ * Inputs: None
++ * Outputs: None
++ *
++ * Side effects: Initializes iiop_unix_socket_list
++ * Global data structures used: iiop_unix_socket_list
++ *
++ * Description: Initializes iiop_unix_socket_list.
++ * Registers Unix domain sockets for
++ * removal at server termination.
++ */
++static void
++iiop_init(void)
++{
++#ifndef __KERNEL__
++ g_atexit(iiop_unlink_unix_sockets);
++#endif
++}
++
++/*
++ * iiop_connection_init
++ *
++ * Inputs: 'connection' - a memory region that needs to be initialized as
++ * an 'IIOPConnection'.
++ *
++ * Side effects: initializes 'connection'
++ *
++ * Description: Performs the IIOP-specific initialization of an
++ * IIOPConnection. giop_connection_init is called.
++ *
++ */
++void
++iiop_connection_init(IIOPConnection *connection,
++ GIOPConnectionClass cnxclass,
++ IIOPConnectionType iioptype)
++{
++ giop_connection_init(GIOP_CONNECTION(connection), cnxclass);
++
++ GIOP_CONNECTION(connection)->connection_type =
++ GIOP_CONNECTION_IIOP;
++
++ GIOP_CONNECTION(connection)->destroy_func =
++ (void (*)(GIOPConnection *))iiop_connection_destroy;
++
++ connection->icnxtype = iioptype;
++}
++
++/*
++ * iiop_connection_from_fd
++ *
++ * Inputs: 'fd' - a file descriptor that attention should be paid to
++ * Outputs: 'fd_cnx' - the created connection
++ *
++ * Description: This is intended to be used on a file descriptor
++ * that has been accept()'d. It creates the connection
++ * and fills in the connection information, then adds
++ * it to the active list.
++ */
++IIOPConnection *
++iiop_connection_from_fd(int fd, IIOPConnection *parent)
++{
++ IIOPConnection *fd_cnx;
++ struct hostent *hent;
++ socklen_t n;
++
++ g_assert(fd >= 0);
++
++ fd_cnx = g_new0(IIOPConnection, 1);
++
++ iiop_connection_init(fd_cnx, GIOP_CONNECTION_CLIENT, parent->icnxtype);
++
++ GIOP_CONNECTION(fd_cnx)->fd = fd;
++
++ switch(parent->icnxtype) {
++ case IIOP_IPV4:
++ n = sizeof(struct sockaddr_in);
++ if(getpeername(GIOP_CONNECTION_GET_FD(fd_cnx), (struct sockaddr *)&fd_cnx->u.ipv4.location, &n))
++ {
++ fd_cnx->u.ipv4.hostname = g_strdup("");
++ }
++ else
++ {
++ hent = gethostbyaddr((const char *)&fd_cnx->u.ipv4.location.sin_addr.s_addr, 4, AF_INET);
++ if(hent)
++ {
++ fd_cnx->u.ipv4.hostname = g_strdup(hent->h_name);
++ }
++ else
++ {
++ fd_cnx->u.ipv4.hostname = inet_ntoa(*((struct in_addr *)&fd_cnx->u.ipv4.location.sin_addr));
++ }
++ }
++ break;
++
++ case IIOP_USOCK:
++ n = sizeof(struct sockaddr_un);
++ fd_cnx->u.usock.sun_family = AF_UNIX;
++ getpeername(GIOP_CONNECTION_GET_FD(fd_cnx),
++ (struct sockaddr *)&fd_cnx->u.usock, &n);
++ break;
++
++#ifdef HAVE_IPV6
++ case IIOP_IPV6:
++ n = sizeof(struct sockaddr_in6);
++ getpeername(GIOP_CONNECTION_GET_FD(fd_cnx),
++ (struct sockaddr *)&fd_cnx->u.ipv6.location, &n);
++ hent = gethostbyaddr((const char *)&fd_cnx->u.ipv6.location.sin6_addr,
++ sizeof(fd_cnx->u.ipv6.location.sin6_addr), AF_INET6);
++ fd_cnx->u.ipv6.hostname = g_strdup(hent->h_name);
++ break;
++#endif
++
++ default:
++ g_error("Unsupported connection type %d", parent->icnxtype);
++ }
++
++ fcntl(GIOP_CONNECTION_GET_FD(fd_cnx), F_SETFD,
++ fcntl(GIOP_CONNECTION_GET_FD(fd_cnx), F_GETFD, 0)
++ | FD_CLOEXEC);
++ fcntl(GIOP_CONNECTION_GET_FD(fd_cnx), F_SETFL,
++ fcntl(GIOP_CONNECTION_GET_FD(fd_cnx), F_GETFL, 0)
++ | O_NONBLOCK);
++
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug,
++ "iiop_connection_from_fd connect [%d]\n",
++ GIOP_CONNECTION_GET_FD(fd_cnx));
++
++ giop_connection_add_to_list(GIOP_CONNECTION(fd_cnx));
++
++ return fd_cnx;
++}
++
++/*
++ * iiop_connection_server
++ *
++ * Outputs: 'server_cnx'
++ *
++ * Description: Creates a special IIOPConnection on which incoming
++ * connections come.
++ */
++IIOPConnection *
++iiop_connection_server(void)
++{
++ struct hostent *hent;
++ char hn_tmp[65];
++ socklen_t n;
++ IIOPConnection *server_cnx = g_new0(IIOPConnection, 1);
++
++ iiop_connection_init(server_cnx, GIOP_CONNECTION_SERVER, IIOP_IPV4);
++
++ server_cnx->is_serversock = TRUE;
++ GIOP_CONNECTION(server_cnx)->fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
++
++ if(GIOP_CONNECTION_GET_FD(server_cnx) < 0) {
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, "iiop_connection_server: socket_error: %s\n", strerror(errno));
++ goto failed;
++ }
++
++ server_cnx->u.ipv4.location.sin_family = AF_INET;
++ server_cnx->u.ipv4.location.sin_addr.s_addr = INADDR_ANY;
++ bind(GIOP_CONNECTION_GET_FD(server_cnx),
++ (struct sockaddr *)&server_cnx->u.ipv4.location,
++ sizeof(struct sockaddr_in));
++
++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx), F_SETFD,
++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx), F_GETFD, 0)
++ | FD_CLOEXEC);
++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx), F_SETFL,
++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx), F_GETFL, 0)
++ | O_NONBLOCK);
++
++ n = sizeof(struct sockaddr_in);
++ getsockname(GIOP_CONNECTION_GET_FD(server_cnx),
++ (struct sockaddr *)&server_cnx->u.ipv4.location, &n);
++
++ gethostname(hn_tmp, sizeof(hn_tmp) - 1);
++
++ hent = gethostbyname(hn_tmp);
++ if(hent)
++ {
++ if (strchr (hent->h_name, '.'))
++ server_cnx->u.ipv4.hostname = g_strdup(hent->h_name);
++ else
++ {
++ struct in_addr * addr = (struct in_addr *) hent->h_addr_list[0];
++ g_assert (hent->h_length == sizeof (struct in_addr) && addr);
++ server_cnx->u.ipv4.hostname = g_strdup (inet_ntoa (*addr));
++ }
++ }
++ else
++ server_cnx->u.ipv4.hostname = g_strdup(hn_tmp);
++
++ listen(GIOP_CONNECTION_GET_FD(server_cnx), 5);
++
++ giop_connection_add_to_list(GIOP_CONNECTION(server_cnx));
++
++ return server_cnx;
++
++failed:
++ close(GIOP_CONNECTION_GET_FD(server_cnx));
++ GIOP_CONNECTION(server_cnx)->fd = -1;
++ giop_connection_free(GIOP_CONNECTION(server_cnx));
++ server_cnx = NULL;
++ /*
++ * FIXME: GET_LOCK and DEFINE_LOCK never called for server_cnx
++ RELEASE_LOCK(server_cnx);
++ */
++ return NULL;
++}
++
++/*
++ * iiop_connection_server_ipv6
++ * Outputs: 'server_cnx'
++ *
++ * Description: Create a special IIOPConnection on which incoming
++ * connections come.
++ */
++IIOPConnection *
++iiop_connection_server_ipv6(void)
++{
++#ifdef HAVE_IPV6
++ struct hostent *hent, *hent2;
++
++ char hn_tmp[65];
++ int n;
++ IIOPConnection *server_cnx;
++
++ g_error("IPv6 support is baroquen! (Actually just never worked)");
++
++ server_cnx = g_new0(IIOPConnection, 1);
++
++ iiop_connection_init(server_cnx, GIOP_CONNECTION_SERVER, IIOP_IPV6);
++
++ server_cnx->is_serversock = TRUE;
++ GIOP_CONNECTION(server_cnx)->fd = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
++
++ if(GIOP_CONNECTION_GET_FD(server_cnx) < 0) {
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, "iiop_connection_server_ipv6: socket_error: %s\n", strerror(errno));
++ goto failed;
++ }
++
++ server_cnx->u.ipv6.location.sin6_family = AF_INET6;
++ bind(GIOP_CONNECTION_GET_FD(server_cnx),
++ (struct sockaddr *)&server_cnx->u.ipv6.location,
++ sizeof(struct sockaddr_in6));
++
++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx), F_SETFD,
++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx), F_GETFD, 0)
++ | FD_CLOEXEC);
++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx), F_SETFL,
++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx), F_GETFL, 0)
++ | O_NONBLOCK);
++
++ n = sizeof(struct sockaddr_in6);
++ getsockname(GIOP_CONNECTION_GET_FD(server_cnx), &server_cnx->u.ipv6.location, &n);
++
++ gethostname(hn_tmp, sizeof(hn_tmp) - 1);
++
++ hent = gethostbyname(hn_tmp);
++ if(hent) {
++ hent2 = gethostbyaddr(hent->h_addr, sizeof(server_cnx->u.ipv6.location.sin6_addr), AF_INET6);
++ if(hent2)
++ server_cnx->hostname = g_strdup(hent2->h_name);
++ else
++ server_cnx->hostname = g_strdup(hn_tmp);
++ } else
++ server_cnx->hostname = g_strdup(hn_tmp);
++
++ listen(GIOP_CONNECTION_GET_FD(server_cnx), 5);
++
++ giop_connection_add_to_list(GIOP_CONNECTION(server_cnx));
++
++ return server_cnx;
++
++failed:
++ close(GIOP_CONNECTION_GET_FD(server_cnx));
++ GIOP_CONNECTION(server_cnx)->fd = -1;
++ giop_connection_free(GIOP_CONNECTION(server_cnx));
++ server_cnx = NULL;
++ /*
++ * FIXME: GET_LOCK and DEFINE_LOCK never called for server_cnx
++ RELEASE_LOCK(server_cnx);
++ */
++#endif
++ return NULL;
++}
++
++/*
++ * iiop_connection_server_unix
++ *
++ * Outputs: 'server_cnx_unix'
++ *
++ * Side effects: Initializes 'server_cnx_unix' if not initialized.
++ *
++ * Description: Return a special IIOPConnection on which incoming connections
++ * come. If not already initialized, it creates the connection,
++ * otherwise it returns the existing one.
++ * This is
++ */
++IIOPConnection *
++iiop_connection_server_unix(const char *sockpath)
++{
++ IIOPConnection *server_cnx_unix;
++
++ g_assert(sockpath && *sockpath);
++
++ server_cnx_unix = g_new0(IIOPConnection, 1);
++
++ iiop_connection_init(server_cnx_unix, GIOP_CONNECTION_SERVER, IIOP_USOCK);
++
++ server_cnx_unix->is_serversock = TRUE;
++ GIOP_CONNECTION(server_cnx_unix)->fd = socket(AF_UNIX, SOCK_STREAM, 0);
++
++ if(GIOP_CONNECTION_GET_FD(server_cnx_unix) < 0) {
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, "iiop_connection_server_unix: socket_error: %s\n", strerror(errno));
++ goto failed;
++ }
++
++ strcpy(server_cnx_unix->u.usock.sun_path, sockpath);
++
++ server_cnx_unix->u.usock.sun_family = AF_UNIX;
++ if(bind(GIOP_CONNECTION_GET_FD(server_cnx_unix),
++ (struct sockaddr *)&server_cnx_unix->u.usock,
++ SUN_LEN(&server_cnx_unix->u.usock)) != 0) {
++ /* see the comment in iiop_connection_destroy switch as to why we
++ close it here. bad hack */
++ close(GIOP_CONNECTION_GET_FD(server_cnx_unix));
++ GIOP_CONNECTION(server_cnx_unix)->fd = -1;
++ goto failed;
++ }
++
++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx_unix), F_SETFD,
++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx_unix), F_GETFD, 0)
++ | FD_CLOEXEC);
++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx_unix), F_SETFL,
++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx_unix), F_GETFL, 0)
++ | O_NONBLOCK);
++
++ if(listen(GIOP_CONNECTION_GET_FD(server_cnx_unix), 5) != 0)
++ goto failed;
++
++ giop_connection_add_to_list(GIOP_CONNECTION(server_cnx_unix));
++ iiop_unix_socket_list = g_slist_prepend(iiop_unix_socket_list,
++ server_cnx_unix);
++
++ /*
++ * FIXME: GET_LOCK and DEFINE_LOCK never called for server_cnx_unix
++ RELEASE_LOCK(server_cnx_unix);
++ */
++
++ return server_cnx_unix;
++
++failed:
++ close(GIOP_CONNECTION_GET_FD(server_cnx_unix));
++ GIOP_CONNECTION(server_cnx_unix)->fd = -1;
++ giop_connection_free(GIOP_CONNECTION(server_cnx_unix));
++ server_cnx_unix = NULL;
++ /*
++ * FIXME: GET_LOCK and DEFINE_LOCK never called for server_cnx_unix
++ RELEASE_LOCK(server_cnx_unix);
++ */
++ return NULL;
++}
++
++/*
++ * iiop_unlink_unix_sockets(void)
++ *
++ * Inputs: None
++ * Outputs: None
++ *
++ * Side effects: Modifies iiop_unix_socket_list
++ * Global data structures used: iiop_unix_socket_list
++ *
++ * Description:
++ * Unlinks any Unix server sockets created.
++ * Called during program termination.
++ */
++static void
++iiop_unlink_unix_sockets(void)
++{
++ GSList *item;
++
++ for (item = iiop_unix_socket_list;
++ item; item = g_slist_next(item)) {
++ GIOPConnection *cnx;
++
++ cnx = GIOP_CONNECTION(item->data);
++ if(cnx->connection_class == GIOP_CONNECTION_SERVER)
++ unlink(IIOP_CONNECTION(cnx)->u.usock.sun_path);
++ }
++
++ if (iiop_unix_socket_list) {
++ g_slist_free(iiop_unix_socket_list);
++ iiop_unix_socket_list = NULL;
++ }
++}
++
++/*
++ * iiop_connection_get
++ *
++ * Inputs: 'host' - the hostname (or dotted quad) of the remote host that
++ * will be connected
++ * 'port' - the port number on the above host to connect to.
++ * 'existing_only' - don't create a new connection if
++ * an existing one with the specified host:port
++ * doesn't exist.
++ *
++ * Outputs: 'cnx' - the connection to the specified host:port, or
++ * NULL upon error.
++ *
++ * Description: Returns an IIOPConnection that is connected to the
++ * specified host:port. If a connection already exists to the
++ * host:port, just returns it. Otherwise, calls
++ * 'iiop_connection_new' to create a new connection
++ * to host:port.
++ */
++IIOPConnection *
++iiop_connection_get(const char *host, gushort port, gboolean existing_only)
++{
++ IIOPConnection *cnx = NULL, *tmp;
++ GList *link;
++
++ g_assert(host);
++ g_assert(port);
++
++ GET_LOCK(giop_connection_list);
++ for(link = giop_connection_list.list; link; link = link->next)
++ {
++ tmp = IIOP_CONNECTION(link->data);
++ if(GIOP_CONNECTION(tmp)->connection_type != GIOP_CONNECTION_IIOP)
++ continue;
++
++ if(!GIOP_CONNECTION(tmp)->is_valid)
++ continue;
++
++ if(GIOP_CONNECTION(tmp)->connection_class != GIOP_CONNECTION_CLIENT)
++ continue;
++
++ if(IIOP_CONNECTION(tmp)->icnxtype != IIOP_IPV4)
++ continue;
++
++ if(!strcmp(host, tmp->u.ipv4.hostname)
++ && htons(port) == tmp->u.ipv4.location.sin_port) {
++ cnx = tmp;
++ break;
++ }
++ }
++ RELEASE_LOCK(giop_connection_list);
++
++ if(!cnx && !existing_only)
++ cnx = iiop_connection_new(host, port);
++
++ return cnx;
++}
++
++
++/*
++ * iiop_connection_new
++ *
++ * Inputs: same meanings as in 'iiop_connection_get'
++ * Outputs: 'retval' - newly created IIOPConnection
++ *
++ * Description: Allocates and initializes a new IIOPConnection,
++ * turns 'host' into an IP address, and then makes a TCP
++ * connection to host:port. Adds it to the list of active
++ * connections.
++ */
++IIOPConnection *
++iiop_connection_new(const char *host, gushort port)
++{
++ IIOPConnection *retval;
++
++ g_return_val_if_fail(host != NULL && port != 0, NULL);
++
++ retval = g_new0(IIOPConnection, 1);
++
++ iiop_connection_init(retval, GIOP_CONNECTION_CLIENT, IIOP_IPV4);
++
++ GIOP_CONNECTION(retval)->fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
++ if(GIOP_CONNECTION_GET_FD(retval) < 0) {
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, "iiop_connection_new: socket_error: %s\n", strerror(errno));
++ goto failed;
++ }
++
++ retval->u.ipv4.hostname = g_strdup(host);
++
++ retval->u.ipv4.location.sin_port = htons(port);
++ retval->u.ipv4.location.sin_family = AF_INET;
++ if(!inet_aton(host, &retval->u.ipv4.location.sin_addr))
++ {
++ struct hostent *hent;
++ hent = gethostbyname(host);
++ if(!hent) {
++ /* a (char *)h_strerror(int) function would be nice here */
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, "iiop_connection_new: gethostbyname error: %d\n", h_errno);
++ goto failed;
++ }
++ memcpy(&retval->u.ipv4.location.sin_addr, hent->h_addr, (size_t) sizeof(retval->u.ipv4.location.sin_addr));
++ }
++ if(connect(GIOP_CONNECTION_GET_FD(retval), (struct sockaddr *)&retval->u.ipv4.location, sizeof(retval->u.ipv4.location)) < 0) {
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, "iiop_connection_new: connect error: %s\n", strerror(errno));
++ goto failed;
++ }
++
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug,
++ "iiop_connection_new connect [%d] to %s:%d\n",
++ GIOP_CONNECTION_GET_FD(retval),
++ host, (guint)port);
++
++
++ fcntl(GIOP_CONNECTION_GET_FD(retval), F_SETFD, FD_CLOEXEC);
++ fcntl(GIOP_CONNECTION_GET_FD(retval), F_SETFL,
++ fcntl(GIOP_CONNECTION_GET_FD(retval), F_GETFL, 0)
++ | O_NONBLOCK);
++
++ GIOP_CONNECTION(retval)->was_initiated = TRUE;
++ GIOP_CONNECTION(retval)->is_auth = TRUE;
++
++ giop_connection_add_to_list(GIOP_CONNECTION(retval));
++
++ return retval;
++
++failed:
++ close(GIOP_CONNECTION_GET_FD(retval));
++ GIOP_CONNECTION(retval)->fd = -1;
++ giop_connection_free(GIOP_CONNECTION(retval));
++ return NULL;
++}
++
++/*
++ * iiop_connection_unix_get
++ *
++ * Inputs: 'sockpath' - Of the format 'path'
++ *
++ * Outputs: 'cnx' - the connection to the specified path, or
++ * NULL upon error.
++ *
++ * Description: Returns an IIOPConnection that is connected to the
++ * specified UNIX socket, if possible. If a connection
++ * already exists, just returns it. Otherwise,
++ * calls 'iiop_connection_unix_new' to create a new
++ * connection to sockpath.
++ */
++IIOPConnection *
++iiop_connection_unix_get(const char *sockpath, gboolean existing_only)
++{
++ IIOPConnection *cnx = NULL, *tmp;
++ GList *link;
++
++ GET_LOCK(giop_connection_list);
++ for(link = giop_connection_list.list; link; link = link->next)
++ {
++ tmp = IIOP_CONNECTION(link->data);
++
++ if(GIOP_CONNECTION(tmp)->connection_type != GIOP_CONNECTION_IIOP)
++ continue;
++
++ if(!GIOP_CONNECTION(tmp)->is_valid)
++ continue;
++
++ if(GIOP_CONNECTION(tmp)->connection_class != GIOP_CONNECTION_CLIENT)
++ continue;
++
++ if(IIOP_CONNECTION(tmp)->icnxtype != IIOP_USOCK)
++ continue;
++
++ if(!strcmp(sockpath, tmp->u.usock.sun_path)) {
++ cnx = tmp;
++ break;
++ }
++ }
++ RELEASE_LOCK(giop_connection_list);
++
++ if(!cnx && !existing_only)
++ cnx = iiop_connection_unix_new(sockpath);
++
++ return cnx;
++}
++
++/*
++ * iiop_connection_unix_new
++ *
++ * Inputs:
++ *
++ * Outputs: 'retval' - newly created IIOPConnection, or NULL upon error
++ *
++ * Description: Creates a connection to a UNIX socket (if possible)
++ * Adds it to the list of active connections.
++ */
++static IIOPConnection *
++iiop_connection_unix_new(const char *sockpath)
++{
++ IIOPConnection *retval;
++
++ retval = g_new0(IIOPConnection, 1);
++
++ retval->u.usock.sun_family = AF_UNIX;
++
++ g_snprintf(retval->u.usock.sun_path,
++ sizeof(retval->u.usock.sun_path), "%s", sockpath);
++
++ iiop_connection_init(retval, GIOP_CONNECTION_CLIENT, IIOP_USOCK);
++
++ GIOP_CONNECTION(retval)->fd = socket(AF_UNIX, SOCK_STREAM, 0);
++ if(GIOP_CONNECTION_GET_FD(retval) < 0) {
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, "iiop_connection_new: socket_error: %s\n", strerror(errno));
++ goto failed;
++ }
++
++ if(connect(GIOP_CONNECTION_GET_FD(retval), (struct sockaddr *)&retval->u.usock, SUN_LEN(&retval->u.usock)) < 0) {
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, "iiop_connection_new: connect error: %s\n", strerror(errno));
++ goto failed;
++ }
++
++ GIOP_CONNECTION(retval)->was_initiated = TRUE;
++ GIOP_CONNECTION(retval)->is_auth = TRUE;
++
++ fcntl(GIOP_CONNECTION_GET_FD(retval), F_SETFD, FD_CLOEXEC);
++ fcntl(GIOP_CONNECTION_GET_FD(retval), F_SETFL,
++ fcntl(GIOP_CONNECTION_GET_FD(retval), F_GETFL, 0)
++ | O_NONBLOCK);
++
++ giop_connection_add_to_list(GIOP_CONNECTION(retval));
++
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug,
++ "iiop_connection_unix_new connect [%d] to %s\n",
++ GIOP_CONNECTION_GET_FD(retval),
++ sockpath);
++
++ return retval;
++
++failed:
++ close(GIOP_CONNECTION_GET_FD(retval));
++ GIOP_CONNECTION(retval)->fd = -1;
++ giop_connection_free(GIOP_CONNECTION(retval));
++ return NULL;
++}
++
++/*
++ * iiop_connection_server_accept
++ * Inputs: 'connection' - a server IIOPConnection.
++ *
++ * Description: Performs accept(), TCP wrapper, access checking and related
++ * duties on a connection
++ */
++int allow_severity = LOG_INFO, deny_severity = LOG_NOTICE;
++
++#if defined(HAVE_HOSTS_ACCESS) && defined(HAVE_TCPD_H)
++DEFINE_LOCK(tcp_wrappers_usage);
++
++#endif
++static void
++iiop_connection_server_accept(GIOPConnection *connection)
++{
++ struct sockaddr sock;
++ socklen_t n;
++ int newfd;
++ GIOPConnection *newcnx;
++
++// printk("iiop_conncetion_server_accept( %d )\n",
++// GIOP_CONNECTION_GET_FD(connection));
++
++ n = sizeof(sock);
++
++ switch(IIOP_CONNECTION(connection)->icnxtype) {
++ case IIOP_IPV4: sock.sa_family = AF_INET; break;
++ case IIOP_USOCK: sock.sa_family = AF_UNIX; break;
++ case IIOP_IPV6:
++#ifdef HAVE_IPV6
++ sock.sa_family = AF_INET6;
++#endif
++ break;
++ }
++
++ newfd = accept(GIOP_CONNECTION_GET_FD(connection), &sock, &n);
++
++#if defined(HAVE_HOSTS_ACCESS) && defined(HAVE_TCPD_H)
++ /* tcp wrappers access checking */
++ switch(IIOP_CONNECTION(connection)->icnxtype) {
++ case IIOP_IPV4:
++ {
++ struct request_info request;
++
++ GET_LOCK(tcp_wrappers_usage);
++
++ request_init(&request, RQ_DAEMON, argv0_val, RQ_FILE, newfd, 0);
++
++ fromhost(&request);
++ if(!hosts_access(&request)) {
++ syslog(deny_severity, "[orbit] refused connect from %s", eval_client(&request));
++ close(newfd); newfd = -1;
++ } else
++ syslog(allow_severity, "[orbit] connect from %s", eval_client(&request));
++
++ RELEASE_LOCK(tcp_wrappers_usage);
++ }
++ break;
++ default:
++ /* No access controls for these transports */
++ break;
++ }
++#endif
++
++ if(newfd >= 0) {
++ newcnx = GIOP_CONNECTION(iiop_connection_from_fd(newfd,
++ IIOP_CONNECTION(connection)));
++ GIOP_CONNECTION(newcnx)->orb_data = connection->orb_data;
++ switch(IIOP_CONNECTION(connection)->icnxtype) {
++ case IIOP_USOCK: newcnx->is_auth = TRUE; break;
++ default:
++ break;
++ }
++ }
++}
++
++/*
++ * iiop_connection_destroy
++ *
++ * Inputs: 'iiop_connection' - an IIOPConnection to be finalized
++ *
++ * Side effects: invalidates 'iiop_connection' for use as an IIOPConnection
++ *
++ * Description: Performs the IIOP-specific parts of connection shutdown,
++ * including sending a CLOSECONNECTION message to the remote side.
++ */
++static void
++iiop_connection_destroy(IIOPConnection *iiop_connection)
++{
++ const GIOPMessageHeader mh = {"GIOP", {1,0}, FLAG_ENDIANNESS,
++ GIOP_CLOSECONNECTION, 0};
++
++ switch(iiop_connection->icnxtype) {
++ case IIOP_IPV4:
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug,
++ "iiop_connection_destroy connect [%d] of %s:%d\n",
++ GIOP_CONNECTION_GET_FD(iiop_connection),
++ iiop_connection->u.ipv4.hostname,
++ ntohs(iiop_connection->u.ipv4.location.sin_port));
++ g_free(iiop_connection->u.ipv4.hostname);
++ break;
++ case IIOP_IPV6:
++#ifdef HAVE_IPV6
++ g_free(iiop_connection->u.ipv6.hostname);
++#else
++ g_warning("IPv6 unsupported, can't free it!");
++#endif
++ break;
++ case IIOP_USOCK:
++ /* why do we check if fd is > 0 here?
++ the orb code tries to reuse existing socket connection points.
++ If binding to any of those fails because another process is using it,
++ we don't want to unlink the other server's socket!
++ if the bind fails, iiop_connection_server_unix closes the fd for us */
++ if(GIOP_CONNECTION(iiop_connection)->connection_class == GIOP_CONNECTION_SERVER
++ && GIOP_CONNECTION(iiop_connection)->fd >= 0)
++ unlink(iiop_connection->u.usock.sun_path);
++ break;
++ default:
++ break;
++ }
++
++ if(GIOP_CONNECTION_GET_FD(iiop_connection) >= 0) {
++ if(GIOP_CONNECTION(iiop_connection)->is_valid
++ && !GIOP_CONNECTION(iiop_connection)->was_initiated)
++ {
++ write(GIOP_CONNECTION_GET_FD(iiop_connection), &mh, sizeof(mh));
++ }
++
++ shutdown(GIOP_CONNECTION_GET_FD(iiop_connection), 2);
++ close(GIOP_CONNECTION_GET_FD(iiop_connection));
++ GIOP_CONNECTION(iiop_connection)->fd = -1;
++ }
++}
++
++static int giop_nloops = 0;
++
++void giop_main_quit(void) { giop_nloops--; }
++
++void
++giop_main(void)
++{
++ int looplevel;
++
++ looplevel = ++giop_nloops;
++
++ while(giop_nloops > 0) {
++
++ giop_main_iterate(TRUE);
++
++ if(giop_nloops != looplevel) {
++ giop_nloops = --looplevel;
++ return;
++ }
++ }
++}
++
++GIOPRecvBuffer *
++giop_main_next_message(gboolean blocking)
++{
++ return giop_main_next_message_2(blocking, NULL);
++}
++
++GIOPRecvBuffer *
++giop_main_next_message_2(gboolean blocking,
++ GIOPConnection *monitor)
++{
++ GIOPConnection *connection;
++ GIOPRecvBuffer *recv_buffer = NULL;
++
++ do {
++ recv_buffer = giop_received_list_pop();
++// printk("giop_main_next_message_2 : recv_buffer = 0x%08X\n", recv_buffer);
++ if(recv_buffer)
++ break;
++
++ connection = giop_check_connections(blocking);
++// printk("giop_main_next_message_2 : connection = 0x%08X\n", connection);
++ if(!connection)
++ {
++ return NULL;
++ }
++
++ if(GIOP_CONNECTION_GET_FD(connection) < 0) {
++ g_assert(!"connection has -ve fd!");
++ }
++
++// printk("giop_main_next_message_2 : connection class = %d\n",
++// connection->connection_class);
++ if(connection->connection_class == GIOP_CONNECTION_SERVER)
++ iiop_connection_server_accept(connection);
++ else
++ recv_buffer = giop_recv_message_buffer_use(connection);
++
++ if(monitor && !monitor->is_valid)
++ {
++ return NULL;
++ }
++
++ } while(!recv_buffer);
++
++ return recv_buffer;
++}
++
++void
++giop_main_handle_connection(GIOPConnection *connection)
++{
++ GIOPRecvBuffer *recv_buffer;
++
++ //printk("giop_main_handle_connection\n");
++
++ g_return_if_fail(connection != NULL);
++ g_return_if_fail(connection->is_valid);
++
++ if(connection->connection_class == GIOP_CONNECTION_SERVER) {
++ iiop_connection_server_accept(connection);
++ return;
++ } else
++ recv_buffer = giop_recv_message_buffer_use(connection);
++
++ if(recv_buffer) {
++ if(IIOPIncomingMessageHandler)
++ IIOPIncomingMessageHandler(recv_buffer);
++ else
++ giop_received_list_push(recv_buffer);
++ }
++}
++
++/*
++ * giop_main_handle_connection_exception
++ *
++ * Input: GIOPConnection *connection
++ *
++ * Output:
++ *
++ * Side effects: invalidates connection
++ *
++ * Description:
++ * When poll() or select() indicates that a file descriptor
++ * has been closed at the remote end, we must invalidate the associated
++ * GIOPConnection structure.
++ */
++void
++giop_main_handle_connection_exception(GIOPConnection *connection)
++{
++ g_return_if_fail(connection != NULL);
++ g_return_if_fail(connection->is_valid);
++
++// printk("giop_main_handle_connection_exception(0x%X)\n", GIOP_CONNECTION_GET_FD(connection));
++
++ giop_connection_ref(connection);
++
++ giop_connection_remove_from_list(connection);
++
++ shutdown(GIOP_CONNECTION_GET_FD(connection), 2);
++ close(GIOP_CONNECTION_GET_FD(connection));
++ GIOP_CONNECTION(connection)->fd = -1;
++ connection->is_valid = FALSE;
++
++ if(connection->incoming_msg) {
++ giop_recv_buffer_unuse(connection->incoming_msg);
++ connection->incoming_msg = NULL;
++ }
++
++ giop_connection_unref(connection);
++}
++
++/*
++ * giop_main_iterate
++ *
++ * Input: 'blocking' - flag to indicate whether to wait for incoming
++ * messages (TRUE), or whether to return immediately if no
++ * incoming messages are available (FALSE).
++ * Output: None
++ * Description:
++ * Gets the next message into recv_buffer (see
++ * giop_main_next_message) If we have a handler for incoming
++ * messages, then pass recv_buffer to the handler (handler
++ * becomes the new owner of recv_buffer's contents). Otherwise,
++ * tosses it onto the list of received-but-unprocessed buffers.
++ *
++ * Warnings:
++ * If you don't have an IIOPIncomingMessageHandler set, you're
++ * probably really screwed in the long run.
++ */
++void
++giop_main_iterate(gboolean blocking)
++{
++ GIOPRecvBuffer *recv_buffer;
++
++// printk("giop_main_iterate: blocking: %d\n", blocking);
++schedule();
++
++ recv_buffer = giop_main_next_message(blocking);
++
++// printk("giop_main_iterate: recv_buffer = 0x%08X\n", recv_buffer);
++
++ if(recv_buffer) {
++ if(IIOPIncomingMessageHandler)
++ IIOPIncomingMessageHandler(recv_buffer);
++ else
++ giop_received_list_push(recv_buffer);
++ }
++}
++
++/*
++ * giop_check_connections
++ *
++ * Inputs: 'block_for_reply' - If no incoming data is immediately available
++ * should this routine wait for incoming data (TRUE) or return
++ * immediately (FALSE).
++ *
++ * Outputs: 'connection' - the first connection that has incoming
++ * data available for reading (supposedly a GIOP message, but
++ * could be anything).
++ *
++ * Side effects: Removes closed connections from the active list.
++ *
++ * Global data structures used: giop_connection_list
++ *
++ * Description: Does a poll or select (OS-dependant) on the list of file
++ * descriptors in giop_connection_list.
++ *
++ * If a file descriptor has been closed, call
++ * giop_connection_handle_exception() on it and (as
++ * appropriated by 'block_for_reply') either return
++ * NULL or do another poll/select.
++ *
++ * If a file descriptor has data available for
++ * reading, find the associated GIOPConnection (using
++ * giop_connection_list.fd_to_connection_mapping) and
++ * return that.
++ *
++ */
++GIOPConnection *
++giop_check_connections(gboolean block_for_reply)
++{
++ GIOPConnection *connection = NULL;
++ int pollret;
++ int numcnx_checks;
++ int i;
++#ifndef USE_POLL
++ fd_set selectset_rd, selectset_ex;
++
++ struct timeval immediate_timeout = {0,0};
++#endif
++
++// printk("giop_check_connections\n");
++
++ do_read_msg:
++
++ if(!giop_connection_list.list)
++ {
++// printk("giop_check_connections : list = NULL\n");
++ BUG();
++ return NULL;
++ }
++
++#if 0
++ giop_connection_list_recreate(); /* easiest way to get valid
++ select sets... */
++#endif
++
++#ifdef USE_POLL
++ numcnx_checks = giop_connection_list.pollset->len;
++#else
++ memcpy(&selectset_rd, &giop_connection_list.selectset_rd,
++ sizeof(selectset_rd));
++ memcpy(&selectset_ex, &giop_connection_list.selectset_ex,
++ sizeof(selectset_ex));
++
++ numcnx_checks = giop_connection_list.max_fd+1;
++#endif
++
++ restart:
++#ifdef USE_POLL
++ pollret = poll((struct pollfd *)giop_connection_list.pollset->data,
++ giop_connection_list.pollset->len,
++ block_for_reply?-1:0);
++
++#if KORBIT_DEBUG_WRITING
++{
++ int ix;
++ struct pollfd *fds = (struct pollfd *)giop_connection_list.pollset->data;
++// printk("back from poll(#fds = %d, block = %d) = %d)\n", giop_connection_list.pollset->len, block_for_reply, pollret);
++// for (ix = 0; ix < giop_connection_list.pollset->len; ix++)
++ // printk(" [fd = 0x%X, event = 0x%X, revent = 0x%X]\n",
++// fds[ix].fd, fds[ix].events, fds[ix].revents);
++
++}
++#endif /* KORBIT_DEBUG_WRITING */
++
++
++# else /* !USE_POLL */
++
++ {
++ pollret = select (giop_connection_list.max_fd + 1,
++ &selectset_rd,
++ NULL, &selectset_ex,
++ block_for_reply?NULL:&immediate_timeout);
++ }
++# endif /* !USE_POLL */
++
++// printk("giop_check_connections : pollret == %d\n", pollret);
++ if(pollret <= 0) {
++ if(pollret < 0) {
++ if(errno == EINTR)
++ goto restart;
++ else
++ g_warning("Error code from select/poll: %s", g_strerror(errno));
++ } else
++ return NULL;
++ }
++
++ /* Check for data to be read on the fd's.
++ Note we have to do the hangup/exception checking in a separate loop,
++ because there may be data waiting to be read on a connection that the
++ other end has closed. */
++ for(i = 0; i < numcnx_checks; i++) {
++ struct fd_hash_elem *el;
++
++#ifdef USE_POLL
++ struct pollfd *p =
++ &g_array_index(giop_connection_list.pollset,
++ struct pollfd,
++ i);
++ g_assert(p->fd <= giop_connection_list.max_fd);
++#ifndef __KORBIT__
++ connection = giop_connection_list.fd_to_connection_mapping->pdata[p->fd];
++#else
++ el = g_hash_table_lookup(giop_connection_list.fd_to_connection_mapping,
++ &(p->fd));
++ if (el)
++ connection = el->cnx;
++#endif
++ if(p->revents & POLLIN)
++ goto got_connection;
++#else
++#ifndef __KORBIT__
++ connection = giop_connection_list.fd_to_connection_mapping->pdata[i];
++#else
++ el = g_hash_table_lookup(giop_connection_list.fd_to_connection_mapping,
++ &i);
++ if (el)
++ connection = el->cnx;
++#endif
++ if (FD_ISSET(i, &selectset_rd)) {
++ goto got_connection;
++ }
++#endif
++ }
++
++ /* Handle fd exceptions */
++ for(i = 0; i < numcnx_checks; i++)
++ {
++ struct fd_hash_elem *el;
++#ifdef USE_POLL
++ struct pollfd *p =
++ &g_array_index(giop_connection_list.pollset,
++ struct pollfd,
++ i);
++
++ g_assert(p->fd <= giop_connection_list.max_fd);
++ if(p->revents & (POLLHUP|POLLNVAL)) {
++#ifndef __KORBIT__
++ connection = giop_connection_list.fd_to_connection_mapping->pdata[p->fd];
++#else
++ el = g_hash_table_lookup(giop_connection_list.fd_to_connection_mapping,
++ &(p->fd));
++ if (el)
++ connection = el->cnx;
++#endif
++ giop_main_handle_connection_exception(connection);
++ }
++#else /* !USE_POLL */
++ if(FD_ISSET(i, &selectset_ex)) {
++#ifndef __KORBIT__
++ connection = giop_connection_list.fd_to_connection_mapping->pdata[i];
++#else
++ el = g_hash_table_lookup(giop_connection_list.fd_to_connection_mapping,
++ &i);
++ if (el)
++ connection = el->cnx;
++#endif
++ giop_main_handle_connection_exception(connection);
++ }
++#endif /* !USE_POLL */
++ }
++
++ /* Only reached if we didn't find a connection to read data from */
++ if(block_for_reply)
++ goto do_read_msg;
++
++ got_connection:
++// printk("giop_check_connections : got connection\n");
++ return connection;
++}
++
+diff -urN linux-2.4.1/net/korbit/IIOP/encoders.c linux-2.4.1-korbit/net/korbit/IIOP/encoders.c
+--- linux-2.4.1/net/korbit/IIOP/encoders.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/encoders.c Thu Feb 1 11:46:51 2001
+@@ -0,0 +1,46 @@
++#include "config.h"
++#include <string.h>
++#include "IIOP.h"
++
++ENCODER_DEC(IOP_ServiceContext)
++{
++ APA(&mem->context_id, sizeof(mem->context_id));
++ ENCODER_CALL(CORBA_sequence_octet, &mem->context_data);
++}
++
++ENCODER_DEC(IOP_ServiceContextList)
++{
++ int i;
++
++ if(!mem)
++ {
++ APA((gpointer)giop_scratch_space, sizeof(mem->_length));
++ return;
++ }
++
++ APA(&mem->_length, sizeof(mem->_length));
++
++ for(i = 0; i < mem->_length; i++)
++ ENCODER_CALL(IOP_ServiceContext, &mem->_buffer[i]);
++}
++
++ENCODER_DEC(CORBA_sequence_octet)
++{
++ if(!mem)
++ {
++ APA((gpointer)giop_scratch_space, sizeof(mem->_length));
++ return;
++ }
++
++ APIA(&mem->_length, sizeof(mem->_length));
++ if(mem->_length > 0)
++ AP(mem->_buffer, mem->_length);
++}
++
++ENCODER_DEC(CORBA_char)
++{
++ GIOP_unsigned_long len = strlen(mem) + 1;
++
++ APIA(&len, sizeof(len));
++ AP(mem, len);
++}
+diff -urN linux-2.4.1/net/korbit/IIOP/giop-msg-buffer.c linux-2.4.1-korbit/net/korbit/IIOP/giop-msg-buffer.c
+--- linux-2.4.1/net/korbit/IIOP/giop-msg-buffer.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/giop-msg-buffer.c Fri Feb 2 01:23:46 2001
+@@ -0,0 +1,1443 @@
++/* The big picture:
++ * For every outgoing request, we have to have the network-ready data
++ * somewhere in memory.
++ *
++ * Using writev, any pieces that do not need endian conversion can
++ * be written in-place.
++ *
++ * The pieces that do need endian conversion can be put into one or more
++ * buffers.
++ *
++ * WHOA WHOA newsflash
++ * Because IIOP lets the message sender specify the endianness,
++ * we do not need to do endian conversion _ever_! The receiver can do all
++ * conversions if need be, or if they are the same endianness as sender they
++ * can just pull it in right off the wire :)
++ *
++ */
++
++#include "config.h"
++#include "iiop-endianP.h"
++#include <string.h>
++#include <unistd.h>
++#include <stdio.h>
++#include <errno.h>
++#include <sys/types.h>
++#include <fcntl.h>
++#include <string.h>
++
++#ifdef HAVE_POLL
++# include <sys/poll.h>
++#else
++# include <sys/types.h>
++# include <sys/time.h>
++#endif
++#include "IIOP.h"
++#include "IIOP-private.h"
++
++#ifdef HAVE_LIMITED_WRITEV
++#define writev g_writev
++#endif
++
++/*
++#ifdef O_NONBLOCK
++#undef O_NONBLOCK
++#endif
++#define O_NONBLOCK 0
++*/
++
++
++/* type defs */
++
++#ifdef __GNUC__
++#define PACKED __attribute__((packed))
++#else
++#define PACKED
++#endif
++
++/*
++ * Overlaps with struct _GIOPMessageHeader on purpose
++ * - we save time because this stuff never changes
++ */
++struct _GIOPMessageHeaderConstants {
++ GIOP_char magic[4];
++ GIOP_char GIOP_version[2];
++ GIOP_octet flags;
++} PACKED;
++
++/* functions */
++static gint giop_recv_decode_message(GIOPRecvBuffer *buf);
++static gboolean num_on_list(GIOP_unsigned_long num,
++ const GIOP_unsigned_long *request_ids,
++ GIOP_unsigned_long req_count);
++static gint giop_recv_reply_decode_message(GIOPRecvBuffer *buf);
++static gint giop_recv_request_decode_message(GIOPRecvBuffer *buf);
++static gint giop_recv_locate_reply_decode_message(GIOPRecvBuffer *buf);
++static gint giop_recv_locate_request_decode_message(GIOPRecvBuffer *buf);
++static GIOPRecvBuffer *giop_received_list_check_reply(GIOP_unsigned_long request_id);
++
++#ifdef NOT_REENTRANT
++extern DEFINE_LOCK(iiop_connection_list);
++#endif
++GList *iiop_connection_list = NULL;
++
++/* global variables */
++char giop_scratch_space[2048];
++
++static const struct _GIOPMessageHeaderConstants
++giop_message_header_constants = {
++ "GIOP",
++ {1,0},
++ FLAG_ENDIANNESS,
++};
++
++struct iovec
++giop_first_message_vec = {NULL,
++ sizeof(struct _GIOPMessageHeaderConstants)};
++
++DEFINE_LOCK(sendbufferlist);
++GSList *sendbufferlist = NULL;
++
++DEFINE_LOCK(recvbufferlist);
++GSList *recvbufferlist = NULL;
++
++DEFINE_LOCK(incoming_bufs);
++GList *incoming_bufs = NULL; /* List of incoming messages that had to be
++ shunted aside */
++
++DEFINE_LOCK(sendbuffers);
++DEFINE_LOCK(recvbuffers);
++GMemChunk *sendbuffers = NULL, *recvbuffers = NULL;
++
++DEFINE_LOCK(request_id_counter);
++GIOP_unsigned_long request_id_counter;
++
++#if 0
++inline
++void giop_message_buffer_append_iovec(GIOPMessageBuffer *msgbuf,
++ const struct iovec *iovec)
++{
++ /* g_print("Appending iovec %d bytes @ %p\n", iovec->iov_len, iovec->iov_base); */
++ g_array_append_val(msgbuf->iovecs, *iovec);
++}
++#else
++#define giop_message_buffer_append_iovec(msgbuf, iovec) g_array_append_val((msgbuf)->iovecs, *(iovec))
++#endif
++
++void
++giop_message_buffer_init(void)
++{
++ giop_first_message_vec.iov_base = (gpointer)&giop_message_header_constants;
++ INIT_LOCK(sendbufferlist);
++ INIT_LOCK(recvbufferlist);
++ request_id_counter = 1;
++ INIT_LOCK(request_id_counter);
++
++ INIT_LOCK(sendbuffers);
++ sendbuffers = g_mem_chunk_create(GIOPSendBuffer, 2, G_ALLOC_ONLY);
++ INIT_LOCK(recvbuffers);
++ recvbuffers = g_mem_chunk_create(GIOPRecvBuffer, 2, G_ALLOC_ONLY);
++}
++
++static void
++giop_message_buffer_new(GIOPMessageBuffer *buf)
++{
++ buf->iovecs = g_array_new(FALSE, FALSE, sizeof(struct iovec));
++}
++
++#define STRUCT_OFFSET(t, f) ((int) ((char*) &((t*) 0)->f))
++
++/* Send buffers only */
++static GIOPSendBuffer *
++giop_send_buffer_new(void)
++{
++ GIOPSendBuffer *msgbuf;
++ struct iovec firstvec;
++
++ GET_LOCK(sendbuffers);
++ msgbuf = g_chunk_new(GIOPSendBuffer, sendbuffers);
++ RELEASE_LOCK(sendbuffers);
++
++ giop_message_buffer_new(GIOP_MESSAGE_BUFFER(msgbuf));
++
++ giop_message_buffer_append_iovec(GIOP_MESSAGE_BUFFER(msgbuf),
++ &giop_first_message_vec);
++
++ firstvec.iov_base = &(GIOP_MESSAGE_BUFFER(msgbuf)->message_header.message_type);
++ firstvec.iov_len = sizeof(GIOPMessageHeader)
++ - STRUCT_OFFSET(GIOPMessageHeader, message_type);
++ GIOP_MESSAGE_BUFFER(msgbuf)->message_header.message_size = 0;
++
++ msgbuf->indirects = g_mem_chunk_create(char[GIOP_INDIRECT_CHUNK_SIZE],
++ 2, G_ALLOC_ONLY);
++
++ giop_message_buffer_append_iovec(GIOP_MESSAGE_BUFFER(msgbuf), &firstvec);
++
++ return msgbuf;
++}
++
++gint
++giop_send_buffer_write(GIOPSendBuffer *send_buffer)
++{
++ gulong nvecs;
++ glong res, sum, t;
++ struct iovec *curvec;
++ int fd;
++ GIOPConnection *cnx;
++ gint retval = -1;
++
++// printf("giop_send_buffer_write\n");
++
++ cnx = GIOP_MESSAGE_BUFFER(send_buffer)->connection;
++ if(!cnx->is_valid)
++ return -1;
++
++ fd = GIOP_CONNECTION_GET_FD(cnx);
++ nvecs = GIOP_MESSAGE_BUFFER(send_buffer)->iovecs->len;
++ curvec = (struct iovec *)GIOP_MESSAGE_BUFFER(send_buffer)->iovecs->data;
++
++#if defined(ORBIT_DEBUG) && 0
++ g_print("Message of length %d looks like:\n",
++ GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_size);
++{ int i = 0;
++ for(sum = 0; i < nvecs; i++) {
++ sum += curvec[i].iov_len;
++ g_print(" [%p, %d]: %d\n", curvec[i].iov_base, curvec[i].iov_len,
++ sum);
++ }
++}
++#endif
++
++ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
++ res = writev(fd, curvec, nvecs);
++// printk("writev wrote %d byte\n", res);
++
++ sum = (GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_size + sizeof(GIOPMessageHeader));
++ if(res < sum) {
++ if(res < 0) {
++//printf("writev returned %d\n", res);
++ if(errno != EAGAIN) {
++ giop_main_handle_connection_exception(cnx);
++ goto out;
++ }
++
++ res = 0;
++ }
++
++ /* wrote 7, iovecs 3, 2, 2, 4:
++ 0 + 3 !> 7
++ 3 + 2 !> 7
++ 5 + 2 !> 7
++ */
++
++ for(t = 0; ; t += curvec->iov_len, curvec++, nvecs--) {
++ if((t + curvec->iov_len) > res)
++ break;
++ }
++ if((res - t) > 0) {
++ curvec->iov_len -= (res - t);
++ curvec->iov_base = (gpointer)((char *)curvec->iov_base + (res - t));
++ }
++
++
++ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
++ t = writev(fd, curvec, nvecs);
++
++ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
++
++ if((t < 0) || ((res + t) < sum)) {
++//printf("crap, t = %d res = %d sum = %d\n", t, res, sum);
++ giop_main_handle_connection_exception(cnx);
++ goto out;
++ }
++ }
++
++ retval = 0;
++
++ out:
++
++ return retval;
++}
++
++static GIOPSendBuffer *
++giop_send_buffer_use(GIOPConnection *connection)
++{
++ GIOPSendBuffer *retval;
++
++ if(!connection->is_valid)
++ return NULL;
++
++ GET_LOCK(sendbufferlist);
++
++ if(sendbufferlist)
++ {
++ GSList *head;
++
++ retval = sendbufferlist->data;
++
++ head = sendbufferlist;
++ sendbufferlist = g_slist_remove_link(sendbufferlist, sendbufferlist);
++ g_slist_free_1 (head);
++
++ g_array_set_size(GIOP_MESSAGE_BUFFER(retval)->iovecs, 2);
++ GIOP_MESSAGE_BUFFER(retval)->message_header.message_size = 0;
++ }
++ else
++ retval = giop_send_buffer_new();
++
++ RELEASE_LOCK(sendbufferlist);
++
++ giop_connection_ref(connection);
++ GIOP_MESSAGE_BUFFER(retval)->connection = connection;
++
++ g_mem_chunk_reset(retval->indirects);
++ retval->indirect = g_chunk_new(gpointer, retval->indirects);
++#ifdef ORBIT_DEBUG
++ memset(retval->indirect, '\xFE', GIOP_INDIRECT_CHUNK_SIZE);
++#endif
++ retval->indirect_used = 0;
++
++ return retval;
++}
++
++GIOPSendBuffer *
++giop_send_reply_buffer_use(GIOPConnection *connection,
++ const IOP_ServiceContextList *service_context,
++ GIOP_unsigned_long request_id,
++ GIOPReplyStatusType reply_status)
++{
++ GIOPSendBuffer *send_buffer;
++
++ send_buffer = giop_send_buffer_use(connection);
++
++ if(!send_buffer)
++ return NULL;
++
++ GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_type = GIOP_REPLY;
++
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer),
++ sizeof(GIOP_unsigned_long));
++ if(!service_context) {
++ static const GIOP_unsigned_long sc_zero_int = 0;
++ AP(&sc_zero_int, sizeof(service_context->_length));
++ } else {
++ int i, n;
++ n = service_context->_length;
++ AP(&service_context->_length, sizeof(service_context->_length));
++ for(i = 0; i < n; i++) {
++ int j, o;
++ CORBA_sequence_octet *seqo;
++
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer),
++ sizeof(GIOP_unsigned_long));
++ AP(&service_context->_buffer[i].context_id,
++ sizeof(service_context->_buffer[i].context_id));
++ seqo = &service_context->_buffer[i].context_data;
++ o = seqo->_length;
++ AP(&seqo->_length, sizeof(GIOP_unsigned_long));
++ for(j = 0; j < o; j++)
++ AP(seqo->_buffer, seqo->_length);
++ }
++ }
++ send_buffer->message.u.reply.request_id = request_id;
++ send_buffer->message.u.reply.reply_status = reply_status;
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer),
++ sizeof(GIOP_unsigned_long));
++ AP(&send_buffer->message.u.reply.request_id,
++ sizeof(GIOP_unsigned_long));
++ AP(&send_buffer->message.u.reply.reply_status,
++ sizeof(GIOP_unsigned_long));
++
++ return send_buffer;
++}
++
++GIOPSendBuffer *
++giop_send_locate_reply_buffer_use(GIOPConnection *connection,
++ GIOP_unsigned_long request_id,
++ GIOPLocateStatusType locate_reply_status)
++{
++ GIOPSendBuffer *send_buffer;
++
++ send_buffer = giop_send_buffer_use(connection);
++
++ if(!send_buffer)
++ return NULL;
++
++ GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_type = GIOP_LOCATEREPLY;
++
++ APIA(&request_id, sizeof(request_id));
++ APIA(&locate_reply_status, sizeof(locate_reply_status));
++
++ return send_buffer;
++}
++
++GIOPSendBuffer *
++giop_send_request_buffer_use(GIOPConnection *connection,
++ const IOP_ServiceContextList *service_context,
++ GIOP_unsigned_long request_id,
++ GIOP_boolean response_expected,
++ const struct iovec *object_key_vec,
++ const struct iovec *operation_vec,
++ const struct iovec *principal_vec)
++{
++ GIOPSendBuffer *send_buffer;
++#if 0
++ static const struct {
++ CORBA_unsigned_long _length;
++ char _buffer[7];
++ } default_principal = { sizeof("nobody"), "nobody" };
++ static const struct iovec default_principal_vec =
++ {(void *)&default_principal,
++ sizeof(CORBA_unsigned_long) + sizeof("nobody")};
++#endif
++
++ if (!connection)
++ return NULL;
++ if(!object_key_vec)
++ return NULL;
++ if(!operation_vec)
++ return NULL;
++
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug,
++ "Sending request %s id %d to %s\n",
++ ((guchar *)operation_vec->iov_base) + 4,
++ request_id, ((guchar *)object_key_vec->iov_base) + 4);
++
++ send_buffer = giop_send_buffer_use(connection);
++
++ if (!send_buffer)
++ return NULL;
++
++ GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_type = GIOP_REQUEST;
++
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer),
++ sizeof(GIOP_unsigned_long));
++ if(!service_context) {
++ static const GIOP_unsigned_long sc_zero_int = 0;
++ AP(&sc_zero_int, sizeof(GIOP_unsigned_long));
++ } else {
++ int i, n;
++ n = service_context->_length;
++ AP(&service_context->_length, sizeof(service_context->_length));
++ for(i = 0; i < n; i++) {
++ int j, o;
++ CORBA_sequence_octet *seqo;
++
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer),
++ sizeof(GIOP_unsigned_long));
++ AP(&service_context->_buffer[i].context_id,
++ sizeof(service_context->_buffer[i].context_id));
++ seqo = &service_context->_buffer[i].context_data;
++ o = seqo->_length;
++ AP(&seqo->_length, sizeof(GIOP_unsigned_long));
++ for(j = 0; j < o; j++)
++ AP(seqo->_buffer, seqo->_length);
++ }
++ }
++ send_buffer->message.u.request.request_id = request_id;
++ send_buffer->message.u.request.response_expected = response_expected;
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer),
++ sizeof(GIOP_unsigned_long));
++ AP(&send_buffer->message.u.request.request_id,
++ sizeof(GIOP_unsigned_long));
++ AP(&send_buffer->message.u.request.response_expected,
++ sizeof(GIOP_boolean));
++#if 0
++ API(&response_expected, 1);
++ AP((gpointer)giop_scratch_space, 3);
++#endif
++
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer),
++ sizeof(CORBA_unsigned_long));
++ giop_message_buffer_append_iovec(GIOP_MESSAGE_BUFFER(send_buffer),
++ object_key_vec);
++ GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_size +=
++ object_key_vec->iov_len;
++
++ /*
++ * We can know the length at compile time - don't calculate it at runtime
++ * if we can help it :)
++ */
++ /* ENCODER_CALL(CORBA_string, (CORBA_string *)operation); */
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer),
++ sizeof(CORBA_unsigned_long));
++ giop_message_buffer_append_iovec(GIOP_MESSAGE_BUFFER(send_buffer),
++ operation_vec);
++ GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_size +=
++ operation_vec->iov_len;
++
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer),
++ sizeof(CORBA_unsigned_long));
++ giop_message_buffer_append_iovec(GIOP_MESSAGE_BUFFER(send_buffer),
++ principal_vec);
++ GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_size +=
++ principal_vec->iov_len;
++
++ return send_buffer;
++}
++
++GIOPSendBuffer *
++giop_send_locate_request_buffer_use(GIOPConnection *connection,
++ GIOP_unsigned_long request_id,
++ const struct iovec *object_key_vec)
++{
++ GIOPSendBuffer *send_buffer;
++
++ if (!connection)
++ return NULL;
++ if (!object_key_vec)
++ return NULL;
++
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug,
++ "Sending locate request id %d to %s\n",
++ request_id, ((guchar *)object_key_vec->iov_base) + 4);
++
++ send_buffer = giop_send_buffer_use(connection);
++
++ if (!send_buffer)
++ return NULL;
++
++ GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_type = GIOP_LOCATEREQUEST;
++
++ APIA(&request_id, sizeof(request_id));
++
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer),
++ sizeof(CORBA_unsigned_long));
++ giop_message_buffer_append_iovec(GIOP_MESSAGE_BUFFER(send_buffer),
++ object_key_vec);
++ GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_size +=
++ object_key_vec->iov_len;
++
++ return send_buffer;
++}
++
++void
++giop_send_buffer_unuse(GIOPSendBuffer *send_buffer)
++{
++ if (send_buffer == NULL)
++ return;
++
++ giop_connection_unref(GIOP_MESSAGE_BUFFER(send_buffer)->connection);
++
++ GET_LOCK(sendbufferlist);
++ sendbufferlist = g_slist_prepend(sendbufferlist, send_buffer);
++ RELEASE_LOCK(sendbufferlist);
++}
++
++gulong
++giop_message_buffer_do_alignment(GIOPMessageBuffer *buffer,
++ gulong align_for)
++{
++ struct iovec newvec;
++ struct iovec *lastvec;
++ guint alignme;
++ gulong real_msgsize;
++ gulong align_diff;
++
++ if(align_for < 2) return 0;
++ if(align_for >
++ MAX(sizeof(GIOP_long_long),sizeof(GIOP_long_double)))
++ align_for = MAX(sizeof(GIOP_long_long), sizeof(GIOP_long_double));
++
++ real_msgsize = buffer->message_header.message_size+sizeof(GIOPMessageHeader);
++
++ alignme = (gulong)ALIGN_ADDRESS(real_msgsize, align_for);
++
++ align_diff = alignme - real_msgsize;
++ if(align_diff > 0)
++ {
++ lastvec = (struct iovec *)(buffer->iovecs->data)
++ + buffer->iovecs->len - 1;
++
++ if(lastvec->iov_base == giop_scratch_space)
++ {
++ newvec.iov_len = align_diff;
++ lastvec->iov_len += align_diff;
++ buffer->message_header.message_size += align_diff;
++ }
++ else
++ {
++ newvec.iov_base = (gpointer)giop_scratch_space;
++ newvec.iov_len = align_diff;
++ buffer->message_header.message_size += align_diff;
++ giop_message_buffer_append_iovec(buffer, &newvec);
++ }
++ return newvec.iov_len;
++ }
++ else
++ return 0;
++}
++
++void
++giop_message_buffer_append_mem_a(GIOPMessageBuffer *buffer,
++ gconstpointer mem_region,
++ gulong mem_region_length)
++{
++ struct iovec newvec;
++ struct iovec *lastvec;
++ gint alignfor;
++
++ alignfor = giop_message_buffer_do_alignment(buffer, mem_region_length);
++
++ lastvec = (struct iovec *)(buffer->iovecs->data) +
++ + buffer->iovecs->len - 1;
++
++ if((mem_region == giop_scratch_space && lastvec->iov_base == giop_scratch_space)
++ || (alignfor == 0 && (((guchar *)lastvec->iov_base) + lastvec->iov_len) == mem_region))
++ {
++ lastvec->iov_len += mem_region_length;
++ }
++ else
++ {
++ newvec.iov_base = (gpointer)mem_region;
++ newvec.iov_len = mem_region_length;
++ giop_message_buffer_append_iovec(buffer, &newvec);
++ }
++
++ buffer->message_header.message_size += mem_region_length;
++}
++
++void
++giop_message_buffer_append_mem(GIOPMessageBuffer *buffer,
++ gconstpointer mem_region,
++ gulong mem_region_length)
++{
++ struct iovec newvec;
++ struct iovec *lastvec;
++
++ lastvec = (struct iovec *)(buffer->iovecs->data)
++ + buffer->iovecs->len - 1;
++
++ if((mem_region == giop_scratch_space
++ && lastvec->iov_base == giop_scratch_space)
++ || ((((guchar *)lastvec->iov_base) + lastvec->iov_len) == mem_region))
++ {
++ lastvec->iov_len += mem_region_length;
++ }
++ else
++ {
++ newvec.iov_base = (gpointer)mem_region;
++ newvec.iov_len = mem_region_length;
++ giop_message_buffer_append_iovec(buffer, &newvec);
++ }
++
++ buffer->message_header.message_size += mem_region_length;
++}
++
++/* I think we need a WE_WANT_NEW_CRAPPY_BUGGY_CODE ifdef here - this
++ tiny routine seems to be horribly hard to get right.
++
++ Basically we have to paste the whole of 'mem_region' into our
++ memory chunks, possibly subdividing it up to fit it into multiple
++ 1K chunks. Because we have to return the first paste point in case
++ the client wants to manipulate it afterwards, if mem_region_length
++ >= sizeof(CORBA_unsigned_long), we also have to guarantee that the
++ pasted stuff doesn't get divided on a finer boundary than
++ sizeof(CORBA_unsigned_long).
++*/
++gpointer
++giop_send_buffer_append_mem_indirect(GIOPSendBuffer *send_buffer,
++ gconstpointer mem_region,
++ gulong mem_region_length)
++{
++ gulong offset = 0, thisblock_size;
++ gpointer blockstart = NULL;
++
++ while(offset < mem_region_length) {
++ thisblock_size = MIN(mem_region_length - offset,
++ GIOP_INDIRECT_CHUNK_SIZE - send_buffer->indirect_used);
++
++ if((thisblock_size >= sizeof(CORBA_unsigned_long))
++ || (mem_region_length - offset) < sizeof(CORBA_unsigned_long)) {
++ if (!blockstart)
++ blockstart =
++ ((guchar*) send_buffer->indirect) + send_buffer->indirect_used;
++
++ memcpy((guchar*)send_buffer->indirect + send_buffer->indirect_used,
++ (guchar*)mem_region + offset, thisblock_size);
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(send_buffer),
++ (guchar*)send_buffer->indirect +
++ send_buffer->indirect_used,
++ thisblock_size);
++ offset += thisblock_size;
++ send_buffer->indirect_used += thisblock_size;
++ }
++
++ if(send_buffer->indirect_used >= (GIOP_INDIRECT_CHUNK_SIZE - sizeof(CORBA_unsigned_long))) {
++#ifdef I_CANT_FIGURE_OUT_WHAT_THIS_LOGIC_WAS_MEANT_TO_DO
++ || (thisblock_size >= sizeof(CORBA_unsigned_long)
++ && (mem_region_length - offset) > 0)) {
++#endif
++ send_buffer->indirect_used = 0;
++ send_buffer->indirect = g_chunk_new(gpointer,
++ send_buffer->indirects);
++ }
++ }
++
++ return blockstart;
++}
++
++#ifdef WE_WANT_OLD_DEAD_CRAPPY_BUGGY_CODE
++gpointer
++_giop_send_buffer_append_mem_indirect(GIOPSendBuffer *send_buffer,
++ gconstpointer mem_region,
++ gulong mem_region_length)
++{
++ gpointer blockstart = NULL;
++ gulong offset, new_offset;
++
++ for(offset = new_offset = 0; new_offset < mem_region_length;)
++ {
++ new_offset =
++ MIN(mem_region_length - offset,
++ GIOP_INDIRECT_CHUNK_SIZE - send_buffer->indirect_used);
++
++ if((new_offset - offset) > sizeof(CORBA_unsigned_long)
++ || mem_region_length >= sizeof(CORBA_unsigned_long)) {
++
++ if(!blockstart)
++ blockstart = send_buffer->indirect + send_buffer->indirect_used;
++ }
++
++ memcpy(send_buffer->indirect + send_buffer->indirect_used,
++ mem_region + offset, new_offset - offset);
++
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(send_buffer),
++ send_buffer->indirect + send_buffer->indirect_used,
++ new_offset - offset);
++
++ send_buffer->indirect_used += new_offset - offset;
++
++ offset = new_offset;
++
++ if(new_offset >= GIOP_INDIRECT_CHUNK_SIZE)
++ {
++ send_buffer->indirect_used = 0;
++ send_buffer->indirect = g_chunk_new(gpointer,
++ send_buffer->indirects);
++#ifdef ORBIT_DEBUG
++ memset(send_buffer->indirect, '\xFE', GIOP_INDIRECT_CHUNK_SIZE);
++#endif
++ }
++ }
++
++ return blockstart;
++}
++#endif
++
++gpointer
++giop_send_buffer_append_mem_indirect_a(GIOPSendBuffer *send_buffer,
++ gconstpointer mem_region,
++ gulong mem_region_length)
++{
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer),
++ mem_region_length);
++ return giop_send_buffer_append_mem_indirect(send_buffer,
++ mem_region, mem_region_length);
++}
++
++GIOP_unsigned_long
++giop_get_request_id(void)
++{
++ GIOP_unsigned_long retval;
++ GET_LOCK(request_id_counter);
++ retval = request_id_counter++;
++ RELEASE_LOCK(request_id_counter);
++ return retval;
++}
++
++/****************************************************
++ * GIOPRecvBuffer routines
++ ****************************************************/
++
++static GIOPRecvBuffer *
++giop_recv_buffer_new(void)
++{
++ GIOPRecvBuffer *msgbuf;
++
++ GET_LOCK(recvbuffers);
++ msgbuf = g_chunk_new(GIOPRecvBuffer, recvbuffers);
++ RELEASE_LOCK(recvbuffers);
++
++ giop_message_buffer_new(GIOP_MESSAGE_BUFFER(msgbuf));
++ msgbuf->message_body = NULL;
++
++ return msgbuf;
++}
++
++void
++giop_recv_buffer_unuse(GIOPRecvBuffer *buffer)
++{
++ if (buffer == NULL)
++ return;
++
++ if(buffer->message_body) {
++ buffer->message_body = ((guchar *)buffer->message_body)
++ - sizeof(GIOPMessageHeader);
++
++ g_free(buffer->message_body);
++ buffer->message_body = NULL;
++ }
++
++ if(GIOP_MESSAGE_BUFFER(buffer)->connection->incoming_msg == buffer)
++ GIOP_MESSAGE_BUFFER(buffer)->connection->incoming_msg = NULL;
++
++ giop_connection_unref(GIOP_MESSAGE_BUFFER(buffer)->connection);
++
++ GET_LOCK(recvbufferlist);
++ recvbufferlist = g_slist_prepend(recvbufferlist, buffer);
++ RELEASE_LOCK(recvbufferlist);
++}
++
++static GIOPRecvBuffer *
++giop_recv_buffer_use(GIOPConnection *connection)
++{
++ GIOPRecvBuffer *retval;
++
++ if(!connection || !connection->is_valid)
++ return NULL;
++
++ GET_LOCK(recvbufferlist);
++
++ if(recvbufferlist)
++ {
++ GSList *head;
++
++ retval = recvbufferlist->data;
++
++ head = recvbufferlist;
++ recvbufferlist = g_slist_remove_link(recvbufferlist, recvbufferlist);
++ g_slist_free_1 (head);
++
++ GIOP_MESSAGE_BUFFER(retval)->message_header.message_size = 0;
++ retval->message_body = NULL;
++ }
++ else
++ retval = giop_recv_buffer_new();
++
++ retval->state = GIOP_MSG_READING_HEADER;
++ retval->left_to_read = sizeof(GIOPMessageHeader);
++
++ RELEASE_LOCK(recvbufferlist);
++
++ giop_connection_ref(connection);
++ GIOP_MESSAGE_BUFFER(retval)->connection = connection;
++
++ return retval;
++}
++
++GIOPRecvBuffer *
++giop_recv_message_buffer_use(GIOPConnection *connection)
++{
++ GIOPRecvBuffer *retval;
++ char *bptr;
++ int sysret;
++ guint message_size;
++
++// printf("giop_recv_message_buffer_use: connection = 0x%X\n", connection);
++
++ if(!connection || !connection->is_valid)
++ return NULL;
++
++ if(connection->incoming_msg)
++ retval = connection->incoming_msg;
++ else {
++ retval = giop_recv_buffer_use(connection);
++ connection->incoming_msg = retval;
++ }
++
++ if(!retval) return NULL;
++
++ do {
++ switch(retval->state) {
++ case GIOP_MSG_READING_HEADER:
++ bptr = ((char *)&(GIOP_MESSAGE_BUFFER(retval)->message_header));
++ bptr += sizeof(GIOP_MESSAGE_BUFFER(retval)->message_header)
++ - retval->left_to_read;
++ break;
++ case GIOP_MSG_READING_BODY:
++ bptr = retval->cur; /* Reason for not using retval->message_body:
++ See note XXX1 below */
++ bptr += GIOP_MESSAGE_BUFFER(retval)->message_header.message_size;
++ bptr -= retval->left_to_read;
++ break;
++ default:
++ bptr = NULL;
++ }
++
++//printf("#1p1: READ %d bytes: errno %d state = %d\n", retval->left_to_read, errno, retval->state);
++ sysret = read(GIOP_CONNECTION_GET_FD(connection), bptr,
++ retval->left_to_read);
++
++ if((sysret == 0)
++ || ((sysret < 0) && (errno != EAGAIN))) {
++//printf("#1: sysret = %d bptr = 0x%X errno = %d\n", sysret, bptr, errno);
++ goto errout;
++ }
++
++ if(sysret > 0)
++ retval->left_to_read -= sysret;
++
++ if(retval->left_to_read == 0) {
++ /* we change states here */
++
++ switch(retval->state) {
++ case GIOP_MSG_READING_HEADER:
++ /* Check the magic stuff */
++ if(strncmp(GIOP_MESSAGE_BUFFER(retval)->message_header.magic, "GIOP", 4)
++ || GIOP_MESSAGE_BUFFER(retval)->message_header.GIOP_version[0] != 1) {
++//printf("#2: Not a GIOP thinger? '%s'\n", GIOP_MESSAGE_BUFFER(retval)->message_header.magic);
++ goto errout;
++ }
++ if(GIOP_MESSAGE_BUFFER(retval)->message_header.message_size == 0
++ && GIOP_MESSAGE_BUFFER(retval)->message_header.message_type != GIOP_CLOSECONNECTION) {
++// printf("Unexpected 0-length IIOP message\n");
++ goto errout;
++ }
++
++ if(giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(retval))) {
++ CORBA_unsigned_long t = GIOP_MESSAGE_BUFFER(retval)->message_header.message_size;
++ retval->decoder = (void (*)(gpointer, gpointer, gulong))iiop_byteswap;
++
++ iiop_byteswap((gpointer)&GIOP_MESSAGE_BUFFER(retval)->message_header.message_size,
++ (gpointer)&t, sizeof(t));
++ } else {
++#ifdef __KERNEL__
++ retval->decoder = (void (*)(gpointer,gpointer,gulong))__memcpy;
++#else
++ retval->decoder = (void (*)(gpointer,gpointer,gulong))memcpy;
++#endif
++ }
++
++ message_size = GIOP_MESSAGE_BUFFER(retval)->message_header.message_size;
++ if(!connection->is_auth
++ && message_size > 131072) {
++// printf("message size is bigger than 128k (%d)\n", message_size);
++ goto errout;
++ }
++
++ retval->message_body = g_malloc(message_size+sizeof(GIOPMessageHeader));
++ /* XXX1 This is a lame hack to work with the fact that
++ alignment is relative to the MessageHeader, not the RequestHeader */
++ retval->message_body = ((guchar *)retval->message_body) + sizeof(GIOPMessageHeader);
++ retval->cur = retval->message_body;
++ retval->state = GIOP_MSG_READING_BODY;
++ retval->left_to_read = message_size;
++ break;
++ case GIOP_MSG_READING_BODY:
++ if(giop_recv_decode_message(retval)) {
++//printf("giop_recv_decode_message FAILURE!\n");
++ goto errout;
++ }
++ connection->incoming_msg = NULL;
++ retval->state = GIOP_MSG_READY;
++ break;
++ default:
++ break;
++ }
++ } else if(retval->left_to_read < 0) {
++// printf("Whoa, we overstepped the number of bytes we were supposed to read by %d\n", -retval->left_to_read);
++ goto errout;
++ } else /* retval->left_to_read > 0 */ {
++ /* couldn't read the whole piece, save it */
++ retval = NULL;
++ }
++ } while(retval && retval->state != GIOP_MSG_READY);
++
++ return retval;
++
++ errout:
++ giop_recv_buffer_unuse(retval);
++ giop_main_handle_connection_exception(connection);
++ return NULL;
++}
++
++void
++giop_received_list_push(GIOPRecvBuffer *recv_buffer)
++{
++ GET_LOCK(incoming_bufs);
++ incoming_bufs = g_list_prepend(incoming_bufs, recv_buffer);
++ RELEASE_LOCK(incoming_bufs);
++}
++
++GIOPRecvBuffer *giop_received_list_pop(void)
++{
++ GList *head;
++ GIOPRecvBuffer *retval;
++
++ GET_LOCK(incoming_bufs);
++
++ head = incoming_bufs;
++
++ if(!head)
++ return NULL;
++
++ retval = head->data;
++ incoming_bufs = g_list_remove_link(incoming_bufs, head);
++ g_list_free_1 (head);
++
++ RELEASE_LOCK(incoming_bufs);
++
++ return retval;
++}
++
++static GIOPRecvBuffer *
++giop_received_list_check_reply(GIOP_unsigned_long request_id)
++{
++ GIOPRecvBuffer *retval = NULL;
++ GList *item = NULL;
++
++ GET_LOCK(incoming_bufs);
++
++ for(item = incoming_bufs; item; item = g_list_next(item))
++ {
++ if(GIOP_MESSAGE_BUFFER(item->data)->message_header.message_type == GIOP_REPLY
++ && GIOP_RECV_BUFFER(item->data)->message.u.reply.request_id == request_id) {
++ retval = item->data;
++ break;
++ }
++ }
++
++ if(retval)
++ incoming_bufs = g_list_remove(incoming_bufs, retval);
++
++ RELEASE_LOCK(incoming_bufs);
++
++ return retval;
++}
++
++/** giop_recv_reply_buffer_use_multiple
++ */
++GIOPRecvBuffer *
++giop_recv_reply_buffer_use_multiple(GArray *request_ids,
++ gboolean block_for_reply)
++{
++ return giop_recv_reply_buffer_use_multiple_2(NULL, request_ids, block_for_reply);
++}
++
++/* here is how it will be:
++ one routine for getting next message with a specified reply ID.
++ */
++
++GIOPRecvBuffer *
++giop_recv_reply_buffer_use_multiple_2(GIOPConnection *request_cnx,
++ GArray *request_ids,
++ gboolean block_for_reply)
++{
++ int i;
++ GIOPRecvBuffer *retval = NULL;
++ GSList *pushme = NULL;
++
++ do {
++ /*
++ * We _do_ want to put this inside the loop,
++ * because we may call ourselves recursively for different request_id's
++ */
++ for(i = 0; i < request_ids->len && !retval; i++)
++ retval = giop_received_list_check_reply(g_array_index(request_ids, GIOP_unsigned_long, i));
++
++ if(retval)
++ break;
++
++ retval = giop_main_next_message_2(block_for_reply, request_cnx);
++
++ if(retval) {
++ if(GIOP_MESSAGE_BUFFER(retval)->message_header.message_type == GIOP_REPLY) {
++ if(num_on_list(retval->message.u.reply.request_id,
++ (GIOP_unsigned_long *)request_ids->data,
++ request_ids->len))
++ break;
++ else {
++ pushme = g_slist_prepend(pushme, retval); retval = NULL;
++ }
++ } else {
++ if(IIOPIncomingMessageHandler)
++ IIOPIncomingMessageHandler(retval);
++ else {
++ pushme = g_slist_prepend(pushme, retval); retval = NULL;
++ }
++ retval = NULL;
++ }
++ } else
++ return NULL;
++
++ } while(!retval && block_for_reply);
++
++ g_slist_foreach(pushme, (GFunc)giop_received_list_push, NULL);
++ g_slist_free(pushme);
++
++ return retval;
++}
++
++GIOPRecvBuffer *
++giop_recv_reply_buffer_use(GIOP_unsigned_long request_id,
++ gboolean block_for_reply)
++{
++ return giop_recv_reply_buffer_use_2(NULL, request_id, block_for_reply);
++}
++
++GIOPRecvBuffer *
++giop_recv_reply_buffer_use_2(GIOPConnection *request_cnx,
++ GIOP_unsigned_long request_id,
++ gboolean block_for_reply)
++{
++ GArray fakeme;
++
++ fakeme.len = 1;
++ fakeme.data = (gpointer)&request_id;
++
++ return giop_recv_reply_buffer_use_multiple_2(request_cnx,
++ &fakeme,
++ block_for_reply);
++}
++
++GIOPRecvBuffer *
++giop_recv_locate_reply_buffer_use(GIOP_unsigned_long request_id,
++ gboolean block_for_reply)
++{
++ GIOPRecvBuffer *retval = NULL;
++
++ do {
++ /*
++ * We _do_ want to put this inside the loop,
++ * because we may call ourselves recursively for different request_id's
++ */
++ retval = giop_received_list_check_reply(request_id);
++
++ if(retval)
++ break;
++
++ retval = giop_main_next_message_2(TRUE, NULL);
++
++ if(retval) {
++ if(GIOP_MESSAGE_BUFFER(retval)->message_header.message_type == GIOP_LOCATEREPLY
++ && retval->message.u.locate_reply.request_id == request_id)
++ break;
++ else {
++ if(IIOPIncomingMessageHandler)
++ IIOPIncomingMessageHandler(retval);
++ else
++ giop_received_list_push(retval);
++ retval = NULL;
++ }
++ } else
++ return NULL;
++ } while(!retval && block_for_reply);
++
++ return retval;
++}
++
++static gint
++giop_recv_decode_message(GIOPRecvBuffer *buf)
++{
++ switch(GIOP_MESSAGE_BUFFER(buf)->message_header.message_type)
++ {
++ case GIOP_REPLY:
++ return giop_recv_reply_decode_message(buf);
++ break;
++ case GIOP_REQUEST:
++ return giop_recv_request_decode_message(buf);
++ break;
++ case GIOP_LOCATEREQUEST:
++ return(giop_recv_locate_request_decode_message(buf));
++ break;
++ case GIOP_LOCATEREPLY:
++ return(giop_recv_locate_reply_decode_message(buf));
++ break;
++ case GIOP_CLOSECONNECTION:
++ return 0;
++ break;
++ default:
++// printf("Don't know how to decode message type %d\n",
++// GIOP_MESSAGE_BUFFER(buf)->message_header.message_type);
++ return -1;
++ }
++}
++
++/* if(currptr+len > end || currptr + len < currptr) */
++
++/* This whole mess needs redoing. */
++#define CHECK_NEW_POS(buf, requested_increment) \
++if(!( (( ((guchar*)GIOP_RECV_BUFFER(buf)->cur) \
++ + (requested_increment) ) \
++ <= ( ((guchar *)GIOP_RECV_BUFFER(buf)->message_body) \
++ + GIOP_MESSAGE_BUFFER(buf)->message_header.message_size)) \
++ && ( ( ((guchar*)GIOP_RECV_BUFFER(buf)->cur) \
++ + (requested_increment) ) \
++ >= ((guchar*)GIOP_RECV_BUFFER(buf)->cur) ))) goto out;
++
++#define NEW_POS_OUT out: return -1
++
++#define SAFE_ALIGN_ADDRESS(buf, amt) G_STMT_START { \
++guchar *newval; \
++newval = ALIGN_ADDRESS(GIOP_RECV_BUFFER(buf)->cur, amt); \
++CHECK_NEW_POS(buf, newval-((guchar *)GIOP_RECV_BUFFER(buf)->cur)); \
++GIOP_RECV_BUFFER(buf)->cur = newval; \
++} G_STMT_END
++
++#define GET_ULONG(x) G_STMT_START{ \
++ (x) = GUINT32_SWAP_LE_BE((*(CORBA_unsigned_long *)buf->cur)); \
++ CHECK_NEW_POS(buf, sizeof(CORBA_unsigned_long)); \
++ buf->cur = ((guchar *)buf->cur) + sizeof(CORBA_unsigned_long); \
++ }G_STMT_END
++
++#define GET_ULONG_NC(x) G_STMT_START{ \
++ *(x) = (*((CORBA_unsigned_long *)(buf->cur))); \
++ CHECK_NEW_POS(buf, sizeof(CORBA_unsigned_long)); \
++ buf->cur = ((guchar *)buf->cur) + sizeof(CORBA_unsigned_long); \
++ }G_STMT_END
++
++/* There be dragons in here. */
++static gint
++giop_recv_reply_decode_message(GIOPRecvBuffer *buf)
++{
++ /*
++ enum ReplyStatusType {
++ NO_EXCEPTION,
++ USER_EXCEPTION,
++ SYSTEM_EXCEPTION,
++ LOCATION_FORWARD
++ };
++
++ struct ReplyHeader {
++ IOP::ServiceContextList service_context;
++ unsigned long request_id;
++ ReplyStatusType reply_status;
++ };
++ */
++ int i;
++
++ buf->message.u.reply.service_context._maximum = 0;
++ if(giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(buf)))
++ {
++ GET_ULONG(buf->message.u.reply.service_context._length);
++/* XXX bad hardcoded hack until someone gives a "right answer" to how to
++solve this problem */
++ if(buf->message.u.reply.service_context._length > 128) return -1;
++ buf->message.u.reply.service_context._buffer =
++ g_new(IOP_ServiceContext, buf->message.u.reply.service_context._length);
++
++ for(i = 0; i < buf->message.u.reply.service_context._length; i++)
++ {
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG(buf->message.u.reply.service_context._buffer[i].context_id);
++ GET_ULONG(buf->message.u.reply.service_context._buffer[i].context_data._length);
++ buf->message.u.reply.service_context._buffer[i].context_data._buffer =
++ buf->cur;
++ CHECK_NEW_POS(buf, buf->message.u.reply.service_context._buffer[i].context_data._length);
++ buf->cur = ((guchar *)buf->cur) + buf->message.u.reply.service_context._buffer[i].context_data._length;
++ }
++ GET_ULONG(buf->message.u.reply.request_id);
++ GET_ULONG(buf->message.u.reply.reply_status);
++ }
++ else
++ {
++
++ GET_ULONG_NC(&buf->message.u.reply.service_context._length);
++/* XXX bad hardcoded hack until someone gives a "right answer" to how to
++solve this problem */
++ if(buf->message.u.reply.service_context._length > 128) return -1;
++ buf->message.u.reply.service_context._buffer =
++ g_new(IOP_ServiceContext, buf->message.u.reply.service_context._length);
++
++ for(i = 0; i < buf->message.u.reply.service_context._length; i++)
++ {
++ SAFE_ALIGN_ADDRESS(buf, sizeof(CORBA_unsigned_long));
++ GET_ULONG_NC(&buf->message.u.reply.service_context._buffer[i].context_id);
++ GET_ULONG_NC(&buf->message.u.reply.service_context._buffer[i].context_data._length);
++ buf->message.u.reply.service_context._buffer[i].context_data._buffer =
++ buf->cur;
++ CHECK_NEW_POS(buf, buf->message.u.reply.service_context._buffer[i].context_data._length);
++ buf->cur = ((guchar *)buf->cur) + buf->message.u.reply.service_context._buffer[i].context_data._length;
++ }
++ GET_ULONG_NC(&buf->message.u.reply.request_id);
++ GET_ULONG_NC(&buf->message.u.reply.reply_status);
++ }
++
++#if 0
++ g_message("[%d] Received reply %d size %d to request %d",
++ getpid(),
++ buf->message.u.reply.reply_status,
++ GIOP_MESSAGE_BUFFER(buf)->message_header.message_size,
++ buf->message.u.reply.request_id);
++#endif
++
++ return 0;
++
++ NEW_POS_OUT;
++}
++
++static gint
++giop_recv_locate_reply_decode_message(GIOPRecvBuffer *buf)
++{
++ if(giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(buf)))
++ {
++ GET_ULONG(buf->message.u.locate_reply.request_id);
++ GET_ULONG(buf->message.u.locate_reply.locate_status);
++ }
++ else
++ {
++ GET_ULONG_NC(&buf->message.u.locate_reply.request_id);
++ GET_ULONG_NC(&buf->message.u.locate_reply.locate_status);
++ }
++
++ return 0;
++ NEW_POS_OUT;
++}
++
++static gint
++giop_recv_request_decode_message(GIOPRecvBuffer *buf)
++{
++ GIOP_unsigned_long len;
++ int i;
++
++ buf->message.u.request.service_context._maximum = 0;
++ if(giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(buf)))
++ {
++ GET_ULONG(buf->message.u.request.service_context._length);
++
++ /* XXX bad hardcoded hack until someone gives a "right answer"
++ to how to solve this problem */
++
++ if(buf->message.u.request.service_context._length > 128) return -1;
++ buf->message.u.request.service_context._buffer =
++ g_new(IOP_ServiceContext, buf->message.u.request.service_context._length);
++
++ for(i = 0; i < buf->message.u.request.service_context._length; i++)
++ {
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG(buf->message.u.request.service_context._buffer[i].context_id);
++ GET_ULONG(buf->message.u.request.service_context._buffer[i].context_data._length);
++ buf->message.u.request.service_context._buffer[i].context_data._buffer =
++ buf->cur;
++ CHECK_NEW_POS(buf, buf->message.u.request.service_context._buffer[i].context_data._length);
++ buf->cur = ((guchar *)buf->cur) + buf->message.u.request.service_context._buffer[i].context_data._length;
++ }
++
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG(buf->message.u.request.request_id);
++ buf->message.u.request.response_expected = *((GIOP_boolean *)buf->cur);
++ CHECK_NEW_POS(buf, sizeof(GIOP_boolean));
++ buf->cur = ((guchar *)buf->cur) + sizeof(GIOP_boolean);
++
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG(buf->message.u.request.object_key._length);
++ buf->message.u.request.object_key._buffer = buf->cur;
++
++ CHECK_NEW_POS(buf, buf->message.u.request.object_key._length);
++ buf->cur = ((guchar *)buf->cur) + buf->message.u.request.object_key._length;
++
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG(len);
++ buf->message.u.request.operation = buf->cur;
++
++ CHECK_NEW_POS(buf, len);
++ buf->cur = ((guchar *)buf->cur) + len;
++
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG(buf->message.u.request.requesting_principal._length);
++ buf->message.u.request.requesting_principal._buffer = buf->cur;
++
++ CHECK_NEW_POS(buf, buf->message.u.request.requesting_principal._length);
++ buf->cur = ((guchar *)buf->cur) + buf->message.u.request.requesting_principal._length;
++ }
++ else
++ {
++ GET_ULONG_NC(&buf->message.u.request.service_context._length);
++
++ /* XXX bad hardcoded hack until someone gives a "right answer"
++ to how to solve this problem */
++ if(buf->message.u.request.service_context._length > 128) return -1;
++ buf->message.u.request.service_context._buffer =
++ g_new(IOP_ServiceContext, buf->message.u.request.service_context._length);
++
++ for(i = 0; i < buf->message.u.request.service_context._length; i++)
++ {
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG_NC(&buf->message.u.request.service_context._buffer[i].context_id);
++ GET_ULONG_NC(&buf->message.u.request.service_context._buffer[i].context_data._length);
++ buf->message.u.request.service_context._buffer[i].context_data._buffer =
++ buf->cur;
++ CHECK_NEW_POS(buf, buf->message.u.request.service_context._buffer[i].context_data._length);
++ buf->cur = ((guchar *)buf->cur) + buf->message.u.request.service_context._buffer[i].context_data._length;
++ }
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG_NC(&buf->message.u.request.request_id);
++ buf->message.u.request.response_expected = *((GIOP_boolean *)buf->cur);
++ CHECK_NEW_POS(buf, sizeof(GIOP_boolean));
++ buf->cur = ((guchar *)buf->cur) + sizeof(GIOP_boolean);
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG_NC(&buf->message.u.request.object_key._length);
++ buf->message.u.request.object_key._buffer = buf->cur;
++ CHECK_NEW_POS(buf, buf->message.u.request.object_key._length);
++ buf->cur = ((guchar *)buf->cur) + buf->message.u.request.object_key._length;
++
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG_NC(&len);
++ buf->message.u.request.operation = buf->cur;
++ CHECK_NEW_POS(buf, len);
++ buf->cur = ((guchar *)buf->cur) + len;
++
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG_NC(&buf->message.u.request.requesting_principal._length);
++ buf->message.u.request.requesting_principal._buffer = buf->cur;
++ CHECK_NEW_POS(buf, buf->message.u.request.requesting_principal._length);
++ buf->cur = ((guchar *)buf->cur) + buf->message.u.request.requesting_principal._length;
++ }
++
++#if 0
++ g_message("[%d] Received request %s size %d ID %d",
++ getpid(),
++ buf->message.u.request.operation,
++ GIOP_MESSAGE_BUFFER(buf)->message_header.message_size,
++ buf->message.u.request.request_id);
++#endif
++
++ return 0;
++
++ NEW_POS_OUT;
++}
++
++static gint
++giop_recv_locate_request_decode_message(GIOPRecvBuffer *buf)
++{
++ if(giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(buf)))
++ {
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG(buf->message.u.locate_request.request_id);
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG(buf->message.u.locate_request.object_key._length);
++ buf->message.u.locate_request.object_key._buffer = buf->cur;
++ CHECK_NEW_POS(buf, buf->message.u.locate_request.object_key._length);
++ buf->cur = ((guchar *)buf->cur) + buf->message.u.locate_request.object_key._length;
++ }
++ else
++ {
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG_NC(&buf->message.u.locate_request.request_id);
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG_NC(&buf->message.u.locate_request.object_key._length);
++ buf->message.u.locate_request.object_key._buffer = buf->cur;
++ CHECK_NEW_POS(buf, buf->message.u.locate_request.object_key._length);
++ buf->cur = ((guchar *)buf->cur) + buf->message.u.locate_request.object_key._length;
++ }
++
++ return 0;
++
++ NEW_POS_OUT;
++}
++
++gboolean
++num_on_list(GIOP_unsigned_long num,
++ const GIOP_unsigned_long *request_ids,
++ GIOP_unsigned_long req_count)
++{
++ int i;
++ for(i = 0; i < req_count; i++)
++ {
++ if(num == request_ids[i])
++ return TRUE;
++ }
++
++ return FALSE;
++}
+diff -urN linux-2.4.1/net/korbit/IIOP/giop-msg-buffer.h linux-2.4.1-korbit/net/korbit/IIOP/giop-msg-buffer.h
+--- linux-2.4.1/net/korbit/IIOP/giop-msg-buffer.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/giop-msg-buffer.h Thu Feb 1 16:19:47 2001
+@@ -0,0 +1,228 @@
++#ifndef GIOP_MSG_BUFFER_H
++#define GIOP_MSG_BUFFER_H 1
++
++#include "IIOP.h"
++/* For struct iovec */
++#include <sys/uio.h>
++
++typedef enum {
++ GIOP_REQUEST,
++ GIOP_REPLY,
++ GIOP_CANCELREQUEST,
++ GIOP_LOCATEREQUEST,
++ GIOP_LOCATEREPLY,
++ GIOP_CLOSECONNECTION,
++ GIOP_MESSAGEERROR,
++ GIOP_FRAGMENT
++} GIOPMsgType;
++
++/* GIOP message header */
++typedef struct _GIOPMessageHeader {
++ GIOP_char magic[4];
++ GIOP_char GIOP_version[2];
++ GIOP_octet flags;
++
++ /*
++ * We should really use GIOPMsgType
++ * but that enum winds up being an int...
++ */
++ GIOP_octet message_type;
++
++ GIOP_unsigned_long message_size;
++} GIOPMessageHeader;
++
++#define GIOP_MESSAGE_BUFFER(x) ((GIOPMessageBuffer *)x)
++typedef struct _GIOPMessageBuffer
++{
++ /* The connection that this message will go out over... */
++ GIOPConnection *connection;
++
++ GArray *iovecs;
++ GIOPMessageHeader message_header;
++} GIOPMessageBuffer;
++
++#include "../orb/iop.h"
++
++/* GIOP_REQUEST header */
++typedef enum {
++ GIOP_NO_EXCEPTION,
++ GIOP_USER_EXCEPTION,
++ GIOP_SYSTEM_EXCEPTION,
++ GIOP_LOCATION_FORWARD
++} GIOPReplyStatusType;
++
++typedef struct _GIOPMessageRequest {
++ IOP_ServiceContextList service_context;
++ GIOP_unsigned_long request_id;
++ GIOP_boolean response_expected;
++ CORBA_sequence_octet object_key;
++ CORBA_char *operation;
++ CORBA_Principal requesting_principal;
++} GIOPMessageRequest;
++
++typedef struct _GIOPMessageReply {
++ IOP_ServiceContextList service_context;
++ GIOP_unsigned_long request_id;
++ GIOPReplyStatusType reply_status;
++} GIOPMessageReply;
++
++typedef struct _GIOPMessageCancelRequest {
++ GIOP_unsigned_long request_id;
++} GIOPMessageCancelRequest;
++
++typedef struct _GIOPMessageLocateRequest {
++ GIOP_unsigned_long request_id;
++ CORBA_sequence_octet object_key;
++} GIOPMessageLocateRequest;
++
++typedef enum {
++ GIOP_UNKNOWN_OBJECT,
++ GIOP_OBJECT_HERE,
++ GIOP_OBJECT_FORWARD
++} GIOPLocateStatusType;
++
++typedef struct _GIOPMessageLocateReply {
++ GIOP_unsigned_long request_id;
++ GIOPLocateStatusType locate_status;
++} GIOPMessageLocateReply;
++
++typedef struct _GIOPMessage
++{
++ union {
++ GIOPMessageRequest request;
++ GIOPMessageReply reply;
++ GIOPMessageCancelRequest cancel_request;
++ GIOPMessageLocateRequest locate_request;
++ GIOPMessageLocateReply locate_reply;
++ } u;
++} GIOPMessage;
++
++typedef enum {
++ GIOP_MSG_READING_HEADER,
++ GIOP_MSG_READING_BODY,
++ GIOP_MSG_READY
++} GIOPMessageBufferState;
++
++#define GIOP_SEND_BUFFER(x) ((GIOPSendBuffer *)x)
++typedef struct _GIOPSendBuffer
++{
++ GIOPMessageBuffer message_buffer;
++
++ gpointer indirect;
++
++ GMemChunk *indirects; /* Request buffers only (at present) */
++ gulong indirect_used;
++
++ GIOPMessage message;
++ CORBA_unsigned_long scontext_tmp;
++} GIOPSendBuffer;
++
++#define GIOP_RECV_BUFFER(x) ((GIOPRecvBuffer *)x)
++typedef struct _GIOPRecvBuffer
++{
++ GIOPMessageBuffer message_buffer;
++ GIOPMessage message;
++
++ gpointer message_body;
++ gpointer cur;
++
++ void (*decoder)(gpointer dest, gpointer src, gulong len);
++
++ GIOPMessageBufferState state;
++ gint left_to_read;
++} GIOPRecvBuffer;
++
++/* This function needs to be called before useful things happen */
++void giop_message_buffer_init(void);
++
++gint giop_send_buffer_write(GIOPSendBuffer *request_buffer);
++
++void
++giop_message_buffer_append_mem_a(GIOPMessageBuffer *request_buffer,
++ gconstpointer mem_region,
++ gulong mem_region_length);
++void
++giop_message_buffer_append_mem(GIOPMessageBuffer *request_buffer,
++ gconstpointer mem_region,
++ gulong mem_region_length);
++
++/*
++ * This copies the value into a request-specific buffer before
++ * adding it to the list
++ */
++gpointer
++giop_send_buffer_append_mem_indirect_a(GIOPSendBuffer *request_buffer,
++ gconstpointer mem_region,
++ gulong mem_region_length);
++gpointer
++giop_send_buffer_append_mem_indirect(GIOPSendBuffer *request_buffer,
++ gconstpointer mem_region,
++ gulong mem_region_length);
++
++GIOPSendBuffer *
++giop_send_request_buffer_use(GIOPConnection *connection,
++ const IOP_ServiceContextList *service_context,
++ GIOP_unsigned_long request_id,
++ GIOP_boolean response_expected,
++ const struct iovec *object_key_vec,
++ const struct iovec *operation_vec,
++ const struct iovec *principal_vec);
++GIOPSendBuffer *
++giop_send_reply_buffer_use(GIOPConnection *connection,
++ const IOP_ServiceContextList *service_context,
++ GIOP_unsigned_long request_id,
++ GIOPReplyStatusType reply_status);
++GIOPSendBuffer *
++giop_send_locate_request_buffer_use(GIOPConnection *connection,
++ GIOP_unsigned_long request_id,
++ const struct iovec *object_key_vec);
++GIOPSendBuffer *
++giop_send_locate_reply_buffer_use(GIOPConnection *connection,
++ GIOP_unsigned_long request_id,
++ GIOPLocateStatusType reply_status);
++
++void giop_send_buffer_unuse(GIOPSendBuffer *send_buffer);
++
++GIOP_unsigned_long giop_get_request_id(void);
++
++GIOPRecvBuffer *
++giop_recv_reply_buffer_use(GIOP_unsigned_long request_id,
++ gboolean block_for_reply);
++GIOPRecvBuffer *
++giop_recv_reply_buffer_use_2(GIOPConnection *request_cnx,
++ GIOP_unsigned_long request_id,
++ gboolean block_for_reply);
++
++/* For DII - hands back the first received request matching an id on the list */
++GIOPRecvBuffer *
++giop_recv_reply_buffer_use_multiple(GArray *request_ids,
++ gboolean block_for_reply);
++GIOPRecvBuffer *
++giop_recv_reply_buffer_use_multiple_2(GIOPConnection *request_cnx,
++ GArray *request_ids,
++ gboolean block_for_reply);
++
++GIOPRecvBuffer *
++giop_recv_locate_reply_buffer_use(GIOP_unsigned_long request_id,
++ gboolean block_for_reply);
++
++/*
++ * For server-side use. It's the responsibility of the caller to do
++ * any select()ion desired
++ */
++GIOPRecvBuffer *
++giop_recv_message_buffer_use(GIOPConnection *connection);
++
++void giop_recv_buffer_unuse(GIOPRecvBuffer *buffer);
++
++/*
++ * This is used for sending (and recving, if we ever
++ * get zero-copy receives implemented) alignment bytes
++ */
++extern char giop_scratch_space[2048];
++gulong giop_message_buffer_do_alignment(GIOPMessageBuffer *buffer,
++ gulong align_for);
++
++#define giop_msg_conversion_needed(msgbuf) (conversion_needed(GIOP_MESSAGE_BUFFER(msgbuf)->message_header.flags & 1))
++
++#endif /* GIOP_MSG_BUFFER_H */
+diff -urN linux-2.4.1/net/korbit/IIOP/iiop-encoders.h linux-2.4.1-korbit/net/korbit/IIOP/iiop-encoders.h
+--- linux-2.4.1/net/korbit/IIOP/iiop-encoders.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/iiop-encoders.h Thu Feb 1 11:46:51 2001
+@@ -0,0 +1,25 @@
++#ifndef ENCODERS_H
++#define ENCODERS_H 1
++
++#define ENCODER_DEC(typename) \
++void giop_encoder_##typename##(GIOPSendBuffer *send_buffer, \
++ const typename *mem)
++
++#define ENCODER_CALL(typename, mem) \
++giop_encoder_##typename##(send_buffer, mem)
++
++#define AP(m, l) giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(send_buffer), m, l)
++#define APA(m, l) giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(send_buffer), m, l)
++
++#define API(m, l) giop_send_buffer_append_mem_indirect(send_buffer, m, l)
++#define APIA(m, l) giop_send_buffer_append_mem_indirect_a(send_buffer, m, l)
++
++ENCODER_DEC(IOP_ServiceContext);
++ENCODER_DEC(IOP_ServiceContextList);
++ENCODER_DEC(CORBA_sequence_octet);
++ENCODER_DEC(CORBA_Principal);
++#define giop_encoder_CORBA_Principal(rb, mem) \
++ giop_encoder_CORBA_sequence_octet(rb, mem)
++ENCODER_DEC(CORBA_char);
++
++#endif /* ENCODERS_H */
+diff -urN linux-2.4.1/net/korbit/IIOP/iiop-endian.c linux-2.4.1-korbit/net/korbit/IIOP/iiop-endian.c
+--- linux-2.4.1/net/korbit/IIOP/iiop-endian.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/iiop-endian.c Thu Feb 1 11:46:51 2001
+@@ -0,0 +1,12 @@
++#define IIOP_DO_NOT_INLINE_IIOP_BYTESWAP
++#include "iiop-endian.h"
++
++void iiop_byteswap(guchar *outdata,
++ const guchar *data,
++ gulong datalen)
++{
++ const guchar *source_ptr = data;
++ guchar *dest_ptr = (guchar *)outdata + datalen - 1;
++ while(dest_ptr >= outdata)
++ *dest_ptr-- = *source_ptr++;
++}
+diff -urN linux-2.4.1/net/korbit/IIOP/iiop-endian.h linux-2.4.1-korbit/net/korbit/IIOP/iiop-endian.h
+--- linux-2.4.1/net/korbit/IIOP/iiop-endian.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/iiop-endian.h Thu Feb 1 11:46:51 2001
+@@ -0,0 +1,42 @@
++#ifndef IIOP_ENDIAN_H
++#define IIOP_ENDIAN_H 1
++
++#include <glib.h>
++
++#if G_BYTE_ORDER == G_BIG_ENDIAN
++
++# define FLAG_ENDIANNESS FLAG_BIG_ENDIAN
++# define conversion_needed(to_endianness) ((to_endianness)!=FLAG_BIG_ENDIAN)
++
++#elif G_BYTE_ORDER == G_LITTLE_ENDIAN
++
++# define FLAG_ENDIANNESS FLAG_LITTLE_ENDIAN
++# define conversion_needed(to_endianness) ((to_endianness)!=FLAG_LITTLE_ENDIAN)
++
++#else
++
++#error "Unsupported endianness on this system."
++
++#endif
++
++#define FLAG_BIG_ENDIAN 0
++#define FLAG_LITTLE_ENDIAN 1
++
++/* This is also defined in IIOP-types.c */
++void iiop_byteswap(guchar *outdata,
++ const guchar *data,
++ gulong datalen);
++
++#if defined(G_CAN_INLINE) && !defined(IIOP_DO_NOT_INLINE_IIOP_BYTESWAP)
++G_INLINE_FUNC void iiop_byteswap(guchar *outdata,
++ const guchar *data,
++ gulong datalen)
++{
++ const guchar *source_ptr = data;
++ guchar *dest_ptr = outdata + datalen - 1;
++ while(dest_ptr >= outdata)
++ *dest_ptr-- = *source_ptr++;
++}
++#endif
++
++#endif
+diff -urN linux-2.4.1/net/korbit/IIOP/iiop-endianP.h linux-2.4.1-korbit/net/korbit/IIOP/iiop-endianP.h
+--- linux-2.4.1/net/korbit/IIOP/iiop-endianP.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/iiop-endianP.h Thu Feb 1 16:19:47 2001
+@@ -0,0 +1,11 @@
++#ifndef IIOP_ENDIANP_H
++#define IIOP_ENDIANP_H 1
++
++/* This is pretty much "here" */
++
++#include "config.h"
++#include "IIOP.h"
++
++#include "iiop-endian.h"
++
++#endif /* !IIOP_ENDIANP_H */
+diff -urN linux-2.4.1/net/korbit/Makefile linux-2.4.1-korbit/net/korbit/Makefile
+--- linux-2.4.1/net/korbit/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/Makefile Thu Feb 1 15:57:33 2001
+@@ -0,0 +1,22 @@
++#
++# Makefile for KORBit
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++O_TARGET := korbit.o
++
++subdir-y := kglib orb IIOP ORBitutil modules
++subdir-m := modules
++
++obj-y := kglib/kglib.o orb/orblib.o IIOP/IIOPlib.o ORBitutil/ORBitutillib.o exported_symbols.o
++
++export-objs := exported_symbols.o
++
++EXTRA_CFLAGS = -D__KORBIT__ -DHAVE_CONFIG_H -I. -I./include -I./kglib -I./ORBitutil -nostdinc
++
++include $(TOPDIR)/Rules.make
++
+diff -urN linux-2.4.1/net/korbit/ORBitutil/CVS/Entries linux-2.4.1-korbit/net/korbit/ORBitutil/CVS/Entries
+--- linux-2.4.1/net/korbit/ORBitutil/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/CVS/Entries Thu Feb 1 11:46:52 2001
+@@ -0,0 +1,13 @@
++/Makefile/1.4/Thu Feb 1 09:46:52 2001//
++/basic_types.h/1.1.1.1/Thu Feb 1 09:46:52 2001//
++/compat.c/1.1.1.1/Thu Feb 1 09:46:52 2001//
++/compat.h/1.1.1.1/Thu Feb 1 09:46:52 2001//
++/orbit-os-config.h/1.2/Thu Feb 1 09:46:52 2001//
++/os-feature-alloca.h/1.1.1.1/Thu Feb 1 09:46:52 2001//
++/os-specifics.h/1.1.1.1/Thu Feb 1 09:46:52 2001//
++/thread-safety.c/1.1.1.1/Thu Feb 1 09:46:52 2001//
++/thread-safety.h/1.1.1.1/Thu Feb 1 09:46:52 2001//
++/trace.c/1.2/Thu Feb 1 09:46:52 2001//
++/trace.h/1.1.1.1/Thu Feb 1 09:46:52 2001//
++/util.h/1.1.1.1/Thu Feb 1 09:46:52 2001//
++D
+diff -urN linux-2.4.1/net/korbit/ORBitutil/CVS/Repository linux-2.4.1-korbit/net/korbit/ORBitutil/CVS/Repository
+--- linux-2.4.1/net/korbit/ORBitutil/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/CVS/Repository Thu Feb 1 11:46:51 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/ORBitutil
+diff -urN linux-2.4.1/net/korbit/ORBitutil/CVS/Root linux-2.4.1-korbit/net/korbit/ORBitutil/CVS/Root
+--- linux-2.4.1/net/korbit/ORBitutil/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/CVS/Root Thu Feb 1 11:46:51 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/ORBitutil/Makefile linux-2.4.1-korbit/net/korbit/ORBitutil/Makefile
+--- linux-2.4.1/net/korbit/ORBitutil/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/Makefile Thu Feb 1 11:46:52 2001
+@@ -0,0 +1,17 @@
++#
++# Makefile for KORBit/ORBitutil
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .o file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++O_TARGET := ORBitutillib.o
++
++#obj-m := $(O_TARGET)
++obj-y := compat.o thread-safety.o trace.o
++
++EXTRA_CFLAGS = -D__KORBIT__ -DHAVE_CONFIG_H -I. -I.. -I../include -I../kglib -I../ORBitutil -nostdinc
++
++include $(TOPDIR)/Rules.make
+diff -urN linux-2.4.1/net/korbit/ORBitutil/basic_types.h linux-2.4.1-korbit/net/korbit/ORBitutil/basic_types.h
+--- linux-2.4.1/net/korbit/ORBitutil/basic_types.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/basic_types.h Thu Feb 1 11:46:52 2001
+@@ -0,0 +1,46 @@
++#ifndef BASIC_TYPES_H
++#define BASIC_TYPES_H 1
++
++#include <glib.h>
++
++typedef gint16 CORBA_short;
++typedef gint32 CORBA_long;
++typedef guint16 CORBA_unsigned_short;
++typedef guint32 CORBA_unsigned_long;
++typedef gfloat CORBA_float;
++typedef gdouble CORBA_double;
++typedef char CORBA_char;
++typedef guchar CORBA_boolean;
++typedef guchar CORBA_octet;
++typedef gdouble CORBA_long_double;
++typedef guint16 CORBA_wchar; /* I'm not sure what size a wchar is supposed to be */
++
++/* Just a peeve */
++typedef CORBA_char GIOP_char;
++typedef CORBA_wchar GIOP_wchar;
++typedef CORBA_short GIOP_short;
++typedef CORBA_long GIOP_long;
++typedef CORBA_unsigned_short GIOP_unsigned_short;
++typedef CORBA_unsigned_long GIOP_unsigned_long;
++typedef CORBA_octet GIOP_octet;
++typedef CORBA_long GIOP_enum;
++typedef CORBA_boolean GIOP_boolean;
++typedef CORBA_float GIOP_float;
++typedef CORBA_double GIOP_double;
++typedef CORBA_long_double GIOP_long_double;
++
++#ifdef G_HAVE_GINT64
++#define HAVE_CORBA_LONG_LONG
++/* According to the spec, these two are optional. We support them if we can. */
++typedef gint64 CORBA_long_long;
++typedef guint64 CORBA_unsigned_long_long;
++typedef CORBA_long_long GIOP_long_long;
++typedef CORBA_unsigned_long_long GIOP_unsigned_long_long;
++#else
++#warning ""
++#warning "You don't G_HAVE_GINT64 defined in glib."
++#warning "Please make sure you don't have an old glibconfig.h lying around."
++#warning ""
++#endif
++
++#endif
+diff -urN linux-2.4.1/net/korbit/ORBitutil/compat.c linux-2.4.1-korbit/net/korbit/ORBitutil/compat.c
+--- linux-2.4.1/net/korbit/ORBitutil/compat.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/compat.c Thu Feb 1 11:46:52 2001
+@@ -0,0 +1,43 @@
++#include "config.h"
++#include "util.h"
++
++#define MAX_IOVS 16
++
++int g_writev(int fd, const struct iovec * vector, size_t count)
++{
++ int retval = 0;
++
++ while(count > MAX_IOVS) {
++ retval += writev(fd, vector, MAX_IOVS);
++ vector += MAX_IOVS; count -= MAX_IOVS;
++ }
++
++ return writev(fd, vector, count) + retval;
++}
++
++#ifndef HAVE_INET_ATON
++#include <netinet/in.h>
++#include <string.h>
++int inet_aton(const char *cp, struct in_addr *inp)
++{
++ union {
++ unsigned int n;
++ char parts[4];
++ } u;
++ int a=0,b=0,c=0,d=0, i;
++
++ i = sscanf(cp, "%d.%d.%d.%d%*s", &a, &b, &c, &d);
++
++ if(i != 4)
++ return 0;
++
++ u.parts[0] = a;
++ u.parts[1] = b;
++ u.parts[2] = c;
++ u.parts[3] = d;
++
++ inp->s_addr = u.n;
++
++ return 1;
++}
++#endif
+diff -urN linux-2.4.1/net/korbit/ORBitutil/compat.h linux-2.4.1-korbit/net/korbit/ORBitutil/compat.h
+--- linux-2.4.1/net/korbit/ORBitutil/compat.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/compat.h Thu Feb 1 11:46:52 2001
+@@ -0,0 +1,8 @@
++#ifndef ORBITUTIL_COMPAT_H
++#define ORBITUTIL_COMPAT_H 1
++#include <sys/types.h>
++#include <sys/uio.h>
++
++int g_writev(int fd, const struct iovec * vector, size_t count);
++
++#endif /*#define ORBITUTIL_COMPAT_H 1 */
+diff -urN linux-2.4.1/net/korbit/ORBitutil/orbit-os-config.h linux-2.4.1-korbit/net/korbit/ORBitutil/orbit-os-config.h
+--- linux-2.4.1/net/korbit/ORBitutil/orbit-os-config.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/orbit-os-config.h Thu Feb 1 11:46:52 2001
+@@ -0,0 +1,8 @@
++#ifndef OS_CONFIG_H
++#define OS_CONFIG_H 1
++
++#ifndef __KORBIT__
++#define ORBIT_HAVE_ALLOCA_H 1
++#endif
++
++#endif
+diff -urN linux-2.4.1/net/korbit/ORBitutil/os-feature-alloca.h linux-2.4.1-korbit/net/korbit/ORBitutil/os-feature-alloca.h
+--- linux-2.4.1/net/korbit/ORBitutil/os-feature-alloca.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/os-feature-alloca.h Thu Feb 1 11:46:52 2001
+@@ -0,0 +1,26 @@
++#ifndef OS_FEATURE_ALLOCA_H
++#define OS_FEATURE_ALLOCA_H 1
++
++# if ORBIT_HAVE_ALLOCA_H
++# include <alloca.h>
++# endif
++
++# include <string.h>
++
++# if defined(__GNUC__)
++
++# if defined(__STRICT_ANSI__)
++# define alloca __builtin_alloca
++# endif
++
++# elif !(ORBIT_HAVE_ALLOCA_H)
++
++# if defined(_AIX)
++ #pragma alloca
++# elif !defined(alloca) /* predefined by HP cc +Olibcalls */
++char *alloca ();
++# endif
++
++# endif /* __GNUC__ etc. */
++
++#endif /* OS_FEATURE_ALLOCA_H */
+diff -urN linux-2.4.1/net/korbit/ORBitutil/os-specifics.h linux-2.4.1-korbit/net/korbit/ORBitutil/os-specifics.h
+--- linux-2.4.1/net/korbit/ORBitutil/os-specifics.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/os-specifics.h Thu Feb 1 11:46:52 2001
+@@ -0,0 +1,12 @@
++#ifndef ORBITUTIL_OS_SPECIFICS_H
++#define ORBITUTIL_OS_SPECIFICS_H 1
++
++#include <ORBitutil/orbit-os-config.h>
++
++#include <ORBitutil/os-feature-alloca.h>
++
++/* This file should be a bunch of #ifdef's to #include the
++ os-<osname>.h for the current OS. It is intended to abstract the
++ gunkiness necessary to get some OS's to build ORBit properly. */
++
++#endif
+diff -urN linux-2.4.1/net/korbit/ORBitutil/thread-safety.c linux-2.4.1-korbit/net/korbit/ORBitutil/thread-safety.c
+--- linux-2.4.1/net/korbit/ORBitutil/thread-safety.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/thread-safety.c Thu Feb 1 11:46:52 2001
+@@ -0,0 +1,19 @@
++#include "util.h"
++
++#ifdef NOT_REENTRANT
++#include <pthread.h>
++
++pthread_key_t thread_data;
++
++void init_thread_data(void) __attribute__ ((constructor));
++
++void init_thread_data(void)
++{
++ pthread_key_create(&thread_data, NULL);
++}
++
++#else
++
++gpointer prog_data = NULL;
++
++#endif
+diff -urN linux-2.4.1/net/korbit/ORBitutil/thread-safety.h linux-2.4.1-korbit/net/korbit/ORBitutil/thread-safety.h
+--- linux-2.4.1/net/korbit/ORBitutil/thread-safety.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/thread-safety.h Thu Feb 1 11:46:52 2001
+@@ -0,0 +1,36 @@
++#ifndef THREAD_SAFETY_H
++#define THREAD_SAFETY_H 1
++
++#ifdef NOT_REENTRANT
++
++#include <pthread.h>
++
++#define DEFINE_LOCK(x) pthread_mutex_t x##_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
++#define INIT_LOCK(x) /* We use static initialization, see above */
++#define GET_LOCK(x) pthread_mutex_lock(&x##_lock)
++#define RELEASE_LOCK(x) pthread_mutex_unlock(&x##_lock)
++#define PARAM_LOCK(x) pthread_mutex_t x##_lock
++#define LOCK_NAME(x) x##_lock
++#define EXTERN_LOCK(x) extern pthread_mutex_t x##_lock
++extern pthread_key_t thread_data;
++#define GET_THREAD_DATA() pthread_getspecific(thread_data)
++#define SET_THREAD_DATA(x) pthread_setspecific(thread_data, (x))
++
++#else
++
++/* stupid work around ANSI & empty semicolons. */
++#define DEFINE_LOCK(x)
++#define INIT_LOCK(x)
++#define GET_LOCK(x)
++#define RELEASE_LOCK(x)
++#define PARAM_LOCK(x) gpointer x##_lock
++#define LOCK_NAME(x) NULL
++#define EXTERN_LOCK(x)
++
++extern gpointer prog_data;
++#define GET_THREAD_DATA() prog_data
++#define SET_THREAD_DATA(x) (prog_data = (x))
++
++#endif
++
++#endif /* THREAD_SAFETY_H */
+diff -urN linux-2.4.1/net/korbit/ORBitutil/trace.c linux-2.4.1-korbit/net/korbit/ORBitutil/trace.c
+--- linux-2.4.1/net/korbit/ORBitutil/trace.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/trace.c Thu Feb 1 11:46:52 2001
+@@ -0,0 +1,94 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@acm.org>
++ *
++ */
++
++#include <stdio.h>
++#include <stdarg.h>
++
++#include "trace.h"
++
++/*
++ * The function to call to handle trace messages, or NULL to use the default
++ * of printing to stderr.
++ */
++#ifdef ORBIT_DEBUG
++static int (* TraceCallback)(char *, va_list)=NULL;
++static int TraceModules=0;
++static ORBit_TraceLevel TraceMaxLevel=0;
++
++const char *ORBit_Trace_levellist[] = {
++ "ALERT ",
++ "CRITICAL",
++ "ERROR ",
++ "WARNING ",
++ "NOTICE ",
++ "INFO ",
++ "DEBUG "
++};
++
++void ORBit_Trace_setCallback(int (*cbf)(char *, va_list))
++{
++ TraceCallback=cbf;
++}
++
++int (*ORBit_Trace_getCallback(void))(char *, va_list)
++{
++ return(TraceCallback);
++}
++
++void ORBit_Trace_setModules(int modules)
++{
++ TraceModules=modules;
++}
++
++void ORBit_Trace_setLevel(ORBit_TraceLevel level)
++{
++ TraceMaxLevel=level;
++}
++
++int ORBit_Trace(ORBit_TraceModule module, ORBit_TraceLevel level, char *fmt, ...)
++{
++ va_list args;
++
++ if(!BitTest(TraceModules, module))
++ return 0;
++ if(TraceMaxLevel < level)
++ return 0;
++
++ va_start(args, fmt);
++ if(TraceCallback!=NULL)
++ return((*TraceCallback)(fmt, args));
++
++#ifdef __KORBIT__
++ printf("[%s]: ", ORBit_Trace_levellist[level]);
++
++ printf("%s", g_strdup_vprintf(fmt, args));
++ return 0; // breaks semantics, but return value is never used
++#else /* !__KORBIT__ */
++ fprintf(stderr, "[%s]: ", ORBit_Trace_levellist[level]);
++
++ return vfprintf(stderr, fmt, args);
++#endif /* !__KORBIT__ */
++}
++#endif
+diff -urN linux-2.4.1/net/korbit/ORBitutil/trace.h linux-2.4.1-korbit/net/korbit/ORBitutil/trace.h
+--- linux-2.4.1/net/korbit/ORBitutil/trace.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/trace.h Thu Feb 1 11:46:52 2001
+@@ -0,0 +1,68 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter and Red Hat Software
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@acm.org>
++ *
++ */
++
++#ifndef _ORBIT_TRACE_H_
++#define _ORBIT_TRACE_H_
++
++#include <stdarg.h>
++#include "util.h"
++
++typedef enum {
++ TraceMod_ORB,
++ TraceMod_CDR,
++ TraceMod_IIOP,
++ TraceMod_TC,
++ TraceMod_IR,
++ TraceMod_User=32
++} ORBit_TraceModule;
++
++typedef enum {
++ TraceLevel_Alert=0,
++ TraceLevel_Critical,
++ TraceLevel_Error,
++ TraceLevel_Warning,
++ TraceLevel_Notice,
++ TraceLevel_Info,
++ TraceLevel_Debug
++} ORBit_TraceLevel;
++
++extern const char *ORBit_Trace_levellist[];
++
++#ifdef ORBIT_DEBUG
++extern void ORBit_Trace_setCallback(int (*)(char *, va_list));
++extern int (*ORBit_Trace_getCallback(void))(char *, va_list);
++extern void ORBit_Trace_setModules(int);
++extern void ORBit_Trace_setLevel(ORBit_TraceLevel);
++extern int ORBit_Trace(ORBit_TraceModule, ORBit_TraceLevel, char *, ...);
++#else
++#define ORBit_Trace_setCallback(x)
++#define ORBit_Trace_getCallback() NULL
++#define ORBit_Trace_setModules(x)
++#define ORBit_Trace_setLevel(x)
++#define ORBit_Trace(module,level,fmt,args...)
++#endif
++
++
++#endif /* !_ORBIT_TRACE_H_ */
+diff -urN linux-2.4.1/net/korbit/ORBitutil/util.h linux-2.4.1-korbit/net/korbit/ORBitutil/util.h
+--- linux-2.4.1/net/korbit/ORBitutil/util.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/util.h Thu Feb 1 11:46:52 2001
+@@ -0,0 +1,35 @@
++#ifndef UTIL_H
++#define UTIL_H 1
++
++#include <glib.h>
++
++#define ORBIT_DEBUG 1
++
++#ifdef ORBIT_DEBUG
++#define ORBIT_DEBUG_NOTE(x) (x)
++#else
++#define ORBIT_DEBUG_NOTE(x)
++#endif
++
++
++#define BitTest(f, bit) ((f) & (1<<(bit)))
++#define BitSet(f, bit) ((f) |= (1<<(bit)))
++#define BitClr(f, bit) ((f) &= ~(1<<(bit)))
++/* Align an address upward to a boundary, expressed as a number of bytes.
++ E.g. align to an 8-byte boundary with argument of 8. */
++
++/*
++ * (this + boundary - 1)
++ * &
++ * ~(boundary - 1)
++ */
++
++#define ALIGN_ADDRESS(this, boundary) \
++ ((gpointer)((( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))))
++
++#include <ORBitutil/thread-safety.h>
++#include <ORBitutil/trace.h>
++#include <ORBitutil/compat.h>
++#include <ORBitutil/os-specifics.h>
++
++#endif
+diff -urN linux-2.4.1/net/korbit/config.h linux-2.4.1-korbit/net/korbit/config.h
+--- linux-2.4.1/net/korbit/config.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/config.h Thu Feb 1 11:46:49 2001
+@@ -0,0 +1,73 @@
++
++/* Define if you have alloca, as a function or macro. */
++#define HAVE_ALLOCA 1
++
++#define HAVE_ATEXIT 1
++#define NO_SYS_SIGLIST 1 /* reduce dependencies */
++#define NO_SYS_ERRLIST 1 /* reduce dependencies */
++
++/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
++/* #define HAVE_ALLOCA_H 1 */
++
++/* Define if you have the vprintf function. */
++#define HAVE_VPRINTF 1
++
++/* Define if you have the ANSI C header files. */
++#define STDC_HEADERS 1
++
++#define HAVE_INET_ATON 1
++/* #undef ORBIT_SERIAL */
++
++/* Define to 'int' if it isn't defined in the header files. */
++/* #undef socklen_t */
++
++#define ALIGNOF_CORBA_BOOLEAN 1
++#define ALIGNOF_CORBA_CHAR 1
++#define ALIGNOF_CORBA_DOUBLE 4
++#define ALIGNOF_CORBA_FLOAT 4
++#define ALIGNOF_CORBA_LONG 4
++#define ALIGNOF_CORBA_LONG_DOUBLE 4
++#define ALIGNOF_CORBA_LONG_LONG 4
++#define ALIGNOF_CORBA_OCTET 1
++#define ALIGNOF_CORBA_SHORT 2
++#define ALIGNOF_CORBA_STRUCT 1
++#define ALIGNOF_CORBA_UNSIGNED_LONG 4
++#define ALIGNOF_CORBA_UNSIGNED_LONG_LONG 4
++#define ALIGNOF_CORBA_UNSIGNED_SHORT 2
++#define ALIGNOF_CORBA_WCHAR 2
++#define ALIGNOF_CORBA_POINTER 4
++
++/* TCP wrappers */
++#define HAVE_TCPD_H 1
++
++#ifdef HAVE_ALLOCA_H
++#include <alloca.h>
++#endif
++
++/* Define if you have the basename function. */
++#define HAVE_BASENAME 1
++
++/* Define if you have the poll function. */
++#define HAVE_POLL 1
++#define I_WANT_POLL 1
++
++/* Define if you have the <endian.h> header file. */
++#define HAVE_ENDIAN_H 1
++
++/* Define if you have the <fcntl.h> header file. */
++#define HAVE_FCNTL_H 1
++
++/* Define if you have the <stddef.h> header file. */
++#define HAVE_STDDEF_H 1
++
++/* Define if you have the <sys/poll.h> header file. */
++#define HAVE_SYS_POLL_H 1
++
++/* Define if you have the <tcpd.h> header file. */
++#define HAVE_TCPD_H 1
++
++/* Define if you have the <unistd.h> header file. */
++#define HAVE_UNISTD_H 1
++
++/* Define if you have the <wchar.h> header file. */
++#define HAVE_WCHAR_H 1
+diff -urN linux-2.4.1/net/korbit/exported_symbols.c linux-2.4.1-korbit/net/korbit/exported_symbols.c
+--- linux-2.4.1/net/korbit/exported_symbols.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/exported_symbols.c Thu Feb 1 11:46:49 2001
+@@ -0,0 +1,93 @@
++/*
++ * #include whatever it takes to get the EXPORT_SYMBOL macro, and
++ * whatever header files from korbit (for things that are being
++ * exported.
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include "errno.h"
++#include "orb/orbit.h"
++
++/*
++ * Stuff that's good to export
++ */
++EXPORT_SYMBOL(errno);
++
++/*
++ * kglib exports...
++ */
++EXPORT_SYMBOL(g_malloc0);
++EXPORT_SYMBOL(g_free);
++EXPORT_SYMBOL(g_snprintf);
++
++/*
++ * Mainline CORBA symbols.
++ */
++EXPORT_SYMBOL(CORBA_exception_init);
++EXPORT_SYMBOL(CORBA_ORB_init);
++EXPORT_SYMBOL(CORBA_ORB_resolve_initial_references);
++EXPORT_SYMBOL(CORBA_ORB_object_to_string);
++EXPORT_SYMBOL(CORBA_free);
++EXPORT_SYMBOL(CORBA_ORB_run);
++EXPORT_SYMBOL(CORBA_Object_release);
++EXPORT_SYMBOL(CORBA_Object_duplicate);
++EXPORT_SYMBOL(CORBA_octet_allocbuf);
++EXPORT_SYMBOL(CORBA_exception_set);
++EXPORT_SYMBOL(CORBA_string__free);
++EXPORT_SYMBOL(CORBA_ORB_string_to_object);
++EXPORT_SYMBOL(CORBA_string_alloc);
++EXPORT_SYMBOL(CORBA_exception_set_system);
++
++/*
++ * ORBIT Specific symbols to export
++ */
++EXPORT_SYMBOL(ORBit_TypeCode_epv);
++EXPORT_SYMBOL(ORBit_send_system_exception);
++EXPORT_SYMBOL(ORBit_register_class);
++EXPORT_SYMBOL(ORBit_marshal_object);
++EXPORT_SYMBOL(ORBit_alloc);
++EXPORT_SYMBOL(ORBit_free);
++EXPORT_SYMBOL(ORBit_send_user_exception);
++EXPORT_SYMBOL(ORBit_delete_profiles);
++EXPORT_SYMBOL(ORBit_demarshal_object);
++EXPORT_SYMBOL(_ORBit_object_get_connection);
++EXPORT_SYMBOL(ORBit_handle_exception);
++EXPORT_SYMBOL(ORBit_object_get_forwarded_connection);
++EXPORT_SYMBOL(ORBit_default_principal_iovec);
++EXPORT_SYMBOL(ORBit_demarshal_IOR);
++
++/*
++ * CORBA giop functions
++ */
++EXPORT_SYMBOL(giop_send_buffer_write);
++EXPORT_SYMBOL(giop_send_buffer_unuse);
++EXPORT_SYMBOL(giop_message_buffer_do_alignment);
++EXPORT_SYMBOL(giop_message_buffer_append_mem);
++EXPORT_SYMBOL(giop_send_reply_buffer_use);
++EXPORT_SYMBOL(giop_send_request_buffer_use);
++EXPORT_SYMBOL(giop_recv_buffer_unuse);
++EXPORT_SYMBOL(giop_recv_reply_buffer_use_2);
++
++/*
++ * POA Symbols.
++ */
++EXPORT_SYMBOL(PortableServer_POAManager_activate);
++EXPORT_SYMBOL(PortableServer_POA_activate_object_with_id);
++EXPORT_SYMBOL(PortableServer_POA_servant_to_reference);
++EXPORT_SYMBOL(PortableServer_POA_deactivate_object);
++EXPORT_SYMBOL(PortableServer_POA__get_the_POAManager);
++EXPORT_SYMBOL(PortableServer_ServantBase__init);
++EXPORT_SYMBOL(PortableServer_ServantBase__fini);
++EXPORT_SYMBOL(PortableServer_POA_reference_to_servant);
++EXPORT_SYMBOL(PortableServer_POA_servant_to_id);
++EXPORT_SYMBOL(PortableServer_POA_activate_object);
++EXPORT_SYMBOL(PortableServer_POA_reference_to_id);
++
++/*
++ * TC Stuff (whatever that is)
++ */
++EXPORT_SYMBOL(TC_octet_struct);
++EXPORT_SYMBOL(TC_long_struct);
++EXPORT_SYMBOL(TC_ulong_struct);
++EXPORT_SYMBOL(TC_short_struct);
++EXPORT_SYMBOL(TC_string_struct);
+diff -urN linux-2.4.1/net/korbit/include/.cvsignore linux-2.4.1-korbit/net/korbit/include/.cvsignore
+--- linux-2.4.1/net/korbit/include/.cvsignore Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/.cvsignore Thu Feb 1 11:46:53 2001
+@@ -0,0 +1 @@
++stdarg.h
+diff -urN linux-2.4.1/net/korbit/include/CVS/Entries linux-2.4.1-korbit/net/korbit/include/CVS/Entries
+--- linux-2.4.1/net/korbit/include/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/CVS/Entries Thu Feb 1 11:46:54 2001
+@@ -0,0 +1,24 @@
++/.cvsignore/1.1/Thu Feb 1 09:46:53 2001//
++/alloca.h/1.3/Thu Feb 1 09:46:53 2001//
++/assert.h/1.1.1.1/Thu Feb 1 09:46:53 2001//
++/ctype.h/1.1.1.1/Thu Feb 1 09:46:53 2001//
++/dirent.h/1.1.1.1/Thu Feb 1 09:46:53 2001//
++/errno.h/1.2/Thu Feb 1 09:46:53 2001//
++/fcntl.h/1.3/Thu Feb 1 09:46:53 2001//
++/host_list.h/1.7/Thu Feb 1 09:46:53 2001//
++/limits.h/1.1.1.1/Thu Feb 1 09:46:53 2001//
++/locale.h/1.1.1.1/Thu Feb 1 09:46:53 2001//
++/math.h/1.2/Thu Feb 1 09:46:53 2001//
++/netdb.h/1.17/Thu Feb 1 09:46:53 2001//
++/pwd.h/1.1.1.1/Thu Feb 1 09:46:53 2001//
++/signal.h/1.1.1.1/Thu Feb 1 09:46:53 2001//
++/stdarg.h/1.3/Thu Feb 1 09:46:54 2001//
++/stddef.h/1.1.1.1/Thu Feb 1 09:46:54 2001//
++/stdio.h/1.19/Thu Feb 1 09:46:54 2001//
++/stdlib.h/1.4/Thu Feb 1 09:46:54 2001//
++/string.h/1.3/Thu Feb 1 09:46:54 2001//
++/syslog.h/1.1.1.1/Thu Feb 1 09:46:54 2001//
++/time.h/1.1.1.1/Thu Feb 1 09:46:54 2001//
++/unistd.h/1.3/Thu Feb 1 09:46:54 2001//
++/utime.h/1.1.1.1/Thu Feb 1 09:46:54 2001//
++D
+diff -urN linux-2.4.1/net/korbit/include/CVS/Entries.Log linux-2.4.1-korbit/net/korbit/include/CVS/Entries.Log
+--- linux-2.4.1/net/korbit/include/CVS/Entries.Log Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/CVS/Entries.Log Thu Feb 1 11:46:55 2001
+@@ -0,0 +1,3 @@
++A D/arpa////
++A D/netinet////
++A D/sys////
+diff -urN linux-2.4.1/net/korbit/include/CVS/Repository linux-2.4.1-korbit/net/korbit/include/CVS/Repository
+--- linux-2.4.1/net/korbit/include/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/CVS/Repository Thu Feb 1 11:46:53 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/include
+diff -urN linux-2.4.1/net/korbit/include/CVS/Root linux-2.4.1-korbit/net/korbit/include/CVS/Root
+--- linux-2.4.1/net/korbit/include/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/CVS/Root Thu Feb 1 11:46:53 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/include/alloca.h linux-2.4.1-korbit/net/korbit/include/alloca.h
+--- linux-2.4.1/net/korbit/include/alloca.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/alloca.h Thu Feb 1 11:46:53 2001
+@@ -0,0 +1,6 @@
++#ifndef __KORBIT_ALLOCA_H__
++#define __KORBIT_ALLOCA_H__
++
++#include <stdlib.h>
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/arpa/CVS/Entries linux-2.4.1-korbit/net/korbit/include/arpa/CVS/Entries
+--- linux-2.4.1/net/korbit/include/arpa/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/arpa/CVS/Entries Thu Feb 1 11:46:55 2001
+@@ -0,0 +1,2 @@
++/inet.h/1.4/Thu Feb 1 09:46:54 2001//
++D
+diff -urN linux-2.4.1/net/korbit/include/arpa/CVS/Repository linux-2.4.1-korbit/net/korbit/include/arpa/CVS/Repository
+--- linux-2.4.1/net/korbit/include/arpa/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/arpa/CVS/Repository Thu Feb 1 11:46:54 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/include/arpa
+diff -urN linux-2.4.1/net/korbit/include/arpa/CVS/Root linux-2.4.1-korbit/net/korbit/include/arpa/CVS/Root
+--- linux-2.4.1/net/korbit/include/arpa/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/arpa/CVS/Root Thu Feb 1 11:46:54 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/include/arpa/inet.h linux-2.4.1-korbit/net/korbit/include/arpa/inet.h
+--- linux-2.4.1/net/korbit/include/arpa/inet.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/arpa/inet.h Thu Feb 1 11:46:54 2001
+@@ -0,0 +1,50 @@
++#ifndef __KORBIT_ARPA_INET_H__
++#define __KORBIT_ARPA_INET_H__
++
++#include <linux/inet.h>
++#include <linux/in.h>
++
++static inline char* inet_ntoa(struct in_addr in)
++{
++ return in_ntoa(in.s_addr);
++}
++
++static inline int inet_aton(const char *cp, struct in_addr *inp)
++{
++ unsigned long l;
++ unsigned int val;
++ int i;
++
++ if (!cp || !inp)
++ return 0;
++
++ l = 0;
++ for (i = 0; i < 4; i++)
++ {
++ l <<= 8;
++ if (*cp != '\0')
++ {
++ val = 0;
++ while (*cp != '\0' && *cp != '.')
++ {
++ if (*cp < '0' || '9' < *cp)
++ return 0;
++
++ val *= 10;
++ val += *cp - '0';
++ cp++;
++ }
++ if (val > 255)
++ return 0;
++
++ l |= val;
++ if (*cp != '\0')
++ cp++;
++ }
++ }
++ inp->s_addr = htonl(l);
++
++ return 1;
++}
++
++#endif /* __KORBIT_ARPA_INET_H__ */
+diff -urN linux-2.4.1/net/korbit/include/assert.h linux-2.4.1-korbit/net/korbit/include/assert.h
+--- linux-2.4.1/net/korbit/include/assert.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/assert.h Thu Feb 1 11:46:53 2001
+@@ -0,0 +1,3 @@
++#ifndef __KORBIT_ASSERT_H__
++#define __KORBIT_ASSERT_H__
++#endif
+diff -urN linux-2.4.1/net/korbit/include/ctype.h linux-2.4.1-korbit/net/korbit/include/ctype.h
+--- linux-2.4.1/net/korbit/include/ctype.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/ctype.h Thu Feb 1 11:46:53 2001
+@@ -0,0 +1,4 @@
++#ifndef __KORBIT_CTYPE_H__
++#define __KORBIT_CTYPE_H__
++#include <linux/ctype.h>
++#endif
+diff -urN linux-2.4.1/net/korbit/include/dirent.h linux-2.4.1-korbit/net/korbit/include/dirent.h
+--- linux-2.4.1/net/korbit/include/dirent.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/dirent.h Thu Feb 1 11:46:53 2001
+@@ -0,0 +1,3 @@
++#ifndef __KORBIT_DIRENT_H__
++#define __KORBIT_DIRENT_H__
++#endif
+diff -urN linux-2.4.1/net/korbit/include/errno.h linux-2.4.1-korbit/net/korbit/include/errno.h
+--- linux-2.4.1/net/korbit/include/errno.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/errno.h Thu Feb 1 11:46:53 2001
+@@ -0,0 +1,9 @@
++#ifndef __KORBIT_ERRNO_H__
++#define __KORBIT_ERRNO_H__
++
++#include <asm/errno.h>
++
++#define errno korbit_errno
++extern int korbit_errno;
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/fcntl.h linux-2.4.1-korbit/net/korbit/include/fcntl.h
+--- linux-2.4.1/net/korbit/include/fcntl.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/fcntl.h Thu Feb 1 11:46:53 2001
+@@ -0,0 +1,49 @@
++#ifndef __KORBIT_FCNTL_H__
++#define __KORBIT_FCNTL_H__
++
++#include <linux/mm.h>
++#include <linux/file.h>
++#include <linux/smp_lock.h>
++
++#include <asm/fcntl.h>
++
++#include <stdio.h>
++
++#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | FASYNC)
++
++static inline int fcntl(int fd, int cmd, long arg)
++{
++ struct file *filp = fd2file(fd);
++ long err = -EINVAL;
++
++ switch (cmd)
++ {
++ case F_SETFD:
++ case F_GETFD:
++ err = 0;
++ break;
++ case F_GETFL:
++ if (filp)
++ err = filp->f_flags;
++ break;
++ case F_SETFL:
++ if (filp)
++ {
++ lock_kernel();
++
++ /* required for strict SunOS emulation */
++ if (O_NONBLOCK != O_NDELAY)
++ if (arg & O_NDELAY)
++ arg |= O_NONBLOCK;
++
++ filp->f_flags = (arg & SETFL_MASK) |
++ (filp->f_flags & ~SETFL_MASK);
++ err = 0;
++ unlock_kernel();
++ }
++ break;
++ }
++ return err;
++}
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/host_list.h linux-2.4.1-korbit/net/korbit/include/host_list.h
+--- linux-2.4.1/net/korbit/include/host_list.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/host_list.h Thu Feb 1 11:46:53 2001
+@@ -0,0 +1,24 @@
++/*
++ * A statically-allocated list of Hostnames<->IPv4 addresses.
++ */
++#ifndef __KORBIT_HOST_LIST_H
++#define __KORBIT_HOST_LIST_H
++
++static struct {
++ char *name;
++ char *IP;
++} host_table[] = {
++ {"redefine.dyndns.org", "206.221.225.140"},
++ {"csil-sunb4.cs.uiuc.edu", "128.174.243.204"},
++ {"kazoo.cs.uiuc.edu", "128.174.237.133"},
++ {"opus0.cs.uiuc.edu", "128.174.236.20"},
++ {"wakeland-56.flexabit.net", "64.198.239.56"},
++ {"es-dcl-border1.cso.uiuc.edu", "127.0.0.1"},
++ {"es-dcl-border1", "127.0.0.1"}
++// {"es-dcl-border1.cso.uiuc.edu", "130.126.112.222"},
++// {"es-dcl-border1", "130.126.112.222"}
++};
++
++#define __MAX_STATIC_NAMES (sizeof(host_table) / sizeof(host_table[0]))
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/limits.h linux-2.4.1-korbit/net/korbit/include/limits.h
+--- linux-2.4.1/net/korbit/include/limits.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/limits.h Thu Feb 1 11:46:53 2001
+@@ -0,0 +1,7 @@
++#ifndef __KORBIT_LIMITS_H__
++#define __KORBIT_LIMITS_H__
++
++#include <linux/limits.h>
++#include <linux/kernel.h>
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/locale.h linux-2.4.1-korbit/net/korbit/include/locale.h
+--- linux-2.4.1/net/korbit/include/locale.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/locale.h Thu Feb 1 11:46:53 2001
+@@ -0,0 +1,3 @@
++#ifndef __KORBIT_LOCALE_H__
++#define __KORBIT_LOCALE_H__
++#endif
+diff -urN linux-2.4.1/net/korbit/include/math.h linux-2.4.1-korbit/net/korbit/include/math.h
+--- linux-2.4.1/net/korbit/include/math.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/math.h Thu Feb 1 11:46:53 2001
+@@ -0,0 +1,16 @@
++#ifndef __KORBIT_MATH_H__
++#define __KORBIT_MATH_H__
++
++#include <asm/page.h>
++
++static inline double pow(double x, double y) {
++ double Q = 1.0;
++ if (y < 0)
++ BUG();
++/* return 1.0/pow(x,-y);*/
++ while (y-- > 0)
++ Q *= x;
++ return Q;
++}
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/netdb.h linux-2.4.1-korbit/net/korbit/include/netdb.h
+--- linux-2.4.1/net/korbit/include/netdb.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/netdb.h Thu Feb 1 11:46:53 2001
+@@ -0,0 +1,197 @@
++#ifndef __KORBIT_NETDB_H__
++#define __KORBIT_NETDB_H__
++
++#include <sys/socket.h>
++#include <linux/in.h>
++#include <arpa/inet.h>
++#include "host_list.h"
++
++#define h_errno 0
++/* static int h_errno; */
++
++/* Description of data base entry for a single host. */
++struct hostent
++{
++ char *h_name; /* Official name of host. */
++ char **h_aliases; /* Alias list. */
++ int h_addrtype; /* Host address type. */
++ socklen_t h_length; /* Length of address. */
++ char **h_addr_list; /* List of addresses from name server. */
++#define h_addr h_addr_list[0] /* Address, for backward compatibility. */
++};
++
++/* Is this defined somewhere else? */
++/*struct in_addr {
++ __uint32_t s_addr;
++};*/
++
++/*
++ * Set h_errno?
++ * #define HOST_NOT_FOUND 1
++ * #define TRY_AGAIN 2
++ * #define NO_RECOVERY 3
++ * #define NO_DATA 4
++ */
++static inline struct hostent *gethostbyname (char *host)
++{
++ int c;
++ static struct in_addr tmp_in;
++ static struct hostent ret_host;
++ static char *aliases[2];
++ static char *addrs[2];
++
++ if (host == NULL)
++ {
++ printf ("** gethostbyname() Error: Got NULL parameter! **\n");
++ return (NULL);
++ }
++
++ /*
++ * The actual lookup.
++ */
++ for (c = 0; c < __MAX_STATIC_NAMES; c++)
++ {
++ if (host_table[c].name && strncmp (host, host_table[c].name, strlen(host_table[c].name)) == 0)
++ {
++/* printf ("Name '%s' found at position %d!\n", argv[1], c);*/
++/* printf ("IP address is: '%s'.\n", IPs[c]);*/
++ break;
++ }
++ }
++
++ if (c == __MAX_STATIC_NAMES)
++ {
++ /* Host not found, return NULL. */
++ return (NULL);
++ }
++ /* else, names[c] is gold! */
++
++ /* make a new hostent, ret_host */
++
++ ret_host.h_addrtype = AF_INET;
++ ret_host.h_aliases = aliases;
++ aliases[0] = host_table[c].name;
++ aliases[1] = NULL;
++ ret_host.h_name = host_table[c].name;
++ if (!inet_aton (host_table[c].IP, &tmp_in))
++ {
++ printf ("** gethostbyname() Error: Invalid IP address in table! **\n");
++ return (NULL);
++ }
++ ret_host.h_addr_list = addrs;
++ addrs[0] = (char *)&tmp_in.s_addr;
++ addrs[1] = NULL;
++ ret_host.h_length = sizeof (tmp_in.s_addr);
++ return (&ret_host);
++} /* End gethostbyname(). */
++
++/*
++ * TODO: getpeername(), gethostbyaddr(), getsockname(), gethostname()
++ * Everything from here-on has been untested (in userland). Buyer beware.
++ */
++static inline struct hostent *gethostbyaddr (const char *addr, int len, int type)
++{
++ struct in_addr tin;
++ char *inp_addr;
++ int c;
++ static struct hostent ret_host;
++ static char *aliases[1];
++ static char *addrs[2];
++ static struct in_addr tmp_in;
++
++
++ if ((type != AF_INET) || (len != 4))
++ {
++ printf ("** gethostbyaddr Error: Don't know how to deal with non-AF_INET addresses! **\n");
++ return (NULL);
++ }
++
++ tin.s_addr = *((__u32 *)addr);
++ inp_addr = inet_ntoa (tin);
++ if (inp_addr == NULL)
++ {
++ /* We got some invalid input, baby. */
++ return (NULL);
++
++ }
++
++ /*
++ * The actual lookup.
++ */
++ for (c = 0; c < __MAX_STATIC_NAMES; c++)
++ {
++ if (host_table[c].IP && strncmp (inp_addr, host_table[c].IP, strlen(host_table[c].IP)) == 0)
++ {
++ break;
++ }
++ }
++
++ if (c == __MAX_STATIC_NAMES)
++ {
++ /* Host not found, return NULL. */
++ return (NULL);
++ }
++ /* else, host_table[c].IP is gold! */
++
++ ret_host.h_addrtype = AF_INET;
++ ret_host.h_aliases = aliases;
++ aliases[0] = NULL;
++ ret_host.h_name = host_table[c].name;
++ if (!inet_aton (host_table[c].IP, &tmp_in))
++ {
++ printf ("** gethostbyname() Error: Invalid IP address in table! **\n");
++ return (NULL);
++ }
++ ret_host.h_addr_list = addrs;
++ addrs[0] = (char *)&tmp_in.s_addr;
++ addrs[1] = NULL;
++ ret_host.h_length = sizeof (tmp_in.s_addr);
++ return (&ret_host);
++} /* End gethostbyaddr(). */
++
++/*
++ * If successful, return 0. Else, return -1 and set errno.
++ * Errors:
++ * EBADF The argument s is not a valid file descriptor.
++ *
++ * ENOMEM
++ * There was insufficient memory available for the opera-
++ * tion to complete.
++ *
++ * ENOSR There were insufficient STREAMS resources available
++ * for the operation to complete.
++ *
++ * ENOTSOCK
++ * The argument s is not a socket.
++ */
++static inline int getsockname (int s, struct sockaddr *name, socklen_t *namelen)
++{
++ struct socket *sock = fd2sock(s);
++
++ if (sock == NULL)
++ return -1;
++
++ /*
++ * getname() wants an 'int *' for the length, will it by this
++ * 'socklen_t *' business? (even though it is just an 'int *'?).
++ */
++ if (sock->ops->getname(sock, name, namelen, 0) == 0)
++ return 0;
++ else
++ return -1; /* should normally also set errno */
++} /* End getsockname(). */
++
++static inline int getpeername (int s, struct sockaddr *name, socklen_t *namelen)
++{
++ struct socket *sock = fd2sock(s);
++
++ if (sock == NULL)
++ return -1;
++
++ if (sock->ops->getname(sock, name, namelen, 1) == 0)
++ return 0;
++ else
++ return -1; /* should normally also set errno */
++} /* End getpeername(). */
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/netinet/CVS/Entries linux-2.4.1-korbit/net/korbit/include/netinet/CVS/Entries
+--- linux-2.4.1/net/korbit/include/netinet/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/netinet/CVS/Entries Thu Feb 1 11:46:55 2001
+@@ -0,0 +1,2 @@
++/in.h/1.1.1.1/Thu Feb 1 09:46:55 2001//
++D
+diff -urN linux-2.4.1/net/korbit/include/netinet/CVS/Repository linux-2.4.1-korbit/net/korbit/include/netinet/CVS/Repository
+--- linux-2.4.1/net/korbit/include/netinet/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/netinet/CVS/Repository Thu Feb 1 11:46:55 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/include/netinet
+diff -urN linux-2.4.1/net/korbit/include/netinet/CVS/Root linux-2.4.1-korbit/net/korbit/include/netinet/CVS/Root
+--- linux-2.4.1/net/korbit/include/netinet/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/netinet/CVS/Root Thu Feb 1 11:46:55 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/include/netinet/in.h linux-2.4.1-korbit/net/korbit/include/netinet/in.h
+--- linux-2.4.1/net/korbit/include/netinet/in.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/netinet/in.h Thu Feb 1 11:46:55 2001
+@@ -0,0 +1,5 @@
++#ifndef __KORBIT_NETINET_IN_H__
++#define __KORBIT_NETINET_IN_H__
++#include <linux/socket.h>
++#include <linux/in.h>
++#endif
+diff -urN linux-2.4.1/net/korbit/include/pwd.h linux-2.4.1-korbit/net/korbit/include/pwd.h
+--- linux-2.4.1/net/korbit/include/pwd.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/pwd.h Thu Feb 1 11:46:53 2001
+@@ -0,0 +1,3 @@
++#ifndef __KORBIT_PWD_H__
++#define __KORBIT_PWD_H__
++#endif
+diff -urN linux-2.4.1/net/korbit/include/signal.h linux-2.4.1-korbit/net/korbit/include/signal.h
+--- linux-2.4.1/net/korbit/include/signal.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/signal.h Thu Feb 1 11:46:53 2001
+@@ -0,0 +1,6 @@
++#ifndef __KORBIT_SIGNAL_H__
++#define __KORBIT_SIGNAL_H__
++
++#include <asm/signal.h>
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/stdarg.h linux-2.4.1-korbit/net/korbit/include/stdarg.h
+--- linux-2.4.1/net/korbit/include/stdarg.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/stdarg.h Thu Feb 1 11:46:54 2001
+@@ -0,0 +1,13 @@
++#ifndef __KORBIT_STDARG_H__
++#define __KORBIT_STDARG_H__
++
++#define ANDY 1
++
++#if FREDRIK
++#include "/usr/lib/gcc-lib/i386-glibc21-linux/egcs-2.91.66/include/stdarg.h"
++#elif CHRIS
++#include "/usr/lib/gcc-lib/i586-mandrake-linux/egcs-2.91.66/include/stdarg.h"
++#elif ANDY
++#include "/usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/include/stdarg.h"
++#endif
++#endif
+diff -urN linux-2.4.1/net/korbit/include/stddef.h linux-2.4.1-korbit/net/korbit/include/stddef.h
+--- linux-2.4.1/net/korbit/include/stddef.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/stddef.h Thu Feb 1 11:46:54 2001
+@@ -0,0 +1,3 @@
++#ifndef __KORBIT_STDDEF_H__
++#define __KORBIT_STDDEF_H__
++#endif
+diff -urN linux-2.4.1/net/korbit/include/stdio.h linux-2.4.1-korbit/net/korbit/include/stdio.h
+--- linux-2.4.1/net/korbit/include/stdio.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/stdio.h Thu Feb 1 11:46:54 2001
+@@ -0,0 +1,402 @@
++#ifndef __KORBIT_STDIO_H__
++#define __KORBIT_STDIO_H__
++
++#include <asm/segment.h>
++#include <asm/uaccess.h>
++#include <linux/smp_lock.h>
++#include <linux/kernel.h>
++#include <linux/fs.h>
++#include <linux/sched.h>
++#include <linux/uio.h>
++#include <linux/dcache.h>
++#include <linux/file.h>
++#include <linux/highuid.h>
++#include <sys/socket.h>
++
++#include <errno.h>
++
++#define KORBIT_DEBUG_WRITING 0
++
++
++#define printf(format,args...) printk(format,##args)
++#define fflush(x)
++
++#define SEEK_SET 0 /* Seek from beginning of file. */
++#define SEEK_CUR 1 /* Seek from current position. */
++#define SEEK_END 2 /* Seek from end of file. */
++
++static inline int unlink(const char *pathname) {
++ printf("KERNEL UNLINK('%s') CALLED!\n", pathname);
++ return -1;
++}
++
++static inline struct file *fd2file(int fd) {
++ if (fd & 1) /* can't convert a socket! */
++ return NULL;
++
++ return (struct file *)(-(fd & ~1));
++}
++
++static inline int open(const char *filename, int flags, int mode) {
++ struct file *RetVal = filp_open(filename, flags, mode);
++ if (IS_ERR(RetVal))
++ {
++ errno = PTR_ERR(RetVal);
++ return -1;
++ }
++ return -(int)RetVal;
++}
++
++static inline int creat(const char *filename, mode_t mode)
++{
++ return open(filename, O_CREAT | O_WRONLY | O_TRUNC, mode);
++}
++
++static inline int lseek(int fd, long offset, int whence)
++{
++ if ((fd & 1) == 1)
++ {
++ printk("KERNEL FSEEK() CALLED ON SOCKET!\n");
++ return -1;
++ }
++ else
++ {
++ struct file *F = fd2file(fd);
++ loff_t (*fn)(struct file *, loff_t, int);
++ int retval = -1;
++
++ if (whence <= 2)
++ {
++ fn = default_llseek;
++ if (F->f_op && F->f_op->llseek)
++ fn = F->f_op->llseek;
++
++ lock_kernel();
++ retval = fn(F, offset, whence);
++ unlock_kernel();
++ }
++ if (retval < 0)
++ {
++ errno = -retval;
++ retval = -1;
++ }
++ return retval;
++ }
++}
++
++
++asmlinkage long sys_newstat(char * filename, struct stat * statbuf);
++static inline int stat(char *filename, struct stat *buf)
++{
++ mm_segment_t oldfs;
++ int retval;
++
++ oldfs = get_fs(); set_fs(KERNEL_DS);
++ retval = sys_newstat(filename, buf);
++ set_fs(oldfs);
++ if (retval < 0)
++ {
++ errno = -retval;
++ retval = -1;
++ }
++ return retval;
++}
++
++asmlinkage long sys_newlstat(char * filename, struct stat * statbuf);
++static inline int lstat(char *filename, struct stat *buf)
++{
++ mm_segment_t oldfs;
++ int retval;
++
++ oldfs = get_fs(); set_fs(KERNEL_DS);
++ retval = sys_newlstat(filename, buf);
++ set_fs(oldfs);
++ if (retval < 0)
++ {
++ errno = -retval;
++ retval = -1;
++ }
++ return retval;
++}
++
++
++static inline int do_revalidate(struct dentry *dentry)
++{
++ struct inode * inode = dentry->d_inode;
++ if (inode->i_op && inode->i_op->revalidate)
++ return inode->i_op->revalidate(dentry);
++ return 0;
++}
++
++
++static inline int cp_new_stat(struct inode * inode, struct stat * statbuf)
++{
++ struct stat tmp;
++
++ memset(&tmp, 0, sizeof(tmp));
++ tmp.st_dev = kdev_t_to_nr(inode->i_dev);
++ tmp.st_ino = inode->i_ino;
++ tmp.st_mode = inode->i_mode;
++ tmp.st_nlink = inode->i_nlink;
++ SET_STAT_UID(tmp, inode->i_uid);
++ SET_STAT_GID(tmp, inode->i_gid);
++ tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
++#if BITS_PER_LONG == 32
++ if (inode->i_size > 0x7fffffff)
++ return -EOVERFLOW;
++ else
++#endif
++ {
++ tmp.st_size = inode->i_size;
++ tmp.st_atime = inode->i_atime;
++ tmp.st_mtime = inode->i_mtime;
++ tmp.st_ctime = inode->i_ctime;
++
++ tmp.st_blocks = inode->i_blocks;
++ tmp.st_blksize = inode->i_blksize;
++
++ memcpy(statbuf, &tmp, sizeof(tmp));
++ return 0;
++ }
++}
++
++
++static inline int fstat(int fd, struct stat *buf)
++{
++ if ((fd & 1) == 1)
++ {
++ printk("TODO : FSTAT FOR SOCKETS, DO WE WANT THIS?\n");
++ errno = EBADF;
++ return -1;
++ }
++ else
++ {
++ struct file *file = fd2file(fd);
++ struct dentry *dentry;
++ int retval = -EBADF;
++
++ if (file)
++ {
++ dentry = file->f_dentry;
++ retval = do_revalidate(dentry);
++
++ if (!retval)
++ retval = cp_new_stat(dentry->d_inode, buf);
++ }
++ if (retval < 0)
++ {
++ errno = -retval;
++ retval = -1;
++ }
++ return retval;
++ }
++}
++
++
++asmlinkage long sys_readlink(const char * path, char * buf, int bufsiz);
++static inline int readlink(const char *path, char *buf, size_t bufsiz)
++{
++ int retval;
++ mm_segment_t oldfs;
++
++ oldfs = get_fs(); set_fs(KERNEL_DS);
++ retval = sys_readlink(path, buf, bufsiz);
++ set_fs(oldfs);
++ if (retval < 0)
++ {
++ errno = -retval;
++ retval = -1;
++ }
++ return retval;
++}
++
++
++static inline int read(int fd, void *buffer, size_t count) {
++ if ((fd & 1) == 1)
++ {
++ struct socket *sock = fd2sock(fd);
++ struct iovec iov;
++ struct msghdr msg;
++ mm_segment_t oldfs;
++ int flags = 0;
++ int RetVal;
++
++ msg.msg_name = NULL;
++ msg.msg_namelen = 0;
++ msg.msg_iov = &iov;
++ msg.msg_iovlen = 1;
++ msg.msg_control = NULL;
++ msg.msg_controllen = 0;
++ msg.msg_flags = 0;
++ iov.iov_base = buffer;
++ iov.iov_len = count;
++ oldfs = get_fs(); set_fs(KERNEL_DS);
++ RetVal = sock_recvmsg(sock, &msg, count, flags);
++ set_fs(oldfs);
++ if (RetVal < 0)
++ {
++ errno = -RetVal;
++ RetVal = -1;
++ }
++ return RetVal;
++ }
++ else
++ {
++ struct file *F = fd2file(fd);
++ mm_segment_t oldfs;
++ int RetVal;
++
++ oldfs = get_fs();
++ set_fs(KERNEL_DS);
++ RetVal = F->f_op->read(F, buffer, count, &F->f_pos);
++ set_fs(oldfs);
++ if (RetVal < 0)
++ {
++ errno = -RetVal;
++ RetVal = -1;
++ }
++ return RetVal;
++ }
++}
++
++static inline int write(int fd, const void *buffer, size_t count) {
++ if ((fd & 1) == 1)
++ {
++ struct socket *sock = fd2sock(fd);
++ struct iovec iov;
++ struct msghdr msg;
++ mm_segment_t oldfs;
++ int RetVal;
++ msg.msg_name = NULL;
++ msg.msg_namelen = 0;
++ msg.msg_iov = &iov;
++ msg.msg_iovlen = 1;
++ msg.msg_control = NULL;
++ msg.msg_controllen = 0;
++ msg.msg_flags = MSG_NOSIGNAL;
++ if (sock->type == SOCK_SEQPACKET)
++ msg.msg_flags |= MSG_EOR;
++ iov.iov_base = (void *)buffer;
++ iov.iov_len = count;
++
++ oldfs = get_fs(); set_fs(KERNEL_DS);
++ RetVal = sock_sendmsg(sock, &msg, count);
++ set_fs(oldfs);
++ if (RetVal < 0)
++ {
++ errno = -RetVal;
++ RetVal = -1;
++ }
++ return RetVal;
++ }
++ else
++ {
++ struct file *F = fd2file(fd);
++ mm_segment_t oldfs;
++ int RetVal;
++
++ oldfs = get_fs();
++ set_fs(KERNEL_DS);
++ RetVal = F->f_op->write(F, buffer, count, &F->f_pos);
++ set_fs(oldfs);
++ if (RetVal < 0)
++ {
++ errno = -RetVal;
++ RetVal = -1;
++ }
++ return RetVal;
++ }
++}
++
++static inline int writev(int fd, const struct iovec *vector, int count) {
++#ifndef DONT_USE_SIMPLE_WRITEV
++ int i, amount = 0;
++#if KORBIT_DEBUG_WRITING
++ printk("writev (fd = 0x%X, vec=0x%p, count = %d)\n", fd, vector, count);
++#endif
++ for (i = 0; i < count; i++) {
++ char *Buf = vector[i].iov_base;
++ int Amount = vector[i].iov_len;
++ while (Amount > 0) {
++ int A = write(fd, Buf, Amount);
++//#if KORBIT_DEBUG_WRITING
++if (A < Amount)
++ printk(" write(fd = 0x%X, buf = 0x%p, size = 0x%X) "
++ "= 0x%X errno = 0x%X\n", fd, Buf, Amount, A, errno);
++//#endif
++ Amount -= A;
++ amount += A;
++ Buf += A;
++ if (Amount > 0) schedule(); // Behave somewhat nicely...
++ }
++ }
++
++#if KORBIT_DEBUG_WRITING
++ printk("writev returning 0x%X[%d]\n", amount, amount);
++#endif
++ return amount;
++
++#else
++ if ((fd & 1) == 1)
++ {
++ struct socket *sock = fd2sock(fd);
++ struct msghdr msg;
++ mm_segment_t oldfs;
++ int i, RetVal;
++ size_t tot_len = 0;
++
++ for (i = 0; i < count; i++)
++ tot_len += vector[i].iov_len;
++
++ msg.msg_name = NULL;
++ msg.msg_namelen = 0;
++ msg.msg_iov = (struct iovec *)vector;
++ msg.msg_iovlen = count;
++ msg.msg_control = NULL;
++ msg.msg_controllen = 0;
++ if (sock->type == SOCK_SEQPACKET)
++ msg.msg_flags |= MSG_EOR;
++
++ oldfs = get_fs(); set_fs(KERNEL_DS);
++ RetVal = sock_sendmsg(sock, &msg, tot_len);
++ set_fs(oldfs);
++ if (RetVal < 0)
++ {
++ errno = -RetVal;
++ RetVal = -1;
++ }
++ return RetVal;
++ }
++ else
++ {
++ struct file *F = fd2file(fd);
++ mm_segment_t oldfs;
++ int RetVal;
++
++ oldfs = get_fs();
++ set_fs(KERNEL_DS);
++ RetVal = F->f_op->writev(F, vector, (unsigned)count, &F->f_pos);
++ set_fs(oldfs);
++ if (RetVal < 0)
++ {
++ errno = -RetVal;
++ RetVal = -1;
++ }
++ return RetVal;
++ }
++#endif
++}
++
++static inline int close(int fd) {
++ int err = 0;
++ if ((fd & 1) == 1) {
++ struct socket *sock = fd2sock(fd);
++ sock_release(sock);
++ } else {
++ struct file *file = fd2file(fd);
++ fput(file);
++ }
++ return err;
++}
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/stdlib.h linux-2.4.1-korbit/net/korbit/include/stdlib.h
+--- linux-2.4.1/net/korbit/include/stdlib.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/stdlib.h Thu Feb 1 11:46:54 2001
+@@ -0,0 +1,99 @@
++#ifndef __KORBIT_STDLIB_H__
++#define __KORBIT_STDLIB_H__
++
++#include <linux/kernel.h>
++#include <linux/malloc.h>
++#include <linux/types.h>
++#include <asm/string.h>
++
++#define strtol(nptr,endptr,base) simple_strtol(nptr,endptr,base)
++
++#if 0
++#define malloc(size) kmalloc(size, GFP_KERNEL)
++#define free(ptr) kfree(ptr)
++#endif
++
++static inline void *malloc(size_t size)
++{
++ void *ptr = NULL;
++
++ if (size == 0)
++ size = 4;
++
++ ptr = kmalloc(size + sizeof(size), GFP_KERNEL);
++
++ if (ptr)
++ {
++ *((size_t *)ptr) = size;
++ ptr = (size_t *)ptr + 1;
++ }
++
++ return ptr;
++}
++
++static inline void free(void *ptr)
++{
++ if (ptr)
++ kfree((size_t *)ptr - 1);
++}
++
++#define alloca(size) malloc(size)
++
++/* freeca(ptr) - free a mem allocation if ptr points to one, otherwise do
++ * nothing.
++ */
++static inline void freeca(void *ptr)
++{
++ if (ptr != NULL) { /* Don't free it if it's already free */
++ free(ptr);
++ }
++}
++
++static inline void *calloc(size_t nmemb, size_t size)
++{
++ void *ptr = malloc(nmemb*size);
++ if (ptr)
++ memset(ptr,0,nmemb*size);
++ return ptr;
++}
++
++static inline void *realloc(void *ptr, size_t size)
++{
++ void *newptr = NULL;
++
++ if (size != 0)
++ newptr = malloc(size);
++
++ if (ptr && newptr) /* Copy old contents */
++ {
++ size_t *p1 = (size_t *)ptr - 1;
++ size_t *p2 = (size_t *)newptr - 1;
++ size_t n = *p1 < *p2 ? *p1 : *p2;
++ memcpy(newptr, ptr, n);
++ }
++
++ if (ptr)
++ free(ptr);
++
++ return newptr;
++}
++
++/* Returned by `div'. */
++typedef struct
++{
++ int quot; /* Quotient. */
++ int rem; /* Remainder. */
++} div_t;
++
++static inline div_t div(int number, int denom)
++{
++ div_t result;
++ result.quot = number/denom;
++ result.rem = number-(number*result.quot);
++ return result;
++}
++
++#define atexit(fn) -1
++#define getenv(name) 0
++
++#endif /* __KORBIT_STDLIB_H__ */
+diff -urN linux-2.4.1/net/korbit/include/string.h linux-2.4.1-korbit/net/korbit/include/string.h
+--- linux-2.4.1/net/korbit/include/string.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/string.h Thu Feb 1 11:46:54 2001
+@@ -0,0 +1,11 @@
++#ifndef __KORBIT_STRING_H__
++#define __KORBIT_STRING_H__
++
++#include <linux/types.h>
++#include <asm/string.h>
++
++#include <glib.h>
++
++#define strerror(errno) g_strerror(errno)
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/sys/CVS/Entries linux-2.4.1-korbit/net/korbit/include/sys/CVS/Entries
+--- linux-2.4.1/net/korbit/include/sys/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/sys/CVS/Entries Thu Feb 1 11:46:56 2001
+@@ -0,0 +1,10 @@
++/ioctl.h/1.1.1.1/Thu Feb 1 09:46:55 2001//
++/poll.h/1.25/Thu Feb 1 09:46:55 2001//
++/socket.h/1.20/Thu Feb 1 09:46:55 2001//
++/stat.h/1.1.1.1/Thu Feb 1 09:46:55 2001//
++/time.h/1.1.1.1/Thu Feb 1 09:46:55 2001//
++/types.h/1.1.1.1/Thu Feb 1 09:46:56 2001//
++/uio.h/1.1.1.1/Thu Feb 1 09:46:56 2001//
++/un.h/1.1.1.1/Thu Feb 1 09:46:56 2001//
++/wait.h/1.1.1.1/Thu Feb 1 09:46:56 2001//
++D
+diff -urN linux-2.4.1/net/korbit/include/sys/CVS/Repository linux-2.4.1-korbit/net/korbit/include/sys/CVS/Repository
+--- linux-2.4.1/net/korbit/include/sys/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/sys/CVS/Repository Thu Feb 1 11:46:55 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/include/sys
+diff -urN linux-2.4.1/net/korbit/include/sys/CVS/Root linux-2.4.1-korbit/net/korbit/include/sys/CVS/Root
+--- linux-2.4.1/net/korbit/include/sys/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/sys/CVS/Root Thu Feb 1 11:46:55 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/include/sys/ioctl.h linux-2.4.1-korbit/net/korbit/include/sys/ioctl.h
+--- linux-2.4.1/net/korbit/include/sys/ioctl.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/sys/ioctl.h Thu Feb 1 11:46:55 2001
+@@ -0,0 +1,3 @@
++#ifndef __KORBIT_SYS_IOCTL_H__
++#define __KORBIT_SYS_IOCTL_H__
++#endif
+diff -urN linux-2.4.1/net/korbit/include/sys/poll.h linux-2.4.1-korbit/net/korbit/include/sys/poll.h
+--- linux-2.4.1/net/korbit/include/sys/poll.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/sys/poll.h Fri Feb 2 01:22:10 2001
+@@ -0,0 +1,112 @@
++#ifndef __KORBIT_SYS_POLL_H__
++#define __KORBIT_SYS_POLL_H__
++
++#include <asm/poll.h>
++#include <asm/param.h>
++#include <linux/net.h>
++#include <linux/tcp.h>
++#include <linux/socket.h>
++#include <net/tcp.h>
++#include <net/sock.h>
++#include <linux/skbuff.h>
++#include <linux/sched.h>
++#include "stdlib.h"
++#include "sys/socket.h"
++
++/* Poll the file descriptors described by the NFDS structures starting at
++ * FDS. If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for
++ * an event to occur; if TIMEOUT is -1, block until an event occurs.
++ * Returns the number of file descriptors with events, zero if timed
++ * out, or -1 for errors.
++ */
++
++/* This implementation of poll assumes that we are sitting on the wait
++ * queues for all of the file descriptors already. Therefore if we are about
++ * to block, all we have to do is perform the schedule call which will
++ * automatically cause us to "block".
++ */
++static int poll_CheckFDs(struct pollfd *fds, unsigned long int nfds)
++{
++ int NumReady = 0, i;
++
++ // Loop over the file descriptors seeing if there is already work to be
++ // done...
++ for (i = 0; i < nfds; i++) {
++ struct socket *sock = fd2sock(fds[i].fd);
++ fds[i].revents = 0;
++
++ // Check to see if stuff is available to read
++ if (sock) {
++ // It's a socket baby
++ fds[i].revents = tcp_poll(0, sock, 0);
++
++ // Apparently tcp_poll doesn't look at the CLOSE_WAIT value,
++ // and we have a lot of sockets that end up in this state.
++ // This is a hack to shortcircuit some read failures from
++ // later. This breaks "poll semantics" strictly speaking, but
++ // it's basically the "right thing to do" (tm).
++ if (sock->sk->state == TCP_CLOSE_WAIT)
++ fds[i].revents = POLLHUP;
++ fds[i].revents &= fds[i].events | POLLERR | POLLHUP;
++ } else {
++ // It's a file
++ //struct file *f = fd2file(fd);
++// printk("POLL NOT IMPLEMENTED FOR FILES YET\n");
++ BUG();
++ }
++
++ if (fds[i].revents) {
++ NumReady++;
++// printk("FD #%d: Event = 0x%X\n", i, fds[i].revents);
++ }
++
++ } /* for */
++
++ return NumReady;
++} /* End poll_CheckFDs(). */
++
++
++static int poll(struct pollfd *fds, unsigned long int nfds, int timeout) {
++ wait_queue_t *WaitQueues = 0;
++ int NumReady = poll_CheckFDs(fds, nfds);
++ int i;
++
++ if (NumReady || timeout == 0)
++ return NumReady;
++
++// printk("Starting to Poll... %d fds...\n", nfds);
++ WaitQueues = (wait_queue_t*)malloc(nfds*sizeof(wait_queue_t));
++ if (WaitQueues == 0) return 0; // Crap, nomem...
++
++ for (i = 0; i < nfds; i++) {
++ struct socket *sock = fd2sock(fds[i].fd);
++ init_waitqueue_entry(WaitQueues+i, current);
++
++ if (sock)
++ add_wait_queue_exclusive(sock->sk->sleep, WaitQueues+i);
++// else
++// printk("I don't know how to wait on fd #%d = 0x%X\n", i, fds[i].fd);
++ }
++
++ // Wait for us to get notified by one of the socket wait queue notifiers!
++ do {
++ // Change our task state so that we are not immediately rescheduled.
++ // This lets the scheduler know that we are waiting for something to happen
++ set_current_state(TASK_INTERRUPTIBLE);
++ schedule();
++ } while (!(NumReady = poll_CheckFDs(fds, nfds)));
++
++ set_current_state(TASK_RUNNING);
++
++ for (i = 0; i < nfds; i++) {
++ struct socket *sock = fd2sock(fds[i].fd);
++ if (sock)
++ remove_wait_queue(sock->sk->sleep, WaitQueues+i);
++ }
++
++ free(WaitQueues);
++// printk("Returning %d\n", NumReady);
++ return NumReady;
++}
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/sys/socket.h linux-2.4.1-korbit/net/korbit/include/sys/socket.h
+--- linux-2.4.1/net/korbit/include/sys/socket.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/sys/socket.h Thu Feb 1 11:46:55 2001
+@@ -0,0 +1,126 @@
++#ifndef __KORBIT_SYS_SOCKET_H__
++#define __KORBIT_SYS_SOCKET_H__
++typedef unsigned int socklen_t;
++
++#include <linux/socket.h>
++#include <linux/wait.h>
++#include <asm/semaphore.h>
++#include <net/sock.h>
++
++/* These functions are declared in net/socket.c */
++asmlinkage long sys_socket(int family, int type, int protocol);
++struct socket *sockfd_lookup(int fd, int *err);
++
++
++static inline int sock2fd(struct socket *s)
++{
++ return (-(int)s) | 1;
++}
++
++static inline struct socket *fd2sock(int sockfd)
++{
++ if ((sockfd & 1) == 0) /* can't convert a file! */
++ return NULL;
++
++ return (struct socket *)(-(sockfd & ~1));
++}
++
++
++static inline int socket(int domain, int type, int protocol) {
++ struct socket *sock;
++ int retval = sock_create(domain, type, protocol, &sock);
++
++ if (retval < 0) return (int)NULL;
++ return sock2fd(sock);
++}
++
++
++static inline int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen)
++{
++ struct socket *sock = fd2sock(sockfd);
++
++ if (sock == NULL)
++ return -1;
++ if (!sock->ops->bind(sock, my_addr, addrlen))
++ return 0;
++ else
++ return -1; /* should normally also set errno */
++}
++
++
++static inline int connect(int sockfd, const struct sockaddr *serv_addr,
++ socklen_t addrlen)
++{
++ struct socket *sock = fd2sock(sockfd);
++ int flags = 0; /* TODO : what is flags supposed to be? */
++
++ if (sock == NULL)
++ return -1;
++
++ if (sock->ops->connect(sock, (struct sockaddr *)serv_addr, addrlen, flags) == 0)
++ return 0;
++ else
++ return -1; /* should normally also set errno */
++}
++
++
++static inline int listen(int sockfd, int backlog)
++{
++ struct socket *sock = fd2sock(sockfd);
++
++ if (sock == NULL)
++ return -1;
++
++ if (sock->ops->listen(sock, backlog) == 0)
++ return 0;
++ else
++ return -1; /* should normally also set errno */
++}
++
++
++static inline int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
++{
++ struct socket *sock = fd2sock(sockfd);
++ struct socket *newsock;
++ struct sockaddr_in *newaddr = (struct sockaddr_in *)addr; /* check? */
++ int flags = 0; /* Should be ok */
++
++ if (sock == 0)
++ return -1;
++
++ newsock = sock_alloc();
++ if (newsock == 0)
++ return -1;
++
++ newsock->type = sock->type;
++ newsock->ops = sock->ops;
++ if (sock->ops->accept(sock, newsock, flags) < 0)
++ {
++ sock_release(newsock);
++ return -1; /* should normally also set errno */
++ }
++
++ newaddr->sin_family = AF_INET;
++ newaddr->sin_port = newsock->sk->dport;
++ newaddr->sin_addr.s_addr = newsock->sk->daddr;
++
++ *addrlen = sizeof(newaddr);
++
++ return sock2fd(newsock);
++}
++
++
++static inline int shutdown(int sockfd, int how)
++{
++ struct socket *sock = fd2sock(sockfd);
++
++ if (sock == NULL)
++ return -1;
++
++ if (sock->ops->shutdown(sock, how) == 0)
++ return 0;
++ else
++ return -1; /* should normally also set errno */
++}
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/sys/stat.h linux-2.4.1-korbit/net/korbit/include/sys/stat.h
+--- linux-2.4.1/net/korbit/include/sys/stat.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/sys/stat.h Thu Feb 1 11:46:55 2001
+@@ -0,0 +1,3 @@
++#ifndef __KORBIT_SYS_STAT_H__
++#define __KORBIT_SYS_STAT_H__
++#endif
+diff -urN linux-2.4.1/net/korbit/include/sys/time.h linux-2.4.1-korbit/net/korbit/include/sys/time.h
+--- linux-2.4.1/net/korbit/include/sys/time.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/sys/time.h Thu Feb 1 11:46:55 2001
+@@ -0,0 +1,6 @@
++#ifndef __KORBIT_TIME_H__
++#define __KORBIT_TIME_H__
++
++#include <linux/time.h>
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/sys/types.h linux-2.4.1-korbit/net/korbit/include/sys/types.h
+--- linux-2.4.1/net/korbit/include/sys/types.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/sys/types.h Thu Feb 1 11:46:56 2001
+@@ -0,0 +1,4 @@
++#ifndef __KORBIT_SYS_TYPES_H__
++#define __KORBIT_SYS_TYPES_H__
++#include <linux/types.h>
++#endif
+diff -urN linux-2.4.1/net/korbit/include/sys/uio.h linux-2.4.1-korbit/net/korbit/include/sys/uio.h
+--- linux-2.4.1/net/korbit/include/sys/uio.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/sys/uio.h Thu Feb 1 11:46:56 2001
+@@ -0,0 +1,4 @@
++#ifndef __KORBIT_SYS_UIO_H__
++#define __KORBIT_SYS_UIO_H__
++#include <linux/uio.h>
++#endif
+diff -urN linux-2.4.1/net/korbit/include/sys/un.h linux-2.4.1-korbit/net/korbit/include/sys/un.h
+--- linux-2.4.1/net/korbit/include/sys/un.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/sys/un.h Thu Feb 1 11:46:56 2001
+@@ -0,0 +1,5 @@
++#ifndef __KORBIT_SYS_UN_H__
++#define __KORBIT_SYS_UN_H__
++#include <linux/socket.h>
++#include <linux/un.h>
++#endif
+diff -urN linux-2.4.1/net/korbit/include/sys/wait.h linux-2.4.1-korbit/net/korbit/include/sys/wait.h
+--- linux-2.4.1/net/korbit/include/sys/wait.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/sys/wait.h Thu Feb 1 11:46:56 2001
+@@ -0,0 +1,3 @@
++#ifndef __KORBIT_SYS_WAIT_H__
++#define __KORBIT_SYS_WAIT_H__
++#endif
+diff -urN linux-2.4.1/net/korbit/include/syslog.h linux-2.4.1-korbit/net/korbit/include/syslog.h
+--- linux-2.4.1/net/korbit/include/syslog.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/syslog.h Thu Feb 1 11:46:54 2001
+@@ -0,0 +1,7 @@
++#ifndef __KORBIT_SYSLOG_H__
++#define __KORBIT_SYSLOG_H__
++
++#define LOG_NOTICE 5 /* normal but significant condition */
++#define LOG_INFO 6 /* informational */
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/time.h linux-2.4.1-korbit/net/korbit/include/time.h
+--- linux-2.4.1/net/korbit/include/time.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/time.h Thu Feb 1 11:46:54 2001
+@@ -0,0 +1,4 @@
++#ifndef __KORBIT_TIME_H__
++#define __KORBIT_TIME_H__
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/unistd.h linux-2.4.1-korbit/net/korbit/include/unistd.h
+--- linux-2.4.1/net/korbit/include/unistd.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/unistd.h Thu Feb 1 11:46:54 2001
+@@ -0,0 +1,19 @@
++#ifndef __KORBIT_UNISTD_H__
++#define __KORBIT_UNISTD_H__
++
++#include <linux/types.h>
++#include <linux/utsname.h>
++#include <asm/string.h>
++#include <asm/semaphore.h>
++/* extern char *getcwd(char * buf, size_t size); */
++
++static inline int gethostname(char *name, size_t len) {
++ down_read(&uts_sem);
++ strncpy(name, system_utsname.nodename, len);
++ up_read(&uts_sem);
++printk("gethostname() = %s\n", name);
++ return 0;
++}
++
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/utime.h linux-2.4.1-korbit/net/korbit/include/utime.h
+--- linux-2.4.1/net/korbit/include/utime.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/utime.h Thu Feb 1 11:46:54 2001
+@@ -0,0 +1,4 @@
++#ifndef __KORBIT_UTIME_H__
++#define __KORBIT_UTIME_H__
++#include <linux/utime.h>
++#endif
+diff -urN linux-2.4.1/net/korbit/kglib/CVS/Entries linux-2.4.1-korbit/net/korbit/kglib/CVS/Entries
+--- linux-2.4.1/net/korbit/kglib/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/CVS/Entries Thu Feb 1 11:46:57 2001
+@@ -0,0 +1,15 @@
++/Makefile/1.4/Thu Feb 1 09:46:56 2001//
++/garray.c/1.3/Thu Feb 1 09:46:56 2001//
++/ghash.c/1.2/Thu Feb 1 09:46:56 2001//
++/glib.h/1.3/Thu Feb 1 09:46:56 2001//
++/glibconfig.h/1.2/Thu Feb 1 09:46:56 2001//
++/glist.c/1.1.1.1/Thu Feb 1 09:46:57 2001//
++/gmem.c/1.2/Thu Feb 1 09:46:57 2001//
++/gprimes.c/1.1.1.1/Thu Feb 1 09:46:57 2001//
++/gslist.c/1.1.1.1/Thu Feb 1 09:46:57 2001//
++/gstrfuncs.c/1.2/Thu Feb 1 09:46:57 2001//
++/gstring.c/1.1.1.1/Thu Feb 1 09:46:57 2001//
++/gtree.c/1.1.1.1/Thu Feb 1 09:46:57 2001//
++/gutils.c/1.2/Thu Feb 1 09:46:57 2001//
++/korbit_errno.c/1.1/Thu Feb 1 09:46:57 2001//
++D
+diff -urN linux-2.4.1/net/korbit/kglib/CVS/Repository linux-2.4.1-korbit/net/korbit/kglib/CVS/Repository
+--- linux-2.4.1/net/korbit/kglib/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/CVS/Repository Thu Feb 1 11:46:56 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/kglib
+diff -urN linux-2.4.1/net/korbit/kglib/CVS/Root linux-2.4.1-korbit/net/korbit/kglib/CVS/Root
+--- linux-2.4.1/net/korbit/kglib/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/CVS/Root Thu Feb 1 11:46:56 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/kglib/Makefile linux-2.4.1-korbit/net/korbit/kglib/Makefile
+--- linux-2.4.1/net/korbit/kglib/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/Makefile Thu Feb 1 11:46:56 2001
+@@ -0,0 +1,18 @@
++#
++# Makefile for KORBit/kglib
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++O_TARGET := kglib.o
++
++#obj-m := $(O_TARGET)
++obj-y := garray.o glist.o gprimes.o gstrfuncs.o gtree.o \
++ ghash.o gmem.o gslist.o gstring.o gutils.o korbit_errno.o
++
++EXTRA_CFLAGS = -D__KORBIT__ -DHAVE_CONFIG_H -DHAVE_UNISTD_H -I. -I.. -I../include -nostdinc
++include $(TOPDIR)/Rules.make
++
+diff -urN linux-2.4.1/net/korbit/kglib/garray.c linux-2.4.1-korbit/net/korbit/kglib/garray.c
+--- linux-2.4.1/net/korbit/kglib/garray.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/garray.c Thu Feb 1 11:46:56 2001
+@@ -0,0 +1,431 @@
++/* GLIB - Library of useful routines for C programming
++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
++ *
++ * 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.
++ */
++
++/*
++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS
++ * file for a list of people on the GLib Team. See the ChangeLog
++ * files for a list of changes. These files are distributed with
++ * GLib at ftp://ftp.gtk.org/pub/gtk/.
++ */
++
++#include <string.h>
++#include "glib.h"
++
++
++#define MIN_ARRAY_SIZE 16
++
++
++typedef struct _GRealArray GRealArray;
++
++struct _GRealArray
++{
++ guint8 *data;
++ guint len;
++ guint alloc;
++ guint elt_size;
++ guint zero_terminated : 1;
++ guint clear : 1;
++};
++
++
++static gint g_nearest_pow (gint num);
++static void g_array_maybe_expand (GRealArray *array,
++ gint len);
++
++static GMemChunk *array_mem_chunk = NULL;
++G_LOCK_DEFINE_STATIC (array_mem_chunk);
++
++GArray*
++g_array_new (gboolean zero_terminated,
++ gboolean clear,
++ guint elt_size)
++{
++ GRealArray *array;
++
++ G_LOCK (array_mem_chunk);
++ if (!array_mem_chunk)
++ array_mem_chunk = g_mem_chunk_new ("array mem chunk",
++ sizeof (GRealArray),
++ 1024, G_ALLOC_AND_FREE);
++
++ array = g_chunk_new (GRealArray, array_mem_chunk);
++ G_UNLOCK (array_mem_chunk);
++
++ array->data = NULL;
++ array->len = 0;
++ array->alloc = 0;
++ array->zero_terminated = (zero_terminated ? 1 : 0);
++ array->clear = (clear ? 1 : 0);
++ array->elt_size = elt_size;
++
++ return (GArray*) array;
++}
++
++void
++g_array_free (GArray *array,
++ gboolean free_segment)
++{
++ if (free_segment)
++ g_free (array->data);
++
++ G_LOCK (array_mem_chunk);
++ g_mem_chunk_free (array_mem_chunk, array);
++ G_UNLOCK (array_mem_chunk);
++}
++
++GArray*
++g_array_append_vals (GArray *farray,
++ gconstpointer data,
++ guint len)
++{
++ GRealArray *array = (GRealArray*) farray;
++
++ g_array_maybe_expand (array, len);
++
++ memcpy (array->data + array->elt_size * array->len, data, array->elt_size * len);
++
++ array->len += len;
++
++ return farray;
++}
++
++GArray*
++g_array_prepend_vals (GArray *farray,
++ gconstpointer data,
++ guint len)
++{
++ GRealArray *array = (GRealArray*) farray;
++
++ g_array_maybe_expand (array, len);
++
++ g_memmove (array->data + array->elt_size * len, array->data, array->elt_size * array->len);
++
++ memcpy (array->data, data, len * array->elt_size);
++
++ array->len += len;
++
++ return farray;
++}
++
++GArray*
++g_array_insert_vals (GArray *farray,
++ guint index,
++ gconstpointer data,
++ guint len)
++{
++ GRealArray *array = (GRealArray*) farray;
++
++ g_array_maybe_expand (array, len);
++
++ g_memmove (array->data + array->elt_size * (len + index),
++ array->data + array->elt_size * index,
++ array->elt_size * (array->len - index));
++
++ memcpy (array->data + array->elt_size * index, data, len * array->elt_size);
++
++ array->len += len;
++
++ return farray;
++}
++
++GArray*
++g_array_set_size (GArray *farray,
++ guint length)
++{
++ GRealArray *array = (GRealArray*) farray;
++
++ if (array->len < length)
++ g_array_maybe_expand (array, length - array->len);
++
++ array->len = length;
++
++ return farray;
++}
++
++GArray*
++g_array_remove_index (GArray* farray,
++ guint index)
++{
++ GRealArray* array = (GRealArray*) farray;
++
++ g_return_val_if_fail (array, NULL);
++
++ g_return_val_if_fail (index < array->len, NULL);
++
++ if (index != array->len - 1)
++ g_memmove (array->data + array->elt_size * index,
++ array->data + array->elt_size * (index + 1),
++ array->elt_size * (array->len - index - 1));
++
++ if (array->zero_terminated)
++ memset (array->data + array->elt_size * (array->len - 1), 0,
++ array->elt_size);
++
++ array->len -= 1;
++
++ return farray;
++}
++
++GArray*
++g_array_remove_index_fast (GArray* farray,
++ guint index)
++{
++ GRealArray* array = (GRealArray*) farray;
++
++ g_return_val_if_fail (array, NULL);
++
++ g_return_val_if_fail (index < array->len, NULL);
++
++ if (index != array->len - 1)
++ g_memmove (array->data + array->elt_size * index,
++ array->data + array->elt_size * (array->len - 1),
++ array->elt_size);
++
++ if (array->zero_terminated)
++ memset (array->data + array->elt_size * (array->len - 1), 0,
++ array->elt_size);
++
++ array->len -= 1;
++
++ return farray;
++}
++
++static gint
++g_nearest_pow (gint num)
++{
++ gint n = 1;
++
++ while (n < num)
++ n <<= 1;
++
++ return n;
++}
++
++static void
++g_array_maybe_expand (GRealArray *array,
++ gint len)
++{
++ guint want_alloc = (array->len + len + array->zero_terminated) * array->elt_size;
++
++ if (want_alloc > array->alloc)
++ {
++ guint old_alloc = array->alloc;
++
++ array->alloc = g_nearest_pow (want_alloc);
++ array->alloc = MAX (array->alloc, MIN_ARRAY_SIZE);
++
++ array->data = g_realloc (array->data, array->alloc);
++
++ if (array->clear || array->zero_terminated)
++ memset (array->data + old_alloc, 0, array->alloc - old_alloc);
++ }
++}
++
++/* Pointer Array
++ */
++
++typedef struct _GRealPtrArray GRealPtrArray;
++
++struct _GRealPtrArray
++{
++ gpointer *pdata;
++ guint len;
++ guint alloc;
++};
++
++static void g_ptr_array_maybe_expand (GRealPtrArray *array,
++ gint len);
++
++static GMemChunk *ptr_array_mem_chunk = NULL;
++G_LOCK_DEFINE_STATIC (ptr_array_mem_chunk);
++
++
++GPtrArray*
++g_ptr_array_new (void)
++{
++ GRealPtrArray *array;
++
++ G_LOCK (ptr_array_mem_chunk);
++ if (!ptr_array_mem_chunk)
++ ptr_array_mem_chunk = g_mem_chunk_new ("array mem chunk",
++ sizeof (GRealPtrArray),
++ 1024, G_ALLOC_AND_FREE);
++
++ array = g_chunk_new (GRealPtrArray, ptr_array_mem_chunk);
++ G_UNLOCK (ptr_array_mem_chunk);
++
++ array->pdata = NULL;
++ array->len = 0;
++ array->alloc = 0;
++
++ return (GPtrArray*) array;
++}
++
++void
++g_ptr_array_free (GPtrArray *array,
++ gboolean free_segment)
++{
++ g_return_if_fail (array);
++
++ if (free_segment)
++ g_free (array->pdata);
++
++ G_LOCK (ptr_array_mem_chunk);
++ g_mem_chunk_free (ptr_array_mem_chunk, array);
++ G_UNLOCK (ptr_array_mem_chunk);
++}
++
++static void
++g_ptr_array_maybe_expand (GRealPtrArray *array,
++ gint len)
++{
++ guint old_alloc;
++
++ if ((array->len + len) > array->alloc)
++ {
++ old_alloc = array->alloc;
++
++ array->alloc = g_nearest_pow (array->len + len);
++ array->alloc = MAX (array->alloc, MIN_ARRAY_SIZE);
++ if (array->pdata)
++ array->pdata = g_realloc (array->pdata, sizeof(gpointer) * array->alloc);
++ else
++ array->pdata = g_new0 (gpointer, array->alloc);
++
++ memset (array->pdata + old_alloc, 0,
++ sizeof (gpointer) * (array->alloc - old_alloc));
++ }
++}
++
++void
++g_ptr_array_set_size (GPtrArray *farray,
++ gint length)
++{
++ GRealPtrArray* array = (GRealPtrArray*) farray;
++
++ g_return_if_fail (array);
++
++ if (length > array->len)
++ g_ptr_array_maybe_expand (array, (length - array->len));
++
++ array->len = length;
++}
++
++gpointer
++g_ptr_array_remove_index (GPtrArray* farray,
++ guint index)
++{
++ GRealPtrArray* array = (GRealPtrArray*) farray;
++ gpointer result;
++
++ g_return_val_if_fail (array, NULL);
++
++ g_return_val_if_fail (index < array->len, NULL);
++
++ result = array->pdata[index];
++
++ if (index != array->len - 1)
++ g_memmove (array->pdata + index, array->pdata + index + 1,
++ sizeof (gpointer) * (array->len - index - 1));
++
++ array->pdata[array->len - 1] = NULL;
++
++ array->len -= 1;
++
++ return result;
++}
++
++gpointer
++g_ptr_array_remove_index_fast (GPtrArray* farray,
++ guint index)
++{
++ GRealPtrArray* array = (GRealPtrArray*) farray;
++ gpointer result;
++
++ g_return_val_if_fail (array, NULL);
++
++ g_return_val_if_fail (index < array->len, NULL);
++
++ result = array->pdata[index];
++
++ if (index != array->len - 1)
++ array->pdata[index] = array->pdata[array->len - 1];
++
++ array->pdata[array->len - 1] = NULL;
++
++ array->len -= 1;
++
++ return result;
++}
++
++gboolean
++g_ptr_array_remove (GPtrArray* farray,
++ gpointer data)
++{
++ GRealPtrArray* array = (GRealPtrArray*) farray;
++ int i;
++
++ g_return_val_if_fail (array, FALSE);
++
++ for (i = 0; i < array->len; i += 1)
++ {
++ if (array->pdata[i] == data)
++ {
++ g_ptr_array_remove_index (farray, i);
++ return TRUE;
++ }
++ }
++
++ return FALSE;
++}
++
++gboolean
++g_ptr_array_remove_fast (GPtrArray* farray,
++ gpointer data)
++{
++ GRealPtrArray* array = (GRealPtrArray*) farray;
++ int i;
++
++ g_return_val_if_fail (array, FALSE);
++
++ for (i = 0; i < array->len; i += 1)
++ {
++ if (array->pdata[i] == data)
++ {
++ g_ptr_array_remove_index_fast (farray, i);
++ return TRUE;
++ }
++ }
++
++ return FALSE;
++}
++
++void
++g_ptr_array_add (GPtrArray* farray,
++ gpointer data)
++{
++ GRealPtrArray* array = (GRealPtrArray*) farray;
++
++ g_return_if_fail (array);
++
++ g_ptr_array_maybe_expand (array, 1);
++
++ array->pdata[array->len++] = data;
++}
++
+diff -urN linux-2.4.1/net/korbit/kglib/ghash.c linux-2.4.1-korbit/net/korbit/kglib/ghash.c
+--- linux-2.4.1/net/korbit/kglib/ghash.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/ghash.c Thu Feb 1 11:46:56 2001
+@@ -0,0 +1,404 @@
++/* GLIB - Library of useful routines for C programming
++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
++ *
++ * 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.
++ */
++
++/*
++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS
++ * file for a list of people on the GLib Team. See the ChangeLog
++ * files for a list of changes. These files are distributed with
++ * GLib at ftp://ftp.gtk.org/pub/gtk/.
++ */
++
++#include "glib.h"
++
++
++#define HASH_TABLE_MIN_SIZE 11
++#define HASH_TABLE_MAX_SIZE 13845163
++
++
++typedef struct _GHashNode GHashNode;
++
++struct _GHashNode
++{
++ gpointer key;
++ gpointer value;
++ GHashNode *next;
++};
++
++struct _GHashTable
++{
++ gint size;
++ gint nnodes;
++ guint frozen;
++ GHashNode **nodes;
++ GHashFunc hash_func;
++ GCompareFunc key_compare_func;
++};
++
++
++static void g_hash_table_resize (GHashTable *hash_table);
++static GHashNode** g_hash_table_lookup_node (GHashTable *hash_table,
++ gconstpointer key);
++static GHashNode* g_hash_node_new (gpointer key,
++ gpointer value);
++static void g_hash_node_destroy (GHashNode *hash_node);
++static void g_hash_nodes_destroy (GHashNode *hash_node);
++
++
++G_LOCK_DEFINE_STATIC (g_hash_global);
++
++static GMemChunk *node_mem_chunk = NULL;
++static GHashNode *node_free_list = NULL;
++
++
++GHashTable*
++g_hash_table_new (GHashFunc hash_func,
++ GCompareFunc key_compare_func)
++{
++ GHashTable *hash_table;
++ guint i;
++
++ hash_table = g_new (GHashTable, 1);
++ hash_table->size = HASH_TABLE_MIN_SIZE;
++ hash_table->nnodes = 0;
++ hash_table->frozen = FALSE;
++ hash_table->hash_func = hash_func ? hash_func : g_direct_hash;
++ hash_table->key_compare_func = key_compare_func;
++ hash_table->nodes = g_new (GHashNode*, hash_table->size);
++
++ for (i = 0; i < hash_table->size; i++)
++ hash_table->nodes[i] = NULL;
++
++ return hash_table;
++}
++
++void
++g_hash_table_destroy (GHashTable *hash_table)
++{
++ guint i;
++
++ g_return_if_fail (hash_table != NULL);
++
++ for (i = 0; i < hash_table->size; i++)
++ g_hash_nodes_destroy (hash_table->nodes[i]);
++
++ g_free (hash_table->nodes);
++ g_free (hash_table);
++}
++
++static inline GHashNode**
++g_hash_table_lookup_node (GHashTable *hash_table,
++ gconstpointer key)
++{
++ GHashNode **node;
++
++ node = &hash_table->nodes
++ [(* hash_table->hash_func) (key) % hash_table->size];
++
++ /* Hash table lookup needs to be fast.
++ * We therefore remove the extra conditional of testing
++ * whether to call the key_compare_func or not from
++ * the inner loop.
++ */
++ if (hash_table->key_compare_func)
++ while (*node && !(*hash_table->key_compare_func) ((*node)->key, key))
++ node = &(*node)->next;
++ else
++ while (*node && (*node)->key != key)
++ node = &(*node)->next;
++
++ return node;
++}
++
++gpointer
++g_hash_table_lookup (GHashTable *hash_table,
++ gconstpointer key)
++{
++ GHashNode *node;
++
++ g_return_val_if_fail (hash_table != NULL, NULL);
++
++ node = *g_hash_table_lookup_node (hash_table, key);
++
++ return node ? node->value : NULL;
++}
++
++void
++g_hash_table_insert (GHashTable *hash_table,
++ gpointer key,
++ gpointer value)
++{
++ GHashNode **node;
++
++ g_return_if_fail (hash_table != NULL);
++
++ node = g_hash_table_lookup_node (hash_table, key);
++
++ if (*node)
++ {
++ /* do not reset node->key in this place, keeping
++ * the old key might be intended.
++ * a g_hash_table_remove/g_hash_table_insert pair
++ * can be used otherwise.
++ *
++ * node->key = key; */
++ (*node)->value = value;
++ }
++ else
++ {
++ *node = g_hash_node_new (key, value);
++ hash_table->nnodes++;
++ if (!hash_table->frozen)
++ g_hash_table_resize (hash_table);
++ }
++}
++
++void
++g_hash_table_remove (GHashTable *hash_table,
++ gconstpointer key)
++{
++ GHashNode **node, *dest;
++
++ g_return_if_fail (hash_table != NULL);
++
++ node = g_hash_table_lookup_node (hash_table, key);
++
++ if (*node)
++ {
++ dest = *node;
++ (*node) = dest->next;
++ g_hash_node_destroy (dest);
++ hash_table->nnodes--;
++
++ if (!hash_table->frozen)
++ g_hash_table_resize (hash_table);
++ }
++}
++
++gboolean
++g_hash_table_lookup_extended (GHashTable *hash_table,
++ gconstpointer lookup_key,
++ gpointer *orig_key,
++ gpointer *value)
++{
++ GHashNode *node;
++
++ g_return_val_if_fail (hash_table != NULL, FALSE);
++
++ node = *g_hash_table_lookup_node (hash_table, lookup_key);
++
++ if (node)
++ {
++ if (orig_key)
++ *orig_key = node->key;
++ if (value)
++ *value = node->value;
++ return TRUE;
++ }
++ else
++ return FALSE;
++}
++
++void
++g_hash_table_freeze (GHashTable *hash_table)
++{
++ g_return_if_fail (hash_table != NULL);
++
++ hash_table->frozen++;
++}
++
++void
++g_hash_table_thaw (GHashTable *hash_table)
++{
++ g_return_if_fail (hash_table != NULL);
++
++ if (hash_table->frozen)
++ if (!(--hash_table->frozen))
++ g_hash_table_resize (hash_table);
++}
++
++guint
++g_hash_table_foreach_remove (GHashTable *hash_table,
++ GHRFunc func,
++ gpointer user_data)
++{
++ GHashNode *node, *prev;
++ guint i;
++ guint deleted = 0;
++
++ g_return_val_if_fail (hash_table != NULL, 0);
++ g_return_val_if_fail (func != NULL, 0);
++
++ for (i = 0; i < hash_table->size; i++)
++ {
++ restart:
++
++ prev = NULL;
++
++ for (node = hash_table->nodes[i]; node; prev = node, node = node->next)
++ {
++ if ((* func) (node->key, node->value, user_data))
++ {
++ deleted += 1;
++
++ hash_table->nnodes -= 1;
++
++ if (prev)
++ {
++ prev->next = node->next;
++ g_hash_node_destroy (node);
++ node = prev;
++ }
++ else
++ {
++ hash_table->nodes[i] = node->next;
++ g_hash_node_destroy (node);
++ goto restart;
++ }
++ }
++ }
++ }
++
++ if (!hash_table->frozen)
++ g_hash_table_resize (hash_table);
++
++ return deleted;
++}
++
++void
++g_hash_table_foreach (GHashTable *hash_table,
++ GHFunc func,
++ gpointer user_data)
++{
++ GHashNode *node;
++ gint i;
++
++ g_return_if_fail (hash_table != NULL);
++ g_return_if_fail (func != NULL);
++
++ for (i = 0; i < hash_table->size; i++)
++ for (node = hash_table->nodes[i]; node; node = node->next)
++ (* func) (node->key, node->value, user_data);
++}
++
++/* Returns the number of elements contained in the hash table. */
++guint
++g_hash_table_size (GHashTable *hash_table)
++{
++ g_return_val_if_fail (hash_table != NULL, 0);
++
++ return hash_table->nnodes;
++}
++
++static void
++g_hash_table_resize (GHashTable *hash_table)
++{
++ GHashNode **new_nodes;
++ GHashNode *node;
++ GHashNode *next;
++#ifdef __KORBIT__
++ guint nodes_per_list;
++#else
++ gfloat nodes_per_list;
++#endif
++ guint hash_val;
++ gint new_size;
++ gint i;
++
++ nodes_per_list = (hash_table->nnodes * 10) / hash_table->size;
++
++ if ((nodes_per_list > 3 || hash_table->size <= HASH_TABLE_MIN_SIZE) &&
++ (nodes_per_list < 30 || hash_table->size >= HASH_TABLE_MAX_SIZE))
++ return;
++
++ new_size = CLAMP(g_spaced_primes_closest (hash_table->nnodes),
++ HASH_TABLE_MIN_SIZE,
++ HASH_TABLE_MAX_SIZE);
++ new_nodes = g_new0 (GHashNode*, new_size);
++
++ for (i = 0; i < hash_table->size; i++)
++ for (node = hash_table->nodes[i]; node; node = next)
++ {
++ next = node->next;
++
++ hash_val = (* hash_table->hash_func) (node->key) % new_size;
++
++ node->next = new_nodes[hash_val];
++ new_nodes[hash_val] = node;
++ }
++
++ g_free (hash_table->nodes);
++ hash_table->nodes = new_nodes;
++ hash_table->size = new_size;
++}
++
++static GHashNode*
++g_hash_node_new (gpointer key,
++ gpointer value)
++{
++ GHashNode *hash_node;
++
++ G_LOCK (g_hash_global);
++ if (node_free_list)
++ {
++ hash_node = node_free_list;
++ node_free_list = node_free_list->next;
++ }
++ else
++ {
++ if (!node_mem_chunk)
++ node_mem_chunk = g_mem_chunk_new ("hash node mem chunk",
++ sizeof (GHashNode),
++ 1024, G_ALLOC_ONLY);
++
++ hash_node = g_chunk_new (GHashNode, node_mem_chunk);
++ }
++ G_UNLOCK (g_hash_global);
++
++ hash_node->key = key;
++ hash_node->value = value;
++ hash_node->next = NULL;
++
++ return hash_node;
++}
++
++static void
++g_hash_node_destroy (GHashNode *hash_node)
++{
++ G_LOCK (g_hash_global);
++ hash_node->next = node_free_list;
++ node_free_list = hash_node;
++ G_UNLOCK (g_hash_global);
++}
++
++static void
++g_hash_nodes_destroy (GHashNode *hash_node)
++{
++ if (hash_node)
++ {
++ GHashNode *node = hash_node;
++
++ while (node->next)
++ node = node->next;
++
++ G_LOCK (g_hash_global);
++ node->next = node_free_list;
++ node_free_list = hash_node;
++ G_UNLOCK (g_hash_global);
++ }
++}
+diff -urN linux-2.4.1/net/korbit/kglib/glib.h linux-2.4.1-korbit/net/korbit/kglib/glib.h
+--- linux-2.4.1/net/korbit/kglib/glib.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/glib.h Thu Feb 1 11:46:56 2001
+@@ -0,0 +1,1671 @@
++/* GLIB - Library of useful routines for C programming
++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
++ *
++ * 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.
++ */
++
++#ifndef __G_LIB_H__
++#define __G_LIB_H__
++
++#ifdef __KORBIT__
++#define G_DISABLE_ASSERT 1
++#include <stdio.h>
++#endif
++
++#include "config.h"
++
++/* system specific config file glibconfig.h provides definitions for
++ * the extrema of many of the standard types. These are:
++ *
++ * G_MINSHORT, G_MAXSHORT
++ * G_MININT, G_MAXINT
++ * G_MINLONG, G_MAXLONG
++ * G_MINFLOAT, G_MAXFLOAT
++ * G_MINDOUBLE, G_MAXDOUBLE
++ *
++ * It also provides the following typedefs:
++ *
++ * gint8, guint8
++ * gint16, guint16
++ * gint32, guint32
++ * gint64, guint64
++ *
++ * It defines the G_BYTE_ORDER symbol to one of G_*_ENDIAN (see later in
++ * this file).
++ *
++ * And it provides a way to store and retrieve a `gint' in/from a `gpointer'.
++ * This is useful to pass an integer instead of a pointer to a callback.
++ *
++ * GINT_TO_POINTER(i), GUINT_TO_POINTER(i)
++ * GPOINTER_TO_INT(p), GPOINTER_TO_UINT(p)
++ *
++ * Finally, it provide the following wrappers to STDC functions:
++ *
++ * g_ATEXIT
++ * To register hooks which are executed on exit().
++ * Usually a wrapper for STDC atexit.
++ *
++ * void *g_memmove(void *dest, const void *src, guint count);
++ * A wrapper for STDC memmove, or an implementation, if memmove doesn't
++ * exist. The prototype looks like the above, give or take a const,
++ * or size_t.
++ */
++#include <glibconfig.h>
++
++/* include varargs functions for assertment macros
++ */
++#include <stdarg.h>
++
++#define G_DIR_SEPARATOR '/'
++#define G_DIR_SEPARATOR_S "/"
++#define G_SEARCHPATH_SEPARATOR ':'
++#define G_SEARCHPATH_SEPARATOR_S ":"
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++
++/* Provide definitions for some commonly used macros.
++ * Some of them are only provided if they haven't already
++ * been defined. It is assumed that if they are already
++ * defined then the current definition is correct.
++ */
++#ifndef NULL
++#define NULL ((void*) 0)
++#endif
++
++#ifndef FALSE
++#define FALSE (0)
++#endif
++
++#ifndef TRUE
++#define TRUE (!FALSE)
++#endif
++
++#undef MAX
++#define MAX(a, b) (((a) > (b)) ? (a) : (b))
++
++#undef MIN
++#define MIN(a, b) (((a) < (b)) ? (a) : (b))
++
++#undef ABS
++#define ABS(a) (((a) < 0) ? -(a) : (a))
++
++#undef CLAMP
++#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
++
++
++/* Define G_VA_COPY() to do the right thing for copying va_list variables.
++ * glibconfig.h may have already defined G_VA_COPY as va_copy or __va_copy.
++ */
++#if !defined (G_VA_COPY)
++# if defined (__GNUC__) && defined (__PPC__) && (defined (_CALL_SYSV) || defined (_WIN32))
++# define G_VA_COPY(ap1, ap2) (*(ap1) = *(ap2))
++# elif defined (G_VA_COPY_AS_ARRAY)
++# define G_VA_COPY(ap1, ap2) g_memmove ((ap1), (ap2), sizeof (va_list))
++# else /* va_list is a pointer */
++# define G_VA_COPY(ap1, ap2) ((ap1) = (ap2))
++# endif /* va_list is a pointer */
++#endif /* !G_VA_COPY */
++
++
++/* Provide convenience macros for handling structure
++ * fields through their offsets.
++ */
++#define G_STRUCT_OFFSET(struct_type, member) \
++ ((gulong) ((gchar*) &((struct_type*) 0)->member))
++#define G_STRUCT_MEMBER_P(struct_p, struct_offset) \
++ ((gpointer) ((gchar*) (struct_p) + (gulong) (struct_offset)))
++#define G_STRUCT_MEMBER(member_type, struct_p, struct_offset) \
++ (*(member_type*) G_STRUCT_MEMBER_P ((struct_p), (struct_offset)))
++
++
++/* inlining hassle. for compilers that don't allow the `inline' keyword,
++ * mostly because of strict ANSI C compliance or dumbness, we try to fall
++ * back to either `__inline__' or `__inline'.
++ * we define G_CAN_INLINE, if the compiler seems to be actually
++ * *capable* to do function inlining, in which case inline function bodys
++ * do make sense. we also define G_INLINE_FUNC to properly export the
++ * function prototypes if no inlining can be performed.
++ * we special case most of the stuff, so inline functions can have a normal
++ * implementation by defining G_INLINE_FUNC to extern and G_CAN_INLINE to 1.
++ */
++#ifndef G_INLINE_FUNC
++# define G_CAN_INLINE 1
++#endif
++#ifdef G_HAVE_INLINE
++# if defined (__GNUC__) && defined (__STRICT_ANSI__)
++# undef inline
++# define inline __inline__
++# endif
++#else /* !G_HAVE_INLINE */
++# undef inline
++# if defined (G_HAVE___INLINE__)
++# define inline __inline__
++# else /* !inline && !__inline__ */
++# if defined (G_HAVE___INLINE)
++# define inline __inline
++# else /* !inline && !__inline__ && !__inline */
++# define inline /* don't inline, then */
++# ifndef G_INLINE_FUNC
++# undef G_CAN_INLINE
++# endif
++# endif
++# endif
++#endif
++#ifndef G_INLINE_FUNC
++# ifdef __GNUC__
++# ifdef __OPTIMIZE__
++# define G_INLINE_FUNC extern inline
++# else
++# undef G_CAN_INLINE
++# define G_INLINE_FUNC extern
++# endif
++# else /* !__GNUC__ */
++# ifdef G_CAN_INLINE
++# define G_INLINE_FUNC static inline
++# else
++# define G_INLINE_FUNC extern
++# endif
++# endif /* !__GNUC__ */
++#endif /* !G_INLINE_FUNC */
++
++
++/* Provide simple macro statement wrappers (adapted from Perl):
++ * G_STMT_START { statements; } G_STMT_END;
++ * can be used as a single statement, as in
++ * if (x) G_STMT_START { ... } G_STMT_END; else ...
++ *
++ * For gcc we will wrap the statements within `({' and `})' braces.
++ * For SunOS they will be wrapped within `if (1)' and `else (void) 0',
++ * and otherwise within `do' and `while (0)'.
++ */
++#if !(defined (G_STMT_START) && defined (G_STMT_END))
++# if defined (__GNUC__) && !defined (__STRICT_ANSI__) && !defined (__cplusplus)
++# define G_STMT_START (void)(
++# define G_STMT_END )
++# else
++# if (defined (sun) || defined (__sun__))
++# define G_STMT_START if (1)
++# define G_STMT_END else (void)0
++# else
++# define G_STMT_START do
++# define G_STMT_END while (0)
++# endif
++# endif
++#endif
++
++
++/* Provide macros to feature the GCC function attribute.
++ */
++#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
++#define G_GNUC_PRINTF( format_idx, arg_idx ) \
++ __attribute__((format (printf, format_idx, arg_idx)))
++#define G_GNUC_SCANF( format_idx, arg_idx ) \
++ __attribute__((format (scanf, format_idx, arg_idx)))
++#define G_GNUC_FORMAT( arg_idx ) \
++ __attribute__((format_arg (arg_idx)))
++#define G_GNUC_NORETURN \
++ __attribute__((noreturn))
++#define G_GNUC_CONST \
++ __attribute__((const))
++#define G_GNUC_UNUSED \
++ __attribute__((unused))
++#else /* !__GNUC__ */
++#define G_GNUC_PRINTF( format_idx, arg_idx )
++#define G_GNUC_SCANF( format_idx, arg_idx )
++#define G_GNUC_FORMAT( arg_idx )
++#define G_GNUC_NORETURN
++#define G_GNUC_CONST
++#define G_GNUC_UNUSED
++#endif /* !__GNUC__ */
++
++
++/* Wrap the gcc __PRETTY_FUNCTION__ and __FUNCTION__ variables with
++ * macros, so we can refer to them as strings unconditionally.
++ */
++#ifdef __GNUC__
++#define G_GNUC_FUNCTION __FUNCTION__
++#define G_GNUC_PRETTY_FUNCTION __PRETTY_FUNCTION__
++#else /* !__GNUC__ */
++#define G_GNUC_FUNCTION ""
++#define G_GNUC_PRETTY_FUNCTION ""
++#endif /* !__GNUC__ */
++
++/* we try to provide a usefull equivalent for ATEXIT if it is
++ * not defined, but use is actually abandoned. people should
++ * use g_atexit() instead.
++ */
++#ifndef ATEXIT
++# define ATEXIT(proc) g_ATEXIT(proc)
++#else
++# define G_NATIVE_ATEXIT
++#endif /* ATEXIT */
++
++/* Hacker macro to place breakpoints for elected machines.
++ * Actual use is strongly deprecated of course ;)
++ */
++#if defined (__i386__) && defined (__GNUC__) && __GNUC__ >= 2
++#define G_BREAKPOINT() G_STMT_START{ __asm__ __volatile__ ("int $03"); }G_STMT_END
++#elif defined (__alpha__) && defined (__GNUC__) && __GNUC__ >= 2
++#define G_BREAKPOINT() G_STMT_START{ __asm__ __volatile__ ("bpt"); }G_STMT_END
++#else /* !__i386__ && !__alpha__ */
++#define G_BREAKPOINT()
++#endif /* __i386__ */
++
++
++/* Provide macros for easily allocating memory. The macros
++ * will cast the allocated memory to the specified type
++ * in order to avoid compiler warnings. (Makes the code neater).
++ */
++
++#ifdef __DMALLOC_H__
++# define g_new(type, count) (ALLOC (type, count))
++# define g_new0(type, count) (CALLOC (type, count))
++# define g_renew(type, mem, count) (REALLOC (mem, type, count))
++#else /* __DMALLOC_H__ */
++# define g_new(type, count) \
++ ((type *) g_malloc ((unsigned) sizeof (type) * (count)))
++# define g_new0(type, count) \
++ ((type *) g_malloc0 ((unsigned) sizeof (type) * (count)))
++# define g_renew(type, mem, count) \
++ ((type *) g_realloc (mem, (unsigned) sizeof (type) * (count)))
++#endif /* __DMALLOC_H__ */
++
++#define g_mem_chunk_create(type, pre_alloc, alloc_type) ( \
++ g_mem_chunk_new (#type " mem chunks (" #pre_alloc ")", \
++ sizeof (type), \
++ sizeof (type) * (pre_alloc), \
++ (alloc_type)) \
++)
++#define g_chunk_new(type, chunk) ( \
++ (type *) g_mem_chunk_alloc (chunk) \
++)
++#define g_chunk_new0(type, chunk) ( \
++ (type *) g_mem_chunk_alloc0 (chunk) \
++)
++#define g_chunk_free(mem, mem_chunk) G_STMT_START { \
++ g_mem_chunk_free ((mem_chunk), (mem)); \
++} G_STMT_END
++
++
++#define g_string(x) #x
++
++
++/* Provide macros for error handling. The "assert" macros will
++ * exit on failure. The "return" macros will exit the current
++ * function. Two different definitions are given for the macros
++ * if G_DISABLE_ASSERT is not defined, in order to support gcc's
++ * __PRETTY_FUNCTION__ capability.
++ */
++
++#ifdef G_DISABLE_ASSERT
++
++#define g_assert(expr)
++#define g_assert_not_reached()
++
++#else /* !G_DISABLE_ASSERT */
++
++#ifdef __GNUC__
++
++#define g_assert(expr) G_STMT_START{ \
++ if (!(expr)) \
++ g_log (G_LOG_DOMAIN, \
++ G_LOG_LEVEL_ERROR, \
++ "file %s: line %d (%s): assertion failed: (%s)", \
++ __FILE__, \
++ __LINE__, \
++ __PRETTY_FUNCTION__, \
++ #expr); }G_STMT_END
++
++#define g_assert_not_reached() G_STMT_START{ \
++ g_log (G_LOG_DOMAIN, \
++ G_LOG_LEVEL_ERROR, \
++ "file %s: line %d (%s): should not be reached", \
++ __FILE__, \
++ __LINE__, \
++ __PRETTY_FUNCTION__); }G_STMT_END
++
++#else /* !__GNUC__ */
++
++#define g_assert(expr) G_STMT_START{ \
++ if (!(expr)) \
++ g_log (G_LOG_DOMAIN, \
++ G_LOG_LEVEL_ERROR, \
++ "file %s: line %d: assertion failed: (%s)", \
++ __FILE__, \
++ __LINE__, \
++ #expr); }G_STMT_END
++
++#define g_assert_not_reached() G_STMT_START{ \
++ g_log (G_LOG_DOMAIN, \
++ G_LOG_LEVEL_ERROR, \
++ "file %s: line %d: should not be reached", \
++ __FILE__, \
++ __LINE__); }G_STMT_END
++
++#endif /* __GNUC__ */
++
++#endif /* !G_DISABLE_ASSERT */
++
++
++#ifdef __KORBIT__
++
++#define g_return_if_fail(expr) G_STMT_START{ \
++ if (!(expr)) \
++ { \
++ return; \
++ }; }G_STMT_END
++
++#define g_return_val_if_fail(expr,val) G_STMT_START{ \
++ if (!(expr)) \
++ { \
++ return val; \
++ }; }G_STMT_END
++
++#else /* !__KORBIT__ */
++
++#ifdef G_DISABLE_CHECKS
++
++#define g_return_if_fail(expr)
++#define g_return_val_if_fail(expr,val)
++
++#else /* !G_DISABLE_CHECKS */
++
++#ifdef __GNUC__
++
++#define g_return_if_fail(expr) G_STMT_START{ \
++ if (!(expr)) \
++ { \
++ g_log (G_LOG_DOMAIN, \
++ G_LOG_LEVEL_CRITICAL, \
++ "file %s: line %d (%s): assertion `%s' failed.", \
++ __FILE__, \
++ __LINE__, \
++ __PRETTY_FUNCTION__, \
++ #expr); \
++ return; \
++ }; }G_STMT_END
++
++#define g_return_val_if_fail(expr,val) G_STMT_START{ \
++ if (!(expr)) \
++ { \
++ g_log (G_LOG_DOMAIN, \
++ G_LOG_LEVEL_CRITICAL, \
++ "file %s: line %d (%s): assertion `%s' failed.", \
++ __FILE__, \
++ __LINE__, \
++ __PRETTY_FUNCTION__, \
++ #expr); \
++ return val; \
++ }; }G_STMT_END
++
++#else /* !__GNUC__ */
++
++#define g_return_if_fail(expr) G_STMT_START{ \
++ if (!(expr)) \
++ { \
++ g_log (G_LOG_DOMAIN, \
++ G_LOG_LEVEL_CRITICAL, \
++ "file %s: line %d: assertion `%s' failed.", \
++ __FILE__, \
++ __LINE__, \
++ #expr); \
++ return; \
++ }; }G_STMT_END
++
++#define g_return_val_if_fail(expr, val) G_STMT_START{ \
++ if (!(expr)) \
++ { \
++ g_log (G_LOG_DOMAIN, \
++ G_LOG_LEVEL_CRITICAL, \
++ "file %s: line %d: assertion `%s' failed.", \
++ __FILE__, \
++ __LINE__, \
++ #expr); \
++ return val; \
++ }; }G_STMT_END
++
++#endif /* !__GNUC__ */
++
++#endif /* !G_DISABLE_CHECKS */
++
++#endif /* !__KORBIT__ */
++
++
++/* Provide type definitions for commonly used types.
++ * These are useful because a "gint8" can be adjusted
++ * to be 1 byte (8 bits) on all platforms. Similarly and
++ * more importantly, "gint32" can be adjusted to be
++ * 4 bytes (32 bits) on all platforms.
++ */
++
++typedef char gchar;
++typedef short gshort;
++typedef long glong;
++typedef int gint;
++typedef gint gboolean;
++
++typedef unsigned char guchar;
++typedef unsigned short gushort;
++typedef unsigned long gulong;
++typedef unsigned int guint;
++
++typedef float gfloat;
++typedef double gdouble;
++
++/* HAVE_LONG_DOUBLE doesn't work correctly on all platforms.
++ * Since gldouble isn't used anywhere, just disable it for now */
++
++#if 0
++#ifdef HAVE_LONG_DOUBLE
++typedef long double gldouble;
++#else /* HAVE_LONG_DOUBLE */
++typedef double gldouble;
++#endif /* HAVE_LONG_DOUBLE */
++#endif /* 0 */
++
++typedef void* gpointer;
++typedef const void *gconstpointer;
++
++
++typedef gint32 gssize;
++typedef guint32 gsize;
++typedef guint32 GQuark;
++typedef gint32 GTime;
++
++
++/* Portable endian checks and conversions
++ *
++ * glibconfig.h defines G_BYTE_ORDER which expands to one of
++ * the below macros.
++ */
++#define G_LITTLE_ENDIAN 1234
++#define G_BIG_ENDIAN 4321
++#define G_PDP_ENDIAN 3412 /* unused, need specific PDP check */
++
++
++/* Basic bit swapping functions
++ */
++#define GUINT16_SWAP_LE_BE_CONSTANT(val) ((guint16) ( \
++ (((guint16) (val) & (guint16) 0x00ffU) << 8) | \
++ (((guint16) (val) & (guint16) 0xff00U) >> 8)))
++#define GUINT32_SWAP_LE_BE_CONSTANT(val) ((guint32) ( \
++ (((guint32) (val) & (guint32) 0x000000ffU) << 24) | \
++ (((guint32) (val) & (guint32) 0x0000ff00U) << 8) | \
++ (((guint32) (val) & (guint32) 0x00ff0000U) >> 8) | \
++ (((guint32) (val) & (guint32) 0xff000000U) >> 24)))
++
++/* Intel specific stuff for speed
++ */
++#if defined (__i386__) && defined (__GNUC__) && __GNUC__ >= 2
++# define GUINT16_SWAP_LE_BE_X86(val) \
++ (__extension__ \
++ ({ register guint16 __v; \
++ if (__builtin_constant_p (val)) \
++ __v = GUINT16_SWAP_LE_BE_CONSTANT (val); \
++ else \
++ __asm__ __const__ ("rorw $8, %w0" \
++ : "=r" (__v) \
++ : "0" ((guint16) (val))); \
++ __v; }))
++# define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_X86 (val))
++# if !defined(__i486__) && !defined(__i586__) \
++ && !defined(__pentium__) && !defined(__i686__) && !defined(__pentiumpro__)
++# define GUINT32_SWAP_LE_BE_X86(val) \
++ (__extension__ \
++ ({ register guint32 __v; \
++ if (__builtin_constant_p (val)) \
++ __v = GUINT32_SWAP_LE_BE_CONSTANT (val); \
++ else \
++ __asm__ __const__ ("rorw $8, %w0\n\t" \
++ "rorl $16, %0\n\t" \
++ "rorw $8, %w0" \
++ : "=r" (__v) \
++ : "0" ((guint32) (val))); \
++ __v; }))
++# else /* 486 and higher has bswap */
++# define GUINT32_SWAP_LE_BE_X86(val) \
++ (__extension__ \
++ ({ register guint32 __v; \
++ if (__builtin_constant_p (val)) \
++ __v = GUINT32_SWAP_LE_BE_CONSTANT (val); \
++ else \
++ __asm__ __const__ ("bswap %0" \
++ : "=r" (__v) \
++ : "0" ((guint32) (val))); \
++ __v; }))
++# endif /* processor specific 32-bit stuff */
++# define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_X86 (val))
++#else /* !__i386__ */
++# define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_CONSTANT (val))
++# define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_CONSTANT (val))
++#endif /* __i386__ */
++
++#ifdef G_HAVE_GINT64
++# define GUINT64_SWAP_LE_BE_CONSTANT(val) ((guint64) ( \
++ (((guint64) (val) & \
++ (guint64) G_GINT64_CONSTANT(0x00000000000000ffU)) << 56) | \
++ (((guint64) (val) & \
++ (guint64) G_GINT64_CONSTANT(0x000000000000ff00U)) << 40) | \
++ (((guint64) (val) & \
++ (guint64) G_GINT64_CONSTANT(0x0000000000ff0000U)) << 24) | \
++ (((guint64) (val) & \
++ (guint64) G_GINT64_CONSTANT(0x00000000ff000000U)) << 8) | \
++ (((guint64) (val) & \
++ (guint64) G_GINT64_CONSTANT(0x000000ff00000000U)) >> 8) | \
++ (((guint64) (val) & \
++ (guint64) G_GINT64_CONSTANT(0x0000ff0000000000U)) >> 24) | \
++ (((guint64) (val) & \
++ (guint64) G_GINT64_CONSTANT(0x00ff000000000000U)) >> 40) | \
++ (((guint64) (val) & \
++ (guint64) G_GINT64_CONSTANT(0xff00000000000000U)) >> 56)))
++# if defined (__i386__) && defined (__GNUC__) && __GNUC__ >= 2
++# define GUINT64_SWAP_LE_BE_X86(val) \
++ (__extension__ \
++ ({ union { guint64 __ll; \
++ guint32 __l[2]; } __r; \
++ if (__builtin_constant_p (val)) \
++ __r.__ll = GUINT64_SWAP_LE_BE_CONSTANT (val); \
++ else \
++ { \
++ union { guint64 __ll; \
++ guint32 __l[2]; } __w; \
++ __w.__ll = ((guint64) val); \
++ __r.__l[0] = GUINT32_SWAP_LE_BE (__w.__l[1]); \
++ __r.__l[1] = GUINT32_SWAP_LE_BE (__w.__l[0]); \
++ } \
++ __r.__ll; }))
++# define GUINT64_SWAP_LE_BE(val) (GUINT64_SWAP_LE_BE_X86 (val))
++# else /* !__i386__ */
++# define GUINT64_SWAP_LE_BE(val) (GUINT64_SWAP_LE_BE_CONSTANT(val))
++# endif
++#endif
++
++#define GUINT16_SWAP_LE_PDP(val) ((guint16) (val))
++#define GUINT16_SWAP_BE_PDP(val) (GUINT16_SWAP_LE_BE (val))
++#define GUINT32_SWAP_LE_PDP(val) ((guint32) ( \
++ (((guint32) (val) & (guint32) 0x0000ffffU) << 16) | \
++ (((guint32) (val) & (guint32) 0xffff0000U) >> 16)))
++#define GUINT32_SWAP_BE_PDP(val) ((guint32) ( \
++ (((guint32) (val) & (guint32) 0x00ff00ffU) << 8) | \
++ (((guint32) (val) & (guint32) 0xff00ff00U) >> 8)))
++
++/* The G*_TO_?E() macros are defined in glibconfig.h.
++ * The transformation is symmetric, so the FROM just maps to the TO.
++ */
++#define GINT16_FROM_LE(val) (GINT16_TO_LE (val))
++#define GUINT16_FROM_LE(val) (GUINT16_TO_LE (val))
++#define GINT16_FROM_BE(val) (GINT16_TO_BE (val))
++#define GUINT16_FROM_BE(val) (GUINT16_TO_BE (val))
++#define GINT32_FROM_LE(val) (GINT32_TO_LE (val))
++#define GUINT32_FROM_LE(val) (GUINT32_TO_LE (val))
++#define GINT32_FROM_BE(val) (GINT32_TO_BE (val))
++#define GUINT32_FROM_BE(val) (GUINT32_TO_BE (val))
++
++#ifdef G_HAVE_GINT64
++#define GINT64_FROM_LE(val) (GINT64_TO_LE (val))
++#define GUINT64_FROM_LE(val) (GUINT64_TO_LE (val))
++#define GINT64_FROM_BE(val) (GINT64_TO_BE (val))
++#define GUINT64_FROM_BE(val) (GUINT64_TO_BE (val))
++#endif
++
++#define GLONG_FROM_LE(val) (GLONG_TO_LE (val))
++#define GULONG_FROM_LE(val) (GULONG_TO_LE (val))
++#define GLONG_FROM_BE(val) (GLONG_TO_BE (val))
++#define GULONG_FROM_BE(val) (GULONG_TO_BE (val))
++
++#define GINT_FROM_LE(val) (GINT_TO_LE (val))
++#define GUINT_FROM_LE(val) (GUINT_TO_LE (val))
++#define GINT_FROM_BE(val) (GINT_TO_BE (val))
++#define GUINT_FROM_BE(val) (GUINT_TO_BE (val))
++
++
++/* Portable versions of host-network order stuff
++ */
++#define g_ntohl(val) (GUINT32_FROM_BE (val))
++#define g_ntohs(val) (GUINT16_FROM_BE (val))
++#define g_htonl(val) (GUINT32_TO_BE (val))
++#define g_htons(val) (GUINT16_TO_BE (val))
++
++
++/* Glib version.
++ * we prefix variable declarations so they can
++ * properly get exported in windows dlls.
++ */
++#define GUTILS_C_VAR extern
++
++
++GUTILS_C_VAR const guint glib_major_version;
++GUTILS_C_VAR const guint glib_minor_version;
++GUTILS_C_VAR const guint glib_micro_version;
++GUTILS_C_VAR const guint glib_interface_age;
++GUTILS_C_VAR const guint glib_binary_age;
++
++#define GLIB_CHECK_VERSION(major,minor,micro) \
++ (GLIB_MAJOR_VERSION > (major) || \
++ (GLIB_MAJOR_VERSION == (major) && GLIB_MINOR_VERSION > (minor)) || \
++ (GLIB_MAJOR_VERSION == (major) && GLIB_MINOR_VERSION == (minor) && \
++ GLIB_MICRO_VERSION >= (micro)))
++
++/* Forward declarations of glib types.
++ */
++typedef struct _GAllocator GAllocator;
++typedef struct _GArray GArray;
++typedef struct _GByteArray GByteArray;
++typedef struct _GDebugKey GDebugKey;
++typedef struct _GHashTable GHashTable;
++typedef struct _GList GList;
++typedef struct _GMemChunk GMemChunk;
++typedef struct _GNode GNode;
++typedef struct _GPtrArray GPtrArray;
++typedef struct _GSList GSList;
++typedef struct _GString GString;
++typedef struct _GStringChunk GStringChunk;
++typedef struct _GTree GTree;
++typedef struct _GTuples GTuples;
++
++/* Tree traverse flags */
++typedef enum
++{
++ G_TRAVERSE_LEAFS = 1 << 0,
++ G_TRAVERSE_NON_LEAFS = 1 << 1,
++ G_TRAVERSE_ALL = G_TRAVERSE_LEAFS | G_TRAVERSE_NON_LEAFS,
++ G_TRAVERSE_MASK = 0x03
++} GTraverseFlags;
++
++/* Tree traverse orders */
++typedef enum
++{
++ G_IN_ORDER,
++ G_PRE_ORDER,
++ G_POST_ORDER,
++ G_LEVEL_ORDER
++} GTraverseType;
++
++/* Log level shift offset for user defined
++ * log levels (0-7 are used by GLib).
++ */
++#define G_LOG_LEVEL_USER_SHIFT (8)
++
++/* Glib log levels and flags.
++ */
++typedef enum
++{
++ /* log flags */
++ G_LOG_FLAG_RECURSION = 1 << 0,
++ G_LOG_FLAG_FATAL = 1 << 1,
++
++ /* GLib log levels */
++ G_LOG_LEVEL_ERROR = 1 << 2, /* always fatal */
++ G_LOG_LEVEL_CRITICAL = 1 << 3,
++ G_LOG_LEVEL_WARNING = 1 << 4,
++ G_LOG_LEVEL_MESSAGE = 1 << 5,
++ G_LOG_LEVEL_INFO = 1 << 6,
++ G_LOG_LEVEL_DEBUG = 1 << 7,
++
++ G_LOG_LEVEL_MASK = ~(G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL)
++} GLogLevelFlags;
++
++/* GLib log levels that are considered fatal by default */
++#define G_LOG_FATAL_MASK (G_LOG_FLAG_RECURSION | G_LOG_LEVEL_ERROR)
++
++
++typedef gint (*GCompareFunc) (gconstpointer a,
++ gconstpointer b);
++typedef gchar* (*GCompletionFunc) (gpointer);
++typedef void (*GDestroyNotify) (gpointer data);
++typedef void (*GDataForeachFunc) (GQuark key_id,
++ gpointer data,
++ gpointer user_data);
++typedef void (*GFunc) (gpointer data,
++ gpointer user_data);
++typedef guint (*GHashFunc) (gconstpointer key);
++typedef void (*GFreeFunc) (gpointer data);
++typedef void (*GHFunc) (gpointer key,
++ gpointer value,
++ gpointer user_data);
++typedef gboolean (*GHRFunc) (gpointer key,
++ gpointer value,
++ gpointer user_data);
++typedef void (*GLogFunc) (const gchar *log_domain,
++ GLogLevelFlags log_level,
++ const gchar *message,
++ gpointer user_data);
++typedef gboolean (*GNodeTraverseFunc) (GNode *node,
++ gpointer data);
++typedef void (*GNodeForeachFunc) (GNode *node,
++ gpointer data);
++typedef gint (*GSearchFunc) (gpointer key,
++ gpointer data);
++typedef gint (*GTraverseFunc) (gpointer key,
++ gpointer value,
++ gpointer data);
++typedef void (*GVoidFunc) (void);
++
++
++struct _GList
++{
++ gpointer data;
++ GList *next;
++ GList *prev;
++};
++
++struct _GSList
++{
++ gpointer data;
++ GSList *next;
++};
++
++struct _GString
++{
++ gchar *str;
++ gint len;
++};
++
++struct _GArray
++{
++ gchar *data;
++ guint len;
++};
++
++struct _GByteArray
++{
++ guint8 *data;
++ guint len;
++};
++
++struct _GPtrArray
++{
++ gpointer *pdata;
++ guint len;
++};
++
++struct _GTuples
++{
++ guint len;
++};
++
++struct _GDebugKey
++{
++ gchar *key;
++ guint value;
++};
++
++
++/* Doubly linked lists
++ */
++void g_list_push_allocator (GAllocator *allocator);
++void g_list_pop_allocator (void);
++GList* g_list_alloc (void);
++void g_list_free (GList *list);
++void g_list_free_1 (GList *list);
++GList* g_list_append (GList *list,
++ gpointer data);
++GList* g_list_prepend (GList *list,
++ gpointer data);
++GList* g_list_insert (GList *list,
++ gpointer data,
++ gint position);
++GList* g_list_insert_sorted (GList *list,
++ gpointer data,
++ GCompareFunc func);
++GList* g_list_concat (GList *list1,
++ GList *list2);
++GList* g_list_remove (GList *list,
++ gpointer data);
++GList* g_list_remove_link (GList *list,
++ GList *llink);
++GList* g_list_reverse (GList *list);
++GList* g_list_copy (GList *list);
++GList* g_list_nth (GList *list,
++ guint n);
++GList* g_list_find (GList *list,
++ gpointer data);
++GList* g_list_find_custom (GList *list,
++ gpointer data,
++ GCompareFunc func);
++gint g_list_position (GList *list,
++ GList *llink);
++gint g_list_index (GList *list,
++ gpointer data);
++GList* g_list_last (GList *list);
++GList* g_list_first (GList *list);
++guint g_list_length (GList *list);
++void g_list_foreach (GList *list,
++ GFunc func,
++ gpointer user_data);
++GList* g_list_sort (GList *list,
++ GCompareFunc compare_func);
++gpointer g_list_nth_data (GList *list,
++ guint n);
++#define g_list_previous(list) ((list) ? (((GList *)(list))->prev) : NULL)
++#define g_list_next(list) ((list) ? (((GList *)(list))->next) : NULL)
++
++
++/* Singly linked lists
++ */
++void g_slist_push_allocator (GAllocator *allocator);
++void g_slist_pop_allocator (void);
++GSList* g_slist_alloc (void);
++void g_slist_free (GSList *list);
++void g_slist_free_1 (GSList *list);
++GSList* g_slist_append (GSList *list,
++ gpointer data);
++GSList* g_slist_prepend (GSList *list,
++ gpointer data);
++GSList* g_slist_insert (GSList *list,
++ gpointer data,
++ gint position);
++GSList* g_slist_insert_sorted (GSList *list,
++ gpointer data,
++ GCompareFunc func);
++GSList* g_slist_concat (GSList *list1,
++ GSList *list2);
++GSList* g_slist_remove (GSList *list,
++ gpointer data);
++GSList* g_slist_remove_link (GSList *list,
++ GSList *llink);
++GSList* g_slist_reverse (GSList *list);
++GSList* g_slist_copy (GSList *list);
++GSList* g_slist_nth (GSList *list,
++ guint n);
++GSList* g_slist_find (GSList *list,
++ gpointer data);
++GSList* g_slist_find_custom (GSList *list,
++ gpointer data,
++ GCompareFunc func);
++gint g_slist_position (GSList *list,
++ GSList *llink);
++gint g_slist_index (GSList *list,
++ gpointer data);
++GSList* g_slist_last (GSList *list);
++guint g_slist_length (GSList *list);
++void g_slist_foreach (GSList *list,
++ GFunc func,
++ gpointer user_data);
++GSList* g_slist_sort (GSList *list,
++ GCompareFunc compare_func);
++gpointer g_slist_nth_data (GSList *list,
++ guint n);
++#define g_slist_next(slist) ((slist) ? (((GSList *)(slist))->next) : NULL)
++
++
++/* Hash tables
++ */
++GHashTable* g_hash_table_new (GHashFunc hash_func,
++ GCompareFunc key_compare_func);
++void g_hash_table_destroy (GHashTable *hash_table);
++void g_hash_table_insert (GHashTable *hash_table,
++ gpointer key,
++ gpointer value);
++void g_hash_table_remove (GHashTable *hash_table,
++ gconstpointer key);
++gpointer g_hash_table_lookup (GHashTable *hash_table,
++ gconstpointer key);
++gboolean g_hash_table_lookup_extended(GHashTable *hash_table,
++ gconstpointer lookup_key,
++ gpointer *orig_key,
++ gpointer *value);
++void g_hash_table_freeze (GHashTable *hash_table);
++void g_hash_table_thaw (GHashTable *hash_table);
++void g_hash_table_foreach (GHashTable *hash_table,
++ GHFunc func,
++ gpointer user_data);
++guint g_hash_table_foreach_remove (GHashTable *hash_table,
++ GHRFunc func,
++ gpointer user_data);
++guint g_hash_table_size (GHashTable *hash_table);
++
++
++
++
++/* Balanced binary trees
++ */
++GTree* g_tree_new (GCompareFunc key_compare_func);
++void g_tree_destroy (GTree *tree);
++void g_tree_insert (GTree *tree,
++ gpointer key,
++ gpointer value);
++void g_tree_remove (GTree *tree,
++ gpointer key);
++gpointer g_tree_lookup (GTree *tree,
++ gpointer key);
++void g_tree_traverse (GTree *tree,
++ GTraverseFunc traverse_func,
++ GTraverseType traverse_type,
++ gpointer data);
++gpointer g_tree_search (GTree *tree,
++ GSearchFunc search_func,
++ gpointer data);
++gint g_tree_height (GTree *tree);
++gint g_tree_nnodes (GTree *tree);
++
++
++
++/* N-way tree implementation
++ */
++struct _GNode
++{
++ gpointer data;
++ GNode *next;
++ GNode *prev;
++ GNode *parent;
++ GNode *children;
++};
++
++#define G_NODE_IS_ROOT(node) (((GNode*) (node))->parent == NULL && \
++ ((GNode*) (node))->prev == NULL && \
++ ((GNode*) (node))->next == NULL)
++#define G_NODE_IS_LEAF(node) (((GNode*) (node))->children == NULL)
++
++void g_node_push_allocator (GAllocator *allocator);
++void g_node_pop_allocator (void);
++GNode* g_node_new (gpointer data);
++void g_node_destroy (GNode *root);
++void g_node_unlink (GNode *node);
++GNode* g_node_insert (GNode *parent,
++ gint position,
++ GNode *node);
++GNode* g_node_insert_before (GNode *parent,
++ GNode *sibling,
++ GNode *node);
++GNode* g_node_prepend (GNode *parent,
++ GNode *node);
++guint g_node_n_nodes (GNode *root,
++ GTraverseFlags flags);
++GNode* g_node_get_root (GNode *node);
++gboolean g_node_is_ancestor (GNode *node,
++ GNode *descendant);
++guint g_node_depth (GNode *node);
++GNode* g_node_find (GNode *root,
++ GTraverseType order,
++ GTraverseFlags flags,
++ gpointer data);
++
++/* convenience macros */
++#define g_node_append(parent, node) \
++ g_node_insert_before ((parent), NULL, (node))
++#define g_node_insert_data(parent, position, data) \
++ g_node_insert ((parent), (position), g_node_new (data))
++#define g_node_insert_data_before(parent, sibling, data) \
++ g_node_insert_before ((parent), (sibling), g_node_new (data))
++#define g_node_prepend_data(parent, data) \
++ g_node_prepend ((parent), g_node_new (data))
++#define g_node_append_data(parent, data) \
++ g_node_insert_before ((parent), NULL, g_node_new (data))
++
++/* traversal function, assumes that `node' is root
++ * (only traverses `node' and its subtree).
++ * this function is just a high level interface to
++ * low level traversal functions, optimized for speed.
++ */
++void g_node_traverse (GNode *root,
++ GTraverseType order,
++ GTraverseFlags flags,
++ gint max_depth,
++ GNodeTraverseFunc func,
++ gpointer data);
++
++/* return the maximum tree height starting with `node', this is an expensive
++ * operation, since we need to visit all nodes. this could be shortened by
++ * adding `guint height' to struct _GNode, but then again, this is not very
++ * often needed, and would make g_node_insert() more time consuming.
++ */
++guint g_node_max_height (GNode *root);
++
++void g_node_children_foreach (GNode *node,
++ GTraverseFlags flags,
++ GNodeForeachFunc func,
++ gpointer data);
++void g_node_reverse_children (GNode *node);
++guint g_node_n_children (GNode *node);
++GNode* g_node_nth_child (GNode *node,
++ guint n);
++GNode* g_node_last_child (GNode *node);
++GNode* g_node_find_child (GNode *node,
++ GTraverseFlags flags,
++ gpointer data);
++gint g_node_child_position (GNode *node,
++ GNode *child);
++gint g_node_child_index (GNode *node,
++ gpointer data);
++
++GNode* g_node_first_sibling (GNode *node);
++GNode* g_node_last_sibling (GNode *node);
++
++#define g_node_prev_sibling(node) ((node) ? \
++ ((GNode*) (node))->prev : NULL)
++#define g_node_next_sibling(node) ((node) ? \
++ ((GNode*) (node))->next : NULL)
++#define g_node_first_child(node) ((node) ? \
++ ((GNode*) (node))->children : NULL)
++
++
++
++/* Fatal error handlers.
++ * g_on_error_query() will prompt the user to either
++ * [E]xit, [H]alt, [P]roceed or show [S]tack trace.
++ * g_on_error_stack_trace() invokes gdb, which attaches to the current
++ * process and shows a stack trace.
++ * These function may cause different actions on non-unix platforms.
++ * The prg_name arg is required by gdb to find the executable, if it is
++ * passed as NULL, g_on_error_query() will try g_get_prgname().
++ */
++void g_on_error_query (const gchar *prg_name);
++void g_on_error_stack_trace (const gchar *prg_name);
++
++
++/* Logging mechanism
++ */
++extern const gchar *g_log_domain_glib;
++guint g_log_set_handler (const gchar *log_domain,
++ GLogLevelFlags log_levels,
++ GLogFunc log_func,
++ gpointer user_data);
++void g_log_remove_handler (const gchar *log_domain,
++ guint handler_id);
++void g_log_default_handler (const gchar *log_domain,
++ GLogLevelFlags log_level,
++ const gchar *message,
++ gpointer unused_data);
++#ifdef __KORBIT__
++#define g_log(log_domain, log_level, format, args...) \
++G_STMT_START { printf(format, ##args); printf("\n"); } G_STMT_END
++#define g_logv(log_domain, log_level, format, args...)
++#else /* !__KORBIT__ */
++void g_log (const gchar *log_domain,
++ GLogLevelFlags log_level,
++ const gchar *format,
++ ...) G_GNUC_PRINTF (3, 4);
++void g_logv (const gchar *log_domain,
++ GLogLevelFlags log_level,
++ const gchar *format,
++ va_list args);
++#endif /* !__KORBIT__ */
++GLogLevelFlags g_log_set_fatal_mask (const gchar *log_domain,
++ GLogLevelFlags fatal_mask);
++GLogLevelFlags g_log_set_always_fatal (GLogLevelFlags fatal_mask);
++#ifndef G_LOG_DOMAIN
++#define G_LOG_DOMAIN ((gchar*) 0)
++#endif /* G_LOG_DOMAIN */
++#ifdef __GNUC__
++#define g_error(format, args...) g_log (G_LOG_DOMAIN, \
++ G_LOG_LEVEL_ERROR, \
++ format, ##args)
++#define g_message(format, args...) g_log (G_LOG_DOMAIN, \
++ G_LOG_LEVEL_MESSAGE, \
++ format, ##args)
++#define g_warning(format, args...) g_log (G_LOG_DOMAIN, \
++ G_LOG_LEVEL_WARNING, \
++ format, ##args)
++#else /* !__GNUC__ */
++static void
++g_error (const gchar *format,
++ ...)
++{
++ va_list args;
++ va_start (args, format);
++ g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, format, args);
++ va_end (args);
++}
++static void
++g_message (const gchar *format,
++ ...)
++{
++ va_list args;
++ va_start (args, format);
++ g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, format, args);
++ va_end (args);
++}
++static void
++g_warning (const gchar *format,
++ ...)
++{
++ va_list args;
++ va_start (args, format);
++ g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, format, args);
++ va_end (args);
++}
++#endif /* !__GNUC__ */
++
++typedef void (*GPrintFunc) (const gchar *string);
++#ifdef __KORBIT__
++#define g_print(format, args...) printf(format, ##args)
++#else
++void g_print (const gchar *format,
++ ...) G_GNUC_PRINTF (1, 2);
++#endif
++GPrintFunc g_set_print_handler (GPrintFunc func);
++void g_printerr (const gchar *format,
++ ...) G_GNUC_PRINTF (1, 2);
++GPrintFunc g_set_printerr_handler (GPrintFunc func);
++
++/* deprecated compatibility functions, use g_log_set_handler() instead */
++typedef void (*GErrorFunc) (const gchar *str);
++typedef void (*GWarningFunc) (const gchar *str);
++GErrorFunc g_set_error_handler (GErrorFunc func);
++GWarningFunc g_set_warning_handler (GWarningFunc func);
++GPrintFunc g_set_message_handler (GPrintFunc func);
++
++
++gpointer g_malloc (gulong size);
++gpointer g_malloc0 (gulong size);
++gpointer g_realloc (gpointer mem,
++ gulong size);
++void g_free (gpointer mem);
++
++/* Generic allocators
++ */
++GAllocator* g_allocator_new (const gchar *name,
++ guint n_preallocs);
++void g_allocator_free (GAllocator *allocator);
++
++#define G_ALLOCATOR_LIST (1)
++#define G_ALLOCATOR_SLIST (2)
++#define G_ALLOCATOR_NODE (3)
++
++
++/* "g_mem_chunk_new" creates a new memory chunk.
++ * Memory chunks are used to allocate pieces of memory which are
++ * always the same size. Lists are a good example of such a data type.
++ * The memory chunk allocates and frees blocks of memory as needed.
++ * Just be sure to call "g_mem_chunk_free" and not "g_free" on data
++ * allocated in a mem chunk. ("g_free" will most likely cause a seg
++ * fault...somewhere).
++ *
++ * Oh yeah, GMemChunk is an opaque data type. (You don't really
++ * want to know what's going on inside do you?)
++ */
++
++/* ALLOC_ONLY MemChunk's can only allocate memory. The free operation
++ * is interpreted as a no op. ALLOC_ONLY MemChunk's save 4 bytes per
++ * atom. (They are also useful for lists which use MemChunk to allocate
++ * memory but are also part of the MemChunk implementation).
++ * ALLOC_AND_FREE MemChunk's can allocate and free memory.
++ */
++
++#define G_ALLOC_ONLY 1
++#define G_ALLOC_AND_FREE 2
++
++GMemChunk* g_mem_chunk_new (gchar *name,
++ gint atom_size,
++ gulong area_size,
++ gint type);
++void g_mem_chunk_destroy (GMemChunk *mem_chunk);
++gpointer g_mem_chunk_alloc (GMemChunk *mem_chunk);
++gpointer g_mem_chunk_alloc0 (GMemChunk *mem_chunk);
++void g_mem_chunk_free (GMemChunk *mem_chunk,
++ gpointer mem);
++void g_mem_chunk_clean (GMemChunk *mem_chunk);
++void g_mem_chunk_reset (GMemChunk *mem_chunk);
++void g_mem_chunk_print (GMemChunk *mem_chunk);
++void g_mem_chunk_info (void);
++
++/* Ah yes...we have a "g_blow_chunks" function.
++ * "g_blow_chunks" simply compresses all the chunks. This operation
++ * consists of freeing every memory area that should be freed (but
++ * which we haven't gotten around to doing yet). And, no,
++ * "g_blow_chunks" doesn't follow the naming scheme, but it is a
++ * much better name than "g_mem_chunk_clean_all" or something
++ * similar.
++ */
++void g_blow_chunks (void);
++
++
++/* String utility functions that modify a string argument or
++ * return a constant string that must not be freed.
++ */
++#define G_STR_DELIMITERS "_-|> <."
++gchar* g_strdelimit (gchar *string,
++ const gchar *delimiters,
++ gchar new_delimiter);
++#ifndef __KORBIT__
++gdouble g_strtod (const gchar *nptr,
++ gchar **endptr);
++#endif /* !__KORBIT__ */
++gchar* g_strerror (gint errnum);
++gchar* g_strsignal (gint signum);
++gint g_strcasecmp (const gchar *s1,
++ const gchar *s2);
++gint g_strncasecmp (const gchar *s1,
++ const gchar *s2,
++ guint n);
++void g_strdown (gchar *string);
++void g_strup (gchar *string);
++void g_strreverse (gchar *string);
++/* removes leading spaces */
++gchar* g_strchug (gchar *string);
++/* removes trailing spaces */
++gchar* g_strchomp (gchar *string);
++/* removes leading & trailing spaces */
++#define g_strstrip( string ) g_strchomp (g_strchug (string))
++
++/* String utility functions that return a newly allocated string which
++ * ought to be freed from the caller at some point.
++ */
++gchar* g_strdup (const gchar *str);
++gchar* g_strdup_printf (const gchar *format,
++ ...) G_GNUC_PRINTF (1, 2);
++gchar* g_strdup_vprintf (const gchar *format,
++ va_list args);
++gchar* g_strndup (const gchar *str,
++ guint n);
++gchar* g_strnfill (guint length,
++ gchar fill_char);
++gchar* g_strconcat (const gchar *string1,
++ ...); /* NULL terminated */
++gchar* g_strjoin (const gchar *separator,
++ ...); /* NULL terminated */
++gchar* g_strescape (gchar *string);
++gpointer g_memdup (gconstpointer mem,
++ guint byte_size);
++
++/* NULL terminated string arrays.
++ * g_strsplit() splits up string into max_tokens tokens at delim and
++ * returns a newly allocated string array.
++ * g_strjoinv() concatenates all of str_array's strings, sliding in an
++ * optional separator, the returned string is newly allocated.
++ * g_strfreev() frees the array itself and all of its strings.
++ */
++gchar** g_strsplit (const gchar *string,
++ const gchar *delimiter,
++ gint max_tokens);
++gchar* g_strjoinv (const gchar *separator,
++ gchar **str_array);
++void g_strfreev (gchar **str_array);
++
++
++
++/* calculate a string size, guarranteed to fit format + args.
++ */
++guint g_printf_string_upper_bound (const gchar* format,
++ va_list args);
++
++
++/* Retrive static string info
++ */
++gchar* g_get_user_name (void);
++gchar* g_get_real_name (void);
++gchar* g_get_home_dir (void);
++gchar* g_get_tmp_dir (void);
++gchar* g_get_prgname (void);
++void g_set_prgname (const gchar *prgname);
++
++
++/* Miscellaneous utility functions
++ */
++guint g_parse_debug_string (const gchar *string,
++ GDebugKey *keys,
++ guint nkeys);
++gint g_snprintf (gchar *string,
++ gulong n,
++ gchar const *format,
++ ...) G_GNUC_PRINTF (3, 4);
++gint g_vsnprintf (gchar *string,
++ gulong n,
++ gchar const *format,
++ va_list args);
++gchar* g_basename (const gchar *file_name);
++/* Check if a file name is an absolute path */
++gboolean g_path_is_absolute (const gchar *file_name);
++/* In case of absolute paths, skip the root part */
++gchar* g_path_skip_root (gchar *file_name);
++
++/* strings are newly allocated with g_malloc() */
++gchar* g_dirname (const gchar *file_name);
++gchar* g_get_current_dir (void);
++gchar* g_getenv (const gchar *variable);
++
++
++/* we use a GLib function as a replacement for ATEXIT, so
++ * the programmer is not required to check the return value
++ * (if there is any in the implementation) and doesn't encounter
++ * missing include files.
++ */
++void g_atexit (GVoidFunc func);
++
++
++/* Bit tests
++ */
++G_INLINE_FUNC gint g_bit_nth_lsf (guint32 mask,
++ gint nth_bit);
++#ifdef G_CAN_INLINE
++G_INLINE_FUNC gint
++g_bit_nth_lsf (guint32 mask,
++ gint nth_bit)
++{
++ do
++ {
++ nth_bit++;
++ if (mask & (1 << (guint) nth_bit))
++ return nth_bit;
++ }
++ while (nth_bit < 32);
++ return -1;
++}
++#endif /* G_CAN_INLINE */
++
++G_INLINE_FUNC gint g_bit_nth_msf (guint32 mask,
++ gint nth_bit);
++#ifdef G_CAN_INLINE
++G_INLINE_FUNC gint
++g_bit_nth_msf (guint32 mask,
++ gint nth_bit)
++{
++ if (nth_bit < 0)
++ nth_bit = 32;
++ do
++ {
++ nth_bit--;
++ if (mask & (1 << (guint) nth_bit))
++ return nth_bit;
++ }
++ while (nth_bit > 0);
++ return -1;
++}
++#endif /* G_CAN_INLINE */
++
++G_INLINE_FUNC guint g_bit_storage (guint number);
++#ifdef G_CAN_INLINE
++G_INLINE_FUNC guint
++g_bit_storage (guint number)
++{
++ register guint n_bits = 0;
++
++ do
++ {
++ n_bits++;
++ number >>= 1;
++ }
++ while (number);
++ return n_bits;
++}
++#endif /* G_CAN_INLINE */
++
++/* String Chunks
++ */
++GStringChunk* g_string_chunk_new (gint size);
++void g_string_chunk_free (GStringChunk *chunk);
++gchar* g_string_chunk_insert (GStringChunk *chunk,
++ const gchar *string);
++gchar* g_string_chunk_insert_const (GStringChunk *chunk,
++ const gchar *string);
++
++
++/* Strings
++ */
++GString* g_string_new (const gchar *init);
++GString* g_string_sized_new (guint dfl_size);
++void g_string_free (GString *string,
++ gint free_segment);
++GString* g_string_assign (GString *lval,
++ const gchar *rval);
++GString* g_string_truncate (GString *string,
++ gint len);
++GString* g_string_append (GString *string,
++ const gchar *val);
++GString* g_string_append_c (GString *string,
++ gchar c);
++GString* g_string_prepend (GString *string,
++ const gchar *val);
++GString* g_string_prepend_c (GString *string,
++ gchar c);
++GString* g_string_insert (GString *string,
++ gint pos,
++ const gchar *val);
++GString* g_string_insert_c (GString *string,
++ gint pos,
++ gchar c);
++GString* g_string_erase (GString *string,
++ gint pos,
++ gint len);
++GString* g_string_down (GString *string);
++GString* g_string_up (GString *string);
++void g_string_sprintf (GString *string,
++ const gchar *format,
++ ...) G_GNUC_PRINTF (2, 3);
++void g_string_sprintfa (GString *string,
++ const gchar *format,
++ ...) G_GNUC_PRINTF (2, 3);
++
++
++/* Resizable arrays, remove fills any cleared spot and shortens the
++ * array, while preserving the order. remove_fast will distort the
++ * order by moving the last element to the position of the removed
++ */
++
++#define g_array_append_val(a,v) g_array_append_vals (a, &v, 1)
++#define g_array_prepend_val(a,v) g_array_prepend_vals (a, &v, 1)
++#define g_array_insert_val(a,i,v) g_array_insert_vals (a, i, &v, 1)
++#define g_array_index(a,t,i) (((t*) (a)->data) [(i)])
++
++GArray* g_array_new (gboolean zero_terminated,
++ gboolean clear,
++ guint element_size);
++void g_array_free (GArray *array,
++ gboolean free_segment);
++GArray* g_array_append_vals (GArray *array,
++ gconstpointer data,
++ guint len);
++GArray* g_array_prepend_vals (GArray *array,
++ gconstpointer data,
++ guint len);
++GArray* g_array_insert_vals (GArray *array,
++ guint index,
++ gconstpointer data,
++ guint len);
++GArray* g_array_set_size (GArray *array,
++ guint length);
++GArray* g_array_remove_index (GArray *array,
++ guint index);
++GArray* g_array_remove_index_fast (GArray *array,
++ guint index);
++
++/* Resizable pointer array. This interface is much less complicated
++ * than the above. Add appends appends a pointer. Remove fills any
++ * cleared spot and shortens the array. remove_fast will again distort
++ * order.
++ */
++#define g_ptr_array_index(array,index) (array->pdata)[index]
++GPtrArray* g_ptr_array_new (void);
++void g_ptr_array_free (GPtrArray *array,
++ gboolean free_seg);
++void g_ptr_array_set_size (GPtrArray *array,
++ gint length);
++gpointer g_ptr_array_remove_index (GPtrArray *array,
++ guint index);
++gpointer g_ptr_array_remove_index_fast (GPtrArray *array,
++ guint index);
++gboolean g_ptr_array_remove (GPtrArray *array,
++ gpointer data);
++gboolean g_ptr_array_remove_fast (GPtrArray *array,
++ gpointer data);
++void g_ptr_array_add (GPtrArray *array,
++ gpointer data);
++
++/* Hash Functions
++ */
++gint g_str_equal (gconstpointer v,
++ gconstpointer v2);
++guint g_str_hash (gconstpointer v);
++
++gint g_int_equal (gconstpointer v,
++ gconstpointer v2);
++guint g_int_hash (gconstpointer v);
++
++/* This "hash" function will just return the key's adress as an
++ * unsigned integer. Useful for hashing on plain adresses or
++ * simple integer values.
++ * passing NULL into g_hash_table_new() as GHashFunc has the
++ * same effect as passing g_direct_hash().
++ */
++guint g_direct_hash (gconstpointer v);
++gint g_direct_equal (gconstpointer v,
++ gconstpointer v2);
++
++
++
++/* Prime numbers.
++ */
++
++/* This function returns prime numbers spaced by approximately 1.5-2.0
++ * and is for use in resizing data structures which prefer
++ * prime-valued sizes. The closest spaced prime function returns the
++ * next largest prime, or the highest it knows about which is about
++ * MAXINT/4.
++ */
++guint g_spaced_primes_closest (guint num);
++
++
++
++#ifndef __KORBIT__
++/* GLib Thread support
++ */
++typedef struct _GMutex GMutex;
++typedef struct _GCond GCond;
++typedef struct _GPrivate GPrivate;
++typedef struct _GStaticPrivate GStaticPrivate;
++typedef struct _GThreadFunctions GThreadFunctions;
++struct _GThreadFunctions
++{
++ GMutex* (*mutex_new) (void);
++ void (*mutex_lock) (GMutex *mutex);
++ gboolean (*mutex_trylock) (GMutex *mutex);
++ void (*mutex_unlock) (GMutex *mutex);
++ void (*mutex_free) (GMutex *mutex);
++ GCond* (*cond_new) (void);
++ void (*cond_signal) (GCond *cond);
++ void (*cond_broadcast) (GCond *cond);
++ void (*cond_wait) (GCond *cond,
++ GMutex *mutex);
++ gboolean (*cond_timed_wait) (GCond *cond,
++ GMutex *mutex,
++ GTimeVal *end_time);
++ void (*cond_free) (GCond *cond);
++ GPrivate* (*private_new) (GDestroyNotify destructor);
++ gpointer (*private_get) (GPrivate *private_key);
++ void (*private_set) (GPrivate *private_key,
++ gpointer data);
++};
++
++GUTILS_C_VAR GThreadFunctions g_thread_functions_for_glib_use;
++GUTILS_C_VAR gboolean g_thread_use_default_impl;
++GUTILS_C_VAR gboolean g_threads_got_initialized;
++
++/* initializes the mutex/cond/private implementation for glib, might
++ * only be called once, and must not be called directly or indirectly
++ * from another glib-function, e.g. as a callback.
++ */
++void g_thread_init (GThreadFunctions *vtable);
++
++/* internal function for fallback static mutex implementation */
++GMutex* g_static_mutex_get_mutex_impl (GMutex **mutex);
++
++/* shorthands for conditional and unconditional function calls */
++#define G_THREAD_UF(name, arglist) \
++ (*g_thread_functions_for_glib_use . name) arglist
++#define G_THREAD_CF(name, fail, arg) \
++ (g_thread_supported () ? G_THREAD_UF (name, arg) : (fail))
++/* keep in mind, all those mutexes and static mutexes are not
++ * recursive in general, don't rely on that
++ */
++#define g_thread_supported() (g_threads_got_initialized)
++#define g_mutex_new() G_THREAD_UF (mutex_new, ())
++#define g_mutex_lock(mutex) G_THREAD_CF (mutex_lock, (void)0, (mutex))
++#define g_mutex_trylock(mutex) G_THREAD_CF (mutex_trylock, TRUE, (mutex))
++#define g_mutex_unlock(mutex) G_THREAD_CF (mutex_unlock, (void)0, (mutex))
++#define g_mutex_free(mutex) G_THREAD_CF (mutex_free, (void)0, (mutex))
++#define g_cond_new() G_THREAD_UF (cond_new, ())
++#define g_cond_signal(cond) G_THREAD_CF (cond_signal, (void)0, (cond))
++#define g_cond_broadcast(cond) G_THREAD_CF (cond_broadcast, (void)0, (cond))
++#define g_cond_wait(cond, mutex) G_THREAD_CF (cond_wait, (void)0, (cond, \
++ mutex))
++#define g_cond_free(cond) G_THREAD_CF (cond_free, (void)0, (cond))
++#define g_cond_timed_wait(cond, mutex, abs_time) G_THREAD_CF (cond_timed_wait, \
++ TRUE, \
++ (cond, mutex, \
++ abs_time))
++#define g_private_new(destructor) G_THREAD_UF (private_new, (destructor))
++#define g_private_get(private_key) G_THREAD_CF (private_get, \
++ ((gpointer)private_key), \
++ (private_key))
++#define g_private_set(private_key, value) G_THREAD_CF (private_set, \
++ (void) (private_key = \
++ (GPrivate*) (value)), \
++ (private_key, value))
++/* GStaticMutexes can be statically initialized with the value
++ * G_STATIC_MUTEX_INIT, and then they can directly be used, that is
++ * much easier, than having to explicitly allocate the mutex before
++ * use
++ */
++#define g_static_mutex_lock(mutex) \
++ g_mutex_lock (g_static_mutex_get_mutex (mutex))
++#define g_static_mutex_trylock(mutex) \
++ g_mutex_trylock (g_static_mutex_get_mutex (mutex))
++#define g_static_mutex_unlock(mutex) \
++ g_mutex_unlock (g_static_mutex_get_mutex (mutex))
++struct _GStaticPrivate
++{
++ guint index;
++};
++#define G_STATIC_PRIVATE_INIT { 0 }
++gpointer g_static_private_get (GStaticPrivate *private_key);
++void g_static_private_set (GStaticPrivate *private_key,
++ gpointer data,
++ GDestroyNotify notify);
++#endif /* __KORBIT__ */
++
++/* these are some convenience macros that expand to nothing if GLib
++ * was configured with --disable-threads. for using StaticMutexes,
++ * you define them with G_LOCK_DEFINE_STATIC (name) or G_LOCK_DEFINE (name)
++ * if you need to export the mutex. With G_LOCK_EXTERN (name) you can
++ * declare such an globally defined lock. name is a unique identifier
++ * for the protected varibale or code portion. locking, testing and
++ * unlocking of such mutexes can be done with G_LOCK(), G_UNLOCK() and
++ * G_TRYLOCK() respectively.
++ */
++#ifdef __KORBIT__
++#undef G_THREADS_ENABLED
++#endif
++
++extern void glib_dummy_decl (void);
++#define G_LOCK_NAME(name) (g__ ## name ## _lock)
++#ifdef G_THREADS_ENABLED
++# define G_LOCK_DEFINE_STATIC(name) static G_LOCK_DEFINE (name)
++# define G_LOCK_DEFINE(name) \
++ GStaticMutex G_LOCK_NAME (name) = G_STATIC_MUTEX_INIT
++# define G_LOCK_EXTERN(name) extern GStaticMutex G_LOCK_NAME (name)
++
++# define G_LOCK(name) g_static_mutex_lock (&G_LOCK_NAME (name))
++# define G_UNLOCK(name) g_static_mutex_unlock (&G_LOCK_NAME (name))
++# define G_TRYLOCK(name) g_static_mutex_trylock (&G_LOCK_NAME (name))
++#else /* !G_THREADS_ENABLED */
++# define G_LOCK_DEFINE_STATIC(name) extern void glib_dummy_decl (void)
++# define G_LOCK_DEFINE(name) extern void glib_dummy_decl (void)
++# define G_LOCK_EXTERN(name) extern void glib_dummy_decl (void)
++# define G_LOCK(name)
++# define G_UNLOCK(name)
++# define G_TRYLOCK(name) (FALSE)
++#endif /* !G_THREADS_ENABLED */
++
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++
++#endif /* __G_LIB_H__ */
+diff -urN linux-2.4.1/net/korbit/kglib/glibconfig.h linux-2.4.1-korbit/net/korbit/kglib/glibconfig.h
+--- linux-2.4.1/net/korbit/kglib/glibconfig.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/glibconfig.h Thu Feb 1 11:46:56 2001
+@@ -0,0 +1,131 @@
++/* glibconfig.h
++ *
++ * This is a generated file. Please modify `configure.in'
++ */
++
++#ifndef GLIBCONFIG_H
++#define GLIBCONFIG_H
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++#include <limits.h>
++/*#include <float.h>*/
++#define GLIB_HAVE_SYS_POLL_H
++
++#define G_MINFLOAT FLT_MIN
++#define G_MAXFLOAT FLT_MAX
++#define G_MINDOUBLE DBL_MIN
++#define G_MAXDOUBLE DBL_MAX
++#define G_MINSHORT SHRT_MIN
++#define G_MAXSHORT SHRT_MAX
++#define G_MININT INT_MIN
++#define G_MAXINT INT_MAX
++#define G_MINLONG LONG_MIN
++#define G_MAXLONG LONG_MAX
++
++typedef signed char gint8;
++typedef unsigned char guint8;
++typedef signed short gint16;
++typedef unsigned short guint16;
++typedef signed int gint32;
++typedef unsigned int guint32;
++
++#if defined (__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8))
++# define G_GNUC_EXTENSION __extension__
++#else
++# define G_GNUC_EXTENSION
++#endif
++
++#define G_HAVE_GINT64 1
++
++G_GNUC_EXTENSION typedef signed long long gint64;
++G_GNUC_EXTENSION typedef unsigned long long guint64;
++
++#define G_GINT64_CONSTANT(val) (G_GNUC_EXTENSION (val##LL))
++
++#define GPOINTER_TO_INT(p) ((gint) (p))
++#define GPOINTER_TO_UINT(p) ((guint) (p))
++
++#define GINT_TO_POINTER(i) ((gpointer) (i))
++#define GUINT_TO_POINTER(u) ((gpointer) (u))
++
++#ifdef NeXT /* @#%@! NeXTStep */
++# define g_ATEXIT(proc) (!atexit (proc))
++#else
++# define g_ATEXIT(proc) (atexit (proc))
++#endif
++
++#define g_memmove(d,s,n) G_STMT_START { memmove ((d), (s), (n)); } G_STMT_END
++
++#define GLIB_MAJOR_VERSION 1
++#define GLIB_MINOR_VERSION 2
++#define GLIB_MICRO_VERSION 8
++
++
++#define G_VA_COPY __va_copy
++
++#ifdef __cplusplus
++#define G_HAVE_INLINE 1
++#else /* !__cplusplus */
++#define G_HAVE_INLINE 1
++#define G_HAVE___INLINE 1
++#define G_HAVE___INLINE__ 1
++#endif /* !__cplusplus */
++
++#define G_THREADS_ENABLED
++#define G_THREADS_IMPL_POSIX
++typedef struct _GStaticMutex GStaticMutex;
++struct _GStaticMutex
++{
++ struct _GMutex *runtime_mutex;
++ union {
++ char pad[24];
++ double dummy_double;
++ void *dummy_pointer;
++ long dummy_long;
++ } aligned_pad_u;
++};
++#define G_STATIC_MUTEX_INIT { NULL, { { 0,0,0,0,0,0,77,88,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} } }
++#define g_static_mutex_get_mutex(mutex) (g_thread_use_default_impl ? ((GMutex*) &((mutex)->aligned_pad_u)) : g_static_mutex_get_mutex_impl (&((mutex)->runtime_mutex)))
++
++#define GINT16_TO_BE(val) ((gint16) (val))
++#define GUINT16_TO_BE(val) ((guint16) (val))
++#define GINT16_TO_LE(val) ((gint16) GUINT16_SWAP_LE_BE (val))
++#define GUINT16_TO_LE(val) (GUINT16_SWAP_LE_BE (val))
++#define GINT32_TO_BE(val) ((gint32) (val))
++#define GUINT32_TO_BE(val) ((guint32) (val))
++#define GINT32_TO_LE(val) ((gint32) GUINT32_SWAP_LE_BE (val))
++#define GUINT32_TO_LE(val) (GUINT32_SWAP_LE_BE (val))
++#define GINT64_TO_BE(val) ((gint64) (val))
++#define GUINT64_TO_BE(val) ((guint64) (val))
++#define GINT64_TO_LE(val) ((gint64) GUINT64_SWAP_LE_BE (val))
++#define GUINT64_TO_LE(val) (GUINT64_SWAP_LE_BE (val))
++#define GLONG_TO_LE(val) ((glong) GINT32_TO_LE (val))
++#define GULONG_TO_LE(val) ((gulong) GUINT32_TO_LE (val))
++#define GLONG_TO_BE(val) ((glong) GINT32_TO_BE (val))
++#define GULONG_TO_BE(val) ((gulong) GUINT32_TO_BE (val))
++#define GINT_TO_LE(val) ((gint) GINT32_TO_LE (val))
++#define GUINT_TO_LE(val) ((guint) GUINT32_TO_LE (val))
++#define GINT_TO_BE(val) ((gint) GINT32_TO_BE (val))
++#define GUINT_TO_BE(val) ((guint) GUINT32_TO_BE (val))
++#define G_BYTE_ORDER G_LITTLE_ENDIAN
++
++#define GLIB_SYSDEF_POLLIN =1
++#define GLIB_SYSDEF_POLLOUT =4
++#define GLIB_SYSDEF_POLLPRI =2
++#define GLIB_SYSDEF_POLLERR =8
++#define GLIB_SYSDEF_POLLHUP =16
++#define GLIB_SYSDEF_POLLNVAL =32
++
++
++#define G_HAVE_WCHAR_H 1
++#define G_HAVE_WCTYPE_H 1
++
++
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif /* GLIBCONFIG_H */
+diff -urN linux-2.4.1/net/korbit/kglib/glist.c linux-2.4.1-korbit/net/korbit/kglib/glist.c
+--- linux-2.4.1/net/korbit/kglib/glist.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/glist.c Thu Feb 1 11:46:57 2001
+@@ -0,0 +1,666 @@
++/* GLIB - Library of useful routines for C programming
++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
++ *
++ * 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.
++ */
++
++/*
++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS
++ * file for a list of people on the GLib Team. See the ChangeLog
++ * files for a list of changes. These files are distributed with
++ * GLib at ftp://ftp.gtk.org/pub/gtk/.
++ */
++
++#include "glib.h"
++
++
++struct _GAllocator /* from gmem.c */
++{
++ gchar *name;
++ guint16 n_preallocs;
++ guint is_unused : 1;
++ guint type : 4;
++ GAllocator *last;
++ GMemChunk *mem_chunk;
++ GList *free_lists; /* implementation specific */
++};
++
++static GAllocator *current_allocator = NULL;
++G_LOCK_DEFINE_STATIC (current_allocator);
++
++/* HOLDS: current_allocator_lock */
++static void
++g_list_validate_allocator (GAllocator *allocator)
++{
++ g_return_if_fail (allocator != NULL);
++ g_return_if_fail (allocator->is_unused == TRUE);
++
++ if (allocator->type != G_ALLOCATOR_LIST)
++ {
++ allocator->type = G_ALLOCATOR_LIST;
++ if (allocator->mem_chunk)
++ {
++ g_mem_chunk_destroy (allocator->mem_chunk);
++ allocator->mem_chunk = NULL;
++ }
++ }
++
++ if (!allocator->mem_chunk)
++ {
++ allocator->mem_chunk = g_mem_chunk_new (allocator->name,
++ sizeof (GList),
++ sizeof (GList) * allocator->n_preallocs,
++ G_ALLOC_ONLY);
++ allocator->free_lists = NULL;
++ }
++
++ allocator->is_unused = FALSE;
++}
++
++void
++g_list_push_allocator(GAllocator *allocator)
++{
++ G_LOCK (current_allocator);
++ g_list_validate_allocator ( allocator );
++ allocator->last = current_allocator;
++ current_allocator = allocator;
++ G_UNLOCK (current_allocator);
++}
++
++void
++g_list_pop_allocator (void)
++{
++ G_LOCK (current_allocator);
++ if (current_allocator)
++ {
++ GAllocator *allocator;
++
++ allocator = current_allocator;
++ current_allocator = allocator->last;
++ allocator->last = NULL;
++ allocator->is_unused = TRUE;
++ }
++ G_UNLOCK (current_allocator);
++}
++
++GList*
++g_list_alloc (void)
++{
++ GList *list;
++
++ G_LOCK (current_allocator);
++ if (!current_allocator)
++ {
++ GAllocator *allocator = g_allocator_new ("GLib default GList allocator",
++ 128);
++ g_list_validate_allocator (allocator);
++ allocator->last = NULL;
++ current_allocator = allocator;
++ }
++ if (!current_allocator->free_lists)
++ {
++ list = g_chunk_new (GList, current_allocator->mem_chunk);
++ list->data = NULL;
++ }
++ else
++ {
++ if (current_allocator->free_lists->data)
++ {
++ list = current_allocator->free_lists->data;
++ current_allocator->free_lists->data = list->next;
++ list->data = NULL;
++ }
++ else
++ {
++ list = current_allocator->free_lists;
++ current_allocator->free_lists = list->next;
++ }
++ }
++ G_UNLOCK (current_allocator);
++ list->next = NULL;
++ list->prev = NULL;
++
++ return list;
++}
++
++void
++g_list_free (GList *list)
++{
++ if (list)
++ {
++ list->data = list->next;
++ G_LOCK (current_allocator);
++ list->next = current_allocator->free_lists;
++ current_allocator->free_lists = list;
++ G_UNLOCK (current_allocator);
++ }
++}
++
++void
++g_list_free_1 (GList *list)
++{
++ if (list)
++ {
++ list->data = NULL;
++ G_LOCK (current_allocator);
++ list->next = current_allocator->free_lists;
++ current_allocator->free_lists = list;
++ G_UNLOCK (current_allocator);
++ }
++}
++
++GList*
++g_list_append (GList *list,
++ gpointer data)
++{
++ GList *new_list;
++ GList *last;
++
++ new_list = g_list_alloc ();
++ new_list->data = data;
++
++ if (list)
++ {
++ last = g_list_last (list);
++ /* g_assert (last != NULL); */
++ last->next = new_list;
++ new_list->prev = last;
++
++ return list;
++ }
++ else
++ return new_list;
++}
++
++GList*
++g_list_prepend (GList *list,
++ gpointer data)
++{
++ GList *new_list;
++
++ new_list = g_list_alloc ();
++ new_list->data = data;
++
++ if (list)
++ {
++ if (list->prev)
++ {
++ list->prev->next = new_list;
++ new_list->prev = list->prev;
++ }
++ list->prev = new_list;
++ new_list->next = list;
++ }
++
++ return new_list;
++}
++
++GList*
++g_list_insert (GList *list,
++ gpointer data,
++ gint position)
++{
++ GList *new_list;
++ GList *tmp_list;
++
++ if (position < 0)
++ return g_list_append (list, data);
++ else if (position == 0)
++ return g_list_prepend (list, data);
++
++ tmp_list = g_list_nth (list, position);
++ if (!tmp_list)
++ return g_list_append (list, data);
++
++ new_list = g_list_alloc ();
++ new_list->data = data;
++
++ if (tmp_list->prev)
++ {
++ tmp_list->prev->next = new_list;
++ new_list->prev = tmp_list->prev;
++ }
++ new_list->next = tmp_list;
++ tmp_list->prev = new_list;
++
++ if (tmp_list == list)
++ return new_list;
++ else
++ return list;
++}
++
++GList *
++g_list_concat (GList *list1, GList *list2)
++{
++ GList *tmp_list;
++
++ if (list2)
++ {
++ tmp_list = g_list_last (list1);
++ if (tmp_list)
++ tmp_list->next = list2;
++ else
++ list1 = list2;
++ list2->prev = tmp_list;
++ }
++
++ return list1;
++}
++
++GList*
++g_list_remove (GList *list,
++ gpointer data)
++{
++ GList *tmp;
++
++ tmp = list;
++ while (tmp)
++ {
++ if (tmp->data != data)
++ tmp = tmp->next;
++ else
++ {
++ if (tmp->prev)
++ tmp->prev->next = tmp->next;
++ if (tmp->next)
++ tmp->next->prev = tmp->prev;
++
++ if (list == tmp)
++ list = list->next;
++
++ g_list_free_1 (tmp);
++
++ break;
++ }
++ }
++ return list;
++}
++
++GList*
++g_list_remove_link (GList *list,
++ GList *link)
++{
++ if (link)
++ {
++ if (link->prev)
++ link->prev->next = link->next;
++ if (link->next)
++ link->next->prev = link->prev;
++
++ if (link == list)
++ list = list->next;
++
++ link->next = NULL;
++ link->prev = NULL;
++ }
++
++ return list;
++}
++
++GList*
++g_list_copy (GList *list)
++{
++ GList *new_list = NULL;
++
++ if (list)
++ {
++ GList *last;
++
++ new_list = g_list_alloc ();
++ new_list->data = list->data;
++ last = new_list;
++ list = list->next;
++ while (list)
++ {
++ last->next = g_list_alloc ();
++ last->next->prev = last;
++ last = last->next;
++ last->data = list->data;
++ list = list->next;
++ }
++ }
++
++ return new_list;
++}
++
++GList*
++g_list_reverse (GList *list)
++{
++ GList *last;
++
++ last = NULL;
++ while (list)
++ {
++ last = list;
++ list = last->next;
++ last->next = last->prev;
++ last->prev = list;
++ }
++
++ return last;
++}
++
++GList*
++g_list_nth (GList *list,
++ guint n)
++{
++ while ((n-- > 0) && list)
++ list = list->next;
++
++ return list;
++}
++
++gpointer
++g_list_nth_data (GList *list,
++ guint n)
++{
++ while ((n-- > 0) && list)
++ list = list->next;
++
++ return list ? list->data : NULL;
++}
++
++GList*
++g_list_find (GList *list,
++ gpointer data)
++{
++ while (list)
++ {
++ if (list->data == data)
++ break;
++ list = list->next;
++ }
++
++ return list;
++}
++
++GList*
++g_list_find_custom (GList *list,
++ gpointer data,
++ GCompareFunc func)
++{
++ g_return_val_if_fail (func != NULL, list);
++
++ while (list)
++ {
++ if (! func (list->data, data))
++ return list;
++ list = list->next;
++ }
++
++ return NULL;
++}
++
++
++gint
++g_list_position (GList *list,
++ GList *link)
++{
++ gint i;
++
++ i = 0;
++ while (list)
++ {
++ if (list == link)
++ return i;
++ i++;
++ list = list->next;
++ }
++
++ return -1;
++}
++
++gint
++g_list_index (GList *list,
++ gpointer data)
++{
++ gint i;
++
++ i = 0;
++ while (list)
++ {
++ if (list->data == data)
++ return i;
++ i++;
++ list = list->next;
++ }
++
++ return -1;
++}
++
++GList*
++g_list_last (GList *list)
++{
++ if (list)
++ {
++ while (list->next)
++ list = list->next;
++ }
++
++ return list;
++}
++
++GList*
++g_list_first (GList *list)
++{
++ if (list)
++ {
++ while (list->prev)
++ list = list->prev;
++ }
++
++ return list;
++}
++
++guint
++g_list_length (GList *list)
++{
++ guint length;
++
++ length = 0;
++ while (list)
++ {
++ length++;
++ list = list->next;
++ }
++
++ return length;
++}
++
++void
++g_list_foreach (GList *list,
++ GFunc func,
++ gpointer user_data)
++{
++ while (list)
++ {
++ (*func) (list->data, user_data);
++ list = list->next;
++ }
++}
++
++
++GList*
++g_list_insert_sorted (GList *list,
++ gpointer data,
++ GCompareFunc func)
++{
++ GList *tmp_list = list;
++ GList *new_list;
++ gint cmp;
++
++ g_return_val_if_fail (func != NULL, list);
++
++ if (!list)
++ {
++ new_list = g_list_alloc();
++ new_list->data = data;
++ return new_list;
++ }
++
++ cmp = (*func) (data, tmp_list->data);
++
++ while ((tmp_list->next) && (cmp > 0))
++ {
++ tmp_list = tmp_list->next;
++ cmp = (*func) (data, tmp_list->data);
++ }
++
++ new_list = g_list_alloc();
++ new_list->data = data;
++
++ if ((!tmp_list->next) && (cmp > 0))
++ {
++ tmp_list->next = new_list;
++ new_list->prev = tmp_list;
++ return list;
++ }
++
++ if (tmp_list->prev)
++ {
++ tmp_list->prev->next = new_list;
++ new_list->prev = tmp_list->prev;
++ }
++ new_list->next = tmp_list;
++ tmp_list->prev = new_list;
++
++ if (tmp_list == list)
++ return new_list;
++ else
++ return list;
++}
++
++static GList *
++g_list_sort_merge (GList *l1,
++ GList *l2,
++ GCompareFunc compare_func)
++{
++ GList list, *l, *lprev;
++
++ l = &list;
++ lprev = NULL;
++
++ while (l1 && l2)
++ {
++ if (compare_func (l1->data, l2->data) < 0)
++ {
++ l->next = l1;
++ l = l->next;
++ l->prev = lprev;
++ lprev = l;
++ l1 = l1->next;
++ }
++ else
++ {
++ l->next = l2;
++ l = l->next;
++ l->prev = lprev;
++ lprev = l;
++ l2 = l2->next;
++ }
++ }
++ l->next = l1 ? l1 : l2;
++ l->next->prev = l;
++
++ return list.next;
++}
++
++GList*
++g_list_sort (GList *list,
++ GCompareFunc compare_func)
++{
++ GList *l1, *l2;
++
++ if (!list)
++ return NULL;
++ if (!list->next)
++ return list;
++
++ l1 = list;
++ l2 = list->next;
++
++ while ((l2 = l2->next) != NULL)
++ {
++ if ((l2 = l2->next) == NULL)
++ break;
++ l1 = l1->next;
++ }
++ l2 = l1->next;
++ l1->next = NULL;
++
++ return g_list_sort_merge (g_list_sort (list, compare_func),
++ g_list_sort (l2, compare_func),
++ compare_func);
++}
++
++GList*
++g_list_sort2 (GList *list,
++ GCompareFunc compare_func)
++{
++ GSList *runs = NULL;
++ GList *tmp;
++
++ /* Degenerate case. */
++ if (!list) return NULL;
++
++ /* Assume: list = [12,2,4,11,2,4,6,1,1,12]. */
++ for (tmp = list; tmp; )
++ {
++ GList *tmp2;
++ for (tmp2 = tmp;
++ tmp2->next && compare_func (tmp2->data, tmp2->next->data) <= 0;
++ tmp2 = tmp2->next)
++ /* Nothing */;
++ runs = g_slist_append (runs, tmp);
++ tmp = tmp2->next;
++ tmp2->next = NULL;
++ }
++ /* Now: runs = [[12],[2,4,11],[2,4,6],[1,1,12]]. */
++
++ while (runs->next)
++ {
++ /* We have more than one run. Merge pairwise. */
++ GSList *dst, *src, *dstprev = NULL;
++ dst = src = runs;
++ while (src && src->next)
++ {
++ dst->data = g_list_sort_merge (src->data,
++ src->next->data,
++ compare_func);
++ dstprev = dst;
++ dst = dst->next;
++ src = src->next->next;
++ }
++
++ /* If number of runs was odd, just keep the last. */
++ if (src)
++ {
++ dst->data = src->data;
++ dstprev = dst;
++ dst = dst->next;
++ }
++
++ dstprev->next = NULL;
++ g_slist_free (dst);
++ }
++
++ /* After 1st loop: runs = [[2,4,11,12],[1,1,2,4,6,12]]. */
++ /* After 2nd loop: runs = [[1,1,2,2,4,4,6,11,12,12]]. */
++
++ list = runs->data;
++ g_slist_free (runs);
++ return list;
++}
+diff -urN linux-2.4.1/net/korbit/kglib/gmem.c linux-2.4.1-korbit/net/korbit/kglib/gmem.c
+--- linux-2.4.1/net/korbit/kglib/gmem.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/gmem.c Thu Feb 1 11:46:57 2001
+@@ -0,0 +1,767 @@
++/* GLIB - Library of useful routines for C programming
++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
++ *
++ * 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.
++ */
++
++/*
++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS
++ * file for a list of people on the GLib Team. See the ChangeLog
++ * files for a list of changes. These files are distributed with
++ * GLib at ftp://ftp.gtk.org/pub/gtk/.
++ *
++ * Mutilated on 10/22/00 by Fredrik and Chris
++ */
++
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
++#include <stdlib.h>
++#include <string.h>
++#include "glib.h"
++
++#define MEM_PROFILE_TABLE_SIZE 8192
++#define ENTER_MEM_CHUNK_ROUTINE()
++#define LEAVE_MEM_CHUNK_ROUTINE()
++
++/*
++ * This library can check for some attempts to do illegal things to
++ * memory (ENABLE_MEM_CHECK), and can do profiling
++ * (ENABLE_MEM_PROFILE). Both features are implemented by storing
++ * words before the start of the memory chunk.
++ *
++ * The first, at offset -2*SIZEOF_LONG, is used only if
++ * ENABLE_MEM_CHECK is set, and stores 0 after the memory has been
++ * allocated and 1 when it has been freed. The second, at offset
++ * -SIZEOF_LONG, is used if either flag is set and stores the size of
++ * the block.
++ *
++ * The MEM_CHECK flag is checked when memory is realloc'd and free'd,
++ * and it can be explicitly checked before using a block by calling
++ * g_mem_check().
++ */
++
++#define MEM_AREA_SIZE 4L
++
++#define MEM_ALIGN sizeof(long)
++
++
++typedef struct _GFreeAtom GFreeAtom;
++typedef struct _GMemArea GMemArea;
++typedef struct _GRealMemChunk GRealMemChunk;
++
++struct _GFreeAtom
++{
++ GFreeAtom *next;
++};
++
++struct _GMemArea
++{
++ GMemArea *next; /* the next mem area */
++ GMemArea *prev; /* the previous mem area */
++ gulong index; /* the current index into the "mem" array */
++ gulong free; /* the number of free bytes in this mem area */
++ gulong allocated; /* the number of atoms allocated from this area */
++ gulong mark; /* is this mem area marked for deletion */
++ gchar mem[MEM_AREA_SIZE]; /* the mem array from which atoms get allocated
++ * the actual size of this array is determined by
++ * the mem chunk "area_size". ANSI says that it
++ * must be declared to be the maximum size it
++ * can possibly be (even though the actual size
++ * may be less).
++ */
++};
++
++struct _GRealMemChunk
++{
++ gchar *name; /* name of this MemChunk...used for debugging output */
++ gint type; /* the type of MemChunk: ALLOC_ONLY or ALLOC_AND_FREE */
++ gint num_mem_areas; /* the number of memory areas */
++ gint num_marked_areas; /* the number of areas marked for deletion */
++ guint atom_size; /* the size of an atom */
++ gulong area_size; /* the size of a memory area */
++ GMemArea *mem_area; /* the current memory area */
++ GMemArea *mem_areas; /* a list of all the mem areas owned by this chunk */
++ GMemArea *free_mem_area; /* the free area...which is about to be destroyed */
++ GFreeAtom *free_atoms; /* the free atoms list */
++ GTree *mem_tree; /* tree of mem areas sorted by memory address */
++ GRealMemChunk *next; /* pointer to the next chunk */
++ GRealMemChunk *prev; /* pointer to the previous chunk */
++};
++
++
++static gulong g_mem_chunk_compute_size (gulong size,
++ gulong min_size);
++static gint g_mem_chunk_area_compare (GMemArea *a,
++ GMemArea *b);
++static gint g_mem_chunk_area_search (GMemArea *a,
++ gchar *addr);
++
++
++/* here we can't use StaticMutexes, as they depend upon a working
++ * g_malloc, the same holds true for StaticPrivate */
++#ifndef __KORBIT__
++static GMutex* mem_chunks_lock = NULL;
++#endif /* !__KORBIT__ */
++static GRealMemChunk *mem_chunks = NULL;
++
++
++gpointer
++g_malloc (gulong size)
++{
++ gpointer p;
++
++ if (size == 0)
++ return NULL;
++
++ p = (gpointer) malloc (size);
++ if (!p)
++ g_error ("could not allocate %ld bytes", size);
++
++ return p;
++}
++
++gpointer
++g_malloc0 (gulong size)
++{
++ gpointer p;
++
++ if (size == 0)
++ return NULL;
++
++ p = (gpointer) calloc (size, 1);
++ if (!p)
++ g_error ("could not allocate %ld bytes", size);
++
++ return p;
++}
++
++gpointer
++g_realloc (gpointer mem,
++ gulong size)
++{
++ gpointer p;
++
++ if (size == 0)
++ {
++ g_free (mem);
++
++ return NULL;
++ }
++
++ if (!mem)
++ {
++#ifdef REALLOC_0_WORKS
++ p = (gpointer) realloc (NULL, size);
++#else /* !REALLOC_0_WORKS */
++ p = (gpointer) malloc (size);
++#endif /* !REALLOC_0_WORKS */
++ }
++ else
++ {
++ p = (gpointer) realloc (mem, size);
++ }
++
++ if (!p)
++ g_error ("could not reallocate %lu bytes", (gulong) size);
++
++ return p;
++}
++
++void
++g_free (gpointer mem)
++{
++ if (mem)
++ {
++ free (mem);
++ }
++}
++
++
++void
++g_mem_profile (void)
++{
++}
++
++void
++g_mem_check (gpointer mem)
++{
++}
++
++GMemChunk*
++g_mem_chunk_new (gchar *name,
++ gint atom_size,
++ gulong area_size,
++ gint type)
++{
++ GRealMemChunk *mem_chunk;
++ gulong rarea_size;
++
++ g_return_val_if_fail (atom_size > 0, NULL);
++ g_return_val_if_fail (area_size >= atom_size, NULL);
++
++ ENTER_MEM_CHUNK_ROUTINE();
++
++ area_size = (area_size + atom_size - 1) / atom_size;
++ area_size *= atom_size;
++
++ mem_chunk = g_new (struct _GRealMemChunk, 1);
++ mem_chunk->name = name;
++ mem_chunk->type = type;
++ mem_chunk->num_mem_areas = 0;
++ mem_chunk->num_marked_areas = 0;
++ mem_chunk->mem_area = NULL;
++ mem_chunk->free_mem_area = NULL;
++ mem_chunk->free_atoms = NULL;
++ mem_chunk->mem_tree = NULL;
++ mem_chunk->mem_areas = NULL;
++ mem_chunk->atom_size = atom_size;
++
++ if (mem_chunk->type == G_ALLOC_AND_FREE)
++ mem_chunk->mem_tree = g_tree_new ((GCompareFunc) g_mem_chunk_area_compare);
++
++ if (mem_chunk->atom_size % MEM_ALIGN)
++ mem_chunk->atom_size += MEM_ALIGN - (mem_chunk->atom_size % MEM_ALIGN);
++
++ rarea_size = area_size + sizeof (GMemArea) - MEM_AREA_SIZE;
++ rarea_size = g_mem_chunk_compute_size (rarea_size, atom_size + sizeof (GMemArea) - MEM_AREA_SIZE);
++ mem_chunk->area_size = rarea_size - (sizeof (GMemArea) - MEM_AREA_SIZE);
++
++#ifndef __KORBIT__
++ g_mutex_lock (mem_chunks_lock);
++#endif /* !__KORBIT__ */
++ mem_chunk->next = mem_chunks;
++ mem_chunk->prev = NULL;
++ if (mem_chunks)
++ mem_chunks->prev = mem_chunk;
++ mem_chunks = mem_chunk;
++#ifndef __KORBIT__
++ g_mutex_unlock (mem_chunks_lock);
++#endif /* !__KORBIT__ */
++
++ LEAVE_MEM_CHUNK_ROUTINE();
++
++ return ((GMemChunk*) mem_chunk);
++}
++
++void
++g_mem_chunk_destroy (GMemChunk *mem_chunk)
++{
++ GRealMemChunk *rmem_chunk;
++ GMemArea *mem_areas;
++ GMemArea *temp_area;
++
++ g_return_if_fail (mem_chunk != NULL);
++
++ ENTER_MEM_CHUNK_ROUTINE();
++
++ rmem_chunk = (GRealMemChunk*) mem_chunk;
++
++ mem_areas = rmem_chunk->mem_areas;
++ while (mem_areas)
++ {
++ temp_area = mem_areas;
++ mem_areas = mem_areas->next;
++ g_free (temp_area);
++ }
++
++ if (rmem_chunk->next)
++ rmem_chunk->next->prev = rmem_chunk->prev;
++ if (rmem_chunk->prev)
++ rmem_chunk->prev->next = rmem_chunk->next;
++
++#ifndef __KORBIT__
++ g_mutex_lock (mem_chunks_lock);
++#endif /* !__KORBIT__ */
++ if (rmem_chunk == mem_chunks)
++ mem_chunks = mem_chunks->next;
++#ifndef __KORBIT__
++ g_mutex_unlock (mem_chunks_lock);
++#endif /* !__KORBIT__ */
++
++ if (rmem_chunk->type == G_ALLOC_AND_FREE)
++ g_tree_destroy (rmem_chunk->mem_tree);
++
++ g_free (rmem_chunk);
++
++ LEAVE_MEM_CHUNK_ROUTINE();
++}
++
++gpointer
++g_mem_chunk_alloc (GMemChunk *mem_chunk)
++{
++ GRealMemChunk *rmem_chunk;
++ GMemArea *temp_area;
++ gpointer mem;
++
++ ENTER_MEM_CHUNK_ROUTINE();
++
++ g_return_val_if_fail (mem_chunk != NULL, NULL);
++
++ rmem_chunk = (GRealMemChunk*) mem_chunk;
++
++ while (rmem_chunk->free_atoms)
++ {
++ /* Get the first piece of memory on the "free_atoms" list.
++ * We can go ahead and destroy the list node we used to keep
++ * track of it with and to update the "free_atoms" list to
++ * point to its next element.
++ */
++ mem = rmem_chunk->free_atoms;
++ rmem_chunk->free_atoms = rmem_chunk->free_atoms->next;
++
++ /* Determine which area this piece of memory is allocated from */
++ temp_area = g_tree_search (rmem_chunk->mem_tree,
++ (GSearchFunc) g_mem_chunk_area_search,
++ mem);
++
++ /* If the area has been marked, then it is being destroyed.
++ * (ie marked to be destroyed).
++ * We check to see if all of the segments on the free list that
++ * reference this area have been removed. This occurs when
++ * the ammount of free memory is less than the allocatable size.
++ * If the chunk should be freed, then we place it in the "free_mem_area".
++ * This is so we make sure not to free the mem area here and then
++ * allocate it again a few lines down.
++ * If we don't allocate a chunk a few lines down then the "free_mem_area"
++ * will be freed.
++ * If there is already a "free_mem_area" then we'll just free this mem area.
++ */
++ if (temp_area->mark)
++ {
++ /* Update the "free" memory available in that area */
++ temp_area->free += rmem_chunk->atom_size;
++
++ if (temp_area->free == rmem_chunk->area_size)
++ {
++ if (temp_area == rmem_chunk->mem_area)
++ rmem_chunk->mem_area = NULL;
++
++ if (rmem_chunk->free_mem_area)
++ {
++ rmem_chunk->num_mem_areas -= 1;
++
++ if (temp_area->next)
++ temp_area->next->prev = temp_area->prev;
++ if (temp_area->prev)
++ temp_area->prev->next = temp_area->next;
++ if (temp_area == rmem_chunk->mem_areas)
++ rmem_chunk->mem_areas = rmem_chunk->mem_areas->next;
++
++ if (rmem_chunk->type == G_ALLOC_AND_FREE)
++ g_tree_remove (rmem_chunk->mem_tree, temp_area);
++ g_free (temp_area);
++ }
++ else
++ rmem_chunk->free_mem_area = temp_area;
++
++ rmem_chunk->num_marked_areas -= 1;
++ }
++ }
++ else
++ {
++ /* Update the number of allocated atoms count.
++ */
++ temp_area->allocated += 1;
++
++ /* The area wasn't marked...return the memory
++ */
++ goto outa_here;
++ }
++ }
++
++ /* If there isn't a current mem area or the current mem area is out of space
++ * then allocate a new mem area. We'll first check and see if we can use
++ * the "free_mem_area". Otherwise we'll just malloc the mem area.
++ */
++ if ((!rmem_chunk->mem_area) ||
++ ((rmem_chunk->mem_area->index + rmem_chunk->atom_size) > rmem_chunk->area_size))
++ {
++ if (rmem_chunk->free_mem_area)
++ {
++ rmem_chunk->mem_area = rmem_chunk->free_mem_area;
++ rmem_chunk->free_mem_area = NULL;
++ }
++ else
++ {
++ rmem_chunk->mem_area = (GMemArea*) g_malloc (sizeof (GMemArea) -
++ MEM_AREA_SIZE +
++ rmem_chunk->area_size);
++
++ rmem_chunk->num_mem_areas += 1;
++ rmem_chunk->mem_area->next = rmem_chunk->mem_areas;
++ rmem_chunk->mem_area->prev = NULL;
++
++ if (rmem_chunk->mem_areas)
++ rmem_chunk->mem_areas->prev = rmem_chunk->mem_area;
++ rmem_chunk->mem_areas = rmem_chunk->mem_area;
++
++ if (rmem_chunk->type == G_ALLOC_AND_FREE)
++ g_tree_insert (rmem_chunk->mem_tree, rmem_chunk->mem_area, rmem_chunk->mem_area);
++ }
++
++ rmem_chunk->mem_area->index = 0;
++ rmem_chunk->mem_area->free = rmem_chunk->area_size;
++ rmem_chunk->mem_area->allocated = 0;
++ rmem_chunk->mem_area->mark = 0;
++ }
++
++ /* Get the memory and modify the state variables appropriately.
++ */
++ mem = (gpointer) &rmem_chunk->mem_area->mem[rmem_chunk->mem_area->index];
++ rmem_chunk->mem_area->index += rmem_chunk->atom_size;
++ rmem_chunk->mem_area->free -= rmem_chunk->atom_size;
++ rmem_chunk->mem_area->allocated += 1;
++
++outa_here:
++
++ LEAVE_MEM_CHUNK_ROUTINE();
++
++ return mem;
++}
++
++gpointer
++g_mem_chunk_alloc0 (GMemChunk *mem_chunk)
++{
++ gpointer mem;
++
++ mem = g_mem_chunk_alloc (mem_chunk);
++ if (mem)
++ {
++ GRealMemChunk *rmem_chunk = (GRealMemChunk*) mem_chunk;
++
++ memset (mem, 0, rmem_chunk->atom_size);
++ }
++
++ return mem;
++}
++
++void
++g_mem_chunk_free (GMemChunk *mem_chunk,
++ gpointer mem)
++{
++ GRealMemChunk *rmem_chunk;
++ GMemArea *temp_area;
++ GFreeAtom *free_atom;
++
++ g_return_if_fail (mem_chunk != NULL);
++ g_return_if_fail (mem != NULL);
++
++ ENTER_MEM_CHUNK_ROUTINE();
++
++ rmem_chunk = (GRealMemChunk*) mem_chunk;
++
++ /* Don't do anything if this is an ALLOC_ONLY chunk
++ */
++ if (rmem_chunk->type == G_ALLOC_AND_FREE)
++ {
++ /* Place the memory on the "free_atoms" list
++ */
++ free_atom = (GFreeAtom*) mem;
++ free_atom->next = rmem_chunk->free_atoms;
++ rmem_chunk->free_atoms = free_atom;
++
++ temp_area = g_tree_search (rmem_chunk->mem_tree,
++ (GSearchFunc) g_mem_chunk_area_search,
++ mem);
++
++ temp_area->allocated -= 1;
++
++ if (temp_area->allocated == 0)
++ {
++ temp_area->mark = 1;
++ rmem_chunk->num_marked_areas += 1;
++ }
++ }
++
++ LEAVE_MEM_CHUNK_ROUTINE();
++}
++
++/* This doesn't free the free_area if there is one */
++void
++g_mem_chunk_clean (GMemChunk *mem_chunk)
++{
++ GRealMemChunk *rmem_chunk;
++ GMemArea *mem_area;
++ GFreeAtom *prev_free_atom;
++ GFreeAtom *temp_free_atom;
++ gpointer mem;
++
++ g_return_if_fail (mem_chunk != NULL);
++
++ rmem_chunk = (GRealMemChunk*) mem_chunk;
++
++ if (rmem_chunk->type == G_ALLOC_AND_FREE)
++ {
++ prev_free_atom = NULL;
++ temp_free_atom = rmem_chunk->free_atoms;
++
++ while (temp_free_atom)
++ {
++ mem = (gpointer) temp_free_atom;
++
++ mem_area = g_tree_search (rmem_chunk->mem_tree,
++ (GSearchFunc) g_mem_chunk_area_search,
++ mem);
++
++ /* If this mem area is marked for destruction then delete the
++ * area and list node and decrement the free mem.
++ */
++ if (mem_area->mark)
++ {
++ if (prev_free_atom)
++ prev_free_atom->next = temp_free_atom->next;
++ else
++ rmem_chunk->free_atoms = temp_free_atom->next;
++ temp_free_atom = temp_free_atom->next;
++
++ mem_area->free += rmem_chunk->atom_size;
++ if (mem_area->free == rmem_chunk->area_size)
++ {
++ rmem_chunk->num_mem_areas -= 1;
++ rmem_chunk->num_marked_areas -= 1;
++
++ if (mem_area->next)
++ mem_area->next->prev = mem_area->prev;
++ if (mem_area->prev)
++ mem_area->prev->next = mem_area->next;
++ if (mem_area == rmem_chunk->mem_areas)
++ rmem_chunk->mem_areas = rmem_chunk->mem_areas->next;
++ if (mem_area == rmem_chunk->mem_area)
++ rmem_chunk->mem_area = NULL;
++
++ if (rmem_chunk->type == G_ALLOC_AND_FREE)
++ g_tree_remove (rmem_chunk->mem_tree, mem_area);
++ g_free (mem_area);
++ }
++ }
++ else
++ {
++ prev_free_atom = temp_free_atom;
++ temp_free_atom = temp_free_atom->next;
++ }
++ }
++ }
++}
++
++void
++g_mem_chunk_reset (GMemChunk *mem_chunk)
++{
++ GRealMemChunk *rmem_chunk;
++ GMemArea *mem_areas;
++ GMemArea *temp_area;
++
++ g_return_if_fail (mem_chunk != NULL);
++
++ rmem_chunk = (GRealMemChunk*) mem_chunk;
++
++ mem_areas = rmem_chunk->mem_areas;
++ rmem_chunk->num_mem_areas = 0;
++ rmem_chunk->mem_areas = NULL;
++ rmem_chunk->mem_area = NULL;
++
++ while (mem_areas)
++ {
++ temp_area = mem_areas;
++ mem_areas = mem_areas->next;
++ g_free (temp_area);
++ }
++
++ rmem_chunk->free_atoms = NULL;
++
++ if (rmem_chunk->mem_tree)
++ g_tree_destroy (rmem_chunk->mem_tree);
++ rmem_chunk->mem_tree = g_tree_new ((GCompareFunc) g_mem_chunk_area_compare);
++}
++
++void
++g_mem_chunk_print (GMemChunk *mem_chunk)
++{
++ GRealMemChunk *rmem_chunk;
++ GMemArea *mem_areas;
++ gulong mem;
++
++ g_return_if_fail (mem_chunk != NULL);
++
++ rmem_chunk = (GRealMemChunk*) mem_chunk;
++ mem_areas = rmem_chunk->mem_areas;
++ mem = 0;
++
++ while (mem_areas)
++ {
++ mem += rmem_chunk->area_size - mem_areas->free;
++ mem_areas = mem_areas->next;
++ }
++
++ g_log (g_log_domain_glib, G_LOG_LEVEL_INFO,
++ "%s: %ld bytes using %d mem areas",
++ rmem_chunk->name, mem, rmem_chunk->num_mem_areas);
++}
++
++void
++g_mem_chunk_info (void)
++{
++ GRealMemChunk *mem_chunk;
++ gint count;
++
++ count = 0;
++#ifndef __KORBIT__
++ g_mutex_lock (mem_chunks_lock);
++#endif /* !__KORBIT__ */
++ mem_chunk = mem_chunks;
++ while (mem_chunk)
++ {
++ count += 1;
++ mem_chunk = mem_chunk->next;
++ }
++#ifndef __KORBIT__
++ g_mutex_unlock (mem_chunks_lock);
++#endif /* !__KORBIT__ */
++ g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%d mem chunks", count);
++
++#ifndef __KORBIT__
++ g_mutex_lock (mem_chunks_lock);
++#endif /* !__KORBIT__ */
++ mem_chunk = mem_chunks;
++#ifndef __KORBIT__
++ g_mutex_unlock (mem_chunks_lock);
++#endif /* !__KORBIT__ */
++
++ while (mem_chunk)
++ {
++ g_mem_chunk_print ((GMemChunk*) mem_chunk);
++ mem_chunk = mem_chunk->next;
++ }
++}
++
++void
++g_blow_chunks (void)
++{
++ GRealMemChunk *mem_chunk;
++
++#ifndef __KORBIT__
++ g_mutex_lock (mem_chunks_lock);
++#endif /* !__KORBIT__ */
++ mem_chunk = mem_chunks;
++#ifndef __KORBIT__
++ g_mutex_unlock (mem_chunks_lock);
++#endif /* !__KORBIT__ */
++ while (mem_chunk)
++ {
++ g_mem_chunk_clean ((GMemChunk*) mem_chunk);
++ mem_chunk = mem_chunk->next;
++ }
++}
++
++
++static gulong
++g_mem_chunk_compute_size (gulong size,
++ gulong min_size)
++{
++ gulong power_of_2;
++ gulong lower, upper;
++
++ power_of_2 = 16;
++ while (power_of_2 < size)
++ power_of_2 <<= 1;
++
++ lower = power_of_2 >> 1;
++ upper = power_of_2;
++
++ if (size - lower < upper - size && lower >= min_size)
++ return lower;
++ else
++ return upper;
++}
++
++static gint
++g_mem_chunk_area_compare (GMemArea *a,
++ GMemArea *b)
++{
++ if (a->mem > b->mem)
++ return 1;
++ else if (a->mem < b->mem)
++ return -1;
++ return 0;
++}
++
++static gint
++g_mem_chunk_area_search (GMemArea *a,
++ gchar *addr)
++{
++ if (a->mem <= addr)
++ {
++ if (addr < &a->mem[a->index])
++ return 0;
++ return 1;
++ }
++ return -1;
++}
++
++/* generic allocators
++ */
++struct _GAllocator /* from gmem.c */
++{
++ gchar *name;
++ guint16 n_preallocs;
++ guint is_unused : 1;
++ guint type : 4;
++ GAllocator *last;
++ GMemChunk *mem_chunk;
++ gpointer dummy; /* implementation specific */
++};
++
++GAllocator*
++g_allocator_new (const gchar *name,
++ guint n_preallocs)
++{
++ GAllocator *allocator;
++
++ g_return_val_if_fail (name != NULL, NULL);
++
++ allocator = g_new0 (GAllocator, 1);
++ allocator->name = g_strdup (name);
++ allocator->n_preallocs = CLAMP (n_preallocs, 1, 65535);
++ allocator->is_unused = TRUE;
++ allocator->type = 0;
++ allocator->last = NULL;
++ allocator->mem_chunk = NULL;
++ allocator->dummy = NULL;
++
++ return allocator;
++}
++
++void
++g_allocator_free (GAllocator *allocator)
++{
++ g_return_if_fail (allocator != NULL);
++ g_return_if_fail (allocator->is_unused == TRUE);
++
++ g_free (allocator->name);
++ if (allocator->mem_chunk)
++ g_mem_chunk_destroy (allocator->mem_chunk);
++
++ g_free (allocator);
++}
++
++void
++g_mem_init (void)
++{
++#ifndef __KORBIT__
++ mem_chunks_lock = g_mutex_new();
++#endif /* !__KORBIT__ */
++}
+diff -urN linux-2.4.1/net/korbit/kglib/gprimes.c linux-2.4.1-korbit/net/korbit/kglib/gprimes.c
+--- linux-2.4.1/net/korbit/kglib/gprimes.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/gprimes.c Thu Feb 1 11:46:57 2001
+@@ -0,0 +1,79 @@
++/* GLIB - Library of useful routines for C programming
++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
++ *
++ * 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.
++ */
++
++/*
++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS
++ * file for a list of people on the GLib Team. See the ChangeLog
++ * files for a list of changes. These files are distributed with
++ * GLib at ftp://ftp.gtk.org/pub/gtk/.
++ */
++
++#include "glib.h"
++
++static const guint g_primes[] =
++{
++ 11,
++ 19,
++ 37,
++ 73,
++ 109,
++ 163,
++ 251,
++ 367,
++ 557,
++ 823,
++ 1237,
++ 1861,
++ 2777,
++ 4177,
++ 6247,
++ 9371,
++ 14057,
++ 21089,
++ 31627,
++ 47431,
++ 71143,
++ 106721,
++ 160073,
++ 240101,
++ 360163,
++ 540217,
++ 810343,
++ 1215497,
++ 1823231,
++ 2734867,
++ 4102283,
++ 6153409,
++ 9230113,
++ 13845163,
++};
++
++static const guint g_nprimes = sizeof (g_primes) / sizeof (g_primes[0]);
++
++guint
++g_spaced_primes_closest (guint num)
++{
++ gint i;
++
++ for (i = 0; i < g_nprimes; i++)
++ if (g_primes[i] > num)
++ return g_primes[i];
++
++ return g_primes[g_nprimes - 1];
++}
+diff -urN linux-2.4.1/net/korbit/kglib/gslist.c linux-2.4.1-korbit/net/korbit/kglib/gslist.c
+--- linux-2.4.1/net/korbit/kglib/gslist.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/gslist.c Thu Feb 1 11:46:57 2001
+@@ -0,0 +1,591 @@
++/* GLIB - Library of useful routines for C programming
++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
++ *
++ * 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.
++ */
++
++/*
++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS
++ * file for a list of people on the GLib Team. See the ChangeLog
++ * files for a list of changes. These files are distributed with
++ * GLib at ftp://ftp.gtk.org/pub/gtk/.
++ */
++
++#include "glib.h"
++
++
++struct _GAllocator /* from gmem.c */
++{
++ gchar *name;
++ guint16 n_preallocs;
++ guint is_unused : 1;
++ guint type : 4;
++ GAllocator *last;
++ GMemChunk *mem_chunk;
++ GSList *free_lists; /* implementation specific */
++};
++
++G_LOCK_DEFINE_STATIC (current_allocator);
++static GAllocator *current_allocator = NULL;
++
++/* HOLDS: current_allocator_lock */
++static void
++g_slist_validate_allocator (GAllocator *allocator)
++{
++ g_return_if_fail (allocator != NULL);
++ g_return_if_fail (allocator->is_unused == TRUE);
++
++ if (allocator->type != G_ALLOCATOR_SLIST)
++ {
++ allocator->type = G_ALLOCATOR_SLIST;
++ if (allocator->mem_chunk)
++ {
++ g_mem_chunk_destroy (allocator->mem_chunk);
++ allocator->mem_chunk = NULL;
++ }
++ }
++
++ if (!allocator->mem_chunk)
++ {
++ allocator->mem_chunk = g_mem_chunk_new (allocator->name,
++ sizeof (GSList),
++ sizeof (GSList) * allocator->n_preallocs,
++ G_ALLOC_ONLY);
++ allocator->free_lists = NULL;
++ }
++
++ allocator->is_unused = FALSE;
++}
++
++void
++g_slist_push_allocator (GAllocator *allocator)
++{
++ G_LOCK (current_allocator);
++ g_slist_validate_allocator (allocator);
++ allocator->last = current_allocator;
++ current_allocator = allocator;
++ G_UNLOCK (current_allocator);
++}
++
++void
++g_slist_pop_allocator (void)
++{
++ G_LOCK (current_allocator);
++ if (current_allocator)
++ {
++ GAllocator *allocator;
++
++ allocator = current_allocator;
++ current_allocator = allocator->last;
++ allocator->last = NULL;
++ allocator->is_unused = TRUE;
++ }
++ G_UNLOCK (current_allocator);
++}
++
++GSList*
++g_slist_alloc (void)
++{
++ GSList *list;
++
++ G_LOCK (current_allocator);
++ if (!current_allocator)
++ {
++ GAllocator *allocator = g_allocator_new ("GLib default GSList allocator",
++ 128);
++ g_slist_validate_allocator (allocator);
++ allocator->last = NULL;
++ current_allocator = allocator;
++ }
++ if (!current_allocator->free_lists)
++ {
++ list = g_chunk_new (GSList, current_allocator->mem_chunk);
++ list->data = NULL;
++ }
++ else
++ {
++ if (current_allocator->free_lists->data)
++ {
++ list = current_allocator->free_lists->data;
++ current_allocator->free_lists->data = list->next;
++ list->data = NULL;
++ }
++ else
++ {
++ list = current_allocator->free_lists;
++ current_allocator->free_lists = list->next;
++ }
++ }
++ G_UNLOCK (current_allocator);
++
++ list->next = NULL;
++
++ return list;
++}
++
++void
++g_slist_free (GSList *list)
++{
++ if (list)
++ {
++ list->data = list->next;
++ G_LOCK (current_allocator);
++ list->next = current_allocator->free_lists;
++ current_allocator->free_lists = list;
++ G_UNLOCK (current_allocator);
++ }
++}
++
++void
++g_slist_free_1 (GSList *list)
++{
++ if (list)
++ {
++ list->data = NULL;
++ G_LOCK (current_allocator);
++ list->next = current_allocator->free_lists;
++ current_allocator->free_lists = list;
++ G_UNLOCK (current_allocator);
++ }
++}
++
++GSList*
++g_slist_append (GSList *list,
++ gpointer data)
++{
++ GSList *new_list;
++ GSList *last;
++
++ new_list = g_slist_alloc ();
++ new_list->data = data;
++
++ if (list)
++ {
++ last = g_slist_last (list);
++ /* g_assert (last != NULL); */
++ last->next = new_list;
++
++ return list;
++ }
++ else
++ return new_list;
++}
++
++GSList*
++g_slist_prepend (GSList *list,
++ gpointer data)
++{
++ GSList *new_list;
++
++ new_list = g_slist_alloc ();
++ new_list->data = data;
++ new_list->next = list;
++
++ return new_list;
++}
++
++GSList*
++g_slist_insert (GSList *list,
++ gpointer data,
++ gint position)
++{
++ GSList *prev_list;
++ GSList *tmp_list;
++ GSList *new_list;
++
++ if (position < 0)
++ return g_slist_append (list, data);
++ else if (position == 0)
++ return g_slist_prepend (list, data);
++
++ new_list = g_slist_alloc ();
++ new_list->data = data;
++
++ if (!list)
++ return new_list;
++
++ prev_list = NULL;
++ tmp_list = list;
++
++ while ((position-- > 0) && tmp_list)
++ {
++ prev_list = tmp_list;
++ tmp_list = tmp_list->next;
++ }
++
++ if (prev_list)
++ {
++ new_list->next = prev_list->next;
++ prev_list->next = new_list;
++ }
++ else
++ {
++ new_list->next = list;
++ list = new_list;
++ }
++
++ return list;
++}
++
++GSList *
++g_slist_concat (GSList *list1, GSList *list2)
++{
++ if (list2)
++ {
++ if (list1)
++ g_slist_last (list1)->next = list2;
++ else
++ list1 = list2;
++ }
++
++ return list1;
++}
++
++GSList*
++g_slist_remove (GSList *list,
++ gpointer data)
++{
++ GSList *tmp;
++ GSList *prev;
++
++ prev = NULL;
++ tmp = list;
++
++ while (tmp)
++ {
++ if (tmp->data == data)
++ {
++ if (prev)
++ prev->next = tmp->next;
++ if (list == tmp)
++ list = list->next;
++
++ tmp->next = NULL;
++ g_slist_free (tmp);
++
++ break;
++ }
++
++ prev = tmp;
++ tmp = tmp->next;
++ }
++
++ return list;
++}
++
++GSList*
++g_slist_remove_link (GSList *list,
++ GSList *link)
++{
++ GSList *tmp;
++ GSList *prev;
++
++ prev = NULL;
++ tmp = list;
++
++ while (tmp)
++ {
++ if (tmp == link)
++ {
++ if (prev)
++ prev->next = tmp->next;
++ if (list == tmp)
++ list = list->next;
++
++ tmp->next = NULL;
++ break;
++ }
++
++ prev = tmp;
++ tmp = tmp->next;
++ }
++
++ return list;
++}
++
++GSList*
++g_slist_copy (GSList *list)
++{
++ GSList *new_list = NULL;
++
++ if (list)
++ {
++ GSList *last;
++
++ new_list = g_slist_alloc ();
++ new_list->data = list->data;
++ last = new_list;
++ list = list->next;
++ while (list)
++ {
++ last->next = g_slist_alloc ();
++ last = last->next;
++ last->data = list->data;
++ list = list->next;
++ }
++ }
++
++ return new_list;
++}
++
++GSList*
++g_slist_reverse (GSList *list)
++{
++ GSList *prev = NULL;
++
++ while (list)
++ {
++ GSList *next = list->next;
++
++ list->next = prev;
++
++ prev = list;
++ list = next;
++ }
++
++ return prev;
++}
++
++GSList*
++g_slist_nth (GSList *list,
++ guint n)
++{
++ while ((n-- > 0) && list)
++ list = list->next;
++
++ return list;
++}
++
++gpointer
++g_slist_nth_data (GSList *list,
++ guint n)
++{
++ while ((n-- > 0) && list)
++ list = list->next;
++
++ return list ? list->data : NULL;
++}
++
++GSList*
++g_slist_find (GSList *list,
++ gpointer data)
++{
++ while (list)
++ {
++ if (list->data == data)
++ break;
++ list = list->next;
++ }
++
++ return list;
++}
++
++GSList*
++g_slist_find_custom (GSList *list,
++ gpointer data,
++ GCompareFunc func)
++{
++ g_return_val_if_fail (func != NULL, list);
++
++ while (list)
++ {
++ if (! func (list->data, data))
++ return list;
++ list = list->next;
++ }
++
++ return NULL;
++}
++
++gint
++g_slist_position (GSList *list,
++ GSList *link)
++{
++ gint i;
++
++ i = 0;
++ while (list)
++ {
++ if (list == link)
++ return i;
++ i++;
++ list = list->next;
++ }
++
++ return -1;
++}
++
++gint
++g_slist_index (GSList *list,
++ gpointer data)
++{
++ gint i;
++
++ i = 0;
++ while (list)
++ {
++ if (list->data == data)
++ return i;
++ i++;
++ list = list->next;
++ }
++
++ return -1;
++}
++
++GSList*
++g_slist_last (GSList *list)
++{
++ if (list)
++ {
++ while (list->next)
++ list = list->next;
++ }
++
++ return list;
++}
++
++guint
++g_slist_length (GSList *list)
++{
++ guint length;
++
++ length = 0;
++ while (list)
++ {
++ length++;
++ list = list->next;
++ }
++
++ return length;
++}
++
++void
++g_slist_foreach (GSList *list,
++ GFunc func,
++ gpointer user_data)
++{
++ while (list)
++ {
++ (*func) (list->data, user_data);
++ list = list->next;
++ }
++}
++
++GSList*
++g_slist_insert_sorted (GSList *list,
++ gpointer data,
++ GCompareFunc func)
++{
++ GSList *tmp_list = list;
++ GSList *prev_list = NULL;
++ GSList *new_list;
++ gint cmp;
++
++ g_return_val_if_fail (func != NULL, list);
++
++ if (!list)
++ {
++ new_list = g_slist_alloc();
++ new_list->data = data;
++ return new_list;
++ }
++
++ cmp = (*func) (data, tmp_list->data);
++
++ while ((tmp_list->next) && (cmp > 0))
++ {
++ prev_list = tmp_list;
++ tmp_list = tmp_list->next;
++ cmp = (*func) (data, tmp_list->data);
++ }
++
++ new_list = g_slist_alloc();
++ new_list->data = data;
++
++ if ((!tmp_list->next) && (cmp > 0))
++ {
++ tmp_list->next = new_list;
++ return list;
++ }
++
++ if (prev_list)
++ {
++ prev_list->next = new_list;
++ new_list->next = tmp_list;
++ return list;
++ }
++ else
++ {
++ new_list->next = list;
++ return new_list;
++ }
++}
++
++static GSList*
++g_slist_sort_merge (GSList *l1,
++ GSList *l2,
++ GCompareFunc compare_func)
++{
++ GSList list, *l;
++
++ l=&list;
++
++ while (l1 && l2)
++ {
++ if (compare_func(l1->data,l2->data) < 0)
++ {
++ l=l->next=l1;
++ l1=l1->next;
++ }
++ else
++ {
++ l=l->next=l2;
++ l2=l2->next;
++ }
++ }
++ l->next= l1 ? l1 : l2;
++
++ return list.next;
++}
++
++GSList*
++g_slist_sort (GSList *list,
++ GCompareFunc compare_func)
++{
++ GSList *l1, *l2;
++
++ if (!list)
++ return NULL;
++ if (!list->next)
++ return list;
++
++ l1 = list;
++ l2 = list->next;
++
++ while ((l2 = l2->next) != NULL)
++ {
++ if ((l2 = l2->next) == NULL)
++ break;
++ l1=l1->next;
++ }
++ l2 = l1->next;
++ l1->next = NULL;
++
++ return g_slist_sort_merge (g_slist_sort (list, compare_func),
++ g_slist_sort (l2, compare_func),
++ compare_func);
++}
+diff -urN linux-2.4.1/net/korbit/kglib/gstrfuncs.c linux-2.4.1-korbit/net/korbit/kglib/gstrfuncs.c
+--- linux-2.4.1/net/korbit/kglib/gstrfuncs.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/gstrfuncs.c Thu Feb 1 11:46:57 2001
+@@ -0,0 +1,1308 @@
++/* GLIB - Library of useful routines for C programming
++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
++ *
++ * 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.
++ */
++
++/*
++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS
++ * file for a list of people on the GLib Team. See the ChangeLog
++ * files for a list of changes. These files are distributed with
++ * GLib at ftp://ftp.gtk.org/pub/gtk/.
++ */
++
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
++#include <stdarg.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <locale.h>
++#include <ctype.h> /* For tolower() */
++#if !defined (HAVE_STRSIGNAL) || !defined(NO_SYS_SIGLIST_DECL)
++#include <signal.h>
++#endif
++#include "glib.h"
++/* do not include <unistd.h> in this place since it
++ * inteferes with g_strsignal() on some OSes
++ */
++
++gchar*
++g_strdup (const gchar *str) {
++ gchar *new_str;
++
++ if (str)
++ {
++ new_str = g_new (char, strlen (str) + 1);
++ strcpy (new_str, str);
++ }
++ else
++ new_str = NULL;
++
++ return new_str;
++}
++
++gpointer
++g_memdup (gconstpointer mem,
++ guint byte_size)
++{
++ gpointer new_mem;
++
++ if (mem)
++ {
++ new_mem = g_malloc (byte_size);
++ memcpy (new_mem, mem, byte_size);
++ }
++ else
++ new_mem = NULL;
++
++ return new_mem;
++}
++
++gchar*
++g_strndup (const gchar *str,
++ guint n)
++{
++ gchar *new_str;
++
++ if (str)
++ {
++ new_str = g_new (gchar, n + 1);
++ strncpy (new_str, str, n);
++ new_str[n] = '\0';
++ }
++ else
++ new_str = NULL;
++
++ return new_str;
++}
++
++gchar*
++g_strnfill (guint length,
++ gchar fill_char)
++{
++ register gchar *str, *s, *end;
++
++ str = g_new (gchar, length + 1);
++ s = str;
++ end = str + length;
++ while (s < end)
++ *(s++) = fill_char;
++ *s = 0;
++
++ return str;
++}
++
++gchar*
++g_strdup_vprintf (const gchar *format,
++ va_list args1)
++{
++ gchar *buffer;
++ va_list args2;
++
++ G_VA_COPY (args2, args1);
++
++ buffer = g_new (gchar, g_printf_string_upper_bound (format, args1));
++
++ vsprintf (buffer, format, args2);
++ va_end (args2);
++
++ return buffer;
++}
++
++gchar*
++g_strdup_printf (const gchar *format,
++ ...)
++{
++ gchar *buffer;
++ va_list args;
++
++ va_start (args, format);
++ buffer = g_strdup_vprintf (format, args);
++ va_end (args);
++
++ return buffer;
++}
++
++gchar*
++g_strconcat (const gchar *string1, ...)
++{
++ guint l;
++ va_list args;
++ gchar *s;
++ gchar *concat;
++
++ g_return_val_if_fail (string1 != NULL, NULL);
++
++ l = 1 + strlen (string1);
++ va_start (args, string1);
++ s = va_arg (args, gchar*);
++ while (s)
++ {
++ l += strlen (s);
++ s = va_arg (args, gchar*);
++ }
++ va_end (args);
++
++ concat = g_new (gchar, l);
++ concat[0] = 0;
++
++ strcat (concat, string1);
++ va_start (args, string1);
++ s = va_arg (args, gchar*);
++ while (s)
++ {
++ strcat (concat, s);
++ s = va_arg (args, gchar*);
++ }
++ va_end (args);
++
++ return concat;
++}
++
++#ifndef __KORBIT__
++gdouble
++g_strtod (const gchar *nptr,
++ gchar **endptr)
++{
++ gchar *fail_pos_1;
++ gchar *fail_pos_2;
++ gdouble val_1;
++ gdouble val_2 = 0;
++
++ g_return_val_if_fail (nptr != NULL, 0);
++
++ fail_pos_1 = NULL;
++ fail_pos_2 = NULL;
++
++ val_1 = strtod (nptr, &fail_pos_1);
++
++ if (fail_pos_1 && fail_pos_1[0] != 0)
++ {
++ gchar *old_locale;
++
++ old_locale = g_strdup (setlocale (LC_NUMERIC, NULL));
++ setlocale (LC_NUMERIC, "C");
++ val_2 = strtod (nptr, &fail_pos_2);
++ setlocale (LC_NUMERIC, old_locale);
++ g_free (old_locale);
++ }
++
++ if (!fail_pos_1 || fail_pos_1[0] == 0 || fail_pos_1 >= fail_pos_2)
++ {
++ if (endptr)
++ *endptr = fail_pos_1;
++ return val_1;
++ }
++ else
++ {
++ if (endptr)
++ *endptr = fail_pos_2;
++ return val_2;
++ }
++}
++#endif /* !__KORBIT__ */
++
++gchar*
++g_strerror (gint errnum)
++{
++#ifndef __KORBIT__
++ static GStaticPrivate msg_private = G_STATIC_PRIVATE_INIT;
++ char *msg;
++#endif
++
++#ifdef __KORBIT__
++#undef HAVE_STRERROR
++#define NO_SYS_ERRLIST 1
++#endif
++
++#if defined(HAVE_STRERROR)
++ return strerror (errnum);
++#elif NO_SYS_ERRLIST
++ switch (errnum)
++ {
++#ifdef E2BIG
++ case E2BIG: return "argument list too long";
++#endif
++#ifdef EACCES
++ case EACCES: return "permission denied";
++#endif
++#ifdef EADDRINUSE
++ case EADDRINUSE: return "address already in use";
++#endif
++#ifdef EADDRNOTAVAIL
++ case EADDRNOTAVAIL: return "can't assign requested address";
++#endif
++#ifdef EADV
++ case EADV: return "advertise error";
++#endif
++#ifdef EAFNOSUPPORT
++ case EAFNOSUPPORT: return "address family not supported by protocol family";
++#endif
++#ifdef EAGAIN
++ case EAGAIN: return "try again";
++#endif
++#ifdef EALIGN
++ case EALIGN: return "EALIGN";
++#endif
++#ifdef EALREADY
++ case EALREADY: return "operation already in progress";
++#endif
++#ifdef EBADE
++ case EBADE: return "bad exchange descriptor";
++#endif
++#ifdef EBADF
++ case EBADF: return "bad file number";
++#endif
++#ifdef EBADFD
++ case EBADFD: return "file descriptor in bad state";
++#endif
++#ifdef EBADMSG
++ case EBADMSG: return "not a data message";
++#endif
++#ifdef EBADR
++ case EBADR: return "bad request descriptor";
++#endif
++#ifdef EBADRPC
++ case EBADRPC: return "RPC structure is bad";
++#endif
++#ifdef EBADRQC
++ case EBADRQC: return "bad request code";
++#endif
++#ifdef EBADSLT
++ case EBADSLT: return "invalid slot";
++#endif
++#ifdef EBFONT
++ case EBFONT: return "bad font file format";
++#endif
++#ifdef EBUSY
++ case EBUSY: return "mount device busy";
++#endif
++#ifdef ECHILD
++ case ECHILD: return "no children";
++#endif
++#ifdef ECHRNG
++ case ECHRNG: return "channel number out of range";
++#endif
++#ifdef ECOMM
++ case ECOMM: return "communication error on send";
++#endif
++#ifdef ECONNABORTED
++ case ECONNABORTED: return "software caused connection abort";
++#endif
++#ifdef ECONNREFUSED
++ case ECONNREFUSED: return "connection refused";
++#endif
++#ifdef ECONNRESET
++ case ECONNRESET: return "connection reset by peer";
++#endif
++#if defined(EDEADLK) && (!defined(EWOULDBLOCK) || (EDEADLK != EWOULDBLOCK)) && (!defined(EDEADLOCK) || (EDEADLK != EDEADLOCK))
++ case EDEADLK: return "resource deadlock avoided";
++#endif
++#ifdef EDEADLOCK
++ case EDEADLOCK: return "resource deadlock avoided";
++#endif
++#ifdef EDESTADDRREQ
++ case EDESTADDRREQ: return "destination address required";
++#endif
++#ifdef EDIRTY
++ case EDIRTY: return "mounting a dirty fs w/o force";
++#endif
++#ifdef EDOM
++ case EDOM: return "math argument out of range";
++#endif
++#ifdef EDOTDOT
++ case EDOTDOT: return "cross mount point";
++#endif
++#ifdef EDQUOT
++ case EDQUOT: return "disk quota exceeded";
++#endif
++#ifdef EDUPPKG
++ case EDUPPKG: return "duplicate package name";
++#endif
++#ifdef EEXIST
++ case EEXIST: return "file already exists";
++#endif
++#ifdef EFAULT
++ case EFAULT: return "bad address in system call argument";
++#endif
++#ifdef EFBIG
++ case EFBIG: return "file too large";
++#endif
++#ifdef EHOSTDOWN
++ case EHOSTDOWN: return "host is down";
++#endif
++#ifdef EHOSTUNREACH
++ case EHOSTUNREACH: return "host is unreachable";
++#endif
++#ifdef EIDRM
++ case EIDRM: return "identifier removed";
++#endif
++#ifdef EINIT
++ case EINIT: return "initialization error";
++#endif
++#ifdef EINPROGRESS
++ case EINPROGRESS: return "operation now in progress";
++#endif
++#ifdef EINTR
++ case EINTR: return "interrupted system call";
++#endif
++#ifdef EINVAL
++ case EINVAL: return "invalid argument";
++#endif
++#ifdef EIO
++ case EIO: return "I/O error";
++#endif
++#ifdef EISCONN
++ case EISCONN: return "socket is already connected";
++#endif
++#ifdef EISDIR
++ case EISDIR: return "illegal operation on a directory";
++#endif
++#ifdef EISNAME
++ case EISNAM: return "is a name file";
++#endif
++#ifdef ELBIN
++ case ELBIN: return "ELBIN";
++#endif
++#ifdef EL2HLT
++ case EL2HLT: return "level 2 halted";
++#endif
++#ifdef EL2NSYNC
++ case EL2NSYNC: return "level 2 not synchronized";
++#endif
++#ifdef EL3HLT
++ case EL3HLT: return "level 3 halted";
++#endif
++#ifdef EL3RST
++ case EL3RST: return "level 3 reset";
++#endif
++#ifdef ELIBACC
++ case ELIBACC: return "can not access a needed shared library";
++#endif
++#ifdef ELIBBAD
++ case ELIBBAD: return "accessing a corrupted shared library";
++#endif
++#ifdef ELIBEXEC
++ case ELIBEXEC: return "can not exec a shared library directly";
++#endif
++#ifdef ELIBMAX
++ case ELIBMAX: return "attempting to link in more shared libraries than system limit";
++#endif
++#ifdef ELIBSCN
++ case ELIBSCN: return ".lib section in a.out corrupted";
++#endif
++#ifdef ELNRNG
++ case ELNRNG: return "link number out of range";
++#endif
++#ifdef ELOOP
++ case ELOOP: return "too many levels of symbolic links";
++#endif
++#ifdef EMFILE
++ case EMFILE: return "too many open files";
++#endif
++#ifdef EMLINK
++ case EMLINK: return "too many links";
++#endif
++#ifdef EMSGSIZE
++ case EMSGSIZE: return "message too long";
++#endif
++#ifdef EMULTIHOP
++ case EMULTIHOP: return "multihop attempted";
++#endif
++#ifdef ENAMETOOLONG
++ case ENAMETOOLONG: return "file name too long";
++#endif
++#ifdef ENAVAIL
++ case ENAVAIL: return "not available";
++#endif
++#ifdef ENET
++ case ENET: return "ENET";
++#endif
++#ifdef ENETDOWN
++ case ENETDOWN: return "network is down";
++#endif
++#ifdef ENETRESET
++ case ENETRESET: return "network dropped connection on reset";
++#endif
++#ifdef ENETUNREACH
++ case ENETUNREACH: return "network is unreachable";
++#endif
++#ifdef ENFILE
++ case ENFILE: return "file table overflow";
++#endif
++#ifdef ENOANO
++ case ENOANO: return "anode table overflow";
++#endif
++#if defined(ENOBUFS) && (!defined(ENOSR) || (ENOBUFS != ENOSR))
++ case ENOBUFS: return "no buffer space available";
++#endif
++#ifdef ENOCSI
++ case ENOCSI: return "no CSI structure available";
++#endif
++#ifdef ENODATA
++ case ENODATA: return "no data available";
++#endif
++#ifdef ENODEV
++ case ENODEV: return "no such device";
++#endif
++#ifdef ENOENT
++ case ENOENT: return "no such file or directory";
++#endif
++#ifdef ENOEXEC
++ case ENOEXEC: return "exec format error";
++#endif
++#ifdef ENOLCK
++ case ENOLCK: return "no locks available";
++#endif
++#ifdef ENOLINK
++ case ENOLINK: return "link has be severed";
++#endif
++#ifdef ENOMEM
++ case ENOMEM: return "not enough memory";
++#endif
++#ifdef ENOMSG
++ case ENOMSG: return "no message of desired type";
++#endif
++#ifdef ENONET
++ case ENONET: return "machine is not on the network";
++#endif
++#ifdef ENOPKG
++ case ENOPKG: return "package not installed";
++#endif
++#ifdef ENOPROTOOPT
++ case ENOPROTOOPT: return "bad proocol option";
++#endif
++#ifdef ENOSPC
++ case ENOSPC: return "no space left on device";
++#endif
++#ifdef ENOSR
++ case ENOSR: return "out of stream resources";
++#endif
++#ifdef ENOSTR
++ case ENOSTR: return "not a stream device";
++#endif
++#ifdef ENOSYM
++ case ENOSYM: return "unresolved symbol name";
++#endif
++#ifdef ENOSYS
++ case ENOSYS: return "function not implemented";
++#endif
++#ifdef ENOTBLK
++ case ENOTBLK: return "block device required";
++#endif
++#ifdef ENOTCONN
++ case ENOTCONN: return "socket is not connected";
++#endif
++#ifdef ENOTDIR
++ case ENOTDIR: return "not a directory";
++#endif
++#ifdef ENOTEMPTY
++ case ENOTEMPTY: return "directory not empty";
++#endif
++#ifdef ENOTNAM
++ case ENOTNAM: return "not a name file";
++#endif
++#ifdef ENOTSOCK
++ case ENOTSOCK: return "socket operation on non-socket";
++#endif
++#ifdef ENOTTY
++ case ENOTTY: return "inappropriate device for ioctl";
++#endif
++#ifdef ENOTUNIQ
++ case ENOTUNIQ: return "name not unique on network";
++#endif
++#ifdef ENXIO
++ case ENXIO: return "no such device or address";
++#endif
++#ifdef EOPNOTSUPP
++ case EOPNOTSUPP: return "operation not supported on socket";
++#endif
++#ifdef EPERM
++ case EPERM: return "not owner";
++#endif
++#ifdef EPFNOSUPPORT
++ case EPFNOSUPPORT: return "protocol family not supported";
++#endif
++#ifdef EPIPE
++ case EPIPE: return "broken pipe";
++#endif
++#ifdef EPROCLIM
++ case EPROCLIM: return "too many processes";
++#endif
++#ifdef EPROCUNAVAIL
++ case EPROCUNAVAIL: return "bad procedure for program";
++#endif
++#ifdef EPROGMISMATCH
++ case EPROGMISMATCH: return "program version wrong";
++#endif
++#ifdef EPROGUNAVAIL
++ case EPROGUNAVAIL: return "RPC program not available";
++#endif
++#ifdef EPROTO
++ case EPROTO: return "protocol error";
++#endif
++#ifdef EPROTONOSUPPORT
++ case EPROTONOSUPPORT: return "protocol not suppored";
++#endif
++#ifdef EPROTOTYPE
++ case EPROTOTYPE: return "protocol wrong type for socket";
++#endif
++#ifdef ERANGE
++ case ERANGE: return "math result unrepresentable";
++#endif
++#if defined(EREFUSED) && (!defined(ECONNREFUSED) || (EREFUSED != ECONNREFUSED))
++ case EREFUSED: return "EREFUSED";
++#endif
++#ifdef EREMCHG
++ case EREMCHG: return "remote address changed";
++#endif
++#ifdef EREMDEV
++ case EREMDEV: return "remote device";
++#endif
++#ifdef EREMOTE
++ case EREMOTE: return "pathname hit remote file system";
++#endif
++#ifdef EREMOTEIO
++ case EREMOTEIO: return "remote i/o error";
++#endif
++#ifdef EREMOTERELEASE
++ case EREMOTERELEASE: return "EREMOTERELEASE";
++#endif
++#ifdef EROFS
++ case EROFS: return "read-only file system";
++#endif
++#ifdef ERPCMISMATCH
++ case ERPCMISMATCH: return "RPC version is wrong";
++#endif
++#ifdef ERREMOTE
++ case ERREMOTE: return "object is remote";
++#endif
++#ifdef ESHUTDOWN
++ case ESHUTDOWN: return "can't send afer socket shutdown";
++#endif
++#ifdef ESOCKTNOSUPPORT
++ case ESOCKTNOSUPPORT: return "socket type not supported";
++#endif
++#ifdef ESPIPE
++ case ESPIPE: return "invalid seek";
++#endif
++#ifdef ESRCH
++ case ESRCH: return "no such process";
++#endif
++#ifdef ESRMNT
++ case ESRMNT: return "srmount error";
++#endif
++#ifdef ESTALE
++ case ESTALE: return "stale remote file handle";
++#endif
++#ifdef ESUCCESS
++ case ESUCCESS: return "Error 0";
++#endif
++#ifdef ETIME
++ case ETIME: return "timer expired";
++#endif
++#ifdef ETIMEDOUT
++ case ETIMEDOUT: return "connection timed out";
++#endif
++#ifdef ETOOMANYREFS
++ case ETOOMANYREFS: return "too many references: can't splice";
++#endif
++#ifdef ETXTBSY
++ case ETXTBSY: return "text file or pseudo-device busy";
++#endif
++#ifdef EUCLEAN
++ case EUCLEAN: return "structure needs cleaning";
++#endif
++#ifdef EUNATCH
++ case EUNATCH: return "protocol driver not attached";
++#endif
++#ifdef EUSERS
++ case EUSERS: return "too many users";
++#endif
++#ifdef EVERSION
++ case EVERSION: return "version mismatch";
++#endif
++#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
++ case EWOULDBLOCK: return "operation would block";
++#endif
++#ifdef EXDEV
++ case EXDEV: return "cross-domain link";
++#endif
++#ifdef EXFULL
++ case EXFULL: return "message tables full";
++#endif
++ }
++#else /* NO_SYS_ERRLIST */
++ extern int sys_nerr;
++ extern char *sys_errlist[];
++
++ if ((errnum > 0) && (errnum <= sys_nerr))
++ return sys_errlist [errnum];
++#endif /* NO_SYS_ERRLIST */
++
++#ifndef __KORBIT__
++ msg = g_static_private_get (&msg_private);
++ if (!msg)
++ {
++ msg = g_new (gchar, 64);
++ g_static_private_set (&msg_private, msg, g_free);
++ }
++
++ sprintf (msg, "unknown error (%d)", errnum);
++
++ return msg;
++#else
++ return "unknown error";
++#endif /* !__KORBIT__ */
++}
++
++gchar*
++g_strsignal (gint signum)
++{
++#ifndef __KORBIT__
++ static GStaticPrivate msg_private = G_STATIC_PRIVATE_INIT;
++ char *msg;
++#endif
++
++#ifdef HAVE_STRSIGNAL
++ extern char *strsignal (int sig);
++ return strsignal (signum);
++#elif NO_SYS_SIGLIST
++ switch (signum)
++ {
++#ifdef SIGHUP
++ case SIGHUP: return "Hangup";
++#endif
++#ifdef SIGINT
++ case SIGINT: return "Interrupt";
++#endif
++#ifdef SIGQUIT
++ case SIGQUIT: return "Quit";
++#endif
++#ifdef SIGILL
++ case SIGILL: return "Illegal instruction";
++#endif
++#ifdef SIGTRAP
++ case SIGTRAP: return "Trace/breakpoint trap";
++#endif
++#ifdef SIGABRT
++ case SIGABRT: return "IOT trap/Abort";
++#endif
++#ifdef SIGBUS
++ case SIGBUS: return "Bus error";
++#endif
++#ifdef SIGFPE
++ case SIGFPE: return "Floating point exception";
++#endif
++#ifdef SIGKILL
++ case SIGKILL: return "Killed";
++#endif
++#ifdef SIGUSR1
++ case SIGUSR1: return "User defined signal 1";
++#endif
++#ifdef SIGSEGV
++ case SIGSEGV: return "Segmentation fault";
++#endif
++#ifdef SIGUSR2
++ case SIGUSR2: return "User defined signal 2";
++#endif
++#ifdef SIGPIPE
++ case SIGPIPE: return "Broken pipe";
++#endif
++#ifdef SIGALRM
++ case SIGALRM: return "Alarm clock";
++#endif
++#ifdef SIGTERM
++ case SIGTERM: return "Terminated";
++#endif
++#ifdef SIGSTKFLT
++ case SIGSTKFLT: return "Stack fault";
++#endif
++#ifdef SIGCHLD
++ case SIGCHLD: return "Child exited";
++#endif
++#ifdef SIGCONT
++ case SIGCONT: return "Continued";
++#endif
++#ifdef SIGSTOP
++ case SIGSTOP: return "Stopped (signal)";
++#endif
++#ifdef SIGTSTP
++ case SIGTSTP: return "Stopped";
++#endif
++#ifdef SIGTTIN
++ case SIGTTIN: return "Stopped (tty input)";
++#endif
++#ifdef SIGTTOU
++ case SIGTTOU: return "Stopped (tty output)";
++#endif
++#ifdef SIGURG
++ case SIGURG: return "Urgent condition";
++#endif
++#ifdef SIGXCPU
++ case SIGXCPU: return "CPU time limit exceeded";
++#endif
++#ifdef SIGXFSZ
++ case SIGXFSZ: return "File size limit exceeded";
++#endif
++#ifdef SIGVTALRM
++ case SIGVTALRM: return "Virtual time alarm";
++#endif
++#ifdef SIGPROF
++ case SIGPROF: return "Profile signal";
++#endif
++#ifdef SIGWINCH
++ case SIGWINCH: return "Window size changed";
++#endif
++#ifdef SIGIO
++ case SIGIO: return "Possible I/O";
++#endif
++#ifdef SIGPWR
++ case SIGPWR: return "Power failure";
++#endif
++#ifdef SIGUNUSED
++ case SIGUNUSED: return "Unused signal";
++#endif
++ }
++#else /* NO_SYS_SIGLIST */
++
++#ifdef NO_SYS_SIGLIST_DECL
++ extern char *sys_siglist[]; /*(see Tue Jan 19 00:44:24 1999 in changelog)*/
++#endif
++
++ return (char*) /* this function should return const --josh */ sys_siglist [signum];
++#endif /* NO_SYS_SIGLIST */
++
++#ifndef __KORBIT__
++ msg = g_static_private_get (&msg_private);
++ if (!msg)
++ {
++ msg = g_new (gchar, 64);
++ g_static_private_set (&msg_private, msg, g_free);
++ }
++
++ sprintf (msg, "unknown signal (%d)", signum);
++
++ return msg;
++#else
++ return "unknown error";
++#endif /* !__KORBIT__ */
++}
++
++guint
++g_printf_string_upper_bound (const gchar* format,
++ va_list args)
++{
++ guint len = 1;
++
++ while (*format)
++ {
++ gboolean long_int = FALSE;
++ gboolean extra_long = FALSE;
++ gchar c;
++
++ c = *format++;
++
++ if (c == '%')
++ {
++ gboolean done = FALSE;
++
++ while (*format && !done)
++ {
++ switch (*format++)
++ {
++ gchar *string_arg;
++
++ case '*':
++ len += va_arg (args, int);
++ break;
++ case '1':
++ case '2':
++ case '3':
++ case '4':
++ case '5':
++ case '6':
++ case '7':
++ case '8':
++ case '9':
++ /* add specified format length, since it might exceed the
++ * size we assume it to have.
++ */
++ format -= 1;
++ len += strtol (format, (char**) &format, 10);
++ break;
++ case 'h':
++ /* ignore short int flag, since all args have at least the
++ * same size as an int
++ */
++ break;
++ case 'l':
++ if (long_int)
++ extra_long = TRUE; /* linux specific */
++ else
++ long_int = TRUE;
++ break;
++ case 'q':
++ case 'L':
++ long_int = TRUE;
++ extra_long = TRUE;
++ break;
++ case 's':
++ string_arg = va_arg (args, char *);
++ if (string_arg)
++ len += strlen (string_arg);
++ else
++ {
++ /* add enough padding to hold "(null)" identifier */
++ len += 16;
++ }
++ done = TRUE;
++ break;
++ case 'd':
++ case 'i':
++ case 'o':
++ case 'u':
++ case 'x':
++ case 'X':
++#ifdef G_HAVE_GINT64
++ if (extra_long)
++ (void) va_arg (args, gint64);
++ else
++#endif /* G_HAVE_GINT64 */
++ {
++ if (long_int)
++ (void) va_arg (args, long);
++ else
++ (void) va_arg (args, int);
++ }
++ len += extra_long ? 64 : 32;
++ done = TRUE;
++ break;
++ case 'D':
++ case 'O':
++ case 'U':
++ (void) va_arg (args, long);
++ len += 32;
++ done = TRUE;
++ break;
++ case 'e':
++ case 'E':
++ case 'f':
++ case 'g':
++#ifdef HAVE_LONG_DOUBLE
++ if (extra_long)
++ (void) va_arg (args, long double);
++ else
++#endif /* HAVE_LONG_DOUBLE */
++ (void) va_arg (args, double);
++ len += extra_long ? 128 : 64;
++ done = TRUE;
++ break;
++ case 'c':
++ (void) va_arg (args, int);
++ len += 1;
++ done = TRUE;
++ break;
++ case 'p':
++ case 'n':
++ (void) va_arg (args, void*);
++ len += 32;
++ done = TRUE;
++ break;
++ case '%':
++ len += 1;
++ done = TRUE;
++ break;
++ default:
++ /* ignore unknow/invalid flags */
++ break;
++ }
++ }
++ }
++ else
++ len += 1;
++ }
++
++ return len;
++}
++
++void
++g_strdown (gchar *string)
++{
++ register guchar *s;
++
++ g_return_if_fail (string != NULL);
++
++ s = string;
++
++ while (*s)
++ {
++ *s = tolower (*s);
++ s++;
++ }
++}
++
++void
++g_strup (gchar *string)
++{
++ register guchar *s;
++
++ g_return_if_fail (string != NULL);
++
++ s = string;
++
++ while (*s)
++ {
++ *s = toupper (*s);
++ s++;
++ }
++}
++
++void
++g_strreverse (gchar *string)
++{
++ g_return_if_fail (string != NULL);
++
++ if (*string)
++ {
++ register gchar *h, *t;
++
++ h = string;
++ t = string + strlen (string) - 1;
++
++ while (h < t)
++ {
++ register gchar c;
++
++ c = *h;
++ *h = *t;
++ h++;
++ *t = c;
++ t--;
++ }
++ }
++}
++
++gint
++g_strcasecmp (const gchar *s1,
++ const gchar *s2)
++{
++#ifdef HAVE_STRCASECMP
++ g_return_val_if_fail (s1 != NULL, 0);
++ g_return_val_if_fail (s2 != NULL, 0);
++
++ return strcasecmp (s1, s2);
++#else
++ gint c1, c2;
++
++ g_return_val_if_fail (s1 != NULL, 0);
++ g_return_val_if_fail (s2 != NULL, 0);
++
++ while (*s1 && *s2)
++ {
++ /* According to A. Cox, some platforms have islower's that
++ * don't work right on non-uppercase
++ */
++ c1 = isupper ((guchar)*s1) ? tolower ((guchar)*s1) : *s1;
++ c2 = isupper ((guchar)*s2) ? tolower ((guchar)*s2) : *s2;
++ if (c1 != c2)
++ return (c1 - c2);
++ s1++; s2++;
++ }
++
++ return (((gint)(guchar) *s1) - ((gint)(guchar) *s2));
++#endif
++}
++
++gint
++g_strncasecmp (const gchar *s1,
++ const gchar *s2,
++ guint n)
++{
++#ifdef HAVE_STRNCASECMP
++ return strncasecmp (s1, s2, n);
++#else
++ gint c1, c2;
++
++ g_return_val_if_fail (s1 != NULL, 0);
++ g_return_val_if_fail (s2 != NULL, 0);
++
++ while (n-- && *s1 && *s2)
++ {
++ /* According to A. Cox, some platforms have islower's that
++ * don't work right on non-uppercase
++ */
++ c1 = isupper ((guchar)*s1) ? tolower ((guchar)*s1) : *s1;
++ c2 = isupper ((guchar)*s2) ? tolower ((guchar)*s2) : *s2;
++ if (c1 != c2)
++ return (c1 - c2);
++ s1++; s2++;
++ }
++
++ if (n)
++ return (((gint)(guchar) *s1) - ((gint)(guchar) *s2));
++ else
++ return 0;
++#endif
++}
++
++gchar*
++g_strdelimit (gchar *string,
++ const gchar *delimiters,
++ gchar new_delim)
++{
++ register gchar *c;
++
++ g_return_val_if_fail (string != NULL, NULL);
++
++ if (!delimiters)
++ delimiters = G_STR_DELIMITERS;
++
++ for (c = string; *c; c++)
++ {
++ if (strchr (delimiters, *c))
++ *c = new_delim;
++ }
++
++ return string;
++}
++
++gchar*
++g_strescape (gchar *string)
++{
++ gchar *q;
++ gchar *escaped;
++ guint backslashes = 0;
++ gchar *p = string;
++
++ g_return_val_if_fail (string != NULL, NULL);
++
++ while (*p != '\000')
++ backslashes += (*p++ == '\\');
++
++ if (!backslashes)
++ return g_strdup (string);
++
++ escaped = g_new (gchar, strlen (string) + backslashes + 1);
++
++ p = string;
++ q = escaped;
++
++ while (*p != '\000')
++ {
++ if (*p == '\\')
++ *q++ = '\\';
++ *q++ = *p++;
++ }
++ *q = '\000';
++
++ return escaped;
++}
++
++/* blame Elliot for these next five routines */
++gchar*
++g_strchug (gchar *string)
++{
++ guchar *start;
++
++ g_return_val_if_fail (string != NULL, NULL);
++
++ for (start = string; *start && isspace (*start); start++)
++ ;
++
++ g_memmove(string, start, strlen(start) + 1);
++
++ return string;
++}
++
++gchar*
++g_strchomp (gchar *string)
++{
++ gchar *s;
++
++ g_return_val_if_fail (string != NULL, NULL);
++
++ if (!*string)
++ return string;
++
++ for (s = string + strlen (string) - 1; s >= string && isspace ((guchar)*s);
++ s--)
++ *s = '\0';
++
++ return string;
++}
++
++gchar**
++g_strsplit (const gchar *string,
++ const gchar *delimiter,
++ gint max_tokens)
++{
++ GSList *string_list = NULL, *slist;
++ gchar **str_array, *s;
++ guint i, n = 1;
++
++ g_return_val_if_fail (string != NULL, NULL);
++ g_return_val_if_fail (delimiter != NULL, NULL);
++
++ if (max_tokens < 1)
++ max_tokens = G_MAXINT;
++
++ s = strstr (string, delimiter);
++ if (s)
++ {
++ guint delimiter_len = strlen (delimiter);
++
++ do
++ {
++ guint len;
++ gchar *new_string;
++
++ len = s - string;
++ new_string = g_new (gchar, len + 1);
++ strncpy (new_string, string, len);
++ new_string[len] = 0;
++ string_list = g_slist_prepend (string_list, new_string);
++ n++;
++ string = s + delimiter_len;
++ s = strstr (string, delimiter);
++ }
++ while (--max_tokens && s);
++ }
++ if (*string)
++ {
++ n++;
++ string_list = g_slist_prepend (string_list, g_strdup (string));
++ }
++
++ str_array = g_new (gchar*, n);
++
++ i = n - 1;
++
++ str_array[i--] = NULL;
++ for (slist = string_list; slist; slist = slist->next)
++ str_array[i--] = slist->data;
++
++ g_slist_free (string_list);
++
++ return str_array;
++}
++
++void
++g_strfreev (gchar **str_array)
++{
++ if (str_array)
++ {
++ int i;
++
++ for(i = 0; str_array[i] != NULL; i++)
++ g_free(str_array[i]);
++
++ g_free (str_array);
++ }
++}
++
++gchar*
++g_strjoinv (const gchar *separator,
++ gchar **str_array)
++{
++ gchar *string;
++
++ g_return_val_if_fail (str_array != NULL, NULL);
++
++ if (separator == NULL)
++ separator = "";
++
++ if (*str_array)
++ {
++ guint i, len;
++ guint separator_len;
++
++ separator_len = strlen (separator);
++ len = 1 + strlen (str_array[0]);
++ for(i = 1; str_array[i] != NULL; i++)
++ len += separator_len + strlen(str_array[i]);
++
++ string = g_new (gchar, len);
++ *string = 0;
++ strcat (string, *str_array);
++ for (i = 1; str_array[i] != NULL; i++)
++ {
++ strcat (string, separator);
++ strcat (string, str_array[i]);
++ }
++ }
++ else
++ string = g_strdup ("");
++
++ return string;
++}
++
++gchar*
++g_strjoin (const gchar *separator,
++ ...)
++{
++ gchar *string, *s;
++ va_list args;
++ guint len;
++ guint separator_len;
++
++ if (separator == NULL)
++ separator = "";
++
++ separator_len = strlen (separator);
++
++ va_start (args, separator);
++
++ s = va_arg (args, gchar*);
++
++ if (s)
++ {
++ len = strlen (s);
++
++ s = va_arg (args, gchar*);
++ while (s)
++ {
++ len += separator_len + strlen (s);
++ s = va_arg (args, gchar*);
++ }
++ va_end (args);
++
++ string = g_new (gchar, len + 1);
++ *string = 0;
++
++ va_start (args, separator);
++
++ s = va_arg (args, gchar*);
++ strcat (string, s);
++
++ s = va_arg (args, gchar*);
++ while (s)
++ {
++ strcat (string, separator);
++ strcat (string, s);
++ s = va_arg (args, gchar*);
++ }
++ }
++ else
++ string = g_strdup ("");
++
++ va_end (args);
++
++ return string;
++}
+diff -urN linux-2.4.1/net/korbit/kglib/gstring.c linux-2.4.1-korbit/net/korbit/kglib/gstring.c
+--- linux-2.4.1/net/korbit/kglib/gstring.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/gstring.c Thu Feb 1 11:46:57 2001
+@@ -0,0 +1,508 @@
++/* GLIB - Library of useful routines for C programming
++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
++ *
++ * 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.
++ */
++
++/*
++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS
++ * file for a list of people on the GLib Team. See the ChangeLog
++ * files for a list of changes. These files are distributed with
++ * GLib at ftp://ftp.gtk.org/pub/gtk/.
++ */
++
++#include <stdarg.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <ctype.h>
++#include "glib.h"
++
++
++typedef struct _GRealStringChunk GRealStringChunk;
++typedef struct _GRealString GRealString;
++
++struct _GRealStringChunk
++{
++ GHashTable *const_table;
++ GSList *storage_list;
++ gint storage_next;
++ gint this_size;
++ gint default_size;
++};
++
++struct _GRealString
++{
++ gchar *str;
++ gint len;
++ gint alloc;
++};
++
++G_LOCK_DEFINE_STATIC (string_mem_chunk);
++static GMemChunk *string_mem_chunk = NULL;
++
++/* Hash Functions.
++ */
++
++gint
++g_str_equal (gconstpointer v, gconstpointer v2)
++{
++ return strcmp ((const gchar*) v, (const gchar*)v2) == 0;
++}
++
++/* 31 bit hash function */
++guint
++g_str_hash (gconstpointer key)
++{
++ const char *p = key;
++ guint h = *p;
++
++ if (h)
++ for (p += 1; *p != '\0'; p++)
++ h = (h << 5) - h + *p;
++
++ return h;
++}
++
++/* String Chunks.
++ */
++
++GStringChunk*
++g_string_chunk_new (gint default_size)
++{
++ GRealStringChunk *new_chunk = g_new (GRealStringChunk, 1);
++ gint size = 1;
++
++ while (size < default_size)
++ size <<= 1;
++
++ new_chunk->const_table = NULL;
++ new_chunk->storage_list = NULL;
++ new_chunk->storage_next = size;
++ new_chunk->default_size = size;
++ new_chunk->this_size = size;
++
++ return (GStringChunk*) new_chunk;
++}
++
++void
++g_string_chunk_free (GStringChunk *fchunk)
++{
++ GRealStringChunk *chunk = (GRealStringChunk*) fchunk;
++ GSList *tmp_list;
++
++ g_return_if_fail (chunk != NULL);
++
++ if (chunk->storage_list)
++ {
++ for (tmp_list = chunk->storage_list; tmp_list; tmp_list = tmp_list->next)
++ g_free (tmp_list->data);
++
++ g_slist_free (chunk->storage_list);
++ }
++
++ if (chunk->const_table)
++ g_hash_table_destroy (chunk->const_table);
++
++ g_free (chunk);
++}
++
++gchar*
++g_string_chunk_insert (GStringChunk *fchunk,
++ const gchar *string)
++{
++ GRealStringChunk *chunk = (GRealStringChunk*) fchunk;
++ gint len = strlen (string);
++ char* pos;
++
++ g_return_val_if_fail (chunk != NULL, NULL);
++
++ if ((chunk->storage_next + len + 1) > chunk->this_size)
++ {
++ gint new_size = chunk->default_size;
++
++ while (new_size < len+1)
++ new_size <<= 1;
++
++ chunk->storage_list = g_slist_prepend (chunk->storage_list,
++ g_new (char, new_size));
++
++ chunk->this_size = new_size;
++ chunk->storage_next = 0;
++ }
++
++ pos = ((char*)chunk->storage_list->data) + chunk->storage_next;
++
++ strcpy (pos, string);
++
++ chunk->storage_next += len + 1;
++
++ return pos;
++}
++
++gchar*
++g_string_chunk_insert_const (GStringChunk *fchunk,
++ const gchar *string)
++{
++ GRealStringChunk *chunk = (GRealStringChunk*) fchunk;
++ char* lookup;
++
++ g_return_val_if_fail (chunk != NULL, NULL);
++
++ if (!chunk->const_table)
++ chunk->const_table = g_hash_table_new (g_str_hash, g_str_equal);
++
++ lookup = (char*) g_hash_table_lookup (chunk->const_table, (gchar *)string);
++
++ if (!lookup)
++ {
++ lookup = g_string_chunk_insert (fchunk, string);
++ g_hash_table_insert (chunk->const_table, lookup, lookup);
++ }
++
++ return lookup;
++}
++
++/* Strings.
++ */
++static gint
++nearest_pow (gint num)
++{
++ gint n = 1;
++
++ while (n < num)
++ n <<= 1;
++
++ return n;
++}
++
++static void
++g_string_maybe_expand (GRealString* string, gint len)
++{
++ if (string->len + len >= string->alloc)
++ {
++ string->alloc = nearest_pow (string->len + len + 1);
++ string->str = g_realloc (string->str, string->alloc);
++ }
++}
++
++GString*
++g_string_sized_new (guint dfl_size)
++{
++ GRealString *string;
++
++ G_LOCK (string_mem_chunk);
++ if (!string_mem_chunk)
++ string_mem_chunk = g_mem_chunk_new ("string mem chunk",
++ sizeof (GRealString),
++ 1024, G_ALLOC_AND_FREE);
++
++ string = g_chunk_new (GRealString, string_mem_chunk);
++ G_UNLOCK (string_mem_chunk);
++
++ string->alloc = 0;
++ string->len = 0;
++ string->str = NULL;
++
++ g_string_maybe_expand (string, MAX (dfl_size, 2));
++ string->str[0] = 0;
++
++ return (GString*) string;
++}
++
++GString*
++g_string_new (const gchar *init)
++{
++ GString *string;
++
++ string = g_string_sized_new (2);
++
++ if (init)
++ g_string_append (string, init);
++
++ return string;
++}
++
++void
++g_string_free (GString *string,
++ gint free_segment)
++{
++ g_return_if_fail (string != NULL);
++
++ if (free_segment)
++ g_free (string->str);
++
++ G_LOCK (string_mem_chunk);
++ g_mem_chunk_free (string_mem_chunk, string);
++ G_UNLOCK (string_mem_chunk);
++}
++
++GString*
++g_string_assign (GString *lval,
++ const gchar *rval)
++{
++ g_return_val_if_fail (lval != NULL, NULL);
++ g_return_val_if_fail (rval != NULL, NULL);
++
++ g_string_truncate (lval, 0);
++ g_string_append (lval, rval);
++
++ return lval;
++}
++
++GString*
++g_string_truncate (GString* fstring,
++ gint len)
++{
++ GRealString *string = (GRealString*)fstring;
++
++ g_return_val_if_fail (string != NULL, NULL);
++ g_return_val_if_fail (len >= 0, NULL);
++
++ string->len = len;
++
++ string->str[len] = 0;
++
++ return fstring;
++}
++
++GString*
++g_string_append (GString *fstring,
++ const gchar *val)
++{
++ GRealString *string = (GRealString*)fstring;
++ int len;
++
++ g_return_val_if_fail (string != NULL, NULL);
++ g_return_val_if_fail (val != NULL, fstring);
++
++ len = strlen (val);
++ g_string_maybe_expand (string, len);
++
++ strcpy (string->str + string->len, val);
++
++ string->len += len;
++
++ return fstring;
++}
++
++GString*
++g_string_append_c (GString *fstring,
++ gchar c)
++{
++ GRealString *string = (GRealString*)fstring;
++
++ g_return_val_if_fail (string != NULL, NULL);
++ g_string_maybe_expand (string, 1);
++
++ string->str[string->len++] = c;
++ string->str[string->len] = 0;
++
++ return fstring;
++}
++
++GString*
++g_string_prepend (GString *fstring,
++ const gchar *val)
++{
++ GRealString *string = (GRealString*)fstring;
++ gint len;
++
++ g_return_val_if_fail (string != NULL, NULL);
++ g_return_val_if_fail (val != NULL, fstring);
++
++ len = strlen (val);
++ g_string_maybe_expand (string, len);
++
++ g_memmove (string->str + len, string->str, string->len);
++
++ strncpy (string->str, val, len);
++
++ string->len += len;
++
++ string->str[string->len] = 0;
++
++ return fstring;
++}
++
++GString*
++g_string_prepend_c (GString *fstring,
++ gchar c)
++{
++ GRealString *string = (GRealString*)fstring;
++
++ g_return_val_if_fail (string != NULL, NULL);
++ g_string_maybe_expand (string, 1);
++
++ g_memmove (string->str + 1, string->str, string->len);
++
++ string->str[0] = c;
++
++ string->len += 1;
++
++ string->str[string->len] = 0;
++
++ return fstring;
++}
++
++GString*
++g_string_insert (GString *fstring,
++ gint pos,
++ const gchar *val)
++{
++ GRealString *string = (GRealString*)fstring;
++ gint len;
++
++ g_return_val_if_fail (string != NULL, NULL);
++ g_return_val_if_fail (val != NULL, fstring);
++ g_return_val_if_fail (pos >= 0, fstring);
++ g_return_val_if_fail (pos <= string->len, fstring);
++
++ len = strlen (val);
++ g_string_maybe_expand (string, len);
++
++ g_memmove (string->str + pos + len, string->str + pos, string->len - pos);
++
++ strncpy (string->str + pos, val, len);
++
++ string->len += len;
++
++ string->str[string->len] = 0;
++
++ return fstring;
++}
++
++GString *
++g_string_insert_c (GString *fstring,
++ gint pos,
++ gchar c)
++{
++ GRealString *string = (GRealString*)fstring;
++
++ g_return_val_if_fail (string != NULL, NULL);
++ g_return_val_if_fail (pos <= string->len, fstring);
++
++ g_string_maybe_expand (string, 1);
++
++ g_memmove (string->str + pos + 1, string->str + pos, string->len - pos);
++
++ string->str[pos] = c;
++
++ string->len += 1;
++
++ string->str[string->len] = 0;
++
++ return fstring;
++}
++
++GString*
++g_string_erase (GString *fstring,
++ gint pos,
++ gint len)
++{
++ GRealString *string = (GRealString*)fstring;
++
++ g_return_val_if_fail (string != NULL, NULL);
++ g_return_val_if_fail (len >= 0, fstring);
++ g_return_val_if_fail (pos >= 0, fstring);
++ g_return_val_if_fail (pos <= string->len, fstring);
++ g_return_val_if_fail (pos + len <= string->len, fstring);
++
++ if (pos + len < string->len)
++ g_memmove (string->str + pos, string->str + pos + len, string->len - (pos + len));
++
++ string->len -= len;
++
++ string->str[string->len] = 0;
++
++ return fstring;
++}
++
++GString*
++g_string_down (GString *fstring)
++{
++ GRealString *string = (GRealString*)fstring;
++ guchar *s;
++
++ g_return_val_if_fail (string != NULL, NULL);
++
++ s = string->str;
++
++ while (*s)
++ {
++ *s = tolower (*s);
++ s++;
++ }
++
++ return fstring;
++}
++
++GString*
++g_string_up (GString *fstring)
++{
++ GRealString *string = (GRealString*)fstring;
++ guchar *s;
++
++ g_return_val_if_fail (string != NULL, NULL);
++
++ s = string->str;
++
++ while (*s)
++ {
++ *s = toupper (*s);
++ s++;
++ }
++
++ return fstring;
++}
++
++static void
++g_string_sprintfa_int (GString *string,
++ const gchar *fmt,
++ va_list args)
++{
++ gchar *buffer;
++
++ buffer = g_strdup_vprintf (fmt, args);
++ g_string_append (string, buffer);
++ g_free (buffer);
++}
++
++void
++g_string_sprintf (GString *string,
++ const gchar *fmt,
++ ...)
++{
++ va_list args;
++
++ g_string_truncate (string, 0);
++
++ va_start (args, fmt);
++ g_string_sprintfa_int (string, fmt, args);
++ va_end (args);
++}
++
++void
++g_string_sprintfa (GString *string,
++ const gchar *fmt,
++ ...)
++{
++ va_list args;
++
++ va_start (args, fmt);
++ g_string_sprintfa_int (string, fmt, args);
++ va_end (args);
++}
+diff -urN linux-2.4.1/net/korbit/kglib/gtree.c linux-2.4.1-korbit/net/korbit/kglib/gtree.c
+--- linux-2.4.1/net/korbit/kglib/gtree.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/gtree.c Thu Feb 1 11:46:57 2001
+@@ -0,0 +1,740 @@
++/* GLIB - Library of useful routines for C programming
++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
++ *
++ * 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.
++ */
++
++/*
++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS
++ * file for a list of people on the GLib Team. See the ChangeLog
++ * files for a list of changes. These files are distributed with
++ * GLib at ftp://ftp.gtk.org/pub/gtk/.
++ */
++
++#include "glib.h"
++
++
++typedef struct _GRealTree GRealTree;
++typedef struct _GTreeNode GTreeNode;
++
++struct _GRealTree
++{
++ GTreeNode *root;
++ GCompareFunc key_compare;
++};
++
++struct _GTreeNode
++{
++ gint balance; /* height (left) - height (right) */
++ GTreeNode *left; /* left subtree */
++ GTreeNode *right; /* right subtree */
++ gpointer key; /* key for this node */
++ gpointer value; /* value stored at this node */
++};
++
++
++static GTreeNode* g_tree_node_new (gpointer key,
++ gpointer value);
++static void g_tree_node_destroy (GTreeNode *node);
++static GTreeNode* g_tree_node_insert (GTreeNode *node,
++ GCompareFunc compare,
++ gpointer key,
++ gpointer value,
++ gint *inserted);
++static GTreeNode* g_tree_node_remove (GTreeNode *node,
++ GCompareFunc compare,
++ gpointer key);
++static GTreeNode* g_tree_node_balance (GTreeNode *node);
++static GTreeNode* g_tree_node_remove_leftmost (GTreeNode *node,
++ GTreeNode **leftmost);
++static GTreeNode* g_tree_node_restore_left_balance (GTreeNode *node,
++ gint old_balance);
++static GTreeNode* g_tree_node_restore_right_balance (GTreeNode *node,
++ gint old_balance);
++static gpointer g_tree_node_lookup (GTreeNode *node,
++ GCompareFunc compare,
++ gpointer key);
++static gint g_tree_node_count (GTreeNode *node);
++static gint g_tree_node_pre_order (GTreeNode *node,
++ GTraverseFunc traverse_func,
++ gpointer data);
++static gint g_tree_node_in_order (GTreeNode *node,
++ GTraverseFunc traverse_func,
++ gpointer data);
++static gint g_tree_node_post_order (GTreeNode *node,
++ GTraverseFunc traverse_func,
++ gpointer data);
++static gpointer g_tree_node_search (GTreeNode *node,
++ GSearchFunc search_func,
++ gpointer data);
++static gint g_tree_node_height (GTreeNode *node);
++static GTreeNode* g_tree_node_rotate_left (GTreeNode *node);
++static GTreeNode* g_tree_node_rotate_right (GTreeNode *node);
++static void g_tree_node_check (GTreeNode *node);
++
++
++G_LOCK_DEFINE_STATIC (g_tree_global);
++static GMemChunk *node_mem_chunk = NULL;
++static GTreeNode *node_free_list = NULL;
++
++
++static GTreeNode*
++g_tree_node_new (gpointer key,
++ gpointer value)
++{
++ GTreeNode *node;
++
++ G_LOCK (g_tree_global);
++ if (node_free_list)
++ {
++ node = node_free_list;
++ node_free_list = node->right;
++ }
++ else
++ {
++ if (!node_mem_chunk)
++ node_mem_chunk = g_mem_chunk_new ("GLib GTreeNode mem chunk",
++ sizeof (GTreeNode),
++ 1024,
++ G_ALLOC_ONLY);
++
++ node = g_chunk_new (GTreeNode, node_mem_chunk);
++ }
++ G_UNLOCK (g_tree_global);
++
++ node->balance = 0;
++ node->left = NULL;
++ node->right = NULL;
++ node->key = key;
++ node->value = value;
++
++ return node;
++}
++
++static void
++g_tree_node_destroy (GTreeNode *node)
++{
++ if (node)
++ {
++ g_tree_node_destroy (node->right);
++ g_tree_node_destroy (node->left);
++ G_LOCK (g_tree_global);
++ node->right = node_free_list;
++ node_free_list = node;
++ G_UNLOCK (g_tree_global);
++ }
++}
++
++
++GTree*
++g_tree_new (GCompareFunc key_compare_func)
++{
++ GRealTree *rtree;
++
++ g_return_val_if_fail (key_compare_func != NULL, NULL);
++
++ rtree = g_new (GRealTree, 1);
++ rtree->root = NULL;
++ rtree->key_compare = key_compare_func;
++
++ return (GTree*) rtree;
++}
++
++void
++g_tree_destroy (GTree *tree)
++{
++ GRealTree *rtree;
++
++ g_return_if_fail (tree != NULL);
++
++ rtree = (GRealTree*) tree;
++
++ g_tree_node_destroy (rtree->root);
++ g_free (rtree);
++}
++
++void
++g_tree_insert (GTree *tree,
++ gpointer key,
++ gpointer value)
++{
++ GRealTree *rtree;
++ gint inserted;
++
++ g_return_if_fail (tree != NULL);
++
++ rtree = (GRealTree*) tree;
++
++ inserted = FALSE;
++ rtree->root = g_tree_node_insert (rtree->root, rtree->key_compare,
++ key, value, &inserted);
++}
++
++void
++g_tree_remove (GTree *tree,
++ gpointer key)
++{
++ GRealTree *rtree;
++
++ g_return_if_fail (tree != NULL);
++
++ rtree = (GRealTree*) tree;
++
++ rtree->root = g_tree_node_remove (rtree->root, rtree->key_compare, key);
++}
++
++gpointer
++g_tree_lookup (GTree *tree,
++ gpointer key)
++{
++ GRealTree *rtree;
++
++ g_return_val_if_fail (tree != NULL, NULL);
++
++ rtree = (GRealTree*) tree;
++
++ return g_tree_node_lookup (rtree->root, rtree->key_compare, key);
++}
++
++void
++g_tree_traverse (GTree *tree,
++ GTraverseFunc traverse_func,
++ GTraverseType traverse_type,
++ gpointer data)
++{
++ GRealTree *rtree;
++
++ g_return_if_fail (tree != NULL);
++
++ rtree = (GRealTree*) tree;
++
++ if (!rtree->root)
++ return;
++
++ switch (traverse_type)
++ {
++ case G_PRE_ORDER:
++ g_tree_node_pre_order (rtree->root, traverse_func, data);
++ break;
++
++ case G_IN_ORDER:
++ g_tree_node_in_order (rtree->root, traverse_func, data);
++ break;
++
++ case G_POST_ORDER:
++ g_tree_node_post_order (rtree->root, traverse_func, data);
++ break;
++
++ case G_LEVEL_ORDER:
++ g_warning ("g_tree_traverse(): traverse type G_LEVEL_ORDER isn't implemented.");
++ break;
++ }
++}
++
++gpointer
++g_tree_search (GTree *tree,
++ GSearchFunc search_func,
++ gpointer data)
++{
++ GRealTree *rtree;
++
++ g_return_val_if_fail (tree != NULL, NULL);
++
++ rtree = (GRealTree*) tree;
++
++ if (rtree->root)
++ return g_tree_node_search (rtree->root, search_func, data);
++ else
++ return NULL;
++}
++
++gint
++g_tree_height (GTree *tree)
++{
++ GRealTree *rtree;
++
++ g_return_val_if_fail (tree != NULL, 0);
++
++ rtree = (GRealTree*) tree;
++
++ if (rtree->root)
++ return g_tree_node_height (rtree->root);
++ else
++ return 0;
++}
++
++gint
++g_tree_nnodes (GTree *tree)
++{
++ GRealTree *rtree;
++
++ g_return_val_if_fail (tree != NULL, 0);
++
++ rtree = (GRealTree*) tree;
++
++ if (rtree->root)
++ return g_tree_node_count (rtree->root);
++ else
++ return 0;
++}
++
++static GTreeNode*
++g_tree_node_insert (GTreeNode *node,
++ GCompareFunc compare,
++ gpointer key,
++ gpointer value,
++ gint *inserted)
++{
++ gint old_balance;
++ gint cmp;
++
++ if (!node)
++ {
++ *inserted = TRUE;
++ return g_tree_node_new (key, value);
++ }
++
++ cmp = (* compare) (key, node->key);
++ if (cmp == 0)
++ {
++ *inserted = FALSE;
++ node->value = value;
++ return node;
++ }
++
++ if (cmp < 0)
++ {
++ if (node->left)
++ {
++ old_balance = node->left->balance;
++ node->left = g_tree_node_insert (node->left, compare, key, value, inserted);
++
++ if ((old_balance != node->left->balance) && node->left->balance)
++ node->balance -= 1;
++ }
++ else
++ {
++ *inserted = TRUE;
++ node->left = g_tree_node_new (key, value);
++ node->balance -= 1;
++ }
++ }
++ else if (cmp > 0)
++ {
++ if (node->right)
++ {
++ old_balance = node->right->balance;
++ node->right = g_tree_node_insert (node->right, compare, key, value, inserted);
++
++ if ((old_balance != node->right->balance) && node->right->balance)
++ node->balance += 1;
++ }
++ else
++ {
++ *inserted = TRUE;
++ node->right = g_tree_node_new (key, value);
++ node->balance += 1;
++ }
++ }
++
++ if (*inserted)
++ {
++ if ((node->balance < -1) || (node->balance > 1))
++ node = g_tree_node_balance (node);
++ }
++
++ return node;
++}
++
++static GTreeNode*
++g_tree_node_remove (GTreeNode *node,
++ GCompareFunc compare,
++ gpointer key)
++{
++ GTreeNode *new_root;
++ gint old_balance;
++ gint cmp;
++
++ if (!node)
++ return NULL;
++
++ cmp = (* compare) (key, node->key);
++ if (cmp == 0)
++ {
++ GTreeNode *garbage;
++
++ garbage = node;
++
++ if (!node->right)
++ {
++ node = node->left;
++ }
++ else
++ {
++ old_balance = node->right->balance;
++ node->right = g_tree_node_remove_leftmost (node->right, &new_root);
++ new_root->left = node->left;
++ new_root->right = node->right;
++ new_root->balance = node->balance;
++ node = g_tree_node_restore_right_balance (new_root, old_balance);
++ }
++
++ G_LOCK (g_tree_global);
++ garbage->right = node_free_list;
++ node_free_list = garbage;
++ G_UNLOCK (g_tree_global);
++ }
++ else if (cmp < 0)
++ {
++ if (node->left)
++ {
++ old_balance = node->left->balance;
++ node->left = g_tree_node_remove (node->left, compare, key);
++ node = g_tree_node_restore_left_balance (node, old_balance);
++ }
++ }
++ else if (cmp > 0)
++ {
++ if (node->right)
++ {
++ old_balance = node->right->balance;
++ node->right = g_tree_node_remove (node->right, compare, key);
++ node = g_tree_node_restore_right_balance (node, old_balance);
++ }
++ }
++
++ return node;
++}
++
++static GTreeNode*
++g_tree_node_balance (GTreeNode *node)
++{
++ if (node->balance < -1)
++ {
++ if (node->left->balance > 0)
++ node->left = g_tree_node_rotate_left (node->left);
++ node = g_tree_node_rotate_right (node);
++ }
++ else if (node->balance > 1)
++ {
++ if (node->right->balance < 0)
++ node->right = g_tree_node_rotate_right (node->right);
++ node = g_tree_node_rotate_left (node);
++ }
++
++ return node;
++}
++
++static GTreeNode*
++g_tree_node_remove_leftmost (GTreeNode *node,
++ GTreeNode **leftmost)
++{
++ gint old_balance;
++
++ if (!node->left)
++ {
++ *leftmost = node;
++ return node->right;
++ }
++
++ old_balance = node->left->balance;
++ node->left = g_tree_node_remove_leftmost (node->left, leftmost);
++ return g_tree_node_restore_left_balance (node, old_balance);
++}
++
++static GTreeNode*
++g_tree_node_restore_left_balance (GTreeNode *node,
++ gint old_balance)
++{
++ if (!node->left)
++ node->balance += 1;
++ else if ((node->left->balance != old_balance) &&
++ (node->left->balance == 0))
++ node->balance += 1;
++
++ if (node->balance > 1)
++ return g_tree_node_balance (node);
++ return node;
++}
++
++static GTreeNode*
++g_tree_node_restore_right_balance (GTreeNode *node,
++ gint old_balance)
++{
++ if (!node->right)
++ node->balance -= 1;
++ else if ((node->right->balance != old_balance) &&
++ (node->right->balance == 0))
++ node->balance -= 1;
++
++ if (node->balance < -1)
++ return g_tree_node_balance (node);
++ return node;
++}
++
++static gpointer
++g_tree_node_lookup (GTreeNode *node,
++ GCompareFunc compare,
++ gpointer key)
++{
++ gint cmp;
++
++ if (!node)
++ return NULL;
++
++ cmp = (* compare) (key, node->key);
++ if (cmp == 0)
++ return node->value;
++
++ if (cmp < 0)
++ {
++ if (node->left)
++ return g_tree_node_lookup (node->left, compare, key);
++ }
++ else if (cmp > 0)
++ {
++ if (node->right)
++ return g_tree_node_lookup (node->right, compare, key);
++ }
++
++ return NULL;
++}
++
++static gint
++g_tree_node_count (GTreeNode *node)
++{
++ gint count;
++
++ count = 1;
++ if (node->left)
++ count += g_tree_node_count (node->left);
++ if (node->right)
++ count += g_tree_node_count (node->right);
++
++ return count;
++}
++
++static gint
++g_tree_node_pre_order (GTreeNode *node,
++ GTraverseFunc traverse_func,
++ gpointer data)
++{
++ if ((*traverse_func) (node->key, node->value, data))
++ return TRUE;
++ if (node->left)
++ {
++ if (g_tree_node_pre_order (node->left, traverse_func, data))
++ return TRUE;
++ }
++ if (node->right)
++ {
++ if (g_tree_node_pre_order (node->right, traverse_func, data))
++ return TRUE;
++ }
++
++ return FALSE;
++}
++
++static gint
++g_tree_node_in_order (GTreeNode *node,
++ GTraverseFunc traverse_func,
++ gpointer data)
++{
++ if (node->left)
++ {
++ if (g_tree_node_in_order (node->left, traverse_func, data))
++ return TRUE;
++ }
++ if ((*traverse_func) (node->key, node->value, data))
++ return TRUE;
++ if (node->right)
++ {
++ if (g_tree_node_in_order (node->right, traverse_func, data))
++ return TRUE;
++ }
++
++ return FALSE;
++}
++
++static gint
++g_tree_node_post_order (GTreeNode *node,
++ GTraverseFunc traverse_func,
++ gpointer data)
++{
++ if (node->left)
++ {
++ if (g_tree_node_post_order (node->left, traverse_func, data))
++ return TRUE;
++ }
++ if (node->right)
++ {
++ if (g_tree_node_post_order (node->right, traverse_func, data))
++ return TRUE;
++ }
++ if ((*traverse_func) (node->key, node->value, data))
++ return TRUE;
++
++ return FALSE;
++}
++
++static gpointer
++g_tree_node_search (GTreeNode *node,
++ GSearchFunc search_func,
++ gpointer data)
++{
++ gint dir;
++
++ if (!node)
++ return NULL;
++
++ do {
++ dir = (* search_func) (node->key, data);
++ if (dir == 0)
++ return node->value;
++
++ if (dir < 0)
++ node = node->left;
++ else if (dir > 0)
++ node = node->right;
++ } while (node && (dir != 0));
++
++ return NULL;
++}
++
++static gint
++g_tree_node_height (GTreeNode *node)
++{
++ gint left_height;
++ gint right_height;
++
++ if (node)
++ {
++ left_height = 0;
++ right_height = 0;
++
++ if (node->left)
++ left_height = g_tree_node_height (node->left);
++
++ if (node->right)
++ right_height = g_tree_node_height (node->right);
++
++ return MAX (left_height, right_height) + 1;
++ }
++
++ return 0;
++}
++
++static GTreeNode*
++g_tree_node_rotate_left (GTreeNode *node)
++{
++ GTreeNode *left;
++ GTreeNode *right;
++ gint a_bal;
++ gint b_bal;
++
++ left = node->left;
++ right = node->right;
++
++ node->right = right->left;
++ right->left = node;
++
++ a_bal = node->balance;
++ b_bal = right->balance;
++
++ if (b_bal <= 0)
++ {
++ if (a_bal >= 1)
++ right->balance = b_bal - 1;
++ else
++ right->balance = a_bal + b_bal - 2;
++ node->balance = a_bal - 1;
++ }
++ else
++ {
++ if (a_bal <= b_bal)
++ right->balance = a_bal - 2;
++ else
++ right->balance = b_bal - 1;
++ node->balance = a_bal - b_bal - 1;
++ }
++
++ return right;
++}
++
++static GTreeNode*
++g_tree_node_rotate_right (GTreeNode *node)
++{
++ GTreeNode *left;
++ gint a_bal;
++ gint b_bal;
++
++ left = node->left;
++
++ node->left = left->right;
++ left->right = node;
++
++ a_bal = node->balance;
++ b_bal = left->balance;
++
++ if (b_bal <= 0)
++ {
++ if (b_bal > a_bal)
++ left->balance = b_bal + 1;
++ else
++ left->balance = a_bal + 2;
++ node->balance = a_bal - b_bal + 1;
++ }
++ else
++ {
++ if (a_bal <= -1)
++ left->balance = b_bal + 1;
++ else
++ left->balance = a_bal + b_bal + 2;
++ node->balance = a_bal + 1;
++ }
++
++ return left;
++}
++
++static void
++g_tree_node_check (GTreeNode *node)
++{
++ gint left_height;
++ gint right_height;
++ gint balance;
++
++ if (node)
++ {
++ left_height = 0;
++ right_height = 0;
++
++ if (node->left)
++ left_height = g_tree_node_height (node->left);
++ if (node->right)
++ right_height = g_tree_node_height (node->right);
++
++ balance = right_height - left_height;
++ if (balance != node->balance)
++ g_log (g_log_domain_glib, G_LOG_LEVEL_INFO,
++ "g_tree_node_check: failed: %d ( %d )\n",
++ balance, node->balance);
++
++ if (node->left)
++ g_tree_node_check (node->left);
++ if (node->right)
++ g_tree_node_check (node->right);
++ }
++}
+diff -urN linux-2.4.1/net/korbit/kglib/gutils.c linux-2.4.1-korbit/net/korbit/kglib/gutils.c
+--- linux-2.4.1/net/korbit/kglib/gutils.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/gutils.c Thu Feb 1 11:46:57 2001
+@@ -0,0 +1,915 @@
++/* GLIB - Library of useful routines for C programming
++ * Copyright (C) 1995-1998 Peter Mattis, Spencer Kimball and Josh MacDonald
++ *
++ * 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.
++ */
++
++/*
++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS
++ * file for a list of people on the GLib Team. See the ChangeLog
++ * files for a list of changes. These files are distributed with
++ * GLib at ftp://ftp.gtk.org/pub/gtk/.
++ */
++
++#define G_INLINE_FUNC extern
++#define G_CAN_INLINE 1
++
++#ifdef HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <stdarg.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <errno.h>
++#ifdef HAVE_PWD_H
++#include <pwd.h>
++#endif
++#include <sys/types.h>
++#ifdef HAVE_SYS_PARAM_H
++#include <sys/param.h>
++#endif
++
++#ifdef NATIVE_WIN32
++# define STRICT /* Strict typing, please */
++# include <windows.h>
++# include <direct.h>
++# include <errno.h>
++# include <ctype.h>
++# ifdef _MSC_VER
++# include <io.h>
++# endif /* _MSC_VER */
++#endif /* NATIVE_WIN32 */
++
++/* implement Glib's inline functions
++ */
++#include "glib.h"
++
++#ifdef MAXPATHLEN
++#define G_PATH_LENGTH (MAXPATHLEN + 1)
++#elif defined (PATH_MAX)
++#define G_PATH_LENGTH (PATH_MAX + 1)
++#else /* !MAXPATHLEN */
++#define G_PATH_LENGTH (2048 + 1)
++#endif /* !MAXPATHLEN && !PATH_MAX */
++
++const guint glib_major_version = 1;
++const guint glib_minor_version = 2;
++const guint glib_micro_version = 8;
++const guint glib_interface_age = 8;
++const guint glib_binary_age = 8;
++
++#if defined (NATIVE_WIN32) && defined (__LCC__)
++int __stdcall
++LibMain (void *hinstDll,
++ unsigned long dwReason,
++ void *reserved)
++{
++ return 1;
++}
++#endif /* NATIVE_WIN32 && __LCC__ */
++
++void
++g_atexit (GVoidFunc func)
++{
++ gint result;
++ gchar *error = NULL;
++
++ /* keep this in sync with glib.h */
++
++#ifdef G_NATIVE_ATEXIT
++ result = ATEXIT (func);
++ if (result)
++ error = g_strerror (errno);
++#elif defined (HAVE_ATEXIT)
++# ifdef NeXT /* @#%@! NeXTStep */
++ result = !atexit ((void (*)(void)) func);
++ if (result)
++ error = g_strerror (errno);
++# else
++ result = atexit ((void (*)(void)) func);
++ if (result)
++ error = g_strerror (errno);
++# endif /* NeXT */
++#elif defined (HAVE_ON_EXIT)
++ result = on_exit ((void (*)(int, void *)) func, NULL);
++ if (result)
++ error = g_strerror (errno);
++#else
++ result = 0;
++ error = "no implementation";
++#endif /* G_NATIVE_ATEXIT */
++
++ if (error)
++ g_error ("Could not register atexit() function: %s", error);
++}
++
++gint
++g_snprintf (gchar *str,
++ gulong n,
++ gchar const *fmt,
++ ...)
++{
++#ifdef HAVE_VSNPRINTF
++ va_list args;
++ gint retval;
++
++ g_return_val_if_fail (str != NULL, 0);
++ g_return_val_if_fail (n > 0, 0);
++ g_return_val_if_fail (fmt != NULL, 0);
++
++ va_start (args, fmt);
++ retval = vsnprintf (str, n, fmt, args);
++ va_end (args);
++
++ if (retval < 0)
++ {
++ str[n-1] = '\0';
++ retval = strlen (str);
++ }
++
++ return retval;
++#else /* !HAVE_VSNPRINTF */
++ gchar *printed;
++ va_list args;
++
++ g_return_val_if_fail (str != NULL, 0);
++ g_return_val_if_fail (n > 0, 0);
++ g_return_val_if_fail (fmt != NULL, 0);
++
++ va_start (args, fmt);
++ printed = g_strdup_vprintf (fmt, args);
++ va_end (args);
++
++ strncpy (str, printed, n);
++ str[n-1] = '\0';
++
++ g_free (printed);
++
++ return strlen (str);
++#endif /* !HAVE_VSNPRINTF */
++}
++
++gint
++g_vsnprintf (gchar *str,
++ gulong n,
++ gchar const *fmt,
++ va_list args)
++{
++#ifdef HAVE_VSNPRINTF
++ gint retval;
++
++ g_return_val_if_fail (str != NULL, 0);
++ g_return_val_if_fail (n > 0, 0);
++ g_return_val_if_fail (fmt != NULL, 0);
++
++ retval = vsnprintf (str, n, fmt, args);
++
++ if (retval < 0)
++ {
++ str[n-1] = '\0';
++ retval = strlen (str);
++ }
++
++ return retval;
++#else /* !HAVE_VSNPRINTF */
++ gchar *printed;
++
++ g_return_val_if_fail (str != NULL, 0);
++ g_return_val_if_fail (n > 0, 0);
++ g_return_val_if_fail (fmt != NULL, 0);
++
++ printed = g_strdup_vprintf (fmt, args);
++ strncpy (str, printed, n);
++ str[n-1] = '\0';
++
++ g_free (printed);
++
++ return strlen (str);
++#endif /* !HAVE_VSNPRINTF */
++}
++
++guint
++g_parse_debug_string (const gchar *string,
++ GDebugKey *keys,
++ guint nkeys)
++{
++ guint i;
++ guint result = 0;
++
++ g_return_val_if_fail (string != NULL, 0);
++
++ if (!g_strcasecmp (string, "all"))
++ {
++ for (i=0; i<nkeys; i++)
++ result |= keys[i].value;
++ }
++ else
++ {
++ gchar *str = g_strdup (string);
++ gchar *p = str;
++ gchar *q;
++ gboolean done = FALSE;
++
++ while (*p && !done)
++ {
++ q = strchr (p, ':');
++ if (!q)
++ {
++ q = p + strlen(p);
++ done = TRUE;
++ }
++
++ *q = 0;
++
++ for (i=0; i<nkeys; i++)
++ if (!g_strcasecmp(keys[i].key, p))
++ result |= keys[i].value;
++
++ p = q+1;
++ }
++
++ g_free (str);
++ }
++
++ return result;
++}
++
++gchar*
++g_basename (const gchar *file_name)
++{
++ register gchar *base;
++
++ g_return_val_if_fail (file_name != NULL, NULL);
++
++ base = strrchr (file_name, G_DIR_SEPARATOR);
++ if (base)
++ return base + 1;
++
++#ifdef NATIVE_WIN32
++ if (isalpha (file_name[0]) && file_name[1] == ':')
++ return (gchar*) file_name + 2;
++#endif /* NATIVE_WIN32 */
++
++ return (gchar*) file_name;
++}
++
++gboolean
++g_path_is_absolute (const gchar *file_name)
++{
++ g_return_val_if_fail (file_name != NULL, FALSE);
++
++ if (file_name[0] == G_DIR_SEPARATOR)
++ return TRUE;
++
++#ifdef NATIVE_WIN32
++ if (isalpha (file_name[0]) && file_name[1] == ':' && file_name[2] == G_DIR_SEPARATOR)
++ return TRUE;
++#endif
++
++ return FALSE;
++}
++
++gchar*
++g_path_skip_root (gchar *file_name)
++{
++ g_return_val_if_fail (file_name != NULL, NULL);
++
++ if (file_name[0] == G_DIR_SEPARATOR)
++ return file_name + 1;
++
++#ifdef NATIVE_WIN32
++ if (isalpha (file_name[0]) && file_name[1] == ':' && file_name[2] == G_DIR_SEPARATOR)
++ return file_name + 3;
++#endif
++
++ return NULL;
++}
++
++gchar*
++g_dirname (const gchar *file_name)
++{
++ register gchar *base;
++ register guint len;
++
++ g_return_val_if_fail (file_name != NULL, NULL);
++
++ base = strrchr (file_name, G_DIR_SEPARATOR);
++ if (!base)
++ return g_strdup (".");
++ while (base > file_name && *base == G_DIR_SEPARATOR)
++ base--;
++ len = (guint) 1 + base - file_name;
++
++ base = g_new (gchar, len + 1);
++ g_memmove (base, file_name, len);
++ base[len] = 0;
++
++ return base;
++}
++
++#ifndef __KORBIT__
++gchar*
++g_get_current_dir (void)
++{
++ gchar *buffer;
++ gchar *dir;
++
++ buffer = g_new (gchar, G_PATH_LENGTH);
++ *buffer = 0;
++
++ /* We don't use getcwd(3) on SUNOS, because, it does a popen("pwd")
++ * and, if that wasn't bad enough, hangs in doing so.
++ */
++#if defined (sun) && !defined (__SVR4)
++ dir = getwd (buffer);
++#else /* !sun */
++ dir = getcwd (buffer, G_PATH_LENGTH - 1);
++#endif /* !sun */
++
++ if (!dir || !*buffer)
++ {
++ /* hm, should we g_error() out here?
++ * this can happen if e.g. "./" has mode \0000
++ */
++ buffer[0] = G_DIR_SEPARATOR;
++ buffer[1] = 0;
++ }
++
++ dir = g_strdup (buffer);
++ g_free (buffer);
++
++ return dir;
++}
++#endif /* !__KORBIT__ */
++
++gchar*
++g_getenv (const gchar *variable)
++{
++#ifndef NATIVE_WIN32
++ g_return_val_if_fail (variable != NULL, NULL);
++
++ return getenv (variable);
++#else
++ gchar *v;
++ guint k;
++ static gchar *p = NULL;
++ static gint l;
++ gchar dummy[2];
++
++ g_return_val_if_fail (variable != NULL, NULL);
++
++ v = getenv (variable);
++ if (!v)
++ return NULL;
++
++ /* On Windows NT, it is relatively typical that environment variables
++ * contain references to other environment variables. Handle that by
++ * calling ExpandEnvironmentStrings.
++ */
++
++ /* First check how much space we need */
++ k = ExpandEnvironmentStrings (v, dummy, 2);
++ /* Then allocate that much, and actualy do the expansion */
++ if (p == NULL)
++ {
++ p = g_malloc (k);
++ l = k;
++ }
++ else if (k > l)
++ {
++ p = g_realloc (p, k);
++ l = k;
++ }
++ ExpandEnvironmentStrings (v, p, k);
++ return p;
++#endif
++}
++
++
++G_LOCK_DEFINE_STATIC (g_utils_global);
++
++static gchar *g_tmp_dir = NULL;
++static gchar *g_user_name = NULL;
++static gchar *g_real_name = NULL;
++static gchar *g_home_dir = NULL;
++
++/* HOLDS: g_utils_global_lock */
++static void
++g_get_any_init (void)
++{
++ if (!g_tmp_dir)
++ {
++ g_tmp_dir = g_strdup (g_getenv ("TMPDIR"));
++ if (!g_tmp_dir)
++ g_tmp_dir = g_strdup (g_getenv ("TMP"));
++ if (!g_tmp_dir)
++ g_tmp_dir = g_strdup (g_getenv ("TEMP"));
++
++#ifdef P_tmpdir
++ if (!g_tmp_dir)
++ {
++ int k;
++ g_tmp_dir = g_strdup (P_tmpdir);
++ k = strlen (g_tmp_dir);
++ if (g_tmp_dir[k-1] == G_DIR_SEPARATOR)
++ g_tmp_dir[k-1] = '\0';
++ }
++#endif
++
++ if (!g_tmp_dir)
++ {
++#ifndef NATIVE_WIN32
++ g_tmp_dir = g_strdup ("/tmp");
++#else /* NATIVE_WIN32 */
++ g_tmp_dir = g_strdup ("C:\\");
++#endif /* NATIVE_WIN32 */
++ }
++
++ if (!g_home_dir)
++ g_home_dir = g_strdup (g_getenv ("HOME"));
++
++#ifdef NATIVE_WIN32
++ if (!g_home_dir)
++ {
++ /* The official way to specify a home directory on NT is
++ * the HOMEDRIVE and HOMEPATH environment variables.
++ *
++ * This is inside #ifdef NATIVE_WIN32 because with the cygwin dll,
++ * HOME should be a POSIX style pathname.
++ */
++
++ if (getenv ("HOMEDRIVE") != NULL && getenv ("HOMEPATH") != NULL)
++ {
++ gchar *homedrive, *homepath;
++
++ homedrive = g_strdup (g_getenv ("HOMEDRIVE"));
++ homepath = g_strdup (g_getenv ("HOMEPATH"));
++
++ g_home_dir = g_strconcat (homedrive, homepath, NULL);
++ g_free (homedrive);
++ g_free (homepath);
++ }
++ }
++#endif /* !NATIVE_WIN32 */
++
++#ifdef HAVE_PWD_H
++ {
++ struct passwd *pw = NULL;
++ gpointer buffer = NULL;
++
++# ifdef HAVE_GETPWUID_R
++ struct passwd pwd;
++ guint bufsize = 64;
++ gint error;
++
++ do
++ {
++ g_free (buffer);
++ buffer = g_malloc (bufsize);
++ errno = 0;
++
++# ifdef HAVE_GETPWUID_R_POSIX
++ error = getpwuid_r (getuid (), &pwd, buffer, bufsize, &pw);
++ error = error < 0 ? errno : error;
++# else /* !HAVE_GETPWUID_R_POSIX */
++# ifdef _AIX
++ error = getpwuid_r (getuid (), &pwd, buffer, bufsize);
++ pw = error == 0 ? &pwd : NULL;
++# else /* !_AIX */
++ pw = getpwuid_r (getuid (), &pwd, buffer, bufsize);
++ error = pw ? 0 : errno;
++# endif /* !_AIX */
++# endif /* !HAVE_GETPWUID_R_POSIX */
++
++ if (!pw)
++ {
++ /* we bail out prematurely if the user id can't be found
++ * (should be pretty rare case actually), or if the buffer
++ * should be sufficiently big and lookups are still not
++ * successfull.
++ */
++ if (error == 0 || error == ENOENT)
++ {
++ g_warning ("getpwuid_r(): failed due to: No such user %d.",
++ getuid ());
++ break;
++ }
++ if (bufsize > 32 * 1024)
++ {
++ g_warning ("getpwuid_r(): failed due to: %s.",
++ g_strerror (error));
++ break;
++ }
++
++ bufsize *= 2;
++ }
++ }
++ while (!pw);
++# endif /* !HAVE_GETPWUID_R */
++
++ if (!pw)
++ {
++ setpwent ();
++ pw = getpwuid (getuid ());
++ endpwent ();
++ }
++ if (pw)
++ {
++ g_user_name = g_strdup (pw->pw_name);
++ g_real_name = g_strdup (pw->pw_gecos);
++ if (!g_home_dir)
++ g_home_dir = g_strdup (pw->pw_dir);
++ }
++ g_free (buffer);
++ }
++
++#else /* !HAVE_PWD_H */
++
++# ifdef NATIVE_WIN32
++ {
++ guint len = 17;
++ gchar buffer[17];
++
++ if (GetUserName (buffer, &len))
++ {
++ g_user_name = g_strdup (buffer);
++ g_real_name = g_strdup (buffer);
++ }
++ }
++# endif /* NATIVE_WIN32 */
++
++#endif /* !HAVE_PWD_H */
++
++ if (!g_user_name)
++ g_user_name = g_strdup ("somebody");
++ if (!g_real_name)
++ g_real_name = g_strdup ("Unknown");
++ else
++ {
++ gchar *p;
++
++ for (p = g_real_name; *p; p++)
++ if (*p == ',')
++ {
++ *p = 0;
++ p = g_strdup (g_real_name);
++ g_free (g_real_name);
++ g_real_name = p;
++ break;
++ }
++ }
++ }
++}
++
++gchar*
++g_get_user_name (void)
++{
++ G_LOCK (g_utils_global);
++ if (!g_tmp_dir)
++ g_get_any_init ();
++ G_UNLOCK (g_utils_global);
++
++ return g_user_name;
++}
++
++gchar*
++g_get_real_name (void)
++{
++ G_LOCK (g_utils_global);
++ if (!g_tmp_dir)
++ g_get_any_init ();
++ G_UNLOCK (g_utils_global);
++
++ return g_real_name;
++}
++
++/* Return the home directory of the user. If there is a HOME
++ * environment variable, its value is returned, otherwise use some
++ * system-dependent way of finding it out. If no home directory can be
++ * deduced, return NULL.
++ */
++
++gchar*
++g_get_home_dir (void)
++{
++ G_LOCK (g_utils_global);
++ if (!g_tmp_dir)
++ g_get_any_init ();
++ G_UNLOCK (g_utils_global);
++
++ return g_home_dir;
++}
++
++/* Return a directory to be used to store temporary files. This is the
++ * value of the TMPDIR, TMP or TEMP environment variables (they are
++ * checked in that order). If none of those exist, use P_tmpdir from
++ * stdio.h. If that isn't defined, return "/tmp" on POSIXly systems,
++ * and C:\ on Windows.
++ */
++
++gchar*
++g_get_tmp_dir (void)
++{
++ G_LOCK (g_utils_global);
++ if (!g_tmp_dir)
++ g_get_any_init ();
++ G_UNLOCK (g_utils_global);
++
++ return g_tmp_dir;
++}
++
++static gchar *g_prgname = NULL;
++
++gchar*
++g_get_prgname (void)
++{
++ gchar* retval;
++
++ G_LOCK (g_utils_global);
++ retval = g_prgname;
++ G_UNLOCK (g_utils_global);
++
++ return retval;
++}
++
++void
++g_set_prgname (const gchar *prgname)
++{
++ gchar *c;
++
++ G_LOCK (g_utils_global);
++ c = g_prgname;
++ g_prgname = g_strdup (prgname);
++ g_free (c);
++ G_UNLOCK (g_utils_global);
++}
++
++guint
++g_direct_hash (gconstpointer v)
++{
++ return GPOINTER_TO_UINT (v);
++}
++
++gint
++g_direct_equal (gconstpointer v1,
++ gconstpointer v2)
++{
++ return v1 == v2;
++}
++
++gint
++g_int_equal (gconstpointer v1,
++ gconstpointer v2)
++{
++ return *((const gint*) v1) == *((const gint*) v2);
++}
++
++guint
++g_int_hash (gconstpointer v)
++{
++ return *(const gint*) v;
++}
++
++#if 0 /* Old IO Channels */
++
++GIOChannel*
++g_iochannel_new (gint fd)
++{
++ GIOChannel *channel = g_new (GIOChannel, 1);
++
++ channel->fd = fd;
++
++#ifdef NATIVE_WIN32
++ channel->peer = 0;
++ channel->peer_fd = 0;
++ channel->offset = 0;
++ channel->need_wakeups = 0;
++#endif /* NATIVE_WIN32 */
++
++ return channel;
++}
++
++void
++g_iochannel_free (GIOChannel *channel)
++{
++ g_return_if_fail (channel != NULL);
++
++ g_free (channel);
++}
++
++void
++g_iochannel_close_and_free (GIOChannel *channel)
++{
++ g_return_if_fail (channel != NULL);
++
++ close (channel->fd);
++
++ g_iochannel_free (channel);
++}
++
++#undef g_iochannel_wakeup_peer
++
++void
++g_iochannel_wakeup_peer (GIOChannel *channel)
++{
++#ifdef NATIVE_WIN32
++ static guint message = 0;
++#endif
++
++ g_return_if_fail (channel != NULL);
++
++#ifdef NATIVE_WIN32
++ if (message == 0)
++ message = RegisterWindowMessage ("gdk-pipe-readable");
++
++# if 0
++ g_print ("g_iochannel_wakeup_peer: calling PostThreadMessage (%#x, %d, %d, %d)\n",
++ channel->peer, message, channel->peer_fd, channel->offset);
++# endif
++ PostThreadMessage (channel->peer, message,
++ channel->peer_fd, channel->offset);
++#endif /* NATIVE_WIN32 */
++}
++
++#endif /* Old IO Channels */
++
++#ifdef NATIVE_WIN32
++#ifdef _MSC_VER
++
++int
++gwin_ftruncate (gint fd,
++ guint size)
++{
++ HANDLE hfile;
++ guint curpos;
++
++ g_return_val_if_fail (fd >= 0, -1);
++
++ hfile = (HANDLE) _get_osfhandle (fd);
++ curpos = SetFilePointer (hfile, 0, NULL, FILE_CURRENT);
++ if (curpos == 0xFFFFFFFF
++ || SetFilePointer (hfile, size, NULL, FILE_BEGIN) == 0xFFFFFFFF
++ || !SetEndOfFile (hfile))
++ {
++ gint error = GetLastError ();
++
++ switch (error)
++ {
++ case ERROR_INVALID_HANDLE:
++ errno = EBADF;
++ break;
++ default:
++ errno = EIO;
++ break;
++ }
++
++ return -1;
++ }
++
++ return 0;
++}
++
++DIR*
++gwin_opendir (const char *dirname)
++{
++ DIR *result;
++ gchar *mask;
++ guint k;
++
++ g_return_val_if_fail (dirname != NULL, NULL);
++
++ result = g_new0 (DIR, 1);
++ result->find_file_data = g_new0 (WIN32_FIND_DATA, 1);
++ result->dir_name = g_strdup (dirname);
++
++ k = strlen (result->dir_name);
++ if (k && result->dir_name[k - 1] == '\\')
++ {
++ result->dir_name[k - 1] = '\0';
++ k--;
++ }
++ mask = g_strdup_printf ("%s\\*", result->dir_name);
++
++ result->find_file_handle = (guint) FindFirstFile (mask,
++ (LPWIN32_FIND_DATA) result->find_file_data);
++ g_free (mask);
++
++ if (result->find_file_handle == (guint) INVALID_HANDLE_VALUE)
++ {
++ int error = GetLastError ();
++
++ g_free (result->dir_name);
++ g_free (result->find_file_data);
++ g_free (result);
++ switch (error)
++ {
++ default:
++ errno = EIO;
++ return NULL;
++ }
++ }
++ result->just_opened = TRUE;
++
++ return result;
++}
++
++struct dirent*
++gwin_readdir (DIR *dir)
++{
++ static struct dirent result;
++
++ g_return_val_if_fail (dir != NULL, NULL);
++
++ if (dir->just_opened)
++ dir->just_opened = FALSE;
++ else
++ {
++ if (!FindNextFile ((HANDLE) dir->find_file_handle,
++ (LPWIN32_FIND_DATA) dir->find_file_data))
++ {
++ int error = GetLastError ();
++
++ switch (error)
++ {
++ case ERROR_NO_MORE_FILES:
++ return NULL;
++ default:
++ errno = EIO;
++ return NULL;
++ }
++ }
++ }
++ strcpy (result.d_name, g_basename (((LPWIN32_FIND_DATA) dir->find_file_data)->cFileName));
++
++ return &result;
++}
++
++void
++gwin_rewinddir (DIR *dir)
++{
++ gchar *mask;
++
++ g_return_if_fail (dir != NULL);
++
++ if (!FindClose ((HANDLE) dir->find_file_handle))
++ g_warning ("gwin_rewinddir(): FindClose() failed\n");
++
++ mask = g_strdup_printf ("%s\\*", dir->dir_name);
++ dir->find_file_handle = (guint) FindFirstFile (mask,
++ (LPWIN32_FIND_DATA) dir->find_file_data);
++ g_free (mask);
++
++ if (dir->find_file_handle == (guint) INVALID_HANDLE_VALUE)
++ {
++ int error = GetLastError ();
++
++ switch (error)
++ {
++ default:
++ errno = EIO;
++ return;
++ }
++ }
++ dir->just_opened = TRUE;
++}
++
++gint
++gwin_closedir (DIR *dir)
++{
++ g_return_val_if_fail (dir != NULL, -1);
++
++ if (!FindClose ((HANDLE) dir->find_file_handle))
++ {
++ int error = GetLastError ();
++
++ switch (error)
++ {
++ default:
++ errno = EIO; return -1;
++ }
++ }
++
++ g_free (dir->dir_name);
++ g_free (dir->find_file_data);
++ g_free (dir);
++
++ return 0;
++}
++
++#endif /* _MSC_VER */
++
++#endif /* NATIVE_WIN32 */
+diff -urN linux-2.4.1/net/korbit/kglib/korbit_errno.c linux-2.4.1-korbit/net/korbit/kglib/korbit_errno.c
+--- linux-2.4.1/net/korbit/kglib/korbit_errno.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/korbit_errno.c Thu Feb 1 11:46:57 2001
+@@ -0,0 +1 @@
++int korbit_errno;
+diff -urN linux-2.4.1/net/korbit/korbit.h linux-2.4.1-korbit/net/korbit/korbit.h
+--- linux-2.4.1/net/korbit/korbit.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/korbit.h Thu Feb 1 11:46:49 2001
+@@ -0,0 +1,53 @@
++
++#ifndef KORBIT_H
++#define KORBIT_H
++
++#ifdef __KERNEL__
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/proc_fs.h>
++#endif
++
++#include "stdlib.h"
++
++#ifdef __KERNEL__
++static int korbit_get_ior_func(char *buffer, char **start, off_t offset,
++ int length, int *eof, void *data) {
++ int Len = strlen((char*)data);
++ memcpy(buffer, data, Len); // Data is the ior...
++ buffer[Len++] = '\n'; // Add a newline to make fredrik happy
++ buffer[Len] = 0; // Null terminate the buffer...
++ *start = buffer + offset;
++ *eof = 1;
++
++ Len -= offset;
++ if (Len > length)
++ Len = length;
++ if (Len < 0)
++ Len = 0;
++
++ return Len;
++}
++
++#endif
++
++
++static inline void korbit_register_ior(const char *name, CORBA_Object obj,
++ CORBA_ORB orb, CORBA_Environment *ev) {
++ char *retval = CORBA_ORB_object_to_string(orb, obj, ev);
++#if defined(__KERNEL__) && defined(CONFIG_PROC_FS)
++ char *procdirname = malloc(strlen(name)+7); // 7 = len("corba/\0")
++ strcpy(procdirname, "corba/");
++ strcpy(procdirname+6, name);
++
++ create_proc_read_entry(procdirname, 0, 0, korbit_get_ior_func, retval);
++
++ free(procdirname);
++ // Don't free the ior in the /proc handling case...
++#else
++ // No procfs support, just print to console... :(
++ g_print("%s IOR:\n%s\n", name, retval);
++ CORBA_free(retval);
++#endif
++}
++#endif
+diff -urN linux-2.4.1/net/korbit/modules/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CVS/Entries Thu Feb 1 11:46:58 2001
+@@ -0,0 +1,5 @@
++/Config.in/1.8/Thu Feb 1 09:46:58 2001//
++/Makefile/1.8/Thu Feb 1 09:46:58 2001//
++/Makefile.module/1.2/Thu Feb 1 09:46:58 2001//
++/README/1.1/Thu Feb 1 09:46:58 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/CVS/Entries.Log linux-2.4.1-korbit/net/korbit/modules/CVS/Entries.Log
+--- linux-2.4.1/net/korbit/modules/CVS/Entries.Log Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CVS/Entries.Log Thu Feb 1 11:47:09 2001
+@@ -0,0 +1,6 @@
++A D/CharDev////
++A D/Console////
++A D/CorbaFS////
++A D/Echo////
++A D/FileServer////
++A D/UserFS////
+diff -urN linux-2.4.1/net/korbit/modules/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CVS/Repository Thu Feb 1 11:46:57 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules
+diff -urN linux-2.4.1/net/korbit/modules/CVS/Root linux-2.4.1-korbit/net/korbit/modules/CVS/Root
+--- linux-2.4.1/net/korbit/modules/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CVS/Root Thu Feb 1 11:46:57 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/CharDev/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/CharDev/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/CVS/Entries Thu Feb 1 11:46:58 2001
+@@ -0,0 +1,4 @@
++/Makefile/1.3/Thu Feb 1 09:46:58 2001//
++/README/1.1/Thu Feb 1 09:46:58 2001//
++/chardev.idl/1.1/Thu Feb 1 09:46:58 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/CVS/Entries.Log linux-2.4.1-korbit/net/korbit/modules/CharDev/CVS/Entries.Log
+--- linux-2.4.1/net/korbit/modules/CharDev/CVS/Entries.Log Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/CVS/Entries.Log Thu Feb 1 11:47:00 2001
+@@ -0,0 +1,3 @@
++A D/kernel////
++A D/kernel-perl////
++A D/userspace////
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/CharDev/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/CharDev/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/CVS/Repository Thu Feb 1 11:46:58 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/CharDev
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/CVS/Root linux-2.4.1-korbit/net/korbit/modules/CharDev/CVS/Root
+--- linux-2.4.1/net/korbit/modules/CharDev/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/CVS/Root Thu Feb 1 11:46:58 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/Makefile linux-2.4.1-korbit/net/korbit/modules/CharDev/Makefile
+--- linux-2.4.1/net/korbit/modules/CharDev/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/Makefile Thu Feb 1 11:46:58 2001
+@@ -0,0 +1,11 @@
++#
++# Makefile for KORBit - CharDev
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++
++subdir-$(CONFIG_CORBA_CHARDEV) := kernel
++
++include $(TOPDIR)/Rules.make
++
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/README linux-2.4.1-korbit/net/korbit/modules/CharDev/README
+--- linux-2.4.1/net/korbit/modules/CharDev/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/README Thu Feb 1 11:46:58 2001
+@@ -0,0 +1 @@
++This module is used to implement a character device with kORBit.
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/chardev.idl linux-2.4.1-korbit/net/korbit/modules/CharDev/chardev.idl
+--- linux-2.4.1/net/korbit/modules/CharDev/chardev.idl Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/chardev.idl Thu Feb 1 11:46:58 2001
+@@ -0,0 +1,5 @@
++typedef sequence<octet> Buffer;
++
++interface CharDev {
++ long read(out Buffer buffer, in long size);
++};
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/CharDev/kernel/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/CVS/Entries Thu Feb 1 11:46:59 2001
+@@ -0,0 +1,4 @@
++/Makefile/1.2/Thu Feb 1 09:46:59 2001//
++/README/1.2/Thu Feb 1 09:46:59 2001//
++/chardev-kernel.c/1.9/Thu Feb 1 09:46:59 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/CharDev/kernel/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/CVS/Repository Thu Feb 1 11:46:59 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/CharDev/kernel
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel/CVS/Root linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/CVS/Root
+--- linux-2.4.1/net/korbit/modules/CharDev/kernel/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/CVS/Root Thu Feb 1 11:46:59 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel/Makefile linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/Makefile
+--- linux-2.4.1/net/korbit/modules/CharDev/kernel/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/Makefile Thu Feb 1 11:46:59 2001
+@@ -0,0 +1,20 @@
++#
++# Makefile for KORBit / chardev
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++O_TARGET := corba-chardev-kernel.o
++
++obj-y := chardev-common.o chardev-stubs.o chardev-kernel.o
++obj-m := $(O_TARGET)
++
++include ../../Makefile.module
++
++chardev-kernel.c: chardev.h
++
++chardev.h chardev-stubs.c chardev-common.c: ../chardev.idl
++ $(ORBIT_IDL) ../chardev.idl
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel/README linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/README
+--- linux-2.4.1/net/korbit/modules/CharDev/kernel/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/README Thu Feb 1 11:46:59 2001
+@@ -0,0 +1,5 @@
++This module is used to implement the kernel side of the CORBA Character
++device.
++
++ORB: kORBit
++Status: Working!!!
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel/chardev-kernel.c linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/chardev-kernel.c
+--- linux-2.4.1/net/korbit/modules/CharDev/kernel/chardev-kernel.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/chardev-kernel.c Thu Feb 1 11:46:59 2001
+@@ -0,0 +1,140 @@
++//-----------------------------------------------------------------------------
++//
++// chardev-kernel - Kernel miscdevice to CORBA glue.
++//
++// This file implements a standard Linux Kernel "miscdevice". This device
++// operates by forwarding all calls across to a remote CORBA server. This
++// server is located by reading the file /tmp/chardev-ior at the time the
++// device is opened. The device exported is major #10, minor #42. Create this
++// device with 'mknod' like all the others.
++//
++// No implementations of CORBA functions should block, although I think it
++// might be just fine, I'm not sure. Let's just make this a TODO. :) -CAL
++//
++// TODO: Locking, finish exporting all "miscdevice" functions, send position
++// on READ request.
++//
++// History:
++// Keith Wessel - Initial hack, initial idea
++// Andy Reitz - Get it to compile
++// Chris Lattner - Make it work. :)
++//
++//-----------------------------------------------------------------------------
++
++
++#include "chardev.h"
++#include <stdio.h>
++#include "orb/orbit.h"
++#include "korbit.h"
++#include <linux/miscdevice.h>
++
++#define DEV_MINOR 42
++
++CORBA_ORB orb;
++CORBA_Environment *ev;
++
++static int open_dev(struct inode *inode, struct file *file) {
++ char *iorstr = (char *)malloc(10240);
++ int error = -EINVAL;
++ int fd, len;
++
++ if (iorstr == 0) return -ENOMEM;
++
++ if ((fd = open ("/tmp/chardev-ior", O_RDONLY, 0)) == -1) {
++ printk("kORBit: chararacter driver couldn't open /tmp/chardev-ior!\n");
++ goto outfree;
++ }
++
++ len = read(fd, iorstr, 10240);
++ close(fd);
++ if (len == -1)
++ goto outfree;
++
++ iorstr[len] = 0; // Null terminate string!
++
++ printk("CharDEV IOR String = %s\n", iorstr);
++ file->private_data = (void*)CORBA_ORB_string_to_object(orb, iorstr, ev);
++ if (!file->private_data)
++ goto outfree;
++
++ // TODO: Send create_dev message out over CORBA
++
++ error = 0;
++ outfree:
++ free(iorstr);
++ return error;
++}
++
++static int release_dev(struct inode *inode, struct file *file) {
++ // TODO: Send release_dev message out over CORBA...
++ if (file->private_data)
++ CORBA_free(file->private_data);
++ return 0;
++}
++
++
++static ssize_t read_dev(struct file * file, char * buf, size_t count,
++ loff_t *ppos) {
++ Buffer *octet_buffer = NULL;
++ if (!file->private_data) return -EINVAL;
++ if (!count) return 0;
++
++ if (!access_ok(VERIFY_WRITE, buf, count))
++ return -EFAULT;
++
++ CharDev_read(file->private_data, &octet_buffer, count, ev);
++
++ if (!octet_buffer)
++ return -EPERM;
++
++ if (copy_to_user(buf, octet_buffer->_buffer, octet_buffer->_length))
++ return -EFAULT;
++
++ // TODO: Should free octet_buffer here!?!?!?
++
++ return octet_buffer->_length;
++}
++
++
++//-----------------------------------------------------------------------------
++// Kernel Callbacks for miscdevice
++//-----------------------------------------------------------------------------
++
++
++static struct file_operations dev_fops = {
++ owner: THIS_MODULE,
++ open: open_dev,
++ read: read_dev,
++ release: release_dev,
++ // mmap: mmap_dev,
++ // llseek: llseek_dev,
++ // write: write_dev,
++};
++
++static struct miscdevice cdev = {
++ DEV_MINOR,
++ "CORBA Character device",
++ &dev_fops
++};
++
++
++//-----------------------------------------------------------------------------
++// Module Initializion/Finalization
++//-----------------------------------------------------------------------------
++
++static int __init CharDev_init(void) {
++ int argc = 1;
++ char *argv[] = { "CharDev-kernel", 0 };
++ ev = g_new0(CORBA_Environment,1);
++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", ev);
++
++ // Register the device
++ return misc_register(&cdev);
++}
++
++static void __exit CharDev_exit(void) {
++ misc_deregister(&cdev);
++}
++
++module_init(CharDev_init)
++module_exit(CharDev_exit)
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/CVS/Entries Thu Feb 1 11:46:59 2001
+@@ -0,0 +1,3 @@
++/PerlTest/1.1/Thu Feb 1 09:46:59 2001//
++/README/1.1/Thu Feb 1 09:46:59 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/CVS/Repository Thu Feb 1 11:46:59 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/CharDev/kernel-perl
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/CVS/Root linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/CVS/Root
+--- linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/CVS/Root Thu Feb 1 11:46:59 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/PerlTest linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/PerlTest
+--- linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/PerlTest Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/PerlTest Thu Feb 1 11:46:59 2001
+@@ -0,0 +1,17 @@
++#!/usr/bin/perl -w
++
++use CORBA::ORBit idl => [ qw(../chardev.idl) ];
++use Error qw(:try);
++use strict;
++
++my $orb = CORBA::ORB_init("orbit-local-orb");
++open IOR, "/tmp/chardev-ior" or die "no chardev server found!";
++my $ior = <IOR>;
++close IOR;
++#chomp($ior); # Kill fredrik's newline...
++
++my $chardev = $orb->string_to_object($ior);
++# Echo echoString(in string astring, out long anum);
++my ($ressize, $buf) = $chardev->read(10);
++
++print "Return size = $ressize\nresult = $buf\n";
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/README linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/README
+--- linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/README Thu Feb 1 11:46:59 2001
+@@ -0,0 +1,6 @@
++This module is used to test the user side of the CORBA Character
++device. It doesn't do anything really complex, just implements a quick
++sanity test for the server.
++
++ORB: ORBit - Perl
++Status: Working!
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/userspace/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/CharDev/userspace/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/CVS/Entries Thu Feb 1 11:47:00 2001
+@@ -0,0 +1,6 @@
++/Makefile/1.5/Thu Feb 1 09:47:00 2001//
++/README/1.1/Thu Feb 1 09:47:00 2001//
++/RunServer.sh/1.1/Thu Feb 1 09:47:00 2001//
++/chardev-server.c/1.5/Thu Feb 1 09:47:00 2001//
++/chardev-skelimpl.c/1.5/Thu Feb 1 09:47:00 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/userspace/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/CharDev/userspace/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/CVS/Repository Thu Feb 1 11:47:00 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/CharDev/userspace
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/userspace/CVS/Root linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/CVS/Root
+--- linux-2.4.1/net/korbit/modules/CharDev/userspace/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/CVS/Root Thu Feb 1 11:47:00 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/userspace/Makefile linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/Makefile
+--- linux-2.4.1/net/korbit/modules/CharDev/userspace/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/Makefile Thu Feb 1 11:47:00 2001
+@@ -0,0 +1,30 @@
++#
++# Makefile for KORBit / CharDev
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++CFLAGS = -Wall -I/usr/lib/glib/include
++LDFLAGS = -lORBit -lIIOP -lORBitutil
++OBJS = chardev-common.o chardev-skels.o chardev-server.o
++ORBIT-IDL = /usr/bin/orbit-idl
++
++chardev-server: $(OBJS)
++ gcc -o chardev-server $(OBJS) $(LDFLAGS)
++
++chardev-server.o: chardev.h chardev-skelimpl.c
++
++chardev.h chardev-skels.c chardev-common.c: ../chardev.idl
++ $(ORBIT-IDL) ../chardev.idl
++
++chardev-skelimpl.c:
++
++%.o: %.c
++ gcc -c $< $(CFLAGS)
++clean:
++ rm -f $(OBJS) chardev-server chardev-common.c chardev-skels.c \
++ chardev-stubs.c chardev.h
++
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/userspace/README linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/README
+--- linux-2.4.1/net/korbit/modules/CharDev/userspace/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/README Thu Feb 1 11:47:00 2001
+@@ -0,0 +1,4 @@
++This is an example character driver.
++
++ORB: ORBit
++Status: not yet working
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/userspace/RunServer.sh linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/RunServer.sh
+--- linux-2.4.1/net/korbit/modules/CharDev/userspace/RunServer.sh Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/RunServer.sh Thu Feb 1 11:47:00 2001
+@@ -0,0 +1 @@
++./chardev-server -ORBIIOPUSock=0 -ORBIIOPIPv4=1
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/userspace/chardev-server.c linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/chardev-server.c
+--- linux-2.4.1/net/korbit/modules/CharDev/userspace/chardev-server.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/chardev-server.c Thu Feb 1 11:47:00 2001
+@@ -0,0 +1,77 @@
++//-----------------------------------------------------------------------------
++//
++// chardev-server.c - TEST Kernel miscdevice implementation
++//
++// This file implements the standard server code for a userspace server. This
++// is basically cut and paste boilerplate code adapted from the CorbaFS server
++// by Fredrik Vraalsen.
++//
++// TODO: Locking, finish exporting all "miscdevice" functions, send position
++// on READ request.
++//
++// History:
++// Keith Wessel - Initial hack, initial idea
++// Andy Reitz - Get it to compile
++// Chris Lattner - Hack'n'slash, make it work, comment it, kill warnings.
++//
++//-----------------------------------------------------------------------------
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <signal.h>
++#include <orb/orbit.h>
++
++// #include the C file because all the functions are static. Bizarre.
++#include "chardev-skelimpl.c"
++
++int main(int argc, char *argv[]) {
++ PortableServer_POA poa;
++ PortableServer_POAManager pm;
++
++ CharDev chardev = CORBA_OBJECT_NIL;
++ impl_POA_CharDev *chardev_impl;
++ PortableServer_ObjectId *objid;
++
++ CORBA_Environment ev;
++ char *retval;
++ CORBA_ORB orb;
++ FILE *IORFILE;
++
++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", &ev);
++ poa = (PortableServer_POA)CORBA_ORB_resolve_initial_references(orb, "RootPOA", &ev);
++
++ chardev = impl_CharDev__create(poa, &ev);
++ pm = PortableServer_POA__get_the_POAManager(poa, &ev);
++ PortableServer_POAManager_activate(pm, &ev);
++
++ if (!chardev) {
++ printf("Cannot get objref\n");
++ return 1;
++ }
++
++ chardev_impl = PortableServer_POA_reference_to_servant(poa, chardev, &ev);
++ objid = PortableServer_POA_servant_to_id(poa, chardev_impl, &ev);
++
++ retval = CORBA_ORB_object_to_string(orb, chardev, &ev);
++
++ g_print("FYI, this also goes into /tmp/chardev-ior for you.\n");
++ g_print("%s\n", retval); fflush(stdout);
++
++ IORFILE = fopen ("/tmp/chardev-ior", "w");
++ if (IORFILE == NULL) {
++ perror("ERROR: IOR_WRITE_TO_DISK");
++ exit(1);
++ }
++
++ fprintf(IORFILE, "%s", retval);
++ fclose(IORFILE);
++
++ CORBA_free(retval); // Free the corba string like a good little CORBear
++
++
++ // La dee dah... I will never return for you mister.
++ CORBA_ORB_run(orb, &ev);
++ return 0;
++}
++
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/userspace/chardev-skelimpl.c linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/chardev-skelimpl.c
+--- linux-2.4.1/net/korbit/modules/CharDev/userspace/chardev-skelimpl.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/chardev-skelimpl.c Thu Feb 1 11:47:00 2001
+@@ -0,0 +1,119 @@
++//-----------------------------------------------------------------------------
++//
++// chardev-skelimpl.c - TEST Kernel miscdevice implementation
++//
++// This file implements a CORBA "miscdevice" (character device node).
++// This device simply outputs a fixed string (set by "message", below) when
++// cat'd. Pretty simple stuff, but you can obviously do much more creative
++// things with it.
++//
++// TODO: Locking, finish exporting all "miscdevice" functions, send position
++// on READ request.
++//
++// Right now we have ONE server object with global state, so that when you
++// read the string from that object, it is finished. This should be reset
++// whenever an open request is had or when the file position is reset (duh).
++//
++// History:
++// Keith Wessel - Initial hack, initial idea
++// Andy Reitz - Get it to compile
++// Chris Lattner - Make it work, comment it, no warnings.
++//
++//-----------------------------------------------------------------------------
++
++#include "chardev.h"
++
++// The message to spit out.
++const char *message = "Hello world!\nI love kORBit\n";
++
++
++/*** App-specific servant structures ***/
++
++typedef struct
++{
++ POA_CharDev servant;
++ PortableServer_POA poa;
++ int AmountRead;
++
++}
++impl_POA_CharDev;
++
++/*** Implementation stub prototypes ***/
++
++static inline void impl_CharDev__destroy(impl_POA_CharDev * servant,
++ CORBA_Environment * ev);
++static CORBA_long
++impl_CharDev_read(impl_POA_CharDev * servant,
++ Buffer ** buffer, CORBA_long size, CORBA_Environment * ev);
++
++/*** epv structures ***/
++
++static PortableServer_ServantBase__epv impl_CharDev_base_epv = {
++ NULL, /* _private data */
++ NULL, /* finalize routine */
++ NULL, /* default_POA routine */
++};
++static POA_CharDev__epv impl_CharDev_epv = {
++ NULL, /* _private */
++ (gpointer) & impl_CharDev_read,
++
++};
++
++/*** vepv structures ***/
++
++static POA_CharDev__vepv impl_CharDev_vepv = {
++ &impl_CharDev_base_epv,
++ &impl_CharDev_epv,
++};
++
++/*** Stub implementations ***/
++
++static CharDev
++impl_CharDev__create(PortableServer_POA poa, CORBA_Environment * ev)
++{
++ CharDev retval;
++ impl_POA_CharDev *newservant;
++ PortableServer_ObjectId *objid;
++
++ newservant = g_new0(impl_POA_CharDev, 1);
++ newservant->servant.vepv = &impl_CharDev_vepv;
++ newservant->poa = poa;
++ newservant->AmountRead = 0; // Initialize chardev stuff...
++
++ POA_CharDev__init((PortableServer_Servant) newservant, ev);
++ objid = PortableServer_POA_activate_object(poa, newservant, ev);
++ CORBA_free(objid);
++ retval = PortableServer_POA_servant_to_reference(poa, newservant, ev);
++
++ return retval;
++}
++
++static inline void
++impl_CharDev__destroy(impl_POA_CharDev * servant, CORBA_Environment * ev)
++{
++ PortableServer_ObjectId *objid;
++
++ objid = PortableServer_POA_servant_to_id(servant->poa, servant, ev);
++ PortableServer_POA_deactivate_object(servant->poa, objid, ev);
++ CORBA_free(objid);
++
++ POA_CharDev__fini((PortableServer_Servant) servant, ev);
++ g_free(servant);
++}
++
++static CORBA_long
++impl_CharDev_read(impl_POA_CharDev * servant,
++ Buffer ** buffer, CORBA_long ReqSize, CORBA_Environment * ev)
++{
++ int AvailSize = strlen(message)-servant->AmountRead;
++ CORBA_long retval = (ReqSize > AvailSize) ? AvailSize : ReqSize;
++
++ *buffer = Buffer__alloc();
++ (*buffer)->_buffer = CORBA_octet_allocbuf(retval);
++ (*buffer)->_length = retval;
++
++ strncpy((*buffer)->_buffer, message + servant->AmountRead, retval);
++ servant->AmountRead += retval;
++ return retval;
++}
++
+diff -urN linux-2.4.1/net/korbit/modules/Config.in linux-2.4.1-korbit/net/korbit/modules/Config.in
+--- linux-2.4.1/net/korbit/modules/Config.in Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Config.in Thu Feb 1 11:46:58 2001
+@@ -0,0 +1,11 @@
++# Console server
++#
++dep_tristate ' CORBA Console Server (EXPERIMENTAL)' CONFIG_CORBA_CONSOLE $CONFIG_KORBIT
++
++dep_tristate ' CORBA Echo Server (EXPERIMENTAL)' CONFIG_CORBA_ECHO $CONFIG_KORBIT
++
++dep_tristate ' CORBA FileSystem Access (EXPERIMENTAL)' CONFIG_CORBA_FILESERVER $CONFIG_KORBIT
++
++dep_tristate ' CORBA User-space FileSystem (EXPERIMENTAL)' CONFIG_CORBA_CORBAFS $CONFIG_KORBIT
++
++dep_tristate ' CORBA Character Device Interface (EXPERIMENTAL)' CONFIG_CORBA_CHARDEV $CONFIG_KORBIT
+diff -urN linux-2.4.1/net/korbit/modules/Console/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/Console/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/Console/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/CVS/Entries Thu Feb 1 11:47:01 2001
+@@ -0,0 +1,4 @@
++/Makefile/1.2/Thu Feb 1 09:47:00 2001//
++/README/1.1/Thu Feb 1 09:47:00 2001//
++/console.idl/1.1/Thu Feb 1 09:47:00 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/Console/CVS/Entries.Log linux-2.4.1-korbit/net/korbit/modules/Console/CVS/Entries.Log
+--- linux-2.4.1/net/korbit/modules/Console/CVS/Entries.Log Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/CVS/Entries.Log Thu Feb 1 11:47:02 2001
+@@ -0,0 +1,3 @@
++A D/PerlClient////
++A D/client////
++A D/server////
+diff -urN linux-2.4.1/net/korbit/modules/Console/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/Console/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/Console/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/CVS/Repository Thu Feb 1 11:47:00 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/Console
+diff -urN linux-2.4.1/net/korbit/modules/Console/CVS/Root linux-2.4.1-korbit/net/korbit/modules/Console/CVS/Root
+--- linux-2.4.1/net/korbit/modules/Console/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/CVS/Root Thu Feb 1 11:47:00 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/Console/Makefile linux-2.4.1-korbit/net/korbit/modules/Console/Makefile
+--- linux-2.4.1/net/korbit/modules/Console/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/Makefile Thu Feb 1 11:47:00 2001
+@@ -0,0 +1,11 @@
++#
++# Makefile for KORBit/modules/Console
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++
++subdir-$(CONFIG_CORBA_CONSOLE) := server
++
++include $(TOPDIR)/Rules.make
++
+diff -urN linux-2.4.1/net/korbit/modules/Console/PerlClient/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/Console/PerlClient/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/CVS/Entries Thu Feb 1 11:47:01 2001
+@@ -0,0 +1,3 @@
++/Client/1.1/Thu Feb 1 09:47:01 2001//
++/README/1.1/Thu Feb 1 09:47:01 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/Console/PerlClient/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/Console/PerlClient/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/CVS/Repository Thu Feb 1 11:47:01 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/Console/PerlClient
+diff -urN linux-2.4.1/net/korbit/modules/Console/PerlClient/CVS/Root linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/CVS/Root
+--- linux-2.4.1/net/korbit/modules/Console/PerlClient/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/CVS/Root Thu Feb 1 11:47:01 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/Console/PerlClient/Client linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/Client
+--- linux-2.4.1/net/korbit/modules/Console/PerlClient/Client Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/Client Thu Feb 1 11:47:01 2001
+@@ -0,0 +1,14 @@
++#!/usr/bin/perl -w
++
++use CORBA::ORBit idl => [ qw(../console.idl) ];
++use Error qw(:try);
++use strict;
++
++my $orb = CORBA::ORB_init("orbit-local-orb");
++open IOR, "/proc/corba/console-server" or die "no console server found!";
++my $ior = <IOR>;
++close IOR;
++chomp($ior); # Kill fredrik's newline...
++
++my $console = $orb->string_to_object($ior);
++$console->print("Hello Strange World");
+diff -urN linux-2.4.1/net/korbit/modules/Console/PerlClient/README linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/README
+--- linux-2.4.1/net/korbit/modules/Console/PerlClient/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/README Thu Feb 1 11:47:01 2001
+@@ -0,0 +1,3 @@
++This is a perl client for the Console server.
++
++ORB: ORBit
+diff -urN linux-2.4.1/net/korbit/modules/Console/README linux-2.4.1-korbit/net/korbit/modules/Console/README
+--- linux-2.4.1/net/korbit/modules/Console/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/README Thu Feb 1 11:47:00 2001
+@@ -0,0 +1 @@
++The "hello world" testcase. This is used to write a string to the linux console.
+diff -urN linux-2.4.1/net/korbit/modules/Console/client/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/Console/client/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/Console/client/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/client/CVS/Entries Thu Feb 1 11:47:01 2001
+@@ -0,0 +1,4 @@
++/Makefile/1.2/Thu Feb 1 09:47:01 2001//
++/README/1.1/Thu Feb 1 09:47:01 2001//
++/console-client.c/1.1/Thu Feb 1 09:47:01 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/Console/client/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/Console/client/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/Console/client/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/client/CVS/Repository Thu Feb 1 11:47:01 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/Console/client
+diff -urN linux-2.4.1/net/korbit/modules/Console/client/CVS/Root linux-2.4.1-korbit/net/korbit/modules/Console/client/CVS/Root
+--- linux-2.4.1/net/korbit/modules/Console/client/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/client/CVS/Root Thu Feb 1 11:47:01 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/Console/client/Makefile linux-2.4.1-korbit/net/korbit/modules/Console/client/Makefile
+--- linux-2.4.1/net/korbit/modules/Console/client/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/client/Makefile Thu Feb 1 11:47:01 2001
+@@ -0,0 +1,32 @@
++#
++# Makefile for KORBit
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++PROJECT = console
++
++CFLAGS = -Wall `orbit-config --cflags client` -I../../..
++LDFLAGS = `orbit-config --libs client`
++OBJS = $(PROJECT)-common.o $(PROJECT)-stubs.o $(PROJECT)-client.o
++ORBIT-IDL = orbit-idl
++
++$(PROJECT)-client: $(OBJS)
++ gcc -o $(PROJECT)-client $(OBJS) $(LDFLAGS)
++
++$(PROJECT)-client.c: $(PROJECT).h
++
++$(PROJECT).h $(PROJECT)-common.c $(PROJECT)-stubs.c: ../$(PROJECT).idl
++ $(ORBIT-IDL) --noskels ../$(PROJECT).idl
++
++clean:
++ rm -f $(OBJS) $(PROJECT)-client
++
++realclean: clean
++ rm -f $(PROJECT).h
++ rm -f $(PROJECT)-common.c
++ rm -f $(PROJECT)-stubs.c
++ rm -f *~
+diff -urN linux-2.4.1/net/korbit/modules/Console/client/README linux-2.4.1-korbit/net/korbit/modules/Console/client/README
+--- linux-2.4.1/net/korbit/modules/Console/client/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/client/README Thu Feb 1 11:47:01 2001
+@@ -0,0 +1,3 @@
++C Client to access console server.
++
++ORB: ORBit
+diff -urN linux-2.4.1/net/korbit/modules/Console/client/console-client.c linux-2.4.1-korbit/net/korbit/modules/Console/client/console-client.c
+--- linux-2.4.1/net/korbit/modules/Console/client/console-client.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/client/console-client.c Thu Feb 1 11:47:01 2001
+@@ -0,0 +1,63 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <orb/orbit.h>
++
++#include "console.h"
++
++Console console_client;
++
++int
++main (int argc, char *argv[])
++{
++ CORBA_Environment ev;
++ CORBA_ORB orb;
++ char *Message = "Hey dood, nice hair";
++ int i;
++
++ int niters = 10;
++
++ CORBA_exception_init(&ev);
++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", &ev);
++
++#if 0
++ for(i = 0; i < (sizeof(theblah) - 1); i++)
++ theblah[i] = 'a';
++ theblah[sizeof(theblah) - 1] = '\0';
++#endif
++
++ if(argc < 2)
++ {
++ printf("Need a binding ID thing as argv[1]\n");
++ return 1;
++ }
++
++ if(argc >= 3)
++ niters = atoi(argv[2]);
++
++ if (argc >= 4)
++ Message = argv[3];
++
++ console_client = CORBA_ORB_string_to_object(orb, argv[1], &ev);
++ if (!console_client) {
++ printf("Cannot bind to %s\n", argv[1]);
++ return 1;
++ }
++
++ printf("corba = %d, console = %d, foobar = %d\n",
++ CORBA_Object_is_a(console_client, "IDL:CORBA/Object:1.0", &ev),
++ CORBA_Object_is_a(console_client, "IDL:Empty:1.0", &ev),
++ CORBA_Object_is_a(console_client, "IDL:Foo/Bar:1.0", &ev));
++
++ for(i = 0; i < niters; i++) {
++ Console_print(console_client, Message, &ev);
++ if(ev._major != CORBA_NO_EXCEPTION) {
++ printf("we got exception %d from doNothing!\n", ev._major);
++ return 1;
++ }
++ }
++
++ CORBA_Object_release(console_client, &ev);
++ CORBA_Object_release((CORBA_Object)orb, &ev);
++
++ return 0;
++}
+diff -urN linux-2.4.1/net/korbit/modules/Console/console.idl linux-2.4.1-korbit/net/korbit/modules/Console/console.idl
+--- linux-2.4.1/net/korbit/modules/Console/console.idl Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/console.idl Thu Feb 1 11:47:00 2001
+@@ -0,0 +1,3 @@
++interface Console {
++ void print(in string TheString);
++};
+diff -urN linux-2.4.1/net/korbit/modules/Console/server/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/Console/server/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/Console/server/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/server/CVS/Entries Thu Feb 1 11:47:02 2001
+@@ -0,0 +1,5 @@
++/Makefile/1.7/Thu Feb 1 09:47:02 2001//
++/Makefile.user/1.1/Thu Feb 1 09:47:02 2001//
++/README/1.1/Thu Feb 1 09:47:02 2001//
++/console-server.c/1.7/Thu Feb 1 09:47:02 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/Console/server/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/Console/server/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/Console/server/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/server/CVS/Repository Thu Feb 1 11:47:02 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/Console/server
+diff -urN linux-2.4.1/net/korbit/modules/Console/server/CVS/Root linux-2.4.1-korbit/net/korbit/modules/Console/server/CVS/Root
+--- linux-2.4.1/net/korbit/modules/Console/server/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/server/CVS/Root Thu Feb 1 11:47:02 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/Console/server/Makefile linux-2.4.1-korbit/net/korbit/modules/Console/server/Makefile
+--- linux-2.4.1/net/korbit/modules/Console/server/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/server/Makefile Thu Feb 1 11:47:02 2001
+@@ -0,0 +1,21 @@
++#
++# Makefile for KORBit
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++O_TARGET := corba-cons-server.o
++
++obj-y := console-server.o console-skels.o console-common.o
++obj-m := $(O_TARGET)
++
++include ../../Makefile.module
++
++console-server.c: console.h console-common.c console-skels.c
++
++
++console.h console-skels.c: ../console.idl
++ $(ORBIT_IDL) ../console.idl
+diff -urN linux-2.4.1/net/korbit/modules/Console/server/Makefile.user linux-2.4.1-korbit/net/korbit/modules/Console/server/Makefile.user
+--- linux-2.4.1/net/korbit/modules/Console/server/Makefile.user Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/server/Makefile.user Thu Feb 1 11:47:02 2001
+@@ -0,0 +1,32 @@
++#
++# Makefile for KORBit
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++PROJECT = console
++
++CFLAGS = -Wall `orbit-config --cflags server` -I../../..
++LDFLAGS = `orbit-config --libs server`
++OBJS = $(PROJECT)-common.o $(PROJECT)-skels.o $(PROJECT)-server.o
++ORBIT-IDL = orbit-idl
++
++$(PROJECT)-server: $(OBJS)
++ gcc -o $(PROJECT)-server $(OBJS) $(LDFLAGS)
++
++$(PROJECT)-server.c: $(PROJECT).h
++
++$(PROJECT).h $(PROJECT)-common.c $(PROJECT)-skels.c: ../$(PROJECT).idl
++ $(ORBIT-IDL) --nostubs ../$(PROJECT).idl
++
++clean:
++ rm -f $(OBJS) $(PROJECT)-server
++
++realclean: clean
++ rm -f $(PROJECT).h
++ rm -f $(PROJECT)-common.c
++ rm -f $(PROJECT)-skels.c
++ rm -f *~
+diff -urN linux-2.4.1/net/korbit/modules/Console/server/README linux-2.4.1-korbit/net/korbit/modules/Console/server/README
+--- linux-2.4.1/net/korbit/modules/Console/server/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/server/README Thu Feb 1 11:47:02 2001
+@@ -0,0 +1 @@
++Kernel module to implement Console server.
+diff -urN linux-2.4.1/net/korbit/modules/Console/server/console-server.c linux-2.4.1-korbit/net/korbit/modules/Console/server/console-server.c
+--- linux-2.4.1/net/korbit/modules/Console/server/console-server.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/server/console-server.c Thu Feb 1 11:47:02 2001
+@@ -0,0 +1,85 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <signal.h>
++#include <orb/orbit.h>
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include "console.h"
++#include "glib.h"
++#include "korbit.h"
++
++Console console_client = CORBA_OBJECT_NIL;
++
++static void corba_console_print(PortableServer_Servant _servant,
++ CORBA_char *TheString,
++ CORBA_Environment *ev);
++
++PortableServer_ServantBase__epv base_epv = {
++ NULL,
++ NULL,
++ NULL
++};
++POA_Console__epv console_epv = { NULL, corba_console_print };
++POA_Console__vepv poa_console_vepv = { &base_epv, &console_epv };
++POA_Console poa_console_servant = { NULL, &poa_console_vepv };
++
++// MAke this global so that I can unregister the module...
++PortableServer_ObjectId objid = {0, sizeof("myFoo"), "myFoo"};
++CORBA_Environment *ev;
++PortableServer_POA poa;
++
++#ifdef __KERNEL__
++int __init corba_console_init(void)
++#else
++int main(int argc, char *argv[])
++#endif
++{
++#ifdef __KERNEL__
++ int argc = 1; char *argv[] = { "server", 0 };
++#endif
++ CORBA_ORB orb;
++
++ ev = g_new0(CORBA_Environment, 1);
++ CORBA_exception_init(ev);
++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", ev);
++
++ poa = (PortableServer_POA)CORBA_ORB_resolve_initial_references(orb, "RootPOA", ev);
++ PortableServer_POAManager_activate(PortableServer_POA__get_the_POAManager(poa, ev), ev);
++
++ POA_Console__init(&poa_console_servant, ev);
++
++ PortableServer_POA_activate_object_with_id(poa,
++ &objid, &poa_console_servant, ev);
++
++ console_client =
++ PortableServer_POA_servant_to_reference(poa, &poa_console_servant, ev);
++ if (!console_client) {
++ printf("Cannot get objref\n");
++ return 1;
++ }
++
++ korbit_register_ior("console-server", console_client, orb, ev);
++
++ CORBA_ORB_run(orb, ev);
++
++ return 0;
++}
++
++#ifdef __KERNEL__
++void corba_console_exit(void) {
++ PortableServer_POA_deactivate_object(poa, &objid, ev);
++ remove_proc_entry("corba/console-server", 0);
++}
++
++module_init(corba_console_init)
++module_exit(corba_console_exit)
++#endif
++
++static void corba_console_print(PortableServer_Servant _servant,
++ CORBA_char *TheString,
++ CORBA_Environment *ev) {
++ printf("Yo. Dood. You said: '%s'!\n", TheString);
++}
++
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/CorbaFS/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CVS/Entries Thu Feb 1 11:47:02 2001
+@@ -0,0 +1,4 @@
++/CorbaFS.idl/1.7/Thu Feb 1 09:47:02 2001//
++/Makefile/1.4/Thu Feb 1 09:47:02 2001//
++/README/1.2/Thu Feb 1 09:47:02 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/CVS/Entries.Log linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CVS/Entries.Log
+--- linux-2.4.1/net/korbit/modules/CorbaFS/CVS/Entries.Log Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CVS/Entries.Log Thu Feb 1 11:47:04 2001
+@@ -0,0 +1,3 @@
++A D/client////
++A D/server////
++A D/server-perl////
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/CorbaFS/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CVS/Repository Thu Feb 1 11:47:02 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/CorbaFS
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/CVS/Root linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CVS/Root
+--- linux-2.4.1/net/korbit/modules/CorbaFS/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CVS/Root Thu Feb 1 11:47:02 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/CorbaFS.idl linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CorbaFS.idl
+--- linux-2.4.1/net/korbit/modules/CorbaFS/CorbaFS.idl Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CorbaFS.idl Thu Feb 1 11:47:02 2001
+@@ -0,0 +1,38 @@
++// -----------------------------------------------------------------------------
++// CorbaDS Module - Implement Kernel functionality in Korba
++// -----------------------------------------------------------------------------
++//
++// Main source of information:
++// http://www.cse.unsw.edu.au/~neilb/oss/linux-commentary/vfs.html
++//
++module CorbaFS {
++
++ struct dirent
++ {
++ long inode; // inode number
++ string name; // file name (null-terminated)
++ };
++
++ typedef sequence<dirent> DirEntSeq;
++ typedef sequence<octet> Buffer;
++
++ interface Inode {
++ void getStatus(out unsigned short mode, out unsigned long uid, out unsigned long gid,
++ out unsigned long size, out unsigned long inodeNum, out unsigned short numLinks,
++ out long atime, out long mtime, out long ctime);
++ void readpage(out Buffer buffer, in long size, in long offset);
++ void release();
++ };
++
++ interface FileSystem {
++ Inode getInode(in string path);
++
++ // DirectoryInode getStatus implementation must have S_IFDIR in the S_IFMT
++ // field of the mode value.
++ DirEntSeq readdir(in string path);
++
++ // SymlinkInode getStatus implementation must have S_IFLNK in the S_IFMT
++ // field of the mode value.
++ string readlink(in string filename);
++ };
++};
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/Makefile linux-2.4.1-korbit/net/korbit/modules/CorbaFS/Makefile
+--- linux-2.4.1/net/korbit/modules/CorbaFS/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/Makefile Thu Feb 1 11:47:02 2001
+@@ -0,0 +1,11 @@
++#
++# Makefile for KORBit - CorbaFS
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++
++subdir-$(CONFIG_CORBA_CORBAFS) := client
++
++include $(TOPDIR)/Rules.make
++
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/README linux-2.4.1-korbit/net/korbit/modules/CorbaFS/README
+--- linux-2.4.1/net/korbit/modules/CorbaFS/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/README Thu Feb 1 11:47:02 2001
+@@ -0,0 +1,14 @@
++This interface is used to implement linux FileSystems in CORBA.
++
++Status: Working for readonly filesystems. Write capability is a todo.
++
++This lets you do all kinds of interesting things (just like the user level
++filesystem proposals would let you do):
++ server/ implements NFS like capability of just exporting an existing FS
++ TODO: webfs, ftpfs, cvsfs, mysqlfs...
++
++Usage:
++ insmod corba-corbafs.o
++ mount -t corbafs -o IOR:... none /mnt/corbafs
++
++Where the IOR comes from a filesystem server that you run somewhere...
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/CorbaFS/client/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CVS/Entries Thu Feb 1 11:47:03 2001
+@@ -0,0 +1,6 @@
++/CorbaFS-client.c/1.9/Thu Feb 1 09:47:03 2001//
++/CorbaFS-user-client.c/1.3/Thu Feb 1 09:47:03 2001//
++/Makefile/1.4/Thu Feb 1 09:47:03 2001//
++/Makefile.user/1.1/Thu Feb 1 09:47:03 2001//
++/README/1.1/Thu Feb 1 09:47:03 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/CorbaFS/client/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CVS/Repository Thu Feb 1 11:47:03 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/CorbaFS/client
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/CVS/Root linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CVS/Root
+--- linux-2.4.1/net/korbit/modules/CorbaFS/client/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CVS/Root Thu Feb 1 11:47:03 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS-client.c linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS-client.c
+--- linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS-client.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS-client.c Fri Feb 2 02:20:21 2001
+@@ -0,0 +1,469 @@
++/*
++ * corbafs - Interface glue between native linux VFS layer and CORBA
++ */
++
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/pagemap.h>
++#include <linux/init.h>
++#include <linux/string.h>
++#include <linux/locks.h>
++#include <linux/dirent.h>
++#include <linux/module.h>
++
++#include <asm/uaccess.h>
++#include "CorbaFS.h"
++
++/* some random number */
++#define CORBAFS_MAGIC 0xC02BAF5
++
++// CORBA Stuff...
++CORBA_ORB orb;
++CORBA_Environment *ev;
++
++
++/*
++ * FILE OPERATIONS FILE OPERATIONS FILE OPERATIONS FILE OPERATIONS
++ */
++
++/* Declarations for the file_operations structure for normal files...
++ */
++static struct file_operations corbafs_file_operations = {
++ read: generic_file_read,
++};
++
++
++/* Declarations for the file_operations structure for directories...
++ */
++static int corbafs_readdir(struct file *file, void *data, filldir_t filldir);
++
++static struct file_operations corbafs_dir_operations = {
++ read: generic_read_dir,
++ readdir: corbafs_readdir,
++};
++
++
++/*
++ * INODE OPERATIONS INODE OPERATIONS INODE OPERATIONS INODE OPERATIONS
++ */
++
++/* Declarations for the inode_operations structure for symlinks...
++ */
++static int corbafs_readlink(struct dentry *dentry, char *buffer, int buflen);
++static int corbafs_followlink(struct dentry *link, struct nameidata *nd);
++
++static struct inode_operations corbafs_symlink_inode_operations = {
++ readlink: corbafs_readlink,
++ follow_link: corbafs_followlink,
++};
++
++
++/* Declarations for the inode_operations structure for directories...
++ */
++static struct dentry *corbafs_lookup(struct inode *dir, struct dentry *dentry);
++
++static struct inode_operations corbafs_dir_inode_operations = {
++ lookup: corbafs_lookup,
++};
++
++
++/*
++ * OTHER OPERATIONS OTHER OPERATIONS OTHER OPERATIONS OTHER OPERATIONS
++ */
++
++/* Declarations for the corba FS's address space ops...
++ */
++static int corbafs_readpage(struct file *file, struct page * page);
++
++static struct address_space_operations corbafs_aops = {
++ readpage: corbafs_readpage,
++};
++
++
++/* Declarations for the super_operations structure...
++ */
++static int corbafs_statfs(struct super_block *sb, struct statfs *buf);
++static void corbafs_delete_inode(struct inode *);
++
++static struct super_operations corbafs_ops = {
++ statfs: corbafs_statfs,
++ delete_inode: corbafs_delete_inode,
++};
++
++
++
++
++/* do_local_path - Modified version of d_path that is used to get the remote
++ * filename that a dentry represents...
++ */
++static char *d_local_path(struct dentry *dentry, char *buffer, int buflen) {
++ char * end = buffer+buflen;
++ char * retval;
++ int namelen;
++
++ *--end = '\0';
++ buflen--;
++
++ /* Get '/' right */
++ retval = end-1;
++ *retval = '/';
++ for (;;) {
++ if (IS_ROOT(dentry)) {
++ if (dentry->d_name.len > 1 ||
++ dentry->d_name.name[0] != '/' ||
++ retval != end) { /* Only for root directory */
++ namelen = dentry->d_name.len;
++ buflen -= namelen;
++ if (buflen >= 0) {
++ end -= namelen;
++ memcpy(end, dentry->d_name.name, namelen);
++ }
++ }
++ return end;
++ }
++ namelen = dentry->d_name.len;
++ buflen -= namelen + 1;
++ if (buflen < 0)
++ break;
++ end -= namelen;
++ memcpy(end, dentry->d_name.name, namelen);
++ *--end = '/';
++ retval = end;
++ if (dentry == dentry->d_parent) break;
++ dentry = dentry->d_parent;
++ }
++ return retval;
++}
++
++
++/* corbafs_readpage - This request should be between a file_open and a
++ * file_release, so file_fd(f) should be valid. Just read the buffer...
++ */
++static int corbafs_readpage(struct file *f, struct page * page)
++{
++ struct inode *d_inode = f->f_dentry->d_inode;
++ CorbaFS_Inode inode;
++ CorbaFS_Buffer *buffer = NULL;
++
++ int offset = page->index*PAGE_CACHE_SIZE;
++ int bytesRead;
++
++#if 0
++ printk("*** READPAGE 0x%p: 0x%lX->0x%lX to 0x%p\n",
++ f,
++ page->index,
++ page->index*PAGE_CACHE_SIZE,
++ page_address(page));
++#endif
++
++ inode = d_inode->u.generic_ip;
++ if (!inode) return -EPERM;
++
++ CorbaFS_Inode_readpage(inode, &buffer, PAGE_CACHE_SIZE, offset, ev);
++ if (!buffer) return -EPERM; /* ??? */
++
++ bytesRead = buffer->_length;
++ memcpy(page_address(page), buffer->_buffer, bytesRead);
++
++ if (bytesRead != PAGE_CACHE_SIZE) { /* EOF? */
++ /* Zero out rest of page for security. */
++ memset((void*)(page_address(page)+bytesRead), 0,
++ PAGE_CACHE_SIZE-bytesRead);
++ }
++
++ SetPageUptodate(page);
++ UnlockPage(page);
++ return 0;
++}
++
++
++
++struct inode *corbafs_get_inode(struct super_block *sb, const char *path)
++{
++ struct inode * inode = get_empty_inode();
++ CorbaFS_FileSystem fs_client;
++ CorbaFS_Inode newInode;
++
++ if (!inode) return 0;
++
++ inode->i_sb = sb;
++ inode->i_dev = sb->s_dev;
++
++ fs_client = sb->u.generic_sbp;
++//printk("\n \n \nCorbaFS_FileSystem_getInode(0x%X, %s)\n", fs_client, path);
++ newInode = CorbaFS_FileSystem_getInode(fs_client, path, ev);
++//printk("NewInode = 0x%X\n \n \n \n", newInode);
++ if (!newInode) {
++ iput(inode);
++ return NULL;
++ }
++
++//printk("CorbaFS_Inode_getStatus\n");
++ CorbaFS_Inode_getStatus(newInode,
++ &inode->i_mode, &inode->i_uid, &inode->i_gid,
++ (CORBA_unsigned_long *)&inode->i_size,
++ (CORBA_unsigned_long *)&inode->i_ino,
++ &inode->i_nlink,
++ (CORBA_long *)&inode->i_atime,
++ (CORBA_long *)&inode->i_mtime,
++ (CORBA_long *)&inode->i_ctime,
++ ev);
++//printk("Back from CorbaFS_Inode_getStatus\n \n \n \n");
++
++ inode->u.generic_ip = (void*)newInode;
++
++ /* TODO: Map things back correctly??? */
++ inode->i_uid = 0 /*current->fsuid */;
++ inode->i_gid = 0 /*current->fsgid */;
++
++ inode->i_blksize = PAGE_CACHE_SIZE;
++ inode->i_blocks = 0;
++ inode->i_rdev = 0;
++ inode->i_op = NULL;
++ inode->i_fop = NULL;
++ inode->i_mapping->a_ops = &corbafs_aops;
++ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
++
++ switch (inode->i_mode & S_IFMT) {
++ default:
++ /* Do I really want to expose device inodes? */
++ init_special_inode(inode, inode->i_mode, sb->s_dev);
++ break;
++ case S_IFREG:
++ inode->i_fop = &corbafs_file_operations;
++ break;
++ case S_IFDIR:
++ inode->i_op = &corbafs_dir_inode_operations;
++ inode->i_fop = &corbafs_dir_operations;
++ break;
++ case S_IFLNK:
++ inode->i_op = &corbafs_symlink_inode_operations;
++ break;
++ }
++ insert_inode_hash(inode);
++
++ return inode;
++}
++
++static int corbafs_readdir(struct file *file, void *data, filldir_t filldir)
++{
++ struct inode *inode = file->f_dentry->d_inode;
++ struct super_block *sb = file->f_dentry->d_sb;
++ unsigned offset = file->f_pos;
++ char *path, *page = (char *)__get_free_page(GFP_KERNEL);
++ int i;
++ unsigned char d_type = DT_UNKNOWN;
++ CorbaFS_FileSystem fs_client;
++ CorbaFS_DirEntSeq *dirEntSeq;
++ CorbaFS_dirent *dirEnts;
++
++ if (offset >= inode->i_size) return 0;
++
++ path = d_local_path(file->f_dentry, page, PAGE_SIZE);
++
++ fs_client = sb->u.generic_sbp;
++ if (!fs_client)
++ return -EPERM; /* ??? */
++
++// printk("\n \n \nCorbaFS_FileSystem_readdir(%s)\n", path);
++
++ dirEntSeq = CorbaFS_FileSystem_readdir(fs_client, path, ev);
++
++// printk("CorbaFS_FileSystem_readdir = %d\n \n \n \n", dirEntSeq->_length);
++
++ if (dirEntSeq->_length == 0) goto full;
++
++ dirEnts = dirEntSeq->_buffer;
++ i = 0;
++ if (offset) { // We have read PART of the directory
++ int idxadj = offset; // Start reading now from where we left
++ while (idxadj > 0) { // off...
++ idxadj -= sizeof(struct dirent)+
++ strlen(dirEnts[i].name);
++ i++;
++ }
++
++ if (idxadj < 0) { // We should end up with exactly 0.
++ printf("Alert! Readdir can't resume in the middle "
++ "of a directory! stopage.\n");
++ goto full;
++ }
++ }
++
++ for (; i < dirEntSeq->_length; i++) {
++ int myinode = dirEnts[i].inode;
++ char *myname = dirEnts[i].name;
++ int namelen = strlen(myname);
++
++ if (filldir(data, myname, namelen, offset, myinode, d_type))
++ goto full;
++ offset += sizeof(struct dirent)+namelen;
++ }
++
++ full:
++ file->f_pos = offset;
++ return 0;
++}
++
++static int corbafs_statfs(struct super_block *sb, struct statfs *buf) {
++ buf->f_type = CORBAFS_MAGIC;
++ buf->f_bsize = PAGE_CACHE_SIZE;
++ buf->f_namelen = 255;
++ return 0;
++}
++
++/*
++ * Lookup the data. Most of the grunt work is done by corbafs_get_inode.
++ */
++static struct dentry *corbafs_lookup(struct inode *dir, struct dentry *dentry)
++{
++ struct inode *New;
++ char *Path, *Page = (char *)__get_free_page(GFP_KERNEL);
++ if (Page == 0) goto out; /* nomem? */
++
++ Path = d_local_path(dentry, Page, PAGE_SIZE);
++
++ New = corbafs_get_inode(dir->i_sb, Path);
++ free_page((unsigned long)Page);
++
++ if (New) {
++ d_add(dentry, New);
++ return 0;
++ }
++
++out:
++ d_add(dentry, NULL);
++ return 0;
++}
++
++
++static char *corbafs_read_a_link(struct dentry *dentry) {
++ char *path, *page, *s = 0;
++ struct super_block *sb = dentry->d_sb;
++ CorbaFS_FileSystem fs_client;
++
++ page = (char *)__get_free_page(GFP_KERNEL);
++ if (page == 0) goto out; /* nomem? */
++
++ path = d_local_path(dentry, page, PAGE_SIZE);
++
++ fs_client = sb->u.generic_sbp;
++// printk("\n \n \nCorbaFS_FileSystem_readlink(%s)\n", path);
++ s = CorbaFS_FileSystem_readlink(fs_client, path, ev);
++// printk("CorbaFS_FileSystem_readlink = %s\n \n \n \n", s);
++
++ if (ev->_major != CORBA_NO_EXCEPTION) {
++ if (s) {
++ // CORBA_string_free(s,..);
++ s = 0;
++ }
++ goto outfree;
++ }
++ outfree:
++ free_page((unsigned long)page);
++ out:
++ return s;
++}
++
++
++static int corbafs_readlink(struct dentry *dentry, char *buffer, int buflen) {
++ char *str = corbafs_read_a_link(dentry);
++ int error = -EINVAL;
++
++ if (str) {
++ error = vfs_readlink(dentry, buffer, buflen, str);
++ // TODO: CORBA_string__free the string str.
++ }
++ return error;
++}
++
++/* Fill in nd->dentry
++ */
++static int corbafs_followlink(struct dentry *link, struct nameidata *nd) {
++ int Error = -ENOMEM;
++ char *Path = corbafs_read_a_link(link);
++ if (!Path) goto out;
++
++#if 1
++ printk("Followlink: %s\n", Path);
++#endif
++ Error = vfs_follow_link(nd, Path);
++ // TODO: CORBA_string__free the string str.
++
++ out:
++ return Error;
++}
++
++static void corbafs_delete_inode(struct inode *inode) {
++ CorbaFS_Inode Inode = inode->u.generic_ip;
++// printk("\n \n \nCorbaFS_Inode_Release\n");
++ CorbaFS_Inode_release(Inode, ev);
++// printk("CorbaFS_Inode_Release done\n \n \n \n");
++}
++
++static void corbafs_put_super(struct super_block *sb) {
++// MOD_DEC_USE_COUNT;
++}
++
++static struct super_block *corbafs_read_super(struct super_block * sb, void * data, int silent) {
++ struct dentry *root = 0;
++ struct inode *root_inode = 0;
++
++ CorbaFS_FileSystem fs_client;
++
++ sb->s_blocksize = PAGE_CACHE_SIZE;
++ sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
++ sb->s_magic = CORBAFS_MAGIC;
++ sb->s_op = &corbafs_ops;
++
++//printk("corbafs_read_super: '%s'\n", (char*)data);
++
++ // Note that the CORBA IOR is now in *data
++ fs_client = CORBA_ORB_string_to_object(orb, data, ev);
++
++//printk("fs_client: 0x%X\n", fs_client);
++ if (!fs_client)
++ return NULL;
++
++ sb->u.generic_sbp = fs_client;
++
++ root_inode = corbafs_get_inode(sb, "/");
++//printk("root_inode = 0x%X\n", root_inode);
++ root = d_alloc_root(root_inode);
++ if (!root) {
++ iput(root_inode);
++ return NULL;
++ }
++ sb->s_root = root;
++
++// MOD_INC_USE_COUNT;
++ return sb;
++}
++
++static DECLARE_FSTYPE(corbafs_fs_type, "corbafs", corbafs_read_super, 0);
++
++static int __init init_corbafs_fs(void) {
++ int argc = 1;
++ char *argv[] = { "client", 0 };
++ ev = g_new0(CORBA_Environment,1);
++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", ev);
++
++ return register_filesystem(&corbafs_fs_type);
++}
++
++static void __exit exit_corbafs_fs(void)
++{
++ // remove object from orb.
++ printf("\n \n \nCorbaFS_exit()\n");
++ unregister_filesystem(&corbafs_fs_type);
++ CORBA_Object_release((CORBA_Object)orb, ev);
++}
++
++module_init(init_corbafs_fs)
++module_exit(exit_corbafs_fs)
++
++/*
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS-common.c linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS-common.c
+--- linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS-common.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS-common.c Thu Feb 1 16:36:08 2001
+@@ -0,0 +1,370 @@
++/*
++ * This file was generated by orbit-idl - DO NOT EDIT!
++ */
++
++#include <string.h>
++#include "CorbaFS.h"
++
++#if ( (TC_IMPL_TC_CorbaFS_dirent_0 == 'C') \
++&& (TC_IMPL_TC_CorbaFS_dirent_1 == 'o') \
++&& (TC_IMPL_TC_CorbaFS_dirent_2 == 'r') \
++&& (TC_IMPL_TC_CorbaFS_dirent_3 == 'b') \
++&& (TC_IMPL_TC_CorbaFS_dirent_4 == 'a') \
++&& (TC_IMPL_TC_CorbaFS_dirent_5 == 'F') \
++&& (TC_IMPL_TC_CorbaFS_dirent_6 == 'S') \
++) && !defined(TC_DEF_TC_CorbaFS_dirent)
++#define TC_DEF_TC_CorbaFS_dirent 1
++static const char *anon_subnames_array1[] = { "inode", "name" };
++static const CORBA_TypeCode anon_subtypes_array2[] =
++ { (CORBA_TypeCode) & TC_CORBA_long_struct,
++ (CORBA_TypeCode) & TC_CORBA_string_struct };
++const struct CORBA_TypeCode_struct TC_CorbaFS_dirent_struct = {
++
++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1},
++ ORBIT_PSEUDO_TYPECODE},
++
++ CORBA_tk_struct, "dirent", "IDL:CorbaFS/dirent:1.0",
++ 0, 2,
++ (const char **) anon_subnames_array1,
++ (CORBA_TypeCode *) anon_subtypes_array2,
++ NULL,
++ CORBA_OBJECT_NIL, 0, -1, 0, 0
++};
++#endif
++#if ( (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_0 == 'C') \
++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_1 == 'o') \
++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_2 == 'r') \
++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_3 == 'b') \
++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_4 == 'a') \
++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_5 == 'F') \
++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_6 == 'S') \
++) && !defined(TC_DEF_TC_CORBA_sequence_CorbaFS_dirent)
++#define TC_DEF_TC_CORBA_sequence_CorbaFS_dirent 1
++static const CORBA_TypeCode anon_subtypes_array6[] =
++ { (CORBA_TypeCode) & TC_CorbaFS_dirent_struct };
++const struct CORBA_TypeCode_struct TC_CORBA_sequence_CorbaFS_dirent_struct = {
++
++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1},
++ ORBIT_PSEUDO_TYPECODE},
++
++ CORBA_tk_sequence, NULL, NULL,
++ 0, 1,
++ NULL,
++ (CORBA_TypeCode *) anon_subtypes_array6,
++ NULL,
++ CORBA_OBJECT_NIL, 0, -1, 0, 0
++};
++#endif
++#if ( (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_0 == 'C') \
++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_1 == 'o') \
++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_2 == 'r') \
++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_3 == 'b') \
++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_4 == 'a') \
++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_5 == 'F') \
++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_6 == 'S') \
++) && !defined(TC_DEF_TC_CORBA_sequence_CorbaFS_dirent)
++#define TC_DEF_TC_CORBA_sequence_CorbaFS_dirent 1
++static const CORBA_TypeCode anon_subtypes_array15[] =
++ { (CORBA_TypeCode) & TC_CorbaFS_dirent_struct };
++const struct CORBA_TypeCode_struct TC_CORBA_sequence_CorbaFS_dirent_struct = {
++
++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1},
++ ORBIT_PSEUDO_TYPECODE},
++
++ CORBA_tk_sequence, NULL, NULL,
++ 0, 1,
++ NULL,
++ (CORBA_TypeCode *) anon_subtypes_array15,
++ NULL,
++ CORBA_OBJECT_NIL, 0, -1, 0, 0
++};
++#endif
++#if ( (TC_IMPL_TC_CorbaFS_DirEntSeq_0 == 'C') \
++&& (TC_IMPL_TC_CorbaFS_DirEntSeq_1 == 'o') \
++&& (TC_IMPL_TC_CorbaFS_DirEntSeq_2 == 'r') \
++&& (TC_IMPL_TC_CorbaFS_DirEntSeq_3 == 'b') \
++&& (TC_IMPL_TC_CorbaFS_DirEntSeq_4 == 'a') \
++&& (TC_IMPL_TC_CorbaFS_DirEntSeq_5 == 'F') \
++&& (TC_IMPL_TC_CorbaFS_DirEntSeq_6 == 'S') \
++) && !defined(TC_DEF_TC_CorbaFS_DirEntSeq)
++#define TC_DEF_TC_CorbaFS_DirEntSeq 1
++static const CORBA_TypeCode anon_subtypes_array19[] =
++ { (CORBA_TypeCode) & TC_CORBA_sequence_CorbaFS_dirent_struct };
++const struct CORBA_TypeCode_struct TC_CorbaFS_DirEntSeq_struct = {
++
++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1},
++ ORBIT_PSEUDO_TYPECODE},
++
++ CORBA_tk_alias, "DirEntSeq", "IDL:CorbaFS/DirEntSeq:1.0",
++ 0, 1,
++ NULL,
++ (CORBA_TypeCode *) anon_subtypes_array19,
++ NULL,
++ CORBA_OBJECT_NIL, 0, -1, 0, 0
++};
++#endif
++#if ( (TC_IMPL_TC_CORBA_sequence_CORBA_octet_0 == 'C') \
++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_1 == 'o') \
++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_2 == 'r') \
++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_3 == 'b') \
++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_4 == 'a') \
++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_5 == 'F') \
++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_6 == 'S') \
++) && !defined(TC_DEF_TC_CORBA_sequence_CORBA_octet)
++#define TC_DEF_TC_CORBA_sequence_CORBA_octet 1
++static const CORBA_TypeCode anon_subtypes_array23[] =
++ { (CORBA_TypeCode) & TC_CORBA_octet_struct };
++const struct CORBA_TypeCode_struct TC_CORBA_sequence_CORBA_octet_struct = {
++
++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1},
++ ORBIT_PSEUDO_TYPECODE},
++
++ CORBA_tk_sequence, NULL, NULL,
++ 0, 1,
++ NULL,
++ (CORBA_TypeCode *) anon_subtypes_array23,
++ NULL,
++ CORBA_OBJECT_NIL, 0, -1, 0, 0
++};
++#endif
++#if ( (TC_IMPL_TC_CORBA_sequence_CORBA_octet_0 == 'C') \
++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_1 == 'o') \
++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_2 == 'r') \
++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_3 == 'b') \
++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_4 == 'a') \
++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_5 == 'F') \
++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_6 == 'S') \
++) && !defined(TC_DEF_TC_CORBA_sequence_CORBA_octet)
++#define TC_DEF_TC_CORBA_sequence_CORBA_octet 1
++static const CORBA_TypeCode anon_subtypes_array32[] =
++ { (CORBA_TypeCode) & TC_CORBA_octet_struct };
++const struct CORBA_TypeCode_struct TC_CORBA_sequence_CORBA_octet_struct = {
++
++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1},
++ ORBIT_PSEUDO_TYPECODE},
++
++ CORBA_tk_sequence, NULL, NULL,
++ 0, 1,
++ NULL,
++ (CORBA_TypeCode *) anon_subtypes_array32,
++ NULL,
++ CORBA_OBJECT_NIL, 0, -1, 0, 0
++};
++#endif
++#if ( (TC_IMPL_TC_CorbaFS_Buffer_0 == 'C') \
++&& (TC_IMPL_TC_CorbaFS_Buffer_1 == 'o') \
++&& (TC_IMPL_TC_CorbaFS_Buffer_2 == 'r') \
++&& (TC_IMPL_TC_CorbaFS_Buffer_3 == 'b') \
++&& (TC_IMPL_TC_CorbaFS_Buffer_4 == 'a') \
++&& (TC_IMPL_TC_CorbaFS_Buffer_5 == 'F') \
++&& (TC_IMPL_TC_CorbaFS_Buffer_6 == 'S') \
++) && !defined(TC_DEF_TC_CorbaFS_Buffer)
++#define TC_DEF_TC_CorbaFS_Buffer 1
++static const CORBA_TypeCode anon_subtypes_array36[] =
++ { (CORBA_TypeCode) & TC_CORBA_sequence_CORBA_octet_struct };
++const struct CORBA_TypeCode_struct TC_CorbaFS_Buffer_struct = {
++
++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1},
++ ORBIT_PSEUDO_TYPECODE},
++
++ CORBA_tk_alias, "Buffer", "IDL:CorbaFS/Buffer:1.0",
++ 0, 1,
++ NULL,
++ (CORBA_TypeCode *) anon_subtypes_array36,
++ NULL,
++ CORBA_OBJECT_NIL, 0, -1, 0, 0
++};
++#endif
++#if ( (TC_IMPL_TC_CorbaFS_Inode_0 == 'C') \
++&& (TC_IMPL_TC_CorbaFS_Inode_1 == 'o') \
++&& (TC_IMPL_TC_CorbaFS_Inode_2 == 'r') \
++&& (TC_IMPL_TC_CorbaFS_Inode_3 == 'b') \
++&& (TC_IMPL_TC_CorbaFS_Inode_4 == 'a') \
++&& (TC_IMPL_TC_CorbaFS_Inode_5 == 'F') \
++&& (TC_IMPL_TC_CorbaFS_Inode_6 == 'S') \
++) && !defined(TC_DEF_TC_CorbaFS_Inode)
++#define TC_DEF_TC_CorbaFS_Inode 1
++const struct CORBA_TypeCode_struct TC_CorbaFS_Inode_struct = {
++
++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1},
++ ORBIT_PSEUDO_TYPECODE},
++
++ CORBA_tk_objref, "Inode", "IDL:CorbaFS/Inode:1.0",
++ 0, 0,
++ NULL,
++ NULL,
++ NULL,
++ CORBA_OBJECT_NIL, 0, -1, 0, 0
++};
++#endif
++#if ( (TC_IMPL_TC_CorbaFS_FileSystem_0 == 'C') \
++&& (TC_IMPL_TC_CorbaFS_FileSystem_1 == 'o') \
++&& (TC_IMPL_TC_CorbaFS_FileSystem_2 == 'r') \
++&& (TC_IMPL_TC_CorbaFS_FileSystem_3 == 'b') \
++&& (TC_IMPL_TC_CorbaFS_FileSystem_4 == 'a') \
++&& (TC_IMPL_TC_CorbaFS_FileSystem_5 == 'F') \
++&& (TC_IMPL_TC_CorbaFS_FileSystem_6 == 'S') \
++) && !defined(TC_DEF_TC_CorbaFS_FileSystem)
++#define TC_DEF_TC_CorbaFS_FileSystem 1
++const struct CORBA_TypeCode_struct TC_CorbaFS_FileSystem_struct = {
++
++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1},
++ ORBIT_PSEUDO_TYPECODE},
++
++ CORBA_tk_objref, "FileSystem", "IDL:CorbaFS/FileSystem:1.0",
++ 0, 0,
++ NULL,
++ NULL,
++ NULL,
++ CORBA_OBJECT_NIL, 0, -1, 0, 0
++};
++#endif
++gpointer
++CorbaFS_dirent__free(gpointer mem, gpointer dat, CORBA_boolean free_strings)
++{
++ CorbaFS_dirent *var = mem;
++
++ if (free_strings) {
++ CORBA_string__free(&(var->name), NULL, free_strings);
++ }
++ return (gpointer) (var + 1);
++}
++
++CorbaFS_dirent *
++CorbaFS_dirent__alloc(void)
++{
++ CorbaFS_dirent *retval;
++
++ retval =
++ ORBit_alloc(sizeof(CorbaFS_dirent),
++ (ORBit_free_childvals) CorbaFS_dirent__free,
++ GUINT_TO_POINTER(1));
++ memset(&(retval->name), '\0', sizeof(retval->name));
++ return retval;
++}
++
++#if ( (ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_0 == 'C') \
++&& (ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_1 == 'o') \
++&& (ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_2 == 'r') \
++&& (ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_3 == 'b') \
++&& (ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_4 == 'a') \
++&& (ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_5 == 'F') \
++&& (ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_6 == 'S') \
++) && !defined(ORBIT_DEF_CORBA_sequence_CorbaFS_dirent)
++#define ORBIT_DEF_CORBA_sequence_CorbaFS_dirent 1
++
++gpointer
++CORBA_sequence_CorbaFS_dirent__free(gpointer mem, gpointer dat,
++ CORBA_boolean free_strings)
++{
++ CORBA_sequence_CorbaFS_dirent *val = mem;
++
++ if (val->_release)
++ ORBit_free(val->_buffer, free_strings);
++ return (gpointer) (val + 1);
++}
++
++CORBA_sequence_CorbaFS_dirent *
++CORBA_sequence_CorbaFS_dirent__alloc(void)
++{
++ CORBA_sequence_CorbaFS_dirent *retval;
++
++ retval =
++ ORBit_alloc(sizeof(CORBA_sequence_CorbaFS_dirent),
++ (ORBit_free_childvals) CORBA_sequence_CorbaFS_dirent__free,
++ GUINT_TO_POINTER(1));
++ retval->_maximum = 0;
++ retval->_length = 0;
++ retval->_buffer = NULL;
++ retval->_release = CORBA_FALSE;
++ return retval;
++}
++
++CorbaFS_dirent *
++CORBA_sequence_CorbaFS_dirent_allocbuf(CORBA_unsigned_long len)
++{
++ CorbaFS_dirent *retval =
++ ORBit_alloc(sizeof(CorbaFS_dirent) * len,
++ (ORBit_free_childvals) CorbaFS_dirent__free,
++ GUINT_TO_POINTER(len));
++
++ memset(retval, '\0', sizeof(CorbaFS_dirent) * len);
++ return retval;
++}
++#endif
++
++gpointer
++CorbaFS_DirEntSeq__free(gpointer mem, gpointer dat,
++ CORBA_boolean free_strings)
++{
++ return CORBA_sequence_CorbaFS_dirent__free(mem, dat, free_strings);
++}
++
++CorbaFS_DirEntSeq *
++CorbaFS_DirEntSeq__alloc(void)
++{
++ return CORBA_sequence_CorbaFS_dirent__alloc();
++}
++
++#if ( (ORBIT_IMPL_CORBA_sequence_CORBA_octet_0 == 'C') \
++&& (ORBIT_IMPL_CORBA_sequence_CORBA_octet_1 == 'o') \
++&& (ORBIT_IMPL_CORBA_sequence_CORBA_octet_2 == 'r') \
++&& (ORBIT_IMPL_CORBA_sequence_CORBA_octet_3 == 'b') \
++&& (ORBIT_IMPL_CORBA_sequence_CORBA_octet_4 == 'a') \
++&& (ORBIT_IMPL_CORBA_sequence_CORBA_octet_5 == 'F') \
++&& (ORBIT_IMPL_CORBA_sequence_CORBA_octet_6 == 'S') \
++) && !defined(ORBIT_DEF_CORBA_sequence_CORBA_octet)
++#define ORBIT_DEF_CORBA_sequence_CORBA_octet 1
++
++gpointer
++CORBA_sequence_CORBA_octet__free(gpointer mem, gpointer dat,
++ CORBA_boolean free_strings)
++{
++ CORBA_sequence_CORBA_octet *val = mem;
++
++ if (val->_release)
++ ORBit_free(val->_buffer, free_strings);
++ return (gpointer) (val + 1);
++}
++
++CORBA_sequence_CORBA_octet *
++CORBA_sequence_CORBA_octet__alloc(void)
++{
++ CORBA_sequence_CORBA_octet *retval;
++
++ retval =
++ ORBit_alloc(sizeof(CORBA_sequence_CORBA_octet),
++ (ORBit_free_childvals) CORBA_sequence_CORBA_octet__free,
++ GUINT_TO_POINTER(1));
++ retval->_maximum = 0;
++ retval->_length = 0;
++ retval->_buffer = NULL;
++ retval->_release = CORBA_FALSE;
++ return retval;
++}
++
++CORBA_octet *
++CORBA_sequence_CORBA_octet_allocbuf(CORBA_unsigned_long len)
++{
++ CORBA_octet *retval =
++ ORBit_alloc(sizeof(CORBA_octet) * len, (ORBit_free_childvals) NULL,
++ GUINT_TO_POINTER(len));
++
++ return retval;
++}
++#endif
++
++gpointer
++CorbaFS_Buffer__free(gpointer mem, gpointer dat, CORBA_boolean free_strings)
++{
++ return CORBA_sequence_CORBA_octet__free(mem, dat, free_strings);
++}
++
++CorbaFS_Buffer *
++CorbaFS_Buffer__alloc(void)
++{
++ return CORBA_sequence_CORBA_octet__alloc();
++}
++
++CORBA_unsigned_long CorbaFS_Inode__classid = 0;
++CORBA_unsigned_long CorbaFS_FileSystem__classid = 0;
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS-stubs.c linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS-stubs.c
+--- linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS-stubs.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS-stubs.c Thu Feb 1 16:36:08 2001
+@@ -0,0 +1,791 @@
++/*
++ * This file was generated by orbit-idl - DO NOT EDIT!
++ */
++
++#include <string.h>
++#include "CorbaFS.h"
++
++void
++CorbaFS_Inode_getStatus(CorbaFS_Inode _obj, CORBA_unsigned_short * mode,
++ CORBA_unsigned_long * uid, CORBA_unsigned_long * gid,
++ CORBA_unsigned_long * size,
++ CORBA_unsigned_long * inodeNum,
++ CORBA_unsigned_short * numLinks, CORBA_long * atime,
++ CORBA_long * mtime, CORBA_long * ctime,
++ CORBA_Environment * ev)
++{
++ register GIOP_unsigned_long _ORBIT_request_id,
++ _ORBIT_system_exception_minor;
++ register CORBA_completion_status _ORBIT_completion_status;
++ register GIOPSendBuffer *_ORBIT_send_buffer;
++ register GIOPRecvBuffer *_ORBIT_recv_buffer;
++ register GIOPConnection *_cnx;
++
++ if (_obj->servant && _obj->vepv && CorbaFS_Inode__classid) {
++
++ ((POA_CorbaFS_Inode__epv *) _obj->vepv[CorbaFS_Inode__classid])->
++ getStatus(_obj->servant, mode, uid, gid, size, inodeNum, numLinks,
++ atime, mtime, ctime, ev);
++ return;
++ }
++ _cnx = ORBit_object_get_connection(_obj);
++ _ORBIT_retry_request:
++ _ORBIT_send_buffer = NULL;
++ _ORBIT_recv_buffer = NULL;
++ _ORBIT_completion_status = CORBA_COMPLETED_NO;
++ _ORBIT_request_id = GPOINTER_TO_UINT(alloca(0));
++ { /* marshalling */
++ static const struct
++ {
++ CORBA_unsigned_long len;
++ char opname[10];
++ }
++ _ORBIT_operation_name_data =
++ {
++ 10, "getStatus"};
++ static const struct iovec _ORBIT_operation_vec =
++ { (gpointer) & _ORBIT_operation_name_data, 14 };
++
++ _ORBIT_send_buffer =
++ giop_send_request_buffer_use(_cnx, NULL, _ORBIT_request_id,
++ CORBA_TRUE,
++ &(_obj->active_profile->object_key_vec),
++ &_ORBIT_operation_vec,
++ &ORBit_default_principal_iovec);
++
++ _ORBIT_system_exception_minor = ex_CORBA_COMM_FAILURE;
++ if (!_ORBIT_send_buffer)
++ goto _ORBIT_system_exception;
++ giop_send_buffer_write(_ORBIT_send_buffer);
++ _ORBIT_completion_status = CORBA_COMPLETED_MAYBE;
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ _ORBIT_send_buffer = NULL;
++ }
++ { /* demarshalling */
++ register guchar *_ORBIT_curptr;
++
++ _ORBIT_recv_buffer =
++ giop_recv_reply_buffer_use_2(_cnx, _ORBIT_request_id, TRUE);
++ if (!_ORBIT_recv_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_completion_status = CORBA_COMPLETED_YES;
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status !=
++ GIOP_NO_EXCEPTION) goto _ORBIT_msg_exception;
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) {
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 2);
++
++ (*((guint16 *) & ((*mode)))) =
++ GUINT16_SWAP_LE_BE(*((guint16 *) _ORBIT_curptr));
++ _ORBIT_curptr += 2;
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++
++ (*((guint32 *) & ((*uid)))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));
++ _ORBIT_curptr += 4;
++ (*((guint32 *) & ((*gid)))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));
++ _ORBIT_curptr += 4;
++ (*((guint32 *) & ((*size)))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));
++ _ORBIT_curptr += 4;
++ (*((guint32 *) & ((*inodeNum)))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));
++ _ORBIT_curptr += 4;
++ (*((guint16 *) & ((*numLinks)))) =
++ GUINT16_SWAP_LE_BE(*((guint16 *) _ORBIT_curptr));
++ _ORBIT_curptr += 2;
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++
++ (*((guint32 *) & ((*atime)))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));
++ _ORBIT_curptr += 4;
++ (*((guint32 *) & ((*mtime)))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));
++ _ORBIT_curptr += 4;
++ (*((guint32 *) & ((*ctime)))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));} else {
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 2);
++ (*mode) = *((CORBA_unsigned_short *) _ORBIT_curptr);
++ _ORBIT_curptr += 2;
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++ (*uid) = *((CORBA_unsigned_long *) _ORBIT_curptr);
++ _ORBIT_curptr += 4;
++ (*gid) = *((CORBA_unsigned_long *) _ORBIT_curptr);
++ _ORBIT_curptr += 4;
++ (*size) = *((CORBA_unsigned_long *) _ORBIT_curptr);
++ _ORBIT_curptr += 4;
++ (*inodeNum) = *((CORBA_unsigned_long *) _ORBIT_curptr);
++ _ORBIT_curptr += 4;
++ (*numLinks) = *((CORBA_unsigned_short *) _ORBIT_curptr);
++ _ORBIT_curptr += 2;
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++ (*atime) = *((CORBA_long *) _ORBIT_curptr);
++ _ORBIT_curptr += 4;
++ (*mtime) = *((CORBA_long *) _ORBIT_curptr);
++ _ORBIT_curptr += 4;
++ (*ctime) = *((CORBA_long *) _ORBIT_curptr);
++ }
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return;
++ _ORBIT_system_exception:
++ CORBA_exception_set_system(ev, _ORBIT_system_exception_minor,
++ _ORBIT_completion_status);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ return;
++ _ORBIT_msg_exception:
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status ==
++ GIOP_LOCATION_FORWARD) {
++ if (_obj->forward_locations != NULL)
++ ORBit_delete_profiles(_obj->forward_locations);
++ _obj->forward_locations = ORBit_demarshal_IOR(_ORBIT_recv_buffer);
++ _cnx = ORBit_object_get_forwarded_connection(_obj);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++
++ goto _ORBIT_retry_request;
++ } else {
++ ORBit_handle_exception(_ORBIT_recv_buffer, ev, NULL, _obj->orb);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return;
++ }
++ }
++}
++void
++CorbaFS_Inode_readpage(CorbaFS_Inode _obj, CorbaFS_Buffer ** buffer,
++ const CORBA_long size, const CORBA_long offset,
++ CORBA_Environment * ev)
++{
++ register GIOP_unsigned_long _ORBIT_request_id,
++ _ORBIT_system_exception_minor;
++ register CORBA_completion_status _ORBIT_completion_status;
++ register GIOPSendBuffer *_ORBIT_send_buffer;
++ register GIOPRecvBuffer *_ORBIT_recv_buffer;
++ register GIOPConnection *_cnx;
++ register CORBA_unsigned_long _ORBIT_tmpvar_1;
++
++ if (_obj->servant && _obj->vepv && CorbaFS_Inode__classid) {
++
++ ((POA_CorbaFS_Inode__epv *) _obj->vepv[CorbaFS_Inode__classid])->
++ readpage(_obj->servant, buffer, size, offset, ev);
++ return;
++ }
++ _cnx = ORBit_object_get_connection(_obj);
++ _ORBIT_retry_request:
++ _ORBIT_send_buffer = NULL;
++ _ORBIT_recv_buffer = NULL;
++ _ORBIT_completion_status = CORBA_COMPLETED_NO;
++ _ORBIT_request_id = GPOINTER_TO_UINT(alloca(0));
++ { /* marshalling */
++ static const struct
++ {
++ CORBA_unsigned_long len;
++ char opname[9];
++ }
++ _ORBIT_operation_name_data =
++ {
++ 9, "readpage"};
++ static const struct iovec _ORBIT_operation_vec =
++ { (gpointer) & _ORBIT_operation_name_data, 13 };
++
++ _ORBIT_send_buffer =
++ giop_send_request_buffer_use(_cnx, NULL, _ORBIT_request_id,
++ CORBA_TRUE,
++ &(_obj->active_profile->object_key_vec),
++ &_ORBIT_operation_vec,
++ &ORBit_default_principal_iovec);
++
++ _ORBIT_system_exception_minor = ex_CORBA_COMM_FAILURE;
++ if (!_ORBIT_send_buffer)
++ goto _ORBIT_system_exception;
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER
++ (_ORBIT_send_buffer), 4);
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer),
++ &(size), sizeof(size));
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer),
++ &(offset), sizeof(offset));
++ giop_send_buffer_write(_ORBIT_send_buffer);
++ _ORBIT_completion_status = CORBA_COMPLETED_MAYBE;
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ _ORBIT_send_buffer = NULL;
++ }
++ { /* demarshalling */
++ register guchar *_ORBIT_curptr;
++
++ _ORBIT_recv_buffer =
++ giop_recv_reply_buffer_use_2(_cnx, _ORBIT_request_id, TRUE);
++ if (!_ORBIT_recv_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_completion_status = CORBA_COMPLETED_YES;
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status !=
++ GIOP_NO_EXCEPTION) goto _ORBIT_msg_exception;
++ *buffer = CorbaFS_Buffer__alloc();
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) {
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++
++ (*((guint32 *) & (((**buffer))._length))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));
++ _ORBIT_curptr += 4;
++
++ ((**buffer))._buffer =
++ CORBA_sequence_CORBA_octet_allocbuf(((**buffer))._length);
++ ((**buffer))._release = CORBA_TRUE;
++ memcpy(((**buffer))._buffer, _ORBIT_curptr,
++ sizeof(((**buffer))._buffer[_ORBIT_tmpvar_1]) *
++ ((**buffer))._length);
++ _ORBIT_curptr +=
++ sizeof(((**buffer))._buffer[_ORBIT_tmpvar_1]) *
++ ((**buffer))._length;
++ } else {
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++ ((**buffer))._length = *((CORBA_unsigned_long *) _ORBIT_curptr);
++ _ORBIT_curptr += 4;
++
++ ((**buffer))._buffer =
++ CORBA_sequence_CORBA_octet_allocbuf(((**buffer))._length);
++ ((**buffer))._release = CORBA_TRUE;
++ memcpy(((**buffer))._buffer, _ORBIT_curptr,
++ sizeof(((**buffer))._buffer[_ORBIT_tmpvar_1]) *
++ ((**buffer))._length);
++ _ORBIT_curptr +=
++ sizeof(((**buffer))._buffer[_ORBIT_tmpvar_1]) *
++ ((**buffer))._length;
++ }
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return;
++ _ORBIT_system_exception:
++ CORBA_exception_set_system(ev, _ORBIT_system_exception_minor,
++ _ORBIT_completion_status);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ return;
++ _ORBIT_msg_exception:
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status ==
++ GIOP_LOCATION_FORWARD) {
++ if (_obj->forward_locations != NULL)
++ ORBit_delete_profiles(_obj->forward_locations);
++ _obj->forward_locations = ORBit_demarshal_IOR(_ORBIT_recv_buffer);
++ _cnx = ORBit_object_get_forwarded_connection(_obj);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++
++ goto _ORBIT_retry_request;
++ } else {
++ ORBit_handle_exception(_ORBIT_recv_buffer, ev, NULL, _obj->orb);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return;
++ }
++ }
++}
++void
++CorbaFS_Inode_release(CorbaFS_Inode _obj, CORBA_Environment * ev)
++{
++ register GIOP_unsigned_long _ORBIT_request_id,
++ _ORBIT_system_exception_minor;
++ register CORBA_completion_status _ORBIT_completion_status;
++ register GIOPSendBuffer *_ORBIT_send_buffer;
++ register GIOPRecvBuffer *_ORBIT_recv_buffer;
++ register GIOPConnection *_cnx;
++
++ if (_obj->servant && _obj->vepv && CorbaFS_Inode__classid) {
++
++ ((POA_CorbaFS_Inode__epv *) _obj->vepv[CorbaFS_Inode__classid])->
++ release(_obj->servant, ev);
++ return;
++ }
++ _cnx = ORBit_object_get_connection(_obj);
++ _ORBIT_retry_request:
++ _ORBIT_send_buffer = NULL;
++ _ORBIT_recv_buffer = NULL;
++ _ORBIT_completion_status = CORBA_COMPLETED_NO;
++ _ORBIT_request_id = GPOINTER_TO_UINT(alloca(0));
++ { /* marshalling */
++ static const struct
++ {
++ CORBA_unsigned_long len;
++ char opname[8];
++ }
++ _ORBIT_operation_name_data =
++ {
++ 8, "release"};
++ static const struct iovec _ORBIT_operation_vec =
++ { (gpointer) & _ORBIT_operation_name_data, 12 };
++
++ _ORBIT_send_buffer =
++ giop_send_request_buffer_use(_cnx, NULL, _ORBIT_request_id,
++ CORBA_TRUE,
++ &(_obj->active_profile->object_key_vec),
++ &_ORBIT_operation_vec,
++ &ORBit_default_principal_iovec);
++
++ _ORBIT_system_exception_minor = ex_CORBA_COMM_FAILURE;
++ if (!_ORBIT_send_buffer)
++ goto _ORBIT_system_exception;
++ giop_send_buffer_write(_ORBIT_send_buffer);
++ _ORBIT_completion_status = CORBA_COMPLETED_MAYBE;
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ _ORBIT_send_buffer = NULL;
++ }
++ { /* demarshalling */
++ register guchar *_ORBIT_curptr;
++
++ _ORBIT_recv_buffer =
++ giop_recv_reply_buffer_use_2(_cnx, _ORBIT_request_id, TRUE);
++ if (!_ORBIT_recv_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_completion_status = CORBA_COMPLETED_YES;
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status !=
++ GIOP_NO_EXCEPTION) goto _ORBIT_msg_exception;
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) {
++ } else {
++ }
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return;
++ _ORBIT_system_exception:
++ CORBA_exception_set_system(ev, _ORBIT_system_exception_minor,
++ _ORBIT_completion_status);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ return;
++ _ORBIT_msg_exception:
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status ==
++ GIOP_LOCATION_FORWARD) {
++ if (_obj->forward_locations != NULL)
++ ORBit_delete_profiles(_obj->forward_locations);
++ _obj->forward_locations = ORBit_demarshal_IOR(_ORBIT_recv_buffer);
++ _cnx = ORBit_object_get_forwarded_connection(_obj);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++
++ goto _ORBIT_retry_request;
++ } else {
++ ORBit_handle_exception(_ORBIT_recv_buffer, ev, NULL, _obj->orb);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return;
++ }
++ }
++}
++CorbaFS_Inode
++CorbaFS_FileSystem_getInode(CorbaFS_FileSystem _obj, const CORBA_char * path,
++ CORBA_Environment * ev)
++{
++ register GIOP_unsigned_long _ORBIT_request_id,
++ _ORBIT_system_exception_minor;
++ register CORBA_completion_status _ORBIT_completion_status;
++ register GIOPSendBuffer *_ORBIT_send_buffer;
++ register GIOPRecvBuffer *_ORBIT_recv_buffer;
++ register GIOPConnection *_cnx;
++ CorbaFS_Inode _ORBIT_retval;
++
++ if (_obj->servant && _obj->vepv && CorbaFS_FileSystem__classid) {
++ _ORBIT_retval =
++ ((POA_CorbaFS_FileSystem__epv *) _obj->
++ vepv[CorbaFS_FileSystem__classid])->getInode(_obj->servant, path,
++ ev);
++ return _ORBIT_retval;
++ }
++ _cnx = ORBit_object_get_connection(_obj);
++ _ORBIT_retry_request:
++ _ORBIT_send_buffer = NULL;
++ _ORBIT_recv_buffer = NULL;
++ _ORBIT_completion_status = CORBA_COMPLETED_NO;
++ _ORBIT_request_id = GPOINTER_TO_UINT(alloca(0));
++ { /* marshalling */
++ static const struct
++ {
++ CORBA_unsigned_long len;
++ char opname[9];
++ }
++ _ORBIT_operation_name_data =
++ {
++ 9, "getInode"};
++ static const struct iovec _ORBIT_operation_vec =
++ { (gpointer) & _ORBIT_operation_name_data, 13 };
++ register CORBA_unsigned_long _ORBIT_tmpvar_0;
++ CORBA_unsigned_long _ORBIT_tmpvar_1;
++
++ _ORBIT_send_buffer =
++ giop_send_request_buffer_use(_cnx, NULL, _ORBIT_request_id,
++ CORBA_TRUE,
++ &(_obj->active_profile->object_key_vec),
++ &_ORBIT_operation_vec,
++ &ORBit_default_principal_iovec);
++
++ _ORBIT_system_exception_minor = ex_CORBA_COMM_FAILURE;
++ if (!_ORBIT_send_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_tmpvar_1 = strlen(path) + 1;
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER
++ (_ORBIT_send_buffer), 4);
++ {
++ guchar *_ORBIT_t;
++
++ _ORBIT_t = alloca(sizeof(_ORBIT_tmpvar_1));
++ memcpy(_ORBIT_t, &(_ORBIT_tmpvar_1), sizeof(_ORBIT_tmpvar_1));
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER
++ (_ORBIT_send_buffer), (_ORBIT_t),
++ sizeof(_ORBIT_tmpvar_1));
++ }
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer),
++ (path),
++ sizeof(path[_ORBIT_tmpvar_0]) *
++ _ORBIT_tmpvar_1);
++ giop_send_buffer_write(_ORBIT_send_buffer);
++ _ORBIT_completion_status = CORBA_COMPLETED_MAYBE;
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ _ORBIT_send_buffer = NULL;
++ }
++ { /* demarshalling */
++ register guchar *_ORBIT_curptr;
++
++ _ORBIT_recv_buffer =
++ giop_recv_reply_buffer_use_2(_cnx, _ORBIT_request_id, TRUE);
++ if (!_ORBIT_recv_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_completion_status = CORBA_COMPLETED_YES;
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status !=
++ GIOP_NO_EXCEPTION) goto _ORBIT_msg_exception;
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) {
++ GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur = _ORBIT_curptr;
++ _ORBIT_retval =
++ ORBit_demarshal_object(_ORBIT_recv_buffer,
++ GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)->
++ connection->orb_data);
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ } else {
++ GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur = _ORBIT_curptr;
++ _ORBIT_retval =
++ ORBit_demarshal_object(_ORBIT_recv_buffer,
++ GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)->
++ connection->orb_data);
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ }
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return _ORBIT_retval;
++ _ORBIT_system_exception:
++ CORBA_exception_set_system(ev, _ORBIT_system_exception_minor,
++ _ORBIT_completion_status);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ return _ORBIT_retval;
++ _ORBIT_msg_exception:
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status ==
++ GIOP_LOCATION_FORWARD) {
++ if (_obj->forward_locations != NULL)
++ ORBit_delete_profiles(_obj->forward_locations);
++ _obj->forward_locations = ORBit_demarshal_IOR(_ORBIT_recv_buffer);
++ _cnx = ORBit_object_get_forwarded_connection(_obj);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++
++ goto _ORBIT_retry_request;
++ } else {
++ ORBit_handle_exception(_ORBIT_recv_buffer, ev, NULL, _obj->orb);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return _ORBIT_retval;
++ }
++ }
++}
++CorbaFS_DirEntSeq *
++CorbaFS_FileSystem_readdir(CorbaFS_FileSystem _obj, const CORBA_char * path,
++ CORBA_Environment * ev)
++{
++ register GIOP_unsigned_long _ORBIT_request_id,
++ _ORBIT_system_exception_minor;
++ register CORBA_completion_status _ORBIT_completion_status;
++ register GIOPSendBuffer *_ORBIT_send_buffer;
++ register GIOPRecvBuffer *_ORBIT_recv_buffer;
++ register GIOPConnection *_cnx;
++ CorbaFS_DirEntSeq *_ORBIT_retval;
++ register CORBA_unsigned_long _ORBIT_tmpvar_5;
++ register CORBA_unsigned_long _ORBIT_tmpvar_6;
++ CORBA_unsigned_long _ORBIT_tmpvar_7;
++
++ if (_obj->servant && _obj->vepv && CorbaFS_FileSystem__classid) {
++ _ORBIT_retval =
++ ((POA_CorbaFS_FileSystem__epv *) _obj->
++ vepv[CorbaFS_FileSystem__classid])->readdir(_obj->servant, path,
++ ev);
++ return _ORBIT_retval;
++ }
++ _cnx = ORBit_object_get_connection(_obj);
++ _ORBIT_retry_request:
++ _ORBIT_send_buffer = NULL;
++ _ORBIT_recv_buffer = NULL;
++ _ORBIT_completion_status = CORBA_COMPLETED_NO;
++ _ORBIT_request_id = GPOINTER_TO_UINT(alloca(0));
++ { /* marshalling */
++ static const struct
++ {
++ CORBA_unsigned_long len;
++ char opname[8];
++ }
++ _ORBIT_operation_name_data =
++ {
++ 8, "readdir"};
++ static const struct iovec _ORBIT_operation_vec =
++ { (gpointer) & _ORBIT_operation_name_data, 12 };
++ register CORBA_unsigned_long _ORBIT_tmpvar_0;
++ CORBA_unsigned_long _ORBIT_tmpvar_1;
++
++ _ORBIT_send_buffer =
++ giop_send_request_buffer_use(_cnx, NULL, _ORBIT_request_id,
++ CORBA_TRUE,
++ &(_obj->active_profile->object_key_vec),
++ &_ORBIT_operation_vec,
++ &ORBit_default_principal_iovec);
++
++ _ORBIT_system_exception_minor = ex_CORBA_COMM_FAILURE;
++ if (!_ORBIT_send_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_tmpvar_1 = strlen(path) + 1;
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER
++ (_ORBIT_send_buffer), 4);
++ {
++ guchar *_ORBIT_t;
++
++ _ORBIT_t = alloca(sizeof(_ORBIT_tmpvar_1));
++ memcpy(_ORBIT_t, &(_ORBIT_tmpvar_1), sizeof(_ORBIT_tmpvar_1));
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER
++ (_ORBIT_send_buffer), (_ORBIT_t),
++ sizeof(_ORBIT_tmpvar_1));
++ }
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer),
++ (path),
++ sizeof(path[_ORBIT_tmpvar_0]) *
++ _ORBIT_tmpvar_1);
++ giop_send_buffer_write(_ORBIT_send_buffer);
++ _ORBIT_completion_status = CORBA_COMPLETED_MAYBE;
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ _ORBIT_send_buffer = NULL;
++ }
++ { /* demarshalling */
++ register guchar *_ORBIT_curptr;
++
++ _ORBIT_recv_buffer =
++ giop_recv_reply_buffer_use_2(_cnx, _ORBIT_request_id, TRUE);
++ if (!_ORBIT_recv_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_completion_status = CORBA_COMPLETED_YES;
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status !=
++ GIOP_NO_EXCEPTION) goto _ORBIT_msg_exception;
++ _ORBIT_retval = CorbaFS_DirEntSeq__alloc();
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) {
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++
++ (*((guint32 *) & ((*_ORBIT_retval)._length))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));
++ _ORBIT_curptr += 4;
++
++ (*_ORBIT_retval)._buffer =
++ CORBA_sequence_CorbaFS_dirent_allocbuf((*_ORBIT_retval)._length);
++ (*_ORBIT_retval)._release = CORBA_TRUE;
++ for (_ORBIT_tmpvar_5 = 0; _ORBIT_tmpvar_5 < (*_ORBIT_retval)._length;
++ _ORBIT_tmpvar_5++) {
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++
++ (*
++ ((guint32 *) &
++ ((*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5].inode))) =
++GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));
++ _ORBIT_curptr += 4;
++
++ (*((guint32 *) & (_ORBIT_tmpvar_7))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));
++ _ORBIT_curptr += 4;
++
++ (*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5].name =
++ CORBA_string_alloc(_ORBIT_tmpvar_7);
++ memcpy((*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5].name,
++ _ORBIT_curptr,
++ sizeof((*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5].
++ name[_ORBIT_tmpvar_6]) * _ORBIT_tmpvar_7);
++ _ORBIT_curptr +=
++ sizeof((*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5].
++ name[_ORBIT_tmpvar_6]) * _ORBIT_tmpvar_7;
++ }
++
++ } else {
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++ (*_ORBIT_retval)._length = *((CORBA_unsigned_long *) _ORBIT_curptr);
++ _ORBIT_curptr += 4;
++
++ (*_ORBIT_retval)._buffer =
++ CORBA_sequence_CorbaFS_dirent_allocbuf((*_ORBIT_retval)._length);
++ (*_ORBIT_retval)._release = CORBA_TRUE;
++ for (_ORBIT_tmpvar_5 = 0; _ORBIT_tmpvar_5 < (*_ORBIT_retval)._length;
++ _ORBIT_tmpvar_5++) {
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++ (*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5].inode = *((CORBA_long *) _ORBIT_curptr);
++ _ORBIT_curptr += 4;
++ _ORBIT_tmpvar_7 = *((CORBA_unsigned_long *) _ORBIT_curptr);
++ _ORBIT_curptr += 4;
++
++ (*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5].name =
++ CORBA_string_alloc(_ORBIT_tmpvar_7);
++ memcpy((*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5].name,
++ _ORBIT_curptr,
++ sizeof((*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5].
++ name[_ORBIT_tmpvar_6]) * _ORBIT_tmpvar_7);
++ _ORBIT_curptr +=
++ sizeof((*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5].
++ name[_ORBIT_tmpvar_6]) * _ORBIT_tmpvar_7;
++ }
++
++ }
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return _ORBIT_retval;
++ _ORBIT_system_exception:
++ CORBA_exception_set_system(ev, _ORBIT_system_exception_minor,
++ _ORBIT_completion_status);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ return _ORBIT_retval;
++ _ORBIT_msg_exception:
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status ==
++ GIOP_LOCATION_FORWARD) {
++ if (_obj->forward_locations != NULL)
++ ORBit_delete_profiles(_obj->forward_locations);
++ _obj->forward_locations = ORBit_demarshal_IOR(_ORBIT_recv_buffer);
++ _cnx = ORBit_object_get_forwarded_connection(_obj);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++
++ goto _ORBIT_retry_request;
++ } else {
++ ORBit_handle_exception(_ORBIT_recv_buffer, ev, NULL, _obj->orb);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return _ORBIT_retval;
++ }
++ }
++}
++CORBA_char *
++CorbaFS_FileSystem_readlink(CorbaFS_FileSystem _obj,
++ const CORBA_char * filename,
++ CORBA_Environment * ev)
++{
++ register GIOP_unsigned_long _ORBIT_request_id,
++ _ORBIT_system_exception_minor;
++ register CORBA_completion_status _ORBIT_completion_status;
++ register GIOPSendBuffer *_ORBIT_send_buffer;
++ register GIOPRecvBuffer *_ORBIT_recv_buffer;
++ register GIOPConnection *_cnx;
++ CORBA_char *_ORBIT_retval;
++ register CORBA_unsigned_long _ORBIT_tmpvar_4;
++ CORBA_unsigned_long _ORBIT_tmpvar_5;
++
++ if (_obj->servant && _obj->vepv && CorbaFS_FileSystem__classid) {
++ _ORBIT_retval =
++ ((POA_CorbaFS_FileSystem__epv *) _obj->
++ vepv[CorbaFS_FileSystem__classid])->readlink(_obj->servant,
++ filename, ev);
++ return _ORBIT_retval;
++ }
++ _cnx = ORBit_object_get_connection(_obj);
++ _ORBIT_retry_request:
++ _ORBIT_send_buffer = NULL;
++ _ORBIT_recv_buffer = NULL;
++ _ORBIT_completion_status = CORBA_COMPLETED_NO;
++ _ORBIT_request_id = GPOINTER_TO_UINT(alloca(0));
++ { /* marshalling */
++ static const struct
++ {
++ CORBA_unsigned_long len;
++ char opname[9];
++ }
++ _ORBIT_operation_name_data =
++ {
++ 9, "readlink"};
++ static const struct iovec _ORBIT_operation_vec =
++ { (gpointer) & _ORBIT_operation_name_data, 13 };
++ register CORBA_unsigned_long _ORBIT_tmpvar_0;
++ CORBA_unsigned_long _ORBIT_tmpvar_1;
++
++ _ORBIT_send_buffer =
++ giop_send_request_buffer_use(_cnx, NULL, _ORBIT_request_id,
++ CORBA_TRUE,
++ &(_obj->active_profile->object_key_vec),
++ &_ORBIT_operation_vec,
++ &ORBit_default_principal_iovec);
++
++ _ORBIT_system_exception_minor = ex_CORBA_COMM_FAILURE;
++ if (!_ORBIT_send_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_tmpvar_1 = strlen(filename) + 1;
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER
++ (_ORBIT_send_buffer), 4);
++ {
++ guchar *_ORBIT_t;
++
++ _ORBIT_t = alloca(sizeof(_ORBIT_tmpvar_1));
++ memcpy(_ORBIT_t, &(_ORBIT_tmpvar_1), sizeof(_ORBIT_tmpvar_1));
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER
++ (_ORBIT_send_buffer), (_ORBIT_t),
++ sizeof(_ORBIT_tmpvar_1));
++ }
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer),
++ (filename),
++ sizeof(filename[_ORBIT_tmpvar_0]) *
++ _ORBIT_tmpvar_1);
++ giop_send_buffer_write(_ORBIT_send_buffer);
++ _ORBIT_completion_status = CORBA_COMPLETED_MAYBE;
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ _ORBIT_send_buffer = NULL;
++ }
++ { /* demarshalling */
++ register guchar *_ORBIT_curptr;
++
++ _ORBIT_recv_buffer =
++ giop_recv_reply_buffer_use_2(_cnx, _ORBIT_request_id, TRUE);
++ if (!_ORBIT_recv_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_completion_status = CORBA_COMPLETED_YES;
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status !=
++ GIOP_NO_EXCEPTION) goto _ORBIT_msg_exception;
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) {
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++
++ (*((guint32 *) & (_ORBIT_tmpvar_5))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));
++ _ORBIT_curptr += 4;
++ _ORBIT_retval = CORBA_string_alloc(_ORBIT_tmpvar_5);
++ memcpy(_ORBIT_retval, _ORBIT_curptr,
++ sizeof(_ORBIT_retval[_ORBIT_tmpvar_4]) * _ORBIT_tmpvar_5);
++ _ORBIT_curptr +=
++ sizeof(_ORBIT_retval[_ORBIT_tmpvar_4]) * _ORBIT_tmpvar_5;
++ } else {
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++ _ORBIT_tmpvar_5 = *((CORBA_unsigned_long *) _ORBIT_curptr);
++ _ORBIT_curptr += 4;
++ _ORBIT_retval = CORBA_string_alloc(_ORBIT_tmpvar_5);
++ memcpy(_ORBIT_retval, _ORBIT_curptr,
++ sizeof(_ORBIT_retval[_ORBIT_tmpvar_4]) * _ORBIT_tmpvar_5);
++ _ORBIT_curptr +=
++ sizeof(_ORBIT_retval[_ORBIT_tmpvar_4]) * _ORBIT_tmpvar_5;
++ }
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return _ORBIT_retval;
++ _ORBIT_system_exception:
++ CORBA_exception_set_system(ev, _ORBIT_system_exception_minor,
++ _ORBIT_completion_status);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ return _ORBIT_retval;
++ _ORBIT_msg_exception:
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status ==
++ GIOP_LOCATION_FORWARD) {
++ if (_obj->forward_locations != NULL)
++ ORBit_delete_profiles(_obj->forward_locations);
++ _obj->forward_locations = ORBit_demarshal_IOR(_ORBIT_recv_buffer);
++ _cnx = ORBit_object_get_forwarded_connection(_obj);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++
++ goto _ORBIT_retry_request;
++ } else {
++ ORBit_handle_exception(_ORBIT_recv_buffer, ev, NULL, _obj->orb);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return _ORBIT_retval;
++ }
++ }
++}
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS-user-client.c linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS-user-client.c
+--- linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS-user-client.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS-user-client.c Thu Feb 1 11:47:03 2001
+@@ -0,0 +1,92 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <orb/orbit.h>
++
++#include "CorbaFS.h"
++
++CorbaFS_FileSystem fs;
++
++int
++main (int argc, char *argv[])
++{
++ CORBA_Environment ev;
++ CORBA_ORB orb;
++ CorbaFS_Inode inode;
++ CorbaFS_Buffer *buffer;
++ CorbaFS_DirEntSeq *dirents;
++ CorbaFS_dirent *dirent;
++
++ CORBA_unsigned_short mode;
++ CORBA_unsigned_long uid;
++ CORBA_unsigned_long gid;
++ CORBA_unsigned_long size;
++ CORBA_unsigned_long inodeNum;
++ CORBA_unsigned_short numLinks;
++ CORBA_long atime;
++ CORBA_long mtime;
++ CORBA_long ctime;
++
++ int i;
++
++ int niters = 10;
++
++ CORBA_exception_init(&ev);
++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", &ev);
++
++ if(argc < 2)
++ {
++ printf("Need a binding ID thing as argv[1]\n");
++ return 1;
++ }
++
++
++ fs = CORBA_ORB_string_to_object(orb, argv[1], &ev);
++ if (!fs) {
++ printf("Cannot bind to %s\n", argv[1]);
++ return 1;
++ }
++
++ if (argc >= 3)
++ inode = CorbaFS_FileSystem_getInode(fs, argv[2], &ev);
++ else
++ inode = CorbaFS_FileSystem_getInode(fs, "/proc/cpuinfo", &ev);
++
++ if (!inode)
++ {
++ printf("Cannot get inode\n");
++ }
++
++ CorbaFS_Inode_getStatus(inode,
++ &mode,
++ &uid,
++ &gid,
++ &size,
++ &inodeNum,
++ &numLinks,
++ &atime,
++ &mtime,
++ &ctime,
++ &ev);
++
++ printf("inode = %x\n", inode);
++ CorbaFS_Inode_readpage(inode, &buffer, 1000, 100, &ev);
++ printf("readpage got %d bytes\n", buffer->_length);
++ printf("readpage returned : %s\n", buffer->_buffer);
++
++ if (argc >= 3)
++ dirents = CorbaFS_FileSystem_readdir(fs, argv[2], &ev);
++ else
++ dirents = CorbaFS_FileSystem_readdir(fs, "/", &ev);
++
++ dirent = dirents->_buffer;
++ for (i = 0; i < dirents->_length; i++)
++ {
++ printf("%d = %s\n", dirent->inode, dirent->name);
++ dirent++;
++ }
++
++ CORBA_Object_release(fs, &ev);
++ CORBA_Object_release((CORBA_Object)orb, &ev);
++
++ return 0;
++}
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS.h linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS.h
+--- linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS.h Thu Feb 1 16:36:08 2001
+@@ -0,0 +1,349 @@
++/*
++ * This file was generated by orbit-idl - DO NOT EDIT!
++ */
++
++#include <glib.h>
++#define ORBIT_IDL_SERIAL 9
++#include <orb/orbit.h>
++
++#ifndef CorbaFS_H
++#define CorbaFS_H 1
++#ifdef __cplusplus
++extern "C"
++{
++#endif /* __cplusplus */
++
++/** typedefs **/
++#if !defined(_CorbaFS_dirent_defined)
++#define _CorbaFS_dirent_defined 1
++ typedef struct
++ {
++ CORBA_long inode;
++ CORBA_char *name;
++ }
++ CorbaFS_dirent;
++
++#if !defined(TC_IMPL_TC_CorbaFS_dirent_0)
++#define TC_IMPL_TC_CorbaFS_dirent_0 'C'
++#define TC_IMPL_TC_CorbaFS_dirent_1 'o'
++#define TC_IMPL_TC_CorbaFS_dirent_2 'r'
++#define TC_IMPL_TC_CorbaFS_dirent_3 'b'
++#define TC_IMPL_TC_CorbaFS_dirent_4 'a'
++#define TC_IMPL_TC_CorbaFS_dirent_5 'F'
++#define TC_IMPL_TC_CorbaFS_dirent_6 'S'
++ extern const struct CORBA_TypeCode_struct TC_CorbaFS_dirent_struct;
++#define TC_CorbaFS_dirent ((CORBA_TypeCode)&TC_CorbaFS_dirent_struct)
++#endif
++ extern CorbaFS_dirent *CorbaFS_dirent__alloc(void);
++ extern gpointer CorbaFS_dirent__free(gpointer mem, gpointer dat,
++ CORBA_boolean free_strings); /* ORBit internal use */
++#endif
++#if !defined(ORBIT_DECL_CORBA_sequence_CorbaFS_dirent) && !defined(_CORBA_sequence_CorbaFS_dirent_defined)
++#define ORBIT_DECL_CORBA_sequence_CorbaFS_dirent 1
++#define _CORBA_sequence_CorbaFS_dirent_defined 1
++#define ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_0 'C'
++#define ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_1 'o'
++#define ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_2 'r'
++#define ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_3 'b'
++#define ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_4 'a'
++#define ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_5 'F'
++#define ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_6 'S'
++ typedef struct
++ {
++ CORBA_unsigned_long _maximum,
++ _length;
++ CorbaFS_dirent *_buffer;
++ CORBA_boolean _release;
++ }
++ CORBA_sequence_CorbaFS_dirent;
++#if !defined(TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_0)
++#define TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_0 'C'
++#define TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_1 'o'
++#define TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_2 'r'
++#define TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_3 'b'
++#define TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_4 'a'
++#define TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_5 'F'
++#define TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_6 'S'
++ extern const struct CORBA_TypeCode_struct
++ TC_CORBA_sequence_CorbaFS_dirent_struct;
++#define TC_CORBA_sequence_CorbaFS_dirent ((CORBA_TypeCode)&TC_CORBA_sequence_CorbaFS_dirent_struct)
++#endif
++ extern CORBA_sequence_CorbaFS_dirent
++ *CORBA_sequence_CorbaFS_dirent__alloc(void);
++ extern gpointer CORBA_sequence_CorbaFS_dirent__free(gpointer mem,
++ gpointer dat,
++ CORBA_boolean free_strings); /* ORBit internal use */
++ CorbaFS_dirent *CORBA_sequence_CorbaFS_dirent_allocbuf(CORBA_unsigned_long
++ len);
++#endif
++#if !defined(_CorbaFS_DirEntSeq_defined)
++#define _CorbaFS_DirEntSeq_defined 1
++ typedef CORBA_sequence_CorbaFS_dirent CorbaFS_DirEntSeq;
++#if !defined(TC_IMPL_TC_CorbaFS_DirEntSeq_0)
++#define TC_IMPL_TC_CorbaFS_DirEntSeq_0 'C'
++#define TC_IMPL_TC_CorbaFS_DirEntSeq_1 'o'
++#define TC_IMPL_TC_CorbaFS_DirEntSeq_2 'r'
++#define TC_IMPL_TC_CorbaFS_DirEntSeq_3 'b'
++#define TC_IMPL_TC_CorbaFS_DirEntSeq_4 'a'
++#define TC_IMPL_TC_CorbaFS_DirEntSeq_5 'F'
++#define TC_IMPL_TC_CorbaFS_DirEntSeq_6 'S'
++ extern const struct CORBA_TypeCode_struct TC_CorbaFS_DirEntSeq_struct;
++#define TC_CorbaFS_DirEntSeq ((CORBA_TypeCode)&TC_CorbaFS_DirEntSeq_struct)
++#endif
++ extern CorbaFS_DirEntSeq *CorbaFS_DirEntSeq__alloc(void);
++ extern gpointer CorbaFS_DirEntSeq__free(gpointer mem, gpointer dat,
++ CORBA_boolean free_strings); /* ORBit internal use */
++#endif
++#if !defined(ORBIT_DECL_CORBA_sequence_CORBA_octet) && !defined(_CORBA_sequence_CORBA_octet_defined)
++#define ORBIT_DECL_CORBA_sequence_CORBA_octet 1
++#define _CORBA_sequence_CORBA_octet_defined 1
++#define ORBIT_IMPL_CORBA_sequence_CORBA_octet_0 'C'
++#define ORBIT_IMPL_CORBA_sequence_CORBA_octet_1 'o'
++#define ORBIT_IMPL_CORBA_sequence_CORBA_octet_2 'r'
++#define ORBIT_IMPL_CORBA_sequence_CORBA_octet_3 'b'
++#define ORBIT_IMPL_CORBA_sequence_CORBA_octet_4 'a'
++#define ORBIT_IMPL_CORBA_sequence_CORBA_octet_5 'F'
++#define ORBIT_IMPL_CORBA_sequence_CORBA_octet_6 'S'
++ typedef struct
++ {
++ CORBA_unsigned_long _maximum,
++ _length;
++ CORBA_octet *_buffer;
++ CORBA_boolean _release;
++ }
++ CORBA_sequence_CORBA_octet;
++#if !defined(TC_IMPL_TC_CORBA_sequence_CORBA_octet_0)
++#define TC_IMPL_TC_CORBA_sequence_CORBA_octet_0 'C'
++#define TC_IMPL_TC_CORBA_sequence_CORBA_octet_1 'o'
++#define TC_IMPL_TC_CORBA_sequence_CORBA_octet_2 'r'
++#define TC_IMPL_TC_CORBA_sequence_CORBA_octet_3 'b'
++#define TC_IMPL_TC_CORBA_sequence_CORBA_octet_4 'a'
++#define TC_IMPL_TC_CORBA_sequence_CORBA_octet_5 'F'
++#define TC_IMPL_TC_CORBA_sequence_CORBA_octet_6 'S'
++ extern const struct CORBA_TypeCode_struct
++ TC_CORBA_sequence_CORBA_octet_struct;
++#define TC_CORBA_sequence_CORBA_octet ((CORBA_TypeCode)&TC_CORBA_sequence_CORBA_octet_struct)
++#endif
++ extern CORBA_sequence_CORBA_octet *CORBA_sequence_CORBA_octet__alloc(void);
++ extern gpointer CORBA_sequence_CORBA_octet__free(gpointer mem,
++ gpointer dat,
++ CORBA_boolean free_strings); /* ORBit internal use */
++ CORBA_octet *CORBA_sequence_CORBA_octet_allocbuf(CORBA_unsigned_long len);
++#endif
++#if !defined(_CorbaFS_Buffer_defined)
++#define _CorbaFS_Buffer_defined 1
++ typedef CORBA_sequence_CORBA_octet CorbaFS_Buffer;
++#if !defined(TC_IMPL_TC_CorbaFS_Buffer_0)
++#define TC_IMPL_TC_CorbaFS_Buffer_0 'C'
++#define TC_IMPL_TC_CorbaFS_Buffer_1 'o'
++#define TC_IMPL_TC_CorbaFS_Buffer_2 'r'
++#define TC_IMPL_TC_CorbaFS_Buffer_3 'b'
++#define TC_IMPL_TC_CorbaFS_Buffer_4 'a'
++#define TC_IMPL_TC_CorbaFS_Buffer_5 'F'
++#define TC_IMPL_TC_CorbaFS_Buffer_6 'S'
++ extern const struct CORBA_TypeCode_struct TC_CorbaFS_Buffer_struct;
++#define TC_CorbaFS_Buffer ((CORBA_TypeCode)&TC_CorbaFS_Buffer_struct)
++#endif
++ extern CorbaFS_Buffer *CorbaFS_Buffer__alloc(void);
++ extern gpointer CorbaFS_Buffer__free(gpointer mem, gpointer dat,
++ CORBA_boolean free_strings); /* ORBit internal use */
++#endif
++#if !defined(ORBIT_DECL_CorbaFS_Inode) && !defined(_CorbaFS_Inode_defined)
++#define ORBIT_DECL_CorbaFS_Inode 1
++#define _CorbaFS_Inode_defined 1
++#define CorbaFS_Inode__free CORBA_Object__free
++ typedef CORBA_Object CorbaFS_Inode;
++ extern CORBA_unsigned_long CorbaFS_Inode__classid;
++#if !defined(TC_IMPL_TC_CorbaFS_Inode_0)
++#define TC_IMPL_TC_CorbaFS_Inode_0 'C'
++#define TC_IMPL_TC_CorbaFS_Inode_1 'o'
++#define TC_IMPL_TC_CorbaFS_Inode_2 'r'
++#define TC_IMPL_TC_CorbaFS_Inode_3 'b'
++#define TC_IMPL_TC_CorbaFS_Inode_4 'a'
++#define TC_IMPL_TC_CorbaFS_Inode_5 'F'
++#define TC_IMPL_TC_CorbaFS_Inode_6 'S'
++ extern const struct CORBA_TypeCode_struct TC_CorbaFS_Inode_struct;
++#define TC_CorbaFS_Inode ((CORBA_TypeCode)&TC_CorbaFS_Inode_struct)
++#endif
++#endif
++#if !defined(ORBIT_DECL_CorbaFS_FileSystem) && !defined(_CorbaFS_FileSystem_defined)
++#define ORBIT_DECL_CorbaFS_FileSystem 1
++#define _CorbaFS_FileSystem_defined 1
++#define CorbaFS_FileSystem__free CORBA_Object__free
++ typedef CORBA_Object CorbaFS_FileSystem;
++ extern CORBA_unsigned_long CorbaFS_FileSystem__classid;
++#if !defined(TC_IMPL_TC_CorbaFS_FileSystem_0)
++#define TC_IMPL_TC_CorbaFS_FileSystem_0 'C'
++#define TC_IMPL_TC_CorbaFS_FileSystem_1 'o'
++#define TC_IMPL_TC_CorbaFS_FileSystem_2 'r'
++#define TC_IMPL_TC_CorbaFS_FileSystem_3 'b'
++#define TC_IMPL_TC_CorbaFS_FileSystem_4 'a'
++#define TC_IMPL_TC_CorbaFS_FileSystem_5 'F'
++#define TC_IMPL_TC_CorbaFS_FileSystem_6 'S'
++ extern const struct CORBA_TypeCode_struct TC_CorbaFS_FileSystem_struct;
++#define TC_CorbaFS_FileSystem ((CORBA_TypeCode)&TC_CorbaFS_FileSystem_struct)
++#endif
++#endif
++
++/** POA structures **/
++ typedef struct
++ {
++ void *_private;
++ void (*getStatus) (PortableServer_Servant _servant,
++ CORBA_unsigned_short * mode,
++ CORBA_unsigned_long * uid, CORBA_unsigned_long * gid,
++ CORBA_unsigned_long * size,
++ CORBA_unsigned_long * inodeNum,
++ CORBA_unsigned_short * numLinks, CORBA_long * atime,
++ CORBA_long * mtime, CORBA_long * ctime,
++ CORBA_Environment * ev);
++ void (*readpage) (PortableServer_Servant _servant,
++ CorbaFS_Buffer ** buffer, const CORBA_long size,
++ const CORBA_long offset, CORBA_Environment * ev);
++ void (*release) (PortableServer_Servant _servant,
++ CORBA_Environment * ev);
++ }
++ POA_CorbaFS_Inode__epv;
++ typedef struct
++ {
++ PortableServer_ServantBase__epv *_base_epv;
++ POA_CorbaFS_Inode__epv *CorbaFS_Inode_epv;
++ }
++ POA_CorbaFS_Inode__vepv;
++ typedef struct
++ {
++ void *_private;
++ POA_CorbaFS_Inode__vepv *vepv;
++ }
++ POA_CorbaFS_Inode;
++ extern void POA_CorbaFS_Inode__init(PortableServer_Servant servant,
++ CORBA_Environment * ev);
++ extern void POA_CorbaFS_Inode__fini(PortableServer_Servant servant,
++ CORBA_Environment * ev);
++ typedef struct
++ {
++ void *_private;
++
++ CorbaFS_Inode(*getInode) (PortableServer_Servant _servant,
++ const CORBA_char * path,
++ CORBA_Environment * ev);
++ CorbaFS_DirEntSeq *(*readdir) (PortableServer_Servant _servant,
++ const CORBA_char * path,
++ CORBA_Environment * ev);
++ CORBA_char *(*readlink) (PortableServer_Servant _servant,
++ const CORBA_char * filename,
++ CORBA_Environment * ev);
++ }
++ POA_CorbaFS_FileSystem__epv;
++ typedef struct
++ {
++ PortableServer_ServantBase__epv *_base_epv;
++ POA_CorbaFS_FileSystem__epv *CorbaFS_FileSystem_epv;
++ }
++ POA_CorbaFS_FileSystem__vepv;
++ typedef struct
++ {
++ void *_private;
++ POA_CorbaFS_FileSystem__vepv *vepv;
++ }
++ POA_CorbaFS_FileSystem;
++ extern void POA_CorbaFS_FileSystem__init(PortableServer_Servant servant,
++ CORBA_Environment * ev);
++ extern void POA_CorbaFS_FileSystem__fini(PortableServer_Servant servant,
++ CORBA_Environment * ev);
++
++/** prototypes **/
++ void CorbaFS_Inode_getStatus(CorbaFS_Inode _obj,
++ CORBA_unsigned_short * mode,
++ CORBA_unsigned_long * uid,
++ CORBA_unsigned_long * gid,
++ CORBA_unsigned_long * size,
++ CORBA_unsigned_long * inodeNum,
++ CORBA_unsigned_short * numLinks,
++ CORBA_long * atime, CORBA_long * mtime,
++ CORBA_long * ctime, CORBA_Environment * ev);
++ void CorbaFS_Inode_readpage(CorbaFS_Inode _obj, CorbaFS_Buffer ** buffer,
++ const CORBA_long size, const CORBA_long offset,
++ CORBA_Environment * ev);
++ void CorbaFS_Inode_release(CorbaFS_Inode _obj, CORBA_Environment * ev);
++ CorbaFS_Inode CorbaFS_FileSystem_getInode(CorbaFS_FileSystem _obj,
++ const CORBA_char * path,
++ CORBA_Environment * ev);
++ CorbaFS_DirEntSeq *CorbaFS_FileSystem_readdir(CorbaFS_FileSystem _obj,
++ const CORBA_char * path,
++ CORBA_Environment * ev);
++ CORBA_char *CorbaFS_FileSystem_readlink(CorbaFS_FileSystem _obj,
++ const CORBA_char * filename,
++ CORBA_Environment * ev);
++
++ void _ORBIT_skel_CorbaFS_Inode_getStatus(POA_CorbaFS_Inode *
++ _ORBIT_servant,
++ GIOPRecvBuffer *
++ _ORBIT_recv_buffer,
++ CORBA_Environment * ev,
++ void (*_impl_getStatus)
++ (PortableServer_Servant _servant,
++ CORBA_unsigned_short * mode,
++ CORBA_unsigned_long * uid,
++ CORBA_unsigned_long * gid,
++ CORBA_unsigned_long * size,
++ CORBA_unsigned_long * inodeNum,
++ CORBA_unsigned_short * numLinks,
++ CORBA_long * atime,
++ CORBA_long * mtime,
++ CORBA_long * ctime,
++ CORBA_Environment * ev));
++ void _ORBIT_skel_CorbaFS_Inode_readpage(POA_CorbaFS_Inode * _ORBIT_servant,
++ GIOPRecvBuffer *
++ _ORBIT_recv_buffer,
++ CORBA_Environment * ev,
++ void (*_impl_readpage)
++ (PortableServer_Servant _servant,
++ CorbaFS_Buffer ** buffer,
++ const CORBA_long size,
++ const CORBA_long offset,
++ CORBA_Environment * ev));
++ void _ORBIT_skel_CorbaFS_Inode_release(POA_CorbaFS_Inode * _ORBIT_servant,
++ GIOPRecvBuffer * _ORBIT_recv_buffer,
++ CORBA_Environment * ev,
++ void (*_impl_release)
++ (PortableServer_Servant _servant,
++ CORBA_Environment * ev));
++ void _ORBIT_skel_CorbaFS_FileSystem_getInode(POA_CorbaFS_FileSystem *
++ _ORBIT_servant,
++ GIOPRecvBuffer *
++ _ORBIT_recv_buffer,
++ CORBA_Environment * ev,
++ CorbaFS_Inode(*_impl_getInode)
++ (PortableServer_Servant
++ _servant,
++ const CORBA_char * path,
++ CORBA_Environment * ev));
++ void _ORBIT_skel_CorbaFS_FileSystem_readdir(POA_CorbaFS_FileSystem *
++ _ORBIT_servant,
++ GIOPRecvBuffer *
++ _ORBIT_recv_buffer,
++ CORBA_Environment * ev,
++ CorbaFS_DirEntSeq *
++ (*_impl_readdir)
++ (PortableServer_Servant
++ _servant,
++ const CORBA_char * path,
++ CORBA_Environment * ev));
++ void _ORBIT_skel_CorbaFS_FileSystem_readlink(POA_CorbaFS_FileSystem *
++ _ORBIT_servant,
++ GIOPRecvBuffer *
++ _ORBIT_recv_buffer,
++ CORBA_Environment * ev,
++ CORBA_char *
++ (*_impl_readlink)
++ (PortableServer_Servant
++ _servant,
++ const CORBA_char * filename,
++ CORBA_Environment * ev));
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif
++#undef ORBIT_IDL_SERIAL
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/Makefile linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/Makefile
+--- linux-2.4.1/net/korbit/modules/CorbaFS/client/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/Makefile Thu Feb 1 11:47:03 2001
+@@ -0,0 +1,20 @@
++#
++# Makefile for KORBit CorbaFS client
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++O_TARGET := corba-corbafs-client.o
++
++obj-y := CorbaFS-common.o CorbaFS-stubs.o CorbaFS-client.o
++obj-m := $(O_TARGET)
++
++include ../../Makefile.module
++
++CorbaFS-client.c: CorbaFS.h
++
++CorbaFS.h CorbaFS-common.c CorbaFS-stubs.c: ../CorbaFS.idl
++ $(ORBIT_IDL) --noskels ../CorbaFS.idl
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/Makefile.user linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/Makefile.user
+--- linux-2.4.1/net/korbit/modules/CorbaFS/client/Makefile.user Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/Makefile.user Thu Feb 1 11:47:03 2001
+@@ -0,0 +1,32 @@
++#
++# Makefile for KORBit
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++PROJECT = CorbaFS
++
++CFLAGS = -Wall `orbit-config --cflags client` -I../../..
++LDFLAGS = `orbit-config --libs client`
++OBJS = $(PROJECT)-common.o $(PROJECT)-stubs.o $(PROJECT)-user-client.o
++ORBIT-IDL = orbit-idl
++
++$(PROJECT)-user-client: $(OBJS)
++ gcc -o $(PROJECT)-user-client $(OBJS) $(LDFLAGS)
++
++$(PROJECT)-user-client.o: $(PROJECT).h
++
++$(PROJECT).h $(PROJECT)-common.c $(PROJECT)-stubs.c: ../$(PROJECT).idl
++ $(ORBIT-IDL) --noskels ../$(PROJECT).idl
++
++clean:
++ rm -f $(OBJS) $(PROJECT)-user-client
++
++realclean: clean
++ rm -f $(PROJECT).h
++ rm -f $(PROJECT)-common.c
++ rm -f $(PROJECT)-skels.c
++ rm -f *~
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/README linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/README
+--- linux-2.4.1/net/korbit/modules/CorbaFS/client/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/README Thu Feb 1 11:47:03 2001
+@@ -0,0 +1,4 @@
++This module implements the kernel VFS->kORBit interface. This is called a 'client'
++because it actually USES a CORBA object that is exported from someplace else.
++
++ORB: kORBit
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/CorbaFS/server/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CVS/Entries Thu Feb 1 11:47:04 2001
+@@ -0,0 +1,6 @@
++/CorbaFS-server.c/1.8/Thu Feb 1 09:47:03 2001//
++/CorbaFS-skelimpl.c/1.10/Thu Feb 1 09:47:04 2001//
++/Makefile/1.5/Thu Feb 1 09:47:04 2001//
++/README/1.2/Thu Feb 1 09:47:04 2001//
++/RunServer.sh/1.1/Thu Feb 1 09:47:04 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/CorbaFS/server/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CVS/Repository Thu Feb 1 11:47:03 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/CorbaFS/server
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server/CVS/Root linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CVS/Root
+--- linux-2.4.1/net/korbit/modules/CorbaFS/server/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CVS/Root Thu Feb 1 11:47:03 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server/CorbaFS-server.c linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CorbaFS-server.c
+--- linux-2.4.1/net/korbit/modules/CorbaFS/server/CorbaFS-server.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CorbaFS-server.c Thu Feb 1 11:47:03 2001
+@@ -0,0 +1,37 @@
++#include <stdio.h>
++#include "CorbaFS-skelimpl.c"
++
++CORBA_ORB orb;
++PortableServer_POA poa;
++CORBA_Environment *ev;
++PortableServer_ObjectId *objid;
++
++int main(int argc, char *argv[]) {
++ CorbaFS_FileSystem fs;
++ impl_POA_CorbaFS_FileSystem *fs_impl;
++
++ PortableServer_POAManager pm;
++ ev = g_new0(CORBA_Environment,1);
++
++ CORBA_exception_init(ev);
++ printf("Make sure you use TCP/IP and not Unix sockets!\n");
++
++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", ev);
++ poa = (PortableServer_POA)
++ CORBA_ORB_resolve_initial_references(orb,
++ "RootPOA",
++ ev);
++ fs = impl_CorbaFS_FileSystem__create(poa, ev);
++
++ pm = PortableServer_POA__get_the_POAManager(poa, ev);
++ PortableServer_POAManager_activate(pm, ev);
++
++ fs_impl = PortableServer_POA_reference_to_servant( poa, fs, ev );
++ objid = PortableServer_POA_servant_to_id( poa, fs_impl, ev );
++
++ printf("CorbaFS-server:\n%s\n", CORBA_ORB_object_to_string(orb, fs, ev));
++
++ CORBA_ORB_run(orb, ev);
++
++ return 0;
++}
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server/CorbaFS-skelimpl.c linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CorbaFS-skelimpl.c
+--- linux-2.4.1/net/korbit/modules/CorbaFS/server/CorbaFS-skelimpl.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CorbaFS-skelimpl.c Thu Feb 1 11:47:04 2001
+@@ -0,0 +1,353 @@
++#include <sys/param.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <unistd.h>
++#include <fcntl.h>
++#include <dirent.h>
++
++#include "CorbaFS.h"
++
++/*** App-specific servant structures ***/
++
++#define printf(fmt, args...) fprintf(stderr, fmt, ##args);
++
++typedef struct
++{
++ POA_CorbaFS_Inode servant;
++ PortableServer_POA poa;
++
++ CORBA_char *path;
++#if 0
++ CORBA_unsigned_short mode;
++ CORBA_unsigned_long uid;
++ CORBA_unsigned_long gid;
++ CORBA_unsigned_long size;
++ CORBA_unsigned_long inodeNum;
++ CORBA_unsigned_short numLinks;
++ CORBA_long atime;
++ CORBA_long mtime;
++ CORBA_long ctime;
++#endif
++}
++impl_POA_CorbaFS_Inode;
++
++typedef struct
++{
++ POA_CorbaFS_FileSystem servant;
++ PortableServer_POA poa;
++
++}
++impl_POA_CorbaFS_FileSystem;
++
++/*** Implementation stub prototypes ***/
++
++static void impl_CorbaFS_Inode__destroy(impl_POA_CorbaFS_Inode * servant,
++ CORBA_Environment * ev);
++static void
++impl_CorbaFS_Inode_getStatus(impl_POA_CorbaFS_Inode * servant,
++ CORBA_unsigned_short * mode,
++ CORBA_unsigned_long * uid,
++ CORBA_unsigned_long * gid,
++ CORBA_unsigned_long * size,
++ CORBA_unsigned_long * inodeNum,
++ CORBA_unsigned_short * numLinks,
++ CORBA_long * atime,
++ CORBA_long * mtime,
++ CORBA_long * ctime, CORBA_Environment * ev);
++
++static void
++impl_CorbaFS_Inode_readpage(impl_POA_CorbaFS_Inode * servant,
++ CorbaFS_Buffer ** buffer,
++ CORBA_long size,
++ CORBA_long offset, CORBA_Environment * ev);
++
++static void
++impl_CorbaFS_Inode_release(impl_POA_CorbaFS_Inode * servant,
++ CORBA_Environment * ev);
++
++static void impl_CorbaFS_FileSystem__destroy(impl_POA_CorbaFS_FileSystem *
++ servant, CORBA_Environment * ev);
++static CorbaFS_Inode
++impl_CorbaFS_FileSystem_getInode(impl_POA_CorbaFS_FileSystem * servant,
++ CORBA_char * path, CORBA_Environment * ev);
++
++static CorbaFS_DirEntSeq
++ *impl_CorbaFS_FileSystem_readdir(impl_POA_CorbaFS_FileSystem * servant,
++ CORBA_char * path,
++
++ CORBA_Environment * ev);
++
++static CORBA_char
++ *impl_CorbaFS_FileSystem_readlink(impl_POA_CorbaFS_FileSystem * servant,
++ CORBA_char * filename,
++ CORBA_Environment * ev);
++
++/*** epv structures ***/
++
++static PortableServer_ServantBase__epv impl_CorbaFS_Inode_base_epv = {
++ NULL, /* _private data */
++ NULL, /* finalize routine */
++ NULL, /* default_POA routine */
++};
++static POA_CorbaFS_Inode__epv impl_CorbaFS_Inode_epv = {
++ NULL, /* _private */
++ (gpointer) & impl_CorbaFS_Inode_getStatus,
++
++ (gpointer) & impl_CorbaFS_Inode_readpage,
++
++ (gpointer) & impl_CorbaFS_Inode_release,
++
++};
++static PortableServer_ServantBase__epv impl_CorbaFS_FileSystem_base_epv = {
++ NULL, /* _private data */
++ NULL, /* finalize routine */
++ NULL, /* default_POA routine */
++};
++static POA_CorbaFS_FileSystem__epv impl_CorbaFS_FileSystem_epv = {
++ NULL, /* _private */
++ (gpointer) & impl_CorbaFS_FileSystem_getInode,
++
++ (gpointer) & impl_CorbaFS_FileSystem_readdir,
++
++ (gpointer) & impl_CorbaFS_FileSystem_readlink,
++
++};
++
++/*** vepv structures ***/
++
++static POA_CorbaFS_Inode__vepv impl_CorbaFS_Inode_vepv = {
++ &impl_CorbaFS_Inode_base_epv,
++ &impl_CorbaFS_Inode_epv,
++};
++static POA_CorbaFS_FileSystem__vepv impl_CorbaFS_FileSystem_vepv = {
++ &impl_CorbaFS_FileSystem_base_epv,
++ &impl_CorbaFS_FileSystem_epv,
++};
++
++/*** Stub implementations ***/
++
++static CorbaFS_Inode
++impl_CorbaFS_Inode__create(PortableServer_POA poa, CORBA_Environment * ev)
++{
++ CorbaFS_Inode retval;
++ impl_POA_CorbaFS_Inode *newservant;
++ PortableServer_ObjectId *objid;
++
++ newservant = g_new0(impl_POA_CorbaFS_Inode, 1);
++ newservant->servant.vepv = &impl_CorbaFS_Inode_vepv;
++ newservant->poa = poa;
++ POA_CorbaFS_Inode__init((PortableServer_Servant) newservant, ev);
++ objid = PortableServer_POA_activate_object(poa, newservant, ev);
++ CORBA_free(objid);
++ retval = PortableServer_POA_servant_to_reference(poa, newservant, ev);
++
++ return retval;
++}
++
++static void
++impl_CorbaFS_Inode__destroy(impl_POA_CorbaFS_Inode * servant,
++ CORBA_Environment * ev)
++{
++ PortableServer_ObjectId *objid;
++
++ objid = PortableServer_POA_servant_to_id(servant->poa, servant, ev);
++ PortableServer_POA_deactivate_object(servant->poa, objid, ev);
++ CORBA_free(objid);
++
++ POA_CorbaFS_Inode__fini((PortableServer_Servant) servant, ev);
++ g_free(servant);
++}
++
++static void
++impl_CorbaFS_Inode_getStatus(impl_POA_CorbaFS_Inode * servant,
++ CORBA_unsigned_short * mode,
++ CORBA_unsigned_long * uid,
++ CORBA_unsigned_long * gid,
++ CORBA_unsigned_long * size,
++ CORBA_unsigned_long * inodeNum,
++ CORBA_unsigned_short * numLinks,
++ CORBA_long * atime,
++ CORBA_long * mtime,
++ CORBA_long * ctime, CORBA_Environment * ev)
++{
++ struct stat buf;
++
++ printf("Inode_getStatus()\n");
++ printf("Inode path = %s\n", servant->path);
++ lstat(servant->path, &buf);
++
++ *mode = buf.st_mode;
++ *uid = buf.st_uid;
++ *gid = buf.st_gid;
++ *size = buf.st_size;
++ *inodeNum = buf.st_ino;
++ *numLinks = buf.st_nlink;
++ *atime = buf.st_atime;
++ *mtime = buf.st_mtime;
++ *ctime = buf.st_ctime;
++}
++
++static void
++impl_CorbaFS_Inode_readpage(impl_POA_CorbaFS_Inode * servant,
++ CorbaFS_Buffer ** buffer,
++ CORBA_long size,
++ CORBA_long offset, CORBA_Environment * ev)
++{
++ int fd = -1, c = 0;
++
++ printf("Inode_readpage(buffer, %d, %d)\n", size, offset);
++ printf("Inode_readpage : path = %s\n", servant->path);
++
++ *buffer = CorbaFS_Buffer__alloc();
++ (*buffer)->_maximum = size;
++ (*buffer)->_buffer = CORBA_octet_allocbuf(size);
++
++ memset((*buffer)->_buffer, size, 0);
++
++ fd = open(servant->path, O_RDONLY);
++ printf("Inode_readpage : fd = %d\n", fd);
++ lseek(fd, offset, SEEK_SET);
++ c = read(fd, (*buffer)->_buffer, size);
++ printf("Inode_readpage : read %d bytes\n", c);
++ (*buffer)->_length = c;
++ close(fd);
++}
++
++static void
++impl_CorbaFS_Inode_release(impl_POA_CorbaFS_Inode * servant,
++ CORBA_Environment * ev)
++{
++ printf("Inode_release()\n");
++}
++
++static CorbaFS_FileSystem
++impl_CorbaFS_FileSystem__create(PortableServer_POA poa,
++ CORBA_Environment * ev)
++{
++ CorbaFS_FileSystem retval;
++ impl_POA_CorbaFS_FileSystem *newservant;
++ PortableServer_ObjectId *objid;
++
++ newservant = g_new0(impl_POA_CorbaFS_FileSystem, 1);
++ newservant->servant.vepv = &impl_CorbaFS_FileSystem_vepv;
++ newservant->poa = poa;
++ POA_CorbaFS_FileSystem__init((PortableServer_Servant) newservant, ev);
++ objid = PortableServer_POA_activate_object(poa, newservant, ev);
++ CORBA_free(objid);
++ retval = PortableServer_POA_servant_to_reference(poa, newservant, ev);
++
++ return retval;
++}
++
++static void
++impl_CorbaFS_FileSystem__destroy(impl_POA_CorbaFS_FileSystem * servant,
++ CORBA_Environment * ev)
++{
++ PortableServer_ObjectId *objid;
++
++ objid = PortableServer_POA_servant_to_id(servant->poa, servant, ev);
++ PortableServer_POA_deactivate_object(servant->poa, objid, ev);
++ CORBA_free(objid);
++
++ POA_CorbaFS_FileSystem__fini((PortableServer_Servant) servant, ev);
++ g_free(servant);
++}
++
++static CorbaFS_Inode
++impl_CorbaFS_FileSystem_getInode(impl_POA_CorbaFS_FileSystem * servant,
++ CORBA_char * path, CORBA_Environment * ev)
++{
++ CorbaFS_Inode retval;
++ impl_POA_CorbaFS_Inode *inode;
++
++ printf("FileSystem_getInode(%s)\n", path);
++
++ retval = impl_CorbaFS_Inode__create(servant->poa, ev);
++
++ inode = PortableServer_POA_reference_to_servant( servant->poa, retval, ev );
++ inode->path = CORBA_string_dup(path);
++#if 0
++ inode->mode = 0040777; /* world-readable directory */
++ inode->uid = 0;
++ inode->gid = 0;
++ inode->size = 4096;
++ inode->inodeNum = inodeNum++;
++ inode->numLinks = 1;
++ inode->atime = 0;
++ inode->mtime = 100;
++ inode->ctime = 10000;
++#endif
++
++ return retval;
++}
++
++static CorbaFS_DirEntSeq *
++impl_CorbaFS_FileSystem_readdir(impl_POA_CorbaFS_FileSystem * servant,
++ CORBA_char * path, CORBA_Environment * ev)
++{
++ CorbaFS_DirEntSeq *retval;
++ CorbaFS_dirent *dirent;
++
++ DIR *dir;
++ struct dirent *dirp;
++ int c;
++
++ printf("FileSystem_readdir(%s)\n", path);
++
++ retval = CorbaFS_DirEntSeq__alloc();
++ retval->_maximum = 0;
++ retval->_length = 0;
++
++ dir = opendir(path);
++ if (dir == NULL)
++ return retval;
++
++ c = 0;
++ while ((dirp = readdir(dir)))
++ c++;
++
++ rewinddir(dir);
++
++ printf("%d directories\n", c);
++
++ retval->_buffer = CORBA_sequence_CorbaFS_dirent_allocbuf(c);
++ retval->_maximum = c;
++ dirent = retval->_buffer;
++
++ c = 0;
++ while ((dirp = readdir(dir)) && (c < retval->_maximum))
++ {
++ printf("Adding directory %d : %s (%d)\n", c, dirp->d_name, dirp->d_ino);
++
++ dirent[c].inode = dirp->d_ino;
++ dirent[c].name = CORBA_string_dup(dirp->d_name);
++ c++;
++ }
++ retval->_length = c;
++
++ closedir(dir);
++
++ return retval;
++}
++
++static CORBA_char *
++impl_CorbaFS_FileSystem_readlink(impl_POA_CorbaFS_FileSystem * servant,
++ CORBA_char * filename,
++ CORBA_Environment * ev)
++{
++ CORBA_char *retval = CORBA_OBJECT_NIL;
++ char tmp[MAXPATHLEN + 1];
++ int len;
++
++ printf("FileSystem_readlink(%s) = ", filename);
++ len = readlink(filename, tmp, MAXPATHLEN);
++ if (len != -1)
++ {
++ tmp[len] = '\0';
++ retval = CORBA_string_dup(tmp);
++ }
++
++ printf("%s\n", retval);
++
++ return retval;
++}
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server/Makefile linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/Makefile
+--- linux-2.4.1/net/korbit/modules/CorbaFS/server/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/Makefile Thu Feb 1 11:47:04 2001
+@@ -0,0 +1,32 @@
++#
++# Makefile for KORBit
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++PROJECT = CorbaFS
++
++CFLAGS = -Wall `orbit-config --cflags server` -I../../..
++LDFLAGS = `orbit-config --libs server`
++OBJS = $(PROJECT)-common.o $(PROJECT)-skels.o $(PROJECT)-server.o
++ORBIT-IDL = orbit-idl
++
++$(PROJECT)-server: $(OBJS)
++ gcc -o $(PROJECT)-server $(OBJS) $(LDFLAGS)
++
++$(PROJECT)-server.o: $(PROJECT).h $(PROJECT)-skelimpl.c
++
++$(PROJECT).h $(PROJECT)-common.c $(PROJECT)-skels.c: ../$(PROJECT).idl
++ $(ORBIT-IDL) --nostubs ../$(PROJECT).idl
++
++clean:
++ rm -f $(OBJS) $(PROJECT)-server
++
++realclean: clean
++ rm -f $(PROJECT).h
++ rm -f $(PROJECT)-common.c
++ rm -f $(PROJECT)-skels.c
++ rm -f *~
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server/README linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/README
+--- linux-2.4.1/net/korbit/modules/CorbaFS/server/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/README Thu Feb 1 11:47:04 2001
+@@ -0,0 +1,8 @@
++This server provides an NFS like capability of exporting an existing filesystem.
++
++ORB: ORBit
++Status: Working! (for readonly fs's)
++
++NOTE!!!!: When starting this server make sure you pass ORBit the options to
++ have it use ipv4 sockets and not unix domain sockets, or else bad
++ things will happen. You can use the included RunServer script.
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server/RunServer.sh linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/RunServer.sh
+--- linux-2.4.1/net/korbit/modules/CorbaFS/server/RunServer.sh Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/RunServer.sh Thu Feb 1 11:47:04 2001
+@@ -0,0 +1 @@
++./CorbaFS-server -ORBIIOPUSock=0 -ORBIIOPIPv4=1
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/CVS/Entries Thu Feb 1 11:47:04 2001
+@@ -0,0 +1,3 @@
++/PerlServer/1.2/Thu Feb 1 09:47:04 2001//
++/README/1.1/Thu Feb 1 09:47:04 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/CVS/Repository Thu Feb 1 11:47:04 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/CorbaFS/server-perl
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/CVS/Root linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/CVS/Root
+--- linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/CVS/Root Thu Feb 1 11:47:04 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/PerlServer linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/PerlServer
+--- linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/PerlServer Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/PerlServer Thu Feb 1 11:47:04 2001
+@@ -0,0 +1,67 @@
++#!/usr/bin/perl -w
++use CORBA::ORBit idl => [ qw(../CorbaFS.idl) ];
++use Error qw(:try);
++use strict;
++
++
++package MyFSInode;
++@MyFSInode::ISA = qw(POA_CorbaFS::Inode);
++
++sub new {
++ my $self = bless { name => shift };
++ print "INODE CREATED: $self->{name}!\n";
++}
++
++sub getStatus {
++ my ($self) = @_;
++ print "$self->getStatus()\n";
++}
++
++sub readpage {
++ return "";
++}
++
++sub release {
++}
++
++
++package MyFileSystem;
++@MyFileSystem::ISA = qw(POA_CorbaFS::FileSystem);
++
++sub new {
++ my $self = bless { root => '/home' };
++}
++
++sub getInode {
++ my $path = shift;
++ print "getInode($path)\n";
++ return new MyFSInode($path);
++}
++
++sub readdir {
++ my $path = shift;
++ print "readdir($path)\n";
++ return [ { inode => 1, name => '...' } ];
++}
++
++sub readlink {
++ my $path = shift;
++ print "readlink($path)\n";
++ return "fredrik";
++}
++
++
++package Main;
++
++my $orb = CORBA::ORB_init("orbit-local-orb");
++my $poa = $orb->resolve_initial_references("RootPOA");
++
++my $Server = new MyFileSystem();
++my $id = $poa->activate_object($Server);
++my $ref = $orb->object_to_string($poa->id_to_reference($id));
++
++print "$ref\n";
++
++print "Running orb:\n";
++$orb->run();
++exit(0);
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/README linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/README
+--- linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/README Thu Feb 1 11:47:04 2001
+@@ -0,0 +1,4 @@
++Test filesystem implementation in Perl.
++
++ORB: ORBit/Perl
++Status: horribly broken
+diff -urN linux-2.4.1/net/korbit/modules/Echo/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/Echo/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/Echo/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/CVS/Entries Thu Feb 1 11:47:05 2001
+@@ -0,0 +1,4 @@
++/Makefile/1.3/Thu Feb 1 09:47:04 2001//
++/README/1.1/Thu Feb 1 09:47:05 2001//
++/echo.idl/1.1/Thu Feb 1 09:47:05 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/Echo/CVS/Entries.Log linux-2.4.1-korbit/net/korbit/modules/Echo/CVS/Entries.Log
+--- linux-2.4.1/net/korbit/modules/Echo/CVS/Entries.Log Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/CVS/Entries.Log Thu Feb 1 11:47:06 2001
+@@ -0,0 +1,3 @@
++A D/client////
++A D/client-perl////
++A D/server////
+diff -urN linux-2.4.1/net/korbit/modules/Echo/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/Echo/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/Echo/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/CVS/Repository Thu Feb 1 11:47:04 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/Echo
+diff -urN linux-2.4.1/net/korbit/modules/Echo/CVS/Root linux-2.4.1-korbit/net/korbit/modules/Echo/CVS/Root
+--- linux-2.4.1/net/korbit/modules/Echo/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/CVS/Root Thu Feb 1 11:47:04 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/Echo/Makefile linux-2.4.1-korbit/net/korbit/modules/Echo/Makefile
+--- linux-2.4.1/net/korbit/modules/Echo/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/Makefile Thu Feb 1 11:47:04 2001
+@@ -0,0 +1,11 @@
++#
++# Makefile for KORBit/modules/Console
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++
++subdir-$(CONFIG_CORBA_ECHO) := client server
++
++include $(TOPDIR)/Rules.make
++
+diff -urN linux-2.4.1/net/korbit/modules/Echo/README linux-2.4.1-korbit/net/korbit/modules/Echo/README
+--- linux-2.4.1/net/korbit/modules/Echo/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/README Thu Feb 1 11:47:05 2001
+@@ -0,0 +1,2 @@
++The Echo test is very similar to the console test, but it also "returns" a
++"random" number. The random number, in our case, is simply a constant.
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/Echo/client/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/Echo/client/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/CVS/Entries Thu Feb 1 11:47:05 2001
+@@ -0,0 +1,6 @@
++/Makefile/1.4/Thu Feb 1 09:47:05 2001//
++/Makefile.user/1.1/Thu Feb 1 09:47:05 2001//
++/README/1.1/Thu Feb 1 09:47:05 2001//
++/RunClient.sh/1.1/Thu Feb 1 09:47:05 2001//
++/echo-client.c/1.6/Thu Feb 1 09:47:05 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/Echo/client/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/Echo/client/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/CVS/Repository Thu Feb 1 11:47:05 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/Echo/client
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client/CVS/Root linux-2.4.1-korbit/net/korbit/modules/Echo/client/CVS/Root
+--- linux-2.4.1/net/korbit/modules/Echo/client/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/CVS/Root Thu Feb 1 11:47:05 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client/Makefile linux-2.4.1-korbit/net/korbit/modules/Echo/client/Makefile
+--- linux-2.4.1/net/korbit/modules/Echo/client/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/Makefile Thu Feb 1 11:47:05 2001
+@@ -0,0 +1,20 @@
++#
++# Makefile for KORBit
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++O_TARGET := corba-echo-client.o
++
++obj-y := echo-common.o echo-stubs.o echo-client.o
++obj-m := $(O_TARGET)
++
++include ../../Makefile.module
++
++echo-client.c: echo.h
++
++echo.h echo-common.c echo-stubs.c: ../echo.idl
++ $(ORBIT_IDL) --noskels ../echo.idl
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client/Makefile.user linux-2.4.1-korbit/net/korbit/modules/Echo/client/Makefile.user
+--- linux-2.4.1/net/korbit/modules/Echo/client/Makefile.user Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/Makefile.user Thu Feb 1 11:47:05 2001
+@@ -0,0 +1,32 @@
++#
++# Makefile for KORBit
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++PROJECT = echo
++
++CFLAGS = -Wall `orbit-config --cflags client` -I../../..
++LDFLAGS = `orbit-config --libs client`
++OBJS = $(PROJECT)-common.o $(PROJECT)-stubs.o $(PROJECT)-client.o
++ORBIT-IDL = orbit-idl
++
++$(PROJECT)-client: $(OBJS)
++ gcc -o $(PROJECT)-client $(OBJS) $(LDFLAGS)
++
++$(PROJECT)-client.c: $(PROJECT).h
++
++$(PROJECT).h $(PROJECT)-common.c $(PROJECT)-stubs.c: ../$(PROJECT).idl
++ $(ORBIT-IDL) --noskels ../$(PROJECT).idl
++
++clean:
++ rm -f $(OBJS) $(PROJECT)-client
++
++realclean: clean
++ rm -f $(PROJECT).h
++ rm -f $(PROJECT)-common.c
++ rm -f $(PROJECT)-stubs.c
++ rm -f *~
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client/README linux-2.4.1-korbit/net/korbit/modules/Echo/client/README
+--- linux-2.4.1/net/korbit/modules/Echo/client/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/README Thu Feb 1 11:47:05 2001
+@@ -0,0 +1,4 @@
++This simply tests the Echo service.
++
++ORB: ORBit
++Status: working
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client/RunClient.sh linux-2.4.1-korbit/net/korbit/modules/Echo/client/RunClient.sh
+--- linux-2.4.1/net/korbit/modules/Echo/client/RunClient.sh Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/RunClient.sh Thu Feb 1 11:47:05 2001
+@@ -0,0 +1,3 @@
++#!/bin/sh
++date
++./echo-client `cat /proc/corba/echo-server` 5
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client/echo-client.c linux-2.4.1-korbit/net/korbit/modules/Echo/client/echo-client.c
+--- linux-2.4.1/net/korbit/modules/Echo/client/echo-client.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/echo-client.c Thu Feb 1 11:47:05 2001
+@@ -0,0 +1,119 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <sys/time.h>
++#include <unistd.h>
++#include <orb/orbit.h>
++
++#ifdef __KERNEL__
++#include <linux/init.h>
++#include <linux/module.h>
++#include "korbit.h"
++#endif
++#include "echo.h"
++
++Echo echo_client, bec;
++
++#define BATCH_SIZE 1
++
++
++#ifndef __KERNEL__
++int main (int argc, char *argv[]) {
++#else
++int __init corba_echo_init(void) {
++ int argc = 1; char *argv[] = { "echo-client", 0, 0 };
++#endif
++ CORBA_Environment ev;
++ CORBA_ORB orb;
++ CORBA_long rv;
++ char buf[30];
++ int i, j;
++
++ int niters = 5;
++
++#ifndef __KERNEL__
++ struct timeval start, end;
++ long diff, diffsum = 0;
++#endif
++
++ CORBA_exception_init(&ev);
++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", &ev);
++
++#ifdef __KERNEL__
++ {
++ int c, fd = open("/tmp/echo-ior", O_RDONLY, 0);
++ if (fd == -1)
++ return -1;
++ printf("Reading IOR from /tmp/echo-ior\n");
++ argv[1] = malloc(501);
++ c = read(fd, argv[1], 500);
++ argv[1][c] = '\0';
++ printf("Reading %d bytes: %s\n", c, argv[1]);
++ }
++#else
++ if(argc < 2)
++ {
++ printf("Need an IOR as argv[1]\n");
++ return 1;
++ }
++
++ if(argc == 3)
++ niters = atoi(argv[2]);
++#endif
++
++ echo_client = CORBA_ORB_string_to_object(orb, argv[1], &ev);
++ if (!echo_client) {
++ printf("Cannot bind to %s\n", argv[1]);
++ return 1;
++ }
++
++ for(i = 0; i < niters; i++) {
++ g_snprintf(buf, sizeof(buf), "Hello, world [%d]", i);
++#ifdef __KERNEL__
++ bec = Echo_echoString(echo_client, buf, &rv, &ev);
++#else
++ gettimeofday(&start, NULL);
++ for (j = BATCH_SIZE; j > 0; j--) {
++ bec = Echo_echoString(echo_client, buf, &rv, &ev);
++ if (j != 1) CORBA_Object_release(bec, &ev);
++ }
++ gettimeofday(&end, NULL);
++ diff = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec);
++ diff /= BATCH_SIZE;
++ diffsum += diff;
++
++ printf("duration = %d usec\t", diff);
++#endif
++
++ if(ev._major != CORBA_NO_EXCEPTION) {
++ printf("\nWe got exception %d from echoString!\n", ev._major);
++ return 1;
++ }
++
++ CORBA_Object_release(echo_client, &ev);
++ if(ev._major != CORBA_NO_EXCEPTION) {
++ printf("we got exception %d from release!\n", ev._major);
++ return 1;
++ }
++
++ printf("[client] %d\n", rv);
++
++ echo_client = bec; bec = CORBA_OBJECT_NIL;
++ }
++
++#ifndef __KERNEL__
++ printf("duration average = %d usec\n", diffsum / niters);
++ CORBA_Object_release(echo_client, &ev);
++ CORBA_Object_release((CORBA_Object)orb, &ev);
++#endif
++
++ return 0;
++}
++
++
++#ifdef __KERNEL__
++void corba_echo_exit(void) {
++}
++
++module_init(corba_echo_init)
++module_exit(corba_echo_exit)
++#endif
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client/echo-common.c linux-2.4.1-korbit/net/korbit/modules/Echo/client/echo-common.c
+--- linux-2.4.1/net/korbit/modules/Echo/client/echo-common.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/echo-common.c Thu Feb 1 16:36:36 2001
+@@ -0,0 +1,27 @@
++/*
++ * This file was generated by orbit-idl - DO NOT EDIT!
++ */
++
++#include <string.h>
++#include "echo.h"
++
++#if ( (TC_IMPL_TC_Echo_0 == 'e') \
++&& (TC_IMPL_TC_Echo_1 == 'c') \
++&& (TC_IMPL_TC_Echo_2 == 'h') \
++&& (TC_IMPL_TC_Echo_3 == 'o') \
++) && !defined(TC_DEF_TC_Echo)
++#define TC_DEF_TC_Echo 1
++const struct CORBA_TypeCode_struct TC_Echo_struct = {
++
++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1},
++ ORBIT_PSEUDO_TYPECODE},
++
++ CORBA_tk_objref, "Echo", "IDL:Echo:1.0",
++ 0, 0,
++ NULL,
++ NULL,
++ NULL,
++ CORBA_OBJECT_NIL, 0, -1, 0, 0
++};
++#endif
++CORBA_unsigned_long Echo__classid = 0;
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client/echo-stubs.c linux-2.4.1-korbit/net/korbit/modules/Echo/client/echo-stubs.c
+--- linux-2.4.1/net/korbit/modules/Echo/client/echo-stubs.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/echo-stubs.c Thu Feb 1 16:36:36 2001
+@@ -0,0 +1,134 @@
++/*
++ * This file was generated by orbit-idl - DO NOT EDIT!
++ */
++
++#include <string.h>
++#include "echo.h"
++
++Echo
++Echo_echoString(Echo _obj, const CORBA_char * astring, CORBA_long * anum,
++ CORBA_Environment * ev)
++{
++ register GIOP_unsigned_long _ORBIT_request_id,
++ _ORBIT_system_exception_minor;
++ register CORBA_completion_status _ORBIT_completion_status;
++ register GIOPSendBuffer *_ORBIT_send_buffer;
++ register GIOPRecvBuffer *_ORBIT_recv_buffer;
++ register GIOPConnection *_cnx;
++ Echo _ORBIT_retval;
++
++ if (_obj->servant && _obj->vepv && Echo__classid) {
++ _ORBIT_retval =
++ ((POA_Echo__epv *) _obj->vepv[Echo__classid])->echoString(_obj->
++ servant,
++ astring,
++ anum, ev);
++ return _ORBIT_retval;
++ }
++ _cnx = ORBit_object_get_connection(_obj);
++ _ORBIT_retry_request:
++ _ORBIT_send_buffer = NULL;
++ _ORBIT_recv_buffer = NULL;
++ _ORBIT_completion_status = CORBA_COMPLETED_NO;
++ _ORBIT_request_id = GPOINTER_TO_UINT(alloca(0));
++ { /* marshalling */
++ static const struct
++ {
++ CORBA_unsigned_long len;
++ char opname[11];
++ }
++ _ORBIT_operation_name_data =
++ {
++ 11, "echoString"};
++ static const struct iovec _ORBIT_operation_vec =
++ { (gpointer) & _ORBIT_operation_name_data, 15 };
++ register CORBA_unsigned_long _ORBIT_tmpvar_0;
++ CORBA_unsigned_long _ORBIT_tmpvar_1;
++
++ _ORBIT_send_buffer =
++ giop_send_request_buffer_use(_cnx, NULL, _ORBIT_request_id,
++ CORBA_TRUE,
++ &(_obj->active_profile->object_key_vec),
++ &_ORBIT_operation_vec,
++ &ORBit_default_principal_iovec);
++
++ _ORBIT_system_exception_minor = ex_CORBA_COMM_FAILURE;
++ if (!_ORBIT_send_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_tmpvar_1 = strlen(astring) + 1;
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER
++ (_ORBIT_send_buffer), 4);
++ {
++ guchar *_ORBIT_t;
++
++ _ORBIT_t = alloca(sizeof(_ORBIT_tmpvar_1));
++ memcpy(_ORBIT_t, &(_ORBIT_tmpvar_1), sizeof(_ORBIT_tmpvar_1));
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER
++ (_ORBIT_send_buffer), (_ORBIT_t),
++ sizeof(_ORBIT_tmpvar_1));
++ }
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer),
++ (astring),
++ sizeof(astring[_ORBIT_tmpvar_0]) *
++ _ORBIT_tmpvar_1);
++ giop_send_buffer_write(_ORBIT_send_buffer);
++ _ORBIT_completion_status = CORBA_COMPLETED_MAYBE;
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ _ORBIT_send_buffer = NULL;
++ }
++ { /* demarshalling */
++ register guchar *_ORBIT_curptr;
++
++ _ORBIT_recv_buffer =
++ giop_recv_reply_buffer_use_2(_cnx, _ORBIT_request_id, TRUE);
++ if (!_ORBIT_recv_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_completion_status = CORBA_COMPLETED_YES;
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status !=
++ GIOP_NO_EXCEPTION) goto _ORBIT_msg_exception;
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) {
++ GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur = _ORBIT_curptr;
++ _ORBIT_retval =
++ ORBit_demarshal_object(_ORBIT_recv_buffer,
++ GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)->
++ connection->orb_data);
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++
++ (*((guint32 *) & ((*anum)))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));} else {
++ GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur = _ORBIT_curptr;
++ _ORBIT_retval =
++ ORBit_demarshal_object(_ORBIT_recv_buffer,
++ GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)->
++ connection->orb_data);
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++ (*anum) = *((CORBA_long *) _ORBIT_curptr);
++ }
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return _ORBIT_retval;
++ _ORBIT_system_exception:
++ CORBA_exception_set_system(ev, _ORBIT_system_exception_minor,
++ _ORBIT_completion_status);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ return _ORBIT_retval;
++ _ORBIT_msg_exception:
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status ==
++ GIOP_LOCATION_FORWARD) {
++ if (_obj->forward_locations != NULL)
++ ORBit_delete_profiles(_obj->forward_locations);
++ _obj->forward_locations = ORBit_demarshal_IOR(_ORBIT_recv_buffer);
++ _cnx = ORBit_object_get_forwarded_connection(_obj);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++
++ goto _ORBIT_retry_request;
++ } else {
++ ORBit_handle_exception(_ORBIT_recv_buffer, ev, NULL, _obj->orb);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return _ORBIT_retval;
++ }
++ }
++}
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client/echo.h linux-2.4.1-korbit/net/korbit/modules/Echo/client/echo.h
+--- linux-2.4.1/net/korbit/modules/Echo/client/echo.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/echo.h Thu Feb 1 16:36:36 2001
+@@ -0,0 +1,77 @@
++/*
++ * This file was generated by orbit-idl - DO NOT EDIT!
++ */
++
++#include <glib.h>
++#define ORBIT_IDL_SERIAL 9
++#include <orb/orbit.h>
++
++#ifndef echo_H
++#define echo_H 1
++#ifdef __cplusplus
++extern "C"
++{
++#endif /* __cplusplus */
++
++/** typedefs **/
++#if !defined(ORBIT_DECL_Echo) && !defined(_Echo_defined)
++#define ORBIT_DECL_Echo 1
++#define _Echo_defined 1
++#define Echo__free CORBA_Object__free
++ typedef CORBA_Object Echo;
++ extern CORBA_unsigned_long Echo__classid;
++#if !defined(TC_IMPL_TC_Echo_0)
++#define TC_IMPL_TC_Echo_0 'e'
++#define TC_IMPL_TC_Echo_1 'c'
++#define TC_IMPL_TC_Echo_2 'h'
++#define TC_IMPL_TC_Echo_3 'o'
++ extern const struct CORBA_TypeCode_struct TC_Echo_struct;
++#define TC_Echo ((CORBA_TypeCode)&TC_Echo_struct)
++#endif
++#endif
++
++/** POA structures **/
++ typedef struct
++ {
++ void *_private;
++
++ Echo(*echoString) (PortableServer_Servant _servant,
++ const CORBA_char * astring, CORBA_long * anum,
++ CORBA_Environment * ev);
++ }
++ POA_Echo__epv;
++ typedef struct
++ {
++ PortableServer_ServantBase__epv *_base_epv;
++ POA_Echo__epv *Echo_epv;
++ }
++ POA_Echo__vepv;
++ typedef struct
++ {
++ void *_private;
++ POA_Echo__vepv *vepv;
++ }
++ POA_Echo;
++ extern void POA_Echo__init(PortableServer_Servant servant,
++ CORBA_Environment * ev);
++ extern void POA_Echo__fini(PortableServer_Servant servant,
++ CORBA_Environment * ev);
++
++/** prototypes **/
++ Echo Echo_echoString(Echo _obj, const CORBA_char * astring,
++ CORBA_long * anum, CORBA_Environment * ev);
++
++ void _ORBIT_skel_Echo_echoString(POA_Echo * _ORBIT_servant,
++ GIOPRecvBuffer * _ORBIT_recv_buffer,
++ CORBA_Environment * ev,
++ Echo(*_impl_echoString)
++ (PortableServer_Servant _servant,
++ const CORBA_char * astring,
++ CORBA_long * anum,
++ CORBA_Environment * ev));
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif
++#undef ORBIT_IDL_SERIAL
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client-perl/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/Echo/client-perl/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/CVS/Entries Thu Feb 1 11:47:06 2001
+@@ -0,0 +1,3 @@
++/PerlTest/1.2/Thu Feb 1 09:47:06 2001//
++/README/1.1/Thu Feb 1 09:47:06 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client-perl/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/Echo/client-perl/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/CVS/Repository Thu Feb 1 11:47:06 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/Echo/client-perl
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client-perl/CVS/Root linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/CVS/Root
+--- linux-2.4.1/net/korbit/modules/Echo/client-perl/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/CVS/Root Thu Feb 1 11:47:06 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client-perl/PerlTest linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/PerlTest
+--- linux-2.4.1/net/korbit/modules/Echo/client-perl/PerlTest Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/PerlTest Thu Feb 1 11:47:06 2001
+@@ -0,0 +1,17 @@
++#!/usr/bin/perl -w
++
++use CORBA::ORBit idl => [ qw(../echo.idl) ];
++use Error qw(:try);
++use strict;
++
++my $orb = CORBA::ORB_init("orbit-local-orb");
++open IOR, "/proc/corba/echo-server" or die "no console server found!";
++my $ior = <IOR>;
++close IOR;
++chomp($ior); # Kill fredrik's newline...
++
++my $echo = $orb->string_to_object($ior);
++# Echo echoString(in string astring, out long anum);
++my ($echo2, $num) = $echo->echoString("Echo Strange World");
++
++print "Return Echo = $echo2\nnum = $num\n";
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client-perl/README linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/README
+--- linux-2.4.1/net/korbit/modules/Echo/client-perl/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/README Thu Feb 1 11:47:06 2001
+@@ -0,0 +1,4 @@
++Another test of the echo server.
++
++ORB: ORBit/Perl
++Status: Working fine
+diff -urN linux-2.4.1/net/korbit/modules/Echo/echo.idl linux-2.4.1-korbit/net/korbit/modules/Echo/echo.idl
+--- linux-2.4.1/net/korbit/modules/Echo/echo.idl Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/echo.idl Thu Feb 1 11:47:05 2001
+@@ -0,0 +1,3 @@
++interface Echo {
++ Echo echoString(in string astring, out long anum);
++};
+diff -urN linux-2.4.1/net/korbit/modules/Echo/server/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/Echo/server/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/Echo/server/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/CVS/Entries Thu Feb 1 11:47:06 2001
+@@ -0,0 +1,6 @@
++/Makefile/1.2/Thu Feb 1 09:47:06 2001//
++/Makefile.user/1.3/Thu Feb 1 09:47:06 2001//
++/README/1.1/Thu Feb 1 09:47:06 2001//
++/RunServer.sh/1.1/Thu Feb 1 09:47:06 2001//
++/echo-server.c/1.8/Thu Feb 1 09:47:06 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/Echo/server/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/Echo/server/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/Echo/server/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/CVS/Repository Thu Feb 1 11:47:06 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/Echo/server
+diff -urN linux-2.4.1/net/korbit/modules/Echo/server/CVS/Root linux-2.4.1-korbit/net/korbit/modules/Echo/server/CVS/Root
+--- linux-2.4.1/net/korbit/modules/Echo/server/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/CVS/Root Thu Feb 1 11:47:06 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/Echo/server/Makefile linux-2.4.1-korbit/net/korbit/modules/Echo/server/Makefile
+--- linux-2.4.1/net/korbit/modules/Echo/server/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/Makefile Thu Feb 1 11:47:06 2001
+@@ -0,0 +1,21 @@
++#
++# Makefile for KORBit
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++O_TARGET := corba-echo-server.o
++
++obj-y := echo-server.o echo-skels.o echo-common.o
++obj-m := $(O_TARGET)
++
++include ../../Makefile.module
++
++echo-server.c: echo.h echo-skels.c
++
++
++echo.h echo-common.c echo-skels.c: ../echo.idl
++ $(ORBIT_IDL) ../echo.idl
+diff -urN linux-2.4.1/net/korbit/modules/Echo/server/Makefile.user linux-2.4.1-korbit/net/korbit/modules/Echo/server/Makefile.user
+--- linux-2.4.1/net/korbit/modules/Echo/server/Makefile.user Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/Makefile.user Thu Feb 1 11:47:06 2001
+@@ -0,0 +1,27 @@
++#
++# Makefile for user level server
++#
++
++PROJECT = echo
++
++CFLAGS = -Wall `orbit-config --cflags server` -I../../..
++LDFLAGS = `orbit-config --libs server`
++OBJS = $(PROJECT)-common.o $(PROJECT)-skels.o $(PROJECT)-server.o
++ORBIT-IDL = orbit-idl
++
++$(PROJECT)-server: $(OBJS)
++ gcc -o $(PROJECT)-server $(OBJS) $(LDFLAGS)
++
++$(PROJECT)-server.c: $(PROJECT).h
++
++$(PROJECT).h $(PROJECT)-common.c $(PROJECT)-skels.c: ../$(PROJECT).idl
++ $(ORBIT-IDL) --nostubs ../$(PROJECT).idl
++
++clean:
++ rm -f $(OBJS) $(PROJECT)-server
++
++realclean: clean
++ rm -f $(PROJECT).h
++ rm -f $(PROJECT)-common.c
++ rm -f $(PROJECT)-skels.c
++ rm -f *~
+diff -urN linux-2.4.1/net/korbit/modules/Echo/server/README linux-2.4.1-korbit/net/korbit/modules/Echo/server/README
+--- linux-2.4.1/net/korbit/modules/Echo/server/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/README Thu Feb 1 11:47:06 2001
+@@ -0,0 +1,5 @@
++This server implements the kernel side interface in terms of printk.
++
++This server also builds in user space with ORBit. Build with
++ make -f Makefile.user
++
+diff -urN linux-2.4.1/net/korbit/modules/Echo/server/RunServer.sh linux-2.4.1-korbit/net/korbit/modules/Echo/server/RunServer.sh
+--- linux-2.4.1/net/korbit/modules/Echo/server/RunServer.sh Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/RunServer.sh Thu Feb 1 11:47:06 2001
+@@ -0,0 +1 @@
++./echo-server -ORBIIOPUSock=0 -ORBIIOPIPv4=1
+diff -urN linux-2.4.1/net/korbit/modules/Echo/server/echo-common.c linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo-common.c
+--- linux-2.4.1/net/korbit/modules/Echo/server/echo-common.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo-common.c Thu Feb 1 16:36:57 2001
+@@ -0,0 +1,27 @@
++/*
++ * This file was generated by orbit-idl - DO NOT EDIT!
++ */
++
++#include <string.h>
++#include "echo.h"
++
++#if ( (TC_IMPL_TC_Echo_0 == 'e') \
++&& (TC_IMPL_TC_Echo_1 == 'c') \
++&& (TC_IMPL_TC_Echo_2 == 'h') \
++&& (TC_IMPL_TC_Echo_3 == 'o') \
++) && !defined(TC_DEF_TC_Echo)
++#define TC_DEF_TC_Echo 1
++const struct CORBA_TypeCode_struct TC_Echo_struct = {
++
++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1},
++ ORBIT_PSEUDO_TYPECODE},
++
++ CORBA_tk_objref, "Echo", "IDL:Echo:1.0",
++ 0, 0,
++ NULL,
++ NULL,
++ NULL,
++ CORBA_OBJECT_NIL, 0, -1, 0, 0
++};
++#endif
++CORBA_unsigned_long Echo__classid = 0;
+diff -urN linux-2.4.1/net/korbit/modules/Echo/server/echo-server.c linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo-server.c
+--- linux-2.4.1/net/korbit/modules/Echo/server/echo-server.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo-server.c Thu Feb 1 11:47:06 2001
+@@ -0,0 +1,103 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <signal.h>
++#include <orb/orbit.h>
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include "echo.h"
++#include "glib.h"
++#include "korbit.h"
++
++Echo echo_client = CORBA_OBJECT_NIL;
++
++static CORBA_Object
++do_echoString(PortableServer_Servant servant,
++ CORBA_char *astring,
++ CORBA_long *outnum,
++ CORBA_Environment *ev);
++
++PortableServer_ServantBase__epv base_epv = {
++ NULL,
++ NULL,
++ NULL
++};
++POA_Echo__epv echo_epv = { NULL, do_echoString };
++POA_Echo__vepv poa_echo_vepv = { &base_epv, &echo_epv };
++POA_Echo poa_echo_servant = { NULL, &poa_echo_vepv };
++
++PortableServer_ObjectId objid = {0, sizeof("myEchoString"), "myEchoString"};
++PortableServer_POA poa;
++CORBA_Environment *ev;
++
++#ifdef __KERNEL__
++int __init corba_echo_init(void)
++#else
++int main(int argc, char *argv[])
++#endif
++{
++#ifdef __KERNEL__
++ int argc = 1; char *argv[] = { "server", 0 };
++#endif
++ CORBA_ORB orb;
++ ev = g_new0(CORBA_Environment, 1);
++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", ev);
++ if (!orb) {
++ printf("Error getting ORB!\n");
++ return 1;
++ }
++
++ poa = (PortableServer_POA)
++ CORBA_ORB_resolve_initial_references(orb, "RootPOA", ev);
++ if (!poa) {
++ printf("Error getting POA!\n");
++ return 1;
++ }
++
++ PortableServer_POAManager_activate(
++ PortableServer_POA__get_the_POAManager(poa, ev), ev);
++
++
++ POA_Echo__init(&poa_echo_servant, ev);
++ PortableServer_POA_activate_object_with_id(poa,
++ &objid, &poa_echo_servant, ev);
++
++ echo_client = PortableServer_POA_servant_to_reference(poa,
++ &poa_echo_servant,
++ ev);
++ if (!echo_client) {
++ printf("Cannot get objref\n");
++ return 1;
++ }
++
++ korbit_register_ior("echo-server", echo_client, orb, ev);
++
++ CORBA_ORB_run(orb, ev);
++ return 0;
++}
++
++#ifdef __KERNEL__
++void corba_echo_exit(void) {
++ PortableServer_POA_deactivate_object(poa, &objid, ev);
++ remove_proc_entry("corba/echo-server", 0);
++}
++
++module_init(corba_echo_init)
++module_exit(corba_echo_exit)
++#endif
++
++static CORBA_Object
++do_echoString(PortableServer_Servant servant,
++ CORBA_char *astring,
++ CORBA_long *outnum,
++ CORBA_Environment *ev)
++{
++ *outnum = 12345678;
++
++#if 1
++ g_message("[server] %s -> %d", astring, *outnum);
++#endif
++
++ return CORBA_Object_duplicate(echo_client, ev);
++}
+diff -urN linux-2.4.1/net/korbit/modules/Echo/server/echo-skels.c linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo-skels.c
+--- linux-2.4.1/net/korbit/modules/Echo/server/echo-skels.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo-skels.c Thu Feb 1 16:36:57 2001
+@@ -0,0 +1,115 @@
++/*
++ * This file was generated by orbit-idl - DO NOT EDIT!
++ */
++
++#include <string.h>
++#include "echo.h"
++
++void
++_ORBIT_skel_Echo_echoString(POA_Echo * _ORBIT_servant,
++ GIOPRecvBuffer * _ORBIT_recv_buffer,
++ CORBA_Environment * ev,
++ Echo(*_impl_echoString) (PortableServer_Servant
++ _servant,
++ const CORBA_char *
++ astring,
++ CORBA_long * anum,
++ CORBA_Environment * ev))
++{
++ Echo _ORBIT_retval;
++ CORBA_char *astring;
++ CORBA_long anum;
++
++ { /* demarshalling */
++ guchar *_ORBIT_curptr;
++ register CORBA_unsigned_long _ORBIT_tmpvar_2;
++ CORBA_unsigned_long _ORBIT_tmpvar_3;
++
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) {
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++
++ (*((guint32 *) & (_ORBIT_tmpvar_3))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));
++ _ORBIT_curptr += 4;
++ astring = (void *) _ORBIT_curptr;
++ _ORBIT_curptr += sizeof(astring[_ORBIT_tmpvar_2]) * _ORBIT_tmpvar_3;
++ } else {
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++ _ORBIT_tmpvar_3 = *((CORBA_unsigned_long *) _ORBIT_curptr);
++ _ORBIT_curptr += 4;
++ astring = (void *) _ORBIT_curptr;
++ _ORBIT_curptr += sizeof(astring[_ORBIT_tmpvar_2]) * _ORBIT_tmpvar_3;
++ }
++ }
++ _ORBIT_retval = _impl_echoString(_ORBIT_servant, astring, &(anum), ev);
++ { /* marshalling */
++ register GIOPSendBuffer *_ORBIT_send_buffer;
++
++ _ORBIT_send_buffer =
++ giop_send_reply_buffer_use(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)->
++ connection, NULL,
++ _ORBIT_recv_buffer->message.u.request.
++ request_id, ev->_major);
++ if (_ORBIT_send_buffer) {
++ if (ev->_major == CORBA_NO_EXCEPTION) {
++ ORBit_marshal_object(_ORBIT_send_buffer, _ORBIT_retval);
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER
++ (_ORBIT_send_buffer), 4);
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER
++ (_ORBIT_send_buffer), &(anum),
++ sizeof(anum));
++ } else
++ ORBit_send_system_exception(_ORBIT_send_buffer, ev);
++ giop_send_buffer_write(_ORBIT_send_buffer);
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ }
++ if (ev->_major == CORBA_NO_EXCEPTION)
++ CORBA_Object_release(_ORBIT_retval, ev);
++ }
++}
++static ORBitSkeleton
++get_skel_Echo(POA_Echo * servant,
++ GIOPRecvBuffer * _ORBIT_recv_buffer, gpointer * impl)
++{
++ gchar *opname = _ORBIT_recv_buffer->message.u.request.operation;
++
++ switch (opname[0]) {
++ case 'e':
++ if (strcmp((opname + 1), "choString"))
++ break;
++ *impl = (gpointer) servant->vepv->Echo_epv->echoString;
++ return (ORBitSkeleton) _ORBIT_skel_Echo_echoString;
++ break;
++ default:
++ break;
++ }
++ return NULL;
++}
++
++static void
++init_local_objref_Echo(CORBA_Object obj, POA_Echo * servant)
++{
++ obj->vepv[Echo__classid] = servant->vepv->Echo_epv;
++}
++
++void
++POA_Echo__init(PortableServer_Servant servant, CORBA_Environment * env)
++{
++ static const PortableServer_ClassInfo class_info =
++ { (ORBit_impl_finder) & get_skel_Echo, "IDL:Echo:1.0",
++ (ORBit_local_objref_init) & init_local_objref_Echo };
++
++ PortableServer_ServantBase__init(((PortableServer_ServantBase *) servant),
++ env);
++ ORBIT_OBJECT_KEY(((PortableServer_ServantBase *) servant)->_private)->
++ class_info = (PortableServer_ClassInfo *) & class_info;
++ if (!Echo__classid)
++ Echo__classid = ORBit_register_class(&class_info);
++}
++
++void
++POA_Echo__fini(PortableServer_Servant servant, CORBA_Environment * env)
++{
++ PortableServer_ServantBase__fini(servant, env);
++}
+diff -urN linux-2.4.1/net/korbit/modules/Echo/server/echo-stubs.c linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo-stubs.c
+--- linux-2.4.1/net/korbit/modules/Echo/server/echo-stubs.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo-stubs.c Thu Feb 1 16:36:57 2001
+@@ -0,0 +1,134 @@
++/*
++ * This file was generated by orbit-idl - DO NOT EDIT!
++ */
++
++#include <string.h>
++#include "echo.h"
++
++Echo
++Echo_echoString(Echo _obj, const CORBA_char * astring, CORBA_long * anum,
++ CORBA_Environment * ev)
++{
++ register GIOP_unsigned_long _ORBIT_request_id,
++ _ORBIT_system_exception_minor;
++ register CORBA_completion_status _ORBIT_completion_status;
++ register GIOPSendBuffer *_ORBIT_send_buffer;
++ register GIOPRecvBuffer *_ORBIT_recv_buffer;
++ register GIOPConnection *_cnx;
++ Echo _ORBIT_retval;
++
++ if (_obj->servant && _obj->vepv && Echo__classid) {
++ _ORBIT_retval =
++ ((POA_Echo__epv *) _obj->vepv[Echo__classid])->echoString(_obj->
++ servant,
++ astring,
++ anum, ev);
++ return _ORBIT_retval;
++ }
++ _cnx = ORBit_object_get_connection(_obj);
++ _ORBIT_retry_request:
++ _ORBIT_send_buffer = NULL;
++ _ORBIT_recv_buffer = NULL;
++ _ORBIT_completion_status = CORBA_COMPLETED_NO;
++ _ORBIT_request_id = GPOINTER_TO_UINT(alloca(0));
++ { /* marshalling */
++ static const struct
++ {
++ CORBA_unsigned_long len;
++ char opname[11];
++ }
++ _ORBIT_operation_name_data =
++ {
++ 11, "echoString"};
++ static const struct iovec _ORBIT_operation_vec =
++ { (gpointer) & _ORBIT_operation_name_data, 15 };
++ register CORBA_unsigned_long _ORBIT_tmpvar_0;
++ CORBA_unsigned_long _ORBIT_tmpvar_1;
++
++ _ORBIT_send_buffer =
++ giop_send_request_buffer_use(_cnx, NULL, _ORBIT_request_id,
++ CORBA_TRUE,
++ &(_obj->active_profile->object_key_vec),
++ &_ORBIT_operation_vec,
++ &ORBit_default_principal_iovec);
++
++ _ORBIT_system_exception_minor = ex_CORBA_COMM_FAILURE;
++ if (!_ORBIT_send_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_tmpvar_1 = strlen(astring) + 1;
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER
++ (_ORBIT_send_buffer), 4);
++ {
++ guchar *_ORBIT_t;
++
++ _ORBIT_t = alloca(sizeof(_ORBIT_tmpvar_1));
++ memcpy(_ORBIT_t, &(_ORBIT_tmpvar_1), sizeof(_ORBIT_tmpvar_1));
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER
++ (_ORBIT_send_buffer), (_ORBIT_t),
++ sizeof(_ORBIT_tmpvar_1));
++ }
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer),
++ (astring),
++ sizeof(astring[_ORBIT_tmpvar_0]) *
++ _ORBIT_tmpvar_1);
++ giop_send_buffer_write(_ORBIT_send_buffer);
++ _ORBIT_completion_status = CORBA_COMPLETED_MAYBE;
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ _ORBIT_send_buffer = NULL;
++ }
++ { /* demarshalling */
++ register guchar *_ORBIT_curptr;
++
++ _ORBIT_recv_buffer =
++ giop_recv_reply_buffer_use_2(_cnx, _ORBIT_request_id, TRUE);
++ if (!_ORBIT_recv_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_completion_status = CORBA_COMPLETED_YES;
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status !=
++ GIOP_NO_EXCEPTION) goto _ORBIT_msg_exception;
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) {
++ GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur = _ORBIT_curptr;
++ _ORBIT_retval =
++ ORBit_demarshal_object(_ORBIT_recv_buffer,
++ GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)->
++ connection->orb_data);
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++
++ (*((guint32 *) & ((*anum)))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));} else {
++ GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur = _ORBIT_curptr;
++ _ORBIT_retval =
++ ORBit_demarshal_object(_ORBIT_recv_buffer,
++ GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)->
++ connection->orb_data);
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++ (*anum) = *((CORBA_long *) _ORBIT_curptr);
++ }
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return _ORBIT_retval;
++ _ORBIT_system_exception:
++ CORBA_exception_set_system(ev, _ORBIT_system_exception_minor,
++ _ORBIT_completion_status);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ return _ORBIT_retval;
++ _ORBIT_msg_exception:
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status ==
++ GIOP_LOCATION_FORWARD) {
++ if (_obj->forward_locations != NULL)
++ ORBit_delete_profiles(_obj->forward_locations);
++ _obj->forward_locations = ORBit_demarshal_IOR(_ORBIT_recv_buffer);
++ _cnx = ORBit_object_get_forwarded_connection(_obj);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++
++ goto _ORBIT_retry_request;
++ } else {
++ ORBit_handle_exception(_ORBIT_recv_buffer, ev, NULL, _obj->orb);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return _ORBIT_retval;
++ }
++ }
++}
+diff -urN linux-2.4.1/net/korbit/modules/Echo/server/echo.h linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo.h
+--- linux-2.4.1/net/korbit/modules/Echo/server/echo.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo.h Thu Feb 1 16:36:57 2001
+@@ -0,0 +1,77 @@
++/*
++ * This file was generated by orbit-idl - DO NOT EDIT!
++ */
++
++#include <glib.h>
++#define ORBIT_IDL_SERIAL 9
++#include <orb/orbit.h>
++
++#ifndef echo_H
++#define echo_H 1
++#ifdef __cplusplus
++extern "C"
++{
++#endif /* __cplusplus */
++
++/** typedefs **/
++#if !defined(ORBIT_DECL_Echo) && !defined(_Echo_defined)
++#define ORBIT_DECL_Echo 1
++#define _Echo_defined 1
++#define Echo__free CORBA_Object__free
++ typedef CORBA_Object Echo;
++ extern CORBA_unsigned_long Echo__classid;
++#if !defined(TC_IMPL_TC_Echo_0)
++#define TC_IMPL_TC_Echo_0 'e'
++#define TC_IMPL_TC_Echo_1 'c'
++#define TC_IMPL_TC_Echo_2 'h'
++#define TC_IMPL_TC_Echo_3 'o'
++ extern const struct CORBA_TypeCode_struct TC_Echo_struct;
++#define TC_Echo ((CORBA_TypeCode)&TC_Echo_struct)
++#endif
++#endif
++
++/** POA structures **/
++ typedef struct
++ {
++ void *_private;
++
++ Echo(*echoString) (PortableServer_Servant _servant,
++ const CORBA_char * astring, CORBA_long * anum,
++ CORBA_Environment * ev);
++ }
++ POA_Echo__epv;
++ typedef struct
++ {
++ PortableServer_ServantBase__epv *_base_epv;
++ POA_Echo__epv *Echo_epv;
++ }
++ POA_Echo__vepv;
++ typedef struct
++ {
++ void *_private;
++ POA_Echo__vepv *vepv;
++ }
++ POA_Echo;
++ extern void POA_Echo__init(PortableServer_Servant servant,
++ CORBA_Environment * ev);
++ extern void POA_Echo__fini(PortableServer_Servant servant,
++ CORBA_Environment * ev);
++
++/** prototypes **/
++ Echo Echo_echoString(Echo _obj, const CORBA_char * astring,
++ CORBA_long * anum, CORBA_Environment * ev);
++
++ void _ORBIT_skel_Echo_echoString(POA_Echo * _ORBIT_servant,
++ GIOPRecvBuffer * _ORBIT_recv_buffer,
++ CORBA_Environment * ev,
++ Echo(*_impl_echoString)
++ (PortableServer_Servant _servant,
++ const CORBA_char * astring,
++ CORBA_long * anum,
++ CORBA_Environment * ev));
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif
++#undef ORBIT_IDL_SERIAL
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/FileServer/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/FileServer/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/CVS/Entries Thu Feb 1 11:47:07 2001
+@@ -0,0 +1,4 @@
++/FileServer.idl/1.3/Thu Feb 1 09:47:07 2001//
++/Makefile/1.2/Thu Feb 1 09:47:07 2001//
++/README/1.1/Thu Feb 1 09:47:07 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/CVS/Entries.Log linux-2.4.1-korbit/net/korbit/modules/FileServer/CVS/Entries.Log
+--- linux-2.4.1/net/korbit/modules/FileServer/CVS/Entries.Log Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/CVS/Entries.Log Thu Feb 1 11:47:09 2001
+@@ -0,0 +1,4 @@
++A D/client////
++A D/server////
++A D/server-user////
++A D/wrapper////
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/FileServer/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/FileServer/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/CVS/Repository Thu Feb 1 11:47:07 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/FileServer
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/CVS/Root linux-2.4.1-korbit/net/korbit/modules/FileServer/CVS/Root
+--- linux-2.4.1/net/korbit/modules/FileServer/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/CVS/Root Thu Feb 1 11:47:07 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/FileServer.idl linux-2.4.1-korbit/net/korbit/modules/FileServer/FileServer.idl
+--- linux-2.4.1/net/korbit/modules/FileServer/FileServer.idl Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/FileServer.idl Thu Feb 1 11:47:07 2001
+@@ -0,0 +1,158 @@
++// -----------------------------------------------------------------------------
++// FileServer.idl
++// -----------------------------------------------------------------------------
++//
++// This file is used to define the Kernel CORBA API for accessing the filesystem
++// on a machine. This defines mappings both to access the files in the kernel
++// and to implement a filesystem for the kernel. This should probably be split
++// into two files eventually.
++//
++// Currently unimplemented: KernelAccessAPI::FileSystem::ReadDirectory
++// KernelAccessAPI::FileSystem::Select
++// KernelImplementationAPI::SuperBlock::getDiskQuotaOps
++//
++// -----------------------------------------------------------------------------
++
++
++// These are the exceptions that may be thrown and what they map to in the
++// Linux kernel. This interface is extended by other interfaces so that the
++// names don't have to be typedef'd into each interface that wants to use these
++// errors.
++//
++interface Errors {
++ exception IsDirectory {}; // EISDIR
++ exception PermissionDenied {}; // EACCES
++ exception FileExists {}; // EEXIST
++ exception FileNotFound {}; // ENOENT
++ exception IsNotDirectory {}; // ENOTDIR
++ exception ReadOnlyFile {}; // EROFS, ETXTBSY
++ exception RecursiveSymlink {}; // ELOOP
++ exception IsBusy {}; // EBUSY
++ exception OtherError{}; // Misc other ones...
++};
++
++
++// -----------------------------------------------------------------------------
++// KernelAccessAPI Module - Allow user level programs to call into the kernel
++// -----------------------------------------------------------------------------
++
++module FileServer {
++ struct FileStatus { // Corba equilivant of struct stat
++ long DeviceNum; // st_dev
++ long InodeNum; // st_ino
++ short Mode; // st_mode
++ short NumLinks; // st_nlink
++ long UserID; // st_uid
++ long GroupID; // st_gid
++ long DeviceType; // st_rdev
++ unsigned long Size; // st_size
++ unsigned long BlockSize; // st_blksize
++ unsigned long NumBlocks; // st_blocks;
++ unsigned long AccessTime; // st_blocks;
++ unsigned long ModifiedTime; // st_blocks;
++ unsigned long ChangeTime; // st_blocks;
++ };
++
++ typedef sequence<octet> buffer;
++
++ // ---------------------------------------------------------------------------
++ // FileSystem Interface - Access to filesystem and File object factory
++ // ---------------------------------------------------------------------------
++
++ interface File : Errors {
++ void Read(in long count, out buffer buf)
++ raises (IsDirectory, OtherError);
++ void Write(in buffer buf)
++ raises (OtherError);
++ void Close();
++
++ long FileControl(in long command) raises (OtherError);
++
++ FileStatus GetStatus() raises (OtherError);
++
++ void ChangeDirectoryTo() // This implements fchdir...
++ raises (IsNotDirectory, PermissionDenied, OtherError);
++
++ enum SeekDirection { FromStart, FromCurrent, FromEnd };
++ long Seek(in long Offset, in SeekDirection Direction) raises (OtherError);
++
++ File Duplicate() raises (OtherError);
++ };
++
++
++
++ // ---------------------------------------------------------------------------
++ // FileSystem Interface - Access to filesystem and File object factory
++ // ---------------------------------------------------------------------------
++
++ interface FileSystem : Errors {
++
++ // -------------------------------------------------------------------------
++ // File Manipulation Routines
++ // -------------------------------------------------------------------------
++
++ File Open(in string Filename, in long openFlags, in short mode)
++ raises (FileExists, IsDirectory, PermissionDenied, FileNotFound,
++ IsNotDirectory, ReadOnlyFile, RecursiveSymlink, OtherError);
++
++ File Create(in string Filename, in short mode)
++ raises (FileExists, IsDirectory, PermissionDenied, FileNotFound,
++ IsNotDirectory, ReadOnlyFile, RecursiveSymlink, OtherError);
++
++ void Link(in string FromPath, in string ToPath)
++ raises (PermissionDenied, IsNotDirectory, RecursiveSymlink, FileExists);
++
++ void Unlink(in string Filename)
++ raises (PermissionDenied, FileNotFound, IsNotDirectory, IsDirectory);
++
++ void Rename(in string OldName, in string NewName)
++ raises (IsDirectory, FileExists, IsBusy, IsNotDirectory, PermissionDenied,
++ RecursiveSymlink);
++
++ void ReadLink(in string Linkname, out string LinkValue)
++ raises (FileNotFound, PermissionDenied, RecursiveSymlink, OtherError);
++
++
++ FileStatus GetStatus(in string Filename)
++ raises (FileNotFound, PermissionDenied, RecursiveSymlink, IsNotDirectory,
++ OtherError);
++
++ FileStatus GetLinkStatus(in string Filename)
++ raises (FileNotFound, PermissionDenied, RecursiveSymlink, IsNotDirectory,
++ OtherError);
++
++
++ // -------------------------------------------------------------------------
++ // Directory Manipulation Routines
++ // -------------------------------------------------------------------------
++
++ void MakeDirectory(in string PathName, in short mode)
++ raises (FileExists, PermissionDenied, FileNotFound, IsNotDirectory,
++ ReadOnlyFile, RecursiveSymlink, OtherError);
++
++ void RemoveDirectory(in string PathName)
++ raises (PermissionDenied, FileNotFound, IsNotDirectory);
++
++ // ChangeDirectory returns CWD so that you can implement getcwd as
++ // { return ChangeDirectory("."); }
++ string ChangeDirectory(in string PathName)
++ raises (IsNotDirectory, PermissionDenied, FileNotFound, RecursiveSymlink);
++
++
++ // -------------------------------------------------------------------------
++ // Special Purpose Routines...
++ // -------------------------------------------------------------------------
++
++ void MakeNode(in string FileName, in short Mode, in long DeviceNum)
++ raises (PermissionDenied, FileExists, FileNotFound, IsNotDirectory,
++ RecursiveSymlink);
++
++ void Mount(in string DeviceFile, in string Location, in string FSType,
++ in long Flags)
++ raises (PermissionDenied, FileNotFound, IsBusy, IsNotDirectory);
++
++ void Unmount(in string Filename)
++ raises (PermissionDenied, FileNotFound, IsBusy);
++ };
++
++};
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/Makefile linux-2.4.1-korbit/net/korbit/modules/FileServer/Makefile
+--- linux-2.4.1/net/korbit/modules/FileServer/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/Makefile Thu Feb 1 11:47:07 2001
+@@ -0,0 +1,11 @@
++#
++# Makefile for KORBit/modules/CorbaFS
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++
++subdir-$(CONFIG_CORBA_FILESERVER) := server
++
++include $(TOPDIR)/Rules.make
++
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/README linux-2.4.1-korbit/net/korbit/modules/FileServer/README
+--- linux-2.4.1/net/korbit/modules/FileServer/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/README Thu Feb 1 11:47:07 2001
+@@ -0,0 +1,8 @@
++This interface lets you export file related syscalls through CORBA. This is
++genuinely useful, however, when you use the 'wrapper' library, that can be
++LD_PRELOADED before you run your application. This allows you to forward
++filesystem calls through CORBA without having to modify your application.
++
++Being able to forward filesystem calls though CORBA, of course, means that
++you can attach to any remote machine you want. :)
++
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/client/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/FileServer/client/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/FileServer/client/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/client/CVS/Entries Thu Feb 1 11:47:07 2001
+@@ -0,0 +1,4 @@
++/FileServer-client.cpp/1.1/Thu Feb 1 09:47:07 2001//
++/Makefile/1.1/Thu Feb 1 09:47:07 2001//
++/README/1.1/Thu Feb 1 09:47:07 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/client/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/FileServer/client/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/FileServer/client/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/client/CVS/Repository Thu Feb 1 11:47:07 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/FileServer/client
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/client/CVS/Root linux-2.4.1-korbit/net/korbit/modules/FileServer/client/CVS/Root
+--- linux-2.4.1/net/korbit/modules/FileServer/client/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/client/CVS/Root Thu Feb 1 11:47:07 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/client/FileServer-client.cpp linux-2.4.1-korbit/net/korbit/modules/FileServer/client/FileServer-client.cpp
+--- linux-2.4.1/net/korbit/modules/FileServer/client/FileServer-client.cpp Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/client/FileServer-client.cpp Thu Feb 1 11:47:07 2001
+@@ -0,0 +1,78 @@
++#include <OB/CORBA.h>
++#include <OB/Util.h>
++#include <OB/CosNaming.h>
++#include <stdlib.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++
++#include "FileServer.h"
++
++int main(int argc, char* argv[])
++{
++ if (argc < 3)
++ {
++ cout << "Usage : " << argv[0] << " ior filename" << endl;
++ exit(1);
++ }
++
++ cout << "FileServer client initializing" << endl;
++
++ CORBA_ORB_var orb = CORBA_ORB_init(argc, argv);
++ cout << "ORB initialized" << endl;
++
++ try
++ {
++ CORBA_Object_var obj = orb->string_to_object( argv[1] );
++ assert(!CORBA_is_nil(obj));
++ cout << "got object... " << orb->object_to_string(obj) << endl;
++
++ FileServer_FileSystem_var fs = FileServer_FileSystem::_narrow(obj);
++ assert(!CORBA_is_nil(fs));
++ cout << "it's a FileServer!" << endl;
++
++ obj = fs->Open(argv[2], O_RDONLY, 0);
++ assert(!CORBA_is_nil(obj));
++ cout << "got object... " << orb->object_to_string(obj) << endl;
++
++ FileServer_File_var file = FileServer_File::_narrow(obj);
++ assert(!CORBA_is_nil(file));
++ cout << "it's a FileServer_File!" << endl;
++
++ FileServer_buffer *buf = new FileServer_buffer;
++ cout << "reading 1000 bytes" << endl;
++ file->Read(1000, buf);
++
++ cout << "got " << buf->length() << " bytes" << endl;
++ cout << buf->data() << endl;
++
++ file->Close();
++
++ delete buf;
++ }
++ catch (const CORBA_SystemException& ex) {
++ OBPrintException(ex);
++ return 1;
++ }
++ catch (const Errors::FileNotFound& ex) {
++ cout << "ERROR : File not found" << endl;
++ return 1;
++ }
++ catch (const Errors::PermissionDenied& ex) {
++ cout << "ERROR : Permission denied" << endl;
++ return 1;
++ }
++ catch (const Errors::IsDirectory& ex) {
++ cout << "ERROR : Is directory" << endl;
++ return 1;
++ }
++ catch (const Errors::OtherError& ex) {
++ cout << "ERROR : Other error" << endl;
++ return 1;
++ }
++ catch (const CORBA_UserException& ex)
++ {
++ cout << "ERROR : Uncaught exception" << endl;
++ return 1;
++ }
++}
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/client/Makefile linux-2.4.1-korbit/net/korbit/modules/FileServer/client/Makefile
+--- linux-2.4.1/net/korbit/modules/FileServer/client/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/client/Makefile Thu Feb 1 11:47:07 2001
+@@ -0,0 +1,32 @@
++CC = CC -mt -pta
++OBDIR = /home/class/cs423/local
++IDL = $(OBDIR)/bin/idl
++CPPFLAGS = -I. -I$(OBDIR)/include
++LDFLAGS = -L$(OBDIR)/lib
++LIBS = -lCosNaming -lOB -lJTC -lsocket -lnsl -lposix4
++
++all: FileServer-client
++
++FileServer-client: FileServer.o FileServer-client.o
++ $(CC) $(LDFLAGS) -o FileServer-client FileServer-client.o FileServer.o $(LIBS)
++
++nameserv:
++ nameserv -i -OAport 10000
++
++FileServer.h FileServer.cpp: ../FileServer.idl
++ rm -f FileServer.cpp FileServer.h
++ rm -f FileServer_skel.h FileServer_skel.cpp
++ $(IDL) ../FileServer.idl
++
++FileServer_skel.cpp FileServer_skel.h: FileServer.cpp
++
++%.o: %.cpp
++ $(CC) $(CPPFLAGS) -c $<
++
++clean:
++ rm -f FileServer-client *.o *~
++
++realclean: clean
++ rm -f FileServer.h FileServer.cpp
++ rm -f FileServer_skel.h FileServer_skel.cpp
++ rm -rf SunWS_cache
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/client/README linux-2.4.1-korbit/net/korbit/modules/FileServer/client/README
+--- linux-2.4.1/net/korbit/modules/FileServer/client/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/client/README Thu Feb 1 11:47:07 2001
+@@ -0,0 +1,4 @@
++Very minimal test of the FileServer capability.
++
++ORB: Orbacus
++
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/FileServer/server/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/FileServer/server/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server/CVS/Entries Thu Feb 1 11:47:08 2001
+@@ -0,0 +1,6 @@
++/FileServer-server.c/1.2/Thu Feb 1 09:47:08 2001//
++/FileServer-skelimpl.c/1.8/Thu Feb 1 09:47:08 2001//
++/Makefile/1.3/Thu Feb 1 09:47:08 2001//
++/Makefile.user/1.4/Thu Feb 1 09:47:08 2001//
++/README/1.1/Thu Feb 1 09:47:08 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/FileServer/server/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/FileServer/server/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server/CVS/Repository Thu Feb 1 11:47:08 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/FileServer/server
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server/CVS/Root linux-2.4.1-korbit/net/korbit/modules/FileServer/server/CVS/Root
+--- linux-2.4.1/net/korbit/modules/FileServer/server/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server/CVS/Root Thu Feb 1 11:47:08 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server/FileServer-server.c linux-2.4.1-korbit/net/korbit/modules/FileServer/server/FileServer-server.c
+--- linux-2.4.1/net/korbit/modules/FileServer/server/FileServer-server.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server/FileServer-server.c Thu Feb 1 11:47:08 2001
+@@ -0,0 +1,57 @@
++#include <stdio.h>
++#include "FileServer-skelimpl.c"
++#include "korbit.h"
++
++CORBA_ORB orb;
++PortableServer_POA poa;
++CORBA_Environment *ev;
++PortableServer_ObjectId *objid;
++
++#ifdef __KERNEL__
++int __init FileServer_init(void) {
++#else
++int main(int argc, char *argv[]) {
++#endif
++ FileServer_FileSystem fs;
++ impl_POA_FileServer_FileSystem *fs_impl;
++
++ PortableServer_POAManager pm;
++#ifdef __KERNEL__
++ int argc = 1;
++ char *argv[] = { "server", 0 };
++#endif
++ ev = g_new0(CORBA_Environment,1);
++
++ CORBA_exception_init(ev);
++
++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", ev);
++ poa = (PortableServer_POA)
++ CORBA_ORB_resolve_initial_references(orb,
++ "RootPOA",
++ ev);
++ fs = impl_FileServer_FileSystem__create(poa, ev);
++
++ pm = PortableServer_POA__get_the_POAManager(poa, ev);
++ PortableServer_POAManager_activate(pm, ev);
++
++ fs_impl = PortableServer_POA_reference_to_servant( poa, fs, ev );
++ objid = PortableServer_POA_servant_to_id( poa, fs_impl, ev );
++
++ korbit_register_ior("FileServer-server", fs, orb, ev);
++
++ CORBA_ORB_run(orb, ev);
++
++ return 0;
++}
++
++#ifdef __KERNEL__
++void FileServer_exit(void)
++{
++ PortableServer_POA_deactivate_object(poa, objid, ev);
++ remove_proc_entry("corba/FileServer-server", 0);
++ printf("FileServer_exit()\n");
++}
++
++module_init(FileServer_init)
++module_exit(FileServer_exit)
++#endif
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server/FileServer-skelimpl.c linux-2.4.1-korbit/net/korbit/modules/FileServer/server/FileServer-skelimpl.c
+--- linux-2.4.1/net/korbit/modules/FileServer/server/FileServer-skelimpl.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server/FileServer-skelimpl.c Thu Feb 1 11:47:08 2001
+@@ -0,0 +1,804 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#include <errno.h>
++
++#include "FileServer.h"
++
++static void set_exception(int errno, CORBA_Environment *ev)
++{
++ switch (errno)
++ {
++ case ENOENT:
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_Errors_FileNotFound,
++ Errors_FileNotFound__alloc());
++ break;
++ case EEXIST:
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_Errors_FileExists,
++ Errors_FileExists__alloc());
++ break;
++ case EACCES:
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_Errors_PermissionDenied,
++ Errors_PermissionDenied__alloc());
++ break;
++ case EISDIR:
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_Errors_IsDirectory,
++ Errors_IsDirectory__alloc());
++ break;
++ case ENOTDIR:
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_Errors_IsNotDirectory,
++ Errors_IsNotDirectory__alloc());
++ break;
++ case EROFS:
++ case ETXTBSY:
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_Errors_ReadOnlyFile,
++ Errors_ReadOnlyFile__alloc());
++ break;
++ case ELOOP:
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_Errors_RecursiveSymlink,
++ Errors_RecursiveSymlink__alloc());
++ break;
++ case EBUSY:
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_Errors_IsBusy,
++ Errors_IsBusy__alloc());
++ break;
++ default:
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_Errors_OtherError,
++ Errors_OtherError__alloc());
++ break;
++ }
++}
++
++
++/*** App-specific servant structures ***/
++typedef struct
++{
++ POA_Errors servant;
++ PortableServer_POA poa;
++
++}
++impl_POA_Errors;
++
++typedef struct
++{
++ POA_FileServer_File servant;
++ PortableServer_POA poa;
++
++ int fd;
++}
++impl_POA_FileServer_File;
++
++typedef struct
++{
++ POA_FileServer_FileSystem servant;
++ PortableServer_POA poa;
++
++}
++impl_POA_FileServer_FileSystem;
++
++/*** Implementation stub prototypes ***/
++static void impl_Errors__destroy(impl_POA_Errors * servant,
++ CORBA_Environment * ev);
++
++static void impl_FileServer_File__destroy(impl_POA_FileServer_File * servant,
++ CORBA_Environment * ev);
++static void
++impl_FileServer_File_Read(impl_POA_FileServer_File * servant,
++ CORBA_long count,
++ FileServer_buffer ** buf, CORBA_Environment * ev);
++
++static void
++impl_FileServer_File_Write(impl_POA_FileServer_File * servant,
++ FileServer_buffer * buf, CORBA_Environment * ev);
++
++static void
++impl_FileServer_File_Close(impl_POA_FileServer_File * servant,
++ CORBA_Environment * ev);
++
++static CORBA_long
++impl_FileServer_File_FileControl(impl_POA_FileServer_File * servant,
++ CORBA_long command, CORBA_Environment * ev);
++
++static FileServer_FileStatus
++impl_FileServer_File_GetStatus(impl_POA_FileServer_File * servant,
++ CORBA_Environment * ev);
++
++static void
++impl_FileServer_File_ChangeDirectoryTo(impl_POA_FileServer_File * servant,
++ CORBA_Environment * ev);
++
++static CORBA_long
++impl_FileServer_File_Seek(impl_POA_FileServer_File * servant,
++ CORBA_long Offset,
++ FileServer_File_SeekDirection Direction,
++ CORBA_Environment * ev);
++
++static FileServer_File
++impl_FileServer_File_Duplicate(impl_POA_FileServer_File * servant,
++ CORBA_Environment * ev);
++
++static void impl_FileServer_FileSystem__destroy(impl_POA_FileServer_FileSystem
++ * servant,
++
++ CORBA_Environment * ev);
++static FileServer_File
++impl_FileServer_FileSystem_Open(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * Filename, CORBA_long openFlags,
++ CORBA_short mode, CORBA_Environment * ev);
++
++static FileServer_File
++impl_FileServer_FileSystem_Create(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * Filename,
++ CORBA_short mode, CORBA_Environment * ev);
++
++static void
++impl_FileServer_FileSystem_Link(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * FromPath,
++ CORBA_char * ToPath, CORBA_Environment * ev);
++
++static void
++impl_FileServer_FileSystem_Unlink(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * Filename,
++
++ CORBA_Environment * ev);
++
++static void
++impl_FileServer_FileSystem_Rename(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * OldName,
++ CORBA_char * NewName,
++
++ CORBA_Environment * ev);
++
++static void
++impl_FileServer_FileSystem_ReadLink(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * Linkname,
++ CORBA_char ** LinkValue,
++ CORBA_Environment * ev);
++
++static FileServer_FileStatus
++impl_FileServer_FileSystem_GetStatus(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * Filename,
++ CORBA_Environment * ev);
++
++static FileServer_FileStatus
++impl_FileServer_FileSystem_GetLinkStatus(impl_POA_FileServer_FileSystem *
++ servant, CORBA_char * Filename,
++ CORBA_Environment * ev);
++
++static void
++impl_FileServer_FileSystem_MakeDirectory(impl_POA_FileServer_FileSystem *
++ servant, CORBA_char * PathName,
++ CORBA_short mode,
++ CORBA_Environment * ev);
++
++static void
++impl_FileServer_FileSystem_RemoveDirectory(impl_POA_FileServer_FileSystem *
++ servant, CORBA_char * PathName,
++ CORBA_Environment * ev);
++
++static CORBA_char
++ *impl_FileServer_FileSystem_ChangeDirectory(impl_POA_FileServer_FileSystem
++ * servant,
++ CORBA_char * PathName,
++ CORBA_Environment * ev);
++
++static void
++impl_FileServer_FileSystem_MakeNode(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * FileName,
++ CORBA_short Mode,
++ CORBA_long DeviceNum,
++
++ CORBA_Environment * ev);
++
++static void
++impl_FileServer_FileSystem_Mount(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * DeviceFile,
++ CORBA_char * Location,
++ CORBA_char * FSType,
++ CORBA_long Flags, CORBA_Environment * ev);
++
++static void
++impl_FileServer_FileSystem_Unmount(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * Filename,
++
++ CORBA_Environment * ev);
++
++/*** epv structures ***/
++static PortableServer_ServantBase__epv impl_Errors_base_epv = {
++ NULL, /* _private data */
++ NULL, /* finalize routine */
++ NULL, /* default_POA routine */
++};
++static POA_Errors__epv impl_Errors_epv = {
++ NULL, /* _private */
++
++};
++
++static PortableServer_ServantBase__epv impl_FileServer_File_base_epv = {
++ NULL, /* _private data */
++ NULL, /* finalize routine */
++ NULL, /* default_POA routine */
++};
++static POA_FileServer_File__epv impl_FileServer_File_epv = {
++ NULL, /* _private */
++ (gpointer) & impl_FileServer_File_Read,
++
++ (gpointer) & impl_FileServer_File_Write,
++
++ (gpointer) & impl_FileServer_File_Close,
++
++ (gpointer) & impl_FileServer_File_FileControl,
++
++ (gpointer) & impl_FileServer_File_GetStatus,
++
++ (gpointer) & impl_FileServer_File_ChangeDirectoryTo,
++
++ (gpointer) & impl_FileServer_File_Seek,
++
++ (gpointer) & impl_FileServer_File_Duplicate,
++
++};
++static POA_Errors__epv impl_FileServer_File_Errors_epv = {
++ NULL, /* _private */
++};
++static PortableServer_ServantBase__epv impl_FileServer_FileSystem_base_epv = {
++ NULL, /* _private data */
++ NULL, /* finalize routine */
++ NULL, /* default_POA routine */
++};
++static POA_FileServer_FileSystem__epv impl_FileServer_FileSystem_epv = {
++ NULL, /* _private */
++ (gpointer) & impl_FileServer_FileSystem_Open,
++
++ (gpointer) & impl_FileServer_FileSystem_Create,
++
++ (gpointer) & impl_FileServer_FileSystem_Link,
++
++ (gpointer) & impl_FileServer_FileSystem_Unlink,
++
++ (gpointer) & impl_FileServer_FileSystem_Rename,
++
++ (gpointer) & impl_FileServer_FileSystem_ReadLink,
++
++ (gpointer) & impl_FileServer_FileSystem_GetStatus,
++
++ (gpointer) & impl_FileServer_FileSystem_GetLinkStatus,
++
++ (gpointer) & impl_FileServer_FileSystem_MakeDirectory,
++
++ (gpointer) & impl_FileServer_FileSystem_RemoveDirectory,
++
++ (gpointer) & impl_FileServer_FileSystem_ChangeDirectory,
++
++ (gpointer) & impl_FileServer_FileSystem_MakeNode,
++
++ (gpointer) & impl_FileServer_FileSystem_Mount,
++
++ (gpointer) & impl_FileServer_FileSystem_Unmount,
++
++};
++static POA_Errors__epv impl_FileServer_FileSystem_Errors_epv = {
++ NULL, /* _private */
++};
++
++/*** vepv structures ***/
++static POA_Errors__vepv impl_Errors_vepv = {
++ &impl_Errors_base_epv,
++ &impl_Errors_epv,
++};
++
++static POA_FileServer_File__vepv impl_FileServer_File_vepv = {
++ &impl_FileServer_File_base_epv,
++ &impl_FileServer_File_Errors_epv,
++ &impl_FileServer_File_epv,
++};
++static POA_FileServer_FileSystem__vepv impl_FileServer_FileSystem_vepv = {
++ &impl_FileServer_FileSystem_base_epv,
++ &impl_FileServer_FileSystem_Errors_epv,
++ &impl_FileServer_FileSystem_epv,
++};
++
++/*** Stub implementations ***/
++static Errors
++impl_Errors__create(PortableServer_POA poa, CORBA_Environment * ev)
++{
++ Errors retval;
++ impl_POA_Errors *newservant;
++ PortableServer_ObjectId *objid;
++
++ newservant = g_new0(impl_POA_Errors, 1);
++ newservant->servant.vepv = &impl_Errors_vepv;
++ newservant->poa = poa;
++ POA_Errors__init((PortableServer_Servant) newservant, ev);
++ objid = PortableServer_POA_activate_object(poa, newservant, ev);
++ CORBA_free(objid);
++ retval = PortableServer_POA_servant_to_reference(poa, newservant, ev);
++
++ return retval;
++}
++
++static void
++impl_Errors__destroy(impl_POA_Errors * servant, CORBA_Environment * ev)
++{
++ PortableServer_ObjectId *objid;
++
++ objid = PortableServer_POA_servant_to_id(servant->poa, servant, ev);
++ PortableServer_POA_deactivate_object(servant->poa, objid, ev);
++ CORBA_free(objid);
++
++ POA_Errors__fini((PortableServer_Servant) servant, ev);
++ g_free(servant);
++}
++
++static FileServer_File
++impl_FileServer_File__create(PortableServer_POA poa, CORBA_Environment * ev)
++{
++ FileServer_File retval;
++ impl_POA_FileServer_File *newservant;
++ PortableServer_ObjectId *objid;
++
++ newservant = g_new0(impl_POA_FileServer_File, 1);
++ newservant->servant.vepv = &impl_FileServer_File_vepv;
++ newservant->poa = poa;
++ newservant->fd = -1;
++
++ POA_FileServer_File__init((PortableServer_Servant) newservant, ev);
++ objid = PortableServer_POA_activate_object(poa, newservant, ev);
++ CORBA_free(objid);
++ retval = PortableServer_POA_servant_to_reference(poa, newservant, ev);
++
++ return retval;
++}
++
++static void
++impl_FileServer_File__destroy(impl_POA_FileServer_File * servant,
++ CORBA_Environment * ev)
++{
++ PortableServer_ObjectId *objid;
++
++ objid = PortableServer_POA_servant_to_id(servant->poa, servant, ev);
++ PortableServer_POA_deactivate_object(servant->poa, objid, ev);
++ CORBA_free(objid);
++
++ POA_FileServer_File__fini((PortableServer_Servant) servant, ev);
++ g_free(servant);
++}
++
++static void
++impl_FileServer_File_Read(impl_POA_FileServer_File * servant,
++ CORBA_long count,
++ FileServer_buffer ** buf, CORBA_Environment * ev)
++{
++ size_t num_read;
++
++ *buf = FileServer_buffer__alloc();
++ (*buf)->_maximum = count;
++ (*buf)->_buffer = CORBA_octet_allocbuf(count);
++ (*buf)->_length = 0;
++
++ printf("File->Read(%d, char *buf)\n", count);
++
++ if (servant->fd == -1) /* Trying to read from a closed file */
++ {
++ printf("File->Read ERROR : fd == -1\n");
++ set_exception(EBADF, ev);
++ return;
++ }
++
++ num_read = read(servant->fd, (*buf)->_buffer, count);
++ if (num_read == -1)
++ {
++ printf("File->Read ERROR : %d\n", errno);
++ set_exception(errno, ev);
++ return;
++ }
++
++ (*buf)->_length = num_read;
++}
++
++static void
++impl_FileServer_File_Write(impl_POA_FileServer_File * servant,
++ FileServer_buffer * buf, CORBA_Environment * ev)
++{
++ printf("UNIMP: FileServer::File::Write called and unimplemented\n");
++}
++
++static void
++impl_FileServer_File_Close(impl_POA_FileServer_File * servant,
++ CORBA_Environment * ev)
++{
++ printf("File->Close()\n");
++
++ if (servant->fd == -1) /* This should never happen !?! */
++ {
++ printf("File->Close ERROR : fd == -1\n");
++ set_exception(EBADF, ev);
++ return;
++ }
++
++ close(servant->fd);
++ servant->fd = 0;
++ impl_FileServer_File__destroy(servant, ev);
++}
++
++static CORBA_long
++impl_FileServer_File_FileControl(impl_POA_FileServer_File * servant,
++ CORBA_long command, CORBA_Environment * ev)
++{
++ CORBA_long retval;
++
++ if (servant->fd == -1)
++ {
++ printf("File->FileControl ERROR : fd == -1\n");
++ set_exception(EBADF, ev);
++ return -1;
++ }
++
++ retval = fcntl(servant->fd, command, 0); /* FIXME arg? */
++ if (retval == -1)
++ {
++ printf("File->FileControl ERROR : %d\n", errno);
++ set_exception(errno, ev);
++ }
++
++ return retval;
++}
++
++
++FileServer_FileStatus
++stat2FileStatus(struct stat buf)
++{
++ FileServer_FileStatus retval;
++
++ retval.DeviceNum = buf.st_dev;
++ retval.InodeNum = buf.st_ino;
++ retval.Mode = buf.st_mode;
++ retval.NumLinks = buf.st_nlink;
++ retval.UserID = buf.st_uid;
++ retval.GroupID = buf.st_gid;
++ retval.DeviceType = buf.st_rdev;
++ retval.Size = buf.st_size;
++ retval.BlockSize = buf.st_blksize;
++ retval.NumBlocks = buf.st_blocks;
++ retval.AccessTime = buf.st_atime;
++ retval.ModifiedTime = buf.st_mtime;
++ retval.ChangeTime = buf.st_ctime;
++
++ return retval;
++}
++
++
++static FileServer_FileStatus
++impl_FileServer_File_GetStatus(impl_POA_FileServer_File * servant,
++ CORBA_Environment * ev)
++{
++ FileServer_FileStatus retval;
++
++ struct stat buf;
++ int res;
++
++ if (servant->fd == -1)
++ {
++ printf("File->GetStatus ERROR : fd == -1\n");
++ set_exception(EBADF, ev);
++ return retval;
++ }
++
++ res = fstat(servant->fd, &buf);
++ if (res == -1)
++ {
++ printf("File->GetStatus ERROR : %d\n", errno);
++ set_exception(errno, ev);
++ return retval;
++ }
++
++ retval = stat2FileStatus(buf);
++
++ return retval;
++}
++
++static void
++impl_FileServer_File_ChangeDirectoryTo(impl_POA_FileServer_File * servant,
++ CORBA_Environment * ev)
++{
++ printf("UNIMP: impl_FileServer_File_ChangeDirectoryTo\n");
++}
++
++static CORBA_long
++impl_FileServer_File_Seek(impl_POA_FileServer_File * servant,
++ CORBA_long Offset,
++ FileServer_File_SeekDirection Direction,
++ CORBA_Environment * ev)
++{
++ CORBA_long retval = -1;
++ int whence;
++
++ if (servant->fd == -1)
++ {
++ printf("File->Seek ERROR : fd == -1\n");
++ set_exception(EBADF, ev);
++ return retval;
++ }
++
++ switch (Direction)
++ {
++ case FileServer_File_FromStart :
++ whence = SEEK_SET;
++ break;
++ case FileServer_File_FromCurrent :
++ whence = SEEK_CUR;
++ break;
++ case FileServer_File_FromEnd :
++ whence = SEEK_END;
++ break;
++ default :
++ set_exception(EINVAL, ev);
++ return retval;
++ }
++
++ retval = lseek(servant->fd, Offset, whence);
++ if (retval == -1)
++ {
++ printf("File->Seek ERROR : %d\n", errno);
++ set_exception(errno, ev);
++ }
++
++ return retval;
++}
++
++static FileServer_File
++impl_FileServer_File_Duplicate(impl_POA_FileServer_File * servant,
++ CORBA_Environment * ev)
++{
++ FileServer_File retval;
++ printf("UNIMP: impl_FileServer_File_Duplicate\n");
++ return retval;
++}
++
++static FileServer_FileSystem
++impl_FileServer_FileSystem__create(PortableServer_POA poa,
++ CORBA_Environment * ev)
++{
++ FileServer_FileSystem retval;
++ impl_POA_FileServer_FileSystem *newservant;
++ PortableServer_ObjectId *objid;
++
++ newservant = g_new0(impl_POA_FileServer_FileSystem, 1);
++ newservant->servant.vepv = &impl_FileServer_FileSystem_vepv;
++ newservant->poa = poa;
++ POA_FileServer_FileSystem__init((PortableServer_Servant) newservant, ev);
++ objid = PortableServer_POA_activate_object(poa, newservant, ev);
++ CORBA_free(objid);
++ retval = PortableServer_POA_servant_to_reference(poa, newservant, ev);
++
++ return retval;
++}
++
++static void
++impl_FileServer_FileSystem__destroy(impl_POA_FileServer_FileSystem * servant,
++ CORBA_Environment * ev)
++{
++ PortableServer_ObjectId *objid;
++
++ objid = PortableServer_POA_servant_to_id(servant->poa, servant, ev);
++ PortableServer_POA_deactivate_object(servant->poa, objid, ev);
++ CORBA_free(objid);
++
++ POA_FileServer_FileSystem__fini((PortableServer_Servant) servant, ev);
++ g_free(servant);
++}
++
++static FileServer_File
++impl_FileServer_FileSystem_Open(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * Filename,
++ CORBA_long openFlags,
++ CORBA_short mode, CORBA_Environment * ev)
++{
++ FileServer_File retval = CORBA_OBJECT_NIL;
++
++ impl_POA_FileServer_File *file;
++
++ printf("FileSystem->Open(%s,%x)\n", Filename, openFlags);
++
++ retval = impl_FileServer_File__create(servant->poa, ev);
++
++ file = PortableServer_POA_reference_to_servant( servant->poa, retval, ev );
++ file->fd = open(Filename, openFlags, mode);
++
++ if (file->fd == -1) {
++ printf("FileSystem->Open ERROR : %d\n", errno);
++ set_exception(errno, ev);
++ }
++
++ return retval;
++}
++
++static FileServer_File
++impl_FileServer_FileSystem_Create(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * Filename,
++ CORBA_short mode, CORBA_Environment * ev)
++{
++ FileServer_File retval = CORBA_OBJECT_NIL;
++
++ impl_POA_FileServer_File *file;
++
++ printf("FileSystem->Create(%s,%x)\n", Filename, mode);
++
++ retval = impl_FileServer_File__create(servant->poa, ev);
++
++ file = PortableServer_POA_reference_to_servant( servant->poa, retval, ev );
++ file->fd = creat(Filename, mode);
++
++ if (file->fd == -1) {
++ printf("FileSystem->Create ERROR : %d\n", errno);
++ set_exception(errno, ev);
++ }
++
++ return retval;
++}
++
++static void
++impl_FileServer_FileSystem_Link(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * FromPath,
++ CORBA_char * ToPath, CORBA_Environment * ev)
++{
++ printf("UNIMP: impl_FileServer_FileSystem_Link\n");
++}
++
++static void
++impl_FileServer_FileSystem_Unlink(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * Filename,
++ CORBA_Environment * ev)
++{
++ printf("UNIMP: impl_FileServer_FileSystem_Unlink\n");
++}
++
++static void
++impl_FileServer_FileSystem_Rename(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * OldName,
++ CORBA_char * NewName,
++ CORBA_Environment * ev)
++{
++ printf("UNIMP: impl_FileServer_FileSystem_Rename\n");
++}
++
++static void
++impl_FileServer_FileSystem_ReadLink(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * Linkname,
++ CORBA_char ** LinkValue,
++ CORBA_Environment * ev)
++{
++ char tmp[PATH_MAX + 1];
++ int res, len;
++
++ printf("FileSystem->ReadLink(%s, value)\n", Linkname);
++
++ res = readlink(Linkname, tmp, PATH_MAX);
++ if (res == -1)
++ {
++ set_exception(errno, ev);
++ return;
++ }
++
++ len = strlen(tmp);
++ *LinkValue = (char *)malloc(len * sizeof(char));
++ memcpy(*LinkValue, tmp, len);
++ (*LinkValue)[len] = '\0';
++}
++
++static FileServer_FileStatus
++impl_FileServer_FileSystem_GetStatus(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * Filename,
++ CORBA_Environment * ev)
++{
++ FileServer_FileStatus retval;
++ struct stat buf;
++ int res;
++
++ printf("FileSystem->GetStatus(%s)\n", Filename);
++
++ res = stat(Filename, &buf);
++
++ if (res == -1)
++ {
++ printf("FileSystem->GetStatus(%s)\n", Filename);
++ set_exception(errno, ev);
++ return retval;
++ }
++
++ retval = stat2FileStatus(buf);
++
++ return retval;
++}
++
++static FileServer_FileStatus
++impl_FileServer_FileSystem_GetLinkStatus(impl_POA_FileServer_FileSystem *
++ servant, CORBA_char * Filename,
++ CORBA_Environment * ev)
++{
++ FileServer_FileStatus retval;
++ struct stat buf;
++ int res;
++
++ printf("FileSystem->GetLinkStatus(%s)\n", Filename);
++
++ res = lstat(Filename, &buf);
++
++ if (res == -1)
++ {
++ printf("FileSystem->GetLinkStatus(%s)\n", Filename);
++ set_exception(errno, ev);
++ return retval;
++ }
++
++ retval = stat2FileStatus(buf);
++
++ return retval;
++}
++
++static void
++impl_FileServer_FileSystem_MakeDirectory(impl_POA_FileServer_FileSystem *
++ servant, CORBA_char * PathName,
++ CORBA_short mode,
++ CORBA_Environment * ev)
++{
++ printf("UNIMP: impl_FileServer_FileSystem_MakeDirectory\n");
++}
++
++static void
++impl_FileServer_FileSystem_RemoveDirectory(impl_POA_FileServer_FileSystem *
++ servant, CORBA_char * PathName,
++ CORBA_Environment * ev)
++{
++ printf("UNIMP: impl_FileServer_FileSystem_RemoveDirectory\n");
++}
++
++static CORBA_char *
++impl_FileServer_FileSystem_ChangeDirectory(impl_POA_FileServer_FileSystem *
++ servant, CORBA_char * PathName,
++ CORBA_Environment * ev)
++{
++ CORBA_char *retval;
++ printf("UNIMP: impl_FileServer_FileSystem_ChangeDirectory\n");
++ return retval;
++}
++
++static void
++impl_FileServer_FileSystem_MakeNode(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * FileName,
++ CORBA_short Mode,
++ CORBA_long DeviceNum,
++ CORBA_Environment * ev)
++{
++ printf("UNIMP: impl_FileServer_FileSystem_MakeNode\n");
++}
++
++static void
++impl_FileServer_FileSystem_Mount(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * DeviceFile,
++ CORBA_char * Location,
++ CORBA_char * FSType,
++ CORBA_long Flags, CORBA_Environment * ev)
++{
++ printf("UNIMP: impl_FileServer_FileSystem_Mount: ARE YOU CRAZY!?!?\n");
++}
++
++static void
++impl_FileServer_FileSystem_Unmount(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * Filename,
++ CORBA_Environment * ev)
++{
++ printf("UNIMP: impl_FileServer_FileSystem_Unmount: Ha ha ha funny guy!\n");
++}
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server/Makefile linux-2.4.1-korbit/net/korbit/modules/FileServer/server/Makefile
+--- linux-2.4.1/net/korbit/modules/FileServer/server/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server/Makefile Thu Feb 1 11:47:08 2001
+@@ -0,0 +1,20 @@
++#
++# Makefile for KORBit / FileServer
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++O_TARGET := corba-fileserver-server.o
++
++obj-y := FileServer-common.o FileServer-skels.o FileServer-server.o
++obj-m := $(O_TARGET)
++
++include ../../Makefile.module
++
++FileServer-server.c: FileServer.h FileServer-common.c FileServer-skels.c FileServer-skelimpl.c
++
++FileServer.h FileServer-skels.c FileServer-common.c: ../FileServer.idl
++ $(ORBIT_IDL) ../FileServer.idl
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server/Makefile.user linux-2.4.1-korbit/net/korbit/modules/FileServer/server/Makefile.user
+--- linux-2.4.1/net/korbit/modules/FileServer/server/Makefile.user Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server/Makefile.user Thu Feb 1 11:47:08 2001
+@@ -0,0 +1,32 @@
++#
++# Makefile for KORBit
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++PROJECT = FileServer
++
++CFLAGS = -Wall `orbit-config --cflags server` -I../../..
++LDFLAGS = `orbit-config --libs server`
++OBJS = $(PROJECT)-common.o $(PROJECT)-skels.o $(PROJECT)-server.o
++ORBIT-IDL = orbit-idl
++
++$(PROJECT)-server: $(OBJS)
++ gcc -o $(PROJECT)-server $(OBJS) $(LDFLAGS)
++
++$(PROJECT)-server.c: $(PROJECT).h $(PROJECT)-skelimpl.c
++
++$(PROJECT).h $(PROJECT)-common.c $(PROJECT)-skels.c $(PROJECT)-skelimpl.c: ../$(PROJECT).idl
++ $(ORBIT-IDL) --nostubs ../$(PROJECT).idl
++
++clean:
++ rm -f $(OBJS) $(PROJECT)-server
++
++realclean: clean
++ rm -f $(PROJECT).h
++ rm -f $(PROJECT)-common.c
++ rm -f $(PROJECT)-skels.c
++ rm -f *~
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server/README linux-2.4.1-korbit/net/korbit/modules/FileServer/server/README
+--- linux-2.4.1/net/korbit/modules/FileServer/server/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server/README Thu Feb 1 11:47:08 2001
+@@ -0,0 +1,4 @@
++Kernel side implementation of the file server functionality.
++
++ORB: kORBit
++Status: Mostly unimplemented.
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server-user/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/FileServer/server-user/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/CVS/Entries Thu Feb 1 11:47:08 2001
+@@ -0,0 +1,4 @@
++/FileServer-server.c/1.1/Thu Feb 1 09:47:08 2001//
++/Makefile/1.1/Thu Feb 1 09:47:08 2001//
++/README/1.1/Thu Feb 1 09:47:08 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server-user/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/FileServer/server-user/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/CVS/Repository Thu Feb 1 11:47:08 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/FileServer/server-user
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server-user/CVS/Root linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/CVS/Root
+--- linux-2.4.1/net/korbit/modules/FileServer/server-user/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/CVS/Root Thu Feb 1 11:47:08 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server-user/FileServer-server.c linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/FileServer-server.c
+--- linux-2.4.1/net/korbit/modules/FileServer/server-user/FileServer-server.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/FileServer-server.c Thu Feb 1 11:47:08 2001
+@@ -0,0 +1,234 @@
++#include <OB/CORBA.h>
++#include <OB/Util.h>
++#include <OB/CosNaming.h>
++#include <stdlib.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#include <errno.h>
++
++#include "FileServer_skel.h"
++
++static void ThrowErr() {
++ switch (errno) {
++ case 0: return;
++ case EISDIR:
++ throw Errors::IsDirectory();
++ case EPERM:
++ throw Errors::PermissionDenied();
++ case EEXIST:
++ throw Errors::FileExists();
++ case ENOENT:
++ throw Errors::FileNotFound();
++ case ENOTDIR:
++ throw Errors::IsNotDirectory();
++ case EROFS:
++ case ETXTBSY:
++ throw Errors::ReadOnlyFile();
++ case ELOOP:
++ throw Errors::RecursiveSymlink();
++ case EBUSY:
++ throw Errors::IsBusy();
++ default:
++ throw Errors::OtherError();
++ }
++}
++
++
++class FileServer_File_impl : public FileServer_File_skel {
++ int FD;
++ public:
++ FileServer_File_impl(int fd) { FD = fd; }
++
++ virtual void Read(CORBA_Long count, FileServer_buffer*& buf) {
++ errno = 0;
++ cout << "Read\n";
++ buf = new FileServer_buffer();
++ ThrowErr();
++ }
++
++ virtual void Write(const FileServer_buffer& buf) {
++ errno = 0;
++ cout << "Write\n";
++ ThrowErr();
++ }
++
++ virtual void Close() {
++ errno = 0;
++ close(FD);
++ cout << "Close()\n";
++ ThrowErr();
++ }
++
++ virtual CORBA_Long FileControl(CORBA_Long command) {
++ errno = 0;
++ cout << "filecontrol\n";
++ ThrowErr();
++ return 0;
++ }
++
++ virtual FileServer_FileStatus GetStatus() {
++ errno = 0;
++ cout << "stat\n";
++ FileServer_FileStatus Stat;
++ ThrowErr();
++ return Stat;
++ }
++
++ virtual void ChangeDirectoryTo() {
++ errno = 0;
++ cout << "ChangeDirectoryTo()\n";
++ ThrowErr();
++ }
++
++ virtual CORBA_Long Seek(CORBA_Long Offset, SeekDirection Direction) {
++ errno = 0;
++ cout << "Seek(" << Offset << ")\n";
++ ThrowErr();
++ return -1;
++ }
++
++ virtual FileServer_File_ptr Duplicate() {
++ errno = 0;
++ cout << "Duplicate!\n";
++ ThrowErr();
++ return 0;
++ }
++};
++
++
++class FileServer_impl : public FileServer_FileSystem_skel {
++ public :
++ virtual FileServer_File_ptr Open(const char* Filename,
++ CORBA_Long openFlags,
++ CORBA_Short mode) {
++ errno = 0;
++ int fd = open(Filename, openFlags, mode);
++ if (fd != -1) return new FileServer_File_impl(fd);
++ cout << "open\n";
++ ThrowErr();
++ return 0;
++ }
++
++ virtual FileServer_File_ptr Create(const char* Filename,
++ CORBA_Short mode) {
++ errno = 0;
++ cout << "create\n";
++ ThrowErr();
++ return 0;
++ }
++
++
++ virtual void Link(const char* FromPath,
++ const char* ToPath) {
++ errno = 0;
++ cout << "link\n";
++ ThrowErr();
++ }
++
++ virtual void Unlink(const char* Filename) {
++ errno = 0;
++ cout << "unlink\n";
++ ThrowErr();
++ }
++
++ virtual void Rename(const char* OldName,
++ const char* NewName) {
++ errno = 0;
++ cout << "rename\n";
++ ThrowErr();
++ }
++
++
++ virtual void ReadLink(const char* Linkname,
++ char*& LinkValue) {
++ errno = 0;
++ cout << "readlink\n";
++ ThrowErr();
++ }
++
++ virtual FileServer_FileStatus GetStatus(const char* Filename) {
++ errno = 0;
++ cout << "stat\n";
++ FileServer_FileStatus Stat;
++ ThrowErr();
++ return Stat;
++ }
++
++
++ virtual FileServer_FileStatus GetLinkStatus(const char* Filename) {
++ errno = 0;
++ cout << "lstat\n";
++ FileServer_FileStatus Stat;
++ ThrowErr();
++ return Stat;
++ }
++
++
++ virtual void MakeDirectory(const char* PathName,
++ CORBA_Short mode) {
++ errno = 0;
++ cout << "mkdir\n";
++ ThrowErr();
++ }
++
++ virtual void RemoveDirectory(const char* PathName) {
++ errno = 0;
++ cout << "rmdir\n";
++ ThrowErr();
++ }
++
++
++ virtual char* ChangeDirectory(const char* PathName) {
++ errno = 0;
++ cout << "chdir\n";
++ ThrowErr();
++ return CORBA_string_dup("hello");
++ }
++
++ virtual void MakeNode(const char* FileName,
++ CORBA_Short Mode,
++ CORBA_Long DeviceNum) {
++ errno = 0;
++ cout << "mknod\n";
++ ThrowErr();
++ }
++
++
++ virtual void Mount(const char* DeviceFile,
++ const char* Location,
++ const char* FSType,
++ CORBA_Long Flags) {
++ errno = 0;
++ cout << "Mount\n";
++ ThrowErr();
++ }
++
++ virtual void Unmount(const char* Filename) {
++ errno = 0;
++ cout << "Unmount\n";
++ ThrowErr();
++ }
++};
++
++
++int main(int argc, char* argv[]) {
++ cout << "FileServer UserSpace Server initializing" << endl;
++
++ try {
++ CORBA_ORB_var orb = CORBA_ORB_init(argc, argv);
++ CORBA_BOA_var boa = orb->BOA_init(argc, argv);
++
++ FileServer_FileSystem_var FS = new FileServer_impl();
++
++ cout << orb->object_to_string(FS) << endl;
++
++ //
++ // Run implementation
++ //
++ boa -> impl_is_ready(CORBA_ImplementationDef::_nil());
++ } catch(CORBA_SystemException& ex) {
++ OBPrintException(ex);
++ return 1;
++ }
++}
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server-user/Makefile linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/Makefile
+--- linux-2.4.1/net/korbit/modules/FileServer/server-user/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/Makefile Thu Feb 1 11:47:08 2001
+@@ -0,0 +1,29 @@
++CC = CC -mt -pta
++OBDIR = /home/class/cs423/local
++IDL = $(OBDIR)/bin/idl
++CPPFLAGS = -I. -I$(OBDIR)/include
++LDFLAGS = -L$(OBDIR)/lib
++LIBS = -lCosNaming -lOB -lJTC -lsocket -lnsl -lposix4
++
++all: FileServer
++
++FileServer: FileServer.o FileServer-server.o FileServer_skel.o
++ $(CC) $(LDFLAGS) -o FileServer FileServer-server.o FileServer.o FileServer_skel.o $(LIBS)
++
++FileServer.h FileServer.cpp: ../FileServer.idl
++ rm -f FileServer.cpp FileServer.h
++ rm -f FileServer_skel.h FileServer_skel.cpp
++ $(IDL) ../FileServer.idl
++
++FileServer_skel.cpp FileServer_skel.h: FileServer.cpp
++
++%.o: %.cpp
++ $(CC) $(CPPFLAGS) -c $<
++
++clean:
++ rm -f FileServer *.o *~
++
++realclean: clean
++ rm -f FileServer.h FileServer.cpp
++ rm -f FileServer_skel.h FileServer_skel.cpp
++ rm -rf SunWS_cache
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server-user/README linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/README
+--- linux-2.4.1/net/korbit/modules/FileServer/server-user/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/README Thu Feb 1 11:47:08 2001
+@@ -0,0 +1 @@
++This is a user space implementation of the FileServer interface.
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/wrapper/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/FileServer/wrapper/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/CVS/Entries Thu Feb 1 11:47:09 2001
+@@ -0,0 +1,6 @@
++/FileServer_wrapper.cpp/1.2/Thu Feb 1 09:47:09 2001//
++/FileServer_wrapper.h/1.2/Thu Feb 1 09:47:09 2001//
++/Makefile/1.1/Thu Feb 1 09:47:09 2001//
++/README/1.1/Thu Feb 1 09:47:09 2001//
++/test.c/1.2/Thu Feb 1 09:47:09 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/wrapper/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/FileServer/wrapper/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/CVS/Repository Thu Feb 1 11:47:09 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/FileServer/wrapper
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/wrapper/CVS/Root linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/CVS/Root
+--- linux-2.4.1/net/korbit/modules/FileServer/wrapper/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/CVS/Root Thu Feb 1 11:47:09 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/wrapper/FileServer_wrapper.cpp linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/FileServer_wrapper.cpp
+--- linux-2.4.1/net/korbit/modules/FileServer/wrapper/FileServer_wrapper.cpp Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/FileServer_wrapper.cpp Thu Feb 1 11:47:09 2001
+@@ -0,0 +1,135 @@
++/*
++ * FileServer_wrapper.cpp
++ *
++ * We want to intercept *all* file I/O, so that once the LD_PRELOAD
++ * variable is set, everything you see is on the remote side.
++ *
++ * Needed environment variables:
++ * LD_PRELOAD - duh (what's the lib name?)
++ * KORBIT_IOR - IOR of the file servin' ORB to connect to.
++ *
++ */
++
++#include <stdio.h>
++#include <dlfcn.h>
++#include <stdarg.h>
++#include <stdlib.h>
++#include <string.h>
++#include <dirent.h>
++#include <errno.h>
++
++#include "OB/CORBA.h"
++//#include "OB/Util.h"
++//#include "OB/CosNaming.h"
++
++#include "FileServer.h"
++#include "FileServer_wrapper.h"
++
++#define DEBUG
++
++#ifdef DEBUG
++#define debugOut(X) cerr << X << flush;
++#else
++#define debugOut(X)
++#endif
++
++
++FileSystemState::FileSystemState() {
++ char *argv[] = { (char*)"/usr/bin/mkdir", 0 };
++ int argc = 1;
++
++ debugOut ("FS_wrapper: InitializeOrb(): start.\n");
++
++ /* Set 'PerformingInitialization = true'? */
++
++ orb = CORBA_ORB_init(argc, argv);
++ if (CORBA_is_nil(orb)) {
++ cerr << "Error initializing ORB!\n";
++ exit(1);
++ }
++ debugOut ("\tORB initialized successfully.\n");
++
++ const char *env = getenv("KORBIT_IOR");
++ if (!env) {
++ // This should check /proc/corba/FileServer-server also!
++ cerr << "InitializeOrb Error: KORBIT_IOR not found in environment!\n";
++ exit(1);
++ }
++
++ cout << "IOR = " << env << endl;
++
++ // WHY DO I HANG IN string_to_object??
++ CORBA_Object_var obj = orb->string_to_object(env);
++ debugOut("\tORB initialized successfully.\n");
++
++ if (CORBA_is_nil(obj)) {
++ cerr << "InitializeOrb Error: IOR is invalid: " << env << endl;
++ exit (1);
++ }
++
++ debugOut ("\tORB initialized successfully.\n");
++ try {
++ FS = FileServer_FileSystem::_narrow(obj);
++ } catch (...) {
++ cerr << "InitializeOrb Error: Got an exception from _narrow().\n";
++ exit (1);
++ }
++
++ /* Initialize my data structure 'o file descriptors. */
++
++ // Set up mapping for stdin, stdout, stderr. Set up a new fd, #4 for
++ // console/debug output
++
++ // stderr can go to console for now.
++
++ debugOut ("FS_wrapper: InitializeOrb(): finished successfully.\n");
++} /* End InitializeOrb(). */
++
++
++FileSystemState::~FileSystemState() (void) {
++} /* End CleanupOrb(). */
++
++
++void HandleException(CORBA_UserException &Exception) {
++ try {
++ throw Exception; // get the type back...
++ } catch (Errors::FileExists &) {
++ errno = EEXIST;
++ } catch (Errors::PermissionDenied &) {
++ errno = EACCES;
++ } catch (Errors::FileNotFound &) {
++ errno = ENOENT;
++ } catch (Errors::IsNotDirectory &) {
++ errno = ENOTDIR;
++ } catch (Errors::ReadOnlyFile &) {
++ errno = EROFS;
++ } catch (Errors::RecursiveSymlink &) {
++ errno = ELOOP;
++ } catch (Errors::OtherError &) {
++ errno = EIO; /* I/O error */
++ } catch (CORBA_UserException &Exception) {
++ cerr << "unknown exception occurred! \n";
++ }
++}
++
++//int open(const char *path, int oflag, mode_t mode) {
++
++
++// return -1;
++//}
++
++int mkdir(const char *pathname, mode_t mode) {
++ debugOut("FS_wrapper: mkdir(" << pathname << "): start.\n");
++
++ try {
++ FileSystemState::get().getFS()->MakeDirectory(pathname, mode);
++ } catch (CORBA_UserException &ex) {
++ HandleException(ex);
++ return -1;
++ }
++
++ // Success!
++ debugOut("FS wrapper: mkdir(): finish successfully.\n");
++ return 0;
++} // End mkdir()
++
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/wrapper/FileServer_wrapper.h linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/FileServer_wrapper.h
+--- linux-2.4.1/net/korbit/modules/FileServer/wrapper/FileServer_wrapper.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/FileServer_wrapper.h Thu Feb 1 11:47:09 2001
+@@ -0,0 +1,81 @@
++// The KORBit FileServer wrapper, which is a shared library that gets
++// hit with the LD_PRELOAD action, so as to redirect all FS calls
++// out the CORBA hole.
++//
++// Note that most of these functions have the side effect of modifying errno.
++//
++#ifndef FILESERVER_WRAPPER_H
++#define FILESERVER_WRAPPER_H
++
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++
++// This class contains all the global variables for this file. It is very
++// important that we use this mechanism so that our library is initialized as
++// early as possible, but no earlier. In particular this means that we cannot
++// be initialized before iostreams are, which we use for debugging. This scheme
++// the only way to that we are constructed and descructed on demand.
++//
++class FileSystemState {
++private:
++ FileSystemState(); // private ctor/dtor. The only way to get one of these is
++ ~FileSystemState(); // to call FileSystemState::get()
++
++ FileSystemState(const FileSystemState &); // do not implement
++ FileSystemState &operator=(const FileSystemState &); // do not implement
++
++
++ CORBA_ORB_var orb; // Global reference to the orb.
++ FileServer_FileSystem_var FS; // Global reference to FS object...
++public:
++ static FileSystemState &get() {
++ // Static objects like this are intialized the first time they are used, and
++ // destroyed when the project shuts down. This is exactly the semantics we
++ // want.
++ static FileSystemState FSS;
++ return FSS;
++ }
++
++ CORBA_ORB_var getORB() { return orb; }
++ FileServer_FileSystem_var getFS() { return FS; }
++};
++
++extern "C" {
++
++ //
++ // interface File
++ //
++ // pread, readv, pwrite, writev
++ int read(int FD, void *Buffer, size_t NumBytes);
++ int write(int FD, void *Buffer, size_t NumBytes);
++ int close(int FD);
++ // fcntl
++ // fstat
++ // fchdir
++ // seek
++ int dup(int FD);
++ int dup2(int FDFrom, int FDTo);
++
++ //
++ // interface FileSystem
++ //
++ // int open(const char *path, int oflag, mode_t mode);
++ int creat(const char *path, mode_t mode);
++
++// link
++// unlink
++// rename
++// readlink
++// stat
++// lstat
++ int mkdir(const char *Path, mode_t Mode);
++// rmdir
++ int chdir(const char *Path);
++}
++
++//
++// Local function prototypes.
++//
++
++#endif
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/wrapper/Makefile linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/Makefile
+--- linux-2.4.1/net/korbit/modules/FileServer/wrapper/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/Makefile Thu Feb 1 11:47:09 2001
+@@ -0,0 +1,29 @@
++CC = CC -mt -pta -g
++OBDIR = /home/class/cs423/local
++IDL = $(OBDIR)/bin/idl
++CPPFLAGS = -I. -I$(OBDIR)/include
++LDFLAGS = -L$(OBDIR)/lib -G -fPIC
++LIBS = -lCosNaming -lOB -lJTC -lsocket -lnsl -lposix4 -lCstd -lCrun
++
++all: libfswrapper.so
++
++libfswrapper.so: FileServer.o FileServer_wrapper.o
++ CC $(LDFLAGS) -o $@ FileServer_wrapper.o FileServer.o $(LIBS)
++
++FileServer.h FileServer.cpp: ../FileServer.idl
++ rm -f FileServer.cpp FileServer.h
++ rm -f FileServer_skel.h FileServer_skel.cpp
++ $(IDL) ../FileServer.idl
++
++FileServer_skel.cpp FileServer_skel.h: FileServer.cpp
++
++%.o: %.cpp
++ $(CC) $(CPPFLAGS) -c $<
++
++clean:
++ rm -f libfswrapper.so *.o *~
++
++realclean: clean
++ rm -f FileServer.h FileServer.cpp
++ rm -f FileServer_skel.h FileServer_skel.cpp
++ rm -rf SunWS_cache
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/wrapper/README linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/README
+--- linux-2.4.1/net/korbit/modules/FileServer/wrapper/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/README Thu Feb 1 11:47:09 2001
+@@ -0,0 +1,5 @@
++This is a library that may be LD_PRELOAD'd to forward filesystem related calls
++through the FileServer interface.
++
++ORB: ORBacus
++Status: Mostly not working
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/wrapper/test.c linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/test.c
+--- linux-2.4.1/net/korbit/modules/FileServer/wrapper/test.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/test.c Thu Feb 1 11:47:09 2001
+@@ -0,0 +1,15 @@
++#include <stdlib.h>
++#include <stdio.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++
++int main(void)
++{
++ if (mkdir("test", 0666) == -1)
++ {
++ perror ("mkdir failed because: ");
++ return (1);
++ }
++
++ return (0);
++}
+diff -urN linux-2.4.1/net/korbit/modules/Makefile linux-2.4.1-korbit/net/korbit/modules/Makefile
+--- linux-2.4.1/net/korbit/modules/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Makefile Thu Feb 1 11:46:58 2001
+@@ -0,0 +1,15 @@
++#
++# Makefile for KORBit/modules
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++
++subdir-$(CONFIG_CORBA_CONSOLE) += Console
++subdir-$(CONFIG_CORBA_ECHO) += Echo
++subdir-$(CONFIG_CORBA_FILESERVER) += FileServer
++subdir-$(CONFIG_CORBA_CORBAFS) += CorbaFS
++subdir-$(CONFIG_CORBA_CHARDEV) += CharDev
++
++include $(TOPDIR)/Rules.make
++
+diff -urN linux-2.4.1/net/korbit/modules/Makefile.module linux-2.4.1-korbit/net/korbit/modules/Makefile.module
+--- linux-2.4.1/net/korbit/modules/Makefile.module Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Makefile.module Thu Feb 1 11:46:58 2001
+@@ -0,0 +1,9 @@
++M_OBJS := $(O_TARGET)
++
++EXTRA_CFLAGS = -D__KORBIT__ -DHAVE_CONFIG_H -I. -I../../.. -I../../../include -I../../../kglib -nostdinc
++
++
++ORBIT_IDL = orbit-idl
++
++include $(TOPDIR)/Rules.make
++
+diff -urN linux-2.4.1/net/korbit/modules/README linux-2.4.1-korbit/net/korbit/modules/README
+--- linux-2.4.1/net/korbit/modules/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/README Thu Feb 1 11:46:58 2001
+@@ -0,0 +1,7 @@
++Modules included so far:
++
++CharDev : Implement Linux character device drivers
++Console : Print strings to the Linux console
++CorbaFS : Implement Linux filesystems through the VFS layer
++Echo : Testcase to test orb two-way communication
++FileServer: Access a filesystem through CORBA
+diff -urN linux-2.4.1/net/korbit/modules/UserFS/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/UserFS/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/UserFS/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/UserFS/CVS/Entries Thu Feb 1 11:47:09 2001
+@@ -0,0 +1 @@
++D
+diff -urN linux-2.4.1/net/korbit/modules/UserFS/CVS/Entries.Log linux-2.4.1-korbit/net/korbit/modules/UserFS/CVS/Entries.Log
+--- linux-2.4.1/net/korbit/modules/UserFS/CVS/Entries.Log Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/UserFS/CVS/Entries.Log Thu Feb 1 11:47:10 2001
+@@ -0,0 +1 @@
++A D/client////
+diff -urN linux-2.4.1/net/korbit/modules/UserFS/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/UserFS/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/UserFS/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/UserFS/CVS/Repository Thu Feb 1 11:47:09 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/UserFS
+diff -urN linux-2.4.1/net/korbit/modules/UserFS/CVS/Root linux-2.4.1-korbit/net/korbit/modules/UserFS/CVS/Root
+--- linux-2.4.1/net/korbit/modules/UserFS/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/UserFS/CVS/Root Thu Feb 1 11:47:09 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/UserFS/client/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/UserFS/client/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/UserFS/client/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/UserFS/client/CVS/Entries Thu Feb 1 11:47:10 2001
+@@ -0,0 +1 @@
++D
+diff -urN linux-2.4.1/net/korbit/modules/UserFS/client/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/UserFS/client/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/UserFS/client/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/UserFS/client/CVS/Repository Thu Feb 1 11:47:10 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/UserFS/client
+diff -urN linux-2.4.1/net/korbit/modules/UserFS/client/CVS/Root linux-2.4.1-korbit/net/korbit/modules/UserFS/client/CVS/Root
+--- linux-2.4.1/net/korbit/modules/UserFS/client/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/UserFS/client/CVS/Root Thu Feb 1 11:47:10 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/orb/CVS/Entries linux-2.4.1-korbit/net/korbit/orb/CVS/Entries
+--- linux-2.4.1/net/korbit/orb/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/CVS/Entries Thu Feb 1 11:47:14 2001
+@@ -0,0 +1,60 @@
++/Makefile/1.6/Thu Feb 1 09:47:10 2001//
++/allocator-defs.h/1.1.1.1/Thu Feb 1 09:47:10 2001//
++/allocators.c/1.2/Thu Feb 1 09:47:10 2001//
++/allocators.h/1.1.1.1/Thu Feb 1 09:47:10 2001//
++/cdr.c/1.1.1.1/Thu Feb 1 09:47:10 2001//
++/cdr.h/1.1.1.1/Thu Feb 1 09:47:10 2001//
++/corba_any.c/1.3/Thu Feb 1 09:47:10 2001//
++/corba_any.h/1.1.1.1/Thu Feb 1 09:47:10 2001//
++/corba_any_proto.h/1.1.1.1/Thu Feb 1 09:47:11 2001//
++/corba_any_type.h/1.1.1.1/Thu Feb 1 09:47:11 2001//
++/corba_basic_sequences_type.h/1.1.1.1/Thu Feb 1 09:47:11 2001//
++/corba_context.c/1.1.1.1/Thu Feb 1 09:47:11 2001//
++/corba_context.h/1.1.1.1/Thu Feb 1 09:47:11 2001//
++/corba_env.h/1.1.1.1/Thu Feb 1 09:47:11 2001//
++/corba_env_type.h/1.1.1.1/Thu Feb 1 09:47:11 2001//
++/corba_object.c/1.7/Thu Feb 1 09:47:11 2001//
++/corba_object.h/1.1.1.1/Thu Feb 1 09:47:11 2001//
++/corba_object_type.h/1.1.1.1/Thu Feb 1 09:47:11 2001//
++/corba_orb.h/1.1.1.1/Thu Feb 1 09:47:11 2001//
++/corba_orb_type.h/1.1.1.1/Thu Feb 1 09:47:11 2001//
++/corba_portableserver.h/1.1.1.1/Thu Feb 1 09:47:11 2001//
++/corba_portableserver_type.h/1.1.1.1/Thu Feb 1 09:47:11 2001//
++/corba_sequences.h/1.1.1.1/Thu Feb 1 09:47:12 2001//
++/corba_sequences_type.h/1.1.1.1/Thu Feb 1 09:47:12 2001//
++/corba_typecode.h/1.1.1.1/Thu Feb 1 09:47:12 2001//
++/corba_typecode_type.h/1.3/Thu Feb 1 09:47:12 2001//
++/dii.c/1.2/Thu Feb 1 09:47:12 2001//
++/dii.h/1.2/Thu Feb 1 09:47:12 2001//
++/env.c/1.2/Thu Feb 1 09:47:12 2001//
++/env.h/1.2/Thu Feb 1 09:47:12 2001//
++/genrand.c/1.4/Thu Feb 1 09:47:12 2001//
++/genrand.h/1.1.1.1/Thu Feb 1 09:47:12 2001//
++/iop.h/1.1.1.1/Thu Feb 1 09:47:12 2001//
++/ir.c/1.1.1.1/Thu Feb 1 09:47:12 2001//
++/ir.h/1.1.1.1/Thu Feb 1 09:47:12 2001//
++/options.c/1.2/Thu Feb 1 09:47:12 2001//
++/options.h/1.2/Thu Feb 1 09:47:13 2001//
++/orb.c/1.13/Thu Feb 1 09:47:13 2001//
++/orb.h/1.2/Thu Feb 1 09:47:13 2001//
++/orbit.c/1.1.1.1/Thu Feb 1 09:47:13 2001//
++/orbit.h/1.2/Thu Feb 1 09:47:13 2001//
++/orbit.h.in/1.1.1.1/Thu Feb 1 09:47:13 2001//
++/orbit_config.h/1.1.1.1/Thu Feb 1 09:47:13 2001//
++/orbit_object.c/1.1.1.1/Thu Feb 1 09:47:13 2001//
++/orbit_object.h/1.1.1.1/Thu Feb 1 09:47:13 2001//
++/orbit_object_type.h/1.1.1.1/Thu Feb 1 09:47:13 2001//
++/orbit_poa.c/1.1.1.1/Thu Feb 1 09:47:13 2001//
++/orbit_poa.h/1.3/Thu Feb 1 09:47:13 2001//
++/orbit_poa_type.h/1.1.1.1/Thu Feb 1 09:47:13 2001//
++/orbit_typecode.c/1.1.1.1/Thu Feb 1 09:47:14 2001//
++/orbit_typecode.h/1.1.1.1/Thu Feb 1 09:47:14 2001//
++/orbit_types.h/1.1.1.1/Thu Feb 1 09:47:14 2001//
++/poa.c/1.1.1.1/Thu Feb 1 09:47:14 2001//
++/poa.h/1.1.1.1/Thu Feb 1 09:47:14 2001//
++/sequences.c/1.1.1.1/Thu Feb 1 09:47:14 2001//
++/sequences.h/1.1.1.1/Thu Feb 1 09:47:14 2001//
++/server.c/1.5/Thu Feb 1 09:47:14 2001//
++/typecode.c/1.1.1.1/Thu Feb 1 09:47:14 2001//
++/typecode.h/1.1.1.1/Thu Feb 1 09:47:14 2001//
++D
+diff -urN linux-2.4.1/net/korbit/orb/CVS/Repository linux-2.4.1-korbit/net/korbit/orb/CVS/Repository
+--- linux-2.4.1/net/korbit/orb/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/CVS/Repository Thu Feb 1 11:47:10 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/orb
+diff -urN linux-2.4.1/net/korbit/orb/CVS/Root linux-2.4.1-korbit/net/korbit/orb/CVS/Root
+--- linux-2.4.1/net/korbit/orb/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/CVS/Root Thu Feb 1 11:47:10 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/orb/Makefile linux-2.4.1-korbit/net/korbit/orb/Makefile
+--- linux-2.4.1/net/korbit/orb/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/Makefile Thu Feb 1 11:47:10 2001
+@@ -0,0 +1,25 @@
++#
++# Makefile for KORBit/orb
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .o file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++O_TARGET := orblib.o
++
++#obj-m := $(O_TARGET)
++obj-y := allocators.o options.o poa.o \
++ cdr.o env.o orb.o sequences.o \
++ corba_any.o genrand.o orbit.o server.o \
++ corba_context.o orbit_object.o typecode.o \
++ corba_object.o orbit_poa.o \
++ dii.o ir.o orbit_typecode.o
++
++EXTRA_CFLAGS = -D__KORBIT__ -DHAVE_CONFIG_H -I. -I.. -I../include -I../kglib -I../ORBitutil -nostdinc \
++ -DORBit_SYSRC=\"/etc/orbitrc\" \
++ -DORBIT_MAJOR_VERSION="0" -DORBIT_MINOR_VERSION="5" -DORBIT_MICRO_VERSION="3" -DORBIT_VERSION=\"0.5.3\"
++
++include $(TOPDIR)/Rules.make
++
+diff -urN linux-2.4.1/net/korbit/orb/allocator-defs.h linux-2.4.1-korbit/net/korbit/orb/allocator-defs.h
+--- linux-2.4.1/net/korbit/orb/allocator-defs.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/allocator-defs.h Thu Feb 1 11:47:10 2001
+@@ -0,0 +1,40 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/* By Elliot Lee. Copyright (c) 1998 Red Hat Software */
++
++
++/********************************************************
++ * Never include this header file directly. Only allocators.[ch]
++ * should do this
++ ********************************************************/
++
++/* Macro crap */
++
++#ifdef ALLOCATOR_DEFINITION
++
++#define ORBIT_DEFINE_CHUNK(x, xsize) \
++DEFINE_LOCK(x##_allocator); \
++GMemChunk *x##_allocator = NULL
++
++#elif defined(ALLOCATOR_INITIALIZATION)
++
++#define ORBIT_DEFINE_CHUNK(x, xsize) INIT_LOCK(x##_allocator); \
++x##_allocator = g_mem_chunk_new(#x, (xsize), \
++(xsize) * ORBIT_CHUNKS_PREALLOC, G_ALLOC_AND_FREE)
++
++#else
++
++#define ORBIT_DEFINE_CHUNK(x, xsize) \
++EXTERN_LOCK(x##_allocator); \
++extern GMemChunk *x##_allocator
++
++#endif
++
++/*****************************************************
++ * Here's where we define the actual chunks that are used
++ *****************************************************/
++ORBIT_DEFINE_CHUNK(CORBA_TypeCode, sizeof(struct CORBA_TypeCode_struct));
++ORBIT_DEFINE_CHUNK(CORBA_Object, sizeof(struct CORBA_Object_struct));
++ORBIT_DEFINE_CHUNK(CORBA_NVList, sizeof(struct CORBA_NVList_type));
++
++#undef ORBIT_DEFINE_CHUNK
+diff -urN linux-2.4.1/net/korbit/orb/allocators.c linux-2.4.1-korbit/net/korbit/orb/allocators.c
+--- linux-2.4.1/net/korbit/orb/allocators.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/allocators.c Thu Feb 1 11:47:10 2001
+@@ -0,0 +1,241 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/* By Elliot Lee. Copyright (c) 1998 Red Hat Software */
++
++#include "orbit.h"
++
++#if 0
++#define CORBA_Object_release(x, y) ({ g_message(__FILE__ ":%d Releasing object %#x from %d", __LINE__, \
++x, ORBIT_ROOT_OBJECT(x)->refs); CORBA_Object_release(x, y); })
++#define CORBA_Object_duplicate(x, y) ({ g_message(__FILE__ ":%d Duping object %#x from %d", __LINE__, \
++x, ORBIT_ROOT_OBJECT(x)->refs); CORBA_Object_duplicate(x, y); })
++#endif
++
++/* The memory chunk stuff */
++
++#define ALLOCATOR_DEFINITION
++#include "allocator-defs.h"
++#undef ALLOCATOR_DEFINITION
++
++void
++ORBit_chunks_init(void)
++{
++#define ALLOCATOR_INITIALIZATION
++#include "allocator-defs.h"
++#undef ALLOCATOR_INTIALIZATION
++}
++
++gpointer
++ORBit_chunk_alloc(GMemChunk *chunk,
++ PARAM_LOCK(chunk))
++{
++ gpointer retval;
++
++ GET_LOCK(chunk);
++ retval = g_mem_chunk_alloc(chunk);
++ RELEASE_LOCK(chunk);
++
++ return retval;
++}
++
++void
++ORBit_chunk_free(GMemChunk *chunk,
++ PARAM_LOCK(chunk),
++ gpointer mem)
++{
++ GET_LOCK(chunk);
++ g_mem_chunk_free(chunk, mem);
++ RELEASE_LOCK(chunk);
++}
++
++/* end memory chunk routines */
++
++/****************************************************************/
++
++/************* begin funky memory alloc/free system */
++
++/****** functions */
++
++gpointer ORBit_alloc(size_t block_size,
++ ORBit_free_childvals freefunc,
++ gpointer func_data)
++{
++ return ORBit_alloc_2(block_size, freefunc, func_data, 0);
++}
++
++gpointer
++ORBit_alloc_2(size_t block_size,
++ ORBit_free_childvals freefunc,
++ gpointer func_data,
++ size_t before_size)
++{
++ ORBit_mem_info *block;
++
++ if(block_size == 0) return NULL;
++
++ block = (ORBit_mem_info *)((char *)
++ g_malloc(block_size + sizeof(ORBit_mem_info) + before_size)
++ + before_size);
++
++#ifdef ORBIT_DEBUG
++ block->magic = 0xdeadbeef;
++#endif
++ block->free = freefunc;
++ block->func_data = func_data;
++
++ return MEMINFO_TO_PTR(block);
++}
++
++/*
++ ORBit_free
++ ----------
++
++ Frees a corba primitive type.
++
++ mem = pointer to the memory block. (must have a preceeding pointer to a meminfo block)
++
++ 1)obtains a pointer to the preceeding meminfo structure
++ 2)Uses the meminfo structure to find the number of elements in the memory block
++ 3)iterates through the memory block, calling the free function for each item.
++
++ */
++
++void
++ORBit_free(gpointer mem, CORBA_boolean free_strings)
++{
++ ORBit_mem_info *block;
++
++ if(!mem)
++ return;
++
++ block = PTR_TO_MEMINFO(mem);
++
++#ifdef ORBIT_DEBUG
++ g_assert(block->magic == 0xdeadbeef);
++#endif
++
++ if(block->free) {
++ int i;
++ gpointer x;
++ gpointer my_data;
++
++ if((gpointer)block->free == (gpointer)ORBit_free_via_TypeCode)
++ my_data = ((guchar *)block) - sizeof(CORBA_TypeCode);
++ else
++ my_data = NULL;
++
++#ifdef ORBIT_DEBUG
++ if(block->func_data == NULL)
++ g_warning("block with freefunc %p has no items", block->free);
++#endif
++
++ for(i = 0, x = mem; i < (gulong)block->func_data; i++)
++ x = block->free(x, my_data, free_strings);
++
++ if((gpointer)block->free == (gpointer)ORBit_free_via_TypeCode)
++ /* ((guchar *)block) -= sizeof(CORBA_TypeCode); */
++ block = (ORBit_mem_info *)
++ (((guchar *)block) - sizeof(CORBA_TypeCode));
++ g_free(block);
++ } else
++ g_free(block);
++}
++
++/******************************************************************/
++/* These aren't currently used... */
++
++gpointer
++ORBit_free_via_TypeCode(gpointer mem, gpointer tcp, gboolean free_strings)
++{
++ CORBA_TypeCode tc = *(CORBA_TypeCode *)tcp, subtc;
++ int i;
++ guchar *retval = NULL;
++
++ switch(tc->kind) {
++ case CORBA_tk_any:
++ {
++ CORBA_any *anyval = mem;
++ if(anyval->_release)
++ CORBA_free(anyval->_value);
++ retval = (guchar *)(anyval + 1);
++ }
++ break;
++ case CORBA_tk_TypeCode:
++ case CORBA_tk_objref:
++ {
++ CORBA_Object_release(*(CORBA_Object *)mem, NULL);
++
++ retval = (guchar *)mem + sizeof(CORBA_Object);
++ }
++ break;
++ case CORBA_tk_Principal:
++ {
++ CORBA_Principal *pval = mem;
++ if(pval->_release)
++ CORBA_free(pval->_buffer);
++ retval = (guchar *)(pval + 1);
++ }
++ break;
++ case CORBA_tk_except:
++ case CORBA_tk_struct:
++ mem = ALIGN_ADDRESS(mem, ORBit_find_alignment(tc));
++ for(i = 0; i < tc->sub_parts; i++) {
++ subtc = (CORBA_TypeCode)CORBA_Object_duplicate((CORBA_Object)tc->subtypes[i], NULL);
++ mem = ORBit_free_via_TypeCode(mem, &subtc,
++ free_strings);
++ }
++ retval = mem;
++ break;
++ case CORBA_tk_union:
++ subtc = (CORBA_TypeCode)CORBA_Object_duplicate(
++ (CORBA_Object)ORBit_get_union_tag(tc, &mem, TRUE), NULL);
++ {
++ int sz = 0;
++ int al = 1;
++ for(i = 0; i < tc->sub_parts; i++) {
++ al = MAX(al, ORBit_find_alignment(tc->subtypes[i]));
++ sz = MAX(sz, ORBit_gather_alloc_info(tc->subtypes[i]));
++ }
++ mem = ALIGN_ADDRESS(mem, al);
++ ORBit_free_via_TypeCode(mem, &subtc, free_strings);
++ /* the end of the body (subtc) may not be the
++ * same as the end of the union */
++ retval = mem + sz;
++ }
++ break;
++ case CORBA_tk_wstring:
++ case CORBA_tk_string:
++ if(free_strings)
++ CORBA_free(*(char **)mem);
++ retval = (guchar *)mem + sizeof(char *);
++ break;
++ case CORBA_tk_sequence:
++ {
++ CORBA_sequence_octet *pval = mem;
++ if(pval->_release)
++ CORBA_free(pval->_buffer);
++
++ retval = (guchar *)mem + sizeof(CORBA_sequence_octet);
++ }
++ break;
++ case CORBA_tk_array:
++ for(i = 0; i < tc->length; i++) {
++ subtc = (CORBA_TypeCode)CORBA_Object_duplicate((CORBA_Object)tc->subtypes[0], NULL);
++ mem = ORBit_free_via_TypeCode(mem, &subtc,
++ free_strings);
++ }
++ retval = mem;
++ break;
++ case CORBA_tk_alias:
++ subtc = (CORBA_TypeCode)CORBA_Object_duplicate((CORBA_Object)tc->subtypes[0], NULL);
++ retval = ORBit_free_via_TypeCode(mem, &subtc, free_strings);
++ break;
++ default:
++ retval = ((guchar *)mem) + ORBit_gather_alloc_info(tc);
++ break;
++ }
++
++ CORBA_Object_release((CORBA_Object)tc, NULL);
++
++ return (gpointer)retval;
++}
+diff -urN linux-2.4.1/net/korbit/orb/allocators.h linux-2.4.1-korbit/net/korbit/orb/allocators.h
+--- linux-2.4.1/net/korbit/orb/allocators.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/allocators.h Thu Feb 1 11:47:10 2001
+@@ -0,0 +1,61 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/* By Elliot Lee. Copyright (c) 1998 Red Hat Software */
++
++#ifndef ALLOCATORS_H
++#define ALLOCATORS_H 1
++
++#include <orb/orbit.h>
++
++#include <orb/allocator-defs.h>
++
++#define ORBIT_CHUNK_ALLOC(typename) \
++ORBit_chunk_alloc(typename##_allocator, LOCK_NAME(typename##_allocator))
++
++#define ORBIT_CHUNK_FREE(typename, mem) \
++ORBit_chunk_free(typename##_allocator, LOCK_NAME(typename##_allocator), (mem))
++
++void ORBit_chunks_init(void);
++
++gpointer ORBit_chunk_alloc(GMemChunk *chunk,
++ PARAM_LOCK(chunk_lock));
++
++void ORBit_chunk_free(GMemChunk *chunk,
++ PARAM_LOCK(chunk_lock),
++ gpointer mem);
++
++/* General memory allocation routines */
++
++#define PTR_TO_MEMINFO(x) (((ORBit_mem_info *)(x)) - 1)
++#define MEMINFO_TO_PTR(x) ((gpointer)((x) + 1))
++
++typedef gpointer (*ORBit_free_childvals)(gpointer mem,
++ gpointer func_data,
++ CORBA_boolean free_strings);
++
++typedef struct {
++#ifdef ORBIT_DEBUG
++ gulong magic;
++#endif
++ /* If this routine returns FALSE, it indicates that it already free'd
++ the memory block itself */
++ ORBit_free_childvals free; /* function pointer to free function */
++ gpointer func_data;
++} ORBit_mem_info;
++
++gpointer ORBit_alloc(size_t block_size,
++ ORBit_free_childvals freefunc,
++ gpointer func_data);
++gpointer ORBit_alloc_2(size_t block_size,
++ ORBit_free_childvals freefunc,
++ gpointer func_data,
++ size_t before_size);
++
++void ORBit_free(gpointer mem, CORBA_boolean free_strings);
++
++/* internal stuff */
++gpointer ORBit_free_via_TypeCode(gpointer mem,
++ gpointer tcp,
++ gboolean free_strings);
++
++#endif /* ALLOCATORS_H */
+diff -urN linux-2.4.1/net/korbit/orb/cdr.c linux-2.4.1-korbit/net/korbit/orb/cdr.c
+--- linux-2.4.1/net/korbit/orb/cdr.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/cdr.c Thu Feb 1 11:47:10 2001
+@@ -0,0 +1,643 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#include "config.h"
++#include "../IIOP/iiop-endianP.h"
++#include <stdlib.h>
++#include <string.h>
++#include <ctype.h>
++#include <assert.h>
++
++#include "orbit.h"
++
++#define CDR_GROW_AMOUNT 128
++
++static CORBA_boolean CDR_buffer_grow(CDR_Codec *codec, const unsigned int growth)
++{
++ unsigned int real_growth;
++ div_t divvy;
++
++ if(codec->release_buffer) {
++ divvy=div(growth, CDR_GROW_AMOUNT);
++ real_growth=CDR_GROW_AMOUNT * (divvy.quot+1);
++
++ codec->buffer=(CORBA_octet *)g_realloc(codec->buffer,
++ codec->buf_len
++ +real_growth);
++ }
++
++ return CORBA_TRUE;
++}
++
++static void CDR_buffer_puts(CDR_Codec *codec, const void *data, const unsigned int len)
++{
++ if(codec->wptr+len > codec->buf_len) {
++ CORBA_boolean res=CDR_buffer_grow(codec, len);
++
++ if(res==CORBA_FALSE) {
++ /* just bail out for now */
++ g_assert(!"Malloc error");
++ }
++ }
++
++ memcpy(&codec->buffer[codec->wptr], data, len);
++ codec->wptr+=len;
++}
++
++CORBA_boolean CDR_buffer_gets(CDR_Codec *codec, void *dest, const unsigned int len)
++{
++ if(codec->rptr+len > codec->buf_len) {
++ ORBit_Trace(TraceMod_CDR, TraceLevel_Debug, "CDR_buffer_gets: attempt to read past end of buffer\n");
++ return(CORBA_FALSE);
++ }
++
++ memcpy(dest, &codec->buffer[codec->rptr], len);
++ codec->rptr+=len;
++
++ return(CORBA_TRUE);
++}
++
++static void CDR_buffer_put(CDR_Codec *codec, void *datum)
++{
++ if(codec->wptr+1 > codec->buf_len) {
++ CORBA_boolean res=CDR_buffer_grow(codec, 1);
++
++ if(res==CORBA_FALSE) {
++ /* just bail out for now */
++ g_assert(!"Malloc error");
++ }
++ }
++
++ codec->buffer[codec->wptr++]=*(unsigned char *)datum;
++}
++
++static CORBA_boolean CDR_buffer_get(CDR_Codec *codec, void *dest)
++{
++ if(codec->rptr+1 > codec->buf_len) {
++ ORBit_Trace(TraceMod_CDR, TraceLevel_Debug, "CDR_buffer_get: attempt to read past end of buffer\n");
++ return(CORBA_FALSE);
++ }
++
++ *(CORBA_octet *)dest=codec->buffer[codec->rptr++];
++ return(CORBA_TRUE);
++}
++
++#ifdef lame_slow_code
++static void CDR_buffer_put2(CDR_Codec *codec, void *datum)
++{
++ unsigned long align;
++
++ g_assert(codec!=NULL);
++ g_assert(codec->readonly!=CORBA_TRUE);
++ g_assert(codec->wptr<=codec->buf_len);
++
++ align=((codec->wptr+1)&~1L);
++
++ if(align+2 > codec->buf_len) {
++ CORBA_boolean res=CDR_buffer_grow(codec, align+2-codec->wptr);
++
++ if(res==CORBA_FALSE) {
++ /* just bail out for now */
++ g_assert(!"Malloc error");
++ }
++ }
++
++ while(codec->wptr < align) {
++ codec->buffer[codec->wptr++]='\0';
++ }
++
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[0];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[1];
++}
++
++static CORBA_boolean CDR_buffer_get2(CDR_Codec *codec, void *dest)
++{
++ unsigned long align;
++
++ g_assert(codec!=NULL);
++ g_assert(dest!=NULL);
++ g_assert(codec->rptr<=codec->buf_len);
++
++ align=((codec->rptr+1)&~1L);
++
++ if(align+2 > codec->buf_len) {
++ ORBit_Trace(TraceMod_CDR, TraceLevel_Debug, "CDR_buffer_get2: attempt to read past end of buffer\n");
++ return(CORBA_FALSE);
++ }
++
++ codec->rptr=align;
++
++ ((CORBA_octet *)dest)[0]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[1]=codec->buffer[codec->rptr++];
++
++ return(CORBA_TRUE);
++}
++
++static void CDR_buffer_put4(CDR_Codec *codec, void *datum)
++{
++ unsigned long align;
++
++ g_assert(codec!=NULL);
++ g_assert(codec->readonly!=CORBA_TRUE);
++ g_assert(codec->wptr<=codec->buf_len);
++
++ align=((codec->wptr+3)&~3L);
++
++ if(align+4 > codec->buf_len) {
++ CORBA_boolean res=CDR_buffer_grow(codec, align+4-codec->wptr);
++
++ if(res==CORBA_FALSE) {
++ /* just bail out for now */
++ g_assert(!"Malloc error");
++ }
++ }
++
++ while(codec->wptr < align) {
++ codec->buffer[codec->wptr++]='\0';
++ }
++
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[0];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[1];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[2];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[3];
++}
++
++static CORBA_boolean CDR_buffer_get4(CDR_Codec *codec, void *dest)
++{
++ unsigned long align;
++
++ g_assert(codec!=NULL);
++ g_assert(dest!=NULL);
++ g_assert(codec->rptr<=codec->buf_len);
++
++ align=((codec->rptr+3)&~3L);
++
++ if(align+4 > codec->buf_len) {
++ ORBit_Trace(TraceMod_CDR, TraceLevel_Debug, "CDR_buffer_get4: attempt to read past end of buffer\n");
++ return(CORBA_FALSE);
++ }
++
++ codec->rptr=align;
++
++ ((CORBA_octet *)dest)[0]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[1]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[2]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[3]=codec->buffer[codec->rptr++];
++
++ return(CORBA_TRUE);
++}
++
++static void CDR_buffer_put8(CDR_Codec *codec, void *datum)
++{
++ unsigned long align;
++
++ g_assert(codec!=NULL);
++ g_assert(codec->readonly!=CORBA_TRUE);
++ g_assert(codec->wptr<=codec->buf_len);
++
++ align=((codec->wptr+7)&~7L);
++
++ if(align+8 > codec->buf_len) {
++ CORBA_boolean res=CDR_buffer_grow(codec, align+8-codec->wptr);
++
++ if(res==CORBA_FALSE) {
++ /* just bail out for now */
++ g_assert(!"Malloc error");
++ }
++ }
++
++ while(codec->wptr < align) {
++ codec->buffer[codec->wptr++]='\0';
++ }
++
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[0];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[1];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[2];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[3];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[4];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[5];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[6];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[7];
++}
++
++#if 0
++static CORBA_boolean CDR_buffer_get8(CDR_Codec *codec, void *dest)
++{
++ unsigned long align;
++
++ g_assert(codec!=NULL);
++ g_assert(dest!=NULL);
++ g_assert(codec->rptr<=codec->buf_len);
++
++ align=((codec->rptr+7)&~7L);
++
++ if(align+8 > codec->buf_len) {
++ ORBit_Trace(TraceMod_CDR, TraceLevel_Debug, "CDR_buffer_get8: attempt to read past end of buffer\n");
++ return(CORBA_FALSE);
++ }
++
++ codec->rptr=align;
++
++ ((CORBA_octet *)dest)[0]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[1]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[2]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[3]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[4]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[5]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[6]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[7]=codec->buffer[codec->rptr++];
++
++ return(CORBA_TRUE);
++}
++#endif
++
++static void CDR_buffer_put16(CDR_Codec *codec, void *datum)
++{
++ unsigned long align;
++
++ g_assert(codec!=NULL);
++ g_assert(codec->readonly!=CORBA_TRUE);
++ g_assert(codec->wptr<=codec->buf_len);
++
++ align=((codec->wptr+15)&~15L);
++
++ if(align+16 > codec->buf_len) {
++ CORBA_boolean res=CDR_buffer_grow(codec, align+16-codec->wptr);
++
++ if(res==CORBA_FALSE) {
++ /* just bail out for now */
++ g_assert(!"Malloc error");
++ }
++ }
++
++ while(codec->wptr < align) {
++ codec->buffer[codec->wptr++]='\0';
++ }
++
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[0];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[1];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[2];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[3];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[4];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[5];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[6];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[7];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[8];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[9];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[10];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[11];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[12];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[13];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[14];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[15];
++}
++
++#if 0
++static CORBA_boolean CDR_buffer_get16(CDR_Codec *codec, void *dest)
++{
++ unsigned long align;
++
++ g_assert(codec!=NULL);
++ g_assert(dest!=NULL);
++ g_assert(codec->rptr<=codec->buf_len);
++
++ align=((codec->rptr+15)&~15L);
++
++ if(align+16 > codec->buf_len) {
++ ORBit_Trace(TraceMod_CDR, TraceLevel_Debug, "CDR_buffer_get16: attempt to read past end of buffer\n");
++ return(CORBA_FALSE);
++ }
++
++ codec->rptr=align;
++
++ ((CORBA_octet *)dest)[0]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[1]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[2]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[3]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[4]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[5]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[6]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[7]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[8]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[9]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[10]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[11]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[12]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[13]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[14]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[15]=codec->buffer[codec->rptr++];
++
++ return(CORBA_TRUE);
++}
++#endif
++#endif /* lame_slow_code */
++
++#define CDR_buffer_put2(codec, datum) CDR_buffer_putn(codec, datum, 2)
++#define CDR_buffer_put4(codec, datum) CDR_buffer_putn(codec, datum, 4)
++#define CDR_buffer_put8(codec, datum) CDR_buffer_putn(codec, datum, 8)
++#define CDR_buffer_put16(codec, datum) CDR_buffer_putn(codec, datum, 16)
++#define CDR_buffer_get2(codec, dest) CDR_buffer_getn(codec, dest, 2)
++#define CDR_buffer_get4(codec, dest) CDR_buffer_getn(codec, dest, 4)
++#define CDR_buffer_get8(codec, dest) CDR_buffer_getn(codec, dest, 8)
++#define CDR_buffer_get16(codec, dest) CDR_buffer_getn(codec, dest, 16)
++
++static CORBA_boolean
++CDR_buffer_getn(CDR_Codec *codec, void *dest, int bsize)
++{
++ codec->rptr = (unsigned long)ALIGN_ADDRESS(codec->rptr, bsize);
++ if(codec->host_endian==codec->data_endian)
++ memcpy(dest, codec->buffer + codec->rptr, bsize);
++ else
++ iiop_byteswap(dest, codec->buffer + codec->rptr, bsize);
++ codec->rptr += bsize;
++
++ return CORBA_TRUE;
++}
++
++static CORBA_boolean
++CDR_buffer_putn(CDR_Codec *codec, void *datum, int bsize)
++{
++ codec->wptr = (unsigned long)ALIGN_ADDRESS(codec->wptr, bsize);
++ if(codec->host_endian==codec->data_endian)
++ memcpy(codec->buffer + codec->wptr, datum, bsize);
++ else
++ iiop_byteswap(codec->buffer + codec->wptr, datum, bsize);
++ codec->wptr += bsize;
++
++ return CORBA_TRUE;
++}
++
++#define CDR_swap2(d,s) iiop_byteswap((d), (s), 2)
++#define CDR_swap4(d,s) iiop_byteswap((d), (s), 4)
++#define CDR_swap8(d,s) iiop_byteswap((d), (s), 8)
++#define CDR_swap16(d,s) iiop_byteswap((d), (s), 16)
++
++#ifdef lame_slow_code
++static void CDR_swap2(void *d, void *s)
++{
++ ((CORBA_octet *)d)[0]=((CORBA_octet *)s)[1];
++ ((CORBA_octet *)d)[1]=((CORBA_octet *)s)[0];
++}
++
++static void CDR_swap4(void *d, void *s)
++{
++ ((CORBA_octet *)d)[0]=((CORBA_octet *)s)[3];
++ ((CORBA_octet *)d)[1]=((CORBA_octet *)s)[2];
++ ((CORBA_octet *)d)[2]=((CORBA_octet *)s)[1];
++ ((CORBA_octet *)d)[3]=((CORBA_octet *)s)[0];
++}
++
++static void CDR_swap8(void *d, void *s)
++{
++ ((CORBA_octet *)d)[0]=((CORBA_octet *)s)[7];
++ ((CORBA_octet *)d)[1]=((CORBA_octet *)s)[6];
++ ((CORBA_octet *)d)[2]=((CORBA_octet *)s)[5];
++ ((CORBA_octet *)d)[3]=((CORBA_octet *)s)[4];
++ ((CORBA_octet *)d)[4]=((CORBA_octet *)s)[3];
++ ((CORBA_octet *)d)[5]=((CORBA_octet *)s)[2];
++ ((CORBA_octet *)d)[6]=((CORBA_octet *)s)[1];
++ ((CORBA_octet *)d)[7]=((CORBA_octet *)s)[0];
++}
++
++static void CDR_swap16(void *d, void *s)
++{
++ ((CORBA_octet *)d)[0]=((CORBA_octet *)s)[15];
++ ((CORBA_octet *)d)[1]=((CORBA_octet *)s)[14];
++ ((CORBA_octet *)d)[2]=((CORBA_octet *)s)[13];
++ ((CORBA_octet *)d)[3]=((CORBA_octet *)s)[12];
++ ((CORBA_octet *)d)[4]=((CORBA_octet *)s)[11];
++ ((CORBA_octet *)d)[5]=((CORBA_octet *)s)[10];
++ ((CORBA_octet *)d)[6]=((CORBA_octet *)s)[9];
++ ((CORBA_octet *)d)[7]=((CORBA_octet *)s)[8];
++ ((CORBA_octet *)d)[8]=((CORBA_octet *)s)[7];
++ ((CORBA_octet *)d)[9]=((CORBA_octet *)s)[6];
++ ((CORBA_octet *)d)[10]=((CORBA_octet *)s)[5];
++ ((CORBA_octet *)d)[11]=((CORBA_octet *)s)[4];
++ ((CORBA_octet *)d)[12]=((CORBA_octet *)s)[3];
++ ((CORBA_octet *)d)[13]=((CORBA_octet *)s)[2];
++ ((CORBA_octet *)d)[14]=((CORBA_octet *)s)[1];
++ ((CORBA_octet *)d)[15]=((CORBA_octet *)s)[0];
++}
++#endif
++
++
++void CDR_put_short(CDR_Codec *codec, CORBA_short s)
++{
++ CDR_buffer_put2(codec, &s);
++}
++
++CORBA_boolean CDR_get_short(CDR_Codec *codec, CORBA_short *s)
++{
++ return CDR_buffer_get2(codec, s);
++}
++
++void CDR_put_ushort(CDR_Codec *codec, CORBA_unsigned_short us)
++{
++ CDR_buffer_put2(codec, &us);
++}
++
++CORBA_boolean CDR_get_ushort(CDR_Codec *codec, CORBA_unsigned_short *us)
++{
++ return CDR_buffer_get2(codec, us);
++}
++
++void CDR_put_long(CDR_Codec *codec, CORBA_long l)
++{
++ CDR_buffer_put4(codec, &l);
++}
++
++CORBA_boolean CDR_get_long(CDR_Codec *codec, CORBA_long *l)
++{
++ return CDR_buffer_get4(codec, l);
++}
++
++void CDR_put_ulong(CDR_Codec *codec, CORBA_unsigned_long ul)
++{
++ CDR_buffer_put4(codec, &ul);
++}
++
++CORBA_boolean CDR_get_ulong(CDR_Codec *codec, CORBA_unsigned_long *ul)
++{
++ return CDR_buffer_get4(codec, ul);
++}
++
++#ifdef HAVE_CORBA_LONG_LONG
++CORBA_boolean CDR_get_long_long(CDR_Codec *codec, CORBA_long_long *ul)
++{
++ return CDR_buffer_get8(codec, ul);
++}
++
++void CDR_put_long_long(CDR_Codec *codec, CORBA_long_long ll)
++{
++ CDR_buffer_put8(codec, &ll);
++}
++
++void CDR_put_ulong_long(CDR_Codec *codec, CORBA_unsigned_long_long ll)
++{
++ CDR_buffer_put8(codec, &ll);
++}
++
++CORBA_boolean CDR_get_ulong_long(CDR_Codec *codec, CORBA_unsigned_long_long *ull)
++{
++ return CDR_buffer_get8(codec, ull);
++}
++#endif
++
++void CDR_put_float(CDR_Codec *codec, CORBA_float f)
++{
++ CDR_buffer_put4(codec, &f);
++}
++
++void CDR_put_double(CDR_Codec *codec, CORBA_double d)
++{
++ CDR_buffer_put8(codec, &d);
++}
++
++void CDR_put_long_double(CDR_Codec *codec, CORBA_long_double ld)
++{
++ CDR_buffer_put16(codec, &ld);
++}
++
++void CDR_put_octet(CDR_Codec *codec, CORBA_octet datum)
++{
++ CDR_buffer_put(codec, &datum);
++}
++
++CORBA_boolean CDR_get_octet(CDR_Codec *codec, CORBA_octet *datum)
++{
++ return(CDR_buffer_get(codec, datum));
++}
++
++void CDR_put_octets(CDR_Codec *codec, void *data, unsigned long len)
++{
++ CDR_buffer_puts(codec, data, len);
++}
++
++void CDR_put_char(CDR_Codec *codec, CORBA_char c)
++{
++ CDR_buffer_put(codec, &c);
++}
++
++CORBA_boolean CDR_get_char(CDR_Codec *codec, CORBA_char *c)
++{
++ return CDR_buffer_get(codec, c);
++}
++
++void CDR_put_boolean(CDR_Codec *codec, CORBA_boolean datum)
++{
++ datum = datum&&1;
++ CDR_buffer_put(codec, &datum);
++}
++
++CORBA_boolean CDR_get_boolean(CDR_Codec *codec, CORBA_boolean *b)
++{
++ return CDR_buffer_get(codec, b);
++}
++
++void CDR_put_string(CDR_Codec *codec, const char *str)
++{
++ unsigned int len;
++
++ len=strlen(str)+1;
++
++ CDR_put_ulong(codec, len);
++ CDR_buffer_puts(codec, str, len);
++}
++
++CORBA_boolean CDR_get_string_static(CDR_Codec *codec,
++ CORBA_char **str)
++{
++ CORBA_unsigned_long len;
++
++ if(CDR_get_ulong(codec, &len)==CORBA_FALSE)
++ return CORBA_FALSE;
++
++ if((codec->rptr + len) > codec->buf_len)
++ return CORBA_FALSE;
++
++ *str = ((CORBA_char *)codec->buffer) + codec->rptr;
++
++ codec->rptr += len;
++
++ return CORBA_TRUE;
++}
++
++CORBA_boolean CDR_get_string(CDR_Codec *codec, CORBA_char **str)
++{
++ CORBA_unsigned_long len;
++
++ if(CDR_get_ulong(codec, &len)==CORBA_FALSE)
++ return(CORBA_FALSE);
++
++ if(len==0)
++ return(CORBA_FALSE);
++
++ *str=g_new(CORBA_char, len);
++
++ if(CDR_buffer_gets(codec, *str, len)==CORBA_FALSE) {
++ g_free(*str);
++ return(CORBA_FALSE);
++ }
++
++ if((*str)[len-1]!='\0') {
++ ORBit_Trace(TraceMod_CDR, TraceLevel_Notice, "CDR_get_string: string was not NULL-terminated, terminating it now\n");
++ (*str)[len-1]='\0';
++ }
++
++ return(CORBA_TRUE);
++}
++
++CORBA_boolean CDR_get_seq_begin(CDR_Codec *codec, CORBA_unsigned_long *ul)
++{
++ return(CDR_get_ulong(codec, ul));
++}
++
++CDR_Codec *CDR_codec_init_static(CDR_Codec *codec)
++{
++ memset(codec, 0, sizeof(CDR_Codec));
++
++ codec->host_endian = FLAG_ENDIANNESS;
++
++ return codec;
++}
++
++CDR_Codec *CDR_codec_init(void)
++{
++ CDR_Codec *new;
++
++ new=g_new0(CDR_Codec, 1);
++ CDR_codec_init_static(new);
++ new->release_buffer = CORBA_TRUE;
++
++ return(new);
++}
++
++void CDR_codec_free(CDR_Codec *codec)
++{
++ if(codec->release_buffer)
++ g_free(codec->buffer);
++
++ g_free(codec);
++}
+diff -urN linux-2.4.1/net/korbit/orb/cdr.h linux-2.4.1-korbit/net/korbit/orb/cdr.h
+--- linux-2.4.1/net/korbit/orb/cdr.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/cdr.h Thu Feb 1 16:22:12 2001
+@@ -0,0 +1,83 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CDR_H_
++#define _ORBIT_CDR_H_
++
++#include "orbit_types.h"
++
++typedef enum {
++ BigEndian=0,
++ LittleEndian=1
++} CDR_Endianness;
++
++typedef struct {
++ CDR_Endianness host_endian;
++ CDR_Endianness data_endian;
++ CORBA_octet *buffer;
++ unsigned int buf_len;
++ unsigned int wptr, rptr;
++ CORBA_boolean readonly;
++ CORBA_boolean release_buffer;
++} CDR_Codec;
++
++#define HEXDIGIT(c) (isdigit((guchar)(c))?(c)-'0':tolower((guchar)(c))-'a'+10)
++#define HEXOCTET(a,b) ((HEXDIGIT((a)) << 4) | HEXDIGIT((b)))
++
++extern CDR_Codec *CDR_codec_init(void);
++extern CDR_Codec *CDR_codec_init_static(CDR_Codec *codec);
++extern void CDR_codec_free(CDR_Codec *);
++
++extern void CDR_put_short(CDR_Codec *codec, CORBA_short s);
++extern void CDR_put_ushort(CDR_Codec *codec, CORBA_unsigned_short us);
++extern void CDR_put_long(CDR_Codec *codec, CORBA_long l);
++extern void CDR_put_ulong(CDR_Codec *codec, CORBA_unsigned_long ul);
++#ifdef HAVE_CORBA_LONG_LONG
++extern void CDR_put_long_long(CDR_Codec *codec, CORBA_long_long ll);
++extern void CDR_put_ulong_long(CDR_Codec *codec, CORBA_unsigned_long_long ull);
++extern CORBA_boolean CDR_get_ulong_long(CDR_Codec *codec, CORBA_unsigned_long_long *ul);
++extern CORBA_boolean CDR_get_long_long(CDR_Codec *codec, CORBA_long_long *ul);
++#endif
++extern void CDR_put_float(CDR_Codec *codec, CORBA_float f);
++extern void CDR_put_double(CDR_Codec *codec, CORBA_double d);
++extern void CDR_put_long_double(CDR_Codec *codec, CORBA_long_double ld);
++extern void CDR_put_octet(CDR_Codec *codec, CORBA_octet datum);
++extern void CDR_put_octets(CDR_Codec *codec, void *data, unsigned long len);
++extern void CDR_put_char(CDR_Codec *codec, CORBA_char c);
++extern void CDR_put_boolean(CDR_Codec *codec, CORBA_boolean datum);
++extern void CDR_put_string(CDR_Codec *codec, const char *str);
++extern CORBA_boolean CDR_buffer_gets(CDR_Codec *codec, void *dest, const unsigned int len);
++extern CORBA_boolean CDR_get_short(CDR_Codec *codec, CORBA_short *us);
++extern CORBA_boolean CDR_get_ushort(CDR_Codec *codec, CORBA_unsigned_short *us);
++extern CORBA_boolean CDR_get_long(CDR_Codec *codec, CORBA_long *l);
++extern CORBA_boolean CDR_get_ulong(CDR_Codec *codec, CORBA_unsigned_long *ul);
++extern CORBA_boolean CDR_get_octet(CDR_Codec *codec, CORBA_octet *datum);
++extern CORBA_boolean CDR_get_boolean(CDR_Codec *codec, CORBA_boolean *b);
++extern CORBA_boolean CDR_get_char(CDR_Codec *codec, CORBA_char *c);
++extern CORBA_boolean CDR_get_string(CDR_Codec *codec, CORBA_char **str);
++extern CORBA_boolean CDR_get_string_static(CDR_Codec *codec, CORBA_char **str);
++extern CORBA_boolean CDR_get_seq_begin(CDR_Codec *codec, CORBA_unsigned_long *ul);
++
++#endif /* !_ORBIT_CDR_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/corba_any.c linux-2.4.1-korbit/net/korbit/orb/corba_any.c
+--- linux-2.4.1/net/korbit/orb/corba_any.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_any.c Thu Feb 1 11:47:10 2001
+@@ -0,0 +1,914 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Red Hat Software
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Elliot Lee <sopwith@redhat.com>
++ *
++ */
++
++#include <config.h>
++#include <IIOP/IIOP.h>
++#include "orbit.h"
++
++#if 0
++#define CORBA_Object_release(x, y) ({ g_message(__FILE__ ":%d Releasing object %#x from %d", __LINE__, \
++x, ORBIT_ROOT_OBJECT(x)->refs); CORBA_Object_release(x, y); })
++#define CORBA_Object_duplicate(x, y) ({ g_message(__FILE__ ":%d Duping object %#x from %d", __LINE__, \
++x, ORBIT_ROOT_OBJECT(x)->refs); CORBA_Object_duplicate(x, y); })
++#endif
++
++gint
++ORBit_find_alignment(CORBA_TypeCode tc)
++{
++ gint retval = 1;
++ int i;
++
++ switch(tc->kind) {
++ case CORBA_tk_union:
++ retval = MAX(retval, ORBit_find_alignment(tc->discriminator));
++ case CORBA_tk_except:
++ case CORBA_tk_struct:
++#if ALIGNOF_CORBA_STRUCT > 1
++ retval = MAX(retval, ALIGNOF_CORBA_STRUCT);
++#endif
++ for(i = 0; i < tc->sub_parts; i++)
++ retval = MAX(retval, ORBit_find_alignment(tc->subtypes[i]));
++ return retval;
++ case CORBA_tk_ulong:
++ case CORBA_tk_long:
++ case CORBA_tk_enum:
++ return ALIGNOF_CORBA_LONG;
++ case CORBA_tk_ushort:
++ case CORBA_tk_short:
++ case CORBA_tk_wchar:
++ return ALIGNOF_CORBA_SHORT;
++ case CORBA_tk_longlong:
++ case CORBA_tk_ulonglong:
++ return ALIGNOF_CORBA_LONG_LONG;
++ case CORBA_tk_longdouble:
++ return ALIGNOF_CORBA_LONG_DOUBLE;
++ case CORBA_tk_float:
++ return ALIGNOF_CORBA_FLOAT;
++ case CORBA_tk_double:
++ return ALIGNOF_CORBA_DOUBLE;
++ case CORBA_tk_boolean:
++ case CORBA_tk_char:
++ case CORBA_tk_octet:
++ return ALIGNOF_CORBA_CHAR;
++ case CORBA_tk_string:
++ case CORBA_tk_wstring:
++ case CORBA_tk_TypeCode:
++ case CORBA_tk_objref:
++ return ALIGNOF_CORBA_POINTER;
++ case CORBA_tk_sequence:
++ case CORBA_tk_any:
++ return MAX(MAX(ALIGNOF_CORBA_LONG, ALIGNOF_CORBA_STRUCT), ALIGNOF_CORBA_POINTER);
++ case CORBA_tk_array:
++ case CORBA_tk_alias:
++ return ORBit_find_alignment(tc->subtypes[0]);
++ case CORBA_tk_fixed:
++ return MAX(ALIGNOF_CORBA_SHORT, ALIGNOF_CORBA_STRUCT);
++ default:
++ return 1;
++ }
++}
++
++static void
++ORBit_marshal_value(GIOPSendBuffer *buf,
++ gpointer *val,
++ CORBA_TypeCode tc,
++ ORBit_marshal_value_info *mi)
++{
++ CORBA_unsigned_long i, ulval;
++ gpointer subval;
++ ORBit_marshal_value_info submi;
++
++#if 0
++ g_message("Marshalling a %d value from %#x to offset %d",
++ tc->kind, (gulong)*val,
++ GIOP_MESSAGE_BUFFER(buf)->message_header.message_size);
++#endif
++
++ switch(tc->kind) {
++ case CORBA_tk_wchar:
++ case CORBA_tk_ushort:
++ case CORBA_tk_short:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_SHORT);
++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(buf), *val, sizeof(CORBA_short));
++ *val = ((guchar *)*val) + sizeof(CORBA_short);
++ break;
++ case CORBA_tk_enum:
++ case CORBA_tk_long:
++ case CORBA_tk_ulong:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_LONG);
++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(buf), *val, sizeof(CORBA_long));
++ *val = ((guchar *)*val) + sizeof(CORBA_long);
++ break;
++ case CORBA_tk_float:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_FLOAT);
++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(buf), *val, sizeof(CORBA_float));
++ *val = ((guchar *)*val) + sizeof(CORBA_float);
++ break;
++ case CORBA_tk_double:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_DOUBLE);
++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(buf), *val, sizeof(CORBA_double));
++ *val = ((guchar *)*val) + sizeof(CORBA_double);
++ break;
++ case CORBA_tk_boolean:
++ case CORBA_tk_char:
++ case CORBA_tk_octet:
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(buf), *val, sizeof(CORBA_octet));
++ *val = ((guchar *)*val) + sizeof(CORBA_octet);
++ break;
++ case CORBA_tk_any:
++ *val = ALIGN_ADDRESS(*val, MAX(ALIGNOF_CORBA_STRUCT, ALIGNOF_CORBA_POINTER));
++ ORBit_marshal_any(buf, *val);
++ *val = ((guchar *)*val) + sizeof(CORBA_any);
++ break;
++ case CORBA_tk_TypeCode:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_POINTER);
++ ORBit_encode_CORBA_TypeCode(*val, buf);
++ *val = ((guchar *)*val) + sizeof(CORBA_TypeCode);
++ break;
++ case CORBA_tk_Principal:
++ *val = ALIGN_ADDRESS(*val,
++ MAX(MAX(ALIGNOF_CORBA_LONG, ALIGNOF_CORBA_STRUCT),
++ ALIGNOF_CORBA_POINTER));
++
++ ulval = *(CORBA_unsigned_long *)(*val);
++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(buf), *val, sizeof(CORBA_unsigned_long));
++
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(buf),
++ *(char**)((char *)*val+sizeof(CORBA_unsigned_long)),
++ ulval);
++ *val = ((guchar *)*val) + sizeof(CORBA_Principal);
++ break;
++ case CORBA_tk_objref:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_POINTER);
++ ORBit_marshal_object(buf, *val);
++ *val = ((guchar *)*val) + sizeof(CORBA_Object);
++ break;
++ case CORBA_tk_except:
++ case CORBA_tk_struct:
++ *val = ALIGN_ADDRESS(*val, ORBit_find_alignment(tc));
++ for(i = 0; i < tc->sub_parts; i++) {
++ ORBit_marshal_value(buf, val, tc->subtypes[i], mi);
++ }
++ break;
++ case CORBA_tk_union:
++ /* Basic algorithm:
++ marshal the discriminator
++ find out which value we want to use */
++ {
++ CORBA_TypeCode utc;
++
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_STRUCT);
++
++ utc = ORBit_get_union_tag(tc, val, TRUE);
++
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_STRUCT);
++
++ ORBit_marshal_value(buf, val, tc->discriminator, mi);
++ *val = ALIGN_ADDRESS(*val, ORBit_find_alignment(tc));
++ ORBit_marshal_value(buf, val, utc, mi);
++ }
++ break;
++ case CORBA_tk_wstring:
++ ulval = strlen(*(char **)*val) + 1;
++
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_POINTER);
++ giop_send_buffer_append_mem_indirect_a(buf,
++ &ulval,
++ sizeof(CORBA_unsigned_long));
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(buf), *(char **)*val, ulval);
++
++ *val = ((guchar *)*val) + sizeof(char *);
++ break;
++ case CORBA_tk_string:
++ ulval = strlen(*(char **)*val) + 1;
++
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_POINTER);
++
++ giop_send_buffer_append_mem_indirect_a(buf,
++ &ulval,
++ sizeof(CORBA_unsigned_long));
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(buf), *(char **)*val, ulval);
++
++ *val = ((guchar *)*val) + sizeof(char *);
++ break;
++ case CORBA_tk_sequence:
++ {
++ CORBA_sequence_octet *sval = *val;
++
++ *val = ALIGN_ADDRESS(*val,
++ MAX(MAX(ALIGNOF_CORBA_LONG, ALIGNOF_CORBA_STRUCT), ALIGNOF_CORBA_POINTER));
++
++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(buf),
++ &sval->_length,
++ sizeof(sval->_length));
++
++ subval = sval->_buffer;
++
++ for(i = 0; i < sval->_length; i++)
++ ORBit_marshal_value(buf, &subval, tc->subtypes[0], mi);
++
++ *val = ((guchar *)*val) + sizeof(CORBA_sequence_octet);
++ }
++ break;
++ case CORBA_tk_array:
++ submi.alias_element_type = tc->subtypes[0];
++ for(i = 0; i < tc->length; i++) {
++ ORBit_marshal_value(buf, val, submi.alias_element_type, &submi);
++ *val = ALIGN_ADDRESS(*val, ORBit_find_alignment(tc->subtypes[0]));
++ }
++ break;
++ case CORBA_tk_alias:
++ submi.alias_element_type = tc->subtypes[0];
++ ORBit_marshal_value(buf, val, submi.alias_element_type, &submi);
++ break;
++ case CORBA_tk_longlong:
++ case CORBA_tk_ulonglong:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_LONG_LONG);
++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(buf), *val, sizeof(CORBA_long_long));
++ return /* *val + sizeof(CORBA_long_long)*/;
++ break;
++ case CORBA_tk_longdouble:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_LONG_DOUBLE);
++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(buf), *val, sizeof(CORBA_long_double));
++ return /* *val + sizeof(CORBA_long_double)*/;
++ break;
++ case CORBA_tk_fixed:
++ /* XXX todo */
++ g_error("CORBA_fixed NYI");
++
++ break;
++ case CORBA_tk_null:
++ case CORBA_tk_void:
++ break;
++ default:
++ g_error("Can't encode unknown type %d", tc->kind);
++ }
++}
++
++static glong ORBit_get_union_switch(CORBA_TypeCode tc, gpointer *val, gboolean update)
++{
++#ifdef __KORBIT__
++ glong retval = 0;
++#else
++ glong retval;
++#endif
++
++ switch(tc->kind) {
++ case CORBA_tk_ulong:
++ case CORBA_tk_long:
++ case CORBA_tk_enum:
++ retval = *(CORBA_long *)*val;
++ if(update) *val += sizeof(CORBA_long);
++ break;
++ case CORBA_tk_ushort:
++ case CORBA_tk_short:
++ retval = *(CORBA_short *)*val;
++ if(update) *val += sizeof(CORBA_short);
++ break;
++ case CORBA_tk_char:
++ case CORBA_tk_boolean:
++ case CORBA_tk_octet:
++ retval = *(CORBA_octet *)*val;
++ if(update) *val += sizeof(CORBA_char);
++ break;
++ case CORBA_tk_alias:
++ return ORBit_get_union_switch(tc->subtypes[0], val, update);
++ break;
++ default:
++ g_error("Wow, some nut has passed us a weird type[%d] as a union discriminator!", tc->kind);
++ }
++
++ return retval;
++}
++
++/* This function (and the one above it) exist for the
++ sole purpose of finding out which CORBA_TypeCode a union discriminator value
++ indicates.
++
++ If {update} is TRUE, {*val} will be advanced by the native size
++ of the descriminator type.
++
++ Hairy stuff.
++*/
++CORBA_TypeCode
++ORBit_get_union_tag(CORBA_TypeCode union_tc, gpointer *val, gboolean update)
++{
++ glong discrim_val, case_val;
++ int i;
++ CORBA_TypeCode retval = CORBA_OBJECT_NIL;
++
++ discrim_val = ORBit_get_union_switch(union_tc->discriminator, val, update);
++
++ for(i = 0; i < union_tc->sub_parts; i++) {
++ if(i == union_tc->default_index)
++ continue;
++
++ case_val = ORBit_get_union_switch(union_tc->sublabels[i]._type,
++ &union_tc->sublabels[i]._value, FALSE);
++ if(case_val == discrim_val) {
++ retval = union_tc->subtypes[i];
++ break;
++ }
++ }
++
++ if(retval)
++ return retval;
++ else if(union_tc->default_index >= 0)
++ return union_tc->subtypes[union_tc->default_index];
++ else {
++ return TC_null;
++ }
++}
++
++void
++ORBit_marshal_arg(GIOPSendBuffer *buf,
++ gpointer val,
++ CORBA_TypeCode tc)
++{
++ ORBit_marshal_value_info mi;
++
++ ORBit_marshal_value(buf, &val, tc, &mi);
++}
++
++
++void
++ORBit_marshal_any(GIOPSendBuffer *buf, const CORBA_any *val)
++{
++ ORBit_marshal_value_info mi;
++
++ gpointer mval = val->_value;
++
++ ORBit_encode_CORBA_TypeCode(val->_type, buf);
++
++ ORBit_marshal_value(buf, &mval, val->_type, &mi);
++}
++
++size_t
++ORBit_gather_alloc_info(CORBA_TypeCode tc)
++{
++ int i, n, align=1, prevalign, sum, prev;
++ size_t block_size;
++
++ switch(tc->kind) {
++ case CORBA_tk_long:
++ case CORBA_tk_ulong:
++ case CORBA_tk_enum:
++ return sizeof(CORBA_long);
++ break;
++ case CORBA_tk_short:
++ case CORBA_tk_ushort:
++ return sizeof(CORBA_short);
++ break;
++ case CORBA_tk_float:
++ return sizeof(CORBA_float);
++ break;
++ case CORBA_tk_double:
++ return sizeof(CORBA_double);
++ break;
++ case CORBA_tk_boolean:
++ case CORBA_tk_char:
++ case CORBA_tk_octet:
++ return sizeof(CORBA_octet);
++ break;
++ case CORBA_tk_any:
++ return sizeof(CORBA_any);
++ break;
++ case CORBA_tk_TypeCode:
++ return sizeof(CORBA_TypeCode);
++ break;
++ case CORBA_tk_Principal:
++ return sizeof(CORBA_Principal);
++ break;
++ case CORBA_tk_objref:
++ return sizeof(CORBA_Object);
++ break;
++ case CORBA_tk_except:
++ case CORBA_tk_struct:
++ sum = 0;
++ for(i = 0; i < tc->sub_parts; i++) {
++ sum = GPOINTER_TO_INT(ALIGN_ADDRESS(sum, ORBit_find_alignment(tc->subtypes[i])));
++ sum += ORBit_gather_alloc_info(tc->subtypes[i]);
++ }
++ sum = GPOINTER_TO_INT(ALIGN_ADDRESS(sum, ORBit_find_alignment(tc)));
++ return sum;
++ break;
++ case CORBA_tk_union:
++ sum = ORBit_gather_alloc_info(tc->discriminator);
++ n = -1;
++ align = 1;
++ for(prev = prevalign = i = 0; i < tc->sub_parts; i++) {
++ prevalign = align;
++ align = ORBit_find_alignment(tc->subtypes[i]);
++ if(align > prevalign)
++ n = i;
++
++ prev = MAX(prev, ORBit_gather_alloc_info(tc->subtypes[i]));
++ }
++ if(n >= 0)
++ sum = GPOINTER_TO_INT(ALIGN_ADDRESS(sum, ORBit_find_alignment(tc->subtypes[n])));
++ sum += prev;
++ sum = GPOINTER_TO_INT(ALIGN_ADDRESS(sum, ORBit_find_alignment(tc)));
++ return sum;
++ break;
++ case CORBA_tk_wstring:
++ case CORBA_tk_string:
++ return sizeof(char *);
++ break;
++ case CORBA_tk_sequence:
++ return sizeof(CORBA_sequence_octet);
++ break;
++ case CORBA_tk_array:
++ block_size = ORBit_gather_alloc_info(tc->subtypes[0]);
++ return block_size * tc->length;
++ break;
++ case CORBA_tk_alias:
++ return ORBit_gather_alloc_info(tc->subtypes[0]);
++ case CORBA_tk_longlong:
++ case CORBA_tk_ulonglong:
++ return sizeof(CORBA_long_long);
++ case CORBA_tk_longdouble:
++ return sizeof(CORBA_long_double);
++ case CORBA_tk_wchar:
++ return sizeof(CORBA_wchar);
++ case CORBA_tk_fixed:
++ return sizeof(CORBA_fixed_d_s);
++ default:
++ return 0;
++ }
++}
++
++/* to allocate a block, we need to know of any important data
++ contained in it.
++*/
++static gpointer
++ORBit_demarshal_allocate_mem(CORBA_TypeCode tc, gint nelements)
++{
++ size_t block_size;
++ gpointer retval = NULL;
++
++ if(!nelements) return retval;
++
++ block_size = ORBit_gather_alloc_info(tc);
++
++ if(block_size) {
++ retval = ORBit_alloc_2(block_size * nelements,
++ (ORBit_free_childvals)ORBit_free_via_TypeCode,
++ GINT_TO_POINTER(nelements),
++ sizeof(CORBA_TypeCode));
++
++ *(CORBA_TypeCode *)((char *)retval-sizeof(ORBit_mem_info)-sizeof(CORBA_TypeCode)) = (CORBA_TypeCode)CORBA_Object_duplicate((CORBA_Object)tc, NULL);
++ }
++
++ return retval;
++}
++
++#define DM_GET_ATOM(x, n) G_STMT_START{ GIOP_RECV_BUFFER(buf)->decoder(x, (GIOP_RECV_BUFFER(buf)->cur), n); GIOP_RECV_BUFFER(buf)->cur = ((guchar *)GIOP_RECV_BUFFER(buf)->cur) + n; }G_STMT_END
++
++static void
++ORBit_demarshal_value(GIOPRecvBuffer *buf,
++ gpointer *val,
++ CORBA_TypeCode tc,
++ gboolean dup_strings,
++ CORBA_ORB orb)
++{
++ CORBA_long i, n;
++
++#if 0
++ g_message("Demarshalling a %d value from offset %d into %#x",
++ tc->kind, buf->cur - buf->message_body, (gulong)*val);
++#endif
++
++ switch(tc->kind) {
++ case CORBA_tk_short:
++ case CORBA_tk_ushort:
++ case CORBA_tk_wchar:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_SHORT);
++ buf->cur = ALIGN_ADDRESS(buf->cur, sizeof(CORBA_short));
++ DM_GET_ATOM(*val, sizeof(CORBA_short));
++ *val = ((guchar *)*val) + sizeof(CORBA_short);
++ break;
++ case CORBA_tk_long:
++ case CORBA_tk_ulong:
++ case CORBA_tk_enum:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_LONG);
++ buf->cur = ALIGN_ADDRESS(buf->cur, sizeof(CORBA_long));
++ DM_GET_ATOM(*val, sizeof(CORBA_long));
++ *val = ((guchar *)*val) + sizeof(CORBA_long);
++ break;
++ case CORBA_tk_longlong:
++ case CORBA_tk_ulonglong:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_LONG_LONG);
++ buf->cur = ALIGN_ADDRESS(buf->cur, sizeof(CORBA_long_long));
++ DM_GET_ATOM(*val, sizeof(CORBA_long_long));
++ *val = ((guchar *)*val) + sizeof(CORBA_long_long);
++ break;
++ case CORBA_tk_longdouble:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_LONG_DOUBLE);
++ buf->cur = ALIGN_ADDRESS(buf->cur, sizeof(CORBA_long_double));
++ DM_GET_ATOM(*val, sizeof(CORBA_long_double));
++ *val = ((guchar *)*val) + sizeof(CORBA_long_double);
++ break;
++ case CORBA_tk_float:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_FLOAT);
++ buf->cur = ALIGN_ADDRESS(buf->cur, sizeof(CORBA_float));
++ DM_GET_ATOM(*val, sizeof(CORBA_float));
++ *val = ((guchar *)*val) + sizeof(CORBA_float);
++ break;
++ case CORBA_tk_double:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_DOUBLE);
++ buf->cur = ALIGN_ADDRESS(buf->cur, sizeof(CORBA_double));
++ DM_GET_ATOM(*val, sizeof(CORBA_double));
++ *val = ((guchar *)*val) + sizeof(CORBA_double);
++ break;
++ case CORBA_tk_boolean:
++ case CORBA_tk_char:
++ case CORBA_tk_octet:
++ DM_GET_ATOM(*val, sizeof(CORBA_octet));
++ *val = ((guchar *)*val) + sizeof(CORBA_octet);
++ break;
++ case CORBA_tk_any:
++ {
++ CORBA_any *decoded;
++
++ *val = ALIGN_ADDRESS(*val,
++ MAX(ALIGNOF_CORBA_LONG,
++ MAX(ALIGNOF_CORBA_POINTER, ALIGNOF_CORBA_STRUCT)));
++ decoded = *val;
++ decoded->_release = CORBA_FALSE;
++ ORBit_demarshal_any(buf, decoded, dup_strings, orb);
++ *val = ((guchar *)*val) + sizeof(CORBA_any);
++ }
++ break;
++ case CORBA_tk_TypeCode:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_POINTER);
++ ORBit_decode_CORBA_TypeCode(*val, buf);
++ CORBA_Object_duplicate(*(CORBA_Object *)*val, NULL);
++ *val = ((guchar *)*val) + sizeof(CORBA_TypeCode);
++ break;
++ case CORBA_tk_Principal:
++ {
++ CORBA_Principal *p;
++
++ *val = ALIGN_ADDRESS(*val, MAX(ALIGNOF_CORBA_STRUCT,
++ MAX(ALIGNOF_CORBA_LONG, ALIGNOF_CORBA_POINTER)));
++
++ p = *val;
++ buf->cur = ALIGN_ADDRESS(buf->cur, sizeof(CORBA_long));
++ CORBA_sequence_set_release(p, dup_strings);
++ DM_GET_ATOM(&p->_length, sizeof(CORBA_long));
++ p->_buffer = ORBit_alloc(p->_length, NULL, GINT_TO_POINTER(1));
++ memcpy(p->_buffer, buf->cur, p->_length);
++ buf->cur = ((guchar *)buf->cur) + p->_length;
++ *val = ((guchar *)*val) + sizeof(CORBA_sequence_octet);
++ }
++ break;
++ case CORBA_tk_objref:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_POINTER);
++ *(CORBA_Object *)*val = ORBit_demarshal_object(buf, orb);
++ *val = ((guchar *)*val) + sizeof(CORBA_Object);
++ break;
++ case CORBA_tk_except:
++ case CORBA_tk_struct:
++ *val = ALIGN_ADDRESS(*val, ORBit_find_alignment(tc));
++ for(i = 0; i < tc->sub_parts; i++) {
++ ORBit_demarshal_value(buf, val, tc->subtypes[i], dup_strings, orb);
++ }
++ break;
++ case CORBA_tk_union:
++ {
++ gpointer discrimptr;
++
++ discrimptr = *val = ALIGN_ADDRESS(*val, ORBit_find_alignment(tc));
++ ORBit_demarshal_value(buf, val, tc->discriminator, dup_strings, orb);
++ n = 1;
++ for(i = 0; i < tc->sub_parts; i++) {
++ n = MAX(n, ORBit_find_alignment(tc->subtypes[i]));
++ }
++ *val = ALIGN_ADDRESS(*val, n);
++ ORBit_demarshal_value(buf, val,
++ ORBit_get_union_tag(tc, &discrimptr, FALSE),
++ dup_strings, orb);
++ }
++ break;
++ case CORBA_tk_string:
++ case CORBA_tk_wstring:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_POINTER);
++ buf->cur = ALIGN_ADDRESS(buf->cur, sizeof(CORBA_long));
++ DM_GET_ATOM(&i, sizeof(CORBA_long));
++ if(dup_strings)
++ *(char **)*val = CORBA_string_dup(buf->cur);
++ else
++ *(char **)*val = buf->cur;
++ *val = ((guchar *)*val) + sizeof(CORBA_char *);
++ buf->cur = (gpointer)((char *)buf->cur + i);
++ break;
++ case CORBA_tk_sequence:
++ {
++ CORBA_sequence_octet *p;
++ gpointer subval;
++
++ *val = ALIGN_ADDRESS(*val, MAX(ALIGNOF_CORBA_STRUCT,
++ MAX(ALIGNOF_CORBA_LONG, ALIGNOF_CORBA_POINTER)));
++ p = *val;
++ buf->cur = ALIGN_ADDRESS(buf->cur, sizeof(CORBA_long));
++ DM_GET_ATOM(&p->_length, sizeof(CORBA_long));
++ if(tc->subtypes[0]->kind == CORBA_tk_octet
++ || tc->subtypes[0]->kind == CORBA_tk_boolean
++ || tc->subtypes[0]->kind == CORBA_tk_char) {
++ /* This special-casing could be taken further to apply to
++ all atoms... */
++ p->_buffer = ORBit_alloc(p->_length, NULL, GINT_TO_POINTER(1));
++ memcpy(p->_buffer, buf->cur, p->_length);
++ buf->cur = ((guchar *)buf->cur) + p->_length;
++ } else {
++ p->_buffer = ORBit_demarshal_allocate_mem(tc->subtypes[0],
++ p->_length);
++ subval = p->_buffer;
++
++ for(i = 0; i < p->_length; i++)
++ ORBit_demarshal_value(buf, &subval,
++ tc->subtypes[0],
++ dup_strings,
++ orb);
++ }
++
++ *val = ((guchar *)*val) + sizeof(CORBA_sequence_octet);
++ }
++ break;
++ case CORBA_tk_array:
++ for(i = 0; i < tc->length; i++)
++ ORBit_demarshal_value(buf, val, tc->subtypes[0], dup_strings, orb);
++ break;
++ case CORBA_tk_alias:
++ ORBit_demarshal_value(buf, val, tc->subtypes[0], dup_strings, orb);
++ break;
++ case CORBA_tk_fixed:
++ g_error("CORBA_fixed NYI");
++ break;
++ default:
++ break;
++ }
++}
++
++gpointer
++ORBit_demarshal_arg(GIOPRecvBuffer *buf,
++ CORBA_TypeCode tc,
++ gboolean dup_strings,
++ CORBA_ORB orb)
++{
++ gpointer retval, val;
++
++ retval = val = ORBit_demarshal_allocate_mem(tc, 1);
++
++ ORBit_demarshal_value(buf, &val, tc, dup_strings, orb);
++
++ return retval;
++}
++
++void
++ORBit_demarshal_any(GIOPRecvBuffer *buf, CORBA_any *retval,
++ gboolean dup_strings,
++ CORBA_ORB orb)
++{
++ gpointer val;
++
++#if 0
++ /* I wish I knew whether this was correct or not. It breaks things like 'any anop();' for sure,
++ since we can't always initialize every single possible 'any' underneath _ORBIT_retval */
++ if(retval->_release)
++ CORBA_free(retval->_value);
++#endif
++
++ CORBA_any_set_release(retval, CORBA_TRUE);
++
++ ORBit_decode_CORBA_TypeCode(&retval->_type, buf);
++ CORBA_Object_duplicate((CORBA_Object)retval->_type, NULL);
++
++ val = retval->_value = ORBit_demarshal_allocate_mem(retval->_type, 1);
++ ORBit_demarshal_value(buf, &val, retval->_type, dup_strings, orb);
++}
++
++void
++_ORBit_copy_value(gpointer *val, gpointer *newval, CORBA_TypeCode tc)
++{
++ CORBA_long i;
++ gpointer pval1, pval2;
++
++ switch(tc->kind) {
++ case CORBA_tk_wchar:
++ case CORBA_tk_short:
++ case CORBA_tk_ushort:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_SHORT);
++ *newval = ALIGN_ADDRESS(*newval, ALIGNOF_CORBA_SHORT);
++ *(CORBA_short *)*newval = *(CORBA_short *)*val;
++ *val = ((guchar *)*val) + sizeof(CORBA_short);
++ *newval = ((guchar *)*newval) + sizeof(CORBA_short);
++ break;
++ case CORBA_tk_enum:
++ case CORBA_tk_long:
++ case CORBA_tk_ulong:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_LONG);
++ *newval = ALIGN_ADDRESS(*newval, ALIGNOF_CORBA_LONG);
++ *(CORBA_long *)*newval = *(CORBA_long *)*val;
++ *val = ((guchar *)*val) + sizeof(CORBA_long);
++ *newval = ((guchar *)*newval) + sizeof(CORBA_long);
++ break;
++ case CORBA_tk_longlong:
++ case CORBA_tk_ulonglong:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_LONG_LONG);
++ *newval = ALIGN_ADDRESS(*newval, ALIGNOF_CORBA_LONG_LONG);
++ *(CORBA_long_long *)*newval = *(CORBA_long_long *)*val;
++ *val = ((guchar *)*val) + sizeof(CORBA_long_long);
++ *newval = ((guchar *)*newval) + sizeof(CORBA_long_long);
++ break;
++ case CORBA_tk_longdouble:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_LONG_DOUBLE);
++ *newval = ALIGN_ADDRESS(*newval, ALIGNOF_CORBA_LONG_DOUBLE);
++ *(CORBA_long_double *)*newval = *(CORBA_long_double *)*val;
++ *val = ((guchar *)*val) + sizeof(CORBA_long_double);
++ *newval = ((guchar *)*newval) + sizeof(CORBA_long_double);
++ break;
++ case CORBA_tk_float:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_FLOAT);
++ *newval = ALIGN_ADDRESS(*newval, ALIGNOF_CORBA_FLOAT);
++ *(CORBA_long *)*newval = *(CORBA_long *)*val;
++ *val = ((guchar *)*val) + sizeof(CORBA_float);
++ *newval = ((guchar *)*newval) + sizeof(CORBA_float);
++ break;
++ case CORBA_tk_double:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_DOUBLE);
++ *newval = ALIGN_ADDRESS(*newval, ALIGNOF_CORBA_DOUBLE);
++ *(CORBA_double *)*newval = *(CORBA_double *)*val;
++ *val = ((guchar *)*val) + sizeof(CORBA_double);
++ *newval = ((guchar *)*newval) + sizeof(CORBA_double);
++ break;
++ case CORBA_tk_boolean:
++ case CORBA_tk_char:
++ case CORBA_tk_octet:
++ *(CORBA_octet *)*newval = *(CORBA_octet *)*val;
++ *val = ((guchar *)*val) + sizeof(CORBA_octet);
++ *newval = ((guchar *)*newval) + sizeof(CORBA_octet);
++ break;
++ case CORBA_tk_any:
++ {
++ CORBA_any *oldany, *newany;
++ *val = ALIGN_ADDRESS(*val, MAX(ALIGNOF_CORBA_STRUCT, ALIGNOF_CORBA_POINTER));
++ *newval = ALIGN_ADDRESS(*newval, MAX(ALIGNOF_CORBA_STRUCT, ALIGNOF_CORBA_POINTER));
++ oldany = *val;
++ newany = *newval;
++ newany->_type = (CORBA_TypeCode)CORBA_Object_duplicate((CORBA_Object)oldany->_type, NULL);
++ /* XXX are we supposed to do this even if oldany->_release
++ == FALSE? */
++ newany->_value = ORBit_copy_value(oldany->_value, oldany->_type);
++ newany->_release = CORBA_TRUE;
++ *val = ((guchar *)*val) + sizeof(CORBA_any);
++ *newval = ((guchar *)*newval) + sizeof(CORBA_any);
++ }
++ break;
++ case CORBA_tk_Principal:
++ *val = ALIGN_ADDRESS(*val,
++ MAX(MAX(ALIGNOF_CORBA_LONG,
++ ALIGNOF_CORBA_STRUCT),
++ ALIGNOF_CORBA_POINTER));
++ *newval = ALIGN_ADDRESS(*newval,
++ MAX(MAX(ALIGNOF_CORBA_LONG,
++ ALIGNOF_CORBA_STRUCT),
++ ALIGNOF_CORBA_POINTER));
++ *(CORBA_Principal *)*newval = *(CORBA_Principal *)*val;
++ ((CORBA_Principal *)*newval)->_buffer =
++ CORBA_octet_allocbuf(((CORBA_Principal *)*newval)->_length);
++ memcpy(((CORBA_Principal *)*newval)->_buffer,
++ ((CORBA_Principal *)*val)->_buffer,
++ ((CORBA_Principal *)*val)->_length);
++ *val = ((guchar *)*val) + sizeof(CORBA_Principal);
++ *newval = ((guchar *)*newval) + sizeof(CORBA_Principal);
++ break;
++ case CORBA_tk_TypeCode:
++ case CORBA_tk_objref:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_POINTER);
++ *newval = ALIGN_ADDRESS(*newval, ALIGNOF_CORBA_POINTER);
++ *(CORBA_Object *)*newval = CORBA_Object_duplicate(*(CORBA_Object *)*val,
++ NULL);
++ *val = ((guchar *)*val) + sizeof(CORBA_Object);
++ *newval = ((guchar *)*newval) + sizeof(CORBA_Object);
++ break;
++ case CORBA_tk_struct:
++ case CORBA_tk_except:
++ *val = ALIGN_ADDRESS(*val, ORBit_find_alignment(tc));
++ *newval = ALIGN_ADDRESS(*newval, ORBit_find_alignment(tc));
++ for(i = 0; i < tc->sub_parts; i++) {
++ _ORBit_copy_value(val, newval, tc->subtypes[i]);
++ }
++ break;
++ case CORBA_tk_union:
++ {
++ CORBA_TypeCode utc = ORBit_get_union_tag(tc, val, FALSE);
++ gint union_align = ORBit_find_alignment(tc);
++ size_t union_size = ORBit_gather_alloc_info(tc);
++
++ /* need to advance val,newval by size of union, not just
++ * current tagged field within it */
++ pval1 = *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_STRUCT);
++ pval2 = *newval = ALIGN_ADDRESS(*newval, ALIGNOF_CORBA_STRUCT);
++ _ORBit_copy_value(&pval1, &pval2, tc->discriminator);
++ pval1 = ALIGN_ADDRESS(pval1, union_align);
++ pval2 = ALIGN_ADDRESS(pval2, union_align);
++ _ORBit_copy_value(&pval1, &pval2, utc);
++ *val = ((guchar *)*val) + union_size;
++ *newval = ((guchar *)*newval) + union_size;
++ }
++ break;
++ case CORBA_tk_wstring:
++ case CORBA_tk_string:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_POINTER);
++ *newval = ALIGN_ADDRESS(*newval, ALIGNOF_CORBA_POINTER);
++
++ *(CORBA_char **)*newval = CORBA_string_dup(*(CORBA_char **)*val);
++ *val = ((guchar *)*val) + sizeof(CORBA_char *);
++ *newval = ((guchar *)*newval) + sizeof(CORBA_char *);
++ break;
++ case CORBA_tk_sequence:
++ *val = ALIGN_ADDRESS(*val,
++ MAX(MAX(ALIGNOF_CORBA_LONG,
++ ALIGNOF_CORBA_STRUCT),
++ ALIGNOF_CORBA_POINTER));
++ *newval = ALIGN_ADDRESS(*newval,
++ MAX(MAX(ALIGNOF_CORBA_LONG,
++ ALIGNOF_CORBA_STRUCT),
++ ALIGNOF_CORBA_POINTER));
++ ((CORBA_Principal *)*newval)->_release = CORBA_TRUE;
++ ((CORBA_Principal *)*newval)->_length =
++ ((CORBA_Principal *)*newval)->_maximum =
++ ((CORBA_Principal *)*val)->_length;
++ ((CORBA_Principal *)*newval)->_buffer = pval2 =
++ ORBit_demarshal_allocate_mem(tc->subtypes[0],
++ ((CORBA_Principal *)*val)->_length);
++ pval1 = ((CORBA_Principal *)*val)->_buffer;
++
++ for(i = 0; i < ((CORBA_Principal *)*newval)->_length; i++) {
++ _ORBit_copy_value(&pval1, &pval2, tc->subtypes[0]);
++ }
++ *val = ((guchar *)*val) + sizeof(CORBA_sequence_octet);
++ *newval = ((guchar *)*newval) + sizeof(CORBA_sequence_octet);
++ break;
++ case CORBA_tk_array:
++ for(i = 0; i < tc->length; i++) {
++ _ORBit_copy_value(val, newval, tc->subtypes[0]);
++ }
++ break;
++ case CORBA_tk_alias:
++ _ORBit_copy_value(val, newval, tc->subtypes[0]);
++ break;
++ case CORBA_tk_fixed:
++ g_error("CORBA_fixed NYI!");
++ break;
++ case CORBA_tk_void:
++ case CORBA_tk_null:
++ *val = NULL;
++ break;
++ default:
++ g_error("Can't handle copy of value kind %d", tc->kind);
++ }
++}
++
++gpointer
++ORBit_copy_value(gpointer value, CORBA_TypeCode tc)
++{
++ gpointer retval, newval;
++
++ retval = newval = ORBit_demarshal_allocate_mem(tc, 1);
++ _ORBit_copy_value(&value, &newval, tc);
++
++ return retval;
++}
++
++void
++CORBA_any__copy(CORBA_any *out, CORBA_any *in)
++{
++ out->_type = (CORBA_TypeCode)CORBA_Object_duplicate((CORBA_Object)in->_type,
++ NULL);
++ out->_value = ORBit_copy_value(in->_value, in->_type);
++ out->_release = CORBA_TRUE;
++}
+diff -urN linux-2.4.1/net/korbit/orb/corba_any.h linux-2.4.1-korbit/net/korbit/orb/corba_any.h
+--- linux-2.4.1/net/korbit/orb/corba_any.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_any.h Thu Feb 1 16:20:50 2001
+@@ -0,0 +1,45 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_ANY_H_
++#define _ORBIT_CORBA_ANY_H_
++
++#include "orbit_types.h"
++#include "corba_typecode.h"
++
++#include <unistd.h>
++
++typedef struct CORBA_any_type CORBA_any;
++
++size_t ORBit_gather_alloc_info(CORBA_TypeCode tc);
++gint ORBit_find_alignment(CORBA_TypeCode tc);
++CORBA_TypeCode ORBit_get_union_tag(CORBA_TypeCode union_tc,
++ gpointer *val, gboolean update);
++gpointer ORBit_copy_value(gpointer value, CORBA_TypeCode tc);
++void _ORBit_copy_value(gpointer *val, gpointer *newval, CORBA_TypeCode tc);
++
++void CORBA_any__copy(CORBA_any *out, CORBA_any *in);
++
++#endif /* !_ORBIT_CORBA_ANY_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/corba_any_proto.h linux-2.4.1-korbit/net/korbit/orb/corba_any_proto.h
+--- linux-2.4.1/net/korbit/orb/corba_any_proto.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_any_proto.h Thu Feb 1 11:47:11 2001
+@@ -0,0 +1,16 @@
++#ifndef _ORBIT_CORBA_ANY_PROTO_H_
++#define _ORBIT_CORBA_ANY_PROTO_H_
++
++void ORBit_marshal_arg(GIOPSendBuffer *buf,
++ gpointer val,
++ CORBA_TypeCode tc);
++void ORBit_marshal_any(GIOPSendBuffer *buf, const CORBA_any *val);
++gpointer ORBit_demarshal_arg(GIOPRecvBuffer *buf,
++ CORBA_TypeCode tc,
++ gboolean dup_strings,
++ CORBA_ORB orb);
++void ORBit_demarshal_any(GIOPRecvBuffer *buf, CORBA_any *retval,
++ gboolean dup_strings,
++ CORBA_ORB orb);
++
++#endif /* !_ORBIT_CORBA_ANY_PROTO_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/corba_any_type.h linux-2.4.1-korbit/net/korbit/orb/corba_any_type.h
+--- linux-2.4.1/net/korbit/orb/corba_any_type.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_any_type.h Thu Feb 1 16:20:50 2001
+@@ -0,0 +1,48 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@acm.org>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_ANY_TYPE_H_
++#define _ORBIT_CORBA_ANY_TYPE_H_
++
++#include "corba_any.h"
++#include "corba_typecode.h"
++
++struct CORBA_any_type {
++ CORBA_TypeCode _type;
++ gpointer _value;
++ CORBA_boolean _release;
++};
++
++typedef struct ORBit_marshal_value_info_struct {
++ CORBA_TypeCode alias_element_type;
++} ORBit_marshal_value_info;
++
++#define CORBA_ANYFLAGS_RELEASE 1
++
++
++#endif /* !_ORBIT_CORBA_ANY_TYPE_H_ */
++
++
++
+diff -urN linux-2.4.1/net/korbit/orb/corba_basic_sequences_type.h linux-2.4.1-korbit/net/korbit/orb/corba_basic_sequences_type.h
+--- linux-2.4.1/net/korbit/orb/corba_basic_sequences_type.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_basic_sequences_type.h Thu Feb 1 11:47:11 2001
+@@ -0,0 +1,43 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_BASIC_SEQUENCES_TYPE_H_
++#define _ORBIT_CORBA_BASIC_SEQUENCES_TYPE_H_
++
++#include <ORBitutil/basic_types.h>
++
++#ifndef _CORBA_sequence_octet_defined
++#define _CORBA_sequence_octet_defined 1
++
++typedef struct CORBA_sequence_octet_struct {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ CORBA_octet *_buffer;
++ CORBA_boolean _release;
++} CORBA_sequence_octet;
++#endif /* !_CORBA_sequence_octet_defined */
++
++#include <orb/corba_sequences.h>
++#endif /* !_ORBIT_CORBA_BASIC_SEQUENCES_TYPE_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/corba_context.c linux-2.4.1-korbit/net/korbit/orb/corba_context.c
+--- linux-2.4.1/net/korbit/orb/corba_context.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_context.c Thu Feb 1 11:47:11 2001
+@@ -0,0 +1,390 @@
++#include "orb/orbit.h"
++
++#define o_return_val_if_fail(expr, val) if(!(expr)) { CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM, CORBA_COMPLETED_NO); return (val); }
++#define o_return_if_fail(expr) if(!(expr)) { CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM, CORBA_COMPLETED_NO); return; }
++
++static gboolean
++free_entry(gpointer key, gpointer value, gpointer user_data)
++{
++ g_free(key);
++ g_free(value);
++
++ return TRUE;
++}
++
++static void
++ORBit_Context_release(CORBA_Context ctx, CORBA_Environment *ev);
++
++static gboolean
++free_child(gpointer value, gpointer user_data)
++{
++ CORBA_Context ctx = value;
++
++ ORBIT_ROOT_OBJECT(ctx)->refs = 1;
++ ctx->parent_ctx = CORBA_OBJECT_NIL;
++ ORBit_Context_release(ctx, NULL);
++
++ return TRUE;
++}
++
++static void
++ORBit_Context_release(CORBA_Context ctx,
++ CORBA_Environment *ev)
++{
++ ORBIT_ROOT_OBJECT_UNREF(ctx);
++
++ if(ORBIT_ROOT_OBJECT(ctx)->refs <= 0) {
++ if(ctx->children) {
++ g_slist_foreach(ctx->children, (GFunc)free_child, ctx);
++ g_slist_free(ctx->children);
++ }
++
++ if(ctx->mappings) {
++ g_hash_table_foreach_remove(ctx->mappings, free_entry, ctx);
++ g_hash_table_destroy(ctx->mappings);
++ }
++
++ if(ctx->parent_ctx != CORBA_OBJECT_NIL)
++ ctx->parent_ctx->children = g_slist_remove(ctx->parent_ctx->children, ctx->the_name);
++
++ g_free(ctx->the_name);
++
++ g_free(ctx);
++ }
++}
++
++static const ORBit_RootObject_Interface CORBA_Context_epv =
++{
++ (void (*)(gpointer, CORBA_Environment *))ORBit_Context_release,
++};
++
++static CORBA_Context
++CORBA_Context_new(CORBA_Context parent, const char *name, CORBA_Environment *ev)
++{
++ CORBA_Context retval;
++
++ retval = g_new0(struct CORBA_Context_type, 1);
++
++ ORBit_pseudo_object_init(ORBIT_PSEUDO_OBJECT(retval), ORBIT_PSEUDO_CONTEXT, ev);
++
++ ORBIT_ROOT_OBJECT(retval)->refs = 0;
++ ORBit_RootObject_set_interface(ORBIT_ROOT_OBJECT(retval), (gpointer)&CORBA_Context_epv, ev);
++
++ if(name)
++ retval->the_name = g_strdup(name);
++
++ retval->parent_ctx = parent;
++ if(parent)
++ parent->children = g_slist_prepend(parent->children, retval);
++
++ return retval;
++}
++
++/* Section 5.6.1 */
++CORBA_Status CORBA_ORB_get_default_context(CORBA_ORB orb, CORBA_Context *ctx, CORBA_Environment *ev)
++{
++ g_return_if_fail(ev != NULL);
++ o_return_if_fail(orb && ctx);
++
++ if(!orb->default_ctx)
++ orb->default_ctx = CORBA_Context_new(CORBA_OBJECT_NIL, NULL, ev);
++
++ *ctx = (CORBA_Context)CORBA_Object_duplicate((CORBA_Object)orb->default_ctx, ev);
++}
++
++/********* XXX todo - CORBA_Context support */
++CORBA_Status CORBA_Context_set_one_value(CORBA_Context ctx, CORBA_Identifier prop_name, char *value, CORBA_Environment *ev)
++{
++ gpointer old_nom, old_value;
++ g_return_if_fail(ev != NULL);
++ o_return_if_fail(ctx && prop_name && value);
++
++ if(!ctx->mappings)
++ ctx->mappings = g_hash_table_new(g_str_hash, g_str_equal);
++
++ if(g_hash_table_lookup_extended(ctx->mappings, prop_name, &old_nom, &old_value)) {
++ g_free(old_nom);
++ g_free(old_value);
++ }
++
++ g_hash_table_insert(ctx->mappings, g_strdup(prop_name), g_strdup(value));
++}
++
++/* Section 5.6.3 */
++CORBA_Status CORBA_Context_set_values(CORBA_Context ctx, CORBA_NVList *values, CORBA_Environment *ev)
++{
++ int i;
++
++ for(i = 0; i < values->list->len; i++) {
++ CORBA_NamedValue *nvp;
++
++ nvp = ((CORBA_NamedValue *)values->list->data) + i;
++
++ g_assert(nvp->argument._type == TC_string);
++
++ CORBA_Context_set_one_value(ctx, nvp->name, nvp->argument._value, ev);
++ }
++}
++
++/* Section 5.6.4 */
++
++typedef struct {
++ CORBA_Context ctx;
++ CORBA_Identifier prop_name;
++ CORBA_NVList *values;
++ CORBA_Environment *ev;
++ int len;
++} CTXSearchInfo;
++
++static gboolean
++list_has_key(CORBA_NVList *list, const char *key)
++{
++ int i;
++
++ for(i = 0; i < list->list->len; i++) {
++ CORBA_NamedValue *nvp;
++
++ nvp = ((CORBA_NamedValue *)list->list->data) + i;
++
++ if(!strcmp(nvp->name, key))
++ return TRUE;
++ }
++
++ return FALSE;
++}
++
++static void
++search_props(gpointer key, gpointer value, CTXSearchInfo *csi)
++{
++ if(strncmp(key, csi->prop_name, csi->len))
++ return;
++
++ if(list_has_key(csi->values, key))
++ return;
++
++ CORBA_NVList_add_item(csi->values, key, TC_string, &value, strlen(value) + 1, CORBA_IN_COPY_VALUE, NULL);
++}
++
++static void
++ctx_get_values(CORBA_Context ctx, CORBA_Flags op_flags,
++ CORBA_Identifier prop_name, CORBA_NVList **values,
++ gint is_wc,
++ CORBA_Environment *ev)
++{
++ gboolean go_up = FALSE;
++
++ if(is_wc >= 0) {
++ CTXSearchInfo csi;
++
++ csi.ctx = ctx;
++ csi.prop_name = prop_name;
++ csi.values = *values;
++ csi.ev = ev;
++ csi.len = is_wc;
++
++ if(ctx->mappings)
++ g_hash_table_foreach(ctx->mappings, (GHFunc)search_props, &csi);
++
++ go_up = TRUE;
++
++ } else {
++ char *val = NULL;
++
++ if(ctx->mappings)
++ val = g_hash_table_lookup(ctx->mappings, prop_name);
++
++ if(val)
++ CORBA_NVList_add_item(*values, prop_name, TC_string, &val, strlen(val) + 1, CORBA_IN_COPY_VALUE, ev);
++ else
++ go_up = TRUE;
++ }
++
++ if(go_up
++ && ctx->parent_ctx
++ && !(op_flags & CORBA_CTX_RESTRICT_SCOPE))
++ ctx_get_values(ctx->parent_ctx, op_flags, prop_name, values, is_wc, ev);
++}
++
++CORBA_Status CORBA_Context_get_values(CORBA_Context ctx,
++ CORBA_Identifier start_scope,
++ CORBA_Flags op_flags,
++ CORBA_Identifier prop_name,
++ CORBA_NVList **values,
++ CORBA_Environment *ev)
++{
++ char *ctmp;
++ int wc_pos;
++
++ CORBA_ORB_create_list(CORBA_OBJECT_NIL, 0, values, ev);
++
++ if(start_scope && *start_scope) {
++ while(ctx && (!ctx->the_name || strcmp(ctx->the_name, start_scope)))
++ ctx = ctx->parent_ctx;
++
++ if(!ctx) {
++ CORBA_exception_set_system(ev, ex_CORBA_INV_IDENT, CORBA_COMPLETED_NO);
++ return;
++ }
++ }
++
++ ctmp = strchr(prop_name, '*');
++ if(ctmp)
++ wc_pos = ctmp - prop_name;
++ else
++ wc_pos = -1;
++
++ CORBA_ORB_create_list(CORBA_OBJECT_NIL, 0, values, ev);
++
++ ctx_get_values(ctx, op_flags, prop_name, values, (prop_name[strlen(prop_name) - 1] == '*'), ev);
++
++ if((*values)->list->len == 0)
++ {
++ CORBA_NVList_free(*values, ev);
++ *values = NULL;
++ CORBA_exception_set_system(ev, ex_CORBA_UNKNOWN, CORBA_COMPLETED_NO);
++ }
++}
++
++/* Section 5.6.5 */
++static void
++delete_props(gpointer key, gpointer value, CTXSearchInfo *csi)
++{
++ if(strncmp(key, csi->prop_name, csi->len))
++ return;
++
++ g_hash_table_remove(csi->ctx->mappings, key);
++ g_free(key);
++ g_free(value);
++}
++
++CORBA_Status CORBA_Context_delete_values(CORBA_Context ctx, CORBA_Identifier prop_name, CORBA_Environment *ev)
++{
++ char *ctmp;
++ int wc_pos;
++
++ if(!ctx->mappings)
++ return;
++
++ ctmp = strchr(prop_name, '*');
++ if(ctmp)
++ wc_pos = ctmp - prop_name;
++ else
++ wc_pos = -1;
++
++ if(wc_pos >= 0) {
++ CTXSearchInfo csi;
++
++ memset(&csi, 0, sizeof(csi));
++ csi.ctx = ctx;
++ csi.prop_name = prop_name;
++ csi.ev = ev;
++ csi.len = wc_pos;
++
++ g_hash_table_foreach(ctx->mappings, (GHFunc)delete_props, &csi);
++ } else {
++ gpointer old_nom, old_value;
++
++ if(g_hash_table_lookup_extended(ctx->mappings, prop_name, &old_nom, &old_value)) {
++ g_free(old_nom);
++ g_free(old_value);
++ }
++ }
++}
++
++/* Section 5.6.6 */
++CORBA_Status CORBA_Context_create_child(CORBA_Context ctx, CORBA_Identifier ctx_name, CORBA_Context *child_ctx, CORBA_Environment *ev)
++{
++ *child_ctx = CORBA_Context_new(ctx, ctx_name, ev);
++}
++
++/* Section 5.6.7 */
++CORBA_Status CORBA_Context_delete(CORBA_Context ctx, CORBA_Flags del_flags, CORBA_Environment *ev)
++{
++ if((del_flags & CORBA_CTX_DELETE_DESCENDENTS)
++ || !ctx->children)
++ free_child(ctx, NULL);
++}
++
++void
++ORBit_Context_marshal(CORBA_Context ctx, const ORBit_ContextMarshalItem *mlist, CORBA_unsigned_long nitems, GIOPSendBuffer *buf)
++{
++ int i;
++ CORBA_unsigned_long *real_nitems, ltmp;
++
++ real_nitems = giop_send_buffer_append_mem_indirect_a(buf, &nitems, sizeof(nitems));
++ if(!ctx->mappings) {
++ *real_nitems = 0;
++ return;
++ }
++
++ for(*real_nitems = i = 0; i < nitems; i++) {
++ char *value;
++
++ value = g_hash_table_lookup(ctx->mappings, mlist[i].str);
++ if(!value)
++ continue;
++
++ /* Key */
++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(buf), &(mlist[i].len), sizeof(mlist[i].len));
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(buf), mlist[i].str, mlist[i].len);
++ (*real_nitems)++;
++
++ /* Value */
++ ltmp = strlen(value) + 1;
++ giop_send_buffer_append_mem_indirect_a(buf, &ltmp, sizeof(ltmp));
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(buf), value, ltmp);
++ (*real_nitems)++;
++ }
++}
++
++#define GET_ATOM(x) G_STMT_START{ GIOP_RECV_BUFFER(recv_buffer)->decoder(&x, (GIOP_RECV_BUFFER(recv_buffer)->cur), sizeof(x)); \
++GIOP_RECV_BUFFER(recv_buffer)->cur = ((guchar *)GIOP_RECV_BUFFER(recv_buffer)->cur) + sizeof(x); \
++}G_STMT_END
++#define ALIGNFOR(x) recv_buffer->cur = ALIGN_ADDRESS(recv_buffer->cur, sizeof(x))
++
++void
++ORBit_Context_demarshal(CORBA_Context parent, CORBA_Context initme, GIOPRecvBuffer *recv_buffer)
++{
++ CORBA_unsigned_long nstrings, keylen, vallen, i;
++ char *key, *value;
++
++ memset(initme, 0, sizeof(struct CORBA_Context_type));
++ ORBIT_ROOT_OBJECT(initme)->refs = -1;
++
++ initme->parent_ctx = parent;
++
++ ALIGNFOR(nstrings);
++ GET_ATOM(nstrings);
++
++ if(nstrings)
++ initme->mappings = g_hash_table_new(g_str_hash, g_str_equal);
++ else
++ return;
++
++ g_hash_table_freeze(initme->mappings);
++ for(i = 0; i < nstrings; ) {
++ ALIGNFOR(keylen);
++ GET_ATOM(keylen);
++ key = recv_buffer->cur;
++ recv_buffer->cur = ((char *)recv_buffer->cur) + keylen;
++ i++;
++
++ if(i >= nstrings)
++ break;
++
++ ALIGNFOR(vallen);
++ GET_ATOM(vallen);
++ value = recv_buffer->cur;
++ recv_buffer->cur = ((char *)recv_buffer->cur) + vallen;
++ i++;
++
++ g_hash_table_insert(initme->mappings, key, value);
++ }
++ g_hash_table_thaw(initme->mappings);
++}
++
++void
++ORBit_Context_server_free(CORBA_Context ctx)
++{
++ g_hash_table_destroy(ctx->mappings);
++}
+diff -urN linux-2.4.1/net/korbit/orb/corba_context.h linux-2.4.1-korbit/net/korbit/orb/corba_context.h
+--- linux-2.4.1/net/korbit/orb/corba_context.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_context.h Thu Feb 1 16:20:50 2001
+@@ -0,0 +1,65 @@
++#ifndef CORBA_CONTEXT_H
++#define CORBA_CONTEXT_H 1
++
++#include "orbit_object_type.h"
++#include "orbit_object.h"
++
++typedef struct {
++ CORBA_unsigned_long len;
++ const CORBA_char *str;
++} ORBit_ContextMarshalItem;
++
++typedef struct CORBA_Context_type *CORBA_Context;
++
++struct CORBA_Context_type {
++ struct ORBit_PseudoObject_struct parent;
++ GHashTable *mappings;
++ GSList *children;
++
++ char *the_name;
++
++ CORBA_Context parent_ctx;
++};
++
++
++extern CORBA_Status CORBA_Context_set_one_value(
++ CORBA_Context ctx,
++ CORBA_Identifier prop_name,
++ char *value,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_Context_set_values(
++ CORBA_Context ctx,
++ CORBA_NVList *values,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_Context_get_values(
++ CORBA_Context ctx,
++ CORBA_Identifier start_scope,
++ CORBA_Flags op_flags,
++ CORBA_Identifier prop_name,
++ CORBA_NVList **values,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_Context_delete_values(
++ CORBA_Context ctx,
++ CORBA_Identifier prop_name,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_Context_create_child(
++ CORBA_Context ctx,
++ CORBA_Identifier ctx_name,
++ CORBA_Context *child_ctx,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_Context_delete(
++ CORBA_Context ctx,
++ CORBA_Flags del_flags,
++ CORBA_Environment *ev);
++
++void ORBit_Context_marshal(CORBA_Context ctx, const ORBit_ContextMarshalItem *mlist,
++ CORBA_unsigned_long nitems, GIOPSendBuffer *buf);
++void ORBit_Context_demarshal(CORBA_Context parent, CORBA_Context initme, GIOPRecvBuffer *recv_buffer);
++void ORBit_Context_server_free(CORBA_Context ctx);
++
++#endif
+diff -urN linux-2.4.1/net/korbit/orb/corba_env.h linux-2.4.1-korbit/net/korbit/orb/corba_env.h
+--- linux-2.4.1/net/korbit/orb/corba_env.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_env.h Thu Feb 1 11:47:11 2001
+@@ -0,0 +1,79 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_ENV_H_
++#define _ORBIT_CORBA_ENV_H_
++
++typedef struct CORBA_Environment_type CORBA_Environment;
++
++/* 3.15 */
++typedef enum {
++ CORBA_COMPLETED_YES=0,
++ CORBA_COMPLETED_NO,
++ CORBA_COMPLETED_MAYBE
++} CORBA_completion_status;
++
++typedef enum {
++ CORBA_NO_EXCEPTION=0,
++ CORBA_USER_EXCEPTION,
++ CORBA_SYSTEM_EXCEPTION
++} CORBA_exception_type;
++
++
++#define ex_CORBA_UNKNOWN 1
++#define ex_CORBA_BAD_PARAM 2
++#define ex_CORBA_NO_MEMORY 3
++#define ex_CORBA_IMP_LIMIT 4
++#define ex_CORBA_COMM_FAILURE 5
++#define ex_CORBA_INV_OBJREF 6
++#define ex_CORBA_NO_PERMISSION 7
++#define ex_CORBA_INTERNAL 8
++#define ex_CORBA_MARSHAL 9
++#define ex_CORBA_INITIALIZE 10
++#define ex_CORBA_NO_IMPLEMENT 11
++#define ex_CORBA_BAD_TYPECODE 12
++#define ex_CORBA_BAD_OPERATION 13
++#define ex_CORBA_NO_RESOURCES 14
++#define ex_CORBA_NO_RESPONSE 15
++#define ex_CORBA_PERSIST_STORE 16
++#define ex_CORBA_BAD_INV_ORDER 17
++#define ex_CORBA_TRANSIENT 18
++#define ex_CORBA_FREE_MEM 19
++#define ex_CORBA_INV_IDENT 20
++#define ex_CORBA_INV_FLAG 21
++#define ex_CORBA_INTF_REPOS 22
++#define ex_CORBA_BAD_CONTEXT 23
++#define ex_CORBA_OBJ_ADAPTER 24
++#define ex_CORBA_DATA_CONVERSION 25
++#define ex_CORBA_OBJECT_NOT_EXIST 26
++#define ex_CORBA_TRANSACTION_REQUIRED 27
++#define ex_CORBA_TRANSACTION_ROLLEDBACK 28
++#define ex_CORBA_INVALID_TRANSACTION 29
++
++
++#endif /* !_ORBIT_CORBA_ENV_H_ */
++
++
++
+diff -urN linux-2.4.1/net/korbit/orb/corba_env_type.h linux-2.4.1-korbit/net/korbit/orb/corba_env_type.h
+--- linux-2.4.1/net/korbit/orb/corba_env_type.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_env_type.h Thu Feb 1 16:20:50 2001
+@@ -0,0 +1,79 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_ENV_TYPE_H_
++#define _ORBIT_CORBA_ENV_TYPE_H_
++
++#include "corba_env.h"
++#include "corba_any.h"
++
++typedef struct CORBA_system_exception {
++ CORBA_unsigned_long minor;
++ CORBA_completion_status completed;
++} CORBA_SystemException;
++
++#define SYSEXC(name) typedef CORBA_SystemException name;
++
++SYSEXC(CORBA_UNKNOWN)
++SYSEXC(CORBA_BAD_PARAM)
++SYSEXC(CORBA_NO_MEMORY)
++SYSEXC(CORBA_IMP_LIMIT)
++SYSEXC(CORBA_COMM_FAILURE)
++SYSEXC(CORBA_INV_OBJREF)
++SYSEXC(CORBA_NO_PERMISSION)
++SYSEXC(CORBA_INTERNAL)
++SYSEXC(CORBA_MARSHAL)
++SYSEXC(CORBA_INITIALIZE)
++SYSEXC(CORBA_NO_IMPLEMENT)
++SYSEXC(CORBA_BAD_TYPECODE)
++SYSEXC(CORBA_BAD_OPERATION)
++SYSEXC(CORBA_NO_RESOURCES)
++SYSEXC(CORBA_NO_RESPONSE)
++SYSEXC(CORBA_PERSIST_STORE)
++SYSEXC(CORBA_BAD_INV_ORDER)
++SYSEXC(CORBA_TRANSIENT)
++SYSEXC(CORBA_FREE_MEM)
++SYSEXC(CORBA_INV_IDENT)
++SYSEXC(CORBA_INV_FLAG)
++SYSEXC(CORBA_INTF_REPOS)
++SYSEXC(CORBA_BAD_CONTEXT)
++SYSEXC(CORBA_OBJ_ADAPTER)
++SYSEXC(CORBA_DATA_CONVERSION)
++SYSEXC(CORBA_OBJECT_NOT_EXIST)
++SYSEXC(CORBA_TRANSACTION_REQUIRED)
++SYSEXC(CORBA_TRANSACTION_ROLLEDBACK)
++SYSEXC(CORBA_INVALID_TRANSACTION)
++
++
++/* 19.22 */
++struct CORBA_Environment_type {
++ CORBA_exception_type _major;
++ CORBA_char *_repo_id;
++ void *_params;
++ CORBA_any *_any;
++};
++
++
++#endif /* !_ORBIT_CORBA_ENV_TYPE_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/corba_object.c linux-2.4.1-korbit/net/korbit/orb/corba_object.c
+--- linux-2.4.1/net/korbit/orb/corba_object.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_object.c Thu Feb 1 11:47:11 2001
+@@ -0,0 +1,467 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ * Elliot Lee <sopwith@redhat.com>
++ *
++ */
++
++#include "config.h"
++#include <IIOP/IIOP.h>
++#include "orbit_types.h"
++#include "corba_object.h"
++#include "corba_object_type.h"
++#include "env.h"
++#include "orb.h"
++#ifdef __KORBIT__
++#include "orbit.h"
++#else /* !__KORBIT__ */
++#include "interface_repository.h"
++#endif /* !__KORBIT__ */
++#include <signal.h>
++#include <sys/types.h>
++#include <sys/wait.h>
++#include <alloca.h>
++
++#ifndef __KERNEL__
++#define freeca(ptr)
++#endif
++
++#ifndef __KORBIT__
++/* Section 4.2.1 */
++CORBA_InterfaceDef CORBA_Object_get_interface(CORBA_Object obj, CORBA_Environment *ev)
++{
++ CORBA_Repository repo;
++ CORBA_InterfaceDef interface;
++
++ if(obj==CORBA_OBJECT_NIL)
++ return(CORBA_OBJECT_NIL); /* no exception defined in spec */
++
++ repo=CORBA_ORB_resolve_initial_references(obj->orb, "InterfaceRepository", ev);
++ if(repo==CORBA_OBJECT_NIL)
++ return(CORBA_OBJECT_NIL);
++
++ interface=CORBA_Repository_lookup_id(repo, obj->object_id, ev);
++ CORBA_Object_release(repo, ev);
++
++ return(interface);
++}
++#endif /* !__KORBIT__ */
++
++/* Section 4.2.3 */
++CORBA_boolean CORBA_Object_is_nil(CORBA_Object obj, CORBA_Environment *ev)
++{
++ if(obj==CORBA_OBJECT_NIL) {
++ return(CORBA_TRUE);
++ } else {
++ return(CORBA_FALSE);
++ }
++}
++
++/* Section 4.2.2 */
++/* XXXX Big warning: lots of places inside ORBit expect this to
++ always return 'obj'. Do not change this, upon pain
++ of death... */
++CORBA_Object CORBA_Object_duplicate(CORBA_Object obj, CORBA_Environment *ev)
++{
++ if(obj == CORBA_OBJECT_NIL)
++ return CORBA_OBJECT_NIL;
++
++ if(ORBIT_ROOT_OBJECT(obj)->refs >= 0)
++ ORBIT_ROOT_OBJECT_REF(obj);
++
++ return(obj);
++}
++
++
++/* Section 4.2.2 */
++void CORBA_Object_release(CORBA_Object obj, CORBA_Environment *ev)
++{
++ if(obj != CORBA_OBJECT_NIL)
++ ORBIT_ROOT_OBJECT_release(obj,ev);
++}
++
++extern GHashTable *ORBit_class_assignments;
++
++void ORBit_impl_CORBA_Object_is_a(gpointer servant,
++ GIOPRecvBuffer * _ORBIT_recv_buffer,
++ CORBA_Environment *ev,
++ gpointer dummy)
++{
++ GIOPSendBuffer *_ORBIT_send_buffer;
++ struct CORBA_Object_struct objdummy; /* XXX badhack to save backwards compat */
++ CORBA_boolean retval;
++ char *repo_id;
++ CORBA_unsigned_long slen;
++ guchar *curptr;
++ ORBit_ObjectKey *objkey;
++ gpointer *tmp_vepv;
++ guint sz;
++ CORBA_unsigned_long clsid;
++ PortableServer_ServantBase *_ORBIT_servant;
++
++ _ORBIT_servant = servant;
++
++ /* XXX security implications */
++ curptr = _ORBIT_recv_buffer->cur;
++ curptr = ALIGN_ADDRESS(curptr, 4);
++ if(giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)))
++ iiop_byteswap((guchar *)&slen, curptr, sizeof(CORBA_unsigned_long));
++ else
++ slen = *((CORBA_unsigned_long *)curptr);
++ curptr += 4;
++ repo_id = curptr;
++
++ repo_id[slen] = '\0';
++
++ objkey = ORBIT_OBJECT_KEY(_ORBIT_servant->_private);
++
++ sz = sizeof(gpointer) * (ORBit_class_assignment_counter + 1);
++ tmp_vepv = alloca(sz);
++ memset(tmp_vepv, '\0', sz);
++
++ objdummy.vepv = tmp_vepv;
++ objkey->class_info->init_local_objref(&objdummy, servant);
++
++ clsid = GPOINTER_TO_UINT(g_hash_table_lookup(ORBit_class_assignments, repo_id));
++ retval = (clsid && tmp_vepv[clsid]);
++
++ _ORBIT_send_buffer = giop_send_reply_buffer_use(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)->connection, NULL,
++ _ORBIT_recv_buffer->message.u.request.request_id, ev->_major);
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer), &retval, sizeof(retval));
++ giop_send_buffer_write(_ORBIT_send_buffer);
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ freeca(tmp_vepv);
++}
++
++/* Section 4.2.4 */
++CORBA_boolean CORBA_Object_is_a(CORBA_Object obj, CORBA_char *logical_type_id, CORBA_Environment *ev)
++{
++ if(obj == CORBA_OBJECT_NIL)
++ return CORBA_FALSE;
++
++ if (obj->servant && obj->vepv) {
++ CORBA_unsigned_long clsid;
++
++ clsid = GPOINTER_TO_UINT(g_hash_table_lookup(ORBit_class_assignments, logical_type_id));
++
++ return (clsid && (clsid < obj->vepv_size) && obj->vepv[clsid]);
++ } else if(!strcmp(obj->object_id, logical_type_id)
++ || !strcmp("IDL:CORBA/Object:1.0", logical_type_id)) {
++ return CORBA_TRUE;
++ } else {
++ /* Cut and paste from orbit-idl output */
++ /* XXX security implications */
++ GIOP_unsigned_long _ORBIT_request_id;
++ register GIOP_unsigned_long _ORBIT_system_exception_minor;
++ register CORBA_completion_status _ORBIT_completion_status;
++ register GIOPSendBuffer *_ORBIT_send_buffer;
++ register GIOPRecvBuffer *_ORBIT_recv_buffer;
++ register GIOPConnection *_cnx;
++
++ _cnx = ORBit_object_get_connection(obj);
++
++ _ORBIT_retry_request:
++ _ORBIT_send_buffer = NULL;
++ _ORBIT_recv_buffer = NULL;
++ _ORBIT_completion_status = CORBA_COMPLETED_NO;
++ /* A unique uint pointer is anything on the stack,
++ so set this variable to point to its own address on the
++ stack. :) */
++ _ORBIT_request_id = GPOINTER_TO_UINT(&_ORBIT_request_id);
++ { /* marshalling */
++ static const struct {
++ CORBA_unsigned_long len;
++ char opname[6];
++ } _ORBIT_operation_name_data = {
++ 6, "_is_a"
++ };
++ static const struct iovec _ORBIT_operation_vec =
++ {(gpointer) & _ORBIT_operation_name_data, 10};
++ register CORBA_unsigned_long _ORBIT_tmpvar_0;
++ CORBA_unsigned_long _ORBIT_tmpvar_1;
++
++ _ORBIT_send_buffer =
++ giop_send_request_buffer_use(_cnx, NULL, _ORBIT_request_id, CORBA_TRUE,
++ &(obj->active_profile->object_key_vec), &_ORBIT_operation_vec, &ORBit_default_principal_iovec);
++
++ _ORBIT_system_exception_minor = ex_CORBA_COMM_FAILURE;
++ if (!_ORBIT_send_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_tmpvar_1 = strlen(logical_type_id) + 1;
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer), 4);
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer), &(_ORBIT_tmpvar_1), sizeof(_ORBIT_tmpvar_1));
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer), (logical_type_id), sizeof(logical_type_id[_ORBIT_tmpvar_0]) * _ORBIT_tmpvar_1);
++ giop_send_buffer_write(_ORBIT_send_buffer);
++ _ORBIT_completion_status = CORBA_COMPLETED_MAYBE;
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ _ORBIT_send_buffer = NULL;
++ }
++ { /* demarshalling */
++ register guchar *_ORBIT_curptr;
++ CORBA_boolean _ORBIT_retval;
++
++ _ORBIT_recv_buffer = giop_recv_reply_buffer_use_2(_cnx, _ORBIT_request_id, TRUE);
++ if (!_ORBIT_recv_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_completion_status = CORBA_COMPLETED_YES;
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status != GIOP_NO_EXCEPTION)
++ goto _ORBIT_msg_exception;
++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) {
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ _ORBIT_retval = *((CORBA_boolean *) _ORBIT_curptr);
++ } else {
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ _ORBIT_retval = *((CORBA_boolean *) _ORBIT_curptr);
++ }
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return _ORBIT_retval;
++ _ORBIT_system_exception:
++ CORBA_exception_set_system(ev, _ORBIT_system_exception_minor, _ORBIT_completion_status);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ return _ORBIT_retval;
++ _ORBIT_msg_exception:
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status == GIOP_LOCATION_FORWARD) {
++ if (obj->forward_locations != NULL)
++ ORBit_delete_profiles(obj->forward_locations);
++ obj->forward_locations = ORBit_demarshal_IOR(_ORBIT_recv_buffer);
++ _cnx = ORBit_object_get_forwarded_connection(obj);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++
++ goto _ORBIT_retry_request;
++ } else {
++ ORBit_handle_exception(_ORBIT_recv_buffer, ev, NULL, obj->orb);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return _ORBIT_retval;
++ }
++ }
++
++ }
++}
++
++/* Section 4.2.5 */
++#ifndef __KORBIT__
++static void do_exit(int signum) {
++ _exit(5);
++#warning "This should be removed... use BUG instead..."
++}
++#endif
++
++/* Lovely hack to try and figure out without hanging whether an object exists or not. */
++CORBA_boolean CORBA_Object_non_existent(CORBA_Object obj, CORBA_Environment *ev)
++{
++#ifndef __KORBIT__
++ int childpid, exitstatus, itmp;
++#endif
++
++ ev->_major = CORBA_NO_EXCEPTION;
++
++ if(obj == CORBA_OBJECT_NIL)
++ return TRUE;
++
++ if(obj->servant)
++ return FALSE;
++
++ if(obj->connection && obj->connection->is_valid)
++ return FALSE;
++
++#ifndef __KORBIT__
++ childpid = fork();
++
++ if(!childpid) {
++ GIOPConnection* cnx = NULL;
++ struct sigaction sa;
++
++ memset(&sa, 0, sizeof(sa));
++ sa.sa_handler = do_exit;
++ sigaction(SIGALRM, &sa, NULL);
++ alarm(2);
++ cnx = _ORBit_object_get_connection(obj);
++
++ /* XXX todo - try invoking a strange operation on the object, and see what type of exception we get. */
++
++ _exit((cnx == NULL)?1:0);
++ }
++
++ itmp = waitpid(childpid, &exitstatus, 0);
++
++ if(itmp < 0) return TRUE;
++ return WEXITSTATUS(exitstatus) && TRUE;
++#else /* __KORBIT__ */
++ return FALSE;
++#endif /* __KORBIT__ */
++}
++
++gboolean
++g_CORBA_Object_equal(CORBA_Object obj1, CORBA_Object obj2)
++{
++ gboolean retval;
++ CORBA_Environment ev;
++
++ CORBA_exception_init(&ev);
++
++ retval = (gboolean)CORBA_Object_is_equivalent(obj1, obj2, &ev);
++
++ CORBA_exception_free(&ev);
++
++ return retval;
++}
++
++/* Section 4.2.6 */
++CORBA_boolean CORBA_Object_is_equivalent(CORBA_Object obj, CORBA_Object other_object, CORBA_Environment *ev)
++{
++ ORBit_Object_info *obj_profile, *other_object_profile;
++ int i,j, obj_profile_count, other_object_profile_count;
++
++ if(obj == CORBA_OBJECT_NIL
++ && other_object == CORBA_OBJECT_NIL)
++ return CORBA_TRUE;
++
++ if(obj == CORBA_OBJECT_NIL
++ || other_object == CORBA_OBJECT_NIL)
++ goto ret_false;
++
++ /*
++ * If one profile in "obj" matches one in "other_object", then these
++ * objects are equivalent.
++ *
++ * This is O(n*m) at worst case :-( Hopefully though most objects will
++ * only have 1 or 2 profiles.
++ *
++ * The profile list could be indexed as a hash table (the linked list
++ * is still needed, as the profile order is significant)
++ */
++
++ obj_profile_count = g_slist_length(obj->profile_list);
++ other_object_profile_count = g_slist_length(other_object->profile_list);
++
++ for(i=0;i<obj_profile_count;i++) {
++ obj_profile=(ORBit_Object_info *)g_slist_nth_data(obj->profile_list, i);
++
++ for(j=0;j<other_object_profile_count;j++) {
++ other_object_profile=(ORBit_Object_info *)g_slist_nth_data(other_object->profile_list, j);
++
++ if(obj_profile->profile_type != other_object_profile->profile_type)
++ continue;
++
++ if(obj_profile->object_key._length != other_object_profile->object_key._length)
++ continue;
++
++ if(memcmp(obj_profile->object_key._buffer, other_object_profile->object_key._buffer, obj_profile->object_key._length))
++ continue;
++
++ if(obj_profile->profile_type == IOP_TAG_INTERNET_IOP) {
++ TAG_INTERNET_IOP_info *ii1, *ii2;
++
++ ii1 = &obj_profile->tag.iopinfo;
++ ii2 = &other_object_profile->tag.iopinfo;
++
++ if(ii1->port != ii2->port)
++ continue;
++ if(strcmp(ii1->host, ii2->host))
++ continue;
++
++ return(CORBA_TRUE);
++ } else if(obj_profile->profile_type == IOP_TAG_ORBIT_SPECIFIC) {
++ TAG_ORBIT_SPECIFIC_info *oi1, *oi2;
++
++ oi1 = &obj_profile->tag.orbitinfo;
++ oi2 = &other_object_profile->tag.orbitinfo;
++
++ if(strcmp(oi1->unix_sock_path, oi2->unix_sock_path))
++ continue;
++ if(oi1->ipv6_port != oi2->ipv6_port)
++ continue;
++
++ return(CORBA_TRUE);
++ }
++ }
++ }
++
++ ret_false:
++ return CORBA_FALSE;
++}
++
++guint
++g_CORBA_Object_hash(CORBA_Object obj)
++{
++ guint retval;
++ CORBA_Environment ev;
++
++ CORBA_exception_init(&ev);
++
++ retval = (guint)CORBA_Object_hash(obj, UINT_MAX, &ev);
++
++ CORBA_exception_free(&ev);
++
++ return retval;
++}
++
++static void profile_hash(gpointer item, gpointer data)
++{
++ ORBit_Object_info *info = (ORBit_Object_info *)item;
++ CORBA_unsigned_long *retval = (CORBA_unsigned_long *)data;
++
++ g_assert(info);
++ g_assert(retval);
++
++ *retval ^= info->object_key._length;
++
++ if(info->profile_type == IOP_TAG_INTERNET_IOP) {
++ *retval ^= !info->tag.iopinfo.port;
++ } else if(info->profile_type == IOP_TAG_ORBIT_SPECIFIC) {
++ *retval ^= g_str_hash(info->tag.orbitinfo.unix_sock_path);
++ *retval ^= !info->tag.orbitinfo.ipv6_port;
++ }
++}
++
++/* Section 4.2.6 */
++CORBA_unsigned_long CORBA_Object_hash(CORBA_Object obj,
++ CORBA_unsigned_long maximum,
++ CORBA_Environment *ev)
++{
++ CORBA_unsigned_long retval = 0;
++ char *tptr;
++
++ g_assert(obj);
++
++ tptr = obj->object_id;
++ while(*tptr) {
++ retval = (retval << 8) ^ *tptr;
++ tptr++;
++ }
++
++ if(g_slist_length(obj->profile_list)>0) {
++ g_slist_foreach(obj->profile_list, profile_hash, &retval);
++ } else {
++ g_warning("Object of type %s doesn't seem to have any connection info!", obj->object_id);
++ }
++
++ return (retval % maximum);
++}
++
++/* Section 4.2.7 */
++CORBA_Policy CORBA_Object_get_policy(CORBA_Object obj, CORBA_PolicyType policy_type, CORBA_Environment *ev)
++{
++ g_assert(!"Not yet implemented");
++ return(NULL);
++}
+diff -urN linux-2.4.1/net/korbit/orb/corba_object.h linux-2.4.1-korbit/net/korbit/orb/corba_object.h
+--- linux-2.4.1/net/korbit/orb/corba_object.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_object.h Thu Feb 1 16:20:50 2001
+@@ -0,0 +1,59 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_OBJECT_H_
++#define _ORBIT_CORBA_OBJECT_H_
++
++#include <ORBitutil/basic_types.h>
++
++#include "corba_env.h"
++#include "corba_orb.h"
++#include "corba_sequences.h"
++
++#define CORBA_OBJECT_NIL NULL
++
++typedef struct CORBA_Object_struct *CORBA_Object;
++
++#define CORBA_OBJECT(x) ((CORBA_Object)(x))
++
++/* Used for internal stuff mostly, but also good if you want to store
++ a hash of objects */
++gboolean g_CORBA_Object_equal(CORBA_Object obj1, CORBA_Object obj2);
++guint g_CORBA_Object_hash(CORBA_Object obj);
++
++void ORBit_impl_CORBA_Object_is_a(gpointer servant,
++ GIOPRecvBuffer * _ORBIT_recv_buffer,
++ CORBA_Environment *ev, gpointer dummy);
++#define ORBIT_IMPLEMENTS_IS_A
++
++extern CORBA_boolean CORBA_Object_is_a(
++ CORBA_Object obj,
++ CORBA_char *logical_type_id,
++ CORBA_Environment *ev);
++
++#endif /* !_ORBIT_CORBA_OBJECT_H_ */
++
++
++
+diff -urN linux-2.4.1/net/korbit/orb/corba_object_type.h linux-2.4.1-korbit/net/korbit/orb/corba_object_type.h
+--- linux-2.4.1/net/korbit/orb/corba_object_type.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_object_type.h Thu Feb 1 16:20:50 2001
+@@ -0,0 +1,54 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_OBJECT_TYPE_H_
++#define _ORBIT_CORBA_OBJECT_TYPE_H_
++
++#include <sys/uio.h> /* for struct iovec */
++
++#include <IIOP/IIOP.h> /* for giop_connection */
++
++#include "corba_object.h"
++#include "corba_basic_sequences_type.h"
++
++#include "orbit_object_type.h"
++
++struct CORBA_Object_struct {
++ struct ORBit_RootObject_struct parent;
++ CORBA_ORB orb;
++ GIOPConnection *connection;
++ CORBA_char *object_id;
++ GSList *profile_list;
++ GSList *forward_locations;
++ ORBit_Object_info *active_profile; /* points at a member of profile_list or forward_locations */
++
++ /* Used for direct calls */
++ gpointer *vepv;
++ /* PortableServer_Servant - looping includes :( */ gpointer servant;
++ guint vepv_size;
++};
++
++
++#endif /* !_ORBIT_CORBA_OBJECT_TYPE_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/corba_orb.h linux-2.4.1-korbit/net/korbit/orb/corba_orb.h
+--- linux-2.4.1/net/korbit/orb/corba_orb.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_orb.h Thu Feb 1 11:47:11 2001
+@@ -0,0 +1,48 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_ORB_H_
++#define _ORBIT_CORBA_ORB_H_
++
++typedef char *CORBA_ORB_ObjectId;
++
++#ifndef CORBA_POLICY_TYPE
++#define CORBA_POLICY_TYPE 1
++/* We need to define this in corba_orb_type.h as well, sometimes... */
++typedef struct CORBA_Policy_type *CORBA_Policy;
++#endif
++
++typedef CORBA_unsigned_long CORBA_PolicyType;
++
++typedef struct CORBA_ORB_type *CORBA_ORB;
++
++typedef struct CORBA_DomainManager_type *CORBA_DomainManager;
++
++typedef struct CORBA_ConstructionPolicy_type *CORBA_ConstructionPolicy;
++
++#define ex_CORBA_ORB_InvalidName "IDL:CORBA/ORB/InvalidName:1.0"
++
++#endif /* !_ORBIT_CORBA_ORB_H_ */
++
+diff -urN linux-2.4.1/net/korbit/orb/corba_orb_type.h linux-2.4.1-korbit/net/korbit/orb/corba_orb_type.h
+--- linux-2.4.1/net/korbit/orb/corba_orb_type.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_orb_type.h Thu Feb 1 16:20:50 2001
+@@ -0,0 +1,77 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_ORB_TYPE_H_
++#define _ORBIT_CORBA_ORB_TYPE_H_
++
++#include "corba_object.h"
++
++struct CORBA_ORB_type {
++ struct ORBit_PseudoObject_struct parent;
++ CORBA_ORBid orb_identifier;
++ CORBA_RepositoryId repoid;
++ CORBA_boolean use_poa;
++
++ CORBA_Object imr, ir, naming, root_poa;
++ struct {
++ GIOPConnection *ipv4;
++ GIOPConnection *ipv6;
++ GIOPConnection *usock;
++ } cnx;
++
++ GHashTable *objrefs;
++
++ GPtrArray *poas;
++
++ CORBA_Context default_ctx;
++};
++
++#define CORBA_ORB_CAST(orb) ((CORBA_ORB)orb)
++
++typedef struct CORBA_ORB_InvalidName {
++ int dummy;
++} CORBA_ORB_InvalidName;
++
++struct CORBA_Policy_type {
++ struct ORBit_PseudoObject_struct parent;
++ CORBA_PolicyType policy_type;
++};
++#ifndef CORBA_POLICY_TYPE
++#define CORBA_POLICY_TYPE 1
++typedef struct CORBA_Policy_type *CORBA_Policy;
++#endif
++
++struct CORBA_DomainManager_type {
++ struct ORBit_PseudoObject_struct parent;
++};
++
++#define CORBA_SecConstruction (11)
++
++struct CORBA_ConstructionPolicy_type {
++ int fill_me_in;
++};
++
++
++#endif /* !_ORBIT_CORBA_ORB_TYPE_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/corba_portableserver.h linux-2.4.1-korbit/net/korbit/orb/corba_portableserver.h
+--- linux-2.4.1/net/korbit/orb/corba_portableserver.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_portableserver.h Thu Feb 1 11:47:11 2001
+@@ -0,0 +1,80 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_PORTABLESERVER_H_
++#define _ORBIT_CORBA_PORTABLESERVER_H_
++
++typedef struct PortableServer_ThreadPolicy_type *PortableServer_ThreadPolicy;
++typedef struct PortableServer_LifespanPolicy_type *PortableServer_LifespanPolicy;
++typedef struct PortableServer_IdUniquenessPolicy_type *PortableServer_IdUniquenessPolicy;
++typedef struct PortableServer_IdAssignmentPolicy_type *PortableServer_IdAssignmentPolicy;
++typedef struct PortableServer_ImplicitActivationPolicy_type *PortableServer_ImplicitActivationPolicy;
++typedef struct PortableServer_ServantRetentionPolicy_type *PortableServer_ServantRetentionPolicy;
++typedef struct PortableServer_RequestProcessingPolicy_type *PortableServer_RequestProcessingPolicy;
++typedef struct PortableServer_POAManager_type* PortableServer_POAManager;
++typedef struct PortableServer_AdapterActivator_type *PortableServer_AdapterActivator;
++typedef struct PortableServer_ServantManager_type *PortableServer_ServantManager;
++typedef struct PortableServer_ServantActivator_type *PortableServer_ServantActivator;
++typedef struct PortableServer_ServantLocator_type *PortableServer_ServantLocator;
++typedef struct PortableServer_POA_type *PortableServer_POA;
++typedef struct PortableServer_Current_type *PortableServer_Current;
++
++typedef enum {
++ PortableServer_ORB_CTRL_MODEL=0,
++ PortableServer_SINGLE_THREAD_MODEL
++} PortableServer_ThreadPolicyValue;
++
++typedef enum {
++ PortableServer_TRANSIENT=0,
++ PortableServer_PERSISTENT
++} PortableServer_LifespanPolicyValue;
++
++typedef enum {
++ PortableServer_UNIQUE_ID=0,
++ PortableServer_MULTIPLE_ID
++} PortableServer_IdUniquenessPolicyValue;
++
++typedef enum {
++ PortableServer_USER_ID=0,
++ PortableServer_SYSTEM_ID
++} PortableServer_IdAssignmentPolicyValue;
++
++typedef enum {
++ PortableServer_IMPLICIT_ACTIVATION=0,
++ PortableServer_NO_IMPLICIT_ACTIVATION
++} PortableServer_ImplicitActivationPolicyValue;
++
++typedef enum {
++ PortableServer_RETAIN=0,
++ PortableServer_NON_RETAIN
++} PortableServer_ServantRetentionPolicyValue;
++
++typedef enum {
++ PortableServer_USE_ACTIVE_OBJECT_MAP_ONLY=0,
++ PortableServer_USE_DEFAULT_SERVANT,
++ PortableServer_USE_SERVANT_MANAGER
++} PortableServer_RequestProcessingPolicyValue;
++
++#endif /* !_ORBIT_CORBA_PORTABLESERVER_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/corba_portableserver_type.h linux-2.4.1-korbit/net/korbit/orb/corba_portableserver_type.h
+--- linux-2.4.1/net/korbit/orb/corba_portableserver_type.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_portableserver_type.h Thu Feb 1 11:47:11 2001
+@@ -0,0 +1,361 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_PORTABLESERVER_TYPE_H_
++#define _ORBIT_CORBA_PORTABLESERVER_TYPE_H_
++
++/* 19.26 */
++
++typedef void *PortableServer_ServantLocator_Cookie;
++typedef void *PortableServer_Servant;
++
++#ifndef _PortableServer_ForwardRequest_defined
++#define _PortableServer_ForwardRequest_defined
++
++typedef struct PortableServer_ForwardRequest {
++ CORBA_Object forward_reference;
++} PortableServer_ForwardRequest;
++
++#define ex_PortableServer_ForwardRequest "IDL:PortableServer/ForwardRequest:1.0"
++#endif /* !_PortableServer_ForwardRequest_defined */
++
++#define PortableServer_THREAD_POLICY_ID 16
++struct PortableServer_ThreadPolicy_type {
++ struct CORBA_Policy_type corba_policy;
++ PortableServer_ThreadPolicyValue value;
++};
++
++#define PortableServer_LIFESPAN_POLICY_ID 17
++extern const CORBA_PolicyType PortableServer_LifespanPolicy_PolicyType;
++struct PortableServer_LifespanPolicy_type {
++ struct CORBA_Policy_type corba_policy;
++ PortableServer_LifespanPolicyValue value;
++};
++
++#define PortableServer_ID_UNIQUENESS_POLICY_ID 18
++struct PortableServer_IdUniquenessPolicy_type {
++ struct CORBA_Policy_type corba_policy;
++ PortableServer_IdUniquenessPolicyValue value;
++};
++
++#define PortableServer_ID_ASSIGNMENT_POLICY_ID 19
++struct PortableServer_IdAssignmentPolicy_type {
++ struct CORBA_Policy_type corba_policy;
++ PortableServer_IdAssignmentPolicyValue value;
++};
++
++#define PortableServer_IMPLICIT_ACTIVATION_POLICY_ID 20
++struct PortableServer_ImplicitActivationPolicy_type {
++ struct CORBA_Policy_type corba_policy;
++ PortableServer_ImplicitActivationPolicyValue value;
++};
++
++#define PortableServer_SERVANT_RETENTION_POLICY_ID 21
++struct PortableServer_ServantRetentionPolicy_type {
++ struct CORBA_Policy_type corba_policy;
++ PortableServer_ServantRetentionPolicyValue value;
++};
++
++#define PortableServer_REQUEST_PROCESSING_POLICY_ID 22
++struct PortableServer_RequestProcessingPolicy_type {
++ struct CORBA_Policy_type corba_policy;
++ PortableServer_RequestProcessingPolicyValue value;
++};
++
++#ifndef _PortableServer_POAManager_AdapterInactive_defined
++#define _PortableServer_POAManager_AdapterInactive_defined
++
++typedef struct PortableServer_POAManager_AdapterInactive {
++ int fill_me_in;
++} PortableServer_POAManager_AdapterInactive;
++
++#define ex_PortableServer_POAManager_AdapterInactive "IDL:PortableServer/POAManager/AdapterInactive:1.0"
++#endif /* !_PortableServer_POAManager_AdapterInactive_defined */
++
++typedef enum { PortableServer_POAManager_HOLDING,
++ PortableServer_POAManager_ACTIVE,
++ PortableServer_POAManager_DISCARDING,
++ PortableServer_POAManager_INACTIVE
++} PortableServer_POAManager_State;
++
++struct PortableServer_POAManager_type {
++ struct ORBit_PseudoObject_struct parent;
++ GSList* poa_collection;
++ CORBA_ORB orb;
++ PortableServer_POAManager_State state;
++};
++
++struct PortableServer_AdapterActivator_type {
++ int fill_me_in;
++};
++
++struct PortableServer_ServantManager_type {
++ int fill_me_in;
++};
++
++#ifndef _PortableServer_POA_AdapterAlreadyExists_defined
++#define _PortableServer_POA_AdapterAlreadyExists_defined
++
++typedef struct PortableServer_POA_AdapterAlreadyExists {
++ int fill_me_in;
++} PortableServer_POA_AdapterAlreadyExists;
++
++#define ex_PortableServer_POA_AdapterAlreadyExists "IDL:PortableServer/POA/AdapterAlreadyExists:1.0"
++#endif /* !_PortableServer_POA_AdapterAlreadyExists_defined */
++
++#ifndef _PortableServer_POAManager_AdapterInactive_defined
++#define _PortableServer_POAManager_AdapterInactive_defined
++
++typedef struct PortableServer_POAManager_AdapterInactive {
++ int fill_me_in;
++} PortableServer_POAManager_AdapterInactive;
++
++#define ex_PortableServer_POAManager_AdapterInactive "IDL:PortableServer/POAManager/AdapterInactive:1.0"
++#endif /* !_PortableServer_POAManager_AdapterInactive_defined */
++
++#ifndef _PortableServer_POA_AdapterNonExistent_defined
++#define _PortableServer_POA_AdapterNonExistent_defined
++
++typedef struct PortableServer_POA_AdapterNonExistent {
++ int fill_me_in;
++} PortableServer_POA_AdapterNonExistent;
++
++#define ex_PortableServer_POA_AdapterNonExistent "IDL:PortableServer/POA/AdapterNonExistent:1.0"
++#endif /* !_PortableServer_POA_AdapterNonExistent_defined */
++
++#ifndef _PortableServer_POA_InvalidPolicy_defined
++#define _PortableServer_POA_InvalidPolicy_defined
++
++typedef struct PortableServer_POA_InvalidPolicy {
++ CORBA_unsigned_short index;
++} PortableServer_POA_InvalidPolicy;
++
++#define ex_PortableServer_POA_InvalidPolicy "IDL:PortableServer/POA/InvalidPolicy:1.0"
++#endif /* !_PortableServer_POA_InvalidPolicy_defined */
++
++#ifndef _PortableServer_POA_NoServant_defined
++#define _PortableServer_POA_NoServant_defined
++
++typedef struct PortableServer_POA_NoServant {
++ int fill_me_in;
++} PortableServer_POA_NoServant;
++
++#define ex_PortableServer_POA_NoServant "IDL:PortableServer/POA/NoServant:1.0"
++#endif /* !_PortableServer_POA_NoServant_defined */
++
++#ifndef _PortableServer_POA_ObjectAlreadyActive_defined
++#define _PortableServer_POA_ObjectAlreadyActive_defined
++
++typedef struct PortableServer_POA_ObjectAlreadyActive {
++ int fill_me_in;
++} PortableServer_POA_ObjectAlreadyActive;
++
++#define ex_PortableServer_POA_ObjectAlreadyActive "IDL:PortableServer/POA/ObjectAlreadyActive:1.0"
++#endif /* !_PortableServer_POA_ObjectAlreadyActive_defined */
++
++#ifndef _PortableServer_POA_ObjectNotActive_defined
++#define _PortableServer_POA_ObjectNotActive_defined
++
++typedef struct PortableServer_POA_ObjectNotActive {
++ int fill_me_in;
++} PortableServer_POA_ObjectNotActive;
++
++#define ex_PortableServer_POA_ObjectNotActive "IDL:PortableServer/POA/ObjectNotActive:1.0"
++#endif /* !_PortableServer_POA_ObjectNotActive_defined */
++
++#ifndef _PortableServer_POA_ServantAlreadyActive_defined
++#define _PortableServer_POA_ServantAlreadyActive_defined
++
++typedef struct PortableServer_POA_ServantAlreadyActive {
++ int fill_me_in;
++} PortableServer_POA_ServantAlreadyActive;
++
++#define ex_PortableServer_POA_ServantAlreadyActive "IDL:PortableServer/POA/ServantAlreadyActive:1.0"
++#endif /* !_PortableServer_POA_ServantAlreadyActive_defined */
++
++#ifndef _PortableServer_POA_ServantNotActive_defined
++#define _PortableServer_POA_ServantNotActive_defined
++
++typedef struct PortableServer_POA_ServantNotActive {
++ int fill_me_in;
++} PortableServer_POA_ServantNotActive;
++
++#define ex_PortableServer_POA_ServantNotActive "IDL:PortableServer/POA/ServantNotActive:1.0"
++#endif /* !_PortableServer_POA_ServantNotActive_defined */
++
++#ifndef _PortableServer_POA_WrongAdapter_defined
++#define _PortableServer_POA_WrongAdapter_defined
++
++typedef struct PortableServer_POA_WrongAdapter {
++ int fill_me_in;
++} PortableServer_POA_WrongAdapter;
++
++#define ex_PortableServer_POA_WrongAdapter "IDL:PortableServer/POA/WrongAdapter:1.0"
++#endif /* !_PortableServer_POA_WrongAdapter_defined */
++
++#ifndef _PortableServer_POA_WrongPolicy_defined
++#define _PortableServer_POA_WrongPolicy_defined
++
++typedef struct PortableServer_POA_WrongPolicy {
++ int fill_me_in;
++} PortableServer_POA_WrongPolicy;
++
++#define ex_PortableServer_POA_WrongPolicy "IDL:PortableServer/POA/WrongPolicy:1.0"
++#endif /* !_PortableServer_POA_WrongPolicy_defined */
++
++#ifndef _PortableServer_Current_NoContext_defined
++#define _PortableServer_Current_NoContext_defined
++
++typedef struct PortableServer_Current_NoContext {
++ int fill_me_in;
++} PortableServer_Current_NoContext;
++
++#define ex_PortableServer_Current_NoContext "IDL:PortableServer/Current/NoContext:1.0"
++#endif /* !_PortableServer_Current_NoContext_defined */
++
++struct PortableServer_Current_type {
++ int fill_me_in;
++};
++
++typedef struct PortableServer_ServantBase__epv {
++ void *_private;
++ void (*finalize)(PortableServer_Servant, CORBA_Environment *);
++ PortableServer_POA (*default_POA)(PortableServer_Servant, CORBA_Environment *);
++} PortableServer_ServantBase__epv;
++
++typedef PortableServer_ServantBase__epv *PortableServer_ServantBase__vepv;
++
++typedef struct PortableServer_ServantBase {
++ void *_private;
++ PortableServer_ServantBase__vepv *vepv;
++} PortableServer_ServantBase;
++
++/* 19.27 */
++
++typedef void (*PortableServer_DynamicImplRoutine) (PortableServer_Servant servant, CORBA_ServerRequest request);
++
++typedef struct PortableServer_DynamicImpl__epv {
++ void *_private;
++ PortableServer_DynamicImplRoutine invoke;
++ CORBA_RepositoryId (*primary_interface) (PortableServer_Servant svt, PortableServer_ObjectId id, PortableServer_POA poa, CORBA_Environment *env);
++} PortableServer_DynamicImpl__epv;
++
++typedef struct PortableServer_DynamicImpl__vepv {
++ PortableServer_ServantBase__epv *_base_epv;
++ PortableServer_DynamicImpl__epv *PortableServer_DynamicImpl_epv;
++} PortableServer_DynamicImpl__vepv;
++
++typedef struct PortableServer_DynamicImpl {
++ void *_private;
++ PortableServer_DynamicImpl__vepv *vepv;
++} PortableServer_DynamicImpl;
++
++typedef struct {
++ void *_private;
++} POA_PortableServer_ServantManager__epv;
++
++typedef struct {
++ void *_private;
++
++ PortableServer_Servant (*incarnate) (PortableServer_Servant servant,
++ PortableServer_ObjectId * oid,
++ PortableServer_POA adapter,
++ CORBA_Environment * ev);
++
++ void (*etherealize) (PortableServer_Servant servant,
++ PortableServer_ObjectId* oid,
++ PortableServer_POA adapter,
++ PortableServer_Servant serv,
++ CORBA_boolean cleanup_in_progress,
++ CORBA_boolean remaining_activations,
++ CORBA_Environment * ev);
++
++} POA_PortableServer_ServantActivator__epv;
++
++typedef struct {
++ PortableServer_ServantBase__epv *_base_epv;
++ POA_PortableServer_ServantManager__epv *PortableServer_ServantManager_epv;
++ POA_PortableServer_ServantActivator__epv *PortableServer_ServantActivator_epv;
++} POA_PortableServer_ServantActivator__vepv;
++
++typedef struct {
++ void *_private;
++ POA_PortableServer_ServantActivator__vepv *vepv;
++} POA_PortableServer_ServantActivator;
++
++extern void
++POA_PortableServer_ServantActivator__init(PortableServer_Servant servant,
++ CORBA_Environment * ev);
++extern void
++POA_PortableServer_ServantActivator__fini(PortableServer_Servant servant,
++ CORBA_Environment * ev);
++
++typedef struct {
++ void *_private;
++
++ PortableServer_Servant (*preinvoke) (PortableServer_Servant servant,
++ PortableServer_ObjectId * oid,
++ PortableServer_POA adapter,
++ CORBA_Identifier operation,
++ PortableServer_ServantLocator_Cookie *the_cookie,
++ CORBA_Environment * ev);
++
++ void (*postinvoke) (PortableServer_Servant servant,
++ PortableServer_ObjectId * oid,
++ PortableServer_POA adapter,
++ CORBA_Identifier operation,
++ PortableServer_ServantLocator_Cookie the_cookie,
++ PortableServer_Servant the_servant,
++ CORBA_Environment * ev);
++} POA_PortableServer_ServantLocator__epv;
++
++typedef struct {
++ PortableServer_ServantBase__epv *_base_epv;
++ POA_PortableServer_ServantManager__epv *PortableServer_ServantManager_epv;
++ POA_PortableServer_ServantLocator__epv *PortableServer_ServantLocator_epv;
++} POA_PortableServer_ServantLocator__vepv;
++
++typedef struct {
++ void *_private;
++ POA_PortableServer_ServantLocator__vepv *vepv;
++} POA_PortableServer_ServantLocator;
++
++extern void
++POA_PortableServer_ServantLocator__init(PortableServer_Servant servant,
++ CORBA_Environment * ev);
++extern void
++POA_PortableServer_ServantLocator__fini(PortableServer_Servant servant,
++ CORBA_Environment * ev);
++
++struct CORBA_ServerRequest_type {
++ struct ORBit_PseudoObject_struct parent;
++ GIOPRecvBuffer *rbuf;
++ GIOPSendBuffer *sbuf;
++ CORBA_NVList *params;
++ CORBA_ORB orb;
++ guchar did_ctx, did_exc;
++};
++
++#endif /* !_ORBIT_CORBA_PORTABLESERVER_TYPE_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/corba_sequences.h linux-2.4.1-korbit/net/korbit/orb/corba_sequences.h
+--- linux-2.4.1/net/korbit/orb/corba_sequences.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_sequences.h Thu Feb 1 11:47:12 2001
+@@ -0,0 +1,74 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_SEQUENCES_H_
++#define _ORBIT_CORBA_SEQUENCES_H_
++
++
++/* moved from sequences.h */
++#include "corba_basic_sequences_type.h"
++
++typedef CORBA_sequence_octet CORBA_ReferenceData;
++
++#define _CORBA_sequence_ServiceOption_defined
++typedef struct CORBA_sequence_ServiceOption CORBA_sequence_ServiceOption;
++
++#define _CORBA_sequence_ServiceDetail_defined
++typedef struct CORBA_sequence_ServiceDetail CORBA_sequence_ServiceDetail;
++
++#define _CORBA_sequence_ORB_ObjectId_defined
++typedef struct CORBA_sequence_ORB_ObjectId CORBA_ORB_ObjectIdList;
++
++#define _CORBA_sequence_NameValuePair_defined
++typedef struct CORBA_sequence_NameValuePair CORBA_NameValuePairSeq;
++
++#define _CORBA_sequence_CORBA_any_defined
++typedef struct CORBA_sequence_CORBA_any_struct CORBA_AnySeq;
++typedef struct CORBA_sequence_CORBA_any_struct CORBA_sequence_CORBA_any;
++
++#define _CORBA_sequence_Policy_defined
++typedef struct CORBA_sequence_Policy CORBA_PolicyList;
++
++#define _CORBA_sequence_DomainManager_defined
++typedef struct CORBA_sequence_DomainManager CORBA_DomainManagerList;
++
++#define _PortableServer_sequence_octet_defined
++typedef struct PortableServer_sequence_octet PortableServer_ObjectId;
++
++
++/* Moved from orbit_types.h */
++#ifndef HAVE_CORBA_PRINCIPAL
++#define HAVE_CORBA_PRINCIPAL 1
++typedef CORBA_sequence_octet CORBA_Principal;
++#endif
++typedef CORBA_sequence_octet CORBA_DynAny_OctetSeq;
++typedef CORBA_sequence_octet CORBA_DynFixed_OctetSeq;
++typedef CORBA_sequence_octet CORBA_DynEnum_OctetSeq;
++typedef CORBA_sequence_octet CORBA_DynStruct_OctetSeq;
++typedef CORBA_sequence_octet CORBA_DynUnion_OctetSeq;
++typedef CORBA_sequence_octet CORBA_DynSequence_OctetSeq;
++typedef CORBA_sequence_octet CORBA_DynArray_OctetSeq;
++
++#endif /* !_ORBIT_CORBA_SEQUENCES_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/corba_sequences_type.h linux-2.4.1-korbit/net/korbit/orb/corba_sequences_type.h
+--- linux-2.4.1/net/korbit/orb/corba_sequences_type.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_sequences_type.h Thu Feb 1 11:47:12 2001
+@@ -0,0 +1,98 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_SEQUENCES_TYPE_H_
++#define _ORBIT_CORBA_SEQUENCES_TYPE_H_
++
++#include "corba_sequences.h"
++
++struct CORBA_sequence_ServiceOption {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ CORBA_ServiceOption *_buffer;
++ CORBA_boolean _release;
++};
++
++struct CORBA_sequence_ServiceDetail {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ CORBA_ServiceDetail *_buffer;
++ CORBA_boolean _release;
++};
++
++struct CORBA_sequence_ORB_ObjectId {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ CORBA_ORB_ObjectId *_buffer;
++ CORBA_boolean _release;
++};
++
++struct CORBA_sequence_NameValuePair {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ struct CORBA_NameValuePair *_buffer;
++ CORBA_boolean _release;
++};
++
++struct CORBA_sequence_CORBA_any_struct {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ CORBA_any *_buffer;
++ CORBA_boolean _release;
++};
++
++struct CORBA_sequence_Policy {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ CORBA_Policy *_buffer;
++ CORBA_boolean _release;
++};
++
++struct CORBA_sequence_DomainManager {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ CORBA_DomainManager *_buffer;
++ CORBA_boolean _release;
++};
++
++struct PortableServer_sequence_octet {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ CORBA_octet *_buffer;
++ CORBA_boolean _release;
++};
++
++/* Generic sequence */
++struct CORBA_Sequence_type {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ void *_buffer;
++ CORBA_boolean _release;
++};
++
++#define CORBA_SEQFLAGS_RELEASE 1
++
++
++#endif /* !_ORBIT_CORBA_SEQUENCES_TYPE_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/corba_typecode.h linux-2.4.1-korbit/net/korbit/orb/corba_typecode.h
+--- linux-2.4.1/net/korbit/orb/corba_typecode.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_typecode.h Thu Feb 1 11:47:12 2001
+@@ -0,0 +1,167 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_TYPECODE_H_
++#define _ORBIT_CORBA_TYPECODE_H_
++
++/* moved from orbit_types.h */
++typedef struct CORBA_TypeCode_struct *CORBA_TypeCode;
++
++typedef enum {
++ CORBA_tk_null=0,
++ CORBA_tk_void=1,
++ CORBA_tk_short=2,
++ CORBA_tk_long=3,
++ CORBA_tk_ushort=4,
++ CORBA_tk_ulong=5,
++ CORBA_tk_float=6,
++ CORBA_tk_double=7,
++ CORBA_tk_boolean=8,
++ CORBA_tk_char=9,
++ CORBA_tk_octet=10,
++ CORBA_tk_any=11,
++ CORBA_tk_TypeCode=12,
++ CORBA_tk_Principal=13,
++ CORBA_tk_objref=14,
++ CORBA_tk_struct=15,
++ CORBA_tk_union=16,
++ CORBA_tk_enum=17,
++ CORBA_tk_string=18,
++ CORBA_tk_sequence=19,
++ CORBA_tk_array=20,
++ CORBA_tk_alias=21,
++ CORBA_tk_except=22,
++ CORBA_tk_longlong=23,
++ CORBA_tk_ulonglong=24,
++ CORBA_tk_longdouble=25,
++ CORBA_tk_wchar=26,
++ CORBA_tk_wstring=27,
++ CORBA_tk_fixed=28,
++ CORBA_tk_recursive=0xffffffff,
++ CORBA_tk_last=29 /* hack for GIOP */
++} CORBA_TCKind;
++
++#define TC_CORBA_short TC_short
++#define TC_CORBA_long TC_long
++#define TC_CORBA_longlong TC_longlong
++#define TC_CORBA_long_long TC_longlong
++#define TC_CORBA_ushort TC_ushort
++#define TC_CORBA_unsigned_short TC_ushort
++#define TC_CORBA_ulong TC_ulong
++#define TC_CORBA_unsigned_long TC_ulong
++#define TC_CORBA_ulonglong TC_ulonglong
++#define TC_CORBA_unsigned_long_long TC_ulonglong
++#define TC_CORBA_float TC_float
++#define TC_CORBA_double TC_double
++#define TC_CORBA_longdouble TC_longdouble
++#define TC_CORBA_long_double TC_longdouble
++#define TC_CORBA_boolean TC_boolean
++#define TC_CORBA_char TC_char
++#define TC_CORBA_wchar TC_wchar
++#define TC_CORBA_octet TC_octet
++#define TC_CORBA_any TC_any
++#define TC_CORBA_TypeCode TC_TypeCode
++#define TC_CORBA_Principal TC_Principal
++#define TC_CORBA_Object TC_Object
++#define TC_CORBA_string TC_string
++#define TC_CORBA_wstring TC_wstring
++
++#define TC_null ((CORBA_TypeCode)&TC_null_struct)
++#define TC_void ((CORBA_TypeCode)&TC_void_struct)
++#define TC_short ((CORBA_TypeCode)&TC_short_struct)
++#define TC_long ((CORBA_TypeCode)&TC_long_struct)
++#define TC_longlong ((CORBA_TypeCode)&TC_longlong_struct)
++#define TC_ushort ((CORBA_TypeCode)&TC_ushort_struct)
++#define TC_ulong ((CORBA_TypeCode)&TC_ulong_struct)
++#define TC_ulonglong ((CORBA_TypeCode)&TC_ulonglong_struct)
++#define TC_float ((CORBA_TypeCode)&TC_float_struct)
++#define TC_double ((CORBA_TypeCode)&TC_double_struct)
++#define TC_longdouble ((CORBA_TypeCode)&TC_longdouble_struct)
++#define TC_boolean ((CORBA_TypeCode)&TC_boolean_struct)
++#define TC_char ((CORBA_TypeCode)&TC_char_struct)
++#define TC_wchar ((CORBA_TypeCode)&TC_wchar_struct)
++#define TC_octet ((CORBA_TypeCode)&TC_octet_struct)
++#define TC_any ((CORBA_TypeCode)&TC_any_struct)
++#define TC_TypeCode ((CORBA_TypeCode)&TC_TypeCode_struct)
++#define TC_Principal ((CORBA_TypeCode)&TC_Principal_struct)
++#define TC_Object ((CORBA_TypeCode)&TC_Object_struct)
++#define TC_string ((CORBA_TypeCode)&TC_string_struct)
++#define TC_wstring ((CORBA_TypeCode)&TC_wstring_struct)
++#define TC_CORBA_NamedValue ((CORBA_TypeCode)&TC_CORBA_NamedValue_struct)
++
++#define TC_CORBA_short_struct TC_short_struct
++#define TC_CORBA_long_struct TC_long_struct
++#define TC_CORBA_longlong_struct TC_longlong_struct
++#define TC_CORBA_long_long_struct TC_longlong_struct
++#define TC_CORBA_ushort_struct TC_ushort_struct
++#define TC_CORBA_unsigned_short_struct TC_ushort_struct
++#define TC_CORBA_ulong_struct TC_ulong_struct
++#define TC_CORBA_unsigned_long_struct TC_ulong_struct
++#define TC_CORBA_ulonglong_struct TC_ulonglong_struct
++#define TC_CORBA_unsigned_long_long_struct TC_ulonglong_struct
++#define TC_CORBA_float_struct TC_float_struct
++#define TC_CORBA_double_struct TC_double_struct
++#define TC_CORBA_longdouble_struct TC_longdouble_struct
++#define TC_CORBA_long_double_struct TC_longdouble_struct
++#define TC_CORBA_boolean_struct TC_boolean_struct
++#define TC_CORBA_char_struct TC_char_struct
++#define TC_CORBA_wchar_struct TC_wchar_struct
++#define TC_CORBA_octet_struct TC_octet_struct
++#define TC_CORBA_any_struct TC_any_struct
++#define TC_CORBA_TypeCode_struct TC_TypeCode_struct
++#define TC_CORBA_Principal_struct TC_Principal_struct
++#define TC_CORBA_Object_struct TC_Object_struct
++#define TC_CORBA_string_struct TC_string_struct
++#define TC_CORBA_wstring_struct TC_wstring_struct
++
++extern const struct CORBA_TypeCode_struct TC_null_struct;
++extern const struct CORBA_TypeCode_struct TC_void_struct;
++extern const struct CORBA_TypeCode_struct TC_short_struct;
++extern const struct CORBA_TypeCode_struct TC_long_struct;
++extern const struct CORBA_TypeCode_struct TC_longlong_struct;
++extern const struct CORBA_TypeCode_struct TC_ushort_struct;
++extern const struct CORBA_TypeCode_struct TC_ulong_struct;
++extern const struct CORBA_TypeCode_struct TC_ulonglong_struct;
++extern const struct CORBA_TypeCode_struct TC_float_struct;
++extern const struct CORBA_TypeCode_struct TC_double_struct;
++extern const struct CORBA_TypeCode_struct TC_longdouble_struct;
++extern const struct CORBA_TypeCode_struct TC_boolean_struct;
++extern const struct CORBA_TypeCode_struct TC_char_struct;
++extern const struct CORBA_TypeCode_struct TC_wchar_struct;
++extern const struct CORBA_TypeCode_struct TC_octet_struct;
++extern const struct CORBA_TypeCode_struct TC_any_struct;
++extern const struct CORBA_TypeCode_struct TC_TypeCode_struct;
++extern const struct CORBA_TypeCode_struct TC_Principal_struct;
++extern const struct CORBA_TypeCode_struct TC_Object_struct;
++extern const struct CORBA_TypeCode_struct TC_string_struct;
++extern const struct CORBA_TypeCode_struct TC_wstring_struct;
++extern const struct CORBA_TypeCode_struct TC_CORBA_NamedValue_struct;
++
++
++#endif /* !_ORBIT_CORBA_TYPECODE_H_ */
++
++
++
++
+diff -urN linux-2.4.1/net/korbit/orb/corba_typecode_type.h linux-2.4.1-korbit/net/korbit/orb/corba_typecode_type.h
+--- linux-2.4.1/net/korbit/orb/corba_typecode_type.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_typecode_type.h Thu Feb 1 16:20:50 2001
+@@ -0,0 +1,66 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_TYPECODE_TYPE_H_
++#define _ORBIT_CORBA_TYPECODE_TYPE_H_
++
++#include <ORBitutil/basic_types.h>
++#include "corba_typecode.h"
++#include "corba_any.h"
++
++typedef struct CORBA_TypeCode_Bounds {
++ int dummy;
++} CORBA_TypeCode_Bounds;
++
++typedef struct CORBA_TypeCode_BadKind {
++ int dummy;
++} CORBA_TypeCode_BadKind;
++
++struct CORBA_TypeCode_struct {
++ struct ORBit_PseudoObject_struct parent;
++ CORBA_TCKind kind;
++#ifndef __KORBIT__
++ const
++#endif
++ char *name;
++#ifndef __KORBIT__
++ const
++#endif
++ char *repo_id;
++ CORBA_unsigned_long length;
++ CORBA_unsigned_long sub_parts;
++ const char **subnames; /* for struct, exception, union, enum */
++ CORBA_TypeCode *subtypes; /* for struct, exception, union, alias, array, sequence */
++ CORBA_any *sublabels; /* for union */
++ CORBA_TypeCode discriminator; /* for union */
++ CORBA_unsigned_long recurse_depth; /* for recursive sequence */
++ CORBA_long default_index; /* for union */
++ CORBA_unsigned_short digits; /* for fixed */
++ CORBA_short scale; /* for fixed */
++};
++
++
++#endif /* !_ORBIT_CORBA_TYPECODE_TYPE_H_ */
++
+diff -urN linux-2.4.1/net/korbit/orb/dii.c linux-2.4.1-korbit/net/korbit/orb/dii.c
+--- linux-2.4.1/net/korbit/orb/dii.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/dii.c Thu Feb 1 11:47:12 2001
+@@ -0,0 +1,454 @@
++/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Red Hat Software, Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Elliot Lee <sopwith@redhat.com>
++ * Dick Porter <dick@cymru.net>
++ *
++ */
++
++#include <stdlib.h>
++#include <string.h>
++#include <assert.h>
++
++#include "orbit.h"
++#ifndef __KORBIT__
++#include "interface_repository.h"
++#endif /* !__KORBIT__ */
++
++struct CORBA_Request_type {
++ struct ORBit_PseudoObject_struct parent;
++
++ CORBA_Object obj;
++ CORBA_Context ctx;
++
++ CORBA_Flags req_flags;
++ CORBA_Identifier operation;
++
++ CORBA_NamedValue *result;
++ CORBA_NVList *arg_list;
++
++ CORBA_unsigned_long request_id;
++ GIOPSendBuffer *request_buffer;
++ GIOPRecvBuffer *reply_buffer;
++};
++
++static const ORBit_RootObject_Interface interface_CORBA_Request = {
++ (void (*)(gpointer,CORBA_Environment *))CORBA_Request_delete
++};
++
++/* Section 5.2.1 */
++CORBA_Status
++CORBA_Object_create_request(CORBA_Object obj,
++ CORBA_Context ctx,
++ CORBA_Identifier operation,
++ CORBA_NVList *arg_list,
++ CORBA_NamedValue *result,
++ CORBA_Request *request,
++ CORBA_Flags req_flags,
++ CORBA_Environment *ev)
++{
++ CORBA_Request new;
++
++ new=g_new0(struct CORBA_Request_type, 1);
++ ORBit_pseudo_object_init((ORBit_PseudoObject)new, ORBIT_PSEUDO_REQUEST, ev);
++ ORBit_RootObject_set_interface((ORBit_RootObject)new,
++ (ORBit_RootObject_Interface *)&interface_CORBA_Request, ev);
++
++ if(new==NULL) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_NO_MEMORY,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ new->obj=CORBA_Object_duplicate(obj, ev);
++ new->ctx=(CORBA_Context)CORBA_Object_duplicate((CORBA_Object)ctx, ev);
++ new->operation=CORBA_string_dup(operation);
++
++ new->result=result;
++
++ new->req_flags=req_flags;
++ new->request_id = giop_get_request_id();
++ new->arg_list = arg_list;
++
++ *request=(CORBA_Request)CORBA_Object_duplicate((CORBA_Object)new, ev);
++}
++
++/* Section 5.2, 5.2.2 */
++CORBA_Status
++CORBA_Request_add_arg(CORBA_Request req,
++ CORBA_Identifier name,
++ CORBA_TypeCode arg_type,
++ void *value,
++ CORBA_long len,
++ CORBA_Flags arg_flags,
++ CORBA_Environment *ev)
++{
++ gpointer new_value;
++
++ g_assert(req!=NULL);
++
++ if((arg_flags & CORBA_IN_COPY_VALUE) && (arg_flags & CORBA_ARG_IN)) {
++ new_value = ORBit_copy_value(value, arg_type);
++ if(new_value==NULL) {
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++ } else
++ new_value=value;
++
++ CORBA_NVList_add_item(req->arg_list, name, arg_type,
++ new_value, len, arg_flags | req->req_flags, ev);
++}
++
++/* Section 5.2, 5.2.3 */
++CORBA_Status
++CORBA_Request_invoke(CORBA_Request req,
++ CORBA_Flags invoke_flags,
++ CORBA_Environment *ev)
++{
++ CORBA_Request_send(req, invoke_flags, ev);
++ if(ev->_major == CORBA_NO_EXCEPTION)
++ CORBA_Request_get_response(req, invoke_flags, ev);
++}
++
++/* Section 5.2, 5.2.4 */
++CORBA_Status CORBA_Request_delete(CORBA_Request req, CORBA_Environment *ev)
++{
++ CORBA_Object_release(req->obj, ev);
++ CORBA_Object_release((CORBA_Object)req->ctx, ev);
++
++ if(req->operation != NULL)
++ CORBA_free(req->operation);
++
++ if(req->arg_list != NULL) {
++ if(req->req_flags & CORBA_OUT_LIST_MEMORY)
++ CORBA_NVList_free(req->arg_list, ev);
++ else {
++ int i;
++ for(i = 0; i < req->arg_list->list->len; i++)
++ ORBit_NamedValue_free(&g_array_index(req->arg_list->list,
++ CORBA_NamedValue, i));
++ g_array_free(req->arg_list->list, TRUE);
++
++ g_free(req->arg_list);
++ }
++ }
++
++ if(req->result!=NULL)
++ ORBit_NamedValue_free(req->result);
++
++ if(req->request_buffer)
++ giop_send_buffer_unuse(req->request_buffer);
++
++ if(req->reply_buffer)
++ giop_recv_buffer_unuse(req->reply_buffer);
++
++ g_free(req);
++}
++
++/* Section 5.2, 5.3.1 */
++CORBA_Status
++CORBA_Request_send(CORBA_Request req,
++ CORBA_Flags invoke_flags,
++ CORBA_Environment *ev)
++{
++ int i;
++ GIOPConnection *cnx;
++
++ struct { CORBA_unsigned_long opstrlen; char opname[1]; } *opnameinfo;
++ struct iovec opvec = { NULL, 0 };
++
++ opvec.iov_len = strlen(req->operation)+1+sizeof(CORBA_unsigned_long);
++
++ opnameinfo = g_malloc(strlen(req->operation)+1+sizeof(CORBA_unsigned_long));
++ opvec.iov_base = (gpointer)opnameinfo;
++ opnameinfo->opstrlen = strlen(req->operation) + 1;
++ strcpy(opnameinfo->opname, req->operation);
++
++ cnx = ORBit_object_get_connection(req->obj);
++
++ g_assert(req->obj->active_profile);
++ req->request_buffer =
++ giop_send_request_buffer_use(req->obj->connection,
++ NULL,
++ req->request_id,
++ req->result?TRUE:FALSE,
++ &(req->obj->active_profile->object_key_vec),
++ &opvec,
++ &ORBit_default_principal_iovec
++ );
++
++ if(!req->request_buffer) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_COMM_FAILURE,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ for(i = 0; i < req->arg_list->list->len; i++) {
++ CORBA_NamedValue *nv;
++
++ nv = &g_array_index(req->arg_list->list, CORBA_NamedValue, i);
++
++ if((nv->arg_modes & CORBA_ARG_IN)
++ || (nv->arg_modes & CORBA_ARG_INOUT))
++ ORBit_marshal_arg(req->request_buffer,
++ nv->argument._value,
++ nv->argument._type);
++ }
++
++ giop_send_buffer_write(req->request_buffer);
++
++ giop_send_buffer_unuse(req->request_buffer);
++ req->request_buffer = 0;
++
++ g_free(opnameinfo);
++}
++
++/* Section 5.3.2 */
++CORBA_Status
++CORBA_send_multiple_requests(CORBA_Request *reqs,
++ CORBA_Environment *env,
++ CORBA_long count,
++ CORBA_Flags invoke_flags)
++{
++ int i;
++
++ for(i = 0; i < count; i++)
++ CORBA_Request_send(reqs[i], invoke_flags, env);
++}
++
++void
++ORBit_handle_dii_reply(CORBA_Request req, CORBA_Environment *ev)
++{
++ int i;
++
++ /* XXX TODO - handle exceptions, location forwards(?), all that */
++ req->result->argument._value =
++ ORBit_demarshal_arg(req->reply_buffer, req->result->argument._type,
++ TRUE, req->obj->orb);
++ req->result->argument._release = CORBA_TRUE;
++
++ for(i = 0; i < req->arg_list->list->len; i++) {
++ CORBA_NamedValue *nv;
++
++ nv = &g_array_index(req->arg_list->list, CORBA_NamedValue, i);
++
++ if(nv->arg_modes & CORBA_ARG_INOUT) {
++ CORBA_Object_duplicate((CORBA_Object)nv->argument._type, NULL);
++ CORBA_any__free(&nv->argument, NULL, TRUE);
++ }
++
++ if((nv->arg_modes & CORBA_ARG_OUT)
++ || (nv->arg_modes & CORBA_ARG_INOUT))
++ nv->argument._value = ORBit_demarshal_arg(req->reply_buffer,
++ nv->argument._type,
++ TRUE, req->obj->orb);
++ }
++
++ giop_recv_buffer_unuse(req->reply_buffer);
++ req->reply_buffer = 0;
++}
++
++/* Section 5.2, 5.3.3
++ *
++ * Raises: WrongTransaction
++ */
++CORBA_Status
++CORBA_Request_get_response(CORBA_Request req,
++ CORBA_Flags response_flags,
++ CORBA_Environment *ev)
++{
++ req->reply_buffer = giop_recv_reply_buffer_use(req->request_id,
++ !(response_flags & CORBA_RESP_NO_WAIT));
++
++ if(!req->reply_buffer) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_COMM_FAILURE,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ ORBit_handle_dii_reply(req, ev);
++}
++
++/* Section 5.3.4
++ *
++ * Raises: WrongTransaction
++ */
++CORBA_Status
++CORBA_Request_get_next_response(CORBA_Environment *env,
++ CORBA_Flags response_flags,
++ CORBA_Request *req)
++{
++ int i;
++ GIOPRecvBuffer *rb;
++ GArray *reqids = g_array_new(FALSE, FALSE,
++ sizeof(CORBA_unsigned_long));
++
++ for(i = 0; req[i]; i++) {
++ g_array_append_val(reqids, req[i]->request_id);
++ }
++
++ rb = giop_recv_reply_buffer_use_multiple(reqids,
++ !(response_flags & CORBA_RESP_NO_WAIT));
++
++ if(rb) {
++ for(i = 0; i < reqids->len; i++) {
++ if(g_array_index(reqids, CORBA_unsigned_long, i)
++ == rb->message.u.reply.request_id) {
++ req[i]->reply_buffer = rb;
++ break;
++ }
++ }
++
++ if(i < reqids->len)
++ ORBit_handle_dii_reply(req[i], env);
++ }
++
++ g_array_free(reqids, TRUE);
++}
++
++
++/* Section 5.4.1 */
++CORBA_Status
++CORBA_ORB_create_list(CORBA_ORB orb,
++ CORBA_long count,
++ CORBA_NVList **new_list,
++ CORBA_Environment *ev)
++{
++ CORBA_NVList *new;
++
++ new = g_new0(CORBA_NVList, 1);
++ if(new==NULL) goto new_alloc_failed;
++
++ new->list = g_array_new(FALSE, TRUE, sizeof(CORBA_NamedValue));
++
++ *new_list = new;
++
++ return;
++
++ new_alloc_failed:
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++}
++
++#ifndef __KORBIT__
++/* Section 5.4.6 */
++CORBA_Status
++CORBA_ORB_create_operation_list(CORBA_ORB orb,
++ CORBA_OperationDef oper,
++ CORBA_NVList **new_list,
++ CORBA_Environment *ev)
++{
++ if(!new_list) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ g_warning("CORBA_ORB_create_operation_list NYI");
++
++ CORBA_exception_set_system(ev,
++ ex_CORBA_IMP_LIMIT,
++ CORBA_COMPLETED_NO);
++}
++#endif /* !__KORBIT__ */
++
++/* Section 5.4.2 */
++CORBA_Status
++CORBA_NVList_add_item(CORBA_NVList *list,
++ CORBA_Identifier item_name,
++ CORBA_TypeCode item_type,
++ void *value,
++ CORBA_long value_len,
++ CORBA_Flags item_flags,
++ CORBA_Environment *ev)
++{
++ CORBA_NamedValue newval;
++
++ g_assert(list!=NULL);
++
++ newval.name = CORBA_string_dup(item_name);
++ newval.argument._type = (CORBA_TypeCode)CORBA_Object_duplicate((CORBA_Object)item_type, ev);
++ if(item_flags & CORBA_IN_COPY_VALUE) {
++ newval.argument._value = ORBit_copy_value(value, item_type);
++ newval.argument._release = CORBA_TRUE;
++ } else {
++ newval.argument._value = value;
++ newval.argument._release = CORBA_FALSE;
++ }
++
++ newval.len = value_len; /* Is this even useful? *sigh* */
++ newval.arg_modes = item_flags;
++
++ g_array_append_val(list->list, newval);
++}
++
++void ORBit_NamedValue_free(CORBA_NamedValue *nv)
++{
++ CORBA_free(nv->name);
++}
++
++/* Section 5.4.3 */
++CORBA_Status
++CORBA_NVList_free(CORBA_NVList *list,
++ CORBA_Environment *ev)
++{
++ int i;
++
++ CORBA_NVList_free_memory(list, ev);
++
++ for(i = 0; i < list->list->len; i++)
++ ORBit_NamedValue_free(&g_array_index(list->list, CORBA_NamedValue, i));
++
++ g_array_free(list->list, TRUE);
++
++ g_free(list);
++}
++
++/* Section 5.4.4 */
++CORBA_Status
++CORBA_NVList_free_memory(CORBA_NVList *list,
++ CORBA_Environment *ev)
++{
++ int i;
++
++ for(i = 0; i < list->list->len; i++) {
++ CORBA_free(g_array_index(list->list, CORBA_NamedValue, i).argument._value);
++ g_array_index(list->list, CORBA_NamedValue, i).argument._value = NULL;
++ CORBA_Object_release((CORBA_Object)g_array_index(list->list, CORBA_NamedValue, i).argument._type, ev);
++ g_array_index(list->list, CORBA_NamedValue, i).argument._release = CORBA_FALSE;
++ }
++}
++
++
++/* Section 5.4.5 */
++CORBA_Status
++CORBA_NVList_get_count(CORBA_NVList *list,
++ CORBA_long *count,
++ CORBA_Environment *ev)
++{
++ *count = list->list->len;
++}
++
+diff -urN linux-2.4.1/net/korbit/orb/dii.h linux-2.4.1-korbit/net/korbit/orb/dii.h
+--- linux-2.4.1/net/korbit/orb/dii.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/dii.h Thu Feb 1 11:47:12 2001
+@@ -0,0 +1,124 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_DII_H_
++#define _ORBIT_DII_H_
++
++#include "orb/orbit_types.h"
++#ifndef __KORBIT__
++#include "orb/interface_repository.h"
++#endif /* !__KORBIT__ */
++
++extern CORBA_Status CORBA_Object_create_request(
++ CORBA_Object obj,
++ CORBA_Context ctx,
++ CORBA_Identifier operation,
++ CORBA_NVList *arg_list,
++ CORBA_NamedValue *result,
++ CORBA_Request *request,
++ CORBA_Flags req_flags,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_Request_add_arg(
++ CORBA_Request req,
++ CORBA_Identifier name,
++ CORBA_TypeCode arg_type,
++ void *value,
++ CORBA_long len,
++ CORBA_Flags arg_flags,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_Request_invoke(
++ CORBA_Request req,
++ CORBA_Flags invoke_flags,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_Request_delete(
++ CORBA_Request req,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_Request_send(
++ CORBA_Request req,
++ CORBA_Flags invoke_flags,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_send_multiple_requests(
++ CORBA_Request reqs[],
++ CORBA_Environment *env,
++ CORBA_long count,
++ CORBA_Flags invoke_flags);
++
++extern CORBA_Status CORBA_Request_get_response(
++ CORBA_Request req,
++ CORBA_Flags response_flags,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_get_next_response(
++ CORBA_Environment *env,
++ CORBA_Flags response_flags,
++ CORBA_Request *req);
++
++extern CORBA_Status CORBA_NVList_add_item(
++ CORBA_NVList *list,
++ CORBA_Identifier item_name,
++ CORBA_TypeCode item_type,
++ void *value,
++ CORBA_long value_len,
++ CORBA_Flags item_flags,
++ CORBA_Environment *ev);
++
++extern void ORBit_NamedValue_free(
++ CORBA_NamedValue *nv);
++
++
++extern CORBA_Status CORBA_ORB_create_list(
++ CORBA_ORB orb,
++ CORBA_long count,
++ CORBA_NVList **new_list,
++ CORBA_Environment *ev);
++
++#ifndef __KORBIT__
++extern CORBA_Status CORBA_ORB_create_operation_list(
++ CORBA_ORB orb,
++ CORBA_OperationDef oper,
++ CORBA_NVList **new_list,
++ CORBA_Environment *ev);
++#endif /* !__KORBIT__ */
++
++extern CORBA_Status CORBA_NVList_free(CORBA_NVList *list,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_NVList_free_memory(
++ CORBA_NVList *list,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_NVList_get_count(
++ CORBA_NVList *list,
++ CORBA_long *count,
++ CORBA_Environment *ev);
++
++extern const int sizeofs[], container_sizeofs[];
++
++#endif /* _ORBIT_DII_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/env.c linux-2.4.1-korbit/net/korbit/orb/env.c
+--- linux-2.4.1/net/korbit/orb/env.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/env.c Thu Feb 1 11:47:12 2001
+@@ -0,0 +1,345 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++/*
++ * CORBA_Environment handling functions
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <assert.h>
++
++#include "orbit.h"
++#ifndef __KORBIT__
++#include "interface_repository.h"
++#endif /* !__KORBIT__ */
++
++struct SysExInfo {
++ const char *repo_id;
++ const int exnum;
++};
++
++static const struct SysExInfo exception_table[] = {
++ {NULL, 0},
++ {"IDL:CORBA/UNKNOWN:1.0", 1},
++ {"IDL:CORBA/BAD_PARAM:1.0", 2},
++ {"IDL:CORBA/NO_MEMORY:1.0", 3},
++ {"IDL:CORBA/IMP_LIMIT:1.0", 4},
++ {"IDL:CORBA/COMM_FAILURE:1.0", 5},
++ {"IDL:CORBA/INV_OBJREF:1.0", 6},
++ {"IDL:CORBA/NO_PERMISSION:1.0", 7},
++ {"IDL:CORBA/INTERNAL:1.0", 8},
++ {"IDL:CORBA/MARSHAL:1.0", 9},
++ {"IDL:CORBA/INITIALIZE:1.0", 10},
++ {"IDL:CORBA/NO_IMPLEMENT:1.0", 11},
++ {"IDL:CORBA/BAD_TYPECODE:1.0", 12},
++ {"IDL:CORBA/BAD_OPERATION:1.0", 13},
++ {"IDL:CORBA/NO_RESOURCES:1.0", 14},
++ {"IDL:CORBA/NO_RESPONSE:1.0", 15},
++ {"IDL:CORBA/PERSIST_STORE:1.0", 16},
++ {"IDL:CORBA/BAD_INV_ORDER:1.0", 17},
++ {"IDL:CORBA/TRANSIENT:1.0", 18},
++ {"IDL:CORBA/FREE_MEM:1.0", 19},
++ {"IDL:CORBA/INV_IDENT:1.0", 20},
++ {"IDL:CORBA/INV_FLAG:1.0", 21},
++ {"IDL:CORBA/INTF_REPOS:1.0", 22},
++ {"IDL:CORBA/BAD_CONTEXT:1.0", 23},
++ {"IDL:CORBA/OBJ_ADAPTER:1.0", 24},
++ {"IDL:CORBA/DATA_CONVERSION:1.0", 25},
++ {"IDL:CORBA/OBJECT_NOT_EXIST:1.0", 26},
++ {"IDL:CORBA/TRANSACTION_REQUIRED:1.0", 27},
++ {"IDL:CORBA/TRANSACTION_ROLLEDBACK:1.0", 28},
++ {"IDL:CORBA/INVALID_TRANSACTION:1.0", 29},
++ {NULL,0}
++};
++
++void CORBA_exception_free(CORBA_Environment *ev)
++{
++ g_assert(ev!=NULL);
++
++ ev->_major=CORBA_NO_EXCEPTION;
++
++ if(ev->_repo_id) {
++ CORBA_free(ev->_repo_id);
++ ev->_repo_id=NULL;
++ }
++
++ if(ev->_params) {
++ CORBA_free(ev->_params);
++ ev->_params=NULL;
++ }
++
++ if(ev->_any) {
++ CORBA_free(ev->_any);
++ ev->_any=NULL;
++ }
++}
++
++void CORBA_exception_set(CORBA_Environment *ev, CORBA_exception_type major,
++ const CORBA_char *except_repos_id, void *param)
++{
++ g_assert(ev!=NULL);
++
++ if(ev->_major != CORBA_NO_EXCEPTION)
++ CORBA_exception_free(ev);
++
++ ev->_major=major;
++
++ if(except_repos_id==NULL) {
++ ev->_repo_id=NULL;
++ } else {
++ ev->_repo_id=CORBA_string_dup(except_repos_id);
++ }
++
++ ev->_params=param;
++}
++
++void CORBA_exception_set_system(CORBA_Environment *ev, CORBA_unsigned_long ex_value,
++ CORBA_completion_status completed)
++{
++ CORBA_SystemException *new;
++
++ new=ORBit_alloc(sizeof(CORBA_SystemException), NULL, NULL);
++ if(new!=NULL) {
++ new->minor=0;
++ new->completed=completed;
++
++ /* XXX what should the repo ID be? */
++ CORBA_exception_set(ev, CORBA_SYSTEM_EXCEPTION,
++ exception_table[ex_value].repo_id,
++ new);
++ }
++}
++
++void CORBA_exception_init(CORBA_Environment *ev)
++{
++ g_assert(ev!=NULL);
++
++ ev->_major=CORBA_NO_EXCEPTION;
++ ev->_repo_id=NULL;
++ ev->_params=NULL;
++ ev->_any=NULL;
++}
++
++CORBA_char *CORBA_exception_id(CORBA_Environment *ev)
++{
++ g_assert(ev!=NULL);
++
++ if(ev->_major==CORBA_NO_EXCEPTION) {
++ return(NULL);
++ } else {
++ return(ev->_repo_id);
++ }
++}
++
++void *CORBA_exception_value(CORBA_Environment *ev)
++{
++ g_assert(ev!=NULL);
++
++ if(ev->_major==CORBA_NO_EXCEPTION) {
++ return(NULL);
++ } else {
++ return(ev->_params);
++ }
++}
++
++#ifndef __KORBIT__
++CORBA_any *CORBA_exception_as_any(CORBA_Environment *ev)
++{
++ g_assert(ev!=NULL);
++
++ if(ev->_major==CORBA_NO_EXCEPTION) {
++ return(NULL);
++ }
++
++ if(ev->_any!=NULL) {
++ return(ev->_any);
++ }
++
++ ev->_any=g_new(CORBA_any, 1);
++ if(ev->_any!=NULL) {
++ /* XXX is this the correct type? */
++ ev->_any->_type = (CORBA_TypeCode)TC_CORBA_ExceptionDescription;
++ ev->_any->_value = ev->_params;
++ ev->_any->_release = 0;
++ }
++
++ return(ev->_any);
++}
++#endif /* !__KORBIT__ */
++
++/**** ORBit_handle_exception
++ Inputs: 'rb' - a receive buffer for which an exception condition has
++ been determined
++ 'ev' - memory in which to store the exception information
++
++ 'user_exceptions' - list of user exceptions raisable
++ for this particular operation.
++ Side-effects: reinitializes '*ev'
++
++ Description:
++ During demarshalling a reply, if reply_status != CORBA_NO_EXCEPTION,
++ we must find out what exception was raised and place that information
++ in '*ev'. */
++
++void ORBit_handle_exception(GIOPRecvBuffer *rb, CORBA_Environment *ev,
++ const ORBit_exception_demarshal_info *user_exceptions,
++ CORBA_ORB orb)
++{
++ CORBA_SystemException *new;
++ CORBA_unsigned_long len, completion_status;
++ CORBA_char *my_repoid;
++
++ g_return_if_fail(GIOP_MESSAGE_BUFFER(rb)->message_header.message_type == GIOP_REPLY);
++
++ CORBA_exception_free(ev);
++
++ rb->cur = ALIGN_ADDRESS(rb->cur, sizeof(len));
++ rb->decoder(&len, rb->cur, sizeof(len));
++ /* (guchar *)rb->cur += sizeof(len); */
++ rb->cur = ((guchar *)rb->cur) + sizeof(len);
++
++ if(len) {
++ my_repoid = rb->cur;
++ rb->cur = ((guchar *)rb->cur) + len;
++ } else
++ my_repoid = NULL;
++
++ if(rb->message.u.reply.reply_status == CORBA_SYSTEM_EXCEPTION) {
++ CORBA_unsigned_long minor;
++
++ ev->_major = CORBA_SYSTEM_EXCEPTION;
++
++ rb->cur = ALIGN_ADDRESS(rb->cur, sizeof(minor));
++ rb->decoder(&minor, rb->cur, sizeof(minor));
++ rb->cur = ((guchar *)rb->cur) + sizeof(minor);
++
++ rb->cur = ALIGN_ADDRESS(rb->cur, sizeof(completion_status));
++ rb->decoder(&completion_status, rb->cur, sizeof(completion_status));
++ rb->cur = ((guchar *)rb->cur) + sizeof(completion_status);
++
++ new=ORBit_alloc(sizeof(CORBA_SystemException), NULL, NULL);
++
++ if(new!=NULL) {
++ new->minor=minor;
++ new->completed=completion_status;
++
++ /* XXX what should the repo ID be? */
++ CORBA_exception_set(ev, CORBA_SYSTEM_EXCEPTION,
++ my_repoid,
++ new);
++ }
++ } else if(rb->message.u.reply.reply_status == CORBA_USER_EXCEPTION) {
++ int i;
++
++ if(!user_exceptions) {
++ /* weirdness; they raised an exception that we don't
++ know about */
++ CORBA_exception_set_system(ev, ex_CORBA_MARSHAL,
++ CORBA_COMPLETED_MAYBE);
++ } else {
++ for(i = 0; user_exceptions[i].tc != CORBA_OBJECT_NIL;
++ i++) {
++ if(!strcmp(user_exceptions[i].tc->repo_id,
++ my_repoid))
++ break;
++ }
++
++ if(user_exceptions[i].tc == CORBA_OBJECT_NIL) {
++ /* weirdness; they raised an exception
++ that we don't know about */
++ CORBA_exception_set_system(ev, ex_CORBA_MARSHAL,
++ CORBA_COMPLETED_MAYBE);
++ } else {
++ user_exceptions[i].demarshal(rb, ev);
++ }
++ }
++ };
++
++ /* ignore LOCATION_FORWARD here, that gets handled in the stub */
++}
++
++void
++ORBit_send_system_exception(GIOPSendBuffer *send_buffer,
++ CORBA_Environment *ev)
++{
++ CORBA_unsigned_long minor;
++ CORBA_unsigned_long completion_status;
++ CORBA_SystemException *se = ev->_params;
++
++ minor = se->minor;
++ completion_status = se->completed;
++
++ ENCODER_CALL(CORBA_char, ev->_repo_id);
++ giop_send_buffer_append_mem_indirect_a(send_buffer, &minor,
++ sizeof(minor));
++ giop_send_buffer_append_mem_indirect_a(send_buffer,
++ &completion_status,
++ sizeof(completion_status));
++}
++
++void
++ORBit_send_user_exception(GIOPSendBuffer *send_buffer,
++ CORBA_Environment *ev,
++ const ORBit_exception_marshal_info *user_exceptions)
++{
++ int i;
++
++ for(i = 0; user_exceptions[i].tc != CORBA_OBJECT_NIL; i++) {
++ if(!strcmp(user_exceptions[i].tc->repo_id, ev->_repo_id))
++ break;
++ }
++
++ if(user_exceptions[i].tc == CORBA_OBJECT_NIL) {
++ CORBA_Environment fakeev;
++ CORBA_exception_init(&fakeev);
++ CORBA_exception_set_system(&fakeev, ex_CORBA_UNKNOWN,
++ CORBA_COMPLETED_MAYBE);
++ ORBit_send_system_exception(send_buffer, &fakeev);
++ CORBA_exception_free(&fakeev);
++ } else {
++ ENCODER_CALL(CORBA_char, ev->_repo_id);
++
++ if(user_exceptions[i].marshal && ev->_params)
++ user_exceptions[i].marshal(send_buffer, ev);
++ }
++}
++
++void
++ORBit_handle_system_exception(CORBA_Environment *ev,
++ CORBA_unsigned_long system_exception_minor,
++ CORBA_unsigned_long completion_status,
++ GIOPRecvBuffer *recv_buffer,
++ GIOPSendBuffer *send_buffer)
++{
++ CORBA_exception_set_system(ev, system_exception_minor, completion_status);
++
++ if(send_buffer)
++ giop_send_buffer_unuse(send_buffer);
++
++ if(recv_buffer)
++ giop_recv_buffer_unuse(recv_buffer);
++}
+diff -urN linux-2.4.1/net/korbit/orb/env.h linux-2.4.1-korbit/net/korbit/orb/env.h
+--- linux-2.4.1/net/korbit/orb/env.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/env.h Thu Feb 1 16:21:56 2001
+@@ -0,0 +1,79 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998, 1999 Richard H. Porter, Red Hat Software
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_ENV_H_
++#define _ORBIT_ENV_H_
++
++#include "orbit_types.h"
++
++extern void CORBA_exception_set(CORBA_Environment *ev,
++ CORBA_exception_type major,
++ const CORBA_char *except_repos_id,
++ void *param);
++
++extern void CORBA_exception_set_system(CORBA_Environment *ev,
++ CORBA_unsigned_long ex_value,
++ CORBA_completion_status completed);
++
++extern void CORBA_exception_init(CORBA_Environment *ev);
++
++extern CORBA_char *CORBA_exception_id(CORBA_Environment *e);
++
++extern void *CORBA_exception_value(CORBA_Environment *ev);
++
++extern void CORBA_exception_free(CORBA_Environment *ev);
++
++#ifndef __KORBIT__
++extern CORBA_any *CORBA_exception_as_any(CORBA_Environment *ev);
++#endif /* !__KORBIT__ */
++
++typedef struct {
++ const CORBA_TypeCode tc;
++ void (*demarshal)(GIOPRecvBuffer *_ORBIT_recv_buffer, CORBA_Environment *ev);
++} ORBit_exception_demarshal_info;
++
++typedef struct {
++ const CORBA_TypeCode tc;
++ void (*marshal)(GIOPSendBuffer *_ORBIT_send_buffer, CORBA_Environment *ev);
++} ORBit_exception_marshal_info;
++
++/* ORBit-specific */
++void ORBit_handle_exception(GIOPRecvBuffer *rb, CORBA_Environment *ev,
++ const ORBit_exception_demarshal_info *user_exceptions,
++ CORBA_ORB orb);
++void ORBit_send_system_exception(GIOPSendBuffer *send_buffer,
++ CORBA_Environment *ev);
++void ORBit_send_user_exception(GIOPSendBuffer *send_buffer,
++ CORBA_Environment *ev,
++ const ORBit_exception_marshal_info *user_exceptions);
++
++/* Used by stubs */
++void ORBit_handle_system_exception(CORBA_Environment *ev,
++ CORBA_unsigned_long system_exception_minor,
++ CORBA_unsigned_long completion_status,
++ GIOPRecvBuffer *recv_buffer,
++ GIOPSendBuffer *send_buffer);
++
++#endif /* !_ORBIT_ENV_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/genrand.c linux-2.4.1-korbit/net/korbit/orb/genrand.c
+--- linux-2.4.1/net/korbit/orb/genrand.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/genrand.c Thu Feb 1 11:47:12 2001
+@@ -0,0 +1,131 @@
++#include "genrand.h"
++#include "ORBitutil/util.h"
++#include <unistd.h>
++#include <sys/types.h>
++#include <fcntl.h>
++#include <glib.h>
++#include <signal.h>
++#include <sys/time.h>
++#include <limits.h>
++#include <stdio.h>
++#ifdef __KERNEL__
++#include <linux/random.h>
++#endif
++
++static gboolean
++genrand_dev(guchar *buffer, int buf_len)
++{
++#ifdef __KERNEL__
++ get_random_bytes(buffer, buf_len);
++#else /*! __KERNEL__*/
++ int fd;
++
++ fd = open("/dev/urandom", O_RDONLY);
++ if(fd < 0)
++ return FALSE;
++
++ if(read(fd, buffer, buf_len) < buf_len)
++ {
++ close(fd);
++ return FALSE;
++ }
++
++ close(fd);
++#endif /*! __KERNEL__*/
++
++ return TRUE;
++}
++
++#ifndef __KORBIT__
++static volatile int received_alarm = 0;
++
++static void
++handle_alarm(int signum)
++{
++ received_alarm = 1;
++}
++
++static inline guchar
++hashlong(long val)
++{
++ guchar retval, *ptr;
++ int i;
++
++ for(ptr = (guchar *)&val, i = 0; i < sizeof(val); i++)
++ retval ^= ptr[i];
++
++ return retval;
++}
++
++static gboolean
++genrand_unix(guchar *buffer, int buf_len)
++{
++ struct sigaction sa, oldsa;
++ struct itimerval it, oldit;
++ int i;
++ long min, max;
++ long *counts;
++ double diff;
++ long *uninit;
++
++ counts = alloca(buf_len * sizeof(long));
++
++ memset(&sa, 0, sizeof(sa));
++ sa.sa_handler = handle_alarm;
++ sigaction(SIGALRM, &sa, &oldsa);
++ memset(&it, 0, sizeof(it));
++ it.it_value.tv_usec = 1;
++ getitimer(ITIMER_REAL, &oldit);
++
++ for(i = 0, min = LONG_MAX, max = 0; i < buf_len; i++)
++ {
++ received_alarm = 0;
++ setitimer(ITIMER_REAL, &it, NULL);
++ for(counts[i] = 0; !received_alarm; counts[i]++);
++
++ max = MAX(counts[i], max);
++ min = MIN(counts[i], min);
++ }
++
++ if(!(max - min))
++ {
++ freeca(counts);
++ return FALSE;
++ }
++
++ diff = max - min;
++
++ uninit = alloca(buf_len * sizeof(long)); /* Purposely not initialized */
++ for(i = 0; i < buf_len; i++)
++ {
++ long diffval;
++ diffval = counts[i] - min;
++
++ buffer[i] ^= (guchar)( ((double) (diffval*256) / diff )) ^ hashlong(uninit[i]);
++ }
++
++ setitimer(ITIMER_REAL, &oldit, NULL);
++ sigaction(SIGALRM, &oldsa, NULL);
++
++ freeca(counts);
++ freeca(uninit);
++
++ return TRUE;
++}
++#endif /* !__KORBIT__ */
++
++void
++orbit_genrand(guchar *buffer, int buf_len)
++{
++ g_return_if_fail(buf_len);
++
++ if(genrand_dev(buffer, buf_len))
++ return;
++#ifndef __KORBIT__
++ else if(genrand_unix(buffer, buf_len))
++ return;
++#endif
++ else
++ g_error("Couldn't generate random data!");
++}
++
+diff -urN linux-2.4.1/net/korbit/orb/genrand.h linux-2.4.1-korbit/net/korbit/orb/genrand.h
+--- linux-2.4.1/net/korbit/orb/genrand.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/genrand.h Thu Feb 1 11:47:12 2001
+@@ -0,0 +1,8 @@
++#ifndef ORBIT_GENRAND_H
++#define ORBIT_GENRAND_H 1
++
++#include <glib.h>
++
++void orbit_genrand(guchar *buffer, int buf_len);
++
++#endif /* ORBIT_GENRAND_H */
+diff -urN linux-2.4.1/net/korbit/orb/iop.h linux-2.4.1-korbit/net/korbit/orb/iop.h
+--- linux-2.4.1/net/korbit/orb/iop.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/iop.h Thu Feb 1 11:47:12 2001
+@@ -0,0 +1,207 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_IOP_H_
++#define _ORBIT_IOP_H_
++
++#include <ORBitutil/basic_types.h>
++
++#include <orb/corba_basic_sequences_type.h>
++
++#ifndef HAVE_CORBA_PRINCIPAL
++#define HAVE_CORBA_PRINCIPAL 1
++typedef CORBA_sequence_octet CORBA_Principal;
++#endif
++
++typedef CORBA_unsigned_long IOP_ProfileId;
++
++#define IOP_TAG_INTERNET_IOP 0
++#define IOP_TAG_MULTIPLE_COMPONENTS 1
++#define IOP_TAG_ORBIT_SPECIFIC 0xbadfaecal
++
++typedef struct IOP_TaggedProfile {
++ IOP_ProfileId tag;
++ CORBA_sequence_octet profile_data;
++} IOP_TaggedProfile;
++
++typedef struct CORBA_sequence_TaggedProfile {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ IOP_TaggedProfile *_buffer;
++} CORBA_sequence_TaggedProfile;
++
++typedef struct IOP_IOR {
++ CORBA_char *type_id;
++ CORBA_sequence_TaggedProfile profiles;
++} IOP_IOR;
++
++typedef CORBA_unsigned_long IOP_ComponentId;
++
++typedef struct IOP_TaggedComponent {
++ IOP_ComponentId tag;
++ CORBA_sequence_octet component_data;
++} IOP_TaggedComponent;
++
++typedef struct CORBA_sequence_TaggedComponent {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ IOP_TaggedComponent *_buffer;
++} CORBA_sequence_TaggedComponent;
++
++typedef struct CORBA_sequence_TaggedComponent IOP_MultipleComponentProfile;
++
++#define IOP_TAG_ORB_TYPE 0
++#define IOP_TAG_CODE_SETS 1
++#define IOP_TAG_SEC_NAME 14
++#define IOP_TAG_ASSOCIATION_OPTIONS 13
++#define IOP_TAG_GENERIC_SEC_MECH 12
++
++typedef CORBA_unsigned_long IOP_ServiceId;
++
++typedef struct IOP_ServiceContext {
++ IOP_ServiceId context_id;
++ CORBA_sequence_octet context_data;
++} IOP_ServiceContext;
++
++typedef struct CORBA_sequence_ServiceContext {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ IOP_ServiceContext *_buffer;
++} CORBA_sequence_ServiceContext;
++
++typedef struct CORBA_sequence_ServiceContext IOP_ServiceContextList;
++
++#define IOP_TransactionService 0
++#define IOP_CodeSets 1
++
++typedef CORBA_unsigned_long CONV_FRAME_CodeSetId;
++
++typedef struct CORBA_sequence_CodeSetId {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ CONV_FRAME_CodeSetId *_buffer;
++} CORBA_sequence_CodeSetId;
++
++typedef struct CONV_FRAME_CodeSetComponent {
++ CONV_FRAME_CodeSetId native_code_set;
++ CORBA_sequence_CodeSetId conversion_code_sets;
++} CONV_FRAME_CodeSetComponent;
++
++typedef struct CONV_FRAME_CodeSetComponentInfo {
++ CONV_FRAME_CodeSetComponent ForCharData;
++ CONV_FRAME_CodeSetComponent ForWcharData;
++} CONV_FRAME_CodeSetComponentInfo;
++
++typedef struct CONV_FRAME_CodeSetContext {
++ CONV_FRAME_CodeSetId char_data;
++ CONV_FRAME_CodeSetId wchar_data;
++} CONV_FRAME_CodeSetContext;
++
++typedef struct GIOP_Version {
++ CORBA_octet major;
++ CORBA_octet minor;
++} GIOP_Version;
++
++typedef enum {
++ GIOP_Request=0,
++ GIOP_Reply,
++ GIOP_CancelRequest,
++ GIOP_LocateRequest,
++ GIOP_LocateReply,
++ GIOP_CloseConnection,
++ GIOP_MessageError
++} GIOP_MsgType_1_0;
++
++typedef struct GIOP_MessageHeader_1_0 {
++ CORBA_char magic[4];
++ GIOP_Version GIOP_version;
++ CORBA_boolean byte_order;
++ CORBA_octet message_type;
++ CORBA_unsigned_long message_size;
++} GIOP_MessageHeader_1_0;
++
++typedef struct GIOP_MessageHeader_1_1 {
++ CORBA_char magic[4];
++ GIOP_Version GIOP_version;
++ CORBA_octet flags;
++ CORBA_octet message_type;
++ CORBA_unsigned_long message_size;
++} GIOP_MessageHeader_1_1;
++
++typedef struct GIOP_RequestHeader_1_0 {
++ IOP_ServiceContextList service_context;
++ CORBA_unsigned_long request_id;
++ CORBA_boolean response_expected;
++ CORBA_sequence_octet object_key;
++ CORBA_char *operation;
++ CORBA_Principal requesting_principal;
++} GIOP_RequestHeader_1_0;
++
++typedef struct GIOP_RequestHeader_1_1 {
++ IOP_ServiceContextList service_context;
++ CORBA_unsigned_long request_id;
++ CORBA_boolean response_expected;
++ CORBA_octet reserved[3];
++ CORBA_sequence_octet object_key;
++ CORBA_char *operation;
++ CORBA_Principal requesting_principal;
++} GIOP_RequestHeader_1_1;
++
++typedef struct GIOP_SystemExceptionReplyBody {
++ CORBA_char *exception_id;
++ CORBA_unsigned_long minor_code_value;
++ CORBA_unsigned_long completion_status;
++} GIOP_SystemExceptionReplyBody;
++
++typedef struct GIOP_CancelRequestHeader {
++ CORBA_unsigned_long request_id;
++} GIOP_CancelRequestHeader;
++
++typedef struct GIOP_LocateRequestHeader {
++ CORBA_unsigned_long request_id;
++ CORBA_sequence_octet object_key;
++} GIOP_LocateRequestHeader;
++
++typedef struct IIOP_Version {
++ CORBA_octet major;
++ CORBA_octet minor;
++} IIOP_Version;
++
++typedef struct IIOP_ProfileBody_1_0 {
++ IIOP_Version iiop_version;
++ CORBA_char *host;
++ CORBA_unsigned_short port;
++ CORBA_sequence_octet object_key;
++} IIOP_ProfileBody_1_0;
++
++typedef struct IIOP_ProfileBody_1_1 {
++ IIOP_Version iiop_version;
++ CORBA_char *host;
++ CORBA_unsigned_short port;
++ CORBA_sequence_octet object_key;
++ CORBA_sequence_TaggedComponent components;
++} IIOP_ProfileBody_1_1;
++
++#endif /* !_ORBIT_IOP_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/ir.c linux-2.4.1-korbit/net/korbit/orb/ir.c
+--- linux-2.4.1/net/korbit/orb/ir.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/ir.c Thu Feb 1 11:47:12 2001
+@@ -0,0 +1,293 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#include <stdlib.h>
++#include <assert.h>
++
++#include "orbit.h"
++
++/* FIXME: Right now this function doesn't record whether or not it has
++ already visited a given TypeCode. I'm not sure if every recursive
++ type will have a tk_recursive node in it; if not, then this will
++ need to be reworked a bit. */
++CORBA_boolean CORBA_TypeCode_equal(CORBA_TypeCode obj, CORBA_TypeCode tc, CORBA_Environment *ev)
++{
++ int i;
++
++ g_return_val_if_fail(obj!=NULL, CORBA_FALSE);
++ g_return_val_if_fail(tc!=NULL, CORBA_FALSE);
++
++ if (obj->kind != tc->kind) {
++ return CORBA_FALSE;
++ }
++
++ switch (obj->kind) {
++ case CORBA_tk_wstring:
++ case CORBA_tk_string:
++ return obj->length == tc->length;
++ case CORBA_tk_objref:
++ return ! strcmp (obj->repo_id, tc->repo_id);
++ case CORBA_tk_except:
++ case CORBA_tk_struct:
++ if (strcmp (obj->repo_id, tc->repo_id)
++ || obj->sub_parts != tc->sub_parts)
++ return CORBA_FALSE;
++ for (i = 0; i < obj->sub_parts; ++i)
++ if (! CORBA_TypeCode_equal (obj->subtypes[i],
++ tc->subtypes[i], ev))
++ return CORBA_FALSE;
++ break;
++ case CORBA_tk_union:
++ if (strcmp (obj->repo_id, tc->repo_id)
++ || obj->sub_parts != tc->sub_parts
++ || ! CORBA_TypeCode_equal (obj->discriminator,
++ tc->discriminator, ev)
++ || obj->default_index != tc->default_index)
++ return CORBA_FALSE;
++ for (i = 0; i < obj->sub_parts; ++i)
++
++ if (! CORBA_TypeCode_equal (obj->subtypes[i],
++ tc->subtypes[i], ev)
++ || ! ORBit_any_equivalent (obj->sublabels[i],
++ tc->sublabels[i], ev))
++ return CORBA_FALSE;
++
++ break;
++ case CORBA_tk_enum:
++ if (obj->sub_parts != tc->sub_parts
++ || strcmp (obj->repo_id, tc->repo_id))
++ return CORBA_FALSE;
++ for (i = 0; i < obj->sub_parts; ++i)
++ if (strcmp (obj->subnames[i], tc->subnames[i]))
++ return CORBA_FALSE;
++ break;
++ case CORBA_tk_sequence:
++ case CORBA_tk_array:
++ if (obj->length != tc->length)
++ return CORBA_FALSE;
++ g_assert (obj->sub_parts == 1);
++ g_assert (tc->sub_parts == 1);
++ return CORBA_TypeCode_equal (obj->subtypes[0], tc->subtypes[0],
++ ev);
++ case CORBA_tk_alias:
++ if (strcmp (obj->repo_id, tc->repo_id))
++ return CORBA_FALSE;
++
++ g_assert (obj->sub_parts == 1);
++ g_assert (tc->sub_parts == 1);
++
++ return CORBA_TypeCode_equal (obj->subtypes[0], tc->subtypes[0],
++ ev);
++ break;
++ case CORBA_tk_recursive:
++ return obj->recurse_depth == tc->recurse_depth;
++ case CORBA_tk_fixed:
++ return obj->digits == tc->digits && obj->scale == tc->scale;
++
++ default:
++ /* Everything else is primitive. */
++ break;
++ }
++
++ return CORBA_TRUE;
++}
++
++CORBA_TCKind CORBA_TypeCode_kind(CORBA_TypeCode obj, CORBA_Environment *ev)
++{
++ return obj->kind;
++}
++
++static void bad_kind (CORBA_Environment *ev)
++{
++ CORBA_TypeCode_BadKind *err;
++ err = g_new (CORBA_TypeCode_BadKind, 1);
++ if (err == NULL) {
++ CORBA_exception_set_system (ev, ex_CORBA_NO_MEMORY,
++ CORBA_COMPLETED_NO);
++ } else {
++ err->dummy = 23;
++ CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
++ "IDL:omg.org/CORBA/TypeCode/BadKind/1.0",
++ err);
++ }
++}
++
++CORBA_RepositoryId CORBA_TypeCode_id(CORBA_TypeCode obj, CORBA_Environment *ev)
++{
++ if (! (obj->kind == CORBA_tk_objref || obj->kind == CORBA_tk_struct
++ || obj->kind == CORBA_tk_enum || obj->kind == CORBA_tk_alias
++ || obj->kind == CORBA_tk_except)) {
++ bad_kind (ev);
++ return NULL;
++ }
++ return obj->repo_id;
++}
++
++CORBA_Identifier CORBA_TypeCode_name(CORBA_TypeCode obj, CORBA_Environment *ev)
++{
++ if (! (obj->kind == CORBA_tk_objref || obj->kind == CORBA_tk_struct
++ || obj->kind == CORBA_tk_enum || obj->kind == CORBA_tk_alias
++ || obj->kind == CORBA_tk_except)) {
++ bad_kind (ev);
++ return NULL;
++ }
++
++ return obj->name;
++}
++
++CORBA_unsigned_long CORBA_TypeCode_member_count(CORBA_TypeCode obj, CORBA_Environment *ev)
++{
++ if (! (obj->kind == CORBA_tk_struct || obj->kind == CORBA_tk_union
++ || obj->kind == CORBA_tk_enum)) {
++ bad_kind (ev);
++ return 0;
++ }
++ return obj->sub_parts;
++}
++
++static void bounds_error (CORBA_Environment *ev)
++{
++ CORBA_TypeCode_Bounds *err;
++ err = g_new (CORBA_TypeCode_Bounds, 1);
++ if (err == NULL) {
++ CORBA_exception_set_system (ev, ex_CORBA_NO_MEMORY,
++ CORBA_COMPLETED_NO);
++ } else {
++ err->dummy = 23;
++ CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
++ "IDL:omg.org/CORBA/TypeCode/Bounds/1.0",
++ err);
++ }
++}
++
++CORBA_Identifier CORBA_TypeCode_member_name(CORBA_TypeCode obj, CORBA_unsigned_long index, CORBA_Environment *ev)
++{
++ if (! (obj->kind == CORBA_tk_struct || obj->kind == CORBA_tk_union
++ || obj->kind == CORBA_tk_enum)) {
++ bad_kind (ev);
++ return NULL;
++ }
++ if (index > obj->sub_parts) {
++ bounds_error (ev);
++ return NULL;
++ }
++ return obj->subnames[index];
++}
++
++CORBA_TypeCode CORBA_TypeCode_member_type(CORBA_TypeCode obj, CORBA_unsigned_long index, CORBA_Environment *ev)
++{
++ if (! (obj->kind == CORBA_tk_struct || obj->kind == CORBA_tk_union
++ || obj->kind == CORBA_tk_enum)) {
++ bad_kind (ev);
++ return NULL;
++ }
++ if (index > obj->sub_parts) {
++ bounds_error (ev);
++ return NULL;
++ }
++ return obj->subtypes[index];
++}
++
++CORBA_any *CORBA_TypeCode_member_label(CORBA_TypeCode obj, CORBA_unsigned_long index, CORBA_Environment *ev)
++{
++ if (obj->kind != CORBA_tk_union) {
++ bad_kind (ev);
++ return NULL;
++ }
++ if (index > obj->sub_parts) {
++ bounds_error (ev);
++ return NULL;
++ }
++ return &obj->sublabels[index];
++}
++
++CORBA_TypeCode CORBA_TypeCode_discriminator_type(CORBA_TypeCode obj, CORBA_Environment *ev)
++{
++ if (obj->kind != CORBA_tk_union) {
++ bad_kind (ev);
++ return NULL;
++ }
++ return obj->discriminator;
++}
++
++CORBA_long CORBA_TypeCode_default_index(CORBA_TypeCode obj, CORBA_Environment *ev)
++{
++ if (obj->kind != CORBA_tk_union) {
++ bad_kind (ev);
++ return 0;
++ }
++ return obj->default_index;
++}
++
++CORBA_unsigned_long CORBA_TypeCode_length(CORBA_TypeCode obj, CORBA_Environment *ev)
++{
++ if (! (obj->kind == CORBA_tk_string || obj->kind == CORBA_tk_wstring
++ || obj->kind == CORBA_tk_array)) {
++ bad_kind (ev);
++ return 0;
++ }
++ return obj->length;
++}
++
++CORBA_TypeCode CORBA_TypeCode_content_type(CORBA_TypeCode obj, CORBA_Environment *ev)
++{
++ if (! (obj->kind == CORBA_tk_sequence || obj->kind == CORBA_tk_array
++ || obj->kind == CORBA_tk_alias)) {
++ bad_kind (ev);
++ return NULL;
++ }
++ g_assert (obj->sub_parts == 1);
++ return obj->subtypes[0];
++}
++
++CORBA_unsigned_short CORBA_TypeCode_fixed_digits(CORBA_TypeCode obj, CORBA_Environment *ev)
++{
++ if (obj->kind != CORBA_tk_fixed) {
++ bad_kind (ev);
++ return 0;
++ }
++ return obj->digits;
++}
++
++CORBA_short CORBA_TypeCode_fixed_scale(CORBA_TypeCode obj, CORBA_Environment *ev)
++{
++ if (obj->kind != CORBA_tk_fixed) {
++ bad_kind (ev);
++ return 0;
++ }
++ return obj->scale;
++}
++
++CORBA_long CORBA_TypeCode_param_count(CORBA_TypeCode obj, CORBA_Environment *ev)
++{
++ g_assert(!"Deprecated");
++ return(0);
++}
++
++CORBA_any *CORBA_TypeCode_parameter(CORBA_TypeCode obj, CORBA_long index, CORBA_Environment *ev)
++{
++ g_assert(!"Deprecated");
++ return(NULL);
++}
+diff -urN linux-2.4.1/net/korbit/orb/ir.h linux-2.4.1-korbit/net/korbit/orb/ir.h
+--- linux-2.4.1/net/korbit/orb/ir.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/ir.h Thu Feb 1 11:47:12 2001
+@@ -0,0 +1,100 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_IR_H_
++#define _ORBIT_IR_H_
++
++#include "orbit_types.h"
++
++extern CORBA_boolean CORBA_TypeCode_equal(
++ CORBA_TypeCode obj,
++ CORBA_TypeCode tc,
++ CORBA_Environment *ev);
++
++extern CORBA_TCKind CORBA_TypeCode_kind(
++ CORBA_TypeCode obj,
++ CORBA_Environment *ev);
++
++extern CORBA_RepositoryId CORBA_TypeCode_id(
++ CORBA_TypeCode obj,
++ CORBA_Environment *ev);
++
++extern CORBA_Identifier CORBA_TypeCode_name(
++ CORBA_TypeCode obj,
++ CORBA_Environment *ev);
++
++extern CORBA_unsigned_long CORBA_TypeCode_member_count(
++ CORBA_TypeCode obj,
++ CORBA_Environment *ev);
++
++extern CORBA_Identifier CORBA_TypeCode_member_name(
++ CORBA_TypeCode obj,
++ CORBA_unsigned_long index,
++ CORBA_Environment *ev);
++
++extern CORBA_TypeCode CORBA_TypeCode_member_type(
++ CORBA_TypeCode obj,
++ CORBA_unsigned_long index,
++ CORBA_Environment *ev);
++
++extern CORBA_any *CORBA_TypeCode_member_label(
++ CORBA_TypeCode obj,
++ CORBA_unsigned_long index,
++ CORBA_Environment *ev);
++
++extern CORBA_TypeCode CORBA_TypeCode_discriminator_type(
++ CORBA_TypeCode obj,
++ CORBA_Environment *ev);
++
++extern CORBA_long CORBA_TypeCode_default_index(
++ CORBA_TypeCode obj,
++ CORBA_Environment *ev);
++
++extern CORBA_unsigned_long CORBA_TypeCode_length(
++ CORBA_TypeCode obj,
++ CORBA_Environment *ev);
++
++extern CORBA_TypeCode CORBA_TypeCode_content_type(
++ CORBA_TypeCode obj,
++ CORBA_Environment *ev);
++
++extern CORBA_unsigned_short CORBA_TypeCode_fixed_digits(
++ CORBA_TypeCode obj,
++ CORBA_Environment *ev);
++
++extern CORBA_short CORBA_TypeCode_fixed_scale(
++ CORBA_TypeCode obj,
++ CORBA_Environment *ev);
++
++extern CORBA_long CORBA_TypeCode_param_count(
++ CORBA_TypeCode obj,
++ CORBA_Environment *ev);
++
++extern CORBA_any *CORBA_TypeCode_parameter(
++ CORBA_TypeCode obj,
++ CORBA_long index,
++ CORBA_Environment *ev);
++
++#endif /* !_ORBIT_IR_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/options.c linux-2.4.1-korbit/net/korbit/orb/options.c
+--- linux-2.4.1/net/korbit/orb/options.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/options.c Thu Feb 1 11:47:12 2001
+@@ -0,0 +1,160 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++/*
++ * Option parsing
++ *
++ * All ORB options are stripped from the application's argv, and argc is
++ * adjusted accordingly
++ */
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <glib.h>
++
++#include "options.h"
++
++#ifndef __KORBIT__
++void ORBit_option_set(ORBit_orb_options *option, const char *val)
++{
++ g_assert(option!=NULL);
++
++ if(option->type==no_arg && option->arg!=NULL) {
++ /* Treat as an int arg with val=1
++ */
++ int *int_arg=(int *)option->arg;
++
++ *int_arg=1;
++ } else {
++ if(option->type==string_arg && option->arg!=NULL) {
++ char **str_arg=(char **)option->arg;
++
++ /* free any existing value */
++ if(*str_arg!=NULL) {
++ g_free(*str_arg);
++ }
++ *str_arg=g_strdup(val);
++ } else if(option->type==int_arg && option->arg!=NULL) {
++ int *int_arg=(int *)option->arg;
++
++ *int_arg=atoi(val);
++ }
++
++ }
++}
++
++void ORBit_option_parse(int *argc, char **argv, ORBit_orb_options *options)
++{
++ int i,j,numargs;
++ char name[1024], *val;
++ ORBit_orb_options *search=NULL;
++ int *erase;
++
++ numargs=*argc;
++
++ erase=g_new0(int, *argc);
++
++ for(i=1; i< *argc; i++) {
++ if(argv[i][0]!='-') {
++ if(search==NULL) {
++ /* Skip non-option */
++ continue;
++ } else {
++ /* an required option value has been found */
++ erase[i]=1;
++ numargs-=1;
++
++ if(search->arg==NULL) {
++ /* dont store any values, just strip
++ * the argv
++ */
++ search=NULL;
++ continue;
++ }
++
++ ORBit_option_set(search, argv[i]);
++
++ search=NULL;
++ continue;
++ }
++ } else {
++ if(search!=NULL &&
++ (search->type==string_arg || search->type==int_arg)) {
++ fprintf(stderr, "Option %s requires an argument\n", search->name);
++ }
++ }
++
++ val=argv[i];
++ while(*val && *val=='-')
++ val++;
++
++ strncpy(name,val,1023);
++ name[1023]='\0';
++
++ val=strchr(name, '=');
++ if(val!=NULL) {
++ *val++='\0';
++ }
++
++ for(search=options;search->name!=NULL;search++) {
++ if(!strcmp(name, search->name)) {
++ break;
++ }
++ }
++
++ if(search->name==NULL) {
++ /* Didn't find it in our list of interesting options */
++ search=NULL;
++ } else {
++ /* Found it */
++ erase[i]=1;
++ numargs-=1;
++
++ if(search->type==no_arg || val!=NULL) {
++ ORBit_option_set(search, val);
++ search=NULL;
++ }
++ }
++ }
++
++ j=1;
++ for(i=1; i< *argc; i++) {
++ if(erase[i]==1) {
++ continue;
++ } else {
++ if(j<numargs) {
++ argv[j++]=argv[i];
++ } else {
++ argv[j++]='\0';
++ }
++ }
++ }
++
++ *argc=numargs;
++
++ g_free(erase);
++}
++#endif /* !__KORBIT__ */
+diff -urN linux-2.4.1/net/korbit/orb/options.h linux-2.4.1-korbit/net/korbit/orb/options.h
+--- linux-2.4.1/net/korbit/orb/options.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/options.h Thu Feb 1 11:47:13 2001
+@@ -0,0 +1,46 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_OPTIONS_H_
++#define _ORBIT_OPTIONS_H_
++
++typedef enum {
++ no_arg=0,
++ string_arg,
++ int_arg
++} ORBit_opt_type;
++
++typedef struct {
++ char *name;
++ ORBit_opt_type type;
++ void *arg;
++} ORBit_orb_options;
++
++#ifndef __KORBIT__
++extern void ORBit_option_set(ORBit_orb_options *found, const char *val);
++extern void ORBit_option_parse(int *argc, char **argv, ORBit_orb_options *options);
++#endif
++
++#endif /* !_ORBIT_OPTIONS_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/orb.c linux-2.4.1-korbit/net/korbit/orb/orb.c
+--- linux-2.4.1/net/korbit/orb/orb.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orb.c Thu Feb 1 11:47:13 2001
+@@ -0,0 +1,1700 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter and Red Hat Software
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@acm.org>
++ * Elliot Lee <sopwith@redhat.com>
++ *
++ */
++
++#define o_return_val_if_fail(expr, val) if(!(expr)) { CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM, CORBA_COMPLETED_NO); return (val); }
++#define o_return_if_fail(expr) if(!(expr)) { CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM, CORBA_COMPLETED_NO); return; }
++
++#include "config.h"
++
++#include <unistd.h>
++#include <errno.h>
++#include <sys/stat.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <ctype.h>
++#include <assert.h>
++#include <pwd.h>
++#include <time.h>
++#include <sys/types.h>
++#include <dirent.h>
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <sys/un.h>
++#include <utime.h>
++
++#include "../IIOP/iiop-endianP.h"
++#include "orbit.h"
++
++#include "orbit_poa.h"
++#include "orbit_object.h"
++#include "orbit_object_type.h"
++
++#ifndef __KERNEL__
++#define freeca(ptr)
++#endif
++
++#ifndef SUN_LEN
++/* This system is not POSIX.1g. */
++#define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
++ + strlen ((ptr)->sun_path))
++#endif
++
++static void ORBit_ORB_release(CORBA_ORB orb, CORBA_Environment *ev);
++
++static const ORBit_RootObject_Interface CORBA_ORB_epv =
++{
++ (void (*)(gpointer, CORBA_Environment *))ORBit_ORB_release
++};
++
++
++static int ORBit_ORBid_setup(CORBA_ORB orb, CORBA_ORBid id)
++{
++ g_assert(orb!=NULL);
++ g_assert(id!=NULL);
++
++ if(strcmp(id, "orbit-local-orb")) {
++#ifdef __KORBIT__
++ printf("ORBit_ORBid_setup: Unknown ORB id: %s\n", id);
++#else
++ fprintf(stderr, "ORBit_ORBid_setup: Unknown ORB id: %s\n", id);
++#endif
++ return(0);
++ }
++
++ orb->orb_identifier=g_strdup(id);
++
++ return(1);
++}
++
++#ifndef __KORBIT__
++static gboolean
++free_key_and_data(gpointer key, gpointer data, gpointer user_data)
++{
++ g_free(key); g_free(data);
++
++ return TRUE;
++}
++
++static void ORBit_rc_load(const char *rcfile, ORBit_orb_options *options)
++{
++ FILE *fp;
++ GHashTable *read_options;
++ ORBit_orb_options *search;
++
++ fp=fopen(rcfile, "r");
++
++ if(fp==NULL)
++ return;
++
++ read_options=g_hash_table_new(g_str_hash, g_str_equal);
++
++ while(!feof(fp)) {
++ char buf[1024];
++
++ if(fgets(buf, 1024, fp)!=NULL) {
++ guchar *bptr, *tmp, *key, *data;
++ size_t start, len;
++
++ if(buf[0]=='#')
++ continue;
++
++ bptr=buf;
++ tmp=strpbrk(bptr, " \t\n=");
++ if(tmp==NULL) continue;
++ *tmp++='\0';
++ key=g_strdup(bptr);
++ bptr=tmp;
++
++ start=0;
++ while(bptr+start != '\0' &&
++ (isspace(bptr[start]) || bptr[start]=='='))
++ start++;
++ len=strcspn(bptr+start, " \t\n");
++ bptr[start+len]='\0';
++ if(len>0) {
++ data=g_strdup(bptr+start);
++ } else {
++ data=g_strdup("TRUE");
++ }
++
++ g_hash_table_insert(read_options, key, data);
++ }
++ }
++ fclose(fp);
++
++ for(search=options;search->name!=NULL;search++) {
++ char *read_val;
++
++ read_val=g_hash_table_lookup(read_options, search->name);
++ if(read_val!=NULL) {
++ ORBit_option_set(search, read_val);
++ }
++ }
++
++ g_hash_table_foreach_remove(read_options, free_key_and_data, NULL);
++ g_hash_table_destroy(read_options);
++}
++#endif /* !__KORBIT__ */
++
++static void ORBit_ORB_release(CORBA_ORB orb, CORBA_Environment *ev)
++{
++ g_assert(orb!=NULL);
++
++ if(--(ORBIT_ROOT_OBJECT(orb)->refs))
++ return;
++
++ if(orb->orb_identifier!=NULL) {
++ g_free(orb->orb_identifier);
++ }
++ if(!CORBA_Object_is_nil(orb->imr, ev)) {
++ CORBA_Object_release(orb->imr, ev);
++ }
++ if(!CORBA_Object_is_nil(orb->ir, ev)) {
++ CORBA_Object_release(orb->ir, ev);
++ }
++ if(!CORBA_Object_is_nil(orb->naming, ev)) {
++ CORBA_Object_release(orb->naming, ev);
++ }
++ if(!CORBA_Object_is_nil(orb->root_poa, ev)) {
++ CORBA_Object_release(orb->root_poa, ev);
++ }
++ if(orb->cnx.ipv4)
++ giop_connection_unref(orb->cnx.ipv4);
++ if(orb->cnx.ipv6)
++ giop_connection_unref(orb->cnx.ipv6);
++#ifndef __KORBIT__
++ if(orb->cnx.usock)
++ giop_connection_unref(orb->cnx.usock);
++#endif
++
++ g_free(orb);
++}
++
++#ifndef __KORBIT__
++static GIOPConnection*
++ORBit_ORB_make_usock_connection(void)
++{
++ GIOPConnection *retval = NULL;
++ GString *tmpstr;
++ struct stat statbuf;
++
++ tmpstr = g_string_new(NULL);
++
++ g_string_sprintf(tmpstr, "/tmp/orbit-%s", g_get_user_name());
++
++ if(mkdir(tmpstr->str, 0700) != 0) {
++ int e = errno;
++
++ switch (e) {
++ case 0:
++ case EEXIST:
++ if (stat(tmpstr->str, &statbuf) != 0)
++ g_error ("Can not stat %s\n", tmpstr->str);
++
++ if (statbuf.st_uid != getuid ())
++ g_error ("Owner of %s is not the current user\n",
++ tmpstr->str);
++
++ if((statbuf.st_mode & (S_IRWXG|S_IRWXO))
++ || !S_ISDIR(statbuf.st_mode))
++ g_error ("Wrong permissions for %s\n",
++ tmpstr->str);
++ break;
++
++ default:
++ g_error("Unknown error on directory creation of %s (%s)\n",
++ tmpstr->str, g_strerror (e));
++ }
++ }
++
++ {
++ struct utimbuf utb;
++ memset(&utb, 0, sizeof(utb));
++ utime(tmpstr->str, &utb);
++ }
++
++
++#ifdef WE_DONT_CARE_ABOUT_STUPID_2DOT0DOTX_KERNELS
++ g_string_sprintf(tmpstr, "/tmp/orbit-%s",
++ g_get_user_name());
++ dirh = opendir(tmpstr->str);
++ while(!retval && (dent = readdir(dirh))) {
++ int usfd, ret;
++ struct sockaddr_un saddr;
++
++ saddr.sun_family = AF_UNIX;
++
++ if(strncmp(dent->d_name, "orb-", 4))
++ continue;
++
++ g_snprintf(saddr.sun_path, sizeof(saddr.sun_path),
++ "/tmp/orbit-%s/%s",
++ g_get_user_name(), dent->d_name);
++
++ usfd = socket(AF_UNIX, SOCK_STREAM, 0);
++ g_assert(usfd >= 0);
++
++ ret = connect(usfd, &saddr, SUN_LEN(&saddr));
++ close(usfd);
++
++ if(ret >= 0)
++ continue;
++
++ unlink(saddr.sun_path);
++ }
++ closedir(dirh);
++#endif /* WE_DONT_CARE_ABOUT_STUPID_2DOT0DOTX_KERNELS */
++
++ srand(time(NULL));
++ while(!retval) {
++ g_string_sprintf(tmpstr, "/tmp/orbit-%s/orb-%d%d",
++ g_get_user_name(), rand(), rand());
++ retval =
++ GIOP_CONNECTION(iiop_connection_server_unix(tmpstr->str));
++ }
++
++ g_string_free(tmpstr, TRUE);
++
++ return retval;
++}
++#endif /* !__KORBIT__ */
++
++
++// Synchronize between the user process starting up the orb and the ORB thread
++// this mutex gets released when the orb is all fired up and ready to go.
++static DECLARE_MUTEX(StartupSem);
++static CORBA_ORB TheOneTrueOrb = 0;
++
++struct CORBA_ORB_init_args { // A pointer to this struct is passed to
++ int *argc; // __CORBA_ORB_init
++ char **argv;
++ CORBA_ORBid orb_identifier;
++ CORBA_Environment *ev;
++};
++
++
++CORBA_ORB __CORBA_ORB_init(struct CORBA_ORB_init_args *Args) {
++ int *argc = Args->argc;
++ char **argv = Args->argv;
++ CORBA_ORBid orb_identifier = Args->orb_identifier;
++ CORBA_Environment *ev = Args->ev;
++
++ int no_iiop_server=0;
++ int no_iiop_proxy=0;
++#ifdef __KORBIT__
++ int use_ipv4=1;
++#else
++ int use_ipv4=0;
++#endif
++ int use_ipv6=0;
++ int use_usock=1;
++ int debug_level=0;
++ int debug_modules=0;
++ int nosysrc=0;
++ int nouserrc=0;
++ char *imr_ior=NULL, *imr_addr=NULL;
++ char *ir_ior=NULL, *ir_addr=NULL;
++ char *naming_ior=NULL, *naming_addr=NULL;
++ char *root_poa_ior=NULL, *root_poa_addr=NULL;
++ char *orb_id_opt=NULL;
++#ifndef __KORBIT__
++ char *ctmp;
++#endif
++ CORBA_ORB orb = 0;
++
++ /* The variable addresses in these structs need to be assigned at
++ * run-time if you want to compile with -pedantic
++ *
++ * (You will also get scads of warnings about "long long" too)
++ */
++
++ ORBit_orb_options pre_rc_options[]={
++ {"ORBNoSystemRC", no_arg, NULL},
++ {"ORBNoUserRC", no_arg, NULL},
++ {NULL, 0, NULL},
++ };
++
++ /* These options are compatible with MICO */
++ ORBit_orb_options options[]={
++ {"ORBNoIIOPServer", no_arg, NULL},
++ {"ORBNoIIOPProxy", no_arg, NULL},
++ {"ORBid", string_arg, NULL},
++ {"ORBImplRepoIOR", string_arg, NULL},
++ {"ORBImplRepoAddr", string_arg, NULL},
++ {"ORBIfaceRepoIOR", string_arg, NULL},
++ {"ORBIfaceRepoAddr", string_arg, NULL},
++ {"ORBNamingIOR", string_arg, NULL},
++ {"ORBNamingAddr", string_arg, NULL},
++ {"ORBDebugLevel", int_arg, NULL},
++ {"ORBBindAddr", string_arg, NULL}, /* XXX need to make
++ libIIOP support this */
++ {"ORBIIOPAddr", string_arg, NULL},
++
++ /* These options aren't */
++ {"ORBDebugModules", int_arg, NULL},
++ {"ORBRootPOAIOR", string_arg, NULL},
++ {"ORBRootPOAAddr", string_arg, NULL},
++ {"ORBIIOPUSock", int_arg, NULL},
++ {"ORBIIOPIPv4", int_arg, NULL},
++ {"ORBIIOPIPv6", int_arg, NULL},
++ {NULL,0,NULL},
++ };
++
++ if (ev == NULL || !argc || !argv || !orb_identifier) {
++ if (ev) {
++ CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ }
++ up(&StartupSem); // Okay, let the insmod thread continue...
++ return 0;
++ }
++
++ pre_rc_options[0].arg = (void *) &nosysrc;
++ pre_rc_options[1].arg = (void *) &nouserrc;
++ options[0].arg = (void *) &no_iiop_server;
++ options[1].arg = (void *) &no_iiop_proxy;
++ options[2].arg = (void *) &orb_id_opt;
++ options[3].arg = (void *) &imr_ior;
++ options[4].arg = (void *) &imr_addr;
++ options[5].arg = (void *) &ir_ior;
++ options[6].arg = (void *) &ir_addr;
++ options[7].arg = (void *) &naming_ior;
++ options[8].arg = (void *) &naming_addr;
++ options[9].arg = (void *) &debug_level;
++ options[12].arg = (void *) &debug_modules;
++ options[13].arg = (void *) &root_poa_ior;
++ options[14].arg = (void *) &root_poa_addr;
++ options[15].arg = (void *) &use_usock;
++ options[16].arg = (void *) &use_ipv4;
++ options[17].arg = (void *) &use_ipv6;
++
++#ifndef __KORBIT__
++ ORBit_option_parse(argc, argv, pre_rc_options);
++
++ if(!nosysrc) {
++ ORBit_rc_load(ORBit_SYSRC, options);
++ }
++
++ if(!nouserrc) {
++ char *buf;
++
++ ctmp = g_get_home_dir();
++
++ buf = alloca(strlen(ctmp) + sizeof("/.orbitrc"));
++ sprintf(buf, "%s/.orbitrc", ctmp);
++ ORBit_rc_load(buf, options);
++ freeca(buf);
++ }
++
++ ORBit_option_parse(argc, argv, options);
++#endif /* !__KORBIT__ */
++
++ ORBit_Trace_setLevel(debug_level);
++ ORBit_Trace_setModules(debug_modules);
++
++ CORBA_exception_init(ev);
++
++ ORBit_chunks_init();
++
++ giop_init(argv[0]);
++
++ orb=g_new0(struct CORBA_ORB_type, 1);
++
++ if(orb==NULL) {
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ goto error;
++ }
++
++ ORBit_pseudo_object_init(ORBIT_PSEUDO_OBJECT(orb), ORBIT_PSEUDO_ORB, ev);
++
++ ORBit_RootObject_set_interface(ORBIT_ROOT_OBJECT(orb),
++ (gpointer)&CORBA_ORB_epv, ev);
++
++ ORBIT_ROOT_OBJECT(orb)->refs = 1;
++
++ if(orb_id_opt!=NULL) {
++ if(!ORBit_ORBid_setup(orb, orb_id_opt))
++ goto error;
++ g_free(orb_id_opt);
++ } else if(orb_identifier!=NULL) {
++ if(!ORBit_ORBid_setup(orb, orb_identifier))
++ goto error;
++ } else {
++ orb->orb_identifier=g_strdup("orbit-local-orb");
++ }
++
++ if(orb->orb_identifier==NULL) {
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ goto error;
++ }
++
++ if(use_ipv4) {
++ orb->cnx.ipv4 = GIOP_CONNECTION(iiop_connection_server());
++
++ giop_connection_ref(orb->cnx.ipv4);
++ GIOP_CONNECTION(orb->cnx.ipv4)->orb_data = orb;
++ }
++
++ if(use_ipv6) {
++ orb->cnx.ipv6 = GIOP_CONNECTION(iiop_connection_server_ipv6());
++ giop_connection_ref(orb->cnx.ipv6);
++ GIOP_CONNECTION(orb->cnx.ipv6)->orb_data = orb;
++ }
++
++#ifndef __KORBIT__
++ if(use_usock) {
++ orb->cnx.usock = ORBit_ORB_make_usock_connection();
++
++ giop_connection_ref(orb->cnx.usock);
++ GIOP_CONNECTION(orb->cnx.usock)->orb_data = orb;
++ }
++#endif
++
++ orb->objrefs = g_hash_table_new((GHashFunc)g_CORBA_Object_hash,
++ (GCompareFunc)g_CORBA_Object_equal);
++ orb->poas = g_ptr_array_new();
++
++ /* when I figure out what MICO is doing with the iiop_proxy and
++ * iiop_server stuff, it'll get handled here.
++ */
++
++ /*
++ * Connect to / create implementation repository
++ */
++
++ {
++ CORBA_Object imr=NULL;
++
++ if(imr_ior!=NULL) {
++ imr=CORBA_ORB_string_to_object(orb, imr_ior, ev);
++ g_free(imr_ior);
++ } else if(imr_addr!=NULL) {
++ /*imr=CORBA_ORB_bind(orb, "IDL:omg.org/CORBA/ImplRepository:1.0", imr_addr, ev);*/
++ g_free(imr_addr);
++ }
++
++ if(!CORBA_Object_is_nil(imr, ev)) {
++ CORBA_ORB_set_initial_reference(orb, "ImplementationRepository", imr, ev);
++ }
++ }
++
++ /*
++ * Connect to / create interface repository
++ */
++
++ {
++ CORBA_Object ir=NULL;
++
++ if(ir_ior!=NULL) {
++ ir=CORBA_ORB_string_to_object(orb, ir_ior, ev);
++ g_free(ir_ior);
++ } else if(ir_addr!=NULL) {
++ /*ir=CORBA_ORB_bind(orb, "IDL:omg.org/CORBA/Repository:1.0", ir_addr, ev);*/
++ g_free(ir_addr);
++ }
++
++ if(!CORBA_Object_is_nil(ir, ev)) {
++ CORBA_ORB_set_initial_reference(orb, "InterfaceRepository", ir, ev);
++ }
++ }
++
++ /*
++ * Connect to naming service
++ */
++
++ {
++ CORBA_Object naming=NULL;
++
++ if(naming_ior!=NULL) {
++ naming=CORBA_ORB_string_to_object(orb, naming_ior, ev);
++ g_free(naming_ior);
++ } else if(naming_addr!=NULL) {
++ /*CORBA_ORB_ObjectTag tag=CORBA_ORB_string_to_tag(orb, "root", ev);*/
++
++ /*naming=CORBA_ORB_bind_tag(orb, "IDL:omg.org/CosNaming/NamingContext:1.0", tag, naming_addr, ev);*/
++ g_free(naming_addr);
++ }
++
++ if(!CORBA_Object_is_nil(naming, ev)) {
++ CORBA_ORB_set_initial_reference(orb, "NameService", naming, ev);
++ }
++ }
++
++ /*
++ * Connect to / create RootPOA
++ */
++
++ {
++ PortableServer_POA root_poa=CORBA_OBJECT_NIL;
++
++ if(root_poa_ior!=NULL) {
++ root_poa=(PortableServer_POA)
++ CORBA_ORB_string_to_object(orb,
++ root_poa_ior, ev);
++ g_free(root_poa_ior);
++ }
++
++ /* And attatch it to the orb */
++
++ if(!CORBA_Object_is_nil((CORBA_Object)root_poa, ev)) {
++ CORBA_ORB_set_initial_reference((CORBA_ORB)orb,
++ "RootPOA",
++ (CORBA_Object)root_poa,
++ ev);
++ }
++ }
++
++ ORBit_custom_run_setup(orb, ev);
++
++ if (!strcmp("server", argv[0])) // Only do this for servers.
++ TheOneTrueOrb = orb;
++ up(&StartupSem); // Okay, let the insmod thread continue...
++ return orb;
++
++error:
++ if(orb!=NULL) {
++ ORBit_ORB_release(orb, ev);
++ orb = NULL;
++ }
++ g_free(imr_ior);
++ g_free(imr_addr);
++ g_free(ir_ior);
++ g_free(ir_addr);
++ g_free(naming_ior);
++ g_free(naming_addr);
++ g_free(root_poa_ior);
++ g_free(root_poa_addr);
++ g_free(orb_id_opt);
++
++ TheOneTrueOrb = 0;
++ up(&StartupSem); // Okay, let the insmod thread continue...
++ return 0;
++}
++
++
++#if __KERNEL__
++#include <linux/smp_lock.h>
++#include <linux/proc_fs.h>
++
++// This is the main corba thread function...
++//
++void __CORBA_ORB_run(CORBA_ORB orb, CORBA_Environment *ev);
++int MainCORBAThread(void *Args) {
++ // Make a directory in /proc... yaay...
++ proc_mkdir("corba", 0);
++
++ __CORBA_ORB_init((struct CORBA_ORB_init_args*)Args);
++ if (TheOneTrueOrb == 0) return 0;
++
++ strcpy(current->comm, "korbit"); // Set the thread name...
++
++ lock_kernel(); /* This seems to be required for exit_mm */
++ exit_mm(current);
++
++ __CORBA_ORB_run(TheOneTrueOrb,
++ ((struct CORBA_ORB_init_args*)Args)->ev);
++ return 0;
++}
++#endif
++
++
++/* Section 4.4
++ *
++ * Adjusts argc and argv appropriately
++ */
++
++CORBA_ORB CORBA_ORB_init(int *argc, char **argv, CORBA_ORBid orb_identifier,
++ CORBA_Environment *ev) {
++
++ struct CORBA_ORB_init_args Args;
++ Args.argc = argc;
++ Args.argv = argv;
++ Args.orb_identifier = orb_identifier;
++ Args.ev = ev;
++
++#ifdef __KERNEL__
++ if (!strcmp(argv[0], "server")) { // Are we a server?
++ down(&StartupSem); // Grab the semaphore...
++ if (TheOneTrueOrb) {
++ CORBA_exception_init(ev);
++ goto out_success;
++ }
++
++ // This releases the semaphore when it is done initializing.
++ (void)kernel_thread(MainCORBAThread, &Args,
++ CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
++
++ // This will block until the semaphore is released by the
++ // ORB thread.
++ down(&StartupSem);
++ } else { // If we are a corba client, like CorbaFS...
++ return __CORBA_ORB_init(&Args);
++ }
++
++ out_success:
++ up(&StartupSem); // Okay, we're now here.
++#else
++ __CORBA_ORB_init(&Args);
++#endif
++ if (TheOneTrueOrb)
++ return (CORBA_ORB)CORBA_Object_duplicate((CORBA_Object)TheOneTrueOrb, ev);
++ return 0;
++}
++
++
++
++
++typedef struct {
++ CORBA_Object obj;
++ CDR_Codec *codec;
++ gboolean emit_active;
++} profile_user_data;
++
++static void ORBit_emit_profile(gpointer item, gpointer userdata)
++{
++ ORBit_Object_info *profile=(ORBit_Object_info *)item;
++ profile_user_data *data=(profile_user_data *)userdata;
++ CORBA_Object obj=data->obj;
++ CDR_Codec encaps_codec_d;
++ CDR_Codec *codec=data->codec, *encaps = &encaps_codec_d;
++ gboolean emit_active=data->emit_active;
++ static const CORBA_octet iiopversion[] = {1,0};
++ CORBA_octet codecbuf[2048];
++
++ g_assert(obj!=NULL);
++ g_assert(codec!=NULL);
++ g_assert(profile!=NULL);
++
++ if((profile == obj->active_profile) && (emit_active == FALSE))
++ return; /* we already did this one */
++
++ switch(profile->profile_type) {
++ case IOP_TAG_INTERNET_IOP:
++ CDR_codec_init_static(encaps);
++ encaps->buffer = codecbuf;
++ encaps->release_buffer = CORBA_FALSE;
++ encaps->buf_len = 2048;
++ encaps->readonly = CORBA_FALSE;
++ encaps->host_endian = encaps->data_endian = FLAG_ENDIANNESS;
++
++ CDR_put_ulong(codec, IOP_TAG_INTERNET_IOP);
++ CDR_put_octet(encaps, FLAG_ENDIANNESS);
++ CDR_put_octets(encaps, (gpointer)iiopversion, sizeof(iiopversion));
++ CDR_put_string(encaps, profile->tag.iopinfo.host);
++ CDR_put_ushort(encaps, profile->tag.iopinfo.port);
++ CDR_put_ulong(encaps, profile->object_key._length);
++ CDR_put_octets(encaps, profile->object_key._buffer,
++ profile->object_key._length);
++ CDR_put_ulong(codec, encaps->wptr);
++ CDR_put_octets(codec, encaps->buffer, encaps->wptr);
++ break;
++
++ case IOP_TAG_ORBIT_SPECIFIC:
++ CDR_codec_init_static(encaps);
++ encaps->buffer = codecbuf;
++ encaps->release_buffer = CORBA_FALSE;
++ encaps->buf_len = 2048;
++ encaps->readonly = CORBA_FALSE;
++ encaps->host_endian = encaps->data_endian = FLAG_ENDIANNESS;
++
++ CDR_put_ulong(codec, IOP_TAG_ORBIT_SPECIFIC);
++ CDR_put_octet(encaps, FLAG_ENDIANNESS);
++ CDR_put_octets(encaps, (gpointer)iiopversion, sizeof(iiopversion));
++ CDR_put_string(encaps, profile->tag.orbitinfo.unix_sock_path);
++ CDR_put_ushort(encaps, profile->tag.orbitinfo.ipv6_port);
++ CDR_put_ulong(encaps, profile->object_key._length);
++ CDR_put_octets(encaps, profile->object_key._buffer,
++ profile->object_key._length);
++ CDR_put_ulong(codec, encaps->wptr);
++ CDR_put_octets(codec, encaps->buffer, encaps->wptr);
++ break;
++
++ default:
++ g_warning("Skipping tag %d", profile->profile_type);
++ break;
++ }
++}
++
++CORBA_char *CORBA_ORB_object_to_string(CORBA_ORB orb,
++ CORBA_Object obj,
++ CORBA_Environment *ev)
++{
++ int i;
++ CDR_Codec codec_d;
++ CDR_Codec *codec = &codec_d;
++ CORBA_char *rc = NULL;
++ CORBA_unsigned_long ntags;
++ profile_user_data data;
++ CORBA_octet codecbuf[2048];
++ char *ctmp;
++
++ g_return_val_if_fail(ev, NULL);
++ o_return_val_if_fail(orb && obj, NULL);
++
++ if(!obj || !orb) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return NULL;
++ }
++
++ if(ORBIT_ROOT_OBJECT(obj)->is_pseudo_object) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_MARSHAL,
++ CORBA_COMPLETED_NO);
++ return NULL;
++ }
++
++ CDR_codec_init_static(codec);
++
++ codec->buffer = codecbuf;
++ codec->release_buffer = CORBA_FALSE;
++ codec->buf_len = 2048;
++ codec->readonly = CORBA_FALSE;
++ codec->host_endian = codec->data_endian = FLAG_ENDIANNESS;
++
++ CDR_put_octet(codec, FLAG_ENDIANNESS);
++
++ CDR_put_string(codec, obj->object_id);
++ ntags = g_slist_length(obj->profile_list);
++ CDR_put_ulong(codec, ntags);
++
++ data.obj=obj;
++ data.codec=codec;
++ data.emit_active=TRUE;
++ if(obj->active_profile != NULL)
++ ORBit_emit_profile(obj->active_profile, &data); /* do this one first */
++
++ data.emit_active=FALSE;
++ g_slist_foreach(obj->profile_list, ORBit_emit_profile, &data);
++
++ rc = CORBA_string_alloc(4 + (codec->wptr * 2) + 1);
++ strcpy(rc, "IOR:");
++
++#define hexdigit(n) (((n)>9)?(n+'a'-10):(n+'0'))
++
++ for(i = 0, ctmp = rc + strlen("IOR:"); i < codec->wptr; i++) {
++ *(ctmp++) = hexdigit((((codec->buffer[i]) & 0xF0) >> 4));
++ *(ctmp++) = hexdigit(((codec->buffer[i]) & 0xF));
++ }
++ *ctmp = '\0';
++
++ {
++ /* Debug check */
++ CORBA_Object obj;
++ CORBA_Environment myev;
++
++ CORBA_exception_init(&myev);
++
++ obj = CORBA_ORB_string_to_object(orb, rc, &myev);
++
++ if (CORBA_Object_is_nil(obj, &myev)) {
++ g_warning("Bug in %s, created bad IOR `%s'\n",
++ __FUNCTION__, rc);
++ CORBA_free(rc);
++ return NULL;
++ }
++
++ CORBA_Object_release(obj, &myev);
++ }
++
++ return rc;
++}
++
++/* Quote from the GNU libc manual:
++
++ "If you try to allocate more storage than the machine can provide,
++ you don't get a clean error message. Instead you get a fatal
++ signal like the one you would get from an infinite recursion;
++ probably a segmentation violation (see section Program Error
++ Signals)."
++
++ The man page claims alloca() returns NULL on failure; this appears
++ to be a load of shit on Linux where you just get flaming death, but
++ we check anyway in case other systems work that way.
++
++ On Linux we check that the size is less than MAX_STACK_ALLOC
++
++ Note that the CORBA_alloc() calls in here can still cause
++ program abort, and really that should be fixed in a similar
++ way since our lengths are coming in from unpredictable sources
++ like files or the network.
++*/
++
++#define MAX_STACK_ALLOC 8192
++
++CORBA_Object CORBA_ORB_string_to_object(CORBA_ORB orb, CORBA_char *str,
++ CORBA_Environment *ev)
++{
++ GSList *profiles=NULL;
++ CORBA_Object retval = NULL;
++ CORBA_char *type_id;
++ ORBit_Object_info *object_info;
++ CDR_Codec codec_d, encaps_codec_d;
++ CDR_Codec *codec = &codec_d, *encaps_codec = &encaps_codec_d;
++ CORBA_octet *buffer, endian;
++ int i, j;
++ CORBA_unsigned_long len, seq_len, misclen;
++
++ g_return_val_if_fail(ev, CORBA_OBJECT_NIL);
++ o_return_val_if_fail(orb && str, CORBA_OBJECT_NIL);
++
++ if(strncmp(str, "IOR:", 4)) {
++ CORBA_exception_set_system(ev, ex_CORBA_MARSHAL,
++ CORBA_COMPLETED_NO);
++ return(CORBA_OBJECT_NIL);
++ }
++
++ CDR_codec_init_static(codec);
++ len = strlen(str);
++
++ if((len % 2) || len <= 4) {
++ CORBA_exception_set_system(ev, ex_CORBA_MARSHAL,
++ CORBA_COMPLETED_NO);
++ return(CORBA_OBJECT_NIL);
++ }
++
++ codec->buf_len = (len-4)/2;
++ buffer = alloca(codec->buf_len);
++
++ codec->buffer=buffer;
++ codec->release_buffer = CORBA_FALSE;
++ codec->readonly = TRUE;
++
++ for(j = 0, i = 4; i < len; i+=2) {
++ buffer[j++] = HEXOCTET(str[i], str[i+1]);
++ };
++
++ CDR_get_octet(codec, &endian);
++
++ codec->data_endian = endian;
++ codec->host_endian = FLAG_ENDIANNESS;
++
++ CDR_get_string_static(codec, &type_id);
++
++ CDR_get_seq_begin(codec, &seq_len);
++
++ for(i = 0; i < seq_len; i++) {
++ IOP_ProfileId tag;
++
++ object_info=g_new0(ORBit_Object_info, 1);
++
++ if (!CDR_get_ulong(codec, &tag))
++ goto error_out;
++
++ switch(tag) {
++ case IOP_TAG_INTERNET_IOP:
++ if (!CDR_get_ulong(codec, &misclen))
++ goto error_out;
++
++ CDR_codec_init_static(encaps_codec);
++
++ if (misclen > MAX_STACK_ALLOC)
++ goto error_out;
++
++ encaps_codec->buffer = alloca(misclen);
++ if (encaps_codec->buffer == NULL)
++ /* misclen was probably junk */
++ goto error_out;
++
++ encaps_codec->release_buffer = FALSE;
++ if(!CDR_buffer_gets(codec, encaps_codec->buffer, misclen))
++ goto error_out;
++
++ encaps_codec->buf_len = misclen;
++ encaps_codec->readonly = CORBA_TRUE;
++ if(!CDR_get_octet(encaps_codec, &endian))
++ goto error_out;
++ encaps_codec->data_endian = endian;
++ encaps_codec->host_endian = FLAG_ENDIANNESS;
++
++ if (encaps_codec->data_endian > 1)
++ goto error_out;
++
++ object_info->profile_type = IOP_TAG_INTERNET_IOP;
++ if(!CDR_get_octet(encaps_codec, &object_info->iiop_major))
++ goto error_out;
++ if(object_info->iiop_major != 1)
++ goto error_out;
++ if(!CDR_get_octet(encaps_codec, &object_info->iiop_minor))
++ goto error_out;
++ if(!CDR_get_string(encaps_codec, &object_info->tag.iopinfo.host))
++ goto error_out;
++ if(!CDR_get_ushort(encaps_codec, &object_info->tag.iopinfo.port))
++ goto error_out;
++ if(!CDR_get_seq_begin(encaps_codec, &object_info->object_key._length))
++ goto error_out;
++
++ object_info->object_key._maximum = 0;
++
++ /* The POA gives out ORBit_alloc()d profiles, so we have to too */
++ object_info->object_key._buffer = ORBit_alloc(object_info->object_key._length, NULL, NULL);
++ if(!CDR_buffer_gets(encaps_codec, object_info->object_key._buffer,
++ object_info->object_key._length))
++ goto error_out;
++
++ ORBit_set_object_key(object_info);
++ profiles=g_slist_append(profiles, object_info);
++ break;
++
++ case IOP_TAG_MULTIPLE_COMPONENTS:
++ /* Just skip any multiple_components data, for now */
++ if(!CDR_get_ulong(codec, &misclen))
++ goto error_out;
++
++ CDR_codec_init_static(encaps_codec);
++
++ if (misclen > MAX_STACK_ALLOC)
++ goto error_out;
++
++ encaps_codec->buf_len = misclen;
++ encaps_codec->buffer = alloca(misclen);
++ if (encaps_codec->buffer == NULL)
++ /* misclen was probably junk */
++ goto error_out;
++
++ encaps_codec->release_buffer = FALSE;
++ encaps_codec->readonly = CORBA_TRUE;
++ if(!CDR_buffer_gets(codec, encaps_codec->buffer, misclen))
++ goto error_out;
++ break;
++
++ case IOP_TAG_ORBIT_SPECIFIC:
++ if(!CDR_get_ulong(codec, &misclen))
++ goto error_out;
++
++ CDR_codec_init_static(encaps_codec);
++
++ if (misclen > MAX_STACK_ALLOC)
++ goto error_out;
++
++ encaps_codec->buffer = alloca(misclen);
++ if (encaps_codec->buffer == NULL)
++ /* misclen was probably junk */
++ goto error_out;
++
++ encaps_codec->release_buffer = FALSE;
++ if(!CDR_buffer_gets(codec, encaps_codec->buffer, misclen))
++ goto error_out;
++
++ encaps_codec->buf_len = misclen;
++ encaps_codec->readonly = CORBA_TRUE;
++
++ if(!CDR_get_octet(encaps_codec, &endian))
++ goto error_out;
++
++ encaps_codec->data_endian = endian;
++ encaps_codec->host_endian = FLAG_ENDIANNESS;
++
++ if (encaps_codec->data_endian > 1)
++ goto error_out;
++
++ object_info->profile_type=IOP_TAG_ORBIT_SPECIFIC;
++ if(!CDR_get_octet(encaps_codec, &object_info->iiop_major))
++ goto error_out;
++
++ if(object_info->iiop_major != 1)
++ goto error_out;
++ if(!CDR_get_octet(encaps_codec, &object_info->iiop_minor))
++ goto error_out;
++
++ if(!CDR_get_string(encaps_codec, &object_info->tag.orbitinfo.unix_sock_path))
++ goto error_out;
++
++ if(!CDR_get_ushort(encaps_codec, &object_info->tag.orbitinfo.ipv6_port))
++ goto error_out;
++ if(!CDR_get_seq_begin(encaps_codec, &object_info->object_key._length))
++ goto error_out;
++ object_info->object_key._maximum = 0;
++
++ /* The POA gives out ORBit_alloc()d profiles, so we have to too */
++ object_info->object_key._buffer = ORBit_alloc(object_info->object_key._length, NULL, NULL);
++ if(!CDR_buffer_gets(encaps_codec, object_info->object_key._buffer,
++ object_info->object_key._length))
++ goto error_out;
++
++ ORBit_set_object_key(object_info);
++ profiles=g_slist_append(profiles, object_info);
++ break;
++ default:
++ g_warning("Unknown tag 0x%x", tag);
++
++ /* Skip it */
++ if(!CDR_get_ulong(codec, &misclen))
++ goto error_out;
++
++ CDR_codec_init_static(encaps_codec);
++
++ if (misclen > MAX_STACK_ALLOC)
++ goto error_out;
++
++ encaps_codec->buf_len = misclen;
++ encaps_codec->buffer = alloca(misclen);
++ if (encaps_codec->buffer == NULL)
++ /* misclen was probably junk */
++ goto error_out;
++
++ encaps_codec->release_buffer = FALSE;
++ encaps_codec->readonly = CORBA_TRUE;
++ if(!CDR_buffer_gets(codec, encaps_codec->buffer, misclen))
++ goto error_out;
++
++ break;
++ }
++ }
++
++ freeca(buffer); /* Same as codec->buffer */
++ freeca(encaps_codec->buffer);
++
++ return ORBit_create_object_with_info(profiles, type_id, orb, ev);
++
++ error_out:
++
++ if(object_info) {
++ CORBA_free(object_info->object_key._buffer);
++ g_free(object_info);
++ ORBit_delete_profiles(profiles);
++ }
++
++ freeca(buffer); /* Same as codec->buffer */
++ freeca(encaps_codec->buffer);
++
++ return retval;
++}
++
++/* Section 4.1.2 */
++CORBA_boolean CORBA_ORB_get_service_information(CORBA_ORB orb, CORBA_ServiceType service_type, CORBA_ServiceInformation *service_information, CORBA_Environment *ev)
++{
++ g_assert(!"Not yet implemented");
++ return(CORBA_FALSE);
++}
++
++CORBA_Current *CORBA_ORB_get_current(CORBA_ORB orb, CORBA_Environment *ev)
++{
++ g_return_val_if_fail(ev, NULL);
++ o_return_val_if_fail(orb, NULL);
++
++ /* XXX check this over */
++ return (CORBA_Current *)GET_THREAD_DATA();
++}
++
++/* Section 4.5 */
++CORBA_ORB_ObjectIdList *CORBA_ORB_list_initial_services(CORBA_ORB orb, CORBA_Environment *ev)
++{
++ static const char *services[] = {"RootPOA"};
++ CORBA_ORB_ObjectIdList *list;
++
++ g_return_val_if_fail(ev, NULL);
++ o_return_val_if_fail(orb, NULL);
++
++ list = (CORBA_ORB_ObjectIdList *)CORBA_sequence_octet__alloc();
++ list->_maximum=list->_length= 1;
++ list->_buffer = (CORBA_ORB_ObjectId *)services;
++ CORBA_sequence_set_release((void *)list, CORBA_FALSE);
++
++ /* defined reserved references are:
++ * RootPOA
++ * POACurrent
++ * InterfaceRepository
++ * NameService
++ * TradingService
++ * SecurityCurrent
++ * TransactionCurrent
++ */
++
++ return list;
++}
++
++/* Section 4.5
++ *
++ * raises InvalidName
++ */
++CORBA_Object CORBA_ORB_resolve_initial_references(CORBA_ORB orb, CORBA_ORB_ObjectId identifier, CORBA_Environment *ev)
++{
++ g_return_val_if_fail(ev, CORBA_OBJECT_NIL);
++ o_return_val_if_fail(orb, CORBA_OBJECT_NIL);
++
++ if(!strcmp(identifier, "ImplementationRepository"))
++ return CORBA_Object_duplicate(orb->imr, ev);
++ else if(!strcmp(identifier, "InterfaceRepository"))
++ return CORBA_Object_duplicate(orb->ir, ev);
++ else if(!strcmp(identifier, "NameService"))
++ return CORBA_Object_duplicate(orb->naming, ev);
++ else if(!strcmp(identifier, "RootPOA")) {
++ if(CORBA_Object_is_nil(orb->root_poa, ev)) {
++ CORBA_PolicyList policies = {0,0,NULL,CORBA_FALSE};
++ PortableServer_POAManager poa_mgr;
++ /* Create a poa manager */
++ poa_mgr = ORBit_POAManager_new(ev);
++ poa_mgr->orb = orb;
++
++ /* Create the root poa */
++ orb->root_poa = (CORBA_Object)
++ ORBit_POA_new(orb,
++ "RootPOA",
++ poa_mgr,
++ &policies,
++ ev);
++ CORBA_Object_duplicate(orb->root_poa, ev);
++ }
++
++ return CORBA_Object_duplicate(orb->root_poa, ev);
++ }
++
++ /* throw user exception: InvalidName */
++ CORBA_exception_set(ev,CORBA_USER_EXCEPTION,
++ ex_CORBA_ORB_InvalidName,
++ NULL);
++
++ goto error;
++error:
++ return(NULL);
++}
++
++/* This is a MICO extension
++ *
++ * raises InvalidName
++ */
++void CORBA_ORB_set_initial_reference(CORBA_ORB orb, CORBA_ORB_ObjectId identifier, CORBA_Object obj, CORBA_Environment *ev)
++{
++ g_return_if_fail(ev);
++ o_return_if_fail(orb && identifier && obj);
++
++ if(!strcmp(identifier, "ImplementationRepository")) {
++ if(!CORBA_Object_is_nil(orb->imr, ev)) {
++ CORBA_Object_release(orb->imr, ev);
++ }
++ orb->imr=CORBA_Object_duplicate(obj, ev);
++ } else if(!strcmp(identifier, "InterfaceRepository")) {
++ if(!CORBA_Object_is_nil(orb->ir, ev)) {
++ CORBA_Object_release(orb->ir, ev);
++ }
++ orb->ir=CORBA_Object_duplicate(obj, ev);
++ } else if(!strcmp(identifier, "NameService")) {
++ if(!CORBA_Object_is_nil(orb->naming, ev)) {
++ CORBA_Object_release(orb->naming, ev);
++ }
++ orb->naming=CORBA_Object_duplicate(obj, ev);
++ } else if(!strcmp(identifier, "RootPOA")) {
++ if(!CORBA_Object_is_nil(orb->root_poa, ev)) {
++ CORBA_Object_release(orb->root_poa, ev);
++ }
++ orb->root_poa=CORBA_Object_duplicate(obj, ev);
++ } else {
++ /* throw user exception: InvalidName */
++ CORBA_exception_set(ev,CORBA_USER_EXCEPTION,ex_CORBA_ORB_InvalidName,NULL);
++ goto error;
++ }
++
++ return;
++error:
++ return;
++}
++
++/* Section 4.9.1 */
++CORBA_boolean CORBA_ORB_work_pending(CORBA_ORB orb, CORBA_Environment *ev)
++{
++ g_assert(!"Not yet implemented");
++ return(CORBA_FALSE);
++}
++
++/* Section 4.9.2 */
++void CORBA_ORB_perform_work(CORBA_ORB orb, CORBA_Environment *ev)
++{
++ g_assert(!"Not yet implemented");
++ return;
++}
++
++/* Section 4.9.4 */
++void
++CORBA_ORB_shutdown(CORBA_ORB orb,
++ CORBA_boolean wait_for_completion,
++ CORBA_Environment *ev)
++{
++ g_return_if_fail(ev);
++ o_return_if_fail(orb);
++
++ /* XXX implement on a per-ORB basis, and also
++ handle whatever wait_for_completion means */
++
++ if(orb->cnx.ipv4)
++ giop_connection_unref(orb->cnx.ipv4);
++ if(orb->cnx.ipv6)
++ giop_connection_unref(orb->cnx.ipv6);
++#ifndef __KORBIT__
++ if(orb->cnx.usock)
++ giop_connection_unref(orb->cnx.usock);
++#endif
++
++ giop_main_quit();
++}
++
++/* Section 4.9.3 */
++/* CORBA_ORB_run is in server.c */
++
++/* Section 4.7 */
++CORBA_PolicyType
++CORBA_Policy__get_policy_type(CORBA_Policy obj, CORBA_Environment *ev)
++{
++ g_return_val_if_fail(ev, 0);
++ o_return_val_if_fail(obj, 0);
++
++ return obj->policy_type;
++}
++
++/* Section 4.7 */
++CORBA_Policy CORBA_Policy_copy(CORBA_Policy obj, CORBA_Environment *ev)
++{
++ g_return_val_if_fail(ev, CORBA_OBJECT_NIL);
++ o_return_val_if_fail(obj, CORBA_OBJECT_NIL);
++
++ ORBIT_ROOT_OBJECT_REF(obj);
++
++ return obj;
++}
++
++/* Section 4.7
++ *
++ * raises CORBA_NO_PERMISSION
++ */
++void CORBA_Policy_destroy(CORBA_Policy obj, CORBA_Environment *ev)
++{
++ g_return_if_fail(ev);
++ o_return_if_fail(obj);
++
++ ORBIT_ROOT_OBJECT_UNREF(obj);
++ if(ORBIT_ROOT_OBJECT(obj)->refs <= 0)
++ ORBIT_ROOT_OBJECT_release(obj, ev);
++}
++
++#ifndef __KORBIT__
++/* Section 4.8.2 */
++CORBA_Policy CORBA_DomainManager_get_domain_policy(CORBA_DomainManager obj, CORBA_PolicyType policy_type, CORBA_Environment *ev)
++{
++ g_return_val_if_fail(ev, CORBA_OBJECT_NIL);
++ o_return_val_if_fail(obj, CORBA_OBJECT_NIL);
++
++ g_assert(!"Not yet implemented");
++ return(NULL);
++}
++
++/* Section 4.8.2 */
++void CORBA_ConstructionPolicy_make_domain_manager(CORBA_ConstructionPolicy obj, CORBA_InterfaceDef object_type, CORBA_boolean constr_policy, CORBA_Environment *
++ev)
++{
++ g_return_if_fail(ev);
++ o_return_if_fail(obj && object_type);
++
++ g_assert(!"Not yet implemented");
++ return;
++}
++
++/* Section 4.2.8 */
++CORBA_DomainManagerList *CORBA_Object_get_domain_managers(CORBA_Object obj, CORBA_Environment *ev)
++{
++ g_return_val_if_fail(ev, NULL);
++ o_return_val_if_fail(obj, NULL);
++
++ g_assert(!"Not yet implemented");
++ return(NULL);
++}
++
++CORBA_TypeCode CORBA_ORB_create_struct_tc(CORBA_ORB obj, CORBA_RepositoryId id, CORBA_Identifier name, CORBA_StructMemberSeq members, CORBA_Environment *ev)
++{
++ CORBA_TypeCode tc;
++ int i;
++
++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ if(tc == NULL)
++ goto tc_alloc_failed;
++
++ tc->subtypes=g_new0(CORBA_TypeCode, members._length);
++ if(tc->subtypes == NULL)
++ goto subtypes_alloc_failed;
++
++ tc->subnames=g_new0(char *, members._length);
++ if(tc->subnames == NULL)
++ goto subnames_alloc_failed;
++
++ tc->kind=CORBA_tk_struct;
++ tc->name=g_strdup(name);
++ tc->repo_id=g_strdup(id);
++ tc->sub_parts=members._length;
++ tc->length=members._length;
++
++ for(i=0;i<members._length;i++) {
++ CORBA_StructMember *mem=(CORBA_StructMember *)&(members._buffer[i]);
++
++ g_assert(&(mem->type)!=NULL);
++
++ tc->subtypes[i] = ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ memcpy(tc->subtypes[i], mem->type, (size_t)sizeof(struct CORBA_TypeCode_struct));
++ tc->subnames[i]=g_strdup(mem->name);
++ }
++
++ return(tc);
++
++ subnames_alloc_failed:
++ g_free(tc->subtypes);
++ subtypes_alloc_failed:
++ ORBIT_CHUNK_FREE(CORBA_TypeCode, tc);
++ tc_alloc_failed:
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ return NULL;
++}
++
++CORBA_TypeCode
++CORBA_ORB_create_union_tc(CORBA_ORB obj, CORBA_RepositoryId id,
++ CORBA_Identifier name,
++ CORBA_TypeCode discriminator_type,
++ CORBA_UnionMemberSeq members,
++ CORBA_Environment *ev)
++{
++ CORBA_TypeCode tc;
++ int i;
++
++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++
++ if(tc == NULL)
++ goto tc_alloc_failed;
++
++ tc->discriminator = ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++
++ if(tc->discriminator == NULL)
++ goto discriminator_alloc_failed;
++
++ memcpy(tc->discriminator, discriminator_type, (size_t)sizeof(CORBA_TypeCode));
++
++ tc->subtypes=g_new0(CORBA_TypeCode, members._length);
++ if(tc->subtypes==NULL)
++ goto subtypes_alloc_failed;
++
++ tc->subnames=g_new0(char *, members._length);
++ if(tc->subnames==NULL)
++ goto subnames_alloc_failed;
++
++ tc->sublabels=g_new0(CORBA_any, members._length);
++ if(tc->sublabels == NULL)
++ goto sublabels_alloc_failed;
++
++ tc->kind=CORBA_tk_union;
++ tc->name=g_strdup(name);
++ tc->repo_id=g_strdup(id);
++ tc->sub_parts=members._length;
++ tc->length=members._length;
++ tc->default_index=-1;
++
++ for(i=0;i<members._length;i++) {
++ CORBA_UnionMember *mem=(CORBA_UnionMember *)&(members._buffer[i]);
++
++ g_assert(&(mem->label)!=NULL);
++ memcpy(&(tc->sublabels[i]), &(mem->label), (size_t)sizeof(CORBA_any));
++ g_assert(&(mem->type)!=NULL);
++ tc->subtypes[i] = ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ memcpy(tc->subtypes[i], mem->type, (size_t)sizeof(struct CORBA_TypeCode_struct));
++ tc->subnames[i]=g_strdup(mem->name);
++
++ if(mem->label._type->kind==CORBA_tk_octet) {
++ tc->default_index=i;
++ }
++ }
++
++ return(tc);
++
++sublabels_alloc_failed:
++ g_free(tc->sublabels);
++subnames_alloc_failed:
++ g_free(tc->subtypes);
++subtypes_alloc_failed:
++ ORBIT_CHUNK_FREE(CORBA_TypeCode, tc->discriminator);
++discriminator_alloc_failed:
++ ORBIT_CHUNK_FREE(CORBA_TypeCode, tc);
++ tc_alloc_failed:
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ return NULL;
++}
++
++CORBA_TypeCode CORBA_ORB_create_enum_tc(CORBA_ORB obj, CORBA_RepositoryId id, CORBA_Identifier name, CORBA_EnumMemberSeq members, CORBA_Environment *ev)
++{
++ CORBA_TypeCode tc;
++ int i;
++
++ tc = ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ if(tc == NULL)
++ goto tc_alloc_failed;
++
++ tc->subnames=g_new0(char *, members._length);
++ if(tc->subnames==NULL)
++ goto subnames_alloc_failed;
++
++ tc->kind = CORBA_tk_enum;
++ tc->name = g_strdup(name);
++ tc->repo_id = g_strdup(id);
++ tc->sub_parts = members._length;
++ tc->length = members._length;
++
++ for(i=0;i<members._length;i++) {
++ tc->subnames[i]=g_strdup(members._buffer[i]);
++ }
++
++ return(tc);
++
++ subnames_alloc_failed:
++ ORBIT_CHUNK_FREE(CORBA_TypeCode, tc);
++ tc_alloc_failed:
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ return(NULL);
++}
++
++CORBA_TypeCode CORBA_ORB_create_alias_tc(CORBA_ORB obj, CORBA_RepositoryId id, CORBA_Identifier name, CORBA_TypeCode original_type, CORBA_Environment *ev)
++{
++ CORBA_TypeCode tc;
++
++ tc = ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ if(tc==NULL)
++ goto tc_alloc_failed;
++
++ /* Can't use chunks here, because it's sometimes an array. Doh! */
++ tc->subtypes=g_new0(CORBA_TypeCode, 1);
++ if(tc->subtypes==NULL)
++ goto subtypes_alloc_failed;
++
++ tc->kind=CORBA_tk_alias;
++ tc->name=g_strdup(name);
++ tc->repo_id=g_strdup(id);
++ tc->sub_parts=1;
++ tc->length=1;
++
++ tc->subtypes[0] = ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ memcpy(tc->subtypes[0], original_type, (size_t)sizeof(struct CORBA_TypeCode_struct));
++
++ return(tc);
++ subtypes_alloc_failed:
++ ORBIT_CHUNK_FREE(CORBA_TypeCode, tc);
++tc_alloc_failed:
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ return NULL;
++}
++
++CORBA_TypeCode CORBA_ORB_create_exception_tc(CORBA_ORB obj, CORBA_RepositoryId id, CORBA_Identifier name, CORBA_StructMemberSeq members, CORBA_Environment *ev)
++{
++ CORBA_TypeCode tc;
++ int i;
++
++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ if(tc==NULL)
++ goto tc_alloc_failed;
++
++ tc->subtypes=g_new0(CORBA_TypeCode, members._length);
++ if(tc->subtypes==NULL)
++ goto subtypes_alloc_failed;
++
++ tc->subnames=g_new0(char *, members._length);
++ if(tc->subnames==NULL)
++ goto subnames_alloc_failed;
++
++ tc->kind=CORBA_tk_except;
++ tc->name=g_strdup(name);
++ tc->repo_id=g_strdup(id);
++ tc->sub_parts=members._length;
++ tc->length=members._length;
++
++ for(i=0;i<members._length;i++) {
++ CORBA_StructMember *mem=(CORBA_StructMember *)&(members._buffer[i]);
++
++ g_assert(mem->type != NULL);
++ tc->subtypes[i] = ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ memcpy(tc->subtypes[i], mem->type, (size_t)sizeof(struct CORBA_TypeCode_struct));
++ tc->subnames[i]=g_strdup(mem->name);
++ }
++
++ return(tc);
++
++ subnames_alloc_failed:
++ g_free(tc->subtypes);
++ subtypes_alloc_failed:
++ ORBIT_CHUNK_FREE(CORBA_TypeCode, tc);
++ tc_alloc_failed:
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ return(NULL);
++}
++
++CORBA_TypeCode CORBA_ORB_create_interface_tc(CORBA_ORB obj, CORBA_RepositoryId id, CORBA_Identifier name, CORBA_Environment *ev)
++{
++ CORBA_TypeCode tc;
++
++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ if(tc==NULL) {
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY,
++ CORBA_COMPLETED_NO);
++ return(NULL);
++ }
++
++ tc->kind=CORBA_tk_objref;
++ tc->name=g_strdup(name);
++ tc->repo_id=g_strdup(id);
++
++ return(tc);
++}
++
++CORBA_TypeCode CORBA_ORB_create_string_tc(CORBA_ORB obj, CORBA_unsigned_long bound, CORBA_Environment *ev)
++{
++ CORBA_TypeCode tc;
++
++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ if(tc==NULL) {
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ return(NULL);
++ }
++
++ tc->kind=CORBA_tk_string;
++ tc->length=bound;
++
++ return(tc);
++}
++
++CORBA_TypeCode CORBA_ORB_create_wstring_tc(CORBA_ORB obj, CORBA_unsigned_long bound, CORBA_Environment *ev)
++{
++ CORBA_TypeCode tc;
++
++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ if(tc==NULL) {
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ return(NULL);
++ }
++
++ tc->kind=CORBA_tk_wstring;
++ tc->length=bound;
++
++ return(tc);
++}
++
++CORBA_TypeCode CORBA_ORB_create_fixed_tc(CORBA_ORB obj, CORBA_unsigned_short digits, CORBA_short scale, CORBA_Environment *ev)
++{
++ CORBA_TypeCode tc;
++
++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ if(tc==NULL) {
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ return(NULL);
++ }
++
++ tc->kind=CORBA_tk_fixed;
++ tc->digits=digits;
++ tc->scale=scale;
++
++ return(tc);
++}
++
++CORBA_TypeCode CORBA_ORB_create_sequence_tc(CORBA_ORB obj, CORBA_unsigned_long bound, CORBA_TypeCode element_type, CORBA_Environment *ev)
++{
++ CORBA_TypeCode tc;
++
++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ if(tc==NULL)
++ goto tc_alloc_failed;
++
++ /* Can't use chunks here because we can only be sure of getting
++ one consecutive chunk from glib */
++ tc->subtypes=g_new0(CORBA_TypeCode, 1);
++ if(tc->subtypes==NULL)
++ goto subtypes_alloc_failed;
++
++ tc->kind=CORBA_tk_sequence;
++ tc->sub_parts=1;
++ tc->length=bound;
++
++ tc->subtypes[0] = ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ memcpy(tc->subtypes[0], element_type,
++ (size_t)sizeof(struct CORBA_TypeCode_struct));
++
++ return(tc);
++
++ subtypes_alloc_failed:
++ ORBIT_CHUNK_FREE(CORBA_TypeCode, tc);
++ tc_alloc_failed:
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ return(NULL);
++}
++
++CORBA_TypeCode CORBA_ORB_create_recursive_sequence_tc(CORBA_ORB obj, CORBA_unsigned_long bound, CORBA_unsigned_long offset, CORBA_Environment *ev)
++{
++ CORBA_TypeCode tc;
++
++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ if(tc==NULL)
++ goto tc_alloc_failed;
++
++ tc->subtypes=g_new0(CORBA_TypeCode, 1);
++ if(tc->subtypes==NULL)
++ goto subtypes_alloc_failed;
++
++ tc->kind=CORBA_tk_sequence;
++ tc->sub_parts=1;
++ tc->length=bound;
++
++ tc->subtypes[0] = ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ tc->subtypes[0]->kind=CORBA_tk_recursive;
++ tc->subtypes[0]->recurse_depth=offset;
++
++ return(tc);
++
++ subtypes_alloc_failed:
++ ORBIT_CHUNK_FREE(CORBA_TypeCode, tc);
++ tc_alloc_failed:
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ return(NULL);
++}
++
++CORBA_TypeCode CORBA_ORB_create_array_tc(CORBA_ORB obj, CORBA_unsigned_long length, CORBA_TypeCode element_type, CORBA_Environment *ev)
++{
++ CORBA_TypeCode tc;
++
++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ if(tc==NULL)
++ goto tc_alloc_failed;
++
++ tc->subtypes=g_new0(CORBA_TypeCode, 1);
++ if(tc->subtypes==NULL)
++ goto subtypes_alloc_failed;
++
++ tc->kind=CORBA_tk_array;
++ tc->sub_parts=1;
++ tc->length=length;
++
++ tc->subtypes[0] = ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ memcpy(tc->subtypes[0], element_type, (size_t)sizeof(CORBA_TypeCode));
++
++ return(tc);
++
++ subtypes_alloc_failed:
++ ORBIT_CHUNK_FREE(CORBA_TypeCode, tc);
++ tc_alloc_failed:
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ return(NULL);
++}
++#endif /* !__KORBIT__ */
+diff -urN linux-2.4.1/net/korbit/orb/orb.h linux-2.4.1-korbit/net/korbit/orb/orb.h
+--- linux-2.4.1/net/korbit/orb/orb.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orb.h Thu Feb 1 11:47:13 2001
+@@ -0,0 +1,231 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_ORB_H_
++#define _ORBIT_ORB_H_
++
++#include "orb/orbit_types.h"
++#ifndef __KORBIT__
++#include "orb/interface_repository.h"
++#endif /* !__KORBIT__ */
++
++extern CORBA_ORB CORBA_ORB_init(
++ int *argc,
++ char **argv,
++ CORBA_ORBid orb_identifier,
++ CORBA_Environment *ev);
++
++extern CORBA_char *CORBA_ORB_object_to_string(
++ CORBA_ORB orb,
++ CORBA_Object obj,
++ CORBA_Environment *ev);
++
++extern CORBA_Object CORBA_ORB_string_to_object(
++ CORBA_ORB orb,
++ CORBA_char *str,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_ORB_get_default_context(
++ CORBA_ORB orb,
++ CORBA_Context *ctx,
++ CORBA_Environment *ev);
++
++extern CORBA_boolean CORBA_ORB_get_service_information(
++ CORBA_ORB orb,
++ CORBA_ServiceType service_type,
++ CORBA_ServiceInformation *service_information,
++ CORBA_Environment *ev);
++
++extern CORBA_Current *CORBA_ORB_get_current(
++ CORBA_ORB orb,
++ CORBA_Environment *ev);
++
++extern CORBA_ORB_ObjectIdList* CORBA_ORB_list_initial_services(
++ CORBA_ORB orb,
++ CORBA_Environment *ev);
++
++extern CORBA_Object CORBA_ORB_resolve_initial_references(
++ CORBA_ORB orb,
++ CORBA_ORB_ObjectId identifier,
++ CORBA_Environment *ev);
++
++extern void CORBA_ORB_set_initial_reference(
++ CORBA_ORB orb,
++ CORBA_ORB_ObjectId identifier,
++ CORBA_Object obj,
++ CORBA_Environment *ev);
++
++extern CORBA_boolean CORBA_ORB_work_pending(
++ CORBA_ORB orb,
++ CORBA_Environment *ev);
++
++extern void CORBA_ORB_perform_work(
++ CORBA_ORB orb,
++ CORBA_Environment *ev);
++
++extern void CORBA_ORB_shutdown(
++ CORBA_ORB orb,
++ CORBA_boolean wait_for_completion,
++ CORBA_Environment *ev);
++
++extern void CORBA_ORB_run(
++ CORBA_ORB orb,
++ CORBA_Environment *ev);
++
++extern CORBA_PolicyType CORBA_Policy__get_policy_type(
++ CORBA_Policy obj,
++ CORBA_Environment *ev);
++
++extern CORBA_Policy CORBA_Policy_copy(
++ CORBA_Policy obj,
++ CORBA_Environment *ev);
++
++extern void CORBA_Policy_destroy(
++ CORBA_Policy obj,
++ CORBA_Environment *ev);
++
++#ifndef __KORBIT__
++extern CORBA_InterfaceDef CORBA_Object_get_interface(
++ CORBA_Object obj,
++ CORBA_Environment *ev);
++#endif /* !__KORBIT__ */
++
++extern CORBA_boolean CORBA_Object_is_nil(
++ CORBA_Object obj,
++ CORBA_Environment *ev);
++
++extern CORBA_Object CORBA_Object_duplicate(
++ CORBA_Object obj,
++ CORBA_Environment *ev);
++
++extern void CORBA_Object_release(
++ CORBA_Object obj,
++ CORBA_Environment *ev);
++
++extern CORBA_boolean CORBA_Object_non_existent(
++ CORBA_Object obj,
++ CORBA_Environment *ev);
++
++extern CORBA_boolean CORBA_Object_is_equivalent(
++ CORBA_Object obj,
++ CORBA_Object other_object,
++ CORBA_Environment *ev);
++
++extern CORBA_unsigned_long CORBA_Object_hash(
++ CORBA_Object obj,
++ CORBA_unsigned_long maximum,
++ CORBA_Environment *ev);
++
++extern CORBA_Policy CORBA_Object_get_policy(
++ CORBA_Object obj,
++ CORBA_PolicyType policy_type,
++ CORBA_Environment *ev);
++
++#ifndef __KORBIT__
++extern CORBA_DomainManagerList *CORBA_Object_get_domain_managers(
++ CORBA_Object obj,
++ CORBA_Environment *ev);
++
++extern CORBA_Policy CORBA_DomainManager_get_domain_policy(
++ CORBA_DomainManager obj,
++ CORBA_PolicyType policy_type,
++ CORBA_Environment *ev);
++
++extern void CORBA_ConstructionPolicy_make_domain_manager(
++ CORBA_ConstructionPolicy obj,
++ CORBA_Object /*CORBA_InterfaceDef*/ object_type,
++ CORBA_boolean constr_policy,
++ CORBA_Environment *ev);
++
++CORBA_TypeCode CORBA_ORB_create_struct_tc(CORBA_ORB obj,
++ CORBA_RepositoryId id,
++ CORBA_Identifier name,
++ CORBA_StructMemberSeq members,
++ CORBA_Environment *ev);
++
++CORBA_TypeCode CORBA_ORB_create_union_tc(CORBA_ORB obj,
++ CORBA_RepositoryId id,
++ CORBA_Identifier name,
++ CORBA_TypeCode discriminator_type,
++ CORBA_UnionMemberSeq members,
++ CORBA_Environment *ev);
++
++CORBA_TypeCode CORBA_ORB_create_enum_tc(CORBA_ORB obj,
++ CORBA_RepositoryId id,
++ CORBA_Identifier name,
++ CORBA_EnumMemberSeq members,
++ CORBA_Environment *ev);
++
++CORBA_TypeCode CORBA_ORB_create_alias_tc(CORBA_ORB obj,
++ CORBA_RepositoryId id,
++ CORBA_Identifier name,
++ CORBA_TypeCode original_type,
++ CORBA_Environment *ev);
++
++CORBA_TypeCode CORBA_ORB_create_exception_tc(CORBA_ORB obj,
++ CORBA_RepositoryId id,
++ CORBA_Identifier name,
++ CORBA_StructMemberSeq members,
++ CORBA_Environment *ev);
++
++CORBA_TypeCode CORBA_ORB_create_interface_tc(CORBA_ORB obj,
++ CORBA_RepositoryId id,
++ CORBA_Identifier name,
++ CORBA_Environment *ev);
++
++CORBA_TypeCode CORBA_ORB_create_string_tc(CORBA_ORB obj,
++ CORBA_unsigned_long bound,
++ CORBA_Environment *ev);
++
++CORBA_TypeCode CORBA_ORB_create_wstring_tc(CORBA_ORB obj,
++ CORBA_unsigned_long bound,
++ CORBA_Environment *ev);
++
++CORBA_TypeCode CORBA_ORB_create_fixed_tc(CORBA_ORB obj,
++ CORBA_unsigned_short digits,
++ CORBA_short scale,
++ CORBA_Environment *ev);
++
++extern CORBA_TypeCode CORBA_ORB_create_sequence_tc(
++ CORBA_ORB obj,
++ CORBA_unsigned_long bound,
++ CORBA_TypeCode element_type,
++ CORBA_Environment *ev);
++
++extern CORBA_TypeCode CORBA_ORB_create_recursive_sequence_tc(
++ CORBA_ORB obj,
++ CORBA_unsigned_long bound,
++ CORBA_unsigned_long offset,
++ CORBA_Environment *ev);
++
++extern CORBA_TypeCode CORBA_ORB_create_array_tc(
++ CORBA_ORB obj,
++ CORBA_unsigned_long length,
++ CORBA_TypeCode element_type,
++ CORBA_Environment *ev);
++
++#endif /* !__KORBIT__ */
++
++#endif /* !_ORBIT_ORB_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/orbit.c linux-2.4.1-korbit/net/korbit/orb/orbit.c
+--- linux-2.4.1/net/korbit/orb/orbit.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orbit.c Thu Feb 1 11:47:13 2001
+@@ -0,0 +1,387 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter and Red Hat Software
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++/*
++ * This file is a repository for random functions that don't fit anywhere
++ * else, and for ORBit-specific stuff.
++ */
++
++#include <stdlib.h>
++#include <string.h>
++#include <sys/types.h>
++#include <netdb.h>
++#include <netinet/in.h>
++#include <arpa/inet.h>
++#include <assert.h>
++#include <math.h>
++
++#include "orbit.h"
++
++const guint orbit_major_version = ORBIT_MAJOR_VERSION,
++ orbit_minor_version = ORBIT_MINOR_VERSION,
++ orbit_micro_version = ORBIT_MICRO_VERSION;
++const char orbit_version[] = ORBIT_VERSION;
++
++typedef struct ORBitClassInfo ORBitClassInfo;
++
++typedef void (*ORBitObjectInitFunc)(CORBA_Object _handle_to_be, gpointer class_data);
++
++struct ORBitClassInfo {
++ char *name;
++ gulong id;
++ gpointer method_stubs, method_skels;
++ ORBitObjectInitFunc class_vtable_init_func;
++ ORBitClassInfo **parent_classes;
++};
++
++GHashTable *orbit_class_list = NULL, *orbit_class_byid;
++glong class_id_counter = -1;
++
++void CORBA_any_set_release(CORBA_any *any, CORBA_boolean flag)
++{
++ g_assert(any!=NULL);
++
++ if(flag==CORBA_TRUE) {
++ any->_release |= CORBA_ANYFLAGS_RELEASE;
++ } else {
++ any->_release &= ~CORBA_ANYFLAGS_RELEASE;
++ }
++
++}
++
++CORBA_boolean CORBA_any_get_release(CORBA_any *any)
++{
++ g_assert(any!=NULL);
++
++ if(any->_release & CORBA_ANYFLAGS_RELEASE)
++ return(CORBA_TRUE);
++ else
++ return(CORBA_FALSE);
++}
++
++void CORBA_sequence_set_release(void *seq, CORBA_boolean flag)
++{
++ struct CORBA_Sequence_type *sequence;
++
++ g_assert(seq!=NULL);
++
++ sequence=(struct CORBA_Sequence_type *)seq;
++
++ if(flag==CORBA_TRUE) {
++ sequence->_release |= CORBA_ANYFLAGS_RELEASE;
++ } else {
++ sequence->_release &= ~CORBA_ANYFLAGS_RELEASE;
++ }
++}
++
++CORBA_boolean CORBA_sequence_get_release(void *seq)
++{
++ struct CORBA_Sequence_type *sequence;
++
++ g_assert(seq!=NULL);
++
++ sequence=(struct CORBA_Sequence_type *)seq;
++
++ if(sequence->_release & CORBA_ANYFLAGS_RELEASE)
++ return(CORBA_TRUE);
++ else
++ return(CORBA_FALSE);
++}
++
++/*
++ * As far as I understand, values returned by CORBA_*_alloc() are supposed to be
++ * freeable by CORBA_free(), so we can't use memory chunks here in any reasonable
++ * fashion.
++ */
++gpointer
++CORBA_any__free(gpointer mem, gpointer func_data, CORBA_boolean free_strings)
++{
++ CORBA_any *aval = mem;
++
++ if(aval->_release)
++ ORBit_free(aval->_value, free_strings);
++ CORBA_Object_release((CORBA_Object)aval->_type, NULL);
++
++ return aval + 1;
++}
++
++CORBA_any *CORBA_any_alloc(void)
++{
++ CORBA_any *retval = ORBit_alloc(sizeof(CORBA_any), &CORBA_any__free,
++ GINT_TO_POINTER(1));
++
++ memset(retval, 0, sizeof(CORBA_any)); /* Make things easier on stubs */
++
++ return retval;
++}
++
++/*
++ * Compares the typecodes of each any
++ */
++CORBA_boolean ORBit_any_equivalent(CORBA_any obj, CORBA_any any, CORBA_Environment *ev)
++{
++ return(CORBA_FALSE);
++}
++
++/* This is needed by skels, that generate a __free function when they see
++ the TypeCode interface */
++gpointer
++CORBA_TypeCode__free(gpointer mem, gpointer func_data, CORBA_boolean free_strings)
++{
++ CORBA_Object_release(*(CORBA_Object *)mem, NULL);
++ return ((guchar *)mem) + sizeof(CORBA_TypeCode);
++}
++
++CORBA_char *CORBA_string_dup(const CORBA_char *string)
++{
++ if(!string)
++ return NULL;
++
++ return strcpy(ORBit_alloc(strlen(string)+1, NULL, NULL), string);
++}
++
++CORBA_char *CORBA_string_alloc(CORBA_unsigned_long len)
++{
++ return ORBit_alloc(len + 1, NULL, NULL);
++}
++
++CORBA_wchar *CORBA_wstring_alloc(CORBA_unsigned_long len)
++{
++ return ORBit_alloc(len + 1, NULL, NULL);
++}
++
++gpointer
++CORBA_string__free(gpointer str, gpointer dat, CORBA_boolean free_strings)
++{
++ if(free_strings)
++ CORBA_free(*((gpointer *)str));
++ return (gpointer)((guchar *)str + sizeof(CORBA_char *));
++}
++
++gpointer CORBA_Object__free(gpointer str, gpointer dat, CORBA_boolean free_strings)
++{
++ CORBA_Environment ev;
++ CORBA_exception_init(&ev);
++ CORBA_Object_release(*((gpointer *)str), &ev);
++ CORBA_exception_free(&ev);
++ return (gpointer)((guchar *)str + sizeof(CORBA_Object));
++}
++
++/* 19.14 */
++
++/* The big picture for fixeds.
++ We have to represent a number in memory.
++
++ 1 2 3 . 4 5 6 7
++
++ There are three pieces of information in a fixed:
++
++ - Number of significant digits. (_digits)
++
++ - The scale. The number of places the decimal point is to the right
++ of the first significant digit. (_scale)
++
++ - The digits themselves (_value)
++
++ */
++CORBA_long CORBA_fixed_integer_part(const void *fp)
++{
++ CORBA_long retval = 0;
++ int i, power_of_ten, digit;
++ const CORBA_fixed_d_s *val = fp;
++
++ g_return_val_if_fail(fp != NULL, INT_MIN);
++
++ for(i = 0; i < (val->_digits - val->_scale); i++) {
++ power_of_ten = val->_digits - i - val->_scale - 1;
++ digit = val->_value[i];
++ retval += digit * ((int)pow(10, power_of_ten));
++ }
++
++ return retval;
++}
++
++CORBA_long CORBA_fixed_fraction_part(const void *fp)
++{
++ CORBA_long retval = 0;
++ int i, power_of_ten, digit;
++ const CORBA_fixed_d_s *val = fp;
++
++ g_return_val_if_fail(fp != NULL, INT_MIN);
++
++ for(i = val->_digits - val->_scale; i < val->_digits; i++){
++ power_of_ten = val->_digits - i - 1;
++ digit = val->_value[i];
++ retval += digit * ((int)pow(10, power_of_ten));
++ }
++
++ return retval;
++}
++
++static inline
++CORBA_long do_div (CORBA_long *n)
++{
++ int __res;
++
++ __res = (*n) % (unsigned) 10;
++ *n = (*n) / (unsigned) 10;
++
++ return __res;
++}
++
++void CORBA_fixed_set(void *rp, CORBA_long i, CORBA_long f)
++{
++ CORBA_fixed_d_s *val = rp;
++ CORBA_long left_to_eat, cur;
++ signed char sign = 1;
++
++ g_return_if_fail(rp != NULL);
++
++ memset(val->_value, 0, val->_digits);
++
++ if(i) sign = i/abs(i);
++ val->_sign = sign;
++ i = abs(i);
++ f = abs(f);
++
++ for(cur = 0, left_to_eat = i;
++ left_to_eat != 0 && cur < val->_digits; cur++) {
++ val->_value[cur] = do_div(&left_to_eat) * sign;
++ sign = 1;
++ }
++
++ val->_scale = cur - 1;
++
++ for(left_to_eat = f;
++ left_to_eat != 0 && cur < val->_digits; cur++) {
++ val->_value[cur] = do_div(&left_to_eat);
++ }
++}
++
++void CORBA_fixed_add(void *rp, const void *f1p, const void *f2p)
++{
++ g_assert(!"Not yet implemented");
++}
++
++void CORBA_fixed_sub(void *rp, const void *f1p, const void *f2p)
++{
++ g_assert(!"Not yet implemented");
++}
++
++void CORBA_fixed_mul(void *rp, const void *f1p, const void *f2p)
++{
++ g_assert(!"Not yet implemented");
++}
++
++void CORBA_fixed_div(void *rp, const void *f1p, const void *f2p)
++{
++ g_assert(!"Not yet implemented");
++}
++
++CORBA_fixed_d_s *CORBA_fixed_alloc(CORBA_unsigned_short d)
++{
++ return (CORBA_fixed_d_s *)
++ g_malloc(sizeof(CORBA_fixed_d_s) + d + 1);
++}
++
++void CORBA_free(void *storage)
++{
++ ORBit_free(storage, CORBA_TRUE);
++}
++
++int ORBit_parse_unixsock(CORBA_Object obj,
++ char *sockpath,
++ gboolean existing_only)
++{
++ if(!sockpath || !*sockpath)
++ return -1;
++
++ obj->connection =
++ GIOP_CONNECTION(iiop_connection_unix_get(sockpath,
++ existing_only));
++
++ if(!obj->connection)
++ return -1;
++
++ giop_connection_ref(obj->connection);
++ return 0;
++}
++
++int ORBit_parse_inet(CORBA_Object obj, char *hostname, unsigned short port,
++ gboolean existing_only)
++{
++ obj->connection = GIOP_CONNECTION(iiop_connection_get(hostname, port, existing_only));
++
++ if(!obj->connection)
++ return -1;
++ giop_connection_ref(obj->connection);
++ return 0;
++}
++
++static const CORBA_unsigned_long zero_int = 0;
++struct iovec ORBit_default_principal_iovec = {(gpointer)&zero_int, sizeof(zero_int)};
++
++void ORBit_set_default_principal(CORBA_Principal *principal)
++{
++ gpointer t;
++
++ if((gpointer)ORBit_default_principal_iovec.iov_base != (gpointer)&zero_int)
++ g_free(ORBit_default_principal_iovec.iov_base);
++
++ ORBit_default_principal_iovec.iov_len = principal->_length
++ + sizeof(CORBA_unsigned_long);
++
++ t = ORBit_default_principal_iovec.iov_base =
++ g_malloc(ORBit_default_principal_iovec.iov_len);
++
++ memcpy(t, &principal->_length, sizeof(principal->_length));
++
++ t = ((guchar *)t) + sizeof(principal->_length);
++ memcpy(t, principal->_buffer, principal->_length);
++}
++
++CORBA_unsigned_long ORBit_class_assignment_counter = 0;
++GHashTable *ORBit_class_assignments = NULL;
++
++/* XXX not thread-safe */
++CORBA_unsigned_long
++ORBit_register_class(const PortableServer_ClassInfo *class_info)
++{
++ CORBA_unsigned_long retval;
++
++ if(!ORBit_class_assignments)
++ ORBit_class_assignments = g_hash_table_new(g_str_hash, g_str_equal);
++
++ /* This needs to be pre-increment - we don't want to give out
++ classid 0, because (a) that is reserved for the base Object class
++ (b) all the routines allocate a new id if the variable
++ storing their ID == 0 */
++ retval = ++ORBit_class_assignment_counter;
++
++ g_hash_table_insert(ORBit_class_assignments, (gpointer)class_info->class_name,
++ GINT_TO_POINTER(retval));
++
++ return retval;
++}
+diff -urN linux-2.4.1/net/korbit/orb/orbit.h linux-2.4.1-korbit/net/korbit/orb/orbit.h
+--- linux-2.4.1/net/korbit/orb/orbit.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orbit.h Thu Feb 1 11:47:13 2001
+@@ -0,0 +1,207 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@acm.org>
++ * Elliot Lee <sopwith@redhat.com>
++ *
++ */
++
++/* these two blocks are outside of the main header for good reason...
++ People may include headers from many different stubs, and we want to
++ have the version checked on all of them.
++ */
++#ifndef ORBIT_SERIAL
++#define ORBIT_SERIAL 9
++#endif
++
++#ifdef ORBIT_IDL_SERIAL
++#if ORBIT_IDL_SERIAL < 9
++#error "You need to rerun 'orbit-idl' on the .idl file whose stubs you are using. These stubs were generated with an older version of ORBit, and need to be regenerated."
++#endif
++#endif
++
++#ifndef _ORBIT_H_
++#define _ORBIT_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++#include <glib.h>
++
++#define BACKWARDS_COMPAT_0_4
++#undef NOT_BACKWARDS_COMPAT_0_4
++
++#include <sys/types.h>
++#include <sys/uio.h>
++#include <IIOP/IIOP.h>
++#include <ORBitutil/util.h>
++#include <orb/orbit_config.h>
++#include <orb/orbit_types.h>
++#include <orb/allocators.h>
++#include <orb/cdr.h>
++#include <orb/dii.h>
++#ifndef __KORBIT__
++#include <orb/dynany.h>
++#endif
++#include <orb/env.h>
++#include <orb/iop.h>
++#include <orb/ir.h>
++#include <orb/options.h>
++#include <orb/orb.h>
++#include <orb/poa.h>
++#include <orb/sequences.h>
++#include <orb/orbit_typecode.h>
++#include <orb/typecode.h>
++
++#ifndef ORBIT_MAJOR_VERSION
++#define ORBIT_MAJOR_VERSION (0)
++#define ORBIT_MINOR_VERSION (5)
++#define ORBIT_MICRO_VERSION (3)
++#endif
++
++extern const guint orbit_major_version,
++ orbit_minor_version,
++ orbit_micro_version;
++extern const char orbit_version[];
++
++extern void CORBA_any_set_release(
++ CORBA_any *,
++ CORBA_boolean);
++
++extern CORBA_boolean CORBA_any_get_release(
++ CORBA_any *);
++
++extern void CORBA_sequence_set_release(
++ void *,
++ CORBA_boolean);
++
++extern CORBA_boolean CORBA_sequence_get_release(
++ void *);
++
++#define CORBA_any__alloc CORBA_any_alloc
++extern CORBA_any *CORBA_any_alloc(
++ void);
++
++extern gpointer CORBA_any__free(gpointer mem, gpointer func_data,
++ CORBA_boolean free_strings);
++extern gpointer CORBA_TypeCode__free(gpointer mem, gpointer func_data,
++ CORBA_boolean free_strings);
++
++extern CORBA_boolean ORBit_any_equivalent(
++ CORBA_any obj,
++ CORBA_any any,
++ CORBA_Environment *ev);
++
++extern CORBA_char *CORBA_string_dup(const CORBA_char *string);
++extern CORBA_char *CORBA_string_alloc(CORBA_unsigned_long len);
++extern gpointer CORBA_string__free(gpointer str, gpointer dat, CORBA_boolean free_strings);
++
++gpointer CORBA_Object__free(gpointer str, gpointer dat, CORBA_boolean free_strings);
++
++extern CORBA_wchar *CORBA_wstring_alloc(CORBA_unsigned_long len);
++#define CORBA_wstring_free CORBA_string_free
++
++/* 19.14 */
++extern CORBA_long CORBA_fixed_integer_part(
++ const void *fp);
++
++extern CORBA_long CORBA_fixed_fraction_part(
++ const void *fp);
++
++extern void CORBA_fixed_set(
++ void *rp,
++ CORBA_long i,
++ CORBA_long f);
++
++extern void CORBA_fixed_add(
++ void *rp,
++ const void *f1p,
++ const void *f2p);
++
++extern void CORBA_fixed_sub(
++ void *rp,
++ const void *f1p,
++ const void *f2p);
++
++extern void CORBA_fixed_mul(
++ void *rp,
++ const void *f1p,
++ const void *f2p);
++
++extern void CORBA_fixed_div(
++ void *rp,
++ const void *f1p,
++ const void *f2p);
++
++extern CORBA_fixed_d_s *CORBA_fixed_alloc(
++ CORBA_unsigned_short d);
++
++extern void CORBA_free(
++ void *storage);
++
++extern int ORBit_parse_inet(
++ CORBA_Object obj,
++ char *hostname,
++ unsigned short port,
++ gboolean existing_only);
++
++extern int ORBit_parse_unixsock(CORBA_Object obj,
++ char *sockpath,
++ gboolean existing_only);
++
++/****
++ This function lets you use your own event loop, if you so wish.
++ Also see IIOP.h's IIOP{Add,Remove}ConnectionHandler function pointers,
++ which are app-settable (you should set them before CORBA_ORB_init,
++ if you want them to be useful)
++ ****/
++
++ /* needs to be called by your event loop when data comes in on one of the
++ GIOPConnection fd's */
++void ORBit_custom_run_setup(CORBA_ORB orb, CORBA_Environment *ev);
++ void ORBit_handle_incoming(GIOPConnection *connection);
++
++/* Returns CORBA_TRUE if the request is OK to proceed. */
++typedef enum {
++ ORBIT_MESSAGE_BAD,
++ ORBIT_MESSAGE_ALLOW,
++ ORBIT_MESSAGE_ALLOW_ALL /* Allow all subsequent messages on
++ this connection with no checking */
++} ORBit_MessageValidationResult;
++typedef ORBit_MessageValidationResult (*ORBit_request_validate)
++ (CORBA_unsigned_long request_id,
++ CORBA_Principal *principal,
++ CORBA_char *operation);
++void ORBit_set_request_validation_handler(ORBit_request_validate validator);
++
++extern struct iovec ORBit_default_principal_iovec;
++void ORBit_set_default_principal(CORBA_Principal *principal);
++
++extern CORBA_unsigned_long ORBit_class_assignment_counter;
++
++CORBA_unsigned_long ORBit_register_class(const PortableServer_ClassInfo *class_info);
++
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif /* !_ORBIT_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/orbit.h.in linux-2.4.1-korbit/net/korbit/orb/orbit.h.in
+--- linux-2.4.1/net/korbit/orb/orbit.h.in Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orbit.h.in Thu Feb 1 11:47:13 2001
+@@ -0,0 +1,205 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@acm.org>
++ * Elliot Lee <sopwith@redhat.com>
++ *
++ */
++
++/* these two blocks are outside of the main header for good reason...
++ People may include headers from many different stubs, and we want to
++ have the version checked on all of them.
++ */
++#ifndef ORBIT_SERIAL
++#define ORBIT_SERIAL @ORBIT_SERIAL@
++#endif
++
++#ifdef ORBIT_IDL_SERIAL
++#if ORBIT_IDL_SERIAL < @ORBIT_SERIAL@
++#error "You need to rerun 'orbit-idl' on the .idl file whose stubs you are using. These stubs were generated with an older version of ORBit, and need to be regenerated."
++#endif
++#endif
++
++#ifndef _ORBIT_H_
++#define _ORBIT_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++#include <glib.h>
++
++#define BACKWARDS_COMPAT_0_4
++#undef NOT_BACKWARDS_COMPAT_0_4
++
++#include <sys/types.h>
++#include <sys/uio.h>
++#include <IIOP/IIOP.h>
++#include <ORBitutil/util.h>
++#include <orb/orbit_config.h>
++#include <orb/orbit_types.h>
++#include <orb/allocators.h>
++#include <orb/cdr.h>
++#include <orb/dii.h>
++#include <orb/dynany.h>
++#include <orb/env.h>
++#include <orb/iop.h>
++#include <orb/ir.h>
++#include <orb/options.h>
++#include <orb/orb.h>
++#include <orb/poa.h>
++#include <orb/sequences.h>
++#include <orb/orbit_typecode.h>
++#include <orb/typecode.h>
++
++#ifndef ORBIT_MAJOR_VERSION
++#define ORBIT_MAJOR_VERSION (@ORBIT_MAJOR_VERSION@)
++#define ORBIT_MINOR_VERSION (@ORBIT_MINOR_VERSION@)
++#define ORBIT_MICRO_VERSION (@ORBIT_MICRO_VERSION@)
++#endif
++
++extern const guint orbit_major_version,
++ orbit_minor_version,
++ orbit_micro_version;
++extern const char orbit_version[];
++
++extern void CORBA_any_set_release(
++ CORBA_any *,
++ CORBA_boolean);
++
++extern CORBA_boolean CORBA_any_get_release(
++ CORBA_any *);
++
++extern void CORBA_sequence_set_release(
++ void *,
++ CORBA_boolean);
++
++extern CORBA_boolean CORBA_sequence_get_release(
++ void *);
++
++#define CORBA_any__alloc CORBA_any_alloc
++extern CORBA_any *CORBA_any_alloc(
++ void);
++
++extern gpointer CORBA_any__free(gpointer mem, gpointer func_data,
++ CORBA_boolean free_strings);
++extern gpointer CORBA_TypeCode__free(gpointer mem, gpointer func_data,
++ CORBA_boolean free_strings);
++
++extern CORBA_boolean ORBit_any_equivalent(
++ CORBA_any obj,
++ CORBA_any any,
++ CORBA_Environment *ev);
++
++extern CORBA_char *CORBA_string_dup(const CORBA_char *string);
++extern CORBA_char *CORBA_string_alloc(CORBA_unsigned_long len);
++extern gpointer CORBA_string__free(gpointer str, gpointer dat, CORBA_boolean free_strings);
++
++gpointer CORBA_Object__free(gpointer str, gpointer dat, CORBA_boolean free_strings);
++
++extern CORBA_wchar *CORBA_wstring_alloc(CORBA_unsigned_long len);
++#define CORBA_wstring_free CORBA_string_free
++
++/* 19.14 */
++extern CORBA_long CORBA_fixed_integer_part(
++ const void *fp);
++
++extern CORBA_long CORBA_fixed_fraction_part(
++ const void *fp);
++
++extern void CORBA_fixed_set(
++ void *rp,
++ CORBA_long i,
++ CORBA_long f);
++
++extern void CORBA_fixed_add(
++ void *rp,
++ const void *f1p,
++ const void *f2p);
++
++extern void CORBA_fixed_sub(
++ void *rp,
++ const void *f1p,
++ const void *f2p);
++
++extern void CORBA_fixed_mul(
++ void *rp,
++ const void *f1p,
++ const void *f2p);
++
++extern void CORBA_fixed_div(
++ void *rp,
++ const void *f1p,
++ const void *f2p);
++
++extern CORBA_fixed_d_s *CORBA_fixed_alloc(
++ CORBA_unsigned_short d);
++
++extern void CORBA_free(
++ void *storage);
++
++extern int ORBit_parse_inet(
++ CORBA_Object obj,
++ char *hostname,
++ unsigned short port,
++ gboolean existing_only);
++
++extern int ORBit_parse_unixsock(CORBA_Object obj,
++ char *sockpath,
++ gboolean existing_only);
++
++/****
++ This function lets you use your own event loop, if you so wish.
++ Also see IIOP.h's IIOP{Add,Remove}ConnectionHandler function pointers,
++ which are app-settable (you should set them before CORBA_ORB_init,
++ if you want them to be useful)
++ ****/
++
++ /* needs to be called by your event loop when data comes in on one of the
++ GIOPConnection fd's */
++void ORBit_custom_run_setup(CORBA_ORB orb, CORBA_Environment *ev);
++ void ORBit_handle_incoming(GIOPConnection *connection);
++
++/* Returns CORBA_TRUE if the request is OK to proceed. */
++typedef enum {
++ ORBIT_MESSAGE_BAD,
++ ORBIT_MESSAGE_ALLOW,
++ ORBIT_MESSAGE_ALLOW_ALL /* Allow all subsequent messages on
++ this connection with no checking */
++} ORBit_MessageValidationResult;
++typedef ORBit_MessageValidationResult (*ORBit_request_validate)
++ (CORBA_unsigned_long request_id,
++ CORBA_Principal *principal,
++ CORBA_char *operation);
++void ORBit_set_request_validation_handler(ORBit_request_validate validator);
++
++extern struct iovec ORBit_default_principal_iovec;
++void ORBit_set_default_principal(CORBA_Principal *principal);
++
++extern CORBA_unsigned_long ORBit_class_assignment_counter;
++
++CORBA_unsigned_long ORBit_register_class(const PortableServer_ClassInfo *class_info);
++
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif /* !_ORBIT_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/orbit_config.h linux-2.4.1-korbit/net/korbit/orb/orbit_config.h
+--- linux-2.4.1/net/korbit/orb/orbit_config.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orbit_config.h Thu Feb 1 11:47:13 2001
+@@ -0,0 +1,9 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++#ifndef ORB_CONFIG_H
++#define ORB_CONFIG_H 1
++
++/* When creating a memory pool for a particular type, how many chunks
++ do we want to pre-allocated? */
++#define ORBIT_CHUNKS_PREALLOC 2
++
++#endif /* ORB_CONFIG_H */
+diff -urN linux-2.4.1/net/korbit/orb/orbit_object.c linux-2.4.1-korbit/net/korbit/orb/orbit_object.c
+--- linux-2.4.1/net/korbit/orb/orbit_object.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orbit_object.c Thu Feb 1 11:47:13 2001
+@@ -0,0 +1,699 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter and Red Hat Software
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Phil Dawes <philipd@parallax.co.uk>
++ * Elliot Lee <sopwith@redhat.com>
++ *
++ */
++
++/*
++ * ORBit specific CORBA_Object functions.
++ *
++ */
++
++#include <string.h>
++#include "config.h"
++#include "../IIOP/iiop-endianP.h"
++#include "orbit_object_type.h"
++#include "corba_object_type.h"
++#include "allocators.h"
++#include "iop.h"
++#include <IIOP/IIOP.h>
++
++static void ORBit_object_try_existing_connections(CORBA_Object obj);
++static void CORBA_Object_release_fn(CORBA_Object obj, CORBA_Environment *ev);
++
++static ORBit_RootObject_Interface CORBA_Object_epv =
++{
++ (void (*)(gpointer, CORBA_Environment *))CORBA_Object_release_fn,
++};
++
++void ORBit_pseudo_object_init(ORBit_PseudoObject obj,
++ ORBit_PseudoObject_type obj_type,
++ CORBA_Environment *ev)
++{
++ ORBIT_ROOT_OBJECT(obj)->is_pseudo_object = TRUE;
++ ORBIT_ROOT_OBJECT(obj)->refs = 0;
++ ORBIT_PSEUDO_OBJECT(obj)->pseudo_object_type = obj_type;
++}
++
++static const ORBit_RootObject_Interface CORBA_Policy__epv =
++{
++ (void (*)(gpointer, CORBA_Environment *))CORBA_Policy_destroy
++};
++
++void ORBit_policy_object_init(CORBA_Policy obj,
++ CORBA_PolicyType obj_type,
++ CORBA_Environment *ev)
++{
++ ORBit_pseudo_object_init(ORBIT_PSEUDO_OBJECT(obj),
++ ORBIT_PSEUDO_POLICY, ev);
++
++ obj->policy_type = obj_type;
++
++ ORBit_RootObject_set_interface(ORBIT_ROOT_OBJECT(obj),
++ (gpointer)&CORBA_Policy__epv,
++ ev);
++}
++
++void ORBit_object_reference_init(CORBA_Object obj, CORBA_Environment *ev)
++{
++ /* set the interface up */
++ ORBit_RootObject_set_interface(ORBIT_ROOT_OBJECT(obj),&CORBA_Object_epv,ev);
++ /* initialise the reference count */
++ ORBIT_ROOT_OBJECT(obj)->refs = 0;
++ ORBIT_ROOT_OBJECT(obj)->is_pseudo_object = FALSE;
++}
++
++CORBA_Object
++ORBit_CORBA_Object_new(CORBA_Environment *ev)
++{
++ CORBA_Object obj;
++ /* Create the object */
++ obj = ORBIT_CHUNK_ALLOC(CORBA_Object);
++ memset(obj, '\0', sizeof(struct CORBA_Object_struct));
++
++ ORBit_object_reference_init(obj, ev);
++
++ return obj;
++
++}
++
++void
++ORBit_set_object_key(ORBit_Object_info *info)
++{
++ g_assert(info);
++
++ g_assert(info->object_key._length);
++
++ info->object_key_data = g_malloc(sizeof(CORBA_unsigned_long) + info->object_key._length);
++ info->object_key_data->_length = info->object_key._length;
++ memcpy(info->object_key_data->_buffer, info->object_key._buffer, info->object_key._length);
++
++ info->object_key_vec.iov_base =
++ (gpointer)info->object_key_data;
++ info->object_key_vec.iov_len = sizeof(CORBA_unsigned_long) + info->object_key._length;
++}
++
++static void ORBit_free_profile(gpointer item, gpointer data)
++{
++ ORBit_Object_info *info=(ORBit_Object_info *)item;
++
++ g_assert(info);
++
++ g_free(info->object_key_data);
++ CORBA_free(info->object_key._buffer);
++
++ if(info->profile_type == IOP_TAG_INTERNET_IOP) {
++ g_free(info->tag.iopinfo.host);
++ } else if(info->profile_type == IOP_TAG_ORBIT_SPECIFIC) {
++ g_free(info->tag.orbitinfo.unix_sock_path);
++ } else {
++ g_warning("ORBit_free_profile asked to free type %d", info->profile_type);
++ }
++
++ g_free(info); /* Check its safe to free the item within a foreach func */
++}
++
++void ORBit_delete_profiles(GSList *profile_list)
++{
++ g_slist_foreach(profile_list, ORBit_free_profile, NULL);
++ g_slist_free(profile_list);
++}
++
++/* this function is wired up to the RootObject interface */
++void
++CORBA_Object_release_fn(CORBA_Object obj, CORBA_Environment *ev)
++{
++
++ g_assert(obj!=NULL);
++
++ ORBIT_ROOT_OBJECT_UNREF(obj);
++
++ if(ORBIT_ROOT_OBJECT(obj)->refs <= 0) {
++ g_hash_table_remove(obj->orb->objrefs, obj);
++
++ if(obj->connection)
++ giop_connection_unref(obj->connection);
++
++ g_free(obj->object_id);
++ ORBit_delete_profiles(obj->profile_list);
++ ORBit_delete_profiles(obj->forward_locations);
++
++ ORBIT_CHUNK_FREE(CORBA_Object, obj);
++ }
++}
++
++
++/* Sets the interface member in the RootObject to the epv specified*/
++void
++ORBit_RootObject_set_interface(ORBit_RootObject obj,
++ ORBit_RootObject_Interface* epv,
++ CORBA_Environment *ev)
++{
++ g_assert(obj!=NULL);
++ g_assert(epv!=NULL);
++
++ obj->interface = epv;
++}
++
++#define GET_ATOM(x) G_STMT_START{ GIOP_RECV_BUFFER(recv_buffer)->decoder(&x, (GIOP_RECV_BUFFER(recv_buffer)->cur), sizeof(x)); \
++GIOP_RECV_BUFFER(recv_buffer)->cur = ((guchar *)GIOP_RECV_BUFFER(recv_buffer)->cur) + sizeof(x); \
++}G_STMT_END
++#define ALIGNFOR(x) recv_buffer->cur = ALIGN_ADDRESS(recv_buffer->cur, sizeof(x))
++
++CORBA_Object
++ORBit_create_object_with_info(GSList *profiles,
++ const CORBA_char *type_id,
++ CORBA_ORB orb,
++ CORBA_Environment *ev)
++{
++ CORBA_Object new;
++ struct CORBA_Object_struct refcheck;
++
++ if(!type_id || !*type_id) {
++ g_warning("Failing object creation because object has no type");
++ CORBA_exception_set_system(ev, ex_CORBA_MARSHAL,
++ CORBA_COMPLETED_MAYBE);
++ return CORBA_OBJECT_NIL;
++ }
++
++ if(g_slist_length(profiles) < 1) {
++ g_warning("Failing object creation because object has no profiles");
++ CORBA_exception_set_system(ev, ex_CORBA_MARSHAL,
++ CORBA_COMPLETED_MAYBE);
++ return CORBA_OBJECT_NIL;
++ }
++
++ /* XXX badhack :) */
++ refcheck.object_id = type_id;
++ refcheck.profile_list = profiles;
++
++ new = g_hash_table_lookup(orb->objrefs, &refcheck);
++ if(new) {
++ ORBit_delete_profiles(profiles);
++ return CORBA_Object_duplicate(new, ev);
++ }
++
++ new = ORBit_CORBA_Object_new(ev);
++ new->connection = NULL;
++ new->object_id = g_strdup(type_id);
++ new->orb = (CORBA_ORB)CORBA_Object_duplicate((CORBA_Object)orb, ev);
++ new->profile_list = profiles;
++ new->active_profile = NULL;
++
++ ORBit_object_try_existing_connections(new);
++
++ g_hash_table_insert(orb->objrefs, new, new);
++
++ return CORBA_Object_duplicate(new, ev);
++}
++
++static ORBit_Object_info *
++ORBit_demarshal_profile(GIOPRecvBuffer *recv_buffer, IOP_ProfileId profile_id)
++{
++ ORBit_Object_info *object_info;
++ CORBA_unsigned_long subpart_len;
++ CORBA_octet o;
++ CDR_Codec codec_d;
++ CDR_Codec *codec=&codec_d;
++
++ object_info = g_new0(ORBit_Object_info, 1);
++
++ switch(profile_id) {
++ case IOP_TAG_INTERNET_IOP:
++ GET_ATOM(subpart_len); /* The length of the embedded sequence */
++ CDR_codec_init_static(codec);
++ codec->buffer = recv_buffer->cur;
++ codec->release_buffer = CORBA_FALSE;
++ recv_buffer->cur = ((guchar *)recv_buffer->cur) + subpart_len;
++
++ codec->readonly = CORBA_TRUE;
++ codec->host_endian = codec->data_endian = FLAG_ENDIANNESS;
++ codec->buf_len = subpart_len;
++
++ CDR_get_octet(codec, &o);
++ codec->data_endian = o;
++
++ object_info->profile_type = IOP_TAG_INTERNET_IOP;
++ CDR_get_octet(codec, &object_info->iiop_major);
++
++ if(object_info->iiop_major != 1)
++ goto error_exit;
++ /* XXX should we check for a specific minor version? */
++ CDR_get_octet(codec, &object_info->iiop_minor);
++
++ CDR_get_string(codec, &object_info->tag.iopinfo.host);
++
++ CDR_get_ushort(codec, &object_info->tag.iopinfo.port);
++
++ CDR_get_seq_begin(codec, &object_info->object_key._length);
++ object_info->object_key._buffer =
++ ORBit_alloc(object_info->object_key._length, NULL, NULL);
++ CDR_buffer_gets(codec, object_info->object_key._buffer,
++ object_info->object_key._length);
++ object_info->object_key._maximum = object_info->object_key._release = 0;
++
++ ORBit_set_object_key(object_info);
++
++ return(object_info);
++ break;
++
++ case IOP_TAG_MULTIPLE_COMPONENTS:
++ default:
++ GET_ATOM(subpart_len);
++ g_warning("IOP_TAG_MULTIPLE_COMPONENTS decoding needs finishing");
++ object_info->profile_type = IOP_TAG_MULTIPLE_COMPONENTS;
++ recv_buffer->cur = ((guchar *)recv_buffer->cur) + subpart_len;
++ return(object_info);
++ break;
++
++ case IOP_TAG_ORBIT_SPECIFIC:
++ GET_ATOM(subpart_len);
++ CDR_codec_init_static(codec);
++ codec->buffer = recv_buffer->cur;
++ codec->release_buffer = CORBA_FALSE;
++ recv_buffer->cur = ((guchar *)recv_buffer->cur) + subpart_len;
++
++ codec->readonly = CORBA_TRUE;
++ codec->host_endian = codec->data_endian = FLAG_ENDIANNESS;
++ codec->buf_len = subpart_len;
++
++ CDR_get_octet(codec, &o);
++ codec->data_endian = o;
++
++ object_info->profile_type = IOP_TAG_ORBIT_SPECIFIC;
++ CDR_get_octet(codec, &object_info->iiop_major);
++
++ if(object_info->iiop_major != 1)
++ goto error_exit;
++ /* XXX should we check for a specific minor version? */
++ CDR_get_octet(codec, &object_info->iiop_minor);
++
++ CDR_get_string(codec, &object_info->tag.orbitinfo.unix_sock_path);
++ CDR_get_ushort(codec, &object_info->tag.orbitinfo.ipv6_port);
++
++ CDR_get_seq_begin(codec, &object_info->object_key._length);
++ object_info->object_key._buffer =
++ ORBit_alloc(object_info->object_key._length, NULL, NULL);
++ CDR_buffer_gets(codec, object_info->object_key._buffer,
++ object_info->object_key._length);
++ object_info->object_key._maximum = object_info->object_key._release = 0;
++
++ ORBit_set_object_key(object_info);
++
++ return(object_info);
++ break;
++ }
++
++error_exit:
++ g_message("demarshal_profile(): IIOP major is %d",
++ object_info->iiop_major);
++ g_free(object_info);
++
++ return(NULL);
++}
++
++GSList *ORBit_demarshal_IOR(GIOPRecvBuffer *recv_buffer)
++{
++ GSList *profiles=NULL;
++ ORBit_Object_info *object_info;
++ CORBA_unsigned_long len, seq_len;
++ IOP_ProfileId profile_id;
++ int i;
++
++ /* Get type_id */
++ ALIGNFOR(CORBA_unsigned_long);
++ GET_ATOM(len);
++
++ if(len == 0)
++ return(NULL);
++
++ recv_buffer->cur = ((guchar *)recv_buffer->cur) + len;
++
++ /* Decode the sequence<TaggedProfile> */
++ ALIGNFOR(CORBA_unsigned_long);
++ GET_ATOM(seq_len);
++ for(i = 0; i < seq_len; i++) {
++ ALIGNFOR(CORBA_unsigned_long);
++ GET_ATOM(profile_id);
++ object_info=ORBit_demarshal_profile(recv_buffer, profile_id);
++ if(object_info==NULL) {
++ goto error_exit;
++ } else {
++ profiles=g_slist_append(profiles, object_info);
++ }
++ }
++
++ return(profiles);
++
++error_exit:
++ ORBit_delete_profiles(profiles);
++ return(NULL);
++}
++
++CORBA_Object
++ORBit_demarshal_object(GIOPRecvBuffer *recv_buffer, CORBA_ORB orb)
++{
++ GSList *profiles=NULL;
++ ORBit_Object_info *object_info;
++ CORBA_char *type_id;
++ CORBA_unsigned_long len, seq_len;
++ IOP_ProfileId profile_id;
++ int i;
++ CORBA_Environment ev;
++ CORBA_Object retval;
++
++ CORBA_exception_init(&ev);
++
++ /* Get type_id */
++ ALIGNFOR(CORBA_unsigned_long);
++ GET_ATOM(len);
++
++ type_id = recv_buffer->cur;
++ recv_buffer->cur = ((guchar *)recv_buffer->cur) + len;
++
++ /* Decode the sequence<TaggedProfile> */
++ ALIGNFOR(CORBA_unsigned_long);
++ GET_ATOM(seq_len);
++
++ if(!seq_len)
++ return CORBA_OBJECT_NIL;
++
++ for(i = 0; i < seq_len; i++) {
++ ALIGNFOR(CORBA_unsigned_long);
++ GET_ATOM(profile_id);
++ object_info=ORBit_demarshal_profile(recv_buffer, profile_id);
++ if(object_info)
++ profiles=g_slist_append(profiles, object_info);
++ }
++
++ if(!profiles)
++ goto error_exit;
++
++ retval = ORBit_create_object_with_info(profiles, type_id, orb, &ev);
++
++ return retval;
++
++ error_exit:
++ ORBit_delete_profiles(profiles);
++
++ CORBA_exception_set_system(&ev, ex_CORBA_MARSHAL,
++ CORBA_COMPLETED_MAYBE);
++ return CORBA_OBJECT_NIL;
++}
++
++static void ORBit_marshal_profile(gpointer item, gpointer data)
++{
++ ORBit_Object_info *info = (ORBit_Object_info *)item;
++ GIOPSendBuffer *send_buffer = (GIOPSendBuffer *)data;
++ static const CORBA_unsigned_long ioptag = IOP_TAG_INTERNET_IOP,
++ orbittag = IOP_TAG_ORBIT_SPECIFIC;
++ CDR_Codec codec_d;
++ CDR_Codec *codec = &codec_d;
++ CORBA_unsigned_long len;
++ CORBA_octet codecbuf[2048];
++ static const CORBA_octet oc_endian = FLAG_ENDIANNESS;
++ static const CORBA_octet iiopversion[] = {1,0};
++
++ g_assert(info);
++ g_assert(send_buffer);
++
++ if(info->profile_type == IOP_TAG_INTERNET_IOP) {
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(send_buffer),
++ &ioptag, sizeof(ioptag));
++
++ CDR_codec_init_static(codec);
++ codec->buffer = codecbuf;
++ codec->buf_len = 2048;
++ codec->release_buffer = CORBA_FALSE;
++ codec->readonly = CORBA_FALSE;
++ codec->data_endian = codec->host_endian = FLAG_ENDIANNESS;
++ CDR_put_octet(codec, oc_endian);
++ CDR_put_octet(codec, iiopversion[0]);
++ CDR_put_octet(codec, iiopversion[1]);
++ CDR_put_string(codec, info->tag.iopinfo.host);
++ CDR_put_ushort(codec, info->tag.iopinfo.port);
++ CDR_put_ulong(codec, info->object_key._length);
++ CDR_put_octets(codec, info->object_key._buffer,
++ info->object_key._length);
++ len = codec->wptr;
++ giop_send_buffer_append_mem_indirect_a(send_buffer,
++ &len, sizeof(len));
++ giop_send_buffer_append_mem_indirect(send_buffer,
++ codec->buffer, codec->wptr);
++ } else if(info->profile_type==IOP_TAG_ORBIT_SPECIFIC) {
++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(send_buffer),
++ &orbittag, sizeof(orbittag));
++ CDR_codec_init_static(codec);
++ codec->buffer = codecbuf;
++ codec->release_buffer = CORBA_FALSE;
++ codec->buf_len = 2048;
++ codec->readonly = CORBA_FALSE;
++ codec->data_endian = codec->host_endian = FLAG_ENDIANNESS;
++ CDR_put_octet(codec, oc_endian);
++ CDR_put_octets(codec, (gpointer)iiopversion, sizeof(iiopversion));
++ CDR_put_string(codec, info->tag.orbitinfo.unix_sock_path);
++ CDR_put_ushort(codec, info->tag.orbitinfo.ipv6_port);
++ CDR_put_ulong(codec, info->object_key._length);
++ CDR_put_octets(codec, info->object_key._buffer,
++ info->object_key._length);
++ len = codec->wptr;
++ giop_send_buffer_append_mem_indirect_a(send_buffer,
++ &len, sizeof(len));
++ giop_send_buffer_append_mem_indirect(send_buffer,
++ codec->buffer, codec->wptr);
++ } else {
++ g_warning("ORBit_marshal_profile ask to marshal type %d\n", info->profile_type);
++ }
++}
++
++void
++ORBit_marshal_object(GIOPSendBuffer *send_buffer, CORBA_Object obj)
++{
++ CORBA_unsigned_long len;
++
++
++ if(!obj) {
++ static const CORBA_unsigned_long zero = 0, one = 1;
++ /* zero-length typename */
++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(send_buffer),
++ &one, sizeof(one));
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(send_buffer),
++ &zero, 1);
++
++ /* zero profiles */
++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(send_buffer),
++ &zero, sizeof(zero));
++ return;
++ }
++ g_return_if_fail(ORBIT_ROOT_OBJECT(obj)->refs > 0);
++
++ len = strlen(obj->object_id) + 1;
++ giop_send_buffer_append_mem_indirect_a(send_buffer, &len,
++ sizeof(len));
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(send_buffer),
++ obj->object_id, len);
++
++ len = g_slist_length(obj->profile_list);
++ giop_send_buffer_append_mem_indirect_a(GIOP_SEND_BUFFER(send_buffer),
++ &len, sizeof(len));
++
++ /* Marshal active first? */
++ g_slist_foreach(obj->profile_list, ORBit_marshal_profile, send_buffer);
++}
++
++static void ORBit_test_profile(gpointer item, gpointer data)
++{
++ ORBit_Object_info *info = (ORBit_Object_info *)item;
++ CORBA_Object obj = (CORBA_Object)data;
++
++ if(obj->active_profile != NULL)
++ return; /* we already have a good profile */
++
++ if(info->profile_type == IOP_TAG_ORBIT_SPECIFIC) {
++ if(!ORBit_parse_unixsock(obj, info->tag.orbitinfo.unix_sock_path, TRUE)) {
++ /* success */
++ obj->active_profile=info;
++ }
++ } else if(info->profile_type == IOP_TAG_INTERNET_IOP) {
++ if(!ORBit_parse_inet(obj, info->tag.iopinfo.host, info->tag.iopinfo.port, TRUE)) {
++ /* success */
++ obj->active_profile=info;
++ }
++ }
++}
++
++static void
++ORBit_object_try_existing_connections(CORBA_Object obj)
++{
++ g_slist_foreach(obj->profile_list, ORBit_test_profile, obj);
++}
++
++static void ORBit_activate_profile(gpointer item, gpointer data)
++{
++ ORBit_Object_info *info = (ORBit_Object_info *)item;
++ CORBA_Object obj = (CORBA_Object)data;
++
++ if(obj->active_profile != NULL)
++ return; /* we already have a good profile */
++
++ if(info->profile_type == IOP_TAG_ORBIT_SPECIFIC) {
++ if(!ORBit_parse_unixsock(obj, info->tag.orbitinfo.unix_sock_path, FALSE)) {
++ /* success */
++ obj->active_profile=info;
++ }
++ } else if(info->profile_type == IOP_TAG_INTERNET_IOP) {
++ if(!ORBit_parse_inet(obj, info->tag.iopinfo.host, info->tag.iopinfo.port, FALSE)) {
++ /* success */
++ obj->active_profile=info;
++ }
++ }
++}
++
++GIOPConnection *
++_ORBit_object_get_connection(CORBA_Object obj)
++{
++ g_return_val_if_fail(obj, NULL);
++
++ if (obj->connection) {
++ giop_connection_unref(obj->connection);
++ obj->connection = NULL;
++ obj->active_profile = NULL;
++ }
++
++ g_slist_foreach(obj->profile_list, ORBit_activate_profile, obj);
++
++ if(obj->active_profile == NULL || !obj->connection)
++ return NULL;
++
++ obj->connection->orb_data = obj->orb;
++
++ return obj->connection;
++}
++
++GIOPConnection *
++ORBit_object_get_forwarded_connection(CORBA_Object obj)
++{
++ g_return_val_if_fail(obj, NULL);
++
++ if (obj->connection) {
++ giop_connection_unref(obj->connection);
++ obj->connection = NULL;
++ obj->active_profile = NULL;
++ }
++
++ g_slist_foreach(obj->forward_locations, ORBit_activate_profile, obj);
++
++ if(obj->active_profile == NULL || !obj->connection)
++ return NULL;
++
++ obj->connection->orb_data = obj->orb;
++
++ return obj->connection;
++}
++
++/* This function is heavily based on the idl stubs output. Any changes there
++ will probably have to be reflected here also. */
++
++void ORBit_object_locate(CORBA_Object obj, CORBA_Environment *ev)
++{
++ GIOPConnection *cnx;
++ GIOPSendBuffer *send_buffer;
++ GIOPRecvBuffer *recv_buffer;
++ GIOP_unsigned_long request_id;
++
++ g_return_if_fail(obj!=NULL);
++ g_return_if_fail(ev!=NULL);
++
++ /* Send a LOCATE_REQUEST, wait for a LOCATE_REPLY. The reply will
++ either say "Object here", or will carry a new location. We set
++ obj->active_profile appropriately */
++
++ cnx=ORBit_object_get_connection(obj);
++ if((cnx==NULL) || (obj->active_profile==NULL)) {
++ CORBA_exception_set_system(ev, ex_CORBA_COMM_FAILURE, CORBA_COMPLETED_NO);
++ return;
++ }
++ request_id=giop_get_request_id();
++ send_buffer=giop_send_locate_request_buffer_use(cnx, request_id, &(obj->active_profile->object_key_vec));
++ if(!send_buffer) {
++ CORBA_exception_set_system(ev, ex_CORBA_COMM_FAILURE, CORBA_COMPLETED_NO);
++ return;
++ }
++
++ giop_send_buffer_write(send_buffer);
++ giop_send_buffer_unuse(send_buffer);
++
++ recv_buffer=giop_recv_locate_reply_buffer_use(request_id, TRUE);
++ if(recv_buffer==NULL || recv_buffer->message_buffer.message_header.message_type!=GIOP_LOCATEREPLY) {
++ CORBA_exception_set_system(ev, ex_CORBA_COMM_FAILURE, CORBA_COMPLETED_MAYBE);
++ if(recv_buffer)
++ giop_recv_buffer_unuse(recv_buffer);
++
++ return;
++ }
++
++ ev->_major=CORBA_NO_EXCEPTION;
++ switch(recv_buffer->message.u.locate_reply.locate_status) {
++ case GIOP_UNKNOWN_OBJECT:
++ CORBA_exception_set_system(ev, ex_CORBA_OBJECT_NOT_EXIST, CORBA_COMPLETED_NO);
++ break;
++
++ case GIOP_OBJECT_HERE:
++ /* No further processing necessary */
++ break;
++
++ case GIOP_OBJECT_FORWARD:
++ /* We've been forwarded onto somewhere else. The message body
++ contains the new IOR */
++ if(obj->forward_locations != NULL) {
++ ORBit_delete_profiles(obj->forward_locations);
++ }
++ obj->forward_locations=ORBit_demarshal_IOR(recv_buffer);
++
++ /* This will adjust obj->active_profile */
++ cnx=ORBit_object_get_forwarded_connection(obj);
++ break;
++
++ default:
++ g_message("Bad Reply in ORBit_locate_object()\n");
++ break;
++
++ }
++
++ giop_recv_buffer_unuse(recv_buffer);
++}
++
++GIOPConnection *
++ORBit_handle_location_forward(GIOPRecvBuffer *rb, CORBA_Object obj)
++{
++ GIOPConnection *retval;
++
++ if(obj->forward_locations)
++ ORBit_delete_profiles(obj->forward_locations);
++ obj->forward_locations = ORBit_demarshal_IOR(rb);
++
++ retval = ORBit_object_get_forwarded_connection(obj);
++ giop_recv_buffer_unuse(rb);
++
++ return retval;
++}
+diff -urN linux-2.4.1/net/korbit/orb/orbit_object.h linux-2.4.1-korbit/net/korbit/orb/orbit_object.h
+--- linux-2.4.1/net/korbit/orb/orbit_object.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orbit_object.h Thu Feb 1 16:20:50 2001
+@@ -0,0 +1,114 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter and Red Hat Software
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Phil Dawes <philipd@parallax.co.uk>
++ *
++ */
++
++/*
++ * ORBit specific CORBA_Object funcitons.
++ *
++ */
++#ifndef _ORBIT_ORBIT_OBJECT_H_
++#define _ORBIT_ORBIT_OBJECT_H_
++
++#include <IIOP/IIOP.h>
++#include "corba_object.h"
++
++extern CORBA_Object ORBit_CORBA_Object_new(CORBA_Environment *ev);
++extern void ORBit_CORBA_Object_free(CORBA_Object obj, CORBA_Environment *ev);
++
++
++typedef enum {
++ ORBIT_PSEUDO_ORB,
++ ORBIT_PSEUDO_POA,
++ ORBIT_PSEUDO_POAMANAGER,
++ ORBIT_PSEUDO_POLICY,
++ ORBIT_PSEUDO_TYPECODE,
++ ORBIT_PSEUDO_REQUEST,
++ ORBIT_PSEUDO_SERVERREQUEST,
++ ORBIT_PSEUDO_CONTEXT
++} ORBit_PseudoObject_type;
++typedef struct ORBit_PseudoObject_struct *ORBit_PseudoObject;
++
++void ORBit_pseudo_object_init(ORBit_PseudoObject obj,
++ ORBit_PseudoObject_type obj_type,
++ CORBA_Environment *ev);
++void ORBit_policy_object_init(CORBA_Policy obj,
++ CORBA_PolicyType obj_type,
++ CORBA_Environment *ev);
++
++/* Use ORBit_CORBA_Object_new() */
++void ORBit_object_reference_init(CORBA_Object obj, CORBA_Environment *ev);
++
++typedef struct {
++ CORBA_char *host;
++ CORBA_unsigned_short port;
++} TAG_INTERNET_IOP_info;
++
++typedef struct {
++ CORBA_char *unix_sock_path;
++ CORBA_unsigned_short ipv6_port;
++} TAG_ORBIT_SPECIFIC_info;
++
++typedef struct {
++ int fill_me_in;
++} TAG_MULTIPLE_COMPONENTS_info;
++
++typedef struct {
++ CORBA_octet iiop_major, iiop_minor;
++ IOP_ProfileId profile_type;
++ union {
++ TAG_INTERNET_IOP_info iopinfo;
++ TAG_ORBIT_SPECIFIC_info orbitinfo;
++ TAG_MULTIPLE_COMPONENTS_info mcinfo;
++ } tag;
++
++ /* If the object key is invariant wrt to the various profiles, then
++ this should probably go in CORBA_Object_struct
++ */
++ CORBA_sequence_octet object_key;
++ struct { CORBA_unsigned_long _length; char _buffer[1]; } *object_key_data;
++ struct iovec object_key_vec;
++} ORBit_Object_info;
++
++void ORBit_set_object_key(ORBit_Object_info *info);
++
++CORBA_Object ORBit_create_object_with_info(GSList *profiles,
++ const CORBA_char *type_id,
++ CORBA_ORB orb,
++ CORBA_Environment *ev);
++
++#define ORBit_object_get_connection(obj) \
++ ((obj)->connection && (obj)->connection->is_valid)?((obj)->connection):_ORBit_object_get_connection(obj)
++GIOPConnection *_ORBit_object_get_connection(CORBA_Object obj);
++GIOPConnection *ORBit_object_get_forwarded_connection(CORBA_Object obj);
++void ORBit_object_locate(CORBA_Object obj, CORBA_Environment *ev);
++
++void ORBit_marshal_object(GIOPSendBuffer *send_buffer, CORBA_Object obj);
++CORBA_Object ORBit_demarshal_object(GIOPRecvBuffer *recv_buffer,
++ CORBA_ORB orb);
++GSList *ORBit_demarshal_IOR(GIOPRecvBuffer *recv_buffer);
++
++extern void ORBit_delete_profiles(GSList *profile_list);
++GIOPConnection *ORBit_handle_location_forward(GIOPRecvBuffer *rb, CORBA_Object obj);
++
++#endif /* _ORBIT_ORBIT_OBJECT_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/orbit_object_type.h linux-2.4.1-korbit/net/korbit/orb/orbit_object_type.h
+--- linux-2.4.1/net/korbit/orb/orbit_object_type.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orbit_object_type.h Thu Feb 1 16:20:50 2001
+@@ -0,0 +1,87 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ * Philip Dawes
++ * Elliot Lee <sopwith@redhat.com>
++ *
++ */
++
++#ifndef _ORBIT_ORBIT_OBJECT_TYPE_H_
++#define _ORBIT_ORBIT_OBJECT_TYPE_H_
++
++#include "orbit_object.h"
++
++
++/****** Root object **********/
++/*****************************/
++
++typedef struct ORBit_RootObject_Interface_struct ORBit_RootObject_Interface;
++struct ORBit_RootObject_Interface_struct
++{
++ void (*release)(gpointer obj, CORBA_Environment *ev);
++};
++
++
++
++#define ORBIT_ROOT_OBJECT(x) ((ORBit_RootObject)(x))
++
++
++typedef struct ORBit_RootObject_struct *ORBit_RootObject;
++struct ORBit_RootObject_struct {
++ ORBit_RootObject_Interface* interface; /* the interface */
++
++ guchar is_pseudo_object;
++ gint refs;
++};
++
++
++/* Reference counting interface */
++
++#define ORBIT_ROOT_OBJECT_REF(obj) (ORBIT_ROOT_OBJECT(obj)->refs++)
++#define ORBIT_ROOT_OBJECT_UNREF(obj) (ORBIT_ROOT_OBJECT(obj)->refs--)
++
++
++ /* Virtual function interface*/
++
++#define ORBIT_ROOT_OBJECT_release(obj,ev) \
++(ORBIT_ROOT_OBJECT(obj)->interface->release(obj,ev))
++
++
++
++extern void ORBit_RootObject_set_interface(ORBit_RootObject obj,
++ ORBit_RootObject_Interface* epv,
++ CORBA_Environment *ev);
++
++
++
++/****** Pseudo object --> RootObject ********/
++/*********************************************/
++
++#define ORBIT_PSEUDO_OBJECT(x) ((ORBit_PseudoObject)(x))
++
++struct ORBit_PseudoObject_struct {
++ struct ORBit_RootObject_struct parent;
++ ORBit_PseudoObject_type pseudo_object_type;
++};
++
++
++#endif /* !_ORBIT_CORBA_OBJECT_TYPE_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/orbit_poa.c linux-2.4.1-korbit/net/korbit/orb/orbit_poa.c
+--- linux-2.4.1/net/korbit/orb/orbit_poa.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orbit_poa.c Thu Feb 1 11:47:13 2001
+@@ -0,0 +1,809 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter and Red Hat Software
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Phil Dawes <philipd@parallax.co.uk>
++ * Elliot Lee <sopwith@redhat.com>
++ *
++ */
++
++/*
++ * ORBit specific POA funcitons.
++ *
++ */
++
++#include <string.h>
++#include "orbit.h"
++#include "orbit_poa_type.h"
++#include "orbit_poa.h"
++#include "genrand.h"
++
++#define POA_KEY_LEN (sizeof(CORBA_unsigned_long) + ORBIT_RAND_KEY_LEN)
++#define OBJ_KEY_LEN (sizeof(CORBA_unsigned_long) + ORBIT_RAND_KEY_LEN)
++
++static void ORBit_POAManager_release(PortableServer_POAManager poa_mgr,
++ CORBA_Environment *ev);
++
++static void ORBit_POA_release(PortableServer_POA poa,
++ CORBA_Environment *ev);
++
++static PortableServer_Servant
++ORBit_POA_ServantManager_use_servant(PortableServer_POA poa,
++ GIOPRecvBuffer *recv_buffer,
++ PortableServer_ServantLocator_Cookie *the_cookie,
++ PortableServer_ObjectId *oid,
++ ORBit_POAObject *fake_obj_impl,
++ CORBA_Environment *ev);
++static void
++ORBit_POA_ServantManager_unuse_servant(PortableServer_Servant servant,
++ PortableServer_POA poa,
++ GIOPRecvBuffer *recv_buffer,
++ PortableServer_ServantLocator_Cookie cookie,
++ PortableServer_ObjectId *oid,
++ ORBit_POAObject *fake_obj_impl,
++ CORBA_Environment *ev);
++
++static const ORBit_RootObject_Interface CORBA_POAManager_epv =
++{
++ (void (*)(gpointer, CORBA_Environment *))ORBit_POAManager_release,
++};
++
++static const ORBit_RootObject_Interface CORBA_POA_epv =
++{
++ (void (*)(gpointer, CORBA_Environment *))ORBit_POA_release,
++};
++
++guint
++g_sequence_octet_hash(CORBA_sequence_octet *so)
++{
++ const char *s = (char*)so->_buffer;
++ const char *p, *e = ((char *)so->_buffer) + so->_length;
++ guint h=0, g;
++
++ for(p = s; p < e; p ++) {
++ h = ( h << 4 ) + *p;
++ if ( ( g = h & 0xf0000000 ) ) {
++ h = h ^ (g >> 24);
++ h = h ^ g;
++ }
++ }
++
++ return h;
++}
++
++gint
++g_sequence_octet_compare(CORBA_sequence_octet *s1, CORBA_sequence_octet *s2)
++{
++ if(s2->_length != s1->_length)
++ return FALSE;
++
++ return !memcmp(s1->_buffer, s2->_buffer, s1->_length);
++}
++
++PortableServer_POAManager
++ORBit_POAManager_new(CORBA_Environment *ev)
++{
++ PortableServer_POAManager poa_mgr;
++
++ poa_mgr = g_new0(struct PortableServer_POAManager_type, 1);
++
++ if(poa_mgr == NULL) {
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ goto error;
++ }
++
++ /* Initialise poa manager */
++
++ ORBit_pseudo_object_init(ORBIT_PSEUDO_OBJECT(poa_mgr),
++ ORBIT_PSEUDO_POAMANAGER, ev);
++ ORBIT_ROOT_OBJECT(poa_mgr)->refs = 0;
++ ORBit_RootObject_set_interface(ORBIT_ROOT_OBJECT(poa_mgr),
++ (gpointer)&CORBA_POAManager_epv, ev);
++
++ poa_mgr->poa_collection = NULL;
++ poa_mgr->state = PortableServer_POAManager_HOLDING;
++
++ return poa_mgr;
++
++error:
++ if(poa_mgr != NULL){
++ ORBit_POAManager_release(poa_mgr, ev);
++ }
++ return NULL;
++}
++
++static void
++ORBit_POAManager_release(PortableServer_POAManager poa_mgr,
++ CORBA_Environment *ev)
++{
++
++ if(--(ORBIT_ROOT_OBJECT(poa_mgr)->refs) > 0)
++ return;
++
++ if(poa_mgr != NULL) {
++ if(poa_mgr->poa_collection != NULL) {
++ g_slist_free(poa_mgr->poa_collection);
++ poa_mgr->poa_collection = NULL;
++ }
++ g_free(poa_mgr);
++ poa_mgr = NULL;
++ }
++}
++
++static void
++ORBit_POAManager_register_poa(PortableServer_POAManager poa_mgr,
++ PortableServer_POA poa,
++ CORBA_Environment *ev)
++{
++ poa_mgr->poa_collection = g_slist_remove(poa_mgr->poa_collection, poa);
++ poa_mgr->poa_collection =
++ g_slist_append(poa_mgr->poa_collection, poa);
++}
++
++static void
++ORBit_POAManager_unregister_poa(PortableServer_POAManager poa_mgr,
++ PortableServer_POA poa,
++ CORBA_Environment *ev)
++{
++ poa_mgr->poa_collection = g_slist_remove(poa_mgr->poa_collection, poa);
++}
++
++static void
++ORBit_POA_set_policy(PortableServer_POA poa,
++ CORBA_Policy policy,
++ CORBA_Environment *ev)
++{
++ switch(policy->policy_type) {
++ case PortableServer_THREAD_POLICY_ID:
++ poa->thread = ((PortableServer_ThreadPolicy)policy)->value;
++ break;
++ case PortableServer_LIFESPAN_POLICY_ID:
++ poa->lifespan = ((PortableServer_LifespanPolicy)policy)->value;
++ break;
++ case PortableServer_ID_UNIQUENESS_POLICY_ID:
++ poa->id_uniqueness = ((PortableServer_IdUniquenessPolicy)policy)->value;
++ break;
++ case PortableServer_ID_ASSIGNMENT_POLICY_ID:
++ poa->id_assignment = ((PortableServer_IdAssignmentPolicy)policy)->value;
++ break;
++ case PortableServer_IMPLICIT_ACTIVATION_POLICY_ID:
++ poa->implicit_activation = ((PortableServer_ImplicitActivationPolicy)policy)->value;
++ break;
++ case PortableServer_SERVANT_RETENTION_POLICY_ID:
++ poa->servant_retention = ((PortableServer_ServantRetentionPolicy)policy)->value;
++ break;
++ case PortableServer_REQUEST_PROCESSING_POLICY_ID:
++ poa->request_processing = ((PortableServer_ServantRetentionPolicy)policy)->value;
++ break;
++ default:
++ g_warning("Unknown policy type, cannot set it on this POA");
++ }
++}
++
++
++static void
++ORBit_POA_check_policy_conflicts(PortableServer_POA poa,
++ CORBA_Environment *ev)
++{
++
++ /* Check for those policy combinations that aren't allowed */
++ if ((poa->servant_retention == PortableServer_NON_RETAIN &&
++ poa->request_processing == PortableServer_USE_ACTIVE_OBJECT_MAP_ONLY) ||
++
++ (poa->request_processing == PortableServer_USE_DEFAULT_SERVANT &&
++ poa->id_uniqueness == PortableServer_UNIQUE_ID) ||
++
++ (poa->implicit_activation == PortableServer_IMPLICIT_ACTIVATION &&
++ (poa->id_assignment == PortableServer_USER_ID ||
++ poa->servant_retention == PortableServer_NON_RETAIN))
++ )
++ {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_InvalidPolicy,
++ NULL);
++ }
++}
++
++
++static void
++ORBit_POA_set_policylist(PortableServer_POA poa,
++ CORBA_PolicyList *policies,
++ CORBA_Environment *ev)
++{
++ CORBA_unsigned_long i;
++
++ for(i = 0; i < policies->_length; i++) {
++ if(ev->_major != CORBA_NO_EXCEPTION)
++ break;
++ ORBit_POA_set_policy(poa, policies->_buffer[i], ev);
++ }
++}
++
++PortableServer_POA
++ORBit_POA_new(CORBA_ORB orb,
++ CORBA_char *adapter_name,
++ PortableServer_POAManager the_POAManager,
++ CORBA_PolicyList *policies,
++ CORBA_Environment *ev)
++{
++ PortableServer_POA poa;
++
++ /* Create the object */
++ poa = (PortableServer_POA) g_new0(struct PortableServer_POA_type, 1);
++ if(poa == NULL) {
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ goto error;
++ }
++
++ ORBit_pseudo_object_init(ORBIT_PSEUDO_OBJECT(poa), ORBIT_PSEUDO_POA, ev);
++
++ ORBIT_ROOT_OBJECT(poa)->refs = 0;
++ ORBit_RootObject_set_interface(ORBIT_ROOT_OBJECT(poa),
++ (gpointer)&CORBA_POA_epv, ev);
++
++ if(ev->_major != CORBA_NO_EXCEPTION) goto error;
++
++ /* If no POAManager was specified, create one */
++ if(the_POAManager == NULL) {
++ the_POAManager = ORBit_POAManager_new(ev);
++ }
++
++ /* Register this poa with the poa manager */
++ if(the_POAManager != NULL)
++ ORBit_POAManager_register_poa(the_POAManager,poa,ev);
++ if(ev->_major != CORBA_NO_EXCEPTION) goto error;
++
++ /* Wire up the poa_manager */
++ poa->the_POAManager = the_POAManager;
++
++ /* Initialise the child poas table */
++ poa->child_POAs = NULL; /* initialise the slist */
++
++ poa->held_requests = NULL;
++
++ poa->poaID = orb->poas->len;
++ g_ptr_array_set_size(orb->poas, orb->poas->len + 1);
++ g_ptr_array_index(orb->poas, poa->poaID) = poa;
++
++ poa->orb = orb;
++
++ g_return_val_if_fail(ev->_major == CORBA_NO_EXCEPTION, NULL);
++
++ /* Need to initialise poa policies etc.. here */
++ poa->thread = PortableServer_ORB_CTRL_MODEL;
++ poa->lifespan = PortableServer_TRANSIENT;
++ poa->id_uniqueness = PortableServer_UNIQUE_ID;
++ poa->id_assignment = PortableServer_SYSTEM_ID;
++ poa->servant_retention = PortableServer_RETAIN;
++ poa->request_processing = PortableServer_USE_ACTIVE_OBJECT_MAP_ONLY;
++ poa->implicit_activation = PortableServer_NO_IMPLICIT_ACTIVATION;
++ if (policies) {
++ ORBit_POA_set_policylist(poa, policies, ev);
++ ORBit_POA_check_policy_conflicts(poa, ev);
++ if(ev->_major != CORBA_NO_EXCEPTION) goto error;
++ }
++
++ /* copy the name */
++ poa->the_name = CORBA_string_dup(adapter_name);
++
++ poa->active_object_map = g_hash_table_new((GHashFunc)g_sequence_octet_hash,
++ (GCompareFunc)g_sequence_octet_compare);
++ poa->objnum_to_obj = g_ptr_array_new();
++ g_ptr_array_set_size(poa->objnum_to_obj, 1);
++ g_ptr_array_index(poa->objnum_to_obj, 0) = NULL;
++
++ orbit_genrand(poa->rand_data, ORBIT_RAND_KEY_LEN);
++
++ return poa;
++
++error:
++ if(poa && poa->the_name){
++ CORBA_free(poa->the_name);
++ }
++
++ if(poa != NULL){
++ ORBit_POA_release(poa, NULL);
++ }
++ return NULL;
++}
++
++static void
++ORBit_POA_release(PortableServer_POA poa,
++ CORBA_Environment *ev)
++{
++ ORBIT_ROOT_OBJECT_UNREF(poa);
++
++ if(ORBIT_ROOT_OBJECT(poa)->refs <= 0) {
++ CORBA_free(poa->the_name);
++
++ g_slist_foreach(poa->child_POAs, (GFunc)CORBA_Object_release,
++ ev);
++
++ if(poa->parent_poa)
++ ORBit_POA_remove_child(poa->parent_poa, poa, ev);
++
++ ORBit_POAManager_unregister_poa(poa->the_POAManager,
++ poa, ev);
++
++ g_ptr_array_index(poa->orb->poas, poa->poaID) = NULL;
++
++ g_free(poa);
++ }
++}
++
++void
++ORBit_POA_add_child(PortableServer_POA poa,
++ PortableServer_POA child_poa,
++ CORBA_Environment *ev)
++
++{
++ g_return_if_fail(poa != NULL);
++ g_return_if_fail(child_poa != NULL);
++
++ poa->child_POAs = g_slist_prepend(poa->child_POAs, child_poa);
++}
++
++void
++ORBit_POA_remove_child(PortableServer_POA poa,
++ PortableServer_POA child_poa,
++ CORBA_Environment *ev)
++{
++ g_return_if_fail(poa != NULL);
++ g_return_if_fail(child_poa != NULL);
++
++ poa->child_POAs = g_slist_remove(poa->child_POAs, child_poa);
++}
++
++extern ORBit_request_validate ORBIT_request_validator;
++
++gboolean
++ORBit_POA_handle_request(GIOPRecvBuffer *recv_buffer,
++ PortableServer_POA poa)
++{
++ PortableServer_ServantBase *servant;
++ PortableServer_ServantLocator_Cookie cookie;
++ ORBit_POAObject *obj_impl = NULL, tmp_obj_impl;
++ ORBitSkeleton skel;
++ gpointer imp = NULL;
++ CORBA_Environment ev;
++ GIOPSendBuffer *send_buffer;
++ guchar *opname;
++ PortableServer_ObjectId *oid = NULL;
++
++ CORBA_exception_init(&ev);
++
++ switch(poa->the_POAManager->state) {
++ case PortableServer_POAManager_HOLDING:
++ poa->held_requests = g_slist_prepend(poa->held_requests,
++ recv_buffer);
++ return FALSE;
++ break;
++ case PortableServer_POAManager_DISCARDING:
++ send_buffer = giop_send_reply_buffer_use(GIOP_MESSAGE_BUFFER(recv_buffer)->connection,
++ NULL,
++ recv_buffer->message.u.request.request_id,
++ CORBA_SYSTEM_EXCEPTION);
++ CORBA_exception_set_system(&ev,
++ ex_CORBA_TRANSIENT,
++ CORBA_COMPLETED_NO);
++ ORBit_send_system_exception(send_buffer, &ev);
++ giop_send_buffer_write(send_buffer);
++ giop_recv_buffer_unuse(recv_buffer);
++ giop_send_buffer_unuse(send_buffer);
++ CORBA_exception_free(&ev);
++ return TRUE;
++ break;
++ case PortableServer_POAManager_INACTIVE:
++ send_buffer = giop_send_reply_buffer_use(GIOP_MESSAGE_BUFFER(recv_buffer)->connection,
++ NULL,
++ recv_buffer->message.u.request.request_id,
++ CORBA_SYSTEM_EXCEPTION);
++ CORBA_exception_set_system(&ev,
++ ex_CORBA_OBJ_ADAPTER,
++ CORBA_COMPLETED_NO);
++ ORBit_send_system_exception(send_buffer, &ev);
++ giop_send_buffer_write(send_buffer);
++ giop_recv_buffer_unuse(recv_buffer);
++ giop_send_buffer_unuse(send_buffer);
++ CORBA_exception_free(&ev);
++ return TRUE;
++ break;
++ case PortableServer_POAManager_ACTIVE:
++ default:
++ break;
++ }
++
++ servant = NULL;
++
++ if(recv_buffer->message.u.request.object_key._length
++ < (POA_KEY_LEN + sizeof(CORBA_unsigned_long))) {
++ CORBA_exception_set_system(&ev,
++ ex_CORBA_OBJECT_NOT_EXIST,
++ CORBA_COMPLETED_NO);
++ goto errout;
++ }
++
++ obj_impl = ORBit_POA_find_oid_for_object_key(poa, &(recv_buffer->message.u.request.object_key), &oid);
++
++ if(poa->servant_retention == PortableServer_RETAIN
++ && obj_impl) {
++ servant = obj_impl->servant;
++ oid = obj_impl->object_id;
++ }
++
++ if(!servant) {
++ switch(poa->request_processing) {
++ case PortableServer_USE_SERVANT_MANAGER:
++ servant = ORBit_POA_ServantManager_use_servant(poa,
++ recv_buffer,
++ &cookie,
++ oid,
++ &tmp_obj_impl,
++ &ev);
++ break;
++ case PortableServer_USE_DEFAULT_SERVANT:
++ servant = poa->default_servant;
++ if(servant == NULL) {
++ CORBA_exception_set_system(&ev,
++ ex_CORBA_OBJ_ADAPTER,
++ CORBA_COMPLETED_NO);
++ goto errout;
++ }
++ break;
++ default:
++ break;
++ }
++ }
++
++ if(!poa || !servant || !servant->_private) {
++ CORBA_exception_set_system(&ev,
++ ex_CORBA_OBJECT_NOT_EXIST,
++ CORBA_COMPLETED_NO);
++ goto errout;
++ }
++
++ opname = recv_buffer->message.u.request.operation;
++
++ skel = ORBIT_OBJECT_KEY(servant->_private)->class_info->relay_call(servant, recv_buffer, &imp);
++
++ if(!skel) {
++ if (opname[0] == '_' && strcmp(opname + 1, "is_a") == 0) {
++ skel = (gpointer)&ORBit_impl_CORBA_Object_is_a;
++ }
++ else {
++ CORBA_exception_set_system(&ev, ex_CORBA_BAD_OPERATION,
++ CORBA_COMPLETED_NO);
++ goto errout;
++ }
++ }
++ else if (!imp) {
++ CORBA_exception_set_system(&ev, ex_CORBA_NO_IMPLEMENT,
++ CORBA_COMPLETED_NO);
++ goto errout;
++ }
++
++ /* If it got through the random keys, and nobody else had the opportunity to say otherwise, it must be auth'd */
++
++ if(!ORBIT_request_validator)
++ GIOP_MESSAGE_BUFFER(recv_buffer)->connection->is_auth = TRUE;
++
++ skel(servant, recv_buffer, &ev, imp);
++
++ if(poa->request_processing == PortableServer_USE_SERVANT_MANAGER) {
++ ORBit_POA_ServantManager_unuse_servant(servant,
++ poa,
++ recv_buffer,
++ cookie, oid,
++ &tmp_obj_impl,
++ &ev);
++ }
++
++ if(!obj_impl)
++ CORBA_free(oid);
++
++ CORBA_exception_free(&ev);
++
++ return TRUE;
++
++ errout:
++ if(ev._major == CORBA_SYSTEM_EXCEPTION) {
++ GIOPSendBuffer *reply_buf;
++
++ reply_buf =
++ giop_send_reply_buffer_use(GIOP_MESSAGE_BUFFER(recv_buffer)->connection,
++ NULL,
++ recv_buffer->message.u.request.request_id,
++ CORBA_SYSTEM_EXCEPTION);
++
++ ORBit_send_system_exception(reply_buf, &ev);
++
++ giop_send_buffer_write(reply_buf);
++ giop_send_buffer_unuse(reply_buf);
++ } else /* User exceptions are handled in the skels! */
++ g_assert(ev._major == CORBA_NO_EXCEPTION);
++
++ if(!obj_impl)
++ CORBA_free(oid);
++
++ CORBA_exception_free(&ev);
++
++ return TRUE;
++}
++
++PortableServer_POA
++ORBit_POA_find_POA_for_object_key(PortableServer_POA root_poa,
++ CORBA_sequence_octet *key)
++{
++ CORBA_unsigned_long pid;
++
++ if(key->_length < (sizeof(CORBA_unsigned_long) + ORBIT_RAND_KEY_LEN))
++ return NULL;
++
++ pid = *((CORBA_unsigned_long *)key->_buffer);
++
++ if(pid < root_poa->orb->poas->len) {
++ PortableServer_POA poa;
++ poa = g_ptr_array_index(root_poa->orb->poas, pid);
++ if(!poa)
++ return NULL;
++ if(memcmp(poa->rand_data, key->_buffer + sizeof(CORBA_unsigned_long), ORBIT_RAND_KEY_LEN))
++ return NULL;
++ return poa;
++ } else
++ return NULL;
++}
++
++void
++ORBit_POA_find_object_key_for_oid(PortableServer_POA poa,
++ ORBit_POAObject *obj,
++ PortableServer_ObjectId *oid,
++ CORBA_sequence_octet *retval)
++{
++ CORBA_long *vptr;
++
++ g_return_if_fail(poa && (obj || oid));
++ g_return_if_fail(retval);
++
++ if(oid)
++ g_assert(!oid->_buffer[oid->_length - 1]);
++
++ if(obj)
++ retval->_length = POA_KEY_LEN + OBJ_KEY_LEN;
++ else
++ retval->_length = POA_KEY_LEN + sizeof(CORBA_long) + oid->_length;
++ retval->_buffer = CORBA_octet_allocbuf(retval->_length);
++ CORBA_sequence_set_release(retval, CORBA_TRUE);
++
++ vptr = (CORBA_long *)retval->_buffer;
++ *vptr = poa->poaID;
++ memcpy(retval->_buffer + sizeof(CORBA_unsigned_long), poa->rand_data, ORBIT_RAND_KEY_LEN);
++
++ vptr = (CORBA_long *)(retval->_buffer + POA_KEY_LEN);
++ if(obj) {
++ *vptr = obj->objnum;
++ memcpy(retval->_buffer + POA_KEY_LEN + sizeof(CORBA_unsigned_long), obj->rand_data, ORBIT_RAND_KEY_LEN);
++ } else {
++ *vptr = -((CORBA_long)oid->_length);
++ memcpy(retval->_buffer + POA_KEY_LEN + sizeof(CORBA_unsigned_long), oid->_buffer, oid->_length);
++ }
++}
++
++ORBit_POAObject *
++ORBit_POA_find_oid_for_object_key(PortableServer_POA poa,
++ CORBA_sequence_octet *object_key,
++ PortableServer_ObjectId **oid)
++{
++ CORBA_long onum;
++ guchar *nptr;
++ ORBit_POAObject *objinfo;
++
++ *oid = NULL;
++ nptr = object_key->_buffer + POA_KEY_LEN;
++
++ if(object_key->_length < (POA_KEY_LEN + sizeof(CORBA_long))) {
++ return NULL;
++ }
++
++ onum = *((CORBA_long *)nptr);
++
++ if(onum < 0) {
++ /* onum will be the -strlen(ObjectId) */
++ if(object_key->_length < (POA_KEY_LEN + sizeof(CORBA_long) - onum))
++ return NULL;
++
++ *oid = (PortableServer_ObjectId *)CORBA_sequence_octet__alloc();
++ (*oid)->_length = -onum;
++ (*oid)->_buffer = CORBA_octet_allocbuf((*oid)->_length);
++ memcpy((*oid)->_buffer, object_key->_buffer + POA_KEY_LEN + sizeof(CORBA_long), (*oid)->_length);
++
++ return NULL;
++ }
++
++ if(onum >= poa->objnum_to_obj->len)
++ return NULL;
++
++ objinfo = g_ptr_array_index(poa->objnum_to_obj, onum);
++
++ if(GPOINTER_TO_UINT(objinfo) <= poa->objnum_to_obj->len)
++ return NULL;
++
++ if(object_key->_length < (POA_KEY_LEN + OBJ_KEY_LEN))
++ return NULL;
++
++ if(memcmp(object_key->_buffer + POA_KEY_LEN + sizeof(CORBA_long), objinfo->rand_data, ORBIT_RAND_KEY_LEN))
++ return NULL;
++
++ return objinfo;
++}
++
++DEFINE_LOCK(id_assignment_counter);
++static int id_assignment_counter = 0;
++
++PortableServer_ObjectId *
++ORBit_POA_allocate_oid(PortableServer_POA poa,
++ const char *basis)
++{
++ PortableServer_ObjectId *new_objid;
++ char buf[512];
++ int len;
++
++ new_objid = (PortableServer_ObjectId *)CORBA_sequence_octet__alloc();
++
++ GET_LOCK(id_assignment_counter);
++ g_snprintf(buf, sizeof(buf), "%s%d", basis?basis:"Object",
++ id_assignment_counter);
++ id_assignment_counter++;
++ RELEASE_LOCK(id_assignment_counter);
++
++ len = strlen(buf)+1;
++ new_objid->_buffer = CORBA_octet_allocbuf(len);
++ new_objid->_length = len;
++ new_objid->_maximum = len;
++ new_objid->_release = CORBA_TRUE;
++
++ strcpy((CORBA_char *)new_objid->_buffer, buf);
++
++ return new_objid;
++}
++
++static PortableServer_Servant
++ORBit_POA_ServantManager_use_servant(PortableServer_POA poa,
++ GIOPRecvBuffer *recv_buffer,
++ PortableServer_ServantLocator_Cookie *the_cookie,
++ PortableServer_ObjectId *oid,
++ ORBit_POAObject *fake_obj_impl,
++ CORBA_Environment *ev)
++{
++ if(poa->servant_retention == PortableServer_RETAIN) {
++ POA_PortableServer_ServantActivator *sm;
++ POA_PortableServer_ServantActivator__epv *epv;
++
++ sm = (POA_PortableServer_ServantActivator *)poa->servant_manager;
++ epv = sm->vepv->PortableServer_ServantActivator_epv;
++ return epv->incarnate(sm, oid, poa, ev);
++ } else {
++ POA_PortableServer_ServantLocator *sm;
++ POA_PortableServer_ServantLocator__epv *epv;
++ PortableServer_ServantBase *retval;
++
++ sm = (POA_PortableServer_ServantLocator *)poa->servant_manager;
++ epv = sm->vepv->PortableServer_ServantLocator_epv;
++ retval = epv->preinvoke(sm, oid,
++ poa, recv_buffer->message.u.request.operation,
++ the_cookie,
++ ev);
++
++ ((ORBit_ObjectKey *)retval->_private)->object = fake_obj_impl;
++ fake_obj_impl->object_id = oid;
++ fake_obj_impl->poa = poa;
++ fake_obj_impl->orb = poa->orb;
++ fake_obj_impl->objnum = -1;
++#ifdef NOT_BACKWARDS_COMPAT_0_4
++ fake_obj_impl->use_count = NULL;
++ fake_obj_impl->death_callback = NULL;
++#endif
++
++ return retval;
++ }
++}
++
++static void
++ORBit_POA_ServantManager_unuse_servant(PortableServer_Servant servant,
++ PortableServer_POA poa,
++ GIOPRecvBuffer *recv_buffer,
++ PortableServer_ServantLocator_Cookie cookie,
++ PortableServer_ObjectId *oid,
++ ORBit_POAObject *fake_obj_impl,
++ CORBA_Environment *ev)
++{
++ POA_PortableServer_ServantLocator *sm;
++ POA_PortableServer_ServantLocator__epv *epv;
++
++ if(poa->servant_retention != PortableServer_NON_RETAIN)
++ return;
++
++ sm = (POA_PortableServer_ServantLocator *)poa->servant_manager;
++ epv = sm->vepv->PortableServer_ServantLocator_epv;
++
++ ((ORBit_ObjectKey *)((PortableServer_ServantBase *)servant)->_private)->object = NULL;
++ epv->postinvoke(sm, oid,
++ poa, recv_buffer->message.u.request.operation,
++ cookie, servant, ev);
++
++}
++
++typedef struct {
++ PortableServer_POA poa;
++ CORBA_Environment *ev;
++} EtherealizeInfo;
++
++void
++ORBit_POA_etherealize_object(PortableServer_ObjectId *oid,
++ ORBit_POAObject *obj_impl,
++ EtherealizeInfo *ei)
++{
++ POA_PortableServer_ServantActivator__epv *epv;
++ POA_PortableServer_ServantActivator *sm;
++
++ g_assert(ei->poa->servant_manager);
++
++ g_hash_table_remove(ei->poa->active_object_map,
++ obj_impl->object_id);
++
++ sm = (POA_PortableServer_ServantActivator *)ei->poa->servant_manager;
++ epv = sm->vepv->PortableServer_ServantActivator_epv;
++ epv->etherealize(sm, obj_impl->object_id, ei->poa,
++ obj_impl->servant,
++ CORBA_TRUE, CORBA_FALSE, ei->ev);
++}
++
++void
++ORBit_POA_etherealize_objects(PortableServer_POA poa,
++ CORBA_Environment *ev)
++{
++ EtherealizeInfo ei;
++
++ ei.poa = poa;
++ ei.ev = ev;
++
++ if(poa->servant_retention == PortableServer_RETAIN
++ && poa->request_processing == PortableServer_USE_SERVANT_MANAGER) {
++
++ g_hash_table_foreach(poa->active_object_map,
++ (GHFunc)ORBit_POA_etherealize_object,
++ &ei);
++ }
++}
++
++#ifdef NOT_BACKWARDS_COMPAT_0_4
++void ORBit_servant_set_deathwatch(PortableServer_ServantBase *servant,
++ int *use_count,
++ GFunc death_func,
++ gpointer user_data)
++{
++ ORBit_POAObject *pobj;
++
++ pobj = ORBIT_OBJECT_KEY(servant->_private)->object;
++
++ pobj->use_count = use_count;
++ pobj->death_callback = death_func;
++ pobj->user_data = user_data;
++}
++#endif
+diff -urN linux-2.4.1/net/korbit/orb/orbit_poa.h linux-2.4.1-korbit/net/korbit/orb/orbit_poa.h
+--- linux-2.4.1/net/korbit/orb/orbit_poa.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orbit_poa.h Thu Feb 1 16:20:50 2001
+@@ -0,0 +1,89 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter and Red Hat Software
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Phil Dawes <philipd@parallax.co.uk>
++ *
++ */
++
++/*
++ * ORBit specific POA funcitons.
++ *
++ */
++
++#ifndef _ORBIT_ORBIT_POA_H_
++#define _ORBIT_ORBIT_POA_H_
++
++#include "orbit_types.h"
++#include "orbit_poa_type.h"
++
++/*
++ * Creates a new POAManager
++ */
++
++extern PortableServer_POAManager ORBit_POAManager_new(CORBA_Environment *ev);
++
++extern void ORBit_POAManager_free(PortableServer_POAManager poa_mgr,
++ CORBA_Environment *ev);
++
++extern PortableServer_POA ORBit_POA_new(CORBA_ORB orb,
++ CORBA_char *adapter_name,
++ PortableServer_POAManager the_POAManager,
++ CORBA_PolicyList *policies,
++ CORBA_Environment *ev);
++
++extern void ORBit_POA_free(PortableServer_POA poa, CORBA_Environment *ev);
++
++extern void ORBit_POA_add_child(PortableServer_POA poa,
++ PortableServer_POA child_poa,
++ CORBA_Environment *ev);
++void ORBit_POA_remove_child(PortableServer_POA poa,
++ PortableServer_POA child_poa,
++ CORBA_Environment *ev);
++
++gboolean ORBit_POA_handle_request(GIOPRecvBuffer *recv_buffer,
++ PortableServer_POA poa);
++PortableServer_POA
++ORBit_POA_find_POA_for_object_key(PortableServer_POA root_poa,
++ CORBA_sequence_octet *key);
++void
++ORBit_POA_find_object_key_for_oid(PortableServer_POA poa,
++ ORBit_POAObject *obj,
++ PortableServer_ObjectId *oid,
++ CORBA_sequence_octet *retval);
++ORBit_POAObject *
++ORBit_POA_find_oid_for_object_key(PortableServer_POA poa,
++ CORBA_sequence_octet *object_key,
++ PortableServer_ObjectId **oid);
++
++PortableServer_ObjectId *ORBit_POA_allocate_oid(PortableServer_POA poa,
++ const char *basis);
++
++void ORBit_POA_etherealize_objects(PortableServer_POA poa, CORBA_Environment *ev);
++
++#ifdef NOT_BACKWARDS_COMPAT_0_4
++/* Bad hack for shared libraries */
++void ORBit_servant_set_deathwatch(PortableServer_ServantBase *servant,
++ int *use_count,
++ GFunc death_func,
++ gpointer user_data);
++#endif
++
++#endif /* !_ORBIT_ORBIT_POA_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/orbit_poa_type.h linux-2.4.1-korbit/net/korbit/orb/orbit_poa_type.h
+--- linux-2.4.1/net/korbit/orb/orbit_poa_type.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orbit_poa_type.h Thu Feb 1 11:47:13 2001
+@@ -0,0 +1,112 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter and Red Hat Software
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Phil Dawes <philipd@parallax.co.uk>
++ *
++ */
++
++/*
++ * ORBit specific POA funcitons.
++ *
++ */
++
++#ifndef _ORBIT_ORBIT_POA_TYPE_H_
++#define _ORBIT_ORBIT_POA_TYPE_H_
++
++typedef void (*ORBitSkeleton)(PortableServer_ServantBase *_ORBIT_servant,
++ gpointer _ORBIT_recv_buffer,
++ CORBA_Environment *ev,
++ gpointer implementation);
++typedef ORBitSkeleton (*ORBit_impl_finder)(PortableServer_ServantBase *servant,
++ gpointer _ORBIT_recv_buffer,
++ gpointer *implementation);
++typedef void (*ORBit_local_objref_init)(CORBA_Object obj,
++ PortableServer_ServantBase *servant);
++typedef struct {
++ ORBit_impl_finder relay_call;
++ const gchar *class_name;
++ ORBit_local_objref_init init_local_objref;
++} PortableServer_ClassInfo;
++
++#define ORBIT_RAND_KEY_LEN 8
++
++typedef struct {
++ PortableServer_ObjectId *object_id;
++ PortableServer_Servant servant;
++ PortableServer_POA poa;
++ CORBA_ORB orb;
++ CORBA_unsigned_long objnum;
++
++ /* Stuff for doing shared libraries nicely */
++ guchar rand_data[ORBIT_RAND_KEY_LEN];
++
++#ifdef NOT_BACKWARDS_COMPAT_0_4
++ int *use_count;
++ GFunc death_callback;
++ gpointer user_data;
++#endif
++} ORBit_POAObject;
++
++typedef struct {
++ PortableServer_ClassInfo *class_info;
++ ORBit_POAObject *object;
++} ORBit_ObjectKey;
++
++#define ORBIT_OBJECT_KEY(x) ((ORBit_ObjectKey *)(x))
++
++struct PortableServer_POA_type {
++ struct ORBit_PseudoObject_struct parent;
++
++ PortableServer_POA parent_poa;
++ CORBA_ORB orb;
++ CORBA_unsigned_long poaID;
++
++ GHashTable *active_object_map;
++ GPtrArray *objnum_to_obj; /* maps objnums to ORBit_POAObject's */
++ CORBA_long first_free_id;
++
++ /* Requests received while in a HOLDING state */
++ GSList *held_requests;
++
++ /* this'll be a hash table when I can be arsed to look up
++ how to implement efficient hash tables - Phil.*/
++ GSList *child_POAs;
++
++ CORBA_char *the_name;
++ PortableServer_POAManager the_POAManager;
++
++ PortableServer_AdapterActivator the_activator;
++
++ PortableServer_ServantManager servant_manager;
++ PortableServer_Servant default_servant;
++
++ PortableServer_ThreadPolicyValue thread;
++ PortableServer_LifespanPolicyValue lifespan;
++ PortableServer_IdUniquenessPolicyValue id_uniqueness;
++ PortableServer_IdAssignmentPolicyValue id_assignment;
++ PortableServer_ImplicitActivationPolicyValue implicit_activation;
++ PortableServer_ServantRetentionPolicyValue servant_retention;
++ PortableServer_RequestProcessingPolicyValue request_processing;
++
++ guchar rand_data[ORBIT_RAND_KEY_LEN];
++};
++
++#endif /* !_ORBIT_ORBIT_POA_TYPE_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/orbit_typecode.c linux-2.4.1-korbit/net/korbit/orb/orbit_typecode.c
+--- linux-2.4.1/net/korbit/orb/orbit_typecode.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orbit_typecode.c Thu Feb 1 11:47:14 2001
+@@ -0,0 +1,593 @@
++#include "orbit.h"
++#include "orbit_typecode.h"
++#include "cdr.h"
++#include "corba_typecode_type.h"
++#include <IIOP/giop-msg-buffer.h>
++#include "../IIOP/iiop-endianP.h"
++
++#if 0
++#define CORBA_Object_release(x, y) ({ g_message(__FILE__ ":%d Releasing object %#x from %d", __LINE__, \
++x, ORBIT_ROOT_OBJECT(x)->refs); CORBA_Object_release(x, y); })
++#define CORBA_Object_duplicate(x, y) ({ g_message(__FILE__ ":%d Duping object %#x from %d", __LINE__, \
++x, ORBIT_ROOT_OBJECT(x)->refs); CORBA_Object_duplicate(x, y); })
++#endif
++
++typedef struct{
++ CORBA_TypeCode tc;
++ guint index;
++}TCRecursionNode;
++
++typedef struct{
++ GSList* prior_tcs; /* Could be a hash table by typecode */
++ guint current_idx; /* The "top-level" index of the start of the current codec */
++}TCEncodeContext;
++
++typedef struct{
++ GSList* prior_tcs; /* Could be a hash table by offset */
++ guint current_idx;
++}TCDecodeContext;
++
++
++
++static void tc_enc(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx);
++static void tc_dec(CORBA_TypeCode* t, CDR_Codec* c, TCDecodeContext* ctx);
++static void tc_enc_tk_objref(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx);
++static void tc_dec_tk_objref(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx);
++static void tc_enc_tk_sequence(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx);
++static void tc_dec_tk_sequence(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx);
++static void tc_enc_tk_string(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx);
++static void tc_dec_tk_string(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx);
++static void tc_enc_tk_struct(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx);
++static void tc_dec_tk_struct(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx);
++static void tc_enc_tk_union(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx);
++static void tc_dec_tk_union(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx);
++static void tc_enc_tk_enum(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx);
++static void tc_dec_tk_enum(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx);
++static void tc_enc_tk_alias(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx);
++static void tc_dec_tk_alias(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx);
++static void tc_enc_tk_except(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx);
++static void tc_dec_tk_except(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx);
++static void tc_enc_tk_array(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx);
++static void tc_dec_tk_array(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx);
++static void tc_enc_tk_fixed(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx);
++static void tc_dec_tk_fixed(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx);
++static void tc_enc_tk_wstring(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx);
++static void tc_dec_tk_wstring(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx);
++
++
++
++typedef void
++(*CORBA_TypeCodeEncoder)(CORBA_TypeCode t,
++ CDR_Codec* c,
++ TCEncodeContext* ctx);
++
++typedef void
++(*CORBA_TypeCodeDecoder)(CORBA_TypeCode t,
++ CDR_Codec* c,
++ TCDecodeContext* ctx);
++
++
++typedef enum{
++ TK_EMPTY,
++ TK_SIMPLE,
++ TK_COMPLEX
++} TkType;
++
++typedef struct{
++ TkType type;
++ CORBA_TypeCodeEncoder encoder;
++ CORBA_TypeCodeDecoder decoder;
++} TkInfo;
++
++static const TkInfo tk_info[CORBA_tk_last]={
++ {TK_EMPTY, NULL, NULL}, /* tk_null */
++ {TK_EMPTY, NULL, NULL}, /* tk_void */
++ {TK_EMPTY, NULL, NULL}, /* tk_short */
++ {TK_EMPTY, NULL, NULL}, /* tk_long */
++ {TK_EMPTY, NULL, NULL}, /* tk_ushort */
++ {TK_EMPTY, NULL, NULL}, /* tk_ulong */
++ {TK_EMPTY, NULL, NULL}, /* tk_float */
++ {TK_EMPTY, NULL, NULL}, /* tk_double */
++ {TK_EMPTY, NULL, NULL}, /* tk_boolean */
++ {TK_EMPTY, NULL, NULL}, /* tk_char */
++ {TK_EMPTY, NULL, NULL}, /* tk_octet */
++ {TK_EMPTY, NULL, NULL}, /* tk_any */
++ {TK_EMPTY, NULL, NULL}, /* tk_TypeCode */
++ {TK_EMPTY, NULL, NULL}, /* tk_Principal */
++ {TK_COMPLEX, tc_enc_tk_objref, tc_dec_tk_objref}, /* tk_objref */
++ {TK_COMPLEX, tc_enc_tk_struct, tc_dec_tk_struct}, /* tk_struct */
++ {TK_COMPLEX, tc_enc_tk_union, tc_dec_tk_union}, /* tk_union */
++ {TK_COMPLEX, tc_enc_tk_enum, tc_dec_tk_enum}, /* tk_enum */
++ {TK_SIMPLE, tc_enc_tk_string, tc_dec_tk_string}, /* tk_string */
++ {TK_COMPLEX, tc_enc_tk_sequence, tc_dec_tk_sequence}, /* tk_sequence */
++ {TK_COMPLEX, tc_enc_tk_array, tc_dec_tk_array}, /* tk_array */
++ {TK_COMPLEX, tc_enc_tk_alias, tc_dec_tk_alias}, /* tk_alias */
++ {TK_COMPLEX, tc_enc_tk_except, tc_dec_tk_except}, /* tk_except */
++ {TK_EMPTY, NULL, NULL}, /* tk_longlong */
++ {TK_EMPTY, NULL, NULL}, /* tk_ulonglong */
++ {TK_EMPTY, NULL, NULL}, /* tk_longdouble */
++ {TK_EMPTY, NULL, NULL}, /* tk_wchar */
++ {TK_SIMPLE, tc_enc_tk_wstring, tc_dec_tk_wstring}, /* tk_wstring */
++ {TK_SIMPLE, tc_enc_tk_fixed, tc_dec_tk_fixed} /* tk_fixed */
++};
++
++void ORBit_encode_CORBA_TypeCode(CORBA_TypeCode t, GIOPSendBuffer* buf)
++{
++ CDR_Codec codec_d;
++ CDR_Codec* codec = &codec_d;
++ TCEncodeContext ctx;
++ GSList* l;
++ CORBA_octet codecbuf[2048];
++
++ CDR_codec_init_static(codec);
++
++ codec->wptr = 0;
++ codec->buffer = codecbuf;
++ codec->release_buffer = FALSE;
++ codec->buf_len = 2048;
++ codec->data_endian=FLAG_ENDIANNESS;
++
++ ctx.current_idx=0;
++ ctx.prior_tcs=NULL;
++ tc_enc(t, codec, &ctx);
++ for(l=ctx.prior_tcs;l;l=l->next)
++ g_free(l->data);
++ g_slist_free(ctx.prior_tcs);
++ giop_send_buffer_append_mem_indirect(buf,
++ codec->buffer,
++ codec->wptr);
++}
++
++void ORBit_decode_CORBA_TypeCode(CORBA_TypeCode* t, GIOPRecvBuffer* buf)
++{
++ CDR_Codec codec_d;
++ CDR_Codec* codec = &codec_d;
++ TCDecodeContext ctx;
++ GSList* l;
++
++ CDR_codec_init_static(codec);
++ codec->buffer=buf->cur;
++ codec->release_buffer=CORBA_FALSE;
++ codec->readonly=CORBA_TRUE;
++ codec->buf_len = /* hope this is correct */
++ ((guchar *)buf->message_body) +
++ GIOP_MESSAGE_BUFFER(buf)->message_header.message_size
++ - ((guchar *)buf->cur);
++
++ codec->data_endian=GIOP_MESSAGE_BUFFER(buf)->message_header.flags & 1;
++
++ ctx.current_idx=0;
++ ctx.prior_tcs=NULL;
++ tc_dec(t, codec, &ctx);
++ for(l=ctx.prior_tcs;l;l=l->next)
++ g_free(l->data);
++ g_slist_free(ctx.prior_tcs);
++ buf->cur = ((guchar *)buf->cur) + codec->rptr;
++}
++
++
++/* Encode a typecode to a codec, possibly recursively */
++
++static void tc_enc(CORBA_TypeCode tc,
++ CDR_Codec* codec,
++ TCEncodeContext* ctx)
++{
++ TCRecursionNode* node;
++ const TkInfo* info;
++ GSList* l;
++ CORBA_octet codecbuf[2048];
++ CDR_Codec encaps_d;
++ CDR_Codec* encaps = &encaps_d;
++
++ g_assert(CLAMP(0, tc->kind, CORBA_tk_last) == tc->kind);
++
++ for(l=ctx->prior_tcs;l;l=l->next){
++ TCRecursionNode* node=l->data;
++ /* CORBA_CORBA_TypeCode_equal might save space, but is slow.. */
++ if(node->tc==tc){
++ CDR_put_ulong(codec, CORBA_tk_recursive);
++ CDR_put_long(codec,
++ node->index
++ -ctx->current_idx
++ -codec->wptr);
++ return;
++ }
++ }
++
++ /* All right, this isn't a previously met type. So record it. */
++ /* NOTE: put kind before recording index so alignment is dealt with! */
++ CDR_put_ulong(codec, tc->kind);
++
++ node=g_new(TCRecursionNode, 1);
++ node->tc=tc;
++ node->index=ctx->current_idx+codec->wptr - 4; /* -4 for kind */
++ ctx->prior_tcs=g_slist_prepend(ctx->prior_tcs, node);
++
++ info=&tk_info[tc->kind];
++ switch(info->type){
++ guint tmp_index;
++ case TK_EMPTY:
++ break;
++ case TK_COMPLEX:
++ tmp_index=ctx->current_idx;
++ ctx->current_idx+=codec->wptr+4; /* +4 for the length */
++ CDR_codec_init_static(encaps);
++ encaps->wptr = 0;
++ encaps->buffer = codecbuf;
++ encaps->release_buffer = FALSE;
++ encaps->buf_len = 2048;
++ encaps->data_endian=FLAG_ENDIANNESS;
++ CDR_put_octet(encaps, FLAG_ENDIANNESS);
++ (info->encoder)(tc, encaps, ctx);
++ CDR_put_ulong(codec, encaps->wptr);
++ /* Now this is a time hog */
++ CDR_put_octets(codec, encaps->buffer, encaps->wptr);
++ ctx->current_idx=tmp_index;
++ break;
++ case TK_SIMPLE:
++ (info->encoder)(tc, codec, ctx);
++ }
++}
++
++static void
++ORBit_TypeCode_release(gpointer obj, CORBA_Environment *ev)
++{
++ /* we will initialize the TC_ constants with a negative refcount */
++ if(ORBIT_ROOT_OBJECT(obj)->refs >= 0) {
++ ORBIT_ROOT_OBJECT_UNREF(obj);
++
++ if(ORBIT_ROOT_OBJECT(obj)->refs <= 0) {
++ CORBA_TypeCode tc = obj;
++ int i;
++
++ g_free(tc->name);
++ g_free(tc->repo_id);
++
++ for(i = 0; i < tc->sub_parts; i++) {
++ if(tc->subnames)
++ g_free(tc->subnames[i]);
++
++ if(tc->subtypes)
++ CORBA_Object_release((CORBA_Object)tc->subtypes[i], ev);
++
++ if(tc->sublabels)
++ CORBA_any__free(&tc->sublabels[i], NULL, TRUE);
++ }
++
++ g_free(tc->subnames);
++ g_free(tc->subtypes);
++ g_free(tc->sublabels);
++
++ if(tc->discriminator)
++ CORBA_Object_release((CORBA_Object)tc->discriminator, ev);
++
++ g_free(obj);
++ }
++
++ }
++}
++
++const ORBit_RootObject_Interface ORBit_TypeCode_epv = {
++ &ORBit_TypeCode_release
++};
++
++static void tc_dec(CORBA_TypeCode* t, CDR_Codec* c, TCDecodeContext* ctx)
++{
++ CORBA_TCKind kind;
++ CORBA_TypeCode tc;
++ const TkInfo* info;
++ TCRecursionNode* node;
++ CDR_Codec encaps_d;
++ CDR_Codec* encaps = &encaps_d;
++
++ CDR_get_ulong(c, &kind);
++
++ g_assert(CLAMP(0, kind, CORBA_tk_last) == kind);
++
++ if(kind==CORBA_tk_recursive){
++ CORBA_long offset;
++ GSList* l;
++ CDR_get_ulong(c, &offset);
++ for(l=ctx->prior_tcs;l;l=l->next){
++ node=l->data;
++ /* NOTE: below, -4 is b/c we already read offset */
++ if(node->index==ctx->current_idx+c->rptr+offset-4){
++ *t=node->tc;
++ return;
++ }
++ }
++ ORBit_Trace(TraceMod_ORB, TraceLevel_Error,
++ "tc_dec: Invalid CORBA_TypeCode recursion offset "
++ "in input buffer\n");
++ g_assert_not_reached();
++ }
++
++ ORBit_Trace(TraceMod_TC, TraceLevel_Debug, "codec->host_endian: %d, codec->data_endian: %d\n", c->host_endian, c->data_endian);
++ ORBit_Trace(TraceMod_TC, TraceLevel_Debug, "kind: %d, CORBA_tk_last: %d\n", kind, CORBA_tk_last);
++ g_assert(kind<CORBA_tk_last);
++
++ node=g_new(TCRecursionNode, 1);
++ node->index=ctx->current_idx+c->rptr-4; /* -4 for the TCKind */
++ info=&tk_info[kind];
++
++ tc=g_new0(struct CORBA_TypeCode_struct, 1);
++
++ /* Passing in NULL for CORBA_Environment is patently dangerous. */
++ ORBit_pseudo_object_init((ORBit_PseudoObject)tc,
++ ORBIT_PSEUDO_TYPECODE, NULL);
++ ORBit_RootObject_set_interface((ORBit_RootObject)tc,
++ (ORBit_RootObject_Interface *)&ORBit_TypeCode_epv,
++ NULL);
++
++ tc->kind=kind;
++ switch(info->type){
++ guint tmp_index;
++ CORBA_octet o;
++
++ case TK_EMPTY:
++ break;
++
++ case TK_COMPLEX:
++ tmp_index=ctx->current_idx;
++ CDR_codec_init_static(encaps);
++ CDR_get_ulong(c, &encaps->buf_len);
++ ctx->current_idx+=c->rptr;
++ encaps->buffer=&c->buffer[c->rptr];
++ encaps->release_buffer=CORBA_FALSE;
++ CDR_get_octet(encaps, &o);
++ encaps->data_endian=o;
++ (info->decoder)(tc, encaps, ctx);
++ c->rptr += encaps->buf_len;
++ ctx->current_idx=tmp_index;
++ break;
++ case TK_SIMPLE:
++ (info->decoder)(tc, c, ctx);
++ break;
++ }
++ node->tc=tc;
++ ctx->prior_tcs=g_slist_prepend(ctx->prior_tcs, node);
++ *t=tc;
++}
++
++
++
++static void tc_enc_tk_objref(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx)
++{
++ CDR_put_string(c, t->repo_id);
++ CDR_put_string(c, t->name);
++}
++
++static void tc_dec_tk_objref(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx)
++{
++ CDR_get_string(c, &t->repo_id);
++ CDR_get_string(c, &t->name);
++}
++
++static void tc_enc_tk_sequence(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx)
++{
++ tc_enc(*t->subtypes, c, ctx);
++ CDR_put_ulong(c, t->length);
++}
++
++static void tc_dec_tk_sequence(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx)
++{
++ t->subtypes=g_new(CORBA_TypeCode, 1);
++ tc_dec(&t->subtypes[0], c, ctx);
++ CORBA_Object_duplicate((CORBA_Object)t->subtypes[0], NULL);
++ CDR_get_ulong(c, &t->length);
++}
++
++static void tc_enc_tk_string(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx)
++{
++ CDR_put_ulong(c, t->length);
++}
++
++static void tc_dec_tk_string(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx)
++{
++ CDR_get_ulong(c, &t->length);
++}
++
++static void tc_enc_tk_struct(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx)
++{
++ CORBA_unsigned_long i;
++ CDR_put_string(c, t->repo_id);
++ CDR_put_string(c, t->name);
++ CDR_put_ulong(c, t->sub_parts);
++ for(i=0;i<t->sub_parts;i++){
++ CDR_put_string(c, t->subnames[i]);
++ tc_enc(t->subtypes[i], c, ctx);
++ }
++}
++
++static void tc_dec_tk_struct(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx)
++{
++ CORBA_unsigned_long i;
++ CDR_get_string(c, &t->repo_id);
++ CDR_get_string(c, &t->name);
++ CDR_get_ulong(c, &t->sub_parts);
++ t->subnames=g_new(gchar*, t->sub_parts);
++ t->subtypes=g_new(CORBA_TypeCode, t->sub_parts);
++ for(i=0;i<t->sub_parts;i++){
++ CDR_get_string(c, &t->subnames[i]);
++ tc_dec(&t->subtypes[i], c, ctx);
++ CORBA_Object_duplicate((CORBA_Object)t->subtypes[i], NULL);
++ }
++}
++
++#define UNION_MEMBERS(dir) \
++ MEMBER_LOOPER_##dir(ulong, long, long); \
++ case CORBA_tk_enum: /* fall through */ \
++ MEMBER_LOOPER_##dir(ulong, unsigned_long, ulong); \
++ MEMBER_LOOPER_##dir(octet, boolean, boolean); \
++ MEMBER_LOOPER_##dir(octet, char, char); \
++ MEMBER_LOOPER_##dir(ushort, short, short); \
++ MEMBER_LOOPER_##dir(ushort, unsigned_short, ushort); \
++ MEMBER_LOOPER_##dir(ulong_long, long_long, longlong); \
++ MEMBER_LOOPER_##dir(ulong_long, unsigned_long_long, ulonglong); \
++ /* MEMBER_LOOPER_##dir(wchar, wchar, wchar); */
++
++
++static void tc_enc_tk_union(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx)
++{
++ CORBA_unsigned_long i;
++ CDR_put_string(c, t->repo_id);
++ CDR_put_string(c, t->name);
++ tc_enc(t->discriminator, c, ctx);
++ CDR_put_long(c, t->default_index);
++ CDR_put_ulong(c, t->sub_parts);
++ i=t->sub_parts;
++ /* Thank goodness the discriminator types are rather limited,
++ we can do the marshalling inline.. */
++#define MEMBER_LOOPER_ENC(putname, typename, tkname) \
++ case CORBA_tk_##tkname: \
++ for(i=0;i<t->sub_parts;i++){ \
++ CDR_put_##putname(c, *(CORBA_##typename*) \
++ (t->sublabels[i]._value)); \
++ CDR_put_string(c, t->subnames[i]); \
++ tc_enc(t->subtypes[i], c, ctx); \
++ } \
++ break
++
++ switch(t->discriminator->kind){
++ UNION_MEMBERS(ENC);
++ default:
++ ORBit_Trace(TraceMod_ORB, TraceLevel_Error,
++ "tc_enc_tk_union: Illegal union discriminator "
++ "type %s\n", t->discriminator->name);
++ }
++}
++
++static void tc_dec_tk_union(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx)
++{
++ CORBA_unsigned_long i;
++ CDR_get_string(c, &t->repo_id);
++ CDR_get_string(c, &t->name);
++ tc_dec(&t->discriminator, c, ctx);
++ CORBA_Object_duplicate((CORBA_Object)t->discriminator, NULL);
++ CDR_get_ulong(c, &t->default_index);
++ CDR_get_ulong(c, &t->sub_parts);
++
++ t->sublabels=g_new(CORBA_any, t->sub_parts);
++ t->subnames=g_new(gchar*, t->sub_parts);
++ t->subtypes=g_new(CORBA_TypeCode, t->sub_parts);
++
++#define MEMBER_LOOPER_DEC(getname, typename, tkname) \
++ case CORBA_tk_##tkname: \
++ for(i=0;i<t->sub_parts;i++){ \
++ t->sublabels[i]._type = \
++ CORBA_Object_duplicate((CORBA_Object)t->discriminator, NULL); \
++ t->sublabels[i]._value = g_new(CORBA_##typename,1); \
++ t->sublabels[i]._release = CORBA_TRUE; \
++ CDR_get_##getname(c, t->sublabels[i]._value); \
++ CDR_get_string(c, &t->subnames[i]); \
++ tc_dec(&t->subtypes[i], c, ctx); \
++ CORBA_Object_duplicate((CORBA_Object)t->subtypes[i], NULL); \
++ } \
++ break
++
++ switch(t->discriminator->kind){
++ UNION_MEMBERS(DEC);
++ default:
++ /* XXX: what is correct error handling */
++ g_assert(!"Not yet implemented.");
++ }
++}
++
++static void tc_enc_tk_enum(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx)
++{
++ CORBA_unsigned_long i;
++ CDR_put_string(c, t->repo_id);
++ CDR_put_string(c, t->name);
++ CDR_put_ulong(c, t->sub_parts);
++ for(i=0;i<t->sub_parts;i++)
++ CDR_put_string(c, t->subnames[i]);
++}
++
++static void tc_dec_tk_enum(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx)
++{
++ CORBA_unsigned_long i;
++ CDR_get_string(c, &t->repo_id);
++ CDR_get_string(c, &t->name);
++ CDR_get_ulong(c, &t->sub_parts);
++ t->subnames=g_new(gchar*, t->sub_parts);
++ for(i=0;i<t->sub_parts;i++)
++ CDR_get_string(c, &t->subnames[i]);
++}
++
++static void tc_enc_tk_alias(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx)
++{
++ CDR_put_string(c, t->repo_id);
++ CDR_put_string(c, t->name);
++ tc_enc(*t->subtypes, c, ctx);
++}
++
++static void tc_dec_tk_alias(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx)
++{
++ CDR_get_string(c, &t->repo_id);
++ CDR_get_string(c, &t->name);
++ t->subtypes=g_new(CORBA_TypeCode, 1);
++ tc_dec(t->subtypes, c, ctx);
++ CORBA_Object_duplicate((CORBA_Object)t->subtypes[0], NULL);
++}
++
++
++static void tc_enc_tk_except(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx)
++{
++ gulong i;
++ CDR_put_string(c, t->repo_id);
++ CDR_put_string(c, t->name);
++ CDR_put_ulong(c, t->sub_parts);
++ for(i=0;i<t->length;i++){
++ CDR_put_string(c, t->subnames[i]);
++ tc_enc(t->subtypes[i], c, ctx);
++ }
++}
++
++static void tc_dec_tk_except(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx)
++{
++ gulong i;
++ CDR_get_string(c, &t->repo_id);
++ CDR_get_string(c, &t->name);
++ CDR_get_ulong(c, &t->sub_parts);
++ t->subtypes=g_new(CORBA_TypeCode, t->sub_parts);
++ t->subnames=g_new(gchar*, t->sub_parts);
++ for(i=0;i<t->length;i++){
++ CDR_get_string(c, &t->subnames[i]);
++ tc_dec(&t->subtypes[i], c, ctx);
++ CORBA_Object_duplicate((CORBA_Object)t->subtypes[i], NULL);
++ }
++}
++
++static void tc_enc_tk_array(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx)
++{
++ tc_enc(*t->subtypes, c, ctx);
++ CDR_put_ulong(c, t->length);
++}
++
++static void tc_dec_tk_array(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx)
++{
++ t->subtypes=g_new(CORBA_TypeCode, 1);
++ tc_dec(t->subtypes, c, ctx);
++ CORBA_Object_duplicate((CORBA_Object)t->subtypes[0], NULL);
++ CDR_get_ulong(c, &t->length);
++}
++
++static void tc_enc_tk_wstring(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx)
++{
++ g_assert(!"Not yet implemented.");
++}
++
++static void tc_dec_tk_wstring(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx)
++{
++ g_assert(!"Not yet implemented.");
++}
++
++static void tc_enc_tk_fixed(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx)
++{
++ g_assert(!"Not yet implemented.");
++}
++
++static void tc_dec_tk_fixed(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx)
++{
++ g_assert(!"Not yet implemented.");
++}
+diff -urN linux-2.4.1/net/korbit/orb/orbit_typecode.h linux-2.4.1-korbit/net/korbit/orb/orbit_typecode.h
+--- linux-2.4.1/net/korbit/orb/orbit_typecode.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orbit_typecode.h Thu Feb 1 16:21:53 2001
+@@ -0,0 +1,10 @@
++#ifndef _ORBIT_ORBIT_TYPECODE_H_
++#define _ORBIT_ORBIT_TYPECODE_H_
++
++#include "orbit_types.h"
++
++extern const ORBit_RootObject_Interface ORBit_TypeCode_epv;
++void ORBit_encode_CORBA_TypeCode(CORBA_TypeCode tc, GIOPSendBuffer* buf);
++void ORBit_decode_CORBA_TypeCode(CORBA_TypeCode* tc, GIOPRecvBuffer* buf);
++
++#endif
+diff -urN linux-2.4.1/net/korbit/orb/orbit_types.h linux-2.4.1-korbit/net/korbit/orb/orbit_types.h
+--- linux-2.4.1/net/korbit/orb/orbit_types.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orbit_types.h Thu Feb 1 16:20:50 2001
+@@ -0,0 +1,176 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter and Red Hat Software
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_TYPES_H_
++#define _ORBIT_TYPES_H_
++
++#include <stddef.h> /* for wchar_t */
++#include <sys/types.h> /* for sysdep types */
++#include <netinet/in.h> /* for sockaddr_in */
++#include <sys/uio.h> /* for struct iovec */
++
++#include <ORBitutil/basic_types.h>
++
++#define CORBA_TRUE 1
++#define CORBA_FALSE 0
++
++typedef CORBA_char *CORBA_ORBid;
++
++typedef CORBA_unsigned_long CORBA_ServiceOption;
++typedef CORBA_unsigned_long CORBA_ServiceDetailType;
++
++#include "corba_orb.h"
++
++/*
++ * CORBA_RepositoryId and CORBA_Identifier are defined in the Interface
++ * Repository, but are needed in other interfaces in the ORB itself.
++ */
++#if !defined(_CORBA_Identifier_defined)
++#define _CORBA_Identifier_defined 1
++typedef CORBA_char *CORBA_Identifier;
++#define CORBA_Identifier__free CORBA_string__free
++#endif
++
++#if !defined(_CORBA_RepositoryId_defined)
++#define _CORBA_RepositoryId_defined 1
++typedef CORBA_char *CORBA_RepositoryId;
++#define CORBA_RepositoryId__free CORBA_string__free
++#endif
++
++#include "corba_any.h"
++
++typedef struct CORBA_ServiceDetail_type CORBA_ServiceDetail;
++typedef struct CORBA_Request_type *CORBA_Request;
++typedef struct CORBA_ServerRequest_type *CORBA_ServerRequest;
++typedef struct CORBA_DynFixed_type *CORBA_DynFixed;
++typedef struct CORBA_Current_type *CORBA_Current;
++typedef void CORBA_Status;
++typedef CORBA_unsigned_long CORBA_enum;
++typedef CORBA_unsigned_long CORBA_Flags;
++
++typedef struct CORBA_NVList_type {
++ CORBA_Flags flags;
++ GArray *list;
++} CORBA_NVList;
++
++#include "corba_context.h"
++
++#include "corba_portableserver.h"
++
++#include "corba_env.h"
++
++#include "corba_sequences_type.h"
++
++#include "corba_basic_sequences_type.h"
++
++#include "corba_object.h"
++
++#include "orbit_object_type.h"
++
++#include "corba_object_type.h"
++
++#include "corba_orb_type.h"
++
++#include "corba_typecode.h"
++#include "corba_typecode_type.h"
++#include "corba_any_type.h"
++#include "corba_any_proto.h"
++
++#if !defined(TC_IMPL_TC_CORBA_Identifier_0)
++#define TC_IMPL_TC_CORBA_Identifier_0 '/'
++#define TC_CORBA_Identifier ((CORBA_TypeCode)&TC_CORBA_Identifier_struct)
++extern const struct CORBA_TypeCode_struct TC_CORBA_Identifier_struct;
++#endif
++
++#if !defined(TC_IMPL_TC_CORBA_RepositoryId_0)
++#define TC_IMPL_TC_CORBA_RepositoryId_0 '/'
++extern const struct CORBA_TypeCode_struct TC_CORBA_RepositoryId_struct;
++#define TC_CORBA_RepositoryId ((CORBA_TypeCode)&TC_CORBA_RepositoryId_struct)
++#endif
++
++/* 19.14 */
++
++/* XXX */
++typedef struct CORBA_fixed_d_s {
++ CORBA_unsigned_short _digits;
++ CORBA_short _scale;
++ signed char _sign;
++ signed char _value[1];
++} CORBA_fixed_d_s;
++
++#include "corba_env_type.h"
++
++
++typedef struct CORBA_WrongTransaction {
++ int dummy;
++} CORBA_WrongTransaction;
++
++#define CORBA_ARG_IN (1<<0)
++#define CORBA_ARG_OUT (1<<1)
++#define CORBA_ARG_INOUT (1<<2)
++#define CORBA_CTX_RESTRICT_SCOPE (1<<3)
++#define CORBA_CTX_DELETE_DESCENDENTS (1<<4)
++#define CORBA_OUT_LIST_MEMORY (1<<5)
++#define CORBA_IN_COPY_VALUE (1<<6)
++#define CORBA_DEPENDENT_LIST (1<<7)
++#define CORBA_INV_NO_RESPONSE (1<<8)
++#define CORBA_INV_TERM_ON_ERROR (1<<9)
++#define CORBA_RESP_NO_WAIT (1<<10)
++
++typedef struct CORBA_NamedValue {
++ CORBA_Identifier name; /* argument name */
++ CORBA_any argument; /* argument */
++ CORBA_long len; /* length/count of argument value */
++ CORBA_Flags arg_modes; /* argument mode flags */
++} CORBA_NamedValue;
++
++typedef CORBA_char *CORBA_FieldName;
++
++typedef struct CORBA_NameValuePair {
++ CORBA_FieldName id;
++ CORBA_any value;
++} CORBA_NameValuePair;
++
++struct CORBA_Current_type {
++ int fill_me_in;
++};
++
++#include "corba_portableserver_type.h"
++
++typedef CORBA_unsigned_short CORBA_ServiceType;
++
++#define CORBA_Security (1)
++
++struct CORBA_ServiceDetail_type {
++ CORBA_ServiceDetailType service_detail_type;
++ CORBA_sequence_octet service_detail;
++};
++
++typedef struct CORBA_ServiceInformation_struct {
++ CORBA_sequence_ServiceOption service_options;
++ CORBA_sequence_ServiceDetail service_details;
++} CORBA_ServiceInformation;
++
++#endif /* !_ORBIT_TYPES_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/poa.c linux-2.4.1-korbit/net/korbit/orb/poa.c
+--- linux-2.4.1/net/korbit/orb/poa.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/poa.c Thu Feb 1 11:47:14 2001
+@@ -0,0 +1,1387 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter, and Red Hat Software
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ * Elliot Lee <sopwith@redhat.com>
++ *
++ */
++
++#include <string.h>
++#include <stdio.h>
++#include <assert.h>
++
++#include "orbit.h"
++#include "orbit_poa.h"
++#include "genrand.h"
++
++PortableServer_ThreadPolicyValue
++PortableServer_ThreadPolicy__get_value(PortableServer_ThreadPolicy obj, CORBA_Environment *ev)
++{
++ if(!obj) {
++ ev->_major = 2 ;
++ goto error_exit;
++ }
++ ev->_major = CORBA_NO_EXCEPTION;
++
++ return obj->value;
++
++error_exit:
++ CORBA_exception_set_system(ev, 0, CORBA_COMPLETED_NO);
++ return 0;
++}
++
++PortableServer_LifespanPolicyValue
++PortableServer_LifespanPolicy__get_value(PortableServer_LifespanPolicy obj, CORBA_Environment *ev)
++{
++ if(!obj) {
++ ev->_major = 2 ;
++ goto error_exit;
++ }
++
++ ev->_major = CORBA_NO_EXCEPTION;
++ return obj->value;
++
++error_exit:
++ CORBA_exception_set_system(ev, 0, CORBA_COMPLETED_NO);
++ return 0;
++}
++
++PortableServer_IdUniquenessPolicyValue
++PortableServer_IdUniquenessPolicy__get_value(PortableServer_IdUniquenessPolicy obj, CORBA_Environment *ev)
++{
++ if(!obj) {
++ ev->_major = 2 ;
++ goto error_exit;
++ }
++
++ ev->_major = CORBA_NO_EXCEPTION;
++ return obj->value;
++
++error_exit:
++ CORBA_exception_set_system(ev, 0, CORBA_COMPLETED_NO);
++ return 0;
++}
++
++PortableServer_IdAssignmentPolicyValue
++PortableServer_IdAssignmentPolicy__get_value(PortableServer_IdAssignmentPolicy obj, CORBA_Environment *ev)
++{
++ if(!obj) {
++ ev->_major = 2 ;
++ goto error_exit;
++ }
++
++ ev->_major = CORBA_NO_EXCEPTION;
++ return obj->value;
++
++error_exit:
++ CORBA_exception_set_system(ev, 0, CORBA_COMPLETED_NO);
++ return 0;
++}
++
++PortableServer_ImplicitActivationPolicyValue
++PortableServer_ImplicitActivationPolicy__get_value(PortableServer_ImplicitActivationPolicy obj, CORBA_Environment *ev)
++{
++ if(!obj) {
++ ev->_major = 2 ;
++ goto error_exit;
++ }
++
++ ev->_major = CORBA_NO_EXCEPTION;
++ return obj->value;
++
++error_exit:
++ CORBA_exception_set_system(ev, 0, CORBA_COMPLETED_NO);
++ return 0;
++}
++
++PortableServer_ServantRetentionPolicyValue
++PortableServer_ServantRetentionPolicy__get_value(PortableServer_ServantRetentionPolicy obj, CORBA_Environment *ev)
++{
++ if(!obj) {
++ ev->_major = 2 ;
++ goto error_exit;
++ }
++
++ ev->_major = CORBA_NO_EXCEPTION;
++ return obj->value;
++
++error_exit:
++ CORBA_exception_set_system(ev, 0, CORBA_COMPLETED_NO);
++ return 0;
++}
++
++PortableServer_RequestProcessingPolicyValue
++PortableServer_RequestProcessingPolicy__get_value(PortableServer_RequestProcessingPolicy obj, CORBA_Environment *ev)
++{
++ if(!obj) {
++ ev->_major = 2 ;
++ goto error_exit;
++ }
++
++ ev->_major = CORBA_NO_EXCEPTION;
++ return obj->value;
++
++error_exit:
++ CORBA_exception_set_system(ev, 0, CORBA_COMPLETED_NO);
++ return 0;
++}
++
++/* make emacs happy; */
++
++PortableServer_POAManager_State
++PortableServer_POAManager_get_state(PortableServer_POAManager obj,
++ CORBA_Environment *ev)
++{
++ if(!obj) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return -1;
++ }
++
++ ev->_major = CORBA_NO_EXCEPTION;
++ return obj->state;
++}
++
++/**** PortableServer_POAManager_activate
++ Inputs: 'obj' - a POAManager to activate
++ Outputs: '*ev' - result of the activate operation
++
++ Side effect: Clears the 'held_requests' lists for all POA's
++ associated with the 'obj' POAManager.
++
++ Description: Sets the POAManager state to 'ACTIVE', then
++ goes through all the POA's associated with this
++ POAManager, and makes them re-process their
++ 'held_requests'
++ */
++void
++PortableServer_POAManager_activate(PortableServer_POAManager obj,
++ CORBA_Environment *ev)
++{
++ GSList *todo;
++ GSList *curitem;
++ PortableServer_POA curpoa;
++
++ if(!obj) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ if(obj->state == PortableServer_POAManager_INACTIVE) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POAManager_AdapterInactive,
++ NULL);
++ return;
++ }
++
++ obj->state = PortableServer_POAManager_ACTIVE;
++
++ for(curitem = obj->poa_collection; curitem;
++ curitem = g_slist_next(curitem)) {
++ curpoa = (PortableServer_POA)curitem->data;
++
++ todo = curpoa->held_requests;
++ curpoa->held_requests = NULL;
++
++ g_slist_foreach(todo, (GFunc)ORBit_POA_handle_request,
++ curpoa);
++ g_slist_foreach(todo, (GFunc)giop_recv_buffer_unuse,
++ NULL);
++
++ g_slist_free(todo);
++ }
++ ev->_major = CORBA_NO_EXCEPTION;
++}
++
++void
++PortableServer_POAManager_hold_requests(PortableServer_POAManager obj,
++ CORBA_boolean wait_for_completion,
++ CORBA_Environment *ev)
++{
++ if(!obj) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ if(obj->state == PortableServer_POAManager_INACTIVE) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POAManager_AdapterInactive,
++ NULL);
++ return;
++ }
++
++ obj->state = PortableServer_POAManager_HOLDING;
++ if(!wait_for_completion)
++ g_warning("hold_requests not finished - don't know how to kill outstanding request fulfillments");
++
++ ev->_major = CORBA_NO_EXCEPTION;
++}
++
++void
++PortableServer_POAManager_discard_requests(PortableServer_POAManager obj,
++ CORBA_boolean wait_for_completion,
++ CORBA_Environment *ev)
++{
++ if(!obj) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ if(obj->state == PortableServer_POAManager_INACTIVE) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POAManager_AdapterInactive,
++ NULL);
++ return;
++ }
++
++ obj->state = PortableServer_POAManager_DISCARDING;
++ if(!wait_for_completion)
++ g_warning("discard_requests not finished - don't know how to kill outstanding request fulfillments");
++ ev->_major = CORBA_NO_EXCEPTION;
++}
++
++void
++PortableServer_POAManager_deactivate(PortableServer_POAManager obj,
++ CORBA_boolean etherealize_objects,
++ CORBA_boolean wait_for_completion,
++ CORBA_Environment *ev)
++{
++ if(!obj) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ if(obj->state == PortableServer_POAManager_INACTIVE) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POAManager_AdapterInactive,
++ NULL);
++ return;
++ }
++
++ obj->state = PortableServer_POAManager_INACTIVE;
++
++ if(etherealize_objects)
++ g_slist_foreach(obj->poa_collection, (GFunc)ORBit_POA_etherealize_objects, ev);
++ ev->_major = CORBA_NO_EXCEPTION;
++}
++
++
++CORBA_boolean
++PortableServer_AdapterActivator_unknown_adapter(PortableServer_AdapterActivator obj,
++ PortableServer_POA parent,
++ CORBA_char *name,
++ CORBA_Environment *ev)
++{
++ g_assert(!"Not yet implemented");
++ return(CORBA_FALSE);
++}
++
++
++/**** PortableServer_ServantActivator_incarnate
++ */
++PortableServer_Servant
++
++PortableServer_ServantActivator_incarnate
++(PortableServer_ServantActivator obj,
++ PortableServer_ObjectId *oid,
++ PortableServer_POA adapter,
++ CORBA_Environment *ev)
++{
++ g_assert(!"Not yet implemented");
++ return(NULL);
++}
++
++void
++PortableServer_ServantActivator_etherealize
++(PortableServer_ServantActivator obj,
++ PortableServer_ObjectId *oid, PortableServer_POA adapter,
++ PortableServer_Servant serv,
++ CORBA_boolean cleanup_in_progress,
++ CORBA_boolean remaining_activations,
++ CORBA_Environment *ev)
++{
++ g_assert(!"Not yet implemented");
++ return;
++}
++
++PortableServer_POA
++PortableServer_POA_create_POA
++ (PortableServer_POA poa,
++ CORBA_char *adapter_name,
++ PortableServer_POAManager a_POAManager,
++ CORBA_PolicyList* policies,
++ CORBA_Environment *ev)
++{
++ PortableServer_POA new_poa = NULL;
++ PortableServer_POA check_poa = NULL;
++
++ /* Check for a child POA by the same name in parent */
++ check_poa = PortableServer_POA_find_POA(poa,adapter_name,
++ FALSE, ev);
++ CORBA_exception_free (ev);
++
++ if (!check_poa) {
++ new_poa = ORBit_POA_new(poa->orb,
++ adapter_name, a_POAManager, policies, ev);
++ } else {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_AdapterAlreadyExists,
++ NULL);
++ new_poa = NULL;
++ }
++
++ if(ev->_major == CORBA_NO_EXCEPTION) {
++ new_poa->parent_poa = poa;
++ ORBit_POA_add_child(poa, new_poa, ev);
++ }
++
++ return new_poa;
++}
++
++/**** PortableServer_POA_find_POA
++ Inputs: 'obj' - a POA
++ 'activate_it' - whether to activate unknown POA's
++
++ Outputs: 'child_poa'
++
++ Description: Finds (and optionally activates) a child POA of 'obj'
++ with the specified names.
++
++ TODO: Activate non-existent adapters if asked.
++
++ */
++PortableServer_POA
++PortableServer_POA_find_POA(PortableServer_POA obj,
++ CORBA_char *adapter_name,
++ CORBA_boolean activate_it,
++ CORBA_Environment *ev)
++{
++ GSList *curitem;
++ PortableServer_POA child_poa;
++
++ for(curitem = obj->child_POAs; curitem;
++ curitem = g_slist_next(curitem)) {
++ child_poa = (PortableServer_POA)curitem->data;
++ if(!strcmp(child_poa->the_name, adapter_name)) {
++ ev->_major = CORBA_NO_EXCEPTION;
++ return child_poa;
++ }
++ }
++
++ if(activate_it)
++ g_warning("Don't yet know how to activate POA named \"%s\"",
++ adapter_name);
++
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_AdapterNonExistent,
++ NULL);
++
++ return NULL;
++}
++
++/**** PortableServer_POA_destroy
++ Inputs: 'obj' - the POA to be destroyed
++ 'etherealize_objects' - flag indicating whether any servant
++ manager should be asked to etherealize
++ objects in the active object map
++ 'wait_for_completion' - flag indicating whether to wait for
++ requests currently being handled
++ */
++void
++PortableServer_POA_destroy(PortableServer_POA obj,
++ CORBA_boolean etherealize_objects,
++ CORBA_boolean wait_for_completion,
++ CORBA_Environment *ev)
++{
++ if(etherealize_objects || !wait_for_completion)
++ g_warning("PortableServer_POA_destroy not yet fully implemented; ignoring flags");
++
++ if(ORBIT_ROOT_OBJECT(obj)->refs > 1)
++ g_warning("POA has multiple refs [%d]",
++ ORBIT_ROOT_OBJECT(obj)->refs);
++
++ CORBA_Object_release((CORBA_Object)obj, ev);
++ ev->_major = CORBA_NO_EXCEPTION;
++}
++
++PortableServer_ThreadPolicy PortableServer_POA_create_thread_policy(PortableServer_POA obj, PortableServer_ThreadPolicyValue value, CORBA_Environment *ev)
++{
++ PortableServer_ThreadPolicy retval;
++
++ retval = g_new(struct PortableServer_ThreadPolicy_type, 1);
++ ORBit_policy_object_init((CORBA_Policy)retval,
++ PortableServer_THREAD_POLICY_ID, ev);
++
++ retval->value = value;
++
++ return (PortableServer_ThreadPolicy)CORBA_Object_duplicate((CORBA_Object)retval, ev);
++}
++
++PortableServer_LifespanPolicy PortableServer_POA_create_lifespan_policy(PortableServer_POA obj, PortableServer_LifespanPolicyValue value, CORBA_Environment *ev)
++{
++ PortableServer_LifespanPolicy retval;
++
++ retval = g_new(struct PortableServer_LifespanPolicy_type, 1);
++ ORBit_policy_object_init((CORBA_Policy)retval,
++ PortableServer_LIFESPAN_POLICY_ID, ev);
++
++ retval->value = value;
++
++ return (PortableServer_LifespanPolicy)CORBA_Object_duplicate((CORBA_Object)retval, ev);
++}
++
++PortableServer_IdUniquenessPolicy PortableServer_POA_create_id_uniqueness_policy(PortableServer_POA obj, PortableServer_IdUniquenessPolicyValue value, CORBA_Environment *ev)
++{
++ PortableServer_IdUniquenessPolicy retval;
++
++ retval = g_new(struct PortableServer_IdUniquenessPolicy_type, 1);
++ ORBit_policy_object_init((CORBA_Policy)retval,
++ PortableServer_ID_UNIQUENESS_POLICY_ID,
++ ev);
++
++ retval->value = value;
++
++ return (PortableServer_IdUniquenessPolicy)CORBA_Object_duplicate((CORBA_Object)retval, ev);
++}
++
++PortableServer_IdAssignmentPolicy PortableServer_POA_create_id_assignment_policy(PortableServer_POA obj, PortableServer_IdAssignmentPolicyValue value, CORBA_Environment *ev)
++{
++ PortableServer_IdAssignmentPolicy retval;
++
++ retval = g_new(struct PortableServer_IdAssignmentPolicy_type, 1);
++ ORBit_policy_object_init((CORBA_Policy)retval,
++ PortableServer_ID_ASSIGNMENT_POLICY_ID, ev);
++
++ retval->value = value;
++
++ return (PortableServer_IdAssignmentPolicy)CORBA_Object_duplicate((CORBA_Object)retval, ev);
++}
++
++PortableServer_ImplicitActivationPolicy PortableServer_POA_create_implicit_activation_policy(PortableServer_POA obj, PortableServer_ImplicitActivationPolicyValue value, CORBA_Environment *ev)
++{
++ PortableServer_ImplicitActivationPolicy retval;
++
++ retval = g_new(struct PortableServer_ImplicitActivationPolicy_type, 1);
++ ORBit_policy_object_init((CORBA_Policy)retval,
++ PortableServer_IMPLICIT_ACTIVATION_POLICY_ID, ev);
++
++ retval->value = value;
++
++ return (PortableServer_ImplicitActivationPolicy)CORBA_Object_duplicate((CORBA_Object)retval, ev);
++}
++
++PortableServer_ServantRetentionPolicy PortableServer_POA_create_servant_retention_policy(PortableServer_POA obj, PortableServer_ServantRetentionPolicyValue value, CORBA_Environment *ev)
++{
++ PortableServer_ServantRetentionPolicy retval;
++
++ retval = g_new(struct PortableServer_ServantRetentionPolicy_type, 1);
++ ORBit_policy_object_init((CORBA_Policy)retval,
++ PortableServer_SERVANT_RETENTION_POLICY_ID, ev);
++
++ retval->value = value;
++
++ return (PortableServer_ServantRetentionPolicy)CORBA_Object_duplicate((CORBA_Object)retval, ev);
++}
++
++PortableServer_RequestProcessingPolicy PortableServer_POA_create_request_processing_policy(PortableServer_POA obj, PortableServer_RequestProcessingPolicyValue value, CORBA_Environment *ev)
++{
++ PortableServer_RequestProcessingPolicy retval;
++
++ retval = g_new(struct PortableServer_RequestProcessingPolicy_type, 1);
++ ORBit_policy_object_init((CORBA_Policy)retval,
++ PortableServer_REQUEST_PROCESSING_POLICY_ID, ev);
++
++ retval->value = value;
++
++ return (PortableServer_RequestProcessingPolicy)CORBA_Object_duplicate((CORBA_Object)retval, ev);
++}
++
++CORBA_char *PortableServer_POA__get_the_name(PortableServer_POA obj, CORBA_Environment *ev)
++{
++ g_assert(obj);
++ g_assert(obj->the_name);
++ return obj->the_name;
++}
++
++PortableServer_POA
++PortableServer_POA__get_the_parent(PortableServer_POA obj,
++ CORBA_Environment *ev)
++{
++ if(!obj) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return NULL;
++ }
++
++ return obj->parent_poa;
++}
++
++PortableServer_POAManager
++PortableServer_POA__get_the_POAManager(PortableServer_POA obj,
++ CORBA_Environment *ev)
++{
++ if(!obj) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return NULL;
++ }
++
++ return obj->the_POAManager;
++}
++
++PortableServer_AdapterActivator PortableServer_POA__get_the_activator(PortableServer_POA obj, CORBA_Environment *ev)
++{
++ if(!obj) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return NULL;
++ }
++
++ return obj->the_activator;
++}
++
++void PortableServer_POA__set_the_activator(PortableServer_POA obj, PortableServer_AdapterActivator the_activator, CORBA_Environment *ev)
++{
++ if(!obj) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ obj->the_activator = the_activator;
++}
++
++PortableServer_ServantManager PortableServer_POA_get_servant_manager(PortableServer_POA obj, CORBA_Environment *ev)
++{
++ if(!obj) {
++ CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return NULL;
++ }
++
++ if(obj->request_processing != PortableServer_USE_SERVANT_MANAGER) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_WrongPolicy,
++ NULL);
++ return NULL;
++ }
++
++ return obj->servant_manager;
++}
++
++void PortableServer_POA_set_servant_manager(PortableServer_POA obj, PortableServer_ServantManager imgr, CORBA_Environment *ev)
++{
++ if(!obj) {
++ CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ if(obj->request_processing != PortableServer_USE_SERVANT_MANAGER) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_WrongPolicy,
++ NULL);
++ return;
++ }
++
++ obj->servant_manager = imgr;
++}
++
++PortableServer_Servant PortableServer_POA_get_servant(PortableServer_POA obj, CORBA_Environment *ev)
++{
++ if(!obj) {
++ CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return NULL;
++ }
++
++ if(obj->request_processing != PortableServer_USE_DEFAULT_SERVANT) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_WrongPolicy,
++ NULL);
++ return NULL;
++ }
++
++ return obj->default_servant;
++}
++
++void PortableServer_POA_set_servant(PortableServer_POA obj, PortableServer_Servant p_servant, CORBA_Environment *ev)
++{
++ if(!obj) {
++ CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ if(obj->request_processing != PortableServer_USE_DEFAULT_SERVANT) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_WrongPolicy,
++ NULL);
++ return;
++ }
++
++ obj->default_servant = p_servant;
++}
++
++static CORBA_unsigned_long
++get_objnum_for_obj(PortableServer_POA poa, ORBit_POAObject *obj)
++{
++ CORBA_unsigned_long retval;
++
++ if(poa->first_free_id) {
++ retval = poa->first_free_id;
++ poa->first_free_id = GPOINTER_TO_UINT(g_ptr_array_index(poa->objnum_to_obj,
++ retval));
++ g_ptr_array_index(poa->objnum_to_obj, retval) = obj;
++ } else {
++ retval = poa->objnum_to_obj->len;
++ g_ptr_array_add(poa->objnum_to_obj,
++ obj);
++ }
++
++ return retval;
++}
++
++static CORBA_ORB
++get_orb_for_poa(PortableServer_POA poa)
++{
++ if(poa->orb)
++ return poa->orb;
++ if(poa->parent_poa)
++ return get_orb_for_poa(poa->parent_poa);
++
++ return CORBA_OBJECT_NIL;
++}
++
++PortableServer_ObjectId *
++PortableServer_POA_activate_object(PortableServer_POA obj,
++ PortableServer_Servant p_servant,
++ CORBA_Environment *ev)
++{
++ PortableServer_ServantBase *servant;
++ PortableServer_ObjectId *new_objid;
++ ORBit_POAObject *new_obj;
++
++ servant = p_servant;
++
++ if(obj->servant_retention != PortableServer_RETAIN
++ || obj->id_assignment != PortableServer_SYSTEM_ID) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_WrongPolicy,
++ NULL);
++ return NULL;
++ }
++
++ /* Servant Already Active */
++ if((obj->id_uniqueness==PortableServer_UNIQUE_ID) &&
++ (ORBIT_OBJECT_KEY(servant->_private)->object != 0)) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_ServantAlreadyActive,
++ NULL);
++ return NULL;
++ }
++
++
++ new_obj = g_new0(ORBit_POAObject, 1);
++ new_obj->object_id = (PortableServer_ObjectId*)CORBA_sequence_octet__alloc();
++
++ new_objid =
++ ORBit_POA_allocate_oid(obj,
++ ORBIT_OBJECT_KEY(servant->_private)->class_info->class_name);
++
++ new_obj->object_id->_buffer = CORBA_octet_allocbuf(new_objid->_length);
++ new_obj->object_id->_length = new_objid->_length;
++ memcpy(new_obj->object_id->_buffer, new_objid->_buffer,
++ new_objid->_length);
++ CORBA_sequence_set_release(new_obj->object_id, CORBA_TRUE);
++
++ new_obj->servant = p_servant;
++ ORBIT_OBJECT_KEY(servant->_private)->object = new_obj;
++ new_obj->orb = get_orb_for_poa(obj);
++ new_obj->poa = obj;
++ new_obj->objnum = get_objnum_for_obj(obj, new_obj);
++ orbit_genrand(new_obj->rand_data, ORBIT_RAND_KEY_LEN);
++
++ g_hash_table_insert(obj->active_object_map,
++ new_obj->object_id,
++ new_obj);
++
++ ev->_major = CORBA_NO_EXCEPTION;
++
++ return new_objid;
++}
++
++void
++PortableServer_POA_activate_object_with_id(PortableServer_POA obj,
++ PortableServer_ObjectId *id,
++ PortableServer_Servant p_servant,
++ CORBA_Environment *ev)
++{
++ PortableServer_ServantBase *servant = p_servant;
++ ORBit_POAObject *newobj;
++
++ if(!obj || !id || !p_servant) {
++ CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ newobj = g_hash_table_lookup(obj->active_object_map,
++ id);
++
++ if(newobj) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_ObjectAlreadyActive, NULL);
++ return;
++ }
++
++ newobj = g_new0(ORBit_POAObject, 1);
++ newobj->object_id = (PortableServer_ObjectId *)CORBA_sequence_octet__alloc();
++ newobj->object_id->_length = id->_length;
++ newobj->object_id->_buffer = CORBA_octet_allocbuf(id->_length);
++ newobj->object_id->_release = CORBA_TRUE;
++ memcpy(newobj->object_id->_buffer, id->_buffer, id->_length);
++ newobj->poa = obj;
++ newobj->orb = get_orb_for_poa(obj);
++ newobj->objnum = get_objnum_for_obj(obj, newobj);
++ orbit_genrand(newobj->rand_data, ORBIT_RAND_KEY_LEN);
++
++ newobj->servant = p_servant;
++
++ g_hash_table_insert(obj->active_object_map,
++ newobj->object_id,
++ newobj);
++
++ ORBIT_OBJECT_KEY(servant->_private)->object = newobj;
++
++ ev->_major = CORBA_NO_EXCEPTION;
++}
++
++void
++PortableServer_POA_deactivate_object(PortableServer_POA obj,
++ PortableServer_ObjectId *oid,
++ CORBA_Environment *ev)
++{
++ ORBit_POAObject *oldobj;
++
++ if(!obj || !oid) {
++ CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ oldobj = g_hash_table_lookup(obj->active_object_map,
++ oid);
++
++ if(!oldobj) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_ObjectNotActive,
++ NULL);
++ return;
++ }
++
++ g_ptr_array_index(obj->objnum_to_obj, oldobj->objnum) = GUINT_TO_POINTER(obj->first_free_id);
++ obj->first_free_id = oldobj->objnum;
++
++ g_hash_table_remove(obj->active_object_map, oid);
++
++ if(obj->request_processing == PortableServer_USE_SERVANT_MANAGER) {
++ POA_PortableServer_ServantActivator__epv *epv;
++ POA_PortableServer_ServantActivator *sm;
++
++ sm = (POA_PortableServer_ServantActivator *)obj->servant_manager;
++ epv = sm->vepv->PortableServer_ServantActivator_epv;
++ epv->etherealize(sm, oldobj->object_id, obj,
++ oldobj->servant,
++ CORBA_FALSE,
++ CORBA_FALSE,
++ ev);
++ }
++
++ CORBA_free(oldobj->object_id);
++
++ g_free(oldobj);
++ ev->_major = CORBA_NO_EXCEPTION;
++}
++
++CORBA_Object
++PortableServer_POA_create_reference(PortableServer_POA obj,
++ CORBA_RepositoryId intf,
++ CORBA_Environment *ev)
++{
++ g_assert(!"Not yet implemented");
++ return(NULL);
++}
++
++PortableServer_ObjectId *PortableServer_POA_servant_to_id(PortableServer_POA obj, PortableServer_Servant p_servant, CORBA_Environment *ev)
++{
++ PortableServer_ObjectId *retval, *orig;
++ PortableServer_ServantBase *serv = p_servant;
++ g_return_val_if_fail(p_servant != NULL, NULL);
++
++ orig = ORBIT_OBJECT_KEY(serv->_private)->object->object_id;
++ retval = (PortableServer_ObjectId *)CORBA_sequence_octet__alloc();
++ retval->_length = retval->_maximum = orig->_length;
++ retval->_buffer = CORBA_octet_allocbuf(retval->_length);
++ memcpy(retval->_buffer, orig->_buffer, retval->_length);
++ CORBA_sequence_set_release(retval, CORBA_TRUE);
++
++ return retval;
++}
++
++CORBA_Object
++PortableServer_POA_servant_to_reference(PortableServer_POA obj, PortableServer_Servant p_servant, CORBA_Environment *ev)
++{
++ CORBA_Object retval;
++ PortableServer_ObjectId *orig_id;
++ PortableServer_ServantBase *servant = p_servant;
++ ORBit_ObjectKey *obj_key = ORBIT_OBJECT_KEY(servant->_private);
++
++ int implicit = (obj->implicit_activation == PortableServer_IMPLICIT_ACTIVATION);
++ int activate_able = (obj_key->object == 0) ||
++ (obj->id_uniqueness==PortableServer_MULTIPLE_ID);
++ /* ImplicitActivationPolicy */
++ if( implicit && activate_able) {
++ orig_id = PortableServer_POA_activate_object(obj, p_servant, ev);
++ } else {
++ orig_id = obj_key->object->object_id;
++ }
++ retval = PortableServer_POA_id_to_reference(obj,orig_id,ev);
++
++ return retval;
++}
++
++PortableServer_Servant
++PortableServer_POA_reference_to_servant(PortableServer_POA obj, CORBA_Object reference, CORBA_Environment *ev)
++{
++ GSList *cur;
++
++ g_assert(reference);
++
++ if(obj->request_processing != PortableServer_USE_DEFAULT_SERVANT
++ && obj->servant_retention != PortableServer_RETAIN) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_WrongPolicy,
++ NULL);
++ return NULL;
++ }
++
++ if(reference->servant)
++ return reference->servant;
++
++ for(cur = reference->profile_list; cur; cur = cur->next) {
++ PortableServer_ObjectId *oid;
++ ORBit_Object_info *curprof = cur->data;
++ ORBit_POAObject *objinfo;
++
++ objinfo = ORBit_POA_find_oid_for_object_key(obj, &(curprof->object_key), &oid);
++ CORBA_free(oid);
++ if(objinfo)
++ return objinfo->servant;
++ }
++
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_ObjectNotActive,
++ NULL);
++ return NULL;
++}
++
++PortableServer_ObjectId *PortableServer_POA_reference_to_id(PortableServer_POA obj, CORBA_Object reference, CORBA_Environment *ev)
++{
++ PortableServer_ObjectId *retval;
++ ORBit_POAObject *objinfo;
++
++ g_assert(reference);
++ g_assert(reference->active_profile);
++
++ if(obj->request_processing != PortableServer_USE_DEFAULT_SERVANT
++ && obj->servant_retention != PortableServer_RETAIN) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_WrongPolicy,
++ NULL);
++ return NULL;
++ }
++
++ objinfo = ORBit_POA_find_oid_for_object_key(obj, &(reference->active_profile->object_key), &retval);
++ if(objinfo) {
++ CORBA_free(retval);
++ retval = (PortableServer_ObjectId *)CORBA_sequence_octet__alloc();
++ retval->_length = retval->_maximum = objinfo->object_id->_length;
++ retval->_buffer = CORBA_octet_allocbuf(retval->_length);
++ memcpy(retval->_buffer, objinfo->object_id->_buffer, retval->_length);
++ CORBA_sequence_set_release(retval, CORBA_TRUE);
++ return retval;
++ } else if(retval)
++ return retval;
++
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_ObjectNotActive,
++ NULL);
++ return NULL;
++}
++
++PortableServer_Servant PortableServer_POA_id_to_servant(PortableServer_POA obj, PortableServer_ObjectId *oid, CORBA_Environment *ev)
++{
++ ORBit_POAObject *objinfo;
++
++ if(obj->servant_retention != PortableServer_RETAIN) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_WrongPolicy,
++ NULL);
++ return NULL;
++ }
++
++ objinfo = g_hash_table_lookup(obj->active_object_map,
++ oid);
++
++ if(!objinfo) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_WrongPolicy,
++ NULL);
++ return NULL;
++ }
++
++ return objinfo->servant;
++}
++
++static CORBA_Object
++my_PortableServer_POA_id_to_reference(PortableServer_POA obj,
++ PortableServer_ObjectId *oid,
++ const char *type_id,
++ CORBA_Environment *ev)
++{
++ GSList *profiles=NULL;
++ ORBit_Object_info *object_info;
++ CORBA_Object retval;
++ CORBA_ORB orb;
++ ORBit_POAObject *pobj;
++ ORBit_ObjectKey *objkey = NULL;
++
++ orb = obj->the_POAManager->orb;
++
++ g_assert(!oid->_buffer[oid->_length - 1]);
++
++ pobj = g_hash_table_lookup(obj->active_object_map, oid);
++
++ if(pobj) {
++ objkey = ORBIT_OBJECT_KEY(((PortableServer_ServantBase *)pobj->servant)->_private);
++ type_id= objkey->class_info->class_name;
++ }
++
++ /* Do the local connection first, so it will be attempted first by
++ the client parsing the IOR string
++ */
++ if(orb->cnx.ipv6 || orb->cnx.usock) {
++ object_info = g_new0(ORBit_Object_info, 1);
++
++ object_info->profile_type=IOP_TAG_ORBIT_SPECIFIC;
++ object_info->iiop_major = 1;
++ object_info->iiop_minor = 0;
++
++ ORBit_POA_find_object_key_for_oid(obj, pobj, oid, &object_info->object_key);
++
++#ifdef HAVE_IPV6
++ if(orb->cnx.ipv6) {
++ object_info->tag.orbitinfo.ipv6_port =
++ ntohs(IIOP_CONNECTION(orb->cnx.ipv6)->u.ipv6.location.sin_port);
++ }
++#endif
++ if(orb->cnx.usock) {
++ object_info->tag.orbitinfo.unix_sock_path =
++ g_strdup(IIOP_CONNECTION(orb->cnx.usock)->u.usock.sun_path);
++ }
++ ORBit_set_object_key(object_info);
++ profiles=g_slist_append(profiles, object_info);
++ }
++
++ if(orb->cnx.ipv4) {
++ object_info=g_new0(ORBit_Object_info, 1);
++
++ object_info->profile_type = IOP_TAG_INTERNET_IOP;
++ object_info->iiop_major = 1;
++ object_info->iiop_minor = 0;
++ ORBit_POA_find_object_key_for_oid(obj, pobj, oid, &object_info->object_key);
++
++ object_info->tag.iopinfo.host = g_strdup(IIOP_CONNECTION(orb->cnx.ipv4)->u.ipv4.hostname);
++ object_info->tag.iopinfo.port = ntohs(IIOP_CONNECTION(orb->cnx.ipv4)->u.ipv4.location.sin_port);
++
++ ORBit_set_object_key(object_info);
++ profiles=g_slist_append(profiles, object_info);
++ }
++
++ retval = ORBit_create_object_with_info(profiles, type_id, orb, ev);
++
++ if(retval != CORBA_OBJECT_NIL
++ && ev->_major == CORBA_NO_EXCEPTION
++ && objkey && objkey->class_info && objkey->class_info->init_local_objref) {
++ /* XXX potential memleak if we get an already-valid objref */
++ retval->vepv = g_new0(gpointer, ORBit_class_assignment_counter + 1);
++ retval->vepv_size = ORBit_class_assignment_counter + 1;
++ objkey->class_info->init_local_objref(retval, pobj->servant);
++ retval->servant = pobj->servant;
++ } else
++ retval->vepv = retval->servant = NULL;
++
++ return retval;
++}
++
++CORBA_Object PortableServer_POA_id_to_reference(PortableServer_POA obj,
++ PortableServer_ObjectId *oid,
++ CORBA_Environment *ev)
++{
++ return my_PortableServer_POA_id_to_reference(obj, oid, NULL, ev);
++}
++
++CORBA_Object
++PortableServer_POA_create_reference_with_id(PortableServer_POA obj,
++ PortableServer_ObjectId *oid,
++ CORBA_RepositoryId intf,
++ CORBA_Environment *ev)
++{
++ return my_PortableServer_POA_id_to_reference(obj, oid, intf, ev);
++}
++
++PortableServer_POA PortableServer_Current_get_POA(PortableServer_Current obj, CORBA_Environment *ev)
++{
++ g_assert(!"Not yet implemented");
++ return(NULL);
++}
++
++PortableServer_ObjectId *PortableServer_Current_get_object_id(PortableServer_Current obj, CORBA_Environment *ev)
++{
++ g_assert(!"Not yet implemented");
++ return(NULL);
++}
++
++
++CORBA_char *PortableServer_ObjectId_to_string(PortableServer_ObjectId *id, CORBA_Environment *env)
++{
++ return CORBA_string_dup((CORBA_char *)id->_buffer);
++}
++
++CORBA_wchar *PortableServer_ObjectId_to_wstring(PortableServer_ObjectId *id, CORBA_Environment *env)
++{
++ g_assert(!"Not yet implemented");
++ return(NULL);
++}
++
++PortableServer_ObjectId *PortableServer_string_to_ObjectId(CORBA_char *str, CORBA_Environment *env)
++{
++ PortableServer_ObjectId *retval;
++
++ retval = (PortableServer_ObjectId *)CORBA_sequence_octet__alloc();
++
++ retval->_length = strlen(str) + 1;
++ retval->_buffer = CORBA_octet_allocbuf(retval->_length);
++
++ memcpy(retval->_buffer, str, retval->_length);
++
++ return retval;
++}
++
++PortableServer_ObjectId *PortableServer_wstring_to_ObjectId(CORBA_wchar *str, CORBA_Environment *env)
++{
++ g_assert(!"Not yet implemented");
++ return(NULL);
++}
++
++
++PortableServer_POA PortableServer_ServantBase__default_POA(PortableServer_Servant servant, CORBA_Environment *ev)
++{
++ g_return_val_if_fail(servant, NULL);
++
++ return ORBIT_OBJECT_KEY(((PortableServer_ServantBase *)servant)->_private)->object->poa;
++}
++
++void PortableServer_ServantLocator_preinvoke(PortableServer_ObjectId *oid, PortableServer_POA adapter, CORBA_Identifier op_name, PortableServer_ServantLocator_Cookie *cookie)
++{
++ g_assert(!"Not yet implemented");
++ return;
++}
++
++void PortableServer_ServantLocator_postinvoke(PortableServer_ObjectId *oid, PortableServer_POA adapter, CORBA_Identifier op_name, PortableServer_ServantLocator_Cookie cookie, PortableServer_Servant servant)
++{
++ g_assert(!"Not yet implemented");
++ return;
++}
++
++void PortableServer_ServantBase__init(PortableServer_Servant servant,
++ CORBA_Environment *ev)
++{
++ PortableServer_ServantBase *serv = servant;
++
++ if(!serv->_private) /* If not already initialized, create the place to
++ stick our info */
++ serv->_private = g_new0(ORBit_ObjectKey, 1);
++}
++
++void PortableServer_ServantBase__fini(PortableServer_Servant servant,
++ CORBA_Environment *ev)
++{
++ PortableServer_ServantBase *serv = servant;
++
++ g_free(serv->_private);
++ serv->_private = NULL;
++}
++
++
++/************************ ServerRequest stuff ********************/
++
++CORBA_Identifier CORBA_ServerRequest_operation(CORBA_ServerRequest req, CORBA_Environment *env)
++{
++ return CORBA_string_dup(req->rbuf->message.u.request.operation);
++}
++
++CORBA_Context
++CORBA_ServerRequest_ctx(CORBA_ServerRequest req, CORBA_Environment *env)
++{
++ if(!req->params || req->did_ctx) {
++ CORBA_exception_set_system(env, ex_CORBA_BAD_INV_ORDER,
++ CORBA_COMPLETED_NO);
++ return NULL;
++ }
++
++ return NULL;
++}
++
++void
++CORBA_ServerRequest_arguments(CORBA_ServerRequest req,
++ CORBA_NVList *parameters,
++ CORBA_Environment *env)
++{
++ int i;
++
++ if(req->params) {
++ CORBA_exception_set_system(env, ex_CORBA_BAD_INV_ORDER,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ req->params = parameters;
++
++ for(i = 0; i < parameters->list->len; i++) {
++ CORBA_NamedValue *cur;
++
++ cur = &g_array_index(parameters->list, CORBA_NamedValue, i);
++
++ if(cur->arg_modes & CORBA_ARG_OUT) continue;
++ cur->argument._value = ORBit_demarshal_arg(req->rbuf,
++ cur->argument._type,
++ TRUE,
++ (CORBA_ORB)req->orb);
++ CORBA_any_set_release(&cur->argument, TRUE);
++ }
++}
++
++void
++CORBA_ServerRequest_set_result(CORBA_ServerRequest req,
++ CORBA_any *value,
++ CORBA_Environment *env)
++{
++ if(req->sbuf) {
++ CORBA_exception_set_system(env, ex_CORBA_BAD_INV_ORDER,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ req->sbuf = giop_send_reply_buffer_use(GIOP_MESSAGE_BUFFER(req->rbuf)->connection,
++ NULL,
++ req->rbuf->message.u.request.request_id,
++ CORBA_NO_EXCEPTION);
++ if(!req->sbuf) {
++ CORBA_exception_set_system(env, ex_CORBA_COMM_FAILURE,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ ORBit_marshal_arg(req->sbuf, value->_value, value->_type);
++}
++
++void
++CORBA_ServerRequest_set_exception(CORBA_ServerRequest req,
++ CORBA_exception_type major,
++ CORBA_any *value,
++ CORBA_Environment *env)
++{
++ if(req->sbuf) {
++ CORBA_exception_set_system(env, ex_CORBA_BAD_INV_ORDER,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ req->sbuf = giop_send_reply_buffer_use(GIOP_MESSAGE_BUFFER(req->rbuf)->connection,
++ NULL,
++ req->rbuf->message.u.request.request_id,
++ major);
++ if(!req->sbuf) {
++ CORBA_exception_set_system(env, ex_CORBA_COMM_FAILURE,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ req->did_exc = TRUE;
++
++ /* XXX do we really need to copy the repo_id into the
++ send buffer? Or is there a way to assume that the CORBA_TypeCode
++ value->_type will be around until after we send the message? */
++ {
++ CORBA_unsigned_long slen;
++ slen = strlen(value->_type->repo_id) + 1;
++ giop_send_buffer_append_mem_indirect_a(req->sbuf, &slen,
++ sizeof(slen));
++ giop_send_buffer_append_mem_indirect(req->sbuf,
++ value->_type->repo_id,
++ slen);
++ }
++
++ ORBit_marshal_arg(req->sbuf, value->_value, value->_type);
++}
++
++void
++POA_PortableServer_ServantActivator__init(PortableServer_Servant servant,
++ CORBA_Environment * ev)
++{
++ static const PortableServer_ClassInfo class_info =
++ {NULL,
++ "IDL:omg.org/PortableServer/ServantActivator:1.0",
++ NULL};
++
++ PortableServer_ServantBase__init(((PortableServer_ServantBase *) servant), ev);
++
++ ORBIT_OBJECT_KEY(((PortableServer_ServantBase *)servant)->_private)->class_info = (gpointer)&class_info;
++}
++
++void
++POA_PortableServer_ServantActivator__fini(PortableServer_Servant servant,
++ CORBA_Environment * ev)
++{
++ PortableServer_ServantBase__fini(servant, ev);
++}
++
++void
++POA_PortableServer_ServantLocator__init(PortableServer_Servant servant,
++ CORBA_Environment * ev)
++{
++ static const PortableServer_ClassInfo class_info =
++ {NULL,
++ "IDL:omg.org/PortableServer/ServantLocator:1.0",
++ NULL};
++
++ PortableServer_ServantBase__init(((PortableServer_ServantBase *)servant), ev);
++
++ ORBIT_OBJECT_KEY(((PortableServer_ServantBase *)servant)->_private)->class_info = (gpointer)&class_info;
++}
++
++void
++POA_PortableServer_ServantLocator__fini(PortableServer_Servant servant,
++ CORBA_Environment * ev)
++{
++ PortableServer_ServantBase__fini(servant, ev);
++}
++
++/* POA-related DSI stuff */
++static void
++dynamic_impl_skel(PortableServer_DynamicImpl *_ORBIT_servant,
++ GIOPRecvBuffer *_ORBIT_recv_buffer,
++ CORBA_Environment *ev,
++ PortableServer_DynamicImplRoutine invoke)
++{
++ /* here the magic occurs... */
++ struct CORBA_ServerRequest_type sr;
++
++ ORBit_pseudo_object_init(ORBIT_PSEUDO_OBJECT(&sr),
++ ORBIT_PSEUDO_SERVERREQUEST, ev);
++
++ CORBA_Object_duplicate((CORBA_Object)&sr, ev); /* just to make
++ sure it doesn't die
++ elsewhere */
++
++ sr.rbuf = _ORBIT_recv_buffer;
++ sr.orb = GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)->connection->orb_data;
++
++ _ORBIT_servant->vepv->PortableServer_DynamicImpl_epv->invoke(_ORBIT_servant,
++ &sr);
++
++ if(sr.sbuf) {
++ int i;
++ for(i = 0; i < sr.params->list->len; i++) {
++ CORBA_NamedValue *cur;
++
++ cur = &g_array_index(sr.params->list, CORBA_NamedValue, i);
++
++ if(cur->arg_modes & CORBA_ARG_IN) continue;
++
++ ORBit_marshal_arg(sr.sbuf, cur->argument._value,
++ cur->argument._type);
++ }
++
++ giop_send_buffer_write(sr.sbuf);
++ giop_send_buffer_unuse(sr.sbuf);
++ } else
++ g_warning("Yo, your DSI code is messed up! You forgot to set_result|set_exception");
++
++ CORBA_NVList_free(sr.params, ev);
++}
++
++static ORBitSkeleton
++dynamic_impl_get_skel(PortableServer_DynamicImpl * servant,
++ GIOPRecvBuffer * _ORBIT_recv_buffer,
++ gpointer * impl)
++{
++ *impl = (gpointer)servant->vepv->PortableServer_DynamicImpl_epv->invoke;
++
++ return (ORBitSkeleton)dynamic_impl_skel;
++}
++
++void
++PortableServer_DynamicImpl__init(PortableServer_Servant servant,
++ CORBA_Environment *ev)
++{
++ static const PortableServer_ClassInfo class_info =
++ {(ORBitSkeleton (*)(PortableServer_ServantBase *, gpointer, gpointer *))
++ &dynamic_impl_get_skel, "IDL:CORBA/Object:1.0", NULL};
++
++ PortableServer_ServantBase__init(servant, ev);
++
++ ORBIT_OBJECT_KEY(((PortableServer_ServantBase *)servant)->_private)->class_info =
++ (PortableServer_ClassInfo *) & class_info;
++
++}
++
++void PortableServer_DynamicImpl__fini(PortableServer_Servant servant,
++ CORBA_Environment *ev)
++{
++ PortableServer_ServantBase__fini(servant, ev);
++}
++
+diff -urN linux-2.4.1/net/korbit/orb/poa.h linux-2.4.1-korbit/net/korbit/orb/poa.h
+--- linux-2.4.1/net/korbit/orb/poa.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/poa.h Thu Feb 1 11:47:14 2001
+@@ -0,0 +1,337 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_POA_H_
++#define _ORBIT_POA_H_
++
++#include "orbit_types.h"
++
++extern PortableServer_ThreadPolicyValue PortableServer_ThreadPolicy__get_value(
++ PortableServer_ThreadPolicy obj,
++ CORBA_Environment *ev);
++
++extern PortableServer_LifespanPolicyValue PortableServer_LifespanPolicy__get_value(
++ PortableServer_LifespanPolicy obj,
++ CORBA_Environment *ev);
++
++extern PortableServer_IdUniquenessPolicyValue PortableServer_IdUniquenessPolicy__get_value(
++ PortableServer_IdUniquenessPolicy obj,
++ CORBA_Environment *ev);
++
++extern PortableServer_IdAssignmentPolicyValue PortableServer_IdAssignmentPolicy__get_value(
++ PortableServer_IdAssignmentPolicy obj,
++ CORBA_Environment *ev);
++
++extern PortableServer_ImplicitActivationPolicyValue PortableServer_ImplicitActivationPolicy__get_value(
++ PortableServer_ImplicitActivationPolicy obj,
++ CORBA_Environment *ev);
++
++extern PortableServer_ServantRetentionPolicyValue PortableServer_ServantRetentionPolicy__get_value(
++ PortableServer_ServantRetentionPolicy obj,
++ CORBA_Environment *ev);
++
++extern PortableServer_RequestProcessingPolicyValue PortableServer_RequestProcessingPolicy__get_value(
++ PortableServer_RequestProcessingPolicy obj,
++ CORBA_Environment *ev);
++
++PortableServer_POAManager_State
++PortableServer_POAManager_get_state(PortableServer_POAManager obj,
++ CORBA_Environment *ev);
++
++extern void PortableServer_POAManager_activate(
++ PortableServer_POAManager obj,
++ CORBA_Environment *ev);
++
++extern void PortableServer_POAManager_hold_requests(
++ PortableServer_POAManager obj,
++ CORBA_boolean wait_for_completion,
++ CORBA_Environment *ev);
++
++extern void PortableServer_POAManager_discard_requests(
++ PortableServer_POAManager obj,
++ CORBA_boolean wait_for_completion,
++ CORBA_Environment *ev);
++
++extern void PortableServer_POAManager_deactivate(
++ PortableServer_POAManager obj,
++ CORBA_boolean etherealize_objects,
++ CORBA_boolean wait_for_completion,
++ CORBA_Environment *ev);
++
++extern CORBA_boolean PortableServer_AdapterActivator_unknown_adapter(
++ PortableServer_AdapterActivator obj,
++ PortableServer_POA parent,
++ CORBA_char *name,
++ CORBA_Environment *ev);
++
++extern PortableServer_Servant PortableServer_ServantActivator_incarnate(
++ PortableServer_ServantActivator obj,
++ PortableServer_ObjectId *oid,
++ PortableServer_POA adapter,
++ CORBA_Environment *ev);
++
++extern void PortableServer_ServantActivator_etherealize(
++ PortableServer_ServantActivator obj,
++ PortableServer_ObjectId *oid,
++ PortableServer_POA adapter,
++ PortableServer_Servant serv,
++ CORBA_boolean cleanup_in_progress,
++ CORBA_boolean remaining_activations,
++ CORBA_Environment *ev);
++
++extern PortableServer_POA PortableServer_POA_create_POA(
++ PortableServer_POA obj,
++ CORBA_char *adapter_name,
++ PortableServer_POAManager a_POAManager,
++ CORBA_PolicyList *policies,
++ CORBA_Environment *ev);
++
++extern PortableServer_POA PortableServer_POA_find_POA(
++ PortableServer_POA obj,
++ CORBA_char *adapter_name,
++ CORBA_boolean activate_it,
++ CORBA_Environment *ev);
++
++extern void PortableServer_POA_destroy(
++ PortableServer_POA obj,
++ CORBA_boolean etherealize_objects,
++ CORBA_boolean wait_for_completion,
++ CORBA_Environment *ev);
++
++extern PortableServer_ThreadPolicy PortableServer_POA_create_thread_policy(
++ PortableServer_POA obj,
++ PortableServer_ThreadPolicyValue value,
++ CORBA_Environment *ev);
++
++extern PortableServer_LifespanPolicy PortableServer_POA_create_lifespan_policy(
++ PortableServer_POA obj,
++ PortableServer_LifespanPolicyValue value,
++ CORBA_Environment *ev);
++
++extern PortableServer_IdUniquenessPolicy PortableServer_POA_create_id_uniqueness_policy(
++ PortableServer_POA obj,
++ PortableServer_IdUniquenessPolicyValue value,
++ CORBA_Environment *ev);
++
++extern PortableServer_IdAssignmentPolicy PortableServer_POA_create_id_assignment_policy(
++ PortableServer_POA obj,
++ PortableServer_IdAssignmentPolicyValue value,
++ CORBA_Environment *ev);
++
++extern PortableServer_ImplicitActivationPolicy PortableServer_POA_create_implicit_activation_policy(
++ PortableServer_POA obj,
++ PortableServer_ImplicitActivationPolicyValue value,
++ CORBA_Environment *ev);
++
++extern PortableServer_ServantRetentionPolicy PortableServer_POA_create_servant_retention_policy(
++ PortableServer_POA obj,
++ PortableServer_ServantRetentionPolicyValue value,
++ CORBA_Environment *ev);
++
++extern PortableServer_RequestProcessingPolicy PortableServer_POA_create_request_processing_policy(
++ PortableServer_POA obj,
++ PortableServer_RequestProcessingPolicyValue value,
++ CORBA_Environment *ev);
++
++extern CORBA_char *PortableServer_POA__get_the_name(
++ PortableServer_POA obj,
++ CORBA_Environment *ev);
++
++extern PortableServer_POA PortableServer_POA__get_the_parent(
++ PortableServer_POA obj,
++ CORBA_Environment *ev);
++
++extern PortableServer_POAManager PortableServer_POA__get_the_POAManager(
++ PortableServer_POA obj,
++ CORBA_Environment *ev);
++
++extern PortableServer_AdapterActivator PortableServer_POA__get_the_activator(
++ PortableServer_POA obj,
++ CORBA_Environment *ev);
++
++extern void PortableServer_POA__set_the_activator(
++ PortableServer_POA obj,
++ PortableServer_AdapterActivator the_activator,
++ CORBA_Environment *ev);
++
++extern PortableServer_ServantManager PortableServer_POA_get_servant_manager(
++ PortableServer_POA obj,
++ CORBA_Environment *ev);
++
++extern void PortableServer_POA_set_servant_manager(
++ PortableServer_POA obj,
++ PortableServer_ServantManager imgr,
++ CORBA_Environment *ev);
++
++extern PortableServer_Servant PortableServer_POA_get_servant(
++ PortableServer_POA obj,
++ CORBA_Environment *ev);
++
++extern void PortableServer_POA_set_servant(
++ PortableServer_POA obj,
++ PortableServer_Servant p_servant,
++ CORBA_Environment *ev);
++
++extern PortableServer_ObjectId *PortableServer_POA_activate_object(
++ PortableServer_POA obj,
++ PortableServer_Servant p_servant,
++ CORBA_Environment *ev);
++
++extern void PortableServer_POA_activate_object_with_id(
++ PortableServer_POA obj,
++ PortableServer_ObjectId *id,
++ PortableServer_Servant p_servant,
++ CORBA_Environment *ev);
++
++extern void PortableServer_POA_deactivate_object(
++ PortableServer_POA obj,
++ PortableServer_ObjectId *oid,
++ CORBA_Environment *ev);
++
++extern CORBA_Object PortableServer_POA_create_reference(
++ PortableServer_POA obj,
++ CORBA_RepositoryId intf,
++ CORBA_Environment *ev);
++
++extern CORBA_Object PortableServer_POA_create_reference_with_id(
++ PortableServer_POA obj,
++ PortableServer_ObjectId *oid,
++ CORBA_RepositoryId intf,
++ CORBA_Environment *ev);
++
++extern PortableServer_ObjectId *PortableServer_POA_servant_to_id(
++ PortableServer_POA obj,
++ PortableServer_Servant p_servant,
++ CORBA_Environment *ev);
++
++extern CORBA_Object PortableServer_POA_servant_to_reference(
++ PortableServer_POA obj,
++ PortableServer_Servant p_servant,
++ CORBA_Environment *ev);
++
++extern PortableServer_Servant PortableServer_POA_reference_to_servant(
++ PortableServer_POA obj,
++ CORBA_Object reference,
++ CORBA_Environment *ev);
++
++extern PortableServer_ObjectId *PortableServer_POA_reference_to_id(
++ PortableServer_POA obj,
++ CORBA_Object reference,
++ CORBA_Environment *ev);
++
++extern PortableServer_Servant PortableServer_POA_id_to_servant(
++ PortableServer_POA obj,
++ PortableServer_ObjectId *oid,
++ CORBA_Environment *ev);
++
++extern CORBA_Object PortableServer_POA_id_to_reference(
++ PortableServer_POA obj,
++ PortableServer_ObjectId *oid,
++ CORBA_Environment *ev);
++
++extern PortableServer_POA PortableServer_Current_get_POA(
++ PortableServer_Current obj,
++ CORBA_Environment *ev);
++
++extern PortableServer_ObjectId *PortableServer_Current_get_object_id(
++ PortableServer_Current obj,
++ CORBA_Environment *ev);
++
++extern CORBA_char *PortableServer_ObjectId_to_string(
++ PortableServer_ObjectId *id,
++ CORBA_Environment *env);
++
++extern CORBA_wchar *PortableServer_ObjectId_to_wstring(
++ PortableServer_ObjectId *id,
++ CORBA_Environment *env);
++
++extern PortableServer_ObjectId *PortableServer_string_to_ObjectId(
++ CORBA_char *str,
++ CORBA_Environment *env);
++
++extern PortableServer_ObjectId *PortableServer_wstring_to_ObjectId(
++ CORBA_wchar *str,
++ CORBA_Environment *env);
++
++extern PortableServer_POA PortableServer_ServantBase__default_POA(
++ PortableServer_Servant,
++ CORBA_Environment *);
++
++extern void PortableServer_ServantLocator_preinvoke(
++ PortableServer_ObjectId *oid,
++ PortableServer_POA adapter,
++ CORBA_Identifier op_name,
++ PortableServer_ServantLocator_Cookie *cookie);
++
++extern void PortableServer_ServantLocator_postinvoke(
++ PortableServer_ObjectId *oid,
++ PortableServer_POA adapter,
++ CORBA_Identifier op_name,
++ PortableServer_ServantLocator_Cookie cookie,
++ PortableServer_Servant servant);
++
++extern void PortableServer_ServantBase__init(
++ PortableServer_Servant,
++ CORBA_Environment *);
++
++extern void PortableServer_ServantBase__fini(
++ PortableServer_Servant,
++ CORBA_Environment *);
++
++/* 19.27 */
++extern CORBA_Identifier CORBA_ServerRequest_operation(
++ CORBA_ServerRequest req,
++ CORBA_Environment *env);
++
++extern CORBA_Context CORBA_ServerRequest_ctx(
++ CORBA_ServerRequest req,
++ CORBA_Environment *env);
++
++extern void CORBA_ServerRequest_arguments(
++ CORBA_ServerRequest req,
++ CORBA_NVList *parameters,
++ CORBA_Environment *env);
++
++extern void CORBA_ServerRequest_set_result(
++ CORBA_ServerRequest req,
++ CORBA_any *value,
++ CORBA_Environment *env);
++
++extern void CORBA_ServerRequest_set_exception(
++ CORBA_ServerRequest req,
++ CORBA_exception_type major,
++ CORBA_any *value,
++ CORBA_Environment *env);
++
++extern void PortableServer_DynamicImpl__init(PortableServer_Servant,
++ CORBA_Environment *ev);
++
++extern void PortableServer_DynamicImpl__fini(PortableServer_Servant,
++ CORBA_Environment *ev);
++
++
++#include "orbit_poa_type.h"
++
++#endif /* !_ORBIT_POA_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/sequences.c linux-2.4.1-korbit/net/korbit/orb/sequences.c
+--- linux-2.4.1/net/korbit/orb/sequences.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/sequences.c Thu Feb 1 11:47:14 2001
+@@ -0,0 +1,35 @@
++#include "orbit.h"
++#include "sequences.h"
++
++gpointer CORBA_sequence_octet_free(gpointer mem,
++ gpointer func_data)
++{
++ CORBA_sequence_octet *seqo = mem;
++
++ if(seqo->_release)
++ CORBA_free(seqo->_buffer);
++
++ return (gpointer)((guchar *)mem + sizeof(CORBA_sequence_octet));
++}
++
++CORBA_octet *
++CORBA_octet_allocbuf(CORBA_unsigned_long len)
++{
++ return (CORBA_octet *)ORBit_alloc(len, NULL, NULL);
++}
++
++CORBA_sequence_octet *CORBA_sequence_octet__alloc(void)
++{
++ CORBA_sequence_octet *seqo;
++
++ seqo = ORBit_alloc(sizeof(CORBA_sequence_octet),
++ (ORBit_free_childvals)CORBA_sequence_octet_free,
++ GUINT_TO_POINTER(1));
++
++ seqo->_length = seqo->_maximum = 0;
++ seqo->_buffer = NULL;
++ seqo->_release = CORBA_TRUE;
++
++ return seqo;
++}
++
+diff -urN linux-2.4.1/net/korbit/orb/sequences.h linux-2.4.1-korbit/net/korbit/orb/sequences.h
+--- linux-2.4.1/net/korbit/orb/sequences.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/sequences.h Thu Feb 1 16:21:19 2001
+@@ -0,0 +1,35 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_SEQUENCES_H_
++#define _ORBIT_SEQUENCES_H_
++
++/* #include "corba_sequences_type.h" */
++#include "orbit_types.h"
++
++CORBA_octet *CORBA_octet_allocbuf(CORBA_unsigned_long len);
++CORBA_sequence_octet *CORBA_sequence_octet__alloc(void);
++
++#endif /* !_ORBIT_SEQUENCES_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/server.c linux-2.4.1-korbit/net/korbit/orb/server.c
+--- linux-2.4.1/net/korbit/orb/server.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/server.c Thu Feb 1 11:47:14 2001
+@@ -0,0 +1,217 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/* Elliot's stuff */
++/* This is somewhat a mess, because I tried to make it easy to add
++ select() support, and as a result #ifdef's litter the land. */
++
++#include "orbit.h"
++#include "orbit_poa.h"
++#include "orbit_poa_type.h"
++#include <IIOP/IIOP-private.h>
++#ifdef HAVE_SYS_POLL_H
++#include <sys/poll.h>
++#endif
++#include <sys/types.h>
++#include <sys/socket.h>
++
++/* We need:
++ a way to find out what FD's need to be selected on
++ a dummy main loop to implement the CORBA_ORB_run() routine;
++*/
++
++gboolean orb_server_keep_running = FALSE;
++
++ORBit_request_validate ORBIT_request_validator = NULL;
++
++/* function protos */
++static PortableServer_POA ORBit_find_POA_for_request(PortableServer_POA poa,
++ GIOPRecvBuffer *recv_buffer);
++static PortableServer_POA ORBit_find_POA_for_locate_request(PortableServer_POA poa,
++ GIOPRecvBuffer *recv_buffer);
++
++static void ORBit_handle_incoming_message(GIOPRecvBuffer *recv_buffer);
++
++void
++ORBit_custom_run_setup(CORBA_ORB orb, CORBA_Environment *ev)
++{
++ IIOPIncomingMessageHandler = ORBit_handle_incoming_message;
++}
++
++
++#if __KERNEL__
++// Modules don't do anything when they call this...
++void CORBA_ORB_run(CORBA_ORB orb, CORBA_Environment *ev) {
++ // This should probably free the ORB pointer, because it is a
++ // duplicated pointer from the one true orb.
++
++}
++
++// The ORB thread calls __CORBA_ORB_run by itself.
++#define CORBA_ORB_run __CORBA_ORB_run
++
++#endif
++
++void
++CORBA_ORB_run(CORBA_ORB orb, CORBA_Environment *ev)
++{
++ ORBit_custom_run_setup(orb, ev);
++
++ orb_server_keep_running = TRUE;
++
++ giop_main();
++}
++
++static void
++ORBit_handle_incoming_request(GIOPRecvBuffer *recv_buffer)
++{
++ CORBA_ORB orb;
++ PortableServer_POA poa;
++ GIOPConnection *connection;
++ ORBit_MessageValidationResult mvr;
++ gboolean do_unuse = TRUE;
++
++ g_assert(recv_buffer);
++
++ connection = GIOP_MESSAGE_BUFFER(recv_buffer)->connection;
++ g_return_if_fail(connection != NULL);
++
++ orb = connection->orb_data;
++
++ g_return_if_fail(orb != NULL);
++
++ ORBit_Trace(TraceMod_ORB, TraceLevel_Debug,
++ "Received request %s, id %d, on %s",
++ recv_buffer->message.u.request.operation,
++ recv_buffer->message.u.request.request_id,
++ recv_buffer->message.u.request.object_key._buffer);
++
++ if(ORBIT_request_validator)
++ mvr = ORBIT_request_validator(recv_buffer->message.u.request.request_id,
++ &recv_buffer->message.u.request.requesting_principal,
++ recv_buffer->message.u.request.operation);
++ else
++ mvr = ORBIT_MESSAGE_ALLOW;
++
++ if(mvr == ORBIT_MESSAGE_ALLOW_ALL)
++ connection->is_auth = TRUE;
++
++ if(mvr != ORBIT_MESSAGE_BAD) {
++ /* Find the POA for this incoming request */
++ poa = ORBit_find_POA_for_request((PortableServer_POA)orb->root_poa,
++ recv_buffer);
++
++ if(poa)
++ do_unuse = ORBit_POA_handle_request(recv_buffer, poa);
++ else
++ g_warning("No POA found for operation %s [%d]",
++ recv_buffer->message.u.request.operation,
++ recv_buffer->message.u.request.request_id);
++ } else {
++ g_warning("Request %s, ID %d was rejected by the authentication mechanism!",
++ recv_buffer->message.u.request.operation,
++ recv_buffer->message.u.request.request_id);
++ }
++
++ if(do_unuse)
++ giop_recv_buffer_unuse(recv_buffer);
++}
++
++static void
++ORBit_handle_incoming_locate_request(GIOPRecvBuffer *recv_buffer)
++{
++ CORBA_ORB orb;
++ PortableServer_POA poa;
++ GIOPConnection *connection;
++ GIOPSendBuffer *send_buffer;
++
++ g_assert(recv_buffer!=NULL);
++
++ connection = GIOP_MESSAGE_BUFFER(recv_buffer)->connection;
++ g_return_if_fail(connection != NULL);
++
++ orb = connection->orb_data;
++
++ g_return_if_fail(orb != NULL);
++
++ ORBit_Trace(TraceMod_ORB, TraceLevel_Debug,
++ "Received locate request id %d, on %s",
++ recv_buffer->message.u.locate_request.request_id,
++ recv_buffer->message.u.locate_request.object_key._buffer);
++ /* Find the POA for this incoming request */
++ poa = ORBit_find_POA_for_locate_request((PortableServer_POA)orb->root_poa, recv_buffer);
++
++ if(poa) {
++ /* Object found, reply with "Object Here" */
++ send_buffer = giop_send_locate_reply_buffer_use(connection,
++ recv_buffer->message.u.locate_request.request_id,
++ GIOP_OBJECT_HERE);
++ giop_send_buffer_write(send_buffer);
++ giop_send_buffer_unuse(send_buffer);
++ } else {
++ /* Object not found, reply with "Unknown Object" */
++ send_buffer = giop_send_locate_reply_buffer_use(connection,
++ recv_buffer->message.u.locate_request.request_id,
++ GIOP_UNKNOWN_OBJECT);
++ giop_send_buffer_write(send_buffer);
++ giop_send_buffer_unuse(send_buffer);
++ }
++
++ giop_recv_buffer_unuse(recv_buffer);
++}
++
++static void
++ORBit_handle_incoming_message(GIOPRecvBuffer *recv_buffer)
++{
++ GIOPConnection *connection;
++
++ g_assert(recv_buffer);
++
++ connection = GIOP_MESSAGE_BUFFER(recv_buffer)->connection;
++ g_return_if_fail(connection != NULL);
++
++ switch(GIOP_MESSAGE_BUFFER(recv_buffer)->message_header.message_type) {
++ case GIOP_REQUEST:
++ ORBit_handle_incoming_request(recv_buffer);
++ break;
++ case GIOP_LOCATEREQUEST:
++ ORBit_handle_incoming_locate_request(recv_buffer);
++ break;
++ case GIOP_CLOSECONNECTION:
++ /* Lame hack - need to do this in a manner that isn't
++ IIOP-specific */
++ giop_recv_buffer_unuse(recv_buffer);
++ giop_main_handle_connection_exception(connection);
++ break;
++ case GIOP_REPLY:
++ /* the above comment probably applies here also... */
++ giop_received_list_push(recv_buffer);
++ break;
++ default:
++ g_warning("discarding message type %d (id possibly %d)",
++ GIOP_MESSAGE_BUFFER(recv_buffer)->message_header.message_type,
++ GIOP_MESSAGE_BUFFER(recv_buffer)->message_header.message_type?recv_buffer->message.u.reply.request_id:recv_buffer->message.u.request.request_id);
++ break;
++ }
++}
++
++static PortableServer_POA
++ORBit_find_POA_for_request(PortableServer_POA poa,
++ GIOPRecvBuffer *recv_buffer)
++{
++ return ORBit_POA_find_POA_for_object_key(poa,
++ &recv_buffer->message.u.request.object_key);
++}
++
++static PortableServer_POA
++ORBit_find_POA_for_locate_request(PortableServer_POA poa,
++ GIOPRecvBuffer *recv_buffer)
++{
++ return ORBit_POA_find_POA_for_object_key(poa,
++ &recv_buffer->message.u.locate_request.object_key);
++}
++
++void
++ORBit_set_request_validation_handler(ORBit_request_validate validator)
++{
++ ORBIT_request_validator = validator;
++}
+diff -urN linux-2.4.1/net/korbit/orb/typecode.c linux-2.4.1-korbit/net/korbit/orb/typecode.c
+--- linux-2.4.1/net/korbit/orb/typecode.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/typecode.c Thu Feb 1 11:47:14 2001
+@@ -0,0 +1,104 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter, Red Hat Software
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ * Elliot Lee <sopwith@cuc.edu>
++ *
++ */
++
++#include "orbit.h"
++#include "orbit_typecode.h"
++
++const struct CORBA_TypeCode_struct TC_null_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_null, "null", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_void_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_void, "void", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_short_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_short, "short", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_long_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_long, "long", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_longlong_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_longlong, "long long", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_ushort_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_ushort, "unsigned short", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_ulong_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_ulong, "unsigned long", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_ulonglong_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_ulonglong, "unsigned long long", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_float_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_float, "float", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_double_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_double, "double", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_longdouble_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_longdouble, "long double", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_boolean_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_boolean, "boolean", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_char_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_char, "char", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_wchar_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_wchar, "wide char", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_octet_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_octet, "octet", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_any_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_any, "any", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_TypeCode_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_TypeCode, "TypeCode", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_Principal_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_Principal, "Principal", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_Object_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_objref, "Object Reference", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_string_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_string, "string", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_wstring_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_wstring, "wide string", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_CORBA_NamedValue_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_struct, "CORBA NamedValue", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++
++static const CORBA_TypeCode anon_subtypes_array7[] =
++{(CORBA_TypeCode) & TC_CORBA_string_struct};
++
++#if (TC_IMPL_TC_CORBA_Identifier_0 == '/')
++const struct CORBA_TypeCode_struct TC_CORBA_Identifier_struct =
++{
++ {
++ {(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1}, ORBIT_PSEUDO_TYPECODE},
++ CORBA_tk_alias, "Identifier", "IDL:omg.org/CORBA/Identifier:1.0",
++ 0, 1,
++ NULL,
++ (CORBA_TypeCode *) anon_subtypes_array7,
++ NULL,
++ CORBA_OBJECT_NIL, 0, -1, 0, 0
++};
++#endif
++
++#if (TC_IMPL_TC_CORBA_RepositoryId_0 == '/')
++const struct CORBA_TypeCode_struct TC_CORBA_RepositoryId_struct =
++{
++ {
++ {(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1}, ORBIT_PSEUDO_TYPECODE},
++ CORBA_tk_alias, "RepositoryId", "IDL:omg.org/CORBA/RepositoryId:1.0",
++ 0, 1,
++ NULL,
++ (CORBA_TypeCode *) anon_subtypes_array7,
++ NULL,
++ CORBA_OBJECT_NIL, 0, -1, 0, 0
++};
++#endif
+diff -urN linux-2.4.1/net/korbit/orb/typecode.h linux-2.4.1-korbit/net/korbit/orb/typecode.h
+--- linux-2.4.1/net/korbit/orb/typecode.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/typecode.h Thu Feb 1 11:47:14 2001
+@@ -0,0 +1,31 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_TYPECODE_H_
++#define _ORBIT_TYPECODE_H_
++
++#include "orbit_types.h"
++
++#endif /* !_ORBIT_TYPECODE_H_ */
+diff -urN linux-2.4.1/net/korbit/sup/CVS/Entries linux-2.4.1-korbit/net/korbit/sup/CVS/Entries
+--- linux-2.4.1/net/korbit/sup/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/sup/CVS/Entries Thu Feb 1 11:47:15 2001
+@@ -0,0 +1 @@
++D
+diff -urN linux-2.4.1/net/korbit/sup/CVS/Repository linux-2.4.1-korbit/net/korbit/sup/CVS/Repository
+--- linux-2.4.1/net/korbit/sup/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/sup/CVS/Repository Thu Feb 1 11:47:15 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/sup
+diff -urN linux-2.4.1/net/korbit/sup/CVS/Root linux-2.4.1-korbit/net/korbit/sup/CVS/Root
+--- linux-2.4.1/net/korbit/sup/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/sup/CVS/Root Thu Feb 1 11:47:15 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
diff --git a/fs/libmysqlfs.c b/fs/libmysqlfs.c
new file mode 100644
index 00000000000..fde325c3c42
--- /dev/null
+++ b/fs/libmysqlfs.c
@@ -0,0 +1,151 @@
+/* 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 "libmysqlfs.h"
+
+int search_and_replace(char *search, char* replace, char* string)
+{
+ char buff[1024];
+ int found=0;
+ char *ptr1;
+ const char *ptr2=buff;
+ char *strptr=string;
+
+ DBUG_ENTER("search_and_replace");
+ DBUG_PRINT("enter",("search: '%s' replace:'%s' string:'%s'",search,replace,string));
+ strcpy(buff,string);
+ while(ptr1=strstr(ptr2,search))
+ {
+ strncpy(strptr,ptr2,ptr1-buff);
+ strptr+=ptr1-buff;
+ ptr2+=ptr1-buff+strlen(search);
+ strcpy(strptr,replace);
+ strptr+=strlen(replace);
+ found++;
+ }
+ DBUG_RETURN(found);
+}
+
+int show_functions(char *b, function_type type)
+{
+ int i=0,j=0;
+ struct func_st func;
+ DBUG_ENTER("show_functions");
+ get_dynamic(&functions_array,(gptr)&func,i);
+ while(func.length) {
+ if (func.type == type)
+ strcpy(&b[j++*BUFLEN],func.filename);
+ get_dynamic(&functions_array,(gptr)&func,++i);
+ }
+ DBUG_RETURN(j);
+}
+
+struct func_st * check_if_function(char *name, function_type type)
+{
+ int pathlen;
+ int j,i=0, len;
+ static struct func_st function;
+ char buffer[BUFLEN];
+
+ DBUG_ENTER("check_if_function");
+ DBUG_PRINT("enter",("name: '%s' type: '%d'", name, type));
+ pathlen=strlen(name);
+
+ /* We try to compare last element in path to function names */
+ get_dynamic(&functions_array,(gptr)&function,i);
+ while(function.length) {
+ function.continuous ?
+ (j=!strncasecmp(function.filename, name, function.length))
+ : (j=!strcasecmp(function.filename,name));
+ if(j) { /* This happens when function was matched */
+ DBUG_PRINT("info",("Function %s detected!",function.filename));
+ break;
+ }
+ get_dynamic(&functions_array,(gptr)&function,++i);
+ }
+
+ /* Copy path to buffer and trip function name (if found) from it */
+ if(function.length != 0)
+ {
+ DBUG_RETURN(&function);
+ } else {
+ DBUG_RETURN(0);
+ }
+}
+
+/*
+ * parse - splits "path" into different variables
+ * in way "/server/database/table/(field|key)/(value|function)". If path is shorter,
+ * then other fields will be NULL. If path is longer than four levels or
+ * shorter than one level, FS_NOTEXIST is returned.
+ */
+int parse(const char * path, char *server, char * database, char *table,
+ char* field, char* value, struct func_st **funce)
+{
+ char buffer[BUFLEN];
+ char *p=buffer;
+ char *x;
+ int len;
+
+ DBUG_ENTER("parse");
+ DBUG_PRINT("enter",("path: '%s'", path));
+
+ *server=*database=*table=*field=*value='\0';
+
+ /* Search for first slash and drop it */
+ strcpy(buffer,path);
+ x=strtok_r(p,"/",&p);
+ if(x)
+ {
+ strcpy(server,x); /* First argument is server name */
+ if(*p)
+ strcpy(database,strtok_r(p,"/",&p)); /* Second is database */
+ if(p && *p)
+ strcpy(table ,strtok_r(p,"/",&p)); /* Third is table name */
+ if(p && *p)
+ strcpy(field ,strtok_r(p,"/",&p)); /* Fourth is field or key name */
+ if(p && *p)
+ strcpy(value ,strtok_r(p,"/",&p)); /* Fifth is field/key value or function */
+ }
+
+ /* We have to find if last argument is function,
+ * In which case we clear it
+ */
+ if(*value) {
+ *funce=check_if_function(value,VALUE_FUNCTION);
+ if(*funce) *value='\0';
+ } else if (*field) {
+ *funce=check_if_function(field,FIELD_FUNCTION);
+ if(*funce) *field='\0';
+ } else if (*table) {
+ *funce=check_if_function(table,TABLE_FUNCTION);
+ if(*funce) *table='\0';
+ } else if (*database) {
+ *funce=check_if_function(database,DATABASE_FUNCTION);
+ if(*funce) *database='\0';
+ } else if (*server) {
+ *funce=check_if_function(server,SERVER_FUNCTION);
+ if(*funce) *server='\0';
+ } else
+ *funce=NULL;
+
+ DBUG_PRINT("info",("path: '%s', server: '%s', db: '%s', table: '%s', field: '%s', value: '%s', function: '%x'",
+ buffer, server, database, table, field, value, funce ));
+ if(p && *p) /* Something is in buffer - too deep in levels */
+ DBUG_RETURN(-1)
+ else
+ DBUG_RETURN(0)
+}
diff --git a/fs/libmysqlfs.h b/fs/libmysqlfs.h
new file mode 100644
index 00000000000..0e95daaa791
--- /dev/null
+++ b/fs/libmysqlfs.h
@@ -0,0 +1,81 @@
+/* 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 "CorbaFS.h"
+
+#include <my_global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include <m_ctype.h>
+#include "mysql.h"
+
+#define BUFLEN 1024
+#define MAXDIRS 1024
+
+typedef enum {
+ FUNC_NONE,
+ FUNC_SERVER_UPTIME,
+ FUNC_SERVER_THREADS,
+ FUNC_SERVER_VERSION,
+ FUNC_DATABASE_CREATED,
+ FUNC_TABLE_COUNT,
+ FUNC_TABLE_CREATED,
+ FUNC_FIELD_LENGTH,
+ FUNC_KEY_AVG,
+ FUNC_KEY_SUM,
+ FUNC_KEY_MAX,
+ FUNC_KEY_MIN
+} func_enum;
+
+
+typedef enum {
+ NONE_FUNCTION,
+ ROOT_FUNCTION,
+ SERVER_FUNCTION,
+ DATABASE_FUNCTION,
+ TABLE_FUNCTION,
+ KEY_FUNCTION,
+ FIELD_FUNCTION,
+ VALUE_FUNCTION
+} function_type;
+
+struct func_st {
+ char type_s[20];
+ char filename[20];
+ char function[80];
+ function_type type;
+ int length;
+ my_bool continuous;
+} ;
+
+
+int parse(const char* path,
+ char* root,
+ char* database,
+ char* table,
+ char* key,
+ char* field,
+ struct func_st **func
+);
+
+gptr db_load_functions();
+int db_function(char *b,const char *server, const char *database,const char *table,const char *field,
+ const char *value, const char *path, struct func_st *function);
+int fix_filenames(char *buf);
+
+DYNAMIC_ARRAY functions_array;
+
+
diff --git a/fs/my.cnf b/fs/my.cnf
new file mode 100644
index 00000000000..e70f2c30cbf
--- /dev/null
+++ b/fs/my.cnf
@@ -0,0 +1,5 @@
+[mysqlcorbafs]
+socket=/var/lib/mysql/mysql.sock
+host=127.0.0.1
+user=root
+#password=xxxxxx
diff --git a/fs/mysqlcorbafs.c b/fs/mysqlcorbafs.c
new file mode 100644
index 00000000000..8943c00ed25
--- /dev/null
+++ b/fs/mysqlcorbafs.c
@@ -0,0 +1,991 @@
+/* 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
+ */
+
+
+/*
+ *
+ * fsck.mysql
+ */
+
+#include "libmysqlfs.h"
+#include "mysqlcorbafs.h"
+#include <getopt.h>
+#define MAXPATHLEN 256
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+#include <my_sys.h>
+static long inodeNum;
+
+extern DYNAMIC_ARRAY functions_array;
+enum options {OPT_FTB=256, OPT_LTB, OPT_ENC, OPT_O_ENC, OPT_ESC, OPT_KEYWORDS,
+ OPT_LOCKS, OPT_DROP, OPT_OPTIMIZE, OPT_DELAYED, OPT_TABLES,
+ OPT_CHARSETS_DIR, OPT_DEFAULT_CHARSET};
+
+CHANGEABLE_VAR changeable_vars[] = {
+ { "max_allowed_packet", (long*) &max_allowed_packet,24*1024*1024,4096,
+ 24*1024L*1024L,MALLOC_OVERHEAD,1024},
+ { "net_buffer_length", (long*) &net_buffer_length,1024*1024L-1025,4096,
+ 24*1024L*1024L,MALLOC_OVERHEAD,1024},
+ { 0, 0, 0, 0, 0, 0, 0}
+};
+
+CORBA_ORB orb;
+PortableServer_POA poa;
+CORBA_Environment *ev;
+PortableServer_ObjectId *objid;
+static my_bool verbose=0,opt_compress=0,extended_insert=0, lock_tables=0,
+ opt_quoted=0, opt_lock=0, opt_delayed=0, ignore_errors=0;
+
+gptr fptr;
+
+static const char *load_default_groups[]= { "mysqlcorbafs","client",0 };
+static char *default_charset, *current_host, *current_user, *opt_password,
+ *path,*fields_terminated=0, *lines_terminated=0, *enclosed=0,
+ *opt_enclosed=0, *escaped=0;
+
+static struct option long_options[] =
+{
+ {"add-locks", no_argument, 0,OPT_LOCKS},
+ {"character-sets-dir",required_argument,0, OPT_CHARSETS_DIR},
+ {"compress", no_argument, 0, 'C'},
+ {"database",required_argument, 0, 'D'},
+ {"debug",optional_argument, 0, '#'},
+ {"default-character-set", required_argument, 0, OPT_DEFAULT_CHARSET},
+ {"delayed-insert",no_argument, 0, OPT_DELAYED},
+ {"fields-terminated-by", required_argument, 0, (int) OPT_FTB},
+ {"fields-enclosed-by", required_argument,0, (int) OPT_ENC},
+ {"fields-optionally-enclosed-by", required_argument, 0, (int) OPT_O_ENC},
+ {"fields-escaped-by", required_argument,0, (int) OPT_ESC},
+ {"functions",required_argument, 0, 'f'},
+ {"help", no_argument, 0,'?'},
+ {"host", required_argument,0, 'h'},
+ {"lines-terminated-by", required_argument, 0, (int) OPT_LTB},
+ {"lock-tables", no_argument, 0, 'l'},
+ {"no-data", no_argument, 0, 'd'},
+ {"password", optional_argument, 0, 'p'},
+#ifdef __WIN__
+ {"pipe",no_argument,0, 'W'},
+#endif
+ {"port", required_argument,0, 'P'},
+// {"quick", no_argument,0, 'q'},
+ {"quote-names",no_argument,0, 'Q'},
+ {"set-variable",required_argument,0, 'O'},
+ {"socket", required_argument,0, 'S'},
+#include "sslopt-longopts.h"
+#ifndef DONT_ALLOW_USER_CHANGE
+ {"user", required_argument,0, 'u'},
+#endif
+ {"verbose", no_argument,0, 'v'},
+ {"version", no_argument,0, 'V'},
+ {0, 0, 0, 0}
+};
+
+
+/*
+void
+print_table_data(MYSQL_RES *result)
+{
+ String separator(256);
+ MYSQL_ROW cur;
+ MYSQL_FIELD *field;
+ bool *num_flag;
+
+ num_flag=(bool*) my_alloca(sizeof(bool)*mysql_num_fields(result));
+ if (info_flag)
+ {
+ print_field_types(result);
+ mysql_field_seek(result,0);
+ }
+ separator.copy("+",1);
+ while ((field = mysql_fetch_field(result)))
+ {
+ uint length=skip_column_names ? 0 : (uint) strlen(field->name);
+ if (quick)
+ length=max(length,field->length);
+ else
+ length=max(length,field->max_length);
+ if (length < 4 && !IS_NOT_NULL(field->flags))
+ length=4; // Room for "NULL"
+ field->max_length=length+1;
+ separator.fill(separator.length()+length+2,'-');
+ separator.append('+');
+ }
+ tee_puts(separator.c_ptr(), PAGER);
+ if (!skip_column_names)
+ {
+ mysql_field_seek(result,0);
+ (void) tee_fputs("|", PAGER);
+ for (uint off=0; (field = mysql_fetch_field(result)) ; off++)
+ {
+ tee_fprintf(PAGER, " %-*s|",min(field->max_length,MAX_COLUMN_LENGTH),
+ field->name);
+ num_flag[off]= IS_NUM(field->type);
+ }
+ (void) tee_fputs("\n", PAGER);
+ tee_puts(separator.c_ptr(), PAGER);
+ }
+
+ while ((cur = mysql_fetch_row(result)))
+ {
+ (void) tee_fputs("|", PAGER);
+ mysql_field_seek(result,0);
+ for (uint off=0 ; off < mysql_num_fields(result); off++)
+ {
+ const char *str=cur[off] ? cur[off] : "NULL";
+ field = mysql_fetch_field(result);
+ uint length=field->max_length;
+ if (length > MAX_COLUMN_LENGTH)
+ {
+ tee_fputs(str,PAGER); tee_fputs(" |",PAGER);
+ }
+ else
+ tee_fprintf(PAGER, num_flag[off] ? "%*s |" : " %-*s|",
+ length, str);
+ }
+ (void) tee_fputs("\n", PAGER);
+ }
+ tee_puts(separator.c_ptr(), PAGER);
+ my_afree((gptr) num_flag);
+}
+
+void
+print_table_data_html(MYSQL_RES *result)
+{
+ MYSQL_ROW cur;
+ MYSQL_FIELD *field;
+
+ mysql_field_seek(result,0);
+ (void) tee_fputs("<TABLE BORDER=1><TR>", PAGER);
+ if (!skip_column_names)
+ {
+ while((field = mysql_fetch_field(result)))
+ {
+ tee_fprintf(PAGER, "<TH>%s</TH>", (field->name ?
+ (field->name[0] ? field->name :
+ " &nbsp; ") : "NULL"));
+ }
+ (void) tee_fputs("</TR>", PAGER);
+ }
+ while ((cur = mysql_fetch_row(result)))
+ {
+ (void) tee_fputs("<TR>", PAGER);
+ for (uint i=0; i < mysql_num_fields(result); i++)
+ {
+ ulong *lengths=mysql_fetch_lengths(result);
+ (void) tee_fputs("<TD>", PAGER);
+ safe_put_field(cur[i],lengths[i]);
+ (void) tee_fputs("</TD>", PAGER);
+ }
+ (void) tee_fputs("</TR>", PAGER);
+ }
+ (void) tee_fputs("</TABLE>", PAGER);
+}
+
+
+void
+print_table_data_xml(MYSQL_RES *result)
+{
+ MYSQL_ROW cur;
+ MYSQL_FIELD *fields;
+
+ mysql_field_seek(result,0);
+
+ char *statement;
+ statement=(char*) my_malloc(strlen(glob_buffer.ptr())*5+1, MYF(MY_WME));
+ xmlencode(statement, (char*) glob_buffer.ptr());
+
+ (void) my_chomp(strend(statement));
+
+ tee_fprintf(PAGER,"<?xml version=\"1.0\"?>\n\n<resultset statement=\"%s\">", statement);
+
+ my_free(statement,MYF(MY_ALLOW_ZERO_PTR));
+
+ fields = mysql_fetch_fields(result);
+
+ while ((cur = mysql_fetch_row(result)))
+ {
+ (void) tee_fputs("\n <row>\n", PAGER);
+ for (uint i=0; i < mysql_num_fields(result); i++)
+ {
+ char *data;
+ ulong *lengths=mysql_fetch_lengths(result);
+ data=(char*) my_malloc(lengths[i]*5+1, MYF(MY_WME));
+ tee_fprintf(PAGER, "\t<%s>", (fields[i].name ?
+ (fields[i].name[0] ? fields[i].name :
+ " &nbsp; ") : "NULL"));
+ xmlencode(data, cur[i]);
+ safe_put_field(data, strlen(data));
+ tee_fprintf(PAGER, "</%s>\n", (fields[i].name ?
+ (fields[i].name[0] ? fields[i].name :
+ " &nbsp; ") : "NULL"));
+ my_free(data,MYF(MY_ALLOW_ZERO_PTR));
+ }
+ (void) tee_fputs(" </row>\n", PAGER);
+ }
+ (void) tee_fputs("</resultset>\n", PAGER);
+}
+
+
+void
+print_table_data_vertically(MYSQL_RES *result)
+{
+ MYSQL_ROW cur;
+ uint max_length=0;
+ MYSQL_FIELD *field;
+
+ while ((field = mysql_fetch_field(result)))
+ {
+ uint length=(uint) strlen(field->name);
+ if (length > max_length)
+ max_length= length;
+ field->max_length=length;
+ }
+
+ mysql_field_seek(result,0);
+ for (uint row_count=1; (cur= mysql_fetch_row(result)); row_count++)
+ {
+ mysql_field_seek(result,0);
+ tee_fprintf(PAGER,
+ "*************************** %d. row ***************************\n", row_count);
+ for (uint off=0; off < mysql_num_fields(result); off++)
+ {
+ field= mysql_fetch_field(result);
+ tee_fprintf(PAGER, "%*s: ",(int) max_length,field->name);
+ tee_fprintf(PAGER, "%s\n",cur[off] ? (char*) cur[off] : "NULL");
+ }
+ }
+}
+
+
+
+*/
+
+
+
+static my_bool test_if_special_chars(const char *str)
+{
+ for ( ; *str ; str++)
+ if (!isvar(*str) && *str != '$')
+ return 1;
+ return 0;
+} /* test_if_special_chars */
+
+char *quote_name(char *name, char *buff)
+{
+ char *end;
+ DBUG_ENTER("quote_name");
+ if (!opt_quoted && !test_if_special_chars(name))
+ return name;
+ buff[0]=QUOTE_CHAR;
+ *end=strmov(buff+1,name);
+ end[0]=QUOTE_CHAR;
+ end[1]=0;
+ DBUG_RETURN(buff);
+} /* quote_name */
+
+/*
+ * Allow the user to specify field terminator strings like:
+ * "'", "\", "\\" (escaped backslash), "\t" (tab), "\n" (newline)
+ * This is done by doubleing ' and add a end -\ if needed to avoid
+ * syntax errors from the SQL parser.
+ */
+
+char *field_escape(char *to,const char *from,uint length)
+{
+ const char *end;
+ uint end_backslashes=0;
+ DBUG_ENTER("field_escape");
+
+ {
+ *to++= *from;
+ if (*from == '\\')
+ end_backslashes^=1; /* find odd number of backslashes */
+ else {
+ if (*from == '\'' && !end_backslashes)
+ *to++= *from; /* We want a duplicate of "'" for MySQL */
+ end_backslashes=0;
+ }
+ }
+ /* Add missing backslashes if user has specified odd number of backs.*/
+ if (end_backslashes)
+ *to++= '\\';
+ DBUG_RETURN(to);
+} /* field_escape */
+
+void safe_exit(int error)
+{
+ if (!first_error)
+ first_error= error;
+ if (ignore_errors)
+ return;
+ if (sock)
+ mysql_close(sock);
+ exit(error);
+}
+/* safe_exit */
+
+
+/*
+ * ** DBerror -- prints mysql error message and exits the program.
+ */
+void DBerror(MYSQL *mysql, const char *when)
+{
+ DBUG_ENTER("DBerror");
+ 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 */
+
+void print_version(void)
+{
+ printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,CORBAFS_VERSION,
+ MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
+} /* print_version */
+
+void usage(void)
+{
+ uint i;
+ print_version();
+ puts("By Tõnu Samuel. Some code is partially from other geeks around the world");
+ 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");
+ puts("Dumping definition and data mysql database or table");
+ printf("Usage: %s [OPTIONS]\n", my_progname);
+ printf("\n\
+ -#, --debug=... Output debug log. Often this is 'd:t:o,filename`.\n\
+ --character-sets-dir=...\n\
+ Directory where character sets are\n\
+ -?, --help Display this help message and exit.\n\
+ -c, --complete-insert Use complete insert statements.\n\
+ -C, --compress Use compression in server/client protocol.\n\
+ --default-character-set=...\n\
+ Set the default character set\n\
+ -e, --extended-insert Allows utilization of the new, much faster\n\
+ INSERT syntax.\n\
+ --add-locks Add locks around insert statements.\n\
+ --allow-keywords Allow creation of column names that are keywords.\n\
+ --delayed-insert Insert rows with INSERT DELAYED.\n\
+ -f, --force Continue even if we get an sql-error.\n\
+ -h, --host=... Connect to host.\n");
+puts("\
+ -l, --lock-tables Lock all tables for read.\n\
+ -t, --no-create-info Don't write table creation info.\n\
+ -d, --no-data No row information.\n\
+ -O, --set-variable var=option\n\
+ give a variable a value. --help lists variables\n\
+ -p, --password[=...] Password to use when connecting to server.\n\
+ If password is not given it's solicited on the tty.\n");
+#ifdef __WIN__
+ puts("-W, --pipe Use named pipes to connect to server");
+#endif
+ printf("\
+ -P, --port=... Port number to use for connection.\n\
+ -q, --quick Don't buffer query, dump directly to stdout.\n\
+ -S, --socket=... Socket file to use for connection.\n\
+ --tables Overrides option --databases (-B).\n");
+#include "sslopt-usage.h"
+#ifndef DONT_ALLOW_USER_CHANGE
+ printf("\
+ -u, --user=# User for login if not current user.\n");
+#endif
+ printf("\
+ -v, --verbose Print info about the various stages.\n\
+ -V, --version Output version information and exit.\n\
+");
+ print_defaults("my",load_default_groups);
+
+ printf("\nPossible variables for option --set-variable (-O) are:\n");
+ for (i=0 ; changeable_vars[i].name ; i++)
+ printf("%-20s current value: %lu\n",
+ changeable_vars[i].name,
+ (ulong) *changeable_vars[i].varptr);
+} /* usage */
+
+
+
+static int get_options(int *argc,char ***argv)
+{
+ int c,option_index;
+ my_bool tty_password=0;
+ DBUG_ENTER("get_options");
+ load_defaults("my",load_default_groups,argc,argv);
+ set_all_changeable_vars(changeable_vars);
+ while ((c=getopt_long(*argc,*argv,"#::p::h:u:O:P:S:T:EBaAcCdefFlnqtvVw:?Ix",
+ long_options, &option_index)) != EOF)
+ {
+ switch(c) {
+ case 'e':
+ extended_insert=1;
+ break;
+ case OPT_DEFAULT_CHARSET:
+ default_charset= optarg;
+ break;
+ case OPT_CHARSETS_DIR:
+ charsets_dir= optarg;
+ break;
+
+ ignore_errors=1;
+ break;
+ case 'h':
+ my_free(current_host,MYF(MY_ALLOW_ZERO_PTR));
+ current_host=my_strdup(optarg,MYF(MY_WME));
+ break;
+#ifndef DONT_ALLOW_USER_CHANGE
+ case 'u':
+ current_user=optarg;
+ break;
+#endif
+ case 'O':
+ if (set_changeable_var(optarg, changeable_vars))
+ {
+ usage();
+ return(1);
+ }
+ break;
+ case 'p':
+ if (optarg)
+ {
+ char *start=optarg;
+ my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
+ opt_password=my_strdup(optarg,MYF(MY_FAE));
+ while (*optarg) *optarg++= 'x'; /* Destroy argument */
+ if (*start)
+ start[1]=0; /* Cut length of argument */
+ } else
+ tty_password=1;
+ break;
+ case 'P':
+ opt_mysql_port= (unsigned int) atoi(optarg);
+ break;
+ case 'S':
+ opt_mysql_unix_port= optarg;
+ break;
+ case 'W':
+#ifdef __WIN__
+ opt_mysql_unix_port=MYSQL_NAMEDPIPE;
+#endif
+ break;
+ case 'T':
+ path= optarg;
+ break;
+ case '#':
+ DBUG_PUSH(optarg ? optarg : "d:t:o");
+ break;
+ case 'C':
+ opt_compress=1;
+ break;
+ case 'l': lock_tables=1; break;
+ case 'Q': opt_quoted=1; break;
+ case 'v': verbose=1; break;
+ case 'V': print_version(); exit(0);
+ default:
+ fprintf(stderr,"%s: Illegal option character '%c'\n",my_progname,opterr);
+ /* Fall throught */
+ case 'I':
+ case '?':
+ usage();
+ exit(0);
+ case (int) OPT_FTB:
+ fields_terminated= optarg;
+ break;
+ case (int) OPT_LTB:
+ lines_terminated= optarg;
+ break;
+ case (int) OPT_ENC:
+ enclosed= optarg;
+ break;
+ case (int) OPT_O_ENC:
+ opt_enclosed= optarg;
+ break;
+ case (int) OPT_ESC:
+ escaped= optarg;
+ break;
+ case (int) OPT_LOCKS:
+ opt_lock=1;
+ break;
+ case (int) OPT_OPTIMIZE:
+ extended_insert=opt_lock=lock_tables=1;
+ break;
+ case (int) OPT_DELAYED:
+ opt_delayed=1;
+ break;
+#include "sslopt-case.h"
+ }
+ }
+ if (opt_delayed)
+ opt_lock=0; /* Can't have lock with delayed */
+ if (!path && (enclosed || opt_enclosed || escaped || lines_terminated ||
+ fields_terminated))
+ {
+ fprintf(stderr, "%s: You must use option --tab with --fields-...\n", my_progname);
+ return(1);
+ }
+
+ if (enclosed && opt_enclosed)
+ {
+ fprintf(stderr, "%s: You can't use ..enclosed.. and ..optionally-enclosed.. at the same time.\n", my_progname);
+ return(1);
+ }
+ if (default_charset)
+ {
+ if (set_default_charset_by_name(default_charset, MYF(MY_WME)))
+ exit(1);
+ }
+ (*argc)-=optind;
+ (*argv)+=optind;
+ if (tty_password)
+ opt_password=get_tty_password(NullS);
+ DBUG_RETURN(0);
+} /* get_options */
+
+
+/*** epv structures ***/
+
+static PortableServer_ServantBase__epv impl_Inode_base_epv = {
+ NULL, /* _private data */
+ NULL, /* finalize routine */
+ NULL, /* default_POA routine */
+};
+static POA_CorbaFS_Inode__epv impl_Inode_epv = {
+ NULL, /* _private */
+ (gpointer) & impl_Inode_getStatus,
+ (gpointer) & impl_Inode_readpage,
+ (gpointer) & impl_Inode_release,
+
+};
+static PortableServer_ServantBase__epv impl_FileSystem_base_epv = {
+ NULL, /* _private data */
+ NULL, /* finalize routine */
+ NULL, /* default_POA routine */
+};
+static POA_CorbaFS_FileSystem__epv impl_FileSystem_epv = {
+ NULL, /* _private */
+ (gpointer) & impl_FileSystem_getInode,
+ (gpointer) & impl_FileSystem_readdir,
+ (gpointer) & impl_FileSystem_readlink,
+};
+
+/*** vepv structures ***/
+
+static POA_CorbaFS_Inode__vepv impl_Inode_vepv = {
+ &impl_Inode_base_epv,
+ &impl_Inode_epv,
+};
+static POA_CorbaFS_FileSystem__vepv impl_FileSystem_vepv = {
+ &impl_FileSystem_base_epv,
+ &impl_FileSystem_epv,
+};
+
+/*** Stub implementations ***/
+
+static CorbaFS_Inode
+impl_Inode__create(PortableServer_POA poa, CORBA_Environment * ev)
+{
+ CorbaFS_Inode retval;
+ impl_POA_CorbaFS_Inode *newservant;
+ PortableServer_ObjectId *objid;
+
+ DBUG_ENTER("impl_Inode__create");
+ newservant = g_new0(impl_POA_CorbaFS_Inode, 1);
+ newservant->servant.vepv = &impl_Inode_vepv;
+ newservant->poa = poa;
+ POA_CorbaFS_Inode__init((PortableServer_Servant) newservant, ev);
+ objid = PortableServer_POA_activate_object(poa, newservant, ev);
+ CORBA_free(objid);
+ retval = PortableServer_POA_servant_to_reference(poa, newservant, ev);
+
+ DBUG_RETURN(retval);
+}
+
+static void
+impl_Inode__destroy(impl_POA_CorbaFS_Inode * servant,
+ CORBA_Environment * ev)
+{
+ PortableServer_ObjectId *objid;
+
+ DBUG_ENTER("impl_Inode__destroy");
+ objid = PortableServer_POA_servant_to_id(servant->poa, servant, ev);
+ PortableServer_POA_deactivate_object(servant->poa, objid, ev);
+ CORBA_free(objid);
+
+ POA_CorbaFS_Inode__fini((PortableServer_Servant) servant, ev);
+ g_free(servant);
+ DBUG_VOID_RETURN;
+}
+
+static void
+impl_Inode_getStatus(impl_POA_CorbaFS_Inode * servant,
+ CORBA_unsigned_short * mode,
+ CORBA_unsigned_long * uid,
+ CORBA_unsigned_long * gid,
+ CORBA_unsigned_long * size,
+ CORBA_unsigned_long * inodeNum,
+ CORBA_unsigned_short * numLinks,
+ CORBA_long * atime,
+ CORBA_long * mtime,
+ CORBA_long * ctime, CORBA_Environment * ev)
+{
+ struct stat buf;
+ char
+ server[BUFLEN],
+ database[BUFLEN],
+ table[BUFLEN],
+ key[BUFLEN],
+ field[BUFLEN],
+ value[BUFLEN];
+
+ struct func_st *func;
+
+ DBUG_ENTER("impl_Inode_getStatus");
+ DBUG_PRINT("enter",("path: '%s', mode: '%o', uid: '%d', gid: '%d', size: '%d',
+ inodeNum: '%d', numLinks: '%d', atime: '%d',mtime: '%d', ctime: '%d'",
+ servant->path, mode, uid, gid, size, inodeNum, numLinks, atime, mtime, ctime));
+ DBUG_PRINT("info",("func: %x",&func));
+ if(parse(servant->path, server, database, table, field, value, &func)>0)
+ {
+ DBUG_PRINT("info",("ENOENT"));
+ *mode=0;
+ } else if (func != NULL){
+ DBUG_PRINT("info",("func: %x",&func));
+ DBUG_PRINT("info",("Argument is function at %x, returning S_IFREG",func));
+ *mode = S_IFREG; // File
+ } else if (*field){
+ DBUG_PRINT("info",("Argument is file, returning S_IFREG"));
+ *mode = S_IFREG; // File
+ } else {
+ DBUG_PRINT("info",("Argument is directory, returning S_IFDIR"));
+ *mode = S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH ; // Dir
+ }
+
+ *mode |= S_IRUSR | S_IRGRP | S_IROTH;
+ *uid = 0;
+ *gid = 0;
+ *size = 4096;
+ *inodeNum = servant->inodeNum;
+ *numLinks = 1;
+ *atime = 3;
+ *mtime = 2;
+ *ctime = 1;
+
+// lstat(servant->path, &buf);
+// *mode = buf.st_mode;
+/* *uid = buf.st_uid;
+ *gid = buf.st_gid;
+ *size = buf.st_size;
+ *inodeNum = buf.st_ino;
+ *numLinks = buf.st_nlink;
+ *atime = buf.st_atime;
+ *mtime = buf.st_mtime;
+ *ctime = buf.st_ctime;*/
+ DBUG_VOID_RETURN;
+}
+
+static void
+impl_Inode_readpage(impl_POA_CorbaFS_Inode * servant,
+ CorbaFS_Buffer ** buffer,
+ CORBA_long size,
+ CORBA_long offset, CORBA_Environment * ev)
+{
+ int type;
+ int fd = -1, c = 0;
+ int res;
+ char
+ server[BUFLEN],
+ database[BUFLEN],
+ table[BUFLEN],
+ key[BUFLEN],
+ field[BUFLEN],
+ value[BUFLEN];
+ struct func_st *func;
+
+ DBUG_ENTER("impl_Inode_readpage");
+ DBUG_PRINT("enter",("path: '%s'", servant->path));
+ *buffer = CorbaFS_Buffer__alloc();
+ (*buffer)->_maximum = size;
+ (*buffer)->_buffer = CORBA_octet_allocbuf(size);
+ printf("requested to read %d bytes\n",size);
+ memset((*buffer)->_buffer, size, 0);
+ type = parse(servant->path, server, database, table, field, value, &func);
+ if (func != NULL)
+ res=db_function((*buffer)->_buffer, server, database, table, field, value, servant->path, func);
+ else
+ res=db_show_field((*buffer)->_buffer, database, table, field, path, value);
+ if(res>0)
+ (*buffer)->_length = strlen((*buffer)->_buffer);
+ else
+ (*buffer)->_length = 0;
+/*
+ fd = open(servant->path, O_RDONLY);
+ printf("Inode_readpage : fd = %d\n", fd);
+ lseek(fd, offset, SEEK_SET);
+ c = read(fd, (*buffer)->_buffer, size);
+ printf("Inode_readpage : read %d bytes\n", c);
+ (*buffer)->_length = c;
+ close(fd);
+*/
+ DBUG_VOID_RETURN;
+}
+
+static void
+impl_Inode_release(impl_POA_CorbaFS_Inode * servant,
+ CORBA_Environment * ev)
+{
+ DBUG_ENTER("impl_Inode_readpage");
+ DBUG_PRINT("enter",("path: '%s'", servant->path));
+ DBUG_VOID_RETURN;
+}
+
+/*
+ * This function is called when we get mounted
+ */
+CorbaFS_FileSystem
+impl_FileSystem__create(PortableServer_POA poa,
+ CORBA_Environment * ev)
+{
+ CorbaFS_FileSystem retval;
+ impl_POA_CorbaFS_FileSystem *newservant;
+ PortableServer_ObjectId *objid;
+
+ DBUG_ENTER("impl_FileSystem__create");
+ newservant = g_new0(impl_POA_CorbaFS_FileSystem, 1);
+ newservant->servant.vepv = &impl_FileSystem_vepv;
+ newservant->poa = poa;
+ POA_CorbaFS_FileSystem__init((PortableServer_Servant) newservant, ev);
+ objid = PortableServer_POA_activate_object(poa, newservant, ev);
+ CORBA_free(objid);
+ retval = PortableServer_POA_servant_to_reference(poa, newservant, ev);
+
+ DBUG_RETURN(retval);
+}
+
+/*
+ * This function is called when we get unmounted
+ */
+static void
+impl_FileSystem__destroy(impl_POA_CorbaFS_FileSystem * servant,
+ CORBA_Environment * ev)
+{
+ PortableServer_ObjectId *objid;
+ DBUG_ENTER("impl_FileSystem__destroy");
+
+ objid = PortableServer_POA_servant_to_id(servant->poa, servant, ev);
+ PortableServer_POA_deactivate_object(servant->poa, objid, ev);
+ CORBA_free(objid);
+
+ POA_CorbaFS_FileSystem__fini((PortableServer_Servant) servant, ev);
+ g_free(servant);
+ DBUG_VOID_RETURN;
+}
+
+static CorbaFS_Inode
+impl_FileSystem_getInode(impl_POA_CorbaFS_FileSystem * servant,
+ CORBA_char * path, CORBA_Environment * ev)
+{
+ CorbaFS_Inode retval;
+ impl_POA_CorbaFS_Inode *inode;
+ char
+ database[BUFLEN],
+ table[BUFLEN],
+ key[BUFLEN],
+ field[BUFLEN];
+ char buffer[MAXDIRS][BUFLEN];
+ int c;
+
+ DBUG_ENTER("impl_FileSystem_getInode");
+ DBUG_PRINT("enter",("path: '%s'", path));
+
+ //FIXME: We should verify the existense of file/dir here
+ //
+ retval = impl_Inode__create(servant->poa, ev);
+ inode = PortableServer_POA_reference_to_servant( servant->poa, retval, ev );
+ inode->path = CORBA_string_dup(path);
+ //FIXME: inodeNum Generation goes here
+ //
+ inode->inodeNum= inodeNum++;
+#if 0
+ inode->mode = 0040777; /* world-readable directory */
+ inode->uid = 0;
+ inode->gid = 0;
+ inode->size = 4096;
+ inode->inodeNum = inodeNum++;
+ inode->numLinks = 1;
+ inode->atime = 0;
+ inode->mtime = 100;
+ inode->ctime = 10000;
+#endif
+ DBUG_RETURN(retval);
+}
+
+
+static CorbaFS_DirEntSeq *
+impl_FileSystem_readdir(impl_POA_CorbaFS_FileSystem * servant,
+ CORBA_char * path, CORBA_Environment * ev)
+{
+ CorbaFS_DirEntSeq *retval;
+ CorbaFS_dirent *dirent;
+
+ struct func_st *func;
+ int c, c2,i;
+ char
+ server[BUFLEN],
+ table[BUFLEN],
+ field[BUFLEN],
+ value[BUFLEN],
+ buffer[MAXDIRS][BUFLEN],
+ buffer2[MAXDIRS][BUFLEN],
+ database[BUFLEN];
+
+ DBUG_ENTER("impl_FileSystem_readdir");
+ DBUG_PRINT("enter",("path: '%s'", path));
+ retval = CorbaFS_DirEntSeq__alloc();
+ retval->_maximum = 0;
+ retval->_length = 0;
+
+ parse(path, server, database, table, field, value, &func);
+ if (func != NULL) {
+ c2 = db_function((char *)buffer, server, database, table, field, value, path, func);
+ } else if(!*server) {
+ c2 = db_show_servers(buffer2,MAXDIRS);
+ c = show_functions((char *)buffer, ROOT_FUNCTION);
+ } else if(!*database) {
+ c2 = db_show_databases(buffer2,MAXDIRS);
+ c = show_functions((char *)buffer, SERVER_FUNCTION);
+ } else if(!*table){
+ c2 = db_show_tables(buffer2, database);
+ c = show_functions((char *)buffer, DATABASE_FUNCTION);
+ } else if(!*field){
+ c2 = db_show_primary_keys(buffer2, database,table);
+ if(c2>=0) {
+ c = show_functions((char *)buffer, TABLE_FUNCTION);
+ }
+ } else {
+ c2 = db_show_fields(buffer2, database, table, field);
+ c = show_functions((char *)buffer, FIELD_FUNCTION);
+ c = show_functions((char *)buffer, KEY_FUNCTION);
+ }
+ if(c2 < 0)
+ c=c2=0; // Error occured in database routines
+
+ /* Allocate space to hold all found entries plus "." and ".." */
+ retval->_maximum = c + c2 + 2;
+ retval->_buffer = CORBA_sequence_CorbaFS_dirent_allocbuf(retval->_maximum) ;
+ dirent = retval->_buffer;
+
+ i = 0;
+ while (i < c) {
+ long inode = 123L;
+ dirent[i].inode = inode;
+ dirent[i].name = CORBA_string_dup(buffer[i]);
+ i++;
+ }
+ i = 0;
+ while (i < c2) {
+ long inode = 123L;
+ dirent[c+i].inode = inode;
+ dirent[c+i].name = CORBA_string_dup(buffer2[i]);
+ i++;
+ }
+ dirent[c+i].inode = 123L;
+ dirent[c+i].name = CORBA_string_dup(".");
+ i++;
+ dirent[c+i].inode = 123L;
+ dirent[c+i].name = CORBA_string_dup("..");
+
+ retval->_length = retval->_maximum;
+ DBUG_RETURN(retval);
+}
+
+static CORBA_char *
+impl_FileSystem_readlink(impl_POA_CorbaFS_FileSystem * servant,
+ CORBA_char * filename,
+ CORBA_Environment * ev)
+{
+ CORBA_char *retval = CORBA_OBJECT_NIL;
+ char tmp[MAXPATHLEN + 1];
+ int len;
+
+ DBUG_ENTER("impl_FileSystem_readlink");
+ DBUG_PRINT("enter",("path: '%s'", filename));
+
+/* len = readlink(filename, tmp, MAXPATHLEN);
+ if (len != -1)
+ {
+ tmp[len] = '\0';
+ retval = CORBA_string_dup(tmp);
+ }
+
+ printf("%s\n", retval);
+ */
+ DBUG_RETURN(retval);
+}
+
+int fix_filenames(char *buf)
+{
+ int i;
+ for(i=0; i<strlen(buf);i++)
+ if(buf[i]=='/')
+ buf[i]='_';
+}
+
+int main(int argc, char *argv[]) {
+ CorbaFS_FileSystem fs;
+ impl_POA_CorbaFS_FileSystem *fs_impl;
+ FILE *f;
+ PortableServer_POAManager pm;
+
+ DBUG_ENTER("main");
+ DBUG_PROCESS(argv[0]);
+ ev = g_new0(CORBA_Environment,1);
+ CORBA_exception_init(ev);
+ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", ev);
+ MY_INIT(argv[0]);
+
+ /*
+ ** Check out the args
+ */
+ if (get_options(&argc, &argv))
+ {
+ my_end(0);
+ exit(EX_USAGE);
+ }
+ if (db_connect(current_host, current_user, opt_password))
+ exit(EX_MYSQLERR);
+ fptr = db_load_functions();
+ db_load_formats();
+ poa = (PortableServer_POA)
+ CORBA_ORB_resolve_initial_references(orb, "RootPOA", ev);
+ fs = impl_FileSystem__create(poa, ev);
+
+ pm = PortableServer_POA__get_the_POAManager(poa, ev);
+ PortableServer_POAManager_activate(pm, ev);
+
+ fs_impl = PortableServer_POA_reference_to_servant( poa, fs, ev );
+ objid = PortableServer_POA_servant_to_id( poa, fs_impl, ev );
+ printf("CorbaFS-server:\n%s\n", CORBA_ORB_object_to_string(orb, fs, ev));
+ f=fopen("/tmp/mysqlcorbafs.ior","w");
+ fputs(CORBA_ORB_object_to_string(orb, fs, ev),f);
+ fclose(f);
+ CORBA_ORB_run(orb, ev);
+ db_disconnect(current_host);
+
+ return 0;
+}
diff --git a/fs/mysqlcorbafs.h b/fs/mysqlcorbafs.h
new file mode 100644
index 00000000000..f805a1fb584
--- /dev/null
+++ b/fs/mysqlcorbafs.h
@@ -0,0 +1,157 @@
+/* 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 "CorbaFS.h"
+
+#include <my_global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include <m_ctype.h>
+#include "mysql.h"
+
+#define QUOTE_CHAR '`'
+/* Exit codes */
+
+#define EX_USAGE 1
+#define EX_MYSQLERR 2
+#define EX_CONSCHECK 3
+#define EX_EOM 4
+
+#define CORBAFS_VERSION "0.01"
+
+typedef struct
+{
+ POA_CorbaFS_Inode servant;
+ PortableServer_POA poa;
+
+ CORBA_char *path;
+ CORBA_unsigned_long inodeNum;
+#if 0
+ CORBA_unsigned_short mode;
+ CORBA_unsigned_long uid;
+ CORBA_unsigned_long gid;
+ CORBA_unsigned_long size;
+ CORBA_unsigned_short numLinks;
+ CORBA_long atime;
+ CORBA_long mtime;
+ CORBA_long ctime;
+#endif
+}
+impl_POA_CorbaFS_Inode;
+
+typedef struct
+{
+ POA_CorbaFS_FileSystem servant;
+ PortableServer_POA poa;
+
+}
+impl_POA_CorbaFS_FileSystem;
+
+/*** Implementation stub prototypes ***/
+CorbaFS_FileSystem
+impl_FileSystem__create(PortableServer_POA poa, CORBA_Environment * ev);
+
+static void
+impl_Inode__destroy(impl_POA_CorbaFS_Inode * servant,
+ CORBA_Environment * ev);
+static void
+impl_Inode_getStatus(impl_POA_CorbaFS_Inode * servant,
+ CORBA_unsigned_short * mode,
+ CORBA_unsigned_long * uid,
+ CORBA_unsigned_long * gid,
+ CORBA_unsigned_long * size,
+ CORBA_unsigned_long * inodeNum,
+ CORBA_unsigned_short * numLinks,
+ CORBA_long * atime,
+ CORBA_long * mtime,
+ CORBA_long * ctime, CORBA_Environment * ev);
+
+static void
+impl_Inode_readpage(impl_POA_CorbaFS_Inode * servant,
+ CorbaFS_Buffer ** buffer,
+ CORBA_long size,
+ CORBA_long offset, CORBA_Environment * ev);
+
+static void
+impl_Inode_release(impl_POA_CorbaFS_Inode * servant,
+ CORBA_Environment * ev);
+
+static void impl_FileSystem__destroy(impl_POA_CorbaFS_FileSystem *
+ servant, CORBA_Environment * ev);
+
+static CorbaFS_Inode
+impl_FileSystem_getInode(impl_POA_CorbaFS_FileSystem * servant,
+ CORBA_char * path, CORBA_Environment * ev);
+
+static CorbaFS_DirEntSeq *
+impl_FileSystem_readdir(impl_POA_CorbaFS_FileSystem * servant,
+ CORBA_char * path,
+ CORBA_Environment * ev);
+
+static CORBA_char *
+impl_FileSystem_readlink(impl_POA_CorbaFS_FileSystem * servant,
+ CORBA_char * filename,
+ CORBA_Environment * ev);
+
+static my_bool verbose,opt_compress;
+static uint opt_mysql_port=0;
+static my_string opt_mysql_unix_port=0;
+static int first_error=0;
+static MYSQL connection, *sock=0;
+
+extern uint opt_mysql_port;
+extern my_string opt_mysql_unix_port,host,user,password;
+
+
+
+static struct format {
+ char *tablestart;
+
+ char *headerrowstart;
+ char *headercellstart;
+ char *headercellseparator;
+ char *headercellend;
+ char *headerrowend;
+ int headerformat; /* 0 - simple, 1 - left padded, 2 - right padded */
+
+ char *contentrowstart;
+ char *contentcellstart;
+ char *contentcellseparator;
+ char *contentcellend;
+ char *contentrowend;
+ int contentformat;
+
+ char *footerrowstart;
+ char *footercellstart;
+ char *footercellseparator;
+ char *footercellend;
+ char *footerrowend;
+ int footerformat;
+
+ char *tableend;
+
+ char *leftuppercorner;
+ char *rightuppercorner;
+ char *leftdowncorner;
+ char *rightdowncorner;
+ char *leftcross;
+ char *rightcross;
+ char *topcross;
+ char *middlecross;
+ char *bottomcross;
+
+
+} Human, HTML, CSF, XML;
diff --git a/fs/mysqlcorbafs_test.c b/fs/mysqlcorbafs_test.c
new file mode 100644
index 00000000000..bd7d9381744
--- /dev/null
+++ b/fs/mysqlcorbafs_test.c
@@ -0,0 +1,92 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <orb/orbit.h>
+
+#include "CorbaFS.h"
+
+CorbaFS_FileSystem fs;
+
+int
+main (int argc, char *argv[])
+{
+ CORBA_Environment ev;
+ CORBA_ORB orb;
+ CorbaFS_Inode inode;
+ CorbaFS_Buffer *buffer;
+ CorbaFS_DirEntSeq *dirents;
+ CorbaFS_dirent *dirent;
+
+ CORBA_unsigned_short mode;
+ CORBA_unsigned_long uid;
+ CORBA_unsigned_long gid;
+ CORBA_unsigned_long size;
+ CORBA_unsigned_long inodeNum;
+ CORBA_unsigned_short numLinks;
+ CORBA_long atime;
+ CORBA_long mtime;
+ CORBA_long ctime;
+
+ int i;
+
+ int niters = 10;
+
+ CORBA_exception_init(&ev);
+ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", &ev);
+
+ if(argc < 2)
+ {
+ printf("Need a binding ID thing as argv[1]\n");
+ return 1;
+ }
+
+
+ fs = CORBA_ORB_string_to_object(orb, argv[1], &ev);
+ if (!fs) {
+ printf("Cannot bind to %s\n", argv[1]);
+ return 1;
+ }
+
+ if (argc >= 3)
+ inode = CorbaFS_FileSystem_getInode(fs, argv[2], &ev);
+ else
+ inode = CorbaFS_FileSystem_getInode(fs, "/proc/cpuinfo", &ev);
+
+ if (!inode)
+ {
+ printf("Cannot get inode\n");
+ }
+
+ CorbaFS_Inode_getStatus(inode,
+ &mode,
+ &uid,
+ &gid,
+ &size,
+ &inodeNum,
+ &numLinks,
+ &atime,
+ &mtime,
+ &ctime,
+ &ev);
+
+ printf("inode = %x\n", inode);
+ CorbaFS_Inode_readpage(inode, &buffer, 100000, 100, &ev);
+ printf("readpage got %d bytes\n", buffer->_length);
+ printf("readpage returned : %s\n", buffer->_buffer);
+
+ if (argc >= 3)
+ dirents = CorbaFS_FileSystem_readdir(fs, argv[2], &ev);
+ else
+ dirents = CorbaFS_FileSystem_readdir(fs, "/", &ev);
+
+ dirent = dirents->_buffer;
+ for (i = 0; i < dirents->_length; i++)
+ {
+ printf("%d = %s\n", dirent->inode, dirent->name);
+ dirent++;
+ }
+
+ CORBA_Object_release(fs, &ev);
+ CORBA_Object_release((CORBA_Object)orb, &ev);
+
+ return 0;
+}
diff --git a/fs/mysqlfsck b/fs/mysqlfsck
new file mode 100755
index 00000000000..7b4e049b1e3
--- /dev/null
+++ b/fs/mysqlfsck
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+mountpoint=$*
+
+if [#($mountpoint) -eq "0"];
+then
+ exit;
+fi
+
+
+
diff --git a/heap/_check.c b/heap/_check.c
index e22eb5e7e4a..03fb664cba9 100644
--- a/heap/_check.c
+++ b/heap/_check.c
@@ -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 */
@@ -79,9 +79,11 @@ static int check_one_key(HP_KEYDEF *keydef, uint keynr, ulong records,
}
DBUG_PRINT("info",
("records: %ld seeks: %d max links: %d hitrate: %.2f",
- records,seek,max_links,(float) seek / (float) (records ? records : 1)));
+ records,seek,max_links,
+ (float) seek / (float) (records ? records : 1)));
if (print_status)
printf("Key: %d records: %ld seeks: %d max links: %d hitrate: %.2f\n",
- keynr, records, seek, max_links, (float) seek / (float) records);
+ keynr, records, seek, max_links,
+ (float) seek / (float) (records ? records : 1));
return error;
}
diff --git a/heap/_rectest.c b/heap/_rectest.c
index 3368fbeeffa..522940286fd 100644
--- a/heap/_rectest.c
+++ b/heap/_rectest.c
@@ -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 */
diff --git a/heap/heapdef.h b/heap/heapdef.h
index 938cb55c0eb..bdd7de45370 100644
--- a/heap/heapdef.h
+++ b/heap/heapdef.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 */
@@ -70,6 +70,7 @@ extern int _hp_rec_key_cmp(HP_KEYDEF *keydef,const byte *rec1,
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);
+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_block.c b/heap/hp_block.c
index 510d89d6d1e..5c052218e58 100644
--- a/heap/hp_block.c
+++ b/heap/hp_block.c
@@ -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 */
diff --git a/heap/hp_clear.c b/heap/hp_clear.c
index 702c2e09d29..2dcf91c03d7 100644
--- a/heap/hp_clear.c
+++ b/heap/hp_clear.c
@@ -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 */
@@ -44,7 +44,7 @@ void _hp_clear(HP_SHARE *info)
block->levels=0;
block->last_allocated=0;
}
- info->records=info->deleted=info->data_length=info->index_length=0;;
+ info->records=info->deleted=info->data_length=info->index_length=0;
info->blength=1;
info->changed=0;
info->del_link=0;
diff --git a/heap/hp_close.c b/heap/hp_close.c
index 583602e98cb..9e7d9ab31d1 100644
--- a/heap/hp_close.c
+++ b/heap/hp_close.c
@@ -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 */
@@ -19,7 +19,7 @@
#include "heapdef.h"
/* Close a database open by hp_open() */
- /* Data is not deallocated */
+ /* Data is normally not deallocated */
int heap_close(HP_INFO *info)
{
@@ -43,9 +43,9 @@ int _hp_close(register HP_INFO *info)
}
#endif
info->s->changed=0;
- info->s->open_count--;
heap_open_list=list_delete(heap_open_list,&info->open_list);
+ if (!--info->s->open_count && info->s->delete_on_close)
+ _hp_free(info->s); /* Table was deleted */
my_free((gptr) info,MYF(0));
DBUG_RETURN(error);
}
-
diff --git a/heap/hp_create.c b/heap/hp_create.c
index 01c5f43adfd..1307fab1d12 100644
--- a/heap/hp_create.c
+++ b/heap/hp_create.c
@@ -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 */
@@ -21,33 +21,49 @@
#include "heapdef.h"
+
int heap_create(const char *name)
{
+ reg1 HP_SHARE *share;
DBUG_ENTER("heap_create");
- (void) heap_delete_all(name);
+ pthread_mutex_lock(&THR_LOCK_heap);
+ if ((share=_hp_find_named_heap(name)))
+ {
+ if (share->open_count == 0)
+ _hp_free(share);
+ }
+ else
+ {
+ my_errno=ENOENT;
+ }
+ pthread_mutex_unlock(&THR_LOCK_heap);
DBUG_RETURN(0);
}
-int heap_delete_all(const char *name)
+int heap_delete_table(const char *name)
{
- reg1 HP_SHARE *info;
- int found;
- DBUG_ENTER("heap_delete_all");
+ int result;
+ reg1 HP_SHARE *share;
+ DBUG_ENTER("heap_delete_table");
+
pthread_mutex_lock(&THR_LOCK_heap);
- if ((info=_hp_find_named_heap(name)))
+ if ((share=_hp_find_named_heap(name)))
{
- if (info->open_count == 0)
- _hp_free(info);
- found=0;
+ if (share->open_count == 0)
+ _hp_free(share);
+ else
+ share->delete_on_close=1;
+ result=0;
}
else
{
- found=my_errno=ENOENT;
+ result=my_errno=ENOENT;
}
pthread_mutex_unlock(&THR_LOCK_heap);
- DBUG_RETURN(found);
+ DBUG_RETURN(result);
}
+
void _hp_free(HP_SHARE *share)
{
heap_share_list=list_delete(heap_share_list,&share->open_list);
diff --git a/heap/hp_delete.c b/heap/hp_delete.c
index a6e77fe5f27..3ac321d5fa2 100644
--- a/heap/hp_delete.c
+++ b/heap/hp_delete.c
@@ -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 */
@@ -50,7 +50,8 @@ int heap_delete(HP_INFO *info, const byte *record)
info->current_hash_ptr=0;
DBUG_RETURN(0);
err:
- if( ++(share->records) == share->blength) share->blength+= share->blength;
+ if (++(share->records) == share->blength)
+ share->blength+= share->blength;
DBUG_RETURN(my_errno);
}
@@ -66,7 +67,8 @@ int _hp_delete_key(HP_INFO *info, register HP_KEYDEF *keyinfo,
DBUG_ENTER("_hp_delete_key");
blength=share->blength;
- if (share->records+1 == blength) blength+= blength;
+ if (share->records+1 == blength)
+ blength+= blength;
lastpos=hp_find_hash(&keyinfo->block,share->records);
last_ptr=0;
diff --git a/heap/hp_extra.c b/heap/hp_extra.c
index 133be01c676..46e3f529f34 100644
--- a/heap/hp_extra.c
+++ b/heap/hp_extra.c
@@ -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 */
diff --git a/heap/hp_hash.c b/heap/hp_hash.c
index eb35b947871..e29e51d2b75 100644
--- a/heap/hp_hash.c
+++ b/heap/hp_hash.c
@@ -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 */
@@ -158,11 +158,22 @@ ulong _hp_hashnr(register HP_KEYDEF *keydef, register const byte *key)
{
uchar *pos=(uchar*) key;
key+=seg->length;
+ if (seg->null_bit)
+ {
+ key++; /* Skipp null byte */
+ if (*pos) /* Found null */
+ {
+ nr^= (nr << 1) | 1;
+ continue;
+ }
+ pos++;
+ }
if (seg->type == HA_KEYTYPE_TEXT)
{
for (; pos < (uchar*) key ; pos++)
{
- nr^=(ulong) ((((uint) nr & 63)+nr2)*((uint) my_sort_order[(uint) *pos]))+ (nr << 8);
+ nr^=(ulong) ((((uint) nr & 63)+nr2) *
+ ((uint) my_sort_order[(uint) *pos])) + (nr << 8);
nr2+=3;
}
}
@@ -170,7 +181,7 @@ ulong _hp_hashnr(register HP_KEYDEF *keydef, register const byte *key)
{
for (; pos < (uchar*) key ; pos++)
{
- nr^=(ulong) ((((uint) nr & 63)+nr2)*((uint) *pos))+ (nr << 8);
+ nr^=(ulong) ((((uint) nr & 63)+nr2)*((uint) *pos)) + (nr << 8);
nr2+=3;
}
}
@@ -188,11 +199,20 @@ 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;
+ if (seg->null_bit)
+ {
+ if (rec[seg->null_pos] & seg->null_bit)
+ {
+ nr^= (nr << 1) | 1;
+ continue;
+ }
+ }
if (seg->type == HA_KEYTYPE_TEXT)
{
for (; pos < end ; pos++)
{
- nr^=(ulong) ((((uint) nr & 63)+nr2)*((uint) my_sort_order[(uint) *pos]))+ (nr << 8);
+ nr^=(ulong) ((((uint) nr & 63)+nr2)*
+ ((uint) my_sort_order[(uint) *pos]))+ (nr << 8);
nr2+=3;
}
}
@@ -234,6 +254,16 @@ ulong _hp_hashnr(register HP_KEYDEF *keydef, register const byte *key)
{
uchar *pos=(uchar*) key;
key+=seg->length;
+ if (seg->null_bit)
+ {
+ key++;
+ if (*pos)
+ {
+ nr^= (nr << 1) | 1;
+ continue;
+ }
+ pos++;
+ }
if (seg->type == HA_KEYTYPE_TEXT)
{
for (; pos < (uchar*) key ; pos++)
@@ -264,6 +294,14 @@ 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;
+ if (seg->null_bit)
+ {
+ if (rec[seg->null_pos] & seg->null_bit)
+ {
+ nr^= (nr << 1) | 1;
+ continue;
+ }
+ }
if (seg->type == HA_KEYTYPE_TEXT)
{
for ( ; pos < end ; pos++)
@@ -295,6 +333,14 @@ int _hp_rec_key_cmp(HP_KEYDEF *keydef, const byte *rec1, const byte *rec2)
for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
{
+ if (seg->null_bit)
+ {
+ if ((rec1[seg->null_pos] & seg->null_bit) !=
+ (rec2[seg->null_pos] & seg->null_bit))
+ return 1;
+ if (rec1[seg->null_pos] & seg->null_bit)
+ continue;
+ }
if (seg->type == HA_KEYTYPE_TEXT)
{
if (my_sortcmp(rec1+seg->start,rec2+seg->start,seg->length))
@@ -309,14 +355,24 @@ int _hp_rec_key_cmp(HP_KEYDEF *keydef, const byte *rec1, const byte *rec2)
return 0;
}
- /* Compare a key in a record to a hole key */
+ /* Compare a key in a record to a whole key */
int _hp_key_cmp(HP_KEYDEF *keydef, const byte *rec, const byte *key)
{
HP_KEYSEG *seg,*endseg;
- for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
+ for (seg=keydef->seg,endseg=seg+keydef->keysegs ;
+ seg < endseg ;
+ key+= (seg++)->length)
{
+ if (seg->null_bit)
+ {
+ int found_null=test(rec[seg->null_pos] & seg->null_bit);
+ if (found_null != (int) *key++)
+ return 1;
+ if (found_null)
+ continue;
+ }
if (seg->type == HA_KEYTYPE_TEXT)
{
if (my_sortcmp(rec+seg->start,key,seg->length))
@@ -327,7 +383,6 @@ int _hp_key_cmp(HP_KEYDEF *keydef, const byte *rec, const byte *key)
if (bcmp(rec+seg->start,key,seg->length))
return 1;
}
- key+=seg->length;
}
return 0;
}
@@ -341,7 +396,28 @@ void _hp_make_key(HP_KEYDEF *keydef, byte *key, const byte *rec)
for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
{
+ if (seg->null_bit)
+ *key++= test(rec[seg->null_pos] & seg->null_bit);
memcpy(key,rec+seg->start,(size_t) seg->length);
key+=seg->length;
}
}
+
+
+/*
+ Test if any of the key parts are NULL.
+ Return:
+ 1 if any of the key parts was NULL
+ 0 otherwise
+*/
+
+my_bool hp_if_null_in_key(HP_KEYDEF *keydef, const byte *record)
+{
+ HP_KEYSEG *seg,*endseg;
+ for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
+ {
+ if (seg->null_bit && (record[seg->null_pos] & seg->null_bit))
+ return 1;
+ }
+ return 0;
+}
diff --git a/heap/hp_info.c b/heap/hp_info.c
index 379f4d9ec0f..3e9d6b6a90b 100644
--- a/heap/hp_info.c
+++ b/heap/hp_info.c
@@ -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 */
diff --git a/heap/hp_open.c b/heap/hp_open.c
index 692142de14a..938ab8c4f78 100644
--- a/heap/hp_open.c
+++ b/heap/hp_open.c
@@ -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 */
@@ -44,7 +44,12 @@ HP_INFO *heap_open(const char *name, int mode, uint keys, HP_KEYDEF *keydef,
key_segs+= keydef[i].keysegs;
bzero((char*) &keydef[i].block,sizeof(keydef[i].block));
for (j=length=0 ; j < keydef[i].keysegs; j++)
+ {
length+=keydef[i].seg[j].length;
+ if (keydef[i].seg[j].null_bit &&
+ !(keydef[i].flag & HA_NULL_ARE_EQUAL))
+ keydef[i].flag |= HA_NULL_PART_KEY;
+ }
keydef[i].length=length;
if (length > max_length)
max_length=length;
diff --git a/heap/hp_panic.c b/heap/hp_panic.c
index cfd370a56d0..4b93190b7e1 100644
--- a/heap/hp_panic.c
+++ b/heap/hp_panic.c
@@ -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 */
diff --git a/heap/hp_rename.c b/heap/hp_rename.c
index 267c16b589d..118c5931f43 100644
--- a/heap/hp_rename.c
+++ b/heap/hp_rename.c
@@ -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 */
diff --git a/heap/hp_rfirst.c b/heap/hp_rfirst.c
index e3b9654061d..9a1f09244a0 100644
--- a/heap/hp_rfirst.c
+++ b/heap/hp_rfirst.c
@@ -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 */
diff --git a/heap/hp_rkey.c b/heap/hp_rkey.c
index 157267f7149..e7a1d81fba6 100644
--- a/heap/hp_rkey.c
+++ b/heap/hp_rkey.c
@@ -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 */
@@ -20,7 +20,7 @@ int heap_rkey(HP_INFO *info, byte *record, int inx, const byte *key)
{
byte *pos;
HP_SHARE *share=info->s;
- DBUG_ENTER("hp_rkey");
+ DBUG_ENTER("heap_rkey");
DBUG_PRINT("enter",("base: %lx inx: %d",info,inx));
if ((uint) inx >= share->keys)
diff --git a/heap/hp_rlast.c b/heap/hp_rlast.c
index 38e07fde2bb..463b6dc9aac 100644
--- a/heap/hp_rlast.c
+++ b/heap/hp_rlast.c
@@ -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 */
diff --git a/heap/hp_rnext.c b/heap/hp_rnext.c
index 6aa3cf06d97..af08a0e68a2 100644
--- a/heap/hp_rnext.c
+++ b/heap/hp_rnext.c
@@ -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 */
@@ -23,7 +23,7 @@ int heap_rnext(HP_INFO *info, byte *record)
byte *pos;
HP_SHARE *share=info->s;
DBUG_ENTER("heap_rnext");
-
+
if (info->lastinx < 0)
DBUG_RETURN(my_errno=HA_ERR_WRONG_INDEX);
diff --git a/heap/hp_rprev.c b/heap/hp_rprev.c
index 28a821c143e..c7c649e6b9f 100644
--- a/heap/hp_rprev.c
+++ b/heap/hp_rprev.c
@@ -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 */
diff --git a/heap/hp_rrnd.c b/heap/hp_rrnd.c
index 63181967a29..78abebcaf47 100644
--- a/heap/hp_rrnd.c
+++ b/heap/hp_rrnd.c
@@ -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 */
diff --git a/heap/hp_rsame.c b/heap/hp_rsame.c
index 888fb349f5a..a346707641b 100644
--- a/heap/hp_rsame.c
+++ b/heap/hp_rsame.c
@@ -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 */
diff --git a/heap/hp_scan.c b/heap/hp_scan.c
index b7684cd2673..e74f8b43ba7 100644
--- a/heap/hp_scan.c
+++ b/heap/hp_scan.c
@@ -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 */
diff --git a/heap/hp_static.c b/heap/hp_static.c
index 5e5326ca76b..a458b742b9c 100644
--- a/heap/hp_static.c
+++ b/heap/hp_static.c
@@ -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 */
diff --git a/heap/hp_test1.c b/heap/hp_test1.c
index f44752af3bc..e07af2761f0 100644
--- a/heap/hp_test1.c
+++ b/heap/hp_test1.c
@@ -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 */
@@ -20,7 +20,7 @@
raderas.
*/
-#include <global.h>
+#include <my_global.h>
#include <my_sys.h>
#include <m_string.h>
#include "heap.h"
diff --git a/heap/hp_test2.c b/heap/hp_test2.c
index a76aa19e082..e2570893519 100644
--- a/heap/hp_test2.c
+++ b/heap/hp_test2.c
@@ -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 */
@@ -30,7 +30,7 @@
#include <signal.h>
#define MAX_RECORDS 100000
-#define MAX_KEYS 3
+#define MAX_KEYS 4
static int get_options(int argc, char *argv[]);
static int rnd(int max_value);
@@ -40,16 +40,20 @@ static uint flag=0,verbose=0,testflag=0,recant=10000,silent=0;
static uint keys=MAX_KEYS;
static uint16 key1[1001];
static my_bool key3[MAX_RECORDS];
+static int reclength=39;
+
static int calc_check(byte *buf,uint length);
+static void make_record(char *record, uint n1, uint n2, uint n3,
+ const char *mark, uint count);
- /* Huvudprogrammet */
+/* Main program */
int main(int argc, char *argv[])
{
register uint i,j;
uint ant,n1,n2,n3;
- uint reclength,write_count,update,opt_delete,check2,dupp_keys,found_key;
+ uint write_count,update,opt_delete,check2,dupp_keys,found_key;
int error;
ulong pos;
unsigned long key_check;
@@ -66,7 +70,6 @@ int main(int argc, char *argv[])
filename2= "test2_2";
file=file2=0;
get_options(argc,argv);
- reclength=37;
write_count=update=opt_delete=0;
key_check=0;
@@ -77,21 +80,33 @@ int main(int argc, char *argv[])
keyinfo[0].seg[0].type=HA_KEYTYPE_BINARY;
keyinfo[0].seg[0].start=0;
keyinfo[0].seg[0].length=6;
+ keyinfo[0].seg[0].null_bit=0;
keyinfo[1].seg=keyseg+1;
keyinfo[1].keysegs=2;
keyinfo[1].flag=0;
keyinfo[1].seg[0].type=HA_KEYTYPE_BINARY;
keyinfo[1].seg[0].start=7;
keyinfo[1].seg[0].length=6;
+ keyinfo[1].seg[0].null_bit=0;
keyinfo[1].seg[1].type=HA_KEYTYPE_TEXT;
- keyinfo[1].seg[1].start=0; /* Tv}delad nyckel */
+ keyinfo[1].seg[1].start=0; /* key in two parts */
keyinfo[1].seg[1].length=6;
+ keyinfo[1].seg[1].null_bit=0;
keyinfo[2].seg=keyseg+3;
keyinfo[2].keysegs=1;
keyinfo[2].flag=HA_NOSAME;
keyinfo[2].seg[0].type=HA_KEYTYPE_BINARY;
keyinfo[2].seg[0].start=12;
keyinfo[2].seg[0].length=8;
+ keyinfo[2].seg[0].null_bit=0;
+ keyinfo[3].keysegs=1;
+ keyinfo[3].flag=HA_NOSAME;
+ keyinfo[3].seg=keyseg+4;
+ keyinfo[3].seg[0].type=HA_KEYTYPE_BINARY;
+ keyinfo[3].seg[0].start=37;
+ keyinfo[3].seg[0].length=1;
+ keyinfo[3].seg[0].null_bit=1;
+ keyinfo[3].seg[0].null_pos=38;
bzero((char*) key1,sizeof(key1));
bzero((char*) key3,sizeof(key3));
@@ -110,7 +125,7 @@ int main(int argc, char *argv[])
for (i=0 ; i < recant ; i++)
{
n1=rnd(1000); n2=rnd(100); n3=rnd(min(recant*5,MAX_RECORDS));
- sprintf(record,"%6d:%4d:%8d:Pos: %4d ",n1,n2,n3,write_count);
+ make_record(record,n1,n2,n3,"Pos",write_count);
if (heap_write(file,record))
{
@@ -191,7 +206,7 @@ int main(int argc, char *argv[])
for (i=0 ; i < write_count/10 ; i++)
{
n1=rnd(1000); n2=rnd(100); n3=rnd(min(recant*2,MAX_RECORDS));
- sprintf(record2,"%6d:%4d:%8d:XXX: %4d ",n1,n2,n3,update);
+ make_record(record2, n1, n2, n3, "XXX", update);
if (rnd(2) == 1)
{
if (heap_scan_init(file))
@@ -572,7 +587,7 @@ end:
heap_clear(file);
if (heap_close(file) || (file2 && heap_close(file2)))
goto err;
- heap_delete_all(filename2);
+ heap_delete_table(filename2);
heap_panic(HA_PANIC_CLOSE);
my_end(MY_GIVE_INFO);
return(0);
@@ -654,3 +669,13 @@ static int calc_check(byte *buf, uint length)
check+= (int) (uchar) *(buf++);
return check;
}
+
+static void make_record(char *record, uint n1, uint n2, uint n3,
+ const char *mark, uint count)
+{
+ bfill(record,reclength,' ');
+ sprintf(record,"%6d:%4d:%8d:%3.3s: %4d",
+ n1,n2,n3,mark,count);
+ record[37]='A'; /* Store A in null key */
+ record[38]=1; /* set as null */
+}
diff --git a/heap/hp_update.c b/heap/hp_update.c
index a1d9c51e9dd..8cf3e4d4b8d 100644
--- a/heap/hp_update.c
+++ b/heap/hp_update.c
@@ -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 */
diff --git a/heap/hp_write.c b/heap/hp_write.c
index 12b5c638f78..806f40e5be5 100644
--- a/heap/hp_write.c
+++ b/heap/hp_write.c
@@ -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 */
@@ -62,6 +62,7 @@ int heap_write(HP_INFO *info, const byte *record)
info->update|=HA_STATE_AKTIV;
DBUG_RETURN(0);
err:
+ DBUG_PRINT("info",("Duplicate key: %d",key));
info->errkey= key;
do
{
@@ -237,8 +238,10 @@ int _hp_write_key(register HP_SHARE *info, HP_KEYDEF *keyinfo,
_hp_movelink(pos,gpos,empty);
}
- /* Check if dupplicated keys */
- if ((keyinfo->flag & HA_NOSAME) && pos == gpos)
+ /* Check if duplicated keys */
+ if ((keyinfo->flag & HA_NOSAME) && pos == gpos &&
+ (!(keyinfo->flag & HA_NULL_PART_KEY) ||
+ !hp_if_null_in_key(keyinfo, record)))
{
pos=empty;
do
diff --git a/include/Makefile.am b/include/Makefile.am
index f3685b51cd3..b943e8d76e6 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -16,28 +16,28 @@
# MA 02111-1307, USA
BUILT_SOURCES = mysql_version.h m_ctype.h my_config.h
-pkginclude_HEADERS = dbug.h m_string.h my_sys.h mysql.h mysql_com.h \
- mysqld_error.h my_list.h \
+pkginclude_HEADERS = dbug.h m_string.h my_sys.h my_list.h \
+ mysql.h mysql_com.h mysqld_error.h mysql_embed.h \
my_pthread.h my_no_pthread.h raid.h errmsg.h \
my_global.h my_net.h \
sslopt-case.h sslopt-longopts.h sslopt-usage.h \
sslopt-vars.h $(BUILT_SOURCES)
-noinst_HEADERS = global.h config-win.h \
+noinst_HEADERS = config-win.h \
nisam.h heap.h merge.h my_bitmap.h\
myisam.h myisampack.h myisammrg.h ft_global.h\
my_dir.h mysys_err.h my_base.h \
my_nosys.h my_alarm.h queues.h \
my_tree.h hash.h thr_alarm.h thr_lock.h \
- getopt.h t_ctype.h violite.h \
+ getopt.h my_getopt.h t_ctype.h violite.h md5.h \
mysql_version.h.in
# mysql_version.h are generated
-SUPERCLEANFILES = mysql_version.h my_global.h my_config.h
+SUPERCLEANFILES = mysql_version.h my_config.h
# Some include files that may be moved and patched by configure
DISTCLEANFILES = sched.h
-all-local: my_global.h my_config.h
+all-local: my_config.h
# Since we include my_config.h it better exist from the beginning
link_sources:
@@ -48,11 +48,6 @@ link_sources:
my_config.h: ../config.h
$(CP) ../config.h my_config.h
-# This should be changed in the source and removed.
-my_global.h: global.h
- $(RM) -f my_global.h
- $(CP) global.h my_global.h
-
# These files should not be included in distributions since they are
# generated by configure from the .h.in files
dist-hook:
diff --git a/include/config-win.h b/include/config-win.h
index 4e4088f07dd..12a89bec21b 100644
--- a/include/config-win.h
+++ b/include/config-win.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Defines for Win32 to make it compatible for MySQL */
@@ -32,7 +31,7 @@
#define SYSTEM_TYPE "Win95/Win98"
#endif
-#ifdef _WIN64
+#if defined(_WIN64) || defined(WIN64)
#define MACHINE_TYPE "ia64" /* Define to machine type name */
#else
#define MACHINE_TYPE "i32" /* Define to machine type name */
@@ -138,7 +137,7 @@ typedef uint rf_SetTimer;
#define USE_MB 1
#define USE_MB_IDENT 1
#define USE_STRCOLL 1
-
+
/* Convert some simple functions to Posix */
#define sigset(A,B) signal((A),(B))
@@ -254,6 +253,9 @@ inline double ulonglong2double(ulonglong value)
#define HAVE_STRPBRK
#define HAVE_STRSTR
#define HAVE_COMPRESS
+#define HAVE_CREATESEMAPHORE
+
+#define HAVE_ISAM /* We want to have support for ISAM in 4.0 */
#ifdef NOT_USED
#define HAVE_SNPRINTF /* Gave link error */
diff --git a/include/dbug.h b/include/dbug.h
index 3c86cbb8ac2..5c88e2e42db 100644
--- a/include/dbug.h
+++ b/include/dbug.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 _dbug_h
#define _dbug_h
diff --git a/include/errmsg.h b/include/errmsg.h
index 8087c526937..76a57f47611 100644
--- a/include/errmsg.h
+++ b/include/errmsg.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Error messages for mysql clients */
/* error messages for the demon is in share/language/errmsg.sys */
@@ -57,3 +56,8 @@ extern const char *client_errors[]; /* Error messages */
#define CR_NAMEDPIPESETSTATE_ERROR 2018
#define CR_CANT_READ_CHARSET 2019
#define CR_NET_PACKET_TOO_LARGE 2020
+#define CR_EMBEDDED_CONNECTION 2021
+#define CR_PROBE_SLAVE_STATUS 2022
+#define CR_PROBE_SLAVE_HOSTS 2023
+#define CR_PROBE_SLAVE_CONNECT 2024
+#define CR_PROBE_MASTER_CONNECT 2025
diff --git a/include/ft_global.h b/include/ft_global.h
index 3937bd87c7f..4218eb75aa7 100644
--- a/include/ft_global.h
+++ b/include/ft_global.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* 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
@@ -27,29 +27,36 @@ extern "C" {
#endif
#define FT_QUERY_MAXLEN 1024
+#define HA_FT_MAXLEN 254
-typedef struct ft_doc_rec {
- my_off_t dpos;
- double weight;
-} FT_DOC;
+typedef struct st_ft_info FT_INFO;
+struct _ft_vft {
+ int (*read_next)(FT_INFO *, char *);
+ float (*find_relevance)(FT_INFO *, byte *, uint);
+ void (*close_search)(FT_INFO *);
+ float (*get_relevance)(FT_INFO *);
+ void (*reinit_search)(FT_INFO *);
+};
-typedef struct st_ft_doclist {
- int ndocs;
- int curdoc;
- void *info; /* actually (MI_INFO *) but don't want to include myisam.h */
- FT_DOC doc[1];
-} FT_DOCLIST;
+#ifndef FT_CORE
+struct st_ft_info {
+ struct _ft_vft *please; /* INTERCAL style :-) */
+};
+#endif
extern const char *ft_precompiled_stopwords[];
+extern ulong ft_min_word_len;
+extern ulong ft_max_word_len;
+extern ulong ft_max_word_len_for_sort;
+extern const char *ft_boolean_syntax;
+
int ft_init_stopwords(const char **);
void ft_free_stopwords(void);
-FT_DOCLIST * ft_init_search(void *, uint, byte *, uint, my_bool);
-int ft_read_next(FT_DOCLIST *, char *);
-#define ft_close_search(handler) my_free(((gptr)(handler)),MYF(0))
-#define ft_get_relevance(handler) ((handler)->doc[(handler)->curdoc].weight)
-#define ft_reinit_search(handler) (((FT_DOCLIST *)(handler))->curdoc=-1)
+#define FT_NL 0
+#define FT_BOOL 1
+FT_INFO *ft_init_search(uint,void *, uint, byte *, uint, my_bool);
#ifdef __cplusplus
}
diff --git a/include/getopt.h b/include/getopt.h
index 790915b97df..94e73c03ff3 100644
--- a/include/getopt.h
+++ b/include/getopt.h
@@ -1,3 +1,19 @@
+/* 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 */
+
/* Declarations for getopt.
Copyright (C) 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc.
diff --git a/include/hash.h b/include/hash.h
index 2f6a424fb3c..e9c8c73c05b 100644
--- a/include/hash.h
+++ b/include/hash.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Dynamic hashing of record with different key-length */
@@ -55,6 +54,7 @@ gptr hash_next(HASH *info,const byte *key,uint length);
my_bool hash_insert(HASH *info,const byte *data);
my_bool hash_delete(HASH *hash,byte *record);
my_bool hash_update(HASH *hash,byte *record,byte *old_key,uint old_key_length);
+void hash_replace(HASH *hash, uint idx, byte *new_row);
my_bool hash_check(HASH *hash); /* Only in debug library */
#define hash_clear(H) bzero((char*) (H),sizeof(*(H)))
diff --git a/include/heap.h b/include/heap.h
index 14698810297..02b04e2b3ec 100644
--- a/include/heap.h
+++ b/include/heap.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 heap_database_funktions */
/* Author: Michael Widenius */
@@ -79,11 +78,13 @@ typedef struct st_hp_keyseg /* Key-portion */
uint start; /* Start of key in record (from 0) */
uint length; /* Keylength */
uint type;
+ uint null_bit; /* bit set in row+null_pos */
+ uint null_pos;
} HP_KEYSEG;
typedef struct st_hp_keydef /* Key definition with open */
{
- uint flag; /* NOSAME */
+ uint flag; /* HA_NOSAME | HA_NULL_PART_KEY */
uint keysegs; /* Number of key-segment */
uint length; /* Length of key (automatic) */
HP_KEYSEG *seg;
@@ -109,6 +110,7 @@ typedef struct st_heap_share
THR_LOCK lock;
pthread_mutex_t intern_lock; /* Locking for use with _locking */
#endif
+ my_bool delete_on_close;
LIST open_list;
} HP_SHARE;
@@ -144,7 +146,7 @@ extern int heap_scan(register HP_INFO *info, byte *record);
extern int heap_delete(HP_INFO *info,const byte *buff);
extern int heap_info(HP_INFO *info,HEAPINFO *x,int flag);
extern int heap_create(const char *name);
-extern int heap_delete_all(const char *name);
+extern int heap_delete_table(const char *name);
extern int heap_extra(HP_INFO *info,enum ha_extra_function function);
extern int heap_rename(const char *old_name,const char *new_name);
extern int heap_panic(enum ha_panic_function flag);
diff --git a/include/m_ctype.h b/include/m_ctype.h
index 645c07b79ae..fc983d1d580 100644
--- a/include/m_ctype.h
+++ b/include/m_ctype.h
@@ -1,23 +1,22 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 better inplementation of the UNIX ctype(3) library.
- Notes: global.h should be included before ctype.h
+ Notes: my_global.h should be included before ctype.h
*/
#ifndef _m_ctype_h
@@ -57,13 +56,12 @@ extern CHARSET_INFO *default_charset_info;
extern CHARSET_INFO *find_compiled_charset(uint cs_number);
extern CHARSET_INFO *find_compiled_charset_by_name(const char *name);
extern CHARSET_INFO compiled_charsets[];
+extern uint compiled_charset_number(const char *name);
+extern const char *compiled_charset_name(uint charset_number);
#define MY_CHARSET_UNDEFINED 0
#define MY_CHARSET_CURRENT (default_charset_info->number)
-#ifdef __WIN__
-#include <ctype.h>
-#endif
/* Don't include std ctype.h when this is included */
#define _CTYPE_H
#define _CTYPE_H_
@@ -71,12 +69,32 @@ extern CHARSET_INFO compiled_charsets[];
#define __CTYPE_INCLUDED
#define _CTYPE_USING /* Don't put names in global namespace. */
+/* Fix things, if ctype.h would have been included before */
+#undef toupper
+#undef _toupper
+#undef _tolower
+#undef toupper
+#undef tolower
+#undef isalpha
+#undef isupper
+#undef islower
+#undef isdigit
+#undef isxdigit
+#undef isalnum
+#undef isspace
+#undef ispunct
+#undef isprint
+#undef isgraph
+#undef iscntrl
+#undef isascii
+#undef toascii
+
#define _U 01 /* Upper case */
#define _L 02 /* Lower case */
-#define _N 04 /* Numeral (digit) */
-#define _S 010 /* Spacing character */
-#define _P 020 /* Punctuation */
-#define _C 040 /* Control character */
+#define _NMR 04 /* Numeral (digit) */
+#define _SPC 010 /* Spacing character */
+#define _PNT 020 /* Punctuation */
+#define _CTR 040 /* Control character */
#define _B 0100 /* Blank */
#define _X 0200 /* heXadecimal digit */
@@ -85,7 +103,6 @@ extern CHARSET_INFO compiled_charsets[];
#define my_to_lower (default_charset_info->to_lower)
#define my_sort_order (default_charset_info->sort_order)
-#ifndef __WIN__
#define _toupper(c) (char) my_to_upper[(uchar) (c)]
#define _tolower(c) (char) my_to_lower[(uchar) (c)]
#define toupper(c) (char) my_to_upper[(uchar) (c)]
@@ -94,14 +111,14 @@ extern CHARSET_INFO compiled_charsets[];
#define isalpha(c) ((my_ctype+1)[(uchar) (c)] & (_U | _L))
#define isupper(c) ((my_ctype+1)[(uchar) (c)] & _U)
#define islower(c) ((my_ctype+1)[(uchar) (c)] & _L)
-#define isdigit(c) ((my_ctype+1)[(uchar) (c)] & _N)
+#define isdigit(c) ((my_ctype+1)[(uchar) (c)] & _NMR)
#define isxdigit(c) ((my_ctype+1)[(uchar) (c)] & _X)
-#define isalnum(c) ((my_ctype+1)[(uchar) (c)] & (_U | _L | _N))
-#define isspace(c) ((my_ctype+1)[(uchar) (c)] & _S)
-#define ispunct(c) ((my_ctype+1)[(uchar) (c)] & _P)
-#define isprint(c) ((my_ctype+1)[(uchar) (c)] & (_P | _U | _L | _N | _B))
-#define isgraph(c) ((my_ctype+1)[(uchar) (c)] & (_P | _U | _L | _N))
-#define iscntrl(c) ((my_ctype+1)[(uchar) (c)] & _C)
+#define isalnum(c) ((my_ctype+1)[(uchar) (c)] & (_U | _L | _NMR))
+#define isspace(c) ((my_ctype+1)[(uchar) (c)] & _SPC)
+#define ispunct(c) ((my_ctype+1)[(uchar) (c)] & _PNT)
+#define isprint(c) ((my_ctype+1)[(uchar) (c)] & (_PNT | _U | _L | _NMR | _B))
+#define isgraph(c) ((my_ctype+1)[(uchar) (c)] & (_PNT | _U | _L | _NMR))
+#define iscntrl(c) ((my_ctype+1)[(uchar) (c)] & _CTR)
#define isascii(c) (!((c) & ~0177))
#define toascii(c) ((c) & 0177)
@@ -109,19 +126,17 @@ extern CHARSET_INFO compiled_charsets[];
#undef ctype
#endif /* ctype */
-#endif /* __WIN__ */
-
#define my_isalpha(s, c) (((s)->ctype+1)[(uchar) (c)] & (_U | _L))
#define my_isupper(s, c) (((s)->ctype+1)[(uchar) (c)] & _U)
#define my_islower(s, c) (((s)->ctype+1)[(uchar) (c)] & _L)
-#define my_isdigit(s, c) (((s)->ctype+1)[(uchar) (c)] & _N)
+#define my_isdigit(s, c) (((s)->ctype+1)[(uchar) (c)] & _NMR)
#define my_isxdigit(s, c) (((s)->ctype+1)[(uchar) (c)] & _X)
-#define my_isalnum(s, c) (((s)->ctype+1)[(uchar) (c)] & (_U | _L | _N))
-#define my_isspace(s, c) (((s)->ctype+1)[(uchar) (c)] & _S)
-#define my_ispunct(s, c) (((s)->ctype+1)[(uchar) (c)] & _P)
-#define my_isprint(s, c) (((s)->ctype+1)[(uchar) (c)] & (_P | _U | _L | _N | _B))
-#define my_isgraph(s, c) (((s)->ctype+1)[(uchar) (c)] & (_P | _U | _L | _N))
-#define my_iscntrl(s, c) (((s)->ctype+1)[(uchar) (c)] & _C)
+#define my_isalnum(s, c) (((s)->ctype+1)[(uchar) (c)] & (_U | _L | _NMR))
+#define my_isspace(s, c) (((s)->ctype+1)[(uchar) (c)] & _SPC)
+#define my_ispunct(s, c) (((s)->ctype+1)[(uchar) (c)] & _PNT)
+#define my_isprint(s, c) (((s)->ctype+1)[(uchar) (c)] & (_PNT | _U | _L | _NMR | _B))
+#define my_isgraph(s, c) (((s)->ctype+1)[(uchar) (c)] & (_PNT | _U | _L | _NMR))
+#define my_iscntrl(s, c) (((s)->ctype+1)[(uchar) (c)] & _CTR)
#define use_strcoll(s) ((s)->strcoll != NULL)
#define MY_STRXFRM_MULTIPLY (default_charset_info->strxfrm_multiply)
diff --git a/include/m_string.h b/include/m_string.h
index 7eb2f1fe690..c6943613b1a 100644
--- a/include/m_string.h
+++ b/include/m_string.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* There may be prolems include all of theese. Try to test in
configure with ones are needed? */
@@ -132,11 +131,12 @@ extern void bzero(gptr dst,uint len);
#if !defined(bcmp) && !defined(HAVE_BCMP)
extern int bcmp(const char *s1,const char *s2,uint len);
+#endif
#ifdef HAVE_purify
extern int my_bcmp(const char *s1,const char *s2,uint len);
+#undef bcmp
#define bcmp(A,B,C) my_bcmp((A),(B),(C))
#endif
-#endif
#ifndef bmove512
extern void bmove512(gptr dst,const gptr src,uint len);
diff --git a/sql/md5.h b/include/md5.h
index 862129391f1..aa4116ff17f 100644
--- a/sql/md5.h
+++ b/include/md5.h
@@ -1,3 +1,19 @@
+/* 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 */
+
/* MD5.H - header file for MD5C.C
*/
@@ -57,24 +73,21 @@ If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
#else
#define PROTO_LIST(list) ()
#endif
-
-
/* MD5 context. */
typedef struct {
UINT4 state[4]; /* state (ABCD) */
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
unsigned char buffer[64]; /* input buffer */
-} MD5_CTX;
+} my_MD5_CTX;
#ifdef __cplusplus
extern "C" {
#endif
- void MD5Init PROTO_LIST ((MD5_CTX *));
- void MD5Update PROTO_LIST
- ((MD5_CTX *, unsigned char *, unsigned int));
- void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
+ void my_MD5Init PROTO_LIST ((my_MD5_CTX *));
+ void my_MD5Update PROTO_LIST
+ ((my_MD5_CTX *, unsigned char *, unsigned int));
+ void my_MD5Final PROTO_LIST ((unsigned char [16], my_MD5_CTX *));
#ifdef __cplusplus
}
#endif
-
diff --git a/include/merge.h b/include/merge.h
index c661e03a0c7..97cea5fabb1 100644
--- a/include/merge.h
+++ b/include/merge.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 */
diff --git a/include/my_alarm.h b/include/my_alarm.h
index b6c5ca6a3f4..fdfce9c65c9 100644
--- a/include/my_alarm.h
+++ b/include/my_alarm.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 to include when we want to use alarm or a loop_counter to display
diff --git a/include/my_base.h b/include/my_base.h
index 6275adab124..68f33147145 100644
--- a/include/my_base.h
+++ b/include/my_base.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 constants used with all databases */
/* Author: Michael Widenius */
@@ -24,7 +23,7 @@
#ifndef stdin /* Included first in handler */
#define USES_TYPES /* my_dir with sys/types is included */
#define CHSIZE_USED
-#include <global.h>
+#include <my_global.h>
#include <my_dir.h> /* This includes types */
#include <my_sys.h>
#include <m_string.h>
@@ -57,7 +56,20 @@ enum ha_rkey_function {
HA_READ_AFTER_KEY, /* Find next rec. after key-record */
HA_READ_BEFORE_KEY, /* Find next rec. before key-record */
HA_READ_PREFIX, /* Key which as same prefix */
- HA_READ_PREFIX_LAST /* Last key with the same prefix */
+ HA_READ_PREFIX_LAST, /* Last key with the same prefix */
+ HA_READ_MBR_CONTAIN,
+ HA_READ_MBR_INTERSECT,
+ HA_READ_MBR_WITHIN,
+ HA_READ_MBR_DISJOINT,
+ HA_READ_MBR_EQUAL
+};
+
+ /* Key algorithm types */
+
+enum ha_key_alg {
+ HA_KEY_ALG_BTREE=0, /* B-tree, default one */
+ HA_KEY_ALG_RTREE=1, /* R-tree, for spatial searches */
+ HA_KEY_ALG_HASH=2 /* HASH keys (HEAP tables) */
};
/* The following is parameter to ha_extra() */
@@ -91,7 +103,10 @@ enum ha_extra_function {
HA_EXTRA_RESET_STATE, /* Reset positions */
HA_EXTRA_IGNORE_DUP_KEY, /* Dup keys don't rollback everything*/
HA_EXTRA_NO_IGNORE_DUP_KEY,
- HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE /* Cursor will not be used for update */
+ HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE, /* Cursor will not be used for update */
+ HA_EXTRA_BULK_INSERT_BEGIN,
+ HA_EXTRA_BULK_INSERT_END,
+ HA_EXTRA_PREPARE_FOR_DELETE
};
/* The following is parameter to ha_panic() */
@@ -134,6 +149,9 @@ enum ha_base_keytype {
#define HA_BINARY_PACK_KEY 32 /* Packing of all keys to prev key */
#define HA_FULLTEXT 128 /* SerG: for full-text search */
#define HA_UNIQUE_CHECK 256 /* Check the key for uniqueness */
+#define HA_SPATIAL 1024 /* Alex Barkov: for spatial search */
+#define HA_NULL_ARE_EQUAL 2048 /* NULL in key are cmp as equal */
+
/* Automatic bits in key-flag */
@@ -156,6 +174,7 @@ enum ha_base_keytype {
#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 */
/* optionbits for database */
#define HA_OPTION_PACK_RECORD 1
@@ -222,6 +241,7 @@ enum ha_base_keytype {
/* Other constants */
#define HA_NAMELEN 64 /* Max length of saved filename */
+#define NO_SUCH_KEY ((uint)~0) /* used as a key no. */
/* Intern constants in databases */
@@ -235,6 +255,13 @@ enum ha_base_keytype {
#define SEARCH_UPDATE 64
#define SEARCH_PREFIX 128
#define SEARCH_LAST 256
+#define MBR_CONTAIN 512
+#define MBR_INTERSECT 1024
+#define MBR_WITHIN 2048
+#define MBR_DISJOINT 4096
+#define MBR_EQUAL 8192
+#define MBR_DATA 16384
+#define SEARCH_NULL_ARE_EQUAL 32768 /* NULL in keys are equal */
/* bits in opt_flag */
#define QUICK_USED 1
@@ -259,8 +286,8 @@ enum ha_base_keytype {
#define HA_STATE_EXTEND_BLOCK 2048
enum en_fieldtype {
- FIELD_LAST=-1,FIELD_NORMAL,FIELD_SKIPP_ENDSPACE,FIELD_SKIPP_PRESPACE,
- FIELD_SKIPP_ZERO,FIELD_BLOB,FIELD_CONSTANT,FIELD_INTERVALL,FIELD_ZERO,
+ FIELD_LAST=-1,FIELD_NORMAL,FIELD_SKIP_ENDSPACE,FIELD_SKIP_PRESPACE,
+ FIELD_SKIP_ZERO,FIELD_BLOB,FIELD_CONSTANT,FIELD_INTERVALL,FIELD_ZERO,
FIELD_VARCHAR,FIELD_CHECK
};
diff --git a/include/my_bitmap.h b/include/my_bitmap.h
index 3243e5f0b24..ca0037addfb 100644
--- a/include/my_bitmap.h
+++ b/include/my_bitmap.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 _my_bitmap_h_
#define _my_bitmap_h_
diff --git a/include/my_dir.h b/include/my_dir.h
index 1961ca79549..4ccda050914 100644
--- a/include/my_dir.h
+++ b/include/my_dir.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 _my_dir_h
#define _my_dir_h
diff --git a/include/my_getopt.h b/include/my_getopt.h
new file mode 100644
index 00000000000..2e40fb8ffaa
--- /dev/null
+++ b/include/my_getopt.h
@@ -0,0 +1,53 @@
+/* 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 */
+
+struct my_optarg
+{
+ char *arg; /* option argument */
+ int pos; /* next element in ARGV */
+ int verbose; /* 0 = inhibit warnings of unrecognized options */
+ int unrecognized; /* position of the unrecognized option */
+};
+
+
+enum get_opt_var_type { GET_NO_ARG, GET_LONG, GET_LL, GET_STR };
+enum get_opt_arg_type { NO_ARG, OPT_ARG, REQUIRED_ARG };
+
+struct my_option
+{
+ const char *name; /* Name of the option */
+ const char *comment; /* option comment, for autom. --help */
+ gptr *value; /* The variable value */
+ gptr *u_max_value; /* The user def. max variable value */
+ const char **str_values; /* Pointer to possible values */
+ enum get_opt_var_type var_type;
+ enum get_opt_arg_type arg_type;
+ int id; /* unique id or short option */
+ longlong def_value; /* Default value */
+ longlong min_value; /* Min allowed value */
+ longlong max_value; /* Max allowed value */
+ longlong sub_size; /* Subtract this from given value */
+ long block_size; /* Value should be a mult. of this */
+ int app_type; /* To be used by an application */
+};
+
+extern int handle_options (int *argc, char ***argv,
+ const struct my_option *longopts,
+ my_bool (*get_one_option)(int,
+ const struct my_option *,
+ char *));
+extern void my_print_help(const struct my_option *options);
+extern void my_print_variables(const struct my_option *options);
diff --git a/include/global.h b/include/my_global.h
index a58179e6759..01910eb1342 100644
--- a/include/global.h
+++ b/include/my_global.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 is the main include file that should included 'first' in every
C file. */
@@ -52,6 +51,33 @@
#endif
#endif /* _WIN32... */
+/* sometimes we want to make sure that the variable is not put into
+ a register in debugging mode so we can see its value in the core
+*/
+
+#ifndef DBUG_OFF
+#define dbug_volatile volatile
+#else
+#define dbug_volatile
+#endif
+
+/*
+ The macros below are borrowed from include/linux/compiler.h in the
+ Linux kernel. Use them to indicate the likelyhood of the truthfulness
+ of a condition. This serves two purposes - newer versions of gcc will be
+ able to optimize for branch predication, which could yield siginficant
+ performance gains in frequently executed sections of the code, and the
+ other reason to use them is for documentation
+*/
+
+#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
+#define __builtin_expect(x, expected_value) (x)
+#endif
+
+#define likely(x) __builtin_expect((x),1)
+#define unlikely(x) __builtin_expect((x),0)
+
+
/* Fix problem with S_ISLNK() on Linux */
#if defined(HAVE_LINUXTHREADS)
#undef _GNU_SOURCE
@@ -103,7 +129,15 @@
#ifdef _AIX /* By soren@t.dk */
#define _H_STRINGS
#define _SYS_STREAM_H
-#define _AIX32_CURSES
+/* #define _AIX32_CURSES */ /* XXX: this breaks AIX 4.3.3 (others?). */
+#endif
+
+#ifdef __QNXNTO__
+#define HAVE_ERRNO_AS_DEFINE
+#define HAVE_FCNTL_LOCK
+#undef HAVE_SYS_UN_H
+#undef HAVE_FINITE
+#undef HAVE_RINT
#endif
#ifdef HAVE_BROKEN_SNPRINTF /* HPUX 10.20 don't have this defined */
@@ -189,7 +223,13 @@
# endif
#endif /* TIME_WITH_SYS_TIME */
#ifdef HAVE_UNISTD_H
+#if defined(HAVE_OPENSSL) && !defined(__FreeBSD__) && !defined(NeXT)
+#define crypt unistd_crypt
+#endif
#include <unistd.h>
+#ifdef HAVE_OPENSSL
+#undef crypt
+#endif
#endif
#if defined(__cplusplus) && defined(NO_CPLUSPLUS_ALLOCA)
#undef HAVE_ALLOCA
@@ -217,7 +257,7 @@
#define setrlimit cma_setrlimit64
#endif
-/* We can not live without these */
+/* We can not live without the following defines */
#define USE_MYFUNC 1 /* Must use syscall indirection */
#define MASTER 1 /* Compile without unireg */
@@ -226,7 +266,7 @@
#define USE_REGEX 1 /* We want the use the regex library */
/* Do not define for ultra sparcs */
#ifndef OS2
-#define USE_BMOVE512 1 /* Use this unless the system bmove is faster */
+#define USE_BMOVE512 1 /* Use this unless system bmove is faster */
#endif
/* Paranoid settings. Define I_AM_PARANOID if you are paranoid */
@@ -261,7 +301,7 @@ int __void__;
#define LINT_INIT(var)
#endif
-/* Define som useful general macros */
+/* Define some useful general macros */
#if defined(__cplusplus) && defined(__GNUC__)
#define max(a, b) ((a) >? (b))
#define min(a, b) ((a) <? (b))
@@ -275,6 +315,7 @@ typedef unsigned int uint;
typedef unsigned short ushort;
#endif
+#define CMP_NUM(a,b) (((a) < (b)) ? -1 : ((a) == (b)) ? 0 : 1)
#define sgn(a) (((a) < 0) ? -1 : ((a) > 0) ? 1 : 0)
#define swap(t,a,b) { register t dummy; dummy = a; a = b; b = dummy; }
#define test(a) ((a) ? 1 : 0)
@@ -323,11 +364,6 @@ typedef unsigned short ushort;
#endif
#include <dbug.h>
-#ifndef DBUG_OFF
-#define dbug_assert(A) assert(A)
-#else
-#define dbug_assert(A)
-#endif
#define MIN_ARRAY_SIZE 0 /* Zero or One. Gcc allows zero*/
#define ASCII_BITS_USED 8 /* Bit char used */
@@ -357,6 +393,7 @@ typedef int pshort; /* Mixed prototypes can't take short int */
typedef double pfloat; /* Mixed prototypes can't take float */
#endif
typedef int (*qsort_cmp)(const void *,const void *);
+typedef int (*qsort_cmp2)(void*, const void *,const void *);
#ifdef HAVE_mit_thread
#define qsort_t void
#undef QSORT_TYPE_IS_VOID
@@ -452,8 +489,6 @@ typedef SOCKET_SIZE_TYPE size_socket;
/* Some things that this system doesn't have */
#define ONLY_OWN_DATABASES /* We are using only databases by monty */
-#define NO_PISAM /* Not needed anymore */
-#define NO_MISAM /* Not needed anymore */
#define NO_HASH /* Not needed anymore */
#ifdef __WIN__
#define NO_DIR_LIBRARY /* Not standar dir-library */
@@ -618,7 +653,7 @@ typedef unsigned long ulong; /* Short for unsigned long */
#ifndef longlong_defined
#if defined(HAVE_LONG_LONG) && SIZEOF_LONG != 8
typedef unsigned long long int ulonglong; /* ulong or unsigned long long */
-typedef long long int longlong;
+typedef long long int longlong;
#else
typedef unsigned long ulonglong; /* ulong or unsigned long long */
typedef long longlong;
@@ -651,13 +686,14 @@ typedef off_t os_off_t;
#if defined(__WIN__)
#define socket_errno WSAGetLastError()
-#define SOCKET_EINTR WSAEINTR
+#define SOCKET_EINTR WSAEINTR
#define SOCKET_EAGAIN WSAEINPROGRESS
+#define SOCKET_EWOULDBLOCK WSAEINPROGRESS
#define SOCKET_ENFILE ENFILE
#define SOCKET_EMFILE EMFILE
#elif defined(OS2)
#define socket_errno sock_errno()
-#define SOCKET_EINTR SOCEINTR
+#define SOCKET_EINTR SOCEINTR
#define SOCKET_EAGAIN SOCEINPROGRESS
#define SOCKET_EWOULDBLOCK SOCEWOULDBLOCK
#define SOCKET_ENFILE SOCENFILE
@@ -718,6 +754,20 @@ typedef char bool; /* Ordinary boolean values 0 1 */
#define MY_HOW_OFTEN_TO_ALARM 2 /* How often we want info on screen */
#define MY_HOW_OFTEN_TO_WRITE 1000 /* How often we want info on screen */
+#ifdef HAVE_TIMESPEC_TS_SEC
+#define set_timespec(ABSTIME,SEC) { (ABSTIME).ts_sec=time(0) + (time_t) (SEC); (ABSTIME).ts_nsec=0; }
+#elif defined(__WIN__)
+#define set_timespec(ABSTIME,SEC) { (ABSTIME).tv_sec=time((time_t*)0) + (time_t) (SEC); (ABSTIME).tv_nsec=0; }
+#else
+#define set_timespec(ABSTIME,SEC) \
+{\
+ struct timeval tv;\
+ gettimeofday(&tv,0);\
+ (ABSTIME).tv_sec=tv.tv_sec+(time_t) (SEC);\
+ (ABSTIME).tv_nsec=tv.tv_usec*1000;\
+}
+#endif
+
/*
** Define-funktions for reading and storing in machine independent format
** (low byte first)
@@ -769,7 +819,7 @@ typedef union {
#define float8get(V,M) doubleget((V),(M))
#define float4store(V,M) memcpy((byte*) V,(byte*) (&M),sizeof(float))
#define float8store(V,M) doublestore((V),(M))
-#endif /* __i386__ */
+#endif /* __i386__ */
#ifndef sint2korr
#define sint2korr(A) (int16) (((int16) ((uchar) (A)[0])) +\
@@ -814,9 +864,9 @@ typedef union {
*((uchar*) (T))= (uchar)(def_temp); \
*((uchar*) (T+1))=(uchar)((def_temp >> 8)); }
#define int3store(T,A) { /*lint -save -e734 */\
- *((T))=(char) ((A));\
- *((T)+1)=(char) (((A) >> 8));\
- *((T)+2)=(char) (((A) >> 16)); \
+ *((uchar*)(T))=(uchar) ((A));\
+ *((uchar*) (T)+1)=(uchar) (((A) >> 8));\
+ *((uchar*)(T)+2)=(uchar) (((A) >> 16)); \
/*lint -restore */}
#define int4store(T,A) { *(T)=(char) ((A));\
*((T)+1)=(char) (((A) >> 8));\
@@ -964,4 +1014,13 @@ typedef union {
#define statistic_add(V,C,L) (V)+=(C)
#endif
+/* Macros to make switching between C and C++ mode easier */
+#ifdef __cplusplus
+#define C_MODE_START extern "C" {
+#define C_MODE_END }
+#else
+#define C_MODE_START
+#define C_MODE_END
+#endif
+
#endif /* _global_h */
diff --git a/include/my_list.h b/include/my_list.h
index 7391db70e27..0f56d4c532b 100644
--- a/include/my_list.h
+++ b/include/my_list.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 _list_h_
#define _list_h_
diff --git a/include/my_net.h b/include/my_net.h
index 6a8e98d685c..c2ebe80a343 100644
--- a/include/my_net.h
+++ b/include/my_net.h
@@ -1,28 +1,33 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
-
-/* thread safe version of some common functions */
-
-/* for thread safe my_inet_ntoa */
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#if !defined(MSDOS) && !defined(__WIN__) && !defined(__BEOS__)
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ thread safe version of some common functions:
+ my_inet_ntoa
+
+ This file is also used to make handling of sockets and ioctl()
+ portable accross systems.
+
+*/
+
+#ifndef _my_net_h
+#define _my_net_h
+C_MODE_START
+
+#include <errno.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
@@ -32,10 +37,35 @@ extern "C" {
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
-#endif /* !defined(MSDOS) && !defined(__WIN__) */
+#ifdef HAVE_POLL
+#include <sys/poll.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#if !defined(MSDOS) && !defined(__WIN__) && !defined(HAVE_BROKEN_NETINET_INCLUDES) && !defined(__BEOS__)
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#if !defined(alpha_linux_port)
+#include <netinet/tcp.h>
+#endif
+#endif
+
+#if defined(__EMX__)
+#include <sys/ioctl.h>
+#define ioctlsocket(A,B,C) ioctl((A),(B),(void *)(C),sizeof(*(C)))
+#undef HAVE_FCNTL
+#endif /* defined(__EMX__) */
+
+#if defined(MSDOS) || defined(__WIN__)
+#define O_NONBLOCK 1 /* For emulation of fcntl() */
+#endif
+
+/* Thread safe or portable version of some functions */
void my_inet_ntoa(struct in_addr in, char *buf);
-#ifdef __cplusplus
-}
+C_MODE_END
#endif
diff --git a/include/my_no_pthread.h b/include/my_no_pthread.h
index 2ff8896fa74..81c0de580db 100644
--- a/include/my_no_pthread.h
+++ b/include/my_no_pthread.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 undefs some pthread mutex locks when one isn't using threads
diff --git a/include/my_nosys.h b/include/my_nosys.h
index 5991904f260..605906f0e07 100644
--- a/include/my_nosys.h
+++ b/include/my_nosys.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
Header to remove use of my_functions in functions where we need speed and
diff --git a/include/my_pthread.h b/include/my_pthread.h
index cd72bcced83..4ca42339897 100644
--- a/include/my_pthread.h
+++ b/include/my_pthread.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Defines to make different thread packages compatible */
@@ -133,16 +132,17 @@ void pthread_exit(void *a); /* was #define pthread_exit(A) ExitThread(A)*/
#define pthread_equal(A,B) ((A) == (B))
#ifdef OS2
-int pthread_mutex_init (pthread_mutex_t *, const pthread_mutexattr_t *);
-int pthread_mutex_lock (pthread_mutex_t *);
-int pthread_mutex_unlock (pthread_mutex_t *);
-int pthread_mutex_destroy (pthread_mutex_t *);
+extern int pthread_mutex_init (pthread_mutex_t *, const pthread_mutexattr_t *);
+extern int pthread_mutex_lock (pthread_mutex_t *);
+extern int pthread_mutex_unlock (pthread_mutex_t *);
+extern int pthread_mutex_destroy (pthread_mutex_t *);
#define my_pthread_setprio(A,B) DosSetPriority(PRTYS_THREAD,PRTYC_NOCHANGE, B, A)
#define pthread_kill(A,B) raise(B)
#define pthread_exit(A) pthread_dummy()
#else
#define pthread_mutex_init(A,B) InitializeCriticalSection(A)
#define pthread_mutex_lock(A) (EnterCriticalSection(A),0)
+#define pthread_mutex_trylock(A) (WaitForSingleObject((A), 0) == WAIT_TIMEOUT)
#define pthread_mutex_unlock(A) LeaveCriticalSection(A)
#define pthread_mutex_destroy(A) DeleteCriticalSection(A)
#define my_pthread_setprio(A,B) SetThreadPriority(GetCurrentThread(), (B))
@@ -446,6 +446,14 @@ struct hostent *my_gethostbyname_r(const char *name,
#endif /* defined(__WIN__) */
+#if defined(HPUX) && !defined(DONT_REMAP_PTHREAD_FUNCTIONS)
+#define pthread_cond_timedwait(a,b,c) my_pthread_cond_timedwait((a),(b),(c))
+#define pthread_mutex_trylock(a) my_pthread_mutex_trylock((a))
+int my_pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+ struct timespec *abstime);
+int my_pthread_mutex_trylock(pthread_mutex_t *mutex);
+#endif
+
/* safe_mutex adds checking to mutex for easier debugging */
typedef struct st_safe_mutex_t
@@ -476,6 +484,7 @@ int safe_cond_timedwait(pthread_cond_t *cond, safe_mutex_t *mp,
#undef pthread_mutex_t
#undef pthread_cond_wait
#undef pthread_cond_timedwait
+#undef pthread_mutex_trylock
#define pthread_mutex_init(A,B) safe_mutex_init((A),(B))
#define pthread_mutex_lock(A) safe_mutex_lock((A),__FILE__,__LINE__)
#define pthread_mutex_unlock(A) safe_mutex_unlock((A),__FILE__,__LINE__)
@@ -623,5 +632,4 @@ extern struct st_my_thread_var *_my_thread_var(void) __attribute__ ((const));
#ifdef __cplusplus
}
#endif
-
#endif /* _my_ptread_h */
diff --git a/include/my_semaphore.h b/include/my_semaphore.h
new file mode 100644
index 00000000000..484423150f7
--- /dev/null
+++ b/include/my_semaphore.h
@@ -0,0 +1,51 @@
+/*
+ * Module: semaphore.h
+ *
+ * Purpose:
+ * Semaphores aren't actually part of the PThreads standard.
+ * They are defined by the POSIX Standard:
+ *
+ * POSIX 1003.1b-1993 (POSIX.1b)
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * 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 is hacked by Monty to be included in mysys library */
+
+#ifndef _my_semaphore_h_
+#define _my_semaphore_h_
+
+#ifndef __WIN__
+#include <semaphore.h>
+#else
+
+C_MODE_START
+
+typedef HANDLE sem_t;
+int sem_init (sem_t * sem, int pshared, unsigned int value);
+int sem_destroy (sem_t * sem);
+int sem_trywait (sem_t * sem);
+int sem_wait (sem_t * sem);
+int sem_post (sem_t * sem);
+int sem_post_multiple (sem_t * sem,int count);
+int sem_getvalue (sem_t * sem, int * sval);
+
+C_MODE_END
+#endif /* __WIN__ */
+#endif /* !_my_semaphore_h_ */
diff --git a/include/my_sys.h b/include/my_sys.h
index ffb3ea83b49..4aee27e2939 100644
--- a/include/my_sys.h
+++ b/include/my_sys.h
@@ -1,25 +1,22 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 _my_sys_h
#define _my_sys_h
-#ifdef __cplusplus
-extern "C" {
-#endif
+C_MODE_START
#ifdef HAVE_AIOWAIT
#include <sys/asynch.h> /* Used by record-cache */
@@ -59,6 +56,9 @@ extern int NEAR my_errno; /* Last error in mysys */
#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_LINK_WARNING 32 /* my_redel() gives warning if links */
#define MY_COPYTIME 64 /* my_redel() copys time */
@@ -90,6 +90,16 @@ extern int NEAR my_errno; /* Last error in mysys */
#define ME_COLOUR2 ((2 << ME_HIGHBYTE))
#define ME_COLOUR3 ((3 << ME_HIGHBYTE))
+ /* Bits in last argument to fn_format */
+#define MY_REPLACE_DIR 1 /* replace dir in name with 'dir' */
+#define MY_REPLACE_EXT 2 /* replace extension with 'ext' */
+#define MY_UNPACK_FILENAME 4 /* Unpack name (~ -> home) */
+#define MY_PACK_FILENAME 8 /* Pack name (home -> ~) */
+#define MY_RESOLVE_SYMLINKS 16 /* Resolve all symbolic links */
+#define MY_RETURN_REAL_PATH 32 /* return full path for file */
+#define MY_SAFE_PATH 64 /* Return NULL if too long path */
+#define MY_RELATIVE_PATH 128 /* name is relative to 'dir' */
+
/* My seek flags */
#define MY_SEEK_SET 0
#define MY_SEEK_CUR 1
@@ -106,10 +116,12 @@ extern int NEAR my_errno; /* Last error in mysys */
#define MY_WAIT_FOR_USER_TO_FIX_PANIC 60 /* in seconds */
#define MY_WAIT_GIVE_USER_A_MESSAGE 10 /* Every 10 times of prev */
#define MIN_COMPRESS_LENGTH 50 /* Don't compress small bl. */
-#define KEYCACHE_BLOCK_SIZE 1024
+#define DEFAULT_KEYCACHE_BLOCK_SIZE 1024
+#define MAX_KEYCACHE_BLOCK_SIZE 16384
/* root_alloc flags */
#define MY_KEEP_PREALLOC 1
+#define MY_MARK_BLOCKS_FREE 2 /* move used to free list and reuse them */
/* defines when allocating data */
@@ -197,9 +209,10 @@ extern char *get_charsets_dir(char *buf);
/* statistics */
extern ulong _my_cache_w_requests,_my_cache_write,_my_cache_r_requests,
_my_cache_read;
-extern ulong _my_blocks_used,_my_blocks_changed;
+extern ulong _my_blocks_used,_my_blocks_changed;
+extern uint key_cache_block_size;
extern ulong my_file_opened,my_stream_opened, my_tmp_file_created;
-extern my_bool key_cache_inited;
+extern my_bool key_cache_inited, my_init_done;
/* Point to current my_message() */
extern void (*my_sigtstp_cleanup)(void),
@@ -235,7 +248,10 @@ typedef struct st_typelib { /* Different types saved here */
const char **type_names;
} TYPELIB;
-enum cache_type {READ_CACHE,WRITE_CACHE,READ_FIFO,READ_NET,WRITE_NET};
+enum cache_type {READ_CACHE,WRITE_CACHE,
+ SEQ_READ_APPEND /* sequential read or append */,
+ READ_FIFO,
+ READ_NET,WRITE_NET};
enum flush_type { FLUSH_KEEP, FLUSH_RELEASE, FLUSH_IGNORE_CHANGED,
FLUSH_FORCE_WRITE};
@@ -254,7 +270,8 @@ typedef struct st_record_cache /* Used when cacheing records */
} RECORD_CACHE;
enum file_type { UNOPEN = 0, FILE_BY_OPEN, FILE_BY_CREATE,
- STREAM_BY_FOPEN, STREAM_BY_FDOPEN, FILE_BY_MKSTEMP };
+ STREAM_BY_FOPEN, STREAM_BY_FDOPEN, FILE_BY_MKSTEMP,
+ FILE_BY_DUP };
extern struct my_file_info
{
@@ -278,20 +295,111 @@ typedef struct st_dynamic_string {
uint length,max_length,alloc_increment;
} DYNAMIC_STRING;
+struct st_io_cache;
+typedef int (*IO_CACHE_CALLBACK)(struct st_io_cache*);
+
typedef struct st_io_cache /* Used when cacheing files */
{
+ /* pos_in_file is offset in file corresponding to the first byte of
+ byte* buffer. end_of_file is the offset of end of file for READ_CACHE
+ and WRITE_CACHE. For SEQ_READ_APPEND it the maximum of the actual
+ end of file and the position represented by read_end.
+ */
my_off_t pos_in_file,end_of_file;
- byte *rc_pos,*rc_end,*buffer,*rc_request_pos;
+ /* read_pos points to current read position in the buffer
+ read_end is the non-inclusive boundary in the buffer for the currently
+ valid read area
+ buffer is the read buffer
+ not sure about request_pos except that it is used in async_io
+ */
+ byte *read_pos,*read_end,*buffer,*request_pos;
+ /* write_buffer is used only in WRITE caches and in SEQ_READ_APPEND to
+ buffer writes
+ append_read_pos is only used in SEQ_READ_APPEND, and points to the
+ current read position in the write buffer. Note that reads in
+ SEQ_READ_APPEND caches can happen from both read buffer (byte* buffer),
+ and write buffer (byte* write_buffer).
+ write_pos points to current write position in the write buffer and
+ write_end is the non-inclusive boundary of the valid write area
+ */
+ byte *write_buffer, *append_read_pos, *write_pos, *write_end;
+ /* current_pos and current_end are convenience variables used by
+ my_b_tell() and other routines that need to know the current offset
+ current_pos points to &write_pos, and current_end to &write_end in a
+ WRITE_CACHE, and &read_pos and &read_end respectively otherwise
+ */
+ byte **current_pos, **current_end;
+/* The lock is for append buffer used in SEQ_READ_APPEND cache */
+#ifdef THREAD
+ pthread_mutex_t append_buffer_lock;
+ /* need mutex copying from append buffer to read buffer */
+#endif
+ /* a caller will use my_b_read() macro to read from the cache
+ if the data is already in cache, it will be simply copied with
+ memcpy() and internal variables will be accordinging updated with
+ no functions invoked. However, if the data is not fully in the cache,
+ my_b_read() will call read_function to fetch the data. read_function
+ must never be invoked directly
+ */
int (*read_function)(struct st_io_cache *,byte *,uint);
+ /* same idea as in the case of read_function, except my_b_write() needs to
+ be replaced with my_b_append() for a SEQ_READ_APPEND cache
+ */
+ int (*write_function)(struct st_io_cache *,const byte *,uint);
+ /* specifies the type of the cache. Depending on the type of the cache
+ certain operations might not be available and yield unpredicatable
+ results. Details to be documented later
+ */
+ enum cache_type type;
+ /* callbacks when the actual read I/O happens. These were added and
+ are currently used for binary logging of LOAD DATA INFILE - when a
+ block is read from the file, we create a block create/append event, and
+ when IO_CACHE is closed, we create an end event. These functions could,
+ of course be used for other things
+ */
+ IO_CACHE_CALLBACK pre_read;
+ IO_CACHE_CALLBACK post_read;
+ IO_CACHE_CALLBACK pre_close;
+ void* arg; /* for use by pre/post_read */
char *file_name; /* if used with 'open_cached_file' */
char *dir,*prefix;
- File file;
+ File file; /* file descriptor */
+ /* seek_not_done is set by my_b_seek() to inform the upcoming read/write
+ operation that a seek needs to be preformed prior to the actual I/O
+ error is 0 if the cache operation was successful, -1 if there was a
+ "hard" error, and the actual number of I/O-ed bytes if the read/write was
+ partial
+ */
int seek_not_done,error;
+ /* buffer_length is the size of memory allocated for buffer or write_buffer
+ read_length is the same as buffer_length except when we use async io
+ not sure why we need it
+ */
uint buffer_length,read_length;
myf myflags; /* Flags used to my_read/my_write */
- enum cache_type type;
+ /*
+ alloced_buffer is 1 if the buffer was allocated by init_io_cache() and
+ 0 if it was supplied by the user
+ Currently READ_NET is the only one that will use a buffer allocated
+ somewhere else
+ */
+ my_bool alloced_buffer;
+ /* init_count is incremented every time we call init_io_cache()
+ It is not reset in end_io_cache(). This variable
+ was introduced for slave relay logs - RELAY_LOG_INFO stores a pointer
+ to IO_CACHE that could in some cases refer to the IO_CACHE of the
+ currently active relay log. The IO_CACHE then could be closed,
+ re-opened and start pointing to a different log file. In that case,
+ we could not know reliably if this happened without init_count
+ one must be careful with bzero() prior to the subsequent init_io_cache()
+ call
+ */
+ int init_count;
#ifdef HAVE_AIOWAIT
+ /* as inidicated by ifdef, this is for async I/O, we will have
+ Sinisa comment this some time
+ */
uint inited;
my_off_t aio_read_pos;
my_aio_result aio_result;
@@ -308,35 +416,41 @@ typedef int (*qsort2_cmp)(const void *, const void *, const void *);
#define my_b_EOF INT_MIN
#define my_b_read(info,Buffer,Count) \
- ((info)->rc_pos + (Count) <= (info)->rc_end ?\
- (memcpy(Buffer,(info)->rc_pos,(size_t) (Count)), \
- ((info)->rc_pos+=(Count)),0) :\
+ ((info)->read_pos + (Count) <= (info)->read_end ?\
+ (memcpy(Buffer,(info)->read_pos,(size_t) (Count)), \
+ ((info)->read_pos+=(Count)),0) :\
(*(info)->read_function)((info),Buffer,Count))
+#define my_b_write(info,Buffer,Count) \
+ ((info)->write_pos + (Count) <=(info)->write_end ?\
+ (memcpy((info)->write_pos, (Buffer), (size_t)(Count)),\
+ ((info)->write_pos+=(Count)),0) : \
+ (*(info)->write_function)((info),(Buffer),(Count)))
+
+
#define my_b_get(info) \
- ((info)->rc_pos != (info)->rc_end ?\
- ((info)->rc_pos++, (int) (uchar) (info)->rc_pos[-1]) :\
+ ((info)->read_pos != (info)->read_end ?\
+ ((info)->read_pos++, (int) (uchar) (info)->read_pos[-1]) :\
_my_b_get(info))
-#define my_b_write(info,Buffer,Count) \
- ((info)->rc_pos + (Count) <= (info)->rc_end ?\
- (memcpy((info)->rc_pos,Buffer,(size_t) (Count)), \
- ((info)->rc_pos+=(Count)),0) :\
- _my_b_write(info,Buffer,Count))
-
/* my_b_write_byte dosn't have any err-check */
#define my_b_write_byte(info,chr) \
- (((info)->rc_pos < (info)->rc_end) ?\
- ((*(info)->rc_pos++)=(chr)) :\
- (_my_b_write(info,0,0) , ((*(info)->rc_pos++)=(chr))))
+ (((info)->write_pos < (info)->write_end) ?\
+ ((*(info)->write_pos++)=(chr)) :\
+ (_my_b_write(info,0,0) , ((*(info)->write_pos++)=(chr))))
#define my_b_fill_cache(info) \
- (((info)->rc_end=(info)->rc_pos),(*(info)->read_function)(info,0,0))
+ (((info)->read_end=(info)->read_pos),(*(info)->read_function)(info,0,0))
#define my_b_tell(info) ((info)->pos_in_file + \
- ((info)->rc_pos - (info)->rc_request_pos))
+ (uint) (*(info)->current_pos - (info)->request_pos))
+
+/* tell write offset in the SEQ_APPEND cache */
+my_off_t my_b_append_tell(IO_CACHE* info);
+
+#define my_b_bytes_in_cache(info) (uint) (*(info)->current_end - \
+ *(info)->current_pos)
-#define my_b_bytes_in_cache(info) ((uint) ((info)->rc_end - (info)->rc_pos))
typedef struct st_changeable_var {
const char *name; /* Name of variable */
@@ -388,6 +502,7 @@ extern File my_register_filename(File fd, const char *FileName,
extern File my_create(const char *FileName,int CreateFlags,
int AccsesFlags, myf MyFlags);
extern int my_close(File Filedes,myf MyFlags);
+extern File my_dup(File file, myf MyFlags);
extern int my_mkdir(const char *dir, int Flags, myf MyFlags);
extern int my_readlink(char *to, const char *filename, myf MyFlags);
extern int my_realpath(char *to, const char *filename, myf MyFlags);
@@ -465,12 +580,12 @@ extern uint dirname_part(my_string to,const char *name);
extern uint dirname_length(const char *name);
#define base_name(A) (A+dirname_length(A))
extern int test_if_hard_path(const char *dir_name);
-extern char *convert_dirname(my_string name);
+extern char *convert_dirname(char *to, const char *from, const char *from_end);
extern void to_unix_path(my_string name);
extern my_string fn_ext(const char *name);
extern my_string fn_same(my_string toname,const char *name,int flag);
-extern my_string fn_format(my_string to,const char *name,const char *dsk,
- const char *form,int flag);
+extern my_string fn_format(my_string to,const char *name,const char *dir,
+ const char *form, uint flag);
extern size_s strlength(const char *str);
extern void pack_dirname(my_string to,const char *from);
extern uint unpack_dirname(my_string to,const char *from);
@@ -529,13 +644,18 @@ extern my_bool reinit_io_cache(IO_CACHE *info,enum cache_type type,
my_off_t seek_offset,pbool use_async_io,
pbool clear_cache);
extern int _my_b_read(IO_CACHE *info,byte *Buffer,uint Count);
+extern int _my_b_seq_read(IO_CACHE *info,byte *Buffer,uint Count);
extern int _my_b_net_read(IO_CACHE *info,byte *Buffer,uint Count);
extern int _my_b_get(IO_CACHE *info);
extern int _my_b_async_read(IO_CACHE *info,byte *Buffer,uint Count);
extern int _my_b_write(IO_CACHE *info,const byte *Buffer,uint Count);
+extern int my_b_append(IO_CACHE *info,const byte *Buffer,uint Count);
extern int my_block_write(IO_CACHE *info, const byte *Buffer,
uint Count, my_off_t pos);
-extern int flush_io_cache(IO_CACHE *info);
+extern int _flush_io_cache(IO_CACHE *info, int need_append_buffer_lock);
+
+#define flush_io_cache(info) _flush_io_cache((info),1)
+
extern int end_io_cache(IO_CACHE *info);
extern uint my_b_fill(IO_CACHE *info);
extern void my_b_seek(IO_CACHE *info,my_off_t pos);
@@ -591,7 +711,9 @@ extern void my_free_lock(byte *ptr,myf flags);
void init_alloc_root(MEM_ROOT *mem_root, uint block_size, uint pre_alloc_size);
gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size);
void free_root(MEM_ROOT *root, myf MyFLAGS);
+void set_prealloc_root(MEM_ROOT *root, char *ptr);
char *strdup_root(MEM_ROOT *root,const char *str);
+char *strmake_root(MEM_ROOT *root,const char *str,uint len);
char *memdup_root(MEM_ROOT *root,const char *str,uint len);
void load_defaults(const char *conf_file, const char **groups,
int *argc, char ***argv);
@@ -601,6 +723,14 @@ my_bool my_compress(byte *, ulong *, ulong *);
my_bool my_uncompress(byte *, ulong *, ulong *);
byte *my_compress_alloc(const byte *packet, ulong *len, ulong *complen);
ulong checksum(const byte *mem, uint count);
+uint my_bit_log2(ulong value);
+
+#if defined(SAFE_MUTEX) && !defined(DBUG_OFF)
+#define DBUG_ASSERT_LOCK(lock) DBUG_ASSERT((lock)->count == 1 && \
+ (lock)->thread == pthread_self())
+#else
+#define DBUG_ASSERT_LOCK(lock)
+#endif
#if defined(_MSC_VER) && !defined(__WIN__)
extern void sleep(int sec);
@@ -609,8 +739,6 @@ extern void sleep(int sec);
extern my_bool have_tcpip; /* Is set if tcpip is used */
#endif
-#ifdef __cplusplus
-}
-#endif
+C_MODE_END
#include "raid.h"
#endif /* _my_sys_h */
diff --git a/include/my_tree.h b/include/my_tree.h
index 0a227ea3944..8b326a19518 100644
--- a/include/my_tree.h
+++ b/include/my_tree.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 _tree_h
#define _tree_h
@@ -32,6 +31,9 @@ typedef enum { left_root_right, right_root_left } TREE_WALK;
typedef uint32 element_count;
typedef int (*tree_walk_action)(void *,element_count,void *);
+typedef enum { free_init, free_free, free_end } TREE_FREE;
+typedef void (*tree_element_free)(void*, TREE_FREE, void *);
+
#ifdef MSDOS
typedef struct st_tree_element {
struct st_tree_element *left,*right;
@@ -49,18 +51,22 @@ typedef struct st_tree_element {
typedef struct st_tree {
TREE_ELEMENT *root,null_element;
TREE_ELEMENT **parents[MAX_TREE_HIGHT];
- uint offset_to_key,elements_in_tree,size_of_element;
- qsort_cmp compare;
+ uint offset_to_key,elements_in_tree,size_of_element,memory_limit,allocated;
+ qsort_cmp2 compare;
+ void* custom_arg;
MEM_ROOT mem_root;
my_bool with_delete;
- void (*free)(void *);
+ tree_element_free free;
} TREE;
- /* Functions on hole tree */
-void init_tree(TREE *tree,uint default_alloc_size, int element_size,
- qsort_cmp compare, my_bool with_delete,
- void (*free_element)(void*));
+ /* Functions on whole tree */
+void init_tree(TREE *tree, uint default_alloc_size, uint memory_limit,
+ int size, qsort_cmp2 compare, my_bool with_delete,
+ tree_element_free free_element, void *custom_arg);
void delete_tree(TREE*);
+void reset_tree(TREE*);
+ /* similar to delete tree, except we do not my_free() blocks in mem_root
+ */
#define is_tree_inited(tree) ((tree)->root != 0)
/* Functions on leafs */
diff --git a/include/myisam.h b/include/myisam.h
index 9ecb5ef4294..c79bdbe14c8 100644
--- a/include/myisam.h
+++ b/include/myisam.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 myisam_funktions */
@@ -46,6 +45,11 @@ extern "C" {
/* Max extra space to use when sorting keys */
#define MI_MAX_TEMP_LENGTH 256*1024L*1024L
+/* Possible values for myisam_block_size (must be power of 2) */
+#define MI_KEY_BLOCK_LENGTH 1024 /* default key block length */
+#define MI_MIN_KEY_BLOCK_LENGTH 1024 /* Min key block length */
+#define MI_MAX_KEY_BLOCK_LENGTH 16384
+
#define mi_portable_sizeof_char_ptr 8
typedef uint32 ha_checksum;
@@ -68,6 +72,7 @@ typedef struct st_mi_isaminfo /* Struct from h_info */
ulong mean_reclength; /* Mean recordlength (if packed) */
ulonglong auto_increment;
ulonglong key_map; /* Which keys are used */
+ char *data_file_name, *index_file_name;
uint keys; /* Number of keys in use */
uint options; /* HA_OPTION_... used */
int errkey, /* With key was dupplicated on err */
@@ -86,6 +91,7 @@ typedef struct st_mi_isaminfo /* Struct from h_info */
typedef struct st_mi_create_info
{
+ char *index_file_name, *data_file_name; /* If using symlinks */
ha_rows max_rows;
ha_rows reloc_rows;
ulonglong auto_increment;
@@ -120,6 +126,7 @@ typedef struct st_mi_keydef /* Key definition with open & info */
uint16 keysegs; /* Number of key-segment */
uint16 flag; /* NOSAME, PACK_USED */
+ uint8 key_alg; /* BTREE, RTREE */
uint16 block_length; /* Length of keyblock (auto) */
uint16 underflow_block_length; /* When to execute underflow */
uint16 keylength; /* Tot length of keyparts (auto) */
@@ -184,12 +191,15 @@ typedef struct st_columndef /* column information */
#endif
} MI_COLUMNDEF;
+/* invalidator function reference for Query Cache */
+typedef void (* invalidator_by_filename)(const char * filename);
extern my_string myisam_log_filename; /* Name of logfile */
extern uint myisam_block_size;
-extern my_bool myisam_flush,myisam_delay_key_write;
+extern my_bool myisam_flush,myisam_delay_key_write,myisam_single_user;
extern my_bool myisam_concurrent_insert;
extern my_off_t myisam_max_temp_length,myisam_max_extra_temp_length;
+extern ulong myisam_bulk_insert_tree_size;
/* Prototypes for myisam-functions */
@@ -219,7 +229,7 @@ extern my_off_t mi_position(struct st_myisam_info *file);
extern int mi_status(struct st_myisam_info *info, MI_ISAMINFO *x, uint flag);
extern int mi_lock_database(struct st_myisam_info *file,int lock_type);
extern int mi_create(const char *name,uint keys,MI_KEYDEF *keydef,
- uint columns, MI_COLUMNDEF *columndef,
+ uint columns, MI_COLUMNDEF *columndef,
uint uniques, MI_UNIQUEDEF *uniquedef,
MI_CREATE_INFO *create_info, uint flags);
extern int mi_delete_table(const char *name);
@@ -245,36 +255,45 @@ extern uint mi_get_pointer_length(ulonglong file_length, uint def);
/* definitions needed for myisamchk.c -- by Sasha Pachev */
-#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 T_FAST 65536L
-#define T_READONLY 131072L
-#define T_MEDIUM T_READONLY*2
-#define T_AUTO_INC T_MEDIUM*2
-#define T_CHECK T_AUTO_INC*2
-#define T_UPDATE_STATE T_CHECK*2
-#define T_CHECK_ONLY_CHANGED T_UPDATE_STATE*2
-#define T_DONT_CHECK_CHECKSUM T_CHECK_ONLY_CHANGED*2
-#define T_TRUST_HEADER T_DONT_CHECK_CHECKSUM*2
-#define T_CREATE_MISSING_KEYS T_TRUST_HEADER*2
-#define T_SAFE_REPAIR T_CREATE_MISSING_KEYS*2
-#define T_AUTO_REPAIR T_SAFE_REPAIR*2
-#define T_BACKUP_DATA T_AUTO_REPAIR*2
-#define T_CALC_CHECKSUM T_BACKUP_DATA*2
+/* entries marked as "QQ to be removed" are NOT used to
+ * pass check/repair options to mi_check.c. They are used
+ * internally by myisamchk.c or/and ha_myisam.cc and should NOT
+ * be stored together with other flags. They should be removed
+ * from the following list to make adding of new flags possible.
+ * -- Sergei */
+
+#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_FORCE_UNIQUENESS 64
+#define T_FORCE_CREATE 128
+#define T_WRITE_LOOP 256
+#define T_UNPACK 512
+#define T_STATISTICS (1L << 10)
+#define T_VERY_SILENT (1L << 11)
+#define T_SORT_RECORDS (1L << 12) /* QQ to be removed */
+#define T_SORT_INDEX (1L << 13) /* QQ to be removed */
+#define T_WAIT_FOREVER (1L << 14)
+#define T_REP_BY_SORT (1L << 15)
+#define T_FAST (1L << 16) /* QQ to be removed */
+#define T_READONLY (1L << 17) /* QQ to be removed */
+#define T_MEDIUM (1L << 18)
+#define T_AUTO_INC (1L << 19)
+#define T_CHECK (1L << 20) /* QQ to be removed */
+#define T_UPDATE_STATE (1L << 21)
+#define T_CHECK_ONLY_CHANGED (1L << 22) /* QQ to be removed */
+#define T_DONT_CHECK_CHECKSUM (1L << 23)
+#define T_TRUST_HEADER (1L << 24)
+#define T_CREATE_MISSING_KEYS (1L << 25)
+#define T_SAFE_REPAIR (1L << 26)
+#define T_AUTO_REPAIR (1L << 27) /* QQ to be removed */
+#define T_BACKUP_DATA (1L << 28)
+#define T_CALC_CHECKSUM (1L << 29)
+#define T_QUICK (1L << 30)
+#define T_RETRY_WITHOUT_QUICK (1L << 31)
#define O_NEW_INDEX 1 /* Bits set in out_flag */
#define O_NEW_DATA 2
@@ -296,17 +315,17 @@ typedef struct st_sort_info {
struct st_mi_check_param *param;
enum data_file_type new_data_file_type;
SORT_KEY_BLOCKS *key_block,*key_block_end;
- uint key,find_length;
+ uint key,find_length,real_key_length;
my_off_t pos,max_pos,filepos,start_recpos,filelength,dupp,buff_length;
ha_rows max_records;
ulonglong unique[MI_MAX_KEY_SEG+1];
my_bool fix_datafile;
char *record,*buff;
+ void *wordlist, *wordptr;
MI_KEYDEF *keyinfo;
MI_KEYSEG *keyseg;
} SORT_INFO;
-
typedef struct st_mi_check_param
{
ulonglong auto_increment_value;
@@ -319,13 +338,12 @@ typedef struct st_mi_check_param
ha_checksum record_checksum,glob_crc;
ulong use_buffers,read_buffer_length,write_buffer_length,
sort_buffer_length,sort_key_blocks;
- uint out_flag,warning_printed,error_printed,
- opt_rep_quick,verbose;
+ uint out_flag,warning_printed,error_printed,verbose;
uint opt_sort_key,total_files,max_level;
uint testflag;
uint8 language;
my_bool using_global_keycache, opt_lock_memory, opt_follow_links;
- my_bool retry_repair,retry_without_quick, force_sort, calc_checksum;
+ my_bool retry_repair, force_sort, calc_checksum;
char temp_filename[FN_REFLEN],*isam_file_name,*tmpdir;
int tmpfile_createflag;
myf myf_rw;
diff --git a/include/myisammrg.h b/include/myisammrg.h
index a797c954614..acf80ee2adf 100644
--- a/include/myisammrg.h
+++ b/include/myisammrg.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000 MySQL AB
- 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 program is free software; 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 library is distributed in the hope that it will be useful,
+ This program is distributed in the hope that 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.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU 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 */
+ You should have received a copy of the GNU General Public 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 */
@@ -34,6 +33,13 @@ extern "C" {
#define MYRG_NAME_EXT ".MRG"
+/* In which table to INSERT rows */
+#define MERGE_INSERT_DISABLED 0
+#define MERGE_INSERT_TO_FIRST 1
+#define MERGE_INSERT_TO_LAST 2
+
+extern TYPELIB merge_insert_method;
+
/* Param to/from myrg_info */
typedef struct st_mymerge_info /* Struct from h_info */
@@ -44,7 +50,7 @@ typedef struct st_mymerge_info /* Struct from h_info */
ulonglong data_file_length;
uint reclength; /* Recordlength */
int errkey; /* With key was dupplicated on err */
- uint options; /* HA_OPTIONS_... used */
+ uint options; /* HA_OPTION_... used */
} MYMERGE_INFO;
typedef struct st_myrg_table_info
@@ -56,6 +62,7 @@ typedef struct st_myrg_table_info
typedef struct st_myrg_info
{
MYRG_TABLE *open_tables,*current_table,*end_table,*last_used_table;
+ uint merge_insert_method;
ulonglong records; /* records in tables */
ulonglong del; /* Removed records */
ulonglong data_file_length;
@@ -81,11 +88,13 @@ extern int myrg_rkey(MYRG_INFO *file,byte *buf,int inx,const byte *key,
extern int myrg_rrnd(MYRG_INFO *file,byte *buf,ulonglong pos);
extern int myrg_rsame(MYRG_INFO *file,byte *record,int inx);
extern int myrg_update(MYRG_INFO *file,const byte *old,byte *new_rec);
+extern int myrg_write(MYRG_INFO *info,byte *rec);
extern int myrg_status(MYRG_INFO *file,MYMERGE_INFO *x,int flag);
extern int myrg_lock_database(MYRG_INFO *file,int lock_type);
-extern int myrg_create(const char *name,const char **table_names,
- my_bool fix_names);
+extern int myrg_create(const char *name, const char **table_names,
+ uint insert_method, my_bool fix_names);
extern int myrg_extra(MYRG_INFO *file,enum ha_extra_function function);
+extern void myrg_extrafunc(MYRG_INFO *info,invalidator_by_filename inv);
extern ha_rows myrg_records_in_range(MYRG_INFO *info,int inx,
const byte *start_key,uint start_key_len,
enum ha_rkey_function start_search_flag,
diff --git a/include/myisampack.h b/include/myisampack.h
index a51cdc7e6eb..31666bb184c 100644
--- a/include/myisampack.h
+++ b/include/myisampack.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
Storing of values in high byte first order.
diff --git a/include/mysql.h b/include/mysql.h
index 0bd5b7092b8..074ea0a1876 100644
--- a/include/mysql.h
+++ b/include/mysql.h
@@ -1,21 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
-/* defines for the libmysql library */
+ You should have received a copy of the GNU General Public 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 _mysql_h
#define _mysql_h
@@ -28,12 +25,10 @@
#undef __WIN__
#endif
-#ifndef MYSQL_SERVER
#ifdef __cplusplus
extern "C" {
#endif
-#endif
-
+
#ifndef _global_h /* If not standard header */
#include <sys/types.h>
#ifdef __LCC__
@@ -50,32 +45,15 @@ typedef char my_bool;
#endif
typedef char * gptr;
-#ifndef ST_USED_MEM_DEFINED
-#define ST_USED_MEM_DEFINED
-typedef struct st_used_mem { /* struct for once_alloc */
- struct st_used_mem *next; /* Next block in use */
- unsigned int left; /* memory left in block */
- unsigned int size; /* size of block */
-} USED_MEM;
-typedef struct st_mem_root {
- USED_MEM *free;
- USED_MEM *used;
- USED_MEM *pre_alloc;
- unsigned int min_malloc;
- unsigned int block_size;
-
- void (*error_handler)(void);
-} MEM_ROOT;
-#endif
-
#ifndef my_socket_defined
#ifdef __WIN__
#define my_socket SOCKET
#else
typedef int my_socket;
-#endif
-#endif
-#endif
+#endif /* __WIN__ */
+#endif /* my_socket_defined */
+#endif /* _global_h */
+
#include "mysql_com.h"
#include "mysql_version.h"
@@ -92,12 +70,14 @@ extern char *mysql_unix_port;
typedef struct st_mysql_field {
char *name; /* Name of column */
char *table; /* Table of column if column was a field */
+ char *org_table; /* Org table name if table was an alias */
+ char *db; /* Database for table */
char *def; /* Default value (set by mysql_list_fields) */
- enum enum_field_types type; /* Type of field. Se mysql_com.h for types */
- unsigned int length; /* Width of column */
- unsigned int max_length; /* Max width of selected set */
+ unsigned long length; /* Width of column */
+ unsigned long max_length; /* Max width of selected set */
unsigned int flags; /* Div flags */
unsigned int decimals; /* Number of decimals in field */
+ enum enum_field_types type; /* Type of field. Se mysql_com.h for types */
} MYSQL_FIELD;
typedef char **MYSQL_ROW; /* return data as array of strings */
@@ -120,6 +100,24 @@ typedef struct st_mysql_rows {
typedef MYSQL_ROWS *MYSQL_ROW_OFFSET; /* offset to current row */
+#ifndef ST_USED_MEM_DEFINED
+#define ST_USED_MEM_DEFINED
+typedef struct st_used_mem { /* struct for once_alloc */
+ struct st_used_mem *next; /* Next block in use */
+ unsigned int left; /* memory left in block */
+ unsigned int size; /* size of block */
+} USED_MEM;
+typedef struct st_mem_root {
+ USED_MEM *free;
+ USED_MEM *used;
+ USED_MEM *pre_alloc;
+ unsigned int min_malloc;
+ unsigned int block_size;
+
+ void (*error_handler)(void);
+} MEM_ROOT;
+#endif
+
typedef struct st_mysql_data {
my_ulonglong rows;
unsigned int fields;
@@ -129,15 +127,31 @@ typedef struct st_mysql_data {
struct st_mysql_options {
unsigned int connect_timeout,client_flag;
- my_bool compress,named_pipe;
unsigned int port;
char *host,*init_command,*user,*password,*unix_socket,*db;
char *my_cnf_file,*my_cnf_group, *charset_dir, *charset_name;
- my_bool use_ssl; /* if to use SSL or not */
char *ssl_key; /* PEM key file */
char *ssl_cert; /* PEM cert file */
char *ssl_ca; /* PEM CA file */
char *ssl_capath; /* PEM directory of CA-s? */
+ char *ssl_cipher; /* cipher to use */
+ my_bool use_ssl; /* if to use SSL or not */
+ my_bool compress,named_pipe;
+ /*
+ on connect, find out the replication role of the server, and
+ establish connections to all the peers
+ */
+ my_bool rpl_probe;
+ /*
+ each call to mysql_real_query() will parse it to tell if it is a read
+ or a write, and direct it to the slave or the master
+ */
+ my_bool rpl_parse;
+ /*
+ if set, never read from a master,only from slave, when doing
+ a read that is replication-aware
+ */
+ my_bool no_master_reads;
};
enum mysql_option { MYSQL_OPT_CONNECT_TIMEOUT, MYSQL_OPT_COMPRESS,
@@ -149,46 +163,106 @@ enum mysql_option { MYSQL_OPT_CONNECT_TIMEOUT, MYSQL_OPT_COMPRESS,
enum mysql_status { MYSQL_STATUS_READY,MYSQL_STATUS_GET_RESULT,
MYSQL_STATUS_USE_RESULT};
+/*
+ There are three types of queries - the ones that have to go to
+ the master, the ones that go to a slave, and the adminstrative
+ type which must happen on the pivot connectioin
+*/
+enum mysql_rpl_type { MYSQL_RPL_MASTER, MYSQL_RPL_SLAVE,
+ MYSQL_RPL_ADMIN };
+
+
typedef struct st_mysql {
NET net; /* Communication parameters */
gptr connector_fd; /* ConnectorFd for SSL */
char *host,*user,*passwd,*unix_socket,*server_version,*host_info,
*info,*db;
- unsigned int port,client_flag,server_capabilities;
- unsigned int protocol_version;
- unsigned int field_count;
- unsigned int server_status;
- unsigned long thread_id; /* Id for connection in server */
+ struct charset_info_st *charset;
+ MYSQL_FIELD *fields;
+ 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 */
+ unsigned long thread_id; /* Id for connection in server */
unsigned long packet_length;
+ unsigned int port,client_flag,server_capabilities;
+ unsigned int protocol_version;
+ unsigned int field_count;
+ unsigned int server_status;
+ unsigned int server_language;
+ struct st_mysql_options options;
enum mysql_status status;
- MYSQL_FIELD *fields;
- MEM_ROOT field_alloc;
my_bool free_me; /* If free in mysql_close */
my_bool reconnect; /* set to 1 if automatic reconnect */
- struct st_mysql_options options;
char scramble_buff[9];
- struct charset_info_st *charset;
- unsigned int server_language;
+
+ /*
+ Set if this is the original connection, not a master or a slave we have
+ added though mysql_rpl_probe() or mysql_set_master()/ mysql_add_slave()
+ */
+ my_bool rpl_pivot;
+ /* pointers to the master, and the next slave
+ connections, points to itself if lone connection */
+ struct st_mysql* master, *next_slave;
+
+ struct st_mysql* last_used_slave; /* needed for round-robin slave pick */
+ /* needed for send/read/store/use result to work correctly with replication */
+ struct st_mysql* last_used_con;
} MYSQL;
typedef struct st_mysql_res {
my_ulonglong row_count;
- unsigned int field_count, current_field;
MYSQL_FIELD *fields;
MYSQL_DATA *data;
MYSQL_ROWS *data_cursor;
+ unsigned long *lengths; /* column lengths of current row */
+ MYSQL *handle; /* for unbuffered reads */
MEM_ROOT field_alloc;
+ unsigned int field_count, current_field;
MYSQL_ROW row; /* If unbuffered read */
MYSQL_ROW current_row; /* buffer to current row */
- unsigned long *lengths; /* column lengths of current row */
- MYSQL *handle; /* for unbuffered reads */
- my_bool eof; /* Used my mysql_fetch_row */
+ my_bool eof; /* Used by mysql_fetch_row */
} MYSQL_RES;
+#define MAX_MYSQL_MANAGER_ERR 256
+#define MAX_MYSQL_MANAGER_MSG 256
+
+#define MANAGER_OK 200
+#define MANAGER_INFO 250
+#define MANAGER_ACCESS 401
+#define MANAGER_CLIENT_ERR 450
+#define MANAGER_INTERNAL_ERR 500
+
+
+
+typedef struct st_mysql_manager
+{
+ NET net;
+ char *host,*user,*passwd;
+ unsigned int port;
+ my_bool free_me;
+ my_bool eof;
+ int cmd_status;
+ int last_errno;
+ char* net_buf,*net_buf_pos,*net_data_end;
+ int net_buf_size;
+ char last_error[MAX_MYSQL_MANAGER_ERR];
+} MYSQL_MANAGER;
+
+/* Set up and bring down the server; to ensure that applications will
+ * work when linked against either the standard client library or the
+ * embedded server library, these functions should be called. */
+int STDCALL mysql_server_init(int argc, char **argv, char **groups);
+void STDCALL mysql_server_end(void);
+
+/* Set up and bring down a thread; these function should be called
+ * for each thread in an application which opens at least one MySQL
+ * connection. All uses of the connection(s) should be between these
+ * function calls. */
+my_bool STDCALL mysql_thread_init(void);
+void STDCALL mysql_thread_end(void);
+
/* Functions to get information from the MYSQL and MYSQL_RES structures */
/* Should definitely be used if one uses shared libraries */
@@ -211,18 +285,12 @@ unsigned long STDCALL mysql_thread_id(MYSQL *mysql);
const char * STDCALL mysql_character_set_name(MYSQL *mysql);
MYSQL * STDCALL mysql_init(MYSQL *mysql);
-#ifdef HAVE_OPENSSL
int STDCALL mysql_ssl_set(MYSQL *mysql, const char *key,
const char *cert, const char *ca,
- const char *capath);
-char * STDCALL mysql_ssl_cipher(MYSQL *mysql);
+ const char *capath, const char *cipher);
int STDCALL mysql_ssl_clear(MYSQL *mysql);
-#endif /* HAVE_OPENSSL */
-MYSQL * STDCALL mysql_connect(MYSQL *mysql, const char *host,
- const char *user, const char *passwd);
my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
const char *passwd, const char *db);
-#if MYSQL_VERSION_ID >= 32200
MYSQL * STDCALL mysql_real_connect(MYSQL *mysql, const char *host,
const char *user,
const char *passwd,
@@ -230,24 +298,55 @@ MYSQL * STDCALL mysql_real_connect(MYSQL *mysql, const char *host,
unsigned int port,
const char *unix_socket,
unsigned int clientflag);
-#else
-MYSQL * STDCALL mysql_real_connect(MYSQL *mysql, const char *host,
- const char *user,
- const char *passwd,
- unsigned int port,
- const char *unix_socket,
- unsigned int clientflag);
-#endif
void STDCALL mysql_close(MYSQL *sock);
int STDCALL mysql_select_db(MYSQL *mysql, const char *db);
int STDCALL mysql_query(MYSQL *mysql, const char *q);
int STDCALL mysql_send_query(MYSQL *mysql, const char *q,
- unsigned int length);
+ unsigned long length);
int STDCALL mysql_read_query_result(MYSQL *mysql);
int STDCALL mysql_real_query(MYSQL *mysql, const char *q,
- unsigned int length);
-int STDCALL mysql_create_db(MYSQL *mysql, const char *DB);
-int STDCALL mysql_drop_db(MYSQL *mysql, const char *DB);
+ unsigned long length);
+/* perform query on master */
+int STDCALL mysql_master_query(MYSQL *mysql, const char *q,
+ unsigned long length);
+int STDCALL mysql_master_send_query(MYSQL *mysql, const char *q,
+ unsigned long length);
+/* perform query on slave */
+int STDCALL mysql_slave_query(MYSQL *mysql, const char *q,
+ unsigned long length);
+int STDCALL mysql_slave_send_query(MYSQL *mysql, const char *q,
+ unsigned long length);
+
+/*
+ enable/disable parsing of all queries to decide if they go on master or
+ slave
+*/
+void STDCALL mysql_enable_rpl_parse(MYSQL* mysql);
+void STDCALL mysql_disable_rpl_parse(MYSQL* mysql);
+/* get the value of the parse flag */
+int STDCALL mysql_rpl_parse_enabled(MYSQL* mysql);
+
+/* enable/disable reads from master */
+void STDCALL mysql_enable_reads_from_master(MYSQL* mysql);
+void STDCALL mysql_disable_reads_from_master(MYSQL* mysql);
+/* get the value of the master read flag */
+int STDCALL mysql_reads_from_master_enabled(MYSQL* mysql);
+
+enum mysql_rpl_type STDCALL mysql_rpl_query_type(const char* q, int len);
+
+/* discover the master and its slaves */
+int STDCALL mysql_rpl_probe(MYSQL* mysql);
+
+/* set the master, close/free the old one, if it is not a pivot */
+int STDCALL mysql_set_master(MYSQL* mysql, const char* host,
+ unsigned int port,
+ const char* user,
+ const char* passwd);
+int STDCALL mysql_add_slave(MYSQL* mysql, const char* host,
+ unsigned int port,
+ const char* user,
+ const char* passwd);
+
int STDCALL mysql_shutdown(MYSQL *mysql);
int STDCALL mysql_dump_debug_info(MYSQL *mysql);
int STDCALL mysql_refresh(MYSQL *mysql,
@@ -295,18 +394,40 @@ char * STDCALL mysql_odbc_escape_string(MYSQL *mysql,
unsigned long *length));
void STDCALL myodbc_remove_escape(MYSQL *mysql,char *name);
unsigned int STDCALL mysql_thread_safe(void);
-
-
+MYSQL_MANAGER* STDCALL mysql_manager_init(MYSQL_MANAGER* con);
+MYSQL_MANAGER* STDCALL mysql_manager_connect(MYSQL_MANAGER* con,
+ const char* host,
+ const char* user,
+ const char* passwd,
+ unsigned int port);
+void STDCALL mysql_manager_close(MYSQL_MANAGER* con);
+int STDCALL mysql_manager_command(MYSQL_MANAGER* con,
+ const char* cmd, int cmd_len);
+int STDCALL mysql_manager_fetch_line(MYSQL_MANAGER* con,
+ char* res_buf,
+ int res_buf_size);
#define mysql_reload(mysql) mysql_refresh((mysql),REFRESH_GRANT)
-/* new api functions */
-
+#ifdef USE_OLD_FUNCTIONS
+MYSQL * STDCALL mysql_connect(MYSQL *mysql, const char *host,
+ const char *user, const char *passwd);
+int STDCALL mysql_create_db(MYSQL *mysql, const char *DB);
+int STDCALL mysql_drop_db(MYSQL *mysql, const char *DB);
+#define mysql_reload(mysql) mysql_refresh((mysql),REFRESH_GRANT)
+#endif
#define HAVE_MYSQL_REAL_CONNECT
-#ifndef MYSQL_SERVER
+/*
+ The following functions are mainly exported because of mysqlbinlog;
+ They are not for general usage
+*/
+
+int simple_command(MYSQL *mysql,enum enum_server_command command,
+ const char *arg, unsigned long length, my_bool skipp_check);
+unsigned long net_safe_read(MYSQL* mysql);
+
#ifdef __cplusplus
}
#endif
-#endif
-#endif
+#endif /* _mysql_h */
diff --git a/include/mysql_com.h b/include/mysql_com.h
index 525a631caf6..269fc665b07 100644
--- a/include/mysql_com.h
+++ b/include/mysql_com.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
** Common definition between mysql server & client
@@ -42,7 +41,8 @@ enum enum_server_command {COM_SLEEP,COM_QUIT,COM_INIT_DB,COM_QUERY,
COM_PROCESS_INFO,COM_CONNECT,COM_PROCESS_KILL,
COM_DEBUG,COM_PING,COM_TIME,COM_DELAYED_INSERT,
COM_CHANGE_USER, COM_BINLOG_DUMP,
- COM_TABLE_DUMP, COM_CONNECT_OUT};
+ COM_TABLE_DUMP, COM_CONNECT_OUT,
+ COM_REGISTER_SLAVE};
#define NOT_NULL_FLAG 1 /* Field can't be NULL */
#define PRI_KEY_FLAG 2 /* Field is part of a primary key */
@@ -77,6 +77,11 @@ enum enum_server_command {COM_SLEEP,COM_QUIT,COM_INIT_DB,COM_QUERY,
#define REFRESH_READ_LOCK 16384 /* Lock tables for read */
#define REFRESH_FAST 32768 /* Intern flag */
+/* RESET (remove all queries) from query cache */
+#define REFRESH_QUERY_CACHE 65536
+#define REFRESH_QUERY_CACHE_FREE 0x20000L /* pack query cache */
+#define REFRESH_DES_KEY_FILE 0x40000L
+
#define CLIENT_LONG_PASSWORD 1 /* new more secure passwords */
#define CLIENT_FOUND_ROWS 2 /* Found instead of affected rows */
#define CLIENT_LONG_FLAG 4 /* Get all column flags */
@@ -100,36 +105,36 @@ enum enum_server_command {COM_SLEEP,COM_QUIT,COM_INIT_DB,COM_QUERY,
#define NET_WRITE_TIMEOUT 60 /* Timeout on write */
#define NET_WAIT_TIMEOUT 8*60*60 /* Wait for new query */
-#ifndef Vio_defined
-#define Vio_defined
-#ifdef HAVE_VIO
-class Vio; /* Fill Vio class in C++ */
-#else
struct st_vio; /* Only C */
typedef struct st_vio Vio;
-#endif
-#endif
+
+#define MAX_CHAR_WIDTH 255 /* Max length for a CHAR colum */
+#define MAX_BLOB_WIDTH 8192 /* Default width for blob */
typedef struct st_net {
Vio* vio;
+ unsigned char *buff,*buff_end,*write_pos,*read_pos;
my_socket fd; /* For Perl DBI/dbd */
+ unsigned long max_packet;
int fcntl;
- unsigned char *buff,*buff_end,*write_pos,*read_pos;
+ unsigned int last_errno,timeout,pkt_nr,compress_pkt_nr;
char last_error[MYSQL_ERRMSG_SIZE];
- unsigned int last_errno,max_packet,timeout,pkt_nr;
unsigned char error;
my_bool return_errno,compress;
- my_bool no_send_ok; /* needed if we are doing several
- queries in one command ( as in LOAD TABLE ... FROM MASTER ),
- and do not want to confuse the client with OK at the wrong time
- */
+ /*
+ The following variable is set if we are doing several queries in one
+ command ( as in LOAD TABLE ... FROM MASTER ),
+ and do not want to confuse the client with OK at the wrong time
+ */
unsigned long remain_in_buf,length, buf_length, where_b;
unsigned int *return_status;
unsigned char reading_or_writing;
char save_char;
+ my_bool no_send_ok;
+ gptr query_cache_query;
} NET;
-#define packet_error ((unsigned int) -1)
+#define packet_error (~(unsigned long) 0)
enum enum_field_types { FIELD_TYPE_DECIMAL, FIELD_TYPE_TINY,
FIELD_TYPE_SHORT, FIELD_TYPE_LONG,
@@ -146,17 +151,22 @@ enum enum_field_types { FIELD_TYPE_DECIMAL, FIELD_TYPE_TINY,
FIELD_TYPE_LONG_BLOB=251,
FIELD_TYPE_BLOB=252,
FIELD_TYPE_VAR_STRING=253,
- FIELD_TYPE_STRING=254
+ FIELD_TYPE_STRING=254,
+ FIELD_TYPE_GEOMETRY=255
};
#define FIELD_TYPE_CHAR FIELD_TYPE_TINY /* For compability */
#define FIELD_TYPE_INTERVAL FIELD_TYPE_ENUM /* For compability */
+#define net_new_transaction(net) ((net)->pkt_nr=0)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
extern unsigned long max_allowed_packet;
extern unsigned long net_buffer_length;
-#define net_new_transaction(net) ((net)->pkt_nr=0)
-
int my_net_init(NET *net, Vio* vio);
void net_end(NET *net);
void net_clear(NET *net);
@@ -165,13 +175,22 @@ int my_net_write(NET *net,const char *packet,unsigned long len);
int net_write_command(NET *net,unsigned char command,const char *packet,
unsigned long len);
int net_real_write(NET *net,const char *packet,unsigned long len);
-unsigned int my_net_read(NET *net);
+unsigned long my_net_read(NET *net);
+
+/* The following function is not meant for normal usage */
+struct sockaddr;
+int my_connect(my_socket s, const struct sockaddr *name, unsigned int namelen,
+ unsigned int timeout);
struct rand_struct {
unsigned long seed1,seed2,max_value;
double max_value_dbl;
};
+#ifdef __cplusplus
+}
+#endif
+
/* The following is for user defined functions */
enum Item_result {STRING_RESULT,REAL_RESULT,INT_RESULT};
@@ -191,7 +210,7 @@ typedef struct st_udf_init
{
my_bool maybe_null; /* 1 if function can return NULL */
unsigned int decimals; /* for real functions */
- unsigned int max_length; /* For string functions */
+ unsigned long max_length; /* For string functions */
char *ptr; /* free pointer for function data */
my_bool const_item; /* 0 if result is independent of arguments */
} UDF_INIT;
@@ -205,7 +224,7 @@ typedef struct st_udf_init
#ifdef __cplusplus
extern "C" {
#endif
-
+
void randominit(struct rand_struct *,unsigned long seed1,
unsigned long seed2);
double rnd(struct rand_struct *);
diff --git a/include/mysql_embed.h b/include/mysql_embed.h
new file mode 100644
index 00000000000..58a743771fa
--- /dev/null
+++ b/include/mysql_embed.h
@@ -0,0 +1,30 @@
+/* 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 */
+
+/* Defines that are unique to the embedded version of MySQL */
+
+#ifdef EMBEDDED_LIBRARY
+
+/* Things we don't need in the embedded version of MySQL */
+
+#undef HAVE_PSTACK /* No stacktrace */
+#undef HAVE_DLOPEN /* No udf functions */
+#undef HAVE_OPENSSL
+#undef HAVE_VIO
+#undef HAVE_ISAM
+
+#define DONT_USE_RAID
+#endif /* EMBEDDED_LIBRARY */
diff --git a/include/mysqld_error.h b/include/mysqld_error.h
index 81e0dd1d06d..c910078331e 100644
--- a/include/mysqld_error.h
+++ b/include/mysqld_error.h
@@ -1,3 +1,19 @@
+/* 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 errormessagenumbers */
#define ER_HASHCHK 1000
@@ -218,4 +234,13 @@
#define ER_CANNOT_ADD_FOREIGN 1215
#define ER_NO_REFERENCED_ROW 1216
#define ER_ROW_IS_REFERENCED 1217
-#define ER_ERROR_MESSAGES 218
+#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_ERROR_MESSAGES 227
diff --git a/include/mysys_err.h b/include/mysys_err.h
index 2d23ead36b6..b3d058aff3e 100644
--- a/include/mysys_err.h
+++ b/include/mysys_err.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 _mysys_err_h
#define _mysys_err_h
diff --git a/include/nisam.h b/include/nisam.h
index 7ce2b44ee79..e8f29991a4e 100644
--- a/include/nisam.h
+++ b/include/nisam.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 */
diff --git a/include/queues.h b/include/queues.h
index 66125e650ca..70cb99a1513 100644
--- a/include/queues.h
+++ b/include/queues.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
Code for generell handling of priority Queues.
@@ -53,6 +52,7 @@ void delete_queue(QUEUE *queue);
void queue_insert(QUEUE *queue,byte *element);
byte *queue_remove(QUEUE *queue,uint idx);
void _downheap(QUEUE *queue,uint idx);
+void queue_fix(QUEUE *queue);
#define is_queue_inited(queue) ((queue)->root != 0)
#ifdef __cplusplus
diff --git a/include/raid.h b/include/raid.h
index 8cbd0f1a442..4a988760157 100644
--- a/include/raid.h
+++ b/include/raid.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000 MySQL AB
- 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 program is free software; 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 library is distributed in the hope that it will be useful,
+ This program is distributed in the hope that 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.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU 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 */
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Parser needs these defines always, even if USE_RAID is not defined */
#define RAID_TYPE_0 1 /* Striping */
@@ -23,15 +22,10 @@
#define RAID_DEFAULT_CHUNKS 4
#define RAID_DEFAULT_CHUNKSIZE 256*1024 /* 256kB */
+C_MODE_START
+#define my_raid_type(raid_type) raid_type_string[(int)(raid_type)]
extern const char *raid_type_string[];
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-const char *my_raid_type(int raid_type);
-#ifdef __cplusplus
-}
-#endif
+C_MODE_END
#if defined(USE_RAID) && !defined(DONT_USE_RAID)
diff --git a/include/sslopt-case.h b/include/sslopt-case.h
index d995e31044e..ae6026f9136 100644
--- a/include/sslopt-case.h
+++ b/include/sslopt-case.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 HAVE_OPENSSL
case OPT_SSL_SSL:
@@ -36,7 +35,12 @@
break;
case OPT_SSL_CAPATH:
opt_use_ssl = 1; /* true */
- my_free(opt_ssl_ca, MYF(MY_ALLOW_ZERO_PTR));
- opt_ssl_ca = my_strdup(optarg, MYF(0));
+ my_free(opt_ssl_capath, MYF(MY_ALLOW_ZERO_PTR));
+ opt_ssl_capath = my_strdup(optarg, MYF(0));
+ break;
+ case OPT_SSL_CIPHER:
+ opt_use_ssl = 1; /* true */
+ my_free(opt_ssl_cipher, MYF(MY_ALLOW_ZERO_PTR));
+ opt_ssl_cipher = my_strdup(optarg, MYF(0));
break;
#endif
diff --git a/include/sslopt-longopts.h b/include/sslopt-longopts.h
index 2f58f0e9265..2a0f27f3235 100644
--- a/include/sslopt-longopts.h
+++ b/include/sslopt-longopts.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 HAVE_OPENSSL
@@ -22,10 +21,12 @@
#define OPT_SSL_CERT 202
#define OPT_SSL_CA 203
#define OPT_SSL_CAPATH 204
+#define OPT_SSL_CIPHER 205
{"ssl", no_argument, 0, OPT_SSL_SSL},
{"ssl-key", required_argument, 0, OPT_SSL_KEY},
{"ssl-cert", required_argument, 0, OPT_SSL_CERT},
{"ssl-ca", required_argument, 0, OPT_SSL_CA},
{"ssl-capath", required_argument, 0, OPT_SSL_CAPATH},
+ {"ssl-cipher", required_argument, 0, OPT_SSL_CIPHER},
#endif /* HAVE_OPENSSL */
diff --git a/include/sslopt-usage.h b/include/sslopt-usage.h
index 5b2b4a88709..e5e374dea44 100644
--- a/include/sslopt-usage.h
+++ b/include/sslopt-usage.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 OPEN_SSL
puts("\
@@ -21,5 +20,6 @@
--ssl-key X509 key in PEM format (implies --ssl)\n\
--ssl-cert X509 cert in PEM format (implies --ssl)\n\
--ssl-ca CA file in PEM format (check OpenSSL docs, implies --ssl)\n\
- --ssl-capath CA directory (check OpenSSL docs, implies --ssl)");
+ --ssl-capath CA directory (check OpenSSL docs, implies --ssl)\n\
+ --ssl-cipher SSL cipher to use (implies --ssl)");
#endif
diff --git a/include/sslopt-vars.h b/include/sslopt-vars.h
index 597ab4d9fa6..164cf541381 100644
--- a/include/sslopt-vars.h
+++ b/include/sslopt-vars.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 HAVE_OPENSSL
static my_bool opt_use_ssl = 0;
@@ -21,4 +20,5 @@ static char *opt_ssl_key = 0;
static char *opt_ssl_cert = 0;
static char *opt_ssl_ca = 0;
static char *opt_ssl_capath = 0;
+static char *opt_ssl_cipher = 0;
#endif
diff --git a/include/t_ctype.h b/include/t_ctype.h
index f6e799828e6..3e190977e6c 100644
--- a/include/t_ctype.h
+++ b/include/t_ctype.h
@@ -1,3 +1,19 @@
+/* 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 */
+
/*
Copyright (C) 1998, 1999 by Pruet Boonma, all rights reserved.
Copyright (C) 1998 by Theppitak Karoonboonyanan, all rights reserved.
@@ -121,7 +137,7 @@ enum l1_symbols {
L1_SARA_AI_MAIMUAN,
L1_SARA_AI_MAIMALAI
};
-
+
/* level 2 symbols & order */
enum l2_symbols {
L2_BLANK = TOT_LEVELS,
@@ -135,7 +151,7 @@ enum l2_symbols {
L2_TONE3,
L2_TONE4
};
-
+
/* level 3 symbols & order */
enum l3_symbols {
L3_BLANK = TOT_LEVELS,
diff --git a/include/thr_alarm.h b/include/thr_alarm.h
index 1f3fed1d29b..5caf552718c 100644
--- a/include/thr_alarm.h
+++ b/include/thr_alarm.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Prototypes when using thr_alarm library functions */
@@ -39,24 +38,23 @@ extern "C" {
#define THR_SERVER_ALARM SIGALRM
#endif
-#if defined(DONT_USE_THR_ALARM)
+#if defined(DONT_USE_THR_ALARM) || !defined(THREAD)
#define USE_ALARM_THREAD
#undef USE_ONE_SIGNAL_HAND
-typedef struct st_thr_alarm_entry
-{
- uint crono;
-} thr_alarm_entry;
+typedef my_bool thr_alarm_t;
+typedef my_bool ALARM;
-#define thr_alarm_init(A) (A)->crono=0
-#define thr_alarm_in_use(A) (A)->crono
+#define thr_alarm_init(A) (*(A))=0
+#define thr_alarm_in_use(A) (*(A) != 0)
+#define thr_end_alarm(A)
+#define thr_alarm(A,B,C) ((*(A)=1)-1)
+/* The following should maybe be (*(A)) */
+#define thr_got_alarm(A) 0
#define init_thr_alarm(A)
#define thr_alarm_kill(A)
#define end_thr_alarm()
-#define thr_alarm(A,B) (((A)->crono=1)-1)
-#define thr_got_alarm(A) (A)->crono
-#define thr_end_alarm(A)
#else
#if defined(__WIN__)
@@ -109,4 +107,3 @@ bool thr_got_alarm(thr_alarm_t *alrm);
}
#endif /* __cplusplus */
#endif /* _thr_alarm_h */
-
diff --git a/include/thr_lock.h b/include/thr_lock.h
index 6dd59f80e64..7459849cb04 100644
--- a/include/thr_lock.h
+++ b/include/thr_lock.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* For use with thr_lock:s */
@@ -28,7 +27,7 @@ extern "C" {
struct st_thr_lock;
extern ulong locks_immediate,locks_waited ;
-
+
enum thr_lock_type { TL_IGNORE=-1,
TL_UNLOCK, /* UNLOCK ANY LOCK */
TL_READ, /* Read lock */
diff --git a/include/violite.h b/include/violite.h
index 49df6994d53..0f36e493b57 100644
--- a/include/violite.h
+++ b/include/violite.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
* Vio Lite.
@@ -25,9 +24,6 @@
#include "my_net.h" /* needed because of struct in_addr */
-#ifdef HAVE_VIO
-#include <Vio.h> /* Full VIO interface */
-#else
/* Simple vio interface in C; The functions are implemented in violite.c */
@@ -35,83 +31,202 @@
extern "C" {
#endif /* __cplusplus */
-#ifndef Vio_defined
-#define Vio_defined
-struct st_vio; /* Only C */
-typedef struct st_vio Vio;
-#endif
-
enum enum_vio_type { VIO_CLOSED, VIO_TYPE_TCPIP, VIO_TYPE_SOCKET,
VIO_TYPE_NAMEDPIPE, VIO_TYPE_SSL};
-Vio* vio_new(my_socket sd,
- enum enum_vio_type type,
- my_bool localhost);
+#ifndef __WIN__
+#define HANDLE void *
+#endif
+
+Vio* vio_new(my_socket sd, enum enum_vio_type type, my_bool localhost);
#ifdef __WIN__
-Vio* vio_new_win32pipe(HANDLE hPipe);
+Vio* vio_new_win32pipe(HANDLE hPipe);
+#endif
+void vio_delete(Vio* vio);
+
+#ifdef EMBEDDED_LIBRARY
+void vio_reset(Vio *vio);
+#else
+void vio_reset(Vio* vio, enum enum_vio_type type,
+ my_socket sd, HANDLE hPipe, my_bool localhost);
#endif
-void vio_delete(Vio* vio);
/*
* vio_read and vio_write should have the same semantics
* as read(2) and write(2).
*/
-int vio_read( Vio* vio,
- gptr buf, int size);
-int vio_write( Vio* vio,
- const gptr buf,
- int size);
+int vio_read(Vio *vio, gptr buf, int size);
+int vio_write(Vio *vio, const gptr buf, int size);
/*
* Whenever the socket is set to blocking mode or not.
*/
-int vio_blocking( Vio* vio,
- my_bool onoff);
-my_bool vio_is_blocking( Vio* vio);
+int vio_blocking(Vio *vio, my_bool onoff);
+my_bool vio_is_blocking(Vio *vio);
/*
* setsockopt TCP_NODELAY at IPPROTO_TCP level, when possible.
*/
- int vio_fastsend( Vio* vio);
+int vio_fastsend(Vio *vio);
/*
* setsockopt SO_KEEPALIVE at SOL_SOCKET level, when possible.
*/
-int vio_keepalive( Vio* vio,
- my_bool onoff);
+int vio_keepalive(Vio *vio, my_bool onoff);
/*
* Whenever we should retry the last read/write operation.
*/
-my_bool vio_should_retry( Vio* vio);
+my_bool vio_should_retry(Vio *vio);
/*
* When the workday is over...
*/
-int vio_close( Vio* vio);
+int vio_close(Vio* vio);
/*
* Short text description of the socket for those, who are curious..
*/
-const char* vio_description( Vio* vio);
+const char* vio_description(Vio *vio);
/* Return the type of the connection */
- enum enum_vio_type vio_type(Vio* vio);
+enum enum_vio_type vio_type(Vio* vio);
/* Return last error number */
-int vio_errno(Vio *vio);
+int vio_errno(Vio*vio);
/* Get socket number */
-my_socket vio_fd(Vio *vio);
+my_socket vio_fd(Vio*vio);
/*
* Remote peer's address and name in text form.
*/
-my_bool vio_peer_addr(Vio * vio, char *buf);
+my_bool vio_peer_addr(Vio* vio, char *buf);
/* Remotes in_addr */
void vio_in_addr(Vio *vio, struct in_addr *in);
- /* Return 1 if there is data to be read */
my_bool vio_poll_read(Vio *vio,uint timeout);
#ifdef __cplusplus
}
#endif
+
+#if defined(HAVE_VIO) && !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)
+#define vio_write(vio, buf, size) (vio)->write(vio, buf, size)
+#define vio_blocking(vio, set_blocking_mode) (vio)->vioblocking(vio, set_blocking_mode)
+#define vio_is_blocking(vio) (vio)->is_blocking(vio)
+#define vio_fastsend(vio) (vio)->fastsend(vio)
+#define vio_keepalive(vio, set_keep_alive) (vio)->viokeepalive(vio, set_keep_alive)
+#define vio_should_retry(vio) (vio)->should_retry(vio)
+#define vio_close(vio) ((vio)->vioclose)(vio)
+#define vio_peer_addr(vio, buf) (vio)->peer_addr(vio, buf)
+#define vio_in_addr(vio, in) (vio)->in_addr(vio, in)
+#endif /* defined(HAVE_VIO) && !defined(DONT_MAP_VIO) */
+
+#ifdef HAVE_OPENSSL
+#define HEADER_DES_LOCL_H dummy_something
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include "my_net.h" /* needed because of struct in_addr */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+void vio_ssl_delete(Vio* vio);
+
+int vio_ssl_read(Vio* vio,gptr buf, int size);
+int vio_ssl_write(Vio* vio,const gptr buf,int size);
+int vio_ssl_blocking(Vio* vio,my_bool onoff);
+my_bool vio_ssl_is_blocking(Vio* vio);
+
+/* setsockopt TCP_NODELAY at IPPROTO_TCP level, when possible. */
+ int vio_ssl_fastsend(Vio* vio);
+/* setsockopt SO_KEEPALIVE at SOL_SOCKET level, when possible. */
+int vio_ssl_keepalive(Vio* vio, my_bool onoff);
+/* Whenever we should retry the last read/write operation. */
+my_bool vio_ssl_should_retry(Vio* vio);
+/* When the workday is over... */
+int vio_ssl_close(Vio* vio);
+/* Return last error number */
+int vio_ssl_errno(Vio *vio);
+my_bool vio_ssl_peer_addr(Vio* vio, char *buf);
+void vio_ssl_in_addr(Vio *vio, struct in_addr *in);
+
+/* Single copy for server */
+struct st_VioSSLAcceptorFd
+{
+ SSL_CTX* ssl_context_;
+ SSL_METHOD* ssl_method_;
+ struct st_VioSSLAcceptorFd* session_id_context_;
+ enum {
+ state_connect = 1,
+ state_accept = 2
+ };
+
+ /* function pointers which are only once for SSL server
+ Vio*(*sslaccept)(struct st_VioSSLAcceptorFd*,Vio*); */
+};
+
+/* One copy for client */
+struct st_VioSSLConnectorFd
+{
+ SSL_CTX* ssl_context_;
+ SSL_METHOD* ssl_method_;
+ /* function pointers which are only once for SSL client */
+};
+void sslaccept(struct st_VioSSLAcceptorFd*, Vio*, long timeout);
+void sslconnect(struct st_VioSSLConnectorFd*, Vio*, long timeout);
+
+struct st_VioSSLConnectorFd
+*new_VioSSLConnectorFd(const char* key_file, const char* cert_file,
+ const char* ca_file, const char* ca_path,
+ const char* cipher);
+struct st_VioSSLAcceptorFd
+*new_VioSSLAcceptorFd(const char* key_file, const char* cert_file,
+ const char* ca_file,const char* ca_path,
+ const char* cipher);
+Vio* new_VioSSL(struct st_VioSSLAcceptorFd* fd, Vio* sd,int state);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* HAVE_OPENSSL */
+
+/* This enumerator is used in parser - should be always visible */
+enum SSL_type {SSL_TYPE_NONE, SSL_TYPE_ANY, SSL_TYPE_X509, SSL_TYPE_SPECIFIED};
+
+#ifndef EMBEDDED_LIBRARY
+/* This structure is for every connection on both sides */
+struct st_vio
+{
+ my_socket sd; /* my_socket - real or imaginary */
+ HANDLE hPipe;
+ my_bool localhost; /* Are we from localhost? */
+ int fcntl_mode; /* Buffered fcntl(sd,F_GETFL) */
+ struct sockaddr_in local; /* Local internet address */
+ struct sockaddr_in remote; /* Remote internet address */
+ enum enum_vio_type type; /* Type of connection */
+ char desc[30]; /* String description */
+#ifdef HAVE_VIO
+ /* function pointers. They are similar for socket/SSL/whatever */
+ void (*viodelete)(Vio*);
+ int (*vioerrno)(Vio*);
+ int (*read)(Vio*, gptr, int);
+ int (*write)(Vio*, gptr, int);
+ int (*vioblocking)(Vio*, my_bool);
+ my_bool (*is_blocking)(Vio*);
+ int (*viokeepalive)(Vio*, my_bool);
+ int (*fastsend)(Vio*);
+ my_bool (*peer_addr)(Vio*, gptr);
+ void (*in_addr)(Vio*, struct in_addr*);
+ my_bool (*should_retry)(Vio*);
+ int (*vioclose)(Vio*);
+
+#ifdef HAVE_OPENSSL
+ SSL* ssl_;
+ my_bool open_;
+#endif /* HAVE_OPENSSL */
#endif /* HAVE_VIO */
+};
+#endif /* EMBEDDED_LIBRARY */
#endif /* vio_violite_h_ */
diff --git a/innobase/btr/btr0btr.c b/innobase/btr/btr0btr.c
index b9253562fe6..0263996a429 100644
--- a/innobase/btr/btr0btr.c
+++ b/innobase/btr/btr0btr.c
@@ -851,7 +851,7 @@ btr_parse_page_reorganize(
/*======================*/
/* out: end of log record or NULL */
byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
+ byte* end_ptr __attribute__((unused)), /* in: buffer end */
page_t* page, /* in: page or NULL */
mtr_t* mtr) /* in: mtr or NULL */
{
@@ -1452,7 +1452,7 @@ btr_page_split_and_insert(
page_t* insert_page;
page_cur_t* page_cursor;
rec_t* first_rec;
- byte* buf;
+ byte* buf = 0; /* remove warning */
rec_t* move_limit;
ibool insert_will_fit;
ulint n_iterations = 0;
@@ -1630,7 +1630,7 @@ static
void
btr_level_list_remove(
/*==================*/
- dict_tree_t* tree, /* in: index tree */
+ dict_tree_t* tree __attribute__((unused)), /* in: index tree */
page_t* page, /* in: page to remove */
mtr_t* mtr) /* in: mtr */
{
@@ -2352,7 +2352,7 @@ btr_validate_level(
{
ulint space;
page_t* page;
- page_t* right_page;
+ page_t* right_page = 0; /* remove warning */
page_t* father_page;
page_t* right_father_page;
rec_t* node_ptr;
diff --git a/innobase/btr/btr0cur.c b/innobase/btr/btr0cur.c
index ddcf5e8faf2..10813bbe1f7 100644
--- a/innobase/btr/btr0cur.c
+++ b/innobase/btr/btr0cur.c
@@ -103,7 +103,7 @@ static
void
btr_cur_latch_leaves(
/*=================*/
- dict_tree_t* tree, /* in: index tree */
+ dict_tree_t* tree __attribute__((unused)), /* in: index tree */
page_t* page, /* in: leaf page where the search
converged */
ulint space, /* in: space id */
@@ -228,7 +228,7 @@ btr_cur_search_to_nth_level(
ulint insert_planned;
ulint buf_mode;
ulint estimate;
- ulint root_height;
+ ulint root_height = 0; /* remove warning */
#ifdef BTR_CUR_ADAPT
btr_search_t* info;
#endif
@@ -497,7 +497,7 @@ btr_cur_open_at_index_side(
ulint page_no;
ulint space;
ulint height;
- ulint root_height;
+ ulint root_height = 0; /* remove warning */
rec_t* node_ptr;
ulint estimate;
@@ -2988,8 +2988,9 @@ btr_store_big_rec_extern_fields(
rec_t* rec, /* in: record */
big_rec_t* big_rec_vec, /* in: vector containing fields
to be stored externally */
- mtr_t* local_mtr) /* in: mtr containing the latch to
- rec and to the tree */
+ mtr_t* local_mtr __attribute__((unused))) /* in: mtr
+ containing the latch to rec and to the
+ tree */
{
byte* data;
ulint local_len;
@@ -3150,9 +3151,9 @@ btr_free_externally_stored_field(
ibool do_not_free_inherited,/* in: TRUE if called in a
rollback and we do not want to free
inherited fields */
- mtr_t* local_mtr) /* in: mtr containing the latch to
- data an an X-latch to the index
- tree */
+ mtr_t* local_mtr __attribute__((unused))) /* in: mtr
+ containing the latch to data an an
+ X-latch to the index tree */
{
page_t* page;
page_t* rec_page;
diff --git a/innobase/btr/btr0sea.c b/innobase/btr/btr0sea.c
index aac86f45ec9..8a54d9de9c0 100644
--- a/innobase/btr/btr0sea.c
+++ b/innobase/btr/btr0sea.c
@@ -1245,7 +1245,7 @@ btr_search_update_hash_on_insert(
dulint tree_id;
ulint fold;
ulint ins_fold;
- ulint next_fold;
+ ulint next_fold = 0; /* remove warning (??? bug ???) */
ulint n_fields;
ulint n_bytes;
ulint side;
diff --git a/innobase/buf/buf0buf.c b/innobase/buf/buf0buf.c
index f1a2d915d46..e840e9f143d 100644
--- a/innobase/buf/buf0buf.c
+++ b/innobase/buf/buf0buf.c
@@ -285,7 +285,7 @@ buf_page_print(
ut_print_timestamp(stderr);
fprintf(stderr,
- " InnoDB: Page dump in ascii and hex (%lu bytes):\n%s",
+ " InnoDB: Page dump in ascii and hex (%u bytes):\n%s",
UNIV_PAGE_SIZE, buf);
fprintf(stderr, "InnoDB: End of page dump\n");
diff --git a/innobase/buf/buf0lru.c b/innobase/buf/buf0lru.c
index a2996eefca9..5ab045212c2 100644
--- a/innobase/buf/buf0lru.c
+++ b/innobase/buf/buf0lru.c
@@ -103,9 +103,10 @@ ibool
buf_LRU_search_and_free_block(
/*==========================*/
/* out: TRUE if freed */
- ulint n_iterations) /* in: how many times this has been called
- repeatedly without result: a high value
- means that we should search farther */
+ ulint n_iterations __attribute__((unused))) /* in: how many times
+ this has been called repeatedly without
+ result: a high value means that we should
+ search farther */
{
buf_block_t* block;
ibool freed;
@@ -199,7 +200,7 @@ buf_LRU_get_free_block(void)
buf_block_t* block = NULL;
ibool freed;
ulint n_iterations = 0;
- ibool mon_value_was;
+ ibool mon_value_was = 0; /* remove bug */
ibool started_monitor = FALSE;
loop:
mutex_enter(&(buf_pool->mutex));
diff --git a/innobase/data/data0data.c b/innobase/data/data0data.c
index 2254dcb6ae6..03abcb9b6e0 100644
--- a/innobase/data/data0data.c
+++ b/innobase/data/data0data.c
@@ -572,7 +572,7 @@ from entry with dtuple_convert_big_rec. */
void
dtuple_convert_back_big_rec(
/*========================*/
- dict_index_t* index, /* in: index */
+ dict_index_t* index __attribute__((unused)), /* in: index */
dtuple_t* entry, /* in: entry whose data was put to vector */
big_rec_t* vector) /* in, own: big rec vector; it is
freed in this function */
diff --git a/innobase/dict/dict0boot.c b/innobase/dict/dict0boot.c
index 206fbe32940..374c567c3ca 100644
--- a/innobase/dict/dict0boot.c
+++ b/innobase/dict/dict0boot.c
@@ -254,27 +254,29 @@ 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);
-
- dict_mem_table_add_col(table, "NAME", DATA_BINARY, 0, 0, 0);
- dict_mem_table_add_col(table, "ID", DATA_BINARY, 0, 0, 0);
- dict_mem_table_add_col(table, "N_COLS", DATA_INT, 0, 4, 0);
- dict_mem_table_add_col(table, "TYPE", DATA_INT, 0, 4, 0);
- dict_mem_table_add_col(table, "MIX_ID", DATA_BINARY, 0, 0, 0);
- dict_mem_table_add_col(table, "MIX_LEN", DATA_INT, 0, 4, 0);
- dict_mem_table_add_col(table, "CLUSTER_NAME", DATA_BINARY, 0, 0, 0);
- dict_mem_table_add_col(table, "SPACE", DATA_INT, 0, 4, 0);
+ table = dict_mem_table_create((char *) "SYS_TABLES", DICT_HDR_SPACE,8);
+
+ dict_mem_table_add_col(table, (char *) "NAME", DATA_BINARY, 0, 0, 0);
+ dict_mem_table_add_col(table, (char *) "ID", DATA_BINARY, 0, 0, 0);
+ dict_mem_table_add_col(table, (char *) "N_COLS", DATA_INT, 0, 4, 0);
+ dict_mem_table_add_col(table, (char *) "TYPE", DATA_INT, 0, 4, 0);
+ dict_mem_table_add_col(table, (char *) "MIX_ID", DATA_BINARY, 0, 0, 0);
+ dict_mem_table_add_col(table, (char *) "MIX_LEN", DATA_INT, 0, 4, 0);
+ dict_mem_table_add_col(table, (char *) "CLUSTER_NAME", DATA_BINARY,
+ 0, 0, 0);
+ dict_mem_table_add_col(table, (char *) "SPACE", DATA_INT, 0, 4, 0);
table->id = DICT_TABLES_ID;
dict_table_add_to_cache(table);
dict_sys->sys_tables = table;
- index = dict_mem_index_create("SYS_TABLES", "CLUST_IND",
- DICT_HDR_SPACE,
- DICT_UNIQUE | DICT_CLUSTERED, 1);
+ index = dict_mem_index_create((char *) "SYS_TABLES", (char *)
+ "CLUST_IND",
+ DICT_HDR_SPACE,
+ DICT_UNIQUE | DICT_CLUSTERED, 1);
- dict_mem_index_add_field(index, "NAME", 0);
+ dict_mem_index_add_field(index, (char *) "NAME", 0);
index->page_no = mtr_read_ulint(dict_hdr + DICT_HDR_TABLES,
MLOG_4BYTES, &mtr);
@@ -282,51 +284,52 @@ dict_boot(void)
ut_a(dict_index_add_to_cache(table, index));
/*-------------------------*/
- index = dict_mem_index_create("SYS_TABLES", "ID_IND", DICT_HDR_SPACE,
- DICT_UNIQUE, 1);
- dict_mem_index_add_field(index, "ID", 0);
+ index = dict_mem_index_create((char *) "SYS_TABLES",
+ (char *) "ID_IND", DICT_HDR_SPACE,
+ DICT_UNIQUE, 1);
+ dict_mem_index_add_field(index, (char *) "ID", 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));
/*-------------------------*/
- table = dict_mem_table_create("SYS_COLUMNS", DICT_HDR_SPACE, 7);
-
- 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);
- dict_mem_table_add_col(table, "NAME", DATA_BINARY, 0, 0, 0);
- dict_mem_table_add_col(table, "MTYPE", DATA_INT, 0, 4, 0);
- dict_mem_table_add_col(table, "PRTYPE", DATA_INT, 0, 4, 0);
- dict_mem_table_add_col(table, "LEN", DATA_INT, 0, 4, 0);
- dict_mem_table_add_col(table, "PREC", DATA_INT, 0, 4, 0);
+ table = dict_mem_table_create((char *) "SYS_COLUMNS",DICT_HDR_SPACE,7);
+
+ dict_mem_table_add_col(table, (char *) "TABLE_ID", DATA_BINARY,0,0,0);
+ dict_mem_table_add_col(table, (char *) "POS", DATA_INT, 0, 4, 0);
+ dict_mem_table_add_col(table, (char *) "NAME", DATA_BINARY, 0, 0, 0);
+ dict_mem_table_add_col(table, (char *) "MTYPE", DATA_INT, 0, 4, 0);
+ dict_mem_table_add_col(table, (char *) "PRTYPE", DATA_INT, 0, 4, 0);
+ dict_mem_table_add_col(table, (char *) "LEN", DATA_INT, 0, 4, 0);
+ dict_mem_table_add_col(table, (char *) "PREC", DATA_INT, 0, 4, 0);
table->id = DICT_COLUMNS_ID;
dict_table_add_to_cache(table);
dict_sys->sys_columns = table;
- index = dict_mem_index_create("SYS_COLUMNS", "CLUST_IND",
- DICT_HDR_SPACE,
- DICT_UNIQUE | DICT_CLUSTERED, 2);
+ index = dict_mem_index_create((char *) "SYS_COLUMNS",
+ (char *) "CLUST_IND", DICT_HDR_SPACE,
+ DICT_UNIQUE | DICT_CLUSTERED, 2);
- dict_mem_index_add_field(index, "TABLE_ID", 0);
- dict_mem_index_add_field(index, "POS", 0);
+ dict_mem_index_add_field(index, (char *) "TABLE_ID", 0);
+ dict_mem_index_add_field(index, (char *) "POS", 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));
/*-------------------------*/
- table = dict_mem_table_create("SYS_INDEXES", DICT_HDR_SPACE, 7);
+ table = dict_mem_table_create((char *) "SYS_INDEXES",DICT_HDR_SPACE,7);
- 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);
- dict_mem_table_add_col(table, "NAME", DATA_BINARY, 0, 0, 0);
- dict_mem_table_add_col(table, "N_FIELDS", DATA_INT, 0, 4, 0);
- dict_mem_table_add_col(table, "TYPE", DATA_INT, 0, 4, 0);
- dict_mem_table_add_col(table, "SPACE", DATA_INT, 0, 4, 0);
- dict_mem_table_add_col(table, "PAGE_NO", DATA_INT, 0, 4, 0);
+ dict_mem_table_add_col(table, (char *) "TABLE_ID", DATA_BINARY, 0,0,0);
+ dict_mem_table_add_col(table, (char *) "ID", DATA_BINARY, 0, 0, 0);
+ dict_mem_table_add_col(table, (char *) "NAME", DATA_BINARY, 0, 0, 0);
+ dict_mem_table_add_col(table, (char *) "N_FIELDS", DATA_INT, 0, 4, 0);
+ dict_mem_table_add_col(table, (char *) "TYPE", DATA_INT, 0, 4, 0);
+ dict_mem_table_add_col(table, (char *) "SPACE", DATA_INT, 0, 4, 0);
+ dict_mem_table_add_col(table, (char *) "PAGE_NO", DATA_INT, 0, 4, 0);
/* The '+ 2' below comes from the 2 system fields */
ut_ad(DICT_SYS_INDEXES_PAGE_NO_FIELD == 6 + 2);
@@ -336,34 +339,34 @@ dict_boot(void)
dict_table_add_to_cache(table);
dict_sys->sys_indexes = table;
- index = dict_mem_index_create("SYS_INDEXES", "CLUST_IND",
- DICT_HDR_SPACE,
- DICT_UNIQUE | DICT_CLUSTERED, 2);
+ index = dict_mem_index_create((char *) "SYS_INDEXES",
+ (char *) "CLUST_IND", DICT_HDR_SPACE,
+ DICT_UNIQUE | DICT_CLUSTERED, 2);
- dict_mem_index_add_field(index, "TABLE_ID", 0);
- dict_mem_index_add_field(index, "ID", 0);
+ dict_mem_index_add_field(index, (char *) "TABLE_ID", 0);
+ dict_mem_index_add_field(index, (char *) "ID", 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));
/*-------------------------*/
- table = dict_mem_table_create("SYS_FIELDS", DICT_HDR_SPACE, 3);
+ table = dict_mem_table_create((char *) "SYS_FIELDS", DICT_HDR_SPACE,3);
- 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);
- dict_mem_table_add_col(table, "COL_NAME", DATA_BINARY, 0, 0, 0);
+ dict_mem_table_add_col(table, (char *) "INDEX_ID", DATA_BINARY, 0,0,0);
+ dict_mem_table_add_col(table, (char *) "POS", DATA_INT, 0, 4, 0);
+ dict_mem_table_add_col(table, (char *) "COL_NAME", DATA_BINARY, 0,0,0);
table->id = DICT_FIELDS_ID;
dict_table_add_to_cache(table);
dict_sys->sys_fields = table;
- index = dict_mem_index_create("SYS_FIELDS", "CLUST_IND",
- DICT_HDR_SPACE,
- DICT_UNIQUE | DICT_CLUSTERED, 2);
+ index = dict_mem_index_create((char *) "SYS_FIELDS",
+ (char *) "CLUST_IND", DICT_HDR_SPACE,
+ DICT_UNIQUE | DICT_CLUSTERED, 2);
- dict_mem_index_add_field(index, "INDEX_ID", 0);
- dict_mem_index_add_field(index, "POS", 0);
+ dict_mem_index_add_field(index, (char *) "INDEX_ID", 0);
+ dict_mem_index_add_field(index, (char *) "POS", 0);
index->page_no = mtr_read_ulint(dict_hdr + DICT_HDR_FIELDS,
MLOG_4BYTES, &mtr);
diff --git a/innobase/dict/dict0crea.c b/innobase/dict/dict0crea.c
index f15d36251e4..69b1e7c61fd 100644
--- a/innobase/dict/dict0crea.c
+++ b/innobase/dict/dict0crea.c
@@ -1044,8 +1044,8 @@ dict_create_or_check_foreign_constraint_tables(void)
mutex_enter(&(dict_sys->mutex));
- table1 = dict_table_get_low("SYS_FOREIGN");
- table2 = dict_table_get_low("SYS_FOREIGN_COLS");
+ table1 = dict_table_get_low((char *) "SYS_FOREIGN");
+ table2 = dict_table_get_low((char *) "SYS_FOREIGN_COLS");
if (table1 && table2
&& UT_LIST_GET_LEN(table1->indexes) == 3
@@ -1061,18 +1061,18 @@ dict_create_or_check_foreign_constraint_tables(void)
trx = trx_allocate_for_mysql();
- trx->op_info = "creating foreign key sys tables";
+ trx->op_info = (char *) "creating foreign key sys tables";
if (table1) {
fprintf(stderr,
"InnoDB: dropping incompletely created SYS_FOREIGN table\n");
- row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE);
+ row_drop_table_for_mysql((char *) "SYS_FOREIGN", trx, TRUE);
}
if (table2) {
fprintf(stderr,
"InnoDB: dropping incompletely created SYS_FOREIGN_COLS table\n");
- row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE);
+ row_drop_table_for_mysql((char *) "SYS_FOREIGN_COLS",trx,TRUE);
}
fprintf(stderr,
@@ -1082,7 +1082,7 @@ dict_create_or_check_foreign_constraint_tables(void)
there are 2 secondary indexes on SYS_FOREIGN, and they
are defined just like below */
- str =
+ str = (char *)
"PROCEDURE CREATE_FOREIGN_SYS_TABLES_PROC () IS\n"
"BEGIN\n"
"CREATE TABLE\n"
@@ -1121,15 +1121,15 @@ dict_create_or_check_foreign_constraint_tables(void)
fprintf(stderr,
"InnoDB: dropping incompletely created SYS_FOREIGN tables\n");
- row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE);
- row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE);
+ row_drop_table_for_mysql((char *) "SYS_FOREIGN", trx, TRUE);
+ row_drop_table_for_mysql((char *) "SYS_FOREIGN_COLS",trx,TRUE);
error = DB_MUST_GET_MORE_FILE_SPACE;
}
que_graph_free(graph);
- trx->op_info = "";
+ trx->op_info = (char *) "";
trx_free_for_mysql(trx);
@@ -1165,7 +1165,7 @@ dict_create_add_foreigns_to_dictionary(
ut_ad(mutex_own(&(dict_sys->mutex)));
- if (NULL == dict_table_get_low("SYS_FOREIGN")) {
+ if (NULL == dict_table_get_low((char *) "SYS_FOREIGN")) {
fprintf(stderr,
"InnoDB: table SYS_FOREIGN not found from internal data dictionary\n");
return(DB_ERROR);
diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c
index d52483074cd..43589eb03fe 100644
--- a/innobase/dict/dict0dict.c
+++ b/innobase/dict/dict0dict.c
@@ -571,15 +571,19 @@ dict_table_add_to_cache(
The clustered index will not always physically contain all
system columns. */
- dict_mem_table_add_col(table, "DB_ROW_ID", DATA_SYS, DATA_ROW_ID, 0, 0);
+ dict_mem_table_add_col(table, (char *) "DB_ROW_ID", DATA_SYS,
+ DATA_ROW_ID, 0, 0);
ut_ad(DATA_ROW_ID == 0);
- dict_mem_table_add_col(table, "DB_TRX_ID", DATA_SYS, DATA_TRX_ID, 0, 0);
+ dict_mem_table_add_col(table, (char *) "DB_TRX_ID", DATA_SYS,
+ DATA_TRX_ID, 0, 0);
ut_ad(DATA_TRX_ID == 1);
- dict_mem_table_add_col(table, "DB_ROLL_PTR", DATA_SYS, DATA_ROLL_PTR,
+ dict_mem_table_add_col(table, (char *) "DB_ROLL_PTR", DATA_SYS,
+ DATA_ROLL_PTR,
0, 0);
ut_ad(DATA_ROLL_PTR == 2);
- dict_mem_table_add_col(table, "DB_MIX_ID", DATA_SYS, DATA_MIX_ID, 0, 0);
+ dict_mem_table_add_col(table, (char *) "DB_MIX_ID", DATA_SYS,
+ DATA_MIX_ID, 0, 0);
ut_ad(DATA_MIX_ID == 3);
ut_ad(DATA_N_SYS_COLS == 4); /* This assert reminds that if a new
system column is added to the program,
@@ -2055,7 +2059,7 @@ dict_create_foreign_constraints(
}
loop:
- ptr = dict_scan_to(ptr, "FOREIGN");
+ ptr = dict_scan_to(ptr, (char *) "FOREIGN");
if (*ptr == '\0') {
@@ -2067,19 +2071,19 @@ loop:
return(error);
}
- ptr = dict_accept(ptr, "FOREIGN", &success);
+ ptr = dict_accept(ptr, (char *) "FOREIGN", &success);
if (!isspace(*ptr)) {
goto loop;
}
- ptr = dict_accept(ptr, "KEY", &success);
+ ptr = dict_accept(ptr, (char *) "KEY", &success);
if (!success) {
goto loop;
}
- ptr = dict_accept(ptr, "(", &success);
+ ptr = dict_accept(ptr, (char *) "(", &success);
if (!success) {
goto loop;
@@ -2097,13 +2101,13 @@ col_loop1:
i++;
- ptr = dict_accept(ptr, ",", &success);
+ ptr = dict_accept(ptr, (char *) ",", &success);
if (success) {
goto col_loop1;
}
- ptr = dict_accept(ptr, ")", &success);
+ ptr = dict_accept(ptr, (char *) ")", &success);
if (!success) {
return(DB_CANNOT_ADD_CONSTRAINT);
@@ -2118,7 +2122,7 @@ col_loop1:
return(DB_CANNOT_ADD_CONSTRAINT);
}
- ptr = dict_accept(ptr, "REFERENCES", &success);
+ ptr = dict_accept(ptr, (char *) "REFERENCES", &success);
if (!success || !isspace(*ptr)) {
return(DB_CANNOT_ADD_CONSTRAINT);
@@ -2149,7 +2153,7 @@ col_loop1:
return(DB_CANNOT_ADD_CONSTRAINT);
}
- ptr = dict_accept(ptr, "(", &success);
+ ptr = dict_accept(ptr, (char *) "(", &success);
if (!success) {
dict_foreign_free(foreign);
@@ -2169,13 +2173,13 @@ col_loop2:
return(DB_CANNOT_ADD_CONSTRAINT);
}
- ptr = dict_accept(ptr, ",", &success);
+ ptr = dict_accept(ptr, (char *) ",", &success);
if (success) {
goto col_loop2;
}
- ptr = dict_accept(ptr, ")", &success);
+ ptr = dict_accept(ptr, (char *) ")", &success);
if (!success || foreign->n_fields != i) {
dict_foreign_free(foreign);
@@ -2710,7 +2714,8 @@ void
dict_update_statistics_low(
/*=======================*/
dict_table_t* table, /* in: table */
- ibool has_dict_mutex) /* in: TRUE if the caller has the
+ ibool has_dict_mutex __attribute__((unused)))
+ /* in: TRUE if the caller has the
dictionary mutex */
{
dict_index_t* index;
diff --git a/innobase/dict/dict0load.c b/innobase/dict/dict0load.c
index 29c98db4a53..53ba09616f7 100644
--- a/innobase/dict/dict0load.c
+++ b/innobase/dict/dict0load.c
@@ -75,7 +75,7 @@ dict_get_first_table_name_in_db(
mtr_start(&mtr);
- sys_tables = dict_table_get_low("SYS_TABLES");
+ sys_tables = dict_table_get_low((char *) "SYS_TABLES");
sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
tuple = dtuple_create(heap, 1);
@@ -154,7 +154,7 @@ dict_print(void)
mtr_start(&mtr);
- sys_tables = dict_table_get_low("SYS_TABLES");
+ sys_tables = dict_table_get_low((char *) "SYS_TABLES");
sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur,
@@ -241,7 +241,7 @@ dict_load_table(
mtr_start(&mtr);
- sys_tables = dict_table_get_low("SYS_TABLES");
+ sys_tables = dict_table_get_low((char *) "SYS_TABLES");
sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
tuple = dtuple_create(heap, 1);
@@ -277,7 +277,7 @@ dict_load_table(
return(NULL);
}
- ut_a(0 == ut_strcmp("SPACE",
+ ut_a(0 == ut_strcmp((char *) "SPACE",
dict_field_get_col(
dict_index_get_nth_field(
dict_table_get_first_index(sys_tables), 9))->name));
@@ -285,7 +285,7 @@ dict_load_table(
field = rec_get_nth_field(rec, 9, &len);
space = mach_read_from_4(field);
- ut_a(0 == ut_strcmp("N_COLS",
+ ut_a(0 == ut_strcmp((char *) "N_COLS",
dict_field_get_col(
dict_index_get_nth_field(
dict_table_get_first_index(sys_tables), 4))->name));
@@ -295,7 +295,7 @@ dict_load_table(
table = dict_mem_table_create(name, space, n_cols);
- ut_a(0 == ut_strcmp("ID",
+ ut_a(0 == ut_strcmp((char *) "ID",
dict_field_get_col(
dict_index_get_nth_field(
dict_table_get_first_index(sys_tables), 3))->name));
@@ -498,7 +498,7 @@ dict_load_columns(
mtr_start(&mtr);
- sys_columns = dict_table_get_low("SYS_COLUMNS");
+ sys_columns = dict_table_get_low((char *) "SYS_COLUMNS");
sys_index = UT_LIST_GET_FIRST(sys_columns->indexes);
tuple = dtuple_create(heap, 1);
@@ -528,7 +528,7 @@ dict_load_columns(
ut_ad(len == 4);
ut_a(i == mach_read_from_4(field));
- ut_a(0 == ut_strcmp("NAME",
+ ut_a(0 == ut_strcmp((char *) "NAME",
dict_field_get_col(
dict_index_get_nth_field(
dict_table_get_first_index(sys_columns), 4))->name));
@@ -550,7 +550,7 @@ dict_load_columns(
field = rec_get_nth_field(rec, 7, &len);
col_len = mach_read_from_4(field);
- ut_a(0 == ut_strcmp("PREC",
+ ut_a(0 == ut_strcmp((char *) "PREC",
dict_field_get_col(
dict_index_get_nth_field(
dict_table_get_first_index(sys_columns), 8))->name));
@@ -608,7 +608,7 @@ dict_load_indexes(
mtr_start(&mtr);
- sys_indexes = dict_table_get_low("SYS_INDEXES");
+ sys_indexes = dict_table_get_low((char *) "SYS_INDEXES");
sys_index = UT_LIST_GET_FIRST(sys_indexes->indexes);
tuple = dtuple_create(heap, 1);
@@ -643,7 +643,7 @@ dict_load_indexes(
ut_ad(len == 8);
id = mach_read_from_8(field);
- ut_a(0 == ut_strcmp("NAME",
+ ut_a(0 == ut_strcmp((char *) "NAME",
dict_field_get_col(
dict_index_get_nth_field(
dict_table_get_first_index(sys_indexes), 4))->name));
@@ -663,7 +663,7 @@ dict_load_indexes(
field = rec_get_nth_field(rec, 7, &len);
space = mach_read_from_4(field);
- ut_a(0 == ut_strcmp("PAGE_NO",
+ ut_a(0 == ut_strcmp((char *) "PAGE_NO",
dict_field_get_col(
dict_index_get_nth_field(
dict_table_get_first_index(sys_indexes), 8))->name));
@@ -674,8 +674,8 @@ dict_load_indexes(
if (is_sys_table
&& ((type & DICT_CLUSTERED)
|| ((table == dict_sys->sys_tables)
- && (name_len == ut_strlen("ID_IND"))
- && (0 == ut_memcmp(name_buf, "ID_IND",
+ && (name_len == ut_strlen((char *) "ID_IND"))
+ && (0 == ut_memcmp(name_buf, (char *) "ID_IND",
name_len))))) {
/* The index was created in memory already in
@@ -736,7 +736,7 @@ dict_load_fields(
mtr_start(&mtr);
- sys_fields = dict_table_get_low("SYS_FIELDS");
+ sys_fields = dict_table_get_low((char *) "SYS_FIELDS");
sys_index = UT_LIST_GET_FIRST(sys_fields->indexes);
tuple = dtuple_create(heap, 1);
@@ -765,7 +765,7 @@ dict_load_fields(
ut_ad(len == 4);
ut_a(i == mach_read_from_4(field));
- ut_a(0 == ut_strcmp("COL_NAME",
+ ut_a(0 == ut_strcmp((char *) "COL_NAME",
dict_field_get_col(
dict_index_get_nth_field(
dict_table_get_first_index(sys_fields), 4))->name));
@@ -816,7 +816,7 @@ dict_load_foreign_cols(
foreign->n_fields * sizeof(void*));
mtr_start(&mtr);
- sys_foreign_cols = dict_table_get_low("SYS_FOREIGN_COLS");
+ sys_foreign_cols = dict_table_get_low((char *) "SYS_FOREIGN_COLS");
sys_index = UT_LIST_GET_FIRST(sys_foreign_cols->indexes);
tuple = dtuple_create(foreign->heap, 1);
@@ -894,7 +894,7 @@ dict_load_foreign(
mtr_start(&mtr);
- sys_foreign = dict_table_get_low("SYS_FOREIGN");
+ sys_foreign = dict_table_get_low((char *) "SYS_FOREIGN");
sys_index = UT_LIST_GET_FIRST(sys_foreign->indexes);
tuple = dtuple_create(heap2, 1);
@@ -1008,7 +1008,7 @@ dict_load_foreigns(
ut_ad(mutex_own(&(dict_sys->mutex)));
- sys_foreign = dict_table_get_low("SYS_FOREIGN");
+ sys_foreign = dict_table_get_low((char *) "SYS_FOREIGN");
if (sys_foreign == NULL) {
/* No foreign keys defined yet in this database */
diff --git a/innobase/eval/eval0eval.c b/innobase/eval/eval0eval.c
index 110387d8373..157d4e4f98d 100644
--- a/innobase/eval/eval0eval.c
+++ b/innobase/eval/eval0eval.c
@@ -164,8 +164,8 @@ eval_logical(
que_node_t* arg1;
que_node_t* arg2;
ibool val1;
- ibool val2;
- ibool val;
+ ibool val2 = 0; /* remove warning */
+ ibool val = 0; /* remove warning */
int func;
ut_ad(que_node_get_type(logical_node) == QUE_NODE_FUNC);
@@ -205,7 +205,7 @@ eval_arith(
que_node_t* arg1;
que_node_t* arg2;
lint val1;
- lint val2;
+ lint val2 = 0; /* remove warning */
lint val;
int func;
@@ -283,7 +283,7 @@ eval_predefined_2(
{
que_node_t* arg;
que_node_t* arg1;
- que_node_t* arg2;
+ que_node_t* arg2 = 0; /* remove warning (??? bug ???) */
lint int_val;
byte* data;
ulint len1;
diff --git a/innobase/fil/fil0fil.c b/innobase/fil/fil0fil.c
index ca508785497..35f3792f041 100644
--- a/innobase/fil/fil0fil.c
+++ b/innobase/fil/fil0fil.c
@@ -1287,7 +1287,7 @@ fil_aio_wait(
ut_ad(fil_validate());
if (os_aio_use_native_aio) {
- srv_io_thread_op_info[segment] = "native aio handle";
+ srv_io_thread_op_info[segment] = (char *) "native aio handle";
#ifdef WIN_ASYNC_IO
ret = os_aio_windows_handle(segment, 0, &fil_node, &message,
&type);
@@ -1298,7 +1298,7 @@ fil_aio_wait(
ut_a(0);
#endif
} else {
- srv_io_thread_op_info[segment] = "simulated aio handle";
+ srv_io_thread_op_info[segment] =(char *)"simulated aio handle";
ret = os_aio_simulated_handle(segment, (void**) &fil_node,
&message, &type);
@@ -1306,7 +1306,7 @@ fil_aio_wait(
ut_a(ret);
- srv_io_thread_op_info[segment] = "complete io for fil node";
+ srv_io_thread_op_info[segment] = (char *) "complete io for fil node";
mutex_enter(&(system->mutex));
@@ -1319,10 +1319,11 @@ fil_aio_wait(
/* Do the i/o handling */
if (buf_pool_is_block(message)) {
- srv_io_thread_op_info[segment] = "complete io for buf page";
+ srv_io_thread_op_info[segment] =
+ (char *) "complete io for buf page";
buf_page_io_complete(message);
} else {
- srv_io_thread_op_info[segment] = "complete io for log";
+ srv_io_thread_op_info[segment] =(char *) "complete io for log";
log_io_complete(message);
}
}
diff --git a/innobase/fsp/fsp0fsp.c b/innobase/fsp/fsp0fsp.c
index e823fe62259..08608731f2e 100644
--- a/innobase/fsp/fsp0fsp.c
+++ b/innobase/fsp/fsp0fsp.c
@@ -803,7 +803,7 @@ fsp_parse_init_file_page(
/*=====================*/
/* out: end of log record or NULL */
byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
+ byte* end_ptr __attribute__((unused)), /* in: buffer end */
page_t* page) /* in: page or NULL */
{
ut_ad(ptr && end_ptr);
@@ -1398,7 +1398,7 @@ fsp_seg_inode_page_get_nth_inode(
/* out: segment inode */
page_t* page, /* in: segment inode page */
ulint i, /* in: inode index on page */
- mtr_t* mtr) /* in: mini-transaction handle */
+ mtr_t* mtr __attribute__((unused))) /* in: mini-transaction handle */
{
ut_ad(i < FSP_SEG_INODES_PER_PAGE);
ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
@@ -1640,7 +1640,7 @@ fseg_get_nth_frag_page_no(
/* out: page number, FIL_NULL if not in use */
fseg_inode_t* inode, /* in: segment inode */
ulint n, /* in: slot index */
- mtr_t* mtr) /* in: mtr handle */
+ mtr_t* mtr __attribute__((unused))) /* in: mtr handle */
{
ut_ad(inode && mtr);
ut_ad(n < FSEG_FRAG_ARR_N_SLOTS);
@@ -1778,7 +1778,7 @@ fseg_create_general(
fsp_header_t* space_header;
fseg_inode_t* inode;
dulint seg_id;
- fseg_header_t* header;
+ fseg_header_t* header = 0; /* remove warning */
rw_lock_t* latch;
ibool success;
page_t* ret = NULL;
diff --git a/innobase/ibuf/ibuf0ibuf.c b/innobase/ibuf/ibuf0ibuf.c
index bd1f0e6e1d8..a6355ce7ca5 100644
--- a/innobase/ibuf/ibuf0ibuf.c
+++ b/innobase/ibuf/ibuf0ibuf.c
@@ -292,6 +292,7 @@ ibuf_count_get(
/**********************************************************************
Sets the ibuf count for a given page. */
+#ifdef UNIV_IBUF_DEBUG
static
void
ibuf_count_set(
@@ -306,6 +307,7 @@ ibuf_count_set(
*(ibuf_counts[space] + page_no) = val;
}
+#endif
/**********************************************************************
Creates the insert buffer data structure at a database startup and
@@ -472,19 +474,18 @@ ibuf_data_init_for_space(
table = dict_mem_table_create(buf, space, 2);
- 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);
+ dict_mem_table_add_col(table,(char *) "PAGE_NO", DATA_BINARY, 0, 0, 0);
+ dict_mem_table_add_col(table,(char *) "TYPES", DATA_BINARY, 0, 0, 0);
table->id = ut_dulint_add(DICT_IBUF_ID_MIN, space);
dict_table_add_to_cache(table);
- index = dict_mem_index_create(buf, "CLUST_IND", space,
- DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF,
- 2);
+ index = dict_mem_index_create(buf, (char *) "CLUST_IND", space,
+ DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF,2);
- dict_mem_index_add_field(index, "PAGE_NO", 0);
- dict_mem_index_add_field(index, "TYPES", 0);
+ dict_mem_index_add_field(index, (char *) "PAGE_NO", 0);
+ dict_mem_index_add_field(index, (char *) "TYPES", 0);
index->page_no = FSP_IBUF_TREE_ROOT_PAGE_NO;
@@ -538,7 +539,7 @@ ibuf_parse_bitmap_init(
/*===================*/
/* out: end of log record or NULL */
byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
+ byte* end_ptr __attribute__((unused)), /* in: buffer end */
page_t* page, /* in: page or NULL */
mtr_t* mtr) /* in: mtr or NULL */
{
@@ -561,7 +562,8 @@ ibuf_bitmap_page_get_bits(
page_t* page, /* in: bitmap page */
ulint page_no,/* in: page whose bits to get */
ulint bit, /* in: IBUF_BITMAP_FREE, IBUF_BITMAP_BUFFERED, ... */
- mtr_t* mtr) /* in: mtr containing an x-latch to the bitmap page */
+ mtr_t* mtr __attribute__((unused))) /* in: mtr containing an x-latch
+ to the bitmap page */
{
ulint byte_offset;
ulint bit_offset;
diff --git a/innobase/include/Makefile.am b/innobase/include/Makefile.am
index fd5cc8b1a80..8664f6dfc17 100644
--- a/innobase/include/Makefile.am
+++ b/innobase/include/Makefile.am
@@ -55,5 +55,7 @@ noinst_HEADERS = btr0btr.h btr0btr.ic btr0cur.h btr0cur.ic \
ut0dbg.h ut0lst.h ut0mem.h ut0mem.ic ut0rnd.h ut0rnd.ic \
ut0sort.h ut0ut.h ut0ut.ic
+EXTRA_DIST = Makefile.i
+
# Don't update the files from bitkeeper
%::SCCS/s.%
diff --git a/innobase/include/Makefile.i b/innobase/include/Makefile.i
index 8c7e9910f26..985ec525950 100644
--- a/innobase/include/Makefile.i
+++ b/innobase/include/Makefile.i
@@ -2,7 +2,7 @@
libsdir = ../libs
-INCLUDES = -I../../include -I../include
+INCLUDES = -I$(srcdir)/../include -I$(srcdir)/../../include -I../../include
# Don't update the files from bitkeeper
%::SCCS/s.%
diff --git a/innobase/include/btr0btr.ic b/innobase/include/btr0btr.ic
index 5c1c89e9840..09006828cc9 100644
--- a/innobase/include/btr0btr.ic
+++ b/innobase/include/btr0btr.ic
@@ -89,7 +89,7 @@ btr_page_get_level(
/*===============*/
/* out: level, leaf level == 0 */
page_t* page, /* in: index page */
- mtr_t* mtr) /* in: mini-transaction handle */
+ mtr_t* mtr __attribute__((unused))) /* in: mini-transaction handle */
{
ut_ad(page && mtr);
@@ -121,7 +121,7 @@ btr_page_get_next(
/*==============*/
/* out: next page number */
page_t* page, /* in: index page */
- mtr_t* mtr) /* in: mini-transaction handle */
+ mtr_t* mtr __attribute__((unused))) /* in: mini-transaction handle */
{
ut_ad(page && mtr);
ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
@@ -155,7 +155,7 @@ btr_page_get_prev(
/*==============*/
/* out: prev page number */
page_t* page, /* in: index page */
- mtr_t* mtr) /* in: mini-transaction handle */
+ mtr_t* mtr __attribute__((unused))) /* in: mini-transaction handle */
{
ut_ad(page && mtr);
diff --git a/innobase/include/buf0buf.ic b/innobase/include/buf0buf.ic
index 8f5443ad150..52bee0eb282 100644
--- a/innobase/include/buf0buf.ic
+++ b/innobase/include/buf0buf.ic
@@ -631,9 +631,10 @@ UNIV_INLINE
void
buf_page_dbg_add_level(
/*===================*/
- buf_frame_t* frame, /* in: buffer page where we have acquired
- a latch */
- ulint level) /* in: latching order level */
+ buf_frame_t* frame __attribute__((unused)), /* in: buffer page
+ where we have acquired latch */
+ ulint level __attribute__((unused))) /* in: latching order
+ level */
{
#ifdef UNIV_SYNC_DEBUG
sync_thread_add_level(&(buf_block_align(frame)->lock), level);
diff --git a/innobase/include/dict0dict.ic b/innobase/include/dict0dict.ic
index 821465f96a8..71ea67117a7 100644
--- a/innobase/include/dict0dict.ic
+++ b/innobase/include/dict0dict.ic
@@ -106,7 +106,7 @@ dict_table_get_n_sys_cols(
/*======================*/
/* out: number of system (e.g.,
ROW_ID) columns of a table */
- dict_table_t* table) /* in: table */
+ dict_table_t* table __attribute__((unused))) /* in: table */
{
ut_ad(table);
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
diff --git a/innobase/include/dyn0dyn.h b/innobase/include/dyn0dyn.h
index 0952a8b4647..332622b6d4c 100644
--- a/innobase/include/dyn0dyn.h
+++ b/innobase/include/dyn0dyn.h
@@ -18,7 +18,12 @@ typedef dyn_block_t dyn_array_t;
/* Initial 'payload' size in bytes in a dynamic array block */
-#define DYN_ARRAY_DATA_SIZE 512
+#ifndef _AIX
+#define DYN_ARRAY_DATA_SIZE 1024
+#else
+/* AIX has a quite small stack / thread */
+#define DYN_ARRAY_DATA_SIZE 128
+#endif
/*************************************************************************
Initializes a dynamic array. */
diff --git a/innobase/include/ha0ha.ic b/innobase/include/ha0ha.ic
index 7b4c624c653..9d344bca04c 100644
--- a/innobase/include/ha0ha.ic
+++ b/innobase/include/ha0ha.ic
@@ -59,7 +59,7 @@ ha_node_t*
ha_chain_get_next(
/*==============*/
/* out: next node, NULL if none */
- hash_table_t* table, /* in: hash table */
+ hash_table_t* table __attribute__((unused)), /* in: hash table */
ha_node_t* node) /* in: hash chain node */
{
ut_ad(table);
diff --git a/innobase/include/row0mysql.ic b/innobase/include/row0mysql.ic
index 6096e5771f7..e9d493da8b5 100644
--- a/innobase/include/row0mysql.ic
+++ b/innobase/include/row0mysql.ic
@@ -15,7 +15,8 @@ row_mysql_store_var_len(
/*====================*/
/* out: dest + 2 */
byte* dest, /* in: where to store */
- ulint len) /* in: length, must fit in two bytes */
+ ulint len __attribute__((unused))) /* in: length, must fit in two
+ bytes */
{
ut_ad(len < 256 * 256);
/*
diff --git a/innobase/include/row0vers.ic b/innobase/include/row0vers.ic
index aa7a7aa2299..5ece47c35d1 100644
--- a/innobase/include/row0vers.ic
+++ b/innobase/include/row0vers.ic
@@ -60,7 +60,7 @@ 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, /* in: secondary index */
+ dict_index_t* index __attribute__((unused)),/* in: secondary index */
read_view_t* view) /* in: read view */
{
page_t* page;
diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h
index 903dd9afc90..6777a24e7db 100644
--- a/innobase/include/srv0srv.h
+++ b/innobase/include/srv0srv.h
@@ -94,6 +94,7 @@ extern ulint srv_n_rows_read;
extern ibool srv_print_innodb_monitor;
extern ibool srv_print_innodb_lock_monitor;
extern ibool srv_print_innodb_tablespace_monitor;
+extern ibool srv_print_verbose_log;
extern ibool srv_print_innodb_table_monitor;
extern ibool srv_lock_timeout_and_monitor_active;
diff --git a/innobase/include/sync0rw.ic b/innobase/include/sync0rw.ic
index af5c4576da6..43e9202360b 100644
--- a/innobase/include/sync0rw.ic
+++ b/innobase/include/sync0rw.ic
@@ -126,7 +126,8 @@ rw_lock_s_lock_low(
/*===============*/
/* out: TRUE if success */
rw_lock_t* lock, /* in: pointer to rw-lock */
- ulint pass, /* in: pass value; != 0, if the lock will be
+ ulint pass __attribute__((unused)),
+ /* in: pass value; != 0, if the lock will be
passed to another thread to unlock */
char* file_name, /* in: file name where lock requested */
ulint line) /* in: line where requested */
diff --git a/innobase/include/univ.i b/innobase/include/univ.i
index a4345babbbe..8870d80f611 100644
--- a/innobase/include/univ.i
+++ b/innobase/include/univ.i
@@ -30,13 +30,14 @@ be defined:
/* Most C compilers other than gcc do not know 'extern inline' */
#if !defined(__GNUC__) && !defined(__WIN__)
+#undef UNIV_MUST_NOT_INLINE
#define UNIV_MUST_NOT_INLINE
#endif
/* Include two header files from MySQL to make the Unix flavor used
in compiling more Posix-compatible. We assume that 'innobase' is a
subdirectory of 'mysql'. */
-#include <global.h>
+#include <my_global.h>
#include <my_pthread.h>
/* Include <sys/stat.h> to get S_I... macros defined for os0file.c */
diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c
index 0b2b85d0337..f2309a5c562 100644
--- a/innobase/lock/lock0lock.c
+++ b/innobase/lock/lock0lock.c
@@ -539,7 +539,8 @@ lock_sec_rec_cons_read_sees(
index record */
rec_t* rec, /* in: user record which should be read or
passed over by a read cursor */
- dict_index_t* index, /* in: non-clustered index */
+ dict_index_t* index __attribute__((unused)),
+ /* in: non-clustered index */
read_view_t* view) /* in: consistent read view */
{
dulint max_trx_id;
@@ -2292,7 +2293,7 @@ list start is moved to another page. */
void
lock_move_rec_list_start(
/*=====================*/
- page_t* new_page, /* in: index page to move to */
+ page_t* new_page __attribute__((unused)),/*in: index page to move to */
page_t* page, /* in: index page */
rec_t* rec, /* in: record on page: this is the
first record NOT copied */
@@ -2736,7 +2737,7 @@ lock_deadlock_recursive(
we return TRUE */
{
lock_t* lock;
- ulint bit_no;
+ ulint bit_no = 0; /* remove warning */
trx_t* lock_trx;
ut_a(trx && start && wait_lock);
diff --git a/innobase/log/log0log.c b/innobase/log/log0log.c
index 2ba035d1eb2..5ec1274d117 100644
--- a/innobase/log/log0log.c
+++ b/innobase/log/log0log.c
@@ -2002,7 +2002,7 @@ log_group_archive(
os_file_t file_handle;
dulint start_lsn;
dulint end_lsn;
- char name[100];
+ char name[1024];
byte* buf;
ulint len;
ibool ret;
@@ -2794,9 +2794,11 @@ logs_empty_and_mark_files_at_shutdown(void)
dulint lsn;
ulint arch_log_no;
- ut_print_timestamp(stderr);
- fprintf(stderr, " InnoDB: Starting shutdown...\n");
-
+ if (srv_print_verbose_log)
+ {
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB: Starting shutdown...\n");
+ }
/* Wait until the master thread and all other operations are idle: our
algorithm only works if the server is idle at shutdown */
@@ -2901,8 +2903,11 @@ loop:
fil_flush_file_spaces(FIL_TABLESPACE);
- ut_print_timestamp(stderr);
- fprintf(stderr, " InnoDB: Shutdown completed\n");
+ if (srv_print_verbose_log)
+ {
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB: Shutdown completed\n");
+ }
}
/**********************************************************
diff --git a/innobase/mem/mem0dbg.c b/innobase/mem/mem0dbg.c
index f8f62dffa8b..f94119b7f38 100644
--- a/innobase/mem/mem0dbg.c
+++ b/innobase/mem/mem0dbg.c
@@ -372,7 +372,8 @@ void
mem_heap_validate_or_print(
/*=======================*/
mem_heap_t* heap, /* in: memory heap */
- byte* top, /* in: calculate and validate only until
+ byte* top __attribute__((unused)),
+ /* in: calculate and validate only until
this top pointer in the heap is reached,
if this pointer is NULL, ignored */
ibool print, /* in: if TRUE, prints the contents
@@ -578,7 +579,8 @@ static
void
mem_print_info_low(
/*===============*/
- ibool print_all) /* in: if TRUE, all heaps are printed,
+ ibool print_all __attribute__((unused)))
+ /* in: if TRUE, all heaps are printed,
else only the heaps allocated after the
previous call of this function */
{
diff --git a/innobase/mtr/mtr0mtr.c b/innobase/mtr/mtr0mtr.c
index f38aa6793b9..6aa1f3509d4 100644
--- a/innobase/mtr/mtr0mtr.c
+++ b/innobase/mtr/mtr0mtr.c
@@ -469,7 +469,8 @@ mtr_read_ulint(
/* out: value read */
byte* ptr, /* in: pointer from where to read */
ulint type, /* in: MLOG_1BYTE, MLOG_2BYTES, MLOG_4BYTES */
- mtr_t* mtr) /* in: mini-transaction handle */
+ mtr_t* mtr __attribute__((unused)))
+ /* in: mini-transaction handle */
{
ut_ad(mtr->state == MTR_ACTIVE);
ut_ad(mtr_memo_contains(mtr, buf_block_align(ptr),
@@ -494,8 +495,9 @@ mtr_read_dulint(
/*===========*/
/* out: value read */
byte* ptr, /* in: pointer from where to read */
- ulint type, /* in: MLOG_8BYTES */
- mtr_t* mtr) /* in: mini-transaction handle */
+ ulint type __attribute__((unused)), /* in: MLOG_8BYTES */
+ mtr_t* mtr __attribute__((unused)))
+ /* in: mini-transaction handle */
{
ut_ad(mtr->state == MTR_ACTIVE);
ut_ad(ptr && mtr);
diff --git a/innobase/odbc/odbc0odbc.c b/innobase/odbc/odbc0odbc.c
index 640a88a2503..0deb17c6714 100644
--- a/innobase/odbc/odbc0odbc.c
+++ b/innobase/odbc/odbc0odbc.c
@@ -421,7 +421,7 @@ SQLError(
}
*pfNativeError = 0;
- ut_memcpy(szSqlState, "S1000", 6);
+ ut_memcpy(szSqlState, (char *) "S1000", 6);
len = (ulint)cbErrorMsgMax - 1;
diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c
index dd51227bbf6..ee4045febde 100644
--- a/innobase/os/os0file.c
+++ b/innobase/os/os0file.c
@@ -643,14 +643,13 @@ os_file_get_size(
return(FALSE);
}
- if (sizeof(off_t) > 4) {
- *size = (ulint)(offs & 0xFFFFFFFF);
- *size_high = (ulint)(offs >> 32);
- } else {
- *size = (ulint) offs;
- *size_high = 0;
- }
-
+#if SIZEOF_OFF_T > 4
+ *size = (ulint)(offs & 0xFFFFFFFF);
+ *size_high = (ulint)(offs >> 32);
+#else
+ *size = (ulint) offs;
+ *size_high = 0;
+#endif
return(TRUE);
#endif
}
@@ -797,18 +796,16 @@ os_file_pread(
/* If off_t is > 4 bytes in size, then we assume we can pass a
64-bit address */
- if (sizeof(off_t) > 4) {
- offs = (off_t)offset + (((off_t)offset_high) << 32);
-
- } else {
- offs = (off_t)offset;
+#if SIZEOF_OFF_T > 4
+ offs = (off_t)offset + (((off_t)offset_high) << 32);
+#else
+ offs = (off_t)offset;
- if (offset_high > 0) {
- fprintf(stderr,
- "InnoDB: Error: file read at offset > 4 GB\n");
- }
+ if (offset_high > 0) {
+ fprintf(stderr,
+ "InnoDB: Error: file read at offset > 4 GB\n");
}
-
+#endif
os_n_file_reads++;
#ifdef HAVE_PREAD
diff --git a/innobase/os/os0thread.c b/innobase/os/os0thread.c
index 11bff73608a..49d4c8518fb 100644
--- a/innobase/os/os0thread.c
+++ b/innobase/os/os0thread.c
@@ -58,7 +58,8 @@ os_thread_create(
#endif
void* arg, /* in: argument to start
function */
- os_thread_id_t* thread_id) /* out: id of created
+ os_thread_id_t* thread_id __attribute__((unused)))
+ /* out: id of created
thread */
{
#ifdef __WIN__
@@ -204,7 +205,8 @@ ulint
os_thread_get_priority(
/*===================*/
/* out: priority */
- os_thread_t handle) /* in: OS handle to the thread */
+ os_thread_t handle __attribute__((unused)))
+ /* in: OS handle to the thread */
{
#ifdef __WIN__
int os_pri;
diff --git a/innobase/page/page0cur.c b/innobase/page/page0cur.c
index 0b233b4dd72..85beffbcc94 100644
--- a/innobase/page/page0cur.c
+++ b/innobase/page/page0cur.c
@@ -510,14 +510,14 @@ page_cur_parse_insert_rec(
mtr_t* mtr) /* in: mtr or NULL */
{
ulint extra_info_yes;
- ulint offset;
+ ulint offset = 0; /* remove warning */
ulint origin_offset;
ulint end_seg_len;
ulint mismatch_index;
rec_t* cursor_rec;
byte buf1[1024];
byte* buf;
- ulint info_bits;
+ ulint info_bits = 0; /* remove warning */
page_cur_t cursor;
if (!is_short) {
@@ -835,9 +835,9 @@ page_copy_rec_list_end_to_created_page(
rec_t* rec, /* in: first record to copy */
mtr_t* mtr) /* in: mtr */
{
- page_dir_slot_t* slot;
+ page_dir_slot_t* slot = 0; /* remove warning */
byte* heap_top;
- rec_t* insert_rec;
+ rec_t* insert_rec = 0; /* remove warning */
rec_t* prev_rec;
ulint count;
ulint n_recs;
@@ -882,6 +882,7 @@ page_copy_rec_list_end_to_created_page(
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);
diff --git a/innobase/page/page0page.c b/innobase/page/page0page.c
index a75a7279fb5..bf8af45a00a 100644
--- a/innobase/page/page0page.c
+++ b/innobase/page/page0page.c
@@ -210,7 +210,7 @@ page_parse_create(
/*==============*/
/* out: end of log record or NULL */
byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
+ byte* end_ptr __attribute__((unused)), /* in: buffer end */
page_t* page, /* in: page or NULL */
mtr_t* mtr) /* in: mtr or NULL */
{
@@ -283,7 +283,7 @@ page_create(
tuple = dtuple_create(heap, 1);
field = dtuple_get_nth_field(tuple, 0);
- dfield_set_data(field, "infimum", strlen("infimum") + 1);
+ dfield_set_data(field,(char *) "infimum", strlen("infimum") + 1);
dtype_set(dfield_get_type(field), DATA_VARCHAR, DATA_ENGLISH, 20, 0);
/* Set the corresponding physical record to its place in the page
@@ -305,7 +305,7 @@ page_create(
tuple = dtuple_create(heap, 1);
field = dtuple_get_nth_field(tuple, 0);
- dfield_set_data(field, "supremum", strlen("supremum") + 1);
+ dfield_set_data(field, (char *) "supremum", strlen("supremum") + 1);
dtype_set(dfield_get_type(field), DATA_VARCHAR, DATA_ENGLISH, 20, 0);
supremum_rec = rec_convert_dtuple_to_rec(heap_top, tuple);
diff --git a/innobase/pars/pars0opt.c b/innobase/pars/pars0opt.c
index 6f4957f96ee..35d39caad00 100644
--- a/innobase/pars/pars0opt.c
+++ b/innobase/pars/pars0opt.c
@@ -528,7 +528,7 @@ opt_search_plan_for_table(
ulint goodness;
ulint last_op;
ulint best_goodness;
- ulint best_last_op;
+ ulint best_last_op = 0; /* remove warning */
ulint mix_id_pos;
que_node_t* index_plan[128];
que_node_t* best_index_plan[128];
@@ -546,6 +546,7 @@ opt_search_plan_for_table(
best_index = index; /* Eliminate compiler warning */
best_goodness = 0;
+ /* should be do ... until ? comment by Jani */
while (index) {
goodness = opt_calc_index_goodness(index, sel_node, i,
index_plan, &last_op);
diff --git a/innobase/pars/pars0pars.c b/innobase/pars/pars0pars.c
index 8ffbca579b8..664f498ef3e 100644
--- a/innobase/pars/pars0pars.c
+++ b/innobase/pars/pars0pars.c
@@ -1942,7 +1942,7 @@ Called by yyparse on error. */
void
yyerror(
/*====*/
- char* s) /* in: error message string */
+ char* s __attribute__((unused))) /* in: error message string */
{
ut_ad(s);
diff --git a/innobase/que/que0que.c b/innobase/que/que0que.c
index 97843311d21..1cee316f32c 100644
--- a/innobase/que/que0que.c
+++ b/innobase/que/que0que.c
@@ -103,7 +103,7 @@ que_thr_add_update_info(
mach_write_to_8(thr->msg_buf + SESS_SRV_MSG_N_DELETES,
graph->n_deletes);
}
-#endif
+#endif
/***************************************************************************
Adds a query graph to the session's list of graphs. */
@@ -395,7 +395,7 @@ graph so that the graph can communicate an error message to the client.) */
void
que_fork_error_handle(
/*==================*/
- trx_t* trx, /* in: trx */
+ trx_t* trx __attribute__((unused)), /* in: trx */
que_t* fork) /* in: query graph which was run before signal
handling started, NULL not allowed */
{
@@ -1164,47 +1164,47 @@ que_node_print_info(
addr = (ulint)node;
if (type == QUE_NODE_SELECT) {
- str = "SELECT";
+ str = (char *) "SELECT";
} else if (type == QUE_NODE_INSERT) {
- str = "INSERT";
+ str = (char *) "INSERT";
} else if (type == QUE_NODE_UPDATE) {
- str = "UPDATE";
+ str = (char *) "UPDATE";
} else if (type == QUE_NODE_WHILE) {
- str = "WHILE";
+ str = (char *) "WHILE";
} else if (type == QUE_NODE_ASSIGNMENT) {
- str = "ASSIGNMENT";
+ str = (char *) "ASSIGNMENT";
} else if (type == QUE_NODE_IF) {
- str = "IF";
+ str = (char *) "IF";
} else if (type == QUE_NODE_FETCH) {
- str = "FETCH";
+ str = (char *) "FETCH";
} else if (type == QUE_NODE_OPEN) {
- str = "OPEN";
+ str = (char *) "OPEN";
} else if (type == QUE_NODE_PROC) {
- str = "STORED PROCEDURE";
+ str = (char *) "STORED PROCEDURE";
} else if (type == QUE_NODE_FUNC) {
- str = "FUNCTION";
+ str = (char *) "FUNCTION";
} else if (type == QUE_NODE_LOCK) {
- str = "LOCK";
+ str = (char *) "LOCK";
} else if (type == QUE_NODE_THR) {
- str = "QUERY THREAD";
+ str = (char *) "QUERY THREAD";
} else if (type == QUE_NODE_COMMIT) {
- str = "COMMIT";
+ str = (char *) "COMMIT";
} else if (type == QUE_NODE_UNDO) {
- str = "UNDO ROW";
+ str = (char *) "UNDO ROW";
} else if (type == QUE_NODE_PURGE) {
- str = "PURGE ROW";
+ str = (char *) "PURGE ROW";
} else if (type == QUE_NODE_ROLLBACK) {
- str = "ROLLBACK";
+ str = (char *) "ROLLBACK";
} else if (type == QUE_NODE_CREATE_TABLE) {
- str = "CREATE TABLE";
+ str = (char *) "CREATE TABLE";
} else if (type == QUE_NODE_CREATE_INDEX) {
- str = "CREATE INDEX";
+ str = (char *) "CREATE INDEX";
} else if (type == QUE_NODE_FOR) {
- str = "FOR LOOP";
+ str = (char *) "FOR LOOP";
} else if (type == QUE_NODE_RETURN) {
- str = "RETURN";
+ str = (char *) "RETURN";
} else {
- str = "UNKNOWN NODE TYPE";
+ str = (char *) "UNKNOWN NODE TYPE";
}
printf("Node type %lu: %s, address %lx\n", type, str, addr);
diff --git a/innobase/rem/rem0cmp.c b/innobase/rem/rem0cmp.c
index e4779b5f26b..c27af604d04 100644
--- a/innobase/rem/rem0cmp.c
+++ b/innobase/rem/rem0cmp.c
@@ -80,7 +80,7 @@ ulint
cmp_collate(
/*========*/
/* out: collation order position */
- dtype_t* type, /* in: type */
+ dtype_t* type __attribute__((unused)) , /* in: type */
ulint code) /* in: code of a character stored in database
record */
{
diff --git a/innobase/rem/rem0rec.c b/innobase/rem/rem0rec.c
index 3889f62afa2..a151389798d 100644
--- a/innobase/rem/rem0rec.c
+++ b/innobase/rem/rem0rec.c
@@ -528,9 +528,9 @@ rec_print(
ut_ad(rec);
if (rec_get_1byte_offs_flag(rec)) {
- offs = "TRUE";
+ offs = (char *) "TRUE";
} else {
- offs = "FALSE";
+ offs = (char *) "FALSE";
}
n = rec_get_n_fields(rec);
diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c
index 04df66c3bbd..eb07291e709 100644
--- a/innobase/row/row0ins.c
+++ b/innobase/row/row0ins.c
@@ -399,7 +399,7 @@ row_ins_check_foreign_constraint(
dictionary cache if they exist at all */
dict_table_t* table, /* in: if check_ref is TRUE, then the foreign
table, else the referenced table */
- dict_index_t* index, /* in: index in table */
+ dict_index_t* index __attribute__((unused)),/* in: index in table */
dtuple_t* entry, /* in: index entry for index */
que_thr_t* thr) /* in: query thread */
{
@@ -869,7 +869,7 @@ row_ins_index_entry_low(
que_thr_t* thr) /* in: query thread */
{
btr_cur_t cursor;
- ulint modify;
+ ulint modify = 0; /* remove warning */
rec_t* insert_rec;
rec_t* rec;
ulint err;
diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c
index 2aca698eebd..78b32a5642b 100644
--- a/innobase/row/row0mysql.c
+++ b/innobase/row/row0mysql.c
@@ -564,7 +564,7 @@ row_lock_table_autoinc_for_mysql(
ut_ad(trx);
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
- trx->op_info = "setting auto-inc lock";
+ trx->op_info = (char *) "setting auto-inc lock";
if (node == NULL) {
row_get_prebuilt_insert_row(prebuilt);
@@ -600,14 +600,14 @@ run_again:
goto run_again;
}
- trx->op_info = "";
+ trx->op_info = (char *) "";
return(err);
}
que_thr_stop_for_mysql_no_error(thr, trx);
- trx->op_info = "";
+ trx->op_info = (char *) "";
return((int) err);
}
@@ -655,7 +655,7 @@ row_insert_for_mysql(
return(DB_ERROR);
}
- trx->op_info = "inserting";
+ trx->op_info = (char *) "inserting";
trx_start_if_not_started(trx);
@@ -696,7 +696,7 @@ run_again:
goto run_again;
}
- trx->op_info = "";
+ trx->op_info = (char *) "";
return(err);
}
@@ -713,7 +713,7 @@ run_again:
}
row_update_statistics_if_needed(prebuilt);
- trx->op_info = "";
+ trx->op_info = (char *) "";
return((int) err);
}
@@ -851,7 +851,7 @@ row_update_for_mysql(
return(DB_ERROR);
}
- trx->op_info = "updating or deleting";
+ trx->op_info = (char *) "updating or deleting";
trx_start_if_not_started(trx);
@@ -896,7 +896,7 @@ run_again:
if (err == DB_RECORD_NOT_FOUND) {
trx->error_state = DB_SUCCESS;
- trx->op_info = "";
+ trx->op_info = (char *) "";
return((int) err);
}
@@ -907,7 +907,7 @@ run_again:
goto run_again;
}
- trx->op_info = "";
+ trx->op_info = (char *) "";
return(err);
}
@@ -926,7 +926,7 @@ run_again:
row_update_statistics_if_needed(prebuilt);
- trx->op_info = "";
+ trx->op_info = (char *) "";
return((int) err);
}
@@ -1060,7 +1060,7 @@ row_create_table_for_mysql(
return(DB_ERROR);
}
- trx->op_info = "creating table";
+ trx->op_info = (char *) "creating table";
if (0 == ut_strcmp(table->name, "mysql/host")
|| 0 == ut_strcmp(table->name, "mysql/user")
@@ -1098,11 +1098,11 @@ row_create_table_for_mysql(
namelen = ut_strlen(table->name);
- keywordlen = ut_strlen("innodb_monitor");
+ keywordlen = ut_strlen((char *) "innodb_monitor");
if (namelen >= keywordlen
&& 0 == ut_memcmp(table->name + namelen - keywordlen,
- "innodb_monitor", keywordlen)) {
+ (char *) "innodb_monitor", keywordlen)) {
/* Table name ends to characters innodb_monitor:
start monitor prints */
@@ -1115,32 +1115,34 @@ row_create_table_for_mysql(
os_event_set(srv_lock_timeout_thread_event);
}
- keywordlen = ut_strlen("innodb_lock_monitor");
+ keywordlen = ut_strlen((char *) "innodb_lock_monitor");
if (namelen >= keywordlen
&& 0 == ut_memcmp(table->name + namelen - keywordlen,
- "innodb_lock_monitor", keywordlen)) {
+ (char *) "innodb_lock_monitor", keywordlen)) {
srv_print_innodb_monitor = TRUE;
srv_print_innodb_lock_monitor = TRUE;
os_event_set(srv_lock_timeout_thread_event);
}
- keywordlen = ut_strlen("innodb_tablespace_monitor");
+ keywordlen = ut_strlen((char *) "innodb_tablespace_monitor");
if (namelen >= keywordlen
&& 0 == ut_memcmp(table->name + namelen - keywordlen,
- "innodb_tablespace_monitor", keywordlen)) {
+ (char *) "innodb_tablespace_monitor",
+ keywordlen)) {
srv_print_innodb_tablespace_monitor = TRUE;
os_event_set(srv_lock_timeout_thread_event);
}
- keywordlen = ut_strlen("innodb_table_monitor");
+ keywordlen = ut_strlen((char *) "innodb_table_monitor");
if (namelen >= keywordlen
&& 0 == ut_memcmp(table->name + namelen - keywordlen,
- "innodb_table_monitor", keywordlen)) {
+ (char *) "innodb_table_monitor",
+ keywordlen)) {
srv_print_innodb_table_monitor = TRUE;
os_event_set(srv_lock_timeout_thread_event);
@@ -1223,7 +1225,7 @@ row_create_table_for_mysql(
mutex_exit(&(dict_sys->mutex));
que_graph_free((que_t*) que_node_get_parent(thr));
- trx->op_info = "";
+ trx->op_info = (char *) "";
return((int) err);
}
@@ -1249,7 +1251,7 @@ row_create_index_for_mysql(
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
- trx->op_info = "creating index";
+ trx->op_info = (char *) "creating index";
trx_start_if_not_started(trx);
@@ -1301,7 +1303,7 @@ row_create_index_for_mysql(
que_graph_free((que_t*) que_node_get_parent(thr));
- trx->op_info = "";
+ trx->op_info = (char *) "";
return((int) err);
}
@@ -1334,7 +1336,7 @@ row_table_add_foreign_constraints(
ut_a(sql_string);
- trx->op_info = "adding foreign keys";
+ trx->op_info = (char *) "adding foreign keys";
trx_start_if_not_started(trx);
@@ -1592,16 +1594,16 @@ row_drop_table_for_mysql(
return(DB_ERROR);
}
- trx->op_info = "dropping table";
+ trx->op_info = (char *) "dropping table";
trx_start_if_not_started(trx);
namelen = ut_strlen(name);
- keywordlen = ut_strlen("innodb_monitor");
+ keywordlen = ut_strlen((char *) "innodb_monitor");
if (namelen >= keywordlen
&& 0 == ut_memcmp(name + namelen - keywordlen,
- "innodb_monitor", keywordlen)) {
+ (char *) "innodb_monitor", keywordlen)) {
/* Table name ends to characters innodb_monitor:
stop monitor prints */
@@ -1610,30 +1612,33 @@ row_drop_table_for_mysql(
srv_print_innodb_lock_monitor = FALSE;
}
- keywordlen = ut_strlen("innodb_lock_monitor");
+ keywordlen = ut_strlen((char *) "innodb_lock_monitor");
if (namelen >= keywordlen
&& 0 == ut_memcmp(name + namelen - keywordlen,
- "innodb_lock_monitor", keywordlen)) {
+ (char *) "innodb_lock_monitor",
+ keywordlen)) {
srv_print_innodb_monitor = FALSE;
srv_print_innodb_lock_monitor = FALSE;
}
- keywordlen = ut_strlen("innodb_tablespace_monitor");
+ keywordlen = ut_strlen((char *) "innodb_tablespace_monitor");
if (namelen >= keywordlen
&& 0 == ut_memcmp(name + namelen - keywordlen,
- "innodb_tablespace_monitor", keywordlen)) {
+ (char *) "innodb_tablespace_monitor",
+ keywordlen)) {
srv_print_innodb_tablespace_monitor = FALSE;
}
- keywordlen = ut_strlen("innodb_table_monitor");
+ keywordlen = ut_strlen((char *) "innodb_table_monitor");
if (namelen >= keywordlen
&& 0 == ut_memcmp(name + namelen - keywordlen,
- "innodb_table_monitor", keywordlen)) {
+ (char *) "innodb_table_monitor",
+ keywordlen)) {
srv_print_innodb_table_monitor = FALSE;
}
@@ -1643,7 +1648,7 @@ row_drop_table_for_mysql(
tables in Innobase. Deleting a row from SYS_INDEXES table also
frees the file segments of the B-tree associated with the index. */
- str1 =
+ str1 = (char *)
"PROCEDURE DROP_TABLE_PROC () IS\n"
"table_name CHAR;\n"
"sys_foreign_id CHAR;\n"
@@ -1654,7 +1659,7 @@ row_drop_table_for_mysql(
"BEGIN\n"
"table_name := '";
- str2 =
+ str2 = (char *)
"';\n"
"SELECT ID INTO table_id\n"
"FROM SYS_TABLES\n"
@@ -1803,7 +1808,7 @@ funct_exit:
trx_commit_for_mysql(trx);
- trx->op_info = "";
+ trx->op_info = (char *) "";
srv_wake_master_thread();
@@ -1828,13 +1833,13 @@ row_drop_database_for_mysql(
ut_a(name != NULL);
ut_a(name[strlen(name) - 1] == '/');
- trx->op_info = "dropping database";
+ trx->op_info = (char *) "dropping database";
trx_start_if_not_started(trx);
loop:
mutex_enter(&(dict_sys->mutex));
- while (table_name = dict_get_first_table_name_in_db(name)) {
+ while ((table_name = dict_get_first_table_name_in_db(name))) {
ut_a(memcmp(table_name, name, strlen(name)) == 0);
table = dict_table_get_low(table_name);
@@ -1876,7 +1881,7 @@ loop:
trx_commit_for_mysql(trx);
- trx->op_info = "";
+ trx->op_info = (char *) "";
return(err);
}
@@ -1953,17 +1958,17 @@ row_rename_table_for_mysql(
return(DB_ERROR);
}
- trx->op_info = "renaming table";
+ trx->op_info = (char *) "renaming table";
trx_start_if_not_started(trx);
- str1 =
+ str1 = (char *)
"PROCEDURE RENAME_TABLE_PROC () IS\n"
"new_table_name CHAR;\n"
"old_table_name CHAR;\n"
"BEGIN\n"
"new_table_name :='";
- str2 =
+ str2 = (char *)
"';\nold_table_name := '";
if (row_is_mysql_tmp_table_name(new_name)) {
@@ -1971,13 +1976,13 @@ row_rename_table_for_mysql(
/* We want to preserve the original foreign key
constraint definitions despite the name change */
- str3 =
+ str3 = (char*)
"';\n"
"UPDATE SYS_TABLES SET NAME = new_table_name\n"
"WHERE NAME = old_table_name;\n"
"END;\n";
} else {
- str3 =
+ str3 = (char*)
"';\n"
"UPDATE SYS_TABLES SET NAME = new_table_name\n"
"WHERE NAME = old_table_name;\n"
@@ -2095,7 +2100,7 @@ funct_exit:
trx_commit_for_mysql(trx);
- trx->op_info = "";
+ trx->op_info = (char *) "";
return((int) err);
}
@@ -2240,7 +2245,7 @@ row_check_table_for_mysql(
ulint n_rows_in_table = ULINT_UNDEFINED;
ulint ret = DB_SUCCESS;
- prebuilt->trx->op_info = "checking table";
+ prebuilt->trx->op_info = (char *) "checking table";
index = dict_table_get_first_index(table);
@@ -2273,7 +2278,7 @@ row_check_table_for_mysql(
index = dict_table_get_next_index(index);
}
- prebuilt->trx->op_info = "";
+ prebuilt->trx->op_info = (char *) "";
return(ret);
}
diff --git a/innobase/row/row0purge.c b/innobase/row/row0purge.c
index 390f1b59a4d..1dca017c349 100644
--- a/innobase/row/row0purge.c
+++ b/innobase/row/row0purge.c
@@ -204,7 +204,7 @@ row_purge_remove_sec_if_poss_low(
btr_pcur_t pcur;
btr_cur_t* btr_cur;
ibool success;
- ibool old_has;
+ ibool old_has = 0; /* remove warning */
ibool found;
ulint err;
mtr_t mtr;
diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c
index 9ebd47c25bf..a7462babb73 100644
--- a/innobase/row/row0sel.c
+++ b/innobase/row/row0sel.c
@@ -64,7 +64,8 @@ row_sel_sec_rec_is_for_clust_rec(
rec_t* sec_rec, /* in: secondary index record */
dict_index_t* sec_index, /* in: secondary index */
rec_t* clust_rec, /* in: clustered index record */
- dict_index_t* clust_index) /* in: clustered index */
+ dict_index_t* clust_index __attribute__((unused)))
+ /* in: clustered index */
{
dict_col_t* col;
byte* sec_field;
@@ -2520,7 +2521,7 @@ row_search_for_mysql(
printf("N tables locked %lu\n", trx->mysql_n_tables_locked);
*/
if (direction == 0) {
- trx->op_info = "starting index read";
+ trx->op_info = (char *) "starting index read";
prebuilt->n_rows_fetched = 0;
prebuilt->n_fetch_cached = 0;
@@ -2531,7 +2532,7 @@ row_search_for_mysql(
row_prebuild_sel_graph(prebuilt);
}
} else {
- trx->op_info = "fetching rows";
+ trx->op_info = (char *) "fetching rows";
if (prebuilt->n_rows_fetched == 0) {
prebuilt->fetch_direction = direction;
@@ -2556,7 +2557,7 @@ row_search_for_mysql(
prebuilt->n_rows_fetched++;
srv_n_rows_read++;
- trx->op_info = "";
+ trx->op_info = (char *) "";
return(DB_SUCCESS);
}
@@ -2568,7 +2569,7 @@ row_search_for_mysql(
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 = "";
+ trx->op_info = (char *) "";
return(DB_RECORD_NOT_FOUND);
}
@@ -2600,7 +2601,7 @@ row_search_for_mysql(
/* printf("%s record not found 1\n", index->name); */
- trx->op_info = "";
+ trx->op_info = (char *) "";
return(DB_RECORD_NOT_FOUND);
}
@@ -2663,7 +2664,7 @@ row_search_for_mysql(
trx->has_search_latch = FALSE;
}
- trx->op_info = "";
+ trx->op_info = (char *) "";
return(DB_SUCCESS);
} else if (shortcut == SEL_EXHAUSTED) {
@@ -2682,7 +2683,7 @@ row_search_for_mysql(
trx->has_search_latch = FALSE;
}
- trx->op_info = "";
+ trx->op_info = (char *) "";
return(DB_RECORD_NOT_FOUND);
}
@@ -3056,7 +3057,7 @@ lock_wait_or_error:
/* printf("Using index %s cnt %lu ret value %lu err\n", index->name,
cnt, err); */
- trx->op_info = "";
+ trx->op_info = (char *) "";
return(err);
@@ -3077,7 +3078,7 @@ normal_return:
srv_n_rows_read++;
}
- trx->op_info = "";
+ trx->op_info = (char *) "";
return(ret);
}
diff --git a/innobase/row/row0uins.c b/innobase/row/row0uins.c
index 27d1fbcb9ba..9990f893432 100644
--- a/innobase/row/row0uins.c
+++ b/innobase/row/row0uins.c
@@ -234,7 +234,7 @@ void
row_undo_ins_parse_undo_rec(
/*========================*/
undo_node_t* node, /* in: row undo node */
- que_thr_t* thr) /* in: query thread */
+ que_thr_t* thr __attribute__((unused))) /* in: query thread */
{
dict_index_t* clust_index;
byte* ptr;
diff --git a/innobase/row/row0umod.c b/innobase/row/row0umod.c
index 9e8ba87fc2f..631f238a72d 100644
--- a/innobase/row/row0umod.c
+++ b/innobase/row/row0umod.c
@@ -139,7 +139,7 @@ row_undo_mod_remove_clust_low(
/* out: DB_SUCCESS, DB_FAIL, or error code:
we may run out of file space */
undo_node_t* node, /* in: row undo node */
- que_thr_t* thr, /* in: query thread */
+ que_thr_t* thr __attribute__((unused)), /* in: query thread */
mtr_t* mtr, /* in: mtr */
ulint mode) /* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */
{
diff --git a/innobase/row/row0upd.c b/innobase/row/row0upd.c
index a566e29f2c3..710f650c0bd 100644
--- a/innobase/row/row0upd.c
+++ b/innobase/row/row0upd.c
@@ -388,7 +388,7 @@ row_upd_write_sys_vals_to_log(
dulint roll_ptr,/* in: roll ptr of the undo log record */
byte* log_ptr,/* pointer to a buffer of size > 20 opened
in mlog */
- mtr_t* mtr) /* in: mtr */
+ mtr_t* mtr __attribute__((unused))) /* in: mtr */
{
ut_ad(index->type & DICT_CLUSTERED);
ut_ad(mtr);
diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c
index 8afe1396f1b..a17646a8c0f 100644
--- a/innobase/srv/srv0srv.c
+++ b/innobase/srv/srv0srv.c
@@ -61,7 +61,7 @@ ulint srv_activity_count = 0;
ibool srv_lock_timeout_and_monitor_active = FALSE;
ibool srv_error_monitor_active = FALSE;
-char* srv_main_thread_op_info = "";
+char* srv_main_thread_op_info = (char *) "";
/* Server parameters which are read from the initfile */
@@ -241,6 +241,12 @@ ulint srv_n_rows_read_old = 0;
ibool srv_print_innodb_monitor = FALSE;
ibool srv_print_innodb_lock_monitor = FALSE;
ibool srv_print_innodb_tablespace_monitor = FALSE;
+
+/*
+ Set the following to 0 if you want InnoDB to write messages on
+ stderr on startup/shutdown
+*/
+ibool srv_print_verbose_log = TRUE;
ibool srv_print_innodb_table_monitor = FALSE;
/* The parameters below are obsolete: */
@@ -981,6 +987,7 @@ srv_communication_init(
/*************************************************************************
Implements the recovery utility. */
+#ifdef NOT_USED
static
ulint
srv_recovery_thread(
@@ -1018,7 +1025,7 @@ srv_recovery_thread(
return(0);
}
-
+#endif
/*************************************************************************
Implements the purge utility. */
@@ -1070,6 +1077,7 @@ srv_create_utility_threads(void)
/*************************************************************************
Implements the communication threads. */
+#ifdef NOT_USED
static
ulint
srv_com_thread(
@@ -1117,7 +1125,7 @@ srv_com_thread(
return(0);
}
-
+#endif
/*************************************************************************
Creates the communication threads. */
@@ -1139,6 +1147,7 @@ srv_create_com_threads(void)
/*************************************************************************
Implements the worker threads. */
+#ifdef NOT_USED
static
ulint
srv_worker_thread(
@@ -1181,7 +1190,7 @@ srv_worker_thread(
return(0);
}
-
+#endif
/*************************************************************************
Creates the worker threads. */
@@ -2468,7 +2477,7 @@ srv_master_thread(
os_event_set(srv_sys->operational);
loop:
- srv_main_thread_op_info = "reserving kernel mutex";
+ srv_main_thread_op_info = (char *) "reserving kernel mutex";
n_ios_very_old = log_sys->n_log_ios + buf_pool->n_pages_read
+ buf_pool->n_pages_written;
@@ -2484,7 +2493,7 @@ loop:
for (i = 0; i < 10; i++) {
n_ios_old = log_sys->n_log_ios + buf_pool->n_pages_read
+ buf_pool->n_pages_written;
- srv_main_thread_op_info = "sleeping";
+ srv_main_thread_op_info = (char *) "sleeping";
os_thread_sleep(1000000);
/* ALTER TABLE in MySQL requires on Unix that the table handler
@@ -2506,7 +2515,7 @@ loop:
is issued or the we have specified in my.cnf no flush
at transaction commit */
- srv_main_thread_op_info = "flushing log";
+ srv_main_thread_op_info = (char *) "flushing log";
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP);
/* If there were less than 10 i/os during the
@@ -2519,10 +2528,11 @@ loop:
n_ios = log_sys->n_log_ios + buf_pool->n_pages_read
+ buf_pool->n_pages_written;
if (n_pend_ios < 3 && (n_ios - n_ios_old < 10)) {
- srv_main_thread_op_info = "doing insert buffer merge";
+ srv_main_thread_op_info =
+ (char *) "doing insert buffer merge";
ibuf_contract_for_n_pages(TRUE, 5);
- srv_main_thread_op_info = "flushing log";
+ srv_main_thread_op_info = (char *) "flushing log";
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP);
}
@@ -2559,20 +2569,20 @@ loop:
+ buf_pool->n_pages_written;
if (n_pend_ios < 3 && (n_ios - n_ios_very_old < 200)) {
- srv_main_thread_op_info = "flushing buffer pool pages";
+ srv_main_thread_op_info =(char *) "flushing buffer pool pages";
buf_flush_batch(BUF_FLUSH_LIST, 50, ut_dulint_max);
- srv_main_thread_op_info = "flushing log";
+ srv_main_thread_op_info = (char *) "flushing log";
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP);
}
/* We run a batch of insert buffer merge every 10 seconds,
even if the server were active */
- srv_main_thread_op_info = "doing insert buffer merge";
+ srv_main_thread_op_info = (char *) "doing insert buffer merge";
ibuf_contract_for_n_pages(TRUE, 5);
- srv_main_thread_op_info = "flushing log";
+ srv_main_thread_op_info = (char *) "flushing log";
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP);
/* We run a full purge every 10 seconds, even if the server
@@ -2589,13 +2599,13 @@ loop:
goto background_loop;
}
- srv_main_thread_op_info = "purging";
+ srv_main_thread_op_info = (char *) "purging";
n_pages_purged = trx_purge();
current_time = time(NULL);
if (difftime(current_time, last_flush_time) > 1) {
- srv_main_thread_op_info = "flushing log";
+ srv_main_thread_op_info = (char *) "flushing log";
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP);
last_flush_time = current_time;
@@ -2624,7 +2634,7 @@ background_loop:
log_checkpoint(TRUE, FALSE);
- srv_main_thread_op_info = "reserving kernel mutex";
+ srv_main_thread_op_info = (char *) "reserving kernel mutex";
mutex_enter(&kernel_mutex);
if (srv_activity_count != old_activity_count) {
@@ -2637,11 +2647,11 @@ background_loop:
/* The server has been quiet for a while: start running background
operations */
- srv_main_thread_op_info = "purging";
+ srv_main_thread_op_info = (char *) "purging";
n_pages_purged = trx_purge();
- srv_main_thread_op_info = "reserving kernel mutex";
+ srv_main_thread_op_info = (char *) "reserving kernel mutex";
mutex_enter(&kernel_mutex);
if (srv_activity_count != old_activity_count) {
@@ -2650,10 +2660,10 @@ background_loop:
}
mutex_exit(&kernel_mutex);
- srv_main_thread_op_info = "doing insert buffer merge";
+ srv_main_thread_op_info = (char *) "doing insert buffer merge";
n_bytes_merged = ibuf_contract_for_n_pages(TRUE, 20);
- srv_main_thread_op_info = "reserving kernel mutex";
+ srv_main_thread_op_info = (char *) "reserving kernel mutex";
mutex_enter(&kernel_mutex);
if (srv_activity_count != old_activity_count) {
@@ -2662,10 +2672,10 @@ background_loop:
}
mutex_exit(&kernel_mutex);
- srv_main_thread_op_info = "flushing buffer pool pages";
+ srv_main_thread_op_info = (char *) "flushing buffer pool pages";
n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, 100, ut_dulint_max);
- srv_main_thread_op_info = "reserving kernel mutex";
+ srv_main_thread_op_info = (char *) "reserving kernel mutex";
mutex_enter(&kernel_mutex);
if (srv_activity_count != old_activity_count) {
@@ -2674,14 +2684,15 @@ background_loop:
}
mutex_exit(&kernel_mutex);
- srv_main_thread_op_info = "waiting for buffer pool flush to end";
+ srv_main_thread_op_info =
+ (char *) "waiting for buffer pool flush to end";
buf_flush_wait_batch_end(BUF_FLUSH_LIST);
- srv_main_thread_op_info = "making checkpoint";
+ srv_main_thread_op_info = (char *) "making checkpoint";
log_checkpoint(TRUE, FALSE);
- srv_main_thread_op_info = "reserving kernel mutex";
+ srv_main_thread_op_info = (char *) "reserving kernel mutex";
mutex_enter(&kernel_mutex);
if (srv_activity_count != old_activity_count) {
@@ -2690,7 +2701,8 @@ background_loop:
}
mutex_exit(&kernel_mutex);
- srv_main_thread_op_info = "archiving log (if log archive is on)";
+ srv_main_thread_op_info =
+ (char *) "archiving log (if log archive is on)";
log_archive_do(FALSE, &n_bytes_archived);
@@ -2716,7 +2728,7 @@ background_loop:
master thread to wait for more server activity */
suspend_thread:
- srv_main_thread_op_info = "suspending";
+ srv_main_thread_op_info = (char *) "suspending";
mutex_enter(&kernel_mutex);
@@ -2730,7 +2742,7 @@ suspend_thread:
mutex_exit(&kernel_mutex);
- srv_main_thread_op_info = "waiting for server activity";
+ srv_main_thread_op_info = (char *) "waiting for server activity";
os_event_wait(event);
diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c
index 1fcf8c76a5f..fa4f4bc9419 100644
--- a/innobase/srv/srv0start.c
+++ b/innobase/srv/srv0start.c
@@ -433,7 +433,8 @@ Normalizes a directory path for Windows: converts slashes to backslashes. */
void
srv_normalize_path_for_win(
/*=======================*/
- char* str) /* in/out: null-terminated character string */
+ char* str __attribute__((unused)))
+ /* in/out: null-terminated character string */
{
#ifdef __WIN__
ulint i;
@@ -618,7 +619,8 @@ open_or_create_log_file(
if (k == 0 && i == 0) {
arch_space_id = 2 * k + 1 + SRV_LOG_SPACE_FIRST_ID;
- fil_space_create("arch_log_space", arch_space_id, FIL_LOG);
+ fil_space_create((char *) "arch_log_space", arch_space_id,
+ FIL_LOG);
} else {
arch_space_id = ULINT_UNDEFINED;
}
@@ -837,6 +839,7 @@ open_or_create_data_files(
/*********************************************************************
This thread is used to measure contention of latches. */
+#ifdef NOT_USED
static
ulint
test_measure_cont(
@@ -906,7 +909,7 @@ test_measure_cont(
return(0);
}
-
+#endif
/********************************************************************
Starts InnoDB and creates a new database if database files
are not found and the user wants. Server parameters are
@@ -938,18 +941,21 @@ innobase_start_or_create_for_mysql(void)
srv_is_being_started = TRUE;
srv_startup_is_before_trx_rollback_phase = TRUE;
- if (0 == ut_strcmp(srv_unix_file_flush_method_str, "fdatasync")) {
- srv_unix_file_flush_method = SRV_UNIX_FDATASYNC;
+ if (0 == ut_strcmp(srv_unix_file_flush_method_str,
+ (char *) "fdatasync")) {
+ srv_unix_file_flush_method = SRV_UNIX_FDATASYNC;
- } else if (0 == ut_strcmp(srv_unix_file_flush_method_str, "O_DSYNC")) {
- srv_unix_file_flush_method = SRV_UNIX_O_DSYNC;
+ } else if (0 == ut_strcmp(srv_unix_file_flush_method_str,
+ (char *) "O_DSYNC")) {
+ srv_unix_file_flush_method = SRV_UNIX_O_DSYNC;
} else if (0 == ut_strcmp(srv_unix_file_flush_method_str,
- "littlesync")) {
- srv_unix_file_flush_method = SRV_UNIX_LITTLESYNC;
+ (char *) "littlesync")) {
+ srv_unix_file_flush_method = SRV_UNIX_LITTLESYNC;
- } else if (0 == ut_strcmp(srv_unix_file_flush_method_str, "nosync")) {
- srv_unix_file_flush_method = SRV_UNIX_NOSYNC;
+ } else if (0 == ut_strcmp(srv_unix_file_flush_method_str,
+ (char *) "nosync")) {
+ srv_unix_file_flush_method = SRV_UNIX_NOSYNC;
} else {
fprintf(stderr,
"InnoDB: Unrecognized value %s for innodb_flush_method\n",
@@ -1305,9 +1311,11 @@ innobase_start_or_create_for_mysql(void)
SRV_MAX_N_IO_THREADS);
/* buf_debug_prints = TRUE; */
- ut_print_timestamp(stderr);
- fprintf(stderr, " InnoDB: Started\n");
-
+ if (srv_print_verbose_log)
+ {
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB: Started\n");
+ }
return((int) DB_SUCCESS);
}
diff --git a/innobase/sync/sync0arr.c b/innobase/sync/sync0arr.c
index 7788b104120..4487fa72995 100644
--- a/innobase/sync/sync0arr.c
+++ b/innobase/sync/sync0arr.c
@@ -446,7 +446,7 @@ sync_array_cell_print(
{
mutex_t* mutex;
rw_lock_t* rwlock;
- char* str = NULL;
+ char* str __attribute__((unused)) = NULL;
ulint type;
type = cell->request_type;
diff --git a/innobase/sync/sync0rw.c b/innobase/sync/sync0rw.c
index 1ef2920618f..86ffed7ca95 100644
--- a/innobase/sync/sync0rw.c
+++ b/innobase/sync/sync0rw.c
@@ -115,8 +115,8 @@ rw_lock_create_func(
lock->cfile_name = cfile_name;
lock->cline = cline;
- lock->last_s_file_name = "not yet reserved";
- lock->last_x_file_name = "not yet reserved";
+ lock->last_s_file_name = (char *) "not yet reserved";
+ lock->last_x_file_name = (char *) "not yet reserved";
lock->last_s_line = 0;
lock->last_x_line = 0;
@@ -789,7 +789,7 @@ Prints debug info of an rw-lock. */
void
rw_lock_print(
/*==========*/
- rw_lock_t* lock) /* in: rw-lock */
+ rw_lock_t* lock __attribute__((unused))) /* in: rw-lock */
{
#ifndef UNIV_SYNC_DEBUG
printf(
diff --git a/innobase/sync/sync0sync.c b/innobase/sync/sync0sync.c
index 8b2a39e15eb..3f40aa166ee 100644
--- a/innobase/sync/sync0sync.c
+++ b/innobase/sync/sync0sync.c
@@ -229,7 +229,7 @@ mutex_create_func(
mutex_set_waiters(mutex, 0);
mutex->magic_n = MUTEX_MAGIC_N;
mutex->line = 0;
- mutex->file_name = "not yet reserved";
+ mutex->file_name = (char *) "not yet reserved";
mutex->thread_id = ULINT_UNDEFINED;
mutex->level = SYNC_LEVEL_NONE;
mutex->cfile_name = cfile_name;
diff --git a/innobase/trx/trx0purge.c b/innobase/trx/trx0purge.c
index b73629c9fa4..97362d00b4b 100644
--- a/innobase/trx/trx0purge.c
+++ b/innobase/trx/trx0purge.c
@@ -674,9 +674,9 @@ trx_purge_choose_next_log(void)
trx_rseg_t* rseg;
trx_rseg_t* min_rseg;
dulint min_trx_no;
- ulint space;
- ulint page_no;
- ulint offset;
+ ulint space = 0; /* remove warning (??? bug ???) */
+ ulint page_no = 0; /* remove warning (??? bug ???) */
+ ulint offset = 0; /* remove warning (??? bug ???) */
mtr_t mtr;
ut_ad(mutex_own(&(purge_sys->mutex)));
diff --git a/innobase/trx/trx0rec.c b/innobase/trx/trx0rec.c
index abce470bd1c..05e179e06a5 100644
--- a/innobase/trx/trx0rec.c
+++ b/innobase/trx/trx0rec.c
@@ -989,7 +989,7 @@ trx_undo_parse_erase_page_end(
/*==========================*/
/* out: end of log record or NULL */
byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
+ byte* end_ptr __attribute__((unused)), /* in: buffer end */
page_t* page, /* in: page or NULL */
mtr_t* mtr) /* in: mtr or NULL */
{
@@ -1263,7 +1263,8 @@ trx_undo_prev_version_build(
DB_ERROR if corrupted record */
rec_t* index_rec,/* in: clustered index record in the
index tree */
- mtr_t* index_mtr,/* in: mtr which contains the latch to
+ mtr_t* index_mtr __attribute__((unused)),
+ /* in: mtr which contains the latch to
index_rec page and purge_view */
rec_t* rec, /* in: version of a clustered index record */
dict_index_t* index, /* in: clustered index */
diff --git a/innobase/trx/trx0roll.c b/innobase/trx/trx0roll.c
index 47fffea5e40..97cc2dbff1a 100644
--- a/innobase/trx/trx0roll.c
+++ b/innobase/trx/trx0roll.c
@@ -101,7 +101,7 @@ trx_rollback_for_mysql(
return(DB_SUCCESS);
}
- trx->op_info = "rollback";
+ trx->op_info = (char *) "rollback";
/* Tell Innobase server that there might be work for
utility threads: */
@@ -117,7 +117,7 @@ trx_rollback_for_mysql(
srv_active_wake_master_thread();
- trx->op_info = "";
+ trx->op_info = (char *) "";
return(err);
}
@@ -138,7 +138,7 @@ trx_rollback_last_sql_stat_for_mysql(
return(DB_SUCCESS);
}
- trx->op_info = "rollback of SQL statement";
+ trx->op_info = (char *) "rollback of SQL statement";
/* Tell Innobase server that there might be work for
utility threads: */
@@ -154,7 +154,7 @@ trx_rollback_last_sql_stat_for_mysql(
srv_active_wake_master_thread();
- trx->op_info = "";
+ trx->op_info = (char *) "";
return(err);
}
@@ -180,7 +180,7 @@ trx_rollback_all_without_sess(void)
if (!trx_dummy_sess) {
trx_dummy_sess = sess_open(NULL, (byte*)"Dummy sess",
- ut_strlen("Dummy sess"));
+ ut_strlen((char *) "Dummy sess"));
}
mutex_exit(&kernel_mutex);
diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c
index 6cbf97104b3..607c80edd09 100644
--- a/innobase/trx/trx0trx.c
+++ b/innobase/trx/trx0trx.c
@@ -66,7 +66,7 @@ trx_create(
trx->magic_n = TRX_MAGIC_N;
- trx->op_info = "";
+ trx->op_info = (char *) "";
trx->type = TRX_USER;
trx->conc_state = TRX_NOT_STARTED;
@@ -143,7 +143,7 @@ trx_allocate_for_mysql(void)
if (!trx_dummy_sess) {
trx_dummy_sess = sess_open(NULL, (byte*)"Dummy sess",
- ut_strlen("Dummy sess"));
+ ut_strlen((char *) "Dummy sess"));
}
trx = trx_create(trx_dummy_sess);
@@ -1052,7 +1052,7 @@ trx_sig_send(
ut_a(0);
sess_raise_error_low(trx, 0, 0, NULL, NULL, NULL, NULL,
- "Signal from another session, or a break execution signal");
+ (char *) "Signal from another session, or a break execution signal");
}
/* If there were no other signals ahead in the queue, try to start
@@ -1353,7 +1353,7 @@ trx_commit_for_mysql(
ut_a(trx);
- trx->op_info = "committing";
+ trx->op_info = (char *) "committing";
trx_start_if_not_started(trx);
@@ -1363,7 +1363,7 @@ trx_commit_for_mysql(
mutex_exit(&kernel_mutex);
- trx->op_info = "";
+ trx->op_info = (char *) "";
return(0);
}
diff --git a/innobase/trx/trx0undo.c b/innobase/trx/trx0undo.c
index b5341871228..aae31f3726b 100644
--- a/innobase/trx/trx0undo.c
+++ b/innobase/trx/trx0undo.c
@@ -374,7 +374,7 @@ trx_undo_seg_create(
/*================*/
/* out: segment header page x-latched, NULL
if no space left */
- trx_rseg_t* rseg, /* in: rollback segment */
+ trx_rseg_t* rseg __attribute__((unused)),/* in: rollback segment */
trx_rsegf_t* rseg_hdr,/* in: rollback segment header, page
x-latched */
ulint type, /* in: type of the segment: TRX_UNDO_INSERT or
@@ -657,7 +657,7 @@ trx_undo_parse_discard_latest(
/*==========================*/
/* out: end of log record or NULL */
byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
+ byte* end_ptr __attribute__((unused)), /* in: buffer end */
page_t* page, /* in: page or NULL */
mtr_t* mtr) /* in: mtr or NULL */
{
@@ -844,7 +844,7 @@ static
void
trx_undo_free_page_in_rollback(
/*===========================*/
- trx_t* trx, /* in: transaction */
+ trx_t* trx __attribute__((unused)), /* in: transaction */
trx_undo_t* undo, /* in: undo log memory copy */
ulint page_no,/* in: page number to free: must not be the
header page */
@@ -1567,7 +1567,7 @@ trx_undo_set_state_at_finish(
/*=========================*/
/* out: undo log segment header page,
x-latched */
- trx_t* trx, /* in: transaction */
+ trx_t* trx __attribute__((unused)), /* in: transaction */
trx_undo_t* undo, /* in: undo log memory copy */
mtr_t* mtr) /* in: mtr */
{
diff --git a/isam/_cache.c b/isam/_cache.c
index 53619126660..bca9a699a85 100644
--- a/isam/_cache.c
+++ b/isam/_cache.c
@@ -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 */
@@ -46,11 +46,11 @@ int _nisam_read_cache(IO_CACHE *info, byte *buff, ulong pos, uint length,
buff+=read_length;
}
if ((offset=pos - (ulong) info->pos_in_file) <
- (ulong) (info->rc_end - info->rc_request_pos))
+ (ulong) (info->read_end - info->request_pos))
{
- in_buff_pos=info->rc_request_pos+(uint) offset;
- in_buff_length= min(length,(uint) (info->rc_end-in_buff_pos));
- memcpy(buff,info->rc_request_pos+(uint) offset,(size_t) in_buff_length);
+ 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;
@@ -61,14 +61,14 @@ int _nisam_read_cache(IO_CACHE *info, byte *buff, ulong pos, uint length,
if (flag & READING_NEXT)
{
if (pos != ((info)->pos_in_file +
- (uint) ((info)->rc_end - (info)->rc_request_pos)))
+ (uint) ((info)->read_end - (info)->request_pos)))
{
info->pos_in_file=pos; /* Force start here */
- info->rc_pos=info->rc_end=info->rc_request_pos; /* Everything used */
+ info->read_pos=info->read_end=info->request_pos; /* Everything used */
info->seek_not_done=1;
}
else
- info->rc_pos=info->rc_end; /* All block used */
+ 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 ||
diff --git a/isam/_dbug.c b/isam/_dbug.c
index 18e671793ed..0a52dbbc916 100644
--- a/isam/_dbug.c
+++ b/isam/_dbug.c
@@ -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 */
diff --git a/isam/_dynrec.c b/isam/_dynrec.c
index 2a908f5b42c..d17d34e6778 100644
--- a/isam/_dynrec.c
+++ b/isam/_dynrec.c
@@ -432,7 +432,7 @@ uint _nisam_rec_pack(N_INFO *info, register byte *to, register const byte *from)
blob++;
from+=sizeof(char*); /* Skipp blob-pointer */
}
- else if (type == FIELD_SKIPP_ZERO)
+ else if (type == FIELD_SKIP_ZERO)
{
if (memcmp((byte*) from,zero_string,length) == 0)
flag|=bit;
@@ -441,11 +441,11 @@ uint _nisam_rec_pack(N_INFO *info, register byte *to, register const byte *from)
memcpy((byte*) to,from,(size_t) length); to+=length;
}
}
- else if (type == FIELD_SKIPP_ENDSPACE ||
- type == FIELD_SKIPP_PRESPACE)
+ else if (type == FIELD_SKIP_ENDSPACE ||
+ type == FIELD_SKIP_PRESPACE)
{
pos= (byte*) from; end= (byte*) from + length;
- if (type == FIELD_SKIPP_ENDSPACE)
+ if (type == FIELD_SKIP_ENDSPACE)
{ /* Pack trailing spaces */
while (end > from && *(end-1) == ' ')
end--;
@@ -532,7 +532,7 @@ my_bool _nisam_rec_check(N_INFO *info,const char *from)
to+=length+ blob_length;
from+=sizeof(char*);
}
- else if (type == FIELD_SKIPP_ZERO)
+ else if (type == FIELD_SKIP_ZERO)
{
if (memcmp((byte*) from,zero_string,length) == 0)
{
@@ -542,11 +542,11 @@ my_bool _nisam_rec_check(N_INFO *info,const char *from)
else
to+=length;
}
- else if (type == FIELD_SKIPP_ENDSPACE ||
- type == FIELD_SKIPP_PRESPACE)
+ else if (type == FIELD_SKIP_ENDSPACE ||
+ type == FIELD_SKIP_PRESPACE)
{
pos= (byte*) from; end= (byte*) from + length;
- if (type == FIELD_SKIPP_ENDSPACE)
+ if (type == FIELD_SKIP_ENDSPACE)
{ /* Pack trailing spaces */
while (end > from && *(end-1) == ' ')
end--;
@@ -641,10 +641,10 @@ uint _nisam_rec_unpack(register N_INFO *info, register byte *to, byte *from,
bzero((byte*) to,rec_length+sizeof(char*));
to+=sizeof(char*);
}
- else if (type == FIELD_SKIPP_ZERO)
+ else if (type == FIELD_SKIP_ZERO)
bzero((byte*) to,rec_length);
- else if (type == FIELD_SKIPP_ENDSPACE ||
- type == FIELD_SKIPP_PRESPACE)
+ else if (type == FIELD_SKIP_ENDSPACE ||
+ type == FIELD_SKIP_PRESPACE)
{
if (rec->base.length > 255 && *from & 128)
{
@@ -662,7 +662,7 @@ uint _nisam_rec_unpack(register N_INFO *info, register byte *to, byte *from,
if (length >= rec_length ||
min_pack_length + length > (uint) (from_end - from))
goto err;
- if (type == FIELD_SKIPP_ENDSPACE)
+ if (type == FIELD_SKIP_ENDSPACE)
{
memcpy(to,(byte*) from,(size_t) length);
bfill((byte*) to+length,rec_length-length,' ');
@@ -690,7 +690,7 @@ uint _nisam_rec_unpack(register N_INFO *info, register byte *to, byte *from,
}
else
{
- if (type == FIELD_SKIPP_ENDSPACE || type == FIELD_SKIPP_PRESPACE)
+ if (type == FIELD_SKIP_ENDSPACE || type == FIELD_SKIP_PRESPACE)
min_pack_length--;
if (min_pack_length + rec_length > (uint) (from_end - from))
goto err;
diff --git a/isam/_key.c b/isam/_key.c
index 62f080af172..c0d667cb32d 100644
--- a/isam/_key.c
+++ b/isam/_key.c
@@ -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 */
diff --git a/isam/_locking.c b/isam/_locking.c
index ca38c611812..cccedbd16c8 100644
--- a/isam/_locking.c
+++ b/isam/_locking.c
@@ -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 */
diff --git a/isam/_packrec.c b/isam/_packrec.c
index 5c387f011ad..74a45852e63 100644
--- a/isam/_packrec.c
+++ b/isam/_packrec.c
@@ -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 */
@@ -456,7 +456,7 @@ int _nisam_pack_rec_unpack(register N_INFO *info, register byte *to,
static void (*get_unpack_function(N_RECINFO *rec))(N_RECINFO *, BIT_BUFF *, uchar *, uchar *)
{
switch (rec->base_type) {
- case FIELD_SKIPP_ZERO:
+ case FIELD_SKIP_ZERO:
if (rec->pack_type & PACK_TYPE_ZERO_FILL)
return &uf_zerofill_skipp_zero;
return &uf_skipp_zero;
@@ -466,7 +466,7 @@ static void (*get_unpack_function(N_RECINFO *rec))(N_RECINFO *, BIT_BUFF *, ucha
if (rec->pack_type & PACK_TYPE_ZERO_FILL)
return &uf_zerofill_normal;
return &decode_bytes;
- case FIELD_SKIPP_ENDSPACE:
+ case FIELD_SKIP_ENDSPACE:
if (rec->pack_type & PACK_TYPE_SPACE_FIELDS)
{
if (rec->pack_type & PACK_TYPE_SELECTED)
@@ -476,7 +476,7 @@ static void (*get_unpack_function(N_RECINFO *rec))(N_RECINFO *, BIT_BUFF *, ucha
if (rec->pack_type & PACK_TYPE_SELECTED)
return &uf_endspace_selected;
return &uf_endspace;
- case FIELD_SKIPP_PRESPACE:
+ case FIELD_SKIP_PRESPACE:
if (rec->pack_type & PACK_TYPE_SPACE_FIELDS)
{
if (rec->pack_type & PACK_TYPE_SELECTED)
diff --git a/isam/_page.c b/isam/_page.c
index 6f6d632e85d..65733d66b77 100644
--- a/isam/_page.c
+++ b/isam/_page.c
@@ -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 */
diff --git a/isam/_search.c b/isam/_search.c
index 93a08ea2b0d..57787d61818 100644
--- a/isam/_search.c
+++ b/isam/_search.c
@@ -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 */
diff --git a/isam/_statrec.c b/isam/_statrec.c
index d93f4fe27f5..9dbc948440f 100644
--- a/isam/_statrec.c
+++ b/isam/_statrec.c
@@ -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 */
@@ -187,7 +187,7 @@ int _nisam_read_rnd_static_record(N_INFO *info, byte *buf,
(skipp_deleted_blocks || !filepos))
{
cache_read=1; /* Read record using cache */
- cache_length=(uint) (info->rec_cache.rc_end - info->rec_cache.rc_pos);
+ cache_length=(uint) (info->rec_cache.read_end - info->rec_cache.read_pos);
}
else
info->rec_cache.seek_not_done=1; /* Filepos is changed */
diff --git a/isam/changed.c b/isam/changed.c
index 4f87a45aa2d..b8132538b86 100644
--- a/isam/changed.c
+++ b/isam/changed.c
@@ -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 */
diff --git a/isam/close.c b/isam/close.c
index 6741e7b23f0..f1465990100 100644
--- a/isam/close.c
+++ b/isam/close.c
@@ -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 */
diff --git a/isam/create.c b/isam/create.c
index fcf54ddc731..1fc2f3b97be 100644
--- a/isam/create.c
+++ b/isam/create.c
@@ -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 */
@@ -96,8 +96,8 @@ int nisam_create(const char *name,uint keys,N_KEYDEF *keyinfo,
pack_reclength+=sizeof(char*)+(1 << (rec->base.length*8));
}
}
- else if (type == FIELD_SKIPP_PRESPACE ||
- type == FIELD_SKIPP_ENDSPACE)
+ else if (type == FIELD_SKIP_PRESPACE ||
+ type == FIELD_SKIP_ENDSPACE)
{
if (pack_reclength != NI_POS_ERROR)
pack_reclength+= rec->base.length > 255 ? 2 : 1;
@@ -105,7 +105,7 @@ int nisam_create(const char *name,uint keys,N_KEYDEF *keyinfo,
}
else if (type == FIELD_ZERO)
packed--;
- else if (type != FIELD_SKIPP_ZERO)
+ else if (type != FIELD_SKIP_ZERO)
{
min_pack_length+=rec->base.length;
packed--; /* Not a pack record type */
@@ -119,7 +119,7 @@ int nisam_create(const char *name,uint keys,N_KEYDEF *keyinfo,
while (rec != recinfo)
{
rec--;
- if (rec->base.type == (int) FIELD_SKIPP_ZERO && rec->base.length == 1)
+ if (rec->base.type == (int) FIELD_SKIP_ZERO && rec->base.length == 1)
{
rec->base.type=(int) FIELD_NORMAL;
packed--;
diff --git a/isam/delete.c b/isam/delete.c
index e50ad72c767..5aa542561c1 100644
--- a/isam/delete.c
+++ b/isam/delete.c
@@ -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 */
@@ -613,5 +613,3 @@ static uint remove_key(N_KEYDEF *keyinfo, uint nod_flag,
(uint) (page_end-start-s_length));
DBUG_RETURN((uint) s_length);
} /* remove_key */
-
-
diff --git a/isam/extra.c b/isam/extra.c
index 1d333fa372f..570c396955f 100644
--- a/isam/extra.c
+++ b/isam/extra.c
@@ -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 */
@@ -204,6 +204,7 @@ int nisam_extra(N_INFO *info, enum ha_extra_function function)
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__
diff --git a/isam/info.c b/isam/info.c
index 43c15af908d..a23494e4876 100644
--- a/isam/info.c
+++ b/isam/info.c
@@ -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 */
diff --git a/isam/isamchk.c b/isam/isamchk.c
index 3aa1cf4e3c2..c09b1cd3324 100644
--- a/isam/isamchk.c
+++ b/isam/isamchk.c
@@ -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 */
@@ -62,7 +62,7 @@ SET_STACK_SIZE(9000) /* Minimum stack size for program */
#define MIN_SORT_BUFFER (4096-MALLOC_OVERHEAD)
#endif
-#define NEAD_MEM ((uint) 10*4*(IO_SIZE+32)+32) /* Nead for recursion */
+#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
@@ -512,7 +512,7 @@ static int nisamchk(my_string filename)
if (!rep_quick)
{
if (testflag & T_EXTEND)
- VOID(init_key_cache(use_buffers,(uint) NEAD_MEM));
+ VOID(init_key_cache(use_buffers,(uint) NEED_MEM));
VOID(init_io_cache(&read_cache,datafile,(uint) read_buffer_length,
READ_CACHE,share->pack.header_length,1,
MYF(MY_WME)));
@@ -1473,7 +1473,7 @@ my_string name;
printf("Data records: %lu\n",(ulong) share->state.records);
}
- VOID(init_key_cache(use_buffers,NEAD_MEM));
+ VOID(init_key_cache(use_buffers,NEED_MEM));
if (init_io_cache(&read_cache,info->dfile,(uint) read_buffer_length,
READ_CACHE,share->pack.header_length,1,MYF(MY_WME)))
goto err;
@@ -1950,7 +1950,7 @@ int write_info;
if (share->state.key_root[sort_key] == NI_POS_ERROR)
DBUG_RETURN(0); /* Nothing to do */
- init_key_cache(use_buffers,NEAD_MEM);
+ init_key_cache(use_buffers,NEED_MEM);
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)))
diff --git a/isam/isamdef.h b/isam/isamdef.h
index da08b5f6a14..0884b18e997 100644
--- a/isam/isamdef.h
+++ b/isam/isamdef.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 */
diff --git a/isam/isamlog.c b/isam/isamlog.c
index 5763b697d07..6d2bde42bf7 100644
--- a/isam/isamlog.c
+++ b/isam/isamlog.c
@@ -327,8 +327,8 @@ static int examine_log(my_string file_name, char **table_names)
init_io_cache(&cache,file,0,READ_CACHE,start_offset,0,MYF(0));
bzero((gptr) com_count,sizeof(com_count));
- init_tree(&tree,0,sizeof(file_info),(qsort_cmp) file_info_compare,1,
- (void(*)(void*)) file_info_free);
+ 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(KEY_CACHE_SIZE,(uint) (10*4*(IO_SIZE+MALLOC_OVERHEAD))));
files_open=0; access_time=0;
@@ -400,11 +400,7 @@ static int examine_log(my_string file_name, char **table_names)
}
to=isam_file_name;
if (filepath)
- {
- strmov(isam_file_name,filepath);
- convert_dirname(isam_file_name);
- to=strend(isam_file_name);
- }
+ to=convert_dirname(isam_file_name, filepath, NullS);
strmov(to,pos);
fn_ext(isam_file_name)[0]=0; /* Remove extension */
}
diff --git a/isam/log.c b/isam/log.c
index a95b53b5110..78b56690401 100644
--- a/isam/log.c
+++ b/isam/log.c
@@ -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 */
diff --git a/isam/open.c b/isam/open.c
index a3ede4512b9..48fab27cac1 100644
--- a/isam/open.c
+++ b/isam/open.c
@@ -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 */
diff --git a/isam/pack_isam.c b/isam/pack_isam.c
index 3d8512847ae..4a3a787ff5c 100644
--- a/isam/pack_isam.c
+++ b/isam/pack_isam.c
@@ -682,9 +682,9 @@ static HUFF_COUNTS *init_huff_count(N_INFO *info,my_off_t records)
type = FIELD_NORMAL;
if (count[i].field_length <= 8 &&
(type == FIELD_NORMAL ||
- type == FIELD_SKIPP_ZERO))
+ type == FIELD_SKIP_ZERO))
count[i].max_zero_fill= count[i].field_length;
- init_tree(&count[i].int_tree,0,-1,(qsort_cmp) compare_tree,0,NULL);
+ 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,
@@ -786,7 +786,7 @@ static int get_statistic(MRG_INFO *mrg,HUFF_COUNTS *huff_counts)
/* Save character counters and space-counts and zero-field-counts */
if (count->field_type == FIELD_NORMAL ||
- count->field_type == FIELD_SKIPP_ENDSPACE)
+ count->field_type == FIELD_SKIP_ENDSPACE)
{
for ( ; end_pos > pos ; end_pos--)
if (end_pos[-1] != ' ')
@@ -805,7 +805,7 @@ static int get_statistic(MRG_INFO *mrg,HUFF_COUNTS *huff_counts)
count->max_end_space = length;
}
if (count->field_type == FIELD_NORMAL ||
- count->field_type == FIELD_SKIPP_PRESPACE)
+ count->field_type == FIELD_SKIP_PRESPACE)
{
for (pos=start_pos; pos < end_pos ; pos++)
if (pos[0] != ' ')
@@ -825,7 +825,7 @@ static int get_statistic(MRG_INFO *mrg,HUFF_COUNTS *huff_counts)
}
if (count->field_length <= 8 &&
(count->field_type == FIELD_NORMAL ||
- count->field_type == FIELD_SKIPP_ZERO))
+ count->field_type == FIELD_SKIP_ZERO))
{
uint i;
if (!memcmp((byte*) start_pos,zero_string,count->field_length))
@@ -906,7 +906,7 @@ static void check_counts(HUFF_COUNTS *huff_counts, uint trees, my_off_t records)
new_length=calc_packed_length(huff_counts,0);
if (old_length < new_length && huff_counts->field_length > 1)
{
- huff_counts->field_type=FIELD_SKIPP_ZERO;
+ huff_counts->field_type=FIELD_SKIP_ZERO;
huff_counts->counts[0]-=length;
huff_counts->bytes_packed=old_length- records/8;
goto found_pack;
@@ -950,7 +950,7 @@ static void check_counts(HUFF_COUNTS *huff_counts, uint trees, my_off_t records)
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_SKIPP_ENDSPACE))
+ huff_counts->tot_end_space,FIELD_SKIP_ENDSPACE))
goto found_pack;
huff_counts->counts[' ']-=huff_counts->tot_pre_space;
}
@@ -958,7 +958,7 @@ static void check_counts(HUFF_COUNTS *huff_counts, uint trees, my_off_t records)
{
if (test_space_compress(huff_counts,records,huff_counts->max_pre_space,
huff_counts->pre_space,
- huff_counts->tot_pre_space,FIELD_SKIPP_PRESPACE))
+ huff_counts->tot_pre_space,FIELD_SKIP_PRESPACE))
goto found_pack;
}
@@ -968,10 +968,10 @@ static void check_counts(HUFF_COUNTS *huff_counts, uint trees, my_off_t records)
if (huff_counts->max_zero_fill &&
(huff_counts->field_type == FIELD_NORMAL ||
- huff_counts->field_type == FIELD_SKIPP_ZERO))
+ huff_counts->field_type == FIELD_SKIP_ZERO))
{
huff_counts->counts[0]-=huff_counts->max_zero_fill*
- (huff_counts->field_type == FIELD_SKIPP_ZERO ?
+ (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);
@@ -1011,9 +1011,9 @@ static void check_counts(HUFF_COUNTS *huff_counts, uint trees, my_off_t records)
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_SKIPP_ZERO],fill_zero_fields,
- field_count[FIELD_SKIPP_PRESPACE],
- field_count[FIELD_SKIPP_ENDSPACE],
+ 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;
@@ -1668,7 +1668,7 @@ static int compress_isam_file(MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
field_length-=count->max_zero_fill;
switch(count->field_type) {
- case FIELD_SKIPP_ZERO:
+ case FIELD_SKIP_ZERO:
if (!memcmp((byte*) start_pos,zero_string,field_length))
{
write_bits(1,1);
@@ -1682,7 +1682,7 @@ static int compress_isam_file(MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
write_bits(tree->code[(uchar) *start_pos],
(uint) tree->code_len[(uchar) *start_pos]);
break;
- case FIELD_SKIPP_ENDSPACE:
+ 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)
@@ -1705,7 +1705,7 @@ static int compress_isam_file(MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
(uint) tree->code_len[(uchar) *start_pos]);
start_pos=end_pos;
break;
- case FIELD_SKIPP_PRESPACE:
+ 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)
diff --git a/isam/panic.c b/isam/panic.c
index 52a5d1eb3b6..e51e83671df 100644
--- a/isam/panic.c
+++ b/isam/panic.c
@@ -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 */
diff --git a/isam/range.c b/isam/range.c
index 5594991cfc3..3b79b6d93a9 100644
--- a/isam/range.c
+++ b/isam/range.c
@@ -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 */
diff --git a/isam/rfirst.c b/isam/rfirst.c
index 82fd3994bdf..cc1cbee92bf 100644
--- a/isam/rfirst.c
+++ b/isam/rfirst.c
@@ -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 */
diff --git a/isam/rkey.c b/isam/rkey.c
index 8f1f2f11ab5..bbe4576418b 100644
--- a/isam/rkey.c
+++ b/isam/rkey.c
@@ -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 */
diff --git a/isam/rlast.c b/isam/rlast.c
index df2b1bc39af..a91f1f1011b 100644
--- a/isam/rlast.c
+++ b/isam/rlast.c
@@ -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 */
diff --git a/isam/rnext.c b/isam/rnext.c
index 451624bb42b..be26098c901 100644
--- a/isam/rnext.c
+++ b/isam/rnext.c
@@ -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 */
diff --git a/isam/rprev.c b/isam/rprev.c
index 50f22c838fd..0997a04fbbe 100644
--- a/isam/rprev.c
+++ b/isam/rprev.c
@@ -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 */
diff --git a/isam/rrnd.c b/isam/rrnd.c
index 7fd197a6d58..16b3ab1b859 100644
--- a/isam/rrnd.c
+++ b/isam/rrnd.c
@@ -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 */
diff --git a/isam/rsame.c b/isam/rsame.c
index fe617cf258c..9a2a03da054 100644
--- a/isam/rsame.c
+++ b/isam/rsame.c
@@ -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 */
diff --git a/isam/rsamepos.c b/isam/rsamepos.c
index 500dfc60e38..c64ac492d1a 100644
--- a/isam/rsamepos.c
+++ b/isam/rsamepos.c
@@ -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 */
diff --git a/isam/sort.c b/isam/sort.c
index 72c4c7564f8..d22b0e648a0 100644
--- a/isam/sort.c
+++ b/isam/sort.c
@@ -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 */
diff --git a/isam/static.c b/isam/static.c
index 941c4defea2..9c68a0cfdba 100644
--- a/isam/static.c
+++ b/isam/static.c
@@ -1,21 +1,21 @@
/* 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 pisam library. All definied here for easy making of
+ Static variables for ISAM library. All definied here for easy making of
a shared library
*/
diff --git a/isam/test1.c b/isam/test1.c
index 33c61a53d4a..9ebc7af041d 100644
--- a/isam/test1.c
+++ b/isam/test1.c
@@ -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 */
@@ -19,7 +19,7 @@
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_SKIPP_PRESPACE;
+ packed_field=FIELD_SKIP_PRESPACE;
int main(int argc, char *argv[])
{
diff --git a/isam/test2.c b/isam/test2.c
index def6a4d3d5c..176346e74fa 100644
--- a/isam/test2.c
+++ b/isam/test2.c
@@ -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 */
@@ -115,17 +115,17 @@ int main(int argc, char *argv[])
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_SKIPP_PRESPACE : 0;
+ recinfo[0].base.type=pack_fields ? FIELD_SKIP_PRESPACE : 0;
recinfo[0].base.length=7;
- recinfo[1].base.type=pack_fields ? FIELD_SKIPP_PRESPACE : 0;
+ recinfo[1].base.type=pack_fields ? FIELD_SKIP_PRESPACE : 0;
recinfo[1].base.length=5;
- recinfo[2].base.type=pack_fields ? FIELD_SKIPP_PRESPACE : 0;
+ 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_SKIPP_ZERO : 0;
+ recinfo[4].base.type=pack_fields ? FIELD_SKIP_ZERO : 0;
recinfo[4].base.length=4;
- recinfo[5].base.type=pack_fields ? FIELD_SKIPP_ENDSPACE : 0;
+ recinfo[5].base.type=pack_fields ? FIELD_SKIP_ENDSPACE : 0;
recinfo[5].base.length=60;
if (use_blob)
{
diff --git a/isam/test3.c b/isam/test3.c
index 935c194106d..6c3390a2720 100644
--- a/isam/test3.c
+++ b/isam/test3.c
@@ -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 */
@@ -172,7 +172,7 @@ void start_test(int id)
}
if (key_cacheing && rnd(2) == 0)
init_key_cache(65536L,(uint) IO_SIZE*4*10);
- printf("Process %d, pid: %d\n",id,getpid()); fflush(stdout);
+ printf("Process %d, pid: %d\n",id,(int) getpid()); fflush(stdout);
for (error=i=0 ; i < tests && !error; i++)
{
@@ -356,7 +356,7 @@ int test_write(N_INFO *file,int id,int lock_type)
nisam_extra(file,HA_EXTRA_WRITE_CACHE);
}
- sprintf(record.id,"%7d",getpid());
+ sprintf(record.id,"%7d",(int) getpid());
strmov(record.text,"Testing...");
tries=(uint) rnd(100)+10;
diff --git a/isam/update.c b/isam/update.c
index 82dab4140e3..b3b676f967d 100644
--- a/isam/update.c
+++ b/isam/update.c
@@ -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 */
diff --git a/isam/write.c b/isam/write.c
index 49b0916afc4..f2c0d8dbc45 100644
--- a/isam/write.c
+++ b/isam/write.c
@@ -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 */
@@ -262,7 +262,7 @@ int _nisam_insert(register N_INFO *info, register N_KEYDEF *keyinfo,
/* 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);
diff --git a/libmysql/Makefile.am b/libmysql/Makefile.am
index 68c2022223e..2eaf9709a36 100644
--- a/libmysql/Makefile.am
+++ b/libmysql/Makefile.am
@@ -18,10 +18,10 @@
# This file is public domain and comes with NO WARRANTY of any kind
target = libmysqlclient.la
-target_defs = -DUNDEF_THREADS_HACK -DDONT_USE_RAID @LIB_EXTRA_CCFLAGS@
+target_defs = -DUNDEF_THREADS_HACK -DDONT_USE_RAID @LIB_EXTRA_CCFLAGS@ -DMYSQL_CLIENT
LIBS = @CLIENT_LIBS@
INCLUDES = -I$(srcdir)/../include -I../include \
- -I$(srcdir)/.. -I$(top_srcdir) -I..
+ -I$(srcdir)/.. -I$(top_srcdir) -I.. $(openssl_includes)
include $(srcdir)/Makefile.shared
@@ -36,14 +36,23 @@ link_sources:
ss=`echo $(mystringsobjects) | sed "s;\.lo;.c;g"`; \
ds=`echo $(dbugobjects) | sed "s;\.lo;.c;g"`; \
ms=`echo $(mysysobjects) | sed "s;\.lo;.c;g"`; \
+ vs=`echo $(vio_objects) | sed "s;\.lo;.c;g"`; \
for f in $$ss; do \
rm -f $(srcdir)/$$f; \
@LN_CP_F@ $(srcdir)/../strings/$$f $(srcdir)/$$f; \
done; \
+ for f in $$vs; do \
+ rm -f $(srcdir)/$$f; \
+ @LN_CP_F@ $(srcdir)/../vio/$$f $(srcdir)/$$f; \
+ done; \
for f in $(mystringsextra); do \
rm -f $(srcdir)/$$f; \
@LN_CP_F@ $(srcdir)/../strings/$$f $(srcdir)/$$f; \
done; \
+ for f in $$qs; do \
+ rm -f $(srcdir)/$$f; \
+ @LN_CP_F@ $(srcdir)/../sql/$$f $(srcdir)/$$f; \
+ done; \
for f in $$ds; do \
rm -f $(srcdir)/$$f; \
@LN_CP_F@ $(srcdir)/../dbug/$$f $(srcdir)/$$f; \
@@ -62,11 +71,11 @@ link_sources:
# keep only the stubs for safemalloc.c and debug.c
#
# A list of needed headers collected from the deps information 000213
-nh = global.h config-win32.h dbug.h errmsg.h global.h \
+nh = my_global.h config-win32.h dbug.h errmsg.h \
m_ctype.h m_string.h \
my_alarm.h my_config.h my_dir.h my_list.h my_net.h my_sys.h \
- mysql.h mysql_com.h mysql_version.h mysqld_error.h mysys_err.h \
- my_pthread.h thr_alarm.h violite.h hash.h
+ mysql.h mysql_com.h mysql_version.h mysqld_error.h \
+ mysys_err.h my_pthread.h thr_alarm.h violite.h hash.h
# Get a list of the needed objects
lobjs = $(mysysobjects1) $(dbugobjects) $(mystringsobjects)
diff --git a/libmysql/Makefile.shared b/libmysql/Makefile.shared
index e9e100e38b1..0d3aa79b9ce 100644
--- a/libmysql/Makefile.shared
+++ b/libmysql/Makefile.shared
@@ -31,13 +31,14 @@ noinst_PROGRAMS = conf_to_src
CHARSET_OBJS=@CHARSET_OBJS@
LTCHARSET_OBJS= ${CHARSET_OBJS:.o=.lo}
-target_sources = libmysql.c net.c violite.c password.c \
+target_sources = libmysql.c net.c password.c manager.c \
get_password.c errmsg.c
-mystringsobjects = strmov.lo strxmov.lo strnmov.lo strmake.lo strend.lo \
+mystringsobjects = strmov.lo strxmov.lo strxnmov.lo strnmov.lo \
+ strmake.lo strend.lo \
strnlen.lo strfill.lo is_prefix.lo \
int2str.lo str2int.lo strinstr.lo strcont.lo \
- strcend.lo \
+ strcend.lo bcmp.lo \
bchange.lo bmove.lo bmove_upp.lo longlong2str.lo \
strtoull.lo strtoll.lo llstr.lo \
ctype.lo $(LTCHARSET_OBJS)
@@ -55,13 +56,17 @@ mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \
mf_loadpath.lo my_pthread.lo my_thr_init.lo \
thr_mutex.lo mulalloc.lo string.lo default.lo \
my_compress.lo array.lo my_once.lo list.lo my_net.lo \
- charset.lo hash.lo mf_iocache.lo my_seek.lo \
- my_pread.lo mf_cache.lo
+ charset.lo hash.lo mf_iocache.lo \
+ mf_iocache2.lo my_seek.lo \
+ my_pread.lo mf_cache.lo my_vsnprintf.lo md5.lo
+
# Not needed in the minimum library
mysysobjects2 = getopt.lo getopt1.lo getvar.lo my_lib.lo
mysysobjects = $(mysysobjects1) $(mysysobjects2)
-target_libadd = $(mysysobjects) $(mystringsobjects) $(dbugobjects)
+target_libadd = $(mysysobjects) $(mystringsobjects) $(dbugobjects) \
+ $(vio_objects)
target_ldflags = -version-info @SHARED_LIB_VERSION@
+vio_objects= vio.lo viosocket.lo viossl.lo viosslfactories.lo
CLEANFILES = $(target_libadd) $(SHLIBOBJS) \
$(target)
DEFS = -DDEFAULT_CHARSET_HOME="\"$(MYSQLBASEdir)\"" \
@@ -76,6 +81,7 @@ clean-local:
rm -f `echo $(mystringsobjects) | sed "s;\.lo;.c;g"` \
`echo $(dbugobjects) | sed "s;\.lo;.c;g"` \
`echo $(mysysobjects) | sed "s;\.lo;.c;g"` \
+ `echo $(vio_objects) | sed "s;\.lo;.c;g"` \
$(mystringsextra) $(mysysheaders) ctype_extra_sources.c \
../linked_client_sources
diff --git a/libmysql/conf_to_src.c b/libmysql/conf_to_src.c
index 76316638153..95ffcf1cb2b 100644
--- a/libmysql/conf_to_src.c
+++ b/libmysql/conf_to_src.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* can't use -lmysys because this prog is used to create -lstrings */
diff --git a/libmysql/dll.c b/libmysql/dll.c
index d1a23794025..f0a67d8f091 100644
--- a/libmysql/dll.c
+++ b/libmysql/dll.c
@@ -1,25 +1,24 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
** Handling initialization of the dll library
*/
-#include <global.h>
+#include <my_global.h>
#include <my_sys.h>
#include <my_pthread.h>
diff --git a/libmysql/errmsg.c b/libmysql/errmsg.c
index 67cfe874f77..3fdb9c0ddc6 100644
--- a/libmysql/errmsg.c
+++ b/libmysql/errmsg.c
@@ -1,24 +1,23 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Error messages for MySQL clients */
-/* error messages for the demon is in share/language/errmsg.sys */
+/* error messages for the daemon is in share/language/errmsg.sys */
-#include <global.h>
+#include <my_global.h>
#include <my_sys.h>
#include "errmsg.h"
@@ -45,7 +44,12 @@ const char *client_errors[]=
"Kann Named Pipe nicht oeffnen. Host: %-.64s pipe: %-.32s (%lu)",
"Kann den Status der Named Pipe nicht setzen. Host: %-.64s pipe: %-.32s (%lu)",
"Can't initialize character set %-.64s (path: %-.64s)",
- "Got packet bigger than 'max_allowed_packet'"
+ "Got packet bigger than 'max_allowed_packet'",
+ "Embedded server",
+ "Error on SHOW SLAVE STATUS:",
+ "Error on SHOW SLAVE HOSTS:",
+ "Error connecting to slave:",
+ "Error connecting to master:"
};
/* Start of code added by Roberto M. Serqueira - martinsc@uol.com.br - 05.24.2001 */
@@ -73,7 +77,12 @@ const char *client_errors[]=
"Não pode abrir 'named pipe' para o 'host' %-.64s - 'pipe' %-.32s (%lu)",
"Não pode estabelecer o estado do 'named pipe' para o 'host' %-.64s - 'pipe' %-.32s (%lu)",
"Não pode inicializar conjunto de caracteres %-.64s (caminho %-.64s)",
- "Obteve pacote maior do que 'max_allowed_packet'"
+ "Obteve pacote maior do que 'max_allowed_packet'",
+ "Embedded server"
+ "Error on SHOW SLAVE STATUS:",
+ "Error on SHOW SLAVE HOSTS:",
+ "Error connecting to slave:",
+ "Error connecting to master:"
};
#else /* ENGLISH */
@@ -99,7 +108,12 @@ const char *client_errors[]=
"Can't open named pipe to host: %-.64s pipe: %-.32s (%lu)",
"Can't set state of named pipe to host: %-.64s pipe: %-.32s (%lu)",
"Can't initialize character set %-.64s (path: %-.64s)",
- "Got packet bigger than 'max_allowed_packet'"
+ "Got packet bigger than 'max_allowed_packet'",
+ "Embedded server",
+ "Error on SHOW SLAVE STATUS:",
+ "Error on SHOW SLAVE HOSTS:",
+ "Error connecting to slave:",
+ "Error connecting to master:"
};
#endif
diff --git a/libmysql/get_password.c b/libmysql/get_password.c
index 989de9dd11a..124c315a821 100644
--- a/libmysql/get_password.c
+++ b/libmysql/get_password.c
@@ -1,25 +1,24 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
** Ask for a password from tty
** This is an own file to avoid conflicts with curses
*/
-#include <global.h>
+#include <my_global.h>
#include <my_sys.h>
#include "mysql.h"
#include <m_string.h>
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
index 09a9fc0dd4c..31b0ea0fb53 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -1,21 +1,20 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
-
-#include <global.h>
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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>
#if defined(__WIN__) || defined(_WIN32) || defined(_WIN64)
#include <winsock.h>
#include <odbcinst.h>
@@ -70,7 +69,7 @@ my_string mysql_unix_port=0;
#endif
#if defined(MSDOS) || defined(__WIN__)
-// socket_errno is defined in global.h for all platforms
+// socket_errno is defined in my_global.h for all platforms
#define perror(A)
#else
#include <errno.h>
@@ -91,6 +90,32 @@ static sig_handler pipe_sig_handler(int sig);
static ulong mysql_sub_escape_string(CHARSET_INFO *charset_info, char *to,
const char *from, ulong length);
+int STDCALL mysql_server_init(int argc __attribute__((unused)),
+ char **argv __attribute__((unused)),
+ char **groups __attribute__((unused)))
+{
+ return 0;
+}
+
+void STDCALL mysql_server_end()
+{}
+
+my_bool STDCALL mysql_thread_init()
+{
+#ifdef THREAD
+ return my_thread_init();
+#else
+ return 0;
+#endif
+}
+
+void STDCALL mysql_thread_end()
+{
+#ifdef THREAD
+ my_thread_end();
+#endif
+}
+
/*
Let the user specify that we don't want SIGPIPE; This doesn't however work
with threaded applications as we can have multiple read in progress.
@@ -106,17 +131,23 @@ static ulong mysql_sub_escape_string(CHARSET_INFO *charset_info, char *to,
#define reset_sigpipe(mysql)
#endif
+static MYSQL* spawn_init(MYSQL* parent, const char* host,
+ unsigned int port,
+ const char* user,
+ const char* passwd);
+
+
/****************************************************************************
* A modified version of connect(). connect2() allows you to specify
* a timeout value, in seconds, that we should wait until we
* derermine we can't connect to a particular host. If timeout is 0,
-* connect2() will behave exactly like connect().
+* my_connect() will behave exactly like connect().
*
* Base version coded by Steve Bernacki, Jr. <steve@navinet.net>
*****************************************************************************/
-static int connect2(my_socket s, const struct sockaddr *name, uint namelen,
- uint timeout)
+int my_connect(my_socket s, const struct sockaddr *name, uint namelen,
+ uint timeout)
{
#if defined(__WIN__) || defined(OS2)
return connect(s, (struct sockaddr*) name, namelen);
@@ -284,11 +315,11 @@ HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host,
** or packet is an error message
*****************************************************************************/
-uint
+ulong
net_safe_read(MYSQL *mysql)
{
NET *net= &mysql->net;
- uint len=0;
+ ulong len=0;
init_sigpipe_variables
/* Don't give sigpipe errors if the client doesn't want them */
@@ -306,26 +337,18 @@ net_safe_read(MYSQL *mysql)
CR_NET_PACKET_TOO_LARGE:
CR_SERVER_LOST);
strmov(net->last_error,ER(net->last_errno));
- return(packet_error);
+ return (packet_error);
}
if (net->read_pos[0] == 255)
{
if (len > 3)
{
char *pos=(char*) net->read_pos+1;
- if (mysql->protocol_version > 9)
- { /* New client protocol */
- net->last_errno=uint2korr(pos);
- pos+=2;
- len-=2;
- }
- else
- {
- net->last_errno=CR_UNKNOWN_ERROR;
- len--;
- }
+ net->last_errno=uint2korr(pos);
+ pos+=2;
+ len-=2;
(void) strmake(net->last_error,(char*) pos,
- min(len,sizeof(net->last_error)-1));
+ min((uint) len,(uint) sizeof(net->last_error)-1));
}
else
{
@@ -416,7 +439,7 @@ static void free_rows(MYSQL_DATA *cur)
int
simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg,
- uint length, my_bool skipp_check)
+ ulong length, my_bool skipp_check)
{
NET *net= &mysql->net;
int result= -1;
@@ -647,8 +670,8 @@ mysql_free_result(MYSQL_RES *result)
DBUG_PRINT("warning",("Not all rows in set were read; Ignoring rows"));
for (;;)
{
- uint pkt_len;
- if ((pkt_len=(uint) net_safe_read(result->handle)) == packet_error)
+ ulong pkt_len;
+ if ((pkt_len=net_safe_read(result->handle)) == packet_error)
break;
if (pkt_len == 1 && result->handle->net.read_pos[0] == 254)
break; /* End of data */
@@ -677,6 +700,8 @@ static const char *default_options[]=
"ssl-key" ,"ssl-cert" ,"ssl-ca" ,"ssl-capath",
"character-set-dir", "default-character-set", "interactive-timeout",
"connect-timeout", "local-infile", "disable-local-infile",
+ "replication-probe", "enable-reads-from-master", "repl-parse-query",
+ "ssl-cipher",
NullS
};
@@ -821,6 +846,15 @@ static void mysql_read_default_options(struct st_mysql_options *options,
break;
case 22:
options->client_flag&= CLIENT_LOCAL_FILES;
+ break;
+ case 23: /* replication probe */
+ options->rpl_probe = 1;
+ break;
+ case 24: /* enable-reads-from-master */
+ options->rpl_parse = 1;
+ break;
+ case 25: /* repl-parse-query */
+ options->no_master_reads = 0;
break;
default:
DBUG_PRINT("warning",("unknown option: %s",option[0]));
@@ -845,13 +879,14 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields,
MYSQL_FIELD *field,*result;
DBUG_ENTER("unpack_fields");
- field=result=(MYSQL_FIELD*) alloc_root(alloc,sizeof(MYSQL_FIELD)*fields);
+ field=result=(MYSQL_FIELD*) alloc_root(alloc,
+ (uint) sizeof(MYSQL_FIELD)*fields);
if (!result)
DBUG_RETURN(0);
for (row=data->data; row ; row = row->next,field++)
{
- field->table= strdup_root(alloc,(char*) row->data[0]);
+ field->org_table= field->table= strdup_root(alloc,(char*) row->data[0]);
field->name= strdup_root(alloc,(char*) row->data[1]);
field->length= (uint) uint3korr(row->data[2]);
field->type= (enum enum_field_types) (uchar) row->data[3][0];
@@ -883,7 +918,8 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields,
static MYSQL_DATA *read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
uint fields)
{
- uint field,pkt_len;
+ uint field;
+ ulong pkt_len;
ulong len;
uchar *cp;
char *to;
@@ -892,7 +928,7 @@ static MYSQL_DATA *read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
NET *net = &mysql->net;
DBUG_ENTER("read_rows");
- if ((pkt_len=(uint) net_safe_read(mysql)) == packet_error)
+ if ((pkt_len= net_safe_read(mysql)) == packet_error)
DBUG_RETURN(0);
if (!(result=(MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA),
MYF(MY_WME | MY_ZEROFILL))))
@@ -969,7 +1005,7 @@ read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths)
ulong pkt_len,len;
uchar *pos,*prev_pos;
- if ((pkt_len=(uint) net_safe_read(mysql)) == packet_error)
+ if ((pkt_len=net_safe_read(mysql)) == packet_error)
return -1;
if (pkt_len == 1 && mysql->net.read_pos[0] == 254)
return 1; /* End of data */
@@ -997,6 +1033,280 @@ read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths)
return 0;
}
+/* perform query on master */
+int STDCALL mysql_master_query(MYSQL *mysql, const char *q,
+ unsigned long length)
+{
+ if (mysql_master_send_query(mysql, q, length))
+ return 1;
+ return mysql_read_query_result(mysql);
+}
+
+int STDCALL mysql_master_send_query(MYSQL *mysql, const char *q,
+ unsigned long length)
+{
+ MYSQL*master = mysql->master;
+ if (!length)
+ length = strlen(q);
+ if (!master->net.vio && !mysql_real_connect(master,0,0,0,0,0,0,0))
+ return 1;
+ mysql->last_used_con = master;
+ return simple_command(master, COM_QUERY, q, length, 1);
+}
+
+
+/* perform query on slave */
+int STDCALL mysql_slave_query(MYSQL *mysql, const char *q,
+ unsigned long length)
+{
+ if (mysql_slave_send_query(mysql, q, length))
+ return 1;
+ return mysql_read_query_result(mysql);
+}
+
+int STDCALL mysql_slave_send_query(MYSQL *mysql, const char *q,
+ unsigned long length)
+{
+ MYSQL* last_used_slave, *slave_to_use = 0;
+
+ if ((last_used_slave = mysql->last_used_slave))
+ slave_to_use = last_used_slave->next_slave;
+ else
+ slave_to_use = mysql->next_slave;
+ /* next_slave is always safe to use - we have a circular list of slaves
+ if there are no slaves, mysql->next_slave == mysql
+ */
+ mysql->last_used_con = mysql->last_used_slave = slave_to_use;
+ if (!length)
+ length = strlen(q);
+ if (!slave_to_use->net.vio && !mysql_real_connect(slave_to_use, 0,0,0,
+ 0,0,0,0))
+ return 1;
+ return simple_command(slave_to_use, COM_QUERY, q, length, 1);
+}
+
+
+/* enable/disable parsing of all queries to decide
+ if they go on master or slave */
+void STDCALL mysql_enable_rpl_parse(MYSQL* mysql)
+{
+ mysql->options.rpl_parse = 1;
+}
+
+void STDCALL mysql_disable_rpl_parse(MYSQL* mysql)
+{
+ mysql->options.rpl_parse = 0;
+}
+
+/* get the value of the parse flag */
+int STDCALL mysql_rpl_parse_enabled(MYSQL* mysql)
+{
+ return mysql->options.rpl_parse;
+}
+
+/* enable/disable reads from master */
+void STDCALL mysql_enable_reads_from_master(MYSQL* mysql)
+{
+ mysql->options.no_master_reads = 0;
+}
+
+void STDCALL mysql_disable_reads_from_master(MYSQL* mysql)
+{
+ mysql->options.no_master_reads = 1;
+}
+
+/* get the value of the master read flag */
+int STDCALL mysql_reads_from_master_enabled(MYSQL* mysql)
+{
+ return !(mysql->options.no_master_reads);
+}
+
+/* We may get an error while doing replication internals.
+ In this case, we add a special explanation to the original
+ error
+*/
+static inline void expand_error(MYSQL* mysql, int error)
+{
+ char tmp[MYSQL_ERRMSG_SIZE];
+ char* p, *tmp_end;
+ tmp_end = strnmov(tmp, mysql->net.last_error, MYSQL_ERRMSG_SIZE);
+ p = strnmov(mysql->net.last_error, ER(error), MYSQL_ERRMSG_SIZE);
+ memcpy(p, tmp, tmp_end - tmp);
+ mysql->net.last_errno = error;
+}
+
+/* This function assumes we have just called SHOW SLAVE STATUS and have
+ read the given result and row
+*/
+static inline int get_master(MYSQL* mysql, MYSQL_RES* res, MYSQL_ROW row)
+{
+ MYSQL* master;
+ if (mysql_num_fields(res) < 3)
+ return 1; /* safety */
+
+ /* use the same username and password as the original connection */
+ if (!(master = spawn_init(mysql, row[0], atoi(row[2]), 0, 0)))
+ return 1;
+ mysql->master = master;
+ return 0;
+}
+
+/* assuming we already know that mysql points to a master connection,
+ retrieve all the slaves
+*/
+static inline int get_slaves_from_master(MYSQL* mysql)
+{
+ MYSQL_RES* res = 0;
+ MYSQL_ROW row;
+ int error = 1;
+ int has_auth_info;
+ int port_ind;
+
+ if (!mysql->net.vio && !mysql_real_connect(mysql,0,0,0,0,0,0,0))
+ {
+ expand_error(mysql, CR_PROBE_MASTER_CONNECT);
+ return 1;
+ }
+
+ if (mysql_query(mysql, "SHOW SLAVE HOSTS") ||
+ !(res = mysql_store_result(mysql)))
+ {
+ expand_error(mysql, CR_PROBE_SLAVE_HOSTS);
+ return 1;
+ }
+
+ switch (mysql_num_fields(res))
+ {
+ case 5:
+ has_auth_info = 0;
+ port_ind=2;
+ break;
+ case 7:
+ has_auth_info = 1;
+ port_ind=4;
+ break;
+ default:
+ goto err;
+ }
+
+ while ((row = mysql_fetch_row(res)))
+ {
+ MYSQL* slave;
+ const char* tmp_user, *tmp_pass;
+
+ if (has_auth_info)
+ {
+ tmp_user = row[2];
+ tmp_pass = row[3];
+ }
+ else
+ {
+ tmp_user = mysql->user;
+ tmp_pass = mysql->passwd;
+ }
+
+ if (!(slave = spawn_init(mysql, row[1], atoi(row[port_ind]),
+ tmp_user, tmp_pass)))
+ goto err;
+
+ /* Now add slave into the circular linked list */
+ slave->next_slave = mysql->next_slave;
+ mysql->next_slave = slave;
+ }
+ error = 0;
+err:
+ if (res)
+ mysql_free_result(res);
+ return error;
+}
+
+int STDCALL mysql_rpl_probe(MYSQL* mysql)
+{
+ MYSQL_RES* res = 0;
+ MYSQL_ROW row;
+ int error = 1;
+ /* first determine the replication role of the server we connected to
+ the most reliable way to do this is to run SHOW SLAVE STATUS and see
+ if we have a non-empty master host. This is still not fool-proof -
+ it is not a sin to have a master that has a dormant slave thread with
+ a non-empty master host. However, it is more reliable to check
+ for empty master than whether the slave thread is actually running
+ */
+ if (mysql_query(mysql, "SHOW SLAVE STATUS") ||
+ !(res = mysql_store_result(mysql)))
+ {
+ expand_error(mysql, CR_PROBE_SLAVE_STATUS);
+ return 1;
+ }
+
+ if (!(row = mysql_fetch_row(res)))
+ goto err;
+
+ /* check master host for emptiness/NULL */
+ if (row[0] && *(row[0]))
+ {
+ /* this is a slave, ask it for the master */
+ if (get_master(mysql, res, row) || get_slaves_from_master(mysql))
+ goto err;
+ }
+ else
+ {
+ mysql->master = mysql;
+ if (get_slaves_from_master(mysql))
+ goto err;
+ }
+
+ error = 0;
+err:
+ if (res)
+ mysql_free_result(res);
+ return error;
+}
+
+
+/* make a not so fool-proof decision on where the query should go, to
+ the master or the slave. Ideally the user should always make this
+ decision himself with mysql_master_query() or mysql_slave_query().
+ However, to be able to more easily port the old code, we support the
+ option of an educated guess - this should work for most applications,
+ however, it may make the wrong decision in some particular cases. If
+ that happens, the user would have to change the code to call
+ mysql_master_query() or mysql_slave_query() explicitly in the place
+ where we have made the wrong decision
+*/
+enum mysql_rpl_type
+STDCALL mysql_rpl_query_type(const char* q, int len)
+{
+ const char* q_end;
+ q_end = (len) ? q + len : strend(q);
+ for(; q < q_end; ++q)
+ {
+ char c;
+ if (isalpha(c=*q))
+ switch(tolower(c))
+ {
+ case 'i': /* insert */
+ case 'u': /* update or unlock tables */
+ case 'l': /* lock tables or load data infile */
+ case 'd': /* drop or delete */
+ case 'a': /* alter */
+ return MYSQL_RPL_MASTER;
+ case 'c': /* create or check */
+ return tolower(q[1]) == 'h' ? MYSQL_RPL_ADMIN : MYSQL_RPL_MASTER ;
+ case 's': /* select or show */
+ return tolower(q[1]) == 'h' ? MYSQL_RPL_ADMIN : MYSQL_RPL_SLAVE;
+ case 'f': /* flush */
+ case 'r': /* repair */
+ case 'g': /* grant */
+ return MYSQL_RPL_ADMIN;
+ default:
+ return MYSQL_RPL_SLAVE;
+ }
+ }
+ return MYSQL_RPL_MASTER; /* By default, send to master */
+}
+
+
/****************************************************************************
** Init MySQL structure or allocate one
****************************************************************************/
@@ -1015,6 +1325,12 @@ mysql_init(MYSQL *mysql)
else
bzero((char*) (mysql),sizeof(*(mysql)));
mysql->options.connect_timeout=CONNECT_TIMEOUT;
+ mysql->last_used_con = mysql->next_slave = mysql->master = mysql;
+ mysql->last_used_slave = 0;
+ /* By default, we are a replication pivot. The caller must reset it
+ after we return if this is not the case.
+ */
+ mysql->rpl_pivot = 1;
#if defined(SIGPIPE) && defined(THREAD) && !defined(__WIN__)
if (!((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE))
(void) signal(SIGPIPE,pipe_sig_handler);
@@ -1074,63 +1390,65 @@ static void mysql_once_init()
#endif
}
-#ifdef HAVE_OPENSSL
/**************************************************************************
** Fill in SSL part of MYSQL structure and set 'use_ssl' flag.
** NB! Errors are not reported until you do mysql_real_connect.
**************************************************************************/
int STDCALL
-mysql_ssl_set(MYSQL *mysql, const char *key, const char *cert,
- const char *ca, const char *capath)
+mysql_ssl_set(MYSQL *mysql __attribute__((unused)) ,
+ const char *key __attribute__((unused)),
+ const char *cert __attribute__((unused)),
+ const char *ca __attribute__((unused)),
+ const char *capath __attribute__((unused)),
+ const char *cipher __attribute__((unused)))
{
+#ifdef HAVE_OPENSSL
mysql->options.ssl_key = key==0 ? 0 : my_strdup(key,MYF(0));
mysql->options.ssl_cert = cert==0 ? 0 : my_strdup(cert,MYF(0));
mysql->options.ssl_ca = ca==0 ? 0 : my_strdup(ca,MYF(0));
mysql->options.ssl_capath = capath==0 ? 0 : my_strdup(capath,MYF(0));
- mysql->options.use_ssl = true;
- mysql->connector_fd = new_VioSSLConnectorFd(key, cert, ca, capath);
+ mysql->options.ssl_cipher = cipher==0 ? 0 : my_strdup(cipher,MYF(0));
+ mysql->options.use_ssl = TRUE;
+ mysql->connector_fd = (gptr)new_VioSSLConnectorFd(key, cert, ca, capath, cipher);
+ DBUG_PRINT("info",("mysql_ssl_set, context: %p",((struct st_VioSSLConnectorFd *)(mysql->connector_fd))->ssl_context_));
+#endif
return 0;
}
-/**************************************************************************
-**************************************************************************/
-
-char * STDCALL
-mysql_ssl_cipher(MYSQL *mysql)
-{
- return (char *)mysql->net.vio->cipher_description();
-}
-
-
-/**************************************************************************
+/*
+***************************************************************************
** Free strings in the SSL structure and clear 'use_ssl' flag.
** NB! Errors are not reported until you do mysql_real_connect.
-**************************************************************************/
-
+**************************************************************************
+*/
int STDCALL
-mysql_ssl_clear(MYSQL *mysql)
+mysql_ssl_clear(MYSQL *mysql __attribute__((unused)))
{
+#ifdef HAVE_OPENSSL
my_free(mysql->options.ssl_key, MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->options.ssl_cert, MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->options.ssl_ca, MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->options.ssl_capath, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.ssl_cipher, MYF(MY_ALLOW_ZERO_PTR));
mysql->options.ssl_key = 0;
mysql->options.ssl_cert = 0;
mysql->options.ssl_ca = 0;
mysql->options.ssl_capath = 0;
- mysql->options.use_ssl = false;
- mysql->connector_fd->delete();
+ mysql->options.ssl_cipher= 0;
+ mysql->options.use_ssl = FALSE;
+ my_free(mysql->connector_fd,MYF(MY_ALLOW_ZERO_PTR));
mysql->connector_fd = 0;
+#endif /* HAVE_OPENSSL */
return 0;
}
-#endif /* HAVE_OPENSSL */
/**************************************************************************
** Connect to sql server
** If host == 0 then use localhost
**************************************************************************/
+#ifdef USE_OLD_FUNCTIONS
MYSQL * STDCALL
mysql_connect(MYSQL *mysql,const char *host,
const char *user, const char *passwd)
@@ -1147,6 +1465,7 @@ mysql_connect(MYSQL *mysql,const char *host,
DBUG_RETURN(res);
}
}
+#endif
/*
@@ -1164,7 +1483,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
my_socket sock;
uint32 ip_addr;
struct sockaddr_in sock_addr;
- uint pkt_length;
+ ulong pkt_length;
NET *net= &mysql->net;
#ifdef __WIN__
HANDLE hPipe=INVALID_HANDLE_VALUE;
@@ -1240,7 +1559,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
bzero((char*) &UNIXaddr,sizeof(UNIXaddr));
UNIXaddr.sun_family = AF_UNIX;
strmov(UNIXaddr.sun_path, unix_socket);
- if (connect2(sock,(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr),
+ if (my_connect(sock,(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr),
mysql->options.connect_timeout) <0)
{
DBUG_PRINT("error",("Got error %d on connect to local server",socket_errno));
@@ -1340,7 +1659,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
}
#endif
sock_addr.sin_port = (ushort) htons((ushort) port);
- if (connect2(sock,(struct sockaddr *) &sock_addr, sizeof(sock_addr),
+ if (my_connect(sock,(struct sockaddr *) &sock_addr, sizeof(sock_addr),
mysql->options.connect_timeout) <0)
{
DBUG_PRINT("error",("Got error %d on connect to '%s'",socket_errno,host));
@@ -1378,8 +1697,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
DBUG_DUMP("packet",(char*) net->read_pos,10);
DBUG_PRINT("info",("mysql protocol version %d, server=%d",
PROTOCOL_VERSION, mysql->protocol_version));
- if (mysql->protocol_version != PROTOCOL_VERSION &&
- mysql->protocol_version != PROTOCOL_VERSION-1)
+ if (mysql->protocol_version != PROTOCOL_VERSION)
{
net->last_errno= CR_VERSION_ERROR;
sprintf(net->last_error, ER(CR_VERSION_ERROR), mysql->protocol_version,
@@ -1415,7 +1733,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
charset_name=charset_name_buff;
sprintf(charset_name,"%d",mysql->server_language); /* In case of errors */
if (!(mysql->charset =
- get_charset((uint8) mysql->server_language, MYF(MY_WME))))
+ get_charset((uint8) mysql->server_language, MYF(0))))
mysql->charset = default_charset_info; /* shouldn't be fatal */
}
@@ -1513,11 +1831,9 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
goto error;
/* Do the SSL layering. */
DBUG_PRINT("info", ("IO layer change in progress..."));
- VioSSLConnectorFd* connector_fd = (VioSSLConnectorFd*)
- (mysql->connector_fd);
- VioSocket* vio_socket = (VioSocket*)(mysql->net.vio);
- VioSSL* vio_ssl = connector_fd->connect(vio_socket);
- mysql->net.vio = (NetVio*)(vio_ssl);
+ DBUG_PRINT("info", ("IO context %p",((struct st_VioSSLConnectorFd*)mysql->connector_fd)->ssl_context_));
+ sslconnect((struct st_VioSSLConnectorFd*)(mysql->connector_fd),mysql->net.vio, (long)(mysql->options.connect_timeout));
+ DBUG_PRINT("info", ("IO layer change done!"));
}
#endif /* HAVE_OPENSSL */
@@ -1542,7 +1858,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
mysql->db=my_strdup(db,MYF(MY_WME));
db=0;
}
- if (my_net_write(net,buff,(uint) (end-buff)) || net_flush(net) ||
+ if (my_net_write(net,buff,(ulong) (end-buff)) || net_flush(net) ||
net_safe_read(mysql) == packet_error)
goto error;
if (client_flag & CLIENT_COMPRESS) /* We will use compression */
@@ -1559,6 +1875,9 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
mysql->reconnect=reconnect;
}
+ if (mysql->options.rpl_probe && mysql_rpl_probe(mysql))
+ goto error;
+
DBUG_PRINT("exit",("Mysql handler: %lx",mysql));
reset_sigpipe(mysql);
DBUG_RETURN(mysql);
@@ -1577,6 +1896,23 @@ error:
DBUG_RETURN(0);
}
+/* needed when we move MYSQL structure to a different address */
+static void mysql_fix_pointers(MYSQL* mysql, MYSQL* old_mysql)
+{
+ MYSQL *tmp, *tmp_prev;
+ if (mysql->master == old_mysql)
+ mysql->master = mysql;
+ if (mysql->last_used_con == old_mysql)
+ mysql->last_used_con = mysql;
+ if (mysql->last_used_slave == old_mysql)
+ mysql->last_used_slave = mysql;
+ for (tmp_prev = mysql, tmp = mysql->next_slave;
+ tmp != old_mysql;tmp = tmp->next_slave)
+ {
+ tmp_prev = tmp;
+ }
+ tmp_prev->next_slave = mysql;
+}
static my_bool mysql_reconnect(MYSQL *mysql)
{
@@ -1586,13 +1922,14 @@ static my_bool mysql_reconnect(MYSQL *mysql)
if (!mysql->reconnect ||
(mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info)
{
- /* Allov reconnect next time */
+ /* Allow reconnect next time */
mysql->server_status&= ~SERVER_STATUS_IN_TRANS;
DBUG_RETURN(1);
}
mysql_init(&tmp_mysql);
tmp_mysql.options=mysql->options;
bzero((char*) &mysql->options,sizeof(mysql->options));
+ tmp_mysql.rpl_pivot = mysql->rpl_pivot;
if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd,
mysql->db, mysql->port, mysql->unix_socket,
mysql->client_flag))
@@ -1601,6 +1938,7 @@ static my_bool mysql_reconnect(MYSQL *mysql)
mysql->free_me=0;
mysql_close(mysql);
*mysql=tmp_mysql;
+ mysql_fix_pointers(mysql, &tmp_mysql); /* adjust connection pointers */
net_clear(&mysql->net);
mysql->affected_rows= ~(my_ulonglong) 0;
DBUG_RETURN(0);
@@ -1626,7 +1964,7 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
pos=scramble(pos, mysql->scramble_buff, passwd,
(my_bool) (mysql->protocol_version == 9));
pos=strmov(pos+1,db ? db : "");
- if (simple_command(mysql,COM_CHANGE_USER, buff,(uint) (pos-buff),0))
+ if (simple_command(mysql,COM_CHANGE_USER, buff,(ulong) (pos-buff),0))
DBUG_RETURN(1);
my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR));
@@ -1651,7 +1989,7 @@ mysql_select_db(MYSQL *mysql, const char *db)
DBUG_ENTER("mysql_select_db");
DBUG_PRINT("enter",("db: '%s'",db));
- if ((error=simple_command(mysql,COM_INIT_DB,db,(uint) strlen(db),0)))
+ if ((error=simple_command(mysql,COM_INIT_DB,db,(ulong) strlen(db),0)))
DBUG_RETURN(error);
my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR));
mysql->db=my_strdup(db,MYF(MY_WME));
@@ -1692,14 +2030,29 @@ mysql_close(MYSQL *mysql)
my_free(mysql->options.my_cnf_group,MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->options.charset_dir,MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->options.charset_name,MYF(MY_ALLOW_ZERO_PTR));
+#ifdef HAVE_OPENSSL
+ mysql_ssl_clear(mysql);
+#endif /* HAVE_OPENSSL */
/* Clear pointers for better safety */
mysql->host_info=mysql->user=mysql->passwd=mysql->db=0;
bzero((char*) &mysql->options,sizeof(mysql->options));
mysql->net.vio = 0;
-#ifdef HAVE_OPENSSL
- ((VioConnectorFd*)(mysql->connector_fd))->delete();
- mysql->connector_fd = 0;
-#endif /* HAVE_OPENSSL */
+
+ /* free/close slave list */
+ if (mysql->rpl_pivot)
+ {
+ MYSQL* tmp;
+ for (tmp = mysql->next_slave; tmp != mysql; )
+ {
+ /* trick to avoid following freed pointer */
+ MYSQL* tmp1 = tmp->next_slave;
+ mysql_close(tmp);
+ tmp = tmp1;
+ }
+ mysql->rpl_pivot=0;
+ }
+ if (mysql != mysql->master)
+ mysql_close(mysql->master);
if (mysql->free_me)
my_free((gptr) mysql,MYF(0));
}
@@ -1718,6 +2071,68 @@ mysql_query(MYSQL *mysql, const char *query)
return mysql_real_query(mysql,query, (uint) strlen(query));
}
+
+static MYSQL* spawn_init(MYSQL* parent, const char* host,
+ unsigned int port, const char* user,
+ const char* passwd)
+{
+ MYSQL* child;
+ if (!(child = mysql_init(0)))
+ return 0;
+
+ child->options.user = my_strdup((user) ? user :
+ (parent->user ? parent->user :
+ parent->options.user), MYF(0));
+ child->options.password = my_strdup((passwd) ? passwd :
+ (parent->passwd ?
+ parent->passwd :
+ parent->options.password), MYF(0));
+ child->options.port = port;
+ child->options.host = my_strdup((host) ? host :
+ (parent->host ?
+ parent->host :
+ parent->options.host), MYF(0));
+ if (parent->db)
+ child->options.db = my_strdup(parent->db, MYF(0));
+ else if (parent->options.db)
+ child->options.db = my_strdup(parent->options.db, MYF(0));
+
+ child->options.rpl_parse = child->options.rpl_probe = child->rpl_pivot = 0;
+
+ return child;
+}
+
+
+int
+STDCALL mysql_set_master(MYSQL* mysql, const char* host,
+ unsigned int port, const char* user,
+ const char* passwd)
+{
+ if (mysql->master != mysql && !mysql->master->rpl_pivot)
+ mysql_close(mysql->master);
+ if (!(mysql->master = spawn_init(mysql, host, port, user, passwd)))
+ return 1;
+ mysql->master->rpl_pivot = 0;
+ mysql->master->options.rpl_parse = 0;
+ mysql->master->options.rpl_probe = 0;
+ return 0;
+}
+
+int
+STDCALL mysql_add_slave(MYSQL* mysql, const char* host,
+ unsigned int port,
+ const char* user,
+ const char* passwd)
+{
+ MYSQL* slave;
+ if (!(slave = spawn_init(mysql, host, port, user, passwd)))
+ return 1;
+ slave->next_slave = mysql->next_slave;
+ mysql->next_slave = slave;
+ return 0;
+}
+
+
/*
Send the query and return so we can do something else.
Needs to be followed by mysql_read_query_result() when we want to
@@ -1725,19 +2140,38 @@ mysql_query(MYSQL *mysql, const char *query)
*/
int STDCALL
-mysql_send_query(MYSQL* mysql, const char* query, uint length)
+mysql_send_query(MYSQL* mysql, const char* query, ulong length)
{
+ if (mysql->options.rpl_parse && mysql->rpl_pivot)
+ {
+ switch (mysql_rpl_query_type(query, length)) {
+ case MYSQL_RPL_MASTER:
+ return mysql_master_send_query(mysql, query, length);
+ case MYSQL_RPL_SLAVE:
+ return mysql_slave_send_query(mysql, query, length);
+ case MYSQL_RPL_ADMIN:
+ break; /* fall through */
+ }
+ }
+
+ mysql->last_used_con = mysql;
return simple_command(mysql, COM_QUERY, query, length, 1);
}
+
int STDCALL mysql_read_query_result(MYSQL *mysql)
{
uchar *pos;
ulong field_count;
MYSQL_DATA *fields;
- uint length;
+ ulong length;
DBUG_ENTER("mysql_read_query_result");
+ /* read from the connection which we actually used, which
+ could differ from the original connection if we have slaves
+ */
+ mysql = mysql->last_used_con;
+
if ((length = net_safe_read(mysql)) == packet_error)
DBUG_RETURN(-1);
free_old_query(mysql); /* Free old result */
@@ -1774,74 +2208,80 @@ get_info:
CLIENT_LONG_FLAG))))
DBUG_RETURN(-1);
mysql->status=MYSQL_STATUS_GET_RESULT;
- mysql->field_count=field_count;
+ mysql->field_count= (uint) field_count;
DBUG_RETURN(0);
}
+
int STDCALL
-mysql_real_query(MYSQL *mysql, const char *query, uint length)
+mysql_real_query(MYSQL *mysql, const char *query, ulong length)
{
DBUG_ENTER("mysql_real_query");
DBUG_PRINT("enter",("handle: %lx",mysql));
DBUG_PRINT("query",("Query = \"%s\"",query));
- if (simple_command(mysql,COM_QUERY,query,length,1))
+
+ if (mysql_send_query(mysql,query,length))
DBUG_RETURN(-1);
DBUG_RETURN(mysql_read_query_result(mysql));
}
+
static int
send_file_to_server(MYSQL *mysql, const char *filename)
{
- int fd, readcount;
- char buf[IO_SIZE*15],*tmp_name;
+ int fd, readcount, result= -1;
+ uint packet_length=MY_ALIGN(mysql->net.max_packet-16,IO_SIZE);
+ char *buf, tmp_name[FN_REFLEN];
DBUG_ENTER("send_file_to_server");
- fn_format(buf,filename,"","",4); /* Convert to client format */
- if (!(tmp_name=my_strdup(buf,MYF(0))))
+ if (!(buf=my_malloc(packet_length,MYF(0))))
{
strmov(mysql->net.last_error, ER(mysql->net.last_errno=CR_OUT_OF_MEMORY));
DBUG_RETURN(-1);
}
+
+ fn_format(tmp_name,filename,"","",4); /* Convert to client format */
if ((fd = my_open(tmp_name,O_RDONLY, MYF(0))) < 0)
{
+ my_net_write(&mysql->net,"",0); /* Server needs one packet */
+ net_flush(&mysql->net);
mysql->net.last_errno=EE_FILENOTFOUND;
- sprintf(buf,EE(mysql->net.last_errno),tmp_name,errno);
- strmake(mysql->net.last_error,buf,sizeof(mysql->net.last_error)-1);
- my_net_write(&mysql->net,"",0); net_flush(&mysql->net);
- my_free(tmp_name,MYF(0));
- DBUG_RETURN(-1);
+ my_snprintf(mysql->net.last_error,sizeof(mysql->net.last_error)-1,
+ EE(mysql->net.last_errno),tmp_name, errno);
+ goto err;
}
- while ((readcount = (int) my_read(fd,buf,sizeof(buf),MYF(0))) > 0)
+ while ((readcount = (int) my_read(fd,(byte*) buf,packet_length,MYF(0))) > 0)
{
if (my_net_write(&mysql->net,buf,readcount))
{
+ DBUG_PRINT("error",("Lost connection to MySQL server during LOAD DATA of local file"));
mysql->net.last_errno=CR_SERVER_LOST;
strmov(mysql->net.last_error,ER(mysql->net.last_errno));
- DBUG_PRINT("error",("Lost connection to MySQL server during LOAD DATA of local file"));
- (void) my_close(fd,MYF(0));
- my_free(tmp_name,MYF(0));
- DBUG_RETURN(-1);
+ goto err;
}
}
- (void) my_close(fd,MYF(0));
/* Send empty packet to mark end of file */
if (my_net_write(&mysql->net,"",0) || net_flush(&mysql->net))
{
mysql->net.last_errno=CR_SERVER_LOST;
- sprintf(mysql->net.last_error,ER(mysql->net.last_errno),socket_errno);
- my_free(tmp_name,MYF(0));
- DBUG_RETURN(-1);
+ sprintf(mysql->net.last_error,ER(mysql->net.last_errno),errno);
+ goto err;
}
if (readcount < 0)
{
mysql->net.last_errno=EE_READ; /* the errmsg for not entire file read */
- sprintf(buf,EE(mysql->net.last_errno),tmp_name,errno);
- strmake(mysql->net.last_error,buf,sizeof(mysql->net.last_error)-1);
- my_free(tmp_name,MYF(0));
- DBUG_RETURN(-1);
+ my_snprintf(mysql->net.last_error,sizeof(mysql->net.last_error)-1,
+ tmp_name,errno);
+ goto err;
}
- DBUG_RETURN(0);
+ result=0; /* Ok */
+
+err:
+ if (fd >= 0)
+ (void) my_close(fd,MYF(0));
+ my_free(buf,MYF(0));
+ DBUG_RETURN(result);
}
@@ -1856,6 +2296,9 @@ mysql_store_result(MYSQL *mysql)
MYSQL_RES *result;
DBUG_ENTER("mysql_store_result");
+ /* read from the actually used connection */
+ mysql = mysql->last_used_con;
+
if (!mysql->fields)
DBUG_RETURN(0);
if (mysql->status != MYSQL_STATUS_GET_RESULT)
@@ -1865,8 +2308,9 @@ mysql_store_result(MYSQL *mysql)
DBUG_RETURN(0);
}
mysql->status=MYSQL_STATUS_READY; /* server is ready */
- if (!(result=(MYSQL_RES*) my_malloc(sizeof(MYSQL_RES)+
- sizeof(ulong)*mysql->field_count,
+ if (!(result=(MYSQL_RES*) my_malloc((uint) (sizeof(MYSQL_RES)+
+ sizeof(ulong) *
+ mysql->field_count),
MYF(MY_WME | MY_ZEROFILL))))
{
mysql->net.last_errno=CR_OUT_OF_MEMORY;
@@ -1908,6 +2352,8 @@ mysql_use_result(MYSQL *mysql)
MYSQL_RES *result;
DBUG_ENTER("mysql_use_result");
+ mysql = mysql->last_used_con;
+
if (!mysql->fields)
DBUG_RETURN(0);
if (mysql->status != MYSQL_STATUS_GET_RESULT)
@@ -2022,7 +2468,7 @@ mysql_fetch_lengths(MYSQL_RES *res)
continue;
}
if (start) /* Found end of prev string */
- *prev_length= (uint) (*column-start-1);
+ *prev_length= (ulong) (*column-start-1);
start= *column;
prev_length=lengths;
}
@@ -2123,7 +2569,7 @@ mysql_list_fields(MYSQL *mysql, const char *table, const char *wild)
LINT_INIT(query);
end=strmake(strmake(buff, table,128)+1,wild ? wild : "",128);
- if (simple_command(mysql,COM_FIELD_LIST,buff,(uint) (end-buff),1) ||
+ if (simple_command(mysql,COM_FIELD_LIST,buff,(ulong) (end-buff),1) ||
!(query = read_rows(mysql,(MYSQL_FIELD*) 0,6)))
DBUG_RETURN(NULL);
@@ -2173,12 +2619,13 @@ mysql_list_processes(MYSQL *mysql)
}
+#ifdef USE_OLD_FUNCTIONS
int STDCALL
mysql_create_db(MYSQL *mysql, const char *db)
{
DBUG_ENTER("mysql_createdb");
DBUG_PRINT("enter",("db: %s",db));
- DBUG_RETURN(simple_command(mysql,COM_CREATE_DB,db, (uint) strlen(db),0));
+ DBUG_RETURN(simple_command(mysql,COM_CREATE_DB,db, (ulong) strlen(db),0));
}
@@ -2187,8 +2634,9 @@ mysql_drop_db(MYSQL *mysql, const char *db)
{
DBUG_ENTER("mysql_drop_db");
DBUG_PRINT("enter",("db: %s",db));
- DBUG_RETURN(simple_command(mysql,COM_DROP_DB,db,(uint) strlen(db),0));
+ DBUG_RETURN(simple_command(mysql,COM_DROP_DB,db,(ulong) strlen(db),0));
}
+#endif
int STDCALL
@@ -2369,32 +2817,32 @@ uint STDCALL mysql_field_tell(MYSQL_RES *res)
unsigned int STDCALL mysql_field_count(MYSQL *mysql)
{
- return mysql->field_count;
+ return mysql->last_used_con->field_count;
}
my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql)
{
- return (mysql)->affected_rows;
+ return mysql->last_used_con->affected_rows;
}
my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql)
{
- return (mysql)->insert_id;
+ return mysql->last_used_con->insert_id;
}
uint STDCALL mysql_errno(MYSQL *mysql)
{
- return (mysql)->net.last_errno;
+ return mysql->net.last_errno;
}
char * STDCALL mysql_error(MYSQL *mysql)
{
- return (mysql)->net.last_error;
+ return mysql->net.last_error;
}
char *STDCALL mysql_info(MYSQL *mysql)
{
- return (mysql)->info;
+ return mysql->info;
}
ulong STDCALL mysql_thread_id(MYSQL *mysql)
diff --git a/libmysql/libmysql.def b/libmysql/libmysql.def
new file mode 100644
index 00000000000..9405ecd58ff
--- /dev/null
+++ b/libmysql/libmysql.def
@@ -0,0 +1,122 @@
+LIBRARY LIBMYSQL
+DESCRIPTION 'MySQL 4.0 Client Library'
+VERSION 4.0
+EXPORTS
+ mysql_affected_rows
+ mysql_close
+ mysql_connect
+ mysql_create_db
+ mysql_data_seek
+ mysql_debug
+ mysql_drop_db
+ mysql_dump_debug_info
+ mysql_eof
+ mysql_errno
+ mysql_error
+ mysql_escape_string
+ mysql_fetch_field
+ mysql_fetch_field_direct
+ mysql_fetch_fields
+ mysql_fetch_lengths
+ mysql_fetch_row
+ mysql_field_count
+ mysql_field_seek
+ mysql_field_tell
+ mysql_free_result
+ mysql_get_client_info
+ mysql_get_host_info
+ mysql_get_proto_info
+ mysql_get_server_info
+ mysql_info
+ mysql_init
+ mysql_insert_id
+ mysql_kill
+ mysql_list_dbs
+ mysql_list_fields
+ mysql_list_processes
+ mysql_list_tables
+ mysql_num_fields
+ mysql_num_rows
+ mysql_odbc_escape_string
+ mysql_options
+ mysql_ping
+ mysql_query
+ mysql_real_connect
+ mysql_real_query
+ mysql_refresh
+ mysql_row_seek
+ mysql_row_tell
+ mysql_select_db
+ mysql_shutdown
+ mysql_stat
+ mysql_store_result
+ mysql_thread_id
+ mysql_use_result
+ bmove_upp
+ delete_dynamic
+ _dig_vec
+ init_dynamic_array
+ insert_dynamic
+ int2str
+ is_prefix
+ list_add
+ list_delete
+ max_allowed_packet
+ my_casecmp
+ my_init
+ my_end
+ my_strdup
+ my_malloc
+ my_memdup
+ my_no_flags_free
+ my_realloc
+ my_thread_end
+ my_thread_init
+ net_buffer_length
+ set_dynamic
+ strcend
+ strdup_root
+ strfill
+ strinstr
+ strmake
+ strmov
+ strxmov
+ myodbc_remove_escape
+ mysql_thread_safe
+ mysql_character_set_name
+ mysql_change_user
+ mysql_send_query
+ mysql_read_query_result
+ mysql_real_escape_string
+ mysql_ssl_set
+ mysql_ssl_clear
+ mysql_real_connect
+ mysql_master_query
+ mysql_master_send_query
+ mysql_slave_query
+ mysql_slave_send_query
+ mysql_enable_rpl_parse
+ mysql_disable_rpl_parse
+ mysql_rpl_parse_enabled
+ mysql_enable_reads_from_master
+ mysql_disable_reads_from_master
+ mysql_reads_from_master_enabled
+ mysql_rpl_query_type
+ mysql_rpl_probe
+ mysql_set_master
+ mysql_add_slave
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libmysql/manager.c b/libmysql/manager.c
new file mode 100644
index 00000000000..fbf0a0b2c22
--- /dev/null
+++ b/libmysql/manager.c
@@ -0,0 +1,273 @@
+/* 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 */
+
+#include <my_global.h>
+#if defined(THREAD)
+#include <my_pthread.h> /* because of signal() */
+#endif
+#include "mysql.h"
+#include "mysql_version.h"
+#include "mysqld_error.h"
+#include <my_sys.h>
+#include <mysys_err.h>
+#include <m_string.h>
+#include <m_ctype.h>
+#include <my_net.h>
+#include <errmsg.h>
+#include <violite.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <errno.h>
+
+#if defined(OS2)
+# include <sys/un.h>
+#elif !defined( __WIN__)
+#include <sys/resource.h>
+#ifdef HAVE_SYS_UN_H
+# include <sys/un.h>
+#endif
+#include <netdb.h>
+#ifdef HAVE_SELECT_H
+# include <select.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#include <sys/utsname.h>
+#endif /* __WIN__ */
+
+#ifndef INADDR_NONE
+#define INADDR_NONE -1
+#endif
+
+#define RES_BUF_SHIFT 5
+#ifndef __WIN__
+#define SOCKET_ERROR -1
+#endif
+#define NET_BUF_SIZE 2048
+
+MYSQL_MANAGER* STDCALL mysql_manager_init(MYSQL_MANAGER* con)
+{
+ int net_buf_size=NET_BUF_SIZE;
+ if (!con)
+ {
+ if (!(con=(MYSQL_MANAGER*)my_malloc(sizeof(*con)+net_buf_size,
+ MYF(MY_WME|MY_ZEROFILL))))
+ return 0;
+ con->free_me=1;
+ con->net_buf=(char*)con+sizeof(*con);
+ }
+ else
+ {
+ bzero((char*)con,sizeof(*con));
+ if (!(con->net_buf=my_malloc(net_buf_size,MYF(0))))
+ return 0;
+ }
+ con->net_buf_pos=con->net_data_end=con->net_buf;
+ con->net_buf_size=net_buf_size;
+ return con;
+}
+
+MYSQL_MANAGER* STDCALL mysql_manager_connect(MYSQL_MANAGER* con,
+ const char* host,
+ const char* user,
+ const char* passwd,
+ unsigned int port)
+{
+ my_socket sock;
+ struct sockaddr_in sock_addr;
+ uint32 ip_addr;
+ char msg_buf[MAX_MYSQL_MANAGER_MSG];
+ int msg_len;
+ Vio* vio;
+
+ if (!host)
+ host="localhost";
+ if (!user)
+ user="root";
+ if (!passwd)
+ passwd="";
+
+ if ((sock=(my_socket)socket(AF_INET,SOCK_STREAM,0)) == SOCKET_ERROR)
+ {
+ con->last_errno=errno;
+ strmov(con->last_error,"Cannot create socket");
+ goto err;
+ }
+ if (!(vio=vio_new(sock,VIO_TYPE_TCPIP,FALSE)))
+ {
+ con->last_errno=ENOMEM;
+ strmov(con->last_error,"Cannot create network I/O object");
+ goto err;
+ }
+ vio_blocking(vio,TRUE);
+ my_net_init(&con->net,vio);
+ bzero((char*) &sock_addr,sizeof(sock_addr));
+ sock_addr.sin_family = AF_INET;
+ if ((int) (ip_addr = inet_addr(host)) != (int) INADDR_NONE)
+ {
+ memcpy_fixed(&sock_addr.sin_addr,&ip_addr,sizeof(ip_addr));
+ }
+ else
+#if defined(HAVE_GETHOSTBYNAME_R) && defined(_REENTRANT) && defined(THREAD)
+ {
+ int tmp_errno;
+ struct hostent tmp_hostent,*hp;
+ char buff2[GETHOSTBYNAME_BUFF_SIZE];
+ hp = my_gethostbyname_r(host,&tmp_hostent,buff2,sizeof(buff2),
+ &tmp_errno);
+ if (!hp)
+ {
+ con->last_errno=tmp_errno;
+ sprintf(con->last_error,"Could not resolve host '%s'",host);
+ goto err;
+ }
+ memcpy(&sock_addr.sin_addr,hp->h_addr, (size_t) hp->h_length);
+ }
+#else
+ {
+ struct hostent *hp;
+ if (!(hp=gethostbyname(host)))
+ {
+ con->last_errno=socket_errno;
+ sprintf(con->last_error, "Could not resolve host '%s'", host);
+ goto err;
+ }
+ memcpy(&sock_addr.sin_addr,hp->h_addr, (size_t) hp->h_length);
+ }
+#endif
+ sock_addr.sin_port = (ushort) htons((ushort) port);
+ if (my_connect(sock,(struct sockaddr *) &sock_addr, sizeof(sock_addr),
+ 0) <0)
+ {
+ con->last_errno=errno;
+ sprintf(con->last_error ,"Could not connect to %-.64s", host);
+ goto err;
+ }
+ /* read the greating */
+ if (my_net_read(&con->net) == packet_error)
+ {
+ con->last_errno=errno;
+ strmov(con->last_error,"Read error on socket");
+ goto err;
+ }
+ sprintf(msg_buf,"%-.16s %-.16s\n",user,passwd);
+ msg_len=strlen(msg_buf);
+ if (my_net_write(&con->net,msg_buf,msg_len) || net_flush(&con->net))
+ {
+ con->last_errno=con->net.last_errno;
+ strmov(con->last_error,"Write error on socket");
+ goto err;
+ }
+ if (my_net_read(&con->net) == packet_error)
+ {
+ con->last_errno=errno;
+ strmov(con->last_error,"Read error on socket");
+ goto err;
+ }
+ if ((con->cmd_status=atoi((char*) con->net.read_pos)) != MANAGER_OK)
+ {
+ strmov(con->last_error,"Access denied");
+ goto err;
+ }
+ if (!my_multi_malloc(MYF(0), &con->host, (uint)strlen(host)+1,
+ &con->user, (uint)strlen(user)+1,
+ &con->passwd, (uint)strlen(passwd)+1,
+ NullS))
+ {
+ con->last_errno=ENOMEM;
+ strmov(con->last_error,"Out of memory");
+ goto err;
+ }
+ strmov(con->host,host);
+ strmov(con->user,user);
+ strmov(con->passwd,passwd);
+ return con;
+err:
+ {
+ my_bool free_me=con->free_me;
+ con->free_me=0;
+ mysql_manager_close(con);
+ con->free_me=free_me;
+ }
+ return 0;
+}
+
+void STDCALL mysql_manager_close(MYSQL_MANAGER* con)
+{
+ my_free((gptr)con->host,MYF(MY_ALLOW_ZERO_PTR));
+ /* no need to free con->user and con->passwd, because they were
+ allocated in my_multimalloc() along with con->host, freeing
+ con->hosts frees the whole block
+ */
+ net_end(&con->net);
+ if (con->free_me)
+ my_free((gptr)con,MYF(0));
+}
+
+int STDCALL mysql_manager_command(MYSQL_MANAGER* con,const char* cmd,
+ int cmd_len)
+{
+ if (!cmd_len)
+ cmd_len=strlen(cmd);
+ if (my_net_write(&con->net,(char*)cmd,cmd_len) || net_flush(&con->net))
+ {
+ con->last_errno=errno;
+ strmov(con->last_error,"Write error on socket");
+ return 1;
+ }
+ con->eof=0;
+ return 0;
+}
+
+int STDCALL mysql_manager_fetch_line(MYSQL_MANAGER* con, char* res_buf,
+ int res_buf_size)
+{
+ char* res_buf_end=res_buf+res_buf_size;
+ char* net_buf=(char*) con->net.read_pos, *net_buf_end;
+ int res_buf_shift=RES_BUF_SHIFT;
+ uint num_bytes;
+
+ if (res_buf_size<RES_BUF_SHIFT)
+ {
+ con->last_errno=ENOMEM;
+ strmov(con->last_error,"Result buffer too small");
+ return 1;
+ }
+
+ if ((num_bytes=my_net_read(&con->net)) == packet_error)
+ {
+ con->last_errno=errno;
+ strmov(con->last_error,"socket read failed");
+ return 1;
+ }
+
+ net_buf_end=net_buf+num_bytes;
+
+ if ((con->eof=(net_buf[3]==' ')))
+ res_buf_shift--;
+ net_buf+=res_buf_shift;
+ res_buf_end[-1]=0;
+ for (;net_buf<net_buf_end && res_buf < res_buf_end;res_buf++,net_buf++)
+ {
+ if((*res_buf=*net_buf) == '\r')
+ {
+ *res_buf=0;
+ break;
+ }
+ }
+ return 0;
+}
diff --git a/libmysql/net.c b/libmysql/net.c
index 24e4da3561a..666c572ccee 100644
--- a/libmysql/net.c
+++ b/libmysql/net.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 and read of logical packets to/from socket
** Writes are cached into net_buffer_length big packets.
@@ -22,19 +21,34 @@
** 3 byte length & 1 byte package-number.
*/
+#ifdef EMBEDDED_LIBRARY
+#define net_read_timeout net_read_timeout1
+#define net_write_timeout net_write_timeout1
+#endif
+
#ifdef __WIN__
#include <winsock.h>
#endif
-#include <global.h>
-#include <violite.h>
+#include <my_global.h>
+#include <mysql.h>
+#include <mysql_embed.h>
+#include <mysql_com.h>
+#include <mysqld_error.h>
#include <my_sys.h>
#include <m_string.h>
-#include "mysql.h"
-#include "mysqld_error.h"
+#include <my_net.h>
+#include <violite.h>
#include <signal.h>
#include <errno.h>
-#include <sys/types.h>
-#include <violite.h>
+
+/*
+ The following handles the differences when this is linked between the
+ client and the server.
+
+ This gives an error if a too big packet is found
+ The server can change this with the -O switch, but because the client
+ can't normally do this the client should have a bigger max_allowed_packet.
+*/
#ifdef MYSQL_SERVER
ulong max_allowed_packet=65536;
@@ -45,73 +59,45 @@ ulong max_allowed_packet=16*1024*1024L;
ulong net_read_timeout= NET_READ_TIMEOUT;
ulong net_write_timeout= NET_WRITE_TIMEOUT;
#endif
-ulong net_buffer_length=8192; /* Default length. Enlarged if necessary */
-#if !defined(__WIN__) && !defined(MSDOS)
-#include <sys/socket.h>
-#else
-#undef MYSQL_SERVER /* Win32 can't handle interrupts */
-#endif
-#if !defined(MSDOS) && !defined(__WIN__) && !defined(HAVE_BROKEN_NETINET_INCLUDES) && !defined(__BEOS__)
-#include <netinet/in_systm.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#if !defined(alpha_linux_port)
-#include <netinet/tcp.h>
-#endif
+#ifdef __WIN__
+/* The following is because alarms doesn't work on windows. */
+#undef MYSQL_SERVER
#endif
-#include "mysqld_error.h"
+
#ifdef MYSQL_SERVER
#include "my_pthread.h"
-#include "thr_alarm.h"
void sql_print_error(const char *format,...);
#define RETRY_COUNT mysqld_net_retry_count
extern ulong mysqld_net_retry_count;
-#else
-
-#ifdef OS2 /* avoid name conflict */
-#define thr_alarm_t thr_alarm_t_net
-#define ALARM ALARM_net
-#endif
-
-typedef my_bool thr_alarm_t;
-typedef my_bool ALARM;
-#define thr_alarm_init(A) (*(A))=0
-#define thr_alarm_in_use(A) (*(A)!= 0)
-#define thr_end_alarm(A)
-#define thr_alarm(A,B,C) local_thr_alarm((A),(B),(C))
-inline int local_thr_alarm(my_bool *A,int B __attribute__((unused)),ALARM *C __attribute__((unused)))
-{
- *A=1;
- return 0;
-}
-#define thr_got_alarm(A) 0
-#define RETRY_COUNT 1
-#endif
-
-#ifdef MYSQL_SERVER
-extern ulong bytes_sent, bytes_received;
+extern ulong bytes_sent, bytes_received;
extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
+
+extern void query_cache_insert(NET *net, const char *packet, ulong length);
#else
#undef statistic_add
#define statistic_add(A,B,C)
-#endif
+#define DONT_USE_THR_ALARM
+#define RETRY_COUNT 1
+#endif /* MYSQL_SERVER */
-/*
-** Give error if a too big packet is found
-** The server can change this with the -O switch, but because the client
-** can't normally do this the client should have a bigger max-buffer.
-*/
+#include "thr_alarm.h"
#define TEST_BLOCKING 8
-static int net_write_buff(NET *net,const char *packet,uint len);
+#define MAX_THREE_BYTES 255L*255L*255L
+
+ulong net_buffer_length=8192; /* Default length. Enlarged if necessary */
+
+static int net_write_buff(NET *net,const char *packet,ulong len);
/* Init with packet info */
int my_net_init(NET *net, Vio* vio)
{
- if (!(net->buff=(uchar*) my_malloc(net_buffer_length,MYF(MY_WME))))
+ if (!(net->buff=(uchar*) my_malloc((uint32) net_buffer_length+
+ NET_HEADER_SIZE + COMP_HEADER_SIZE,
+ MYF(MY_WME))))
return 1;
if (net_buffer_length > max_allowed_packet)
max_allowed_packet=net_buffer_length;
@@ -120,12 +106,13 @@ int my_net_init(NET *net, Vio* vio)
net->no_send_ok = 0;
net->error=0; net->return_errno=0; net->return_status=0;
net->timeout=(uint) net_read_timeout; /* Timeout for read */
- net->pkt_nr=0;
+ net->pkt_nr=net->compress_pkt_nr=0;
net->write_pos=net->read_pos = net->buff;
net->last_error[0]=0;
net->compress=0; net->reading_or_writing=0;
net->where_b = net->remain_in_buf=0;
net->last_errno=0;
+ net->query_cache_query=0;
if (vio != 0) /* If real connection */
{
@@ -158,8 +145,12 @@ static my_bool net_realloc(NET *net, ulong length)
net->last_errno=ER_NET_PACKET_TOO_LARGE;
return 1;
}
- pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
- if (!(buff=(uchar*) my_realloc((char*) net->buff, pkt_length, MYF(MY_WME))))
+ pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
+ /* We must allocate some extra bytes for the end 0 and to be able to
+ read big compressed blocks */
+ if (!(buff=(uchar*) my_realloc((char*) net->buff, (uint32) pkt_length +
+ NET_HEADER_SIZE + COMP_HEADER_SIZE,
+ MYF(MY_WME))))
{
net->error=1;
#ifdef MYSQL_SERVER
@@ -177,21 +168,21 @@ static my_bool net_realloc(NET *net, ulong length)
void net_clear(NET *net)
{
#ifndef EXTRA_DEBUG
- int count;
+ int count; /* One may get 'unused' warn */
bool is_blocking=vio_is_blocking(net->vio);
if (is_blocking)
vio_blocking(net->vio, FALSE);
if (!vio_is_blocking(net->vio)) /* Safety if SSL */
{
while ( (count = vio_read(net->vio, (char*) (net->buff),
- net->max_packet)) > 0)
+ (uint32) net->max_packet)) > 0)
DBUG_PRINT("info",("skipped %d bytes from file: %s",
count,vio_description(net->vio)));
if (is_blocking)
vio_blocking(net->vio, TRUE);
}
#endif /* EXTRA_DEBUG */
- net->pkt_nr=0; /* Ready for new command */
+ net->pkt_nr=net->compress_pkt_nr=0; /* Ready for new command */
net->write_pos=net->buff;
}
@@ -204,9 +195,12 @@ int net_flush(NET *net)
if (net->buff != net->write_pos)
{
error=net_real_write(net,(char*) net->buff,
- (uint) (net->write_pos - net->buff));
+ (ulong) (net->write_pos - net->buff));
net->write_pos=net->buff;
}
+ /* Sync packet number if using compression */
+ if (net->compress)
+ net->pkt_nr=net->compress_pkt_nr;
DBUG_RETURN(error);
}
@@ -215,44 +209,91 @@ int net_flush(NET *net)
** Write something to server/client buffer
*****************************************************************************/
-
/*
** Write a logical packet with packet header
** Format: Packet length (3 bytes), packet number(1 byte)
** When compression is used a 3 byte compression length is added
-** NOTE: If compression is used the original package is destroyed!
+** NOTE: If compression is used the original package is modified!
*/
int
my_net_write(NET *net,const char *packet,ulong len)
{
uchar buff[NET_HEADER_SIZE];
+ /*
+ Big packets are handled by splitting them in packets of MAX_THREE_BYTES
+ length. The last packet is always a packet that is < MAX_THREE_BYTES.
+ (The last packet may even have a lengt of 0)
+ */
+ while (len >= MAX_THREE_BYTES)
+ {
+ const ulong z_size = MAX_THREE_BYTES;
+ int3store(buff, z_size);
+ buff[3]= (uchar) net->pkt_nr++;
+ if (net_write_buff(net, (char*) buff, NET_HEADER_SIZE) ||
+ net_write_buff(net, packet, z_size))
+ return 1;
+ packet += z_size;
+ len-= z_size;
+ }
+ /* Write last packet */
int3store(buff,len);
- buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
+ buff[3]= (uchar) net->pkt_nr++;
if (net_write_buff(net,(char*) buff,NET_HEADER_SIZE))
return 1;
return net_write_buff(net,packet,len);
}
+/*
+ Send a command to the server.
+ As the command is part of the first data packet, we have to do some data
+ juggling to put the command in there, without having to create a new
+ packet.
+ This function will split big packets into sub-packets if needed.
+ (Each sub packet can only be 2^24 bytes)
+*/
+
int
net_write_command(NET *net,uchar command,const char *packet,ulong len)
{
+ ulong length=len+1; /* 1 extra byte for command */
uchar buff[NET_HEADER_SIZE+1];
- uint length=len+1; /* 1 extra byte for command */
+ uint header_size=NET_HEADER_SIZE+1;
+ buff[4]=command; /* For first packet */
+ if (length >= MAX_THREE_BYTES)
+ {
+ /* Take into account that we have the command in the first header */
+ len= MAX_THREE_BYTES -1;
+ do
+ {
+ int3store(buff, MAX_THREE_BYTES);
+ buff[3]= (uchar) net->pkt_nr++;
+ if (net_write_buff(net,(char*) buff, header_size) ||
+ net_write_buff(net,packet,len))
+ return 1;
+ packet+= len;
+ length-= MAX_THREE_BYTES;
+ len=MAX_THREE_BYTES;
+ header_size=NET_HEADER_SIZE;
+ } while (length >= MAX_THREE_BYTES);
+ len=length; /* Data left to be written */
+ }
int3store(buff,length);
- buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
- buff[4]=command;
- if (net_write_buff(net,(char*) buff,5))
- return 1;
- return test(net_write_buff(net,packet,len) || net_flush(net));
+ buff[3]= (uchar) net->pkt_nr++;
+ return test(net_write_buff(net,(char*) buff,header_size) ||
+ net_write_buff(net,packet,len) || net_flush(net));
}
+/*
+ Caching the data in a local buffer before sending it.
+ One can force the buffer to be flushed with 'net_flush'.
+*/
static int
-net_write_buff(NET *net,const char *packet,uint len)
+net_write_buff(NET *net,const char *packet,ulong len)
{
- uint left_length=(uint) (net->buff_end - net->write_pos);
+ ulong left_length=(ulong) (net->buff_end - net->write_pos);
while (len > left_length)
{
@@ -269,21 +310,29 @@ net_write_buff(NET *net,const char *packet,uint len)
return 0;
}
-/* Read and write using timeouts */
+
+/*
+ Read and write one packet using timeouts.
+ If needed, the packet is compressed before sending.
+*/
int
net_real_write(NET *net,const char *packet,ulong len)
{
- int length;
+ long int length;
char *pos,*end;
thr_alarm_t alarmed;
-#if !defined(__WIN__) && !defined(__EMX__) && !defined(OS2)
+#if defined(MYSQL_SERVER)
ALARM alarm_buff;
#endif
uint retry_count=0;
my_bool net_blocking = vio_is_blocking(net->vio);
DBUG_ENTER("net_real_write");
+#ifdef MYSQL_SERVER
+ query_cache_insert(net, packet, len);
+#endif
+
if (net->error == 2)
DBUG_RETURN(-1); /* socket can't be used */
@@ -294,8 +343,8 @@ net_real_write(NET *net,const char *packet,ulong len)
ulong complen;
uchar *b;
uint header_length=NET_HEADER_SIZE+COMP_HEADER_SIZE;
- if (!(b=(uchar*) my_malloc(len + NET_HEADER_SIZE + COMP_HEADER_SIZE,
- MYF(MY_WME))))
+ if (!(b=(uchar*) my_malloc((uint32) len + NET_HEADER_SIZE +
+ COMP_HEADER_SIZE, MYF(MY_WME))))
{
#ifdef MYSQL_SERVER
net->last_errno=ER_OUT_OF_RESOURCES;
@@ -314,7 +363,7 @@ net_real_write(NET *net,const char *packet,ulong len)
}
int3store(&b[NET_HEADER_SIZE],complen);
int3store(b,len);
- b[3]=(uchar) (net->pkt_nr++);
+ b[3]=(uchar) (net->compress_pkt_nr++);
len+= header_length;
packet= (char*) b;
}
@@ -332,7 +381,7 @@ net_real_write(NET *net,const char *packet,ulong len)
pos=(char*) packet; end=pos+len;
while (pos != end)
{
- if ((int) (length=vio_write(net->vio,pos,(int) (end-pos))) <= 0)
+ if ((long) (length=vio_write(net->vio,pos,(uint32) (end-pos))) <= 0)
{
my_bool interrupted = vio_should_retry(net->vio);
#if (!defined(__WIN__) && !defined(__EMX__) && !defined(OS2))
@@ -416,7 +465,7 @@ net_real_write(NET *net,const char *packet,ulong len)
big packet
*/
-static void my_net_skip_rest(NET *net, ulong remain, thr_alarm_t *alarmed)
+static void my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed)
{
ALARM alarm_buff;
uint retry_count=0;
@@ -432,21 +481,27 @@ static void my_net_skip_rest(NET *net, ulong remain, thr_alarm_t *alarmed)
if ((int) (length=vio_read(net->vio,(char*) net->buff,remain)) <= 0L)
{
my_bool interrupted = vio_should_retry(net->vio);
- if (!thr_got_alarm(alarmed) && interrupted)
+ if (!thr_got_alarm(&alarmed) && interrupted)
{ /* Probably in MIT threads */
if (retry_count++ < RETRY_COUNT)
continue;
}
return;
}
- remain -=(ulong) length;
- statistic_add(bytes_received,(ulong) length,&LOCK_bytes_received);
+ remain -= (uint32) length;
+ statistic_add(bytes_received,length,&LOCK_bytes_received);
}
}
#endif /* MYSQL_SERVER */
-static uint
+/*
+ Reads one packet to net->buff + net->where_b
+ Returns length of packet. Long packets are handled by my_net_read().
+ This function reallocates the net->buff buffer if necessary.
+*/
+
+static ulong
my_real_read(NET *net, ulong *complen)
{
uchar *pos;
@@ -454,12 +509,12 @@ my_real_read(NET *net, ulong *complen)
uint i,retry_count=0;
ulong len=packet_error;
thr_alarm_t alarmed;
-#if (!defined(__WIN__) && !defined(__EMX__) && !defined(OS2)) || defined(MYSQL_SERVER)
+#if defined(MYSQL_SERVER)
ALARM alarm_buff;
#endif
my_bool net_blocking=vio_is_blocking(net->vio);
- ulong remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
- NET_HEADER_SIZE);
+ uint32 remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
+ NET_HEADER_SIZE);
*complen = 0;
net->reading_or_writing=1;
@@ -536,7 +591,7 @@ my_real_read(NET *net, ulong *complen)
continue;
}
#endif
- DBUG_PRINT("error",("Couldn't read packet: remain: %d errno: %d length: %d alarmed: %d", remain,vio_errno(net->vio),length,alarmed));
+ DBUG_PRINT("error",("Couldn't read packet: remain: %lu errno: %d length: %ld alarmed: %d", remain,vio_errno(net->vio),length,alarmed));
len= packet_error;
net->error=2; /* Close socket */
#ifdef MYSQL_SERVER
@@ -545,7 +600,7 @@ my_real_read(NET *net, ulong *complen)
#endif
goto end;
}
- remain -= (ulong) length;
+ remain -= (uint32) length;
pos+= (ulong) length;
statistic_add(bytes_received,(ulong) length,&LOCK_bytes_received);
}
@@ -557,9 +612,9 @@ my_real_read(NET *net, ulong *complen)
if (net->buff[net->where_b] != (uchar) 255)
{
DBUG_PRINT("error",
- ("Packets out of order (Found: %d, expected %d)",
+ ("Packets out of order (Found: %d, expected %u)",
(int) net->buff[net->where_b + 3],
- (uint) (uchar) net->pkt_nr));
+ net->pkt_nr));
#ifdef EXTRA_DEBUG
fprintf(stderr,"Packets out of order (Found: %d, expected %d)\n",
(int) net->buff[net->where_b + 3],
@@ -572,7 +627,7 @@ my_real_read(NET *net, ulong *complen)
#endif
goto end;
}
- net->pkt_nr++;
+ net->compress_pkt_nr= ++net->pkt_nr;
#ifdef HAVE_COMPRESS
if (net->compress)
{
@@ -582,23 +637,24 @@ my_real_read(NET *net, ulong *complen)
#endif
len=uint3korr(net->buff+net->where_b);
+ if (!len) /* End of big multi-packet */
+ goto end;
helping = max(len,*complen) + net->where_b;
/* The necessary size of net->buff */
if (helping >= net->max_packet)
{
- /* We must allocate one extra byte for the end null */
- if (net_realloc(net,helping+1))
+ if (net_realloc(net,helping))
{
#ifdef MYSQL_SERVER
if (i == 1)
- my_net_skip_rest(net, len, &alarmed);
+ my_net_skip_rest(net, (uint32) len, &alarmed);
#endif
len= packet_error; /* Return error */
goto end;
}
}
pos=net->buff + net->where_b;
- remain = len;
+ remain = (uint32) len;
}
}
@@ -612,7 +668,21 @@ end:
return(len);
}
-uint
+
+/*
+ Read a packet from the client/server and return it without the internal
+ package header.
+ If the packet is the first packet of a multi-packet packet
+ (which is indicated by the length of the packet = 0xffffff) then
+ all sub packets are read and concatenated.
+ If the packet was compressed, its uncompressed and the length of the
+ uncompressed packet is returned.
+
+ The function returns the length of the found packet or packet_error.
+ net->read_pos points to the read data.
+*/
+
+ulong
my_net_read(NET *net)
{
ulong len,complen;
@@ -621,65 +691,126 @@ my_net_read(NET *net)
if (!net->compress)
{
#endif
- len = my_real_read (net,&complen);
+ len = my_real_read(net,&complen);
+ if (len == MAX_THREE_BYTES)
+ {
+ /* First packet of a multi-packet. Concatenate the packets */
+ ulong save_pos = net->where_b;
+ ulong total_length=0;
+ do
+ {
+ net->where_b += len;
+ total_length += len;
+ len = my_real_read (net,&complen);
+ } while (len == MAX_THREE_BYTES);
+ if (len != packet_error)
+ len+= total_length;
+ net->where_b = save_pos;
+ }
net->read_pos = net->buff + net->where_b;
if (len != packet_error)
net->read_pos[len]=0; /* Safeguard for mysql_use_result */
return len;
#ifdef HAVE_COMPRESS
}
- if (net->remain_in_buf)
- net->buff[net->buf_length - net->remain_in_buf]=net->save_char;
- for (;;)
+ else
{
+ /* We are using the compressed protocol */
+
+ ulong buf_length= net->buf_length;
+ ulong start_of_packet= net->buf_length - net->remain_in_buf;
+ ulong first_packet_offset=start_of_packet;
+ uint read_length, multi_byte_packet=0;
+
if (net->remain_in_buf)
{
- uchar *pos = net->buff + net->buf_length - net->remain_in_buf;
- if (net->remain_in_buf >= 4)
+ /* Restore the character that was overwritten by the end 0 */
+ net->buff[start_of_packet]=net->save_char;
+ }
+ else
+ {
+ /* reuse buffer, as there is noting in it that we need */
+ buf_length=start_of_packet=first_packet_offset=0;
+ }
+ for (;;)
+ {
+ ulong packet_len;
+
+ if (buf_length - start_of_packet >= NET_HEADER_SIZE)
{
- net->length = uint3korr(pos);
- if (net->length <= net->remain_in_buf - 4)
+ read_length = uint3korr(net->buff+start_of_packet);
+ if (!read_length)
+ {
+ /* End of multi-byte packet */
+ start_of_packet += NET_HEADER_SIZE;
+ break;
+ }
+ if (read_length + NET_HEADER_SIZE <= buf_length - start_of_packet)
{
- /* We have a full packet */
- len=net->length;
- net->remain_in_buf -= net->length + 4;
- net->read_pos=pos + 4;
- break; /* We have a full packet */
+ if (multi_byte_packet)
+ {
+ /* Remove packet header for second packet */
+ memmove(net->buff + first_packet_offset + start_of_packet,
+ net->buff + first_packet_offset + start_of_packet +
+ NET_HEADER_SIZE,
+ buf_length - start_of_packet);
+ start_of_packet += read_length;
+ buf_length -= NET_HEADER_SIZE;
+ }
+ else
+ start_of_packet+= read_length + NET_HEADER_SIZE;
+
+ if (read_length != MAX_THREE_BYTES) /* last package */
+ {
+ multi_byte_packet= 0; /* No last zero len packet */
+ break;
+ }
+ multi_byte_packet= NET_HEADER_SIZE;
+ /* Move data down to read next data packet after current one */
+ if (first_packet_offset)
+ {
+ memmove(net->buff,net->buff+first_packet_offset,
+ buf_length-first_packet_offset);
+ buf_length-=first_packet_offset;
+ start_of_packet -= first_packet_offset;
+ first_packet_offset=0;
+ }
+ continue;
}
}
/* Move data down to read next data packet after current one */
- if (net->buf_length != net->remain_in_buf)
+ if (first_packet_offset)
{
- memmove(net->buff,pos,net->remain_in_buf);
- net->buf_length=net->remain_in_buf;
+ memmove(net->buff,net->buff+first_packet_offset,
+ buf_length-first_packet_offset);
+ buf_length-=first_packet_offset;
+ start_of_packet -= first_packet_offset;
+ first_packet_offset=0;
}
- net->where_b=net->buf_length;
- }
- else
- {
- net->where_b=0;
- net->buf_length=0;
- }
- if ((len = my_real_read(net,&complen)) == packet_error)
- break;
- if (my_uncompress((byte*) net->buff + net->where_b, &len, &complen))
- {
- len= packet_error;
- net->error=2; /* caller will close socket */
+ net->where_b=buf_length;
+ if ((packet_len = my_real_read(net,&complen)) == packet_error)
+ return packet_error;
+ if (my_uncompress((byte*) net->buff + net->where_b, &packet_len,
+ &complen))
+ {
+ net->error=2; /* caller will close socket */
#ifdef MYSQL_SERVER
- net->last_errno=ER_NET_UNCOMPRESS_ERROR;
+ net->last_errno=ER_NET_UNCOMPRESS_ERROR;
#endif
- break;
+ return packet_error;
+ }
+ buf_length+=packet_len;
}
- net->buf_length+=len;
- net->remain_in_buf+=len;
- }
- if (len != packet_error)
- {
+
+ net->read_pos= net->buff+ first_packet_offset + NET_HEADER_SIZE;
+ net->buf_length= buf_length;
+ net->remain_in_buf= (ulong) (buf_length - start_of_packet);
+ len = ((ulong) (start_of_packet - first_packet_offset) - NET_HEADER_SIZE -
+ multi_byte_packet);
net->save_char= net->read_pos[len]; /* Must be saved */
net->read_pos[len]=0; /* Safeguard for mysql_use_result */
}
+#endif /* HAVE_COMPRESS */
return len;
-#endif
}
diff --git a/libmysql/password.c b/libmysql/password.c
index 0fd5861873a..9b154603b98 100644
--- a/libmysql/password.c
+++ b/libmysql/password.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* password checking routines */
/*****************************************************************************
@@ -35,7 +34,7 @@
This saves a hashed number as a string in the password field.
*****************************************************************************/
-#include <global.h>
+#include <my_global.h>
#include <my_sys.h>
#include <m_string.h>
#include "mysql.h"
diff --git a/libmysql/violite.c b/libmysql/violite.c
deleted file mode 100644
index 37fee6fad3d..00000000000
--- a/libmysql/violite.c
+++ /dev/null
@@ -1,443 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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 */
-
-/*
- Note that we can't have assertion on file descriptors; The reason for
- this is that during mysql shutdown, another thread can close a file
- we are working on. In this case we should just return read errors from
- the file descriptior.
-*/
-
-#include <global.h>
-
-#ifndef HAVE_VIO /* is Vio suppored by the Vio lib ? */
-
-#include <errno.h>
-#include <assert.h>
-#include <violite.h>
-#include <my_sys.h>
-#include <my_net.h>
-#include <m_string.h>
-#ifdef HAVE_POLL
-#include <sys/poll.h>
-#endif
-#ifdef HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-
-#if !defined(MSDOS) && !defined(__WIN__) && !defined(HAVE_BROKEN_NETINET_INCLUDES) && !defined(__BEOS__) && !defined(__FreeBSD__)
-#include <netinet/in_systm.h>
-#include <netinet/ip.h>
-#if !defined(alpha_linux_port)
-#include <netinet/tcp.h>
-#endif
-#endif
-
-#if defined(__EMX__) || defined(OS2)
-#define ioctlsocket ioctl
-#endif /* defined(__EMX__) */
-
-#if defined(MSDOS) || defined(__WIN__)
-#define O_NONBLOCK 1 /* For emulation of fcntl() */
-#endif
-#ifndef EWOULDBLOCK
-#define SOCKET_EWOULDBLOCK SOCKET_EAGAIN
-#endif
-
-#ifndef __WIN__
-#define HANDLE void *
-#endif
-
-struct st_vio
-{
- my_socket sd; /* my_socket - real or imaginary */
- HANDLE hPipe;
- my_bool localhost; /* Are we from localhost? */
- int fcntl_mode; /* Buffered fcntl(sd,F_GETFL) */
- struct sockaddr_in local; /* Local internet address */
- struct sockaddr_in remote; /* Remote internet address */
- enum enum_vio_type type; /* Type of connection */
- char desc[30]; /* String description */
-};
-
-typedef void *vio_ptr;
-typedef char *vio_cstring;
-
-/*
- * Helper to fill most of the Vio* with defaults.
- */
-
-static void vio_reset(Vio* vio, enum enum_vio_type type,
- my_socket sd, HANDLE hPipe,
- my_bool localhost)
-{
- bzero((char*) vio, sizeof(*vio));
- vio->type = type;
- vio->sd = sd;
- vio->hPipe = hPipe;
- vio->localhost= localhost;
-}
-
-/* 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;
- DBUG_ENTER("vio_new");
- DBUG_PRINT("enter", ("sd=%d", sd));
- if ((vio = (Vio*) my_malloc(sizeof(*vio),MYF(MY_WME))))
- {
- vio_reset(vio, type, sd, 0, localhost);
- sprintf(vio->desc,
- (vio->type == VIO_TYPE_SOCKET ? "socket (%d)" : "TCP/IP (%d)"),
- vio->sd);
-#if !defined(___WIN__) && !defined(__EMX__) && !defined(OS2)
-#if !defined(NO_FCNTL_NONBLOCK)
- vio->fcntl_mode = fcntl(sd, F_GETFL);
-#elif defined(HAVE_SYS_IOCTL_H) /* hpux */
- /* Non blocking sockets doesn't work good on HPUX 11.0 */
- (void) ioctl(sd,FIOSNBIO,0);
-#endif
-#else /* !defined(__WIN__) && !defined(__EMX__) */
- {
- /* set to blocking mode by default */
- ulong arg=0, r;
- r = ioctlsocket(vio->sd,FIONBIO,(void*) &arg, sizeof(arg));
- }
-#endif
- }
- DBUG_RETURN(vio);
-}
-
-
-#ifdef __WIN__
-
-Vio *vio_new_win32pipe(HANDLE hPipe)
-{
- Vio *vio;
- DBUG_ENTER("vio_new_handle");
- if ((vio = (Vio*) my_malloc(sizeof(Vio),MYF(MY_WME))))
- {
- vio_reset(vio, VIO_TYPE_NAMEDPIPE, 0, hPipe, TRUE);
- strmov(vio->desc, "named pipe");
- }
- DBUG_RETURN(vio);
-}
-
-#endif
-
-void vio_delete(Vio * vio)
-{
- /* It must be safe to delete null pointers. */
- /* This matches the semantics of C++'s delete operator. */
- if (vio)
- {
- if (vio->type != VIO_CLOSED)
- vio_close(vio);
- my_free((gptr) vio,MYF(0));
- }
-}
-
-int vio_errno(Vio *vio __attribute__((unused)))
-{
- return socket_errno; /* On Win32 this mapped to WSAGetLastError() */
-}
-
-
-int vio_read(Vio * vio, gptr buf, int size)
-{
- int r;
- DBUG_ENTER("vio_read");
- DBUG_PRINT("enter", ("sd=%d size=%d", vio->sd, size));
-#if defined( __WIN__) || defined(OS2)
- if (vio->type == VIO_TYPE_NAMEDPIPE)
- {
- DWORD length;
-#ifdef OS2
- if (!DosRead((HFILE)vio->hPipe, buf, size, &length))
- DBUG_RETURN(-1);
-#else
- if (!ReadFile(vio->hPipe, buf, size, &length, NULL))
- DBUG_RETURN(-1);
-#endif
- DBUG_RETURN(length);
- }
- r = recv(vio->sd, buf, size,0);
-#else
- errno=0; /* For linux */
- r = read(vio->sd, buf, size);
-#endif /* __WIN__ */
-#ifndef DBUG_OFF
- if (r < 0)
- {
- DBUG_PRINT("vio_error", ("Got error %d during read",socket_errno));
- }
-#endif /* DBUG_OFF */
- DBUG_PRINT("exit", ("%d", r));
- DBUG_RETURN(r);
-}
-
-
-int vio_write(Vio * vio, const gptr buf, int size)
-{
- int r;
- DBUG_ENTER("vio_write");
- DBUG_PRINT("enter", ("sd=%d size=%d", vio->sd, size));
-#if defined( __WIN__) || defined(OS2)
- if ( vio->type == VIO_TYPE_NAMEDPIPE)
- {
- DWORD length;
-#ifdef OS2
- if (!DosWrite((HFILE)vio->hPipe, (char*) buf, size, &length))
- DBUG_RETURN(-1);
-#else
- if (!WriteFile(vio->hPipe, (char*) buf, size, &length, NULL))
- DBUG_RETURN(-1);
-#endif
- DBUG_RETURN(length);
- }
- r = send(vio->sd, buf, size,0);
-#else
- r = write(vio->sd, buf, size);
-#endif /* __WIN__ */
-#ifndef DBUG_OFF
- if (r < 0)
- {
- DBUG_PRINT("vio_error", ("Got error on write: %d",socket_errno));
- }
-#endif /* DBUG_OFF */
- DBUG_PRINT("exit", ("%d", r));
- DBUG_RETURN(r);
-}
-
-
-int vio_blocking(Vio * vio, my_bool set_blocking_mode)
-{
- int r=0;
- DBUG_ENTER("vio_blocking");
- DBUG_PRINT("enter", ("set_blocking_mode: %d", (int) set_blocking_mode));
-
-#if !defined(___WIN__) && !defined(__EMX__) && !defined(OS2)
-#if !defined(NO_FCNTL_NONBLOCK)
-
- if (vio->sd >= 0)
- {
- int old_fcntl=vio->fcntl_mode;
- if (set_blocking_mode)
- vio->fcntl_mode &= ~O_NONBLOCK; /* clear bit */
- else
- vio->fcntl_mode |= O_NONBLOCK; /* set bit */
- if (old_fcntl != vio->fcntl_mode)
- r = fcntl(vio->sd, F_SETFL, vio->fcntl_mode);
- }
-#endif /* !defined(NO_FCNTL_NONBLOCK) */
-#else /* !defined(__WIN__) && !defined(__EMX__) */
-#ifndef __EMX__
- if (vio->type != VIO_TYPE_NAMEDPIPE)
-#endif
- {
- ulong arg;
- int old_fcntl=vio->fcntl_mode;
- if (set_blocking_mode)
- {
- arg = 0;
- vio->fcntl_mode &= ~O_NONBLOCK; /* clear bit */
- }
- else
- {
- arg = 1;
- vio->fcntl_mode |= O_NONBLOCK; /* set bit */
- }
- if (old_fcntl != vio->fcntl_mode)
- r = ioctlsocket(vio->sd,FIONBIO,(void*) &arg, sizeof(arg));
- }
-#endif /* !defined(__WIN__) && !defined(__EMX__) */
- DBUG_RETURN(r);
-}
-
-my_bool
-vio_is_blocking(Vio * vio)
-{
- my_bool r;
- DBUG_ENTER("vio_is_blocking");
- r = !(vio->fcntl_mode & O_NONBLOCK);
- DBUG_PRINT("exit", ("%d", (int) r));
- DBUG_RETURN(r);
-}
-
-
-int vio_fastsend(Vio * vio __attribute__((unused)))
-{
- int r=0;
- DBUG_ENTER("vio_fastsend");
-
-#ifdef IPTOS_THROUGHPUT
- {
-#ifndef __EMX__
- int tos = IPTOS_THROUGHPUT;
- if (!setsockopt(vio->sd, IPPROTO_IP, IP_TOS, (void *) &tos, sizeof(tos)))
-#endif /* !__EMX__ */
- {
- int nodelay = 1;
- if (setsockopt(vio->sd, IPPROTO_TCP, TCP_NODELAY, (void *) &nodelay,
- sizeof(nodelay))) {
- DBUG_PRINT("warning",
- ("Couldn't set socket option for fast send"));
- r= -1;
- }
- }
- }
-#endif /* IPTOS_THROUGHPUT */
- DBUG_PRINT("exit", ("%d", r));
- DBUG_RETURN(r);
-}
-
-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)
- set_keep_alive));
- if (vio->type != VIO_TYPE_NAMEDPIPE)
- {
- if (set_keep_alive)
- opt = 1;
- r = setsockopt(vio->sd, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt,
- sizeof(opt));
- }
- DBUG_RETURN(r);
-}
-
-
-my_bool
-vio_should_retry(Vio * vio __attribute__((unused)))
-{
- int en = socket_errno;
- return en == SOCKET_EAGAIN || en == SOCKET_EINTR || en == SOCKET_EWOULDBLOCK;
-}
-
-
-int vio_close(Vio * vio)
-{
- int r;
- DBUG_ENTER("vio_close");
-#ifdef __WIN__
- if (vio->type == VIO_TYPE_NAMEDPIPE)
- {
-#if defined(__NT__) && defined(MYSQL_SERVER)
- CancelIo(vio->hPipe);
- DisconnectNamedPipe(vio->hPipe);
-#endif
- r=CloseHandle(vio->hPipe);
- }
- else if (vio->type != VIO_CLOSED)
-#endif /* __WIN__ */
- {
- r=0;
- if (shutdown(vio->sd,2))
- r= -1;
- if (closesocket(vio->sd))
- r= -1;
- }
- if (r)
- {
- DBUG_PRINT("vio_error", ("close() failed, error: %d",socket_errno));
- /* FIXME: error handling (not critical for MySQL) */
- }
- vio->type= VIO_CLOSED;
- vio->sd= -1;
- DBUG_RETURN(r);
-}
-
-
-const char *vio_description(Vio * vio)
-{
- return vio->desc;
-}
-
-enum enum_vio_type vio_type(Vio* vio)
-{
- return vio->type;
-}
-
-my_socket vio_fd(Vio* vio)
-{
- return vio->sd;
-}
-
-
-my_bool vio_peer_addr(Vio * vio, char *buf)
-{
- DBUG_ENTER("vio_peer_addr");
- DBUG_PRINT("enter", ("sd=%d", vio->sd));
- if (vio->localhost)
- {
- strmov(buf,"127.0.0.1");
- }
- else
- {
- size_socket addrLen = sizeof(struct sockaddr);
- if (getpeername(vio->sd, (struct sockaddr *) (& (vio->remote)),
- &addrLen) != 0)
- {
- DBUG_PRINT("exit", ("getpeername, error: %d", socket_errno));
- DBUG_RETURN(1);
- }
- my_inet_ntoa(vio->remote.sin_addr,buf);
- }
- DBUG_PRINT("exit", ("addr=%s", buf));
- DBUG_RETURN(0);
-}
-
-
-void vio_in_addr(Vio *vio, struct in_addr *in)
-{
- DBUG_ENTER("vio_in_addr");
- if (vio->localhost)
- bzero((char*) in, sizeof(*in)); /* This should never be executed */
- else
- *in=vio->remote.sin_addr;
- DBUG_VOID_RETURN;
-}
-
-
-/* Return 0 if there is data to be read */
-
-my_bool vio_poll_read(Vio *vio,uint timeout)
-{
-#ifndef HAVE_POLL
- return 0;
-#else
- struct pollfd fds;
- int res;
- DBUG_ENTER("vio_poll");
- fds.fd=vio->sd;
- fds.events=POLLIN;
- fds.revents=0;
- if ((res=poll(&fds,1,(int) timeout*1000)) <= 0)
- {
- DBUG_RETURN(res < 0 ? 0 : 1); /* Don't return 1 on errors */
- }
- DBUG_RETURN(fds.revents & POLLIN ? 0 : 1);
-#endif
-}
-
-#endif /* HAVE_VIO */
diff --git a/libmysql_r/Makefile.am b/libmysql_r/Makefile.am
index aa1d398f874..22d71e00752 100644
--- a/libmysql_r/Makefile.am
+++ b/libmysql_r/Makefile.am
@@ -22,7 +22,7 @@ target_defs = -DDONT_USE_RAID @LIB_EXTRA_CCFLAGS@
## LIBS = @LIBS@
INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include -I../include \
- -I$(srcdir)/.. -I$(top_srcdir) -I..
+ -I$(srcdir)/.. -I$(top_srcdir) -I.. $(openssl_includes)
## automake barfs if you don't use $(srcdir) or $(top_srcdir) in include
include $(top_srcdir)/libmysql/Makefile.shared
diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am
new file mode 100644
index 00000000000..edee13c98bb
--- /dev/null
+++ b/libmysqld/Makefile.am
@@ -0,0 +1,135 @@
+# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#
+# 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 public domain and comes with NO WARRANTY of any kind
+
+MYSQLDATAdir = $(localstatedir)
+MYSQLSHAREdir = $(pkgdatadir)
+MYSQLBASEdir= $(prefix)
+
+DEFS = -DEMBEDDED_LIBRARY -DMYSQL_SERVER \
+ -DDEFAULT_MYSQL_HOME="\"$(MYSQLBASEdir)\"" \
+ -DDATADIR="\"$(MYSQLDATAdir)\"" \
+ -DSHAREDIR="\"$(MYSQLSHAREdir)\""
+INCLUDES= @MT_INCLUDES@ @bdb_includes@ -I$(srcdir)/../include \
+ -I../include -I$(srcdir)/.. -I$(top_srcdir) -I.. \
+ -I../sql -I../regex
+
+noinst_LIBRARIES = libmysqld_int.a
+pkglib_LIBRARIES = libmysqld.a
+SUBDIRS = . examples
+libmysqld_sources= libmysqld.c lib_sql.cc lib_load.cc
+libmysqlsources = errmsg.c get_password.c password.c
+
+noinst_HEADERS = embedded_priv.h
+
+sqlsources = convert.cc derror.cc field.cc field_conv.cc filesort.cc \
+ ha_innodb.cc ha_berkeley.cc ha_heap.cc ha_isam.cc ha_isammrg.cc \
+ ha_myisam.cc ha_myisammrg.cc handler.cc sql_handler.cc \
+ hostname.cc init.cc \
+ item.cc item_buff.cc item_cmpfunc.cc item_create.cc \
+ item_func.cc item_strfunc.cc item_sum.cc item_timefunc.cc \
+ item_uniq.cc key.cc lock.cc log.cc log_event.cc mf_iocache.cc\
+ mini_client.cc net_pkg.cc net_serv.cc opt_ft.cc opt_range.cc \
+ opt_sum.cc procedure.cc records.cc sql_acl.cc \
+ repl_failsafe.cc slave.cc \
+ sql_analyse.cc sql_base.cc sql_cache.cc sql_class.cc \
+ sql_crypt.cc sql_db.cc sql_delete.cc sql_insert.cc sql_lex.cc \
+ sql_list.cc sql_manager.cc sql_map.cc sql_parse.cc \
+ sql_rename.cc sql_repl.cc sql_select.cc sql_do.cc sql_show.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
+
+EXTRA_DIST = lib_vio.c
+
+libmysqld_int_a_SOURCES= $(libmysqld_sources) $(libmysqlsources) $(sqlsources)
+libmysqld_a_SOURCES=
+
+# Don't depend on things from mit-pthreads
+
+OMIT_DEPENDENCIES = pthread.h stdio.h __stdio.h stdlib.h __stdlib.h math.h\
+ __math.h time.h __time.h unistd.h __unistd.h types.h \
+ xtypes.h ac-types.h posix.h string.h __string.h \
+ errno.h socket.h inet.h dirent.h netdb.h \
+ cleanup.h cond.h debug_out.h fd.h kernel.h mutex.h \
+ prio_queue.h pthread_attr.h pthread_once.h queue.h\
+ sleep.h specific.h version.h pwd.h timers.h uio.h \
+ cdefs.h machdep.h signal.h __signal.h util.h lex.h \
+ wait.h
+
+# automake misses these
+sql_yacc.cc sql_yacc.h: $(top_srcdir)/sql/sql_yacc.yy
+
+# The following libraries should be included in libmysqld.a
+INC_LIB= $(top_builddir)/regex/libregex.a \
+ $(top_builddir)/myisam/libmyisam.a \
+ $(top_builddir)/myisammrg/libmyisammrg.a \
+ $(top_builddir)/heap/libheap.a \
+ @innodb_libs@ @bdb_libs_with_path@ \
+ $(top_builddir)/mysys/libmysys.a \
+ $(top_builddir)/strings/libmystrings.a \
+ $(top_builddir)/dbug/libdbug.a \
+ $(top_builddir)/regex/libregex.a
+
+#
+# To make it easy for the end user to use the embedded library we
+# generate a total libmysqld.a from all library files,
+
+libmysqld.a: libmysqld_int.a $(INC_LIB)
+ if test ! -d tmp ; then mkdir tmp ; fi
+ rm -f $@ libmysqld_int2.a tmp/*.o tmp/*.a
+ cp $(INC_LIB) tmp
+ cp libmysqld_int.a libmysqld_int2.a ; \
+ cd tmp ; \
+ for file in *.a ; do \
+ bfile=`basename $$file .a` ; \
+ ar x $$file; \
+ for obj in *.o ; do mv $$obj $${bfile}_$$obj ; done ; \
+ ar q ../libmysqld_int2.a *.o ; \
+ rm *.o ; \
+ done
+ mv libmysqld_int2.a libmysqld.a
+ rm tmp/*
+ $(RANLIB) libmysqld.a
+
+## XXX: any time the client interface changes, we'll need to bump
+## the version info for libmysqld; however, it's possible for the
+## libmysqld interface to change without affecting the standard
+## libmysqlclient interface. Should we make a separate version
+## string for the two?
+#libmysqld_la_LDFLAGS = -version-info @SHARED_LIB_VERSION@
+#CLEANFILES = $(libmysqld_la_LIBADD) libmysqld.la
+
+# This is called from the toplevel makefile
+link_sources:
+ set -x; \
+ for f in $(sqlsources); do \
+ rm -f $(srcdir)/$$f; \
+ @LN_CP_F@ $(srcdir)/../sql/$$f $(srcdir)/$$f; \
+ done; \
+ for f in $(libmysqlsources); do \
+ rm -f $(srcdir)/$$f; \
+ @LN_CP_F@ $(srcdir)/../libmysql/$$f $(srcdir)/$$f; \
+ done
+
+clean-local:
+ rm -f `echo $(sqlsources) $(libmysqlsources) | sed "s;\.lo;.c;g"` \
+ $(top_srcdir)/linked_libmysqld_sources
+
+# Don't update the files from bitkeeper
+%::SCCS/s.%
diff --git a/libmysqld/copyright b/libmysqld/copyright
new file mode 100644
index 00000000000..0b4dd1725a2
--- /dev/null
+++ b/libmysqld/copyright
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2000
+ * SWsoft company
+ *
+ * This material is provided "as is", with absolutely no warranty expressed
+ * or implied. Any use is at your own risk.
+ *
+ * Permission to use or copy this software for any purpose is hereby granted
+ * without fee, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ *
+ */
diff --git a/libmysqld/embedded_priv.h b/libmysqld/embedded_priv.h
new file mode 100644
index 00000000000..96d2c96ed0b
--- /dev/null
+++ b/libmysqld/embedded_priv.h
@@ -0,0 +1,32 @@
+/* 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 */
+
+/* Prototypes for the embedded version of MySQL */
+
+#include <my_global.h>
+#include <mysql_embed.h>
+#include <mysql.h>
+#include <mysql_version.h>
+#include <mysqld_error.h>
+#include <my_pthread.h>
+
+C_MODE_START
+extern void start_embedded_connection(NET * net);
+extern void end_embedded_connection(NET * net);
+extern void lib_connection_phase(NET *net, int phase);
+extern bool lib_dispatch_command(enum enum_server_command command, NET *net,
+ const char *arg, ulong length);
+C_MODE_END
diff --git a/libmysqld/examples/Makefile.am b/libmysqld/examples/Makefile.am
new file mode 100644
index 00000000000..d9f9f05ae97
--- /dev/null
+++ b/libmysqld/examples/Makefile.am
@@ -0,0 +1,26 @@
+noinst_PROGRAMS = mysqltest mysql
+client_sources = $(mysqltest_SOURCES) $(mysql_SOURCES)
+
+link_sources:
+ for f in $(client_sources); do \
+ rm -f $(srcdir)/$$f; \
+ @LN_CP_F@ $(srcdir)/../../client/$$f $(srcdir)/$$f; \
+ done;
+
+DEFS = -DEMBEDDED_LIBRARY
+INCLUDES = -I$(top_srcdir)/include $(openssl_includes) \
+ -I$(srcdir) -I$(top_srcdir) -I$(top_srcdir)/client
+LIBS = @LIBS@
+LDADD = ../libmysqld.a @innodb_system_libs@ @LIBDL@ $(CXXLDFLAGS)
+
+mysqltest_SOURCES = mysqltest.c
+
+mysql_SOURCES = mysql.cc readline.cc completion_hash.cc \
+ my_readline.h sql_string.h completion_hash.h
+mysql_LDADD = @readline_link@ @TERMCAP_LIB@ $(LDADD)
+
+clean:
+ rm -f $(client_sources)
+
+# Don't update the files from bitkeeper
+%::SCCS/s.%
diff --git a/libmysqld/examples/test-run b/libmysqld/examples/test-run
new file mode 100755
index 00000000000..c7434488259
--- /dev/null
+++ b/libmysqld/examples/test-run
@@ -0,0 +1,138 @@
+#! /bin/sh
+
+# This is slapped together as a quick way to run the tests and
+# is not meant for prime time. Please hack at it and submit
+# changes, though, so we can gradually turn it into something
+# that will run on all platforms (or incorporate it into the
+# standard mysql-test-run).
+
+# All paths below must be relative to $test_data_dir
+top_builddir=../..
+mysql_test_dir=$top_builddir/mysql-test
+examples=$top_builddir/libmysqld/examples
+mysqltest=$examples/mysqltest
+datadir=$mysql_test_dir/var/master-data
+test_data_dir=test
+gdb=0
+list=0
+run=
+tests=
+start=
+clean=1
+
+cr="
+"
+er="\b\b\b\b\b\b\b\b"
+
+usage () {
+ cat <<EOF
+usage: $0 [-g|-h|-r] [test-name ...]
+
+ -C | --noclean Do not remove old innodb and bdb files at start.
+ -g | --gdb run $mysqltest in gdb
+ -h | --help show this help
+ -l | --list ) list all available tests
+ -r | --run automatically 'run' program in gdb
+ -s t | --start=t start with test t (skip all tests before t)
+EOF
+}
+
+init_args="--server-arg=--language=$top_builddir/sql/share/english"
+while test $# -gt 0
+do
+ arg=
+ argset=0
+ case "$1" in
+ --?*=* ) arg=`echo "$1" | sed -e 's,^[^=][^=]*=,,'`; argset=1 ;;
+ esac
+
+ case "$1" in
+ -g | --gdb ) gdb=1; shift;;
+ -h | --help | -\? ) usage; exit 0;;
+ -l | --list ) list=1 ; shift ;;
+ -r | --run ) run="${cr}run"; shift;;
+ --debug) init_args="$init_args --debug" ; shift ;;
+ -C | --noclean) clean=0 ; shift ;;
+ -s | --start=* )
+ test $argset -eq 0 && { shift; arg="$1"; }
+ start="$arg"
+ shift
+ ;;
+ -* ) usage; exit 1;;
+ * ) tests="$tests $1"; shift;;
+ esac
+done
+
+if test ! -d "$datadir/$test_data_dir"
+then
+ echo "bad setup (is '$datadir/$test_data_dir'', missing ?)" >&2
+ exit 1
+fi
+
+test -n "$tests" ||
+ tests=`/bin/ls -1 "$mysql_test_dir"/t/*.test | grep -v '^.*/rpl[^/]*$' | \
+ sed -e 's,^.*/,,' -e 's,.test$,,'`
+
+echo "cleaning data directory '$datadir/$test_data_dir'"
+if test $clean = 1
+then
+ rm -f $datadir/ib_* $datadir/ibdata*
+ rm -f $datadir/log.00*
+ rm -f $datadir/test/*.db
+fi
+rm -f $datadir/../tmp/*
+rm -f test-gdbinit
+
+TZ=GMT-3; export TZ
+
+# At least one of the tests needs the following environment variable
+MYSQL_TEST_DIR=`( cd $mysql_test_dir ; pwd )` ; export MYSQL_TEST_DIR
+
+skip=1
+test -z "$start" && skip=0
+
+for b in $tests
+do
+ test $list -eq 1 && { echo " $b"; continue; }
+ test $skip -eq 1 && test -n "$start" && test "$start" = "$b" && skip=0
+ test $skip -eq 1 && { echo "skipping '$b'"; continue; }
+
+ t="t/$b.test"
+ r="r/$b.result"
+
+ # Only test if $t exists; there is no $r for some tests
+ test -f $mysql_test_dir/$t || {
+ echo "test '$mysql_test_dir/$t' doesn't exist" >&2
+ continue
+ }
+ args="$init_args -v --basedir=$mysql_test_dir/ -R $r -x $t --server-arg=--datadir=$datadir"
+ if test -f "$mysql_test_dir/t/$b-master.opt" ; then
+ args="$args --server-file=t/$b-master.opt"
+ fi
+
+ args="$args $test_data_dir" # Add database last
+ echo "set args $args$run" > test-gdbinit
+ #if false && test -n "$run"
+ if test -n "$run" -o $gdb -eq 1
+ then
+ echo -e "$er>>> $b"
+ else
+ echo -e "$er>>> $b> \c"
+ read junk
+ fi
+ if test $gdb -eq 1
+ then
+ if [ -x "$top_builddir/libtool" ]; then
+ $top_builddir/libtool gdb -x test-gdbinit -q $mysqltest
+ else
+ gdb -x test-gdbinit -q $mysqltest
+ fi
+ res=$?
+ rm -f test-gdbinit
+ else
+ $mysqltest $args
+ res=$?
+ fi
+
+ test $res -eq 0 -o $res -eq 2 || echo "!!! error: $res"
+done
diff --git a/libmysqld/lib_load.cc b/libmysqld/lib_load.cc
new file mode 100644
index 00000000000..3db5a2488d1
--- /dev/null
+++ b/libmysqld/lib_load.cc
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2000
+ * SWsoft company
+ *
+ * This material is provided "as is", with absolutely no warranty expressed
+ * or implied. Any use is at your own risk.
+ *
+ * Permission to use or copy this software for any purpose is hereby granted
+ * without fee, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ *
+ */
+/* Copy data from a textfile to table */
+
+#include "mysql_priv.h"
+#include <my_dir.h>
+#include <m_ctype.h>
+
+
+int
+mysql_load_internal(THD * thd, sql_exchange * ex, TABLE_LIST * table_list,
+ List<Item> & fields, enum enum_duplicates handle_duplicates,
+ bool read_file_from_client, thr_lock_type lock_type);
+
+int
+mysql_load(THD * thd, sql_exchange * ex, TABLE_LIST * table_list,
+ List<Item> & fields, enum enum_duplicates handle_duplicates,
+ bool read_file_from_client, thr_lock_type lock_type)
+{
+ read_file_from_client = 0; //server is always in the same process
+ return mysql_load_internal(thd, ex, table_list, fields, handle_duplicates,
+ read_file_from_client, lock_type);
+}
+
+#define mysql_load mysql_load_internal
+
+
+#if defined (__WIN__)
+#include "../sql/sql_load.cpp"
+#else
+#include "../sql/sql_load.cc"
+#endif
diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc
new file mode 100644
index 00000000000..2a9a369e645
--- /dev/null
+++ b/libmysqld/lib_sql.cc
@@ -0,0 +1,600 @@
+/*
+ * Copyright (c) 2000
+ * SWsoft company
+ *
+ * This material is provided "as is", with absolutely no warranty expressed
+ * or implied. Any use is at your own risk.
+ *
+ * Permission to use or copy this software for any purpose is hereby granted
+ * without fee, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ *
+ */
+#include "embedded_priv.h"
+#include "sys/types.h"
+#include "../regex/regex.h"
+#include "my_sys.h"
+
+/*
+ The following is needed to not cause conflicts when we include mysqld.cc
+*/
+
+#define main main1
+#define mysql_unix_port mysql_inix_port1
+#define mysql_port mysql_port1
+#if !defined(__WIN__)
+#define net_read_timeout net_read_timeout1
+#define net_write_timeout net_write_timeout1
+#endif
+#define changeable_vars changeable_vars1
+
+extern "C"
+{
+#include "mysql_com.h"
+#include "lib_vio.c"
+}
+
+
+class THD;
+
+static int check_connections1(THD * thd);
+static int check_connections2(THD * thd);
+static bool check_user(THD *thd, enum_server_command command,
+ const char *user, const char *passwd, const char *db,
+ bool check_count);
+void free_defaults_internal(char ** argv) {if (argv) free_defaults(argv);}
+#define free_defaults free_defaults_internal
+
+#if defined (__WIN__)
+#include "../sql/mysqld.cpp"
+#else
+#include "../sql/mysqld.cc"
+#endif
+
+#define SCRAMBLE_LENGTH 8
+C_MODE_START
+
+char * get_mysql_home(){ return mysql_home;};
+char * get_mysql_real_data_home(){ return mysql_real_data_home;};
+
+
+bool lib_dispatch_command(enum enum_server_command command, NET *net,
+ const char *arg, ulong length)
+{
+ THD *thd=(THD *) net->vio->dest_thd;
+ thd->store_globals(); // Fix if more than one connect
+ thd->net.last_error[0]=0; // Clear error message
+ thd->net.last_errno=0;
+
+ net_new_transaction(&thd->net);
+ return dispatch_command(command, thd, (char *) arg, length + 1);
+}
+
+
+void lib_connection_phase(NET * net, int phase)
+{
+ THD * thd;
+ thd = (THD *)(net->vio->dest_thd);
+ if (thd)
+ {
+ switch (phase)
+ {
+ case 2:
+ check_connections2(thd);
+ break;
+ }
+ }
+}
+C_MODE_END
+
+
+void start_embedded_conn1(NET * net)
+{
+ THD * thd = new THD;
+ my_net_init(&thd->net,NULL);
+ /* if (protocol_version>9) */
+ thd->net.return_errno=1;
+ thd->thread_id = thread_id++;
+
+ Vio * v = net->vio;
+ if (!v)
+ {
+ v = vio_new(0,VIO_CLOSED,0);
+ net->vio = v;
+ }
+ if (v)
+ {
+ v -> dest_thd = thd;
+ }
+ thd->net.vio = v;
+ if (thd->store_globals())
+ {
+ fprintf(stderr,"store_globals failed.\n");
+ return;
+ }
+
+ thd->mysys_var=my_thread_var;
+ thd->dbug_thread_id=my_thread_id();
+ thd->thread_stack= (char*) &thd;
+
+ if (thd->max_join_size == HA_POS_ERROR)
+ thd->options |= OPTION_BIG_SELECTS;
+
+ thd->proc_info=0; // Remove 'login'
+ thd->command=COM_SLEEP;
+ thd->version=refresh_version;
+ thd->set_time();
+ init_sql_alloc(&thd->mem_root,8192,8192);
+
+ check_connections1(thd);
+}
+
+
+
+
+static int
+check_connections1(THD *thd)
+{
+ uint connect_errors=0;
+ NET *net= &thd->net;
+ /*
+ ** store the connection details
+ */
+ DBUG_PRINT("info", (("check_connections called by thread %d"),
+ thd->thread_id));
+ DBUG_PRINT("general",("New connection received on %s",
+ vio_description(net->vio)));
+ if (!thd->host) // If TCP/IP connection
+ {
+ thd->host=(char*) localhost;
+ }
+ else /* Hostname given means that the connection was on a socket */
+ {
+ DBUG_PRINT("general",("Host: %s",thd->host));
+ thd->ip=0;
+ bzero((char*) &thd->remote,sizeof(struct sockaddr));
+ }
+ //vio_keepalive(net->vio, TRUE);
+
+ /* nasty, but any other way? */
+ uint pkt_len = 0;
+
+ char buff[80],*end;
+ int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
+ CLIENT_TRANSACTIONS;
+ LINT_INIT(pkt_len);
+
+ end=strmov(buff,server_version)+1;
+ int4store((uchar*) end,thd->thread_id);
+ end+=4;
+ memcpy(end,thd->scramble,SCRAMBLE_LENGTH+1);
+ end+=SCRAMBLE_LENGTH +1;
+ int2store(end,client_flags);
+ end[2]=MY_CHARSET_CURRENT;
+
+#define MIN_HANDSHAKE_SIZE 6
+
+ int2store(end+3,thd->server_status);
+ bzero(end+5,13);
+ end+=18;
+ if (net_write_command(net,protocol_version, buff,
+ (uint) (end-buff)))
+ {
+ inc_host_errors(&thd->remote.sin_addr);
+ return(ER_HANDSHAKE_ERROR);
+ }
+ return 0;
+}
+
+static int
+check_connections2(THD * thd)
+{
+ uint connect_errors=0;
+ uint pkt_len = 0;
+ NET * net = &thd -> net;
+ if (protocol_version>9) net -> return_errno=1;
+
+ if ( (pkt_len=my_net_read(net)) == packet_error ||
+ pkt_len < MIN_HANDSHAKE_SIZE)
+ {
+ inc_host_errors(&thd->remote.sin_addr);
+ return(ER_HANDSHAKE_ERROR);
+ }
+
+#ifdef _CUSTOMCONFIG_
+#include "_cust_sql_parse.h"
+#endif
+ if (connect_errors)
+ reset_host_errors(&thd->remote.sin_addr);
+ if (thd->packet.alloc(net_buffer_length))
+ return(ER_OUT_OF_RESOURCES);
+
+ thd->client_capabilities=uint2korr(net->read_pos);
+
+ thd->max_packet_length=uint3korr(net->read_pos+2);
+ char *user= (char*) net->read_pos+5;
+ char *passwd= strend(user)+1;
+ char *db=0;
+ if (passwd[0] && strlen(passwd) != SCRAMBLE_LENGTH)
+ return ER_HANDSHAKE_ERROR;
+ if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB)
+ db=strend(passwd)+1;
+ if (thd->client_capabilities & CLIENT_INTERACTIVE)
+ thd->inactive_timeout=net_interactive_timeout;
+ if (thd->client_capabilities & CLIENT_TRANSACTIONS)
+ thd->net.return_status= &thd->server_status;
+ net->timeout=net_read_timeout;
+ if (check_user(thd,COM_CONNECT, user, passwd, db, 1))
+ return (-1);
+ thd->password=test(passwd[0]);
+ return 0;
+}
+
+static bool check_user(THD *thd,enum_server_command command, const char *user,
+ const char *passwd, const char *db, bool check_count)
+{
+ NET *net= &thd->net;
+ uint max=0;
+ thd->db=0;
+
+ if (!(thd->user = my_strdup(user, MYF(0))))
+ {
+ send_error(net,ER_OUT_OF_RESOURCES);
+ return 1;
+ }
+ thd->master_access=acl_getroot(thd, thd->host, thd->ip, thd->user,
+ passwd, thd->scramble, &thd->priv_user,
+ protocol_version == 9 ||
+ !(thd->client_capabilities &
+ CLIENT_LONG_PASSWORD),&max);
+ DBUG_PRINT("general",
+ ("Capabilities: %d packet_length: %d Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'",
+ thd->client_capabilities, thd->max_packet_length,
+ thd->host ? thd->host : thd->ip, thd->priv_user,
+ passwd[0] ? "yes": "no",
+ thd->master_access, thd->db ? thd->db : "*none*"));
+ if (thd->master_access & NO_ACCESS)
+ {
+ net_printf(net, ER_ACCESS_DENIED_ERROR,
+ thd->user,
+ thd->host ? thd->host : thd->ip,
+ passwd[0] ? ER(ER_YES) : ER(ER_NO));
+ mysql_log.write(thd,COM_CONNECT,ER(ER_ACCESS_DENIED_ERROR),
+ thd->user,
+ thd->host ? thd->host : thd->ip ? thd->ip : "unknown ip",
+ passwd[0] ? ER(ER_YES) : ER(ER_NO));
+ return(1); // Error already given
+ }
+ if (check_count)
+ {
+ VOID(pthread_mutex_lock(&LOCK_thread_count));
+ bool tmp=(thread_count - delayed_insert_threads >= max_connections &&
+ !(thd->master_access & PROCESS_ACL));
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ if (tmp)
+ { // Too many connections
+ send_error(net, ER_CON_COUNT_ERROR);
+ return(1);
+ }
+ }
+ mysql_log.write(thd,command,
+ (thd->priv_user == thd->user ?
+ (char*) "%s@%s on %s" :
+ (char*) "%s@%s as anonymous on %s"),
+ user,
+ thd->host ? thd->host : thd->ip ? thd->ip : "unknown ip",
+ db ? db : (char*) "");
+ thd->db_access=0;
+ if (db && db[0])
+ return test(mysql_change_db(thd,db));
+ else
+ send_ok(net); // Ready to handle questions
+ return 0; // ok
+}
+
+
+extern "C"
+{
+
+static my_bool inited, org_my_init_done;
+
+int STDCALL mysql_server_init(int argc, char **argv, char **groups)
+{
+ char glob_hostname[FN_REFLEN];
+
+ /* This mess is to allow people to call the init function without
+ * having to mess with a fake argv */
+ int *argcp;
+ char ***argvp;
+ int fake_argc = 1;
+ char *fake_argv[] = { (char *)"", 0 };
+ const char *fake_groups[] = { "server", "embedded", 0 };
+ if (argc)
+ {
+ argcp = &argc;
+ argvp = (char***) &argv;
+ }
+ else
+ {
+ argcp = &fake_argc;
+ argvp = (char ***) &fake_argv;
+ }
+ if (!groups)
+ groups = (char**) fake_groups;
+
+ my_umask=0660; // Default umask for new files
+ my_umask_dir=0700; // Default umask for new directories
+
+ /* Only call MY_INIT() if it hasn't been called before */
+ if (!inited)
+ {
+ inited=1;
+ org_my_init_done=my_init_done;
+ }
+ if (!org_my_init_done)
+ {
+ MY_INIT((char *)"mysql_embedded"); // init my_sys library & pthreads
+ }
+
+ tzset(); // Set tzname
+
+ start_time=time((time_t*) 0);
+#ifdef HAVE_TZNAME
+#if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT)
+ {
+ struct tm tm_tmp;
+ localtime_r(&start_time,&tm_tmp);
+ strmov(time_zone,tzname[tm_tmp.tm_isdst != 0 ? 1 : 0]);
+ }
+#else
+ {
+ struct tm *start_tm;
+ start_tm=localtime(&start_time);
+ strmov(time_zone,tzname[start_tm->tm_isdst != 0 ? 1 : 0]);
+ }
+#endif
+#endif
+
+ if (gethostname(glob_hostname,sizeof(glob_hostname)-4) < 0)
+ strmov(glob_hostname,"mysql");
+#ifndef DBUG_OFF
+ strcat(server_version,"-debug");
+#endif
+ strcat(server_version,"-embedded");
+ load_defaults("my", (const char **) groups, argcp, argvp);
+ defaults_argv=*argvp;
+ mysql_tmpdir=getenv("TMPDIR"); /* Use this if possible */
+#if defined( __WIN__) || defined(OS2)
+ if (!mysql_tmpdir)
+ mysql_tmpdir=getenv("TEMP");
+ if (!mysql_tmpdir)
+ mysql_tmpdir=getenv("TMP");
+#endif
+ if (!mysql_tmpdir || !mysql_tmpdir[0])
+ mysql_tmpdir=(char*) P_tmpdir; /* purecov: inspected */
+ set_options();
+ get_options(*argcp, *argvp);
+
+ if (opt_log || opt_update_log || opt_slow_log || opt_bin_log)
+ strcat(server_version,"-log");
+ DBUG_PRINT("info",("%s Ver %s for %s on %s\n",my_progname,
+ server_version, SYSTEM_TYPE,MACHINE_TYPE));
+
+ /* These must be set early */
+
+ (void) pthread_mutex_init(&LOCK_mysql_create_db,MY_MUTEX_INIT_SLOW);
+ (void) pthread_mutex_init(&LOCK_Acl,MY_MUTEX_INIT_SLOW);
+ (void) pthread_mutex_init(&LOCK_grant,MY_MUTEX_INIT_FAST);
+ (void) pthread_mutex_init(&LOCK_open,MY_MUTEX_INIT_FAST);
+ (void) pthread_mutex_init(&LOCK_thread_count,MY_MUTEX_INIT_FAST);
+ (void) pthread_mutex_init(&LOCK_mapped_file,MY_MUTEX_INIT_SLOW);
+ (void) pthread_mutex_init(&LOCK_status,MY_MUTEX_INIT_FAST);
+ (void) pthread_mutex_init(&LOCK_error_log,MY_MUTEX_INIT_FAST);
+ (void) pthread_mutex_init(&LOCK_delayed_insert,MY_MUTEX_INIT_FAST);
+ (void) pthread_mutex_init(&LOCK_delayed_status,MY_MUTEX_INIT_FAST);
+ (void) pthread_mutex_init(&LOCK_delayed_create,MY_MUTEX_INIT_SLOW);
+ (void) pthread_mutex_init(&LOCK_manager,MY_MUTEX_INIT_FAST);
+ (void) pthread_mutex_init(&LOCK_crypt,MY_MUTEX_INIT_FAST);
+ (void) pthread_mutex_init(&LOCK_bytes_sent,MY_MUTEX_INIT_FAST);
+ (void) pthread_mutex_init(&LOCK_bytes_received,MY_MUTEX_INIT_FAST);
+ (void) pthread_mutex_init(&LOCK_timezone,MY_MUTEX_INIT_FAST);
+ (void) pthread_mutex_init(&LOCK_user_conn, MY_MUTEX_INIT_FAST);
+ (void) pthread_cond_init(&COND_thread_count,NULL);
+ (void) pthread_cond_init(&COND_refresh,NULL);
+ (void) pthread_cond_init(&COND_thread_cache,NULL);
+ (void) pthread_cond_init(&COND_flush_thread_cache,NULL);
+ (void) pthread_cond_init(&COND_manager,NULL);
+ (void) pthread_cond_init(&COND_binlog_update, NULL);
+
+ if (set_default_charset_by_name(default_charset, MYF(MY_WME)))
+ {
+ mysql_server_end();
+ return 1;
+ }
+ charsets_list = list_charsets(MYF(MY_COMPILED_SETS|MY_CONFIG_SETS));
+
+ /* Parameter for threads created for connections */
+ (void) pthread_attr_init(&connection_attrib);
+ (void) pthread_attr_setdetachstate(&connection_attrib,
+ PTHREAD_CREATE_DETACHED);
+ pthread_attr_setstacksize(&connection_attrib,thread_stack);
+ pthread_attr_setscope(&connection_attrib, PTHREAD_SCOPE_SYSTEM);
+
+#if defined( SET_RLIMIT_NOFILE) || defined( OS2)
+ /* connections and databases neads lots of files */
+ {
+ uint wanted_files=10+(uint) max(max_connections*5,
+ max_connections+table_cache_size*2);
+ uint files=set_maximum_open_files(wanted_files);
+ if (files && files < wanted_files) // Some systems return 0
+ {
+ max_connections= (ulong) min((files-10),max_connections);
+ table_cache_size= (ulong) max((files-10-max_connections)/2,64);
+ DBUG_PRINT("warning",
+ ("Changed limits: max_connections: %ld table_cache: %ld",
+ max_connections,table_cache_size));
+ sql_print_error("Warning: Changed limits: max_connections: %ld table_cache: %ld",max_connections,table_cache_size);
+ }
+ }
+#endif
+ unireg_init(opt_specialflag); /* Set up extern variabels */
+ init_errmessage(); /* Read error messages from file */
+ lex_init();
+ item_init();
+ mysys_uses_curses=0;
+#ifdef USE_REGEX
+ regex_init();
+#endif
+ if (use_temp_pool && bitmap_init(&temp_pool,1024,1))
+ {
+ mysql_server_end();
+ return 1;
+ }
+
+ /*
+ ** We have enough space for fiddling with the argv, continue
+ */
+ umask(((~my_umask) & 0666));
+ table_cache_init();
+ hostname_cache_init();
+ /*sql_cache_init();*/
+ randominit(&sql_rand,(ulong) start_time,(ulong) start_time/2);
+ reset_floating_point_exceptions();
+ init_thr_lock();
+ init_slave_list();
+
+ /* Setup log files */
+ if (opt_log)
+ open_log(&mysql_log, glob_hostname, opt_logname, ".log", LOG_NORMAL);
+ if (opt_update_log)
+ {
+ open_log(&mysql_update_log, glob_hostname, opt_update_logname, "",
+ LOG_NEW);
+ using_update_log=1;
+ }
+ if (opt_bin_log)
+ {
+ if (!opt_bin_logname)
+ {
+ char tmp[FN_REFLEN];
+ strmake(tmp,glob_hostname,FN_REFLEN-5);
+ strmov(strcend(tmp,'.'),"-bin");
+ opt_bin_logname=my_strdup(tmp,MYF(MY_WME));
+ }
+ mysql_bin_log.set_index_file_name(opt_binlog_index_name);
+ open_log(&mysql_bin_log, glob_hostname, opt_bin_logname, "-bin",
+ LOG_BIN);
+ using_update_log=1;
+ }
+
+ if (opt_slow_log)
+ open_log(&mysql_slow_log, glob_hostname, opt_slow_logname, "-slow.log",
+ LOG_NORMAL);
+ if (ha_init())
+ {
+ sql_print_error("Can't init databases");
+ exit(1);
+ }
+ ha_key_cache();
+#ifdef HAVE_MLOCKALL
+ if (locked_in_memory && !geteuid())
+ {
+ ha_key_cache();
+ if (mlockall(MCL_CURRENT))
+ {
+ sql_print_error("Warning: Failed to lock memory. Errno: %d\n",errno);
+ }
+ else
+ locked_in_memory=1;
+ }
+#else
+ locked_in_memory=0;
+#endif
+
+ if (opt_myisam_log)
+ (void) mi_log( 1 );
+ ft_init_stopwords(ft_precompiled_stopwords); /* SerG */
+
+ /*
+ init signals & alarm
+ After this we can't quit by a simple unireg_abort
+ */
+ error_handler_hook = my_message_sql;
+ if (pthread_key_create(&THR_THD,NULL) || pthread_key_create(&THR_NET,NULL) ||
+ pthread_key_create(&THR_MALLOC,NULL))
+ {
+ sql_print_error("Can't create thread-keys");
+ exit(1);
+ }
+ opt_noacl = 1; // No permissions
+ if (acl_init(opt_noacl))
+ {
+ mysql_server_end();
+ return 1;
+ }
+
+#ifdef HAVE_DLOPEN
+ if (!opt_noacl)
+ udf_init();
+#endif
+
+ (void) thr_setconcurrency(concurrency); // 10 by default
+
+ if (
+#ifdef HAVE_BERKELEY_DB
+ !berkeley_skip ||
+#endif
+ (flush_time && flush_time != ~(ulong) 0L))
+ {
+ pthread_t hThread;
+ if (pthread_create(&hThread,&connection_attrib,handle_manager,0))
+ {
+ sql_print_error("Warning: Can't create thread to manage maintenance");
+ mysql_server_end();
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+void STDCALL mysql_server_end()
+{
+ clean_up(0);
+#ifdef THREAD
+ /* Don't call my_thread_end() if the application is using MY_INIT() */
+ if (!org_my_init_done)
+ my_thread_end();
+#endif
+}
+
+my_bool STDCALL mysql_thread_init()
+{
+#ifdef THREAD
+ return my_thread_init();
+#else
+ return 0;
+#endif
+}
+
+void STDCALL mysql_thread_end()
+{
+#ifdef THREAD
+ my_thread_end();
+#endif
+}
+
+void start_embedded_connection(NET * net)
+{
+ start_embedded_conn1(net);
+}
+
+void end_embedded_connection(NET * net)
+{
+ THD *thd = (THD *) net->vio->dest_thd;
+ delete thd;
+}
+
+} /* extern "C" */
diff --git a/libmysqld/lib_vio.c b/libmysqld/lib_vio.c
new file mode 100644
index 00000000000..9bf492ed5ea
--- /dev/null
+++ b/libmysqld/lib_vio.c
@@ -0,0 +1,215 @@
+/* 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 */
+
+/*
+ Note that we can't have assertion on file descriptors; The reason for
+ this is that during mysql shutdown, another thread can close a file
+ we are working on. In this case we should just return read errors from
+ the file descriptior.
+*/
+
+#include <my_global.h>
+#include "mysql_embed.h"
+#include "mysql.h"
+
+#ifndef HAVE_VIO /* is Vio enabled */
+
+#include <errno.h>
+#include <my_sys.h>
+#include <violite.h>
+#include <my_sys.h>
+#include <my_net.h>
+#include <m_string.h>
+#include <dbug.h>
+#include <assert.h>
+
+#ifndef __WIN__
+#define HANDLE void *
+#endif
+
+struct st_vio
+{
+ my_socket sd; /* my_socket - real or imaginary */
+ HANDLE hPipe;
+ my_bool localhost; /* Are we from localhost? */
+ int fcntl_mode; /* Buffered fcntl(sd,F_GETFL) */
+ struct sockaddr_in local; /* Local internet address */
+ struct sockaddr_in remote; /* Remote internet address */
+ enum enum_vio_type type; /* Type of connection */
+ char desc[30]; /* String description */
+ void *dest_thd;
+ char *packets, **last_packet;
+ char *where_in_packet, *end_of_packet;
+ my_bool reading;
+ MEM_ROOT root;
+};
+
+/* Initialize the communication buffer */
+
+Vio *vio_new(my_socket sd, enum enum_vio_type type, my_bool localhost)
+{
+ Vio * vio = NULL;
+ vio = (Vio *) my_malloc (sizeof(*vio),MYF(MY_WME|MY_ZEROFILL));
+ if (vio)
+ {
+ init_alloc_root(&vio->root, 8192, 8192);
+ vio->root.min_malloc = sizeof(char *) + 4;
+ vio->last_packet = &vio->packets;
+ }
+ return (vio);
+}
+
+
+#ifdef __WIN__
+
+Vio *vio_new_win32pipe(HANDLE hPipe)
+{
+ return (NULL);
+}
+
+#endif
+
+void vio_delete(Vio * vio)
+{
+ if (vio)
+ {
+ if (vio->type != VIO_CLOSED) vio_close(vio);
+ free_root(&vio->root, MYF(0));
+ my_free((gptr)vio, MYF(0));
+ }
+}
+
+void vio_reset(Vio *vio)
+{
+ free_root(&vio->root, MYF(MY_KEEP_PREALLOC));
+ vio->packets = vio->where_in_packet = vio->end_of_packet = 0;
+ vio->last_packet = &vio->packets;
+}
+
+int vio_errno(Vio *vio __attribute__((unused)))
+{
+ return socket_errno; /* On Win32 this mapped to WSAGetLastError() */
+}
+
+int vio_read(Vio * vio, gptr buf, int size)
+{
+ vio->reading = 1;
+ if (vio->where_in_packet >= vio->end_of_packet)
+ {
+ DBUG_ASSERT(vio->packets);
+ vio->where_in_packet = vio->packets + sizeof(char *) + 4;
+ vio->end_of_packet = vio->where_in_packet +
+ uint4korr(vio->packets + sizeof(char *));
+ vio->packets = *(char **)vio->packets;
+ }
+ if (vio->where_in_packet + size > vio->end_of_packet)
+ size = vio->end_of_packet - vio->where_in_packet;
+ memcpy(buf, vio->where_in_packet, size);
+ vio->where_in_packet += size;
+ return (size);
+}
+
+int vio_write(Vio * vio, const gptr buf, int size)
+{
+ char *packet;
+ if (vio->reading)
+ {
+ vio->reading = 0;
+ vio_reset(vio);
+ }
+ if ((packet = alloc_root(&vio->root, sizeof(char*) + 4 + size)))
+ {
+ *vio->last_packet = packet;
+ vio->last_packet = (char **)packet;
+ *((char **)packet) = 0; /* Set forward link to 0 */
+ packet += sizeof(char *);
+ int4store(packet, size);
+ memcpy(packet + 4, buf, size);
+ }
+ else
+ size= -1;
+ return (size);
+}
+
+int vio_blocking(Vio * vio, my_bool set_blocking_mode)
+{
+ return (0);
+}
+
+my_bool
+vio_is_blocking(Vio * vio)
+{
+ return(0);
+}
+
+int vio_fastsend(Vio * vio)
+{
+ return(0);
+}
+
+int vio_keepalive(Vio* vio, my_bool set_keep_alive)
+{
+ return (0);
+}
+
+
+my_bool
+vio_should_retry(Vio * vio __attribute__((unused)))
+{
+ int en = socket_errno;
+ return (en == SOCKET_EAGAIN || en == SOCKET_EINTR ||
+ en == SOCKET_EWOULDBLOCK);
+}
+
+
+int vio_close(Vio * vio)
+{
+ return(0);
+}
+
+
+const char *vio_description(Vio * vio)
+{
+ return "embedded vio";
+}
+
+enum enum_vio_type vio_type(Vio* vio)
+{
+ return VIO_CLOSED;
+}
+
+my_socket vio_fd(Vio* vio)
+{
+ return 0;
+}
+
+
+my_bool vio_peer_addr(Vio * vio, char *buf)
+{
+ return(0);
+}
+
+
+void vio_in_addr(Vio *vio, struct in_addr *in)
+{
+}
+
+my_bool vio_poll_read(Vio *vio,uint timeout)
+{
+ return 0;
+}
+
+#endif /* HAVE_VIO */
diff --git a/libmysqld/libmysqld.c b/libmysqld/libmysqld.c
new file mode 100644
index 00000000000..82928434cc6
--- /dev/null
+++ b/libmysqld/libmysqld.c
@@ -0,0 +1,2091 @@
+/* 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 */
+
+#include "embedded_priv.h"
+#include <my_sys.h>
+#include <mysys_err.h>
+#include <m_string.h>
+#include <m_ctype.h>
+#include "errmsg.h"
+#include <violite.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <time.h>
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#if !defined(MSDOS) && !defined(__WIN__)
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#ifdef HAVE_SELECT_H
+# include <select.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#endif
+#ifdef HAVE_SYS_UN_H
+# include <sys/un.h>
+#endif
+#ifndef INADDR_NONE
+#define INADDR_NONE -1
+#endif
+
+static my_bool mysql_client_init=0;
+uint mysql_port=0;
+my_string mysql_unix_port=0;
+
+#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_TRANSACTIONS)
+
+#if defined(MSDOS) || defined(__WIN__)
+#define ERRNO WSAGetLastError()
+#define perror(A)
+#else
+#include <errno.h>
+#define ERRNO errno
+#define SOCKET_ERROR -1
+#define closesocket(A) close(A)
+#endif
+
+static void mysql_once_init(void);
+static MYSQL_DATA *read_rows (MYSQL *mysql,MYSQL_FIELD *fields,
+ uint field_count);
+static int read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row,
+ ulong *lengths);
+static void end_server(MYSQL *mysql);
+static void read_user_name(char *name);
+static void append_wild(char *to,char *end,const char *wild);
+static int send_file_to_server(MYSQL *mysql,const char *filename);
+static ulong mysql_sub_escape_string(CHARSET_INFO *charset_info, char *to,
+ const char *from, ulong length);
+
+#define init_sigpipe_variables
+#define set_sigpipe(mysql)
+#define reset_sigpipe(mysql)
+
+/*****************************************************************************
+** read a packet from server. Give error message if socket was down
+** or packet is an error message
+*****************************************************************************/
+
+ulong
+net_safe_read(MYSQL *mysql)
+{
+ NET *net= &mysql->net;
+ uint len=0;
+ //init_sigpipe_variables
+ /* Don't give sigpipe errors if the client doesn't want them */
+ set_sigpipe(mysql);
+ if (net->vio != 0)
+ len=my_net_read(net);
+ reset_sigpipe(mysql);
+ if (len == packet_error || len == 0)
+ {
+ DBUG_PRINT("error",("Wrong connection or packet. fd: %s len: %d",
+ vio_description(net->vio),len));
+ end_server(mysql);
+ net->last_errno=(net->last_errno == ER_NET_PACKET_TOO_LARGE ?
+ CR_NET_PACKET_TOO_LARGE:
+ CR_SERVER_LOST);
+ strmov(net->last_error,ER(net->last_errno));
+ return(packet_error);
+ }
+ if (net->read_pos[0] == 255)
+ {
+
+ if (len > 3)
+ {
+ char *pos=(char*) net->read_pos+1;
+ if (mysql->protocol_version > 9)
+ { /* New client protocol */
+ net->last_errno=uint2korr(pos);
+ pos+=2;
+ len-=2;
+ }
+ else
+ {
+ net->last_errno=CR_UNKNOWN_ERROR;
+ len--;
+ }
+ (void) strmake(net->last_error,(char*) pos,
+ min(len,sizeof(net->last_error)-1));
+ }
+ else
+ {
+ net->last_errno=CR_UNKNOWN_ERROR;
+ (void) strmov(net->last_error,ER(net->last_errno));
+ }
+ DBUG_PRINT("error",("Got error: %d (%s)", net->last_errno,
+ net->last_error));
+ return(packet_error);
+ }
+ return len;
+}
+
+
+/* Get the length of next field. Change parameter to point at fieldstart */
+static ulong
+net_field_length(uchar **packet)
+{
+ reg1 uchar *pos= *packet;
+ if (*pos < 251)
+ {
+ (*packet)++;
+ return (ulong) *pos;
+ }
+ if (*pos == 251)
+ {
+ (*packet)++;
+ return NULL_LENGTH;
+ }
+ if (*pos == 252)
+ {
+ (*packet)+=3;
+ return (ulong) uint2korr(pos+1);
+ }
+ if (*pos == 253)
+ {
+ (*packet)+=4;
+ return (ulong) uint3korr(pos+1);
+ }
+ (*packet)+=9; /* Must be 254 when here */
+ return (ulong) uint4korr(pos+1);
+}
+
+/* Same as above, but returns ulonglong values */
+
+static my_ulonglong
+net_field_length_ll(uchar **packet)
+{
+ reg1 uchar *pos= *packet;
+ if (*pos < 251)
+ {
+ (*packet)++;
+ return (my_ulonglong) *pos;
+ }
+ if (*pos == 251)
+ {
+ (*packet)++;
+ return (my_ulonglong) NULL_LENGTH;
+ }
+ if (*pos == 252)
+ {
+ (*packet)+=3;
+ return (my_ulonglong) uint2korr(pos+1);
+ }
+ if (*pos == 253)
+ {
+ (*packet)+=4;
+ return (my_ulonglong) uint3korr(pos+1);
+ }
+ (*packet)+=9; /* Must be 254 when here */
+#ifdef NO_CLIENT_LONGLONG
+ return (my_ulonglong) uint4korr(pos+1);
+#else
+ return (my_ulonglong) uint8korr(pos+1);
+#endif
+}
+
+
+static void free_rows(MYSQL_DATA *cur)
+{
+ if (cur)
+ {
+ free_root(&cur->alloc,MYF(0));
+ my_free((gptr) cur,MYF(0));
+ }
+}
+
+
+int
+simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg,
+ ulong length, my_bool skipp_check)
+{
+ NET *net= &mysql->net;
+ int result= -1;
+
+ /* Check that we are calling the client functions in right order */
+ if (mysql->status != MYSQL_STATUS_READY)
+ {
+ strmov(net->last_error,ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC));
+ goto end;
+ }
+
+ /* Clear result variables */
+ mysql->net.last_error[0]=0;
+ mysql->net.last_errno=0;
+ mysql->info=0;
+ mysql->affected_rows= ~(my_ulonglong) 0;
+
+ /* Clear receive buffer and vio packet list */
+ net_clear(net);
+ vio_reset(net->vio);
+
+ result = lib_dispatch_command(command, net, arg,length);
+ if (!skipp_check)
+ result= ((mysql->packet_length=net_safe_read(mysql)) == packet_error ?
+ -1 : 0);
+ end:
+ return result;
+}
+
+
+static void free_old_query(MYSQL *mysql)
+{
+ DBUG_ENTER("free_old_query");
+ if (mysql->fields)
+ free_root(&mysql->field_alloc,MYF(0));
+ init_alloc_root(&mysql->field_alloc,8192,0); /* Assume rowlength < 8192 */
+ mysql->fields=0;
+ mysql->field_count=0; /* For API */
+ DBUG_VOID_RETURN;
+}
+
+#ifdef HAVE_GETPWUID
+struct passwd *getpwuid(uid_t);
+char* getlogin(void);
+#endif
+
+#if !defined(MSDOS) && ! defined(VMS) && !defined(__WIN__)
+static void read_user_name(char *name)
+{
+ DBUG_ENTER("read_user_name");
+ if (geteuid() == 0)
+ (void) strmov(name,"root"); /* allow use of surun */
+ else
+ {
+#ifdef HAVE_GETPWUID
+ struct passwd *skr;
+ const char *str;
+/*#ifdef __cplusplus
+ extern "C" struct passwd *getpwuid(uid_t);
+ extern "C" { char* getlogin(void); }
+#else
+ char * getlogin();
+ struct passwd *getpwuid(uid_t);
+#endif
+*/
+ if ((str=getlogin()) == NULL)
+ {
+ if ((skr=getpwuid(geteuid())) != NULL)
+ str=skr->pw_name;
+ else if (!(str=getenv("USER")) && !(str=getenv("LOGNAME")) &&
+ !(str=getenv("LOGIN")))
+ str="UNKNOWN_USER";
+ }
+ (void) strmake(name,str,USERNAME_LENGTH);
+#elif HAVE_CUSERID
+ (void) cuserid(name);
+#else
+ strmov(name,"UNKNOWN_USER");
+#endif
+ }
+ DBUG_VOID_RETURN;
+}
+
+#else /* If MSDOS || VMS */
+
+static void read_user_name(char *name)
+{
+ char *str=getenv("USER");
+ strmov(name,str ? str : "ODBC"); /* ODBC will send user variable */
+}
+
+#endif
+
+#ifdef __WIN__
+static my_bool is_NT(void)
+{
+ char *os=getenv("OS");
+ return (os && !strcmp(os, "Windows_NT")) ? 1 : 0;
+}
+#endif
+
+/*
+** Expand wildcard to a sql string
+*/
+
+static void
+append_wild(char *to, char *end, const char *wild)
+{
+ end-=5; /* Some extra */
+ if (wild && wild[0])
+ {
+ to=strmov(to," like '");
+ while (*wild && to < end)
+ {
+ if (*wild == '\\' || *wild == '\'')
+ *to++='\\';
+ *to++= *wild++;
+ }
+ if (*wild) /* Too small buffer */
+ *to++='%'; /* Nicer this way */
+ to[0]='\'';
+ to[1]=0;
+ }
+}
+
+
+
+/**************************************************************************
+** Init debugging if MYSQL_DEBUG environment variable is found
+**************************************************************************/
+
+void STDCALL
+mysql_debug(const char *debug)
+{
+#ifndef DBUG_OFF
+ char *env;
+ if (_db_on_)
+ return; /* Already using debugging */
+ if (debug)
+ {
+ DEBUGGER_ON;
+ DBUG_PUSH(debug);
+ }
+ else if ((env = getenv("MYSQL_DEBUG")))
+ {
+ DEBUGGER_ON;
+ DBUG_PUSH(env);
+#if !defined(_WINVER) && !defined(WINVER)
+ puts("\n-------------------------------------------------------");
+ puts("MYSQL_DEBUG found. libmysql started with the following:");
+ puts(env);
+ puts("-------------------------------------------------------\n");
+#else
+ {
+ char buff[80];
+ strmov(strmov(buff,"libmysql: "),env);
+ MessageBox((HWND) 0,"Debugging variable MYSQL_DEBUG used",buff,MB_OK);
+ }
+#endif
+ }
+#endif
+}
+
+/**************************************************************************
+** Shut down connection
+**************************************************************************/
+
+static void
+end_server(MYSQL *mysql)
+{
+ DBUG_ENTER("end_server");
+ if (mysql->net.vio != 0)
+ {
+ end_embedded_connection(&mysql->net);
+ mysql->net.vio= 0; /* Marker */
+ }
+ net_end(&mysql->net);
+ free_old_query(mysql);
+ DBUG_VOID_RETURN;
+}
+
+
+void STDCALL
+mysql_free_result(MYSQL_RES *result)
+{
+ DBUG_ENTER("mysql_free_result");
+ DBUG_PRINT("enter",("mysql_res: %lx",result));
+ if (result)
+ {
+ if (result->handle && result->handle->status == MYSQL_STATUS_USE_RESULT)
+ {
+ DBUG_PRINT("warning",("Not all rows in set were read; Ignoring rows"));
+ for (;;)
+ {
+ uint pkt_len;
+ if ((pkt_len=(uint) net_safe_read(result->handle)) == packet_error)
+ break;
+ if (pkt_len == 1 && result->handle->net.read_pos[0] == 254)
+ break; /* End of data */
+ }
+ result->handle->status=MYSQL_STATUS_READY;
+ }
+ free_rows(result->data);
+ if (result->fields)
+ free_root(&result->field_alloc,MYF(0));
+ if (result->row)
+ my_free((gptr) result->row,MYF(0));
+ my_free((gptr) result,MYF(0));
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/****************************************************************************
+** Get options from my.cnf
+****************************************************************************/
+
+static const char *default_options[]=
+{"port","socket","compress","password","pipe", "timeout", "user",
+ "init-command", "host", "database", "debug", "return-found-rows",
+ "ssl_key" ,"ssl_cert" ,"ssl_ca" ,"ssl_capath",
+ "character-set-dir", "default-character-set",
+ NullS
+};
+
+static TYPELIB option_types={array_elements(default_options)-1,
+ "options",default_options};
+
+static void mysql_read_default_options(struct st_mysql_options *options,
+ const char *filename,const char *group)
+{
+ int argc;
+ char *argv_buff[1],**argv;
+ const char *groups[3];
+ DBUG_ENTER("mysql_read_default_options");
+ DBUG_PRINT("enter",("file: %s group: %s",filename,group ? group :"NULL"));
+
+ argc=1; argv=argv_buff; argv_buff[0]= (char*) "client";
+ groups[0]= (char*) "client"; groups[1]= (char*) group; groups[2]=0;
+
+ load_defaults(filename, groups, &argc, &argv);
+ if (argc != 1) /* If some default option */
+ {
+ char **option=argv;
+ while (*++option)
+ {
+ /* DBUG_PRINT("info",("option: %s",option[0])); */
+ if (option[0][0] == '-' && option[0][1] == '-')
+ {
+ char *end=strcend(*option,'=');
+ char *opt_arg=0;
+ if (*end)
+ {
+ opt_arg=end+1;
+ *end=0; /* Remove '=' */
+ }
+ switch (find_type(*option+2,&option_types,2)) {
+ case 1: /* port */
+ if (opt_arg)
+ options->port=atoi(opt_arg);
+ break;
+ case 2: /* socket */
+ if (opt_arg)
+ {
+ my_free(options->unix_socket,MYF(MY_ALLOW_ZERO_PTR));
+ options->unix_socket=my_strdup(opt_arg,MYF(MY_WME));
+ }
+ break;
+ case 3: /* compress */
+ options->compress=1;
+ break;
+ case 4: /* password */
+ if (opt_arg)
+ {
+ my_free(options->password,MYF(MY_ALLOW_ZERO_PTR));
+ options->password=my_strdup(opt_arg,MYF(MY_WME));
+ }
+ break;
+ case 5: /* pipe */
+ options->named_pipe=1; /* Force named pipe */
+ break;
+ case 6: /* timeout */
+ if (opt_arg)
+ options->connect_timeout=atoi(opt_arg);
+ break;
+ case 7: /* user */
+ if (opt_arg)
+ {
+ my_free(options->user,MYF(MY_ALLOW_ZERO_PTR));
+ options->user=my_strdup(opt_arg,MYF(MY_WME));
+ }
+ break;
+ case 8: /* init-command */
+ if (opt_arg)
+ {
+ my_free(options->init_command,MYF(MY_ALLOW_ZERO_PTR));
+ options->init_command=my_strdup(opt_arg,MYF(MY_WME));
+ }
+ break;
+ case 9: /* host */
+ if (opt_arg)
+ {
+ my_free(options->host,MYF(MY_ALLOW_ZERO_PTR));
+ options->host=my_strdup(opt_arg,MYF(MY_WME));
+ }
+ break;
+ case 10: /* database */
+ if (opt_arg)
+ {
+ my_free(options->db,MYF(MY_ALLOW_ZERO_PTR));
+ options->db=my_strdup(opt_arg,MYF(MY_WME));
+ }
+ break;
+ case 11: /* debug */
+ mysql_debug(opt_arg ? opt_arg : "d:t:o,/tmp/client.trace");
+ break;
+ case 12: /* return-found-rows */
+ options->client_flag|=CLIENT_FOUND_ROWS;
+ break;
+ case 13: /* Ignore SSL options */
+ case 14:
+ case 15:
+ case 16:
+ break;
+ case 17: /* charset-lib */
+ my_free(options->charset_dir,MYF(MY_ALLOW_ZERO_PTR));
+ options->charset_dir = my_strdup(opt_arg, MYF(MY_WME));
+ break;
+ case 18:
+ my_free(options->charset_name,MYF(MY_ALLOW_ZERO_PTR));
+ options->charset_name = my_strdup(opt_arg, MYF(MY_WME));
+ break;
+ default:
+ DBUG_PRINT("warning",("unknown option: %s",option[0]));
+ }
+ }
+ }
+ }
+ free_defaults(argv);
+ DBUG_VOID_RETURN;
+}
+
+
+/***************************************************************************
+** Change field rows to field structs
+***************************************************************************/
+
+static MYSQL_FIELD *
+unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields,
+ my_bool default_value, my_bool long_flag_protocol)
+{
+ MYSQL_ROWS *row;
+ MYSQL_FIELD *field,*result;
+ DBUG_ENTER("unpack_fields");
+
+ field=result=(MYSQL_FIELD*) alloc_root(alloc,sizeof(MYSQL_FIELD)*fields);
+ if (!result)
+ DBUG_RETURN(0);
+
+ for (row=data->data; row ; row = row->next,field++)
+ {
+ field->table= strdup_root(alloc,(char*) row->data[0]);
+ field->name= strdup_root(alloc,(char*) row->data[1]);
+ field->length= (uint) uint3korr(row->data[2]);
+ field->type= (enum enum_field_types) (uchar) row->data[3][0];
+ if (long_flag_protocol)
+ {
+ field->flags= uint2korr(row->data[4]);
+ field->decimals=(uint) (uchar) row->data[4][2];
+ }
+ else
+ {
+ field->flags= (uint) (uchar) row->data[4][0];
+ field->decimals=(uint) (uchar) row->data[4][1];
+ }
+ if (INTERNAL_NUM_FIELD(field))
+ field->flags|= NUM_FLAG;
+ if (default_value && row->data[5])
+ field->def=strdup_root(alloc,(char*) row->data[5]);
+ else
+ field->def=0;
+ field->max_length= 0;
+ }
+ free_rows(data); /* Free old data */
+ DBUG_RETURN(result);
+}
+
+
+/* Read all rows (fields or data) from server */
+
+static MYSQL_DATA *read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
+ uint fields)
+{
+ uint field,pkt_len;
+ ulong len;
+ uchar *cp;
+ char *to;
+ MYSQL_DATA *result;
+ MYSQL_ROWS **prev_ptr,*cur;
+ NET *net = &mysql->net;
+ DBUG_ENTER("read_rows");
+
+ if ((pkt_len=(uint) net_safe_read(mysql)) == packet_error)
+ DBUG_RETURN(0);
+ if (!(result=(MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA),
+ MYF(MY_WME | MY_ZEROFILL))))
+ {
+ net->last_errno=CR_OUT_OF_MEMORY;
+ strmov(net->last_error,ER(net->last_errno));
+ DBUG_RETURN(0);
+ }
+ init_alloc_root(&result->alloc,8192,0); /* Assume rowlength < 8192 */
+ result->alloc.min_malloc=sizeof(MYSQL_ROWS);
+ prev_ptr= &result->data;
+ result->rows=0;
+ result->fields=fields;
+
+ while (*(cp=net->read_pos) != 254 || pkt_len != 1)
+ {
+ result->rows++;
+ if (!(cur= (MYSQL_ROWS*) alloc_root(&result->alloc,
+ sizeof(MYSQL_ROWS))) ||
+ !(cur->data= ((MYSQL_ROW)
+ alloc_root(&result->alloc,
+ (fields+1)*sizeof(char *)+pkt_len))))
+ {
+ free_rows(result);
+ net->last_errno=CR_OUT_OF_MEMORY;
+ strmov(net->last_error,ER(net->last_errno));
+ DBUG_RETURN(0);
+ }
+ *prev_ptr=cur;
+ prev_ptr= &cur->next;
+ to= (char*) (cur->data+fields+1);
+ for (field=0 ; field < fields ; field++)
+ {
+ if ((len=(ulong) net_field_length(&cp)) == NULL_LENGTH)
+ { /* null field */
+ cur->data[field] = 0;
+ }
+ else
+ {
+ cur->data[field] = to;
+ memcpy(to,(char*) cp,len); to[len]=0;
+ to+=len+1;
+ cp+=len;
+ if (mysql_fields)
+ {
+ if (mysql_fields[field].max_length < len)
+ mysql_fields[field].max_length=len;
+ }
+ }
+ }
+ cur->data[field]=to; /* End of last field */
+ if ((pkt_len=net_safe_read(mysql)) == packet_error)
+ {
+ free_rows(result);
+ DBUG_RETURN(0);
+ }
+ }
+ *prev_ptr=0; /* last pointer is null */
+ DBUG_PRINT("exit",("Got %d rows",result->rows));
+ DBUG_RETURN(result);
+}
+
+
+/*
+** Read one row. Uses packet buffer as storage for fields.
+** When next packet is read, the previous field values are destroyed
+*/
+
+
+static int
+read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths)
+{
+ uint field;
+ ulong pkt_len,len;
+ uchar *pos,*prev_pos;
+
+ if ((pkt_len=net_safe_read(mysql)) == packet_error)
+ return -1;
+ if (pkt_len == 1 && mysql->net.read_pos[0] == 254)
+ return 1; /* End of data */
+ prev_pos= 0; /* allowed to write at packet[-1] */
+ pos=mysql->net.read_pos;
+ for (field=0 ; field < fields ; field++)
+ {
+ if ((len=(ulong) net_field_length(&pos)) == NULL_LENGTH)
+ { /* null field */
+ row[field] = 0;
+ *lengths++=0;
+ }
+ else
+ {
+ row[field] = (char*) pos;
+ pos+=len;
+ *lengths++=len;
+ }
+ if (prev_pos)
+ *prev_pos=0; /* Terminate prev field */
+ prev_pos=pos;
+ }
+ row[field]=(char*) prev_pos+1; /* End of last field */
+ *prev_pos=0; /* Terminate last field */
+ return 0;
+}
+
+/****************************************************************************
+** Init MySQL structure or allocate one
+****************************************************************************/
+
+MYSQL * STDCALL
+mysql_init(MYSQL *mysql)
+{
+ mysql_once_init();
+ if (!mysql)
+ {
+ if (!(mysql=(MYSQL*) my_malloc(sizeof(*mysql),MYF(MY_WME | MY_ZEROFILL))))
+ return 0;
+ mysql->free_me=1;
+ mysql->net.vio = 0;
+ }
+ else
+ bzero((char*) (mysql),sizeof(*(mysql)));
+ return mysql;
+}
+
+
+static void mysql_once_init()
+{
+ if (!mysql_client_init)
+ {
+ mysql_client_init=1;
+ my_init(); /* Will init threads */
+ init_client_errs();
+ mysql_port = MYSQL_PORT;
+ mysql_debug(NullS);
+ }
+#ifdef THREAD
+ else
+ my_thread_init(); /* Init if new thread */
+#endif
+}
+
+/**************************************************************************
+** Connect to sql server
+** If host == 0 then use localhost
+**************************************************************************/
+
+MYSQL * STDCALL
+mysql_connect(MYSQL *mysql,const char *host,
+ const char *user, const char *passwd)
+{
+ MYSQL *res;
+ mysql=mysql_init(mysql); /* Make it thread safe */
+ {
+ DBUG_ENTER("mysql_connect");
+ if (!(res=mysql_real_connect(mysql,host,user,passwd,NullS,0,NullS,0)))
+ {
+ if (mysql->free_me)
+ my_free((gptr) mysql,MYF(0));
+ }
+ DBUG_RETURN(res);
+ }
+}
+
+
+/*
+** Note that the mysql argument must be initialized with mysql_init()
+** before calling mysql_real_connect !
+*/
+
+MYSQL * STDCALL
+mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
+ const char *passwd, const char *db,
+ uint port, const char *unix_socket,uint client_flag)
+{
+ char buff[100],charset_name_buff[16],*end,*host_info, *charset_name;
+ uint pkt_length;
+ NET *net= &mysql->net;
+ DBUG_ENTER("mysql_real_connect");
+ DBUG_PRINT("enter",("host: %s db: %s user: %s",
+ host ? host : "(Null)",
+ db ? db : "(Null)",
+ user ? user : "(Null)"));
+
+ net->vio = 0; /* If something goes wrong */
+ /* use default options */
+ if (mysql->options.my_cnf_file || mysql->options.my_cnf_group)
+ {
+ mysql_read_default_options(&mysql->options,
+ (mysql->options.my_cnf_file ?
+ mysql->options.my_cnf_file : "my"),
+ mysql->options.my_cnf_group);
+ my_free(mysql->options.my_cnf_file,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.my_cnf_group,MYF(MY_ALLOW_ZERO_PTR));
+ mysql->options.my_cnf_file=mysql->options.my_cnf_group=0;
+ }
+
+ /* Some empty-string-tests are done because of ODBC */
+ if (!host || !host[0])
+ host=mysql->options.host;
+ if (!user || !user[0])
+ user=mysql->options.user;
+ if (!passwd)
+ {
+ passwd=mysql->options.password;
+ }
+ if (!db || !db[0])
+ db=mysql->options.db;
+ port=0;
+ unix_socket=0;
+ mysql->reconnect=1; /* Reconnect as default */
+ mysql->server_status=SERVER_STATUS_AUTOCOMMIT;
+ host_info=(char*) ER(CR_EMBEDDED_CONNECTION);
+ if (my_net_init(net, net->vio))
+ {
+ vio_delete(net->vio);
+ net->last_errno=CR_OUT_OF_MEMORY;
+ strmov(net->last_error,ER(net->last_errno));
+ goto error;
+ }
+
+ /* Get version info */
+ mysql->protocol_version= PROTOCOL_VERSION; /* Assume this */
+ start_embedded_connection(net);
+
+ if ((pkt_length=net_safe_read(mysql)) == packet_error)
+ goto error;
+
+ /* Check if version of protocoll matches current one */
+
+ mysql->protocol_version= net->read_pos[0];
+ DBUG_DUMP("packet",(char*) net->read_pos,10);
+ DBUG_PRINT("info",("mysql protocol version %d, server=%d",
+ PROTOCOL_VERSION, mysql->protocol_version));
+ if (mysql->protocol_version != PROTOCOL_VERSION &&
+ mysql->protocol_version != PROTOCOL_VERSION-1)
+ {
+ net->last_errno= CR_VERSION_ERROR;
+ sprintf(net->last_error, ER(CR_VERSION_ERROR), mysql->protocol_version,
+ PROTOCOL_VERSION);
+ goto error;
+ }
+ end=strend((char*) net->read_pos+1);
+ mysql->thread_id=uint4korr(end+1);
+ end+=5;
+ strmake(mysql->scramble_buff,end,8);
+ end+=9;
+ if (pkt_length >= (uint) (end+1 - (char*) net->read_pos))
+ mysql->server_capabilities=uint2korr(end);
+ if (pkt_length >= (uint) (end+18 - (char*) net->read_pos))
+ {
+ /* New protocol with 16 bytes to describe server characteristics */
+ mysql->server_language=end[2];
+ mysql->server_status=uint2korr(end+3);
+ }
+
+ /* Set character set */
+ if ((charset_name=mysql->options.charset_name))
+ {
+ const char *save=charsets_dir;
+ if (mysql->options.charset_dir)
+ charsets_dir=mysql->options.charset_dir;
+ mysql->charset=get_charset_by_name(mysql->options.charset_name,
+ MYF(MY_WME));
+ charsets_dir=save;
+ }
+ else if (mysql->server_language)
+ {
+ charset_name=charset_name_buff;
+ sprintf(charset_name,"%d",mysql->server_language); /* In case of errors */
+ mysql->charset=get_charset((uint8) mysql->server_language, MYF(MY_WME));
+ }
+ else
+ mysql->charset=default_charset_info;
+
+ if (!mysql->charset)
+ {
+ net->last_errno=CR_CANT_READ_CHARSET;
+ if (mysql->options.charset_dir)
+ sprintf(net->last_error,ER(net->last_errno),
+ charset_name ? charset_name : "unknown",
+ mysql->options.charset_dir);
+ else
+ {
+ char cs_dir_name[FN_REFLEN];
+ get_charsets_dir(cs_dir_name);
+ sprintf(net->last_error,ER(net->last_errno),
+ charset_name ? charset_name : "unknown",
+ cs_dir_name);
+ }
+ goto error;
+ }
+
+ /* Save connection information */
+ if (!user) user="";
+ if (!passwd) passwd="";
+ host=LOCAL_HOST;
+ if (!my_multi_malloc(MYF(0),
+ &mysql->host_info, (uint) strlen(host_info)+1,
+ &mysql->host, (uint) strlen(host)+1,
+ &mysql->unix_socket,unix_socket ?
+ (uint) strlen(unix_socket)+1 : (uint) 1,
+ &mysql->server_version,
+ (uint) (end - (char*) net->read_pos),
+ NullS) ||
+ !(mysql->user=my_strdup(user,MYF(0))) ||
+ !(mysql->passwd=my_strdup(passwd,MYF(0))))
+ {
+ strmov(net->last_error, ER(net->last_errno=CR_OUT_OF_MEMORY));
+ goto error;
+ }
+ strmov(mysql->host_info,host_info);
+ strmov(mysql->host,host);
+ if (unix_socket)
+ strmov(mysql->unix_socket,unix_socket);
+ else
+ mysql->unix_socket=0;
+ strmov(mysql->server_version,(char*) net->read_pos+1);
+ mysql->port=port;
+ mysql->client_flag=client_flag | mysql->options.client_flag;
+ DBUG_PRINT("info",("Server version = '%s' capabilites: %ld status: %d",
+ mysql->server_version,mysql->server_capabilities,
+ mysql->server_status));
+
+ /* Send client information for access check */
+ client_flag|=CLIENT_CAPABILITIES;
+ client_flag&= ~CLIENT_COMPRESS;
+ if (db)
+ client_flag|=CLIENT_CONNECT_WITH_DB;
+ int2store(buff,client_flag);
+ mysql->client_flag=client_flag;
+
+
+ int3store(buff+2,max_allowed_packet);
+ if (user && user[0])
+ strmake(buff+5,user,32);
+ else
+ read_user_name((char*) buff+5);
+#ifdef _CUSTOMCONFIG_
+#include "_cust_libmysql.h";
+#endif
+ DBUG_PRINT("info",("user: %s",buff+5));
+ end=scramble(strend(buff+5)+1, mysql->scramble_buff, passwd,
+ (my_bool) (mysql->protocol_version == 9));
+
+ if (db)
+ {
+ end=strmov(end+1,db);
+ mysql->db=my_strdup(db,MYF(MY_WME));
+ db=0;
+ }
+ if (my_net_write(net,buff,(ulong) (end-buff)) || net_flush(net))
+ goto error;
+
+ lib_connection_phase(net,2);
+
+ if( net_safe_read(mysql) == packet_error)
+ goto error;
+ if (db && mysql_select_db(mysql,db))
+ goto error;
+ if (mysql->options.init_command)
+ {
+ my_bool reconnect=mysql->reconnect;
+ mysql->reconnect=0;
+ if (mysql_query(mysql,mysql->options.init_command))
+ goto error;
+ mysql_free_result(mysql_use_result(mysql));
+ mysql->reconnect=reconnect;
+ }
+
+ DBUG_PRINT("exit",("Mysql handler: %lx",mysql));
+ reset_sigpipe(mysql);
+ DBUG_RETURN(mysql);
+
+error:
+ reset_sigpipe(mysql);
+ DBUG_PRINT("error",("message: %u (%s)",net->last_errno,net->last_error));
+ {
+ /* Free alloced memory */
+ my_bool free_me=mysql->free_me;
+ end_server(mysql);
+ mysql->free_me=0;
+ mysql_close(mysql);
+ mysql->free_me=free_me;
+ }
+ DBUG_RETURN(0);
+}
+
+
+/**************************************************************************
+** Change user and database
+**************************************************************************/
+
+my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
+ const char *passwd, const char *db)
+{
+ char buff[512],*pos=buff;
+ DBUG_ENTER("mysql_change_user");
+
+ if (!user)
+ user="";
+ if (!passwd)
+ passwd="";
+
+ pos=strmov(pos,user)+1;
+ pos=scramble(pos, mysql->scramble_buff, passwd,
+ (my_bool) (mysql->protocol_version == 9));
+ pos=strmov(pos+1,db ? db : "");
+ if (simple_command(mysql,COM_CHANGE_USER, buff,(ulong) (pos-buff),0))
+ DBUG_RETURN(1);
+
+ my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->passwd,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR));
+
+ mysql->user= my_strdup(user,MYF(MY_WME));
+ mysql->passwd=my_strdup(passwd,MYF(MY_WME));
+ mysql->db= db ? my_strdup(db,MYF(MY_WME)) : 0;
+ DBUG_RETURN(0);
+}
+
+
+/**************************************************************************
+** Set current database
+**************************************************************************/
+
+int STDCALL
+mysql_select_db(MYSQL *mysql, const char *db)
+{
+ int error;
+ DBUG_ENTER("mysql_select_db");
+ DBUG_PRINT("enter",("db: '%s'",db));
+
+ if ((error=simple_command(mysql,COM_INIT_DB,db,(ulong) strlen(db),0)))
+ DBUG_RETURN(error);
+ my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR));
+ mysql->db=my_strdup(db,MYF(MY_WME));
+ DBUG_RETURN(0);
+}
+
+
+/*************************************************************************
+** Send a QUIT to the server and close the connection
+** If handle is alloced by mysql connect free it.
+*************************************************************************/
+
+void STDCALL
+mysql_close(MYSQL *mysql)
+{
+ DBUG_ENTER("mysql_close");
+ if (mysql) /* Some simple safety */
+ {
+ if (mysql->net.vio != 0)
+ {
+ free_old_query(mysql);
+ mysql->status=MYSQL_STATUS_READY; /* Force command */
+ simple_command(mysql,COM_QUIT,"",0,1);
+ end_server(mysql);
+ }
+ my_free((gptr) mysql->host_info,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->passwd,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.init_command,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.user,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.host,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.password,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.unix_socket,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.db,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.my_cnf_file,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.my_cnf_group,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.charset_dir,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.charset_name,MYF(MY_ALLOW_ZERO_PTR));
+ /* Clear pointers for better safety */
+ mysql->host_info=mysql->user=mysql->passwd=mysql->db=0;
+ bzero((char*) &mysql->options,sizeof(mysql->options));
+ mysql->net.vio = 0;
+#ifdef HAVE_OPENSSL
+ ((VioConnectorFd*)(mysql->connector_fd))->delete();
+ mysql->connector_fd = 0;
+#endif /* HAVE_OPENSSL */
+ if (mysql->free_me)
+ my_free((gptr) mysql,MYF(0));
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/**************************************************************************
+** Do a query. If query returned rows, free old rows.
+** Read data by mysql_store_result or by repeat call of mysql_fetch_row
+**************************************************************************/
+
+int STDCALL
+mysql_query(MYSQL *mysql, const char *query)
+{
+ return mysql_real_query(mysql,query, (ulong) strlen(query));
+}
+
+int STDCALL
+mysql_send_query(MYSQL* mysql, const char* query, ulong length)
+{
+ return simple_command(mysql, COM_QUERY, query, length, 1);
+}
+
+
+int STDCALL
+mysql_read_query_result(MYSQL *mysql)
+{
+ uchar *pos;
+ ulong field_count;
+ MYSQL_DATA *fields;
+ uint length;
+ DBUG_ENTER("mysql_read_query_result");
+
+ if ((length=net_safe_read(mysql)) == packet_error)
+ DBUG_RETURN(-1);
+ free_old_query(mysql); /* Free old result */
+get_info:
+ pos=(uchar*) mysql->net.read_pos;
+ if ((field_count= net_field_length(&pos)) == 0)
+ {
+ mysql->affected_rows= net_field_length_ll(&pos);
+ mysql->insert_id= net_field_length_ll(&pos);
+ if (mysql->server_capabilities & CLIENT_TRANSACTIONS)
+ {
+ mysql->server_status=uint2korr(pos); pos+=2;
+ }
+ if (pos < mysql->net.read_pos+length && net_field_length(&pos))
+ mysql->info=(char*) pos;
+ DBUG_RETURN(0);
+ }
+ if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */
+ {
+ int error=send_file_to_server(mysql,(char*) pos);
+ if ((length=net_safe_read(mysql)) == packet_error || error)
+ DBUG_RETURN(-1);
+ goto get_info; /* Get info packet */
+ }
+ 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=read_rows(mysql,(MYSQL_FIELD*) 0,5)))
+ DBUG_RETURN(-1);
+ if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,
+ (uint) field_count,0,
+ (my_bool) test(mysql->server_capabilities &
+ CLIENT_LONG_FLAG))))
+ DBUG_RETURN(-1);
+ mysql->status=MYSQL_STATUS_GET_RESULT;
+ mysql->field_count=field_count;
+ DBUG_RETURN(0);
+}
+
+/****************************************************************************
+* A modified version of connect(). connect2() allows you to specify
+* a timeout value, in seconds, that we should wait until we
+* derermine we can't connect to a particular host. If timeout is 0,
+* my_connect() will behave exactly like connect().
+*
+* Base version coded by Steve Bernacki, Jr. <steve@navinet.net>
+*****************************************************************************/
+
+int my_connect(my_socket s, const struct sockaddr *name, uint namelen,
+ uint timeout)
+{
+#if defined(__WIN__) || defined(OS2)
+ return connect(s, (struct sockaddr*) name, namelen);
+#else
+ int flags, res, s_err;
+ SOCKOPT_OPTLEN_TYPE s_err_size = sizeof(uint);
+ fd_set sfds;
+ struct timeval tv;
+ time_t start_time, now_time;
+
+ /* If they passed us a timeout of zero, we should behave
+ * exactly like the normal connect() call does.
+ */
+
+ if (timeout == 0)
+ return connect(s, (struct sockaddr*) name, namelen);
+
+ flags = fcntl(s, F_GETFL, 0); /* Set socket to not block */
+#ifdef O_NONBLOCK
+ fcntl(s, F_SETFL, flags | O_NONBLOCK); /* and save the flags.. */
+#endif
+
+ res = connect(s, (struct sockaddr*) name, namelen);
+ s_err = errno; /* Save the error... */
+ fcntl(s, F_SETFL, flags);
+ if ((res != 0) && (s_err != EINPROGRESS))
+ {
+ errno = s_err; /* Restore it */
+ return(-1);
+ }
+ if (res == 0) /* Connected quickly! */
+ return(0);
+
+ /* Otherwise, our connection is "in progress." We can use
+ * the select() call to wait up to a specified period of time
+ * for the connection to suceed. If select() returns 0
+ * (after waiting howevermany seconds), our socket never became
+ * writable (host is probably unreachable.) Otherwise, if
+ * select() returns 1, then one of two conditions exist:
+ *
+ * 1. An error occured. We use getsockopt() to check for this.
+ * 2. The connection was set up sucessfully: getsockopt() will
+ * return 0 as an error.
+ *
+ * Thanks goes to Andrew Gierth <andrew@erlenstar.demon.co.uk>
+ * who posted this method of timing out a connect() in
+ * comp.unix.programmer on August 15th, 1997.
+ */
+
+ FD_ZERO(&sfds);
+ FD_SET(s, &sfds);
+ /*
+ * select could be interrupted by a signal, and if it is,
+ * the timeout should be adjusted and the select restarted
+ * to work around OSes that don't restart select and
+ * implementations of select that don't adjust tv upon
+ * failure to reflect the time remaining
+ */
+ start_time = time(NULL);
+ for (;;)
+ {
+ tv.tv_sec = (long) timeout;
+ tv.tv_usec = 0;
+ if ((res = select(s+1, NULL, &sfds, NULL, &tv)) >= 0)
+ break;
+ now_time=time(NULL);
+ timeout-= (uint) (now_time - start_time);
+ if (errno != EINTR || (int) timeout <= 0)
+ return -1;
+ }
+
+ /* select() returned something more interesting than zero, let's
+ * see if we have any errors. If the next two statements pass,
+ * we've got an open socket!
+ */
+
+ s_err=0;
+ if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char*) &s_err, &s_err_size) != 0)
+ return(-1);
+
+ if (s_err)
+ { /* getsockopt could succeed */
+ errno = s_err;
+ return(-1); /* but return an error... */
+ }
+ return(0); /* It's all good! */
+#endif
+}
+
+
+int STDCALL
+mysql_real_query(MYSQL *mysql, const char *query, ulong length)
+{
+ DBUG_ENTER("mysql_real_query");
+ DBUG_PRINT("enter",("handle: %lx",mysql));
+ DBUG_PRINT("query",("Query = \"%s\"",query));
+ if (mysql_send_query(mysql, query, length))
+ DBUG_RETURN(-1);
+ DBUG_RETURN(mysql_read_query_result(mysql));
+}
+
+
+static int
+send_file_to_server(MYSQL *mysql, const char *filename)
+{
+ int fd, readcount;
+ char buf[IO_SIZE*15],*tmp_name;
+ DBUG_ENTER("send_file_to_server");
+
+ fn_format(buf,filename,"","",4); /* Convert to client format */
+ if (!(tmp_name=my_strdup(buf,MYF(0))))
+ {
+ strmov(mysql->net.last_error, ER(mysql->net.last_errno=CR_OUT_OF_MEMORY));
+ DBUG_RETURN(-1);
+ }
+ if ((fd = my_open(tmp_name,O_RDONLY, MYF(0))) < 0)
+ {
+ mysql->net.last_errno=EE_FILENOTFOUND;
+ sprintf(buf,EE(mysql->net.last_errno),tmp_name,errno);
+ strmake(mysql->net.last_error,buf,sizeof(mysql->net.last_error)-1);
+ my_net_write(&mysql->net,"",0); net_flush(&mysql->net);
+ my_free(tmp_name,MYF(0));
+ DBUG_RETURN(-1);
+ }
+
+ while ((readcount = (int) my_read(fd,buf,sizeof(buf),MYF(0))) > 0)
+ {
+ if (my_net_write(&mysql->net,buf,readcount))
+ {
+ mysql->net.last_errno=CR_SERVER_LOST;
+ strmov(mysql->net.last_error,ER(mysql->net.last_errno));
+ DBUG_PRINT("error",("Lost connection to MySQL server during LOAD DATA of local file"));
+ (void) my_close(fd,MYF(0));
+ my_free(tmp_name,MYF(0));
+ DBUG_RETURN(-1);
+ }
+ }
+ (void) my_close(fd,MYF(0));
+ /* Send empty packet to mark end of file */
+ if (my_net_write(&mysql->net,"",0) || net_flush(&mysql->net))
+ {
+ mysql->net.last_errno=CR_SERVER_LOST;
+ sprintf(mysql->net.last_error,ER(mysql->net.last_errno),errno);
+ my_free(tmp_name,MYF(0));
+ DBUG_RETURN(-1);
+ }
+ if (readcount < 0)
+ {
+ mysql->net.last_errno=EE_READ; /* the errmsg for not entire file read */
+ sprintf(buf,EE(mysql->net.last_errno),tmp_name,errno);
+ strmake(mysql->net.last_error,buf,sizeof(mysql->net.last_error)-1);
+ my_free(tmp_name,MYF(0));
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+/**************************************************************************
+** Alloc result struct for buffered results. All rows are read to buffer.
+** mysql_data_seek may be used.
+**************************************************************************/
+
+MYSQL_RES * STDCALL
+mysql_store_result(MYSQL *mysql)
+{
+ MYSQL_RES *result;
+ DBUG_ENTER("mysql_store_result");
+
+ if (!mysql->fields)
+ DBUG_RETURN(0);
+ if (mysql->status != MYSQL_STATUS_GET_RESULT)
+ {
+ strmov(mysql->net.last_error,
+ ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC));
+ DBUG_RETURN(0);
+ }
+ mysql->status=MYSQL_STATUS_READY; /* server is ready */
+ if (!(result=(MYSQL_RES*) my_malloc(sizeof(MYSQL_RES)+
+ sizeof(ulong)*mysql->field_count,
+ MYF(MY_WME | MY_ZEROFILL))))
+ {
+ mysql->net.last_errno=CR_OUT_OF_MEMORY;
+ strmov(mysql->net.last_error, ER(mysql->net.last_errno));
+ DBUG_RETURN(0);
+ }
+ result->eof=1; /* Marker for buffered */
+ result->lengths=(ulong*) (result+1);
+ if (!(result->data=read_rows(mysql,mysql->fields,mysql->field_count)))
+ {
+ my_free((gptr) result,MYF(0));
+ DBUG_RETURN(0);
+ }
+ mysql->affected_rows= result->row_count= result->data->rows;
+ result->data_cursor= result->data->data;
+ result->fields= mysql->fields;
+ result->field_alloc= mysql->field_alloc;
+ result->field_count= mysql->field_count;
+ result->current_field=0;
+ result->current_row=0; /* Must do a fetch first */
+ mysql->fields=0; /* fields is now in result */
+ DBUG_RETURN(result); /* Data fetched */
+}
+
+
+/**************************************************************************
+** Alloc struct for use with unbuffered reads. Data is fetched by domand
+** when calling to mysql_fetch_row.
+** mysql_data_seek is a noop.
+**
+** No other queries may be specified with the same MYSQL handle.
+** There shouldn't be much processing per row because mysql server shouldn't
+** have to wait for the client (and will not wait more than 30 sec/packet).
+**************************************************************************/
+
+MYSQL_RES * STDCALL
+mysql_use_result(MYSQL *mysql)
+{
+ MYSQL_RES *result;
+ DBUG_ENTER("mysql_use_result");
+
+ if (!mysql->fields)
+ DBUG_RETURN(0);
+ if (mysql->status != MYSQL_STATUS_GET_RESULT)
+ {
+ strmov(mysql->net.last_error,
+ ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC));
+ DBUG_RETURN(0);
+ }
+ if (!(result=(MYSQL_RES*) my_malloc(sizeof(*result)+
+ sizeof(ulong)*mysql->field_count,
+ MYF(MY_WME | MY_ZEROFILL))))
+ DBUG_RETURN(0);
+ result->lengths=(ulong*) (result+1);
+ if (!(result->row=(MYSQL_ROW)
+ my_malloc(sizeof(result->row[0])*(mysql->field_count+1), MYF(MY_WME))))
+ { /* Ptrs: to one row */
+ my_free((gptr) result,MYF(0));
+ DBUG_RETURN(0);
+ }
+ result->fields= mysql->fields;
+ result->field_alloc= mysql->field_alloc;
+ result->field_count= mysql->field_count;
+ result->current_field=0;
+ result->handle= mysql;
+ result->current_row= 0;
+ mysql->fields=0; /* fields is now in result */
+ mysql->status=MYSQL_STATUS_USE_RESULT;
+ DBUG_RETURN(result); /* Data is read to be fetched */
+}
+
+
+
+/**************************************************************************
+** Return next field of the query results
+**************************************************************************/
+
+MYSQL_FIELD * STDCALL
+mysql_fetch_field(MYSQL_RES *result)
+{
+ if (result->current_field >= result->field_count)
+ return(NULL);
+ return &result->fields[result->current_field++];
+}
+
+
+/**************************************************************************
+** Return next row of the query results
+**************************************************************************/
+
+MYSQL_ROW STDCALL
+mysql_fetch_row(MYSQL_RES *res)
+{
+ DBUG_ENTER("mysql_fetch_row");
+ if (!res->data)
+ { /* Unbufferred fetch */
+ if (!res->eof)
+ {
+ if (!(read_one_row(res->handle,res->field_count,res->row, res->lengths)))
+ {
+ res->row_count++;
+ DBUG_RETURN(res->current_row=res->row);
+ }
+ else
+ {
+ DBUG_PRINT("info",("end of data"));
+ res->eof=1;
+ res->handle->status=MYSQL_STATUS_READY;
+ }
+ }
+ DBUG_RETURN((MYSQL_ROW) NULL);
+ }
+ {
+ MYSQL_ROW tmp;
+ if (!res->data_cursor)
+ {
+ DBUG_PRINT("info",("end of data"));
+ DBUG_RETURN(res->current_row=(MYSQL_ROW) NULL);
+ }
+ tmp = res->data_cursor->data;
+ res->data_cursor = res->data_cursor->next;
+ DBUG_RETURN(res->current_row=tmp);
+ }
+}
+
+/**************************************************************************
+** 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)
+{
+ ulong *lengths,*prev_length;
+ byte *start;
+ MYSQL_ROW column,end;
+
+ if (!(column=res->current_row))
+ return 0; /* Something is wrong */
+ if (res->data)
+ {
+ start=0;
+ prev_length=0; /* Keep gcc happy */
+ lengths=res->lengths;
+ for (end=column+res->field_count+1 ; column != end ; column++,lengths++)
+ {
+ if (!*column)
+ {
+ *lengths=0; /* Null */
+ continue;
+ }
+ if (start) /* Found end of prev string */
+ *prev_length= (uint) (*column-start-1);
+ start= *column;
+ prev_length=lengths;
+ }
+ }
+ return res->lengths;
+}
+
+/**************************************************************************
+** Move to a specific row and column
+**************************************************************************/
+
+void STDCALL
+mysql_data_seek(MYSQL_RES *result, my_ulonglong row)
+{
+ MYSQL_ROWS *tmp=0;
+ DBUG_PRINT("info",("mysql_data_seek(%ld)",(long) row));
+ if (result->data)
+ for (tmp=result->data->data; row-- && tmp ; tmp = tmp->next) ;
+ result->current_row=0;
+ result->data_cursor = tmp;
+}
+
+/*************************************************************************
+** put the row or field cursor one a position one got from mysql_row_tell()
+** This doesn't restore any data. The next mysql_fetch_row or
+** mysql_fetch_field will return the next row or field after the last used
+*************************************************************************/
+
+MYSQL_ROW_OFFSET STDCALL
+mysql_row_seek(MYSQL_RES *result, MYSQL_ROW_OFFSET row)
+{
+ MYSQL_ROW_OFFSET return_value=result->data_cursor;
+ result->current_row= 0;
+ result->data_cursor= row;
+ return return_value;
+}
+
+
+MYSQL_FIELD_OFFSET STDCALL
+mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET field_offset)
+{
+ MYSQL_FIELD_OFFSET return_value=result->current_field;
+ result->current_field=field_offset;
+ return return_value;
+}
+
+/*****************************************************************************
+** List all databases
+*****************************************************************************/
+
+MYSQL_RES * STDCALL
+mysql_list_dbs(MYSQL *mysql, const char *wild)
+{
+ char buff[255];
+ DBUG_ENTER("mysql_list_dbs");
+
+ append_wild(strmov(buff,"show databases"),buff+sizeof(buff),wild);
+ if (mysql_query(mysql,buff))
+ DBUG_RETURN(0);
+ DBUG_RETURN (mysql_store_result(mysql));
+}
+
+
+/*****************************************************************************
+** List all tables in a database
+** If wild is given then only the tables matching wild is returned
+*****************************************************************************/
+
+MYSQL_RES * STDCALL
+mysql_list_tables(MYSQL *mysql, const char *wild)
+{
+ char buff[255];
+ DBUG_ENTER("mysql_list_tables");
+
+ append_wild(strmov(buff,"show tables"),buff+sizeof(buff),wild);
+ if (mysql_query(mysql,buff))
+ DBUG_RETURN(0);
+ DBUG_RETURN (mysql_store_result(mysql));
+}
+
+
+/**************************************************************************
+** List all fields in a table
+** If wild is given then only the fields matching wild is returned
+** Instead of this use query:
+** show fields in 'table' like "wild"
+**************************************************************************/
+
+MYSQL_RES * STDCALL
+mysql_list_fields(MYSQL *mysql, const char *table, const char *wild)
+{
+ MYSQL_RES *result;
+ MYSQL_DATA *query;
+ char buff[257],*end;
+ DBUG_ENTER("mysql_list_fields");
+ DBUG_PRINT("enter",("table: '%s' wild: '%s'",table,wild ? wild : ""));
+
+ LINT_INIT(query);
+
+ end=strmake(strmake(buff, table,128)+1,wild ? wild : "",128);
+ if (simple_command(mysql,COM_FIELD_LIST,buff,(uint) (end-buff),1) ||
+ !(query = read_rows(mysql,(MYSQL_FIELD*) 0,6)))
+ DBUG_RETURN(NULL);
+
+ free_old_query(mysql);
+ if (!(result = (MYSQL_RES *) my_malloc(sizeof(MYSQL_RES),
+ MYF(MY_WME | MY_ZEROFILL))))
+ {
+ free_rows(query);
+ DBUG_RETURN(NULL);
+ }
+ result->field_alloc=mysql->field_alloc;
+ mysql->fields=0;
+ result->field_count = (uint) query->rows;
+ result->fields= unpack_fields(query,&result->field_alloc,
+ result->field_count,1,
+ (my_bool) test(mysql->server_capabilities &
+ CLIENT_LONG_FLAG));
+ result->eof=1;
+ DBUG_RETURN(result);
+}
+
+/* List all running processes (threads) in server */
+
+MYSQL_RES * STDCALL
+mysql_list_processes(MYSQL *mysql)
+{
+ MYSQL_DATA *fields;
+ uint field_count;
+ uchar *pos;
+ DBUG_ENTER("mysql_list_processes");
+
+ LINT_INIT(fields);
+ if (simple_command(mysql,COM_PROCESS_INFO,"",0,0))
+ DBUG_RETURN(0);
+ free_old_query(mysql);
+ pos=(uchar*) mysql->net.read_pos;
+ field_count=(uint) net_field_length(&pos);
+ if (!(fields = read_rows(mysql,(MYSQL_FIELD*) 0,5)))
+ DBUG_RETURN(NULL);
+ if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,field_count,0,
+ (my_bool) test(mysql->server_capabilities &
+ CLIENT_LONG_FLAG))))
+ DBUG_RETURN(0);
+ mysql->status=MYSQL_STATUS_GET_RESULT;
+ mysql->field_count=field_count;
+ DBUG_RETURN(mysql_store_result(mysql));
+}
+
+
+int STDCALL
+mysql_create_db(MYSQL *mysql, const char *db)
+{
+ DBUG_ENTER("mysql_createdb");
+ DBUG_PRINT("enter",("db: %s",db));
+ DBUG_RETURN(simple_command(mysql,COM_CREATE_DB,db, (ulong) strlen(db),0));
+}
+
+
+int STDCALL
+mysql_drop_db(MYSQL *mysql, const char *db)
+{
+ DBUG_ENTER("mysql_drop_db");
+ DBUG_PRINT("enter",("db: %s",db));
+ DBUG_RETURN(simple_command(mysql,COM_DROP_DB,db,(ulong) strlen(db),0));
+}
+
+
+int STDCALL
+mysql_shutdown(MYSQL *mysql)
+{
+ DBUG_ENTER("mysql_shutdown");
+ DBUG_RETURN(simple_command(mysql,COM_SHUTDOWN,"",0,0));
+}
+
+
+int STDCALL
+mysql_refresh(MYSQL *mysql,uint options)
+{
+ uchar bits[1];
+ DBUG_ENTER("mysql_refresh");
+ bits[0]= (uchar) options;
+ DBUG_RETURN(simple_command(mysql,COM_REFRESH,(char*) bits,1,0));
+}
+
+int STDCALL
+mysql_kill(MYSQL *mysql,ulong pid)
+{
+ char buff[12];
+ DBUG_ENTER("mysql_kill");
+ int4store(buff,pid);
+ DBUG_RETURN(simple_command(mysql,COM_PROCESS_KILL,buff,4,0));
+}
+
+
+int STDCALL
+mysql_dump_debug_info(MYSQL *mysql)
+{
+ DBUG_ENTER("mysql_dump_debug_info");
+ DBUG_RETURN(simple_command(mysql,COM_DEBUG,"",0,0));
+}
+
+char * STDCALL
+mysql_stat(MYSQL *mysql)
+{
+ DBUG_ENTER("mysql_stat");
+ if (simple_command(mysql,COM_STATISTICS,"",0,0))
+ return mysql->net.last_error;
+ mysql->net.read_pos[mysql->packet_length]=0; /* End of stat string */
+ if (!mysql->net.read_pos[0])
+ {
+ mysql->net.last_errno=CR_WRONG_HOST_INFO;
+ strmov(mysql->net.last_error, ER(mysql->net.last_errno));
+ return mysql->net.last_error;
+ }
+ DBUG_RETURN((char*) mysql->net.read_pos);
+}
+
+
+int STDCALL
+mysql_ping(MYSQL *mysql)
+{
+ DBUG_ENTER("mysql_ping");
+ DBUG_RETURN(simple_command(mysql,COM_PING,"",0,0));
+}
+
+
+char * STDCALL
+mysql_get_server_info(MYSQL *mysql)
+{
+ return((char*) mysql->server_version);
+}
+
+
+char * STDCALL
+mysql_get_host_info(MYSQL *mysql)
+{
+ return(mysql->host_info);
+}
+
+
+uint STDCALL
+mysql_get_proto_info(MYSQL *mysql)
+{
+ return (mysql->protocol_version);
+}
+
+char * STDCALL
+mysql_get_client_info(void)
+{
+ return (char*) MYSQL_SERVER_VERSION;
+}
+
+
+int STDCALL
+mysql_options(MYSQL *mysql,enum mysql_option option, const char *arg)
+{
+ DBUG_ENTER("mysql_option");
+ DBUG_PRINT("enter",("option: %d",(int) option));
+ switch (option) {
+ case MYSQL_OPT_CONNECT_TIMEOUT:
+ mysql->options.connect_timeout= *(uint*) arg;
+ break;
+ case MYSQL_OPT_COMPRESS:
+ mysql->options.compress=1; /* Remember for connect */
+ break;
+ case MYSQL_OPT_NAMED_PIPE:
+ mysql->options.named_pipe=1; /* Force named pipe */
+ break;
+ case MYSQL_INIT_COMMAND:
+ my_free(mysql->options.init_command,MYF(MY_ALLOW_ZERO_PTR));
+ mysql->options.init_command=my_strdup(arg,MYF(MY_WME));
+ break;
+ case MYSQL_READ_DEFAULT_FILE:
+ my_free(mysql->options.my_cnf_file,MYF(MY_ALLOW_ZERO_PTR));
+ mysql->options.my_cnf_file=my_strdup(arg,MYF(MY_WME));
+ break;
+ case MYSQL_READ_DEFAULT_GROUP:
+ my_free(mysql->options.my_cnf_group,MYF(MY_ALLOW_ZERO_PTR));
+ mysql->options.my_cnf_group=my_strdup(arg,MYF(MY_WME));
+ break;
+ case MYSQL_SET_CHARSET_DIR:
+ my_free(mysql->options.charset_dir,MYF(MY_ALLOW_ZERO_PTR));
+ mysql->options.charset_dir=my_strdup(arg,MYF(MY_WME));
+ break;
+ case MYSQL_SET_CHARSET_NAME:
+ my_free(mysql->options.charset_name,MYF(MY_ALLOW_ZERO_PTR));
+ mysql->options.charset_name=my_strdup(arg,MYF(MY_WME));
+ break;
+ default:
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(0);
+}
+
+/****************************************************************************
+** Functions to get information from the MySQL structure
+** These are functions to make shared libraries more usable.
+****************************************************************************/
+
+/* MYSQL_RES */
+my_ulonglong STDCALL mysql_num_rows(MYSQL_RES *res)
+{
+ return res->row_count;
+}
+
+unsigned int STDCALL mysql_num_fields(MYSQL_RES *res)
+{
+ return res->field_count;
+}
+
+my_bool STDCALL mysql_eof(MYSQL_RES *res)
+{
+ return res->eof;
+}
+
+MYSQL_FIELD * STDCALL mysql_fetch_field_direct(MYSQL_RES *res,uint fieldnr)
+{
+ return &(res)->fields[fieldnr];
+}
+
+MYSQL_FIELD * STDCALL mysql_fetch_fields(MYSQL_RES *res)
+{
+ return (res)->fields;
+}
+
+MYSQL_ROWS * STDCALL mysql_row_tell(MYSQL_RES *res)
+{
+ return res->data_cursor;
+}
+
+uint STDCALL mysql_field_tell(MYSQL_RES *res)
+{
+ return (res)->current_field;
+}
+
+/* MYSQL */
+
+unsigned int STDCALL mysql_field_count(MYSQL *mysql)
+{
+ return mysql->field_count;
+}
+
+my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql)
+{
+ return (mysql)->affected_rows;
+}
+
+my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql)
+{
+ return (mysql)->insert_id;
+}
+
+uint STDCALL mysql_errno(MYSQL *mysql)
+{
+ return (mysql)->net.last_errno;
+}
+
+char * STDCALL mysql_error(MYSQL *mysql)
+{
+ return (mysql)->net.last_error;
+}
+
+char *STDCALL mysql_info(MYSQL *mysql)
+{
+ return (mysql)->info;
+}
+
+ulong STDCALL mysql_thread_id(MYSQL *mysql)
+{
+ return (mysql)->thread_id;
+}
+
+const char * STDCALL mysql_character_set_name(MYSQL *mysql)
+{
+ return mysql->charset->name;
+}
+
+
+uint STDCALL mysql_thread_safe(void)
+{
+#ifdef THREAD
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+/****************************************************************************
+** Some support functions
+****************************************************************************/
+
+/*
+** Add escape characters to a string (blob?) to make it suitable for a insert
+** to should at least have place for length*2+1 chars
+** Returns the length of the to string
+*/
+
+ulong STDCALL
+mysql_escape_string(char *to,const char *from,ulong length)
+{
+ return mysql_sub_escape_string(default_charset_info,to,from,length);
+}
+
+ulong STDCALL
+mysql_real_escape_string(MYSQL *mysql, char *to,const char *from,
+ ulong length)
+{
+ return mysql_sub_escape_string(mysql->charset,to,from,length);
+}
+
+
+static ulong
+mysql_sub_escape_string(CHARSET_INFO *charset_info, char *to,
+ const char *from, ulong length)
+{
+ const char *to_start=to;
+ const char *end;
+#ifdef USE_MB
+ my_bool use_mb_flag=use_mb(charset_info);
+#endif
+ for (end=from+length; from != end ; from++)
+ {
+#ifdef USE_MB
+ int l;
+ if (use_mb_flag && (l = my_ismbchar(charset_info, from, end)))
+ {
+ while (l--)
+ *to++ = *from++;
+ from--;
+ continue;
+ }
+#endif
+ switch (*from) {
+ case 0: /* Must be escaped for 'mysql' */
+ *to++= '\\';
+ *to++= '0';
+ break;
+ case '\n': /* Must be escaped for logs */
+ *to++= '\\';
+ *to++= 'n';
+ break;
+ case '\r':
+ *to++= '\\';
+ *to++= 'r';
+ break;
+ case '\\':
+ *to++= '\\';
+ *to++= '\\';
+ break;
+ case '\'':
+ *to++= '\\';
+ *to++= '\'';
+ break;
+ case '"': /* Better safe than sorry */
+ *to++= '\\';
+ *to++= '"';
+ break;
+ case '\032': /* This gives problems on Win32 */
+ *to++= '\\';
+ *to++= 'Z';
+ break;
+ default:
+ *to++= *from;
+ }
+ }
+ *to=0;
+ return (ulong) (to-to_start);
+}
+
+
+char * STDCALL
+mysql_odbc_escape_string(MYSQL *mysql,
+ char *to, ulong to_length,
+ const char *from, ulong from_length,
+ void *param,
+ char * (*extend_buffer)
+ (void *, char *, ulong *))
+{
+ char *to_end=to+to_length-5;
+ const char *end;
+#ifdef USE_MB
+ my_bool use_mb_flag=use_mb(mysql->charset);
+#endif
+
+ for (end=from+from_length; from != end ; from++)
+ {
+ if (to >= to_end)
+ {
+ to_length = (ulong) (end-from)+512; /* We want this much more */
+ if (!(to=(*extend_buffer)(param, to, &to_length)))
+ return to;
+ to_end=to+to_length-5;
+ }
+#ifdef USE_MB
+ {
+ int l;
+ if (use_mb_flag && (l = my_ismbchar(mysql->charset, from, end)))
+ {
+ while (l--)
+ *to++ = *from++;
+ from--;
+ continue;
+ }
+ }
+#endif
+ switch (*from) {
+ case 0: /* Must be escaped for 'mysql' */
+ *to++= '\\';
+ *to++= '0';
+ break;
+ case '\n': /* Must be escaped for logs */
+ *to++= '\\';
+ *to++= 'n';
+ break;
+ case '\r':
+ *to++= '\\';
+ *to++= 'r';
+ break;
+ case '\\':
+ *to++= '\\';
+ *to++= '\\';
+ break;
+ case '\'':
+ *to++= '\\';
+ *to++= '\'';
+ break;
+ case '"': /* Better safe than sorry */
+ *to++= '\\';
+ *to++= '"';
+ break;
+ case '\032': /* This gives problems on Win32 */
+ *to++= '\\';
+ *to++= 'Z';
+ break;
+ default:
+ *to++= *from;
+ }
+ }
+ return to;
+}
+
+void STDCALL
+myodbc_remove_escape(MYSQL *mysql,char *name)
+{
+ char *to;
+#ifdef USE_MB
+ my_bool use_mb_flag=use_mb(mysql->charset);
+ char *end;
+ LINT_INIT(end);
+ if (use_mb_flag)
+ for (end=name; *end ; end++) ;
+#endif
+
+ for (to=name ; *name ; name++)
+ {
+#ifdef USE_MB
+ int l;
+ if (use_mb_flag && (l = my_ismbchar( mysql->charset, name , end ) ) )
+ {
+ while (l--)
+ *to++ = *name++;
+ name--;
+ continue;
+ }
+#endif
+ if (*name == '\\' && name[1])
+ name++;
+ *to++= *name;
+ }
+ *to=0;
+}
diff --git a/libmysqld/libmysqld.def b/libmysqld/libmysqld.def
new file mode 100644
index 00000000000..0e126aa9ceb
--- /dev/null
+++ b/libmysqld/libmysqld.def
@@ -0,0 +1,72 @@
+LIBRARY LIBMYSQLD
+DESCRIPTION 'MySQL 4.0 Embedded Server Library'
+VERSION 4.0
+EXPORTS
+ mysql_server_end
+ mysql_server_init
+ mysql_use_result
+ mysql_thread_safe
+ mysql_thread_id
+ mysql_store_result
+ mysql_stat
+ mysql_shutdown
+ mysql_select_db
+ mysql_row_tell
+ mysql_row_seek
+ mysql_real_query
+ mysql_real_connect
+ mysql_query
+ mysql_ping
+ mysql_options
+ mysql_num_rows
+ mysql_num_fields
+ mysql_list_tables
+ mysql_list_processes
+ mysql_list_fields
+ mysql_list_dbs
+ mysql_kill
+ mysql_insert_id
+ mysql_init
+ mysql_info
+ mysql_get_server_info
+ mysql_get_proto_info
+ mysql_get_host_info
+ mysql_get_client_info
+ mysql_free_result
+ mysql_field_tell
+ mysql_field_count
+ mysql_field_seek
+ mysql_fetch_row
+ mysql_fetch_lengths
+ mysql_fetch_fields
+ mysql_fetch_field_direct
+ mysql_fetch_field
+ mysql_escape_string
+ mysql_real_escape_string
+ mysql_error
+ mysql_errno
+ mysql_eof
+ mysql_dump_debug_info
+ mysql_drop_db
+ mysql_debug
+ mysql_data_seek
+ mysql_create_db
+ mysql_character_set_name
+ mysql_change_user
+ mysql_connect
+ mysql_close
+ mysql_affected_rows
+ mysql_thread_init
+ mysql_thread_end
+ mysql_send_query
+ mysql_read_query_result
+ mysql_refresh
+ mysql_odbc_escape_string
+ myodbc_remove_escape
+
+
+
+
+
+
+
diff --git a/ltconfig b/ltconfig
index 18af7c4dce8..b9df847729d 100755
--- a/ltconfig
+++ b/ltconfig
@@ -1308,7 +1308,9 @@ else
hardcode_direct=yes
fi
allow_undefined_flag=' ${wl}-berok'
- archive_cmds="\$CC $shared_flag"' -o $objdir/$soname $libobjs $deplibs $linkopts ${wl}-bexpall ${wl}-bnoentry${allow_undefined_flag}'
+ # -qmkshrobj used to be -bexpall, but MySQL uses symbols which start with
+ # an underscore (e.g., _my_b_write), so -bexpall doesn't work.
+ archive_cmds="\$CC $shared_flag"' -o $objdir/$soname $libobjs $deplibs $linkopts ${wl}-qmkshrobj ${wl}-bnoentry${allow_undefined_flag}'
archive_expsym_cmds="\$CC $shared_flag"' -o $objdir/$soname $libobjs $deplibs $linkopts ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}'
case "$host_os" in aix4.[01]|aix4.[01].*)
# According to Greg Wooledge, -bexpall is only supported from AIX 4.2 on
diff --git a/man/Makefile.am b/man/Makefile.am
index 186fc01685e..7019d2aa865 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -19,7 +19,7 @@
man_MANS = mysql.1 isamchk.1 isamlog.1 mysql_zap.1 mysqlaccess.1 \
mysqladmin.1 mysqld.1 mysqld_multi.1 mysqldump.1 mysqlshow.1 \
- perror.1 replace.1 safe_mysqld.1
+ perror.1 replace.1 mysqld_safe.1
EXTRA_DIST = $(man_MANS)
diff --git a/man/isamchk.1 b/man/isamchk.1
index f225dc35d18..2552d9f80cd 100755..100644
--- a/man/isamchk.1
+++ b/man/isamchk.1
@@ -125,7 +125,7 @@ mysqlshow (1),
msql2mysql (1),
perror (1),
replace (1),
-safe_mysqld (1),
+mysqld_safe (1),
which1 (1),
zap (1),
.SH AUTHOR
diff --git a/man/isamlog.1 b/man/isamlog.1
index efc042ccd7c..ef6ceaff8da 100644
--- a/man/isamlog.1
+++ b/man/isamlog.1
@@ -83,7 +83,7 @@ mysqlshow (1),
msql2mysql (1),
perror (1),
replace (1),
-safe_mysqld (1),
+mysqld_safe (1),
which1 (1),
zap (1),
diff --git a/man/mysql.1 b/man/mysql.1
index 96ccca8f50e..e10fd589092 100644
--- a/man/mysql.1
+++ b/man/mysql.1
@@ -111,7 +111,7 @@ executable
.I /depot/bin/mysqld
executable
.TP
-.I /depot/bin/safe_mysqld
+.I /depot/bin/mysqld_safe
executable shell script for starting mysqld safely
.TP
.I /site/var/mysql/data
@@ -135,7 +135,7 @@ mysqlshow (1),
msql2mysql (1),
perror (1),
replace (1),
-safe_mysqld (1),
+mysqld_safe (1),
which1 (1),
zap (1),
.SH AUTHOR
diff --git a/man/mysql_zap.1 b/man/mysql_zap.1
index 98da195894e..e57eb7a4d07 100644
--- a/man/mysql_zap.1
+++ b/man/mysql_zap.1
@@ -28,7 +28,7 @@ isn't given, ask user for confirmation for each process to kill. If signal isn't
.BR -t
is given the processes is only shown on stdout.
.SH "SEE ALSO"
-isamchk (1), isamlog (1), mysqlaccess (1), mysqladmin (1), mysqlbug (1), mysqld (1), mysqldump (1), mysqlshow (1), msql2mysql (1), perror (1), replace (1), safe_mysqld (1), which1 (1), zap (1),
+isamchk (1), isamlog (1), mysqlaccess (1), mysqladmin (1), mysqlbug (1), mysqld (1), mysqldump (1), mysqlshow (1), msql2mysql (1), perror (1), replace (1), mysqld_safe (1), which1 (1), zap (1),
.SH AUTHOR
Ver 1.0, distribution 3.23.29a Michael (Monty) Widenius (monty@tcx.se), TCX Datakonsult AB (http://www.tcx.se). 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 \ No newline at end of file
diff --git a/man/mysqlaccess.1 b/man/mysqlaccess.1
index 888cfe8f646..0ae06dca137 100755..100644
--- a/man/mysqlaccess.1
+++ b/man/mysqlaccess.1
@@ -106,7 +106,7 @@ mysqlshow (1),
msql2mysql (1),
perror (1),
replace (1),
-safe_mysqld (1),
+mysqld_safe (1),
which1 (1),
zap (1),
.SH AUTHOR
diff --git a/man/mysqladmin.1 b/man/mysqladmin.1
index 58bd2070de6..1e435006bb2 100755..100644
--- a/man/mysqladmin.1
+++ b/man/mysqladmin.1
@@ -189,7 +189,7 @@ mysqlshow (1),
msql2mysql (1),
perror (1),
replace (1),
-safe_mysqld (1),
+mysqld_safe (1),
which1 (1),
zap (1),
.SH AUTHOR
diff --git a/man/mysqld.1 b/man/mysqld.1
index d3f22c0be1b..1f87eb9cf32 100755..100644
--- a/man/mysqld.1
+++ b/man/mysqld.1
@@ -137,7 +137,7 @@ Don't check the rows in the table if there isn't any delete blocks.
Before a table is automaticly repaired, mysqld will add a note about this in the error log. If you want to be able to recover from most things without user intervention, you should use the options BACKUP,FORCE. This will force a repair of a table even if some rows would be deleted, but it will keep the old data file as a backup so that you can later examine what happened.
.TP
.BR \-\-pid\-file=\fP\fIpath \fP
-Path to pid file used by safe_mysqld.
+Path to pid file used by mysqld_safe.
.TP
.BR \-P | \-\-port=...
Port number to listen for TCP/IP connections.
@@ -215,7 +215,7 @@ mysqlshow (1),
msql2mysql (1),
perror (1),
replace (1),
-safe_mysqld (1),
+mysqld_safe (1),
which1 (1),
zap (1),
.SH AUTHOR
diff --git a/man/mysqld_multi.1 b/man/mysqld_multi.1
index b68050e92ef..b7aa77f656d 100644
--- a/man/mysqld_multi.1
+++ b/man/mysqld_multi.1
@@ -36,7 +36,7 @@ Log file. Full path to and the name for the log file. NOTE: If the file exists,
mysqladmin binary to be used for a server shutdown.
.TP
.BR --mysqld=...
-mysqld binary to be used. Note that you can give safe_mysqld to this option also. The options are passed to mysqld. Just make sure you have mysqld in your environment variable PATH or fix safe_mysqld.
+mysqld binary to be used. Note that you can give mysqld_safe to this option also. The options are passed to mysqld. Just make sure you have mysqld in your environment variable PATH or fix mysqld_safe.
.TP
.BR --no-log
Print to stdout instead of the log file. By default the log file is turned on.
@@ -70,7 +70,7 @@ mysqlshow (1),
msql2mysql (1),
perror (1),
replace (1),
-safe_mysqld (1),
+mysqld_safe (1),
which1 (1),
zap (1),
diff --git a/man/safe_mysqld.1 b/man/mysqld_safe.1
index 3874801be3b..c900d193929 100755..100644
--- a/man/safe_mysqld.1
+++ b/man/mysqld_safe.1
@@ -1,8 +1,8 @@
.TH SAFE_MYSQLD 1 "19 December 2000" "safe_mysqld (mysql)" mysql.com
.SH NAME
-safe_mysqld \- start the mysqld daemon on Unix.
+mysqld_safe \- start the mysqld daemon on Unix.
.SH SYNOPSIS
-.B safe_mysqld
+.B mysqld_safe
.RB [ \-\-basedir=\fP\fIpath\fP ]
.RB [ \-\-core\-file\-size=# ]
.RB [ \-\-defaults\-extra\-file=\fP\fIpath\fP ]
@@ -20,21 +20,19 @@ safe_mysqld \- start the mysqld daemon on Unix.
.RB [ \-\-timezone=# ]
.RB [ \-\-user=# ]
.SH DESCRIPTION
-safe_mysqld adds some safety features such as restarting the server when an
+mysqld_safe adds some safety features such as restarting the server when an
error occurs and logging run-time information to a log file.
.BR
.TP
.BR \-\-basedir=\fP\fIpath \fP
.TP
-.BR \-\-core\-file\-size=#
+.BR \-\-core\-file\-size=#
+Size of the core file mysqld should be able to create. Passed to ulimit \-c.
.TP
.BR \-\-defaults\-extra\-file=\fP\fIpath \fP
.TP
.BR \-\-defaults\-file=\fP\fIpath \fP
.TP
-.BR \-\-open\-files=#
-Size of the core file mysqld should be able to create. Passed to ulimit \-c.
-.TP
.BR \-\-datadir=\fP\fIpath \fP
.TP
.BR \-\-err\-log=\fP\fIpath \fP
@@ -60,7 +58,7 @@ Set the timezone (the TZ) variable to the value of this parameter.
.TP
.BR \-\-user=#
.SH NOTE
-Note that all options on the command line to safe_mysqld are passed to mysqld. If you wants to use any options in safe_mysqld that mysqld doesn't support, you must specify these in the option file.
+Note that all options on the command line to mysqld_safe are passed to mysqld. If you wants to use any options in mysqld_safe that mysqld doesn't support, you must specify these in the option file.
.SH "SEE ALSO"
isamchk (1),
isamlog (1),
@@ -73,13 +71,13 @@ mysqlshow (1),
msql2mysql (1),
perror (1),
replace (1),
-safe_mysqld (1),
+mysqld_safe (1),
which1 (1),
zap (1),
.SH AUTHOR
Ver 1.0, distribution 3.23.29a
-Michael (Monty) Widenius (monty@tcx.se),
-TCX Datakonsult AB (http://www.tcx.se).
+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 /
diff --git a/man/mysqldump.1 b/man/mysqldump.1
index f108da17bf9..b9e5aa33791 100755..100644
--- a/man/mysqldump.1
+++ b/man/mysqldump.1
@@ -258,7 +258,7 @@ mysqlshow (1),
msql2mysql (1),
perror (1),
replace (1),
-safe_mysqld (1),
+mysqld_safe (1),
which1 (1),
zap (1),
.SH AUTHOR
diff --git a/man/mysqlshow.1 b/man/mysqlshow.1
index 55a87c1df78..661b2cd02c8 100755..100644
--- a/man/mysqlshow.1
+++ b/man/mysqlshow.1
@@ -78,7 +78,7 @@ mysqlshow (1),
msql2mysql (1),
perror (1),
replace (1),
-safe_mysqld (1),
+mysqld_safe (1),
which1 (1),
zap (1),
.SH AUTHOR
diff --git a/man/perror.1 b/man/perror.1
index 2853f2cb1ba..7adf99ea772 100755..100644
--- a/man/perror.1
+++ b/man/perror.1
@@ -43,7 +43,7 @@ mysqlshow (1),
msql2mysql (1),
perror (1),
replace (1),
-safe_mysqld (1),
+mysqld_safe (1),
which1 (1),
zap (1),
.SH AUTHOR
diff --git a/man/replace.1 b/man/replace.1
index 10bcf64fc88..38ffe998027 100644
--- a/man/replace.1
+++ b/man/replace.1
@@ -52,7 +52,7 @@ mysqlshow (1),
msql2mysql (1),
perror (1),
replace (1),
-safe_mysqld (1),
+mysqld_safe (1),
which1 (1),
zap (1),
.SH AUTHOR
diff --git a/man/which.2 b/man/which.2
index 599b68080a2..30d5557ed01 100644
--- a/man/which.2
+++ b/man/which.2
@@ -48,7 +48,7 @@ Ignore option
.BR --read-alias;
don\'t read stdin.
.SH "SEE ALSO"
-isamchk (1), isamlog (1), mysqlaccess (1), mysqladmin (1), mysqlbug (1), mysqld (1), mysqldump (1), mysqlshow (1), msql2mysql (1), perror (1), replace (1), safe_mysqld (1), which1 (1), zap (1),
+isamchk (1), isamlog (1), mysqlaccess (1), mysqladmin (1), mysqlbug (1), mysqld (1), mysqldump (1), mysqlshow (1), msql2mysql (1), perror (1), replace (1), mysqld_safe (1), which1 (1), zap (1),
.SH AUTHOR
Ver 1.0, distribution 3.23.29a Michael (Monty) Widenius (monty@tcx.se), TCX Datakonsult AB (http://www.tcx.se). 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 \ No newline at end of file
diff --git a/merge/Makefile.am b/merge/Makefile.am
index 52abfc4cdc0..94de6d65391 100644
--- a/merge/Makefile.am
+++ b/merge/Makefile.am
@@ -16,10 +16,10 @@
INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include -I../include
pkglib_LIBRARIES = libmerge.a
-noinst_HEADERS = mrgdef.h
-libmerge_a_SOURCES = open.c extra.c info.c _locking.c \
- rrnd.c update.c delete.c rsame.c panic.c \
- close.c create.c static.c
+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
OMIT_DEPENDENCIES = pthread.h stdio.h __stdio.h stdlib.h __stdlib.h math.h\
__math.h time.h __time.h unistd.h __unistd.h types.h \
diff --git a/merge/close.c b/merge/mrg_close.c
index 2b769ade8e9..e835fd06e47 100644
--- a/merge/close.c
+++ b/merge/mrg_close.c
@@ -1,22 +1,22 @@
/* 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 "mrgdef.h"
+#include "mrg_def.h"
int mrg_close(register MRG_INFO *info)
{
diff --git a/merge/create.c b/merge/mrg_create.c
index fd2c16f9ea2..d55a1421647 100644
--- a/merge/create.c
+++ b/merge/mrg_create.c
@@ -1,22 +1,22 @@
/* 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 "mrgdef.h"
+#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
diff --git a/merge/mrgdef.h b/merge/mrg_def.h
index 3f22c83589a..8b6be08c32d 100644
--- a/merge/mrgdef.h
+++ b/merge/mrg_def.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 */
diff --git a/merge/delete.c b/merge/mrg_delete.c
index a4ee46eedc2..920156be01e 100644
--- a/merge/delete.c
+++ b/merge/mrg_delete.c
@@ -1,22 +1,22 @@
/* 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 */
/* Delete last read record */
-#include "mrgdef.h"
+#include "mrg_def.h"
int mrg_delete(MRG_INFO *info,const byte *record)
{
diff --git a/merge/extra.c b/merge/mrg_extra.c
index c4f048a4385..d37b1aaa03c 100644
--- a/merge/extra.c
+++ b/merge/mrg_extra.c
@@ -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 */
@@ -20,7 +20,7 @@
record-cache-flags are set in mrg_rrnd when we are changing database.
*/
-#include "mrgdef.h"
+#include "mrg_def.h"
int mrg_extra(
MRG_INFO *info,
diff --git a/merge/info.c b/merge/mrg_info.c
index d44ada8e6e6..57f22276487 100644
--- a/merge/info.c
+++ b/merge/mrg_info.c
@@ -1,20 +1,20 @@
/* 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 "mrgdef.h"
+#include "mrg_def.h"
ulong mrg_position(MRG_INFO *info)
{
diff --git a/merge/_locking.c b/merge/mrg_locking.c
index 81582da1312..bd33e047091 100644
--- a/merge/_locking.c
+++ b/merge/mrg_locking.c
@@ -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 */
@@ -18,7 +18,7 @@
Lock databases against read or write.
*/
-#include "mrgdef.h"
+#include "mrg_def.h"
int mrg_lock_database(MRG_INFO *info,int lock_type)
{
diff --git a/merge/open.c b/merge/mrg_open.c
index c1be98b7e18..83b776ea201 100644
--- a/merge/open.c
+++ b/merge/mrg_open.c
@@ -1,22 +1,22 @@
/* 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 "mrgdef.h"
+#include "mrg_def.h"
#include <stddef.h>
#include <errno.h>
#ifdef VMS
@@ -36,7 +36,7 @@ int mode,
int handle_locking)
{
int save_errno,i,errpos;
- uint files,dir_length,length;
+ uint files,dir_length,length, options;
ulonglong file_offset;
char name_buff[FN_REFLEN*2],buff[FN_REFLEN],*end;
MRG_INFO info,*m_info;
@@ -90,16 +90,22 @@ int handle_locking)
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++)
diff --git a/merge/panic.c b/merge/mrg_panic.c
index cf333e3a9bf..e9ad1974d8f 100644
--- a/merge/panic.c
+++ b/merge/mrg_panic.c
@@ -1,20 +1,20 @@
/* 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 "mrgdef.h"
+#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
diff --git a/merge/rrnd.c b/merge/mrg_rrnd.c
index e53982aca21..206427d74d4 100644
--- a/merge/rrnd.c
+++ b/merge/mrg_rrnd.c
@@ -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 */
@@ -19,7 +19,7 @@
get by mrg_info(). The next record can be read with pos= -1 */
-#include "mrgdef.h"
+#include "mrg_def.h"
static MRG_TABLE *find_table(MRG_TABLE *start,MRG_TABLE *end,mrg_off_t pos);
diff --git a/merge/rsame.c b/merge/mrg_rsame.c
index 4ebf25b21c1..ee840bc3060 100644
--- a/merge/rsame.c
+++ b/merge/mrg_rsame.c
@@ -1,20 +1,20 @@
/* 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 "mrgdef.h"
+#include "mrg_def.h"
int mrg_rsame(
diff --git a/merge/static.c b/merge/mrg_static.c
index e5f95ef195a..1b7327c870f 100644
--- a/merge/static.c
+++ b/merge/mrg_static.c
@@ -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 */
@@ -20,7 +20,7 @@
*/
#ifndef stdin
-#include "mrgdef.h"
+#include "mrg_def.h"
#endif
LIST *mrg_open_list=0;
diff --git a/merge/update.c b/merge/mrg_update.c
index 9fcb82089e4..a6650267f36 100644
--- a/merge/update.c
+++ b/merge/mrg_update.c
@@ -1,22 +1,22 @@
/* 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 "mrgdef.h"
+#include "mrg_def.h"
int mrg_update(
register MRG_INFO *info,
diff --git a/myisam/Makefile.am b/myisam/Makefile.am
index a18ff55ba9e..6802bcb115f 100644
--- a/myisam/Makefile.am
+++ b/myisam/Makefile.am
@@ -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
@@ -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$(srcdir)/../include -I../include
+INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include -I../include
LDADD = @CLIENT_EXTRA_LDFLAGS@ libmyisam.a ../mysys/libmysys.a \
../dbug/libdbug.a ../strings/libmystrings.a
pkglib_LIBRARIES = libmyisam.a
@@ -25,13 +25,14 @@ bin_PROGRAMS = myisamchk myisamlog myisampack
myisamchk_DEPENDENCIES= $(LIBRARIES)
myisamlog_DEPENDENCIES= $(LIBRARIES)
myisampack_DEPENDENCIES=$(LIBRARIES)
-noinst_PROGRAMS = mi_test1 mi_test2 mi_test3 ft_test1 ft_eval
+noinst_PROGRAMS = mi_test1 mi_test2 mi_test3 ft_dump #ft_test1 ft_eval
noinst_HEADERS = myisamdef.h fulltext.h ftdefs.h ft_test1.h ft_eval.h
mi_test1_DEPENDENCIES= $(LIBRARIES)
mi_test2_DEPENDENCIES= $(LIBRARIES)
mi_test3_DEPENDENCIES= $(LIBRARIES)
-ft_test1_DEPENDENCIES= $(LIBRARIES)
-ft_eval_DEPENDENCIES= $(LIBRARIES)
+#ft_test1_DEPENDENCIES= $(LIBRARIES)
+#ft_eval_DEPENDENCIES= $(LIBRARIES)
+ft_dump_DEPENDENCIES= $(LIBRARIES)
libmyisam_a_SOURCES = mi_open.c mi_extra.c mi_info.c mi_rkey.c \
mi_rnext.c mi_rnext_same.c \
mi_search.c mi_page.c mi_key.c mi_locking.c \
@@ -44,8 +45,8 @@ libmyisam_a_SOURCES = mi_open.c mi_extra.c mi_info.c mi_rkey.c \
mi_range.c mi_dbug.c mi_checksum.c mi_log.c \
mi_changed.c mi_static.c mi_delete_all.c \
mi_delete_table.c mi_rename.c mi_check.c \
- ft_parser.c ft_search.c ft_stopwords.c ft_static.c \
- ft_update.c sort.c
+ ft_parser.c ft_stopwords.c ft_static.c \
+ ft_update.c ft_boolean_search.c ft_nlq_search.c sort.c
CLEANFILES = test?.MY? FT?.MY? isam.log mi_test_all
DEFS = -DMAP_TO_USE_RAID
# Omit dependency for ../mit-pthreads/include/sys that only exits if
diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c
new file mode 100644
index 00000000000..9b51601be40
--- /dev/null
+++ b/myisam/ft_boolean_search.c
@@ -0,0 +1,494 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Written by Sergei A. Golubchik, who has a shared copyright to this code */
+
+/* TODO: add caching - pre-read several index entries at once */
+
+#define FT_CORE
+#include "ftdefs.h"
+#include <queues.h>
+
+/* search with boolean queries */
+
+static double _wghts[11]={
+ 0.131687242798354,
+ 0.197530864197531,
+ 0.296296296296296,
+ 0.444444444444444,
+ 0.666666666666667,
+ 1.000000000000000,
+ 1.500000000000000,
+ 2.250000000000000,
+ 3.375000000000000,
+ 5.062500000000000,
+ 7.593750000000000};
+static double *wghts=_wghts+5; /* wghts[i] = 1.5**i */
+
+static double _nwghts[11]={
+ -0.065843621399177,
+ -0.098765432098766,
+ -0.148148148148148,
+ -0.222222222222222,
+ -0.333333333333334,
+ -0.500000000000000,
+ -0.750000000000000,
+ -1.125000000000000,
+ -1.687500000000000,
+ -2.531250000000000,
+ -3.796875000000000};
+static double *nwghts=_nwghts+5; /* nwghts[i] = -0.5*1.5**i */
+
+#define FTB_FLAG_TRUNC 1 /* MUST be 1 */
+#define FTB_FLAG_YES 2 /* These two - YES and NO */
+#define FTB_FLAG_NO 4 /* should NEVER be set both */
+
+typedef struct st_ftb_expr FTB_EXPR;
+struct st_ftb_expr {
+ FTB_EXPR *up;
+ float weight;
+ uint flags;
+ my_off_t docid[2]; /* for index search and for scan */
+ float cur_weight;
+ int yesses; /* number of "yes" words matched */
+ int nos; /* number of "no" words matched */
+ int ythresh; /* number of "yes" words in expr */
+ int yweaks; /* number of "yes" words for scan only */
+};
+
+typedef struct st_ftb_word {
+ FTB_EXPR *up;
+ float weight;
+ uint flags;
+ my_off_t docid[2]; /* for index search and for scan */
+ uint ndepth;
+ int len;
+ /* ... there can be docid cache added here. SerG */
+ byte word[1];
+} FTB_WORD;
+
+typedef struct st_ft_info {
+ struct _ft_vft *please;
+ MI_INFO *info;
+ uint keynr;
+ enum { UNINITIALIZED, READY, INDEX_SEARCH, INDEX_DONE /*, SCAN*/ } state;
+ uint with_scan;
+ FTB_EXPR *root;
+ QUEUE queue;
+ FTB_WORD **list;
+ MEM_ROOT mem_root;
+} FTB;
+
+int FTB_WORD_cmp(void *v __attribute__((unused)), FTB_WORD *a, FTB_WORD *b)
+{
+ /* ORDER BY docid, ndepth DESC */
+ int i=CMP_NUM(a->docid[0], b->docid[0]);
+ if (!i)
+ i=CMP_NUM(b->ndepth,a->ndepth);
+ return i;
+}
+
+int FTB_WORD_cmp_list(void *v __attribute__((unused)), FTB_WORD **a, FTB_WORD **b)
+{
+ /* ORDER BY word DESC, ndepth DESC */
+ int i=_mi_compare_text(default_charset_info, (*b)->word+1,(*b)->len-1,
+ (*a)->word+1,(*a)->len-1,0);
+ if (!i)
+ i=CMP_NUM((*b)->ndepth,(*a)->ndepth);
+ return i;
+}
+
+void _ftb_parse_query(FTB *ftb, byte **start, byte *end,
+ FTB_EXPR *up, uint depth)
+{
+ byte res;
+ FTB_PARAM param;
+ FT_WORD w;
+ FTB_WORD *ftbw;
+ FTB_EXPR *ftbe;
+ uint extra=HA_FT_WLEN+ftb->info->s->rec_reflength; /* just a shortcut */
+
+ if (ftb->state != UNINITIALIZED)
+ return;
+
+ param.prev=' ';
+ while ((res=ft_get_word(start,end,&w,&param)))
+ {
+ int r=param.plusminus;
+ float weight= (float) (param.pmsign ? nwghts : wghts)[(r>5)?5:((r<-5)?-5:r)];
+ switch (res) {
+ case 1: /* word found */
+ ftbw=(FTB_WORD *)alloc_root(&ftb->mem_root,
+ sizeof(FTB_WORD) +
+ (param.trunc ? MI_MAX_KEY_BUFF :
+ w.len+extra));
+ ftbw->len=w.len+1;
+ ftbw->flags=0;
+ if (param.yesno>0) ftbw->flags|=FTB_FLAG_YES;
+ if (param.yesno<0) ftbw->flags|=FTB_FLAG_NO;
+ if (param.trunc) ftbw->flags|=FTB_FLAG_TRUNC;
+ ftbw->weight=weight;
+ ftbw->up=up;
+ ftbw->docid[0]=ftbw->docid[1]=HA_POS_ERROR;
+ ftbw->ndepth= (param.yesno<0) + depth;
+ memcpy(ftbw->word+1, w.pos, w.len);
+ ftbw->word[0]=w.len;
+ if (param.yesno > 0) up->ythresh++;
+ queue_insert(& ftb->queue, (byte *)ftbw);
+ ftb->with_scan|=param.trunc;
+ break;
+ case 2: /* left bracket */
+ ftbe=(FTB_EXPR *)alloc_root(&ftb->mem_root, sizeof(FTB_EXPR));
+ ftbe->flags=0;
+ if (param.yesno>0) ftbe->flags|=FTB_FLAG_YES;
+ if (param.yesno<0) ftbe->flags|=FTB_FLAG_NO;
+ ftbe->weight=weight;
+ ftbe->up=up;
+ ftbe->ythresh=ftbe->yweaks=0;
+ ftbe->docid[0]=ftbe->docid[1]=HA_POS_ERROR;
+ if (param.yesno > 0) up->ythresh++;
+ _ftb_parse_query(ftb, start, end, ftbe, depth+1);
+ break;
+ case 3: /* right bracket */
+ return;
+ }
+ }
+ return;
+}
+
+void _ftb_init_index_search(FT_INFO *ftb)
+{
+ int i, r;
+ FTB_WORD *ftbw;
+ MI_INFO *info=ftb->info;
+ MI_KEYDEF *keyinfo;
+ my_off_t keyroot;
+
+ if (ftb->state != READY || ftb->keynr == NO_SUCH_KEY)
+ return;
+ ftb->state=INDEX_SEARCH;
+
+ keyinfo=info->s->keyinfo+ftb->keynr;
+ keyroot=info->s->state.key_root[ftb->keynr];
+
+ for (i=ftb->queue.elements; i; i--)
+ {
+ ftbw=(FTB_WORD *)(ftb->queue.root[i]);
+
+ if (ftbw->flags&FTB_FLAG_TRUNC &&
+ (ftbw->up->ythresh > test(ftbw->flags&FTB_FLAG_YES)))
+ {
+ /* no need to search for this prefix in the index -
+ * it cannot ADD new matches, and to REMOVE half-matched
+ * rows we do scan anyway */
+ ftbw->docid[0]=HA_POS_ERROR;
+ ftbw->up->yweaks++;
+ continue;
+ }
+
+ r=_mi_search(info, keyinfo, (uchar*) ftbw->word, ftbw->len,
+ SEARCH_FIND | SEARCH_BIGGER, keyroot);
+ if (!r)
+ {
+ r=_mi_compare_text(default_charset_info,
+ info->lastkey + (ftbw->flags&FTB_FLAG_TRUNC),
+ ftbw->len - (ftbw->flags&FTB_FLAG_TRUNC),
+ ftbw->word + (ftbw->flags&FTB_FLAG_TRUNC),
+ ftbw->len - (ftbw->flags&FTB_FLAG_TRUNC),
+ 0);
+ }
+ if (r) /* not found */
+ {
+ if (ftbw->flags&FTB_FLAG_YES && ftbw->up->up==0)
+ { /* this word MUST BE present in every document returned,
+ so we can abort the search right now */
+ ftb->state=INDEX_DONE;
+ return;
+ }
+ }
+ else
+ {
+ memcpy(ftbw->word, info->lastkey, info->lastkey_length);
+ ftbw->docid[0]=info->lastpos;
+ }
+ }
+ queue_fix(& ftb->queue);
+}
+
+FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query,
+ uint query_len, my_bool presort __attribute__((unused)))
+{
+ FTB *ftb;
+ FTB_EXPR *ftbe;
+ uint res;
+
+ if (!(ftb=(FTB *)my_malloc(sizeof(FTB), MYF(MY_WME))))
+ return 0;
+ ftb->please= (struct _ft_vft *) & _ft_vft_boolean;
+ ftb->state=UNINITIALIZED;
+ ftb->info=info;
+ ftb->keynr=keynr;
+ ftb->with_scan=0;
+
+ init_alloc_root(&ftb->mem_root, 1024, 1024);
+
+ /* hack: instead of init_queue, we'll use reinit queue to be able
+ * to alloc queue with alloc_root()
+ */
+ res=ftb->queue.max_elements=query_len/(ft_min_word_len+1);
+ ftb->queue.root=(byte **)alloc_root(&ftb->mem_root, (res+1)*sizeof(void*));
+ reinit_queue(& ftb->queue, res, 0, 0,
+ (int (*)(void*,byte*,byte*))FTB_WORD_cmp, ftb);
+ ftbe=(FTB_EXPR *)alloc_root(&ftb->mem_root, sizeof(FTB_EXPR));
+ ftbe->weight=1;
+ ftbe->flags=FTB_FLAG_YES;
+ ftbe->nos=1;
+ ftbe->up=0;
+ ftbe->ythresh=ftbe->yweaks=0;
+ ftbe->docid[0]=ftbe->docid[1]=HA_POS_ERROR;
+ ftb->root=ftbe;
+ _ftb_parse_query(ftb, &query, query+query_len, ftbe, 0);
+ ftb->list=(FTB_WORD **)alloc_root(&ftb->mem_root,
+ sizeof(FTB_WORD *)*ftb->queue.elements);
+ memcpy(ftb->list, ftb->queue.root, sizeof(FTB_WORD *)*ftb->queue.elements);
+ qsort2(ftb->list, ftb->queue.elements, sizeof(FTB_WORD *),
+ (qsort2_cmp)FTB_WORD_cmp_list, 0);
+ if (ftb->queue.elements<2) ftb->with_scan=0;
+ ftb->state=READY;
+ return ftb;
+}
+
+void _ftb_climb_the_tree(FTB_WORD *ftbw, uint mode)
+{
+ FTB_EXPR *ftbe;
+ float weight=ftbw->weight;
+ int yn=ftbw->flags, ythresh;
+ my_off_t curdoc=ftbw->docid[mode];
+
+ for (ftbe=ftbw->up; ftbe; ftbe=ftbe->up)
+ {
+ ythresh = ftbe->ythresh - (mode ? 0 : ftbe->yweaks);
+ if (ftbe->docid[mode] != curdoc)
+ {
+ ftbe->cur_weight=0;
+ ftbe->yesses=ftbe->nos=0;
+ ftbe->docid[mode]=curdoc;
+ }
+ if (ftbe->nos)
+ break;
+ if (yn & FTB_FLAG_YES)
+ {
+ ftbe->cur_weight+=weight;
+ if (++ftbe->yesses == ythresh)
+ {
+ yn=ftbe->flags;
+ weight=ftbe->cur_weight*ftbe->weight;
+ }
+ else
+ break;
+ }
+ else
+ if (yn & FTB_FLAG_NO)
+ {
+ /* NOTE: special sort function of queue assures that all
+ * (yn & FTB_FLAG_NO) != 0
+ * events for every particular subexpression will
+ * "auto-magically" happen BEFORE all the
+ * (yn & FTB_FLAG_YES) != 0 events. So no
+ * already matched expression can become not-matched again.
+ */
+ ++ftbe->nos;
+ break;
+ }
+ else
+ {
+ ftbe->cur_weight+=weight;
+ if (ftbe->yesses < ythresh)
+ break;
+ yn= (ftbe->yesses++ == ythresh) ? ftbe->flags : 0 ;
+ weight*=ftbe->weight;
+ }
+ }
+}
+
+int ft_boolean_read_next(FT_INFO *ftb, char *record)
+{
+ FTB_EXPR *ftbe;
+ FTB_WORD *ftbw;
+ MI_INFO *info=ftb->info;
+ MI_KEYDEF *keyinfo=info->s->keyinfo+ftb->keynr;
+ my_off_t keyroot=info->s->state.key_root[ftb->keynr];
+ my_off_t curdoc;
+ int r;
+
+ if (ftb->state != INDEX_SEARCH && ftb->state != INDEX_DONE)
+ return -1;
+
+ /* black magic ON */
+ if ((int) _mi_check_index(info, ftb->keynr) < 0)
+ return my_errno;
+ if (_mi_readinfo(info, F_RDLCK, 1))
+ return my_errno;
+ /* black magic OFF */
+
+ if (!ftb->queue.elements)
+ return my_errno=HA_ERR_END_OF_FILE;
+
+ while(ftb->state == INDEX_SEARCH &&
+ (curdoc=((FTB_WORD *)queue_top(& ftb->queue))->docid[0]) != HA_POS_ERROR)
+ {
+ while (curdoc==(ftbw=(FTB_WORD *)queue_top(& ftb->queue))->docid[0])
+ {
+ _ftb_climb_the_tree(ftbw,0);
+
+ /* update queue */
+ r=_mi_search(info, keyinfo, (uchar*) ftbw->word, USE_WHOLE_KEY,
+ SEARCH_BIGGER , keyroot);
+ if (!r)
+ {
+ r=_mi_compare_text(default_charset_info,
+ info->lastkey + (ftbw->flags&FTB_FLAG_TRUNC),
+ ftbw->len - (ftbw->flags&FTB_FLAG_TRUNC),
+ ftbw->word + (ftbw->flags&FTB_FLAG_TRUNC),
+ ftbw->len - (ftbw->flags&FTB_FLAG_TRUNC),
+ 0);
+ }
+ if (r) /* not found */
+ {
+ ftbw->docid[0]=HA_POS_ERROR;
+ if (ftbw->flags&FTB_FLAG_YES && ftbw->up->up==0)
+ { /* this word MUST BE present in every document returned,
+ so we can stop the search right now */
+ ftb->state=INDEX_DONE;
+ }
+ }
+ else
+ {
+ memcpy(ftbw->word, info->lastkey, info->lastkey_length);
+ ftbw->docid[0]=info->lastpos;
+ }
+ queue_replaced(& ftb->queue);
+ }
+
+ ftbe=ftb->root;
+ if (ftbe->docid[0]==curdoc && ftbe->cur_weight>0 &&
+ ftbe->yesses>=(ftbe->ythresh-ftbe->yweaks) && !ftbe->nos)
+ {
+ /* curdoc matched ! */
+ info->lastpos=curdoc;
+ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED); /* why is this ? */
+
+ if (!(*info->read_record)(info,curdoc,record))
+ {
+ info->update|= HA_STATE_AKTIV; /* Record is read */
+ if (ftb->with_scan && ft_boolean_find_relevance(ftb,record,0)==0)
+ continue; /* no match */
+ return 0;
+ }
+ return my_errno;
+ }
+ }
+ ftb->state=INDEX_DONE;
+ return my_errno=HA_ERR_END_OF_FILE;
+}
+
+float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length)
+{
+ FT_WORD word;
+ FTB_WORD *ftbw;
+ FTB_EXPR *ftbe;
+ FT_SEG_ITERATOR ftsi;
+ const byte *end;
+ my_off_t docid=ftb->info->lastpos;
+
+ if (docid == HA_POS_ERROR)
+ return -2.0;
+ if (!ftb->queue.elements)
+ return 0;
+
+#if NOT_USED
+ if (ftb->state == READY || ftb->state == INDEX_DONE)
+ ftb->state=SCAN;
+ else if (ftb->state != SCAN)
+ return -3.0;
+#endif
+
+ if (ftb->keynr==NO_SUCH_KEY)
+ _mi_ft_segiterator_dummy_init(record, length, &ftsi);
+ else
+ _mi_ft_segiterator_init(ftb->info, ftb->keynr, record, &ftsi);
+
+ while (_mi_ft_segiterator(&ftsi))
+ {
+ if (!ftsi.pos)
+ continue;
+
+ end=ftsi.pos+ftsi.len;
+ while (ft_simple_get_word((byte **)&ftsi.pos,(byte *)end,&word))
+ {
+ int a, b, c;
+ for (a=0, b=ftb->queue.elements, c=(a+b)/2; b-a>1; c=(a+b)/2)
+ {
+ ftbw=(FTB_WORD *)(ftb->list[c]);
+ if (_mi_compare_text(default_charset_info, word.pos,word.len,
+ (uchar*) ftbw->word+1,ftbw->len-1,
+ (ftbw->flags&FTB_FLAG_TRUNC) ) >0)
+ b=c;
+ else
+ a=c;
+ }
+ for (; c>=0; c--)
+ {
+ ftbw=(FTB_WORD *)(ftb->list[c]);
+ if (_mi_compare_text(default_charset_info, word.pos,word.len,
+ (uchar*) ftbw->word+1,ftbw->len-1,
+ (ftbw->flags&FTB_FLAG_TRUNC) ))
+ break;
+ if (ftbw->docid[1] == docid)
+ continue;
+ ftbw->docid[1]=docid;
+ _ftb_climb_the_tree(ftbw,1);
+ }
+ }
+ }
+
+ ftbe=ftb->root;
+ if (ftbe->docid[1]==docid && ftbe->cur_weight>0 &&
+ ftbe->yesses>=ftbe->ythresh && !ftbe->nos)
+ { /* row matched ! */
+ return ftbe->cur_weight;
+ }
+ else
+ { /* match failed ! */
+ return 0.0;
+ }
+}
+
+void ft_boolean_close_search(FT_INFO *ftb)
+{
+ free_root(& ftb->mem_root, MYF(0));
+ my_free((gptr)ftb,MYF(0));
+}
+
+float ft_boolean_get_relevance(FT_INFO *ftb)
+{
+ return ftb->root->cur_weight;
+}
+
+void ft_boolean_reinit_search(FT_INFO *ftb)
+{
+ _ftb_init_index_search(ftb);
+}
diff --git a/myisam/ft_dump.c b/myisam/ft_dump.c
new file mode 100644
index 00000000000..6308694b58e
--- /dev/null
+++ b/myisam/ft_dump.c
@@ -0,0 +1,233 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Written by Sergei A. Golubchik, who has a shared copyright to this code */
+
+#include "ftdefs.h"
+#include <getopt.h>
+
+static void get_options(int argc,char *argv[]);
+static void usage(char *argv[]);
+static void complain(int val);
+
+static int count=0, stats=0, dump=0, verbose=0, lstats=0;
+static char *query=NULL;
+static uint lengths[256];
+
+#define MAX_LEN (HA_FT_MAXLEN+10)
+#define HOW_OFTEN_TO_WRITE 10000
+
+int main(int argc,char *argv[])
+{
+ int error=0;
+ uint keylen, keylen2=0, inx, doc_cnt=0;
+ float weight;
+ double gws, min_gws=0, avg_gws=0;
+ MI_INFO *info;
+ char buf[MAX_LEN], buf2[MAX_LEN], buf_maxlen[MAX_LEN], buf_min_gws[MAX_LEN];
+ ulong total=0, maxlen=0, uniq=0, max_doc_cnt=0;
+ struct { MI_INFO *info; } aio0, *aio=&aio0; /* for GWS_IN_USE */
+
+ MY_INIT(argv[0]);
+ get_options(argc,argv);
+ if (count || dump)
+ verbose=0;
+ if (!count && !dump && !lstats && !query)
+ stats=1;
+
+ if (verbose)
+ setbuf(stdout,NULL);
+
+ if (argc-optind < 2)
+ usage(argv);
+
+ if (!(info=mi_open(argv[optind],2,HA_OPEN_ABORT_IF_LOCKED)))
+ goto err;
+
+ inx=atoi(argv[optind+1]);
+ *buf2=0;
+ aio->info=info;
+
+ if ((inx >= info->s->base.keys) || !(info->s->keyinfo[inx].flag & HA_FULLTEXT))
+ {
+ printf("Key %d in table %s is not a FULLTEXT key\n", inx, info->filename);
+ goto err;
+ }
+
+ if (query)
+ {
+#if 0
+ FT_DOCLIST *result;
+ int i;
+
+ ft_init_stopwords(ft_precompiled_stopwords);
+
+ result=ft_nlq_init_search(info,inx,query,strlen(query),1);
+ if(!result)
+ goto err;
+
+ if (verbose)
+ printf("%d rows matched\n",result->ndocs);
+
+ for(i=0 ; i<result->ndocs ; i++)
+ printf("%9qx %20.7f\n",result->doc[i].dpos,result->doc[i].weight);
+
+ ft_nlq_close_search(result);
+#else
+ printf("-e option is disabled\n");
+#endif
+ }
+ else
+ {
+ info->lastpos= HA_OFFSET_ERROR;
+ info->update|= HA_STATE_PREV_FOUND;
+
+ while (!(error=mi_rnext(info,NULL,inx)))
+ {
+ keylen=*(info->lastkey);
+
+#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT
+ mi_float4get(weight,info->lastkey+keylen+1);
+#else
+#error
+#endif
+
+ snprintf(buf,MAX_LEN,"%.*s",(int) keylen,info->lastkey+1);
+ casedn_str(buf);
+ total++;
+ lengths[keylen]++;
+
+ if (count || stats)
+ {
+ doc_cnt++;
+ if (strcmp(buf, buf2))
+ {
+ if (*buf2)
+ {
+ uniq++;
+ avg_gws+=gws=GWS_IN_USE;
+ if (count)
+ printf("%9u %20.7f %s\n",doc_cnt,gws,buf2);
+ if (maxlen<keylen2)
+ {
+ maxlen=keylen2;
+ strcpy(buf_maxlen, buf2);
+ }
+ if (max_doc_cnt < doc_cnt)
+ {
+ max_doc_cnt=doc_cnt;
+ strcpy(buf_min_gws, buf2);
+ min_gws=gws;
+ }
+ }
+ strcpy(buf2, buf);
+ keylen2=keylen;
+ doc_cnt=0;
+ }
+ }
+ if (dump)
+ printf("%9qx %20.7f %s\n",info->lastpos,weight,buf);
+
+ if(verbose && (total%HOW_OFTEN_TO_WRITE)==0)
+ printf("%10ld\r",total);
+ }
+
+ if (stats)
+ {
+ count=0;
+ for (inx=0;inx<256;inx++)
+ {
+ count+=lengths[inx];
+ if ((ulong) count >= total/2)
+ break;
+ }
+ printf("Total rows: %qu\nTotal words: %lu\n"
+ "Unique words: %lu\nLongest word: %lu chars (%s)\n"
+ "Median length: %u\n"
+ "Average global weight: %f\n"
+ "Most common word: %lu times, weight: %f (%s)\n",
+ (ulonglong)info->state->records, total, uniq, maxlen, buf_maxlen,
+ inx, avg_gws/uniq, max_doc_cnt, min_gws, buf_min_gws);
+ }
+ if (lstats)
+ {
+ count=0;
+ for (inx=0; inx<256; inx++)
+ {
+ count+=lengths[inx];
+ if (count && lengths[inx])
+ printf("%3u: %10lu %5.2f%% %20lu %4.1f%%\n", inx,
+ (ulong) lengths[inx],100.0*lengths[inx]/total,(ulong) count,
+ 100.0*count/total);
+ }
+ }
+ }
+
+err:
+ if (error && error != HA_ERR_END_OF_FILE)
+ printf("got error %d\n",my_errno);
+ if (info)
+ mi_close(info);
+ return 0;
+}
+
+const char *options="dslcvh";
+
+static void get_options(int argc, char *argv[])
+{
+ int c;
+
+ while ((c=getopt(argc,argv,options)) != -1)
+ {
+ switch(c) {
+ case 'd': dump=1; complain(count || query); break;
+ case 's': stats=1; complain(query!=0); break;
+ case 'v': verbose=1; break;
+ case 'c': count=1; complain(dump || query); break;
+ case 'l': lstats=1; complain(query!=0); break;
+ case 'e': query=my_strdup(optarg,MYF(MY_FAE)); complain(dump || count || stats); break;
+ case '?':
+ case 'h':
+ default:
+ usage(argv);
+ }
+ }
+ return;
+} /* get options */
+
+static void usage(char *argv[])
+{
+ printf("\n\
+Use: %s [-%s] <table_name> <index_no>\n\
+\n\
+-d Dump index (incl. data offsets and word weights)\n\
+-s Report global stats\n\
+-c Calculate per-word stats (counts and global weights)\n\
+-l Report length distribution\n\
+-v Be verbose\n\
+-h This text\n\
+", *argv, options);
+ exit(1);
+}
+
+static void complain(int val) /* Kinda assert :-) */
+{
+ if (val)
+ {
+ printf("You cannot use these options together!\n");
+ exit(1);
+ }
+}
diff --git a/myisam/ft_eval.c b/myisam/ft_eval.c
index 9466104100a..c498725daab 100644
--- a/myisam/ft_eval.c
+++ b/myisam/ft_eval.c
@@ -32,7 +32,7 @@ int main(int argc,char *argv[])
bzero((char*)recinfo,sizeof(recinfo));
/* First define 2 columns */
- recinfo[0].type=FIELD_SKIPP_ENDSPACE;
+ recinfo[0].type=FIELD_SKIP_ENDSPACE;
recinfo[0].length=docid_length;
recinfo[1].type=FIELD_BLOB;
recinfo[1].length= 4+mi_portable_sizeof_char_ptr;
@@ -83,23 +83,23 @@ int main(int argc,char *argv[])
for(i=1;create_record(record,qf);i++) {
FT_DOCLIST *result; double w; int t,err;
- result=ft_init_search(file,0,blob_record,(uint) strlen(blob_record),1);
+ result=ft_nlq_init_search(file,0,blob_record,(uint) strlen(blob_record),1);
if(!result) {
printf("Query %d failed with errno %3d\n",i,my_errno);
goto err;
}
if (!silent)
printf("Query %d. Found: %d.\n",i,result->ndocs);
- for(j=0;(err=ft_read_next(result, read_record))==0;j++) {
+ for(j=0;(err=ft_nlq_read_next(result, read_record))==0;j++) {
t=uint2korr(read_record);
- w=ft_get_relevance(result);
+ w=ft_nlq_get_relevance(result);
printf("%d %.*s %f\n",i,t,read_record+2,w);
}
if(err != HA_ERR_END_OF_FILE) {
printf("ft_read_next %d failed with errno %3d\n",j,my_errno);
goto err;
}
- ft_close_search(result);
+ ft_nlq_close_search(result);
}
if (mi_close(file)) goto err;
diff --git a/myisam/ft_eval.h b/myisam/ft_eval.h
index d87b6be9c7c..68be3a39f33 100644
--- a/myisam/ft_eval.h
+++ b/myisam/ft_eval.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & Sergei A. Golubchik
-
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; 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 */
@@ -40,4 +40,3 @@ MI_KEYSEG keyseg[10];
#define MAX_LINE_LENGTH 128
char line[MAX_LINE_LENGTH];
-
diff --git a/myisam/ft_search.c b/myisam/ft_nlq_search.c
index 9a728a4c211..ac9fa5a9a8c 100644
--- a/myisam/ft_search.c
+++ b/myisam/ft_nlq_search.c
@@ -16,9 +16,23 @@
/* Written by Sergei A. Golubchik, who has a shared copyright to this code */
+#define FT_CORE
#include "ftdefs.h"
-/* queries isam and returns list of documents matched */
+/* search with natural language queries */
+
+typedef struct ft_doc_rec {
+ my_off_t dpos;
+ double weight;
+} FT_DOC;
+
+struct st_ft_info {
+ struct _ft_vft *please;
+ MI_INFO *info;
+ int ndocs;
+ int curdoc;
+ FT_DOC doc[1];
+};
typedef struct st_all_in_one {
MI_INFO *info;
@@ -35,7 +49,8 @@ typedef struct st_ft_superdoc {
double tmp_weight;
} FT_SUPERDOC;
-static int FT_SUPERDOC_cmp(FT_SUPERDOC *p1, FT_SUPERDOC *p2)
+static int FT_SUPERDOC_cmp(void* cmp_arg __attribute__((unused)),
+ FT_SUPERDOC *p1, FT_SUPERDOC *p2)
{
if (p1->doc.dpos < p2->doc.dpos)
return -1;
@@ -151,65 +166,67 @@ static int FT_DOC_cmp(FT_DOC *a, FT_DOC *b)
return sgn(b->weight - a->weight);
}
-FT_DOCLIST * ft_init_search(void *info, uint keynr, byte *key,
- uint key_len, my_bool presort)
+FT_INFO *ft_init_nlq_search(MI_INFO *info, uint keynr, byte *query,
+ uint query_len, my_bool presort)
{
- TREE *wtree;
- ALL_IN_ONE aio;
- FT_DOCLIST *dlist;
+ TREE allocated_wtree, *wtree=&allocated_wtree;
+ ALL_IN_ONE aio;
FT_DOC *dptr;
- my_off_t saved_lastpos=((MI_INFO *)info)->lastpos;
+ FT_INFO *dlist=NULL;
+ my_off_t saved_lastpos=info->lastpos;
/* black magic ON */
- if ((int) (keynr = _mi_check_index((MI_INFO *)info,keynr)) < 0)
+ if ((int) (keynr = _mi_check_index(info,keynr)) < 0)
return NULL;
- if (_mi_readinfo((MI_INFO *)info,F_RDLCK,1))
+ if (_mi_readinfo(info,F_RDLCK,1))
return NULL;
/* black magic OFF */
- dlist=NULL;
- aio.info=(MI_INFO *)info;
+ aio.info=info;
aio.keynr=keynr;
- aio.keybuff=aio.info->lastkey+aio.info->s->base.max_key_length;
- aio.keyinfo=aio.info->s->keyinfo+keynr;
- aio.key_root=aio.info->s->state.key_root[keynr];
+ aio.keybuff=info->lastkey+info->s->base.max_key_length;
+ aio.keyinfo=info->s->keyinfo+keynr;
+ aio.key_root=info->s->state.key_root[keynr];
- if (!(wtree=ft_parse(NULL,key,key_len))) return NULL;
+ bzero(&allocated_wtree,sizeof(allocated_wtree));
- init_tree(&aio.dtree,0,sizeof(FT_SUPERDOC),(qsort_cmp)&FT_SUPERDOC_cmp,0,
- NULL);
+ init_tree(&aio.dtree,0,0,sizeof(FT_SUPERDOC),(qsort_cmp2)&FT_SUPERDOC_cmp,0,
+ NULL, NULL);
- if (tree_walk(wtree, (tree_walk_action)&walk_and_match, &aio,
- left_root_right))
+ if(ft_parse(&allocated_wtree,query,query_len))
goto err;
- dlist=(FT_DOCLIST *) my_malloc(sizeof(FT_DOCLIST)+sizeof(FT_DOC)*
- (aio.dtree.elements_in_tree-1),MYF(0));
- if (!dlist)
- goto err;
+ if(tree_walk(wtree, (tree_walk_action)&walk_and_match, &aio,
+ left_root_right))
+ goto err2;
+
+ dlist=(FT_INFO *)my_malloc(sizeof(FT_INFO)+
+ sizeof(FT_DOC)*(aio.dtree.elements_in_tree-1),MYF(0));
+ if(!dlist)
+ goto err2;
+ dlist->please= (struct _ft_vft *) & _ft_vft_nlq;
dlist->ndocs=aio.dtree.elements_in_tree;
dlist->curdoc=-1;
dlist->info=aio.info;
dptr=dlist->doc;
- tree_walk(&aio.dtree, (tree_walk_action)&walk_and_copy, &dptr,
- left_root_right);
+ tree_walk(&aio.dtree, (tree_walk_action)&walk_and_copy,
+ &dptr, left_root_right);
- if (presort)
- {
+ if(presort)
qsort(dlist->doc, dlist->ndocs, sizeof(FT_DOC), (qsort_cmp)&FT_DOC_cmp);
- }
-err:
- delete_tree(&aio.dtree);
+err2:
delete_tree(wtree);
- my_free((char*) wtree,MYF(0));
- ((MI_INFO *)info)->lastpos=saved_lastpos;
+ delete_tree(&aio.dtree);
+
+err:
+ info->lastpos=saved_lastpos;
return dlist;
}
-int ft_read_next(FT_DOCLIST *handler, char *record)
+int ft_nlq_read_next(FT_INFO *handler, char *record)
{
MI_INFO *info= (MI_INFO *) handler->info;
@@ -229,3 +246,45 @@ int ft_read_next(FT_DOCLIST *handler, char *record)
}
return my_errno;
}
+
+float ft_nlq_find_relevance(FT_INFO *handler,
+ byte *record __attribute__((unused)),
+ uint length __attribute__((unused)))
+{
+ int a,b,c;
+ FT_DOC *docs=handler->doc;
+ my_off_t docid=handler->info->lastpos;
+
+ if (docid == HA_POS_ERROR)
+ return -5.0;
+
+ /* Assuming docs[] is sorted by dpos... */
+
+ for (a=0, b=handler->ndocs, c=(a+b)/2; b-a>1; c=(a+b)/2)
+ {
+ if (docs[c].dpos > docid)
+ b=c;
+ else
+ a=c;
+ }
+ if (docs[a].dpos == docid)
+ return (float) docs[a].weight;
+ else
+ return 0.0;
+}
+
+void ft_nlq_close_search(FT_INFO *handler)
+{
+ my_free((gptr)handler,MYF(0));
+}
+
+float ft_nlq_get_relevance(FT_INFO *handler)
+{
+ return (float) handler->doc[handler->curdoc].weight;
+}
+
+void ft_nlq_reinit_search(FT_INFO *handler)
+{
+ handler->curdoc=-1;
+}
+
diff --git a/myisam/ft_parser.c b/myisam/ft_parser.c
index 7ea2e240c36..c1b1190bcab 100644
--- a/myisam/ft_parser.c
+++ b/myisam/ft_parser.c
@@ -33,16 +33,14 @@ typedef struct st_ft_docstat {
double max, nsum, nsum2;
#endif /* EVAL_RUN */
- MI_INFO *info;
- uint keynr;
- byte *keybuf;
} FT_DOCSTAT;
-static int FT_WORD_cmp(FT_WORD *w1, FT_WORD *w2)
+static int FT_WORD_cmp(void* cmp_arg, FT_WORD *w1, FT_WORD *w2)
{
return _mi_compare_text(default_charset_info,
- (uchar*) w1->pos,w1->len,
- (uchar*) w2->pos, w2->len,0);
+ (uchar*) w1->pos, w1->len,
+ (uchar*) w2->pos, w2->len,
+ (my_bool) (cmp_arg != 0));
}
static int walk_and_copy(FT_WORD *word,uint32 count,FT_DOCSTAT *docstat)
@@ -63,17 +61,15 @@ static int walk_and_copy(FT_WORD *word,uint32 count,FT_DOCSTAT *docstat)
/* transforms tree of words into the array, applying normalization */
-FT_WORD * ft_linearize(MI_INFO *info, uint keynr, byte *keybuf, TREE *wtree)
+FT_WORD * ft_linearize(TREE *wtree)
{
FT_WORD *wlist,*p;
FT_DOCSTAT docstat;
+ DBUG_ENTER("ft_linearize");
if ((wlist=(FT_WORD *) my_malloc(sizeof(FT_WORD)*
(1+wtree->elements_in_tree),MYF(0))))
{
- docstat.info=info;
- docstat.keynr=keynr;
- docstat.keybuf=keybuf;
docstat.list=wlist;
docstat.uniq=wtree->elements_in_tree;
#ifdef EVAL_RUN
@@ -83,13 +79,12 @@ FT_WORD * ft_linearize(MI_INFO *info, uint keynr, byte *keybuf, TREE *wtree)
tree_walk(wtree,(tree_walk_action)&walk_and_copy,&docstat,left_root_right);
}
delete_tree(wtree);
- my_free((char*) wtree,MYF(0));
if (!wlist)
- return NULL;
+ DBUG_RETURN(NULL);
docstat.list->pos=NULL;
- for(p=wlist;p->pos;p++)
+ for (p=wlist;p->pos;p++)
{
p->weight=PRENORM_IN_USE;
#ifdef EVAL_RUN
@@ -104,48 +99,133 @@ FT_WORD * ft_linearize(MI_INFO *info, uint keynr, byte *keybuf, TREE *wtree)
#endif
#endif /* EVAL_RUN */
- for(p=wlist;p->pos;p++)
+ for (p=wlist;p->pos;p++)
{
p->weight/=NORM_IN_USE;
}
- return wlist;
+ DBUG_RETURN(wlist);
}
+#define true_word_char(X) (isalnum(X) || (X)=='_')
#ifdef HYPHEN_IS_DELIM
-#define word_char(X) (isalnum(X) || (X)=='_' || (X)=='\'')
+#define misc_word_char(X) ((X)=='\'')
#else
-#define word_char(X) (isalnum(X) || (X)=='_' || (X)=='\'' || (X)=='-')
+#define misc_word_char(X) ((X)=='\'' || (X)=='-')
#endif
+#define word_char(X) (true_word_char(X) || misc_word_char(X))
-/* this is rather dumb first version of the parser */
-TREE * ft_parse(TREE *wtree, byte *doc, int doclen)
+
+/* returns:
+ * 0 - eof
+ * 1 - word found
+ * 2 - left bracket
+ * 3 - right bracket
+ */
+byte ft_get_word(byte **start, byte *end, FT_WORD *word, FTB_PARAM *param)
{
- byte *end=doc+doclen;
- FT_WORD w;
+ byte *doc=*start;
+ int mwc;
+
+ param->yesno=(FTB_YES==' ')?1:0;
+ param->plusminus=param->pmsign=0;
- if (!wtree)
+ while (doc<end)
{
- if (!(wtree=(TREE *)my_malloc(sizeof(TREE),MYF(0)))) return NULL;
- init_tree(wtree,0,sizeof(FT_WORD),(qsort_cmp)&FT_WORD_cmp,0,NULL);
+ for (;doc<end;doc++)
+ {
+ if (true_word_char(*doc)) break;
+ if (*doc == FTB_LBR || *doc == FTB_RBR)
+ {
+ /* param->prev=' '; */
+ *start=doc+1;
+ return (*doc == FTB_RBR)+2;
+ }
+ if (param->prev == ' ')
+ {
+ if (*doc == FTB_YES ) { param->yesno=+1; continue; } else
+ if (*doc == FTB_EGAL) { param->yesno= 0; continue; } else
+ if (*doc == FTB_NO ) { param->yesno=-1; continue; } else
+ if (*doc == FTB_INC ) { param->plusminus++; continue; } else
+ if (*doc == FTB_DEC ) { param->plusminus--; continue; } else
+ if (*doc == FTB_NEG ) { param->pmsign=!param->pmsign; continue; }
+ }
+ param->prev=*doc;
+ param->yesno=param->plusminus=param->pmsign=0;
+ }
+
+ mwc=0;
+ for (word->pos=doc; doc<end; doc++)
+ if (true_word_char(*doc))
+ mwc=0;
+ else if (!misc_word_char(*doc) || mwc++)
+ break;
+
+ param->prev='A'; /* be sure *prev is true_word_char */
+ word->len= (uint)(doc-word->pos) - mwc;
+ if ((param->trunc=(doc<end && *doc == FTB_TRUNC)))
+ doc++;
+
+ if (((word->len >= ft_min_word_len && !is_stopword(word->pos, word->len))
+ || param->trunc) && word->len < ft_max_word_len)
+ {
+ *start=doc;
+ return 1;
+ }
}
+ return 0;
+}
+
+byte ft_simple_get_word(byte **start, byte *end, FT_WORD *word)
+{
+ byte *doc=*start;
+ int mwc;
- w.weight=0;
while (doc<end)
{
for (;doc<end;doc++)
- if (word_char(*doc)) break;
- for (w.pos=doc; doc<end; doc++)
- if (!word_char(*doc)) break;
- if ((w.len= (uint) (doc-w.pos)) < MIN_WORD_LEN) continue;
- if (w.len >= HA_FT_MAXLEN) continue;
- if (is_stopword(w.pos, w.len)) continue;
- if (!tree_insert(wtree, &w, 0))
{
- delete_tree(wtree);
- my_free((char*) wtree,MYF(0));
- return NULL;
+ if (true_word_char(*doc)) break;
+ }
+
+ mwc=0;
+ for(word->pos=doc; doc<end; doc++)
+ if (true_word_char(*doc))
+ mwc=0;
+ else if (!misc_word_char(*doc) || mwc++)
+ break;
+
+ word->len= (uint)(doc-word->pos) - mwc;
+
+ if (word->len >= ft_min_word_len && word->len < ft_max_word_len &&
+ !is_stopword(word->pos, word->len))
+ {
+ *start=doc;
+ return 1;
}
}
- return wtree;
+ return 0;
}
+
+int ft_parse(TREE *wtree, byte *doc, int doclen)
+{
+ byte *end=doc+doclen;
+ FT_WORD w;
+
+ if (!is_tree_inited(wtree))
+ {
+ init_tree(wtree,0,0,sizeof(FT_WORD),(qsort_cmp2)&FT_WORD_cmp,0,NULL, NULL);
+ }
+
+ while (ft_simple_get_word(&doc,end,&w))
+ {
+ if (!tree_insert(wtree, &w, 0))
+ goto err;
+ }
+ return 0;
+
+err:
+ delete_tree(wtree);
+ return 1;
+}
+
diff --git a/myisam/ft_static.c b/myisam/ft_static.c
index 00d9d4ed19a..3efb3a3ec74 100644
--- a/myisam/ft_static.c
+++ b/myisam/ft_static.c
@@ -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 */
@@ -18,6 +18,11 @@
#include "ftdefs.h"
+ulong ft_min_word_len=4;
+ulong ft_max_word_len=HA_FT_MAXLEN;
+ulong ft_max_word_len_for_sort=20;
+const char *ft_boolean_syntax="+ -><()~*:\"\"&|";
+
const MI_KEYSEG ft_keysegs[FT_SEGS]={
{
HA_KEYTYPE_VARTEXT, /* type */
@@ -39,10 +44,29 @@ const MI_KEYSEG ft_keysegs[FT_SEGS]={
},
#endif /* EVAL_RUN */
{
- HA_FT_WTYPE, 7, 0, 0, 0, 0, HA_FT_WLEN, 0, 0, NULL
+ HA_FT_WTYPE, 7, 0, 0, 0, HA_NO_SORT, HA_FT_WLEN, 0, 0, NULL
}
};
+const struct _ft_vft _ft_vft_nlq = {
+ ft_nlq_read_next, ft_nlq_find_relevance, ft_nlq_close_search,
+ ft_nlq_get_relevance, ft_nlq_reinit_search
+};
+const struct _ft_vft _ft_vft_boolean = {
+ ft_boolean_read_next, ft_boolean_find_relevance, ft_boolean_close_search,
+ ft_boolean_get_relevance, ft_boolean_reinit_search
+};
+
+FT_INFO *(*_ft_init_vft[2])(MI_INFO *, uint, byte *, uint, my_bool) =
+{ ft_init_nlq_search, ft_init_boolean_search };
+
+FT_INFO *ft_init_search(uint mode, void *info, uint keynr,
+ byte *query, uint query_len, my_bool presort)
+{
+ return (*_ft_init_vft[mode])((MI_INFO *)info, keynr,
+ query, query_len, presort);
+}
+
const char *ft_precompiled_stopwords[] = {
#ifdef COMPILE_STOPWORDS_IN
diff --git a/myisam/ft_stem.c b/myisam/ft_stem.c
index bdfc73b774b..846d5d2247f 100644
--- a/myisam/ft_stem.c
+++ b/myisam/ft_stem.c
@@ -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 */
@@ -17,4 +17,3 @@
/* Written by Sergei A. Golubchik, who has a shared copyright to this code */
/* mulitingual stem */
-
diff --git a/myisam/ft_stopwords.c b/myisam/ft_stopwords.c
index d796b87ed71..9c2047c3b56 100644
--- a/myisam/ft_stopwords.c
+++ b/myisam/ft_stopwords.c
@@ -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 */
@@ -25,7 +25,8 @@ typedef struct st_ft_stopwords {
static TREE *stopwords3=NULL;
-static int FT_STOPWORD_cmp(FT_STOPWORD *w1, FT_STOPWORD *w2)
+static int FT_STOPWORD_cmp(void* cmp_arg __attribute__((unused)),
+ FT_STOPWORD *w1, FT_STOPWORD *w2)
{
return _mi_compare_text(default_charset_info,
(uchar *)w1->pos,w1->len,
@@ -40,15 +41,15 @@ int ft_init_stopwords(const char **sws)
if(!stopwords3)
{
if(!(stopwords3=(TREE *)my_malloc(sizeof(TREE),MYF(0)))) return -1;
- init_tree(stopwords3,0,sizeof(FT_STOPWORD),(qsort_cmp)&FT_STOPWORD_cmp,0,
- NULL);
+ init_tree(stopwords3,0,0,sizeof(FT_STOPWORD),(qsort_cmp2)&FT_STOPWORD_cmp,0,
+ NULL, NULL);
}
if(!sws) return 0;
for(;*sws;sws++)
{
- if( (sw.len= (uint) strlen(sw.pos=*sws)) < MIN_WORD_LEN) continue;
+ if( (sw.len= (uint) strlen(sw.pos=*sws)) < ft_min_word_len) continue;
if(!tree_insert(stopwords3, &sw, 0))
{
delete_tree(stopwords3); /* purecov: inspected */
diff --git a/myisam/ft_test1.c b/myisam/ft_test1.c
index 5093b591fb2..e1a47ff87c3 100644
--- a/myisam/ft_test1.c
+++ b/myisam/ft_test1.c
@@ -20,7 +20,7 @@
#include "ft_test1.h"
#include <getopt.h>
-static int key_field=FIELD_VARCHAR,extra_field=FIELD_SKIPP_ENDSPACE;
+static int key_field=FIELD_VARCHAR,extra_field=FIELD_SKIP_ENDSPACE;
static uint key_length=200,extra_length=50;
static int key_type=HA_KEYTYPE_TEXT;
static int verbose=0,silent=0,skip_update=0,
@@ -137,7 +137,7 @@ static int run_test(const char *filename)
printf("- Reading rows with key\n");
for (i=0 ; i < NQUERIES ; i++)
{ FT_DOCLIST *result;
- result=ft_init_search(file,0,(char*) query[i],strlen(query[i]),1);
+ result=ft_nlq_init_search(file,0,(char*) query[i],strlen(query[i]),1);
if(!result) {
printf("Query %d: `%s' failed with errno %3d\n",i,query[i],my_errno);
continue;
@@ -145,7 +145,7 @@ static int run_test(const char *filename)
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_read_next(result, read_record);
+ err=ft_nlq_read_next(result, read_record);
if(err==HA_ERR_END_OF_FILE) {
printf("No more matches!\n");
break;
@@ -153,7 +153,7 @@ static int run_test(const char *filename)
printf("ft_read_next %d failed with errno %3d\n",j,my_errno);
break;
}
- w=ft_get_relevance(result);
+ w=ft_nlq_get_relevance(result);
if(key_field == FIELD_VARCHAR) {
uint l;
char *p;
@@ -164,7 +164,7 @@ static int run_test(const char *filename)
printf("%10.7f: %.*s\n",w,recinfo[1].length,
recinfo[0].length+read_record);
}
- ft_close_search(result);
+ ft_nlq_close_search(result);
}
if (mi_close(file)) goto err;
diff --git a/myisam/ft_test1.h b/myisam/ft_test1.h
index 17b0cae66b7..e360244057b 100644
--- a/myisam/ft_test1.h
+++ b/myisam/ft_test1.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 */
@@ -419,4 +419,3 @@ const char *query[NQUERIES]={
"against about after more right the with/without", /* stopwords test */
"mysql license and copyright"
};
-
diff --git a/myisam/ft_update.c b/myisam/ft_update.c
index 753c4dc4029..8ffc35157d2 100644
--- a/myisam/ft_update.c
+++ b/myisam/ft_update.c
@@ -19,6 +19,7 @@
/* functions to work with full-text indices */
#include "ftdefs.h"
+#include <math.h>
/**************************************************************
This is to make ft-code to ignore keyseg.length at all *
@@ -27,46 +28,91 @@
#define set_if_smaller(A,B) /* no op */
/**************************************************************/
+void _mi_ft_segiterator_init(MI_INFO *info, uint keynr, const byte *record,
+ FT_SEG_ITERATOR *ftsi)
+{
+ ftsi->num=info->s->keyinfo[keynr].keysegs-FT_SEGS;
+ ftsi->seg=info->s->keyinfo[keynr].seg;
+ ftsi->rec=record;
+}
-/* parses a document i.e. calls _mi_ft_parse for every keyseg */
-static FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr, byte *keybuf,
- const byte *record)
+void _mi_ft_segiterator_dummy_init(const byte *record, uint len,
+ FT_SEG_ITERATOR *ftsi)
{
- TREE *parsed=NULL;
- MI_KEYSEG *keyseg;
- byte *pos;
- uint i;
+ ftsi->num=1;
+ ftsi->seg=0;
+ ftsi->pos=record;
+ ftsi->len=len;
+}
- keyseg=info->s->keyinfo[keynr].seg;
- for (i=info->s->keyinfo[keynr].keysegs-FT_SEGS ; i-- ; )
- {
- uint len;
+/* This function breaks convention "return 0 in success"
+ but it's easier to use like this
- keyseg--;
- if (keyseg->null_bit && (record[keyseg->null_pos] & keyseg->null_bit))
- continue; /* NULL field */
- pos= (byte *)record+keyseg->start;
- if (keyseg->flag & HA_VAR_LENGTH)
- {
- len=uint2korr(pos);
- pos+=2; /* Skip VARCHAR length */
- set_if_smaller(len,keyseg->length);
- }
- else if (keyseg->flag & HA_BLOB_PART)
- {
- len=_mi_calc_blob_length(keyseg->bit_start,pos);
- memcpy_fixed(&pos,pos+keyseg->bit_start,sizeof(char*));
- set_if_smaller(len,keyseg->length);
- }
- else
- len=keyseg->length;
- if (!(parsed=ft_parse(parsed, pos, len)))
- return NULL;
+ while(_mi_ft_segiterator())
+
+ so "1" means "OK", "0" means "EOF"
+*/
+
+uint _mi_ft_segiterator(register FT_SEG_ITERATOR *ftsi)
+{
+ if (!ftsi->num) return 0; else ftsi->num--;
+ if (!ftsi->seg) return 1; else ftsi->seg--;
+
+ if (ftsi->seg->null_bit &&
+ (ftsi->rec[ftsi->seg->null_pos] & ftsi->seg->null_bit))
+ {
+ ftsi->pos=0;
+ return 1;
+ }
+ ftsi->pos= ftsi->rec+ftsi->seg->start;
+ if (ftsi->seg->flag & HA_VAR_LENGTH)
+ {
+ ftsi->len=uint2korr(ftsi->pos);
+ ftsi->pos+=2; /* Skip VARCHAR length */
+ set_if_smaller(ftsi->len,ftsi->seg->length);
+ return 1;
}
+ if (ftsi->seg->flag & HA_BLOB_PART)
+ {
+ ftsi->len=_mi_calc_blob_length(ftsi->seg->bit_start,ftsi->pos);
+ memcpy_fixed((char*) &ftsi->pos, ftsi->pos+ftsi->seg->bit_start,
+ sizeof(char*));
+ set_if_smaller(ftsi->len,ftsi->seg->length);
+ return 1;
+ }
+ ftsi->len=ftsi->seg->length;
+ return 1;
+}
+
+/* parses a document i.e. calls ft_parse for every keyseg */
+uint _mi_ft_parse(TREE *parsed, MI_INFO *info, uint keynr, const byte *record)
+{
+ FT_SEG_ITERATOR ftsi;
+ _mi_ft_segiterator_init(info, keynr, record, &ftsi);
+
+ while (_mi_ft_segiterator(&ftsi))
+ if (ftsi.pos)
+ if (ft_parse(parsed, (byte *)ftsi.pos, ftsi.len))
+ return 1;
+
/* Handle the case where all columns are NULL */
- if (!parsed && !(parsed=ft_parse(0, (byte*) "", 0)))
+ if (!is_tree_inited(parsed) && ft_parse(parsed, (byte*) "", 0))
+ return 1;
+ else
+ return 0;
+}
+
+FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr,
+ byte *keybuf __attribute__((unused)),
+ const byte *record)
+{
+ TREE ptree;
+
+ bzero((char*) &ptree, sizeof(ptree));
+ if (_mi_ft_parse(&ptree, info, keynr, record))
return NULL;
- return ft_linearize(info, keynr, keybuf, parsed);
+
+ return ft_linearize(/*info, keynr, keybuf, */ &ptree);
}
static int _mi_ft_store(MI_INFO *info, uint keynr, byte *keybuf,
@@ -106,53 +152,70 @@ static int _mi_ft_erase(MI_INFO *info, uint keynr, byte *keybuf, FT_WORD *wlist,
int _mi_ft_cmp(MI_INFO *info, uint keynr, const byte *rec1, const byte *rec2)
{
- MI_KEYSEG *keyseg;
- byte *pos1, *pos2;
- uint i;
+ FT_SEG_ITERATOR ftsi1, ftsi2;
+ _mi_ft_segiterator_init(info, keynr, rec1, &ftsi1);
+ _mi_ft_segiterator_init(info, keynr, rec2, &ftsi2);
- i=info->s->keyinfo[keynr].keysegs-FT_SEGS;
- keyseg=info->s->keyinfo[keynr].seg;
- while(i--)
+ while(_mi_ft_segiterator(&ftsi1) && _mi_ft_segiterator(&ftsi2))
{
- uint len1, len2;
- LINT_INIT(len1); LINT_INIT(len2);
- keyseg--;
- if (keyseg->null_bit)
- {
- if ( (rec1[keyseg->null_pos] ^ rec2[keyseg->null_pos])
- & keyseg->null_bit )
- return THOSE_TWO_DAMN_KEYS_ARE_REALLY_DIFFERENT;
- if (rec1[keyseg->null_pos] & keyseg->null_bit )
- continue; /* NULL field */
- }
- pos1= (byte *)rec1+keyseg->start;
- pos2= (byte *)rec2+keyseg->start;
- if (keyseg->flag & HA_VAR_LENGTH)
- {
- len1=uint2korr(pos1);
- pos1+=2; /* Skip VARCHAR length */
- set_if_smaller(len1,keyseg->length);
- len2=uint2korr(pos2);
- pos2+=2; /* Skip VARCHAR length */
- set_if_smaller(len2,keyseg->length);
- }
- else if (keyseg->flag & HA_BLOB_PART)
+ if ((ftsi1.pos != ftsi2.pos) &&
+ (!ftsi1.pos || !ftsi2.pos ||
+ _mi_compare_text(default_charset_info,
+ (uchar*) ftsi1.pos,ftsi1.len,
+ (uchar*) ftsi2.pos,ftsi2.len,0)))
+ return THOSE_TWO_DAMN_KEYS_ARE_REALLY_DIFFERENT;
+ }
+ return GEE_THEY_ARE_ABSOLUTELY_IDENTICAL;
+}
+
+/* update a document entry */
+int _mi_ft_update(MI_INFO *info, uint keynr, byte *keybuf,
+ const byte *oldrec, const byte *newrec, my_off_t pos)
+{
+ int error= -1;
+ FT_WORD *oldlist,*newlist, *old_word, *new_word;
+ uint key_length;
+ int cmp, cmp2;
+
+ if (!(old_word=oldlist=_mi_ft_parserecord(info, keynr, keybuf, oldrec)))
+ goto err0;
+ if (!(new_word=newlist=_mi_ft_parserecord(info, keynr, keybuf, newrec)))
+ goto err1;
+
+ error=0;
+ while(old_word->pos && new_word->pos)
+ {
+ cmp=_mi_compare_text(default_charset_info,
+ (uchar*) old_word->pos,old_word->len,
+ (uchar*) new_word->pos,new_word->len,0);
+ cmp2= cmp ? 0 : (fabs(old_word->weight - new_word->weight) > 1.e-5);
+
+ if (cmp < 0 || cmp2)
{
- len1=_mi_calc_blob_length(keyseg->bit_start,pos1);
- memcpy_fixed(&pos1,pos1+keyseg->bit_start,sizeof(char*));
- set_if_smaller(len1,keyseg->length);
- len2=_mi_calc_blob_length(keyseg->bit_start,pos2);
- memcpy_fixed(&pos2,pos2+keyseg->bit_start,sizeof(char*));
- set_if_smaller(len2,keyseg->length);
+ key_length=_ft_make_key(info,keynr,keybuf,old_word,pos);
+ if ((error=_mi_ck_delete(info,keynr,(uchar*) keybuf,key_length)))
+ goto err2;
}
- else /* fixed length key */
+ if (cmp > 0 || cmp2)
{
- len1=len2=keyseg->length;
+ key_length=_ft_make_key(info,keynr,keybuf,new_word,pos);
+ if ((error=_mi_ck_write(info,keynr,(uchar*) keybuf,key_length)))
+ goto err2;
}
- if ((len1 != len2) || memcmp(pos1, pos2, len1))
- return THOSE_TWO_DAMN_KEYS_ARE_REALLY_DIFFERENT;
- }
- return GEE_THEY_ARE_ABSOLUTELY_IDENTICAL;
+ if (cmp<=0) old_word++;
+ if (cmp>=0) new_word++;
+ }
+ if (old_word->pos)
+ error=_mi_ft_erase(info,keynr,keybuf,old_word,pos);
+ else if (new_word->pos)
+ error=_mi_ft_store(info,keynr,keybuf,new_word,pos);
+
+err2:
+ my_free((char*) newlist,MYF(0));
+err1:
+ my_free((char*) oldlist,MYF(0));
+err0:
+ return error;
}
/* adds a document to the collection */
diff --git a/myisam/ftdefs.h b/myisam/ftdefs.h
index d9b4ff6b44d..1a3c0ef60dc 100644
--- a/myisam/ftdefs.h
+++ b/myisam/ftdefs.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 */
@@ -22,15 +22,18 @@
#include <m_ctype.h>
#include <my_tree.h>
-#define MIN_WORD_LEN 4
-
#define HYPHEN_IS_DELIM
#define HYPHEN_IS_CONCAT /* not used for now */
#define COMPILE_STOPWORDS_IN
-/* Most of the formulae were shamelessly stolen from SMART distribution
- ftp://ftp.cs.cornell.edu/pub/smart/smart.11.0.tar.Z
+/* Interested readers may consult SMART
+ (ftp://ftp.cs.cornell.edu/pub/smart/smart.11.0.tar.Z)
+ for an excellent implementation of vector space model we use.
+ It also demonstrate the usage of different weghting techniques.
+ This code, though, is completely original and is not based on the
+ SMART code but was in some cases inspired by it.
+
NORM_PIVOT was taken from the article
A.Singhal, C.Buckley, M.Mitra, "Pivoted Document Length Normalization",
ACM SIGIR'96, 21-29, 1996
@@ -82,6 +85,17 @@ extern ulong collstat;
#define GWS_ENTROPY (1-(suml/sum-log(sum))/log(aio->info->state->records))
/*=================================================================*/
+/* Boolean search operators */
+#define FTB_YES (ft_boolean_syntax[0])
+#define FTB_EGAL (ft_boolean_syntax[1])
+#define FTB_NO (ft_boolean_syntax[2])
+#define FTB_INC (ft_boolean_syntax[3])
+#define FTB_DEC (ft_boolean_syntax[4])
+#define FTB_LBR (ft_boolean_syntax[5])
+#define FTB_RBR (ft_boolean_syntax[6])
+#define FTB_NEG (ft_boolean_syntax[7])
+#define FTB_TRUNC (ft_boolean_syntax[8])
+
typedef struct st_ft_word {
byte * pos;
uint len;
@@ -91,9 +105,50 @@ typedef struct st_ft_word {
#endif /* EVAL_RUN */
} FT_WORD;
+typedef struct st_ftb_param {
+ byte prev;
+ int yesno;
+ int plusminus;
+ bool pmsign;
+ bool trunc;
+} FTB_PARAM;
+
int is_stopword(char *word, uint len);
uint _ft_make_key(MI_INFO *, uint , byte *, FT_WORD *, my_off_t);
-TREE * ft_parse(TREE *, byte *, int);
-FT_WORD * ft_linearize(MI_INFO *, uint, byte *, TREE *);
+byte ft_get_word(byte **, byte *, FT_WORD *, FTB_PARAM *);
+byte ft_simple_get_word(byte **, byte *, FT_WORD *);
+
+typedef struct _st_ft_seg_iterator {
+ uint num, len;
+ MI_KEYSEG *seg;
+ const byte *rec, *pos;
+} FT_SEG_ITERATOR;
+
+void _mi_ft_segiterator_init(MI_INFO *, uint, const byte *, FT_SEG_ITERATOR *);
+void _mi_ft_segiterator_dummy_init(const byte *, uint, FT_SEG_ITERATOR *);
+uint _mi_ft_segiterator(FT_SEG_ITERATOR *);
+
+int ft_parse(TREE *, byte *, int);
+FT_WORD * ft_linearize(/*MI_INFO *, uint, byte *, */TREE *);
+FT_WORD * _mi_ft_parserecord(MI_INFO *, uint, byte *, const byte *);
+uint _mi_ft_parse(TREE *parsed, MI_INFO *info, uint keynr, const byte *record);
+
+extern const struct _ft_vft _ft_vft_nlq;
+FT_INFO *ft_init_nlq_search(MI_INFO *, uint, byte *, uint, my_bool);
+int ft_nlq_read_next(FT_INFO *, char *);
+float ft_nlq_find_relevance(FT_INFO *, byte *, uint);
+void ft_nlq_close_search(FT_INFO *);
+float ft_nlq_get_relevance(FT_INFO *);
+my_off_t ft_nlq_get_docid(FT_INFO *);
+void ft_nlq_reinit_search(FT_INFO *);
+
+extern const struct _ft_vft _ft_vft_boolean;
+FT_INFO *ft_init_boolean_search(MI_INFO *, uint, byte *, uint, my_bool);
+int ft_boolean_read_next(FT_INFO *, char *);
+float ft_boolean_find_relevance(FT_INFO *, byte *, uint);
+void ft_boolean_close_search(FT_INFO *);
+float ft_boolean_get_relevance(FT_INFO *);
+my_off_t ft_boolean_get_docid(FT_INFO *);
+void ft_boolean_reinit_search(FT_INFO *);
diff --git a/myisam/fulltext.h b/myisam/fulltext.h
index 8fcac8172b1..f787c9bcfe8 100644
--- a/myisam/fulltext.h
+++ b/myisam/fulltext.h
@@ -24,7 +24,6 @@
/* shoudn't be def'ed when linking with mysql */
#undef EVAL_RUN
-#define HA_FT_MAXLEN 254
#define HA_FT_WTYPE HA_KEYTYPE_FLOAT
#define HA_FT_WLEN 4
#ifdef EVAL_RUN
diff --git a/myisam/mi_cache.c b/myisam/mi_cache.c
index 69a1cb0d7a5..55f85fb99d1 100644
--- a/myisam/mi_cache.c
+++ b/myisam/mi_cache.c
@@ -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 */
@@ -45,11 +45,11 @@ int _mi_read_cache(IO_CACHE *info, byte *buff, my_off_t pos, uint length,
buff+=read_length;
}
if ((offset= (my_off_t) (pos - info->pos_in_file)) <
- (my_off_t) (info->rc_end - info->rc_request_pos))
+ (my_off_t) (info->read_end - info->request_pos))
{
- in_buff_pos=info->rc_request_pos+(uint) offset;
- in_buff_length= min(length,(uint) (info->rc_end-in_buff_pos));
- memcpy(buff,info->rc_request_pos+(uint) offset,(size_t) in_buff_length);
+ 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))
DBUG_RETURN(0);
pos+=in_buff_length;
@@ -60,19 +60,22 @@ int _mi_read_cache(IO_CACHE *info, byte *buff, my_off_t pos, uint length,
if (flag & READING_NEXT)
{
if (pos != ((info)->pos_in_file +
- (uint) ((info)->rc_end - (info)->rc_request_pos)))
+ (uint) ((info)->read_end - (info)->request_pos)))
{
info->pos_in_file=pos; /* Force start here */
- info->rc_pos=info->rc_end=info->rc_request_pos; /* Everything used */
+ info->read_pos=info->read_end=info->request_pos; /* Everything used */
info->seek_not_done=1;
}
else
- info->rc_pos=info->rc_end; /* All block used */
+ info->read_pos=info->read_end; /* All block used */
if (!(*info->read_function)(info,buff,length))
DBUG_RETURN(0);
if (!(flag & READING_HEADER) || info->error == -1 ||
(uint) info->error+in_buff_length < 3)
{
+ DBUG_PRINT("error",
+ ("Error %d reading next-multi-part block (Got %d bytes)",
+ my_errno, info->error));
if (!my_errno || my_errno == -1)
my_errno=HA_ERR_WRONG_IN_RECORD;
DBUG_RETURN(1);
@@ -87,6 +90,9 @@ int _mi_read_cache(IO_CACHE *info, byte *buff, my_off_t pos, uint length,
if (!(flag & READING_HEADER) || (int) read_length == -1 ||
read_length+in_buff_length < 3)
{
+ DBUG_PRINT("error",
+ ("Error %d reading new block (Got %d bytes)",
+ my_errno, (int) read_length));
if (!my_errno || my_errno == -1)
my_errno=HA_ERR_WRONG_IN_RECORD;
DBUG_RETURN(1);
diff --git a/myisam/mi_changed.c b/myisam/mi_changed.c
index bd6b14b0c6c..c2ab5568eba 100644
--- a/myisam/mi_changed.c
+++ b/myisam/mi_changed.c
@@ -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 */
@@ -24,7 +24,7 @@ int mi_is_changed(MI_INFO *info)
{
int result;
DBUG_ENTER("mi_is_changed");
- if (_mi_readinfo(info,F_RDLCK,1))
+ if (fast_mi_readinfo(info))
DBUG_RETURN(-1);
VOID(_mi_writeinfo(info,0));
result=(int) info->data_changed;
diff --git a/myisam/mi_check.c b/myisam/mi_check.c
index 89fcfe74cea..2ba74836ab7 100644
--- a/myisam/mi_check.c
+++ b/myisam/mi_check.c
@@ -16,7 +16,7 @@
/* Descript, check and repair of ISAM tables */
-#include "fulltext.h"
+#include "ftdefs.h"
#include <m_ctype.h>
#include <stdarg.h>
#include <getopt.h>
@@ -46,6 +46,7 @@ static int writekeys(MI_CHECK *param, MI_INFO *info,byte *buff,
static int sort_one_index(MI_CHECK *param, MI_INFO *info,MI_KEYDEF *keyinfo,
my_off_t pagepos, File new_file);
static int sort_key_read(SORT_INFO *sort_info,void *key);
+static int sort_ft_key_read(SORT_INFO *sort_info,void *key);
static int sort_get_next_record(SORT_INFO *sort_info);
static int sort_key_cmp(SORT_INFO *sort_info, const void *a,const void *b);
static int sort_key_write(SORT_INFO *sort_info, const void *a);
@@ -54,7 +55,7 @@ static my_off_t get_record_for_key(MI_INFO *info,MI_KEYDEF *keyinfo,
static int sort_insert_key(MI_CHECK *param, reg1 SORT_KEY_BLOCKS *key_block,
uchar *key, my_off_t prev_block);
static int sort_delete_record(MI_CHECK *param);
-static int flush_pending_blocks(MI_CHECK *param);
+/*static int flush_pending_blocks(MI_CHECK *param);*/
static SORT_KEY_BLOCKS *alloc_key_blocks(MI_CHECK *param, uint blocks,
uint buffer_length);
static void update_key_parts(MI_KEYDEF *keyinfo,
@@ -104,6 +105,7 @@ void myisamchk_init(MI_CHECK *param)
int chk_status(MI_CHECK *param, register MI_INFO *info)
{
MYISAM_SHARE *share=info->s;
+
if (mi_is_crashed_on_repair(info))
mi_check_print_warning(param,
"Table is marked as crashed and last repair failed");
@@ -219,7 +221,7 @@ int chk_del(MI_CHECK *param, register MI_INFO *info, uint test_flag)
}
DBUG_RETURN(0);
wrong:
- param->retry_without_quick=1; /* Don't use quick repair */
+ param->testflag|=T_RETRY_WITHOUT_QUICK;
if (test_flag & T_VERBOSE) puts("");
mi_check_print_error(param,"record delete-link-chain corrupted");
DBUG_RETURN(1);
@@ -231,7 +233,7 @@ wrong:
static int check_k_link(MI_CHECK *param, register MI_INFO *info, uint nr)
{
my_off_t next_link;
- uint block_size=(nr+1)*MI_KEY_BLOCK_LENGTH;
+ uint block_size=(nr+1)*MI_MIN_KEY_BLOCK_LENGTH;
ha_rows records;
char llbuff[21],*buff;
DBUG_ENTER("check_k_link");
@@ -319,7 +321,7 @@ int chk_size(MI_CHECK *param, register MI_INFO *info)
error=1;
mi_check_print_error(param,"Size of datafile is: %-9s Should be: %s",
llstr(size,buff), llstr(skr,buff2));
- param->retry_without_quick=1; /* Don't use quick repair */
+ param->testflag|=T_RETRY_WITHOUT_QUICK;
}
else
{
@@ -1092,7 +1094,7 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend)
mi_check_print_error(param,"got error: %d when reading datafile at record: %s",my_errno, llstr(records,llbuff));
err2:
my_free((gptr) record,MYF(0));
- param->retry_without_quick=1;
+ param->testflag|=T_RETRY_WITHOUT_QUICK;
DBUG_RETURN(1);
} /* chk_data_link */
@@ -1119,6 +1121,10 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info,
share->pack.header_length;
got_error=1;
new_file= -1;
+ sort_info->buff=0;
+ sort_info->buff_length=0;
+ sort_info->record=0;
+
if (!(param->testflag & T_SILENT))
{
printf("- recovering (with keycache) MyISAM-table '%s'\n",name);
@@ -1126,12 +1132,15 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info,
}
if (!param->using_global_keycache)
- VOID(init_key_cache(param->use_buffers,NEAD_MEM));
+ VOID(init_key_cache(param->use_buffers,NEED_MEM));
if (init_io_cache(&param->read_cache,info->dfile,
(uint) param->read_buffer_length,
READ_CACHE,share->pack.header_length,1,MYF(MY_WME)))
+ {
+ bzero(&info->rec_cache,sizeof(info->rec_cache));
goto err;
+ }
if (!rep_quick)
if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length,
WRITE_CACHE, new_header_length, 1,
@@ -1139,7 +1148,6 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info,
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_malloc((uint) share->base.pack_reclength,
MYF(0))))
{
@@ -1149,7 +1157,10 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info,
if (!rep_quick)
{
- if ((new_file=my_raid_create(fn_format(param->temp_filename,name,"",
+ /* Get real path for data file */
+ fn_format(param->temp_filename,name,"", MI_NAME_DEXT,2+4+32);
+ if ((new_file=my_raid_create(fn_format(param->temp_filename,
+ param->temp_filename,"",
DATA_TMP_EXT,
2+4),
0,param->tmpfile_createflag,
@@ -1227,9 +1238,10 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info,
USE_WHOLE_KEY);
}
sort_info->dupp++;
- if (rep_quick == 1)
+ if (!(rep_quick & T_FORCE_UNIQUENESS))
{
- param->error_printed=param->retry_without_quick=1;
+ param->testflag|=T_RETRY_WITHOUT_QUICK;
+ param->error_printed=1;
goto err;
}
continue;
@@ -1258,7 +1270,8 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info,
mi_check_print_error(param,"Couldn't fix table with quick recovery: Found wrong number of deleted records");
mi_check_print_error(param,"Run recovery again without -q");
got_error=1;
- param->retry_repair=param->retry_without_quick=1;
+ param->retry_repair=1;
+ param->testflag|=T_RETRY_WITHOUT_QUICK;
goto err;
}
if (param->testflag & T_SAFE_REPAIR)
@@ -1277,8 +1290,6 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info,
my_close(info->dfile,MYF(0));
info->dfile=new_file;
info->state->data_file_length=sort_info->filepos;
- /* Only whole records */
- share->state.split=info->state->records+info->state->del;
share->state.version=(ulong) time((time_t*) 0); /* Force reopen */
}
else
@@ -1311,11 +1322,11 @@ err:
{
my_close(new_file,MYF(0));
info->dfile=new_file= -1;
- if (change_to_newfile(share->filename,MI_NAME_DEXT,
+ if (change_to_newfile(share->data_file_name,MI_NAME_DEXT,
DATA_TMP_EXT, share->base.raid_chunks,
(param->testflag & T_BACKUP_DATA ?
MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) ||
- mi_open_datafile(info,share))
+ mi_open_datafile(info,share,-1))
got_error=1;
}
}
@@ -1501,8 +1512,10 @@ int mi_sort_index(MI_CHECK *param, register MI_INFO *info, my_string name)
if (!(param->testflag & T_SILENT))
printf("- Sorting index for MyISAM-table '%s'\n",name);
- if ((new_file=my_create(fn_format(param->temp_filename,name,"",
- INDEX_TMP_EXT,2+4),
+ /* Get real path for index file */
+ fn_format(param->temp_filename,name,"", MI_NAME_IEXT,2+4+32);
+ if ((new_file=my_create(fn_format(param->temp_filename,param->temp_filename,
+ "", INDEX_TMP_EXT,2+4),
0,param->tmpfile_createflag,MYF(0))) <= 0)
{
mi_check_print_error(param,"Can't create new tempfile: '%s'",
@@ -1522,7 +1535,7 @@ int mi_sort_index(MI_CHECK *param, register MI_INFO *info, my_string name)
if (share->state.key_root[key] != HA_OFFSET_ERROR)
{
- index_pos[key]=param->new_file_pos; /* Write first block here */
+ index_pos[key]=param->new_file_pos; /* Write first block here */
if (sort_one_index(param,info,keyinfo,share->state.key_root[key],
new_file))
goto err;
@@ -1543,7 +1556,7 @@ int mi_sort_index(MI_CHECK *param, register MI_INFO *info, my_string name)
VOID(my_close(share->kfile,MYF(MY_WME)));
share->kfile = -1;
VOID(my_close(new_file,MYF(MY_WME)));
- if (change_to_newfile(share->filename,MI_NAME_IEXT,INDEX_TMP_EXT,0,
+ if (change_to_newfile(share->index_file_name,MI_NAME_IEXT,INDEX_TMP_EXT,0,
MYF(0)) ||
mi_open_keyfile(share))
goto err2;
@@ -1643,9 +1656,14 @@ err:
} /* 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 */
+ /*
+ Let temporary file replace old file.
+ This assumes that the new file was created in the same
+ directory as given by realpath(filename).
+ This will ensure that any symlinks that are used will still work.
+ Copy stats from old file to new file, deletes orignal and
+ changes new file name to old file name
+ */
int change_to_newfile(const char * filename, const char * old_ext,
const char * new_ext,
@@ -1660,8 +1678,10 @@ int change_to_newfile(const char * filename, const char * old_ext,
raid_chunks,
MYF(MY_WME | MY_LINK_WARNING | MyFlags));
#endif
- return my_redel(fn_format(old_filename,filename,"",old_ext,2+4),
- fn_format(new_filename,filename,"",new_ext,2+4),
+ /* Get real path to filename */
+ (void) fn_format(old_filename,filename,"",old_ext,2+4+32);
+ return my_redel(old_filename,
+ fn_format(new_filename,old_filename,"",new_ext,2+4),
MYF(MY_WME | MY_LINK_WARNING | MyFlags));
} /* change_to_newfile */
@@ -1752,22 +1772,6 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
printf("Data records: %s\n", llstr(start_records,llbuff));
}
- /* Hmm, repair_by_sort uses find_all_keys, and find_all_keys strictly
- implies "one row - one key per keynr", while for ft_key one row/keynr
- can produce as many keys as the number of unique words in the text
- that's why I disabled repair_by_sort for ft-keys. (serg)
- */
- for (i=0 ; i < share->base.keys ; i++)
- {
- if ((((ulonglong) 1 << i) & key_map) &&
- (share->keyinfo[i].flag & HA_FULLTEXT))
- {
- mi_check_print_error(param,
- "Can`t use repair_by_sort with FULLTEXT key");
- DBUG_RETURN(1);
- }
- }
-
bzero((char*) sort_info,sizeof(*sort_info));
if (!(sort_info->key_block=
alloc_key_blocks(param,
@@ -1794,7 +1798,10 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
}
if (!rep_quick)
{
- if ((new_file=my_raid_create(fn_format(param->temp_filename,name,"",
+ /* Get real path for data file */
+ fn_format(param->temp_filename,name,"", MI_NAME_DEXT,2+4+32);
+ if ((new_file=my_raid_create(fn_format(param->temp_filename,
+ param->temp_filename, "",
DATA_TMP_EXT,
2+4),
0,param->tmpfile_createflag,
@@ -1851,6 +1858,8 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
param->read_cache.end_of_file=sort_info->filelength=
my_seek(param->read_cache.file,0L,MY_SEEK_END,MYF(0));
+ sort_info->wordlist=NULL;
+
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)
@@ -1862,7 +1871,6 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
(ha_rows) (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;
sort_param.tmpdir=param->tmpdir;
sort_param.myf_rw=param->myf_rw;
@@ -1908,6 +1916,17 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
info->state->records=info->state->del=share->state.split=0;
info->state->empty=0;
+ if (sort_info->keyinfo->flag & HA_FULLTEXT)
+ {
+ sort_param.max_records=sort_info->max_records=
+ (ha_rows) (sort_info->filelength/ft_max_word_len_for_sort+1);
+
+ sort_param.key_read=sort_ft_key_read;
+ sort_param.key_length+=ft_max_word_len_for_sort-ft_max_word_len;
+ }
+ else
+ sort_param.key_read=sort_key_read;
+
if (_create_index_by_sort(&sort_param,
(my_bool) (!(param->testflag & T_VERBOSE)),
(uint) param->sort_buffer_length))
@@ -1943,7 +1962,6 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
share->state.state.data_file_length = info->state->data_file_length
= sort_info->filepos;
/* Only whole records */
- share->state.split=info->state->records+info->state->del;
share->state.version=(ulong) time((time_t*) 0);
my_close(info->dfile,MYF(0));
info->dfile=new_file;
@@ -1953,8 +1971,8 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
else
info->state->data_file_length=sort_info->max_pos;
- if (flush_pending_blocks(param))
- goto err;
+ /*if (flush_pending_blocks(param))
+ goto err;*/
param->read_cache.file=info->dfile; /* re-init read cache */
reinit_io_cache(&param->read_cache,READ_CACHE,share->pack.header_length,1,
@@ -1971,11 +1989,12 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
mi_check_print_error(param,"Couldn't fix table with quick recovery: Found wrong number of deleted records");
mi_check_print_error(param,"Run recovery again without -q");
got_error=1;
- param->retry_repair=param->retry_without_quick=1;
+ param->retry_repair=1;
+ param->testflag|=T_RETRY_WITHOUT_QUICK;
goto err;
}
- if (rep_quick != 1)
+ if (rep_quick & T_FORCE_UNIQUENESS)
{
my_off_t skr=info->state->data_file_length+
(share->options & HA_OPTION_COMPRESS_RECORD ?
@@ -2023,11 +2042,11 @@ err:
{
my_close(new_file,MYF(0));
info->dfile=new_file= -1;
- if (change_to_newfile(share->filename,MI_NAME_DEXT,
+ if (change_to_newfile(share->data_file_name,MI_NAME_DEXT,
DATA_TMP_EXT, share->base.raid_chunks,
(param->testflag & T_BACKUP_DATA ?
MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) ||
- mi_open_datafile(info,share))
+ mi_open_datafile(info,share,-1))
got_error=1;
}
}
@@ -2081,12 +2100,57 @@ static int sort_key_read(SORT_INFO *sort_info, void *key)
"Found too many records; Can`t continue");
DBUG_RETURN(1);
}
- (void) _mi_make_key(info,sort_info->key,(uchar*)key,sort_info->record,
- sort_info->filepos);
+ sort_info->real_key_length=(info->s->rec_reflength+
+ _mi_make_key(info, sort_info->key,
+ (uchar*) key, sort_info->record,
+ sort_info->filepos));
DBUG_RETURN(sort_write_record(sort_info));
} /* sort_key_read */
+static int sort_ft_key_read(SORT_INFO *sort_info, void *key)
+{
+ int error;
+ MI_INFO *info;
+ FT_WORD *wptr=0;
+ DBUG_ENTER("sort_ft_key_read");
+
+ info=sort_info->info;
+
+ if (!sort_info->wordlist)
+ {
+ do
+ {
+ my_free((char*) wptr, MYF(MY_ALLOW_ZERO_PTR));
+ if ((error=sort_get_next_record(sort_info)))
+ DBUG_RETURN(error);
+ if (!(wptr=_mi_ft_parserecord(info,sort_info->key,key,sort_info->record)))
+ DBUG_RETURN(1);
+ error=sort_write_record(sort_info);
+ }
+ while (!wptr->pos);
+ sort_info->wordptr=sort_info->wordlist=wptr;
+ }
+ else
+ {
+ error=0;
+ wptr=(FT_WORD*)(sort_info->wordptr);
+ }
+
+ sort_info->real_key_length=info->s->rec_reflength+_ft_make_key(info,
+ sort_info->key,key,wptr++,sort_info->filepos);
+ if (!wptr->pos)
+ {
+ my_free((char*) sort_info->wordlist, MYF(0));
+ sort_info->wordlist=0;
+ }
+ else
+ sort_info->wordptr=(void*)wptr;
+
+
+ DBUG_RETURN(error);
+} /* sort_ft_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 */
@@ -2114,14 +2178,17 @@ static int sort_get_next_record(SORT_INFO *sort_info)
{
if (param->read_cache.error)
param->out_flag |= O_DATA_LOST;
- param->retry_repair=param->retry_without_quick=1;
+ param->retry_repair=1;
+ param->testflag|=T_RETRY_WITHOUT_QUICK;
DBUG_RETURN(-1);
}
sort_info->start_recpos=sort_info->pos;
if (!sort_info->fix_datafile)
+ {
sort_info->filepos=sort_info->pos;
+ share->state.split++;
+ }
sort_info->max_pos=(sort_info->pos+=share->base.pack_reclength);
- share->state.split++;
if (*sort_info->record)
{
if (param->calc_checksum)
@@ -2146,8 +2213,8 @@ static int sort_get_next_record(SORT_INFO *sort_info)
if (searching)
{
pos=MY_ALIGN(pos,MI_DYN_ALIGN_SIZE);
- param->retry_without_quick=1;
- sort_info->start_recpos=pos;
+ param->testflag|=T_RETRY_WITHOUT_QUICK;
+ sort_info->start_recpos=pos;
}
do
{
@@ -2182,7 +2249,8 @@ static int sort_get_next_record(SORT_INFO *sort_info)
if (searching && ! sort_info->fix_datafile)
{
param->error_printed=1;
- param->retry_repair=param->retry_without_quick=1;
+ param->retry_repair=1;
+ param->testflag|=T_RETRY_WITHOUT_QUICK;
DBUG_RETURN(1); /* Something wrong with data */
}
if (((b_type=_mi_get_block_info(&block_info,-1,pos)) &
@@ -2292,7 +2360,8 @@ static int sort_get_next_record(SORT_INFO *sort_info)
continue;
}
- share->state.split++;
+ if (!sort_info->fix_datafile)
+ share->state.split++;
if (! found_record++)
{
sort_info->find_length=left_length=block_info.rec_len;
@@ -2392,7 +2461,8 @@ static int sort_get_next_record(SORT_INFO *sort_info)
if (searching && ! sort_info->fix_datafile)
{
param->error_printed=1;
- param->retry_repair=param->retry_without_quick=1;
+ param->retry_repair=1;
+ param->testflag|=T_RETRY_WITHOUT_QUICK;
DBUG_RETURN(1); /* Something wrong with data */
}
sort_info->start_recpos=sort_info->pos;
@@ -2430,10 +2500,12 @@ static int sort_get_next_record(SORT_INFO *sort_info)
}
info->checksum=mi_checksum(info,sort_info->record);
if (!sort_info->fix_datafile)
+ {
sort_info->filepos=sort_info->pos;
+ share->state.split++;
+ }
sort_info->max_pos=(sort_info->pos=block_info.filepos+
block_info.rec_len);
- share->state.split++;
info->packed_length=block_info.rec_len;
if (param->calc_checksum)
param->glob_crc+= info->checksum;
@@ -2471,6 +2543,7 @@ int sort_write_record(SORT_INFO *sort_info)
DBUG_RETURN(1);
}
sort_info->filepos+=share->base.pack_reclength;
+ info->s->state.split++;
/* sort_info->param->glob_crc+=mi_static_checksum(info, sort_info->record); */
break;
case DYNAMIC_RECORD:
@@ -2495,20 +2568,28 @@ int sort_write_record(SORT_INFO *sort_info)
}
info->checksum=mi_checksum(info,sort_info->record);
reclength=_mi_rec_pack(info,from,sort_info->record);
- /* sort_info->param->glob_crc+=info->checksum; */
- block_length=reclength+ 3 + test(reclength >= (65520-3));
- if (block_length < share->base.min_block_length)
- block_length=share->base.min_block_length;
flag=0;
- info->update|=HA_STATE_WRITE_AT_END;
- block_length=MY_ALIGN(block_length,MI_DYN_ALIGN_SIZE);
- if (_mi_write_part_record(info,0L,block_length,HA_OFFSET_ERROR,
- &from,&reclength,&flag))
+ /* sort_info->param->glob_crc+=info->checksum; */
+
+ do
{
- mi_check_print_error(param,"%d when writing to datafile",my_errno);
- DBUG_RETURN(1);
- }
- sort_info->filepos+=block_length;
+ block_length=reclength+ 3 + test(reclength >= (65520-3));
+ if (block_length < share->base.min_block_length)
+ block_length=share->base.min_block_length;
+ info->update|=HA_STATE_WRITE_AT_END;
+ block_length=MY_ALIGN(block_length,MI_DYN_ALIGN_SIZE);
+ if (block_length > MI_MAX_BLOCK_LENGTH)
+ block_length=MI_MAX_BLOCK_LENGTH;
+ if (_mi_write_part_record(info,0L,block_length,
+ sort_info->filepos+block_length,
+ &from,&reclength,&flag))
+ {
+ mi_check_print_error(param,"%d when writing to datafile",my_errno);
+ DBUG_RETURN(1);
+ }
+ sort_info->filepos+=block_length;
+ info->s->state.split++;
+ } while (reclength);
/* sort_info->param->glob_crc+=info->checksum; */
break;
case COMPRESSED_RECORD:
@@ -2524,6 +2605,7 @@ int sort_write_record(SORT_INFO *sort_info)
}
/* sort_info->param->glob_crc+=info->checksum; */
sort_info->filepos+=reclength+length;
+ info->s->state.split++;
break;
}
}
@@ -2579,7 +2661,7 @@ static int sort_key_write(SORT_INFO *sort_info, const void *a)
sort_info->key_block->
lastkey),
llbuff2));
- param->retry_without_quick=1;
+ param->testflag|=T_RETRY_WITHOUT_QUICK;
if (sort_info->param->testflag & T_VERBOSE)
_mi_print_key(stdout,sort_info->keyseg,(uchar*) a, USE_WHOLE_KEY);
return (sort_delete_record(param));
@@ -2702,10 +2784,10 @@ static int sort_delete_record(MI_CHECK *param)
SORT_INFO *sort_info= &param->sort_info;
DBUG_ENTER("sort_delete_record");
- if (param->opt_rep_quick == 1)
+ if (!(param->testflag & T_FORCE_UNIQUENESS))
{
mi_check_print_error(param,
- "Quick-recover aborted; Run recovery without switch 'q' or with switch -qq");
+ "Quick-recover aborted; Run recovery without switch -q or with switch -qq");
DBUG_RETURN(1);
}
info=sort_info->info;
@@ -2752,7 +2834,7 @@ static int sort_delete_record(MI_CHECK *param)
/* Fix all pending blocks and flush everything to disk */
-static int flush_pending_blocks(MI_CHECK *param)
+int flush_pending_blocks(MI_CHECK *param)
{
uint nod_flag,length;
my_off_t filepos,key_file_length;
@@ -2846,7 +2928,6 @@ int recreate_table(MI_CHECK *param, MI_INFO **org_info, char *filename)
MI_STATUS_INFO status_info;
uint unpack,key_parts;
ha_rows max_records;
- char name[FN_REFLEN];
ulonglong file_length,tmp_length;
MI_CREATE_INFO create_info;
@@ -2955,8 +3036,9 @@ int recreate_table(MI_CHECK *param, MI_INFO **org_info, char *filename)
create_info.language = (param->language ? param->language :
share.state.header.language);
- if (mi_create(fn_format(name,filename,"",MI_NAME_IEXT,
- 4+ (param->opt_follow_links ? 16 : 0)),
+ /* We don't have to handle symlinks here because we are using
+ HA_DONT_TOUCH_DATA */
+ if (mi_create(filename,
share.base.keys - share.state.header.uniques,
keyinfo, share.base.fields, recdef,
share.state.header.uniques, uniquedef,
@@ -2966,7 +3048,7 @@ int recreate_table(MI_CHECK *param, MI_INFO **org_info, char *filename)
mi_check_print_error(param,"Got error %d when trying to recreate indexfile",my_errno);
goto end;
}
- *org_info=mi_open(name,O_RDWR,
+ *org_info=mi_open(filename,O_RDWR,
(param->testflag & T_WAIT_FOREVER) ? HA_OPEN_WAIT_IF_LOCKED :
(param->testflag & T_DESCRIPT) ? HA_OPEN_IGNORE_IF_LOCKED :
HA_OPEN_ABORT_IF_LOCKED);
@@ -3219,15 +3301,7 @@ my_bool mi_test_if_sort_rep(MI_INFO *info, ha_rows rows,
return FALSE; /* Can't use sort */
for (i=0 ; i < share->base.keys ; i++,key++)
{
-/* It's to disable repair_by_sort for ft-keys.
- Another solution would be to make ft-keys just too_big_key_for_sort,
- but then they won't be disabled by dectivate_non_unique_index
- and so they will be created at the first stage. As ft-key creation
- is very time-consuming process, it's better to leave it to repair stage
- but this repair shouldn't be repair_by_sort (serg)
- */
- if ((!force && mi_too_big_key_for_sort(key,rows)) ||
- (key->flag & HA_FULLTEXT))
+ if (!force && mi_too_big_key_for_sort(key,rows))
return FALSE;
}
return TRUE;
diff --git a/myisam/mi_checksum.c b/myisam/mi_checksum.c
index 9dabe55e239..a760b03a032 100644
--- a/myisam/mi_checksum.c
+++ b/myisam/mi_checksum.c
@@ -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 */
diff --git a/myisam/mi_close.c b/myisam/mi_close.c
index f30119144bc..bd8b9aff727 100644
--- a/myisam/mi_close.c
+++ b/myisam/mi_close.c
@@ -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 */
diff --git a/myisam/mi_create.c b/myisam/mi_create.c
index 7abf274d621..91c2c64c3cf 100644
--- a/myisam/mi_create.c
+++ b/myisam/mi_create.c
@@ -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 */
@@ -38,12 +38,13 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
register uint i,j;
File dfile,file;
int errpos,save_errno;
+ myf create_flag;
uint fields,length,max_key_length,packed,pointer,
key_length,info_length,key_segs,options,min_key_length_skipp,
base_pos,varchar_count,long_varchar_count,varchar_length,
max_key_block_length,unique_key_parts,offset;
ulong reclength, real_reclength,min_pack_length;
- char buff[FN_REFLEN];
+ char filename[FN_REFLEN],linkname[FN_REFLEN], *linkname_ptr;
ulong pack_reclength;
ulonglong tot_length,max_rows;
enum en_fieldtype type;
@@ -118,8 +119,8 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
pack_reclength+=(1 << ((rec->length-mi_portable_sizeof_char_ptr)*8)); /* Max blob length */
}
}
- else if (type == FIELD_SKIPP_PRESPACE ||
- type == FIELD_SKIPP_ENDSPACE)
+ else if (type == FIELD_SKIP_PRESPACE ||
+ type == FIELD_SKIP_ENDSPACE)
{
if (pack_reclength != INT_MAX32)
pack_reclength+= rec->length > 255 ? 2 : 1;
@@ -137,7 +138,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
pack_reclength+=2;
}
}
- else if (type != FIELD_SKIPP_ZERO)
+ else if (type != FIELD_SKIP_ZERO)
{
min_pack_length+=rec->length;
packed--; /* Not a pack record type */
@@ -151,7 +152,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
while (rec != recinfo)
{
rec--;
- if (rec->type == (int) FIELD_SKIPP_ZERO && rec->length == 1)
+ if (rec->type == (int) FIELD_SKIP_ZERO && rec->length == 1)
{
rec->type=(int) FIELD_NORMAL;
packed--;
@@ -163,6 +164,9 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
if (packed || (flags & HA_PACK_RECORD))
options|=HA_OPTION_PACK_RECORD; /* Must use packed records */
+ /* 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
@@ -223,8 +227,8 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
share.state.key_del=key_del;
if (uniques)
{
- max_key_block_length= MI_KEY_BLOCK_LENGTH;
- max_key_length= MI_UNIQUE_HASH_LENGTH;
+ max_key_block_length= myisam_block_size;
+ max_key_length= MI_UNIQUE_HASH_LENGTH;
}
for (i=0, keydef=keydefs ; i < keys ; i++ , keydef++)
@@ -366,7 +370,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
share.state.rec_per_key_part[key_segs-1]=1L;
length+=key_length;
keydef->block_length= MI_BLOCK_SIZE(length,pointer,MI_MAX_KEYPTR_SIZE);
- if (keydef->block_length/MI_KEY_BLOCK_LENGTH > MI_MAX_KEY_BLOCK_SIZE)
+ if (keydef->block_length > MI_MAX_KEY_BLOCK_LENGTH)
{
my_errno=HA_WRONG_CREATE_OPTION;
goto err;
@@ -382,7 +386,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
(length*2)))*
(ulong) keydef->block_length;
}
- for (i=max_key_block_length/MI_KEY_BLOCK_LENGTH ; i-- ; )
+ for (i=max_key_block_length/MI_MIN_KEY_BLOCK_LENGTH ; i-- ; )
key_del[i]=HA_OFFSET_ERROR;
unique_key_parts=0;
@@ -397,7 +401,8 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
key_segs+=uniques; /* Each unique has 1 key seg */
base_pos=(MI_STATE_INFO_SIZE + keys * MI_STATE_KEY_SIZE +
- max_key_block_length/MI_KEY_BLOCK_LENGTH*MI_STATE_KEYBLOCK_SIZE+
+ max_key_block_length/MI_MIN_KEY_BLOCK_LENGTH*
+ MI_STATE_KEYBLOCK_SIZE+
key_segs*MI_STATE_KEYSEG_SIZE);
info_length=base_pos+(uint) (MI_BASE_INFO_SIZE+
keys * MI_KEYDEF_SIZE+
@@ -416,7 +421,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
mi_int2store(share.state.header.base_pos,base_pos);
share.state.header.language= (ci->language ?
ci->language : MY_CHARSET_CURRENT);
- share.state.header.max_block_size=max_key_block_length/MI_KEY_BLOCK_LENGTH;
+ share.state.header.max_block_size=max_key_block_length/MI_MIN_KEY_BLOCK_LENGTH;
share.state.dellink = HA_OFFSET_ERROR;
share.state.process= (ulong) getpid();
@@ -429,7 +434,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
share.base.rec_reflength=pointer;
share.base.key_reflength=
mi_get_pointer_length((tot_length + max_key_block_length * keys *
- MI_INDEX_BLOCK_MARGIN) / MI_KEY_BLOCK_LENGTH,
+ MI_INDEX_BLOCK_MARGIN) / MI_MIN_KEY_BLOCK_LENGTH,
3);
share.base.keys= share.state.header.keys = keys;
share.state.header.uniques= uniques;
@@ -444,7 +449,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
share.base.records=ci->max_rows;
share.base.reloc= ci->reloc_rows;
share.base.reclength=real_reclength;
- share.base.pack_reclength=reclength+ test(options & HA_OPTION_CHECKSUM);;
+ share.base.pack_reclength=reclength+ test(options & HA_OPTION_CHECKSUM);
share.base.max_pack_length=pack_reclength;
share.base.min_pack_length=min_pack_length;
share.base.pack_bits=packed;
@@ -468,17 +473,40 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
if (! (flags & HA_DONT_TOUCH_DATA))
share.state.create_time= (long) time((time_t*) 0);
- if ((file = my_create(fn_format(buff,name,"",MI_NAME_IEXT,4),0,
- O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
+ if (ci->index_file_name)
+ {
+ fn_format(filename, ci->index_file_name,"",MI_NAME_IEXT,4);
+ fn_format(linkname,name, "",MI_NAME_IEXT,4);
+ linkname_ptr=linkname;
+ /*
+ Don't create the table if the link or file exists to ensure that one
+ doesn't accidently destroy another table.
+ */
+ create_flag=0;
+ }
+ else
+ {
+ fn_format(filename,name,"",MI_NAME_IEXT,(4+ (flags & HA_DONT_TOUCH_DATA) ?
+ 32 : 0));
+ linkname_ptr=0;
+ /* Replace the current file */
+ create_flag=MY_DELETE_OLD;
+ }
+
+ if ((file= my_create_with_symlink(linkname_ptr,
+ filename,
+ 0, O_RDWR | O_TRUNC,
+ MYF(MY_WME | create_flag))) < 0)
goto err;
errpos=1;
- VOID(fn_format(buff,name,"",MI_NAME_DEXT,2+4));
+
if (!(flags & HA_DONT_TOUCH_DATA))
{
#ifdef USE_RAID
if (share.base.raid_type)
{
- if ((dfile=my_raid_create(buff,0,O_RDWR | O_TRUNC,
+ (void) fn_format(filename,name,"",MI_NAME_DEXT,2+4);
+ if ((dfile=my_raid_create(filename,0,O_RDWR | O_TRUNC,
share.base.raid_type,
share.base.raid_chunks,
share.base.raid_chunksize,
@@ -487,9 +515,26 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
}
else
#endif
- if ((dfile = my_create(buff,0,O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
- goto err;
-
+ {
+ if (ci->data_file_name)
+ {
+ fn_format(filename, ci->data_file_name,"",MI_NAME_DEXT,4);
+ fn_format(linkname, name, "",MI_NAME_DEXT,4);
+ linkname_ptr=linkname;
+ create_flag=0;
+ }
+ else
+ {
+ fn_format(filename,name,"",MI_NAME_DEXT,4);
+ linkname_ptr=0;
+ create_flag=MY_DELETE_OLD;
+ }
+ if ((dfile=
+ my_create_with_symlink(linkname_ptr, filename,
+ 0,O_RDWR | O_TRUNC,
+ MYF(MY_WME | create_flag))) < 0)
+ goto err;
+ }
errpos=3;
}
@@ -508,14 +553,14 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
/* Write key and keyseg definitions */
for (i=0 ; i < share.base.keys - uniques; i++)
{
- uint ft_segs=(keydefs[i].flag & HA_FULLTEXT) ? FT_SEGS : 0; /* SerG */
+ uint ft_segs=(keydefs[i].flag & HA_FULLTEXT) ? FT_SEGS : 0;
if (mi_keydef_write(file, &keydefs[i]))
goto err;
for (j=0 ; j < keydefs[i].keysegs-ft_segs ; j++)
if (mi_keyseg_write(file, &keydefs[i].seg[j]))
goto err;
- for (j=0 ; j < ft_segs ; j++) /* SerG */
+ for (j=0 ; j < ft_segs ; j++)
{
MI_KEYSEG seg=ft_keysegs[j];
seg.language= keydefs[i].seg[0].language;
@@ -531,7 +576,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
{
tmp_keydef.keysegs=1;
tmp_keydef.flag= HA_UNIQUE_CHECK;
- tmp_keydef.block_length= MI_KEY_BLOCK_LENGTH;
+ tmp_keydef.block_length= myisam_block_size;
tmp_keydef.keylength= MI_UNIQUE_HASH_LENGTH + pointer;
tmp_keydef.minlength=tmp_keydef.maxlength=tmp_keydef.keylength;
tmp_keyseg.type= MI_UNIQUE_HASH_TYPE;
@@ -596,20 +641,16 @@ err:
VOID(my_close(dfile,MYF(0)));
/* fall through */
case 2:
- if (! (flags & HA_DONT_TOUCH_DATA))
- {
/* QQ: Tõnu should add a call to my_raid_delete() here */
- VOID(fn_format(buff,name,"",MI_NAME_DEXT,2+4));
- my_delete(buff,MYF(0));
- }
+ if (! (flags & HA_DONT_TOUCH_DATA))
+ my_delete_with_symlink(fn_format(filename,name,"",MI_NAME_DEXT,2+4),
+ MYF(0));
/* fall through */
case 1:
VOID(my_close(file,MYF(0)));
if (! (flags & HA_DONT_TOUCH_DATA))
- {
- VOID(fn_format(buff,name,"",MI_NAME_IEXT,2+4));
- my_delete(buff,MYF(0));
- }
+ my_delete_with_symlink(fn_format(filename,name,"",MI_NAME_IEXT,2+4),
+ MYF(0));
}
my_free((char*) rec_per_key_part, MYF(0));
DBUG_RETURN(my_errno=save_errno); /* return the fatal errno */
diff --git a/myisam/mi_dbug.c b/myisam/mi_dbug.c
index eda1aafecc8..482287938c0 100644
--- a/myisam/mi_dbug.c
+++ b/myisam/mi_dbug.c
@@ -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 */
@@ -162,7 +162,7 @@ my_bool check_table_is_closed(const char *name, const char *where)
{
MI_INFO *info=(MI_INFO*) pos->data;
MYISAM_SHARE *share=info->s;
- if (!strcmp(share->filename,filename))
+ if (!strcmp(share->unique_file_name,filename))
{
if (share->last_version)
{
diff --git a/myisam/mi_delete.c b/myisam/mi_delete.c
index 445e745b07d..6f94e3c4256 100644
--- a/myisam/mi_delete.c
+++ b/myisam/mi_delete.c
@@ -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 */
@@ -97,6 +97,12 @@ int mi_delete(MI_INFO *info,const byte *record)
myisam_log_command(MI_LOG_DELETE,info,(byte*) lastpos,sizeof(lastpos),0);
VOID(_mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
allow_break(); /* Allow SIGHUP & SIGINT */
+ if (info->invalidator != 0)
+ {
+ DBUG_PRINT("info", ("invalidator... '%s' (delete)", info->filename));
+ (*info->invalidator)(info->filename);
+ info->invalidator=0;
+ }
DBUG_RETURN(0);
err:
@@ -196,7 +202,8 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
DBUG_ENTER("d_search");
DBUG_DUMP("page",(byte*) anc_buff,mi_getint(anc_buff));
- flag=(*keyinfo->bin_search)(info,keyinfo,anc_buff,key,key_length,SEARCH_SAME,
+ flag=(*keyinfo->bin_search)(info,keyinfo,anc_buff,key, USE_WHOLE_KEY,
+ SEARCH_SAME,
&keypos, lastkey, &last_key);
if (flag == MI_FOUND_WRONG_KEY)
{
diff --git a/myisam/mi_delete_all.c b/myisam/mi_delete_all.c
index c3ed9455e12..82cf9e7a406 100644
--- a/myisam/mi_delete_all.c
+++ b/myisam/mi_delete_all.c
@@ -1,21 +1,21 @@
/* 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 */
/* Remove all rows from a MyISAM table */
-/* This only clears the status information; The files are not truncated */
+/* This only clears the status information and truncates the data file */
#include "myisamdef.h"
@@ -43,13 +43,15 @@ int mi_delete_all_rows(MI_INFO *info)
info->state->empty=info->state->key_empty=0;
state->checksum=0;
- for (i=share->base.max_key_block_length/MI_KEY_BLOCK_LENGTH ; i-- ; )
+ for (i=share->base.max_key_block_length/MI_MIN_KEY_BLOCK_LENGTH ; i-- ; )
state->key_del[i]= HA_OFFSET_ERROR;
for (i=0 ; i < share->base.keys ; i++)
state->key_root[i]= HA_OFFSET_ERROR;
myisam_log_command(MI_LOG_DELETE_ALL,info,(byte*) 0,0,0);
VOID(_mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
+ if (my_chsize(info->dfile, 0, MYF(MY_WME)))
+ goto err;
allow_break(); /* Allow SIGHUP & SIGINT */
DBUG_RETURN(0);
@@ -62,4 +64,3 @@ err:
DBUG_RETURN(my_errno=save_errno);
}
} /* mi_delete */
-
diff --git a/myisam/mi_delete_table.c b/myisam/mi_delete_table.c
index 995106160ef..6d842d7e6a4 100644
--- a/myisam/mi_delete_table.c
+++ b/myisam/mi_delete_table.c
@@ -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 */
@@ -50,12 +50,12 @@ int mi_delete_table(const char *name)
#endif /* USE_RAID */
fn_format(from,name,"",MI_NAME_IEXT,4);
- if (my_delete(from, MYF(MY_WME)))
+ if (my_delete_with_symlink(from, MYF(MY_WME)))
DBUG_RETURN(my_errno);
fn_format(from,name,"",MI_NAME_DEXT,4);
#ifdef USE_RAID
if (raid_type)
DBUG_RETURN(my_raid_delete(from, raid_chunks, MYF(MY_WME)) ? my_errno : 0);
#endif
- DBUG_RETURN(my_delete(from, MYF(MY_WME)) ? my_errno : 0);
+ DBUG_RETURN(my_delete_with_symlink(from, MYF(MY_WME)) ? my_errno : 0);
}
diff --git a/myisam/mi_dynrec.c b/myisam/mi_dynrec.c
index c9fe493744d..b5f5ca7fd33 100644
--- a/myisam/mi_dynrec.c
+++ b/myisam/mi_dynrec.c
@@ -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 */
@@ -64,11 +64,13 @@ int _mi_write_blob_record(MI_INFO *info, const byte *record)
MI_DYN_DELETE_BLOCK_HEADER+1;
reclength=info->s->base.pack_reclength+
_my_calc_total_blob_length(info,record)+ extra;
+#ifdef NOT_USED /* We now support big rows */
if (reclength > MI_DYN_MAX_ROW_LENGTH)
{
my_errno=HA_ERR_TO_BIG_ROW;
return -1;
}
+#endif
if (!(rec_buff=(byte*) my_alloca(reclength)))
{
my_errno=ENOMEM;
@@ -93,11 +95,13 @@ int _mi_update_blob_record(MI_INFO *info, my_off_t pos, const byte *record)
MI_DYN_DELETE_BLOCK_HEADER;
reclength=info->s->base.pack_reclength+
_my_calc_total_blob_length(info,record)+ extra;
+#ifdef NOT_USED /* We now support big rows */
if (reclength > MI_DYN_MAX_ROW_LENGTH)
{
my_errno=HA_ERR_TO_BIG_ROW;
return -1;
}
+#endif
if (!(rec_buff=(byte*) my_alloca(reclength)))
{
my_errno=ENOMEM;
@@ -130,14 +134,14 @@ static int write_dynamic_record(MI_INFO *info, const byte *record,
DBUG_ENTER("write_dynamic_record");
flag=0;
- while (reclength)
+ do
{
if (_mi_find_writepos(info,reclength,&filepos,&length))
goto err;
if (_mi_write_part_record(info,filepos,length,info->s->state.dellink,
(byte**) &record,&reclength,&flag))
goto err;
- }
+ } while (reclength);
DBUG_RETURN(0);
err:
@@ -190,6 +194,8 @@ static int _mi_find_writepos(MI_INFO *info,
my_errno=HA_ERR_RECORD_FILE_FULL;
DBUG_RETURN(-1);
}
+ if (*length > MI_MAX_BLOCK_LENGTH)
+ *length=MI_MAX_BLOCK_LENGTH;
info->state->data_file_length+= *length;
info->s->state.split++;
info->update|=HA_STATE_WRITE_AT_END;
@@ -370,19 +376,30 @@ int _mi_write_part_record(MI_INFO *info,
info->s->state.dellink : info->state->data_file_length;
if (*flag == 0) /* First block */
{
- head_length=5+8+long_block*2;
- temp[0]=5+(uchar) long_block;
- if (long_block)
+ if (*reclength > MI_MAX_BLOCK_LENGTH)
{
- mi_int3store(temp+1,*reclength);
- mi_int3store(temp+4,length-head_length);
- mi_sizestore((byte*) temp+7,next_filepos);
+ head_length= 16;
+ temp[0]=13;
+ mi_int4store(temp+1,*reclength);
+ mi_int3store(temp+5,length-head_length);
+ mi_sizestore((byte*) temp+8,next_filepos);
}
else
{
- mi_int2store(temp+1,*reclength);
- mi_int2store(temp+3,length-head_length);
- mi_sizestore((byte*) temp+5,next_filepos);
+ head_length=5+8+long_block*2;
+ temp[0]=5+(uchar) long_block;
+ if (long_block)
+ {
+ mi_int3store(temp+1,*reclength);
+ mi_int3store(temp+4,length-head_length);
+ mi_sizestore((byte*) temp+7,next_filepos);
+ }
+ else
+ {
+ mi_int2store(temp+1,*reclength);
+ mi_int2store(temp+3,length-head_length);
+ mi_sizestore((byte*) temp+5,next_filepos);
+ }
}
}
else
@@ -629,7 +646,7 @@ uint _mi_rec_pack(MI_INFO *info, register byte *to, register const byte *from)
}
blob++;
}
- else if (type == FIELD_SKIPP_ZERO)
+ else if (type == FIELD_SKIP_ZERO)
{
if (memcmp((byte*) from,zero_string,length) == 0)
flag|=bit;
@@ -638,11 +655,11 @@ uint _mi_rec_pack(MI_INFO *info, register byte *to, register const byte *from)
memcpy((byte*) to,from,(size_t) length); to+=length;
}
}
- else if (type == FIELD_SKIPP_ENDSPACE ||
- type == FIELD_SKIPP_PRESPACE)
+ else if (type == FIELD_SKIP_ENDSPACE ||
+ type == FIELD_SKIP_PRESPACE)
{
pos= (byte*) from; end= (byte*) from + length;
- if (type == FIELD_SKIPP_ENDSPACE)
+ if (type == FIELD_SKIP_ENDSPACE)
{ /* Pack trailing spaces */
while (end > from && *(end-1) == ' ')
end--;
@@ -737,7 +754,7 @@ my_bool _mi_rec_check(MI_INFO *info,const char *record)
if (blob_length)
to+=length - mi_portable_sizeof_char_ptr+ blob_length;
}
- else if (type == FIELD_SKIPP_ZERO)
+ else if (type == FIELD_SKIP_ZERO)
{
if (memcmp((byte*) record,zero_string,length) == 0)
{
@@ -747,11 +764,11 @@ my_bool _mi_rec_check(MI_INFO *info,const char *record)
else
to+=length;
}
- else if (type == FIELD_SKIPP_ENDSPACE ||
- type == FIELD_SKIPP_PRESPACE)
+ else if (type == FIELD_SKIP_ENDSPACE ||
+ type == FIELD_SKIP_PRESPACE)
{
pos= (byte*) record; end= (byte*) record + length;
- if (type == FIELD_SKIPP_ENDSPACE)
+ if (type == FIELD_SKIP_ENDSPACE)
{ /* Pack trailing spaces */
while (end > record && *(end-1) == ' ')
end--;
@@ -863,10 +880,10 @@ ulong _mi_rec_unpack(register MI_INFO *info, register byte *to, byte *from,
}
if (flag & bit)
{
- if (type == FIELD_BLOB || type == FIELD_SKIPP_ZERO)
+ if (type == FIELD_BLOB || type == FIELD_SKIP_ZERO)
bzero((byte*) to,rec_length);
- else if (type == FIELD_SKIPP_ENDSPACE ||
- type == FIELD_SKIPP_PRESPACE)
+ else if (type == FIELD_SKIP_ENDSPACE ||
+ type == FIELD_SKIP_PRESPACE)
{
if (rec->length > 255 && *from & 128)
{
@@ -884,7 +901,7 @@ ulong _mi_rec_unpack(register MI_INFO *info, register byte *to, byte *from,
if (length >= rec_length ||
min_pack_length + length > (uint) (from_end - from))
goto err;
- if (type == FIELD_SKIPP_ENDSPACE)
+ if (type == FIELD_SKIP_ENDSPACE)
{
memcpy(to,(byte*) from,(size_t) length);
bfill((byte*) to+length,rec_length-length,' ');
@@ -911,7 +928,7 @@ ulong _mi_rec_unpack(register MI_INFO *info, register byte *to, byte *from,
}
else
{
- if (type == FIELD_SKIPP_ENDSPACE || type == FIELD_SKIPP_PRESPACE)
+ if (type == FIELD_SKIP_ENDSPACE || type == FIELD_SKIP_PRESPACE)
min_pack_length--;
if (min_pack_length + rec_length > (uint) (from_end - from))
goto err;
@@ -1059,11 +1076,11 @@ int _mi_read_dynamic_record(MI_INFO *info, my_off_t filepos, byte *buf)
} while (left_length);
info->update|= HA_STATE_AKTIV; /* We have a aktive record */
- VOID(_mi_writeinfo(info,0));
+ fast_mi_writeinfo(info);
DBUG_RETURN(_mi_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
MY_FILE_ERROR ? 0 : -1);
}
- VOID(_mi_writeinfo(info,0));
+ fast_mi_writeinfo(info);
DBUG_RETURN(-1); /* Wrong data to read */
panic:
@@ -1393,8 +1410,7 @@ int _mi_read_rnd_dynamic_record(MI_INFO *info, byte *buf,
} while (left_len);
info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
- if (share->r_locks == 0 && share->w_locks == 0)
- VOID(_mi_writeinfo(info,0));
+ fast_mi_writeinfo(info);
if (_mi_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
MY_FILE_ERROR)
DBUG_RETURN(0);
@@ -1429,15 +1445,15 @@ uint _mi_get_block_info(MI_BLOCK_INFO *info, File file, my_off_t filepos)
DBUG_DUMP("header",(byte*) header,MI_BLOCK_INFO_HEADER_LENGTH);
if (info->second_read)
{
- if (info->header[0] <= 6)
+ if (info->header[0] <= 6 || info->header[0] == 13)
return_val=BLOCK_SYNC_ERROR;
}
else
{
- if (info->header[0] > 6)
+ if (info->header[0] > 6 && info->header[0] != 13)
return_val=BLOCK_SYNC_ERROR;
}
- info->next_filepos= HA_OFFSET_ERROR; /* Dummy ifall no next block */
+ info->next_filepos= HA_OFFSET_ERROR; /* Dummy if no next block */
switch (info->header[0]) {
case 0:
@@ -1471,6 +1487,14 @@ uint _mi_get_block_info(MI_BLOCK_INFO *info, File file, my_off_t filepos)
info->filepos=filepos+4;
return return_val | BLOCK_FIRST | BLOCK_LAST;
+ case 13:
+ info->rec_len=mi_uint4korr(header+1);
+ info->block_len=info->data_len=mi_uint3korr(header+5);
+ info->next_filepos=mi_sizekorr(header+8);
+ info->second_read=1;
+ info->filepos=filepos+16;
+ return return_val | BLOCK_FIRST;
+
case 3:
info->rec_len=info->data_len=mi_uint2korr(header+1);
info->block_len=info->rec_len+ (uint) header[3];
diff --git a/myisam/mi_extra.c b/myisam/mi_extra.c
index cf075512ac4..21cd9919ada 100644
--- a/myisam/mi_extra.c
+++ b/myisam/mi_extra.c
@@ -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 */
@@ -34,6 +34,7 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function)
int error=0;
MYISAM_SHARE *share=info->s;
DBUG_ENTER("mi_extra");
+ DBUG_PRINT("enter",("function: %d",(int) function));
switch (function) {
case HA_EXTRA_RESET:
@@ -50,7 +51,7 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function)
if (info->opt_flag & MEMMAP_USED)
madvise(share->file_map,share->state.state.data_file_length,MADV_RANDOM);
#endif
- info->opt_flag&= ~(KEY_READ_USED | REMEMBER_OLD_POS);
+ info->opt_flag&= ~(KEY_READ_USED | REMEMBER_OLD_POS);
info->quick_mode=0;
/* Fall through */
@@ -219,9 +220,17 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function)
}
if (share->state.key_map)
{
- share->state.key_map=0;
- info->state->key_file_length=share->state.state.key_file_length=
- share->base.keystart;
+ MI_KEYDEF *key=share->keyinfo;
+ uint i;
+ for (i=0 ; i < share->base.keys ; i++,key++)
+ {
+ if (!(key->flag & HA_NOSAME) && info->s->base.auto_key != i+1)
+ {
+ share->state.key_map&= ~ ((ulonglong) 1 << i);
+ info->update|= HA_STATE_CHANGED;
+ }
+ }
+
if (!share->changed)
{
share->state.changed|= STATE_CHANGED | STATE_NOT_ANALYZED;
@@ -237,12 +246,15 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function)
}
break;
case HA_EXTRA_FORCE_REOPEN:
+ case HA_EXTRA_PREPARE_FOR_DELETE:
pthread_mutex_lock(&THR_LOCK_myisam);
share->last_version= 0L; /* Impossible version */
#ifdef __WIN__
/* Close the isam and data files as Win32 can't drop an open table */
pthread_mutex_lock(&share->intern_lock);
- if (flush_key_blocks(share->kfile,FLUSH_RELEASE))
+ if (flush_key_blocks(share->kfile,
+ (function == HA_EXTRA_FORCE_REOPEN ?
+ FLUSH_RELEASE : FLUSH_IGNORE_CHANGED)))
{
error=my_errno;
share->changed=1;
@@ -328,6 +340,24 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function)
case HA_EXTRA_QUICK:
info->quick_mode=1;
break;
+ case HA_EXTRA_BULK_INSERT_BEGIN:
+ error=_mi_init_bulk_insert(info);
+ break;
+ case HA_EXTRA_BULK_INSERT_END:
+ if (info->bulk_insert)
+ {
+ uint i;
+ for (i=0 ; i < share->base.keys ; i++)
+ {
+ if (is_tree_inited(& info->bulk_insert[i]))
+ {
+ delete_tree(& info->bulk_insert[i]);
+ }
+ }
+ my_free((void *)info->bulk_insert, MYF(0));
+ info->bulk_insert=0;
+ }
+ break;
case HA_EXTRA_NO_ROWS:
if (!share->state.header.uniques)
info->opt_flag|= OPT_NO_ROWS;
diff --git a/myisam/mi_info.c b/myisam/mi_info.c
index 6e7abfc0914..0be3cc44d80 100644
--- a/myisam/mi_info.c
+++ b/myisam/mi_info.c
@@ -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 */
@@ -45,7 +45,7 @@ int mi_status(MI_INFO *info, register MI_ISAMINFO *x, uint flag)
{
pthread_mutex_lock(&share->intern_lock);
VOID(_mi_readinfo(info,F_RDLCK,0));
- VOID(_mi_writeinfo(info,0));
+ fast_mi_writeinfo(info);
pthread_mutex_unlock(&share->intern_lock);
}
if (flag & HA_STATUS_VARIABLE)
@@ -87,6 +87,8 @@ int mi_status(MI_INFO *info, register MI_ISAMINFO *x, uint flag)
x->raid_chunks= share->base.raid_chunks;
x->raid_chunksize= share->base.raid_chunksize;
x->key_map = share->state.key_map;
+ x->data_file_name = share->data_file_name;
+ x->index_file_name = share->index_file_name;
}
if ((flag & HA_STATUS_TIME) && !my_fstat(info->dfile,&state,MYF(0)))
x->update_time=state.st_mtime;
diff --git a/myisam/mi_key.c b/myisam/mi_key.c
index 9f4e2cb1524..6ec8668ab61 100644
--- a/myisam/mi_key.c
+++ b/myisam/mi_key.c
@@ -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 */
@@ -18,6 +18,9 @@
#include "myisamdef.h"
#include "m_ctype.h"
+#ifdef HAVE_IEEEFP_H
+#include <ieeefp.h>
+#endif
#define CHECK_KEYS
@@ -88,25 +91,28 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key,
}
else if (keyseg->flag & HA_SWAP_KEY)
{ /* Numerical column */
-#ifdef NAN_TEST
- float float_nr;
- double dbl_nr;
+#ifdef HAVE_ISNAN
if (type == HA_KEYTYPE_FLOAT)
{
- float_nr=float4get(pos);
- if (float_nr == (float) FLT_MAX)
+ float nr;
+ float4get(nr,pos);
+ if (isnan(nr))
{
- float_nr= (float) FLT_MAX;
- pos= (byte*) &float_nr;
+ /* Replace NAN with zero */
+ bzero(key,length);
+ key+=length;
+ continue;
}
}
else if (type == HA_KEYTYPE_DOUBLE)
{
- dbl_nr=float8get(key);
- if (dbl_nr == DBL_MAX)
+ double nr;
+ float8get(nr,pos);
+ if (isnan(nr))
{
- dbl_nr=DBL_MAX;
- pos=(byte*) &dbl_nr;
+ bzero(key,length);
+ key+=length;
+ continue;
}
}
#endif
@@ -346,7 +352,7 @@ err:
int _mi_read_key_record(MI_INFO *info, my_off_t filepos, byte *buf)
{
- VOID(_mi_writeinfo(info,0));
+ fast_mi_writeinfo(info);
if (filepos != HA_OFFSET_ERROR)
{
if (info->lastinx >= 0)
diff --git a/myisam/mi_locking.c b/myisam/mi_locking.c
index de5f0d0c2cf..ea4966b05c5 100644
--- a/myisam/mi_locking.c
+++ b/myisam/mi_locking.c
@@ -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 */
@@ -43,13 +43,13 @@ int mi_lock_database(MI_INFO *info, int lock_type)
pthread_mutex_lock(&share->intern_lock);
if (share->kfile >= 0) /* May only be false on windows */
{
- switch (lock_type)
- {
+ switch (lock_type) {
case F_UNLCK:
if (info->lock_type == F_RDLCK)
count= --share->r_locks;
else
count= --share->w_locks;
+ --share->tot_locks;
if (info->lock_type == F_WRLCK && !share->w_locks &&
!share->delay_key_write && flush_key_blocks(share->kfile,FLUSH_KEEP))
{
@@ -153,6 +153,7 @@ int mi_lock_database(MI_INFO *info, int lock_type)
}
VOID(_mi_test_if_changed(info));
share->r_locks++;
+ share->tot_locks++;
info->lock_type=lock_type;
break;
case F_WRLCK:
@@ -199,7 +200,9 @@ int mi_lock_database(MI_INFO *info, int lock_type)
}
VOID(_mi_test_if_changed(info));
info->lock_type=lock_type;
+ info->invalidator=info->s->invalidator;
share->w_locks++;
+ share->tot_locks++;
break;
default:
break; /* Impossible */
@@ -295,13 +298,12 @@ my_bool mi_check_status(void* param)
int _mi_readinfo(register MI_INFO *info, int lock_type, int check_keybuffer)
{
- MYISAM_SHARE *share;
DBUG_ENTER("_mi_readinfo");
- share=info->s;
if (info->lock_type == F_UNLCK)
{
- if (!share->r_locks && !share->w_locks)
+ MYISAM_SHARE *share=info->s;
+ if (!share->tot_locks)
{
if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,
info->lock_wait | MY_SEEK_NOT_DONE))
@@ -317,6 +319,7 @@ int _mi_readinfo(register MI_INFO *info, int lock_type, int check_keybuffer)
}
if (check_keybuffer)
VOID(_mi_test_if_changed(info));
+ info->invalidator=info->s->invalidator;
}
else if (lock_type == F_WRLCK && info->lock_type == F_RDLCK)
{
@@ -338,7 +341,7 @@ int _mi_writeinfo(register MI_INFO *info, uint operation)
DBUG_ENTER("_mi_writeinfo");
error=0;
- if (share->r_locks == 0 && share->w_locks == 0)
+ if (share->tot_locks == 0)
{
olderror=my_errno; /* Remember last error */
if (operation)
@@ -411,11 +414,14 @@ int _mi_mark_file_changed(MI_INFO *info)
share->global_changed=1;
share->state.open_count++;
}
- mi_int2store(buff,share->state.open_count);
- buff[2]=1; /* Mark that it's changed */
- return (my_pwrite(share->kfile,buff,sizeof(buff),
- sizeof(share->state.header),
- MYF(MY_NABP)));
+ if (!share->temporary)
+ {
+ mi_int2store(buff,share->state.open_count);
+ buff[2]=1; /* Mark that it's changed */
+ return (my_pwrite(share->kfile,buff,sizeof(buff),
+ sizeof(share->state.header),
+ MYF(MY_NABP)));
+ }
}
return 0;
}
diff --git a/myisam/mi_log.c b/myisam/mi_log.c
index 5c64c130212..1dcfd5250d2 100644
--- a/myisam/mi_log.c
+++ b/myisam/mi_log.c
@@ -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 */
diff --git a/myisam/mi_open.c b/myisam/mi_open.c
index 617b1cd8d90..bcf8369b439 100644
--- a/myisam/mi_open.c
+++ b/myisam/mi_open.c
@@ -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 */
@@ -48,7 +48,7 @@ static MI_INFO *test_if_reopen(char *filename)
{
MI_INFO *info=(MI_INFO*) pos->data;
MYISAM_SHARE *share=info->s;
- if (!strcmp(share->filename,filename) && share->last_version)
+ if (!strcmp(share->unique_file_name,filename) && share->last_version)
return info;
}
return 0;
@@ -68,7 +68,9 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
int lock_error,kfile,open_mode,save_errno;
uint i,j,len,errpos,head_length,base_pos,offset,info_length,extra,keys,
key_parts,unique_key_parts,tmp_length,uniques;
- char name_buff[FN_REFLEN],*disk_cache,*disk_pos;
+ char name_buff[FN_REFLEN], org_name [FN_REFLEN], index_name[FN_REFLEN],
+ data_name[FN_REFLEN];
+ char *disk_cache,*disk_pos;
MI_INFO info,*m_info,*old_info;
MYISAM_SHARE share_buff,*share;
ulong rec_per_key_part[MI_MAX_POSSIBLE_KEY*MI_MAX_KEY_SEG];
@@ -83,7 +85,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
head_length=sizeof(share_buff.state.header);
bzero((byte*) &info,sizeof(info));
- VOID(fn_format(name_buff,name,"",MI_NAME_IEXT,4+16+32));
+ my_realpath(name_buff, fn_format(org_name,name,"",MI_NAME_IEXT,4),MYF(0));
pthread_mutex_lock(&THR_LOCK_myisam);
if (!(old_info=test_if_reopen(name_buff)))
{
@@ -112,7 +114,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
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;
+ my_errno=HA_ERR_WRONG_TABLE_DEF;
goto err;
}
share->options= mi_uint2korr(share->state.header.options);
@@ -127,6 +129,13 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
my_errno=HA_ERR_OLD_FILE;
goto err;
}
+ /* Don't call realpath() if the name can't be a link */
+ if (strcmp(name_buff, org_name))
+ (void) my_readlink(index_name, org_name, MYF(0));
+ else
+ (void) strmov(index_name, org_name);
+ (void) fn_format(data_name,org_name,"",MI_NAME_DEXT,2+4+16);
+
info_length=mi_uint2korr(share->state.header.header_length);
base_pos=mi_uint2korr(share->state.header.base_pos);
if (!(disk_cache=(char*) my_alloca(info_length)))
@@ -207,7 +216,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
(mi_safe_mul(share->base.reclength,
(ulonglong) 1 << (share->base.rec_reflength*8))-1);
max_key_file_length=
- mi_safe_mul(MI_KEY_BLOCK_LENGTH,
+ mi_safe_mul(MI_MIN_KEY_BLOCK_LENGTH,
((ulonglong) 1 << (share->base.key_reflength*8))-1);
#if SIZEOF_OFF_T == 4
set_if_smaller(max_data_file_length, INT_MAX32);
@@ -249,7 +258,9 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
&share->rec,
(share->base.fields+1)*sizeof(MI_COLUMNDEF),
&share->blobs,sizeof(MI_BLOB)*share->base.blobs,
- &share->filename,strlen(name_buff)+1,
+ &share->unique_file_name,strlen(name_buff)+1,
+ &share->index_file_name,strlen(index_name)+1,
+ &share->data_file_name,strlen(data_name)+1,
&share->state.key_root,keys*sizeof(my_off_t),
&share->state.key_del,
(share->state.header.max_block_size*sizeof(my_off_t)),
@@ -267,7 +278,9 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
memcpy((char*) share->state.key_del,
(char*) key_del, (sizeof(my_off_t) *
share->state.header.max_block_size));
- strmov(share->filename,name_buff);
+ strmov(share->unique_file_name, name_buff);
+ strmov(share->index_file_name, index_name);
+ strmov(share->data_file_name, data_name);
share->blocksize=min(IO_SIZE,myisam_block_size);
{
@@ -354,7 +367,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
lock_error=1; /* Database unlocked */
}
- if (mi_open_datafile(&info, share))
+ if (mi_open_datafile(&info, share, -1))
goto err;
errpos=5;
@@ -427,7 +440,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
my_errno=EACCES; /* Can't open in write mode */
goto err;
}
- if (mi_open_datafile(&info, share))
+ if (mi_open_datafile(&info, share, old_info->dfile))
goto err;
errpos=5;
}
@@ -439,12 +452,12 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
&info.buff,(share->base.max_key_block_length*2+
share->base.max_key_length),
&info.lastkey,share->base.max_key_length*3+1,
- &info.filename,strlen(name)+1,
+ &info.filename,strlen(org_name)+1,
NullS))
goto err;
errpos=6;
- strmov(info.filename,name);
+ strmov(info.filename,org_name);
memcpy(info.blobs,share->blobs,sizeof(MI_BLOB)*share->base.blobs);
info.lastkey2=info.lastkey+share->base.max_key_length;
@@ -462,6 +475,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
share->options|=HA_OPTION_READ_ONLY_DATA;
info.lock_type=F_UNLCK;
info.quick_mode=0;
+ info.bulk_insert=0;
info.errkey= -1;
info.page_changed=1;
pthread_mutex_lock(&share->intern_lock);
@@ -515,7 +529,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
pthread_mutex_unlock(&THR_LOCK_myisam);
if (myisam_log_file >= 0)
{
- intern_filename(name_buff,share->filename);
+ intern_filename(name_buff,share->index_file_name);
_myisam_log(MI_LOG_OPEN,m_info,name_buff,(uint) strlen(name_buff));
}
DBUG_RETURN(m_info);
@@ -626,15 +640,20 @@ static void setup_key_functions(register MI_KEYDEF *keyinfo)
}
else if (keyinfo->flag & HA_VAR_LENGTH_KEY)
{
- keyinfo->bin_search=_mi_seq_search;
keyinfo->get_key= _mi_get_pack_key;
if (keyinfo->seg[0].flag & HA_PACK_KEY)
{ /* Prefix compression */
+ if (!keyinfo->seg->charset || use_strcoll(keyinfo->seg->charset) ||
+ (keyinfo->seg->flag & HA_NULL_PART))
+ keyinfo->bin_search=_mi_seq_search;
+ else
+ keyinfo->bin_search=_mi_prefix_search;
keyinfo->pack_key=_mi_calc_var_pack_key_length;
keyinfo->store_key=_mi_store_var_pack_key;
}
else
{
+ keyinfo->bin_search=_mi_seq_search;
keyinfo->pack_key=_mi_calc_var_key_length; /* Variable length key */
keyinfo->store_key=_mi_store_static_key;
}
@@ -773,14 +792,17 @@ uint mi_state_info_read_dsk(File file, MI_STATE_INFO *state, my_bool pRead)
{
char buff[MI_STATE_INFO_SIZE + MI_STATE_EXTRA_SIZE];
- if (pRead)
+ if (!myisam_single_user)
{
- if (my_pread(file, buff, state->state_length,0L, MYF(MY_NABP)))
+ if (pRead)
+ {
+ if (my_pread(file, buff, state->state_length,0L, MYF(MY_NABP)))
+ return (MY_FILE_ERROR);
+ }
+ else if (my_read(file, buff, state->state_length,MYF(MY_NABP)))
return (MY_FILE_ERROR);
+ mi_state_info_read(buff, state);
}
- else if (my_read(file, buff, state->state_length,MYF(MY_NABP)))
- return (MY_FILE_ERROR);
- mi_state_info_read(buff, state);
return 0;
}
@@ -892,7 +914,7 @@ char *mi_keydef_read(char *ptr, MI_KEYDEF *keydef)
keydef->keylength = mi_uint2korr(ptr); ptr +=2;
keydef->minlength = mi_uint2korr(ptr); ptr +=2;
keydef->maxlength = mi_uint2korr(ptr); ptr +=2;
- keydef->block_size = keydef->block_length/MI_KEY_BLOCK_LENGTH-1;
+ keydef->block_size = keydef->block_length/MI_MIN_KEY_BLOCK_LENGTH-1;
keydef->underflow_block_length=keydef->block_length/3;
keydef->version = 0; /* Not saved */
return ptr;
@@ -988,37 +1010,37 @@ char *mi_recinfo_read(char *ptr, MI_COLUMNDEF *recinfo)
}
/**************************************************************************
- ** Help functions for recover
- *************************************************************************/
+Open data file with or without RAID
+We can't use dup() here as the data file descriptors need to have different
+active seek-positions.
-int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share)
-{
- char name_buff[FN_REFLEN];
- (void) fn_format(name_buff, share->filename,"",MI_NAME_DEXT, 2+4);
+The argument file_to_dup is here for the future if there would on some OS
+exist a dup()-like call that would give us two different file descriptors.
+*************************************************************************/
+int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, File file_to_dup __attribute__((unused)))
+{
#ifdef USE_RAID
if (share->base.raid_type)
{
- if ((info->dfile=my_raid_open(name_buff,
- share->mode | O_SHARE,
- share->base.raid_type,
- share->base.raid_chunks,
- share->base.raid_chunksize,
- MYF(MY_WME | MY_RAID))) < 0)
- return 1;
+ info->dfile=my_raid_open(share->data_file_name,
+ share->mode | O_SHARE,
+ share->base.raid_type,
+ share->base.raid_chunks,
+ share->base.raid_chunksize,
+ MYF(MY_WME | MY_RAID));
}
else
#endif
- if ((info->dfile=my_open(name_buff, share->mode | O_SHARE,
- MYF(MY_WME))) < 0)
- return 1;
- return 0;
+ info->dfile=my_open(share->data_file_name, share->mode | O_SHARE,
+ MYF(MY_WME));
+ return info->dfile >= 0 ? 0 : 1;
}
int mi_open_keyfile(MYISAM_SHARE *share)
{
- if ((share->kfile=my_open(share->filename, share->mode | O_SHARE,
+ if ((share->kfile=my_open(share->unique_file_name, share->mode | O_SHARE,
MYF(MY_WME))) < 0)
return 1;
return 0;
diff --git a/myisam/mi_packrec.c b/myisam/mi_packrec.c
index 242883a2c4a..d067fdc0fc5 100644
--- a/myisam/mi_packrec.c
+++ b/myisam/mi_packrec.c
@@ -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 */
@@ -465,7 +465,7 @@ static void (*get_unpack_function(MI_COLUMNDEF *rec))
(MI_COLUMNDEF *, MI_BIT_BUFF *, uchar *, uchar *)
{
switch (rec->base_type) {
- case FIELD_SKIPP_ZERO:
+ case FIELD_SKIP_ZERO:
if (rec->pack_type & PACK_TYPE_ZERO_FILL)
return &uf_zerofill_skipp_zero;
return &uf_skipp_zero;
@@ -475,7 +475,7 @@ static void (*get_unpack_function(MI_COLUMNDEF *rec))
if (rec->pack_type & PACK_TYPE_ZERO_FILL)
return &uf_zerofill_normal;
return &decode_bytes;
- case FIELD_SKIPP_ENDSPACE:
+ case FIELD_SKIP_ENDSPACE:
if (rec->pack_type & PACK_TYPE_SPACE_FIELDS)
{
if (rec->pack_type & PACK_TYPE_SELECTED)
@@ -485,7 +485,7 @@ static void (*get_unpack_function(MI_COLUMNDEF *rec))
if (rec->pack_type & PACK_TYPE_SELECTED)
return &uf_endspace_selected;
return &uf_endspace;
- case FIELD_SKIPP_PRESPACE:
+ case FIELD_SKIP_PRESPACE:
if (rec->pack_type & PACK_TYPE_SPACE_FIELDS)
{
if (rec->pack_type & PACK_TYPE_SELECTED)
diff --git a/myisam/mi_page.c b/myisam/mi_page.c
index f8e2a977754..064e9239e73 100644
--- a/myisam/mi_page.c
+++ b/myisam/mi_page.c
@@ -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 */
@@ -64,9 +64,9 @@ int _mi_write_keypage(register MI_INFO *info, register MI_KEYDEF *keyinfo,
#ifndef FAST /* Safety check */
if (page < info->s->base.keystart ||
page+keyinfo->block_length > info->state->key_file_length ||
- page & (myisam_block_size-1))
+ (page & (MI_MIN_KEY_BLOCK_LENGTH-1)))
{
- DBUG_PRINT("error",("Trying to write outside key region: %lu",
+ DBUG_PRINT("error",("Trying to write inside key status region: %lu",
(long) page));
my_errno=EINVAL;
return(-1);
diff --git a/myisam/mi_panic.c b/myisam/mi_panic.c
index 92fc6f3695c..bd0b07b097e 100644
--- a/myisam/mi_panic.c
+++ b/myisam/mi_panic.c
@@ -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 */
diff --git a/myisam/mi_range.c b/myisam/mi_range.c
index 038f9abc3a6..70694bf4620 100644
--- a/myisam/mi_range.c
+++ b/myisam/mi_range.c
@@ -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 */
@@ -45,7 +45,7 @@ ha_rows mi_records_in_range(MI_INFO *info, int inx, const byte *start_key,
if ((inx = _mi_check_index(info,inx)) < 0)
DBUG_RETURN(HA_POS_ERROR);
- if (_mi_readinfo(info,F_RDLCK,1))
+ if (fast_mi_readinfo(info))
DBUG_RETURN(HA_POS_ERROR);
info->update&= (HA_STATE_CHANGED+HA_STATE_ROW_CHANGED);
if (info->s->concurrent_insert)
@@ -58,7 +58,7 @@ ha_rows mi_records_in_range(MI_INFO *info, int inx, const byte *start_key,
info->state->records+ (ha_rows) 1);
if (info->s->concurrent_insert)
rw_unlock(&info->s->key_root_lock[inx]);
- VOID(_mi_writeinfo(info,0));
+ fast_mi_writeinfo(info);
if (start_pos == HA_POS_ERROR || end_pos == HA_POS_ERROR)
DBUG_RETURN(HA_POS_ERROR);
DBUG_PRINT("info",("records: %ld",(ulong) (end_pos-start_pos)));
@@ -72,7 +72,7 @@ ha_rows mi_records_in_range(MI_INFO *info, int inx, const byte *start_key,
static ha_rows _mi_record_pos(MI_INFO *info, const byte *key, uint key_len,
enum ha_rkey_function search_flag)
{
- uint inx=(uint) info->lastinx;
+ uint inx=(uint) info->lastinx, nextflag;
MI_KEYDEF *keyinfo=info->s->keyinfo+inx;
uchar *key_buff;
double pos;
@@ -86,8 +86,12 @@ static ha_rows _mi_record_pos(MI_INFO *info, const byte *key, uint key_len,
key_len=_mi_pack_key(info,inx,key_buff,(uchar*) key,key_len);
DBUG_EXECUTE("key",_mi_print_key(DBUG_FILE,keyinfo->seg,
(uchar*) key_buff,key_len););
+ nextflag=myisam_read_vec[search_flag];
+ if (!(nextflag & (SEARCH_FIND | SEARCH_NO_FIND | SEARCH_LAST)))
+ key_len=USE_WHOLE_KEY;
+
pos=_mi_search_pos(info,keyinfo,key_buff,key_len,
- myisam_read_vec[search_flag] | SEARCH_SAVE_BUFF,
+ nextflag | SEARCH_SAVE_BUFF,
info->s->state.key_root[inx]);
if (pos >= 0.0)
{
@@ -145,9 +149,9 @@ static double _mi_search_pos(register MI_INFO *info,
** Matches keynr+1
*/
offset=1.0; /* Matches keynr+1 */
- if (nextflag & SEARCH_FIND &&
+ if ((nextflag & SEARCH_FIND) && nod_flag &&
((keyinfo->flag & (HA_NOSAME | HA_NULL_PART)) != HA_NOSAME ||
- key_len) && nod_flag)
+ key_len != USE_WHOLE_KEY))
{
/*
** There may be identical keys in the tree. Try to match on of those.
diff --git a/myisam/mi_rename.c b/myisam/mi_rename.c
index 5c92db3f7ce..db44b8fe28f 100644
--- a/myisam/mi_rename.c
+++ b/myisam/mi_rename.c
@@ -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 */
@@ -51,7 +51,7 @@ int mi_rename(const char *old_name, const char *new_name)
fn_format(from,old_name,"",MI_NAME_IEXT,4);
fn_format(to,new_name,"",MI_NAME_IEXT,4);
- if (my_rename(from, to, MYF(MY_WME)))
+ if (my_rename_with_symlink(from, to, MYF(MY_WME)))
DBUG_RETURN(my_errno);
fn_format(from,old_name,"",MI_NAME_DEXT,4);
fn_format(to,new_name,"",MI_NAME_DEXT,4);
@@ -60,5 +60,5 @@ int mi_rename(const char *old_name, const char *new_name)
DBUG_RETURN(my_raid_rename(from, to, raid_chunks, MYF(MY_WME)) ? my_errno :
0);
#endif
- DBUG_RETURN(my_rename(from, to,MYF(MY_WME)) ? my_errno : 0);
+ DBUG_RETURN(my_rename_with_symlink(from, to,MYF(MY_WME)) ? my_errno : 0);
}
diff --git a/myisam/mi_rfirst.c b/myisam/mi_rfirst.c
index 8928c6332c5..e30f61801a0 100644
--- a/myisam/mi_rfirst.c
+++ b/myisam/mi_rfirst.c
@@ -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 */
diff --git a/myisam/mi_rkey.c b/myisam/mi_rkey.c
index 0df390412b9..86547d3ef04 100644
--- a/myisam/mi_rkey.c
+++ b/myisam/mi_rkey.c
@@ -27,7 +27,7 @@ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len,
{
uchar *key_buff;
MYISAM_SHARE *share=info->s;
- uint pack_key_length;
+ uint pack_key_length, use_key_length, nextflag;
DBUG_ENTER("mi_rkey");
DBUG_PRINT("enter",("base: %lx inx: %d search_flag: %d",
info,inx,search_flag));
@@ -55,11 +55,17 @@ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len,
bmove(key_buff,key,key_len);
}
- if (_mi_readinfo(info,F_RDLCK,1))
+ if (fast_mi_readinfo(info))
goto err;
if (share->concurrent_insert)
rw_rdlock(&share->key_root_lock[inx]);
- if (!_mi_search(info,info->s->keyinfo+inx,key_buff,pack_key_length,
+
+ nextflag=myisam_read_vec[search_flag];
+ use_key_length=pack_key_length;
+ if (!(nextflag & (SEARCH_FIND | SEARCH_NO_FIND | SEARCH_LAST)))
+ use_key_length=USE_WHOLE_KEY;
+
+ if (!_mi_search(info,info->s->keyinfo+inx,key_buff,use_key_length,
myisam_read_vec[search_flag],info->s->state.key_root[inx]))
{
while (info->lastpos >= info->state->data_file_length)
diff --git a/myisam/mi_rlast.c b/myisam/mi_rlast.c
index c08174e9117..61c3ff58fd5 100644
--- a/myisam/mi_rlast.c
+++ b/myisam/mi_rlast.c
@@ -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 */
diff --git a/myisam/mi_rnext.c b/myisam/mi_rnext.c
index f297740af60..6d135462f96 100644
--- a/myisam/mi_rnext.c
+++ b/myisam/mi_rnext.c
@@ -35,7 +35,7 @@ int mi_rnext(MI_INFO *info, byte *buf, int inx)
if (info->lastpos == HA_OFFSET_ERROR && info->update & HA_STATE_PREV_FOUND)
flag=0; /* Read first */
- if (_mi_readinfo(info,F_RDLCK,1))
+ if (fast_mi_readinfo(info))
DBUG_RETURN(my_errno);
if (info->s->concurrent_insert)
rw_rdlock(&info->s->key_root_lock[inx]);
@@ -51,7 +51,7 @@ int mi_rnext(MI_INFO *info, byte *buf, int inx)
info->s->state.key_root[inx]);
else
error=_mi_search(info,info->s->keyinfo+inx,info->lastkey,
- info->lastkey_length,flag, info->s->state.key_root[inx]);
+ USE_WHOLE_KEY,flag, info->s->state.key_root[inx]);
if (!error)
{
diff --git a/myisam/mi_rnext_same.c b/myisam/mi_rnext_same.c
index 0e172894cdf..662bdb154b3 100644
--- a/myisam/mi_rnext_same.c
+++ b/myisam/mi_rnext_same.c
@@ -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,7 +35,7 @@ int mi_rnext_same(MI_INFO *info, byte *buf)
DBUG_RETURN(my_errno=HA_ERR_WRONG_INDEX);
keyinfo=info->s->keyinfo+inx;
flag=SEARCH_BIGGER; /* Read next */
- if (_mi_readinfo(info,F_RDLCK,1))
+ if (fast_mi_readinfo(info))
DBUG_RETURN(my_errno);
memcpy(info->lastkey2,info->lastkey,info->last_rkey_length);
diff --git a/myisam/mi_rprev.c b/myisam/mi_rprev.c
index fff2d2257b6..4807e636252 100644
--- a/myisam/mi_rprev.c
+++ b/myisam/mi_rprev.c
@@ -36,7 +36,7 @@ int mi_rprev(MI_INFO *info, byte *buf, int inx)
if (info->lastpos == HA_OFFSET_ERROR && info->update & HA_STATE_NEXT_FOUND)
flag=0; /* Read last */
- if (_mi_readinfo(info,F_RDLCK,1))
+ if (fast_mi_readinfo(info))
DBUG_RETURN(my_errno);
changed=_mi_test_if_changed(info);
if (share->concurrent_insert)
@@ -50,7 +50,7 @@ int mi_rprev(MI_INFO *info, byte *buf, int inx)
share->state.key_root[inx]);
else
error=_mi_search(info,share->keyinfo+inx,info->lastkey,
- info->lastkey_length, flag, share->state.key_root[inx]);
+ USE_WHOLE_KEY, flag, share->state.key_root[inx]);
if (!error)
{
diff --git a/myisam/mi_rrnd.c b/myisam/mi_rrnd.c
index 11fa2af59bd..f8009441cff 100644
--- a/myisam/mi_rrnd.c
+++ b/myisam/mi_rrnd.c
@@ -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 */
diff --git a/myisam/mi_rsame.c b/myisam/mi_rsame.c
index a4092b53c0b..56c8d1226ca 100644
--- a/myisam/mi_rsame.c
+++ b/myisam/mi_rsame.c
@@ -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 */
@@ -41,7 +41,7 @@ int mi_rsame(MI_INFO *info, byte *record, int inx)
info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
/* Read row from data file */
- if (_mi_readinfo(info,F_RDLCK,1))
+ if (fast_mi_readinfo(info))
DBUG_RETURN(my_errno);
if (inx >= 0)
@@ -51,7 +51,8 @@ int mi_rsame(MI_INFO *info, byte *record, int inx)
info->lastpos);
if (info->s->concurrent_insert)
rw_rdlock(&info->s->key_root_lock[inx]);
- VOID(_mi_search(info,info->s->keyinfo+inx,info->lastkey,0,SEARCH_SAME,
+ VOID(_mi_search(info,info->s->keyinfo+inx,info->lastkey, USE_WHOLE_KEY,
+ SEARCH_SAME,
info->s->state.key_root[inx]));
if (info->s->concurrent_insert)
rw_unlock(&info->s->key_root_lock[inx]);
diff --git a/myisam/mi_rsamepos.c b/myisam/mi_rsamepos.c
index 28a5b6783b2..a1d96fb7104 100644
--- a/myisam/mi_rsamepos.c
+++ b/myisam/mi_rsamepos.c
@@ -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 */
diff --git a/myisam/mi_scan.c b/myisam/mi_scan.c
index c06f092ab17..90bc3430ba7 100644
--- a/myisam/mi_scan.c
+++ b/myisam/mi_scan.c
@@ -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 */
diff --git a/myisam/mi_search.c b/myisam/mi_search.c
index 2c04679ed4c..4114125d6f7 100644
--- a/myisam/mi_search.c
+++ b/myisam/mi_search.c
@@ -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 */
@@ -19,29 +19,27 @@
#include "fulltext.h"
#include "m_ctype.h"
-#define CMP(a,b) (a<b ? -1 : a == b ? 0 : 1)
-
static my_bool _mi_get_prev_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
- uchar *key, uchar *keypos,
- uint *return_key_length);
+ uchar *key, uchar *keypos,
+ uint *return_key_length);
- /* Check index */
+ /* Check index */
int _mi_check_index(MI_INFO *info, int inx)
{
- if (inx == -1) /* Use last index */
+ if (inx == -1) /* Use last index */
inx=info->lastinx;
if (inx < 0 || ! (((ulonglong) 1 << inx) & info->s->state.key_map))
{
my_errno=HA_ERR_WRONG_INDEX;
return -1;
}
- if (info->lastinx != inx) /* Index changed */
+ if (info->lastinx != inx) /* Index changed */
{
info->lastinx = inx;
info->page_changed=1;
info->update= ((info->update & (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED)) |
- HA_STATE_NEXT_FOUND | HA_STATE_PREV_FOUND);
+ HA_STATE_NEXT_FOUND | HA_STATE_PREV_FOUND);
}
if (info->opt_flag & WRITE_CACHE_USED && flush_io_cache(&info->rec_cache))
return(-1);
@@ -49,15 +47,15 @@ int _mi_check_index(MI_INFO *info, int inx)
} /* mi_check_index */
- /*
- ** Search after row by a key
- ** Position to row is stored in info->lastpos
- ** Return: -1 if not found
- ** 1 if one should continue search on higher level
- */
+ /*
+ ** Search after row by a key
+ ** Position to row is stored in info->lastpos
+ ** Return: -1 if not found
+ ** 1 if one should continue search on higher level
+ */
int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
- uchar *key, uint key_len, uint nextflag, register my_off_t pos)
+ uchar *key, uint key_len, uint nextflag, register my_off_t pos)
{
my_bool last_key;
int error,flag;
@@ -66,25 +64,25 @@ int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
uchar lastkey[MI_MAX_KEY_BUFF],*buff;
DBUG_ENTER("_mi_search");
DBUG_PRINT("enter",("pos: %ld nextflag: %d lastpos: %ld",
- pos,nextflag,info->lastpos));
+ pos,nextflag,info->lastpos));
DBUG_EXECUTE("key",_mi_print_key(DBUG_FILE,keyinfo->seg,key,key_len););
if (pos == HA_OFFSET_ERROR)
{
- my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
+ my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
info->lastpos= HA_OFFSET_ERROR;
if (!(nextflag & (SEARCH_SMALLER | SEARCH_BIGGER | SEARCH_LAST)))
- DBUG_RETURN(-1); /* Not found ; return error */
- DBUG_RETURN(1); /* Search at upper levels */
+ DBUG_RETURN(-1); /* Not found ; return error */
+ DBUG_RETURN(1); /* Search at upper levels */
}
if (!(buff=_mi_fetch_keypage(info,keyinfo,pos,info->buff,
- test(!(nextflag & SEARCH_SAVE_BUFF)))))
+ test(!(nextflag & SEARCH_SAVE_BUFF)))))
goto err;
DBUG_DUMP("page",(byte*) buff,mi_getint(buff));
flag=(*keyinfo->bin_search)(info,keyinfo,buff,key,key_len,nextflag,
- &keypos,lastkey, &last_key);
+ &keypos,lastkey, &last_key);
if (flag == MI_FOUND_WRONG_KEY)
DBUG_RETURN(-1);
nod_flag=mi_test_if_nod(buff);
@@ -93,35 +91,36 @@ int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
if (flag)
{
if ((error=_mi_search(info,keyinfo,key,key_len,nextflag,
- _mi_kpos(nod_flag,keypos))) <= 0)
+ _mi_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 */
+ keypos == buff+2+nod_flag)
+ DBUG_RETURN(1); /* Bigger than key */
}
else if (nextflag & SEARCH_BIGGER && keypos >= maxpos)
- DBUG_RETURN(1); /* Smaller than key */
+ DBUG_RETURN(1); /* Smaller than key */
}
else
{
- if (nextflag & SEARCH_FIND && (!(keyinfo->flag & HA_NOSAME)
- || key_len) && nod_flag)
+ if ((nextflag & SEARCH_FIND) && nod_flag &&
+ ((keyinfo->flag & (HA_NOSAME | HA_NULL_PART)) != HA_NOSAME ||
+ key_len != USE_WHOLE_KEY))
{
if ((error=_mi_search(info,keyinfo,key,key_len,SEARCH_FIND,
- _mi_kpos(nod_flag,keypos))) >= 0 ||
- my_errno != HA_ERR_KEY_NOT_FOUND)
- DBUG_RETURN(error);
- info->last_keypage= HA_OFFSET_ERROR; /* Buffer not in memory */
+ _mi_kpos(nod_flag,keypos))) >= 0 ||
+ my_errno != HA_ERR_KEY_NOT_FOUND)
+ DBUG_RETURN(error);
+ info->last_keypage= HA_OFFSET_ERROR; /* Buffer not in mem */
}
}
if (pos != info->last_keypage)
{
uchar *old_buff=buff;
if (!(buff=_mi_fetch_keypage(info,keyinfo,pos,info->buff,
- test(!(nextflag & SEARCH_SAVE_BUFF)))))
+ test(!(nextflag & SEARCH_SAVE_BUFF)))))
goto err;
keypos=buff+(keypos-old_buff);
maxpos=buff+(maxpos-old_buff);
@@ -131,13 +130,13 @@ int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
{
uint not_used;
if (_mi_get_prev_key(info,keyinfo, buff, info->lastkey, keypos,
- &info->lastkey_length))
+ &info->lastkey_length))
goto err;
if ((nextflag & SEARCH_LAST) &&
- _mi_key_cmp(keyinfo->seg, info->lastkey, key, key_len, SEARCH_FIND,
- &not_used))
+ _mi_key_cmp(keyinfo->seg, info->lastkey, key, key_len, SEARCH_FIND,
+ &not_used))
{
- my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
+ my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
goto err;
}
}
@@ -156,7 +155,7 @@ int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
info->int_keytree_version=keyinfo->version;
info->last_search_keypage=info->last_keypage;
info->page_changed=0;
- info->buff_used= (info->buff != buff); /* If we have to reread buff */
+ info->buff_used= (info->buff != buff); /* If we have to reread buff */
DBUG_PRINT("exit",("found key at %lu",(ulong) info->lastpos));
DBUG_RETURN(0);
@@ -168,14 +167,14 @@ err:
} /* _mi_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 */
+ /* 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 _mi_bin_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
- uchar *key, uint key_len, uint comp_flag, uchar **ret_pos,
- uchar *buff __attribute__((unused)), my_bool *last_key)
+ uchar *key, uint key_len, uint comp_flag, uchar **ret_pos,
+ uchar *buff __attribute__((unused)), my_bool *last_key)
{
reg4 int start,mid,end,save_end;
int flag;
@@ -193,17 +192,17 @@ int _mi_bin_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
{
mid= (start+end)/2;
if ((flag=_mi_key_cmp(keyinfo->seg,page+(uint) mid*totlength,key,key_len,
- comp_flag,&not_used))
- >= 0)
+ comp_flag,&not_used))
+ >= 0)
end=mid;
else
start=mid+1;
}
if (mid != start)
flag=_mi_key_cmp(keyinfo->seg,page+(uint) start*totlength,key,key_len,
- comp_flag,&not_used);
+ comp_flag,&not_used);
if (flag < 0)
- start++; /* point at next, bigger key */
+ start++; /* point at next, bigger key */
*ret_pos=page+(uint) start*totlength;
*last_key= end == save_end;
DBUG_PRINT("exit",("flag: %d keypos: %d",flag,start));
@@ -211,13 +210,13 @@ int _mi_bin_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
} /* _mi_bin_search */
- /* Used instead of _mi_bin_search() when key is packed */
- /* Puts smaller or identical key in buff */
- /* Key is searched sequentially */
+ /* Used instead of _mi_bin_search() when key is packed */
+ /* Puts smaller or identical key in buff */
+ /* Key is searched sequentially */
int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
- uchar *key, uint key_len, uint comp_flag, uchar **ret_pos,
- uchar *buff, my_bool *last_key)
+ uchar *key, uint key_len, uint comp_flag, uchar **ret_pos,
+ uchar *buff, my_bool *last_key)
{
int flag;
uint nod_flag,length,not_used;
@@ -229,7 +228,7 @@ int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
nod_flag=mi_test_if_nod(page);
page+=2+nod_flag;
*ret_pos=page;
- t_buff[0]=0; /* Avoid bugs */
+ t_buff[0]=0; /* Avoid bugs */
while (page < end)
{
length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,t_buff);
@@ -237,11 +236,11 @@ int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
{
my_errno=HA_ERR_CRASHED;
DBUG_PRINT("error",("Found wrong key: length: %d page: %lx end: %lx",
- length,page,end));
+ length,page,end));
DBUG_RETURN(MI_FOUND_WRONG_KEY);
}
if ((flag=_mi_key_cmp(keyinfo->seg,t_buff,key,key_len,comp_flag,
- &not_used)) >= 0)
+ &not_used)) >= 0)
break;
#ifdef EXTRA_DEBUG
DBUG_PRINT("loop",("page: %lx key: '%s' flag: %d",page,t_buff,flag));
@@ -250,14 +249,224 @@ int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
*ret_pos=page;
}
if (flag == 0)
- memcpy(buff,t_buff,length); /* Result is first key */
+ memcpy(buff,t_buff,length); /* Result is first key */
*last_key= page == end;
DBUG_PRINT("exit",("flag: %d ret_pos: %lx",flag,*ret_pos));
DBUG_RETURN(flag);
} /* _mi_seq_search */
- /* Get pos to a key_block */
+int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
+ uchar *key, uint key_len, uint nextflag, uchar **ret_pos,
+ uchar *buff, my_bool *last_key)
+{
+ /* my_flag is raw comparison result to be changed according to
+ SEARCH_NO_FIND,SEARCH_LAST and HA_REVERSE_SORT flags.
+ flag is the value returned by _mi_key_cmp and as treated as final */
+ int flag=0, my_flag=-1;
+ uint nod_flag, length, len, matched, cmplen, kseg_len;
+ uint prefix_len,suffix_len;
+ int key_len_skip, seg_len_pack, key_len_left;
+ uchar *end, *kseg, *vseg;
+ uchar *sort_order=keyinfo->seg->charset->sort_order;
+ uchar tt_buff[MI_MAX_KEY_BUFF+2], *t_buff=tt_buff+2;
+ uchar *saved_from, *saved_to, *saved_vseg;
+ uint saved_length=0, saved_prefix_len=0;
+ DBUG_ENTER("_mi_prefix_search");
+
+ LINT_INIT(length);
+ LINT_INIT(prefix_len);
+ LINT_INIT(seg_len_pack);
+ LINT_INIT(saved_from);
+ LINT_INIT(saved_to);
+ LINT_INIT(saved_vseg);
+
+ t_buff[0]=0; /* Avoid bugs */
+ end= page+mi_getint(page);
+ nod_flag=mi_test_if_nod(page);
+ page+=2+nod_flag;
+ *ret_pos=page;
+ kseg=key;
+ {
+ uint lenght_pack;
+ get_key_pack_length(kseg_len,lenght_pack,kseg);
+ key_len_skip=lenght_pack+kseg_len;
+ key_len_left=(int) key_len- (int) key_len_skip;
+ cmplen=(key_len_left>=0) ? kseg_len : key_len-lenght_pack;
+ DBUG_PRINT("info",("key: '%.*s'",kseg_len,kseg));
+ }
+
+/*
+ Keys are compressed the following way:
+
+ If the max length of first key segment <= 127 characters the prefix is
+ 1 byte else it's 2 byte
+
+ prefix The high bit is set if this is a prefix for the prev key
+ length Packed length if the previous was a prefix byte
+ [length] Length character of data
+ next-key-seg Next key segments
+*/
+
+ matched=0; /* how many char's from prefix were alredy matched */
+ len=0; /* length of previous key unpacked */
+
+ while (page < end)
+ {
+ uint packed= *page & 128;
+
+ vseg=page;
+ if (keyinfo->seg->length >= 127)
+ {
+ suffix_len=mi_uint2korr(vseg) & 32767;
+ vseg+=2;
+ }
+ else
+ suffix_len= *vseg++ & 127;
+
+ if (packed)
+ {
+ if (suffix_len == 0) /* Same key */
+ prefix_len=len;
+ else
+ {
+ prefix_len=suffix_len;
+ get_key_length(suffix_len,vseg);
+ }
+ }
+ else
+ prefix_len=0;
+
+ len=prefix_len+suffix_len;
+ seg_len_pack=get_pack_length(len);
+ t_buff=tt_buff+3-seg_len_pack;
+ store_key_length(t_buff,len);
+
+ if (prefix_len > saved_prefix_len)
+ memcpy(t_buff+seg_len_pack+saved_prefix_len,saved_vseg,
+ prefix_len-saved_prefix_len);
+ saved_vseg=vseg;
+ saved_prefix_len=prefix_len;
+
+ DBUG_PRINT("loop",("page: '%.*s%.*s'",prefix_len,t_buff+seg_len_pack,suffix_len,vseg));
+ {
+ uchar *from=vseg+suffix_len;
+ MI_KEYSEG *keyseg;
+ uint l;
+
+ for (keyseg=keyinfo->seg+1 ; keyseg->type ; keyseg++ )
+ {
+
+ if (keyseg->flag & HA_NULL_PART)
+ {
+ if (!(*from++))
+ continue;
+ }
+ if (keyseg->flag & (HA_VAR_LENGTH | HA_BLOB_PART | HA_SPACE_PACK))
+ {
+ get_key_length(l,from);
+ }
+ else
+ l=keyseg->length;
+
+ from+=l;
+ }
+ from+=keyseg->length;
+ page=from+nod_flag;
+ length=from-vseg;
+ }
+
+ if (page > end)
+ {
+ my_errno=HA_ERR_CRASHED;
+ DBUG_PRINT("error",("Found wrong key: length: %d page: %lx end: %lx",
+ length,page,end));
+ DBUG_RETURN(MI_FOUND_WRONG_KEY);
+ }
+
+ if (matched >= prefix_len)
+ {
+ /* We have to compare. But we can still skip part of the key */
+ uint left;
+ uchar *k=kseg+prefix_len;
+
+ left=(len>cmplen) ? cmplen-prefix_len : suffix_len;
+
+ matched=prefix_len+left;
+
+ for(my_flag=0;left;left--)
+ if ((my_flag= (int) sort_order[*vseg++] - (int) sort_order[*k++]))
+ break;
+
+ if (my_flag>0) /* mismatch */
+ break;
+ else if (my_flag==0) /* match */
+ { /*
+ ** len cmplen seg_left_len more_segs
+ ** < matched=len; continue search
+ ** > = prefix ? found : (matched=len; continue search)
+ ** > < - ok, found
+ ** = < - ok, found
+ ** = = - ok, found
+ ** = = + next seg
+ */
+ if (len < cmplen)
+ {
+ my_flag= -1;
+ }
+ else if (len > cmplen)
+ {
+ if ((my_flag= (!(nextflag & SEARCH_PREFIX) || key_len_left>0)))
+ break;
+ goto fix_flag;
+ }
+ else if (key_len_left>0)
+ {
+ uint not_used;
+ if ((flag = _mi_key_cmp(keyinfo->seg+1,vseg,
+ k,key_len_left,nextflag,&not_used)) >= 0)
+ break;
+ }
+ else
+ {
+ /* at this line flag==-1 if the following lines were already
+ visited and 0 otherwise, i.e. flag <=0 here always !!! */
+ fix_flag:
+ if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST))
+ flag=(nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1;
+ if (flag>=0) break;
+ }
+ }
+ matched-=left;
+ }
+ /* else (matched < prefix_len) ---> do nothing. */
+
+ memcpy(buff,t_buff,saved_length=seg_len_pack+prefix_len);
+ saved_to=buff+saved_length;
+ saved_from=saved_vseg;
+ saved_length=length;
+ *ret_pos=page;
+ }
+ if (my_flag)
+ flag=(keyinfo->seg->flag & HA_REVERSE_SORT) ? -my_flag : my_flag;
+ if (flag == 0)
+ {
+ memcpy(buff,t_buff,saved_length=seg_len_pack+prefix_len);
+ saved_to=buff+saved_length;
+ saved_from=saved_vseg;
+ saved_length=length;
+ }
+ if (saved_length)
+ memcpy(saved_to,saved_from,saved_length);
+
+ *last_key= page == end;
+
+ DBUG_PRINT("exit",("flag: %d ret_pos: %lx",flag,*ret_pos));
+ DBUG_RETURN(flag);
+} /* _mi_prefix_search */
+
+
+ /* Get pos to a key_block */
my_off_t _mi_kpos(uint nod_flag, uchar *after_key)
{
@@ -265,11 +474,11 @@ my_off_t _mi_kpos(uint nod_flag, uchar *after_key)
switch (nod_flag) {
#if SIZEOF_OFF_T > 4
case 7:
- return mi_uint7korr(after_key)*MI_KEY_BLOCK_LENGTH;
+ return mi_uint7korr(after_key)*MI_MIN_KEY_BLOCK_LENGTH;
case 6:
- return mi_uint6korr(after_key)*MI_KEY_BLOCK_LENGTH;
+ return mi_uint6korr(after_key)*MI_MIN_KEY_BLOCK_LENGTH;
case 5:
- return mi_uint5korr(after_key)*MI_KEY_BLOCK_LENGTH;
+ return mi_uint5korr(after_key)*MI_MIN_KEY_BLOCK_LENGTH;
#else
case 7:
after_key++;
@@ -279,25 +488,25 @@ my_off_t _mi_kpos(uint nod_flag, uchar *after_key)
after_key++;
#endif
case 4:
- return ((my_off_t) mi_uint4korr(after_key))*MI_KEY_BLOCK_LENGTH;
+ return ((my_off_t) mi_uint4korr(after_key))*MI_MIN_KEY_BLOCK_LENGTH;
case 3:
- return ((my_off_t) mi_uint3korr(after_key))*MI_KEY_BLOCK_LENGTH;
+ return ((my_off_t) mi_uint3korr(after_key))*MI_MIN_KEY_BLOCK_LENGTH;
case 2:
- return (my_off_t) (mi_uint2korr(after_key)*MI_KEY_BLOCK_LENGTH);
+ return (my_off_t) (mi_uint2korr(after_key)*MI_MIN_KEY_BLOCK_LENGTH);
case 1:
- return (uint) (*after_key)*MI_KEY_BLOCK_LENGTH;
- case 0: /* At leaf page */
- default: /* Impossible */
+ return (uint) (*after_key)*MI_MIN_KEY_BLOCK_LENGTH;
+ case 0: /* At leaf page */
+ default: /* Impossible */
return(HA_OFFSET_ERROR);
}
} /* _kpos */
- /* Save pos to a key_block */
+ /* Save pos to a key_block */
void _mi_kpointer(register MI_INFO *info, register uchar *buff, my_off_t pos)
{
- pos/=MI_KEY_BLOCK_LENGTH;
+ pos/=MI_MIN_KEY_BLOCK_LENGTH;
switch (info->s->base.key_reflength) {
#if SIZEOF_OFF_T > 4
case 7: mi_int7store(buff,pos); break;
@@ -315,12 +524,12 @@ void _mi_kpointer(register MI_INFO *info, register uchar *buff, my_off_t pos)
case 3: mi_int3store(buff,pos); break;
case 2: mi_int2store(buff,(uint) pos); break;
case 1: buff[0]= (uchar) pos; break;
- default: abort(); /* impossible */
+ default: abort(); /* impossible */
}
} /* _mi_kpointer */
- /* Calc pos to a data-record from a key */
+ /* Calc pos to a data-record from a key */
my_off_t _mi_dpos(MI_INFO *info, uint nod_flag, uchar *after_key)
@@ -335,19 +544,19 @@ my_off_t _mi_dpos(MI_INFO *info, uint nod_flag, uchar *after_key)
case 5: pos= (my_off_t) mi_uint5korr(after_key); break;
#else
case 8: pos= (my_off_t) mi_uint4korr(after_key+4); break;
- case 7: pos= (my_off_t) mi_uint4korr(after_key+3); break;
- case 6: pos= (my_off_t) mi_uint4korr(after_key+2); break;
- case 5: pos= (my_off_t) mi_uint4korr(after_key+1); break;
+ case 7: pos= (my_off_t) mi_uint4korr(after_key+3); break;
+ case 6: pos= (my_off_t) mi_uint4korr(after_key+2); break;
+ case 5: pos= (my_off_t) mi_uint4korr(after_key+1); break;
#endif
case 4: pos= (my_off_t) mi_uint4korr(after_key); break;
case 3: pos= (my_off_t) mi_uint3korr(after_key); break;
case 2: pos= (my_off_t) mi_uint2korr(after_key); break;
default:
- pos=0L; /* Shut compiler up */
+ pos=0L; /* Shut compiler up */
}
return (info->s->options &
- (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? pos :
- pos*info->s->base.pack_reclength;
+ (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? pos :
+ pos*info->s->base.pack_reclength;
}
@@ -361,22 +570,22 @@ my_off_t _mi_rec_pos(MYISAM_SHARE *s, uchar *ptr)
case 8:
pos= (my_off_t) mi_uint8korr(ptr);
if (pos == HA_OFFSET_ERROR)
- return HA_OFFSET_ERROR; /* end of list */
+ return HA_OFFSET_ERROR; /* end of list */
break;
case 7:
pos= (my_off_t) mi_uint7korr(ptr);
if (pos == (((my_off_t) 1) << 56) -1)
- return HA_OFFSET_ERROR; /* end of list */
+ return HA_OFFSET_ERROR; /* end of list */
break;
case 6:
pos= (my_off_t) mi_uint6korr(ptr);
if (pos == (((my_off_t) 1) << 48) -1)
- return HA_OFFSET_ERROR; /* end of list */
+ return HA_OFFSET_ERROR; /* end of list */
break;
case 5:
pos= (my_off_t) mi_uint5korr(ptr);
if (pos == (((my_off_t) 1) << 40) -1)
- return HA_OFFSET_ERROR; /* end of list */
+ return HA_OFFSET_ERROR; /* end of list */
break;
#else
case 8:
@@ -401,20 +610,20 @@ my_off_t _mi_rec_pos(MYISAM_SHARE *s, uchar *ptr)
if (pos == (my_off_t) (1 << 16) -1)
return HA_OFFSET_ERROR;
break;
- default: abort(); /* Impossible */
+ default: abort(); /* Impossible */
}
return ((s->options &
- (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? pos :
- pos*s->base.pack_reclength);
+ (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? pos :
+ pos*s->base.pack_reclength);
}
- /* save position to record */
+ /* save position to record */
void _mi_dpointer(MI_INFO *info, uchar *buff, my_off_t pos)
{
if (!(info->s->options &
- (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) &&
+ (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) &&
pos != HA_OFFSET_ERROR)
pos/=info->s->base.pack_reclength;
@@ -437,27 +646,27 @@ void _mi_dpointer(MI_INFO *info, uchar *buff, my_off_t pos)
case 4: mi_int4store(buff,pos); break;
case 3: mi_int3store(buff,pos); break;
case 2: mi_int2store(buff,(uint) pos); break;
- default: abort(); /* Impossible */
+ default: abort(); /* Impossible */
}
} /* _mi_dpointer */
int _mi_compare_text(CHARSET_INFO *charset_info, uchar *a, uint a_length,
- uchar *b, uint b_length, my_bool part_key)
+ uchar *b, uint b_length, my_bool part_key)
{
- uint length= min(a_length,b_length);
- uchar *end= a+ length;
int flag;
#ifdef USE_STRCOLL
if (use_strcoll(charset_info))
{
- if ((flag = my_strnncoll(charset_info, a, a_length, b, b_length)))
- return flag;
+ /* QQ: This needs to work with part keys at some point */
+ return my_strnncoll(charset_info, a, a_length, b, b_length);
}
else
#endif
{
+ uint length= min(a_length,b_length);
+ uchar *end= a+ length;
uchar *sort_order=charset_info->sort_order;
while (a < end)
if ((flag= (int) sort_order[*a++] - (int) sort_order[*b++]))
@@ -470,7 +679,7 @@ int _mi_compare_text(CHARSET_INFO *charset_info, uchar *a, uint a_length,
static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length,
- my_bool part_key)
+ my_bool part_key)
{
uint length= min(a_length,b_length);
uchar *end= a+ length;
@@ -485,19 +694,19 @@ static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length,
}
- /*
- ** 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 splited
- ** If flag <> SEARCH_FIND compare also position
- */
+ /*
+ ** Compare two keys
+ ** Returns <0, 0, >0 acording to which is bigger
+ ** Key_length specifies length of key to use. Number-keys can't
+ ** be splited
+ ** If flag <> SEARCH_FIND compare also position
+ */
#define FCMP(A,B) ((int) (A) - (int) (B))
int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a,
- register uchar *b, uint key_length, uint nextflag,
- uint *diff_pos)
+ register uchar *b, uint key_length, uint nextflag,
+ uint *diff_pos)
{
int flag;
int16 s_1,s_2;
@@ -507,129 +716,134 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a,
double d_1,d_2;
uint next_key_length;
- if (!(nextflag & (SEARCH_FIND | SEARCH_NO_FIND | SEARCH_LAST)))
- key_length=USE_WHOLE_KEY;
*diff_pos=0;
-
for ( ; (int) key_length >0 ; key_length=next_key_length, keyseg++)
{
uchar *end;
+ uint piks=! (keyseg->flag & HA_NO_SORT);
(*diff_pos)++;
/* Handle NULL part */
if (keyseg->null_bit)
{
key_length--;
- if (*a != *b)
+ if (*a != *b && piks)
{
- flag = (int) *a - (int) *b;
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ flag = (int) *a - (int) *b;
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
}
b++;
- if (!*a++) /* If key was NULL */
+ if (!*a++) /* If key was NULL */
{
- if (nextflag == (SEARCH_FIND | SEARCH_UPDATE))
- nextflag=SEARCH_SAME; /* Allow duplicate keys */
- next_key_length=key_length;
- continue; /* To next key part */
+ if (nextflag == (SEARCH_FIND | SEARCH_UPDATE))
+ nextflag=SEARCH_SAME; /* Allow duplicate keys */
+ next_key_length=key_length;
+ continue; /* To next key part */
}
}
end= a+ min(keyseg->length,key_length);
next_key_length=key_length-keyseg->length;
switch ((enum ha_base_keytype) keyseg->type) {
- case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */
+ case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */
if (keyseg->flag & HA_SPACE_PACK)
{
- int a_length,b_length,pack_length;
- get_key_length(a_length,a);
- get_key_pack_length(b_length,pack_length,b);
- next_key_length=key_length-b_length-pack_length;
-
- if ((flag=_mi_compare_text(keyseg->charset,a,a_length,b,b_length,
- (my_bool) ((nextflag & SEARCH_PREFIX) &&
- next_key_length <= 0))))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
- a+=a_length;
- b+=b_length;
- break;
+ int a_length,b_length,pack_length;
+ get_key_length(a_length,a);
+ get_key_pack_length(b_length,pack_length,b);
+ next_key_length=key_length-b_length-pack_length;
+
+ if (piks &&
+ (flag=_mi_compare_text(keyseg->charset,a,a_length,b,b_length,
+ (my_bool) ((nextflag & SEARCH_PREFIX) && next_key_length <= 0))))
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ a+=a_length;
+ b+=b_length;
+ break;
}
else
{
- uint length=(uint) (end-a);
- if ((flag=_mi_compare_text(keyseg->charset,a,length,b,length,
- (my_bool) ((nextflag & SEARCH_PREFIX) &&
- next_key_length <= 0))))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
- a=end;
- b+=length;
+ uint length=(uint) (end-a), a_length=length, b_length=length;
+ if (!(nextflag & SEARCH_PREFIX))
+ {
+ while (a_length && a[a_length-1] == ' ')
+ a_length--;
+ while (b_length && b[b_length-1] == ' ')
+ b_length--;
+ }
+ if (piks &&
+ (flag=_mi_compare_text(keyseg->charset,a,a_length,b,b_length,
+ (my_bool) ((nextflag & SEARCH_PREFIX) && next_key_length <= 0))))
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ a=end;
+ b+=length;
}
break;
case HA_KEYTYPE_BINARY:
if (keyseg->flag & HA_SPACE_PACK)
{
- int a_length,b_length,pack_length;
- get_key_length(a_length,a);
- get_key_pack_length(b_length,pack_length,b);
- next_key_length=key_length-b_length-pack_length;
-
- if ((flag=compare_bin(a,a_length,b,b_length,
- (my_bool) ((nextflag & SEARCH_PREFIX) &&
- next_key_length <= 0))))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
- a+=a_length;
- b+=b_length;
- break;
+ int a_length,b_length,pack_length;
+ get_key_length(a_length,a);
+ get_key_pack_length(b_length,pack_length,b);
+ next_key_length=key_length-b_length-pack_length;
+
+ if (piks &&
+ (flag=compare_bin(a,a_length,b,b_length,
+ (my_bool) ((nextflag & SEARCH_PREFIX) && next_key_length <= 0))))
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ a+=a_length;
+ b+=b_length;
+ break;
}
else
{
- uint length=keyseg->length;
- if ((flag=compare_bin(a,length,b,length,
- (my_bool) ((nextflag & SEARCH_PREFIX) &&
- next_key_length <= 0))))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
- a+=length;
- b+=length;
+ uint length=keyseg->length;
+ if (piks &&
+ (flag=compare_bin(a,length,b,length,
+ (my_bool) ((nextflag & SEARCH_PREFIX) && next_key_length <= 0))))
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ a+=length;
+ b+=length;
}
break;
case HA_KEYTYPE_VARTEXT:
{
- int a_length,b_length,pack_length;
- get_key_length(a_length,a);
- get_key_pack_length(b_length,pack_length,b);
- next_key_length=key_length-b_length-pack_length;
-
- if ((flag=_mi_compare_text(keyseg->charset,a,a_length,b,b_length,
- (my_bool) ((nextflag & SEARCH_PREFIX) &&
- next_key_length <= 0))))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
- a+=a_length;
- b+=b_length;
- break;
+ int a_length,b_length,pack_length;
+ get_key_length(a_length,a);
+ get_key_pack_length(b_length,pack_length,b);
+ next_key_length=key_length-b_length-pack_length;
+
+ if (piks &&
+ (flag=_mi_compare_text(keyseg->charset,a,a_length,b,b_length,
+ (my_bool) ((nextflag & SEARCH_PREFIX) && next_key_length <= 0))))
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ a+=a_length;
+ b+=b_length;
+ break;
}
break;
case HA_KEYTYPE_VARBINARY:
{
- int a_length,b_length,pack_length;
- get_key_length(a_length,a);
- get_key_pack_length(b_length,pack_length,b);
- next_key_length=key_length-b_length-pack_length;
-
- if ((flag=compare_bin(a,a_length,b,b_length,
- (my_bool) ((nextflag & SEARCH_PREFIX) &&
- next_key_length <= 0))))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
- a+=a_length;
- b+=b_length;
- break;
+ int a_length,b_length,pack_length;
+ get_key_length(a_length,a);
+ get_key_pack_length(b_length,pack_length,b);
+ next_key_length=key_length-b_length-pack_length;
+
+ if (piks &&
+ (flag=compare_bin(a,a_length,b,b_length,
+ (my_bool) ((nextflag & SEARCH_PREFIX) && next_key_length <= 0))))
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ a+=a_length;
+ b+=b_length;
+ break;
}
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->flag & HA_REVERSE_SORT) ? -flag : flag);
+ if (piks && (flag = CMP_NUM(i_1,i_2)))
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b++;
break;
@@ -637,125 +851,132 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a,
case HA_KEYTYPE_SHORT_INT:
s_1= mi_sint2korr(a);
s_2= mi_sint2korr(b);
- if ((flag = CMP(s_1,s_2)))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ if (piks && (flag = CMP_NUM(s_1,s_2)))
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+= 2; /* sizeof(short int); */
break;
case HA_KEYTYPE_USHORT_INT:
{
- uint16 us_1,us_2;
- us_1= mi_sint2korr(a);
- us_2= mi_sint2korr(b);
- if ((flag = CMP(us_1,us_2)))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
- a= end;
- b+=2; /* sizeof(short int); */
- break;
+ uint16 us_1,us_2;
+ us_1= mi_sint2korr(a);
+ us_2= mi_sint2korr(b);
+ if (piks && (flag = CMP_NUM(us_1,us_2)))
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ a= end;
+ b+=2; /* sizeof(short int); */
+ break;
}
case HA_KEYTYPE_LONG_INT:
l_1= mi_sint4korr(a);
l_2= mi_sint4korr(b);
- if ((flag = CMP(l_1,l_2)))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ if (piks && (flag = CMP_NUM(l_1,l_2)))
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+= 4; /* sizeof(long int); */
break;
case HA_KEYTYPE_ULONG_INT:
u_1= mi_sint4korr(a);
u_2= mi_sint4korr(b);
- if ((flag = CMP(u_1,u_2)))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ if (piks && (flag = CMP_NUM(u_1,u_2)))
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+= 4; /* sizeof(long int); */
break;
case HA_KEYTYPE_INT24:
l_1=mi_sint3korr(a);
l_2=mi_sint3korr(b);
- if ((flag = CMP(l_1,l_2)))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ if (piks && (flag = CMP_NUM(l_1,l_2)))
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+= 3;
break;
case HA_KEYTYPE_UINT24:
l_1=mi_uint3korr(a);
l_2=mi_uint3korr(b);
- if ((flag = CMP(l_1,l_2)))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ if (piks && (flag = CMP_NUM(l_1,l_2)))
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+= 3;
break;
case HA_KEYTYPE_FLOAT:
mi_float4get(f_1,a);
mi_float4get(f_2,b);
- if ((flag = CMP(f_1,f_2)))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ if (piks && (flag = CMP_NUM(f_1,f_2)))
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+= 4; /* sizeof(float); */
break;
case HA_KEYTYPE_DOUBLE:
mi_float8get(d_1,a);
mi_float8get(d_2,b);
- if ((flag = CMP(d_1,d_2)))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ if (piks && (flag = CMP_NUM(d_1,d_2)))
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+= 8; /* sizeof(double); */
break;
- case HA_KEYTYPE_NUM: /* Numeric key */
+ case HA_KEYTYPE_NUM: /* Numeric key */
{
int swap_flag= 0;
int alength,blength;
-
+
if (keyseg->flag & HA_REVERSE_SORT)
{
- swap(uchar*,a,b);
- swap_flag=1; /* Remember swap of a & b */
+ swap(uchar*,a,b);
+ swap_flag=1; /* Remember swap of a & b */
end= a+ (int) (end-b);
}
if (keyseg->flag & HA_SPACE_PACK)
{
- alength= *a++; blength= *b++;
- end=a+alength;
- next_key_length=key_length-blength-1;
+ alength= *a++; blength= *b++;
+ end=a+alength;
+ next_key_length=key_length-blength-1;
}
else
{
- alength= (int) (end-a);
- blength=keyseg->length;
- /* remove pre space from keys */
- for ( ; alength && *a == ' ' ; a++, alength--) ;
- for ( ; blength && *b == ' ' ; b++, blength--) ;
+ alength= (int) (end-a);
+ blength=keyseg->length;
+ /* remove pre space from keys */
+ for ( ; alength && *a == ' ' ; a++, alength--) ;
+ for ( ; blength && *b == ' ' ; b++, blength--) ;
}
-
- if (*a == '-')
+ if (piks)
{
- if (*b != '-')
- return -1;
- a++; b++;
- swap(uchar*,a,b);
- swap(int,alength,blength);
- swap_flag=1-swap_flag;
- alength--; blength--;
- end=a+alength;
+ if (*a == '-')
+ {
+ if (*b != '-')
+ return -1;
+ a++; b++;
+ swap(uchar*,a,b);
+ swap(int,alength,blength);
+ swap_flag=1-swap_flag;
+ alength--; blength--;
+ end=a+alength;
+ }
+ else if (*b == '-')
+ return 1;
+ while (alength && (*a == '+' || *a == '0'))
+ {
+ a++; alength--;
+ }
+ while (blength && (*b == '+' || *b == '0'))
+ {
+ b++; blength--;
+ }
+ if (alength != blength)
+ return (alength < blength) ? -1 : 1;
+ while (a < end)
+ if (*a++ != *b++)
+ return ((int) a[-1] - (int) b[-1]);
}
- else if (*b == '-')
- return 1;
- while (alength && (*a == '+' || *a == '0'))
- {
- a++; alength--;
- }
- while (blength && (*b == '+' || *b == '0'))
+ else
{
- b++; blength--;
+ b+=(end-a);
+ a=end;
}
- if (alength != blength)
- return (alength < blength) ? -1 : 1;
- while (a < end)
- if (*a++ != *b++)
- return ((int) a[-1] - (int) b[-1]);
-
- if (swap_flag) /* Restore pointers */
- swap(uchar*,a,b);
+
+ if (swap_flag) /* Restore pointers */
+ swap(uchar*,a,b);
break;
}
#ifdef HAVE_LONG_LONG
@@ -764,8 +985,8 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a,
longlong ll_a,ll_b;
ll_a= mi_sint8korr(a);
ll_b= mi_sint8korr(b);
- if ((flag = CMP(ll_a,ll_b)))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ if (piks && (flag = CMP_NUM(ll_a,ll_b)))
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+= 8;
break;
@@ -775,15 +996,15 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a,
ulonglong ll_a,ll_b;
ll_a= mi_uint8korr(a);
ll_b= mi_uint8korr(b);
- if ((flag = CMP(ll_a,ll_b)))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ if (piks && (flag = CMP_NUM(ll_a,ll_b)))
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+= 8;
break;
}
#endif
- case HA_KEYTYPE_END: /* Ready */
- goto end; /* diff_pos is incremented */
+ case HA_KEYTYPE_END: /* Ready */
+ goto end; /* diff_pos is incremented */
}
}
(*diff_pos)++;
@@ -798,33 +1019,33 @@ end:
{
if (*a++ != *b++)
{
- flag= FCMP(a[-1],b[-1]);
- break;
+ flag= FCMP(a[-1],b[-1]);
+ break;
}
}
if (nextflag & SEARCH_SAME)
- return (flag); /* read same */
+ return (flag); /* read same */
if (nextflag & SEARCH_BIGGER)
- return (flag <= 0 ? -1 : 1); /* read next */
- return (flag < 0 ? -1 : 1); /* read previous */
+ return (flag <= 0 ? -1 : 1); /* read next */
+ return (flag < 0 ? -1 : 1); /* read previous */
}
return 0;
} /* _mi_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 */
+ /* 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 */
- /* same as _mi_get_key but used with fixed length keys */
+ /* same as _mi_get_key but used with fixed length keys */
uint _mi_get_static_key(register MI_KEYDEF *keyinfo, uint nod_flag,
- register uchar **page, register uchar *key)
+ register uchar **page, register uchar *key)
{
memcpy((byte*) key,(byte*) *page,
- (size_t) (keyinfo->keylength+nod_flag));
+ (size_t) (keyinfo->keylength+nod_flag));
*page+=keyinfo->keylength+nod_flag;
return(keyinfo->keylength);
} /* _mi_get_static_key */
@@ -833,7 +1054,7 @@ uint _mi_get_static_key(register MI_KEYDEF *keyinfo, uint nod_flag,
/* Key with is packed against previous key or key with a NULL column */
uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
- register uchar **page_pos, register uchar *key)
+ register uchar **page_pos, register uchar *key)
{
reg1 MI_KEYSEG *keyseg;
uchar *start_key,*page=*page_pos;
@@ -849,11 +1070,11 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
uint packed= *page & 128,tot_length,rest_length;
if (keyseg->length >= 127)
{
- length=mi_uint2korr(page) & 32767;
- page+=2;
+ length=mi_uint2korr(page) & 32767;
+ page+=2;
}
else
- length= *page++ & 127;
+ length= *page++ & 127;
if (packed)
{
@@ -914,23 +1135,23 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
}
else
{
- if (keyseg->flag & HA_NULL_PART)
- {
- if (!length--) /* Null part */
- {
- *key++=0;
- continue;
- }
- *key++=1; /* Not null */
- }
+ if (keyseg->flag & HA_NULL_PART)
+ {
+ if (!length--) /* Null part */
+ {
+ *key++=0;
+ continue;
+ }
+ *key++=1; /* Not null */
+ }
}
if (length > (uint) keyseg->length)
{
- DBUG_PRINT("error",("Found too long packed key: %d of %d at %lx",
- length, keyseg->length, *page_pos));
- DBUG_DUMP("key",(char*) *page_pos,16);
- my_errno=HA_ERR_CRASHED;
- return 0; /* Error */
+ DBUG_PRINT("error",("Found too long packed key: %d of %d at %lx",
+ length, keyseg->length, *page_pos));
+ DBUG_DUMP("key",(char*) *page_pos,16);
+ my_errno=HA_ERR_CRASHED;
+ return 0; /* Error */
}
store_key_length_inc(key,length);
}
@@ -938,18 +1159,18 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
{
if (keyseg->flag & HA_NULL_PART)
{
- if (!(*key++ = *page++))
- continue;
+ if (!(*key++ = *page++))
+ continue;
}
if (keyseg->flag &
- (HA_VAR_LENGTH | HA_BLOB_PART | HA_SPACE_PACK))
+ (HA_VAR_LENGTH | HA_BLOB_PART | HA_SPACE_PACK))
{
- uchar *tmp=page;
- get_key_length(length,tmp);
- length+=(uint) (tmp-page);
+ uchar *tmp=page;
+ get_key_length(length,tmp);
+ length+=(uint) (tmp-page);
}
else
- length=keyseg->length;
+ length=keyseg->length;
}
memcpy((byte*) key,(byte*) page,(size_t) length);
key+=length;
@@ -966,7 +1187,7 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
/* key that is packed relatively to previous */
uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
- register uchar **page_pos, register uchar *key)
+ register uchar **page_pos, register uchar *key)
{
reg1 MI_KEYSEG *keyseg;
uchar *start_key,*page=*page_pos,*page_end,*from,*from_end;
@@ -981,16 +1202,16 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
if (length > keyinfo->maxlength)
{
DBUG_PRINT("error",("Found too long binary packed key: %d of %d at %lx",
- length, keyinfo->maxlength, *page_pos));
+ length, keyinfo->maxlength, *page_pos));
DBUG_DUMP("key",(char*) *page_pos,16);
my_errno=HA_ERR_CRASHED;
- return 0; /* Wrong key */
+ return 0; /* Wrong key */
}
from=key; from_end=key+length;
}
else
{
- from=page; from_end=page_end; /* Not packed key */
+ from=page; from_end=page_end; /* Not packed key */
}
/*
@@ -1004,7 +1225,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
{
if (from == from_end) { from=page; from_end=page_end; }
if (!(*key++ = *from++))
- continue; /* Null part */
+ continue; /* Null part */
}
if (keyseg->flag & (HA_VAR_LENGTH | HA_BLOB_PART | HA_SPACE_PACK))
{
@@ -1012,10 +1233,10 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
if (from == from_end) { from=page; from_end=page_end; }
if ((length= (*key++ = *from++)) == 255)
{
- if (from == from_end) { from=page; from_end=page_end; }
- length= (uint) ((*key++ = *from++)) << 8;
- if (from == from_end) { from=page; from_end=page_end; }
- length+= (uint) ((*key++ = *from++));
+ if (from == from_end) { from=page; from_end=page_end; }
+ length= (uint) ((*key++ = *from++)) << 8;
+ if (from == from_end) { from=page; from_end=page_end; }
+ length+= (uint) ((*key++ = *from++));
}
}
else
@@ -1023,7 +1244,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
if ((tmp=(uint) (from_end-from)) <= length)
{
- key+=tmp; /* Use old key */
+ key+=tmp; /* Use old key */
length-=tmp;
from=page; from_end=page_end;
}
@@ -1034,7 +1255,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
length=keyseg->length+nod_flag;
if ((tmp=(uint) (from_end-from)) <= length)
{
- memcpy(key+tmp,page,length-tmp); /* Get last part of key */
+ memcpy(key+tmp,page,length-tmp); /* Get last part of key */
*page_pos= page+length-tmp;
}
else
@@ -1043,7 +1264,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
{
DBUG_PRINT("error",("Error when unpacking key"));
my_errno=HA_ERR_CRASHED;
- return 0; /* Error */
+ return 0; /* Error */
}
memcpy((byte*) key,(byte*) from,(size_t) length);
*page_pos= from+length;
@@ -1052,11 +1273,11 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
}
- /* Get key at position without knowledge of previous key */
- /* Returns pointer to next key */
+ /* Get key at position without knowledge of previous key */
+ /* Returns pointer to next key */
uchar *_mi_get_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
- uchar *key, uchar *keypos, uint *return_key_length)
+ uchar *key, uchar *keypos, uint *return_key_length)
{
uint nod_flag;
DBUG_ENTER("_mi_get_key");
@@ -1070,14 +1291,14 @@ uchar *_mi_get_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
else
{
page+=2+nod_flag;
- key[0]=0; /* safety */
+ key[0]=0; /* safety */
while (page <= keypos)
{
*return_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,key);
if (*return_key_length == 0)
{
- my_errno=HA_ERR_CRASHED;
- DBUG_RETURN(0);
+ my_errno=HA_ERR_CRASHED;
+ DBUG_RETURN(0);
}
}
}
@@ -1086,12 +1307,12 @@ uchar *_mi_get_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
} /* _mi_get_key */
- /* Get key at position without knowledge of previous key */
- /* Returns 0 if ok */
+ /* Get key at position without knowledge of previous key */
+ /* Returns 0 if ok */
static my_bool _mi_get_prev_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
- uchar *key, uchar *keypos,
- uint *return_key_length)
+ uchar *key, uchar *keypos,
+ uint *return_key_length)
{
uint nod_flag;
DBUG_ENTER("_mi_get_prev_key");
@@ -1101,20 +1322,20 @@ static my_bool _mi_get_prev_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
{
*return_key_length=keyinfo->keylength;
bmove((byte*) key,(byte*) keypos- *return_key_length-nod_flag,
- *return_key_length);
+ *return_key_length);
DBUG_RETURN(0);
}
else
{
page+=2+nod_flag;
- key[0]=0; /* safety */
+ key[0]=0; /* safety */
while (page < keypos)
{
*return_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,key);
if (*return_key_length == 0)
{
- my_errno=HA_ERR_CRASHED;
- DBUG_RETURN(1);
+ my_errno=HA_ERR_CRASHED;
+ DBUG_RETURN(1);
}
}
}
@@ -1123,11 +1344,11 @@ static my_bool _mi_get_prev_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
- /* Get last key from key-page */
- /* Return pointer to where key starts */
+ /* Get last key from key-page */
+ /* Return pointer to where key starts */
uchar *_mi_get_last_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
- uchar *lastkey, uchar *endpos, uint *return_key_length)
+ uchar *lastkey, uchar *endpos, uint *return_key_length)
{
uint nod_flag;
uchar *lastpos;
@@ -1152,9 +1373,9 @@ uchar *_mi_get_last_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
*return_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,lastkey);
if (*return_key_length == 0)
{
- DBUG_PRINT("error",("Couldn't find last key: page: %lx",page));
- my_errno=HA_ERR_CRASHED;
- DBUG_RETURN(0);
+ DBUG_PRINT("error",("Couldn't find last key: page: %lx",page));
+ my_errno=HA_ERR_CRASHED;
+ DBUG_RETURN(0);
}
}
}
@@ -1163,7 +1384,7 @@ uchar *_mi_get_last_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
} /* _mi_get_last_key */
- /* Calculate length of key */
+ /* Calculate length of key */
uint _mi_keylength(MI_KEYDEF *keyinfo, register uchar *key)
{
@@ -1178,7 +1399,7 @@ uint _mi_keylength(MI_KEYDEF *keyinfo, register uchar *key)
{
if (keyseg->flag & HA_NULL_PART)
if (!*key++)
- continue;
+ continue;
if (keyseg->flag & (HA_SPACE_PACK | HA_BLOB_PART | HA_VAR_LENGTH))
{
uint length;
@@ -1192,28 +1413,28 @@ uint _mi_keylength(MI_KEYDEF *keyinfo, register uchar *key)
} /* _mi_keylength */
- /* Move a key */
+ /* Move a key */
uchar *_mi_move_key(MI_KEYDEF *keyinfo, uchar *to, uchar *from)
{
reg1 uint length;
memcpy((byte*) to, (byte*) from,
- (size_t) (length=_mi_keylength(keyinfo,from)));
+ (size_t) (length=_mi_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 */
+ /* Find next/previous record with same key */
+ /* This can't be used when database is touched after last read */
int _mi_search_next(register MI_INFO *info, register MI_KEYDEF *keyinfo,
- uchar *key, uint key_length, uint nextflag, my_off_t pos)
+ uchar *key, uint key_length, uint nextflag, my_off_t pos)
{
int error;
uint nod_flag;
uchar lastkey[MI_MAX_KEY_BUFF];
DBUG_ENTER("_mi_search_next");
DBUG_PRINT("enter",("nextflag: %d lastpos: %ld int_keypos: %lx",
- nextflag,(long) info->lastpos,info->int_keypos));
+ nextflag,(long) info->lastpos,info->int_keypos));
DBUG_EXECUTE("key",_mi_print_key(DBUG_FILE,keyinfo->seg,key,key_length););
/* Force full read if we are at last key or if we are not on a leaf
@@ -1227,51 +1448,53 @@ int _mi_search_next(register MI_INFO *info, register MI_KEYDEF *keyinfo,
info->page_changed ||
(info->int_keytree_version != keyinfo->version &&
(info->int_nod_flag || info->buff_used)))
- DBUG_RETURN(_mi_search(info,keyinfo,key,key_length,
- nextflag | SEARCH_SAVE_BUFF, pos));
+ DBUG_RETURN(_mi_search(info,keyinfo,key, USE_WHOLE_KEY,
+ nextflag | SEARCH_SAVE_BUFF, pos));
if (info->buff_used)
{
if (!_mi_fetch_keypage(info,keyinfo,info->last_search_keypage,
- info->buff,0))
+ info->buff,0))
DBUG_RETURN(-1);
info->buff_used=0;
}
/* Last used buffer is in info->buff */
nod_flag=mi_test_if_nod(info->buff);
- memcpy(lastkey,key,key_length);
- if (nextflag & SEARCH_BIGGER) /* Next key */
+ if (nextflag & SEARCH_BIGGER) /* Next key */
{
my_off_t tmp_pos=_mi_kpos(nod_flag,info->int_keypos);
if (tmp_pos != HA_OFFSET_ERROR)
{
- if ((error=_mi_search(info,keyinfo,key,key_length,
- nextflag | SEARCH_SAVE_BUFF, tmp_pos)) <=0)
- DBUG_RETURN(error);
+ if ((error=_mi_search(info,keyinfo,key, USE_WHOLE_KEY,
+ nextflag | SEARCH_SAVE_BUFF, tmp_pos)) <=0)
+ DBUG_RETURN(error);
}
+ memcpy(lastkey,key,key_length);
if (!(info->lastkey_length=(*keyinfo->get_key)(keyinfo,nod_flag,
- &info->int_keypos,lastkey)))
+ &info->int_keypos,lastkey)))
DBUG_RETURN(-1);
}
- else /* Previous key */
+ else /* Previous key */
{
uint length;
/* Find start of previous key */
info->int_keypos=_mi_get_last_key(info,keyinfo,info->buff,lastkey,
- info->int_keypos, &length);
+ info->int_keypos, &length);
if (!info->int_keypos)
DBUG_RETURN(-1);
if (info->int_keypos == info->buff+2)
- DBUG_RETURN(_mi_search(info,keyinfo,key,key_length,
- nextflag | SEARCH_SAVE_BUFF, pos));
- if ((error=_mi_search(info,keyinfo,key,0,nextflag | SEARCH_SAVE_BUFF,
- _mi_kpos(nod_flag,info->int_keypos))) <= 0)
+ DBUG_RETURN(_mi_search(info,keyinfo,key, USE_WHOLE_KEY,
+ nextflag | SEARCH_SAVE_BUFF, pos));
+ if ((error=_mi_search(info,keyinfo,key, USE_WHOLE_KEY,
+ nextflag | SEARCH_SAVE_BUFF,
+ _mi_kpos(nod_flag,info->int_keypos))) <= 0)
DBUG_RETURN(error);
+ /* QQ: We should be able to optimize away the following call */
if (! _mi_get_last_key(info,keyinfo,info->buff,lastkey,
- info->int_keypos,&info->lastkey_length))
+ info->int_keypos,&info->lastkey_length))
DBUG_RETURN(-1);
}
memcpy(info->lastkey,lastkey,info->lastkey_length);
@@ -1281,11 +1504,11 @@ int _mi_search_next(register MI_INFO *info, register MI_KEYDEF *keyinfo,
} /* _mi_search_next */
- /* Search after position for the first row in an index */
- /* This is stored in info->lastpos */
+ /* Search after position for the first row in an index */
+ /* This is stored in info->lastpos */
int _mi_search_first(register MI_INFO *info, register MI_KEYDEF *keyinfo,
- register my_off_t pos)
+ register my_off_t pos)
{
uint nod_flag;
uchar *page;
@@ -1310,7 +1533,7 @@ int _mi_search_first(register MI_INFO *info, register MI_KEYDEF *keyinfo,
} while ((pos=_mi_kpos(nod_flag,page)) != HA_OFFSET_ERROR);
info->lastkey_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,
- info->lastkey);
+ info->lastkey);
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;
@@ -1323,11 +1546,11 @@ int _mi_search_first(register MI_INFO *info, register MI_KEYDEF *keyinfo,
} /* _mi_search_first */
- /* Search after position for the last row in an index */
- /* This is stored in info->lastpos */
+ /* Search after position for the last row in an index */
+ /* This is stored in info->lastpos */
int _mi_search_last(register MI_INFO *info, register MI_KEYDEF *keyinfo,
- register my_off_t pos)
+ register my_off_t pos)
{
uint nod_flag;
uchar *buff,*page;
@@ -1335,7 +1558,7 @@ int _mi_search_last(register MI_INFO *info, register MI_KEYDEF *keyinfo,
if (pos == HA_OFFSET_ERROR)
{
- my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
+ my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
info->lastpos= HA_OFFSET_ERROR;
DBUG_RETURN(-1);
}
@@ -1353,7 +1576,7 @@ int _mi_search_last(register MI_INFO *info, register MI_KEYDEF *keyinfo,
} while ((pos=_mi_kpos(nod_flag,page)) != HA_OFFSET_ERROR);
if (!_mi_get_last_key(info,keyinfo,buff,info->lastkey,page,
- &info->lastkey_length))
+ &info->lastkey_length))
DBUG_RETURN(-1);
info->lastpos=_mi_dpos(info,0,info->lastkey+info->lastkey_length);
info->int_keypos=info->int_maxpos=page;
@@ -1373,22 +1596,22 @@ int _mi_search_last(register MI_INFO *info, register MI_KEYDEF *keyinfo,
** Functions to store and pack a key in a page
**
** mi_calc_xx_key_length takes the following arguments:
-** nod_flag If nod: Length of nod-pointer
-** next_key Position to pos after the new key in buffer
-** org_key Key that was before the next key in buffer
-** prev_key Last key before current key
-** key Key that will be stored
-** s_temp Information how next key will be packed
+** nod_flag If nod: Length of nod-pointer
+** next_key Position to pos after the new key in buffer
+** org_key Key that was before the next key in buffer
+** prev_key Last key before current key
+** key Key that will be stored
+** s_temp Information how next key will be packed
****************************************************************************/
/* Static length key */
int
_mi_calc_static_key_length(MI_KEYDEF *keyinfo,uint nod_flag,
- uchar *next_pos __attribute__((unused)),
- uchar *org_key __attribute__((unused)),
- uchar *prev_key __attribute__((unused)),
- uchar *key, MI_KEY_PARAM *s_temp)
+ uchar *next_pos __attribute__((unused)),
+ uchar *org_key __attribute__((unused)),
+ uchar *prev_key __attribute__((unused)),
+ uchar *key, MI_KEY_PARAM *s_temp)
{
s_temp->key=key;
return (int) (s_temp->totlength=keyinfo->keylength+nod_flag);
@@ -1398,10 +1621,10 @@ _mi_calc_static_key_length(MI_KEYDEF *keyinfo,uint nod_flag,
int
_mi_calc_var_key_length(MI_KEYDEF *keyinfo,uint nod_flag,
- uchar *next_pos __attribute__((unused)),
- uchar *org_key __attribute__((unused)),
- uchar *prev_key __attribute__((unused)),
- uchar *key, MI_KEY_PARAM *s_temp)
+ uchar *next_pos __attribute__((unused)),
+ uchar *org_key __attribute__((unused)),
+ uchar *prev_key __attribute__((unused)),
+ uchar *key, MI_KEY_PARAM *s_temp)
{
s_temp->key=key;
return (int) (s_temp->totlength=_mi_keylength(keyinfo,key)+nod_flag);
@@ -1416,10 +1639,10 @@ _mi_calc_var_key_length(MI_KEYDEF *keyinfo,uint nod_flag,
If the max length of first key segment <= 127 characters the prefix is
1 byte else it's 2 byte
- prefix byte The high bit is set if this is a prefix for the prev key
- length Packed length if the previous was a prefix byte
- [length] Length character of data
- next-key-seg Next key segments
+ prefix byte The high bit is set if this is a prefix for the prev key
+ length Packed length if the previous was a prefix byte
+ [length] Length character of data
+ next-key-seg Next key segments
If the first segment can have NULL:
The length is 0 for NULLS and 1+length for not null columns.
@@ -1428,8 +1651,8 @@ _mi_calc_var_key_length(MI_KEYDEF *keyinfo,uint nod_flag,
int
_mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
- uchar *org_key, uchar *prev_key, uchar *key,
- MI_KEY_PARAM *s_temp)
+ uchar *org_key, uchar *prev_key, uchar *key,
+ MI_KEY_PARAM *s_temp)
{
reg1 MI_KEYSEG *keyseg;
int length;
@@ -1470,15 +1693,15 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
s_temp->key=key;
s_temp->ref_length=s_temp->key_length=0;
s_temp->totlength=key_length-1+diff_flag;
- s_temp->next_key_pos=0; /* No next key */
+ s_temp->next_key_pos=0; /* No next key */
return (s_temp->totlength);
}
s_temp->store_not_null=1;
- key_length--; /* We don't store NULL */
+ key_length--; /* We don't store NULL */
if (prev_key && !*prev_key++)
- org_key=prev_key=0; /* Can't pack against prev */
+ org_key=prev_key=0; /* Can't pack against prev */
else if (org_key)
- org_key++; /* Skipp NULL */
+ org_key++; /* Skipp NULL */
}
else
s_temp->store_not_null=0;
@@ -1494,14 +1717,14 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
if (prev_key)
{
get_key_length(org_key_length,prev_key);
- s_temp->prev_key=prev_key; /* Pointer at data */
+ s_temp->prev_key=prev_key; /* Pointer at data */
/* Don't use key-pack if length == 0 */
if (new_key_length && new_key_length == org_key_length)
same_length=1;
else if (new_key_length > org_key_length)
end=key + org_key_length;
- if (sort_order) /* SerG */
+ if (sort_order) /* SerG */
{
while (key < end && sort_order[*key] == sort_order[*prev_key])
{
@@ -1512,7 +1735,7 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
{
while (key < end && *key == *prev_key)
{
- key++; prev_key++;
+ key++; prev_key++;
}
}
}
@@ -1527,15 +1750,15 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
length=(int) key_length-(int) (key_end-start)-length_pack;
length+= diff_flag;
if (next_key)
- { /* Can't combine with next */
- s_temp->n_length= *next_key; /* Needed by _mi_store_key */
+ { /* Can't combine with next */
+ s_temp->n_length= *next_key; /* Needed by _mi_store_key */
next_key=0;
}
}
else
{
if (start != key)
- { /* Starts as prev key */
+ { /* Starts as prev key */
ref_length= (uint) (key-start);
s_temp->ref_length= ref_length + pack_marker;
length= (int) (key_length - ref_length);
@@ -1546,16 +1769,16 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
}
else
{
- s_temp->key_length+=s_temp->store_not_null; /* If null */
+ s_temp->key_length+=s_temp->store_not_null; /* If null */
length= key_length - length_pack+ diff_flag;
}
}
s_temp->totlength=(uint) length;
s_temp->prev_length=0;
DBUG_PRINT("test",("tot_length: %d length: %d uniq_key_length: %d",
- key_length,length,s_temp->key_length));
+ key_length,length,s_temp->key_length));
- /* If something after that hasn't length=0, test if we can combine */
+ /* If something after that hasn't length=0, test if we can combine */
if ((s_temp->next_key_pos=next_key))
{
uint packed,n_length;
@@ -1571,134 +1794,134 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
if (!packed)
n_length-= s_temp->store_not_null;
- if (n_length || packed) /* Don't pack 0 length keys */
+ if (n_length || packed) /* Don't pack 0 length keys */
{
uint next_length_pack, new_ref_length=s_temp->ref_length;
if (packed)
{
- /* If first key and next key is packed (only on delete) */
- if (!prev_key && org_key)
- {
- get_key_length(org_key_length,org_key);
- key=start;
- if (sort_order) /* SerG */
- {
- while (key < end && sort_order[*key] == sort_order[*org_key])
- {
- key++; org_key++;
- }
- }
- else
- {
- while (key < end && *key == *org_key)
- {
- key++; org_key++;
- }
- }
- if ((new_ref_length= (uint) (key - start)))
- new_ref_length+=pack_marker;
- }
-
- if (!n_length)
- {
- /*
- We put a different key between two identical variable length keys
- Extend next key to have same prefix as this key
- */
- if (new_ref_length) /* prefix of previus key */
- { /* make next key longer */
- s_temp->part_of_prev_key= new_ref_length;
- s_temp->prev_length= org_key_length -
- (new_ref_length-pack_marker);
- s_temp->n_ref_length= s_temp->n_length= s_temp->prev_length;
- n_length= get_pack_length(s_temp->prev_length);
- s_temp->prev_key+= (new_ref_length - pack_marker);
- length+= s_temp->prev_length + n_length;
- }
- else
- { /* Can't use prev key */
- s_temp->part_of_prev_key=0;
- s_temp->prev_length= org_key_length;
- s_temp->n_ref_length=s_temp->n_length= org_key_length;
- length+= org_key_length;
- /* +get_pack_length(org_key_length); */
- }
- return (int) length;
- }
-
- ref_length=n_length;
- get_key_pack_length(n_length,next_length_pack,next_key);
-
- /* Test if new keys has fewer characters that match the previous key */
- if (!new_ref_length)
- { /* Can't use prev key */
- s_temp->part_of_prev_key= 0;
- s_temp->prev_length= ref_length;
- s_temp->n_ref_length= s_temp->n_length= n_length+ref_length;
- /* s_temp->prev_key+= get_pack_length(org_key_length); */
- return (int) length+ref_length-next_length_pack;
- }
- if (ref_length+pack_marker > new_ref_length)
- {
- uint new_pack_length=new_ref_length-pack_marker;
- /* We must copy characters from the original key to the next key */
- s_temp->part_of_prev_key= new_ref_length;
- s_temp->prev_length= ref_length - new_pack_length;
- s_temp->n_ref_length=s_temp->n_length=n_length + s_temp->prev_length;
- s_temp->prev_key+= new_pack_length;
-/* +get_pack_length(org_key_length); */
- length= length-get_pack_length(ref_length)+
- get_pack_length(new_pack_length);
- return (int) length + s_temp->prev_length;
- }
+ /* If first key and next key is packed (only on delete) */
+ if (!prev_key && org_key)
+ {
+ get_key_length(org_key_length,org_key);
+ key=start;
+ if (sort_order) /* SerG */
+ {
+ while (key < end && sort_order[*key] == sort_order[*org_key])
+ {
+ key++; org_key++;
+ }
+ }
+ else
+ {
+ while (key < end && *key == *org_key)
+ {
+ key++; org_key++;
+ }
+ }
+ if ((new_ref_length= (uint) (key - start)))
+ new_ref_length+=pack_marker;
+ }
+
+ if (!n_length)
+ {
+ /*
+ We put a different key between two identical variable length keys
+ Extend next key to have same prefix as this key
+ */
+ if (new_ref_length) /* prefix of previus key */
+ { /* make next key longer */
+ s_temp->part_of_prev_key= new_ref_length;
+ s_temp->prev_length= org_key_length -
+ (new_ref_length-pack_marker);
+ s_temp->n_ref_length= s_temp->n_length= s_temp->prev_length;
+ n_length= get_pack_length(s_temp->prev_length);
+ s_temp->prev_key+= (new_ref_length - pack_marker);
+ length+= s_temp->prev_length + n_length;
+ }
+ else
+ { /* Can't use prev key */
+ s_temp->part_of_prev_key=0;
+ s_temp->prev_length= org_key_length;
+ s_temp->n_ref_length=s_temp->n_length= org_key_length;
+ length+= org_key_length;
+ /* +get_pack_length(org_key_length); */
+ }
+ return (int) length;
+ }
+
+ ref_length=n_length;
+ get_key_pack_length(n_length,next_length_pack,next_key);
+
+ /* Test if new keys has fewer characters that match the previous key */
+ if (!new_ref_length)
+ { /* Can't use prev key */
+ s_temp->part_of_prev_key= 0;
+ s_temp->prev_length= ref_length;
+ s_temp->n_ref_length= s_temp->n_length= n_length+ref_length;
+ /* s_temp->prev_key+= get_pack_length(org_key_length); */
+ return (int) length+ref_length-next_length_pack;
+ }
+ if (ref_length+pack_marker > new_ref_length)
+ {
+ uint new_pack_length=new_ref_length-pack_marker;
+ /* We must copy characters from the original key to the next key */
+ s_temp->part_of_prev_key= new_ref_length;
+ s_temp->prev_length= ref_length - new_pack_length;
+ s_temp->n_ref_length=s_temp->n_length=n_length + s_temp->prev_length;
+ s_temp->prev_key+= new_pack_length;
+/* +get_pack_length(org_key_length); */
+ length= length-get_pack_length(ref_length)+
+ get_pack_length(new_pack_length);
+ return (int) length + s_temp->prev_length;
+ }
}
else
{
- /* Next key wasn't a prefix of previous key */
- ref_length=0;
- next_length_pack=0;
+ /* Next key wasn't a prefix of previous key */
+ ref_length=0;
+ next_length_pack=0;
}
DBUG_PRINT("test",("length: %d next_key: %lx",length,next_key));
{
- uint tmp_length;
- key=(start+=ref_length);
- if (key+n_length < key_end) /* Normalize length based */
- key_end=key+n_length;
- if (sort_order) /* SerG */
- {
+ uint tmp_length;
+ key=(start+=ref_length);
+ if (key+n_length < key_end) /* Normalize length based */
+ key_end=key+n_length;
+ if (sort_order) /* SerG */
+ {
while (key < key_end && sort_order[*key] ==
- sort_order[*next_key])
- {
- key++; next_key++;
- }
- }
- else
- {
- while (key < key_end && *key == *next_key)
- {
- key++; next_key++;
- }
- }
- if (!(tmp_length=(uint) (key-start)))
- { /* Key can't be re-packed */
- s_temp->next_key_pos=0;
- return length;
- }
- ref_length+=tmp_length;
- n_length-=tmp_length;
- length-=tmp_length+next_length_pack; /* We gained these chars */
+ sort_order[*next_key])
+ {
+ key++; next_key++;
+ }
+ }
+ else
+ {
+ while (key < key_end && *key == *next_key)
+ {
+ key++; next_key++;
+ }
+ }
+ if (!(tmp_length=(uint) (key-start)))
+ { /* Key can't be re-packed */
+ s_temp->next_key_pos=0;
+ return length;
+ }
+ ref_length+=tmp_length;
+ n_length-=tmp_length;
+ length-=tmp_length+next_length_pack; /* We gained these chars */
}
if (n_length == 0)
{
- s_temp->n_ref_length=pack_marker; /* Same as prev key */
+ s_temp->n_ref_length=pack_marker; /* Same as prev key */
}
else
{
- s_temp->n_ref_length=ref_length | pack_marker;
- length+= get_pack_length(n_length);
- s_temp->n_length=n_length;
+ s_temp->n_ref_length=ref_length | pack_marker;
+ length+= get_pack_length(n_length);
+ s_temp->n_length=n_length;
}
}
}
@@ -1710,15 +1933,15 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
int
_mi_calc_bin_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
- uchar *org_key, uchar *prev_key, uchar *key,
- MI_KEY_PARAM *s_temp)
+ uchar *org_key, uchar *prev_key, uchar *key,
+ MI_KEY_PARAM *s_temp)
{
uint length,key_length,ref_length;
s_temp->totlength=key_length=_mi_keylength(keyinfo,key)+nod_flag;
s_temp->key=key;
s_temp->prev_key=org_key;
- if (prev_key) /* If not first key in block */
+ if (prev_key) /* If not first key in block */
{
/* pack key against previous key */
/*
@@ -1737,7 +1960,7 @@ _mi_calc_bin_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
s_temp->ref_length=ref_length=0;
length=key_length+1;
}
- if ((s_temp->next_key_pos=next_key)) /* If another key after */
+ if ((s_temp->next_key_pos=next_key)) /* If another key after */
{
/* pack key against next key */
uint next_length,next_length_pack;
@@ -1748,21 +1971,21 @@ _mi_calc_bin_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
{
uchar *end;
for (key= s_temp->key, end=key+next_length ;
- *key == *org_key && key < end;
- key++,org_key++) ;
+ *key == *org_key && key < end;
+ key++,org_key++) ;
ref_length= (uint) (key - s_temp->key);
}
if (next_length > ref_length)
{
/* We put a key with different case between two keys with the same prefix
- Extend next key to have same prefix as
- this key */
+ Extend next key to have same prefix as
+ this key */
s_temp->n_ref_length= ref_length;
s_temp->prev_length= next_length-ref_length;
s_temp->prev_key+= ref_length;
return (int) (length+ s_temp->prev_length - next_length_pack +
- get_pack_length(ref_length));
+ get_pack_length(ref_length));
}
/* Check how many characters are identical to next key */
key= s_temp->key+next_length;
@@ -1770,12 +1993,12 @@ _mi_calc_bin_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
if ((ref_length= (uint) (key - s_temp->key)-1) == next_length)
{
s_temp->next_key_pos=0;
- return length; /* can't pack next key */
+ return length; /* can't pack next key */
}
s_temp->prev_length=0;
s_temp->n_ref_length=ref_length;
return (int) (length-(ref_length - next_length) - next_length_pack +
- get_pack_length(ref_length));
+ get_pack_length(ref_length));
}
return (int) length;
}
@@ -1788,8 +2011,8 @@ _mi_calc_bin_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
/* store key without compression */
void _mi_store_static_key(MI_KEYDEF *keyinfo __attribute__((unused)),
- register uchar *key_pos,
- register MI_KEY_PARAM *s_temp)
+ register uchar *key_pos,
+ register MI_KEY_PARAM *s_temp)
{
memcpy((byte*) key_pos,(byte*) s_temp->key,(size_t) s_temp->totlength);
}
@@ -1803,8 +2026,8 @@ void _mi_store_static_key(MI_KEYDEF *keyinfo __attribute__((unused)),
void _mi_store_var_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)),
- register uchar *key_pos,
- register MI_KEY_PARAM *s_temp)
+ register uchar *key_pos,
+ register MI_KEY_PARAM *s_temp)
{
uint length;
uchar *start;
@@ -1825,9 +2048,9 @@ void _mi_store_var_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)),
store_pack_length(s_temp->pack_marker == 128,key_pos,s_temp->key_length);
}
bmove((byte*) key_pos,(byte*) s_temp->key,
- (length=s_temp->totlength-(uint) (key_pos-start)));
+ (length=s_temp->totlength-(uint) (key_pos-start)));
- if (!s_temp->next_key_pos) /* No following key */
+ if (!s_temp->next_key_pos) /* No following key */
return;
key_pos+=length;
@@ -1837,14 +2060,14 @@ void _mi_store_var_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)),
if (s_temp->part_of_prev_key)
{
store_pack_length(s_temp->pack_marker == 128,key_pos,
- s_temp->part_of_prev_key);
+ s_temp->part_of_prev_key);
store_key_length_inc(key_pos,s_temp->n_length);
}
else
{
s_temp->n_length+= s_temp->store_not_null;
store_pack_length(s_temp->pack_marker == 128,key_pos,
- s_temp->n_length);
+ s_temp->n_length);
}
memcpy(key_pos, s_temp->prev_key, s_temp->prev_length);
}
@@ -1852,7 +2075,7 @@ void _mi_store_var_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)),
{
store_pack_length(s_temp->pack_marker == 128,key_pos,s_temp->n_ref_length);
if (s_temp->n_ref_length == s_temp->pack_marker)
- return; /* Identical key */
+ return; /* Identical key */
store_key_length(key_pos,s_temp->n_length);
}
else
@@ -1866,18 +2089,18 @@ void _mi_store_var_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)),
/* variable length key with prefix compression */
void _mi_store_bin_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)),
- register uchar *key_pos,
- register MI_KEY_PARAM *s_temp)
+ register uchar *key_pos,
+ register MI_KEY_PARAM *s_temp)
{
store_key_length_inc(key_pos,s_temp->ref_length);
memcpy((char*) key_pos,(char*) s_temp->key+s_temp->ref_length,
- (size_t) s_temp->totlength-s_temp->ref_length);
+ (size_t) s_temp->totlength-s_temp->ref_length);
if (s_temp->next_key_pos)
{
key_pos+=(uint) (s_temp->totlength-s_temp->ref_length);
store_key_length_inc(key_pos,s_temp->n_ref_length);
- if (s_temp->prev_length) /* If we must extend key */
+ if (s_temp->prev_length) /* If we must extend key */
{
memcpy(key_pos,s_temp->prev_key,s_temp->prev_length);
}
diff --git a/myisam/mi_static.c b/myisam/mi_static.c
index f790f90ca78..86d7fc38f25 100644
--- a/myisam/mi_static.c
+++ b/myisam/mi_static.c
@@ -1,21 +1,21 @@
/* 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 pisam library. All definied here for easy making of
+ Static variables for MyISAM library. All definied here for easy making of
a shared library
*/
@@ -32,7 +32,7 @@ my_string myisam_log_filename=(char*) "myisam.log";
File myisam_log_file= -1;
uint myisam_quick_table_bits=9;
uint myisam_block_size=MI_KEY_BLOCK_LENGTH; /* Best by test */
-my_bool myisam_flush=0,myisam_delay_key_write=0;
+my_bool myisam_flush=0, myisam_delay_key_write=0, myisam_single_user=0;
#if defined(THREAD) && !defined(DONT_USE_RW_LOCKS)
my_bool myisam_concurrent_insert=1;
#else
@@ -40,7 +40,7 @@ my_bool myisam_concurrent_insert=0;
#endif
my_off_t myisam_max_extra_temp_length= MI_MAX_TEMP_LENGTH;
my_off_t myisam_max_temp_length= MAX_FILE_SIZE;
-
+ulong myisam_bulk_insert_tree_size=8192*1024;
/* read_vec[] is used for converting between P_READ_KEY.. and SEARCH_ */
/* Position is , == , >= , <= , > , < */
diff --git a/myisam/mi_statrec.c b/myisam/mi_statrec.c
index 05ff40d8921..ad00b6d2595 100644
--- a/myisam/mi_statrec.c
+++ b/myisam/mi_statrec.c
@@ -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 */
@@ -27,17 +27,16 @@ int _mi_write_static_record(MI_INFO *info, const byte *record)
{
my_off_t 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],info->s->base.rec_reflength,
- MYF(MY_NABP)))
+ if (my_pread(info->dfile,(char*) &temp[0],info->s->base.rec_reflength,
+ info->s->state.dellink+1,
+ MYF(MY_NABP)))
goto err;
info->s->state.dellink= _mi_rec_pos(info->s,temp);
info->state->del--;
info->state->empty-=info->s->base.pack_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)))
+ if (my_pwrite(info->dfile, (char*) record, info->s->base.reclength,
+ filepos,
+ MYF(MY_NABP)))
goto err;
}
else
@@ -64,16 +63,18 @@ int _mi_write_static_record(MI_INFO *info, const byte *record)
else
{
info->rec_cache.seek_not_done=1; /* We have done a seek */
- VOID(my_seek(info->dfile,info->state->data_file_length,
- MY_SEEK_SET,MYF(0)));
- if (my_write(info->dfile,(char*) record,info->s->base.reclength,
- info->s->write_flag))
+ if (my_pwrite(info->dfile,(char*) record,info->s->base.reclength,
+ info->state->data_file_length,
+ info->s->write_flag))
goto err;
if (info->s->base.pack_reclength != info->s->base.reclength)
{
uint length=info->s->base.pack_reclength - info->s->base.reclength;
bzero((char*) temp,length);
- if (my_write(info->dfile, (byte*) temp,length, info->s->write_flag))
+ if (my_pwrite(info->dfile, (byte*) temp,length,
+ info->state->data_file_length+
+ info->s->base.reclength,
+ info->s->write_flag))
goto err;
}
}
@@ -88,9 +89,10 @@ int _mi_write_static_record(MI_INFO *info, const byte *record)
int _mi_update_static_record(MI_INFO *info, my_off_t 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);
+ return (my_pwrite(info->dfile,
+ (char*) record,info->s->base.reclength,
+ pos,
+ MYF(MY_NABP)) != 0);
}
@@ -104,9 +106,8 @@ int _mi_delete_static_record(MI_INFO *info)
_mi_dpointer(info,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, 1+info->s->rec_reflength,
- MYF(MY_NABP)) != 0);
+ return (my_pwrite(info->dfile,(byte*) temp, 1+info->s->rec_reflength,
+ info->lastpos, MYF(MY_NABP)) != 0);
}
@@ -129,9 +130,9 @@ int _mi_cmp_static_record(register MI_INFO *info, register const byte *old)
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)))
+ if (my_pread(info->dfile, (char*) info->rec_buff, info->s->base.reclength,
+ info->lastpos,
+ MYF(MY_NABP)))
DBUG_RETURN(-1);
if (memcmp((byte*) info->rec_buff, (byte*) old,
(uint) info->s->base.reclength))
@@ -152,9 +153,8 @@ int _mi_cmp_static_unique(MI_INFO *info, MI_UNIQUEDEF *def,
DBUG_ENTER("_mi_cmp_static_unique");
info->rec_cache.seek_not_done=1; /* We have done a seek */
- VOID(my_seek(info->dfile,pos,MY_SEEK_SET,MYF(0)));
- if (my_read(info->dfile, (char*) info->rec_buff, info->s->base.reclength,
- MYF(MY_NABP)))
+ if (my_pread(info->dfile, (char*) info->rec_buff, info->s->base.reclength,
+ pos, MYF(MY_NABP)))
DBUG_RETURN(-1);
DBUG_RETURN(mi_unique_comp(def, record, info->rec_buff,
def->null_are_equal));
@@ -181,8 +181,7 @@ int _mi_read_static_record(register MI_INFO *info, register my_off_t pos,
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(_mi_writeinfo(info,0));
+ fast_mi_writeinfo(info);
if (! error)
{
if (!*record)
@@ -195,7 +194,7 @@ int _mi_read_static_record(register MI_INFO *info, register my_off_t pos,
}
return(-1); /* Error on read */
}
- VOID(_mi_writeinfo(info,0)); /* No such record */
+ fast_mi_writeinfo(info); /* No such record */
return(-1);
}
@@ -222,7 +221,7 @@ int _mi_read_rnd_static_record(MI_INFO *info, byte *buf,
(skipp_deleted_blocks || !filepos))
{
cache_read=1; /* Read record using cache */
- cache_length=(uint) (info->rec_cache.rc_end - info->rec_cache.rc_pos);
+ cache_length=(uint) (info->rec_cache.read_end - info->rec_cache.read_pos);
}
else
info->rec_cache.seek_not_done=1; /* Filepos is changed */
@@ -257,7 +256,7 @@ int _mi_read_rnd_static_record(MI_INFO *info, byte *buf,
DBUG_PRINT("test",("filepos: %ld (%ld) records: %ld del: %ld",
filepos/share->base.reclength,filepos,
info->state->records, info->state->del));
- VOID(_mi_writeinfo(info,0));
+ fast_mi_writeinfo(info);
DBUG_RETURN(my_errno=HA_ERR_END_OF_FILE);
}
info->lastpos= filepos;
diff --git a/myisam/mi_test1.c b/myisam/mi_test1.c
index ae09bd4142e..bb32860b575 100644
--- a/myisam/mi_test1.c
+++ b/myisam/mi_test1.c
@@ -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 */
@@ -23,7 +23,7 @@
#define MAX_REC_LENGTH 1024
static int rec_pointer_size=0,verbose=0,flags[50];
-static int key_field=FIELD_SKIPP_PRESPACE,extra_field=FIELD_SKIPP_ENDSPACE;
+static int key_field=FIELD_SKIP_PRESPACE,extra_field=FIELD_SKIP_ENDSPACE;
static int key_type=HA_KEYTYPE_NUM;
static int create_flag=0;
diff --git a/myisam/mi_test2.c b/myisam/mi_test2.c
index b66b02afdf9..81d00893d27 100644
--- a/myisam/mi_test2.c
+++ b/myisam/mi_test2.c
@@ -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 */
@@ -148,15 +148,15 @@ int main(int argc, char *argv[])
keyinfo[5].keysegs=1;
keyinfo[5].flag = pack_type;
- recinfo[0].type=pack_fields ? FIELD_SKIPP_PRESPACE : 0;
+ recinfo[0].type=pack_fields ? FIELD_SKIP_PRESPACE : 0;
recinfo[0].length=7;
recinfo[0].null_bit=0;
recinfo[0].null_pos=0;
- recinfo[1].type=pack_fields ? FIELD_SKIPP_PRESPACE : 0;
+ recinfo[1].type=pack_fields ? FIELD_SKIP_PRESPACE : 0;
recinfo[1].length=5;
recinfo[1].null_bit=0;
recinfo[1].null_pos=0;
- recinfo[2].type=pack_fields ? FIELD_SKIPP_PRESPACE : 0;
+ recinfo[2].type=pack_fields ? FIELD_SKIP_PRESPACE : 0;
recinfo[2].length=9;
recinfo[2].null_bit=0;
recinfo[2].null_pos=0;
@@ -164,11 +164,11 @@ int main(int argc, char *argv[])
recinfo[3].length=STANDARD_LENGTH-7-5-9-4;
recinfo[3].null_bit=0;
recinfo[3].null_pos=0;
- recinfo[4].type=pack_fields ? FIELD_SKIPP_ZERO : 0;
+ recinfo[4].type=pack_fields ? FIELD_SKIP_ZERO : 0;
recinfo[4].length=4;
recinfo[4].null_bit=0;
recinfo[4].null_pos=0;
- recinfo[5].type=pack_fields ? FIELD_SKIPP_ENDSPACE : 0;
+ recinfo[5].type=pack_fields ? FIELD_SKIP_ENDSPACE : 0;
recinfo[5].length=60;
recinfo[5].null_bit=0;
recinfo[5].null_pos=0;
@@ -343,68 +343,72 @@ int main(int argc, char *argv[])
}
if (testflag==3) goto end;
- if (!silent)
- 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; }
+ 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 (mi_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT)) goto err;
- if (mi_rsame(file,read_record2,-1)) goto err;
- if (memcmp(read_record,read_record2,reclength) != 0)
- {
- printf("mi_rsame didn't find same record\n");
- goto end;
- }
- info.recpos=mi_position(file);
- if (mi_rfirst(file,read_record2,0) ||
- mi_rsame_with_pos(file,read_record2,0,info.recpos) ||
- memcmp(read_record,read_record2,reclength) != 0)
- {
- printf("mi_rsame_with_pos didn't find same record\n");
- goto end;
- }
+ if (dupp_keys)
{
- int skr=mi_rnext(file,read_record2,0);
- if ((skr && my_errno != HA_ERR_END_OF_FILE) ||
- mi_rprev(file,read_record2,-1) ||
+ if (!silent)
+ printf("- Same key: first - next -> last - prev -> first\n");
+ DBUG_PRINT("progpos",("first - next -> last - prev -> first"));
+ if (verbose) printf(" Using key: \"%s\" Keys: %d\n",key,dupp_keys);
+
+ if (mi_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT)) goto err;
+ if (mi_rsame(file,read_record2,-1)) goto err;
+ if (memcmp(read_record,read_record2,reclength) != 0)
+ {
+ printf("mi_rsame didn't find same record\n");
+ goto end;
+ }
+ info.recpos=mi_position(file);
+ if (mi_rfirst(file,read_record2,0) ||
+ mi_rsame_with_pos(file,read_record2,0,info.recpos) ||
memcmp(read_record,read_record2,reclength) != 0)
{
- printf("mi_rsame_with_pos lost position\n");
+ printf("mi_rsame_with_pos didn't find same record\n");
+ goto end;
+ }
+ {
+ int skr=mi_rnext(file,read_record2,0);
+ if ((skr && my_errno != HA_ERR_END_OF_FILE) ||
+ mi_rprev(file,read_record2,-1) ||
+ memcmp(read_record,read_record2,reclength) != 0)
+ {
+ printf("mi_rsame_with_pos lost position\n");
+ goto end;
+ }
+ }
+ ant=1;
+ start=keyinfo[0].seg[0].start; length=keyinfo[0].seg[0].length;
+ while (mi_rnext(file,read_record2,0) == 0 &&
+ memcmp(read_record2+start,key,length) == 0) ant++;
+ if (ant != dupp_keys)
+ {
+ printf("next: Found: %d keys of %d\n",ant,dupp_keys);
+ goto end;
+ }
+ ant=0;
+ while (mi_rprev(file,read_record3,0) == 0 &&
+ bcmp(read_record3+start,key,length) == 0) ant++;
+ if (ant != dupp_keys)
+ {
+ printf("prev: Found: %d records of %d\n",ant,dupp_keys);
goto end;
}
- }
- ant=1;
- start=keyinfo[0].seg[0].start; length=keyinfo[0].seg[0].length;
- while (mi_rnext(file,read_record2,0) == 0 &&
- memcmp(read_record2+start,key,length) == 0) ant++;
- if (ant != dupp_keys)
- {
- printf("next: Found: %d keys of %d\n",ant,dupp_keys);
- goto end;
- }
- ant=0;
- while (mi_rprev(file,read_record3,0) == 0 &&
- bcmp(read_record3+start,key,length) == 0) ant++;
- if (ant != dupp_keys)
- {
- printf("prev: Found: %d records of %d\n",ant,dupp_keys);
- goto end;
- }
- /* Check of mi_rnext_same */
- if (mi_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT))
- goto err;
- ant=1;
- while (!mi_rnext_same(file,read_record3) && ant < dupp_keys+10)
- ant++;
- if (ant != dupp_keys || my_errno != HA_ERR_END_OF_FILE)
- {
- printf("mi_rnext_same: Found: %d records of %d\n",ant,dupp_keys);
- goto end;
+ /* Check of mi_rnext_same */
+ if (mi_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT))
+ goto err;
+ ant=1;
+ while (!mi_rnext_same(file,read_record3) && ant < dupp_keys+10)
+ ant++;
+ if (ant != dupp_keys || my_errno != HA_ERR_END_OF_FILE)
+ {
+ printf("mi_rnext_same: Found: %d records of %d\n",ant,dupp_keys);
+ goto end;
+ }
}
if (!silent)
@@ -776,9 +780,13 @@ end:
printf("\nFollowing test have been made:\n");
printf("Write records: %d\nUpdate records: %d\nSame-key-read: %d\nDelete records: %d\n", write_count,update,dupp_keys,opt_delete);
if (rec_pointer_size)
- printf("Record pointer size: %d\n",rec_pointer_size);
+ printf("Record pointer size: %d\n",rec_pointer_size);
+ printf("myisam_block_size: %u\n", myisam_block_size);
if (key_cacheing)
+ {
puts("Key cacheing used");
+ printf("key_cache_block_size: %u\n", key_cache_block_size);
+ }
if (write_cacheing)
puts("Write cacheing used");
if (write_cacheing)
@@ -801,7 +809,7 @@ reads: %10lu\n",
end_key_cache();
if (blob_buffer)
my_free(blob_buffer,MYF(0));
- my_end(MY_CHECK_ERROR | MY_GIVE_INFO);
+ my_end(silent ? MY_CHECK_ERROR : MY_CHECK_ERROR | MY_GIVE_INFO);
return(0);
err:
printf("got error: %d when using MyISAM-database\n",my_errno);
@@ -861,7 +869,29 @@ static void get_options(int argc, char **argv)
verbose=1;
break;
case 'm': /* records */
- recant=atoi(++pos);
+ if ((recant=atoi(++pos)) < 10)
+ {
+ fprintf(stderr,"record count must be >= 10\n");
+ exit(1);
+ }
+ break;
+ case 'e': /* myisam_block_length */
+ if ((myisam_block_size=atoi(++pos)) < MI_MIN_KEY_BLOCK_LENGTH ||
+ myisam_block_size > MI_MAX_KEY_BLOCK_LENGTH)
+ {
+ fprintf(stderr,"Wrong myisam_block_length\n");
+ exit(1);
+ }
+ myisam_block_size=1 << my_bit_log2(myisam_block_size);
+ break;
+ case 'E': /* myisam_block_length */
+ if ((key_cache_block_size=atoi(++pos)) < MI_MIN_KEY_BLOCK_LENGTH ||
+ key_cache_block_size > MI_MAX_KEY_BLOCK_LENGTH)
+ {
+ fprintf(stderr,"Wrong key_cache_block_size\n");
+ exit(1);
+ }
+ key_cache_block_size=1 << my_bit_log2(key_cache_block_size);
break;
case 'f':
if ((first_key=atoi(++pos)) < 0 || first_key >= MYISAM_KEYS)
@@ -904,7 +934,7 @@ static void get_options(int argc, char **argv)
case 'V':
printf("%s Ver 1.2 for %s at %s\n",progname,SYSTEM_TYPE,MACHINE_TYPE);
puts("By Monty, for your professional use\n");
- printf("Usage: %s [-?AbBcDIKLPRqSsVWltv] [-k#] [-f#] [-m#] [-t#]\n",
+ printf("Usage: %s [-?AbBcDIKLPRqSsVWltv] [-k#] [-f#] [-m#] [-e#] [-E#] [-t#]\n",
progname);
exit(0);
case '#':
diff --git a/myisam/mi_test3.c b/myisam/mi_test3.c
index 48325b2dcac..36222c3edbc 100644
--- a/myisam/mi_test3.c
+++ b/myisam/mi_test3.c
@@ -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 */
diff --git a/myisam/mi_test_all.res b/myisam/mi_test_all.res
index d6b4703d702..94355bf1aa2 100644
--- a/myisam/mi_test_all.res
+++ b/myisam/mi_test_all.res
@@ -1,48 +1,50 @@
-Maximum memory usage: 545477 bytes (533k)
-Maximum memory usage: 545477 bytes (533k)
-Maximum memory usage: 545369 bytes (533k)
-mi_test2-i686 -s -L -K -R1 -m2000 ; Should give error 135
+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
-Maximum memory usage: 29439 bytes (29k)
-Maximum memory usage: 66541 bytes (65k)
-Maximum memory usage: 5101 bytes (5k)
-Maximum memory usage: 545488 bytes (533k)
+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 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
-Maximum memory usage: 545744 bytes (533k)
+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
Commands Used count Errors Recover errors
-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
-Maximum memory usage: 5101 bytes (5k)
-1.12user 0.52system 0:01.71elapsed 95%CPU (0avgtext+0avgdata 0maxresident)k
-0inputs+0outputs (214major+25minor)pagefaults 0swaps
-Maximum memory usage: 21189 bytes (21k)
-1.29user 0.55system 0:01.82elapsed 101%CPU (0avgtext+0avgdata 0maxresident)k
-0inputs+0outputs (215major+29minor)pagefaults 0swaps
-Maximum memory usage: 66541 bytes (65k)
-1.10user 0.51system 0:01.66elapsed 96%CPU (0avgtext+0avgdata 0maxresident)k
-0inputs+0outputs (216major+40minor)pagefaults 0swaps
-Maximum memory usage: 82629 bytes (81k)
-1.33user 0.24system 0:01.54elapsed 101%CPU (0avgtext+0avgdata 0maxresident)k
-0inputs+0outputs (216major+44minor)pagefaults 0swaps
-Maximum memory usage: 545477 bytes (533k)
-1.31user 0.24system 0:01.55elapsed 99%CPU (0avgtext+0avgdata 0maxresident)k
-0inputs+0outputs (216major+173minor)pagefaults 0swaps
-Maximum memory usage: 545389 bytes (533k)
-1.37user 0.18system 0:01.57elapsed 98%CPU (0avgtext+0avgdata 0maxresident)k
-0inputs+0outputs (218major+180minor)pagefaults 0swaps
-Maximum memory usage: 109165 bytes (107k)
-1.42user 0.38system 0:01.78elapsed 101%CPU (0avgtext+0avgdata 0maxresident)k
-0inputs+0outputs (218major+51minor)pagefaults 0swaps
+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
+
+real 0m1.054s
+user 0m0.410s
+sys 0m0.640s
+
+real 0m1.077s
+user 0m0.550s
+sys 0m0.530s
+
+real 0m1.100s
+user 0m0.420s
+sys 0m0.680s
+
+real 0m0.783s
+user 0m0.590s
+sys 0m0.200s
+
+real 0m0.764s
+user 0m0.560s
+sys 0m0.210s
+
+real 0m0.699s
+user 0m0.570s
+sys 0m0.130s
+
+real 0m0.991s
+user 0m0.630s
+sys 0m0.350s
diff --git a/myisam/mi_test_all.sh b/myisam/mi_test_all.sh
index ccc9c39c64e..a2d57ea1a83 100755
--- a/myisam/mi_test_all.sh
+++ b/myisam/mi_test_all.sh
@@ -66,6 +66,14 @@ myisamchk$suffix -rs test1
myisamchk$suffix -se test1
myisamchk$suffix -rqs test1
myisamchk$suffix -se test1
+myisamchk$suffix -rs --correct-checksum test1
+myisamchk$suffix -se test1
+myisamchk$suffix -rqs --correct-checksum test1
+myisamchk$suffix -se test1
+myisamchk$suffix -ros --correct-checksum test1
+myisamchk$suffix -se test1
+myisamchk$suffix -rqos --correct-checksum test1
+myisamchk$suffix -se test1
# check of myisampack / myisamchk
myisampack$suffix --force -s test1
@@ -105,13 +113,25 @@ mi_test1$suffix $silent --key_multiple -P -S
myisamchk$suffix -sm test1
mi_test2$suffix $silent -L -K -W -P
+myisamchk$suffix -sm test2
mi_test2$suffix $silent -L -K -W -P -A
+myisamchk$suffix -sm test2
mi_test2$suffix $silent -L -K -W -P -S -R1 -m500
echo "mi_test2$suffix $silent -L -K -R1 -m2000 ; Should give error 135"
+myisamchk$suffix -sm test2
mi_test2$suffix $silent -L -K -R1 -m2000
+myisamchk$suffix -sm test2
mi_test2$suffix $silent -L -K -P -S -R3 -m50 -b1000000
+myisamchk$suffix -sm test2
mi_test2$suffix $silent -L -B
+myisamchk$suffix -sm test2
mi_test2$suffix $silent -D -B -c
+myisamchk$suffix -sm test2
+mi_test2$suffix $silent -m10000 -e8192 -K
+myisamchk$suffix -sm test2
+mi_test2$suffix $silent -m10000 -e16384 -E16384 -K -L
+myisamchk$suffix -sm test2
+
mi_test2$suffix $silent -L -K -W -P -m50 -l
myisamlog$suffix
mi_test2$suffix $silent -L -K -W -P -m50 -l -b100
diff --git a/myisam/mi_unique.c b/myisam/mi_unique.c
index e598fbeedb4..5806502823a 100644
--- a/myisam/mi_unique.c
+++ b/myisam/mi_unique.c
@@ -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 */
diff --git a/myisam/mi_update.c b/myisam/mi_update.c
index 185624f3878..2c6bc42bbdb 100644
--- a/myisam/mi_update.c
+++ b/myisam/mi_update.c
@@ -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 */
@@ -98,9 +98,7 @@ int mi_update(register MI_INFO *info, const byte *oldrec, byte *newrec)
if ((int) i == info->lastinx)
key_changed|=HA_STATE_WRITTEN;
changed|=((ulonglong) 1 << i);
- if (_mi_ft_del(info,i,(char*) old_key,oldrec,pos))
- goto err;
- if (_mi_ft_add(info,i,(char*) new_key,newrec,pos))
+ if (_mi_ft_update(info,i,(char*) old_key,oldrec,newrec,pos))
goto err;
}
}
@@ -138,6 +136,12 @@ int mi_update(register MI_INFO *info, const byte *oldrec, byte *newrec)
myisam_log_record(MI_LOG_UPDATE,info,newrec,info->lastpos,0);
VOID(_mi_writeinfo(info,key_changed ? WRITEINFO_UPDATE_KEYFILE : 0));
allow_break(); /* Allow SIGHUP & SIGINT */
+ if (info->invalidator != 0)
+ {
+ DBUG_PRINT("info", ("invalidator... '%s' (update)", info->filename));
+ (*info->invalidator)(info->filename);
+ info->invalidator=0;
+ }
DBUG_RETURN(0);
err:
diff --git a/myisam/mi_write.c b/myisam/mi_write.c
index f31e43e52ab..5a2711aac92 100644
--- a/myisam/mi_write.c
+++ b/myisam/mi_write.c
@@ -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 */
@@ -25,7 +25,8 @@
/* Functions declared in this file */
-static int w_search(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key,
+static int w_search(MI_INFO *info,MI_KEYDEF *keyinfo,
+ uint comp_flag, uchar *key,
uint key_length, my_off_t pos, uchar *father_buff,
uchar *father_keypos, my_off_t father_page,
my_bool insert_last);
@@ -35,17 +36,21 @@ static int _mi_balance_page(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key,
static uchar *_mi_find_last_pos(MI_KEYDEF *keyinfo, uchar *page,
uchar *key, uint *return_key_length,
uchar **after_key);
-
+int _mi_ck_write_tree(register MI_INFO *info, uint keynr, uchar *key,
+ uint key_length);
+int _mi_ck_write_btree(register MI_INFO *info, uint keynr, uchar *key,
+ uint key_length);
/* Write new record to database */
int mi_write(MI_INFO *info, byte *record)
{
+ MYISAM_SHARE *share=info->s;
uint i;
int save_errno;
my_off_t filepos;
uchar *buff;
- MYISAM_SHARE *share=info->s;
+ my_bool lock_tree= share->concurrent_insert;
DBUG_ENTER("mi_write");
DBUG_PRINT("enter",("isam: %d data: %d",info->s->kfile,info->dfile));
@@ -96,33 +101,36 @@ int mi_write(MI_INFO *info, byte *record)
{
if (((ulonglong) 1 << i) & share->state.key_map)
{
- if (share->concurrent_insert)
+ bool local_lock_tree= (lock_tree &&
+ !(info->bulk_insert &&
+ is_tree_inited(& info->bulk_insert[i])));
+ if (local_lock_tree)
{
rw_wrlock(&share->key_root_lock[i]);
share->keyinfo[i].version++;
}
- if (share->keyinfo[i].flag & HA_FULLTEXT ) /* SerG */
- { /* SerG */
- if (_mi_ft_add(info,i,(char*) buff,record,filepos)) /* SerG */
- { /* SerG */
- if (share->concurrent_insert)
+ if (share->keyinfo[i].flag & HA_FULLTEXT )
+ {
+ if (_mi_ft_add(info,i,(char*) buff,record,filepos))
+ {
+ if (local_lock_tree)
rw_unlock(&share->key_root_lock[i]);
- DBUG_PRINT("error",("Got error: %d on write",my_errno)); /* SerG */
- goto err; /* SerG */
- } /* SerG */
- } /* SerG */
- else /* SerG */
+ DBUG_PRINT("error",("Got error: %d on write",my_errno));
+ goto err;
+ }
+ }
+ else
{
uint key_length=_mi_make_key(info,i,buff,record,filepos);
if (_mi_ck_write(info,i,buff,key_length))
{
- if (share->concurrent_insert)
+ if (local_lock_tree)
rw_unlock(&share->key_root_lock[i]);
DBUG_PRINT("error",("Got error: %d on write",my_errno));
goto err;
}
}
- if (share->concurrent_insert)
+ if (local_lock_tree)
rw_unlock(&share->key_root_lock[i]);
}
}
@@ -142,6 +150,12 @@ int mi_write(MI_INFO *info, byte *record)
info->lastpos=filepos;
myisam_log_record(MI_LOG_WRITE,info,record,filepos,0);
VOID(_mi_writeinfo(info, WRITEINFO_UPDATE_KEYFILE));
+ if (info->invalidator != 0)
+ {
+ DBUG_PRINT("info", ("invalidator... '%s' (update)", info->filename));
+ (*info->invalidator)(info->filename);
+ info->invalidator=0;
+ }
allow_break(); /* Allow SIGHUP & SIGINT */
DBUG_RETURN(0);
@@ -149,19 +163,32 @@ err:
save_errno=my_errno;
if (my_errno == HA_ERR_FOUND_DUPP_KEY || my_errno == HA_ERR_RECORD_FILE_FULL)
{
+ if (info->bulk_insert)
+ {
+ uint j;
+ for (j=0 ; j < share->base.keys ; j++)
+ {
+ if (is_tree_inited(& info->bulk_insert[j]))
+ {
+ reset_tree(& info->bulk_insert[j]);
+ }
+ }
+ }
info->errkey= (int) i;
while ( i-- > 0)
{
if (((ulonglong) 1 << i) & share->state.key_map)
{
- if (share->concurrent_insert)
+ bool local_lock_tree= (lock_tree &&
+ !(info->bulk_insert &&
+ is_tree_inited(& info->bulk_insert[i])));
+ if (local_lock_tree)
rw_wrlock(&share->key_root_lock[i]);
- /* The following code block is for text searching by SerG */
if (share->keyinfo[i].flag & HA_FULLTEXT)
{
if (_mi_ft_del(info,i,(char*) buff,record,filepos))
{
- if (share->concurrent_insert)
+ if (local_lock_tree)
rw_unlock(&share->key_root_lock[i]);
break;
}
@@ -171,12 +198,12 @@ err:
uint key_length=_mi_make_key(info,i,buff,record,filepos);
if (_mi_ck_delete(info,i,buff,key_length))
{
- if (share->concurrent_insert)
+ if (local_lock_tree)
rw_unlock(&share->key_root_lock[i]);
break;
}
}
- if (share->concurrent_insert)
+ if (local_lock_tree)
rw_unlock(&share->key_root_lock[i]);
}
}
@@ -196,19 +223,51 @@ err2:
/* Write one key to btree */
-int _mi_ck_write(register MI_INFO *info, uint keynr, uchar *key,
- uint key_length)
+int _mi_ck_write(MI_INFO *info, uint keynr, uchar *key, uint key_length)
{
- int error;
DBUG_ENTER("_mi_ck_write");
+ if (info->bulk_insert && is_tree_inited(& info->bulk_insert[keynr]))
+ {
+ DBUG_RETURN(_mi_ck_write_tree(info, keynr, key, key_length));
+ }
+ else
+ {
+ DBUG_RETURN(_mi_ck_write_btree(info, keynr, key, key_length));
+ }
+} /* _mi_ck_write */
+
+
+/**********************************************************************
+ * Normal insert code *
+ **********************************************************************/
+
+int _mi_ck_write_btree(register MI_INFO *info, uint keynr, uchar *key,
+ uint key_length)
+{
+ int error;
+ uint comp_flag;
+ MI_KEYDEF *keyinfo=info->s->keyinfo+keynr;
+ DBUG_ENTER("_mi_ck_write_btree");
+
+ if (keyinfo->flag & HA_SORT_ALLOWS_SAME)
+ comp_flag=SEARCH_BIGGER; /* Put after same key */
+ else if (keyinfo->flag & HA_NOSAME)
+ {
+ comp_flag=SEARCH_FIND | SEARCH_UPDATE; /* No dupplicates */
+ if (keyinfo->flag & HA_NULL_ARE_EQUAL)
+ comp_flag|= SEARCH_NULL_ARE_EQUAL;
+ }
+ else
+ comp_flag=SEARCH_SAME; /* Keys in rec-pos order */
+
if (info->s->state.key_root[keynr] == HA_OFFSET_ERROR ||
- (error=w_search(info,info->s->keyinfo+keynr,key, key_length,
+ (error=w_search(info, keyinfo, comp_flag, key, key_length,
info->s->state.key_root[keynr], (uchar *) 0, (uchar*) 0,
(my_off_t) 0, 1)) > 0)
error=_mi_enlarge_root(info,keynr,key);
DBUG_RETURN(error);
-} /* _mi_ck_write */
+} /* _mi_ck_write_btree */
/* Make a new root with key as only pointer */
@@ -246,13 +305,12 @@ int _mi_enlarge_root(register MI_INFO *info, uint keynr, uchar *key)
*/
static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
- uchar *key, uint key_length, my_off_t page,
- uchar *father_buff,
- uchar *father_keypos, my_off_t father_page,
- my_bool insert_last)
+ uint comp_flag, uchar *key, uint key_length, my_off_t page,
+ uchar *father_buff, uchar *father_keypos,
+ my_off_t father_page, my_bool insert_last)
{
int error,flag;
- uint comp_flag,nod_flag;
+ uint nod_flag, search_key_length;
uchar *temp_buff,*keypos;
uchar keybuff[MI_MAX_KEY_BUFF];
my_bool was_last_key;
@@ -260,21 +318,15 @@ static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
DBUG_ENTER("w_search");
DBUG_PRINT("enter",("page: %ld",page));
- if (keyinfo->flag & HA_SORT_ALLOWS_SAME)
- comp_flag=SEARCH_BIGGER; /* Put after same key */
- else if (keyinfo->flag & HA_NOSAME)
- comp_flag=SEARCH_FIND | SEARCH_UPDATE; /* No dupplicates */
- else
- comp_flag=SEARCH_SAME; /* Keys in rec-pos order */
-
+ search_key_length= (comp_flag & SEARCH_FIND) ? key_length : USE_WHOLE_KEY;
if (!(temp_buff= (uchar*) my_alloca((uint) keyinfo->block_length+
MI_MAX_KEY_BUFF*2)))
DBUG_RETURN(-1);
if (!_mi_fetch_keypage(info,keyinfo,page,temp_buff,0))
goto err;
- flag=(*keyinfo->bin_search)(info,keyinfo,temp_buff,key,key_length,comp_flag,
- &keypos, keybuff, &was_last_key);
+ flag=(*keyinfo->bin_search)(info,keyinfo,temp_buff,key,search_key_length,
+ comp_flag, &keypos, keybuff, &was_last_key);
nod_flag=mi_test_if_nod(temp_buff);
if (flag == 0)
{
@@ -295,7 +347,7 @@ static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
insert_last=0;
next_page=_mi_kpos(nod_flag,keypos);
if (next_page == HA_OFFSET_ERROR ||
- (error=w_search(info,keyinfo,key,key_length,next_page,
+ (error=w_search(info, keyinfo, comp_flag, key, key_length, next_page,
temp_buff, keypos, page, insert_last)) >0)
{
error=_mi_insert(info,keyinfo,key,temp_buff,keypos,keybuff,father_buff,
@@ -682,3 +734,119 @@ static int _mi_balance_page(register MI_INFO *info, MI_KEYDEF *keyinfo,
err:
DBUG_RETURN(-1);
} /* _mi_balance_page */
+
+/**********************************************************************
+ * Bulk insert code *
+ **********************************************************************/
+
+typedef struct {
+ MI_INFO *info;
+ uint keynr;
+} bulk_insert_param;
+
+int _mi_ck_write_tree(register MI_INFO *info, uint keynr, uchar *key,
+ uint key_length)
+{
+ int error;
+ DBUG_ENTER("_mi_ck_write_tree");
+
+ error= tree_insert(& info->bulk_insert[keynr], key,
+ key_length + info->s->rec_reflength) ? 0 : HA_ERR_OUT_OF_MEM ;
+
+ DBUG_RETURN(error);
+} /* _mi_ck_write_tree */
+
+
+/* typeof(_mi_keys_compare)=qsort_cmp2 */
+static int keys_compare(bulk_insert_param *param, uchar *key1, uchar *key2)
+{
+ uint not_used;
+ return _mi_key_cmp(param->info->s->keyinfo[param->keynr].seg,
+ key1, key2, USE_WHOLE_KEY, SEARCH_SAME,
+ &not_used);
+}
+
+
+static int keys_free(uchar *key, TREE_FREE mode, bulk_insert_param *param)
+{
+ /*
+ Probably I can use info->lastkey here, but I'm not sure,
+ and to be safe I'd better use local lastkey.
+ */
+ uchar lastkey[MI_MAX_KEY_BUFF];
+ uint keylen;
+ MI_KEYDEF *keyinfo;
+
+ switch (mode) {
+ case free_init:
+ if (param->info->s->concurrent_insert)
+ {
+ rw_wrlock(&param->info->s->key_root_lock[param->keynr]);
+ param->info->s->keyinfo[param->keynr].version++;
+ }
+ return 0;
+ case free_free:
+ keyinfo=param->info->s->keyinfo+param->keynr;
+ keylen=_mi_keylength(keyinfo, key);
+ memcpy(lastkey, key, keylen);
+ return _mi_ck_write_btree(param->info,param->keynr,lastkey,
+ keylen - param->info->s->rec_reflength);
+ case free_end:
+ if (param->info->s->concurrent_insert)
+ rw_unlock(&param->info->s->key_root_lock[param->keynr]);
+ return 0;
+ }
+ return -1;
+}
+
+
+int _mi_init_bulk_insert(MI_INFO *info)
+{
+ MYISAM_SHARE *share=info->s;
+ MI_KEYDEF *key=share->keyinfo;
+ bulk_insert_param *params;
+ uint i, num_keys;
+ ulonglong key_map=0;
+
+ if (info->bulk_insert)
+ return 0;
+
+ for (i=num_keys=0 ; i < share->base.keys ; i++)
+ {
+ if (!(key[i].flag & HA_NOSAME) && share->base.auto_key != i+1
+ && test(share->state.key_map & ((ulonglong) 1 << i)))
+ {
+ num_keys++;
+ key_map |=((ulonglong) 1 << i);
+ }
+ }
+
+ if (num_keys==0 || num_keys>myisam_bulk_insert_tree_size)
+ return 0;
+
+ info->bulk_insert=(TREE *)
+ my_malloc((sizeof(TREE)*share->base.keys+
+ sizeof(bulk_insert_param)*num_keys),MYF(0));
+
+ if (!info->bulk_insert)
+ return HA_ERR_OUT_OF_MEM;
+
+ params=(bulk_insert_param *)(info->bulk_insert+share->base.keys);
+ for (i=0 ; i < share->base.keys ; i++,key++)
+ {
+ if (test(key_map & ((ulonglong) 1 << i)))
+ {
+ params->info=info;
+ params->keynr=i;
+ init_tree(& info->bulk_insert[i],
+ myisam_bulk_insert_tree_size / num_keys / 4 + 10,
+ myisam_bulk_insert_tree_size / num_keys, 0,
+ (qsort_cmp2)keys_compare, 0,
+ (tree_element_free) keys_free, (void *)params++);
+ }
+ else
+ info->bulk_insert[i].root=0;
+ }
+
+ return 0;
+}
diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c
index cb321f8fda3..20554b69393 100644
--- a/myisam/myisamchk.c
+++ b/myisam/myisamchk.c
@@ -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 */
@@ -20,7 +20,7 @@
#include <m_ctype.h>
#include <stdarg.h>
-#include <getopt.h>
+#include <my_getopt.h>
#include <assert.h>
#ifdef HAVE_SYS_VADVICE_H
#include <sys/vadvise.h>
@@ -44,6 +44,7 @@ static char **default_argv;
static const char *load_default_groups[]= { "myisamchk", 0 };
static const char *set_charset_name;
static CHARSET_INFO *set_charset;
+static long opt_myisam_block_size;
static const char *type_names[]=
{ "?","char","binary", "short", "long", "float",
@@ -141,76 +142,155 @@ int main(int argc, char **argv)
#endif
} /* main */
+enum options {
+ OPT_CHARSETS_DIR=256, OPT_SET_CHARSET,OPT_START_CHECK_POS,
+ OPT_CORRECT_CHECKSUM, OPT_KEY_BUFFER_SIZE, OPT_MYISAM_BLOCK_SIZE,
+ OPT_READ_BUFFER_SIZE, OPT_WRITE_BUFFER_SIZE, OPT_SORT_BUFFER_SIZE,
+ OPT_SORT_KEY_BLOCKS, OPT_DECODE_BITS, OPT_FT_MIN_WORD_LEN,
+ OPT_FT_MAX_WORD_LEN, OPT_FT_MAX_WORD_LEN_FOR_SORT
+};
-static CHANGEABLE_VAR changeable_vars[] = {
- { "key_buffer_size",(long*) &check_param.use_buffers,(long) USE_BUFFER_INIT,
- (long) MALLOC_OVERHEAD, (long) ~0L,(long) MALLOC_OVERHEAD,(long) IO_SIZE },
- { "read_buffer_size", (long*) &check_param.read_buffer_length,(long) READ_BUFFER_INIT,
- (long) MALLOC_OVERHEAD,(long) ~0L,(long) MALLOC_OVERHEAD,(long) 1L },
- { "write_buffer_size", (long*) &check_param.write_buffer_length,(long) READ_BUFFER_INIT,
- (long) MALLOC_OVERHEAD,(long) ~0L,(long) MALLOC_OVERHEAD,(long) 1L },
- { "sort_buffer_size",(long*) &check_param.sort_buffer_length,(long) SORT_BUFFER_INIT,
- (long) (MIN_SORT_BUFFER+MALLOC_OVERHEAD),(long) ~0L,
- (long) MALLOC_OVERHEAD,(long) 1L },
- { "sort_key_blocks",(long*) &check_param.sort_key_blocks,BUFFERS_WHEN_SORTING,4L,100L,0L,
- 1L },
- { "decode_bits",(long*) &decode_bits,9L,4L,17L,0L,1L },
- { NullS,(long*) 0,0L,0L,0L,0L,0L,} };
-
-enum options {OPT_CHARSETS_DIR=256, OPT_SET_CHARSET,OPT_START_CHECK_POS};
-
-
-static struct option long_options[] =
+static struct my_option my_long_options[] =
{
- {"analyze", no_argument, 0, 'a'},
- {"block-search", required_argument,0, 'b'},
- {"backup", no_argument, 0, 'B'},
- {"character-sets-dir",required_argument,0, OPT_CHARSETS_DIR},
- {"check", no_argument, 0, 'c'},
- {"check-only-changed",no_argument, 0, 'C'},
+ {"analyze",
+ "Analyze distribution of keys. Will make some joins in MySQL faster. You can check the calculated distribution.", 0, 0, 0, GET_NO_ARG, NO_ARG, 'a', 0, 0,
+ 0, 0, 0, 0},
+ {"block-search", "No help available.", 0, 0, 0, GET_LONG, REQUIRED_ARG, 'b',
+ 0, 0, 0, 0, 0, 0},
+ {"backup", "Make a backup of the .MYD file as 'filename-time.BAK'", 0, 0, 0,
+ GET_NO_ARG, NO_ARG, 'B', 0, 0, 0, 0, 0, 0},
+ {"character-sets-dir", "Directory where character sets are.",
+ (gptr*) &set_charset_name, 0, 0, GET_STR, REQUIRED_ARG, OPT_CHARSETS_DIR, 0,
+ 0, 0, 0, 0, 0},
+ {"check", "Check table for errors.", 0, 0, 0, GET_NO_ARG, NO_ARG, 'c', 0, 0,
+ 0, 0, 0, 0},
+ {"check-only-changed",
+ "Check only tables that has changed since last check.", 0, 0, 0, GET_NO_ARG,
+ NO_ARG, 'C', 0, 0, 0, 0, 0, 0},
+ {"correct-checksum", "Correct checksum information for table.", 0, 0, 0,
+ GET_NO_ARG, NO_ARG, OPT_CORRECT_CHECKSUM, 0, 0, 0, 0, 0, 0},
#ifndef DBUG_OFF
- {"debug", optional_argument, 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},
#endif
- {"description", no_argument, 0, 'd'},
- {"data-file-length", required_argument, 0, 'D'},
- {"extend-check", no_argument, 0, 'e'},
- {"fast", no_argument, 0, 'F'},
- {"force", no_argument, 0, 'f'},
- {"help", no_argument, 0, '?'},
- {"information", no_argument, 0, 'i'},
- {"keys-used", required_argument, 0, 'k'},
- {"medium-check", no_argument, 0, 'm'},
- {"no-symlinks", no_argument, 0, 'l'},
- {"quick", no_argument, 0, 'q'},
- {"read-only", no_argument, 0, 'T'},
- {"recover", no_argument, 0, 'r'},
- {"safe-recover", no_argument, 0, 'o'},
- {"start-check-pos", required_argument, 0, OPT_START_CHECK_POS},
- {"set-auto-increment",optional_argument, 0, 'A'},
- {"set-character-set",required_argument,0,OPT_SET_CHARSET},
- {"set-variable", required_argument, 0, 'O'},
- {"silent", no_argument, 0, 's'},
- {"sort-index", no_argument, 0, 'S'},
- {"sort-records", required_argument, 0, 'R'},
- {"sort-recover", no_argument, 0, 'n'},
- {"tmpdir", required_argument, 0, 't'},
- {"update-state", no_argument, 0, 'U'},
- {"unpack", no_argument, 0, 'u'},
- {"verbose", no_argument, 0, 'v'},
- {"version", no_argument, 0, 'V'},
- {"wait", no_argument, 0, 'w'},
- {0, 0, 0, 0}
+ {"description", "Prints some information about table.", 0, 0, 0, GET_NO_ARG,
+ NO_ARG, 'd', 0, 0, 0, 0, 0, 0},
+ {"data-file-length",
+ "Max length of data file (when recreating data-file when it's full).",
+ (gptr*) &check_param.max_data_file_length,
+ (gptr*) &check_param.max_data_file_length, 0, GET_LONG, REQUIRED_ARG, 'D',
+ 0, 0, 0, 0, 0, 0},
+ {"extend-check",
+ "Try to recover every possible row from the data file. Normally this will also find a lot of garbage rows; Don't use this option if you are not totally desperate.", 0, 0, 0, GET_NO_ARG, NO_ARG, 'e', 0, 0, 0, 0, 0, 0},
+ {"fast", "Check only tables that hasn't been closed properly.", 0, 0, 0,
+ GET_NO_ARG, NO_ARG, 'F', 0, 0, 0, 0, 0, 0},
+ {"force",
+ "Restart with -r if there are any errors in the table. States will be updated as with --update-state.", 0, 0, 0, GET_NO_ARG, NO_ARG, 'f', 0, 0, 0, 0, 0,
+ 0},
+ {"help", "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, '?', 0,
+ 0, 0, 0, 0, 0},
+ {"information", "Print statistics information about table that is checked.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 'i', 0, 0, 0, 0, 0, 0},
+ {"keys-used", "Tell MyISAM to update only some specific keys. # is a bit mask of which keys to use. This can be used to get faster inserts!",
+ (gptr*) &check_param.keys_in_use, (gptr*) &check_param.keys_in_use, 0,
+ GET_LL, REQUIRED_ARG, 'k',-1, 0, 0, 0, 0, 0},
+ {"medium-check",
+ "Faster than extended-check, but only finds 99.99% of all errors. Should be good enough for most cases.", 0, 0, 0, GET_NO_ARG, NO_ARG, 'm', 0, 0, 0, 0, 0,
+ 0},
+ {"quick", "Faster repair by not modifying the data file.", 0, 0, 0,
+ GET_NO_ARG, NO_ARG, 'q', 0, 0, 0, 0, 0, 0},
+ {"read-only", "Don't mark table as checked.", 0, 0, 0, GET_NO_ARG, NO_ARG,
+ 'T', 0, 0, 0, 0, 0, 0},
+ {"recover",
+ "Can fix almost anything except unique keys that aren't unique.", 0, 0, 0,
+ GET_NO_ARG, NO_ARG, 'r', 0, 0, 0, 0, 0, 0},
+ {"safe-recover",
+ "Uses old recovery method; Slower than '-r' but can handle a couple of cases where '-r' reports that it can't fix the data file.", 0, 0, 0, GET_NO_ARG,
+ NO_ARG, 'o', 0, 0, 0, 0, 0, 0},
+ {"start-check-pos", "No help available.", 0, 0, 0, GET_LONG, REQUIRED_ARG,
+ OPT_START_CHECK_POS, 0, 0, 0, 0, 0, 0},
+ {"set-auto-increment",
+ "Force auto_increment to start at this or higher value. If no value is given, then sets the next auto_increment value to the highest used value for the auto key + 1.", (gptr*) &check_param.auto_increment_value,
+ (gptr*) &check_param.auto_increment_value, 0, GET_LONG, OPT_ARG, 'A', 0, 0,
+ 0, 0, 0, 0},
+ {"set-character-set", "Change the character set used by the index", 0, 0, 0,
+ GET_STR, REQUIRED_ARG, OPT_SET_CHARSET, 0, 0, 0, 0, 0, 0},
+ {"set-variable", "Change the value of a variable. Please note that this option is depricated; you can set variables directly with --variable-name=value.",
+ 0, 0, 0, GET_STR, REQUIRED_ARG, 'O', 0, 0, 0, 0, 0, 0},
+ {"silent",
+ "Only print errors. One can use two -s to make myisamchk very silent.", 0,
+ 0, 0, GET_NO_ARG, NO_ARG, 's', 0, 0, 0, 0, 0, 0},
+ {"sort-index",
+ "Sort index blocks. This speeds up 'read-next' in applications.", 0, 0, 0,
+ GET_NO_ARG, NO_ARG, 'S', 0, 0, 0, 0, 0, 0},
+ {"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!)",
+ (gptr*) &check_param.opt_sort_key, (gptr*) &check_param.opt_sort_key, 0,
+ GET_LONG, REQUIRED_ARG, 'R', 0, 0, 0, 0, 0, 0},
+ {"sort-recover",
+ "Force recovering with sorting even if the temporary file was very big.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 'n', 0, 0, 0, 0, 0, 0},
+ {"tmpdir", "Path for temporary files.", (gptr*) &check_param.tmpdir, 0, 0,
+ GET_STR, REQUIRED_ARG, 't', 0, 0, 0, 0, 0, 0},
+ {"update-state", "Mark tables as crashed if any errors were found.", 0, 0,
+ 0, GET_NO_ARG, NO_ARG, 'U', 0, 0, 0, 0, 0, 0},
+ {"unpack", "Unpack file packed with myisampack.", 0, 0, 0, GET_NO_ARG,
+ NO_ARG, 'u', 0, 0, 0, 0, 0, 0},
+ {"verbose",
+ "Print more information. This can be used with --describe and --check. Use many -v for more verbosity!", 0, 0, 0, GET_NO_ARG, NO_ARG, 'v', 0, 0, 0, 0, 0,
+ 0},
+ {"version", "Print version and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 'V', 0,
+ 0, 0, 0, 0, 0},
+ {"wait", "Wait if table is locked.", 0, 0, 0, GET_NO_ARG, NO_ARG, 'w', 0, 0,
+ 0, 0, 0, 0},
+ { "key_buffer_size", "", (gptr*) &check_param.use_buffers,
+ (gptr*) &check_param.use_buffers, 0, GET_LONG, REQUIRED_ARG,
+ OPT_KEY_BUFFER_SIZE, (long) USE_BUFFER_INIT, (long) MALLOC_OVERHEAD,
+ (long) ~0L, (long) MALLOC_OVERHEAD, (long) IO_SIZE, 0},
+ { "myisam_block_size", "", (gptr*) &opt_myisam_block_size,
+ (gptr*) &opt_myisam_block_size, 0, GET_LONG, REQUIRED_ARG,
+ OPT_MYISAM_BLOCK_SIZE, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
+ MI_MAX_KEY_BLOCK_LENGTH, 0, MI_MIN_KEY_BLOCK_LENGTH, 0},
+ { "read_buffer_size", "", (gptr*) &check_param.read_buffer_length,
+ (gptr*) &check_param.read_buffer_length, 0, GET_LONG, REQUIRED_ARG,
+ OPT_READ_BUFFER_SIZE, (long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
+ (long) ~0L, (long) MALLOC_OVERHEAD, (long) 1L, 0},
+ { "write_buffer_size", "", (gptr*) &check_param.write_buffer_length,
+ (gptr*) &check_param.write_buffer_length, 0, GET_LONG, REQUIRED_ARG,
+ OPT_WRITE_BUFFER_SIZE, (long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
+ (long) ~0L, (long) MALLOC_OVERHEAD, (long) 1L, 0},
+ { "sort_buffer_size", "", (gptr*) &check_param.sort_buffer_length,
+ (gptr*) &check_param.sort_buffer_length, 0, GET_LONG, REQUIRED_ARG,
+ OPT_SORT_BUFFER_SIZE, (long) SORT_BUFFER_INIT,
+ (long) (MIN_SORT_BUFFER + MALLOC_OVERHEAD), (long) ~0L,
+ (long) MALLOC_OVERHEAD, (long) 1L, 0},
+ { "sort_key_blocks", "", (gptr*) &check_param.sort_key_blocks,
+ (gptr*) &check_param.sort_key_blocks, 0, GET_LONG, REQUIRED_ARG,
+ OPT_SORT_KEY_BLOCKS, BUFFERS_WHEN_SORTING, 4L, 100L, 0L, 1L, 0},
+ { "decode_bits", "", (gptr*) &decode_bits, (gptr*) &decode_bits, 0,
+ GET_LONG, REQUIRED_ARG, OPT_DECODE_BITS, 9L, 4L, 17L, 0L, 1L, 0},
+ { "ft_min_word_len", "", (gptr*) &ft_min_word_len, (gptr*) &ft_min_word_len,
+ 0, GET_LONG, REQUIRED_ARG, OPT_FT_MIN_WORD_LEN, 4, 1, HA_FT_MAXLEN, 0, 1,
+ 0},
+ { "ft_max_word_len", "", (gptr*) &ft_max_word_len, (gptr*) &ft_max_word_len,
+ 0, GET_LONG, REQUIRED_ARG, OPT_FT_MAX_WORD_LEN, HA_FT_MAXLEN, 10,
+ HA_FT_MAXLEN, 0, 1, 0},
+ { "ft_max_word_len_for_sort", "", (gptr*) &ft_max_word_len_for_sort,
+ (gptr*) &ft_max_word_len_for_sort, 0, GET_LONG, REQUIRED_ARG,
+ OPT_FT_MAX_WORD_LEN_FOR_SORT, 20, 4, HA_FT_MAXLEN, 0, 1, 0},
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};
+
static void print_version(void)
{
- printf("%s Ver 1.53 for %s at %s\n",my_progname,SYSTEM_TYPE,
+ printf("%s Ver 2.3 for %s at %s\n", my_progname, SYSTEM_TYPE,
MACHINE_TYPE);
}
+
static void usage(void)
{
- uint i;
print_version();
puts("By Monty, for your professional use");
puts("This software comes with NO WARRANTY: see the PUBLIC for details.\n");
@@ -247,6 +327,7 @@ static void usage(void)
puts("Repair options (When using -r or -o) \n\
-B, --backup Make a backup of the .MYD file as 'filename-time.BAK'\n\
+ --correct-checksum Correct checksum information for table.\n\
-D, --data-file-length=# Max length of data file (when recreating data\n\
file when it's full)\n\
-e, --extend-check Try to recover every possible row from the data file\n\
@@ -256,8 +337,6 @@ static void usage(void)
-k, --keys-used=# Tell MyISAM to update only some specific keys. # is a\n\
bit mask of which keys to use. This can be used to\n\
get faster inserts!\n\
- -l, --no-symlinks Do not follow symbolic links. Normally\n\
- myisamchk repairs the table a symlink points at.\n\
-r, --recover Can fix almost anything except unique keys that aren't\n\
unique.\n\
-n, --sort-recover Force recovering with sorting even if the temporary\n\
@@ -292,124 +371,182 @@ static void usage(void)
data much more localized and may speed up things\n\
(It may be VERY slow to do a sort the first time!)");
- print_defaults("my",load_default_groups);
- printf("\nPossible variables for option --set-variable (-O) are:\n");
- for (i=0; changeable_vars[i].name ; i++)
- printf("%-20s current value: %lu\n",
- changeable_vars[i].name,
- *changeable_vars[i].varptr);
+ print_defaults("my", load_default_groups);
+ putchar('\n');
+ my_print_variables(my_long_options);
}
/* Read options */
-static void get_options(register int *argc,register char ***argv)
+static my_bool
+get_one_option(int optid,
+ const struct my_option *opt __attribute__((unused)),
+ char *argument)
{
- int c,option_index=0;
- uint old_testflag;
-
- load_defaults("my",load_default_groups,argc,argv);
- default_argv= *argv;
- set_all_changeable_vars(changeable_vars);
- if (isatty(fileno(stdout)))
- check_param.testflag|=T_WRITE_LOOP;
- while ((c=getopt_long(*argc,*argv,
- "aBcCdeifF?lqrmnosSTuUvVw#:b:D:k:O:R:A::t:",
- long_options, &option_index)) != EOF)
- {
- switch(c) {
- case 'a':
+ switch (optid) {
+ case 'a':
+ if (argument && *argument == '0')
+ check_param.testflag&= ~T_STATISTICS;
+ else
check_param.testflag|= T_STATISTICS;
- break;
- case 'A':
- if (optarg)
- check_param.auto_increment_value=strtoull(optarg,NULL,0);
- else
- check_param.auto_increment_value=0; /* Set to max used value */
- check_param.testflag|= T_AUTO_INC;
- break;
- case 'b':
- check_param.search_after_block=strtoul(optarg,NULL,10);
- break;
- case 'B':
+ break;
+ case 'A':
+ if (argument)
+ check_param.auto_increment_value= strtoull(argument, NULL, 0);
+ else
+ check_param.auto_increment_value= 0; /* Set to max used value */
+ check_param.testflag|= T_AUTO_INC;
+ break;
+ case 'b':
+ check_param.search_after_block= strtoul(argument, NULL, 10);
+ break;
+ case 'B':
+ if (argument && *argument == '0')
+ check_param.testflag&= ~T_BACKUP_DATA;
+ else
check_param.testflag|= T_BACKUP_DATA;
- break;
- case 'c':
+ break;
+ case 'c':
+ if (argument && *argument == '0')
+ check_param.testflag&= ~T_CHECK;
+ else
check_param.testflag|= T_CHECK;
- break;
- case 'C':
+ break;
+ case 'C':
+ if (argument && *argument == '0')
+ check_param.testflag&= ~(T_CHECK | T_CHECK_ONLY_CHANGED);
+ else
check_param.testflag|= T_CHECK | T_CHECK_ONLY_CHANGED;
- break;
- case 'D':
- check_param.max_data_file_length=strtoll(optarg,NULL,10);
- break;
- case 's': /* silent */
+ break;
+ case 'D':
+ check_param.max_data_file_length=strtoll(argument, NULL, 10);
+ break;
+ case 's': /* silent */
+ if (argument && *argument == '0')
+ check_param.testflag&= ~(T_SILENT | T_VERY_SILENT);
+ else
+ {
if (check_param.testflag & T_SILENT)
- check_param.testflag|=T_VERY_SILENT;
+ check_param.testflag|= T_VERY_SILENT;
check_param.testflag|= T_SILENT;
check_param.testflag&= ~T_WRITE_LOOP;
- break;
- case 'w':
+ }
+ break;
+ case 'w':
+ if (argument && *argument == '0')
+ check_param.testflag&= ~T_WAIT_FOREVER;
+ else
check_param.testflag|= T_WAIT_FOREVER;
- break;
- case 'd': /* description if isam-file */
+ break;
+ case 'd': /* description if isam-file */
+ if (argument && *argument == '0')
+ check_param.testflag&= ~T_DESCRIPT;
+ else
check_param.testflag|= T_DESCRIPT;
- break;
- case 'e': /* extend check */
+ break;
+ case 'e': /* extend check */
+ if (argument && *argument == '0')
+ check_param.testflag&= ~T_EXTEND;
+ else
check_param.testflag|= T_EXTEND;
- break;
- case 'i':
+ break;
+ case 'i':
+ if (argument && *argument == '0')
+ check_param.testflag&= ~T_INFO;
+ else
check_param.testflag|= T_INFO;
- break;
- case 'f':
+ break;
+ case 'f':
+ if (argument && *argument == '0')
+ {
+ check_param.tmpfile_createflag= O_RDWR | O_TRUNC | O_EXCL;
+ check_param.testflag&= ~(T_FORCE_CREATE | T_UPDATE_STATE);
+ }
+ else
+ {
check_param.tmpfile_createflag= O_RDWR | O_TRUNC;
check_param.testflag|= T_FORCE_CREATE | T_UPDATE_STATE;
- break;
- case 'F':
- check_param.testflag|=T_FAST;
- break;
- case 'k':
- check_param.keys_in_use= (ulonglong) strtoll(optarg,NULL,10);
- break;
- case 'l':
- check_param.opt_follow_links=0;
- break;
- case 'm':
+ }
+ break;
+ case 'F':
+ if (argument && *argument == '0')
+ check_param.testflag&= ~T_FAST;
+ else
+ check_param.testflag|= T_FAST;
+ break;
+ case 'k':
+ check_param.keys_in_use= (ulonglong) strtoll(argument, NULL, 10);
+ break;
+ case 'm':
+ if (argument && *argument == '0')
+ check_param.testflag&= ~T_MEDIUM;
+ else
check_param.testflag|= T_MEDIUM; /* Medium check */
- break;
- case 'r': /* Repair table */
+ break;
+ case 'r': /* Repair table */
+ if (argument && *argument == '0')
+ check_param.testflag&= ~(T_REP | T_REP_BY_SORT);
+ else
check_param.testflag= (check_param.testflag & ~T_REP) | T_REP_BY_SORT;
- break;
- case 'o':
+ break;
+ case 'o':
+ if (argument && *argument == '0')
+ {
+ check_param.testflag&= ~(T_REP | T_REP_BY_SORT);
+ check_param.force_sort= 0;
+ }
+ else
+ {
check_param.testflag= (check_param.testflag & ~T_REP_BY_SORT) | T_REP;
- check_param.force_sort=0;
- my_disable_async_io=1; /* More safety */
- break;
- case 'n':
+ check_param.force_sort= 0;
+ my_disable_async_io= 1; /* More safety */
+ }
+ break;
+ case 'n':
+ if (argument && *argument == '0')
+ {
+ check_param.testflag&= ~(T_REP | T_REP_BY_SORT);
+ check_param.force_sort= 0;
+ }
+ else
+ {
check_param.testflag= (check_param.testflag & ~T_REP) | T_REP_BY_SORT;
- check_param.force_sort=1;
- break;
- case 'q':
- check_param.opt_rep_quick++;
- break;
- case 'u':
+ check_param.force_sort= 1;
+ }
+ break;
+ case 'q':
+ if (argument && *argument == '0')
+ check_param.testflag&= ~(T_QUICK | T_FORCE_UNIQUENESS);
+ else
+ check_param.testflag|=
+ (check_param.testflag & T_QUICK) ? T_FORCE_UNIQUENESS : T_QUICK;
+ break;
+ case 'u':
+ if (argument && *argument == '0')
+ check_param.testflag&= ~(T_UNPACK | T_REP_BY_SORT);
+ else
check_param.testflag|= T_UNPACK | T_REP_BY_SORT;
- break;
- case 'v': /* Verbose */
+ break;
+ case 'v': /* Verbose */
+ if (argument && *argument == '0')
+ {
+ check_param.testflag&= ~T_VERBOSE;
+ check_param.verbose=0;
+ }
+ else
+ {
check_param.testflag|= T_VERBOSE;
check_param.verbose++;
- break;
- case 'O':
- if (set_changeable_var(optarg, changeable_vars))
- {
- usage();
- exit(1);
- }
- break;
- case 'R': /* Sort records */
- old_testflag=check_param.testflag;
+ }
+ break;
+ case 'R': /* Sort records */
+ if (argument && *argument == '0')
+ check_param.testflag&= ~T_SORT_RECORDS;
+ else
+ {
check_param.testflag|= T_SORT_RECORDS;
- check_param.opt_sort_key=(uint) atoi(optarg)-1;
+ check_param.opt_sort_key= (uint) atoi(argument) - 1;
if (check_param.opt_sort_key >= MI_MAX_KEY)
{
fprintf(stderr,
@@ -417,51 +554,81 @@ static void get_options(register int *argc,register char ***argv)
MI_MAX_KEY);
exit(1);
}
- break;
- case 'S': /* Sort index */
- old_testflag=check_param.testflag;
+ }
+ break;
+ case 'S': /* Sort index */
+ if (argument && *argument == '0')
+ check_param.testflag&= ~T_SORT_INDEX;
+ else
check_param.testflag|= T_SORT_INDEX;
- break;
- case 't':
- check_param.tmpdir=optarg;
- break;
- case 'T':
+ break;
+ case 'T':
+ if (argument && *argument == '0')
+ check_param.testflag&= ~T_READONLY;
+ else
check_param.testflag|= T_READONLY;
- break;
- case 'U':
+ break;
+ case 'U':
+ if (argument && *argument == '0')
+ check_param.testflag&= ~T_UPDATE_STATE;
+ else
check_param.testflag|= T_UPDATE_STATE;
- break;
- case '#':
- DBUG_PUSH(optarg ? optarg : "d:t:o,/tmp/myisamchk.trace");
- break;
- case 'V':
- print_version();
- exit(0);
- case OPT_CHARSETS_DIR:
- charsets_dir = optarg;
- break;
- case OPT_SET_CHARSET:
- set_charset_name=optarg;
- break;
+ break;
+ case '#':
+ if (argument && *argument == '0')
+ {
+ DBUG_POP();
+ }
+ else
+ {
+ DBUG_PUSH(argument ? argument : "d:t:o,/tmp/myisamchk.trace");
+ }
+ break;
+ case 'V':
+ print_version();
+ exit(0);
+ case OPT_CORRECT_CHECKSUM:
+ if (argument && *argument == '0')
+ check_param.testflag&= ~T_CALC_CHECKSUM;
+ else
+ check_param.testflag|= T_CALC_CHECKSUM;
+ break;
#ifdef DEBUG /* Only useful if debugging */
- case OPT_START_CHECK_POS:
- check_param.start_check_pos=strtoull(optarg,NULL,0);
- break;
+ case OPT_START_CHECK_POS:
+ check_param.start_check_pos= strtoull(argument, NULL, 0);
+ break;
#endif
- case '?':
- usage();
- exit(0);
- }
+ case '?':
+ usage();
+ exit(0);
}
- (*argc)-=optind;
- (*argv)+=optind;
+ return 0;
+}
+
+
+static void get_options(register int *argc,register char ***argv)
+{
+ load_defaults("my", load_default_groups, argc, argv);
+ default_argv= *argv;
+ if (isatty(fileno(stdout)))
+ check_param.testflag|=T_WRITE_LOOP;
+
+ if (handle_options(argc, argv, my_long_options, get_one_option))
+ exit(1);
+
+ /* If using repair, then update checksum if one uses --update-state */
+ if ((check_param.testflag & T_UPDATE_STATE) &&
+ (check_param.testflag & (T_REP | T_REP_BY_SORT)))
+ check_param.testflag|= T_CALC_CHECKSUM;
+
if (*argc == 0)
{
usage();
exit(-1);
}
+
if ((check_param.testflag & T_UNPACK) &&
- (check_param.opt_rep_quick || (check_param.testflag & T_SORT_RECORDS)))
+ (check_param.testflag & (T_QUICK | T_SORT_RECORDS)))
{
VOID(fprintf(stderr,
"%s: --unpack can't be used with --quick or --sort-records\n",
@@ -483,6 +650,7 @@ static void get_options(register int *argc,register char ***argv)
if (!(set_charset=get_charset_by_name(set_charset_name, MYF(MY_WME))))
exit(1);
+ myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size);
return;
} /* get options */
@@ -492,11 +660,10 @@ static void get_options(register int *argc,register char ***argv)
static int myisamchk(MI_CHECK *param, my_string filename)
{
int error,lock_type,recreate;
- int rep_quick= param->opt_rep_quick;
+ int rep_quick= param->testflag & (T_QUICK | T_FORCE_UNIQUENESS);
uint raid_chunks;
MI_INFO *info;
File datafile;
- char fixed_name[FN_REFLEN];
char llbuff[22],llbuff2[22];
my_bool state_updated=0;
MYISAM_SHARE *share;
@@ -610,7 +777,8 @@ static int myisamchk(MI_CHECK *param, my_string filename)
(((ulonglong) 1L << share->base.keys)-1)) ||
test_if_almost_full(info) ||
info->s->state.header.file_version[3] != myisam_file_magic[3] ||
- (set_charset && set_charset->number != share->state.header.language)))
+ (set_charset && set_charset->number != share->state.header.language) ||
+ myisam_block_size != MI_KEY_BLOCK_LENGTH))
{
if (set_charset)
check_param.language=set_charset->number;
@@ -627,8 +795,7 @@ static int myisamchk(MI_CHECK *param, my_string filename)
param->testflag|=T_REP_BY_SORT; /* if only STATISTICS */
if (!(param->testflag & T_SILENT))
printf("- '%s' has old table-format. Recreating index\n",filename);
- if (!rep_quick)
- rep_quick=1;
+ rep_quick|=T_QUICK;
}
share=info->s;
share->r_locks=0;
@@ -674,9 +841,6 @@ static int myisamchk(MI_CHECK *param, my_string filename)
if (tmp != share->state.key_map)
info->update|=HA_STATE_CHANGED;
}
- VOID(fn_format(fixed_name,filename,"",MI_NAME_IEXT,
- 4+ (param->opt_follow_links ? 16 : 0)));
-
if (rep_quick && chk_del(&check_param, info,
param->testflag & ~T_VERBOSE))
{
@@ -701,11 +865,11 @@ static int myisamchk(MI_CHECK *param, my_string filename)
info->s->state.key_map,
check_param.force_sort))
{
- error=mi_repair_by_sort(&check_param,info,fixed_name,rep_quick);
+ error=mi_repair_by_sort(&check_param,info,filename,rep_quick);
state_updated=1;
}
else if (param->testflag & (T_REP | T_REP_BY_SORT))
- error=mi_repair(&check_param, info,fixed_name,rep_quick);
+ error=mi_repair(&check_param, info,filename,rep_quick);
}
if (!error && param->testflag & T_SORT_RECORDS)
{
@@ -717,10 +881,10 @@ static int myisamchk(MI_CHECK *param, my_string filename)
if (param->out_flag & O_NEW_DATA)
{ /* Change temp file to org file */
VOID(my_close(info->dfile,MYF(MY_WME))); /* Close new file */
- error|=change_to_newfile(fixed_name,MI_NAME_DEXT,DATA_TMP_EXT,
+ error|=change_to_newfile(filename,MI_NAME_DEXT,DATA_TMP_EXT,
raid_chunks,
MYF(0));
- if (mi_open_datafile(info,info->s))
+ if (mi_open_datafile(info,info->s, -1))
error=1;
param->out_flag&= ~O_NEW_DATA; /* We are using new datafile */
param->read_cache.file=info->dfile;
@@ -738,7 +902,7 @@ static int myisamchk(MI_CHECK *param, my_string filename)
if (share->keyinfo[key].flag & HA_BINARY_PACK_KEY)
update_index=0;
- error=mi_sort_records(param,info,fixed_name,param->opt_sort_key,
+ error=mi_sort_records(param,info,filename,param->opt_sort_key,
(my_bool) !(param->testflag & T_REP),
update_index);
datafile=info->dfile; /* This is now locked */
@@ -746,12 +910,12 @@ static int myisamchk(MI_CHECK *param, my_string filename)
{
if (check_param.verbose)
puts("Table had a compressed index; We must now recreate the index");
- error=mi_repair_by_sort(&check_param,info,fixed_name,1);
+ error=mi_repair_by_sort(&check_param,info,filename,1);
}
}
}
if (!error && param->testflag & T_SORT_INDEX)
- error=mi_sort_index(param,info,fixed_name);
+ error=mi_sort_index(param,info,filename);
if (!error)
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
STATE_CRASHED_ON_REPAIR);
@@ -786,7 +950,7 @@ static int myisamchk(MI_CHECK *param, my_string filename)
!(param->testflag & (T_FAST | T_FORCE_CREATE)))
{
if (param->testflag & (T_EXTEND | T_MEDIUM))
- VOID(init_key_cache(param->use_buffers,(uint) NEAD_MEM));
+ VOID(init_key_cache(param->use_buffers,(uint) NEED_MEM));
VOID(init_io_cache(&param->read_cache,datafile,
(uint) param->read_buffer_length,
READ_CACHE,
@@ -848,12 +1012,12 @@ end2:
if (error == 0)
{
if (param->out_flag & O_NEW_DATA)
- error|=change_to_newfile(fixed_name,MI_NAME_DEXT,DATA_TMP_EXT,
+ error|=change_to_newfile(filename,MI_NAME_DEXT,DATA_TMP_EXT,
raid_chunks,
((param->testflag & T_BACKUP_DATA) ?
MYF(MY_REDEL_MAKE_BACKUP) : MYF(0)));
if (param->out_flag & O_NEW_INDEX)
- error|=change_to_newfile(fixed_name,MI_NAME_IEXT,INDEX_TMP_EXT,0,
+ error|=change_to_newfile(filename,MI_NAME_IEXT,INDEX_TMP_EXT,0,
MYF(0));
}
VOID(fflush(stdout)); VOID(fflush(stderr));
@@ -1193,7 +1357,7 @@ static int mi_sort_records(MI_CHECK *param,
if (share->state.key_root[sort_key] == HA_OFFSET_ERROR)
DBUG_RETURN(0); /* Nothing to do */
- init_key_cache(param->use_buffers,NEAD_MEM);
+ init_key_cache(param->use_buffers,NEED_MEM);
if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length,
WRITE_CACHE,share->pack.header_length,1,
MYF(MY_WME | MY_WAIT_IF_FULL)))
@@ -1211,7 +1375,9 @@ static int mi_sort_records(MI_CHECK *param,
mi_check_print_error(param,"Not enough memory for record");
goto err;
}
- new_file=my_raid_create(fn_format(param->temp_filename,name,"",
+ fn_format(param->temp_filename,name,"", MI_NAME_DEXT,2+4+32);
+ new_file=my_raid_create(fn_format(param->temp_filename,
+ param->temp_filename,"",
DATA_TMP_EXT,2+4),
0,param->tmpfile_createflag,
share->base.raid_type,
diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h
index 260e9665b31..e9d3461fe9a 100644
--- a/myisam/myisamdef.h
+++ b/myisam/myisamdef.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 */
@@ -18,6 +18,7 @@
#include "myisam.h" /* Structs & some defines */
#include "myisampack.h" /* packing of keys */
+#include <my_tree.h>
#ifdef THREAD
#include <my_pthread.h>
#include <thr_lock.h>
@@ -37,7 +38,7 @@ typedef struct st_mi_status_info
my_off_t key_empty; /* lost space in indexfile */
my_off_t key_file_length;
my_off_t data_file_length;
-} MI_STATUS_INFO;
+} MI_STATUS_INFO;
typedef struct st_mi_state_info
{
@@ -65,8 +66,10 @@ typedef struct st_mi_state_info
ulong unique; /* Unique number for this process */
ulong update_count; /* Updated for each write lock */
ulong status;
+ ulong *rec_per_key_part;
my_off_t *key_root; /* Start of key trees */
my_off_t *key_del; /* delete links for trees */
+ my_off_t rec_per_key_rows; /* Rows when calculating rec_per_key */
ulong sec_index_changed; /* Updated when new sec_index */
ulong sec_index_used; /* which extra index are in use */
@@ -79,8 +82,6 @@ typedef struct st_mi_state_info
uint sortkey; /* sorted by this key (not used) */
uint open_count;
uint8 changed; /* Changed since myisamchk */
- my_off_t rec_per_key_rows; /* Rows when calculating rec_per_key */
- ulong *rec_per_key_part;
/* the following isn't saved on disk */
uint state_diff_length; /* Should be 0 */
@@ -159,42 +160,45 @@ typedef struct st_mi_isam_share { /* Shared between opens */
MI_COLUMNDEF *rec; /* Pointer to field information */
MI_PACK pack; /* Data about packed records */
MI_BLOB *blobs; /* Pointer to blobs */
- char *filename; /* Name of indexfile */
+ char *unique_file_name; /* realpath() of index file */
+ char *data_file_name, /* Resolved path names from symlinks */
+ *index_file_name;
byte *file_map; /* mem-map of file if possible */
+ MI_DECODE_TREE *decode_trees;
+ uint16 *decode_tables;
+ int (*read_record)(struct st_myisam_info*, my_off_t, byte*);
+ int (*write_record)(struct st_myisam_info*, const byte*);
+ int (*update_record)(struct st_myisam_info*, my_off_t, const byte*);
+ int (*delete_record)(struct st_myisam_info*);
+ int (*read_rnd)(struct st_myisam_info*, byte*, my_off_t, my_bool);
+ int (*compare_record)(struct st_myisam_info*, const byte *);
+ ha_checksum (*calc_checksum)(struct st_myisam_info*, const byte *);
+ int (*compare_unique)(struct st_myisam_info*, MI_UNIQUEDEF *,
+ const byte *record, my_off_t pos);
+ invalidator_by_filename invalidator; /* query cache invalidator */
ulong this_process; /* processid */
ulong last_process; /* For table-change-check */
ulong last_version; /* Version on start */
ulong options; /* Options used */
+ ulong min_pack_length; /* Theese are used by packed data */
+ ulong max_pack_length;
+ ulong state_diff_length;
uint rec_reflength; /* rec_reflength in use now */
- int kfile; /* Shared keyfile */
- int data_file; /* Shared data file */
+ File kfile; /* Shared keyfile */
+ File data_file; /* Shared data file */
int mode; /* mode of file on open */
uint reopen; /* How many times reopened */
- uint w_locks,r_locks; /* Number of read/write locks */
+ uint w_locks,r_locks,tot_locks; /* Number of read/write locks */
uint blocksize; /* blocksize of keyfile */
- ulong min_pack_length; /* Theese are used by packed data */
- ulong max_pack_length;
- ulong state_diff_length;
+ myf write_flag;
+ int rnd; /* rnd-counter */
+ enum data_file_type data_file_type;
my_bool changed, /* If changed since lock */
global_changed, /* If changed since open */
not_flushed,
temporary,delay_key_write,
concurrent_insert,
fulltext_index;
- myf write_flag;
- int rnd; /* rnd-counter */
- MI_DECODE_TREE *decode_trees;
- uint16 *decode_tables;
- enum data_file_type data_file_type;
- int (*read_record)(struct st_myisam_info*, my_off_t, byte*);
- int (*write_record)(struct st_myisam_info*, const byte*);
- int (*update_record)(struct st_myisam_info*, my_off_t, const byte*);
- int (*delete_record)(struct st_myisam_info*);
- int (*read_rnd)(struct st_myisam_info*, byte*, my_off_t, my_bool);
- int (*compare_record)(struct st_myisam_info*, const byte *);
- ha_checksum (*calc_checksum)(struct st_myisam_info*, const byte *);
- int (*compare_unique)(struct st_myisam_info*, MI_UNIQUEDEF *,
- const byte *record, my_off_t pos);
#ifdef THREAD
THR_LOCK lock;
pthread_mutex_t intern_lock; /* Locking for use with _locking */
@@ -212,16 +216,22 @@ typedef struct st_mi_bit_buff { /* Used for packing of record */
uint error;
} MI_BIT_BUFF;
-
struct st_myisam_info {
MYISAM_SHARE *s; /* Shared between open:s */
MI_STATUS_INFO *state,save_state;
MI_BLOB *blobs; /* Pointer to blobs */
- int dfile; /* The datafile */
- MI_BIT_BUFF bit_buff;
- uint opt_flag; /* Optim. for space/speed */
- uint update; /* If file changed since open */
+ MI_BIT_BUFF bit_buff;
+ /* accumulate indexfile changes between write's */
+ TREE *bulk_insert;
char *filename; /* parameter to open filename */
+ uchar *buff, /* Temp area for key */
+ *lastkey,*lastkey2; /* Last used search key */
+ byte *rec_buff, /* Tempbuff for recordpack */
+ *rec_alloc; /* Malloced area for record */
+ uchar *int_keypos, /* Save position for next/previous */
+ *int_maxpos; /* -""- */
+ int (*read_record)(struct st_myisam_info*, my_off_t, byte*);
+ invalidator_by_filename invalidator; /* query cache invalidator */
ulong this_unique; /* uniq filenumber or thread */
ulong last_unique; /* last unique number */
ulong this_loop; /* counter for this open */
@@ -230,20 +240,16 @@ struct st_myisam_info {
nextpos; /* Position to next record */
my_off_t save_lastpos;
my_off_t pos; /* Intern variable */
+ my_off_t last_keypage; /* Last key page read */
+ my_off_t last_search_keypage; /* Last keypage when searching */
+ my_off_t dupp_key_pos;
ha_checksum checksum;
ulong packed_length,blob_length; /* Length of found, packed record */
+ int dfile; /* The datafile */
+ uint opt_flag; /* Optim. for space/speed */
+ uint update; /* If file changed since open */
uint alloced_rec_buff_length; /* Max recordlength malloced */
- uchar *buff, /* Temp area for key */
- *lastkey,*lastkey2; /* Last used search key */
- byte *rec_buff, /* Tempbuff for recordpack */
- *rec_alloc; /* Malloced area for record */
- uchar *int_keypos, /* Save position for next/previous */
- *int_maxpos; /* -""- */
- uint32 int_keytree_version; /* -""- */
uint int_nod_flag; /* -""- */
- my_off_t last_keypage; /* Last key page read */
- my_off_t last_search_keypage; /* Last keypage when searching */
- my_off_t dupp_key_pos;
int lastinx; /* Last used index */
uint lastkey_length; /* Length of key in lastkey */
uint last_rkey_length; /* Last length in mi_rkey() */
@@ -254,15 +260,15 @@ struct st_myisam_info {
uint data_changed; /* Somebody has changed data */
uint save_update; /* When using KEY_READ */
int save_lastinx;
+ uint32 int_keytree_version; /* -""- */
+ LIST open_list;
+ IO_CACHE rec_cache; /* When cacheing records */
+ myf lock_wait; /* is 0 or MY_DONT_WAIT */
my_bool was_locked; /* Was locked in panic */
my_bool quick_mode;
my_bool page_changed; /* If info->buff can't be used for rnext */
my_bool buff_used; /* If info->buff has to be reread for rnext */
my_bool use_packed_key; /* For MYISAMMRG */
- myf lock_wait; /* is 0 or MY_DONT_WAIT */
- int (*read_record)(struct st_myisam_info*, my_off_t, byte*);
- LIST open_list;
- IO_CACHE rec_cache; /* When cacheing records */
#ifdef THREAD
THR_LOCK_DATA lock;
#endif
@@ -285,7 +291,7 @@ struct st_myisam_info {
#define STATE_CHANGED 1
#define STATE_CRASHED 2
-#define STATE_CRASHED_ON_REPAIR 4
+#define STATE_CRASHED_ON_REPAIR 4
#define STATE_NOT_ANALYZED 8
#define STATE_NOT_OPTIMIZED_KEYS 16
#define STATE_NOT_SORTED_PAGES 32
@@ -352,7 +358,8 @@ struct st_myisam_info {
#define MI_DYN_MAX_BLOCK_LENGTH ((1L << 24)-4L)
#define MI_DYN_MAX_ROW_LENGTH (MI_DYN_MAX_BLOCK_LENGTH - MI_SPLIT_LENGTH)
#define MI_DYN_ALIGN_SIZE 4 /* Align blocks on this */
-#define MI_MAX_DYN_HEADER_BYTE 12 /* max header byte for dynamic rows */
+#define MI_MAX_DYN_HEADER_BYTE 13 /* max header byte for dynamic rows */
+#define MI_MAX_BLOCK_LENGTH ((((ulong) 1 << 24)-1) & (~ (ulong) (MI_DYN_ALIGN_SIZE-1)))
#define MEMMAP_EXTRA_MARGIN 7 /* Write this as a suffix for file */
@@ -361,10 +368,8 @@ struct st_myisam_info {
#define PACK_TYPE_ZERO_FILL 4
#define MI_FOUND_WRONG_KEY 32738 /* Impossible value from _mi_key_cmp */
-#define MI_KEY_BLOCK_LENGTH 1024 /* Min key block length */
-#define MI_MAX_KEY_BLOCK_LENGTH 8192
-#define MI_MAX_KEY_BLOCK_SIZE (MI_MAX_KEY_BLOCK_LENGTH/MI_KEY_BLOCK_LENGTH)
-#define MI_BLOCK_SIZE(key_length,data_pointer,key_pointer) ((((key_length+data_pointer+key_pointer)*4+key_pointer+2)/MI_KEY_BLOCK_LENGTH+1)*MI_KEY_BLOCK_LENGTH)
+#define MI_MAX_KEY_BLOCK_SIZE (MI_MAX_KEY_BLOCK_LENGTH/MI_MIN_KEY_BLOCK_LENGTH)
+#define MI_BLOCK_SIZE(key_length,data_pointer,key_pointer) ((((key_length+data_pointer+key_pointer)*4+key_pointer+2)/myisam_block_size+1)*myisam_block_size)
#define MI_MAX_KEYPTR_SIZE 5 /* For calculating block lengths */
#define MI_MIN_KEYBLOCK_LENGTH 50 /* When to split delete blocks */
@@ -473,6 +478,9 @@ extern int _mi_bin_search(struct st_myisam_info *info,MI_KEYDEF *keyinfo,
extern int _mi_seq_search(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *page,
uchar *key,uint key_len,uint comp_flag,
uchar **ret_pos,uchar *buff, my_bool *was_last_key);
+extern int _mi_prefix_search(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *page,
+ uchar *key,uint key_len,uint comp_flag,
+ uchar **ret_pos,uchar *buff, my_bool *was_last_key);
extern int _mi_compare_text(CHARSET_INFO *, uchar *, uint, uchar *, uint ,
my_bool);
extern my_off_t _mi_kpos(uint nod_flag,uchar *after_key);
@@ -528,6 +536,8 @@ extern int _mi_read_rnd_pack_record(MI_INFO*, byte *,my_off_t, my_bool);
extern int _mi_pack_rec_unpack(MI_INFO *info,byte *to,byte *from,
ulong reclength);
extern ulonglong mi_safe_mul(ulonglong a,ulonglong b);
+extern int _mi_ft_update(MI_INFO *info, uint keynr, byte *keybuf,
+ const byte *oldrec, const byte *newrec, my_off_t pos);
struct st_sort_info;
@@ -554,7 +564,7 @@ typedef struct st_mi_block_info { /* Parameter to _mi_get_block_info */
#define BLOCK_SYNC_ERROR 16 /* Right data at wrong place */
#define BLOCK_FATAL_ERROR 32 /* hardware-error */
-#define NEAD_MEM ((uint) 10*4*(IO_SIZE+32)+32) /* Nead for recursion */
+#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
@@ -580,6 +590,9 @@ enum myisam_log_commands {
#define myisam_log_command(a,b,c,d,e) if (myisam_log_file >= 0) _myisam_log_command(a,b,c,d,e)
#define myisam_log_record(a,b,c,d,e) if (myisam_log_file >= 0) _myisam_log_record(a,b,c,d,e)
+#define fast_mi_writeinfo(INFO) if (!(INFO)->s->tot_locks) (void) _mi_writeinfo((INFO),0)
+#define fast_mi_readinfo(INFO) ((INFO)->lock_type == F_UNLCK) && _mi_readinfo((INFO),F_RDLCK,1)
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -633,14 +646,17 @@ my_bool mi_check_status(void* param);
void mi_disable_non_unique_index(MI_INFO *info, ha_rows rows);
my_bool check_table_is_closed(const char *name, const char *where);
-int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share);
+int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, File file_to_dup);
int mi_open_keyfile(MYISAM_SHARE *share);
void mi_setup_functions(register MYISAM_SHARE *share);
-/* Functions needed by mi_check */
+int _mi_init_bulk_insert(MI_INFO *info);
+
+ /* Functions needed by mi_check */
void mi_check_print_error _VARARGS((MI_CHECK *param, const char *fmt,...));
void mi_check_print_warning _VARARGS((MI_CHECK *param, const char *fmt,...));
void mi_check_print_info _VARARGS((MI_CHECK *param, const char *fmt,...));
+int flush_pending_blocks(MI_CHECK *param);
#ifdef __cplusplus
}
diff --git a/myisam/myisamlog.c b/myisam/myisamlog.c
index ddfafb91430..2d4c7570956 100644
--- a/myisam/myisamlog.c
+++ b/myisam/myisamlog.c
@@ -56,7 +56,7 @@ 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 file_info_compare(void *cmp_arg, void *a,void *b);
static int test_if_open(struct file_info *key,element_count count,
struct test_if_open_param *param);
static void fix_blob_pointers(MI_INFO *isam,byte *record);
@@ -331,8 +331,8 @@ static int examine_log(my_string file_name, char **table_names)
init_io_cache(&cache,file,0,READ_CACHE,start_offset,0,MYF(0));
bzero((gptr) com_count,sizeof(com_count));
- init_tree(&tree,0,sizeof(file_info),(qsort_cmp) file_info_compare,1,
- (void(*)(void*)) file_info_free);
+ 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(KEY_CACHE_SIZE,(uint) (10*4*(IO_SIZE+MALLOC_OVERHEAD))));
files_open=0; access_time=0;
@@ -404,11 +404,7 @@ static int examine_log(my_string file_name, char **table_names)
}
to=isam_file_name;
if (filepath)
- {
- strmov(isam_file_name,filepath);
- convert_dirname(isam_file_name);
- to=strend(isam_file_name);
- }
+ to=convert_dirname(isam_file_name,filepath,NullS);
strmov(to,pos);
fn_ext(isam_file_name)[0]=0; /* Remove extension */
}
@@ -695,7 +691,8 @@ static int read_string(IO_CACHE *file, register gptr *to, register uint length)
} /* read_string */
-static int file_info_compare(void *a, void *b)
+static int file_info_compare(void* cmp_arg __attribute__((unused)),
+ void *a, void *b)
{
long lint;
diff --git a/myisam/myisampack.c b/myisam/myisampack.c
index 81ae77738ea..5d7898e9020 100644
--- a/myisam/myisampack.c
+++ b/myisam/myisampack.c
@@ -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 */
@@ -124,7 +124,8 @@ 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 compare_tree(void* cmp_arg __attribute__((unused)),
+ const uchar *s,const uchar *t);
static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts);
static void check_counts(HUFF_COUNTS *huff_counts,uint trees,
my_off_t records);
@@ -664,9 +665,9 @@ static HUFF_COUNTS *init_huff_count(MI_INFO *info,my_off_t records)
type = FIELD_NORMAL;
if (count[i].field_length <= 8 &&
(type == FIELD_NORMAL ||
- type == FIELD_SKIPP_ZERO))
+ type == FIELD_SKIP_ZERO))
count[i].max_zero_fill= count[i].field_length;
- init_tree(&count[i].int_tree,0,-1,(qsort_cmp) compare_tree,0,NULL);
+ init_tree(&count[i].int_tree,0,0,-1,(qsort_cmp2) compare_tree,0,NULL,NULL);
if (records && type != FIELD_BLOB && type != FIELD_VARCHAR)
count[i].tree_pos=count[i].tree_buff =
my_malloc(count[i].field_length > 1 ? tree_buff_length : 2,
@@ -788,7 +789,7 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts)
/* Save character counters and space-counts and zero-field-counts */
if (count->field_type == FIELD_NORMAL ||
- count->field_type == FIELD_SKIPP_ENDSPACE)
+ count->field_type == FIELD_SKIP_ENDSPACE)
{
for ( ; end_pos > pos ; end_pos--)
if (end_pos[-1] != ' ')
@@ -807,7 +808,7 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts)
count->max_end_space = length;
}
if (count->field_type == FIELD_NORMAL ||
- count->field_type == FIELD_SKIPP_PRESPACE)
+ count->field_type == FIELD_SKIP_PRESPACE)
{
for (pos=start_pos; pos < end_pos ; pos++)
if (pos[0] != ' ')
@@ -843,7 +844,7 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts)
}
if (count->field_length <= 8 &&
(count->field_type == FIELD_NORMAL ||
- count->field_type == FIELD_SKIPP_ZERO))
+ count->field_type == FIELD_SKIP_ZERO))
{
uint i;
if (!memcmp((byte*) start_pos,zero_string,count->field_length))
@@ -948,7 +949,7 @@ static void check_counts(HUFF_COUNTS *huff_counts, uint trees,
new_length=calc_packed_length(huff_counts,0);
if (old_length < new_length && huff_counts->field_length > 1)
{
- huff_counts->field_type=FIELD_SKIPP_ZERO;
+ huff_counts->field_type=FIELD_SKIP_ZERO;
huff_counts->counts[0]-=length;
huff_counts->bytes_packed=old_length- records/8;
goto found_pack;
@@ -992,7 +993,7 @@ static void check_counts(HUFF_COUNTS *huff_counts, uint trees,
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_SKIPP_ENDSPACE))
+ huff_counts->tot_end_space,FIELD_SKIP_ENDSPACE))
goto found_pack;
huff_counts->counts[' ']-=huff_counts->tot_pre_space;
}
@@ -1000,7 +1001,7 @@ static void check_counts(HUFF_COUNTS *huff_counts, uint trees,
{
if (test_space_compress(huff_counts,records,huff_counts->max_pre_space,
huff_counts->pre_space,
- huff_counts->tot_pre_space,FIELD_SKIPP_PRESPACE))
+ huff_counts->tot_pre_space,FIELD_SKIP_PRESPACE))
goto found_pack;
}
@@ -1010,10 +1011,10 @@ static void check_counts(HUFF_COUNTS *huff_counts, uint trees,
if (huff_counts->max_zero_fill &&
(huff_counts->field_type == FIELD_NORMAL ||
- huff_counts->field_type == FIELD_SKIPP_ZERO))
+ huff_counts->field_type == FIELD_SKIP_ZERO))
{
huff_counts->counts[0]-=huff_counts->max_zero_fill*
- (huff_counts->field_type == FIELD_SKIPP_ZERO ?
+ (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);
@@ -1053,9 +1054,9 @@ static void check_counts(HUFF_COUNTS *huff_counts, uint trees,
if (verbose)
printf("\nnormal: %3d empty-space: %3d empty-zero: %3d empty-fill: %3d\npre-space: %3d end-space: %3d intervall-fields: %3d zero: %3d\n",
field_count[FIELD_NORMAL],space_fields,
- field_count[FIELD_SKIPP_ZERO],fill_zero_fields,
- field_count[FIELD_SKIPP_PRESPACE],
- field_count[FIELD_SKIPP_ENDSPACE],
+ 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;
@@ -1283,7 +1284,8 @@ static int make_huff_tree(HUFF_TREE *huff_tree, HUFF_COUNTS *huff_counts)
return 0;
}
-static int compare_tree(register const uchar *s, register const uchar *t)
+static int compare_tree(void* cmp_arg __attribute__((unused)),
+ register const uchar *s, register const uchar *t)
{
uint length;
for (length=global_count->field_length; length-- ;)
@@ -1720,7 +1722,7 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
field_length-=count->max_zero_fill;
switch(count->field_type) {
- case FIELD_SKIPP_ZERO:
+ case FIELD_SKIP_ZERO:
if (!memcmp((byte*) start_pos,zero_string,field_length))
{
write_bits(1,1);
@@ -1734,7 +1736,7 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
write_bits(tree->code[(uchar) *start_pos],
(uint) tree->code_len[(uchar) *start_pos]);
break;
- case FIELD_SKIPP_ENDSPACE:
+ 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)
@@ -1757,7 +1759,7 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
(uint) tree->code_len[(uchar) *start_pos]);
start_pos=end_pos;
break;
- case FIELD_SKIPP_PRESPACE:
+ 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)
diff --git a/myisam/sort.c b/myisam/sort.c
index 161a5f92bf5..66a8254732a 100644
--- a/myisam/sort.c
+++ b/myisam/sort.c
@@ -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 */
@@ -19,7 +19,7 @@
them in sorted order through SORT_INFO functions.
*/
-#include "myisamdef.h"
+#include "fulltext.h"
#if defined(MSDOS) || defined(__WIN__)
#include <fcntl.h>
#else
@@ -52,10 +52,12 @@ extern void print_error _VARARGS((const char *fmt,...));
static ha_rows NEAR_F find_all_keys(MI_SORT_PARAM *info,uint keys,
uchar **sort_keys,
- BUFFPEK *buffpek,int *maxbuffer,
- IO_CACHE *tempfile);
+ DYNAMIC_ARRAY *buffpek,int *maxbuffer,
+ IO_CACHE *tempfile,
+ IO_CACHE *tempfile_for_exceptions);
static int NEAR_F write_keys(MI_SORT_PARAM *info,uchar * *sort_keys,
uint count, BUFFPEK *buffpek,IO_CACHE *tempfile);
+static int NEAR_F write_key(MI_SORT_PARAM *info, uchar *key, IO_CACHE *tempfile);
static int NEAR_F write_index(MI_SORT_PARAM *info,uchar * *sort_keys,
uint count);
static int NEAR_F merge_many_buff(MI_SORT_PARAM *info,uint keys,
@@ -70,7 +72,6 @@ static int NEAR_F merge_buffers(MI_SORT_PARAM *info,uint keys,
BUFFPEK *Fb, BUFFPEK *Tb);
static int NEAR_F merge_index(MI_SORT_PARAM *,uint,uchar **,BUFFPEK *, int,
IO_CACHE *);
-static char **make_char_array(uint fields,uint length,myf my_flag);
/* Creates a index of sorted keys */
/* Returns 0 if everything went ok */
@@ -80,15 +81,17 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages,
{
int error,maxbuffer,skr;
uint memavl,old_memavl,keys,sort_length;
- BUFFPEK *buffpek;
+ DYNAMIC_ARRAY buffpek;
ha_rows records;
uchar **sort_keys;
- IO_CACHE tempfile;
+ IO_CACHE tempfile, tempfile_for_exceptions;
DBUG_ENTER("_create_index_by_sort");
DBUG_PRINT("enter",("sort_length: %d", info->key_length));
my_b_clear(&tempfile);
- buffpek= (BUFFPEK *) NULL; sort_keys= (uchar **) NULL; error= 1;
+ my_b_clear(&tempfile_for_exceptions);
+ bzero((char*) &buffpek,sizeof(buffpek));
+ sort_keys= (uchar **) NULL; error= 1;
maxbuffer=1;
memavl=max(sortbuff_size,MIN_SORT_MEMORY);
@@ -116,14 +119,14 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages,
}
while ((maxbuffer= (int) (records/(keys-1)+1)) != skr);
- if ((sort_keys= (uchar **) make_char_array(keys,sort_length,MYF(0))))
+ if ((sort_keys=(uchar **)my_malloc(keys*(sort_length+sizeof(char*))+
+ HA_FT_MAXLEN, MYF(0))))
{
- if ((buffpek = (BUFFPEK*) my_malloc((uint) (sizeof(BUFFPEK)*
- (uint) maxbuffer),
- MYF(0))))
- break;
- else
+ if (init_dynamic_array(&buffpek, sizeof(BUFFPEK), maxbuffer,
+ maxbuffer/2))
my_free((gptr) sort_keys,MYF(0));
+ else
+ break;
}
old_memavl=memavl;
if ((memavl=memavl/4*3) < MIN_SORT_MEMORY && old_memavl > MIN_SORT_MEMORY)
@@ -139,7 +142,8 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages,
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))
+ if ((records=find_all_keys(info,keys,sort_keys,&buffpek,&maxbuffer,
+ &tempfile,&tempfile_for_exceptions))
== HA_POS_ERROR)
goto err; /* purecov: tested */
if (maxbuffer == 0)
@@ -156,25 +160,51 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages,
{
if (!no_messages)
printf(" - Merging %lu keys\n",records); /* purecov: tested */
- if (merge_many_buff(info,keys,sort_keys,buffpek,&maxbuffer,&tempfile))
- goto err; /* purecov: inspected */
+ if (merge_many_buff(info,keys,sort_keys,
+ dynamic_element(&buffpek,0,BUFFPEK *),&maxbuffer,&tempfile))
+ goto err; /* purecov: inspected */
}
if (flush_io_cache(&tempfile) ||
reinit_io_cache(&tempfile,READ_CACHE,0L,0,0))
- goto err; /* purecov: inspected */
+ goto err; /* purecov: inspected */
if (!no_messages)
puts(" - Last merge and dumping keys"); /* purecov: tested */
- if (merge_index(info,keys,sort_keys,buffpek,maxbuffer,&tempfile))
- goto err; /* purecov: inspected */
+ if (merge_index(info,keys,sort_keys,dynamic_element(&buffpek,0,BUFFPEK *),
+ maxbuffer,&tempfile))
+ goto err; /* purecov: inspected */
}
+
+ if (flush_pending_blocks(info->sort_info->param))
+ goto err;
+
+ if (my_b_inited(&tempfile_for_exceptions))
+ {
+ MI_INFO *index=info->sort_info->info;
+ uint keyno=info->sort_info->key;
+ uint key_length, ref_length=index->s->rec_reflength;
+
+ if (flush_io_cache(&tempfile_for_exceptions) ||
+ reinit_io_cache(&tempfile_for_exceptions,READ_CACHE,0L,0,0))
+ goto err;
+
+ while (!my_b_read(&tempfile_for_exceptions,(byte*)&key_length,
+ sizeof(key_length))
+ && !my_b_read(&tempfile_for_exceptions,(byte*)sort_keys,
+ (uint) key_length))
+ {
+ if (_mi_ck_write(index,keyno,(uchar*) sort_keys,key_length-ref_length))
+ goto err;
+ }
+ }
+
error =0;
err:
if (sort_keys)
my_free((gptr) sort_keys,MYF(0));
- if (buffpek)
- my_free((gptr) buffpek,MYF(0));
+ delete_dynamic(&buffpek);
close_cached_file(&tempfile);
+ close_cached_file(&tempfile_for_exceptions);
DBUG_RETURN(error ? -1 : 0);
} /* _create_index_by_sort */
@@ -183,36 +213,51 @@ err:
/* Search after all keys and place them in a temp. file */
static ha_rows NEAR_F find_all_keys(MI_SORT_PARAM *info, uint keys,
- uchar **sort_keys, BUFFPEK *buffpek,
- int *maxbuffer, IO_CACHE *tempfile)
+ uchar **sort_keys, DYNAMIC_ARRAY *buffpek,
+ int *maxbuffer, IO_CACHE *tempfile,
+ IO_CACHE *tempfile_for_exceptions)
{
int error;
- uint idx,indexpos;
+ uint idx;
DBUG_ENTER("find_all_keys");
- idx=indexpos=error=0;
+ idx=error=0;
+ sort_keys[0]=(uchar*) (sort_keys+keys);
- while (!(error=(*info->key_read)(info->sort_info,sort_keys[idx])))
+ while(!(error=(*info->key_read)(info->sort_info,sort_keys[idx])))
{
- if ((uint) ++idx == keys)
+ if (info->sort_info->real_key_length > info->key_length)
{
- if (indexpos >= (uint) *maxbuffer ||
- write_keys(info,sort_keys,idx-1,buffpek+indexpos,tempfile))
- DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
+ if (write_key(info,sort_keys[idx],tempfile_for_exceptions))
+ DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
+ continue;
+ }
+
+ if (++idx == keys)
+ {
+ if (write_keys(info,sort_keys,idx-1,(BUFFPEK *)alloc_dynamic(buffpek),
+ tempfile))
+ DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
+
+ sort_keys[0]=(uchar*) (sort_keys+keys);
memcpy(sort_keys[0],sort_keys[idx-1],(size_t) info->key_length);
- idx=1; indexpos++;
+ idx=1;
}
+ sort_keys[idx]=sort_keys[idx-1]+info->key_length;
}
if (error > 0)
DBUG_RETURN(HA_POS_ERROR); /* Aborted by get_key */ /* purecov: inspected */
- if (indexpos)
- if (indexpos >= (uint) *maxbuffer ||
- write_keys(info,sort_keys,idx,buffpek+indexpos,tempfile))
- DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
- *maxbuffer=(int) indexpos;
- DBUG_RETURN(indexpos*(keys-1)+idx);
-} /* find_all_keys */
+ if (buffpek->elements)
+ {
+ if (write_keys(info,sort_keys,idx,(BUFFPEK *)alloc_dynamic(buffpek),tempfile))
+ DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
+ *maxbuffer=buffpek->elements-1;
+ }
+ else
+ *maxbuffer=0;
+ DBUG_RETURN((*maxbuffer)*(keys-1)+idx);
+} /* find_all_keys */
/* Write all keys in memory to file for later merge */
@@ -225,11 +270,12 @@ static int NEAR_F write_keys(MI_SORT_PARAM *info, register uchar **sort_keys,
DBUG_ENTER("write_keys");
qsort2((byte*) sort_keys,count,sizeof(byte*),(qsort2_cmp) info->key_cmp,
- info->sort_info);
+ info->sort_info);
if (!my_b_inited(tempfile) &&
open_cached_file(tempfile, info->tmpdir, "ST", DISK_BUFFER_SIZE,
info->myf_rw))
DBUG_RETURN(1); /* purecov: inspected */
+
buffpek->file_pos=my_b_tell(tempfile);
buffpek->count=count;
@@ -240,6 +286,22 @@ static int NEAR_F write_keys(MI_SORT_PARAM *info, register uchar **sort_keys,
} /* write_keys */
+static int NEAR_F write_key(MI_SORT_PARAM *info, uchar *key, IO_CACHE *tempfile)
+{
+ uint key_length=info->sort_info->real_key_length;
+ DBUG_ENTER("write_key");
+
+ if (!my_b_inited(tempfile) &&
+ open_cached_file(tempfile, info->tmpdir, "ST", DISK_BUFFER_SIZE,
+ info->myf_rw))
+ DBUG_RETURN(1);
+
+ if (my_b_write(tempfile,(byte*)&key_length,sizeof(key_length)) ||
+ my_b_write(tempfile,(byte*)key,(uint) key_length))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+} /* write_key */
+
/* Write index */
static int NEAR_F write_index(MI_SORT_PARAM *info, register uchar **sort_keys,
@@ -329,7 +391,7 @@ static uint NEAR_F read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek,
/* If to_file == 0 then use info->key_write */
static int NEAR_F
-merge_buffers(MI_SORT_PARAM *info, uint keys, IO_CACHE *from_file,
+merge_buffers(MI_SORT_PARAM *info, uint keys, IO_CACHE *from_file,
IO_CACHE *to_file, uchar **sort_keys, BUFFPEK *lastbuff,
BUFFPEK *Fb, BUFFPEK *Tb)
{
@@ -475,21 +537,3 @@ merge_index(MI_SORT_PARAM *info, uint keys, uchar **sort_keys,
DBUG_RETURN(0);
} /* merge_index */
-
- /* Make a pointer of arrays to keys */
-
-static char **make_char_array(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 */
diff --git a/myisammrg/Makefile.am b/myisammrg/Makefile.am
index b09d7d70191..5355534eb77 100644
--- a/myisammrg/Makefile.am
+++ b/myisammrg/Makefile.am
@@ -16,12 +16,12 @@
INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include -I../include
pkglib_LIBRARIES = libmyisammrg.a
-noinst_HEADERS = mymrgdef.h
+noinst_HEADERS = myrg_def.h
libmyisammrg_a_SOURCES = myrg_open.c myrg_extra.c myrg_info.c myrg_locking.c \
myrg_rrnd.c myrg_update.c myrg_delete.c myrg_rsame.c \
myrg_panic.c myrg_close.c myrg_create.c myrg_static.c \
myrg_rkey.c myrg_rfirst.c myrg_rlast.c myrg_rnext.c \
- myrg_rprev.c myrg_queue.c
+ myrg_rprev.c myrg_queue.c myrg_write.c
OMIT_DEPENDENCIES = pthread.h stdio.h __stdio.h stdlib.h __stdlib.h math.h\
__math.h time.h __time.h unistd.h __unistd.h types.h \
xtypes.h ac-types.h posix.h string.h __string.h \
diff --git a/myisammrg/myrg_close.c b/myisammrg/myrg_close.c
index 7ab73c5ded4..897020c6865 100644
--- a/myisammrg/myrg_close.c
+++ b/myisammrg/myrg_close.c
@@ -1,22 +1,22 @@
/* 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 "mymrgdef.h"
+#include "myrg_def.h"
int myrg_close(MYRG_INFO *info)
{
diff --git a/myisammrg/myrg_create.c b/myisammrg/myrg_create.c
index 113831b9d7f..5fc3c60ff32 100644
--- a/myisammrg/myrg_create.c
+++ b/myisammrg/myrg_create.c
@@ -1,29 +1,30 @@
/* 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 MYMERGE_-file */
-#include "mymrgdef.h"
+#include "myrg_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 myrg_create(const char *name, const char **table_names, my_bool fix_names)
+int myrg_create(const char *name, const char **table_names,
+ uint insert_method, my_bool fix_names)
{
int save_errno;
uint errpos;
@@ -50,6 +51,13 @@ int myrg_create(const char *name, const char **table_names, my_bool fix_names)
goto err;
}
}
+ if (insert_method != MERGE_INSERT_DISABLED)
+ {
+ end=strxmov(buff,"#INSERT_METHOD=",
+ get_type(&merge_insert_method,insert_method-1),"\n",NullS);
+ if (my_write(file,buff,(uint) (end-buff),MYF(MY_WME | MY_NABP)))
+ goto err;
+ }
if (my_close(file,MYF(0)))
goto err;
DBUG_RETURN(0);
diff --git a/myisammrg/mymrgdef.h b/myisammrg/myrg_def.h
index aae1d07cd64..d56cf4aa8d8 100644
--- a/myisammrg/mymrgdef.h
+++ b/myisammrg/myrg_def.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 */
diff --git a/myisammrg/myrg_delete.c b/myisammrg/myrg_delete.c
index 9ac32655172..94fa9835d3d 100644
--- a/myisammrg/myrg_delete.c
+++ b/myisammrg/myrg_delete.c
@@ -1,22 +1,22 @@
/* 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 */
/* Delete last read record */
-#include "mymrgdef.h"
+#include "myrg_def.h"
int myrg_delete(
MYRG_INFO *info,
diff --git a/myisammrg/myrg_extra.c b/myisammrg/myrg_extra.c
index c8a634e748f..5434d30a50e 100644
--- a/myisammrg/myrg_extra.c
+++ b/myisammrg/myrg_extra.c
@@ -20,7 +20,7 @@
record-cache-flags are set in myrg_rrnd when we are changing database.
*/
-#include "mymrgdef.h"
+#include "myrg_def.h"
int myrg_extra(MYRG_INFO *info,enum ha_extra_function function)
{
@@ -46,3 +46,14 @@ int myrg_extra(MYRG_INFO *info,enum ha_extra_function function)
}
DBUG_RETURN(save_error);
}
+
+void myrg_extrafunc(MYRG_INFO *info, invalidator_by_filename inv)
+{
+ MYRG_TABLE *file;
+ DBUG_ENTER("myrg_extrafunc");
+
+ for (file=info->open_tables ; file != info->end_table ; file++)
+ file->table->s->invalidator = inv;
+
+ DBUG_VOID_RETURN;
+}
diff --git a/myisammrg/myrg_info.c b/myisammrg/myrg_info.c
index 8ca830339b9..14bc228cc1f 100644
--- a/myisammrg/myrg_info.c
+++ b/myisammrg/myrg_info.c
@@ -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 */
-#include "mymrgdef.h"
+#include "myrg_def.h"
ulonglong myrg_position(MYRG_INFO *info)
{
diff --git a/myisammrg/myrg_locking.c b/myisammrg/myrg_locking.c
index c89acca3918..41c972f72c0 100644
--- a/myisammrg/myrg_locking.c
+++ b/myisammrg/myrg_locking.c
@@ -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 */
@@ -18,7 +18,7 @@
Lock databases against read or write.
*/
-#include "mymrgdef.h"
+#include "myrg_def.h"
int myrg_lock_database(
MYRG_INFO *info,
diff --git a/myisammrg/myrg_open.c b/myisammrg/myrg_open.c
index df94fb680cb..668744442a6 100644
--- a/myisammrg/myrg_open.c
+++ b/myisammrg/myrg_open.c
@@ -14,29 +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 */
-/* open a MYMERGE_-database */
+/* open a MyISAM MERGE table */
-#include "mymrgdef.h"
+#include "myrg_def.h"
#include <stddef.h>
#include <errno.h>
#ifdef VMS
#include "mrg_static.c"
#endif
-/* open a MYMERGE_-database.
-
+/*
+ open a MyISAM MERGE table
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
*/
-MYRG_INFO *myrg_open(
-const char *name,
-int mode,
-int handle_locking)
+MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking)
{
int save_errno,i,errpos;
- uint files,dir_length,length;
+ uint files,dir_length,length,options;
ulonglong file_offset;
char name_buff[FN_REFLEN*2],buff[FN_REFLEN],*end;
MYRG_INFO info,*m_info;
@@ -63,25 +60,34 @@ int handle_locking)
{
if ((end=buff+length)[-1] == '\n')
end[-1]='\0';
- if (buff[0] && buff[0] != '#') /* Skipp empty lines and comments */
+ if (!buff[0])
+ continue; /* Skip empty lines */
+ if (buff[0] == '#')
{
- 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( !strncmp(buff+1,"INSERT_METHOD=",14))
+ { /* Lookup insert method */
+ int tmp=find_type(buff+15,&merge_insert_method,2);
+ info.merge_insert_method = (uint) (tmp >= 0 ? tmp : 0);
}
- if (!(isam=mi_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;
+ continue; /* Skip comments */
+ }
+
+ 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=mi_open(buff,mode,test(handle_locking))))
goto err;
- }
- info.reclength=isam->s->base.reclength;
+ 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= (MYRG_INFO*) my_malloc(sizeof(MYRG_INFO)+
files*sizeof(MYRG_TABLE),
@@ -92,16 +98,22 @@ int handle_locking)
m_info->tables=files;
errpos=2;
+ options= (uint) ~0;
for (i=files ; i-- > 0 ; )
{
m_info->open_tables[i].table=isam;
m_info->options|=isam->s->options;
+ options&=isam->s->options;
m_info->records+=isam->state->records;
m_info->del+=isam->state->del;
m_info->data_file_length+=isam->state->data_file_length;
if (i)
isam=(MI_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++)
diff --git a/myisammrg/myrg_panic.c b/myisammrg/myrg_panic.c
index 99a1f6828d1..ab08b8082c3 100644
--- a/myisammrg/myrg_panic.c
+++ b/myisammrg/myrg_panic.c
@@ -1,20 +1,20 @@
/* 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 "mymrgdef.h"
+#include "myrg_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
diff --git a/myisammrg/myrg_queue.c b/myisammrg/myrg_queue.c
index d6f831db48c..b4f729fc2cf 100644
--- a/myisammrg/myrg_queue.c
+++ b/myisammrg/myrg_queue.c
@@ -16,7 +16,7 @@
/* Read record based on a key */
-#include "mymrgdef.h"
+#include "myrg_def.h"
static int queue_key_cmp(void *keyseg, byte *a, byte *b)
{
diff --git a/myisammrg/myrg_rfirst.c b/myisammrg/myrg_rfirst.c
index 0625e848660..2ee9c015a84 100644
--- a/myisammrg/myrg_rfirst.c
+++ b/myisammrg/myrg_rfirst.c
@@ -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 */
-#include "mymrgdef.h"
+#include "myrg_def.h"
/* Read first row according to specific key */
diff --git a/myisammrg/myrg_rkey.c b/myisammrg/myrg_rkey.c
index cd2c73c8ec2..ba042352a51 100644
--- a/myisammrg/myrg_rkey.c
+++ b/myisammrg/myrg_rkey.c
@@ -27,7 +27,7 @@
*/
-#include "mymrgdef.h"
+#include "myrg_def.h"
/* todo: we could store some additional info to speedup lookups:
column (key, keyseg) can be constant per table
diff --git a/myisammrg/myrg_rlast.c b/myisammrg/myrg_rlast.c
index f41844dfd5c..e03a07c295a 100644
--- a/myisammrg/myrg_rlast.c
+++ b/myisammrg/myrg_rlast.c
@@ -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 */
-#include "mymrgdef.h"
+#include "myrg_def.h"
/* Read last row with the same key as the previous read. */
diff --git a/myisammrg/myrg_rnext.c b/myisammrg/myrg_rnext.c
index 5a3fbdfb299..abb9ef95e44 100644
--- a/myisammrg/myrg_rnext.c
+++ b/myisammrg/myrg_rnext.c
@@ -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 */
-#include "mymrgdef.h"
+#include "myrg_def.h"
/*
Read next row with the same key as previous read
diff --git a/myisammrg/myrg_rprev.c b/myisammrg/myrg_rprev.c
index d8089e80498..bd7e6a1f6d2 100644
--- a/myisammrg/myrg_rprev.c
+++ b/myisammrg/myrg_rprev.c
@@ -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 */
-#include "mymrgdef.h"
+#include "myrg_def.h"
/*
Read previous row with the same key as previous read
diff --git a/myisammrg/myrg_rrnd.c b/myisammrg/myrg_rrnd.c
index de731e58d5b..d50d077e6ba 100644
--- a/myisammrg/myrg_rrnd.c
+++ b/myisammrg/myrg_rrnd.c
@@ -19,7 +19,7 @@
get by myrg_info(). The next record can be read with pos= -1 */
-#include "mymrgdef.h"
+#include "myrg_def.h"
static MYRG_TABLE *find_table(MYRG_TABLE *start,MYRG_TABLE *end,ulonglong pos);
diff --git a/myisammrg/myrg_rsame.c b/myisammrg/myrg_rsame.c
index 301b96e667b..ddc77f85913 100644
--- a/myisammrg/myrg_rsame.c
+++ b/myisammrg/myrg_rsame.c
@@ -1,20 +1,20 @@
/* 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 "mymrgdef.h"
+#include "myrg_def.h"
int myrg_rsame(MYRG_INFO *info,byte *record,int inx)
{
diff --git a/myisammrg/myrg_static.c b/myisammrg/myrg_static.c
index 88eb095382b..b21b834ac24 100644
--- a/myisammrg/myrg_static.c
+++ b/myisammrg/myrg_static.c
@@ -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 */
@@ -20,7 +20,11 @@
*/
#ifndef stdin
-#include "mymrgdef.h"
+#include "myrg_def.h"
#endif
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};
diff --git a/myisammrg/myrg_update.c b/myisammrg/myrg_update.c
index b75c6ea6f9b..cb1b0b51ef9 100644
--- a/myisammrg/myrg_update.c
+++ b/myisammrg/myrg_update.c
@@ -1,22 +1,22 @@
/* 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 "mymrgdef.h"
+#include "myrg_def.h"
int myrg_update(register MYRG_INFO *info,const byte *oldrec, byte *newrec)
{
diff --git a/myisammrg/myrg_write.c b/myisammrg/myrg_write.c
new file mode 100644
index 00000000000..4e597005503
--- /dev/null
+++ b/myisammrg/myrg_write.c
@@ -0,0 +1,30 @@
+/* Copyright (C) 2001 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 a row to a MyISAM MERGE table */
+
+#include "myrg_def.h"
+
+int myrg_write(register MYRG_INFO *info, byte *rec)
+{
+ /* [phi] MERGE_WRITE_DISABLED is handled by the else case */
+ if (info->merge_insert_method == MERGE_INSERT_TO_FIRST)
+ return mi_write(info->open_tables[0].table,rec);
+ else if (info->merge_insert_method == MERGE_INSERT_TO_LAST)
+ return mi_write(info->end_table[-1].table,rec);
+ else /* unsupported insertion method */
+ return (my_errno=HA_ERR_WRONG_COMMAND);
+}
diff --git a/mysql-test/Makefile.am b/mysql-test/Makefile.am
index d98c10a29a9..91333dfad9b 100644
--- a/mysql-test/Makefile.am
+++ b/mysql-test/Makefile.am
@@ -59,6 +59,8 @@ SUFFIXES = .sh
-e 's!@''libexecdir''@!$(libexecdir)!g' \
-e 's!@''PERL''@!@PERL@!' \
-e 's!@''VERSION''@!@VERSION@!' \
+ -e 's!@''MYSQL_BASE_VERSION''@!@MYSQL_BASE_VERSION@!' \
+ -e 's!@''MYSQL_NO_DASH_VERSION''@!@MYSQL_NO_DASH_VERSION@!' \
-e 's!@''MYSQL_SERVER_SUFFIX''@!@MYSQL_SERVER_SUFFIX@!' \
$< > $@-t
@CHMOD@ +x $@-t
diff --git a/mysql-test/create-test-result b/mysql-test/create-test-result
index 24c3d175303..bfd64f32fc5 100755
--- a/mysql-test/create-test-result
+++ b/mysql-test/create-test-result
@@ -5,7 +5,7 @@
# If you have a spare moment feel free to improve it - the right way is
# to start mysqld yourself and run mysqltest -r
-RESULT_DIR=r/3.23
+RESULT_DIR=r
if [ -z $EDITOR] ; then
EDITOR=vi
fi
@@ -32,7 +32,7 @@ result_file=$RESULT_DIR/$test_name.result
touch $result_file
echo "Running the test case against empty file, will fail, but don't worry"
-./mysql-test-run $test_name
+./mysql-test-run --do-test=$test_name
reject_file=$result_file.reject
diff --git a/mysql-test/fix-result b/mysql-test/fix-result
new file mode 100755
index 00000000000..bd380332ff5
--- /dev/null
+++ b/mysql-test/fix-result
@@ -0,0 +1,22 @@
+#! /bin/sh
+
+# Sasha's hack to fix results generated with mysql-test-run --record
+# to be version and test port independent. In some cases, further minor
+# manual edititing may be required, but most of the time it should not
+# happen
+
+#It is assumed we are running the script in mysql-test directory
+
+VERSION=4.0.1-alpha-debug-log
+TEST_CASE=$1
+
+if [ -z "$TEST_CASE" ] ;
+then
+ echo "usage: $0 test_case_name"
+ exit 1
+fi
+
+../extra/replace $VERSION '$VERSION' 9306 '$MASTER_MYPORT' 9307 \
+'$SLAVE_MYPORT' \\ \\\\ -- r/$TEST_CASE.result
+
+
diff --git a/mysql-test/include/have_bdb.inc b/mysql-test/include/have_bdb.inc
index 0126e30210f..3f7377e7515 100644
--- a/mysql-test/include/have_bdb.inc
+++ b/mysql-test/include/have_bdb.inc
@@ -1,2 +1,4 @@
-- require r/have_bdb.require
+disable_query_log;
show variables like "have_bdb";
+enable_query_log;
diff --git a/mysql-test/include/have_gemini.inc b/mysql-test/include/have_gemini.inc
deleted file mode 100644
index 78a84ac6f3e..00000000000
--- a/mysql-test/include/have_gemini.inc
+++ /dev/null
@@ -1,2 +0,0 @@
--- require r/have_gemini.require
-show variables like "have_gemini";
diff --git a/mysql-test/include/have_innodb.inc b/mysql-test/include/have_innodb.inc
index 7dcaef44878..4f83d378cbc 100644
--- a/mysql-test/include/have_innodb.inc
+++ b/mysql-test/include/have_innodb.inc
@@ -1,2 +1,4 @@
-- require r/have_innodb.require
+disable_query_log;
show variables like "have_innodb";
+enable_query_log;
diff --git a/mysql-test/include/have_isam.inc b/mysql-test/include/have_isam.inc
index d83328f70f4..830170c921f 100644
--- a/mysql-test/include/have_isam.inc
+++ b/mysql-test/include/have_isam.inc
@@ -1,2 +1,4 @@
-- require r/have_isam.require
+disable_query_log;
show variables like "have_isam";
+enable_query_log;
diff --git a/mysql-test/include/have_openssl.inc b/mysql-test/include/have_openssl.inc
new file mode 100644
index 00000000000..54c5b04b3e4
--- /dev/null
+++ b/mysql-test/include/have_openssl.inc
@@ -0,0 +1,4 @@
+-- require r/have_openssl.require
+disable_query_log;
+show variables like "have_openssl";
+enable_query_log;
diff --git a/mysql-test/include/have_openssl_1.inc b/mysql-test/include/have_openssl_1.inc
new file mode 100644
index 00000000000..4d3646abdc2
--- /dev/null
+++ b/mysql-test/include/have_openssl_1.inc
@@ -0,0 +1,4 @@
+-- require r/have_openssl_1.require
+disable_query_log;
+show variables like "have_openssl";
+enable_query_log;
diff --git a/mysql-test/include/have_openssl_2.inc b/mysql-test/include/have_openssl_2.inc
new file mode 100644
index 00000000000..724d295a398
--- /dev/null
+++ b/mysql-test/include/have_openssl_2.inc
@@ -0,0 +1,4 @@
+-- require r/have_openssl_2.require
+disable_query_log;
+SHOW STATUS LIKE "SSL_get_cipher";
+enable_query_log;
diff --git a/mysql-test/include/master-slave.inc b/mysql-test/include/master-slave.inc
index 61077f898f6..23392690239 100644
--- a/mysql-test/include/master-slave.inc
+++ b/mysql-test/include/master-slave.inc
@@ -1,8 +1,9 @@
-connect (master,localhost,root,,test,0,mysql-master.sock);
-connect (master1,localhost,root,,test,0,mysql-master.sock);
-connect (slave,localhost,root,,test,0,mysql-slave.sock);
-connect (slave1,localhost,root,,test,0,mysql-slave.sock);
+connect (master,127.0.0.1,root,,test,$MASTER_MYPORT,);
+connect (master1,127.0.0.1,root,,test,$MASTER_MYPORT,);
+connect (slave,127.0.0.1,root,,test,$SLAVE_MYPORT,);
+connect (slave1,127.0.0.1,root,,test,$SLAVE_MYPORT,);
connection slave;
+--error 0,1199
!slave stop;
@r/slave-stopped.result show status like 'Slave_running';
connection master;
diff --git a/mysql-test/include/not_embedded.inc b/mysql-test/include/not_embedded.inc
new file mode 100644
index 00000000000..52ae026ece3
--- /dev/null
+++ b/mysql-test/include/not_embedded.inc
@@ -0,0 +1,5 @@
+-- require r/not_embedded.require
+disable_query_log;
+select version() like "%embedded%" as "have_embedded";
+enable_query_log;
+
diff --git a/mysql-test/install_test_db.sh b/mysql-test/install_test_db.sh
index 6fe736644d3..acf8cebc723 100644
--- a/mysql-test/install_test_db.sh
+++ b/mysql-test/install_test_db.sh
@@ -30,7 +30,7 @@ else
fi
mdata=$data/mysql
-
+EXTRA_ARG=""
if test ! -x $execdir/mysqld
then
@@ -57,9 +57,7 @@ if [ x$BINARY_DIST = x1 ] ; then
basedir=..
else
basedir=.
-rm -rf share
-mkdir share
-ln -f -s ../../sql/share share/mysql
+EXTRA_ARG="--language=../sql/share/english/"
fi
# Initialize variables
@@ -136,16 +134,20 @@ then
c_u="$c_u References_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
c_u="$c_u Index_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
c_u="$c_u Alter_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_u="$c_u ssl_type enum('NONE','ANY', 'X509', 'SPECIFIED') NOT NULL,"
+ c_u="$c_u ssl_cipher char(60) NULL,"
+ c_u="$c_u x509_issuer blob NULL,"
+ c_u="$c_u x509_subject blob NULL,"
c_u="$c_u PRIMARY KEY Host (Host,User)"
c_u="$c_u )"
c_u="$c_u comment='Users and global privileges';"
- i_u="INSERT INTO user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
- INSERT INTO user VALUES ('$hostname','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
- REPLACE INTO user VALUES ('127.0.0.1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
+ i_u="INSERT INTO user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','none',NULL,NULL,NULL);
+ INSERT INTO user VALUES ('$hostname','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','none',NULL,NULL,NULL);
+ REPLACE INTO user VALUES ('127.0.0.1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','none',NULL,NULL,NULL);
- INSERT INTO user VALUES ('localhost','','','N','N','N','N','N','N','N','N','N','N','N','N','N','N');
- INSERT INTO user VALUES ('$hostname','','','N','N','N','N','N','N','N','N','N','N','N','N','N','N');"
+ INSERT INTO user VALUES ('localhost','','','N','N','N','N','N','N','N','N','N','N','N','N','N','N','none',NULL,NULL,NULL);
+ INSERT INTO user VALUES ('$hostname','','','N','N','N','N','N','N','N','N','N','N','N','N','N','N','none',NULL,NULL,NULL);"
fi
if test ! -f $mdata/func.frm
@@ -192,8 +194,11 @@ then
c_c="$c_c comment='Column privileges';"
fi
-if $execdir/mysqld --no-defaults --bootstrap --skip-grant-tables \
- --basedir=$basedir --datadir=$ldata --skip-innodb --skip-bdb --skip-gemini << END_OF_DATA
+mysqld_boot=" $execdir/mysqld --no-defaults --bootstrap --skip-grant-tables \
+ --basedir=$basedir --datadir=$ldata --skip-innodb --skip-bdb $EXTRA_ARG"
+echo "running $mysqld_boot"
+
+if $mysqld_boot << END_OF_DATA
use mysql;
$c_d
$i_d
@@ -213,5 +218,6 @@ END_OF_DATA
then
exit 0
else
+ echo "Error executing mysqld --boostrap"
exit 1
fi
diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh
index 4898d9c5464..efebc5b5c86 100644
--- a/mysql-test/mysql-test-run.sh
+++ b/mysql-test/mysql-test-run.sh
@@ -12,13 +12,15 @@
DB=test
DBPASSWD=
VERBOSE=""
+USE_MANAGER=0
TZ=GMT-3; export TZ # for UNIX_TIMESTAMP tests to work
#++
# Program Definitions
#--
-PATH=/bin:/usr/bin:/usr/local/bin:/usr/bsd:/usr/X11R6/bin
+PATH=/bin:/usr/bin:/usr/local/bin:/usr/bsd:/usr/X11R6/bin:/usr/openwin/bin
+MASTER_40_ARGS="--rpl-recovery-rank=1 --init-rpl-role=master"
# Standard functions
@@ -42,6 +44,39 @@ which ()
}
+sleep_until_file_deleted ()
+{
+ file=$1
+ loop=$SLEEP_TIME_FOR_DELETE
+ while (test $loop -gt 0)
+ do
+ if [ ! -r $file ]
+ then
+ sleep $SLEEP_TIME_AFTER_RESTART
+ return
+ fi
+ loop=`expr $loop - 1`
+ done
+}
+
+sleep_until_file_created ()
+{
+ file=$1
+ loop=$2
+ org_time=$2
+ while (test $loop -gt 0)
+ do
+ if [ -r $file ]
+ then
+ return
+ fi
+ sleep 1
+ loop=`expr $loop - 1`
+ done
+ echo "ERROR: $file was not created in $org_time seconds; Aborting"
+ exit 1;
+}
+
# No paths below as we can't be sure where the program is!
SED=sed
@@ -50,6 +85,7 @@ BASENAME=`which basename | $SED q`
DIFF=`which diff | $SED q`
CAT=cat
CUT=cut
+HEAD=head
TAIL=tail
ECHO=echo # use internal echo if possible
EXPR=expr # use internal if possible
@@ -90,7 +126,7 @@ else
BINARY_DIST=1
fi
-#BASEDIR is always one above mysql-test directory
+#BASEDIR is always one above mysql-test directory
CWD=`pwd`
cd ..
BASEDIR=`pwd`
@@ -99,7 +135,8 @@ MYSQL_TEST_DIR=$BASEDIR/mysql-test
export MYSQL_TEST_DIR
STD_DATA=$MYSQL_TEST_DIR/std_data
hostname=`hostname` # Installed in the mysql privilege table
-
+
+MANAGER_QUIET_OPT="-q"
TESTDIR="$MYSQL_TEST_DIR/t"
TESTSUFFIX=test
TOT_SKIP=0
@@ -114,16 +151,21 @@ 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 \
myisammrg heap sql"
+MY_LOG_DIR="$MYSQL_TEST_DIR/var/log"
#
# Set LD_LIBRARY_PATH if we are using shared libraries
#
-LD_LIBRARY_PATH="$BASEDIR/lib:$LD_LIBRARY_PATH"
+LD_LIBRARY_PATH="$BASEDIR/lib:$BASEDIR/libmysql/.libs:$LD_LIBRARY_PATH"
export LD_LIBRARY_PATH
MASTER_RUNNING=0
MASTER_MYPORT=9306
SLAVE_RUNNING=0
SLAVE_MYPORT=9307
+MYSQL_MANAGER_PORT=9305 # needs to be out of the way of slaves
+MYSQL_MANAGER_PW_FILE=$MYSQL_TEST_DIR/var/tmp/manager.pwd
+MYSQL_MANAGER_LOG=$MYSQL_TEST_DIR/var/log/manager.log
+MYSQL_MANAGER_USER=root
NO_SLAVE=0
USER_TEST=
@@ -132,19 +174,40 @@ EXTRA_MYSQL_TEST_OPT=""
USE_RUNNING_SERVER=1
DO_GCOV=""
DO_GDB=""
+MANUAL_GDB=""
DO_DDD=""
DO_CLIENT_GDB=""
-SLEEP_TIME=2
+SLEEP_TIME_AFTER_RESTART=1
+SLEEP_TIME_FOR_DELETE=10
+SLEEP_TIME_FOR_FIRST_MASTER=400 # Enough time to create innodb tables
+SLEEP_TIME_FOR_SECOND_MASTER=30
+SLEEP_TIME_FOR_FIRST_SLAVE=400
+SLEEP_TIME_FOR_SECOND_SLAVE=30
+CHARACTER_SET=latin1
DBUSER=""
+START_WAIT_TIMEOUT=10
+STOP_WAIT_TIMEOUT=10
while test $# -gt 0; do
case "$1" in
--user=*) DBUSER=`$ECHO "$1" | $SED -e "s;--user=;;"` ;;
--force) FORCE=1 ;;
+ --verbose-manager) MANAGER_QUIET_OPT="" ;;
+ --old-master) MASTER_40_ARGS="";;
+ --master-binary=*)
+ MASTER_MYSQLD=`$ECHO "$1" | $SED -e "s;--master-binary=;;"` ;;
+ --slave-binary=*)
+ SLAVE_MYSQLD=`$ECHO "$1" | $SED -e "s;--slave-binary=;;"` ;;
--local) USE_RUNNING_SERVER="" ;;
--tmpdir=*) MYSQL_TMP_DIR=`$ECHO "$1" | $SED -e "s;--tmpdir=;;"` ;;
+ --local-master)
+ MASTER_MYPORT=3306;
+ EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT --host=127.0.0.1 \
+ --port=$MYSQL_MYPORT"
+ LOCAL_MASTER=1 ;;
--master_port=*) MASTER_MYPORT=`$ECHO "$1" | $SED -e "s;--master_port=;;"` ;;
--slave_port=*) SLAVE_MYPORT=`$ECHO "$1" | $SED -e "s;--slave_port=;;"` ;;
+ --manager-port=*) MYSQL_MANAGER_PORT=`$ECHO "$1" | $SED -e "s;--manager_port=;;"` ;;
--with-openssl)
EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT \
--ssl-ca=$BASEDIR/SSL/cacert.pem \
@@ -154,27 +217,40 @@ while test $# -gt 0; do
--ssl-ca=$BASEDIR/SSL/cacert.pem \
--ssl-cert=$BASEDIR/SSL/server-cert.pem \
--ssl-key=$BASEDIR/SSL/server-key.pem" ;;
- --skip-innobase)
- EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --skip-innobase"
- EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --skip-innobase" ;;
+ --no-manager | --skip-manager) USE_MANAGER=0 ;;
+ --manager)
+ USE_MANAGER=1
+ USE_RUNNING_SERVER=
+ ;;
+ --start-and-exit)
+ START_AND_EXIT=1
+ ;;
+ --skip-innodb)
+ EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --skip-innodb"
+ EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --skip-innodb" ;;
--skip-bdb)
EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --skip-bdb"
EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --skip-bdb" ;;
--skip-rpl) NO_SLAVE=1 ;;
--skip-test=*) SKIP_TEST=`$ECHO "$1" | $SED -e "s;--skip-test=;;"`;;
--do-test=*) DO_TEST=`$ECHO "$1" | $SED -e "s;--do-test=;;"`;;
+ --wait-timeout=*)
+ START_WAIT_TIMEOUT=`$ECHO "$1" | $SED -e "s;--wait-timeout=;;"`
+ STOP_WAIT_TIMEOUT=$START_WAIT_TIMEOUT;;
--record)
RECORD=1;
EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT $1" ;;
--bench)
DO_BENCH=1
NO_SLAVE=1
- ;;
+ ;;
--big*) # Actually --big-test
EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT $1" ;;
+ --compress)
+ EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT $1" ;;
--sleep=*)
EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT $1"
- SLEEP_TIME=`$ECHO "$1" | $SED -e "s;--sleep=;;"`
+ SLEEP_TIME_AFTER_RESTART=`$ECHO "$1" | $SED -e "s;--sleep=;;"`
;;
--user-test=*)
USER_TEST=`$ECHO "$1" | $SED -e "s;--user-test=;;"`
@@ -193,12 +269,16 @@ while test $# -gt 0; do
;;
--gprof )
DO_GPROF=1
- ;;
+ ;;
--gdb )
+ START_WAIT_TIMEOUT=300
+ STOP_WAIT_TIMEOUT=300
if [ x$BINARY_DIST = x1 ] ; then
$ECHO "Note: you will get more meaningful output on a source distribution compiled with debugging option when running tests with --gdb option"
fi
DO_GDB=1
+ # This needs to be checked properly
+ # USE_MANAGER=1
USE_RUNNING_SERVER=""
;;
--client-gdb )
@@ -207,6 +287,11 @@ while test $# -gt 0; do
fi
DO_CLIENT_GDB=1
;;
+ --manual-gdb )
+ DO_GDB=1
+ MANUAL_GDB=1
+ USE_RUNNING_SERVER=""
+ ;;
--ddd )
if [ x$BINARY_DIST = x1 ] ; then
$ECHO "Note: you will get more meaningful output on a source distribution compiled with debugging option when running tests with --ddd option"
@@ -218,6 +303,9 @@ while test $# -gt 0; do
EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT $1"
EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT $1"
;;
+ --strace-client )
+ STRACE_CLIENT=1
+ ;;
--debug)
EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT \
--debug=d:t:i:O,$MYSQL_TEST_DIR/var/log/master.trace"
@@ -237,17 +325,19 @@ done
#--
MYRUN_DIR=$MYSQL_TEST_DIR/var/run
+MANAGER_PID_FILE="$MYRUN_DIR/manager.pid"
+
MASTER_MYDDIR="$MYSQL_TEST_DIR/var/master-data"
-MASTER_MYSOCK="$MYSQL_TMP_DIR/mysql-master.sock"
-MASTER_MYPID="$MYRUN_DIR/mysqld.pid"
-MASTER_MYLOG="$MYSQL_TEST_DIR/var/log/mysqld.log"
-MASTER_MYERR="$MYSQL_TEST_DIR/var/log/mysqld.err"
+MASTER_MYSOCK="$MYSQL_TMP_DIR/master.sock"
+MASTER_MYPID="$MYRUN_DIR/master.pid"
+MASTER_MYLOG="$MYSQL_TEST_DIR/var/log/master.log"
+MASTER_MYERR="$MYSQL_TEST_DIR/var/log/master.err"
SLAVE_MYDDIR="$MYSQL_TEST_DIR/var/slave-data"
-SLAVE_MYSOCK="$MYSQL_TMP_DIR/mysql-slave.sock"
-SLAVE_MYPID="$MYRUN_DIR/mysqld-slave.pid"
-SLAVE_MYLOG="$MYSQL_TEST_DIR/var/log/mysqld-slave.log"
-SLAVE_MYERR="$MYSQL_TEST_DIR/var/log/mysqld-slave.err"
+SLAVE_MYSOCK="$MYSQL_TMP_DIR/slave.sock"
+SLAVE_MYPID="$MYRUN_DIR/slave.pid"
+SLAVE_MYLOG="$MYSQL_TEST_DIR/var/log/slave.log"
+SLAVE_MYERR="$MYSQL_TEST_DIR/var/log/slave.err"
SMALL_SERVER="-O key_buffer_size=1M -O sort_buffer=256K -O max_heap_table_size=1M"
@@ -258,7 +348,7 @@ if [ x$SOURCE_DIST = x1 ] ; then
MY_BASEDIR=$MYSQL_TEST_DIR
else
MY_BASEDIR=$BASEDIR
-fi
+fi
# Create the directories
@@ -269,7 +359,7 @@ fi
[ -d $MYSQL_TEST_DIR/var/tmp ] || mkdir $MYSQL_TEST_DIR/var/tmp
[ -d $MYSQL_TEST_DIR/var/run ] || mkdir $MYSQL_TEST_DIR/var/run
-[ -z "$COLUMNS" ] && COLUMNS=80
+if test ${COLUMNS:-0} -lt 80 ; then COLUMNS=80 ; fi
E=`$EXPR $COLUMNS - 8`
DASH72=`$ECHO '------------------------------------------------------------------------'|$CUT -c 1-$E`
@@ -279,10 +369,19 @@ if [ x$SOURCE_DIST = x1 ] ; then
MYSQLD="$BASEDIR/sql/mysqld"
if [ -f "$BASEDIR/client/.libs/lt-mysqltest" ] ; then
MYSQL_TEST="$BASEDIR/client/.libs/lt-mysqltest"
+ elif [ -f "$BASEDIR/client/.libs/mysqltest" ] ; then
+ MYSQL_TEST="$BASEDIR/client/.libs/mysqltest"
else
MYSQL_TEST="$BASEDIR/client/mysqltest"
fi
+ if [ -n "$STRACE_CLIENT" ]; then
+ MYSQL_TEST="strace -o $MYSQL_TEST_DIR/var/log/mysqltest.strace $MYSQL_TEST"
+ fi
+
MYSQLADMIN="$BASEDIR/client/mysqladmin"
+ MYSQL_MANAGER_CLIENT="$BASEDIR/client/mysqlmanagerc"
+ MYSQL_MANAGER="$BASEDIR/tools/mysqlmanager"
+ MYSQL_MANAGER_PWGEN="$BASEDIR/client/mysqlmanager-pwgen"
MYSQL="$BASEDIR/client/mysql"
LANGUAGE="$BASEDIR/sql/share/english/"
CHARSETSDIR="$BASEDIR/sql/share/charsets"
@@ -291,9 +390,12 @@ else
MYSQLD="$BASEDIR/bin/mysqld"
MYSQL_TEST="$BASEDIR/bin/mysqltest"
MYSQLADMIN="$BASEDIR/bin/mysqladmin"
+ MYSQL_MANAGER="$BASEDIR/bin/mysqlmanager"
+ MYSQL_MANAGER_CLIENT="$BASEDIR/bin/mysqlmanagerc"
+ MYSQL_MANAGER_PWGEN="$BASEDIR/bin/mysqlmanager-pwgen"
MYSQL="$BASEDIR/bin/mysql"
INSTALL_DB="./install_test_db -bin"
- if test -d "$BASEDIR/share/mysql/english"
+ if test -d "$BASEDIR/share/mysql/english"
then
LANGUAGE="$BASEDIR/share/mysql/english/"
CHARSETSDIR="$BASEDIR/share/mysql/charsets"
@@ -303,6 +405,16 @@ else
fi
fi
+if [ -z "$MASTER_MYSQLD" ]
+then
+MASTER_MYSQLD=$MYSQLD
+fi
+
+if [ -z "$SLAVE_MYSQLD" ]
+then
+SLAVE_MYSQLD=$MYSQLD
+fi
+
# If we should run all tests cases, we will use a local server for that
if [ -z "$1" ]
@@ -325,7 +437,9 @@ then
fi
-MYSQL_TEST_ARGS="--no-defaults --socket=$MASTER_MYSOCK --database=$DB --user=$DBUSER --password=$DBPASSWD --silent -v --tmpdir=$MYSQL_TMP_DIR"
+MYSQL_TEST_ARGS="--no-defaults --socket=$MASTER_MYSOCK --database=$DB \
+ --user=$DBUSER --password=$DBPASSWD --silent -v \
+ --tmpdir=$MYSQL_TMP_DIR"
MYSQL_TEST_BIN=$MYSQL_TEST
MYSQL_TEST="$MYSQL_TEST $MYSQL_TEST_ARGS"
GDB_CLIENT_INIT=$MYSQL_TMP_DIR/gdbinit.client
@@ -336,8 +450,8 @@ GCOV_ERR=$MYSQL_TMP_DIR/mysqld-gcov.err
GPROF_DIR=$MYSQL_TMP_DIR/gprof
GPROF_MASTER=$GPROF_DIR/master.gprof
GPROF_SLAVE=$GPROF_DIR/slave.gprof
-TIMEFILE="$MYSQL_TMP_DIR/mysqltest-time"
-SLAVE_MYSQLD=$MYSQLD #this can be changed later if we are doing gcov
+TIMEFILE="$MYSQL_TEST_DIR/var/log/mysqltest-time"
+XTERM=`which xterm`
#++
# Function Definitions
@@ -360,12 +474,12 @@ show_failed_diff ()
reject_file=r/$1.reject
result_file=r/$1.result
eval_file=r/$1.eval
-
+
if [ -f $eval_file ]
then
result_file=$eval_file
fi
-
+
if [ -x "$DIFF" ] && [ -f $reject_file ]
then
echo "Below are the diffs between actual and expected results:"
@@ -375,7 +489,7 @@ show_failed_diff ()
echo "Please follow the instructions outlined at"
echo "http://www.mysql.com/doc/R/e/Reporting_mysqltest_bugs.html"
echo "to find the reason to this problem and how to report this."
- fi
+ fi
}
do_gdb_test ()
@@ -384,7 +498,7 @@ do_gdb_test ()
$ECHO "set args $mysql_test_args < $2" > $GDB_CLIENT_INIT
echo "Set breakpoints ( if needed) and type 'run' in gdb window"
#this xterm should not be backgrounded
- xterm -title "Client" -e gdb -x $GDB_CLIENT_INIT $MYSQL_TEST_BIN
+ $XTERM -title "Client" -e gdb -x $GDB_CLIENT_INIT $MYSQL_TEST_BIN
}
error () {
@@ -393,7 +507,7 @@ error () {
}
error_is () {
- $TR "\n" " " < $TIMEFILE | $SED -e 's/.* At line \(.*\)\: \(.*\)Command .*$/ \>\> Error at line \1: \2<\</'
+ $CAT < $TIMEFILE | $SED -e 's/.* At line \(.*\)\: \(.*\)/ \>\> Error at line \1: \2<\</' | $HEAD -1
}
prefix_to_8() {
@@ -420,15 +534,15 @@ report_stats () {
if [ $TOT_FAIL = 0 ]; then
$ECHO "All $TOT_TEST tests were successful."
else
- xten=`$EXPR $TOT_PASS \* 10000`
- raw=`$EXPR $xten / $TOT_TEST`
- raw=`$PRINTF %.4d $raw`
- whole=`$PRINTF %.2s $raw`
- xwhole=`$EXPR $whole \* 100`
- deci=`$EXPR $raw - $xwhole`
+ xten=`$EXPR $TOT_PASS \* 10000`
+ raw=`$EXPR $xten / $TOT_TEST`
+ raw=`$PRINTF %.4d $raw`
+ whole=`$PRINTF %.2s $raw`
+ xwhole=`$EXPR $whole \* 100`
+ deci=`$EXPR $raw - $xwhole`
$ECHO "Failed ${TOT_FAIL}/${TOT_TEST} tests, ${whole}.${deci}% successful."
$ECHO ""
- $ECHO "The log files in $MYSQL_TEST_DIR/var/log may give you some hint"
+ $ECHO "The log files in $MY_LOG_DIR may give you some hint"
$ECHO "of what when wrong."
$ECHO "If you want to report this error, please read first the documentation at"
$ECHO "http://www.mysql.com/doc/M/y/MySQL_test_suite.html"
@@ -437,8 +551,7 @@ report_stats () {
mysql_install_db () {
$ECHO "Removing Stale Files"
- $RM -rf $MASTER_MYDDIR $SLAVE_MYDDIR $SLAVE_MYLOG $MASTER_MYLOG \
- $SLAVE_MYERR $MASTER_MYERR
+ $RM -rf $MASTER_MYDDIR $SLAVE_MYDDIR $MY_LOG_DIR/*
$ECHO "Installing Master Databases"
$INSTALL_DB
if [ $? != 0 ]; then
@@ -451,25 +564,31 @@ mysql_install_db () {
error "Could not install slave test DBs"
exit 1
fi
- # Give mysqld some time to die.
- sleep $SLEEP_TIME
+
+ for slave_num in 1 2 ;
+ do
+ $RM -rf var/slave$slave_num-data/
+ mkdir -p var/slave$slave_num-data/mysql
+ mkdir -p var/slave$slave_num-data/test
+ cp var/slave-data/mysql/* var/slave$slave_num-data/mysql
+ done
return 0
}
gprof_prepare ()
{
- rm -rf $GPROF_DIR
- mkdir -p $GPROF_DIR
+ $RM -rf $GPROF_DIR
+ mkdir -p $GPROF_DIR
}
gprof_collect ()
{
if [ -f $MASTER_MYDDIR/gmon.out ]; then
- gprof $MYSQLD $MASTER_MYDDIR/gmon.out > $GPROF_MASTER
+ gprof $MASTER_MYSQLD $MASTER_MYDDIR/gmon.out > $GPROF_MASTER
echo "Master execution profile has been saved in $GPROF_MASTER"
fi
if [ -f $SLAVE_MYDDIR/gmon.out ]; then
- gprof $MYSQLD $SLAVE_MYDDIR/gmon.out > $GPROF_SLAVE
+ gprof $SLAVE_MYSQLD $SLAVE_MYDDIR/gmon.out > $GPROF_SLAVE
echo "Slave execution profile has been saved in $GPROF_SLAVE"
fi
}
@@ -494,173 +613,357 @@ gcov_collect () {
$ECHO "gcov info in $GCOV_MSG, errors in $GCOV_ERR"
}
+abort_if_failed()
+{
+ if [ ! $? = 0 ] ; then
+ echo $1
+ exit 1
+ fi
+}
-start_master()
+start_manager()
{
- [ x$MASTER_RUNNING = 1 ] && return
- #run master initialization shell script if one exists
- if [ -f "$master_init_script" ] ;
- then
- /bin/sh $master_init_script
+ if [ $USE_MANAGER = 0 ] ; then
+ echo "Manager disabled, skipping manager start."
+ $RM -f $MYSQL_MANAGER_LOG
+ return
+ fi
+ $ECHO "Starting MySQL Manager"
+ if [ -f "$MANAGER_PID_FILE" ] ; then
+ kill `cat $MANAGER_PID_FILE`
+ sleep 1
+ if [ -f "$MANAGER_PID_FILE" ] ; then
+ kill -9 `cat $MANAGER_PID_FILE`
+ sleep 1
fi
- cd $BASEDIR # for gcov
- # Remove old berkeley db log files that can confuse the server
- $RM -f $MASTER_MYDDIR/log.*
- #start master
- if [ -z "$DO_BENCH" ]
- then
- master_args="--no-defaults --log-bin=master-bin \
- --server-id=1 \
- --basedir=$MY_BASEDIR \
- --port=$MASTER_MYPORT \
- --exit-info=256 \
- --core \
- --datadir=$MASTER_MYDDIR \
- --pid-file=$MASTER_MYPID \
- --socket=$MASTER_MYSOCK \
- --log=$MASTER_MYLOG \
- --character-sets-dir=$CHARSETSDIR \
- --tmpdir=$MYSQL_TMP_DIR \
- --language=$LANGUAGE \
- --innodb_data_file_path=ibdata1:50M \
- $SMALL_SERVER \
- $EXTRA_MASTER_OPT $EXTRA_MASTER_MYSQLD_OPT"
- else
- master_args="--no-defaults --log-bin=master-bin --server-id=1 \
- --basedir=$MY_BASEDIR \
- --port=$MASTER_MYPORT \
- --datadir=$MASTER_MYDDIR \
- --pid-file=$MASTER_MYPID \
- --socket=$MASTER_MYSOCK \
- --default-character-set=$CHARACTER_SET \
- --core \
- --tmpdir=$MYSQL_TMP_DIR \
- --language=$LANGUAGE \
- --innodb_data_file_path=ibdata1:50M \
- $SMALL_SERVER \
- $EXTRA_MASTER_OPT $EXTRA_MASTER_MYSQLD_OPT"
- fi
- if [ x$DO_DDD = x1 ]
- then
- $ECHO "set args $master_args" > $GDB_MASTER_INIT
- ddd --debugger "gdb -x $GDB_MASTER_INIT" $MYSQLD &
- prompt_user "Hit enter to continue after you've started the master"
- elif [ x$DO_GDB = x1 ]
+ fi
+
+ $RM -f $MANAGER_PID_FILE
+ MYSQL_MANAGER_PW=`$MYSQL_MANAGER_PWGEN -u $MYSQL_MANAGER_USER \
+ -o $MYSQL_MANAGER_PW_FILE`
+ $MYSQL_MANAGER --log=$MYSQL_MANAGER_LOG --port=$MYSQL_MANAGER_PORT \
+ --password-file=$MYSQL_MANAGER_PW_FILE --pid-file=$MANAGER_PID_FILE
+ abort_if_failed "Could not start MySQL manager"
+ mysqltest_manager_args="--manager-host=localhost \
+ --manager-user=$MYSQL_MANAGER_USER \
+ --manager-password=$MYSQL_MANAGER_PW \
+ --manager-port=$MYSQL_MANAGER_PORT \
+ --manager-wait-timeout=$START_WAIT_TIMEOUT"
+ MYSQL_TEST="$MYSQL_TEST $mysqltest_manager_args"
+ MYSQL_TEST_ARGS="$MYSQL_TEST_ARGS $mysqltest_manager_args"
+ while [ ! -f $MANAGER_PID_FILE ] ; do
+ sleep 1
+ done
+ echo "Manager started"
+}
+
+stop_manager()
+{
+ if [ $USE_MANAGER = 0 ] ; then
+ return
+ fi
+ $MYSQL_MANAGER_CLIENT $MANAGER_QUIET_OPT -u$MYSQL_MANAGER_USER \
+ -p$MYSQL_MANAGER_PW -P $MYSQL_MANAGER_PORT <<EOF
+shutdown
+EOF
+ echo "Manager terminated"
+
+}
+
+manager_launch()
+{
+ ident=$1
+ shift
+ if [ $USE_MANAGER = 0 ] ; then
+ $@ >$CUR_MYERR 2>&1 &
+ sleep 2 #hack
+ return
+ fi
+ $MYSQL_MANAGER_CLIENT $MANAGER_QUIET_OPT --user=$MYSQL_MANAGER_USER \
+ --password=$MYSQL_MANAGER_PW --port=$MYSQL_MANAGER_PORT <<EOF
+def_exec $ident $@
+set_exec_stdout $ident $CUR_MYERR
+set_exec_stderr $ident $CUR_MYERR
+set_exec_con $ident root localhost $CUR_MYSOCK
+start_exec $ident $START_WAIT_TIMEOUT
+EOF
+ abort_if_failed "Could not execute manager command"
+}
+
+manager_term()
+{
+ ident=$1
+ shift
+ if [ $USE_MANAGER = 0 ] ; then
+ $MYSQLADMIN --no-defaults -uroot --socket=$MYSQL_TMP_DIR/$ident.sock -O \
+ connect_timeout=5 -O shutdown_timeout=20 shutdown >> $MYSQL_MANAGER_LOG 2>&1
+ return
+ fi
+ $MYSQL_MANAGER_CLIENT $MANAGER_QUIET_OPT --user=$MYSQL_MANAGER_USER \
+ --password=$MYSQL_MANAGER_PW --port=$MYSQL_MANAGER_PORT <<EOF
+stop_exec $ident $STOP_WAIT_TIMEOUT
+EOF
+ abort_if_failed "Could not execute manager command"
+}
+
+
+start_master()
+{
+ if [ x$MASTER_RUNNING = x1 ] || [ x$LOCAL_MASTER = x1 ] ; then
+ return
+ fi
+ # Remove old berkeley db log files that can confuse the server
+ $RM -f $MASTER_MYDDIR/log.*
+ # Remove stale binary logs
+ $RM -f $MYSQL_TEST_DIR/var/log/master-bin.*
+
+ #run master initialization shell script if one exists
+
+ if [ -f "$master_init_script" ] ;
+ then
+ /bin/sh $master_init_script
+ fi
+ cd $BASEDIR # for gcov
+ #start master
+ if [ -z "$DO_BENCH" ]
+ then
+ master_args="--no-defaults --log-bin=$MYSQL_TEST_DIR/var/log/master-bin \
+ --server-id=1 \
+ --basedir=$MY_BASEDIR \
+ --port=$MASTER_MYPORT \
+ --local-infile \
+ --exit-info=256 \
+ --core \
+ --datadir=$MASTER_MYDDIR \
+ --pid-file=$MASTER_MYPID \
+ --socket=$MASTER_MYSOCK \
+ --log=$MASTER_MYLOG \
+ --character-sets-dir=$CHARSETSDIR \
+ --default-character-set=$CHARACTER_SET \
+ --tmpdir=$MYSQL_TMP_DIR \
+ --language=$LANGUAGE \
+ --innodb_data_file_path=ibdata1:50M \
+ $MASTER_40_ARGS \
+ $SMALL_SERVER \
+ $EXTRA_MASTER_OPT $EXTRA_MASTER_MYSQLD_OPT"
+ else
+ master_args="--no-defaults --log-bin=$MYSQL_TEST_DIR/var/log/master-bin \
+ --server-id=1 --rpl-recovery-rank=1 \
+ --basedir=$MY_BASEDIR --init-rpl-role=master \
+ --port=$MASTER_MYPORT \
+ --local-infile \
+ --datadir=$MASTER_MYDDIR \
+ --pid-file=$MASTER_MYPID \
+ --socket=$MASTER_MYSOCK \
+ --character-sets-dir=$CHARSETSDIR \
+ --default-character-set=$CHARACTER_SET \
+ --core \
+ --tmpdir=$MYSQL_TMP_DIR \
+ --language=$LANGUAGE \
+ --innodb_data_file_path=ibdata1:50M \
+ $MASTER_40_ARGS \
+ $SMALL_SERVER \
+ $EXTRA_MASTER_OPT $EXTRA_MASTER_MYSQLD_OPT"
+ fi
+
+ CUR_MYERR=$MASTER_MYERR
+ CUR_MYSOCK=$MASTER_MYSOCK
+
+ if [ x$DO_DDD = x1 ]
+ then
+ $ECHO "set args $master_args" > $GDB_MASTER_INIT
+ manager_launch master ddd -display $DISPLAY --debugger \
+ "gdb -x $GDB_MASTER_INIT" $MASTER_MYSQLD
+ elif [ x$DO_GDB = x1 ]
+ then
+ if [ x$MANUAL_GDB = x1 ]
then
$ECHO "set args $master_args" > $GDB_MASTER_INIT
- xterm -title "Master" -e gdb -x $GDB_MASTER_INIT $MYSQLD &
- prompt_user "Hit enter to continue after you've started the master"
- else
- $MYSQLD $master_args >> $MASTER_MYERR 2>&1 &
- fi
- wait_for_server_start $MASTER_MYPORT
+ $ECHO "To start gdb for the master , type in another window:"
+ $ECHO "cd $CWD ; gdb -x $GDB_MASTER_INIT $MASTER_MYSQLD"
+ wait_for_master=1500
+ else
+ ( $ECHO set args $master_args;
+ if [ $USE_MANAGER = 0 ] ; then
+ cat <<EOF
+b mysql_parse
+commands 1
+disa 1
+end
+r
+EOF
+ fi ) > $GDB_MASTER_INIT
+ manager_launch master $XTERM -display $DISPLAY \
+ -title "Master" -e gdb -x $GDB_MASTER_INIT $MASTER_MYSQLD
+ fi
+ else
+ manager_launch master $MASTER_MYSQLD $master_args
+ fi
+ sleep_until_file_created $MASTER_MYPID $wait_for_master
+ wait_for_master=$SLEEP_TIME_FOR_SECOND_MASTER
MASTER_RUNNING=1
}
start_slave()
{
- [ x$SKIP_SLAVE = x1 ] && return
- [ x$SLAVE_RUNNING = 1 ] && return
-
- #run slave initialization shell script if one exists
- if [ -f "$slave_init_script" ] ;
- then
- /bin/sh $slave_init_script
- fi
-
- if [ -z "$SLAVE_MASTER_INFO" ] ; then
- master_info="--master-user=root \
- --master-connect-retry=1 \
- --master-host=127.0.0.1 \
- --master-password= \
- --master-port=$MASTER_MYPORT \
- --server-id=2"
- else
- master_info=$SLAVE_MASTER_INFO
- fi
-
- $RM -f $SLAVE_MYDDIR/log.*
- slave_args="--no-defaults $master_info \
- --exit-info=256 \
- --log-bin=slave-bin --log-slave-updates \
- --log=$SLAVE_MYLOG \
- --basedir=$MY_BASEDIR \
- --datadir=$SLAVE_MYDDIR \
- --pid-file=$SLAVE_MYPID \
- --port=$SLAVE_MYPORT \
- --socket=$SLAVE_MYSOCK \
- --character-sets-dir=$CHARSETSDIR \
- --core \
- --tmpdir=$MYSQL_TMP_DIR \
- --language=$LANGUAGE \
- --skip-innodb --skip-slave-start \
- --master-retry-count=5 \
- $SMALL_SERVER \
- $EXTRA_SLAVE_OPT $EXTRA_SLAVE_MYSQLD_OPT"
- if [ x$DO_DDD = x1 ]
- then
- $ECHO "set args $master_args" > $GDB_SLAVE_INIT
- ddd --debugger "gdb -x $GDB_SLAVE_INIT" $SLAVE_MYSQLD &
- prompt_user "Hit enter to continue after you've started the slave"
- elif [ x$DO_GDB = x1 ]
+ [ x$SKIP_SLAVE = x1 ] && return
+ eval "this_slave_running=\$SLAVE$1_RUNNING"
+ [ x$this_slave_running = 1 ] && return
+ #when testing fail-safe replication, we will have more than one slave
+ #in this case, we start secondary slaves with an argument
+ slave_ident="slave$1"
+ if [ -n "$1" ] ;
+ then
+ slave_server_id=`$EXPR 2 + $1`
+ slave_rpl_rank=$slave_server_id
+ slave_port=`expr $SLAVE_MYPORT + $1`
+ slave_log="$SLAVE_MYLOG.$1"
+ slave_err="$SLAVE_MYERR.$1"
+ slave_datadir="var/$slave_ident-data/"
+ slave_pid="$MYRUN_DIR/mysqld-$slave_ident.pid"
+ slave_sock="$SLAVE_MYSOCK-$1"
+ else
+ slave_server_id=2
+ slave_rpl_rank=2
+ slave_port=$SLAVE_MYPORT
+ slave_log=$SLAVE_MYLOG
+ slave_err=$SLAVE_MYERR
+ slave_datadir=$SLAVE_MYDDIR
+ slave_pid=$SLAVE_MYPID
+ slave_sock="$SLAVE_MYSOCK"
+ fi
+ # Remove stale binary logs
+ $RM -f $MYSQL_TEST_DIR/var/log/$slave_ident-bin.*
+
+ #run slave initialization shell script if one exists
+ if [ -f "$slave_init_script" ] ;
+ then
+ /bin/sh $slave_init_script
+ fi
+
+ if [ -z "$SLAVE_MASTER_INFO" ] ; then
+ master_info="--master-user=root \
+ --master-connect-retry=1 \
+ --master-host=127.0.0.1 \
+ --master-password= \
+ --master-port=$MASTER_MYPORT \
+ --server-id=$slave_server_id --rpl-recovery-rank=$slave_rpl_rank"
+ else
+ master_info=$SLAVE_MASTER_INFO
+ fi
+
+ $RM -f $slave_datadir/log.*
+ slave_args="--no-defaults $master_info \
+ --exit-info=256 \
+ --log-bin=$MYSQL_TEST_DIR/var/log/$slave_ident-bin \
+ --relay-log=$MYSQL_TEST_DIR/var/log/$slave_ident-relay-bin \
+ --log-slave-updates \
+ --log=$slave_log \
+ --basedir=$MY_BASEDIR \
+ --datadir=$slave_datadir \
+ --pid-file=$slave_pid \
+ --port=$slave_port \
+ --socket=$slave_sock \
+ --character-sets-dir=$CHARSETSDIR \
+ --default-character-set=$CHARACTER_SET \
+ --core --init-rpl-role=slave \
+ --tmpdir=$MYSQL_TMP_DIR \
+ --language=$LANGUAGE \
+ --skip-innodb --skip-slave-start \
+ --slave-load-tmpdir=$SLAVE_LOAD_TMPDIR \
+ --report-host=127.0.0.1 --report-user=root \
+ --report-port=$slave_port \
+ --master-retry-count=5 \
+ $SMALL_SERVER \
+ $EXTRA_SLAVE_OPT $EXTRA_SLAVE_MYSQLD_OPT"
+ CUR_MYERR=$slave_err
+ CUR_MYSOCK=$slave_sock
+
+ if [ x$DO_DDD = x1 ]
+ then
+ $ECHO "set args $master_args" > $GDB_SLAVE_INIT
+ manager_launch $slave_ident ddd -display $DISPLAY --debugger \
+ "gdb -x $GDB_SLAVE_INIT" $SLAVE_MYSQLD
+ elif [ x$DO_GDB = x1 ]
+ then
+ $ECHO "set args $slave_args" > $GDB_SLAVE_INIT
+ if [ x$MANUAL_GDB = x1 ]
then
- $ECHO "set args $slave_args" > $GDB_SLAVE_INIT
- xterm -title "Slave" -e gdb -x $GDB_SLAVE_INIT $SLAVE_MYSQLD &
- prompt_user "Hit enter to continue after you've started the slave"
+ echo "To start gdb for the slave, type in another window:"
+ echo "cd $CWD ; gdb -x $GDB_SLAVE_INIT $SLAVE_MYSQLD"
+ wait_for_slave=1500
else
- $SLAVE_MYSQLD $slave_args >> $SLAVE_MYERR 2>&1 &
+ manager_launch $slave_ident $XTERM -display $DISPLAY -title "Slave" -e \
+ gdb -x $GDB_SLAVE_INIT $SLAVE_MYSQLD
fi
- wait_for_server_start $SLAVE_MYPORT
- SLAVE_RUNNING=1
+ else
+ manager_launch $slave_ident $SLAVE_MYSQLD $slave_args
+ fi
+ eval "SLAVE$1_RUNNING=1"
+ sleep_until_file_created $slave_pid $wait_for_slave
+ wait_for_slave=$SLEEP_TIME_FOR_SECOND_SLAVE
}
-mysql_start () {
- $ECHO "Starting MySQL daemon"
- start_master
- start_slave
- cd $MYSQL_TEST_DIR
- return 1
+mysql_start ()
+{
+ $ECHO "Starting MySQL daemon"
+ start_master
+ start_slave
+ cd $MYSQL_TEST_DIR
+ return 1
}
stop_slave ()
{
- if [ x$SLAVE_RUNNING = x1 ]
+ eval "this_slave_running=\$SLAVE$1_RUNNING"
+ slave_ident="slave$1"
+ if [ -n "$1" ] ;
+ then
+ slave_pid="$MYRUN_DIR/mysqld-$slave_ident.pid"
+ else
+ slave_pid=$SLAVE_MYPID
+ fi
+ if [ x$this_slave_running = x1 ]
then
- $MYSQLADMIN --no-defaults --socket=$SLAVE_MYSOCK -u root -O shutdown_timeout=20 shutdown
- if [ $? != 0 ] && [ -f $SLAVE_MYPID ]
+ manager_term $slave_ident
+ if [ $? != 0 ] && [ -f $slave_pid ]
then # try harder!
- $ECHO "slave not cooperating with mysqladmin, will try manual kill"
- kill `$CAT $SLAVE_MYPID`
- sleep $SLEEP_TIME
- if [ -f $SLAVE_MYPID ] ; then
- $ECHO "slave refused to die. Sending SIGKILL"
- kill -9 `$CAT $SLAVE_MYPID`
- $RM -f $SLAVE_MYPID
- else
- $ECHO "slave responded to SIGTERM "
- fi
+ $ECHO "slave not cooperating with mysqladmin, will try manual kill"
+ kill `$CAT $slave_pid`
+ sleep_until_file_deleted $slave_pid
+ if [ -f $slave_pid ] ; then
+ $ECHO "slave refused to die. Sending SIGKILL"
+ kill -9 `$CAT $slave_pid`
+ $RM -f $slave_pid
+ else
+ $ECHO "slave responded to SIGTERM "
+ fi
+ else
+ sleep $SLEEP_TIME_AFTER_RESTART
fi
- SLAVE_RUNNING=0
- fi
+ eval "SLAVE$1_RUNNING=0"
+ fi
}
stop_master ()
{
if [ x$MASTER_RUNNING = x1 ]
then
- $MYSQLADMIN --no-defaults --socket=$MASTER_MYSOCK -u root -O shutdown_timeout=20 shutdown
+ manager_term master
if [ $? != 0 ] && [ -f $MASTER_MYPID ]
then # try harder!
- $ECHO "master not cooperating with mysqladmin, will try manual kill"
- kill `$CAT $MASTER_MYPID`
- sleep $SLEEP_TIME
- if [ -f $MASTER_MYPID ] ; then
- $ECHO "master refused to die. Sending SIGKILL"
- kill -9 `$CAT $MASTER_MYPID`
- $RM -f $MASTER_MYPID
- else
- $ECHO "master responded to SIGTERM "
- fi
+ $ECHO "master not cooperating with mysqladmin, will try manual kill"
+ kill `$CAT $MASTER_MYPID`
+ sleep_until_file_deleted $MASTER_MYPID
+ if [ -f $MASTER_MYPID ] ; then
+ $ECHO "master refused to die. Sending SIGKILL"
+ kill -9 `$CAT $MASTER_MYPID`
+ $RM -f $MASTER_MYPID
+ else
+ $ECHO "master responded to SIGTERM "
+ fi
+ else
+ sleep $SLEEP_TIME_AFTER_RESTART
fi
MASTER_RUNNING=0
fi
@@ -674,22 +977,23 @@ mysql_stop ()
stop_master
$ECHO "Master shutdown finished"
stop_slave
+ stop_slave 1
+ stop_slave 2
$ECHO "Slave shutdown finished"
-
+
return 1
}
-mysql_restart () {
-
- mysql_stop
- mysql_start
-
- return 1
+mysql_restart ()
+{
+ mysql_stop
+ mysql_start
+ return 1
}
mysql_loadstd () {
-
- # cp $STD_DATA/*.frm $STD_DATA/*.MRG $MASTER_MYDDIR/test
+
+ # cp $STD_DATA/*.frm $STD_DATA/*.MRG $MASTER_MYDDIR/test
return 1
}
@@ -703,7 +1007,11 @@ run_testcase ()
slave_init_script=$TESTDIR/$tname-slave.sh
slave_master_info_file=$TESTDIR/$tname-slave-master-info.opt
SKIP_SLAVE=`$EXPR \( $tname : rpl \) = 0`
- if [ -n "$SKIP_TEST" ] ; then
+ if [ $USE_MANAGER = 1 ] ; then
+ many_slaves=`$EXPR \( $tname : rpl_failsafe \) != 0`
+ fi
+
+ if [ -n "$SKIP_TEST" ] ; then
SKIP_THIS_TEST=`$EXPR \( $tname : "$SKIP_TEST" \) != 0`
if [ x$SKIP_THIS_TEST = x1 ] ;
then
@@ -711,7 +1019,7 @@ run_testcase ()
fi
fi
- if [ -n "$DO_TEST" ] ; then
+ if [ -n "$DO_TEST" ] ; then
DO_THIS_TEST=`$EXPR \( $tname : "$DO_TEST" \) != 0`
if [ x$DO_THIS_TEST = x0 ] ;
then
@@ -737,7 +1045,7 @@ run_testcase ()
then
if [ -f $master_opt_file ] ;
then
- EXTRA_MASTER_OPT=`$CAT $master_opt_file`
+ EXTRA_MASTER_OPT=`$CAT $master_opt_file | $SED -e "s;\\$MYSQL_TEST_DIR;$MYSQL_TEST_DIR;"`
stop_master
start_master
else
@@ -746,20 +1054,20 @@ run_testcase ()
EXTRA_MASTER_OPT=""
stop_master
start_master
- fi
+ fi
fi
do_slave_restart=0
-
+
if [ -f $slave_opt_file ] ;
then
- EXTRA_SLAVE_OPT=`$CAT $slave_opt_file`
+ EXTRA_SLAVE_OPT=`$CAT $slave_opt_file | $SED -e "s;\\$MYSQL_TEST_DIR;$MYSQL_TEST_DIR;"`
do_slave_restart=1
else
if [ ! -z "$EXTRA_SLAVE_OPT" ] || [ x$SLAVE_RUNNING != x1 ] ;
then
EXTRA_SLAVE_OPT=""
- do_slave_restart=1
- fi
+ do_slave_restart=1
+ fi
fi
if [ -f $slave_master_info_file ] ; then
@@ -769,26 +1077,30 @@ run_testcase ()
if [ ! -z "$SLAVE_MASTER_INFO" ] || [ x$SLAVE_RUNNING != x1 ] ;
then
SLAVE_MASTER_INFO=""
- do_slave_restart=1
- fi
+ do_slave_restart=1
+ fi
fi
if [ x$do_slave_restart = x1 ] ; then
stop_slave
start_slave
fi
+ if [ x$many_slaves = x1 ]; then
+ start_slave 1
+ start_slave 2
+ fi
fi
cd $MYSQL_TEST_DIR
-
+
if [ -f $tf ] ; then
$RM -f r/$tname.*reject
mysql_test_args="-R r/$tname.result $EXTRA_MYSQL_TEST_OPT"
- if [ -z "$DO_CLIENT_GDB" ] ; then
- mytime=`$TIME -p $MYSQL_TEST $mysql_test_args < $tf 2> $TIMEFILE`
+ if [ -z "$DO_CLIENT_GDB" ] ; then
+ mytime=`$TIME -p $MYSQL_TEST $mysql_test_args < $tf 2> $TIMEFILE`
else
- do_gdb_test "$mysql_test_args" "$tf"
+ do_gdb_test "$mysql_test_args" "$tf"
fi
-
+
res=$?
if [ $res = 0 ]; then
@@ -810,6 +1122,11 @@ run_testcase ()
pname=`$ECHO "$tname "|$CUT -c 1-24`
RES="$pname $timestr"
+ if [ x$many_slaves = x1 ] ; then
+ stop_slave 1
+ stop_slave 2
+ fi
+
if [ $res = 0 ]; then
total_inc
pass_inc
@@ -833,10 +1150,11 @@ run_testcase ()
if [ -z "$DO_GDB" ] && [ -z "$USE_RUNNING_SERVER" ] && [ -z "$DO_DDD" ]
then
mysql_stop
+ stop_manager
fi
exit 1
fi
-
+
if [ -z "$DO_GDB" ] && [ -z "$USE_RUNNING_SERVER" ] && [ -z "$DO_DDD" ]
then
mysql_restart
@@ -848,26 +1166,49 @@ run_testcase ()
fi
}
-
######################################################################
# Main script starts here
######################################################################
[ "$DO_GCOV" -a ! -x "$GCOV" ] && error "No gcov found"
-[ "$DO_GCOV" ] && gcov_prepare
-[ "$DO_GPROF" ] && gprof_prepare
+[ "$DO_GCOV" ] && gcov_prepare
+[ "$DO_GPROF" ] && gprof_prepare
-# Ensure that no old mysqld test servers are running
if [ -z "$USE_RUNNING_SERVER" ]
then
- $MYSQLADMIN --no-defaults --socket=$MASTER_MYSOCK -u root -O connect_timeout=5 shutdown > /dev/null 2>&1
- $MYSQLADMIN --no-defaults --socket=$SLAVE_MYSOCK -u root -O connect_timeout=5 shutdown > /dev/null 2>&1
+ # Ensure that no old mysqld test servers are running
+ $MYSQLADMIN --no-defaults --socket=$MASTER_MYSOCK -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=$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 $MASTER_MYPID
+ sleep_until_file_deleted $SLAVE_MYPID
+
+ # Kill any running managers
+ if [ -f "$MANAGER_PID_FILE" ]
+ then
+ kill `cat $MANAGER_PID_FILE`
+ sleep 1
+ if [ -f "$MANAGER_PID_FILE" ]
+ then
+ kill -9 `cat $MANAGER_PID_FILE`
+ sleep 1
+ fi
+ fi
+
+ # Remove files that can cause problems
+ $RM -f $MYSQL_TEST_DIR/var/run/* $MYSQL_TEST_DIR/var/tmp/*
+
+ wait_for_master=$SLEEP_TIME_FOR_FIRST_MASTER
+ wait_for_slave=$SLEEP_TIME_FOR_FIRST_SLAVE
$ECHO "Installing Test Databases"
mysql_install_db
+ start_manager
-#do not automagically start deamons if we are in gdb or running only one test
-#case
+# Do not automagically start deamons if we are in gdb or running only one test
+# case
if [ -z "$DO_GDB" ] && [ -z "$DO_DDD" ]
then
mysql_start
@@ -876,31 +1217,35 @@ then
mysql_loadstd
fi
+if [ "x$START_AND_EXIT" = "x1" ] ; then
+ echo "Servers started, exiting"
+ exit
+fi
$ECHO "Starting Tests"
if [ "$DO_BENCH" = 1 ]
then
- BENCHDIR=$BASEDIR/sql-bench/
- savedir=`pwd`
- cd $BENCHDIR
- if [ -z "$1" ]
- then
- ./run-all-tests --socket=$MASTER_MYSOCK --user=root
- else
- if [ -x "./$1" ]
+ BENCHDIR=$BASEDIR/sql-bench/
+ savedir=`pwd`
+ cd $BENCHDIR
+ if [ -z "$1" ]
then
- ./$1 --socket=$MASTER_MYSOCK --user=root
+ ./run-all-tests --socket=$MASTER_MYSOCK --user=root
else
- echo "benchmark $1 not found"
+ if [ -x "./$1" ]
+ then
+ ./$1 --socket=$MASTER_MYSOCK --user=root
+ else
+ echo "benchmark $1 not found"
+ fi
fi
- fi
- cd $savedir
- mysql_stop
- exit
+ cd $savedir
+ mysql_stop
+ stop_manager
+ exit
fi
-
$ECHO
$ECHO " TEST USER SYSTEM ELAPSED RESULT"
$ECHO $DASH72
@@ -910,25 +1255,23 @@ then
if [ x$RECORD = x1 ]; then
$ECHO "Will not run in record mode without a specific test case."
else
- if [ -z "$USER_TEST" ]
- then
- for tf in $TESTDIR/*.$TESTSUFFIX
- do
- run_testcase $tf
- done
- $RM -f $TIMEFILE # Remove for full test
- else
- $USER_TEST
- fi
- fi
-else
-tname=`$BASENAME $1 .test`
- tf=$TESTDIR/$tname.$TESTSUFFIX
- if [ -f $tf ] ; then
- run_testcase $tf
- else
- $ECHO "Test case $tf does not exist."
+ for tf in $TESTDIR/*.$TESTSUFFIX
+ do
+ run_testcase $tf
+ done
+ $RM -f $TIMEFILE # Remove for full test
fi
+else
+ while [ ! -z "$1" ]; do
+ tname=`$BASENAME $1 .test`
+ tf=$TESTDIR/$tname.$TESTSUFFIX
+ if [ -f $tf ] ; then
+ run_testcase $tf
+ else
+ $ECHO "Test case $tf does not exist."
+ fi
+ shift
+ done
fi
$ECHO $DASH72
@@ -939,6 +1282,7 @@ then
mysql_stop
fi
+stop_manager
report_stats
$ECHO
diff --git a/mysql-test/r/alias.result b/mysql-test/r/alias.result
index 61a65f68007..3954c2d0170 100644
--- a/mysql-test/r/alias.result
+++ b/mysql-test/r/alias.result
@@ -1,2 +1,61 @@
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+cont_nr int(11) NOT NULL auto_increment,
+ver_nr int(11) NOT NULL default '0',
+aufnr int(11) NOT NULL default '0',
+username varchar(50) NOT NULL default '',
+hdl_nr int(11) NOT NULL default '0',
+eintrag date NOT NULL default '0000-00-00',
+st_klasse varchar(40) NOT NULL default '',
+st_wert varchar(40) NOT NULL default '',
+st_zusatz varchar(40) NOT NULL default '',
+st_bemerkung varchar(255) NOT NULL default '',
+kunden_art varchar(40) NOT NULL default '',
+mcbs_knr int(11) default NULL,
+mcbs_aufnr int(11) NOT NULL default '0',
+schufa_status char(1) default '?',
+bemerkung text,
+wirknetz text,
+wf_igz int(11) NOT NULL default '0',
+tarifcode varchar(80) default NULL,
+recycle char(1) default NULL,
+sim varchar(30) default NULL,
+mcbs_tpl varchar(30) default NULL,
+emp_nr int(11) NOT NULL default '0',
+laufzeit int(11) default NULL,
+hdl_name varchar(30) default NULL,
+prov_hdl_nr int(11) NOT NULL default '0',
+auto_wirknetz varchar(50) default NULL,
+auto_billing varchar(50) default NULL,
+touch timestamp(14) NOT NULL,
+kategorie varchar(50) default NULL,
+kundentyp varchar(20) NOT NULL default '',
+sammel_rech_msisdn varchar(30) NOT NULL default '',
+p_nr varchar(9) NOT NULL default '',
+suffix char(3) NOT NULL default '',
+PRIMARY KEY (cont_nr),
+KEY idx_aufnr(aufnr),
+KEY idx_hdl_nr(hdl_nr),
+KEY idx_st_klasse(st_klasse),
+KEY ver_nr(ver_nr),
+KEY eintrag_idx(eintrag),
+KEY emp_nr_idx(emp_nr),
+KEY wf_igz(wf_igz),
+KEY touch(touch),
+KEY hdl_tag(eintrag,hdl_nr),
+KEY prov_hdl_nr(prov_hdl_nr),
+KEY mcbs_aufnr(mcbs_aufnr),
+KEY kundentyp(kundentyp),
+KEY p_nr(p_nr,suffix)
+) TYPE=MyISAM;
+INSERT INTO t1 VALUES (3359356,405,3359356,'Mustermann Musterfrau',52500,'2000-05-20','workflow','Auftrag erledigt','Originalvertrag eingegangen und geprüft','','privat',1485525,2122316,'+','','N',1909160,'MobilComSuper92000D2',NULL,NULL,'MS9ND2',3,24,'MobilCom Shop Koeln',52500,NULL,'auto',20010202105916,'Mobilfunk','PP','','','');
+INSERT INTO t1 VALUES (3359357,468,3359357,'Mustermann Musterfrau',7001,'2000-05-20','workflow','Auftrag erledigt','Originalvertrag eingegangen und geprüft','','privat',1503580,2139699,'+','','P',1909171,'MobilComSuper9D1T10SFreisprech(Akquise)',NULL,NULL,'MS9NS1',327,24,'MobilCom Intern',7003,NULL,'auto',20010202105916,'Mobilfunk','PP','','','');
+INSERT INTO t1 VALUES (3359358,407,3359358,'Mustermann Musterfrau',7001,'2000-05-20','workflow','Auftrag erledigt','Originalvertrag eingegangen und geprüft','','privat',1501358,2137473,'N','','N',1909159,'MobilComSuper92000D2',NULL,NULL,'MS9ND2',325,24,'MobilCom Intern',7003,NULL,'auto',20010202105916,'Mobilfunk','PP','','','');
+INSERT INTO t1 VALUES (3359359,468,3359359,'Mustermann Musterfrau',7001,'2000-05-20','workflow','Auftrag erledigt','Originalvertrag eingegangen und geprüft','','privat',1507831,2143894,'+','','P',1909162,'MobilComSuper9D1T10SFreisprech(Akquise)',NULL,NULL,'MS9NS1',327,24,'MobilCom Intern',7003,NULL,'auto',20010202105916,'Mobilfunk','PP','','','');
+INSERT INTO t1 VALUES (3359360,0,0,'Mustermann Musterfrau',29674907,'2000-05-20','workflow','Auftrag erledigt','Originalvertrag eingegangen und geprüft','','privat',1900169997,2414578,'+',NULL,'N',1909148,'',NULL,NULL,'RV99066_2',20,NULL,'POS',29674907,NULL,NULL,20010202105916,'Mobilfunk','','','97317481','007');
+INSERT INTO t1 VALUES (3359361,406,3359361,'Mustermann Musterfrau',7001,'2000-05-20','workflow','Auftrag storniert','','(7001-84):Storno, Kd. möchte nicht mehr','privat',NULL,0,'+','','P',1909150,'MobilComSuper92000D1(Akquise)',NULL,NULL,'MS9ND1',325,24,'MobilCom Intern',7003,NULL,'auto',20010202105916,'Mobilfunk','PP','','','');
+INSERT INTO t1 VALUES (3359362,406,3359362,'Mustermann Musterfrau',7001,'2000-05-20','workflow','Auftrag erledigt','Originalvertrag eingegangen und geprüft','','privat',1509984,2145874,'+','','P',1909154,'MobilComSuper92000D1(Akquise)',NULL,NULL,'MS9ND1',327,24,'MobilCom Intern',7003,NULL,'auto',20010202105916,'Mobilfunk','PP','','','');
+SELECT ELT(FIELD(kundentyp,'PP','PPA','PG','PGA','FK','FKA','FP','FPA','K','KA','V','VA',''), 'Privat (Private Nutzung)','Privat (Private Nutzung) Sitz im Ausland','Privat (geschaeftliche Nutzung)','Privat (geschaeftliche Nutzung) Sitz im Ausland','Firma (Kapitalgesellschaft)','Firma (Kapitalgesellschaft) Sitz im Ausland','Firma (Personengesellschaft)','Firma (Personengesellschaft) Sitz im Ausland','oeff. rechtl. Koerperschaft','oeff. rechtl. Koerperschaft Sitz im Ausland','Eingetragener Verein','Eingetragener Verein Sitz im Ausland','Typ unbekannt') AS Kundentyp ,kategorie FROM t1 WHERE hdl_nr < 2000000 AND kategorie IN ('Prepaid','Mobilfunk') AND st_klasse = 'Workflow' GROUP BY kundentyp ORDER BY kategorie;
Kundentyp kategorie
Privat (Private Nutzung) Mobilfunk
+drop table t1;
diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result
index dbdbb7f57a9..f0c3e2d162a 100644
--- a/mysql-test/r/alter_table.result
+++ b/mysql-test/r/alter_table.result
@@ -1,3 +1,26 @@
+drop table if exists t1;
+create table t1 (
+col1 int not null auto_increment primary key,
+col2 varchar(30) not null,
+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);
+insert into t1 values (2,4,3,5,"PENDING",1,7);
+alter table t1
+add column col4_5 varchar(20) not null after col4,
+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;
+select * from t1;
+col6 col1 col3 fourth col4 col4_5 col5 col7 col8
+1 2 3 4 5 PENDING 0000-00-00 00:00:00
+drop table t1;
+create table t1 (bandID MEDIUMINT UNSIGNED NOT NULL PRIMARY KEY, payoutID SMALLINT UNSIGNED NOT NULL);
+insert into t1 (bandID,payoutID) VALUES (1,6),(2,6),(3,4),(4,9),(5,10),(6,1),(7,12),(8,12);
+alter table t1 add column new_col int, order by payoutid,bandid;
+select * from t1;
bandID payoutID new_col
6 1 NULL
3 4 NULL
@@ -7,6 +30,8 @@ bandID payoutID new_col
5 10 NULL
7 12 NULL
8 12 NULL
+alter table t1 order by bandid,payoutid;
+select * from t1;
bandID payoutID new_col
1 6 NULL
2 6 NULL
@@ -16,19 +41,76 @@ bandID payoutID new_col
6 1 NULL
7 12 NULL
8 12 NULL
+drop table t1;
+CREATE TABLE t1 (
+GROUP_ID int(10) unsigned DEFAULT '0' NOT NULL,
+LANG_ID smallint(5) unsigned DEFAULT '0' NOT NULL,
+NAME varchar(80) DEFAULT '' NOT NULL,
+PRIMARY KEY (GROUP_ID,LANG_ID),
+KEY NAME (NAME));
+ALTER TABLE t1 CHANGE NAME NAME CHAR(80) not null;
+SHOW FULL COLUMNS FROM t1;
Field Type Null Key Default Extra Privileges
GROUP_ID int(10) unsigned PRI 0 select,insert,update,references
LANG_ID smallint(5) unsigned PRI 0 select,insert,update,references
NAME char(80) MUL select,insert,update,references
+DROP TABLE t1;
+create table t1 (n int);
+insert into t1 values(9),(3),(12),(10);
+alter table t1 order by n;
+select * from t1;
n
3
9
10
12
+drop table t1;
+CREATE TABLE t1 (
+id int(11) unsigned NOT NULL default '0',
+category_id tinyint(4) unsigned NOT NULL default '0',
+type_id tinyint(4) unsigned NOT NULL default '0',
+body text NOT NULL,
+user_id int(11) unsigned NOT NULL default '0',
+status enum('new','old') NOT NULL default 'new',
+PRIMARY KEY (id)
+) TYPE=MyISAM;
+ALTER TABLE t1 ORDER BY t1.id, t1.status, t1.type_id, t1.user_id, t1.body;
+DROP TABLE t1;
+CREATE TABLE t1 (AnamneseId int(10) unsigned NOT NULL auto_increment,B BLOB,PRIMARY KEY (AnamneseId)) type=myisam;
+insert into t1 values (null,"hello");
+LOCK TABLES t1 WRITE;
+ALTER TABLE t1 ADD Column new_col int not null;
+UNLOCK TABLES;
+OPTIMIZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 optimize status OK
+DROP TABLE t1;
+create table t1 (n1 int not null, n2 int, n3 int, n4 float,
+unique(n1),
+key (n1, n2, n3, n4),
+key (n2, n3, n4, n1),
+key (n3, n4, n1, n2),
+key (n4, n1, n2, n3) );
+alter table t1 disable keys;
+insert into t1 values(10,RAND()*1000,RAND()*1000,RAND());
+insert into t1 values(9,RAND()*1000,RAND()*1000,RAND());
+insert into t1 values(8,RAND()*1000,RAND()*1000,RAND());
+insert into t1 values(7,RAND()*1000,RAND()*1000,RAND());
+insert into t1 values(6,RAND()*1000,RAND()*1000,RAND());
+insert into t1 values(5,RAND()*1000,RAND()*1000,RAND());
+insert into t1 values(4,RAND()*1000,RAND()*1000,RAND());
+insert into t1 values(3,RAND()*1000,RAND()*1000,RAND());
+insert into t1 values(2,RAND()*1000,RAND()*1000,RAND());
+insert into t1 values(1,RAND()*1000,RAND()*1000,RAND());
+alter table t1 enable keys;
+drop table t1;
+create table t1 (i int unsigned not null auto_increment primary key);
+insert into t1 values (null),(null),(null),(null);
+alter table t1 drop i,add i int unsigned not null auto_increment, drop primary key, add primary key (i);
+select * from t1;
i
1
2
3
4
+drop table t1;
diff --git a/mysql-test/r/analyse.result b/mysql-test/r/analyse.result
index f6b8cc2fcbf..c183530df48 100644
--- a/mysql-test/r/analyse.result
+++ b/mysql-test/r/analyse.result
@@ -1,6 +1,13 @@
+drop table if exists t1,t2;
+create table t1 (i int, j int);
+insert into t1 values (1,2), (3,4), (5,6), (7,8);
+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
t1.i 1 7 1 1 0 0 4.0000 2.2361 ENUM('1','3','5','7') NOT NULL
t1.j 2 8 1 1 0 0 5.0000 2.2361 ENUM('2','4','6','8') NOT NULL
+create table t2 select * from t1 procedure analyse();
+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
t1.i 1 7 1 1 0 0 4.0000 2.2361 ENUM('1','3','5','7') NOT NULL
t1.j 2 8 1 1 0 0 5.0000 2.2361 ENUM('2','4','6','8') NOT NULL
+drop table t1,t2;
diff --git a/mysql-test/r/auto_increment.result b/mysql-test/r/auto_increment.result
index bf6265e5b64..66efd2ba567 100644
--- a/mysql-test/r/auto_increment.result
+++ b/mysql-test/r/auto_increment.result
@@ -1,32 +1,52 @@
+drop table if exists t1;
+create table t1 (a int not null auto_increment,b int, primary key (a)) type=myisam auto_increment=3;
+insert into t1 values (1,1),(NULL,3),(NULL,4);
+delete from t1 where a=4;
+insert into t1 values (NULL,5),(NULL,6);
+select * from t1;
a b
1 1
3 3
5 5
6 6
+delete from t1 where a=6;
+replace t1 values (3,1);
+ALTER TABLE t1 add c int;
+replace t1 values (3,3,3);
+insert into t1 values (NULL,7,7);
+update t1 set a=8,b=b+1,c=c+1 where a=7;
+insert into t1 values (NULL,9,9);
+select * from t1;
a b c
1 1 NULL
3 3 3
5 5 NULL
8 8 8
9 9 9
-a b
-1 1
-5 5
-3 3
-4 4
-6 6
-a b c
-1 1 NULL
-5 5 NULL
-3 3 NULL
-4 4 NULL
-6 6 6
+drop table t1;
+create table t1 (
+skey tinyint unsigned NOT NULL auto_increment PRIMARY KEY,
+sval char(20)
+);
+insert into t1 values (NULL, "hello");
+insert into t1 values (NULL, "hey");
+select * from t1;
skey sval
1 hello
2 hey
+select _rowid,t1._rowid,skey,sval from t1;
_rowid _rowid skey sval
1 1 1 hello
2 2 2 hey
+drop table t1;
+create table t1 (a char(10) not null, b int not null auto_increment, primary key(a,b));
+insert into t1 values ("a",1),("b",2),("a",2),("c",1);
+insert into t1 values ("a",NULL),("b",NULL),("c",NULL),("e",NULL);
+insert into t1 (a) values ("a"),("b"),("c"),("d");
+insert into t1 (a) values ('k'),('d');
+insert into t1 (a) values ("a");
+insert into t1 values ("d",last_insert_id());
+select * from t1;
a b
a 1
a 2
@@ -44,9 +64,17 @@ d 2
d 5
e 1
k 1
+drop table t1;
+create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null, primary key (ordid), index(ord,ordid));
+insert into t1 (ordid,ord) values (NULL,'sdj'),(NULL,'sdj');
+select * from t1;
ordid ord
1 sdj
2 sdj
+drop table t1;
+create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null, primary key (ord,ordid));
+insert into t1 values (NULL,'sdj'),(NULL,'sdj'),(NULL,"abc"),(NULL,'abc'),(NULL,'zzz'),(NULL,'sdj'),(NULL,'abc');
+select * from t1;
ordid ord
1 abc
2 abc
@@ -55,8 +83,15 @@ ordid ord
2 sdj
3 sdj
1 zzz
+drop table t1;
+create table t1 (a int not null primary key auto_increment);
+insert into t1 values (0);
+update t1 set a=0;
+select * from t1;
a
0
+check table t1;
Table Op Msg_type Msg_text
test.t1 check warning Found row where the auto_increment column has the value 0
test.t1 check status OK
+drop table t1;
diff --git a/mysql-test/r/backup.result b/mysql-test/r/backup.result
index 2bbe15954dc..43d57d2d4f7 100644
--- a/mysql-test/r/backup.result
+++ b/mysql-test/r/backup.result
@@ -1,43 +1,73 @@
+set SQL_LOG_BIN=0;
+drop table if exists t1;
+create table t1(n int);
+backup table t1 to '../bogus';
Table Op Msg_type Msg_text
test.t1 backup error Failed copying .frm file: errno = X
test.t1 backup status Operation failed
+backup table t1 to '../tmp';
Table Op Msg_type Msg_text
test.t1 backup status OK
+drop table t1;
+restore table t1 from '../tmp';
Table Op Msg_type Msg_text
test.t1 restore status OK
+select count(*) from t1;
count(*)
0
+insert into t1 values (23),(45),(67);
+backup table t1 to '../tmp';
Table Op Msg_type Msg_text
test.t1 backup status OK
+drop table t1;
+restore table t1 from '../bogus';
Table Op Msg_type Msg_text
t1 restore error Failed copying .frm file
+restore table t1 from '../tmp';
Table Op Msg_type Msg_text
test.t1 restore status OK
+select n from t1;
n
23
45
67
+create table t2(m int not null primary key);
+create table t3(k int not null primary key);
+insert into t2 values (123),(145),(167);
+insert into t3 values (223),(245),(267);
+backup table t1,t2,t3 to '../tmp';
Table Op Msg_type Msg_text
test.t1 backup status OK
test.t2 backup status OK
test.t3 backup status OK
+drop table t1,t2,t3;
+restore table t1,t2,t3 from '../tmp';
Table Op Msg_type Msg_text
test.t1 restore status OK
test.t2 restore status OK
test.t3 restore status OK
+select n from t1;
n
23
45
67
+select m from t2;
m
123
145
167
+select k from t3;
k
223
245
267
+drop table t1,t2,t3;
+restore table t1 from '../tmp';
Table Op Msg_type Msg_text
test.t1 restore status OK
+lock tables t1 write;
+backup table t1 to '../tmp';
+unlock tables;
Table Op Msg_type Msg_text
test.t1 backup status OK
+drop table t1;
diff --git a/mysql-test/r/bdb-crash.result b/mysql-test/r/bdb-crash.result
index 8fa8378640b..42c826d55da 100644
--- a/mysql-test/r/bdb-crash.result
+++ b/mysql-test/r/bdb-crash.result
@@ -1,3 +1,32 @@
+drop table if exists t1;
+CREATE TABLE t1 (
+ChargeID int(10) unsigned DEFAULT '0' NOT NULL auto_increment,
+ServiceID int(10) unsigned DEFAULT '0' NOT NULL,
+ChargeDate date DEFAULT '0000-00-00' NOT NULL,
+ChargeAmount decimal(20,2) DEFAULT '0.00' NOT NULL,
+FedTaxes decimal(20,2) DEFAULT '0.00' NOT NULL,
+ProvTaxes decimal(20,2) DEFAULT '0.00' NOT NULL,
+ChargeStatus enum('New','Auth','Unauth','Sale','Denied','Refund')
+DEFAULT 'New' NOT NULL,
+ChargeAuthorizationMessage text,
+ChargeComment text,
+ChargeTimeStamp varchar(20),
+PRIMARY KEY (ChargeID),
+KEY ServiceID (ServiceID),
+KEY ChargeDate (ChargeDate)
+) type=BDB;
+BEGIN;
+INSERT INTO t1
+VALUES(NULL,1,'2001-03-01',1,1,1,'New',NULL,NULL,'now');
+COMMIT;
+BEGIN;
+UPDATE t1 SET ChargeAuthorizationMessage = 'blablabla' WHERE
+ChargeID = 1;
+COMMIT;
+INSERT INTO t1
+VALUES(NULL,1,'2001-03-01',1,1,1,'New',NULL,NULL,'now');
+select * from t1;
ChargeID ServiceID ChargeDate ChargeAmount FedTaxes ProvTaxes ChargeStatus ChargeAuthorizationMessage ChargeComment ChargeTimeStamp
1 1 2001-03-01 1.00 1.00 1.00 New blablabla NULL now
2 1 2001-03-01 1.00 1.00 1.00 New NULL NULL now
+drop table t1;
diff --git a/mysql-test/r/bdb-deadlock.result b/mysql-test/r/bdb-deadlock.result
index 89077d16980..55b3d3ea2a5 100644
--- a/mysql-test/r/bdb-deadlock.result
+++ b/mysql-test/r/bdb-deadlock.result
@@ -1,10 +1,31 @@
+drop table if exists t1,t2;
+create table t1 (id integer, x integer) type=BDB;
+create table t2 (id integer, x integer) type=BDB;
+insert into t1 values(0, 0);
+insert into t2 values(0, 0);
+set autocommit=0;
+update t1 set x = 1 where id = 0;
+set autocommit=0;
+update t2 set x = 1 where id = 0;
+select x from t1 where id = 0;
+select x from t2 where id = 0;
+Deadlock found when trying to get lock; Try restarting transaction
+commit;
x
1
+commit;
+select * from t1;
id x
0 1
+select * from t2;
id x
0 1
+commit;
+select * from t1;
id x
0 1
+select * from t2;
id x
0 1
+commit;
+drop table t1,t2;
diff --git a/mysql-test/r/bdb.result b/mysql-test/r/bdb.result
index 4d26304db4c..7374e936c36 100644
--- a/mysql-test/r/bdb.result
+++ b/mysql-test/r/bdb.result
@@ -1,3 +1,7 @@
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8;
+create table t1 (id int unsigned not null auto_increment, code tinyint unsigned not null, name char(20) not null, primary key (id), key (code), unique (name)) type=bdb;
+insert into t1 (code, name) values (1, 'Tim'), (1, 'Monty'), (2, 'David'), (2, 'Erik'), (3, 'Sasha'), (3, 'Jeremy'), (4, 'Matt');
+select id, code, name from t1 order by id;
id code name
1 1 Tim
2 1 Monty
@@ -6,6 +10,8 @@ id code name
5 3 Sasha
6 3 Jeremy
7 4 Matt
+update ignore t1 set id = 8, name = 'Sinisa' where id < 3;
+select id, code, name from t1 order by id;
id code name
2 1 Monty
3 2 David
@@ -14,6 +20,8 @@ id code name
6 3 Jeremy
7 4 Matt
8 1 Sinisa
+update ignore t1 set id = id + 10, name = 'Ralph' where id < 4;
+select id, code, name from t1 order by id;
id code name
3 2 David
4 2 Erik
@@ -22,10 +30,26 @@ id code name
7 4 Matt
8 1 Sinisa
12 1 Ralph
+drop table t1;
+CREATE TABLE t1 (
+id int(11) NOT NULL auto_increment,
+parent_id int(11) DEFAULT '0' NOT NULL,
+level tinyint(4) DEFAULT '0' NOT NULL,
+PRIMARY KEY (id),
+KEY parent_id (parent_id),
+KEY level (level)
+) type=bdb;
+INSERT INTO t1 VALUES (1,0,0),(3,1,1),(4,1,1),(8,2,2),(9,2,2),(17,3,2),(22,4,2),(24,4,2),(28,5,2),(29,5,2),(30,5,2),(31,6,2),(32,6,2),(33,6,2),(203,7,2),(202,7,2),(20,3,2),(157,0,0),(193,5,2),(40,7,2),(2,1,1),(15,2,2),(6,1,1),(34,6,2),(35,6,2),(16,3,2),(7,1,1),(36,7,2),(18,3,2),(26,5,2),(27,5,2),(183,4,2),(38,7,2),(25,5,2),(37,7,2),(21,4,2),(19,3,2),(5,1,1),(179,5,2);
+update t1 set parent_id=parent_id+100;
+select * from t1 where parent_id=102;
id parent_id level
8 102 2
9 102 2
15 102 2
+update t1 set id=id+1000;
+update t1 set id=1024 where id=1009;
+Duplicate entry '1024' for key 1
+select * from t1;
id parent_id level
1001 100 0
1002 101 1
@@ -66,6 +90,8 @@ id parent_id level
1193 105 2
1202 107 2
1203 107 2
+update ignore t1 set id=id+1;
+select * from t1;
id parent_id level
1001 100 0
1002 101 1
@@ -106,16 +132,22 @@ id parent_id level
1194 105 2
1202 107 2
1204 107 2
+update ignore t1 set id=1023 where id=1010;
+select * from t1 where parent_id=102;
id parent_id level
1008 102 2
1015 102 2
1010 102 2
+explain select level from t1 where level=1;
table type possible_keys key key_len ref rows Extra
t1 ref level level 1 const 1 where used; Using index
+explain select level,id from t1 where level=1;
table type possible_keys key key_len ref rows Extra
t1 ref level level 1 const 1 where used; Using index
+explain select level,id,parent_id from t1 where level=1;
table type possible_keys key key_len ref rows Extra
t1 ref level level 1 const 1 where used
+select level,id from t1 where level=1;
level id
1 1002
1 1003
@@ -123,6 +155,7 @@ level id
1 1005
1 1006
1 1007
+select level,id,parent_id from t1 where level=1;
level id parent_id
1 1002 101
1 1003 101
@@ -130,31 +163,77 @@ level id parent_id
1 1005 101
1 1006 101
1 1007 101
+optimize table t1;
Table Op Msg_type Msg_text
test.t1 optimize status OK
-Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Comment
-t1 0 PRIMARY 1 id A 39 NULL NULL
-t1 1 parent_id 1 parent_id A 9 NULL NULL
-t1 1 level 1 level A 3 NULL NULL
+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 id A 39 NULL NULL BTREE
+t1 1 parent_id 1 parent_id A 9 NULL NULL BTREE
+t1 1 level 1 level A 3 NULL NULL BTREE
+drop table t1;
+CREATE TABLE t1 (
+gesuchnr int(11) DEFAULT '0' NOT NULL,
+benutzer_id int(11) DEFAULT '0' NOT NULL,
+PRIMARY KEY (gesuchnr,benutzer_id)
+) type=BDB;
+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);
+select * from t1;
gesuchnr benutzer_id
1 1
2 1
+drop table t1;
+create table t1 (id int not null primary key, x int not null, key (x)) type=bdb;
+insert into t1 (id, x) values (1, 1);
+replace into t1 (id, x) values (1, 2);
+select * from t1;
id x
1 2
+drop table t1;
+create table t1 (a int) type=bdb;
+insert into t1 values (1), (2);
+optimize table t1;
Table Op Msg_type Msg_text
test.t1 optimize status OK
+delete from t1 where a = 1;
+select * from t1;
a
2
+check table t1;
Table Op Msg_type Msg_text
test.t1 check error The handler for the table doesn't support check/repair
+drop table t1;
+create table t1 (a int,b varchar(20)) type=bdb;
+insert into t1 values (1,""), (2,"testing");
+delete from t1 where a = 1;
+select * from t1;
a b
2 testing
+create index skr on t1 (a);
+insert into t1 values (3,""), (4,"testing");
+analyze table t1;
Table Op Msg_type Msg_text
test.t1 analyze status OK
-Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Comment
-t1 1 skr 1 a A 3 NULL NULL
+show keys from t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 1 skr 1 a A 3 NULL NULL YES BTREE
+drop table t1;
+create table t1 (a int,b varchar(20),key(a)) type=bdb;
+insert into t1 values (1,""), (2,"testing");
+select * from t1 where a = 1;
a b
1
+drop table t1;
+create table t1 (a char(10) not null, b int not null auto_increment, primary key(a,b)) type=BDB;
+insert into t1 values ("a",1),("b",2),("a",2),("c",1);
+insert into t1 values ("a",NULL),("b",NULL),("c",NULL),("e",NULL);
+insert into t1 (a) values ("a"),("b"),("c"),("d");
+insert into t1 (a) values ('k'),('d');
+insert into t1 (a) values ("a");
+insert into t1 values ("d",last_insert_id());
+select * from t1;
a b
a 1
a 2
@@ -172,121 +251,290 @@ d 2
d 5
e 1
k 1
+flush tables;
+select count(*) from t1;
count(*)
16
+drop table t1;
+create table t1 (n int not null primary key) type=bdb;
+set autocommit=0;
+insert into t1 values (4);
+rollback;
+select n, "after rollback" from t1;
n after rollback
+insert into t1 values (4);
+commit;
+select n, "after commit" from t1;
n after commit
4 after commit
+commit;
+insert into t1 values (5);
+insert into t1 values (4);
+Duplicate entry '4' for key 1
+commit;
+select n, "after commit" from t1;
n after commit
4 after commit
5 after commit
+set autocommit=1;
+insert into t1 values (6);
+insert into t1 values (4);
+Duplicate entry '4' for key 1
+select n from t1;
n
4
5
6
+rollback;
+drop table t1;
+create table t1 ( id int NOT NULL PRIMARY KEY, nom varchar(64)) type=BDB;
+begin;
+insert into t1 values(1,'hamdouni');
+select id as afterbegin_id,nom as afterbegin_nom from t1;
afterbegin_id afterbegin_nom
1 hamdouni
+rollback;
+select id as afterrollback_id,nom as afterrollback_nom from t1;
afterrollback_id afterrollback_nom
+set autocommit=0;
+insert into t1 values(2,'mysql');
+select id as afterautocommit0_id,nom as afterautocommit0_nom from t1;
afterautocommit0_id afterautocommit0_nom
2 mysql
+rollback;
+select id as afterrollback_id,nom as afterrollback_nom from t1;
afterrollback_id afterrollback_nom
+set autocommit=1;
+drop table t1;
+CREATE TABLE t1 (id char(8) not null primary key, val int not null) type=bdb;
+insert into t1 values ('pippo', 12);
+insert into t1 values ('pippo', 12);
+Duplicate entry 'pippo' for key 1
+delete from t1;
+delete from t1 where id = 'pippo';
+select * from t1;
id val
+insert into t1 values ('pippo', 12);
+set autocommit=0;
+delete from t1;
+rollback;
+select * from t1;
id val
pippo 12
+delete from t1;
+commit;
+select * from t1;
id val
+drop table t1;
+set autocommit=1;
+CREATE TABLE t1 (ID INTEGER NOT NULL PRIMARY KEY, NAME VARCHAR(64)) TYPE=BDB;
+INSERT INTO t1 VALUES (1, 'Jochen');
+select * from t1;
ID NAME
1 Jochen
+drop table t1;
+CREATE TABLE t1 ( _userid VARCHAR(60) NOT NULL PRIMARY KEY) TYPE=BDB;
+set autocommit=0;
+INSERT INTO t1 SET _userid='marc@anyware.co.uk';
+COMMIT;
+SELECT * FROM t1;
_userid
marc@anyware.co.uk
+SELECT _userid FROM t1 WHERE _userid='marc@anyware.co.uk';
_userid
marc@anyware.co.uk
+drop table t1;
+set autocommit=1;
+CREATE TABLE t1 (
+user_id int(10) DEFAULT '0' NOT NULL,
+name varchar(100),
+phone varchar(100),
+ref_email varchar(100) DEFAULT '' NOT NULL,
+detail varchar(200),
+PRIMARY KEY (user_id,ref_email)
+)type=bdb;
+INSERT INTO t1 VALUES (10292,'sanjeev','29153373','sansh777@hotmail.com','xxx'),(10292,'shirish','2333604','shirish@yahoo.com','ddsds'),(10292,'sonali','323232','sonali@bolly.com','filmstar');
+select * from t1 where user_id=10292;
user_id name phone ref_email detail
10292 sanjeev 29153373 sansh777@hotmail.com xxx
10292 shirish 2333604 shirish@yahoo.com ddsds
10292 sonali 323232 sonali@bolly.com filmstar
+INSERT INTO t1 VALUES (10291,'sanjeev','29153373','sansh777@hotmail.com','xxx'),(10293,'shirish','2333604','shirish@yahoo.com','ddsds');
+select * from t1 where user_id=10292;
user_id name phone ref_email detail
10292 sanjeev 29153373 sansh777@hotmail.com xxx
10292 shirish 2333604 shirish@yahoo.com ddsds
10292 sonali 323232 sonali@bolly.com filmstar
+select * from t1 where user_id>=10292;
user_id name phone ref_email detail
10292 sanjeev 29153373 sansh777@hotmail.com xxx
10292 shirish 2333604 shirish@yahoo.com ddsds
10292 sonali 323232 sonali@bolly.com filmstar
10293 shirish 2333604 shirish@yahoo.com ddsds
+select * from t1 where user_id>10292;
user_id name phone ref_email detail
10293 shirish 2333604 shirish@yahoo.com ddsds
+select * from t1 where user_id<10292;
user_id name phone ref_email detail
10291 sanjeev 29153373 sansh777@hotmail.com xxx
-Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Comment
-t1 0 PRIMARY 1 a A NULL NULL NULL
-t1 0 PRIMARY 2 b A 0 NULL NULL
-t1 0 b 1 b A 0 NULL NULL
-t1 0 c 1 c A 0 NULL NULL
-t1 1 a 1 a A NULL NULL NULL
-t1 1 a_2 1 a A NULL NULL NULL
+drop table t1;
+CREATE TABLE t1 (a int not null, b int not null,c int not null,
+key(a),primary key(a,b), unique(c),key(a),unique(b));
+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 NULL NULL NULL BTREE
+t1 0 PRIMARY 2 b A 0 NULL NULL BTREE
+t1 0 c 1 c A 0 NULL NULL BTREE
+t1 0 b 1 b A 0 NULL NULL BTREE
+t1 1 a 1 a A NULL NULL NULL BTREE
+t1 1 a_2 1 a A NULL NULL NULL BTREE
+drop table t1;
+create table t1 (col1 int not null, col2 char(4) not null, primary key(col1));
+alter table t1 type=BDB;
+insert into t1 values ('1','1'),('5','2'),('2','3'),('3','4'),('4','4');
+select * from t1;
col1 col2
1 1
2 3
3 4
4 4
5 2
+update t1 set col2='7' where col1='4';
+select * from t1;
col1 col2
1 1
2 3
3 4
4 7
5 2
+alter table t1 add co3 int not null;
+select * from t1;
col1 col2 co3
1 1 0
2 3 0
3 4 0
4 7 0
5 2 0
+update t1 set col2='9' where col1='2';
+select * from t1;
col1 col2 co3
1 1 0
2 9 0
3 4 0
4 7 0
5 2 0
+drop table t1;
+create table t1 (a int not null , b int, primary key (a)) type = BDB;
+create table t2 (a int not null , b int, primary key (a)) type = myisam;
+insert into t1 VALUES (1,3) , (2,3), (3,3);
+select * from t1;
a b
1 3
2 3
3 3
+insert into t2 select * from t1;
+select * from t2;
a b
1 3
2 3
3 3
+delete from t1 where b = 3;
+select * from t1;
a b
+insert into t1 select * from t2;
+select * from t1;
a b
1 3
2 3
3 3
+select * from t2;
a b
1 3
2 3
3 3
+drop table t1,t2;
+CREATE TABLE t1 (
+id int(11) NOT NULL auto_increment,
+ggid varchar(32) binary DEFAULT '' NOT NULL,
+email varchar(64) DEFAULT '' NOT NULL,
+passwd varchar(32) binary DEFAULT '' NOT NULL,
+PRIMARY KEY (id),
+UNIQUE ggid (ggid)
+) TYPE=BDB;
+insert into t1 (ggid,passwd) values ('test1','xxx');
+insert into t1 (ggid,passwd) values ('test2','yyy');
+insert into t1 (ggid,passwd) values ('test2','this will fail');
+Duplicate entry 'test2' for key 2
+insert into t1 (ggid,id) values ('this will fail',1);
+Duplicate entry '1' for key 1
+select * from t1 where ggid='test1';
id ggid email passwd
1 test1 xxx
+select * from t1 where passwd='xxx';
id ggid email passwd
1 test1 xxx
+select * from t1 where id=2;
id ggid email passwd
2 test2 yyy
+replace into t1 (ggid,id) values ('this will work',1);
+replace into t1 (ggid,passwd) values ('test2','this will work');
+update t1 set id=100,ggid='test2' where id=1;
+Duplicate entry 'test2' for key 2
+select * from t1;
id ggid email passwd
1 this will work
3 test2 this will work
+select * from t1 where id=1;
id ggid email passwd
1 this will work
+select * from t1 where id=999;
id ggid email passwd
+drop table t1;
+CREATE TABLE t1 (
+user_name varchar(12),
+password text,
+subscribed char(1),
+user_id int(11) DEFAULT '0' NOT NULL,
+quota bigint(20),
+weight double,
+access_date date,
+access_time time,
+approved datetime,
+dummy_primary_key int(11) NOT NULL auto_increment,
+PRIMARY KEY (dummy_primary_key)
+) TYPE=BDB;
+INSERT INTO t1 VALUES ('user_0','somepassword','N',0,0,0,'2000-09-07','23:06:59','2000-09-07 23:06:59',1);
+INSERT INTO t1 VALUES ('user_1','somepassword','Y',1,1,1,'2000-09-07','23:06:59','2000-09-07 23:06:59',2);
+INSERT INTO t1 VALUES ('user_2','somepassword','N',2,2,1.4142135623731,'2000-09-07','23:06:59','2000-09-07 23:06:59',3);
+INSERT INTO t1 VALUES ('user_3','somepassword','Y',3,3,1.7320508075689,'2000-09-07','23:06:59','2000-09-07 23:06:59',4);
+INSERT INTO t1 VALUES ('user_4','somepassword','N',4,4,2,'2000-09-07','23:06:59','2000-09-07 23:06:59',5);
+select user_name, password , subscribed, user_id, quota, weight, access_date, access_time, approved, dummy_primary_key from t1 order by user_name;
user_name password subscribed user_id quota weight access_date access_time approved dummy_primary_key
user_0 somepassword N 0 0 0 2000-09-07 23:06:59 2000-09-07 23:06:59 1
user_1 somepassword Y 1 1 1 2000-09-07 23:06:59 2000-09-07 23:06:59 2
user_2 somepassword N 2 2 1.4142135623731 2000-09-07 23:06:59 2000-09-07 23:06:59 3
user_3 somepassword Y 3 3 1.7320508075689 2000-09-07 23:06:59 2000-09-07 23:06:59 4
user_4 somepassword N 4 4 2 2000-09-07 23:06:59 2000-09-07 23:06:59 5
+drop table t1;
+CREATE TABLE t1 (
+id int(11) NOT NULL auto_increment,
+parent_id int(11) DEFAULT '0' NOT NULL,
+level tinyint(4) DEFAULT '0' NOT NULL,
+KEY (id),
+KEY parent_id (parent_id),
+KEY level (level)
+) type=bdb;
+INSERT INTO t1 VALUES (1,0,0),(3,1,1),(4,1,1),(8,2,2),(9,2,2),(17,3,2),(22,4,2),(24,4,2),(28,5,2),(29,5,2),(30,5,2),(31,6,2),(32,6,2),(33,6,2),(203,7,2),(202,7,2),(20,3,2),(157,0,0),(193,5,2),(40,7,2),(2,1,1),(15,2,2),(6,1,1),(34,6,2),(35,6,2),(16,3,2),(7,1,1),(36,7,2),(18,3,2),(26,5,2),(27,5,2),(183,4,2),(38,7,2),(25,5,2),(37,7,2),(21,4,2),(19,3,2),(5,1,1);
+INSERT INTO t1 values (179,5,2);
+update t1 set parent_id=parent_id+100;
+select * from t1 where parent_id=102;
id parent_id level
8 102 2
9 102 2
15 102 2
+update t1 set id=id+1000;
+update t1 set id=1024 where id=1009;
+select * from t1;
id parent_id level
1001 100 0
1003 101 1
@@ -327,6 +575,8 @@ id parent_id level
1019 103 2
1005 101 1
1179 105 2
+update ignore t1 set id=id+1;
+select * from t1;
id parent_id level
1002 100 0
1004 101 1
@@ -367,12 +617,16 @@ id parent_id level
1020 103 2
1006 101 1
1180 105 2
+update ignore t1 set id=1023 where id=1010;
+select * from t1 where parent_id=102;
id parent_id level
1009 102 2
1025 102 2
1016 102 2
+explain select level from t1 where level=1;
table type possible_keys key key_len ref rows Extra
t1 ref level level 1 const 1 where used; Using index
+select level,id from t1 where level=1;
level id
1 1004
1 1005
@@ -380,6 +634,7 @@ level id
1 1007
1 1008
1 1006
+select level,id,parent_id from t1 where level=1;
level id parent_id
1 1004 101
1 1005 101
@@ -387,6 +642,7 @@ level id parent_id
1 1007 101
1 1008 101
1 1006 101
+select level,id from t1 where level=1 order by id;
level id
1 1003
1 1004
@@ -394,6 +650,8 @@ level id
1 1006
1 1007
1 1008
+delete from t1 where level=1;
+select * from t1;
id parent_id level
1002 100 0
1009 102 2
@@ -428,43 +686,86 @@ id parent_id level
1022 104 2
1020 103 2
1180 105 2
+drop table t1;
+CREATE TABLE t1 (
+sca_code char(6) NOT NULL,
+cat_code char(6) NOT NULL,
+sca_desc varchar(50),
+lan_code char(2) NOT NULL,
+sca_pic varchar(100),
+sca_sdesc varchar(50),
+sca_sch_desc varchar(16),
+PRIMARY KEY (sca_code, cat_code, lan_code),
+INDEX sca_pic (sca_pic)
+) type = bdb ;
+INSERT INTO t1 ( sca_code, cat_code, sca_desc, lan_code, sca_pic, sca_sdesc, sca_sch_desc) VALUES ( 'PD', 'J', 'PENDANT', 'EN', NULL, NULL, 'PENDANT'),( 'RI', 'J', 'RING', 'EN', NULL, NULL, 'RING'),( 'QQ', 'N', 'RING', 'EN', 'not null', NULL, 'RING');
+select count(*) from t1 where sca_code = 'PD';
count(*)
1
+select count(*) from t1 where sca_code <= 'PD';
count(*)
1
+select count(*) from t1 where sca_pic is null;
count(*)
2
+alter table t1 drop index sca_pic, add index sca_pic (cat_code, sca_pic);
+select count(*) from t1 where sca_code='PD' and sca_pic is null;
count(*)
1
+select count(*) from t1 where cat_code='E';
count(*)
0
+alter table t1 drop index sca_pic, add index (sca_pic, cat_code);
+select count(*) from t1 where sca_code='PD' and sca_pic is null;
count(*)
1
+select count(*) from t1 where sca_pic >= 'n';
count(*)
1
+select sca_pic from t1 where sca_pic is null;
sca_pic
NULL
NULL
+update t1 set sca_pic="test" where sca_pic is null;
+delete from t1 where sca_code='pd';
+drop table t1;
+set @a:=now();
+CREATE TABLE t1 (a int not null, b timestamp not null, primary key (a)) type=bdb;
+insert into t1 (a) values(1),(2),(3);
+select t1.a from t1 natural join t1 as t2 where t1.b >= @a order by t1.a;
a
1
2
3
+update t1 set a=5 where a=1;
+select a from t1;
a
2
3
5
+drop table t1;
+flush logs;
+create table t1 (b blob, i int, key (b(100)), key (i), key (i, b(20))) type=bdb;
+insert into t1 values ('this is a blob', 1), (null, -1), (null, null),("",1),("",2),("",3);
+select b from t1 where b = 'this is a blob';
b
this is a blob
+select * from t1 where b like 't%';
b i
this is a blob 1
+select b, i from t1 where b is not null;
b i
this is a blob 1
1
2
3
+select * from t1 where b is null and i > 0;
b i
+select * from t1 where i is NULL;
b i
NULL NULL
+update t1 set b='updated' where i=1;
+select * from t1;
b i
updated 1
NULL -1
@@ -472,63 +773,353 @@ NULL NULL
updated 1
2
3
+drop table t1;
+create table t1 (a varchar(100) not null, primary key(a), b int not null) type=bdb;
+insert into t1 values("hello",1),("world",2);
+select * from t1 order by b desc;
a b
world 2
hello 1
+optimize table t1;
Table Op Msg_type Msg_text
test.t1 optimize status OK
-Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Comment
-t1 0 PRIMARY 1 a A 2 NULL NULL
+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 a A 2 NULL NULL BTREE
+drop table t1;
+create table t1 (i int, j int )TYPE=BDB;
+insert into t1 values (1,2);
+select * from t1 where i=1 and j=2;
i j
1 2
+create index ax1 on t1 (i,j);
+select * from t1 where i=1 and j=2;
i j
1 2
+drop table t1;
+drop table if exists t1, t2, t3, t4, t5, t6, t7;
+create table t1
+(
+branch_id int auto_increment primary key,
+branch_name varchar(255) not null,
+branch_active int not null default 1,
+unique branch_name(branch_name),
+index branch_active(branch_active)
+) type=bdb;
+drop table if exists t2 ;
+create table t2
+(
+target_id int auto_increment primary key,
+target_name varchar(255) not null,
+target_active int not null default 1,
+unique target_name(target_name),
+index target_active(target_active)
+) type=bdb;
+drop table if exists t3 ;
+create table t3
+(
+platform_id int auto_increment primary key,
+platform_name varchar(255) not null,
+platform_active int not null default 1,
+unique platform_name(platform_name),
+index platform_active(platform_active)
+) type=bdb;
+drop table if exists t4 ;
+create table t4
+(
+product_id int auto_increment primary key,
+product_name varchar(255) not null,
+version_file varchar(255) not null,
+product_active int not null default 1,
+unique product_name(product_name),
+index product_active(product_active)
+) type=bdb;
+drop table if exists t5 ;
+create table t5
+(
+product_file_id int auto_increment primary key,
+product_id int not null,
+file_name varchar(255) not null,
+/* cvs module used to find the file version */
+module_name varchar(255) not null,
+/* flag whether the file is still included in the product */
+file_included int not null default 1,
+unique product_file(product_id,file_name),
+index file_included(file_included)
+) type=bdb;
+drop table if exists t6 ;
+create table t6
+(
+file_platform_id int auto_increment primary key,
+product_file_id int not null,
+platform_id int not null,
+branch_id int not null,
+/* filename in the build system */
+build_filename varchar(255) not null,
+/* default filename in the build archive */
+archive_filename varchar(255) not null,
+unique file_platform(product_file_id,platform_id,branch_id)
+) type=bdb;
+drop table if exists t8 ;
+create table t8
+(
+archive_id int auto_increment primary key,
+branch_id int not null,
+target_id int not null,
+platform_id int not null,
+product_id int not null,
+status_id int not null default 1,
+unique archive(branch_id,target_id,platform_id,product_id),
+index status_id(status_id)
+) type=bdb;
+drop table if exists t7 ;
+create table t7
+(
+build_id int auto_increment primary key,
+branch_id int not null,
+target_id int not null,
+build_number int not null,
+build_date date not null,
+/* build system tag, e.g. 'rmanight-022301-1779' */
+build_tag varchar(255) not null,
+/* path relative to the build archive root, e.g. 'current' */
+build_path text not null,
+unique build(branch_id,target_id,build_number)
+) type=bdb;
+insert into t1 (branch_name)
+values ('RealMedia');
+insert into t1 (branch_name)
+values ('RP8REV');
+insert into t1 (branch_name)
+values ('SERVER_8_0_GOLD');
+insert into t2 (target_name)
+values ('rmanight');
+insert into t2 (target_name)
+values ('playerall');
+insert into t2 (target_name)
+values ('servproxyall');
+insert into t3 (platform_name)
+values ('linux-2.0-libc6-i386');
+insert into t3 (platform_name)
+values ('win32-i386');
+insert into t4 (product_name, version_file)
+values ('realserver', 'servinst');
+insert into t4 (product_name, version_file)
+values ('realproxy', 'prxyinst');
+insert into t4 (product_name, version_file)
+values ('realplayer', 'playinst');
+insert into t4 (product_name, version_file)
+values ('plusplayer', 'plusinst');
+create temporary table tmp1
+select branch_id, target_id, platform_id, product_id
+from t1, t2, t3, t4 ;
+create temporary table tmp2
+select tmp1.branch_id, tmp1.target_id, tmp1.platform_id, tmp1.product_id
+from tmp1 left join t8
+using (branch_id,target_id,platform_id,product_id)
+where t8.archive_id is null ;
+insert into t8
+(branch_id, target_id, platform_id, product_id, status_id)
+select branch_id, target_id, platform_id, product_id, 1
+from tmp2 ;
+drop table tmp1 ;
+drop table tmp2 ;
+insert into t5 (product_id, file_name, module_name)
+values (1, 'servinst', 'server');
+insert into t5 (product_id, file_name, module_name)
+values (2, 'prxyinst', 'server');
+insert into t5 (product_id, file_name, module_name)
+values (3, 'playinst', 'rpapp');
+insert into t5 (product_id, file_name, module_name)
+values (4, 'plusinst', 'rpapp');
+insert into t6
+(product_file_id,platform_id,branch_id,build_filename,archive_filename)
+values (1, 2, 3, 'servinst.exe', 'win32-servinst.exe');
+insert into t6
+(product_file_id,platform_id,branch_id,build_filename,archive_filename)
+values (1, 1, 3, 'v80_linux-2.0-libc6-i386_servinst.bin', 'linux2-servinst.exe');
+insert into t6
+(product_file_id,platform_id,branch_id,build_filename,archive_filename)
+values (3, 2, 2, 'playinst.exe', 'win32-playinst.exe');
+insert into t6
+(product_file_id,platform_id,branch_id,build_filename,archive_filename)
+values (4, 2, 2, 'playinst.exe', 'win32-playinst.exe');
+insert into t7
+(branch_id,target_id,build_number,build_tag,build_date,build_path)
+values (2, 2, 1071, 'playerall-022101-1071', '2001-02-21', 'current');
+insert into t7
+(branch_id,target_id,build_number,build_tag,build_date,build_path)
+values (2, 2, 1072, 'playerall-022201-1072', '2001-02-22', 'current');
+insert into t7
+(branch_id,target_id,build_number,build_tag,build_date,build_path)
+values (3, 3, 388, 'servproxyall-022201-388', '2001-02-22', 'current');
+insert into t7
+(branch_id,target_id,build_number,build_tag,build_date,build_path)
+values (3, 3, 389, 'servproxyall-022301-389', '2001-02-23', 'current');
+insert into t7
+(branch_id,target_id,build_number,build_tag,build_date,build_path)
+values (4, 4, 100, 'foo target-010101-100', '2001-01-01', 'current');
+update t8
+set status_id=2
+where branch_id=2 and target_id=2 and platform_id=2 and product_id=1;
+select t7.build_path
+from
+t1,
+t7,
+t2,
+t3,
+t4,
+t5,
+t6
+where
+t7.branch_id = t1.branch_id and
+t7.target_id = t2.target_id and
+t5.product_id = t4.product_id and
+t6.product_file_id = t5.product_file_id and
+t6.platform_id = t3.platform_id and
+t6.branch_id = t6.branch_id and
+t7.build_id = 1 and
+t4.product_id = 3 and
+t5.file_name = 'playinst' and
+t3.platform_id = 2;
build_path
current
+drop table t1, t2, t3, t4, t5, t6, t7, t8;
+CREATE TABLE t1 (
+a tinytext NOT NULL,
+b tinyint(3) unsigned NOT NULL default '0',
+PRIMARY KEY (a(32),b)
+) TYPE=BDB;
+INSERT INTO t1 VALUES ('a',1),('a',2);
+SELECT * FROM t1 WHERE a='a' AND b=2;
a b
a 2
+SELECT * FROM t1 WHERE a='a' AND b in (2);
a b
a 2
+SELECT * FROM t1 WHERE a='a' AND b in (1,2);
a b
a 1
a 2
+drop table t1;
+CREATE TABLE t1 (
+a int3 unsigned NOT NULL,
+b int1 unsigned NOT NULL,
+UNIQUE (a, b)
+) TYPE = BDB;
+INSERT INTO t1 VALUES (1, 1);
+SELECT MIN(B),MAX(b) FROM t1 WHERE t1.a = 1;
MIN(B) MAX(b)
1 1
+drop table t1;
+create table t1 (id int NOT NULL,id2 int NOT NULL,id3 int NOT NULL,dummy1 char(30),primary key (id,id2),index index_id3 (id3)) type=bdb;
+insert into t1 values (0,0,0,'ABCDEFGHIJ'),(2,2,2,'BCDEFGHIJK'),(1,1,1,'CDEFGHIJKL');
+LOCK TABLES t1 WRITE;
+insert into t1 values (99,1,2,'D'),(1,1,2,'D');
+Duplicate entry '1-1' for key 1
+select id from t1;
id
0
1
2
+select id from t1;
id
0
1
2
+UNLOCK TABLES;
+DROP TABLE t1;
+create table t1 (id int NOT NULL,id2 int NOT NULL,id3 int NOT NULL,dummy1 char(30),primary key (id,id2),index index_id3 (id3)) type=bdb;
+insert into t1 values (0,0,0,'ABCDEFGHIJ'),(2,2,2,'BCDEFGHIJK'),(1,1,1,'CDEFGHIJKL');
+LOCK TABLES t1 WRITE;
+begin;
+insert into t1 values (99,1,2,'D'),(1,1,2,'D');
+Duplicate entry '1-1' for key 1
+select id from t1;
id
0
1
2
+insert ignore into t1 values (100,1,2,'D'),(1,1,99,'D');
+commit;
+select id,id3 from t1;
id id3
0 0
1 1
2 2
100 2
+UNLOCK TABLES;
+DROP TABLE t1;
+CREATE TABLE t1 (SYAIN_NO char(5) NOT NULL default '', KINMU_DATE char(6) NOT NULL default '', PRIMARY KEY (SYAIN_NO,KINMU_DATE)) TYPE=BerkeleyDB;
+CREATE TABLE t2 ( SYAIN_NO char(5) NOT NULL default '',STR_DATE char(8) NOT NULL default '',PRIMARY KEY (SYAIN_NO,STR_DATE) ) TYPE=BerkeleyDB;
+select T1.KINMU_DATE from t1 T1 ,t2 T2 where T1.SYAIN_NO = '12345' and T1.KINMU_DATE = '200106' and T2.SYAIN_NO = T1.SYAIN_NO;
KINMU_DATE
+select T1.KINMU_DATE from t1 T1 ,t2 T2 where T1.SYAIN_NO = '12345' and T1.KINMU_DATE = '200106' and T2.SYAIN_NO = T1.SYAIN_NO;
KINMU_DATE
+DROP TABLE t1,t2;
+drop table if exists t1;
+create table t1 (a int(11) not null, b int(11) not null, unique (a,b)) type=bdb;
+insert into t1 values (1,1), (1,2);
+select * from t1 where a = 1;
a b
1 1
1 2
+select t1.*, t2.* from t1, t1 t2 where t1.a = t2.a and t2.a = 1;
a b a b
1 1 1 1
1 1 1 2
1 2 1 1
1 2 1 2
+select * from t1 where a = 1;
a b
1 1
1 2
+drop table t1;
+create table t1 (id int NOT NULL,id2 int NOT NULL,id3 int NOT NULL,dummy1 char(30),primary key (id,id2),index index_id3 (id3)) type=bdb;
+insert into t1 values (0,0,0,'ABCDEFGHIJ');
+create table t2 (id int NOT NULL,primary key (id)) type=bdb;
+LOCK TABLES t1 WRITE, t2 WRITE;
+insert into t2 values(1);
+SELECT t1.* FROM t1 WHERE id IN (1);
id id2 id3 dummy1
+SELECT t1.* FROM t2 left outer join t1 on (t1.id=t2.id);
id id2 id3 dummy1
NULL NULL NULL NULL
+delete from t1 where id3 >= 0 and id3 <= 0;
+drop table t1,t2;
+CREATE TABLE t1 (i varchar(48) NOT NULL default '', p varchar(255) default NULL,s varchar(48) NOT NULL default '', PRIMARY KEY (i), UNIQUE(p,s)) TYPE=BDB;
+INSERT INTO t1 VALUES ('00000000-e6c4ddeaa6-003b8-83458387','programs/xxxxxxxx.wmv','00000000-e6c4ddeb32-003bc-83458387');
+SELECT * FROM t1 WHERE p='programs/xxxxxxxx.wmv';
i p s
00000000-e6c4ddeaa6-003b8-83458387 programs/xxxxxxxx.wmv 00000000-e6c4ddeb32-003bc-83458387
+drop table t1;
+CREATE TABLE t1 ( STR_DATE varchar(8) NOT NULL default '',INFO_NOTE varchar(200) default NULL,PRIMARY KEY (STR_DATE) ) TYPE=BerkeleyDB;
+select INFO_NOTE from t1 where STR_DATE = '20010610';
INFO_NOTE
+select INFO_NOTE from t1 where STR_DATE < '20010610';
INFO_NOTE
+select INFO_NOTE from t1 where STR_DATE > '20010610';
INFO_NOTE
+drop table t1;
+create table t1 (a int not null, b int, primary key (a)) type =bdb;
+create table t2 (a int not null, b int, primary key (a)) type =bdb;
+insert into t1 values (2, 3),(1, 7),(10, 7);
+insert into t2 values (2, 3),(1, 7),(10, 7);
+select * from t1;
+a b
+1 7
+2 3
+10 7
+select * from t2;
+a b
+1 7
+2 3
+10 7
+delete t1, t2 from t1, t2 where t1.a = t2.a;
+select * from t1;
+a b
+select * from t2;
+a b
+select * from t2;
+a b
+drop table t1,t2;
diff --git a/mysql-test/r/bench_count_distinct.result b/mysql-test/r/bench_count_distinct.result
index 20f23c0abbe..d414e8e466e 100644
--- a/mysql-test/r/bench_count_distinct.result
+++ b/mysql-test/r/bench_count_distinct.result
@@ -1,2 +1,6 @@
+drop table if exists t1;
+create table t1(n int not null, key(n)) delay_key_write = 1;
+select count(distinct n) from t1;
count(distinct n)
100
+drop table t1;
diff --git a/mysql-test/r/big_test.require b/mysql-test/r/big_test.require
new file mode 100644
index 00000000000..001b903496b
--- /dev/null
+++ b/mysql-test/r/big_test.require
@@ -0,0 +1,2 @@
+using_big_test
+1
diff --git a/mysql-test/r/bigint.result b/mysql-test/r/bigint.result
index 46ce0fda2c1..f2cb6437f8f 100644
--- a/mysql-test/r/bigint.result
+++ b/mysql-test/r/bigint.result
@@ -1,15 +1,78 @@
+select 0,256,00000000000000065536,2147483647,-2147483648,2147483648,+4294967296;
0 256 00000000000000065536 2147483647 -2147483648 2147483648 +4294967296
0 256 65536 2147483647 -2147483648 2147483648 4294967296
+select 9223372036854775807,-009223372036854775808;
9223372036854775807 -009223372036854775808
9223372036854775807 -9223372036854775808
+select +9999999999999999999,-9999999999999999999;
+9999999999999999999 -9999999999999999999
10000000000000000000 -10000000000000000000
+drop table if exists t1;
+create table t1 (a bigint unsigned not null, primary key(a));
+insert into t1 values (18446744073709551615), (0xFFFFFFFFFFFFFFFE);
+select * from t1;
a
18446744073709551614
18446744073709551615
+select * from t1 where a=18446744073709551615;
a
18446744073709551615
+select * from t1 where a='18446744073709551615';
a
18446744073709551615
+delete from t1 where a=18446744073709551615;
+select * from t1;
a
18446744073709551614
+drop table t1;
+create table t1 ( a int not null default 1, big bigint );
+insert into t1 (big) values (-1),(12345678901234567),(9223372036854775807),(18446744073709551615);
+select min(big),max(big),max(big)-1 from t1;
+min(big) max(big) max(big)-1
+-1 9223372036854775807 9223372036854775806
+select min(big),max(big),max(big)-1 from t1 group by a;
+min(big) max(big) max(big)-1
+-1 9223372036854775807 9223372036854775806
+alter table t1 modify big bigint unsigned not null;
+select min(big),max(big),max(big)-1 from t1;
+min(big) max(big) max(big)-1
+12345678901234567 18446744073709551615 18446744073709551614
+select min(big),max(big),max(big)-1 from t1 group by a;
+min(big) max(big) max(big)-1
+12345678901234567 18446744073709551615 18446744073709551614
+alter table t1 add key (big);
+select min(big),max(big),max(big)-1 from t1;
+min(big) max(big) max(big)-1
+12345678901234567 18446744073709551615 18446744073709551614
+select min(big),max(big),max(big)-1 from t1 group by a;
+min(big) max(big) max(big)-1
+12345678901234567 18446744073709551615 18446744073709551614
+alter table t1 modify big bigint not null;
+select min(big),max(big),max(big)-1 from t1;
+min(big) max(big) max(big)-1
+-1 9223372036854775807 9223372036854775806
+select min(big),max(big),max(big)-1 from t1 group by a;
+min(big) max(big) max(big)-1
+-1 9223372036854775807 9223372036854775806
+drop table t1;
+select CAST(1-2 AS UNSIGNED);
+CAST(1-2 AS UNSIGNED)
+18446744073709551615
+select CAST(CAST(1-2 AS UNSIGNED) AS SIGNED INTEGER);
+CAST(CAST(1-2 AS UNSIGNED) AS SIGNED INTEGER)
+-1
+select CONVERT('-1',UNSIGNED);
+CONVERT('-1',UNSIGNED)
+18446744073709551615
+select cast(-5 as unsigned) | 1, cast(-5 as unsigned) & -1;
+cast(-5 as unsigned) | 1 cast(-5 as unsigned) & -1
+18446744073709551611 18446744073709551611
+select cast(-5 as unsigned) -1, cast(-5 as unsigned) + 1;
+cast(-5 as unsigned) -1 cast(-5 as unsigned) + 1
+18446744073709551610 18446744073709551612
+select ~5, cast(~5 as signed);
+~5 cast(~5 as signed)
+18446744073709551610 -6
+select cast(5 as unsigned) -6.0;
+cast(5 as unsigned) -6.0
+-1.0
diff --git a/mysql-test/r/binary.result b/mysql-test/r/binary.result
index c5f9961699d..9f1c8ffac41 100644
--- a/mysql-test/r/binary.result
+++ b/mysql-test/r/binary.result
@@ -1,33 +1,55 @@
+create table t1 (name char(20) not null, primary key (name));
+create table t2 (name char(20) binary not null, primary key (name));
+insert into t1 values ("å");
+insert into t1 values ("ä");
+insert into t1 values ("ö");
+insert into t2 select * from t1;
+select * from t1 order by name;
name
å
ä
ö
+select concat("*",name,"*") from t1 order by 1;
concat("*",name,"*")
*å*
*ä*
*ö*
+select min(name),min(concat("*",name,"*")),max(name),max(concat("*",name,"*")) from t1;
min(name) min(concat("*",name,"*")) max(name) max(concat("*",name,"*"))
å *å* ö *ö*
+select * from t2 order by name;
name
ä
å
ö
+select concat("*",name,"*") from t2 order by 1;
concat("*",name,"*")
*ä*
*å*
*ö*
+select min(name),min(concat("*",name,"*")),max(name),max(concat("*",name,"*")) from t2;
min(name) min(concat("*",name,"*")) max(name) max(concat("*",name,"*"))
ä *ä* ö *ö*
+select name from t1 where name between 'Ä' and 'Ö';
name
ä
ö
+select name from t2 where name between 'ä' and 'ö';
name
ä
å
ö
+select name from t2 where name between 'Ä' and 'Ö';
name
+drop table t1,t2;
+create table t1 (a char(10) not null, b char(10) binary not null,index (a));
+insert into t1 values ("hello ","hello "),("hello2 ","hello2 ");
+select * from t1 where a="hello ";
a b
hello hello
+select * from t1 where b="hello ";
a b
+select * from t1 where b="hello";
a b
hello hello
+drop table t1;
diff --git a/mysql-test/r/bulk_replace.result b/mysql-test/r/bulk_replace.result
new file mode 100644
index 00000000000..0a079965b82
--- /dev/null
+++ b/mysql-test/r/bulk_replace.result
@@ -0,0 +1,11 @@
+drop table if exists t1;
+CREATE TABLE t1 (a int, unique (a), b int not null, unique(b), c int not null, index(c));
+replace into t1 values (1,1,1),(2,2,2),(3,1,3);
+select * from t1;
+a b c
+3 1 3
+2 2 2
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
diff --git a/mysql-test/r/case.result b/mysql-test/r/case.result
index 073164aa035..ec37c9a5763 100644
--- a/mysql-test/r/case.result
+++ b/mysql-test/r/case.result
@@ -1,42 +1,65 @@
+drop table if exists t1;
+select CASE "b" when "a" then 1 when "b" then 2 END;
CASE "b" when "a" then 1 when "b" then 2 END
2
+select CASE "c" when "a" then 1 when "b" then 2 END;
CASE "c" when "a" then 1 when "b" then 2 END
NULL
+select CASE "c" when "a" then 1 when "b" then 2 ELSE 3 END;
CASE "c" when "a" then 1 when "b" then 2 ELSE 3 END
3
+select CASE BINARY "b" when "a" then 1 when "B" then 2 WHEN "b" then "ok" END;
CASE BINARY "b" when "a" then 1 when "B" then 2 WHEN "b" then "ok" END
ok
+select CASE "b" when "a" then 1 when binary "B" then 2 WHEN "b" then "ok" END;
CASE "b" when "a" then 1 when binary "B" then 2 WHEN "b" then "ok" END
ok
+select CASE concat("a","b") when concat("ab","") then "a" when "b" then "b" end;
CASE concat("a","b") when concat("ab","") then "a" when "b" then "b" end
a
+select CASE when 1=0 then "true" else "false" END;
CASE when 1=0 then "true" else "false" END
false
+select CASE 1 when 1 then "one" WHEN 2 then "two" ELSE "more" END;
CASE 1 when 1 then "one" WHEN 2 then "two" ELSE "more" END
one
+select CASE 2.0 when 1 then "one" WHEN 2.0 then "two" ELSE "more" END;
CASE 2.0 when 1 then "one" WHEN 2.0 then "two" ELSE "more" END
two
+select (CASE "two" when "one" then "1" WHEN "two" then "2" END) | 0;
(CASE "two" when "one" then "1" WHEN "two" then "2" END) | 0
2
+select (CASE "two" when "one" then 1.00 WHEN "two" then 2.00 END) +0.0;
(CASE "two" when "one" then 1.00 WHEN "two" then 2.00 END) +0.0
2.00
+select case 1/0 when "a" then "true" else "false" END;
case 1/0 when "a" then "true" else "false" END
false
+select case 1/0 when "a" then "true" END;
case 1/0 when "a" then "true" END
NULL
+select (case 1/0 when "a" then "true" END) | 0;
(case 1/0 when "a" then "true" END) | 0
NULL
+select (case 1/0 when "a" then "true" END) + 0.0;
(case 1/0 when "a" then "true" END) + 0.0
NULL
+select case when 1>0 then "TRUE" else "FALSE" END;
case when 1>0 then "TRUE" else "FALSE" END
TRUE
+select case when 1<0 then "TRUE" else "FALSE" END;
case when 1<0 then "TRUE" else "FALSE" END
FALSE
+create table t1 (a int);
+insert into t1 values(1),(2),(3),(4);
+select case a when 1 then 2 when 2 then 3 else 0 end as fcase, count(*) from t1 group by fcase;
fcase count(*)
0 2
2 1
3 1
+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
one 1
two 1
+drop table t1;
diff --git a/mysql-test/r/check.result b/mysql-test/r/check.result
index 694d7429a14..ecaa13642bd 100644
--- a/mysql-test/r/check.result
+++ b/mysql-test/r/check.result
@@ -1,2 +1,7 @@
+drop table if exists t1;
+create table t1(n int not null, key(n), key(n), key(n), key(n));
+ check table t1 extended;
+insert into t1 values (200000);
Table Op Msg_type Msg_text
test.t1 check status OK
+drop table t1;
diff --git a/mysql-test/r/comments.result b/mysql-test/r/comments.result
index 7044667e4af..8092f789954 100644
--- a/mysql-test/r/comments.result
+++ b/mysql-test/r/comments.result
@@ -1,15 +1,28 @@
+select 1+2/*hello*/+3;
1+2/*hello*/+3
6
+select 1 /* long
+multi line comment */;
1
1
+;
+Query was empty
+select 1 /*!32301 +1 */;
1 /*!32301 +1
2
+select 1 /*!52301 +1 */;
1
1
+select 1--1;
1--1
2
+select 1 --2
++1;
1 --2
+1
4
+select 1 # The rest of the row will be ignored
+;
1
1
+/* line with only comment */;
diff --git a/mysql-test/r/compare.result b/mysql-test/r/compare.result
index 6af85c16dff..07f9ce4e81a 100644
--- a/mysql-test/r/compare.result
+++ b/mysql-test/r/compare.result
@@ -1,6 +1,14 @@
+drop table if exists t1;
+CREATE TABLE t1 (id CHAR(12) not null, PRIMARY KEY (id));
+insert into t1 values ('000000000001'),('000000000002');
+explain select * from t1 where id=000000000001;
table type possible_keys key key_len ref rows Extra
t1 index PRIMARY PRIMARY 12 NULL 2 where used; Using index
+select * from t1 where id=000000000001;
id
000000000001
+delete from t1 where id=000000000002;
+select * from t1;
id
000000000001
+drop table t1;
diff --git a/mysql-test/r/count_distinct.result b/mysql-test/r/count_distinct.result
index 97d7b57f249..3bff6c6ad88 100644
--- a/mysql-test/r/count_distinct.result
+++ b/mysql-test/r/count_distinct.result
@@ -1,11 +1,46 @@
+drop table if exists t1,t2,t3;
+create table t1 (libname varchar(21) not null, city text, primary key (libname));
+create table t2 (isbn varchar(21) not null, author text, title text, primary key (isbn));
+create table t3 (isbn varchar(21) not null, libname varchar(21) not null, quantity int ,primary key (isbn,libname));
+insert into t2 values ('001','Daffy','A duck''s life');
+insert into t2 values ('002','Bugs','A rabbit\'s life');
+insert into t2 values ('003','Cowboy','Life on the range');
+insert into t2 values ('000','Anonymous','Wanna buy this book?');
+insert into t2 values ('004','Best Seller','One Heckuva book');
+insert into t2 values ('005','EveryoneBuys','This very book');
+insert into t2 values ('006','San Fran','It is a san fran lifestyle');
+insert into t2 values ('007','BerkAuthor','Cool.Berkley.the.book');
+insert into t3 values('000','New York Public Libra','1');
+insert into t3 values('001','New York Public Libra','2');
+insert into t3 values('002','New York Public Libra','3');
+insert into t3 values('003','New York Public Libra','4');
+insert into t3 values('004','New York Public Libra','5');
+insert into t3 values('005','New York Public Libra','6');
+insert into t3 values('006','San Fransisco Public','5');
+insert into t3 values('007','Berkeley Public1','3');
+insert into t3 values('007','Berkeley Public2','3');
+insert into t3 values('001','NYC Lib','8');
+insert into t1 values ('New York Public Libra','New York');
+insert into t1 values ('San Fransisco Public','San Fran');
+insert into t1 values ('Berkeley Public1','Berkeley');
+insert into t1 values ('Berkeley Public2','Berkeley');
+insert into t1 values ('NYC Lib','New York');
+select t2.isbn,city,t1.libname,count(t1.libname) as a from t3 left join t1 on t3.libname=t1.libname left join t2 on t3.isbn=t2.isbn group by city,t1.libname;
isbn city libname a
007 Berkeley Berkeley Public1 1
007 Berkeley Berkeley Public2 1
000 New York New York Public Libra 6
001 New York NYC Lib 1
006 San Fran San Fransisco Public 1
+select t2.isbn,city,t1.libname,count(distinct t1.libname) as a from t3 left join t1 on t3.libname=t1.libname left join t2 on t3.isbn=t2.isbn group by city having count(distinct t1.libname) > 1;
isbn city libname a
007 Berkeley Berkeley Public1 2
000 New York New York Public Libra 2
+drop table t1, t2, t3;
+create table t1 (f1 int);
+insert into t1 values (1);
+create table t2 (f1 int,f2 int);
+select t1.f1,count(distinct t2.f2),count(distinct 1,NULL) from t1 left join t2 on t1.f1=t2.f1 group by t1.f1;
f1 count(distinct t2.f2) count(distinct 1,NULL)
1 0 0
+drop table t1,t2;
diff --git a/mysql-test/r/count_distinct2.result b/mysql-test/r/count_distinct2.result
new file mode 100644
index 00000000000..131e3b325ec
--- /dev/null
+++ b/mysql-test/r/count_distinct2.result
@@ -0,0 +1,129 @@
+drop table if exists t1;
+create table t1(n1 int, n2 int, s char(20), vs varchar(20), t text);
+insert into t1 values (1,11, 'one','eleven', 'eleven'),
+(1,11, 'one','eleven', 'eleven'),
+(2,11, 'two','eleven', 'eleven'),
+(2,12, 'two','twevle', 'twelve'),
+(2,13, 'two','thirteen', 'foo'),
+(2,13, 'two','thirteen', 'foo'),
+(2,13, 'two','thirteen', 'bar'),
+(NULL,13, 'two','thirteen', 'bar'),
+(2,NULL, 'two','thirteen', 'bar'),
+(2,13, NULL,'thirteen', 'bar'),
+(2,13, 'two',NULL, 'bar'),
+(2,13, 'two','thirteen', NULL);
+select distinct n1 from t1;
+n1
+1
+2
+NULL
+select count(distinct n1) from t1;
+count(distinct n1)
+2
+select distinct n2 from t1;
+n2
+11
+12
+13
+NULL
+select count(distinct n2) from t1;
+count(distinct n2)
+3
+select distinct s from t1;
+s
+one
+two
+NULL
+select count(distinct s) from t1;
+count(distinct s)
+2
+select distinct vs from t1;
+vs
+eleven
+twevle
+thirteen
+NULL
+select count(distinct vs) from t1;
+count(distinct vs)
+3
+select distinct t from t1;
+t
+eleven
+twelve
+foo
+bar
+NULL
+select count(distinct t) from t1;
+count(distinct t)
+4
+select distinct n1,n2 from t1;
+n1 n2
+1 11
+2 11
+2 12
+2 13
+NULL 13
+2 NULL
+select count(distinct n1,n2) from t1;
+count(distinct n1,n2)
+4
+select distinct n1,s from t1;
+n1 s
+1 one
+2 two
+NULL two
+2 NULL
+select count(distinct n1,s) from t1;
+count(distinct n1,s)
+2
+select distinct s,n1,vs from t1;
+s n1 vs
+one 1 eleven
+two 2 eleven
+two 2 twevle
+two 2 thirteen
+two NULL thirteen
+NULL 2 thirteen
+two 2 NULL
+select count(distinct s,n1,vs) from t1;
+count(distinct s,n1,vs)
+4
+select distinct s,t from t1;
+s t
+one eleven
+two eleven
+two twelve
+two foo
+two bar
+NULL bar
+two NULL
+select count(distinct s,t) from t1;
+count(distinct s,t)
+5
+select count(distinct n1), count(distinct n2) from t1;
+count(distinct n1) count(distinct n2)
+2 3
+select count(distinct n2), n1 from t1 group by n1;
+count(distinct n2) n1
+1 NULL
+1 1
+3 2
+drop table t1;
+create table t1 (n int default NULL);
+flush status;
+select count(distinct n) from t1;
+count(distinct n)
+5000
+show status like 'Created_tmp_disk_tables';
+Variable_name Value
+Created_tmp_disk_tables 1
+drop table t1;
+create table t1 (s text);
+flush status;
+select count(distinct s) from t1;
+count(distinct s)
+5000
+show status like 'Created_tmp_disk_tables';
+Variable_name Value
+Created_tmp_disk_tables 1
+drop table t1;
diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result
index 88d597bd3d7..ef44e840a79 100644
--- a/mysql-test/r/create.result
+++ b/mysql-test/r/create.result
@@ -1,17 +1,101 @@
+drop table if exists t1,t2;
+create table t1 (b char(0));
+insert into t1 values (""),(null);
+select * from t1;
b
NULL
+drop table if exists t1;
+create table t1 (b char(0) not null);
+create table if not exists t1 (b char(0) not null);
+insert into t1 values (""),(null);
+select * from t1;
b
+drop table if exists t1;
+create table t2 type=heap select * from t1;
+Table 'test.t1' doesn't exist
+create table t2 select auto+1 from t1;
+Table 'test.t1' doesn't exist
+drop table if exists t1,t2;
+create table t1 (b char(0) not null, index(b));
+The used table handler can't index column 'b'
+create table t1 (a int not null auto_increment,primary key (a)) type=heap;
+The used table type doesn't support AUTO_INCREMENT columns
+create table t1 (a int not null,b text) type=heap;
+The used table type doesn't support BLOB/TEXT columns
+create table t1 (a int ,primary key(a)) type=heap;
+All parts of a PRIMARY KEY must be NOT NULL; If you need NULL in a key, use UNIQUE instead
+drop table if exists t1;
+create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null, primary key (ord,ordid)) type=heap;
+The used table type doesn't support AUTO_INCREMENT columns
+create table t1 (ordid int(8), primary key (ordid));
+All parts of a PRIMARY KEY must be NOT NULL; If you need NULL in a key, use UNIQUE instead
+create table not_existing_database.test (a int);
+Got one of the listed errors
+create table `a/a` (a int);
+Incorrect table name 'a/a'
+create table `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa` (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa int);
+Incorrect table name 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
+create table a (`aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa` int);
+Identifier name 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' is too long
+create table 1ea10 (1a20 int,1e int);
+insert into 1ea10 values(1,1);
+select 1ea10.1a20,1e+ 1e+10 from 1ea10;
1a20 1e+ 1e+10
1 10000000001
+drop table 1ea10;
+create table t1 (t1.index int);
+drop table t1;
+drop database if exists test_$1;
+create database test_$1;
+create table test_$1.$test1 (a$1 int, $b int, c$ int);
+insert into test_$1.$test1 values (1,2,3);
+select a$1, $b, c$ from test_$1.$test1;
a$1 $b c$
1 2 3
+create table test_$1.test2$ (a int);
+drop table test_$1.test2$;
+drop database test_$1;
+create table t1 (a int auto_increment not null primary key, B CHAR(20));
+insert into t1 (b) values ("hello"),("my"),("world");
+create table t2 (key (b)) select * from t1;
+explain select * from t2 where b="world";
table type possible_keys key key_len ref rows Extra
t2 ref B B 21 const 1 where used
+select * from t2 where b="world";
a B
3 world
+drop table t1,t2;
+create table t1(x varchar(50) );
+create table t2 select x from t1 where 1=2;
+describe t1;
+Field Type Null Key Default Extra
+x varchar(50) YES NULL
+describe t2;
+Field Type Null Key Default Extra
+x char(50) YES NULL
+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
+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;
+Field Type Null Key Default Extra
+d date 0000-00-00
+t time 00:00:00
+dt datetime 0000-00-00 00:00:00
+drop table t1,t2;
+create table t1 (a int not null, b int, primary key(a), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b));
+show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) NOT NULL default '0',
@@ -49,3 +133,4 @@ t1 CREATE TABLE `t1` (
KEY `b_30` (`b`),
KEY `b_31` (`b`)
) TYPE=MyISAM
+drop table t1;
diff --git a/mysql-test/r/ctype_latin1_de.result b/mysql-test/r/ctype_latin1_de.result
new file mode 100644
index 00000000000..58ed0dfdbf3
--- /dev/null
+++ b/mysql-test/r/ctype_latin1_de.result
@@ -0,0 +1,207 @@
+drop table if exists t1;
+create table t1 (a char (20) not null, b int not null auto_increment, index (a,b),index(b));
+insert into t1 (a) values ('ä'),('ac'),('ae'),('ad'),('Äc'),('aeb');
+insert into t1 (a) values ('üc'),('uc'),('ue'),('ud'),('Ü'),('ueb'),('uf');
+insert into t1 (a) values ('ö'),('oc'),('Öa'),('oe'),('od'),('Öc'),('oeb');
+insert into t1 (a) values ('s'),('ss'),('ß'),('ßb'),('ssa'),('ssc'),('ßa');
+insert into t1 (a) values ('eä'),('uü'),('öo'),('ää'),('ääa'),('aeae');
+insert into t1 (a) values ('q'),('a'),('u'),('o'),('é'),('É');
+select a,b from t1 order by a,b;
+a b
+a 35
+ac 2
+ad 4
+ä 1
+ae 3
+ää 31
+aeae 33
+ääa 32
+aeb 6
+Äc 5
+é 38
+É 39
+eä 28
+o 37
+oc 15
+od 18
+ö 14
+oe 17
+Öa 16
+oeb 20
+Öc 19
+öo 30
+q 34
+s 21
+ss 22
+ß 23
+ssa 25
+ßa 27
+ßb 24
+ssc 26
+u 36
+uc 8
+ud 10
+ue 9
+Ü 11
+ueb 12
+üc 7
+uf 13
+uü 29
+select a,b from t1 order by upper(a),b;
+a b
+a 35
+ac 2
+ad 4
+ä 1
+ae 3
+ää 31
+aeae 33
+ääa 32
+aeb 6
+Äc 5
+é 38
+É 39
+eä 28
+o 37
+oc 15
+od 18
+ö 14
+oe 17
+Öa 16
+oeb 20
+Öc 19
+öo 30
+q 34
+s 21
+ss 22
+ß 23
+ssa 25
+ßa 27
+ßb 24
+ssc 26
+u 36
+uc 8
+ud 10
+ue 9
+Ü 11
+ueb 12
+üc 7
+uf 13
+uü 29
+select a from t1 order by a desc;
+a
+uü
+uf
+üc
+ueb
+ue
+ud
+uc
+u
+ssc
+ßb
+ßa
+ssa
+ss
+s
+q
+öo
+Öc
+oeb
+Öa
+oe
+od
+oc
+o
+eä
+Äc
+aeb
+ääa
+aeae
+ää
+ae
+ad
+ac
+a
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+select * from t1 where a like "ö%";
+a b
+ö 14
+Öa 16
+Öc 19
+öo 30
+select * from t1 where a like binary "%É%";
+a b
+É 39
+select * from t1 where a like "%Á%";
+a b
+a 35
+ac 2
+ad 4
+ae 3
+aeae 33
+ääa 32
+aeb 6
+Öa 16
+ssa 25
+ßa 27
+select * from t1 where a like "%U%";
+a b
+u 36
+uc 8
+ud 10
+ue 9
+ueb 12
+uf 13
+uü 29
+select * from t1 where a like "%ss%";
+a b
+ss 22
+ssa 25
+ssc 26
+drop table t1;
+select strcmp('ä','ae'),strcmp('ae','ä'),strcmp('aeq','äq'),strcmp('äq','aeq');
+strcmp('ä','ae') strcmp('ae','ä') strcmp('aeq','äq') strcmp('äq','aeq')
+0 0 0 0
+select strcmp('ss','ß'),strcmp('ß','ss'),strcmp('ßs','sss'),strcmp('ßq','ssq');
+strcmp('ss','ß') strcmp('ß','ss') strcmp('ßs','sss') strcmp('ßq','ssq')
+0 0 0 0
+select strcmp('ä','af'),strcmp('a','ä'),strcmp('ää','aeq'),strcmp('ää','aeaeq');
+strcmp('ä','af') strcmp('a','ä') strcmp('ää','aeq') strcmp('ää','aeaeq')
+-1 -1 -1 -1
+select strcmp('ss','ßa'),strcmp('ß','ssa'),strcmp('sßa','sssb'),strcmp('s','ß');
+strcmp('ss','ßa') strcmp('ß','ssa') strcmp('sßa','sssb') strcmp('s','ß')
+-1 -1 -1 -1
+select strcmp('ö','oö'),strcmp('Ü','uü'),strcmp('ö','oeb');
+strcmp('ö','oö') strcmp('Ü','uü') strcmp('ö','oeb')
+-1 -1 -1
+select strcmp('af','ä'),strcmp('ä','a'),strcmp('aeq','ää'),strcmp('aeaeq','ää');
+strcmp('af','ä') strcmp('ä','a') strcmp('aeq','ää') strcmp('aeaeq','ää')
+1 1 1 1
+select strcmp('ßa','ss'),strcmp('ssa','ß'),strcmp('sssb','sßa'),strcmp('ß','s');
+strcmp('ßa','ss') strcmp('ssa','ß') strcmp('sssb','sßa') strcmp('ß','s')
+1 1 1 1
+select strcmp('u','öa'),strcmp('u','ö');
+strcmp('u','öa') strcmp('u','ö')
+1 1
+create table t1 (a varchar(10), key(a));
+insert into t1 values ("a"),("abc"),("abcd"),("hello"),("test");
+select * from t1 where a like "abc%";
+a
+abc
+abcd
+select * from t1 where a like "test%";
+a
+test
+select * from t1 where a like "te_t";
+a
+test
+drop table t1;
diff --git a/mysql-test/r/delayed.result b/mysql-test/r/delayed.result
index d1914341a8d..44aef139ad2 100644
--- a/mysql-test/r/delayed.result
+++ b/mysql-test/r/delayed.result
@@ -1,10 +1,30 @@
+create table t1 (a char(10), tmsp timestamp);
+insert into t1 set a = 1;
+insert delayed into t1 set a = 2;
+insert into t1 set a = 3, tmsp=NULL;
+insert delayed into t1 set a = 4;
+insert delayed into t1 set a = 5, tmsp = 19711006010203;
+insert delayed into t1 (a, tmsp) values (6, 19711006010203);
+insert delayed into t1 (a, tmsp) values (7, NULL);
+insert into t1 set a = 8,tmsp=19711006010203;
+select * from t1 where tmsp=0;
a tmsp
+select * from t1 where tmsp=19711006010203;
a tmsp
5 19711006010203
6 19711006010203
8 19711006010203
+drop table t1;
+create table t1 (a int not null auto_increment primary key, b char(10));
+insert delayed into t1 values (1,"b");
+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");
+Column count doesn't match value count at row 1
+select * from t1;
a b
1 b
2 c
3 d
4 e
+drop table t1;
diff --git a/mysql-test/r/delete.result b/mysql-test/r/delete.result
new file mode 100644
index 00000000000..c2230722aa6
--- /dev/null
+++ b/mysql-test/r/delete.result
@@ -0,0 +1,26 @@
+drop table if exists t1;
+CREATE TABLE t1 (a tinyint(3), b tinyint(5));
+INSERT INTO t1 VALUES (1,1);
+INSERT LOW_PRIORITY INTO t1 VALUES (1,2);
+INSERT INTO t1 VALUES (1,3);
+DELETE from t1 where a=1 limit 1;
+DELETE LOW_PRIORITY from t1 where a=1;
+INSERT INTO t1 VALUES (1,1);
+DELETE from t1;
+LOCK TABLE t1 write;
+INSERT INTO t1 VALUES (1,2);
+DELETE from t1;
+UNLOCK TABLES;
+INSERT INTO t1 VALUES (1,2);
+SET AUTOCOMMIT=0;
+DELETE from t1;
+SET AUTOCOMMIT=1;
+drop table t1;
+create table t1 (a bigint not null, primary key (a,a,a,a,a,a,a,a,a,a));
+insert into t1 values (2),(4),(6),(8),(10),(12),(14),(16),(18),(20),(22),(24),(26),(23);
+delete from t1 where a=26;
+drop table t1;
+create table t1 (a bigint not null, primary key (a,a,a,a,a,a,a,a,a,a));
+insert into t1 values (2),(4),(6),(8),(10),(12),(14),(16),(18),(20),(22),(24),(26),(23),(27);
+delete from t1 where a=27;
+drop table t1;
diff --git a/mysql-test/r/dirty-close.result b/mysql-test/r/dirty-close.result
deleted file mode 100644
index f85b057eefa..00000000000
--- a/mysql-test/r/dirty-close.result
+++ /dev/null
@@ -1,4 +0,0 @@
-n
-1
-2
-3
diff --git a/mysql-test/r/dirty_close.result b/mysql-test/r/dirty_close.result
new file mode 100644
index 00000000000..c4fc19a35f8
--- /dev/null
+++ b/mysql-test/r/dirty_close.result
@@ -0,0 +1,9 @@
+drop table if exists t1;
+create table t1 (n int);
+insert into t1 values (1),(2),(3);
+select * from t1;
+n
+1
+2
+3
+drop table t1;
diff --git a/mysql-test/r/distinct.result b/mysql-test/r/distinct.result
index 8f8770e5602..e347a95b037 100644
--- a/mysql-test/r/distinct.result
+++ b/mysql-test/r/distinct.result
@@ -1,3 +1,21 @@
+drop table if exists t1,t2,t3;
+CREATE TABLE t1 (id int,facility char(20));
+CREATE TABLE t2 (facility char(20));
+INSERT INTO t1 VALUES (NULL,NULL);
+INSERT INTO t1 VALUES (-1,'');
+INSERT INTO t1 VALUES (0,'');
+INSERT INTO t1 VALUES (1,'/L');
+INSERT INTO t1 VALUES (2,'A01');
+INSERT INTO t1 VALUES (3,'ANC');
+INSERT INTO t1 VALUES (4,'F01');
+INSERT INTO t1 VALUES (5,'FBX');
+INSERT INTO t1 VALUES (6,'MT');
+INSERT INTO t1 VALUES (7,'P');
+INSERT INTO t1 VALUES (8,'RV');
+INSERT INTO t1 VALUES (9,'SRV');
+INSERT INTO t1 VALUES (10,'VMT');
+INSERT INTO t2 SELECT DISTINCT FACILITY FROM t1;
+select id from t1 group by id;
id
NULL
-1
@@ -12,6 +30,7 @@ NULL
8
9
10
+select * from t1 order by id;
id facility
NULL NULL
-1
@@ -26,6 +45,7 @@ NULL NULL
8 RV
9 SRV
10 VMT
+select id-5,facility from t1 order by "id-5";
id-5 facility
NULL NULL
-6
@@ -40,6 +60,7 @@ NULL NULL
3 RV
4 SRV
5 VMT
+select id,concat(facility) from t1 group by id ;
id concat(facility)
NULL NULL
-1
@@ -54,7 +75,9 @@ NULL NULL
8 RV
9 SRV
10 VMT
+select id+0 as a,max(id),concat(facility) as b from t1 group by a order by b desc,a;
a max(id) b
+NULL NULL NULL
10 10 VMT
9 9 SRV
8 8 RV
@@ -67,10 +90,11 @@ a max(id) b
1 1 /L
-1 -1
0 0
-NULL NULL NULL
+select id >= 0 and id <= 5 as grp,count(*) from t1 group by grp;
grp count(*)
0 7
1 6
+SELECT DISTINCT FACILITY FROM t1;
FACILITY
NULL
@@ -84,6 +108,7 @@ P
RV
SRV
VMT
+SELECT FACILITY FROM t2;
FACILITY
NULL
@@ -97,52 +122,157 @@ P
RV
SRV
VMT
+SELECT count(*) from t1,t2 where t1.facility=t2.facility;
count(*)
12
+select count(facility) from t1;
count(facility)
12
+select count(*) from t1;
count(*)
13
+select count(*) from t1 where facility IS NULL;
count(*)
1
+select count(*) from t1 where facility = NULL;
count(*)
0
+select count(*) from t1 where facility IS NOT NULL;
count(*)
12
+select count(*) from t1 where id IS NULL;
count(*)
1
+select count(*) from t1 where id IS NOT NULL;
count(*)
12
+drop table t1,t2;
+CREATE TABLE t1 (UserId int(11) DEFAULT '0' NOT NULL);
+INSERT INTO t1 VALUES (20);
+INSERT INTO t1 VALUES (27);
+SELECT UserId FROM t1 WHERE Userid=22;
UserId
+SELECT UserId FROM t1 WHERE UserId=22 group by Userid;
UserId
+SELECT DISTINCT UserId FROM t1 WHERE UserId=22 group by Userid;
UserId
+SELECT DISTINCT UserId FROM t1 WHERE UserId=22;
UserId
+drop table t1;
+CREATE TABLE t1 (a int(10) unsigned not null primary key,b int(10) unsigned);
+INSERT INTO t1 VALUES (1,1),(2,1);
+CREATE TABLE t2 (a int(10) unsigned not null, key (A));
+INSERT INTO t2 VALUES (1),(2);
+CREATE TABLE t3 (a int(10) unsigned, key(A), b text);
+INSERT INTO t3 VALUES (1,'1'),(2,'2');
+SELECT DISTINCT t3.b FROM t3,t2,t1 WHERE t3.a=t1.b AND t1.a=t2.a;
b
1
+INSERT INTO t2 values (1),(2),(3);
+INSERT INTO t3 VALUES (1,'1'),(2,'2'),(1,'1'),(2,'2');
+explain SELECT distinct t3.a FROM t3,t2,t1 WHERE t3.a=t1.b AND t1.a=t2.a;
table type possible_keys key key_len ref rows Extra
t3 index a a 5 NULL 6 Using index; Using temporary
t2 index a a 4 NULL 5 Using index; Distinct
t1 eq_ref PRIMARY PRIMARY 4 t2.a 1 where used; Distinct
+SELECT distinct t3.a FROM t3,t2,t1 WHERE t3.a=t1.b AND t1.a=t2.a;
a
1
+create temporary table t4 select * from t3;
+insert into t3 select * from t4;
+insert into t4 select * from t3;
+insert into t3 select * from t4;
+insert into t4 select * from t3;
+insert into t3 select * from t4;
+insert into t4 select * from t3;
+insert into t3 select * from t4;
+explain select distinct t1.a from t1,t3 where t1.a=t3.a;
table type possible_keys key key_len ref rows Extra
t1 index PRIMARY PRIMARY 4 NULL 2 Using index; Using temporary
t3 ref a a 5 t1.a 10 Using index; Distinct
+select distinct t1.a from t1,t3 where t1.a=t3.a;
a
1
2
+select distinct 1 from t1,t3 where t1.a=t3.a;
1
1
+drop table t1,t2,t3,t4;
+CREATE TABLE t1 (name varchar(255));
+INSERT INTO t1 VALUES ('aa'),('ab'),('ac'),('ad'),('ae');
+SELECT DISTINCT * FROM t1 LIMIT 2;
name
aa
ab
+SELECT DISTINCT name FROM t1 LIMIT 2;
name
aa
ab
+SELECT DISTINCT 1 FROM t1 LIMIT 2;
1
1
+drop table t1;
+CREATE TABLE t1 (
+ID int(11) NOT NULL auto_increment,
+NAME varchar(75) DEFAULT '' NOT NULL,
+LINK_ID int(11) DEFAULT '0' NOT NULL,
+PRIMARY KEY (ID),
+KEY NAME (NAME),
+KEY LINK_ID (LINK_ID)
+);
+INSERT INTO t1 (ID, NAME, LINK_ID) VALUES (1,'Mike',0),(2,'Jack',0),(3,'Bill',0);
+CREATE TABLE t2 (
+ID int(11) NOT NULL auto_increment,
+NAME varchar(150) DEFAULT '' NOT NULL,
+PRIMARY KEY (ID),
+KEY NAME (NAME)
+);
+SELECT DISTINCT
+t2.id AS key_link_id,
+t2.name AS link
+FROM t1
+LEFT JOIN t2 ON t1.link_id=t2.id
+GROUP BY t1.id
+ORDER BY link;
key_link_id link
NULL NULL
+drop table t1,t2;
+create table t1 (
+id int not null,
+name tinytext not null,
+unique (id)
+);
+create table t2 (
+id int not null,
+idx int not null,
+unique (id, idx)
+);
+create table t3 (
+id int not null,
+idx int not null,
+unique (id, idx)
+);
+insert into t1 values (1,'yes'), (2,'no');
+insert into t2 values (1,1);
+insert into t3 values (1,1);
+EXPLAIN
+SELECT DISTINCT
+t1.id
+from
+t1
+straight_join
+t2
+straight_join
+t3
+straight_join
+t1 as j_lj_t2 left join t2 as t2_lj
+on j_lj_t2.id=t2_lj.id
+straight_join
+t1 as j_lj_t3 left join t3 as t3_lj
+on j_lj_t3.id=t3_lj.id
+WHERE
+((t1.id=j_lj_t2.id AND t2_lj.id IS NULL) OR (t1.id=t2.id AND t2.idx=2))
+AND ((t1.id=j_lj_t3.id AND t3_lj.id IS NULL) OR (t1.id=t3.id AND t3.idx=2));
table type possible_keys key key_len ref rows Extra
t1 index id id 4 NULL 2 Using index; Using temporary
t2 index id id 8 NULL 1 Using index; Distinct
@@ -151,25 +281,71 @@ j_lj_t2 index id id 4 NULL 2 where used; Using index; Distinct
t2_lj index id id 8 NULL 1 where used; Using index; Distinct
j_lj_t3 index id id 4 NULL 2 where used; Using index; Distinct
t3_lj index id id 8 NULL 1 where used; Using index; Distinct
+SELECT DISTINCT
+t1.id
+from
+t1
+straight_join
+t2
+straight_join
+t3
+straight_join
+t1 as j_lj_t2 left join t2 as t2_lj
+on j_lj_t2.id=t2_lj.id
+straight_join
+t1 as j_lj_t3 left join t3 as t3_lj
+on j_lj_t3.id=t3_lj.id
+WHERE
+((t1.id=j_lj_t2.id AND t2_lj.id IS NULL) OR (t1.id=t2.id AND t2.idx=2))
+AND ((t1.id=j_lj_t3.id AND t3_lj.id IS NULL) OR (t1.id=t3.id AND t3.idx=2));
id
2
+drop table t1,t2,t3;
+drop table if exists t1;
+create table t1 (a int not null, b int not null, t time);
+insert into t1 values (1,1,"00:06:15"),(1,2,"00:06:15"),(1,2,"00:30:15"),(1,3,"00:06:15"),(1,3,"00:30:15");
+select a,sec_to_time(sum(time_to_sec(t))) from t1 group by a,b;
a sec_to_time(sum(time_to_sec(t)))
1 00:06:15
1 00:36:30
1 00:36:30
+select distinct a,sec_to_time(sum(time_to_sec(t))) from t1 group by a,b;
a sec_to_time(sum(time_to_sec(t)))
1 00:06:15
1 00:36:30
+create table t2 (a int not null primary key, b int);
+insert into t2 values (1,1),(2,2),(3,3);
+select t1.a,sec_to_time(sum(time_to_sec(t))) from t1 left join t2 on (t1.b=t2.a) group by t1.a,t2.b;
a sec_to_time(sum(time_to_sec(t)))
1 00:06:15
1 00:36:30
1 00:36:30
+select distinct t1.a,sec_to_time(sum(time_to_sec(t))) from t1 left join t2 on (t1.b=t2.a) group by t1.a,t2.b;
a sec_to_time(sum(time_to_sec(t)))
1 00:06:15
1 00:36:30
+drop table t1,t2;
+create table t1 (a int not null,b char(5), c text);
+insert into t1 (a) values (1),(2),(3),(4),(1),(2),(3),(4);
+select distinct a from t1 group by b,a having a > 2 order by a desc;
a
4
3
+select distinct a,c from t1 group by b,c,a having a > 2 order by a desc;
a c
4 NULL
3 NULL
+drop table t1;
+create table t1 (a char(1), key(a)) type=myisam;
+insert into t1 values('1'),('1');
+select * from t1 where a >= '1';
+a
+1
+1
+select distinct a from t1 order by a desc;
+a
+1
+select distinct a from t1 where a >= '1' order by a desc;
+a
+1
+drop table t1;
diff --git a/mysql-test/r/drop.result b/mysql-test/r/drop.result
index 741fc6bba85..178c3a8cb4f 100644
--- a/mysql-test/r/drop.result
+++ b/mysql-test/r/drop.result
@@ -1,11 +1,48 @@
+drop table if exists t1;
+drop table if exists t1;
+drop table t1;
+Unknown table 't1'
+create table t1(n int);
+insert into t1 values(1);
+create temporary table t1( n int);
+insert into t1 values(2);
+create table t1(n int);
+Table 't1' already exists
+drop table t1;
+select * from t1;
n
1
+drop database if exists mysqltest;
+create database mysqltest;
+drop database if exists mysqltest;
+create database mysqltest;
+create table mysqltest.mysqltest (n int);
+insert into mysqltest.mysqltest values (4);
+select * from mysqltest.mysqltest;
n
4
+drop database if exists mysqltest;
+create database mysqltest;
+drop database mysqltest;
+drop database if exists mysqltest;
+flush tables with read lock;
+create database mysqltest;
+Got one of the listed errors
+unlock tables;
+create database mysqltest;
+show databases;
Database
-foo
mysql
+mysqltest
test
+flush tables with read lock;
+drop database mysqltest;
+Got one of the listed errors
+unlock tables;
+drop database mysqltest;
+show databases;
Database
mysql
test
+drop database mysqltest;
+Can't drop database 'mysqltest'. Database doesn't exist
diff --git a/mysql-test/r/empty_table.result b/mysql-test/r/empty_table.result
index 284ed65ee3b..cea787f4abd 100644
--- a/mysql-test/r/empty_table.result
+++ b/mysql-test/r/empty_table.result
@@ -1,4 +1,10 @@
+drop table if exists t1;
+create table t1 (nr int(5) not null auto_increment,b blob,str char(10), primary key (nr));
+select count(*) from t1;
count(*)
0
+select * from t1;
nr b str
+select * from t1 limit 0;
nr b str
+drop table t1;
diff --git a/mysql-test/r/err000001.result b/mysql-test/r/err000001.result
new file mode 100644
index 00000000000..5afecc6d600
--- /dev/null
+++ b/mysql-test/r/err000001.result
@@ -0,0 +1,25 @@
+drop table if exists t1;
+insert into t1 values(1);
+Table 'test.t1' doesn't exist
+delete from t1;
+Table 'test.t1' doesn't exist
+update t1 set a=1;
+Table 'test.t1' doesn't exist
+create table t1 (a int);
+select count(test.t1.b) from t1;
+Unknown column 'test.t1.b' in 'field list'
+select count(not_existing_database.t1) from t1;
+Unknown table 'not_existing_database' in field list
+select count(not_existing_database.t1.a) from t1;
+Unknown table 'not_existing_database.t1' in field list
+select count(not_existing_database.t1.a) from not_existing_database.t1;
+Got one of the listed errors
+select 1 from t1 order by 2;
+Unknown column '2' in 'order clause'
+select 1 from t1 group by 2;
+Unknown column '2' in 'group statement'
+select 1 from t1 order by t1.b;
+Unknown column 't1.b' in 'order clause'
+select count(*),b from t1;
+Unknown column 'b' in 'field list'
+drop table t1;
diff --git a/mysql-test/r/explain.result b/mysql-test/r/explain.result
index 558feb10f84..5b4da25d535 100644
--- a/mysql-test/r/explain.result
+++ b/mysql-test/r/explain.result
@@ -1,15 +1,30 @@
+drop table if exists t1;
+create table t1 (id int not null, str char(10), unique(str));
+insert into t1 values (1, null),(2, null),(3, "foo"),(4, "bar");
+select * from t1 where str is null;
id str
1 NULL
2 NULL
+select * from t1 where str="foo";
id str
3 foo
+explain select * from t1 where str is null;
table type possible_keys key key_len ref rows Extra
t1 ref str str 11 const 1 where used
+explain select * from t1 where str="foo";
table type possible_keys key key_len ref rows Extra
t1 const str str 11 const 1
+explain select * from t1 ignore key (str) where str="foo";
table type possible_keys key key_len ref rows Extra
-t1 ALL str NULL NULL NULL 4 where used
+t1 ALL NULL NULL NULL NULL 4 where used
+explain select * from t1 use key (str,str) where str="foo";
table type possible_keys key key_len ref rows Extra
t1 const str str 11 const 1
+explain select * from t1 use key (str,str,foo) where str="foo";
+Key column 'foo' doesn't exist in table
+explain select * from t1 ignore key (str,str,foo) where str="foo";
+Key column 'foo' doesn't exist in table
+drop table t1;
+explain select 1;
Comment
No tables used
diff --git a/mysql-test/r/flush.result b/mysql-test/r/flush.result
index fca84de710c..a7f73a6840b 100644
--- a/mysql-test/r/flush.result
+++ b/mysql-test/r/flush.result
@@ -1,6 +1,35 @@
+drop table if exists t1;
+create temporary table t1(n int not null primary key);
+drop table if exists t2;
+create table t2(n int);
+insert into t2 values(3);
+select * from t1;
n
3
+flush tables with read lock;
+drop table t2;
+Table 't2' was locked with a READ lock and can't be updated
+ drop table t2;
+unlock tables;
+drop database if exists mysqltest;
+create database mysqltest;
+create table mysqltest.t1(n int);
+insert into mysqltest.t1 values (23);
+flush tables with read lock;
+ drop database mysqltest;
+select * from mysqltest.t1;
n
23
+unlock tables;
+create table t1 (n int);
+flush tables with read lock;
+insert into t1 values (345);
+select * from t1;
n
345
+drop table t1;
+flush query cache;
+reset query cache;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
diff --git a/mysql-test/r/foreign_key.result b/mysql-test/r/foreign_key.result
new file mode 100644
index 00000000000..ece53db2e9a
--- /dev/null
+++ b/mysql-test/r/foreign_key.result
@@ -0,0 +1,15 @@
+drop table if exists t1;
+create table t1 (
+a int not null references t2,
+b int not null references t2 (c),
+primary key (a,b),
+foreign key (a) references t3 match full,
+foreign key (a) references t3 match partial,
+foreign key (a,b) references t3 (c,d) on delete no action
+on update no action,
+foreign key (a,b) references t3 (c,d) on update cascade,
+foreign key (a,b) references t3 (c,d) on delete set default,
+foreign key (a,b) references t3 (c,d) on update set null);
+create index a on t1 (a);
+create unique index b on t1 (a,b);
+drop table t1;
diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result
index c39210107ae..dd5e59e4081 100644
--- a/mysql-test/r/fulltext.result
+++ b/mysql-test/r/fulltext.result
@@ -1,22 +1,122 @@
+drop table if exists t1,t2,t3;
+CREATE TABLE t1 (a VARCHAR(200), b TEXT, FULLTEXT (a,b));
+INSERT INTO t1 VALUES('MySQL has now support', 'for full-text search'),
+('Full-text indexes', 'are called collections'),
+('Only MyISAM tables','support collections'),
+('Function MATCH ... AGAINST()','is used to do a search'),
+('Full-text search in MySQL', 'implements vector space model');
+select * from t1 where MATCH(a,b) AGAINST ("collections");
a b
Only MyISAM tables support collections
Full-text indexes are called collections
+select * from t1 where MATCH(a,b) AGAINST ("indexes");
a b
Full-text indexes are called collections
+select * from t1 where MATCH(a,b) AGAINST ("indexes collections");
a b
Full-text indexes are called collections
Only MyISAM tables support collections
+select * from t1 where MATCH(a,b) AGAINST ("collections") UNION ALL select * from t1 where MATCH(a,b) AGAINST ("indexes");
+a b
+Only MyISAM tables support collections
+Full-text indexes are called collections
+Full-text indexes are called collections
+select * from t1 where MATCH(a,b) AGAINST("support -collections" IN BOOLEAN MODE);
+a b
+MySQL has now support for full-text search
+select * from t1 where MATCH(a,b) AGAINST("support collections" IN BOOLEAN MODE);
+a b
+MySQL has now support for full-text search
+Full-text indexes are called collections
+Only MyISAM tables support collections
+select * from t1 where MATCH(a,b) AGAINST("support +collections" IN BOOLEAN MODE);
+a b
+Full-text indexes are called collections
+Only MyISAM tables support collections
+select * from t1 where MATCH(a,b) AGAINST("sear*" IN BOOLEAN MODE);
+a b
+MySQL has now support for full-text search
+Function MATCH ... AGAINST() is used to do a search
+Full-text search in MySQL implements vector space model
+select * from t1 where MATCH(a,b) AGAINST("+support +collections" IN BOOLEAN MODE);
+a b
+Only MyISAM tables support collections
+select * from t1 where MATCH(a,b) AGAINST("+search" IN BOOLEAN MODE);
+a b
+MySQL has now support for full-text search
+Function MATCH ... AGAINST() is used to do a search
+Full-text search in MySQL implements vector space model
+select * from t1 where MATCH(a,b) AGAINST("+search +(support vector)" IN BOOLEAN MODE);
+a b
+MySQL has now support for full-text search
+Full-text search in MySQL implements vector space model
+select * from t1 where MATCH(a,b) AGAINST("+search -(support vector)" IN BOOLEAN MODE);
+a b
+Function MATCH ... AGAINST() is used to do a search
+select *, MATCH(a,b) AGAINST("support collections" IN BOOLEAN MODE) as x from t1;
+a b x
+MySQL has now support for full-text search 1
+Full-text indexes are called collections 1
+Only MyISAM tables support collections 2
+Function MATCH ... AGAINST() is used to do a search 0
+Full-text search in MySQL implements vector space model 0
+select *, MATCH(a,b) AGAINST("collections support" IN BOOLEAN MODE) as x from t1;
+a b x
+MySQL has now support for full-text search 1
+Full-text indexes are called collections 1
+Only MyISAM tables support collections 2
+Function MATCH ... AGAINST() is used to do a search 0
+Full-text search in MySQL implements vector space model 0
+select * from t1 where MATCH a AGAINST ("search" IN BOOLEAN MODE);
+a b
+Full-text search in MySQL implements vector space model
+select * from t1 where MATCH b AGAINST ("sear*" IN BOOLEAN MODE);
+a b
+MySQL has now support for full-text search
+Function MATCH ... AGAINST() is used to do a search
+delete from t1 where a like "MySQL%";
+update t1 set a='some test foobar' where MATCH a,b AGAINST ('model');
+delete from t1 where MATCH(a,b) AGAINST ("indexes");
+select * from t1;
a b
Only MyISAM tables support collections
Function MATCH ... AGAINST() is used to do a search
some test foobar implements vector space model
+drop table t1;
+CREATE TABLE t1 (
+id int(11),
+ticket int(11),
+KEY ti (id),
+KEY tit (ticket)
+);
+INSERT INTO t1 VALUES (2,3),(1,2);
+CREATE TABLE t2 (
+ticket int(11),
+inhalt text,
+KEY tig (ticket),
+fulltext index tix (inhalt)
+);
+INSERT INTO t2 VALUES (1,'foo'),(2,'bar'),(3,'foobar');
+select t1.id FROM t2 as ttxt,t1,t1 as ticket2
+WHERE ticket2.id = ttxt.ticket AND t1.id = ticket2.ticket and
+match(ttxt.inhalt) against ('foobar');
id
+select t1.id FROM t2 as ttxt,t1 INNER JOIN t1 as ticket2 ON
+ticket2.id = ttxt.ticket
+WHERE t1.id = ticket2.ticket and match(ttxt.inhalt) against ('foobar');
id
+INSERT INTO t1 VALUES (3,3);
+select t1.id FROM t2 as ttxt,t1
+INNER JOIN t1 as ticket2 ON ticket2.id = ttxt.ticket
+WHERE t1.id = ticket2.ticket and
+match(ttxt.inhalt) against ('foobar');
id
3
-Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Comment
-t2 1 tig 1 ticket A NULL NULL NULL
-t2 1 tix 1 inhalt A NULL 1 NULL FULLTEXT
+show keys from t2;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t2 1 tig 1 ticket A NULL NULL NULL YES BTREE
+t2 1 tix 1 inhalt A NULL 1 NULL YES FULLTEXT
+show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
`ticket` int(11) default NULL,
@@ -24,8 +124,47 @@ t2 CREATE TABLE `t2` (
KEY `tig` (`ticket`),
FULLTEXT KEY `tix` (`inhalt`)
) TYPE=MyISAM
+select * from t2 where MATCH inhalt AGAINST (NULL);
ticket inhalt
+select * from t2 where MATCH inhalt AGAINST ('foobar');
ticket inhalt
3 foobar
+select * from t2 having MATCH inhalt AGAINST ('foobar');
ticket inhalt
3 foobar
+CREATE TABLE t3 (
+ticket int(11),
+inhalt text,
+KEY tig (ticket),
+fulltext index tix (inhalt)
+);
+select * from t2 where MATCH inhalt AGAINST (t2.inhalt);
+Wrong arguments to AGAINST
+select * from t2 where MATCH ticket AGAINST ('foobar');
+Can't find FULLTEXT index matching the column list
+select * from t2,t3 where MATCH (t2.inhalt,t3.inhalt) AGAINST ('foobar');
+Wrong arguments to MATCH
+drop table t1,t2,t3;
+CREATE TABLE t1 (
+id int(11) auto_increment,
+title varchar(100) default '',
+PRIMARY KEY (id),
+KEY ind5 (title),
+FULLTEXT KEY FT1 (title)
+) TYPE=MyISAM;
+insert into t1 (title) values ('this is a test');
+update t1 set title='this is A test' where id=1;
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+update t1 set title='this test once revealed a bug' where id=1;
+select * from t1;
+id title
+1 this test once revealed a bug
+update t1 set title=NULL where id=1;
+drop table t1;
+CREATE TABLE t1 (a int(11), b text, FULLTEXT KEY (b)) TYPE=MyISAM;
+insert into t1 values (1,"I wonder why the fulltext index doesnt work?");
+SELECT * from t1 where MATCH (b) AGAINST ('apples');
+a b
+drop table t1;
diff --git a/mysql-test/r/fulltext_cache.result b/mysql-test/r/fulltext_cache.result
index a580437b0ce..c489bdefeb8 100644
--- a/mysql-test/r/fulltext_cache.result
+++ b/mysql-test/r/fulltext_cache.result
@@ -1,5 +1,30 @@
+drop table if exists t1, t2;
+CREATE TABLE t1 (
+id int(10) unsigned NOT NULL auto_increment,
+q varchar(255) default NULL,
+PRIMARY KEY (id)
+);
+INSERT INTO t1 VALUES (1,'aaaaaaaaa dsaass de');
+INSERT INTO t1 VALUES (2,'ssde df s fsda sad er');
+CREATE TABLE t2 (
+id int(10) unsigned NOT NULL auto_increment,
+id2 int(10) unsigned default NULL,
+item varchar(255) default NULL,
+PRIMARY KEY (id),
+FULLTEXT KEY item(item)
+);
+INSERT INTO t2 VALUES (1,1,'sushi');
+INSERT INTO t2 VALUES (2,1,'Bolo de Chocolate');
+INSERT INTO t2 VALUES (3,1,'Feijoada');
+INSERT INTO t2 VALUES (4,1,'Mousse de Chocolate');
+INSERT INTO t2 VALUES (5,2,'um copo de Vodka');
+INSERT INTO t2 VALUES (6,2,'um chocolate Snickers');
+INSERT INTO t2 VALUES (7,1,'Bife');
+INSERT INTO t2 VALUES (8,1,'Pizza de Salmao');
+SELECT t1.q, t2.item, t2.id, MATCH t2.item AGAINST ('sushi')
+as x FROM t1, t2 WHERE (t2.id2 = t1.id) ORDER BY x DESC,t2.id;
q item id x
-aaaaaaaaa dsaass de sushi 1 1.92378665219675
+aaaaaaaaa dsaass de sushi 1 1.92378664016724
aaaaaaaaa dsaass de Bolo de Chocolate 2 0
aaaaaaaaa dsaass de Feijoada 3 0
aaaaaaaaa dsaass de Mousse de Chocolate 4 0
@@ -7,8 +32,10 @@ ssde df s fsda sad er um copo de Vodka 5 0
ssde df s fsda sad er um chocolate Snickers 6 0
aaaaaaaaa dsaass de Bife 7 0
aaaaaaaaa dsaass de Pizza de Salmao 8 0
+SELECT t1.q, t2.item, t2.id, MATCH t2.item AGAINST ('sushi' IN BOOLEAN MODE)
+as x FROM t1, t2 WHERE (t2.id2 = t1.id) ORDER BY x DESC,t2.id;
q item id x
-aaaaaaaaa dsaass de sushi 1 1.92378665219675
+aaaaaaaaa dsaass de sushi 1 1
aaaaaaaaa dsaass de Bolo de Chocolate 2 0
aaaaaaaaa dsaass de Feijoada 3 0
aaaaaaaaa dsaass de Mousse de Chocolate 4 0
@@ -16,3 +43,26 @@ ssde df s fsda sad er um copo de Vodka 5 0
ssde df s fsda sad er um chocolate Snickers 6 0
aaaaaaaaa dsaass de Bife 7 0
aaaaaaaaa dsaass de Pizza de Salmao 8 0
+SELECT t1.q, t2.item, t2.id, MATCH t2.item AGAINST ('sushi')
+as x FROM t2, t1 WHERE (t2.id2 = t1.id) ORDER BY x DESC,t2.id;
+q item id x
+aaaaaaaaa dsaass de sushi 1 1.92378664016724
+aaaaaaaaa dsaass de Bolo de Chocolate 2 0
+aaaaaaaaa dsaass de Feijoada 3 0
+aaaaaaaaa dsaass de Mousse de Chocolate 4 0
+ssde df s fsda sad er um copo de Vodka 5 0
+ssde df s fsda sad er um chocolate Snickers 6 0
+aaaaaaaaa dsaass de Bife 7 0
+aaaaaaaaa dsaass de Pizza de Salmao 8 0
+SELECT t1.q, t2.item, t2.id, MATCH t2.item AGAINST ('sushi' IN BOOLEAN MODE)
+as x FROM t2, t1 WHERE (t2.id2 = t1.id) ORDER BY x DESC,t2.id;
+q item id x
+aaaaaaaaa dsaass de sushi 1 1
+aaaaaaaaa dsaass de Bolo de Chocolate 2 0
+aaaaaaaaa dsaass de Feijoada 3 0
+aaaaaaaaa dsaass de Mousse de Chocolate 4 0
+ssde df s fsda sad er um copo de Vodka 5 0
+ssde df s fsda sad er um chocolate Snickers 6 0
+aaaaaaaaa dsaass de Bife 7 0
+aaaaaaaaa dsaass de Pizza de Salmao 8 0
+drop table t1, t2;
diff --git a/mysql-test/r/fulltext_distinct.result b/mysql-test/r/fulltext_distinct.result
new file mode 100644
index 00000000000..abb4929d0ec
--- /dev/null
+++ b/mysql-test/r/fulltext_distinct.result
@@ -0,0 +1,43 @@
+DROP TABLE IF EXISTS t1, t2;
+CREATE TABLE t1 (
+id mediumint unsigned NOT NULL auto_increment,
+tag char(6) NOT NULL default '',
+value text NOT NULL default '',
+PRIMARY KEY (id),
+KEY kt(tag),
+KEY kv(value(15)),
+FULLTEXT KEY kvf(value)
+) TYPE=MyISAM;
+CREATE TABLE t2 (
+id_t2 mediumint unsigned NOT NULL default '0',
+id_t1 mediumint unsigned NOT NULL default '0',
+field_number tinyint unsigned NOT NULL default '0',
+PRIMARY KEY (id_t2,id_t1,field_number),
+KEY id_t1(id_t1)
+) TYPE=MyISAM;
+INSERT INTO t1 (tag,value) VALUES ('foo123','bar111');
+INSERT INTO t1 (tag,value) VALUES ('foo123','bar222');
+INSERT INTO t1 (tag,value) VALUES ('bar345','baz333 ar');
+INSERT INTO t2 VALUES (2231626,64280,0);
+INSERT INTO t2 VALUES (2231626,64281,0);
+INSERT INTO t2 VALUES (12346, 3, 1);
+SELECT * FROM t1;
+id tag value
+1 foo123 bar111
+2 foo123 bar222
+3 bar345 baz333 ar
+SELECT * FROM t2;
+id_t2 id_t1 field_number
+12346 3 1
+2231626 64280 0
+2231626 64281 0
+SELECT DISTINCT t2.id_t2 FROM t2, t1
+WHERE MATCH (t1.value) AGAINST ('baz333') AND t1.id = t2.id_t1;
+id_t2
+12346
+SELECT DISTINCT t2.id_t2 FROM t2, t1
+WHERE MATCH (t1.value) AGAINST ('baz333' IN BOOLEAN MODE)
+AND t1.id = t2.id_t1;
+id_t2
+12346
+DROP TABLE t1, t2;
diff --git a/mysql-test/r/fulltext_left_join.result b/mysql-test/r/fulltext_left_join.result
index 04244e309e5..9f2ba6a5947 100644
--- a/mysql-test/r/fulltext_left_join.result
+++ b/mysql-test/r/fulltext_left_join.result
@@ -1,5 +1,32 @@
+CREATE TABLE t1 (
+id VARCHAR(255) NOT NULL PRIMARY KEY,
+sujet VARCHAR(255),
+motsclefs TEXT,
+texte MEDIUMTEXT,
+FULLTEXT(sujet, motsclefs, texte)
+);
+INSERT INTO t1 VALUES('123','toto','essai','test');
+INSERT INTO t1 VALUES('456','droit','penal','lawyer');
+INSERT INTO t1 VALUES('789','aaaaa','bbbbb','cccccc');
+CREATE TABLE t2 (
+id VARCHAR(255) NOT NULL,
+author VARCHAR(255) NOT NULL
+);
+INSERT INTO t2 VALUES('123', 'moi');
+INSERT INTO t2 VALUES('123', 'lui');
+INSERT INTO t2 VALUES('456', 'lui');
+select match(t1.texte,t1.sujet,t1.motsclefs) against('droit')
+from t1 left join t2 on t2.id=t1.id;
match(t1.texte,t1.sujet,t1.motsclefs) against('droit')
0
0
-0.67003110026735
+0.67003107070923
0
+select match(t1.texte,t1.sujet,t1.motsclefs) against('droit' IN BOOLEAN MODE)
+from t1 left join t2 on t2.id=t1.id;
+match(t1.texte,t1.sujet,t1.motsclefs) against('droit' IN BOOLEAN MODE)
+0
+0
+1
+0
+drop table t1, t2;
diff --git a/mysql-test/r/fulltext_multi.result b/mysql-test/r/fulltext_multi.result
index d78d88172b5..72b7102fd3f 100644
--- a/mysql-test/r/fulltext_multi.result
+++ b/mysql-test/r/fulltext_multi.result
@@ -1,12 +1,30 @@
+use test;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+a int(11) NOT NULL auto_increment,
+b text,
+c varchar(254) default NULL,
+PRIMARY KEY (a),
+FULLTEXT KEY bb(b),
+FULLTEXT KEY cc(c),
+FULLTEXT KEY a(b,c)
+);
+INSERT INTO t1 VALUES (1,'lala lolo lili','oooo aaaa pppp');
+INSERT INTO t1 VALUES (2,'asdf fdsa','lkjh fghj');
+INSERT INTO t1 VALUES (3,'qpwoei','zmxnvb');
+SELECT a, MATCH b AGAINST ('lala lkjh') FROM t1;
a MATCH b AGAINST ('lala lkjh')
-1 0.67003110026735
+1 0.67003107070923
2 0
3 0
+SELECT a, MATCH c AGAINST ('lala lkjh') FROM t1;
a MATCH c AGAINST ('lala lkjh')
1 0
-2 0.67756324121582
+2 0.67756325006485
3 0
+SELECT a, MATCH b,c AGAINST ('lala lkjh') FROM t1;
a MATCH b,c AGAINST ('lala lkjh')
-1 0.64840710366884
-2 0.66266459031789
+1 0.64840710163116
+2 0.66266459226608
3 0
+drop table t1;
diff --git a/mysql-test/r/fulltext_order_by.result b/mysql-test/r/fulltext_order_by.result
index 3ac5285151b..8d88b8d6ebf 100644
--- a/mysql-test/r/fulltext_order_by.result
+++ b/mysql-test/r/fulltext_order_by.result
@@ -1,19 +1,66 @@
+use test;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+a INT AUTO_INCREMENT PRIMARY KEY,
+message CHAR(20),
+FULLTEXT(message)
+) comment = 'original testcase by sroussey@network54.com';
+INSERT INTO t1 (message) VALUES ("Testing"),("table"),("testbug"),
+("steve"),("is"),("cool"),("steve is cool");
+SELECT a, MATCH (message) AGAINST ('steve') FROM t1 WHERE MATCH (message) AGAINST ('steve');
a MATCH (message) AGAINST ('steve')
-4 0.90587321329654
-7 0.89568988462614
+4 0.90587323904037
+7 0.89568990468979
+SELECT a, MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) FROM t1 WHERE MATCH (message) AGAINST ('steve');
+a MATCH (message) AGAINST ('steve' IN BOOLEAN MODE)
+4 1
+7 1
+SELECT a, MATCH (message) AGAINST ('steve') FROM t1 WHERE MATCH (message) AGAINST ('steve' IN BOOLEAN MODE);
a MATCH (message) AGAINST ('steve')
-4 0.90587321329654
-7 0.89568988462614
+4 0.90587323904037
+7 0.89568990468979
+SELECT a, MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) FROM t1 WHERE MATCH (message) AGAINST ('steve' IN BOOLEAN MODE);
+a MATCH (message) AGAINST ('steve' IN BOOLEAN MODE)
+4 1
+7 1
+SELECT a, MATCH (message) AGAINST ('steve') FROM t1 WHERE MATCH (message) AGAINST ('steve') ORDER BY a;
a MATCH (message) AGAINST ('steve')
-7 0.89568988462614
-4 0.90587321329654
+4 0.90587323904037
+7 0.89568990468979
+SELECT a, MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) FROM t1 WHERE MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) ORDER BY a;
+a MATCH (message) AGAINST ('steve' IN BOOLEAN MODE)
+4 1
+7 1
+SELECT a, MATCH (message) AGAINST ('steve') FROM t1 WHERE a in (2,7,4) and MATCH (message) AGAINST ('steve') ORDER BY a DESC;
a MATCH (message) AGAINST ('steve')
-7 0.89568988462614
+7 0.89568990468979
+4 0.90587323904037
+SELECT a, MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) FROM t1 WHERE a in (2,7,4) and MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) ORDER BY a DESC;
+a MATCH (message) AGAINST ('steve' IN BOOLEAN MODE)
+7 1
+4 1
+SELECT a, MATCH (message) AGAINST ('steve') FROM t1 WHERE a=7 and MATCH (message) AGAINST ('steve') ORDER BY 1;
+a MATCH (message) AGAINST ('steve')
+7 0.89568990468979
+SELECT a, MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) FROM t1 WHERE a=7 and MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) ORDER BY 1;
+a MATCH (message) AGAINST ('steve' IN BOOLEAN MODE)
+7 1
+SELECT a, MATCH (message) AGAINST ('steve') as rel FROM t1 ORDER BY rel;
+a rel
+1 0
+2 0
+3 0
+5 0
+6 0
+7 0.89568990468979
+4 0.90587323904037
+SELECT a, MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) as rel FROM t1 ORDER BY rel;
a rel
1 0
2 0
3 0
5 0
6 0
-7 0.89568988462614
-4 0.90587321329654
+4 1
+7 1
+drop table t1;
diff --git a/mysql-test/r/fulltext_update.result b/mysql-test/r/fulltext_update.result
index 77ee76ad30d..5d3f95b318c 100644
--- a/mysql-test/r/fulltext_update.result
+++ b/mysql-test/r/fulltext_update.result
@@ -1,2 +1,22 @@
+drop table if exists test;
+CREATE TABLE test (
+gnr INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+url VARCHAR(80) DEFAULT '' NOT NULL,
+shortdesc VARCHAR(200) DEFAULT '' NOT NULL,
+longdesc text DEFAULT '' NOT NULL,
+description VARCHAR(80) DEFAULT '' NOT NULL,
+name VARCHAR(80) DEFAULT '' NOT NULL,
+FULLTEXT(url,description,shortdesc,longdesc),
+PRIMARY KEY(gnr)
+);
+insert into test (url,shortdesc,longdesc,description,name) VALUES
+("http:/test.at", "kurz", "lang","desc", "name");
+insert into test (url,shortdesc,longdesc,description,name) VALUES
+("http:/test.at", "kurz", "","desc", "name");
+update test set url='test', description='ddd', name='nam' where gnr=2;
+update test set url='test', shortdesc='ggg', longdesc='mmm',
+description='ddd', name='nam' where gnr=2;
+check table test;
Table Op Msg_type Msg_text
test.test check status OK
+drop table test;
diff --git a/mysql-test/r/fulltext_var.result b/mysql-test/r/fulltext_var.result
new file mode 100644
index 00000000000..eb71e87538d
--- /dev/null
+++ b/mysql-test/r/fulltext_var.result
@@ -0,0 +1,6 @@
+show variables like "ft\_%";
+Variable_name Value
+ft_min_word_len 4
+ft_max_word_len 254
+ft_max_word_len_for_sort 20
+ft_boolean_syntax + -><()~*:""&|
diff --git a/mysql-test/r/func_crypt.result b/mysql-test/r/func_crypt.result
index 021989add8d..cf464ec21b2 100644
--- a/mysql-test/r/func_crypt.result
+++ b/mysql-test/r/func_crypt.result
@@ -1,2 +1,6 @@
+select length(encrypt('foo', 'ff')) <> 0;
length(encrypt('foo', 'ff')) <> 0
1
+select password('test'),length(encrypt('test')),encrypt('test','aa');
+password('test') length(encrypt('test')) encrypt('test','aa')
+378b243e220ca493 13 aaqPiZY5xR5l.
diff --git a/mysql-test/r/func_date_add.result b/mysql-test/r/func_date_add.result
index 3bc0fb1aff3..acdf2c5d7be 100644
--- a/mysql-test/r/func_date_add.result
+++ b/mysql-test/r/func_date_add.result
@@ -1,12 +1,47 @@
+drop table if exists t1;
+CREATE TABLE t1 (
+visitor_id int(10) unsigned DEFAULT '0' NOT NULL,
+group_id int(10) unsigned DEFAULT '0' NOT NULL,
+hits int(10) unsigned DEFAULT '0' NOT NULL,
+sessions int(10) unsigned DEFAULT '0' NOT NULL,
+ts timestamp(14),
+PRIMARY KEY (visitor_id,group_id)
+)/*! type=MyISAM */;
+INSERT INTO t1 VALUES (465931136,7,2,2,20000318160952);
+INSERT INTO t1 VALUES (173865424,2,2,2,20000318233615);
+INSERT INTO t1 VALUES (173865424,8,2,2,20000318233615);
+INSERT INTO t1 VALUES (173865424,39,2,2,20000318233615);
+INSERT INTO t1 VALUES (173865424,7,2,2,20000318233615);
+INSERT INTO t1 VALUES (173865424,3,2,2,20000318233615);
+INSERT INTO t1 VALUES (173865424,6,2,2,20000318233615);
+INSERT INTO t1 VALUES (173865424,60,2,2,20000318233615);
+INSERT INTO t1 VALUES (173865424,1502,2,2,20000318233615);
+INSERT INTO t1 VALUES (48985536,2,2,2,20000319013932);
+INSERT INTO t1 VALUES (48985536,8,2,2,20000319013932);
+INSERT INTO t1 VALUES (48985536,39,2,2,20000319013932);
+INSERT INTO t1 VALUES (48985536,7,2,2,20000319013932);
+INSERT INTO t1 VALUES (465931136,3,2,2,20000318160951);
+INSERT INTO t1 VALUES (465931136,119,1,1,20000318160953);
+INSERT INTO t1 VALUES (465931136,2,1,1,20000318160950);
+INSERT INTO t1 VALUES (465931136,8,1,1,20000318160950);
+INSERT INTO t1 VALUES (465931136,39,1,1,20000318160950);
+INSERT INTO t1 VALUES (1092858576,14,1,1,20000319013445);
+INSERT INTO t1 VALUES (357917728,3,2,2,20000319145026);
+INSERT INTO t1 VALUES (357917728,7,2,2,20000319145027);
+select visitor_id,max(ts) as mts from t1 group by visitor_id
+having mts < DATE_SUB(NOW(),INTERVAL 3 MONTH);
visitor_id mts
48985536 20000319013932
173865424 20000318233615
357917728 20000319145027
465931136 20000318160953
1092858576 20000319013445
+select visitor_id,max(ts) as mts from t1 group by visitor_id
+having DATE_ADD(mts,INTERVAL 3 MONTH) < NOW();
visitor_id mts
48985536 20000319013932
173865424 20000318233615
357917728 20000319145027
465931136 20000318160953
1092858576 20000319013445
+drop table t1;
diff --git a/mysql-test/r/func_encrypt.result b/mysql-test/r/func_encrypt.result
new file mode 100644
index 00000000000..39c734999b2
--- /dev/null
+++ b/mysql-test/r/func_encrypt.result
@@ -0,0 +1,136 @@
+drop table if exists t1;
+create table t1 (x blob);
+insert into t1 values (des_encrypt('The quick red fox jumped over the lazy brown dog','The quick red fox jumped over the lazy brown dog'));
+insert into t1 values (des_encrypt('a','The quick red fox jumped over the lazy brown dog'));
+insert into t1 values (des_encrypt('The quick red fox jumped over the lazy brown dog','a'));
+insert into t1 values (des_encrypt('ab','The quick red fox jumped over the lazy brown dog'));
+insert into t1 values (des_encrypt('The quick red fox jumped over the lazy brown dog','ab'));
+insert into t1 values (des_encrypt('abc','The quick red fox jumped over the lazy brown dog'));
+insert into t1 values (des_encrypt('The quick red fox jumped over the lazy brown dog','abc'));
+insert into t1 values (des_encrypt('abcd','The quick red fox jumped over the lazy brown dog'));
+insert into t1 values (des_encrypt('The quick red fox jumped over the lazy brown dog','abcd'));
+insert into t1 values (des_encrypt('abcde','The quick red fox jumped over the lazy brown dog'));
+insert into t1 values (des_encrypt('The quick red fox jumped over the lazy brown dog','abcde'));
+insert into t1 values (des_encrypt('abcdef','The quick red fox jumped over the lazy brown dog'));
+insert into t1 values (des_encrypt('The quick red fox jumped over the lazy brown dog','abcdef'));
+insert into t1 values (des_encrypt('abcdefg','The quick red fox jumped over the lazy brown dog'));
+insert into t1 values (des_encrypt('The quick red fox jumped over the lazy brown dog','abcdefg'));
+insert into t1 values (des_encrypt('abcdefgh','The quick red fox jumped over the lazy brown dog'));
+insert into t1 values (des_encrypt('The quick red fox jumped over the lazy brown dog','abcdefgh'));
+insert into t1 values (des_encrypt('abcdefghi','The quick red fox jumped over the lazy brown dog'));
+insert into t1 values (des_encrypt('The quick red fox jumped over the lazy brown dog','abcdefghi'));
+insert into t1 values (des_encrypt('abcdefghij','The quick red fox jumped over the lazy brown dog'));
+insert into t1 values (des_encrypt('The quick red fox jumped over the lazy brown dog','abcdefghij'));
+insert into t1 values (des_encrypt('abcdefghijk','The quick red fox jumped over the lazy brown dog'));
+insert into t1 values (des_encrypt('The quick red fox jumped over the lazy brown dog','abcdefghijk'));
+insert into t1 values (des_encrypt('The quick red fox jumped over the lazy brown dog','sabakala'));
+insert into t1 values (des_encrypt('quick red fox jumped over the lazy brown dog','sabakala'));
+insert into t1 values (des_encrypt('red fox jumped over the lazy brown dog','sabakala'));
+insert into t1 values (des_encrypt('fox jumped over the lazy brown dog','sabakala'));
+insert into t1 values (des_encrypt('jumped over the lazy brown dog','sabakala'));
+insert into t1 values (des_encrypt('over the lazy brown dog','sabakala'));
+insert into t1 values (des_encrypt('the lazy brown dog','sabakala'));
+insert into t1 values (des_encrypt('lazy brown dog','sabakala'));
+insert into t1 values (des_encrypt('brown dog','sabakala'));
+insert into t1 values (des_encrypt('dog','sabakala'));
+insert into t1 values (des_encrypt('dog!','sabakala'));
+insert into t1 values (des_encrypt('dog!!','sabakala'));
+insert into t1 values (des_encrypt('dog!!!','sabakala'));
+insert into t1 values (des_encrypt('dog!!!!','sabakala'));
+insert into t1 values (des_encrypt('dog!!!!!','sabakala'));
+insert into t1 values (des_encrypt('jumped over the lazy brown dog','sabakala'));
+insert into t1 values (des_encrypt('jumped over the lazy brown dog','sabakala'));
+select hex(x), hex(des_decrypt(x,'sabakala')) from t1;
+hex(x) hex(des_decrypt(x,'sabakala'))
+FFA185A4656D113445E31D7A5B31BB57671A4CA9E21E63FE5D9C801E0CC7AA6190C13E269C2AE8D8060D3FB3FEA94FEC7FB006B9DCAC3E3E41 NULL
+FFC620C3B84E926A54 NULL
+FFA4F77D4220A16C980AF7CB576F8DC0A864F357825C16F329F24F66EBA775765B7C1538B90970740F853B556AEBD35AC31B962EA9B12B5AD4 NULL
+FFACFF5921BB876A90 NULL
+FFA6F18760E7CC5A4C325244B8486F692AAA11D229AF9ED4E4C9D56D7C0278C0DDA58F73E15E2B5F6C1DDD19B22B8071C454C930585449AAEB NULL
+FF3736DFEDC4B765F4 NULL
+FF598681EA5F03CD6D6AEA2B118DF4885DD78BECDFB012BBB05386E436DC403D3CB9DE3BE8D5D3BB7FD90A1F9F9A3E055BB3B4FD3F6A869473 NULL
+FF15B8B5952D630CAE NULL
+FF11EE3A400685226B76D5EC567681FA90247CE3C9DBE43341311C22F74562B1199957D80E300737791F6345BBC61AE03F28F52E5A6DCC78B2 NULL
+FF0A832AE10DC85483 NULL
+FF6F5C0BF4C5F899B4E7C091D9B1F1E92A7623B651B150CA3E7F420B4DD316D2C1BF76FCF9F9A046C000A9E21C106591E8C1930201B1750269 NULL
+FFA08D5FB849A9FC90 NULL
+FFF7331312FE153A39B1EC0D65BC1D3A0B6FCD49DA8C95D6161F53B11D297BAE142BCA6B9492DAE9A02AF455F16CA2C1CF4E1AD17297E947E2 NULL
+FFDEE60A938478E059 NULL
+FF95A729E73D5D87416A53055029E8CAA95B4F7B49F3D2D821A95D1FCE70F4B7A3226077176723F3DCC0A44D3B2EE9EFBC4D31AA87C948916C NULL
+FF1C78557F542A1FDC91943761B2EED14F NULL
+FF1E35B0775EEE512544A75BDAF58EA1655F5C899D3C5191A47263E2D11C3E688F662AB79F66D3B1DF9C75BD869EB8E04FDAE85719CB573A43 NULL
+FF1C78557F542A1FDCDC4182B5314185E5 NULL
+FF783123DCB36F98A51C39A560C92E129F1DDEEAB170825406A61260FBFBBFB0F2E48DB3282588A975C9C71E0EACA71A2B642A8C9C2E921A9F NULL
+FF1C78557F542A1FDCAC4B1B6B47206306 NULL
+FF6D9B450837017D06CA1F1C9A0E700D03DEF06A4F954527A961CA805F70320E9F3F0007636B80768A253A5F7ADABC18B78F1A2FA560CC0B21 NULL
+FF1C78557F542A1FDCE9038BD99DD43F2E NULL
+FF23FD03BA7548DD0957EBA7A8FBF7A18589762F3913E9A935BDA72F6F28202DC64572E0D633A54EA55BFD2C749E408C8632CCE36A7AE00619 NULL
+FFD8DD3C4ABCB02FCDFE1383ECC0F61E7D02CD3BA72BBAEA26384D14835796501B3DC9A2F7EC2FC1633BDA6D56464536FE12010049C53A1991 54686520717569636B2072656420666F78206A756D706564206F76657220746865206C617A792062726F776E20646F67
+FFACC5C5479575CBCA518B05778139B1BFC10F07299C98D04F580BC2F816828722D65A89C1831BD29DA626D319813BD374 717569636B2072656420666F78206A756D706564206F76657220746865206C617A792062726F776E20646F67
+FF128D5517241DEEC631ABD2A47FA66E57930001417F18204328B0B2CB13F7AD2F50B8336EFAE7DE21 72656420666F78206A756D706564206F76657220746865206C617A792062726F776E20646F67
+FF7CF971283B4DC2D050B3DB22684737B74B5B1CF12CF2FAC5A5995A298505F56D82BBFB9FC3E70059 666F78206A756D706564206F76657220746865206C617A792062726F776E20646F67
+FF8333F3DD21E4488F967E03DD12394813A49F72848BB49473D3CB1C8A1AACF220 6A756D706564206F76657220746865206C617A792062726F776E20646F67
+FFE8CB7FD80E6262C5FEB042A2DCC73B699CEEDCA6DC4458A0 6F76657220746865206C617A792062726F776E20646F67
+FFA29334D7CDB1B403DF3EB992067DD524C7D568E8D98EBFE5 746865206C617A792062726F776E20646F67
+FF4F0C5858FE2358D400E38831D5577C85 6C617A792062726F776E20646F67
+FFB370CD6BAFD1CB95974D21DCCA2DD9D7 62726F776E20646F67
+FF8F7777B28C7A459A 646F67
+FF75213A4D7D01D715 646F6721
+FF2DCAF574B173FB4D 646F672121
+FFFA775787BE776B15 646F67212121
+FF3FC2E42D7C840905 646F6721212121
+FF9723312D26D9E6DA01D01A784A64DB9D 646F672121212121
+FF8333F3DD21E4488F967E03DD12394813A49F72848BB49473D3CB1C8A1AACF220 6A756D706564206F76657220746865206C617A792062726F776E20646F67
+FF8333F3DD21E4488F967E03DD12394813A49F72848BB49473D3CB1C8A1AACF220 6A756D706564206F76657220746865206C617A792062726F776E20646F67
+select des_decrypt(x,'sabakala') as s from t1 having s like '%dog%';
+s
+The quick red fox jumped over the lazy brown dog
+quick red fox jumped over the lazy brown dog
+red fox jumped over the lazy brown dog
+fox jumped over the lazy brown dog
+jumped over the lazy brown dog
+over the lazy brown dog
+the lazy brown dog
+lazy brown dog
+brown dog
+dog
+dog!
+dog!!
+dog!!!
+dog!!!!
+dog!!!!!
+jumped over the lazy brown dog
+jumped over the lazy brown dog
+drop table t1;
+select hex(des_encrypt("hello")),des_decrypt(des_encrypt("hello"));
+hex(des_encrypt("hello")) des_decrypt(des_encrypt("hello"))
+85D6DC8859F9759BBB hello
+select des_decrypt(des_encrypt("hello",4));
+des_decrypt(des_encrypt("hello",4))
+hello
+select des_decrypt(des_encrypt("hello",'test'),'test');
+des_decrypt(des_encrypt("hello",'test'),'test')
+hello
+select hex(des_encrypt("hello")),hex(des_encrypt("hello",5)),hex(des_encrypt("hello",'default_password'));
+hex(des_encrypt("hello")) hex(des_encrypt("hello",5)) hex(des_encrypt("hello",'default_password'))
+85D6DC8859F9759BBB 85D6DC8859F9759BBB FFD6DC8859F9759BBB
+select des_decrypt(des_encrypt("hello"),'default_password');
+des_decrypt(des_encrypt("hello"),'default_password')
+hello
+select des_decrypt(des_encrypt("hello",4),'password4');
+des_decrypt(des_encrypt("hello",4),'password4')
+hello
+SET @a=des_decrypt(des_encrypt("hello"));
+flush des_key_file;
+select @a = des_decrypt(des_encrypt("hello"));
+@a = des_decrypt(des_encrypt("hello"))
+1
+select hex("hello");
+hex("hello")
+68656C6C6F
+select hex(des_decrypt(des_encrypt("hello",4),'password2'));
+hex(des_decrypt(des_encrypt("hello",4),'password2'))
+NULL
+select hex(des_decrypt(des_encrypt("hello","hidden")));
+hex(des_decrypt(des_encrypt("hello","hidden")))
+NULL
diff --git a/mysql-test/r/func_equal.result b/mysql-test/r/func_equal.result
index 6e2933641aa..32a911eedf8 100644
--- a/mysql-test/r/func_equal.result
+++ b/mysql-test/r/func_equal.result
@@ -1,15 +1,29 @@
+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 1<=>0,0<=>NULL,NULL<=>0;
1<=>0 0<=>NULL NULL<=>0
0 0 0
+select 1.0<=>0.0,0.0<=>NULL,NULL<=>0.0;
1.0<=>0.0 0.0<=>NULL NULL<=>0.0
0 0 0
+select "A"<=>"B","A"<=>NULL,NULL<=>"A";
"A"<=>"B" "A"<=>NULL NULL<=>"A"
0 0 0
+drop table if exists t1,t2;
+create table t1 (id int, value int);
+create table t2 (id int, value int);
+insert into t1 values (1,null);
+insert into t2 values (1,null);
+select t1.*, t2.*, t1.value<=>t2.value from t1, t2 where t1.id=t2.id and t1.id=1;
id value id value t1.value<=>t2.value
1 NULL 1 NULL 1
+select * from t1 where id <=>id;
id value
1 NULL
+select * from t1 where value <=> value;
id value
1 NULL
+select * from t1 where id <=> value or value<=>id;
id value
+drop table t1,t2;
diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result
index ea9a06123ae..2d24b8ffd4e 100644
--- a/mysql-test/r/func_group.result
+++ b/mysql-test/r/func_group.result
@@ -1,3 +1,11 @@
+create table t1 (grp int, a bigint unsigned, c char(10) not null);
+insert into t1 values (1,1,"a");
+insert into t1 values (2,2,"b");
+insert into t1 values (2,3,"c");
+insert into t1 values (3,4,"E");
+insert into t1 values (3,5,"C");
+insert into t1 values (3,6,"D");
+select a,c,sum(a) from t1 group by a;
a c sum(a)
1 a 1
2 b 2
@@ -5,82 +13,140 @@ a c sum(a)
4 E 4
5 C 5
6 D 6
+select a,c,sum(a) from t1 where a > 10 group by a;
a c sum(a)
+select sum(a) from t1 where a > 10;
sum(a)
NULL
+select a from t1 order by rand(10);
a
+2
+6
1
3
-6
5
-2
4
+select distinct a from t1 order by rand(10);
a
+2
+6
1
3
-6
5
-2
4
+select count(distinct a),count(distinct grp) from t1;
count(distinct a) count(distinct grp)
6 3
+insert into t1 values (null,null,'');
+select count(distinct a),count(distinct grp) from t1;
count(distinct a) count(distinct grp)
6 3
+select sum(a),count(a),avg(a),std(a),bit_or(a),bit_and(a),min(a),max(a),min(c),max(c) from t1;
sum(a) count(a) avg(a) std(a) bit_or(a) bit_and(a) min(a) max(a) min(c) max(c)
21 6 3.5000 1.7078 7 0 1 6 E
+select grp, sum(a),count(a),avg(a),std(a),bit_or(a),bit_and(a),min(a),max(a),min(c),max(c) from t1 group by grp;
grp sum(a) count(a) avg(a) std(a) bit_or(a) bit_and(a) min(a) max(a) min(c) max(c)
NULL 0 0 NULL NULL 0 0 NULL NULL
1 1 1 1.0000 0.0000 1 1 1 1 a a
2 5 2 2.5000 0.5000 3 2 2 3 b c
3 15 3 5.0000 0.8165 7 4 4 6 C E
+select grp, sum(a)+count(a)+avg(a)+std(a)+bit_or(a)+bit_and(a)+min(a)+max(a)+min(c)+max(c) as sum from t1 group by grp;
grp sum
NULL NULL
1 7
2 20
3 44.816496580928
+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 into t2 select grp, a, c from t1 limit 2,1;
+select * from t2;
grp a c
NULL NULL
1 2 a
2 5 c
3 9 E
2 3 c
+drop table t1,t2;
+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);
+CREATE TABLE t2 (id int(11),name char(20));
+INSERT INTO t2 VALUES (1,'Set One'),(2,'Set Two');
+select id, avg(value1), std(value1) from t1 group by id;
id avg(value1) std(value1)
1 1.000000 0.816497
2 11.000000 0.816497
+select name, avg(value1), std(value1) from t1, t2 where t1.id = t2.id group by t1.id;
name avg(value1) std(value1)
Set One 1.000000 0.816497
Set Two 11.000000 0.816497
+drop table t1,t2;
+create table t1 (id int not null);
+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;
id avg(rating)
1 3.0000
2 NULL
3 2.0000
+drop table t1,t2;
+create table t1 (a smallint(6) primary key, c char(10), b text);
+INSERT INTO t1 VALUES (1,'1','1');
+INSERT INTO t1 VALUES (2,'2','2');
+INSERT INTO t1 VALUES (4,'4','4');
+select count(*) from t1;
count(*)
3
+select count(*) from t1 where a = 1;
count(*)
1
+select count(*) from t1 where a = 100;
count(*)
0
+select count(*) from t1 where a >= 10;
count(*)
0
+select count(a) from t1 where a = 1;
count(a)
1
+select count(a) from t1 where a = 100;
count(a)
0
+select count(a) from t1 where a >= 10;
count(a)
0
+select count(b) from t1 where b >= 2;
count(b)
2
+select count(b) from t1 where b >= 10;
count(b)
0
+select count(c) from t1 where c = 10;
count(c)
0
+drop table t1;
+CREATE TABLE t1 (d DATETIME, i INT);
+INSERT INTO t1 VALUES (NOW(), 1);
+SELECT COUNT(i), i, COUNT(i)*i FROM t1 GROUP BY i;
COUNT(i) i COUNT(i)*i
1 1 1
+SELECT COUNT(i), (i+0), COUNT(i)*(i+0) FROM t1 GROUP BY i;
COUNT(i) (i+0) COUNT(i)*(i+0)
1 1 1
+DROP TABLE t1;
+create table t1 (
+num float(5,2),
+user char(20)
+);
+insert into t1 values (10.3,'nem'),(20.53,'monty'),(30.23,'sinisa');
+insert into t1 values (30.13,'nem'),(20.98,'monty'),(10.45,'sinisa');
+insert into t1 values (5.2,'nem'),(8.64,'monty'),(11.12,'sinisa');
+select sum(num) from t1;
sum(num)
147.58
+select sum(num) from t1 group by user;
sum(num)
50.15
45.63
51.80
+drop table t1;
diff --git a/mysql-test/r/func_in.result b/mysql-test/r/func_in.result
index f201d371876..8c991dee8d8 100644
--- a/mysql-test/r/func_in.result
+++ b/mysql-test/r/func_in.result
@@ -1,14 +1,27 @@
+CREATE TABLE t1 (field char(1));
+INSERT INTO t1 VALUES ('A'),(NULL);
+SELECT * from t1 WHERE field IN (NULL);
field
+SELECT * from t1 WHERE field NOT IN (NULL);
field
A
+SELECT * from t1 where field = field;
field
A
+SELECT * from t1 where field <=> field;
field
A
NULL
+DELETE FROM t1 WHERE field NOT IN (NULL);
+SELECT * FROM t1;
field
NULL
+drop table t1;
+create table t1 (id int(10) primary key);
+insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9);
+select * from t1 where id in (2,5,9);
id
2
5
9
+drop table t1;
diff --git a/mysql-test/r/func_like.result b/mysql-test/r/func_like.result
index 78bede19762..796674b5fa4 100644
--- a/mysql-test/r/func_like.result
+++ b/mysql-test/r/func_like.result
@@ -1,7 +1,18 @@
+drop table if exists t1;
+create table t1 (a varchar(10), key(a));
+insert into t1 values ("a"),("abc"),("abcd"),("hello"),("test");
+select * from t1 where a like "abc%";
a
abc
abcd
+select * from t1 where a like "ABC%";
+a
+abc
+abcd
+select * from t1 where a like "test%";
a
test
+select * from t1 where a like "te_t";
a
test
+drop table t1;
diff --git a/mysql-test/r/func_math.result b/mysql-test/r/func_math.result
index cee67a3e25c..fce98a58682 100644
--- a/mysql-test/r/func_math.result
+++ b/mysql-test/r/func_math.result
@@ -1,22 +1,33 @@
+select floor(5.5),floor(-5.5);
floor(5.5) floor(-5.5)
5 -6
+select ceiling(5.5),ceiling(-5.5);
ceiling(5.5) ceiling(-5.5)
6 -5
+select truncate(52.64,1),truncate(52.64,2),truncate(52.64,-1),truncate(52.64,-2);
truncate(52.64,1) truncate(52.64,2) truncate(52.64,-1) truncate(52.64,-2)
52.6 52.64 50 0
+select round(5.5),round(-5.5);
round(5.5) round(-5.5)
6 -6
+select round(5.64,1),round(5.64,2),round(5.64,-1),round(5.64,-2);
round(5.64,1) round(5.64,2) round(5.64,-1) round(5.64,-2)
5.6 5.64 10 0
+select abs(-10), sign(-5), sign(5), sign(0);
abs(-10) sign(-5) sign(5) sign(0)
10 -1 1 0
+select log(exp(10)),exp(log(sqrt(10))*2);
log(exp(10)) exp(log(sqrt(10))*2)
10.000000 10.000000
+select pow(10,log10(10)),power(2,4);
pow(10,log10(10)) power(2,4)
10.000000 16.000000
+select rand(999999),rand();
rand(999999) rand()
-0.18435012473199 0.76373626176616
+0.014231365187309 0.8078568166195
+select pi(),sin(pi()/2),cos(pi()/2),abs(tan(pi())),cot(1),asin(1),acos(0),atan(1);
PI() sin(pi()/2) cos(pi()/2) abs(tan(pi())) cot(1) asin(1) acos(0) atan(1)
3.141593 1.000000 0.000000 0.000000 0.64209262 1.570796 1.570796 0.785398
+select degrees(pi()),radians(360);
degrees(pi()) radians(360)
180 6.2831853071796
diff --git a/mysql-test/r/func_misc.result b/mysql-test/r/func_misc.result
index 5448127548b..575f5e5429a 100644
--- a/mysql-test/r/func_misc.result
+++ b/mysql-test/r/func_misc.result
@@ -1,8 +1,12 @@
+select format(1.5555,0),format(123.5555,1),format(1234.5555,2),format(12345.5555,3),format(123456.5555,4),format(1234567.5555,5),format("12345.2399",2);
format(1.5555,0) format(123.5555,1) format(1234.5555,2) format(12345.5555,3) format(123456.5555,4) format(1234567.5555,5) format("12345.2399",2)
2 123.6 1,234.56 12,345.556 123,456.5555 1,234,567.55550 12,345.24
+select inet_ntoa(inet_aton("255.255.255.255.255.255.255.255"));
inet_ntoa(inet_aton("255.255.255.255.255.255.255.255"))
255.255.255.255.255.255.255.255
+select inet_aton("255.255.255.255.255"),inet_aton("255.255.1.255"),inet_aton("0.1.255");
inet_aton("255.255.255.255.255") inet_aton("255.255.1.255") inet_aton("0.1.255")
1099511627775 4294902271 511
+select inet_ntoa(1099511627775),inet_ntoa(4294902271),inet_ntoa(511);
inet_ntoa(1099511627775) inet_ntoa(4294902271) inet_ntoa(511)
255.255.255.255.255 255.255.1.255 0.0.1.255
diff --git a/mysql-test/r/func_op.result b/mysql-test/r/func_op.result
index b14f575c998..9f49b5809df 100644
--- a/mysql-test/r/func_op.result
+++ b/mysql-test/r/func_op.result
@@ -1,6 +1,9 @@
+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
+select 1 | (1+1),5 & 3,bit_count(7) ;
1 | (1+1) 5 & 3 bit_count(7)
3 1 3
+select 1 << 32,1 << 63, 1 << 64, 4 >> 2, 4 >> 63, 1<< 63 >> 60;
1 << 32 1 << 63 1 << 64 4 >> 2 4 >> 63 1<< 63 >> 60
-4294967296 -9223372036854775808 0 1 0 8
+4294967296 9223372036854775808 0 1 0 8
diff --git a/mysql-test/r/func_regexp.result b/mysql-test/r/func_regexp.result
index 5927dba0974..8d22994ef2b 100644
--- a/mysql-test/r/func_regexp.result
+++ b/mysql-test/r/func_regexp.result
@@ -1,3 +1,20 @@
+drop table if exists t1;
+create table t1 (s1 char(64),s2 char(64));
+insert into t1 values('aaa','aaa');
+insert into t1 values('aaa|qqq','qqq');
+insert into t1 values('gheis','^[^a-dXYZ]+$');
+insert into t1 values('aab','^aa?b');
+insert into t1 values('Baaan','^Ba*n');
+insert into t1 values('aaa','qqq|aaa');
+insert into t1 values('qqq','qqq|aaa');
+insert into t1 values('bbb','qqq|aaa');
+insert into t1 values('bbb','qqq');
+insert into t1 values('aaa','aba');
+insert into t1 values(null,'abc');
+insert into t1 values('def',null);
+insert into t1 values(null,null);
+insert into t1 values('ghi','ghi[');
+select HIGH_PRIORITY s1 regexp s2 from t1;
s1 regexp s2
1
1
@@ -13,13 +30,25 @@ NULL
NULL
NULL
NULL
+drop table t1;
+create table t1 (xxx char(128));
+insert into t1 (xxx) values('this is a test of some long text to see what happens');
+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
+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
+select * from t1 where xxx regexp('is a test of some long text to s');
xxx
this is a test of some long text to see what happens
+select * from t1 where xxx regexp('is a test of some long text to se');
xxx
this is a test of some long text to see what happens
+drop table t1;
+create table t1 (xxx char(128));
+insert into t1 (xxx) values('this is some text: to test - out.reg exp (22/45)');
+select * from t1 where xxx REGEXP '^this is some text: to test - out\\.reg exp [[(][0-9]+[/\\][0-9]+[])][ ]*$';
xxx
this is some text: to test - out.reg exp (22/45)
+drop table t1;
diff --git a/mysql-test/r/func_set.result b/mysql-test/r/func_set.result
index b82fffc3dbd..5305c16c5d9 100644
--- a/mysql-test/r/func_set.result
+++ b/mysql-test/r/func_set.result
@@ -1,18 +1,27 @@
+select interval(55,10,20,30,40,50,60,70,80,90,100),interval(3,1,1+1,1+1+1+1),field("IBM","NCA","ICL","SUN","IBM","DIGITAL"),field("A","B","C"),elt(2,"ONE","TWO","THREE"),interval(0,1,2,3,4),elt(1,1,2,3)|0,elt(1,1.1,1.2,1.3)+0;
interval(55,10,20,30,40,50,60,70,80,90,100) interval(3,1,1+1,1+1+1+1) field("IBM","NCA","ICL","SUN","IBM","DIGITAL") field("A","B","C") elt(2,"ONE","TWO","THREE") interval(0,1,2,3,4) elt(1,1,2,3)|0 elt(1,1.1,1.2,1.3)+0
5 2 4 0 TWO 0 1 1.1
+select find_in_set("b","a,b,c"),find_in_set("c","a,b,c"),find_in_set("dd","a,bbb,dd"),find_in_set("bbb","a,bbb,dd");
find_in_set("b","a,b,c") find_in_set("c","a,b,c") find_in_set("dd","a,bbb,dd") find_in_set("bbb","a,bbb,dd")
2 3 3 2
+select find_in_set("d","a,b,c"),find_in_set("dd","a,bbb,d"),find_in_set("bb","a,bbb,dd");
find_in_set("d","a,b,c") find_in_set("dd","a,bbb,d") find_in_set("bb","a,bbb,dd")
0 0 0
+select make_set(0,'a','b','c'),make_set(-1,'a','b','c'),make_set(1,'a','b','c'),make_set(2,'a','b','c'),make_set(1+2,concat('a','b'),'c');
make_set(0,'a','b','c') make_set(-1,'a','b','c') make_set(1,'a','b','c') make_set(2,'a','b','c') make_set(1+2,concat('a','b'),'c')
a,b,c a b ab,c
+select make_set(NULL,'a','b','c'),make_set(1|4,'a',NULL,'c'),make_set(1+2,'a',NULL,'c');
make_set(NULL,'a','b','c') make_set(1|4,'a',NULL,'c') make_set(1+2,'a',NULL,'c')
NULL a,c a
+select export_set(9,"Y","N","-",5),export_set(9,"Y","N"),export_set(9,"Y","N","");
export_set(9,"Y","N","-",5) export_set(9,"Y","N") export_set(9,"Y","N","")
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,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 YNNYNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
+select elt(2,1),field(NULL,"a","b","c");
elt(2,1) field(NULL,"a","b","c")
NULL 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
+select find_in_set("abc","abc"),find_in_set("ab","abc"),find_in_set("abcd","abc");
find_in_set("abc","abc") find_in_set("ab","abc") find_in_set("abcd","abc")
1 0 0
diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result
index ec421e9f31b..a58f3c57169 100644
--- a/mysql-test/r/func_str.result
+++ b/mysql-test/r/func_str.result
@@ -1,112 +1,186 @@
+drop table if exists t1;
+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
hello 'hello' ""hello"" 'h'e'l'l'o' hel"lo hel'lo
+select 'hello' 'monty';
hello
hellomonty
+select length('\n\t\r\b\0\_\%\\');
length('\n\t\r\b\0\_\%\\')
10
+select bit_length('\n\t\r\b\0\_\%\\');
+bit_length('\n\t\r\b\0\_\%\\')
+80
+select concat('monty',' was here ','again'),length('hello'),char(ascii('h'));
concat('monty',' was here ','again') length('hello') char(ascii('h'))
monty was here again 5 h
+select locate('he','hello'),locate('he','hello',2),locate('lo','hello',2) ;
locate('he','hello') locate('he','hello',2) locate('lo','hello',2)
1 0 4
-instr('hello','he')
-1
-position('ll' in 'hello') position('a' in 'hello')
+select instr('hello','HE'), instr('hello',binary 'HE'), instr(binary 'hello','HE');
+instr('hello','HE') instr('hello',binary 'HE') instr(binary 'hello','HE')
+1 0 0
+select position(binary 'll' in 'hello'),position('a' in binary 'hello');
+position(binary 'll' in 'hello') position('a' in binary 'hello')
3 0
+select left('hello',2),right('hello',2),substring('hello',2,2),mid('hello',1,5) ;
left('hello',2) right('hello',2) substring('hello',2,2) mid('hello',1,5)
he lo el hello
+select concat('',left(right(concat('what ',concat('is ','happening')),9),4),'',substring('monty',5,1)) ;
concat('',left(right(concat('what ',concat('is ','happening')),9),4),'',substring('monty',5,1))
happy
+select substring_index('www.tcx.se','.',-2),substring_index('www.tcx.se','.',1);
substring_index('www.tcx.se','.',-2) substring_index('www.tcx.se','.',1)
tcx.se www
+select substring_index('www.tcx.se','tcx',1),substring_index('www.tcx.se','tcx',-1);
substring_index('www.tcx.se','tcx',1) substring_index('www.tcx.se','tcx',-1)
www. .se
+select substring_index('.tcx.se','.',-2),substring_index('.tcx.se','.tcx',-1);
substring_index('.tcx.se','.',-2) substring_index('.tcx.se','.tcx',-1)
tcx.se .se
+select 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(' m '),':',trim(BOTH FROM ' y '),':',trim('*' FROM '*s*'),':');
concat(':',trim(' m '),':',trim(BOTH FROM ' y '),':',trim('*' FROM '*s*'),':')
:m:y:s:
+select concat(':',trim(BOTH 'ab' FROM 'ababmyabab'),':',trim(BOTH '*' FROM '***sql'),':');
concat(':',trim(BOTH 'ab' FROM 'ababmyabab'),':',trim(BOTH '*' FROM '***sql'),':')
:my:sql:
+select concat(':',trim(LEADING '.*' FROM '.*my'),':',trim(TRAILING '.*' FROM 'sql.*.*'),':');
concat(':',trim(LEADING '.*' FROM '.*my'),':',trim(TRAILING '.*' FROM 'sql.*.*'),':')
:my:sql:
+select TRIM("foo" FROM "foo"), TRIM("foo" FROM "foook"), TRIM("foo" FROM "okfoo");
TRIM("foo" FROM "foo") TRIM("foo" FROM "foook") TRIM("foo" FROM "okfoo")
ok ok
+select concat_ws(', ','monty','was here','again');
concat_ws(', ','monty','was here','again')
monty, was here, again
+select concat_ws(NULL,'a'),concat_ws(',',NULL,'');
concat_ws(NULL,'a') concat_ws(',',NULL,'')
NULL
+select concat_ws(',','',NULL,'a');
concat_ws(',','',NULL,'a')
a
+SELECT CONCAT('"',CONCAT_WS('";"',repeat('a',60),repeat('b',60),repeat('c',60),repeat('d',100)), '"');
CONCAT('"',CONCAT_WS('";"',repeat('a',60),repeat('b',60),repeat('c',60),repeat('d',100)), '"')
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc";"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
+select insert('txs',2,1,'hi'),insert('is ',4,0,'a'),insert('txxxxt',2,4,'es');
insert('txs',2,1,'hi') insert('is ',4,0,'a') insert('txxxxt',2,4,'es')
this is a test
+select replace('aaaa','a','b'),replace('aaaa','aa','b'),replace('aaaa','a','bb'),replace('aaaa','','b'),replace('bbbb','a','c');
replace('aaaa','a','b') replace('aaaa','aa','b') replace('aaaa','a','bb') replace('aaaa','','b') replace('bbbb','a','c')
bbbb bb bbbbbbbb aaaa bbbb
+select replace(concat(lcase(concat('THIS',' ','IS',' ','A',' ')),ucase('false'),' ','test'),'FALSE','REAL') ;
replace(concat(lcase(concat('THIS',' ','IS',' ','A',' ')),ucase('false'),' ','test'),'FALSE','REAL')
this is a REAL test
+select soundex(''),soundex('he'),soundex('hello all folks');
soundex('') soundex('he') soundex('hello all folks')
H000 H4142
-password('test') length(encrypt('test')) encrypt('test','aa')
-378b243e220ca493 13 aaqPiZY5xR5l.
+select md5('hello');
md5('hello')
5d41402abc4b2a76b9719d911017c592
+select repeat('monty',5),concat('*',space(5),'*');
repeat('monty',5) concat('*',space(5),'*')
montymontymontymontymonty * *
+select reverse('abc'),reverse('abcd');
reverse('abc') reverse('abcd')
cba dcba
+select rpad('a',4,'1'),rpad('a',4,'12'),rpad('abcd',3,'12');
rpad('a',4,'1') rpad('a',4,'12') rpad('abcd',3,'12')
a111 a121 abc
+select lpad('a',4,'1'),lpad('a',4,'12'),lpad('abcd',3,'12');
lpad('a',4,'1') lpad('a',4,'12') lpad('abcd',3,'12')
111a 121a abc
+select rpad(741653838,17,'0'),lpad(741653838,17,'0');
rpad(741653838,17,'0') lpad(741653838,17,'0')
74165383800000000 00000000741653838
+select rpad('abcd',7,'ab'),lpad('abcd',7,'ab');
rpad('abcd',7,'ab') lpad('abcd',7,'ab')
abcdaba abaabcd
+select rpad('abcd',1,'ab'),lpad('abcd',1,'ab');
rpad('abcd',1,'ab') lpad('abcd',1,'ab')
a a
+select LEAST(NULL,'HARRY','HARRIOT',NULL,'HAROLD'),GREATEST(NULL,'HARRY','HARRIOT',NULL,'HAROLD');
LEAST(NULL,'HARRY','HARRIOT',NULL,'HAROLD') GREATEST(NULL,'HARRY','HARRIOT',NULL,'HAROLD')
HAROLD HARRY
+select least(1,2,3) | greatest(16,32,8), least(5,4)*1,greatest(-1.0,1.0)*1,least(3,2,1)*1.0,greatest(1,1.1,1.0),least("10",9),greatest("A","B","0");
least(1,2,3) | greatest(16,32,8) least(5,4)*1 greatest(-1.0,1.0)*1 least(3,2,1)*1.0 greatest(1,1.1,1.0) least("10",9) greatest("A","B","0")
33 4 1.0 1.0 1.1 9 B
+select decode(encode(repeat("a",100000),"monty"),"monty")=repeat("a",100000);
decode(encode(repeat("a",100000),"monty"),"monty")=repeat("a",100000)
1
+select decode(encode("abcdef","monty"),"monty")="abcdef";
decode(encode("abcdef","monty"),"monty")="abcdef"
1
+select reverse("");
reverse("")
+select insert("aa",100,1,"b"),insert("aa",1,3,"b"),left("aa",-1),substring("a",1,2);
insert("aa",100,1,"b") insert("aa",1,3,"b") left("aa",-1) substring("a",1,2)
aa b a
+select elt(2,1),field(NULL,"a","b","c"),reverse("");
elt(2,1) field(NULL,"a","b","c") reverse("")
NULL 0
+select locate("a","b",2),locate("","a",1);
locate("a","b",2) locate("","a",1)
0 1
+select ltrim("a"),rtrim("a"),trim(BOTH "" from "a"),trim(BOTH " " from "a");
ltrim("a") rtrim("a") trim(BOTH "" from "a") trim(BOTH " " from "a")
a a a a
+select concat("1","2")|0,concat("1",".5")+0.0;
concat("1","2")|0 concat("1",".5")+0.0
12 1.5
+select substring_index("www.tcx.se","",3);
substring_index("www.tcx.se","",3)
+select length(repeat("a",100000000)),length(repeat("a",1000*64));
length(repeat("a",100000000)) length(repeat("a",1000*64))
NULL 64000
+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
+select position(("1" in (1,2,3)) in "01");
position(("1" in (1,2,3)) in "01")
2
+select length(repeat("a",65500)),length(concat(repeat("a",32000),repeat("a",32000))),length(replace("aaaaa","a",concat(repeat("a",10000)))),length(insert(repeat("a",40000),1,30000,repeat("b",50000)));
length(repeat("a",65500)) length(concat(repeat("a",32000),repeat("a",32000))) length(replace("aaaaa","a",concat(repeat("a",10000)))) length(insert(repeat("a",40000),1,30000,repeat("b",50000)))
65500 64000 50000 60000
+select length(repeat("a",1000000)),length(concat(repeat("a",32000),repeat("a",32000),repeat("a",32000))),length(replace("aaaaa","a",concat(repeat("a",32000)))),length(insert(repeat("a",48000),1,1000,repeat("a",48000)));
length(repeat("a",1000000)) length(concat(repeat("a",32000),repeat("a",32000),repeat("a",32000))) length(replace("aaaaa","a",concat(repeat("a",32000)))) length(insert(repeat("a",48000),1,1000,repeat("a",48000)))
1000000 96000 160000 95000
+create table t1 ( domain char(50) );
+insert into t1 VALUES ("hello.de" ), ("test.de" );
+select domain from t1 where concat('@', trim(leading '.' from concat('.', domain))) = '@hello.de';
domain
hello.de
+select domain from t1 where concat('@', trim(leading '.' from concat('.', domain))) = '@test.de';
domain
test.de
+drop table t1;
+CREATE TABLE t1 (
+id int(10) unsigned NOT NULL,
+title varchar(255) default NULL,
+prio int(10) unsigned default NULL,
+category int(10) unsigned default NULL,
+program int(10) unsigned default NULL,
+bugdesc text,
+created datetime default NULL,
+modified timestamp(14) NOT NULL,
+bugstatus int(10) unsigned default NULL,
+submitter int(10) unsigned default NULL
+) TYPE=MyISAM;
+INSERT INTO t1 VALUES (1,'Link',1,1,1,'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa','2001-02-28 08:40:16',20010228084016,0,4);
+SELECT CONCAT('"',CONCAT_WS('";"',title,prio,category,program,bugdesc,created,modified,bugstatus,submitter), '"') FROM t1;
CONCAT('"',CONCAT_WS('";"',title,prio,category,program,bugdesc,created,modified,bugstatus,submitter), '"')
"Link";"1";"1";"1";"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";"2001-02-28 08:40:16";"20010228084016";"0";"4"
+SELECT CONCAT('"',CONCAT_WS('";"',title,prio,category,program,bugstatus,submitter), '"') FROM t1;
CONCAT('"',CONCAT_WS('";"',title,prio,category,program,bugstatus,submitter), '"')
"Link";"1";"1";"1";"0";"4"
+SELECT CONCAT_WS('";"',title,prio,category,program,bugdesc,created,modified,bugstatus,submitter) FROM t1;
CONCAT_WS('";"',title,prio,category,program,bugdesc,created,modified,bugstatus,submitter)
Link";"1";"1";"1";"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";"2001-02-28 08:40:16";"20010228084016";"0";"4
+drop table t1;
diff --git a/mysql-test/r/func_system.result b/mysql-test/r/func_system.result
index c6ec28bfd34..5ea4ed5e4e0 100644
--- a/mysql-test/r/func_system.result
+++ b/mysql-test/r/func_system.result
@@ -1,4 +1,6 @@
-database() user()
-test root@localhost
+select database(),user() like "%@%";
+database() user() like "%@%"
+test 1
+select version()>="3.23.29";
version()>="3.23.29"
1
diff --git a/mysql-test/r/func_test.result b/mysql-test/r/func_test.result
index 5d2211baf50..0a45f9e8b5c 100644
--- a/mysql-test/r/func_test.result
+++ b/mysql-test/r/func_test.result
@@ -1,38 +1,61 @@
+select 0=0,1>0,1>=1,1<0,1<=0,1!=0,strcmp("abc","abcd"),strcmp("b","a"),strcmp("a","a") ;
0=0 1>0 1>=1 1<0 1<=0 1!=0 strcmp("abc","abcd") strcmp("b","a") strcmp("a","a")
1 1 1 0 0 1 -1 1 0
+select "a"<"b","a"<="b","b">="a","b">"a","a"="A","a"<>"b";
"a"<"b" "a"<="b" "b">="a" "b">"a" "a"="A" "a"<>"b"
1 1 1 1 1 1
+select "a "="A", "A "="a", "a " <= "A b";
"a "="A" "A "="a" "a " <= "A b"
1 1 1
+select "abc" like "a%", "abc" not like "%d%", "a%" like "a\%","abc%" like "a%\%","abcd" like "a%b_%d", "a" like "%%a","abcde" like "a%_e","abc" like "abc%";
"abc" like "a%" "abc" not like "%d%" "a%" like "a\%" "abc%" like "a%\%" "abcd" like "a%b_%d" "a" like "%%a" "abcde" like "a%_e" "abc" like "abc%"
1 1 1 1 1 1 1 1
+select "a" like "%%b","a" like "%%ab","ab" like "a\%", "ab" like "_", "ab" like "ab_", "abc" like "%_d", "abc" like "abc%d";
"a" like "%%b" "a" like "%%ab" "ab" like "a\%" "ab" like "_" "ab" like "ab_" "abc" like "%_d" "abc" like "abc%d"
0 0 0 0 0 0 0
+select '?' like '|%', '?' like '|%' ESCAPE '|', '%' like '|%', '%' like '|%' ESCAPE '|', '%' like '%';
'?' like '|%' '?' like '|%' ESCAPE '|' '%' like '|%' '%' like '|%' ESCAPE '|' '%' like '%'
0 0 0 1 1
+select 'abc' like '%c','abcabc' like '%c', "ab" like "", "ab" like "a", "ab" like "ab";
'abc' like '%c' 'abcabc' like '%c' "ab" like "" "ab" like "a" "ab" like "ab"
1 1 0 0 1
+select "Det här är svenska" regexp "h[[:alpha:]]+r", "aba" regexp "^(a|b)*$";
"Det här är svenska" regexp "h[[:alpha:]]+r" "aba" regexp "^(a|b)*$"
1 1
+select "aba" regexp concat("^","a");
"aba" regexp concat("^","a")
1
+select !0,NOT 0=1,!(0=0),1 AND 1,1 && 0,0 OR 1,1 || NULL, 1=1 or 1=1 and 1=0;
!0 NOT 0=1 !(0=0) 1 AND 1 1 && 0 0 OR 1 1 || NULL 1=1 or 1=1 and 1=0
1 1 0 1 0 1 1 1
+select IF(0,"ERROR","this"),IF(1,"is","ERROR"),IF(NULL,"ERROR","a"),IF(1,2,3)|0,IF(1,2.0,3.0)+0 ;
IF(0,"ERROR","this") IF(1,"is","ERROR") IF(NULL,"ERROR","a") IF(1,2,3)|0 IF(1,2.0,3.0)+0
this is a 2 2.0
+select 2 between 1 and 3, "monty" between "max" and "my",2=2 and "monty" between "max" and "my" and 3=3;
2 between 1 and 3 "monty" between "max" and "my" 2=2 and "monty" between "max" and "my" and 3=3
1 1 1
+select 'b' between 'a' and 'c', 'B' between 'a' and 'c';
'b' between 'a' and 'c' 'B' between 'a' and 'c'
1 1
+select 2 in (3,2,5,9,5,1),"monty" in ("david","monty","allan"), 1.2 in (1.4,1.2,1.0);
2 in (3,2,5,9,5,1) "monty" in ("david","monty","allan") 1.2 in (1.4,1.2,1.0)
1 1 1
+select -1.49 or -1.49,0.6 or 0.6;
-1.49 or -1.49 0.6 or 0.6
1 1
+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
0 1
+select 1 and 2 between 2 and 10, 2 between 2 and 10 and 1;
1 and 2 between 2 and 10 2 between 2 and 10 and 1
1 1
+select 1 and 0 or 2, 2 or 1 and 0;
1 and 0 or 2 2 or 1 and 0
1 1
+drop table if exists t1;
+create table t1 (num double(12,2));
+insert into t1 values (144.54);
+select sum(if(num is null,0.00,num)) from t1;
sum(if(num is null,0.00,num))
144.54
+drop table t1;
diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result
index 71fc7e4b90b..5433194c719 100644
--- a/mysql-test/r/func_time.result
+++ b/mysql-test/r/func_time.result
@@ -1,222 +1,374 @@
+drop table if exists t1,t2;
+select from_days(to_days("960101")),to_days(960201)-to_days("19960101"),to_days(date_add(curdate(), interval 1 day))-to_days(curdate()),weekday("1997-11-29");
from_days(to_days("960101")) to_days(960201)-to_days("19960101") to_days(date_add(curdate(), interval 1 day))-to_days(curdate()) weekday("1997-11-29")
1996-01-01 31 1 5
+select period_add("9602",-12),period_diff(199505,"9404") ;
period_add("9602",-12) period_diff(199505,"9404")
199502 13
+select now()-now(),weekday(curdate())-weekday(now()),unix_timestamp()-unix_timestamp(now());
now()-now() weekday(curdate())-weekday(now()) unix_timestamp()-unix_timestamp(now())
0 0 0
+select from_unixtime(unix_timestamp("1994-03-02 10:11:12")),from_unixtime(unix_timestamp("1994-03-02 10:11:12"),"%Y-%m-%d %h:%i:%s"),from_unixtime(unix_timestamp("1994-03-02 10:11:12"))+0;
from_unixtime(unix_timestamp("1994-03-02 10:11:12")) from_unixtime(unix_timestamp("1994-03-02 10:11:12"),"%Y-%m-%d %h:%i:%s") from_unixtime(unix_timestamp("1994-03-02 10:11:12"))+0
1994-03-02 10:11:12 1994-03-02 10:11:12 19940302101112
+select sec_to_time(9001),sec_to_time(9001)+0,time_to_sec("15:12:22"),
+sec_to_time(time_to_sec("0:30:47")/6.21);
sec_to_time(9001) sec_to_time(9001)+0 time_to_sec("15:12:22") sec_to_time(time_to_sec("0:30:47")/6.21)
02:30:01 23001 54742 00:04:57
+select sec_to_time(time_to_sec('-838:59:59'));
sec_to_time(time_to_sec('-838:59:59'))
-838:59:59
+select now()-curdate()*1000000-curtime();
now()-curdate()*1000000-curtime()
0
+select strcmp(current_timestamp(),concat(current_date()," ",current_time()));
strcmp(current_timestamp(),concat(current_date()," ",current_time()))
0
+select date_format("1997-01-02 03:04:05", "%M %W %D %Y %y %m %d %h %i %s %w");
date_format("1997-01-02 03:04:05", "%M %W %D %Y %y %m %d %h %i %s %w")
January Thursday 2nd 1997 97 01 02 03 04 05 4
+select date_format("1997-01-02", concat("%M %W %D ","%Y %y %m %d %h %i %s %w"));
date_format("1997-01-02", concat("%M %W %D ","%Y %y %m %d %h %i %s %w"))
January Thursday 2nd 1997 97 01 02 12 00 00 4
+select dayofmonth("1997-01-02"),dayofmonth(19970323);
dayofmonth("1997-01-02") dayofmonth(19970323)
2 23
+select month("1997-01-02"),year("98-02-03"),dayofyear("1997-12-31");
month("1997-01-02") year("98-02-03") dayofyear("1997-12-31")
1 1998 365
+select month("2001-02-00"),year("2001-00-00");
month("2001-02-00") year("2001-00-00")
2 2001
+select DAYOFYEAR("1997-03-03"), WEEK("1998-03-03"), QUARTER(980303);
DAYOFYEAR("1997-03-03") WEEK("1998-03-03") QUARTER(980303)
62 9 1
+select HOUR("1997-03-03 23:03:22"), MINUTE("23:03:22"), SECOND(230322);
HOUR("1997-03-03 23:03:22") MINUTE("23:03:22") SECOND(230322)
23 3 22
+select week(19980101),week(19970101),week(19980101,1),week(19970101,1);
week(19980101) week(19970101) week(19980101,1) week(19970101,1)
-0 1 1 1
+0 0 1 1
+select week(19981231),week(19971231),week(19981231,1),week(19971231,1);
week(19981231) week(19971231) week(19981231,1) week(19971231,1)
-52 53 53 53
+52 52 53 53
+select week(19950101),week(19950101,1);
week(19950101) week(19950101,1)
1 0
+select yearweek('1981-12-31',1),yearweek('1982-01-01',1),yearweek('1982-12-31',1),yearweek('1983-01-01',1);
yearweek('1981-12-31',1) yearweek('1982-01-01',1) yearweek('1982-12-31',1) yearweek('1983-01-01',1)
198153 198153 198252 198252
+select yearweek('1987-01-01',1),yearweek('1987-01-01');
+yearweek('1987-01-01',1) yearweek('1987-01-01')
+198701 198652
+select week("2000-01-01",0) as '2000', week("2001-01-01",0) as '2001', week("2002-01-01",0) as '2002',week("2003-01-01",0) as '2003', week("2004-01-01",0) as '2004', week("2005-01-01",0) as '2005', week("2006-01-01",0) as '2006';
+2000 2001 2002 2003 2004 2005 2006
+0 0 0 0 0 0 1
+select week("2000-01-06",0) as '2000', week("2001-01-06",0) as '2001', week("2002-01-06",0) as '2002',week("2003-01-06",0) as '2003', week("2004-01-06",0) as '2004', week("2005-01-06",0) as '2005', week("2006-01-06",0) as '2006';
+2000 2001 2002 2003 2004 2005 2006
+1 0 1 1 1 1 1
+select week("2000-01-01",1) as '2000', week("2001-01-01",1) as '2001', week("2002-01-01",1) as '2002',week("2003-01-01",1) as '2003', week("2004-01-01",1) as '2004', week("2005-01-01",1) as '2005', week("2006-01-01",1) as '2006';
+2000 2001 2002 2003 2004 2005 2006
+0 1 1 1 1 0 0
+select week("2000-01-06",1) as '2000', week("2001-01-06",1) as '2001', week("2002-01-06",1) as '2002',week("2003-01-06",1) as '2003', week("2004-01-06",1) as '2004', week("2005-01-06",1) as '2005', week("2006-01-06",1) as '2006';
+2000 2001 2002 2003 2004 2005 2006
+1 1 1 2 2 1 1
+select yearweek("2000-01-01",0) as '2000', yearweek("2001-01-01",0) as '2001', yearweek("2002-01-01",0) as '2002',yearweek("2003-01-01",0) as '2003', yearweek("2004-01-01",0) as '2004', yearweek("2005-01-01",0) as '2005', yearweek("2006-01-01",0) as '2006';
+2000 2001 2002 2003 2004 2005 2006
+199952 200053 200152 200252 200352 200452 200601
+select yearweek("2000-01-06",0) as '2000', yearweek("2001-01-06",0) as '2001', yearweek("2002-01-06",0) as '2002',yearweek("2003-01-06",0) as '2003', yearweek("2004-01-06",0) as '2004', yearweek("2005-01-06",0) as '2005', yearweek("2006-01-06",0) as '2006';
+2000 2001 2002 2003 2004 2005 2006
+200001 200053 200201 200301 200401 200501 200601
+select yearweek("2000-01-01",1) as '2000', yearweek("2001-01-01",1) as '2001', yearweek("2002-01-01",1) as '2002',yearweek("2003-01-01",1) as '2003', yearweek("2004-01-01",1) as '2004', yearweek("2005-01-01",1) as '2005', yearweek("2006-01-01",1) as '2006';
+2000 2001 2002 2003 2004 2005 2006
+199952 200101 200201 200301 200401 200453 200552
+select yearweek("2000-01-06",1) as '2000', yearweek("2001-01-06",1) as '2001', yearweek("2002-01-06",1) as '2002',yearweek("2003-01-06",1) as '2003', yearweek("2004-01-06",1) as '2004', yearweek("2005-01-06",1) as '2005', yearweek("2006-01-06",1) as '2006';
+2000 2001 2002 2003 2004 2005 2006
+200001 200101 200201 200302 200402 200501 200601
+select date_format('1998-12-31','%x-%v'),date_format('1999-01-01','%x-%v');
date_format('1998-12-31','%x-%v') date_format('1999-01-01','%x-%v')
1998-53 1998-53
+select date_format('1999-12-31','%x-%v'),date_format('2000-01-01','%x-%v');
date_format('1999-12-31','%x-%v') date_format('2000-01-01','%x-%v')
1999-52 1999-52
-yearweek('1987-01-01',1) yearweek('1987-01-01')
-198701 198653
+select dayname("1962-03-03"),dayname("1962-03-03")+0;
dayname("1962-03-03") dayname("1962-03-03")+0
Saturday 5
+select monthname("1972-03-04"),monthname("1972-03-04")+0;
monthname("1972-03-04") monthname("1972-03-04")+0
March 3
+select time_format(19980131000000,'%H|%I|%k|%l|%i|%p|%r|%S|%T');
time_format(19980131000000,'%H|%I|%k|%l|%i|%p|%r|%S|%T')
00|12|0|12|00|AM|12:00:00 AM|00|00:00:00
+select time_format(19980131010203,'%H|%I|%k|%l|%i|%p|%r|%S|%T');
time_format(19980131010203,'%H|%I|%k|%l|%i|%p|%r|%S|%T')
01|01|1|1|02|AM|01:02:03 AM|03|01:02:03
+select time_format(19980131131415,'%H|%I|%k|%l|%i|%p|%r|%S|%T');
time_format(19980131131415,'%H|%I|%k|%l|%i|%p|%r|%S|%T')
13|01|13|1|14|PM|01:14:15 PM|15|13:14:15
+select time_format(19980131010015,'%H|%I|%k|%l|%i|%p|%r|%S|%T');
time_format(19980131010015,'%H|%I|%k|%l|%i|%p|%r|%S|%T')
01|01|1|1|00|AM|01:00:15 AM|15|01:00:15
+select date_format(concat('19980131',131415),'%H|%I|%k|%l|%i|%p|%r|%S|%T| %M|%W|%D|%Y|%y|%a|%b|%j|%m|%d|%h|%s|%w');
date_format(concat('19980131',131415),'%H|%I|%k|%l|%i|%p|%r|%S|%T| %M|%W|%D|%Y|%y|%a|%b|%j|%m|%d|%h|%s|%w')
13|01|13|1|14|PM|01:14:15 PM|15|13:14:15| January|Saturday|31st|1998|98|Sat|Jan|031|01|31|01|15|6
+select date_format(19980021000000,'%H|%I|%k|%l|%i|%p|%r|%S|%T| %M|%W|%D|%Y|%y|%a|%b|%j|%m|%d|%h|%s|%w');
date_format(19980021000000,'%H|%I|%k|%l|%i|%p|%r|%S|%T| %M|%W|%D|%Y|%y|%a|%b|%j|%m|%d|%h|%s|%w')
NULL
+select date_add("1997-12-31 23:59:59",INTERVAL 1 SECOND);
date_add("1997-12-31 23:59:59",INTERVAL 1 SECOND)
1998-01-01 00:00:00
+select date_add("1997-12-31 23:59:59",INTERVAL 1 MINUTE);
date_add("1997-12-31 23:59:59",INTERVAL 1 MINUTE)
1998-01-01 00:00:59
+select date_add("1997-12-31 23:59:59",INTERVAL 1 HOUR);
date_add("1997-12-31 23:59:59",INTERVAL 1 HOUR)
1998-01-01 00:59:59
+select date_add("1997-12-31 23:59:59",INTERVAL 1 DAY);
date_add("1997-12-31 23:59:59",INTERVAL 1 DAY)
1998-01-01 23:59:59
+select date_add("1997-12-31 23:59:59",INTERVAL 1 MONTH);
date_add("1997-12-31 23:59:59",INTERVAL 1 MONTH)
1998-01-31 23:59:59
+select date_add("1997-12-31 23:59:59",INTERVAL 1 YEAR);
date_add("1997-12-31 23:59:59",INTERVAL 1 YEAR)
1998-12-31 23:59:59
+select date_add("1997-12-31 23:59:59",INTERVAL "1:1" MINUTE_SECOND);
date_add("1997-12-31 23:59:59",INTERVAL "1:1" MINUTE_SECOND)
1998-01-01 00:01:00
+select date_add("1997-12-31 23:59:59",INTERVAL "1:1" HOUR_MINUTE);
date_add("1997-12-31 23:59:59",INTERVAL "1:1" HOUR_MINUTE)
1998-01-01 01:00:59
+select date_add("1997-12-31 23:59:59",INTERVAL "1:1" DAY_HOUR);
date_add("1997-12-31 23:59:59",INTERVAL "1:1" DAY_HOUR)
1998-01-02 00:59:59
+select date_add("1997-12-31 23:59:59",INTERVAL "1 1" YEAR_MONTH);
date_add("1997-12-31 23:59:59",INTERVAL "1 1" YEAR_MONTH)
1999-01-31 23:59:59
+select date_add("1997-12-31 23:59:59",INTERVAL "1:1:1" HOUR_SECOND);
date_add("1997-12-31 23:59:59",INTERVAL "1:1:1" HOUR_SECOND)
1998-01-01 01:01:00
+select date_add("1997-12-31 23:59:59",INTERVAL "1 1:1" DAY_MINUTE);
date_add("1997-12-31 23:59:59",INTERVAL "1 1:1" DAY_MINUTE)
1998-01-02 01:00:59
+select date_add("1997-12-31 23:59:59",INTERVAL "1 1:1:1" DAY_SECOND);
date_add("1997-12-31 23:59:59",INTERVAL "1 1:1:1" DAY_SECOND)
1998-01-02 01:01:00
+select date_sub("1998-01-01 00:00:00",INTERVAL 1 SECOND);
date_sub("1998-01-01 00:00:00",INTERVAL 1 SECOND)
1997-12-31 23:59:59
+select date_sub("1998-01-01 00:00:00",INTERVAL 1 MINUTE);
date_sub("1998-01-01 00:00:00",INTERVAL 1 MINUTE)
1997-12-31 23:59:00
+select date_sub("1998-01-01 00:00:00",INTERVAL 1 HOUR);
date_sub("1998-01-01 00:00:00",INTERVAL 1 HOUR)
1997-12-31 23:00:00
+select date_sub("1998-01-01 00:00:00",INTERVAL 1 DAY);
date_sub("1998-01-01 00:00:00",INTERVAL 1 DAY)
1997-12-31 00:00:00
+select date_sub("1998-01-01 00:00:00",INTERVAL 1 MONTH);
date_sub("1998-01-01 00:00:00",INTERVAL 1 MONTH)
1997-12-01 00:00:00
+select date_sub("1998-01-01 00:00:00",INTERVAL 1 YEAR);
date_sub("1998-01-01 00:00:00",INTERVAL 1 YEAR)
1997-01-01 00:00:00
+select date_sub("1998-01-01 00:00:00",INTERVAL "1:1" MINUTE_SECOND);
date_sub("1998-01-01 00:00:00",INTERVAL "1:1" MINUTE_SECOND)
1997-12-31 23:58:59
+select date_sub("1998-01-01 00:00:00",INTERVAL "1:1" HOUR_MINUTE);
date_sub("1998-01-01 00:00:00",INTERVAL "1:1" HOUR_MINUTE)
1997-12-31 22:59:00
+select date_sub("1998-01-01 00:00:00",INTERVAL "1:1" DAY_HOUR);
date_sub("1998-01-01 00:00:00",INTERVAL "1:1" DAY_HOUR)
1997-12-30 23:00:00
+select date_sub("1998-01-01 00:00:00",INTERVAL "1 1" YEAR_MONTH);
date_sub("1998-01-01 00:00:00",INTERVAL "1 1" YEAR_MONTH)
1996-12-01 00:00:00
+select date_sub("1998-01-01 00:00:00",INTERVAL "1:1:1" HOUR_SECOND);
date_sub("1998-01-01 00:00:00",INTERVAL "1:1:1" HOUR_SECOND)
1997-12-31 22:58:59
+select date_sub("1998-01-01 00:00:00",INTERVAL "1 1:1" DAY_MINUTE);
date_sub("1998-01-01 00:00:00",INTERVAL "1 1:1" DAY_MINUTE)
1997-12-30 22:59:00
+select date_sub("1998-01-01 00:00:00",INTERVAL "1 1:1:1" DAY_SECOND);
date_sub("1998-01-01 00:00:00",INTERVAL "1 1:1:1" DAY_SECOND)
1997-12-30 22:58:59
+select date_add("1997-12-31 23:59:59",INTERVAL 100000 SECOND);
date_add("1997-12-31 23:59:59",INTERVAL 100000 SECOND)
1998-01-02 03:46:39
+select date_add("1997-12-31 23:59:59",INTERVAL -100000 MINUTE);
date_add("1997-12-31 23:59:59",INTERVAL -100000 MINUTE)
1997-10-23 13:19:59
+select date_add("1997-12-31 23:59:59",INTERVAL 100000 HOUR);
date_add("1997-12-31 23:59:59",INTERVAL 100000 HOUR)
2009-05-29 15:59:59
+select date_add("1997-12-31 23:59:59",INTERVAL -100000 DAY);
date_add("1997-12-31 23:59:59",INTERVAL -100000 DAY)
1724-03-17 23:59:59
+select date_add("1997-12-31 23:59:59",INTERVAL 100000 MONTH);
date_add("1997-12-31 23:59:59",INTERVAL 100000 MONTH)
NULL
+select date_add("1997-12-31 23:59:59",INTERVAL -100000 YEAR);
date_add("1997-12-31 23:59:59",INTERVAL -100000 YEAR)
NULL
+select date_add("1997-12-31 23:59:59",INTERVAL "10000:1" MINUTE_SECOND);
date_add("1997-12-31 23:59:59",INTERVAL "10000:1" MINUTE_SECOND)
1998-01-07 22:40:00
+select date_add("1997-12-31 23:59:59",INTERVAL "-10000:1" HOUR_MINUTE);
date_add("1997-12-31 23:59:59",INTERVAL "-10000:1" HOUR_MINUTE)
1996-11-10 07:58:59
+select date_add("1997-12-31 23:59:59",INTERVAL "10000:1" DAY_HOUR);
date_add("1997-12-31 23:59:59",INTERVAL "10000:1" DAY_HOUR)
2025-05-19 00:59:59
+select date_add("1997-12-31 23:59:59",INTERVAL "-100 1" YEAR_MONTH);
date_add("1997-12-31 23:59:59",INTERVAL "-100 1" YEAR_MONTH)
1897-11-30 23:59:59
+select date_add("1997-12-31 23:59:59",INTERVAL "10000:99:99" HOUR_SECOND);
date_add("1997-12-31 23:59:59",INTERVAL "10000:99:99" HOUR_SECOND)
1999-02-21 17:40:38
+select date_add("1997-12-31 23:59:59",INTERVAL " -10000 99:99" DAY_MINUTE);
date_add("1997-12-31 23:59:59",INTERVAL " -10000 99:99" DAY_MINUTE)
1970-08-11 19:20:59
+select date_add("1997-12-31 23:59:59",INTERVAL "10000 99:99:99" DAY_SECOND);
date_add("1997-12-31 23:59:59",INTERVAL "10000 99:99:99" DAY_SECOND)
2025-05-23 04:40:38
+select "1997-12-31 23:59:59" + INTERVAL 1 SECOND;
"1997-12-31 23:59:59" + INTERVAL 1 SECOND
1998-01-01 00:00:00
+select INTERVAL 1 DAY + "1997-12-31";
INTERVAL 1 DAY + "1997-12-31"
1998-01-01
+select "1998-01-01 00:00:00" - INTERVAL 1 SECOND;
"1998-01-01 00:00:00" - INTERVAL 1 SECOND
1997-12-31 23:59:59
+select date_sub("1998-01-02",INTERVAL 31 DAY);
date_sub("1998-01-02",INTERVAL 31 DAY)
1997-12-02
+select date_add("1997-12-31",INTERVAL 1 SECOND);
date_add("1997-12-31",INTERVAL 1 SECOND)
1997-12-31 00:00:01
+select date_add("1997-12-31",INTERVAL 1 DAY);
date_add("1997-12-31",INTERVAL 1 DAY)
1998-01-01
+select date_add(NULL,INTERVAL 100000 SECOND);
date_add(NULL,INTERVAL 100000 SECOND)
NULL
+select date_add("1997-12-31 23:59:59",INTERVAL NULL SECOND);
date_add("1997-12-31 23:59:59",INTERVAL NULL SECOND)
NULL
+select date_add("1997-12-31 23:59:59",INTERVAL NULL MINUTE_SECOND);
date_add("1997-12-31 23:59:59",INTERVAL NULL MINUTE_SECOND)
NULL
+select date_add("9999-12-31 23:59:59",INTERVAL 1 SECOND);
date_add("9999-12-31 23:59:59",INTERVAL 1 SECOND)
NULL
+select date_sub("0000-00-00 00:00:00",INTERVAL 1 SECOND);
date_sub("0000-00-00 00:00:00",INTERVAL 1 SECOND)
NULL
+select date_add('1998-01-30',Interval 1 month);
date_add('1998-01-30',Interval 1 month)
1998-02-28
+select date_add('1998-01-30',Interval '2:1' year_month);
date_add('1998-01-30',Interval '2:1' year_month)
2000-02-29
+select date_add('1996-02-29',Interval '1' year);
date_add('1996-02-29',Interval '1' year)
1997-02-28
+select extract(YEAR FROM "1999-01-02 10:11:12");
extract(YEAR FROM "1999-01-02 10:11:12")
1999
+select extract(YEAR_MONTH FROM "1999-01-02");
extract(YEAR_MONTH FROM "1999-01-02")
199901
+select extract(DAY FROM "1999-01-02");
extract(DAY FROM "1999-01-02")
2
+select extract(DAY_HOUR FROM "1999-01-02 10:11:12");
extract(DAY_HOUR FROM "1999-01-02 10:11:12")
210
+select extract(DAY_MINUTE FROM "02 10:11:12");
extract(DAY_MINUTE FROM "02 10:11:12")
21011
+select extract(DAY_SECOND FROM "225 10:11:12");
extract(DAY_SECOND FROM "225 10:11:12")
225101112
+select extract(HOUR FROM "1999-01-02 10:11:12");
extract(HOUR FROM "1999-01-02 10:11:12")
10
+select extract(HOUR_MINUTE FROM "10:11:12");
extract(HOUR_MINUTE FROM "10:11:12")
1011
+select extract(HOUR_SECOND FROM "10:11:12");
extract(HOUR_SECOND FROM "10:11:12")
101112
+select extract(MINUTE FROM "10:11:12");
extract(MINUTE FROM "10:11:12")
11
+select extract(MINUTE_SECOND FROM "10:11:12");
extract(MINUTE_SECOND FROM "10:11:12")
1112
+select extract(SECOND FROM "1999-01-02 10:11:12");
extract(SECOND FROM "1999-01-02 10:11:12")
12
+select extract(MONTH FROM "2001-02-00");
extract(MONTH FROM "2001-02-00")
2
+create table t1 (ctime varchar(20));
+insert into t1 values ('2001-01-12 12:23:40');
+select ctime, hour(ctime) from t1;
ctime hour(ctime)
2001-01-12 12:23:40 12
+drop table t1;
+create table t1 (id int);
+create table t2 (id int, date date);
+insert into t1 values (1);
+insert into t2 values (1, "0000-00-00");
+insert into t1 values (2);
+insert into t2 values (2, "2000-01-01");
+select monthname(date) from t1 inner join t2 on t1.id = t2.id;
monthname(date)
NULL
January
+select monthname(date) from t1 inner join t2 on t1.id = t2.id order by t1.id;
monthname(date)
NULL
January
+drop table t1,t2;
+CREATE TABLE t1 (updated text) TYPE=MyISAM;
+INSERT INTO t1 VALUES ('');
+SELECT month(updated) from t1;
month(updated)
NULL
+SELECT year(updated) from t1;
year(updated)
NULL
+drop table t1;
+create table t1 (d date, dt datetime, t timestamp, c char(10));
+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
+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
+select month("0000-00-00"),month(d),month(dt),month(t),month(c) from t1;
month("0000-00-00") month(d) month(dt) month(t) month(c)
0 0 0 0 0
+select quarter("0000-00-00"),quarter(d),quarter(dt),quarter(t),quarter(c) from t1;
quarter("0000-00-00") quarter(d) quarter(dt) quarter(t) quarter(c)
0 0 0 0 0
+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
+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
+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
+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
+drop table t1;
diff --git a/mysql-test/r/func_timestamp.result b/mysql-test/r/func_timestamp.result
index 4d4a5b541ac..d9912f08b72 100644
--- a/mysql-test/r/func_timestamp.result
+++ b/mysql-test/r/func_timestamp.result
@@ -1,3 +1,11 @@
+drop table if exists t1;
+create table t1 (Zeit time, Tag tinyint not null, Monat tinyint not null,
+Jahr smallint not null, index(Tag), index(Monat), index(Jahr) );
+insert into t1 values ("09:26:00",16,9,1998),("09:26:00",16,9,1998);
+SELECT CONCAT(Jahr,'-',Monat,'-',Tag,' ',Zeit) AS Date,
+UNIX_TIMESTAMP(CONCAT(Jahr,'-',Monat,'-',Tag,' ',Zeit)) AS Unix
+FROM t1;
Date Unix
1998-9-16 09:26:00 905927160
1998-9-16 09:26:00 905927160
+drop table t1;
diff --git a/mysql-test/r/gcc296.result b/mysql-test/r/gcc296.result
index 7184bfb9cdc..8f78f70cc1f 100644
--- a/mysql-test/r/gcc296.result
+++ b/mysql-test/r/gcc296.result
@@ -1,5 +1,20 @@
+drop table if exists obory;
+CREATE TABLE obory (
+kodoboru varchar(10) default NULL,
+obor tinytext,
+aobor tinytext,
+UNIQUE INDEX kodoboru (kodoboru),
+FULLTEXT KEY obor (obor),
+FULLTEXT KEY aobor (aobor)
+);
+INSERT INTO obory VALUES ('0101000000','aaa','AAA');
+INSERT INTO obory VALUES ('0102000000','bbb','BBB');
+INSERT INTO obory VALUES ('0103000000','ccc','CCC');
+INSERT INTO obory VALUES ('0104000000','xxx','XXX');
+select * from obory;
kodoboru obor aobor
0101000000 aaa AAA
0102000000 bbb BBB
0103000000 ccc CCC
0104000000 xxx XXX
+drop table obory;
diff --git a/mysql-test/r/gemini.result b/mysql-test/r/gemini.result
deleted file mode 100644
index 0b43b4f5192..00000000000
--- a/mysql-test/r/gemini.result
+++ /dev/null
@@ -1,370 +0,0 @@
-id code name
-1 1 Tim
-2 1 Monty
-3 2 David
-4 2 Erik
-5 3 Sasha
-6 3 Jeremy
-7 4 Matt
-id code name
-2 1 Monty
-3 2 David
-4 2 Erik
-5 3 Sasha
-6 3 Jeremy
-7 4 Matt
-8 1 Sinisa
-id code name
-3 2 David
-4 2 Erik
-5 3 Sasha
-6 3 Jeremy
-7 4 Matt
-8 1 Sinisa
-12 1 Ralph
-id parent_id level
-8 102 2
-9 102 2
-15 102 2
-id parent_id level
-1001 100 0
-1003 101 1
-1004 101 1
-1008 102 2
-1009 102 2
-1017 103 2
-1022 104 2
-1024 104 2
-1028 105 2
-1029 105 2
-1030 105 2
-1031 106 2
-1032 106 2
-1033 106 2
-1203 107 2
-1202 107 2
-1020 103 2
-1157 100 0
-1193 105 2
-1040 107 2
-1002 101 1
-1015 102 2
-1006 101 1
-1034 106 2
-1035 106 2
-1016 103 2
-1007 101 1
-1036 107 2
-1018 103 2
-1026 105 2
-1027 105 2
-1183 104 2
-1038 107 2
-1025 105 2
-1037 107 2
-1021 104 2
-1019 103 2
-1005 101 1
-1179 105 2
-id parent_id level
-1001 100 0
-1003 101 1
-1004 101 1
-1008 102 2
-1010 102 2
-1017 103 2
-1023 104 2
-1024 104 2
-1028 105 2
-1029 105 2
-1030 105 2
-1031 106 2
-1032 106 2
-1033 106 2
-1204 107 2
-1203 107 2
-1020 103 2
-1158 100 0
-1194 105 2
-1041 107 2
-1002 101 1
-1015 102 2
-1006 101 1
-1034 106 2
-1035 106 2
-1016 103 2
-1007 101 1
-1036 107 2
-1018 103 2
-1026 105 2
-1027 105 2
-1184 104 2
-1039 107 2
-1025 105 2
-1038 107 2
-1022 104 2
-1019 103 2
-1005 101 1
-1180 105 2
-id parent_id level
-1008 102 2
-1010 102 2
-1015 102 2
-table type possible_keys key key_len ref rows Extra
-t1 ref level level 1 const 6 where used; Using index
-table type possible_keys key key_len ref rows Extra
-t1 ref level level 1 const 6 where used
-table type possible_keys key key_len ref rows Extra
-t1 ref level level 1 const 6 where used
-level id
-1 1003
-1 1004
-1 1002
-1 1006
-1 1007
-1 1005
-level id parent_id
-1 1003 101
-1 1004 101
-1 1002 101
-1 1006 101
-1 1007 101
-1 1005 101
-gesuchnr benutzer_id
-1 1
-2 1
-a
-2
-user_id name phone ref_email detail
-10292 sanjeev 29153373 sansh777@hotmail.com xxx
-10292 shirish 2333604 shirish@yahoo.com ddsds
-10292 sonali 323232 sonali@bolly.com filmstar
-user_id name phone ref_email detail
-10292 sanjeev 29153373 sansh777@hotmail.com xxx
-10292 shirish 2333604 shirish@yahoo.com ddsds
-10292 sonali 323232 sonali@bolly.com filmstar
-user_id name phone ref_email detail
-10292 sanjeev 29153373 sansh777@hotmail.com xxx
-10292 shirish 2333604 shirish@yahoo.com ddsds
-10292 sonali 323232 sonali@bolly.com filmstar
-10293 shirish 2333604 shirish@yahoo.com ddsds
-user_id name phone ref_email detail
-10293 shirish 2333604 shirish@yahoo.com ddsds
-user_id name phone ref_email detail
-10291 sanjeev 29153373 sansh777@hotmail.com xxx
-a b
-1 3
-2 3
-3 3
-a b
-1 3
-2 3
-3 3
-a b
-a b
-1 3
-2 3
-3 3
-a b
-1 3
-2 3
-3 3
-id ggid email passwd
-1 test1 xxx
-id ggid email passwd
-1 test1 xxx
-id ggid email passwd
-2 test2 yyy
-id parent_id level
-8 102 2
-9 102 2
-15 102 2
-id parent_id level
-1001 100 0
-1003 101 1
-1004 101 1
-1008 102 2
-1024 102 2
-1017 103 2
-1022 104 2
-1024 104 2
-1028 105 2
-1029 105 2
-1030 105 2
-1031 106 2
-1032 106 2
-1033 106 2
-1203 107 2
-1202 107 2
-1020 103 2
-1157 100 0
-1193 105 2
-1040 107 2
-1002 101 1
-1015 102 2
-1006 101 1
-1034 106 2
-1035 106 2
-1016 103 2
-1007 101 1
-1036 107 2
-1018 103 2
-1026 105 2
-1027 105 2
-1183 104 2
-1038 107 2
-1025 105 2
-1037 107 2
-1021 104 2
-1019 103 2
-1005 101 1
-1179 105 2
-id parent_id level
-1002 100 0
-1004 101 1
-1005 101 1
-1009 102 2
-1025 102 2
-1018 103 2
-1023 104 2
-1025 104 2
-1029 105 2
-1030 105 2
-1031 105 2
-1032 106 2
-1033 106 2
-1034 106 2
-1204 107 2
-1203 107 2
-1021 103 2
-1158 100 0
-1194 105 2
-1041 107 2
-1003 101 1
-1016 102 2
-1007 101 1
-1035 106 2
-1036 106 2
-1017 103 2
-1008 101 1
-1037 107 2
-1019 103 2
-1027 105 2
-1028 105 2
-1184 104 2
-1039 107 2
-1026 105 2
-1038 107 2
-1022 104 2
-1020 103 2
-1006 101 1
-1180 105 2
-id parent_id level
-1009 102 2
-1025 102 2
-1016 102 2
-table type possible_keys key key_len ref rows Extra
-t1 ref level level 1 const 6 where used; Using index
-level id
-1 1004
-1 1005
-1 1003
-1 1007
-1 1008
-1 1006
-level id parent_id
-1 1004 101
-1 1005 101
-1 1003 101
-1 1007 101
-1 1008 101
-1 1006 101
-level id
-1 1003
-1 1004
-1 1005
-1 1006
-1 1007
-1 1008
-id parent_id level
-1002 100 0
-1009 102 2
-1025 102 2
-1018 103 2
-1023 104 2
-1025 104 2
-1029 105 2
-1030 105 2
-1031 105 2
-1032 106 2
-1033 106 2
-1034 106 2
-1204 107 2
-1203 107 2
-1021 103 2
-1158 100 0
-1194 105 2
-1041 107 2
-1016 102 2
-1035 106 2
-1036 106 2
-1017 103 2
-1037 107 2
-1019 103 2
-1027 105 2
-1028 105 2
-1184 104 2
-1039 107 2
-1026 105 2
-1038 107 2
-1022 104 2
-1020 103 2
-1180 105 2
-count(*)
-1
-a
-1
-2
-3
-test for rollback
-test for rollback
-n after rollback
-4 after rollback
-n after commit
-4 after commit
-5 after commit
-n after commit
-4 after commit
-5 after commit
-6 after commit
-n
-4
-5
-6
-7
-afterbegin_id afterbegin_nom
-1 first
-2 hamdouni
-afterrollback_id afterrollback_nom
-1 first
-afterautocommit0_id afterautocommit0_nom
-1 first
-3 mysql
-afterrollback_id afterrollback_nom
-1 first
-id val
-id val
-pippo 12
-id val
-ID NAME
-1 Jochen
-_userid
-marc@anyware.co.uk
-_userid
-marc@anyware.co.uk
-f1
-65
-379
-468
-469
-508
diff --git a/mysql-test/r/grant_cache.result b/mysql-test/r/grant_cache.result
new file mode 100644
index 00000000000..d236c26d71a
--- /dev/null
+++ b/mysql-test/r/grant_cache.result
@@ -0,0 +1,153 @@
+drop table if exists test.t1,mysqltest.t1,mysqltest.t2;
+reset query cache;
+flush status;
+create database if not exists mysqltest;
+create table mysqltest.t1 (a int,b int,c int);
+create table mysqltest.t2 (a int,b int,c int);
+insert into mysqltest.t1 values (1,1,1),(2,2,2);
+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;
+a
+test.t1
+select * from t1;
+a b c
+1 1 1
+2 2 2
+select a from t1;
+a
+1
+2
+select c from t1;
+c
+1
+2
+select * from t2;
+a b c
+3 3 3
+select * from mysqltest.t1,test.t1;
+a b c a
+1 1 1 test.t1
+2 2 2 test.t1
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 6
+show status like "Qcache_hits%";
+Variable_name Value
+Qcache_hits 0
+grant SELECT on mysqltest.* to mysqltest_1@localhost;
+grant SELECT on mysqltest.t1 to mysqltest_2@localhost;
+grant SELECT on test.t1 to mysqltest_2@localhost;
+grant SELECT(a) on mysqltest.t1 to mysqltest_3@localhost;
+select "user1";
+user1
+user1
+select * from t1;
+a b c
+1 1 1
+2 2 2
+select a from t1 ;
+a
+1
+2
+select c from t1;
+c
+1
+2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 6
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 3
+show status like "Qcache_not_cached";
+Variable_name Value
+Qcache_not_cached 1
+select "user2";
+user2
+user2
+select * from t1;
+a b c
+1 1 1
+2 2 2
+select a from t1;
+a
+1
+2
+select c from t1;
+c
+1
+2
+select * from mysqltest.t1,test.t1;
+a b c a
+1 1 1 test.t1
+2 2 2 test.t1
+select * from t2;
+select command denied to user: 'mysqltest_2@localhost' for table 't2'
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 6
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 7
+show status like "Qcache_not_cached";
+Variable_name Value
+Qcache_not_cached 3
+select "user3";
+user3
+user3
+select * from t1;
+select command denied to user: 'mysqltest_3@localhost' for column 'b' in table 't1'
+select a from t1;
+a
+1
+2
+select c from t1;
+select command denied to user: 'mysqltest_3@localhost' for column 'c' in table 't1'
+select * from t2;
+select command denied to user: 'mysqltest_3@localhost' for table 't2'
+select mysqltest.t1.c from test.t1,mysqltest.t1;
+select command denied to user: 'mysqltest_3@localhost' for column 'c' in table 't1'
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 6
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 7
+show status like "Qcache_not_cached";
+Variable_name Value
+Qcache_not_cached 8
+select "user4";
+user4
+user4
+select a from t1;
+No Database Selected
+select * from mysqltest.t1,test.t1;
+a b c a
+1 1 1 test.t1
+2 2 2 test.t1
+select a from mysqltest.t1;
+a
+1
+2
+select a from mysqltest.t1;
+a
+1
+2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 8
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 8
+show status like "Qcache_not_cached";
+Variable_name Value
+Qcache_not_cached 9
+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");
+delete from mysql.tables_priv where user in ("mysqltest_1","mysqltest_2","mysqltest_3");
+delete from mysql.columns_priv where user in ("mysqltest_1","mysqltest_2","mysqltest_3");
+flush privileges;
+drop table test.t1,mysqltest.t1,mysqltest.t2;
+drop database mysqltest;
diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result
index d5fcc7d85e8..2affdc1b653 100644
--- a/mysql-test/r/group_by.result
+++ b/mysql-test/r/group_by.result
@@ -1,15 +1,189 @@
+drop table if exists t1,t2;
+CREATE TABLE t1 (
+spID int(10) unsigned,
+userID int(10) unsigned,
+score smallint(5) unsigned,
+lsg char(40),
+date date
+);
+INSERT INTO t1 VALUES (1,1,1,'','0000-00-00');
+INSERT INTO t1 VALUES (2,2,2,'','0000-00-00');
+INSERT INTO t1 VALUES (2,1,1,'','0000-00-00');
+INSERT INTO t1 VALUES (3,3,3,'','0000-00-00');
+CREATE TABLE t2 (
+userID int(10) unsigned DEFAULT '0' NOT NULL auto_increment,
+niName char(15),
+passwd char(8),
+mail char(50),
+isAukt enum('N','Y') DEFAULT 'N',
+vName char(30),
+nName char(40),
+adr char(60),
+plz char(5),
+ort char(35),
+land char(20),
+PRIMARY KEY (userID)
+);
+INSERT INTO t2 VALUES (1,'name','pass','mail','Y','v','n','adr','1','1','1');
+INSERT INTO t2 VALUES (2,'name','pass','mail','Y','v','n','adr','1','1','1');
+INSERT INTO t2 VALUES (3,'name','pass','mail','Y','v','n','adr','1','1','1');
+SELECT t2.userid, MIN(t1.score) FROM t1, t2 WHERE t1.userID=t2.userID GROUP BY t2.userid;
userid MIN(t1.score)
1 1
2 2
3 3
+SELECT t2.userid, MIN(t1.score) FROM t1, t2 WHERE t1.userID=t2.userID AND t1.spID=2 GROUP BY t2.userid;
userid MIN(t1.score)
1 1
2 2
+SELECT t2.userid, MIN(t1.score+0.0) FROM t1, t2 WHERE t1.userID=t2.userID AND t1.spID=2 GROUP BY t2.userid;
userid MIN(t1.score+0.0)
1 1.0
2 2.0
+drop table test.t1,test.t2;
+CREATE TABLE t1 (
+PID int(10) unsigned DEFAULT '0' NOT NULL auto_increment,
+payDate date DEFAULT '0000-00-00' NOT NULL,
+recDate datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
+URID int(10) unsigned DEFAULT '0' NOT NULL,
+CRID int(10) unsigned DEFAULT '0' NOT NULL,
+amount int(10) unsigned DEFAULT '0' NOT NULL,
+operator int(10) unsigned,
+method enum('unknown','cash','dealer','check','card','lazy','delayed','test') DEFAULT 'unknown' NOT NULL,
+DIID int(10) unsigned,
+reason char(1) binary DEFAULT '' NOT NULL,
+code_id int(10) unsigned,
+qty mediumint(8) unsigned DEFAULT '0' NOT NULL,
+PRIMARY KEY (PID),
+KEY URID (URID),
+KEY reason (reason),
+KEY method (method),
+KEY payDate (payDate)
+);
+INSERT INTO t1 VALUES (1,'1970-01-01','1997-10-17 00:00:00',2529,1,21000,11886,'check',0,'F',16200,6);
+SELECT COUNT(P.URID),SUM(P.amount),P.method, MIN(PP.recdate+0) > 19980501000000 AS IsNew FROM t1 AS P JOIN t1 as PP WHERE P.URID = PP.URID GROUP BY method,IsNew;
+Can't group on 'IsNew'
+drop table t1;
+CREATE TABLE t1 (
+cid mediumint(9) DEFAULT '0' NOT NULL auto_increment,
+firstname varchar(32) DEFAULT '' NOT NULL,
+surname varchar(32) DEFAULT '' NOT NULL,
+PRIMARY KEY (cid)
+);
+INSERT INTO t1 VALUES (1,'That','Guy');
+INSERT INTO t1 VALUES (2,'Another','Gent');
+CREATE TABLE t2 (
+call_id mediumint(8) DEFAULT '0' NOT NULL auto_increment,
+contact_id mediumint(8) DEFAULT '0' NOT NULL,
+PRIMARY KEY (call_id),
+KEY contact_id (contact_id)
+);
+lock tables t1 read,t2 write;
+INSERT INTO t2 VALUES (10,2);
+INSERT INTO t2 VALUES (18,2);
+INSERT INTO t2 VALUES (62,2);
+INSERT INTO t2 VALUES (91,2);
+INSERT INTO t2 VALUES (92,2);
+SELECT cid, CONCAT(firstname, ' ', surname), COUNT(call_id) FROM t1 LEFT JOIN t2 ON cid=contact_id WHERE firstname like '%foo%' GROUP BY cid;
cid CONCAT(firstname, ' ', surname) COUNT(call_id)
+SELECT HIGH_PRIORITY cid, CONCAT(firstname, ' ', surname), COUNT(call_id) FROM t1 LEFT JOIN t2 ON cid=contact_id WHERE firstname like '%foo%' GROUP BY cid ORDER BY surname, firstname;
cid CONCAT(firstname, ' ', surname) COUNT(call_id)
+drop table t1,t2;
+unlock tables;
+CREATE TABLE t1 (
+bug_id mediumint(9) DEFAULT '0' NOT NULL auto_increment,
+groupset bigint(20) DEFAULT '0' NOT NULL,
+assigned_to mediumint(9) DEFAULT '0' NOT NULL,
+bug_file_loc text,
+bug_severity enum('blocker','critical','major','normal','minor','trivial','enhancement') DEFAULT 'blocker' NOT NULL,
+bug_status enum('NEW','ASSIGNED','REOPENED','RESOLVED','VERIFIED','CLOSED') DEFAULT 'NEW' NOT NULL,
+creation_ts datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
+delta_ts timestamp(14),
+short_desc mediumtext,
+long_desc mediumtext,
+op_sys enum('All','Windows 3.1','Windows 95','Windows 98','Windows NT','Windows 2000','Linux','other') DEFAULT 'All' NOT NULL,
+priority enum('P1','P2','P3','P4','P5') DEFAULT 'P1' NOT NULL,
+product varchar(64) DEFAULT '' NOT NULL,
+rep_platform enum('All','PC','VTD-8','Other'),
+reporter mediumint(9) DEFAULT '0' NOT NULL,
+version varchar(16) DEFAULT '' NOT NULL,
+component varchar(50) DEFAULT '' NOT NULL,
+resolution enum('','FIXED','INVALID','WONTFIX','LATER','REMIND','DUPLICATE','WORKSFORME') DEFAULT '' NOT NULL,
+target_milestone varchar(20) DEFAULT '' NOT NULL,
+qa_contact mediumint(9) DEFAULT '0' NOT NULL,
+status_whiteboard mediumtext NOT NULL,
+votes mediumint(9) DEFAULT '0' NOT NULL,
+PRIMARY KEY (bug_id),
+KEY assigned_to (assigned_to),
+KEY creation_ts (creation_ts),
+KEY delta_ts (delta_ts),
+KEY bug_severity (bug_severity),
+KEY bug_status (bug_status),
+KEY op_sys (op_sys),
+KEY priority (priority),
+KEY product (product),
+KEY reporter (reporter),
+KEY version (version),
+KEY component (component),
+KEY resolution (resolution),
+KEY target_milestone (target_milestone),
+KEY qa_contact (qa_contact),
+KEY votes (votes)
+);
+INSERT INTO t1 VALUES (1,0,0,'','normal','','2000-02-10 09:25:12',20000321114747,'','','Linux','P1','TestProduct','PC',3,'other','TestComponent','','M1',0,'',0);
+INSERT INTO t1 VALUES (9,0,0,'','enhancement','','2000-03-10 11:49:36',20000321114747,'','','All','P5','AAAAA','PC',3,'2.00 CD - Pre','BBBBBBBBBBBBB - conversion','','',0,'',0);
+INSERT INTO t1 VALUES (10,0,0,'','enhancement','','2000-03-10 18:10:16',20000321114747,'','','All','P4','AAAAA','PC',3,'2.00 CD - Pre','BBBBBBBBBBBBB - conversion','','',0,'',0);
+INSERT INTO t1 VALUES (7,0,0,'','critical','','2000-03-09 10:50:21',20000321114747,'','','All','P1','AAAAA','PC',3,'2.00 CD - Pre','BBBBBBBBBBBBB - generic','','',0,'',0);
+INSERT INTO t1 VALUES (6,0,0,'','normal','','2000-03-09 10:42:44',20000321114747,'','','All','P2','AAAAA','PC',3,'2.00 CD - Pre','kkkkkkkkkkk lllllllllll','','',0,'',0);
+INSERT INTO t1 VALUES (8,0,0,'','major','','2000-03-09 11:32:14',20000321114747,'','','All','P3','AAAAA','PC',3,'2.00 CD - Pre','kkkkkkkkkkk lllllllllll','','',0,'',0);
+INSERT INTO t1 VALUES (5,0,0,'','enhancement','','2000-03-09 10:38:59',20000321114747,'','','All','P5','CCC/CCCCCC','PC',5,'7.00','Administration','','',0,'',0);
+INSERT INTO t1 VALUES (4,0,0,'','normal','','2000-03-08 18:32:14',20000321114747,'','','other','P2','TestProduct','Other',3,'other','TestComponent2','','',0,'',0);
+INSERT INTO t1 VALUES (3,0,0,'','normal','','2000-03-08 18:30:52',20000321114747,'','','other','P2','TestProduct','Other',3,'other','TestComponent','','',0,'',0);
+INSERT INTO t1 VALUES (2,0,0,'','enhancement','','2000-03-08 18:24:51',20000321114747,'','','All','P2','TestProduct','Other',4,'other','TestComponent2','','',0,'',0);
+INSERT INTO t1 VALUES (11,0,0,'','blocker','','2000-03-13 09:43:41',20000321114747,'','','All','P2','CCC/CCCCCC','PC',5,'7.00','DDDDDDDDD','','',0,'',0);
+INSERT INTO t1 VALUES (12,0,0,'','normal','','2000-03-13 16:14:31',20000321114747,'','','All','P2','AAAAA','PC',3,'2.00 CD - Pre','kkkkkkkkkkk lllllllllll','','',0,'',0);
+INSERT INTO t1 VALUES (13,0,0,'','normal','','2000-03-15 16:20:44',20000321114747,'','','other','P2','TestProduct','Other',3,'other','TestComponent','','',0,'',0);
+INSERT INTO t1 VALUES (14,0,0,'','blocker','','2000-03-15 18:13:47',20000321114747,'','','All','P1','AAAAA','PC',3,'2.00 CD - Pre','BBBBBBBBBBBBB - generic','','',0,'',0);
+INSERT INTO t1 VALUES (15,0,0,'','minor','','2000-03-16 18:03:28',20000321114747,'','','All','P2','CCC/CCCCCC','Other',5,'7.00','DDDDDDDDD','','',0,'',0);
+INSERT INTO t1 VALUES (16,0,0,'','normal','','2000-03-16 18:33:41',20000321114747,'','','All','P2','CCC/CCCCCC','Other',5,'7.00','Administration','','',0,'',0);
+INSERT INTO t1 VALUES (17,0,0,'','normal','','2000-03-16 18:34:18',20000321114747,'','','All','P2','CCC/CCCCCC','Other',5,'7.00','Administration','','',0,'',0);
+INSERT INTO t1 VALUES (18,0,0,'','normal','','2000-03-16 18:34:56',20000321114747,'','','All','P2','CCC/CCCCCC','Other',5,'7.00','Administration','','',0,'',0);
+INSERT INTO t1 VALUES (19,0,0,'','enhancement','','2000-03-16 18:35:34',20000321114747,'','','All','P2','CCC/CCCCCC','Other',5,'7.00','Administration','','',0,'',0);
+INSERT INTO t1 VALUES (20,0,0,'','enhancement','','2000-03-16 18:36:23',20000321114747,'','','All','P2','CCC/CCCCCC','Other',5,'7.00','Administration','','',0,'',0);
+INSERT INTO t1 VALUES (21,0,0,'','enhancement','','2000-03-16 18:37:23',20000321114747,'','','All','P2','CCC/CCCCCC','Other',5,'7.00','Administration','','',0,'',0);
+INSERT INTO t1 VALUES (22,0,0,'','enhancement','','2000-03-16 18:38:16',20000321114747,'','','All','P2','CCC/CCCCCC','Other',5,'7.00','Administration','','',0,'',0);
+INSERT INTO t1 VALUES (23,0,0,'','normal','','2000-03-16 18:58:12',20000321114747,'','','All','P2','CCC/CCCCCC','Other',5,'7.00','DDDDDDDDD','','',0,'',0);
+INSERT INTO t1 VALUES (24,0,0,'','normal','','2000-03-17 11:08:10',20000321114747,'','','All','P2','AAAAAAAA-AAA','PC',3,'2.8','Web Interface','','',0,'',0);
+INSERT INTO t1 VALUES (25,0,0,'','normal','','2000-03-17 11:10:45',20000321114747,'','','All','P2','AAAAAAAA-AAA','PC',3,'2.8','Web Interface','','',0,'',0);
+INSERT INTO t1 VALUES (26,0,0,'','normal','','2000-03-17 11:15:47',20000321114747,'','','All','P2','AAAAAAAA-AAA','PC',3,'2.8','Web Interface','','',0,'',0);
+INSERT INTO t1 VALUES (27,0,0,'','normal','','2000-03-17 17:45:41',20000321114747,'','','All','P2','CCC/CCCCCC','PC',5,'7.00','DDDDDDDDD','','',0,'',0);
+INSERT INTO t1 VALUES (28,0,0,'','normal','','2000-03-20 09:51:45',20000321114747,'','','Windows NT','P2','TestProduct','PC',8,'other','TestComponent','','',0,'',0);
+INSERT INTO t1 VALUES (29,0,0,'','normal','','2000-03-20 11:15:09',20000321114747,'','','All','P5','AAAAAAAA-AAA','PC',3,'2.8','Web Interface','','',0,'',0);
+CREATE TABLE t2 (
+value tinytext,
+program varchar(64),
+initialowner tinytext NOT NULL,
+initialqacontact tinytext NOT NULL,
+description mediumtext NOT NULL
+);
+INSERT INTO t2 VALUES ('TestComponent','TestProduct','id0001','','');
+INSERT INTO t2 VALUES ('BBBBBBBBBBBBB - conversion','AAAAA','id0001','','');
+INSERT INTO t2 VALUES ('BBBBBBBBBBBBB - generic','AAAAA','id0001','','');
+INSERT INTO t2 VALUES ('TestComponent2','TestProduct','id0001','','');
+INSERT INTO t2 VALUES ('BBBBBBBBBBBBB - eeeeeeeee','AAAAA','id0001','','');
+INSERT INTO t2 VALUES ('kkkkkkkkkkk lllllllllll','AAAAA','id0001','','');
+INSERT INTO t2 VALUES ('Test Procedures','AAAAA','id0001','','');
+INSERT INTO t2 VALUES ('Documentation','AAAAA','id0003','','');
+INSERT INTO t2 VALUES ('DDDDDDDDD','CCC/CCCCCC','id0002','','');
+INSERT INTO t2 VALUES ('Eeeeeeee Lite','CCC/CCCCCC','id0002','','');
+INSERT INTO t2 VALUES ('Eeeeeeee Full','CCC/CCCCCC','id0002','','');
+INSERT INTO t2 VALUES ('Administration','CCC/CCCCCC','id0002','','');
+INSERT INTO t2 VALUES ('Distribution','CCC/CCCCCC','id0002','','');
+INSERT INTO t2 VALUES ('Setup','CCC/CCCCCC','id0002','','');
+INSERT INTO t2 VALUES ('Unspecified','CCC/CCCCCC','id0002','','');
+INSERT INTO t2 VALUES ('Web Interface','AAAAAAAA-AAA','id0001','','');
+INSERT INTO t2 VALUES ('Host communication','AAAAA','id0001','','');
+select value,description,bug_id from t2 left join t1 on t2.program=t1.product and t2.value=t1.component where program="AAAAA";
value description bug_id
BBBBBBBBBBBBB - conversion 9
BBBBBBBBBBBBB - conversion 10
@@ -22,6 +196,7 @@ kkkkkkkkkkk lllllllllll 12
Test Procedures NULL
Documentation NULL
Host communication NULL
+select value,description,COUNT(bug_id) from t2 left join t1 on t2.program=t1.product and t2.value=t1.component where program="AAAAA" group by value;
value description COUNT(bug_id)
BBBBBBBBBBBBB - conversion 2
BBBBBBBBBBBBB - eeeeeeeee 0
@@ -30,37 +205,171 @@ Documentation 0
Host communication 0
kkkkkkkkkkk lllllllllll 3
Test Procedures 0
+drop table t1,t2;
+create table t1 (foo int);
+insert into t1 values (1);
+select 1+1, "a",count(*) from t1 where foo in (2);
1+1 a count(*)
2 a 0
+insert into t1 values (1);
+select 1+1,"a",count(*) from t1 where foo in (2);
1+1 a count(*)
2 a 0
+drop table t1;
+CREATE TABLE t1 (
+spID int(10) unsigned,
+userID int(10) unsigned,
+score smallint(5) unsigned,
+key (spid),
+key (score)
+);
+INSERT INTO t1 VALUES (1,1,1),(2,2,2),(2,1,1),(3,3,3),(4,3,3),(5,3,3);
+explain select userid,count(*) from t1 group by userid desc;
table type possible_keys key key_len ref rows Extra
-t1 ALL NULL NULL NULL NULL 6 Using temporary
+t1 ALL NULL NULL NULL NULL 6 Using temporary; Using filesort
+select userid,count(*) from t1 group by userid desc;
userid count(*)
3 3
2 1
1 2
+explain select spid,count(*) from t1 where spid between 1 and 2 group by spid desc;
table type possible_keys key key_len ref rows Extra
-t1 range spID spID 5 NULL 2 where used; Using index; Using temporary
+t1 range spID spID 5 NULL 2 where used; Using index
+explain select spid,count(*) from t1 where spid between 1 and 2 group by spid;
table type possible_keys key key_len ref rows Extra
t1 range spID spID 5 NULL 2 where used; Using index
+select spid,count(*) from t1 where spid between 1 and 2 group by spid;
spid count(*)
1 1
2 2
+select spid,count(*) from t1 where spid between 1 and 2 group by spid desc;
spid count(*)
2 2
1 1
+explain select sql_big_result spid,sum(userid) from t1 group by spid desc;
table type possible_keys key key_len ref rows Extra
t1 ALL NULL NULL NULL NULL 6 Using filesort
+select sql_big_result spid,sum(userid) from t1 group by spid desc;
spid sum(userid)
5 3
4 3
3 3
2 3
1 1
+explain select sql_big_result score,count(*) from t1 group by score desc;
table type possible_keys key key_len ref rows Extra
t1 index NULL score 3 NULL 6 Using index
+select sql_big_result score,count(*) from t1 group by score desc;
score count(*)
3 3
2 1
1 2
+drop table t1;
+CREATE TABLE t1 (a char(1));
+INSERT INTO t1 VALUES ('A'),('B'),('A'),('B'),('A'),('B'),(NULL),('a'),('b'),(NULL),('A'),('B'),(NULL);
+SELECT a FROM t1 GROUP BY a;
+a
+NULL
+A
+B
+SELECT a,count(*) FROM t1 GROUP BY a;
+a count(*)
+NULL 3
+A 5
+B 5
+SELECT a FROM t1 GROUP BY binary a;
+a
+NULL
+A
+B
+a
+b
+SELECT a,count(*) FROM t1 GROUP BY binary a;
+a count(*)
+NULL 3
+A 4
+B 4
+a 1
+b 1
+SELECT binary a FROM t1 GROUP BY 1;
+binary a
+NULL
+A
+B
+a
+b
+SELECT binary a,count(*) FROM t1 GROUP BY 1;
+binary a count(*)
+NULL 3
+A 4
+B 4
+a 1
+b 1
+SET SQL_BIG_TABLES=1;
+SELECT a FROM t1 GROUP BY a;
+a
+NULL
+A
+B
+SELECT a,count(*) FROM t1 GROUP BY a;
+a count(*)
+NULL 3
+A 5
+B 5
+SELECT a FROM t1 GROUP BY binary a;
+a
+NULL
+A
+B
+a
+b
+SELECT a,count(*) FROM t1 GROUP BY binary a;
+a count(*)
+NULL 3
+A 4
+B 4
+a 1
+b 1
+SELECT binary a FROM t1 GROUP BY 1;
+binary a
+NULL
+A
+B
+a
+b
+SELECT binary a,count(*) FROM t1 GROUP BY 1;
+binary a count(*)
+NULL 3
+A 4
+B 4
+a 1
+b 1
+SET SQL_BIG_TABLES=0;
+drop table t1;
+CREATE TABLE t1 (
+`a` char(193) default NULL,
+`b` char(63) default NULL
+);
+INSERT INTO t1 VALUES ('abc','def'),('hij','klm');
+SELECT CONCAT(a, b) FROM t1 GROUP BY 1;
+CONCAT(a, b)
+abcdef
+hijklm
+SELECT CONCAT(a, b),count(*) FROM t1 GROUP BY 1;
+CONCAT(a, b) count(*)
+abcdef 1
+hijklm 1
+SELECT CONCAT(a, b),count(distinct a) FROM t1 GROUP BY 1;
+CONCAT(a, b) count(distinct a)
+abcdef 1
+hijklm 1
+SELECT 1 FROM t1 GROUP BY CONCAT(a, b);
+1
+1
+1
+INSERT INTO t1 values ('hij','klm');
+SELECT CONCAT(a, b),count(*) FROM t1 GROUP BY 1;
+CONCAT(a, b) count(*)
+abcdef 1
+hijklm 2
+DROP TABLE t1;
diff --git a/mysql-test/r/handler.result b/mysql-test/r/handler.result
new file mode 100644
index 00000000000..d495dde75bf
--- /dev/null
+++ b/mysql-test/r/handler.result
@@ -0,0 +1,139 @@
+drop table if exists t1;
+create table t1 (a int, b char(10), key a(a), key b(a,b));
+insert into t1 values
+(17,"ddd"),(18,"eee"),(19,"fff"),(19,"yyy"),
+(14,"aaa"),(15,"bbb"),(16,"ccc"),(16,"xxx"),
+(20,"ggg"),(21,"hhh"),(22,"iii");
+handler t1 open as t2;
+handler t2 read a first;
+a b
+14 aaa
+handler t2 read a next;
+a b
+15 bbb
+handler t2 read a next;
+a b
+16 ccc
+handler t2 read a prev;
+a b
+15 bbb
+handler t2 read a last;
+a b
+22 iii
+handler t2 read a prev;
+a b
+21 hhh
+handler t2 read a prev;
+a b
+20 ggg
+handler t2 read a first;
+a b
+14 aaa
+handler t2 read a prev;
+a b
+handler t2 read a last;
+a b
+22 iii
+handler t2 read a prev;
+a b
+21 hhh
+handler t2 read a next;
+a b
+22 iii
+handler t2 read a next;
+a b
+handler t2 read a=(15);
+a b
+15 bbb
+handler t2 read a=(16);
+a b
+16 ccc
+handler t2 read a=(19,"fff");
+Too many key parts specified. Max 1 parts allowed
+handler t2 read b=(19,"fff");
+a b
+19 fff
+handler t2 read b=(19,"yyy");
+a b
+19 yyy
+handler t2 read b=(19);
+a b
+19 fff
+handler t1 read a last;
+Unknown table 't1' in HANDLER
+handler t2 read a=(11);
+a b
+handler t2 read a>=(11);
+a b
+14 aaa
+handler t2 read a=(18);
+a b
+18 eee
+handler t2 read a>=(18);
+a b
+18 eee
+handler t2 read a>(18);
+a b
+19 fff
+handler t2 read a<=(18);
+a b
+18 eee
+handler t2 read a<(18);
+a b
+17 ddd
+handler t2 read a first limit 5;
+a b
+14 aaa
+15 bbb
+16 ccc
+16 xxx
+17 ddd
+handler t2 read a next limit 3;
+a b
+18 eee
+19 fff
+19 yyy
+handler t2 read a prev limit 10;
+a b
+19 fff
+18 eee
+17 ddd
+16 xxx
+16 ccc
+15 bbb
+14 aaa
+handler t2 read a>=(16) limit 4;
+a b
+16 ccc
+16 xxx
+17 ddd
+18 eee
+handler t2 read a>=(16) limit 2,2;
+a b
+17 ddd
+18 eee
+handler t2 read a last limit 3;
+a b
+22 iii
+21 hhh
+20 ggg
+handler t2 read a=(19);
+a b
+19 fff
+handler t2 read a=(19) where b="yyy";
+a b
+19 yyy
+handler t2 read first;
+a b
+17 ddd
+handler t2 read next;
+a b
+18 eee
+alter table t1 type=MyISAM;
+handler t2 read next;
+a b
+19 fff
+handler t2 read last;
+You have an error in your SQL syntax near '' at line 1
+handler t2 close;
+drop table if exists t1;
diff --git a/mysql-test/r/have_openssl.require b/mysql-test/r/have_openssl.require
new file mode 100644
index 00000000000..dae48a472b5
--- /dev/null
+++ b/mysql-test/r/have_openssl.require
@@ -0,0 +1,2 @@
+Variable_name Value
+have_openssl YES
diff --git a/mysql-test/r/have_openssl_1.require b/mysql-test/r/have_openssl_1.require
new file mode 100644
index 00000000000..dae48a472b5
--- /dev/null
+++ b/mysql-test/r/have_openssl_1.require
@@ -0,0 +1,2 @@
+Variable_name Value
+have_openssl YES
diff --git a/mysql-test/r/have_gemini.require b/mysql-test/r/have_openssl_2.require
index 0ffe0e40d3b..09a65d7d9bc 100644
--- a/mysql-test/r/have_gemini.require
+++ b/mysql-test/r/have_openssl_2.require
@@ -1,2 +1,2 @@
Variable_name Value
-have_gemini YES
+jkhjkhfs
diff --git a/mysql-test/r/have_symlink.require b/mysql-test/r/have_symlink.require
new file mode 100644
index 00000000000..55ad9437034
--- /dev/null
+++ b/mysql-test/r/have_symlink.require
@@ -0,0 +1,2 @@
+Variable_name Value
+have_symlink YES
diff --git a/mysql-test/r/having.result b/mysql-test/r/having.result
index 69943c505f0..a33ce457176 100644
--- a/mysql-test/r/having.result
+++ b/mysql-test/r/having.result
@@ -1,6 +1,65 @@
+drop table if exists t1,t2;
+create table t1 (a int);
+select count(a) as b from t1 where a=0 having b > 0;
b
+insert into t1 values (null);
+select count(a) as b from t1 where a=0 having b > 0;
b
+select count(a) as b from t1 where a=0 having b >=0;
b
0
+drop table t1;
+CREATE TABLE t1 (
+raw_id int(10) NOT NULL default '0',
+chr_start int(10) NOT NULL default '0',
+chr_end int(10) NOT NULL default '0',
+raw_start int(10) NOT NULL default '0',
+raw_end int(10) NOT NULL default '0',
+raw_ori int(2) NOT NULL default '0'
+);
+INSERT INTO t1 VALUES (469713,1,164123,1,164123,1),(317330,164124,317193,101,153170,1),(469434,317194,375620,101,58527,1),(591816,375621,484273,1,108653,1),(591807,484274,534671,91,50488,1),(318885,534672,649362,101,114791,1),(318728,649363,775520,102,126259,1),(336829,775521,813997,101,38577,1),(317740,813998,953227,101,139330,1),(1,813998,953227,101,139330,1);
+CREATE TABLE t2 (
+id int(10) unsigned NOT NULL default '0',
+contig_id int(10) unsigned NOT NULL default '0',
+seq_start int(10) NOT NULL default '0',
+seq_end int(10) NOT NULL default '0',
+strand tinyint(2) NOT NULL default '0',
+KEY id (id)
+);
+INSERT INTO t2 VALUES (133195,469713,61327,61384,1),(133196,469713,64113,64387,1),(133197,1,1,1,0),(133197,1,1,1,-2);
+SELECT e.id,
+MIN( IF(sgp.raw_ori=1,
+(e.seq_start+sgp.chr_start-sgp.raw_start),
+(sgp.chr_start+sgp.raw_end-e.seq_end))) as start,
+MAX( IF(sgp.raw_ori=1,
+(e.seq_end+sgp.chr_start-sgp.raw_start),
+(sgp.chr_start+sgp.raw_end-e.seq_start))) as end,
+AVG(IF (sgp.raw_ori=1,e.strand,(-e.strand))) as chr_strand
+FROM t1 sgp,
+t2 e
+WHERE sgp.raw_id=e.contig_id
+GROUP BY e.id
+HAVING chr_strand= -1 and end >= 0
+AND start <= 999660;
id start end chr_strand
133197 813898 813898 -1.0000
+drop table t1,t2;
+CREATE TABLE t1 (Fld1 int(11) default NULL,Fld2 int(11) default NULL);
+INSERT INTO t1 VALUES (1,10),(1,20),(2,NULL),(2,NULL),(3,50);
+select Fld1, max(Fld2) as q from t1 group by Fld1 having q is not null;
+Fld1 q
+1 20
+3 50
+select Fld1, max(Fld2) from t1 group by Fld1 having max(Fld2) is not null;
+Fld1 max(Fld2)
+1 20
+3 50
+select Fld1, max(Fld2) from t1 group by Fld1 having avg(Fld2) is not null;
+Fld1 max(Fld2)
+1 20
+3 50
+select Fld1, max(Fld2) from t1 group by Fld1 having std(Fld2) is not null;
+Fld1 max(Fld2)
+1 20
+3 50
+drop table t1;
diff --git a/mysql-test/r/heap.result b/mysql-test/r/heap.result
index d3d16128ebd..13f452e26d8 100644
--- a/mysql-test/r/heap.result
+++ b/mysql-test/r/heap.result
@@ -1,41 +1,81 @@
-Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Comment
-t1 0 PRIMARY 1 a NULL NULL NULL NULL
+drop table if exists t1;
+create table t1 (a int not null,b int not null, primary key (a)) type=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;
+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 a NULL NULL NULL NULL HASH
+select * from t1;
a b
2 2
3 3
4 4
+select * from t1 where a=4;
a b
4 4
+update t1 set b=5 where a=4;
+update t1 set b=b+1 where a>=3;
+replace t1 values (3,3);
+select * from t1;
a b
2 2
3 3
4 6
+alter table t1 add c int not null, add key (c,a);
+drop table t1;
+create table t1 (a int not null,b int not null, primary key (a)) type=heap comment="testing heaps";
+insert into t1 values(1,1),(2,2),(3,3),(4,4);
+delete from t1 where a > 0;
+select * from t1;
+a b
+drop table t1;
+create table t1 (a int not null,b int not null, primary key (a)) type=heap comment="testing heaps";
+insert into t1 values(1,1),(2,2),(3,3),(4,4);
+alter table t1 modify a int not null auto_increment, type=myisam, comment="new myisam table";
+select * from t1;
a b
1 1
2 2
3 3
4 4
+drop table t1;
+create table t1 (a int not null) type=heap;
+insert into t1 values (869751),(736494),(226312),(802616);
+select * from t1 where a > 736494;
a
869751
802616
+alter table t1 add unique uniq_id(a);
+select * from t1 where a > 736494;
a
869751
802616
+select * from t1 where a = 736494;
a
736494
+select * from t1 where a=869751 or a=736494;
a
736494
869751
+select * from t1 where a in (869751,736494,226312,802616);
a
226312
736494
802616
869751
+alter table t1 type=myisam;
+explain select * from t1 where a in (869751,736494,226312,802616);
table type possible_keys key key_len ref rows Extra
t1 range uniq_id uniq_id 4 NULL 4 where used; Using index
+drop table t1;
+create table t1 (x int not null, y int not null, key x(x), unique y(y))
+type=heap;
+insert into t1 values (1,1),(2,2),(1,3),(2,4),(2,5),(2,6);
+select * from t1 where x=1;
x y
1 3
1 1
+select * from t1,t1 as t2 where t1.x=t2.y;
x y x y
1 1 1 1
2 2 2 2
@@ -43,11 +83,20 @@ x y x y
2 4 2 2
2 5 2 2
2 6 2 2
+explain select * from t1,t1 as t2 where t1.x=t2.y;
table type possible_keys key key_len ref rows Extra
t1 ALL x NULL NULL NULL 6
t2 eq_ref y y 4 t1.x 1
+drop table t1;
+create table t1 (a int) type=heap;
+insert into t1 values(1);
+select max(a) from t1;
max(a)
1
+drop table t1;
+CREATE TABLE t1 ( a int not null default 0, b int not null default 0, key(a), key(b) ) TYPE=HEAP;
+insert into t1 values(1,1),(1,2),(2,3),(1,3),(1,4),(1,5),(1,6);
+select * from t1 where a=1;
a b
1 6
1 5
@@ -55,6 +104,8 @@ a b
1 3
1 2
1 1
+insert into t1 values(1,1),(1,2),(2,3),(1,3),(1,4),(1,5),(1,6);
+select * from t1 where a=1;
a b
1 6
1 5
@@ -68,20 +119,87 @@ a b
1 3
1 2
1 1
+drop table t1;
+create table t1 (id int unsigned not null, primary key (id)) type=HEAP;
+insert into t1 values(1);
+select max(id) from t1;
max(id)
1
+insert into t1 values(2);
+select max(id) from t1;
max(id)
2
+replace into t1 values(1);
+drop table t1;
+create table t1 (n int) type=heap;
+drop table t1;
+create table t1 (n int) type=heap;
+drop table if exists t1;
+CREATE table t1(f1 int not null,f2 char(20) not
+null,index(f2)) type=heap;
+INSERT into t1 set f1=12,f2="bill";
+INSERT into t1 set f1=13,f2="bill";
+INSERT into t1 set f1=14,f2="bill";
+INSERT into t1 set f1=15,f2="bill";
+INSERT into t1 set f1=16,f2="ted";
+INSERT into t1 set f1=12,f2="ted";
+INSERT into t1 set f1=12,f2="ted";
+INSERT into t1 set f1=12,f2="ted";
+INSERT into t1 set f1=12,f2="ted";
+delete from t1 where f2="bill";
+select * from t1;
f1 f2
16 ted
12 ted
12 ted
12 ted
12 ted
+drop table t1;
+create table t1 (btn char(10) not null, key(btn)) type=heap;
+insert into t1 values ("hello"),("hello"),("hello"),("hello"),("hello"),("a"),("b"),("c"),("d"),("e"),("f"),("g"),("h"),("i");
+explain select * from t1 where btn like "q%";
table type possible_keys key key_len ref rows Extra
t1 ALL btn NULL NULL NULL 14 where used
+select * from t1 where btn like "q%";
btn
+alter table t1 add column new_col char(1) not null, add key (btn,new_col), drop key btn;
+update t1 set new_col=btn;
+explain select * from t1 where btn="a";
table type possible_keys key key_len ref rows Extra
t1 ALL btn NULL NULL NULL 14 where used
+explain select * from t1 where btn="a" and new_col="a";
table type possible_keys key key_len ref rows Extra
t1 ref btn btn 11 const,const 10 where used
+drop table t1;
+CREATE TABLE t1 (
+a int default NULL,
+b int default NULL,
+KEY a (a),
+UNIQUE b (b)
+) type=heap;
+INSERT INTO t1 VALUES (NULL,99),(99,NULL),(1,1),(2,2),(1,3);
+SELECT * FROM t1 WHERE a=NULL;
+a b
+explain SELECT * FROM t1 WHERE a IS NULL;
+table type possible_keys key key_len ref rows Extra
+t1 ref a a 5 const 10 where used
+SELECT * FROM t1 WHERE a<=>NULL;
+a b
+NULL 99
+SELECT * FROM t1 WHERE b=NULL;
+a b
+explain SELECT * FROM t1 WHERE b IS NULL;
+table type possible_keys key key_len ref rows Extra
+t1 ref b b 5 const 1 where used
+SELECT * FROM t1 WHERE b<=>NULL;
+a b
+99 NULL
+INSERT INTO t1 VALUES (1,3);
+Duplicate entry '3' for key 1
+DROP TABLE t1;
+CREATE TABLE t1 (a int not null, primary key(a)) type=heap;
+INSERT into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11);
+DELETE from t1 where a < 100;
+SELECT * from t1;
+a
+DROP TABLE t1;
diff --git a/mysql-test/r/identity.result b/mysql-test/r/identity.result
index 45968248d26..39123e9c127 100644
--- a/mysql-test/r/identity.result
+++ b/mysql-test/r/identity.result
@@ -1,4 +1,6 @@
+select last_insert_id(345);
last_insert_id(345)
345
+select @@IDENTITY,last_insert_id();
@@IDENTITY last_insert_id()
345 345
diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result
index d13347b7903..1c5e4165885 100644
--- a/mysql-test/r/innodb.result
+++ b/mysql-test/r/innodb.result
@@ -1,3 +1,7 @@
+drop table if exists t1,t2;
+create table t1 (id int unsigned not null auto_increment, code tinyint unsigned not null, name char(20) not null, primary key (id), key (code), unique (name)) type=innodb;
+insert into t1 (code, name) values (1, 'Tim'), (1, 'Monty'), (2, 'David'), (2, 'Erik'), (3, 'Sasha'), (3, 'Jeremy'), (4, 'Matt');
+select id, code, name from t1 order by id;
id code name
1 1 Tim
2 1 Monty
@@ -6,6 +10,8 @@ id code name
5 3 Sasha
6 3 Jeremy
7 4 Matt
+update ignore t1 set id = 8, name = 'Sinisa' where id < 3;
+select id, code, name from t1 order by id;
id code name
2 1 Monty
3 2 David
@@ -14,6 +20,8 @@ id code name
6 3 Jeremy
7 4 Matt
8 1 Sinisa
+update ignore t1 set id = id + 10, name = 'Ralph' where id < 4;
+select id, code, name from t1 order by id;
id code name
3 2 David
4 2 Erik
@@ -22,10 +30,26 @@ id code name
7 4 Matt
8 1 Sinisa
12 1 Ralph
+drop table t1;
+CREATE TABLE t1 (
+id int(11) NOT NULL auto_increment,
+parent_id int(11) DEFAULT '0' NOT NULL,
+level tinyint(4) DEFAULT '0' NOT NULL,
+PRIMARY KEY (id),
+KEY parent_id (parent_id),
+KEY level (level)
+) type=innodb;
+INSERT INTO t1 VALUES (1,0,0),(3,1,1),(4,1,1),(8,2,2),(9,2,2),(17,3,2),(22,4,2),(24,4,2),(28,5,2),(29,5,2),(30,5,2),(31,6,2),(32,6,2),(33,6,2),(203,7,2),(202,7,2),(20,3,2),(157,0,0),(193,5,2),(40,7,2),(2,1,1),(15,2,2),(6,1,1),(34,6,2),(35,6,2),(16,3,2),(7,1,1),(36,7,2),(18,3,2),(26,5,2),(27,5,2),(183,4,2),(38,7,2),(25,5,2),(37,7,2),(21,4,2),(19,3,2),(5,1,1),(179,5,2);
+update t1 set parent_id=parent_id+100;
+select * from t1 where parent_id=102;
id parent_id level
8 102 2
9 102 2
15 102 2
+update t1 set id=id+1000;
+update t1 set id=1024 where id=1009;
+Got one of the listed errors
+select * from t1;
id parent_id level
1001 100 0
1002 101 1
@@ -66,6 +90,8 @@ id parent_id level
1193 105 2
1202 107 2
1203 107 2
+update ignore t1 set id=id+1;
+select * from t1;
id parent_id level
1001 100 0
1002 101 1
@@ -106,16 +132,22 @@ id parent_id level
1194 105 2
1202 107 2
1204 107 2
+update ignore t1 set id=1023 where id=1010;
+select * from t1 where parent_id=102;
id parent_id level
1008 102 2
1010 102 2
1015 102 2
+explain select level from t1 where level=1;
table type possible_keys key key_len ref rows Extra
t1 ref level level 1 const 12 where used; Using index
+explain select level,id from t1 where level=1;
table type possible_keys key key_len ref rows Extra
t1 ref level level 1 const 12 where used; Using index
+explain select level,id,parent_id from t1 where level=1;
table type possible_keys key key_len ref rows Extra
t1 ref level level 1 const 12 where used
+select level,id from t1 where level=1;
level id
1 1002
1 1003
@@ -123,6 +155,7 @@ level id
1 1005
1 1006
1 1007
+select level,id,parent_id from t1 where level=1;
level id parent_id
1 1002 101
1 1003 101
@@ -130,142 +163,350 @@ level id parent_id
1 1005 101
1 1006 101
1 1007 101
+optimize table t1;
Table Op Msg_type Msg_text
test.t1 optimize error The handler for the table doesn't support check/repair
-Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Comment
-t1 0 PRIMARY 1 id A 87 NULL NULL
-t1 1 parent_id 1 parent_id A 43 NULL NULL
-t1 1 level 1 level A 8 NULL NULL
+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 id A 87 NULL NULL BTREE
+t1 1 parent_id 1 parent_id A 43 NULL NULL BTREE
+t1 1 level 1 level A 8 NULL NULL BTREE
+drop table t1;
+CREATE TABLE t1 (
+gesuchnr int(11) DEFAULT '0' NOT NULL,
+benutzer_id int(11) DEFAULT '0' NOT NULL,
+PRIMARY KEY (gesuchnr,benutzer_id)
+) type=innodb;
+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);
+select * from t1;
gesuchnr benutzer_id
1 1
2 1
+drop table t1;
+create table t1 (a int) type=innodb;
+insert into t1 values (1), (2);
+optimize table t1;
Table Op Msg_type Msg_text
test.t1 optimize error The handler for the table doesn't support check/repair
+delete from t1 where a = 1;
+select * from t1;
a
2
+check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
+drop table t1;
+create table t1 (a int,b varchar(20)) type=innodb;
+insert into t1 values (1,""), (2,"testing");
+delete from t1 where a = 1;
+select * from t1;
a b
2 testing
+create index skr on t1 (a);
+insert into t1 values (3,""), (4,"testing");
+analyze table t1;
Table Op Msg_type Msg_text
test.t1 analyze error The handler for the table doesn't support check/repair
-Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Comment
-t1 1 skr 1 a A 3 NULL NULL
+show keys from t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 1 skr 1 a A 3 NULL NULL YES BTREE
+drop table t1;
+create table t1 (a int,b varchar(20),key(a)) type=innodb;
+insert into t1 values (1,""), (2,"testing");
+select * from t1 where a = 1;
a b
1
+drop table t1;
+create table t1 (n int not null primary key) type=innodb;
+set autocommit=0;
+insert into t1 values (4);
+rollback;
+select n, "after rollback" from t1;
n after rollback
+insert into t1 values (4);
+commit;
+select n, "after commit" from t1;
n after commit
4 after commit
+commit;
+insert into t1 values (5);
+insert into t1 values (4);
+Duplicate entry '4' for key 1
+commit;
+select n, "after commit" from t1;
n after commit
4 after commit
5 after commit
+set autocommit=1;
+insert into t1 values (6);
+insert into t1 values (4);
+Duplicate entry '4' for key 1
+select n from t1;
n
4
5
6
+rollback;
+drop table t1;
+create table t1 ( id int NOT NULL PRIMARY KEY, nom varchar(64)) type=innodb;
+begin;
+insert into t1 values(1,'hamdouni');
+select id as afterbegin_id,nom as afterbegin_nom from t1;
afterbegin_id afterbegin_nom
1 hamdouni
+rollback;
+select id as afterrollback_id,nom as afterrollback_nom from t1;
afterrollback_id afterrollback_nom
+set autocommit=0;
+insert into t1 values(2,'mysql');
+select id as afterautocommit0_id,nom as afterautocommit0_nom from t1;
afterautocommit0_id afterautocommit0_nom
2 mysql
+rollback;
+select id as afterrollback_id,nom as afterrollback_nom from t1;
afterrollback_id afterrollback_nom
+set autocommit=1;
+drop table t1;
+CREATE TABLE t1 (id char(8) not null primary key, val int not null) type=innodb;
+insert into t1 values ('pippo', 12);
+insert into t1 values ('pippo', 12);
+Duplicate entry 'pippo' for key 1
+delete from t1;
+delete from t1 where id = 'pippo';
+select * from t1;
id val
+insert into t1 values ('pippo', 12);
+set autocommit=0;
+delete from t1;
+rollback;
+select * from t1;
id val
pippo 12
+delete from t1;
+commit;
+select * from t1;
id val
+drop table t1;
+create table t1 (a integer) type=innodb;
+begin;
+rename table t1 to t2;
+create table t1 (b integer) type=innodb;
+insert into t1 values (1);
+rollback;
+drop table t1;
+rename table t2 to t1;
+drop table t1;
+set autocommit=1;
+CREATE TABLE t1 (ID INTEGER NOT NULL PRIMARY KEY, NAME VARCHAR(64)) TYPE=innodb;
+INSERT INTO t1 VALUES (1, 'Jochen');
+select * from t1;
ID NAME
1 Jochen
+drop table t1;
+CREATE TABLE t1 ( _userid VARCHAR(60) NOT NULL PRIMARY KEY) TYPE=innodb;
+set autocommit=0;
+INSERT INTO t1 SET _userid='marc@anyware.co.uk';
+COMMIT;
+SELECT * FROM t1;
_userid
marc@anyware.co.uk
+SELECT _userid FROM t1 WHERE _userid='marc@anyware.co.uk';
_userid
marc@anyware.co.uk
+drop table t1;
+set autocommit=1;
+CREATE TABLE t1 (
+user_id int(10) DEFAULT '0' NOT NULL,
+name varchar(100),
+phone varchar(100),
+ref_email varchar(100) DEFAULT '' NOT NULL,
+detail varchar(200),
+PRIMARY KEY (user_id,ref_email)
+)type=innodb;
+INSERT INTO t1 VALUES (10292,'sanjeev','29153373','sansh777@hotmail.com','xxx'),(10292,'shirish','2333604','shirish@yahoo.com','ddsds'),(10292,'sonali','323232','sonali@bolly.com','filmstar');
+select * from t1 where user_id=10292;
user_id name phone ref_email detail
10292 sanjeev 29153373 sansh777@hotmail.com xxx
10292 shirish 2333604 shirish@yahoo.com ddsds
10292 sonali 323232 sonali@bolly.com filmstar
+INSERT INTO t1 VALUES (10291,'sanjeev','29153373','sansh777@hotmail.com','xxx'),(10293,'shirish','2333604','shirish@yahoo.com','ddsds');
+select * from t1 where user_id=10292;
user_id name phone ref_email detail
10292 sanjeev 29153373 sansh777@hotmail.com xxx
10292 shirish 2333604 shirish@yahoo.com ddsds
10292 sonali 323232 sonali@bolly.com filmstar
+select * from t1 where user_id>=10292;
user_id name phone ref_email detail
10292 sanjeev 29153373 sansh777@hotmail.com xxx
10292 shirish 2333604 shirish@yahoo.com ddsds
10292 sonali 323232 sonali@bolly.com filmstar
10293 shirish 2333604 shirish@yahoo.com ddsds
+select * from t1 where user_id>10292;
user_id name phone ref_email detail
10293 shirish 2333604 shirish@yahoo.com ddsds
+select * from t1 where user_id<10292;
user_id name phone ref_email detail
10291 sanjeev 29153373 sansh777@hotmail.com xxx
-Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Comment
-t1 0 PRIMARY 1 a A NULL NULL NULL
-t1 0 PRIMARY 2 b A 0 NULL NULL
-t1 0 b 1 b A 0 NULL NULL
-t1 0 c 1 c A 0 NULL NULL
-t1 1 a 1 a A NULL NULL NULL
-t1 1 a_2 1 a A NULL NULL NULL
+drop table t1;
+CREATE TABLE t1 (a int not null, b int not null,c int not null,
+key(a),primary key(a,b), unique(c),key(a),unique(b));
+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 NULL NULL NULL BTREE
+t1 0 PRIMARY 2 b A 0 NULL NULL BTREE
+t1 0 c 1 c A 0 NULL NULL BTREE
+t1 0 b 1 b A 0 NULL NULL BTREE
+t1 1 a 1 a A NULL NULL NULL BTREE
+t1 1 a_2 1 a A NULL NULL NULL BTREE
+drop table t1;
+create table t1 (col1 int not null, col2 char(4) not null, primary key(col1));
+alter table t1 type=innodb;
+insert into t1 values ('1','1'),('5','2'),('2','3'),('3','4'),('4','4');
+select * from t1;
col1 col2
1 1
2 3
3 4
4 4
5 2
+update t1 set col2='7' where col1='4';
+select * from t1;
col1 col2
1 1
2 3
3 4
4 7
5 2
+alter table t1 add co3 int not null;
+select * from t1;
col1 col2 co3
1 1 0
2 3 0
3 4 0
4 7 0
5 2 0
+update t1 set col2='9' where col1='2';
+select * from t1;
col1 col2 co3
1 1 0
2 9 0
3 4 0
4 7 0
5 2 0
+drop table t1;
+create table t1 (a int not null , b int, primary key (a)) type = innodb;
+create table t2 (a int not null , b int, primary key (a)) type = myisam;
+insert into t1 VALUES (1,3) , (2,3), (3,3);
+select * from t1;
a b
1 3
2 3
3 3
+insert into t2 select * from t1;
+select * from t2;
a b
1 3
2 3
3 3
+delete from t1 where b = 3;
+select * from t1;
a b
+insert into t1 select * from t2;
+select * from t1;
a b
1 3
2 3
3 3
+select * from t2;
a b
1 3
2 3
3 3
+drop table t1,t2;
+CREATE TABLE t1 (
+id int(11) NOT NULL auto_increment,
+ggid varchar(32) binary DEFAULT '' NOT NULL,
+email varchar(64) DEFAULT '' NOT NULL,
+passwd varchar(32) binary DEFAULT '' NOT NULL,
+PRIMARY KEY (id),
+UNIQUE ggid (ggid)
+) TYPE=innodb;
+insert into t1 (ggid,passwd) values ('test1','xxx');
+insert into t1 (ggid,passwd) values ('test2','yyy');
+insert into t1 (ggid,passwd) values ('test2','this will fail');
+Duplicate entry 'test2' for key 2
+insert into t1 (ggid,id) values ('this will fail',1);
+Duplicate entry '1' for key 1
+select * from t1 where ggid='test1';
id ggid email passwd
1 test1 xxx
+select * from t1 where passwd='xxx';
id ggid email passwd
1 test1 xxx
+select * from t1 where id=2;
id ggid email passwd
2 test2 yyy
+replace into t1 (ggid,id) values ('this will work',1);
+replace into t1 (ggid,passwd) values ('test2','this will work');
+update t1 set id=100,ggid='test2' where id=1;
+Duplicate entry 'test2' for key 2
+select * from t1;
id ggid email passwd
1 this will work
4 test2 this will work
+select * from t1 where id=1;
id ggid email passwd
1 this will work
+select * from t1 where id=999;
id ggid email passwd
+drop table t1;
+CREATE TABLE t1 (
+user_name varchar(12),
+password text,
+subscribed char(1),
+user_id int(11) DEFAULT '0' NOT NULL,
+quota bigint(20),
+weight double,
+access_date date,
+access_time time,
+approved datetime,
+dummy_primary_key int(11) NOT NULL auto_increment,
+PRIMARY KEY (dummy_primary_key)
+) TYPE=innodb;
+INSERT INTO t1 VALUES ('user_0','somepassword','N',0,0,0,'2000-09-07','23:06:59','2000-09-07 23:06:59',1);
+INSERT INTO t1 VALUES ('user_1','somepassword','Y',1,1,1,'2000-09-07','23:06:59','2000-09-07 23:06:59',2);
+INSERT INTO t1 VALUES ('user_2','somepassword','N',2,2,1.4142135623731,'2000-09-07','23:06:59','2000-09-07 23:06:59',3);
+INSERT INTO t1 VALUES ('user_3','somepassword','Y',3,3,1.7320508075689,'2000-09-07','23:06:59','2000-09-07 23:06:59',4);
+INSERT INTO t1 VALUES ('user_4','somepassword','N',4,4,2,'2000-09-07','23:06:59','2000-09-07 23:06:59',5);
+select user_name, password , subscribed, user_id, quota, weight, access_date, access_time, approved, dummy_primary_key from t1 order by user_name;
user_name password subscribed user_id quota weight access_date access_time approved dummy_primary_key
user_0 somepassword N 0 0 0 2000-09-07 23:06:59 2000-09-07 23:06:59 1
user_1 somepassword Y 1 1 1 2000-09-07 23:06:59 2000-09-07 23:06:59 2
user_2 somepassword N 2 2 1.4142135623731 2000-09-07 23:06:59 2000-09-07 23:06:59 3
user_3 somepassword Y 3 3 1.7320508075689 2000-09-07 23:06:59 2000-09-07 23:06:59 4
user_4 somepassword N 4 4 2 2000-09-07 23:06:59 2000-09-07 23:06:59 5
+drop table t1;
+CREATE TABLE t1 (
+id int(11) NOT NULL auto_increment,
+parent_id int(11) DEFAULT '0' NOT NULL,
+level tinyint(4) DEFAULT '0' NOT NULL,
+KEY (id),
+KEY parent_id (parent_id),
+KEY level (level)
+) type=innodb;
+INSERT INTO t1 VALUES (1,0,0),(3,1,1),(4,1,1),(8,2,2),(9,2,2),(17,3,2),(22,4,2),(24,4,2),(28,5,2),(29,5,2),(30,5,2),(31,6,2),(32,6,2),(33,6,2),(203,7,2),(202,7,2),(20,3,2),(157,0,0),(193,5,2),(40,7,2),(2,1,1),(15,2,2),(6,1,1),(34,6,2),(35,6,2),(16,3,2),(7,1,1),(36,7,2),(18,3,2),(26,5,2),(27,5,2),(183,4,2),(38,7,2),(25,5,2),(37,7,2),(21,4,2),(19,3,2),(5,1,1);
+INSERT INTO t1 values (179,5,2);
+update t1 set parent_id=parent_id+100;
+select * from t1 where parent_id=102;
id parent_id level
8 102 2
9 102 2
15 102 2
+update t1 set id=id+1000;
+update t1 set id=1024 where id=1009;
+select * from t1;
id parent_id level
1001 100 0
1003 101 1
@@ -306,6 +547,8 @@ id parent_id level
1019 103 2
1005 101 1
1179 105 2
+update ignore t1 set id=id+1;
+select * from t1;
id parent_id level
1002 100 0
1004 101 1
@@ -346,12 +589,16 @@ id parent_id level
1020 103 2
1006 101 1
1180 105 2
+update ignore t1 set id=1023 where id=1010;
+select * from t1 where parent_id=102;
id parent_id level
1009 102 2
1025 102 2
1016 102 2
+explain select level from t1 where level=1;
table type possible_keys key key_len ref rows Extra
t1 ref level level 1 const 6 where used; Using index
+select level,id from t1 where level=1;
level id
1 1004
1 1005
@@ -359,6 +606,7 @@ level id
1 1007
1 1008
1 1006
+select level,id,parent_id from t1 where level=1;
level id parent_id
1 1004 101
1 1005 101
@@ -366,6 +614,7 @@ level id parent_id
1 1007 101
1 1008 101
1 1006 101
+select level,id from t1 where level=1 order by id;
level id
1 1003
1 1004
@@ -373,6 +622,8 @@ level id
1 1006
1 1007
1 1008
+delete from t1 where level=1;
+select * from t1;
id parent_id level
1002 100 0
1009 102 2
@@ -407,97 +658,334 @@ id parent_id level
1022 104 2
1020 103 2
1180 105 2
+drop table t1;
+CREATE TABLE t1 (
+sca_code char(6) NOT NULL,
+cat_code char(6) NOT NULL,
+sca_desc varchar(50),
+lan_code char(2) NOT NULL,
+sca_pic varchar(100),
+sca_sdesc varchar(50),
+sca_sch_desc varchar(16),
+PRIMARY KEY (sca_code, cat_code, lan_code),
+INDEX sca_pic (sca_pic)
+) type = innodb ;
+INSERT INTO t1 ( sca_code, cat_code, sca_desc, lan_code, sca_pic, sca_sdesc, sca_sch_desc) VALUES ( 'PD', 'J', 'PENDANT', 'EN', NULL, NULL, 'PENDANT'),( 'RI', 'J', 'RING', 'EN', NULL, NULL, 'RING'),( 'QQ', 'N', 'RING', 'EN', 'not null', NULL, 'RING');
+select count(*) from t1 where sca_code = 'PD';
count(*)
1
+select count(*) from t1 where sca_code <= 'PD';
count(*)
1
+select count(*) from t1 where sca_pic is null;
count(*)
2
+alter table t1 drop index sca_pic, add index sca_pic (cat_code, sca_pic);
+select count(*) from t1 where sca_code='PD' and sca_pic is null;
count(*)
1
+select count(*) from t1 where cat_code='E';
count(*)
0
+alter table t1 drop index sca_pic, add index (sca_pic, cat_code);
+select count(*) from t1 where sca_code='PD' and sca_pic is null;
count(*)
1
+select count(*) from t1 where sca_pic >= 'n';
count(*)
1
+select sca_pic from t1 where sca_pic is null;
sca_pic
NULL
NULL
+update t1 set sca_pic="test" where sca_pic is null;
+delete from t1 where sca_code='pd';
+drop table t1;
+set @a:=now();
+CREATE TABLE t1 (a int not null, b timestamp not null, primary key (a)) type=innodb;
+insert into t1 (a) values(1),(2),(3);
+select t1.a from t1 natural join t1 as t2 where t1.b >= @a order by t1.a;
a
1
2
3
+update t1 set a=5 where a=1;
+select a from t1;
a
2
3
5
+drop table t1;
+create table t1 (a varchar(100) not null, primary key(a), b int not null) type=innodb;
+insert into t1 values("hello",1),("world",2);
+select * from t1 order by b desc;
a b
world 2
hello 1
+optimize table t1;
Table Op Msg_type Msg_text
test.t1 optimize error The handler for the table doesn't support check/repair
-Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Comment
-t1 0 PRIMARY 1 a A 2 NULL NULL
+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 a A 2 NULL NULL BTREE
+drop table t1;
+create table t1 (i int, j int ) TYPE=innodb;
+insert into t1 values (1,2);
+select * from t1 where i=1 and j=2;
i j
1 2
+create index ax1 on t1 (i,j);
+select * from t1 where i=1 and j=2;
i j
1 2
+drop table t1;
+CREATE TABLE t1 (
+a int3 unsigned NOT NULL,
+b int1 unsigned NOT NULL,
+UNIQUE (a, b)
+) TYPE = innodb;
+INSERT INTO t1 VALUES (1, 1);
+SELECT MIN(B),MAX(b) FROM t1 WHERE t1.a = 1;
MIN(B) MAX(b)
1 1
+drop table t1;
+CREATE TABLE t1 (a int unsigned NOT NULL) type=innodb;
+INSERT INTO t1 VALUES (1);
+SELECT * FROM t1;
a
1
+DROP TABLE t1;
+create table t1 (a int primary key,b int, c int, d int, e int, f int, g int, h int, i int, j int, k int, l int, m int, n int, o int, p int, q int, r int, s int, t int, u int, v int, w int, x int, y int, z int, a1 int, a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int, b1 int, b2 int, b3 int, b4 int, b5 int, b6 int) type = innodb;
+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);
+explain select * from t1 where a > 0 and a < 50;
table type possible_keys key key_len ref rows Extra
t1 range PRIMARY PRIMARY 4 NULL 1 where used
+drop table t1;
+create table t1 (id int NOT NULL,id2 int NOT NULL,id3 int NOT NULL,dummy1 char(30),primary key (id,id2),index index_id3 (id3)) type=innodb;
+insert into t1 values (0,0,0,'ABCDEFGHIJ'),(2,2,2,'BCDEFGHIJK'),(1,1,1,'CDEFGHIJKL');
+LOCK TABLES t1 WRITE;
+insert into t1 values (99,1,2,'D'),(1,1,2,'D');
+Duplicate entry '1-1' for key 1
+select id from t1;
id
0
1
2
+select id from t1;
id
0
1
2
+UNLOCK TABLES;
+DROP TABLE t1;
+create table t1 (id int NOT NULL,id2 int NOT NULL,id3 int NOT NULL,dummy1 char(30),primary key (id,id2),index index_id3 (id3)) type=innodb;
+insert into t1 values (0,0,0,'ABCDEFGHIJ'),(2,2,2,'BCDEFGHIJK'),(1,1,1,'CDEFGHIJKL');
+LOCK TABLES t1 WRITE;
+begin;
+insert into t1 values (99,1,2,'D'),(1,1,2,'D');
+Duplicate entry '1-1' for key 1
+select id from t1;
id
0
1
2
+insert ignore into t1 values (100,1,2,'D'),(1,1,99,'D');
+commit;
+select id,id3 from t1;
id id3
0 0
1 1
2 2
100 2
+UNLOCK TABLES;
+DROP TABLE t1;
+create table t1 (a char(20), unique (a(5))) type=innodb;
+Incorrect sub part key. The used key part isn't a string, the used length is longer than the key part or the table handler doesn't support unique sub keys
+create table t1 (a char(20), index (a(5))) type=innodb;
+show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` char(20) default NULL,
KEY `a` (`a`)
) TYPE=InnoDB
+drop table t1;
+create temporary table t1 (a int not null auto_increment, primary key(a)) type=innodb;
+insert into t1 values (NULL),(NULL),(NULL);
+delete from t1 where a=3;
+insert into t1 values (NULL);
+select * from t1;
a
1
2
4
+alter table t1 add b int;
+select * from t1;
a b
1 NULL
2 NULL
4 NULL
+drop table t1;
+create table t1
+(
+id int auto_increment primary key,
+name varchar(32) not null,
+value text not null,
+uid int not null,
+unique key(name,uid)
+) type=innodb;
+insert into t1 values (1,'one','one value',101),
+(2,'two','two value',102),(3,'three','three value',103);
+set insert_id=5;
+replace into t1 (value,name,uid) values ('other value','two',102);
+delete from t1 where uid=102;
+set insert_id=5;
+replace into t1 (value,name,uid) values ('other value','two',102);
+set insert_id=6;
+replace into t1 (value,name,uid) values ('other value','two',102);
+select * from t1;
id name value uid
1 one one value 101
3 three three value 103
6 two other value 102
+drop table t1;
+create database mysqltest;
+create table mysqltest.t1 (a int not null) type= innodb;
+insert into mysqltest.t1 values(1);
+create table mysqltest.t2 (a int not null) type= myisam;
+insert into mysqltest.t2 values(1);
+create table mysqltest.t3 (a int not null) type= heap;
+insert into mysqltest.t3 values(1);
+commit;
+drop database mysqltest;
+show tables from mysqltest;
+Got one of the listed errors
+set autocommit=0;
+create table t1 (a int not null) type= innodb;
+insert into t1 values(1),(2);
+truncate table t1;
+Can't execute the given command because you have active locked tables or an active transaction
+commit;
+truncate table t1;
+select * from t1;
+a
+insert into t1 values(1),(2);
+delete from t1;
+select * from t1;
+a
+commit;
+drop table t1;
+set autocommit=1;
+create table t1 (a int not null) type= innodb;
+insert into t1 values(1),(2);
+truncate table t1;
+insert into t1 values(1),(2);
+select * from t1;
+a
+1
+2
+truncate table t1;
+insert into t1 values(1),(2);
+delete from t1;
+select * from t1;
+a
+drop table t1;
+create table t1 (a int not null, b int not null, c int not null, primary key (a),key(b)) type=innodb;
+insert into t1 values (3,3,3),(1,1,1),(2,2,2),(4,4,4);
+explain select * from t1 order by a;
table type possible_keys key key_len ref rows Extra
t1 index NULL PRIMARY 4 NULL 4
+explain select * from t1 order by b;
table type possible_keys key key_len ref rows Extra
t1 index NULL b 4 NULL 4
+explain select * from t1 order by c;
table type possible_keys key key_len ref rows Extra
t1 ALL NULL NULL NULL NULL 4 Using filesort
+explain select a from t1 order by a;
table type possible_keys key key_len ref rows Extra
t1 index NULL PRIMARY 4 NULL 4 Using index
+explain select b from t1 order by b;
table type possible_keys key key_len ref rows Extra
t1 index NULL b 4 NULL 4 Using index
+explain select a,b from t1 order by b;
table type possible_keys key key_len ref rows Extra
t1 index NULL b 4 NULL 4 Using index
+explain select a,b from t1;
table type possible_keys key key_len ref rows Extra
t1 index NULL b 4 NULL 4 Using index
+explain select a,b,c from t1;
table type possible_keys key key_len ref rows Extra
t1 ALL NULL NULL NULL NULL 4
+drop table t1;
+create table t1 (t int not null default 1, key (t)) type=innodb;
+desc t1;
Field Type Null Key Default Extra
-testint int(11) 1
+t int(11) MUL 1
+handler t1 open t1;
+Table handler for 't1' doesn't have this option
+handler t1 read t first;
+Unknown table 't1' in HANDLER
+handler t1 close;
+Unknown table 't1' in HANDLER
+drop table t1;
+CREATE TABLE t1 (
+number bigint(20) NOT NULL default '0',
+cname char(15) NOT NULL default '',
+carrier_id smallint(6) NOT NULL default '0',
+privacy tinyint(4) NOT NULL default '0',
+last_mod_date timestamp(14) NOT NULL,
+last_mod_id smallint(6) NOT NULL default '0',
+last_app_date timestamp(14) NOT NULL,
+last_app_id smallint(6) default '-1',
+version smallint(6) NOT NULL default '0',
+assigned_scps int(11) default '0',
+status tinyint(4) default '0'
+) TYPE=InnoDB;
+INSERT INTO t1 VALUES (4077711111,'SeanWheeler',90,2,20020111112846,500,00000000000000,-1,2,3,1);
+INSERT INTO t1 VALUES (9197722223,'berry',90,3,20020111112809,500,20020102114532,501,4,10,0);
+INSERT INTO t1 VALUES (650,'San Francisco',0,0,20011227111336,342,00000000000000,-1,1,24,1);
+INSERT INTO t1 VALUES (302467,'Sue\'s Subshop',90,3,20020109113241,500,20020102115111,501,7,24,0);
+INSERT INTO t1 VALUES (6014911113,'SudzCarwash',520,1,20020102115234,500,20020102115259,501,33,32768,0);
+INSERT INTO t1 VALUES (333,'tubs',99,2,20020109113440,501,20020109113440,500,3,10,0);
+CREATE TABLE t2 (
+number bigint(20) NOT NULL default '0',
+cname char(15) NOT NULL default '',
+carrier_id smallint(6) NOT NULL default '0',
+privacy tinyint(4) NOT NULL default '0',
+last_mod_date timestamp(14) NOT NULL,
+last_mod_id smallint(6) NOT NULL default '0',
+last_app_date timestamp(14) NOT NULL,
+last_app_id smallint(6) default '-1',
+version smallint(6) NOT NULL default '0',
+assigned_scps int(11) default '0',
+status tinyint(4) default '0'
+) TYPE=InnoDB;
+INSERT INTO t2 VALUES (4077711111,'SeanWheeler',0,2,20020111112853,500,00000000000000,-1,2,3,1);
+INSERT INTO t2 VALUES (9197722223,'berry',90,3,20020111112818,500,20020102114532,501,4,10,0);
+INSERT INTO t2 VALUES (650,'San Francisco',90,0,20020109113158,342,00000000000000,-1,1,24,1);
+INSERT INTO t2 VALUES (333,'tubs',99,2,20020109113453,501,20020109113453,500,3,10,0);
+select * from t1;
+number cname carrier_id privacy last_mod_date last_mod_id last_app_date last_app_id version assigned_scps status
+4077711111 SeanWheeler 90 2 20020111112846 500 00000000000000 -1 2 3 1
+9197722223 berry 90 3 20020111112809 500 20020102114532 501 4 10 0
+650 San Francisco 0 0 20011227111336 342 00000000000000 -1 1 24 1
+302467 Sue's Subshop 90 3 20020109113241 500 20020102115111 501 7 24 0
+6014911113 SudzCarwash 520 1 20020102115234 500 20020102115259 501 33 32768 0
+333 tubs 99 2 20020109113440 501 20020109113440 500 3 10 0
+select * from t2;
+number cname carrier_id privacy last_mod_date last_mod_id last_app_date last_app_id version assigned_scps status
+4077711111 SeanWheeler 0 2 20020111112853 500 00000000000000 -1 2 3 1
+9197722223 berry 90 3 20020111112818 500 20020102114532 501 4 10 0
+650 San Francisco 90 0 20020109113158 342 00000000000000 -1 1 24 1
+333 tubs 99 2 20020109113453 501 20020109113453 500 3 10 0
+delete t1, t2 from t1 left join t2 on t1.number=t2.number where (t1.carrier_id=90 and t1.number=t2.number) or (t2.carrier_id=90 and t1.number=t2.number) or (t1.carrier_id=90 and t2.number is null);
+select * from t1;
+number cname carrier_id privacy last_mod_date last_mod_id last_app_date last_app_id version assigned_scps status
+6014911113 SudzCarwash 520 1 20020102115234 500 20020102115259 501 33 32768 0
+333 tubs 99 2 20020109113440 501 20020109113440 500 3 10 0
+select * from t2;
+number cname carrier_id privacy last_mod_date last_mod_id last_app_date last_app_id version assigned_scps status
+333 tubs 99 2 20020109113453 501 20020109113453 500 3 10 0
+select * from t2;
+number cname carrier_id privacy last_mod_date last_mod_id last_app_date last_app_id version assigned_scps status
+333 tubs 99 2 20020109113453 501 20020109113453 500 3 10 0
+drop table t1,t2;
diff --git a/mysql-test/r/innodb_cache.result b/mysql-test/r/innodb_cache.result
new file mode 100644
index 00000000000..df331addb99
--- /dev/null
+++ b/mysql-test/r/innodb_cache.result
@@ -0,0 +1,15 @@
+drop table if exists t1;
+set autocommit=0;
+create table t1 (a int not null) type=innodb;
+insert into t1 values (1),(2),(3);
+select * from t1;
+a
+1
+2
+3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+drop table t1;
+commit;
+set autocommit=1;
diff --git a/mysql-test/r/ins000001.result b/mysql-test/r/ins000001.result
index 283f31ffb43..ec4f73e7a5d 100644
--- a/mysql-test/r/ins000001.result
+++ b/mysql-test/r/ins000001.result
@@ -1,3 +1,12 @@
+use test;
+drop table if exists t1,t2;
+create table t1 (email varchar(50));
+insert into t1 values ('sasha@mysql.com'),('monty@mysql.com'),
+('foo@hotmail.com'),('foo@aol.com'),('bar@aol.com');
+create table t2(id int not null auto_increment primary key,
+t2 varchar(50), unique(t2));
+insert into t2 (t2) select distinct substring(email, locate('@', email)+1) from t1;
+select * from t2;
id t2
1 mysql.com
2 hotmail.com
diff --git a/mysql-test/r/insert.result b/mysql-test/r/insert.result
index 145ec8a5cf4..f57efa33020 100644
--- a/mysql-test/r/insert.result
+++ b/mysql-test/r/insert.result
@@ -1,6 +1,21 @@
+drop table if exists t1;
+create table t1 (a int not null);
+insert into t1 values (1);
+insert into t1 values (a+2);
+insert into t1 values (a+3);
+insert into t1 values (4),(a+5);
+select * from t1;
a
1
2
3
4
5
+drop table t1;
+create table t1 (id int not null auto_increment primary key, username varchar(32) not null, unique (username));
+insert into t1 values (0,"mysql");
+insert into t1 values (0,"mysql ab");
+insert into t1 values (0,"mysql a");
+insert into t1 values (0,"r1manic");
+insert into t1 values (0,"r1man");
+drop table t1;
diff --git a/mysql-test/r/insert_select.result b/mysql-test/r/insert_select.result
index c754085ccb3..d61b6c67030 100644
--- a/mysql-test/r/insert_select.result
+++ b/mysql-test/r/insert_select.result
@@ -1,3 +1,12 @@
+drop table if exists t1,t2;
+create table t1 (bandID MEDIUMINT UNSIGNED NOT NULL PRIMARY KEY, payoutID SMALLINT UNSIGNED NOT NULL);
+insert into t1 (bandID,payoutID) VALUES (1,6),(2,6),(3,4),(4,9),(5,10),(6,1),(7,12),(8,12);
+create table t2 (payoutID SMALLINT UNSIGNED NOT NULL PRIMARY KEY);
+insert into t2 (payoutID) SELECT DISTINCT payoutID FROM t1;
+insert into t2 (payoutID) SELECT payoutID+10 FROM t1;
+Duplicate entry '16' for key 1
+insert ignore into t2 (payoutID) SELECT payoutID+10 FROM t1;
+select * from t2;
payoutID
1
4
@@ -11,3 +20,49 @@ payoutID
19
20
22
+drop table t1,t2;
+DROP TABLE IF EXISTS crash1,crash2;
+CREATE TABLE `crash1` (
+`numeropost` bigint(20) unsigned NOT NULL default '0',
+`icone` tinyint(4) unsigned NOT NULL default '0',
+`numreponse` bigint(20) unsigned NOT NULL auto_increment,
+`contenu` text NOT NULL,
+`pseudo` varchar(50) NOT NULL default '',
+`date` datetime NOT NULL default '0000-00-00 00:00:00',
+`ip` bigint(11) NOT NULL default '0',
+`signature` tinyint(1) unsigned NOT NULL default '0',
+PRIMARY KEY (`numeropost`,`numreponse`)
+,KEY `ip` (`ip`),
+KEY `date` (`date`),
+KEY `pseudo` (`pseudo`),
+KEY `numreponse` (`numreponse`)
+) TYPE=MyISAM;
+CREATE TABLE `crash2` (
+`numeropost` bigint(20) unsigned NOT NULL default '0',
+`icone` tinyint(4) unsigned NOT NULL default '0',
+`numreponse` bigint(20) unsigned NOT NULL auto_increment,
+`contenu` text NOT NULL,
+`pseudo` varchar(50) NOT NULL default '',
+`date` datetime NOT NULL default '0000-00-00 00:00:00',
+`ip` bigint(11) NOT NULL default '0',
+`signature` tinyint(1) unsigned NOT NULL default '0',
+PRIMARY KEY (`numeropost`,`numreponse`),
+KEY `ip` (`ip`),
+KEY `date` (`date`),
+KEY `pseudo` (`pseudo`),
+KEY `numreponse` (`numreponse`)
+) TYPE=MyISAM;
+INSERT INTO crash2
+(numeropost,icone,numreponse,contenu,pseudo,date,ip,signature) VALUES
+(9,1,56,'test','joce','2001-07-25 13:50:53'
+,3649052399,0);
+INSERT INTO crash1 (numeropost,icone,contenu,pseudo,date,signature,ip)
+SELECT 1618,icone,contenu,pseudo,date,signature,ip FROM crash2
+WHERE numeropost=9 ORDER BY numreponse ASC;
+show variables like '%bulk%';
+Variable_name Value
+myisam_bulk_insert_tree_size 8388608
+INSERT INTO crash1 (numeropost,icone,contenu,pseudo,date,signature,ip)
+SELECT 1718,icone,contenu,pseudo,date,signature,ip FROM crash2
+WHERE numeropost=9 ORDER BY numreponse ASC;
+DROP TABLE IF EXISTS crash1,crash2;
diff --git a/mysql-test/r/isam.result b/mysql-test/r/isam.result
index ba12ca05feb..d19352aad42 100644
--- a/mysql-test/r/isam.result
+++ b/mysql-test/r/isam.result
@@ -1,10 +1,79 @@
+drop table if exists t1,t2;
+create table t1 (a tinyint not null auto_increment, b blob not null, primary key (a)) type=isam;
+delete from t1 where (a & 1);
+select sum(length(b)) from t1;
+sum(length(b))
+3274494
+drop table t1;
+create table t1 (a int not null auto_increment,b int, primary key (a)) type=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;
+a b
+1 1
+5 5
+3 3
+4 4
+6 6
+delete from t1 where a=6;
+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;
+a b c
+1 1 NULL
+5 5 NULL
+3 3 NULL
+4 4 NULL
+6 6 6
+drop table t1;
+create table t1 (a int,b text, index(a)) type=isam;
+Column 'a' is used with UNIQUE or INDEX but is not defined as NOT NULL
+create table t1 (a int,b text, index(b)) type=isam;
+BLOB column 'b' can't be used in key specification with the used table type
+create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null, primary key (ord,ordid)) type=isam;
+Incorrect table definition; There can only be one auto column and it must be defined as a key
+create table t1 (ordid int(8), unique (ordid)) type=isam;
+Column 'ordid' is used with UNIQUE or INDEX but is not defined as NOT NULL
+drop table if exists t1;
+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 type=isam select * from t1;
+optimize table t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+check table t1,t2;
Table Op Msg_type Msg_text
test.t1 check status OK
+test.t2 check error The handler for the table doesn't support check/repair
+repair table t1,t2;
Table Op Msg_type Msg_text
test.t1 repair status OK
+test.t2 repair error The handler for the table doesn't support check/repair
+check table t2,t1;
Table Op Msg_type Msg_text
+test.t2 check error The handler for the table doesn't support check/repair
test.t1 check status OK
+lock tables t1 write;
+check table t2,t1;
Table Op Msg_type Msg_text
-test.t1 repair status OK
-Table Op Msg_type Msg_text
+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
+show full columns from t1;
+Field Type Null Key Default Extra Privileges
+a int(11) PRI 0 select,insert,update,references
+b int(11) MUL 0 select,insert,update,references
+c int(11) 0 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
+t1 1 b 1 b A 1 NULL NULL BTREE
+t1 1 b 2 c A 4 NULL NULL BTREE
+drop table t1,t2;
diff --git a/mysql-test/r/isolation.result b/mysql-test/r/isolation.result
deleted file mode 100644
index 60b71e217bb..00000000000
--- a/mysql-test/r/isolation.result
+++ /dev/null
@@ -1,61 +0,0 @@
-f1
-test1
-bar
-f1
-test2
-bar
-f1
-test3
-bar
-f1
-f1
-test4
-bar
-f1
-test5
-bar
-f1
-test6
-bar
-f1
-test7
-bar
-f1
-test8
-bar
-f1
-test9
-bar
-f1
-test10
-bar
-f1
-test11
-bar
-f1
-test12
-bar
-f1
-test13
-bar
-f1
-test14
-bar
-f1
-test15
-bar
-f1
-test16
-bar
-f1
-test17
-bar
-f1
-test18
-bar
-f1
-test19
-bar
-f1
-test20
-bar
diff --git a/mysql-test/r/join.result b/mysql-test/r/join.result
index c99c63245dd..b8ec13e9f50 100644
--- a/mysql-test/r/join.result
+++ b/mysql-test/r/join.result
@@ -1,36 +1,210 @@
+drop table if exists t1,t2,t3;
+create table t1 (id int primary key);
+create table t2 (id int);
+insert into t1 values (75);
+insert into t1 values (79);
+insert into t1 values (78);
+insert into t1 values (77);
+replace into t1 values (76);
+replace into t1 values (76);
+insert into t1 values (104);
+insert into t1 values (103);
+insert into t1 values (102);
+insert into t1 values (101);
+insert into t1 values (105);
+insert into t1 values (106);
+insert into t1 values (107);
+insert into t2 values (107);
+insert into t2 values (75);
+select t1.id, t2.id from t1, t2 where t2.id = t1.id;
id id
107 107
75 75
+select t1.id, count(t2.id) from t1,t2 where t2.id = t1.id group by t1.id;
id count(t2.id)
75 1
107 1
+select t1.id, count(t2.id) from t1,t2 where t2.id = t1.id group by t2.id;
id count(t2.id)
75 1
107 1
+drop table t1,t2;
+CREATE TABLE t1 (
+id int(11) NOT NULL auto_increment,
+token varchar(100) DEFAULT '' NOT NULL,
+count int(11) DEFAULT '0' NOT NULL,
+qty int(11),
+phone char(1) DEFAULT '' NOT NULL,
+timestamp datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
+PRIMARY KEY (id),
+KEY token (token(15)),
+KEY timestamp (timestamp),
+UNIQUE token_2 (token(75),count,phone)
+);
+INSERT INTO t1 VALUES (21,'e45703b64de71482360de8fec94c3ade',3,7800,'n','1999-12-23 17:22:21');
+INSERT INTO t1 VALUES (22,'e45703b64de71482360de8fec94c3ade',4,5000,'y','1999-12-23 17:22:21');
+INSERT INTO t1 VALUES (18,'346d1cb63c89285b2351f0ca4de40eda',3,13200,'b','1999-12-23 11:58:04');
+INSERT INTO t1 VALUES (17,'ca6ddeb689e1b48a04146b1b5b6f936a',4,15000,'b','1999-12-23 11:36:53');
+INSERT INTO t1 VALUES (16,'ca6ddeb689e1b48a04146b1b5b6f936a',3,13200,'b','1999-12-23 11:36:53');
+INSERT INTO t1 VALUES (26,'a71250b7ed780f6ef3185bfffe027983',5,1500,'b','1999-12-27 09:44:24');
+INSERT INTO t1 VALUES (24,'4d75906f3c37ecff478a1eb56637aa09',3,5400,'y','1999-12-23 17:29:12');
+INSERT INTO t1 VALUES (25,'4d75906f3c37ecff478a1eb56637aa09',4,6500,'y','1999-12-23 17:29:12');
+INSERT INTO t1 VALUES (27,'a71250b7ed780f6ef3185bfffe027983',3,6200,'b','1999-12-27 09:44:24');
+INSERT INTO t1 VALUES (28,'a71250b7ed780f6ef3185bfffe027983',3,5400,'y','1999-12-27 09:44:36');
+INSERT INTO t1 VALUES (29,'a71250b7ed780f6ef3185bfffe027983',4,17700,'b','1999-12-27 09:45:05');
+CREATE TABLE t2 (
+id int(11) NOT NULL auto_increment,
+category int(11) DEFAULT '0' NOT NULL,
+county int(11) DEFAULT '0' NOT NULL,
+state int(11) DEFAULT '0' NOT NULL,
+phones int(11) DEFAULT '0' NOT NULL,
+nophones int(11) DEFAULT '0' NOT NULL,
+PRIMARY KEY (id),
+KEY category (category,county,state)
+);
+INSERT INTO t2 VALUES (3,2,11,12,5400,7800);
+INSERT INTO t2 VALUES (4,2,25,12,6500,11200);
+INSERT INTO t2 VALUES (5,1,37,6,10000,12000);
+select a.id, b.category as catid, b.state as stateid, b.county as
+countyid from t1 a, t2 b where (a.token =
+'a71250b7ed780f6ef3185bfffe027983') and (a.count = b.id);
id catid stateid countyid
27 2 12 11
28 2 12 11
29 2 12 25
26 1 6 37
+select a.id, b.category as catid, b.state as stateid, b.county as
+countyid from t1 a, t2 b where (a.token =
+'a71250b7ed780f6ef3185bfffe027983') and (a.count = b.id) order by a.id;
id catid stateid countyid
26 1 6 37
27 2 12 11
28 2 12 11
29 2 12 25
+drop table t1, t2;
+create table t1 (a int primary key);
+insert into t1 values(1),(2);
+select t1.a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a);
a
1
2
+select t1.a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a) left join t1 as t32 using (a) left join t1 as t33 using (a) left join t1 as t34 using (a) left join t1 as t35 using (a) left join t1 as t36 using (a) left join t1 as t37 using (a) left join t1 as t38 using (a) left join t1 as t39 using (a) left join t1 as t40 using (a) left join t1 as t41 using (a) left join t1 as t42 using (a) left join t1 as t43 using (a) left join t1 as t44 using (a) left join t1 as t45 using (a) left join t1 as t46 using (a) left join t1 as t47 using (a) left join t1 as t48 using (a) left join t1 as t49 using (a) left join t1 as t50 using (a) left join t1 as t51 using (a) left join t1 as t52 using (a) left join t1 as t53 using (a) left join t1 as t54 using (a) left join t1 as t55 using (a) left join t1 as t56 using (a) left join t1 as t57 using (a) left join t1 as t58 using (a) left join t1 as t59 using (a) left join t1 as t60 using (a) left join t1 as t61 using (a) left join t1 as t62 using (a) left join t1 as t63 using (a) left join t1 as t64 using (a) left join t1 as t65 using (a);
+Too many tables. MySQL can only use XX tables in a join
+drop table t1;
+CREATE TABLE t1 (
+a int(11) NOT NULL,
+b int(11) NOT NULL,
+PRIMARY KEY (a,b)
+) TYPE=MyISAM;
+INSERT INTO t1 VALUES (1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(2,3);
+CREATE TABLE t2 (
+a int(11) default NULL
+) TYPE=MyISAM;
+INSERT INTO t2 VALUES (2),(3);
+SELECT t1.a,t2.a,b FROM t1,t2 WHERE t1.a=t2.a AND (t1.a=1 OR t1.a=2) AND b>=1 AND b<=3;
a a b
2 2 3
+DROP TABLE t1, t2;
+CREATE TABLE t1 (d DATE NOT NULL);
+CREATE TABLE t2 (d DATE NOT NULL);
+INSERT INTO t1 (d) VALUES ('2001-08-01'),('0000-00-00');
+SELECT * FROM t1 LEFT JOIN t2 USING (d) WHERE t2.d IS NULL;
d d
2001-08-01 NULL
0000-00-00 NULL
+SELECT * from t1 WHERE t1.d IS NULL;
d
0000-00-00
+DROP TABLE t1,t2;
+CREATE TABLE t1 (
+Document_ID varchar(50) NOT NULL default '',
+Contractor_ID varchar(6) NOT NULL default '',
+Language_ID char(3) NOT NULL default '',
+Expiration_Date datetime default NULL,
+Publishing_Date datetime default NULL,
+Title text,
+Column_ID varchar(50) NOT NULL default '',
+PRIMARY KEY (Language_ID,Document_ID,Contractor_ID)
+);
+INSERT INTO t1 VALUES ('xep80','1','ger','2001-12-31 20:00:00','2001-11-12 10:58:00','Kartenbestellung - jetzt auch online','anle'),('','999998','',NULL,NULL,NULL,'');
+CREATE TABLE t2 (
+Contractor_ID char(6) NOT NULL default '',
+Language_ID char(3) NOT NULL default '',
+Document_ID char(50) NOT NULL default '',
+CanRead char(1) default NULL,
+Customer_ID int(11) NOT NULL default '0',
+PRIMARY KEY (Contractor_ID,Language_ID,Document_ID,Customer_ID)
+);
+INSERT INTO t2 VALUES ('5','ger','xep80','1',999999),('1','ger','xep80','1',999999);
+CREATE TABLE t3 (
+Language_ID char(3) NOT NULL default '',
+Column_ID char(50) NOT NULL default '',
+Contractor_ID char(6) NOT NULL default '',
+CanRead char(1) default NULL,
+Active char(1) default NULL,
+PRIMARY KEY (Language_ID,Column_ID,Contractor_ID)
+);
+INSERT INTO t3 VALUES ('ger','home','1','1','1'),('ger','Test','1','0','0'),('ger','derclu','1','0','0'),('ger','clubne','1','0','0'),('ger','philos','1','0','0'),('ger','clubko','1','0','0'),('ger','clubim','1','1','1'),('ger','progra','1','0','0'),('ger','progvo','1','0','0'),('ger','progsp','1','0','0'),('ger','progau','1','0','0'),('ger','progku','1','0','0'),('ger','progss','1','0','0'),('ger','nachl','1','0','0'),('ger','mitgli','1','0','0'),('ger','mitsu','1','0','0'),('ger','mitbus','1','0','0'),('ger','ergmar','1','1','1'),('ger','home','4','1','1'),('ger','derclu','4','1','1'),('ger','clubne','4','0','0'),('ger','philos','4','1','1'),('ger','clubko','4','1','1'),('ger','clubim','4','1','1'),('ger','progra','4','1','1'),('ger','progvo','4','1','1'),('ger','progsp','4','1','1'),('ger','progau','4','0','0'),('ger','progku','4','1','1'),('ger','progss','4','1','1'),('ger','nachl','4','1','1'),('ger','mitgli','4','0','0'),('ger','mitsu','4','0','0'),('ger','mitbus','4','0','0'),('ger','ergmar','4','1','1'),('ger','progra2','1','0','0'),('ger','archiv','4','1','1'),('ger','anmeld','4','1','1'),('ger','thema','4','1','1'),('ger','edito','4','1','1'),('ger','madis','4','1','1'),('ger','enma','4','1','1'),('ger','madis','1','1','1'),('ger','enma','1','1','1'),('ger','vorsch','4','0','0'),('ger','veranst','4','0','0'),('ger','anle','4','1','1'),('ger','redak','4','1','1'),('ger','nele','4','1','1'),('ger','aukt','4','1','1'),('ger','callcenter','4','1','1'),('ger','anle','1','0','0');
+delete from t1 where Contractor_ID='999998';
+insert into t1 (Contractor_ID) Values ('999998');
+SELECT DISTINCT COUNT(t1.Title) FROM t1,
+t2, t3 WHERE
+t1.Document_ID='xep80' AND t1.Contractor_ID='1' AND
+t1.Language_ID='ger' AND '2001-12-21 23:14:24' >=
+Publishing_Date AND '2001-12-21 23:14:24' <= Expiration_Date AND
+t1.Document_ID = t2.Document_ID AND
+t1.Language_ID = t2.Language_ID AND
+t1.Contractor_ID = t2.Contractor_ID AND (
+t2.Customer_ID = '4' OR
+t2.Customer_ID = '999999' OR
+t2.Customer_ID = '1' )AND t2.CanRead
+= '1' AND t1.Column_ID=t3.Column_ID AND
+t1.Language_ID=t3.Language_ID AND (
+t3.Contractor_ID = '4' OR
+t3.Contractor_ID = '999999' OR
+t3.Contractor_ID = '1') AND
+t3.CanRead='1' AND t3.Active='1';
COUNT(t1.Title)
1
+SELECT DISTINCT COUNT(t1.Title) FROM t1,
+t2, t3 WHERE
+t1.Document_ID='xep80' AND t1.Contractor_ID='1' AND
+t1.Language_ID='ger' AND '2001-12-21 23:14:24' >=
+Publishing_Date AND '2001-12-21 23:14:24' <= Expiration_Date AND
+t1.Document_ID = t2.Document_ID AND
+t1.Language_ID = t2.Language_ID AND
+t1.Contractor_ID = t2.Contractor_ID AND (
+t2.Customer_ID = '4' OR
+t2.Customer_ID = '999999' OR
+t2.Customer_ID = '1' )AND t2.CanRead
+= '1' AND t1.Column_ID=t3.Column_ID AND
+t1.Language_ID=t3.Language_ID AND (
+t3.Contractor_ID = '4' OR
+t3.Contractor_ID = '999999' OR
+t3.Contractor_ID = '1') AND
+t3.CanRead='1' AND t3.Active='1';
COUNT(t1.Title)
1
+drop table t1,t2,t3;
+CREATE TABLE t1 (
+t1_id int(11) default NULL,
+t2_id int(11) default NULL,
+type enum('Cost','Percent') default NULL,
+cost_unit enum('Cost','Unit') default NULL,
+min_value double default NULL,
+max_value double default NULL,
+t3_id int(11) default NULL,
+item_id int(11) default NULL
+) TYPE=MyISAM;
+INSERT INTO t1 VALUES (12,5,'Percent','Cost',-1,0,-1,-1),(14,4,'Percent','Cost',-1,0,-1,-1),(18,5,'Percent','Cost',-1,0,-1,-1),(19,4,'Percent','Cost',-1,0,-1,-1),(20,5,'Percent','Cost',100,-1,22,291),(21,5,'Percent','Cost',100,-1,18,291),(22,1,'Percent','Cost',100,-1,6,291),(23,1,'Percent','Cost',100,-1,21,291),(24,1,'Percent','Cost',100,-1,9,291),(25,1,'Percent','Cost',100,-1,4,291),(26,1,'Percent','Cost',100,-1,20,291),(27,4,'Percent','Cost',100,-1,7,202),(28,1,'Percent','Cost',50,-1,-1,137),(29,2,'Percent','Cost',100,-1,4,354),(30,2,'Percent','Cost',100,-1,9,137),(93,2,'Cost','Cost',-1,10000000,-1,-1);
+CREATE TABLE t2 (
+id int(10) unsigned NOT NULL auto_increment,
+name varchar(255) default NULL,
+PRIMARY KEY (id)
+) TYPE=MyISAM;
+INSERT INTO t2 VALUES (1,'s1'),(2,'s2'),(3,'s3'),(4,'s4'),(5,'s5');
+select t1.*, t2.* from t1, t2 where t2.id=t1.t2_id limit 2;
t1_id t2_id type cost_unit min_value max_value t3_id item_id id name
22 1 Percent Cost 100 -1 6 291 1 s1
23 1 Percent Cost 100 -1 21 291 1 s1
+drop table t1,t2;
diff --git a/mysql-test/r/join_crash.result b/mysql-test/r/join_crash.result
index f7bef8af8ec..c7bca9f7497 100644
--- a/mysql-test/r/join_crash.result
+++ b/mysql-test/r/join_crash.result
@@ -1 +1,110 @@
+DROP TABLE IF EXISTS t1,t2,t3,t4;
+CREATE TABLE t1 (
+project_id int(11) NOT NULL auto_increment,
+project_row_lock int(11) NOT NULL default '0',
+project_name varchar(80) NOT NULL default '',
+client_ptr int(11) NOT NULL default '0',
+project_contact_ptr int(11) default NULL,
+client_contact_ptr int(11) default NULL,
+billing_contact_ptr int(11) default NULL,
+comments mediumtext,
+PRIMARY KEY (project_id),
+UNIQUE KEY project (client_ptr,project_name)
+) TYPE=MyISAM PACK_KEYS=1;
+INSERT INTO t1 VALUES (1,0,'Rejected Time',1,NULL,NULL,NULL,NULL);
+INSERT INTO t1 VALUES (209,0,'MDGRAD Proposal/Investigation',97,NULL,NULL,NULL,'');
+INSERT INTO t1 VALUES (208,0,'Font 9 Design',84,NULL,NULL,NULL,'');
+INSERT INTO t1 VALUES (207,0,'Web Based Order Processing',95,NULL,NULL,NULL,'');
+INSERT INTO t1 VALUES (205,0,'Mac Screen Saver',95,NULL,NULL,NULL,'');
+INSERT INTO t1 VALUES (206,0,'Web Site',96,NULL,NULL,NULL,'');
+INSERT INTO t1 VALUES (204,0,'Magnafire Glue',94,NULL,NULL,NULL,'');
+INSERT INTO t1 VALUES (203,0,'Print Bid',93,NULL,NULL,NULL,'');
+INSERT INTO t1 VALUES (202,0,'EPOC Port',92,NULL,NULL,NULL,'');
+INSERT INTO t1 VALUES (201,0,'TravelMate',88,NULL,NULL,NULL,'');
+CREATE TABLE t2 (
+period_id int(11) NOT NULL auto_increment,
+period_type enum('user_table','client_table','role_table','member_table','project_table') default NULL,
+period_key int(11) default NULL,
+start_date datetime default NULL,
+end_date datetime default NULL,
+work_load int(11) default NULL,
+PRIMARY KEY (period_id),
+KEY period_index (period_type,period_key),
+KEY date_index (start_date,end_date)
+) TYPE=MyISAM PACK_KEYS=1;
+INSERT INTO t2 VALUES (1,'user_table',98,'2000-01-01 00:00:00',NULL,NULL);
+INSERT INTO t2 VALUES (2,'user_table',99,'2000-01-01 00:00:00',NULL,NULL);
+INSERT INTO t2 VALUES (3,'user_table',100,'2000-01-01 00:00:00',NULL,NULL);
+INSERT INTO t2 VALUES (49,'project_table',148,'2000-01-01 00:00:00',NULL,NULL);
+INSERT INTO t2 VALUES (50,'client_table',68,'2000-01-01 00:00:00',NULL,NULL);
+INSERT INTO t2 VALUES (51,'project_table',149,'2000-01-01 00:00:00',NULL,NULL);
+INSERT INTO t2 VALUES (52,'project_table',150,'2000-01-01 00:00:00',NULL,NULL);
+INSERT INTO t2 VALUES (53,'client_table',69,'2000-01-01 00:00:00',NULL,NULL);
+INSERT INTO t2 VALUES (54,'project_table',151,'2000-01-01 00:00:00',NULL,NULL);
+INSERT INTO t2 VALUES (55,'client_table',70,'2000-01-01 00:00:00',NULL,NULL);
+INSERT INTO t2 VALUES (155,'role_table',1,'2000-01-01 00:00:00',NULL,NULL);
+INSERT INTO t2 VALUES (156,'role_table',2,'2000-01-01 00:00:00',NULL,NULL);
+INSERT INTO t2 VALUES (160,'member_table',1,'2000-01-01 00:00:00',NULL,1);
+INSERT INTO t2 VALUES (161,'member_table',2,'2000-01-01 00:00:00',NULL,1);
+INSERT INTO t2 VALUES (162,'member_table',3,'2000-01-01 00:00:00',NULL,1);
+CREATE TABLE t3 (
+budget_id int(11) NOT NULL auto_increment,
+project_ptr int(11) NOT NULL default '0',
+po_number varchar(20) NOT NULL default '',
+status enum('open','closed') default NULL,
+date_received datetime default NULL,
+amount_received float(10,2) default NULL,
+adjustment float(10,2) default NULL,
+PRIMARY KEY (budget_id),
+UNIQUE KEY po (project_ptr,po_number)
+) TYPE=MyISAM PACK_KEYS=1;
+CREATE TABLE t4 (
+client_id int(11) NOT NULL auto_increment,
+client_row_lock int(11) NOT NULL default '0',
+client_name varchar(80) NOT NULL default '',
+contact_ptr int(11) default NULL,
+comments mediumtext,
+PRIMARY KEY (client_id),
+UNIQUE KEY client_name (client_name)
+) TYPE=MyISAM PACK_KEYS=1;
+INSERT INTO t4 VALUES (1,0,'CPS',NULL,NULL);
+select distinct
+t1.project_id as project_id,
+t1.project_name as project_name,
+t1.client_ptr as client_ptr,
+t1.comments as comments,
+sum( t3.amount_received ) + sum( t3.adjustment ) as total_budget
+from
+t1 ,
+t2 as client_period ,
+t2 as project_period
+left join
+t3
+on
+t3.project_ptr = t1.project_id
+and t3.date_received <= '2001-03-22 14:15:09'
+ left join
+t4
+on
+t4.client_id = t1.client_ptr
+where
+1
+and ( client_period.period_type = 'client_table'
+ and client_period.period_key = t4.client_id
+and ( client_period.start_date <= '2001-03-22 14:15:09' or isnull( client_period.start_date ))
+and ( client_period.end_date > '2001-03-21 14:15:09' or isnull( client_period.end_date ))
+)
+and ( project_period.period_type = 'project_table'
+ and project_period.period_key = t1.project_id
+and ( project_period.start_date <= '2001-03-22 14:15:09' or isnull( project_period.start_date ))
+and ( project_period.end_date > '2001-03-21 14:15:09' or isnull( project_period.end_date )) )
+group by
+client_id,
+project_id ,
+client_period.period_id ,
+project_period.period_id
+order by
+client_name asc,
+project_name asc;
project_id project_name client_ptr comments total_budget
+DROP TABLE t1,t2,t3,t4;
diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result
index f5e643a9bbf..9d3c152e516 100644
--- a/mysql-test/r/join_outer.result
+++ b/mysql-test/r/join_outer.result
@@ -1,8 +1,19 @@
+drop table if exists t1,t2,t3,t4,t5;
+CREATE TABLE t1 (
+grp int(11) default NULL,
+a bigint(20) unsigned default NULL,
+c char(10) NOT NULL default ''
+) TYPE=MyISAM;
+INSERT INTO t1 VALUES (1,1,'a'),(2,2,'b'),(2,3,'c'),(3,4,'E'),(3,5,'C'),(3,6,'D'),(NULL,NULL,'');
+create table t2 (id int, a bigint unsigned not null, c char(10), d int, primary key (a));
+insert into t2 values (1,1,"a",1),(3,4,"A",4),(3,5,"B",5),(3,6,"C",6),(4,7,"D",7);
+select t1.*,t2.* from t1 JOIN t2 where t1.a=t2.a;
grp a c id a c d
1 1 a 1 1 a 1
3 4 E 3 4 A 4
3 5 C 3 5 B 5
3 6 D 3 6 C 6
+select t1.*,t2.* from t1 left join t2 on (t1.a=t2.a) order by t1.grp,t1.a,t2.c;
grp a c id a c d
NULL NULL NULL NULL NULL NULL
1 1 a 1 1 a 1
@@ -11,18 +22,21 @@ NULL NULL NULL NULL NULL NULL
3 4 E 3 4 A 4
3 5 C 3 5 B 5
3 6 D 3 6 C 6
+select t1.*,t2.* from { oj t2 left outer join t1 on (t1.a=t2.a) };
grp a c id a c d
1 1 a 1 1 a 1
3 4 E 3 4 A 4
3 5 C 3 5 B 5
3 6 D 3 6 C 6
NULL NULL NULL 4 7 D 7
+select t1.*,t2.* from t1 as t0,{ oj t2 left outer join t1 on (t1.a=t2.a) } WHERE t0.a=2;
grp a c id a c d
1 1 a 1 1 a 1
3 4 E 3 4 A 4
3 5 C 3 5 B 5
3 6 D 3 6 C 6
NULL NULL NULL 4 7 D 7
+select t1.*,t2.* from t1 left join t2 using (a);
grp a c id a c d
1 1 a 1 1 a 1
2 2 b NULL NULL NULL NULL
@@ -31,11 +45,13 @@ grp a c id a c d
3 5 C 3 5 B 5
3 6 D 3 6 C 6
NULL NULL NULL NULL NULL NULL
+select t1.*,t2.* from t1 left join t2 using (a) where t1.a=t2.a;
grp a c id a c d
1 1 a 1 1 a 1
3 4 E 3 4 A 4
3 5 C 3 5 B 5
3 6 D 3 6 C 6
+select t1.*,t2.* from t1 left join t2 using (a,c);
grp a c id a c d
1 1 a 1 1 a 1
2 2 b NULL NULL NULL NULL
@@ -44,6 +60,7 @@ grp a c id a c d
3 5 C NULL NULL NULL NULL
3 6 D NULL NULL NULL NULL
NULL NULL NULL NULL NULL NULL
+select t1.*,t2.* from t1 left join t2 using (c);
grp a c id a c d
1 1 a 1 1 a 1
1 1 a 3 4 A 4
@@ -53,6 +70,7 @@ grp a c id a c d
3 5 C 3 6 C 6
3 6 D 4 7 D 7
NULL NULL NULL NULL NULL NULL
+select t1.*,t2.* from t1 natural left outer join t2;
grp a c id a c d
1 1 a 1 1 a 1
2 2 b NULL NULL NULL NULL
@@ -61,19 +79,24 @@ grp a c id a c d
3 5 C NULL NULL NULL NULL
3 6 D NULL NULL NULL NULL
NULL NULL NULL NULL NULL NULL
+select t1.*,t2.* from t1 left join t2 on (t1.a=t2.a) where t2.id=3;
grp a c id a c d
3 4 E 3 4 A 4
3 5 C 3 5 B 5
3 6 D 3 6 C 6
+select t1.*,t2.* from t1 left join t2 on (t1.a=t2.a) where t2.id is null;
grp a c id a c d
2 2 b NULL NULL NULL NULL
2 3 c NULL NULL NULL NULL
NULL NULL NULL NULL NULL NULL
+explain select t1.*,t2.* from t1,t2 where t1.a=t2.a and isnull(t2.a)=1;
Comment
Impossible WHERE noticed after reading const tables
+explain select t1.*,t2.* from t1 left join t2 on t1.a=t2.a where isnull(t2.a)=1;
table type possible_keys key key_len ref rows Extra
t1 ALL NULL NULL NULL NULL 7
t2 eq_ref PRIMARY PRIMARY 8 t1.a 1 where used
+select t1.*,t2.*,t3.a from t1 left join t2 on (t1.a=t2.a) left join t1 as t3 on (t2.a=t3.a);
grp a c id a c d a
1 1 a 1 1 a 1 1
2 2 b NULL NULL NULL NULL NULL
@@ -82,28 +105,161 @@ grp a c id a c d a
3 5 C 3 5 B 5 5
3 6 D 3 6 C 6 6
NULL NULL NULL NULL NULL NULL NULL
+explain select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on (t1.a=t3.a);
+Cross dependency found in OUTER JOIN. Examine your ON conditions
+select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on (t1.a=t3.a);
+Cross dependency found in OUTER JOIN. Examine your ON conditions
+select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on (t2.a=t3.a);
+Cross dependency found in OUTER JOIN. Examine your ON conditions
+select t1.*,t2.* from t1 inner join t2 using (a);
grp a c id a c d
1 1 a 1 1 a 1
3 4 E 3 4 A 4
3 5 C 3 5 B 5
3 6 D 3 6 C 6
+select t1.*,t2.* from t1 inner join t2 on (t1.a=t2.a);
grp a c id a c d
1 1 a 1 1 a 1
3 4 E 3 4 A 4
3 5 C 3 5 B 5
3 6 D 3 6 C 6
+select t1.*,t2.* from t1 natural join t2;
grp a c id a c d
1 1 a 1 1 a 1
+drop table t1,t2;
+CREATE TABLE t1 (
+usr_id INT unsigned NOT NULL,
+uniq_id INT unsigned NOT NULL AUTO_INCREMENT,
+start_num INT unsigned NOT NULL DEFAULT 1,
+increment INT unsigned NOT NULL DEFAULT 1,
+PRIMARY KEY (uniq_id),
+INDEX usr_uniq_idx (usr_id, uniq_id),
+INDEX uniq_usr_idx (uniq_id, usr_id)
+);
+CREATE TABLE t2 (
+id INT unsigned NOT NULL DEFAULT 0,
+usr2_id INT unsigned NOT NULL DEFAULT 0,
+max INT unsigned NOT NULL DEFAULT 0,
+c_amount INT unsigned NOT NULL DEFAULT 0,
+d_max INT unsigned NOT NULL DEFAULT 0,
+d_num INT unsigned NOT NULL DEFAULT 0,
+orig_time INT unsigned NOT NULL DEFAULT 0,
+c_time INT unsigned NOT NULL DEFAULT 0,
+active ENUM ("no","yes") NOT NULL,
+PRIMARY KEY (id,usr2_id),
+INDEX id_idx (id),
+INDEX usr2_idx (usr2_id)
+);
+INSERT INTO t1 VALUES (3,NULL,0,50),(3,NULL,0,200),(3,NULL,0,25),(3,NULL,0,84676),(3,NULL,0,235),(3,NULL,0,10),(3,NULL,0,3098),(3,NULL,0,2947),(3,NULL,0,8987),(3,NULL,0,8347654),(3,NULL,0,20398),(3,NULL,0,8976),(3,NULL,0,500),(3,NULL,0,198);
+SELECT t1.usr_id,t1.uniq_id,t1.increment,
+t2.usr2_id,t2.c_amount,t2.max
+FROM t1
+LEFT JOIN t2 ON t2.id = t1.uniq_id
+WHERE t1.uniq_id = 4
+ORDER BY t2.c_amount;
usr_id uniq_id increment usr2_id c_amount max
3 4 84676 NULL NULL NULL
+SELECT t1.usr_id,t1.uniq_id,t1.increment,
+t2.usr2_id,t2.c_amount,t2.max
+FROM t2
+RIGHT JOIN t1 ON t2.id = t1.uniq_id
+WHERE t1.uniq_id = 4
+ORDER BY t2.c_amount;
usr_id uniq_id increment usr2_id c_amount max
3 4 84676 NULL NULL NULL
+INSERT INTO t2 VALUES (2,3,3000,6000,0,0,746584,837484,'yes');
+INSERT INTO t2 VALUES (2,3,3000,6000,0,0,746584,837484,'yes');
+Duplicate entry '2-3' for key 1
+INSERT INTO t2 VALUES (7,3,1000,2000,0,0,746294,937484,'yes');
+SELECT t1.usr_id,t1.uniq_id,t1.increment,t2.usr2_id,t2.c_amount,t2.max FROM t1 LEFT JOIN t2 ON t2.id = t1.uniq_id WHERE t1.uniq_id = 4 ORDER BY t2.c_amount;
usr_id uniq_id increment usr2_id c_amount max
3 4 84676 NULL NULL NULL
+SELECT t1.usr_id,t1.uniq_id,t1.increment,t2.usr2_id,t2.c_amount,t2.max FROM t1 LEFT JOIN t2 ON t2.id = t1.uniq_id WHERE t1.uniq_id = 4 GROUP BY t2.c_amount;
usr_id uniq_id increment usr2_id c_amount max
3 4 84676 NULL NULL NULL
+SELECT t1.usr_id,t1.uniq_id,t1.increment,t2.usr2_id,t2.c_amount,t2.max FROM t1 LEFT JOIN t2 ON t2.id = t1.uniq_id WHERE t1.uniq_id = 4;
usr_id uniq_id increment usr2_id c_amount max
3 4 84676 NULL NULL NULL
+drop table t1,t2;
+drop table if exists t1,t2,t3,t4;
+CREATE TABLE t1 (
+cod_asig int(11) DEFAULT '0' NOT NULL,
+desc_larga_cat varchar(80) DEFAULT '' NOT NULL,
+desc_larga_cas varchar(80) DEFAULT '' NOT NULL,
+desc_corta_cat varchar(40) DEFAULT '' NOT NULL,
+desc_corta_cas varchar(40) DEFAULT '' NOT NULL,
+cred_total double(3,1) DEFAULT '0.0' NOT NULL,
+pre_requisit int(11),
+co_requisit int(11),
+preco_requisit int(11),
+PRIMARY KEY (cod_asig)
+);
+INSERT INTO t1 VALUES (10360,'asdfggfg','Introduccion a los Ordenadores I','asdfggfg','Introduccio Ordinadors I',6.0,NULL,NULL,NULL);
+INSERT INTO t1 VALUES (10361,'Components i Circuits Electronics I','Componentes y Circuitos Electronicos I','Components i Circuits Electronics I','Comp. i Circ. Electr. I',6.0,NULL,NULL,NULL);
+INSERT INTO t1 VALUES (10362,'Laboratori d`Ordinadors','Laboratorio de Ordenadores','Laboratori d`Ordinadors','Laboratori Ordinadors',4.5,NULL,NULL,NULL);
+INSERT INTO t1 VALUES (10363,'Tecniques de Comunicacio Oral i Escrita','Tecnicas de Comunicacion Oral y Escrita','Tecniques de Comunicacio Oral i Escrita','Tec. Com. Oral i Escrita',4.5,NULL,NULL,NULL);
+INSERT INTO t1 VALUES (11403,'Projecte Fi de Carrera','Proyecto Fin de Carrera','Projecte Fi de Carrera','PFC',9.0,NULL,NULL,NULL);
+INSERT INTO t1 VALUES (11404,'+lgebra lineal','Algebra lineal','+lgebra lineal','+lgebra lineal',15.0,NULL,NULL,NULL);
+INSERT INTO t1 VALUES (11405,'+lgebra lineal','Algebra lineal','+lgebra lineal','+lgebra lineal',18.0,NULL,NULL,NULL);
+INSERT INTO t1 VALUES (11406,'Calcul Infinitesimal','Cßlculo Infinitesimal','Calcul Infinitesimal','Calcul Infinitesimal',15.0,NULL,NULL,NULL);
+CREATE TABLE t2 (
+idAssignatura int(11) DEFAULT '0' NOT NULL,
+Grup int(11) DEFAULT '0' NOT NULL,
+Places smallint(6) DEFAULT '0' NOT NULL,
+PlacesOcupades int(11) DEFAULT '0',
+PRIMARY KEY (idAssignatura,Grup)
+);
+INSERT INTO t2 VALUES (10360,12,333,0);
+INSERT INTO t2 VALUES (10361,30,2,0);
+INSERT INTO t2 VALUES (10361,40,3,0);
+INSERT INTO t2 VALUES (10360,45,10,0);
+INSERT INTO t2 VALUES (10362,10,12,0);
+INSERT INTO t2 VALUES (10360,55,2,0);
+INSERT INTO t2 VALUES (10360,70,0,0);
+INSERT INTO t2 VALUES (10360,565656,0,0);
+INSERT INTO t2 VALUES (10360,32767,7,0);
+INSERT INTO t2 VALUES (10360,33,8,0);
+INSERT INTO t2 VALUES (10360,7887,85,0);
+INSERT INTO t2 VALUES (11405,88,8,0);
+INSERT INTO t2 VALUES (10360,0,55,0);
+INSERT INTO t2 VALUES (10360,99,0,0);
+INSERT INTO t2 VALUES (11411,30,10,0);
+INSERT INTO t2 VALUES (11404,0,0,0);
+INSERT INTO t2 VALUES (10362,11,111,0);
+INSERT INTO t2 VALUES (10363,33,333,0);
+INSERT INTO t2 VALUES (11412,55,0,0);
+INSERT INTO t2 VALUES (50003,66,6,0);
+INSERT INTO t2 VALUES (11403,5,0,0);
+INSERT INTO t2 VALUES (11406,11,11,0);
+INSERT INTO t2 VALUES (11410,11410,131,0);
+INSERT INTO t2 VALUES (11416,11416,32767,0);
+INSERT INTO t2 VALUES (11409,0,0,0);
+CREATE TABLE t3 (
+id int(11) DEFAULT '0' NOT NULL auto_increment,
+dni_pasaporte char(16) DEFAULT '' NOT NULL,
+idPla int(11) DEFAULT '0' NOT NULL,
+cod_asig int(11) DEFAULT '0' NOT NULL,
+any smallint(6) DEFAULT '0' NOT NULL,
+quatrimestre smallint(6) DEFAULT '0' NOT NULL,
+estat char(1) DEFAULT 'M' NOT NULL,
+PRIMARY KEY (id),
+UNIQUE dni_pasaporte (dni_pasaporte,idPla),
+UNIQUE dni_pasaporte_2 (dni_pasaporte,idPla,cod_asig,any,quatrimestre)
+);
+INSERT INTO t3 VALUES (1,'11111111',1,10362,98,1,'M');
+CREATE TABLE t4 (
+id int(11) DEFAULT '0' NOT NULL auto_increment,
+papa int(11) DEFAULT '0' NOT NULL,
+fill int(11) DEFAULT '0' NOT NULL,
+idPla int(11) DEFAULT '0' NOT NULL,
+PRIMARY KEY (id),
+KEY papa (idPla,papa),
+UNIQUE papa_2 (idPla,papa,fill)
+);
+INSERT INTO t4 VALUES (1,-1,10360,1);
+INSERT INTO t4 VALUES (2,-1,10361,1);
+INSERT INTO t4 VALUES (3,-1,10362,1);
+SELECT DISTINCT fill,desc_larga_cat,cred_total,Grup,Places,PlacesOcupades FROM t4 LEFT JOIN t3 ON t3.cod_asig=fill AND estat='S' AND dni_pasaporte='11111111' AND t3.idPla=1 , t2,t1 WHERE fill=t1.cod_asig AND Places>PlacesOcupades AND fill=idAssignatura AND t4.idPla=1 AND papa=-1;
fill desc_larga_cat cred_total Grup Places PlacesOcupades
10360 asdfggfg 6.0 0 55 0
10360 asdfggfg 6.0 12 333 0
@@ -116,49 +272,82 @@ fill desc_larga_cat cred_total Grup Places PlacesOcupades
10361 Components i Circuits Electronics I 6.0 40 3 0
10362 Laboratori d`Ordinadors 4.5 10 12 0
10362 Laboratori d`Ordinadors 4.5 11 111 0
+SELECT DISTINCT fill,t3.idPla FROM t4 LEFT JOIN t3 ON t3.cod_asig=t4.fill AND t3.estat='S' AND t3.dni_pasaporte='1234' AND t3.idPla=1 ;
fill idPla
10360 NULL
10361 NULL
10362 NULL
+INSERT INTO t3 VALUES (3,'1234',1,10360,98,1,'S');
+SELECT DISTINCT fill,t3.idPla FROM t4 LEFT JOIN t3 ON t3.cod_asig=t4.fill AND t3.estat='S' AND t3.dni_pasaporte='1234' AND t3.idPla=1 ;
fill idPla
10360 1
10361 NULL
10362 NULL
+drop table t1,t2,t3,test.t4;
+CREATE TABLE t1 (
+id smallint(5) unsigned DEFAULT '0' NOT NULL auto_increment,
+name char(60) DEFAULT '' NOT NULL,
+PRIMARY KEY (id)
+);
+INSERT INTO t1 VALUES (1,'Antonio Paz');
+INSERT INTO t1 VALUES (2,'Lilliana Angelovska');
+INSERT INTO t1 VALUES (3,'Thimble Smith');
+CREATE TABLE t2 (
+id smallint(5) unsigned DEFAULT '0' NOT NULL auto_increment,
+owner smallint(5) unsigned DEFAULT '0' NOT NULL,
+name char(60),
+PRIMARY KEY (id)
+);
+INSERT INTO t2 VALUES (1,1,'El Gato');
+INSERT INTO t2 VALUES (2,1,'Perrito');
+INSERT INTO t2 VALUES (3,3,'Happy');
+select t1.name, t2.name, t2.id from t1 left join t2 on (t1.id = t2.owner);
name name id
Antonio Paz El Gato 1
Antonio Paz Perrito 2
Lilliana Angelovska NULL NULL
Thimble Smith Happy 3
+select t1.name, t2.name, t2.id from t1 left join t2 on (t1.id = t2.owner) where t2.id is null;
name name id
Lilliana Angelovska NULL NULL
+explain select t1.name, t2.name, t2.id from t1 left join t2 on (t1.id = t2.owner) where t2.id is null;
table type possible_keys key key_len ref rows Extra
t1 ALL NULL NULL NULL NULL 3
t2 ALL NULL NULL NULL NULL 3 where used; Not exists
+explain select t1.name, t2.name, t2.id from t1 left join t2 on (t1.id = t2.owner) where t2.name is null;
table type possible_keys key key_len ref rows Extra
t1 ALL NULL NULL NULL NULL 3
t2 ALL NULL NULL NULL NULL 3 where used
+select count(*) from t1 left join t2 on (t1.id = t2.owner);
count(*)
4
+select t1.name, t2.name, t2.id from t2 right join t1 on (t1.id = t2.owner);
name name id
Antonio Paz El Gato 1
Antonio Paz Perrito 2
Lilliana Angelovska NULL NULL
Thimble Smith Happy 3
+select t1.name, t2.name, t2.id from t2 right join t1 on (t1.id = t2.owner) where t2.id is null;
name name id
Lilliana Angelovska NULL NULL
+explain select t1.name, t2.name, t2.id from t2 right join t1 on (t1.id = t2.owner) where t2.id is null;
table type possible_keys key key_len ref rows Extra
t1 ALL NULL NULL NULL NULL 3
t2 ALL NULL NULL NULL NULL 3 where used; Not exists
+explain select t1.name, t2.name, t2.id from t2 right join t1 on (t1.id = t2.owner) where t2.name is null;
table type possible_keys key key_len ref rows Extra
t1 ALL NULL NULL NULL NULL 3
t2 ALL NULL NULL NULL NULL 3 where used
+select count(*) from t2 right join t1 on (t1.id = t2.owner);
count(*)
4
+select t1.name, t2.name, t2.id,t3.id from t2 right join t1 on (t1.id = t2.owner) left join t1 as t3 on t3.id=t2.owner;
name name id id
Antonio Paz El Gato 1 1
Antonio Paz Perrito 2 1
Lilliana Angelovska NULL NULL NULL
Thimble Smith Happy 3 3
+select t1.name, t2.name, t2.id,t3.id from t1 right join t2 on (t1.id = t2.owner) right join t1 as t3 on t3.id=t2.owner;
name name id id
Antonio Paz El Gato 1 1
Antonio Paz Perrito 2 1
@@ -169,6 +358,7 @@ NULL Happy 3 2
NULL El Gato 1 3
NULL Perrito 2 3
Thimble Smith Happy 3 3
+select t1.name, t2.name, t2.id, t2.owner, t3.id from t1 left join t2 on (t1.id = t2.owner) right join t1 as t3 on t3.id=t2.owner;
name name id owner id
Antonio Paz El Gato 1 1 1
Antonio Paz Perrito 2 1 1
@@ -180,49 +370,136 @@ Thimble Smith NULL NULL NULL 2
Antonio Paz NULL NULL NULL 3
Lilliana Angelovska NULL NULL NULL 3
Thimble Smith Happy 3 3 3
+drop table t1,t2;
+create table t1 (id int not null, str char(10), index(str));
+insert into t1 values (1, null), (2, null), (3, "foo"), (4, "bar");
+select * from t1 where str is not null;
id str
4 bar
3 foo
+select * from t1 where str is null;
id str
1 NULL
2 NULL
+drop table t1;
+CREATE TABLE t1 (
+t1_id bigint(21) DEFAULT '0' NOT NULL auto_increment,
+PRIMARY KEY (t1_id)
+);
+CREATE TABLE t2 (
+t2_id bigint(21) DEFAULT '0' NOT NULL auto_increment,
+PRIMARY KEY (t2_id)
+);
+CREATE TABLE t3 (
+t3_id bigint(21) DEFAULT '0' NOT NULL auto_increment,
+PRIMARY KEY (t3_id)
+);
+CREATE TABLE t4 (
+seq_0_id bigint(21) DEFAULT '0' NOT NULL,
+seq_1_id bigint(21) DEFAULT '0' NOT NULL,
+KEY seq_0_id (seq_0_id),
+KEY seq_1_id (seq_1_id)
+);
+CREATE TABLE t5 (
+seq_0_id bigint(21) DEFAULT '0' NOT NULL,
+seq_1_id bigint(21) DEFAULT '0' NOT NULL,
+KEY seq_1_id (seq_1_id),
+KEY seq_0_id (seq_0_id)
+);
+insert into t1 values (1);
+insert into t2 values (1);
+insert into t3 values (1);
+insert into t4 values (1,1);
+insert into t5 values (1,1);
+explain select * from t3 left join t4 on t4.seq_1_id = t2.t2_id left join t1 on t1.t1_id = t4.seq_0_id left join t5 on t5.seq_0_id = t1.t1_id left join t2 on t2.t2_id = t5.seq_1_id where t3.t3_id = 23;
+Cross dependency found in OUTER JOIN. Examine your ON conditions
+drop table t1,t2,t3,t4,t5;
+create table t1 (n int, m int, o int, key(n));
+create table t2 (n int not null, m int, o int, primary key(n));
+insert into t1 values (1, 2, 11), (1, 2, 7), (2, 2, 8), (1,2,9),(1,3,9);
+insert into t2 values (1, 2, 3),(2, 2, 8), (4,3,9),(3,2,10);
+select t1.*, t2.* from t1 left join t2 on t1.n = t2.n and
+t1.m = t2.m where t1.n = 1;
n m o n m o
1 2 11 1 2 3
1 2 7 1 2 3
1 2 9 1 2 3
1 3 9 NULL NULL NULL
+select t1.*, t2.* from t1 left join t2 on t1.n = t2.n and
+t1.m = t2.m where t1.n = 1 order by t1.o;
n m o n m o
1 2 7 1 2 3
1 2 9 1 2 3
1 3 9 NULL NULL NULL
1 2 11 1 2 3
+drop table t1,t2;
+CREATE TABLE t1 (id1 INT NOT NULL PRIMARY KEY, dat1 CHAR(1), id2 INT);
+INSERT INTO t1 VALUES (1,'a',1);
+INSERT INTO t1 VALUES (2,'b',1);
+INSERT INTO t1 VALUES (3,'c',2);
+CREATE TABLE t2 (id2 INT NOT NULL PRIMARY KEY, dat2 CHAR(1));
+INSERT INTO t2 VALUES (1,'x');
+INSERT INTO t2 VALUES (2,'y');
+INSERT INTO t2 VALUES (3,'z');
+SELECT t2.id2 FROM t2 LEFT OUTER JOIN t1 ON t1.id2 = t2.id2 WHERE id1 IS NULL;
id2
3
+SELECT t2.id2 FROM t2 NATURAL LEFT OUTER JOIN t1 WHERE id1 IS NULL;
id2
3
+drop table t1,t2;
+create table t1 ( color varchar(20), name varchar(20) );
+insert into t1 values ( 'red', 'apple' );
+insert into t1 values ( 'yellow', 'banana' );
+insert into t1 values ( 'green', 'lime' );
+insert into t1 values ( 'black', 'grape' );
+insert into t1 values ( 'blue', 'blueberry' );
+create table t2 ( count int, color varchar(20) );
+insert into t2 values (10, 'green');
+insert into t2 values (5, 'black');
+insert into t2 values (15, 'white');
+insert into t2 values (7, 'green');
+select * from t1;
color name
red apple
yellow banana
green lime
black grape
blue blueberry
+select * from t2;
count color
10 green
5 black
15 white
7 green
+select * from t2 natural join t1;
count color color name
10 green green lime
7 green green lime
5 black black grape
+select t2.count, t1.name from t2 natural join t1;
count name
10 lime
7 lime
5 grape
+select t2.count, t1.name from t2 inner join t1 using (color);
count name
10 lime
7 lime
5 grape
+drop table t1;
+drop table t2;
+CREATE TABLE t1 (
+pcode varchar(8) DEFAULT '' NOT NULL
+);
+INSERT INTO t1 VALUES ('kvw2000'),('kvw2001'),('kvw3000'),('kvw3001'),('kvw3002'),('kvw3500'),('kvw3501'),('kvw3502'),('kvw3800'),('kvw3801'),('kvw3802'),('kvw3900'),('kvw3901'),('kvw3902'),('kvw4000'),('kvw4001'),('kvw4002'),('kvw4200'),('kvw4500'),('kvw5000'),('kvw5001'),('kvw5500'),('kvw5510'),('kvw5600'),('kvw5601'),('kvw6000'),('klw1000'),('klw1020'),('klw1500'),('klw2000'),('klw2001'),('klw2002'),('kld2000'),('klw2500'),('kmw1000'),('kmw1500'),('kmw2000'),('kmw2001'),('kmw2100'),('kmw3000'),('kmw3200');
+CREATE TABLE t2 (
+pcode varchar(8) DEFAULT '' NOT NULL,
+KEY pcode (pcode)
+);
+INSERT INTO t2 VALUES ('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw6000'),('kvw6000'),('kld2000');
+SELECT t1.pcode, IF(ISNULL(t2.pcode), 0, COUNT(*)) AS count FROM t1
+LEFT JOIN t2 ON t1.pcode = t2.pcode GROUP BY t1.pcode;
pcode count
kld2000 1
klw1000 0
@@ -265,6 +542,7 @@ kvw5510 0
kvw5600 0
kvw5601 0
kvw6000 2
+SELECT SQL_BIG_RESULT t1.pcode, IF(ISNULL(t2.pcode), 0, COUNT(*)) AS count FROM t1 LEFT JOIN t2 ON t1.pcode = t2.pcode GROUP BY t1.pcode;
pcode count
kld2000 1
klw1000 0
@@ -307,27 +585,70 @@ kvw5510 0
kvw5600 0
kvw5601 0
kvw6000 2
+drop table t1,t2;
+CREATE TABLE t1 (
+id int(11),
+pid int(11),
+rep_del tinyint(4),
+KEY id (id),
+KEY pid (pid)
+);
+INSERT INTO t1 VALUES (1,NULL,NULL);
+INSERT INTO t1 VALUES (2,1,NULL);
+select * from t1 LEFT JOIN t1 t2 ON (t1.id=t2.pid) AND t2.rep_del IS NULL;
id pid rep_del id pid rep_del
1 NULL NULL 2 1 NULL
2 1 NULL NULL NULL NULL
+create index rep_del ON t1(rep_del);
+select * from t1 LEFT JOIN t1 t2 ON (t1.id=t2.pid) AND t2.rep_del IS NULL;
id pid rep_del id pid rep_del
1 NULL NULL 2 1 NULL
2 1 NULL NULL NULL NULL
+drop table t1;
+CREATE TABLE t1 (
+id int(11) DEFAULT '0' NOT NULL,
+name tinytext DEFAULT '' NOT NULL,
+UNIQUE id (id)
+);
+INSERT INTO t1 VALUES (1,'yes'),(2,'no');
+CREATE TABLE t2 (
+id int(11) DEFAULT '0' NOT NULL,
+idx int(11) DEFAULT '0' NOT NULL,
+UNIQUE id (id,idx)
+);
+INSERT INTO t2 VALUES (1,1);
+explain SELECT * from t1 left join t2 on t1.id=t2.id where t2.id IS NULL;
table type possible_keys key key_len ref rows Extra
t1 ALL NULL NULL NULL NULL 2
t2 index id id 8 NULL 1 where used; Using index; Not exists
+SELECT * from t1 left join t2 on t1.id=t2.id where t2.id IS NULL;
id name id idx
2 no NULL NULL
+drop table t1,t2;
+create table t1 (bug_id mediumint, reporter mediumint);
+create table t2 (bug_id mediumint, who mediumint, index(who));
+insert into t2 values (1,1),(1,2);
+insert into t1 values (1,1),(2,1);
+SELECT * FROM t1 LEFT JOIN t2 ON (t1.bug_id = t2.bug_id AND t2.who = 2) WHERE (t1.reporter = 2 OR t2.who = 2);
bug_id reporter bug_id who
1 1 1 2
+drop table t1,t2;
+create table t1 (fooID smallint unsigned auto_increment, primary key (fooID));
+create table t2 (fooID smallint unsigned not null, barID smallint unsigned not null, primary key (fooID,barID));
+insert into t1 (fooID) values (10),(20),(30);
+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;
table type possible_keys key key_len ref rows Extra
t2 index NULL PRIMARY 4 NULL 3 Using index
t1 eq_ref PRIMARY PRIMARY 2 const 1 where used; Using index
+select * from t2 left join t1 on t1.fooID = t2.fooID and t1.fooID = 30;
fooID barID fooID
10 1 NULL
20 2 NULL
30 3 30
+select * from t2 left join t1 ignore index(primary) on t1.fooID = t2.fooID and t1.fooID = 30;
fooID barID fooID
10 1 NULL
20 2 NULL
30 3 30
+drop table t1,t2;
diff --git a/mysql-test/r/key.result b/mysql-test/r/key.result
index dbdec824d3b..6dfe0809e7f 100644
--- a/mysql-test/r/key.result
+++ b/mysql-test/r/key.result
@@ -1,19 +1,149 @@
+drop table if exists t1,t2,t3;
+CREATE TABLE t1 (
+ID CHAR(32) NOT NULL,
+name CHAR(32) NOT NULL,
+value CHAR(255),
+INDEX indexIDname (ID(8),name(8))
+) ;
+INSERT INTO t1 VALUES
+('keyword','indexdir','/export/home/local/www/database/indexes/keyword');
+INSERT INTO t1 VALUES ('keyword','urlprefix','text/ /text');
+INSERT INTO t1 VALUES ('keyword','urlmap','/text/ /');
+INSERT INTO t1 VALUES ('keyword','attr','personal employee company');
+INSERT INTO t1 VALUES
+('emailgids','indexdir','/export/home/local/www/database/indexes/emailgids');
+INSERT INTO t1 VALUES ('emailgids','urlprefix','text/ /text');
+INSERT INTO t1 VALUES ('emailgids','urlmap','/text/ /');
+INSERT INTO t1 VALUES ('emailgids','attr','personal employee company');
+SELECT value FROM t1 WHERE ID='emailgids' AND name='attr';
value
personal employee company
+drop table t1;
+CREATE TABLE t1 (
+price int(5) DEFAULT '0' NOT NULL,
+area varchar(40) DEFAULT '' NOT NULL,
+type varchar(40) DEFAULT '' NOT NULL,
+transityes enum('Y','N') DEFAULT 'Y' NOT NULL,
+shopsyes enum('Y','N') DEFAULT 'Y' NOT NULL,
+schoolsyes enum('Y','N') DEFAULT 'Y' NOT NULL,
+petsyes enum('Y','N') DEFAULT 'Y' NOT NULL,
+KEY price (price,area,type,transityes,shopsyes,schoolsyes,petsyes)
+);
+INSERT INTO t1 VALUES (900,'Vancouver','Shared/Roomate','N','N','N','N');
+INSERT INTO t1 VALUES (900,'Vancouver','Shared/Roomate','N','N','N','N');
+INSERT INTO t1 VALUES (900,'Vancouver','Shared/Roomate','','','','');
+INSERT INTO t1 VALUES (900,'Vancouver','Shared/Roomate','Y','Y','Y','Y');
+INSERT INTO t1 VALUES (900,'Vancouver','Shared/Roomate','Y','Y','Y','Y');
+INSERT INTO t1 VALUES (900,'Vancouver','Shared/Roomate','Y','Y','Y','Y');
+INSERT INTO t1 VALUES (900,'Vancouver','Shared/Roomate','Y','Y','Y','Y');
+INSERT INTO t1 VALUES (900,'Vancouver','Shared/Roomate','Y','Y','Y','Y');
+SELECT * FROM t1 WHERE area='Vancouver' and transityes='y' and schoolsyes='y' and ( ((type='1 Bedroom' or type='Studio/Bach') and (price<=500)) or ((type='2 Bedroom') and (price<=550)) or ((type='Shared/Roomate') and (price<=300)) or ((type='Room and Board') and (price<=500)) ) and price <= 400;
price area type transityes shopsyes schoolsyes petsyes
+drop table t1;
+CREATE TABLE t1 (program enum('signup','unique','sliding') not null, type enum('basic','sliding','signup'), sites set('mt'), PRIMARY KEY (program));
+ALTER TABLE t1 modify program enum('signup','unique','sliding');
+All parts of a PRIMARY KEY must be NOT NULL; If you need NULL in a key, use UNIQUE instead
+drop table t1;
+CREATE TABLE t1 (
+name varchar(50) DEFAULT '' NOT NULL,
+author varchar(50) DEFAULT '' NOT NULL,
+category decimal(10,0) DEFAULT '0' NOT NULL,
+email varchar(50),
+password varchar(50),
+proxy varchar(50),
+bitmap varchar(20),
+msg varchar(255),
+urlscol varchar(127),
+urlhttp varchar(127),
+timeout decimal(10,0),
+nbcnx decimal(10,0),
+creation decimal(10,0),
+livinguntil decimal(10,0),
+lang decimal(10,0),
+type decimal(10,0),
+subcat decimal(10,0),
+subtype decimal(10,0),
+reg char(1),
+scs varchar(255),
+capacity decimal(10,0),
+userISP varchar(50),
+CCident varchar(50) DEFAULT '' NOT NULL,
+PRIMARY KEY (name,author,category)
+);
+INSERT INTO t1 VALUES
+('patnom','patauteur',0,'p.favre@cryo-networks.fr',NULL,NULL,'#p2sndnq6ae5g1u6t','essai\nsalut','scol://195.242.78.119:patauteur.patnom',NULL,NULL,NULL,950036174,-882087474,NULL,3,0,3,'1','Pub/patnom/futur_divers.scs',NULL,'pat','CC1');
+INSERT INTO t1 VALUES
+('LeNomDeMonSite','Marc',0,'m.barilley@cryo-networks.fr',NULL,NULL,NULL,NULL,'scol://195.242.78.119:Marc.LeNomDeMonSite',NULL,NULL,NULL,950560434,-881563214,NULL,3,0,3,'1','Pub/LeNomDeMonSite/domus_hibere.scs',NULL,'Marq','CC1');
+select * from t1 where name='patnom' and author='patauteur' and category=0;
name author category email password proxy bitmap msg urlscol urlhttp timeout nbcnx creation livinguntil lang type subcat subtype reg scs capacity userISP CCident
patnom patauteur 0 p.favre@cryo-networks.fr NULL NULL #p2sndnq6ae5g1u6t essai
salut scol://195.242.78.119:patauteur.patnom NULL NULL NULL 950036174 -882087474 NULL 3 0 3 1 Pub/patnom/futur_divers.scs NULL pat CC1
+drop table t1;
+create table t1
+(
+name_id int not null auto_increment,
+name blob,
+INDEX name_idx (name(5)),
+primary key (name_id)
+);
+INSERT t1 VALUES(NULL,'/');
+INSERT t1 VALUES(NULL,'[T,U]_axpby');
+SELECT * FROM t1 WHERE name='[T,U]_axpy';
name_id name
+SELECT * FROM t1 WHERE name='[T,U]_axpby';
name_id name
2 [T,U]_axpby
+create table t2
+(
+name_id int not null auto_increment,
+name char(255) binary,
+INDEX name_idx (name(5)),
+primary key (name_id)
+);
+INSERT t2 select * from t1;
+SELECT * FROM t2 WHERE name='[T,U]_axpy';
name_id name
+SELECT * FROM t2 WHERE name='[T,U]_axpby';
name_id name
2 [T,U]_axpby
+drop table t1,t2;
+create table t1
+(
+SEQNO numeric(12 ) not null,
+MOTYPEID numeric(12 ) not null,
+MOINSTANCEID numeric(12 ) not null,
+ATTRID numeric(12 ) not null,
+VALUE varchar(120) not null,
+primary key (SEQNO, MOTYPEID, MOINSTANCEID, ATTRID, VALUE )
+);
+INSERT INTO t1 VALUES (1, 1, 1, 1, 'a');
+INSERT INTO t1 VALUES (1, 1, 1, 1, 'b');
+INSERT INTO t1 VALUES (1, 1, 1, 1, 'a');
+Duplicate entry '1-1-1-1-a' for key 1
+drop table t1;
+CREATE TABLE t1 (
+a tinytext NOT NULL,
+b tinyint(3) unsigned NOT NULL default '0',
+PRIMARY KEY (a(32),b)
+) TYPE=MyISAM;
+INSERT INTO t1 VALUES ('a',1),('a',2);
+SELECT * FROM t1 WHERE a='a' AND b=2;
a b
a 2
+SELECT * FROM t1 WHERE a='a' AND b in (2);
a b
a 2
+SELECT * FROM t1 WHERE a='a' AND b in (1,2);
a b
a 1
a 2
+drop table t1;
+create table t1 (a int not null unique, b int unique, c int, d int not null primary key, key(c), e int not null unique);
+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 d A 0 NULL NULL BTREE
+t1 0 a 1 a A 0 NULL NULL BTREE
+t1 0 e 1 e A 0 NULL NULL BTREE
+t1 0 b 1 b A NULL NULL NULL YES BTREE
+t1 1 c 1 c A NULL NULL NULL YES BTREE
+drop table t1;
diff --git a/mysql-test/r/key_diff.result b/mysql-test/r/key_diff.result
index ab5b9bcc0e7..0886850f38a 100644
--- a/mysql-test/r/key_diff.result
+++ b/mysql-test/r/key_diff.result
@@ -1,3 +1,12 @@
+drop table if exists t1;
+CREATE TABLE t1 (
+a char(5) NOT NULL,
+b char(4) NOT NULL,
+KEY (a),
+KEY (b)
+);
+INSERT INTO t1 VALUES ('A','B'),('b','A'),('C','c'),('D','E'),('a','a');
+select * from t1,t1 as t2;
a b a b
A B A B
b A A B
@@ -24,9 +33,11 @@ b A a a
C c a a
D E a a
a a a a
+explain select t1.*,t2.* from t1,t1 as t2 where t1.A=t2.B;
table type possible_keys key key_len ref rows Extra
t1 ALL a NULL NULL NULL 5
t2 ALL b NULL NULL NULL 5 where used
+select t1.*,t2.* from t1,t1 as t2 where t1.A=t2.B order by binary t1.a,t2.a;
a b a b
A B a a
A B b A
@@ -34,6 +45,8 @@ C c C c
a a a a
a a b A
b A A B
+select * from t1 where a='a';
a b
A B
a a
+drop table t1;
diff --git a/mysql-test/r/key_primary.result b/mysql-test/r/key_primary.result
index ee0c1c957dc..10771a134fc 100644
--- a/mysql-test/r/key_primary.result
+++ b/mysql-test/r/key_primary.result
@@ -1,9 +1,19 @@
+create table t1 (t1 char(3) primary key);
+insert into t1 values("ABC");
+insert into t1 values("ABA");
+insert into t1 values("AB%");
+select * from t1 where t1="ABC";
t1
ABC
+select * from t1 where t1="ABCD";
t1
+select * from t1 where t1 like "a_\%";
t1
AB%
+describe select * from t1 where t1="ABC";
table type possible_keys key key_len ref rows Extra
t1 const PRIMARY PRIMARY 3 const 1
+describe select * from t1 where t1="ABCD";
Comment
Impossible WHERE noticed after reading const tables
+drop table t1;
diff --git a/mysql-test/r/keywords.result b/mysql-test/r/keywords.result
index f49681ad93b..2ca36425841 100644
--- a/mysql-test/r/keywords.result
+++ b/mysql-test/r/keywords.result
@@ -1,4 +1,16 @@
+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");
+select * from t1;
time date timestamp
12:22:22 1997-02-03 19970102000000
+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
+drop table t1;
+create table events(binlog int);
+insert into events values(1);
+select events.binlog from events;
+binlog
+1
+drop table events;
diff --git a/mysql-test/r/kill.result b/mysql-test/r/kill.result
index 628c6d21094..788fab8d31a 100644
--- a/mysql-test/r/kill.result
+++ b/mysql-test/r/kill.result
@@ -1,4 +1,11 @@
+drop table if exists t1;
+create table t1 (kill_id int);
+insert into t1 values(connection_id());
+select ((@id := kill_id) - kill_id) from t1;
((@id := kill_id) - kill_id)
0
+kill @id;
+select 4;
4
4
+drop table t1;
diff --git a/mysql-test/r/limit.result b/mysql-test/r/limit.result
index 6c3a1ed17e4..5a8edc99c12 100644
--- a/mysql-test/r/limit.result
+++ b/mysql-test/r/limit.result
@@ -1,25 +1,52 @@
+drop table if exists t1;
+create table t1 (a int primary key, b int not null);
+insert into t1 () values ();
+insert into t1 values (1,1),(2,1),(3,1);
+update t1 set a=4 where b=1 limit 1;
+select * from t1;
a b
0 0
4 1
2 1
3 1
+update t1 set b=2 where b=1 limit 2;
+select * from t1;
a b
0 0
4 2
2 2
3 1
+update t1 set b=4 where b=1;
+select * from t1;
a b
0 0
4 2
2 2
3 4
+delete from t1 where b=2 limit 1;
+select * from t1;
a b
0 0
2 2
3 4
+delete from t1 limit 1;
+select * from t1;
a b
2 2
3 4
+drop table t1;
+create table t1 (i int);
+insert into t1 (i) values(1);
+insert into t1 (i) values(1);
+insert into t1 (i) values(1);
+delete from t1 limit 1;
+update t1 set i=2 limit 1;
+delete from t1 limit 0;
+update t1 set i=3 limit 0;
+select * from t1;
i
2
1
+drop table t1;
+select 0 limit 0;
+0
diff --git a/mysql-test/r/lock.result b/mysql-test/r/lock.result
index ccd3c02558d..ad5251b9110 100644
--- a/mysql-test/r/lock.result
+++ b/mysql-test/r/lock.result
@@ -1,10 +1,45 @@
+drop table if exists t1,t2;
+CREATE TABLE t1 ( `id` int(11) NOT NULL default '0', `id2` int(11) NOT NULL default '0', `id3` int(11) NOT NULL default '0', `dummy1` char(30) default NULL, PRIMARY KEY (`id`,`id2`), KEY `index_id3` (`id3`)) TYPE=MyISAM;
+insert into t1 (id,id2) values (1,1),(1,2),(1,3);
+LOCK TABLE t1 WRITE;
+select dummy1,count(distinct id) from t1 group by dummy1;
dummy1 count(distinct id)
NULL 1
+update t1 set id=-1 where id=1;
+LOCK TABLE t1 READ;
+update t1 set id=1 where id=1;
+Table 't1' was locked with a READ lock and can't be updated
+create table t2 SELECT * from t1;
+Table 't2' was not locked with LOCK TABLES
+create temporary table t2 SELECT * from t1;
+drop table if exists t2;
+unlock tables;
+create table t2 SELECT * from t1;
+LOCK TABLE t1 WRITE,t2 write;
+insert into t2 SELECT * from t1;
+update t1 set id=1 where id=-1;
+drop table t1,t2;
+CREATE TABLE t1 (
+index1 smallint(6) default NULL,
+nr smallint(6) default NULL,
+KEY index1(index1)
+) TYPE=MyISAM;
+CREATE TABLE t2 (
+nr smallint(6) default NULL,
+name varchar(20) default NULL
+) TYPE=MyISAM;
+INSERT INTO t2 VALUES (1,'item1');
+INSERT INTO t2 VALUES (2,'item2');
+lock tables t1 write, t2 read;
+insert into t1 select 1,nr from t2 where name='item1';
+insert into t1 select 2,nr from t2 where name='item2';
+unlock tables;
+check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
+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
-n
-4
-n
-1
+unlock tables;
+drop table t1,t2;
diff --git a/mysql-test/r/lock_multi.result b/mysql-test/r/lock_multi.result
new file mode 100644
index 00000000000..6fe8cc71185
--- /dev/null
+++ b/mysql-test/r/lock_multi.result
@@ -0,0 +1,18 @@
+create table t1(n int);
+insert into t1 values (1);
+lock tables t1 write;
+ update low_priority t1 set n = 4;
+ select n from t1;
+unlock tables;
+n
+4
+drop table t1;
+create table t1(n int);
+insert into t1 values (1);
+lock tables t1 read;
+ update low_priority t1 set n = 4;
+ select n from t1;
+unlock tables;
+n
+1
+drop table t1;
diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result
index 653e25af799..9b72ff26350 100644
--- a/mysql-test/r/merge.result
+++ b/mysql-test/r/merge.result
@@ -1,3 +1,10 @@
+drop table if exists t1,t2,t3,t4,t5,t6;
+create table t1 (a int not null primary key auto_increment, message char(20));
+create table t2 (a int not null primary key auto_increment, message char(20));
+INSERT INTO t1 (message) VALUES ("Testing"),("table"),("t1");
+INSERT INTO t2 (message) VALUES ("Testing"),("table"),("t2");
+create table t3 (a int not null, b char(20), key(a)) type=MERGE UNION=(t1,t2);
+select * from t3;
a b
1 Testing
2 table
@@ -5,6 +12,7 @@ a b
1 Testing
2 table
3 t2
+select * from t3 order by a desc;
a b
3 t1
3 t2
@@ -12,13 +20,30 @@ a b
2 table
1 Testing
1 Testing
+drop table t3;
+insert into t1 select NULL,message from t2;
+insert into t2 select NULL,message from t1;
+insert into t1 select NULL,message from t2;
+insert into t2 select NULL,message from t1;
+insert into t1 select NULL,message from t2;
+insert into t2 select NULL,message from t1;
+insert into t1 select NULL,message from t2;
+insert into t2 select NULL,message from t1;
+insert into t1 select NULL,message from t2;
+insert into t2 select NULL,message from t1;
+insert into t1 select NULL,message from t2;
+create table t3 (a int not null, b char(20), key(a)) type=MERGE UNION=(test.t1,test.t2);
+explain select * from t3 where a < 10;
table type possible_keys key key_len ref rows Extra
t3 range a a 4 NULL 10 where used
+explain select * from t3 where a > 10 and a < 20;
table type possible_keys key key_len ref rows Extra
t3 range a a 4 NULL 10 where used
+select * from t3 where a = 10;
a b
10 Testing
10 Testing
+select * from t3 where a < 10;
a b
1 Testing
1 Testing
@@ -38,6 +63,7 @@ a b
8 table
9 t2
9 t2
+select * from t3 where a > 10 and a < 20;
a b
11 table
11 table
@@ -57,8 +83,10 @@ a b
18 t2
19 Testing
19 Testing
+explain select a from t3 order by a desc limit 10;
table type possible_keys key key_len ref rows Extra
t3 index NULL a 4 NULL 1131 Using index
+select a from t3 order by a desc limit 10;
a
699
698
@@ -70,6 +98,7 @@ a
692
691
690
+select a from t3 order by a desc limit 300,10;
a
416
415
@@ -81,12 +110,87 @@ a
412
412
411
+delete from t3 where a=3;
+select * from t3 where a < 10;
+a b
+1 Testing
+1 Testing
+2 table
+2 table
+4 Testing
+4 Testing
+5 table
+5 table
+6 t2
+6 t1
+7 Testing
+7 Testing
+8 table
+8 table
+9 t2
+9 t2
+delete from t3 where a >= 6 and a <= 8;
+select * from t3 where a < 10;
+a b
+1 Testing
+1 Testing
+2 table
+2 table
+4 Testing
+4 Testing
+5 table
+5 table
+9 t2
+9 t2
+update t3 set a=3 where a=9;
+select * from t3 where a < 10;
+a b
+1 Testing
+1 Testing
+2 table
+2 table
+3 t2
+3 t2
+4 Testing
+4 Testing
+5 table
+5 table
+update t3 set a=6 where a=7;
+select * from t3 where a < 10;
+a b
+1 Testing
+1 Testing
+2 table
+2 table
+3 t2
+3 t2
+4 Testing
+4 Testing
+5 table
+5 table
+show create table t3;
Table Create Table
t3 CREATE TABLE `t3` (
`a` int(11) NOT NULL default '0',
`b` char(20) default NULL,
KEY `a` (`a`)
) TYPE=MRG_MyISAM UNION=(t1,t2)
+create table t4 (a int not null, b char(10), key(a)) type=MERGE UNION=(t1,t2);
+select * from t4;
+Can't open file: 't4.MRG'. (errno: 143)
+create table t5 (a int not null, b char(10), key(a)) type=MERGE UNION=(test.t1,test_2.t2);
+Incorrect table definition; All MERGE tables must be in the same database
+drop table if exists t5,t4,t3,t1,t2;
+create table t1 (c char(10)) type=myisam;
+create table t2 (c char(10)) type=myisam;
+create table t3 (c char(10)) union=(t1,t2) type=merge;
+insert into t1 (c) values ('test1');
+insert into t1 (c) values ('test1');
+insert into t1 (c) values ('test1');
+insert into t2 (c) values ('test2');
+insert into t2 (c) values ('test2');
+insert into t2 (c) values ('test2');
+select * from t3;
c
test1
test1
@@ -94,6 +198,7 @@ test1
test2
test2
test2
+select * from t3;
c
test1
test1
@@ -101,32 +206,259 @@ test1
test2
test2
test2
+delete from t3 where 1=1;
+select * from t3;
c
+select * from t1;
c
+drop table t3,t2,t1;
+CREATE TABLE t1 (incr int not null, othr int not null, primary key(incr));
+CREATE TABLE t2 (incr int not null, othr int not null, primary key(incr));
+CREATE TABLE t3 (incr int not null, othr int not null, primary key(incr))
+TYPE=MERGE UNION=(t1,t2);
+SELECT * from t3;
incr othr
+INSERT INTO t1 VALUES ( 1,10),( 3,53),( 5,21),( 7,12),( 9,17);
+INSERT INTO t2 VALUES ( 2,24),( 4,33),( 6,41),( 8,26),( 0,32);
+INSERT INTO t1 VALUES (11,20),(13,43),(15,11),(17,22),(19,37);
+INSERT INTO t2 VALUES (12,25),(14,31),(16,42),(18,27),(10,30);
+SELECT * from t3 where incr in (1,2,3,4) order by othr;
incr othr
1 10
2 24
4 33
3 53
+alter table t3 UNION=(t1);
+select count(*) from t3;
count(*)
10
+alter table t3 UNION=(t1,t2);
+select count(*) from t3;
count(*)
20
+alter table t3 TYPE=MYISAM;
+select count(*) from t3;
count(*)
20
+drop table t3;
+CREATE TABLE t3 (incr int not null, othr int not null, primary key(incr))
+TYPE=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',
PRIMARY KEY (`incr`)
) TYPE=MRG_MyISAM 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'
) TYPE=MRG_MyISAM UNION=(t1,t2)
+drop table t3,t2,t1;
+create table t1 (a int not null) type=merge;
+select * from t1;
a
+drop table t1;
+drop table if exists t3, t2, t1;
+create table t1 (a int not null, b int not null, key(a,b));
+create table t2 (a int not null, b int not null, key(a,b));
+create table t3 (a int not null, b int not null, key(a,b)) TYPE=MERGE UNION=(t1,t2);
+insert into t1 values (1,2),(2,1),(0,0),(4,4),(5,5),(6,6);
+insert into t2 values (1,1),(2,2),(0,0),(4,4),(5,5),(6,6);
+flush tables;
+select * from t3 where a=1 order by b limit 2;
+a b
+1 1
+1 2
+drop table t3,t1,t2;
+drop table if exists t6, t5, t4, t3, t2, t1;
+create table t1 (a int not null, b int not null, key(a,b));
+create table t2 (a int not null, b int not null, key(a,b));
+create table t3 (a int not null, b int not null, key(a,b)) UNION=(t1,t2) INSERT_METHOD=NO;
+create table t4 (a int not null, b int not null, key(a,b)) TYPE=MERGE UNION=(t1,t2) INSERT_METHOD=NO;
+create table t5 (a int not null, b int not null, key(a,b)) TYPE=MERGE UNION=(t1,t2) INSERT_METHOD=FIRST;
+create table t6 (a int not null, b int not null, key(a,b)) TYPE=MERGE UNION=(t1,t2) INSERT_METHOD=LAST;
+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',
+ KEY `a` (`a`,`b`)
+) TYPE=MyISAM
+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',
+ KEY `a` (`a`,`b`)
+) TYPE=MRG_MyISAM UNION=(t1,t2)
+show create table t5;
+Table Create Table
+t5 CREATE TABLE `t5` (
+ `a` int(11) NOT NULL default '0',
+ `b` int(11) NOT NULL default '0',
+ KEY `a` (`a`,`b`)
+) TYPE=MRG_MyISAM INSERT_METHOD=FIRST UNION=(t1,t2)
+show create table t6;
+Table Create Table
+t6 CREATE TABLE `t6` (
+ `a` int(11) NOT NULL default '0',
+ `b` int(11) NOT NULL default '0',
+ KEY `a` (`a`,`b`)
+) TYPE=MRG_MyISAM INSERT_METHOD=LAST UNION=(t1,t2)
+insert into t1 values (1,1),(1,2),(1,3),(1,4);
+insert into t2 values (2,1),(2,2),(2,3),(2,4);
+select * from t3 order by b,a limit 3;
+a b
+select * from t4 order by b,a limit 3;
+a b
+1 1
+2 1
+1 2
+select * from t5 order by b,a limit 3,3;
+a b
+2 2
+1 3
+2 3
+select * from t6 order by b,a limit 6,3;
+a b
+1 4
+2 4
+insert into t5 values (5,1),(5,2);
+insert into t6 values (6,1),(6,2);
+select * from t1 order by a,b;
+a b
+1 1
+1 2
+1 3
+1 4
+5 1
+5 2
+select * from t2 order by a,b;
+a b
+2 1
+2 2
+2 3
+2 4
+6 1
+6 2
+select * from t4 order by a,b;
+a b
+1 1
+1 2
+1 3
+1 4
+2 1
+2 2
+2 3
+2 4
+5 1
+5 2
+6 1
+6 2
+insert into t3 values (3,1),(3,2),(3,3),(3,4);
+select * from t3 order by a,b;
+a b
+3 1
+3 2
+3 3
+3 4
+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',
+ KEY `a` (`a`,`b`)
+) TYPE=MRG_MyISAM UNION=(t1,t2,t3)
+select * from t4 order by a,b;
+a b
+1 1
+1 2
+1 3
+1 4
+2 1
+2 2
+2 3
+2 4
+3 1
+3 2
+3 3
+3 4
+5 1
+5 2
+6 1
+6 2
+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',
+ KEY `a` (`a`,`b`)
+) TYPE=MRG_MyISAM INSERT_METHOD=FIRST UNION=(t1,t2,t3)
+insert into t4 values (4,1),(4,2);
+select * from t1 order by a,b;
+a b
+1 1
+1 2
+1 3
+1 4
+4 1
+4 2
+5 1
+5 2
+select * from t2 order by a,b;
+a b
+2 1
+2 2
+2 3
+2 4
+6 1
+6 2
+select * from t3 order by a,b;
+a b
+3 1
+3 2
+3 3
+3 4
+select * from t4 order by a,b;
+a b
+1 1
+1 2
+1 3
+1 4
+2 1
+2 2
+2 3
+2 4
+3 1
+3 2
+3 3
+3 4
+4 1
+4 2
+5 1
+5 2
+6 1
+6 2
+select * from t5 order by a,b;
a b
1 1
1 2
+1 3
+1 4
+2 1
+2 2
+2 3
+2 4
+4 1
+4 2
+5 1
+5 2
+6 1
+6 2
+drop table if exists t6, t5, t4, t3, t2, t1;
diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result
new file mode 100644
index 00000000000..b1423667c44
--- /dev/null
+++ b/mysql-test/r/multi_update.result
@@ -0,0 +1,41 @@
+drop table if exists t1,t2,t3;
+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));
+update t1,t2,t3 set t1.t="aaa", t2.t="bbb", t3.t="cc" where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 90;
+delete t1.*, t2.*, t3.* from t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 95;
+check table t1, t2, t3;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+test.t2 check status OK
+test.t3 check status OK
+select count(*) from t1 where id1 > 95;
+count(*)
+0
+select count(*) from t2 where id2 > 95;
+count(*)
+0
+select count(*) from t3 where id3 > 95;
+count(*)
+0
+delete t1, t2, t3 from t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 5;
+select count(*) from t1 where id1 > 5;
+count(*)
+0
+select count(*) from t2 where id2 > 5;
+count(*)
+0
+select count(*) from t3 where id3 > 5;
+count(*)
+0
+delete from t1, t2, t3 using t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 0;
+select count(*) from t1 where id1;
+count(*)
+0
+select count(*) from t2 where id2;
+count(*)
+0
+select count(*) from t3 where id3;
+count(*)
+0
+drop table t1,t2,t3;
diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result
index a8f97c57d33..c5c69c1ba7b 100644
--- a/mysql-test/r/myisam.result
+++ b/mysql-test/r/myisam.result
@@ -1,38 +1,77 @@
+drop table if exists t1;
+CREATE TABLE t1 (
+STRING_DATA char(255) default NULL,
+KEY STRING_DATA (STRING_DATA)
+) TYPE=MyISAM;
+INSERT INTO t1 VALUES ('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
+INSERT INTO t1 VALUES ('DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD');
+INSERT INTO t1 VALUES ('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF');
+INSERT INTO t1 VALUES ('FGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG');
+INSERT INTO t1 VALUES ('HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH');
+INSERT INTO t1 VALUES ('WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW');
+CHECK TABLE t1;
Table Op Msg_type Msg_text
test.t1 check status OK
+drop table t1;
+create table t1 (a tinyint not null auto_increment, b blob not null, primary key (a));
+check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
+repair table t1;
Table Op Msg_type Msg_text
test.t1 repair status OK
+delete from t1 where (a & 1);
+check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
+repair table t1;
Table Op Msg_type Msg_text
test.t1 repair status OK
+check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
+drop table t1;
+create table t1 (a int not null auto_increment, b int not null, primary key (a), index(b));
+insert into t1 (b) values (1),(2),(2),(2),(2);
+optimize table t1;
Table Op Msg_type Msg_text
test.t1 optimize status OK
-Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Comment
-t1 0 PRIMARY 1 a A 5 NULL NULL
-t1 1 b 1 b A 1 NULL NULL
+show index from t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 0 PRIMARY 1 a A 5 NULL NULL BTREE
+t1 1 b 1 b A 1 NULL NULL BTREE
+optimize table t1;
Table Op Msg_type Msg_text
test.t1 optimize status Table is already up to date
-Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Comment
-t1 0 PRIMARY 1 a A 5 NULL NULL
-t1 1 b 1 b A 1 NULL NULL
+show index from t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 0 PRIMARY 1 a A 5 NULL NULL BTREE
+t1 1 b 1 b A 1 NULL NULL BTREE
+drop table t1;
+create table t1 (a int not null, b int not null, c int not null, primary key (a),key(b)) type=myisam;
+insert into t1 values (3,3,3),(1,1,1),(2,2,2),(4,4,4);
+explain select * from t1 order by a;
table type possible_keys key key_len ref rows Extra
t1 ALL NULL NULL NULL NULL 4 Using filesort
+explain select * from t1 order by b;
table type possible_keys key key_len ref rows Extra
t1 ALL NULL NULL NULL NULL 4 Using filesort
+explain select * from t1 order by c;
table type possible_keys key key_len ref rows Extra
t1 ALL NULL NULL NULL NULL 4 Using filesort
+explain select a from t1 order by a;
table type possible_keys key key_len ref rows Extra
t1 index NULL PRIMARY 4 NULL 4 Using index
+explain select b from t1 order by b;
table type possible_keys key key_len ref rows Extra
t1 index NULL b 4 NULL 4 Using index
+explain select a,b from t1 order by b;
table type possible_keys key key_len ref rows Extra
t1 ALL NULL NULL NULL NULL 4 Using filesort
+explain select a,b from t1;
table type possible_keys key key_len ref rows Extra
t1 ALL NULL NULL NULL NULL 4
+explain select a,b,c from t1;
table type possible_keys key key_len ref rows Extra
t1 ALL NULL NULL NULL NULL 4
+drop table t1;
diff --git a/mysql-test/r/not_embedded.require b/mysql-test/r/not_embedded.require
new file mode 100644
index 00000000000..b2ea98bcd0a
--- /dev/null
+++ b/mysql-test/r/not_embedded.require
@@ -0,0 +1,2 @@
+have_embedded
+0
diff --git a/mysql-test/r/null.result b/mysql-test/r/null.result
index 9f0bdb07973..e6e3b7155a3 100644
--- a/mysql-test/r/null.result
+++ b/mysql-test/r/null.result
@@ -1,32 +1,58 @@
+select null,\N,isnull(null),isnull(1/0),isnull(1/0 = null),ifnull(null,1),ifnull(null,"TRUE"),ifnull("TRUE","ERROR"),1/0 is null,1 is not null;
NULL NULL isnull(null) isnull(1/0) isnull(1/0 = null) ifnull(null,1) ifnull(null,"TRUE") ifnull("TRUE","ERROR") 1/0 is null 1 is not null
NULL NULL 1 1 1 1 TRUE TRUE 1 1
+select 1 | NULL,1 & NULL,1+NULL,1-NULL;
1 | NULL 1 & NULL 1+NULL 1-NULL
NULL NULL NULL NULL
+select NULL=NULL,NULL<>NULL,IFNULL(NULL,1.1)+0,IFNULL(NULL,1) | 0;
NULL=NULL NULL<>NULL IFNULL(NULL,1.1)+0 IFNULL(NULL,1) | 0
NULL NULL 1.1 1
+select strcmp("a",NULL),(1<NULL)+0.0,NULL regexp "a",null like "a%","a%" like null;
strcmp("a",NULL) (1<NULL)+0.0 NULL regexp "a" null like "a%" "a%" like null
NULL NULL NULL NULL NULL
+select concat("a",NULL),replace(NULL,"a","b"),replace("string","i",NULL),replace("string",NULL,"i"),insert("abc",1,1,NULL),left(NULL,1);
concat("a",NULL) replace(NULL,"a","b") replace("string","i",NULL) replace("string",NULL,"i") insert("abc",1,1,NULL) left(NULL,1)
NULL NULL NULL NULL NULL NULL
+select repeat("a",0),repeat("ab",5+5),repeat("ab",-1),reverse(NULL);
repeat("a",0) repeat("ab",5+5) repeat("ab",-1) reverse(NULL)
abababababababababab NULL
+select field(NULL,"a","b","c");
field(NULL,"a","b","c")
0
+select 2 between null and 1,2 between 3 AND NULL,NULL between 1 and 2,2 between NULL and 3, 2 between 1 AND null;
2 between null and 1 2 between 3 AND NULL NULL between 1 and 2 2 between NULL and 3 2 between 1 AND null
0 0 NULL NULL NULL
+SELECT NULL AND NULL, 1 AND NULL, NULL AND 1, NULL OR NULL, 0 OR NULL, NULL OR 0;
NULL AND NULL 1 AND NULL NULL AND 1 NULL OR NULL 0 OR NULL NULL OR 0
NULL NULL NULL NULL NULL NULL
+SELECT (NULL OR NULL) IS NULL;
(NULL OR NULL) IS NULL
1
+select NULL AND 0, 0 and NULL;
NULL AND 0 0 and NULL
NULL 0
+select inet_ntoa(null),inet_aton(null),inet_aton("122.256"),inet_aton("122.226."),inet_aton("");
inet_ntoa(null) inet_aton(null) inet_aton("122.256") inet_aton("122.226.") inet_aton("")
NULL NULL NULL NULL NULL
+drop table if exists t1;
+create table t1 (x int);
+insert into t1 values (null);
+select * from t1 where x != 0;
x
+drop table t1;
+CREATE TABLE t1 (
+indexed_field int default NULL,
+KEY indexed_field (indexed_field)
+);
+INSERT INTO t1 VALUES (NULL),(NULL);
+SELECT * FROM t1 WHERE indexed_field=NULL;
indexed_field
+SELECT * FROM t1 WHERE indexed_field IS NULL;
indexed_field
NULL
NULL
+SELECT * FROM t1 WHERE indexed_field<=>NULL;
indexed_field
NULL
NULL
+DROP TABLE t1;
diff --git a/mysql-test/r/null_key.result b/mysql-test/r/null_key.result
index ead1dc29326..a28830a696d 100644
--- a/mysql-test/r/null_key.result
+++ b/mysql-test/r/null_key.result
@@ -1,101 +1,164 @@
+drop table if exists t1;
+create table t1 (a int, b int not null,unique key (a,b),index(b)) type=myisam;
+insert ignore into t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(null,7),(9,9),(8,8),(7,7),(null,9),(null,9),(6,6);
+explain select * from t1 where a is null;
table type possible_keys key key_len ref rows Extra
t1 ref a a 5 const 3 where used; Using index
+explain select * from t1 where a is null and b = 2;
table type possible_keys key key_len ref rows Extra
t1 ref a,b a 9 const,const 1 where used; Using index
+explain select * from t1 where a is null and b = 7;
table type possible_keys key key_len ref rows Extra
t1 ref a,b a 9 const,const 1 where used; Using index
+explain select * from t1 where a=2 and b = 2;
table type possible_keys key key_len ref rows Extra
t1 const a,b a 9 const,const 1
+explain select * from t1 where a<=>b limit 2;
table type possible_keys key key_len ref rows Extra
t1 index NULL a 9 NULL 12 where used; Using index
+explain select * from t1 where (a is null or a > 0 and a < 3) and b < 5 limit 3;
table type possible_keys key key_len ref rows Extra
t1 range a,b a 9 NULL 3 where used; Using index
+explain select * from t1 where (a is null or a = 7) and b=7;
table type possible_keys key key_len ref rows Extra
t1 ref a,b b 4 const 2 where used
+explain select * from t1 where (a is null and b>a) or a is null and b=7 limit 2;
table type possible_keys key key_len ref rows Extra
t1 ref a,b a 5 const 3 where used; Using index
+explain select * from t1 where a is null and b=9 or a is null and b=7 limit 3;
table type possible_keys key key_len ref rows Extra
t1 range a,b a 9 NULL 2 where used; Using index
+explain select * from t1 where a > 1 and a < 3 limit 1;
table type possible_keys key key_len ref rows Extra
t1 range a a 5 NULL 1 where used; Using index
+explain select * from t1 where a > 8 and a < 9;
table type possible_keys key key_len ref rows Extra
t1 range a a 5 NULL 1 where used; Using index
+select * from t1 where a is null;
a b
NULL 7
NULL 9
NULL 9
+select * from t1 where a is null and b = 7;
a b
NULL 7
+select * from t1 where a<=>b limit 2;
a b
1 1
2 2
+select * from t1 where (a is null or a > 0 and a < 3) and b < 5 limit 3;
a b
1 1
2 2
+select * from t1 where (a is null or a > 0 and a < 3) and b > 7 limit 3;
a b
NULL 9
NULL 9
+select * from t1 where (a is null or a = 7) and b=7;
a b
NULL 7
7 7
+select * from t1 where a is null and b=9 or a is null and b=7 limit 3;
a b
NULL 7
NULL 9
NULL 9
+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));
+explain select * from t1 where a is null and b = 2;
table type possible_keys key key_len ref rows Extra
t1 ref a,b a 5 const 3 where used
+explain select * from t1 where a is null and b = 2 and c=0;
table type possible_keys key key_len ref rows Extra
t1 ref a,b a 5 const 3 where used
+explain select * from t1 where a is null and b = 7 and c=0;
table type possible_keys key key_len ref rows Extra
t1 ref a,b a 5 const 3 where used
+explain select * from t1 where a=2 and b = 2;
table type possible_keys key key_len ref rows Extra
t1 ref a,b a 5 const 1 where used
+explain select * from t1 where a<=>b limit 2;
table type possible_keys key key_len ref rows Extra
t1 ALL NULL NULL NULL NULL 12 where used
+explain select * from t1 where (a is null or a > 0 and a < 3) and b < 5 and c=0 limit 3;
table type possible_keys key key_len ref rows Extra
-t1 range a,b a 5 NULL 12 where used
+t1 range a,b a 5 NULL 5 where used
+explain select * from t1 where (a is null or a = 7) and b=7 and c=0;
table type possible_keys key key_len ref rows Extra
t1 range a,b a 5 NULL 4 where used
+explain select * from t1 where (a is null and b>a) or a is null and b=7 limit 2;
table type possible_keys key key_len ref rows Extra
t1 ref a,b a 5 const 3 where used
+explain select * from t1 where a is null and b=9 or a is null and b=7 limit 3;
table type possible_keys key key_len ref rows Extra
t1 ref a,b a 5 const 3 where used
+explain select * from t1 where a > 1 and a < 3 limit 1;
table type possible_keys key key_len ref rows Extra
t1 range a a 5 NULL 1 where used
+explain select * from t1 where a is null and b=7 or a > 1 and a < 3 limit 1;
table type possible_keys key key_len ref rows Extra
t1 range a,b a 5 NULL 4 where used
+explain select * from t1 where a > 8 and a < 9;
table type possible_keys key key_len ref rows Extra
t1 range a a 5 NULL 1 where used
+explain select * from t1 where b like "6%";
table type possible_keys key key_len ref rows Extra
t1 range b b 12 NULL 1 where used
+select * from t1 where a is null;
a b c
NULL 7 0
NULL 9 0
NULL 9 0
+select * from t1 where a is null and b = 7 and c=0;
a b c
NULL 7 0
+select * from t1 where a<=>b limit 2;
a b c
1 1 0
2 2 0
+select * from t1 where (a is null or a > 0 and a < 3) and b < 5 limit 3;
a b c
1 1 0
2 2 0
+select * from t1 where (a is null or a > 0 and a < 3) and b > 7 limit 3;
a b c
NULL 9 0
NULL 9 0
+select * from t1 where (a is null or a = 7) and b=7 and c=0;
a b c
NULL 7 0
7 7 0
+select * from t1 where a is null and b=9 or a is null and b=7 limit 3;
a b c
NULL 7 0
NULL 9 0
NULL 9 0
+select * from t1 where b like "6%";
a b c
6 6 0
+drop table t1;
+DROP TABLE IF EXISTS t1,t2;
+CREATE TABLE t1 (
+id int(10) unsigned NOT NULL auto_increment,
+uniq_id int(10) unsigned default NULL,
+PRIMARY KEY (id),
+UNIQUE KEY idx1 (uniq_id)
+) TYPE=MyISAM;
+CREATE TABLE t2 (
+id int(10) unsigned NOT NULL auto_increment,
+uniq_id int(10) unsigned default NULL,
+PRIMARY KEY (id)
+) TYPE=MyISAM;
+INSERT INTO t1 VALUES (1,NULL),(2,NULL),(3,1),(4,2),(5,NULL),(6,NULL),(7,3),(8,4),(9,NULL),(10,NULL);
+INSERT INTO t2 VALUES (1,NULL),(2,NULL),(3,1),(4,2),(5,NULL),(6,NULL),(7,3),(8,4),(9,NULL),(10,NULL);
+explain select id from t1 where uniq_id is null;
table type possible_keys key key_len ref rows Extra
t1 ref idx1 idx1 5 const 1 where used
+explain select id from t1 where uniq_id =1;
table type possible_keys key key_len ref rows Extra
t1 const idx1 idx1 5 const 1
+UPDATE t1 SET id=id+100 where uniq_id is null;
+UPDATE t2 SET id=id+100 where uniq_id is null;
+select id from t1 where uniq_id is null;
id
101
102
@@ -103,6 +166,7 @@ id
106
109
110
+select id from t2 where uniq_id is null;
id
101
102
@@ -110,13 +174,18 @@ id
106
109
110
+DELETE FROM t1 WHERE uniq_id IS NULL;
+DELETE FROM t2 WHERE uniq_id IS NULL;
+SELECT * FROM t1 ORDER BY uniq_id, id;
id uniq_id
3 1
4 2
7 3
8 4
+SELECT * FROM t2 ORDER BY uniq_id, id;
id uniq_id
3 1
4 2
7 3
8 4
+DROP table t1,t2;
diff --git a/mysql-test/r/odbc.result b/mysql-test/r/odbc.result
index 753d80e4539..c696cf94e9d 100644
--- a/mysql-test/r/odbc.result
+++ b/mysql-test/r/odbc.result
@@ -1,7 +1,15 @@
+select {fn length("hello")}, { date "1997-10-20" };
{fn length("hello")} 1997-10-20
5 1997-10-20
+create table t1 (a int not null auto_increment,b int not null,primary key (a,b));
+insert into t1 SET A=NULL,B=1;
+insert into t1 SET a=null,b=2;
+select * from t1 where a is null and b=2;
a b
2 2
+select * from t1 where a is null;
a b
+explain select * from t1 where b is null;
Comment
Impossible WHERE noticed after reading const tables
+drop table t1;
diff --git a/mysql-test/r/openssl_1.result b/mysql-test/r/openssl_1.result
new file mode 100644
index 00000000000..b5c67dfbcb0
--- /dev/null
+++ b/mysql-test/r/openssl_1.result
@@ -0,0 +1,2 @@
+SHOW STATUS LIKE 'SSL%';
+Variable_name Value
diff --git a/mysql-test/r/openssl_2.result b/mysql-test/r/openssl_2.result
new file mode 100644
index 00000000000..b5c67dfbcb0
--- /dev/null
+++ b/mysql-test/r/openssl_2.result
@@ -0,0 +1,2 @@
+SHOW STATUS LIKE 'SSL%';
+Variable_name Value
diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result
index 1a292b1203c..9bc716ee8b9 100644
--- a/mysql-test/r/order_by.result
+++ b/mysql-test/r/order_by.result
@@ -1,3 +1,39 @@
+drop table if exists t1,t2,t3;
+CREATE TABLE t1 (
+id int(6) DEFAULT '0' NOT NULL,
+idservice int(5),
+clee char(20) NOT NULL,
+flag char(1),
+KEY id (id),
+PRIMARY KEY (clee)
+);
+INSERT INTO t1 VALUES (2,4,'6067169d','Y');
+INSERT INTO t1 VALUES (2,5,'606716d1','Y');
+INSERT INTO t1 VALUES (2,1,'606717c1','Y');
+INSERT INTO t1 VALUES (3,1,'6067178d','Y');
+INSERT INTO t1 VALUES (2,6,'60671515','Y');
+INSERT INTO t1 VALUES (2,7,'60671569','Y');
+INSERT INTO t1 VALUES (2,3,'dd','Y');
+CREATE TABLE t2 (
+id int(6) DEFAULT '0' NOT NULL auto_increment,
+description varchar(40) NOT NULL,
+idform varchar(40),
+ordre int(6) unsigned DEFAULT '0' NOT NULL,
+image varchar(60),
+PRIMARY KEY (id),
+KEY id (id,ordre)
+);
+INSERT INTO t2 VALUES (1,'Emettre un appel d''offres','en_construction.html',10,'emettre.gif');
+INSERT INTO t2 VALUES (2,'Emettre des soumissions','en_construction.html',20,'emettre.gif');
+INSERT INTO t2 VALUES (7,'Liste des t2','t2_liste_form.phtml',51060,'link.gif');
+INSERT INTO t2 VALUES (8,'Consulter les soumissions','consulter_soumissions.phtml',200,'link.gif');
+INSERT INTO t2 VALUES (9,'Ajouter un type de materiel','typeMateriel_ajoute_form.phtml',51000,'link.gif');
+INSERT INTO t2 VALUES (10,'Lister/modifier un type de materiel','typeMateriel_liste_form.phtml',51010,'link.gif');
+INSERT INTO t2 VALUES (3,'Créer une fiche de client','clients_ajoute_form.phtml',40000,'link.gif');
+INSERT INTO t2 VALUES (4,'Modifier des clients','en_construction.html',40010,'link.gif');
+INSERT INTO t2 VALUES (5,'Effacer des clients','en_construction.html',40020,'link.gif');
+INSERT INTO t2 VALUES (6,'Ajouter un service','t2_ajoute_form.phtml',51050,'link.gif');
+select t1.id,t1.idservice,t2.ordre,t2.description from t1, t2 where t1.id = 2 and t1.idservice = t2.id order by t2.ordre;
id idservice ordre description
2 1 10 Emettre un appel d'offres
2 3 40000 Créer une fiche de client
@@ -5,34 +41,53 @@ id idservice ordre description
2 5 40020 Effacer des clients
2 6 51050 Ajouter un service
2 7 51060 Liste des t2
+drop table t1,t2;
+create table t1 (first char(10),last char(10));
+insert into t1 values ("Michael","Widenius");
+insert into t1 values ("Allan","Larsson");
+insert into t1 values ("David","Axmark");
+select concat(first," ",last) as name from t1 order by name;
name
Allan Larsson
David Axmark
Michael Widenius
+select concat(last," ",first) as name from t1 order by name;
name
Axmark David
Larsson Allan
Widenius Michael
+drop table t1;
+create table t1 (i int);
+insert into t1 values(1),(2),(1),(2),(1),(2),(3);
+select distinct i from t1;
i
1
2
3
+select distinct i from t1 order by rand(5);
i
1
3
2
+select distinct i from t1 order by i desc;
i
3
2
1
+select distinct i from t1 order by 1-i;
i
3
2
1
+select distinct i from t1 order by mod(i,2),i;
i
2
1
3
+drop table t1;
+create table t1 (id int not null,col1 int not null,col2 int not null,index(col1));
+insert into t1 values(1,2,2),(2,2,1),(3,1,2),(4,1,1),(5,1,4),(6,2,3),(7,3,1),(8,2,4);
+select * from t1 order by col1,col2;
id col1 col2
4 1 1
3 1 2
@@ -42,6 +97,7 @@ id col1 col2
6 2 3
8 2 4
7 3 1
+select col1 from t1 order by id;
col1
2
2
@@ -51,6 +107,7 @@ col1
2
3
2
+select col1 as id from t1 order by t1.id;
id
1
1
@@ -60,6 +117,7 @@ id
2
2
3
+select concat(col1) as id from t1 order by t1.id;
id
2
2
@@ -69,21 +127,75 @@ id
2
3
2
+drop table t1;
+CREATE TABLE t1 (id int auto_increment primary key,aika varchar(40),aikakentta timestamp);
+insert into t1 (aika) values ('Keskiviikko');
+insert into t1 (aika) values ('Tiistai');
+insert into t1 (aika) values ('Maanantai');
+insert into t1 (aika) values ('Sunnuntai');
+SELECT FIELD(SUBSTRING(t1.aika,1,2),'Ma','Ti','Ke','To','Pe','La','Su') AS test FROM t1 ORDER by test;
test
1
2
3
7
+drop table t1;
+CREATE TABLE t1
+(
+a int unsigned NOT NULL,
+b int unsigned NOT NULL,
+c int unsigned NOT NULL,
+UNIQUE(a),
+INDEX(b),
+INDEX(c)
+);
+CREATE TABLE t2
+(
+c int unsigned NOT NULL,
+i int unsigned NOT NULL,
+INDEX(c)
+);
+CREATE TABLE t3
+(
+c int unsigned NOT NULL,
+v varchar(64),
+INDEX(c)
+);
+INSERT INTO t1 VALUES (1,1,1);
+INSERT INTO t1 VALUES (2,1,2);
+INSERT INTO t1 VALUES (3,2,1);
+INSERT INTO t1 VALUES (4,2,2);
+INSERT INTO t2 VALUES (1,50);
+INSERT INTO t2 VALUES (2,25);
+INSERT INTO t3 VALUES (1,'123 Park Place');
+INSERT INTO t3 VALUES (2,'453 Boardwalk');
+SELECT a,b,if(b = 1,i,if(b = 2,v,''))
+FROM t1
+LEFT JOIN t2 USING(c)
+LEFT JOIN t3 ON t3.c = t1.c;
a b if(b = 1,i,if(b = 2,v,''))
1 1 50
2 1 25
3 2 123 Park Place
4 2 453 Boardwalk
+SELECT a,b,if(b = 1,i,if(b = 2,v,''))
+FROM t1
+LEFT JOIN t2 USING(c)
+LEFT JOIN t3 ON t3.c = t1.c
+ORDER BY a;
a b if(b = 1,i,if(b = 2,v,''))
1 1 50
2 1 25
3 2 123 Park Place
4 2 453 Boardwalk
+drop table t1,t2,t3;
+create table t1 (ID int not null primary key, TransactionID int not null);
+insert into t1 (ID, TransactionID) values (1, 87), (2, 89), (3, 92), (4, 94), (5, 486), (6, 490), (7, 753), (9, 828), (10, 832), (11, 834), (12, 840);
+create table t2 (ID int not null primary key, GroupID int not null);
+insert into t2 (ID, GroupID) values (87, 87), (89, 89), (92, 92), (94, 94), (486, 486), (490, 490),(753, 753), (828, 828), (832, 832), (834, 834), (840, 840);
+create table t3 (ID int not null primary key, DateOfAction date not null);
+insert into t3 (ID, DateOfAction) values (87, '1999-07-19'), (89, '1999-07-19'), (92, '1999-07-19'), (94, '1999-07-19'), (486, '1999-07-18'), (490, '2000-03-27'), (753, '2000-03-28'), (828, '1999-07-27'), (832, '1999-07-27'),(834, '1999-07-27'), (840, '1999-07-27');
+select t3.DateOfAction, t1.TransactionID from t1 join t2 join t3 where t2.ID = t1.TransactionID and t3.ID = t2.GroupID order by t3.DateOfAction, t1.TransactionID;
DateOfAction TransactionID
1999-07-18 486
1999-07-19 87
@@ -96,6 +208,7 @@ DateOfAction TransactionID
1999-07-27 840
2000-03-27 490
2000-03-28 753
+select t3.DateOfAction, t1.TransactionID from t1 join t2 join t3 where t2.ID = t1.TransactionID and t3.ID = t2.GroupID order by t1.TransactionID,t3.DateOfAction;
DateOfAction TransactionID
1999-07-19 87
1999-07-19 89
@@ -108,9 +221,218 @@ DateOfAction TransactionID
1999-07-27 832
1999-07-27 834
1999-07-27 840
+drop table t1,t2,t3;
+drop table if exists t1;
+CREATE TABLE t1 (
+member_id int(11) NOT NULL auto_increment,
+inschrijf_datum varchar(20) NOT NULL default '',
+lastchange_datum varchar(20) NOT NULL default '',
+nickname varchar(20) NOT NULL default '',
+password varchar(8) NOT NULL default '',
+voornaam varchar(30) NOT NULL default '',
+tussenvoegsels varchar(10) NOT NULL default '',
+achternaam varchar(50) NOT NULL default '',
+straat varchar(100) NOT NULL default '',
+postcode varchar(10) NOT NULL default '',
+wijk varchar(40) NOT NULL default '',
+plaats varchar(50) NOT NULL default '',
+telefoon varchar(10) NOT NULL default '',
+geboortedatum date NOT NULL default '0000-00-00',
+geslacht varchar(5) NOT NULL default '',
+email varchar(80) NOT NULL default '',
+uin varchar(15) NOT NULL default '',
+homepage varchar(100) NOT NULL default '',
+internet varchar(15) NOT NULL default '',
+scherk varchar(30) NOT NULL default '',
+favo_boek varchar(50) NOT NULL default '',
+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,
+ipnr varchar(30) NOT NULL default '',
+PRIMARY KEY (member_id)
+) TYPE=MyISAM PACK_KEYS=1;
+insert into t1 (member_id) values (1),(2),(3);
+select member_id, nickname, voornaam FROM t1
+ORDER by lastchange_datum DESC LIMIT 2;
member_id nickname voornaam
1
2
+drop table t1;
+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;
+table type possible_keys key key_len ref rows Extra
+t1 range a a 20 NULL 2 where used; 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
+explain select * from t1 where a >= 1 and a < 3 order by a desc;
+table type possible_keys key key_len ref rows Extra
+t1 range a a 4 NULL 10 where used; Using index
+select * from t1 where a >= 1 and a < 3 order by a desc;
+a b c
+2 3 c
+2 2 b
+2 2 a
+2 1 b
+2 1 a
+1 3 b
+1 1 b
+1 1 b
+1 1 NULL
+1 NULL b
+1 NULL NULL
+explain select * from t1 where a = 1 order by a desc, b desc;
+table type possible_keys key key_len ref rows Extra
+t1 ref a a 4 const 5 where used; Using index
+select * from t1 where a = 1 order by a desc, b desc;
+a b c
+1 3 b
+1 1 b
+1 1 b
+1 1 NULL
+1 NULL b
+1 NULL NULL
+explain select * from t1 where a = 1 and b is null order by a desc, b desc;
+table type possible_keys key key_len ref rows Extra
+t1 ref a a 9 const,const 2 where used; Using index; Using filesort
+select * from t1 where a = 1 and b is null order by a desc, b desc;
+a b c
+1 NULL NULL
+1 NULL b
+explain select * from t1 where a >= 1 and a < 3 and b >0 order by a desc,b desc;
+table type possible_keys key key_len ref rows Extra
+t1 range a a 9 NULL 8 where used; Using index; Using filesort
+explain select * from t1 where a = 2 and b >0 order by a desc,b desc;
+table type possible_keys key key_len ref rows Extra
+t1 range a a 9 NULL 5 where used; Using index
+explain select * from t1 where a = 2 and b is null order by a desc,b desc;
+table type possible_keys key key_len ref rows Extra
+t1 ref a a 9 const,const 1 where used; Using index; Using filesort
+explain select * from t1 where a = 2 and (b is null or b > 0) order by a
+desc,b desc;
+table type possible_keys key key_len ref rows Extra
+t1 range a a 9 NULL 6 where used; Using index
+explain select * from t1 where a = 2 and b > 0 order by a desc,b desc;
+table type possible_keys key key_len ref rows Extra
+t1 range a a 9 NULL 5 where used; Using index
+explain select * from t1 where a = 2 and b < 2 order by a desc,b desc;
+table type possible_keys key key_len ref rows Extra
+t1 range a a 9 NULL 2 where used; Using index; Using filesort
+alter table t1 modify b int not null, modify c varchar(10) not null;
+explain select * from t1 order by a, b, c;
+table type possible_keys key key_len ref rows Extra
+t1 index NULL a 18 NULL 11 Using index
+select * from t1 order by a, b, c;
+a b c
+1 0
+1 0 b
+1 1
+1 1 b
+1 1 b
+1 3 b
+2 1 a
+2 1 b
+2 2 a
+2 2 b
+2 3 c
+explain select * from t1 order by a desc, b desc, c desc;
+table type possible_keys key key_len ref rows Extra
+t1 index NULL a 18 NULL 11 Using index
+select * from t1 order by a desc, b desc, c desc;
+a b c
+2 3 c
+2 2 b
+2 2 a
+2 1 b
+2 1 a
+1 3 b
+1 1 b
+1 1 b
+1 1
+1 0 b
+1 0
+explain select * from t1 where (a = 1 and b = 1 and c = 'b') or (a > 2) order by a desc;
+table type possible_keys key key_len ref rows Extra
+t1 range a a 18 NULL 3 where used; 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
+1 1 b
+explain select * from t1 where a < 2 and b <= 1 order by a desc, b desc;
+table type possible_keys key key_len ref rows Extra
+t1 range a a 4 NULL 6 where used; Using index
+select * from t1 where a < 2 and b <= 1 order by a desc, b desc;
+a b c
+1 1 b
+1 1 b
+1 1
+1 0 b
+1 0
+select count(*) from t1 where a < 5 and b > 0;
+count(*)
+9
+select * from t1 where a < 5 and b > 0 order by a desc,b desc;
+a b c
+2 3 c
+2 2 b
+2 2 a
+2 1 b
+2 1 a
+1 3 b
+1 1 b
+1 1 b
+1 1
+explain select * from t1 where a between 1 and 3 and b <= 1 order by a desc, b desc;
+table type possible_keys key key_len ref rows Extra
+t1 range a a 8 NULL 10 where used; Using index
+select * from t1 where a between 1 and 3 and b <= 1 order by a desc, b desc;
+a b c
+2 1 b
+2 1 a
+1 1 b
+1 1 b
+1 1
+1 0 b
+1 0
+explain select * from t1 where a between 0 and 1 order by a desc, b desc;
+table type possible_keys key key_len ref rows Extra
+t1 range a a 4 NULL 5 where used; Using index
+select * from t1 where a between 0 and 1 order by a desc, b desc;
+a b c
+1 3 b
+1 1 b
+1 1 b
+1 1
+1 0 b
+1 0
+drop table t1;
+CREATE TABLE t1 (
+gid int(10) unsigned NOT NULL auto_increment,
+cid smallint(5) unsigned NOT NULL default '0',
+PRIMARY KEY (gid),
+KEY component_id (cid)
+) TYPE=MyISAM;
+INSERT INTO t1 VALUES (103853,108),(103867,108),(103962,108),(104505,108),(104619,108),(104620,108);
+ALTER TABLE t1 add skr int(10) not null;
+CREATE TABLE t2 (
+gid int(10) unsigned NOT NULL default '0',
+uid smallint(5) unsigned NOT NULL default '1',
+sid tinyint(3) unsigned NOT NULL default '1',
+PRIMARY KEY (gid),
+KEY uid (uid),
+KEY status_id (sid)
+) TYPE=MyISAM;
+INSERT INTO t2 VALUES (103853,250,5),(103867,27,5),(103962,27,5),(104505,117,5),(104619,75,5),(104620,15,5);
+CREATE TABLE t3 (
+uid smallint(6) NOT NULL auto_increment,
+PRIMARY KEY (uid)
+) TYPE=MyISAM;
+INSERT INTO t3 VALUES (1),(15),(27),(75),(117),(250);
+ALTER TABLE t3 add skr int(10) not null;
+select t1.gid, t2.sid, t3.uid from t2, t1, t3 where t2.gid = t1.gid and t2.uid = t3.uid order by t3.uid, t1.gid;
gid sid uid
104620 5 15
103867 5 27
@@ -118,6 +440,7 @@ gid sid uid
104619 5 75
104505 5 117
103853 5 250
+select t1.gid, t2.sid, t3.uid from t3, t2, t1 where t2.gid = t1.gid and t2.uid = t3.uid order by t3.uid, t1.gid;
gid sid uid
104620 5 15
103867 5 27
@@ -125,20 +448,26 @@ gid sid uid
104619 5 75
104505 5 117
103853 5 250
+EXPLAIN select t1.gid, t2.sid, t3.uid from t3, t2, t1 where t2.gid = t1.gid and t2.uid = t3.uid order by t1.gid, t3.uid;
table type possible_keys key key_len ref rows Extra
t1 index PRIMARY PRIMARY 4 NULL 6 Using index
t2 eq_ref PRIMARY,uid PRIMARY 4 t1.gid 1
t3 eq_ref PRIMARY PRIMARY 2 t2.uid 1 where used; Using index
+EXPLAIN SELECT t1.gid, t3.uid from t1, t3 where t1.gid = t3.uid order by t1.gid,t3.skr;
table type possible_keys key key_len ref rows Extra
t1 index PRIMARY PRIMARY 4 NULL 6 Using index
t3 eq_ref PRIMARY PRIMARY 2 t1.gid 1 where used
+EXPLAIN SELECT t1.gid, t2.sid, t3.uid from t2, t1, t3 where t2.gid = t1.gid and t2.uid = t3.uid order by t3.uid, t1.gid;
table type possible_keys key key_len ref rows Extra
t1 index PRIMARY PRIMARY 4 NULL 6 Using index; Using temporary; Using filesort
t2 eq_ref PRIMARY,uid PRIMARY 4 t1.gid 1
t3 eq_ref PRIMARY PRIMARY 2 t2.uid 1 where used; Using index
+EXPLAIN SELECT t1.gid, t3.uid from t1, t3 where t1.gid = t3.uid order by t3.skr,t1.gid;
table type possible_keys key key_len ref rows Extra
t1 index PRIMARY PRIMARY 4 NULL 6 Using index; Using temporary; Using filesort
t3 eq_ref PRIMARY PRIMARY 2 t1.gid 1 where used
+EXPLAIN SELECT t1.gid, t3.uid from t1, t3 where t1.skr = t3.uid order by t1.gid,t3.skr;
table type possible_keys key key_len ref rows Extra
t1 ALL NULL NULL NULL NULL 6 Using temporary; Using filesort
t3 eq_ref PRIMARY PRIMARY 2 t1.skr 1 where used
+drop table t1,t2,t3;
diff --git a/mysql-test/r/order_fill_sortbuf.result b/mysql-test/r/order_fill_sortbuf.result
new file mode 100644
index 00000000000..2226e842901
--- /dev/null
+++ b/mysql-test/r/order_fill_sortbuf.result
@@ -0,0 +1,10 @@
+drop table if exists t1,t2;
+CREATE TABLE `t1` (
+`id` int(11) NOT NULL default '0',
+`id2` int(11) NOT NULL default '0',
+`id3` int(11) NOT NULL default '0');
+create table t2 select id2 from t1 order by id3;
+select count(*) from t2;
+count(*)
+4000
+drop table t1,t2;
diff --git a/mysql-test/r/overflow.result b/mysql-test/r/overflow.result
new file mode 100644
index 00000000000..a5fa7154833
--- /dev/null
+++ b/mysql-test/r/overflow.result
@@ -0,0 +1,2 @@
+drop database AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA;
+Got one of the listed errors
diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result
new file mode 100644
index 00000000000..af14575a812
--- /dev/null
+++ b/mysql-test/r/query_cache.result
@@ -0,0 +1,492 @@
+flush query cache;
+flush query cache;
+reset query cache;
+flush status;
+drop table if exists t1,t2,t3,t11,t21, mysqltest.t1;
+create table t1 (a int not null);
+insert into t1 values (1),(2),(3);
+select * from t1;
+a
+1
+2
+3
+select * from t1;
+a
+1
+2
+3
+select sql_no_cache * from t1;
+a
+1
+2
+3
+select length(now()) from t1;
+length(now())
+19
+19
+19
+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 table t1;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+create table t1 (a int not null);
+insert into t1 values (1),(2),(3);
+create table t2 (a int not null);
+insert into t2 values (4),(5),(6);
+create table t3 (a int not null) type=MERGE UNION=(t1,t2) INSERT_METHOD=FIRST;
+select * from t3;
+a
+1
+2
+3
+4
+5
+6
+select * from t3;
+a
+1
+2
+3
+4
+5
+6
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+insert into t2 values (7);
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+select * from t1;
+a
+1
+2
+3
+select * from t1;
+a
+1
+2
+3
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+insert into t3 values (8);
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+select * from t3;
+a
+1
+2
+3
+8
+4
+5
+6
+7
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+update t2 set a=9 where a=7;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+select * from t1;
+a
+1
+2
+3
+8
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+update t3 set a=10 where a=1;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+select * from t3;
+a
+10
+2
+3
+8
+4
+5
+6
+9
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+delete from t2 where a=9;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+select * from t1;
+a
+10
+2
+3
+8
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+delete from t3 where a=10;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+drop table t1, t2, t3;
+create table t1 (a int not null);
+insert into t1 values (1),(2),(3);
+create table t2 (a int not null);
+insert into t2 values (1),(2),(3);
+select * from t1;
+a
+1
+2
+3
+select * from t2;
+a
+1
+2
+3
+insert into t1 values (4);
+show status like "Qcache_free_blocks";
+Variable_name Value
+Qcache_free_blocks 2
+flush query cache;
+show status like "Qcache_free_blocks";
+Variable_name Value
+Qcache_free_blocks 1
+drop table t1, t2;
+create table t1 (a text not null);
+create table t11 (a text not null);
+create table t2 (a text not null);
+create table t21 (a text not null);
+create table t3 (a text not null);
+insert into t1 values("1111111111111111111111111111111111111111111111111111");
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t11 select * from t1;
+insert into t21 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t3 select * from t1;
+insert into t3 select * from t2;
+insert into t3 select * from t1;
+select * from t11;
+select * from t21;
+show status like "Qcache_total_blocks";
+Variable_name Value
+Qcache_total_blocks 7
+show status like "Qcache_free_blocks";
+Variable_name Value
+Qcache_free_blocks 1
+insert into t11 values("");
+select * from t3;
+show status like "Qcache_total_blocks";
+Variable_name Value
+Qcache_total_blocks 8
+show status like "Qcache_free_blocks";
+Variable_name Value
+Qcache_free_blocks 1
+flush query cache;
+show status like "Qcache_total_blocks";
+Variable_name Value
+Qcache_total_blocks 7
+show status like "Qcache_free_blocks";
+Variable_name Value
+Qcache_free_blocks 1
+drop table t1, t2, t3, t11, t21;
+set sql_query_cache_type=demand;
+create table t1 (a int not null);
+insert into t1 values (1),(2),(3);
+select * from t1;
+a
+1
+2
+3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+select sql_cache * from t1;
+a
+1
+2
+3
+set sql_query_cache_type=2;
+select sql_cache * from t1;
+a
+1
+2
+3
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 4
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+set sql_query_cache_type=on;
+reset query cache;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+select sql_no_cache * from t1;
+a
+1
+2
+3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+drop table t1;
+create table t1 (a text not null);
+select CONNECTION_ID() from t1;
+CONNECTION_ID()
+select FOUND_ROWS();
+FOUND_ROWS()
+0
+select NOW() from t1;
+NOW()
+select CURDATE() from t1;
+CURDATE()
+select CURTIME() from t1;
+CURTIME()
+select DATABASE() from t1;
+DATABASE()
+select ENCRYPT("test") from t1;
+ENCRYPT("test")
+select LAST_INSERT_ID() from t1;
+last_insert_id()
+select RAND() from t1;
+RAND()
+select UNIX_TIMESTAMP() from t1;
+UNIX_TIMESTAMP()
+select USER() from t1;
+USER()
+select benchmark(1,1) from t1;
+benchmark(1,1)
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+create table t2 (a text not null);
+insert into t1 values("1111111111111111111111111111111111111111111111111111");
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 4
+select a as a1, a as a2 from t1;
+select a as a2, a as a3 from t1;
+select a as a3, a as a4 from t1;
+select a as a1, a as a2 from t1;
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 4
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+reset query cache;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+select * from t1;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+drop table t1,t2;
+create database if not exists mysqltest;
+create table mysqltest.t1 (i int not null auto_increment, a int, primary key (i));
+insert into mysqltest.t1 (a) values (1);
+select * from mysqltest.t1 where i is null;
+i a
+1 1
+select * from mysqltest.t1;
+i a
+1 1
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+drop database mysqltest;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+create table t1 (a char(1) not null);
+insert into t1 values("á");
+select * from t1;
+a
+set CHARACTER SET cp1251_koi8;
+select * from t1;
+a
+set CHARACTER SET DEFAULT;
+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 4
+drop table t1;
+create database if not exists mysqltest;
+create table mysqltest.t1 (i int not null);
+create table t1 (i int not null);
+insert into mysqltest.t1 (i) values (1);
+insert into t1 (i) values (2);
+select * from t1;
+i
+2
+use mysqltest;
+select * from t1;
+i
+1
+select * from t1;
+i
+1
+use test;
+select * from t1;
+i
+2
+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 6
+drop database mysqltest;
+drop table t1;
+create table t1 (i int not null);
+insert into t1 (i) values (1),(2),(3),(4);
+select SQL_CALC_FOUND_ROWS * from t1 limit 2;
+i
+1
+2
+select FOUND_ROWS();
+FOUND_ROWS()
+4
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 6
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+select * from t1 where i=1;
+i
+1
+select FOUND_ROWS();
+FOUND_ROWS()
+1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 6
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+select SQL_CALC_FOUND_ROWS * from t1 limit 2;
+i
+1
+2
+select FOUND_ROWS();
+FOUND_ROWS()
+4
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 7
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+select * from t1 where i=1;
+i
+1
+select FOUND_ROWS();
+FOUND_ROWS()
+1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 8
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+drop table t1;
+flush query cache;
+reset query cache;
+create table t1 (a int not null);
+insert into t1 values (1),(2),(3);
+select * from t1;
+a
+1
+2
+3
+select * from t1;
+a
+1
+2
+3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+insert delayed into t1 values (4);
+select a from t1;
+a
+1
+2
+3
+4
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+drop table t1;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
diff --git a/mysql-test/r/raid.result b/mysql-test/r/raid.result
index ffda2a6966d..41af50851e9 100644
--- a/mysql-test/r/raid.result
+++ b/mysql-test/r/raid.result
@@ -1,8 +1,196 @@
+DROP TABLE IF EXISTS t1,t2;
+CREATE TABLE t1 (
+id int unsigned not null auto_increment primary key,
+c char(255) not null
+) RAID_TYPE=STRIPED RAID_CHUNKS=2 RAID_CHUNKSIZE=123;
+INSERT INTO t1 VALUES
+(NULL,'1'),(NULL,'a'),(NULL,'a'),(NULL,'a'),(NULL,'p'),(NULL,'a'),
+(NULL,'2'),(NULL,'b'),(NULL,'a'),(NULL,'a'),(NULL,'q'),(NULL,'a'),
+(NULL,'3'),(NULL,'c'),(NULL,'a'),(NULL,'a'),(NULL,'r'),(NULL,'a'),
+(NULL,'4'),(NULL,'d'),(NULL,'a'),(NULL,'a'),(NULL,'s'),(NULL,'a'),
+(NULL,'5'),(NULL,'e'),(NULL,'a'),(NULL,'a'),(NULL,'t'),(NULL,'a'),
+(NULL,'6'),(NULL,'f'),(NULL,'a'),(NULL,'a'),(NULL,'u'),(NULL,'a'),
+(NULL,'7'),(NULL,'g'),(NULL,'a'),(NULL,'a'),(NULL,'v'),(NULL,'a'),
+(NULL,'8'),(NULL,'h'),(NULL,'a'),(NULL,'a'),(NULL,'w'),(NULL,'a'),
+(NULL,'9'),(NULL,'i'),(NULL,'a'),(NULL,'a'),(NULL,'x'),(NULL,'a'),
+(NULL,'0'),(NULL,'j'),(NULL,'a'),(NULL,'a'),(NULL,'y'),(NULL,'a'),
+(NULL,'1'),(NULL,'k'),(NULL,'a'),(NULL,'a'),(NULL,'z'),(NULL,'a'),
+(NULL,'2'),(NULL,'l'),(NULL,'a'),(NULL,'a'),(NULL,'/'),(NULL,'a'),
+(NULL,'3'),(NULL,'m'),(NULL,'a'),(NULL,'a'),(NULL,'*'),(NULL,'a'),
+(NULL,'4'),(NULL,'n'),(NULL,'a'),(NULL,'a'),(NULL,'+'),(NULL,'a'),
+(NULL,'5'),(NULL,'o'),(NULL,'a'),(NULL,'a'),(NULL,'?'),(NULL,'a');
+INSERT INTO t1 VALUES
+(NULL,'1'),(NULL,'a'),(NULL,'a'),(NULL,'a'),(NULL,'p'),(NULL,'a'),
+(NULL,'2'),(NULL,'b'),(NULL,'a'),(NULL,'a'),(NULL,'q'),(NULL,'a'),
+(NULL,'3'),(NULL,'c'),(NULL,'a'),(NULL,'a'),(NULL,'r'),(NULL,'a'),
+(NULL,'4'),(NULL,'d'),(NULL,'a'),(NULL,'a'),(NULL,'s'),(NULL,'a'),
+(NULL,'5'),(NULL,'e'),(NULL,'a'),(NULL,'a'),(NULL,'t'),(NULL,'a'),
+(NULL,'6'),(NULL,'f'),(NULL,'a'),(NULL,'a'),(NULL,'u'),(NULL,'a'),
+(NULL,'7'),(NULL,'g'),(NULL,'a'),(NULL,'a'),(NULL,'v'),(NULL,'a'),
+(NULL,'8'),(NULL,'h'),(NULL,'a'),(NULL,'a'),(NULL,'w'),(NULL,'a'),
+(NULL,'9'),(NULL,'i'),(NULL,'a'),(NULL,'a'),(NULL,'x'),(NULL,'a'),
+(NULL,'0'),(NULL,'j'),(NULL,'a'),(NULL,'a'),(NULL,'y'),(NULL,'a'),
+(NULL,'1'),(NULL,'k'),(NULL,'a'),(NULL,'a'),(NULL,'z'),(NULL,'a'),
+(NULL,'2'),(NULL,'l'),(NULL,'a'),(NULL,'a'),(NULL,'/'),(NULL,'a'),
+(NULL,'3'),(NULL,'m'),(NULL,'a'),(NULL,'a'),(NULL,'*'),(NULL,'a'),
+(NULL,'4'),(NULL,'n'),(NULL,'a'),(NULL,'a'),(NULL,'+'),(NULL,'a'),
+(NULL,'5'),(NULL,'o'),(NULL,'a'),(NULL,'a'),(NULL,'?'),(NULL,'a');
+INSERT INTO t1 VALUES
+(NULL,'1'),(NULL,'a'),(NULL,'a'),(NULL,'a'),(NULL,'p'),(NULL,'a'),
+(NULL,'2'),(NULL,'b'),(NULL,'a'),(NULL,'a'),(NULL,'q'),(NULL,'a'),
+(NULL,'3'),(NULL,'c'),(NULL,'a'),(NULL,'a'),(NULL,'r'),(NULL,'a'),
+(NULL,'4'),(NULL,'d'),(NULL,'a'),(NULL,'a'),(NULL,'s'),(NULL,'a'),
+(NULL,'5'),(NULL,'e'),(NULL,'a'),(NULL,'a'),(NULL,'t'),(NULL,'a'),
+(NULL,'6'),(NULL,'f'),(NULL,'a'),(NULL,'a'),(NULL,'u'),(NULL,'a'),
+(NULL,'7'),(NULL,'g'),(NULL,'a'),(NULL,'a'),(NULL,'v'),(NULL,'a'),
+(NULL,'8'),(NULL,'h'),(NULL,'a'),(NULL,'a'),(NULL,'w'),(NULL,'a'),
+(NULL,'9'),(NULL,'i'),(NULL,'a'),(NULL,'a'),(NULL,'x'),(NULL,'a'),
+(NULL,'0'),(NULL,'j'),(NULL,'a'),(NULL,'a'),(NULL,'y'),(NULL,'a'),
+(NULL,'1'),(NULL,'k'),(NULL,'a'),(NULL,'a'),(NULL,'z'),(NULL,'a'),
+(NULL,'2'),(NULL,'l'),(NULL,'a'),(NULL,'a'),(NULL,'/'),(NULL,'a'),
+(NULL,'3'),(NULL,'m'),(NULL,'a'),(NULL,'a'),(NULL,'*'),(NULL,'a'),
+(NULL,'4'),(NULL,'n'),(NULL,'a'),(NULL,'a'),(NULL,'+'),(NULL,'a'),
+(NULL,'5'),(NULL,'o'),(NULL,'a'),(NULL,'a'),(NULL,'?'),(NULL,'a');
+INSERT INTO t1 VALUES
+(NULL,'1'),(NULL,'a'),(NULL,'a'),(NULL,'a'),(NULL,'p'),(NULL,'a'),
+(NULL,'2'),(NULL,'b'),(NULL,'a'),(NULL,'a'),(NULL,'q'),(NULL,'a'),
+(NULL,'3'),(NULL,'c'),(NULL,'a'),(NULL,'a'),(NULL,'r'),(NULL,'a'),
+(NULL,'4'),(NULL,'d'),(NULL,'a'),(NULL,'a'),(NULL,'s'),(NULL,'a'),
+(NULL,'5'),(NULL,'e'),(NULL,'a'),(NULL,'a'),(NULL,'t'),(NULL,'a'),
+(NULL,'6'),(NULL,'f'),(NULL,'a'),(NULL,'a'),(NULL,'u'),(NULL,'a'),
+(NULL,'7'),(NULL,'g'),(NULL,'a'),(NULL,'a'),(NULL,'v'),(NULL,'a'),
+(NULL,'8'),(NULL,'h'),(NULL,'a'),(NULL,'a'),(NULL,'w'),(NULL,'a'),
+(NULL,'9'),(NULL,'i'),(NULL,'a'),(NULL,'a'),(NULL,'x'),(NULL,'a'),
+(NULL,'0'),(NULL,'j'),(NULL,'a'),(NULL,'a'),(NULL,'y'),(NULL,'a'),
+(NULL,'1'),(NULL,'k'),(NULL,'a'),(NULL,'a'),(NULL,'z'),(NULL,'a'),
+(NULL,'2'),(NULL,'l'),(NULL,'a'),(NULL,'a'),(NULL,'/'),(NULL,'a'),
+(NULL,'3'),(NULL,'m'),(NULL,'a'),(NULL,'a'),(NULL,'*'),(NULL,'a'),
+(NULL,'4'),(NULL,'n'),(NULL,'a'),(NULL,'a'),(NULL,'+'),(NULL,'a'),
+(NULL,'5'),(NULL,'o'),(NULL,'a'),(NULL,'a'),(NULL,'?'),(NULL,'a');
+INSERT INTO t1 VALUES
+(NULL,'1'),(NULL,'a'),(NULL,'a'),(NULL,'a'),(NULL,'p'),(NULL,'a'),
+(NULL,'2'),(NULL,'b'),(NULL,'a'),(NULL,'a'),(NULL,'q'),(NULL,'a'),
+(NULL,'3'),(NULL,'c'),(NULL,'a'),(NULL,'a'),(NULL,'r'),(NULL,'a'),
+(NULL,'4'),(NULL,'d'),(NULL,'a'),(NULL,'a'),(NULL,'s'),(NULL,'a'),
+(NULL,'5'),(NULL,'e'),(NULL,'a'),(NULL,'a'),(NULL,'t'),(NULL,'a'),
+(NULL,'6'),(NULL,'f'),(NULL,'a'),(NULL,'a'),(NULL,'u'),(NULL,'a'),
+(NULL,'7'),(NULL,'g'),(NULL,'a'),(NULL,'a'),(NULL,'v'),(NULL,'a'),
+(NULL,'8'),(NULL,'h'),(NULL,'a'),(NULL,'a'),(NULL,'w'),(NULL,'a'),
+(NULL,'9'),(NULL,'i'),(NULL,'a'),(NULL,'a'),(NULL,'x'),(NULL,'a'),
+(NULL,'0'),(NULL,'j'),(NULL,'a'),(NULL,'a'),(NULL,'y'),(NULL,'a'),
+(NULL,'1'),(NULL,'k'),(NULL,'a'),(NULL,'a'),(NULL,'z'),(NULL,'a'),
+(NULL,'2'),(NULL,'l'),(NULL,'a'),(NULL,'a'),(NULL,'/'),(NULL,'a'),
+(NULL,'3'),(NULL,'m'),(NULL,'a'),(NULL,'a'),(NULL,'*'),(NULL,'a'),
+(NULL,'4'),(NULL,'n'),(NULL,'a'),(NULL,'a'),(NULL,'+'),(NULL,'a'),
+(NULL,'5'),(NULL,'o'),(NULL,'a'),(NULL,'a'),(NULL,'?'),(NULL,'a');
+select count(*) from t1;
count(*)
450
+ALTER TABLE t1 ADD COLUMN x INT UNSIGNED NOT NULL;
+ALTER TABLE t1 ADD KEY c (c);
+ALTER TABLE t1 DROP KEY c;
+ALTER TABLE t1 DROP COLUMN x;
+ALTER TABLE t1 RENAME t2;
+select count(*) from t2;
count(*)
450
+DROP TABLE t2;
+/* variable rows */
+DROP TABLE IF EXISTS t2;
+CREATE TABLE t1 (
+id int unsigned not null auto_increment primary key,
+c varchar(255) not null
+) RAID_TYPE=STRIPED RAID_CHUNKS=5 RAID_CHUNKSIZE=121;
+INSERT INTO t1 VALUES
+(NULL,'1'),(NULL,'a'),(NULL,'a'),(NULL,'a'),(NULL,'p'),(NULL,'a'),
+(NULL,'2'),(NULL,'b'),(NULL,'a'),(NULL,'a'),(NULL,'q'),(NULL,'a'),
+(NULL,'3'),(NULL,'c'),(NULL,'a'),(NULL,'a'),(NULL,'r'),(NULL,'a'),
+(NULL,'4'),(NULL,'d'),(NULL,'a'),(NULL,'a'),(NULL,'s'),(NULL,'a'),
+(NULL,'5'),(NULL,'e'),(NULL,'a'),(NULL,'a'),(NULL,'t'),(NULL,'a'),
+(NULL,'6'),(NULL,'f'),(NULL,'a'),(NULL,'a'),(NULL,'u'),(NULL,'a'),
+(NULL,'7'),(NULL,'g'),(NULL,'a'),(NULL,'a'),(NULL,'v'),(NULL,'a'),
+(NULL,'8'),(NULL,'h'),(NULL,'a'),(NULL,'a'),(NULL,'w'),(NULL,'a'),
+(NULL,'9'),(NULL,'i'),(NULL,'a'),(NULL,'a'),(NULL,'x'),(NULL,'a'),
+(NULL,'0'),(NULL,'j'),(NULL,'a'),(NULL,'a'),(NULL,'y'),(NULL,'a'),
+(NULL,'1'),(NULL,'k'),(NULL,'a'),(NULL,'a'),(NULL,'z'),(NULL,'a'),
+(NULL,'2'),(NULL,'l'),(NULL,'a'),(NULL,'a'),(NULL,'/'),(NULL,'a'),
+(NULL,'3'),(NULL,'m'),(NULL,'a'),(NULL,'a'),(NULL,'*'),(NULL,'a'),
+(NULL,'4'),(NULL,'n'),(NULL,'a'),(NULL,'a'),(NULL,'+'),(NULL,'a'),
+(NULL,'5'),(NULL,'o'),(NULL,'a'),(NULL,'a'),(NULL,'?'),(NULL,'a');
+INSERT INTO t1 VALUES
+(NULL,'1'),(NULL,'a'),(NULL,'a'),(NULL,'a'),(NULL,'p'),(NULL,'a'),
+(NULL,'2'),(NULL,'b'),(NULL,'a'),(NULL,'a'),(NULL,'q'),(NULL,'a'),
+(NULL,'3'),(NULL,'c'),(NULL,'a'),(NULL,'a'),(NULL,'r'),(NULL,'a'),
+(NULL,'4'),(NULL,'d'),(NULL,'a'),(NULL,'a'),(NULL,'s'),(NULL,'a'),
+(NULL,'5'),(NULL,'e'),(NULL,'a'),(NULL,'a'),(NULL,'t'),(NULL,'a'),
+(NULL,'6'),(NULL,'f'),(NULL,'a'),(NULL,'a'),(NULL,'u'),(NULL,'a'),
+(NULL,'7'),(NULL,'g'),(NULL,'a'),(NULL,'a'),(NULL,'v'),(NULL,'a'),
+(NULL,'8'),(NULL,'h'),(NULL,'a'),(NULL,'a'),(NULL,'w'),(NULL,'a'),
+(NULL,'9'),(NULL,'i'),(NULL,'a'),(NULL,'a'),(NULL,'x'),(NULL,'a'),
+(NULL,'0'),(NULL,'j'),(NULL,'a'),(NULL,'a'),(NULL,'y'),(NULL,'a'),
+(NULL,'1'),(NULL,'k'),(NULL,'a'),(NULL,'a'),(NULL,'z'),(NULL,'a'),
+(NULL,'2'),(NULL,'l'),(NULL,'a'),(NULL,'a'),(NULL,'/'),(NULL,'a'),
+(NULL,'3'),(NULL,'m'),(NULL,'a'),(NULL,'a'),(NULL,'*'),(NULL,'a'),
+(NULL,'4'),(NULL,'n'),(NULL,'a'),(NULL,'a'),(NULL,'+'),(NULL,'a'),
+(NULL,'5'),(NULL,'o'),(NULL,'a'),(NULL,'a'),(NULL,'?'),(NULL,'a');
+INSERT INTO t1 VALUES
+(NULL,'1'),(NULL,'a'),(NULL,'a'),(NULL,'a'),(NULL,'p'),(NULL,'a'),
+(NULL,'2'),(NULL,'b'),(NULL,'a'),(NULL,'a'),(NULL,'q'),(NULL,'a'),
+(NULL,'3'),(NULL,'c'),(NULL,'a'),(NULL,'a'),(NULL,'r'),(NULL,'a'),
+(NULL,'4'),(NULL,'d'),(NULL,'a'),(NULL,'a'),(NULL,'s'),(NULL,'a'),
+(NULL,'5'),(NULL,'e'),(NULL,'a'),(NULL,'a'),(NULL,'t'),(NULL,'a'),
+(NULL,'6'),(NULL,'f'),(NULL,'a'),(NULL,'a'),(NULL,'u'),(NULL,'a'),
+(NULL,'7'),(NULL,'g'),(NULL,'a'),(NULL,'a'),(NULL,'v'),(NULL,'a'),
+(NULL,'8'),(NULL,'h'),(NULL,'a'),(NULL,'a'),(NULL,'w'),(NULL,'a'),
+(NULL,'9'),(NULL,'i'),(NULL,'a'),(NULL,'a'),(NULL,'x'),(NULL,'a'),
+(NULL,'0'),(NULL,'j'),(NULL,'a'),(NULL,'a'),(NULL,'y'),(NULL,'a'),
+(NULL,'1'),(NULL,'k'),(NULL,'a'),(NULL,'a'),(NULL,'z'),(NULL,'a'),
+(NULL,'2'),(NULL,'l'),(NULL,'a'),(NULL,'a'),(NULL,'/'),(NULL,'a'),
+(NULL,'3'),(NULL,'m'),(NULL,'a'),(NULL,'a'),(NULL,'*'),(NULL,'a'),
+(NULL,'4'),(NULL,'n'),(NULL,'a'),(NULL,'a'),(NULL,'+'),(NULL,'a'),
+(NULL,'5'),(NULL,'o'),(NULL,'a'),(NULL,'a'),(NULL,'?'),(NULL,'a');
+INSERT INTO t1 VALUES
+(NULL,'1'),(NULL,'a'),(NULL,'a'),(NULL,'a'),(NULL,'p'),(NULL,'a'),
+(NULL,'2'),(NULL,'b'),(NULL,'a'),(NULL,'a'),(NULL,'q'),(NULL,'a'),
+(NULL,'3'),(NULL,'c'),(NULL,'a'),(NULL,'a'),(NULL,'r'),(NULL,'a'),
+(NULL,'4'),(NULL,'d'),(NULL,'a'),(NULL,'a'),(NULL,'s'),(NULL,'a'),
+(NULL,'5'),(NULL,'e'),(NULL,'a'),(NULL,'a'),(NULL,'t'),(NULL,'a'),
+(NULL,'6'),(NULL,'f'),(NULL,'a'),(NULL,'a'),(NULL,'u'),(NULL,'a'),
+(NULL,'7'),(NULL,'g'),(NULL,'a'),(NULL,'a'),(NULL,'v'),(NULL,'a'),
+(NULL,'8'),(NULL,'h'),(NULL,'a'),(NULL,'a'),(NULL,'w'),(NULL,'a'),
+(NULL,'9'),(NULL,'i'),(NULL,'a'),(NULL,'a'),(NULL,'x'),(NULL,'a'),
+(NULL,'0'),(NULL,'j'),(NULL,'a'),(NULL,'a'),(NULL,'y'),(NULL,'a'),
+(NULL,'1'),(NULL,'k'),(NULL,'a'),(NULL,'a'),(NULL,'z'),(NULL,'a'),
+(NULL,'2'),(NULL,'l'),(NULL,'a'),(NULL,'a'),(NULL,'/'),(NULL,'a'),
+(NULL,'3'),(NULL,'m'),(NULL,'a'),(NULL,'a'),(NULL,'*'),(NULL,'a'),
+(NULL,'4'),(NULL,'n'),(NULL,'a'),(NULL,'a'),(NULL,'+'),(NULL,'a'),
+(NULL,'5'),(NULL,'o'),(NULL,'a'),(NULL,'a'),(NULL,'?'),(NULL,'a');
+INSERT INTO t1 VALUES
+(NULL,'1'),(NULL,'a'),(NULL,'a'),(NULL,'a'),(NULL,'p'),(NULL,'a'),
+(NULL,'2'),(NULL,'b'),(NULL,'a'),(NULL,'a'),(NULL,'q'),(NULL,'a'),
+(NULL,'3'),(NULL,'c'),(NULL,'a'),(NULL,'a'),(NULL,'r'),(NULL,'a'),
+(NULL,'4'),(NULL,'d'),(NULL,'a'),(NULL,'a'),(NULL,'s'),(NULL,'a'),
+(NULL,'5'),(NULL,'e'),(NULL,'a'),(NULL,'a'),(NULL,'t'),(NULL,'a'),
+(NULL,'6'),(NULL,'f'),(NULL,'a'),(NULL,'a'),(NULL,'u'),(NULL,'a'),
+(NULL,'7'),(NULL,'g'),(NULL,'a'),(NULL,'a'),(NULL,'v'),(NULL,'a'),
+(NULL,'8'),(NULL,'h'),(NULL,'a'),(NULL,'a'),(NULL,'w'),(NULL,'a'),
+(NULL,'9'),(NULL,'i'),(NULL,'a'),(NULL,'a'),(NULL,'x'),(NULL,'a'),
+(NULL,'0'),(NULL,'j'),(NULL,'a'),(NULL,'a'),(NULL,'y'),(NULL,'a'),
+(NULL,'1'),(NULL,'k'),(NULL,'a'),(NULL,'a'),(NULL,'z'),(NULL,'a'),
+(NULL,'2'),(NULL,'l'),(NULL,'a'),(NULL,'a'),(NULL,'/'),(NULL,'a'),
+(NULL,'3'),(NULL,'m'),(NULL,'a'),(NULL,'a'),(NULL,'*'),(NULL,'a'),
+(NULL,'4'),(NULL,'n'),(NULL,'a'),(NULL,'a'),(NULL,'+'),(NULL,'a'),
+(NULL,'5'),(NULL,'o'),(NULL,'a'),(NULL,'a'),(NULL,'?'),(NULL,'a');
+select count(*) from t1;
count(*)
450
+ALTER TABLE t1 ADD COLUMN x INT UNSIGNED NOT NULL;
+ALTER TABLE t1 ADD KEY c (c);
+ALTER TABLE t1 DROP KEY c;
+ALTER TABLE t1 DROP COLUMN x;
+ALTER TABLE t1 RENAME t2;
+ALTER TABLE t2 CHANGE COLUMN c c VARCHAR(251) NOT NULL;
+select count(*) from t2;
count(*)
450
+DROP TABLE t2;
diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result
index 1a45c252b7c..431a4956785 100644
--- a/mysql-test/r/range.result
+++ b/mysql-test/r/range.result
@@ -1,3 +1,12 @@
+drop table if exists t1;
+CREATE TABLE t1 (
+event_date date DEFAULT '0000-00-00' NOT NULL,
+type int(11) DEFAULT '0' NOT NULL,
+event_id int(11) DEFAULT '0' NOT NULL,
+PRIMARY KEY (event_date,type,event_id)
+);
+INSERT INTO t1 VALUES ('1999-07-10',100100,24),('1999-07-11',100100,25),('1999-07-13',100600,0),('1999-07-13',100600,4),('1999-07-13',100600,26),('1999-07-14',100600,10),('1999-07-15',100600,16),('1999-07-15',100800,45),('1999-07-15',101000,47),('1999-07-16',100800,46),('1999-07-20',100600,5),('1999-07-20',100600,27),('1999-07-21',100600,11),('1999-07-22',100600,17),('1999-07-23',100100,39),('1999-07-24',100100,39),('1999-07-24',100500,40),('1999-07-25',100100,39),('1999-07-27',100600,1),('1999-07-27',100600,6),('1999-07-27',100600,28),('1999-07-28',100600,12),('1999-07-29',100500,41),('1999-07-29',100600,18),('1999-07-30',100500,41),('1999-07-31',100500,41),('1999-08-01',100700,34),('1999-08-03',100600,7),('1999-08-03',100600,29),('1999-08-04',100600,13),('1999-08-05',100500,42),('1999-08-05',100600,19),('1999-08-06',100500,42),('1999-08-07',100500,42),('1999-08-08',100500,42),('1999-08-10',100600,2),('1999-08-10',100600,9),('1999-08-10',100600,30),('1999-08-11',100600,14),('1999-08-12',100600,20),('1999-08-17',100500,8),('1999-08-17',100600,31),('1999-08-18',100600,15),('1999-08-19',100600,22),('1999-08-24',100600,3),('1999-08-24',100600,32),('1999-08-27',100500,43),('1999-08-31',100600,33),('1999-09-17',100100,37),('1999-09-18',100100,37),('1999-09-19',100100,37),('2000-12-18',100700,38);
+select event_date,type,event_id from t1 WHERE event_date >= "1999-07-01" AND event_date < "1999-07-15" AND (type=100600 OR type=100100) ORDER BY event_date;
event_date type event_id
1999-07-10 100100 24
1999-07-11 100100 25
@@ -5,8 +14,10 @@ event_date type event_id
1999-07-13 100600 4
1999-07-13 100600 26
1999-07-14 100600 10
+explain select event_date,type,event_id from t1 WHERE type = 100601 and event_date >= "1999-07-01" AND event_date < "1999-07-15" AND (type=100600 OR type=100100) ORDER BY event_date;
Comment
Impossible WHERE
+select event_date,type,event_id from t1 WHERE event_date >= "1999-07-01" AND event_date <= "1999-07-15" AND (type=100600 OR type=100100) or event_date >= "1999-07-01" AND event_date <= "1999-07-15" AND type=100099;
event_date type event_id
1999-07-10 100100 24
1999-07-11 100100 25
@@ -15,6 +26,45 @@ event_date type event_id
1999-07-13 100600 26
1999-07-14 100600 10
1999-07-15 100600 16
+drop table t1;
+CREATE TABLE t1 (
+PAPER_ID smallint(6) DEFAULT '0' NOT NULL,
+YEAR smallint(6) DEFAULT '0' NOT NULL,
+ISSUE smallint(6) DEFAULT '0' NOT NULL,
+CLOSED tinyint(4) DEFAULT '0' NOT NULL,
+ISS_DATE date DEFAULT '0000-00-00' NOT NULL,
+PRIMARY KEY (PAPER_ID,YEAR,ISSUE)
+);
+INSERT INTO t1 VALUES (3,1999,34,0,'1999-07-12');
+INSERT INTO t1 VALUES (1,1999,111,0,'1999-03-23');
+INSERT INTO t1 VALUES (1,1999,222,0,'1999-03-23');
+INSERT INTO t1 VALUES (3,1999,33,0,'1999-07-12');
+INSERT INTO t1 VALUES (3,1999,32,0,'1999-07-12');
+INSERT INTO t1 VALUES (3,1999,31,0,'1999-07-12');
+INSERT INTO t1 VALUES (3,1999,30,0,'1999-07-12');
+INSERT INTO t1 VALUES (3,1999,29,0,'1999-07-12');
+INSERT INTO t1 VALUES (3,1999,28,0,'1999-07-12');
+INSERT INTO t1 VALUES (1,1999,40,1,'1999-05-01');
+INSERT INTO t1 VALUES (1,1999,41,1,'1999-05-01');
+INSERT INTO t1 VALUES (1,1999,42,1,'1999-05-01');
+INSERT INTO t1 VALUES (1,1999,46,1,'1999-05-01');
+INSERT INTO t1 VALUES (1,1999,47,1,'1999-05-01');
+INSERT INTO t1 VALUES (1,1999,48,1,'1999-05-01');
+INSERT INTO t1 VALUES (1,1999,49,1,'1999-05-01');
+INSERT INTO t1 VALUES (1,1999,50,0,'1999-05-01');
+INSERT INTO t1 VALUES (1,1999,51,0,'1999-05-01');
+INSERT INTO t1 VALUES (1,1999,200,0,'1999-06-28');
+INSERT INTO t1 VALUES (1,1999,52,0,'1999-06-28');
+INSERT INTO t1 VALUES (1,1999,53,0,'1999-06-28');
+INSERT INTO t1 VALUES (1,1999,54,0,'1999-06-28');
+INSERT INTO t1 VALUES (1,1999,55,0,'1999-06-28');
+INSERT INTO t1 VALUES (1,1999,56,0,'1999-07-01');
+INSERT INTO t1 VALUES (1,1999,57,0,'1999-07-01');
+INSERT INTO t1 VALUES (1,1999,58,0,'1999-07-01');
+INSERT INTO t1 VALUES (1,1999,59,0,'1999-07-01');
+INSERT INTO t1 VALUES (1,1999,60,0,'1999-07-01');
+INSERT INTO t1 VALUES (3,1999,35,0,'1999-07-12');
+select YEAR,ISSUE from t1 where PAPER_ID=3 and (YEAR>1999 or (YEAR=1999 and ISSUE>28)) order by YEAR,ISSUE;
YEAR ISSUE
1999 29
1999 30
@@ -23,10 +73,23 @@ YEAR ISSUE
1999 33
1999 34
1999 35
+check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
+repair table t1;
Table Op Msg_type Msg_text
test.t1 repair status OK
+drop table t1;
+CREATE TABLE t1 (
+id int(11) NOT NULL auto_increment,
+parent_id int(11) DEFAULT '0' NOT NULL,
+level tinyint(4) DEFAULT '0' NOT NULL,
+PRIMARY KEY (id),
+KEY parent_id (parent_id),
+KEY level (level)
+);
+INSERT INTO t1 VALUES (1,0,0),(3,1,1),(4,1,1),(8,2,2),(9,2,2),(17,3,2),(22,4,2),(24,4,2),(28,5,2),(29,5,2),(30,5,2),(31,6,2),(32,6,2),(33,6,2),(203,7,2),(202,7,2),(20,3,2),(157,0,0),(193,5,2),(40,7,2),(2,1,1),(15,2,2),(6,1,1),(34,6,2),(35,6,2),(16,3,2),(7,1,1),(36,7,2),(18,3,2),(26,5,2),(27,5,2),(183,4,2),(38,7,2),(25,5,2),(37,7,2),(21,4,2),(19,3,2),(5,1,1),(179,5,2);
+SELECT * FROM t1 WHERE level = 1 AND parent_id = 1;
id parent_id level
3 1 1
4 1 1
@@ -34,6 +97,7 @@ id parent_id level
6 1 1
7 1 1
5 1 1
+SELECT * FROM t1 WHERE level = 1 AND parent_id = 1 order by id;
id parent_id level
2 1 1
3 1 1
@@ -41,18 +105,38 @@ id parent_id level
5 1 1
6 1 1
7 1 1
+drop table t1;
+create table t1(
+Satellite varchar(25) not null,
+SensorMode varchar(25) not null,
+FullImageCornersUpperLeftLongitude double not null,
+FullImageCornersUpperRightLongitude double not null,
+FullImageCornersUpperRightLatitude double not null,
+FullImageCornersLowerRightLatitude double not null,
+index two (Satellite, SensorMode, FullImageCornersUpperLeftLongitude, FullImageCornersUpperRightLongitude, FullImageCornersUpperRightLatitude, FullImageCornersLowerRightLatitude));
+insert into t1 values("OV-3","PAN1",91,-92,40,50);
+insert into t1 values("OV-4","PAN1",91,-92,40,50);
+select * from t1 where t1.Satellite = "OV-3" and t1.SensorMode = "PAN1" and t1.FullImageCornersUpperLeftLongitude > -90.000000 and t1.FullImageCornersUpperRightLongitude < -82.000000;
Satellite SensorMode FullImageCornersUpperLeftLongitude FullImageCornersUpperRightLongitude FullImageCornersUpperRightLatitude FullImageCornersLowerRightLatitude
OV-3 PAN1 91 -92 40 50
+drop table t1;
+create table t1 ( aString char(100) not null default "", key aString (aString(10)) );
+insert t1 (aString) values ( "believe in myself" ), ( "believe" ), ("baaa" ), ( "believe in love");
+select * from t1 where aString < "believe in myself" order by aString;
aString
baaa
believe
believe in love
+select * from t1 where aString > "believe in love" order by aString;
aString
believe in myself
+alter table t1 drop key aString;
+select * from t1 where aString < "believe in myself" order by aString;
aString
baaa
believe
believe in love
+select * from t1 where aString > "believe in love" order by aString;
aString
believe in myself
count(*)
diff --git a/mysql-test/r/rename.result b/mysql-test/r/rename.result
index 57ef20e41b1..b2bb659502a 100644
--- a/mysql-test/r/rename.result
+++ b/mysql-test/r/rename.result
@@ -1,14 +1,39 @@
+drop table if exists t0,t1,t2,t3,t4;
+create table t0 SELECT 1,"table 1";
+create table t2 SELECT 2,"table 2";
+create table t3 SELECT 3,"table 3";
+rename table t0 to t1;
+rename table t3 to t4, t2 to t3, t1 to t2, t4 to t1;
+select * from t1;
3 table 3
3 table 3
+rename table t3 to t4, t2 to t3, t1 to t2, t4 to t1;
+rename table t3 to t4, t2 to t3, t1 to t2, t4 to t1;
+select * from t1;
1 table 1
1 table 1
+rename table t1 to t2;
+Got one of the listed errors
+rename table t1 to t1;
+Got one of the listed errors
+rename table t3 to t4, t2 to t3, t1 to t2, t4 to t2;
+Got one of the listed errors
+show tables like "t_";
Tables_in_test (t_)
t1
t2
t3
+rename table t3 to t1, t2 to t3, t1 to t2, t4 to t1;
+Got one of the listed errors
+rename table t3 to t4, t5 to t3, t1 to t2, t4 to t1;
+Got one of the listed errors
+select * from t1;
1 table 1
1 table 1
+select * from t2;
2 table 2
2 table 2
+select * from t3;
3 table 3
3 table 3
+drop table if exists t1,t2,t3,t4;
diff --git a/mysql-test/r/replace.result b/mysql-test/r/replace.result
index 25a6a17da35..0aa80e18ccc 100644
--- a/mysql-test/r/replace.result
+++ b/mysql-test/r/replace.result
@@ -1,3 +1,26 @@
+drop table if exists t1;
+CREATE TABLE t1 (
+gesuchnr int(11) DEFAULT '0' NOT NULL,
+benutzer_id int(11) DEFAULT '0' NOT NULL,
+PRIMARY KEY (gesuchnr,benutzer_id)
+) type=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 type=myisam;
+replace into t1 (gesuchnr,benutzer_id) values (1,1);
+alter table t1 type=heap;
+replace into t1 (gesuchnr,benutzer_id) values (1,1);
+drop table t1;
+create table t1 (a tinyint not null auto_increment primary key, b char(20));
+insert into t1 values (126,"first"),(0,"last");
+insert into t1 values (0,"error");
+Duplicate entry '127' for key 1
+replace into t1 values (0,"error");
+Duplicate entry '127' for key 1
+replace into t1 values (126,"first updated");
+select * from t1;
a b
126 first updated
127 last
+drop table t1;
diff --git a/mysql-test/r/rollback.result b/mysql-test/r/rollback.result
index ac3743e1dc7..a5eb6f8729f 100644
--- a/mysql-test/r/rollback.result
+++ b/mysql-test/r/rollback.result
@@ -1,3 +1,12 @@
+drop table if exists t1;
+create table t1 (n int not null primary key) type=myisam;
+begin work;
+insert into t1 values (4);
+insert into t1 values (5);
+rollback;
+Warning: Some non-transactional changed tables couldn't be rolled back
+select * from t1;
n
4
5
+drop table t1;
diff --git a/mysql-test/r/rpl000001.result b/mysql-test/r/rpl000001.result
index ebccb1e1e6b..60a5db1de3a 100644
--- a/mysql-test/r/rpl000001.result
+++ b/mysql-test/r/rpl000001.result
@@ -1,17 +1,95 @@
+slave stop;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+slave start;
+use test;
+drop table if exists t1,t3;
+create table t1 (word char(20) not null);
+load data infile '../../std_data/words.dat' into table t1;
+load data local infile 'MYSQL_TEST_DIR/std_data/words.dat' into table t1;
+select * from t1;
+word
+Aarhus
+Aaron
+Ababa
+aback
+abaft
+abandon
+abandoned
+abandoning
+abandonment
+abandons
+Aarhus
+Aaron
+Ababa
+aback
+abaft
+abandon
+abandoned
+abandoning
+abandonment
+abandons
+set password for root@"localhost" = password('foo');
+set password for root@"localhost" = password('');
+create table t3(n int);
+insert into t3 values(1),(2);
+use test;
+select * from t3;
n
1
2
+select sum(length(word)) from t1;
sum(length(word))
-71
+141
+drop table t1,t3;
+reset master;
+slave stop;
+reset slave;
+drop table if exists t1,t2;
+create table t1(n int);
+select get_lock("hold_slave",10);
+get_lock("hold_slave",10)
+1
+slave start;
+select release_lock("hold_slave");
+release_lock("hold_slave")
+1
+unlock tables;
+create table t2(id int);
+insert into t2 values(connection_id());
+create temporary table t1_temp(n int);
+insert into t1_temp select get_lock('crash_lock%20C', 1) from t2;
+ update t1 set n = n + get_lock('crash_lock%20C', 2);
+select (@id := id) - id from t2;
(@id := id) - id
0
+kill @id;
+drop table t2;
+Server shutdown in progress
+set sql_slave_skip_counter=1;
+slave start;
+select count(*) from t1;
count(*)
-10
+5000
+drop table t1;
+create table t1 (n int);
+insert into t1 values(3456);
+use mysql;
+insert into user (Host, User, Password)
+VALUES ("10.10.10.%", "blafasel2", password("blafasel2"));
+select select_priv,user from mysql.user where user = 'blafasel2';
select_priv user
N blafasel2
+update user set Select_priv = "Y" where User="blafasel2";
+select select_priv,user from mysql.user where user = 'blafasel2';
select_priv user
Y blafasel2
+use test;
+select n from t1;
n
3456
+select select_priv,user from mysql.user where user = 'blafasel2';
select_priv user
Y blafasel2
+drop table t1;
diff --git a/mysql-test/r/rpl000002.result b/mysql-test/r/rpl000002.result
index a68ef517708..88228321897 100644
--- a/mysql-test/r/rpl000002.result
+++ b/mysql-test/r/rpl000002.result
@@ -1,8 +1,33 @@
+slave stop;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+slave start;
+use test;
+drop table if exists t1;
+create table t1 (n int auto_increment primary key);
+set insert_id = 2000;
+insert into t1 values (NULL),(NULL),(NULL);
+use test;
+select * from t1;
n
2000
2001
2002
+show slave hosts;
+Server_id Host Port Rpl_recovery_rank Master_id
+2 127.0.0.1 $SLAVE_MYPORT 2 1
+drop table t1;
+slave stop;
+drop table if exists t2;
+create table t2(id int auto_increment primary key, created datetime);
+set timestamp=12345;
+insert into t2 set created=now();
+select * from t2;
id created
1 1970-01-01 06:25:45
+slave start;
+select * from t2;
id created
1 1970-01-01 06:25:45
+drop table t2;
diff --git a/mysql-test/r/rpl000003.result b/mysql-test/r/rpl000003.result
index f85b057eefa..eb64d1855b1 100644
--- a/mysql-test/r/rpl000003.result
+++ b/mysql-test/r/rpl000003.result
@@ -1,4 +1,16 @@
+slave stop;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+slave start;
+drop table if exists t1;
+create table t1(n int primary key);
+insert into t1 values (1),(2),(2);
+Duplicate entry '2' for key 1
+insert into t1 values (3);
+select * from t1;
n
1
2
3
+drop table t1;
diff --git a/mysql-test/r/rpl000004.result b/mysql-test/r/rpl000004.result
index a1c135a142e..e5dee880f73 100644
--- a/mysql-test/r/rpl000004.result
+++ b/mysql-test/r/rpl000004.result
@@ -1,6 +1,34 @@
+slave stop;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+slave start;
+use test;
+set SQL_LOG_BIN=0;
+drop table if exists t1;
+create table t1 (word char(20) not null, index(word));
+load data infile '../../std_data/words.dat' into table t1;
+drop table if exists t2;
+create table t2 (word char(20) not null);
+load data infile '../../std_data/words.dat' into table t2;
+create table t3 (word char(20) not null primary key);
+use test;
+drop table if exists t1;
+load table t1 from master;
+drop table if exists t2;
+load table t2 from master;
+drop table if exists t3;
+load table t3 from master;
+check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
+select count(*) from t2;
count(*)
10
+select count(*) from t3;
count(*)
0
+set SQL_LOG_BIN=1;
+drop table if exists t1,t2,t3;
+create table t1(n int);
+drop table t1;
diff --git a/mysql-test/r/rpl000005.result b/mysql-test/r/rpl000005.result
index 4f1541c75ca..0c91f984db1 100644
--- a/mysql-test/r/rpl000005.result
+++ b/mysql-test/r/rpl000005.result
@@ -1,8 +1,22 @@
+slave stop;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+slave start;
+drop table if exists t1;
+CREATE TABLE t1 (name varchar(64), age smallint(3));
+INSERT INTO t1 SET name='Andy', age=31;
+INSERT t1 SET name='Jacob', age=2;
+INSERT into t1 SET name='Caleb', age=1;
+ALTER TABLE t1 ADD id int(8) ZEROFILL AUTO_INCREMENT PRIMARY KEY;
+select * from t1;
name age id
Andy 31 00000001
Jacob 2 00000002
Caleb 1 00000003
+select * from t1;
name age id
Andy 31 00000001
Jacob 2 00000002
Caleb 1 00000003
+drop table t1;
diff --git a/mysql-test/r/rpl000006.result b/mysql-test/r/rpl000006.result
index 56cd7166510..f4e965236af 100644
--- a/mysql-test/r/rpl000006.result
+++ b/mysql-test/r/rpl000006.result
@@ -1,6 +1,30 @@
+slave stop;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+slave start;
+set SQL_LOG_BIN=0,timestamp=200006;
+drop table if exists t1;
+create table t1(t timestamp not null,a char(1));
+insert into t1 ( a) values ('F');
+select unix_timestamp(t) from t1;
unix_timestamp(t)
200006
+drop table if exists t1;
+load table t1 from master;
+select unix_timestamp(t) from t1;
unix_timestamp(t)
200006
+set SQL_LOG_BIN=1,timestamp=default;
+drop table t1;
+set SQL_LOG_BIN=0;
+CREATE TABLE t1 (
+a int not null
+) TYPE=MyISAM MAX_ROWS=4000 CHECKSUM=1;
+INSERT INTO t1 VALUES (1);
+load table t1 from master;
+check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
+drop table t1;
+drop table t1;
diff --git a/mysql-test/r/rpl000007.result b/mysql-test/r/rpl000007.result
index d5b4cdf3bee..7b2b9939228 100644
--- a/mysql-test/r/rpl000007.result
+++ b/mysql-test/r/rpl000007.result
@@ -1,2 +1,21 @@
+slave stop;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+slave start;
+use test;
+drop table if exists foo;
+create table foo (n int);
+insert into foo values(4);
+use test;
+drop table if exists foo;
+create table foo (s char(20));
+load data infile '../../std_data/words.dat' into table foo;
+insert into foo values('five');
+drop table if exists bar;
+create table bar (m int);
+insert into bar values(15);
+select foo.n,bar.m from foo,bar;
n m
4 15
+drop table if exists bar,foo;
diff --git a/mysql-test/r/rpl000008.result b/mysql-test/r/rpl000008.result
index 870e8a5510d..5ca156fecf0 100644
--- a/mysql-test/r/rpl000008.result
+++ b/mysql-test/r/rpl000008.result
@@ -1,2 +1,24 @@
+slave stop;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+slave start;
+use test;
+drop table if exists foo;
+create table foo (n int);
+insert into foo values(4);
+use test;
+drop table if exists foo;
+create table foo (n int);
+insert into foo values(5);
+drop table if exists bar;
+create table bar (m int);
+insert into bar values(15);
+drop table if exists choo;
+create table choo (k int);
+insert into choo values(55);
+select foo.n,bar.m,choo.k from foo,bar,choo;
n m k
4 15 55
+drop table if exists foo,bar,choo;
+drop table if exists foo,bar,choo;
diff --git a/mysql-test/r/rpl000009.result b/mysql-test/r/rpl000009.result
index d5b4cdf3bee..5246dadc06b 100644
--- a/mysql-test/r/rpl000009.result
+++ b/mysql-test/r/rpl000009.result
@@ -1,2 +1,82 @@
+slave stop;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+slave start;
+drop database if exists foo;
+create database foo;
+drop database if exists bar;
+create database bar;
+drop table if exists foo.foo;
+create table foo.foo (n int);
+insert into foo.foo values(4);
+drop table if exists foo.foo;
+create table foo.foo (n int);
+insert into foo.foo values(5);
+drop table if exists bar.bar;
+create table bar.bar (m int);
+insert into bar.bar values(15);
+select foo.foo.n,bar.bar.m from foo.foo,bar.bar;
n m
4 15
+drop database if exists bar;
+drop database if exists foo;
+drop database if exists bar;
+drop database if exists foo;
+set sql_log_bin = 0;
+create database foo;
+create database bar;
+show databases;
+Database
+bar
+foo
+mysql
+test
+create table foo.t1(n int, s char(20));
+create table foo.t2(n int, s text);
+insert into foo.t1 values (1, 'one'), (2, 'two'), (3, 'three');
+insert into foo.t2 values (11, 'eleven'), (12, 'twelve'), (13, 'thirteen');
+create table bar.t1(n int, s char(20));
+create table bar.t2(n int, s text);
+insert into bar.t1 values (1, 'one bar'), (2, 'two bar'), (3, 'three bar');
+insert into bar.t2 values (11, 'eleven bar'), (12, 'twelve bar'),
+(13, 'thirteen bar');
+set sql_log_bin = 1;
+show databases;
+Database
+mysql
+test
+load data from master;
+show databases;
+Database
+bar
+foo
+mysql
+test
+use foo;
+show tables;
+Tables_in_foo
+use bar;
+show tables;
+Tables_in_bar
+t1
+t2
+select * from bar.t1;
+n s
+1 one bar
+2 two bar
+3 three bar
+select * from bar.t2;
+n s
+11 eleven bar
+12 twelve bar
+13 thirteen bar
+insert into bar.t1 values (4, 'four bar');
+select * from bar.t1;
+n s
+1 one bar
+2 two bar
+3 three bar
+4 four bar
+drop database bar;
+drop database foo;
diff --git a/mysql-test/r/rpl000010.result b/mysql-test/r/rpl000010.result
index c52b83d729a..95792a72a6d 100644
--- a/mysql-test/r/rpl000010.result
+++ b/mysql-test/r/rpl000010.result
@@ -1,3 +1,15 @@
+slave stop;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+slave start;
+drop table if exists t1;
+drop table if exists t1;
+create table t1 (n int not null auto_increment primary key);
+insert into t1 values(NULL);
+insert into t1 values(2);
+select n from t1;
n
1
2
+drop table t1;
diff --git a/mysql-test/r/rpl000011.result b/mysql-test/r/rpl000011.result
index c52b83d729a..1a46f479677 100644
--- a/mysql-test/r/rpl000011.result
+++ b/mysql-test/r/rpl000011.result
@@ -1,3 +1,17 @@
+slave stop;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+slave start;
+use test;
+drop table if exists t1;
+create table t1 (n int);
+insert into t1 values(1);
+slave stop;
+slave start;
+insert into t1 values(2);
+select * from t1;
n
1
2
+drop table t1;
diff --git a/mysql-test/r/rpl000012.result b/mysql-test/r/rpl000012.result
index 9ce7037101e..c7f3ab8f578 100644
--- a/mysql-test/r/rpl000012.result
+++ b/mysql-test/r/rpl000012.result
@@ -1,3 +1,26 @@
+slave stop;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+slave start;
+drop table if exists t1,t2,t3;
+create table t2 (n int);
+create temporary table t1 (n int);
+insert into t1 values(1),(2),(3);
+insert into t2 select * from t1;
+drop table if exists test.t3;
+create temporary table test.t3 (n int not null);
+alter table test.t3 add primary key(n);
+flush logs;
+insert into t3 values (100);
+insert into t2 select * from t3;
+drop table if exists test.t3;
+insert into t2 values (101);
+create temporary table t1 (n int);
+insert into t1 values (4),(5);
+insert into t2 select * from t1;
+insert into t2 values(6);
+select * from t2;
n
1
2
@@ -7,5 +30,7 @@ n
4
5
6
+show status like 'Slave_open_temp_tables';
Variable_name Value
Slave_open_temp_tables 0
+drop table if exists t1,t2;
diff --git a/mysql-test/r/rpl000013.result b/mysql-test/r/rpl000013.result
index ec2bd0684f1..5e4b4159e3a 100644
--- a/mysql-test/r/rpl000013.result
+++ b/mysql-test/r/rpl000013.result
@@ -1,3 +1,18 @@
+slave stop;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+slave start;
+drop table if exists t2;
+create table t2(n int);
+create temporary table t1 (n int);
+insert into t1 values(1),(2),(3);
+insert into t2 select * from t1;
+create temporary table t1 (n int);
+insert into t1 values (4),(5);
+insert into t2 select * from t1 as t10;
+insert into t2 values(6);
+select * from t2;
n
1
2
@@ -5,5 +20,7 @@ n
4
5
6
+show status like 'Slave_open_temp_tables';
Variable_name Value
Slave_open_temp_tables 0
+drop table if exists t1,t2;
diff --git a/mysql-test/r/rpl000014.result b/mysql-test/r/rpl000014.result
index a47c3c91c1d..7a691119e5c 100644
--- a/mysql-test/r/rpl000014.result
+++ b/mysql-test/r/rpl000014.result
@@ -1,16 +1,39 @@
+slave stop;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+slave start;
+show master status;
File Position Binlog_do_db Binlog_ignore_db
-master-bin.001 73
-Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter
-127.0.0.1 root 9999 1 master-bin.001 73 Yes 0 0
-Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter
-127.0.0.1 root 9999 1 master-bin.001 73 No 0 0
-Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter
-127.0.0.1 root 9999 1 master-bin.001 73 Yes 0 0
-Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter
-127.0.0.1 root 9999 1 master-bin.001 173 Yes 0 0
+master-bin.001 79
+show slave status;
+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 Last_errno Last_error Skip_counter Exec_master_log_pos
+127.0.0.1 root MASTER_PORT 1 master-bin.001 79 slave-relay-bin.002 120 master-bin.001 Yes Yes 0 0 79
+change master to master_log_pos=73;
+slave stop;
+change master to master_log_pos=73;
+show slave status;
+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 Last_errno Last_error Skip_counter Exec_master_log_pos
+127.0.0.1 root MASTER_PORT 1 master-bin.001 73 slave-relay-bin.001 4 master-bin.001 No No 0 0 73
+slave start;
+show slave status;
+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 Last_errno Last_error Skip_counter Exec_master_log_pos
+127.0.0.1 root MASTER_PORT 1 master-bin.001 73 slave-relay-bin.001 4 master-bin.001 Yes Yes 0 0 73
+change master to master_log_pos=173;
+show slave status;
+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 Last_errno Last_error Skip_counter Exec_master_log_pos
+127.0.0.1 root MASTER_PORT 1 master-bin.001 173 slave-relay-bin.001 4 master-bin.001 Yes Yes 0 0 173
+show master status;
File Position Binlog_do_db Binlog_ignore_db
-master-bin.001 73
+master-bin.001 79
+create table if not exists foo(n int);
+drop table if exists foo;
+create table foo (n int);
+insert into foo values (1),(2),(3);
+change master to master_log_pos=79;
+select * from foo;
n
1
2
3
+drop table foo;
diff --git a/mysql-test/r/rpl000015.result b/mysql-test/r/rpl000015.result
index 58487af27f8..03370bc6b0d 100644
--- a/mysql-test/r/rpl000015.result
+++ b/mysql-test/r/rpl000015.result
@@ -1,14 +1,30 @@
+reset master;
+show master status;
File Position Binlog_do_db Binlog_ignore_db
-master-bin.001 73
-Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter
- 0 0 0 No 0 0
-Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter
-127.0.0.1 test 9998 60 4 No 0 0
-Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter
-127.0.0.1 root 9999 60 4 No 0 0
-Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter
-127.0.0.1 root 9999 60 master-bin.001 73 Yes 0 0
+master-bin.001 79
+reset slave;
+show slave status;
+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 Last_errno Last_error Skip_counter Exec_master_log_pos
+ 0 0 0 0 No No 0 0 0
+change master to master_host='127.0.0.1';
+show slave status;
+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 Last_errno Last_error Skip_counter Exec_master_log_pos
+127.0.0.1 test MASTER_PORT 60 4 slave-relay-bin.001 4 No No 0 0 0
+change master to master_host='127.0.0.1',master_user='root',
+master_password='',master_port=MASTER_PORT;
+show slave status;
+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 Last_errno Last_error Skip_counter Exec_master_log_pos
+127.0.0.1 root MASTER_PORT 60 4 slave-relay-bin.001 4 No No 0 0 0
+slave start;
+show slave status;
+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 Last_errno Last_error Skip_counter Exec_master_log_pos
+127.0.0.1 root MASTER_PORT 60 master-bin.001 79 slave-relay-bin.001 120 master-bin.001 Yes Yes 0 0 79
+drop table if exists t1;
+create table t1 (n int);
+insert into t1 values (10),(45),(90);
+select * from t1;
n
10
45
90
+drop table t1;
diff --git a/mysql-test/r/rpl000016.result b/mysql-test/r/rpl000016.result
index 1390291f1e8..6a91309c29c 100644
--- a/mysql-test/r/rpl000016.result
+++ b/mysql-test/r/rpl000016.result
@@ -1,30 +1,74 @@
-Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter
-127.0.0.1 root 9999 60 master-bin.001 216 Yes 0 0
+slave start;
+Could not initialize master info structure, check permisions on master.info
+slave start;
+Could not initialize master info structure, check permisions on master.info
+change master to master_host='127.0.0.1',master_port=MASTER_PORT,
+master_user='root';
+Could not initialize master info
+reset slave;
+change master to master_host='127.0.0.1',master_port=MASTER_PORT,
+master_user='root';
+reset master;
+slave start;
+drop table if exists t1;
+create table t1 (s text);
+insert into t1 values('Could not break slave'),('Tried hard');
+show slave status;
+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 Last_errno Last_error Skip_counter Exec_master_log_pos
+127.0.0.1 root MASTER_PORT 60 master-bin.001 234 slave-relay-bin.001 275 master-bin.001 Yes Yes 0 0 234
+select * from t1;
s
Could not break slave
Tried hard
+flush logs;
+drop table if exists t2;
+create table t2(m int not null auto_increment primary key);
+insert into t2 values (34),(67),(123);
+flush logs;
+show master logs;
Log_name
master-bin.001
master-bin.002
master-bin.003
+insert into t2 values(1234);
+set insert_id=1234;
+insert into t2 values(NULL);
+set sql_slave_skip_counter=1;
+slave start;
+purge master logs to 'master-bin.003';
+show master logs;
Log_name
master-bin.003
-Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter
-127.0.0.1 root 9999 60 master-bin.003 206 Yes 0 0
+insert into t2 values (65);
+show slave status;
+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 Last_errno Last_error Skip_counter Exec_master_log_pos
+127.0.0.1 root MASTER_PORT 60 master-bin.003 155 slave-relay-bin.001 755 master-bin.003 Yes Yes 0 0 155
+select * from t2;
m
34
65
67
123
1234
+drop table if exists t3;
+create table t3 (n int);
+show master logs;
Log_name
master-bin.003
master-bin.004
master-bin.005
master-bin.006
+show master status;
File Position Binlog_do_db Binlog_ignore_db
-master-bin.006 131
-Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter
-127.0.0.1 root 9999 60 master-bin.006 131 Yes 0 0
+master-bin.006 445
+slave stop;
+slave start;
+show slave status;
+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 Last_errno Last_error Skip_counter Exec_master_log_pos
+127.0.0.1 root MASTER_PORT 60 master-bin.006 445 slave-relay-bin.004 1229 master-bin.006 Yes Yes 0 0 445
+lock tables t3 read;
+select count(*) from t3 where n >= 4;
count(*)
100
+unlock tables;
+drop table if exists t1,t2,t3;
diff --git a/mysql-test/r/rpl000017.result b/mysql-test/r/rpl000017.result
index e4f324047f8..e2c3c089378 100644
--- a/mysql-test/r/rpl000017.result
+++ b/mysql-test/r/rpl000017.result
@@ -1,2 +1,11 @@
+reset master;
+grant file on *.* to replicate@localhost identified by 'aaaaaaaaaaaaaaab';
+grant file on *.* to replicate@127.0.0.1 identified by 'aaaaaaaaaaaaaaab';
+slave start;
+drop table if exists t1;
+create table t1(n int);
+insert into t1 values(24);
+select * from t1;
n
24
+drop table t1;
diff --git a/mysql-test/r/rpl000018.result b/mysql-test/r/rpl000018.result
index 7c89c2ef2b2..ba51406bba0 100644
--- a/mysql-test/r/rpl000018.result
+++ b/mysql-test/r/rpl000018.result
@@ -1,5 +1,13 @@
+reset slave;
+slave start;
+show master logs;
Log_name
master-bin.001
master-bin.002
+drop table if exists t1;
+create table t1(n int);
+insert into t1 values (3351);
+select * from t1;
n
3351
+drop table t1;
diff --git a/mysql-test/r/rpl_compat.result b/mysql-test/r/rpl_compat.result
new file mode 100644
index 00000000000..5e497791771
--- /dev/null
+++ b/mysql-test/r/rpl_compat.result
@@ -0,0 +1,77 @@
+slave stop;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+slave start;
+use test;
+drop table if exists t1,t3;
+create table t1 (word char(20) not null);
+load data infile '../../std_data/words.dat' into table t1;
+select * from t1;
+word
+Aarhus
+Aaron
+Ababa
+aback
+abaft
+abandon
+abandoned
+abandoning
+abandonment
+abandons
+set password for root@"localhost" = password('foo');
+set password for root@"localhost" = password('');
+create table t3(n int);
+insert into t3 values(1),(2);
+use test;
+select * from t3;
+n
+1
+2
+select sum(length(word)) from t1;
+sum(length(word))
+71
+drop table t1,t3;
+reset master;
+slave stop;
+reset slave;
+create table t1(n int);
+insert into t1 values (1),(2),(3);
+create table t2(id int);
+insert into t2 values(connection_id());
+create temporary table t1_temp(n int);
+insert into t1_temp select get_lock('crash_lock%20C', 1) from t2;
+ update t1 set n = n + get_lock('crash_lock%20C', 2);
+select (@id := id) - id from t2;
+(@id := id) - id
+0
+kill @id;
+drop table t2;
+Server shutdown in progress
+slave start;
+set sql_slave_skip_counter=1;
+slave start;
+select count(*) from t1;
+count(*)
+3
+drop table t1;
+create table t1 (n int);
+insert into t1 values(3456);
+use mysql;
+insert into user (Host, User, Password)
+VALUES ("10.10.10.%", "blafasel2", password("blafasel2"));
+select select_priv,user from mysql.user where user = 'blafasel2';
+select_priv user
+N blafasel2
+update user set Select_priv = "Y" where User="blafasel2";
+select select_priv,user from mysql.user where user = 'blafasel2';
+select_priv user
+Y blafasel2
+use test;
+select n from t1;
+n
+3456
+select select_priv,user from mysql.user where user = 'blafasel2';
+select_priv user
+Y blafasel2
+drop table t1;
diff --git a/mysql-test/r/rpl_failsafe.result b/mysql-test/r/rpl_failsafe.result
new file mode 100644
index 00000000000..14b749fada9
--- /dev/null
+++ b/mysql-test/r/rpl_failsafe.result
@@ -0,0 +1,33 @@
+slave stop;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+slave start;
+show variables like 'rpl_recovery_rank';
+Variable_name Value
+rpl_recovery_rank 1
+show status like 'Rpl_status';
+Variable_name Value
+Rpl_status AUTH_MASTER
+create table t1(n int);
+drop table t1;
+show variables like 'rpl_recovery_rank';
+Variable_name Value
+rpl_recovery_rank 2
+show status like 'Rpl_status';
+Variable_name Value
+Rpl_status ACTIVE_SLAVE
+slave start;
+show variables like 'rpl_recovery_rank';
+Variable_name Value
+rpl_recovery_rank 3
+show status like 'Rpl_status';
+Variable_name Value
+Rpl_status ACTIVE_SLAVE
+slave start;
+show variables like 'rpl_recovery_rank';
+Variable_name Value
+rpl_recovery_rank 4
+show status like 'Rpl_status';
+Variable_name Value
+Rpl_status ACTIVE_SLAVE
diff --git a/mysql-test/r/rpl_get_lock.result b/mysql-test/r/rpl_get_lock.result
index 84749c1a9b1..c86b8f830a5 100644
--- a/mysql-test/r/rpl_get_lock.result
+++ b/mysql-test/r/rpl_get_lock.result
@@ -1,8 +1,20 @@
+slave stop;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+slave start;
+create table t1(n int);
+insert into t1 values(get_lock("lock",2));
+select get_lock("lock",2);
get_lock("lock",2)
1
+select release_lock("lock");
release_lock("lock")
1
+select get_lock("lock",3);
get_lock("lock",3)
1
+select * from t1;
n
1
+drop table t1;
diff --git a/mysql-test/r/rpl_log.result b/mysql-test/r/rpl_log.result
new file mode 100644
index 00000000000..e91d17426c8
--- /dev/null
+++ b/mysql-test/r/rpl_log.result
@@ -0,0 +1,98 @@
+slave stop;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+slave start;
+slave stop;
+reset master;
+reset slave;
+reset master;
+drop table if exists t1;
+create table t1(n int not null auto_increment primary key);
+insert into t1 values (NULL);
+drop table t1;
+create table t1 (word char(20) not null);
+load data infile '../../std_data/words.dat' into table t1;
+drop table t1;
+show binlog events;
+Log_name Pos Event_type Server_id Orig_log_pos Info
+master-bin.001 4 Start 1 4 Server ver: VERSION, Binlog ver: 3
+master-bin.001 79 Query 1 79 use test; create table t1(n int not null auto_increment primary key)
+master-bin.001 172 Intvar 1 172 INSERT_ID=1
+master-bin.001 200 Query 1 200 use test; insert into t1 values (NULL)
+master-bin.001 263 Query 1 263 use test; drop table t1
+master-bin.001 311 Query 1 311 use test; create table t1 (word char(20) not null)
+master-bin.001 386 Create_file 1 386 db=test;table=t1;file_id=1;block_len=81
+master-bin.001 556 Exec_load 1 556 ;file_id=1
+master-bin.001 579 Query 1 579 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.001 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.001 79 Query 1 79 use test; create table t1(n int not null auto_increment primary key)
+master-bin.001 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.001 200 Query 1 200 use test; insert into t1 values (NULL)
+flush logs;
+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.001 4 Start 1 4 Server ver: VERSION, Binlog ver: 3
+master-bin.001 79 Query 1 79 use test; create table t1(n int not null auto_increment primary key)
+master-bin.001 172 Intvar 1 172 INSERT_ID=1
+master-bin.001 200 Query 1 200 use test; insert into t1 values (NULL)
+master-bin.001 263 Query 1 263 use test; drop table t1
+master-bin.001 311 Query 1 311 use test; create table t1 (word char(20) not null)
+master-bin.001 386 Create_file 1 386 db=test;table=t1;file_id=1;block_len=81
+master-bin.001 556 Exec_load 1 556 ;file_id=1
+master-bin.001 579 Query 1 579 use test; drop table t1
+master-bin.001 627 Rotate 1 627 master-bin.002;pos=4
+master-bin.001 668 Stop 1 668
+show binlog events in 'master-bin.002';
+Log_name Pos Event_type Server_id Orig_log_pos Info
+master-bin.002 4 Query 1 4 use test; create table t1 (n int)
+master-bin.002 62 Query 1 62 use test; insert into t1 values (1)
+master-bin.002 122 Query 1 122 use test; drop table t1
+show master logs;
+Log_name
+master-bin.001
+master-bin.002
+slave start;
+show master logs;
+Log_name
+slave-bin.001
+slave-bin.002
+show binlog events in 'slave-bin.001' from 4;
+show binlog events in 'slave-bin.002' from 4;
+Log_name Pos Event_type Server_id Orig_log_pos Info
+slave-bin.002 4 Slave 2 627 host=127.0.0.1,port=MASTER_PORT,log=master-bin.002,pos=4
+slave-bin.002 57 Query 1 4 use test; create table t1 (n int)
+slave-bin.002 115 Query 1 62 use test; insert into t1 values (1)
+slave-bin.002 175 Query 1 122 use test; drop table t1
+show slave status;
+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 Last_errno Last_error Skip_counter Exec_master_log_pos
+127.0.0.1 root MASTER_PORT 1 master-bin.002 170 slave-relay-bin.002 916 master-bin.002 Yes Yes 0 0 170
+show new master for slave with master_log_file='master-bin.001' and
+master_log_pos=4 and master_server_id=1;
+Log_name Log_pos
+slave-bin.001 132
+show new master for slave with master_log_file='master-bin.001' and
+master_log_pos=79 and master_server_id=1;
+Log_name Log_pos
+slave-bin.001 225
+show new master for slave with master_log_file='master-bin.001' and
+master_log_pos=311 and master_server_id=1;
+Log_name Log_pos
+slave-bin.001 439
+show new master for slave with master_log_file='master-bin.002' and
+master_log_pos=4 and master_server_id=1;
+Log_name Log_pos
+slave-bin.002 57
+show new master for slave with master_log_file='master-bin.002' and
+master_log_pos=122 and master_server_id=1;
+Log_name Log_pos
+slave-bin.002 223
diff --git a/mysql-test/r/rpl_magic.result b/mysql-test/r/rpl_magic.result
new file mode 100644
index 00000000000..b30d40d04eb
--- /dev/null
+++ b/mysql-test/r/rpl_magic.result
@@ -0,0 +1,36 @@
+slave stop;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+slave start;
+drop table if exists t1;
+create table t1 ( n int);
+insert into t1 values (1),(2),(3),(4);
+insert into t1 values(5);
+select * from t1;
+n
+1
+2
+3
+4
+5
+select * from t1;
+n
+1
+2
+3
+4
+select * from t1;
+n
+1
+2
+3
+4
+select * from t1;
+n
+1
+2
+3
+4
+5
+drop table t1;
diff --git a/mysql-test/r/rpl_mystery22.result b/mysql-test/r/rpl_mystery22.result
index f85b057eefa..e798d774380 100644
--- a/mysql-test/r/rpl_mystery22.result
+++ b/mysql-test/r/rpl_mystery22.result
@@ -1,4 +1,23 @@
+drop table if exists t1;
+slave stop;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+slave start;
+create table t1(n int auto_increment primary key);
+insert into t1 values (2);
+insert into t1 values(NULL);
+insert into t1 values(NULL);
+delete from t1 where n = 2;
+slave start;
+slave stop;
+create table t2(n int);
+drop table t2;
+insert into t1 values(NULL);
+slave start;
+select * from t1;
n
1
2
3
+drop table t1;
diff --git a/mysql-test/r/rpl_skip_error.result b/mysql-test/r/rpl_skip_error.result
index f85b057eefa..9fe92292178 100644
--- a/mysql-test/r/rpl_skip_error.result
+++ b/mysql-test/r/rpl_skip_error.result
@@ -1,3 +1,14 @@
+slave stop;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+slave start;
+drop table if exists t1;
+create table t1 (n int not null primary key);
+insert into t1 values (1);
+insert into t1 values (1);
+insert into t1 values (2),(3);
+select * from t1;
n
1
2
diff --git a/mysql-test/r/rpl_sporadic_master.result b/mysql-test/r/rpl_sporadic_master.result
index ed616c26b67..ca74904889b 100644
--- a/mysql-test/r/rpl_sporadic_master.result
+++ b/mysql-test/r/rpl_sporadic_master.result
@@ -1,3 +1,21 @@
+slave stop;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+slave start;
+drop table if exists t1,t2;
+create table t2(n int);
+create table t1(n int not null auto_increment primary key);
+insert into t1 values (NULL),(NULL);
+truncate table t1;
+insert into t1 values (4),(NULL);
+slave stop;
+slave start;
+insert into t1 values (NULL),(NULL);
+flush logs;
+truncate table t1;
+insert into t1 values (10),(NULL),(NULL),(NULL),(NULL),(NULL);
+select * from t1;
n
10
11
@@ -5,3 +23,4 @@ n
13
14
15
+drop table t1,t2;
diff --git a/mysql-test/r/sel000001.result b/mysql-test/r/sel000001.result
index bee97cc7b53..28f6d3d1d5a 100644
--- a/mysql-test/r/sel000001.result
+++ b/mysql-test/r/sel000001.result
@@ -1,2 +1,7 @@
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (s CHAR(20) PRIMARY KEY, id INT);
+INSERT INTO t1 VALUES ('cat', 1), ('mouse', 3), ('dog', 2), ('snake', 77);
+SELECT s, id FROM t1 WHERE s = 'mouse';
s id
mouse 3
+drop table t1;
diff --git a/mysql-test/r/sel000002.result b/mysql-test/r/sel000002.result
index f85b057eefa..b824de8de4a 100644
--- a/mysql-test/r/sel000002.result
+++ b/mysql-test/r/sel000002.result
@@ -1,4 +1,9 @@
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (n INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+SELECT * FROM t1;
n
1
2
3
+drop table t1;
diff --git a/mysql-test/r/sel000003.result b/mysql-test/r/sel000003.result
index 77312414818..c3853832f87 100644
--- a/mysql-test/r/sel000003.result
+++ b/mysql-test/r/sel000003.result
@@ -1,3 +1,8 @@
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (name CHAR(20) NOT NULL PRIMARY KEY, score SMALLINT NOT NULL, KEY(score));
+INSERT INTO t1 VALUES ('Sasha', 20), ('Matt', 20), ('Monty', 10), ('David', 10), ('Tim', 10), ('Jeremy', 10);
+SELECT COUNT(*) as n, score FROM t1 GROUP BY score;
n score
4 10
2 20
+drop table t1;
diff --git a/mysql-test/r/sel000031.result b/mysql-test/r/sel000031.result
index c1caa04a00a..d3f01ab687f 100644
--- a/mysql-test/r/sel000031.result
+++ b/mysql-test/r/sel000031.result
@@ -1,4 +1,12 @@
+drop table if exists t1,t2;
+create table t1 (id int(10) not null unique);
+create table t2 (id int(10) not null primary key,
+val int(10) not null);
+insert into t1 values (1),(2),(4);
+insert into t2 values (1,1),(2,1),(3,1),(4,2);
+select one.id, elt(two.val,'one','two') from t1 one, t2 two where two.id=one.id order by one.id;
id elt(two.val,'one','two')
1 one
2 one
4 two
+drop table t1,t2;
diff --git a/mysql-test/r/sel000032.result b/mysql-test/r/sel000032.result
index c1caa04a00a..4cca245d75b 100644
--- a/mysql-test/r/sel000032.result
+++ b/mysql-test/r/sel000032.result
@@ -1,4 +1,12 @@
+drop table if exists t1,t2;
+create table t1 (id int(10) not null unique);
+create table t2 (id int(10) not null primary key,
+val int(10) not null);
+insert into t1 values (1),(2),(4);
+insert into t2 values (1,1),(2,1),(3,1),(4,2);
+select one.id, elt(two.val,'one','two') from t1 one, t2 two where two.id=one.id;
id elt(two.val,'one','two')
1 one
2 one
4 two
+drop table t1,t2;
diff --git a/mysql-test/r/sel000033.result b/mysql-test/r/sel000033.result
index 689c94082e7..1bfafaf5b27 100644
--- a/mysql-test/r/sel000033.result
+++ b/mysql-test/r/sel000033.result
@@ -1,8 +1,14 @@
+drop table if exists t1;
+create table t1 (id int(10) primary key);
+insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9);
+select id from t1 where id in (2,5,9) ;
id
2
5
9
+select id from t1 where id=2 or id=5 or id=9 ;
id
2
5
9
+drop table t1;
diff --git a/mysql-test/r/sel000100.result b/mysql-test/r/sel000100.result
index e7d8cf0e7ac..f9234815a2b 100644
--- a/mysql-test/r/sel000100.result
+++ b/mysql-test/r/sel000100.result
@@ -1,2 +1,28 @@
+DROP TABLE IF EXISTS t1,t2;
+CREATE TABLE t1 (
+ID int(11) NOT NULL auto_increment,
+NAME varchar(75) DEFAULT '' NOT NULL,
+LINK_ID int(11) DEFAULT '0' NOT NULL,
+PRIMARY KEY (ID),
+KEY NAME (NAME),
+KEY LINK_ID (LINK_ID)
+);
+INSERT INTO t1 (ID, NAME, LINK_ID) VALUES (1,'Mike',0);
+INSERT INTO t1 (ID, NAME, LINK_ID) VALUES (2,'Jack',0);
+INSERT INTO t1 (ID, NAME, LINK_ID) VALUES (3,'Bill',0);
+CREATE TABLE t2 (
+ID int(11) NOT NULL auto_increment,
+NAME varchar(150) DEFAULT '' NOT NULL,
+PRIMARY KEY (ID),
+KEY NAME (NAME)
+);
+SELECT DISTINCT
+t2.id AS key_link_id,
+t2.name AS link
+FROM t1
+LEFT JOIN t2 ON t1.link_id=t2.id
+GROUP BY t1.id
+ORDER BY link;
key_link_id link
NULL NULL
+drop table t1,t2;
diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result
index 413b03130f6..051aeb43b43 100644
--- a/mysql-test/r/select.result
+++ b/mysql-test/r/select.result
@@ -1,13 +1,1237 @@
+use test;
+drop table if exists t1,t2,t3,t4;
+CREATE TABLE t1 (
+Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL,
+Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL
+);
+INSERT INTO t1 VALUES (9410,9412);
+select period from t1;
period
9410
+select * from t1;
Period Varor_period
9410 9412
+select t1.* from t1;
Period Varor_period
9410 9412
+CREATE TABLE t2 (
+auto int not null auto_increment,
+fld1 int(6) unsigned zerofill DEFAULT '000000' NOT NULL,
+companynr tinyint(2) unsigned zerofill DEFAULT '00' NOT NULL,
+fld3 char(30) DEFAULT '' NOT NULL,
+fld4 char(35) DEFAULT '' NOT NULL,
+fld5 char(35) DEFAULT '' NOT NULL,
+fld6 char(4) DEFAULT '' NOT NULL,
+UNIQUE fld1 (fld1),
+KEY fld3 (fld3),
+PRIMARY KEY (auto)
+);
+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','');
+INSERT INTO t2 VALUES (4,011403,37,'intercepted','audiology','tinily','');
+INSERT INTO t2 VALUES (5,011501,37,'bewilderingly','wallet','balled','');
+INSERT INTO t2 VALUES (6,011701,37,'astound','parters','persist','W');
+INSERT INTO t2 VALUES (7,011702,37,'admonishing','eschew','attainments','');
+INSERT INTO t2 VALUES (8,011703,37,'sumac','quitter','fanatic','');
+INSERT INTO t2 VALUES (9,012001,37,'flanking','neat','measures','FAS');
+INSERT INTO t2 VALUES (10,012003,37,'combed','Steinberg','rightfulness','');
+INSERT INTO t2 VALUES (11,012004,37,'subjective','jarring','capably','');
+INSERT INTO t2 VALUES (12,012005,37,'scatterbrain','tinily','impulsive','');
+INSERT INTO t2 VALUES (13,012301,37,'Eulerian','balled','starlet','');
+INSERT INTO t2 VALUES (14,012302,36,'dubbed','persist','terminators','');
+INSERT INTO t2 VALUES (15,012303,37,'Kane','attainments','untying','');
+INSERT INTO t2 VALUES (16,012304,37,'overlay','fanatic','announces','FAS');
+INSERT INTO t2 VALUES (17,012305,37,'perturb','measures','featherweight','FAS');
+INSERT INTO t2 VALUES (18,012306,37,'goblins','rightfulness','pessimist','FAS');
+INSERT INTO t2 VALUES (19,012501,37,'annihilates','capably','daughter','');
+INSERT INTO t2 VALUES (20,012602,37,'Wotan','impulsive','decliner','FAS');
+INSERT INTO t2 VALUES (21,012603,37,'snatching','starlet','lawgiver','');
+INSERT INTO t2 VALUES (22,012604,37,'concludes','terminators','stated','');
+INSERT INTO t2 VALUES (23,012605,37,'laterally','untying','readable','');
+INSERT INTO t2 VALUES (24,012606,37,'yelped','announces','attrition','');
+INSERT INTO t2 VALUES (25,012701,37,'grazing','featherweight','cascade','FAS');
+INSERT INTO t2 VALUES (26,012702,37,'Baird','pessimist','motors','FAS');
+INSERT INTO t2 VALUES (27,012703,37,'celery','daughter','interrogate','');
+INSERT INTO t2 VALUES (28,012704,37,'misunderstander','decliner','pests','W');
+INSERT INTO t2 VALUES (29,013601,37,'handgun','lawgiver','stairway','');
+INSERT INTO t2 VALUES (30,013602,37,'foldout','stated','dopers','FAS');
+INSERT INTO t2 VALUES (31,013603,37,'mystic','readable','testicle','W');
+INSERT INTO t2 VALUES (32,013604,37,'succumbed','attrition','Parsifal','W');
+INSERT INTO t2 VALUES (33,013605,37,'Nabisco','cascade','leavings','');
+INSERT INTO t2 VALUES (34,013606,37,'fingerings','motors','postulation','W');
+INSERT INTO t2 VALUES (35,013607,37,'aging','interrogate','squeaking','');
+INSERT INTO t2 VALUES (36,013608,37,'afield','pests','contrasted','');
+INSERT INTO t2 VALUES (37,013609,37,'ammonium','stairway','leftover','');
+INSERT INTO t2 VALUES (38,013610,37,'boat','dopers','whiteners','');
+INSERT INTO t2 VALUES (39,013801,37,'intelligibility','testicle','erases','W');
+INSERT INTO t2 VALUES (40,013802,37,'Augustine','Parsifal','Punjab','W');
+INSERT INTO t2 VALUES (41,013803,37,'teethe','leavings','Merritt','');
+INSERT INTO t2 VALUES (42,013804,37,'dreaded','postulation','Quixotism','');
+INSERT INTO t2 VALUES (43,013901,37,'scholastics','squeaking','sweetish','FAS');
+INSERT INTO t2 VALUES (44,016001,37,'audiology','contrasted','dogging','FAS');
+INSERT INTO t2 VALUES (45,016201,37,'wallet','leftover','scornfully','FAS');
+INSERT INTO t2 VALUES (46,016202,37,'parters','whiteners','bellow','');
+INSERT INTO t2 VALUES (47,016301,37,'eschew','erases','bills','');
+INSERT INTO t2 VALUES (48,016302,37,'quitter','Punjab','cupboard','FAS');
+INSERT INTO t2 VALUES (49,016303,37,'neat','Merritt','sureties','FAS');
+INSERT INTO t2 VALUES (50,016304,37,'Steinberg','Quixotism','puddings','');
+INSERT INTO t2 VALUES (51,018001,37,'jarring','sweetish','tapestry','');
+INSERT INTO t2 VALUES (52,018002,37,'tinily','dogging','fetters','');
+INSERT INTO t2 VALUES (53,018003,37,'balled','scornfully','bivalves','');
+INSERT INTO t2 VALUES (54,018004,37,'persist','bellow','incurring','');
+INSERT INTO t2 VALUES (55,018005,37,'attainments','bills','Adolph','');
+INSERT INTO t2 VALUES (56,018007,37,'fanatic','cupboard','pithed','');
+INSERT INTO t2 VALUES (57,018008,37,'measures','sureties','emergency','');
+INSERT INTO t2 VALUES (58,018009,37,'rightfulness','puddings','Miles','');
+INSERT INTO t2 VALUES (59,018010,37,'capably','tapestry','trimmings','');
+INSERT INTO t2 VALUES (60,018012,37,'impulsive','fetters','tragedies','W');
+INSERT INTO t2 VALUES (61,018013,37,'starlet','bivalves','skulking','W');
+INSERT INTO t2 VALUES (62,018014,37,'terminators','incurring','flint','');
+INSERT INTO t2 VALUES (63,018015,37,'untying','Adolph','flopping','W');
+INSERT INTO t2 VALUES (64,018016,37,'announces','pithed','relaxing','FAS');
+INSERT INTO t2 VALUES (65,018017,37,'featherweight','emergency','offload','FAS');
+INSERT INTO t2 VALUES (66,018018,37,'pessimist','Miles','suites','W');
+INSERT INTO t2 VALUES (67,018019,37,'daughter','trimmings','lists','FAS');
+INSERT INTO t2 VALUES (68,018020,37,'decliner','tragedies','animized','FAS');
+INSERT INTO t2 VALUES (69,018021,37,'lawgiver','skulking','multilayer','W');
+INSERT INTO t2 VALUES (70,018022,37,'stated','flint','standardizes','FAS');
+INSERT INTO t2 VALUES (71,018023,37,'readable','flopping','Judas','');
+INSERT INTO t2 VALUES (72,018024,37,'attrition','relaxing','vacuuming','W');
+INSERT INTO t2 VALUES (73,018025,37,'cascade','offload','dentally','W');
+INSERT INTO t2 VALUES (74,018026,37,'motors','suites','humanness','W');
+INSERT INTO t2 VALUES (75,018027,37,'interrogate','lists','inch','W');
+INSERT INTO t2 VALUES (76,018028,37,'pests','animized','Weissmuller','W');
+INSERT INTO t2 VALUES (77,018029,37,'stairway','multilayer','irresponsibly','W');
+INSERT INTO t2 VALUES (78,018030,37,'dopers','standardizes','luckily','FAS');
+INSERT INTO t2 VALUES (79,018032,37,'testicle','Judas','culled','W');
+INSERT INTO t2 VALUES (80,018033,37,'Parsifal','vacuuming','medical','FAS');
+INSERT INTO t2 VALUES (81,018034,37,'leavings','dentally','bloodbath','FAS');
+INSERT INTO t2 VALUES (82,018035,37,'postulation','humanness','subschema','W');
+INSERT INTO t2 VALUES (83,018036,37,'squeaking','inch','animals','W');
+INSERT INTO t2 VALUES (84,018037,37,'contrasted','Weissmuller','Micronesia','');
+INSERT INTO t2 VALUES (85,018038,37,'leftover','irresponsibly','repetitions','');
+INSERT INTO t2 VALUES (86,018039,37,'whiteners','luckily','Antares','');
+INSERT INTO t2 VALUES (87,018040,37,'erases','culled','ventilate','W');
+INSERT INTO t2 VALUES (88,018041,37,'Punjab','medical','pityingly','');
+INSERT INTO t2 VALUES (89,018042,37,'Merritt','bloodbath','interdependent','');
+INSERT INTO t2 VALUES (90,018043,37,'Quixotism','subschema','Graves','FAS');
+INSERT INTO t2 VALUES (91,018044,37,'sweetish','animals','neonatal','');
+INSERT INTO t2 VALUES (92,018045,37,'dogging','Micronesia','scribbled','FAS');
+INSERT INTO t2 VALUES (93,018046,37,'scornfully','repetitions','chafe','W');
+INSERT INTO t2 VALUES (94,018048,37,'bellow','Antares','honoring','');
+INSERT INTO t2 VALUES (95,018049,37,'bills','ventilate','realtor','');
+INSERT INTO t2 VALUES (96,018050,37,'cupboard','pityingly','elite','');
+INSERT INTO t2 VALUES (97,018051,37,'sureties','interdependent','funereal','');
+INSERT INTO t2 VALUES (98,018052,37,'puddings','Graves','abrogating','');
+INSERT INTO t2 VALUES (99,018053,50,'tapestry','neonatal','sorters','');
+INSERT INTO t2 VALUES (100,018054,37,'fetters','scribbled','Conley','');
+INSERT INTO t2 VALUES (101,018055,37,'bivalves','chafe','lectured','');
+INSERT INTO t2 VALUES (102,018056,37,'incurring','honoring','Abraham','');
+INSERT INTO t2 VALUES (103,018057,37,'Adolph','realtor','Hawaii','W');
+INSERT INTO t2 VALUES (104,018058,37,'pithed','elite','cage','');
+INSERT INTO t2 VALUES (105,018059,36,'emergency','funereal','hushes','');
+INSERT INTO t2 VALUES (106,018060,37,'Miles','abrogating','Simla','');
+INSERT INTO t2 VALUES (107,018061,37,'trimmings','sorters','reporters','');
+INSERT INTO t2 VALUES (108,018101,37,'tragedies','Conley','Dutchman','FAS');
+INSERT INTO t2 VALUES (109,018102,37,'skulking','lectured','descendants','FAS');
+INSERT INTO t2 VALUES (110,018103,37,'flint','Abraham','groupings','FAS');
+INSERT INTO t2 VALUES (111,018104,37,'flopping','Hawaii','dissociate','');
+INSERT INTO t2 VALUES (112,018201,37,'relaxing','cage','coexist','W');
+INSERT INTO t2 VALUES (113,018202,37,'offload','hushes','Beebe','');
+INSERT INTO t2 VALUES (114,018402,37,'suites','Simla','Taoism','');
+INSERT INTO t2 VALUES (115,018403,37,'lists','reporters','Connally','');
+INSERT INTO t2 VALUES (116,018404,37,'animized','Dutchman','fetched','FAS');
+INSERT INTO t2 VALUES (117,018405,37,'multilayer','descendants','checkpoints','FAS');
+INSERT INTO t2 VALUES (118,018406,37,'standardizes','groupings','rusting','');
+INSERT INTO t2 VALUES (119,018409,37,'Judas','dissociate','galling','');
+INSERT INTO t2 VALUES (120,018601,37,'vacuuming','coexist','obliterates','');
+INSERT INTO t2 VALUES (121,018602,37,'dentally','Beebe','traitor','');
+INSERT INTO t2 VALUES (122,018603,37,'humanness','Taoism','resumes','FAS');
+INSERT INTO t2 VALUES (123,018801,37,'inch','Connally','analyzable','FAS');
+INSERT INTO t2 VALUES (124,018802,37,'Weissmuller','fetched','terminator','FAS');
+INSERT INTO t2 VALUES (125,018803,37,'irresponsibly','checkpoints','gritty','FAS');
+INSERT INTO t2 VALUES (126,018804,37,'luckily','rusting','firearm','W');
+INSERT INTO t2 VALUES (127,018805,37,'culled','galling','minima','');
+INSERT INTO t2 VALUES (128,018806,37,'medical','obliterates','Selfridge','');
+INSERT INTO t2 VALUES (129,018807,37,'bloodbath','traitor','disable','');
+INSERT INTO t2 VALUES (130,018808,37,'subschema','resumes','witchcraft','W');
+INSERT INTO t2 VALUES (131,018809,37,'animals','analyzable','betroth','W');
+INSERT INTO t2 VALUES (132,018810,37,'Micronesia','terminator','Manhattanize','');
+INSERT INTO t2 VALUES (133,018811,37,'repetitions','gritty','imprint','');
+INSERT INTO t2 VALUES (134,018812,37,'Antares','firearm','peeked','');
+INSERT INTO t2 VALUES (135,019101,37,'ventilate','minima','swelling','');
+INSERT INTO t2 VALUES (136,019102,37,'pityingly','Selfridge','interrelationships','W');
+INSERT INTO t2 VALUES (137,019103,37,'interdependent','disable','riser','');
+INSERT INTO t2 VALUES (138,019201,37,'Graves','witchcraft','Gandhian','W');
+INSERT INTO t2 VALUES (139,030501,37,'neonatal','betroth','peacock','A');
+INSERT INTO t2 VALUES (140,030502,50,'scribbled','Manhattanize','bee','A');
+INSERT INTO t2 VALUES (141,030503,37,'chafe','imprint','kanji','');
+INSERT INTO t2 VALUES (142,030504,37,'honoring','peeked','dental','');
+INSERT INTO t2 VALUES (143,031901,37,'realtor','swelling','scarf','FAS');
+INSERT INTO t2 VALUES (144,036001,37,'elite','interrelationships','chasm','A');
+INSERT INTO t2 VALUES (145,036002,37,'funereal','riser','insolence','A');
+INSERT INTO t2 VALUES (146,036004,37,'abrogating','Gandhian','syndicate','');
+INSERT INTO t2 VALUES (147,036005,37,'sorters','peacock','alike','');
+INSERT INTO t2 VALUES (148,038001,37,'Conley','bee','imperial','A');
+INSERT INTO t2 VALUES (149,038002,37,'lectured','kanji','convulsion','A');
+INSERT INTO t2 VALUES (150,038003,37,'Abraham','dental','railway','A');
+INSERT INTO t2 VALUES (151,038004,37,'Hawaii','scarf','validate','A');
+INSERT INTO t2 VALUES (152,038005,37,'cage','chasm','normalizes','A');
+INSERT INTO t2 VALUES (153,038006,37,'hushes','insolence','comprehensive','');
+INSERT INTO t2 VALUES (154,038007,37,'Simla','syndicate','chewing','');
+INSERT INTO t2 VALUES (155,038008,37,'reporters','alike','denizen','');
+INSERT INTO t2 VALUES (156,038009,37,'Dutchman','imperial','schemer','');
+INSERT INTO t2 VALUES (157,038010,37,'descendants','convulsion','chronicle','');
+INSERT INTO t2 VALUES (158,038011,37,'groupings','railway','Kline','');
+INSERT INTO t2 VALUES (159,038012,37,'dissociate','validate','Anatole','');
+INSERT INTO t2 VALUES (160,038013,37,'coexist','normalizes','partridges','');
+INSERT INTO t2 VALUES (161,038014,37,'Beebe','comprehensive','brunch','');
+INSERT INTO t2 VALUES (162,038015,37,'Taoism','chewing','recruited','');
+INSERT INTO t2 VALUES (163,038016,37,'Connally','denizen','dimensions','W');
+INSERT INTO t2 VALUES (164,038017,37,'fetched','schemer','Chicana','W');
+INSERT INTO t2 VALUES (165,038018,37,'checkpoints','chronicle','announced','');
+INSERT INTO t2 VALUES (166,038101,37,'rusting','Kline','praised','FAS');
+INSERT INTO t2 VALUES (167,038102,37,'galling','Anatole','employing','');
+INSERT INTO t2 VALUES (168,038103,37,'obliterates','partridges','linear','');
+INSERT INTO t2 VALUES (169,038104,37,'traitor','brunch','quagmire','');
+INSERT INTO t2 VALUES (170,038201,37,'resumes','recruited','western','A');
+INSERT INTO t2 VALUES (171,038202,37,'analyzable','dimensions','relishing','');
+INSERT INTO t2 VALUES (172,038203,37,'terminator','Chicana','serving','A');
+INSERT INTO t2 VALUES (173,038204,37,'gritty','announced','scheduling','');
+INSERT INTO t2 VALUES (174,038205,37,'firearm','praised','lore','');
+INSERT INTO t2 VALUES (175,038206,37,'minima','employing','eventful','');
+INSERT INTO t2 VALUES (176,038208,37,'Selfridge','linear','arteriole','A');
+INSERT INTO t2 VALUES (177,042801,37,'disable','quagmire','disentangle','');
+INSERT INTO t2 VALUES (178,042802,37,'witchcraft','western','cured','A');
+INSERT INTO t2 VALUES (179,046101,37,'betroth','relishing','Fenton','W');
+INSERT INTO t2 VALUES (180,048001,37,'Manhattanize','serving','avoidable','A');
+INSERT INTO t2 VALUES (181,048002,37,'imprint','scheduling','drains','A');
+INSERT INTO t2 VALUES (182,048003,37,'peeked','lore','detectably','FAS');
+INSERT INTO t2 VALUES (183,048004,37,'swelling','eventful','husky','');
+INSERT INTO t2 VALUES (184,048005,37,'interrelationships','arteriole','impelling','');
+INSERT INTO t2 VALUES (185,048006,37,'riser','disentangle','undoes','');
+INSERT INTO t2 VALUES (186,048007,37,'Gandhian','cured','evened','');
+INSERT INTO t2 VALUES (187,048008,37,'peacock','Fenton','squeezes','');
+INSERT INTO t2 VALUES (188,048101,37,'bee','avoidable','destroyer','FAS');
+INSERT INTO t2 VALUES (189,048102,37,'kanji','drains','rudeness','');
+INSERT INTO t2 VALUES (190,048201,37,'dental','detectably','beaner','FAS');
+INSERT INTO t2 VALUES (191,048202,37,'scarf','husky','boorish','');
+INSERT INTO t2 VALUES (192,048203,37,'chasm','impelling','Everhart','');
+INSERT INTO t2 VALUES (193,048204,37,'insolence','undoes','encompass','A');
+INSERT INTO t2 VALUES (194,048205,37,'syndicate','evened','mushrooms','');
+INSERT INTO t2 VALUES (195,048301,37,'alike','squeezes','Alison','A');
+INSERT INTO t2 VALUES (196,048302,37,'imperial','destroyer','externally','FAS');
+INSERT INTO t2 VALUES (197,048303,37,'convulsion','rudeness','pellagra','');
+INSERT INTO t2 VALUES (198,048304,37,'railway','beaner','cult','');
+INSERT INTO t2 VALUES (199,048305,37,'validate','boorish','creek','A');
+INSERT INTO t2 VALUES (200,048401,37,'normalizes','Everhart','Huffman','');
+INSERT INTO t2 VALUES (201,048402,37,'comprehensive','encompass','Majorca','FAS');
+INSERT INTO t2 VALUES (202,048403,37,'chewing','mushrooms','governing','A');
+INSERT INTO t2 VALUES (203,048404,37,'denizen','Alison','gadfly','FAS');
+INSERT INTO t2 VALUES (204,048405,37,'schemer','externally','reassigned','FAS');
+INSERT INTO t2 VALUES (205,048406,37,'chronicle','pellagra','intentness','W');
+INSERT INTO t2 VALUES (206,048407,37,'Kline','cult','craziness','');
+INSERT INTO t2 VALUES (207,048408,37,'Anatole','creek','psychic','');
+INSERT INTO t2 VALUES (208,048409,37,'partridges','Huffman','squabbled','');
+INSERT INTO t2 VALUES (209,048410,37,'brunch','Majorca','burlesque','');
+INSERT INTO t2 VALUES (210,048411,37,'recruited','governing','capped','');
+INSERT INTO t2 VALUES (211,048412,37,'dimensions','gadfly','extracted','A');
+INSERT INTO t2 VALUES (212,048413,37,'Chicana','reassigned','DiMaggio','');
+INSERT INTO t2 VALUES (213,048601,37,'announced','intentness','exclamation','FAS');
+INSERT INTO t2 VALUES (214,048602,37,'praised','craziness','subdirectory','');
+INSERT INTO t2 VALUES (215,048603,37,'employing','psychic','fangs','');
+INSERT INTO t2 VALUES (216,048604,37,'linear','squabbled','buyer','A');
+INSERT INTO t2 VALUES (217,048801,37,'quagmire','burlesque','pithing','A');
+INSERT INTO t2 VALUES (218,050901,37,'western','capped','transistorizing','A');
+INSERT INTO t2 VALUES (219,051201,37,'relishing','extracted','nonbiodegradable','');
+INSERT INTO t2 VALUES (220,056002,37,'serving','DiMaggio','dislocate','');
+INSERT INTO t2 VALUES (221,056003,37,'scheduling','exclamation','monochromatic','FAS');
+INSERT INTO t2 VALUES (222,056004,37,'lore','subdirectory','batting','');
+INSERT INTO t2 VALUES (223,056102,37,'eventful','fangs','postcondition','A');
+INSERT INTO t2 VALUES (224,056203,37,'arteriole','buyer','catalog','FAS');
+INSERT INTO t2 VALUES (225,056204,37,'disentangle','pithing','Remus','');
+INSERT INTO t2 VALUES (226,058003,37,'cured','transistorizing','devices','A');
+INSERT INTO t2 VALUES (227,058004,37,'Fenton','nonbiodegradable','bike','A');
+INSERT INTO t2 VALUES (228,058005,37,'avoidable','dislocate','qualify','');
+INSERT INTO t2 VALUES (229,058006,37,'drains','monochromatic','detained','');
+INSERT INTO t2 VALUES (230,058007,37,'detectably','batting','commended','');
+INSERT INTO t2 VALUES (231,058101,37,'husky','postcondition','civilize','');
+INSERT INTO t2 VALUES (232,058102,37,'impelling','catalog','Elmhurst','');
+INSERT INTO t2 VALUES (233,058103,37,'undoes','Remus','anesthetizing','');
+INSERT INTO t2 VALUES (234,058105,37,'evened','devices','deaf','');
+INSERT INTO t2 VALUES (235,058111,37,'squeezes','bike','Brigham','');
+INSERT INTO t2 VALUES (236,058112,37,'destroyer','qualify','title','');
+INSERT INTO t2 VALUES (237,058113,37,'rudeness','detained','coarse','');
+INSERT INTO t2 VALUES (238,058114,37,'beaner','commended','combinations','');
+INSERT INTO t2 VALUES (239,058115,37,'boorish','civilize','grayness','');
+INSERT INTO t2 VALUES (240,058116,37,'Everhart','Elmhurst','innumerable','FAS');
+INSERT INTO t2 VALUES (241,058117,37,'encompass','anesthetizing','Caroline','A');
+INSERT INTO t2 VALUES (242,058118,37,'mushrooms','deaf','fatty','FAS');
+INSERT INTO t2 VALUES (243,058119,37,'Alison','Brigham','eastbound','');
+INSERT INTO t2 VALUES (244,058120,37,'externally','title','inexperienced','');
+INSERT INTO t2 VALUES (245,058121,37,'pellagra','coarse','hoarder','A');
+INSERT INTO t2 VALUES (246,058122,37,'cult','combinations','scotch','W');
+INSERT INTO t2 VALUES (247,058123,37,'creek','grayness','passport','A');
+INSERT INTO t2 VALUES (248,058124,37,'Huffman','innumerable','strategic','FAS');
+INSERT INTO t2 VALUES (249,058125,37,'Majorca','Caroline','gated','');
+INSERT INTO t2 VALUES (250,058126,37,'governing','fatty','flog','');
+INSERT INTO t2 VALUES (251,058127,37,'gadfly','eastbound','Pipestone','');
+INSERT INTO t2 VALUES (252,058128,37,'reassigned','inexperienced','Dar','');
+INSERT INTO t2 VALUES (253,058201,37,'intentness','hoarder','Corcoran','');
+INSERT INTO t2 VALUES (254,058202,37,'craziness','scotch','flyers','A');
+INSERT INTO t2 VALUES (255,058303,37,'psychic','passport','competitions','W');
+INSERT INTO t2 VALUES (256,058304,37,'squabbled','strategic','suppliers','FAS');
+INSERT INTO t2 VALUES (257,058602,37,'burlesque','gated','skips','');
+INSERT INTO t2 VALUES (258,058603,37,'capped','flog','institutes','');
+INSERT INTO t2 VALUES (259,058604,37,'extracted','Pipestone','troop','A');
+INSERT INTO t2 VALUES (260,058605,37,'DiMaggio','Dar','connective','W');
+INSERT INTO t2 VALUES (261,058606,37,'exclamation','Corcoran','denies','');
+INSERT INTO t2 VALUES (262,058607,37,'subdirectory','flyers','polka','');
+INSERT INTO t2 VALUES (263,060401,36,'fangs','competitions','observations','FAS');
+INSERT INTO t2 VALUES (264,061701,36,'buyer','suppliers','askers','');
+INSERT INTO t2 VALUES (265,066201,36,'pithing','skips','homeless','FAS');
+INSERT INTO t2 VALUES (266,066501,36,'transistorizing','institutes','Anna','');
+INSERT INTO t2 VALUES (267,068001,36,'nonbiodegradable','troop','subdirectories','W');
+INSERT INTO t2 VALUES (268,068002,36,'dislocate','connective','decaying','FAS');
+INSERT INTO t2 VALUES (269,068005,36,'monochromatic','denies','outwitting','W');
+INSERT INTO t2 VALUES (270,068006,36,'batting','polka','Harpy','W');
+INSERT INTO t2 VALUES (271,068007,36,'postcondition','observations','crazed','');
+INSERT INTO t2 VALUES (272,068008,36,'catalog','askers','suffocate','');
+INSERT INTO t2 VALUES (273,068009,36,'Remus','homeless','provers','FAS');
+INSERT INTO t2 VALUES (274,068010,36,'devices','Anna','technically','');
+INSERT INTO t2 VALUES (275,068011,36,'bike','subdirectories','Franklinizations','');
+INSERT INTO t2 VALUES (276,068202,36,'qualify','decaying','considered','');
+INSERT INTO t2 VALUES (277,068302,36,'detained','outwitting','tinnily','');
+INSERT INTO t2 VALUES (278,068303,36,'commended','Harpy','uninterruptedly','');
+INSERT INTO t2 VALUES (279,068401,36,'civilize','crazed','whistled','A');
+INSERT INTO t2 VALUES (280,068501,36,'Elmhurst','suffocate','automate','');
+INSERT INTO t2 VALUES (281,068502,36,'anesthetizing','provers','gutting','W');
+INSERT INTO t2 VALUES (282,068503,36,'deaf','technically','surreptitious','');
+INSERT INTO t2 VALUES (283,068602,36,'Brigham','Franklinizations','Choctaw','');
+INSERT INTO t2 VALUES (284,068603,36,'title','considered','cooks','');
+INSERT INTO t2 VALUES (285,068701,36,'coarse','tinnily','millivolt','FAS');
+INSERT INTO t2 VALUES (286,068702,36,'combinations','uninterruptedly','counterpoise','');
+INSERT INTO t2 VALUES (287,068703,36,'grayness','whistled','Gothicism','');
+INSERT INTO t2 VALUES (288,076001,36,'innumerable','automate','feminine','');
+INSERT INTO t2 VALUES (289,076002,36,'Caroline','gutting','metaphysically','W');
+INSERT INTO t2 VALUES (290,076101,36,'fatty','surreptitious','sanding','A');
+INSERT INTO t2 VALUES (291,076102,36,'eastbound','Choctaw','contributorily','');
+INSERT INTO t2 VALUES (292,076103,36,'inexperienced','cooks','receivers','FAS');
+INSERT INTO t2 VALUES (293,076302,36,'hoarder','millivolt','adjourn','');
+INSERT INTO t2 VALUES (294,076303,36,'scotch','counterpoise','straggled','A');
+INSERT INTO t2 VALUES (295,076304,36,'passport','Gothicism','druggists','');
+INSERT INTO t2 VALUES (296,076305,36,'strategic','feminine','thanking','FAS');
+INSERT INTO t2 VALUES (297,076306,36,'gated','metaphysically','ostrich','');
+INSERT INTO t2 VALUES (298,076307,36,'flog','sanding','hopelessness','FAS');
+INSERT INTO t2 VALUES (299,076402,36,'Pipestone','contributorily','Eurydice','');
+INSERT INTO t2 VALUES (300,076501,36,'Dar','receivers','excitation','W');
+INSERT INTO t2 VALUES (301,076502,36,'Corcoran','adjourn','presumes','FAS');
+INSERT INTO t2 VALUES (302,076701,36,'flyers','straggled','imaginable','FAS');
+INSERT INTO t2 VALUES (303,078001,36,'competitions','druggists','concoct','W');
+INSERT INTO t2 VALUES (304,078002,36,'suppliers','thanking','peering','W');
+INSERT INTO t2 VALUES (305,078003,36,'skips','ostrich','Phelps','FAS');
+INSERT INTO t2 VALUES (306,078004,36,'institutes','hopelessness','ferociousness','FAS');
+INSERT INTO t2 VALUES (307,078005,36,'troop','Eurydice','sentences','');
+INSERT INTO t2 VALUES (308,078006,36,'connective','excitation','unlocks','');
+INSERT INTO t2 VALUES (309,078007,36,'denies','presumes','engrossing','W');
+INSERT INTO t2 VALUES (310,078008,36,'polka','imaginable','Ruth','');
+INSERT INTO t2 VALUES (311,078101,36,'observations','concoct','tying','');
+INSERT INTO t2 VALUES (312,078103,36,'askers','peering','exclaimers','');
+INSERT INTO t2 VALUES (313,078104,36,'homeless','Phelps','synergy','');
+INSERT INTO t2 VALUES (314,078105,36,'Anna','ferociousness','Huey','W');
+INSERT INTO t2 VALUES (315,082101,36,'subdirectories','sentences','merging','');
+INSERT INTO t2 VALUES (316,083401,36,'decaying','unlocks','judges','A');
+INSERT INTO t2 VALUES (317,084001,36,'outwitting','engrossing','Shylock','W');
+INSERT INTO t2 VALUES (318,084002,36,'Harpy','Ruth','Miltonism','');
+INSERT INTO t2 VALUES (319,086001,36,'crazed','tying','hen','W');
+INSERT INTO t2 VALUES (320,086102,36,'suffocate','exclaimers','honeybee','FAS');
+INSERT INTO t2 VALUES (321,086201,36,'provers','synergy','towers','');
+INSERT INTO t2 VALUES (322,088001,36,'technically','Huey','dilutes','W');
+INSERT INTO t2 VALUES (323,088002,36,'Franklinizations','merging','numerals','FAS');
+INSERT INTO t2 VALUES (324,088003,36,'considered','judges','democracy','FAS');
+INSERT INTO t2 VALUES (325,088004,36,'tinnily','Shylock','Ibero-','');
+INSERT INTO t2 VALUES (326,088101,36,'uninterruptedly','Miltonism','invalids','');
+INSERT INTO t2 VALUES (327,088102,36,'whistled','hen','behavior','');
+INSERT INTO t2 VALUES (328,088103,36,'automate','honeybee','accruing','');
+INSERT INTO t2 VALUES (329,088104,36,'gutting','towers','relics','A');
+INSERT INTO t2 VALUES (330,088105,36,'surreptitious','dilutes','rackets','');
+INSERT INTO t2 VALUES (331,088106,36,'Choctaw','numerals','Fischbein','W');
+INSERT INTO t2 VALUES (332,088201,36,'cooks','democracy','phony','W');
+INSERT INTO t2 VALUES (333,088203,36,'millivolt','Ibero-','cross','FAS');
+INSERT INTO t2 VALUES (334,088204,36,'counterpoise','invalids','cleanup','');
+INSERT INTO t2 VALUES (335,088302,37,'Gothicism','behavior','conspirator','');
+INSERT INTO t2 VALUES (336,088303,37,'feminine','accruing','label','FAS');
+INSERT INTO t2 VALUES (337,088305,37,'metaphysically','relics','university','');
+INSERT INTO t2 VALUES (338,088402,37,'sanding','rackets','cleansed','FAS');
+INSERT INTO t2 VALUES (339,088501,36,'contributorily','Fischbein','ballgown','');
+INSERT INTO t2 VALUES (340,088502,36,'receivers','phony','starlet','');
+INSERT INTO t2 VALUES (341,088503,36,'adjourn','cross','aqueous','');
+INSERT INTO t2 VALUES (342,098001,58,'straggled','cleanup','portrayal','A');
+INSERT INTO t2 VALUES (343,098002,58,'druggists','conspirator','despising','W');
+INSERT INTO t2 VALUES (344,098003,58,'thanking','label','distort','W');
+INSERT INTO t2 VALUES (345,098004,58,'ostrich','university','palmed','');
+INSERT INTO t2 VALUES (346,098005,58,'hopelessness','cleansed','faced','');
+INSERT INTO t2 VALUES (347,098006,58,'Eurydice','ballgown','silverware','');
+INSERT INTO t2 VALUES (348,141903,29,'excitation','starlet','assessor','');
+INSERT INTO t2 VALUES (349,098008,58,'presumes','aqueous','spiders','');
+INSERT INTO t2 VALUES (350,098009,58,'imaginable','portrayal','artificially','');
+INSERT INTO t2 VALUES (351,098010,58,'concoct','despising','reminiscence','');
+INSERT INTO t2 VALUES (352,098011,58,'peering','distort','Mexican','');
+INSERT INTO t2 VALUES (353,098012,58,'Phelps','palmed','obnoxious','');
+INSERT INTO t2 VALUES (354,098013,58,'ferociousness','faced','fragile','');
+INSERT INTO t2 VALUES (355,098014,58,'sentences','silverware','apprehensible','');
+INSERT INTO t2 VALUES (356,098015,58,'unlocks','assessor','births','');
+INSERT INTO t2 VALUES (357,098016,58,'engrossing','spiders','garages','');
+INSERT INTO t2 VALUES (358,098017,58,'Ruth','artificially','panty','');
+INSERT INTO t2 VALUES (359,098018,58,'tying','reminiscence','anteater','');
+INSERT INTO t2 VALUES (360,098019,58,'exclaimers','Mexican','displacement','A');
+INSERT INTO t2 VALUES (361,098020,58,'synergy','obnoxious','drovers','A');
+INSERT INTO t2 VALUES (362,098021,58,'Huey','fragile','patenting','A');
+INSERT INTO t2 VALUES (363,098022,58,'merging','apprehensible','far','A');
+INSERT INTO t2 VALUES (364,098023,58,'judges','births','shrieks','');
+INSERT INTO t2 VALUES (365,098024,58,'Shylock','garages','aligning','W');
+INSERT INTO t2 VALUES (366,098025,37,'Miltonism','panty','pragmatism','');
+INSERT INTO t2 VALUES (367,106001,36,'hen','anteater','fevers','W');
+INSERT INTO t2 VALUES (368,108001,36,'honeybee','displacement','reexamines','A');
+INSERT INTO t2 VALUES (369,108002,36,'towers','drovers','occupancies','');
+INSERT INTO t2 VALUES (370,108003,36,'dilutes','patenting','sweats','FAS');
+INSERT INTO t2 VALUES (371,108004,36,'numerals','far','modulators','');
+INSERT INTO t2 VALUES (372,108005,36,'democracy','shrieks','demand','W');
+INSERT INTO t2 VALUES (373,108007,36,'Ibero-','aligning','Madeira','');
+INSERT INTO t2 VALUES (374,108008,36,'invalids','pragmatism','Viennese','W');
+INSERT INTO t2 VALUES (375,108009,36,'behavior','fevers','chillier','W');
+INSERT INTO t2 VALUES (376,108010,36,'accruing','reexamines','wildcats','FAS');
+INSERT INTO t2 VALUES (377,108011,36,'relics','occupancies','gentle','');
+INSERT INTO t2 VALUES (378,108012,36,'rackets','sweats','Angles','W');
+INSERT INTO t2 VALUES (379,108101,36,'Fischbein','modulators','accuracies','');
+INSERT INTO t2 VALUES (380,108102,36,'phony','demand','toggle','');
+INSERT INTO t2 VALUES (381,108103,36,'cross','Madeira','Mendelssohn','W');
+INSERT INTO t2 VALUES (382,108111,50,'cleanup','Viennese','behaviorally','');
+INSERT INTO t2 VALUES (383,108105,36,'conspirator','chillier','Rochford','');
+INSERT INTO t2 VALUES (384,108106,36,'label','wildcats','mirror','W');
+INSERT INTO t2 VALUES (385,108107,36,'university','gentle','Modula','');
+INSERT INTO t2 VALUES (386,108108,50,'cleansed','Angles','clobbering','');
+INSERT INTO t2 VALUES (387,108109,36,'ballgown','accuracies','chronography','');
+INSERT INTO t2 VALUES (388,108110,36,'starlet','toggle','Eskimoizeds','');
+INSERT INTO t2 VALUES (389,108201,36,'aqueous','Mendelssohn','British','W');
+INSERT INTO t2 VALUES (390,108202,36,'portrayal','behaviorally','pitfalls','');
+INSERT INTO t2 VALUES (391,108203,36,'despising','Rochford','verify','W');
+INSERT INTO t2 VALUES (392,108204,36,'distort','mirror','scatter','FAS');
+INSERT INTO t2 VALUES (393,108205,36,'palmed','Modula','Aztecan','');
+INSERT INTO t2 VALUES (394,108301,36,'faced','clobbering','acuity','W');
+INSERT INTO t2 VALUES (395,108302,36,'silverware','chronography','sinking','W');
+INSERT INTO t2 VALUES (396,112101,36,'assessor','Eskimoizeds','beasts','FAS');
+INSERT INTO t2 VALUES (397,112102,36,'spiders','British','Witt','W');
+INSERT INTO t2 VALUES (398,113701,36,'artificially','pitfalls','physicists','FAS');
+INSERT INTO t2 VALUES (399,116001,36,'reminiscence','verify','folksong','A');
+INSERT INTO t2 VALUES (400,116201,36,'Mexican','scatter','strokes','FAS');
+INSERT INTO t2 VALUES (401,116301,36,'obnoxious','Aztecan','crowder','');
+INSERT INTO t2 VALUES (402,116302,36,'fragile','acuity','merry','');
+INSERT INTO t2 VALUES (403,116601,36,'apprehensible','sinking','cadenced','');
+INSERT INTO t2 VALUES (404,116602,36,'births','beasts','alimony','A');
+INSERT INTO t2 VALUES (405,116603,36,'garages','Witt','principled','A');
+INSERT INTO t2 VALUES (406,116701,36,'panty','physicists','golfing','');
+INSERT INTO t2 VALUES (407,116702,36,'anteater','folksong','undiscovered','');
+INSERT INTO t2 VALUES (408,118001,36,'displacement','strokes','irritates','');
+INSERT INTO t2 VALUES (409,118002,36,'drovers','crowder','patriots','A');
+INSERT INTO t2 VALUES (410,118003,36,'patenting','merry','rooms','FAS');
+INSERT INTO t2 VALUES (411,118004,36,'far','cadenced','towering','W');
+INSERT INTO t2 VALUES (412,118005,36,'shrieks','alimony','displease','');
+INSERT INTO t2 VALUES (413,118006,36,'aligning','principled','photosensitive','');
+INSERT INTO t2 VALUES (414,118007,36,'pragmatism','golfing','inking','');
+INSERT INTO t2 VALUES (415,118008,36,'fevers','undiscovered','gainers','');
+INSERT INTO t2 VALUES (416,118101,36,'reexamines','irritates','leaning','A');
+INSERT INTO t2 VALUES (417,118102,36,'occupancies','patriots','hydrant','A');
+INSERT INTO t2 VALUES (418,118103,36,'sweats','rooms','preserve','');
+INSERT INTO t2 VALUES (419,118202,36,'modulators','towering','blinded','A');
+INSERT INTO t2 VALUES (420,118203,36,'demand','displease','interactions','A');
+INSERT INTO t2 VALUES (421,118204,36,'Madeira','photosensitive','Barry','');
+INSERT INTO t2 VALUES (422,118302,36,'Viennese','inking','whiteness','A');
+INSERT INTO t2 VALUES (423,118304,36,'chillier','gainers','pastimes','W');
+INSERT INTO t2 VALUES (424,118305,36,'wildcats','leaning','Edenization','');
+INSERT INTO t2 VALUES (425,118306,36,'gentle','hydrant','Muscat','');
+INSERT INTO t2 VALUES (426,118307,36,'Angles','preserve','assassinated','');
+INSERT INTO t2 VALUES (427,123101,36,'accuracies','blinded','labeled','');
+INSERT INTO t2 VALUES (428,123102,36,'toggle','interactions','glacial','A');
+INSERT INTO t2 VALUES (429,123301,36,'Mendelssohn','Barry','implied','W');
+INSERT INTO t2 VALUES (430,126001,36,'behaviorally','whiteness','bibliographies','W');
+INSERT INTO t2 VALUES (431,126002,36,'Rochford','pastimes','Buchanan','');
+INSERT INTO t2 VALUES (432,126003,36,'mirror','Edenization','forgivably','FAS');
+INSERT INTO t2 VALUES (433,126101,36,'Modula','Muscat','innuendo','A');
+INSERT INTO t2 VALUES (434,126301,36,'clobbering','assassinated','den','FAS');
+INSERT INTO t2 VALUES (435,126302,36,'chronography','labeled','submarines','W');
+INSERT INTO t2 VALUES (436,126402,36,'Eskimoizeds','glacial','mouthful','A');
+INSERT INTO t2 VALUES (437,126601,36,'British','implied','expiring','');
+INSERT INTO t2 VALUES (438,126602,36,'pitfalls','bibliographies','unfulfilled','FAS');
+INSERT INTO t2 VALUES (439,126702,36,'verify','Buchanan','precession','');
+INSERT INTO t2 VALUES (440,128001,36,'scatter','forgivably','nullified','');
+INSERT INTO t2 VALUES (441,128002,36,'Aztecan','innuendo','affects','');
+INSERT INTO t2 VALUES (442,128003,36,'acuity','den','Cynthia','');
+INSERT INTO t2 VALUES (443,128004,36,'sinking','submarines','Chablis','A');
+INSERT INTO t2 VALUES (444,128005,36,'beasts','mouthful','betterments','FAS');
+INSERT INTO t2 VALUES (445,128007,36,'Witt','expiring','advertising','');
+INSERT INTO t2 VALUES (446,128008,36,'physicists','unfulfilled','rubies','A');
+INSERT INTO t2 VALUES (447,128009,36,'folksong','precession','southwest','FAS');
+INSERT INTO t2 VALUES (448,128010,36,'strokes','nullified','superstitious','A');
+INSERT INTO t2 VALUES (449,128011,36,'crowder','affects','tabernacle','W');
+INSERT INTO t2 VALUES (450,128012,36,'merry','Cynthia','silk','A');
+INSERT INTO t2 VALUES (451,128013,36,'cadenced','Chablis','handsomest','A');
+INSERT INTO t2 VALUES (452,128014,36,'alimony','betterments','Persian','A');
+INSERT INTO t2 VALUES (453,128015,36,'principled','advertising','analog','W');
+INSERT INTO t2 VALUES (454,128016,36,'golfing','rubies','complex','W');
+INSERT INTO t2 VALUES (455,128017,36,'undiscovered','southwest','Taoist','');
+INSERT INTO t2 VALUES (456,128018,36,'irritates','superstitious','suspend','');
+INSERT INTO t2 VALUES (457,128019,36,'patriots','tabernacle','relegated','');
+INSERT INTO t2 VALUES (458,128020,36,'rooms','silk','awesome','W');
+INSERT INTO t2 VALUES (459,128021,36,'towering','handsomest','Bruxelles','');
+INSERT INTO t2 VALUES (460,128022,36,'displease','Persian','imprecisely','A');
+INSERT INTO t2 VALUES (461,128023,36,'photosensitive','analog','televise','');
+INSERT INTO t2 VALUES (462,128101,36,'inking','complex','braking','');
+INSERT INTO t2 VALUES (463,128102,36,'gainers','Taoist','true','FAS');
+INSERT INTO t2 VALUES (464,128103,36,'leaning','suspend','disappointing','FAS');
+INSERT INTO t2 VALUES (465,128104,36,'hydrant','relegated','navally','W');
+INSERT INTO t2 VALUES (466,128106,36,'preserve','awesome','circus','');
+INSERT INTO t2 VALUES (467,128107,36,'blinded','Bruxelles','beetles','');
+INSERT INTO t2 VALUES (468,128108,36,'interactions','imprecisely','trumps','');
+INSERT INTO t2 VALUES (469,128202,36,'Barry','televise','fourscore','W');
+INSERT INTO t2 VALUES (470,128203,36,'whiteness','braking','Blackfoots','');
+INSERT INTO t2 VALUES (471,128301,36,'pastimes','true','Grady','');
+INSERT INTO t2 VALUES (472,128302,36,'Edenization','disappointing','quiets','FAS');
+INSERT INTO t2 VALUES (473,128303,36,'Muscat','navally','floundered','FAS');
+INSERT INTO t2 VALUES (474,128304,36,'assassinated','circus','profundity','W');
+INSERT INTO t2 VALUES (475,128305,36,'labeled','beetles','Garrisonian','W');
+INSERT INTO t2 VALUES (476,128307,36,'glacial','trumps','Strauss','');
+INSERT INTO t2 VALUES (477,128401,36,'implied','fourscore','cemented','FAS');
+INSERT INTO t2 VALUES (478,128502,36,'bibliographies','Blackfoots','contrition','A');
+INSERT INTO t2 VALUES (479,128503,36,'Buchanan','Grady','mutations','');
+INSERT INTO t2 VALUES (480,128504,36,'forgivably','quiets','exhibits','W');
+INSERT INTO t2 VALUES (481,128505,36,'innuendo','floundered','tits','');
+INSERT INTO t2 VALUES (482,128601,36,'den','profundity','mate','A');
+INSERT INTO t2 VALUES (483,128603,36,'submarines','Garrisonian','arches','');
+INSERT INTO t2 VALUES (484,128604,36,'mouthful','Strauss','Moll','');
+INSERT INTO t2 VALUES (485,128702,36,'expiring','cemented','ropers','');
+INSERT INTO t2 VALUES (486,128703,36,'unfulfilled','contrition','bombast','');
+INSERT INTO t2 VALUES (487,128704,36,'precession','mutations','difficultly','A');
+INSERT INTO t2 VALUES (488,138001,36,'nullified','exhibits','adsorption','');
+INSERT INTO t2 VALUES (489,138002,36,'affects','tits','definiteness','FAS');
+INSERT INTO t2 VALUES (490,138003,36,'Cynthia','mate','cultivation','A');
+INSERT INTO t2 VALUES (491,138004,36,'Chablis','arches','heals','A');
+INSERT INTO t2 VALUES (492,138005,36,'betterments','Moll','Heusen','W');
+INSERT INTO t2 VALUES (493,138006,36,'advertising','ropers','target','FAS');
+INSERT INTO t2 VALUES (494,138007,36,'rubies','bombast','cited','A');
+INSERT INTO t2 VALUES (495,138008,36,'southwest','difficultly','congresswoman','W');
+INSERT INTO t2 VALUES (496,138009,36,'superstitious','adsorption','Katherine','');
+INSERT INTO t2 VALUES (497,138102,36,'tabernacle','definiteness','titter','A');
+INSERT INTO t2 VALUES (498,138103,36,'silk','cultivation','aspire','A');
+INSERT INTO t2 VALUES (499,138104,36,'handsomest','heals','Mardis','');
+INSERT INTO t2 VALUES (500,138105,36,'Persian','Heusen','Nadia','W');
+INSERT INTO t2 VALUES (501,138201,36,'analog','target','estimating','FAS');
+INSERT INTO t2 VALUES (502,138302,36,'complex','cited','stuck','A');
+INSERT INTO t2 VALUES (503,138303,36,'Taoist','congresswoman','fifteenth','A');
+INSERT INTO t2 VALUES (504,138304,36,'suspend','Katherine','Colombo','');
+INSERT INTO t2 VALUES (505,138401,29,'relegated','titter','survey','A');
+INSERT INTO t2 VALUES (506,140102,29,'awesome','aspire','staffing','');
+INSERT INTO t2 VALUES (507,140103,29,'Bruxelles','Mardis','obtain','');
+INSERT INTO t2 VALUES (508,140104,29,'imprecisely','Nadia','loaded','');
+INSERT INTO t2 VALUES (509,140105,29,'televise','estimating','slaughtered','');
+INSERT INTO t2 VALUES (510,140201,29,'braking','stuck','lights','A');
+INSERT INTO t2 VALUES (511,140701,29,'true','fifteenth','circumference','');
+INSERT INTO t2 VALUES (512,141501,29,'disappointing','Colombo','dull','A');
+INSERT INTO t2 VALUES (513,141502,29,'navally','survey','weekly','A');
+INSERT INTO t2 VALUES (514,141901,29,'circus','staffing','wetness','');
+INSERT INTO t2 VALUES (515,141902,29,'beetles','obtain','visualized','');
+INSERT INTO t2 VALUES (516,142101,29,'trumps','loaded','Tannenbaum','');
+INSERT INTO t2 VALUES (517,142102,29,'fourscore','slaughtered','moribund','');
+INSERT INTO t2 VALUES (518,142103,29,'Blackfoots','lights','demultiplex','');
+INSERT INTO t2 VALUES (519,142701,29,'Grady','circumference','lockings','');
+INSERT INTO t2 VALUES (520,143001,29,'quiets','dull','thugs','FAS');
+INSERT INTO t2 VALUES (521,143501,29,'floundered','weekly','unnerves','');
+INSERT INTO t2 VALUES (522,143502,29,'profundity','wetness','abut','');
+INSERT INTO t2 VALUES (523,148001,29,'Garrisonian','visualized','Chippewa','A');
+INSERT INTO t2 VALUES (524,148002,29,'Strauss','Tannenbaum','stratifications','A');
+INSERT INTO t2 VALUES (525,148003,29,'cemented','moribund','signaled','');
+INSERT INTO t2 VALUES (526,148004,29,'contrition','demultiplex','Italianizes','A');
+INSERT INTO t2 VALUES (527,148005,29,'mutations','lockings','algorithmic','A');
+INSERT INTO t2 VALUES (528,148006,29,'exhibits','thugs','paranoid','FAS');
+INSERT INTO t2 VALUES (529,148007,29,'tits','unnerves','camping','A');
+INSERT INTO t2 VALUES (530,148009,29,'mate','abut','signifying','A');
+INSERT INTO t2 VALUES (531,148010,29,'arches','Chippewa','Patrice','W');
+INSERT INTO t2 VALUES (532,148011,29,'Moll','stratifications','search','A');
+INSERT INTO t2 VALUES (533,148012,29,'ropers','signaled','Angeles','A');
+INSERT INTO t2 VALUES (534,148013,29,'bombast','Italianizes','semblance','');
+INSERT INTO t2 VALUES (535,148023,36,'difficultly','algorithmic','taxed','');
+INSERT INTO t2 VALUES (536,148015,29,'adsorption','paranoid','Beatrice','');
+INSERT INTO t2 VALUES (537,148016,29,'definiteness','camping','retrace','');
+INSERT INTO t2 VALUES (538,148017,29,'cultivation','signifying','lockout','');
+INSERT INTO t2 VALUES (539,148018,29,'heals','Patrice','grammatic','');
+INSERT INTO t2 VALUES (540,148019,29,'Heusen','search','helmsman','');
+INSERT INTO t2 VALUES (541,148020,29,'target','Angeles','uniform','W');
+INSERT INTO t2 VALUES (542,148021,29,'cited','semblance','hamming','');
+INSERT INTO t2 VALUES (543,148022,29,'congresswoman','taxed','disobedience','');
+INSERT INTO t2 VALUES (544,148101,29,'Katherine','Beatrice','captivated','A');
+INSERT INTO t2 VALUES (545,148102,29,'titter','retrace','transferals','A');
+INSERT INTO t2 VALUES (546,148201,29,'aspire','lockout','cartographer','A');
+INSERT INTO t2 VALUES (547,148401,29,'Mardis','grammatic','aims','FAS');
+INSERT INTO t2 VALUES (548,148402,29,'Nadia','helmsman','Pakistani','');
+INSERT INTO t2 VALUES (549,148501,29,'estimating','uniform','burglarized','FAS');
+INSERT INTO t2 VALUES (550,148502,29,'stuck','hamming','saucepans','A');
+INSERT INTO t2 VALUES (551,148503,29,'fifteenth','disobedience','lacerating','A');
+INSERT INTO t2 VALUES (552,148504,29,'Colombo','captivated','corny','');
+INSERT INTO t2 VALUES (553,148601,29,'survey','transferals','megabytes','FAS');
+INSERT INTO t2 VALUES (554,148602,29,'staffing','cartographer','chancellor','');
+INSERT INTO t2 VALUES (555,150701,29,'obtain','aims','bulk','A');
+INSERT INTO t2 VALUES (556,152101,29,'loaded','Pakistani','commits','A');
+INSERT INTO t2 VALUES (557,152102,29,'slaughtered','burglarized','meson','W');
+INSERT INTO t2 VALUES (558,155202,36,'lights','saucepans','deputies','');
+INSERT INTO t2 VALUES (559,155203,29,'circumference','lacerating','northeaster','A');
+INSERT INTO t2 VALUES (560,155204,29,'dull','corny','dipole','');
+INSERT INTO t2 VALUES (561,155205,29,'weekly','megabytes','machining','0');
+INSERT INTO t2 VALUES (562,156001,29,'wetness','chancellor','therefore','');
+INSERT INTO t2 VALUES (563,156002,29,'visualized','bulk','Telefunken','');
+INSERT INTO t2 VALUES (564,156102,29,'Tannenbaum','commits','salvaging','');
+INSERT INTO t2 VALUES (565,156301,29,'moribund','meson','Corinthianizes','A');
+INSERT INTO t2 VALUES (566,156302,29,'demultiplex','deputies','restlessly','A');
+INSERT INTO t2 VALUES (567,156303,29,'lockings','northeaster','bromides','');
+INSERT INTO t2 VALUES (568,156304,29,'thugs','dipole','generalized','A');
+INSERT INTO t2 VALUES (569,156305,29,'unnerves','machining','mishaps','');
+INSERT INTO t2 VALUES (570,156306,29,'abut','therefore','quelling','');
+INSERT INTO t2 VALUES (571,156501,29,'Chippewa','Telefunken','spiritual','A');
+INSERT INTO t2 VALUES (572,158001,29,'stratifications','salvaging','beguiles','FAS');
+INSERT INTO t2 VALUES (573,158002,29,'signaled','Corinthianizes','Trobriand','FAS');
+INSERT INTO t2 VALUES (574,158101,29,'Italianizes','restlessly','fleeing','A');
+INSERT INTO t2 VALUES (575,158102,29,'algorithmic','bromides','Armour','A');
+INSERT INTO t2 VALUES (576,158103,29,'paranoid','generalized','chin','A');
+INSERT INTO t2 VALUES (577,158201,29,'camping','mishaps','provers','A');
+INSERT INTO t2 VALUES (578,158202,29,'signifying','quelling','aeronautic','A');
+INSERT INTO t2 VALUES (579,158203,29,'Patrice','spiritual','voltage','W');
+INSERT INTO t2 VALUES (580,158204,29,'search','beguiles','sash','');
+INSERT INTO t2 VALUES (581,158301,29,'Angeles','Trobriand','anaerobic','A');
+INSERT INTO t2 VALUES (582,158302,29,'semblance','fleeing','simultaneous','A');
+INSERT INTO t2 VALUES (583,158303,29,'taxed','Armour','accumulating','A');
+INSERT INTO t2 VALUES (584,158304,29,'Beatrice','chin','Medusan','A');
+INSERT INTO t2 VALUES (585,158305,29,'retrace','provers','shouted','A');
+INSERT INTO t2 VALUES (586,158306,29,'lockout','aeronautic','freakish','');
+INSERT INTO t2 VALUES (587,158501,29,'grammatic','voltage','index','FAS');
+INSERT INTO t2 VALUES (588,160301,29,'helmsman','sash','commercially','');
+INSERT INTO t2 VALUES (589,166101,50,'uniform','anaerobic','mistiness','A');
+INSERT INTO t2 VALUES (590,166102,50,'hamming','simultaneous','endpoint','');
+INSERT INTO t2 VALUES (591,168001,29,'disobedience','accumulating','straight','A');
+INSERT INTO t2 VALUES (592,168002,29,'captivated','Medusan','flurried','');
+INSERT INTO t2 VALUES (593,168003,29,'transferals','shouted','denotative','A');
+INSERT INTO t2 VALUES (594,168101,29,'cartographer','freakish','coming','FAS');
+INSERT INTO t2 VALUES (595,168102,29,'aims','index','commencements','FAS');
+INSERT INTO t2 VALUES (596,168103,29,'Pakistani','commercially','gentleman','');
+INSERT INTO t2 VALUES (597,168104,29,'burglarized','mistiness','gifted','');
+INSERT INTO t2 VALUES (598,168202,29,'saucepans','endpoint','Shanghais','');
+INSERT INTO t2 VALUES (599,168301,29,'lacerating','straight','sportswriting','A');
+INSERT INTO t2 VALUES (600,168502,29,'corny','flurried','sloping','A');
+INSERT INTO t2 VALUES (601,168503,29,'megabytes','denotative','navies','');
+INSERT INTO t2 VALUES (602,168601,29,'chancellor','coming','leaflet','A');
+INSERT INTO t2 VALUES (603,173001,40,'bulk','commencements','shooter','');
+INSERT INTO t2 VALUES (604,173701,40,'commits','gentleman','Joplin','FAS');
+INSERT INTO t2 VALUES (605,173702,40,'meson','gifted','babies','');
+INSERT INTO t2 VALUES (606,176001,40,'deputies','Shanghais','subdivision','FAS');
+INSERT INTO t2 VALUES (607,176101,40,'northeaster','sportswriting','burstiness','W');
+INSERT INTO t2 VALUES (608,176201,40,'dipole','sloping','belted','FAS');
+INSERT INTO t2 VALUES (609,176401,40,'machining','navies','assails','FAS');
+INSERT INTO t2 VALUES (610,176501,40,'therefore','leaflet','admiring','W');
+INSERT INTO t2 VALUES (611,176601,40,'Telefunken','shooter','swaying','0');
+INSERT INTO t2 VALUES (612,176602,40,'salvaging','Joplin','Goldstine','FAS');
+INSERT INTO t2 VALUES (613,176603,40,'Corinthianizes','babies','fitting','');
+INSERT INTO t2 VALUES (614,178001,40,'restlessly','subdivision','Norwalk','W');
+INSERT INTO t2 VALUES (615,178002,40,'bromides','burstiness','weakening','W');
+INSERT INTO t2 VALUES (616,178003,40,'generalized','belted','analogy','FAS');
+INSERT INTO t2 VALUES (617,178004,40,'mishaps','assails','deludes','');
+INSERT INTO t2 VALUES (618,178005,40,'quelling','admiring','cokes','');
+INSERT INTO t2 VALUES (619,178006,40,'spiritual','swaying','Clayton','');
+INSERT INTO t2 VALUES (620,178007,40,'beguiles','Goldstine','exhausts','');
+INSERT INTO t2 VALUES (621,178008,40,'Trobriand','fitting','causality','');
+INSERT INTO t2 VALUES (622,178101,40,'fleeing','Norwalk','sating','FAS');
+INSERT INTO t2 VALUES (623,178102,40,'Armour','weakening','icon','');
+INSERT INTO t2 VALUES (624,178103,40,'chin','analogy','throttles','');
+INSERT INTO t2 VALUES (625,178201,40,'provers','deludes','communicants','FAS');
+INSERT INTO t2 VALUES (626,178202,40,'aeronautic','cokes','dehydrate','FAS');
+INSERT INTO t2 VALUES (627,178301,40,'voltage','Clayton','priceless','FAS');
+INSERT INTO t2 VALUES (628,178302,40,'sash','exhausts','publicly','');
+INSERT INTO t2 VALUES (629,178401,40,'anaerobic','causality','incidentals','FAS');
+INSERT INTO t2 VALUES (630,178402,40,'simultaneous','sating','commonplace','');
+INSERT INTO t2 VALUES (631,178403,40,'accumulating','icon','mumbles','');
+INSERT INTO t2 VALUES (632,178404,40,'Medusan','throttles','furthermore','W');
+INSERT INTO t2 VALUES (633,178501,40,'shouted','communicants','cautioned','W');
+INSERT INTO t2 VALUES (634,186002,37,'freakish','dehydrate','parametrized','A');
+INSERT INTO t2 VALUES (635,186102,37,'index','priceless','registration','A');
+INSERT INTO t2 VALUES (636,186201,40,'commercially','publicly','sadly','FAS');
+INSERT INTO t2 VALUES (637,186202,40,'mistiness','incidentals','positioning','');
+INSERT INTO t2 VALUES (638,186203,40,'endpoint','commonplace','babysitting','');
+INSERT INTO t2 VALUES (639,186302,37,'straight','mumbles','eternal','A');
+INSERT INTO t2 VALUES (640,188007,37,'flurried','furthermore','hoarder','');
+INSERT INTO t2 VALUES (641,188008,37,'denotative','cautioned','congregates','');
+INSERT INTO t2 VALUES (642,188009,37,'coming','parametrized','rains','');
+INSERT INTO t2 VALUES (643,188010,37,'commencements','registration','workers','W');
+INSERT INTO t2 VALUES (644,188011,37,'gentleman','sadly','sags','A');
+INSERT INTO t2 VALUES (645,188012,37,'gifted','positioning','unplug','W');
+INSERT INTO t2 VALUES (646,188013,37,'Shanghais','babysitting','garage','A');
+INSERT INTO t2 VALUES (647,188014,37,'sportswriting','eternal','boulder','A');
+INSERT INTO t2 VALUES (648,188015,37,'sloping','hoarder','hollowly','A');
+INSERT INTO t2 VALUES (649,188016,37,'navies','congregates','specifics','');
+INSERT INTO t2 VALUES (650,188017,37,'leaflet','rains','Teresa','');
+INSERT INTO t2 VALUES (651,188102,37,'shooter','workers','Winsett','');
+INSERT INTO t2 VALUES (652,188103,37,'Joplin','sags','convenient','A');
+INSERT INTO t2 VALUES (653,188202,37,'babies','unplug','buckboards','FAS');
+INSERT INTO t2 VALUES (654,188301,40,'subdivision','garage','amenities','');
+INSERT INTO t2 VALUES (655,188302,40,'burstiness','boulder','resplendent','FAS');
+INSERT INTO t2 VALUES (656,188303,40,'belted','hollowly','priding','FAS');
+INSERT INTO t2 VALUES (657,188401,37,'assails','specifics','configurations','');
+INSERT INTO t2 VALUES (658,188402,37,'admiring','Teresa','untidiness','A');
+INSERT INTO t2 VALUES (659,188503,37,'swaying','Winsett','Brice','W');
+INSERT INTO t2 VALUES (660,188504,37,'Goldstine','convenient','sews','FAS');
+INSERT INTO t2 VALUES (661,188505,37,'fitting','buckboards','participated','');
+INSERT INTO t2 VALUES (662,190701,37,'Norwalk','amenities','Simon','FAS');
+INSERT INTO t2 VALUES (663,190703,50,'weakening','resplendent','certificates','');
+INSERT INTO t2 VALUES (664,191701,37,'analogy','priding','Fitzpatrick','');
+INSERT INTO t2 VALUES (665,191702,37,'deludes','configurations','Evanston','A');
+INSERT INTO t2 VALUES (666,191703,37,'cokes','untidiness','misted','');
+INSERT INTO t2 VALUES (667,196001,37,'Clayton','Brice','textures','A');
+INSERT INTO t2 VALUES (668,196002,37,'exhausts','sews','save','');
+INSERT INTO t2 VALUES (669,196003,37,'causality','participated','count','');
+INSERT INTO t2 VALUES (670,196101,37,'sating','Simon','rightful','A');
+INSERT INTO t2 VALUES (671,196103,37,'icon','certificates','chaperone','');
+INSERT INTO t2 VALUES (672,196104,37,'throttles','Fitzpatrick','Lizzy','A');
+INSERT INTO t2 VALUES (673,196201,37,'communicants','Evanston','clenched','A');
+INSERT INTO t2 VALUES (674,196202,37,'dehydrate','misted','effortlessly','');
+INSERT INTO t2 VALUES (675,196203,37,'priceless','textures','accessed','');
+INSERT INTO t2 VALUES (676,198001,37,'publicly','save','beaters','A');
+INSERT INTO t2 VALUES (677,198003,37,'incidentals','count','Hornblower','FAS');
+INSERT INTO t2 VALUES (678,198004,37,'commonplace','rightful','vests','A');
+INSERT INTO t2 VALUES (679,198005,37,'mumbles','chaperone','indulgences','FAS');
+INSERT INTO t2 VALUES (680,198006,37,'furthermore','Lizzy','infallibly','A');
+INSERT INTO t2 VALUES (681,198007,37,'cautioned','clenched','unwilling','FAS');
+INSERT INTO t2 VALUES (682,198008,37,'parametrized','effortlessly','excrete','FAS');
+INSERT INTO t2 VALUES (683,198009,37,'registration','accessed','spools','A');
+INSERT INTO t2 VALUES (684,198010,37,'sadly','beaters','crunches','FAS');
+INSERT INTO t2 VALUES (685,198011,37,'positioning','Hornblower','overestimating','FAS');
+INSERT INTO t2 VALUES (686,198012,37,'babysitting','vests','ineffective','');
+INSERT INTO t2 VALUES (687,198013,37,'eternal','indulgences','humiliation','A');
+INSERT INTO t2 VALUES (688,198014,37,'hoarder','infallibly','sophomore','');
+INSERT INTO t2 VALUES (689,198015,37,'congregates','unwilling','star','');
+INSERT INTO t2 VALUES (690,198017,37,'rains','excrete','rifles','');
+INSERT INTO t2 VALUES (691,198018,37,'workers','spools','dialysis','');
+INSERT INTO t2 VALUES (692,198019,37,'sags','crunches','arriving','');
+INSERT INTO t2 VALUES (693,198020,37,'unplug','overestimating','indulge','');
+INSERT INTO t2 VALUES (694,198021,37,'garage','ineffective','clockers','');
+INSERT INTO t2 VALUES (695,198022,37,'boulder','humiliation','languages','');
+INSERT INTO t2 VALUES (696,198023,50,'hollowly','sophomore','Antarctica','A');
+INSERT INTO t2 VALUES (697,198024,37,'specifics','star','percentage','');
+INSERT INTO t2 VALUES (698,198101,37,'Teresa','rifles','ceiling','A');
+INSERT INTO t2 VALUES (699,198103,37,'Winsett','dialysis','specification','');
+INSERT INTO t2 VALUES (700,198105,37,'convenient','arriving','regimented','A');
+INSERT INTO t2 VALUES (701,198106,37,'buckboards','indulge','ciphers','');
+INSERT INTO t2 VALUES (702,198201,37,'amenities','clockers','pictures','A');
+INSERT INTO t2 VALUES (703,198204,37,'resplendent','languages','serpents','A');
+INSERT INTO t2 VALUES (704,198301,53,'priding','Antarctica','allot','A');
+INSERT INTO t2 VALUES (705,198302,53,'configurations','percentage','realized','A');
+INSERT INTO t2 VALUES (706,198303,53,'untidiness','ceiling','mayoral','A');
+INSERT INTO t2 VALUES (707,198304,53,'Brice','specification','opaquely','A');
+INSERT INTO t2 VALUES (708,198401,37,'sews','regimented','hostess','FAS');
+INSERT INTO t2 VALUES (709,198402,37,'participated','ciphers','fiftieth','');
+INSERT INTO t2 VALUES (710,198403,37,'Simon','pictures','incorrectly','');
+INSERT INTO t2 VALUES (711,202101,37,'certificates','serpents','decomposition','FAS');
+INSERT INTO t2 VALUES (712,202301,37,'Fitzpatrick','allot','stranglings','');
+INSERT INTO t2 VALUES (713,202302,37,'Evanston','realized','mixture','FAS');
+INSERT INTO t2 VALUES (714,202303,37,'misted','mayoral','electroencephalography','FAS');
+INSERT INTO t2 VALUES (715,202304,37,'textures','opaquely','similarities','FAS');
+INSERT INTO t2 VALUES (716,202305,37,'save','hostess','charges','W');
+INSERT INTO t2 VALUES (717,202601,37,'count','fiftieth','freest','FAS');
+INSERT INTO t2 VALUES (718,202602,37,'rightful','incorrectly','Greenberg','FAS');
+INSERT INTO t2 VALUES (719,202605,37,'chaperone','decomposition','tinting','');
+INSERT INTO t2 VALUES (720,202606,37,'Lizzy','stranglings','expelled','W');
+INSERT INTO t2 VALUES (721,202607,37,'clenched','mixture','warm','');
+INSERT INTO t2 VALUES (722,202901,37,'effortlessly','electroencephalography','smoothed','');
+INSERT INTO t2 VALUES (723,202902,37,'accessed','similarities','deductions','FAS');
+INSERT INTO t2 VALUES (724,202903,37,'beaters','charges','Romano','W');
+INSERT INTO t2 VALUES (725,202904,37,'Hornblower','freest','bitterroot','');
+INSERT INTO t2 VALUES (726,202907,37,'vests','Greenberg','corset','');
+INSERT INTO t2 VALUES (727,202908,37,'indulgences','tinting','securing','');
+INSERT INTO t2 VALUES (728,203101,37,'infallibly','expelled','environing','FAS');
+INSERT INTO t2 VALUES (729,203103,37,'unwilling','warm','cute','');
+INSERT INTO t2 VALUES (730,203104,37,'excrete','smoothed','Crays','');
+INSERT INTO t2 VALUES (731,203105,37,'spools','deductions','heiress','FAS');
+INSERT INTO t2 VALUES (732,203401,37,'crunches','Romano','inform','FAS');
+INSERT INTO t2 VALUES (733,203402,37,'overestimating','bitterroot','avenge','');
+INSERT INTO t2 VALUES (734,203404,37,'ineffective','corset','universals','');
+INSERT INTO t2 VALUES (735,203901,37,'humiliation','securing','Kinsey','W');
+INSERT INTO t2 VALUES (736,203902,37,'sophomore','environing','ravines','FAS');
+INSERT INTO t2 VALUES (737,203903,37,'star','cute','bestseller','');
+INSERT INTO t2 VALUES (738,203906,37,'rifles','Crays','equilibrium','');
+INSERT INTO t2 VALUES (739,203907,37,'dialysis','heiress','extents','0');
+INSERT INTO t2 VALUES (740,203908,37,'arriving','inform','relatively','');
+INSERT INTO t2 VALUES (741,203909,37,'indulge','avenge','pressure','FAS');
+INSERT INTO t2 VALUES (742,206101,37,'clockers','universals','critiques','FAS');
+INSERT INTO t2 VALUES (743,206201,37,'languages','Kinsey','befouled','');
+INSERT INTO t2 VALUES (744,206202,37,'Antarctica','ravines','rightfully','FAS');
+INSERT INTO t2 VALUES (745,206203,37,'percentage','bestseller','mechanizing','FAS');
+INSERT INTO t2 VALUES (746,206206,37,'ceiling','equilibrium','Latinizes','');
+INSERT INTO t2 VALUES (747,206207,37,'specification','extents','timesharing','');
+INSERT INTO t2 VALUES (748,206208,37,'regimented','relatively','Aden','');
+INSERT INTO t2 VALUES (749,208001,37,'ciphers','pressure','embassies','');
+INSERT INTO t2 VALUES (750,208002,37,'pictures','critiques','males','FAS');
+INSERT INTO t2 VALUES (751,208003,37,'serpents','befouled','shapelessly','FAS');
+INSERT INTO t2 VALUES (752,208004,37,'allot','rightfully','genres','FAS');
+INSERT INTO t2 VALUES (753,208008,37,'realized','mechanizing','mastering','');
+INSERT INTO t2 VALUES (754,208009,37,'mayoral','Latinizes','Newtonian','');
+INSERT INTO t2 VALUES (755,208010,37,'opaquely','timesharing','finishers','FAS');
+INSERT INTO t2 VALUES (756,208011,37,'hostess','Aden','abates','');
+INSERT INTO t2 VALUES (757,208101,37,'fiftieth','embassies','teem','');
+INSERT INTO t2 VALUES (758,208102,37,'incorrectly','males','kiting','FAS');
+INSERT INTO t2 VALUES (759,208103,37,'decomposition','shapelessly','stodgy','FAS');
+INSERT INTO t2 VALUES (760,208104,37,'stranglings','genres','scalps','FAS');
+INSERT INTO t2 VALUES (761,208105,37,'mixture','mastering','feed','FAS');
+INSERT INTO t2 VALUES (762,208110,37,'electroencephalography','Newtonian','guitars','');
+INSERT INTO t2 VALUES (763,208111,37,'similarities','finishers','airships','');
+INSERT INTO t2 VALUES (764,208112,37,'charges','abates','store','');
+INSERT INTO t2 VALUES (765,208113,37,'freest','teem','denounces','');
+INSERT INTO t2 VALUES (766,208201,37,'Greenberg','kiting','Pyle','FAS');
+INSERT INTO t2 VALUES (767,208203,37,'tinting','stodgy','Saxony','');
+INSERT INTO t2 VALUES (768,208301,37,'expelled','scalps','serializations','FAS');
+INSERT INTO t2 VALUES (769,208302,37,'warm','feed','Peruvian','FAS');
+INSERT INTO t2 VALUES (770,208305,37,'smoothed','guitars','taxonomically','FAS');
+INSERT INTO t2 VALUES (771,208401,37,'deductions','airships','kingdom','A');
+INSERT INTO t2 VALUES (772,208402,37,'Romano','store','stint','A');
+INSERT INTO t2 VALUES (773,208403,37,'bitterroot','denounces','Sault','A');
+INSERT INTO t2 VALUES (774,208404,37,'corset','Pyle','faithful','');
+INSERT INTO t2 VALUES (775,208501,37,'securing','Saxony','Ganymede','FAS');
+INSERT INTO t2 VALUES (776,208502,37,'environing','serializations','tidiness','FAS');
+INSERT INTO t2 VALUES (777,208503,37,'cute','Peruvian','gainful','FAS');
+INSERT INTO t2 VALUES (778,208504,37,'Crays','taxonomically','contrary','FAS');
+INSERT INTO t2 VALUES (779,208505,37,'heiress','kingdom','Tipperary','FAS');
+INSERT INTO t2 VALUES (780,210101,37,'inform','stint','tropics','W');
+INSERT INTO t2 VALUES (781,210102,37,'avenge','Sault','theorizers','');
+INSERT INTO t2 VALUES (782,210103,37,'universals','faithful','renew','0');
+INSERT INTO t2 VALUES (783,210104,37,'Kinsey','Ganymede','already','');
+INSERT INTO t2 VALUES (784,210105,37,'ravines','tidiness','terminal','');
+INSERT INTO t2 VALUES (785,210106,37,'bestseller','gainful','Hegelian','');
+INSERT INTO t2 VALUES (786,210107,37,'equilibrium','contrary','hypothesizer','');
+INSERT INTO t2 VALUES (787,210401,37,'extents','Tipperary','warningly','FAS');
+INSERT INTO t2 VALUES (788,213201,37,'relatively','tropics','journalizing','FAS');
+INSERT INTO t2 VALUES (789,213203,37,'pressure','theorizers','nested','');
+INSERT INTO t2 VALUES (790,213204,37,'critiques','renew','Lars','');
+INSERT INTO t2 VALUES (791,213205,37,'befouled','already','saplings','');
+INSERT INTO t2 VALUES (792,213206,37,'rightfully','terminal','foothill','');
+INSERT INTO t2 VALUES (793,213207,37,'mechanizing','Hegelian','labeled','');
+INSERT INTO t2 VALUES (794,216101,37,'Latinizes','hypothesizer','imperiously','FAS');
+INSERT INTO t2 VALUES (795,216103,37,'timesharing','warningly','reporters','FAS');
+INSERT INTO t2 VALUES (796,218001,37,'Aden','journalizing','furnishings','FAS');
+INSERT INTO t2 VALUES (797,218002,37,'embassies','nested','precipitable','FAS');
+INSERT INTO t2 VALUES (798,218003,37,'males','Lars','discounts','FAS');
+INSERT INTO t2 VALUES (799,218004,37,'shapelessly','saplings','excises','FAS');
+INSERT INTO t2 VALUES (800,143503,50,'genres','foothill','Stalin','');
+INSERT INTO t2 VALUES (801,218006,37,'mastering','labeled','despot','FAS');
+INSERT INTO t2 VALUES (802,218007,37,'Newtonian','imperiously','ripeness','FAS');
+INSERT INTO t2 VALUES (803,218008,37,'finishers','reporters','Arabia','');
+INSERT INTO t2 VALUES (804,218009,37,'abates','furnishings','unruly','');
+INSERT INTO t2 VALUES (805,218010,37,'teem','precipitable','mournfulness','');
+INSERT INTO t2 VALUES (806,218011,37,'kiting','discounts','boom','FAS');
+INSERT INTO t2 VALUES (807,218020,37,'stodgy','excises','slaughter','A');
+INSERT INTO t2 VALUES (808,218021,50,'scalps','Stalin','Sabine','');
+INSERT INTO t2 VALUES (809,218022,37,'feed','despot','handy','FAS');
+INSERT INTO t2 VALUES (810,218023,37,'guitars','ripeness','rural','');
+INSERT INTO t2 VALUES (811,218024,37,'airships','Arabia','organizer','');
+INSERT INTO t2 VALUES (812,218101,37,'store','unruly','shipyard','FAS');
+INSERT INTO t2 VALUES (813,218102,37,'denounces','mournfulness','civics','FAS');
+INSERT INTO t2 VALUES (814,218103,37,'Pyle','boom','inaccuracy','FAS');
+INSERT INTO t2 VALUES (815,218201,37,'Saxony','slaughter','rules','FAS');
+INSERT INTO t2 VALUES (816,218202,37,'serializations','Sabine','juveniles','FAS');
+INSERT INTO t2 VALUES (817,218203,37,'Peruvian','handy','comprised','W');
+INSERT INTO t2 VALUES (818,218204,37,'taxonomically','rural','investigations','');
+INSERT INTO t2 VALUES (819,218205,37,'kingdom','organizer','stabilizes','A');
+INSERT INTO t2 VALUES (820,218301,37,'stint','shipyard','seminaries','FAS');
+INSERT INTO t2 VALUES (821,218302,37,'Sault','civics','Hunter','A');
+INSERT INTO t2 VALUES (822,218401,37,'faithful','inaccuracy','sporty','FAS');
+INSERT INTO t2 VALUES (823,218402,37,'Ganymede','rules','test','FAS');
+INSERT INTO t2 VALUES (824,218403,37,'tidiness','juveniles','weasels','');
+INSERT INTO t2 VALUES (825,218404,37,'gainful','comprised','CERN','');
+INSERT INTO t2 VALUES (826,218407,37,'contrary','investigations','tempering','');
+INSERT INTO t2 VALUES (827,218408,37,'Tipperary','stabilizes','afore','FAS');
+INSERT INTO t2 VALUES (828,218409,37,'tropics','seminaries','Galatean','');
+INSERT INTO t2 VALUES (829,218410,37,'theorizers','Hunter','techniques','W');
+INSERT INTO t2 VALUES (830,226001,37,'renew','sporty','error','');
+INSERT INTO t2 VALUES (831,226002,37,'already','test','veranda','');
+INSERT INTO t2 VALUES (832,226003,37,'terminal','weasels','severely','');
+INSERT INTO t2 VALUES (833,226004,37,'Hegelian','CERN','Cassites','FAS');
+INSERT INTO t2 VALUES (834,226005,37,'hypothesizer','tempering','forthcoming','');
+INSERT INTO t2 VALUES (835,226006,37,'warningly','afore','guides','');
+INSERT INTO t2 VALUES (836,226007,37,'journalizing','Galatean','vanish','FAS');
+INSERT INTO t2 VALUES (837,226008,37,'nested','techniques','lied','A');
+INSERT INTO t2 VALUES (838,226203,37,'Lars','error','sawtooth','FAS');
+INSERT INTO t2 VALUES (839,226204,37,'saplings','veranda','fated','FAS');
+INSERT INTO t2 VALUES (840,226205,37,'foothill','severely','gradually','');
+INSERT INTO t2 VALUES (841,226206,37,'labeled','Cassites','widens','');
+INSERT INTO t2 VALUES (842,226207,37,'imperiously','forthcoming','preclude','');
+INSERT INTO t2 VALUES (843,226208,37,'reporters','guides','Jobrel','');
+INSERT INTO t2 VALUES (844,226209,37,'furnishings','vanish','hooker','');
+INSERT INTO t2 VALUES (845,226210,37,'precipitable','lied','rainstorm','');
+INSERT INTO t2 VALUES (846,226211,37,'discounts','sawtooth','disconnects','');
+INSERT INTO t2 VALUES (847,228001,37,'excises','fated','cruelty','');
+INSERT INTO t2 VALUES (848,228004,37,'Stalin','gradually','exponentials','A');
+INSERT INTO t2 VALUES (849,228005,37,'despot','widens','affective','A');
+INSERT INTO t2 VALUES (850,228006,37,'ripeness','preclude','arteries','');
+INSERT INTO t2 VALUES (851,228007,37,'Arabia','Jobrel','Crosby','FAS');
+INSERT INTO t2 VALUES (852,228008,37,'unruly','hooker','acquaint','');
+INSERT INTO t2 VALUES (853,228009,37,'mournfulness','rainstorm','evenhandedly','');
+INSERT INTO t2 VALUES (854,228101,37,'boom','disconnects','percentage','');
+INSERT INTO t2 VALUES (855,228108,37,'slaughter','cruelty','disobedience','');
+INSERT INTO t2 VALUES (856,228109,37,'Sabine','exponentials','humility','');
+INSERT INTO t2 VALUES (857,228110,37,'handy','affective','gleaning','A');
+INSERT INTO t2 VALUES (858,228111,37,'rural','arteries','petted','A');
+INSERT INTO t2 VALUES (859,228112,37,'organizer','Crosby','bloater','A');
+INSERT INTO t2 VALUES (860,228113,37,'shipyard','acquaint','minion','A');
+INSERT INTO t2 VALUES (861,228114,37,'civics','evenhandedly','marginal','A');
+INSERT INTO t2 VALUES (862,228115,37,'inaccuracy','percentage','apiary','A');
+INSERT INTO t2 VALUES (863,228116,37,'rules','disobedience','measures','');
+INSERT INTO t2 VALUES (864,228117,37,'juveniles','humility','precaution','');
+INSERT INTO t2 VALUES (865,228118,37,'comprised','gleaning','repelled','');
+INSERT INTO t2 VALUES (866,228119,37,'investigations','petted','primary','FAS');
+INSERT INTO t2 VALUES (867,228120,37,'stabilizes','bloater','coverings','');
+INSERT INTO t2 VALUES (868,228121,37,'seminaries','minion','Artemia','A');
+INSERT INTO t2 VALUES (869,228122,37,'Hunter','marginal','navigate','');
+INSERT INTO t2 VALUES (870,228201,37,'sporty','apiary','spatial','');
+INSERT INTO t2 VALUES (871,228206,37,'test','measures','Gurkha','');
+INSERT INTO t2 VALUES (872,228207,37,'weasels','precaution','meanwhile','A');
+INSERT INTO t2 VALUES (873,228208,37,'CERN','repelled','Melinda','A');
+INSERT INTO t2 VALUES (874,228209,37,'tempering','primary','Butterfield','');
+INSERT INTO t2 VALUES (875,228210,37,'afore','coverings','Aldrich','A');
+INSERT INTO t2 VALUES (876,228211,37,'Galatean','Artemia','previewing','A');
+INSERT INTO t2 VALUES (877,228212,37,'techniques','navigate','glut','A');
+INSERT INTO t2 VALUES (878,228213,37,'error','spatial','unaffected','');
+INSERT INTO t2 VALUES (879,228214,37,'veranda','Gurkha','inmate','');
+INSERT INTO t2 VALUES (880,228301,37,'severely','meanwhile','mineral','');
+INSERT INTO t2 VALUES (881,228305,37,'Cassites','Melinda','impending','A');
+INSERT INTO t2 VALUES (882,228306,37,'forthcoming','Butterfield','meditation','A');
+INSERT INTO t2 VALUES (883,228307,37,'guides','Aldrich','ideas','');
+INSERT INTO t2 VALUES (884,228308,37,'vanish','previewing','miniaturizes','W');
+INSERT INTO t2 VALUES (885,228309,37,'lied','glut','lewdly','');
+INSERT INTO t2 VALUES (886,228310,37,'sawtooth','unaffected','title','');
+INSERT INTO t2 VALUES (887,228311,37,'fated','inmate','youthfulness','');
+INSERT INTO t2 VALUES (888,228312,37,'gradually','mineral','creak','FAS');
+INSERT INTO t2 VALUES (889,228313,37,'widens','impending','Chippewa','');
+INSERT INTO t2 VALUES (890,228314,37,'preclude','meditation','clamored','');
+INSERT INTO t2 VALUES (891,228401,65,'Jobrel','ideas','freezes','');
+INSERT INTO t2 VALUES (892,228402,65,'hooker','miniaturizes','forgivably','FAS');
+INSERT INTO t2 VALUES (893,228403,65,'rainstorm','lewdly','reduce','FAS');
+INSERT INTO t2 VALUES (894,228404,65,'disconnects','title','McGovern','W');
+INSERT INTO t2 VALUES (895,228405,65,'cruelty','youthfulness','Nazis','W');
+INSERT INTO t2 VALUES (896,228406,65,'exponentials','creak','epistle','W');
+INSERT INTO t2 VALUES (897,228407,65,'affective','Chippewa','socializes','W');
+INSERT INTO t2 VALUES (898,228408,65,'arteries','clamored','conceptions','');
+INSERT INTO t2 VALUES (899,228409,65,'Crosby','freezes','Kevin','');
+INSERT INTO t2 VALUES (900,228410,65,'acquaint','forgivably','uncovering','');
+INSERT INTO t2 VALUES (901,230301,37,'evenhandedly','reduce','chews','FAS');
+INSERT INTO t2 VALUES (902,230302,37,'percentage','McGovern','appendixes','FAS');
+INSERT INTO t2 VALUES (903,230303,37,'disobedience','Nazis','raining','');
+INSERT INTO t2 VALUES (904,018062,37,'humility','epistle','infest','');
+INSERT INTO t2 VALUES (905,230501,37,'gleaning','socializes','compartment','');
+INSERT INTO t2 VALUES (906,230502,37,'petted','conceptions','minting','');
+INSERT INTO t2 VALUES (907,230503,37,'bloater','Kevin','ducks','');
+INSERT INTO t2 VALUES (908,230504,37,'minion','uncovering','roped','A');
+INSERT INTO t2 VALUES (909,230505,37,'marginal','chews','waltz','');
+INSERT INTO t2 VALUES (910,230506,37,'apiary','appendixes','Lillian','');
+INSERT INTO t2 VALUES (911,230507,37,'measures','raining','repressions','A');
+INSERT INTO t2 VALUES (912,230508,37,'precaution','infest','chillingly','');
+INSERT INTO t2 VALUES (913,230509,37,'repelled','compartment','noncritical','');
+INSERT INTO t2 VALUES (914,230901,37,'primary','minting','lithograph','');
+INSERT INTO t2 VALUES (915,230902,37,'coverings','ducks','spongers','');
+INSERT INTO t2 VALUES (916,230903,37,'Artemia','roped','parenthood','');
+INSERT INTO t2 VALUES (917,230904,37,'navigate','waltz','posed','');
+INSERT INTO t2 VALUES (918,230905,37,'spatial','Lillian','instruments','');
+INSERT INTO t2 VALUES (919,230906,37,'Gurkha','repressions','filial','');
+INSERT INTO t2 VALUES (920,230907,37,'meanwhile','chillingly','fixedly','');
+INSERT INTO t2 VALUES (921,230908,37,'Melinda','noncritical','relives','');
+INSERT INTO t2 VALUES (922,230909,37,'Butterfield','lithograph','Pandora','');
+INSERT INTO t2 VALUES (923,230910,37,'Aldrich','spongers','watering','A');
+INSERT INTO t2 VALUES (924,230911,37,'previewing','parenthood','ungrateful','');
+INSERT INTO t2 VALUES (925,230912,37,'glut','posed','secures','');
+INSERT INTO t2 VALUES (926,230913,37,'unaffected','instruments','chastisers','');
+INSERT INTO t2 VALUES (927,230914,37,'inmate','filial','icon','');
+INSERT INTO t2 VALUES (928,231304,37,'mineral','fixedly','reuniting','A');
+INSERT INTO t2 VALUES (929,231305,37,'impending','relives','imagining','A');
+INSERT INTO t2 VALUES (930,231306,37,'meditation','Pandora','abiding','A');
+INSERT INTO t2 VALUES (931,231307,37,'ideas','watering','omnisciently','');
+INSERT INTO t2 VALUES (932,231308,37,'miniaturizes','ungrateful','Britannic','');
+INSERT INTO t2 VALUES (933,231309,37,'lewdly','secures','scholastics','A');
+INSERT INTO t2 VALUES (934,231310,37,'title','chastisers','mechanics','A');
+INSERT INTO t2 VALUES (935,231311,37,'youthfulness','icon','humidly','A');
+INSERT INTO t2 VALUES (936,231312,37,'creak','reuniting','masterpiece','');
+INSERT INTO t2 VALUES (937,231313,37,'Chippewa','imagining','however','');
+INSERT INTO t2 VALUES (938,231314,37,'clamored','abiding','Mendelian','');
+INSERT INTO t2 VALUES (939,231315,37,'freezes','omnisciently','jarred','');
+INSERT INTO t2 VALUES (940,232102,37,'forgivably','Britannic','scolds','');
+INSERT INTO t2 VALUES (941,232103,37,'reduce','scholastics','infatuate','');
+INSERT INTO t2 VALUES (942,232104,37,'McGovern','mechanics','willed','A');
+INSERT INTO t2 VALUES (943,232105,37,'Nazis','humidly','joyfully','');
+INSERT INTO t2 VALUES (944,232106,37,'epistle','masterpiece','Microsoft','');
+INSERT INTO t2 VALUES (945,232107,37,'socializes','however','fibrosities','');
+INSERT INTO t2 VALUES (946,232108,37,'conceptions','Mendelian','Baltimorean','');
+INSERT INTO t2 VALUES (947,232601,37,'Kevin','jarred','equestrian','');
+INSERT INTO t2 VALUES (948,232602,37,'uncovering','scolds','Goodrich','');
+INSERT INTO t2 VALUES (949,232603,37,'chews','infatuate','apish','A');
+INSERT INTO t2 VALUES (950,232605,37,'appendixes','willed','Adlerian','');
+INSERT INTO t2 VALUES (5950,1232605,37,'appendixes','willed','Adlerian','');
+INSERT INTO t2 VALUES (5951,1232606,37,'appendixes','willed','Adlerian','');
+INSERT INTO t2 VALUES (5952,1232607,37,'appendixes','willed','Adlerian','');
+INSERT INTO t2 VALUES (5953,1232608,37,'appendixes','willed','Adlerian','');
+INSERT INTO t2 VALUES (5954,1232609,37,'appendixes','willed','Adlerian','');
+INSERT INTO t2 VALUES (951,232606,37,'raining','joyfully','Tropez','');
+INSERT INTO t2 VALUES (952,232607,37,'infest','Microsoft','nouns','');
+INSERT INTO t2 VALUES (953,232608,37,'compartment','fibrosities','distracting','');
+INSERT INTO t2 VALUES (954,232609,37,'minting','Baltimorean','mutton','');
+INSERT INTO t2 VALUES (955,236104,37,'ducks','equestrian','bridgeable','A');
+INSERT INTO t2 VALUES (956,236105,37,'roped','Goodrich','stickers','A');
+INSERT INTO t2 VALUES (957,236106,37,'waltz','apish','transcontinental','A');
+INSERT INTO t2 VALUES (958,236107,37,'Lillian','Adlerian','amateurish','');
+INSERT INTO t2 VALUES (959,236108,37,'repressions','Tropez','Gandhian','');
+INSERT INTO t2 VALUES (960,236109,37,'chillingly','nouns','stratified','');
+INSERT INTO t2 VALUES (961,236110,37,'noncritical','distracting','chamberlains','');
+INSERT INTO t2 VALUES (962,236111,37,'lithograph','mutton','creditably','');
+INSERT INTO t2 VALUES (963,236112,37,'spongers','bridgeable','philosophic','');
+INSERT INTO t2 VALUES (964,236113,37,'parenthood','stickers','ores','');
+INSERT INTO t2 VALUES (965,238005,37,'posed','transcontinental','Carleton','');
+INSERT INTO t2 VALUES (966,238006,37,'instruments','amateurish','tape','A');
+INSERT INTO t2 VALUES (967,238007,37,'filial','Gandhian','afloat','A');
+INSERT INTO t2 VALUES (968,238008,37,'fixedly','stratified','goodness','A');
+INSERT INTO t2 VALUES (969,238009,37,'relives','chamberlains','welcoming','');
+INSERT INTO t2 VALUES (970,238010,37,'Pandora','creditably','Pinsky','FAS');
+INSERT INTO t2 VALUES (971,238011,37,'watering','philosophic','halting','');
+INSERT INTO t2 VALUES (972,238012,37,'ungrateful','ores','bibliography','');
+INSERT INTO t2 VALUES (973,238013,37,'secures','Carleton','decoding','');
+INSERT INTO t2 VALUES (974,240401,41,'chastisers','tape','variance','A');
+INSERT INTO t2 VALUES (975,240402,41,'icon','afloat','allowed','A');
+INSERT INTO t2 VALUES (976,240901,41,'reuniting','goodness','dire','A');
+INSERT INTO t2 VALUES (977,240902,41,'imagining','welcoming','dub','A');
+INSERT INTO t2 VALUES (978,241801,41,'abiding','Pinsky','poisoning','');
+INSERT INTO t2 VALUES (979,242101,41,'omnisciently','halting','Iraqis','A');
+INSERT INTO t2 VALUES (980,242102,41,'Britannic','bibliography','heaving','');
+INSERT INTO t2 VALUES (981,242201,41,'scholastics','decoding','population','A');
+INSERT INTO t2 VALUES (982,242202,41,'mechanics','variance','bomb','A');
+INSERT INTO t2 VALUES (983,242501,41,'humidly','allowed','Majorca','A');
+INSERT INTO t2 VALUES (984,242502,41,'masterpiece','dire','Gershwins','');
+INSERT INTO t2 VALUES (985,246201,41,'however','dub','explorers','');
+INSERT INTO t2 VALUES (986,246202,41,'Mendelian','poisoning','libretto','A');
+INSERT INTO t2 VALUES (987,246203,41,'jarred','Iraqis','occurred','');
+INSERT INTO t2 VALUES (988,246204,41,'scolds','heaving','Lagos','');
+INSERT INTO t2 VALUES (989,246205,41,'infatuate','population','rats','');
+INSERT INTO t2 VALUES (990,246301,41,'willed','bomb','bankruptcies','A');
+INSERT INTO t2 VALUES (991,246302,41,'joyfully','Majorca','crying','');
+INSERT INTO t2 VALUES (992,248001,41,'Microsoft','Gershwins','unexpected','');
+INSERT INTO t2 VALUES (993,248002,41,'fibrosities','explorers','accessed','A');
+INSERT INTO t2 VALUES (994,248003,41,'Baltimorean','libretto','colorful','A');
+INSERT INTO t2 VALUES (995,248004,41,'equestrian','occurred','versatility','A');
+INSERT INTO t2 VALUES (996,248005,41,'Goodrich','Lagos','cosy','');
+INSERT INTO t2 VALUES (997,248006,41,'apish','rats','Darius','A');
+INSERT INTO t2 VALUES (998,248007,41,'Adlerian','bankruptcies','mastering','A');
+INSERT INTO t2 VALUES (999,248008,41,'Tropez','crying','Asiaticizations','A');
+INSERT INTO t2 VALUES (1000,248009,41,'nouns','unexpected','offerers','A');
+INSERT INTO t2 VALUES (1001,248010,41,'distracting','accessed','uncles','A');
+INSERT INTO t2 VALUES (1002,248011,41,'mutton','colorful','sleepwalk','');
+INSERT INTO t2 VALUES (1003,248012,41,'bridgeable','versatility','Ernestine','');
+INSERT INTO t2 VALUES (1004,248013,41,'stickers','cosy','checksumming','');
+INSERT INTO t2 VALUES (1005,248014,41,'transcontinental','Darius','stopped','');
+INSERT INTO t2 VALUES (1006,248015,41,'amateurish','mastering','sicker','');
+INSERT INTO t2 VALUES (1007,248016,41,'Gandhian','Asiaticizations','Italianization','');
+INSERT INTO t2 VALUES (1008,248017,41,'stratified','offerers','alphabetic','');
+INSERT INTO t2 VALUES (1009,248018,41,'chamberlains','uncles','pharmaceutic','');
+INSERT INTO t2 VALUES (1010,248019,41,'creditably','sleepwalk','creator','');
+INSERT INTO t2 VALUES (1011,248020,41,'philosophic','Ernestine','chess','');
+INSERT INTO t2 VALUES (1012,248021,41,'ores','checksumming','charcoal','');
+INSERT INTO t2 VALUES (1013,248101,41,'Carleton','stopped','Epiphany','A');
+INSERT INTO t2 VALUES (1014,248102,41,'tape','sicker','bulldozes','A');
+INSERT INTO t2 VALUES (1015,248201,41,'afloat','Italianization','Pygmalion','A');
+INSERT INTO t2 VALUES (1016,248202,41,'goodness','alphabetic','caressing','A');
+INSERT INTO t2 VALUES (1017,248203,41,'welcoming','pharmaceutic','Palestine','A');
+INSERT INTO t2 VALUES (1018,248204,41,'Pinsky','creator','regimented','A');
+INSERT INTO t2 VALUES (1019,248205,41,'halting','chess','scars','A');
+INSERT INTO t2 VALUES (1020,248206,41,'bibliography','charcoal','realest','A');
+INSERT INTO t2 VALUES (1021,248207,41,'decoding','Epiphany','diffusing','A');
+INSERT INTO t2 VALUES (1022,248208,41,'variance','bulldozes','clubroom','A');
+INSERT INTO t2 VALUES (1023,248209,41,'allowed','Pygmalion','Blythe','A');
+INSERT INTO t2 VALUES (1024,248210,41,'dire','caressing','ahead','');
+INSERT INTO t2 VALUES (1025,248211,50,'dub','Palestine','reviver','');
+INSERT INTO t2 VALUES (1026,250501,34,'poisoning','regimented','retransmitting','A');
+INSERT INTO t2 VALUES (1027,250502,34,'Iraqis','scars','landslide','');
+INSERT INTO t2 VALUES (1028,250503,34,'heaving','realest','Eiffel','');
+INSERT INTO t2 VALUES (1029,250504,34,'population','diffusing','absentee','');
+INSERT INTO t2 VALUES (1030,250505,34,'bomb','clubroom','aye','');
+INSERT INTO t2 VALUES (1031,250601,34,'Majorca','Blythe','forked','A');
+INSERT INTO t2 VALUES (1032,250602,34,'Gershwins','ahead','Peruvianizes','');
+INSERT INTO t2 VALUES (1033,250603,34,'explorers','reviver','clerked','');
+INSERT INTO t2 VALUES (1034,250604,34,'libretto','retransmitting','tutor','');
+INSERT INTO t2 VALUES (1035,250605,34,'occurred','landslide','boulevard','');
+INSERT INTO t2 VALUES (1036,251001,34,'Lagos','Eiffel','shuttered','');
+INSERT INTO t2 VALUES (1037,251002,34,'rats','absentee','quotes','A');
+INSERT INTO t2 VALUES (1038,251003,34,'bankruptcies','aye','Caltech','');
+INSERT INTO t2 VALUES (1039,251004,34,'crying','forked','Mossberg','');
+INSERT INTO t2 VALUES (1040,251005,34,'unexpected','Peruvianizes','kept','');
+INSERT INTO t2 VALUES (1041,251301,34,'accessed','clerked','roundly','');
+INSERT INTO t2 VALUES (1042,251302,34,'colorful','tutor','features','A');
+INSERT INTO t2 VALUES (1043,251303,34,'versatility','boulevard','imaginable','A');
+INSERT INTO t2 VALUES (1044,251304,34,'cosy','shuttered','controller','');
+INSERT INTO t2 VALUES (1045,251305,34,'Darius','quotes','racial','');
+INSERT INTO t2 VALUES (1046,251401,34,'mastering','Caltech','uprisings','A');
+INSERT INTO t2 VALUES (1047,251402,34,'Asiaticizations','Mossberg','narrowed','A');
+INSERT INTO t2 VALUES (1048,251403,34,'offerers','kept','cannot','A');
+INSERT INTO t2 VALUES (1049,251404,34,'uncles','roundly','vest','');
+INSERT INTO t2 VALUES (1050,251405,34,'sleepwalk','features','famine','');
+INSERT INTO t2 VALUES (1051,251406,34,'Ernestine','imaginable','sugars','');
+INSERT INTO t2 VALUES (1052,251801,34,'checksumming','controller','exterminated','A');
+INSERT INTO t2 VALUES (1053,251802,34,'stopped','racial','belays','');
+INSERT INTO t2 VALUES (1054,252101,34,'sicker','uprisings','Hodges','A');
+INSERT INTO t2 VALUES (1055,252102,34,'Italianization','narrowed','translatable','');
+INSERT INTO t2 VALUES (1056,252301,34,'alphabetic','cannot','duality','A');
+INSERT INTO t2 VALUES (1057,252302,34,'pharmaceutic','vest','recording','A');
+INSERT INTO t2 VALUES (1058,252303,34,'creator','famine','rouses','A');
+INSERT INTO t2 VALUES (1059,252304,34,'chess','sugars','poison','');
+INSERT INTO t2 VALUES (1060,252305,34,'charcoal','exterminated','attitude','');
+INSERT INTO t2 VALUES (1061,252306,34,'Epiphany','belays','dusted','');
+INSERT INTO t2 VALUES (1062,252307,34,'bulldozes','Hodges','encompasses','');
+INSERT INTO t2 VALUES (1063,252308,34,'Pygmalion','translatable','presentation','');
+INSERT INTO t2 VALUES (1064,252309,34,'caressing','duality','Kantian','');
+INSERT INTO t2 VALUES (1065,256001,34,'Palestine','recording','imprecision','A');
+INSERT INTO t2 VALUES (1066,256002,34,'regimented','rouses','saving','');
+INSERT INTO t2 VALUES (1067,256003,34,'scars','poison','maternal','');
+INSERT INTO t2 VALUES (1068,256004,34,'realest','attitude','hewed','');
+INSERT INTO t2 VALUES (1069,256005,34,'diffusing','dusted','kerosene','');
+INSERT INTO t2 VALUES (1070,258001,34,'clubroom','encompasses','Cubans','');
+INSERT INTO t2 VALUES (1071,258002,34,'Blythe','presentation','photographers','');
+INSERT INTO t2 VALUES (1072,258003,34,'ahead','Kantian','nymph','A');
+INSERT INTO t2 VALUES (1073,258004,34,'reviver','imprecision','bedlam','A');
+INSERT INTO t2 VALUES (1074,258005,34,'retransmitting','saving','north','A');
+INSERT INTO t2 VALUES (1075,258006,34,'landslide','maternal','Schoenberg','A');
+INSERT INTO t2 VALUES (1076,258007,34,'Eiffel','hewed','botany','A');
+INSERT INTO t2 VALUES (1077,258008,34,'absentee','kerosene','curs','');
+INSERT INTO t2 VALUES (1078,258009,34,'aye','Cubans','solidification','');
+INSERT INTO t2 VALUES (1079,258010,34,'forked','photographers','inheritresses','');
+INSERT INTO t2 VALUES (1080,258011,34,'Peruvianizes','nymph','stiller','');
+INSERT INTO t2 VALUES (1081,258101,68,'clerked','bedlam','t1','A');
+INSERT INTO t2 VALUES (1082,258102,68,'tutor','north','suite','A');
+INSERT INTO t2 VALUES (1083,258103,34,'boulevard','Schoenberg','ransomer','');
+INSERT INTO t2 VALUES (1084,258104,68,'shuttered','botany','Willy','');
+INSERT INTO t2 VALUES (1085,258105,68,'quotes','curs','Rena','A');
+INSERT INTO t2 VALUES (1086,258106,68,'Caltech','solidification','Seattle','A');
+INSERT INTO t2 VALUES (1087,258107,68,'Mossberg','inheritresses','relaxes','A');
+INSERT INTO t2 VALUES (1088,258108,68,'kept','stiller','exclaim','');
+INSERT INTO t2 VALUES (1089,258109,68,'roundly','t1','implicated','A');
+INSERT INTO t2 VALUES (1090,258110,68,'features','suite','distinguish','');
+INSERT INTO t2 VALUES (1091,258111,68,'imaginable','ransomer','assayed','');
+INSERT INTO t2 VALUES (1092,258112,68,'controller','Willy','homeowner','');
+INSERT INTO t2 VALUES (1093,258113,68,'racial','Rena','and','');
+INSERT INTO t2 VALUES (1094,258201,34,'uprisings','Seattle','stealth','');
+INSERT INTO t2 VALUES (1095,258202,34,'narrowed','relaxes','coinciding','A');
+INSERT INTO t2 VALUES (1096,258203,34,'cannot','exclaim','founder','A');
+INSERT INTO t2 VALUES (1097,258204,34,'vest','implicated','environing','');
+INSERT INTO t2 VALUES (1098,258205,34,'famine','distinguish','jewelry','');
+INSERT INTO t2 VALUES (1099,258301,34,'sugars','assayed','lemons','A');
+INSERT INTO t2 VALUES (1100,258401,34,'exterminated','homeowner','brokenness','A');
+INSERT INTO t2 VALUES (1101,258402,34,'belays','and','bedpost','A');
+INSERT INTO t2 VALUES (1102,258403,34,'Hodges','stealth','assurers','A');
+INSERT INTO t2 VALUES (1103,258404,34,'translatable','coinciding','annoyers','');
+INSERT INTO t2 VALUES (1104,258405,34,'duality','founder','affixed','');
+INSERT INTO t2 VALUES (1105,258406,34,'recording','environing','warbling','');
+INSERT INTO t2 VALUES (1106,258407,34,'rouses','jewelry','seriously','');
+INSERT INTO t2 VALUES (1107,228123,37,'poison','lemons','boasted','');
+INSERT INTO t2 VALUES (1108,250606,34,'attitude','brokenness','Chantilly','');
+INSERT INTO t2 VALUES (1109,208405,37,'dusted','bedpost','Iranizes','');
+INSERT INTO t2 VALUES (1110,212101,37,'encompasses','assurers','violinist','');
+INSERT INTO t2 VALUES (1111,218206,37,'presentation','annoyers','extramarital','');
+INSERT INTO t2 VALUES (1112,150401,37,'Kantian','affixed','spates','');
+INSERT INTO t2 VALUES (1113,248212,41,'imprecision','warbling','cloakroom','');
+INSERT INTO t2 VALUES (1114,128026,00,'saving','seriously','gazer','');
+INSERT INTO t2 VALUES (1115,128024,00,'maternal','boasted','hand','');
+INSERT INTO t2 VALUES (1116,128027,00,'hewed','Chantilly','tucked','');
+INSERT INTO t2 VALUES (1117,128025,00,'kerosene','Iranizes','gems','');
+INSERT INTO t2 VALUES (1118,128109,00,'Cubans','violinist','clinker','');
+INSERT INTO t2 VALUES (1119,128705,00,'photographers','extramarital','refiner','');
+INSERT INTO t2 VALUES (1120,126303,00,'nymph','spates','callus','');
+INSERT INTO t2 VALUES (1121,128308,00,'bedlam','cloakroom','leopards','');
+INSERT INTO t2 VALUES (1122,128204,00,'north','gazer','comfortingly','');
+INSERT INTO t2 VALUES (1123,128205,00,'Schoenberg','hand','generically','');
+INSERT INTO t2 VALUES (1124,128206,00,'botany','tucked','getters','');
+INSERT INTO t2 VALUES (1125,128207,00,'curs','gems','sexually','');
+INSERT INTO t2 VALUES (1126,118205,00,'solidification','clinker','spear','');
+INSERT INTO t2 VALUES (1127,116801,00,'inheritresses','refiner','serums','');
+INSERT INTO t2 VALUES (1128,116803,00,'stiller','callus','Italianization','');
+INSERT INTO t2 VALUES (1129,116804,00,'t1','leopards','attendants','');
+INSERT INTO t2 VALUES (1130,116802,00,'suite','comfortingly','spies','');
+INSERT INTO t2 VALUES (1131,128605,00,'ransomer','generically','Anthony','');
+INSERT INTO t2 VALUES (1132,118308,00,'Willy','getters','planar','');
+INSERT INTO t2 VALUES (1133,113702,00,'Rena','sexually','cupped','');
+INSERT INTO t2 VALUES (1134,113703,00,'Seattle','spear','cleanser','');
+INSERT INTO t2 VALUES (1135,112103,00,'relaxes','serums','commuters','');
+INSERT INTO t2 VALUES (1136,118009,00,'exclaim','Italianization','honeysuckle','');
+INSERT INTO t2 VALUES (5136,1118009,00,'exclaim','Italianization','honeysuckle','');
+INSERT INTO t2 VALUES (1137,138011,00,'implicated','attendants','orphanage','');
+INSERT INTO t2 VALUES (1138,138010,00,'distinguish','spies','skies','');
+INSERT INTO t2 VALUES (1139,138012,00,'assayed','Anthony','crushers','');
+INSERT INTO t2 VALUES (1140,068304,00,'homeowner','planar','Puritan','');
+INSERT INTO t2 VALUES (1141,078009,00,'and','cupped','squeezer','');
+INSERT INTO t2 VALUES (1142,108013,00,'stealth','cleanser','bruises','');
+INSERT INTO t2 VALUES (1143,084004,00,'coinciding','commuters','bonfire','');
+INSERT INTO t2 VALUES (1144,083402,00,'founder','honeysuckle','Colombo','');
+INSERT INTO t2 VALUES (1145,084003,00,'environing','orphanage','nondecreasing','');
+INSERT INTO t2 VALUES (1146,088504,00,'jewelry','skies','innocents','');
+INSERT INTO t2 VALUES (1147,088005,00,'lemons','crushers','masked','');
+INSERT INTO t2 VALUES (1148,088007,00,'brokenness','Puritan','file','');
+INSERT INTO t2 VALUES (1149,088006,00,'bedpost','squeezer','brush','');
+INSERT INTO t2 VALUES (1150,148025,00,'assurers','bruises','mutilate','');
+INSERT INTO t2 VALUES (1151,148024,00,'annoyers','bonfire','mommy','');
+INSERT INTO t2 VALUES (1152,138305,00,'affixed','Colombo','bulkheads','');
+INSERT INTO t2 VALUES (1153,138306,00,'warbling','nondecreasing','undeclared','');
+INSERT INTO t2 VALUES (1154,152701,00,'seriously','innocents','displacements','');
+INSERT INTO t2 VALUES (1155,148505,00,'boasted','masked','nieces','');
+INSERT INTO t2 VALUES (1156,158003,00,'Chantilly','file','coeducation','');
+INSERT INTO t2 VALUES (1157,156201,00,'Iranizes','brush','brassy','');
+INSERT INTO t2 VALUES (1158,156202,00,'violinist','mutilate','authenticator','');
+INSERT INTO t2 VALUES (1159,158307,00,'extramarital','mommy','Washoe','');
+INSERT INTO t2 VALUES (1160,158402,00,'spates','bulkheads','penny','');
+INSERT INTO t2 VALUES (1161,158401,00,'cloakroom','undeclared','Flagler','');
+INSERT INTO t2 VALUES (1162,068013,00,'gazer','displacements','stoned','');
+INSERT INTO t2 VALUES (1163,068012,00,'hand','nieces','cranes','');
+INSERT INTO t2 VALUES (1164,068203,00,'tucked','coeducation','masterful','');
+INSERT INTO t2 VALUES (1165,088205,00,'gems','brassy','biracial','');
+INSERT INTO t2 VALUES (1166,068704,00,'clinker','authenticator','steamships','');
+INSERT INTO t2 VALUES (1167,068604,00,'refiner','Washoe','windmills','');
+INSERT INTO t2 VALUES (1168,158502,00,'callus','penny','exploit','');
+INSERT INTO t2 VALUES (1169,123103,00,'leopards','Flagler','riverfront','');
+INSERT INTO t2 VALUES (1170,148026,00,'comfortingly','stoned','sisterly','');
+INSERT INTO t2 VALUES (1171,123302,00,'generically','cranes','sharpshoot','');
+INSERT INTO t2 VALUES (1172,076503,00,'getters','masterful','mittens','');
+INSERT INTO t2 VALUES (1173,126304,00,'sexually','biracial','interdependency','');
+INSERT INTO t2 VALUES (1174,068306,00,'spear','steamships','policy','');
+INSERT INTO t2 VALUES (1175,143504,00,'serums','windmills','unleashing','');
+INSERT INTO t2 VALUES (1176,160201,00,'Italianization','exploit','pretenders','');
+INSERT INTO t2 VALUES (1177,148028,00,'attendants','riverfront','overstatements','');
+INSERT INTO t2 VALUES (1178,148027,00,'spies','sisterly','birthed','');
+INSERT INTO t2 VALUES (1179,143505,00,'Anthony','sharpshoot','opportunism','');
+INSERT INTO t2 VALUES (1180,108014,00,'planar','mittens','showroom','');
+INSERT INTO t2 VALUES (1181,076104,00,'cupped','interdependency','compromisingly','');
+INSERT INTO t2 VALUES (1182,078106,00,'cleanser','policy','Medicare','');
+INSERT INTO t2 VALUES (1183,126102,00,'commuters','unleashing','corresponds','');
+INSERT INTO t2 VALUES (1184,128029,00,'honeysuckle','pretenders','hardware','');
+INSERT INTO t2 VALUES (1185,128028,00,'orphanage','overstatements','implant','');
+INSERT INTO t2 VALUES (1186,018410,00,'skies','birthed','Alicia','');
+INSERT INTO t2 VALUES (1187,128110,00,'crushers','opportunism','requesting','');
+INSERT INTO t2 VALUES (1188,148506,00,'Puritan','showroom','produced','');
+INSERT INTO t2 VALUES (1189,123303,00,'squeezer','compromisingly','criticizes','');
+INSERT INTO t2 VALUES (1190,123304,00,'bruises','Medicare','backer','');
+INSERT INTO t2 VALUES (1191,068504,00,'bonfire','corresponds','positively','');
+INSERT INTO t2 VALUES (1192,068305,00,'Colombo','hardware','colicky','');
+INSERT INTO t2 VALUES (1193,000000,00,'nondecreasing','implant','thrillingly','');
+select t2.fld3 from t2 where companynr = 58 and fld3 like "%imaginable%";
fld3
imaginable
+select fld3 from t2 where fld3 like "%cultivation" ;
fld3
cultivation
+select t2.fld3,companynr from t2 where companynr = 57+1 order by fld3;
fld3 companynr
concoct 58
druggists 58
@@ -32,6 +1256,7 @@ synergy 58
thanking 58
tying 58
unlocks 58
+select fld3,companynr from t2 where companynr = 58 order by fld3;
fld3 companynr
concoct 58
druggists 58
@@ -56,6 +1281,7 @@ synergy 58
thanking 58
tying 58
unlocks 58
+select fld3 from t2 order by fld3 desc limit 10;
fld3
youthfulness
yelped
@@ -67,49 +1293,71 @@ Winsett
Willy
willed
wildcats
+select fld3 from t2 order by fld3 desc limit 5;
fld3
youthfulness
yelped
Wotan
workers
Witt
+select fld3 from t2 order by fld3 desc limit 5,5;
fld3
witchcraft
Winsett
Willy
willed
wildcats
+select t2.fld3 from t2 where fld3 = 'honeysuckle';
fld3
honeysuckle
+select t2.fld3 from t2 where fld3 LIKE 'honeysuckl_';
fld3
honeysuckle
+select t2.fld3 from t2 where fld3 LIKE 'hon_ysuckl_';
fld3
honeysuckle
+select t2.fld3 from t2 where fld3 LIKE 'honeysuckle%';
fld3
honeysuckle
+select t2.fld3 from t2 where fld3 LIKE 'h%le';
fld3
honeysuckle
+select t2.fld3 from t2 where fld3 LIKE 'honeysuckle_';
fld3
+select t2.fld3 from t2 where fld3 LIKE 'don_t_find_me_please%';
fld3
+explain select t2.fld3 from t2 where fld3 = 'honeysuckle';
table type possible_keys key key_len ref rows Extra
t2 ref fld3 fld3 30 const 1 where used; Using index
+explain select fld3 from t2 ignore index (fld3) where fld3 = 'honeysuckle';
table type possible_keys key key_len ref rows Extra
-t2 index fld3 fld3 30 NULL 1199 where used; Using index
+t2 index NULL fld3 30 NULL 1199 where used; Using index
+explain select fld3 from t2 use index (fld1) where fld3 = 'honeysuckle';
table type possible_keys key key_len ref rows Extra
-t2 index fld3 fld3 30 NULL 1199 where used; Using index
+t2 index NULL fld3 30 NULL 1199 where used; Using index
+explain select fld3 from t2 use index (fld3) where fld3 = 'honeysuckle';
table type possible_keys key key_len ref rows Extra
t2 ref fld3 fld3 30 const 1 where used; Using index
+explain select fld3 from t2 use index (fld1,fld3) where fld3 = 'honeysuckle';
table type possible_keys key key_len ref rows Extra
t2 ref fld3 fld3 30 const 1 where used; Using index
+explain select fld3 from t2 ignore index (fld3,not_used);
+Key column 'not_used' doesn't exist in table
+explain select fld3 from t2 use index (not_used);
+Key column 'not_used' doesn't exist in table
+select t2.fld3 from t2 where fld3 >= 'honeysuckle' and fld3 <= 'honoring' order by fld3;
fld3
honeysuckle
honoring
+explain select t2.fld3 from t2 where fld3 >= 'honeysuckle' and fld3 <= 'honoring' order by fld3;
table type possible_keys key key_len ref rows Extra
t2 range fld3 fld3 30 NULL 2 where used; Using index
+select fld1,fld3 from t2 where fld3="Colombo" or fld3 = "nondecreasing" order by fld3;
fld1 fld3
148504 Colombo
068305 Colombo
000000 nondecreasing
+select fld1,fld3 from t2 where companynr = 37 and fld3 = 'appendixes';
fld1 fld3
232605 appendixes
1232605 appendixes
@@ -117,18 +1365,23 @@ fld1 fld3
1232607 appendixes
1232608 appendixes
1232609 appendixes
+select fld1 from t2 where fld1=250501 or fld1="250502";
fld1
250501
250502
+explain select fld1 from t2 where fld1=250501 or fld1="250502";
table type possible_keys key key_len ref rows Extra
t2 range fld1 fld1 4 NULL 2 where used; Using index
+select fld1 from t2 where fld1=250501 or fld1=250502 or fld1 >= 250505 and fld1 <= 250601 or fld1 between 250501 and 250502;
fld1
250501
250502
250505
250601
+explain select fld1 from t2 where fld1=250501 or fld1=250502 or fld1 >= 250505 and fld1 <= 250601 or fld1 between 250501 and 250502;
table type possible_keys key key_len ref rows Extra
t2 range fld1 fld1 4 NULL 4 where used; Using index
+select fld1,fld3 from t2 where companynr = 37 and fld3 like 'f%';
fld1 fld3
218401 faithful
018007 fanatic
@@ -161,21 +1414,26 @@ fld1 fld3
036002 funereal
226209 furnishings
198006 furthermore
+select fld3 from t2 where fld3 like "L%" and fld3 = "ok";
fld3
+select fld3 from t2 where (fld3 like "C%" and fld3 = "Chantilly");
fld3
Chantilly
+select fld1,fld3 from t2 where fld1 like "25050%";
fld1 fld3
250501 poisoning
250502 Iraqis
250503 heaving
250504 population
250505 bomb
+select fld1,fld3 from t2 where fld1 like "25050_";
fld1 fld3
250501 poisoning
250502 Iraqis
250503 heaving
250504 population
250505 bomb
+select distinct companynr from t2;
companynr
00
37
@@ -189,6 +1447,7 @@ companynr
41
34
68
+select distinct companynr from t2 order by companynr;
companynr
00
29
@@ -202,6 +1461,7 @@ companynr
58
65
68
+select distinct companynr from t2 order by companynr desc;
companynr
68
65
@@ -215,6 +1475,7 @@ companynr
34
29
00
+select distinct t2.fld3,period from t2,t1 where companynr=37 and fld3 like "O%";
fld3 period
obliterates 9410
offload 9410
@@ -222,6 +1483,7 @@ opaquely 9410
organizer 9410
overestimating 9410
overlay 9410
+select distinct fld3 from t2 where companynr = 34 order by fld3;
fld3
absentee
accessed
@@ -293,6 +1555,7 @@ unexpected
uprisings
versatility
vest
+select distinct fld3 from t2 limit 10;
fld3
abates
abiding
@@ -304,6 +1567,7 @@ accessed
accruing
accumulating
accuracies
+select distinct fld3 from t2 having fld3 like "A%" limit 10;
fld3
abates
abiding
@@ -315,6 +1579,7 @@ accessed
accruing
accumulating
accuracies
+select distinct substring(fld3,1,3) from t2 where fld3 like "A%";
substring(fld3,1,3)
aba
abi
@@ -378,6 +1643,7 @@ avo
awe
aye
Azt
+select distinct substring(fld3,1,3) as a from t2 having a like "A%" order by a limit 10;
a
aba
abi
@@ -389,6 +1655,7 @@ acq
acu
Ade
adj
+select distinct substring(fld3,1,3) from t2 where fld3 like "A%" limit 10;
substring(fld3,1,3)
aba
abi
@@ -400,6 +1667,7 @@ acq
acu
Ade
adj
+select distinct substring(fld3,1,3) as a from t2 having a like "A%" limit 10;
a
aba
abi
@@ -411,6 +1679,47 @@ acq
acu
Ade
adj
+create table t3 (
+period int not null,
+name char(32) not null,
+companynr int not null,
+price double(11,0),
+price2 double(11,0),
+key (period),
+key (name)
+);
+INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1001,"Iranizes",37,5987435,234724);
+INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1002,"violinist",37,28357832,8723648);
+INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1003,"extramarital",37,39654943,235872);
+INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1004,"spates",78,726498,72987523);
+INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1005,"cloakroom",78,98439034,823742);
+INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1006,"gazer",101,834598,27348324);
+INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1007,"hand",154,983543950,29837423);
+INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1008,"tucked",311,234298,3275892);
+INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1009,"gems",447,2374834,9872392);
+INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1010,"clinker",512,786542,76234234);
+create temporary table tmp type = myisam select * from t3;
+insert into t3 select * from tmp;
+insert into tmp select * from t3;
+insert into t3 select * from tmp;
+insert into tmp select * from t3;
+insert into t3 select * from tmp;
+insert into tmp select * from t3;
+insert into t3 select * from tmp;
+insert into tmp select * from t3;
+insert into t3 select * from tmp;
+insert into tmp select * from t3;
+insert into t3 select * from tmp;
+insert into tmp select * from t3;
+insert into t3 select * from tmp;
+insert into tmp select * from t3;
+insert into t3 select * from tmp;
+insert into tmp select * from t3;
+insert into t3 select * from tmp;
+alter table t3 add t2nr int not null auto_increment primary key first;
+drop table tmp;
+SET OPTION SQL_BIG_TABLES=1;
+select distinct concat(fld3," ",fld3) as namn from t2,t3 where t2.fld1=t3.t2nr order by namn limit 10;
namn
Abraham Abraham
abrogating abrogating
@@ -422,6 +1731,8 @@ ammonium ammonium
analyzable analyzable
animals animals
animized animized
+SET OPTION SQL_BIG_TABLES=0;
+select distinct concat(fld3," ",fld3) from t2,t3 where t2.fld1=t3.t2nr order by fld3 limit 10;
concat(fld3," ",fld3)
Abraham Abraham
abrogating abrogating
@@ -433,6 +1744,7 @@ ammonium ammonium
analyzable analyzable
animals animals
animized animized
+select distinct fld5 from t2 limit 10;
fld5
neat
Steinberg
@@ -444,6 +1756,7 @@ attainments
fanatic
measures
rightfulness
+select distinct fld3,count(*) from t2 group by companynr,fld3 limit 10;
fld3 count(*)
affixed 1
and 1
@@ -455,6 +1768,8 @@ attendants 1
bedlam 1
bedpost 1
boasted 1
+SET OPTION SQL_BIG_TABLES=1;
+select distinct fld3,count(*) from t2 group by companynr,fld3 limit 10;
fld3 count(*)
affixed 1
and 1
@@ -466,6 +1781,8 @@ attendants 1
bedlam 1
bedpost 1
boasted 1
+SET OPTION SQL_BIG_TABLES=0;
+select distinct fld3,repeat("a",length(fld3)),count(*) from t2 group by companynr,fld3 limit 100,10;
fld3 repeat("a",length(fld3)) count(*)
circus aaaaaa 1
cited aaaaa 1
@@ -477,6 +1794,7 @@ cultivation aaaaaaaaaaa 1
definiteness aaaaaaaaaaaa 1
demultiplex aaaaaaaaaaa 1
disappointing aaaaaaaaaaaaa 1
+select distinct companynr,rtrim(space(512+companynr)) from t3 order by 1,2;
companynr rtrim(space(512+companynr))
37
78
@@ -485,20 +1803,28 @@ companynr rtrim(space(512+companynr))
311
447
512
+select distinct fld3 from t2,t3 where t2.companynr = 34 and t2.fld1=t3.t2nr order by fld3;
fld3
+explain select t3.t2nr,fld3 from t2,t3 where t2.companynr = 34 and t2.fld1=t3.t2nr order by t3.t2nr,fld3;
table type possible_keys key key_len ref rows Extra
t2 ALL fld1 NULL NULL NULL 1199 where used; Using temporary; Using filesort
t3 eq_ref PRIMARY PRIMARY 4 t2.fld1 1 where used; Using index
+select period from t1;
period
9410
+select period from t1 where period=1900;
period
+select fld3,period from t1,t2 where fld1 = 011401 order by period;
fld3 period
breaking 9410
+select fld3,period from t2,t3 where t2.fld1 = 011401 and t2.fld1=t3.t2nr and t3.period=1001;
fld3 period
breaking 1001
+explain select fld3,period from t2,t3 where t2.fld1 = 011401 and t3.t2nr=t2.fld1 and 1001 = t3.period;
table type possible_keys key key_len ref rows Extra
t2 const fld1 fld1 4 const 1
t3 const PRIMARY,period PRIMARY 4 const 1
+select fld3,period from t2,t1 where companynr*10 = 37*10;
fld3 period
breaking 9410
Romans 9410
@@ -1088,6 +2414,7 @@ dusted 9410
encompasses 9410
presentation 9410
Kantian 9410
+select fld3,period,price,price2 from t2,t3 where t2.fld1=t3.t2nr and period >= 1001 and period <= 1002 and t2.companynr = 37 order by fld3,period, price;
fld3 period price price2
admonishing 1002 28357832 8723648
analyzable 1002 28357832 8723648
@@ -1148,11 +2475,32 @@ ventilate 1001 5987435 234724
wallet 1001 5987435 234724
Weissmuller 1002 28357832 8723648
Wotan 1002 28357832 8723648
+select t2.fld1,fld3,period,price,price2 from t2,t3 where t2.fld1>= 18201 and t2.fld1 <= 18811 and t2.fld1=t3.t2nr and period = 1001 and t2.companynr = 37;
fld1 fld3 period price price2
018201 relaxing 1001 5987435 234724
018601 vacuuming 1001 5987435 234724
018801 inch 1001 5987435 234724
018811 repetitions 1001 5987435 234724
+drop table if exists company;
+create table t4 (
+companynr tinyint(2) unsigned zerofill NOT NULL default '00',
+companyname char(30) NOT NULL default '',
+PRIMARY KEY (companynr),
+UNIQUE KEY companyname(companyname)
+) TYPE=MyISAM MAX_ROWS=50 PACK_KEYS=1 COMMENT='companynames';
+INSERT INTO t4 (companynr, companyname) VALUES (29,'company 1');
+INSERT INTO t4 (companynr, companyname) VALUES (34,'company 2');
+INSERT INTO t4 (companynr, companyname) VALUES (36,'company 3');
+INSERT INTO t4 (companynr, companyname) VALUES (37,'company 4');
+INSERT INTO t4 (companynr, companyname) VALUES (40,'company 5');
+INSERT INTO t4 (companynr, companyname) VALUES (41,'company 6');
+INSERT INTO t4 (companynr, companyname) VALUES (53,'company 7');
+INSERT INTO t4 (companynr, companyname) VALUES (58,'company 8');
+INSERT INTO t4 (companynr, companyname) VALUES (65,'company 9');
+INSERT INTO t4 (companynr, companyname) VALUES (68,'company 10');
+INSERT INTO t4 (companynr, companyname) VALUES (50,'company 11');
+INSERT INTO t4 (companynr, companyname) VALUES (00,'Unknown');
+select STRAIGHT_JOIN t2.companynr,companyname from t4,t2 where t2.companynr=t4.companynr group by t2.companynr;
companynr companyname
00 Unknown
29 company 1
@@ -1166,6 +2514,7 @@ companynr companyname
58 company 8
65 company 9
68 company 10
+select SQL_SMALL_RESULT t2.companynr,companyname from t4,t2 where t2.companynr=t4.companynr group by t2.companynr;
companynr companyname
00 Unknown
29 company 1
@@ -1179,8 +2528,10 @@ companynr companyname
58 company 8
65 company 9
68 company 10
+select * from t1,t1 t12;
Period Varor_period Period Varor_period
9410 9412 9410 9412
+select t2.fld1,t22.fld1 from t2,t2 t22 where t2.fld1 >= 250501 and t2.fld1 <= 250505 and t22.fld1 >= 250501 and t22.fld1 <= 250505;
fld1 fld1
250501 250501
250502 250501
@@ -1207,44 +2558,58 @@ fld1 fld1
250503 250505
250504 250505
250505 250505
+select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null;
companynr companyname
+explain select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null;
table type possible_keys key key_len ref rows Extra
t2 ALL NULL NULL NULL NULL 1199
-t4 eq_ref PRIMARY PRIMARY 1 t2.companynr 1 where used; Not exists
+t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1 where used; Not exists
+explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr is null;
table type possible_keys key key_len ref rows Extra
t4 ALL NULL NULL NULL NULL 12
t2 ALL NULL NULL NULL NULL 1199 where used; Not exists
+select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr=t4.companynr+1;
companynr companynr
37 36
41 40
+explain select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr=t4.companynr+1;
table type possible_keys key key_len ref rows Extra
t2 ALL NULL NULL NULL NULL 1199 Using temporary
t4 index NULL PRIMARY 1 NULL 12 where used; Using index
+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
038208 37 Selfridge 1008
+select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t2.fld1 = 38208 or t2.fld1 = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009;
fld1 companynr fld3 period
038008 37 reporters 1008
038208 37 Selfridge 1008
+select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t3.t2nr = 38208 or t3.t2nr = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009;
fld1 companynr fld3 period
038008 37 reporters 1008
038208 37 Selfridge 1008
+select period from t1 where (((period > 0) or period < 10000 or (period = 1900)) and (period=1900 and period <= 1901) or (period=1903 and (period=1903)) and period>=1902) or ((period=1904 or period=1905) or (period=1906 or period>1907)) or (period=1908 and period = 1909);
period
9410
+select period from t1 where ((period > 0 and period < 1) or (((period > 0 and period < 100) and (period > 10)) or (period > 10)) or (period > 0 and (period > 5 or period > 6)));
period
9410
+select a.fld1 from t2 as a,t2 b where ((a.fld1 = 250501 and a.fld1=b.fld1) or a.fld1=250502 or a.fld1=250503 or (a.fld1=250505 and a.fld1<=b.fld1 and b.fld1>=a.fld1)) and a.fld1=b.fld1;
fld1
250501
250502
250503
250505
+select fld1 from t2 where fld1 in (250502,98005,98006,250503,250605,250606) and fld1 >=250502 and fld1 not in (250605,250606);
fld1
250502
250503
+select fld1 from t2 where fld1 between 250502 and 250504;
fld1
250502
250503
250504
+select fld3 from t2 where (((fld3 like "_%L%" ) or (fld3 like "%ok%")) and ( fld3 like "L%" or fld3 like "G%")) and fld3 like "L%" ;
fld3
label
labeled
@@ -1255,8 +2620,10 @@ leaflet
lewdly
Lillian
luckily
+select count(*) from t1;
count(*)
1
+select companynr,count(*),sum(fld1) from t2 group by companynr;
companynr count(*) sum(fld1)
00 82 10355753
29 95 14473298
@@ -1270,18 +2637,22 @@ companynr count(*) sum(fld1)
58 23 2254293
65 10 2284055
68 12 3097288
+select companynr,count(*) from t2 group by companynr order by companynr desc limit 5;
companynr count(*)
68 12
65 10
58 23
53 4
50 11
+select count(*),min(fld4),max(fld4),sum(fld1),avg(fld1),std(fld1) from t2 where companynr = 34 and fld4<>"";
count(*) min(fld4) max(fld4) sum(fld1) avg(fld1) std(fld1)
70 absentee vest 17788966 254128.0857 3272.5940
+select companynr,count(*),min(fld4),max(fld4),sum(fld1),avg(fld1),std(fld1) from t2 group by companynr limit 3;
companynr count(*) min(fld4) max(fld4) sum(fld1) avg(fld1) std(fld1)
00 82 Anthony windmills 10355753 126289.6707 115550.9757
29 95 abut wetness 14473298 152350.5053 8368.5480
34 70 absentee vest 17788966 254128.0857 3272.5940
+select companynr,t2nr,count(price),sum(price),min(price),max(price),avg(price) from t3 where companynr = 37 group by companynr,t2nr limit 10;
companynr t2nr count(price) sum(price) min(price) max(price) avg(price)
37 1 1 5987435 5987435 5987435 5987435.0000
37 2 1 28357832 28357832 28357832 28357832.0000
@@ -1293,6 +2664,7 @@ companynr t2nr count(price) sum(price) min(price) max(price) avg(price)
37 22 1 28357832 28357832 28357832 28357832.0000
37 23 1 39654943 39654943 39654943 39654943.0000
37 31 1 5987435 5987435 5987435 5987435.0000
+select /*! SQL_SMALL_RESULT */ companynr,t2nr,count(price),sum(price),min(price),max(price),avg(price) from t3 where companynr = 37 group by companynr,t2nr limit 10;
companynr t2nr count(price) sum(price) min(price) max(price) avg(price)
37 1 1 5987435 5987435 5987435 5987435.0000
37 2 1 28357832 28357832 28357832 28357832.0000
@@ -1304,6 +2676,7 @@ companynr t2nr count(price) sum(price) min(price) max(price) avg(price)
37 22 1 28357832 28357832 28357832 28357832.0000
37 23 1 39654943 39654943 39654943 39654943.0000
37 31 1 5987435 5987435 5987435 5987435.0000
+select companynr,count(price),sum(price),min(price),max(price),avg(price) from t3 group by companynr ;
companynr count(price) sum(price) min(price) max(price) avg(price)
37 12543 309394878010 5987435 39654943 24666736.6667
78 8362 414611089292 726498 98439034 49582766.0000
@@ -1312,6 +2685,7 @@ companynr count(price) sum(price) min(price) max(price) avg(price)
311 4181 979599938 234298 234298 234298.0000
447 4181 9929180954 2374834 2374834 2374834.0000
512 4181 3288532102 786542 786542 786542.0000
+select distinct mod(companynr,10) from t4 group by companynr;
mod(companynr,10)
0
9
@@ -1322,10 +2696,13 @@ mod(companynr,10)
3
8
5
+select distinct 1 from t4 group by companynr;
1
1
+select count(distinct fld1) from t2;
count(distinct fld1)
1199
+select companynr,count(distinct fld1) from t2 group by companynr;
companynr count(distinct fld1)
00 82
29 95
@@ -1339,6 +2716,7 @@ companynr count(distinct fld1)
58 23
65 10
68 12
+select companynr,count(*) from t2 group by companynr;
companynr count(*)
00 82
29 95
@@ -1352,6 +2730,7 @@ companynr count(*)
58 23
65 10
68 12
+select companynr,count(distinct concat(fld1,repeat(65,1000))) from t2 group by companynr;
companynr count(distinct concat(fld1,repeat(65,1000)))
00 82
29 95
@@ -1365,6 +2744,7 @@ companynr count(distinct concat(fld1,repeat(65,1000)))
58 23
65 10
68 12
+select companynr,count(distinct concat(fld1,repeat(65,200))) from t2 group by companynr;
companynr count(distinct concat(fld1,repeat(65,200)))
00 82
29 95
@@ -1378,6 +2758,7 @@ companynr count(distinct concat(fld1,repeat(65,200)))
58 23
65 10
68 12
+select companynr,count(distinct floor(fld1/100)) from t2 group by companynr;
companynr count(distinct floor(fld1/100))
00 47
29 35
@@ -1391,6 +2772,7 @@ companynr count(distinct floor(fld1/100))
58 1
65 1
68 1
+select companynr,count(distinct concat(repeat(65,1000),floor(fld1/100))) from t2 group by companynr;
companynr count(distinct concat(repeat(65,1000),floor(fld1/100)))
00 47
29 35
@@ -1404,16 +2786,22 @@ companynr count(distinct concat(repeat(65,1000),floor(fld1/100)))
58 1
65 1
68 1
+select sum(fld1),fld3 from t2 where fld3="Romans" group by fld1 limit 10;
sum(fld1) fld3
11402 Romans
+select name,count(*) from t3 where name='cloakroom' group by name;
name count(*)
cloakroom 4181
+select name,count(*) from t3 where name='cloakroom' and price>10 group by name;
name count(*)
cloakroom 4181
+select count(*) from t3 where name='cloakroom' and price2=823742;
count(*)
4181
+select name,count(*) from t3 where name='cloakroom' and price2=823742 group by name;
name count(*)
cloakroom 4181
+select name,count(*) from t3 where name >= "extramarital" and price <= 39654943 group by name;
name count(*)
extramarital 4181
gazer 4181
@@ -1422,8 +2810,10 @@ Iranizes 4181
spates 4181
tucked 4181
violinist 4181
+select t2.fld3,count(*) from t2,t3 where t2.fld1=158402 and t3.name=t2.fld3 group by t3.name;
fld3 count(*)
spates 4181
+select companynr|0,companyname from t4 group by 1;
companynr|0 companyname
0 Unknown
29 company 1
@@ -1437,6 +2827,7 @@ companynr|0 companyname
58 company 8
65 company 9
68 company 10
+select t2.companynr,companyname,count(*) from t2,t4 where t2.companynr=t4.companynr group by t2.companynr order by companyname;
companynr companyname count(*)
29 company 1 95
68 company 10 12
@@ -1450,10 +2841,13 @@ companynr companyname count(*)
58 company 8 23
65 company 9 10
00 Unknown 82
+select t2.fld1,count(*) from t2,t3 where t2.fld1=158402 and t3.name=t2.fld3 group by t3.name;
fld1 count(*)
158402 4181
+select sum(Period)/count(*) from t1;
sum(Period)/count(*)
9410.00
+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
78 8362 414611089292 0.0000 652236
@@ -1462,8 +2856,10 @@ companynr count sum diff func
311 4181 979599938 0.0000 1300291
447 4181 9929180954 0.0000 1868907
512 4181 3288532102 0.0000 2140672
+select companynr,sum(price)/count(price) as avg from t3 group by companynr having avg > 70000000 order by avg;
companynr avg
154 983543950.00
+select companynr,count(*) from t2 group by companynr order by 2 desc;
companynr count(*)
37 588
36 215
@@ -1477,6 +2873,7 @@ companynr count(*)
50 11
65 10
53 4
+select companynr,count(*) from t2 where companynr > 40 group by companynr order by 2 desc;
companynr count(*)
41 52
58 23
@@ -1484,6 +2881,7 @@ companynr count(*)
50 11
65 10
53 4
+select t2.fld4,t2.fld1,count(price),sum(price),min(price),max(price),avg(price) from t3,t2 where t3.companynr = 37 and t2.fld1 = t3.t2nr group by fld1,t2.fld4;
fld4 fld1 count(price) sum(price) min(price) max(price) avg(price)
teethe 000001 1 5987435 5987435 5987435 5987435.0000
dreaded 011401 1 5987435 5987435 5987435 5987435.0000
@@ -1572,6 +2970,7 @@ partridges 038103 1 39654943 39654943 39654943 39654943.0000
recruited 038201 1 5987435 5987435 5987435 5987435.0000
dimensions 038202 1 28357832 28357832 28357832 28357832.0000
Chicana 038203 1 39654943 39654943 39654943 39654943.0000
+select t3.companynr,fld3,sum(price) from t3,t2 where t2.fld1 = t3.t2nr and t3.companynr = 512 group by companynr,fld3;
companynr fld3 sum(price)
512 boat 786542
512 capably 786542
@@ -1583,11 +2982,13 @@ companynr fld3 sum(price)
512 Micronesia 786542
512 Miles 786542
512 skies 786542
+select t2.companynr,count(*),min(fld3),max(fld3),sum(price),avg(price) from t2,t3 where t3.companynr >= 30 and t3.companynr <= 58 and t3.t2nr = t2.fld1 and 1+1=2 group by t2.companynr;
companynr count(*) min(fld3) max(fld3) sum(price) avg(price)
00 1 Omaha Omaha 5987435 5987435.0000
36 1 dubbed dubbed 28357832 28357832.0000
37 83 Abraham Wotan 1908978016 22999735.1325
50 2 scribbled tapestry 68012775 34006387.5000
+select t3.companynr+0,t3.t2nr,fld3,sum(price) from t3,t2 where t2.fld1 = t3.t2nr and t3.companynr = 37 group by 1,t3.t2nr,fld3,fld3,fld3,fld3,fld3 order by fld1;
t3.companynr+0 t2nr fld3 sum(price)
37 1 Omaha 5987435
37 11401 breaking 5987435
@@ -1676,32 +3077,41 @@ t3.companynr+0 t2nr fld3 sum(price)
37 38201 resumes 5987435
37 38202 analyzable 28357832
37 38203 terminator 39654943
+select sum(price) from t3,t2 where t2.fld1 = t3.t2nr and t3.companynr = 512 and t3.t2nr = 38008 and t2.fld1 = 38008 or t2.fld1= t3.t2nr and t3.t2nr = 38008 and t2.fld1 = 38008;
sum(price)
234298
+select t2.fld1,sum(price) from t3,t2 where t2.fld1 = t3.t2nr and t3.companynr = 512 and t3.t2nr = 38008 and t2.fld1 = 38008 or t2.fld1 = t3.t2nr and t3.t2nr = 38008 and t2.fld1 = 38008 or t3.t2nr = t2.fld1 and t2.fld1 = 38008 group by t2.fld1;
fld1 sum(price)
038008 234298
+explain select fld3 from t2 where 1>2 or 2>3;
Comment
Impossible WHERE
+explain select fld3 from t2 where fld1=fld1;
table type possible_keys key key_len ref rows Extra
t2 ALL NULL NULL NULL NULL 1199
+select companynr,fld1 from t2 HAVING fld1=250501 or fld1=250502;
companynr fld1
34 250501
34 250502
+select companynr,fld1 from t2 WHERE fld1>=250501 HAVING fld1<=250502;
companynr fld1
34 250501
34 250502
+select companynr,count(*) as count,sum(fld1) as sum from t2 group by companynr having count > 40 and sum/count >= 120000;
companynr count sum
00 82 10355753
29 95 14473298
34 70 17788966
37 588 83602098
41 52 12816335
+select companynr from t2 group by companynr having count(*) > 40 and sum(fld1)/count(*) >= 120000 ;
companynr
00
29
34
37
41
+select t2.companynr,companyname,count(*) from t2,t4 where t2.companynr=t4.companynr group by companyname having t2.companynr >= 40;
companynr companyname count(*)
68 company 10 12
50 company 11 11
@@ -1710,26 +3120,37 @@ companynr companyname count(*)
53 company 7 4
58 company 8 23
65 company 9 10
+select count(*) from t2;
count(*)
1199
+select count(*) from t2 where fld1 < 098024;
count(*)
387
+select min(fld1) from t2 where fld1>= 098024;
min(fld1)
98024
+select max(fld1) from t2 where fld1>= 098024;
max(fld1)
1232609
+select count(*) from t3 where price2=76234234;
count(*)
4181
+select count(*) from t3 where companynr=512 and price2=76234234;
count(*)
4181
+explain select min(fld1),max(fld1),count(*) from t2;
Comment
Select tables optimized away
+select min(fld1),max(fld1),count(*) from t2;
min(fld1) max(fld1) count(*)
0 1232609 1199
+select min(t2nr),max(t2nr) from t3 where t2nr=2115 and price2=823742;
min(t2nr) max(t2nr)
2115 2115
+select count(*),min(t2nr),max(t2nr) from t3 where name='spates' and companynr=78;
count(*) min(t2nr) max(t2nr)
4181 4 41804
+select t2nr,count(*) from t3 where name='gems' group by t2nr limit 20;
t2nr count(*)
9 1
19 1
@@ -1751,29 +3172,41 @@ t2nr count(*)
179 1
189 1
199 1
+select max(t2nr) from t3 where price=983543950;
max(t2nr)
41807
+select t1.period from t3 = t1 limit 1;
period
1001
+select t1.period from t1 as t1 limit 1;
period
9410
+select t1.period as "Nuvarande period" from t1 as t1 limit 1;
Nuvarande period
9410
+select period as ok_period from t1 limit 1;
ok_period
9410
+select period as ok_period from t1 group by ok_period limit 1;
ok_period
9410
+select 1+1 as summa from t1 group by summa limit 1;
summa
2
+select period as "Nuvarande period" from t1 group by "Nuvarande period" limit 1;
Nuvarande period
9410
+show tables;
Tables_in_test
t1
t2
t3
t4
+show tables from test like "s%";
Tables_in_test (s%)
+show tables from test like "t?";
Tables_in_test (t?)
+show full columns from t2;
Field Type Null Key Default Extra Privileges
auto int(11) PRI NULL auto_increment select,insert,update,references
fld1 int(6) unsigned zerofill UNI 000000 select,insert,update,references
@@ -1782,14 +3215,20 @@ fld3 char(30) MUL select,insert,update,references
fld4 char(35) select,insert,update,references
fld5 char(35) select,insert,update,references
fld6 char(4) select,insert,update,references
+show full columns from t2 from test like 'f%';
Field Type Null Key Default Extra Privileges
fld1 int(6) unsigned zerofill UNI 000000 select,insert,update,references
fld3 char(30) MUL select,insert,update,references
fld4 char(35) select,insert,update,references
fld5 char(35) select,insert,update,references
fld6 char(4) select,insert,update,references
+show full columns from t2 from test like 's%';
Field Type Null Key Default Extra Privileges
-Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Comment
-t2 0 PRIMARY 1 auto A 1199 NULL NULL
-t2 0 fld1 1 fld1 A 1199 NULL NULL
-t2 1 fld3 1 fld3 A NULL NULL NULL
+show keys from t2;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t2 0 PRIMARY 1 auto A 1199 NULL NULL BTREE
+t2 0 fld1 1 fld1 A 1199 NULL NULL BTREE
+t2 1 fld3 1 fld3 A NULL NULL NULL BTREE
+DO 1;
+DO benchmark(100,1+1),1,1;
+drop table t4, t3,t2, t1;
diff --git a/mysql-test/r/select_found.result b/mysql-test/r/select_found.result
new file mode 100644
index 00000000000..0e2cc108bb4
--- /dev/null
+++ b/mysql-test/r/select_found.result
@@ -0,0 +1,70 @@
+drop table if exists t1;
+create table t1 (a int not null auto_increment, b int not null, primary key(a));
+insert into t1 (b) values (2),(3),(5),(5),(5),(6),(7),(9);
+select SQL_CALC_FOUND_ROWS * from t1;
+a b
+1 2
+2 3
+3 5
+4 5
+5 5
+6 6
+7 7
+8 9
+select found_rows();
+FOUND_ROWS()
+8
+select SQL_CALC_FOUND_ROWS * from t1 limit 1;
+a b
+1 2
+select found_rows();
+FOUND_ROWS()
+8
+select SQL_BUFFER_RESULT SQL_CALC_FOUND_ROWS * from t1 limit 1;
+a b
+1 2
+select found_rows();
+FOUND_ROWS()
+8
+select SQL_CALC_FOUND_ROWS * from t1 order by b desc limit 1;
+a b
+8 9
+select found_rows();
+FOUND_ROWS()
+8
+select SQL_CALC_FOUND_ROWS distinct b from t1 limit 1;
+b
+2
+select found_rows();
+FOUND_ROWS()
+6
+select SQL_CALC_FOUND_ROWS b,count(*) as c from t1 group by b order by c desc limit 1;
+b c
+5 3
+select found_rows();
+FOUND_ROWS()
+6
+select SQL_CALC_FOUND_ROWS * from t1 left join t1 as t2 on (t1.b=t2.a) limit 2,1;
+a b a b
+3 5 5 5
+select found_rows();
+FOUND_ROWS()
+8
+drop table t1;
+create table t1 (a int not null primary key);
+insert into t1 values (1),(2),(3),(4),(5);
+select sql_calc_found_rows a from t1 where a in (1,2,3) order by a desc limit 0,2;
+a
+3
+2
+select FOUND_ROWS();
+FOUND_ROWS()
+3
+select sql_calc_found_rows a from t1 where a in (1,2,3) order by a+2 desc limit 0,2;
+a
+3
+2
+select FOUND_ROWS();
+FOUND_ROWS()
+3
+drop table t1;
diff --git a/mysql-test/r/select_safe.result b/mysql-test/r/select_safe.result
index 1111ba00cd9..e225a0e3995 100644
--- a/mysql-test/r/select_safe.result
+++ b/mysql-test/r/select_safe.result
@@ -1,10 +1,39 @@
+drop table if exists t1;
+SET SQL_SAFE_UPDATES=1,SQL_SELECT_LIMIT=4, SQL_MAX_JOIN_SIZE=9;
+create table t1 (a int primary key, b char(20));
+insert into t1 values(1,"test");
+SELECT SQL_BUFFER_RESULT * from t1;
a b
1 test
+update t1 set b="a" where a=1;
+delete from t1 where a=1;
+insert into t1 values(1,"test"),(2,"test2");
+SELECT SQL_BUFFER_RESULT * from t1;
a b
1 test
2 test2
+update t1 set b="a" where a=1;
+select 1 from t1,t1 as t2,t1 as t3,t1 as t4;
1
1
1
1
1
+update t1 set b="a";
+You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column
+update t1 set b="a" where b="test";
+You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column
+delete from t1;
+You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column
+delete from t1 where b="test";
+You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column
+delete from t1 where a+0=1;
+You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column
+select 1 from t1,t1 as t2,t1 as t3,t1 as t4,t1 as t5;
+The SELECT would examine too many records and probably take a very long time. Check your WHERE and use SET OPTION SQL_BIG_SELECTS=1 if the SELECT is ok
+update t1 set b="a" limit 1;
+update t1 set b="a" where b="b" limit 2;
+delete from t1 where b="test" limit 1;
+delete from t1 where a+0=1 limit 2;
+drop table t1;
+SET SQL_SAFE_UPDATES=0,SQL_SELECT_LIMIT=DEFAULT, SQL_MAX_JOIN_SIZE=DEFAULT;
diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result
index 099ea2fa109..d78f8b16170 100644
--- a/mysql-test/r/show_check.result
+++ b/mysql-test/r/show_check.result
@@ -1,92 +1,145 @@
-Table Op Msg_type Msg_text
-test.t1 optimize status OK
-Table Op Msg_type Msg_text
-test.t1 check status OK
-test.t2 check error The handler for the table doesn't support check/repair
-Table Op Msg_type Msg_text
-test.t1 repair status OK
-test.t2 repair error The handler for the table doesn't support check/repair
-Table Op Msg_type Msg_text
-test.t2 check error The handler for the table doesn't support check/repair
-test.t1 check status OK
-Table Op Msg_type Msg_text
-test.t2 check error Table 't2' was not locked with LOCK TABLES
-test.t1 check status OK
-Field Type Null Key Default Extra
-a int(11) PRI 0
-b int(11) MUL 0
-c int(11) 0
-Field Type Null Key Default Extra Privileges
-a int(11) PRI 0 select,insert,update,references
-b int(11) MUL 0 select,insert,update,references
-c int(11) 0 select,insert,update,references
-Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Comment
-t1 0 PRIMARY 1 a A 4 NULL NULL
-t1 1 b 1 b A 1 NULL NULL
-t1 1 b 2 c A 4 NULL NULL
+drop table if exists t1,t2;
+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);
+check table t1 fast;
Table Op Msg_type Msg_text
test.t1 check status Table is already up to date
+check table t1 fast;
Table Op Msg_type Msg_text
test.t1 check status Table is already up to date
+check table t1 changed;
Table Op Msg_type Msg_text
test.t1 check status OK
+insert into t1 values (5,5,5);
+check table t1 changed;
Table Op Msg_type Msg_text
test.t1 check status OK
+check table t1 medium;
Table Op Msg_type Msg_text
test.t1 check status OK
+check table t1 extended;
Table Op Msg_type Msg_text
test.t1 check status OK
-Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Comment
-t1 0 PRIMARY 1 a A 5 NULL NULL
-t1 1 b 1 b A 1 NULL NULL
-t1 1 b 2 c A 5 NULL NULL
+show index from t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 0 PRIMARY 1 a A 5 NULL NULL BTREE
+t1 1 b 1 b A 1 NULL NULL BTREE
+t1 1 b 2 c A 5 NULL NULL BTREE
+insert into t1 values (5,5,5);
+Duplicate entry '5' for key 1
+optimize table t1;
Table Op Msg_type Msg_text
test.t1 optimize status OK
+optimize table t1;
Table Op Msg_type Msg_text
test.t1 optimize status Table is already up to date
+drop table t1;
+show variables like "wait_timeout%";
Variable_name Value
wait_timeout 28800
+show variables like "this_doesn't_exists%";
Variable_name Value
+show table status from test like "this_doesn't_exists%";
Name Type Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Create_options Comment
+show databases;
Database
mysql
test
+show databases like "test%";
Database (test%)
test
+create table t1 (f1 int not null, f2 int not null, f3 int not null, f4 int not null, primary key(f1,f2,f3,f4));
+insert into t1 values (1,1,1,0),(1,1,2,0),(1,1,3,0),(1,2,1,0),(1,2,2,0),(1,2,3,0),(1,3,1,0),(1,3,2,0),(1,3,3,0),(1,1,1,1),(1,1,2,1),(1,1,3,1),(1,2,1,1),(1,2,2,1),(1,2,3,1),(1,3,1,1),(1,3,2,1),(1,3,3,1);
+analyze table t1;
Table Op Msg_type Msg_text
test.t1 analyze status OK
-Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Comment
-t1 0 PRIMARY 1 f1 A 1 NULL NULL
-t1 0 PRIMARY 2 f2 A 3 NULL NULL
-t1 0 PRIMARY 3 f3 A 9 NULL NULL
-t1 0 PRIMARY 4 f4 A 18 NULL NULL
+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 f1 A 1 NULL NULL BTREE
+t1 0 PRIMARY 2 f2 A 3 NULL NULL BTREE
+t1 0 PRIMARY 3 f3 A 9 NULL NULL BTREE
+t1 0 PRIMARY 4 f4 A 18 NULL NULL BTREE
+repair table t1;
Table Op Msg_type Msg_text
test.t1 repair status OK
-Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Comment
-t1 0 PRIMARY 1 f1 A 1 NULL NULL
-t1 0 PRIMARY 2 f2 A 3 NULL NULL
-t1 0 PRIMARY 3 f3 A 9 NULL NULL
-t1 0 PRIMARY 4 f4 A 18 NULL NULL
+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 f1 A 1 NULL NULL BTREE
+t1 0 PRIMARY 2 f2 A 3 NULL NULL BTREE
+t1 0 PRIMARY 3 f3 A 9 NULL NULL BTREE
+t1 0 PRIMARY 4 f4 A 18 NULL NULL BTREE
+drop table t1;
+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'
) TYPE=MyISAM
+alter table t1 rename t2;
+show create table t2;
Table Create Table
t2 CREATE TEMPORARY TABLE `t2` (
`a` int(11) NOT NULL default '0'
) TYPE=MyISAM
+drop table t2;
+create table t1 (
+test_set set( 'val1', 'val2', 'val3' ) not null default '',
+name char(20) default 'O''Brien'
+ ) comment = 'it\'s a table' ;
+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'
) TYPE=MyISAM COMMENT='it''s a table'
+drop table t1;
+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',
UNIQUE KEY `aa` (`a`)
) TYPE=MyISAM
+drop table t1;
+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',
PRIMARY KEY (`a`)
) TYPE=MyISAM
+drop table t1;
+flush tables;
+show open tables;
+Database Table In_use Name_locked
+create table t1(n int);
+insert into t1 values (1);
+show open tables;
+Database Table In_use Name_locked
+test t1 0 0
+drop table t1;
+create table t1 (a int not null, b VARCHAR(10), INDEX (b) ) AVG_ROW_LENGTH=10 CHECKSUM=1 COMMENT="test" TYPE=MYISAM MIN_ROWS=10 MAX_ROWS=100 PACK_KEYS=1 DELAY_KEY_WRITE=1 ROW_FORMAT=fixed;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL default '0',
+ `b` char(10) default NULL,
+ KEY `b` (`b`)
+) TYPE=MyISAM 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',
+ `b` varchar(10) default NULL,
+ KEY `b` (`b`)
+) TYPE=MyISAM MIN_ROWS=10 MAX_ROWS=200 AVG_ROW_LENGTH=10 PACK_KEYS=0 CHECKSUM=1 DELAY_KEY_WRITE=1 ROW_FORMAT=DYNAMIC COMMENT='test'
+ALTER TABLE t1 AVG_ROW_LENGTH=0 CHECKSUM=0 COMMENT="" MIN_ROWS=0 MAX_ROWS=0 PACK_KEYS=DEFAULT DELAY_KEY_WRITE=0 ROW_FORMAT=default;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL default '0',
+ `b` varchar(10) default NULL,
+ KEY `b` (`b`)
+) TYPE=MyISAM
+drop table t1;
diff --git a/mysql-test/r/slave-running.result b/mysql-test/r/slave-running.result
index 794d0935ef4..3699390a7d3 100644
--- a/mysql-test/r/slave-running.result
+++ b/mysql-test/r/slave-running.result
@@ -1,2 +1,3 @@
+show status like 'Slave_running';
Variable_name Value
Slave_running ON
diff --git a/mysql-test/r/slave-stopped.result b/mysql-test/r/slave-stopped.result
index 29ab2ac73e4..90b416b7bd7 100644
--- a/mysql-test/r/slave-stopped.result
+++ b/mysql-test/r/slave-stopped.result
@@ -1,2 +1,3 @@
+show status like 'Slave_running';
Variable_name Value
Slave_running OFF
diff --git a/mysql-test/r/status.result b/mysql-test/r/status.result
index 8f3ad3e0d59..3ef6cec32b3 100644
--- a/mysql-test/r/status.result
+++ b/mysql-test/r/status.result
@@ -1,6 +1,19 @@
+flush status;
+show status like 'Table_lock%';
Variable_name Value
Table_locks_immediate 0
Table_locks_waited 0
+SET SQL_LOG_BIN=0;
+drop table if exists t1;
+create table t1(n int) type=myisam;
+insert into t1 values(1);
+lock tables t1 read;
+unlock tables;
+lock tables t1 read;
+update t1 set n = 3;
+unlock tables;
+show status like 'Table_lock%';
Variable_name Value
Table_locks_immediate 3
Table_locks_waited 1
+drop table t1;
diff --git a/mysql-test/r/symlink.result b/mysql-test/r/symlink.result
new file mode 100644
index 00000000000..5626bc0fe11
--- /dev/null
+++ b/mysql-test/r/symlink.result
@@ -0,0 +1,65 @@
+drop table if exists t1,t2,t7,t8,t9;
+create table t1 (a int not null auto_increment, b char(16) not null, primary key (a));
+create table t2 (a int not null auto_increment, b char(16) not null, primary key (a));
+insert into t1 (b) values ("test"),("test1"),("test2"),("test3");
+insert into t2 (b) select b from t1;
+insert into t1 (b) select b from t2;
+insert into t2 (b) select b from t1;
+insert into t1 (b) select b from t2;
+insert into t2 (b) select b from t1;
+insert into t1 (b) select b from t2;
+insert into t2 (b) select b from t1;
+insert into t1 (b) select b from t2;
+insert into t2 (b) select b from t1;
+insert into t1 (b) select b from t2;
+insert into t2 (b) select b from t1;
+insert into t1 (b) select b from t2;
+insert into t2 (b) select b from t1;
+insert into t1 (b) select b from t2;
+insert into t2 (b) select b from t1;
+insert into t1 (b) select b from t2;
+insert into t2 (b) select b from t1;
+insert into t1 (b) select b from t2;
+drop table t2;
+insert into t9 select * from t1;
+check table t9;
+Table Op Msg_type Msg_text
+test.t9 check status OK
+optimize table t9;
+Table Op Msg_type Msg_text
+test.t9 optimize status OK
+repair table t9;
+Table Op Msg_type Msg_text
+test.t9 repair status OK
+alter table t9 add column c int not null;
+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',
+ PRIMARY KEY (`a`)
+) TYPE=MyISAM
+alter table t9 rename t8, add column d int not null;
+alter table t8 rename t7;
+rename table t7 to t9;
+drop table t1;
+Got one of the listed errors
+Got one of the listed errors
+Got one of the listed errors
+Got one of the listed errors
+Got one of the listed errors
+alter table t9 rename test_mysqltest.t9;
+select count(*) from test_mysqltest.t9;
+count(*)
+16724
+show create table test_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',
+ PRIMARY KEY (`a`)
+) TYPE=MyISAM
+drop database test_mysqltest;
diff --git a/mysql-test/r/tablelock.result b/mysql-test/r/tablelock.result
index 4fbeac979b1..2ffd8f928a9 100644
--- a/mysql-test/r/tablelock.result
+++ b/mysql-test/r/tablelock.result
@@ -1,12 +1,48 @@
+drop table if exists t1,t2;
+create table t1 ( n int auto_increment primary key);
+lock tables t1 write;
+insert into t1 values(NULL);
+unlock tables;
+check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
+lock tables t1 write, t1 as t0 read;
+insert into t1 values(NULL);
+unlock tables;
+check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
+lock tables t1 write, t1 as t0 read, t1 as t2 read;
+insert into t1 values(NULL);
+unlock tables;
+check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
+lock tables t1 write, t1 as t0 write, t1 as t2 read;
+insert into t1 values(NULL);
+unlock tables;
+check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
+lock tables t1 write, t1 as t0 write, t1 as t2 read, t1 as t3 read;
+insert into t1 values(NULL);
+unlock tables;
+check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
+lock tables t1 write, t1 as t0 write, t1 as t2 write;
+insert into t1 values(NULL);
+unlock tables;
+check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
+drop table t1;
+CREATE TABLE t1 (a int);
+CREATE TABLE t2 (a int);
+lock tables t1 write,t1 as b write, t2 write, t2 as c read;
+drop table t1,t2;
+CREATE TABLE t1 (a int);
+CREATE TABLE t2 (a int);
+lock tables t1 write,t1 as b write, t2 write, t2 as c read;
+drop table t2,t1;
+unlock tables;
diff --git a/mysql-test/r/temp_table.result b/mysql-test/r/temp_table.result
index 12e76bba3f7..84a00bfea34 100644
--- a/mysql-test/r/temp_table.result
+++ b/mysql-test/r/temp_table.result
@@ -1,30 +1,74 @@
+drop table if exists t1,t2;
+CREATE TABLE t1 (c int not null, d char (10) not null);
+insert into t1 values(1,""),(2,"a"),(3,"b");
+CREATE TEMPORARY TABLE t1 (a int not null, b char (10) not null);
+insert into t1 values(4,"e"),(5,"f"),(6,"g");
+alter table t1 rename t2;
+select * from t1;
c d
1
2 a
3 b
+select * from t2;
a b
4 e
5 f
6 g
+CREATE TABLE t2 (x int not null, y int not null);
+alter table t2 rename t1;
+select * from t1;
a b
4 e
5 f
6 g
+create TEMPORARY TABLE t2 type=heap select * from t1;
+create TEMPORARY TABLE IF NOT EXISTS t2 (a int) type=heap;
+CREATE TEMPORARY TABLE t1 (a int not null, b char (10) not null);
+Table 't1' already exists
+ALTER TABLE t1 RENAME t2;
+Table 't2' already exists
+select * from t2;
a b
4 e
5 f
6 g
+alter table t2 add primary key (a,b);
+drop table t1,t2;
+select * from t1;
c d
1
2 a
3 b
+drop table t2;
+create temporary table t1 select *,2 as "e" from t1;
+select * from t1;
c d e
1 2
2 a 2
3 b 2
+drop table t1;
+drop table t1;
+drop table if exists t1;
+CREATE TABLE t1 (pkCrash INTEGER PRIMARY KEY,strCrash VARCHAR(255));
+INSERT INTO t1 ( pkCrash, strCrash ) VALUES ( 1, '1');
+SELECT CONCAT_WS(pkCrash, strCrash) FROM t1;
CONCAT_WS(pkCrash, strCrash)
1
+drop table t1;
+create temporary table t1 select 1 as 'x';
+drop table t1;
+CREATE TABLE t1 (x INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TEMPORARY TABLE tmp SELECT *, NULL FROM t1;
+drop table t1;
+create temporary table t1 (id int(10) not null unique);
+create temporary table t2 (id int(10) not null primary key,
+val int(10) not null);
+insert into t1 values (1),(2),(4);
+insert into t2 values (1,1),(2,1),(3,1),(4,2);
+select one.id, two.val, elt(two.val,'one','two') from t1 one, t2 two where two.id=one.id order by one.id;
id val elt(two.val,'one','two')
1 1 one
2 1 one
4 2 two
+drop table t1,t2;
diff --git a/mysql-test/r/truncate.result b/mysql-test/r/truncate.result
index 716b38c57c7..79471611638 100644
--- a/mysql-test/r/truncate.result
+++ b/mysql-test/r/truncate.result
@@ -1,4 +1,16 @@
+create table t1 (a integer, b integer,c1 CHAR(10));
+insert into t1 (a) values (1),(2);
+truncate table t1;
+select count(*) from t1;
count(*)
0
+insert into t1 values(1,2,"test");
+select count(*) from t1;
count(*)
1
+delete from t1;
+select * from t1;
+a b c1
+drop table t1;
+select count(*) from t1;
+Table 'test.t1' doesn't exist
diff --git a/mysql-test/r/type_blob.result b/mysql-test/r/type_blob.result
index bc80ba38452..2047eed6227 100644
--- a/mysql-test/r/type_blob.result
+++ b/mysql-test/r/type_blob.result
@@ -1,5 +1,12 @@
+drop table if exists t1,t2,t3,t4,t5,t6,t7;
+create table t1 (nr int(5) not null auto_increment,b blob,str char(10), primary key (nr));
+insert into t1 values (null,"a","A");
+insert into t1 values (null,"bbb","BBB");
+insert into t1 values (null,"ccc","CCC");
+select last_insert_id();
last_insert_id()
3
+select * from t1,t1 as t2;
nr b str nr b str
1 a A 1 a A
2 bbb BBB 1 a A
@@ -10,54 +17,88 @@ nr b str nr b str
1 a A 3 ccc CCC
2 bbb BBB 3 ccc CCC
3 ccc CCC 3 ccc CCC
+drop table t1;
+create table t1 (a text);
+insert into t1 values ('where');
+update t1 set a='Where';
+select * from t1;
a
Where
+drop table t1;
+create table t1 (t text,c char(10),b blob, d char(10) binary);
+insert into t1 values (NULL,NULL,NULL,NULL);
+insert into t1 values ("","","","");
+insert into t1 values ("hello","hello","hello","hello");
+insert into t1 values ("HELLO","HELLO","HELLO","HELLO");
+insert into t1 values ("HELLO MY","HELLO MY","HELLO MY","HELLO MY");
+insert into t1 values ("a","a","a","a");
+insert into t1 values (1,1,1,1);
+insert into t1 values (NULL,NULL,NULL,NULL);
+update t1 set c="",b=null where c="1";
+lock tables t1 READ;
+show full fields from t1;
Field Type Null Key Default Extra Privileges
t text YES NULL select,insert,update,references
c varchar(10) YES NULL select,insert,update,references
b blob YES NULL select,insert,update,references
d varchar(10) binary YES NULL select,insert,update,references
+lock tables t1 WRITE;
+show full fields from t1;
Field Type Null Key Default Extra Privileges
t text YES NULL select,insert,update,references
c varchar(10) YES NULL select,insert,update,references
b blob YES NULL select,insert,update,references
d varchar(10) binary YES NULL select,insert,update,references
+unlock tables;
+select t from t1 where t like "hello";
t
hello
HELLO
+select c from t1 where c like "hello";
c
hello
HELLO
+select b from t1 where b like "hello";
b
hello
+select d from t1 where d like "hello";
d
hello
+select c from t1 having c like "hello";
c
hello
HELLO
+select d from t1 having d like "hello";
d
hello
+select t from t1 where t like "%HELLO%";
t
hello
HELLO
HELLO MY
+select c from t1 where c like "%HELLO%";
c
hello
HELLO
HELLO MY
+select b from t1 where b like "%HELLO%";
b
HELLO
HELLO MY
+select d from t1 where d like "%HELLO%";
d
HELLO
HELLO MY
+select c from t1 having c like "%HELLO%";
c
hello
HELLO
HELLO MY
+select d from t1 having d like "%HELLO%";
d
HELLO
HELLO MY
+select t from t1 order by t;
t
NULL
NULL
@@ -67,6 +108,7 @@ a
hello
HELLO
HELLO MY
+select c from t1 order by c;
c
NULL
NULL
@@ -76,6 +118,7 @@ a
hello
HELLO
HELLO MY
+select b from t1 order by b;
b
NULL
NULL
@@ -85,6 +128,7 @@ HELLO
HELLO MY
a
hello
+select d from t1 order by d;
d
NULL
NULL
@@ -94,6 +138,7 @@ HELLO
HELLO MY
a
hello
+select distinct t from t1;
t
NULL
@@ -101,6 +146,7 @@ hello
HELLO MY
a
1
+select distinct b from t1;
b
NULL
@@ -108,6 +154,7 @@ hello
HELLO
HELLO MY
a
+select distinct t from t1 order by t;
t
NULL
@@ -115,6 +162,7 @@ NULL
a
hello
HELLO MY
+select distinct b from t1 order by b;
b
NULL
@@ -122,6 +170,7 @@ HELLO
HELLO MY
a
hello
+select t from t1 group by t;
t
NULL
@@ -129,6 +178,7 @@ NULL
a
hello
HELLO MY
+select b from t1 group by b;
b
NULL
@@ -136,6 +186,8 @@ HELLO
HELLO MY
a
hello
+set option sql_big_tables=1;
+select distinct t from t1;
t
NULL
@@ -143,6 +195,7 @@ hello
HELLO MY
a
1
+select distinct b from t1;
b
NULL
@@ -150,6 +203,7 @@ hello
HELLO
HELLO MY
a
+select distinct t from t1 order by t;
t
NULL
@@ -157,6 +211,7 @@ NULL
a
hello
HELLO MY
+select distinct b from t1 order by b;
b
NULL
@@ -164,12 +219,14 @@ HELLO
HELLO MY
a
hello
+select distinct c from t1;
c
NULL
hello
HELLO MY
a
+select distinct d from t1;
d
NULL
@@ -178,12 +235,14 @@ HELLO
HELLO MY
a
1
+select distinct c from t1 order by c;
c
NULL
a
hello
HELLO MY
+select distinct d from t1 order by d;
d
NULL
@@ -192,12 +251,14 @@ HELLO
HELLO MY
a
hello
+select c from t1 group by c;
c
NULL
a
hello
HELLO MY
+select d from t1 group by d;
d
NULL
@@ -206,6 +267,8 @@ HELLO
HELLO MY
a
hello
+set option sql_big_tables=0;
+select distinct * from t1;
t c b d
NULL NULL NULL NULL
@@ -214,6 +277,7 @@ HELLO HELLO HELLO HELLO
HELLO MY HELLO MY HELLO MY HELLO MY
a a a a
1 NULL 1
+select t,count(*) from t1 group by t;
t count(*)
NULL 2
1
@@ -221,6 +285,7 @@ NULL 2
a 1
hello 2
HELLO MY 1
+select b,count(*) from t1 group by b;
b count(*)
NULL 3
1
@@ -228,12 +293,14 @@ HELLO 1
HELLO MY 1
a 1
hello 1
+select c,count(*) from t1 group by c;
c count(*)
NULL 2
2
a 1
hello 2
HELLO MY 1
+select d,count(*) from t1 group by d;
d count(*)
NULL 2
1
@@ -242,22 +309,142 @@ HELLO 1
HELLO MY 1
a 1
hello 1
+drop table t1;
+create table t1 (a text, key (a(300)));
+Incorrect sub part key. The used key part isn't a string, the used length is longer than the key part or the table handler doesn't support unique sub keys
+create table t1 (a text, key (a(255)));
+drop table t1;
+CREATE TABLE t1 (
+t1_id bigint(21) DEFAULT '0' NOT NULL auto_increment,
+_field_72 varchar(128) DEFAULT '' NOT NULL,
+_field_95 varchar(32),
+_field_115 tinyint(4) DEFAULT '0' NOT NULL,
+_field_122 tinyint(4) DEFAULT '0' NOT NULL,
+_field_126 tinyint(4),
+_field_134 tinyint(4),
+PRIMARY KEY (t1_id),
+UNIQUE _field_72 (_field_72),
+KEY _field_115 (_field_115),
+KEY _field_122 (_field_122)
+);
+INSERT INTO t1 VALUES (1,'admin','21232f297a57a5a743894a0e4a801fc3',0,1,NULL,NULL);
+INSERT INTO t1 VALUES (2,'hroberts','7415275a8c95952901e42b13a6b78566',0,1,NULL,NULL);
+INSERT INTO t1 VALUES (3,'guest','d41d8cd98f00b204e9800998ecf8427e',1,0,NULL,NULL);
+CREATE TABLE t2 (
+seq_0_id bigint(21) DEFAULT '0' NOT NULL,
+seq_1_id bigint(21) DEFAULT '0' NOT NULL,
+PRIMARY KEY (seq_0_id,seq_1_id)
+);
+INSERT INTO t2 VALUES (1,1);
+INSERT INTO t2 VALUES (2,1);
+INSERT INTO t2 VALUES (2,2);
+CREATE TABLE t3 (
+t3_id bigint(21) DEFAULT '0' NOT NULL auto_increment,
+_field_131 varchar(128),
+_field_133 tinyint(4) DEFAULT '0' NOT NULL,
+_field_135 datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
+_field_137 tinyint(4),
+_field_139 datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
+_field_140 blob,
+_field_142 tinyint(4) DEFAULT '0' NOT NULL,
+_field_145 tinyint(4) DEFAULT '0' NOT NULL,
+_field_148 tinyint(4) DEFAULT '0' NOT NULL,
+PRIMARY KEY (t3_id),
+KEY _field_133 (_field_133),
+KEY _field_135 (_field_135),
+KEY _field_139 (_field_139),
+KEY _field_142 (_field_142),
+KEY _field_145 (_field_145),
+KEY _field_148 (_field_148)
+);
+INSERT INTO t3 VALUES (1,'test job 1',0,'0000-00-00 00:00:00',0,'1999-02-25 22:43:32','test\r\njob\r\n1',0,0,0);
+INSERT INTO t3 VALUES (2,'test job 2',0,'0000-00-00 00:00:00',0,'1999-02-26 21:08:04','',0,0,0);
+CREATE TABLE t4 (
+seq_0_id bigint(21) DEFAULT '0' NOT NULL,
+seq_1_id bigint(21) DEFAULT '0' NOT NULL,
+PRIMARY KEY (seq_0_id,seq_1_id)
+);
+INSERT INTO t4 VALUES (1,1);
+INSERT INTO t4 VALUES (2,1);
+CREATE TABLE t5 (
+t5_id bigint(21) DEFAULT '0' NOT NULL auto_increment,
+_field_149 tinyint(4),
+_field_156 varchar(128) DEFAULT '' NOT NULL,
+_field_157 varchar(128) DEFAULT '' NOT NULL,
+_field_158 varchar(128) DEFAULT '' NOT NULL,
+_field_159 varchar(128) DEFAULT '' NOT NULL,
+_field_160 varchar(128) DEFAULT '' NOT NULL,
+_field_161 varchar(128) DEFAULT '' NOT NULL,
+PRIMARY KEY (t5_id),
+KEY _field_156 (_field_156),
+KEY _field_157 (_field_157),
+KEY _field_158 (_field_158),
+KEY _field_159 (_field_159),
+KEY _field_160 (_field_160),
+KEY _field_161 (_field_161)
+);
+INSERT INTO t5 VALUES (1,0,'tomato','','','','','');
+INSERT INTO t5 VALUES (2,0,'cilantro','','','','','');
+CREATE TABLE t6 (
+seq_0_id bigint(21) DEFAULT '0' NOT NULL,
+seq_1_id bigint(21) DEFAULT '0' NOT NULL,
+PRIMARY KEY (seq_0_id,seq_1_id)
+);
+INSERT INTO t6 VALUES (1,1);
+INSERT INTO t6 VALUES (1,2);
+INSERT INTO t6 VALUES (2,2);
+CREATE TABLE t7 (
+t7_id bigint(21) DEFAULT '0' NOT NULL auto_increment,
+_field_143 tinyint(4),
+_field_165 varchar(32),
+_field_166 smallint(6) DEFAULT '0' NOT NULL,
+PRIMARY KEY (t7_id),
+KEY _field_166 (_field_166)
+);
+INSERT INTO t7 VALUES (1,0,'High',1);
+INSERT INTO t7 VALUES (2,0,'Medium',2);
+INSERT INTO t7 VALUES (3,0,'Low',3);
+select replace(t3._field_140, "\r","^M"),t3_id,min(t3._field_131), min(t3._field_135), min(t3._field_139), min(t3._field_137), min(link_alias_142._field_165), min(link_alias_133._field_72), min(t3._field_145), min(link_alias_148._field_156), replace(min(t3._field_140), "\r","^M"),t3.t3_id from t3 left join t4 on t4.seq_0_id = t3.t3_id left join t7 link_alias_142 on t4.seq_1_id = link_alias_142.t7_id left join t6 on t6.seq_0_id = t3.t3_id left join t1 link_alias_133 on t6.seq_1_id = link_alias_133.t1_id left join t2 on t2.seq_0_id = t3.t3_id left join t5 link_alias_148 on t2.seq_1_id = link_alias_148.t5_id where t3.t3_id in (1) group by t3.t3_id order by link_alias_142._field_166, _field_139, link_alias_133._field_72, _field_135, link_alias_148._field_156;
replace(t3._field_140, "\r","^M") t3_id min(t3._field_131) min(t3._field_135) min(t3._field_139) min(t3._field_137) min(link_alias_142._field_165) min(link_alias_133._field_72) min(t3._field_145) min(link_alias_148._field_156) replace(min(t3._field_140), "\r","^M") t3_id
test^M
job^M
1 1 test job 1 0000-00-00 00:00:00 1999-02-25 22:43:32 0 High admin 0 tomato test^M
job^M
1 1
+drop table t1,t2,t3,t4,t5,t6,t7;
+create table t1 (a blob);
+insert into t1 values ("empty"),("");
+select a,reverse(a) from t1;
a reverse(a)
empty ytpme
+drop table t1;
+create table t1 (a blob, key (a(10)));
+insert into t1 values ("bye"),("hello"),("hello"),("hello word");
+select * from t1 where a like "hello%";
a
hello
hello
hello word
+drop table t1;
+CREATE TABLE t1 (
+f1 int(11) DEFAULT '0' NOT NULL,
+f2 varchar(16) DEFAULT '' NOT NULL,
+f5 text,
+KEY index_name (f1,f2,f5(16))
+);
+INSERT INTO t1 VALUES (0,'traktor','1111111111111');
+INSERT INTO t1 VALUES (1,'traktor','1111111111111111111111111');
+select count(*) from t1 where f2='traktor';
count(*)
2
+drop table t1;
+create table t1 (foobar tinyblob not null, boggle smallint not null, key (foobar(32), boggle));
+insert into t1 values ('fish', 10),('bear', 20);
+select foobar, boggle from t1 where foobar = 'fish';
foobar boggle
fish 10
+select foobar, boggle from t1 where foobar = 'fish' and boggle = 10;
foobar boggle
fish 10
+drop table t1;
diff --git a/mysql-test/r/type_date.result b/mysql-test/r/type_date.result
index df8f0ee1814..214328eab47 100644
--- a/mysql-test/r/type_date.result
+++ b/mysql-test/r/type_date.result
@@ -1,24 +1,73 @@
+create table t1 (a char(16), b date, c datetime);
+insert into t1 SET a='test 2000-01-01', b='2000-01-01', c='2000-01-01';
+select * from t1 where c = '2000-01-01';
a b c
test 2000-01-01 2000-01-01 2000-01-01 00:00:00
+select * from t1 where b = '2000-01-01';
a b c
test 2000-01-01 2000-01-01 2000-01-01 00:00:00
+drop table t1;
+drop table if exists t1,t2;
+CREATE TABLE t1 (name char(6),cdate date);
+INSERT INTO t1 VALUES ('name1','1998-01-01');
+INSERT INTO t1 VALUES ('name2','1998-01-01');
+INSERT INTO t1 VALUES ('name1','1998-01-02');
+INSERT INTO t1 VALUES ('name2','1998-01-02');
+CREATE TABLE t2 (cdate date, note char(6));
+INSERT INTO t2 VALUES ('1998-01-01','note01');
+INSERT INTO t2 VALUES ('1998-01-02','note02');
+select name,t1.cdate,note from t1,t2 where t1.cdate=t2.cdate and t1.cdate='1998-01-01';
name cdate note
name1 1998-01-01 note01
name2 1998-01-01 note01
+drop table t1,t2;
+CREATE TABLE t1 ( datum DATE );
+INSERT INTO t1 VALUES ( "2000-1-1" );
+INSERT INTO t1 VALUES ( "2000-1-2" );
+INSERT INTO t1 VALUES ( "2000-1-3" );
+INSERT INTO t1 VALUES ( "2000-1-4" );
+INSERT INTO t1 VALUES ( "2000-1-5" );
+SELECT * FROM t1 WHERE datum BETWEEN "2000-1-2" AND "2000-1-4";
datum
2000-01-02
2000-01-03
2000-01-04
+DROP TABLE t1;
+CREATE TABLE t1 (
+user_id char(10),
+summa int(11),
+rdate date
+);
+INSERT INTO t1 VALUES ('aaa',100,'1998-01-01');
+INSERT INTO t1 VALUES ('aaa',200,'1998-01-03');
+INSERT INTO t1 VALUES ('bbb',50,'1998-01-02');
+INSERT INTO t1 VALUES ('bbb',200,'1998-01-04');
+select max(rdate) as s from t1 where rdate < '1998-01-03' having s> "1998-01-01";
s
1998-01-02
+select max(rdate) as s from t1 having s="1998-01-04";
s
1998-01-04
+select max(rdate+0) as s from t1 having s="19980104";
s
19980104
+drop table t1;
+create table t1 (date date);
+insert into t1 values ("2000-08-10"),("2000-08-11");
+select date_add(date,INTERVAL 1 DAY),date_add(date,INTERVAL 1 SECOND) from t1;
date_add(date,INTERVAL 1 DAY) date_add(date,INTERVAL 1 SECOND)
2000-08-11 2000-08-10 00:00:01
2000-08-12 2000-08-11 00:00:01
+drop table t1;
+CREATE TABLE t1(AFIELD INT);
+INSERT INTO t1 VALUES(1);
+CREATE TABLE t2(GMT VARCHAR(32));
+INSERT INTO t2 VALUES('GMT-0800');
+SELECT DATE_FORMAT("2002-03-06 10:11:12", CONCAT('%a, %d %M %Y %H:%i:%s ' , t2.GMT)) FROM t1, t2 GROUP BY t1.AFIELD;
DATE_FORMAT("2002-03-06 10:11:12", CONCAT('%a, %d %M %Y %H:%i:%s ' , t2.GMT))
Wed, 06 March 2002 10:11:12 GMT-0800
+INSERT INTO t1 VALUES(1);
+SELECT DATE_FORMAT("2002-03-06 10:11:12", CONCAT('%a, %d %M %Y %H:%i:%s ' , t2.GMT)), DATE_FORMAT("2002-03-06 10:11:12", CONCAT('%a, %d %M %Y %H:%i:%s ' , t2.GMT)) FROM t1,t2 GROUP BY t1.AFIELD;
DATE_FORMAT("2002-03-06 10:11:12", CONCAT('%a, %d %M %Y %H:%i:%s ' , t2.GMT)) DATE_FORMAT("2002-03-06 10:11:12", CONCAT('%a, %d %M %Y %H:%i:%s ' , t2.GMT))
Wed, 06 March 2002 10:11:12 GMT-0800 Wed, 06 March 2002 10:11:12 GMT-0800
+drop table t1,t2;
diff --git a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result
index 7028b5ffe33..3e13485c872 100644
--- a/mysql-test/r/type_datetime.result
+++ b/mysql-test/r/type_datetime.result
@@ -1,3 +1,7 @@
+drop table if exists t1;
+create table t1 (t datetime);
+insert into t1 values(101),(691231),(700101),(991231),(10000101),(99991231),(101000000),(691231000000),(700101000000),(991231235959),(10000101000000),(99991231235959);
+select * from t1;
t
2000-01-01 00:00:00
2069-12-31 00:00:00
@@ -11,10 +15,15 @@ t
1999-12-31 23:59:59
1000-01-01 00:00:00
9999-12-31 23:59:59
+delete from t1 where t > 0;
+optimize table t1;
Table Op Msg_type Msg_text
test.t1 optimize status OK
+check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
+insert into t1 values("000101"),("691231"),("700101"),("991231"),("00000101"),("00010101"),("99991231"),("00101000000"),("691231000000"),("700101000000"),("991231235959"),("10000101000000"),("99991231235959");
+select * from t1;
t
2000-01-01 00:00:00
2069-12-31 00:00:00
@@ -29,7 +38,22 @@ t
1999-12-31 23:59:59
1000-01-01 00:00:00
9999-12-31 23:59:59
+drop table t1;
+CREATE TABLE t1 (a timestamp, b date, c time, d datetime);
+insert into t1 (b,c,d) values(now(),curtime(),now());
+select date_format(a,"%Y-%m-%d")=b,right(a,6)=c+0,a=d+0 from t1;
date_format(a,"%Y-%m-%d")=b right(a,6)=c+0 a=d+0
1 1 1
+drop table t1;
+CREATE TABLE t1 (a datetime not null);
+insert into t1 values (0);
+select * from t1 where a is null;
a
0000-00-00 00:00:00
+drop table t1;
+create table t1 (id int, dt datetime);
+insert into t1 values (1,"2001-08-14 00:00:00"),(2,"2001-08-15 00:00:00"),(3,"2001-08-16 00:00:00");
+select * from t1 where dt='2001-08-14 00:00:00' and dt = if(id=1,'2001-08-14 00:00:00','1999-08-15');
+id dt
+1 2001-08-14 00:00:00
+drop table t1;
diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result
index 0877424648b..9fee88f4bf8 100644
--- a/mysql-test/r/type_decimal.result
+++ b/mysql-test/r/type_decimal.result
@@ -1,5 +1,152 @@
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+id int(11) DEFAULT '0' NOT NULL auto_increment,
+datatype_id int(11) DEFAULT '0' NOT NULL,
+minvalue decimal(20,10) DEFAULT '0.0000000000' NOT NULL,
+maxvalue decimal(20,10) DEFAULT '0.0000000000' NOT NULL,
+valuename varchar(20),
+forecolor int(11),
+backcolor int(11),
+PRIMARY KEY (id),
+UNIQUE datatype_id (datatype_id, minvalue, maxvalue)
+);
+INSERT INTO t1 VALUES ( '1', '4', '0.0000000000', '0.0000000000', 'Ei saja', '0', '16776960');
+INSERT INTO t1 VALUES ( '2', '4', '1.0000000000', '1.0000000000', 'Sajab', '16777215', '255');
+INSERT INTO t1 VALUES ( '3', '1', '2.0000000000', '49.0000000000', '', '0', '16777215');
+INSERT INTO t1 VALUES ( '60', '11', '0.0000000000', '0.0000000000', 'Rikkis', '16777215', '16711680');
+INSERT INTO t1 VALUES ( '4', '12', '1.0000000000', '1.0000000000', 'nork sadu', '65280', '14474460');
+INSERT INTO t1 VALUES ( '5', '12', '2.0000000000', '2.0000000000', 'keskmine sadu', '255', '14474460');
+INSERT INTO t1 VALUES ( '6', '12', '3.0000000000', '3.0000000000', 'tugev sadu', '127', '14474460');
+INSERT INTO t1 VALUES ( '43', '39', '6.0000000000', '6.0000000000', 'lobjakas', '13107327', '16763080');
+INSERT INTO t1 VALUES ( '40', '39', '2.0000000000', '2.0000000000', 'vihm', '8355839', '16777215');
+INSERT INTO t1 VALUES ( '53', '1', '-35.0000000000', '-5.0000000000', '', '0', '16777215');
+INSERT INTO t1 VALUES ( '41', '39', '3.0000000000', '3.0000000000', 'külm vihm', '120', '16763080');
+INSERT INTO t1 VALUES ( '12', '21', '21.0000000000', '21.0000000000', 'Kuiv', '13158600', '16777215');
+INSERT INTO t1 VALUES ( '13', '21', '13.0000000000', '13.0000000000', 'Märg', '5263615', '16777215');
+INSERT INTO t1 VALUES ( '14', '21', '22.0000000000', '22.0000000000', 'Niiske', '9869055', '16777215');
+INSERT INTO t1 VALUES ( '19', '21', '33.0000000000', '33.0000000000', 'Märg', '5263615', '16777215');
+INSERT INTO t1 VALUES ( '15', '21', '23.0000000000', '23.0000000000', 'Märg', '5263615', '16777215');
+INSERT INTO t1 VALUES ( '16', '21', '31.0000000000', '31.0000000000', 'Kuiv', '13158600', '16777215');
+INSERT INTO t1 VALUES ( '17', '21', '12.0000000000', '12.0000000000', 'Niiske', '9869055', '16777215');
+INSERT INTO t1 VALUES ( '18', '21', '32.0000000000', '32.0000000000', 'Niiske', '9869055', '16777215');
+INSERT INTO t1 VALUES ( '20', '21', '331.0000000000', '331.0000000000', 'Härmatise hoiatus!', '14448840', '13158600');
+INSERT INTO t1 VALUES ( '21', '21', '11.0000000000', '11.0000000000', 'Kuiv', '13158600', '16777215');
+INSERT INTO t1 VALUES ( '22', '33', '21.0000000000', '21.0000000000', 'Pilves, kuiv', '8355711', '12632256');
+INSERT INTO t1 VALUES ( '23', '33', '13.0000000000', '13.0000000000', 'Sajab, märg', '0', '8355839');
+INSERT INTO t1 VALUES ( '24', '33', '22.0000000000', '22.0000000000', 'Pilves, niiske', '8355711', '12632319');
+INSERT INTO t1 VALUES ( '29', '33', '33.0000000000', '33.0000000000', 'Selge, märg', '16777215', '8355839');
+INSERT INTO t1 VALUES ( '25', '33', '23.0000000000', '23.0000000000', 'Pilves, märg', '8355711', '8355839');
+INSERT INTO t1 VALUES ( '26', '33', '31.0000000000', '31.0000000000', 'Selge, kuiv', '16777215', '12632256');
+INSERT INTO t1 VALUES ( '27', '33', '12.0000000000', '12.0000000000', 'Sajab, niiske', '0', '12632319');
+INSERT INTO t1 VALUES ( '28', '33', '32.0000000000', '32.0000000000', 'Selge, niiske', '16777215', '12632319');
+INSERT INTO t1 VALUES ( '30', '33', '331.0000000000', '331.0000000000', 'Härmatis! selge,kuiv', '16711680', '12632256');
+INSERT INTO t1 VALUES ( '31', '33', '11.0000000000', '11.0000000000', 'Sajab, kuiv', '0', '12632256');
+INSERT INTO t1 VALUES ( '32', '11', '1.0000000000', '1.0000000000', 'Korras', '16777215', '49152');
+INSERT INTO t1 VALUES ( '33', '21', '335.0000000000', '335.0000000000', 'Härmatis!', '14448840', '11842740');
+INSERT INTO t1 VALUES ( '34', '21', '134.0000000000', '134.0000000000', 'Hoiatus, M+S!', '255', '13158600');
+INSERT INTO t1 VALUES ( '35', '21', '133.0000000000', '133.0000000000', 'Hoiatus, märg!', '5263615', '13158600');
+INSERT INTO t1 VALUES ( '36', '21', '135.0000000000', '135.0000000000', 'Härmatis!', '14448840', '11842740');
+INSERT INTO t1 VALUES ( '37', '21', '334.0000000000', '334.0000000000', 'Härmatise hoiatus!', '14448840', '13158600');
+INSERT INTO t1 VALUES ( '38', '21', '132.0000000000', '132.0000000000', 'Hoiatus, niiske!', '9869055', '13158600');
+INSERT INTO t1 VALUES ( '39', '39', '1.0000000000', '1.0000000000', 'ei saja', '11206570', '16777215');
+INSERT INTO t1 VALUES ( '44', '39', '4.0000000000', '5.0000000000', 'lumi', '16711680', '16763080');
+INSERT INTO t1 VALUES ( '45', '12', '0.0000000000', '0.0000000000', '', '16777215', '14474460');
+INSERT INTO t1 VALUES ( '46', '39', '8.0000000000', '8.0000000000', 'rahe', '9830400', '16763080');
+INSERT INTO t1 VALUES ( '47', '39', '9.0000000000', '9.0000000000', 'tüüp ebaselge', '12582912', '16777215');
+INSERT INTO t1 VALUES ( '48', '39', '7.0000000000', '7.0000000000', 'lumetuisk', '7209070', '16763080');
+INSERT INTO t1 VALUES ( '142', '15', '2.0000000000', '49.0000000000', '', '0', '16777215');
+INSERT INTO t1 VALUES ( '52', '1', '-4.9000000000', '-0.1000000000', '', '0', '15774720');
+INSERT INTO t1 VALUES ( '141', '15', '-4.9000000000', '-0.1000000000', '', '0', '15774720');
+INSERT INTO t1 VALUES ( '55', '8', '0.0000000000', '0.0000000000', '', '0', '16777215');
+INSERT INTO t1 VALUES ( '56', '8', '0.0100000000', '0.1000000000', '', '0', '16770560');
+INSERT INTO t1 VALUES ( '57', '8', '0.1100000000', '25.0000000000', '', '0', '15774720');
+INSERT INTO t1 VALUES ( '58', '2', '90.0000000000', '94.9000000000', '', NULL, '16770560');
+INSERT INTO t1 VALUES ( '59', '6', '0.0000000000', '360.0000000000', '', NULL, '16777215');
+INSERT INTO t1 VALUES ( '61', '21', '38.0000000000', '38.0000000000', 'Niiske', '9869055', '16777215');
+INSERT INTO t1 VALUES ( '62', '38', '500.0000000000', '999.0000000000', '', '0', '16770560');
+INSERT INTO t1 VALUES ( '63', '38', '1000.0000000000', '2000.0000000000', '', '0', '16777215');
+INSERT INTO t1 VALUES ( '64', '17', '0.0000000000', '0.0000000000', '', NULL, '16777215');
+INSERT INTO t1 VALUES ( '65', '17', '0.1000000000', '10.0000000000', '', NULL, '16770560');
+INSERT INTO t1 VALUES ( '67', '21', '412.0000000000', '412.0000000000', 'Niiske', '9869055', '16777215');
+INSERT INTO t1 VALUES ( '68', '21', '413.0000000000', '413.0000000000', 'Märg', '5263615', '16777215');
+INSERT INTO t1 VALUES ( '69', '21', '113.0000000000', '113.0000000000', 'Märg', '5263615', '16777215');
+INSERT INTO t1 VALUES ( '70', '21', '416.0000000000', '416.0000000000', 'Lumine!', '16711680', '11842740');
+INSERT INTO t1 VALUES ( '71', '38', '0.0000000000', '499.0000000000', '', NULL, '16711680');
+INSERT INTO t1 VALUES ( '72', '22', '-49.0000000000', '49.0000000000', '', NULL, '16777215');
+INSERT INTO t1 VALUES ( '73', '13', '0.0000000000', '9.9000000000', '', NULL, '16777215');
+INSERT INTO t1 VALUES ( '74', '13', '10.0000000000', '14.9000000000', '', NULL, '16770560');
+INSERT INTO t1 VALUES ( '75', '7', '0.0000000000', '50.0000000000', '', NULL, '16777215');
+INSERT INTO t1 VALUES ( '76', '18', '0.0000000000', '0.0000000000', '', NULL, '16777215');
+INSERT INTO t1 VALUES ( '77', '18', '0.1000000000', '10.0000000000', '', NULL, '16770560');
+INSERT INTO t1 VALUES ( '78', '19', '300.0000000000', '400.0000000000', '', NULL, '16777215');
+INSERT INTO t1 VALUES ( '79', '19', '0.0000000000', '299.0000000000', '', NULL, '16770560');
+INSERT INTO t1 VALUES ( '80', '23', '0.0000000000', '100.0000000000', '', NULL, '16777215');
+INSERT INTO t1 VALUES ( '81', '24', '0.0000000000', '200.0000000000', '', NULL, '16777215');
+INSERT INTO t1 VALUES ( '82', '26', '0.0000000000', '0.0000000000', '', NULL, '16777215');
+INSERT INTO t1 VALUES ( '83', '26', '0.1000000000', '5.0000000000', '', NULL, '16776960');
+INSERT INTO t1 VALUES ( '84', '21', '422.0000000000', '422.0000000000', 'Niiske', '9869055', '16777215');
+INSERT INTO t1 VALUES ( '85', '21', '411.0000000000', '411.0000000000', 'Saju hoiat.,kuiv!', '16777215', '13158600');
+INSERT INTO t1 VALUES ( '86', '21', '423.0000000000', '423.0000000000', 'Märg', '5263615', '16777215');
+INSERT INTO t1 VALUES ( '144', '16', '-49.0000000000', '-5.0000000000', '', NULL, '16777215');
+INSERT INTO t1 VALUES ( '88', '16', '2.0000000000', '49.0000000000', '', NULL, '16777215');
+INSERT INTO t1 VALUES ( '89', '21', '338.0000000000', '338.0000000000', 'Härm.hoiatus, N+S!', '16744319', '13158600');
+INSERT INTO t1 VALUES ( '90', '21', '332.0000000000', '332.0000000000', 'Härm.hoiat., niiske!', '16744319', '13158600');
+INSERT INTO t1 VALUES ( '91', '21', '114.0000000000', '114.0000000000', 'Hoiatus, M+S!', '255', '13158600');
+INSERT INTO t1 VALUES ( '92', '21', '117.0000000000', '117.0000000000', 'Hoiatus, JÄÄ!', '14448840', '16711680');
+INSERT INTO t1 VALUES ( '93', '21', '116.0000000000', '116.0000000000', 'Lumine!', '16711680', '11842740');
+INSERT INTO t1 VALUES ( '94', '21', '414.0000000000', '414.0000000000', 'Hoiatus, M+S!', '255', '13158600');
+INSERT INTO t1 VALUES ( '95', '21', '325.0000000000', '325.0000000000', 'Härmatis!', '14448840', '11842740');
+INSERT INTO t1 VALUES ( '96', '21', '321.0000000000', '321.0000000000', 'Härmatise hoiatus!', '14448840', '13158600');
+INSERT INTO t1 VALUES ( '97', '21', '328.0000000000', '328.0000000000', 'Härm.hoiatus, N+S!', '16744319', '13158600');
+INSERT INTO t1 VALUES ( '98', '21', '28.0000000000', '28.0000000000', 'Niiske ja sool', '9869055', '16777215');
+INSERT INTO t1 VALUES ( '99', '21', '118.0000000000', '118.0000000000', 'Hoiatus, N+S!', '9869055', '13158600');
+INSERT INTO t1 VALUES ( '100', '21', '418.0000000000', '418.0000000000', 'Hoiatus, N+S!', '9869055', '13158600');
+INSERT INTO t1 VALUES ( '101', '21', '322.0000000000', '322.0000000000', 'Härm.hoiat., niiske!', '16744319', '13158600');
+INSERT INTO t1 VALUES ( '102', '21', '428.0000000000', '428.0000000000', 'Hoiatus, N+S!', '9869055', '13158600');
+INSERT INTO t1 VALUES ( '103', '21', '432.0000000000', '432.0000000000', 'Hoiatus, niiske!', '7895240', '13158600');
+INSERT INTO t1 VALUES ( '104', '21', '421.0000000000', '421.0000000000', 'Saju hoiat.,kuiv!', '16777215', '13158600');
+INSERT INTO t1 VALUES ( '105', '21', '24.0000000000', '24.0000000000', 'Märg ja sool', '255', '16777215');
+INSERT INTO t1 VALUES ( '106', '21', '438.0000000000', '438.0000000000', 'Hoiatus, N+S!', '9869055', '13158600');
+INSERT INTO t1 VALUES ( '107', '21', '112.0000000000', '112.0000000000', 'Hoiatus, niiske!', '9869055', '13158600');
+INSERT INTO t1 VALUES ( '108', '21', '34.0000000000', '34.0000000000', 'Märg ja sool', '255', '16777215');
+INSERT INTO t1 VALUES ( '109', '21', '434.0000000000', '434.0000000000', 'Hoiatus, M+S!', '255', '13158600');
+INSERT INTO t1 VALUES ( '110', '21', '124.0000000000', '124.0000000000', 'Hoiatus, M+S!', '255', '13158600');
+INSERT INTO t1 VALUES ( '111', '21', '424.0000000000', '424.0000000000', 'Hoiatus, M+S!', '255', '13158600');
+INSERT INTO t1 VALUES ( '112', '21', '123.0000000000', '123.0000000000', 'Hoiatus, märg!', '5263615', '13158600');
+INSERT INTO t1 VALUES ( '140', '15', '-49.0000000000', '-5.0000000000', '', '0', '16777215');
+INSERT INTO t1 VALUES ( '114', '21', '18.0000000000', '18.0000000000', 'Niiske ja sool', '9869055', '16777215');
+INSERT INTO t1 VALUES ( '115', '21', '122.0000000000', '122.0000000000', 'Hoiatus, niiske!', '9869055', '13158600');
+INSERT INTO t1 VALUES ( '116', '21', '14.0000000000', '14.0000000000', 'Märg ja sool', '255', '16777215');
+INSERT INTO t1 VALUES ( '117', '21', '311.0000000000', '311.0000000000', 'Härmatise hoiatus!', '14448840', '13158600');
+INSERT INTO t1 VALUES ( '121', '2', '95.0000000000', '100.0000000000', '', NULL, '15774720');
+INSERT INTO t1 VALUES ( '118', '2', '0.0000000000', '89.9000000000', '', NULL, '16777215');
+INSERT INTO t1 VALUES ( '119', '21', '16.0000000000', '16.0000000000', 'Lumine!', '16711680', '11842740');
+INSERT INTO t1 VALUES ( '120', '21', '26.0000000000', '26.0000000000', 'Lumine!', '16711680', '11842740');
+INSERT INTO t1 VALUES ( '122', '13', '15.0000000000', '50.0000000000', '', NULL, '15774720');
+INSERT INTO t1 VALUES ( '123', '5', '0.0000000000', '9.9000000000', '', NULL, '16777215');
+INSERT INTO t1 VALUES ( '124', '5', '10.0000000000', '14.9000000000', '', NULL, '16770560');
+INSERT INTO t1 VALUES ( '125', '5', '15.0000000000', '50.0000000000', '', NULL, '15774720');
+INSERT INTO t1 VALUES ( '126', '21', '128.0000000000', '128.0000000000', 'Hoiatus, N+S!', '9869055', '13158600');
+INSERT INTO t1 VALUES ( '127', '21', '318.0000000000', '318.0000000000', 'Härm.hoiatus, N+S!', '16744319', '13158600');
+INSERT INTO t1 VALUES ( '128', '21', '312.0000000000', '312.0000000000', 'Härm.hoiat., niiske!', '16744319', '13158600');
+INSERT INTO t1 VALUES ( '129', '21', '126.0000000000', '126.0000000000', 'Lumine!', '16711680', '11842740');
+INSERT INTO t1 VALUES ( '130', '21', '324.0000000000', '324.0000000000', 'Härmatise hoiatus!', '14448840', '13158600');
+INSERT INTO t1 VALUES ( '131', '21', '316.0000000000', '316.0000000000', 'Lumine!', '16711680', '11842740');
+INSERT INTO t1 VALUES ( '132', '1', '0.0000000000', '1.9000000000', '', NULL, '16769024');
+INSERT INTO t1 VALUES ( '134', '3', '-50.0000000000', '50.0000000000', '', NULL, '16777215');
+INSERT INTO t1 VALUES ( '135', '8', '26.0000000000', '2000.0000000000', '', '9868950', '15774720');
+INSERT INTO t1 VALUES ( '136', '21', '426.0000000000', '426.0000000000', 'Lumine!', '16711680', '11842740');
+INSERT INTO t1 VALUES ( '137', '21', '127.0000000000', '127.0000000000', 'Hoiatus, JÄÄ!', '14448840', '16711680');
+INSERT INTO t1 VALUES ( '138', '21', '121.0000000000', '121.0000000000', 'Kuiv', '13158600', '16777215');
+INSERT INTO t1 VALUES ( '139', '21', '326.0000000000', '326.0000000000', 'Lumine!', '16711680', '11842740');
+INSERT INTO t1 VALUES ( '143', '16', '-4.9000000000', '-0.1000000000', '', NULL, '15774720');
+INSERT INTO t1 VALUES ( '145', '15', '0.0000000000', '1.9000000000', '', '0', '16769024');
+INSERT INTO t1 VALUES ( '146', '16', '0.0000000000', '1.9000000000', '', '0', '16769024');
+select * from t1 where minvalue<=1 and maxvalue>=-1 and datatype_id=16;
id datatype_id minvalue maxvalue valuename forecolor backcolor
143 16 -4.9000000000 -0.1000000000 NULL 15774720
146 16 0.0000000000 1.9000000000 0 16769024
+select * from t1 where minvalue<=-1 and maxvalue>=-1 and datatype_id=16;
id datatype_id minvalue maxvalue valuename forecolor backcolor
143 16 -4.9000000000 -0.1000000000 NULL 15774720
+drop table t1;
diff --git a/mysql-test/r/type_enum.result b/mysql-test/r/type_enum.result
index de48527edad..355133532bf 100644
--- a/mysql-test/r/type_enum.result
+++ b/mysql-test/r/type_enum.result
@@ -1,3 +1,10 @@
+DROP TABLE if exists t1;
+CREATE TABLE t1 (
+field enum('001001','001004','001010','001018','001019','001020','001021','001027','001028','001029','001030','001031','001100','002003','002004','002005','002007','002008','002009','002012','002013','002014','003002','003003','003004','003005','003006','003007','003008','003009','003010','003011','003012','003013','003014','003015','003016','003017','003018','003019','004002','004003','004005','004006','004007','004008','004010','004012','004014','004016','004017','004020','004021','004022','004023','004024','004025','004026','006002','006004','006006','006010','006011','006012','006013','006014','007001','007002','007003','007004','007005','007006','007007','007008','007009','007010','007011','007012','007013','007014','007015','007016','007017','007018','007019','007020','007021','007022','007023','007024','007025','007026','007027','007028','007029','007030','007031','007032','007033','007034','007035','007036','007037','007038','007039','007040','007043','007044','009001','009002','009004','009005','009006','009007','009008','009009','009010','009011','009012','009013','010002','010003','010004','010005','010006','010007','010008','010009','010010','010011','010012','010013','010015','010016','010017','010018','010019','010020','010021','010022','010023','010024','010025','010026','010027','010028','011001','011002','011003','011004','011006','011012','011013','011014','011015','011016','012017','012018','012019','012023','012027','012028','012029','012030','012031','012032','012033','012034','012035','012036','012037','012038','012039','014001','016002','016003','016004','016007','016010','016011','016016','016019','016020','016021','016022','016023','016024','016026','016027','016028','016029','016030','016031','016032','016033','016034','017002','018001','019002','019004','020001','020003','020004','020005','020006','020007','020008','020009','022001','022002','022003','023001','023002','023003','023004','023005','023006','023007','023008','023010','023011','023012','023017','023019','023020','023021','023025','023026','023027','023028','023029','023030','023031','023032','023033','023034','023035','025001','025003','025004','025005','025006','025007','025008','025009','025010','025011','025012','025013','025014','025015','025016','025017','025018','025019','025020','025021','025022','025023','025024','025025','025026','025027','025028','025029','025030','025031','025032','025033','025034','025035','025036','025037','025038','025039','025040','025041','025042','025043','025044','025045','025046','025047','025048','025049','025050','025051','025052','025053','025054','025055','025056','025057','025058','025059','025060','025061','025062','025063','027001','027002','027011','035008','035012','036001','037001','037003','037004','037005','037006','037007','037008','037009','038004','038005','038006','038007','038009','039001','039002','039003','039004','039005','039006','046001','046002','046003','046004','046005','046007','046008','046009','046010','046011','046012','046013','046014','047001','047002','048001','051001','051002','051003','051004','052001','052002','052005','053015','053016','053019','053020','053023','053024','053026','053028','053029','053033','053034','053036','053037','053038','053039','053041','053042','053043','053045','053046','053047','053048','053051','053052','053054','053055','053056','053057','053068','053069','053070','053073','053074','053075','053086','053094','053095','053096','053097','053098','053099','053100','053101','053102','053103','053104','053105','053107','053122','053123','053124','053125','053127','053128','054001','054002','054003','054004','054005','054006','054007','054009','054010','056001','056002','056003','056004','056005','056006','056009','056010','056011','056016','056017','056018','056019','056020','056021','056022','057001','057002','057003','057004','058002','058003','058004','058005','060001','060003','060004','060005','060006','060007','061002','061003','061004','061005','061006','069006','069007','069010','069011','069012','069013','069014','069015','069016','069017','069018','069020','069021','069022','069023','069024','071002','071003','071004','071005','071006','071008','071011','071013','071020','071021','071022','072001','073001','073002','073003','073004','074001','074002','074003','074004','074005','074006','074007','074008','074009','074010','074011','074012','075001','075007','076101','076102','076103','077001','077002','077003','077004','077006','077007','077008','077009','078005','079002','079003','079004','079005','079006','079007','081001','082006','082007','082011','082013','082014','082015','082016','082017','082021','082022','082023','082024','082025','082026','082027','082028','082029','082030','082031','082032','082033','082034','082035','082036','082037','082038','082039','082040','082041','082042','082043','082044','084001','084002','084003','084004','084005','084007','084008','084009','084011','084013','084014','084016','084017','084027','084031','084032','084033','084035','084036','084037','084038','084039','084040','084041','084042','084043','084044','084045','084046','084047','084048','084049','084050','084051','085001','085002','085003','085004','085005','085006','085007','085009','085011','085012','085013','085014','085015','085016','085017','085018','085019','085020','085021','085022','085023','085028','085029','085030','085031','085033','085034','085035','085036','085037','085038','085040','085041','085042','085043','085044','085045','085046','085047','085048','085063','085064','085065','085068','085070','085071','085073','085082','085083','085086','085088','085089','085090','085091','085092','085093','085094','085095','085096','085097','085098','085099','085100','085101','085102','085103','085104','085105','085106','085107','085108','085109','085110','085111','085112','085113','085115','085119','085120','085121','085122','085123','085124','085125','085126','085127','085128','085129','085130','085132','085133','085134','085135','085136','085137','086001','086002','086003','086004','086005','088001','088003','088005','088006','088007','088008','088009','089001','090001','090002','090003','090004','090005','090006','090007','090008','090009','090010','090013','090015','090016','090017','090018','090019','090022','090027','090028','091001','091002','091005','091008','091009','091010','091011','091012','091013','091014','091015','091016','091017','091018','093001','093003','093098','093100','093102','093104','093141','093142','093146','093151','093153','093167','093168','093176','094001','094002','094004','094005','095004','099001','099002','100001','101001','102002','102003','105001','105002','106001','113001','113002','113003','113004','113005','113006','113007','113008','113009','113010','113011','113012','113013','113014','113015','113016','113017','113018','113019','113020','113021','113022','113023','113024','113025','113026','113027','113028','114001','115001','115002','115003','115004','115005','115006','115007','115008','115009','115010','115011','115012','115013','115014','115015','115016','115017','115018','115020','115021','115022','115023','115025','115026','115027','115028','115029','115030','115031','115032','115033','115034','115035','115036','115039','115040','115041','115042','115043','115044','115045','115046','115047','115048','115049','115050','115051','115052','115053','115054','115055','115056','115057','115059','115060','115061','115062','115063','115064','115065','115066','115067','115068','115069','115070','115071','115072','115073','115075','115076','115081','115082','115085','115086','115087','115088','115095','115096','115097','115098','115099','115101','115102','115103','115104','115105','115106','115108','115109','115110','115111','115112','115113','115114','115115','115116','115117','115118','115119','115120','115121','115122','116001','116002','116003','116004','116005','116006','116007','116008','116009','116010','116011','116012','117001','117002','117003','123001','124010','124014','124015','124019','124024','124025','124026','124027','124028','124029','124030','124031','124032','124033','124035','124036','124037','124038','124039','124040','124041','124042','124043','124044','124045','124046','124047','124048','124049','124050','124051','124052','124053','124054','124055','124056','124057','124058','124059','124060','124061','124062','124063','124064','124065','126001','126002','126003','126004','126005','126006','126007','126008','126009','126010','126011','126012','130001','132001','132002','132003','133001','133008','133009','133010','133011','133012','133013','133014','133015','133016','133017','133018','133019','133020','133021','133022','133023','133024','133025','133027','133028','133029','133030','133031','134001','135001','135002','135003','135004','135005','135006','135007','135008','135009','135010','136001','137009','137010','137011','137012','137013','137014','137015','137016','137017','137018','137019','138001','138002','138003','138004','139001','139003','140001','141001','141002','141003','141006','141007','141008','141009','141011','141012','141014','141015','141016','141017','141018','141019','141020','141021','141022','141023','141024','141025','141026','141027','141028','142001','142002','142003','142004','142005','142006','142007','142008','142010','142011','142012','144001','145001','145002','145003','145004','145005','145006','145007','145008','145009','145010','145011','145012','145013','145014','145015','145016','147001','150003','150005','150009','150013','150014','150015','150016','150017','150020','150021','152001','152002','152003','152004','152005','152006','152007','154001','154002','154003','155001','155002','155003','155004','155005','155006','159001','159002','159003','159004','160001','160002','160003','161001','162001','162002','162003','162004','162007','162010','162011','162012','163001','163002','163003','163005','163010','163011','163014','163015','163016','165001','165002','165003','165004','165005','165006','165007','165008','165009','165010','165011','165012','165013','165014','165015','165016','165017','165018','165019','165020','165021','165022','165023','165024','165025','165026','165027','165028','165029','165030','165031','165032','165033','165034','165035','165036','167001','168001','168002','168003','168004','168005','168007','168008','168009','168010','168011','168012','168013','168014','169001','169002','169003','169007','169008','169009','169010','170001','171001','171002','171003','171004','171005','171006','171007','171008','171009','172001','174001','174002','174003','176001','176002','176003','177001','177002','179001','179002','179003','179004','179005','179006','179007','179008','179009','179010','179011','179012','179013','179014','179015','179016','179017','179018','179019','179020','179021','179022','179023','179024','179025','179026','179027','179028','179029','179030','179031','179032','179033','179034','179035','179036','179037','179038','179039','179040','179041','179042','179043','179044','179045','179046','179047','180001','180010','180012','180013','180014','180015','180016','180017','180018','180019','180020','180021','180022','180023','180024','180025','180026','180027','180028','180030','180031','180032','180033','180034','180035','180036','180037','180038','180039','180041','180042','180043','180044','180045','180046','180047','180048','180049','180050','180051','180052','180053','180054','180055','180056','180057','180058','180059','180060','180061','180062','180063','180064','180065','180066','180067','180068','180069','180070','180071','182001','184001','184002','184005','184006','184007','184008','184009','184010','184011','185001','185003','187001','188001','188002','188003','188004','188005','188006','188007','188008','188009','188010','188011','191001','191002','192002','194001','194002','194003','194004','194005','194006','194007','195001','195002','195003','195004','195005','195006','195007','196001','196002','197001','197002','197003','197004','197005','197006','198001','198003','198004','198005','198006','198007','198008','198009','198010','198011','198012','198013','198014','198015','198016','198017','201001','201002','201005','202001','203001','203002','203003','203017','203018','203019','204001','204002','204003','205001','208001','208002','208003','208004','208005','209001','209002','209003','210001','210002','210003','210004','210005','210006','210007','210008','210009','210010','210011','210012','210013','211017','212001','212002','212003','212004','212005','212006','212007','212008','212009','212010','212011','212012','212013','218001','218003','218004','218006','218007','218008','218009','218011','218015','218016','218017','218018','218019','218020','218021','218022','218023','218024','218025','218026','218027','218028','218029','218030','218031','218032','218033','218034','218035','218036','221001','221002','221003','221004','221005','221006','221007','221008','221009','221010','221011','221012','221013','223001','223002','223003','224001','224002','224003','224006','224007','224008','225001','225002','225003','225004','225005','225006','225007','225008','225009','225010','225011','225012','225013','226001','226002','226003','226004','226005','226006','226007','226008','226009','227001','227002','227003','227004','227005','227006','227007','227008','227009','227010','227011','227012','227013','227014','227015','227016','227017','227018','227019','227020','227021','227022','227023','227024','227025','227026','227027','227028','227029','227030','227031','227032','227033','227034','227035','227036','227037','227038','227039','227040','227041','227042','227043','227044','227045','227046','227047','227048','227049','227050','227051','227052','227053','227054','227055','227056','227057','227058','227059','227060','227061','227062','227063','227064','227065','227066','227067','227068','227069','227070','227071','227072','227073','227074','227075','227076','227077','227078','227079','227080','227081','227082','227083','227084','227085','227086','227087','227088','227089','227090','227091','227092','227093','227094','227095','227096','227097','227098','227099','227100','227101','227102','227103','227104','227105','227106','227107','227108','227109','227110','227111','227112','227113','227114','227115','227116','227117','227118','227119','227120','227122','227123','227124','227125','227126','227127','227128','227129','227130','227131','227132','227133','227134','227135','227136','227137','227138','227139','227140','227141','227142','227143','227144','227145','227146','227147','227148','227149','227150','227151','227152','228001','229001','229002','229003','229004','229005','230001','230002','232001','233001','233002','233003','233004','233005','233006','233007','233008','234001','234002','234003','234004','234005','234006','234007','234008','234009','234010','234011','234012','234013','234014','234015','234016','234017','234018','234019','234020','234021','234022','234023','234024','234025','234026','234027','234028','234029','234030','235001','235002','235003','235004','235005','236001','236002','236003','237001','238002','238003','238004','238005','238006','238007','238008','333013','333014','333015','333016','333017','333018','333019','333020','333021','333022','333023','333024','333025','333030','333031','333032','333033','333034','333035','334001','334002','334003','334004','334005','334006','334007','336004','337001','337002','337003','337004','339001','339002','343001','344001','344002','344003','344004','344005','345001','345002','345003','347001','347002','348001','348002','348003','348004','348005','349001','349002','349003','350001','353001','353002','353003','353004','355001','355002','355003','355004','355005','355006','356001','358001','359001','359002','360001','360002','360003','360004','360005','366001','366002','366003','366004','369001','373001','373002','373003','373004','373005','373006','373007','373008','373009','373010','373011','373012','373013','373014','373015','373016','373017','373018','373019','373020','373021','374001','374002','374003','374004','374005','374006','374007','374008','374009','374010','374011','374012','374013','374014','374015','374016','376001','376002','376003','376004','376005','376006','376007','376008','376009','376010','376011','376012','376013','376016','376017','376018','376019','376020','376021','379003','382001','382002','383001','384001','384002','385001','385002','386001','386002','386003','386004','386005','386006','386007','386008','386009','386010','386011','386012','386013','386014','387001','389001','389002','389003','389004','392001','393001','393002','393003','393004','395001','396001','397001','397002','399001','399002','399003','400001','400002','401001','401002','401003','402001','402002','402003','402004','402005','403001','403002','403003','504001','504002','504004','504005','504006','504007','504008','504009','504010','504011','504012','504013','504014','504017','504018','504019','504021','504022','504023','504024','504025','506001','506002','508001','508002','511001','511002','511003','511004','511005','511006','511007','511008','511009','511010','511011','511012','511013','511014','511017','511018','511020','511021','511022','511024','511028','511029','513001','513002','513003','513004','514001','515001','515002','515003','515007','515008','515009','515010','515011','515012','515013','515014','515015','518001','518002','518003','520001','520002','521001','521002','521003','521004','521005','521006','521007','521008','521009','521010','521011','521012','521013','521014','521015','521016','523001','523002','523003','523004','523005','523006','523007','524001','700001','701001','701002','701003','702001','702002','702003','702004','702005','702006','702007','702008','703001','703002','703003','704001','704002','704003','704004','705001','706001','706002','707001','707002','707003','708001','709001','709002','710001','710002','711001','711002','712001','713001','713002','714001','714002','715001','716001','718001','718002','719001','719002','991001','991002','991003','991004','991005','991006','991007','991008','992001','995001','996001','996002','996003','998001','998002','998003','998004','998005','998006','998007','999001','999002','011017','011018','034001','034002','071010','208006','239001','519001','519003','126013','184012','053071','374017','374018','374019','374020','374021','404001','405002','405001','405003','405007','405006','405005','405004','240011','240010','240009','240008','240007','240006','240005','240004','240003','240002','240001','240012','240013','240014','240015','240016','240017','357001','235006','235007','712002','355008','355007','056023','999999','046015','019005','126014','241003','241002','241001','240018','240020','240019','242001','242002','242003','242004','242005','242006','089002','406001','406002','406003','406004','406005','406006','243001','243002','243003','243004','243005','243006','243007','243008','010030','010029','407001','407006','407005','407004','407003','407002','408001','366005','133032','016035','077010','996004','025064','011019','407007','407008','407009','409001','115123','504026','039007','039009','039008','039010','039011','039012','180072','240021','240023','408002','405008','235008','525001','525002','525003','525004','410001','410002','410003','410004','410005','410006','410007','410008','410009','410010','410011','410012','410013','410014','410015','410016','344006','240031','240030','240029','240028','240027','240026','240025','240024','240034','240033','240032','410017','410018','411001','411002','411003','411004','411005','411006','411007','411008','203020','203021','203022','412001','412002','412003','412004','069025','244001','244002','244009','244008','244007','244006','244005','244004','244003','244015','244014','244013','244012','244011','244010','244016','244017','240042','240041','240040','240039','240038','240037','240036','240035','405009','405010','240043','504034','504033','504032','504031','504030','504029','504028','504027','504042','504041','504040','504039','504038','504037','504036','504035','800001','410019','410020','410021','244018','244019','244020','399004','413001','504043','198018','198019','344007','082045','010031','010032','010033','010034','010035','504044','515016','801002','801003','801004','801005','802001','801001','414001','414002','414003','141029','141030','803001','803002','803003','803004','803005','803006','803007','803008','803009','803010','803011','803012','803013','803014','803015','803016','803017','410022','410023','803018','803019','803020','415002','415001','244021','011020','011023','011022','011021','025065','165037','165038','165039','416001','416002','416003','417001','418001','504045','803022','803021','240022','419001','420001','804010','804009','804008','804007','804006','804005','804004','804003','804002','804001','804020','804019','804018','804017','804016','804015','804014','804013','804012','804011','804024','804021','804023','804022','511019','511016','511015','511032','511031','511030','511027','511026','511025','511033','511023','133034','133033','169011','344008','344009','244022','244026','244025','244030','244023','244024','244027','244028','244029','244031','082046','082047','082048','126015','126016','416004','416005','421001','421002','016037','016036','115124','115125','115126','240049','240048','240047','240046','240045','240044','244032','244033','422001','422002','422003','422004','422005','184013','239002','805001','805002','805003','805004','805005','056024','423001','344010','235009','212014','056025','056026','802002','244034','244035','244036','244037','244038','244039','515017','504046','203015','245002','245001','071023','056027','056028','056029','056030','056031','056032','424001','056034','056033','805006','805007','805008','805009','805010','422008','422007','422006','422010','422009','422011','209004','150022','150023','100002','056035','023036','185004','185005','246001','247001','247002','425001','416006','165042','165041','165040','165043','010040','010039','010038','010037','010036','422012','422013','422014','422015','426000','248001','248002','248003','248004','248005','249001','249002','249003','249004','249005','249006','250007','250001','250002','250003','250004','250005','250006','250008','250009','250010','250011','250012','250013','251001','251002','422016','422017','422018','806001','806002','116013','235010','235011','091026','091027','091028','091029','091019','091020','091021','091022','091023','091024','091025','252001','243009','249007','249008','249009','011024','011025','427001','428002','428001','169012','429001','429002','429003') DEFAULT '001001' NOT NULL,
+KEY field (field)
+);
+INSERT INTO t1 VALUES ('001001'),('001001'),('001001'),('001001'),('001001'),('001001'),('001001'),('001001'),('001001'),('001010'),('001010'),('001010'),('001010'),('001010'),('001018'),('001018'),('001018'),('001018'),('001018'),('001018'),('001020'),('001020'),('001020'),('001020'),('001020'),('001020'),('001020'),('001020'),('001021'),('001021'),('001021'),('001021'),('001021'),('001021'),('001027'),('001027'),('001028'),('001030'),('001030'),('001030'),('001030'),('001031'),('001031'),('001031'),('001031'),('001031'),('001100'),('001100'),('002003'),('002003'),('002003'),('002003'),('002003'),('002003'),('002003'),('002003'),('002003'),('002004'),('002004'),('002004'),('002004'),('002004'),('002004'),('002004'),('002004'),('002004'),('002005'),('002005'),('002005'),('002005'),('002005'),('002005'),('002005'),('002005'),('002007'),('002007'),('002007'),('002007'),('002007'),('002007'),('002007'),('002008'),('002008'),('002008'),('002008'),('002008'),('002008'),('002008'),('002008'),('002009'),('002009'),('002009'),('002009'),('002009'),('002009'),('002009'),('002009'),('002012'),('002012'),('002012'),('002012'),('002012'),('002012'),('002012'),('002013'),('002013'),('002013'),('002013'),('002013'),('002013'),('002013'),('002013'),('002013'),('002014'),('002014'),('002014'),('002014'),('002014'),('002014'),('002014'),('002014'),('003002'),('003002'),('003002'),('003002'),('003002'),('003002'),('003003'),('003003'),('003003'),('003003'),('003003'),('003003'),('003004'),('003004'),('003004'),('003004'),('003004'),('003004'),('003005'),('003005'),('003005'),('003005'),('003005'),('003005'),('003005'),('003005'),('003005'),('003006'),('003006'),('003006'),('003006'),('003006'),('003006'),('003006'),('003006'),('003007'),('003007'),('003007'),('003007'),('003007'),('003008'),('003008'),('003008'),('003008'),('003008'),('003008'),('003009'),('003009'),('003009'),('003009'),('003009'),('003009'),('003009'),('003009'),('003009'),('003010'),('003010'),('003010'),('003010'),('003010'),('003010'),('003010'),('003010'),('003010'),('003011'),('003011'),('003011'),('003011'),('003011'),('003011'),('003011'),('003011'),('003012'),('003012'),('003012'),('003012'),('003012'),('003012'),('003012'),('003012'),('003013'),('003013'),('003013'),('003013'),('003013'),('003013'),('003013'),('003013'),('003014'),('003014'),('003014'),('003014'),('003014'),('003014'),('003014'),('003014'),('003015'),('003015'),('003015'),('003015'),('003015'),('003015'),('003016'),('003016'),('003016'),('003016'),('003016'),('003016'),('003017'),('003017'),('003017'),('003017'),('003017'),('003018'),('003018'),('003018'),('003018'),('003018'),('003019'),('003019'),('004003'),('004005'),('004005'),('004005'),('004005'),('004005'),('004005'),('004006'),('004008'),('004010'),('004012'),('004012'),('004014'),('004014'),('004014'),('004014'),('004014'),('004016'),('004017'),('004017'),('004017'),('004017'),('004017'),('004017'),('004017'),('004017'),('004020'),('004020'),('004020'),('004020'),('004020'),('004020'),('004021'),('004021'),('004021'),('004021'),('004021'),('004021'),('004021'),('004022'),('004023'),('004023'),('004023'),('004023'),('004023'),('004023'),('004023'),('004025'),('004026'),('004026'),('004026'),('004026'),('004026'),('006004'),('006006'),('006010'),('006010'),('006010'),('006010'),('006010'),('006010'),('006010'),('006011'),('006011'),('006011'),('006011'),('006011'),('006011'),('006012'),('006012'),('006012'),('006012'),('006012'),('006012'),('006014'),('006014'),('006014'),('007001'),('007001'),('007002'),('007003'),('007005'),('007007'),('007008'),('007009'),('007011'),('007012'),('007013'),('007015'),('007016'),('007017'),('007018'),('007019'),('007019'),('007020'),('007021'),('007021'),('007022'),('007023'),('007023'),('007025'),('007025'),('007025'),('007027'),('007029'),('007031'),('007031'),('007032'),('007034'),('007034'),('007036'),('007036'),('007036'),('007037'),('007037'),('007038'),('007040'),('007040'),('007040'),('007043'),('009001'),('009001'),('009001'),('009001'),('009001'),('009001'),('009001'),('009002'),('009002'),('009002'),('009002'),('009002'),('009004'),('009004'),('009004'),('009004'),('009005'),('009005'),('009005'),('009005'),('009005'),('009005'),('009005'),('009005'),('009006'),('009006'),('009006'),('009006'),('009007'),('009007'),('009007'),('009007'),('009007'),('009007'),('009008'),('009010'),('009010'),('009010'),('009010'),('009010'),('009010'),('009011'),('009011'),('009011'),('009011'),('009011'),('009012'),('009013'),('009013'),('009013'),('010002'),('010002'),('010002'),('010002'),('010002'),('010002'),('010002'),('010002'),('010003'),('010003'),('010003'),('010003'),('010003'),('010003'),('010003'),('010003'),('010003'),('010004'),('010004'),('010004'),('010004'),('010004'),('010004'),('010004'),('010004'),('010004'),('010005'),('010005'),('010005'),('010005'),('010006'),('010006'),('010006'),('010006'),('010006'),('010006'),('010006'),('010006'),('010006'),('010007'),('010007'),('010007'),('010007'),('010007'),('010007'),('010008'),('010008'),('010008'),('010008'),('010008'),('010008'),('010008'),('010009'),('010009'),('010009'),('010009'),('010009'),('010009'),('010010'),('010010'),('010010'),('010010'),('010010'),('010010'),('010010'),('010011'),('010011'),('010011'),('010011'),('010011'),('010011'),('010011'),('010011'),('010012'),('010012'),('010012'),('010012'),('010012'),('010012'),('010012'),('010013'),('010013'),('010013'),('010013'),('010013'),('010013'),('010015'),('010016'),('010016'),('010016'),('010016'),('010016'),('010016'),('010016'),('010016'),('010017'),('010017'),('010017'),('010017'),('010017'),('010017'),('010018'),('010018'),('010018'),('010018'),('010018'),('010018'),('010018'),('010018'),('010018'),('010019'),('010019'),('010019'),('010019'),('010019'),('010019'),('010020'),('010020'),('010020'),('010021'),('010021'),('010021'),('010021'),('010021'),('010021'),('010022'),('010022'),('010022'),('010022'),('010022'),('010022'),('010022'),('010022'),('010023'),('010023'),('010023'),('010023'),('010023'),('010023'),('010023'),('010023'),('010026'),('010027'),('010028'),('010028'),('011001'),('011001'),('011001'),('011001'),('011001'),('011001'),('011001'),('011002'),('011002'),('011002'),('011002'),('011002'),('011002'),('011002'),('011003'),('011003'),('011003'),('011003'),('011003'),('011003'),('011003'),('011003'),('011004'),('011004'),('011004'),('011004'),('011004'),('011004'),('011004'),('011006'),('011006'),('011006'),('011006'),('011006'),('011006'),('011006'),('011012'),('011012'),('011012'),('011013'),('011013'),('011013'),('011013'),('011013'),('011013'),('011014'),('011014'),('011014'),('011014'),('011015'),('011015'),('011015'),('011015'),('011015'),('011016'),('011016'),('011016'),('011016'),('011016'),('012017'),('012017'),('012027'),('012027'),('012032'),('012034'),('012036'),('012036'),('012037'),('012037'),('012038'),('012039'),('014001'),('014001'),('016016'),('016016'),('016016'),('016019'),('016020'),('016020'),('016020'),('016020'),('016020'),('016020'),('016020'),('016020'),('016021'),('016021'),('016021'),('016021'),('016021'),('016021'),('016021'),('016022'),('016022'),('016022'),('016023'),('016023'),('016023'),('016024'),('016024'),('016024'),('016024'),('016024'),('016024'),('016024'),('016026'),('016026'),('016026'),('016026'),('016026'),('016026'),('016028'),('016028'),('016028'),('016028'),('016028'),('016028'),('016028'),('016029'),('016029'),('016030'),('016031'),('016032'),('016032'),('016032'),('016032'),('016032'),('016032'),('016032'),('016033'),('016033'),('016033'),('016033'),('016033'),('016034'),('016034'),('016034'),('016034'),('016034'),('017002'),('017002'),('017002'),('017002'),('017002'),('018001'),('018001'),('018001'),('018001'),('018001'),('018001'),('018001'),('018001'),('019002'),('019002'),('019002'),('019002'),('019002'),('019002'),('019004'),('019004'),('019004'),('019004'),('019004'),('019004'),('020001'),('020001'),('020001'),('020001'),('020004'),('020006'),('020006'),('020006'),('020006'),('020006'),('020006'),('020008'),('020009'),('020009'),('020009'),('020009'),('020009'),('022001'),('022001'),('022001'),('022001'),('022002'),('022002'),('022002'),('022002'),('022003'),('022003'),('022003'),('022003'),('023001'),('023002'),('023002'),('023002'),('023002'),('023002'),('023002'),('023003'),('023003'),('023003'),('023003'),('023004'),('023004'),('023005'),('023005'),('023006'),('023006'),('023006'),('023006'),('023006'),('023006'),('023007'),('023007'),('023010'),('023010'),('023011'),('023011'),('023017'),('023019'),('023019'),('023019'),('023020'),('023020'),('023025'),('023025'),('023025'),('023026'),('023026'),('023026'),('023027'),('023027'),('023027'),('023028'),('023028'),('023029'),('023029'),('023030'),('023030'),('023032'),('023033'),('023033'),('023033'),('023033'),('023033'),('023033'),('023034'),('023035'),('023035'),('025001'),('025001'),('025001'),('025001'),('025001'),('025001'),('025001'),('025003'),('025003'),('025004'),('025004'),('025005'),('025005'),('025007'),('025007'),('025008'),('025008'),('025009'),('025010'),('025010'),('025010'),('025011'),('025011'),('025012'),('025012'),('025013'),('025013'),('025013'),('025014'),('025015'),('025016'),('025018'),('025018'),('025019'),('025019'),('025020'),('025020'),('025021'),('025022'),('025022'),('025023'),('025023'),('025024'),('025025'),('025025'),('025026'),('025026'),('025027'),('025027'),('025027'),('025028'),('025030'),('025031'),('025033'),('025034'),('025035'),('025037'),('025041'),('025042'),('025043'),('025046'),('025048'),('025048'),('025048'),('025049'),('025049'),('025049'),('025050'),('025050'),('025050'),('025051'),('025051'),('025052'),('025052'),('025052'),('025053'),('025053'),('025054'),('025054'),('025054'),('025054'),('025055'),('025056'),('025056'),('025056'),('025056'),('025056'),('025056'),('025056'),('025056'),('025056'),('025057'),('025057'),('025058'),('025058'),('025060'),('025060'),('025061'),('025062'),('025063'),('027001'),('027002'),('027011'),('036001'),('036001'),('036001'),('036001'),('036001'),('037003'),('037006'),('037007'),('037008'),('037008'),('038009'),('039001'),('039001'),('039001'),('039001'),('039001'),('039001'),('039002'),('039002'),('039002'),('039002'),('039002'),('039003'),('039003'),('039003'),('039003'),('039003'),('039003'),('039004'),('039004'),('039004'),('039004'),('039004'),('039005'),('039005'),('039005'),('039005'),('039005'),('039006'),('039006'),('039006'),('039006'),('046001'),('046001'),('046001'),('046001'),('046001'),('046001'),('046001'),('046001'),('046002'),('046002'),('046002'),('046002'),('046002'),('046002'),('046002'),('046002'),('046003'),('046003'),('046003'),('046003'),('046003'),('046003'),('046003'),('046005'),('046005'),('046005'),('046005'),('046005'),('046005'),('046005'),('046007'),('046007'),('046007'),('046007'),('046007'),('046007'),('046008'),('046008'),('046008'),('046008'),('046008'),('046009'),('046009'),('046009'),('046010'),('046012'),('046012'),('046012'),('046013'),('046014'),('046014'),('046014'),('047001'),('047001'),('047001'),('047001'),('047001'),('047001'),('047001'),('047001'),('047002'),('047002'),('047002'),('047002'),('047002'),('047002'),('047002'),('047002'),('048001'),('048001'),('048001'),('048001'),('048001'),('048001'),('048001'),('048001'),('051003'),('051003'),('051003'),('051003'),('051003'),('051004'),('051004'),('051004'),('051004'),('052001'),('052001'),('052001'),('052001'),('052001'),('052001'),('052001'),('052001'),('052002'),('052002'),('052005'),('052005'),('052005'),('052005'),('052005'),('052005'),('053016'),('053019'),('053019'),('053023'),('053023'),('053023'),('053023'),('053024'),('053024'),('053024'),('053026'),('053026'),('053026'),('053026'),('053028'),('053028'),('053029'),('053029'),('053029'),('053029'),('053033'),('053033'),('053033'),('053045'),('053046'),('053051'),('053051'),('053051'),('053054'),('053054'),('053054'),('053054'),('053057'),('053069'),('053069'),('053097'),('053107'),('053125'),('053125'),('053127'),('054001'),('054001'),('054001'),('054001'),('054001'),('054001'),('054001'),('054002'),('054002'),('054002'),('054002'),('054002'),('054002'),('054003'),('054003'),('054003'),('054003'),('054003'),('054003'),('054003'),('054004'),('054004'),('054004'),('054004'),('054004'),('054004'),('054004'),('054006'),('054006'),('054006'),('054007'),('054007'),('054007'),('054007'),('054007'),('054009'),('054009'),('054009'),('054009'),('054010'),('054010'),('054010'),('054010'),('054010'),('054010'),('054010'),('056001'),('056001'),('056001'),('056001'),('056001'),('056001'),('056001'),('056001'),('056001'),('056002'),('056002'),('056002'),('056002'),('056002'),('056002'),('056002'),('056002'),('056003'),('056003'),('056003'),('056003'),('056003'),('056003'),('056004'),('056004'),('056004'),('056004'),('056004'),('056004'),('056004'),('056005'),('056005'),('056005'),('056005'),('056005'),('056005'),('056005'),('056005'),('056005'),('056006'),('056006'),('056006'),('056006'),('056006'),('056006'),('056006'),('056006'),('056006'),('056009'),('056009'),('056009'),('056011'),('056016'),('056016'),('056016'),('056016'),('056016'),('056016'),('056016'),('056017'),('056017'),('056017'),('056017'),('056017'),('056017'),('056017'),('056017'),('056017'),('056018'),('056018'),('056018'),('056018'),('056018'),('056018'),('056019'),('056019'),('056019'),('056019'),('056019'),('056019'),('056019'),('056019'),('056020'),('056020'),('056020'),('056020'),('056022'),('056022'),('056022'),('056022'),('056022'),('057003'),('057003'),('057004'),('058002'),('058002'),('058002'),('058002'),('058003'),('058003'),('058003'),('058003'),('058004'),('058004'),('058004'),('058005'),('058005'),('058005'),('060001'),('060001'),('060001'),('060001'),('060001'),('060004'),('060004'),('060004'),('060004'),('060004'),('060004'),('060005'),('060005'),('060005'),('060005'),('060005'),('060005'),('060007'),('060007'),('060007'),('060007'),('060007'),('060007'),('060007'),('061004'),('061004'),('061004'),('061004'),('061004'),('061004'),('061006'),('061006'),('061006'),('061006'),('061006'),('061006'),('069006'),('069006'),('069006'),('069006'),('069006'),('069006'),('069006'),('069006'),('069006'),('069007'),('069007'),('069007'),('069007'),('069007'),('069007'),('069007'),('069007'),('069010'),('069010'),('069010'),('069010'),('069010'),('069010'),('069011'),('069012'),('069012'),('069012'),('069012'),('069012'),('069012'),('069012'),('069012'),('069012'),('069012'),('069013'),('069013'),('069013'),('069013'),('069013'),('069013'),('069013'),('069013'),('069013'),('069014'),('069014'),('069014'),('069014'),('069014'),('069014'),('069014'),('069014'),('069014'),('069015'),('069015'),('069015'),('069015'),('069015'),('069015'),('069015'),('069015'),('069015'),('069015'),('069016'),('069016'),('069016'),('069016'),('069016'),('069018'),('069018'),('069018'),('069018'),('069018'),('069018'),('069018'),('069018'),('069018'),('069020'),('069020'),('069020'),('069020'),('069021'),('069023'),('071002'),('071002'),('071002'),('071002'),('071002'),('071003'),('071003'),('071003'),('071003'),('071003'),('071004'),('071004'),('071004'),('071004'),('071004'),('071005'),('071005'),('071005'),('071005'),('071005'),('071005'),('071006'),('071006'),('071006'),('071006'),('071008'),('071008'),('071008'),('071008'),('071008'),('071008'),('071011'),('071011'),('071011'),('071011'),('071011'),('071020'),('071020'),('071020'),('071020'),('071020'),('071021'),('071022'),('071022'),('071022'),('072001'),('072001'),('074001'),('074002'),('074002'),('074002'),('074002'),('074002'),('074002'),('074002'),('074002'),('074003'),('074003'),('074003'),('074003'),('074003'),('074003'),('074003'),('074003'),('074004'),('074004'),('074004'),('074004'),('074004'),('074004'),('074004'),('074004'),('074005'),('074005'),('074005'),('074005'),('074005'),('074005'),('074005'),('074005'),('074006'),('074006'),('074006'),('074006'),('074006'),('074006'),('074006'),('074006'),('074007'),('074007'),('074007'),('074007'),('074007'),('074007'),('074007'),('074007'),('074008'),('074008'),('074008'),('074008'),('074008'),('074008'),('074008'),('074008'),('074009'),('074009'),('074009'),('074009'),('074009'),('074009'),('074009'),('074009'),('074010'),('074010'),('074010'),('074010'),('074010'),('074010'),('074010'),('074010'),('074011'),('074011'),('074011'),('074011'),('074011'),('074011'),('074011'),('074011'),('074012'),('074012'),('074012'),('074012'),('074012'),('074012'),('074012'),('075001'),('075001'),('075001'),('075007'),('075007'),('075007'),('075007'),('076101'),('076101'),('076101'),('076101'),('076102'),('076102'),('076102'),('076103'),('076103'),('076103'),('076103'),('076103'),('077001'),('077001'),('077001'),('077002'),('077002'),('077002'),('077002'),('077002'),('077002'),('077002'),('077003'),('077003'),('077003'),('077003'),('077003'),('077003'),('077003'),('077004'),('077004'),('077004'),('077004'),('077004'),('077004'),('077006'),('077006'),('077008'),('077008'),('077008'),('077008'),('077008'),('077008'),('077008'),('077009'),('077009'),('077009'),('077009'),('077009'),('077009'),('077009'),('078005'),('078005'),('078005'),('079002'),('079002'),('079002'),('079002'),('079002'),('079002'),('079002'),('079003'),('079003'),('079004'),('079004'),('079005'),('079005'),('079005'),('079005'),('079005'),('079005'),('079006'),('079006'),('079006'),('079006'),('079007'),('079007'),('079007'),('079007'),('079007'),('081001'),('081001'),('081001'),('081001'),('081001'),('082011'),('082011'),('082011'),('082011'),('082011'),('082013'),('082013'),('082013'),('082013'),('082013'),('082013'),('082014'),('082014'),('082014'),('082014'),('082014'),('082014'),('082014'),('082015'),('082015'),('082015'),('082015'),('082015'),('082016'),('082016'),('082016'),('082016'),('082016'),('082016'),('082017'),('082017'),('082017'),('082017'),('082017'),('082017'),('082017'),('082021'),('082021'),('082022'),('082022'),('082022'),('082022'),('082022'),('082023'),('082023'),('082023'),('082023'),('082023'),('082024'),('082024'),('082024'),('082024'),('082024'),('082025'),('082025'),('082025'),('082025'),('082025'),('082026'),('082026'),('082026'),('082026'),('082026'),('082027'),('082027'),('082027'),('082027'),('082027'),('082028'),('082028'),('082028'),('082028'),('082029'),('082029'),('082029'),('082029'),('082029'),('082030'),('082030'),('082030'),('082030'),('082031'),('082031'),('082031'),('082031'),('082031'),('082032'),('082032'),('082032'),('082033'),('082033'),('082034'),('082034'),('082034'),('082034'),('082034'),('082034'),('082034'),('082035'),('082035'),('082035'),('082036'),('082036'),('082036'),('082036'),('082037'),('082037'),('082037'),('082038'),('082038'),('082038'),('082038'),('082039'),('082039'),('082039'),('082039'),('082040'),('082040'),('082040'),('082040'),('082040'),('082041'),('082041'),('082041'),('082041'),('082042'),('082042'),('082043'),('082043'),('082043'),('082043'),('082043'),('082044'),('082044'),('082044'),('082044'),('084001'),('084002'),('084002'),('084002'),('084002'),('084003'),('084003'),('084003'),('084003'),('084003'),('084003'),('084003'),('084003'),('084004'),('084004'),('084004'),('084004'),('084004'),('084005'),('084005'),('084005'),('084005'),('084005'),('084007'),('084007'),('084007'),('084007'),('084007'),('084007'),('084008'),('084008'),('084008'),('084008'),('084008'),('084008'),('084009'),('084009'),('084009'),('084009'),('084009'),('084009'),('084011'),('084013'),('084013'),('084013'),('084013'),('084013'),('084014'),('084014'),('084014'),('084016'),('084016'),('084016'),('084016'),('084016'),('084016'),('084016'),('084016'),('084017'),('084017'),('084017'),('084017'),('084017'),('084017'),('084017'),('084017'),('084017'),('084027'),('084027'),('084027'),('084027'),('084027'),('084027'),('084032'),('084032'),('084033'),('084033'),('084033'),('084035'),('084035'),('084035'),('084036'),('084036'),('084036'),('084036'),('084036'),('084036'),('084037'),('084037'),('084038'),('084038'),('084038'),('084038'),('084038'),('084038'),('084039'),('084039'),('084039'),('084039'),('084040'),('084040'),('084040'),('084040'),('084040'),('084041'),('084041'),('084041'),('084041'),('084042'),('084042'),('084043'),('084043'),('084043'),('084043'),('084044'),('084044'),('084044'),('084044'),('084044'),('084045'),('084046'),('084046'),('084046'),('084047'),('084048'),('084048'),('084049'),('084049'),('084050'),('084051'),('084051'),('085001'),('085001'),('085001'),('085001'),('085001'),('085001'),('085002'),('085002'),('085002'),('085002'),('085003'),('085003'),('085003'),('085003'),('085003'),('085003'),('085003'),('085004'),('085004'),('085004'),('085004'),('085004'),('085004'),('085004'),('085005'),('085005'),('085005'),('085005'),('085005'),('085005'),('085006'),('085006'),('085006'),('085006'),('085006'),('085006'),('085006'),('085006'),('085007'),('085007'),('085007'),('085007'),('085007'),('085007'),('085007'),('085009'),('085009'),('085009'),('085009'),('085009'),('085009'),('085011'),('085011'),('085011'),('085011'),('085011'),('085011'),('085011'),('085011'),('085012'),('085012'),('085012'),('085012'),('085012'),('085012'),('085012'),('085014'),('085014'),('085014'),('085014'),('085014'),('085014'),('085014'),('085014'),('085014'),('085015'),('085015'),('085015'),('085015'),('085015'),('085015'),('085015'),('085015'),('085016'),('085016'),('085016'),('085016'),('085016'),('085016'),('085016'),('085016'),('085017'),('085017'),('085017'),('085017'),('085017'),('085018'),('085018'),('085018'),('085018'),('085018'),('085019'),('085019'),('085019'),('085019'),('085019'),('085019'),('085019'),('085019'),('085019'),('085020'),('085020'),('085020'),('085020'),('085020'),('085020'),('085022'),('085022'),('085022'),('085022'),('085022'),('085022'),('085023'),('085023'),('085023'),('085023'),('085023'),('085028'),('085028'),('085028'),('085028'),('085028'),('085028'),('085028'),('085029'),('085029'),('085029'),('085029'),('085029'),('085029'),('085029'),('085030'),('085030'),('085030'),('085030'),('085030'),('085030'),('085030'),('085031'),('085031'),('085031'),('085031'),('085031'),('085031'),('085031'),('085033'),('085034'),('085034'),('085034'),('085034'),('085034'),('085034'),('085034'),('085035'),('085035'),('085035'),('085035'),('085035'),('085035'),('085036'),('085036'),('085036'),('085036'),('085036'),('085036'),('085037'),('085037'),('085037'),('085037'),('085037'),('085037'),('085038'),('085038'),('085038'),('085038'),('085038'),('085038'),('085038'),('085040'),('085040'),('085040'),('085040'),('085040'),('085040'),('085040'),('085040'),('085041'),('085041'),('085041'),('085041'),('085041'),('085041'),('085041'),('085041'),('085042'),('085042'),('085042'),('085042'),('085042'),('085042'),('085042'),('085043'),('085043'),('085043'),('085043'),('085043'),('085043'),('085044'),('085044'),('085044'),('085044'),('085044'),('085044'),('085044'),('085045'),('085045'),('085045'),('085045'),('085045'),('085046'),('085046'),('085046'),('085046'),('085046'),('085046'),('085046'),('085046'),('085047'),('085047'),('085047'),('085047'),('085047'),('085047'),('085047'),('085047'),('085048'),('085048'),('085048'),('085048'),('085048'),('085048'),('085048'),('085063'),('085063'),('085063'),('085063'),('085063'),('085064'),('085064'),('085064'),('085064'),('085064'),('085065'),('085065'),('085068'),('085068'),('085068'),('085068'),('085068'),('085068'),('085071'),('085071'),('085071'),('085071'),('085071'),('085071'),('085073'),('085073'),('085082'),('085082'),('085082'),('085082'),('085082'),('085086'),('085086'),('085086'),('085088'),('085088'),('085088'),('085088'),('085088'),('085088'),('085088'),('085089'),('085089'),('085090'),('085090'),('085090'),('085090'),('085090'),('085090'),('085090'),('085090'),('085091'),('085091'),('085091'),('085091'),('085091'),('085092'),('085092'),('085092'),('085093'),('085093'),('085095'),('085095'),('085095'),('085095'),('085095'),('085096'),('085096'),('085096'),('085096'),('085096'),('085096'),('085097'),('085097'),('085097'),('085097'),('085097'),('085098'),('085098'),('085098'),('085098'),('085098'),('085098'),('085098'),('085099'),('085099'),('085099'),('085099'),('085099'),('085099'),('085099'),('085100'),('085100'),('085100'),('085100'),('085100'),('085100'),('085100'),('085100'),('085100'),('085100'),('085101'),('085101'),('085101'),('085101'),('085101'),('085101'),('085101'),('085101'),('085102'),('085102'),('085103'),('085103'),('085103'),('085104'),('085104'),('085104'),('085104'),('085104'),('085105'),('085105'),('085106'),('085106'),('085106'),('085106'),('085106'),('085106'),('085108'),('085108'),('085109'),('085109'),('085109'),('085109'),('085109'),('085109'),('085109'),('085109'),('085110'),('085110'),('085110'),('085110'),('085110'),('085111'),('085111'),('085111'),('085112'),('085112'),('085112'),('085112'),('085113'),('085113'),('085113'),('085113'),('085113'),('085115'),('085120'),('085121'),('085121'),('085121'),('085121'),('085122'),('085122'),('085122'),('085122'),('085122'),('085122'),('085122'),('085122'),('085123'),('085123'),('085123'),('085123'),('085123'),('085123'),('085123'),('085123'),('085125'),('085125'),('085125'),('085125'),('085125'),('085126'),('085126'),('085126'),('085126'),('085126'),('085127'),('085127'),('085127'),('085127'),('085127'),('085127'),('085127'),('085127'),('085128'),('085128'),('085128'),('085128'),('085128'),('085129'),('085129'),('085129'),('085129'),('085129'),('085130'),('085130'),('085130'),('085130'),('085130'),('085132'),('085132'),('085132'),('085132'),('085132'),('085132'),('085133'),('085133'),('085133'),('085133'),('085133'),('085134'),('085134'),('085134'),('085135'),('085135'),('085135'),('085136'),('085136'),('085136'),('085136'),('085137'),('085137'),('085137'),('085137'),('085137'),('085137'),('085137'),('086002'),('086002'),('086002'),('086002'),('086003'),('086003'),('086003'),('086003'),('086005'),('088001'),('088001'),('088001'),('088001'),('088001'),('088003'),('088003'),('088003'),('088003'),('088003'),('088003'),('088005'),('088005'),('088005'),('088005'),('088005'),('088006'),('088006'),('088006'),('088006'),('088006'),('088007'),('088007'),('088007'),('088008'),('088008'),('088008'),('088008'),('088009'),('088009'),('088009'),('088009'),('088009'),('089001'),('089001'),('089001'),('089001'),('089001'),('089001'),('089001'),('090001'),('090001'),('090001'),('090001'),('090001'),('090001'),('090001'),('090002'),('090002'),('090002'),('090002'),('090002'),('090002'),('090003'),('090003'),('090003'),('090003'),('090003'),('090003'),('090003'),('090004'),('090004'),('090004'),('090004'),('090004'),('090004'),('090004'),('090006'),('090006'),('090006'),('090006'),('090006'),('090006'),('090006'),('090008'),('090008'),('090008'),('090008'),('090008'),('090009'),('090009'),('090009'),('090009'),('090009'),('090010'),('090010'),('090013'),('090013'),('090013'),('090016'),('090016'),('090017'),('090018'),('090022'),('090027'),('091001'),('091001'),('091001'),('091001'),('091001'),('091001'),('091002'),('091002'),('091002'),('091002'),('091002'),('091002'),('091009'),('091009'),('091009'),('091009'),('091009'),('091011'),('091011'),('091011'),('091011'),('091011'),('091011'),('091011'),('091012'),('091012'),('091013'),('091013'),('091013'),('091013'),('091013'),('091013'),('091015'),('091015'),('091015'),('091015'),('091015'),('091015'),('091016'),('091016'),('091016'),('091016'),('091016'),('091017'),('091017'),('091018'),('091018'),('091018'),('091018'),('093003'),('093003'),('093003'),('093003'),('093003'),('093003'),('099001'),('099001'),('099001'),('099001'),('099001'),('099001'),('099001'),('100001'),('100001'),('100001'),('100001'),('106001'),('113005'),('113005'),('113005'),('113006'),('113006'),('113018'),('113019'),('113020'),('115001'),('115001'),('115001'),('115002'),('115002'),('115003'),('115004'),('115004'),('115004'),('115004'),('115005'),('115005'),('115005'),('115006'),('115006'),('115006'),('115007'),('115007'),('115007'),('115007'),('115007'),('115008'),('115008'),('115008'),('115009'),('115010'),('115010'),('115010'),('115010'),('115010'),('115011'),('115011'),('115011'),('115011'),('115012'),('115012'),('115013'),('115013'),('115013'),('115014'),('115014'),('115014'),('115014'),('115015'),('115015'),('115015'),('115016'),('115016'),('115016'),('115016'),('115017'),('115017'),('115017'),('115017'),('115017'),('115018'),('115018'),('115020'),('115020'),('115021'),('115021'),('115022'),('115022'),('115022'),('115023'),('115023'),('115023'),('115023'),('115023'),('115025'),('115025'),('115025'),('115026'),('115026'),('115027'),('115027'),('115027'),('115028'),('115028'),('115028'),('115028'),('115029'),('115029'),('115029'),('115030'),('115030'),('115030'),('115031'),('115031'),('115032'),('115032'),('115032'),('115033'),('115033'),('115033'),('115033'),('115034'),('115034'),('115034'),('115035'),('115035'),('115036'),('115036'),('115036'),('115036'),('115036'),('115039'),('115040'),('115040'),('115040'),('115041'),('115041'),('115041'),('115041'),('115041'),('115042'),('115042'),('115042'),('115042'),('115042'),('115043'),('115043'),('115043'),('115044'),('115044'),('115044'),('115044'),('115046'),('115046'),('115046'),('115047'),('115048'),('115050'),('115050'),('115050'),('115050'),('115050'),('115051'),('115051'),('115051'),('115052'),('115053'),('115053'),('115054'),('115054'),('115054'),('115055'),('115055'),('115055'),('115057'),('115059'),('115059'),('115059'),('115059'),('115060'),('115060'),('115060'),('115060'),('115060'),('115060'),('115061'),('115061'),('115061'),('115062'),('115062'),('115062'),('115062'),('115064'),('115064'),('115064'),('115065'),('115065'),('115065'),('115065'),('115066'),('115066'),('115066'),('115067'),('115067'),('115067'),('115068'),('115068'),('115068'),('115069'),('115069'),('115069'),('115069'),('115069'),('115070'),('115070'),('115070'),('115071'),('115071'),('115071'),('115072'),('115072'),('115072'),('115073'),('115073'),('115075'),('115075'),('115075'),('115076'),('115076'),('115076'),('115076'),('115076'),('115076'),('115081'),('115081'),('115081'),('115082'),('115082'),('115082'),('115085'),('115085'),('115085'),('115085'),('115085'),('115086'),('115086'),('115086'),('115087'),('115087'),('115088'),('115088'),('115088'),('115088'),('115088'),('115095'),('115095'),('115095'),('115096'),('115096'),('115097'),('115097'),('115098'),('115098'),('115099'),('115101'),('115102'),('115102'),('115102'),('115103'),('115103'),('115104'),('115104'),('115104'),('115104'),('115105'),('115105'),('115106'),('115106'),('115106'),('115106'),('115106'),('115108'),('115109'),('115111'),('115111'),('115111'),('115111'),('115112'),('115112'),('115112'),('115112'),('115112'),('115113'),('115113'),('115113'),('115114'),('115114'),('115114'),('115114'),('115114'),('115115'),('115115'),('115115'),('115115'),('115116'),('115117'),('115117'),('115117'),('115118'),('115118'),('115119'),('115119'),('115119'),('115119'),('115120'),('115121'),('115121'),('115122'),('115122'),('116001'),('116003'),('116003'),('116003'),('116003'),('116004'),('116004'),('116005'),('116005'),('116006'),('116006'),('116006'),('116007'),('116007'),('116008'),('116008'),('116009'),('116009'),('116009'),('116010'),('116010'),('116010'),('116010'),('116011'),('116011'),('116011'),('116011'),('116012'),('116012'),('123001'),('123001'),('123001'),('123001'),('123001'),('124065'),('126001'),('126001'),('126001'),('126001'),('126001'),('126001'),('126001'),('126001'),('126002'),('126002'),('126002'),('126002'),('126002'),('126002'),('126002'),('126002'),('126003'),('126003'),('126003'),('126003'),('126003'),('126003'),('126003'),('126003'),('126003'),('126004'),('126004'),('126004'),('126004'),('126004'),('126004'),('126004'),('126004'),('126004'),('126004'),('126005'),('126005'),('126005'),('126005'),('126005'),('126005'),('126005'),('126005'),('126005'),('126006'),('126006'),('126006'),('126006'),('126006'),('126006'),('126006'),('126006'),('126006'),('126007'),('126007'),('126007'),('126007'),('126007'),('126007'),('126007'),('126008'),('126008'),('126008'),('126008'),('126008'),('126008'),('126008'),('126008'),('126009'),('126009'),('126009'),('126009'),('126009'),('126009'),('126009'),('126009'),('126010'),('126010'),('126010'),('126010'),('126010'),('126010'),('126010'),('126010'),('126010'),('126011'),('126011'),('126011'),('126011'),('126011'),('126011'),('126011'),('126012'),('126012'),('126012'),('126012'),('130001'),('130001'),('130001'),('130001'),('132001'),('132001'),('132001'),('132001'),('132001'),('132002'),('132002'),('132002'),('132002'),('132002'),('132002'),('132002'),('133001'),('133001'),('133008'),('133009'),('133010'),('133011'),('133011'),('133011'),('133011'),('133011'),('133011'),('133012'),('133015'),('133015'),('133015'),('133015'),('133016'),('133018'),('133018'),('133018'),('133018'),('133018'),('133019'),('133021'),('133021'),('133022'),('133022'),('133023'),('133023'),('133024'),('133024'),('133024'),('133024'),('133024'),('133024'),('133025'),('133027'),('133027'),('133027'),('133027'),('133027'),('133028'),('133028'),('133028'),('133029'),('133029'),('133029'),('133029'),('133029'),('133029'),('133030'),('133030'),('133031'),('133031'),('133031'),('134001'),('134001'),('134001'),('135001'),('135001'),('135001'),('135001'),('135001'),('135002'),('135002'),('135002'),('135004'),('135010'),('135010'),('135010'),('135010'),('135010'),('135010'),('137010'),('137011'),('137012'),('137014'),('137015'),('137015'),('137016'),('137019'),('139001'),('140001'),('140001'),('140001'),('140001'),('140001'),('140001'),('141001'),('141001'),('141001'),('141001'),('141001'),('141002'),('141002'),('141002'),('141002'),('141002'),('141003'),('141003'),('141003'),('141003'),('141003'),('141003'),('141003'),('141003'),('141006'),('141006'),('141006'),('141006'),('141006'),('141006'),('141006'),('141006'),('141007'),('141007'),('141007'),('141007'),('141007'),('141009'),('141009'),('141009'),('141009'),('141009'),('141011'),('141011'),('141011'),('141011'),('141011'),('141011'),('141012'),('141014'),('141014'),('141014'),('141014'),('141014'),('141014'),('141014'),('141014'),('141015'),('141015'),('141015'),('141015'),('141015'),('141016'),('141016'),('141016'),('141016'),('141016'),('141016'),('141017'),('141017'),('141017'),('141017'),('141017'),('141017'),('141018'),('141018'),('141018'),('141018'),('141019'),('141019'),('141019'),('141019'),('141020'),('141020'),('141020'),('141020'),('141020'),('141020'),('141020'),('141021'),('141021'),('141021'),('141021'),('141021'),('141021'),('141022'),('141022'),('141022'),('141022'),('141022'),('141022'),('141023'),('141023'),('141023'),('141023'),('141023'),('141023'),('141023'),('141024'),('141025'),('141025'),('141025'),('141026'),('141026'),('141026'),('141026'),('141026'),('141026'),('141027'),('141027'),('141027'),('141027'),('141027'),('141028'),('141028'),('145001'),('145001'),('145001'),('145001'),('145001'),('145001'),('145001'),('145001'),('145001'),('145002'),('145002'),('145002'),('145002'),('145002'),('145002'),('145002'),('145002'),('145002'),('145003'),('145003'),('145003'),('145003'),('145003'),('145003'),('145003'),('145003'),('145003'),('145003'),('145004'),('145004'),('145004'),('145004'),('145004'),('145004'),('145004'),('145004'),('145004'),('145005'),('145005'),('145005'),('145005'),('145005'),('145005'),('145005'),('145005'),('145005'),('145006'),('145006'),('145006'),('145006'),('145006'),('145006'),('145006'),('145006'),('145006'),('145008'),('145008'),('145008'),('145008'),('145008'),('145008'),('145008'),('145008'),('145009'),('145009'),('145009'),('145009'),('145009'),('145009'),('145009'),('145011'),('145011'),('145011'),('145011'),('145011'),('145011'),('145011'),('145011'),('145012'),('145012'),('145012'),('145012'),('145012'),('145012'),('145012'),('145012'),('145013'),('145013'),('145013'),('145013'),('145013'),('145013'),('145013'),('150009'),('150013'),('150014'),('150015'),('150015'),('150015'),('150016'),('150016'),('150017'),('150017'),('150017'),('150017'),('150020'),('152001'),('152001'),('152001'),('152002'),('152003'),('152003'),('152003'),('152003'),('152004'),('152005'),('152006'),('152006'),('152006'),('152006'),('152007'),('154001'),('154002'),('154002'),('155001'),('155001'),('155002'),('155003'),('155004'),('155004'),('155006'),('159001'),('159003'),('160001'),('160001'),('160001'),('160001'),('160002'),('160002'),('161001'),('162002'),('162002'),('162003'),('162003'),('162003'),('162003'),('162003'),('162007'),('162012'),('162012'),('162012'),('163001'),('163001'),('163001'),('163011'),('163015'),('163016'),('163016'),('165001'),('165001'),('165001'),('165001'),('165002'),('165002'),('165002'),('165002'),('165003'),('165003'),('165003'),('165004'),('165004'),('165004'),('165005'),('165005'),('165005'),('165006'),('165006'),('165006'),('165006'),('165007'),('165007'),('165007'),('165007'),('165008'),('165008'),('165008'),('165008'),('165009'),('165009'),('165009'),('165009'),('165010'),('165010'),('165010'),('165011'),('165011'),('165012'),('165012'),('165012'),('165013'),('165013'),('165013'),('165014'),('165014'),('165014'),('165015'),('165015'),('165015'),('165015'),('165016'),('165016'),('165016'),('165017'),('165017'),('165017'),('165017'),('165018'),('165018'),('165018'),('165018'),('165019'),('165019'),('165019'),('165019'),('165020'),('165020'),('165020'),('165020'),('165021'),('165021'),('165021'),('165021'),('165022'),('165022'),('165022'),('165023'),('165024'),('165024'),('165024'),('165025'),('165025'),('165025'),('165026'),('165026'),('165026'),('165028'),('165029'),('165030'),('165030'),('165030'),('165031'),('165031'),('165033'),('165033'),('165034'),('165034'),('165034'),('165035'),('165035'),('165035'),('165036'),('165036'),('165036'),('168003'),('168003'),('168004'),('168005'),('168014'),('169001'),('169001'),('169001'),('169001'),('169001'),('169001'),('169001'),('169001'),('169001'),('169001'),('169002'),('169002'),('169002'),('169002'),('169002'),('169002'),('169002'),('169002'),('169002'),('169002'),('169003'),('169003'),('169003'),('169003'),('169007'),('169007'),('169007'),('169007'),('169007'),('169007'),('169007'),('169007'),('169007'),('169007'),('169008'),('169008'),('169008'),('169008'),('169008'),('169008'),('169008'),('169009'),('169009'),('169009'),('169009'),('169010'),('171006'),('171006'),('171007'),('171007'),('171008'),('171008'),('171008'),('171009'),('171009'),('171009'),('172001'),('176001'),('176001'),('176001'),('176001'),('176001'),('176001'),('176001'),('176002'),('176002'),('176002'),('176002'),('176002'),('176003'),('176003'),('176003'),('176003'),('176003'),('176003'),('177001'),('177001'),('177001'),('177001'),('177001'),('177001'),('179007'),('179007'),('179012'),('179012'),('179012'),('179012'),('179012'),('179012'),('179013'),('179013'),('179013'),('179013'),('179013'),('179013'),('179042'),('179044'),('179045'),('180001'),('180013'),('180014'),('180014'),('180015'),('180017'),('180018'),('180020'),('180020'),('180021'),('180021'),('180027'),('180030'),('180033'),('180035'),('180036'),('180037'),('180038'),('180041'),('180042'),('180045'),('180045'),('180047'),('180048'),('180049'),('180050'),('180054'),('180060'),('180066'),('180067'),('180068'),('180070'),('182001'),('184001'),('184002'),('184005'),('184005'),('184005'),('184005'),('184006'),('184006'),('184006'),('184006'),('184008'),('184008'),('184008'),('184008'),('184009'),('184009'),('184009'),('184009'),('184010'),('184010'),('184010'),('184010'),('184011'),('184011'),('184011'),('184011'),('185001'),('185001'),('185001'),('185001'),('185001'),('185001'),('185001'),('185003'),('185003'),('185003'),('185003'),('185003'),('185003'),('185003'),('187001'),('191002'),('191002'),('192002'),('194003'),('197001'),('197001'),('197001'),('197001'),('197001'),('197001'),('197001'),('197002'),('197002'),('197002'),('197002'),('197002'),('197002'),('197002'),('197003'),('197003'),('197003'),('197003'),('197003'),('197003'),('197003'),('197004'),('197004'),('197004'),('197004'),('197004'),('197004'),('197004'),('197005'),('197005'),('197005'),('197005'),('197005'),('197005'),('197006'),('197006'),('197006'),('197006'),('197006'),('198001'),('198001'),('198001'),('198001'),('198001'),('198001'),('198003'),('198003'),('198003'),('198004'),('198004'),('198004'),('198004'),('198004'),('198004'),('198005'),('198005'),('198005'),('198005'),('198005'),('198005'),('198005'),('198006'),('198006'),('198006'),('198006'),('198006'),('198006'),('198007'),('198007'),('198007'),('198007'),('198007'),('198007'),('198007'),('198008'),('198008'),('198008'),('198008'),('198008'),('198008'),('198009'),('198009'),('198009'),('198009'),('198009'),('198009'),('198009'),('198010'),('198010'),('198010'),('198010'),('198010'),('198010'),('198011'),('198012'),('198012'),('198012'),('198012'),('198015'),('198015'),('198016'),('198016'),('198016'),('198016'),('198016'),('198016'),('198017'),('198017'),('198017'),('198017'),('198017'),('198017'),('201001'),('201001'),('201001'),('201001'),('201001'),('201002'),('202001'),('202001'),('203001'),('203001'),('203001'),('203001'),('203001'),('203001'),('203001'),('203002'),('203002'),('203002'),('203002'),('203003'),('203003'),('203003'),('203003'),('203003'),('203017'),('203017'),('203017'),('203017'),('203017'),('203017'),('203017'),('203017'),('203017'),('203018'),('203018'),('203018'),('203018'),('203018'),('203019'),('203019'),('203019'),('203019'),('203019'),('204001'),('204002'),('205001'),('205001'),('205001'),('205001'),('205001'),('205001'),('205001'),('208001'),('208001'),('208002'),('208002'),('208002'),('208003'),('208003'),('208003'),('208004'),('208004'),('208004'),('208004'),('208004'),('208004'),('208004'),('208005'),('208005'),('208005'),('208005'),('208005'),('209001'),('209001'),('209001'),('209001'),('209001'),('209002'),('209002'),('209002'),('209002'),('209002'),('209003'),('209003'),('209003'),('209003'),('209003'),('210001'),('210001'),('210001'),('210001'),('210001'),('210004'),('210004'),('210004'),('210004'),('210004'),('210004'),('210009'),('210010'),('212001'),('212001'),('212002'),('212002'),('212002'),('212002'),('212003'),('212003'),('212003'),('212004'),('212004'),('212004'),('212005'),('212005'),('212005'),('212005'),('212005'),('212006'),('212006'),('212006'),('212007'),('212007'),('212008'),('212008'),('212008'),('212008'),('212009'),('212009'),('212009'),('212009'),('212010'),('212010'),('212010'),('212010'),('212011'),('212011'),('212012'),('212012'),('212013'),('212013'),('212013'),('218001'),('218004'),('218009'),('218011'),('218011'),('218015'),('218020'),('218021'),('218021'),('218022'),('218022'),('218022'),('218023'),('218024'),('218025'),('218026'),('218026'),('218027'),('218028'),('218029'),('218029'),('218029'),('218030'),('218031'),('221001'),('221001'),('221001'),('221001'),('221001'),('221001'),('221002'),('221002'),('221002'),('221002'),('221002'),('221002'),('221003'),('221003'),('221003'),('221003'),('221003'),('221003'),('221004'),('221004'),('221004'),('221004'),('221004'),('221004'),('221005'),('221005'),('221005'),('221005'),('221005'),('221006'),('221006'),('221006'),('221006'),('221006'),('221007'),('221007'),('221007'),('221007'),('221007'),('221007'),('221008'),('221008'),('221008'),('221008'),('221008'),('221008'),('221009'),('221009'),('221009'),('221009'),('221009'),('221009'),('221010'),('221010'),('221010'),('221010'),('221011'),('221011'),('221011'),('221011'),('221012'),('221012'),('221012'),('221012'),('221012'),('221012'),('221013'),('221013'),('221013'),('221013'),('221013'),('221013'),('223003'),('223003'),('224001'),('224001'),('224002'),('224002'),('224003'),('224007'),('224008'),('225001'),('225002'),('225002'),('225002'),('225003'),('225003'),('225003'),('225003'),('225004'),('225004'),('225004'),('225005'),('225005'),('225005'),('225005'),('225005'),('225005'),('225006'),('225006'),('225006'),('225007'),('225007'),('225007'),('225008'),('225008'),('225008'),('225008'),('225008'),('225009'),('225009'),('225009'),('225010'),('225010'),('225010'),('225011'),('225011'),('225011'),('225011'),('225011'),('225012'),('225012'),('225012'),('225012'),('225012'),('225012'),('225013'),('225013'),('226001'),('226002'),('226003'),('226003'),('226005'),('226005'),('226006'),('226007'),('226007'),('226007'),('226007'),('227011'),('227015'),('227015'),('227041'),('227045'),('227052'),('227056'),('227063'),('227064'),('227066'),('227067'),('227069'),('227071'),('227073'),('227085'),('227116'),('227119'),('227131'),('227133'),('227147'),('229005'),('229005'),('229005'),('233003'),('233004'),('235001'),('235001'),('235002'),('235003'),('235003'),('235003'),('235004'),('235005'),('235005'),('235005'),('235005'),('235005'),('235005'),('235005'),('236001'),('236001'),('236001'),('236001'),('236002'),('236003'),('236003'),('236003'),('236003'),('236003'),('236003'),('238002'),('238002'),('238002'),('238002'),('238002'),('238002'),('238003'),('238003'),('238003'),('238003'),('238003'),('238003'),('238004'),('238004'),('238004'),('238004'),('238004'),('238005'),('238005'),('238005'),('238007'),('238007'),('238007'),('238007'),('238007'),('238007'),('238007'),('238008'),('238008'),('238008'),('238008'),('238008'),('238008'),('238008'),('334005'),('334006'),('337001'),('337001'),('337001'),('337002'),('337002'),('337003'),('337003'),('337003'),('337004'),('343001'),('343001'),('344001'),('344002'),('344003'),('344004'),('344005'),('344005'),('345001'),('345001'),('348001'),('348004'),('348005'),('348005'),('349001'),('349001'),('349002'),('349002'),('349002'),('350001'),('353002'),('353002'),('353002'),('353003'),('355001'),('355002'),('355005'),('355006'),('355006'),('356001'),('358001'),('358001'),('358001'),('359001'),('359001'),('359002'),('359002'),('359002'),('359002'),('360001'),('360001'),('360002'),('360002'),('360003'),('360003'),('360004'),('360004'),('360005'),('360005'),('360005'),('366001'),('366002'),('366002'),('366003'),('366004'),('369001'),('369001'),('373001'),('373002'),('373002'),('373003'),('373003'),('373005'),('373007'),('373008'),('373009'),('373009'),('373010'),('373010'),('373010'),('373011'),('373011'),('373011'),('373011'),('373012'),('373012'),('373012'),('373013'),('373013'),('373014'),('373014'),('373015'),('373015'),('373015'),('373015'),('373017'),('373017'),('373017'),('373017'),('373018'),('373021'),('374002'),('374004'),('374006'),('374007'),('374008'),('374009'),('374010'),('374011'),('374012'),('374015'),('374016'),('382001'),('382002'),('382002'),('384001'),('386001'),('386001'),('386001'),('386001'),('386001'),('386001'),('386001'),('386002'),('386002'),('386002'),('386002'),('386002'),('386002'),('386002'),('386003'),('386003'),('386003'),('386003'),('386003'),('386003'),('386003'),('386003'),('386003'),('386004'),('386004'),('386004'),('386004'),('386004'),('386004'),('386004'),('386004'),('386005'),('386005'),('386005'),('386005'),('386005'),('386005'),('386005'),('386006'),('386006'),('386006'),('386006'),('386006'),('386006'),('386007'),('386007'),('386007'),('386007'),('386007'),('386007'),('386007'),('386007'),('386007'),('386008'),('386008'),('386008'),('386008'),('386008'),('386008'),('386008'),('386008'),('386009'),('386009'),('386009'),('386010'),('386010'),('386010'),('386010'),('386010'),('386010'),('386010'),('386010'),('386011'),('386011'),('386011'),('386011'),('386011'),('386011'),('386011'),('386011'),('386011'),('386012'),('386012'),('386012'),('386012'),('386012'),('386012'),('386012'),('386012'),('386012'),('386013'),('386013'),('386013'),('386013'),('386013'),('386013'),('386013'),('386014'),('386014'),('386014'),('386014'),('389001'),('389002'),('389002'),('389003'),('389003'),('389003'),('389003'),('389004'),('389004'),('389004'),('389004'),('392001'),('393001'),('393002'),('393002'),('393003'),('393004'),('395001'),('395001'),('397001'),('397001'),('397001'),('397002'),('399001'),('399001'),('399001'),('399001'),('399001'),('399001'),('399001'),('399002'),('399002'),('399002'),('399002'),('399002'),('399002'),('399002'),('399003'),('400001'),('400001'),('400001'),('400001'),('400002'),('403002'),('504001'),('504001'),('504002'),('504002'),('504002'),('504004'),('504004'),('504005'),('504006'),('504007'),('504007'),('504007'),('504008'),('504008'),('504009'),('504009'),('504009'),('504009'),('504009'),('504010'),('504011'),('504011'),('504012'),('504012'),('504014'),('504014'),('504014'),('504014'),('504014'),('504014'),('504014'),('504014'),('504017'),('504017'),('504021'),('504021'),('504021'),('504021'),('504021'),('504021'),('504021'),('504022'),('504023'),('504023'),('504024'),('504024'),('504025'),('504025'),('506001'),('506001'),('506001'),('506001'),('506001'),('506001'),('506002'),('506002'),('506002'),('506002'),('506002'),('511001'),('511001'),('511001'),('511001'),('511001'),('511001'),('511001'),('511002'),('511002'),('511002'),('511002'),('511002'),('511002'),('511002'),('511003'),('511003'),('511003'),('511003'),('511003'),('511003'),('511004'),('511004'),('511004'),('511004'),('511004'),('511004'),('511004'),('511005'),('511005'),('511005'),('511005'),('511005'),('511005'),('511005'),('511006'),('511006'),('511006'),('511006'),('511006'),('511006'),('511006'),('511007'),('511007'),('511007'),('511007'),('511007'),('511008'),('511008'),('511008'),('511008'),('511008'),('511008'),('511009'),('511009'),('511009'),('511009'),('511009'),('511009'),('511010'),('511010'),('511010'),('511010'),('511010'),('511010'),('511011'),('511011'),('511011'),('511011'),('511011'),('511011'),('511012'),('511012'),('511012'),('511012'),('511012'),('511012'),('511012'),('511013'),('511013'),('511013'),('511013'),('511013'),('511013'),('511013'),('511014'),('511014'),('511014'),('511014'),('511014'),('511017'),('511018'),('511020'),('511021'),('511022'),('511024'),('511028'),('511029'),('511029'),('511029'),('511029'),('511029'),('511029'),('513001'),('513001'),('513001'),('513001'),('513001'),('513001'),('513001'),('513001'),('513002'),('513002'),('513002'),('513002'),('513002'),('513002'),('513003'),('513003'),('513003'),('513003'),('513003'),('513003'),('513003'),('513003'),('513004'),('513004'),('513004'),('515001'),('515001'),('515001'),('515001'),('515001'),('515002'),('515002'),('515003'),('515003'),('515007'),('515007'),('515008'),('515011'),('515011'),('515011'),('515011'),('515011'),('515011'),('515012'),('515012'),('515012'),('515012'),('515013'),('515013'),('515013'),('515013'),('515013'),('515014'),('515014'),('515014'),('515014'),('515014'),('515015'),('515015'),('515015'),('515015'),('515015'),('518001'),('518002'),('521001'),('521002'),('521002'),('521002'),('521003'),('521003'),('521003'),('521003'),('521004'),('521004'),('521004'),('521004'),('521005'),('521005'),('521005'),('521005'),('521006'),('521006'),('521006'),('521009'),('521010'),('521010'),('521010'),('521010'),('521011'),('521011'),('521011'),('521011'),('521012'),('521013'),('521013'),('521015'),('521016'),('521016'),('523001'),('523001'),('523001'),('523001'),('523001'),('523001'),('523001'),('523002'),('523002'),('523002'),('523002'),('523002'),('523002'),('523003'),('523003'),('523003'),('523003'),('523003'),('523003'),('523003'),('523004'),('523004'),('523004'),('523004'),('523004'),('523004'),('523005'),('523005'),('523005'),('523005'),('523005'),('523005'),('523005'),('523005'),('523006'),('523006'),('523006'),('523006'),('523006'),('523006'),('523006'),('523007'),('523007'),('523007'),('523007'),('523007'),('523007'),('523007'),('524001'),('700001'),('701001'),('701002'),('701003'),('702001'),('702002'),('702004'),('702005'),('704001'),('704004'),('705001'),('706001'),('706002'),('707001'),('707002'),('707003'),('708001'),('710001'),('710002'),('711001'),('711002'),('712001'),('714001'),('714002'),('715001'),('719001'),('719002'),('991002'),('991002'),('991002'),('991003'),('991003'),('991003'),('991003'),('991003'),('991003'),('991003'),('991004'),('991004'),('991004'),('991005'),('991005'),('991005'),('991006'),('991007'),('995001'),('995001'),('995001'),('995001'),('995001'),('995001'),('995001'),('995001'),('995001'),('995001'),('995001'),('996001'),('996001'),('996001'),('996001'),('996001'),('996001'),('996001'),('996001'),('996002'),('996002'),('996003'),('996003'),('996003'),('996003'),('996003'),('998001'),('998001'),('998001'),('998001'),('998001'),('998001'),('998001'),('998001'),('998001'),('998001'),('998002'),('998002'),('998002'),('998002'),('998002'),('998002'),('998002'),('998002'),('998002'),('998002'),('998003'),('998003'),('998003'),('998003'),('998003'),('998003'),('998003'),('998003'),('998004'),('998004'),('998005'),('998005'),('998006'),('998007'),('999001'),('999001'),('999001'),('999001'),('999001'),('999001'),('999001'),('999001'),('999001'),('999001'),('999001'),('999002'),('999002'),('011017'),('011017'),('011017'),('011017'),('011017'),('011017'),('011017'),('011018'),('011018'),('011018'),('011018'),('034001'),('034001'),('034002'),('034002'),('071010'),('071010'),('071010'),('519001'),('126013'),('126013'),('126013'),('126013'),('126013'),('184012'),('184012'),('184012'),('404001'),('405002'),('405002'),('405001'),('405003'),('405006'),('240011'),('240011'),('240011'),('240011'),('240011'),('240011'),('240010'),('240010'),('240010'),('240009'),('240009'),('240009'),('240009'),('240008'),('240008'),('240008'),('240007'),('240007'),('240007'),('240007'),('240007'),('240007'),('240005'),('240005'),('240005'),('240005'),('240005'),('240004'),('240004'),('240004'),('240004'),('240004'),('240003'),('240003'),('240003'),('240003'),('240002'),('240002'),('240002'),('240002'),('240002'),('240002'),('240002'),('240001'),('240001'),('240001'),('240001'),('240001'),('240012'),('240012'),('240012'),('240012'),('240012'),('240013'),('240014'),('240015'),('240015'),('240015'),('240015'),('240015'),('240015'),('240015'),('240015'),('240016'),('240016'),('240016'),('240016'),('240016'),('240016'),('240017'),('240017'),('240017'),('357001'),('357001'),('235006'),('235006'),('235007'),('235007'),('235007'),('235007'),('235007'),('056023'),('056023'),('056023'),('056023'),('056023'),('046015'),('019005'),('019005'),('126014'),('126014'),('126014'),('126014'),('126014'),('126014'),('241003'),('241003'),('241003'),('241003'),('241003'),('241003'),('241002'),('241002'),('241002'),('241002'),('241002'),('241002'),('241001'),('241001'),('241001'),('241001'),('241001'),('240020'),('240020'),('240020'),('240020'),('240020'),('240020'),('240019'),('240019'),('240019'),('242001'),('242002'),('242004'),('242005'),('242006'),('089002'),('089002'),('089002'),('089002'),('089002'),('089002'),('406001'),('406002'),('406003'),('406004'),('406004'),('243001'),('243005'),('243006'),('243007'),('243008'),('408001'),('408001'),('408001'),('408001'),('408001'),('366005'),('366005'),('016035'),('016035'),('016035'),('016035'),('077010'),('996004'),('996004'),('996004'),('996004'),('996004'),('996004'),('996004'),('996004'),('025064'),('025064'),('025064'),('025064'),('011019'),('011019'),('011019'),('011019'),('011019'),('115123'),('115123'),('504026'),('039007'),('039009'),('039008'),('039008'),('039010'),('039010'),('039011'),('039012'),('180072'),('240021'),('240021'),('240021'),('240021'),('240021'),('240021'),('240021'),('240023'),('240023'),('240023'),('240023'),('405008'),('405008'),('525002'),('410002'),('410002'),('410004'),('410005'),('410005'),('410006'),('410007'),('410007'),('410008'),('410009'),('410010'),('410011'),('410011'),('410012'),('410012'),('410013'),('410013'),('410014'),('410014'),('410016'),('410016'),('344006'),('240031'),('240031'),('240031'),('240031'),('240030'),('240030'),('240030'),('240030'),('240029'),('240029'),('240029'),('240029'),('240028'),('240028'),('240028'),('240028'),('240027'),('240027'),('240026'),('240026'),('240026'),('240025'),('240025'),('240025'),('240025'),('240024'),('240024'),('240034'),('240034'),('240034'),('240033'),('240033'),('240033'),('240032'),('240032'),('240032'),('240032'),('411001'),('411002'),('203020'),('069025'),('069025'),('069025'),('069025'),('069025'),('069025'),('244001'),('244001'),('244001'),('244001'),('244001'),('244001'),('244001'),('244001'),('244001'),('244001'),('244001'),('244002'),('244002'),('244002'),('244002'),('244002'),('244002'),('244002'),('244002'),('244002'),('244002'),('244002'),('244009'),('244009'),('244009'),('244009'),('244009'),('244009'),('244009'),('244009'),('244009'),('244009'),('244009'),('244008'),('244008'),('244008'),('244008'),('244008'),('244008'),('244008'),('244008'),('244008'),('244008'),('244008'),('244007'),('244007'),('244007'),('244007'),('244007'),('244007'),('244007'),('244007'),('244007'),('244007'),('244007'),('244006'),('244006'),('244006'),('244006'),('244006'),('244006'),('244006'),('244006'),('244006'),('244006'),('244006'),('244004'),('244004'),('244004'),('244004'),('244004'),('244004'),('244004'),('244004'),('244004'),('244004'),('244004'),('244003'),('244003'),('244003'),('244003'),('244003'),('244003'),('244003'),('244003'),('244003'),('244003'),('244003'),('244014'),('244014'),('244014'),('244014'),('244014'),('244014'),('244014'),('244014'),('244013'),('244013'),('244013'),('244013'),('244013'),('244013'),('244013'),('244013'),('244012'),('244012'),('244012'),('244012'),('244012'),('244012'),('244012'),('244012'),('244011'),('244011'),('244011'),('244011'),('244011'),('244011'),('244011'),('244011'),('244016'),('244016'),('244016'),('244016'),('244016'),('244016'),('244016'),('244016'),('244016'),('244016'),('244016'),('244017'),('244017'),('244017'),('244017'),('244017'),('244017'),('244017'),('244017'),('244017'),('240040'),('240037'),('405009'),('405009'),('405009'),('405010'),('405010'),('240043'),('240043'),('504028'),('504040'),('800001'),('410019'),('410019'),('410020'),('410020'),('410020'),('410021'),('410021'),('244018'),('244018'),('244018'),('244018'),('244018'),('244018'),('244018'),('244018'),('244018'),('244018'),('244018'),('244019'),('244019'),('244019'),('244019'),('244019'),('244019'),('244019'),('244019'),('244019'),('244019'),('244019'),('244020'),('244020'),('244020'),('244020'),('244020'),('244020'),('244020'),('244020'),('413001'),('344007'),('082045'),('082045'),('082045'),('082045'),('082045'),('010031'),('010031'),('010031'),('010031'),('010032'),('010032'),('010032'),('010032'),('010033'),('010033'),('010033'),('010033'),('010033'),('010034'),('010034'),('010034'),('010034'),('010035'),('010035'),('010035'),('010035'),('504044'),('515016'),('515016'),('515016'),('515016'),('801002'),('801003'),('801004'),('801005'),('802001'),('801001'),('414001'),('141029'),('803001'),('803002'),('803004'),('803005'),('803006'),('803007'),('803008'),('803009'),('803013'),('803014'),('803015'),('803016'),('803017'),('410022'),('410023'),('410023'),('803019'),('415002'),('415001'),('244021'),('244021'),('244021'),('244021'),('244021'),('244021'),('244021'),('011020'),('011020'),('011020'),('011020'),('011023'),('011023'),('011023'),('011023'),('011022'),('011022'),('011022'),('011022'),('011022'),('011022'),('011021'),('011021'),('011021'),('011021'),('025065'),('025065'),('025065'),('025065'),('165037'),('165037'),('165038'),('165038'),('165038'),('165039'),('416001'),('416001'),('416001'),('416001'),('416001'),('416002'),('416003'),('417001'),('418001'),('504045'),('504045'),('504045'),('803022'),('240022'),('240022'),('240022'),('240022'),('420001'),('420001'),('420001'),('420001'),('804010'),('804005'),('804002'),('804018'),('804013'),('511019'),('511016'),('511015'),('511032'),('511031'),('511030'),('511027'),('511026'),('511025'),('511033'),('511023'),('133034'),('133034'),('133034'),('133033'),('169011'),('169011'),('169011'),('169011'),('169011'),('344008'),('244022'),('244022'),('244022'),('244022'),('244022'),('244022'),('244022'),('244026'),('244026'),('244026'),('244026'),('244026'),('244026'),('244025'),('244025'),('244025'),('244025'),('244025'),('244025'),('244025'),('244025'),('244030'),('244030'),('244030'),('244030'),('244030'),('244030'),('244030'),('244030'),('244023'),('244023'),('244023'),('244023'),('244023'),('244023'),('244024'),('244024'),('244024'),('244024'),('244024'),('244024'),('244024'),('244024'),('244027'),('244027'),('244027'),('244027'),('244027'),('244027'),('244027'),('244027'),('244028'),('244028'),('244028'),('244028'),('244028'),('244028'),('244028'),('244028'),('244029'),('244029'),('244029'),('244029'),('244029'),('244029'),('244029'),('244029'),('244031'),('244031'),('244031'),('244031'),('244031'),('244031'),('244031'),('244031'),('082046'),('082046'),('082046'),('082046'),('082047'),('082047'),('082048'),('082048'),('126015'),('126015'),('126016'),('126016'),('126016'),('126016'),('126016'),('416005'),('421001'),('421001'),('421002'),('016037'),('016037'),('016037'),('016037'),('016036'),('016036'),('016036'),('016036'),('115124'),('115124'),('115126'),('240049'),('240049'),('240048'),('240048'),('240047'),('240047'),('240046'),('240046'),('240045'),('240044'),('244032'),('244033'),('422002'),('422004'),('422004'),('422004'),('422005'),('422005'),('184013'),('184013'),('184013'),('805001'),('805002'),('805003'),('805004'),('805005'),('056024'),('056024'),('056024'),('423001'),('344010'),('235009'),('235009'),('235009'),('235009'),('212014'),('212014'),('056025'),('056025'),('056025'),('056026'),('056026'),('056026'),('056026'),('056026'),('056026'),('244034'),('244034'),('244034'),('244034'),('244034'),('244034'),('244035'),('244035'),('244035'),('244035'),('244035'),('244035'),('244035'),('244036'),('244036'),('244036'),('244036'),('244036'),('244036'),('244036'),('244037'),('244037'),('244037'),('244037'),('244037'),('244037'),('244037'),('244038'),('244038'),('244038'),('244038'),('244038'),('244038'),('244038'),('244039'),('244039'),('244039'),('244039'),('244039'),('244039'),('244039'),('203015'),('245002'),('245002'),('245001'),('245001'),('056029'),('056030'),('056032'),('424001'),('056034'),('056034'),('056034'),('056034'),('056033'),('056033'),('056033'),('805006'),('805007'),('805008'),('805009'),('805010'),('422008'),('422008'),('422007'),('422007'),('422006'),('422006'),('422010'),('422009'),('422009'),('422011'),('422011'),('209004'),('209004'),('150022'),('100002'),('056035'),('056035'),('056035'),('023036'),('023036'),('185005'),('246001'),('246001'),('247001'),('247001'),('247001'),('247001'),('247001'),('247001'),('247001'),('247002'),('247002'),('425001'),('416006'),('416006'),('165042'),('165041'),('165040'),('165043'),('010040'),('010039'),('010038'),('010036'),('248001'),('248002'),('248003'),('248004'),('248005'),('249001'),('249003'),('249004'),('249005'),('250007'),('250001'),('250002'),('250003'),('250004'),('250005'),('250006'),('250008'),('250009'),('250010'),('250011'),('250012'),('250013'),('251001'),('251002'),('806001'),('806002'),('235010'),('243009'),('249007'),('249008'),('249009'),('011024'),('011025'),('429001'),('429001'),('429002'),('429002'),('429003'),('429003');
+select field from t1 group by field;
field
001001
001010
@@ -1614,3 +1621,4 @@ field
429001
429002
429003
+drop table t1;
diff --git a/mysql-test/r/type_float.result b/mysql-test/r/type_float.result
index 30a2f884557..4dbfa1b9f66 100644
--- a/mysql-test/r/type_float.result
+++ b/mysql-test/r/type_float.result
@@ -1,12 +1,21 @@
+SELECT 10,10.0,10.,.1e+2,100.0e-1;
10 10.0 10. .1e+2 100.0e-1
10 10.0 10 10 10
+SELECT 6e-05, -6e-05, --6e-05, -6e-05+1.000000;
6e-05 -6e-05 --6e-05 -6e-05+1.000000
6e-05 -6e-05 6e-05 0.99994
+SELECT 1e1,1.e1,1.0e1,1e+1,1.e+1,1.0e+1,1e-1,1.e-1,1.0e-1;
1e1 1.e1 1.0e1 1e+1 1.e+1 1.0e+1 1e-1 1.e-1 1.0e-1
10 10 10 10 10 10 0.1 0.1 0.1
+drop table if exists t1;
+create table t1 (f1 float(24),f2 float(52));
+show full columns from t1;
Field Type Null Key Default Extra Privileges
f1 float YES NULL select,insert,update,references
f2 double YES NULL select,insert,update,references
+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);
+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
10 10
100000 100000
@@ -23,28 +32,43 @@ f1 f2
1e-20 1e-20
0 1e-50
0 1e-150
+drop table t1;
+create table t1 (datum double);
+insert into t1 values (0.5),(1.0),(1.5),(2.0),(2.5);
+select * from t1;
datum
0.5
1
1.5
2
2.5
+select * from t1 where datum < 1.5;
datum
0.5
1
+select * from t1 where datum > 1.5;
datum
2
2.5
+select * from t1 where datum = 1.5;
datum
1.5
+drop table t1;
+create table t1 (a decimal(7,3) not null, key (a));
+insert into t1 values ("0"),("-0.00"),("-0.01"),("-0.002"),("1");
+select a from t1 order by a;
a
-0.010
-0.002
-0.000
0.000
1.000
+select min(a) from t1;
min(a)
-0.010
+drop table t1;
+create table t1 (f float, f2 float(24), f3 float(6,2), d double, d2 float(53), d3 double(10,3), de decimal, de2 decimal(6), de3 decimal(5,2), n numeric, n2 numeric(8), n3 numeric(5,6));
+show full columns from t1;
Field Type Null Key Default Extra Privileges
f float YES NULL select,insert,update,references
f2 float YES NULL select,insert,update,references
@@ -58,11 +82,20 @@ de3 decimal(5,2) YES NULL select,insert,update,references
n decimal(10,0) YES NULL select,insert,update,references
n2 decimal(8,0) YES NULL select,insert,update,references
n3 decimal(8,6) YES NULL select,insert,update,references
+drop table t1;
+create table t1 (a decimal(7,3) not null, key (a));
+insert into t1 values ("0"),("-0.00"),("-0.01"),("-0.002"),("1");
+select a from t1 order by a;
a
-0.010
-0.002
-0.000
0.000
1.000
+select min(a) from t1;
min(a)
-0.010
+drop table t1;
+create table t1 (f float(54));
+Incorrect column specifier for column 'f'
+drop table if exists t1;
diff --git a/mysql-test/r/type_ranges.result b/mysql-test/r/type_ranges.result
index abb8ef8cb09..fc7cc5255cf 100644
--- a/mysql-test/r/type_ranges.result
+++ b/mysql-test/r/type_ranges.result
@@ -1,3 +1,43 @@
+drop table if exists t1,t2,t3;
+CREATE TABLE t1 (
+auto int(5) unsigned DEFAULT 0 NOT NULL auto_increment,
+string char(10) default "hello",
+tiny tinyint(4) DEFAULT '0' NOT NULL ,
+short smallint(6) DEFAULT '1' NOT NULL ,
+medium mediumint(8) DEFAULT '0' NOT NULL,
+long_int int(11) DEFAULT '0' NOT NULL,
+longlong bigint(13) DEFAULT '0' NOT NULL,
+real_float float(13,1) DEFAULT 0.0 NOT NULL,
+real_double double(16,4),
+utiny tinyint(3) unsigned DEFAULT '0' NOT NULL,
+ushort smallint(5) unsigned zerofill DEFAULT '00000' NOT NULL,
+umedium mediumint(8) unsigned DEFAULT '0' NOT NULL,
+ulong int(11) unsigned DEFAULT '0' NOT NULL,
+ulonglong bigint(13) unsigned DEFAULT '0' NOT NULL,
+time_stamp timestamp,
+date_field date,
+time_field time,
+date_time datetime,
+blob_col blob,
+tinyblob_col tinyblob,
+mediumblob_col mediumblob not null,
+longblob_col longblob not null,
+options enum('one','two','tree') not null,
+flags set('one','two','tree') not null,
+PRIMARY KEY (auto),
+KEY (utiny),
+KEY (tiny),
+KEY (short),
+KEY any_name (medium),
+KEY (longlong),
+KEY (real_float),
+KEY (ushort),
+KEY (umedium),
+KEY (ulong),
+KEY (ulonglong,ulong),
+KEY (options,flags)
+);
+show full fields from t1;
Field Type Null Key Default Extra Privileges
auto int(5) unsigned PRI NULL auto_increment select,insert,update,references
string varchar(10) YES hello select,insert,update,references
@@ -23,21 +63,34 @@ mediumblob_col mediumblob select,insert,update,references
longblob_col longblob select,insert,update,references
options enum('one','two','tree') MUL one select,insert,update,references
flags set('one','two','tree') select,insert,update,references
-Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Comment
-t1 0 PRIMARY 1 auto A 0 NULL NULL
-t1 1 utiny 1 utiny A NULL NULL NULL
-t1 1 tiny 1 tiny A NULL NULL NULL
-t1 1 short 1 short A NULL NULL NULL
-t1 1 any_name 1 medium A NULL NULL NULL
-t1 1 longlong 1 longlong A NULL NULL NULL
-t1 1 real_float 1 real_float A NULL NULL NULL
-t1 1 ushort 1 ushort A NULL NULL NULL
-t1 1 umedium 1 umedium A NULL NULL NULL
-t1 1 ulong 1 ulong A NULL NULL NULL
-t1 1 ulonglong 1 ulonglong A NULL NULL NULL
-t1 1 ulonglong 2 ulong A NULL NULL NULL
-t1 1 options 1 options A NULL NULL NULL
-t1 1 options 2 flags A NULL NULL NULL
+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
+t1 1 utiny 1 utiny A NULL NULL NULL BTREE
+t1 1 tiny 1 tiny A NULL NULL NULL BTREE
+t1 1 short 1 short A NULL NULL NULL BTREE
+t1 1 any_name 1 medium A NULL NULL NULL BTREE
+t1 1 longlong 1 longlong A NULL NULL NULL BTREE
+t1 1 real_float 1 real_float A NULL NULL NULL BTREE
+t1 1 ushort 1 ushort A NULL NULL NULL BTREE
+t1 1 umedium 1 umedium A NULL NULL NULL BTREE
+t1 1 ulong 1 ulong A NULL NULL NULL BTREE
+t1 1 ulonglong 1 ulonglong A NULL NULL NULL BTREE
+t1 1 ulonglong 2 ulong A NULL NULL NULL BTREE
+t1 1 options 1 options A NULL NULL NULL BTREE
+t1 1 options 2 flags A NULL NULL NULL BTREE
+CREATE UNIQUE INDEX test on t1 ( auto ) ;
+CREATE INDEX test2 on t1 ( ulonglong,ulong) ;
+CREATE INDEX test3 on t1 ( medium ) ;
+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','19970303 101010','','','','3',3,3);
+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);
+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");
+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);
+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
@@ -46,6 +99,27 @@ auto string tiny short medium long_int longlong real_float real_double utiny ush
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
16 hello 1 1 0 0 0 0.0 NULL 0 00000 0 0 0 0 NULL NULL NULL NULL NULL
+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 short drop default,
+DROP INDEX utiny,
+DROP INDEX ushort,
+DROP PRIMARY KEY,
+DROP FOREIGN KEY any_name,
+ADD INDEX (auto);
+LOCK TABLES t1 WRITE;
+ALTER TABLE t1
+RENAME as t2,
+DROP longblob_col;
+UNLOCK TABLES;
+ALTER TABLE t2 rename as t3;
+LOCK TABLES t3 WRITE ;
+ALTER TABLE t3 rename as t1;
+UNLOCK TABLES;
+select auto,new_field,new_blob_col,date_field from t1 ;
auto new_field new_blob_col date_field
10 new 1 0000-00-00
11 new NULL NULL
@@ -54,6 +128,15 @@ auto new_field new_blob_col date_field
14 new -4294967295 0000-00-00
15 new 4294967295 0000-00-00
16 new NULL NULL
+CREATE TABLE t2 (
+auto int(5) unsigned NOT NULL DEFAULT 0 auto_increment,
+string char(20),
+mediumblob_col mediumblob not null,
+new_field char(2),
+PRIMARY KEY (auto)
+);
+INSERT INTO t2 (string,mediumblob_col,new_field) SELECT string,mediumblob_col,new_field from t1 where auto > 10;
+select * from t2;
auto string mediumblob_col new_field
1 2 2 ne
2 0.33 ne
@@ -61,21 +144,30 @@ auto string mediumblob_col new_field
4 -429496729 -4294967295 ne
5 4294967295 4294967295 ne
6 hello ne
+select distinct flags from t1;
flags
one,two,tree
one
one,two
+select flags from t1 where find_in_set("two",flags)>0;
flags
one,two,tree
one,two,tree
one,two
one,two
+select flags from t1 where find_in_set("unknown",flags)>0;
flags
+select options,flags from t1 where options="ONE" and flags="ONE";
options flags
one one
+select options,flags from t1 where options="one" and flags="one";
options flags
one one
+drop table t2;
+create table t2 select * from t1;
+update t2 set string="changed" where auto=16;
+show full columns from t1;
Field Type Null Key Default Extra Privileges
auto int(5) unsigned MUL NULL auto_increment select,insert,update,references
string varchar(10) YES new defaul select,insert,update,references
@@ -101,6 +193,7 @@ mediumblob_col mediumblob select,insert,update,references
options enum('one','two','tree') MUL one select,insert,update,references
flags set('one','two','tree') select,insert,update,references
new_field varchar(10) new select,insert,update,references
+show full columns from t2;
Field Type Null Key Default Extra Privileges
auto int(5) unsigned 0 select,insert,update,references
string varchar(10) YES new defaul select,insert,update,references
@@ -126,16 +219,22 @@ mediumblob_col mediumblob select,insert,update,references
options enum('one','two','tree') one select,insert,update,references
flags set('one','two','tree') select,insert,update,references
new_field varchar(10) new select,insert,update,references
+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
+select t1.auto,t2.auto from t1,t2 where t1.auto=t2.auto and not (t1.string<=>t2.string and t1.tiny<=>t2.tiny and t1.short<=>t2.short and t1.medium<=>t2.medium and t1.long_int<=>t2.long_int and t1.longlong<=>t2.longlong and t1.real_float<=>t2.real_float and t1.real_double<=>t2.real_double and t1.utiny<=>t2.utiny and t1.ushort<=>t2.ushort and t1.umedium<=>t2.umedium and t1.ulong<=>t2.ulong and t1.ulonglong<=>t2.ulonglong and t1.time_stamp<=>t2.time_stamp and t1.date_field<=>t2.date_field and t1.time_field<=>t2.time_field and t1.date_time<=>t2.date_time and t1.new_blob_col<=>t2.new_blob_col and t1.tinyblob_col<=>t2.tinyblob_col and t1.mediumblob_col<=>t2.mediumblob_col and t1.options<=>t2.options and t1.flags<=>t2.flags and t1.new_field<=>t2.new_field);
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;
+show full columns from t2;
Field Type Null Key Default Extra Privileges
-auto bigint(17) PRI 0 select,insert,update,references
+auto bigint(17) unsigned PRI 0 select,insert,update,references
t1 bigint(1) 0 select,insert,update,references
t2 char(1) select,insert,update,references
t3 mediumtext select,insert,update,references
t4 mediumblob select,insert,update,references
+select * from t2;
auto t1 t2 t3 t4
11 1 a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
12 1 a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
@@ -144,16 +243,39 @@ auto t1 t2 t3 t4
15 1 a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
16 1 a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
17 1 a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+drop table t1,t2;
+create table t1 (c int);
+insert into t1 values(1),(2);
+create table t2 select * from t1;
+create table t3 select * from t1, t2;
+Duplicate column name 'c'
+create table t3 select t1.c AS c1, t2.c AS c2,1 as "const" from t1, t2;
+show full columns from t3;
Field Type Null Key Default Extra Privileges
c1 int(11) YES NULL select,insert,update,references
c2 int(11) YES NULL select,insert,update,references
const bigint(1) 0 select,insert,update,references
+drop table t1,t2,t3;
+create table t1 ( myfield INT NOT NULL, UNIQUE INDEX (myfield), unique (myfield), index(myfield));
+drop table t1;
+create table t1 ( id integer unsigned not null primary key );
+create table t2 ( id integer unsigned not null primary key );
+insert into t1 values (1), (2);
+insert into t2 values (1);
+select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id );
id_A id_B
1 1
2 NULL
+create table t3 (id_A integer unsigned not null, id_B integer unsigned null );
+insert into t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id );
+select * from t3;
id_A id_B
1 1
2 NULL
+drop table t3;
+create table t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id );
+select * from t3;
id_A id_B
1 1
2 NULL
+drop table t1,t2,t3;
diff --git a/mysql-test/r/type_time.result b/mysql-test/r/type_time.result
index 1a137a89b1e..ff700f456ef 100644
--- a/mysql-test/r/type_time.result
+++ b/mysql-test/r/type_time.result
@@ -1,3 +1,7 @@
+create table t1 (t time);
+insert into t1 values("10:22:33"),("12:34:56.78"),(10),(1234),(123456.78),(1234559.99),("1"),("1:23"),("1:23:45"), ("10.22"), ("-10 1:22:33.45"),("20 10:22:33"),("1999-02-03 20:33:34");
+insert t1 values (30),(1230),("1230"),("12:30"),("12:30:35"),("1 12:30:31.32");
+select * from t1;
t
10:22:33
12:34:56
@@ -18,6 +22,8 @@ t
12:30:00
12:30:35
36:30:31
+insert into t1 values("10.22.22"),(1234567),(123456789),(123456789.10),("10 22:22"),("12.45a");
+select * from t1;
t
10:22:33
12:34:56
@@ -44,6 +50,10 @@ t
838:59:59
262:22:00
00:00:12
+drop table t1;
+create table t1 (t time);
+insert into t1 values ('09:00:00'),('13:00:00'),('19:38:34'), ('13:00:00'),('09:00:00'),('09:00:00'),('13:00:00'),('13:00:00'),('13:00:00'),('09:00:00');
+select t, time_to_sec(t),sec_to_time(time_to_sec(t)) from t1;
t time_to_sec(t) sec_to_time(time_to_sec(t))
09:00:00 32400 09:00:00
13:00:00 46800 13:00:00
@@ -55,6 +65,7 @@ t time_to_sec(t) sec_to_time(time_to_sec(t))
13:00:00 46800 13:00:00
13:00:00 46800 13:00:00
09:00:00 32400 09:00:00
+select sec_to_time(time_to_sec(t)) from t1;
sec_to_time(time_to_sec(t))
09:00:00
13:00:00
@@ -66,3 +77,4 @@ sec_to_time(time_to_sec(t))
13:00:00
13:00:00
09:00:00
+drop table t1;
diff --git a/mysql-test/r/type_timestamp.result b/mysql-test/r/type_timestamp.result
index 8996ca59f7f..ab53d27e8f3 100644
--- a/mysql-test/r/type_timestamp.result
+++ b/mysql-test/r/type_timestamp.result
@@ -1,11 +1,29 @@
+CREATE TABLE t1 ( t timestamp);
+SET TIMESTAMP=1234;
+insert into t1 values(NULL);
+select * from t1;
t
19700101032034
+drop table t1;
+CREATE TABLE t1 (value TEXT NOT NULL, id VARCHAR(32) NOT NULL, stamp timestamp, PRIMARY KEY (id));
+INSERT INTO t1 VALUES ("my value", "myKey","1999-04-02 00:00:00");
+SELECT stamp FROM t1 WHERE id="myKey";
stamp
19990402000000
+UPDATE t1 SET value="my value" WHERE id="myKey";
+SELECT stamp FROM t1 WHERE id="myKey";
stamp
19990402000000
+drop table t1;
+create table t1 (a timestamp);
+insert into t1 values (now());
+select date_format(a,"%Y %y"),year(a),year(now()) from t1;
date_format(a,"%Y %y") year(a) year(now())
1970 70 1970 1970
+drop table t1;
+create table t1 (ix timestamp);
+insert into t1 values (19991101000000),(19990102030405),(19990630232922),(19990601000000),(19990930232922),(19990531232922),(19990501000000),(19991101000000),(19990501000000);
+select * from t1;
ix
19991101000000
19990102030405
@@ -16,6 +34,21 @@ ix
19990501000000
19991101000000
19990501000000
+drop table t1;
+CREATE TABLE t1 (date date, date_time datetime, time_stamp timestamp);
+INSERT INTO t1 VALUES ("1998-12-31","1998-12-31 23:59:59",19981231235959);
+INSERT INTO t1 VALUES ("1999-01-01","1999-01-01 00:00:00",19990101000000);
+INSERT INTO t1 VALUES ("1999-09-09","1999-09-09 23:59:59",19990909235959);
+INSERT INTO t1 VALUES ("2000-01-01","2000-01-01 00:00:00",20000101000000);
+INSERT INTO t1 VALUES ("2000-02-28","2000-02-28 00:00:00",20000228000000);
+INSERT INTO t1 VALUES ("2000-02-29","2000-02-29 00:00:00",20000229000000);
+INSERT INTO t1 VALUES ("2000-03-01","2000-03-01 00:00:00",20000301000000);
+INSERT INTO t1 VALUES ("2000-12-31","2000-12-31 23:59:59",20001231235959);
+INSERT INTO t1 VALUES ("2001-01-01","2001-01-01 00:00:00",20010101000000);
+INSERT INTO t1 VALUES ("2004-12-31","2004-12-31 23:59:59",20041231235959);
+INSERT INTO t1 VALUES ("2005-01-01","2005-01-01 00:00:00",20050101000000);
+INSERT INTO t1 VALUES ("2030-01-01","2030-01-01 00:00:00",20300101000000);
+SELECT * FROM t1;
date date_time time_stamp
1998-12-31 1998-12-31 23:59:59 19981231235959
1999-01-01 1999-01-01 00:00:00 19990101000000
@@ -29,3 +62,4 @@ date date_time time_stamp
2004-12-31 2004-12-31 23:59:59 20041231235959
2005-01-01 2005-01-01 00:00:00 20050101000000
2030-01-01 2030-01-01 00:00:00 20300101000000
+drop table t1;
diff --git a/mysql-test/r/type_uint.result b/mysql-test/r/type_uint.result
index 54fa717e0f8..1acfc700d3a 100644
--- a/mysql-test/r/type_uint.result
+++ b/mysql-test/r/type_uint.result
@@ -1,3 +1,9 @@
+drop table if exists t1;
+create table t1 (this int unsigned);
+insert into t1 values (1);
+insert into t1 values (-1);
+select * from t1;
this
1
0
+drop table t1;
diff --git a/mysql-test/r/type_year.result b/mysql-test/r/type_year.result
index 7dc15a4dd1b..c892d575ca0 100644
--- a/mysql-test/r/type_year.result
+++ b/mysql-test/r/type_year.result
@@ -1,3 +1,6 @@
+create table t1 (y year,y2 year(2));
+insert into t1 values (0,0),(1999,1999),(2000,2000),(2001,2001),(70,70),(69,69);
+select * from t1;
y y2
0000 00
1999 99
@@ -5,6 +8,7 @@ y y2
2001 01
1970 70
2069 69
+select * from t1 order by y;
y y2
0000 00
1970 70
@@ -12,6 +16,7 @@ y y2
2000 00
2001 01
2069 69
+select * from t1 order by y2;
y y2
1970 70
1999 99
@@ -19,3 +24,4 @@ y y2
2000 00
2001 01
2069 69
+drop table t1;
diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result
new file mode 100644
index 00000000000..e842bb3b447
--- /dev/null
+++ b/mysql-test/r/union.result
@@ -0,0 +1,159 @@
+drop table if exists t1,t2,t3;
+CREATE TABLE t1 (a int not null, b char (10) not null);
+insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c');
+CREATE TABLE t2 (a int not null, b char (10) not null);
+insert into t2 values (3,'c'),(4,'d'),(5,'f'),(6,'e');
+select a,b from t1 union select a,b from t2;
+a b
+1 a
+2 b
+3 c
+4 d
+5 f
+6 e
+select a,b from t1 union all select a,b from t2;
+a b
+1 a
+2 b
+3 c
+3 c
+3 c
+4 d
+5 f
+6 e
+select a,b from t1 union all select a,b from t2 order by b;
+a b
+1 a
+2 b
+3 c
+3 c
+3 c
+4 d
+6 e
+5 f
+select a,b from t1 union all select a,b from t2 union select 7,'g';
+a b
+1 a
+2 b
+3 c
+3 c
+3 c
+4 d
+5 f
+6 e
+7 g
+select 0,'#' union select a,b from t1 union all select a,b from t2 union select 7,'gg';
+0 #
+0 #
+1 a
+2 b
+3 c
+3 c
+3 c
+4 d
+5 f
+6 e
+7 g
+select a,b from t1 union select a,b from t1;
+a b
+1 a
+2 b
+3 c
+select 't1',b,count(*) from t1 group by b UNION select 't2',b,count(*) from t2 group by b;
+t1 b count(*)
+t1 a 1
+t1 b 1
+t1 c 2
+t2 c 1
+t2 d 1
+t2 e 1
+t2 f 1
+(select a,b from t1 limit 2) union all (select a,b from t2 order by a) limit 4;
+a b
+1 a
+2 b
+3 c
+4 d
+(select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1);
+a b
+1 a
+(select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by b desc;
+a b
+3 c
+2 b
+1 a
+explain select a,b from t1 union all select a,b from t2;
+table type possible_keys key key_len ref rows Extra
+t1 ALL NULL NULL NULL NULL 4
+t2 ALL NULL NULL NULL NULL 4
+explain select xx from t1 union select 1;
+Unknown column 'xx' in 'field list'
+explain select a,b from t1 union select 1;
+table type possible_keys key key_len ref rows Extra
+t1 ALL NULL NULL NULL NULL 4
+ 0 0 No tables used
+explain select 1 union select a,b from t1 union select 1;
+table type possible_keys key key_len ref rows Extra
+ 0 0 No tables used
+t1 ALL NULL NULL NULL NULL 4
+ 0 0 No tables used
+explain select a,b from t1 union select 1 limit 0;
+table type possible_keys key key_len ref rows Extra
+t1 ALL NULL NULL NULL NULL 4
+ 0 0 Impossible WHERE
+select a,b from t1 into outfile 'skr' union select a,b from t2;
+Wrong usage of UNION and INTO
+select a,b from t1 order by a union select a,b from t2;
+Wrong usage of UNION and ORDER BY
+insert into t3 select a from t1 order by a union select a from t2;
+Wrong usage of UNION and ORDER BY
+create table t3 select a,b from t1 union select a from t2;
+The used SELECT statements have a different number of columns
+select a,b from t1 union select a from t2;
+The used SELECT statements have a different number of columns
+select * from t1 union select a from t2;
+The used SELECT statements have a different number of columns
+select a from t1 union select * from t2;
+The used SELECT statements have a different number of columns
+create table t3 select a,b from t1 union all select a,b from t2;
+insert into t3 select a,b from t1 union all select a,b from t2;
+replace into t3 select a,b as c from t1 union all select a,b from t2;
+drop table t1,t2,t3;
+CREATE TABLE t1 (
+`pseudo` char(35) NOT NULL default '',
+`pseudo1` char(35) NOT NULL default '',
+`same` tinyint(1) unsigned NOT NULL default '1',
+PRIMARY KEY (`pseudo1`),
+KEY `pseudo` (`pseudo`)
+) TYPE=MyISAM;
+INSERT INTO t1 (pseudo,pseudo1,same) VALUES ('joce', 'testtt', 1),('joce', 'tsestset', 1),('dekad', 'joce', 1);
+SELECT pseudo FROM t1 WHERE pseudo1='joce' UNION SELECT pseudo FROM t1 WHERE pseudo='joce';
+pseudo
+dekad
+joce
+SELECT pseudo1 FROM t1 WHERE pseudo1='joce' UNION SELECT pseudo1 FROM t1 WHERE pseudo='joce';
+pseudo1
+joce
+testtt
+tsestset
+SELECT * FROM t1 WHERE pseudo1='joce' UNION SELECT * FROM t1 WHERE pseudo='joce' order by pseudo desc,pseudo1 desc;
+pseudo pseudo1 same
+joce tsestset 1
+joce testtt 1
+dekad joce 1
+SELECT pseudo1 FROM t1 WHERE pseudo='joce' UNION SELECT pseudo FROM t1 WHERE pseudo1='joce';
+pseudo1
+testtt
+tsestset
+dekad
+SELECT pseudo1 FROM t1 WHERE pseudo='joce' UNION ALL SELECT pseudo FROM t1 WHERE pseudo1='joce';
+pseudo1
+testtt
+tsestset
+dekad
+SELECT pseudo1 FROM t1 WHERE pseudo='joce' UNION SELECT 1;
+pseudo1
+testtt
+tsestset
+1
+drop table t1;
diff --git a/mysql-test/r/update.result b/mysql-test/r/update.result
index bd34700e5ec..ba5c1c6e28f 100644
--- a/mysql-test/r/update.result
+++ b/mysql-test/r/update.result
@@ -1,3 +1,16 @@
+drop table if exists t1;
+create table t1 (a int auto_increment , primary key (a));
+insert into t1 values (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL);
+update t1 set a=a+10 where a > 34;
+update t1 set a=a+100 where a > 0;
+update t1 set a=a+100 where a=1 and a=2;
+update t1 set a=b+100 where a=1 and a=2;
+Unknown column 'b' in 'field list'
+update t1 set a=b+100 where c=1 and a=2;
+Unknown column 'c' in 'where clause'
+update t1 set d=a+100 where a=1;
+Unknown column 'd' in 'field list'
+select * from t1;
a
101
102
@@ -35,7 +48,67 @@ a
134
145
146
+drop table t1;
+CREATE TABLE t1
+(
+place_id int (10) unsigned NOT NULL,
+shows int(10) unsigned DEFAULT '0' NOT NULL,
+ishows int(10) unsigned DEFAULT '0' NOT NULL,
+ushows int(10) unsigned DEFAULT '0' NOT NULL,
+clicks int(10) unsigned DEFAULT '0' NOT NULL,
+iclicks int(10) unsigned DEFAULT '0' NOT NULL,
+uclicks int(10) unsigned DEFAULT '0' NOT NULL,
+ts timestamp(14),
+PRIMARY KEY (place_id,ts)
+);
+INSERT INTO t1 (place_id,shows,ishows,ushows,clicks,iclicks,uclicks,ts)
+VALUES (1,0,0,0,0,0,0,20000928174434);
+UPDATE t1 SET shows=shows+1,ishows=ishows+1,ushows=ushows+1,clicks=clicks+1,iclicks=iclicks+1,uclicks=uclicks+1 WHERE place_id=1 AND ts>="2000-09-28 00:00:00";
+select place_id,shows from t1;
place_id shows
1 1
+drop table t1;
+CREATE TABLE t1 (
+lfdnr int(10) unsigned NOT NULL default '0',
+ticket int(10) unsigned NOT NULL default '0',
+client varchar(255) NOT NULL default '',
+replyto varchar(255) NOT NULL default '',
+subject varchar(100) NOT NULL default '',
+timestamp int(10) unsigned NOT NULL default '0',
+tstamp timestamp(14) NOT NULL,
+status int(3) NOT NULL default '0',
+type varchar(15) NOT NULL default '',
+assignment int(10) unsigned NOT NULL default '0',
+fupcount int(4) unsigned NOT NULL default '0',
+parent int(10) unsigned NOT NULL default '0',
+activity int(10) unsigned NOT NULL default '0',
+priority tinyint(1) unsigned NOT NULL default '1',
+cc varchar(255) NOT NULL default '',
+bcc varchar(255) NOT NULL default '',
+body text NOT NULL,
+comment text,
+header text,
+PRIMARY KEY (lfdnr),
+KEY k1 (timestamp),
+KEY k2 (type),
+KEY k3 (parent),
+KEY k4 (assignment),
+KEY ticket (ticket)
+) TYPE=MyISAM;
+INSERT INTO t1 VALUES (773,773,'','','',980257344,20010318180652,0,'Open',10,0,0,0,1,'','','','','');
+alter table t1 change lfdnr lfdnr int(10) unsigned default 0 not null auto_increment;
+update t1 set status=1 where type='Open';
+select status from t1;
status
1
+drop table t1;
+create table t1 (a int not null, b int not null);
+insert into t1 values (1,1),(1,2),(1,3);
+update t1 set b=4 where a=1 order by b asc limit 1;
+update t1 set b=4 where a=1 order by b desc limit 1;
+select * from t1;
+a b
+1 4
+1 2
+1 4
+drop table t1;
diff --git a/mysql-test/r/user_var.result b/mysql-test/r/user_var.result
index e06a113bd29..5c8b4581c5c 100644
--- a/mysql-test/r/user_var.result
+++ b/mysql-test/r/user_var.result
@@ -1,16 +1,32 @@
+set @a := foo;
+You may only use constant expressions with SET
+set @a := connection_id() + 3;
+select @a - connection_id();
@a - connection_id()
3
+drop table if exists t1,t2;
+CREATE TABLE t1 ( i int not null, v int not null,index (i));
+insert into t1 values (1,1),(1,3),(2,1);
+create table t2 (i int not null, unique (i));
+insert into t2 select distinct i from t1;
+select * from t2;
i
1
2
+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;
i @vv1:=if(sv1.i,1,0) @vv2:=if(sv2.i,1,0) @vv3:=if(sv3.i,1,0) @vv1+@vv2+@vv3
1 1 0 1 2
2 1 0 0 1
+explain select * from t1 where i=@vv1;
table type possible_keys key key_len ref rows Extra
t1 ref i i 4 const 1 where used
+explain select * from t1 where @vv1:=@vv1+1 and i=@vv1;
table type possible_keys key key_len ref rows Extra
t1 ALL NULL NULL NULL NULL 3 where used
+explain select @vv1:=i from t1 where i=@vv1;
table type possible_keys key key_len ref rows Extra
t1 index NULL i 4 NULL 3 where used; Using index
+explain select * from t1 where i=@vv1;
table type possible_keys key key_len ref rows Extra
t1 ref i i 4 const 1 where used
+drop table t1,t2;
diff --git a/mysql-test/r/varbinary.result b/mysql-test/r/varbinary.result
index 62aeae21970..a63db14b736 100644
--- a/mysql-test/r/varbinary.result
+++ b/mysql-test/r/varbinary.result
@@ -1,6 +1,25 @@
+select 0x41,0x41+0,0x41 | 0x7fffffffffffffff | 0,0xffffffffffffffff | 0 ;
0x41 0x41+0 0x41 | 0x7fffffffffffffff | 0 0xffffffffffffffff | 0
-A 65 9223372036854775807 -1
+A 65 9223372036854775807 18446744073709551615
+select 0x31+1,concat(0x31)+1,-0xf;
0x31+1 concat(0x31)+1 -0xf
50 2 -15
+select x'31',X'ffff'+0;
+x'31' X'ffff'+0
+1 65535
+create table t1 (ID int(8) unsigned zerofill not null auto_increment,UNIQ bigint(21) unsigned zerofill not null,primary key (ID),unique (UNIQ) );
+insert into t1 set UNIQ=0x38afba1d73e6a18a;
+insert into t1 set UNIQ=123;
+explain select * from t1 where UNIQ=0x38afba1d73e6a18a;
table type possible_keys key key_len ref rows Extra
t1 const UNIQ UNIQ 8 const 1
+drop table t1;
+select x'hello';
+You have an error in your SQL syntax near 'x'hello'' at line 1
+select 0xfg;
+Unknown column '0xfg' in 'field list'
+create table t1 select 1 as x, 2 as xx;
+select x,xx from t1;
+x xx
+1 2
+drop table t1;
diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result
index ab60d5042b0..e1f21f324ce 100644
--- a/mysql-test/r/variables.result
+++ b/mysql-test/r/variables.result
@@ -1,25 +1,46 @@
+drop table if exists t1;
+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_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
10 1e-10 abcdeghi abcdefghij NULL
+set @test_int="hello",@test_double="hello",@test_string="hello",@test_string2="hello";
+select @test_int,@test_double,@test_string,@test_string2;
@test_int @test_double @test_string @test_string2
hello hello hello hello
+set @test_int="hellohello",@test_double="hellohello",@test_string="hellohello",@test_string2="hellohello";
+select @test_int,@test_double,@test_string,@test_string2;
@test_int @test_double @test_string @test_string2
hellohello hellohello hellohello hellohello
+set @test_int=null,@test_double=null,@test_string=null,@test_string2=null;
+select @test_int,@test_double,@test_string,@test_string2;
@test_int @test_double @test_string @test_string2
NULL NULL NULL NULL
+select @t1:=(@t2:=1)+@t3:=4,@t1,@t2,@t3;
@t1:=(@t2:=1)+@t3:=4 @t1 @t2 @t3
5 5 1 4
+select @t5;
@t5
1.23456
+CREATE TABLE t1 (c_id INT(4) NOT NULL, c_name CHAR(20), c_country CHAR(3), PRIMARY KEY(c_id));
+INSERT INTO t1 VALUES (1,'Bozo','USA'),(2,'Ronald','USA'),(3,'Kinko','IRE'),(4,'Mr. Floppy','GB');
+SELECT @min_cid:=min(c_id), @max_cid:=max(c_id) from t1;
@min_cid:=min(c_id) @max_cid:=max(c_id)
1 4
+SELECT * FROM t1 WHERE c_id=@min_cid OR c_id=@max_cid;
c_id c_name c_country
1 Bozo USA
4 Mr. Floppy GB
+SELECT * FROM t1 WHERE c_id=@min_cid OR c_id=@max_cid OR c_id=666;
c_id c_name c_country
1 Bozo USA
4 Mr. Floppy GB
+ALTER TABLE t1 DROP PRIMARY KEY;
+select * from t1 where c_id=@min_cid OR c_id=@max_cid;
c_id c_name c_country
1 Bozo USA
4 Mr. Floppy GB
+drop table t1;
diff --git a/mysql-test/r/warnings.result b/mysql-test/r/warnings.result
new file mode 100644
index 00000000000..d77e98cc635
--- /dev/null
+++ b/mysql-test/r/warnings.result
@@ -0,0 +1,9 @@
+create table t1 (a int);
+insert into t1 values (1);
+insert into t1 values ("hej");
+insert into t1 values ("hej"),("då");
+set SQL_WARNINGS=1;
+insert into t1 values ("hej");
+insert into t1 values ("hej"),("då");
+drop table t1;
+set SQL_WARNINGS=0;
diff --git a/mysql-test/resolve-stack b/mysql-test/resolve-stack
new file mode 100755
index 00000000000..cdbe362c752
--- /dev/null
+++ b/mysql-test/resolve-stack
@@ -0,0 +1,8 @@
+#! /bin/sh
+# A shortcut for resolving stacks when debugging when
+# we cannot duplicate the crash in a debugger and have to
+# resort to using stack traces
+
+nm --numeric-sort ../sql/mysqld > var/tmp/mysqld.sym
+echo "Please type or paste the numeric stack trace,Ctrl-C to quit:"
+../extra/resolve_stack_dump -s var/tmp/mysqld.sym
diff --git a/mysql-test/std_data/des_key_file b/mysql-test/std_data/des_key_file
new file mode 100644
index 00000000000..fa53802d449
--- /dev/null
+++ b/mysql-test/std_data/des_key_file
@@ -0,0 +1,4 @@
+5 default_password
+1 password1
+4 password4
+2 password2
diff --git a/mysql-test/std_data/gemini.dat b/mysql-test/std_data/gemini.dat
deleted file mode 100644
index c2e1045f5ac..00000000000
--- a/mysql-test/std_data/gemini.dat
+++ /dev/null
@@ -1,5 +0,0 @@
-65,-1,1
-379,-1,1
-468,-1,1
-469,-1,1
-508,-1,1
diff --git a/mysql-test/std_data/master-bin.001 b/mysql-test/std_data/master-bin.001
index fa30d8e5302..2ec2397acdd 100644
--- a/mysql-test/std_data/master-bin.001
+++ b/mysql-test/std_data/master-bin.001
Binary files differ
diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test
index dbfbd4267d8..22af6663e0a 100644
--- a/mysql-test/t/alter_table.test
+++ b/mysql-test/t/alter_table.test
@@ -10,10 +10,14 @@ 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);
+insert into t1 values (2,4,3,5,"PENDING",1,7);
alter table t1
add column col4_5 varchar(20) not null after col4,
-add column col7 varchar(30) not null after col6,
-add column col8 datetime not null, drop column to_be_deleted;
+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;
+select * from t1;
drop table t1;
create table t1 (bandID MEDIUMINT UNSIGNED NOT NULL PRIMARY KEY, payoutID SMALLINT UNSIGNED NOT NULL);
@@ -73,6 +77,26 @@ OPTIMIZE TABLE t1;
DROP TABLE t1;
#
+# ALTER TABLE ... ENABLE/DISABLE KEYS
+
+create table t1 (n1 int not null, n2 int, n3 int, n4 float,
+ unique(n1),
+ key (n1, n2, n3, n4),
+ key (n2, n3, n4, n1),
+ key (n3, n4, n1, n2),
+ key (n4, n1, n2, n3) );
+alter table t1 disable keys;
+#let $1=10000;
+let $1=10;
+while ($1)
+{
+ eval insert into t1 values($1,RAND()*1000,RAND()*1000,RAND());
+ dec $1;
+}
+alter table t1 enable keys;
+drop table t1;
+
+#
# Drop and add an auto_increment column
#
@@ -81,4 +105,3 @@ insert into t1 values (null),(null),(null),(null);
alter table t1 drop i,add i int unsigned not null auto_increment, drop primary key, add primary key (i);
select * from t1;
drop table t1;
-
diff --git a/mysql-test/t/analyse.test b/mysql-test/t/analyse.test
index 1b5022f6e4c..3f56b3e47ce 100644
--- a/mysql-test/t/analyse.test
+++ b/mysql-test/t/analyse.test
@@ -2,6 +2,7 @@
# Test of procedure analyse
#
+drop table if exists t1,t2;
create table t1 (i int, j int);
insert into t1 values (1,2), (3,4), (5,6), (7,8);
select * from t1 procedure analyse();
diff --git a/mysql-test/t/auto_increment.test b/mysql-test/t/auto_increment.test
index b9b8c244699..d86466572d8 100644
--- a/mysql-test/t/auto_increment.test
+++ b/mysql-test/t/auto_increment.test
@@ -2,6 +2,7 @@
# Test of auto_increment; The test for BDB tables is in bdb.test
#
+drop table if exists t1;
create table t1 (a int not null auto_increment,b int, primary key (a)) type=myisam auto_increment=3;
insert into t1 values (1,1),(NULL,3),(NULL,4);
delete from t1 where a=4;
@@ -18,20 +19,6 @@ insert into t1 values (NULL,9,9);
select * from t1;
drop table t1;
-create table t1 (a int not null auto_increment,b int, primary key (a)) type=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;
-
create table t1 (
skey tinyint unsigned NOT NULL auto_increment PRIMARY KEY,
sval char(20)
diff --git a/mysql-test/t/backup.test b/mysql-test/t/backup.test
index 71343783d69..ad332cde646 100644
--- a/mysql-test/t/backup.test
+++ b/mysql-test/t/backup.test
@@ -40,9 +40,3 @@ unlock tables;
connection con1;
reap;
drop table t1;
-
-
-
-
-
-
diff --git a/mysql-test/t/bdb-crash.test b/mysql-test/t/bdb-crash.test
index 55e00ad2a5e..cdbc2dbe0e4 100644
--- a/mysql-test/t/bdb-crash.test
+++ b/mysql-test/t/bdb-crash.test
@@ -1,3 +1,4 @@
+-- source include/have_bdb.inc
# test for bug reported by Mark Steele
drop table if exists t1;
diff --git a/mysql-test/t/bdb.test b/mysql-test/t/bdb.test
index 50698bb8df6..0df93b5f220 100644
--- a/mysql-test/t/bdb.test
+++ b/mysql-test/t/bdb.test
@@ -767,3 +767,19 @@ select INFO_NOTE from t1 where STR_DATE = '20010610';
select INFO_NOTE from t1 where STR_DATE < '20010610';
select INFO_NOTE from t1 where STR_DATE > '20010610';
drop table t1;
+
+#
+# Test problem with multi table delete which quickly shows up with bdb tables.
+#
+
+create table t1 (a int not null, b int, primary key (a)) type =bdb;
+create table t2 (a int not null, b int, primary key (a)) type =bdb;
+insert into t1 values (2, 3),(1, 7),(10, 7);
+insert into t2 values (2, 3),(1, 7),(10, 7);
+select * from t1;
+select * from t2;
+delete t1, t2 from t1, t2 where t1.a = t2.a;
+select * from t1;
+select * from t2;
+select * from t2;
+drop table t1,t2;
diff --git a/mysql-test/t/bench_count_distinct.test b/mysql-test/t/bench_count_distinct.test
index 62d456a3cf8..9059428bea4 100644
--- a/mysql-test/t/bench_count_distinct.test
+++ b/mysql-test/t/bench_count_distinct.test
@@ -1,12 +1,13 @@
drop table if exists t1;
create table t1(n int not null, key(n)) delay_key_write = 1;
let $1=100;
+disable_query_log;
while ($1)
{
eval insert into t1 values($1);
eval insert into t1 values($1);
dec $1;
}
-
+enable_query_log;
select count(distinct n) from t1;
drop table t1;
diff --git a/mysql-test/t/bigint.test b/mysql-test/t/bigint.test
index 6470b6f6a30..cec3e1ca45c 100644
--- a/mysql-test/t/bigint.test
+++ b/mysql-test/t/bigint.test
@@ -14,3 +14,26 @@ select * from t1 where a='18446744073709551615';
delete from t1 where a=18446744073709551615;
select * from t1;
drop table t1;
+
+create table t1 ( a int not null default 1, big bigint );
+insert into t1 (big) values (-1),(12345678901234567),(9223372036854775807),(18446744073709551615);
+select min(big),max(big),max(big)-1 from t1;
+select min(big),max(big),max(big)-1 from t1 group by a;
+alter table t1 modify big bigint unsigned not null;
+select min(big),max(big),max(big)-1 from t1;
+select min(big),max(big),max(big)-1 from t1 group by a;
+alter table t1 add key (big);
+select min(big),max(big),max(big)-1 from t1;
+select min(big),max(big),max(big)-1 from t1 group by a;
+alter table t1 modify big bigint not null;
+select min(big),max(big),max(big)-1 from t1;
+select min(big),max(big),max(big)-1 from t1 group by a;
+drop table t1;
+
+select CAST(1-2 AS UNSIGNED);
+select CAST(CAST(1-2 AS UNSIGNED) AS SIGNED INTEGER);
+select CONVERT('-1',UNSIGNED);
+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);
+select cast(5 as unsigned) -6.0;
diff --git a/mysql-test/t/bulk_replace.test b/mysql-test/t/bulk_replace.test
new file mode 100644
index 00000000000..d366004c16f
--- /dev/null
+++ b/mysql-test/t/bulk_replace.test
@@ -0,0 +1,14 @@
+#
+# this is a test of bulk-insert code
+# as used by REPLACE
+#
+# by Monty
+#
+
+drop table if exists t1;
+CREATE TABLE t1 (a int, unique (a), b int not null, unique(b), c int not null, index(c));
+replace into t1 values (1,1,1),(2,2,2),(3,1,3);
+select * from t1;
+check table t1;
+drop table t1;
+
diff --git a/mysql-test/t/check.test b/mysql-test/t/check.test
index 62af9f92e65..947566e725b 100644
--- a/mysql-test/t/check.test
+++ b/mysql-test/t/check.test
@@ -5,14 +5,17 @@ drop table if exists t1;
#add a lot of keys to slow down check
create table t1(n int not null, key(n), key(n), key(n), key(n));
let $1=10000;
+disable_query_log;
while ($1)
{
eval insert into t1 values ($1);
dec $1;
}
-send check table t1 type=extended;
+enable_query_log;
+send check table t1 extended;
connection con2;
insert into t1 values (200000);
connection con1;
reap;
drop table t1;
+
diff --git a/mysql-test/t/count_distinct2-master.opt b/mysql-test/t/count_distinct2-master.opt
new file mode 100644
index 00000000000..d81cc55090d
--- /dev/null
+++ b/mysql-test/t/count_distinct2-master.opt
@@ -0,0 +1 @@
+--set-variable=max_heap_table_size=16384
diff --git a/mysql-test/t/count_distinct2.test b/mysql-test/t/count_distinct2.test
new file mode 100644
index 00000000000..d1bea7614c8
--- /dev/null
+++ b/mysql-test/t/count_distinct2.test
@@ -0,0 +1,79 @@
+drop table if exists t1;
+
+create table t1(n1 int, n2 int, s char(20), vs varchar(20), t text);
+insert into t1 values (1,11, 'one','eleven', 'eleven'),
+ (1,11, 'one','eleven', 'eleven'),
+ (2,11, 'two','eleven', 'eleven'),
+ (2,12, 'two','twevle', 'twelve'),
+ (2,13, 'two','thirteen', 'foo'),
+ (2,13, 'two','thirteen', 'foo'),
+ (2,13, 'two','thirteen', 'bar'),
+ (NULL,13, 'two','thirteen', 'bar'),
+ (2,NULL, 'two','thirteen', 'bar'),
+ (2,13, NULL,'thirteen', 'bar'),
+ (2,13, 'two',NULL, 'bar'),
+ (2,13, 'two','thirteen', NULL);
+
+select distinct n1 from t1;
+select count(distinct n1) from t1;
+
+select distinct n2 from t1;
+select count(distinct n2) from t1;
+
+select distinct s from t1;
+select count(distinct s) from t1;
+
+select distinct vs from t1;
+select count(distinct vs) from t1;
+
+select distinct t from t1;
+select count(distinct t) from t1;
+
+select distinct n1,n2 from t1;
+select count(distinct n1,n2) from t1;
+
+select distinct n1,s from t1;
+select count(distinct n1,s) from t1;
+
+select distinct s,n1,vs from t1;
+select count(distinct s,n1,vs) from t1;
+
+select distinct s,t from t1;
+select count(distinct s,t) from t1;
+
+select count(distinct n1), count(distinct n2) from t1;
+
+select count(distinct n2), n1 from t1 group by n1;
+drop table t1;
+
+# test the conversion from tree to MyISAM
+create table t1 (n int default NULL);
+let $1=5000;
+disable_query_log;
+while ($1)
+{
+ eval insert into t1 values($1);
+ dec $1;
+}
+enable_query_log;
+
+flush status;
+select count(distinct n) from t1;
+show status like 'Created_tmp_disk_tables';
+drop table t1;
+
+#test conversion from heap to MyISAM
+create table t1 (s text);
+let $1=5000;
+disable_query_log;
+while ($1)
+{
+ eval insert into t1 values('$1');
+ dec $1;
+}
+enable_query_log;
+flush status;
+select count(distinct s) from t1;
+show status like 'Created_tmp_disk_tables';
+drop table t1;
+
diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test
index 1a829eec6a3..99d4e5ae229 100644
--- a/mysql-test/t/create.test
+++ b/mysql-test/t/create.test
@@ -25,14 +25,10 @@ drop table if exists t1,t2;
!$1164 create table t1 (a int not null auto_increment,primary key (a)) type=heap;
!$1163 create table t1 (a int not null,b text) type=heap;
!$1171 create table t1 (a int ,primary key(a)) type=heap;
-!$1121 create table t1 (a int,b text, index(a)) type=isam;
-!$1073 create table t1 (a int,b text, index(b)) type=isam;
drop table if exists t1;
-!$1075 create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null, primary key (ord,ordid)) type=isam;
!$1164 create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null, primary key (ord,ordid)) type=heap;
!$1171 create table t1 (ordid int(8), primary key (ordid));
-!$1121 create table t1 (ordid int(8), unique (ordid)) type=isam;
-- error 1044,1
create table not_existing_database.test (a int);
@@ -71,6 +67,22 @@ select * from t2 where b="world";
drop table t1,t2;
#
+# Test types after CREATE ... SELECT
+#
+
+create table t1(x varchar(50) );
+create table t2 select x from t1 where 1=2;
+describe t1;
+describe t2;
+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;
+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;
+drop table t1,t2;
+
+#
# Test of primary key with 32 index
#
diff --git a/mysql-test/t/ctype_latin1_de-master.opt b/mysql-test/t/ctype_latin1_de-master.opt
new file mode 100644
index 00000000000..98accd58c46
--- /dev/null
+++ b/mysql-test/t/ctype_latin1_de-master.opt
@@ -0,0 +1 @@
+--default-character-set=latin1_de
diff --git a/mysql-test/t/ctype_latin1_de.test b/mysql-test/t/ctype_latin1_de.test
new file mode 100644
index 00000000000..d39d7f6e5dd
--- /dev/null
+++ b/mysql-test/t/ctype_latin1_de.test
@@ -0,0 +1,46 @@
+#
+# Test latin_de character set
+#
+drop table if exists t1;
+create table t1 (a char (20) not null, b int not null auto_increment, index (a,b),index(b));
+insert into t1 (a) values ('ä'),('ac'),('ae'),('ad'),('Äc'),('aeb');
+insert into t1 (a) values ('üc'),('uc'),('ue'),('ud'),('Ü'),('ueb'),('uf');
+insert into t1 (a) values ('ö'),('oc'),('Öa'),('oe'),('od'),('Öc'),('oeb');
+insert into t1 (a) values ('s'),('ss'),('ß'),('ßb'),('ssa'),('ssc'),('ßa');
+insert into t1 (a) values ('eä'),('uü'),('öo'),('ää'),('ääa'),('aeae');
+insert into t1 (a) values ('q'),('a'),('u'),('o'),('é'),('É');
+select a,b from t1 order by a,b;
+select a,b from t1 order by upper(a),b;
+select a from t1 order by a desc;
+check table t1;
+select * from t1 where a like "ö%";
+select * from t1 where a like binary "%É%";
+select * from t1 where a like "%Á%";
+select * from t1 where a like "%U%";
+select * from t1 where a like "%ss%";
+drop table t1;
+
+# The following should all be true
+select strcmp('ä','ae'),strcmp('ae','ä'),strcmp('aeq','äq'),strcmp('äq','aeq');
+select strcmp('ss','ß'),strcmp('ß','ss'),strcmp('ßs','sss'),strcmp('ßq','ssq');
+
+# The following should all return -1
+select strcmp('ä','af'),strcmp('a','ä'),strcmp('ää','aeq'),strcmp('ää','aeaeq');
+select strcmp('ss','ßa'),strcmp('ß','ssa'),strcmp('sßa','sssb'),strcmp('s','ß');
+select strcmp('ö','oö'),strcmp('Ü','uü'),strcmp('ö','oeb');
+
+# The following should all return 1
+select strcmp('af','ä'),strcmp('ä','a'),strcmp('aeq','ää'),strcmp('aeaeq','ää');
+select strcmp('ßa','ss'),strcmp('ssa','ß'),strcmp('sssb','sßa'),strcmp('ß','s');
+select strcmp('u','öa'),strcmp('u','ö');
+
+#
+# Some other simple tests with the current character set
+#
+
+create table t1 (a varchar(10), key(a));
+insert into t1 values ("a"),("abc"),("abcd"),("hello"),("test");
+select * from t1 where a like "abc%";
+select * from t1 where a like "test%";
+select * from t1 where a like "te_t";
+drop table t1;
diff --git a/mysql-test/t/dirty-close.test b/mysql-test/t/dirty_close.test
index 3ed22f26d5b..3ed22f26d5b 100644
--- a/mysql-test/t/dirty-close.test
+++ b/mysql-test/t/dirty_close.test
diff --git a/mysql-test/t/distinct.test b/mysql-test/t/distinct.test
index bf8a03ac40d..b850ec5d562 100644
--- a/mysql-test/t/distinct.test
+++ b/mysql-test/t/distinct.test
@@ -207,3 +207,14 @@ insert into t1 (a) values (1),(2),(3),(4),(1),(2),(3),(4);
select distinct a from t1 group by b,a having a > 2 order by a desc;
select distinct a,c from t1 group by b,c,a having a > 2 order by a desc;
drop table t1;
+
+#
+# Test problem with DISTINCT and ORDER BY DESC
+#
+
+create table t1 (a char(1), key(a)) type=myisam;
+insert into t1 values('1'),('1');
+select * from t1 where a >= '1';
+select distinct a from t1 order by a desc;
+select distinct a from t1 where a >= '1' order by a desc;
+drop table t1;
diff --git a/mysql-test/t/drop.test b/mysql-test/t/drop.test
index 2a45fe8253b..c92f2b1f3b9 100644
--- a/mysql-test/t/drop.test
+++ b/mysql-test/t/drop.test
@@ -11,33 +11,33 @@ create table t1(n int);
drop table t1;
select * from t1;
-#now test for a bug in drop database - it is important that the name
-#of the table is the same as the name of the database - in the original
-#code this triggered a bug
-drop database if exists foo;
-create database foo;
-drop database if exists foo;
-create database foo;
-create table foo.foo (n int);
-insert into foo.foo values (4);
-select * from foo.foo;
-drop database if exists foo;
-create database foo;
-drop database foo;
+# now test for a bug in drop database - it is important that the name
+# of the table is the same as the name of the database - in the original
+# code this triggered a bug
+drop database if exists mysqltest;
+create database mysqltest;
+drop database if exists mysqltest;
+create database mysqltest;
+create table mysqltest.mysqltest (n int);
+insert into mysqltest.mysqltest values (4);
+select * from mysqltest.mysqltest;
+drop database if exists mysqltest;
+create database mysqltest;
+drop database mysqltest;
# test drop/create database and FLUSH TABLES WITH READ LOCK
-drop database if exists foo;
+drop database if exists mysqltest;
flush tables with read lock;
---error 1209
-create database foo;
+--error 1209,1223;
+create database mysqltest;
unlock tables;
-create database foo;
+create database mysqltest;
show databases;
flush tables with read lock;
---error 1208
-drop database foo;
+--error 1208,1223;
+drop database mysqltest;
unlock tables;
-drop database foo;
+drop database mysqltest;
show databases;
-
-
+--error 1008
+drop database mysqltest;
diff --git a/mysql-test/t/flush.test b/mysql-test/t/flush.test
index 4491de1f82b..38aa37caa4f 100644
--- a/mysql-test/t/flush.test
+++ b/mysql-test/t/flush.test
@@ -1,3 +1,11 @@
+# This test doesn't work with the embedded version as this code
+# assumes that one query is running while we are doing queries on
+# a second connection.
+# This would work if mysqltest run would be threaded and handle each
+# connection in a separate thread.
+#
+-- source include/not_embedded.inc
+
connect (con1,localhost,root,,);
connect (con2,localhost,root,,);
connection con1;
@@ -7,6 +15,7 @@ drop table if exists t2;
create table t2(n int);
insert into t2 values(3);
let $1=100;
+disable_query_log;
while ($1)
{
connection con1;
@@ -19,7 +28,7 @@ while ($1)
reap;
dec $1;
}
-
+enable_query_log;
connection con1;
select * from t1;
connection con2;
@@ -35,15 +44,15 @@ reap;
#test if drop database will wait until we release the global read lock
connection con1;
-drop database if exists foo;
-create database foo;
-create table foo.t1(n int);
-insert into foo.t1 values (23);
+drop database if exists mysqltest;
+create database mysqltest;
+create table mysqltest.t1(n int);
+insert into mysqltest.t1 values (23);
flush tables with read lock;
connection con2;
-send drop database foo;
+send drop database mysqltest;
connection con1;
-select * from foo.t1;
+select * from mysqltest.t1;
unlock tables;
connection con2;
reap;
@@ -57,3 +66,12 @@ connection con2;
insert into t1 values (345);
select * from t1;
drop table t1;
+
+#
+# Test that QUERY CACHE commands doesn't core dump.
+# (Normally we don't have a cache active at this point)
+#
+
+flush query cache;
+reset query cache;
+show status like "Qcache_queries_in_cache";
diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test
index 83e328ca616..ea7a572951a 100644
--- a/mysql-test/t/fulltext.test
+++ b/mysql-test/t/fulltext.test
@@ -5,10 +5,42 @@
drop table if exists t1,t2,t3;
CREATE TABLE t1 (a VARCHAR(200), b TEXT, FULLTEXT (a,b));
-INSERT INTO t1 VALUES('MySQL has now support', 'for full-text search'),('Full-text indexes', 'are called collections'),('Only MyISAM tables','support collections'),('Function MATCH ... AGAINST()','is used to do a search'),('Full-text search in MySQL', 'implements vector space model');
+INSERT INTO t1 VALUES('MySQL has now support', 'for full-text search'),
+ ('Full-text indexes', 'are called collections'),
+ ('Only MyISAM tables','support collections'),
+ ('Function MATCH ... AGAINST()','is used to do a search'),
+ ('Full-text search in MySQL', 'implements vector space model');
+
+# nl search
+
select * from t1 where MATCH(a,b) AGAINST ("collections");
select * from t1 where MATCH(a,b) AGAINST ("indexes");
select * from t1 where MATCH(a,b) AGAINST ("indexes collections");
+
+# UNION of fulltext's
+select * from t1 where MATCH(a,b) AGAINST ("collections") UNION ALL select * from t1 where MATCH(a,b) AGAINST ("indexes");
+
+
+# boolean search
+
+select * from t1 where MATCH(a,b) AGAINST("support -collections" IN BOOLEAN MODE);
+select * from t1 where MATCH(a,b) AGAINST("support collections" IN BOOLEAN MODE);
+select * from t1 where MATCH(a,b) AGAINST("support +collections" IN BOOLEAN MODE);
+select * from t1 where MATCH(a,b) AGAINST("sear*" IN BOOLEAN MODE);
+select * from t1 where MATCH(a,b) AGAINST("+support +collections" IN BOOLEAN MODE);
+select * from t1 where MATCH(a,b) AGAINST("+search" IN BOOLEAN MODE);
+select * from t1 where MATCH(a,b) AGAINST("+search +(support vector)" IN BOOLEAN MODE);
+select * from t1 where MATCH(a,b) AGAINST("+search -(support vector)" IN BOOLEAN MODE);
+select *, MATCH(a,b) AGAINST("support collections" IN BOOLEAN MODE) as x from t1;
+select *, MATCH(a,b) AGAINST("collections support" IN BOOLEAN MODE) as x from t1;
+
+# boolean w/o index:
+
+select * from t1 where MATCH a AGAINST ("search" IN BOOLEAN MODE);
+select * from t1 where MATCH b AGAINST ("sear*" IN BOOLEAN MODE);
+
+#update/delete with fulltext index
+
delete from t1 where a like "MySQL%";
update t1 set a='some test foobar' where MATCH a,b AGAINST ('model');
delete from t1 where MATCH(a,b) AGAINST ("indexes");
@@ -77,14 +109,38 @@ CREATE TABLE t3 (
--error 1210
select * from t2 where MATCH inhalt AGAINST (t2.inhalt);
-
---error 1210
-select * from t2 where MATCH inhalt AGAINST (t2.inhalt);
-
--error 1191
select * from t2 where MATCH ticket AGAINST ('foobar');
-
--error 1210
select * from t2,t3 where MATCH (t2.inhalt,t3.inhalt) AGAINST ('foobar');
drop table t1,t2,t3;
+
+#
+# two more bugtests
+#
+
+CREATE TABLE t1 (
+ id int(11) auto_increment,
+ title varchar(100) default '',
+ PRIMARY KEY (id),
+ KEY ind5 (title),
+ FULLTEXT KEY FT1 (title)
+) TYPE=MyISAM;
+
+insert into t1 (title) values ('this is a test');
+update t1 set title='this is A test' where id=1;
+check table t1;
+update t1 set title='this test once revealed a bug' where id=1;
+select * from t1;
+update t1 set title=NULL where id=1;
+
+drop table t1;
+
+# one more bug - const_table related
+
+CREATE TABLE t1 (a int(11), b text, FULLTEXT KEY (b)) TYPE=MyISAM;
+insert into t1 values (1,"I wonder why the fulltext index doesnt work?");
+SELECT * from t1 where MATCH (b) AGAINST ('apples');
+
+drop table t1;
diff --git a/mysql-test/t/fulltext_cache.test b/mysql-test/t/fulltext_cache.test
index fc5f0e266b3..0b15e57a97b 100644
--- a/mysql-test/t/fulltext_cache.test
+++ b/mysql-test/t/fulltext_cache.test
@@ -26,10 +26,16 @@ INSERT INTO t2 VALUES (6,2,'um chocolate Snickers');
INSERT INTO t2 VALUES (7,1,'Bife');
INSERT INTO t2 VALUES (8,1,'Pizza de Salmao');
-SELECT t1.q, t2.item, t2.id, MATCH t2.item AGAINST ('sushi') as x FROM t1, t2
-WHERE (t2.id2 = t1.id) ORDER BY x DESC,t2.id;
+SELECT t1.q, t2.item, t2.id, MATCH t2.item AGAINST ('sushi')
+as x FROM t1, t2 WHERE (t2.id2 = t1.id) ORDER BY x DESC,t2.id;
-SELECT t1.q, t2.item, t2.id, MATCH t2.item AGAINST ('sushi') as x FROM t2, t1
-WHERE (t2.id2 = t1.id) ORDER BY x DESC,t2.id;
+SELECT t1.q, t2.item, t2.id, MATCH t2.item AGAINST ('sushi' IN BOOLEAN MODE)
+as x FROM t1, t2 WHERE (t2.id2 = t1.id) ORDER BY x DESC,t2.id;
+
+SELECT t1.q, t2.item, t2.id, MATCH t2.item AGAINST ('sushi')
+as x FROM t2, t1 WHERE (t2.id2 = t1.id) ORDER BY x DESC,t2.id;
+
+SELECT t1.q, t2.item, t2.id, MATCH t2.item AGAINST ('sushi' IN BOOLEAN MODE)
+as x FROM t2, t1 WHERE (t2.id2 = t1.id) ORDER BY x DESC,t2.id;
drop table t1, t2;
diff --git a/mysql-test/t/fulltext_distinct.test b/mysql-test/t/fulltext_distinct.test
new file mode 100644
index 00000000000..86e2f7ca1b4
--- /dev/null
+++ b/mysql-test/t/fulltext_distinct.test
@@ -0,0 +1,41 @@
+#
+# Test of fulltext index
+# bug reported by Tibor Simko <tibor.simko@cern.ch>
+#
+
+DROP TABLE IF EXISTS t1, t2;
+CREATE TABLE t1 (
+ id mediumint unsigned NOT NULL auto_increment,
+ tag char(6) NOT NULL default '',
+ value text NOT NULL default '',
+ PRIMARY KEY (id),
+ KEY kt(tag),
+ KEY kv(value(15)),
+ FULLTEXT KEY kvf(value)
+) TYPE=MyISAM;
+CREATE TABLE t2 (
+ id_t2 mediumint unsigned NOT NULL default '0',
+ id_t1 mediumint unsigned NOT NULL default '0',
+ field_number tinyint unsigned NOT NULL default '0',
+ PRIMARY KEY (id_t2,id_t1,field_number),
+ KEY id_t1(id_t1)
+) TYPE=MyISAM;
+
+INSERT INTO t1 (tag,value) VALUES ('foo123','bar111');
+INSERT INTO t1 (tag,value) VALUES ('foo123','bar222');
+INSERT INTO t1 (tag,value) VALUES ('bar345','baz333 ar');
+
+INSERT INTO t2 VALUES (2231626,64280,0);
+INSERT INTO t2 VALUES (2231626,64281,0);
+INSERT INTO t2 VALUES (12346, 3, 1);
+
+SELECT * FROM t1; SELECT * FROM t2;
+
+SELECT DISTINCT t2.id_t2 FROM t2, t1
+WHERE MATCH (t1.value) AGAINST ('baz333') AND t1.id = t2.id_t1;
+
+SELECT DISTINCT t2.id_t2 FROM t2, t1
+WHERE MATCH (t1.value) AGAINST ('baz333' IN BOOLEAN MODE)
+AND t1.id = t2.id_t1;
+
+DROP TABLE t1, t2;
diff --git a/mysql-test/t/fulltext_left_join.test b/mysql-test/t/fulltext_left_join.test
index d09d577d04b..abb1c8e8473 100644
--- a/mysql-test/t/fulltext_left_join.test
+++ b/mysql-test/t/fulltext_left_join.test
@@ -22,6 +22,8 @@ INSERT INTO t2 VALUES('456', 'lui');
select match(t1.texte,t1.sujet,t1.motsclefs) against('droit')
from t1 left join t2 on t2.id=t1.id;
+select match(t1.texte,t1.sujet,t1.motsclefs) against('droit' IN BOOLEAN MODE)
+ from t1 left join t2 on t2.id=t1.id;
drop table t1, t2;
diff --git a/mysql-test/t/fulltext_order_by.test b/mysql-test/t/fulltext_order_by.test
index 9f35d58e699..d5cb99ef0ee 100644
--- a/mysql-test/t/fulltext_order_by.test
+++ b/mysql-test/t/fulltext_order_by.test
@@ -9,17 +9,24 @@ INSERT INTO t1 (message) VALUES ("Testing"),("table"),("testbug"),
("steve"),("is"),("cool"),("steve is cool");
# basic MATCH
SELECT a, MATCH (message) AGAINST ('steve') FROM t1 WHERE MATCH (message) AGAINST ('steve');
+SELECT a, MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) FROM t1 WHERE MATCH (message) AGAINST ('steve');
+SELECT a, MATCH (message) AGAINST ('steve') FROM t1 WHERE MATCH (message) AGAINST ('steve' IN BOOLEAN MODE);
+SELECT a, MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) FROM t1 WHERE MATCH (message) AGAINST ('steve' IN BOOLEAN MODE);
# MATCH + ORDER BY (with ft-ranges)
SELECT a, MATCH (message) AGAINST ('steve') FROM t1 WHERE MATCH (message) AGAINST ('steve') ORDER BY a;
+SELECT a, MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) FROM t1 WHERE MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) ORDER BY a;
# MATCH + ORDER BY (with normal ranges) + UNIQUE
SELECT a, MATCH (message) AGAINST ('steve') FROM t1 WHERE a in (2,7,4) and MATCH (message) AGAINST ('steve') ORDER BY a DESC;
+SELECT a, MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) FROM t1 WHERE a in (2,7,4) and MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) ORDER BY a DESC;
# MATCH + ORDER BY + UNIQUE (const_table)
SELECT a, MATCH (message) AGAINST ('steve') FROM t1 WHERE a=7 and MATCH (message) AGAINST ('steve') ORDER BY 1;
+SELECT a, MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) FROM t1 WHERE a=7 and MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) ORDER BY 1;
# ORDER BY MATCH
SELECT a, MATCH (message) AGAINST ('steve') as rel FROM t1 ORDER BY rel;
+SELECT a, MATCH (message) AGAINST ('steve' IN BOOLEAN MODE) as rel FROM t1 ORDER BY rel;
drop table t1;
diff --git a/mysql-test/t/fulltext_var.test b/mysql-test/t/fulltext_var.test
new file mode 100644
index 00000000000..71213d1195a
--- /dev/null
+++ b/mysql-test/t/fulltext_var.test
@@ -0,0 +1,5 @@
+#
+# Fulltext configurable parameters
+#
+
+show variables like "ft\_%";
diff --git a/mysql-test/t/func_crypt.test b/mysql-test/t/func_crypt.test
index ddc0816e301..f01504d3691 100644
--- a/mysql-test/t/func_crypt.test
+++ b/mysql-test/t/func_crypt.test
@@ -1,2 +1,3 @@
-
select length(encrypt('foo', 'ff')) <> 0;
+--replace_result $1$aa$4OSUA5cjdx0RUQ08opV27/ aaqPiZY5xR5l.
+select password('test'),length(encrypt('test')),encrypt('test','aa');
diff --git a/mysql-test/t/func_encrypt-master.opt b/mysql-test/t/func_encrypt-master.opt
new file mode 100644
index 00000000000..0b042f52e9a
--- /dev/null
+++ b/mysql-test/t/func_encrypt-master.opt
@@ -0,0 +1 @@
+--des-key-file=$MYSQL_TEST_DIR/std_data/des_key_file
diff --git a/mysql-test/t/func_encrypt.test b/mysql-test/t/func_encrypt.test
new file mode 100644
index 00000000000..3b6acc54ec9
--- /dev/null
+++ b/mysql-test/t/func_encrypt.test
@@ -0,0 +1,67 @@
+-- source include/have_openssl.inc
+
+drop table if exists t1;
+create table t1 (x blob);
+insert into t1 values (des_encrypt('The quick red fox jumped over the lazy brown dog','The quick red fox jumped over the lazy brown dog'));
+insert into t1 values (des_encrypt('a','The quick red fox jumped over the lazy brown dog'));
+insert into t1 values (des_encrypt('The quick red fox jumped over the lazy brown dog','a'));
+insert into t1 values (des_encrypt('ab','The quick red fox jumped over the lazy brown dog'));
+insert into t1 values (des_encrypt('The quick red fox jumped over the lazy brown dog','ab'));
+insert into t1 values (des_encrypt('abc','The quick red fox jumped over the lazy brown dog'));
+insert into t1 values (des_encrypt('The quick red fox jumped over the lazy brown dog','abc'));
+insert into t1 values (des_encrypt('abcd','The quick red fox jumped over the lazy brown dog'));
+insert into t1 values (des_encrypt('The quick red fox jumped over the lazy brown dog','abcd'));
+insert into t1 values (des_encrypt('abcde','The quick red fox jumped over the lazy brown dog'));
+insert into t1 values (des_encrypt('The quick red fox jumped over the lazy brown dog','abcde'));
+insert into t1 values (des_encrypt('abcdef','The quick red fox jumped over the lazy brown dog'));
+insert into t1 values (des_encrypt('The quick red fox jumped over the lazy brown dog','abcdef'));
+insert into t1 values (des_encrypt('abcdefg','The quick red fox jumped over the lazy brown dog'));
+insert into t1 values (des_encrypt('The quick red fox jumped over the lazy brown dog','abcdefg'));
+insert into t1 values (des_encrypt('abcdefgh','The quick red fox jumped over the lazy brown dog'));
+insert into t1 values (des_encrypt('The quick red fox jumped over the lazy brown dog','abcdefgh'));
+insert into t1 values (des_encrypt('abcdefghi','The quick red fox jumped over the lazy brown dog'));
+insert into t1 values (des_encrypt('The quick red fox jumped over the lazy brown dog','abcdefghi'));
+insert into t1 values (des_encrypt('abcdefghij','The quick red fox jumped over the lazy brown dog'));
+insert into t1 values (des_encrypt('The quick red fox jumped over the lazy brown dog','abcdefghij'));
+insert into t1 values (des_encrypt('abcdefghijk','The quick red fox jumped over the lazy brown dog'));
+insert into t1 values (des_encrypt('The quick red fox jumped over the lazy brown dog','abcdefghijk'));
+insert into t1 values (des_encrypt('The quick red fox jumped over the lazy brown dog','sabakala'));
+insert into t1 values (des_encrypt('quick red fox jumped over the lazy brown dog','sabakala'));
+insert into t1 values (des_encrypt('red fox jumped over the lazy brown dog','sabakala'));
+insert into t1 values (des_encrypt('fox jumped over the lazy brown dog','sabakala'));
+insert into t1 values (des_encrypt('jumped over the lazy brown dog','sabakala'));
+insert into t1 values (des_encrypt('over the lazy brown dog','sabakala'));
+insert into t1 values (des_encrypt('the lazy brown dog','sabakala'));
+insert into t1 values (des_encrypt('lazy brown dog','sabakala'));
+insert into t1 values (des_encrypt('brown dog','sabakala'));
+insert into t1 values (des_encrypt('dog','sabakala'));
+insert into t1 values (des_encrypt('dog!','sabakala'));
+insert into t1 values (des_encrypt('dog!!','sabakala'));
+insert into t1 values (des_encrypt('dog!!!','sabakala'));
+insert into t1 values (des_encrypt('dog!!!!','sabakala'));
+insert into t1 values (des_encrypt('dog!!!!!','sabakala'));
+insert into t1 values (des_encrypt('jumped over the lazy brown dog','sabakala'));
+insert into t1 values (des_encrypt('jumped over the lazy brown dog','sabakala'));
+select hex(x), hex(des_decrypt(x,'sabakala')) from t1;
+select des_decrypt(x,'sabakala') as s from t1 having s like '%dog%';
+drop table t1;
+
+#
+# Test default keys
+#
+select hex(des_encrypt("hello")),des_decrypt(des_encrypt("hello"));
+select des_decrypt(des_encrypt("hello",4));
+select des_decrypt(des_encrypt("hello",'test'),'test');
+select hex(des_encrypt("hello")),hex(des_encrypt("hello",5)),hex(des_encrypt("hello",'default_password'));
+select des_decrypt(des_encrypt("hello"),'default_password');
+select des_decrypt(des_encrypt("hello",4),'password4');
+
+# Test flush
+SET @a=des_decrypt(des_encrypt("hello"));
+flush des_key_file;
+select @a = des_decrypt(des_encrypt("hello"));
+
+# Test usage of wrong password
+select hex("hello");
+select hex(des_decrypt(des_encrypt("hello",4),'password2'));
+select hex(des_decrypt(des_encrypt("hello","hidden")));
diff --git a/mysql-test/t/func_like.test b/mysql-test/t/func_like.test
index d160b04176c..e0f1f0db9ce 100644
--- a/mysql-test/t/func_like.test
+++ b/mysql-test/t/func_like.test
@@ -2,9 +2,11 @@
# Test of like
#
+drop table if exists t1;
create table t1 (a varchar(10), key(a));
insert into t1 values ("a"),("abc"),("abcd"),("hello"),("test");
select * from t1 where a like "abc%";
+select * from t1 where a like "ABC%";
select * from t1 where a like "test%";
select * from t1 where a like "te_t";
drop table t1;
diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test
index b7200b2d144..26272fba03f 100644
--- a/mysql-test/t/func_str.test
+++ b/mysql-test/t/func_str.test
@@ -9,10 +9,11 @@ drop table if exists t1;
select 'hello',"'hello'",'""hello""','''h''e''l''l''o''',"hel""lo",'hel\'lo';
select 'hello' 'monty';
select length('\n\t\r\b\0\_\%\\');
+select bit_length('\n\t\r\b\0\_\%\\');
select concat('monty',' was here ','again'),length('hello'),char(ascii('h'));
select locate('he','hello'),locate('he','hello',2),locate('lo','hello',2) ;
-select instr('hello','he');
-select position('ll' in 'hello'),position('a' in 'hello');
+select instr('hello','HE'), instr('hello',binary 'HE'), instr(binary 'hello','HE');
+select position(binary 'll' in 'hello'),position('a' in binary 'hello');
select left('hello',2),right('hello',2),substring('hello',2,2),mid('hello',1,5) ;
select concat('',left(right(concat('what ',concat('is ','happening')),9),4),'',substring('monty',5,1)) ;
select substring_index('www.tcx.se','.',-2),substring_index('www.tcx.se','.',1);
@@ -35,7 +36,6 @@ select insert('txs',2,1,'hi'),insert('is ',4,0,'a'),insert('txxxxt',2,4,'es');
select replace('aaaa','a','b'),replace('aaaa','aa','b'),replace('aaaa','a','bb'),replace('aaaa','','b'),replace('bbbb','a','c');
select replace(concat(lcase(concat('THIS',' ','IS',' ','A',' ')),ucase('false'),' ','test'),'FALSE','REAL') ;
select soundex(''),soundex('he'),soundex('hello all folks');
-select password('test'),length(encrypt('test')),encrypt('test','aa');
select md5('hello');
select repeat('monty',5),concat('*',space(5),'*');
select reverse('abc'),reverse('abcd');
diff --git a/mysql-test/t/func_system.test b/mysql-test/t/func_system.test
index b0bdbe472dd..052e0530cf6 100644
--- a/mysql-test/t/func_system.test
+++ b/mysql-test/t/func_system.test
@@ -2,5 +2,5 @@
# system functions
#
-select database(),user();
+select database(),user() like "%@%";
select version()>="3.23.29";
diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test
index ffb0f8bbf1e..a052f5f2d92 100644
--- a/mysql-test/t/func_time.test
+++ b/mysql-test/t/func_time.test
@@ -19,13 +19,23 @@ select month("1997-01-02"),year("98-02-03"),dayofyear("1997-12-31");
select month("2001-02-00"),year("2001-00-00");
select DAYOFYEAR("1997-03-03"), WEEK("1998-03-03"), QUARTER(980303);
select HOUR("1997-03-03 23:03:22"), MINUTE("23:03:22"), SECOND(230322);
+
+# Test of week and yearweek
select week(19980101),week(19970101),week(19980101,1),week(19970101,1);
select week(19981231),week(19971231),week(19981231,1),week(19971231,1);
select week(19950101),week(19950101,1);
select yearweek('1981-12-31',1),yearweek('1982-01-01',1),yearweek('1982-12-31',1),yearweek('1983-01-01',1);
+select yearweek('1987-01-01',1),yearweek('1987-01-01');
+select week("2000-01-01",0) as '2000', week("2001-01-01",0) as '2001', week("2002-01-01",0) as '2002',week("2003-01-01",0) as '2003', week("2004-01-01",0) as '2004', week("2005-01-01",0) as '2005', week("2006-01-01",0) as '2006';
+select week("2000-01-06",0) as '2000', week("2001-01-06",0) as '2001', week("2002-01-06",0) as '2002',week("2003-01-06",0) as '2003', week("2004-01-06",0) as '2004', week("2005-01-06",0) as '2005', week("2006-01-06",0) as '2006';
+select week("2000-01-01",1) as '2000', week("2001-01-01",1) as '2001', week("2002-01-01",1) as '2002',week("2003-01-01",1) as '2003', week("2004-01-01",1) as '2004', week("2005-01-01",1) as '2005', week("2006-01-01",1) as '2006';
+select week("2000-01-06",1) as '2000', week("2001-01-06",1) as '2001', week("2002-01-06",1) as '2002',week("2003-01-06",1) as '2003', week("2004-01-06",1) as '2004', week("2005-01-06",1) as '2005', week("2006-01-06",1) as '2006';
+select yearweek("2000-01-01",0) as '2000', yearweek("2001-01-01",0) as '2001', yearweek("2002-01-01",0) as '2002',yearweek("2003-01-01",0) as '2003', yearweek("2004-01-01",0) as '2004', yearweek("2005-01-01",0) as '2005', yearweek("2006-01-01",0) as '2006';
+select yearweek("2000-01-06",0) as '2000', yearweek("2001-01-06",0) as '2001', yearweek("2002-01-06",0) as '2002',yearweek("2003-01-06",0) as '2003', yearweek("2004-01-06",0) as '2004', yearweek("2005-01-06",0) as '2005', yearweek("2006-01-06",0) as '2006';
+select yearweek("2000-01-01",1) as '2000', yearweek("2001-01-01",1) as '2001', yearweek("2002-01-01",1) as '2002',yearweek("2003-01-01",1) as '2003', yearweek("2004-01-01",1) as '2004', yearweek("2005-01-01",1) as '2005', yearweek("2006-01-01",1) as '2006';
+select yearweek("2000-01-06",1) as '2000', yearweek("2001-01-06",1) as '2001', yearweek("2002-01-06",1) as '2002',yearweek("2003-01-06",1) as '2003', yearweek("2004-01-06",1) as '2004', yearweek("2005-01-06",1) as '2005', yearweek("2006-01-06",1) as '2006';
select date_format('1998-12-31','%x-%v'),date_format('1999-01-01','%x-%v');
select date_format('1999-12-31','%x-%v'),date_format('2000-01-01','%x-%v');
-select yearweek('1987-01-01',1),yearweek('1987-01-01');
select dayname("1962-03-03"),dayname("1962-03-03")+0;
select monthname("1972-03-04"),monthname("1972-03-04")+0;
diff --git a/mysql-test/t/gemini.test b/mysql-test/t/gemini.test
deleted file mode 100644
index 9d4451c3551..00000000000
--- a/mysql-test/t/gemini.test
+++ /dev/null
@@ -1,355 +0,0 @@
--- source include/have_gemini.inc
-
-#
-# Small basic test with ignore
-#
-
-drop table if exists t1;
-create table t1 (id int unsigned not null auto_increment, code tinyint unsigned not null, name char(20) not null, primary key (id), key (code), unique (name)) type=gemini;
-
-insert into t1 (code, name) values (1, 'Tim'), (1, 'Monty'), (2, 'David'), (2, 'Erik'), (3, 'Sasha'), (3, 'Jeremy'), (4, 'Matt');
-select id, code, name from t1 order by id;
-
-update ignore t1 set id = 8, name = 'Sinisa' where id < 3;
-select id, code, name from t1 order by id;
-update ignore t1 set id = id + 10, name = 'Ralph' where id < 4;
-select id, code, name from t1 order by id;
-
-drop table t1;
-
-#
-# A bit bigger test
-#
-
-CREATE TABLE t1 (
- id int(11) NOT NULL auto_increment,
- parent_id int(11) DEFAULT '0' NOT NULL,
- level tinyint(4) DEFAULT '0' NOT NULL,
- PRIMARY KEY (id),
- KEY parent_id (parent_id),
- KEY level (level)
-) type=gemini;
-INSERT INTO t1 VALUES (1,0,0),(3,1,1),(4,1,1),(8,2,2),(9,2,2),(17,3,2),(22,4,2),(24,4,2),(28,5,2),(29,5,2),(30,5,2),(31,6,2),(32,6,2),(33,6,2),(203,7,2),(202,7,2),(20,3,2),(157,0,0),(193,5,2),(40,7,2),(2,1,1),(15,2,2),(6,1,1),(34,6,2),(35,6,2),(16,3,2),(7,1,1),(36,7,2),(18,3,2),(26,5,2),(27,5,2),(183,4,2),(38,7,2),(25,5,2),(37,7,2),(21,4,2),(19,3,2),(5,1,1),(179,5,2);
-update t1 set parent_id=parent_id+100;
-select * from t1 where parent_id=102;
-update t1 set id=id+1000;
-!$1062 update t1 set id=1024 where id=1009;
-select * from t1;
-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;
-explain select level from t1 where level=1;
-explain select level,id from t1 where level=1;
-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;
-drop table t1;
-
-#
-# Test replace
-#
-
-CREATE TABLE t1 (
- gesuchnr int(11) DEFAULT '0' NOT NULL,
- benutzer_id int(11) DEFAULT '0' NOT NULL,
- PRIMARY KEY (gesuchnr,benutzer_id)
-) type=gemini;
-
-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);
-select * from t1;
-drop table t1;
-
-#
-# test delete using hidden_primary_key
-#
-
-create table t1 (a int) type=gemini;
-insert into t1 values (1), (2);
-delete from t1 where a = 1;
-select * from t1;
-drop table t1;
-
-#
-# Test auto_increment on sub key
-#
-
-#create table t1 (a char(10) not null, b int not null auto_increment, primary key(a,b)) type=gemini;
-#insert into t1 values ("a",1),("b",2),("a",2),("c",1);
-#insert into t1 values ("a",NULL),("b",NULL),("c",NULL),("e",NULL);
-#insert into t1 (a) values ("a"),("b"),("c"),("d");
-#insert into t1 (a) values ('k'),('d');
-#insert into t1 (a) values ("a");
-#insert into t1 values ("d",last_insert_id());
-#select * from t1;
-#drop table t1;
-
-#
-# Test when reading on part of unique key
-#
-CREATE TABLE t1 (
- user_id int(10) DEFAULT '0' NOT NULL,
- name varchar(100),
- phone varchar(100),
- ref_email varchar(100) DEFAULT '' NOT NULL,
- detail varchar(200),
- PRIMARY KEY (user_id,ref_email)
-)type=gemini;
-
-INSERT INTO t1 VALUES (10292,'sanjeev','29153373','sansh777@hotmail.com','xxx'),(10292,'shirish','2333604','shirish@yahoo.com','ddsds'),(10292,'sonali','323232','sonali@bolly.com','filmstar');
-select * from t1 where user_id=10292;
-INSERT INTO t1 VALUES (10291,'sanjeev','29153373','sansh777@hotmail.com','xxx'),(10293,'shirish','2333604','shirish@yahoo.com','ddsds');
-select * from t1 where user_id=10292;
-select * from t1 where user_id>=10292;
-select * from t1 where user_id>10292;
-select * from t1 where user_id<10292;
-drop table t1;
-
-#
-# Test that keys are created in right order
-# - Needs ANALYZE TABLE to work - MikeF 2/12/01
-#
-#CREATE TABLE t1 (a int not null, b int not null,c int not null,
-#key(a),primary key(a,b), unique(c),key(a),unique(b)) type = gemini;
-#show index from t1;
-#drop table t1;
-
-#
-# Test of ALTER TABLE and gemini tables
-#
-
-#create table t1 (col1 int not null, col2 char(4) not null, primary key(col1));
-#alter table t1 type=gemini;
-#insert into t1 values ('1','1'),('5','2'),('2','3'),('3','4'),('4','4');
-#select * from t1;
-#update t1 set col2='7' where col1='4';
-#select * from t1;
-#alter table t1 add co3 int not null;
-#select * from t1;
-#update t1 set col2='9' where col1='2';
-#select * from t1;
-#drop table t1;
-
-#
-# INSERT INTO gemini tables
-#
-
-create table t1 (a int not null , b int, primary key (a)) type = gemini;
-create table t2 (a int not null , b int, primary key (a)) type = myisam;
-insert into t1 VALUES (1,3) , (2,3), (3,3);
-select * from t1;
-insert into t2 select * from t1;
-select * from t2;
-delete from t1 where b = 3;
-select * from t1;
-insert into t1 select * from t2;
-select * from t1;
-select * from t2;
-drop table t1,t2;
-
-#
-# Search on unique key
-#
-
-CREATE TABLE t1 (
- id int(11) NOT NULL auto_increment,
- ggid varchar(32) binary DEFAULT '' NOT NULL,
- email varchar(64) DEFAULT '' NOT NULL,
- passwd varchar(32) binary DEFAULT '' NOT NULL,
- PRIMARY KEY (id),
- UNIQUE ggid (ggid)
-) TYPE=gemini;
-
-insert into t1 (ggid,passwd) values ('test1','xxx');
-insert into t1 (ggid,passwd) values ('test2','yyy');
-
-select * from t1 where ggid='test1';
-select * from t1 where passwd='xxx';
-select * from t1 where id=2;
-drop table t1;
-
-#
-# ORDER BY on not primary key
-#
-
-#CREATE TABLE t1 (
-# user_name varchar(12),
- #password text,
- #subscribed char(1),
- #user_id int(11) DEFAULT '0' NOT NULL,
- #quota bigint(20),
- #weight double,
- #access_date date,
- #access_time time,
- #approved datetime,
- #dummy_primary_key int(11) NOT NULL auto_increment,
- #PRIMARY KEY (dummy_primary_key)
-#) TYPE=gemini;
-#INSERT INTO t1 VALUES ('user_0','somepassword','N',0,0,0,'2000-09-07','23:06:59','2000-09-07 23:06:59',1);
-#INSERT INTO t1 VALUES ('user_1','somepassword','Y',1,1,1,'2000-09-07','23:06:59','2000-09-07 23:06:59',2);
-#INSERT INTO t1 VALUES ('user_2','somepassword','N',2,2,1.4142135623731,'2000-09-07','23:06:59','2000-09-07 23:06:59',3);
-#INSERT INTO t1 VALUES ('user_3','somepassword','Y',3,3,1.7320508075689,'2000-09-07','23:06:59','2000-09-07 23:06:59',4);
-#INSERT INTO t1 VALUES ('user_4','somepassword','N',4,4,2,'2000-09-07','23:06:59','2000-09-07 23:06:59',5);
-#select user_name, password , subscribed, user_id, quota, weight, access_date, access_time, approved, dummy_primary_key from t1 order by user_name;
-#drop table t1;
-
-#
-# Testing of tables without primary keys
-#
-
-CREATE TABLE t1 (
- id int(11) NOT NULL auto_increment,
- parent_id int(11) DEFAULT '0' NOT NULL,
- level tinyint(4) DEFAULT '0' NOT NULL,
- KEY (id),
- KEY parent_id (parent_id),
- KEY level (level)
-) type=gemini;
-INSERT INTO t1 VALUES (1,0,0),(3,1,1),(4,1,1),(8,2,2),(9,2,2),(17,3,2),(22,4,2),(24,4,2),(28,5,2),(29,5,2),(30,5,2),(31,6,2),(32,6,2),(33,6,2),(203,7,2),(202,7,2),(20,3,2),(157,0,0),(193,5,2),(40,7,2),(2,1,1),(15,2,2),(6,1,1),(34,6,2),(35,6,2),(16,3,2),(7,1,1),(36,7,2),(18,3,2),(26,5,2),(27,5,2),(183,4,2),(38,7,2),(25,5,2),(37,7,2),(21,4,2),(19,3,2),(5,1,1);
-INSERT INTO t1 values (179,5,2);
-update t1 set parent_id=parent_id+100;
-select * from t1 where parent_id=102;
-update t1 set id=id+1000;
-update t1 set id=1024 where id=1009;
-select * from t1;
-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;
-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;
-select level,id from t1 where level=1 order by id;
-delete from t1 where level=1;
-select * from t1;
-drop table t1;
-
-#
-# Test of index only reads
-#
-CREATE TABLE t1 (
- sca_code char(6) NOT NULL,
- cat_code char(6) NOT NULL,
- sca_desc varchar(50),
- lan_code char(2) NOT NULL,
- sca_pic varchar(100),
- sca_sdesc varchar(50),
- sca_sch_desc varchar(16),
- PRIMARY KEY (sca_code, cat_code, lan_code)
-) type = gemini ;
-
-INSERT INTO t1 ( sca_code, cat_code, sca_desc, lan_code, sca_pic, sca_sdesc, sca_sch_desc) VALUES ( 'PD', 'J', 'PENDANT', 'EN', NULL, NULL, 'PENDANT'),( 'RI', 'J', 'RING', 'EN', NULL, NULL, 'RING');
-select count(*) from t1 where sca_code = 'PD';
-drop table t1;
-
-#
-# Test of opening table twice
-#
-CREATE TABLE t1 (a int not null, primary key (a)) type=gemini;
-insert into t1 values(1),(2),(3);
-select t1.a from t1 natural join t1 as t2 order by t1.a;
-drop table t1;
-
-#
-# Test rollback
-#
-
-select "test for rollback";
-create table t1 (n int not null primary key) type=gemini;
-set autocommit=0;
-insert into t1 values (4);
-commit;
-insert into t1 values (5);
-rollback;
-select n, "after rollback" from t1;
-insert into t1 values (5);
-commit;
-select n, "after commit" from t1;
-commit;
-insert into t1 values (6);
-!$1062 insert into t1 values (4);
-commit;
-select n, "after commit" from t1;
-set autocommit=1;
-insert into t1 values (7);
-!$1062 insert into t1 values (4);
-select n from t1;
-# nop
-rollback;
-drop table t1;
-
-#
-# Testing transactions
-#
-
-create table t1 ( id int NOT NULL PRIMARY KEY, nom varchar(64)) type=gemini;
-insert into t1 values(1,'first');
-begin;
-insert into t1 values(2,'hamdouni');
-select id as afterbegin_id,nom as afterbegin_nom from t1;
-rollback;
-select id as afterrollback_id,nom as afterrollback_nom from t1;
-set autocommit=0;
-insert into t1 values(3,'mysql');
-select id as afterautocommit0_id,nom as afterautocommit0_nom from t1;
-rollback;
-select id as afterrollback_id,nom as afterrollback_nom from t1;
-set autocommit=1;
-drop table t1;
-
-#
-# Simple not autocommit test
-#
-
-CREATE TABLE t1 (id char(8) not null primary key, val int not null) type=gemini;
-insert into t1 values ('pippo', 12);
-!$1062 insert into t1 values ('pippo', 12); # Gives error
-delete from t1;
-delete from t1 where id = 'pippo';
-select * from t1;
-
-insert into t1 values ('pippo', 12);
-set autocommit=0;
-delete from t1;
-rollback;
-select * from t1;
-delete from t1;
-commit;
-select * from t1;
-drop table t1;
-set autocommit=1;
-
-#
-# The following simple tests failed at some point
-#
-
-CREATE TABLE t1 (ID INTEGER NOT NULL PRIMARY KEY, NAME VARCHAR(64)) TYPE=gemini;
-INSERT INTO t1 VALUES (1, 'Jochen');
-select * from t1;
-drop table t1;
-
-CREATE TABLE t1 ( _userid VARCHAR(60) NOT NULL PRIMARY KEY) TYPE=gemini;
-set autocommit=0;
-INSERT INTO t1 SET _userid='marc@anyware.co.uk';
-COMMIT;
-SELECT * FROM t1;
-SELECT _userid FROM t1 WHERE _userid='marc@anyware.co.uk';
-drop table t1;
-set autocommit=1;
-
-#
-# Test of load data infile
-#
-
-CREATE TABLE if not exists `t1` (
- `f1` int(11) unsigned NOT NULL default '0',
- `f2` tinyint(3) unsigned NOT NULL default '0',
- `f3` tinyint(3) unsigned NOT NULL default '0',
- PRIMARY KEY (`f1`)
-) TYPE=Gemini;
-lock table t1 write;
-load data infile ''../../std_data/gemini.dat' ignore into table t1 fields terminated by ',';
-select f1 from t1;
-drop table t1;
diff --git a/mysql-test/t/grant_cache-master.opt b/mysql-test/t/grant_cache-master.opt
new file mode 100644
index 00000000000..cfdce628e74
--- /dev/null
+++ b/mysql-test/t/grant_cache-master.opt
@@ -0,0 +1 @@
+--set-variable=query_cache_size=1355776
diff --git a/mysql-test/t/grant_cache.test b/mysql-test/t/grant_cache.test
new file mode 100644
index 00000000000..a6c878cc31c
--- /dev/null
+++ b/mysql-test/t/grant_cache.test
@@ -0,0 +1,102 @@
+#
+# Test grants with query cache
+#
+drop table if exists test.t1,mysqltest.t1,mysqltest.t2;
+reset query cache;
+flush status;
+connect (root,localhost,root,,test,0,master.sock);
+connection root;
+create database if not exists mysqltest;
+
+create table mysqltest.t1 (a int,b int,c int);
+create table mysqltest.t2 (a int,b int,c int);
+insert into mysqltest.t1 values (1,1,1),(2,2,2);
+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,0,master.sock);
+connection root2;
+# put queries in cache
+select * from t1;
+select a from t1;
+select c from t1;
+select * from t2;
+select * from mysqltest.t1,test.t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits%";
+
+# Create the test users
+grant SELECT on mysqltest.* to mysqltest_1@localhost;
+grant SELECT on mysqltest.t1 to mysqltest_2@localhost;
+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,0,master.sock);
+connection user1;
+select "user1";
+select * from t1;
+# The pre and end space are intentional
+ select a from t1 ;
+select c from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+show status like "Qcache_not_cached";
+
+# The following queries should be fetched from cache
+connect (user2,localhost,mysqltest_2,,mysqltest,0,master.sock);
+connection user2;
+select "user2";
+select * from t1;
+select a from t1;
+select c from t1;
+select * from mysqltest.t1,test.t1;
+--error 1142
+select * from t2;
+show status like "Qcache_queries_in_cache";
+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,0,master.sock);
+connection user3;
+select "user3";
+--error 1143
+select * from t1;
+select a from t1;
+--error 1143
+select c from t1;
+--error 1142
+select * from t2;
+--error 1143
+select mysqltest.t1.c from test.t1,mysqltest.t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+show status like "Qcache_not_cached";
+
+# Connect without a database
+connect (user4,localhost,mysqltest_1,,*NO-ONE*,0,master.sock);
+connection user4;
+select "user4";
+--error 1046
+select a from t1;
+# The following query is not cached before (different database)
+select * from mysqltest.t1,test.t1;
+# Cache a query with 'no database'
+select a from mysqltest.t1;
+select a from mysqltest.t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+show status like "Qcache_not_cached";
+
+# Cleanup
+
+connection root;
+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");
+delete from mysql.tables_priv where user in ("mysqltest_1","mysqltest_2","mysqltest_3");
+delete from mysql.columns_priv where user in ("mysqltest_1","mysqltest_2","mysqltest_3");
+flush privileges;
+drop table test.t1,mysqltest.t1,mysqltest.t2;
+drop database mysqltest;
diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test
index efa1744feee..17ad9588f1b 100644
--- a/mysql-test/t/group_by.test
+++ b/mysql-test/t/group_by.test
@@ -243,3 +243,43 @@ select sql_big_result spid,sum(userid) from t1 group by spid desc;
explain select sql_big_result score,count(*) from t1 group by score desc;
select sql_big_result score,count(*) from t1 group by score desc;
drop table t1;
+
+#
+# Compare with hash keys
+#
+
+CREATE TABLE t1 (a char(1));
+INSERT INTO t1 VALUES ('A'),('B'),('A'),('B'),('A'),('B'),(NULL),('a'),('b'),(NULL),('A'),('B'),(NULL);
+SELECT a FROM t1 GROUP BY a;
+SELECT a,count(*) FROM t1 GROUP BY a;
+SELECT a FROM t1 GROUP BY binary a;
+SELECT a,count(*) FROM t1 GROUP BY binary a;
+SELECT binary a FROM t1 GROUP BY 1;
+SELECT binary a,count(*) FROM t1 GROUP BY 1;
+# Do the same tests with MyISAM temporary tables
+SET SQL_BIG_TABLES=1;
+SELECT a FROM t1 GROUP BY a;
+SELECT a,count(*) FROM t1 GROUP BY a;
+SELECT a FROM t1 GROUP BY binary a;
+SELECT a,count(*) FROM t1 GROUP BY binary a;
+SELECT binary a FROM t1 GROUP BY 1;
+SELECT binary a,count(*) FROM t1 GROUP BY 1;
+SET SQL_BIG_TABLES=0;
+drop table t1;
+
+#
+# Test of key >= 256 bytes
+#
+
+CREATE TABLE t1 (
+ `a` char(193) default NULL,
+ `b` char(63) default NULL
+);
+INSERT INTO t1 VALUES ('abc','def'),('hij','klm');
+SELECT CONCAT(a, b) FROM t1 GROUP BY 1;
+SELECT CONCAT(a, b),count(*) FROM t1 GROUP BY 1;
+SELECT CONCAT(a, b),count(distinct a) FROM t1 GROUP BY 1;
+SELECT 1 FROM t1 GROUP BY CONCAT(a, b);
+INSERT INTO t1 values ('hij','klm');
+SELECT CONCAT(a, b),count(*) FROM t1 GROUP BY 1;
+DROP TABLE t1;
diff --git a/mysql-test/t/handler.test b/mysql-test/t/handler.test
new file mode 100644
index 00000000000..4f1b11c80ff
--- /dev/null
+++ b/mysql-test/t/handler.test
@@ -0,0 +1,67 @@
+#
+# test of HANDLER ...
+#
+
+drop table if exists t1;
+create table t1 (a int, b char(10), key a(a), key b(a,b));
+insert into t1 values
+(17,"ddd"),(18,"eee"),(19,"fff"),(19,"yyy"),
+(14,"aaa"),(15,"bbb"),(16,"ccc"),(16,"xxx"),
+(20,"ggg"),(21,"hhh"),(22,"iii");
+handler t1 open as t2;
+handler t2 read a first;
+handler t2 read a next;
+handler t2 read a next;
+handler t2 read a prev;
+handler t2 read a last;
+handler t2 read a prev;
+handler t2 read a prev;
+
+handler t2 read a first;
+handler t2 read a prev;
+
+handler t2 read a last;
+handler t2 read a prev;
+handler t2 read a next;
+handler t2 read a next;
+
+handler t2 read a=(15);
+handler t2 read a=(16);
+
+!$1070 handler t2 read a=(19,"fff");
+
+handler t2 read b=(19,"fff");
+handler t2 read b=(19,"yyy");
+handler t2 read b=(19);
+
+!$1109 handler t1 read a last;
+
+handler t2 read a=(11);
+handler t2 read a>=(11);
+
+handler t2 read a=(18);
+handler t2 read a>=(18);
+handler t2 read a>(18);
+handler t2 read a<=(18);
+handler t2 read a<(18);
+
+handler t2 read a first limit 5;
+handler t2 read a next limit 3;
+handler t2 read a prev limit 10;
+
+handler t2 read a>=(16) limit 4;
+handler t2 read a>=(16) limit 2,2;
+handler t2 read a last limit 3;
+
+handler t2 read a=(19);
+handler t2 read a=(19) where b="yyy";
+
+handler t2 read first;
+handler t2 read next;
+alter table t1 type=MyISAM;
+handler t2 read next;
+!$1064 handler t2 read last;
+
+handler t2 close;
+drop table if exists t1;
+
diff --git a/mysql-test/t/having.test b/mysql-test/t/having.test
index fff5415976c..8dd7606d82b 100644
--- a/mysql-test/t/having.test
+++ b/mysql-test/t/having.test
@@ -48,3 +48,15 @@ GROUP BY e.id
HAVING chr_strand= -1 and end >= 0
AND start <= 999660;
drop table t1,t2;
+
+#
+# Test problem with having and MAX() IS NOT NULL
+#
+
+CREATE TABLE t1 (Fld1 int(11) default NULL,Fld2 int(11) default NULL);
+INSERT INTO t1 VALUES (1,10),(1,20),(2,NULL),(2,NULL),(3,50);
+select Fld1, max(Fld2) as q from t1 group by Fld1 having q is not null;
+select Fld1, max(Fld2) from t1 group by Fld1 having max(Fld2) is not null;
+select Fld1, max(Fld2) from t1 group by Fld1 having avg(Fld2) is not null;
+select Fld1, max(Fld2) from t1 group by Fld1 having std(Fld2) is not null;
+drop table t1;
diff --git a/mysql-test/t/heap.test b/mysql-test/t/heap.test
index abb9e1fd1bc..ef7e3239a96 100644
--- a/mysql-test/t/heap.test
+++ b/mysql-test/t/heap.test
@@ -19,6 +19,12 @@ drop table t1;
create table t1 (a int not null,b int not null, primary key (a)) type=heap comment="testing heaps";
insert into t1 values(1,1),(2,2),(3,3),(4,4);
+delete from t1 where a > 0;
+select * from t1;
+drop table t1;
+
+create table t1 (a int not null,b int not null, primary key (a)) type=heap comment="testing heaps";
+insert into t1 values(1,1),(2,2),(3,3),(4,4);
alter table t1 modify a int not null auto_increment, type=myisam, comment="new myisam table";
#show table status like "t1";
select * from t1;
@@ -100,3 +106,35 @@ update t1 set new_col=btn;
explain select * from t1 where btn="a";
explain select * from t1 where btn="a" and new_col="a";
drop table t1;
+
+#
+# Test of NULL keys
+#
+
+CREATE TABLE t1 (
+ a int default NULL,
+ b int default NULL,
+ KEY a (a),
+ UNIQUE b (b)
+) type=heap;
+INSERT INTO t1 VALUES (NULL,99),(99,NULL),(1,1),(2,2),(1,3);
+SELECT * FROM t1 WHERE a=NULL;
+explain SELECT * FROM t1 WHERE a IS NULL;
+SELECT * FROM t1 WHERE a<=>NULL;
+SELECT * FROM t1 WHERE b=NULL;
+explain SELECT * FROM t1 WHERE b IS NULL;
+SELECT * FROM t1 WHERE b<=>NULL;
+
+--error 1062
+INSERT INTO t1 VALUES (1,3);
+DROP TABLE t1;
+
+#
+# Test when deleting all rows
+#
+
+CREATE TABLE t1 (a int not null, primary key(a)) type=heap;
+INSERT into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11);
+DELETE from t1 where a < 100;
+SELECT * from t1;
+DROP TABLE t1;
diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test
index a962f120d4e..1b7ee99e15a 100644
--- a/mysql-test/t/innodb.test
+++ b/mysql-test/t/innodb.test
@@ -515,6 +515,53 @@ select * from t1;
drop table t1;
#
+# Test DROP DATABASE
+#
+
+create database mysqltest;
+create table mysqltest.t1 (a int not null) type= innodb;
+insert into mysqltest.t1 values(1);
+create table mysqltest.t2 (a int not null) type= myisam;
+insert into mysqltest.t2 values(1);
+create table mysqltest.t3 (a int not null) type= heap;
+insert into mysqltest.t3 values(1);
+commit;
+drop database mysqltest;
+# Don't check error message
+--error 12,12
+show tables from mysqltest;
+
+#
+# Test truncate table with and without auto_commit
+#
+
+set autocommit=0;
+create table t1 (a int not null) type= innodb;
+insert into t1 values(1),(2);
+--error 1192
+truncate table t1;
+commit;
+truncate table t1;
+select * from t1;
+insert into t1 values(1),(2);
+delete from t1;
+select * from t1;
+commit;
+drop table t1;
+set autocommit=1;
+
+create table t1 (a int not null) type= innodb;
+insert into t1 values(1),(2);
+truncate table t1;
+insert into t1 values(1),(2);
+select * from t1;
+truncate table t1;
+insert into t1 values(1),(2);
+delete from t1;
+select * from t1;
+drop table t1;
+
+#
# Test of how ORDER BY works when doing it on the whole table
#
@@ -531,9 +578,63 @@ explain select a,b,c from t1;
drop table t1;
#
-# Check describe
+# Check describe & handler
#
-create table t1 (testint int not null default 1) type=innodb;
+create table t1 (t int not null default 1, key (t)) type=innodb;
desc t1;
+--error 1031
+handler t1 open t1;
+--error 1109
+handler t1 read t first;
+--error 1109
+handler t1 close;
drop table t1;
+
+#
+# Test of multi-table-delete
+#
+
+CREATE TABLE t1 (
+ number bigint(20) NOT NULL default '0',
+ cname char(15) NOT NULL default '',
+ carrier_id smallint(6) NOT NULL default '0',
+ privacy tinyint(4) NOT NULL default '0',
+ last_mod_date timestamp(14) NOT NULL,
+ last_mod_id smallint(6) NOT NULL default '0',
+ last_app_date timestamp(14) NOT NULL,
+ last_app_id smallint(6) default '-1',
+ version smallint(6) NOT NULL default '0',
+ assigned_scps int(11) default '0',
+ status tinyint(4) default '0'
+) TYPE=InnoDB;
+INSERT INTO t1 VALUES (4077711111,'SeanWheeler',90,2,20020111112846,500,00000000000000,-1,2,3,1);
+INSERT INTO t1 VALUES (9197722223,'berry',90,3,20020111112809,500,20020102114532,501,4,10,0);
+INSERT INTO t1 VALUES (650,'San Francisco',0,0,20011227111336,342,00000000000000,-1,1,24,1);
+INSERT INTO t1 VALUES (302467,'Sue\'s Subshop',90,3,20020109113241,500,20020102115111,501,7,24,0);
+INSERT INTO t1 VALUES (6014911113,'SudzCarwash',520,1,20020102115234,500,20020102115259,501,33,32768,0);
+INSERT INTO t1 VALUES (333,'tubs',99,2,20020109113440,501,20020109113440,500,3,10,0);
+CREATE TABLE t2 (
+ number bigint(20) NOT NULL default '0',
+ cname char(15) NOT NULL default '',
+ carrier_id smallint(6) NOT NULL default '0',
+ privacy tinyint(4) NOT NULL default '0',
+ last_mod_date timestamp(14) NOT NULL,
+ last_mod_id smallint(6) NOT NULL default '0',
+ last_app_date timestamp(14) NOT NULL,
+ last_app_id smallint(6) default '-1',
+ version smallint(6) NOT NULL default '0',
+ assigned_scps int(11) default '0',
+ status tinyint(4) default '0'
+) TYPE=InnoDB;
+INSERT INTO t2 VALUES (4077711111,'SeanWheeler',0,2,20020111112853,500,00000000000000,-1,2,3,1);
+INSERT INTO t2 VALUES (9197722223,'berry',90,3,20020111112818,500,20020102114532,501,4,10,0);
+INSERT INTO t2 VALUES (650,'San Francisco',90,0,20020109113158,342,00000000000000,-1,1,24,1);
+INSERT INTO t2 VALUES (333,'tubs',99,2,20020109113453,501,20020109113453,500,3,10,0);
+select * from t1;
+select * from t2;
+delete t1, t2 from t1 left join t2 on t1.number=t2.number where (t1.carrier_id=90 and t1.number=t2.number) or (t2.carrier_id=90 and t1.number=t2.number) or (t1.carrier_id=90 and t2.number is null);
+select * from t1;
+select * from t2;
+select * from t2;
+drop table t1,t2;
diff --git a/mysql-test/t/innodb_cache-master.opt b/mysql-test/t/innodb_cache-master.opt
new file mode 100644
index 00000000000..5f0ebff98f6
--- /dev/null
+++ b/mysql-test/t/innodb_cache-master.opt
@@ -0,0 +1 @@
+--set-variable=query_cache_size=1M
diff --git a/mysql-test/t/innodb_cache.test b/mysql-test/t/innodb_cache.test
new file mode 100644
index 00000000000..0a162a9debe
--- /dev/null
+++ b/mysql-test/t/innodb_cache.test
@@ -0,0 +1,14 @@
+-- source include/have_innodb.inc
+
+#
+# Without auto_commit.
+#
+drop table if exists t1;
+set autocommit=0;
+create table t1 (a int not null) type=innodb;
+insert into t1 values (1),(2),(3);
+select * from t1;
+show status like "Qcache_queries_in_cache";
+drop table t1;
+commit;
+set autocommit=1;
diff --git a/mysql-test/t/insert.test b/mysql-test/t/insert.test
index cf6f41d454d..270b1cd4c79 100644
--- a/mysql-test/t/insert.test
+++ b/mysql-test/t/insert.test
@@ -10,3 +10,15 @@ insert into t1 values (a+3);
insert into t1 values (4),(a+5);
select * from t1;
drop table t1;
+
+#
+# Test of duplicate key values with packed keys
+#
+
+create table t1 (id int not null auto_increment primary key, username varchar(32) not null, unique (username));
+insert into t1 values (0,"mysql");
+insert into t1 values (0,"mysql ab");
+insert into t1 values (0,"mysql a");
+insert into t1 values (0,"r1manic");
+insert into t1 values (0,"r1man");
+drop table t1;
diff --git a/mysql-test/t/insert_select.test b/mysql-test/t/insert_select.test
index 17ecb2d5a1f..42f65858d77 100644
--- a/mysql-test/t/insert_select.test
+++ b/mysql-test/t/insert_select.test
@@ -7,6 +7,64 @@ create table t1 (bandID MEDIUMINT UNSIGNED NOT NULL PRIMARY KEY, payoutID SMALLI
insert into t1 (bandID,payoutID) VALUES (1,6),(2,6),(3,4),(4,9),(5,10),(6,1),(7,12),(8,12);
create table t2 (payoutID SMALLINT UNSIGNED NOT NULL PRIMARY KEY);
insert into t2 (payoutID) SELECT DISTINCT payoutID FROM t1;
+--error 1062
insert into t2 (payoutID) SELECT payoutID+10 FROM t1;
+insert ignore into t2 (payoutID) SELECT payoutID+10 FROM t1;
select * from t2;
drop table t1,t2;
+#
+# bug in bulk insert optimization
+# test case by Fournier Jocelyn <joc@presence-pc.com>
+#
+
+DROP TABLE IF EXISTS crash1,crash2;
+CREATE TABLE `crash1` (
+ `numeropost` bigint(20) unsigned NOT NULL default '0',
+ `icone` tinyint(4) unsigned NOT NULL default '0',
+ `numreponse` bigint(20) unsigned NOT NULL auto_increment,
+ `contenu` text NOT NULL,
+ `pseudo` varchar(50) NOT NULL default '',
+ `date` datetime NOT NULL default '0000-00-00 00:00:00',
+ `ip` bigint(11) NOT NULL default '0',
+ `signature` tinyint(1) unsigned NOT NULL default '0',
+ PRIMARY KEY (`numeropost`,`numreponse`)
+ ,KEY `ip` (`ip`),
+ KEY `date` (`date`),
+ KEY `pseudo` (`pseudo`),
+ KEY `numreponse` (`numreponse`)
+) TYPE=MyISAM;
+
+CREATE TABLE `crash2` (
+ `numeropost` bigint(20) unsigned NOT NULL default '0',
+ `icone` tinyint(4) unsigned NOT NULL default '0',
+ `numreponse` bigint(20) unsigned NOT NULL auto_increment,
+ `contenu` text NOT NULL,
+ `pseudo` varchar(50) NOT NULL default '',
+ `date` datetime NOT NULL default '0000-00-00 00:00:00',
+ `ip` bigint(11) NOT NULL default '0',
+ `signature` tinyint(1) unsigned NOT NULL default '0',
+ PRIMARY KEY (`numeropost`,`numreponse`),
+ KEY `ip` (`ip`),
+ KEY `date` (`date`),
+ KEY `pseudo` (`pseudo`),
+ KEY `numreponse` (`numreponse`)
+) TYPE=MyISAM;
+
+INSERT INTO crash2
+(numeropost,icone,numreponse,contenu,pseudo,date,ip,signature) VALUES
+(9,1,56,'test','joce','2001-07-25 13:50:53'
+,3649052399,0);
+
+
+INSERT INTO crash1 (numeropost,icone,contenu,pseudo,date,signature,ip)
+SELECT 1618,icone,contenu,pseudo,date,signature,ip FROM crash2
+WHERE numeropost=9 ORDER BY numreponse ASC;
+
+show variables like '%bulk%';
+
+INSERT INTO crash1 (numeropost,icone,contenu,pseudo,date,signature,ip)
+SELECT 1718,icone,contenu,pseudo,date,signature,ip FROM crash2
+WHERE numeropost=9 ORDER BY numreponse ASC;
+
+DROP TABLE IF EXISTS crash1,crash2;
+
diff --git a/mysql-test/t/isam.test b/mysql-test/t/isam.test
index 1cf068b42ba..c7308c4b999 100644
--- a/mysql-test/t/isam.test
+++ b/mysql-test/t/isam.test
@@ -1,19 +1,66 @@
+-- source include/have_isam.inc
+
+drop table if exists t1,t2;
+
#
# 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));
+create table t1 (a tinyint not null auto_increment, b blob not null, primary key (a)) type=isam;
let $1=100;
+disable_query_log;
while ($1)
{
eval insert into t1 (b) values(repeat(char(65+$1),65540-$1));
dec $1;
}
-check table t1;
-repair table t1;
+enable_query_log;
delete from t1 where (a & 1);
-check table t1;
-repair table t1;
-check table t1;
+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)) type=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
+#
+!$1121 create table t1 (a int,b text, index(a)) type=isam;
+!$1073 create table t1 (a int,b text, index(b)) type=isam;
+!$1075 create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null, primary key (ord,ordid)) type=isam;
+!$1121 create table t1 (ordid int(8), unique (ordid)) type=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 type=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;
diff --git a/mysql-test/t/isolation.test b/mysql-test/t/isolation.test
deleted file mode 100644
index d9750ecb351..00000000000
--- a/mysql-test/t/isolation.test
+++ /dev/null
@@ -1,208 +0,0 @@
-source include/have_gemini.inc
-source include/master-slave.inc;
-connection master;
-drop table if exists t1;
-create table t1 (f1 char(20) not null) type = gemini;
-set autocommit=0;
-
-insert into t1 (f1) values ("test1"), ("bar");
-connection master1;
-!$1030 select * from t1;
-connection master;
-commit;
-
-drop table if exists t1;
-create table t1 (f1 char(20) not null) type = gemini;
-insert into t1 (f1) values ("test2"), ("bar");
-connection master1;
-set transaction isolation level serializable;
-!$-1217 select * from t1;
-connection master;
-commit;
-
-drop table if exists t1;
-create table t1 (f1 char(20) not null) type = gemini;
-insert into t1 (f1) values ("test3"), ("bar");
-connection master1;
-set transaction isolation level read uncommitted;
-select * from t1;
-connection master;
-commit;
-
-drop table if exists t1;
-create table t1 (f1 char(20) not null) type = gemini;
-connection master1;
-set transaction isolation level read committed;
-select * from t1;
-connection master;
-commit;
-
-drop table if exists t1;
-create table t1 (f1 char(20) not null) type = gemini;
-insert into t1 (f1) values ("test4"), ("bar");
-connection master1;
-set transaction isolation level repeatable read;
-select * from t1;
-connection master;
-commit;
-
-drop table if exists t1;
-create table t1 (f1 char(20) not null) type = gemini;
-set transaction isolation level serializable;
-insert into t1 (f1) values ("test5"), ("bar");
-connection master1;
-set transaction isolation level serializable;
-select * from t1;
-connection master;
-commit;
-
-drop table if exists t1;
-create table t1 (f1 char(20) not null) type = gemini;
-set transaction isolation level serializable;
-insert into t1 (f1) values ("test6"), ("bar");
-connection master1;
-set transaction isolation level read uncommitted;
-select * from t1;
-connection master;
-commit;
-
-drop table if exists t1;
-create table t1 (f1 char(20) not null) type = gemini;
-set transaction isolation level serializable;
-insert into t1 (f1) values ("test7"), ("bar");
-connection master1;
-set transaction isolation level read committed;
-select * from t1;
-connection master;
-commit;
-
-drop table if exists t1;
-create table t1 (f1 char(20) not null) type = gemini;
-set transaction isolation level serializable;
-insert into t1 (f1) values ("test8"), ("bar");
-connection master1;
-set transaction isolation level repeatable read;
-select * from t1;
-connection master;
-commit;
-
-drop table if exists t1;
-create table t1 (f1 char(20) not null) type = gemini;
-set transaction isolation level read uncommitted;
-insert into t1 (f1) values ("test9"), ("bar");
-connection master1;
-set transaction isolation level serializable;
-select * from t1;
-connection master;
-commit;
-
-drop table if exists t1;
-create table t1 (f1 char(20) not null) type = gemini;
-set transaction isolation level read uncommitted;
-insert into t1 (f1) values ("test10"), ("bar");
-connection master1;
-set transaction isolation level read uncommitted;
-select * from t1;
-connection master;
-commit;
-
-drop table if exists t1;
-create table t1 (f1 char(20) not null) type = gemini;
-set transaction isolation level read uncommitted;
-insert into t1 (f1) values ("test11"), ("bar");
-connection master1;
-set transaction isolation level read committed;
-select * from t1;
-connection master;
-commit;
-
-drop table if exists t1;
-create table t1 (f1 char(20) not null) type = gemini;
-set transaction isolation level read uncommitted;
-insert into t1 (f1) values ("test12"), ("bar");
-connection master1;
-set transaction isolation level repeatable read;
-select * from t1;
-connection master;
-commit;
-
-drop table if exists t1;
-create table t1 (f1 char(20) not null) type = gemini;
-set transaction isolation level read committed;
-insert into t1 (f1) values ("test13"), ("bar");
-connection master1;
-set transaction isolation level serializable;
-select * from t1;
-connection master;
-commit;
-
-drop table if exists t1;
-create table t1 (f1 char(20) not null) type = gemini;
-set transaction isolation level read committed;
-insert into t1 (f1) values ("test14"), ("bar");
-connection master1;
-set transaction isolation level read uncommitted;
-select * from t1;
-connection master;
-commit;
-
-drop table if exists t1;
-create table t1 (f1 char(20) not null) type = gemini;
-set transaction isolation level read committed;
-insert into t1 (f1) values ("test15"), ("bar");
-connection master1;
-set transaction isolation level read committed;
-select * from t1;
-connection master;
-commit;
-
-drop table if exists t1;
-create table t1 (f1 char(20) not null) type = gemini;
-set transaction isolation level read committed;
-insert into t1 (f1) values ("test16"), ("bar");
-connection master1;
-set transaction isolation level repeatable read;
-select * from t1;
-connection master;
-commit;
-
-drop table if exists t1;
-create table t1 (f1 char(20) not null) type = gemini;
-set transaction isolation level repeatable read;
-insert into t1 (f1) values ("test17"), ("bar");
-connection master1;
-set transaction isolation level serializable;
-select * from t1;
-connection master;
-commit;
-
-drop table if exists t1;
-create table t1 (f1 char(20) not null) type = gemini;
-set transaction isolation level repeatable read;
-insert into t1 (f1) values ("test18"), ("bar");
-connection master1;
-set transaction isolation level read uncommitted;
-select * from t1;
-connection master;
-commit;
-
-drop table if exists t1;
-create table t1 (f1 char(20) not null) type = gemini;
-set transaction isolation level repeatable read;
-insert into t1 (f1) values ("test19"), ("bar");
-connection master1;
-set transaction isolation level read committed;
-select * from t1;
-connection master;
-commit;
-
-drop table if exists t1;
-create table t1 (f1 char(20) not null) type = gemini;
-set transaction isolation level repeatable read;
-insert into t1 (f1) values ("test20"), ("bar");
-connection master1;
-set transaction isolation level repeatable read;
-select * from t1;
-connection master;
-commit;
-drop table t1;
diff --git a/mysql-test/t/join.test b/mysql-test/t/join.test
index 9db520a5edf..3bd78350267 100644
--- a/mysql-test/t/join.test
+++ b/mysql-test/t/join.test
@@ -1,7 +1,6 @@
#
# This failed for lia Perminov
#
-
drop table if exists t1,t2,t3;
create table t1 (id int primary key);
@@ -87,6 +86,7 @@ drop table t1, t2;
create table t1 (a int primary key);
insert into t1 values(1),(2);
select t1.a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a);
+--replace_result "31 tables" "XX tables" "63 tables" "XX tables"
--error 1116
select t1.a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a) left join t1 as t32 using (a) left join t1 as t33 using (a) left join t1 as t34 using (a) left join t1 as t35 using (a) left join t1 as t36 using (a) left join t1 as t37 using (a) left join t1 as t38 using (a) left join t1 as t39 using (a) left join t1 as t40 using (a) left join t1 as t41 using (a) left join t1 as t42 using (a) left join t1 as t43 using (a) left join t1 as t44 using (a) left join t1 as t45 using (a) left join t1 as t46 using (a) left join t1 as t47 using (a) left join t1 as t48 using (a) left join t1 as t49 using (a) left join t1 as t50 using (a) left join t1 as t51 using (a) left join t1 as t52 using (a) left join t1 as t53 using (a) left join t1 as t54 using (a) left join t1 as t55 using (a) left join t1 as t56 using (a) left join t1 as t57 using (a) left join t1 as t58 using (a) left join t1 as t59 using (a) left join t1 as t60 using (a) left join t1 as t61 using (a) left join t1 as t62 using (a) left join t1 as t63 using (a) left join t1 as t64 using (a) left join t1 as t65 using (a);
drop table t1;
diff --git a/mysql-test/t/key.test b/mysql-test/t/key.test
index a8417fad876..6fc975a1cb3 100644
--- a/mysql-test/t/key.test
+++ b/mysql-test/t/key.test
@@ -160,3 +160,11 @@ SELECT * FROM t1 WHERE a='a' AND b=2;
SELECT * FROM t1 WHERE a='a' AND b in (2);
SELECT * FROM t1 WHERE a='a' AND b in (1,2);
drop table t1;
+
+#
+# Test of create key order
+#
+
+create table t1 (a int not null unique, b int unique, c int, d int not null primary key, key(c), e int not null unique);
+show keys from t1;
+drop table t1;
diff --git a/mysql-test/t/keywords.test b/mysql-test/t/keywords.test
index b9a1f34c715..3bd757aa069 100644
--- a/mysql-test/t/keywords.test
+++ b/mysql-test/t/keywords.test
@@ -8,3 +8,7 @@ insert into t1 values ("12:22:22","97:02:03","1997-01-02");
select * from t1;
select t1.time+0,t1.date+0,t1.timestamp+0,concat(date," ",time) from t1;
drop table t1;
+create table events(binlog int);
+insert into events values(1);
+select events.binlog from events;
+drop table events;
diff --git a/mysql-test/t/kill.test b/mysql-test/t/kill.test
index be6860a3cc3..6bcc43ac916 100644
--- a/mysql-test/t/kill.test
+++ b/mysql-test/t/kill.test
@@ -1,3 +1,11 @@
+# This test doesn't work with the embedded version as this code
+# assumes that one query is running while we are doing queries on
+# a second connection.
+# This would work if mysqltest run would be threaded and handle each
+# connection in a separate thread.
+#
+-- source include/not_embedded.inc
+
connect (con1, localhost, root,,);
connect (con2, localhost, root,,);
diff --git a/mysql-test/t/limit.test b/mysql-test/t/limit.test
index 112761abd87..d4f6ce186cf 100644
--- a/mysql-test/t/limit.test
+++ b/mysql-test/t/limit.test
@@ -28,3 +28,5 @@ delete from t1 limit 0;
update t1 set i=3 limit 0;
select * from t1;
drop table t1;
+
+select 0 limit 0;
diff --git a/mysql-test/t/lock.test b/mysql-test/t/lock.test
index 77354e63252..385713174d2 100644
--- a/mysql-test/t/lock.test
+++ b/mysql-test/t/lock.test
@@ -53,45 +53,3 @@ lock tables t1 write;
check table t2;
unlock tables;
drop table t1,t2;
-
-#test to see if select will get the lock ahead of low priority update
-connect (locker,localhost,root,,);
-connect (reader,localhost,root,,);
-connect (writer,localhost,root,,);
-
-connection locker;
-create table t1(n int);
-insert into t1 values (1);
-lock tables t1 write;
-connection writer;
-send update low_priority t1 set n = 4;
-connection reader;
---sleep 2
-send select n from t1;
-connection locker;
---sleep 2
-unlock tables;
-connection writer;
-reap;
-connection reader;
-reap;
-drop table t1;
-
-connection locker;
-create table t1(n int);
-insert into t1 values (1);
-lock tables t1 read;
-connection writer;
-send update low_priority t1 set n = 4;
-connection reader;
---sleep 2
-send select n from t1;
-connection locker;
---sleep 2
-unlock tables;
-connection writer;
-reap;
-connection reader;
-reap;
-drop table t1;
-
diff --git a/mysql-test/t/lock_multi.test b/mysql-test/t/lock_multi.test
new file mode 100644
index 00000000000..53e9fd3393c
--- /dev/null
+++ b/mysql-test/t/lock_multi.test
@@ -0,0 +1,49 @@
+# This test doesn't work with the embedded version as this code
+# assumes that one query is running while we are doing queries on
+# a second connection.
+# This would work if mysqltest run would be threaded and handle each
+# connection in a separate thread.
+#
+-- source include/not_embedded.inc
+
+#test to see if select will get the lock ahead of low priority update
+
+connect (locker,localhost,root,,);
+connect (reader,localhost,root,,);
+connect (writer,localhost,root,,);
+
+connection locker;
+create table t1(n int);
+insert into t1 values (1);
+lock tables t1 write;
+connection writer;
+send update low_priority t1 set n = 4;
+connection reader;
+--sleep 2
+send select n from t1;
+connection locker;
+--sleep 2
+unlock tables;
+connection writer;
+reap;
+connection reader;
+reap;
+drop table t1;
+
+connection locker;
+create table t1(n int);
+insert into t1 values (1);
+lock tables t1 read;
+connection writer;
+send update low_priority t1 set n = 4;
+connection reader;
+--sleep 2
+send select n from t1;
+connection locker;
+--sleep 2
+unlock tables;
+connection writer;
+reap;
+connection reader;
+reap;
+drop table t1;
diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test
index 238dd599664..5bd78769a05 100644
--- a/mysql-test/t/merge.test
+++ b/mysql-test/t/merge.test
@@ -2,7 +2,7 @@
# test of MERGE TABLES
#
-drop table if exists t1,t2,t3;
+drop table if exists t1,t2,t3,t4,t5,t6;
create table t1 (a int not null primary key auto_increment, message char(20));
create table t2 (a int not null primary key auto_increment, message char(20));
INSERT INTO t1 (message) VALUES ("Testing"),("table"),("t1");
@@ -22,7 +22,7 @@ insert into t2 select NULL,message from t1;
insert into t1 select NULL,message from t2;
insert into t2 select NULL,message from t1;
insert into t1 select NULL,message from t2;
-create table t3 (a int not null, b char(20), key(a)) type=MERGE UNION=(t1,t2);
+create table t3 (a int not null, b char(20), key(a)) type=MERGE UNION=(test.t1,test.t2);
explain select * from t3 where a < 10;
explain select * from t3 where a > 10 and a < 20;
select * from t3 where a = 10;
@@ -31,6 +31,14 @@ select * from t3 where a > 10 and a < 20;
explain select a from t3 order by a desc limit 10;
select a from t3 order by a desc limit 10;
select a from t3 order by a desc limit 300,10;
+delete from t3 where a=3;
+select * from t3 where a < 10;
+delete from t3 where a >= 6 and a <= 8;
+select * from t3 where a < 10;
+update t3 set a=3 where a=9;
+select * from t3 where a < 10;
+update t3 set a=6 where a=7;
+select * from t3 where a < 10;
show create table t3;
# The following should give errors
@@ -114,3 +122,49 @@ insert into t2 values (1,1),(2,2),(0,0),(4,4),(5,5),(6,6);
flush tables;
select * from t3 where a=1 order by b limit 2;
drop table t3,t1,t2;
+
+#
+# [phi] testing INSERT_METHOD stuff
+#
+
+drop table if exists t6, t5, t4, t3, t2, t1;
+# first testing of common stuff with new parameters
+create table t1 (a int not null, b int not null, key(a,b));
+create table t2 (a int not null, b int not null, key(a,b));
+create table t3 (a int not null, b int not null, key(a,b)) UNION=(t1,t2) INSERT_METHOD=NO;
+create table t4 (a int not null, b int not null, key(a,b)) TYPE=MERGE UNION=(t1,t2) INSERT_METHOD=NO;
+create table t5 (a int not null, b int not null, key(a,b)) TYPE=MERGE UNION=(t1,t2) INSERT_METHOD=FIRST;
+create table t6 (a int not null, b int not null, key(a,b)) TYPE=MERGE UNION=(t1,t2) INSERT_METHOD=LAST;
+show create table t3;
+show create table t4;
+show create table t5;
+show create table t6;
+insert into t1 values (1,1),(1,2),(1,3),(1,4);
+insert into t2 values (2,1),(2,2),(2,3),(2,4);
+select * from t3 order by b,a limit 3;
+select * from t4 order by b,a limit 3;
+select * from t5 order by b,a limit 3,3;
+select * from t6 order by b,a limit 6,3;
+# now testing inserts and where the data gets written
+insert into t5 values (5,1),(5,2);
+insert into t6 values (6,1),(6,2);
+select * from t1 order by a,b;
+select * from t2 order by a,b;
+select * from t4 order by a,b;
+# preperation for next test
+insert into t3 values (3,1),(3,2),(3,3),(3,4);
+select * from t3 order by a,b;
+# now testing whether options are kept by alter table
+alter table t4 UNION=(t1,t2,t3);
+show create table t4;
+select * from t4 order by a,b;
+# testing switching off insert method and inserts again
+alter table t4 INSERT_METHOD=FIRST;
+show create table t4;
+insert into t4 values (4,1),(4,2);
+select * from t1 order by a,b;
+select * from t2 order by a,b;
+select * from t3 order by a,b;
+select * from t4 order by a,b;
+select * from t5 order by a,b;
+drop table if exists t6, t5, t4, t3, t2, t1;
diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test
new file mode 100644
index 00000000000..11697f794a9
--- /dev/null
+++ b/mysql-test/t/multi_update.test
@@ -0,0 +1,53 @@
+#
+# Only run the test if we are using --big-test, because this test takes a
+# long time
+#
+#-- require r/big_test.require
+#eval select $BIG_TEST as using_big_test;
+
+drop table if exists t1,t2,t3;
+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;
+update t1,t2,t3 set t1.t="aaa", t2.t="bbb", t3.t="cc" where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 90;
+delete t1.*, t2.*, t3.* from t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 95;
+
+check table t1, t2, t3;
+
+select count(*) from t1 where id1 > 95;
+select count(*) from t2 where id2 > 95;
+select count(*) from t3 where id3 > 95;
+
+delete t1, t2, t3 from t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 5;
+select count(*) from t1 where id1 > 5;
+select count(*) from t2 where id2 > 5;
+select count(*) from t3 where id3 > 5;
+
+delete from t1, t2, t3 using t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 0;
+
+# These queries will force a scan of the table
+select count(*) from t1 where id1;
+select count(*) from t2 where id2;
+select count(*) from t3 where id3;
+
+drop table t1,t2,t3;
diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test
index eb1d9a01020..861bc807323 100644
--- a/mysql-test/t/myisam.test
+++ b/mysql-test/t/myisam.test
@@ -24,11 +24,13 @@ drop table t1;
create table t1 (a tinyint not null auto_increment, b blob not null, primary key (a));
let $1=100;
+disable_query_log;
while ($1)
{
eval insert into t1 (b) values(repeat(char(65+$1),65550-$1));
dec $1;
}
+enable_query_log;
check table t1;
repair table t1;
delete from t1 where (a & 1);
diff --git a/mysql-test/t/null.test b/mysql-test/t/null.test
index a010ab38e07..8bd9e806118 100644
--- a/mysql-test/t/null.test
+++ b/mysql-test/t/null.test
@@ -25,7 +25,6 @@ drop table t1;
# Test problem med index on NULL columns and testing with =NULL;
#
-DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (
indexed_field int default NULL,
KEY indexed_field (indexed_field)
diff --git a/mysql-test/t/openssl_1.test b/mysql-test/t/openssl_1.test
new file mode 100644
index 00000000000..8dfd0d8c2f9
--- /dev/null
+++ b/mysql-test/t/openssl_1.test
@@ -0,0 +1,6 @@
+# We test openssl. Result set is optimized to be compiled with --with-openssl but
+# SSL is swithced off in some reason
+-- source include/have_openssl_2.inc
+
+SHOW STATUS LIKE 'SSL%';
+
diff --git a/mysql-test/t/openssl_2.test b/mysql-test/t/openssl_2.test
new file mode 100644
index 00000000000..12f1240f3af
--- /dev/null
+++ b/mysql-test/t/openssl_2.test
@@ -0,0 +1,5 @@
+# We want to test everything with SSL turned on.
+-- source include/have_openssl_2.inc
+
+SHOW STATUS LIKE 'SSL%';
+
diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test
index 16094206745..baa3fe67f0b 100644
--- a/mysql-test/t/order_by.test
+++ b/mysql-test/t/order_by.test
@@ -206,8 +206,53 @@ ORDER by lastchange_datum DESC LIMIT 2;
drop table t1;
#
-# Test optimizing bug with EQ_REF tables, where some ORDER BY parts where
-# wrongly removed.
+# Test optimization of ORDER BY DESC
+#
+
+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;
+select * from t1 where (a = 1 and b is null and c = 'b') or (a > 2) order by a desc;
+explain select * from t1 where a >= 1 and a < 3 order by a desc;
+select * from t1 where a >= 1 and a < 3 order by a desc;
+explain select * from t1 where a = 1 order by a desc, b desc;
+select * from t1 where a = 1 order by a desc, b desc;
+explain select * from t1 where a = 1 and b is null order by a desc, b desc;
+select * from t1 where a = 1 and b is null order by a desc, b desc;
+explain select * from t1 where a >= 1 and a < 3 and b >0 order by a desc,b desc;
+explain select * from t1 where a = 2 and b >0 order by a desc,b desc;
+explain select * from t1 where a = 2 and b is null order by a desc,b desc;
+explain select * from t1 where a = 2 and (b is null or b > 0) order by a
+desc,b desc;
+explain select * from t1 where a = 2 and b > 0 order by a desc,b desc;
+explain select * from t1 where a = 2 and b < 2 order by a desc,b desc;
+
+#
+# Test things when we don't have NULL keys
+#
+
+alter table t1 modify b int not null, modify c varchar(10) not null;
+explain select * from t1 order by a, b, c;
+select * from t1 order by a, b, c;
+explain select * from t1 order by a desc, b desc, c desc;
+select * from t1 order by a desc, b desc, c desc;
+# test multiple ranges, NO_MAX_RANGE and EQ_RANGE
+explain select * from t1 where (a = 1 and b = 1 and c = 'b') or (a > 2) order by a desc;
+select * from t1 where (a = 1 and b = 1 and c = 'b') or (a > 2) order by a desc;
+# test NEAR_MAX, NO_MIN_RANGE
+explain select * from t1 where a < 2 and b <= 1 order by a desc, b desc;
+select * from t1 where a < 2 and b <= 1 order by a desc, b desc;
+select count(*) from t1 where a < 5 and b > 0;
+select * from t1 where a < 5 and b > 0 order by a desc,b desc;
+# test HA_READ_AFTER_KEY (at the end of the file), NEAR_MIN
+explain select * from t1 where a between 1 and 3 and b <= 1 order by a desc, b desc;
+select * from t1 where a between 1 and 3 and b <= 1 order by a desc, b desc;
+# test HA_READ_AFTER_KEY (in the middle of the file)
+explain select * from t1 where a between 0 and 1 order by a desc, b desc;
+select * from t1 where a between 0 and 1 order by a desc, b desc;
+drop table t1;
+
CREATE TABLE t1 (
gid int(10) unsigned NOT NULL auto_increment,
diff --git a/mysql-test/t/order_fill_sortbuf-master.opt b/mysql-test/t/order_fill_sortbuf-master.opt
new file mode 100644
index 00000000000..116494d4588
--- /dev/null
+++ b/mysql-test/t/order_fill_sortbuf-master.opt
@@ -0,0 +1 @@
+--set-variable=sort_buffer=0
diff --git a/mysql-test/t/order_fill_sortbuf.test b/mysql-test/t/order_fill_sortbuf.test
new file mode 100644
index 00000000000..6419f2a93df
--- /dev/null
+++ b/mysql-test/t/order_fill_sortbuf.test
@@ -0,0 +1,21 @@
+#
+# This test does a create-select with ORDER BY, where there is so many
+# rows MySQL needs to use a merge during the sort phase.
+#
+
+drop table if exists t1,t2;
+CREATE TABLE `t1` (
+ `id` int(11) NOT NULL default '0',
+ `id2` int(11) NOT NULL default '0',
+ `id3` int(11) NOT NULL default '0');
+let $1=4000;
+disable_query_log;
+while ($1)
+ {
+ eval insert into t1 (id,id2,id3) values ($1,$1,$1);
+ dec $1;
+ }
+enable_query_log;
+create table t2 select id2 from t1 order by id3;
+select count(*) from t2;
+drop table t1,t2;
diff --git a/mysql-test/t/query_cache-master.opt b/mysql-test/t/query_cache-master.opt
new file mode 100644
index 00000000000..cfdce628e74
--- /dev/null
+++ b/mysql-test/t/query_cache-master.opt
@@ -0,0 +1 @@
+--set-variable=query_cache_size=1355776
diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test
new file mode 100644
index 00000000000..b4d00639587
--- /dev/null
+++ b/mysql-test/t/query_cache.test
@@ -0,0 +1,336 @@
+#
+# Tests with query cache
+#
+
+# Reset query cache variables.
+
+flush query cache; # This crashed in some versions
+flush query cache; # This crashed in some versions
+reset query cache;
+flush status;
+drop table if exists t1,t2,t3,t11,t21, mysqltest.t1;
+
+#
+# First simple test
+#
+
+create table t1 (a int not null);
+insert into t1 values (1),(2),(3);
+select * from t1;
+select * from t1;
+select sql_no_cache * from t1;
+select length(now()) from t1;
+
+# Only check the variables that are independent of the machine and startup
+# options
+
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+
+drop table t1;
+
+show status like "Qcache_queries_in_cache";
+
+#
+# MERGE TABLES with INSERT/UPDATE and DELETE
+#
+create table t1 (a int not null);
+insert into t1 values (1),(2),(3);
+create table t2 (a int not null);
+insert into t2 values (4),(5),(6);
+create table t3 (a int not null) type=MERGE UNION=(t1,t2) INSERT_METHOD=FIRST;
+# insert
+select * from t3;
+select * from t3;
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+insert into t2 values (7);
+show status like "Qcache_queries_in_cache";
+select * from t1;
+select * from t1;
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+insert into t3 values (8);
+show status like "Qcache_queries_in_cache";
+# update
+select * from t3;
+show status like "Qcache_queries_in_cache";
+update t2 set a=9 where a=7;
+show status like "Qcache_queries_in_cache";
+select * from t1;
+show status like "Qcache_queries_in_cache";
+update t3 set a=10 where a=1;
+show status like "Qcache_queries_in_cache";
+#delete
+select * from t3;
+show status like "Qcache_queries_in_cache";
+delete from t2 where a=9;
+show status like "Qcache_queries_in_cache";
+select * from t1;
+show status like "Qcache_queries_in_cache";
+delete from t3 where a=10;
+show status like "Qcache_queries_in_cache";
+drop table t1, t2, t3;
+#
+# FLUSH QUERY CACHE
+#
+create table t1 (a int not null);
+insert into t1 values (1),(2),(3);
+create table t2 (a int not null);
+insert into t2 values (1),(2),(3);
+select * from t1;
+select * from t2;
+insert into t1 values (4);
+show status like "Qcache_free_blocks";
+flush query cache;
+show status like "Qcache_free_blocks";
+drop table t1, t2;
+# With join results...
+create table t1 (a text not null);
+create table t11 (a text not null);
+create table t2 (a text not null);
+create table t21 (a text not null);
+create table t3 (a text not null);
+insert into t1 values("1111111111111111111111111111111111111111111111111111");
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+# t11 and t21 must be over 4Kb (QUERY_CACHE_MIN_RESULT_DATA_SIZE)
+insert into t11 select * from t1;
+insert into t21 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+#results of t3 must be > 0.5Mb
+insert into t3 select * from t1;
+insert into t3 select * from t2;
+insert into t3 select * from t1;
+disable_result_log;
+select * from t11;
+select * from t21;
+enable_result_log;
+show status like "Qcache_total_blocks";
+show status like "Qcache_free_blocks";
+disable_result_log;
+insert into t11 values("");
+select * from t3;
+enable_result_log;
+show status like "Qcache_total_blocks";
+show status like "Qcache_free_blocks";
+flush query cache;
+show status like "Qcache_total_blocks";
+show status like "Qcache_free_blocks";
+drop table t1, t2, t3, t11, t21;
+#
+# SELECT SQL_CACHE ...
+#
+set sql_query_cache_type=demand;
+create table t1 (a int not null);
+insert into t1 values (1),(2),(3);
+select * from t1;
+show status like "Qcache_queries_in_cache";
+select sql_cache * from t1;
+set sql_query_cache_type=2;
+select sql_cache * from t1;
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+set sql_query_cache_type=on;
+#
+# RESET QUERY CACHE
+#
+reset query cache;
+show status like "Qcache_queries_in_cache";
+#
+# SELECT SQL_NO_CACHE
+#
+select sql_no_cache * from t1;
+show status like "Qcache_queries_in_cache";
+drop table t1;
+#
+# Check that queries that uses NOW(), LAST_INSERT_ID()... are not cached.
+#
+create table t1 (a text not null);
+select CONNECTION_ID() from t1;
+#GET_LOCK
+#RELEASE_LOCK
+#LOAD_FILE
+select FOUND_ROWS();
+select NOW() from t1;
+select CURDATE() from t1;
+select CURTIME() from t1;
+select DATABASE() from t1;
+select ENCRYPT("test") from t1;
+select LAST_INSERT_ID() from t1;
+select RAND() from t1;
+select UNIX_TIMESTAMP() from t1;
+select USER() from t1;
+select benchmark(1,1) from t1;
+show status like "Qcache_queries_in_cache";
+#
+# Tests when the cache is filled
+#
+create table t2 (a text not null);
+insert into t1 values("1111111111111111111111111111111111111111111111111111");
+insert into t2 select * from t1;
+insert into t1 select * from t2; # 2
+insert into t2 select * from t1; # 3
+insert into t1 select * from t2; # 5
+insert into t2 select * from t1; # 8
+insert into t1 select * from t2; # 13
+insert into t2 select * from t1; # 21
+insert into t1 select * from t2; # 34
+insert into t2 select * from t1; # 55
+insert into t1 select * from t2; # 89
+insert into t2 select * from t1; # 144
+insert into t1 select * from t2; # 233
+insert into t2 select * from t1; # 357
+insert into t1 select * from t2; # 610
+insert into t2 select * from t1; # 987
+insert into t1 select * from t2; # 1597
+insert into t2 select * from t1; # 2584
+insert into t1 select * from t2; # 4181
+
+show status like "Qcache_hits";
+disable_result_log;
+select a as a1, a as a2 from t1;
+select a as a2, a as a3 from t1;
+select a as a3, a as a4 from t1;
+# next query must be out of 1Mb cache
+select a as a1, a as a2 from t1;
+enable_result_log;
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+reset query cache;
+#
+# Query bigger then query_cache_limit
+#
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+disable_result_log;
+select * from t1;
+enable_result_log;
+show status like "Qcache_queries_in_cache";
+drop table t1,t2;
+
+#
+# noncachable ODBC work around (and prepare cache for drop database)
+#
+create database if not exists mysqltest;
+create table mysqltest.t1 (i int not null auto_increment, a int, primary key (i));
+insert into mysqltest.t1 (a) values (1);
+select * from mysqltest.t1 where i is null;
+
+#
+# drop db
+#
+select * from mysqltest.t1;
+show status like "Qcache_queries_in_cache";
+drop database mysqltest;
+show status like "Qcache_queries_in_cache";
+
+#
+# Charset convertion (cp1251_koi8 always present)
+#
+create table t1 (a char(1) not null);
+insert into t1 values("á");
+select * from t1;
+set CHARACTER SET cp1251_koi8;
+select * from t1;
+set CHARACTER SET DEFAULT;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+drop table t1;
+
+# The following tests can't be done as the values differen on 32 and 64 bit
+# machines :(
+#show variables like "query_cache_size";
+#show status like "Qcache_free_memory";
+
+#
+# same tables in different db
+#
+create database if not exists mysqltest;
+create table mysqltest.t1 (i int not null);
+create table t1 (i int not null);
+insert into mysqltest.t1 (i) values (1);
+insert into t1 (i) values (2);
+
+select * from t1;
+use mysqltest;
+select * from t1;
+select * from t1;
+use test;
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+drop database mysqltest;
+drop table t1;
+
+#
+# FOUND_ROWS()
+#
+
+create table t1 (i int not null);
+insert into t1 (i) values (1),(2),(3),(4);
+
+select SQL_CALC_FOUND_ROWS * from t1 limit 2;
+select FOUND_ROWS();
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+
+select * from t1 where i=1;
+select FOUND_ROWS();
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+
+select SQL_CALC_FOUND_ROWS * from t1 limit 2;
+select FOUND_ROWS();
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+
+select * from t1 where i=1;
+select FOUND_ROWS();
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+drop table t1;
+
+#
+# Test insert delayed
+#
+
+flush query cache;
+reset query cache;
+
+create table t1 (a int not null);
+insert into t1 values (1),(2),(3);
+select * from t1;
+select * from t1;
+show status like "Qcache_queries_in_cache";
+insert delayed into t1 values (4);
+--sleep 5 # Wait for insert delayed to be executed.
+select a from t1;
+show status like "Qcache_queries_in_cache";
+drop table t1;
+show status like "Qcache_queries_in_cache";
diff --git a/mysql-test/t/rename.test b/mysql-test/t/rename.test
index 2a9cf113a47..ce4651d8de3 100644
--- a/mysql-test/t/rename.test
+++ b/mysql-test/t/rename.test
@@ -12,13 +12,19 @@ select * from t1;
rename table t3 to t4, t2 to t3, t1 to t2, t4 to t1;
rename table t3 to t4, t2 to t3, t1 to t2, t4 to t1;
select * from t1;
+
# The following should give errors
-!$1050 rename table t1 to t2;
-!$1050 rename table t1 to t1;
-!$1050 rename table t3 to t4, t2 to t3, t1 to t2, t4 to t2;
+--error 1050,1050
+rename table t1 to t2;
+--error 1050,1050
+rename table t1 to t1;
+--error 1050,1050
+rename table t3 to t4, t2 to t3, t1 to t2, t4 to t2;
show tables like "t_";
-!$1050 rename table t3 to t1, t2 to t3, t1 to t2, t4 to t1;
-!$1017 rename table t3 to t4, t5 to t3, t1 to t2, t4 to t1;
+--error 1050,1050
+rename table t3 to t1, t2 to t3, t1 to t2, t4 to t1;
+--error 1017,1017
+rename table t3 to t4, t5 to t3, t1 to t2, t4 to t1;
select * from t1;
select * from t2;
diff --git a/mysql-test/t/rpl000001.test b/mysql-test/t/rpl000001.test
index 113a9637dac..a5496d505f0 100644
--- a/mysql-test/t/rpl000001.test
+++ b/mysql-test/t/rpl000001.test
@@ -1,11 +1,15 @@
+eval_result;
source include/master-slave.inc;
connection master;
use test;
drop table if exists t1,t3;
create table t1 (word char(20) not null);
load data infile '../../std_data/words.dat' into table t1;
-set password = password('foo');
-set password = password('');
+--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
+eval load data local infile '$MYSQL_TEST_DIR/std_data/words.dat' into table t1;
+select * from t1;
+set password for root@"localhost" = password('foo');
+set password for root@"localhost" = password('');
create table t3(n int);
insert into t3 values(1),(2);
save_master_pos;
@@ -24,21 +28,38 @@ sync_with_master;
connection master;
reset master;
connection slave;
+slave stop;
reset slave;
connection master;
drop table if exists t1,t2;
create table t1(n int);
-let $1=10;
+#we want the log to exceed 16K to test deal with the log that is bigger than
+#IO_SIZE
+let $1=5000;
+disable_query_log;
while ($1)
{
- eval insert into t1 values($1);
+ eval insert into t1 values($1+get_lock("hold_slave",10)*0);
dec $1;
}
+enable_query_log;
+
+#try to cause a large relay log lag on the slave
+connection slave;
+select get_lock("hold_slave",10);
+slave start;
+#hope this is long enough for I/O thread to fetch over 16K relay log data
+sleep 1;
+select release_lock("hold_slave");
+unlock tables;
+
+connection master;
create table t2(id int);
insert into t2 values(connection_id());
save_master_pos;
+
connection master1;
#avoid generating result
create temporary table t1_temp(n int);
@@ -57,7 +78,7 @@ reap;
connection slave;
sync_with_master ;
#give the slave a chance to exit
-sleep 0.5;
+wait_for_slave_to_stop;
# The following test can't be done because the result of Pos will differ
# on different computers
diff --git a/mysql-test/t/rpl000002.test b/mysql-test/t/rpl000002.test
index 0c490e6316d..420ae27a337 100644
--- a/mysql-test/t/rpl000002.test
+++ b/mysql-test/t/rpl000002.test
@@ -1,4 +1,5 @@
source include/master-slave.inc;
+eval_result;
connection master;
use test;
drop table if exists t1;
@@ -11,6 +12,7 @@ use test;
sync_with_master;
select * from t1;
connection master;
+show slave hosts;
drop table t1;
save_master_pos;
connection slave;
diff --git a/mysql-test/t/rpl000009.test b/mysql-test/t/rpl000009.test
index 768c6c151b4..208e6f0b037 100644
--- a/mysql-test/t/rpl000009.test
+++ b/mysql-test/t/rpl000009.test
@@ -31,3 +31,56 @@ connection slave;
sync_with_master;
drop database if exists bar;
drop database if exists foo;
+
+#now let's test load data from master
+
+#first create some databases and tables on the master
+connection master;
+set sql_log_bin = 0;
+create database foo;
+create database bar;
+show databases;
+create table foo.t1(n int, s char(20));
+create table foo.t2(n int, s text);
+insert into foo.t1 values (1, 'one'), (2, 'two'), (3, 'three');
+insert into foo.t2 values (11, 'eleven'), (12, 'twelve'), (13, 'thirteen');
+
+create table bar.t1(n int, s char(20));
+create table bar.t2(n int, s text);
+insert into bar.t1 values (1, 'one bar'), (2, 'two bar'), (3, 'three bar');
+insert into bar.t2 values (11, 'eleven bar'), (12, 'twelve bar'),
+ (13, 'thirteen bar');
+set sql_log_bin = 1;
+save_master_pos;
+connection slave;
+sync_with_master;
+
+#this should show that the slave is empty at this point
+show databases;
+load data from master;
+
+#now let's check if we have the right tables and the right data in them
+show databases;
+use foo;
+show tables;
+use bar;
+show tables;
+select * from bar.t1;
+select * from bar.t2;
+
+#now let's see if replication works
+connection master;
+insert into bar.t1 values (4, 'four bar');
+save_master_pos;
+connection slave;
+sync_with_master;
+select * from bar.t1;
+
+#now time for cleanup
+connection master;
+drop database bar;
+drop database foo;
+save_master_pos;
+connection slave;
+sync_with_master;
+
diff --git a/mysql-test/t/rpl000014.test b/mysql-test/t/rpl000014.test
index b501d63b10e..a673a23dde2 100644
--- a/mysql-test/t/rpl000014.test
+++ b/mysql-test/t/rpl000014.test
@@ -4,18 +4,18 @@ show master status;
save_master_pos;
connection slave;
sync_with_master;
---replace_result 9306 9999 3334 9999 3335 9999
+--replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT
show slave status;
change master to master_log_pos=73;
slave stop;
change master to master_log_pos=73;
---replace_result 9306 9999 3334 9999 3335 9999
+--replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT
show slave status;
slave start;
---replace_result 9306 9999 3334 9999 3335 9999
+--replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT
show slave status;
change master to master_log_pos=173;
---replace_result 9306 9999 3334 9999 3335 9999
+--replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT
show slave status;
connection master;
show master status;
@@ -25,7 +25,7 @@ create table foo (n int);
insert into foo values (1),(2),(3);
save_master_pos;
connection slave;
-change master to master_log_pos=73;
+change master to master_log_pos=79;
sync_with_master;
select * from foo;
connection master;
diff --git a/mysql-test/t/rpl000015.test b/mysql-test/t/rpl000015.test
index 73a10bed7b3..8fd04613ab8 100644
--- a/mysql-test/t/rpl000015.test
+++ b/mysql-test/t/rpl000015.test
@@ -1,22 +1,25 @@
-connect (master,localhost,root,,test,0,mysql-master.sock);
-connect (slave,localhost,root,,test,0, mysql-slave.sock);
+connect (master,localhost,root,,test,0,master.sock);
+connect (slave,localhost,root,,test,0, slave.sock);
connection master;
reset master;
show master status;
save_master_pos;
connection slave;
reset slave;
+--replace_result $MASTER_MYPORT MASTER_PORT
show slave status;
change master to master_host='127.0.0.1';
---replace_result 3306 9998 9306 9999 3334 9999 3335 9999
+# The following needs to be cleaned up when change master is fixed
+--replace_result $MASTER_MYPORT MASTER_PORT 3306 MASTER_PORT 3334 MASTER_PORT
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 9306 9999 3334 9999 3335 9999
+--replace_result $MASTER_MYPORT MASTER_PORT
show slave status;
slave start;
sync_with_master;
---replace_result 9306 9999 3334 9999 3335 9999
+--replace_result $MASTER_MYPORT MASTER_PORT
show slave status;
connection master;
drop table if exists t1;
@@ -31,4 +34,3 @@ drop table t1;
save_master_pos;
connection slave;
sync_with_master;
-
diff --git a/mysql-test/t/rpl000016-slave.opt b/mysql-test/t/rpl000016-slave.opt
new file mode 100644
index 00000000000..f27601e0d7d
--- /dev/null
+++ b/mysql-test/t/rpl000016-slave.opt
@@ -0,0 +1 @@
+-O max_binlog_size=2048
diff --git a/mysql-test/t/rpl000016-slave.sh b/mysql-test/t/rpl000016-slave.sh
index 62748605af1..9259f593e54 100755
--- a/mysql-test/t/rpl000016-slave.sh
+++ b/mysql-test/t/rpl000016-slave.sh
@@ -1 +1,2 @@
rm -f $MYSQL_TEST_DIR/var/slave-data/master.info
+rm -f $MYSQL_TEST_DIR/var/slave-data/*relay*
diff --git a/mysql-test/t/rpl000016.test b/mysql-test/t/rpl000016.test
index c9b6ccabcd2..7559b2d3515 100644
--- a/mysql-test/t/rpl000016.test
+++ b/mysql-test/t/rpl000016.test
@@ -1,14 +1,16 @@
-connect (master,localhost,root,,test,0,mysql-master.sock);
-connect (slave,localhost,root,,test,0,mysql-slave.sock);
+connect (master,localhost,root,,test,0,master.sock);
+connect (slave,localhost,root,,test,0,slave.sock);
system cat /dev/null > var/slave-data/master.info;
system chmod 000 var/slave-data/master.info;
connection slave;
!slave start;
system chmod 600 var/slave-data/master.info;
!slave start;
+--replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT
!eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT,
master_user='root';
reset slave;
+--replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT
eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT,
master_user='root';
connection master;
@@ -22,7 +24,7 @@ insert into t1 values('Could not break slave'),('Tried hard');
save_master_pos;
connection slave;
sync_with_master;
---replace_result 9306 9999 3334 9999 3335 9999
+--replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT
show slave status;
select * from t1;
connection master;
@@ -49,8 +51,7 @@ insert into t2 values(NULL);
connection slave;
sync_with_master;
-#the slave may have already stopped, so we ignore the error
-!slave stop;
+wait_for_slave_to_stop;
#restart slave skipping one event
set sql_slave_skip_counter=1;
@@ -69,19 +70,21 @@ insert into t2 values (65);
save_master_pos;
connection slave;
sync_with_master;
---replace_result 9306 9999 3334 9999 3335 9999
+--replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT
show slave status;
select * from t2;
connection master;
let $1=100;
drop table if exists t3;
create table t3 (n int);
+disable_query_log;
while ($1)
{
#eval means expand $ expressions
eval insert into t3 values($1 + 4);
dec $1;
}
+enable_query_log;
show master logs;
show master status;
save_master_pos;
@@ -89,7 +92,7 @@ connection slave;
slave stop;
slave start;
sync_with_master;
---replace_result 9306 9999 3334 9999 3335 9999
+--replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT
show slave status;
# because of concurrent insert, the table may not be up to date
# if we do not lock
diff --git a/mysql-test/t/rpl000017-slave.sh b/mysql-test/t/rpl000017-slave.sh
index 0588859c591..066b4880cc1 100755
--- a/mysql-test/t/rpl000017-slave.sh
+++ b/mysql-test/t/rpl000017-slave.sh
@@ -1,3 +1,5 @@
+rm -f $MYSQL_TEST_DIR/var/log/*relay*
+rm -f $MYSQL_TEST_DIR/var/slave-data/relay-log.info
cat > $MYSQL_TEST_DIR/var/slave-data/master.info <<EOF
master-bin.001
4
@@ -6,4 +8,5 @@ replicate
aaaaaaaaaaaaaaabthispartofthepasswordisnotused
$MASTER_MYPORT
1
+0
EOF
diff --git a/mysql-test/t/rpl000017.test b/mysql-test/t/rpl000017.test
index 8e4e61cb9d6..011b6507e49 100644
--- a/mysql-test/t/rpl000017.test
+++ b/mysql-test/t/rpl000017.test
@@ -1,5 +1,5 @@
-connect (master,localhost,root,,test,0,mysql-master.sock);
-connect (slave,localhost,root,,test,0,mysql-slave.sock);
+connect (master,localhost,root,,test,0,master.sock);
+connect (slave,localhost,root,,test,0,slave.sock);
connection master;
reset master;
grant file on *.* to replicate@localhost identified by 'aaaaaaaaaaaaaaab';
diff --git a/mysql-test/t/rpl000018-master.sh b/mysql-test/t/rpl000018-master.sh
deleted file mode 100755
index e570f106ec6..00000000000
--- a/mysql-test/t/rpl000018-master.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-rm -f $MYSQL_TEST_DIR/var/master-data/master-bin.*
-cp $MYSQL_TEST_DIR/std_data/master-bin.001 $MYSQL_TEST_DIR/var/master-data/
-echo ./master-bin.001 > $MYSQL_TEST_DIR/var/master-data/master-bin.index
diff --git a/mysql-test/t/rpl000018.test b/mysql-test/t/rpl000018.test
index 44236323d1d..30d601bb375 100644
--- a/mysql-test/t/rpl000018.test
+++ b/mysql-test/t/rpl000018.test
@@ -1,5 +1,8 @@
-connect (master,localhost,root,,test,0,mysql-master.sock);
-connect (slave,localhost,root,,test,0,mysql-slave.sock);
+require_manager;
+connect (master,localhost,root,,test,0,master.sock);
+connect (slave,localhost,root,,test,0,slave.sock);
+server_stop master;
+server_start master;
connection slave;
reset slave;
slave start;
diff --git a/mysql-test/t/rpl_compat.test b/mysql-test/t/rpl_compat.test
new file mode 100644
index 00000000000..c9455c1e2d2
--- /dev/null
+++ b/mysql-test/t/rpl_compat.test
@@ -0,0 +1,86 @@
+eval_result;
+source include/master-slave.inc;
+connection master;
+require_version 3.23;
+use test;
+drop table if exists t1,t3;
+create table t1 (word char(20) not null);
+load data infile '../../std_data/words.dat' into table t1;
+select * from t1;
+set password for root@"localhost" = password('foo');
+set password for root@"localhost" = password('');
+create table t3(n int);
+insert into t3 values(1),(2);
+save_master_pos;
+connection slave;
+sync_with_master;
+use test;
+select * from t3;
+select sum(length(word)) from t1;
+connection master;
+drop table t1,t3;
+save_master_pos;
+connection slave;
+sync_with_master;
+
+#test handling of aborted connection in the middle of update
+connection master;
+reset master;
+connection slave;
+slave stop;
+reset slave;
+
+connection master;
+create table t1(n int);
+insert into t1 values (1),(2),(3);
+create table t2(id int);
+insert into t2 values(connection_id());
+save_master_pos;
+
+connection master1;
+#avoid generating result
+create temporary table t1_temp(n int);
+insert into t1_temp select get_lock('crash_lock%20C', 1) from t2;
+
+connection master;
+send update t1 set n = n + get_lock('crash_lock%20C', 2);
+connection master1;
+sleep 2;
+select (@id := id) - id from t2;
+kill @id;
+drop table t2;
+connection master;
+--error 1053;
+reap;
+connection slave;
+slave start;
+sync_with_master ;
+#now slave will hit an error
+wait_for_slave_to_stop;
+
+set sql_slave_skip_counter=1;
+slave start;
+select count(*) from t1;
+connection master1;
+drop table t1;
+create table t1 (n int);
+insert into t1 values(3456);
+use mysql;
+insert into user (Host, User, Password)
+ VALUES ("10.10.10.%", "blafasel2", password("blafasel2"));
+select select_priv,user from mysql.user where user = 'blafasel2';
+update user set Select_priv = "Y" where User="blafasel2";
+select select_priv,user from mysql.user where user = 'blafasel2';
+use test;
+save_master_pos;
+connection slave;
+sync_with_master;
+select n from t1;
+select select_priv,user from mysql.user where user = 'blafasel2';
+connection master1;
+drop table t1;
+save_master_pos;
+connection slave;
+sync_with_master;
+
+
diff --git a/mysql-test/t/rpl_failsafe.test b/mysql-test/t/rpl_failsafe.test
new file mode 100644
index 00000000000..866efbce5bf
--- /dev/null
+++ b/mysql-test/t/rpl_failsafe.test
@@ -0,0 +1,24 @@
+require_manager;
+source include/master-slave.inc;
+connect (slave_sec,localhost,root,,test,0,slave.sock-1);
+connect (slave_ter,localhost,root,,test,0,slave.sock-2);
+connection master;
+show variables like 'rpl_recovery_rank';
+show status like 'Rpl_status';
+create table t1(n int);
+drop table t1;
+save_master_pos;
+connection slave;
+sync_with_master;
+show variables like 'rpl_recovery_rank';
+show status like 'Rpl_status';
+connection slave_sec;
+slave start;
+sync_with_master;
+show variables like 'rpl_recovery_rank';
+show status like 'Rpl_status';
+connection slave_ter;
+slave start;
+sync_with_master;
+show variables like 'rpl_recovery_rank';
+show status like 'Rpl_status';
diff --git a/mysql-test/t/rpl_get_lock.test b/mysql-test/t/rpl_get_lock.test
index 3c33103e4c7..3fe45eecf46 100644
--- a/mysql-test/t/rpl_get_lock.test
+++ b/mysql-test/t/rpl_get_lock.test
@@ -6,6 +6,8 @@ dirty_close master;
connection master1;
select get_lock("lock",2);
select release_lock("lock");
+#ignore
+disable_query_log;
let $1=2000;
while ($1)
{
@@ -13,6 +15,7 @@ while ($1)
do release_lock("lock");
dec $1;
}
+enable_query_log;
save_master_pos;
connection slave;
sync_with_master;
diff --git a/mysql-test/t/rpl_log.test b/mysql-test/t/rpl_log.test
new file mode 100644
index 00000000000..3514d435737
--- /dev/null
+++ b/mysql-test/t/rpl_log.test
@@ -0,0 +1,57 @@
+source include/master-slave.inc;
+
+#clean up slave binlogs
+connection slave;
+slave stop;
+reset master;
+reset slave;
+let $VERSION=`select version()`;
+
+connection master;
+reset master;
+drop table if exists t1;
+create table t1(n int not null auto_increment primary key);
+insert into t1 values (NULL);
+drop table t1;
+create table t1 (word char(20) not null);
+load data infile '../../std_data/words.dat' into table 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;
+flush logs;
+create table t1 (n int);
+insert into t1 values (1);
+drop table t1;
+--replace_result $VERSION VERSION
+show binlog events;
+show binlog events in 'master-bin.002';
+show master logs;
+save_master_pos;
+connection slave;
+slave start;
+sync_with_master;
+show master logs;
+--replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT $VERSION VERSION
+# We can't compare binlog from slave as the result differ between
+# machines based on where the LOAD DATA file is stored.
+disable_result_log;
+
+show binlog events in 'slave-bin.001' from 4;
+--replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT $VERSION VERSION
+enable_result_log;
+show binlog events in 'slave-bin.002' from 4;
+--replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT
+show slave status;
+show new master for slave with master_log_file='master-bin.001' and
+ master_log_pos=4 and master_server_id=1;
+show new master for slave with master_log_file='master-bin.001' and
+ master_log_pos=79 and master_server_id=1;
+show new master for slave with master_log_file='master-bin.001' and
+ master_log_pos=311 and master_server_id=1;
+show new master for slave with master_log_file='master-bin.002' and
+ master_log_pos=4 and master_server_id=1;
+show new master for slave with master_log_file='master-bin.002' and
+ master_log_pos=122 and master_server_id=1;
diff --git a/mysql-test/t/rpl_magic.test b/mysql-test/t/rpl_magic.test
new file mode 100644
index 00000000000..376edc301d7
--- /dev/null
+++ b/mysql-test/t/rpl_magic.test
@@ -0,0 +1,31 @@
+source include/master-slave.inc;
+
+#first, make sure the slave has had enough time to register
+connection master;
+save_master_pos;
+connection slave;
+sync_with_master;
+
+#discover slaves
+connection master;
+rpl_probe;
+
+#turn on master/slave query direction auto-magic
+enable_rpl_parse;
+drop table if exists t1;
+create table t1 ( n int);
+insert into t1 values (1),(2),(3),(4);
+disable_rpl_parse;
+save_master_pos;
+enable_rpl_parse;
+connection slave;
+sync_with_master;
+insert into t1 values(5);
+connection master;
+select * from t1;
+select * from t1;
+disable_rpl_parse;
+select * from t1;
+connection slave;
+select * from t1;
+drop table t1;
diff --git a/mysql-test/t/rpl_mystery22.test b/mysql-test/t/rpl_mystery22.test
index 3a48ef84dc1..e987074697b 100644
--- a/mysql-test/t/rpl_mystery22.test
+++ b/mysql-test/t/rpl_mystery22.test
@@ -1,5 +1,6 @@
# test case to make slave thread get ahead by 22 bytes
+drop table if exists t1;
source include/master-slave.inc;
connection master;
# first, cause a duplicate key problem on the slave
diff --git a/mysql-test/t/rpl_sporadic_master.test b/mysql-test/t/rpl_sporadic_master.test
index c1a47781ddf..0487f868436 100644
--- a/mysql-test/t/rpl_sporadic_master.test
+++ b/mysql-test/t/rpl_sporadic_master.test
@@ -7,7 +7,7 @@ drop table if exists t1,t2;
create table t2(n int);
create table t1(n int not null auto_increment primary key);
insert into t1 values (NULL),(NULL);
-delete from t1;
+truncate table t1;
# We have to use 4 in the following to make this test work with all table types
insert into t1 values (4),(NULL);
save_master_pos;
@@ -18,10 +18,8 @@ slave start;
connection master;
insert into t1 values (NULL),(NULL);
flush logs;
-delete from t1;
-insert into t1 values (10),(NULL);
-insert into t1 values (NULL),(NULL);
-insert into t1 values (NULL),(NULL);
+truncate table t1;
+insert into t1 values (10),(NULL),(NULL),(NULL),(NULL),(NULL);
save_master_pos;
connection slave;
sync_with_master;
diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test
index cdb6ee57e0f..ab4251fe536 100644
--- a/mysql-test/t/select.test
+++ b/mysql-test/t/select.test
@@ -1713,6 +1713,12 @@ show full columns from t2 from test like 's%';
show keys from t2;
#
+# Test of DO
+
+DO 1;
+DO benchmark(100,1+1),1,1;
+
+#
# Drop the test tables
#
diff --git a/mysql-test/t/select_found.test b/mysql-test/t/select_found.test
new file mode 100644
index 00000000000..d6b6284a88b
--- /dev/null
+++ b/mysql-test/t/select_found.test
@@ -0,0 +1,34 @@
+#
+# Testing of found_rows()
+#
+
+drop table if exists t1;
+create table t1 (a int not null auto_increment, b int not null, primary key(a));
+insert into t1 (b) values (2),(3),(5),(5),(5),(6),(7),(9);
+select SQL_CALC_FOUND_ROWS * from t1;
+select found_rows();
+select SQL_CALC_FOUND_ROWS * from t1 limit 1;
+select found_rows();
+select SQL_BUFFER_RESULT SQL_CALC_FOUND_ROWS * from t1 limit 1;
+select found_rows();
+select SQL_CALC_FOUND_ROWS * from t1 order by b desc limit 1;
+select found_rows();
+select SQL_CALC_FOUND_ROWS distinct b from t1 limit 1;
+select found_rows();
+select SQL_CALC_FOUND_ROWS b,count(*) as c from t1 group by b order by c desc limit 1;
+select found_rows();
+select SQL_CALC_FOUND_ROWS * from t1 left join t1 as t2 on (t1.b=t2.a) limit 2,1;
+select found_rows();
+drop table t1;
+
+#
+# Test SQL_CALC_FOUND_ROWS optimization when used with one table and filesort
+#
+
+create table t1 (a int not null primary key);
+insert into t1 values (1),(2),(3),(4),(5);
+select sql_calc_found_rows a from t1 where a in (1,2,3) order by a desc limit 0,2;
+select FOUND_ROWS();
+select sql_calc_found_rows a from t1 where a in (1,2,3) order by a+2 desc limit 0,2;
+select FOUND_ROWS();
+drop table t1;
diff --git a/mysql-test/t/show_check.test b/mysql-test/t/show_check.test
index 0f07d577c0c..a2b7fa381ee 100644
--- a/mysql-test/t/show_check.test
+++ b/mysql-test/t/show_check.test
@@ -1,30 +1,17 @@
#
# Test of some show commands
#
-drop table if exists t1,t2;
-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 type=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;
+drop table if exists t1,t2;
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);
-check table t1 type=fast;
-check table t1 type=fast;
-check table t1 type=changed;
+check table t1 fast;
+check table t1 fast;
+check table t1 changed;
insert into t1 values (5,5,5);
-check table t1 type=changed;
-check table t1 type=medium;
-check table t1 type=extended;
+check table t1 changed;
+check table t1 medium;
+check table t1 extended;
show index from t1;
!$1062 insert into t1 values (5,5,5);
optimize table t1;
@@ -72,3 +59,18 @@ drop table t1;
create table t1 (a int not null, primary key (a));
show create table t1;
drop table t1;
+
+flush tables;
+show open tables;
+create table t1(n int);
+insert into t1 values (1);
+show open tables;
+drop table t1;
+
+create table t1 (a int not null, b VARCHAR(10), INDEX (b) ) AVG_ROW_LENGTH=10 CHECKSUM=1 COMMENT="test" TYPE=MYISAM MIN_ROWS=10 MAX_ROWS=100 PACK_KEYS=1 DELAY_KEY_WRITE=1 ROW_FORMAT=fixed;
+show create table t1;
+alter table t1 MAX_ROWS=200 ROW_FORMAT=dynamic PACK_KEYS=0;
+show create table t1;
+ALTER TABLE t1 AVG_ROW_LENGTH=0 CHECKSUM=0 COMMENT="" MIN_ROWS=0 MAX_ROWS=0 PACK_KEYS=DEFAULT DELAY_KEY_WRITE=0 ROW_FORMAT=default;
+show create table t1;
+drop table t1;
diff --git a/mysql-test/t/status.test b/mysql-test/t/status.test
index 70a7a3ab584..cffca437cf1 100644
--- a/mysql-test/t/status.test
+++ b/mysql-test/t/status.test
@@ -1,3 +1,11 @@
+# This test doesn't work with the embedded version as this code
+# assumes that one query is running while we are doing queries on
+# a second connection.
+# This would work if mysqltest run would be threaded and handle each
+# connection in a separate thread.
+#
+-- source include/not_embedded.inc
+
connect (con1,localhost,root,,);
connect (con2,localhost,root,,);
@@ -6,7 +14,7 @@ show status like 'Table_lock%';
connection con1;
SET SQL_LOG_BIN=0;
drop table if exists t1;
-create table t1(n int);
+create table t1(n int) type=myisam;
insert into t1 values(1);
connection con2;
lock tables t1 read;
diff --git a/mysql-test/t/symlink.test b/mysql-test/t/symlink.test
new file mode 100644
index 00000000000..586761921b8
--- /dev/null
+++ b/mysql-test/t/symlink.test
@@ -0,0 +1,89 @@
+-- require r/have_symlink.require
+disable_query_log;
+show variables like "have_symlink";
+enable_query_log;
+
+#
+# First create little data to play with
+#
+drop table if exists t1,t2,t7,t8,t9;
+create table t1 (a int not null auto_increment, b char(16) not null, primary key (a));
+create table t2 (a int not null auto_increment, b char(16) not null, primary key (a));
+insert into t1 (b) values ("test"),("test1"),("test2"),("test3");
+insert into t2 (b) select b from t1;
+insert into t1 (b) select b from t2;
+insert into t2 (b) select b from t1;
+insert into t1 (b) select b from t2;
+insert into t2 (b) select b from t1;
+insert into t1 (b) select b from t2;
+insert into t2 (b) select b from t1;
+insert into t1 (b) select b from t2;
+insert into t2 (b) select b from t1;
+insert into t1 (b) select b from t2;
+insert into t2 (b) select b from t1;
+insert into t1 (b) select b from t2;
+insert into t2 (b) select b from t1;
+insert into t1 (b) select b from t2;
+insert into t2 (b) select b from t1;
+insert into t1 (b) select b from t2;
+insert into t2 (b) select b from t1;
+insert into t1 (b) select b from t2;
+drop table t2;
+
+#
+# Start the test
+# We use t9 here to not crash with tables generated by the backup test
+#
+
+disable_query_log;
+eval create table t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam data directory="$MYSQL_TEST_DIR/var/tmp" index directory="$MYSQL_TEST_DIR/var/run";
+enable_query_log;
+
+insert into t9 select * from t1;
+check table t9;
+optimize table t9;
+repair table t9;
+alter table t9 add column c int not null;
+show create table t9;
+
+# Test renames
+alter table t9 rename t8, add column d int not null;
+alter table t8 rename t7;
+rename table t7 to t9;
+# Drop old t1 table, keep t9
+drop table t1;
+
+#
+# Test error handling
+# Note that we are using the above table t9 here!
+#
+
+disable_query_log;
+--error 1103,1103
+create table t1 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam data directory="tmp";
+
+# Check that we cannot link over a table from another database.
+
+drop database if exists test_mysqltest;
+create database test_mysqltest;
+
+--error 1,1
+create table test_mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam index directory="/this-dir-does-not-exist";
+
+--error 1103,1103
+create table test_mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam index directory="not-hard-path";
+
+--error 1,1
+eval create table test_mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam index directory="$MYSQL_TEST_DIR/var/run";
+
+--error 1,1
+eval create table test_mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam data directory="$MYSQL_TEST_DIR/var/tmp";
+enable_query_log;
+
+# Check moving table t9 from default database to test_mysqltest;
+# In this case the symlinks should be removed.
+
+alter table t9 rename test_mysqltest.t9;
+select count(*) from test_mysqltest.t9;
+show create table test_mysqltest.t9;
+drop database test_mysqltest;
diff --git a/mysql-test/t/tablelock.test b/mysql-test/t/tablelock.test
index c32a3f7cd35..fa8c4f03675 100644
--- a/mysql-test/t/tablelock.test
+++ b/mysql-test/t/tablelock.test
@@ -2,6 +2,7 @@
# Test of lock tables
#
+drop table if exists t1,t2;
create table t1 ( n int auto_increment primary key);
lock tables t1 write;
insert into t1 values(NULL);
@@ -36,12 +37,10 @@ drop table t1;
CREATE TABLE t1 (a int);
CREATE TABLE t2 (a int);
lock tables t1 write,t1 as b write, t2 write, t2 as c read;
-drop table t1;
-drop table t2;
+drop table t1,t2;
CREATE TABLE t1 (a int);
CREATE TABLE t2 (a int);
lock tables t1 write,t1 as b write, t2 write, t2 as c read;
-drop table t2;
-drop table t1;
+drop table t2,t1;
unlock tables;
diff --git a/mysql-test/t/truncate.test b/mysql-test/t/truncate.test
index e995517cf1e..2430682a93f 100644
--- a/mysql-test/t/truncate.test
+++ b/mysql-test/t/truncate.test
@@ -2,10 +2,14 @@
# Test of truncate
#
create table t1 (a integer, b integer,c1 CHAR(10));
+insert into t1 (a) values (1),(2);
truncate table t1;
select count(*) from t1;
insert into t1 values(1,2,"test");
select count(*) from t1;
+delete from t1;
+select * from t1;
drop table t1;
# The following should fail
-!$1146 select count(*) from t1;
+--error 1146
+select count(*) from t1;
diff --git a/mysql-test/t/type_datetime.test b/mysql-test/t/type_datetime.test
index 1e7bd11bab1..857937fd90e 100644
--- a/mysql-test/t/type_datetime.test
+++ b/mysql-test/t/type_datetime.test
@@ -30,3 +30,12 @@ CREATE TABLE t1 (a datetime not null);
insert into t1 values (0);
select * from t1 where a is null;
drop table t1;
+
+#
+# Test with bug when propagating DATETIME to integer and WHERE optimization
+#
+
+create table t1 (id int, dt datetime);
+insert into t1 values (1,"2001-08-14 00:00:00"),(2,"2001-08-15 00:00:00"),(3,"2001-08-16 00:00:00");
+select * from t1 where dt='2001-08-14 00:00:00' and dt = if(id=1,'2001-08-14 00:00:00','1999-08-15');
+drop table t1;
diff --git a/mysql-test/t/type_enum.test b/mysql-test/t/type_enum.test
index 0278f53c642..62d83388a67 100644
--- a/mysql-test/t/type_enum.test
+++ b/mysql-test/t/type_enum.test
@@ -2,6 +2,7 @@
# Problem with many enums
#
+DROP TABLE if exists t1;
CREATE TABLE t1 (
field enum('001001','001004','001010','001018','001019','001020','001021','001027','001028','001029','001030','001031','001100','002003','002004','002005','002007','002008','002009','002012','002013','002014','003002','003003','003004','003005','003006','003007','003008','003009','003010','003011','003012','003013','003014','003015','003016','003017','003018','003019','004002','004003','004005','004006','004007','004008','004010','004012','004014','004016','004017','004020','004021','004022','004023','004024','004025','004026','006002','006004','006006','006010','006011','006012','006013','006014','007001','007002','007003','007004','007005','007006','007007','007008','007009','007010','007011','007012','007013','007014','007015','007016','007017','007018','007019','007020','007021','007022','007023','007024','007025','007026','007027','007028','007029','007030','007031','007032','007033','007034','007035','007036','007037','007038','007039','007040','007043','007044','009001','009002','009004','009005','009006','009007','009008','009009','009010','009011','009012','009013','010002','010003','010004','010005','010006','010007','010008','010009','010010','010011','010012','010013','010015','010016','010017','010018','010019','010020','010021','010022','010023','010024','010025','010026','010027','010028','011001','011002','011003','011004','011006','011012','011013','011014','011015','011016','012017','012018','012019','012023','012027','012028','012029','012030','012031','012032','012033','012034','012035','012036','012037','012038','012039','014001','016002','016003','016004','016007','016010','016011','016016','016019','016020','016021','016022','016023','016024','016026','016027','016028','016029','016030','016031','016032','016033','016034','017002','018001','019002','019004','020001','020003','020004','020005','020006','020007','020008','020009','022001','022002','022003','023001','023002','023003','023004','023005','023006','023007','023008','023010','023011','023012','023017','023019','023020','023021','023025','023026','023027','023028','023029','023030','023031','023032','023033','023034','023035','025001','025003','025004','025005','025006','025007','025008','025009','025010','025011','025012','025013','025014','025015','025016','025017','025018','025019','025020','025021','025022','025023','025024','025025','025026','025027','025028','025029','025030','025031','025032','025033','025034','025035','025036','025037','025038','025039','025040','025041','025042','025043','025044','025045','025046','025047','025048','025049','025050','025051','025052','025053','025054','025055','025056','025057','025058','025059','025060','025061','025062','025063','027001','027002','027011','035008','035012','036001','037001','037003','037004','037005','037006','037007','037008','037009','038004','038005','038006','038007','038009','039001','039002','039003','039004','039005','039006','046001','046002','046003','046004','046005','046007','046008','046009','046010','046011','046012','046013','046014','047001','047002','048001','051001','051002','051003','051004','052001','052002','052005','053015','053016','053019','053020','053023','053024','053026','053028','053029','053033','053034','053036','053037','053038','053039','053041','053042','053043','053045','053046','053047','053048','053051','053052','053054','053055','053056','053057','053068','053069','053070','053073','053074','053075','053086','053094','053095','053096','053097','053098','053099','053100','053101','053102','053103','053104','053105','053107','053122','053123','053124','053125','053127','053128','054001','054002','054003','054004','054005','054006','054007','054009','054010','056001','056002','056003','056004','056005','056006','056009','056010','056011','056016','056017','056018','056019','056020','056021','056022','057001','057002','057003','057004','058002','058003','058004','058005','060001','060003','060004','060005','060006','060007','061002','061003','061004','061005','061006','069006','069007','069010','069011','069012','069013','069014','069015','069016','069017','069018','069020','069021','069022','069023','069024','071002','071003','071004','071005','071006','071008','071011','071013','071020','071021','071022','072001','073001','073002','073003','073004','074001','074002','074003','074004','074005','074006','074007','074008','074009','074010','074011','074012','075001','075007','076101','076102','076103','077001','077002','077003','077004','077006','077007','077008','077009','078005','079002','079003','079004','079005','079006','079007','081001','082006','082007','082011','082013','082014','082015','082016','082017','082021','082022','082023','082024','082025','082026','082027','082028','082029','082030','082031','082032','082033','082034','082035','082036','082037','082038','082039','082040','082041','082042','082043','082044','084001','084002','084003','084004','084005','084007','084008','084009','084011','084013','084014','084016','084017','084027','084031','084032','084033','084035','084036','084037','084038','084039','084040','084041','084042','084043','084044','084045','084046','084047','084048','084049','084050','084051','085001','085002','085003','085004','085005','085006','085007','085009','085011','085012','085013','085014','085015','085016','085017','085018','085019','085020','085021','085022','085023','085028','085029','085030','085031','085033','085034','085035','085036','085037','085038','085040','085041','085042','085043','085044','085045','085046','085047','085048','085063','085064','085065','085068','085070','085071','085073','085082','085083','085086','085088','085089','085090','085091','085092','085093','085094','085095','085096','085097','085098','085099','085100','085101','085102','085103','085104','085105','085106','085107','085108','085109','085110','085111','085112','085113','085115','085119','085120','085121','085122','085123','085124','085125','085126','085127','085128','085129','085130','085132','085133','085134','085135','085136','085137','086001','086002','086003','086004','086005','088001','088003','088005','088006','088007','088008','088009','089001','090001','090002','090003','090004','090005','090006','090007','090008','090009','090010','090013','090015','090016','090017','090018','090019','090022','090027','090028','091001','091002','091005','091008','091009','091010','091011','091012','091013','091014','091015','091016','091017','091018','093001','093003','093098','093100','093102','093104','093141','093142','093146','093151','093153','093167','093168','093176','094001','094002','094004','094005','095004','099001','099002','100001','101001','102002','102003','105001','105002','106001','113001','113002','113003','113004','113005','113006','113007','113008','113009','113010','113011','113012','113013','113014','113015','113016','113017','113018','113019','113020','113021','113022','113023','113024','113025','113026','113027','113028','114001','115001','115002','115003','115004','115005','115006','115007','115008','115009','115010','115011','115012','115013','115014','115015','115016','115017','115018','115020','115021','115022','115023','115025','115026','115027','115028','115029','115030','115031','115032','115033','115034','115035','115036','115039','115040','115041','115042','115043','115044','115045','115046','115047','115048','115049','115050','115051','115052','115053','115054','115055','115056','115057','115059','115060','115061','115062','115063','115064','115065','115066','115067','115068','115069','115070','115071','115072','115073','115075','115076','115081','115082','115085','115086','115087','115088','115095','115096','115097','115098','115099','115101','115102','115103','115104','115105','115106','115108','115109','115110','115111','115112','115113','115114','115115','115116','115117','115118','115119','115120','115121','115122','116001','116002','116003','116004','116005','116006','116007','116008','116009','116010','116011','116012','117001','117002','117003','123001','124010','124014','124015','124019','124024','124025','124026','124027','124028','124029','124030','124031','124032','124033','124035','124036','124037','124038','124039','124040','124041','124042','124043','124044','124045','124046','124047','124048','124049','124050','124051','124052','124053','124054','124055','124056','124057','124058','124059','124060','124061','124062','124063','124064','124065','126001','126002','126003','126004','126005','126006','126007','126008','126009','126010','126011','126012','130001','132001','132002','132003','133001','133008','133009','133010','133011','133012','133013','133014','133015','133016','133017','133018','133019','133020','133021','133022','133023','133024','133025','133027','133028','133029','133030','133031','134001','135001','135002','135003','135004','135005','135006','135007','135008','135009','135010','136001','137009','137010','137011','137012','137013','137014','137015','137016','137017','137018','137019','138001','138002','138003','138004','139001','139003','140001','141001','141002','141003','141006','141007','141008','141009','141011','141012','141014','141015','141016','141017','141018','141019','141020','141021','141022','141023','141024','141025','141026','141027','141028','142001','142002','142003','142004','142005','142006','142007','142008','142010','142011','142012','144001','145001','145002','145003','145004','145005','145006','145007','145008','145009','145010','145011','145012','145013','145014','145015','145016','147001','150003','150005','150009','150013','150014','150015','150016','150017','150020','150021','152001','152002','152003','152004','152005','152006','152007','154001','154002','154003','155001','155002','155003','155004','155005','155006','159001','159002','159003','159004','160001','160002','160003','161001','162001','162002','162003','162004','162007','162010','162011','162012','163001','163002','163003','163005','163010','163011','163014','163015','163016','165001','165002','165003','165004','165005','165006','165007','165008','165009','165010','165011','165012','165013','165014','165015','165016','165017','165018','165019','165020','165021','165022','165023','165024','165025','165026','165027','165028','165029','165030','165031','165032','165033','165034','165035','165036','167001','168001','168002','168003','168004','168005','168007','168008','168009','168010','168011','168012','168013','168014','169001','169002','169003','169007','169008','169009','169010','170001','171001','171002','171003','171004','171005','171006','171007','171008','171009','172001','174001','174002','174003','176001','176002','176003','177001','177002','179001','179002','179003','179004','179005','179006','179007','179008','179009','179010','179011','179012','179013','179014','179015','179016','179017','179018','179019','179020','179021','179022','179023','179024','179025','179026','179027','179028','179029','179030','179031','179032','179033','179034','179035','179036','179037','179038','179039','179040','179041','179042','179043','179044','179045','179046','179047','180001','180010','180012','180013','180014','180015','180016','180017','180018','180019','180020','180021','180022','180023','180024','180025','180026','180027','180028','180030','180031','180032','180033','180034','180035','180036','180037','180038','180039','180041','180042','180043','180044','180045','180046','180047','180048','180049','180050','180051','180052','180053','180054','180055','180056','180057','180058','180059','180060','180061','180062','180063','180064','180065','180066','180067','180068','180069','180070','180071','182001','184001','184002','184005','184006','184007','184008','184009','184010','184011','185001','185003','187001','188001','188002','188003','188004','188005','188006','188007','188008','188009','188010','188011','191001','191002','192002','194001','194002','194003','194004','194005','194006','194007','195001','195002','195003','195004','195005','195006','195007','196001','196002','197001','197002','197003','197004','197005','197006','198001','198003','198004','198005','198006','198007','198008','198009','198010','198011','198012','198013','198014','198015','198016','198017','201001','201002','201005','202001','203001','203002','203003','203017','203018','203019','204001','204002','204003','205001','208001','208002','208003','208004','208005','209001','209002','209003','210001','210002','210003','210004','210005','210006','210007','210008','210009','210010','210011','210012','210013','211017','212001','212002','212003','212004','212005','212006','212007','212008','212009','212010','212011','212012','212013','218001','218003','218004','218006','218007','218008','218009','218011','218015','218016','218017','218018','218019','218020','218021','218022','218023','218024','218025','218026','218027','218028','218029','218030','218031','218032','218033','218034','218035','218036','221001','221002','221003','221004','221005','221006','221007','221008','221009','221010','221011','221012','221013','223001','223002','223003','224001','224002','224003','224006','224007','224008','225001','225002','225003','225004','225005','225006','225007','225008','225009','225010','225011','225012','225013','226001','226002','226003','226004','226005','226006','226007','226008','226009','227001','227002','227003','227004','227005','227006','227007','227008','227009','227010','227011','227012','227013','227014','227015','227016','227017','227018','227019','227020','227021','227022','227023','227024','227025','227026','227027','227028','227029','227030','227031','227032','227033','227034','227035','227036','227037','227038','227039','227040','227041','227042','227043','227044','227045','227046','227047','227048','227049','227050','227051','227052','227053','227054','227055','227056','227057','227058','227059','227060','227061','227062','227063','227064','227065','227066','227067','227068','227069','227070','227071','227072','227073','227074','227075','227076','227077','227078','227079','227080','227081','227082','227083','227084','227085','227086','227087','227088','227089','227090','227091','227092','227093','227094','227095','227096','227097','227098','227099','227100','227101','227102','227103','227104','227105','227106','227107','227108','227109','227110','227111','227112','227113','227114','227115','227116','227117','227118','227119','227120','227122','227123','227124','227125','227126','227127','227128','227129','227130','227131','227132','227133','227134','227135','227136','227137','227138','227139','227140','227141','227142','227143','227144','227145','227146','227147','227148','227149','227150','227151','227152','228001','229001','229002','229003','229004','229005','230001','230002','232001','233001','233002','233003','233004','233005','233006','233007','233008','234001','234002','234003','234004','234005','234006','234007','234008','234009','234010','234011','234012','234013','234014','234015','234016','234017','234018','234019','234020','234021','234022','234023','234024','234025','234026','234027','234028','234029','234030','235001','235002','235003','235004','235005','236001','236002','236003','237001','238002','238003','238004','238005','238006','238007','238008','333013','333014','333015','333016','333017','333018','333019','333020','333021','333022','333023','333024','333025','333030','333031','333032','333033','333034','333035','334001','334002','334003','334004','334005','334006','334007','336004','337001','337002','337003','337004','339001','339002','343001','344001','344002','344003','344004','344005','345001','345002','345003','347001','347002','348001','348002','348003','348004','348005','349001','349002','349003','350001','353001','353002','353003','353004','355001','355002','355003','355004','355005','355006','356001','358001','359001','359002','360001','360002','360003','360004','360005','366001','366002','366003','366004','369001','373001','373002','373003','373004','373005','373006','373007','373008','373009','373010','373011','373012','373013','373014','373015','373016','373017','373018','373019','373020','373021','374001','374002','374003','374004','374005','374006','374007','374008','374009','374010','374011','374012','374013','374014','374015','374016','376001','376002','376003','376004','376005','376006','376007','376008','376009','376010','376011','376012','376013','376016','376017','376018','376019','376020','376021','379003','382001','382002','383001','384001','384002','385001','385002','386001','386002','386003','386004','386005','386006','386007','386008','386009','386010','386011','386012','386013','386014','387001','389001','389002','389003','389004','392001','393001','393002','393003','393004','395001','396001','397001','397002','399001','399002','399003','400001','400002','401001','401002','401003','402001','402002','402003','402004','402005','403001','403002','403003','504001','504002','504004','504005','504006','504007','504008','504009','504010','504011','504012','504013','504014','504017','504018','504019','504021','504022','504023','504024','504025','506001','506002','508001','508002','511001','511002','511003','511004','511005','511006','511007','511008','511009','511010','511011','511012','511013','511014','511017','511018','511020','511021','511022','511024','511028','511029','513001','513002','513003','513004','514001','515001','515002','515003','515007','515008','515009','515010','515011','515012','515013','515014','515015','518001','518002','518003','520001','520002','521001','521002','521003','521004','521005','521006','521007','521008','521009','521010','521011','521012','521013','521014','521015','521016','523001','523002','523003','523004','523005','523006','523007','524001','700001','701001','701002','701003','702001','702002','702003','702004','702005','702006','702007','702008','703001','703002','703003','704001','704002','704003','704004','705001','706001','706002','707001','707002','707003','708001','709001','709002','710001','710002','711001','711002','712001','713001','713002','714001','714002','715001','716001','718001','718002','719001','719002','991001','991002','991003','991004','991005','991006','991007','991008','992001','995001','996001','996002','996003','998001','998002','998003','998004','998005','998006','998007','999001','999002','011017','011018','034001','034002','071010','208006','239001','519001','519003','126013','184012','053071','374017','374018','374019','374020','374021','404001','405002','405001','405003','405007','405006','405005','405004','240011','240010','240009','240008','240007','240006','240005','240004','240003','240002','240001','240012','240013','240014','240015','240016','240017','357001','235006','235007','712002','355008','355007','056023','999999','046015','019005','126014','241003','241002','241001','240018','240020','240019','242001','242002','242003','242004','242005','242006','089002','406001','406002','406003','406004','406005','406006','243001','243002','243003','243004','243005','243006','243007','243008','010030','010029','407001','407006','407005','407004','407003','407002','408001','366005','133032','016035','077010','996004','025064','011019','407007','407008','407009','409001','115123','504026','039007','039009','039008','039010','039011','039012','180072','240021','240023','408002','405008','235008','525001','525002','525003','525004','410001','410002','410003','410004','410005','410006','410007','410008','410009','410010','410011','410012','410013','410014','410015','410016','344006','240031','240030','240029','240028','240027','240026','240025','240024','240034','240033','240032','410017','410018','411001','411002','411003','411004','411005','411006','411007','411008','203020','203021','203022','412001','412002','412003','412004','069025','244001','244002','244009','244008','244007','244006','244005','244004','244003','244015','244014','244013','244012','244011','244010','244016','244017','240042','240041','240040','240039','240038','240037','240036','240035','405009','405010','240043','504034','504033','504032','504031','504030','504029','504028','504027','504042','504041','504040','504039','504038','504037','504036','504035','800001','410019','410020','410021','244018','244019','244020','399004','413001','504043','198018','198019','344007','082045','010031','010032','010033','010034','010035','504044','515016','801002','801003','801004','801005','802001','801001','414001','414002','414003','141029','141030','803001','803002','803003','803004','803005','803006','803007','803008','803009','803010','803011','803012','803013','803014','803015','803016','803017','410022','410023','803018','803019','803020','415002','415001','244021','011020','011023','011022','011021','025065','165037','165038','165039','416001','416002','416003','417001','418001','504045','803022','803021','240022','419001','420001','804010','804009','804008','804007','804006','804005','804004','804003','804002','804001','804020','804019','804018','804017','804016','804015','804014','804013','804012','804011','804024','804021','804023','804022','511019','511016','511015','511032','511031','511030','511027','511026','511025','511033','511023','133034','133033','169011','344008','344009','244022','244026','244025','244030','244023','244024','244027','244028','244029','244031','082046','082047','082048','126015','126016','416004','416005','421001','421002','016037','016036','115124','115125','115126','240049','240048','240047','240046','240045','240044','244032','244033','422001','422002','422003','422004','422005','184013','239002','805001','805002','805003','805004','805005','056024','423001','344010','235009','212014','056025','056026','802002','244034','244035','244036','244037','244038','244039','515017','504046','203015','245002','245001','071023','056027','056028','056029','056030','056031','056032','424001','056034','056033','805006','805007','805008','805009','805010','422008','422007','422006','422010','422009','422011','209004','150022','150023','100002','056035','023036','185004','185005','246001','247001','247002','425001','416006','165042','165041','165040','165043','010040','010039','010038','010037','010036','422012','422013','422014','422015','426000','248001','248002','248003','248004','248005','249001','249002','249003','249004','249005','249006','250007','250001','250002','250003','250004','250005','250006','250008','250009','250010','250011','250012','250013','251001','251002','422016','422017','422018','806001','806002','116013','235010','235011','091026','091027','091028','091029','091019','091020','091021','091022','091023','091024','091025','252001','243009','249007','249008','249009','011024','011025','427001','428002','428001','169012','429001','429002','429003') DEFAULT '001001' NOT NULL,
KEY field (field)
diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test
new file mode 100644
index 00000000000..f782c61d97a
--- /dev/null
+++ b/mysql-test/t/union.test
@@ -0,0 +1,79 @@
+#
+# Test of unions
+#
+
+drop table if exists t1,t2,t3;
+CREATE TABLE t1 (a int not null, b char (10) not null);
+insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c');
+CREATE TABLE t2 (a int not null, b char (10) not null);
+insert into t2 values (3,'c'),(4,'d'),(5,'f'),(6,'e');
+
+select a,b from t1 union select a,b from t2;
+select a,b from t1 union all select a,b from t2;
+select a,b from t1 union all select a,b from t2 order by b;
+select a,b from t1 union all select a,b from t2 union select 7,'g';
+select 0,'#' union select a,b from t1 union all select a,b from t2 union select 7,'gg';
+select a,b from t1 union select a,b from t1;
+select 't1',b,count(*) from t1 group by b UNION select 't2',b,count(*) from t2 group by b;
+
+#test alternate syntax for unions
+(select a,b from t1 limit 2) union all (select a,b from t2 order by a) limit 4;
+(select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1);
+(select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by b desc;
+
+# Test some error conditions with UNION
+explain select a,b from t1 union all select a,b from t2;
+
+--error 1054
+explain select xx from t1 union select 1;
+explain select a,b from t1 union select 1;
+explain select 1 union select a,b from t1 union select 1;
+explain select a,b from t1 union select 1 limit 0;
+
+--error 1221
+select a,b from t1 into outfile 'skr' union select a,b from t2;
+
+--error 1221
+select a,b from t1 order by a union select a,b from t2;
+
+--error 1221
+insert into t3 select a from t1 order by a union select a from t2;
+
+--error 1222
+create table t3 select a,b from t1 union select a from t2;
+
+--error 1222
+select a,b from t1 union select a from t2;
+
+--error 1222
+select * from t1 union select a from t2;
+
+--error 1222
+select a from t1 union select * from t2;
+
+# Test CREATE, INSERT and REPLACE
+create table t3 select a,b from t1 union all select a,b from t2;
+insert into t3 select a,b from t1 union all select a,b from t2;
+replace into t3 select a,b as c from t1 union all select a,b from t2;
+
+drop table t1,t2,t3;
+
+#
+# Test bug reported by joc@presence-pc.com
+#
+
+CREATE TABLE t1 (
+ `pseudo` char(35) NOT NULL default '',
+ `pseudo1` char(35) NOT NULL default '',
+ `same` tinyint(1) unsigned NOT NULL default '1',
+ PRIMARY KEY (`pseudo1`),
+ KEY `pseudo` (`pseudo`)
+) TYPE=MyISAM;
+INSERT INTO t1 (pseudo,pseudo1,same) VALUES ('joce', 'testtt', 1),('joce', 'tsestset', 1),('dekad', 'joce', 1);
+SELECT pseudo FROM t1 WHERE pseudo1='joce' UNION SELECT pseudo FROM t1 WHERE pseudo='joce';
+SELECT pseudo1 FROM t1 WHERE pseudo1='joce' UNION SELECT pseudo1 FROM t1 WHERE pseudo='joce';
+SELECT * FROM t1 WHERE pseudo1='joce' UNION SELECT * FROM t1 WHERE pseudo='joce' order by pseudo desc,pseudo1 desc;
+SELECT pseudo1 FROM t1 WHERE pseudo='joce' UNION SELECT pseudo FROM t1 WHERE pseudo1='joce';
+SELECT pseudo1 FROM t1 WHERE pseudo='joce' UNION ALL SELECT pseudo FROM t1 WHERE pseudo1='joce';
+SELECT pseudo1 FROM t1 WHERE pseudo='joce' UNION SELECT 1;
+drop table t1;
diff --git a/mysql-test/t/update.test b/mysql-test/t/update.test
index 6f446a11521..5cbbd2a350e 100644
--- a/mysql-test/t/update.test
+++ b/mysql-test/t/update.test
@@ -76,3 +76,14 @@ alter table t1 change lfdnr lfdnr int(10) unsigned default 0 not null auto_incre
update t1 set status=1 where type='Open';
select status from t1;
drop table t1;
+
+#
+# Test of ORDER BY
+#
+
+create table t1 (a int not null, b int not null);
+insert into t1 values (1,1),(1,2),(1,3);
+update t1 set b=4 where a=1 order by b asc limit 1;
+update t1 set b=4 where a=1 order by b desc limit 1;
+select * from t1;
+drop table t1;
diff --git a/mysql-test/t/varbinary.test b/mysql-test/t/varbinary.test
index 0ab26f51e65..6d2660271ea 100644
--- a/mysql-test/t/varbinary.test
+++ b/mysql-test/t/varbinary.test
@@ -4,6 +4,7 @@
select 0x41,0x41+0,0x41 | 0x7fffffffffffffff | 0,0xffffffffffffffff | 0 ;
select 0x31+1,concat(0x31)+1,-0xf;
+select x'31',X'ffff'+0;
#
# Test of hex constants in WHERE:
@@ -14,3 +15,18 @@ insert into t1 set UNIQ=0x38afba1d73e6a18a;
insert into t1 set UNIQ=123;
explain select * from t1 where UNIQ=0x38afba1d73e6a18a;
drop table t1;
+
+#
+# Test error conditions
+#
+--error 1064
+select x'hello';
+--error 1054
+select 0xfg;
+
+#
+# Test likely error conditions
+#
+create table t1 select 1 as x, 2 as xx;
+select x,xx from t1;
+drop table t1;
diff --git a/mysql-test/xml/README b/mysql-test/xml/README
deleted file mode 100644
index ee1af30db33..00000000000
--- a/mysql-test/xml/README
+++ /dev/null
@@ -1,74 +0,0 @@
-This directory contains all of the test cases for the MySQL Test Suite
-marked up in XML.
-
-To convert these test cases from XML into 'mysqltest' format, one needs
-an XSL translator installed on their system. At MySQL, we use Sablotron
-(http://www.gingerall.com/). Once installed, conversion happens with a
-command like this:
-
- sabcmd xsl/mysqltest.xsl < tests/sel000001.xml > sel000001.test
-
-The file 'sel000001.test' contains the plain text conversion that is
-to be fed into the 'mysqltest' program.
-
-Below is an example of a test case marked up in XML; illustrating all
-of the XML mark-up currently supported in our 'mysqltest.xsl' stylesheet.
-
-----------------------------------------------------
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000001">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>This test will monkey around trying to kill mysqld.</description>
-
- <connect name="Test_Connect1"
- host="MyHostName"
- user="Matt"
- pass="MattPass"
- db="MyDB"
- port="3306"
- sock="MyDB.sock"
- />
-
- <connection name="Test_Connect1">
- <resultfile name="sel000001.result">
- <sql>SELECT y FROM foo WHERE bar='2'</sql>
- </resultfile>
- <sql>INSERT INTO foo VALUES (y='2') WHERE bar='1'</sql>
- </connection>
-
-</test>
-----------------------------------------------------
-
-
-The converted (mysqltest format) output of this source XML file looks
-like:
-
-
-----------------------------------------------------
-# sel000001
-#
-# Versions
-# --------
-# 3.22
-# 3.23
-#
-# Description
-# -----------
-# This test will monkey around trying to kill mysqld.
-#
-
-
-connect(Test_Connect1, MyHostName, Matt, MattPass, MyDB, 3306, MyDB.sock)
-
-connection Test_Connect1
-INSERT INTO foo VALUES (y='2') WHERE bar='1';
-@sel000001.result SELECT y FROM foo WHERE bar='2';
-----------------------------------------------------
-
-
diff --git a/mysql-test/xml/tests/sel000001.xml b/mysql-test/xml/tests/sel000001.xml
deleted file mode 100644
index 7ce4dae8ee1..00000000000
--- a/mysql-test/xml/tests/sel000001.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000001">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>This test is just a simple select.</description>
- <description>Testing WHERE clause.</description>
-
- <sql>DROP TABLE IF EXISTS t</sql>
- <sql>CREATE TABLE t (s CHAR(20) PRIMARY KEY, id INT)</sql>
- <sql>INSERT INTO t VALUES ('cat', 1), ('mouse', 3), ('dog', 2), ('snake', 77)</sql>
-
- <resultfile name="r/3.23/sel000001.result">
- <sql>SELECT s, id FROM t WHERE s = 'mouse'</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000002.xml b/mysql-test/xml/tests/sel000002.xml
deleted file mode 100644
index 902233cbbf0..00000000000
--- a/mysql-test/xml/tests/sel000002.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000002">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>This test is just a simple select.</description>
-
- <sql>DROP TABLE IF EXISTS t</sql>
- <sql>CREATE TABLE t (n INT)</sql>
- <sql>INSERT INTO t VALUES (1), (2), (3)</sql>
-
- <resultfile name="r/3.23/sel000002.result">
- <sql>SELECT * FROM t</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000003.xml b/mysql-test/xml/tests/sel000003.xml
deleted file mode 100644
index c9334c972d8..00000000000
--- a/mysql-test/xml/tests/sel000003.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000003">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>This test is just a simple select.</description>
- <description>Testing count() function and GROUP BY clause.</description>
-
- <sql>DROP TABLE IF EXISTS t</sql>
- <sql>CREATE TABLE t (name CHAR(20) NOT NULL PRIMARY KEY, score SMALLINT NOT NULL, KEY(score))</sql>
- <sql>INSERT INTO t VALUES ('Sasha', 20), ('Matt', 20), ('Monty', 10), ('David', 10), ('Tim', 10), ('Jeremy', 10)</sql>
-
- <resultfile name="r/3.23/sel000003.result">
- <sql>SELECT COUNT(*) as n, score FROM t GROUP BY score</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000004.xml b/mysql-test/xml/tests/sel000004.xml
deleted file mode 100644
index 9c28c632c32..00000000000
--- a/mysql-test/xml/tests/sel000004.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000004">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>Simple arithmetic.</description>
- <description>Testing MOD(), SIGN(), and arithmetic grouping.</description>
-
- <resultfile name="r/3.23/sel000004.result">
- <sql>SELECT 1+1,1-1,1+1*2,8/5,8%5,MOD(8,5),MOD(8,5)|0,-(1+1)*-2,SIGN(-5)</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000005.xml b/mysql-test/xml/tests/sel000005.xml
deleted file mode 100644
index 0bcddb2fbb6..00000000000
--- a/mysql-test/xml/tests/sel000005.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000005">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>Numeric functions.</description>
- <description>Testing FLOOR(), CEILING(), ROUND().</description>
-
- <resultfile name="r/3.23/sel000005.result">
- <sql>SELECT FLOOR(5.5),FLOOR(-5.5),CEILING(5.5),CEILING(-5.5),ROUND(5.5),ROUND(-5.5)</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000006.xml b/mysql-test/xml/tests/sel000006.xml
deleted file mode 100644
index 3059f8bb7df..00000000000
--- a/mysql-test/xml/tests/sel000006.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000006">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>Numeric functions.</description>
- <description>Testing ROUND(); hundreths precision.</description>
-
- <resultfile name="r/3.23/sel000006.result">
- <sql>SELECT ROUND(5.64,1),ROUND(5.64,2),ROUND(5.64,-1),ROUND(5.64,-2)</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000007.xml b/mysql-test/xml/tests/sel000007.xml
deleted file mode 100644
index 8f8bb7162c3..00000000000
--- a/mysql-test/xml/tests/sel000007.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000007">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>Numeric functions.</description>
- <description>Testing TRUNCATE().</description>
-
- <resultfile name="r/3.23/sel000007.result">
- <sql>SELECT TRUNCATE(52.64,1),TRUNCATE(52.64,2),TRUNCATE(52.64,-1),TRUNCATE(52.64,-2)</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000008.xml b/mysql-test/xml/tests/sel000008.xml
deleted file mode 100644
index 70a54a15d5b..00000000000
--- a/mysql-test/xml/tests/sel000008.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000008">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>Numeric functions.</description>
- <description>Testing ABS(), LOG(), LOG10(), EXP(), SQRT(), POW(), RAND(), POWER().</description>
-
- <resultfile name="r/3.23/sel000008.result">
- <sql>SELECT ABS(-10),LOG(EXP(10)),EXP(LOG(SQRT(10))*2),POW(10,LOG10(10)),RAND(999999),RAND(),POWER(2,4)</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000009.xml b/mysql-test/xml/tests/sel000009.xml
deleted file mode 100644
index 0c79f032112..00000000000
--- a/mysql-test/xml/tests/sel000009.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000009">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>Numeric functions.</description>
- <description>Testing PI(), SIN(), COS(), TAN(), COT(), ASIN(), ACOS(), ATAN().</description>
-
- <resultfile name="r/3.23/sel000009.result">
- <sql>SELECT PI(),SIN(PI()/2),COS(PI()/2),TAN(PI()),COT(1),ASIN(1),ACOS(0),ATAN(1)</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000010.xml b/mysql-test/xml/tests/sel000010.xml
deleted file mode 100644
index 6954fef0750..00000000000
--- a/mysql-test/xml/tests/sel000010.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000010">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>Numeric bitwise comparisons.</description>
- <description>Testing |, &amp;, BIT_COUNT().</description>
-
- <resultfile name="r/3.23/sel000010.result">
- <sql>SELECT 1 | (1+1),5 &amp; 3,BIT_COUNT(7)</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000011.xml b/mysql-test/xml/tests/sel000011.xml
deleted file mode 100644
index 5c981b2f85a..00000000000
--- a/mysql-test/xml/tests/sel000011.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000011">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>Numeric bitmoving comparisons.</description>
- <description>Testing &lt;&lt;, >>.</description>
-
- <resultfile name="r/3.23/sel000011.result">
- <sql>SELECT 1 &lt;&lt; 32,1 &lt;&lt; 63, 1 &lt;&lt; 64, 4 >> 2, 4 >> 63, 1&lt;&lt; 63 >> 60</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000012.xml b/mysql-test/xml/tests/sel000012.xml
deleted file mode 100644
index 7abcc498164..00000000000
--- a/mysql-test/xml/tests/sel000012.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000012">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>Numeric floating point.</description>
-
- <resultfile name="r/3.23/sel000012.result">
- <sql>SELECT 10,10.0,10.,.1e+2,100.0e-1</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000013.xml b/mysql-test/xml/tests/sel000013.xml
deleted file mode 100644
index fbeca6663fc..00000000000
--- a/mysql-test/xml/tests/sel000013.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000013">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>Numeric floating point.</description>
-
- <resultfile name="r/3.23/sel000013.result">
- <sql>SELECT 6e-05, -6e-05, --6e-05, -6e-05+1.000000</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000014.xml b/mysql-test/xml/tests/sel000014.xml
deleted file mode 100644
index 96a51e671fc..00000000000
--- a/mysql-test/xml/tests/sel000014.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000014">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>Numerics.</description>
- <description>Testing pos/neg and zero padding.</description>
-
- <resultfile name="r/3.23/sel000014.result">
- <sql>SELECT 0,256,00000000000000065536,2147483647,-2147483648,2147483648,+4294967296</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000015.xml b/mysql-test/xml/tests/sel000015.xml
deleted file mode 100644
index a339330e6b1..00000000000
--- a/mysql-test/xml/tests/sel000015.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000015">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>Numerics.</description>
- <description>Testing big numbers.</description>
-
- <resultfile name="r/3.23/sel000015.result">
- <sql>SELECT 922337203685477580,92233720368547758000</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000016.xml b/mysql-test/xml/tests/sel000016.xml
deleted file mode 100644
index ae971e6576a..00000000000
--- a/mysql-test/xml/tests/sel000016.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000016">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>Numerics.</description>
- <description>Testing big negative numbers.</description>
-
- <resultfile name="r/3.23/sel000016.result">
- <sql>SELECT -922337203685477580,-92233720368547758000</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000017.xml b/mysql-test/xml/tests/sel000017.xml
deleted file mode 100644
index 9d06d640ac3..00000000000
--- a/mysql-test/xml/tests/sel000017.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000017">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>Numerics.</description>
- <description>Testing big pos/neg numbers.</description>
-
- <resultfile name="r/3.23/sel000017.result">
- <sql>SELECT 9223372036854775807,-009223372036854775808</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000018.xml b/mysql-test/xml/tests/sel000018.xml
deleted file mode 100644
index 909728599fa..00000000000
--- a/mysql-test/xml/tests/sel000018.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000018">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>Numerics.</description>
- <description>Testing big pos/neg numbers.</description>
-
- <resultfile name="r/3.23/sel000018.result">
- <sql>SELECT +9999999999999999999,-9999999999999999999</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000019.xml b/mysql-test/xml/tests/sel000019.xml
deleted file mode 100644
index e0286ae2db7..00000000000
--- a/mysql-test/xml/tests/sel000019.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000019">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>Numerics.</description>
- <description>Testing DEGREES(), RADIANS().</description>
-
- <resultfile name="r/3.23/sel000019.result">
- <sql>SELECT DEGREES(PI()),RADIANS(360)</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000020.xml b/mysql-test/xml/tests/sel000020.xml
deleted file mode 100644
index 41ad5981cb9..00000000000
--- a/mysql-test/xml/tests/sel000020.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000020">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>Strings.</description>
- <description>Testing string comparisons; STRCMP(), =, >, >=, &lt;=, !=.</description>
-
- <resultfile name="r/3.23/sel000020.result">
- <sql>SELECT 0=0,1>0,1>=1,1&lt;0,1&lt;=0,1!=0,STRCMP("abc","abcd"),STRCMP("b","a"),STRCMP("a","a")</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000021.xml b/mysql-test/xml/tests/sel000021.xml
deleted file mode 100644
index ba2e8149abd..00000000000
--- a/mysql-test/xml/tests/sel000021.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000021">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>Strings.</description>
- <description>Testing string comparisons; =, >, >=, &lt;=, &lt;>.</description>
-
- <resultfile name="r/3.23/sel000021.result">
- <sql>SELECT "a"&lt;"b","a"&lt;="b","b">="a","b">"a","a"="A","a"&lt;>"b"</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000022.xml b/mysql-test/xml/tests/sel000022.xml
deleted file mode 100644
index 3dca0eb9b7f..00000000000
--- a/mysql-test/xml/tests/sel000022.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000022">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>Strings.</description>
- <description>Testing string comparisons; =, >, &lt;=.</description>
-
- <resultfile name="r/3.23/sel000022.result">
- <sql>SELECT "a "="A", "A "="a", "a " &lt;= "A b"</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000023.xml b/mysql-test/xml/tests/sel000023.xml
deleted file mode 100644
index 7cceb4aabca..00000000000
--- a/mysql-test/xml/tests/sel000023.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000023">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>Strings.</description>
- <description>Testing string comparisons; LIKE, NOT LIKE, '%'.</description>
-
- <resultfile name="r/3.23/sel000023.result">
- <sql>SELECT "abc" LIKE "a%", "abc" NOT LIKE "%d%", "a%" LIKE "a\%","abc%" LIKE "a%\%","abcd" LIKE "a%b_%d", "a" LIKE "%%a","abcde" LIKE "a%_e","abc" LIKE "abc%"</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000024.xml b/mysql-test/xml/tests/sel000024.xml
deleted file mode 100644
index 5bf9c0be7dc..00000000000
--- a/mysql-test/xml/tests/sel000024.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000024">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>Strings.</description>
- <description>Testing string comparisons; LIKE, '%'.</description>
-
- <resultfile name="r/3.23/sel000024.result">
- <sql>SELECT "a" LIKE "%%b","a" LIKE "%%ab","ab" LIKE "a\%", "ab" LIKE "_", "ab" LIKE "ab_", "abc" LIKE "%_d", "abc" LIKE "abc%d"</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000025.xml b/mysql-test/xml/tests/sel000025.xml
deleted file mode 100644
index 4144b65775f..00000000000
--- a/mysql-test/xml/tests/sel000025.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000025">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>Strings.</description>
- <description>Testing string comparisons; LIKE, ESCAPE, '%'.</description>
-
- <resultfile name="r/3.23/sel000025.result">
- <sql>SELECT '?' LIKE '|%', '?' LIKE '|%' ESCAPE '|', '%' LIKE '|%', '%' LIKE '|%' ESCAPE '|', '%' LIKE '%'</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000026.xml b/mysql-test/xml/tests/sel000026.xml
deleted file mode 100644
index afaa34009fa..00000000000
--- a/mysql-test/xml/tests/sel000026.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000026">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>Strings.</description>
- <description>Testing string comparisons; LIKE, '%'.</description>
-
- <resultfile name="r/3.23/sel000026.result">
- <sql>SELECT 'abc' LIKE '%c','abcabc' LIKE '%c', "ab" LIKE "", "ab" LIKE "a", "ab" LIKE "ab"</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000027.xml b/mysql-test/xml/tests/sel000027.xml
deleted file mode 100644
index 641d5d3a619..00000000000
--- a/mysql-test/xml/tests/sel000027.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000027">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>Strings.</description>
- <description>Testing string comparisons; REGEXP.</description>
-
- <resultfile name="r/3.23/sel000027.result">
- <sql>SELECT "Det här är svenska" REGEXP "h[[:alpha:]]+r", "aba" REGEXP "^(a|b)*$"</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000028.xml b/mysql-test/xml/tests/sel000028.xml
deleted file mode 100644
index c8db245c25d..00000000000
--- a/mysql-test/xml/tests/sel000028.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000028">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>Strings.</description>
- <description>Testing string comparisons; REGEXP, CONCAT().</description>
-
- <resultfile name="r/3.23/sel000028.result">
- <sql>SELECT "aba" REGEXP CONCAT("^","a")</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000029.xml b/mysql-test/xml/tests/sel000029.xml
deleted file mode 100644
index 84d12a44dc5..00000000000
--- a/mysql-test/xml/tests/sel000029.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000029">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>Strings.</description>
- <description>Testing string comparisons; NOT, AND, OR, !, &amp;&amp;, ||.</description>
-
- <resultfile name="r/3.23/sel000029.result">
- <sql>SELECT !0,NOT 0=1,!(0=0),1 AND 1,1 &amp;&amp; 0,0 OR 1,1 || NULL, 1=1 OR 1=1 AND 1=0</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/tests/sel000030.xml b/mysql-test/xml/tests/sel000030.xml
deleted file mode 100644
index 8a8a4d5e0d2..00000000000
--- a/mysql-test/xml/tests/sel000030.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!-- This file is maintained by matt@mysql.com -->
-
-<test name="sel000030">
-
- <version value="3.22"/>
- <version value="3.23"/>
-
- <description>Control flow.</description>
- <description>Testing control flow; IF()</description>
-
- <resultfile name="r/3.23/sel000030.result">
- <sql>SELECT IF(0,"ERROR","this"),IF(1,"is","ERROR"),IF(NULL,"ERROR","a"),IF(1,2,3)|0,IF(1,2.0,3.0)+0</sql>
- </resultfile>
-
-</test>
diff --git a/mysql-test/xml/xsl/README b/mysql-test/xml/xsl/README
deleted file mode 100644
index fe11b57cf11..00000000000
--- a/mysql-test/xml/xsl/README
+++ /dev/null
@@ -1,4 +0,0 @@
-XML Stylesheets for converting test cases in XML to other forms.
-
- - mysqltest.xsl -> mysqltest format (text)
-
diff --git a/mysql-test/xml/xsl/mysqltest.xsl b/mysql-test/xml/xsl/mysqltest.xsl
deleted file mode 100644
index 8a1e738e611..00000000000
--- a/mysql-test/xml/xsl/mysqltest.xsl
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0"?>
-<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
-
-<xsl:output method="text"/>
-
-<xsl:template match="/"><xsl:apply-templates /></xsl:template>
-
-<!-- Main Template -->
-
-<xsl:template match="/test"># <xsl:apply-templates select="@name"/>
-#
-# Versions
-# --------<xsl:apply-templates select="version"/>
-#
-# Description
-# -----------<xsl:apply-templates select="description"/>
-#
-
-<xsl:apply-templates select="connect"/>
-
-<xsl:apply-templates select="connection"/>
-
-<xsl:apply-templates select="sql"/>
-
-<xsl:apply-templates select="resultfile"/>
-
-</xsl:template>
-
-<!-- End Main Template -->
-
-
-<xsl:template match="version">
-# <xsl:apply-templates select="@value"/>
-</xsl:template>
-
-<xsl:template match="description">
-# <xsl:apply-templates />
-</xsl:template>
-
-<xsl:template match="connect">
-connect(<xsl:apply-templates select="@name"/>, <xsl:apply-templates select="@host"/>, <xsl:apply-templates select="@user"/>, <xsl:apply-templates select="@pass"/>, <xsl:apply-templates select="@db"/>, <xsl:apply-templates select="@port"/>, <xsl:apply-templates select="@sock"/>)
-</xsl:template>
-
-<xsl:template match="connection">
-<xsl:text>
-connection </xsl:text><xsl:apply-templates select="@name"/>
-<xsl:text>
-</xsl:text>
-<xsl:apply-templates select="sql"/>
-<xsl:apply-templates select="resultfile"/>
-</xsl:template>
-
-<xsl:template match="resultfile">@<xsl:apply-templates select="@name"/><xsl:text> </xsl:text><xsl:apply-templates select="sql"/>
-</xsl:template>
-
-<xsl:template match="sql">
-<xsl:apply-templates />;
-</xsl:template>
-</xsl:stylesheet>
diff --git a/mysys/Makefile.am b/mysys/Makefile.am
index 73cd9768013..287dc357b3d 100644
--- a/mysys/Makefile.am
+++ b/mysys/Makefile.am
@@ -24,7 +24,7 @@ LDADD = libmysys.a ../dbug/libdbug.a \
noinst_HEADERS = mysys_priv.h my_static.h
libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c\
mf_path.c mf_loadpath.c\
- my_open.c my_create.c my_seek.c my_read.c \
+ my_open.c my_create.c my_dup.c my_seek.c my_read.c \
my_pread.c my_write.c \
mf_keycache.c \
mf_iocache.c mf_iocache2.c mf_cache.c mf_tempfile.c \
@@ -35,7 +35,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c\
my_error.c errors.c my_div.c my_messnc.c \
mf_format.c mf_same.c mf_dirname.c mf_fn_ext.c \
my_symlink.c my_symlink2.c \
- mf_pack.c mf_pack2.c mf_unixpath.c mf_stripp.c \
+ mf_pack.c mf_unixpath.c mf_stripp.c \
mf_casecnv.c mf_soundex.c mf_wcomp.c mf_wfile.c \
mf_qsort.c mf_qsort2.c mf_sort.c \
ptr_cmp.c mf_radix.c queues.c \
@@ -44,9 +44,9 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c\
my_delete.c my_rename.c my_redel.c my_tempnam.c \
my_chsize.c my_lread.c my_lwrite.c my_clock.c \
my_quick.c my_lockmem.c my_static.c \
- getopt.c getopt1.c getvar.c my_mkdir.c \
+ getopt.c getopt1.c my_getopt.c getvar.c my_mkdir.c \
default.c my_compress.c checksum.c raid.cc my_net.c \
- my_vsnprintf.c charset.c my_bitmap.c
+ my_vsnprintf.c charset.c my_bitmap.c my_bit.c md5.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@
@@ -96,6 +96,10 @@ test_vsnprintf: my_vsnprintf.c $(LIBRARIES)
$(CP) $(srcdir)/my_vsnprintf.c test_vsnprintf.c
$(LINK) $(FLAGS) -DMAIN ./test_vsnprintf.c $(LDADD) $(LIBS)
$(RM) -f test_vsnprintf.*
+test_io_cache: mf_iocache.c $(LIBRARIES)
+ $(CP) $(srcdir)/mf_iocache.c test_io_cache.c
+ $(LINK) $(FLAGS) -DMAIN ./test_io_cache.c $(LDADD) $(LIBS)
+ $(RM) -f test_io_cache.*
test_dir: test_dir.c $(LIBRARIES)
$(LINK) $(FLAGS) -DMAIN $(srcdir)/test_dir.c $(LDADD) $(LIBS)
diff --git a/mysys/array.c b/mysys/array.c
index 85dfdaa09d8..2420213d454 100644
--- a/mysys/array.c
+++ b/mysys/array.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Handling of arrays that can grow dynamicly. */
@@ -30,7 +29,8 @@
*/
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)
{
DBUG_ENTER("init_dynamic_array");
if (!alloc_increment)
diff --git a/mysys/charset.c b/mysys/charset.c
index f778afb4144..93e8b697904 100644
--- a/mysys/charset.c
+++ b/mysys/charset.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysys_priv.h"
#include "mysys_err.h"
@@ -44,13 +43,6 @@ struct simpleconfig_buf_st {
char *p;
};
-/* Defined in strings/ctype.c */
-
-CHARSET_INFO *find_compiled_charset(uint cs_number);
-uint compiled_charset_number(const char *name);
-const char *compiled_charset_name(uint charset_number);
-
-
static uint num_from_csname(CS_ID **cs, const char *name)
{
CS_ID **c;
@@ -110,7 +102,7 @@ char *get_charsets_dir(char *buf)
strxmov(buf, DEFAULT_CHARSET_HOME, "/", sharedir, "/", CHARSET_DIR,
NullS);
}
- convert_dirname(buf);
+ convert_dirname(buf,buf,NullS);
DBUG_PRINT("info",("charsets dir='%s'", buf));
DBUG_RETURN(strend(buf));
}
@@ -203,6 +195,7 @@ static my_bool init_available_charsets(myf myflags)
void free_charsets(void)
{
delete_dynamic(&cs_info_table);
+ charset_initialized=0;
}
@@ -264,22 +257,22 @@ static my_bool read_charset_file(uint cs_number, CHARSET_INFO *set,
uint get_charset_number(const char *charset_name)
{
- my_bool error;
- error = init_available_charsets(MYF(0)); /* If it isn't initialized */
- if (error)
- return compiled_charset_number(charset_name);
- else
- return num_from_csname(available_charsets, charset_name);
+ uint number=compiled_charset_number(charset_name);
+ if (number)
+ return number;
+ if (init_available_charsets(MYF(0))) /* If it isn't initialized */
+ return 0;
+ return num_from_csname(available_charsets, charset_name);
}
const char *get_charset_name(uint charset_number)
{
- my_bool error;
- error = init_available_charsets(MYF(0)); /* If it isn't initialized */
- if (error)
- return compiled_charset_name(charset_number);
- else
- return name_from_csnum(available_charsets, charset_number);
+ const char *name=compiled_charset_name(charset_number);
+ if (*name != '?')
+ return name;
+ if (init_available_charsets(MYF(0))) /* If it isn't initialized */
+ return "?";
+ return name_from_csnum(available_charsets, charset_number);
}
@@ -293,8 +286,8 @@ static CHARSET_INFO *find_charset(CHARSET_INFO **table, uint cs_number,
return NULL;
}
-static CHARSET_INFO *find_charset_by_name(CHARSET_INFO **table, const char *name,
- size_t tablesz)
+static CHARSET_INFO *find_charset_by_name(CHARSET_INFO **table,
+ const char *name, size_t tablesz)
{
uint i;
for (i = 0; i < tablesz; ++i)
@@ -303,7 +296,7 @@ static CHARSET_INFO *find_charset_by_name(CHARSET_INFO **table, const char *name
return NULL;
}
-static CHARSET_INFO *add_charset(uint cs_number, const char *cs_name)
+static CHARSET_INFO *add_charset(uint cs_number, const char *cs_name, myf flags)
{
CHARSET_INFO tmp_cs,*cs;
uchar tmp_ctype[CTYPE_TABLE_SIZE];
@@ -318,11 +311,11 @@ static CHARSET_INFO *add_charset(uint cs_number, const char *cs_name)
cs->to_lower=tmp_to_lower;
cs->to_upper=tmp_to_upper;
cs->sort_order=tmp_sort_order;
- if (read_charset_file(cs_number, cs, MYF(MY_WME)))
+ if (read_charset_file(cs_number, cs, flags))
return NULL;
cs = (CHARSET_INFO*) my_once_alloc(sizeof(CHARSET_INFO),
- MYF(MY_WME));
+ MYF(MY_WME));
*cs=tmp_cs;
cs->name = (char *) my_once_alloc((uint) strlen(cs_name)+1, MYF(MY_WME));
cs->ctype = (uchar*) my_once_alloc(CTYPE_TABLE_SIZE, MYF(MY_WME));
@@ -340,7 +333,7 @@ static CHARSET_INFO *add_charset(uint cs_number, const char *cs_name)
return cs;
}
-static CHARSET_INFO *get_internal_charset(uint cs_number)
+static CHARSET_INFO *get_internal_charset(uint cs_number, myf flags)
{
CHARSET_INFO *cs;
/*
@@ -351,13 +344,13 @@ static CHARSET_INFO *get_internal_charset(uint cs_number)
if (!(cs = find_charset((CHARSET_INFO**) cs_info_table.buffer, cs_number,
cs_info_table.elements)))
if (!(cs = find_compiled_charset(cs_number)))
- cs=add_charset(cs_number, get_charset_name(cs_number));
+ cs=add_charset(cs_number, get_charset_name(cs_number), flags);
pthread_mutex_unlock(&THR_LOCK_charset);
return cs;
}
-static CHARSET_INFO *get_internal_charset_by_name(const char *name)
+static CHARSET_INFO *get_internal_charset_by_name(const char *name, myf flags)
{
CHARSET_INFO *cs;
/*
@@ -368,7 +361,7 @@ static CHARSET_INFO *get_internal_charset_by_name(const char *name)
if (!(cs = find_charset_by_name((CHARSET_INFO**) cs_info_table.buffer, name,
cs_info_table.elements)))
if (!(cs = find_compiled_charset_by_name(name)))
- cs=add_charset(get_charset_number(name), name);
+ cs=add_charset(get_charset_number(name), name, flags);
pthread_mutex_unlock(&THR_LOCK_charset);
return cs;
}
@@ -378,7 +371,7 @@ CHARSET_INFO *get_charset(uint cs_number, myf flags)
{
CHARSET_INFO *cs;
(void) init_available_charsets(MYF(0)); /* If it isn't initialized */
- cs=get_internal_charset(cs_number);
+ cs=get_internal_charset(cs_number, flags);
if (!cs && (flags & MY_WME))
{
@@ -410,7 +403,7 @@ CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags)
{
CHARSET_INFO *cs;
(void) init_available_charsets(MYF(0)); /* If it isn't initialized */
- cs=get_internal_charset_by_name(cs_name);
+ cs=get_internal_charset_by_name(cs_name, flags);
if (!cs && (flags & MY_WME))
{
diff --git a/mysys/checksum.c b/mysys/checksum.c
index 00861853945..e09de7d5969 100644
--- a/mysys/checksum.c
+++ b/mysys/checksum.c
@@ -1,23 +1,22 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Calculate a long checksum for a memoryblock. Used to verify pack_isam */
-#include <global.h>
+#include <my_global.h>
#include "my_sys.h"
ulong checksum(const byte *mem, uint count)
diff --git a/mysys/default.c b/mysys/default.c
index e2e80f36a68..d3c1b3815eb 100644
--- a/mysys/default.c
+++ b/mysys/default.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/****************************************************************************
** Add all options from files named "group".cnf from the default_directories
@@ -95,6 +94,7 @@ void load_defaults(const char *conf_file, const char **groups,
res[0]= **argv; /* Copy program name */
for (i=2 ; i < (uint) *argc ; i++)
res[i-1]=argv[0][i];
+ res[i-1]=0; /* End pointer */
(*argc)--;
*argv=res;
*(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */
@@ -231,11 +231,10 @@ static my_bool search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
return 0; /* Ignore wrong paths */
if (dir)
{
- strmov(name,dir);
- convert_dirname(name);
+ end=convert_dirname(name, dir, NullS);
if (dir[0] == FN_HOMELIB) /* Add . to filenames in home */
- strcat(name,".");
- strxmov(strend(name),config_file,ext,NullS);
+ *end++='.';
+ strxmov(end,config_file,ext,NullS);
}
else
{
@@ -369,16 +368,18 @@ void print_defaults(const char *conf_file, const char **groups)
#endif
for (dirs=default_directories ; *dirs; dirs++)
{
+ const char *pos;
+ char *end;
if (**dirs)
- strmov(name,*dirs);
+ pos= *dirs;
else if (defaults_extra_file)
- strmov(name,defaults_extra_file);
+ pos= defaults_extra_file;
else
continue;
- convert_dirname(name);
+ end=convert_dirname(name, pos, NullS);
if (name[0] == FN_HOMELIB) /* Add . to filenames in home */
- strcat(name,".");
- strxmov(strend(name),conf_file,default_ext," ",NullS);
+ *end++='.';
+ strxmov(end,conf_file,default_ext," ",NullS);
fputs(name,stdout);
}
puts("");
@@ -395,4 +396,3 @@ void print_defaults(const char *conf_file, const char **groups)
--defaults-file=# Only read default options from the given file #\n\
--defaults-extra-file=# Read this file after the global files are read");
}
-
diff --git a/mysys/errors.c b/mysys/errors.c
index 77e52c2f0b3..8a120e0e869 100644
--- a/mysys/errors.c
+++ b/mysys/errors.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysys_priv.h"
#include "mysys_err.h"
diff --git a/mysys/getopt.c b/mysys/getopt.c
index 774cf3b82f4..7b96e10c85c 100644
--- a/mysys/getopt.c
+++ b/mysys/getopt.c
@@ -27,7 +27,7 @@ You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA. */
-
+
/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
Ditto for AIX 3.2 and <stdlib.h>. */
#ifndef _NO_PROTO
@@ -46,7 +46,7 @@ Cambridge, MA 02139, USA. */
#endif
#endif
-#include <global.h> /* Changes for mysys */
+#include <my_global.h> /* Changes for mysys */
#include <m_string.h>
/* Comment out all this code if we are using the GNU C Library, and are not
diff --git a/mysys/getopt1.c b/mysys/getopt1.c
index bff76d6e5b2..15f3c8f544b 100644
--- a/mysys/getopt1.c
+++ b/mysys/getopt1.c
@@ -24,7 +24,7 @@ Cambridge, MA 02139, USA. */
#include <config.h>
#endif
-#include <global.h>
+#include <my_global.h>
#include "getopt.h"
#if (!defined (__STDC__) || !__STDC__) && !defined(MSDOS) && !defined(OS2)
diff --git a/mysys/getvar.c b/mysys/getvar.c
index 90ab599244d..bb470423c57 100644
--- a/mysys/getvar.c
+++ b/mysys/getvar.c
@@ -1,26 +1,25 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Allow use of the -O variable= option to set long variables */
#include "mysys_priv.h"
#include <m_string.h>
#include <m_ctype.h>
-
+#include <my_getopt.h>
/* set all changeable variables */
void set_all_changeable_vars(CHANGEABLE_VAR *vars)
diff --git a/mysys/hash.c b/mysys/hash.c
index 727df46758c..b3769d1dfb2 100644
--- a/mysys/hash.c
+++ b/mysys/hash.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* The hash functions used for saveing keys */
/* One of key_length or key_length_offset must be given */
@@ -148,9 +147,7 @@ static uint calc_hashnr_caseup(const byte *key,uint length)
*
* The magic is in the interesting relationship between the special prime
* 16777619 (2^24 + 403) and 2^32 and 2^8.
- *
- * This hash produces the fewest collisions of any function that we've seen so
- * far, and works well on both numbers and strings.
+ * This works well on both numbers and strings.
*/
uint calc_hashnr(const byte *key, uint len)
@@ -517,8 +514,8 @@ my_bool hash_update(HASH *hash,byte *record,byte *old_key,uint old_key_length)
/* Search after record with key */
idx=hash_mask((*hash->calc_hashnr)(old_key,(old_key_length ?
- old_key_length :
- hash->key_length)),
+ old_key_length :
+ hash->key_length)),
blength,records);
new_index=hash_mask(rec_hashnr(hash,record),blength,records);
if (idx == new_index)
@@ -578,6 +575,18 @@ byte *hash_element(HASH *hash,uint idx)
}
+/*
+ Replace old row with new row. This should only be used when key
+ isn't changed
+*/
+
+void hash_replace(HASH *hash, uint idx, byte *new_row)
+{
+ if (idx != NO_RECORD) /* Safety */
+ dynamic_element(&hash->array,idx,HASH_LINK*)->data=new_row;
+}
+
+
#ifndef DBUG_OFF
my_bool hash_check(HASH *hash)
diff --git a/mysys/list.c b/mysys/list.c
index c9c863d4cc2..ac9e1b979a0 100644
--- a/mysys/list.c
+++ b/mysys/list.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
Code for handling dubble-linked lists in C
diff --git a/mysys/make-conf.c b/mysys/make-conf.c
index 9db766574e2..404299e1726 100644
--- a/mysys/make-conf.c
+++ b/mysys/make-conf.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* make-conf.c
* make a charset .conf file out of a ctype-charset.c file.
@@ -34,7 +33,7 @@
#define CH_INCLUDE STRINGIZE(CH_SRC)
/* aaaah, that's better */
-#include <my_global.h>
+#include <my_my_global.h>
#include CH_INCLUDE
#include <stdio.h>
diff --git a/sql/md5.c b/mysys/md5.c
index 4c2e80107b8..5de95288141 100644
--- a/sql/md5.c
+++ b/mysys/md5.c
@@ -1,3 +1,19 @@
+/* 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 */
+
/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
*/
@@ -28,7 +44,7 @@ documentation and/or software.
Replace of MD5_memset and MD5_memcpy with memset & memcpy
*/
-#include <global.h>
+#include <my_global.h>
#include <m_string.h>
#include "md5.h"
@@ -108,7 +124,7 @@ Rotation is separate from addition to prevent recomputation.
/* MD5 initialization. Begins an MD5 operation, writing a new context.
*/
-void MD5Init (MD5_CTX *context) /* context */
+void my_MD5Init (my_MD5_CTX *context) /* context */
{
context->count[0] = context->count[1] = 0;
/* Load magic initialization constants.
@@ -123,8 +139,9 @@ void MD5Init (MD5_CTX *context) /* context */
operation, processing another message block, and updating the
context.
*/
-void MD5Update (
-MD5_CTX *context, /* context */
+
+void my_MD5Update (
+my_MD5_CTX *context, /* context */
unsigned char *input, /* input block */
unsigned int inputLen) /* length of input block */
{
@@ -164,9 +181,10 @@ unsigned int inputLen) /* length of input block */
/* MD5 finalization. Ends an MD5 message-digest operation, writing the
the message digest and zeroizing the context.
*/
-void MD5Final (
+
+void my_MD5Final (
unsigned char digest[16], /* message digest */
-MD5_CTX *context) /* context */
+my_MD5_CTX *context) /* context */
{
unsigned char bits[8];
unsigned int idx, padLen;
@@ -178,10 +196,10 @@ MD5_CTX *context) /* context */
*/
idx = (unsigned int)((context->count[0] >> 3) & 0x3f);
padLen = (idx < 56) ? (56 - idx) : (120 - idx);
- MD5Update (context, PADDING, padLen);
+ my_MD5Update (context, PADDING, padLen);
/* Append length (before padding) */
- MD5Update (context, bits, 8);
+ my_MD5Update (context, bits, 8);
/* Store state in digest */
Encode (digest, context->state, 16);
diff --git a/mysys/mf_brkhant.c b/mysys/mf_brkhant.c
index debf5d9a712..4180bd6df66 100644
--- a/mysys/mf_brkhant.c
+++ b/mysys/mf_brkhant.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Dont let the user break when you are doing something important */
/* Remembers if it got 'SIGINT' and executes it on allow_break */
diff --git a/mysys/mf_cache.c b/mysys/mf_cache.c
index 85b6b19b328..2c5d8658625 100644
--- a/mysys/mf_cache.c
+++ b/mysys/mf_cache.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000 MySQL AB
- 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 program is free software; 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 library is distributed in the hope that it will be useful,
+ This program is distributed in the hope that 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.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU 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 */
+ You should have received a copy of the GNU General Public 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 temporary file and cache it with io_cache. Delete it on close */
diff --git a/mysys/mf_casecnv.c b/mysys/mf_casecnv.c
index 125f54b2594..0302688ad1f 100644
--- a/mysys/mf_casecnv.c
+++ b/mysys/mf_casecnv.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 convert to lover_case and to upper_case in scandinavia.
@@ -25,7 +24,9 @@
#include "mysys_priv.h"
#include <m_ctype.h>
+#ifndef SCO
#include <m_string.h>
+#endif
/* string to uppercase */
@@ -35,7 +36,7 @@ void caseup_str(my_string str)
if (use_mb(default_charset_info))
{
register uint32 l;
- register char *end=str+(uint) strlen(str);
+ register char *end=str+strlen(str);
while (*str)
{
if ((l=my_ismbchar(default_charset_info, str,end))) str+=l;
@@ -56,7 +57,7 @@ void casedn_str(my_string str)
if (use_mb(default_charset_info))
{
register uint32 l;
- register char *end=str+(uint) strlen(str);
+ register char *end=str+strlen(str);
while (*str)
{
if ((l=my_ismbchar(default_charset_info, str,end))) str+=l;
@@ -155,7 +156,7 @@ int my_strcasecmp(const char *s, const char *t)
if (use_mb(default_charset_info))
{
register uint32 l;
- register const char *end=s+(uint) strlen(s);
+ register const char *end=s+strlen(s);
while (s<end)
{
if ((l=my_ismbchar(default_charset_info, s,end)))
diff --git a/mysys/mf_dirname.c b/mysys/mf_dirname.c
index 399082a238b..6523abcdb12 100644
--- a/mysys/mf_dirname.c
+++ b/mysys/mf_dirname.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysys_priv.h"
#include <m_string.h>
@@ -50,57 +49,70 @@ uint dirname_part(my_string to, const char *name)
DBUG_PRINT("enter",("'%s'",name));
length=dirname_length(name);
- (void) strmake(to,(char*) name,min(length,FN_REFLEN-2));
- convert_dirname(to); /* Convert chars */
+ convert_dirname(to, name, name+length);
DBUG_RETURN(length);
} /* dirname */
- /* convert dirname to use under this system */
- /* If MSDOS converts '/' to '\' */
- /* If VMS converts '<' to '[' and '>' to ']' */
- /* Adds a '/' to end if there isn't one and the last isn't a dev_char */
- /* ARGSUSED */
+ /*
+ Convert directory name to use under this system
+ If MSDOS converts '/' to '\'
+ If VMS converts '<' to '[' and '>' to ']'
+ Adds a FN_LIBCHAR to end if the result string if there isn't one
+ and the last isn't dev_char.
+ Copies data from 'from' until ASCII(0) for until from == from_end
+ If you want to use the whole 'from' string, just send NullS as the
+ last argument.
+ If the result string is larger than FN_REFLEN -1, then it's cut.
+
+ Returns pointer to end \0
+ */
#ifndef FN_DEVCHAR
#define FN_DEVCHAR '\0' /* For easier code */
#endif
-char *convert_dirname(my_string to)
+char *convert_dirname(char *to, const char *from, const char *from_end)
{
- reg1 char *pos;
-#ifdef FN_UPPER_CASE
- caseup_str(to);
-#endif
-#ifdef FN_LOWER_CASE
- casedn_str(to);
-#endif
-#if FN_LIBCHAR != '/'
- {
- pos=to-1; /* Change from '/' */
- while ((pos=strchr(pos+1,'/')) != 0)
- *pos=FN_LIBCHAR;
- }
-#endif
-#ifdef FN_C_BEFORE_DIR_2
+ char *to_org=to;
+
+ /* We use -2 here, becasue we need place for the last FN_LIBCHAR */
+ if (!from_end || (from_end - from) > FN_REFLEN-2)
+ from_end=from+FN_REFLEN -2;
+
+#if FN_LIBCHAR != '/' || defined(FN_C_BEFORE_DIR_2)
{
- for (pos=to ; *pos ; pos++)
+ for (; *from && from != from_end; from++)
{
- if (*pos == FN_C_BEFORE_DIR_2)
- *pos=FN_C_BEFORE_DIR;
- if (*pos == FN_C_AFTER_DIR_2)
- *pos=FN_C_AFTER_DIR;
+ if (*from == '/')
+ *to++= FN_LIBCHAR;
+#ifdef FN_C_BEFORE_DIR_2
+ else if (*from == FN_C_BEFORE_DIR_2)
+ *to++= FN_C_BEFORE_DIR;
+ else if (*from == FN_C_AFTER_DIR_2)
+ *to++= FN_C_AFTER_DIR;
+#endif
+ else
+ *to++= *from;
}
+ *to=0;
}
#else
- { /* Append FN_LIBCHAR if not there */
- pos=strend(to);
- if (pos != to && (pos[-1] != FN_LIBCHAR && pos[-1] != FN_DEVCHAR))
- {
- *pos++=FN_LIBCHAR;
- *pos=0;
- }
+ /* This is ok even if to == from, becasue we need to cut the string */
+ to= strmake(to, from, (uint) (from_end-from));
+#endif
+
+ /* Add FN_LIBCHAR to the end of directory path */
+ if (to != to_org && (to[-1] != FN_LIBCHAR && to[-1] != FN_DEVCHAR))
+ {
+ *to++=FN_LIBCHAR;
+ *to=0;
}
+#ifdef FN_UPPER_CASE
+ caseup_str(to_org);
+#endif
+#ifdef FN_LOWER_CASE
+ casedn_str(to_org);
#endif
- return pos; /* Pointer to end of dir */
+ return to; /* Pointer to end of dir */
} /* convert_dirname */
diff --git a/mysys/mf_fn_ext.c b/mysys/mf_fn_ext.c
index 6a9b9d18341..fb3fd8870aa 100644
--- a/mysys/mf_fn_ext.c
+++ b/mysys/mf_fn_ext.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Returnerar en pekare till filnamnets extension. */
diff --git a/mysys/mf_format.c b/mysys/mf_format.c
index 7dac46cf0d0..ab1904da162 100644
--- a/mysys/mf_format.c
+++ b/mysys/mf_format.c
@@ -1,94 +1,84 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysys_priv.h"
#include <m_string.h>
-#ifdef HAVE_REALPATH
-#include <sys/param.h>
-#include <sys/stat.h>
-#endif
- /* format a filename with replace of library and extension */
- /* params to and name may be identicall */
- /* function doesn't change name if name != to */
- /* Flag may be: 1 replace filenames library with 'dsk' */
- /* 2 replace extension with 'form' */
- /* 4 Unpack filename (replace ~ with home) */
- /* 8 Pack filename as short as possibly */
- /* 16 Resolve symbolic links for filename */
- /* 32 Resolve filename to full path */
- /* 64 Return NULL if too long path */
+ /*
+ Formats a filename with possible replace of directory of extension
+ Function can handle the case where 'to' == 'name'
+ For a description of the flag values, consult my_sys.h
+ The arguments should be in unix format.
+ */
-#ifdef SCO
-#define BUFF_LEN 4097
-#else
-#ifdef MAXPATHLEN
-#define BUFF_LEN MAXPATHLEN
-#else
-#define BUFF_LEN FN_LEN
-#endif
-#endif
-my_string fn_format(my_string to, const char *name, const char *dsk,
- const char *form, int flag)
+my_string fn_format(my_string to, const char *name, const char *dir,
+ const char *extension, uint flag)
{
reg1 uint length;
- char dev[FN_REFLEN], buff[BUFF_LEN], *pos, *startpos;
+ char dev[FN_REFLEN], buff[FN_REFLEN], *pos, *startpos;
const char *ext;
DBUG_ENTER("fn_format");
- DBUG_PRINT("enter",("name: %s dsk: %s form: %s flag: %d",
- name,dsk,form,flag));
+ DBUG_PRINT("enter",("name: %s dir: %s extension: %s flag: %d",
+ name,dir,extension,flag));
- /* Kopiera & skippa enheten */
+ /* Copy and skip directory */
name+=(length=dirname_part(dev,(startpos=(my_string) name)));
- if (length == 0 || flag & 1)
+ if (length == 0 || (flag & MY_REPLACE_DIR))
{
- (void) strmake(dev,dsk, sizeof(dev) - 2);
- /* Use given directory */
- convert_dirname(dev); /* Fix to this OS */
+ /* Use given directory */
+ convert_dirname(dev,dir,NullS); /* Fix to this OS */
}
- if (flag & 8)
+ else if ((flag & MY_RELATIVE_PATH) && !test_if_hard_path(name))
+ {
+ /* Put 'dir' before the given path */
+ strmake(buff,dev,sizeof(buff)-1);
+ pos=convert_dirname(dev,dir,NullS);
+ strmake(pos,buff,sizeof(buff)-1- (int) (pos-dev));
+ }
+
+ if (flag & MY_PACK_FILENAME)
pack_dirname(dev,dev); /* Put in ./.. and ~/.. */
- if (flag & 4)
+ if (flag & MY_UNPACK_FILENAME)
(void) unpack_dirname(dev,dev); /* Replace ~/.. with dir */
- if ((pos=(char*)strchr(name,FN_EXTCHAR)) != NullS)
+ if ((pos= (char*) strchr(name,FN_EXTCHAR)) != NullS)
{
- if ((flag & 2) == 0) /* Skall vi byta extension ? */
+ if ((flag & MY_REPLACE_EXT) == 0) /* If we should keep old ext */
{
- length=strlength(name); /* Old extension */
+ length=strlength(name); /* Use old extension */
ext = "";
}
else
{
length=(uint) (pos-(char*) name); /* Change extension */
- ext= form;
+ ext= extension;
}
}
else
{
- length=strlength(name); /* Har ingen ext- tag nya */
- ext=form;
+ length=strlength(name); /* No ext, use the now one */
+ ext=extension;
}
if (strlen(dev)+length+strlen(ext) >= FN_REFLEN || length >= FN_LEN )
- { /* To long path, return original */
+ {
+ /* To long path, return original or NULL */
uint tmp_length;
- if (flag & 64)
- return 0;
+ if (flag & MY_SAFE_PATH)
+ return NullS;
tmp_length=strlength(startpos);
DBUG_PRINT("error",("dev: '%s' ext: '%s' length: %d",dev,ext,length));
(void) strmake(to,startpos,min(tmp_length,FN_REFLEN-1));
@@ -109,18 +99,18 @@ my_string fn_format(my_string to, const char *name, const char *dsk,
#endif
(void) strmov(pos,ext); /* Don't convert extension */
}
- /* Purify gives a lot of UMR errors when using realpath */
-#if defined(HAVE_REALPATH) && !defined(HAVE_purify) && !defined(HAVE_BROKEN_REALPATH)
- if (flag & 16)
+ /*
+ If MY_RETURN_REAL_PATH and MY_RESOLVE_SYMLINK is given, only do
+ realpath if the file is a symbolic link
+ */
+ if (flag & MY_RETURN_REAL_PATH)
+ (void) my_realpath(to, to, MYF(flag & MY_RESOLVE_SYMLINKS ?
+ MY_RESOLVE_LINK: 0));
+ else if (flag & MY_RESOLVE_SYMLINKS)
{
- struct stat stat_buff;
- if (flag & 32 || (!lstat(to,&stat_buff) && S_ISLNK(stat_buff.st_mode)))
- {
- if (realpath(to,buff))
- strmake(to,buff,FN_REFLEN-1);
- }
+ strmov(buff,to);
+ (void) my_readlink(to, buff, MYF(0));
}
-#endif
DBUG_RETURN (to);
} /* fn_format */
diff --git a/mysys/mf_getdate.c b/mysys/mf_getdate.c
index f01d1d7633a..189d43e782a 100644
--- a/mysys/mf_getdate.c
+++ b/mysys/mf_getdate.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Get date in a printable form: yyyy-mm-dd hh:mm:ss */
diff --git a/mysys/mf_iocache.c b/mysys/mf_iocache.c
index 0d1c227c2b2..872757f77c5 100644
--- a/mysys/mf_iocache.c
+++ b/mysys/mf_iocache.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
Cashing of files with only does (sequential) read or writes of fixed-
@@ -23,12 +22,30 @@
Possibly use of asyncronic io.
macros for read and writes for faster io.
Used instead of FILE when reading or writing whole files.
- This will make mf_rec_cache obsolete.
+ This code makes mf_rec_cache obsolete (currently only used by ISAM)
One can change info->pos_in_file to a higher value to skip bytes in file if
- also info->rc_pos is set to info->rc_end.
+ 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().
+ 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
+ then done from the write buffer. This is an efficient way to read
+ from a log file when one is writing to it at the same time.
+ For this to work, the file has to be opened in append mode!
+ Note that when one uses SEQ_READ_APPEND, one MUST write using
+ my_b_append ! This is needed because we need to lock the mutex
+ every time we access the write buffer.
+
+TODO:
+ When one SEQ_READ_APPEND and we are reading and writing at the same time,
+ 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
+ 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.
*/
#define MAP_TO_USE_RAID
@@ -36,10 +53,54 @@
#include <m_string.h>
#ifdef HAVE_AIOWAIT
#include "mysys_err.h"
-#include <errno.h>
static void my_aiowait(my_aio_result *result);
#endif
+#include <assert.h>
+#include <errno.h>
+
+#ifdef THREAD
+#define lock_append_buffer(info) \
+ pthread_mutex_lock(&(info)->append_buffer_lock)
+#define unlock_append_buffer(info) \
+ pthread_mutex_unlock(&(info)->append_buffer_lock)
+#else
+#define lock_append_buffer(info)
+#define unlock_append_buffer(info)
+#endif
+
+static void
+init_functions(IO_CACHE* info, enum cache_type type)
+{
+ switch (type) {
+ case READ_NET:
+ /* must be initialized by the caller. The problem is that
+ _my_b_net_read has to be defined in sql directory because of
+ the dependency on THD, and therefore cannot be visible to
+ programs that link against mysys but know nothing about THD, such
+ as myisamchk
+ */
+ break;
+ case SEQ_READ_APPEND:
+ info->read_function = _my_b_seq_read;
+ info->write_function = 0; /* Force a core if used */
+ break;
+ default:
+ info->read_function = _my_b_read;
+ info->write_function = _my_b_write;
+ }
+ /* Ensure that my_b_tell() and my_b_bytes_in_cache works */
+ if (type == WRITE_CACHE)
+ {
+ info->current_pos= &info->write_pos;
+ info->current_end= &info->write_end;
+ }
+ else
+ {
+ info->current_pos= &info->read_pos;
+ info->current_end= &info->read_end;
+ }
+}
/*
** if cachesize == 0 then use default cachesize (from s-file)
@@ -52,70 +113,95 @@ int init_io_cache(IO_CACHE *info, File file, uint cachesize,
pbool use_async_io, myf cache_myflags)
{
uint min_cache;
+ my_off_t end_of_file= ~(my_off_t) 0;
DBUG_ENTER("init_io_cache");
DBUG_PRINT("enter",("type: %d pos: %ld",(int) type, (ulong) seek_offset));
- info->file=file;
+ info->file= file;
+ info->type=type;
+ info->pos_in_file= seek_offset;
+ info->pre_close = info->pre_read = info->post_read = 0;
+ info->arg = 0;
+ info->init_count++; /* we assume the user had set it to 0 prior to
+ first call */
+ info->alloced_buffer = 0;
+ info->buffer=0;
+ info->seek_not_done= test(file >= 0);
+
if (!cachesize)
if (! (cachesize= my_default_record_cache_size))
DBUG_RETURN(1); /* No cache requested */
min_cache=use_async_io ? IO_SIZE*4 : IO_SIZE*2;
- if (type == READ_CACHE)
+ if (type == READ_CACHE || type == SEQ_READ_APPEND)
{ /* Assume file isn't growing */
- if (cache_myflags & MY_DONT_CHECK_FILESIZE)
- {
- cache_myflags &= ~MY_DONT_CHECK_FILESIZE;
- }
- else
+ if (!(cache_myflags & MY_DONT_CHECK_FILESIZE))
{
- my_off_t file_pos,end_of_file;
- if ((file_pos=my_tell(file,MYF(0)) == MY_FILEPOS_ERROR))
- DBUG_RETURN(1);
+ /* Calculate end of file to not allocate to big buffers */
end_of_file=my_seek(file,0L,MY_SEEK_END,MYF(0));
if (end_of_file < seek_offset)
end_of_file=seek_offset;
- VOID(my_seek(file,file_pos,MY_SEEK_SET,MYF(0)));
+ /* Trim cache size if the file is very small */
if ((my_off_t) cachesize > end_of_file-seek_offset+IO_SIZE*2-1)
{
cachesize=(uint) (end_of_file-seek_offset)+IO_SIZE*2-1;
- use_async_io=0; /* No nead to use async */
+ use_async_io=0; /* No need to use async */
}
}
}
-
- for (;;)
+ cache_myflags &= ~MY_DONT_CHECK_FILESIZE;
+ if (type != READ_NET && type != WRITE_NET)
{
- cachesize=(uint) ((ulong) (cachesize + min_cache-1) &
- (ulong) ~(min_cache-1));
- if (cachesize < min_cache)
- cachesize = min_cache;
- if ((info->buffer=
- (byte*) my_malloc(cachesize,
- MYF((cache_myflags & ~ MY_WME) |
- (cachesize == min_cache ? MY_WME : 0)))) != 0)
- break; /* Enough memory found */
- if (cachesize == min_cache)
- DBUG_RETURN(2); /* Can't alloc cache */
- cachesize= (uint) ((long) cachesize*3/4); /* Try with less memory */
- }
- info->pos_in_file=seek_offset;
+ /* Retry allocating memory in smaller blocks until we get one */
+ for (;;)
+ {
+ uint buffer_block;
+ cachesize=(uint) ((ulong) (cachesize + min_cache-1) &
+ (ulong) ~(min_cache-1));
+ if (cachesize < min_cache)
+ cachesize = min_cache;
+ buffer_block = cachesize;
+ if (type == SEQ_READ_APPEND)
+ buffer_block *= 2;
+ if ((info->buffer=
+ (byte*) my_malloc(buffer_block,
+ MYF((cache_myflags & ~ MY_WME) |
+ (cachesize == min_cache ? MY_WME : 0)))) != 0)
+ {
+ info->write_buffer=info->buffer;
+ if (type == SEQ_READ_APPEND)
+ info->write_buffer = info->buffer + cachesize;
+ info->alloced_buffer=1;
+ break; /* Enough memory found */
+ }
+ if (cachesize == min_cache)
+ DBUG_RETURN(2); /* Can't alloc cache */
+ cachesize= (uint) ((long) cachesize*3/4); /* Try with less memory */
+ }
+ }
+
+ DBUG_PRINT("info",("init_io_cache: cachesize = %u",cachesize));
info->read_length=info->buffer_length=cachesize;
- info->seek_not_done= test(file >= 0); /* Seek not done */
info->myflags=cache_myflags & ~(MY_NABP | MY_FNABP);
- info->rc_request_pos=info->rc_pos=info->buffer;
-
- if (type == READ_CACHE)
- {
- info->rc_end=info->buffer; /* Nothing in cache */
- }
- else /* type == WRITE_CACHE */
+ info->request_pos= info->read_pos= info->write_pos = info->buffer;
+ if (type == SEQ_READ_APPEND)
{
- info->rc_end=info->buffer+info->buffer_length- (seek_offset & (IO_SIZE-1));
+ info->append_read_pos = info->write_pos = info->write_buffer;
+ info->write_end = info->write_buffer + info->buffer_length;
+#ifdef THREAD
+ pthread_mutex_init(&info->append_buffer_lock,MY_MUTEX_INIT_FAST);
+#endif
}
- info->end_of_file=MY_FILEPOS_ERROR; /* May be changed by user */
- info->type=type;
+
+ if (type == WRITE_CACHE)
+ info->write_end=
+ info->buffer+info->buffer_length- (seek_offset & (IO_SIZE-1));
+ else
+ info->read_end=info->buffer; /* Nothing in cache */
+
+ /* End_of_file may be changed by user later */
+ info->end_of_file= end_of_file;
info->error=0;
- info->read_function=_my_b_read;
+ init_functions(info,type);
#ifdef HAVE_AIOWAIT
if (use_async_io && ! my_disable_async_io)
{
@@ -156,8 +242,13 @@ static void my_aiowait(my_aio_result *result)
}
#endif
- /* Use this to reset cache to start or other type */
- /* Some simple optimizing is done when reinit in current buffer */
+
+/*
+ Use this to reset cache to re-start reading or to change the type
+ between READ_CACHE <-> WRITE_CACHE
+ If we are doing a reinit of a cache where we have the start of the file
+ in the cache, we are reusing this memory without flushing it to disk.
+*/
my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type,
my_off_t seek_offset,
@@ -165,47 +256,71 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type,
pbool clear_cache)
{
DBUG_ENTER("reinit_io_cache");
+ DBUG_PRINT("enter",("type: %d seek_offset: %lu clear_cache: %d",
+ type, (ulong) seek_offset, (int) clear_cache));
- info->seek_not_done= test(info->file >= 0); /* Seek not done */
+ /* One can't do reinit with the following types */
+ DBUG_ASSERT(type != READ_NET && info->type != READ_NET &&
+ type != WRITE_NET && info->type != WRITE_NET &&
+ type != SEQ_READ_APPEND && info->type != SEQ_READ_APPEND);
+
+ /* If the whole file is in memory, avoid flushing to disk */
if (! clear_cache &&
seek_offset >= info->pos_in_file &&
- seek_offset <= info->pos_in_file +
- (uint) (info->rc_end - info->rc_request_pos))
- { /* use current buffer */
+ seek_offset <= my_b_tell(info))
+ {
+ /* Reuse current buffer without flushing it to disk */
+ byte *pos;
if (info->type == WRITE_CACHE && type == READ_CACHE)
{
- info->rc_end=info->rc_pos;
+ info->read_end=info->write_pos;
info->end_of_file=my_b_tell(info);
}
- else if (info->type == READ_CACHE && type == WRITE_CACHE)
- info->rc_end=info->buffer+info->buffer_length;
- info->rc_pos=info->rc_request_pos+(seek_offset-info->pos_in_file);
+ else if (type == WRITE_CACHE)
+ {
+ if (info->type == READ_CACHE)
+ info->write_end=info->write_buffer+info->buffer_length;
+ info->end_of_file = ~(my_off_t) 0;
+ }
+ pos=info->request_pos+(seek_offset-info->pos_in_file);
+ if (type == WRITE_CACHE)
+ info->write_pos=pos;
+ else
+ info->read_pos= pos;
#ifdef HAVE_AIOWAIT
my_aiowait(&info->aio_result); /* Wait for outstanding req */
#endif
}
else
{
+ /*
+ If we change from WRITE_CACHE to READ_CACHE, assume that everything
+ after the current positions should be ignored
+ */
if (info->type == WRITE_CACHE && type == READ_CACHE)
info->end_of_file=my_b_tell(info);
- if (flush_io_cache(info))
+ /* flush cache if we want to reuse it */
+ if (!clear_cache && flush_io_cache(info))
DBUG_RETURN(1);
info->pos_in_file=seek_offset;
- info->rc_request_pos=info->rc_pos=info->buffer;
+ /* Better to do always do a seek */
+ info->seek_not_done=1;
+ info->request_pos=info->read_pos=info->write_pos=info->buffer;
if (type == READ_CACHE)
{
- info->rc_end=info->buffer; /* Nothing in cache */
+ info->read_end=info->buffer; /* Nothing in cache */
}
else
{
- info->rc_end=info->buffer+info->buffer_length-
- (seek_offset & (IO_SIZE-1));
- info->end_of_file=MY_FILEPOS_ERROR; /* May be changed by user */
+ info->write_end=(info->buffer + info->buffer_length -
+ (seek_offset & (IO_SIZE-1)));
+ info->end_of_file= ~(my_off_t) 0;
}
}
info->type=type;
info->error=0;
- info->read_function=_my_b_read;
+ init_functions(info,type);
+
#ifdef HAVE_AIOWAIT
if (use_async_io && ! my_disable_async_io &&
((ulong) info->buffer_length <
@@ -217,23 +332,34 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type,
info->inited=0;
#endif
DBUG_RETURN(0);
-} /* init_io_cache */
+} /* reinit_io_cache */
- /* Read buffered. Returns 1 if can't read requested characters */
- /* Returns 0 if record read */
+/*
+ Read buffered. Returns 1 if can't read requested characters
+ This function is only called from the my_b_read() macro
+ when there isn't enough characters in the buffer to
+ satisfy the request.
+ Returns 0 we succeeded in reading all data
+*/
int _my_b_read(register IO_CACHE *info, byte *Buffer, uint Count)
{
uint length,diff_length,left_length;
my_off_t max_length, pos_in_file;
+ DBUG_ENTER("_my_b_read");
- memcpy(Buffer,info->rc_pos,
- (size_t) (left_length=(uint) (info->rc_end-info->rc_pos)));
- Buffer+=left_length;
- Count-=left_length;
- pos_in_file=info->pos_in_file+(uint) (info->rc_end - info->buffer);
+ if ((left_length=(uint) (info->read_end-info->read_pos)))
+ {
+ DBUG_ASSERT(Count >= left_length); /* User is not using my_b_read() */
+ memcpy(Buffer,info->read_pos, (size_t) (left_length));
+ Buffer+=left_length;
+ Count-=left_length;
+ }
+
+ /* pos_in_file always point on where info->buffer was read */
+ pos_in_file=info->pos_in_file+(uint) (info->read_end - info->buffer);
if (info->seek_not_done)
{ /* File touched, do seek */
VOID(my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0)));
@@ -246,7 +372,7 @@ int _my_b_read(register IO_CACHE *info, byte *Buffer, uint Count)
if (info->end_of_file == pos_in_file)
{ /* End of file */
info->error=(int) left_length;
- return 1;
+ DBUG_RETURN(1);
}
length=(Count & (uint) ~(IO_SIZE-1))-diff_length;
if ((read_length=my_read(info->file,Buffer,(uint) length,info->myflags))
@@ -254,7 +380,7 @@ int _my_b_read(register IO_CACHE *info, byte *Buffer, uint Count)
{
info->error= read_length == (uint) -1 ? -1 :
(int) (read_length+left_length);
- return 1;
+ DBUG_RETURN(1);
}
Count-=length;
Buffer+=length;
@@ -262,16 +388,17 @@ int _my_b_read(register IO_CACHE *info, byte *Buffer, uint Count)
left_length+=length;
diff_length=0;
}
- max_length=info->end_of_file - pos_in_file;
- if (max_length > info->read_length-diff_length)
- max_length=info->read_length-diff_length;
+ max_length=info->read_length-diff_length;
+ if (info->type != READ_FIFO &&
+ max_length > (info->end_of_file - pos_in_file))
+ max_length = info->end_of_file - pos_in_file;
if (!max_length)
{
if (Count)
{
info->error= left_length; /* We only got this many char */
- return 1;
+ DBUG_RETURN(1);
}
length=0; /* Didn't read any chars */
}
@@ -282,13 +409,160 @@ int _my_b_read(register IO_CACHE *info, byte *Buffer, uint Count)
if (length != (uint) -1)
memcpy(Buffer,info->buffer,(size_t) length);
info->error= length == (uint) -1 ? -1 : (int) (length+left_length);
- return 1;
+ info->read_pos=info->read_end=info->buffer;
+ DBUG_RETURN(1);
}
- info->rc_pos=info->buffer+Count;
- info->rc_end=info->buffer+length;
+ info->read_pos=info->buffer+Count;
+ info->read_end=info->buffer+length;
+ info->pos_in_file=pos_in_file;
+ memcpy(Buffer,info->buffer,(size_t) Count);
+ DBUG_RETURN(0);
+}
+
+/*
+ Do sequential read from the SEQ_READ_APPEND cache
+ we do this in three stages:
+ - first read from info->buffer
+ - then if there are still data to read, try the file descriptor
+ - afterwards, if there are still data to read, try append buffer
+*/
+
+int _my_b_seq_read(register IO_CACHE *info, byte *Buffer, uint Count)
+{
+ uint length,diff_length,left_length,save_count;
+ my_off_t max_length, pos_in_file;
+ save_count=Count;
+
+ /* first, read the regular buffer */
+ if ((left_length=(uint) (info->read_end-info->read_pos)))
+ {
+ DBUG_ASSERT(Count > left_length); /* User is not using my_b_read() */
+ memcpy(Buffer,info->read_pos, (size_t) (left_length));
+ Buffer+=left_length;
+ Count-=left_length;
+ }
+ lock_append_buffer(info);
+
+ /* pos_in_file always point on where info->buffer was read */
+ if ((pos_in_file=info->pos_in_file+(uint) (info->read_end - info->buffer)) >=
+ info->end_of_file)
+ goto read_append_buffer;
+
+ /*
+ With read-append cache we must always do a seek before we read,
+ because the write could have moved the file pointer astray
+ */
+ VOID(my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0)));
+ info->seek_not_done=0;
+
+ diff_length=(uint) (pos_in_file & (IO_SIZE-1));
+
+ /* now the second stage begins - read from file descriptor */
+ if (Count >= (uint) (IO_SIZE+(IO_SIZE-diff_length)))
+ { /* Fill first intern buffer */
+ uint read_length;
+
+ length=(Count & (uint) ~(IO_SIZE-1))-diff_length;
+ if ((read_length=my_read(info->file,Buffer,(uint) length,info->myflags)) ==
+ (uint)-1)
+ {
+ info->error= -1;
+ unlock_append_buffer(info);
+ return 1;
+ }
+ Count-=read_length;
+ Buffer+=read_length;
+ pos_in_file+=read_length;
+
+ if (read_length != (uint) length)
+ {
+ /*
+ We only got part of data; Read the rest of the data from the
+ write buffer
+ */
+ goto read_append_buffer;
+ }
+ left_length+=length;
+ diff_length=0;
+ }
+
+ max_length=info->read_length-diff_length;
+ if (max_length > (info->end_of_file - pos_in_file))
+ max_length = info->end_of_file - pos_in_file;
+ if (!max_length)
+ {
+ if (Count)
+ goto read_append_buffer;
+ length=0; /* Didn't read any more chars */
+ }
+ else
+ {
+ length=my_read(info->file,info->buffer,(uint) max_length,
+ info->myflags);
+ if (length == (uint) -1)
+ {
+ info->error= -1;
+ unlock_append_buffer(info);
+ return 1;
+ }
+ if (length < Count)
+ {
+ memcpy(Buffer,info->buffer,(size_t) length);
+ Count -= length;
+ Buffer += length;
+
+ /*
+ added the line below to make
+ DBUG_ASSERT(pos_in_file==info->end_of_file) pass.
+ otherwise this does not appear to be needed
+ */
+ pos_in_file += length;
+ goto read_append_buffer;
+ }
+ }
+ unlock_append_buffer(info);
+ info->read_pos=info->buffer+Count;
+ info->read_end=info->buffer+length;
info->pos_in_file=pos_in_file;
memcpy(Buffer,info->buffer,(size_t) Count);
return 0;
+
+read_append_buffer:
+
+ /*
+ Read data from the current write buffer.
+ Count should never be == 0 here (The code will work even if count is 0)
+ */
+
+ {
+ /* First copy the data to Count */
+ uint len_in_buff = (uint) (info->write_pos - info->append_read_pos);
+ uint copy_len;
+ uint transfer_len;
+
+ DBUG_ASSERT(info->append_read_pos <= info->write_pos);
+ /*
+ TODO: figure out if the assert below is needed or correct.
+ */
+ DBUG_ASSERT(pos_in_file == info->end_of_file);
+ copy_len=min(Count, len_in_buff);
+ memcpy(Buffer, info->append_read_pos, copy_len);
+ info->append_read_pos += copy_len;
+ Count -= copy_len;
+ if (Count)
+ info->error = save_count - Count;
+
+ /* Fill read buffer with data from write buffer */
+ memcpy(info->buffer, info->append_read_pos,
+ (size_t) (transfer_len=len_in_buff - copy_len));
+ info->read_pos= info->buffer;
+ info->read_end= info->buffer+transfer_len;
+ info->append_read_pos=info->write_pos;
+ info->pos_in_file=pos_in_file+copy_len;
+ info->end_of_file+=len_in_buff;
+ }
+ unlock_append_buffer(info);
+ return Count ? 1 : 0;
}
@@ -301,8 +575,8 @@ int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count)
my_off_t next_pos_in_file;
byte *read_buffer;
- memcpy(Buffer,info->rc_pos,
- (size_t) (left_length=(uint) (info->rc_end-info->rc_pos)));
+ memcpy(Buffer,info->read_pos,
+ (size_t) (left_length=(uint) (info->read_end-info->read_pos)));
Buffer+=left_length;
org_Count=Count;
Count-=left_length;
@@ -329,13 +603,13 @@ int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count)
(int) (read_length+left_length));
return(1);
}
- info->pos_in_file+=(uint) (info->rc_end - info->rc_request_pos);
+ info->pos_in_file+=(uint) (info->read_end - info->request_pos);
- if (info->rc_request_pos != info->buffer)
- info->rc_request_pos=info->buffer;
+ if (info->request_pos != info->buffer)
+ info->request_pos=info->buffer;
else
- info->rc_request_pos=info->buffer+info->read_length;
- info->rc_pos=info->rc_request_pos;
+ info->request_pos=info->buffer+info->read_length;
+ info->read_pos=info->request_pos;
next_pos_in_file=info->aio_read_pos+read_length;
/* Check if pos_in_file is changed
@@ -352,8 +626,8 @@ int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count)
{
my_off_t offset= (info->pos_in_file - info->aio_read_pos);
info->pos_in_file=info->aio_read_pos; /* Whe are here */
- info->rc_pos=info->rc_request_pos+offset;
- read_length-=offset; /* Bytes left from rc_pos */
+ info->read_pos=info->request_pos+offset;
+ read_length-=offset; /* Bytes left from read_pos */
}
}
#ifndef DBUG_OFF
@@ -365,16 +639,16 @@ int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count)
#endif
/* Copy found bytes to buffer */
length=min(Count,read_length);
- memcpy(Buffer,info->rc_pos,(size_t) length);
+ memcpy(Buffer,info->read_pos,(size_t) length);
Buffer+=length;
Count-=length;
left_length+=length;
- info->rc_end=info->rc_pos+read_length;
- info->rc_pos+=length;
+ info->read_end=info->rc_pos+read_length;
+ info->read_pos+=length;
}
else
next_pos_in_file=(info->pos_in_file+ (uint)
- (info->rc_end - info->rc_request_pos));
+ (info->read_end - info->request_pos));
/* If reading large blocks, or first read or read with skipp */
if (Count)
@@ -388,13 +662,13 @@ int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count)
read_length=IO_SIZE*2- (uint) (next_pos_in_file & (IO_SIZE-1));
if (Count < read_length)
{ /* Small block, read to cache */
- if ((read_length=my_read(info->file,info->rc_request_pos,
+ if ((read_length=my_read(info->file,info->request_pos,
read_length, info->myflags)) == (uint) -1)
return info->error= -1;
use_length=min(Count,read_length);
- memcpy(Buffer,info->rc_request_pos,(size_t) use_length);
- info->rc_pos=info->rc_request_pos+Count;
- info->rc_end=info->rc_request_pos+read_length;
+ memcpy(Buffer,info->request_pos,(size_t) use_length);
+ info->read_pos=info->request_pos+Count;
+ info->read_end=info->request_pos+read_length;
info->pos_in_file=next_pos_in_file; /* Start of block in cache */
next_pos_in_file+=read_length;
@@ -415,7 +689,7 @@ int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count)
info->error= read_length == (uint) -1 ? -1 : read_length+left_length;
return 1;
}
- info->rc_pos=info->rc_end=info->rc_request_pos;
+ info->read_pos=info->read_end=info->request_pos;
info->pos_in_file=(next_pos_in_file+=Count);
}
}
@@ -426,7 +700,7 @@ int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count)
if (max_length > (my_off_t) info->read_length - diff_length)
max_length= (my_off_t) info->read_length - diff_length;
- if (info->rc_request_pos != info->buffer)
+ if (info->request_pos != info->buffer)
read_buffer=info->buffer;
else
read_buffer=info->buffer+info->read_length;
@@ -443,13 +717,13 @@ int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count)
my_errno=errno;
DBUG_PRINT("error",("got error: %d, aio_result: %d from aioread, async skipped",
errno, info->aio_result.result.aio_errno));
- if (info->rc_request_pos != info->buffer)
+ if (info->request_pos != info->buffer)
{
- bmove(info->buffer,info->rc_request_pos,
- (uint) (info->rc_end - info->rc_pos));
- info->rc_request_pos=info->buffer;
- info->rc_pos-=info->read_length;
- info->rc_end-=info->read_length;
+ bmove(info->buffer,info->request_pos,
+ (uint) (info->read_end - info->read_pos));
+ info->request_pos=info->buffer;
+ info->read_pos-=info->read_length;
+ info->read_end-=info->read_length;
}
info->read_length=info->buffer_length; /* Use hole buffer */
info->read_function=_my_b_read; /* Use normal IO_READ next */
@@ -467,8 +741,13 @@ int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count)
int _my_b_get(IO_CACHE *info)
{
byte buff;
+ IO_CACHE_CALLBACK pre_read,post_read;
+ if ((pre_read = info->pre_read))
+ (*pre_read)(info);
if ((*(info)->read_function)(info,&buff,1))
return my_b_EOF;
+ if ((post_read = info->post_read))
+ (*post_read)(info);
return (int) (uchar) buff;
}
@@ -478,11 +757,17 @@ int _my_b_write(register IO_CACHE *info, const byte *Buffer, uint Count)
{
uint rest_length,length;
- rest_length=(uint) (info->rc_end - info->rc_pos);
- memcpy(info->rc_pos,Buffer,(size_t) rest_length);
+ if (info->pos_in_file+info->buffer_length > info->end_of_file)
+ {
+ my_errno=errno=EFBIG;
+ return info->error = -1;
+ }
+
+ rest_length=(uint) (info->write_end - info->write_pos);
+ memcpy(info->write_pos,Buffer,(size_t) rest_length);
Buffer+=rest_length;
Count-=rest_length;
- info->rc_pos+=rest_length;
+ info->write_pos+=rest_length;
if (flush_io_cache(info))
return 1;
if (Count >= IO_SIZE)
@@ -499,8 +784,52 @@ int _my_b_write(register IO_CACHE *info, const byte *Buffer, uint Count)
Buffer+=length;
info->pos_in_file+=length;
}
- memcpy(info->rc_pos,Buffer,(size_t) Count);
- info->rc_pos+=Count;
+ memcpy(info->write_pos,Buffer,(size_t) Count);
+ info->write_pos+=Count;
+ return 0;
+}
+
+
+/*
+ Append a block to the write buffer.
+ This is done with the buffer locked to ensure that we don't read from
+ the write buffer before we are ready with it.
+*/
+
+int my_b_append(register IO_CACHE *info, const byte *Buffer, uint Count)
+{
+ uint rest_length,length;
+
+ lock_append_buffer(info);
+ rest_length=(uint) (info->write_end - info->write_pos);
+ if (Count <= rest_length)
+ goto end;
+ memcpy(info->write_pos,Buffer,(size_t) rest_length);
+ Buffer+=rest_length;
+ Count-=rest_length;
+ info->write_pos+=rest_length;
+ if (_flush_io_cache(info,0))
+ {
+ unlock_append_buffer(info);
+ return 1;
+ }
+ if (Count >= IO_SIZE)
+ { /* Fill first intern buffer */
+ length=Count & (uint) ~(IO_SIZE-1);
+ if (my_write(info->file,Buffer,(uint) length,info->myflags | MY_NABP))
+ {
+ unlock_append_buffer(info);
+ return info->error= -1;
+ }
+ Count-=length;
+ Buffer+=length;
+ info->end_of_file+=length;
+ }
+
+end:
+ memcpy(info->write_pos,Buffer,(size_t) Count);
+ info->write_pos+=Count;
+ unlock_append_buffer(info);
return 0;
}
@@ -530,10 +859,13 @@ int my_block_write(register IO_CACHE *info, const byte *Buffer, uint Count,
Buffer+=length;
pos+= length;
Count-= length;
+#ifndef HAVE_PREAD
+ info->seek_not_done=1;
+#endif
}
/* Check if we want to write inside the used part of the buffer.*/
- length= (uint) (info->rc_end - info->buffer);
+ length= (uint) (info->write_end - info->buffer);
if (pos < info->pos_in_file + length)
{
uint offset= (uint) (pos - info->pos_in_file);
@@ -544,8 +876,8 @@ int my_block_write(register IO_CACHE *info, const byte *Buffer, uint Count,
Buffer+=length;
Count-= length;
/* Fix length of buffer if the new data was larger */
- if (info->buffer+length > info->rc_pos)
- info->rc_pos=info->buffer+length;
+ if (info->buffer+length > info->write_pos)
+ info->write_pos=info->buffer+length;
if (!Count)
return (error);
}
@@ -555,46 +887,89 @@ int my_block_write(register IO_CACHE *info, const byte *Buffer, uint Count,
return error;
}
+
/* Flush write cache */
-int flush_io_cache(IO_CACHE *info)
+#ifdef THREAD
+#define LOCK_APPEND_BUFFER if (need_append_buffer_lock) \
+ lock_append_buffer(info);
+#define UNLOCK_APPEND_BUFFER if (need_append_buffer_lock) \
+ unlock_append_buffer(info);
+#else
+#define LOCK_APPEND_BUFFER
+#define UNLOCK_APPEND_BUFFER
+#endif
+
+
+int _flush_io_cache(IO_CACHE *info, int need_append_buffer_lock)
{
uint length;
+ my_bool append_cache;
+ my_off_t pos_in_file;
DBUG_ENTER("flush_io_cache");
- if (info->type == WRITE_CACHE)
+ if (!(append_cache = (info->type == SEQ_READ_APPEND)))
+ need_append_buffer_lock=0;
+
+ if (info->type == WRITE_CACHE || append_cache)
{
if (info->file == -1)
{
if (real_open_cached_file(info))
DBUG_RETURN((info->error= -1));
}
- if (info->rc_pos != info->buffer)
+ LOCK_APPEND_BUFFER;
+
+ if ((length=(uint) (info->write_pos - info->write_buffer)))
{
- length=(uint) (info->rc_pos - info->buffer);
- if (info->seek_not_done)
+ pos_in_file=info->pos_in_file;
+ /* if we have append cache, we always open the file with
+ O_APPEND which moves the pos to EOF automatically on every write
+ */
+ if (!append_cache && info->seek_not_done)
{ /* File touched, do seek */
- if (my_seek(info->file,info->pos_in_file,MY_SEEK_SET,MYF(0)) ==
+ if (my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0)) ==
MY_FILEPOS_ERROR)
+ {
+ UNLOCK_APPEND_BUFFER;
DBUG_RETURN((info->error= -1));
- info->seek_not_done=0;
+ }
+ if (!append_cache)
+ info->seek_not_done=0;
}
- info->rc_pos=info->buffer;
- info->pos_in_file+=length;
- info->rc_end=(info->buffer+info->buffer_length-
- (info->pos_in_file & (IO_SIZE-1)));
- if (my_write(info->file,info->buffer,length,info->myflags | MY_NABP))
- DBUG_RETURN((info->error= -1));
- DBUG_RETURN(0);
+ if (!append_cache)
+ info->pos_in_file+=length;
+ info->write_end= (info->write_buffer+info->buffer_length-
+ ((pos_in_file+length) & (IO_SIZE-1)));
+
+ if (my_write(info->file,info->write_buffer,length,
+ info->myflags | MY_NABP))
+ info->error= -1;
+ else
+ info->error= 0;
+ if (!append_cache)
+ {
+ set_if_bigger(info->end_of_file,(pos_in_file+length));
+ }
+ else
+ {
+ info->end_of_file+=(info->write_pos-info->append_read_pos);
+ DBUG_ASSERT(info->end_of_file == my_tell(info->file,MYF(0)));
+ }
+
+ info->append_read_pos=info->write_pos=info->write_buffer;
+ UNLOCK_APPEND_BUFFER;
+ DBUG_RETURN(info->error);
}
}
#ifdef HAVE_AIOWAIT
- else
+ else if (info->type != READ_NET)
{
- my_aiowait(&info->aio_result); /* Wait for outstanding req */
+ my_aiowait(&info->aio_result); /* Wait for outstanding req */
info->inited=0;
}
#endif
+ UNLOCK_APPEND_BUFFER;
DBUG_RETURN(0);
}
@@ -602,13 +977,118 @@ int flush_io_cache(IO_CACHE *info)
int end_io_cache(IO_CACHE *info)
{
int error=0;
+ IO_CACHE_CALLBACK pre_close;
DBUG_ENTER("end_io_cache");
- if (info->buffer)
+
+ if ((pre_close=info->pre_close))
+ (*pre_close)(info);
+ if (info->alloced_buffer)
{
+ info->alloced_buffer=0;
if (info->file != -1) /* File doesn't exist */
error=flush_io_cache(info);
my_free((gptr) info->buffer,MYF(MY_WME));
- info->buffer=info->rc_pos=(byte*) 0;
+ info->buffer=info->read_pos=(byte*) 0;
+ }
+ if (info->type == SEQ_READ_APPEND)
+ {
+ /* Destroy allocated mutex */
+ info->type=0;
+#ifdef THREAD
+ pthread_mutex_destroy(&info->append_buffer_lock);
+#endif
}
DBUG_RETURN(error);
} /* end_io_cache */
+
+
+/**********************************************************************
+ Testing of MF_IOCACHE
+**********************************************************************/
+
+#ifdef MAIN
+
+#include <my_dir.h>
+
+void die(const char* fmt, ...)
+{
+ va_list va_args;
+ va_start(va_args,fmt);
+ fprintf(stderr,"Error:");
+ vfprintf(stderr, fmt,va_args);
+ fprintf(stderr,", errno=%d\n", errno);
+ exit(1);
+}
+
+int open_file(const char* fname, IO_CACHE* info, int cache_size)
+{
+ int fd;
+ if ((fd=my_open(fname,O_CREAT | O_RDWR,MYF(MY_WME))) < 0)
+ die("Could not open %s", fname);
+ if (init_io_cache(info, fd, cache_size, SEQ_READ_APPEND, 0,0,MYF(MY_WME)))
+ die("failed in init_io_cache()");
+ return fd;
+}
+
+void close_file(IO_CACHE* info)
+{
+ end_io_cache(info);
+ my_close(info->file, MYF(MY_WME));
+}
+
+int main(int argc, char** argv)
+{
+ IO_CACHE sra_cache; /* SEQ_READ_APPEND */
+ MY_STAT status;
+ const char* fname="/tmp/iocache.test";
+ int cache_size=16384;
+ char llstr_buf[22];
+ int max_block,total_bytes=0;
+ int i,num_loops=100,error=0;
+ char *p;
+ char* block, *block_end;
+ MY_INIT(argv[0]);
+ max_block = cache_size*3;
+ if (!(block=(char*)my_malloc(max_block,MYF(MY_WME))))
+ die("Not enough memory to allocate test block");
+ block_end = block + max_block;
+ for (p = block,i=0; p < block_end;i++)
+ {
+ *p++ = (char)i;
+ }
+ if (my_stat(fname,&status, MYF(0)) &&
+ my_delete(fname,MYF(MY_WME)))
+ {
+ die("Delete of %s failed, aborting", fname);
+ }
+ open_file(fname,&sra_cache, cache_size);
+ for (i = 0; i < num_loops; i++)
+ {
+ char buf[4];
+ int block_size = abs(rand() % max_block);
+ int4store(buf, block_size);
+ if (my_b_append(&sra_cache,buf,4) ||
+ my_b_append(&sra_cache, block, block_size))
+ die("write failed");
+ total_bytes += 4+block_size;
+ }
+ close_file(&sra_cache);
+ my_free(block,MYF(MY_WME));
+ if (!my_stat(fname,&status,MYF(MY_WME)))
+ die("%s failed to stat, but I had just closed it,\
+ wonder how that happened");
+ printf("Final size of %s is %s, wrote %d bytes\n",fname,
+ llstr(status.st_size,llstr_buf),
+ total_bytes);
+ my_delete(fname, MYF(MY_WME));
+ /* check correctness of tests */
+ if (total_bytes != status.st_size)
+ {
+ fprintf(stderr,"Not the same number of bytes acutally in file as bytes \
+supposedly written\n");
+ error=1;
+ }
+ exit(error);
+ return 0;
+}
+#endif
diff --git a/mysys/mf_iocache2.c b/mysys/mf_iocache2.c
index 3e9cc74e0a2..127bf20e8fe 100644
--- a/mysys/mf_iocache2.c
+++ b/mysys/mf_iocache2.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
More functions to be used with IO_CACHE files
@@ -24,58 +23,114 @@
#include <m_string.h>
#include <stdarg.h>
#include <m_ctype.h>
+#include <assert.h>
+
+my_off_t my_b_append_tell(IO_CACHE* info)
+{
+ /* prevent optimizer from putting res in a register when debugging
+ we need this to be able to see the value of res when the assert fails
+ */
+ dbug_volatile my_off_t res;
+/* we need to lock the append buffer mutex to keep flush_io_cache()
+ from messing with the variables that we need in order to provide the
+ answer to the question.
+*/
+#ifdef THREAD
+ pthread_mutex_lock(&info->append_buffer_lock);
+#endif
+ /* save the value of my_tell in res so we can see it when studying
+ coredump
+ */
+#ifndef DBUG_OFF
+ /* make sure EOF is where we think it is. Note that we cannot just use
+ my_tell() because we have a reader thread that could have left the
+ file offset in a non-EOF location
+ */
+ {
+ volatile my_off_t save_pos;
+ save_pos = my_tell(info->file,MYF(0));
+ my_seek(info->file,(my_off_t)0,MY_SEEK_END,MYF(0));
+ DBUG_ASSERT(info->end_of_file - (info->append_read_pos-info->write_buffer)
+ == (res=my_tell(info->file,MYF(0))));
+ my_seek(info->file,save_pos,MY_SEEK_SET,MYF(0));
+ }
+#endif
+ res = info->end_of_file + (info->write_pos-info->append_read_pos);
+#ifdef THREAD
+ pthread_mutex_unlock(&info->append_buffer_lock);
+#endif
+ return res;
+}
/*
-** Fix that next read will be made at certain position
-** For write cache, make next write happen at a certain position
+ Make next read happen at the given position
+ For write cache, make next write happen at the given position
*/
void my_b_seek(IO_CACHE *info,my_off_t pos)
{
- my_off_t offset = (pos - info->pos_in_file);
+ my_off_t offset;
DBUG_ENTER("my_b_seek");
DBUG_PRINT("enter",("pos: %lu", (ulong) pos));
- if (info->type == READ_CACHE)
+ /*
+ TODO: verify that it is OK to do seek in the non-append
+ area in SEQ_READ_APPEND cache
+ */
+ /* TODO:
+ a) see if this always works
+ b) see if there is a better way to make it work
+ */
+ if (info->type == SEQ_READ_APPEND)
+ flush_io_cache(info);
+
+ offset=(pos - info->pos_in_file);
+
+ if (info->type == READ_CACHE || info->type == SEQ_READ_APPEND)
{
- if ((ulonglong) offset < (ulonglong) (info->rc_end - info->buffer))
+ /* TODO: explain why this works if pos < info->pos_in_file */
+ if ((ulonglong) offset < (ulonglong) (info->read_end - info->buffer))
{
/* The read is in the current buffer; Reuse it */
- info->rc_pos = info->buffer + offset;
+ info->read_pos = info->buffer + offset;
DBUG_VOID_RETURN;
}
else
{
/* Force a new read on next my_b_read */
- info->rc_pos=info->rc_end=info->buffer;
+ info->read_pos=info->read_end=info->buffer;
}
}
else if (info->type == WRITE_CACHE)
{
/* If write is in current buffer, reuse it */
if ((ulonglong) offset <
- (ulonglong) (info->rc_end - info->buffer))
+ (ulonglong) (info->write_end - info->write_buffer))
{
- info->rc_pos = info->buffer + offset;
+ info->write_pos = info->write_buffer + offset;
DBUG_VOID_RETURN;
}
flush_io_cache(info);
- info->rc_end=(info->buffer+info->buffer_length-(pos & (IO_SIZE-1)));
+ /* Correct buffer end so that we write in increments of IO_SIZE */
+ info->write_end=(info->write_buffer+info->buffer_length-
+ (pos & (IO_SIZE-1)));
}
info->pos_in_file=pos;
info->seek_not_done=1;
}
+
/*
-** Fill buffer. Note that this assumes that you have already used
-** all characters in the CACHE, independent of the rc_pos value!
-** return: 0 on error or EOF (info->error = -1 on error)
-** number of characters
+ Fill buffer. Note that this assumes that you have already used
+ all characters in the CACHE, independent of the read_pos value!
+ return: 0 on error or EOF (info->error = -1 on error)
+ number of characters
*/
uint my_b_fill(IO_CACHE *info)
{
- my_off_t pos_in_file=info->pos_in_file+(uint) (info->rc_end - info->buffer);
+ my_off_t pos_in_file=(info->pos_in_file+
+ (uint) (info->read_end - info->buffer));
my_off_t max_length;
uint diff_length,length;
if (info->seek_not_done)
@@ -103,16 +158,18 @@ uint my_b_fill(IO_CACHE *info)
info->error= -1;
return 0;
}
- info->rc_pos=info->buffer;
- info->rc_end=info->buffer+length;
+ info->read_pos=info->buffer;
+ info->read_end=info->buffer+length;
info->pos_in_file=pos_in_file;
return length;
}
+
/*
-** Read a string ended by '\n' into a buffer of 'max_length' size.
-** Returns number of characters read, 0 on error.
-** last byte is set to '\0'
+ Read a string ended by '\n' into a buffer of 'max_length' size.
+ Returns number of characters read, 0 on error.
+ last byte is set to '\0'
+ If buffer is full then to[max_length-1] will be set to \0.
*/
uint my_b_gets(IO_CACHE *info, char *to, uint max_length)
@@ -129,11 +186,11 @@ uint my_b_gets(IO_CACHE *info, char *to, uint max_length)
char *pos,*end;
if (length > max_length)
length=max_length;
- for (pos=info->rc_pos,end=pos+length ; pos < end ;)
+ for (pos=info->read_pos,end=pos+length ; pos < end ;)
{
if ((*to++ = *pos++) == '\n')
{
- info->rc_pos=pos;
+ info->read_pos=pos;
*to='\0';
return (uint) (to-start);
}
@@ -141,7 +198,7 @@ uint my_b_gets(IO_CACHE *info, char *to, uint max_length)
if (!(max_length-=length))
{
/* Found enough charcters; Return found string */
- info->rc_pos=pos;
+ info->read_pos=pos;
*to='\0';
return (uint) (to-start);
}
@@ -150,6 +207,7 @@ uint my_b_gets(IO_CACHE *info, char *to, uint max_length)
}
}
+
/*
Simple printf version. Supports '%s', '%d', '%u', "%ld" and "%lu"
Used for logging in MySQL
diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c
index 5b8ec96b4d1..2ddf13bfa1f 100644
--- a/mysys/mf_keycache.c
+++ b/mysys/mf_keycache.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 functions is handle keyblock cacheing for NISAM, MISAM and PISAM
@@ -53,7 +52,6 @@ typedef struct sec_link {
} SEC_LINK;
-static uint find_next_bigger_power(uint value);
static SEC_LINK *find_key_block(int file,my_off_t filepos,int *error);
/* static variables in this file */
@@ -61,9 +59,11 @@ static SEC_LINK *_my_block_root,**_my_hash_root,
*_my_used_first,*_my_used_last;
static int _my_disk_blocks;
static uint _my_disk_blocks_used, _my_hash_blocks;
+static uint key_cache_shift;
ulong _my_blocks_used,_my_blocks_changed;
ulong _my_cache_w_requests,_my_cache_write,_my_cache_r_requests,
_my_cache_read;
+uint key_cache_block_size=DEFAULT_KEYCACHE_BLOCK_SIZE;
static byte HUGE_PTR *_my_block_mem;
static SEC_LINK *changed_blocks[CHANGED_BLOCKS_HASH];
static SEC_LINK *file_blocks[CHANGED_BLOCKS_HASH];
@@ -92,12 +92,16 @@ int init_key_cache(ulong use_mem,
{
key_cache_inited=TRUE;
_my_disk_blocks= -1;
+ key_cache_shift=my_bit_log2(key_cache_block_size);
+ DBUG_PRINT("info",("key_cache_block_size: %u key_cache_shift: %u",
+ key_cache_block_size, key_cache_shift));
#ifndef DBUG_OFF
_my_printed=0;
#endif
}
- blocks= (uint) (use_mem/(sizeof(SEC_LINK)+sizeof(SEC_LINK*)*5/4+KEYCACHE_BLOCK_SIZE));
+ blocks= (uint) (use_mem/(sizeof(SEC_LINK)+sizeof(SEC_LINK*)*5/4+
+ key_cache_block_size));
/* No use to have very few blocks */
if (blocks >= 8 && _my_disk_blocks < 0)
{
@@ -107,13 +111,15 @@ int init_key_cache(ulong use_mem,
#endif
for (;;)
{
- if ((_my_hash_blocks=find_next_bigger_power((uint) blocks)) < blocks*5/4)
- _my_hash_blocks<<=1;
+ /* Set my_hash_blocks to the next bigger 2 power */
+ _my_hash_blocks=(uint) 1 << (my_bit_log2(blocks*5/4)+1);
while ((length=(uint) blocks*sizeof(SEC_LINK)+
- sizeof(SEC_LINK*)*_my_hash_blocks)+(ulong) blocks*KEYCACHE_BLOCK_SIZE >
+ sizeof(SEC_LINK*)*_my_hash_blocks)+
+ ((ulong) blocks << key_cache_shift) >
use_mem)
blocks--;
- if ((_my_block_mem=my_malloc_lock((ulong) blocks * KEYCACHE_BLOCK_SIZE,MYF(0))))
+ if ((_my_block_mem=my_malloc_lock((ulong) blocks << key_cache_shift,
+ MYF(0))))
{
if ((_my_block_root=(SEC_LINK*) my_malloc((uint) length,MYF(0))) != 0)
break;
@@ -162,6 +168,7 @@ void end_key_cache(void)
}
}
key_cache_inited=0;
+ _my_hash_blocks=_my_blocks_used=0;
DBUG_PRINT("status",
("used: %d changed: %d w_requests: %ld writes: %ld r_requests: %ld reads: %ld",
_my_blocks_used,_my_blocks_changed,_my_cache_w_requests,
@@ -170,17 +177,6 @@ void end_key_cache(void)
} /* end_key_cache */
-static uint find_next_bigger_power(uint value)
-{
- uint old_value=1;
- while (value)
- {
- old_value=value;
- value&= value-1;
- }
- return (old_value << 1);
-}
-
static inline void link_into_file_blocks(SEC_LINK *next, int file)
{
reg1 SEC_LINK **ptr= &file_blocks[(uint) file & CHANGED_BLOCKS_MASK];
@@ -243,7 +239,7 @@ static void test_key_cache(const char *where, my_bool lock);
/*
** read a key_buffer
- ** filepos must point at a even KEYCACHE_BLOCK_SIZE block
+ ** filepos must point at a even key_cache_block_size block
** if return_buffer is set then the intern buffer is returned if
** it can be used
** Returns adress to where data is read
@@ -255,9 +251,12 @@ byte *key_cache_read(File file, my_off_t filepos, byte *buff, uint length,
{
reg1 SEC_LINK *next;
int error=0;
+ DBUG_ENTER("key_cache_read");
+ DBUG_PRINT("enter", ("file %u, filepos %lu, length %u",
+ (uint) file, (ulong) filepos, length));
#ifndef THREAD
- if (block_length > KEYCACHE_BLOCK_SIZE)
+ if (block_length > key_cache_block_size)
return_buffer=0;
#endif
if (_my_disk_blocks > 0)
@@ -268,18 +267,19 @@ byte *key_cache_read(File file, my_off_t filepos, byte *buff, uint length,
do
{
_my_cache_r_requests++;
- read_length= length > KEYCACHE_BLOCK_SIZE ? KEYCACHE_BLOCK_SIZE : length;
+ read_length= (length > key_cache_block_size ? key_cache_block_size :
+ length);
if (!(next=find_key_block(file,filepos,&error)))
{
pthread_mutex_unlock(&THR_LOCK_keycache);
- return (byte*) 0; /* Got a fatal error */
+ DBUG_RETURN ((byte*) 0); /* Got a fatal error */
}
if (error)
{ /* Didn't find it in cache */
if (my_pread(file,next->buffer,read_length,filepos,MYF(MY_NABP)))
{
pthread_mutex_unlock(&THR_LOCK_keycache);
- return((byte*) 0);
+ DBUG_RETURN((byte*) 0);
}
_my_cache_read++;
}
@@ -287,7 +287,7 @@ byte *key_cache_read(File file, my_off_t filepos, byte *buff, uint length,
if (return_buffer)
{
pthread_mutex_unlock(&THR_LOCK_keycache);
- return (next->buffer);
+ DBUG_RETURN (next->buffer);
}
#endif
if (! (read_length & 511))
@@ -298,19 +298,19 @@ byte *key_cache_read(File file, my_off_t filepos, byte *buff, uint length,
filepos+=read_length;
} while ((length-= read_length));
pthread_mutex_unlock(&THR_LOCK_keycache);
- return(start);
+ DBUG_RETURN(start);
}
_my_cache_r_requests++;
_my_cache_read++;
if (my_pread(file,(byte*) buff,length,filepos,MYF(MY_NABP)))
error=1;
- return (error ? (byte*) 0 : buff);
+ DBUG_RETURN(error ? (byte*) 0 : buff);
} /* key_cache_read */
/* write a key_buffer */
/* We don't have to use pwrite because of write locking */
- /* buff must point at a even KEYCACHE_BLOCK_SIZE block */
+ /* buff must point at a even key_cache_block_size block */
int key_cache_write(File file, my_off_t filepos, byte *buff, uint length,
uint block_length __attribute__((unused)),
@@ -318,12 +318,15 @@ int key_cache_write(File file, my_off_t filepos, byte *buff, uint length,
{
reg1 SEC_LINK *next;
int error=0;
+ DBUG_ENTER("key_cache_write");
+ DBUG_PRINT("enter", ("file %u, filepos %lu, length %u",
+ (uint) file, (ulong) filepos, length));
if (!dont_write)
{ /* Forced write of buffer */
_my_cache_write++;
if (my_pwrite(file,buff,length,filepos,MYF(MY_NABP | MY_WAIT_IF_FULL)))
- return(1);
+ DBUG_RETURN(1);
}
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
@@ -336,7 +339,7 @@ int key_cache_write(File file, my_off_t filepos, byte *buff, uint length,
_my_cache_w_requests++;
do
{
- read_length= length > KEYCACHE_BLOCK_SIZE ? KEYCACHE_BLOCK_SIZE : length;
+ read_length= length > key_cache_block_size ? key_cache_block_size : length;
if (!(next=find_key_block(file,filepos,&error)))
goto end; /* Fatal error */
if (!dont_write) /* If we wrote buff at start */
@@ -369,7 +372,7 @@ end:
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
DBUG_EXECUTE("check_keycache",test_key_cache("end of key_cache_write",1););
#endif
- return(error);
+ DBUG_RETURN(error);
} /* key_cache_write */
@@ -379,13 +382,16 @@ end:
static SEC_LINK *find_key_block(int file, my_off_t filepos, int *error)
{
reg1 SEC_LINK *next,**start;
+ DBUG_ENTER("find_key_block");
+ DBUG_PRINT("enter", ("file %u, filepos %lu",
+ (uint) file, (ulong) filepos));
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
DBUG_EXECUTE("check_keycache2",test_key_cache("start of find_key_block",0););
#endif
*error=0;
- next= *(start= &_my_hash_root[((ulong) (filepos/KEYCACHE_BLOCK_SIZE)+(ulong) file) &
+ next= *(start= &_my_hash_root[((ulong) (filepos >> key_cache_shift)+(ulong) file) &
(_my_hash_blocks-1)]);
while (next && (next->diskpos != filepos || next->file != file))
next= next->next_hash;
@@ -411,7 +417,8 @@ static SEC_LINK *find_key_block(int file, my_off_t filepos, int *error)
{ /* There are unused blocks */
next= &_my_block_root[_my_blocks_used++]; /* Link in hash-chain */
next->buffer=ADD_TO_PTR(_my_block_mem,
- (ulong) _my_disk_blocks_used*KEYCACHE_BLOCK_SIZE,byte*);
+ ((ulong) _my_disk_blocks_used << key_cache_shift),
+ byte*);
/* link first in file_blocks */
next->changed=0;
link_into_file_blocks(next,file);
@@ -426,7 +433,8 @@ static SEC_LINK *find_key_block(int file, my_off_t filepos, int *error)
next= _my_used_first;
if (next->changed)
{
- if (my_pwrite(next->file,next->buffer,KEYCACHE_BLOCK_SIZE,next->diskpos,
+ if (my_pwrite(next->file,next->buffer,key_cache_block_size,
+ next->diskpos,
MYF(MY_NABP | MY_WAIT_IF_FULL)))
{
*error=1;
@@ -461,7 +469,7 @@ static SEC_LINK *find_key_block(int file, my_off_t filepos, int *error)
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
DBUG_EXECUTE("check_keycache2",test_key_cache("end of find_key_block",0););
#endif
- return next;
+ DBUG_RETURN(next);
} /* find_key_block */
@@ -505,7 +513,8 @@ static int flush_cached_blocks(File file, SEC_LINK **cache, uint count)
qsort((byte*) cache, count, sizeof(*cache), (qsort_cmp) cmp_sec_link);
for ( ; count-- ; cache++)
{
- if (my_pwrite(file,(*cache)->buffer,KEYCACHE_BLOCK_SIZE,(*cache)->diskpos,
+ if (my_pwrite(file,(*cache)->buffer,key_cache_block_size,
+ (*cache)->diskpos,
MYF(MY_NABP | MY_WAIT_IF_FULL)))
{
if (!last_errno)
@@ -646,7 +655,7 @@ static void test_key_cache(const char *where, my_bool lock)
i,(ulong) pos,(ulong) prev,(ulong) pos->prev_hash));
}
- if (((pos->diskpos/KEYCACHE_BLOCK_SIZE)+pos->file) % _my_hash_blocks != i)
+ if (((pos->diskpos >> key_cache_shift)+pos->file) % _my_hash_blocks != i)
{
DBUG_PRINT("error",("hash: %d pos: %lx : Wrong disk_buffer %ld",
i,(ulong) pos,(ulong) pos->diskpos));
diff --git a/mysys/mf_loadpath.c b/mysys/mf_loadpath.c
index 641528b8b5d..291ad62e297 100644
--- a/mysys/mf_loadpath.c
+++ b/mysys/mf_loadpath.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysys_priv.h"
#include <m_string.h>
@@ -37,8 +36,7 @@ my_string my_load_path(my_string to, const char *path,
test_if_hard_path(path))
VOID(strmov(buff,path));
else if ((path[0] == FN_CURLIB && path[1] == FN_LIBCHAR) ||
- (is_prefix((gptr) path,FN_PARENTDIR) &&
- path[strlen(FN_PARENTDIR)] == FN_LIBCHAR) ||
+ (is_prefix((gptr) path,FN_PARENTDIR)) ||
! own_path_prefix)
{
if (! my_getwd(buff,(uint) (FN_REFLEN-strlen(path)),MYF(0)))
diff --git a/mysys/mf_pack.c b/mysys/mf_pack.c
index b442af7e9e5..8fba14f626b 100644
--- a/mysys/mf_pack.c
+++ b/mysys/mf_pack.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysys_priv.h"
#include <m_string.h>
@@ -40,6 +39,7 @@ void pack_dirname(my_string to, const char *from)
char buff[FN_REFLEN];
DBUG_ENTER("pack_dirname");
+ LINT_INIT(buff_length);
(void) intern_filename(to,from); /* Change to intern name */
#ifdef FN_DEVCHAR
@@ -49,7 +49,6 @@ void pack_dirname(my_string to, const char *from)
#endif
start=to;
- LINT_INIT(buff_length);
if (!(cwd_err= my_getwd(buff,FN_REFLEN,MYF(0))))
{
buff_length= (uint) strlen(buff);
@@ -218,7 +217,7 @@ uint cleanup_dirname(register my_string to, const char *from)
to the directory. This will be used if the directory name
doesn't exists
*/
-
+
my_bool my_use_symdir=0; /* Set this if you want to use symdirs */
@@ -459,8 +458,7 @@ my_string intern_filename(my_string to, const char *from)
my_string pos,from_pos,to_pos,end_pos;
char buff[FN_REFLEN];
- (void) strmov(buff,from);
- convert_dirname(buff); /* change '<>' to '[]' */
+ convert_dirname(buff,from,NullS); /* change '<>' to '[]' */
from_pos=buff;
if ((pos=strrchr(from_pos,FN_DEVCHAR))) /* Skipp device part */
{
diff --git a/mysys/mf_pack2.c b/mysys/mf_pack2.c
deleted file mode 100644
index 1cda7797457..00000000000
--- a/mysys/mf_pack2.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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 */
-
-#include "mysys_priv.h"
-#include <m_string.h>
-
- /* Pack a filename for output on screen */
- /* Changes long paths to .../ */
- /* Removes pathname and extension */
- /* If not possibly to pack returns '?' in to and returns 1*/
-
-int pack_filename(my_string to, const char *name, size_s max_length)
- /* to may be name */
-
-{
- int i;
- char buff[FN_REFLEN];
-
- if (strlen(fn_format(to,name,"","",0)) <= max_length)
- return 0;
- if (strlen(fn_format(to,name,"","",8)) <= max_length)
- return 0;
- if (strlen(fn_format(buff,name,".../","",1)) <= max_length)
- {
- VOID(strmov(to,buff));
- return 0;
- }
- for (i= 0 ; i < 3 ; i++)
- {
- if (strlen(fn_format(buff,to,"","", i == 0 ? 2 : i == 1 ? 1 : 3 ))
- <= max_length)
- {
- VOID(strmov(to,buff));
- return 0;
- }
- }
- to[0]='?'; to[1]=0; /* Can't pack filename */
- return 1;
-} /* pack_filename */
diff --git a/mysys/mf_path.c b/mysys/mf_path.c
index 9a88b938e2c..23eadd2acce 100644
--- a/mysys/mf_path.c
+++ b/mysys/mf_path.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysys_priv.h"
#include <m_string.h>
diff --git a/mysys/mf_qsort2.c b/mysys/mf_qsort2.c
index 7b1ca4e39ab..160bb6df817 100644
--- a/mysys/mf_qsort2.c
+++ b/mysys/mf_qsort2.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* qsort that sends one extra argument to the compare subrutine */
diff --git a/mysys/mf_radix.c b/mysys/mf_radix.c
index 99aa4d0b073..7ee96b966b9 100644
--- a/mysys/mf_radix.c
+++ b/mysys/mf_radix.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
Radixsort for pointers to fixed length strings.
diff --git a/mysys/mf_same.c b/mysys/mf_same.c
index c1a5cae11cb..efd6e7b2ca4 100644
--- a/mysys/mf_same.c
+++ b/mysys/mf_same.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Kopierar biblioteksstrukturen och extensionen fr}n ett filnamn */
diff --git a/mysys/mf_sleep.c b/mysys/mf_sleep.c
index f33a904cf5a..49db465e7c5 100644
--- a/mysys/mf_sleep.c
+++ b/mysys/mf_sleep.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Wait a given time (On systems that dont have sleep !!; MSDOS) */
diff --git a/mysys/mf_sort.c b/mysys/mf_sort.c
index 754a1deb1a7..0dc6c78a589 100644
--- a/mysys/mf_sort.c
+++ b/mysys/mf_sort.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Sort of string pointers in string-order with radix or qsort */
@@ -25,7 +24,7 @@ void my_string_ptr_sort(void *base, uint items, size_s size)
#if INT_MAX > 65536L
uchar **ptr=0;
- if (size <= 20 && items >= 1000 &&
+ if (size <= 20 && items >= 1000 && items < 100000 &&
(ptr= (uchar**) my_malloc(items*sizeof(char*),MYF(0))))
{
radixsort_for_str_ptr((uchar**) base,items,size,ptr);
diff --git a/mysys/mf_soundex.c b/mysys/mf_soundex.c
index 827385a1466..4f7aa7da601 100644
--- a/mysys/mf_soundex.c
+++ b/mysys/mf_soundex.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/****************************************************************
* SOUNDEX ALGORITHM in C *
diff --git a/mysys/mf_stripp.c b/mysys/mf_stripp.c
index 6ebdce4cff6..d2fd171ec8c 100644
--- a/mysys/mf_stripp.c
+++ b/mysys/mf_stripp.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* T|mmer en str{ng p{ slut_space */
diff --git a/mysys/mf_tempfile.c b/mysys/mf_tempfile.c
index 465311088c1..86e43e5b6fc 100644
--- a/mysys/mf_tempfile.c
+++ b/mysys/mf_tempfile.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysys_priv.h"
#include <m_string.h>
@@ -90,9 +89,10 @@ File create_temp_file(char *to, const char *dir, const char *prefix,
uint pfx_len;
File org_file;
- pfx_len=(strmov(strnmov(prefix_buff,
- prefix ? prefix : "tmp.",
- sizeof(prefix_buff)-7),"XXXXXX") - prefix_buff);
+ pfx_len= (uint) (strmov(strnmov(prefix_buff,
+ prefix ? prefix : "tmp.",
+ sizeof(prefix_buff)-7),"XXXXXX") -
+ prefix_buff);
if (!dir && ! (dir =getenv("TMPDIR")))
dir=P_tmpdir;
if (strlen(dir)+ pfx_len > FN_REFLEN-2)
@@ -100,8 +100,7 @@ File create_temp_file(char *to, const char *dir, const char *prefix,
errno=my_errno= ENAMETOOLONG;
return 1;
}
- strmov(to,dir);
- strmov(convert_dirname(to),prefix_buff);
+ strmov(convert_dirname(to,dir,NullS),prefix_buff);
org_file=mkstemp(to);
file=my_register_filename(org_file, to, FILE_BY_MKSTEMP,
EE_CANTCREATEFILE, MyFlags);
@@ -178,7 +177,7 @@ File create_temp_file(char *to, const char *dir, const char *prefix,
if (end_pos != to && end_pos[-1] != FN_LIBCHAR)
*end_pos++=FN_LIBCHAR;
end_pos=strmov(end_pos,pfx);
-
+
for (length=0 ; length < 8 && uniq ; length++)
{
*end_pos++= _dig_vec[(int) (uniq & 31)];
diff --git a/mysys/mf_unixpath.c b/mysys/mf_unixpath.c
index 6ae29f99136..9efc3e5d9b8 100644
--- a/mysys/mf_unixpath.c
+++ b/mysys/mf_unixpath.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysys_priv.h"
#include <m_string.h>
diff --git a/mysys/mf_util.c b/mysys/mf_util.c
index 12af323680e..132c83b4623 100644
--- a/mysys/mf_util.c
+++ b/mysys/mf_util.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Utilities with are missing on some systems */
diff --git a/mysys/mf_wcomp.c b/mysys/mf_wcomp.c
index 5f1ab9b813e..bdcfb0501d8 100644
--- a/mysys/mf_wcomp.c
+++ b/mysys/mf_wcomp.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Funktions for comparing with wild-cards */
diff --git a/mysys/mf_wfile.c b/mysys/mf_wfile.c
index 87d1392250a..e9e12c72755 100644
--- a/mysys/mf_wfile.c
+++ b/mysys/mf_wfile.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 finding files with wildcards */
diff --git a/mysys/mulalloc.c b/mysys/mulalloc.c
index 8a7ee312aa9..a2960aec4b5 100644
--- a/mysys/mulalloc.c
+++ b/mysys/mulalloc.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Malloc many pointers at the same time */
/* format myFlags,ptr,length,ptr,length ... until null ptr */
diff --git a/mysys/my_alarm.c b/mysys/my_alarm.c
index aab01ad77f4..70daf4a9dd0 100644
--- a/mysys/my_alarm.c
+++ b/mysys/my_alarm.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Function to set a varible when we got a alarm */
/* Used by my_lock samt functions in m_alarm.h */
diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c
index db482454e69..789e64526a3 100644
--- a/mysys/my_alloc.c
+++ b/mysys/my_alloc.c
@@ -1,27 +1,29 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Routines to handle mallocing of results which will be freed the same time */
-#include <global.h>
+#include <my_global.h>
#include <my_sys.h>
#include <m_string.h>
+#undef EXTRA_DEBUG
+#define EXTRA_DEBUG
-void init_alloc_root(MEM_ROOT *mem_root, uint block_size, uint pre_alloc_size)
+void init_alloc_root(MEM_ROOT *mem_root, uint block_size,
+ uint pre_alloc_size __attribute__((unused)))
{
mem_root->free=mem_root->used=0;
mem_root->min_malloc=32;
@@ -55,6 +57,7 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size)
return((gptr) 0); /* purecov: inspected */
}
next->next=mem_root->used;
+ next->size= Size;
mem_root->used=next;
return (gptr) (((char*) next)+ALIGN_SIZE(sizeof(USED_MEM)));
#else
@@ -100,7 +103,34 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size)
#endif
}
- /* deallocate everything used by alloc_root */
+/* Mark all data in blocks free for reusage */
+
+static inline void mark_blocks_free(MEM_ROOT* root)
+{
+ reg1 USED_MEM *next;
+ reg2 USED_MEM **last;
+
+ /* iterate through (partially) free blocks, mark them free */
+ last= &root->free;
+ for (next= root->free; next; next= *(last= &next->next))
+ next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
+
+ /* Combine the free and the used list */
+ *last= next=root->used;
+
+ /* now go through the used blocks and mark them free */
+ for (; next; next= next->next)
+ next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
+
+ /* Now everything is set; Indicate that nothing is used anymore */
+ root->used= 0;
+}
+
+
+/*
+ Deallocate everything used by alloc_root or just move
+ used blocks to free list if called with MY_USED_TO_FREE
+*/
void free_root(MEM_ROOT *root, myf MyFlags)
{
@@ -109,18 +139,23 @@ void free_root(MEM_ROOT *root, myf MyFlags)
if (!root)
DBUG_VOID_RETURN; /* purecov: inspected */
+ if (MyFlags & MY_MARK_BLOCKS_FREE)
+ {
+ mark_blocks_free(root);
+ DBUG_VOID_RETURN;
+ }
if (!(MyFlags & MY_KEEP_PREALLOC))
root->pre_alloc=0;
- for ( next=root->used; next ;)
+ for (next=root->used; next ;)
{
old=next; next= next->next ;
if (old != root->pre_alloc)
my_free((gptr) old,MYF(0));
}
- for (next= root->free ; next ; )
+ for (next=root->free ; next ;)
{
- old=next; next= next->next ;
+ old=next; next= next->next;
if (old != root->pre_alloc)
my_free((gptr) old,MYF(0));
}
@@ -134,13 +169,45 @@ void free_root(MEM_ROOT *root, myf MyFlags)
DBUG_VOID_RETURN;
}
+/*
+ Find block that contains an object and set the pre_alloc to it
+*/
+
+void set_prealloc_root(MEM_ROOT *root, char *ptr)
+{
+ USED_MEM *next;
+ for (next=root->used; next ; next=next->next)
+ {
+ if ((char*) next <= ptr && (char*) next + next->size > ptr)
+ {
+ root->pre_alloc=next;
+ return;
+ }
+ }
+ for (next=root->free ; next ; next=next->next)
+ {
+ if ((char*) next <= ptr && (char*) next + next->size > ptr)
+ {
+ root->pre_alloc=next;
+ return;
+ }
+ }
+}
+
char *strdup_root(MEM_ROOT *root,const char *str)
{
- uint len= (uint) strlen(str)+1;
+ return strmake_root(root, str, strlen(str));
+}
+
+char *strmake_root(MEM_ROOT *root,const char *str, uint len)
+{
char *pos;
- if ((pos=alloc_root(root,len)))
+ if ((pos=alloc_root(root,len+1)))
+ {
memcpy(pos,str,len);
+ pos[len]=0;
+ }
return pos;
}
diff --git a/mysys/my_append.c b/mysys/my_append.c
index 0d3296fb278..2e08b4b4c05 100644
--- a/mysys/my_append.c
+++ b/mysys/my_append.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#define USES_TYPES /* sys/types is included */
#include "mysys_priv.h"
diff --git a/mysys/my_bit.c b/mysys/my_bit.c
new file mode 100644
index 00000000000..0ff487afe03
--- /dev/null
+++ b/mysys/my_bit.c
@@ -0,0 +1,31 @@
+/* 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 */
+
+/* Some useful bit functions */
+
+#include "mysys_priv.h"
+
+/*
+ Find smallest X in 2^X >= value
+ This can be used to divide a number with value by doing a shift instead
+*/
+
+uint my_bit_log2(ulong value)
+{
+ uint bit;
+ for (bit=0 ; value > 1 ; value>>=1, bit++) ;
+ return bit;
+}
diff --git a/mysys/my_bitmap.c b/mysys/my_bitmap.c
index a18fcba0b60..8834dda98e1 100644
--- a/mysys/my_bitmap.c
+++ b/mysys/my_bitmap.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
Handling of uchar arrays as large bitmaps.
@@ -26,7 +25,6 @@
#include "mysys_priv.h"
#include <my_bitmap.h>
#include <assert.h>
-#include <string.h>
#include <m_string.h>
inline void bitmap_lock(MY_BITMAP* map)
@@ -50,7 +48,7 @@ my_bool bitmap_init(MY_BITMAP *map, uint bitmap_size, my_bool thread_safe)
if (!(map->bitmap=(uchar*) my_malloc((bitmap_size+7)/8,
MYF(MY_WME | MY_ZEROFILL))))
return 1;
- dbug_assert(bitmap_size != ~(uint) 0);
+ DBUG_ASSERT(bitmap_size != ~(uint) 0);
#ifdef THREAD
if ((map->thread_safe = thread_safe))
pthread_mutex_init(&map->mutex, MY_MUTEX_INIT_FAST);
@@ -123,6 +121,7 @@ void bitmap_clear_bit(MY_BITMAP *map, uint bitmap_bit)
}
}
+
void bitmap_set_all(MY_BITMAP* map)
{
bitmap_lock(map);
diff --git a/mysys/my_chsize.c b/mysys/my_chsize.c
index 2c07e8d136f..aeab9e47ee2 100644
--- a/mysys/my_chsize.c
+++ b/mysys/my_chsize.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysys_priv.h"
#include "mysys_err.h"
diff --git a/mysys/my_clock.c b/mysys/my_clock.c
index e7d1758fa2e..e49b2f85b66 100644
--- a/mysys/my_clock.c
+++ b/mysys/my_clock.c
@@ -1,22 +1,21 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#define USES_TYPES
-#include "global.h"
+#include "my_global.h"
#if !defined(_MSC_VER) && !defined(__BORLANDC__) && !defined(OS2)
#include "mysys_priv.h"
diff --git a/mysys/my_compress.c b/mysys/my_compress.c
index f97d28c25ea..1e46584d525 100644
--- a/mysys/my_compress.c
+++ b/mysys/my_compress.c
@@ -1,26 +1,27 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/* Written by Sinisa Milivojevic <sinisa@coresinc.com> */
+/* Written by Sinisa Milivojevic <sinisa@mysql.com> */
-#include <global.h>
+#include <my_global.h>
#ifdef HAVE_COMPRESS
#include <my_sys.h>
+#ifndef SCO
#include <m_string.h>
+#endif
#include <zlib.h>
/*
diff --git a/mysys/my_copy.c b/mysys/my_copy.c
index 9b02d84d063..253608c5306 100644
--- a/mysys/my_copy.c
+++ b/mysys/my_copy.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#define USES_TYPES /* sys/types is included */
#include "mysys_priv.h"
diff --git a/mysys/my_create.c b/mysys/my_create.c
index 5a10b0fd8b5..5fa97a9ca78 100644
--- a/mysys/my_create.c
+++ b/mysys/my_create.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#define USES_TYPES
#include "mysys_priv.h"
diff --git a/mysys/my_delete.c b/mysys/my_delete.c
index 77d5f311418..5670f03da64 100644
--- a/mysys/my_delete.c
+++ b/mysys/my_delete.c
@@ -1,22 +1,20 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
-#include "mysys_priv.h"
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#include "mysys_priv.h"
#include "mysys_err.h"
int my_delete(const char *name, myf MyFlags)
diff --git a/mysys/my_div.c b/mysys/my_div.c
index 24794679376..e47589a087c 100644
--- a/mysys/my_div.c
+++ b/mysys/my_div.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
diff --git a/mysys/my_dup.c b/mysys/my_dup.c
new file mode 100644
index 00000000000..df298780e3e
--- /dev/null
+++ b/mysys/my_dup.c
@@ -0,0 +1,39 @@
+/* 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 */
+
+#define USES_TYPES
+#include "mysys_priv.h"
+#include "mysys_err.h"
+#include <my_dir.h>
+#include <errno.h>
+#if defined(MSDOS) || defined(__WIN__) || defined(__EMX__)
+#include <share.h>
+#endif
+
+ /* Open a file */
+
+File my_dup(File file, myf MyFlags)
+{
+ File fd;
+ const char *filename;
+ DBUG_ENTER("my_dup");
+ DBUG_PRINT("my",("file: %d MyFlags: %d", MyFlags));
+ fd = dup(file);
+ filename= (((int) file < MY_NFILE) ?
+ my_file_info[(int) file].name : "Unknown");
+ DBUG_RETURN(my_register_filename(fd, filename, FILE_BY_DUP,
+ EE_FILENOTFOUND, MyFlags));
+} /* my_open */
diff --git a/mysys/my_error.c b/mysys/my_error.c
index 4aa946aa6c3..61f8c16aba5 100644
--- a/mysys/my_error.c
+++ b/mysys/my_error.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysys_priv.h"
#include "mysys_err.h"
diff --git a/mysys/my_fopen.c b/mysys/my_fopen.c
index e1575b0af48..d3b0b90f9c5 100644
--- a/mysys/my_fopen.c
+++ b/mysys/my_fopen.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysys_priv.h"
#include "my_static.h"
diff --git a/mysys/my_fstream.c b/mysys/my_fstream.c
index d93caadbcdc..94f3aaf3464 100644
--- a/mysys/my_fstream.c
+++ b/mysys/my_fstream.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* USE_MY_STREAM isn't set because we can't thrust my_fclose! */
@@ -147,7 +146,8 @@ uint my_fwrite(FILE *stream, const byte *Buffer, uint Count, myf MyFlags)
/* Seek to position in file */
/* ARGSUSED */
-my_off_t my_fseek(FILE *stream, my_off_t pos, int whence, myf MyFlags)
+my_off_t my_fseek(FILE *stream, my_off_t pos, int whence,
+ myf MyFlags __attribute__((unused)))
{
DBUG_ENTER("my_fseek");
DBUG_PRINT("my",("stream: %lx pos: %lu whence: %d MyFlags: %d",
@@ -160,7 +160,7 @@ my_off_t my_fseek(FILE *stream, my_off_t pos, int whence, myf MyFlags)
/* Tell current position of file */
/* ARGSUSED */
-my_off_t my_ftell(FILE *stream, myf MyFlags)
+my_off_t my_ftell(FILE *stream, myf MyFlags __attribute__((unused)))
{
off_t pos;
DBUG_ENTER("my_ftell");
diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c
new file mode 100644
index 00000000000..5ec26e3de3f
--- /dev/null
+++ b/mysys/my_getopt.c
@@ -0,0 +1,577 @@
+/* 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 <my_global.h>
+#include <m_string.h>
+#include <stdlib.h>
+#include <my_getopt.h>
+#include <assert.h>
+
+static int findopt (char *optpat, uint length,
+ const struct my_option **opt_res,
+ char **ffname);
+static my_bool compare_strings (register const char *s, register const char *t,
+ uint length);
+static longlong getopt_ll (char *arg, const struct my_option *optp, int *err);
+static void init_variables(const struct my_option *options);
+
+
+#define DISABLE_OPTION_COUNT 2
+
+static const char *special_opt_prefix[]=
+{"skip", "disable", "enable", "maximum", 0};
+
+
+/* Return error values from handle_options */
+
+#define ERR_UNKNOWN_OPTION 1
+#define ERR_AMBIGUOUS_OPTION 2
+#define ERR_NO_ARGUMENT_ALLOWED 3
+#define ERR_ARGUMENT_REQUIRED 4
+#define ERR_VAR_PREFIX_NOT_UNIQUE 5
+#define ERR_UNKNOWN_VARIABLE 6
+#define ERR_MUST_BE_VARIABLE 7
+#define ERR_UNKNOWN_SUFFIX 8
+#define ERR_NO_PTR_TO_VARIABLE 9
+
+
+/*
+ function: handle_options
+
+ Sort options; put options first, until special end of options (--), or
+ until end of argv. Parse options; check that the given option matches with
+ one of the options in struct 'my_option', return error in case of ambiguous
+ or unknown option. Check that option was given an argument if it requires
+ one. Call function 'get_one_option()' once for each option.
+*/
+
+int handle_options(int *argc, char ***argv,
+ const struct my_option *longopts,
+ my_bool (*get_one_option)(int,
+ const struct my_option *,
+ char *))
+{
+ uint opt_found, argvpos= 0, length, spec_len, i;
+ int err;
+ my_bool end_of_options= 0, must_be_var, set_maximum_value, special_used;
+ char *progname= *(*argv), **pos, *optend, *prev_found;
+ const struct my_option *optp;
+
+ LINT_INIT(opt_found);
+ (*argc)--; /* Skip the program name */
+ (*argv)++; /* --- || ---- */
+ init_variables(longopts);
+ for (pos= *argv; *pos; pos++)
+ {
+ char *cur_arg= *pos;
+ if (cur_arg[0] == '-' && cur_arg[1] && !end_of_options) /* must be opt */
+ {
+ char *argument= 0;
+ must_be_var= 0;
+ set_maximum_value= 0;
+ special_used= 0;
+
+ cur_arg++; /* skip '-' */
+ if (*cur_arg == 'O')
+ {
+ must_be_var= 1;
+
+ if (!(*++cur_arg)) /* If not -Ovar=# */
+ {
+ /* the argument must be in next argv */
+ if (!*++pos)
+ {
+ fprintf(stderr, "%s: Option '-O' requires an argument\n",
+ progname);
+ return ERR_ARGUMENT_REQUIRED;
+ }
+ cur_arg= *pos;
+ (*argc)--;
+ }
+ }
+ else if (*cur_arg == '-') /* check for long option, or --set-variable */
+ {
+ if (!compare_strings(cur_arg, "-set-variable", 13))
+ {
+ must_be_var= 1;
+ if (cur_arg[13] == '=')
+ {
+ cur_arg+= 14;
+ if (!*cur_arg)
+ {
+ fprintf(stderr,
+ "%s: Option '--set-variable' requires an argument\n",
+ progname);
+ return ERR_ARGUMENT_REQUIRED;
+ }
+ }
+ else if (cur_arg[14]) /* garbage, or another option. break out */
+ must_be_var= 0;
+ else
+ {
+ /* the argument must be in next argv */
+ if (!*++pos)
+ {
+ fprintf(stderr,
+ "%s: Option '--set-variable' requires an argument\n",
+ progname);
+ return ERR_ARGUMENT_REQUIRED;
+ }
+ cur_arg= *pos;
+ (*argc)--;
+ }
+ }
+ else if (!must_be_var)
+ {
+ if (!*++cur_arg) /* skip the double dash */
+ {
+ /* '--' means end of options, look no further */
+ end_of_options= 1;
+ (*argc)--;
+ continue;
+ }
+ }
+ optend= strcend(cur_arg, '=');
+ length= optend - cur_arg;
+ if (*optend == '=')
+ optend++;
+ else
+ optend=0;
+
+ /*
+ Find first the right option. Return error in case of an ambiguous,
+ or unknown option
+ */
+ optp= longopts;
+ if (!(opt_found= findopt(cur_arg, length, &optp, &prev_found)))
+ {
+ /*
+ Didn't find any matching option. Let's see if someone called
+ option with a special option prefix
+ */
+ if (!must_be_var)
+ {
+ if (optend)
+ must_be_var= 1;
+ for (i= 0; special_opt_prefix[i]; i++)
+ {
+ spec_len= strlen(special_opt_prefix[i]);
+ if (!compare_strings(special_opt_prefix[i], cur_arg, spec_len) &&
+ cur_arg[spec_len] == '-')
+ {
+ /*
+ We were called with a special prefix, we can reuse opt_found
+ */
+ special_used= 1;
+ cur_arg += (spec_len + 1);
+ if ((opt_found= findopt(cur_arg, length - (spec_len + 1),
+ &optp, &prev_found)))
+ {
+ if (opt_found > 1)
+ {
+ fprintf(stderr,
+ "%s: ambiguous option '--%s-%s' (--%s-%s)\n",
+ progname, special_opt_prefix[i], cur_arg,
+ special_opt_prefix[i], prev_found);
+ return ERR_AMBIGUOUS_OPTION;
+ }
+ if (i < DISABLE_OPTION_COUNT)
+ optend= (char*) "0";
+ else if (!compare_strings(special_opt_prefix[i],"enable",6))
+ optend= (char*) "1";
+ else if (!compare_strings(special_opt_prefix[i],"maximum",7))
+ {
+ set_maximum_value= 1;
+ must_be_var= 1;
+ }
+ break; /* break from the inner loop, main loop continues */
+ }
+ }
+ }
+ }
+ if (!opt_found)
+ {
+ if (must_be_var)
+ {
+ fprintf(stderr,
+ "%s: unknown variable '%s'\n", progname, cur_arg);
+ return ERR_UNKNOWN_VARIABLE;
+ }
+ else
+ {
+ fprintf(stderr,
+ "%s: unknown option '--%s'\n", progname, cur_arg);
+ return ERR_UNKNOWN_OPTION;
+ }
+ }
+ }
+ if (opt_found > 1)
+ {
+ if (must_be_var)
+ {
+ fprintf(stderr, "%s: variable prefix '%s' is not unique\n",
+ progname, cur_arg);
+ return ERR_VAR_PREFIX_NOT_UNIQUE;
+ }
+ else
+ {
+ fprintf(stderr, "%s: ambiguous option '--%s' (%s, %s)\n",
+ progname, cur_arg, prev_found, optp->name);
+ return ERR_AMBIGUOUS_OPTION;
+ }
+ }
+ if (must_be_var && !optp->value)
+ {
+ fprintf(stderr, "%s: the argument '%s' is not an variable\n",
+ progname, *pos);
+ return ERR_MUST_BE_VARIABLE;
+ }
+ if (optp->arg_type == NO_ARG && optend && !special_used)
+ {
+ fprintf(stderr, "%s: option '--%s' cannot take an argument\n",
+ progname, optp->name);
+ return ERR_NO_ARGUMENT_ALLOWED;
+ }
+ else if (optp->arg_type == REQUIRED_ARG && !optend)
+ {
+ /* Check if there are more arguments after this one */
+ if (!*++pos)
+ {
+ fprintf(stderr, "%s: option '--%s' requires an argument\n",
+ progname, optp->name);
+ return ERR_ARGUMENT_REQUIRED;
+ }
+ argument= *pos;
+ (*argc)--;
+ }
+ else
+ argument= optend;
+ }
+ else /* must be short option */
+ {
+ for (optend= cur_arg; *optend; optend++, opt_found= 0)
+ {
+ for (optp= longopts; optp->id; optp++)
+ {
+ if (optp->id == (int) (uchar) *optend)
+ {
+ /* Option recognized. Find next what to do with it */
+ opt_found= 1;
+ if (optp->arg_type == REQUIRED_ARG || optp->arg_type == OPT_ARG)
+ {
+ if (*(optend + 1))
+ {
+ // The rest of the option is option argument
+ argument= optend + 1;
+ // This is in effect a jump out of the outer loop
+ optend= (char*) " ";
+ }
+ else if (optp->arg_type == REQUIRED_ARG)
+ {
+ /* Check if there are more arguments after this one */
+ if (!*++pos)
+ {
+ fprintf(stderr, "%s: option '-%c' requires an argument\n",
+ progname, optp->id);
+ return ERR_ARGUMENT_REQUIRED;
+ }
+ argument= *pos;
+ (*argc)--;
+ /* the other loop will break, because *optend + 1 == 0 */
+ }
+ }
+ get_one_option(optp->id, optp, argument);
+ break;
+ }
+ }
+ if (!opt_found)
+ {
+ fprintf(stderr,
+ "%s: unknown option '-%c'\n", progname, *cur_arg);
+ return ERR_UNKNOWN_OPTION;
+ }
+ }
+ (*argc)--; /* option handled (short), decrease argument count */
+ continue;
+ }
+ if (optp->value)
+ {
+ gptr *result_pos= (set_maximum_value) ?
+ optp->u_max_value : optp->value;
+ if (!result_pos)
+ {
+ fprintf(stderr,
+ "%s: Can't set a value for %s\n", progname, optp->name);
+ return ERR_NO_PTR_TO_VARIABLE;
+ }
+ if (optp->var_type == GET_LONG)
+ *((long*) result_pos)= (long) getopt_ll(argument, optp, &err);
+ else if (optp->var_type == GET_LL)
+ *((longlong*) result_pos)= getopt_ll(argument, optp, &err);
+ else if (optp->var_type == GET_STR)
+ *((char**) result_pos)= argument;
+ if (err)
+ return ERR_UNKNOWN_SUFFIX;
+ }
+ else
+ get_one_option(optp->id, optp, argument);
+
+ (*argc)--; /* option handled (short or long), decrease argument count */
+ }
+ else /* non-option found */
+ (*argv)[argvpos++]= cur_arg;
+ }
+ return 0;
+}
+
+
+/*
+ function: findopt
+
+ Arguments: opt_pattern, length of opt_pattern, opt_struct, first found
+ name (ffname)
+
+ Go through all options in the my_option struct. Return number
+ of options found that match the pattern and in the argument
+ list the option found, if any. In case of ambiguous option, store
+ the name in ffname argument
+*/
+
+static int findopt (char *optpat, uint length,
+ const struct my_option **opt_res,
+ char **ffname)
+{
+ int count;
+ struct my_option *opt= (struct my_option *) *opt_res;
+
+ for (count= 0; opt->name; opt++)
+ {
+ if (!compare_strings(opt->name, optpat, length)) /* match found */
+ {
+ (*opt_res)= opt;
+ if (!count)
+ *ffname= (char *) opt->name; /* we only need to know one prev */
+ if (length == strlen(opt->name)) /* exact match */
+ return 1;
+ count++;
+ }
+ }
+ return count;
+}
+
+
+/*
+ function: compare_strings
+
+ Works like strncmp, other than 1.) considers '-' and '_' the same.
+ 2.) Returns -1 if strings differ, 0 if they are equal
+*/
+
+static my_bool compare_strings(register const char *s, register const char *t,
+ uint length)
+{
+ char const *end= s + length;
+ for (;s != end ; s++, t++)
+ {
+ if ((*s != '-' ? *s : '_') != (*t != '-' ? *t : '_'))
+ return 1;
+ }
+ return 0;
+}
+
+
+/*
+ function: getopt_ll
+
+ Evaluates and returns the value that user gave as an argument
+ to a variable. Recognizes (case insensitive) K as KILO, M as MEGA
+ and G as GIGA bytes. Some values must be in certain blocks, as
+ defined in the given my_option struct, this function will check
+ that those values are honored.
+ In case of an error, set error value in *err.
+*/
+
+static longlong getopt_ll (char *arg, const struct my_option *optp, int *err)
+{
+ char *endchar;
+ longlong num;
+
+ *err= 0;
+ num= strtoll(arg, &endchar, 10);
+ if (*endchar == 'k' || *endchar == 'K')
+ num*= 1024L;
+ else if (*endchar == 'm' || *endchar == 'M')
+ num*= 1024L * 1024L;
+ else if (*endchar == 'g' || *endchar == 'G')
+ num*= 1024L * 1024L * 1024L;
+ else if (*endchar)
+ {
+ fprintf(stderr,
+ "Unknown suffix '%c' used for variable '%s' (value '%s')\n",
+ *endchar, optp->name, arg);
+ *err= 1;
+ }
+ if (num < (longlong) optp->min_value)
+ num= (longlong) optp->min_value;
+ else if (num > 0 && (ulonglong) num > (ulonglong) (ulong) optp->max_value
+ && optp->max_value) // if max value is not set -> no upper limit
+ num= (longlong) (ulong) optp->max_value;
+ num= ((num - (longlong) optp->sub_size) / (optp->block_size ?
+ (ulonglong) optp->block_size :
+ 1L));
+ return (longlong) (num * (optp->block_size ? (ulonglong) optp->block_size :
+ 1L));
+}
+
+
+/*
+ function: init_variables
+
+ initialize all variables to their default values
+*/
+
+static void init_variables(const struct my_option *options)
+{
+ for (; options->name; options++)
+ {
+ if (options->value)
+ {
+ if (options->var_type == GET_LONG)
+ *((long*) options->u_max_value)= *((long*) options->value)=
+ (long) options->def_value;
+ else if (options->var_type == GET_LL)
+ *((longlong*) options->u_max_value)= *((longlong*) options->value)=
+ options->def_value;
+ }
+ }
+}
+
+
+/*
+ function: my_print_options
+
+ Print help for all options and variables.
+*/
+
+void my_print_help(const struct my_option *options)
+{
+ uint col, name_space= 22, comment_space= 57;
+ const char *line_end;
+ const struct my_option *optp;
+
+ for (optp= options; optp->id; optp++)
+ {
+ if (optp->id < 256)
+ {
+ printf(" -%c, ", optp->id);
+ col= 6;
+ }
+ else
+ {
+ printf(" ");
+ col= 2;
+ }
+ printf("--%s", optp->name);
+ col+= 2 + strlen(optp->name);
+ if (optp->var_type == GET_STR)
+ {
+ printf("=name ");
+ col+= 6;
+ }
+ else if (optp->var_type == GET_NO_ARG)
+ {
+ putchar(' ');
+ col++;
+ }
+ else
+ {
+ printf("=# ");
+ col+= 3;
+ }
+ if (col > name_space)
+ {
+ putchar('\n');
+ col= 0;
+ }
+ for (; col < name_space; col++)
+ putchar(' ');
+ if (optp->comment && *optp->comment)
+ {
+ const char *comment= optp->comment, *end= strend(comment);
+
+ while ((uint) (end - comment) > comment_space)
+ {
+ for (line_end= comment + comment_space; *line_end != ' '; line_end--);
+ for (; comment != line_end; comment++)
+ putchar(*comment);
+ comment++; // skip the space, as a newline will take it's place now
+ putchar('\n');
+ for (col= 0; col < name_space; col++)
+ putchar(' ');
+ }
+ printf("%s", comment);
+ }
+ putchar('\n');
+ }
+}
+
+
+/*
+ function: my_print_options
+
+ Print variables.
+*/
+
+void my_print_variables(const struct my_option *options)
+{
+ uint name_space= 34, length;
+ char buff[255];
+ const struct my_option *optp;
+
+ printf("Variables (--variable-name=value) Default value\n");
+ printf("--------------------------------- -------------\n");
+ for (optp= options; optp->id; optp++)
+ {
+ if (optp->value)
+ {
+ printf("%s", optp->name);
+ length= strlen(optp->name);
+ for (; length < name_space; length++)
+ putchar(' ');
+ if (optp->var_type == GET_STR)
+ {
+ if (!optp->def_value && !*((char**) optp->value))
+ printf("(No default value)\n");
+ else
+ printf("%s\n", *((char**) optp->value));
+ }
+ else if (optp->var_type == GET_LONG)
+ {
+ if (!optp->def_value && !*((long*) optp->value))
+ printf("(No default value)\n");
+ else
+ printf("%lu\n", *((long*) optp->value));
+ }
+ else
+ {
+ if (!optp->def_value && !*((longlong*) optp->value))
+ printf("(No default value)\n");
+ else
+ printf("%s\n", llstr(*((longlong*) optp->value), buff));
+ }
+ }
+ }
+}
diff --git a/mysys/my_getwd.c b/mysys/my_getwd.c
index 6bdea813fe4..22c6a4dbc2b 100644
--- a/mysys/my_getwd.c
+++ b/mysys/my_getwd.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* my_setwd() and my_getwd() works with intern_filenames !! */
diff --git a/mysys/my_init.c b/mysys/my_init.c
index 3bc87fd179d..c4e6132aa9c 100644
--- a/mysys/my_init.c
+++ b/mysys/my_init.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysys_priv.h"
#include "my_static.h"
@@ -45,9 +44,8 @@ static my_bool win32_init_tcp_ip();
#else
#define my_win_init()
#endif
-static my_bool my_init_done=0;
-
+my_bool my_init_done=0;
static ulong atoi_octal(const char *str)
{
@@ -169,6 +167,7 @@ Voluntary context switches %ld, Involuntary context switches %ld\n",
pthread_mutex_destroy(&THR_LOCK_malloc);
pthread_mutex_destroy(&THR_LOCK_open);
DBUG_POP(); /* Must be done before my_thread_end */
+ my_once_free();
my_thread_end();
my_thread_global_end();
#endif
diff --git a/mysys/my_lib.c b/mysys/my_lib.c
index f9774d8a4aa..a06120894c5 100644
--- a/mysys/my_lib.c
+++ b/mysys/my_lib.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* TODO: check for overun of memory for names. */
/* Convert MSDOS-TIME to standar time_t */
@@ -112,6 +111,10 @@ MY_DIR *my_dir(const char *path, myf MyFlags)
dirp = opendir(directory_file_name(tmp_path,(my_string) path));
size = STARTSIZE;
+#if defined(__amiga__)
+ if ((dirp->dd_fd) < 0) /* Directory doesn't exists */
+ goto error;
+#endif
if (dirp == NULL || ! (buffer = (char *) my_malloc(size, MyFlags)))
goto error;
@@ -183,7 +186,7 @@ MY_DIR *my_dir(const char *path, myf MyFlags)
my_errno=errno;
if (dirp)
(void) closedir(dirp);
- if (MyFlags & (MY_FAE+MY_WME))
+ if (MyFlags & (MY_FAE | MY_WME))
my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,my_errno);
DBUG_RETURN((MY_DIR *) NULL);
} /* my_dir */
@@ -580,13 +583,15 @@ error:
** Note that MY_STAT is assumed to be same as struct stat
****************************************************************************/
-int my_fstat(int Filedes, MY_STAT *stat_area, myf MyFlags )
+int my_fstat(int Filedes, MY_STAT *stat_area,
+ myf MyFlags __attribute__((unused)))
{
DBUG_ENTER("my_fstat");
DBUG_PRINT("my",("fd: %d MyFlags: %d",Filedes,MyFlags));
DBUG_RETURN(fstat(Filedes, (struct stat *) stat_area));
}
+
MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags)
{
int m_used;
@@ -611,4 +616,3 @@ error:
}
DBUG_RETURN((MY_STAT *) NULL);
} /* my_stat */
-
diff --git a/mysys/my_lock.c b/mysys/my_lock.c
index c002f447f59..44ac53677ba 100644
--- a/mysys/my_lock.c
+++ b/mysys/my_lock.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysys_priv.h"
#include "mysys_err.h"
diff --git a/mysys/my_lockmem.c b/mysys/my_lockmem.c
index 9c77c885797..6712c387a71 100644
--- a/mysys/my_lockmem.c
+++ b/mysys/my_lockmem.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Alloc a block of locked memory */
diff --git a/mysys/my_lread.c b/mysys/my_lread.c
index 94ed258151e..601d772b844 100644
--- a/mysys/my_lread.c
+++ b/mysys/my_lread.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysys_priv.h"
#include "mysys_err.h"
diff --git a/mysys/my_lwrite.c b/mysys/my_lwrite.c
index 734916173ce..e1a3decd053 100644
--- a/mysys/my_lwrite.c
+++ b/mysys/my_lwrite.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysys_priv.h"
#include "mysys_err.h"
diff --git a/mysys/my_malloc.c b/mysys/my_malloc.c
index c2df22ec7ec..1e7cdd3a3b5 100644
--- a/mysys/my_malloc.c
+++ b/mysys/my_malloc.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 SAFEMALLOC /* We don't need SAFEMALLOC here */
#undef SAFEMALLOC
diff --git a/mysys/my_messnc.c b/mysys/my_messnc.c
index 0dd3be5ba98..6bb88443109 100644
--- a/mysys/my_messnc.c
+++ b/mysys/my_messnc.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
diff --git a/mysys/my_mkdir.c b/mysys/my_mkdir.c
index 3685312132c..ba1f4c1f2d8 100644
--- a/mysys/my_mkdir.c
+++ b/mysys/my_mkdir.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysys_priv.h"
#include "mysys_err.h"
diff --git a/mysys/my_net.c b/mysys/my_net.c
index 1c91f7ff802..a4a842ac15e 100644
--- a/mysys/my_net.c
+++ b/mysys/my_net.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* thread safe version of some common functions */
diff --git a/mysys/my_once.c b/mysys/my_once.c
index 0b8b5addc16..3358112551f 100644
--- a/mysys/my_once.c
+++ b/mysys/my_once.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Not MT-SAFE */
diff --git a/mysys/my_open.c b/mysys/my_open.c
index 748113528a1..a0a802b8a2e 100644
--- a/mysys/my_open.c
+++ b/mysys/my_open.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#define USES_TYPES
#include "mysys_priv.h"
diff --git a/mysys/my_pread.c b/mysys/my_pread.c
index 5c7d0be5854..661ef48ab3e 100644
--- a/mysys/my_pread.c
+++ b/mysys/my_pread.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysys_priv.h"
#include "mysys_err.h"
diff --git a/mysys/my_pthread.c b/mysys/my_pthread.c
index 8bdbc0f7fd8..37c18a32451 100644
--- a/mysys/my_pthread.c
+++ b/mysys/my_pthread.c
@@ -1,22 +1,22 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 get threads more portable */
+#define DONT_REMAP_PTHREAD_FUNCTIONS
#include "mysys_priv.h"
#ifdef THREAD
#include <signal.h>
@@ -424,7 +424,7 @@ struct hostent *my_gethostbyname_r(const char *name,
int buflen, int *h_errnop)
{
struct hostent *hp;
- dbug_assert((size_t) buflen >= sizeof(*result));
+ DBUG_ASSERT((size_t) buflen >= sizeof(*result));
if (gethostbyname_r(name,result, buffer, (size_t) buflen, &hp, h_errnop))
return 0;
return hp;
@@ -436,7 +436,7 @@ struct hostent *my_gethostbyname_r(const char *name,
struct hostent *result, char *buffer,
int buflen, int *h_errnop)
{
- dbug_assert(buflen >= sizeof(struct hostent_data));
+ DBUG_ASSERT(buflen >= sizeof(struct hostent_data));
if (gethostbyname_r(name,result,(struct hostent_data *) buffer) == -1)
{
*h_errnop= errno;
@@ -452,7 +452,7 @@ struct hostent *my_gethostbyname_r(const char *name,
int buflen, int *h_errnop)
{
struct hostent *hp;
- dbug_assert(buflen >= sizeof(struct hostent_data));
+ DBUG_ASSERT(buflen >= sizeof(struct hostent_data));
hp= gethostbyname_r(name,result,(struct hostent_data *) buffer);
*h_errnop= errno;
return hp;
@@ -461,6 +461,41 @@ struct hostent *my_gethostbyname_r(const char *name,
#endif /* GLIBC2_STYLE_GETHOSTBYNAME_R */
#endif
+/*****************************************************************************
+ Patches for HPUX
+ We need these because the pthread_mutex.. code returns -1 on error,
+ instead of the error code.
+
+ Note that currently we only remap pthread_ functions used by MySQL.
+ If we are depending on the value for some other pthread_xxx functions,
+ this has to be added here.
+*****************************************************************************/
+
+#ifdef HPUX
+
+int my_pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+ struct timespec *abstime)
+{
+ int error=pthread_cond_timedwait(cond, mutex, abstime);
+ if (error == -1) /* Safety if the lib is fixed */
+ error=errno;
+ if (error == EAGAIN) /* Correct errno to Posix */
+ error=ETIMEDOUT;
+ return error;
+}
+
+
+int my_pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+ int error=pthread_mutex_trylock(mutex);
+ if (error == 1) /* Safety if the lib is fixed */
+ return 0; /* Mutex was locked */
+ if (error == -1) /* Safety if the lib is fixed */
+ error=errno;
+ return error;
+}
+
+#endif
/* Some help functions */
diff --git a/mysys/my_quick.c b/mysys/my_quick.c
index 6151d5037ae..44ed3fc0b2c 100644
--- a/mysys/my_quick.c
+++ b/mysys/my_quick.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Quicker interface to read & write. Used with my_nosys.h */
diff --git a/mysys/my_read.c b/mysys/my_read.c
index b317630f4bd..0c8962e91a9 100644
--- a/mysys/my_read.c
+++ b/mysys/my_read.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysys_priv.h"
#include "mysys_err.h"
@@ -28,10 +27,11 @@ uint my_read(File Filedes, byte *Buffer, uint Count, myf MyFlags)
/* Max number of bytes returnd */
/* Flags on what to do on error */
{
- uint readbytes;
+ uint readbytes,save_count;
DBUG_ENTER("my_read");
DBUG_PRINT("my",("Fd: %d Buffer: %lx Count: %u MyFlags: %d",
Filedes, Buffer, Count, MyFlags));
+ save_count=Count;
for (;;)
{
@@ -54,12 +54,21 @@ uint my_read(File Filedes, byte *Buffer, uint Count, myf MyFlags)
my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
my_filename(Filedes),my_errno);
}
- if ((int) readbytes == -1 || (MyFlags & (MY_FNABP | MY_NABP)))
+ if ((int) readbytes == -1 ||
+ ((MyFlags & (MY_FNABP | MY_NABP)) && !(MyFlags & MY_FULL_IO)))
DBUG_RETURN(MY_FILE_ERROR); /* Return with error */
+ if (readbytes > 0 && (MyFlags & MY_FULL_IO))
+ {
+ Buffer+=readbytes;
+ Count-=readbytes;
+ continue;
+ }
}
if (MyFlags & (MY_NABP | MY_FNABP))
readbytes=0; /* Ok on read */
+ else if (MyFlags & MY_FULL_IO)
+ readbytes=save_count;
break;
}
DBUG_RETURN(readbytes);
diff --git a/mysys/my_realloc.c b/mysys/my_realloc.c
index 7ab75d47619..49d96c2eb4f 100644
--- a/mysys/my_realloc.c
+++ b/mysys/my_realloc.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 SAFEMALLOC /* We don't need SAFEMALLOC here */
#undef SAFEMALLOC
diff --git a/mysys/my_redel.c b/mysys/my_redel.c
index 16ec77394d2..8474dab0d13 100644
--- a/mysys/my_redel.c
+++ b/mysys/my_redel.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#define USES_TYPES /* sys/types is included */
#include "mysys_priv.h"
diff --git a/mysys/my_rename.c b/mysys/my_rename.c
index ea895ffcf76..fde45eba456 100644
--- a/mysys/my_rename.c
+++ b/mysys/my_rename.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#define USES_TYPES
#include "mysys_priv.h"
diff --git a/mysys/my_seek.c b/mysys/my_seek.c
index 7c4da4f6010..177a5cee953 100644
--- a/mysys/my_seek.c
+++ b/mysys/my_seek.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
@@ -26,7 +25,8 @@ my_off_t my_seek(File fd, my_off_t pos, int whence,
reg1 os_off_t newpos;
DBUG_ENTER("my_seek");
DBUG_PRINT("my",("Fd: %d Hpos: %lu Pos: %lu Whence: %d MyFlags: %d",
- fd, ((ulonglong) pos) >> 32, (ulong) pos, whence, MyFlags));
+ fd, (ulong) (((ulonglong) pos) >> 32), (ulong) pos,
+ whence, MyFlags));
newpos=lseek(fd, pos, whence);
if (newpos == (os_off_t) -1)
{
@@ -34,6 +34,10 @@ my_off_t my_seek(File fd, my_off_t pos, int whence,
DBUG_PRINT("error",("lseek: %lu, errno: %d",newpos,errno));
DBUG_RETURN(MY_FILEPOS_ERROR);
}
+ if ((my_off_t) newpos != pos)
+ {
+ DBUG_PRINT("exit",("pos: %lu", (ulong) newpos));
+ }
DBUG_RETURN((my_off_t) newpos);
} /* my_seek */
@@ -53,6 +57,6 @@ my_off_t my_tell(File fd, myf MyFlags __attribute__((unused)))
#endif
if (pos == (os_off_t) -1)
my_errno=errno;
- DBUG_PRINT("exit",("pos: %lu",pos));
+ DBUG_PRINT("exit",("pos: %lu", (ulong) pos));
DBUG_RETURN((my_off_t) pos);
} /* my_tell */
diff --git a/mysys/my_static.c b/mysys/my_static.c
index 00061893cdc..1eb6220f185 100644
--- a/mysys/my_static.c
+++ b/mysys/my_static.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 mysys library. All definied here for easy making of
@@ -83,6 +82,13 @@ struct remember *pRememberRoot = NULL;
int volatile my_have_got_alarm=0; /* declare variable to reset */
ulong my_time_to_wait_for_lock=2; /* In seconds */
+ /*
+ We need to have this define here as otherwise linking will fail
+ on OSF1 when compiling --without-raid --with-debug
+ */
+
+const char *raid_type_string[]={"none","striped"};
+
/* from errors.c */
#ifdef SHARED_LIBRARY
char * NEAR globerrs[GLOBERRS]; /* my_error_messages is here */
diff --git a/mysys/my_static.h b/mysys/my_static.h
index e9d1a30b786..4f944938b8d 100644
--- a/mysys/my_static.h
+++ b/mysys/my_static.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 mysys library. All definied here for easy making of
diff --git a/mysys/my_symlink.c b/mysys/my_symlink.c
index 65d165fc026..5cc22b6bfbc 100644
--- a/mysys/my_symlink.c
+++ b/mysys/my_symlink.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysys_priv.h"
#include "mysys_err.h"
diff --git a/mysys/my_symlink2.c b/mysys/my_symlink2.c
index f1e90abaa9b..68b034bec5c 100644
--- a/mysys/my_symlink2.c
+++ b/mysys/my_symlink2.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
Advanced symlink handling.
@@ -23,6 +22,7 @@
*/
#include "mysys_priv.h"
+#include "mysys_err.h"
#include <m_string.h>
File my_create_with_symlink(const char *linkname, const char *filename,
@@ -30,11 +30,27 @@ File my_create_with_symlink(const char *linkname, const char *filename,
{
File file;
int tmp_errno;
+ /* Test if we should create a link */
+ int create_link=(linkname && strcmp(linkname,filename));
DBUG_ENTER("my_create_with_symlink");
+
+ if (!(MyFlags & MY_DELETE_OLD))
+ {
+ if (!access(filename,F_OK))
+ {
+ my_error(EE_CANTCREATEFILE, MYF(0), filename, EEXIST);
+ DBUG_RETURN(-1);
+ }
+ if (create_link && !access(linkname,F_OK))
+ {
+ my_error(EE_CANTCREATEFILE, MYF(0), linkname, EEXIST);
+ DBUG_RETURN(-1);
+ }
+ }
+
if ((file=my_create(filename, createflags, access_flags, MyFlags)) >= 0)
{
- /* Test if we should create a link */
- if (linkname && strcmp(linkname,filename))
+ if (create_link)
{
/* Delete old link/file */
if (MyFlags & MY_DELETE_OLD)
diff --git a/mysys/my_tempnam.c b/mysys/my_tempnam.c
index fdaf018af0d..da0692b46c5 100644
--- a/mysys/my_tempnam.c
+++ b/mysys/my_tempnam.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000 MySQL AB
- 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 program is free software; 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 library is distributed in the hope that it will be useful,
+ This program is distributed in the hope that 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.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU 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 */
+ You should have received a copy of the GNU General Public 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 function is only used by some old ISAM code.
diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c
index e1f9e23912e..b4d98feeeb6 100644
--- a/mysys/my_thr_init.c
+++ b/mysys/my_thr_init.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 initializating and allocationg of all mysys & debug
diff --git a/mysys/my_vsnprintf.c b/mysys/my_vsnprintf.c
index ab8edec4d7b..7490ab4a9f2 100644
--- a/mysys/my_vsnprintf.c
+++ b/mysys/my_vsnprintf.c
@@ -1,25 +1,25 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysys_priv.h"
#include "mysys_err.h"
#include <m_string.h>
#include <stdarg.h>
#include <m_ctype.h>
+#include <assert.h>
int my_snprintf(char* to, size_t n, const char* fmt, ...)
{
@@ -40,7 +40,7 @@ int my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap)
*to++= *fmt; /* Copy ordinary char */
continue;
}
- /* Skipp if max size is used (to be compatible with printf) */
+ /* Skip if max size is used (to be compatible with printf) */
fmt++;
while (isdigit(*fmt) || *fmt == '.' || *fmt == '-')
fmt++;
@@ -49,14 +49,13 @@ int my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap)
if (*fmt == 's') /* String parameter */
{
reg2 char *par = va_arg(ap, char *);
- uint plen;
+ uint plen,left_len = (uint)(end-to);
if (!par) par = (char*)"(null)";
plen = (uint) strlen(par);
- if ((uint) (end-to) > plen) /* Replace if possible */
- {
- to=strmov(to,par);
- continue;
- }
+ if (left_len <= plen)
+ plen = left_len - 1;
+ to=strnmov(to,par,plen);
+ continue;
}
else if (*fmt == 'd' || *fmt == 'u') /* Integer parameter */
{
@@ -75,26 +74,34 @@ int my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap)
break;
*to++='%'; /* % used as % or unknown code */
}
+ DBUG_ASSERT(to <= end);
*to='\0'; /* End of errmessage */
return (uint) (to - start);
}
#ifdef MAIN
+#define OVERRUN_SENTRY 250
static void my_printf(const char * fmt, ...)
{
- char buf[32];
+ char buf[33];
int n;
va_list ar;
va_start(ar, fmt);
- n = my_vsnprintf(buf, sizeof(buf),fmt, ar);
+ buf[sizeof(buf)-1]=OVERRUN_SENTRY;
+ n = my_vsnprintf(buf, sizeof(buf)-1,fmt, ar);
printf(buf);
printf("n=%d, strlen=%d\n", n, strlen(buf));
+ if (buf[sizeof(buf)-1] != OVERRUN_SENTRY)
+ {
+ fprintf(stderr, "Buffer overrun\n");
+ abort();
+ }
va_end(ar);
}
int main()
{
-
+
my_printf("Hello\n");
my_printf("Hello int, %d\n", 1);
my_printf("Hello string '%s'\n", "I am a string");
@@ -109,4 +116,3 @@ int main()
return 0;
}
#endif
-
diff --git a/mysys/my_wincond.c b/mysys/my_wincond.c
index 0c5b01f90d8..8c497e8f250 100644
--- a/mysys/my_wincond.c
+++ b/mysys/my_wincond.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*****************************************************************************
** The following is a simple implementation of posix conditions
diff --git a/mysys/my_winsem.c b/mysys/my_winsem.c
new file mode 100644
index 00000000000..268a05a0b21
--- /dev/null
+++ b/mysys/my_winsem.c
@@ -0,0 +1,406 @@
+/*
+ * -------------------------------------------------------------
+ *
+ * Module: my_semaphore.c (Original: semaphore.c from pthreads library)
+ *
+ * Purpose:
+ * Semaphores aren't actually part of the PThreads standard.
+ * They are defined by the POSIX Standard:
+ *
+ * POSIX 1003.1b-1993 (POSIX.1b)
+ *
+ * -------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * 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
+ */
+
+/*
+ NEED_SEM is not used in MySQL and should only be needed under
+ Windows CE.
+
+ The big changes compared to the original version was to not allocate
+ any additional memory in sem_init() but to instead store everthing
+ we need in sem_t.
+
+ TODO:
+ To get HAVE_CREATESEMAPHORE we have to define the struct
+ in my_semaphore.h
+*/
+
+#include "mysys_priv.h"
+#ifdef __WIN__
+#include "my_semaphore.h"
+#include <errno.h>
+
+/*
+ DOCPUBLIC
+ This function initializes an unnamed semaphore. the
+ initial value of the semaphore is 'value'
+
+ PARAMETERS
+ sem Pointer to an instance of sem_t
+
+ pshared If zero, this semaphore may only be shared between
+ threads in the same process.
+ If nonzero, the semaphore can be shared between
+ processes
+
+ value Initial value of the semaphore counter
+
+ RESULTS
+ 0 Successfully created semaphore,
+ -1 Failed, error in errno
+
+ ERRNO
+ EINVAL 'sem' is not a valid semaphore,
+ ENOSPC A required resource has been exhausted,
+ ENOSYS Semaphores are not supported,
+ EPERM The process lacks appropriate privilege
+
+*/
+
+int
+sem_init (sem_t *sem, int pshared, unsigned int value)
+{
+ int result = 0;
+
+ if (pshared != 0)
+ {
+ /*
+ We don't support creating a semaphore that can be shared between
+ processes
+ */
+ result = EPERM;
+ }
+ else
+ {
+#ifndef HAVE_CREATESEMAPHORE
+ sem->value = value;
+ sem->event = CreateEvent(NULL,
+ FALSE, /* manual reset */
+ FALSE, /* initial state */
+ NULL);
+ if (!sem->event)
+ result = ENOSPC;
+ else
+ {
+ if (value)
+ SetEvent(sem->event);
+ InitializeCriticalSection(&sem->sem_lock_cs);
+ }
+#else /* HAVE_CREATESEMAPHORE */
+ *sem = CreateSemaphore (NULL, /* Always NULL */
+ value, /* Initial value */
+ 0x7FFFFFFFL, /* Maximum value */
+ NULL); /* Name */
+ if (!*sem)
+ result = ENOSPC;
+#endif /* HAVE_CREATESEMAPHORE */
+ }
+ if (result != 0)
+ {
+ errno = result;
+ return -1;
+ }
+ return 0;
+} /* sem_init */
+
+
+/*
+ DOCPUBLIC
+ This function destroys an unnamed semaphore.
+
+ PARAMETERS
+ sem Pointer to an instance of sem_t
+
+ RESULTS
+ 0 Successfully destroyed semaphore,
+ -1 Failed, error in errno
+ ERRNO
+ EINVAL 'sem' is not a valid semaphore,
+ ENOSYS Semaphores are not supported,
+ EBUSY Threads (or processes) are currently blocked on 'sem'
+*/
+
+int
+sem_destroy (sem_t * sem)
+{
+ int result = 0;
+
+#ifdef EXTRA_DEBUG
+ if (sem == NULL || *sem == NULL)
+ {
+ errno=EINVAL;
+ return;
+ }
+#endif /* EXTRA_DEBUG */
+
+#ifndef HAVE_CREATESEMAPHORE
+ if (! CloseHandle(sem->event))
+ result = EINVAL;
+ else
+ DeleteCriticalSection(&sem->sem_lock_cs);
+#else /* HAVE_CREATESEMAPHORE */
+ if (!CloseHandle(*sem))
+ result = EINVAL;
+#endif /* HAVE_CREATESEMAPHORE */
+ if (result)
+ {
+ errno = result;
+ return -1;
+ }
+ *sem=0; /* Safety */
+ return 0;
+} /* sem_destroy */
+
+
+/*
+ DOCPUBLIC
+ This function tries to wait on a semaphore. If the
+ semaphore value is greater than zero, it decreases
+ its value by one. If the semaphore value is zero, then
+ this function returns immediately with the error EAGAIN
+
+ PARAMETERS
+ sem Pointer to an instance of sem_t
+
+ RESULTS
+ 0 Successfully decreased semaphore,
+ -1 Failed, error in errno
+
+ ERRNO
+ EAGAIN The semaphore was already locked,
+ EINVAL 'sem' is not a valid semaphore,
+ ENOSYS Semaphores are not supported,
+ EINTR The function was interrupted by a signal,
+ EDEADLK A deadlock condition was detected.
+*/
+
+int
+sem_trywait(sem_t * sem)
+{
+#ifndef HAVE_CREATESEMAPHORE
+ /* not yet implemented! */
+ int errno = EINVAL;
+ return -1;
+#else /* HAVE_CREATESEMAPHORE */
+#ifdef EXTRA_DEBUG
+ if (sem == NULL || *sem == NULL)
+ {
+ errno=EINVAL;
+ return -1;
+ }
+#endif /* EXTRA_DEBUG */
+ if (WaitForSingleObject (*sem, 0) == WAIT_TIMEOUT)
+ {
+ errno= EAGAIN;
+ return -1;
+ }
+ return 0;
+#endif /* HAVE_CREATESEMAPHORE */
+
+} /* sem_trywait */
+
+
+#ifndef HAVE_CREATESEMAPHORE
+
+static void
+ptw32_decrease_semaphore(sem_t * sem)
+{
+ EnterCriticalSection(&sem->sem_lock_cs);
+ DBUG_ASSERT(sem->value != 0);
+ sem->value--;
+ if (sem->value != 0)
+ SetEvent(sem->event);
+ LeaveCriticalSection(&sem->sem_lock_cs);
+}
+
+static BOOL
+ptw32_increase_semaphore(sem_t * sem, unsigned int n)
+{
+ BOOL result=FALSE;
+
+ EnterCriticalSection(&sem->sem_lock_cs);
+ if (sem->value + n > sem->value)
+ {
+ sem->value += n;
+ SetEvent(sem->event);
+ result = TRUE;
+ }
+ LeaveCriticalSection(&sem->sem_lock_cs);
+ return result;
+}
+
+#endif /* HAVE_CREATESEMAPHORE */
+
+
+/*
+ ------------------------------------------------------
+ DOCPUBLIC
+ This function waits on a semaphore. If the
+ semaphore value is greater than zero, it decreases
+ its value by one. If the semaphore value is zero, then
+ the calling thread (or process) is blocked until it can
+ successfully decrease the value or until interrupted by
+ a signal.
+
+ PARAMETERS
+ sem Pointer to an instance of sem_t
+
+ RESULTS
+ 0 Successfully decreased semaphore,
+ -1 Failed, error in errno
+
+ ERRNO
+ EINVAL 'Sem' is not a valid semaphore,
+ ENOSYS Semaphores are not supported,
+ EINTR The function was interrupted by a signal,
+ EDEADLK A deadlock condition was detected.
+*/
+
+int
+sem_wait(sem_t *sem)
+{
+ int result;
+
+#ifdef EXTRA_DEBUG
+ if (sem == NULL || *sem == NULL)
+ {
+ errno=EINVAL;
+ return -1;
+ }
+#endif /* EXTRA_DEBUG */
+
+#ifndef HAVE_CREATESEMAPHORE
+ result=WaitForSingleObject(sem->event, INFINITE);
+#else
+ result=WaitForSingleObject(*sem, INFINITE);
+#endif
+ if (result == WAIT_FAILED || result == WAIT_ABANDONED_0)
+ result = EINVAL;
+ else if (result == WAIT_TIMEOUT)
+ result = ETIMEDOUT;
+ else
+ result=0;
+ if (result)
+ {
+ errno = result;
+ return -1;
+ }
+#ifndef HAVE_CREATESEMAPHORE
+ ptw32_decrease_semaphore(sem);
+#endif /* HAVE_CREATESEMAPHORE */
+ return 0;
+}
+
+
+/*
+ ------------------------------------------------------
+ DOCPUBLIC
+ This function posts a wakeup to a semaphore. If there
+ are waiting threads (or processes), one is awakened;
+ otherwise, the semaphore value is incremented by one.
+
+ PARAMETERS
+ sem Pointer to an instance of sem_t
+
+ RESULTS
+ 0 Successfully posted semaphore,
+ -1 Failed, error in errno
+
+ ERRNO
+ EINVAL 'sem' is not a valid semaphore,
+ ENOSYS Semaphores are not supported,
+
+*/
+
+int
+sem_post (sem_t * sem)
+{
+#ifdef EXTRA_DEBUG
+ if (sem == NULL || *sem == NULL)
+ {
+ errno=EINVAL;
+ return -1;
+ }
+#endif /* EXTRA_DEBUG */
+
+#ifndef HAVE_CREATESEMAPHORE
+ if (! ptw32_increase_semaphore(sem, 1))
+#else /* HAVE_CREATESEMAPHORE */
+ if (! ReleaseSemaphore(*sem, 1, 0))
+#endif /* HAVE_CREATESEMAPHORE */
+ {
+ errno=EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+
+/*
+ ------------------------------------------------------
+ DOCPUBLIC
+ This function posts multiple wakeups to a semaphore. If there
+ are waiting threads (or processes), n <= count are awakened;
+ the semaphore value is incremented by count - n.
+
+ PARAMETERS
+ sem Pointer to an instance of sem_t
+ count Counter, must be greater than zero.
+
+ RESULTS
+ 0 Successfully posted semaphore,
+ -1 Failed, error in errno
+
+ ERRNO
+ EINVAL 'sem' is not a valid semaphore or count is less
+ than or equal to zero.
+*/
+
+int
+sem_post_multiple (sem_t * sem, int count )
+{
+#ifdef EXTRA_DEBUG
+ if (sem == NULL || *sem == NULL || count <= 0)
+ {
+ errno=EINVAL;
+ return -1;
+ }
+#endif /* EXTRA_DEBUG */
+#ifndef HAVE_CREATESEMAPHORE
+ if (! ptw32_increase_semaphore (sem, count))
+#else /* HAVE_CREATESEMAPHORE */
+ if (! ReleaseSemaphore(*sem, count, 0))
+#endif /* HAVE_CREATESEMAPHORE */
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+int
+sem_getvalue (sem_t *sem, int *sval)
+{
+ errno = ENOSYS;
+ return -1;
+} /* sem_getvalue */
+
+#endif /* __WIN__ */
diff --git a/mysys/my_winthread.c b/mysys/my_winthread.c
index a77167c23e4..eebc07df180 100644
--- a/mysys/my_winthread.c
+++ b/mysys/my_winthread.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*****************************************************************************
** Simulation of posix threads calls for WIN95 and NT
diff --git a/mysys/my_write.c b/mysys/my_write.c
index 5d5a48a3dda..61fd6097e28 100644
--- a/mysys/my_write.c
+++ b/mysys/my_write.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysys_priv.h"
#include "mysys_err.h"
diff --git a/mysys/mysys_priv.h b/mysys/mysys_priv.h
index 20fda270658..ba16e8820fe 100644
--- a/mysys/mysys_priv.h
+++ b/mysys/mysys_priv.h
@@ -1,21 +1,20 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <global.h>
+#include <my_global.h>
#include <my_sys.h>
#ifdef USE_SYSTEM_WRAPPERS
diff --git a/mysys/ptr_cmp.c b/mysys/ptr_cmp.c
index 65b2c51aafd..5fc7ccab4fa 100644
--- a/mysys/ptr_cmp.c
+++ b/mysys/ptr_cmp.c
@@ -1,27 +1,23 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
get_ptr_compare(len) returns a pointer to a optimal byte-compare function
for a array of stringpointer where all strings have size len.
The bytes are compare as unsigned chars.
- Because the size is saved in a static variable.
- When using threads the program must have called my_init and the thread
- my_init_thread()
*/
#include "mysys_priv.h"
diff --git a/mysys/queues.c b/mysys/queues.c
index 1c7a1a4a618..50ef3944a3f 100644
--- a/mysys/queues.c
+++ b/mysys/queues.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
Code for generell handling of priority Queues.
@@ -124,7 +123,6 @@ byte *queue_remove(register QUEUE *queue, uint idx)
}
}
-
/* Fix when element on top has been replaced */
#ifndef queue_replaced
@@ -166,3 +164,22 @@ void _downheap(register QUEUE *queue, uint idx)
}
queue->root[idx]=element;
}
+
+
+static int queue_fix_cmp(QUEUE *queue, void **a, void **b)
+{
+ return queue->compare(queue->first_cmp_arg,
+ (char*) (*a)+queue->offset_to_key,
+ (char*) (*b)+queue->offset_to_key);
+}
+
+/* Fix heap when every element was changed
+ actually, it can be done in linear time,
+ not in n*log(n), but some code (myisam/ft_boolean_search.c)
+ requires a strict order here, not just a queue property
+*/
+void queue_fix(QUEUE *queue)
+{
+ qsort2(queue->root+1,queue->elements, sizeof(void *),
+ (qsort2_cmp)queue_fix_cmp, queue);
+}
diff --git a/mysys/raid.cc b/mysys/raid.cc
index 48aa5cdb134..72d3b2074be 100644
--- a/mysys/raid.cc
+++ b/mysys/raid.cc
@@ -1,75 +1,74 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
-
-/* --------------------------------------------------------*
-*
-* RAID support for MySQL. Raid 0 (stiping) only implemented yet.
-*
-* Why RAID? Why it must be in MySQL?
-*
-* This is because then you can:
-* 1. Have bigger tables than your OS limit. In time of writing this
-* we are hitting to 2GB limit under linux/ext2
-* 2. You can get more speed from IO bottleneck by putting
-* Raid dirs on different physical disks.
-* 3. Getting more fault tolerance (not implemented yet)
-*
-* Why not to use RAID:
-*
-* 1. You are losing some processor power to calculate things,
-* do more syscalls and interrupts.
-*
-* Functionality is supplied by two classes: RaidFd and RaidName.
-* RaidFd supports funtionality over file descriptors like
-* open/create/write/seek/close. RaidName supports functionality
-* like rename/delete where we have no relations to filedescriptors.
-* RaidName can be prorably unchanged for different Raid levels. RaidFd
-* have to be virtual I think ;).
-* You can speed up some calls in MySQL code by skipping RAID code.
-* For example LOAD DATA INFILE never needs to read RAID-ed files.
-* This can be done adding proper "#undef my_read" or similar undef-s
-* in your code. Check out the raid.h!
-*
-* Some explanation about _seek_vector[]
-* This is seek cache. RAID seeks too much and we cacheing this. We
-* fool it and just storing new position in file to _seek_vector.
-* When there is no seeks to do, we are putting RAID_SEEK_DONE into it.
-* Any other value requires seeking to that position.
-*
-* TODO:
-*
-*
-* - Implement other fancy things like RAID 1 (mirroring) and RAID 5.
-* Should not to be very complex.
-*
-* - Optimize big blob writes by resorting write buffers and writing
-* big chunks at once instead of doing many syscalls. - after thinking I
-* found this is useless. This is because same thing one can do with just
-* increasing RAID_CHUNKSIZE. Monty, what do you think? tonu.
-*
-* - If needed, then implement missing syscalls. One known to miss is stat();
-*
-* - Make and use a thread safe dynamic_array buffer. The used one
-* will not work if needs to be extended at the same time someone is
-* accessing it.
-*
-*
-* tonu@mysql.com & monty@mysql.com
-* --------------------------------------------------------*/
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+
+ RAID support for MySQL. Raid 0 (stiping) only implemented yet.
+
+ Why RAID? Why it must be in MySQL?
+
+ This is because then you can:
+ 1. Have bigger tables than your OS limit. In time of writing this
+ we are hitting to 2GB limit under linux/ext2
+ 2. You can get more speed from IO bottleneck by putting
+ Raid dirs on different physical disks.
+ 3. Getting more fault tolerance (not implemented yet)
+
+ Why not to use RAID:
+
+ 1. You are losing some processor power to calculate things,
+ do more syscalls and interrupts.
+
+ Functionality is supplied by two classes: RaidFd and RaidName.
+ RaidFd supports funtionality over file descriptors like
+ open/create/write/seek/close. RaidName supports functionality
+ like rename/delete where we have no relations to filedescriptors.
+ RaidName can be prorably unchanged for different Raid levels. RaidFd
+ have to be virtual I think ;).
+ You can speed up some calls in MySQL code by skipping RAID code.
+ For example LOAD DATA INFILE never needs to read RAID-ed files.
+ This can be done adding proper "#undef my_read" or similar undef-s
+ in your code. Check out the raid.h!
+
+ Some explanation about _seek_vector[]
+ This is seek cache. RAID seeks too much and we cacheing this. We
+ fool it and just storing new position in file to _seek_vector.
+ When there is no seeks to do, we are putting RAID_SEEK_DONE into it.
+ Any other value requires seeking to that position.
+
+ TODO:
+
+
+ - Implement other fancy things like RAID 1 (mirroring) and RAID 5.
+ Should not to be very complex.
+
+ - Optimize big blob writes by resorting write buffers and writing
+ big chunks at once instead of doing many syscalls. - after thinking I
+ found this is useless. This is because same thing one can do with just
+ increasing RAID_CHUNKSIZE. Monty, what do you think? tonu.
+
+ - If needed, then implement missing syscalls. One known to miss is stat();
+
+ - Make and use a thread safe dynamic_array buffer. The used one
+ will not work if needs to be extended at the same time someone is
+ accessing it.
+
+
+ tonu@mysql.com & monty@mysql.com
+*/
#ifdef __GNUC__
#pragma implementation // gcc: Class implementation
@@ -80,16 +79,6 @@
#include <m_string.h>
#include <assert.h>
-const char *raid_type_string[]={"none","striped"};
-
-
-extern "C" {
- const char *my_raid_type(int raid_type)
- {
- return raid_type_string[raid_type];
- }
-}
-
#if defined(USE_RAID) && !defined(MYSQL_CLIENT)
#define RAID_SEEK_DONE ~(off_t) 0
@@ -420,8 +409,8 @@ IsRaid(File fd)
RaidFd::
RaidFd(uint raid_type, uint raid_chunks, ulong raid_chunksize)
:_raid_type(raid_type), _raid_chunks(raid_chunks),
- _raid_chunksize(raid_chunksize), _position(0), _fd_vector(0),
- _size(RAID_SIZE_UNKNOWN)
+ _raid_chunksize(raid_chunksize), _position(0), _size(RAID_SIZE_UNKNOWN),
+ _fd_vector(0)
{
DBUG_ENTER("RaidFd::RaidFd");
DBUG_PRINT("enter",("RaidFd_type: %u Disks: %u Chunksize: %d",
diff --git a/mysys/safemalloc.c b/mysys/safemalloc.c
index 34fcfff756c..d8c089c2ff0 100644
--- a/mysys/safemalloc.c
+++ b/mysys/safemalloc.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 posting refers to an article entitled "oops, corrupted memory
diff --git a/mysys/string.c b/mysys/string.c
index 96a503c1179..ea747bc9847 100644
--- a/mysys/string.c
+++ b/mysys/string.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
Code for handling strings with can grow dynamicly.
@@ -51,7 +50,7 @@ my_bool init_dynamic_string(DYNAMIC_STRING *str, const char *init_str,
my_bool dynstr_set(DYNAMIC_STRING *str, const char *init_str)
{
- uint length;
+ uint length=0;
DBUG_ENTER("dynstr_set");
if (init_str && (length= (uint) strlen(init_str)+1) > str->max_length)
diff --git a/mysys/test_charset.c b/mysys/test_charset.c
index 6a5183d2cd3..15e46f3ff82 100644
--- a/mysys/test_charset.c
+++ b/mysys/test_charset.c
@@ -1,21 +1,20 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
-
-#include <global.h>
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <m_ctype.h>
#include <my_sys.h>
#include <mysql_version.h>
diff --git a/mysys/test_dir.c b/mysys/test_dir.c
index fafdde137b6..f3d220e942f 100644
--- a/mysys/test_dir.c
+++ b/mysys/test_dir.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* TODO: Test all functions */
diff --git a/mysys/test_fn.c b/mysys/test_fn.c
index 224b899ebe1..5a0546392ab 100644
--- a/mysys/test_fn.c
+++ b/mysys/test_fn.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
diff --git a/mysys/testhash.c b/mysys/testhash.c
index a8fbf800595..461f1d8be5e 100644
--- a/mysys/testhash.c
+++ b/mysys/testhash.c
@@ -1,23 +1,22 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 hash libarary: stor test */
-#include <global.h>
+#include <my_global.h>
#include <my_sys.h>
#include <hash.h>
#include <m_string.h>
diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c
index f51f27b7f51..ef514efe39e 100644
--- a/mysys/thr_alarm.c
+++ b/mysys/thr_alarm.c
@@ -1,21 +1,23 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
-
-#include <global.h>
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* To avoid problems with alarms in debug code, we disable DBUG here */
+#undef DBUG_OFF
+#define DBUG_OFF
+#include <my_global.h>
#if defined(THREAD) && !defined(DONT_USE_THR_ALARM)
#include <errno.h>
diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c
index aa50877072d..0288c7c1cbe 100644
--- a/mysys/thr_lock.c
+++ b/mysys/thr_lock.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
Read and write locks for Posix threads. All tread must acquire
diff --git a/mysys/thr_mutex.c b/mysys/thr_mutex.c
index fa7ae4f1e82..4493c54069f 100644
--- a/mysys/thr_mutex.c
+++ b/mysys/thr_mutex.c
@@ -1,23 +1,22 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 makes a wrapper for mutex handling to make it easier to debug mutex */
-#include <global.h>
+#include <my_global.h>
#if defined(HAVE_LINUXTHREADS) && !defined (__USE_UNIX98)
#define __USE_UNIX98 /* To get rw locks under Linux */
#endif
@@ -70,7 +69,8 @@ int safe_mutex_lock(safe_mutex_t *mp,const char *file, uint line)
}
if (mp->count++)
{
- fprintf(stderr,"safe_mutex: Error in thread libray: Got mutex at %s, line %d more than 1 time\n", file,line);
+ fprintf(stderr,"safe_mutex: Error in thread libray: Got mutex at %s, \
+line %d more than 1 time\n", file,line);
fflush(stderr);
abort();
}
@@ -108,7 +108,7 @@ int safe_mutex_unlock(safe_mutex_t *mp,const char *file, uint line)
error=pthread_mutex_unlock(&mp->mutex);
if (error)
{
- fprintf(stderr,"safe_mutex: Got error: %d when trying to unlock mutex at %s, line %d\n", error, file, line);
+ fprintf(stderr,"safe_mutex: Got error: %d (%d) when trying to unlock mutex at %s, line %d\n", error, errno, file, line);
fflush(stderr);
abort();
}
@@ -149,7 +149,7 @@ int safe_cond_wait(pthread_cond_t *cond, safe_mutex_t *mp, const char *file,
pthread_mutex_lock(&mp->global);
if (error)
{
- fprintf(stderr,"safe_mutex: Got error: %d when doing a safe_mutex_wait at %s, line %d\n", error, file, line);
+ fprintf(stderr,"safe_mutex: Got error: %d (%d) when doing a safe_mutex_wait at %s, line %d\n", error, errno, file, line);
fflush(stderr);
abort();
}
@@ -187,15 +187,15 @@ int safe_cond_timedwait(pthread_cond_t *cond, safe_mutex_t *mp,
#ifdef EXTRA_DEBUG
if (error && (error != EINTR && error != ETIMEDOUT))
{
- fprintf(stderr,"safe_mutex: Got error: %d when doing a safe_mutex_timedwait at %s, line %d\n", error, file, line);
+ fprintf(stderr,"safe_mutex: Got error: %d (%d) when doing a safe_mutex_timedwait at %s, line %d\n", error, errno, file, line);
}
#endif
pthread_mutex_lock(&mp->global);
if (mp->count++)
{
fprintf(stderr,
- "safe_mutex: Count was %d in thread %lx when locking mutex at %s, line %d (error: %d)\n",
- mp->count-1, my_thread_id(), file, line, error);
+ "safe_mutex: Count was %d in thread %lx when locking mutex at %s, line %d (error: %d (%d))\n",
+ mp->count-1, my_thread_id(), file, line, error, error);
fflush(stderr);
abort();
}
diff --git a/mysys/thr_rwlock.c b/mysys/thr_rwlock.c
index 866948a1c23..4e2cf3554b7 100644
--- a/mysys/thr_rwlock.c
+++ b/mysys/thr_rwlock.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Synchronization - readers / writer thread locks */
diff --git a/mysys/tree.c b/mysys/tree.c
index cd05a17fd72..2ac2c88fd66 100644
--- a/mysys/tree.c
+++ b/mysys/tree.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
Code for handling red-black (balanced) binary trees.
@@ -62,28 +61,35 @@ static void rb_delete_fixup(TREE *tree,TREE_ELEMENT ***parent);
/* The actuall code for handling binary trees */
-void init_tree(TREE *tree, uint default_alloc_size, int size,
- qsort_cmp compare, my_bool with_delete,
- void (*free_element) (void *))
+#ifndef DBUG_OFF
+static int test_rb_tree(TREE_ELEMENT *element);
+#endif
+
+void init_tree(TREE *tree, uint default_alloc_size, uint memory_limit,
+ int size, qsort_cmp2 compare, my_bool with_delete,
+ tree_element_free free_element, void *custom_arg)
{
DBUG_ENTER("init_tree");
DBUG_PRINT("enter",("tree: %lx size: %d",tree,size));
- if (!default_alloc_size)
- default_alloc_size= DEFAULT_ALLOC_SIZE;
+ if (!default_alloc_size)
+ default_alloc_size= DEFAULT_ALLOC_SIZE;
bzero((gptr) &tree->null_element,sizeof(tree->null_element));
tree->root= &tree->null_element;
tree->compare=compare;
tree->size_of_element=size > 0 ? (uint) size : 0;
+ tree->memory_limit=memory_limit;
tree->free=free_element;
+ tree->allocated=0;
tree->elements_in_tree=0;
+ tree->custom_arg = custom_arg;
tree->null_element.colour=BLACK;
tree->null_element.left=tree->null_element.right=0;
if (!free_element && size >= 0 &&
((uint) size <= sizeof(void*) || ((uint) size & (sizeof(void*)-1))))
{
tree->offset_to_key=sizeof(TREE_ELEMENT); /* Put key after element */
- /* Fix allocation size so that we don't loose any memory */
+ /* Fix allocation size so that we don't lose any memory */
default_alloc_size/=(sizeof(TREE_ELEMENT)+size);
if (!default_alloc_size)
default_alloc_size=1;
@@ -102,9 +108,9 @@ void init_tree(TREE *tree, uint default_alloc_size, int size,
DBUG_VOID_RETURN;
}
-void delete_tree(TREE *tree)
+static void free_tree(TREE *tree, myf free_flags)
{
- DBUG_ENTER("delete_tree");
+ DBUG_ENTER("free_tree");
DBUG_PRINT("enter",("tree: %lx",tree));
if (tree->root) /* If initialized */
@@ -114,24 +120,43 @@ void delete_tree(TREE *tree)
else
{
if (tree->free)
+ {
+ if (tree->memory_limit)
+ (*tree->free)(NULL, free_init, tree->custom_arg);
delete_tree_element(tree,tree->root);
- free_root(&tree->mem_root,MYF(0));
+ if (tree->memory_limit)
+ (*tree->free)(NULL, free_end, tree->custom_arg);
+ }
+ free_root(&tree->mem_root, free_flags);
}
}
tree->root= &tree->null_element;
tree->elements_in_tree=0;
+ tree->allocated=0;
DBUG_VOID_RETURN;
}
+void delete_tree(TREE* tree)
+{
+ free_tree(tree, MYF(0)); /* my_free() mem_root if applicable */
+}
+
+void reset_tree(TREE* tree)
+{
+ free_tree(tree, MYF(MY_MARK_BLOCKS_FREE));
+ /* do not my_free() mem_root if applicable, just mark blocks as free */
+}
+
+
static void delete_tree_element(TREE *tree, TREE_ELEMENT *element)
{
if (element != &tree->null_element)
{
delete_tree_element(tree,element->left);
- delete_tree_element(tree,element->right);
if (tree->free)
- (*tree->free)(ELEMENT_KEY(tree,element));
+ (*tree->free)(ELEMENT_KEY(tree,element), free_free, tree->custom_arg);
+ delete_tree_element(tree,element->right);
if (tree->with_delete)
my_free((char*) element,MYF(0));
}
@@ -152,7 +177,8 @@ TREE_ELEMENT *tree_insert(TREE *tree, void *key, uint key_size)
for (;;)
{
if (element == &tree->null_element ||
- (cmp=(*tree->compare)(ELEMENT_KEY(tree,element),key)) == 0)
+ (cmp=(*tree->compare)(tree->custom_arg,
+ ELEMENT_KEY(tree,element),key)) == 0)
break;
if (cmp < 0)
{
@@ -165,13 +191,22 @@ TREE_ELEMENT *tree_insert(TREE *tree, void *key, uint key_size)
}
if (element == &tree->null_element)
{
+ uint alloc_size=sizeof(TREE_ELEMENT)+key_size+tree->size_of_element;
+ tree->allocated+=alloc_size;
+
+ if (tree->memory_limit && tree->elements_in_tree
+ && tree->allocated > tree->memory_limit)
+ {
+ reset_tree(tree);
+ return tree_insert(tree, key, key_size);
+ }
+
key_size+=tree->size_of_element;
if (tree->with_delete)
- element=(TREE_ELEMENT *) my_malloc(sizeof(TREE_ELEMENT)+key_size,
- MYF(MY_WME));
+ element=(TREE_ELEMENT *) my_malloc(alloc_size, MYF(MY_WME));
else
element=(TREE_ELEMENT *)
- alloc_root(&tree->mem_root,sizeof(TREE_ELEMENT)+key_size);
+ alloc_root(&tree->mem_root,alloc_size);
if (!element)
return(NULL);
**parent=element;
@@ -195,6 +230,7 @@ TREE_ELEMENT *tree_insert(TREE *tree, void *key, uint key_size)
}
else
element->count++;
+ DBUG_EXECUTE("check_tree", test_rb_tree(tree->root););
return element;
}
@@ -212,7 +248,8 @@ int tree_delete(TREE *tree, void *key)
{
if (element == &tree->null_element)
return 1; /* Was not in tree */
- if ((cmp=(*tree->compare)(ELEMENT_KEY(tree,element),key)) == 0)
+ if ((cmp=(*tree->compare)(tree->custom_arg,
+ ELEMENT_KEY(tree,element),key)) == 0)
break;
if (cmp < 0)
{
@@ -252,7 +289,7 @@ int tree_delete(TREE *tree, void *key)
if (remove_colour == BLACK)
rb_delete_fixup(tree,parent);
if (tree->free)
- (*tree->free)(ELEMENT_KEY(tree,element));
+ (*tree->free)(ELEMENT_KEY(tree,element), free_free, tree->custom_arg);
my_free((gptr) element,MYF(0));
tree->elements_in_tree--;
return 0;
@@ -268,7 +305,8 @@ void *tree_search(TREE *tree, void *key)
{
if (element == &tree->null_element)
return (void*) 0;
- if ((cmp=(*tree->compare)(ELEMENT_KEY(tree,element),key)) == 0)
+ if ((cmp=(*tree->compare)(tree->custom_arg,
+ ELEMENT_KEY(tree,element),key)) == 0)
return ELEMENT_KEY(tree,element);
if (cmp < 0)
element=element->right;
@@ -484,8 +522,7 @@ static void rb_delete_fixup(TREE *tree, TREE_ELEMENT ***parent)
x->colour=BLACK;
}
-
-#ifdef TESTING_TREES
+#ifndef DBUG_OFF
/* Test that the proporties for a red-black tree holds */
@@ -511,5 +548,4 @@ static int test_rb_tree(TREE_ELEMENT *element)
}
return -1;
}
-
#endif
diff --git a/mysys/typelib.c b/mysys/typelib.c
index b18959442ae..e2c8eade5c8 100644
--- a/mysys/typelib.c
+++ b/mysys/typelib.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 typelib */
@@ -84,7 +83,8 @@ int find_type(my_string x, TYPELIB *typelib, uint full_name)
/* Get name of type nr 'nr' */
/* Warning first type is 1, 0 = empty field */
-void make_type(register my_string to, register uint nr, register TYPELIB *typelib)
+void make_type(register my_string to, register uint nr,
+ register TYPELIB *typelib)
{
DBUG_ENTER("make_type");
if (!nr)
diff --git a/pstack/Makefile.am b/pstack/Makefile.am
new file mode 100644
index 00000000000..863a52f4488
--- /dev/null
+++ b/pstack/Makefile.am
@@ -0,0 +1,36 @@
+# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#
+# As pstack doesn't work on all configurations, we have to use
+# the USE_PSTACK hack to get all files into distribution
+#
+
+SUBDIRS = aout
+INCLUDES = -I$(srcdir)/../include -I../include
+noinst_HEADERS = bucomm.h debug.h ieee.h budbg.h demangle.h \
+ linuxthreads.h pstack.h pstacktrace.h
+SRC= bucomm.c filemode.c linuxthreads.c rddbg.c \
+ debug.c ieee.c pstack.c stabs.c
+EXTRA_DIST= $(SRC)
+
+if COMPILE_PSTACK
+pkglib_LIBRARIES = libpstack.a
+libpstack_a_SOURCES = bucomm.c filemode.c linuxthreads.c rddbg.c debug.c ieee.c pstack.c stabs.c
+endif
+
+# Don't update the files from bitkeeper
+%::SCCS/s.%
diff --git a/pstack/aout/Makefile.am b/pstack/aout/Makefile.am
new file mode 100644
index 00000000000..0b02cb7b643
--- /dev/null
+++ b/pstack/aout/Makefile.am
@@ -0,0 +1 @@
+noinst_HEADERS = aout64.h stab.def stab_gnu.h
diff --git a/pstack/aout/aout64.h b/pstack/aout/aout64.h
new file mode 100644
index 00000000000..76f1140b682
--- /dev/null
+++ b/pstack/aout/aout64.h
@@ -0,0 +1,475 @@
+/* `a.out' object-file definitions, including extensions to 64-bit fields */
+
+#ifndef __A_OUT_64_H__
+#define __A_OUT_64_H__
+
+/* This is the layout on disk of the 32-bit or 64-bit exec header. */
+
+#ifndef external_exec
+struct external_exec
+{
+ bfd_byte e_info[4]; /* magic number and stuff */
+ bfd_byte e_text[BYTES_IN_WORD]; /* length of text section in bytes */
+ bfd_byte e_data[BYTES_IN_WORD]; /* length of data section in bytes */
+ bfd_byte e_bss[BYTES_IN_WORD]; /* length of bss area in bytes */
+ bfd_byte e_syms[BYTES_IN_WORD]; /* length of symbol table in bytes */
+ bfd_byte e_entry[BYTES_IN_WORD]; /* start address */
+ bfd_byte e_trsize[BYTES_IN_WORD]; /* length of text relocation info */
+ bfd_byte e_drsize[BYTES_IN_WORD]; /* length of data relocation info */
+};
+
+#define EXEC_BYTES_SIZE (4 + BYTES_IN_WORD * 7)
+
+/* Magic numbers for a.out files */
+
+#if ARCH_SIZE==64
+#define OMAGIC 0x1001 /* Code indicating object file */
+#define ZMAGIC 0x1002 /* Code indicating demand-paged executable. */
+#define NMAGIC 0x1003 /* Code indicating pure executable. */
+
+/* There is no 64-bit QMAGIC as far as I know. */
+
+#define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \
+ && N_MAGIC(x) != NMAGIC \
+ && N_MAGIC(x) != ZMAGIC)
+#else
+#define OMAGIC 0407 /* ...object file or impure executable. */
+#define NMAGIC 0410 /* Code indicating pure executable. */
+#define ZMAGIC 0413 /* Code indicating demand-paged executable. */
+#define BMAGIC 0415 /* Used by a b.out object. */
+
+/* This indicates a demand-paged executable with the header in the text.
+ It is used by 386BSD (and variants) and Linux, at least. */
+#ifndef QMAGIC
+#define QMAGIC 0314
+#endif
+# ifndef N_BADMAG
+# define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \
+ && N_MAGIC(x) != NMAGIC \
+ && N_MAGIC(x) != ZMAGIC \
+ && N_MAGIC(x) != QMAGIC)
+# endif /* N_BADMAG */
+#endif
+
+#endif
+
+#ifdef QMAGIC
+#define N_IS_QMAGIC(x) (N_MAGIC (x) == QMAGIC)
+#else
+#define N_IS_QMAGIC(x) (0)
+#endif
+
+/* The difference between TARGET_PAGE_SIZE and N_SEGSIZE is that TARGET_PAGE_SIZE is
+ the finest granularity at which you can page something, thus it
+ controls the padding (if any) before the text segment of a ZMAGIC
+ file. N_SEGSIZE is the resolution at which things can be marked as
+ read-only versus read/write, so it controls the padding between the
+ text segment and the data segment (in memory; on disk the padding
+ between them is TARGET_PAGE_SIZE). TARGET_PAGE_SIZE and N_SEGSIZE are the same
+ for most machines, but different for sun3. */
+
+/* By default, segment size is constant. But some machines override this
+ to be a function of the a.out header (e.g. machine type). */
+
+#ifndef N_SEGSIZE
+#define N_SEGSIZE(x) SEGMENT_SIZE
+#endif
+
+/* Virtual memory address of the text section.
+ This is getting very complicated. A good reason to discard a.out format
+ for something that specifies these fields explicitly. But til then...
+
+ * OMAGIC and NMAGIC files:
+ (object files: text for "relocatable addr 0" right after the header)
+ start at 0, offset is EXEC_BYTES_SIZE, size as stated.
+ * The text address, offset, and size of ZMAGIC files depend
+ on the entry point of the file:
+ * entry point below TEXT_START_ADDR:
+ (hack for SunOS shared libraries)
+ start at 0, offset is 0, size as stated.
+ * If N_HEADER_IN_TEXT(x) is true (which defaults to being the
+ case when the entry point is EXEC_BYTES_SIZE or further into a page):
+ no padding is needed; text can start after exec header. Sun
+ considers the text segment of such files to include the exec header;
+ for BFD's purposes, we don't, which makes more work for us.
+ start at TEXT_START_ADDR + EXEC_BYTES_SIZE, offset is EXEC_BYTES_SIZE,
+ size as stated minus EXEC_BYTES_SIZE.
+ * If N_HEADER_IN_TEXT(x) is false (which defaults to being the case when
+ the entry point is less than EXEC_BYTES_SIZE into a page (e.g. page
+ aligned)): (padding is needed so that text can start at a page boundary)
+ start at TEXT_START_ADDR, offset TARGET_PAGE_SIZE, size as stated.
+
+ Specific configurations may want to hardwire N_HEADER_IN_TEXT,
+ for efficiency or to allow people to play games with the entry point.
+ In that case, you would #define N_HEADER_IN_TEXT(x) as 1 for sunos,
+ and as 0 for most other hosts (Sony News, Vax Ultrix, etc).
+ (Do this in the appropriate bfd target file.)
+ (The default is a heuristic that will break if people try changing
+ the entry point, perhaps with the ld -e flag.)
+
+ * QMAGIC is always like a ZMAGIC for which N_HEADER_IN_TEXT is true,
+ and for which the starting address is TARGET_PAGE_SIZE (or should this be
+ SEGMENT_SIZE?) (TEXT_START_ADDR only applies to ZMAGIC, not to QMAGIC).
+ */
+
+/* This macro is only relevant for ZMAGIC files; QMAGIC always has the header
+ in the text. */
+#ifndef N_HEADER_IN_TEXT
+#define N_HEADER_IN_TEXT(x) (((x).a_entry & (TARGET_PAGE_SIZE-1)) >= EXEC_BYTES_SIZE)
+#endif
+
+/* Sun shared libraries, not linux. This macro is only relevant for ZMAGIC
+ files. */
+#ifndef N_SHARED_LIB
+#define N_SHARED_LIB(x) ((x).a_entry < TEXT_START_ADDR)
+#endif
+
+/* Returning 0 not TEXT_START_ADDR for OMAGIC and NMAGIC is based on
+ the assumption that we are dealing with a .o file, not an
+ executable. This is necessary for OMAGIC (but means we don't work
+ right on the output from ld -N); more questionable for NMAGIC. */
+
+#ifndef N_TXTADDR
+#define N_TXTADDR(x) \
+ (/* The address of a QMAGIC file is always one page in, */ \
+ /* with the header in the text. */ \
+ N_IS_QMAGIC (x) ? TARGET_PAGE_SIZE + EXEC_BYTES_SIZE : \
+ N_MAGIC(x) != ZMAGIC ? 0 : /* object file or NMAGIC */\
+ N_SHARED_LIB(x) ? 0 : \
+ N_HEADER_IN_TEXT(x) ? \
+ TEXT_START_ADDR + EXEC_BYTES_SIZE : /* no padding */\
+ TEXT_START_ADDR /* a page of padding */\
+ )
+#endif
+
+/* If N_HEADER_IN_TEXT is not true for ZMAGIC, there is some padding
+ to make the text segment start at a certain boundary. For most
+ systems, this boundary is TARGET_PAGE_SIZE. But for Linux, in the
+ time-honored tradition of crazy ZMAGIC hacks, it is 1024 which is
+ not what TARGET_PAGE_SIZE needs to be for QMAGIC. */
+
+#ifndef ZMAGIC_DISK_BLOCK_SIZE
+#define ZMAGIC_DISK_BLOCK_SIZE TARGET_PAGE_SIZE
+#endif
+
+#define N_DISK_BLOCK_SIZE(x) \
+ (N_MAGIC(x) == ZMAGIC ? ZMAGIC_DISK_BLOCK_SIZE : TARGET_PAGE_SIZE)
+
+/* Offset in an a.out of the start of the text section. */
+#ifndef N_TXTOFF
+#define N_TXTOFF(x) \
+ (/* For {O,N,Q}MAGIC, no padding. */ \
+ N_MAGIC(x) != ZMAGIC ? EXEC_BYTES_SIZE : \
+ N_SHARED_LIB(x) ? 0 : \
+ N_HEADER_IN_TEXT(x) ? \
+ EXEC_BYTES_SIZE : /* no padding */\
+ ZMAGIC_DISK_BLOCK_SIZE /* a page of padding */\
+ )
+#endif
+/* Size of the text section. It's always as stated, except that we
+ offset it to `undo' the adjustment to N_TXTADDR and N_TXTOFF
+ for ZMAGIC files that nominally include the exec header
+ as part of the first page of text. (BFD doesn't consider the
+ exec header to be part of the text segment.) */
+#ifndef N_TXTSIZE
+#define N_TXTSIZE(x) \
+ (/* For QMAGIC, we don't consider the header part of the text section. */\
+ N_IS_QMAGIC (x) ? (x).a_text - EXEC_BYTES_SIZE : \
+ (N_MAGIC(x) != ZMAGIC || N_SHARED_LIB(x)) ? (x).a_text : \
+ N_HEADER_IN_TEXT(x) ? \
+ (x).a_text - EXEC_BYTES_SIZE: /* no padding */\
+ (x).a_text /* a page of padding */\
+ )
+#endif
+/* The address of the data segment in virtual memory.
+ It is the text segment address, plus text segment size, rounded
+ up to a N_SEGSIZE boundary for pure or pageable files. */
+#ifndef N_DATADDR
+#define N_DATADDR(x) \
+ (N_MAGIC(x)==OMAGIC? (N_TXTADDR(x)+N_TXTSIZE(x)) \
+ : (N_SEGSIZE(x) + ((N_TXTADDR(x)+N_TXTSIZE(x)-1) & ~(N_SEGSIZE(x)-1))))
+#endif
+/* The address of the BSS segment -- immediately after the data segment. */
+
+#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data)
+
+/* Offsets of the various portions of the file after the text segment. */
+
+/* For {Q,Z}MAGIC, there is padding to make the data segment start on
+ a page boundary. Most of the time the a_text field (and thus
+ N_TXTSIZE) already contains this padding. It is possible that for
+ BSDI and/or 386BSD it sometimes doesn't contain the padding, and
+ perhaps we should be adding it here. But this seems kind of
+ questionable and probably should be BSDI/386BSD-specific if we do
+ do it.
+
+ For NMAGIC (at least for hp300 BSD, probably others), there is
+ padding in memory only, not on disk, so we must *not* ever pad here
+ for NMAGIC. */
+
+#ifndef N_DATOFF
+#define N_DATOFF(x) \
+ (N_TXTOFF(x) + N_TXTSIZE(x))
+#endif
+
+#ifndef N_TRELOFF
+#define N_TRELOFF(x) ( N_DATOFF(x) + (x).a_data )
+#endif
+#ifndef N_DRELOFF
+#define N_DRELOFF(x) ( N_TRELOFF(x) + (x).a_trsize )
+#endif
+#ifndef N_SYMOFF
+#define N_SYMOFF(x) ( N_DRELOFF(x) + (x).a_drsize )
+#endif
+#ifndef N_STROFF
+#define N_STROFF(x) ( N_SYMOFF(x) + (x).a_syms )
+#endif
+
+/* Symbols */
+#ifndef external_nlist
+struct external_nlist {
+ bfd_byte e_strx[BYTES_IN_WORD]; /* index into string table of name */
+ bfd_byte e_type[1]; /* type of symbol */
+ bfd_byte e_other[1]; /* misc info (usually empty) */
+ bfd_byte e_desc[2]; /* description field */
+ bfd_byte e_value[BYTES_IN_WORD]; /* value of symbol */
+};
+#define EXTERNAL_NLIST_SIZE (BYTES_IN_WORD+4+BYTES_IN_WORD)
+#endif
+
+struct internal_nlist {
+ unsigned long n_strx; /* index into string table of name */
+ unsigned char n_type; /* type of symbol */
+ unsigned char n_other; /* misc info (usually empty) */
+ unsigned short n_desc; /* description field */
+ bfd_vma n_value; /* value of symbol */
+};
+
+/* The n_type field is the symbol type, containing: */
+
+#define N_UNDF 0 /* Undefined symbol */
+#define N_ABS 2 /* Absolute symbol -- defined at particular addr */
+#define N_TEXT 4 /* Text sym -- defined at offset in text seg */
+#define N_DATA 6 /* Data sym -- defined at offset in data seg */
+#define N_BSS 8 /* BSS sym -- defined at offset in zero'd seg */
+#define N_COMM 0x12 /* Common symbol (visible after shared lib dynlink) */
+#define N_FN 0x1f /* File name of .o file */
+#define N_FN_SEQ 0x0C /* N_FN from Sequent compilers (sigh) */
+/* Note: N_EXT can only be usefully OR-ed with N_UNDF, N_ABS, N_TEXT,
+ N_DATA, or N_BSS. When the low-order bit of other types is set,
+ (e.g. N_WARNING versus N_FN), they are two different types. */
+#define N_EXT 1 /* External symbol (as opposed to local-to-this-file) */
+#define N_TYPE 0x1e
+#define N_STAB 0xe0 /* If any of these bits are on, it's a debug symbol */
+
+#define N_INDR 0x0a
+
+/* The following symbols refer to set elements.
+ All the N_SET[ATDB] symbols with the same name form one set.
+ Space is allocated for the set in the text section, and each set
+ elements value is stored into one word of the space.
+ The first word of the space is the length of the set (number of elements).
+
+ The address of the set is made into an N_SETV symbol
+ whose name is the same as the name of the set.
+ This symbol acts like a N_DATA global symbol
+ in that it can satisfy undefined external references. */
+
+/* These appear as input to LD, in a .o file. */
+#define N_SETA 0x14 /* Absolute set element symbol */
+#define N_SETT 0x16 /* Text set element symbol */
+#define N_SETD 0x18 /* Data set element symbol */
+#define N_SETB 0x1A /* Bss set element symbol */
+
+/* This is output from LD. */
+#define N_SETV 0x1C /* Pointer to set vector in data area. */
+
+/* Warning symbol. The text gives a warning message, the next symbol
+ in the table will be undefined. When the symbol is referenced, the
+ message is printed. */
+
+#define N_WARNING 0x1e
+
+/* Weak symbols. These are a GNU extension to the a.out format. The
+ semantics are those of ELF weak symbols. Weak symbols are always
+ externally visible. The N_WEAK? values are squeezed into the
+ available slots. The value of a N_WEAKU symbol is 0. The values
+ of the other types are the definitions. */
+#define N_WEAKU 0x0d /* Weak undefined symbol. */
+#define N_WEAKA 0x0e /* Weak absolute symbol. */
+#define N_WEAKT 0x0f /* Weak text symbol. */
+#define N_WEAKD 0x10 /* Weak data symbol. */
+#define N_WEAKB 0x11 /* Weak bss symbol. */
+
+/* Relocations
+
+ There are two types of relocation flavours for a.out systems,
+ standard and extended. The standard form is used on systems where the
+ instruction has room for all the bits of an offset to the operand, whilst
+ the extended form is used when an address operand has to be split over n
+ instructions. Eg, on the 68k, each move instruction can reference
+ the target with a displacement of 16 or 32 bits. On the sparc, move
+ instructions use an offset of 14 bits, so the offset is stored in
+ the reloc field, and the data in the section is ignored.
+*/
+
+/* This structure describes a single relocation to be performed.
+ The text-relocation section of the file is a vector of these structures,
+ all of which apply to the text section.
+ Likewise, the data-relocation section applies to the data section. */
+
+struct reloc_std_external {
+ bfd_byte r_address[BYTES_IN_WORD]; /* offset of of data to relocate */
+ bfd_byte r_index[3]; /* symbol table index of symbol */
+ bfd_byte r_type[1]; /* relocation type */
+};
+
+#define RELOC_STD_BITS_PCREL_BIG ((unsigned int) 0x80)
+#define RELOC_STD_BITS_PCREL_LITTLE ((unsigned int) 0x01)
+
+#define RELOC_STD_BITS_LENGTH_BIG ((unsigned int) 0x60)
+#define RELOC_STD_BITS_LENGTH_SH_BIG 5
+#define RELOC_STD_BITS_LENGTH_LITTLE ((unsigned int) 0x06)
+#define RELOC_STD_BITS_LENGTH_SH_LITTLE 1
+
+#define RELOC_STD_BITS_EXTERN_BIG ((unsigned int) 0x10)
+#define RELOC_STD_BITS_EXTERN_LITTLE ((unsigned int) 0x08)
+
+#define RELOC_STD_BITS_BASEREL_BIG ((unsigned int) 0x08)
+#define RELOC_STD_BITS_BASEREL_LITTLE ((unsigned int) 0x10)
+
+#define RELOC_STD_BITS_JMPTABLE_BIG ((unsigned int) 0x04)
+#define RELOC_STD_BITS_JMPTABLE_LITTLE ((unsigned int) 0x20)
+
+#define RELOC_STD_BITS_RELATIVE_BIG ((unsigned int) 0x02)
+#define RELOC_STD_BITS_RELATIVE_LITTLE ((unsigned int) 0x40)
+
+#define RELOC_STD_SIZE (BYTES_IN_WORD + 3 + 1) /* Bytes per relocation entry */
+
+struct reloc_std_internal
+{
+ bfd_vma r_address; /* Address (within segment) to be relocated. */
+ /* The meaning of r_symbolnum depends on r_extern. */
+ unsigned int r_symbolnum:24;
+ /* Nonzero means value is a pc-relative offset
+ and it should be relocated for changes in its own address
+ as well as for changes in the symbol or section specified. */
+ unsigned int r_pcrel:1;
+ /* Length (as exponent of 2) of the field to be relocated.
+ Thus, a value of 2 indicates 1<<2 bytes. */
+ unsigned int r_length:2;
+ /* 1 => relocate with value of symbol.
+ r_symbolnum is the index of the symbol
+ in files the symbol table.
+ 0 => relocate with the address of a segment.
+ r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS
+ (the N_EXT bit may be set also, but signifies nothing). */
+ unsigned int r_extern:1;
+ /* The next three bits are for SunOS shared libraries, and seem to
+ be undocumented. */
+ unsigned int r_baserel:1; /* Linkage table relative */
+ unsigned int r_jmptable:1; /* pc-relative to jump table */
+ unsigned int r_relative:1; /* "relative relocation" */
+ /* unused */
+ unsigned int r_pad:1; /* Padding -- set to zero */
+};
+
+
+/* EXTENDED RELOCS */
+
+struct reloc_ext_external {
+ bfd_byte r_address[BYTES_IN_WORD]; /* offset of of data to relocate */
+ bfd_byte r_index[3]; /* symbol table index of symbol */
+ bfd_byte r_type[1]; /* relocation type */
+ bfd_byte r_addend[BYTES_IN_WORD]; /* datum addend */
+};
+
+#define RELOC_EXT_BITS_EXTERN_BIG ((unsigned int) 0x80)
+#define RELOC_EXT_BITS_EXTERN_LITTLE ((unsigned int) 0x01)
+
+#define RELOC_EXT_BITS_TYPE_BIG ((unsigned int) 0x1F)
+#define RELOC_EXT_BITS_TYPE_SH_BIG 0
+#define RELOC_EXT_BITS_TYPE_LITTLE ((unsigned int) 0xF8)
+#define RELOC_EXT_BITS_TYPE_SH_LITTLE 3
+
+/* Bytes per relocation entry */
+#define RELOC_EXT_SIZE (BYTES_IN_WORD + 3 + 1 + BYTES_IN_WORD)
+
+enum reloc_type
+{
+ /* simple relocations */
+ RELOC_8, /* data[0:7] = addend + sv */
+ RELOC_16, /* data[0:15] = addend + sv */
+ RELOC_32, /* data[0:31] = addend + sv */
+ /* pc-rel displacement */
+ RELOC_DISP8, /* data[0:7] = addend - pc + sv */
+ RELOC_DISP16, /* data[0:15] = addend - pc + sv */
+ RELOC_DISP32, /* data[0:31] = addend - pc + sv */
+ /* Special */
+ RELOC_WDISP30, /* data[0:29] = (addend + sv - pc)>>2 */
+ RELOC_WDISP22, /* data[0:21] = (addend + sv - pc)>>2 */
+ RELOC_HI22, /* data[0:21] = (addend + sv)>>10 */
+ RELOC_22, /* data[0:21] = (addend + sv) */
+ RELOC_13, /* data[0:12] = (addend + sv) */
+ RELOC_LO10, /* data[0:9] = (addend + sv) */
+ RELOC_SFA_BASE,
+ RELOC_SFA_OFF13,
+ /* P.I.C. (base-relative) */
+ RELOC_BASE10, /* Not sure - maybe we can do this the */
+ RELOC_BASE13, /* right way now */
+ RELOC_BASE22,
+ /* for some sort of pc-rel P.I.C. (?) */
+ RELOC_PC10,
+ RELOC_PC22,
+ /* P.I.C. jump table */
+ RELOC_JMP_TBL,
+ /* reputedly for shared libraries somehow */
+ RELOC_SEGOFF16,
+ RELOC_GLOB_DAT,
+ RELOC_JMP_SLOT,
+ RELOC_RELATIVE,
+
+ RELOC_11,
+ RELOC_WDISP2_14,
+ RELOC_WDISP19,
+ RELOC_HHI22, /* data[0:21] = (addend + sv) >> 42 */
+ RELOC_HLO10, /* data[0:9] = (addend + sv) >> 32 */
+
+ /* 29K relocation types */
+ RELOC_JUMPTARG,
+ RELOC_CONST,
+ RELOC_CONSTH,
+
+ /* All the new ones I can think of, for sparc v9 */
+
+ RELOC_64, /* data[0:63] = addend + sv */
+ RELOC_DISP64, /* data[0:63] = addend - pc + sv */
+ RELOC_WDISP21, /* data[0:20] = (addend + sv - pc)>>2 */
+ RELOC_DISP21, /* data[0:20] = addend - pc + sv */
+ RELOC_DISP14, /* data[0:13] = addend - pc + sv */
+ /* Q .
+ What are the other ones,
+ Since this is a clean slate, can we throw away the ones we dont
+ understand ? Should we sort the values ? What about using a
+ microcode format like the 68k ?
+ */
+ NO_RELOC
+ };
+
+
+struct reloc_internal {
+ bfd_vma r_address; /* offset of of data to relocate */
+ long r_index; /* symbol table index of symbol */
+ enum reloc_type r_type; /* relocation type */
+ bfd_vma r_addend; /* datum addend */
+};
+
+/* Q.
+ Should the length of the string table be 4 bytes or 8 bytes ?
+
+ Q.
+ What about archive indexes ?
+
+ */
+
+#endif /* __A_OUT_64_H__ */
diff --git a/pstack/aout/stab.def b/pstack/aout/stab.def
new file mode 100644
index 00000000000..3c6b456d3a9
--- /dev/null
+++ b/pstack/aout/stab.def
@@ -0,0 +1,264 @@
+/* Table of DBX symbol codes for the GNU system.
+ Copyright (C) 1988, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* New stab from Solaris 2. This uses an n_type of 0, which in a.out files
+ overlaps the N_UNDF used for ordinary symbols. In ELF files, the
+ debug information is in a different file section, so there is no conflict.
+ This symbol's n_value gives the size of the string section associated
+ with this file. The symbol's n_strx (relative to the just-updated
+ string section start address) gives the name of the source file,
+ e.g. "foo.c", without any path information. The symbol's n_desc gives
+ the count of upcoming symbols associated with this file (not including
+ this one). */
+/* __define_stab (N_UNDF, 0x00, "UNDF") */
+
+/* Global variable. Only the name is significant.
+ To find the address, look in the corresponding external symbol. */
+__define_stab (N_GSYM, 0x20, "GSYM")
+
+/* Function name for BSD Fortran. Only the name is significant.
+ To find the address, look in the corresponding external symbol. */
+__define_stab (N_FNAME, 0x22, "FNAME")
+
+/* Function name or text-segment variable for C. Value is its address.
+ Desc is supposedly starting line number, but GCC doesn't set it
+ and DBX seems not to miss it. */
+__define_stab (N_FUN, 0x24, "FUN")
+
+/* Data-segment variable with internal linkage. Value is its address.
+ "Static Sym". */
+__define_stab (N_STSYM, 0x26, "STSYM")
+
+/* BSS-segment variable with internal linkage. Value is its address. */
+__define_stab (N_LCSYM, 0x28, "LCSYM")
+
+/* Name of main routine. Only the name is significant. */
+__define_stab (N_MAIN, 0x2a, "MAIN")
+
+/* Solaris2: Read-only data symbols. */
+__define_stab (N_ROSYM, 0x2c, "ROSYM")
+
+/* Global symbol in Pascal.
+ Supposedly the value is its line number; I'm skeptical. */
+__define_stab (N_PC, 0x30, "PC")
+
+/* Number of symbols: 0, files,,funcs,lines according to Ultrix V4.0. */
+__define_stab (N_NSYMS, 0x32, "NSYMS")
+
+/* "No DST map for sym: name, ,0,type,ignored" according to Ultrix V4.0. */
+__define_stab (N_NOMAP, 0x34, "NOMAP")
+
+/* New stab from Solaris 2. Like N_SO, but for the object file. Two in
+ a row provide the build directory and the relative path of the .o from it.
+ Solaris2 uses this to avoid putting the stabs info into the linked
+ executable; this stab goes into the ".stab.index" section, and the debugger
+ reads the real stabs directly from the .o files instead. */
+__define_stab (N_OBJ, 0x38, "OBJ")
+
+/* New stab from Solaris 2. Options for the debugger, related to the
+ source language for this module. E.g. whether to use ANSI
+ integral promotions or traditional integral promotions. */
+__define_stab (N_OPT, 0x3c, "OPT")
+
+/* Register variable. Value is number of register. */
+__define_stab (N_RSYM, 0x40, "RSYM")
+
+/* Modula-2 compilation unit. Can someone say what info it contains? */
+__define_stab (N_M2C, 0x42, "M2C")
+
+/* Line number in text segment. Desc is the line number;
+ value is corresponding address. On Solaris2, the line number is
+ relative to the start of the current function. */
+__define_stab (N_SLINE, 0x44, "SLINE")
+
+/* Similar, for data segment. */
+__define_stab (N_DSLINE, 0x46, "DSLINE")
+
+/* Similar, for bss segment. */
+__define_stab (N_BSLINE, 0x48, "BSLINE")
+
+/* Sun's source-code browser stabs. ?? Don't know what the fields are.
+ Supposedly the field is "path to associated .cb file". THIS VALUE
+ OVERLAPS WITH N_BSLINE! */
+__define_stab_duplicate (N_BROWS, 0x48, "BROWS")
+
+/* GNU Modula-2 definition module dependency. Value is the modification time
+ of the definition file. Other is non-zero if it is imported with the
+ GNU M2 keyword %INITIALIZE. Perhaps N_M2C can be used if there
+ are enough empty fields? */
+__define_stab(N_DEFD, 0x4a, "DEFD")
+
+/* New in Solaris2. Function start/body/end line numbers. */
+__define_stab(N_FLINE, 0x4C, "FLINE")
+
+/* THE FOLLOWING TWO STAB VALUES CONFLICT. Happily, one is for Modula-2
+ and one is for C++. Still,... */
+/* GNU C++ exception variable. Name is variable name. */
+__define_stab (N_EHDECL, 0x50, "EHDECL")
+/* Modula2 info "for imc": name,,0,0,0 according to Ultrix V4.0. */
+__define_stab_duplicate (N_MOD2, 0x50, "MOD2")
+
+/* GNU C++ `catch' clause. Value is its address. Desc is nonzero if
+ this entry is immediately followed by a CAUGHT stab saying what exception
+ was caught. Multiple CAUGHT stabs means that multiple exceptions
+ can be caught here. If Desc is 0, it means all exceptions are caught
+ here. */
+__define_stab (N_CATCH, 0x54, "CATCH")
+
+/* Structure or union element. Value is offset in the structure. */
+__define_stab (N_SSYM, 0x60, "SSYM")
+
+/* Solaris2: Last stab emitted for module. */
+__define_stab (N_ENDM, 0x62, "ENDM")
+
+/* Name of main source file.
+ Value is starting text address of the compilation.
+ If multiple N_SO's appear, the first to contain a trailing / is the
+ compilation directory. The first to not contain a trailing / is the
+ source file name, relative to the compilation directory. Others (perhaps
+ resulting from cfront) are ignored.
+ On Solaris2, value is undefined, but desc is a source-language code. */
+
+__define_stab (N_SO, 0x64, "SO")
+
+/* Automatic variable in the stack. Value is offset from frame pointer.
+ Also used for type descriptions. */
+__define_stab (N_LSYM, 0x80, "LSYM")
+
+/* Beginning of an include file. Only Sun uses this.
+ In an object file, only the name is significant.
+ The Sun linker puts data into some of the other fields. */
+__define_stab (N_BINCL, 0x82, "BINCL")
+
+/* Name of sub-source file (#include file).
+ Value is starting text address of the compilation. */
+__define_stab (N_SOL, 0x84, "SOL")
+
+/* Parameter variable. Value is offset from argument pointer.
+ (On most machines the argument pointer is the same as the frame pointer. */
+__define_stab (N_PSYM, 0xa0, "PSYM")
+
+/* End of an include file. No name.
+ This and N_BINCL act as brackets around the file's output.
+ In an object file, there is no significant data in this entry.
+ The Sun linker puts data into some of the fields. */
+__define_stab (N_EINCL, 0xa2, "EINCL")
+
+/* Alternate entry point. Value is its address. */
+__define_stab (N_ENTRY, 0xa4, "ENTRY")
+
+/* Beginning of lexical block.
+ The desc is the nesting level in lexical blocks.
+ The value is the address of the start of the text for the block.
+ The variables declared inside the block *precede* the N_LBRAC symbol.
+ On Solaris2, the value is relative to the start of the current function. */
+__define_stab (N_LBRAC, 0xc0, "LBRAC")
+
+/* Place holder for deleted include file. Replaces a N_BINCL and everything
+ up to the corresponding N_EINCL. The Sun linker generates these when
+ it finds multiple identical copies of the symbols from an include file.
+ This appears only in output from the Sun linker. */
+__define_stab (N_EXCL, 0xc2, "EXCL")
+
+/* Modula-2 scope information. Can someone say what info it contains? */
+__define_stab (N_SCOPE, 0xc4, "SCOPE")
+
+/* End of a lexical block. Desc matches the N_LBRAC's desc.
+ The value is the address of the end of the text for the block.
+ On Solaris2, the value is relative to the start of the current function. */
+__define_stab (N_RBRAC, 0xe0, "RBRAC")
+
+/* Begin named common block. Only the name is significant. */
+__define_stab (N_BCOMM, 0xe2, "BCOMM")
+
+/* End named common block. Only the name is significant
+ (and it should match the N_BCOMM). */
+__define_stab (N_ECOMM, 0xe4, "ECOMM")
+
+/* Member of a common block; value is offset within the common block.
+ This should occur within a BCOMM/ECOMM pair. */
+__define_stab (N_ECOML, 0xe8, "ECOML")
+
+/* Solaris2: Pascal "with" statement: type,,0,0,offset */
+__define_stab (N_WITH, 0xea, "WITH")
+
+/* These STAB's are used on Gould systems for Non-Base register symbols
+ or something like that. FIXME. I have assigned the values at random
+ since I don't have a Gould here. Fixups from Gould folk welcome... */
+__define_stab (N_NBTEXT, 0xF0, "NBTEXT")
+__define_stab (N_NBDATA, 0xF2, "NBDATA")
+__define_stab (N_NBBSS, 0xF4, "NBBSS")
+__define_stab (N_NBSTS, 0xF6, "NBSTS")
+__define_stab (N_NBLCS, 0xF8, "NBLCS")
+
+/* Second symbol entry containing a length-value for the preceding entry.
+ The value is the length. */
+__define_stab (N_LENG, 0xfe, "LENG")
+
+/* The above information, in matrix format.
+
+ STAB MATRIX
+ _________________________________________________
+ | 00 - 1F are not dbx stab symbols |
+ | In most cases, the low bit is the EXTernal bit|
+
+ | 00 UNDEF | 02 ABS | 04 TEXT | 06 DATA |
+ | 01 |EXT | 03 |EXT | 05 |EXT | 07 |EXT |
+
+ | 08 BSS | 0A INDR | 0C FN_SEQ | 0E WEAKA |
+ | 09 |EXT | 0B | 0D WEAKU | 0F WEAKT |
+
+ | 10 WEAKD | 12 COMM | 14 SETA | 16 SETT |
+ | 11 WEAKB | 13 | 15 | 17 |
+
+ | 18 SETD | 1A SETB | 1C SETV | 1E WARNING|
+ | 19 | 1B | 1D | 1F FN |
+
+ |_______________________________________________|
+ | Debug entries with bit 01 set are unused. |
+ | 20 GSYM | 22 FNAME | 24 FUN | 26 STSYM |
+ | 28 LCSYM | 2A MAIN | 2C ROSYM | 2E |
+ | 30 PC | 32 NSYMS | 34 NOMAP | 36 |
+ | 38 OBJ | 3A | 3C OPT | 3E |
+ | 40 RSYM | 42 M2C | 44 SLINE | 46 DSLINE |
+ | 48 BSLINE*| 4A DEFD | 4C FLINE | 4E |
+ | 50 EHDECL*| 52 | 54 CATCH | 56 |
+ | 58 | 5A | 5C | 5E |
+ | 60 SSYM | 62 ENDM | 64 SO | 66 |
+ | 68 | 6A | 6C | 6E |
+ | 70 | 72 | 74 | 76 |
+ | 78 | 7A | 7C | 7E |
+ | 80 LSYM | 82 BINCL | 84 SOL | 86 |
+ | 88 | 8A | 8C | 8E |
+ | 90 | 92 | 94 | 96 |
+ | 98 | 9A | 9C | 9E |
+ | A0 PSYM | A2 EINCL | A4 ENTRY | A6 |
+ | A8 | AA | AC | AE |
+ | B0 | B2 | B4 | B6 |
+ | B8 | BA | BC | BE |
+ | C0 LBRAC | C2 EXCL | C4 SCOPE | C6 |
+ | C8 | CA | CC | CE |
+ | D0 | D2 | D4 | D6 |
+ | D8 | DA | DC | DE |
+ | E0 RBRAC | E2 BCOMM | E4 ECOMM | E6 |
+ | E8 ECOML | EA WITH | EC | EE |
+ | F0 | F2 | F4 | F6 |
+ | F8 | FA | FC | FE LENG |
+ +-----------------------------------------------+
+ * 50 EHDECL is also MOD2.
+ * 48 BSLINE is also BROWS.
+ */
diff --git a/pstack/aout/stab_gnu.h b/pstack/aout/stab_gnu.h
new file mode 100644
index 00000000000..7d18e14a263
--- /dev/null
+++ b/pstack/aout/stab_gnu.h
@@ -0,0 +1,37 @@
+#ifndef __GNU_STAB__
+
+/* Indicate the GNU stab.h is in use. */
+
+#define __GNU_STAB__
+
+#define __define_stab(NAME, CODE, STRING) NAME=CODE,
+#define __define_stab_duplicate(NAME, CODE, STRING) NAME=CODE,
+
+enum __stab_debug_code
+{
+#include "aout/stab.def"
+LAST_UNUSED_STAB_CODE
+};
+
+#undef __define_stab
+
+/* Definitions of "desc" field for N_SO stabs in Solaris2. */
+
+#define N_SO_AS 1
+#define N_SO_C 2
+#define N_SO_ANSI_C 3
+#define N_SO_CC 4 /* C++ */
+#define N_SO_FORTRAN 5
+#define N_SO_PASCAL 6
+
+/* Solaris2: Floating point type values in basic types. */
+
+#define NF_NONE 0
+#define NF_SINGLE 1 /* IEEE 32-bit */
+#define NF_DOUBLE 2 /* IEEE 64-bit */
+#define NF_COMPLEX 3 /* Fortran complex */
+#define NF_COMPLEX16 4 /* Fortran double complex */
+#define NF_COMPLEX32 5 /* Fortran complex*16 */
+#define NF_LDOUBLE 6 /* Long double (whatever that is) */
+
+#endif /* __GNU_STAB_ */
diff --git a/pstack/bucomm.c b/pstack/bucomm.c
new file mode 100644
index 00000000000..d3231e71747
--- /dev/null
+++ b/pstack/bucomm.c
@@ -0,0 +1,238 @@
+/* bucomm.c -- Bin Utils COMmon code.
+ Copyright (C) 1991, 92, 93, 94, 95, 1997 Free Software Foundation, Inc.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; 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. */
+
+/* We might put this in a library someday so it could be dynamically
+ loaded, but for now it's not necessary. */
+
+#include <bfd.h>
+#include <libiberty.h>
+#include "bucomm.h"
+
+#include <sys/stat.h>
+#include <time.h> /* ctime, maybe time_t */
+
+#ifdef ANSI_PROTOTYPES
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+/* Error reporting */
+
+char *program_name;
+
+void
+bfd_nonfatal (string)
+ CONST char *string;
+{
+ CONST char *errmsg = bfd_errmsg (bfd_get_error ());
+
+ if (string)
+ fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg);
+ else
+ fprintf (stderr, "%s: %s\n", program_name, errmsg);
+}
+
+void
+bfd_fatal (string)
+ CONST char *string;
+{
+ bfd_nonfatal (string);
+ xexit (1);
+}
+
+#ifdef ANSI_PROTOTYPES
+void
+fatal (const char *format, ...)
+{
+ va_list args;
+
+ fprintf (stderr, "%s: ", program_name);
+ va_start (args, format);
+ vfprintf (stderr, format, args);
+ va_end (args);
+ putc ('\n', stderr);
+ xexit (1);
+}
+#else
+void
+fatal (va_alist)
+ va_dcl
+{
+ char *Format;
+ va_list args;
+
+ fprintf (stderr, "%s: ", program_name);
+ va_start (args);
+ Format = va_arg (args, char *);
+ vfprintf (stderr, Format, args);
+ va_end (args);
+ putc ('\n', stderr);
+ xexit (1);
+}
+#endif
+
+/* Set the default BFD target based on the configured target. Doing
+ this permits the binutils to be configured for a particular target,
+ and linked against a shared BFD library which was configured for a
+ different target. */
+
+#define TARGET "elf32-i386" /* FIXME: hard-coded! */
+void
+set_default_bfd_target ()
+{
+ /* The macro TARGET is defined by Makefile. */
+ const char *target = TARGET;
+
+ if (! bfd_set_default_target (target))
+ {
+ char *errmsg;
+
+ errmsg = (char *) xmalloc (100 + strlen (target));
+ sprintf (errmsg, "can't set BFD default target to `%s'", target);
+ bfd_fatal (errmsg);
+ }
+}
+
+/* After a false return from bfd_check_format_matches with
+ bfd_get_error () == bfd_error_file_ambiguously_recognized, print
+ the possible matching targets. */
+
+void
+list_matching_formats (p)
+ char **p;
+{
+ fprintf(stderr, "%s: Matching formats:", program_name);
+ while (*p)
+ fprintf(stderr, " %s", *p++);
+ fprintf(stderr, "\n");
+}
+
+/* List the supported targets. */
+
+void
+list_supported_targets (name, f)
+ const char *name;
+ FILE *f;
+{
+ extern bfd_target *bfd_target_vector[];
+ int t;
+
+ if (name == NULL)
+ fprintf (f, "Supported targets:");
+ else
+ fprintf (f, "%s: supported targets:", name);
+ for (t = 0; bfd_target_vector[t] != NULL; t++)
+ fprintf (f, " %s", bfd_target_vector[t]->name);
+ fprintf (f, "\n");
+}
+
+/* Display the archive header for an element as if it were an ls -l listing:
+
+ Mode User\tGroup\tSize\tDate Name */
+
+void
+print_arelt_descr (file, abfd, verbose)
+ FILE *file;
+ bfd *abfd;
+ boolean verbose;
+{
+ struct stat buf;
+
+ if (verbose)
+ {
+ if (bfd_stat_arch_elt (abfd, &buf) == 0)
+ {
+ char modebuf[11];
+ char timebuf[40];
+ time_t when = buf.st_mtime;
+ CONST char *ctime_result = (CONST char *) ctime (&when);
+
+ /* POSIX format: skip weekday and seconds from ctime output. */
+ sprintf (timebuf, "%.12s %.4s", ctime_result + 4, ctime_result + 20);
+
+ mode_string (buf.st_mode, modebuf);
+ modebuf[10] = '\0';
+ /* POSIX 1003.2/D11 says to skip first character (entry type). */
+ fprintf (file, "%s %ld/%ld %6ld %s ", modebuf + 1,
+ (long) buf.st_uid, (long) buf.st_gid,
+ (long) buf.st_size, timebuf);
+ }
+ }
+
+ fprintf (file, "%s\n", bfd_get_filename (abfd));
+}
+
+/* Return the name of a temporary file in the same directory as FILENAME. */
+
+char *
+make_tempname (filename)
+ char *filename;
+{
+ static char template[] = "stXXXXXX";
+ char *tmpname;
+ char *slash = strrchr (filename, '/');
+
+#if defined (__DJGPP__) || defined (__GO32__) || defined (_WIN32)
+ if (slash == NULL)
+ slash = strrchr (filename, '\\');
+#endif
+
+ if (slash != (char *) NULL)
+ {
+ char c;
+
+ c = *slash;
+ *slash = 0;
+ tmpname = xmalloc (strlen (filename) + sizeof (template) + 1);
+ strcpy (tmpname, filename);
+ strcat (tmpname, "/");
+ strcat (tmpname, template);
+ mkstemp (tmpname);
+ *slash = c;
+ }
+ else
+ {
+ tmpname = xmalloc (sizeof (template));
+ strcpy (tmpname, template);
+ mkstemp (tmpname);
+ }
+ return tmpname;
+}
+
+/* Parse a string into a VMA, with a fatal error if it can't be
+ parsed. */
+
+bfd_vma
+parse_vma (s, arg)
+ const char *s;
+ const char *arg;
+{
+ bfd_vma ret;
+ const char *end;
+
+ ret = bfd_scan_vma (s, &end, 0);
+ if (*end != '\0')
+ {
+ fprintf (stderr, "%s: %s: bad number: %s\n", program_name, arg, s);
+ exit (1);
+ }
+ return ret;
+}
diff --git a/pstack/bucomm.h b/pstack/bucomm.h
new file mode 100644
index 00000000000..7712a70f5a2
--- /dev/null
+++ b/pstack/bucomm.h
@@ -0,0 +1,85 @@
+/* bucomm.h -- binutils common include file.
+ Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
+
+This file is part of GNU Binutils.
+
+This program is free software; 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 _BUCOMM_H
+#define _BUCOMM_H
+
+#include "ansidecl.h"
+#include <stdio.h>
+#include <sys/types.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <string.h>
+
+#include <stdlib.h>
+
+#include <fcntl.h>
+
+#ifdef __GNUC__
+# undef alloca
+# define alloca __builtin_alloca
+#else
+# if HAVE_ALLOCA_H
+# include <alloca.h>
+# else
+# ifndef alloca /* predefined by HP cc +Olibcalls */
+# if !defined (__STDC__) && !defined (__hpux)
+char *alloca ();
+# else
+void *alloca ();
+# endif /* __STDC__, __hpux */
+# endif /* alloca */
+# endif /* HAVE_ALLOCA_H */
+#endif
+
+/* bucomm.c */
+void bfd_nonfatal PARAMS ((CONST char *));
+
+void bfd_fatal PARAMS ((CONST char *));
+
+void fatal PARAMS ((CONST char *, ...));
+
+void set_default_bfd_target PARAMS ((void));
+
+void list_matching_formats PARAMS ((char **p));
+
+void list_supported_targets PARAMS ((const char *, FILE *));
+
+void print_arelt_descr PARAMS ((FILE *file, bfd *abfd, boolean verbose));
+
+char *make_tempname PARAMS ((char *));
+
+bfd_vma parse_vma PARAMS ((const char *, const char *));
+
+extern char *program_name;
+
+/* filemode.c */
+void mode_string PARAMS ((unsigned long mode, char *buf));
+
+/* version.c */
+extern void print_version PARAMS ((const char *));
+
+/* libiberty */
+PTR xmalloc PARAMS ((size_t));
+
+PTR xrealloc PARAMS ((PTR, size_t));
+
+#endif /* _BUCOMM_H */
diff --git a/pstack/budbg.h b/pstack/budbg.h
new file mode 100644
index 00000000000..d8ee8895e76
--- /dev/null
+++ b/pstack/budbg.h
@@ -0,0 +1,58 @@
+/* budbg.c -- Interfaces to the generic debugging information routines.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <ian@cygnus.com>.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; 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 BUDBG_H
+#define BUDBG_H
+
+#include <stdio.h>
+
+/* Routine used to read generic debugging information. */
+
+extern PTR read_debugging_info PARAMS ((bfd *, asymbol **, long));
+
+/* Routine used to print generic debugging information. */
+
+extern boolean print_debugging_info PARAMS ((FILE *, PTR));
+
+/* Routines used to read and write stabs information. */
+
+extern PTR start_stab PARAMS ((PTR, bfd *, boolean, asymbol **, long));
+
+extern boolean finish_stab PARAMS ((PTR, PTR));
+
+extern boolean parse_stab PARAMS ((PTR, PTR, int, int, bfd_vma, const char *));
+
+extern boolean write_stabs_in_sections_debugging_info
+ PARAMS ((bfd *, PTR, bfd_byte **, bfd_size_type *, bfd_byte **,
+ bfd_size_type *));
+
+/* Routines used to read and write IEEE debugging information. */
+
+extern boolean parse_ieee
+ PARAMS ((PTR, bfd *, const bfd_byte *, bfd_size_type));
+
+extern boolean write_ieee_debugging_info PARAMS ((bfd *, PTR));
+
+/* Routine used to read COFF debugging information. */
+
+extern boolean parse_coff PARAMS ((bfd *, asymbol **, long, PTR));
+
+#endif
diff --git a/pstack/debug.c b/pstack/debug.c
new file mode 100644
index 00000000000..73412ae3f03
--- /dev/null
+++ b/pstack/debug.c
@@ -0,0 +1,3509 @@
+/* debug.c -- Handle generic debugging information.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <ian@cygnus.com>.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; 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 implements a generic debugging format. We may eventually
+ have readers which convert different formats into this generic
+ format, and writers which write it out. The initial impetus for
+ this was writing a convertor from stabs to HP IEEE-695 debugging
+ format. */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include <bfd.h>
+#include "bucomm.h"
+#include <libiberty.h>
+#include "debug.h"
+
+/* Global information we keep for debugging. A pointer to this
+ structure is the debugging handle passed to all the routines. */
+
+struct debug_handle
+{
+ /* A linked list of compilation units. */
+ struct debug_unit *units;
+ /* The current compilation unit. */
+ struct debug_unit *current_unit;
+ /* The current source file. */
+ struct debug_file *current_file;
+ /* The current function. */
+ struct debug_function *current_function;
+ /* The current block. */
+ struct debug_block *current_block;
+ /* The current line number information for the current unit. */
+ struct debug_lineno *current_lineno;
+ /* Mark. This is used by debug_write. */
+ unsigned int mark;
+ /* A struct/class ID used by debug_write. */
+ unsigned int class_id;
+ /* The base for class_id for this call to debug_write. */
+ unsigned int base_id;
+ /* The current line number in debug_write. */
+ struct debug_lineno *current_write_lineno;
+ unsigned int current_write_lineno_index;
+ /* A list of classes which have assigned ID's during debug_write.
+ This is linked through the next_id field of debug_class_type. */
+ struct debug_class_id *id_list;
+ /* A list used to avoid recursion during debug_type_samep. */
+ struct debug_type_compare_list *compare_list;
+};
+
+/* Information we keep for a single compilation unit. */
+
+struct debug_unit
+{
+ /* The next compilation unit. */
+ struct debug_unit *next;
+ /* A list of files included in this compilation unit. The first
+ file is always the main one, and that is where the main file name
+ is stored. */
+ struct debug_file *files;
+ /* Line number information for this compilation unit. This is not
+ stored by function, because assembler code may have line number
+ information without function information. */
+ struct debug_lineno *linenos;
+};
+
+/* Information kept for a single source file. */
+
+struct debug_file
+{
+ /* The next source file in this compilation unit. */
+ struct debug_file *next;
+ /* The name of the source file. */
+ const char *filename;
+ /* Global functions, variables, types, etc. */
+ struct debug_namespace *globals;
+};
+
+/* A type. */
+
+struct debug_type
+{
+ /* Kind of type. */
+ enum debug_type_kind kind;
+ /* Size of type (0 if not known). */
+ unsigned int size;
+ /* Type which is a pointer to this type. */
+ debug_type pointer;
+ /* Tagged union with additional information about the type. */
+ union
+ {
+ /* DEBUG_KIND_INDIRECT. */
+ struct debug_indirect_type *kindirect;
+ /* DEBUG_KIND_INT. */
+ /* Whether the integer is unsigned. */
+ boolean kint;
+ /* DEBUG_KIND_STRUCT, DEBUG_KIND_UNION, DEBUG_KIND_CLASS,
+ DEBUG_KIND_UNION_CLASS. */
+ struct debug_class_type *kclass;
+ /* DEBUG_KIND_ENUM. */
+ struct debug_enum_type *kenum;
+ /* DEBUG_KIND_POINTER. */
+ struct debug_type *kpointer;
+ /* DEBUG_KIND_FUNCTION. */
+ struct debug_function_type *kfunction;
+ /* DEBUG_KIND_REFERENCE. */
+ struct debug_type *kreference;
+ /* DEBUG_KIND_RANGE. */
+ struct debug_range_type *krange;
+ /* DEBUG_KIND_ARRAY. */
+ struct debug_array_type *karray;
+ /* DEBUG_KIND_SET. */
+ struct debug_set_type *kset;
+ /* DEBUG_KIND_OFFSET. */
+ struct debug_offset_type *koffset;
+ /* DEBUG_KIND_METHOD. */
+ struct debug_method_type *kmethod;
+ /* DEBUG_KIND_CONST. */
+ struct debug_type *kconst;
+ /* DEBUG_KIND_VOLATILE. */
+ struct debug_type *kvolatile;
+ /* DEBUG_KIND_NAMED, DEBUG_KIND_TAGGED. */
+ struct debug_named_type *knamed;
+ } u;
+};
+
+/* Information kept for an indirect type. */
+
+struct debug_indirect_type
+{
+ /* Slot where the final type will appear. */
+ debug_type *slot;
+ /* Tag. */
+ const char *tag;
+};
+
+/* Information kept for a struct, union, or class. */
+
+struct debug_class_type
+{
+ /* NULL terminated array of fields. */
+ debug_field *fields;
+ /* A mark field which indicates whether the struct has already been
+ printed. */
+ unsigned int mark;
+ /* This is used to uniquely identify unnamed structs when printing. */
+ unsigned int id;
+ /* The remaining fields are only used for DEBUG_KIND_CLASS and
+ DEBUG_KIND_UNION_CLASS. */
+ /* NULL terminated array of base classes. */
+ debug_baseclass *baseclasses;
+ /* NULL terminated array of methods. */
+ debug_method *methods;
+ /* The type of the class providing the virtual function table for
+ this class. This may point to the type itself. */
+ debug_type vptrbase;
+};
+
+/* Information kept for an enum. */
+
+struct debug_enum_type
+{
+ /* NULL terminated array of names. */
+ const char **names;
+ /* Array of corresponding values. */
+ bfd_signed_vma *values;
+};
+
+/* Information kept for a function. FIXME: We should be able to
+ record the parameter types. */
+
+struct debug_function_type
+{
+ /* Return type. */
+ debug_type return_type;
+ /* NULL terminated array of argument types. */
+ debug_type *arg_types;
+ /* Whether the function takes a variable number of arguments. */
+ boolean varargs;
+};
+
+/* Information kept for a range. */
+
+struct debug_range_type
+{
+ /* Range base type. */
+ debug_type type;
+ /* Lower bound. */
+ bfd_signed_vma lower;
+ /* Upper bound. */
+ bfd_signed_vma upper;
+};
+
+/* Information kept for an array. */
+
+struct debug_array_type
+{
+ /* Element type. */
+ debug_type element_type;
+ /* Range type. */
+ debug_type range_type;
+ /* Lower bound. */
+ bfd_signed_vma lower;
+ /* Upper bound. */
+ bfd_signed_vma upper;
+ /* Whether this array is really a string. */
+ boolean stringp;
+};
+
+/* Information kept for a set. */
+
+struct debug_set_type
+{
+ /* Base type. */
+ debug_type type;
+ /* Whether this set is really a bitstring. */
+ boolean bitstringp;
+};
+
+/* Information kept for an offset type (a based pointer). */
+
+struct debug_offset_type
+{
+ /* The type the pointer is an offset from. */
+ debug_type base_type;
+ /* The type the pointer points to. */
+ debug_type target_type;
+};
+
+/* Information kept for a method type. */
+
+struct debug_method_type
+{
+ /* The return type. */
+ debug_type return_type;
+ /* The object type which this method is for. */
+ debug_type domain_type;
+ /* A NULL terminated array of argument types. */
+ debug_type *arg_types;
+ /* Whether the method takes a variable number of arguments. */
+ boolean varargs;
+};
+
+/* Information kept for a named type. */
+
+struct debug_named_type
+{
+ /* Name. */
+ struct debug_name *name;
+ /* Real type. */
+ debug_type type;
+};
+
+/* A field in a struct or union. */
+
+struct debug_field
+{
+ /* Name of the field. */
+ const char *name;
+ /* Type of the field. */
+ struct debug_type *type;
+ /* Visibility of the field. */
+ enum debug_visibility visibility;
+ /* Whether this is a static member. */
+ boolean static_member;
+ union
+ {
+ /* If static_member is false. */
+ struct
+ {
+ /* Bit position of the field in the struct. */
+ unsigned int bitpos;
+ /* Size of the field in bits. */
+ unsigned int bitsize;
+ } f;
+ /* If static_member is true. */
+ struct
+ {
+ const char *physname;
+ } s;
+ } u;
+};
+
+/* A base class for an object. */
+
+struct debug_baseclass
+{
+ /* Type of the base class. */
+ struct debug_type *type;
+ /* Bit position of the base class in the object. */
+ unsigned int bitpos;
+ /* Whether the base class is virtual. */
+ boolean virtual;
+ /* Visibility of the base class. */
+ enum debug_visibility visibility;
+};
+
+/* A method of an object. */
+
+struct debug_method
+{
+ /* The name of the method. */
+ const char *name;
+ /* A NULL terminated array of different types of variants. */
+ struct debug_method_variant **variants;
+};
+
+/* The variants of a method function of an object. These indicate
+ which method to run. */
+
+struct debug_method_variant
+{
+ /* The physical name of the function. */
+ const char *physname;
+ /* The type of the function. */
+ struct debug_type *type;
+ /* The visibility of the function. */
+ enum debug_visibility visibility;
+ /* Whether the function is const. */
+ boolean constp;
+ /* Whether the function is volatile. */
+ boolean volatilep;
+ /* The offset to the function in the virtual function table. */
+ bfd_vma voffset;
+ /* If voffset is VOFFSET_STATIC_METHOD, this is a static method. */
+#define VOFFSET_STATIC_METHOD ((bfd_vma) -1)
+ /* Context of a virtual method function. */
+ struct debug_type *context;
+};
+
+/* A variable. This is the information we keep for a variable object.
+ This has no name; a name is associated with a variable in a
+ debug_name structure. */
+
+struct debug_variable
+{
+ /* Kind of variable. */
+ enum debug_var_kind kind;
+ /* Type. */
+ debug_type type;
+ /* Value. The interpretation of the value depends upon kind. */
+ bfd_vma val;
+};
+
+/* A function. This has no name; a name is associated with a function
+ in a debug_name structure. */
+
+struct debug_function
+{
+ /* Return type. */
+ debug_type return_type;
+ /* Parameter information. */
+ struct debug_parameter *parameters;
+ /* Block information. The first structure on the list is the main
+ block of the function, and describes function local variables. */
+ struct debug_block *blocks;
+};
+
+/* A function parameter. */
+
+struct debug_parameter
+{
+ /* Next parameter. */
+ struct debug_parameter *next;
+ /* Name. */
+ const char *name;
+ /* Type. */
+ debug_type type;
+ /* Kind. */
+ enum debug_parm_kind kind;
+ /* Value (meaning depends upon kind). */
+ bfd_vma val;
+};
+
+/* A typed constant. */
+
+struct debug_typed_constant
+{
+ /* Type. */
+ debug_type type;
+ /* Value. FIXME: We may eventually need to support non-integral
+ values. */
+ bfd_vma val;
+};
+
+/* Information about a block within a function. */
+
+struct debug_block
+{
+ /* Next block with the same parent. */
+ struct debug_block *next;
+ /* Parent block. */
+ struct debug_block *parent;
+ /* List of child blocks. */
+ struct debug_block *children;
+ /* Start address of the block. */
+ bfd_vma start;
+ /* End address of the block. */
+ bfd_vma end;
+ /* Local variables. */
+ struct debug_namespace *locals;
+};
+
+/* Line number information we keep for a compilation unit. FIXME:
+ This structure is easy to create, but can be very space
+ inefficient. */
+
+struct debug_lineno
+{
+ /* More line number information for this block. */
+ struct debug_lineno *next;
+ /* Source file. */
+ struct debug_file *file;
+ /* Line numbers, terminated by a -1 or the end of the array. */
+#define DEBUG_LINENO_COUNT 10
+ unsigned long linenos[DEBUG_LINENO_COUNT];
+ /* Addresses for the line numbers. */
+ bfd_vma addrs[DEBUG_LINENO_COUNT];
+};
+
+/* A namespace. This is a mapping from names to objects. FIXME: This
+ should be implemented as a hash table. */
+
+struct debug_namespace
+{
+ /* List of items in this namespace. */
+ struct debug_name *list;
+ /* Pointer to where the next item in this namespace should go. */
+ struct debug_name **tail;
+};
+
+/* Kinds of objects that appear in a namespace. */
+
+enum debug_object_kind
+{
+ /* A type. */
+ DEBUG_OBJECT_TYPE,
+ /* A tagged type (really a different sort of namespace). */
+ DEBUG_OBJECT_TAG,
+ /* A variable. */
+ DEBUG_OBJECT_VARIABLE,
+ /* A function. */
+ DEBUG_OBJECT_FUNCTION,
+ /* An integer constant. */
+ DEBUG_OBJECT_INT_CONSTANT,
+ /* A floating point constant. */
+ DEBUG_OBJECT_FLOAT_CONSTANT,
+ /* A typed constant. */
+ DEBUG_OBJECT_TYPED_CONSTANT
+};
+
+/* Linkage of an object that appears in a namespace. */
+
+enum debug_object_linkage
+{
+ /* Local variable. */
+ DEBUG_LINKAGE_AUTOMATIC,
+ /* Static--either file static or function static, depending upon the
+ namespace is. */
+ DEBUG_LINKAGE_STATIC,
+ /* Global. */
+ DEBUG_LINKAGE_GLOBAL,
+ /* No linkage. */
+ DEBUG_LINKAGE_NONE
+};
+
+/* A name in a namespace. */
+
+struct debug_name
+{
+ /* Next name in this namespace. */
+ struct debug_name *next;
+ /* Name. */
+ const char *name;
+ /* Mark. This is used by debug_write. */
+ unsigned int mark;
+ /* Kind of object. */
+ enum debug_object_kind kind;
+ /* Linkage of object. */
+ enum debug_object_linkage linkage;
+ /* Tagged union with additional information about the object. */
+ union
+ {
+ /* DEBUG_OBJECT_TYPE. */
+ struct debug_type *type;
+ /* DEBUG_OBJECT_TAG. */
+ struct debug_type *tag;
+ /* DEBUG_OBJECT_VARIABLE. */
+ struct debug_variable *variable;
+ /* DEBUG_OBJECT_FUNCTION. */
+ struct debug_function *function;
+ /* DEBUG_OBJECT_INT_CONSTANT. */
+ bfd_vma int_constant;
+ /* DEBUG_OBJECT_FLOAT_CONSTANT. */
+ double float_constant;
+ /* DEBUG_OBJECT_TYPED_CONSTANT. */
+ struct debug_typed_constant *typed_constant;
+ } u;
+};
+
+/* During debug_write, a linked list of these structures is used to
+ keep track of ID numbers that have been assigned to classes. */
+
+struct debug_class_id
+{
+ /* Next ID number. */
+ struct debug_class_id *next;
+ /* The type with the ID. */
+ struct debug_type *type;
+ /* The tag; NULL if no tag. */
+ const char *tag;
+};
+
+/* During debug_type_samep, a linked list of these structures is kept
+ on the stack to avoid infinite recursion. */
+
+struct debug_type_compare_list
+{
+ /* Next type on list. */
+ struct debug_type_compare_list *next;
+ /* The types we are comparing. */
+ struct debug_type *t1;
+ struct debug_type *t2;
+};
+
+/* Local functions. */
+
+static void debug_error PARAMS ((const char *));
+static struct debug_name *debug_add_to_namespace
+ PARAMS ((struct debug_handle *, struct debug_namespace **, const char *,
+ enum debug_object_kind, enum debug_object_linkage));
+static struct debug_name *debug_add_to_current_namespace
+ PARAMS ((struct debug_handle *, const char *, enum debug_object_kind,
+ enum debug_object_linkage));
+static struct debug_type *debug_make_type
+ PARAMS ((struct debug_handle *, enum debug_type_kind, unsigned int));
+static struct debug_type *debug_get_real_type PARAMS ((PTR, debug_type));
+static boolean debug_write_name
+ PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR,
+ struct debug_name *));
+static boolean debug_write_type
+ PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR,
+ struct debug_type *, struct debug_name *));
+static boolean debug_write_class_type
+ PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR,
+ struct debug_type *, const char *));
+static boolean debug_write_function
+ PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR,
+ const char *, enum debug_object_linkage, struct debug_function *));
+static boolean debug_write_block
+ PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR,
+ struct debug_block *));
+static boolean debug_write_linenos
+ PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR,
+ bfd_vma));
+static boolean debug_set_class_id
+ PARAMS ((struct debug_handle *, const char *, struct debug_type *));
+static boolean debug_type_samep
+ PARAMS ((struct debug_handle *, struct debug_type *, struct debug_type *));
+static boolean debug_class_type_samep
+ PARAMS ((struct debug_handle *, struct debug_type *, struct debug_type *));
+
+/* Issue an error message. */
+
+static void
+debug_error (message)
+ const char *message;
+{
+ fprintf (stderr, "%s\n", message);
+}
+
+/* Add an object to a namespace. */
+
+static struct debug_name *
+debug_add_to_namespace (info, nsp, name, kind, linkage)
+ struct debug_handle *info;
+ struct debug_namespace **nsp;
+ const char *name;
+ enum debug_object_kind kind;
+ enum debug_object_linkage linkage;
+{
+ struct debug_name *n;
+ struct debug_namespace *ns;
+
+ n = (struct debug_name *) xmalloc (sizeof *n);
+ memset (n, 0, sizeof *n);
+
+ n->name = name;
+ n->kind = kind;
+ n->linkage = linkage;
+
+ ns = *nsp;
+ if (ns == NULL)
+ {
+ ns = (struct debug_namespace *) xmalloc (sizeof *ns);
+ memset (ns, 0, sizeof *ns);
+
+ ns->tail = &ns->list;
+
+ *nsp = ns;
+ }
+
+ *ns->tail = n;
+ ns->tail = &n->next;
+
+ return n;
+}
+
+/* Add an object to the current namespace. */
+
+static struct debug_name *
+debug_add_to_current_namespace (info, name, kind, linkage)
+ struct debug_handle *info;
+ const char *name;
+ enum debug_object_kind kind;
+ enum debug_object_linkage linkage;
+{
+ struct debug_namespace **nsp;
+
+ if (info->current_unit == NULL
+ || info->current_file == NULL)
+ {
+ debug_error ("debug_add_to_current_namespace: no current file");
+ return NULL;
+ }
+
+ if (info->current_block != NULL)
+ nsp = &info->current_block->locals;
+ else
+ nsp = &info->current_file->globals;
+
+ return debug_add_to_namespace (info, nsp, name, kind, linkage);
+}
+
+/* Return a handle for debugging information. */
+
+PTR
+debug_init ()
+{
+ struct debug_handle *ret;
+
+ ret = (struct debug_handle *) xmalloc (sizeof *ret);
+ memset (ret, 0, sizeof *ret);
+ return (PTR) ret;
+}
+
+/* Set the source filename. This implicitly starts a new compilation
+ unit. */
+
+boolean
+debug_set_filename (handle, name)
+ PTR handle;
+ const char *name;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_file *nfile;
+ struct debug_unit *nunit;
+
+ if (name == NULL)
+ name = "";
+
+ nfile = (struct debug_file *) xmalloc (sizeof *nfile);
+ memset (nfile, 0, sizeof *nfile);
+
+ nfile->filename = name;
+
+ nunit = (struct debug_unit *) xmalloc (sizeof *nunit);
+ memset (nunit, 0, sizeof *nunit);
+
+ nunit->files = nfile;
+ info->current_file = nfile;
+
+ if (info->current_unit != NULL)
+ info->current_unit->next = nunit;
+ else
+ {
+ assert (info->units == NULL);
+ info->units = nunit;
+ }
+
+ info->current_unit = nunit;
+
+ info->current_function = NULL;
+ info->current_block = NULL;
+ info->current_lineno = NULL;
+
+ return true;
+}
+
+/* Change source files to the given file name. This is used for
+ include files in a single compilation unit. */
+
+boolean
+debug_start_source (handle, name)
+ PTR handle;
+ const char *name;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_file *f, **pf;
+
+ if (name == NULL)
+ name = "";
+
+ if (info->current_unit == NULL)
+ {
+ debug_error ("debug_start_source: no debug_set_filename call");
+ return false;
+ }
+
+ for (f = info->current_unit->files; f != NULL; f = f->next)
+ {
+ if (f->filename[0] == name[0]
+ && f->filename[1] == name[1]
+ && strcmp (f->filename, name) == 0)
+ {
+ info->current_file = f;
+ return true;
+ }
+ }
+
+ f = (struct debug_file *) xmalloc (sizeof *f);
+ memset (f, 0, sizeof *f);
+
+ f->filename = name;
+
+ for (pf = &info->current_file->next;
+ *pf != NULL;
+ pf = &(*pf)->next)
+ ;
+ *pf = f;
+
+ info->current_file = f;
+
+ return true;
+}
+
+/* Record a function definition. This implicitly starts a function
+ block. The debug_type argument is the type of the return value.
+ The boolean indicates whether the function is globally visible.
+ The bfd_vma is the address of the start of the function. Currently
+ the parameter types are specified by calls to
+ debug_record_parameter. FIXME: There is no way to specify nested
+ functions. */
+
+boolean
+debug_record_function (handle, name, return_type, global, addr)
+ PTR handle;
+ const char *name;
+ debug_type return_type;
+ boolean global;
+ bfd_vma addr;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_function *f;
+ struct debug_block *b;
+ struct debug_name *n;
+
+ if (name == NULL)
+ name = "";
+ if (return_type == NULL)
+ return false;
+
+ if (info->current_unit == NULL)
+ {
+ debug_error ("debug_record_function: no debug_set_filename call");
+ return false;
+ }
+
+ f = (struct debug_function *) xmalloc (sizeof *f);
+ memset (f, 0, sizeof *f);
+
+ f->return_type = return_type;
+
+ b = (struct debug_block *) xmalloc (sizeof *b);
+ memset (b, 0, sizeof *b);
+
+ b->start = addr;
+ b->end = (bfd_vma) -1;
+
+ f->blocks = b;
+
+ info->current_function = f;
+ info->current_block = b;
+
+ /* FIXME: If we could handle nested functions, this would be the
+ place: we would want to use a different namespace. */
+ n = debug_add_to_namespace (info,
+ &info->current_file->globals,
+ name,
+ DEBUG_OBJECT_FUNCTION,
+ (global
+ ? DEBUG_LINKAGE_GLOBAL
+ : DEBUG_LINKAGE_STATIC));
+ if (n == NULL)
+ return false;
+
+ n->u.function = f;
+
+ return true;
+}
+
+/* Record a parameter for the current function. */
+
+boolean
+debug_record_parameter (handle, name, type, kind, val)
+ PTR handle;
+ const char *name;
+ debug_type type;
+ enum debug_parm_kind kind;
+ bfd_vma val;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_parameter *p, **pp;
+
+ if (name == NULL || type == NULL)
+ return false;
+
+ if (info->current_unit == NULL
+ || info->current_function == NULL)
+ {
+ debug_error ("debug_record_parameter: no current function");
+ return false;
+ }
+
+ p = (struct debug_parameter *) xmalloc (sizeof *p);
+ memset (p, 0, sizeof *p);
+
+ p->name = name;
+ p->type = type;
+ p->kind = kind;
+ p->val = val;
+
+ for (pp = &info->current_function->parameters;
+ *pp != NULL;
+ pp = &(*pp)->next)
+ ;
+ *pp = p;
+
+ return true;
+}
+
+/* End a function. FIXME: This should handle function nesting. */
+
+boolean
+debug_end_function (handle, addr)
+ PTR handle;
+ bfd_vma addr;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+
+ if (info->current_unit == NULL
+ || info->current_block == NULL
+ || info->current_function == NULL)
+ {
+ debug_error ("debug_end_function: no current function");
+ return false;
+ }
+
+ if (info->current_block->parent != NULL)
+ {
+ debug_error ("debug_end_function: some blocks were not closed");
+ return false;
+ }
+
+ info->current_block->end = addr;
+
+ info->current_function = NULL;
+ info->current_block = NULL;
+
+ return true;
+}
+
+/* Start a block in a function. All local information will be
+ recorded in this block, until the matching call to debug_end_block.
+ debug_start_block and debug_end_block may be nested. The bfd_vma
+ argument is the address at which this block starts. */
+
+boolean
+debug_start_block (handle, addr)
+ PTR handle;
+ bfd_vma addr;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_block *b, **pb;
+
+ /* We must always have a current block: debug_record_function sets
+ one up. */
+ if (info->current_unit == NULL
+ || info->current_block == NULL)
+ {
+ debug_error ("debug_start_block: no current block");
+ return false;
+ }
+
+ b = (struct debug_block *) xmalloc (sizeof *b);
+ memset (b, 0, sizeof *b);
+
+ b->parent = info->current_block;
+ b->start = addr;
+ b->end = (bfd_vma) -1;
+
+ /* This new block is a child of the current block. */
+ for (pb = &info->current_block->children;
+ *pb != NULL;
+ pb = &(*pb)->next)
+ ;
+ *pb = b;
+
+ info->current_block = b;
+
+ return true;
+}
+
+/* Finish a block in a function. This matches the call to
+ debug_start_block. The argument is the address at which this block
+ ends. */
+
+boolean
+debug_end_block (handle, addr)
+ PTR handle;
+ bfd_vma addr;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_block *parent;
+
+ if (info->current_unit == NULL
+ || info->current_block == NULL)
+ {
+ debug_error ("debug_end_block: no current block");
+ return false;
+ }
+
+ parent = info->current_block->parent;
+ if (parent == NULL)
+ {
+ debug_error ("debug_end_block: attempt to close top level block");
+ return false;
+ }
+
+ info->current_block->end = addr;
+
+ info->current_block = parent;
+
+ return true;
+}
+
+/* Associate a line number in the current source file and function
+ with a given address. */
+
+boolean
+debug_record_line (handle, lineno, addr)
+ PTR handle;
+ unsigned long lineno;
+ bfd_vma addr;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_lineno *l;
+ unsigned int i;
+
+ if (info->current_unit == NULL)
+ {
+ debug_error ("debug_record_line: no current unit");
+ return false;
+ }
+
+ l = info->current_lineno;
+ if (l != NULL && l->file == info->current_file)
+ {
+ for (i = 0; i < DEBUG_LINENO_COUNT; i++)
+ {
+ if (l->linenos[i] == (unsigned long) -1)
+ {
+ l->linenos[i] = lineno;
+ l->addrs[i] = addr;
+ return true;
+ }
+ }
+ }
+
+ /* If we get here, then either 1) there is no current_lineno
+ structure, which means this is the first line number in this
+ compilation unit, 2) the current_lineno structure is for a
+ different file, or 3) the current_lineno structure is full.
+ Regardless, we want to allocate a new debug_lineno structure, put
+ it in the right place, and make it the new current_lineno
+ structure. */
+
+ l = (struct debug_lineno *) xmalloc (sizeof *l);
+ memset (l, 0, sizeof *l);
+
+ l->file = info->current_file;
+ l->linenos[0] = lineno;
+ l->addrs[0] = addr;
+ for (i = 1; i < DEBUG_LINENO_COUNT; i++)
+ l->linenos[i] = (unsigned long) -1;
+
+ if (info->current_lineno != NULL)
+ info->current_lineno->next = l;
+ else
+ info->current_unit->linenos = l;
+
+ info->current_lineno = l;
+
+ return true;
+}
+
+/* Start a named common block. This is a block of variables that may
+ move in memory. */
+
+boolean
+debug_start_common_block (handle, name)
+ PTR handle;
+ const char *name;
+{
+ /* FIXME */
+ debug_error ("debug_start_common_block: not implemented");
+ return false;
+}
+
+/* End a named common block. */
+
+boolean
+debug_end_common_block (handle, name)
+ PTR handle;
+ const char *name;
+{
+ /* FIXME */
+ debug_error ("debug_end_common_block: not implemented");
+ return false;
+}
+
+/* Record a named integer constant. */
+
+boolean
+debug_record_int_const (handle, name, val)
+ PTR handle;
+ const char *name;
+ bfd_vma val;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_name *n;
+
+ if (name == NULL)
+ return false;
+
+ n = debug_add_to_current_namespace (info, name, DEBUG_OBJECT_INT_CONSTANT,
+ DEBUG_LINKAGE_NONE);
+ if (n == NULL)
+ return false;
+
+ n->u.int_constant = val;
+
+ return true;
+}
+
+/* Record a named floating point constant. */
+
+boolean
+debug_record_float_const (handle, name, val)
+ PTR handle;
+ const char *name;
+ double val;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_name *n;
+
+ if (name == NULL)
+ return false;
+
+ n = debug_add_to_current_namespace (info, name, DEBUG_OBJECT_FLOAT_CONSTANT,
+ DEBUG_LINKAGE_NONE);
+ if (n == NULL)
+ return false;
+
+ n->u.float_constant = val;
+
+ return true;
+}
+
+/* Record a typed constant with an integral value. */
+
+boolean
+debug_record_typed_const (handle, name, type, val)
+ PTR handle;
+ const char *name;
+ debug_type type;
+ bfd_vma val;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_name *n;
+ struct debug_typed_constant *tc;
+
+ if (name == NULL || type == NULL)
+ return false;
+
+ n = debug_add_to_current_namespace (info, name, DEBUG_OBJECT_TYPED_CONSTANT,
+ DEBUG_LINKAGE_NONE);
+ if (n == NULL)
+ return false;
+
+ tc = (struct debug_typed_constant *) xmalloc (sizeof *tc);
+ memset (tc, 0, sizeof *tc);
+
+ tc->type = type;
+ tc->val = val;
+
+ n->u.typed_constant = tc;
+
+ return true;
+}
+
+/* Record a label. */
+
+boolean
+debug_record_label (handle, name, type, addr)
+ PTR handle;
+ const char *name;
+ debug_type type;
+ bfd_vma addr;
+{
+ /* FIXME. */
+ debug_error ("debug_record_label not implemented");
+ return false;
+}
+
+/* Record a variable. */
+
+boolean
+debug_record_variable (handle, name, type, kind, val)
+ PTR handle;
+ const char *name;
+ debug_type type;
+ enum debug_var_kind kind;
+ bfd_vma val;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_namespace **nsp;
+ enum debug_object_linkage linkage;
+ struct debug_name *n;
+ struct debug_variable *v;
+
+ if (name == NULL || type == NULL)
+ return false;
+
+ if (info->current_unit == NULL
+ || info->current_file == NULL)
+ {
+ debug_error ("debug_record_variable: no current file");
+ return false;
+ }
+
+ if (kind == DEBUG_GLOBAL || kind == DEBUG_STATIC)
+ {
+ nsp = &info->current_file->globals;
+ if (kind == DEBUG_GLOBAL)
+ linkage = DEBUG_LINKAGE_GLOBAL;
+ else
+ linkage = DEBUG_LINKAGE_STATIC;
+ }
+ else
+ {
+ if (info->current_block == NULL)
+ {
+ debug_error ("debug_record_variable: no current block");
+ return false;
+ }
+ nsp = &info->current_block->locals;
+ linkage = DEBUG_LINKAGE_AUTOMATIC;
+ }
+
+ n = debug_add_to_namespace (info, nsp, name, DEBUG_OBJECT_VARIABLE, linkage);
+ if (n == NULL)
+ return false;
+
+ v = (struct debug_variable *) xmalloc (sizeof *v);
+ memset (v, 0, sizeof *v);
+
+ v->kind = kind;
+ v->type = type;
+ v->val = val;
+
+ n->u.variable = v;
+
+ return true;
+}
+
+/* Make a type with a given kind and size. */
+
+/*ARGSUSED*/
+static struct debug_type *
+debug_make_type (info, kind, size)
+ struct debug_handle *info;
+ enum debug_type_kind kind;
+ unsigned int size;
+{
+ struct debug_type *t;
+
+ t = (struct debug_type *) xmalloc (sizeof *t);
+ memset (t, 0, sizeof *t);
+
+ t->kind = kind;
+ t->size = size;
+
+ return t;
+}
+
+/* Make an indirect type which may be used as a placeholder for a type
+ which is referenced before it is defined. */
+
+debug_type
+debug_make_indirect_type (handle, slot, tag)
+ PTR handle;
+ debug_type *slot;
+ const char *tag;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+ struct debug_indirect_type *i;
+
+ t = debug_make_type (info, DEBUG_KIND_INDIRECT, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ i = (struct debug_indirect_type *) xmalloc (sizeof *i);
+ memset (i, 0, sizeof *i);
+
+ i->slot = slot;
+ i->tag = tag;
+
+ t->u.kindirect = i;
+
+ return t;
+}
+
+/* Make a void type. There is only one of these. */
+
+debug_type
+debug_make_void_type (handle)
+ PTR handle;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+
+ return debug_make_type (info, DEBUG_KIND_VOID, 0);
+}
+
+/* Make an integer type of a given size. The boolean argument is true
+ if the integer is unsigned. */
+
+debug_type
+debug_make_int_type (handle, size, unsignedp)
+ PTR handle;
+ unsigned int size;
+ boolean unsignedp;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+
+ t = debug_make_type (info, DEBUG_KIND_INT, size);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t->u.kint = unsignedp;
+
+ return t;
+}
+
+/* Make a floating point type of a given size. FIXME: On some
+ platforms, like an Alpha, you probably need to be able to specify
+ the format. */
+
+debug_type
+debug_make_float_type (handle, size)
+ PTR handle;
+ unsigned int size;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+
+ return debug_make_type (info, DEBUG_KIND_FLOAT, size);
+}
+
+/* Make a boolean type of a given size. */
+
+debug_type
+debug_make_bool_type (handle, size)
+ PTR handle;
+ unsigned int size;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+
+ return debug_make_type (info, DEBUG_KIND_BOOL, size);
+}
+
+/* Make a complex type of a given size. */
+
+debug_type
+debug_make_complex_type (handle, size)
+ PTR handle;
+ unsigned int size;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+
+ return debug_make_type (info, DEBUG_KIND_COMPLEX, size);
+}
+
+/* Make a structure type. The second argument is true for a struct,
+ false for a union. The third argument is the size of the struct.
+ The fourth argument is a NULL terminated array of fields. */
+
+debug_type
+debug_make_struct_type (handle, structp, size, fields)
+ PTR handle;
+ boolean structp;
+ bfd_vma size;
+ debug_field *fields;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+ struct debug_class_type *c;
+
+ t = debug_make_type (info,
+ structp ? DEBUG_KIND_STRUCT : DEBUG_KIND_UNION,
+ size);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ c = (struct debug_class_type *) xmalloc (sizeof *c);
+ memset (c, 0, sizeof *c);
+
+ c->fields = fields;
+
+ t->u.kclass = c;
+
+ return t;
+}
+
+/* Make an object type. The first three arguments after the handle
+ are the same as for debug_make_struct_type. The next arguments are
+ a NULL terminated array of base classes, a NULL terminated array of
+ methods, the type of the object holding the virtual function table
+ if it is not this object, and a boolean which is true if this
+ object has its own virtual function table. */
+
+debug_type
+debug_make_object_type (handle, structp, size, fields, baseclasses,
+ methods, vptrbase, ownvptr)
+ PTR handle;
+ boolean structp;
+ bfd_vma size;
+ debug_field *fields;
+ debug_baseclass *baseclasses;
+ debug_method *methods;
+ debug_type vptrbase;
+ boolean ownvptr;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+ struct debug_class_type *c;
+
+ t = debug_make_type (info,
+ structp ? DEBUG_KIND_CLASS : DEBUG_KIND_UNION_CLASS,
+ size);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ c = (struct debug_class_type *) xmalloc (sizeof *c);
+ memset (c, 0, sizeof *c);
+
+ c->fields = fields;
+ c->baseclasses = baseclasses;
+ c->methods = methods;
+ if (ownvptr)
+ c->vptrbase = t;
+ else
+ c->vptrbase = vptrbase;
+
+ t->u.kclass = c;
+
+ return t;
+}
+
+/* Make an enumeration type. The arguments are a null terminated
+ array of strings, and an array of corresponding values. */
+
+debug_type
+debug_make_enum_type (handle, names, values)
+ PTR handle;
+ const char **names;
+ bfd_signed_vma *values;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+ struct debug_enum_type *e;
+
+ t = debug_make_type (info, DEBUG_KIND_ENUM, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ e = (struct debug_enum_type *) xmalloc (sizeof *e);
+ memset (e, 0, sizeof *e);
+
+ e->names = names;
+ e->values = values;
+
+ t->u.kenum = e;
+
+ return t;
+}
+
+/* Make a pointer to a given type. */
+
+debug_type
+debug_make_pointer_type (handle, type)
+ PTR handle;
+ debug_type type;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+
+ if (type == NULL)
+ return DEBUG_TYPE_NULL;
+
+ if (type->pointer != DEBUG_TYPE_NULL)
+ return type->pointer;
+
+ t = debug_make_type (info, DEBUG_KIND_POINTER, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t->u.kpointer = type;
+
+ type->pointer = t;
+
+ return t;
+}
+
+/* Make a function returning a given type. FIXME: We should be able
+ to record the parameter types. */
+
+debug_type
+debug_make_function_type (handle, type, arg_types, varargs)
+ PTR handle;
+ debug_type type;
+ debug_type *arg_types;
+ boolean varargs;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+ struct debug_function_type *f;
+
+ if (type == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t = debug_make_type (info, DEBUG_KIND_FUNCTION, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ f = (struct debug_function_type *) xmalloc (sizeof *f);
+ memset (f, 0, sizeof *f);
+
+ f->return_type = type;
+ f->arg_types = arg_types;
+ f->varargs = varargs;
+
+ t->u.kfunction = f;
+
+ return t;
+}
+
+/* Make a reference to a given type. */
+
+debug_type
+debug_make_reference_type (handle, type)
+ PTR handle;
+ debug_type type;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+
+ if (type == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t = debug_make_type (info, DEBUG_KIND_REFERENCE, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t->u.kreference = type;
+
+ return t;
+}
+
+/* Make a range of a given type from a lower to an upper bound. */
+
+debug_type
+debug_make_range_type (handle, type, lower, upper)
+ PTR handle;
+ debug_type type;
+ bfd_signed_vma lower;
+ bfd_signed_vma upper;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+ struct debug_range_type *r;
+
+ if (type == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t = debug_make_type (info, DEBUG_KIND_RANGE, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ r = (struct debug_range_type *) xmalloc (sizeof *r);
+ memset (r, 0, sizeof *r);
+
+ r->type = type;
+ r->lower = lower;
+ r->upper = upper;
+
+ t->u.krange = r;
+
+ return t;
+}
+
+/* Make an array type. The second argument is the type of an element
+ of the array. The third argument is the type of a range of the
+ array. The fourth and fifth argument are the lower and upper
+ bounds, respectively. The sixth argument is true if this array is
+ actually a string, as in C. */
+
+debug_type
+debug_make_array_type (handle, element_type, range_type, lower, upper,
+ stringp)
+ PTR handle;
+ debug_type element_type;
+ debug_type range_type;
+ bfd_signed_vma lower;
+ bfd_signed_vma upper;
+ boolean stringp;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+ struct debug_array_type *a;
+
+ if (element_type == NULL || range_type == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t = debug_make_type (info, DEBUG_KIND_ARRAY, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ a = (struct debug_array_type *) xmalloc (sizeof *a);
+ memset (a, 0, sizeof *a);
+
+ a->element_type = element_type;
+ a->range_type = range_type;
+ a->lower = lower;
+ a->upper = upper;
+ a->stringp = stringp;
+
+ t->u.karray = a;
+
+ return t;
+}
+
+/* Make a set of a given type. For example, a Pascal set type. The
+ boolean argument is true if this set is actually a bitstring, as in
+ CHILL. */
+
+debug_type
+debug_make_set_type (handle, type, bitstringp)
+ PTR handle;
+ debug_type type;
+ boolean bitstringp;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+ struct debug_set_type *s;
+
+ if (type == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t = debug_make_type (info, DEBUG_KIND_SET, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ s = (struct debug_set_type *) xmalloc (sizeof *s);
+ memset (s, 0, sizeof *s);
+
+ s->type = type;
+ s->bitstringp = bitstringp;
+
+ t->u.kset = s;
+
+ return t;
+}
+
+/* Make a type for a pointer which is relative to an object. The
+ second argument is the type of the object to which the pointer is
+ relative. The third argument is the type that the pointer points
+ to. */
+
+debug_type
+debug_make_offset_type (handle, base_type, target_type)
+ PTR handle;
+ debug_type base_type;
+ debug_type target_type;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+ struct debug_offset_type *o;
+
+ if (base_type == NULL || target_type == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t = debug_make_type (info, DEBUG_KIND_OFFSET, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ o = (struct debug_offset_type *) xmalloc (sizeof *o);
+ memset (o, 0, sizeof *o);
+
+ o->base_type = base_type;
+ o->target_type = target_type;
+
+ t->u.koffset = o;
+
+ return t;
+}
+
+/* Make a type for a method function. The second argument is the
+ return type, the third argument is the domain, and the fourth
+ argument is a NULL terminated array of argument types. */
+
+debug_type
+debug_make_method_type (handle, return_type, domain_type, arg_types, varargs)
+ PTR handle;
+ debug_type return_type;
+ debug_type domain_type;
+ debug_type *arg_types;
+ boolean varargs;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+ struct debug_method_type *m;
+
+ if (return_type == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t = debug_make_type (info, DEBUG_KIND_METHOD, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ m = (struct debug_method_type *) xmalloc (sizeof *m);
+ memset (m, 0, sizeof *m);
+
+ m->return_type = return_type;
+ m->domain_type = domain_type;
+ m->arg_types = arg_types;
+ m->varargs = varargs;
+
+ t->u.kmethod = m;
+
+ return t;
+}
+
+/* Make a const qualified version of a given type. */
+
+debug_type
+debug_make_const_type (handle, type)
+ PTR handle;
+ debug_type type;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+
+ if (type == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t = debug_make_type (info, DEBUG_KIND_CONST, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t->u.kconst = type;
+
+ return t;
+}
+
+/* Make a volatile qualified version of a given type. */
+
+debug_type
+debug_make_volatile_type (handle, type)
+ PTR handle;
+ debug_type type;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+
+ if (type == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t = debug_make_type (info, DEBUG_KIND_VOLATILE, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t->u.kvolatile = type;
+
+ return t;
+}
+
+/* Make an undefined tagged type. For example, a struct which has
+ been mentioned, but not defined. */
+
+debug_type
+debug_make_undefined_tagged_type (handle, name, kind)
+ PTR handle;
+ const char *name;
+ enum debug_type_kind kind;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+
+ if (name == NULL)
+ return DEBUG_TYPE_NULL;
+
+ switch (kind)
+ {
+ case DEBUG_KIND_STRUCT:
+ case DEBUG_KIND_UNION:
+ case DEBUG_KIND_CLASS:
+ case DEBUG_KIND_UNION_CLASS:
+ case DEBUG_KIND_ENUM:
+ break;
+
+ default:
+ debug_error ("debug_make_undefined_type: unsupported kind");
+ return DEBUG_TYPE_NULL;
+ }
+
+ t = debug_make_type (info, kind, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ return debug_tag_type (handle, name, t);
+}
+
+/* Make a base class for an object. The second argument is the base
+ class type. The third argument is the bit position of this base
+ class in the object (always 0 unless doing multiple inheritance).
+ The fourth argument is whether this is a virtual class. The fifth
+ argument is the visibility of the base class. */
+
+/*ARGSUSED*/
+debug_baseclass
+debug_make_baseclass (handle, type, bitpos, virtual, visibility)
+ PTR handle;
+ debug_type type;
+ bfd_vma bitpos;
+ boolean virtual;
+ enum debug_visibility visibility;
+{
+ struct debug_baseclass *b;
+
+ b = (struct debug_baseclass *) xmalloc (sizeof *b);
+ memset (b, 0, sizeof *b);
+
+ b->type = type;
+ b->bitpos = bitpos;
+ b->virtual = virtual;
+ b->visibility = visibility;
+
+ return b;
+}
+
+/* Make a field for a struct. The second argument is the name. The
+ third argument is the type of the field. The fourth argument is
+ the bit position of the field. The fifth argument is the size of
+ the field (it may be zero). The sixth argument is the visibility
+ of the field. */
+
+/*ARGSUSED*/
+debug_field
+debug_make_field (handle, name, type, bitpos, bitsize, visibility)
+ PTR handle;
+ const char *name;
+ debug_type type;
+ bfd_vma bitpos;
+ bfd_vma bitsize;
+ enum debug_visibility visibility;
+{
+ struct debug_field *f;
+
+ f = (struct debug_field *) xmalloc (sizeof *f);
+ memset (f, 0, sizeof *f);
+
+ f->name = name;
+ f->type = type;
+ f->static_member = false;
+ f->u.f.bitpos = bitpos;
+ f->u.f.bitsize = bitsize;
+ f->visibility = visibility;
+
+ return f;
+}
+
+/* Make a static member of an object. The second argument is the
+ name. The third argument is the type of the member. The fourth
+ argument is the physical name of the member (i.e., the name as a
+ global variable). The fifth argument is the visibility of the
+ member. */
+
+/*ARGSUSED*/
+debug_field
+debug_make_static_member (handle, name, type, physname, visibility)
+ PTR handle;
+ const char *name;
+ debug_type type;
+ const char *physname;
+ enum debug_visibility visibility;
+{
+ struct debug_field *f;
+
+ f = (struct debug_field *) xmalloc (sizeof *f);
+ memset (f, 0, sizeof *f);
+
+ f->name = name;
+ f->type = type;
+ f->static_member = true;
+ f->u.s.physname = physname;
+ f->visibility = visibility;
+
+ return f;
+}
+
+/* Make a method. The second argument is the name, and the third
+ argument is a NULL terminated array of method variants. */
+
+/*ARGSUSED*/
+debug_method
+debug_make_method (handle, name, variants)
+ PTR handle;
+ const char *name;
+ debug_method_variant *variants;
+{
+ struct debug_method *m;
+
+ m = (struct debug_method *) xmalloc (sizeof *m);
+ memset (m, 0, sizeof *m);
+
+ m->name = name;
+ m->variants = variants;
+
+ return m;
+}
+
+/* Make a method argument. The second argument is the real name of
+ the function. The third argument is the type of the function. The
+ fourth argument is the visibility. The fifth argument is whether
+ this is a const function. The sixth argument is whether this is a
+ volatile function. The seventh argument is the offset in the
+ virtual function table, if any. The eighth argument is the virtual
+ function context. FIXME: Are the const and volatile arguments
+ necessary? Could we just use debug_make_const_type? */
+
+/*ARGSUSED*/
+debug_method_variant
+debug_make_method_variant (handle, physname, type, visibility, constp,
+ volatilep, voffset, context)
+ PTR handle;
+ const char *physname;
+ debug_type type;
+ enum debug_visibility visibility;
+ boolean constp;
+ boolean volatilep;
+ bfd_vma voffset;
+ debug_type context;
+{
+ struct debug_method_variant *m;
+
+ m = (struct debug_method_variant *) xmalloc (sizeof *m);
+ memset (m, 0, sizeof *m);
+
+ m->physname = physname;
+ m->type = type;
+ m->visibility = visibility;
+ m->constp = constp;
+ m->volatilep = volatilep;
+ m->voffset = voffset;
+ m->context = context;
+
+ return m;
+}
+
+/* Make a static method argument. The arguments are the same as for
+ debug_make_method_variant, except that the last two are omitted
+ since a static method can not also be virtual. */
+
+debug_method_variant
+debug_make_static_method_variant (handle, physname, type, visibility,
+ constp, volatilep)
+ PTR handle;
+ const char *physname;
+ debug_type type;
+ enum debug_visibility visibility;
+ boolean constp;
+ boolean volatilep;
+{
+ struct debug_method_variant *m;
+
+ m = (struct debug_method_variant *) xmalloc (sizeof *m);
+ memset (m, 0, sizeof *m);
+
+ m->physname = physname;
+ m->type = type;
+ m->visibility = visibility;
+ m->constp = constp;
+ m->volatilep = volatilep;
+ m->voffset = VOFFSET_STATIC_METHOD;
+
+ return m;
+}
+
+/* Name a type. */
+
+debug_type
+debug_name_type (handle, name, type)
+ PTR handle;
+ const char *name;
+ debug_type type;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+ struct debug_named_type *n;
+ struct debug_name *nm;
+
+ if (name == NULL || type == NULL)
+ return DEBUG_TYPE_NULL;
+
+ if (info->current_unit == NULL
+ || info->current_file == NULL)
+ {
+ debug_error ("debug_name_type: no current file");
+ return DEBUG_TYPE_NULL;
+ /* return false; */
+ }
+
+ t = debug_make_type (info, DEBUG_KIND_NAMED, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ n = (struct debug_named_type *) xmalloc (sizeof *n);
+ memset (n, 0, sizeof *n);
+
+ n->type = type;
+
+ t->u.knamed = n;
+
+ /* We always add the name to the global namespace. This is probably
+ wrong in some cases, but it seems to be right for stabs. FIXME. */
+
+ nm = debug_add_to_namespace (info, &info->current_file->globals, name,
+ DEBUG_OBJECT_TYPE, DEBUG_LINKAGE_NONE);
+ if (nm == NULL)
+ return DEBUG_TYPE_NULL;
+
+ nm->u.type = t;
+
+ n->name = nm;
+
+ return t;
+}
+
+/* Tag a type. */
+
+debug_type
+debug_tag_type (handle, name, type)
+ PTR handle;
+ const char *name;
+ debug_type type;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+ struct debug_named_type *n;
+ struct debug_name *nm;
+
+ if (name == NULL || type == NULL)
+ return DEBUG_TYPE_NULL;
+
+ if (info->current_file == NULL)
+ {
+ debug_error ("debug_tag_type: no current file");
+ return DEBUG_TYPE_NULL;
+ }
+
+ if (type->kind == DEBUG_KIND_TAGGED)
+ {
+ if (strcmp (type->u.knamed->name->name, name) == 0)
+ return type;
+ debug_error ("debug_tag_type: extra tag attempted");
+ return DEBUG_TYPE_NULL;
+ }
+
+ t = debug_make_type (info, DEBUG_KIND_TAGGED, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ n = (struct debug_named_type *) xmalloc (sizeof *n);
+ memset (n, 0, sizeof *n);
+
+ n->type = type;
+
+ t->u.knamed = n;
+
+ /* We keep a global namespace of tags for each compilation unit. I
+ don't know if that is the right thing to do. */
+
+ nm = debug_add_to_namespace (info, &info->current_file->globals, name,
+ DEBUG_OBJECT_TAG, DEBUG_LINKAGE_NONE);
+ if (nm == NULL)
+ return DEBUG_TYPE_NULL;
+
+ nm->u.tag = t;
+
+ n->name = nm;
+
+ return t;
+}
+
+/* Record the size of a given type. */
+
+/*ARGSUSED*/
+boolean
+debug_record_type_size (handle, type, size)
+ PTR handle;
+ debug_type type;
+ unsigned int size;
+{
+#if 0
+ if (type->size != 0 && type->size != size)
+ fprintf (stderr, "Warning: changing type size from %d to %d\n",
+ type->size, size);
+#endif
+
+ type->size = size;
+
+ return true;
+}
+
+/* Find a named type. */
+
+debug_type
+debug_find_named_type (handle, name)
+ PTR handle;
+ const char *name;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_block *b;
+ struct debug_file *f;
+
+ /* We only search the current compilation unit. I don't know if
+ this is right or not. */
+
+ if (info->current_unit == NULL)
+ {
+ debug_error ("debug_find_named_type: no current compilation unit");
+ return DEBUG_TYPE_NULL;
+ }
+
+ for (b = info->current_block; b != NULL; b = b->parent)
+ {
+ if (b->locals != NULL)
+ {
+ struct debug_name *n;
+
+ for (n = b->locals->list; n != NULL; n = n->next)
+ {
+ if (n->kind == DEBUG_OBJECT_TYPE
+ && n->name[0] == name[0]
+ && strcmp (n->name, name) == 0)
+ return n->u.type;
+ }
+ }
+ }
+
+ for (f = info->current_unit->files; f != NULL; f = f->next)
+ {
+ if (f->globals != NULL)
+ {
+ struct debug_name *n;
+
+ for (n = f->globals->list; n != NULL; n = n->next)
+ {
+ if (n->kind == DEBUG_OBJECT_TYPE
+ && n->name[0] == name[0]
+ && strcmp (n->name, name) == 0)
+ return n->u.type;
+ }
+ }
+ }
+
+ return DEBUG_TYPE_NULL;
+}
+
+/* Find a tagged type. */
+
+debug_type
+debug_find_tagged_type (handle, name, kind)
+ PTR handle;
+ const char *name;
+ enum debug_type_kind kind;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_unit *u;
+
+ /* We search the globals of all the compilation units. I don't know
+ if this is correct or not. It would be easy to change. */
+
+ for (u = info->units; u != NULL; u = u->next)
+ {
+ struct debug_file *f;
+
+ for (f = u->files; f != NULL; f = f->next)
+ {
+ struct debug_name *n;
+
+ if (f->globals != NULL)
+ {
+ for (n = f->globals->list; n != NULL; n = n->next)
+ {
+ if (n->kind == DEBUG_OBJECT_TAG
+ && (kind == DEBUG_KIND_ILLEGAL
+ || n->u.tag->kind == kind)
+ && n->name[0] == name[0]
+ && strcmp (n->name, name) == 0)
+ return n->u.tag;
+ }
+ }
+ }
+ }
+
+ return DEBUG_TYPE_NULL;
+}
+
+/* Get a base type. */
+
+static struct debug_type *
+debug_get_real_type (handle, type)
+ PTR handle;
+ debug_type type;
+{
+ switch (type->kind)
+ {
+ default:
+ return type;
+ case DEBUG_KIND_INDIRECT:
+ if (*type->u.kindirect->slot != NULL)
+ return debug_get_real_type (handle, *type->u.kindirect->slot);
+ return type;
+ case DEBUG_KIND_NAMED:
+ case DEBUG_KIND_TAGGED:
+ return debug_get_real_type (handle, type->u.knamed->type);
+ }
+ /*NOTREACHED*/
+}
+
+/* Get the kind of a type. */
+
+enum debug_type_kind
+debug_get_type_kind (handle, type)
+ PTR handle;
+ debug_type type;
+{
+ if (type == NULL)
+ return DEBUG_KIND_ILLEGAL;
+ type = debug_get_real_type (handle, type);
+ return type->kind;
+}
+
+/* Get the name of a type. */
+
+const char *
+debug_get_type_name (handle, type)
+ PTR handle;
+ debug_type type;
+{
+ if (type->kind == DEBUG_KIND_INDIRECT)
+ {
+ if (*type->u.kindirect->slot != NULL)
+ return debug_get_type_name (handle, *type->u.kindirect->slot);
+ return type->u.kindirect->tag;
+ }
+ if (type->kind == DEBUG_KIND_NAMED
+ || type->kind == DEBUG_KIND_TAGGED)
+ return type->u.knamed->name->name;
+ return NULL;
+}
+
+/* Get the size of a type. */
+
+bfd_vma
+debug_get_type_size (handle, type)
+ PTR handle;
+ debug_type type;
+{
+ if (type == NULL)
+ return 0;
+
+ /* We don't call debug_get_real_type, because somebody might have
+ called debug_record_type_size on a named or indirect type. */
+
+ if (type->size != 0)
+ return type->size;
+
+ switch (type->kind)
+ {
+ default:
+ return 0;
+ case DEBUG_KIND_INDIRECT:
+ if (*type->u.kindirect->slot != NULL)
+ return debug_get_type_size (handle, *type->u.kindirect->slot);
+ return 0;
+ case DEBUG_KIND_NAMED:
+ case DEBUG_KIND_TAGGED:
+ return debug_get_type_size (handle, type->u.knamed->type);
+ }
+ /*NOTREACHED*/
+}
+
+/* Get the return type of a function or method type. */
+
+debug_type
+debug_get_return_type (handle, type)
+ PTR handle;
+ debug_type type;
+{
+ if (type == NULL)
+ return DEBUG_TYPE_NULL;
+ type = debug_get_real_type (handle, type);
+ switch (type->kind)
+ {
+ default:
+ return DEBUG_TYPE_NULL;
+ case DEBUG_KIND_FUNCTION:
+ return type->u.kfunction->return_type;
+ case DEBUG_KIND_METHOD:
+ return type->u.kmethod->return_type;
+ }
+ /*NOTREACHED*/
+}
+
+/* Get the parameter types of a function or method type (except that
+ we don't currently store the parameter types of a function). */
+
+const debug_type *
+debug_get_parameter_types (handle, type, pvarargs)
+ PTR handle;
+ debug_type type;
+ boolean *pvarargs;
+{
+ if (type == NULL)
+ return NULL;
+ type = debug_get_real_type (handle, type);
+ switch (type->kind)
+ {
+ default:
+ return NULL;
+ case DEBUG_KIND_FUNCTION:
+ *pvarargs = type->u.kfunction->varargs;
+ return type->u.kfunction->arg_types;
+ case DEBUG_KIND_METHOD:
+ *pvarargs = type->u.kmethod->varargs;
+ return type->u.kmethod->arg_types;
+ }
+ /*NOTREACHED*/
+}
+
+/* Get the target type of a type. */
+
+debug_type
+debug_get_target_type (handle, type)
+ PTR handle;
+ debug_type type;
+{
+ if (type == NULL)
+ return NULL;
+ type = debug_get_real_type (handle, type);
+ switch (type->kind)
+ {
+ default:
+ return NULL;
+ case DEBUG_KIND_POINTER:
+ return type->u.kpointer;
+ case DEBUG_KIND_REFERENCE:
+ return type->u.kreference;
+ case DEBUG_KIND_CONST:
+ return type->u.kconst;
+ case DEBUG_KIND_VOLATILE:
+ return type->u.kvolatile;
+ }
+ /*NOTREACHED*/
+}
+
+/* Get the NULL terminated array of fields for a struct, union, or
+ class. */
+
+const debug_field *
+debug_get_fields (handle, type)
+ PTR handle;
+ debug_type type;
+{
+ if (type == NULL)
+ return NULL;
+ type = debug_get_real_type (handle, type);
+ switch (type->kind)
+ {
+ default:
+ return NULL;
+ case DEBUG_KIND_STRUCT:
+ case DEBUG_KIND_UNION:
+ case DEBUG_KIND_CLASS:
+ case DEBUG_KIND_UNION_CLASS:
+ return type->u.kclass->fields;
+ }
+ /*NOTREACHED*/
+}
+
+/* Get the type of a field. */
+
+/*ARGSUSED*/
+debug_type
+debug_get_field_type (handle, field)
+ PTR handle;
+ debug_field field;
+{
+ if (field == NULL)
+ return NULL;
+ return field->type;
+}
+
+/* Get the name of a field. */
+
+/*ARGSUSED*/
+const char *
+debug_get_field_name (handle, field)
+ PTR handle;
+ debug_field field;
+{
+ if (field == NULL)
+ return NULL;
+ return field->name;
+}
+
+/* Get the bit position of a field. */
+
+/*ARGSUSED*/
+bfd_vma
+debug_get_field_bitpos (handle, field)
+ PTR handle;
+ debug_field field;
+{
+ if (field == NULL || field->static_member)
+ return (bfd_vma) -1;
+ return field->u.f.bitpos;
+}
+
+/* Get the bit size of a field. */
+
+/*ARGSUSED*/
+bfd_vma
+debug_get_field_bitsize (handle, field)
+ PTR handle;
+ debug_field field;
+{
+ if (field == NULL || field->static_member)
+ return (bfd_vma) -1;
+ return field->u.f.bitsize;
+}
+
+/* Get the visibility of a field. */
+
+/*ARGSUSED*/
+enum debug_visibility
+debug_get_field_visibility (handle, field)
+ PTR handle;
+ debug_field field;
+{
+ if (field == NULL)
+ return DEBUG_VISIBILITY_IGNORE;
+ return field->visibility;
+}
+
+/* Get the physical name of a field. */
+
+const char *
+debug_get_field_physname (handle, field)
+ PTR handle;
+ debug_field field;
+{
+ if (field == NULL || ! field->static_member)
+ return NULL;
+ return field->u.s.physname;
+}
+
+/* Write out the debugging information. This is given a handle to
+ debugging information, and a set of function pointers to call. */
+
+boolean
+debug_write (handle, fns, fhandle)
+ PTR handle;
+ const struct debug_write_fns *fns;
+ PTR fhandle;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_unit *u;
+
+ /* We use a mark to tell whether we have already written out a
+ particular name. We use an integer, so that we don't have to
+ clear the mark fields if we happen to write out the same
+ information more than once. */
+ ++info->mark;
+
+ /* The base_id field holds an ID value which will never be used, so
+ that we can tell whether we have assigned an ID during this call
+ to debug_write. */
+ info->base_id = info->class_id;
+
+ /* We keep a linked list of classes for which was have assigned ID's
+ during this call to debug_write. */
+ info->id_list = NULL;
+
+ for (u = info->units; u != NULL; u = u->next)
+ {
+ struct debug_file *f;
+ boolean first_file;
+
+ info->current_write_lineno = u->linenos;
+ info->current_write_lineno_index = 0;
+
+ if (! (*fns->start_compilation_unit) (fhandle, u->files->filename))
+ return false;
+
+ first_file = true;
+ for (f = u->files; f != NULL; f = f->next)
+ {
+ struct debug_name *n;
+
+ if (first_file)
+ first_file = false;
+ else
+ {
+ if (! (*fns->start_source) (fhandle, f->filename))
+ return false;
+ }
+
+ if (f->globals != NULL)
+ {
+ for (n = f->globals->list; n != NULL; n = n->next)
+ {
+ if (! debug_write_name (info, fns, fhandle, n))
+ return false;
+ }
+ }
+ }
+
+ /* Output any line number information which hasn't already been
+ handled. */
+ if (! debug_write_linenos (info, fns, fhandle, (bfd_vma) -1))
+ return false;
+ }
+
+ return true;
+}
+
+/* Write out an element in a namespace. */
+
+static boolean
+debug_write_name (info, fns, fhandle, n)
+ struct debug_handle *info;
+ const struct debug_write_fns *fns;
+ PTR fhandle;
+ struct debug_name *n;
+{
+ switch (n->kind)
+ {
+ case DEBUG_OBJECT_TYPE:
+ if (! debug_write_type (info, fns, fhandle, n->u.type, n)
+ || ! (*fns->typdef) (fhandle, n->name))
+ return false;
+ return true;
+ case DEBUG_OBJECT_TAG:
+ if (! debug_write_type (info, fns, fhandle, n->u.tag, n))
+ return false;
+ return (*fns->tag) (fhandle, n->name);
+ case DEBUG_OBJECT_VARIABLE:
+ if (! debug_write_type (info, fns, fhandle, n->u.variable->type,
+ (struct debug_name *) NULL))
+ return false;
+ return (*fns->variable) (fhandle, n->name, n->u.variable->kind,
+ n->u.variable->val);
+ case DEBUG_OBJECT_FUNCTION:
+ return debug_write_function (info, fns, fhandle, n->name,
+ n->linkage, n->u.function);
+ case DEBUG_OBJECT_INT_CONSTANT:
+ return (*fns->int_constant) (fhandle, n->name, n->u.int_constant);
+ case DEBUG_OBJECT_FLOAT_CONSTANT:
+ return (*fns->float_constant) (fhandle, n->name, n->u.float_constant);
+ case DEBUG_OBJECT_TYPED_CONSTANT:
+ if (! debug_write_type (info, fns, fhandle, n->u.typed_constant->type,
+ (struct debug_name *) NULL))
+ return false;
+ return (*fns->typed_constant) (fhandle, n->name,
+ n->u.typed_constant->val);
+ default:
+ abort ();
+ return false;
+ }
+ /*NOTREACHED*/
+}
+
+/* Write out a type. If the type is DEBUG_KIND_NAMED or
+ DEBUG_KIND_TAGGED, then the name argument is the name for which we
+ are about to call typedef or tag. If the type is anything else,
+ then the name argument is a tag from a DEBUG_KIND_TAGGED type which
+ points to this one. */
+
+static boolean
+debug_write_type (info, fns, fhandle, type, name)
+ struct debug_handle *info;
+ const struct debug_write_fns *fns;
+ PTR fhandle;
+ struct debug_type *type;
+ struct debug_name *name;
+{
+ unsigned int i;
+ int is;
+ const char *tag;
+
+ /* If we have a name for this type, just output it. We only output
+ typedef names after they have been defined. We output type tags
+ whenever we are not actually defining them. */
+ if ((type->kind == DEBUG_KIND_NAMED
+ || type->kind == DEBUG_KIND_TAGGED)
+ && (type->u.knamed->name->mark == info->mark
+ || (type->kind == DEBUG_KIND_TAGGED
+ && type->u.knamed->name != name)))
+ {
+ if (type->kind == DEBUG_KIND_NAMED)
+ return (*fns->typedef_type) (fhandle, type->u.knamed->name->name);
+ else
+ {
+ struct debug_type *real;
+ unsigned int id;
+
+ real = debug_get_real_type ((PTR) info, type);
+ id = 0;
+ if ((real->kind == DEBUG_KIND_STRUCT
+ || real->kind == DEBUG_KIND_UNION
+ || real->kind == DEBUG_KIND_CLASS
+ || real->kind == DEBUG_KIND_UNION_CLASS)
+ && real->u.kclass != NULL)
+ {
+ if (real->u.kclass->id <= info->base_id)
+ {
+ if (! debug_set_class_id (info,
+ type->u.knamed->name->name,
+ real))
+ return false;
+ }
+ id = real->u.kclass->id;
+ }
+
+ return (*fns->tag_type) (fhandle, type->u.knamed->name->name, id,
+ real->kind);
+ }
+ }
+
+ /* Mark the name after we have already looked for a known name, so
+ that we don't just define a type in terms of itself. We need to
+ mark the name here so that a struct containing a pointer to
+ itself will work. */
+ if (name != NULL)
+ name->mark = info->mark;
+
+ tag = NULL;
+ if (name != NULL
+ && type->kind != DEBUG_KIND_NAMED
+ && type->kind != DEBUG_KIND_TAGGED)
+ {
+ assert (name->kind == DEBUG_OBJECT_TAG);
+ tag = name->name;
+ }
+
+ switch (type->kind)
+ {
+ case DEBUG_KIND_ILLEGAL:
+ debug_error ("debug_write_type: illegal type encountered");
+ return false;
+ case DEBUG_KIND_INDIRECT:
+ if (*type->u.kindirect->slot == DEBUG_TYPE_NULL)
+ return (*fns->empty_type) (fhandle);
+ return debug_write_type (info, fns, fhandle, *type->u.kindirect->slot,
+ name);
+ case DEBUG_KIND_VOID:
+ return (*fns->void_type) (fhandle);
+ case DEBUG_KIND_INT:
+ return (*fns->int_type) (fhandle, type->size, type->u.kint);
+ case DEBUG_KIND_FLOAT:
+ return (*fns->float_type) (fhandle, type->size);
+ case DEBUG_KIND_COMPLEX:
+ return (*fns->complex_type) (fhandle, type->size);
+ case DEBUG_KIND_BOOL:
+ return (*fns->bool_type) (fhandle, type->size);
+ case DEBUG_KIND_STRUCT:
+ case DEBUG_KIND_UNION:
+ if (type->u.kclass != NULL)
+ {
+ if (type->u.kclass->id <= info->base_id)
+ {
+ if (! debug_set_class_id (info, tag, type))
+ return false;
+ }
+
+ if (info->mark == type->u.kclass->mark)
+ {
+ /* We are currently outputting this struct, or we have
+ already output it. I don't know if this can happen,
+ but it can happen for a class. */
+ assert (type->u.kclass->id > info->base_id);
+ return (*fns->tag_type) (fhandle, tag, type->u.kclass->id,
+ type->kind);
+ }
+ type->u.kclass->mark = info->mark;
+ }
+
+ if (! (*fns->start_struct_type) (fhandle, tag,
+ (type->u.kclass != NULL
+ ? type->u.kclass->id
+ : 0),
+ type->kind == DEBUG_KIND_STRUCT,
+ type->size))
+ return false;
+ if (type->u.kclass != NULL
+ && type->u.kclass->fields != NULL)
+ {
+ for (i = 0; type->u.kclass->fields[i] != NULL; i++)
+ {
+ struct debug_field *f;
+
+ f = type->u.kclass->fields[i];
+ if (! debug_write_type (info, fns, fhandle, f->type,
+ (struct debug_name *) NULL)
+ || ! (*fns->struct_field) (fhandle, f->name, f->u.f.bitpos,
+ f->u.f.bitsize, f->visibility))
+ return false;
+ }
+ }
+ return (*fns->end_struct_type) (fhandle);
+ case DEBUG_KIND_CLASS:
+ case DEBUG_KIND_UNION_CLASS:
+ return debug_write_class_type (info, fns, fhandle, type, tag);
+ case DEBUG_KIND_ENUM:
+ if (type->u.kenum == NULL)
+ return (*fns->enum_type) (fhandle, tag, (const char **) NULL,
+ (bfd_signed_vma *) NULL);
+ return (*fns->enum_type) (fhandle, tag, type->u.kenum->names,
+ type->u.kenum->values);
+ case DEBUG_KIND_POINTER:
+ if (! debug_write_type (info, fns, fhandle, type->u.kpointer,
+ (struct debug_name *) NULL))
+ return false;
+ return (*fns->pointer_type) (fhandle);
+ case DEBUG_KIND_FUNCTION:
+ if (! debug_write_type (info, fns, fhandle,
+ type->u.kfunction->return_type,
+ (struct debug_name *) NULL))
+ return false;
+ if (type->u.kfunction->arg_types == NULL)
+ is = -1;
+ else
+ {
+ for (is = 0; type->u.kfunction->arg_types[is] != NULL; is++)
+ if (! debug_write_type (info, fns, fhandle,
+ type->u.kfunction->arg_types[is],
+ (struct debug_name *) NULL))
+ return false;
+ }
+ return (*fns->function_type) (fhandle, is,
+ type->u.kfunction->varargs);
+ case DEBUG_KIND_REFERENCE:
+ if (! debug_write_type (info, fns, fhandle, type->u.kreference,
+ (struct debug_name *) NULL))
+ return false;
+ return (*fns->reference_type) (fhandle);
+ case DEBUG_KIND_RANGE:
+ if (! debug_write_type (info, fns, fhandle, type->u.krange->type,
+ (struct debug_name *) NULL))
+ return false;
+ return (*fns->range_type) (fhandle, type->u.krange->lower,
+ type->u.krange->upper);
+ case DEBUG_KIND_ARRAY:
+ if (! debug_write_type (info, fns, fhandle, type->u.karray->element_type,
+ (struct debug_name *) NULL)
+ || ! debug_write_type (info, fns, fhandle,
+ type->u.karray->range_type,
+ (struct debug_name *) NULL))
+ return false;
+ return (*fns->array_type) (fhandle, type->u.karray->lower,
+ type->u.karray->upper,
+ type->u.karray->stringp);
+ case DEBUG_KIND_SET:
+ if (! debug_write_type (info, fns, fhandle, type->u.kset->type,
+ (struct debug_name *) NULL))
+ return false;
+ return (*fns->set_type) (fhandle, type->u.kset->bitstringp);
+ case DEBUG_KIND_OFFSET:
+ if (! debug_write_type (info, fns, fhandle, type->u.koffset->base_type,
+ (struct debug_name *) NULL)
+ || ! debug_write_type (info, fns, fhandle,
+ type->u.koffset->target_type,
+ (struct debug_name *) NULL))
+ return false;
+ return (*fns->offset_type) (fhandle);
+ case DEBUG_KIND_METHOD:
+ if (! debug_write_type (info, fns, fhandle,
+ type->u.kmethod->return_type,
+ (struct debug_name *) NULL))
+ return false;
+ if (type->u.kmethod->arg_types == NULL)
+ is = -1;
+ else
+ {
+ for (is = 0; type->u.kmethod->arg_types[is] != NULL; is++)
+ if (! debug_write_type (info, fns, fhandle,
+ type->u.kmethod->arg_types[is],
+ (struct debug_name *) NULL))
+ return false;
+ }
+ if (type->u.kmethod->domain_type != NULL)
+ {
+ if (! debug_write_type (info, fns, fhandle,
+ type->u.kmethod->domain_type,
+ (struct debug_name *) NULL))
+ return false;
+ }
+ return (*fns->method_type) (fhandle,
+ type->u.kmethod->domain_type != NULL,
+ is,
+ type->u.kmethod->varargs);
+ case DEBUG_KIND_CONST:
+ if (! debug_write_type (info, fns, fhandle, type->u.kconst,
+ (struct debug_name *) NULL))
+ return false;
+ return (*fns->const_type) (fhandle);
+ case DEBUG_KIND_VOLATILE:
+ if (! debug_write_type (info, fns, fhandle, type->u.kvolatile,
+ (struct debug_name *) NULL))
+ return false;
+ return (*fns->volatile_type) (fhandle);
+ case DEBUG_KIND_NAMED:
+ return debug_write_type (info, fns, fhandle, type->u.knamed->type,
+ (struct debug_name *) NULL);
+ case DEBUG_KIND_TAGGED:
+ return debug_write_type (info, fns, fhandle, type->u.knamed->type,
+ type->u.knamed->name);
+ default:
+ abort ();
+ return false;
+ }
+}
+
+/* Write out a class type. */
+
+static boolean
+debug_write_class_type (info, fns, fhandle, type, tag)
+ struct debug_handle *info;
+ const struct debug_write_fns *fns;
+ PTR fhandle;
+ struct debug_type *type;
+ const char *tag;
+{
+ unsigned int i;
+ unsigned int id;
+ struct debug_type *vptrbase;
+
+ if (type->u.kclass == NULL)
+ {
+ id = 0;
+ vptrbase = NULL;
+ }
+ else
+ {
+ if (type->u.kclass->id <= info->base_id)
+ {
+ if (! debug_set_class_id (info, tag, type))
+ return false;
+ }
+
+ if (info->mark == type->u.kclass->mark)
+ {
+ /* We are currently outputting this class, or we have
+ already output it. This can happen when there are
+ methods for an anonymous class. */
+ assert (type->u.kclass->id > info->base_id);
+ return (*fns->tag_type) (fhandle, tag, type->u.kclass->id,
+ type->kind);
+ }
+ type->u.kclass->mark = info->mark;
+ id = type->u.kclass->id;
+
+ vptrbase = type->u.kclass->vptrbase;
+ if (vptrbase != NULL && vptrbase != type)
+ {
+ if (! debug_write_type (info, fns, fhandle, vptrbase,
+ (struct debug_name *) NULL))
+ return false;
+ }
+ }
+
+ if (! (*fns->start_class_type) (fhandle, tag, id,
+ type->kind == DEBUG_KIND_CLASS,
+ type->size,
+ vptrbase != NULL,
+ vptrbase == type))
+ return false;
+
+ if (type->u.kclass != NULL)
+ {
+ if (type->u.kclass->fields != NULL)
+ {
+ for (i = 0; type->u.kclass->fields[i] != NULL; i++)
+ {
+ struct debug_field *f;
+
+ f = type->u.kclass->fields[i];
+ if (! debug_write_type (info, fns, fhandle, f->type,
+ (struct debug_name *) NULL))
+ return false;
+ if (f->static_member)
+ {
+ if (! (*fns->class_static_member) (fhandle, f->name,
+ f->u.s.physname,
+ f->visibility))
+ return false;
+ }
+ else
+ {
+ if (! (*fns->struct_field) (fhandle, f->name, f->u.f.bitpos,
+ f->u.f.bitsize, f->visibility))
+ return false;
+ }
+ }
+ }
+
+ if (type->u.kclass->baseclasses != NULL)
+ {
+ for (i = 0; type->u.kclass->baseclasses[i] != NULL; i++)
+ {
+ struct debug_baseclass *b;
+
+ b = type->u.kclass->baseclasses[i];
+ if (! debug_write_type (info, fns, fhandle, b->type,
+ (struct debug_name *) NULL))
+ return false;
+ if (! (*fns->class_baseclass) (fhandle, b->bitpos, b->virtual,
+ b->visibility))
+ return false;
+ }
+ }
+
+ if (type->u.kclass->methods != NULL)
+ {
+ for (i = 0; type->u.kclass->methods[i] != NULL; i++)
+ {
+ struct debug_method *m;
+ unsigned int j;
+
+ m = type->u.kclass->methods[i];
+ if (! (*fns->class_start_method) (fhandle, m->name))
+ return false;
+ for (j = 0; m->variants[j] != NULL; j++)
+ {
+ struct debug_method_variant *v;
+
+ v = m->variants[j];
+ if (v->context != NULL)
+ {
+ if (! debug_write_type (info, fns, fhandle, v->context,
+ (struct debug_name *) NULL))
+ return false;
+ }
+ if (! debug_write_type (info, fns, fhandle, v->type,
+ (struct debug_name *) NULL))
+ return false;
+ if (v->voffset != VOFFSET_STATIC_METHOD)
+ {
+ if (! (*fns->class_method_variant) (fhandle, v->physname,
+ v->visibility,
+ v->constp,
+ v->volatilep,
+ v->voffset,
+ v->context != NULL))
+ return false;
+ }
+ else
+ {
+ if (! (*fns->class_static_method_variant) (fhandle,
+ v->physname,
+ v->visibility,
+ v->constp,
+ v->volatilep))
+ return false;
+ }
+ }
+ if (! (*fns->class_end_method) (fhandle))
+ return false;
+ }
+ }
+ }
+
+ return (*fns->end_class_type) (fhandle);
+}
+
+/* Write out information for a function. */
+
+static boolean
+debug_write_function (info, fns, fhandle, name, linkage, function)
+ struct debug_handle *info;
+ const struct debug_write_fns *fns;
+ PTR fhandle;
+ const char *name;
+ enum debug_object_linkage linkage;
+ struct debug_function *function;
+{
+ struct debug_parameter *p;
+ struct debug_block *b;
+
+ if (! debug_write_linenos (info, fns, fhandle, function->blocks->start))
+ return false;
+
+ if (! debug_write_type (info, fns, fhandle, function->return_type,
+ (struct debug_name *) NULL))
+ return false;
+
+ if (! (*fns->start_function) (fhandle, name,
+ linkage == DEBUG_LINKAGE_GLOBAL))
+ return false;
+
+ for (p = function->parameters; p != NULL; p = p->next)
+ {
+ if (! debug_write_type (info, fns, fhandle, p->type,
+ (struct debug_name *) NULL)
+ || ! (*fns->function_parameter) (fhandle, p->name, p->kind, p->val))
+ return false;
+ }
+
+ for (b = function->blocks; b != NULL; b = b->next)
+ {
+ if (! debug_write_block (info, fns, fhandle, b))
+ return false;
+ }
+
+ return (*fns->end_function) (fhandle);
+}
+
+/* Write out information for a block. */
+
+static boolean
+debug_write_block (info, fns, fhandle, block)
+ struct debug_handle *info;
+ const struct debug_write_fns *fns;
+ PTR fhandle;
+ struct debug_block *block;
+{
+ struct debug_name *n;
+ struct debug_block *b;
+
+ if (! debug_write_linenos (info, fns, fhandle, block->start))
+ return false;
+
+ /* I can't see any point to writing out a block with no local
+ variables, so we don't bother, except for the top level block. */
+ if (block->locals != NULL || block->parent == NULL)
+ {
+ if (! (*fns->start_block) (fhandle, block->start))
+ return false;
+ }
+
+ if (block->locals != NULL)
+ {
+ for (n = block->locals->list; n != NULL; n = n->next)
+ {
+ if (! debug_write_name (info, fns, fhandle, n))
+ return false;
+ }
+ }
+
+ for (b = block->children; b != NULL; b = b->next)
+ {
+ if (! debug_write_block (info, fns, fhandle, b))
+ return false;
+ }
+
+ if (! debug_write_linenos (info, fns, fhandle, block->end))
+ return false;
+
+ if (block->locals != NULL || block->parent == NULL)
+ {
+ if (! (*fns->end_block) (fhandle, block->end))
+ return false;
+ }
+
+ return true;
+}
+
+/* Write out line number information up to ADDRESS. */
+
+static boolean
+debug_write_linenos (info, fns, fhandle, address)
+ struct debug_handle *info;
+ const struct debug_write_fns *fns;
+ PTR fhandle;
+ bfd_vma address;
+{
+ while (info->current_write_lineno != NULL)
+ {
+ struct debug_lineno *l;
+
+ l = info->current_write_lineno;
+
+ while (info->current_write_lineno_index < DEBUG_LINENO_COUNT)
+ {
+ if (l->linenos[info->current_write_lineno_index]
+ == (unsigned long) -1)
+ break;
+
+ if (l->addrs[info->current_write_lineno_index] >= address)
+ return true;
+
+ if (! (*fns->lineno) (fhandle, l->file->filename,
+ l->linenos[info->current_write_lineno_index],
+ l->addrs[info->current_write_lineno_index]))
+ return false;
+
+ ++info->current_write_lineno_index;
+ }
+
+ info->current_write_lineno = l->next;
+ info->current_write_lineno_index = 0;
+ }
+
+ return true;
+}
+
+/* Get the ID number for a class. If during the same call to
+ debug_write we find a struct with the same definition with the same
+ name, we use the same ID. This type of things happens because the
+ same struct will be defined by multiple compilation units. */
+
+static boolean
+debug_set_class_id (info, tag, type)
+ struct debug_handle *info;
+ const char *tag;
+ struct debug_type *type;
+{
+ struct debug_class_type *c;
+ struct debug_class_id *l;
+
+ assert (type->kind == DEBUG_KIND_STRUCT
+ || type->kind == DEBUG_KIND_UNION
+ || type->kind == DEBUG_KIND_CLASS
+ || type->kind == DEBUG_KIND_UNION_CLASS);
+
+ c = type->u.kclass;
+
+ if (c->id > info->base_id)
+ return true;
+
+ for (l = info->id_list; l != NULL; l = l->next)
+ {
+ if (l->type->kind != type->kind)
+ continue;
+
+ if (tag == NULL)
+ {
+ if (l->tag != NULL)
+ continue;
+ }
+ else
+ {
+ if (l->tag == NULL
+ || l->tag[0] != tag[0]
+ || strcmp (l->tag, tag) != 0)
+ continue;
+ }
+
+ if (debug_type_samep (info, l->type, type))
+ {
+ c->id = l->type->u.kclass->id;
+ return true;
+ }
+ }
+
+ /* There are no identical types. Use a new ID, and add it to the
+ list. */
+ ++info->class_id;
+ c->id = info->class_id;
+
+ l = (struct debug_class_id *) xmalloc (sizeof *l);
+ memset (l, 0, sizeof *l);
+
+ l->type = type;
+ l->tag = tag;
+
+ l->next = info->id_list;
+ info->id_list = l;
+
+ return true;
+}
+
+/* See if two types are the same. At this point, we don't care about
+ tags and the like. */
+
+static boolean
+debug_type_samep (info, t1, t2)
+ struct debug_handle *info;
+ struct debug_type *t1;
+ struct debug_type *t2;
+{
+ struct debug_type_compare_list *l;
+ struct debug_type_compare_list top;
+ boolean ret;
+
+ if (t1 == NULL)
+ return t2 == NULL;
+ if (t2 == NULL)
+ return false;
+
+ while (t1->kind == DEBUG_KIND_INDIRECT)
+ {
+ t1 = *t1->u.kindirect->slot;
+ if (t1 == NULL)
+ return false;
+ }
+ while (t2->kind == DEBUG_KIND_INDIRECT)
+ {
+ t2 = *t2->u.kindirect->slot;
+ if (t2 == NULL)
+ return false;
+ }
+
+ if (t1 == t2)
+ return true;
+
+ /* As a special case, permit a typedef to match a tag, since C++
+ debugging output will sometimes add a typedef where C debugging
+ output will not. */
+ if (t1->kind == DEBUG_KIND_NAMED
+ && t2->kind == DEBUG_KIND_TAGGED)
+ return debug_type_samep (info, t1->u.knamed->type, t2);
+ else if (t1->kind == DEBUG_KIND_TAGGED
+ && t2->kind == DEBUG_KIND_NAMED)
+ return debug_type_samep (info, t1, t2->u.knamed->type);
+
+ if (t1->kind != t2->kind
+ || t1->size != t2->size)
+ return false;
+
+ /* Get rid of the trivial cases first. */
+ switch (t1->kind)
+ {
+ default:
+ break;
+ case DEBUG_KIND_VOID:
+ case DEBUG_KIND_FLOAT:
+ case DEBUG_KIND_COMPLEX:
+ case DEBUG_KIND_BOOL:
+ return true;
+ case DEBUG_KIND_INT:
+ return t1->u.kint == t2->u.kint;
+ }
+
+ /* We have to avoid an infinite recursion. We do this by keeping a
+ list of types which we are comparing. We just keep the list on
+ the stack. If we encounter a pair of types we are currently
+ comparing, we just assume that they are equal. */
+ for (l = info->compare_list; l != NULL; l = l->next)
+ {
+ if (l->t1 == t1 && l->t2 == t2)
+ return true;
+ }
+
+ top.t1 = t1;
+ top.t2 = t2;
+ top.next = info->compare_list;
+ info->compare_list = &top;
+
+ switch (t1->kind)
+ {
+ default:
+ abort ();
+ ret = false;
+ break;
+
+ case DEBUG_KIND_STRUCT:
+ case DEBUG_KIND_UNION:
+ case DEBUG_KIND_CLASS:
+ case DEBUG_KIND_UNION_CLASS:
+ if (t1->u.kclass == NULL)
+ ret = t2->u.kclass == NULL;
+ else if (t2->u.kclass == NULL)
+ ret = false;
+ else if (t1->u.kclass->id > info->base_id
+ && t1->u.kclass->id == t2->u.kclass->id)
+ ret = true;
+ else
+ ret = debug_class_type_samep (info, t1, t2);
+ break;
+
+ case DEBUG_KIND_ENUM:
+ if (t1->u.kenum == NULL)
+ ret = t2->u.kenum == NULL;
+ else if (t2->u.kenum == NULL)
+ ret = false;
+ else
+ {
+ const char **pn1, **pn2;
+ bfd_signed_vma *pv1, *pv2;
+
+ pn1 = t1->u.kenum->names;
+ pn2 = t2->u.kenum->names;
+ pv1 = t1->u.kenum->values;
+ pv2 = t2->u.kenum->values;
+ while (*pn1 != NULL && *pn2 != NULL)
+ {
+ if (**pn1 != **pn2
+ || *pv1 != *pv2
+ || strcmp (*pn1, *pn2) != 0)
+ break;
+ ++pn1;
+ ++pn2;
+ ++pv1;
+ ++pv2;
+ }
+ ret = *pn1 == NULL && *pn2 == NULL;
+ }
+ break;
+
+ case DEBUG_KIND_POINTER:
+ ret = debug_type_samep (info, t1->u.kpointer, t2->u.kpointer);
+ break;
+
+ case DEBUG_KIND_FUNCTION:
+ if (t1->u.kfunction->varargs != t2->u.kfunction->varargs
+ || ! debug_type_samep (info, t1->u.kfunction->return_type,
+ t2->u.kfunction->return_type)
+ || ((t1->u.kfunction->arg_types == NULL)
+ != (t2->u.kfunction->arg_types == NULL)))
+ ret = false;
+ else if (t1->u.kfunction->arg_types == NULL)
+ ret = true;
+ else
+ {
+ struct debug_type **a1, **a2;
+
+ a1 = t1->u.kfunction->arg_types;
+ a2 = t2->u.kfunction->arg_types;
+ while (*a1 != NULL && *a2 != NULL)
+ if (! debug_type_samep (info, *a1, *a2))
+ break;
+ ret = *a1 == NULL && *a2 == NULL;
+ }
+ break;
+
+ case DEBUG_KIND_REFERENCE:
+ ret = debug_type_samep (info, t1->u.kreference, t2->u.kreference);
+ break;
+
+ case DEBUG_KIND_RANGE:
+ ret = (t1->u.krange->lower == t2->u.krange->lower
+ && t1->u.krange->upper == t2->u.krange->upper
+ && debug_type_samep (info, t1->u.krange->type,
+ t2->u.krange->type));
+
+ case DEBUG_KIND_ARRAY:
+ ret = (t1->u.karray->lower == t2->u.karray->lower
+ && t1->u.karray->upper == t2->u.karray->upper
+ && t1->u.karray->stringp == t2->u.karray->stringp
+ && debug_type_samep (info, t1->u.karray->element_type,
+ t2->u.karray->element_type));
+ break;
+
+ case DEBUG_KIND_SET:
+ ret = (t1->u.kset->bitstringp == t2->u.kset->bitstringp
+ && debug_type_samep (info, t1->u.kset->type, t2->u.kset->type));
+ break;
+
+ case DEBUG_KIND_OFFSET:
+ ret = (debug_type_samep (info, t1->u.koffset->base_type,
+ t2->u.koffset->base_type)
+ && debug_type_samep (info, t1->u.koffset->target_type,
+ t2->u.koffset->target_type));
+ break;
+
+ case DEBUG_KIND_METHOD:
+ if (t1->u.kmethod->varargs != t2->u.kmethod->varargs
+ || ! debug_type_samep (info, t1->u.kmethod->return_type,
+ t2->u.kmethod->return_type)
+ || ! debug_type_samep (info, t1->u.kmethod->domain_type,
+ t2->u.kmethod->domain_type)
+ || ((t1->u.kmethod->arg_types == NULL)
+ != (t2->u.kmethod->arg_types == NULL)))
+ ret = false;
+ else if (t1->u.kmethod->arg_types == NULL)
+ ret = true;
+ else
+ {
+ struct debug_type **a1, **a2;
+
+ a1 = t1->u.kmethod->arg_types;
+ a2 = t2->u.kmethod->arg_types;
+ while (*a1 != NULL && *a2 != NULL)
+ if (! debug_type_samep (info, *a1, *a2))
+ break;
+ ret = *a1 == NULL && *a2 == NULL;
+ }
+ break;
+
+ case DEBUG_KIND_CONST:
+ ret = debug_type_samep (info, t1->u.kconst, t2->u.kconst);
+ break;
+
+ case DEBUG_KIND_VOLATILE:
+ ret = debug_type_samep (info, t1->u.kvolatile, t2->u.kvolatile);
+ break;
+
+ case DEBUG_KIND_NAMED:
+ case DEBUG_KIND_TAGGED:
+ ret = (strcmp (t1->u.knamed->name->name, t2->u.knamed->name->name) == 0
+ && debug_type_samep (info, t1->u.knamed->type,
+ t2->u.knamed->type));
+ break;
+ }
+
+ info->compare_list = top.next;
+
+ return ret;
+}
+
+/* See if two classes are the same. This is a subroutine of
+ debug_type_samep. */
+
+static boolean
+debug_class_type_samep (info, t1, t2)
+ struct debug_handle *info;
+ struct debug_type *t1;
+ struct debug_type *t2;
+{
+ struct debug_class_type *c1, *c2;
+
+ c1 = t1->u.kclass;
+ c2 = t2->u.kclass;
+
+ if ((c1->fields == NULL) != (c2->fields == NULL)
+ || (c1->baseclasses == NULL) != (c2->baseclasses == NULL)
+ || (c1->methods == NULL) != (c2->methods == NULL)
+ || (c1->vptrbase == NULL) != (c2->vptrbase == NULL))
+ return false;
+
+ if (c1->fields != NULL)
+ {
+ struct debug_field **pf1, **pf2;
+
+ for (pf1 = c1->fields, pf2 = c2->fields;
+ *pf1 != NULL && *pf2 != NULL;
+ pf1++, pf2++)
+ {
+ struct debug_field *f1, *f2;
+
+ f1 = *pf1;
+ f2 = *pf2;
+ if (f1->name[0] != f2->name[0]
+ || f1->visibility != f2->visibility
+ || f1->static_member != f2->static_member)
+ return false;
+ if (f1->static_member)
+ {
+ if (strcmp (f1->u.s.physname, f2->u.s.physname) != 0)
+ return false;
+ }
+ else
+ {
+ if (f1->u.f.bitpos != f2->u.f.bitpos
+ || f1->u.f.bitsize != f2->u.f.bitsize)
+ return false;
+ }
+ /* We do the checks which require function calls last. We
+ don't require that the types of fields have the same
+ names, since that sometimes fails in the presence of
+ typedefs and we really don't care. */
+ if (strcmp (f1->name, f2->name) != 0
+ || ! debug_type_samep (info,
+ debug_get_real_type ((PTR) info,
+ f1->type),
+ debug_get_real_type ((PTR) info,
+ f2->type)))
+ return false;
+ }
+ if (*pf1 != NULL || *pf2 != NULL)
+ return false;
+ }
+
+ if (c1->vptrbase != NULL)
+ {
+ if (! debug_type_samep (info, c1->vptrbase, c2->vptrbase))
+ return false;
+ }
+
+ if (c1->baseclasses != NULL)
+ {
+ struct debug_baseclass **pb1, **pb2;
+
+ for (pb1 = c1->baseclasses, pb2 = c2->baseclasses;
+ *pb1 != NULL && *pb2 != NULL;
+ ++pb1, ++pb2)
+ {
+ struct debug_baseclass *b1, *b2;
+
+ b1 = *pb1;
+ b2 = *pb2;
+ if (b1->bitpos != b2->bitpos
+ || b1->virtual != b2->virtual
+ || b1->visibility != b2->visibility
+ || ! debug_type_samep (info, b1->type, b2->type))
+ return false;
+ }
+ if (*pb1 != NULL || *pb2 != NULL)
+ return false;
+ }
+
+ if (c1->methods != NULL)
+ {
+ struct debug_method **pm1, **pm2;
+
+ for (pm1 = c1->methods, pm2 = c2->methods;
+ *pm1 != NULL && *pm2 != NULL;
+ ++pm1, ++pm2)
+ {
+ struct debug_method *m1, *m2;
+
+ m1 = *pm1;
+ m2 = *pm2;
+ if (m1->name[0] != m2->name[0]
+ || strcmp (m1->name, m2->name) != 0
+ || (m1->variants == NULL) != (m2->variants == NULL))
+ return false;
+ if (m1->variants == NULL)
+ {
+ struct debug_method_variant **pv1, **pv2;
+
+ for (pv1 = m1->variants, pv2 = m2->variants;
+ *pv1 != NULL && *pv2 != NULL;
+ ++pv1, ++pv2)
+ {
+ struct debug_method_variant *v1, *v2;
+
+ v1 = *pv1;
+ v2 = *pv2;
+ if (v1->physname[0] != v2->physname[0]
+ || v1->visibility != v2->visibility
+ || v1->constp != v2->constp
+ || v1->volatilep != v2->volatilep
+ || v1->voffset != v2->voffset
+ || (v1->context == NULL) != (v2->context == NULL)
+ || strcmp (v1->physname, v2->physname) != 0
+ || ! debug_type_samep (info, v1->type, v2->type))
+ return false;
+ if (v1->context != NULL)
+ {
+ if (! debug_type_samep (info, v1->context,
+ v2->context))
+ return false;
+ }
+ }
+ if (*pv1 != NULL || *pv2 != NULL)
+ return false;
+ }
+ }
+ if (*pm1 != NULL || *pm2 != NULL)
+ return false;
+ }
+
+ return true;
+}
diff --git a/pstack/debug.h b/pstack/debug.h
new file mode 100644
index 00000000000..a4d3d8306cd
--- /dev/null
+++ b/pstack/debug.h
@@ -0,0 +1,798 @@
+/* debug.h -- Describe generic debugging information.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <ian@cygnus.com>.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; 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 DEBUG_H
+#define DEBUG_H
+
+/* This header file describes a generic debugging information format.
+ We may eventually have readers which convert different formats into
+ this generic format, and writers which write it out. The initial
+ impetus for this was writing a convertor from stabs to HP IEEE-695
+ debugging format. */
+
+/* Different kinds of types. */
+
+enum debug_type_kind
+{
+ /* Not used. */
+ DEBUG_KIND_ILLEGAL,
+ /* Indirect via a pointer. */
+ DEBUG_KIND_INDIRECT,
+ /* Void. */
+ DEBUG_KIND_VOID,
+ /* Integer. */
+ DEBUG_KIND_INT,
+ /* Floating point. */
+ DEBUG_KIND_FLOAT,
+ /* Complex. */
+ DEBUG_KIND_COMPLEX,
+ /* Boolean. */
+ DEBUG_KIND_BOOL,
+ /* Struct. */
+ DEBUG_KIND_STRUCT,
+ /* Union. */
+ DEBUG_KIND_UNION,
+ /* Class. */
+ DEBUG_KIND_CLASS,
+ /* Union class (can this really happen?). */
+ DEBUG_KIND_UNION_CLASS,
+ /* Enumeration type. */
+ DEBUG_KIND_ENUM,
+ /* Pointer. */
+ DEBUG_KIND_POINTER,
+ /* Function. */
+ DEBUG_KIND_FUNCTION,
+ /* Reference. */
+ DEBUG_KIND_REFERENCE,
+ /* Range. */
+ DEBUG_KIND_RANGE,
+ /* Array. */
+ DEBUG_KIND_ARRAY,
+ /* Set. */
+ DEBUG_KIND_SET,
+ /* Based pointer. */
+ DEBUG_KIND_OFFSET,
+ /* Method. */
+ DEBUG_KIND_METHOD,
+ /* Const qualified type. */
+ DEBUG_KIND_CONST,
+ /* Volatile qualified type. */
+ DEBUG_KIND_VOLATILE,
+ /* Named type. */
+ DEBUG_KIND_NAMED,
+ /* Tagged type. */
+ DEBUG_KIND_TAGGED
+};
+
+/* Different kinds of variables. */
+
+enum debug_var_kind
+{
+ /* Not used. */
+ DEBUG_VAR_ILLEGAL,
+ /* A global variable. */
+ DEBUG_GLOBAL,
+ /* A static variable. */
+ DEBUG_STATIC,
+ /* A local static variable. */
+ DEBUG_LOCAL_STATIC,
+ /* A local variable. */
+ DEBUG_LOCAL,
+ /* A register variable. */
+ DEBUG_REGISTER
+};
+
+/* Different kinds of function parameters. */
+
+enum debug_parm_kind
+{
+ /* Not used. */
+ DEBUG_PARM_ILLEGAL,
+ /* A stack based parameter. */
+ DEBUG_PARM_STACK,
+ /* A register parameter. */
+ DEBUG_PARM_REG,
+ /* A stack based reference parameter. */
+ DEBUG_PARM_REFERENCE,
+ /* A register reference parameter. */
+ DEBUG_PARM_REF_REG
+};
+
+/* Different kinds of visibility. */
+
+enum debug_visibility
+{
+ /* A public field (e.g., a field in a C struct). */
+ DEBUG_VISIBILITY_PUBLIC,
+ /* A protected field. */
+ DEBUG_VISIBILITY_PROTECTED,
+ /* A private field. */
+ DEBUG_VISIBILITY_PRIVATE,
+ /* A field which should be ignored. */
+ DEBUG_VISIBILITY_IGNORE
+};
+
+/* A type. */
+
+typedef struct debug_type *debug_type;
+
+#define DEBUG_TYPE_NULL ((debug_type) NULL)
+
+/* A field in a struct or union. */
+
+typedef struct debug_field *debug_field;
+
+#define DEBUG_FIELD_NULL ((debug_field) NULL)
+
+/* A base class for an object. */
+
+typedef struct debug_baseclass *debug_baseclass;
+
+#define DEBUG_BASECLASS_NULL ((debug_baseclass) NULL)
+
+/* A method of an object. */
+
+typedef struct debug_method *debug_method;
+
+#define DEBUG_METHOD_NULL ((debug_method) NULL)
+
+/* The arguments to a method function of an object. These indicate
+ which method to run. */
+
+typedef struct debug_method_variant *debug_method_variant;
+
+#define DEBUG_METHOD_VARIANT_NULL ((debug_method_variant) NULL)
+
+/* This structure is passed to debug_write. It holds function
+ pointers that debug_write will call based on the accumulated
+ debugging information. */
+
+struct debug_write_fns
+{
+ /* This is called at the start of each new compilation unit with the
+ name of the main file in the new unit. */
+ boolean (*start_compilation_unit) PARAMS ((PTR, const char *));
+
+ /* This is called at the start of each source file within a
+ compilation unit, before outputting any global information for
+ that file. The argument is the name of the file. */
+ boolean (*start_source) PARAMS ((PTR, const char *));
+
+ /* Each writer must keep a stack of types. */
+
+ /* Push an empty type onto the type stack. This type can appear if
+ there is a reference to a type which is never defined. */
+ boolean (*empty_type) PARAMS ((PTR));
+
+ /* Push a void type onto the type stack. */
+ boolean (*void_type) PARAMS ((PTR));
+
+ /* Push an integer type onto the type stack, given the size and
+ whether it is unsigned. */
+ boolean (*int_type) PARAMS ((PTR, unsigned int, boolean));
+
+ /* Push a floating type onto the type stack, given the size. */
+ boolean (*float_type) PARAMS ((PTR, unsigned int));
+
+ /* Push a complex type onto the type stack, given the size. */
+ boolean (*complex_type) PARAMS ((PTR, unsigned int));
+
+ /* Push a boolean type onto the type stack, given the size. */
+ boolean (*bool_type) PARAMS ((PTR, unsigned int));
+
+ /* Push an enum type onto the type stack, given the tag, a NULL
+ terminated array of names and the associated values. If there is
+ no tag, the tag argument will be NULL. If this is an undefined
+ enum, the names and values arguments will be NULL. */
+ boolean (*enum_type) PARAMS ((PTR, const char *, const char **,
+ bfd_signed_vma *));
+
+ /* Pop the top type on the type stack, and push a pointer to that
+ type onto the type stack. */
+ boolean (*pointer_type) PARAMS ((PTR));
+
+ /* Push a function type onto the type stack. The second argument
+ indicates the number of argument types that have been pushed onto
+ the stack. If the number of argument types is passed as -1, then
+ the argument types of the function are unknown, and no types have
+ been pushed onto the stack. The third argument is true if the
+ function takes a variable number of arguments. The return type
+ of the function is pushed onto the type stack below the argument
+ types, if any. */
+ boolean (*function_type) PARAMS ((PTR, int, boolean));
+
+ /* Pop the top type on the type stack, and push a reference to that
+ type onto the type stack. */
+ boolean (*reference_type) PARAMS ((PTR));
+
+ /* Pop the top type on the type stack, and push a range of that type
+ with the given lower and upper bounds onto the type stack. */
+ boolean (*range_type) PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma));
+
+ /* Push an array type onto the type stack. The top type on the type
+ stack is the range, and the next type on the type stack is the
+ element type. These should be popped before the array type is
+ pushed. The arguments are the lower bound, the upper bound, and
+ whether the array is a string. */
+ boolean (*array_type) PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma,
+ boolean));
+
+ /* Pop the top type on the type stack, and push a set of that type
+ onto the type stack. The argument indicates whether this set is
+ a bitstring. */
+ boolean (*set_type) PARAMS ((PTR, boolean));
+
+ /* Push an offset type onto the type stack. The top type on the
+ type stack is the target type, and the next type on the type
+ stack is the base type. These should be popped before the offset
+ type is pushed. */
+ boolean (*offset_type) PARAMS ((PTR));
+
+ /* Push a method type onto the type stack. If the second argument
+ is true, the top type on the stack is the class to which the
+ method belongs; otherwise, the class must be determined by the
+ class to which the method is attached. The third argument is the
+ number of argument types; these are pushed onto the type stack in
+ reverse order (the first type popped is the last argument to the
+ method). A value of -1 for the third argument means that no
+ argument information is available. The fourth argument is true
+ if the function takes a variable number of arguments. The next
+ type on the type stack below the domain and the argument types is
+ the return type of the method. All these types must be popped,
+ and then the method type must be pushed. */
+ boolean (*method_type) PARAMS ((PTR, boolean, int, boolean));
+
+ /* Pop the top type off the type stack, and push a const qualified
+ version of that type onto the type stack. */
+ boolean (*const_type) PARAMS ((PTR));
+
+ /* Pop the top type off the type stack, and push a volatile
+ qualified version of that type onto the type stack. */
+ boolean (*volatile_type) PARAMS ((PTR));
+
+ /* Start building a struct. This is followed by calls to the
+ struct_field function, and finished by a call to the
+ end_struct_type function. The second argument is the tag; this
+ will be NULL if there isn't one. If the second argument is NULL,
+ the third argument is a constant identifying this struct for use
+ with tag_type. The fourth argument is true for a struct, false
+ for a union. The fifth argument is the size. If this is an
+ undefined struct or union, the size will be 0 and struct_field
+ will not be called before end_struct_type is called. */
+ boolean (*start_struct_type) PARAMS ((PTR, const char *, unsigned int,
+ boolean, unsigned int));
+
+ /* Add a field to the struct type currently being built. The type
+ of the field should be popped off the type stack. The arguments
+ are the name, the bit position, the bit size (may be zero if the
+ field is not packed), and the visibility. */
+ boolean (*struct_field) PARAMS ((PTR, const char *, bfd_vma, bfd_vma,
+ enum debug_visibility));
+
+ /* Finish building a struct, and push it onto the type stack. */
+ boolean (*end_struct_type) PARAMS ((PTR));
+
+ /* Start building a class. This is followed by calls to several
+ functions: struct_field, class_static_member, class_baseclass,
+ class_start_method, class_method_variant,
+ class_static_method_variant, and class_end_method. The class is
+ finished by a call to end_class_type. The first five arguments
+ are the same as for start_struct_type. The sixth argument is
+ true if there is a virtual function table; if there is, the
+ seventh argument is true if the virtual function table can be
+ found in the type itself, and is false if the type of the object
+ holding the virtual function table should be popped from the type
+ stack. */
+ boolean (*start_class_type) PARAMS ((PTR, const char *, unsigned int,
+ boolean, unsigned int, boolean,
+ boolean));
+
+ /* Add a static member to the class currently being built. The
+ arguments are the field name, the physical name, and the
+ visibility. The type must be popped off the type stack. */
+ boolean (*class_static_member) PARAMS ((PTR, const char *, const char *,
+ enum debug_visibility));
+
+ /* Add a baseclass to the class currently being built. The type of
+ the baseclass must be popped off the type stack. The arguments
+ are the bit position, whether the class is virtual, and the
+ visibility. */
+ boolean (*class_baseclass) PARAMS ((PTR, bfd_vma, boolean,
+ enum debug_visibility));
+
+ /* Start adding a method to the class currently being built. This
+ is followed by calls to class_method_variant and
+ class_static_method_variant to describe different variants of the
+ method which take different arguments. The method is finished
+ with a call to class_end_method. The argument is the method
+ name. */
+ boolean (*class_start_method) PARAMS ((PTR, const char *));
+
+ /* Describe a variant to the class method currently being built.
+ The type of the variant must be popped off the type stack. The
+ second argument is the physical name of the function. The
+ following arguments are the visibility, whether the variant is
+ const, whether the variant is volatile, the offset in the virtual
+ function table, and whether the context is on the type stack
+ (below the variant type). */
+ boolean (*class_method_variant) PARAMS ((PTR, const char *,
+ enum debug_visibility,
+ boolean, boolean,
+ bfd_vma, boolean));
+
+ /* Describe a static variant to the class method currently being
+ built. The arguments are the same as for class_method_variant,
+ except that the last two arguments are omitted. The type of the
+ variant must be popped off the type stack. */
+ boolean (*class_static_method_variant) PARAMS ((PTR, const char *,
+ enum debug_visibility,
+ boolean, boolean));
+
+ /* Finish describing a class method. */
+ boolean (*class_end_method) PARAMS ((PTR));
+
+ /* Finish describing a class, and push it onto the type stack. */
+ boolean (*end_class_type) PARAMS ((PTR));
+
+ /* Push a type on the stack which was given a name by an earlier
+ call to typdef. */
+ boolean (*typedef_type) PARAMS ((PTR, const char *));
+
+ /* Push a tagged type on the stack which was defined earlier. If
+ the second argument is not NULL, the type was defined by a call
+ to tag. If the second argument is NULL, the type was defined by
+ a call to start_struct_type or start_class_type with a tag of
+ NULL and the number of the third argument. Either way, the
+ fourth argument is the tag kind. Note that this may be called
+ for a struct (class) being defined, in between the call to
+ start_struct_type (start_class_type) and the call to
+ end_struct_type (end_class_type). */
+ boolean (*tag_type) PARAMS ((PTR, const char *, unsigned int,
+ enum debug_type_kind));
+
+ /* Pop the type stack, and typedef it to the given name. */
+ boolean (*typdef) PARAMS ((PTR, const char *));
+
+ /* Pop the type stack, and declare it as a tagged struct or union or
+ enum or whatever. The tag passed down here is redundant, since
+ was also passed when enum_type, start_struct_type, or
+ start_class_type was called. */
+ boolean (*tag) PARAMS ((PTR, const char *));
+
+ /* This is called to record a named integer constant. */
+ boolean (*int_constant) PARAMS ((PTR, const char *, bfd_vma));
+
+ /* This is called to record a named floating point constant. */
+ boolean (*float_constant) PARAMS ((PTR, const char *, double));
+
+ /* This is called to record a typed integer constant. The type is
+ popped off the type stack. */
+ boolean (*typed_constant) PARAMS ((PTR, const char *, bfd_vma));
+
+ /* This is called to record a variable. The type is popped off the
+ type stack. */
+ boolean (*variable) PARAMS ((PTR, const char *, enum debug_var_kind,
+ bfd_vma));
+
+ /* Start writing out a function. The return type must be popped off
+ the stack. The boolean is true if the function is global. This
+ is followed by calls to function_parameter, followed by block
+ information. */
+ boolean (*start_function) PARAMS ((PTR, const char *, boolean));
+
+ /* Record a function parameter for the current function. The type
+ must be popped off the stack. */
+ boolean (*function_parameter) PARAMS ((PTR, const char *,
+ enum debug_parm_kind, bfd_vma));
+
+ /* Start writing out a block. There is at least one top level block
+ per function. Blocks may be nested. The argument is the
+ starting address of the block. */
+ boolean (*start_block) PARAMS ((PTR, bfd_vma));
+
+ /* Finish writing out a block. The argument is the ending address
+ of the block. */
+ boolean (*end_block) PARAMS ((PTR, bfd_vma));
+
+ /* Finish writing out a function. */
+ boolean (*end_function) PARAMS ((PTR));
+
+ /* Record line number information for the current compilation unit. */
+ boolean (*lineno) PARAMS ((PTR, const char *, unsigned long, bfd_vma));
+};
+
+/* Exported functions. */
+
+/* The first argument to most of these functions is a handle. This
+ handle is returned by the debug_init function. The purpose of the
+ handle is to permit the debugging routines to not use static
+ variables, and hence to be reentrant. This would be useful for a
+ program which wanted to handle two executables simultaneously. */
+
+/* Return a debugging handle. */
+
+extern PTR debug_init PARAMS ((void));
+
+/* Set the source filename. This implicitly starts a new compilation
+ unit. */
+
+extern boolean debug_set_filename PARAMS ((PTR, const char *));
+
+/* Change source files to the given file name. This is used for
+ include files in a single compilation unit. */
+
+extern boolean debug_start_source PARAMS ((PTR, const char *));
+
+/* Record a function definition. This implicitly starts a function
+ block. The debug_type argument is the type of the return value.
+ The boolean indicates whether the function is globally visible.
+ The bfd_vma is the address of the start of the function. Currently
+ the parameter types are specified by calls to
+ debug_record_parameter. */
+
+extern boolean debug_record_function
+ PARAMS ((PTR, const char *, debug_type, boolean, bfd_vma));
+
+/* Record a parameter for the current function. */
+
+extern boolean debug_record_parameter
+ PARAMS ((PTR, const char *, debug_type, enum debug_parm_kind, bfd_vma));
+
+/* End a function definition. The argument is the address where the
+ function ends. */
+
+extern boolean debug_end_function PARAMS ((PTR, bfd_vma));
+
+/* Start a block in a function. All local information will be
+ recorded in this block, until the matching call to debug_end_block.
+ debug_start_block and debug_end_block may be nested. The argument
+ is the address at which this block starts. */
+
+extern boolean debug_start_block PARAMS ((PTR, bfd_vma));
+
+/* Finish a block in a function. This matches the call to
+ debug_start_block. The argument is the address at which this block
+ ends. */
+
+extern boolean debug_end_block PARAMS ((PTR, bfd_vma));
+
+/* Associate a line number in the current source file with a given
+ address. */
+
+extern boolean debug_record_line PARAMS ((PTR, unsigned long, bfd_vma));
+
+/* Start a named common block. This is a block of variables that may
+ move in memory. */
+
+extern boolean debug_start_common_block PARAMS ((PTR, const char *));
+
+/* End a named common block. */
+
+extern boolean debug_end_common_block PARAMS ((PTR, const char *));
+
+/* Record a named integer constant. */
+
+extern boolean debug_record_int_const PARAMS ((PTR, const char *, bfd_vma));
+
+/* Record a named floating point constant. */
+
+extern boolean debug_record_float_const PARAMS ((PTR, const char *, double));
+
+/* Record a typed constant with an integral value. */
+
+extern boolean debug_record_typed_const
+ PARAMS ((PTR, const char *, debug_type, bfd_vma));
+
+/* Record a label. */
+
+extern boolean debug_record_label
+ PARAMS ((PTR, const char *, debug_type, bfd_vma));
+
+/* Record a variable. */
+
+extern boolean debug_record_variable
+ PARAMS ((PTR, const char *, debug_type, enum debug_var_kind, bfd_vma));
+
+/* Make an indirect type. The first argument is a pointer to the
+ location where the real type will be placed. The second argument
+ is the type tag, if there is one; this may be NULL; the only
+ purpose of this argument is so that debug_get_type_name can return
+ something useful. This function may be used when a type is
+ referenced before it is defined. */
+
+extern debug_type debug_make_indirect_type
+ PARAMS ((PTR, debug_type *, const char *));
+
+/* Make a void type. */
+
+extern debug_type debug_make_void_type PARAMS ((PTR));
+
+/* Make an integer type of a given size. The boolean argument is true
+ if the integer is unsigned. */
+
+extern debug_type debug_make_int_type PARAMS ((PTR, unsigned int, boolean));
+
+/* Make a floating point type of a given size. FIXME: On some
+ platforms, like an Alpha, you probably need to be able to specify
+ the format. */
+
+extern debug_type debug_make_float_type PARAMS ((PTR, unsigned int));
+
+/* Make a boolean type of a given size. */
+
+extern debug_type debug_make_bool_type PARAMS ((PTR, unsigned int));
+
+/* Make a complex type of a given size. */
+
+extern debug_type debug_make_complex_type PARAMS ((PTR, unsigned int));
+
+/* Make a structure type. The second argument is true for a struct,
+ false for a union. The third argument is the size of the struct.
+ The fourth argument is a NULL terminated array of fields. */
+
+extern debug_type debug_make_struct_type
+ PARAMS ((PTR, boolean, bfd_vma, debug_field *));
+
+/* Make an object type. The first three arguments after the handle
+ are the same as for debug_make_struct_type. The next arguments are
+ a NULL terminated array of base classes, a NULL terminated array of
+ methods, the type of the object holding the virtual function table
+ if it is not this object, and a boolean which is true if this
+ object has its own virtual function table. */
+
+extern debug_type debug_make_object_type
+ PARAMS ((PTR, boolean, bfd_vma, debug_field *, debug_baseclass *,
+ debug_method *, debug_type, boolean));
+
+/* Make an enumeration type. The arguments are a null terminated
+ array of strings, and an array of corresponding values. */
+
+extern debug_type debug_make_enum_type
+ PARAMS ((PTR, const char **, bfd_signed_vma *));
+
+/* Make a pointer to a given type. */
+
+extern debug_type debug_make_pointer_type
+ PARAMS ((PTR, debug_type));
+
+/* Make a function type. The second argument is the return type. The
+ third argument is a NULL terminated array of argument types. The
+ fourth argument is true if the function takes a variable number of
+ arguments. If the third argument is NULL, then the argument types
+ are unknown. */
+
+extern debug_type debug_make_function_type
+ PARAMS ((PTR, debug_type, debug_type *, boolean));
+
+/* Make a reference to a given type. */
+
+extern debug_type debug_make_reference_type PARAMS ((PTR, debug_type));
+
+/* Make a range of a given type from a lower to an upper bound. */
+
+extern debug_type debug_make_range_type
+ PARAMS ((PTR, debug_type, bfd_signed_vma, bfd_signed_vma));
+
+/* Make an array type. The second argument is the type of an element
+ of the array. The third argument is the type of a range of the
+ array. The fourth and fifth argument are the lower and upper
+ bounds, respectively (if the bounds are not known, lower should be
+ 0 and upper should be -1). The sixth argument is true if this
+ array is actually a string, as in C. */
+
+extern debug_type debug_make_array_type
+ PARAMS ((PTR, debug_type, debug_type, bfd_signed_vma, bfd_signed_vma,
+ boolean));
+
+/* Make a set of a given type. For example, a Pascal set type. The
+ boolean argument is true if this set is actually a bitstring, as in
+ CHILL. */
+
+extern debug_type debug_make_set_type PARAMS ((PTR, debug_type, boolean));
+
+/* Make a type for a pointer which is relative to an object. The
+ second argument is the type of the object to which the pointer is
+ relative. The third argument is the type that the pointer points
+ to. */
+
+extern debug_type debug_make_offset_type
+ PARAMS ((PTR, debug_type, debug_type));
+
+/* Make a type for a method function. The second argument is the
+ return type. The third argument is the domain. The fourth
+ argument is a NULL terminated array of argument types. The fifth
+ argument is true if the function takes a variable number of
+ arguments, in which case the array of argument types indicates the
+ types of the first arguments. The domain and the argument array
+ may be NULL, in which case this is a stub method and that
+ information is not available. Stabs debugging uses this, and gets
+ the argument types from the mangled name. */
+
+extern debug_type debug_make_method_type
+ PARAMS ((PTR, debug_type, debug_type, debug_type *, boolean));
+
+/* Make a const qualified version of a given type. */
+
+extern debug_type debug_make_const_type PARAMS ((PTR, debug_type));
+
+/* Make a volatile qualified version of a given type. */
+
+extern debug_type debug_make_volatile_type PARAMS ((PTR, debug_type));
+
+/* Make an undefined tagged type. For example, a struct which has
+ been mentioned, but not defined. */
+
+extern debug_type debug_make_undefined_tagged_type
+ PARAMS ((PTR, const char *, enum debug_type_kind));
+
+/* Make a base class for an object. The second argument is the base
+ class type. The third argument is the bit position of this base
+ class in the object. The fourth argument is whether this is a
+ virtual class. The fifth argument is the visibility of the base
+ class. */
+
+extern debug_baseclass debug_make_baseclass
+ PARAMS ((PTR, debug_type, bfd_vma, boolean, enum debug_visibility));
+
+/* Make a field for a struct. The second argument is the name. The
+ third argument is the type of the field. The fourth argument is
+ the bit position of the field. The fifth argument is the size of
+ the field (it may be zero). The sixth argument is the visibility
+ of the field. */
+
+extern debug_field debug_make_field
+ PARAMS ((PTR, const char *, debug_type, bfd_vma, bfd_vma,
+ enum debug_visibility));
+
+/* Make a static member of an object. The second argument is the
+ name. The third argument is the type of the member. The fourth
+ argument is the physical name of the member (i.e., the name as a
+ global variable). The fifth argument is the visibility of the
+ member. */
+
+extern debug_field debug_make_static_member
+ PARAMS ((PTR, const char *, debug_type, const char *,
+ enum debug_visibility));
+
+/* Make a method. The second argument is the name, and the third
+ argument is a NULL terminated array of method variants. Each
+ method variant is a method with this name but with different
+ argument types. */
+
+extern debug_method debug_make_method
+ PARAMS ((PTR, const char *, debug_method_variant *));
+
+/* Make a method variant. The second argument is the physical name of
+ the function. The third argument is the type of the function,
+ probably constructed by debug_make_method_type. The fourth
+ argument is the visibility. The fifth argument is whether this is
+ a const function. The sixth argument is whether this is a volatile
+ function. The seventh argument is the index in the virtual
+ function table, if any. The eighth argument is the virtual
+ function context. */
+
+extern debug_method_variant debug_make_method_variant
+ PARAMS ((PTR, const char *, debug_type, enum debug_visibility, boolean,
+ boolean, bfd_vma, debug_type));
+
+/* Make a static method argument. The arguments are the same as for
+ debug_make_method_variant, except that the last two are omitted
+ since a static method can not also be virtual. */
+
+extern debug_method_variant debug_make_static_method_variant
+ PARAMS ((PTR, const char *, debug_type, enum debug_visibility, boolean,
+ boolean));
+
+/* Name a type. This returns a new type with an attached name. */
+
+extern debug_type debug_name_type PARAMS ((PTR, const char *, debug_type));
+
+/* Give a tag to a type, such as a struct or union. This returns a
+ new type with an attached tag. */
+
+extern debug_type debug_tag_type PARAMS ((PTR, const char *, debug_type));
+
+/* Record the size of a given type. */
+
+extern boolean debug_record_type_size PARAMS ((PTR, debug_type, unsigned int));
+
+/* Find a named type. */
+
+extern debug_type debug_find_named_type PARAMS ((PTR, const char *));
+
+/* Find a tagged type. */
+
+extern debug_type debug_find_tagged_type
+ PARAMS ((PTR, const char *, enum debug_type_kind));
+
+/* Get the kind of a type. */
+
+extern enum debug_type_kind debug_get_type_kind PARAMS ((PTR, debug_type));
+
+/* Get the name of a type. */
+
+extern const char *debug_get_type_name PARAMS ((PTR, debug_type));
+
+/* Get the size of a type. */
+
+extern bfd_vma debug_get_type_size PARAMS ((PTR, debug_type));
+
+/* Get the return type of a function or method type. */
+
+extern debug_type debug_get_return_type PARAMS ((PTR, debug_type));
+
+/* Get the NULL terminated array of parameter types for a function or
+ method type (actually, parameter types are not currently stored for
+ function types). This may be used to determine whether a method
+ type is a stub method or not. The last argument points to a
+ boolean which is set to true if the function takes a variable
+ number of arguments. */
+
+extern const debug_type *debug_get_parameter_types PARAMS ((PTR,
+ debug_type,
+ boolean *));
+
+/* Get the target type of a pointer or reference or const or volatile
+ type. */
+
+extern debug_type debug_get_target_type PARAMS ((PTR, debug_type));
+
+/* Get the NULL terminated array of fields for a struct, union, or
+ class. */
+
+extern const debug_field *debug_get_fields PARAMS ((PTR, debug_type));
+
+/* Get the type of a field. */
+
+extern debug_type debug_get_field_type PARAMS ((PTR, debug_field));
+
+/* Get the name of a field. */
+
+extern const char *debug_get_field_name PARAMS ((PTR, debug_field));
+
+/* Get the bit position of a field within the containing structure.
+ If the field is a static member, this will return (bfd_vma) -1. */
+
+extern bfd_vma debug_get_field_bitpos PARAMS ((PTR, debug_field));
+
+/* Get the bit size of a field. If the field is a static member, this
+ will return (bfd_vma) -1. */
+
+extern bfd_vma debug_get_field_bitsize PARAMS ((PTR, debug_field));
+
+/* Get the visibility of a field. */
+
+extern enum debug_visibility debug_get_field_visibility
+ PARAMS ((PTR, debug_field));
+
+/* Get the physical name of a field, if it is a static member. If the
+ field is not a static member, this will return NULL. */
+
+extern const char *debug_get_field_physname PARAMS ((PTR, debug_field));
+
+/* Write out the recorded debugging information. This takes a set of
+ function pointers which are called to do the actual writing. The
+ first PTR is the debugging handle. The second PTR is a handle
+ which is passed to the functions. */
+
+extern boolean debug_write PARAMS ((PTR, const struct debug_write_fns *, PTR));
+
+#endif /* DEBUG_H */
diff --git a/pstack/demangle.h b/pstack/demangle.h
new file mode 100644
index 00000000000..a961436ca77
--- /dev/null
+++ b/pstack/demangle.h
@@ -0,0 +1,90 @@
+/* Defs for interface to demanglers.
+ Copyright 1992, 1995, 1996 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+
+#if !defined (DEMANGLE_H)
+#define DEMANGLE_H
+
+#ifdef IN_GCC
+#include "gansidecl.h"
+#define PARAMS(ARGS) PROTO(ARGS)
+#else /* ! IN_GCC */
+#include <ansidecl.h>
+#endif /* IN_GCC */
+
+/* Options passed to cplus_demangle (in 2nd parameter). */
+
+#define DMGL_NO_OPTS 0 /* For readability... */
+#define DMGL_PARAMS (1 << 0) /* Include function args */
+#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
+#define DMGL_JAVA (1 << 2) /* Demangle as Java rather than C++. */
+
+#define DMGL_AUTO (1 << 8)
+#define DMGL_GNU (1 << 9)
+#define DMGL_LUCID (1 << 10)
+#define DMGL_ARM (1 << 11)
+/* If none of these are set, use 'current_demangling_style' as the default. */
+#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM)
+
+/* Enumeration of possible demangling styles.
+
+ Lucid and ARM styles are still kept logically distinct, even though
+ they now both behave identically. The resulting style is actual the
+ union of both. I.E. either style recognizes both "__pt__" and "__rf__"
+ for operator "->", even though the first is lucid style and the second
+ is ARM style. (FIXME?) */
+
+extern enum demangling_styles
+{
+ unknown_demangling = 0,
+ auto_demangling = DMGL_AUTO,
+ gnu_demangling = DMGL_GNU,
+ lucid_demangling = DMGL_LUCID,
+ arm_demangling = DMGL_ARM
+} current_demangling_style;
+
+/* Define string names for the various demangling styles. */
+
+#define AUTO_DEMANGLING_STYLE_STRING "auto"
+#define GNU_DEMANGLING_STYLE_STRING "gnu"
+#define LUCID_DEMANGLING_STYLE_STRING "lucid"
+#define ARM_DEMANGLING_STYLE_STRING "arm"
+
+/* Some macros to test what demangling style is active. */
+
+#define CURRENT_DEMANGLING_STYLE current_demangling_style
+#define AUTO_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_AUTO)
+#define GNU_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU)
+#define LUCID_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_LUCID)
+#define ARM_DEMANGLING (CURRENT_DEMANGLING_STYLE & DMGL_ARM)
+
+extern char *
+cplus_demangle PARAMS ((const char *mangled, int options));
+
+extern int
+cplus_demangle_opname PARAMS ((const char *opname, char *result, int options));
+
+extern const char *
+cplus_mangle_opname PARAMS ((const char *opname, int options));
+
+/* Note: This sets global state. FIXME if you care about multi-threading. */
+
+extern void
+set_cplus_marker_for_demangling PARAMS ((int ch));
+
+#endif /* DEMANGLE_H */
diff --git a/pstack/filemode.c b/pstack/filemode.c
new file mode 100644
index 00000000000..58b52ba7489
--- /dev/null
+++ b/pstack/filemode.c
@@ -0,0 +1,266 @@
+/* filemode.c -- make a string describing file modes
+ Copyright (C) 1985, 90, 91, 94, 95, 1997 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, 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 "bfd.h"
+#include "bucomm.h"
+
+static char ftypelet PARAMS ((unsigned long));
+static void setst PARAMS ((unsigned long, char *));
+
+/* filemodestring - fill in string STR with an ls-style ASCII
+ representation of the st_mode field of file stats block STATP.
+ 10 characters are stored in STR; no terminating null is added.
+ The characters stored in STR are:
+
+ 0 File type. 'd' for directory, 'c' for character
+ special, 'b' for block special, 'm' for multiplex,
+ 'l' for symbolic link, 's' for socket, 'p' for fifo,
+ '-' for any other file type
+
+ 1 'r' if the owner may read, '-' otherwise.
+
+ 2 'w' if the owner may write, '-' otherwise.
+
+ 3 'x' if the owner may execute, 's' if the file is
+ set-user-id, '-' otherwise.
+ 'S' if the file is set-user-id, but the execute
+ bit isn't set.
+
+ 4 'r' if group members may read, '-' otherwise.
+
+ 5 'w' if group members may write, '-' otherwise.
+
+ 6 'x' if group members may execute, 's' if the file is
+ set-group-id, '-' otherwise.
+ 'S' if it is set-group-id but not executable.
+
+ 7 'r' if any user may read, '-' otherwise.
+
+ 8 'w' if any user may write, '-' otherwise.
+
+ 9 'x' if any user may execute, 't' if the file is "sticky"
+ (will be retained in swap space after execution), '-'
+ otherwise.
+ 'T' if the file is sticky but not executable. */
+
+#if 0
+
+/* This is not used; only mode_string is used. */
+
+void
+filemodestring (statp, str)
+ struct stat *statp;
+ char *str;
+{
+ mode_string ((unsigned long) statp->st_mode, str);
+}
+
+#endif
+
+/* Get definitions for the file permission bits. */
+
+#ifndef S_IRWXU
+#define S_IRWXU 0700
+#endif
+#ifndef S_IRUSR
+#define S_IRUSR 0400
+#endif
+#ifndef S_IWUSR
+#define S_IWUSR 0200
+#endif
+#ifndef S_IXUSR
+#define S_IXUSR 0100
+#endif
+
+#ifndef S_IRWXG
+#define S_IRWXG 0070
+#endif
+#ifndef S_IRGRP
+#define S_IRGRP 0040
+#endif
+#ifndef S_IWGRP
+#define S_IWGRP 0020
+#endif
+#ifndef S_IXGRP
+#define S_IXGRP 0010
+#endif
+
+#ifndef S_IRWXO
+#define S_IRWXO 0007
+#endif
+#ifndef S_IROTH
+#define S_IROTH 0004
+#endif
+#ifndef S_IWOTH
+#define S_IWOTH 0002
+#endif
+#ifndef S_IXOTH
+#define S_IXOTH 0001
+#endif
+
+/* Like filemodestring, but only the relevant part of the `struct stat'
+ is given as an argument. */
+
+void
+mode_string (mode, str)
+ unsigned long mode;
+ char *str;
+{
+ str[0] = ftypelet ((unsigned long) mode);
+ str[1] = (mode & S_IRUSR) != 0 ? 'r' : '-';
+ str[2] = (mode & S_IWUSR) != 0 ? 'w' : '-';
+ str[3] = (mode & S_IXUSR) != 0 ? 'x' : '-';
+ str[4] = (mode & S_IRGRP) != 0 ? 'r' : '-';
+ str[5] = (mode & S_IWGRP) != 0 ? 'w' : '-';
+ str[6] = (mode & S_IXGRP) != 0 ? 'x' : '-';
+ str[7] = (mode & S_IROTH) != 0 ? 'r' : '-';
+ str[8] = (mode & S_IWOTH) != 0 ? 'w' : '-';
+ str[9] = (mode & S_IXOTH) != 0 ? 'x' : '-';
+ setst ((unsigned long) mode, str);
+}
+
+/* Return a character indicating the type of file described by
+ file mode BITS:
+ 'd' for directories
+ 'b' for block special files
+ 'c' for character special files
+ 'm' for multiplexor files
+ 'l' for symbolic links
+ 's' for sockets
+ 'p' for fifos
+ '-' for any other file type. */
+
+#ifndef S_ISDIR
+#ifdef S_IFDIR
+#define S_ISDIR(i) (((i) & S_IFMT) == S_IFDIR)
+#else /* ! defined (S_IFDIR) */
+#define S_ISDIR(i) (((i) & 0170000) == 040000)
+#endif /* ! defined (S_IFDIR) */
+#endif /* ! defined (S_ISDIR) */
+
+#ifndef S_ISBLK
+#ifdef S_IFBLK
+#define S_ISBLK(i) (((i) & S_IFMT) == S_IFBLK)
+#else /* ! defined (S_IFBLK) */
+#define S_ISBLK(i) 0
+#endif /* ! defined (S_IFBLK) */
+#endif /* ! defined (S_ISBLK) */
+
+#ifndef S_ISCHR
+#ifdef S_IFCHR
+#define S_ISCHR(i) (((i) & S_IFMT) == S_IFCHR)
+#else /* ! defined (S_IFCHR) */
+#define S_ISCHR(i) 0
+#endif /* ! defined (S_IFCHR) */
+#endif /* ! defined (S_ISCHR) */
+
+#ifndef S_ISFIFO
+#ifdef S_IFIFO
+#define S_ISFIFO(i) (((i) & S_IFMT) == S_IFIFO)
+#else /* ! defined (S_IFIFO) */
+#define S_ISFIFO(i) 0
+#endif /* ! defined (S_IFIFO) */
+#endif /* ! defined (S_ISFIFO) */
+
+#ifndef S_ISSOCK
+#ifdef S_IFSOCK
+#define S_ISSOCK(i) (((i) & S_IFMT) == S_IFSOCK)
+#else /* ! defined (S_IFSOCK) */
+#define S_ISSOCK(i) 0
+#endif /* ! defined (S_IFSOCK) */
+#endif /* ! defined (S_ISSOCK) */
+
+#ifndef S_ISLNK
+#ifdef S_IFLNK
+#define S_ISLNK(i) (((i) & S_IFMT) == S_IFLNK)
+#else /* ! defined (S_IFLNK) */
+#define S_ISLNK(i) 0
+#endif /* ! defined (S_IFLNK) */
+#endif /* ! defined (S_ISLNK) */
+
+static char
+ftypelet (bits)
+ unsigned long bits;
+{
+ if (S_ISDIR (bits))
+ return 'd';
+ if (S_ISLNK (bits))
+ return 'l';
+ if (S_ISBLK (bits))
+ return 'b';
+ if (S_ISCHR (bits))
+ return 'c';
+ if (S_ISSOCK (bits))
+ return 's';
+ if (S_ISFIFO (bits))
+ return 'p';
+
+#ifdef S_IFMT
+#ifdef S_IFMPC
+ if ((bits & S_IFMT) == S_IFMPC
+ || (bits & S_IFMT) == S_IFMPB)
+ return 'm';
+#endif
+#ifdef S_IFNWK
+ if ((bits & S_IFMT) == S_IFNWK)
+ return 'n';
+#endif
+#endif
+
+ return '-';
+}
+
+/* Set the 's' and 't' flags in file attributes string CHARS,
+ according to the file mode BITS. */
+
+static void
+setst (bits, chars)
+ unsigned long bits;
+ char *chars;
+{
+#ifdef S_ISUID
+ if (bits & S_ISUID)
+ {
+ if (chars[3] != 'x')
+ /* Set-uid, but not executable by owner. */
+ chars[3] = 'S';
+ else
+ chars[3] = 's';
+ }
+#endif
+#ifdef S_ISGID
+ if (bits & S_ISGID)
+ {
+ if (chars[6] != 'x')
+ /* Set-gid, but not executable by group. */
+ chars[6] = 'S';
+ else
+ chars[6] = 's';
+ }
+#endif
+#ifdef S_ISVTX
+ if (bits & S_ISVTX)
+ {
+ if (chars[9] != 'x')
+ /* Sticky, but not executable by others. */
+ chars[9] = 'T';
+ else
+ chars[9] = 't';
+ }
+#endif
+}
diff --git a/pstack/ieee.c b/pstack/ieee.c
new file mode 100644
index 00000000000..8084656a5ef
--- /dev/null
+++ b/pstack/ieee.c
@@ -0,0 +1,7602 @@
+/* ieee.c -- Read and write IEEE-695 debugging information.
+ Copyright (C) 1996 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <ian@cygnus.com>.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; 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 reads and writes IEEE-695 debugging information. */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include <bfd.h>
+#include "ieee.h"
+#include "bucomm.h"
+#include <libiberty.h>
+#include "debug.h"
+#include "budbg.h"
+
+/* This structure holds an entry on the block stack. */
+
+struct ieee_block
+{
+ /* The kind of block. */
+ int kind;
+ /* The source file name, for a BB5 block. */
+ const char *filename;
+ /* The index of the function type, for a BB4 or BB6 block. */
+ unsigned int fnindx;
+ /* True if this function is being skipped. */
+ boolean skip;
+};
+
+/* This structure is the block stack. */
+
+#define BLOCKSTACK_SIZE (16)
+
+struct ieee_blockstack
+{
+ /* The stack pointer. */
+ struct ieee_block *bsp;
+ /* The stack. */
+ struct ieee_block stack[BLOCKSTACK_SIZE];
+};
+
+/* This structure holds information for a variable. */
+
+struct ieee_var
+{
+ /* Start of name. */
+ const char *name;
+ /* Length of name. */
+ unsigned long namlen;
+ /* Type. */
+ debug_type type;
+ /* Slot if we make an indirect type. */
+ debug_type *pslot;
+ /* Kind of variable or function. */
+ enum
+ {
+ IEEE_UNKNOWN,
+ IEEE_EXTERNAL,
+ IEEE_GLOBAL,
+ IEEE_STATIC,
+ IEEE_LOCAL,
+ IEEE_FUNCTION
+ } kind;
+};
+
+/* This structure holds all the variables. */
+
+struct ieee_vars
+{
+ /* Number of slots allocated. */
+ unsigned int alloc;
+ /* Variables. */
+ struct ieee_var *vars;
+};
+
+/* This structure holds information for a type. We need this because
+ we don't want to represent bitfields as real types. */
+
+struct ieee_type
+{
+ /* Type. */
+ debug_type type;
+ /* Slot if this is type is referenced before it is defined. */
+ debug_type *pslot;
+ /* Slots for arguments if we make indirect types for them. */
+ debug_type *arg_slots;
+ /* If this is a bitfield, this is the size in bits. If this is not
+ a bitfield, this is zero. */
+ unsigned long bitsize;
+};
+
+/* This structure holds all the type information. */
+
+struct ieee_types
+{
+ /* Number of slots allocated. */
+ unsigned int alloc;
+ /* Types. */
+ struct ieee_type *types;
+ /* Builtin types. */
+#define BUILTIN_TYPE_COUNT (60)
+ debug_type builtins[BUILTIN_TYPE_COUNT];
+};
+
+/* This structure holds a linked last of structs with their tag names,
+ so that we can convert them to C++ classes if necessary. */
+
+struct ieee_tag
+{
+ /* Next tag. */
+ struct ieee_tag *next;
+ /* This tag name. */
+ const char *name;
+ /* The type of the tag. */
+ debug_type type;
+ /* The tagged type is an indirect type pointing at this slot. */
+ debug_type slot;
+ /* This is an array of slots used when a field type is converted
+ into a indirect type, in case it needs to be later converted into
+ a reference type. */
+ debug_type *fslots;
+};
+
+/* This structure holds the information we pass around to the parsing
+ functions. */
+
+struct ieee_info
+{
+ /* The debugging handle. */
+ PTR dhandle;
+ /* The BFD. */
+ bfd *abfd;
+ /* The start of the bytes to be parsed. */
+ const bfd_byte *bytes;
+ /* The end of the bytes to be parsed. */
+ const bfd_byte *pend;
+ /* The block stack. */
+ struct ieee_blockstack blockstack;
+ /* Whether we have seen a BB1 or BB2. */
+ boolean saw_filename;
+ /* The variables. */
+ struct ieee_vars vars;
+ /* The global variables, after a global typedef block. */
+ struct ieee_vars *global_vars;
+ /* The types. */
+ struct ieee_types types;
+ /* The global types, after a global typedef block. */
+ struct ieee_types *global_types;
+ /* The list of tagged structs. */
+ struct ieee_tag *tags;
+};
+
+/* Basic builtin types, not including the pointers. */
+
+enum builtin_types
+{
+ builtin_unknown = 0,
+ builtin_void = 1,
+ builtin_signed_char = 2,
+ builtin_unsigned_char = 3,
+ builtin_signed_short_int = 4,
+ builtin_unsigned_short_int = 5,
+ builtin_signed_long = 6,
+ builtin_unsigned_long = 7,
+ builtin_signed_long_long = 8,
+ builtin_unsigned_long_long = 9,
+ builtin_float = 10,
+ builtin_double = 11,
+ builtin_long_double = 12,
+ builtin_long_long_double = 13,
+ builtin_quoted_string = 14,
+ builtin_instruction_address = 15,
+ builtin_int = 16,
+ builtin_unsigned = 17,
+ builtin_unsigned_int = 18,
+ builtin_char = 19,
+ builtin_long = 20,
+ builtin_short = 21,
+ builtin_unsigned_short = 22,
+ builtin_short_int = 23,
+ builtin_signed_short = 24,
+ builtin_bcd_float = 25
+};
+
+/* These are the values found in the derivation flags of a 'b'
+ component record of a 'T' type extension record in a C++ pmisc
+ record. These are bitmasks. */
+
+/* Set for a private base class, clear for a public base class.
+ Protected base classes are not supported. */
+#define BASEFLAGS_PRIVATE (0x1)
+/* Set for a virtual base class. */
+#define BASEFLAGS_VIRTUAL (0x2)
+/* Set for a friend class, clear for a base class. */
+#define BASEFLAGS_FRIEND (0x10)
+
+/* These are the values found in the specs flags of a 'd', 'm', or 'v'
+ component record of a 'T' type extension record in a C++ pmisc
+ record. The same flags are used for a 'M' record in a C++ pmisc
+ record. */
+
+/* The lower two bits hold visibility information. */
+#define CXXFLAGS_VISIBILITY (0x3)
+/* This value in the lower two bits indicates a public member. */
+#define CXXFLAGS_VISIBILITY_PUBLIC (0x0)
+/* This value in the lower two bits indicates a private member. */
+#define CXXFLAGS_VISIBILITY_PRIVATE (0x1)
+/* This value in the lower two bits indicates a protected member. */
+#define CXXFLAGS_VISIBILITY_PROTECTED (0x2)
+/* Set for a static member. */
+#define CXXFLAGS_STATIC (0x4)
+/* Set for a virtual override. */
+#define CXXFLAGS_OVERRIDE (0x8)
+/* Set for a friend function. */
+#define CXXFLAGS_FRIEND (0x10)
+/* Set for a const function. */
+#define CXXFLAGS_CONST (0x20)
+/* Set for a volatile function. */
+#define CXXFLAGS_VOLATILE (0x40)
+/* Set for an overloaded function. */
+#define CXXFLAGS_OVERLOADED (0x80)
+/* Set for an operator function. */
+#define CXXFLAGS_OPERATOR (0x100)
+/* Set for a constructor or destructor. */
+#define CXXFLAGS_CTORDTOR (0x400)
+/* Set for a constructor. */
+#define CXXFLAGS_CTOR (0x200)
+/* Set for an inline function. */
+#define CXXFLAGS_INLINE (0x800)
+
+/* Local functions. */
+
+static void ieee_error
+ PARAMS ((struct ieee_info *, const bfd_byte *, const char *));
+static void ieee_eof PARAMS ((struct ieee_info *));
+static char *savestring PARAMS ((const char *, unsigned long));
+static boolean ieee_read_number
+ PARAMS ((struct ieee_info *, const bfd_byte **, bfd_vma *));
+static boolean ieee_read_optional_number
+ PARAMS ((struct ieee_info *, const bfd_byte **, bfd_vma *, boolean *));
+static boolean ieee_read_id
+ PARAMS ((struct ieee_info *, const bfd_byte **, const char **,
+ unsigned long *));
+static boolean ieee_read_optional_id
+ PARAMS ((struct ieee_info *, const bfd_byte **, const char **,
+ unsigned long *, boolean *));
+static boolean ieee_read_expression
+ PARAMS ((struct ieee_info *, const bfd_byte **, bfd_vma *));
+static debug_type ieee_builtin_type
+ PARAMS ((struct ieee_info *, const bfd_byte *, unsigned int));
+static boolean ieee_alloc_type
+ PARAMS ((struct ieee_info *, unsigned int, boolean));
+static boolean ieee_read_type_index
+ PARAMS ((struct ieee_info *, const bfd_byte **, debug_type *));
+static int ieee_regno_to_genreg PARAMS ((bfd *, int));
+static int ieee_genreg_to_regno PARAMS ((bfd *, int));
+static boolean parse_ieee_bb PARAMS ((struct ieee_info *, const bfd_byte **));
+static boolean parse_ieee_be PARAMS ((struct ieee_info *, const bfd_byte **));
+static boolean parse_ieee_nn PARAMS ((struct ieee_info *, const bfd_byte **));
+static boolean parse_ieee_ty PARAMS ((struct ieee_info *, const bfd_byte **));
+static boolean parse_ieee_atn PARAMS ((struct ieee_info *, const bfd_byte **));
+static boolean ieee_read_cxx_misc
+ PARAMS ((struct ieee_info *, const bfd_byte **, unsigned long));
+static boolean ieee_read_cxx_class
+ PARAMS ((struct ieee_info *, const bfd_byte **, unsigned long));
+static boolean ieee_read_cxx_defaults
+ PARAMS ((struct ieee_info *, const bfd_byte **, unsigned long));
+static boolean ieee_read_reference
+ PARAMS ((struct ieee_info *, const bfd_byte **));
+static boolean ieee_require_asn
+ PARAMS ((struct ieee_info *, const bfd_byte **, bfd_vma *));
+static boolean ieee_require_atn65
+ PARAMS ((struct ieee_info *, const bfd_byte **, const char **,
+ unsigned long *));
+
+/* Report an error in the IEEE debugging information. */
+
+static void
+ieee_error (info, p, s)
+ struct ieee_info *info;
+ const bfd_byte *p;
+ const char *s;
+{
+ if (p != NULL)
+ fprintf (stderr, "%s: 0x%lx: %s (0x%x)\n", bfd_get_filename (info->abfd),
+ (unsigned long) (p - info->bytes), s, *p);
+ else
+ fprintf (stderr, "%s: %s\n", bfd_get_filename (info->abfd), s);
+}
+
+/* Report an unexpected EOF in the IEEE debugging information. */
+
+static void
+ieee_eof (info)
+ struct ieee_info *info;
+{
+ ieee_error (info, (const bfd_byte *) NULL,
+ "unexpected end of debugging information");
+}
+
+/* Save a string in memory. */
+
+static char *
+savestring (start, len)
+ const char *start;
+ unsigned long len;
+{
+ char *ret;
+
+ ret = (char *) xmalloc (len + 1);
+ memcpy (ret, start, len);
+ ret[len] = '\0';
+ return ret;
+}
+
+/* Read a number which must be present in an IEEE file. */
+
+static boolean
+ieee_read_number (info, pp, pv)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+ bfd_vma *pv;
+{
+ return ieee_read_optional_number (info, pp, pv, (boolean *) NULL);
+}
+
+/* Read a number in an IEEE file. If ppresent is not NULL, the number
+ need not be there. */
+
+static boolean
+ieee_read_optional_number (info, pp, pv, ppresent)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+ bfd_vma *pv;
+ boolean *ppresent;
+{
+ ieee_record_enum_type b;
+
+ if (*pp >= info->pend)
+ {
+ if (ppresent != NULL)
+ {
+ *ppresent = false;
+ return true;
+ }
+ ieee_eof (info);
+ return false;
+ }
+
+ b = (ieee_record_enum_type) **pp;
+ ++*pp;
+
+ if (b <= ieee_number_end_enum)
+ {
+ *pv = (bfd_vma) b;
+ if (ppresent != NULL)
+ *ppresent = true;
+ return true;
+ }
+
+ if (b >= ieee_number_repeat_start_enum && b <= ieee_number_repeat_end_enum)
+ {
+ unsigned int i;
+
+ i = (int) b - (int) ieee_number_repeat_start_enum;
+ if (*pp + i - 1 >= info->pend)
+ {
+ ieee_eof (info);
+ return false;
+ }
+
+ *pv = 0;
+ for (; i > 0; i--)
+ {
+ *pv <<= 8;
+ *pv += **pp;
+ ++*pp;
+ }
+
+ if (ppresent != NULL)
+ *ppresent = true;
+
+ return true;
+ }
+
+ if (ppresent != NULL)
+ {
+ --*pp;
+ *ppresent = false;
+ return true;
+ }
+
+ ieee_error (info, *pp - 1, "invalid number");
+ return false;
+}
+
+/* Read a required string from an IEEE file. */
+
+static boolean
+ieee_read_id (info, pp, pname, pnamlen)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+ const char **pname;
+ unsigned long *pnamlen;
+{
+ return ieee_read_optional_id (info, pp, pname, pnamlen, (boolean *) NULL);
+}
+
+/* Read a string from an IEEE file. If ppresent is not NULL, the
+ string is optional. */
+
+static boolean
+ieee_read_optional_id (info, pp, pname, pnamlen, ppresent)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+ const char **pname;
+ unsigned long *pnamlen;
+ boolean *ppresent;
+{
+ bfd_byte b;
+ unsigned long len;
+
+ if (*pp >= info->pend)
+ {
+ ieee_eof (info);
+ return false;
+ }
+
+ b = **pp;
+ ++*pp;
+
+ if (b <= 0x7f)
+ len = b;
+ else if ((ieee_record_enum_type) b == ieee_extension_length_1_enum)
+ {
+ len = **pp;
+ ++*pp;
+ }
+ else if ((ieee_record_enum_type) b == ieee_extension_length_2_enum)
+ {
+ len = (**pp << 8) + (*pp)[1];
+ *pp += 2;
+ }
+ else
+ {
+ if (ppresent != NULL)
+ {
+ --*pp;
+ *ppresent = false;
+ return true;
+ }
+ ieee_error (info, *pp - 1, "invalid string length");
+ return false;
+ }
+
+ if ((unsigned long) (info->pend - *pp) < len)
+ {
+ ieee_eof (info);
+ return false;
+ }
+
+ *pname = (const char *) *pp;
+ *pnamlen = len;
+ *pp += len;
+
+ if (ppresent != NULL)
+ *ppresent = true;
+
+ return true;
+}
+
+/* Read an expression from an IEEE file. Since this code is only used
+ to parse debugging information, I haven't bothered to write a full
+ blown IEEE expression parser. I've only thrown in the things I've
+ seen in debugging information. This can be easily extended if
+ necessary. */
+
+static boolean
+ieee_read_expression (info, pp, pv)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+ bfd_vma *pv;
+{
+ const bfd_byte *expr_start;
+#define EXPR_STACK_SIZE (10)
+ bfd_vma expr_stack[EXPR_STACK_SIZE];
+ bfd_vma *esp;
+
+ expr_start = *pp;
+
+ esp = expr_stack;
+
+ while (1)
+ {
+ const bfd_byte *start;
+ bfd_vma val;
+ boolean present;
+ ieee_record_enum_type c;
+
+ start = *pp;
+
+ if (! ieee_read_optional_number (info, pp, &val, &present))
+ return false;
+
+ if (present)
+ {
+ if (esp - expr_stack >= EXPR_STACK_SIZE)
+ {
+ ieee_error (info, start, "expression stack overflow");
+ return false;
+ }
+ *esp++ = val;
+ continue;
+ }
+
+ c = (ieee_record_enum_type) **pp;
+
+ if (c >= ieee_module_beginning_enum)
+ break;
+
+ ++*pp;
+
+ if (c == ieee_comma)
+ break;
+
+ switch (c)
+ {
+ default:
+ ieee_error (info, start, "unsupported IEEE expression operator");
+ break;
+
+ case ieee_variable_R_enum:
+ {
+ bfd_vma indx;
+ asection *s;
+
+ if (! ieee_read_number (info, pp, &indx))
+ return false;
+ for (s = info->abfd->sections; s != NULL; s = s->next)
+ if ((bfd_vma) s->target_index == indx)
+ break;
+ if (s == NULL)
+ {
+ ieee_error (info, start, "unknown section");
+ return false;
+ }
+
+ if (esp - expr_stack >= EXPR_STACK_SIZE)
+ {
+ ieee_error (info, start, "expression stack overflow");
+ return false;
+ }
+
+ *esp++ = bfd_get_section_vma (info->abfd, s);
+ }
+ break;
+
+ case ieee_function_plus_enum:
+ case ieee_function_minus_enum:
+ {
+ bfd_vma v1, v2;
+
+ if (esp - expr_stack < 2)
+ {
+ ieee_error (info, start, "expression stack underflow");
+ return false;
+ }
+
+ v1 = *--esp;
+ v2 = *--esp;
+ *esp++ = v1 + v2;
+ }
+ break;
+ }
+ }
+
+ if (esp - 1 != expr_stack)
+ {
+ ieee_error (info, expr_start, "expression stack mismatch");
+ return false;
+ }
+
+ *pv = *--esp;
+
+ return true;
+}
+
+/* Return an IEEE builtin type. */
+
+static debug_type
+ieee_builtin_type (info, p, indx)
+ struct ieee_info *info;
+ const bfd_byte *p;
+ unsigned int indx;
+{
+ PTR dhandle;
+ debug_type type;
+ const char *name;
+
+ if (indx < BUILTIN_TYPE_COUNT
+ && info->types.builtins[indx] != DEBUG_TYPE_NULL)
+ return info->types.builtins[indx];
+
+ dhandle = info->dhandle;
+
+ if (indx >= 32 && indx < 64)
+ {
+ type = debug_make_pointer_type (dhandle,
+ ieee_builtin_type (info, p, indx - 32));
+ assert (indx < BUILTIN_TYPE_COUNT);
+ info->types.builtins[indx] = type;
+ return type;
+ }
+
+ switch ((enum builtin_types) indx)
+ {
+ default:
+ ieee_error (info, p, "unknown builtin type");
+ return NULL;
+
+ case builtin_unknown:
+ type = debug_make_void_type (dhandle);
+ name = NULL;
+ break;
+
+ case builtin_void:
+ type = debug_make_void_type (dhandle);
+ name = "void";
+ break;
+
+ case builtin_signed_char:
+ type = debug_make_int_type (dhandle, 1, false);
+ name = "signed char";
+ break;
+
+ case builtin_unsigned_char:
+ type = debug_make_int_type (dhandle, 1, true);
+ name = "unsigned char";
+ break;
+
+ case builtin_signed_short_int:
+ type = debug_make_int_type (dhandle, 2, false);
+ name = "signed short int";
+ break;
+
+ case builtin_unsigned_short_int:
+ type = debug_make_int_type (dhandle, 2, true);
+ name = "unsigned short int";
+ break;
+
+ case builtin_signed_long:
+ type = debug_make_int_type (dhandle, 4, false);
+ name = "signed long";
+ break;
+
+ case builtin_unsigned_long:
+ type = debug_make_int_type (dhandle, 4, true);
+ name = "unsigned long";
+ break;
+
+ case builtin_signed_long_long:
+ type = debug_make_int_type (dhandle, 8, false);
+ name = "signed long long";
+ break;
+
+ case builtin_unsigned_long_long:
+ type = debug_make_int_type (dhandle, 8, true);
+ name = "unsigned long long";
+ break;
+
+ case builtin_float:
+ type = debug_make_float_type (dhandle, 4);
+ name = "float";
+ break;
+
+ case builtin_double:
+ type = debug_make_float_type (dhandle, 8);
+ name = "double";
+ break;
+
+ case builtin_long_double:
+ /* FIXME: The size for this type should depend upon the
+ processor. */
+ type = debug_make_float_type (dhandle, 12);
+ name = "long double";
+ break;
+
+ case builtin_long_long_double:
+ type = debug_make_float_type (dhandle, 16);
+ name = "long long double";
+ break;
+
+ case builtin_quoted_string:
+ type = debug_make_array_type (dhandle,
+ ieee_builtin_type (info, p,
+ ((unsigned int)
+ builtin_char)),
+ ieee_builtin_type (info, p,
+ ((unsigned int)
+ builtin_int)),
+ 0, -1, true);
+ name = "QUOTED STRING";
+ break;
+
+ case builtin_instruction_address:
+ /* FIXME: This should be a code address. */
+ type = debug_make_int_type (dhandle, 4, true);
+ name = "instruction address";
+ break;
+
+ case builtin_int:
+ /* FIXME: The size for this type should depend upon the
+ processor. */
+ type = debug_make_int_type (dhandle, 4, false);
+ name = "int";
+ break;
+
+ case builtin_unsigned:
+ /* FIXME: The size for this type should depend upon the
+ processor. */
+ type = debug_make_int_type (dhandle, 4, true);
+ name = "unsigned";
+ break;
+
+ case builtin_unsigned_int:
+ /* FIXME: The size for this type should depend upon the
+ processor. */
+ type = debug_make_int_type (dhandle, 4, true);
+ name = "unsigned int";
+ break;
+
+ case builtin_char:
+ type = debug_make_int_type (dhandle, 1, false);
+ name = "char";
+ break;
+
+ case builtin_long:
+ type = debug_make_int_type (dhandle, 4, false);
+ name = "long";
+ break;
+
+ case builtin_short:
+ type = debug_make_int_type (dhandle, 2, false);
+ name = "short";
+ break;
+
+ case builtin_unsigned_short:
+ type = debug_make_int_type (dhandle, 2, true);
+ name = "unsigned short";
+ break;
+
+ case builtin_short_int:
+ type = debug_make_int_type (dhandle, 2, false);
+ name = "short int";
+ break;
+
+ case builtin_signed_short:
+ type = debug_make_int_type (dhandle, 2, false);
+ name = "signed short";
+ break;
+
+ case builtin_bcd_float:
+ ieee_error (info, p, "BCD float type not supported");
+ return DEBUG_TYPE_NULL;
+ }
+
+ if (name != NULL)
+ type = debug_name_type (dhandle, name, type);
+
+ assert (indx < BUILTIN_TYPE_COUNT);
+
+ info->types.builtins[indx] = type;
+
+ return type;
+}
+
+/* Allocate more space in the type table. If ref is true, this is a
+ reference to the type; if it is not already defined, we should set
+ up an indirect type. */
+
+static boolean
+ieee_alloc_type (info, indx, ref)
+ struct ieee_info *info;
+ unsigned int indx;
+ boolean ref;
+{
+ unsigned int nalloc;
+ register struct ieee_type *t;
+ struct ieee_type *tend;
+
+ if (indx >= info->types.alloc)
+ {
+ nalloc = info->types.alloc;
+ if (nalloc == 0)
+ nalloc = 4;
+ while (indx >= nalloc)
+ nalloc *= 2;
+
+ info->types.types = ((struct ieee_type *)
+ xrealloc (info->types.types,
+ nalloc * sizeof *info->types.types));
+
+ memset (info->types.types + info->types.alloc, 0,
+ (nalloc - info->types.alloc) * sizeof *info->types.types);
+
+ tend = info->types.types + nalloc;
+ for (t = info->types.types + info->types.alloc; t < tend; t++)
+ t->type = DEBUG_TYPE_NULL;
+
+ info->types.alloc = nalloc;
+ }
+
+ if (ref)
+ {
+ t = info->types.types + indx;
+ if (t->type == NULL)
+ {
+ t->pslot = (debug_type *) xmalloc (sizeof *t->pslot);
+ *t->pslot = DEBUG_TYPE_NULL;
+ t->type = debug_make_indirect_type (info->dhandle, t->pslot,
+ (const char *) NULL);
+ if (t->type == NULL)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* Read a type index and return the corresponding type. */
+
+static boolean
+ieee_read_type_index (info, pp, ptype)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+ debug_type *ptype;
+{
+ const bfd_byte *start;
+ bfd_vma indx;
+
+ start = *pp;
+
+ if (! ieee_read_number (info, pp, &indx))
+ return false;
+
+ if (indx < 256)
+ {
+ *ptype = ieee_builtin_type (info, start, indx);
+ if (*ptype == NULL)
+ return false;
+ return true;
+ }
+
+ indx -= 256;
+ if (! ieee_alloc_type (info, indx, true))
+ return false;
+
+ *ptype = info->types.types[indx].type;
+
+ return true;
+}
+
+/* Parse IEEE debugging information for a file. This is passed the
+ bytes which compose the Debug Information Part of an IEEE file. */
+
+boolean
+parse_ieee (dhandle, abfd, bytes, len)
+ PTR dhandle;
+ bfd *abfd;
+ const bfd_byte *bytes;
+ bfd_size_type len;
+{
+ struct ieee_info info;
+ unsigned int i;
+ const bfd_byte *p, *pend;
+
+ info.dhandle = dhandle;
+ info.abfd = abfd;
+ info.bytes = bytes;
+ info.pend = bytes + len;
+ info.blockstack.bsp = info.blockstack.stack;
+ info.saw_filename = false;
+ info.vars.alloc = 0;
+ info.vars.vars = NULL;
+ info.types.alloc = 0;
+ info.types.types = NULL;
+ info.tags = NULL;
+ for (i = 0; i < BUILTIN_TYPE_COUNT; i++)
+ info.types.builtins[i] = DEBUG_TYPE_NULL;
+
+ p = bytes;
+ pend = info.pend;
+ while (p < pend)
+ {
+ const bfd_byte *record_start;
+ ieee_record_enum_type c;
+
+ record_start = p;
+
+ c = (ieee_record_enum_type) *p++;
+
+ if (c == ieee_at_record_enum)
+ c = (ieee_record_enum_type) (((unsigned int) c << 8) | *p++);
+
+ if (c <= ieee_number_repeat_end_enum)
+ {
+ ieee_error (&info, record_start, "unexpected number");
+ return false;
+ }
+
+ switch (c)
+ {
+ default:
+ ieee_error (&info, record_start, "unexpected record type");
+ return false;
+
+ case ieee_bb_record_enum:
+ if (! parse_ieee_bb (&info, &p))
+ return false;
+ break;
+
+ case ieee_be_record_enum:
+ if (! parse_ieee_be (&info, &p))
+ return false;
+ break;
+
+ case ieee_nn_record:
+ if (! parse_ieee_nn (&info, &p))
+ return false;
+ break;
+
+ case ieee_ty_record_enum:
+ if (! parse_ieee_ty (&info, &p))
+ return false;
+ break;
+
+ case ieee_atn_record_enum:
+ if (! parse_ieee_atn (&info, &p))
+ return false;
+ break;
+ }
+ }
+
+ if (info.blockstack.bsp != info.blockstack.stack)
+ {
+ ieee_error (&info, (const bfd_byte *) NULL,
+ "blocks left on stack at end");
+ return false;
+ }
+
+ return true;
+}
+
+/* Handle an IEEE BB record. */
+
+static boolean
+parse_ieee_bb (info, pp)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+{
+ const bfd_byte *block_start;
+ bfd_byte b;
+ bfd_vma size;
+ const char *name;
+ unsigned long namlen;
+ char *namcopy = NULL;
+ unsigned int fnindx;
+ boolean skip;
+
+ block_start = *pp;
+
+ b = **pp;
+ ++*pp;
+
+ if (! ieee_read_number (info, pp, &size)
+ || ! ieee_read_id (info, pp, &name, &namlen))
+ return false;
+
+ fnindx = (unsigned int) -1;
+ skip = false;
+
+ switch (b)
+ {
+ case 1:
+ /* BB1: Type definitions local to a module. */
+ namcopy = savestring (name, namlen);
+ if (namcopy == NULL)
+ return false;
+ if (! debug_set_filename (info->dhandle, namcopy))
+ return false;
+ info->saw_filename = true;
+
+ /* Discard any variables or types we may have seen before. */
+ if (info->vars.vars != NULL)
+ free (info->vars.vars);
+ info->vars.vars = NULL;
+ info->vars.alloc = 0;
+ if (info->types.types != NULL)
+ free (info->types.types);
+ info->types.types = NULL;
+ info->types.alloc = 0;
+
+ /* Initialize the types to the global types. */
+ if (info->global_types != NULL)
+ {
+ info->types.alloc = info->global_types->alloc;
+ info->types.types = ((struct ieee_type *)
+ xmalloc (info->types.alloc
+ * sizeof (*info->types.types)));
+ memcpy (info->types.types, info->global_types->types,
+ info->types.alloc * sizeof (*info->types.types));
+ }
+
+ break;
+
+ case 2:
+ /* BB2: Global type definitions. The name is supposed to be
+ empty, but we don't check. */
+ if (! debug_set_filename (info->dhandle, "*global*"))
+ return false;
+ info->saw_filename = true;
+ break;
+
+ case 3:
+ /* BB3: High level module block begin. We don't have to do
+ anything here. The name is supposed to be the same as for
+ the BB1, but we don't check. */
+ break;
+
+ case 4:
+ /* BB4: Global function. */
+ {
+ bfd_vma stackspace, typindx, offset;
+ debug_type return_type;
+
+ if (! ieee_read_number (info, pp, &stackspace)
+ || ! ieee_read_number (info, pp, &typindx)
+ || ! ieee_read_expression (info, pp, &offset))
+ return false;
+
+ /* We have no way to record the stack space. FIXME. */
+
+ if (typindx < 256)
+ {
+ return_type = ieee_builtin_type (info, block_start, typindx);
+ if (return_type == DEBUG_TYPE_NULL)
+ return false;
+ }
+ else
+ {
+ typindx -= 256;
+ if (! ieee_alloc_type (info, typindx, true))
+ return false;
+ fnindx = typindx;
+ return_type = info->types.types[typindx].type;
+ if (debug_get_type_kind (info->dhandle, return_type)
+ == DEBUG_KIND_FUNCTION)
+ return_type = debug_get_return_type (info->dhandle,
+ return_type);
+ }
+
+ namcopy = savestring (name, namlen);
+ if (namcopy == NULL)
+ return false;
+ if (! debug_record_function (info->dhandle, namcopy, return_type,
+ true, offset))
+ return false;
+ }
+ break;
+
+ case 5:
+ /* BB5: File name for source line numbers. */
+ {
+ unsigned int i;
+
+ /* We ignore the date and time. FIXME. */
+ for (i = 0; i < 6; i++)
+ {
+ bfd_vma ignore;
+ boolean present;
+
+ if (! ieee_read_optional_number (info, pp, &ignore, &present))
+ return false;
+ if (! present)
+ break;
+ }
+
+ namcopy = savestring (name, namlen);
+ if (namcopy == NULL)
+ return false;
+ if (! debug_start_source (info->dhandle, namcopy))
+ return false;
+ }
+ break;
+
+ case 6:
+ /* BB6: Local function or block. */
+ {
+ bfd_vma stackspace, typindx, offset;
+
+ if (! ieee_read_number (info, pp, &stackspace)
+ || ! ieee_read_number (info, pp, &typindx)
+ || ! ieee_read_expression (info, pp, &offset))
+ return false;
+
+ /* We have no way to record the stack space. FIXME. */
+
+ if (namlen == 0)
+ {
+ if (! debug_start_block (info->dhandle, offset))
+ return false;
+ /* Change b to indicate that this is a block
+ rather than a function. */
+ b = 0x86;
+ }
+ else
+ {
+ /* The MRI C++ compiler will output a fake function named
+ __XRYCPP to hold C++ debugging information. We skip
+ that function. This is not crucial, but it makes
+ converting from IEEE to other debug formats work
+ better. */
+ if (strncmp (name, "__XRYCPP", namlen) == 0)
+ skip = true;
+ else
+ {
+ debug_type return_type;
+
+ if (typindx < 256)
+ {
+ return_type = ieee_builtin_type (info, block_start,
+ typindx);
+ if (return_type == NULL)
+ return false;
+ }
+ else
+ {
+ typindx -= 256;
+ if (! ieee_alloc_type (info, typindx, true))
+ return false;
+ fnindx = typindx;
+ return_type = info->types.types[typindx].type;
+ if (debug_get_type_kind (info->dhandle, return_type)
+ == DEBUG_KIND_FUNCTION)
+ return_type = debug_get_return_type (info->dhandle,
+ return_type);
+ }
+
+ namcopy = savestring (name, namlen);
+ if (namcopy == NULL)
+ return false;
+ if (! debug_record_function (info->dhandle, namcopy,
+ return_type, false, offset))
+ return false;
+ }
+ }
+ }
+ break;
+
+ case 10:
+ /* BB10: Assembler module scope. In the normal case, we
+ completely ignore all this information. FIXME. */
+ {
+ const char *inam, *vstr;
+ unsigned long inamlen, vstrlen;
+ bfd_vma tool_type;
+ boolean present;
+ unsigned int i;
+
+ if (! info->saw_filename)
+ {
+ namcopy = savestring (name, namlen);
+ if (namcopy == NULL)
+ return false;
+ if (! debug_set_filename (info->dhandle, namcopy))
+ return false;
+ info->saw_filename = true;
+ }
+
+ if (! ieee_read_id (info, pp, &inam, &inamlen)
+ || ! ieee_read_number (info, pp, &tool_type)
+ || ! ieee_read_optional_id (info, pp, &vstr, &vstrlen, &present))
+ return false;
+ for (i = 0; i < 6; i++)
+ {
+ bfd_vma ignore;
+
+ if (! ieee_read_optional_number (info, pp, &ignore, &present))
+ return false;
+ if (! present)
+ break;
+ }
+ }
+ break;
+
+ case 11:
+ /* BB11: Module section. We completely ignore all this
+ information. FIXME. */
+ {
+ bfd_vma sectype, secindx, offset, map;
+ boolean present;
+
+ if (! ieee_read_number (info, pp, &sectype)
+ || ! ieee_read_number (info, pp, &secindx)
+ || ! ieee_read_expression (info, pp, &offset)
+ || ! ieee_read_optional_number (info, pp, &map, &present))
+ return false;
+ }
+ break;
+
+ default:
+ ieee_error (info, block_start, "unknown BB type");
+ return false;
+ }
+
+
+ /* Push this block on the block stack. */
+
+ if (info->blockstack.bsp >= info->blockstack.stack + BLOCKSTACK_SIZE)
+ {
+ ieee_error (info, (const bfd_byte *) NULL, "stack overflow");
+ return false;
+ }
+
+ info->blockstack.bsp->kind = b;
+ if (b == 5)
+ info->blockstack.bsp->filename = namcopy;
+ info->blockstack.bsp->fnindx = fnindx;
+ info->blockstack.bsp->skip = skip;
+ ++info->blockstack.bsp;
+
+ return true;
+}
+
+/* Handle an IEEE BE record. */
+
+static boolean
+parse_ieee_be (info, pp)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+{
+ bfd_vma offset;
+
+ if (info->blockstack.bsp <= info->blockstack.stack)
+ {
+ ieee_error (info, *pp, "stack underflow");
+ return false;
+ }
+ --info->blockstack.bsp;
+
+ switch (info->blockstack.bsp->kind)
+ {
+ case 2:
+ /* When we end the global typedefs block, we copy out the the
+ contents of info->vars. This is because the variable indices
+ may be reused in the local blocks. However, we need to
+ preserve them so that we can locate a function returning a
+ reference variable whose type is named in the global typedef
+ block. */
+ info->global_vars = ((struct ieee_vars *)
+ xmalloc (sizeof *info->global_vars));
+ info->global_vars->alloc = info->vars.alloc;
+ info->global_vars->vars = ((struct ieee_var *)
+ xmalloc (info->vars.alloc
+ * sizeof (*info->vars.vars)));
+ memcpy (info->global_vars->vars, info->vars.vars,
+ info->vars.alloc * sizeof (*info->vars.vars));
+
+ /* We also copy out the non builtin parts of info->types, since
+ the types are discarded when we start a new block. */
+ info->global_types = ((struct ieee_types *)
+ xmalloc (sizeof *info->global_types));
+ info->global_types->alloc = info->types.alloc;
+ info->global_types->types = ((struct ieee_type *)
+ xmalloc (info->types.alloc
+ * sizeof (*info->types.types)));
+ memcpy (info->global_types->types, info->types.types,
+ info->types.alloc * sizeof (*info->types.types));
+ memset (info->global_types->builtins, 0,
+ sizeof (info->global_types->builtins));
+
+ break;
+
+ case 4:
+ case 6:
+ if (! ieee_read_expression (info, pp, &offset))
+ return false;
+ if (! info->blockstack.bsp->skip)
+ {
+ if (! debug_end_function (info->dhandle, offset + 1))
+ return false;
+ }
+ break;
+
+ case 0x86:
+ /* This is BE6 when BB6 started a block rather than a local
+ function. */
+ if (! ieee_read_expression (info, pp, &offset))
+ return false;
+ if (! debug_end_block (info->dhandle, offset + 1))
+ return false;
+ break;
+
+ case 5:
+ /* When we end a BB5, we look up the stack for the last BB5, if
+ there is one, so that we can call debug_start_source. */
+ if (info->blockstack.bsp > info->blockstack.stack)
+ {
+ struct ieee_block *bl;
+
+ bl = info->blockstack.bsp;
+ do
+ {
+ --bl;
+ if (bl->kind == 5)
+ {
+ if (! debug_start_source (info->dhandle, bl->filename))
+ return false;
+ break;
+ }
+ }
+ while (bl != info->blockstack.stack);
+ }
+ break;
+
+ case 11:
+ if (! ieee_read_expression (info, pp, &offset))
+ return false;
+ /* We just ignore the module size. FIXME. */
+ break;
+
+ default:
+ /* Other block types do not have any trailing information. */
+ break;
+ }
+
+ return true;
+}
+
+/* Parse an NN record. */
+
+static boolean
+parse_ieee_nn (info, pp)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+{
+ const bfd_byte *nn_start;
+ bfd_vma varindx;
+ const char *name;
+ unsigned long namlen;
+
+ nn_start = *pp;
+
+ if (! ieee_read_number (info, pp, &varindx)
+ || ! ieee_read_id (info, pp, &name, &namlen))
+ return false;
+
+ if (varindx < 32)
+ {
+ ieee_error (info, nn_start, "illegal variable index");
+ return false;
+ }
+ varindx -= 32;
+
+ if (varindx >= info->vars.alloc)
+ {
+ unsigned int alloc;
+
+ alloc = info->vars.alloc;
+ if (alloc == 0)
+ alloc = 4;
+ while (varindx >= alloc)
+ alloc *= 2;
+ info->vars.vars = ((struct ieee_var *)
+ xrealloc (info->vars.vars,
+ alloc * sizeof *info->vars.vars));
+ memset (info->vars.vars + info->vars.alloc, 0,
+ (alloc - info->vars.alloc) * sizeof *info->vars.vars);
+ info->vars.alloc = alloc;
+ }
+
+ info->vars.vars[varindx].name = name;
+ info->vars.vars[varindx].namlen = namlen;
+
+ return true;
+}
+
+/* Parse a TY record. */
+
+static boolean
+parse_ieee_ty (info, pp)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+{
+ const bfd_byte *ty_start, *ty_var_start, *ty_code_start;
+ bfd_vma typeindx, varindx, tc;
+ PTR dhandle;
+ boolean tag, typdef;
+ debug_type *arg_slots;
+ unsigned long type_bitsize;
+ debug_type type;
+
+ ty_start = *pp;
+
+ if (! ieee_read_number (info, pp, &typeindx))
+ return false;
+
+ if (typeindx < 256)
+ {
+ ieee_error (info, ty_start, "illegal type index");
+ return false;
+ }
+
+ typeindx -= 256;
+ if (! ieee_alloc_type (info, typeindx, false))
+ return false;
+
+ if (**pp != 0xce)
+ {
+ ieee_error (info, *pp, "unknown TY code");
+ return false;
+ }
+ ++*pp;
+
+ ty_var_start = *pp;
+
+ if (! ieee_read_number (info, pp, &varindx))
+ return false;
+
+ if (varindx < 32)
+ {
+ ieee_error (info, ty_var_start, "illegal variable index");
+ return false;
+ }
+ varindx -= 32;
+
+ if (varindx >= info->vars.alloc || info->vars.vars[varindx].name == NULL)
+ {
+ ieee_error (info, ty_var_start, "undefined variable in TY");
+ return false;
+ }
+
+ ty_code_start = *pp;
+
+ if (! ieee_read_number (info, pp, &tc))
+ return false;
+
+ dhandle = info->dhandle;
+
+ tag = false;
+ typdef = false;
+ arg_slots = NULL;
+ type_bitsize = 0;
+ switch (tc)
+ {
+ default:
+ ieee_error (info, ty_code_start, "unknown TY code");
+ return false;
+
+ case '!':
+ /* Unknown type, with size. We treat it as int. FIXME. */
+ {
+ bfd_vma size;
+
+ if (! ieee_read_number (info, pp, &size))
+ return false;
+ type = debug_make_int_type (dhandle, size, false);
+ }
+ break;
+
+ case 'A': /* Array. */
+ case 'a': /* FORTRAN array in column/row order. FIXME: Not
+ distinguished from normal array. */
+ {
+ debug_type ele_type;
+ bfd_vma lower, upper;
+
+ if (! ieee_read_type_index (info, pp, &ele_type)
+ || ! ieee_read_number (info, pp, &lower)
+ || ! ieee_read_number (info, pp, &upper))
+ return false;
+ type = debug_make_array_type (dhandle, ele_type,
+ ieee_builtin_type (info, ty_code_start,
+ ((unsigned int)
+ builtin_int)),
+ (bfd_signed_vma) lower,
+ (bfd_signed_vma) upper,
+ false);
+ }
+ break;
+
+ case 'E':
+ /* Simple enumeration. */
+ {
+ bfd_vma size;
+ unsigned int alloc;
+ const char **names;
+ unsigned int c;
+ bfd_signed_vma *vals;
+ unsigned int i;
+
+ if (! ieee_read_number (info, pp, &size))
+ return false;
+ /* FIXME: we ignore the enumeration size. */
+
+ alloc = 10;
+ names = (const char **) xmalloc (alloc * sizeof *names);
+ memset (names, 0, alloc * sizeof *names);
+ c = 0;
+ while (1)
+ {
+ const char *name;
+ unsigned long namlen;
+ boolean present;
+
+ if (! ieee_read_optional_id (info, pp, &name, &namlen, &present))
+ return false;
+ if (! present)
+ break;
+
+ if (c + 1 >= alloc)
+ {
+ alloc += 10;
+ names = ((const char **)
+ xrealloc (names, alloc * sizeof *names));
+ }
+
+ names[c] = savestring (name, namlen);
+ if (names[c] == NULL)
+ return false;
+ ++c;
+ }
+
+ names[c] = NULL;
+
+ vals = (bfd_signed_vma *) xmalloc (c * sizeof *vals);
+ for (i = 0; i < c; i++)
+ vals[i] = i;
+
+ type = debug_make_enum_type (dhandle, names, vals);
+ tag = true;
+ }
+ break;
+
+ case 'G':
+ /* Struct with bit fields. */
+ {
+ bfd_vma size;
+ unsigned int alloc;
+ debug_field *fields;
+ unsigned int c;
+
+ if (! ieee_read_number (info, pp, &size))
+ return false;
+
+ alloc = 10;
+ fields = (debug_field *) xmalloc (alloc * sizeof *fields);
+ c = 0;
+ while (1)
+ {
+ const char *name;
+ unsigned long namlen;
+ boolean present;
+ debug_type ftype;
+ bfd_vma bitpos, bitsize;
+
+ if (! ieee_read_optional_id (info, pp, &name, &namlen, &present))
+ return false;
+ if (! present)
+ break;
+ if (! ieee_read_type_index (info, pp, &ftype)
+ || ! ieee_read_number (info, pp, &bitpos)
+ || ! ieee_read_number (info, pp, &bitsize))
+ return false;
+
+ if (c + 1 >= alloc)
+ {
+ alloc += 10;
+ fields = ((debug_field *)
+ xrealloc (fields, alloc * sizeof *fields));
+ }
+
+ fields[c] = debug_make_field (dhandle, savestring (name, namlen),
+ ftype, bitpos, bitsize,
+ DEBUG_VISIBILITY_PUBLIC);
+ if (fields[c] == NULL)
+ return false;
+ ++c;
+ }
+
+ fields[c] = NULL;
+
+ type = debug_make_struct_type (dhandle, true, size, fields);
+ tag = true;
+ }
+ break;
+
+ case 'N':
+ /* Enumeration. */
+ {
+ unsigned int alloc;
+ const char **names;
+ bfd_signed_vma *vals;
+ unsigned int c;
+
+ alloc = 10;
+ names = (const char **) xmalloc (alloc * sizeof *names);
+ vals = (bfd_signed_vma *) xmalloc (alloc * sizeof *names);
+ c = 0;
+ while (1)
+ {
+ const char *name;
+ unsigned long namlen;
+ boolean present;
+ bfd_vma val;
+
+ if (! ieee_read_optional_id (info, pp, &name, &namlen, &present))
+ return false;
+ if (! present)
+ break;
+ if (! ieee_read_number (info, pp, &val))
+ return false;
+
+ /* If the length of the name is zero, then the value is
+ actually the size of the enum. We ignore this
+ information. FIXME. */
+ if (namlen == 0)
+ continue;
+
+ if (c + 1 >= alloc)
+ {
+ alloc += 10;
+ names = ((const char **)
+ xrealloc (names, alloc * sizeof *names));
+ vals = ((bfd_signed_vma *)
+ xrealloc (vals, alloc * sizeof *vals));
+ }
+
+ names[c] = savestring (name, namlen);
+ if (names[c] == NULL)
+ return false;
+ vals[c] = (bfd_signed_vma) val;
+ ++c;
+ }
+
+ names[c] = NULL;
+
+ type = debug_make_enum_type (dhandle, names, vals);
+ tag = true;
+ }
+ break;
+
+ case 'O': /* Small pointer. We don't distinguish small and large
+ pointers. FIXME. */
+ case 'P': /* Large pointer. */
+ {
+ debug_type t;
+
+ if (! ieee_read_type_index (info, pp, &t))
+ return false;
+ type = debug_make_pointer_type (dhandle, t);
+ }
+ break;
+
+ case 'R':
+ /* Range. */
+ {
+ bfd_vma low, high, signedp, size;
+
+ if (! ieee_read_number (info, pp, &low)
+ || ! ieee_read_number (info, pp, &high)
+ || ! ieee_read_number (info, pp, &signedp)
+ || ! ieee_read_number (info, pp, &size))
+ return false;
+
+ type = debug_make_range_type (dhandle,
+ debug_make_int_type (dhandle, size,
+ ! signedp),
+ (bfd_signed_vma) low,
+ (bfd_signed_vma) high);
+ }
+ break;
+
+ case 'S': /* Struct. */
+ case 'U': /* Union. */
+ {
+ bfd_vma size;
+ unsigned int alloc;
+ debug_field *fields;
+ unsigned int c;
+
+ if (! ieee_read_number (info, pp, &size))
+ return false;
+
+ alloc = 10;
+ fields = (debug_field *) xmalloc (alloc * sizeof *fields);
+ c = 0;
+ while (1)
+ {
+ const char *name;
+ unsigned long namlen;
+ boolean present;
+ bfd_vma tindx;
+ bfd_vma offset;
+ debug_type ftype;
+ bfd_vma bitsize;
+
+ if (! ieee_read_optional_id (info, pp, &name, &namlen, &present))
+ return false;
+ if (! present)
+ break;
+ if (! ieee_read_number (info, pp, &tindx)
+ || ! ieee_read_number (info, pp, &offset))
+ return false;
+
+ if (tindx < 256)
+ {
+ ftype = ieee_builtin_type (info, ty_code_start, tindx);
+ bitsize = 0;
+ offset *= 8;
+ }
+ else
+ {
+ struct ieee_type *t;
+
+ tindx -= 256;
+ if (! ieee_alloc_type (info, tindx, true))
+ return false;
+ t = info->types.types + tindx;
+ ftype = t->type;
+ bitsize = t->bitsize;
+ if (bitsize == 0)
+ offset *= 8;
+ }
+
+ if (c + 1 >= alloc)
+ {
+ alloc += 10;
+ fields = ((debug_field *)
+ xrealloc (fields, alloc * sizeof *fields));
+ }
+
+ fields[c] = debug_make_field (dhandle, savestring (name, namlen),
+ ftype, offset, bitsize,
+ DEBUG_VISIBILITY_PUBLIC);
+ if (fields[c] == NULL)
+ return false;
+ ++c;
+ }
+
+ fields[c] = NULL;
+
+ type = debug_make_struct_type (dhandle, tc == 'S', size, fields);
+ tag = true;
+ }
+ break;
+
+ case 'T':
+ /* Typedef. */
+ if (! ieee_read_type_index (info, pp, &type))
+ return false;
+ typdef = true;
+ break;
+
+ case 'X':
+ /* Procedure. FIXME: This is an extern declaration, which we
+ have no way of representing. */
+ {
+ bfd_vma attr;
+ debug_type rtype;
+ bfd_vma nargs;
+ boolean present;
+ struct ieee_var *pv;
+
+ /* FIXME: We ignore the attribute and the argument names. */
+
+ if (! ieee_read_number (info, pp, &attr)
+ || ! ieee_read_type_index (info, pp, &rtype)
+ || ! ieee_read_number (info, pp, &nargs))
+ return false;
+ do
+ {
+ const char *name;
+ unsigned long namlen;
+
+ if (! ieee_read_optional_id (info, pp, &name, &namlen, &present))
+ return false;
+ }
+ while (present);
+
+ pv = info->vars.vars + varindx;
+ pv->kind = IEEE_EXTERNAL;
+ if (pv->namlen > 0
+ && debug_get_type_kind (dhandle, rtype) == DEBUG_KIND_POINTER)
+ {
+ /* Set up the return type as an indirect type pointing to
+ the variable slot, so that we can change it to a
+ reference later if appropriate. */
+ pv->pslot = (debug_type *) xmalloc (sizeof *pv->pslot);
+ *pv->pslot = rtype;
+ rtype = debug_make_indirect_type (dhandle, pv->pslot,
+ (const char *) NULL);
+ }
+
+ type = debug_make_function_type (dhandle, rtype, (debug_type *) NULL,
+ false);
+ }
+ break;
+
+ case 'V':
+ /* Void. This is not documented, but the MRI compiler emits it. */
+ type = debug_make_void_type (dhandle);
+ break;
+
+ case 'Z':
+ /* Array with 0 lower bound. */
+ {
+ debug_type etype;
+ bfd_vma high;
+
+ if (! ieee_read_type_index (info, pp, &etype)
+ || ! ieee_read_number (info, pp, &high))
+ return false;
+
+ type = debug_make_array_type (dhandle, etype,
+ ieee_builtin_type (info, ty_code_start,
+ ((unsigned int)
+ builtin_int)),
+ 0, (bfd_signed_vma) high, false);
+ }
+ break;
+
+ case 'c': /* Complex. */
+ case 'd': /* Double complex. */
+ {
+ const char *name;
+ unsigned long namlen;
+
+ /* FIXME: I don't know what the name means. */
+
+ if (! ieee_read_id (info, pp, &name, &namlen))
+ return false;
+
+ type = debug_make_complex_type (dhandle, tc == 'c' ? 4 : 8);
+ }
+ break;
+
+ case 'f':
+ /* Pascal file name. FIXME. */
+ ieee_error (info, ty_code_start, "Pascal file name not supported");
+ return false;
+
+ case 'g':
+ /* Bitfield type. */
+ {
+ bfd_vma signedp, bitsize, dummy;
+ const bfd_byte *hold;
+ boolean present;
+
+ if (! ieee_read_number (info, pp, &signedp)
+ || ! ieee_read_number (info, pp, &bitsize))
+ return false;
+
+ /* I think the documentation says that there is a type index,
+ but some actual files do not have one. */
+ hold = *pp;
+ if (! ieee_read_optional_number (info, pp, &dummy, &present))
+ return false;
+ if (! present)
+ {
+ /* FIXME: This is just a guess. */
+ type = debug_make_int_type (dhandle, 4,
+ signedp ? false : true);
+ }
+ else
+ {
+ *pp = hold;
+ if (! ieee_read_type_index (info, pp, &type))
+ return false;
+ }
+ type_bitsize = bitsize;
+ }
+ break;
+
+ case 'n':
+ /* Qualifier. */
+ {
+ bfd_vma kind;
+ debug_type t;
+
+ if (! ieee_read_number (info, pp, &kind)
+ || ! ieee_read_type_index (info, pp, &t))
+ return false;
+
+ switch (kind)
+ {
+ default:
+ ieee_error (info, ty_start, "unsupported qualifer");
+ return false;
+
+ case 1:
+ type = debug_make_const_type (dhandle, t);
+ break;
+
+ case 2:
+ type = debug_make_volatile_type (dhandle, t);
+ break;
+ }
+ }
+ break;
+
+ case 's':
+ /* Set. */
+ {
+ bfd_vma size;
+ debug_type etype;
+
+ if (! ieee_read_number (info, pp, &size)
+ || ! ieee_read_type_index (info, pp, &etype))
+ return false;
+
+ /* FIXME: We ignore the size. */
+
+ type = debug_make_set_type (dhandle, etype, false);
+ }
+ break;
+
+ case 'x':
+ /* Procedure with compiler dependencies. */
+ {
+ struct ieee_var *pv;
+ bfd_vma attr, frame_type, push_mask, nargs, level, father;
+ debug_type rtype;
+ debug_type *arg_types;
+ boolean varargs;
+ boolean present;
+
+ /* FIXME: We ignore some of this information. */
+
+ pv = info->vars.vars + varindx;
+
+ if (! ieee_read_number (info, pp, &attr)
+ || ! ieee_read_number (info, pp, &frame_type)
+ || ! ieee_read_number (info, pp, &push_mask)
+ || ! ieee_read_type_index (info, pp, &rtype)
+ || ! ieee_read_number (info, pp, &nargs))
+ return false;
+ if (nargs == (bfd_vma) -1)
+ {
+ arg_types = NULL;
+ varargs = false;
+ }
+ else
+ {
+ unsigned int i;
+
+ arg_types = ((debug_type *)
+ xmalloc ((nargs + 1) * sizeof *arg_types));
+ for (i = 0; i < nargs; i++)
+ if (! ieee_read_type_index (info, pp, arg_types + i))
+ return false;
+
+ /* If the last type is pointer to void, this is really a
+ varargs function. */
+ varargs = false;
+ if (nargs > 0)
+ {
+ debug_type last;
+
+ last = arg_types[nargs - 1];
+ if (debug_get_type_kind (dhandle, last) == DEBUG_KIND_POINTER
+ && (debug_get_type_kind (dhandle,
+ debug_get_target_type (dhandle,
+ last))
+ == DEBUG_KIND_VOID))
+ {
+ --nargs;
+ varargs = true;
+ }
+ }
+
+ /* If there are any pointer arguments, turn them into
+ indirect types in case we later need to convert them to
+ reference types. */
+ for (i = 0; i < nargs; i++)
+ {
+ if (debug_get_type_kind (dhandle, arg_types[i])
+ == DEBUG_KIND_POINTER)
+ {
+ if (arg_slots == NULL)
+ {
+ arg_slots = ((debug_type *)
+ xmalloc (nargs * sizeof *arg_slots));
+ memset (arg_slots, 0, nargs * sizeof *arg_slots);
+ }
+ arg_slots[i] = arg_types[i];
+ arg_types[i] =
+ debug_make_indirect_type (dhandle,
+ arg_slots + i,
+ (const char *) NULL);
+ }
+ }
+
+ arg_types[nargs] = DEBUG_TYPE_NULL;
+ }
+ if (! ieee_read_number (info, pp, &level)
+ || ! ieee_read_optional_number (info, pp, &father, &present))
+ return false;
+
+ /* We can't distinguish between a global function and a static
+ function. */
+ pv->kind = IEEE_FUNCTION;
+
+ if (pv->namlen > 0
+ && debug_get_type_kind (dhandle, rtype) == DEBUG_KIND_POINTER)
+ {
+ /* Set up the return type as an indirect type pointing to
+ the variable slot, so that we can change it to a
+ reference later if appropriate. */
+ pv->pslot = (debug_type *) xmalloc (sizeof *pv->pslot);
+ *pv->pslot = rtype;
+ rtype = debug_make_indirect_type (dhandle, pv->pslot,
+ (const char *) NULL);
+ }
+
+ type = debug_make_function_type (dhandle, rtype, arg_types, varargs);
+ }
+ break;
+ }
+
+ /* Record the type in the table. */
+
+ if (type == DEBUG_TYPE_NULL)
+ return false;
+
+ info->vars.vars[varindx].type = type;
+
+ if ((tag || typdef)
+ && info->vars.vars[varindx].namlen > 0)
+ {
+ const char *name;
+
+ name = savestring (info->vars.vars[varindx].name,
+ info->vars.vars[varindx].namlen);
+ if (typdef)
+ type = debug_name_type (dhandle, name, type);
+ else if (tc == 'E' || tc == 'N')
+ type = debug_tag_type (dhandle, name, type);
+ else
+ {
+ struct ieee_tag *it;
+
+ /* We must allocate all struct tags as indirect types, so
+ that if we later see a definition of the tag as a C++
+ record we can update the indirect slot and automatically
+ change all the existing references. */
+ it = (struct ieee_tag *) xmalloc (sizeof *it);
+ memset (it, 0, sizeof *it);
+ it->next = info->tags;
+ info->tags = it;
+ it->name = name;
+ it->slot = type;
+
+ type = debug_make_indirect_type (dhandle, &it->slot, name);
+ type = debug_tag_type (dhandle, name, type);
+
+ it->type = type;
+ }
+ if (type == NULL)
+ return false;
+ }
+
+ info->types.types[typeindx].type = type;
+ info->types.types[typeindx].arg_slots = arg_slots;
+ info->types.types[typeindx].bitsize = type_bitsize;
+
+ /* We may have already allocated type as an indirect type pointing
+ to slot. It does no harm to replace the indirect type with the
+ real type. Filling in slot as well handles the indirect types
+ which are already hanging around. */
+ if (info->types.types[typeindx].pslot != NULL)
+ *info->types.types[typeindx].pslot = type;
+
+ return true;
+}
+
+/* Parse an ATN record. */
+
+static boolean
+parse_ieee_atn (info, pp)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+{
+ const bfd_byte *atn_start, *atn_code_start;
+ bfd_vma varindx;
+ struct ieee_var *pvar;
+ debug_type type;
+ bfd_vma atn_code;
+ PTR dhandle;
+ bfd_vma v, v2, v3, v4, v5;
+ const char *name;
+ unsigned long namlen;
+ char *namcopy;
+ boolean present;
+ int blocktype;
+
+ atn_start = *pp;
+
+ if (! ieee_read_number (info, pp, &varindx)
+ || ! ieee_read_type_index (info, pp, &type))
+ return false;
+
+ atn_code_start = *pp;
+
+ if (! ieee_read_number (info, pp, &atn_code))
+ return false;
+
+ if (varindx == 0)
+ {
+ pvar = NULL;
+ name = "";
+ namlen = 0;
+ }
+ else if (varindx < 32)
+ {
+ ieee_error (info, atn_start, "illegal variable index");
+ return false;
+ }
+ else
+ {
+ varindx -= 32;
+ if (varindx >= info->vars.alloc
+ || info->vars.vars[varindx].name == NULL)
+ {
+ /* The MRI compiler or linker sometimes omits the NN record
+ for a pmisc record. */
+ if (atn_code == 62)
+ {
+ if (varindx >= info->vars.alloc)
+ {
+ unsigned int alloc;
+
+ alloc = info->vars.alloc;
+ if (alloc == 0)
+ alloc = 4;
+ while (varindx >= alloc)
+ alloc *= 2;
+ info->vars.vars = ((struct ieee_var *)
+ xrealloc (info->vars.vars,
+ (alloc
+ * sizeof *info->vars.vars)));
+ memset (info->vars.vars + info->vars.alloc, 0,
+ ((alloc - info->vars.alloc)
+ * sizeof *info->vars.vars));
+ info->vars.alloc = alloc;
+ }
+
+ pvar = info->vars.vars + varindx;
+ pvar->name = "";
+ pvar->namlen = 0;
+ }
+ else
+ {
+ ieee_error (info, atn_start, "undefined variable in ATN");
+ return false;
+ }
+ }
+
+ pvar = info->vars.vars + varindx;
+
+ pvar->type = type;
+
+ name = pvar->name;
+ namlen = pvar->namlen;
+ }
+
+ dhandle = info->dhandle;
+
+ /* If we are going to call debug_record_variable with a pointer
+ type, change the type to an indirect type so that we can later
+ change it to a reference type if we encounter a C++ pmisc 'R'
+ record. */
+ if (pvar != NULL
+ && type != DEBUG_TYPE_NULL
+ && debug_get_type_kind (dhandle, type) == DEBUG_KIND_POINTER)
+ {
+ switch (atn_code)
+ {
+ case 1:
+ case 2:
+ case 3:
+ case 5:
+ case 8:
+ case 10:
+ pvar->pslot = (debug_type *) xmalloc (sizeof *pvar->pslot);
+ *pvar->pslot = type;
+ type = debug_make_indirect_type (dhandle, pvar->pslot,
+ (const char *) NULL);
+ pvar->type = type;
+ break;
+ }
+ }
+
+ switch (atn_code)
+ {
+ default:
+ ieee_error (info, atn_code_start, "unknown ATN type");
+ return false;
+
+ case 1:
+ /* Automatic variable. */
+ if (! ieee_read_number (info, pp, &v))
+ return false;
+ namcopy = savestring (name, namlen);
+ if (type == NULL)
+ type = debug_make_void_type (dhandle);
+ if (pvar != NULL)
+ pvar->kind = IEEE_LOCAL;
+ return debug_record_variable (dhandle, namcopy, type, DEBUG_LOCAL, v);
+
+ case 2:
+ /* Register variable. */
+ if (! ieee_read_number (info, pp, &v))
+ return false;
+ namcopy = savestring (name, namlen);
+ if (type == NULL)
+ type = debug_make_void_type (dhandle);
+ if (pvar != NULL)
+ pvar->kind = IEEE_LOCAL;
+ return debug_record_variable (dhandle, namcopy, type, DEBUG_REGISTER,
+ ieee_regno_to_genreg (info->abfd, v));
+
+ case 3:
+ /* Static variable. */
+ if (! ieee_require_asn (info, pp, &v))
+ return false;
+ namcopy = savestring (name, namlen);
+ if (type == NULL)
+ type = debug_make_void_type (dhandle);
+ if (info->blockstack.bsp <= info->blockstack.stack)
+ blocktype = 0;
+ else
+ blocktype = info->blockstack.bsp[-1].kind;
+ if (pvar != NULL)
+ {
+ if (blocktype == 4 || blocktype == 6)
+ pvar->kind = IEEE_LOCAL;
+ else
+ pvar->kind = IEEE_STATIC;
+ }
+ return debug_record_variable (dhandle, namcopy, type,
+ (blocktype == 4 || blocktype == 6
+ ? DEBUG_LOCAL_STATIC
+ : DEBUG_STATIC),
+ v);
+
+ case 4:
+ /* External function. We don't currently record these. FIXME. */
+ if (pvar != NULL)
+ pvar->kind = IEEE_EXTERNAL;
+ return true;
+
+ case 5:
+ /* External variable. We don't currently record these. FIXME. */
+ if (pvar != NULL)
+ pvar->kind = IEEE_EXTERNAL;
+ return true;
+
+ case 7:
+ if (! ieee_read_number (info, pp, &v)
+ || ! ieee_read_number (info, pp, &v2)
+ || ! ieee_read_optional_number (info, pp, &v3, &present))
+ return false;
+ if (present)
+ {
+ if (! ieee_read_optional_number (info, pp, &v4, &present))
+ return false;
+ }
+
+ /* We just ignore the two optional fields in v3 and v4, since
+ they are not defined. */
+
+ if (! ieee_require_asn (info, pp, &v3))
+ return false;
+
+ /* We have no way to record the column number. FIXME. */
+
+ return debug_record_line (dhandle, v, v3);
+
+ case 8:
+ /* Global variable. */
+ if (! ieee_require_asn (info, pp, &v))
+ return false;
+ namcopy = savestring (name, namlen);
+ if (type == NULL)
+ type = debug_make_void_type (dhandle);
+ if (pvar != NULL)
+ pvar->kind = IEEE_GLOBAL;
+ return debug_record_variable (dhandle, namcopy, type, DEBUG_GLOBAL, v);
+
+ case 9:
+ /* Variable lifetime information. */
+ if (! ieee_read_number (info, pp, &v))
+ return false;
+
+ /* We have no way to record this information. FIXME. */
+ return true;
+
+ case 10:
+ /* Locked register. The spec says that there are two required
+ fields, but at least on occasion the MRI compiler only emits
+ one. */
+ if (! ieee_read_number (info, pp, &v)
+ || ! ieee_read_optional_number (info, pp, &v2, &present))
+ return false;
+
+ /* I think this means a variable that is both in a register and
+ a frame slot. We ignore the frame slot. FIXME. */
+
+ namcopy = savestring (name, namlen);
+ if (type == NULL)
+ type = debug_make_void_type (dhandle);
+ if (pvar != NULL)
+ pvar->kind = IEEE_LOCAL;
+ return debug_record_variable (dhandle, namcopy, type, DEBUG_REGISTER, v);
+
+ case 11:
+ /* Reserved for FORTRAN common. */
+ ieee_error (info, atn_code_start, "unsupported ATN11");
+
+ /* Return true to keep going. */
+ return true;
+
+ case 12:
+ /* Based variable. */
+ v3 = 0;
+ v4 = 0x80;
+ v5 = 0;
+ if (! ieee_read_number (info, pp, &v)
+ || ! ieee_read_number (info, pp, &v2)
+ || ! ieee_read_optional_number (info, pp, &v3, &present))
+ return false;
+ if (present)
+ {
+ if (! ieee_read_optional_number (info, pp, &v4, &present))
+ return false;
+ if (present)
+ {
+ if (! ieee_read_optional_number (info, pp, &v5, &present))
+ return false;
+ }
+ }
+
+ /* We have no way to record this information. FIXME. */
+
+ ieee_error (info, atn_code_start, "unsupported ATN12");
+
+ /* Return true to keep going. */
+ return true;
+
+ case 16:
+ /* Constant. The description of this that I have is ambiguous,
+ so I'm not going to try to implement it. */
+ if (! ieee_read_number (info, pp, &v)
+ || ! ieee_read_optional_number (info, pp, &v2, &present))
+ return false;
+ if (present)
+ {
+ if (! ieee_read_optional_number (info, pp, &v2, &present))
+ return false;
+ if (present)
+ {
+ if (! ieee_read_optional_id (info, pp, &name, &namlen, &present))
+ return false;
+ }
+ }
+
+ if ((ieee_record_enum_type) **pp == ieee_e2_first_byte_enum)
+ {
+ if (! ieee_require_asn (info, pp, &v3))
+ return false;
+ }
+
+ return true;
+
+ case 19:
+ /* Static variable from assembler. */
+ v2 = 0;
+ if (! ieee_read_number (info, pp, &v)
+ || ! ieee_read_optional_number (info, pp, &v2, &present)
+ || ! ieee_require_asn (info, pp, &v3))
+ return false;
+ namcopy = savestring (name, namlen);
+ /* We don't really handle this correctly. FIXME. */
+ return debug_record_variable (dhandle, namcopy,
+ debug_make_void_type (dhandle),
+ v2 != 0 ? DEBUG_GLOBAL : DEBUG_STATIC,
+ v3);
+
+ case 62:
+ /* Procedure miscellaneous information. */
+ case 63:
+ /* Variable miscellaneous information. */
+ case 64:
+ /* Module miscellaneous information. */
+ if (! ieee_read_number (info, pp, &v)
+ || ! ieee_read_number (info, pp, &v2)
+ || ! ieee_read_optional_id (info, pp, &name, &namlen, &present))
+ return false;
+
+ if (atn_code == 62 && v == 80)
+ {
+ if (present)
+ {
+ ieee_error (info, atn_code_start,
+ "unexpected string in C++ misc");
+ return false;
+ }
+ return ieee_read_cxx_misc (info, pp, v2);
+ }
+
+ /* We just ignore all of this stuff. FIXME. */
+
+ for (; v2 > 0; --v2)
+ {
+ switch ((ieee_record_enum_type) **pp)
+ {
+ default:
+ ieee_error (info, *pp, "bad misc record");
+ return false;
+
+ case ieee_at_record_enum:
+ if (! ieee_require_atn65 (info, pp, &name, &namlen))
+ return false;
+ break;
+
+ case ieee_e2_first_byte_enum:
+ if (! ieee_require_asn (info, pp, &v3))
+ return false;
+ break;
+ }
+ }
+
+ return true;
+ }
+
+ /*NOTREACHED*/
+}
+
+/* Handle C++ debugging miscellaneous records. This is called for
+ procedure miscellaneous records of type 80. */
+
+static boolean
+ieee_read_cxx_misc (info, pp, count)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+ unsigned long count;
+{
+ const bfd_byte *start;
+ bfd_vma category;
+
+ start = *pp;
+
+ /* Get the category of C++ misc record. */
+ if (! ieee_require_asn (info, pp, &category))
+ return false;
+ --count;
+
+ switch (category)
+ {
+ default:
+ ieee_error (info, start, "unrecognized C++ misc record");
+ return false;
+
+ case 'T':
+ if (! ieee_read_cxx_class (info, pp, count))
+ return false;
+ break;
+
+ case 'M':
+ {
+ bfd_vma flags;
+ const char *name;
+ unsigned long namlen;
+
+ /* The IEEE spec indicates that the 'M' record only has a
+ flags field. The MRI compiler also emits the name of the
+ function. */
+
+ if (! ieee_require_asn (info, pp, &flags))
+ return false;
+ if (*pp < info->pend
+ && (ieee_record_enum_type) **pp == ieee_at_record_enum)
+ {
+ if (! ieee_require_atn65 (info, pp, &name, &namlen))
+ return false;
+ }
+
+ /* This is emitted for method functions, but I don't think we
+ care very much. It might help if it told us useful
+ information like the class with which this function is
+ associated, but it doesn't, so it isn't helpful. */
+ }
+ break;
+
+ case 'B':
+ if (! ieee_read_cxx_defaults (info, pp, count))
+ return false;
+ break;
+
+ case 'z':
+ {
+ const char *name, *mangled, *class;
+ unsigned long namlen, mangledlen, classlen;
+ bfd_vma control;
+
+ /* Pointer to member. */
+
+ if (! ieee_require_atn65 (info, pp, &name, &namlen)
+ || ! ieee_require_atn65 (info, pp, &mangled, &mangledlen)
+ || ! ieee_require_atn65 (info, pp, &class, &classlen)
+ || ! ieee_require_asn (info, pp, &control))
+ return false;
+
+ /* FIXME: We should now track down name and change its type. */
+ }
+ break;
+
+ case 'R':
+ if (! ieee_read_reference (info, pp))
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+/* Read a C++ class definition. This is a pmisc type 80 record of
+ category 'T'. */
+
+static boolean
+ieee_read_cxx_class (info, pp, count)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+ unsigned long count;
+{
+ const bfd_byte *start;
+ bfd_vma class;
+ const char *tag;
+ unsigned long taglen;
+ struct ieee_tag *it;
+ PTR dhandle;
+ debug_field *fields;
+ unsigned int field_count, field_alloc;
+ debug_baseclass *baseclasses;
+ unsigned int baseclasses_count, baseclasses_alloc;
+ const debug_field *structfields;
+ struct ieee_method
+ {
+ const char *name;
+ unsigned long namlen;
+ debug_method_variant *variants;
+ unsigned count;
+ unsigned int alloc;
+ } *methods;
+ unsigned int methods_count, methods_alloc;
+ debug_type vptrbase;
+ boolean ownvptr;
+ debug_method *dmethods;
+
+ start = *pp;
+
+ if (! ieee_require_asn (info, pp, &class))
+ return false;
+ --count;
+
+ if (! ieee_require_atn65 (info, pp, &tag, &taglen))
+ return false;
+ --count;
+
+ /* Find the C struct with this name. */
+ for (it = info->tags; it != NULL; it = it->next)
+ if (it->name[0] == tag[0]
+ && strncmp (it->name, tag, taglen) == 0
+ && strlen (it->name) == taglen)
+ break;
+ if (it == NULL)
+ {
+ ieee_error (info, start, "undefined C++ object");
+ return false;
+ }
+
+ dhandle = info->dhandle;
+
+ fields = NULL;
+ field_count = 0;
+ field_alloc = 0;
+ baseclasses = NULL;
+ baseclasses_count = 0;
+ baseclasses_alloc = 0;
+ methods = NULL;
+ methods_count = 0;
+ methods_alloc = 0;
+ vptrbase = DEBUG_TYPE_NULL;
+ ownvptr = false;
+
+ structfields = debug_get_fields (dhandle, it->type);
+
+ while (count > 0)
+ {
+ bfd_vma id;
+ const bfd_byte *spec_start;
+
+ spec_start = *pp;
+
+ if (! ieee_require_asn (info, pp, &id))
+ return false;
+ --count;
+
+ switch (id)
+ {
+ default:
+ ieee_error (info, spec_start, "unrecognized C++ object spec");
+ return false;
+
+ case 'b':
+ {
+ bfd_vma flags, cinline;
+ const char *basename, *fieldname;
+ unsigned long baselen, fieldlen;
+ char *basecopy;
+ debug_type basetype;
+ bfd_vma bitpos;
+ boolean virtualp;
+ enum debug_visibility visibility;
+ debug_baseclass baseclass;
+
+ /* This represents a base or friend class. */
+
+ if (! ieee_require_asn (info, pp, &flags)
+ || ! ieee_require_atn65 (info, pp, &basename, &baselen)
+ || ! ieee_require_asn (info, pp, &cinline)
+ || ! ieee_require_atn65 (info, pp, &fieldname, &fieldlen))
+ return false;
+ count -= 4;
+
+ /* We have no way of recording friend information, so we
+ just ignore it. */
+ if ((flags & BASEFLAGS_FRIEND) != 0)
+ break;
+
+ /* I assume that either all of the members of the
+ baseclass are included in the object, starting at the
+ beginning of the object, or that none of them are
+ included. */
+
+ if ((fieldlen == 0) == (cinline == 0))
+ {
+ ieee_error (info, start, "unsupported C++ object type");
+ return false;
+ }
+
+ basecopy = savestring (basename, baselen);
+ basetype = debug_find_tagged_type (dhandle, basecopy,
+ DEBUG_KIND_ILLEGAL);
+ free (basecopy);
+ if (basetype == DEBUG_TYPE_NULL)
+ {
+ ieee_error (info, start, "C++ base class not defined");
+ return false;
+ }
+
+ if (fieldlen == 0)
+ bitpos = 0;
+ else
+ {
+ const debug_field *pf;
+
+ if (structfields == NULL)
+ {
+ ieee_error (info, start, "C++ object has no fields");
+ return false;
+ }
+
+ for (pf = structfields; *pf != DEBUG_FIELD_NULL; pf++)
+ {
+ const char *fname;
+
+ fname = debug_get_field_name (dhandle, *pf);
+ if (fname == NULL)
+ return false;
+ if (fname[0] == fieldname[0]
+ && strncmp (fname, fieldname, fieldlen) == 0
+ && strlen (fname) == fieldlen)
+ break;
+ }
+ if (*pf == DEBUG_FIELD_NULL)
+ {
+ ieee_error (info, start,
+ "C++ base class not found in container");
+ return false;
+ }
+
+ bitpos = debug_get_field_bitpos (dhandle, *pf);
+ }
+
+ if ((flags & BASEFLAGS_VIRTUAL) != 0)
+ virtualp = true;
+ else
+ virtualp = false;
+ if ((flags & BASEFLAGS_PRIVATE) != 0)
+ visibility = DEBUG_VISIBILITY_PRIVATE;
+ else
+ visibility = DEBUG_VISIBILITY_PUBLIC;
+
+ baseclass = debug_make_baseclass (dhandle, basetype, bitpos,
+ virtualp, visibility);
+ if (baseclass == DEBUG_BASECLASS_NULL)
+ return false;
+
+ if (baseclasses_count + 1 >= baseclasses_alloc)
+ {
+ baseclasses_alloc += 10;
+ baseclasses = ((debug_baseclass *)
+ xrealloc (baseclasses,
+ (baseclasses_alloc
+ * sizeof *baseclasses)));
+ }
+
+ baseclasses[baseclasses_count] = baseclass;
+ ++baseclasses_count;
+ baseclasses[baseclasses_count] = DEBUG_BASECLASS_NULL;
+ }
+ break;
+
+ case 'd':
+ {
+ bfd_vma flags;
+ const char *fieldname, *mangledname;
+ unsigned long fieldlen, mangledlen;
+ char *fieldcopy;
+ boolean staticp;
+ debug_type ftype;
+ const debug_field *pf = NULL;
+ enum debug_visibility visibility;
+ debug_field field;
+
+ /* This represents a data member. */
+
+ if (! ieee_require_asn (info, pp, &flags)
+ || ! ieee_require_atn65 (info, pp, &fieldname, &fieldlen)
+ || ! ieee_require_atn65 (info, pp, &mangledname, &mangledlen))
+ return false;
+ count -= 3;
+
+ fieldcopy = savestring (fieldname, fieldlen);
+
+ staticp = (flags & CXXFLAGS_STATIC) != 0 ? true : false;
+
+ if (staticp)
+ {
+ struct ieee_var *pv, *pvend;
+
+ /* See if we can find a definition for this variable. */
+ pv = info->vars.vars;
+ pvend = pv + info->vars.alloc;
+ for (; pv < pvend; pv++)
+ if (pv->namlen == mangledlen
+ && strncmp (pv->name, mangledname, mangledlen) == 0)
+ break;
+ if (pv < pvend)
+ ftype = pv->type;
+ else
+ {
+ /* This can happen if the variable is never used. */
+ ftype = ieee_builtin_type (info, start,
+ (unsigned int) builtin_void);
+ }
+ }
+ else
+ {
+ unsigned int findx;
+
+ if (structfields == NULL)
+ {
+ ieee_error (info, start, "C++ object has no fields");
+ return false;
+ }
+
+ for (pf = structfields, findx = 0;
+ *pf != DEBUG_FIELD_NULL;
+ pf++, findx++)
+ {
+ const char *fname;
+
+ fname = debug_get_field_name (dhandle, *pf);
+ if (fname == NULL)
+ return false;
+ if (fname[0] == mangledname[0]
+ && strncmp (fname, mangledname, mangledlen) == 0
+ && strlen (fname) == mangledlen)
+ break;
+ }
+ if (*pf == DEBUG_FIELD_NULL)
+ {
+ ieee_error (info, start,
+ "C++ data member not found in container");
+ return false;
+ }
+
+ ftype = debug_get_field_type (dhandle, *pf);
+
+ if (debug_get_type_kind (dhandle, ftype) == DEBUG_KIND_POINTER)
+ {
+ /* We might need to convert this field into a
+ reference type later on, so make it an indirect
+ type. */
+ if (it->fslots == NULL)
+ {
+ unsigned int fcnt;
+ const debug_field *pfcnt;
+
+ fcnt = 0;
+ for (pfcnt = structfields;
+ *pfcnt != DEBUG_FIELD_NULL;
+ pfcnt++)
+ ++fcnt;
+ it->fslots = ((debug_type *)
+ xmalloc (fcnt * sizeof *it->fslots));
+ memset (it->fslots, 0,
+ fcnt * sizeof *it->fslots);
+ }
+
+ if (ftype == DEBUG_TYPE_NULL)
+ return false;
+ it->fslots[findx] = ftype;
+ ftype = debug_make_indirect_type (dhandle,
+ it->fslots + findx,
+ (const char *) NULL);
+ }
+ }
+ if (ftype == DEBUG_TYPE_NULL)
+ return false;
+
+ switch (flags & CXXFLAGS_VISIBILITY)
+ {
+ default:
+ ieee_error (info, start, "unknown C++ visibility");
+ return false;
+
+ case CXXFLAGS_VISIBILITY_PUBLIC:
+ visibility = DEBUG_VISIBILITY_PUBLIC;
+ break;
+
+ case CXXFLAGS_VISIBILITY_PRIVATE:
+ visibility = DEBUG_VISIBILITY_PRIVATE;
+ break;
+
+ case CXXFLAGS_VISIBILITY_PROTECTED:
+ visibility = DEBUG_VISIBILITY_PROTECTED;
+ break;
+ }
+
+ if (staticp)
+ {
+ char *mangledcopy;
+
+ mangledcopy = savestring (mangledname, mangledlen);
+
+ field = debug_make_static_member (dhandle, fieldcopy,
+ ftype, mangledcopy,
+ visibility);
+ }
+ else
+ {
+ bfd_vma bitpos, bitsize;
+
+ bitpos = debug_get_field_bitpos (dhandle, *pf);
+ bitsize = debug_get_field_bitsize (dhandle, *pf);
+ if (bitpos == (bfd_vma) -1 || bitsize == (bfd_vma) -1)
+ {
+ ieee_error (info, start, "bad C++ field bit pos or size");
+ return false;
+ }
+ field = debug_make_field (dhandle, fieldcopy, ftype, bitpos,
+ bitsize, visibility);
+ }
+
+ if (field == DEBUG_FIELD_NULL)
+ return false;
+
+ if (field_count + 1 >= field_alloc)
+ {
+ field_alloc += 10;
+ fields = ((debug_field *)
+ xrealloc (fields, field_alloc * sizeof *fields));
+ }
+
+ fields[field_count] = field;
+ ++field_count;
+ fields[field_count] = DEBUG_FIELD_NULL;
+ }
+ break;
+
+ case 'm':
+ case 'v':
+ {
+ bfd_vma flags, voffset, control;
+ const char *name, *mangled;
+ unsigned long namlen, mangledlen;
+ struct ieee_var *pv, *pvend;
+ debug_type type;
+ enum debug_visibility visibility;
+ boolean constp, volatilep;
+ char *mangledcopy;
+ debug_method_variant mv;
+ struct ieee_method *meth;
+ unsigned int im;
+
+ if (! ieee_require_asn (info, pp, &flags)
+ || ! ieee_require_atn65 (info, pp, &name, &namlen)
+ || ! ieee_require_atn65 (info, pp, &mangled, &mangledlen))
+ return false;
+ count -= 3;
+ if (id != 'v')
+ voffset = 0;
+ else
+ {
+ if (! ieee_require_asn (info, pp, &voffset))
+ return false;
+ --count;
+ }
+ if (! ieee_require_asn (info, pp, &control))
+ return false;
+ --count;
+
+ /* We just ignore the control information. */
+
+ /* We have no way to represent friend information, so we
+ just ignore it. */
+ if ((flags & CXXFLAGS_FRIEND) != 0)
+ break;
+
+ /* We should already have seen a type for the function. */
+ pv = info->vars.vars;
+ pvend = pv + info->vars.alloc;
+ for (; pv < pvend; pv++)
+ if (pv->namlen == mangledlen
+ && strncmp (pv->name, mangled, mangledlen) == 0)
+ break;
+
+ if (pv >= pvend)
+ {
+ /* We won't have type information for this function if
+ it is not included in this file. We don't try to
+ handle this case. FIXME. */
+ type = (debug_make_function_type
+ (dhandle,
+ ieee_builtin_type (info, start,
+ (unsigned int) builtin_void),
+ (debug_type *) NULL,
+ false));
+ }
+ else
+ {
+ debug_type return_type;
+ const debug_type *arg_types;
+ boolean varargs;
+
+ if (debug_get_type_kind (dhandle, pv->type)
+ != DEBUG_KIND_FUNCTION)
+ {
+ ieee_error (info, start,
+ "bad type for C++ method function");
+ return false;
+ }
+
+ return_type = debug_get_return_type (dhandle, pv->type);
+ arg_types = debug_get_parameter_types (dhandle, pv->type,
+ &varargs);
+ if (return_type == DEBUG_TYPE_NULL || arg_types == NULL)
+ {
+ ieee_error (info, start,
+ "no type information for C++ method function");
+ return false;
+ }
+
+ type = debug_make_method_type (dhandle, return_type, it->type,
+ (debug_type *) arg_types,
+ varargs);
+ }
+ if (type == DEBUG_TYPE_NULL)
+ return false;
+
+ switch (flags & CXXFLAGS_VISIBILITY)
+ {
+ default:
+ ieee_error (info, start, "unknown C++ visibility");
+ return false;
+
+ case CXXFLAGS_VISIBILITY_PUBLIC:
+ visibility = DEBUG_VISIBILITY_PUBLIC;
+ break;
+
+ case CXXFLAGS_VISIBILITY_PRIVATE:
+ visibility = DEBUG_VISIBILITY_PRIVATE;
+ break;
+
+ case CXXFLAGS_VISIBILITY_PROTECTED:
+ visibility = DEBUG_VISIBILITY_PROTECTED;
+ break;
+ }
+
+ constp = (flags & CXXFLAGS_CONST) != 0 ? true : false;
+ volatilep = (flags & CXXFLAGS_VOLATILE) != 0 ? true : false;
+
+ mangledcopy = savestring (mangled, mangledlen);
+
+ if ((flags & CXXFLAGS_STATIC) != 0)
+ {
+ if (id == 'v')
+ {
+ ieee_error (info, start, "C++ static virtual method");
+ return false;
+ }
+ mv = debug_make_static_method_variant (dhandle, mangledcopy,
+ type, visibility,
+ constp, volatilep);
+ }
+ else
+ {
+ debug_type vcontext;
+
+ if (id != 'v')
+ vcontext = DEBUG_TYPE_NULL;
+ else
+ {
+ /* FIXME: How can we calculate this correctly? */
+ vcontext = it->type;
+ }
+ mv = debug_make_method_variant (dhandle, mangledcopy, type,
+ visibility, constp,
+ volatilep, voffset,
+ vcontext);
+ }
+ if (mv == DEBUG_METHOD_VARIANT_NULL)
+ return false;
+
+ for (meth = methods, im = 0; im < methods_count; meth++, im++)
+ if (meth->namlen == namlen
+ && strncmp (meth->name, name, namlen) == 0)
+ break;
+ if (im >= methods_count)
+ {
+ if (methods_count >= methods_alloc)
+ {
+ methods_alloc += 10;
+ methods = ((struct ieee_method *)
+ xrealloc (methods,
+ methods_alloc * sizeof *methods));
+ }
+ methods[methods_count].name = name;
+ methods[methods_count].namlen = namlen;
+ methods[methods_count].variants = NULL;
+ methods[methods_count].count = 0;
+ methods[methods_count].alloc = 0;
+ meth = methods + methods_count;
+ ++methods_count;
+ }
+
+ if (meth->count + 1 >= meth->alloc)
+ {
+ meth->alloc += 10;
+ meth->variants = ((debug_method_variant *)
+ xrealloc (meth->variants,
+ (meth->alloc
+ * sizeof *meth->variants)));
+ }
+
+ meth->variants[meth->count] = mv;
+ ++meth->count;
+ meth->variants[meth->count] = DEBUG_METHOD_VARIANT_NULL;
+ }
+ break;
+
+ case 'o':
+ {
+ bfd_vma spec;
+
+ /* We have no way to store this information, so we just
+ ignore it. */
+ if (! ieee_require_asn (info, pp, &spec))
+ return false;
+ --count;
+ if ((spec & 4) != 0)
+ {
+ const char *filename;
+ unsigned long filenamlen;
+ bfd_vma lineno;
+
+ if (! ieee_require_atn65 (info, pp, &filename, &filenamlen)
+ || ! ieee_require_asn (info, pp, &lineno))
+ return false;
+ count -= 2;
+ }
+ else if ((spec & 8) != 0)
+ {
+ const char *mangled;
+ unsigned long mangledlen;
+
+ if (! ieee_require_atn65 (info, pp, &mangled, &mangledlen))
+ return false;
+ --count;
+ }
+ else
+ {
+ ieee_error (info, start,
+ "unrecognized C++ object overhead spec");
+ return false;
+ }
+ }
+ break;
+
+ case 'z':
+ {
+ const char *vname, *basename;
+ unsigned long vnamelen, baselen;
+ bfd_vma vsize, control;
+
+ /* A virtual table pointer. */
+
+ if (! ieee_require_atn65 (info, pp, &vname, &vnamelen)
+ || ! ieee_require_asn (info, pp, &vsize)
+ || ! ieee_require_atn65 (info, pp, &basename, &baselen)
+ || ! ieee_require_asn (info, pp, &control))
+ return false;
+ count -= 4;
+
+ /* We just ignore the control number. We don't care what
+ the virtual table name is. We have no way to store the
+ virtual table size, and I don't think we care anyhow. */
+
+ /* FIXME: We can't handle multiple virtual table pointers. */
+
+ if (baselen == 0)
+ ownvptr = true;
+ else
+ {
+ char *basecopy;
+
+ basecopy = savestring (basename, baselen);
+ vptrbase = debug_find_tagged_type (dhandle, basecopy,
+ DEBUG_KIND_ILLEGAL);
+ free (basecopy);
+ if (vptrbase == DEBUG_TYPE_NULL)
+ {
+ ieee_error (info, start, "undefined C++ vtable");
+ return false;
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ /* Now that we have seen all the method variants, we can call
+ debug_make_method for each one. */
+
+ if (methods_count == 0)
+ dmethods = NULL;
+ else
+ {
+ unsigned int i;
+
+ dmethods = ((debug_method *)
+ xmalloc ((methods_count + 1) * sizeof *dmethods));
+ for (i = 0; i < methods_count; i++)
+ {
+ char *namcopy;
+
+ namcopy = savestring (methods[i].name, methods[i].namlen);
+ dmethods[i] = debug_make_method (dhandle, namcopy,
+ methods[i].variants);
+ if (dmethods[i] == DEBUG_METHOD_NULL)
+ return false;
+ }
+ dmethods[i] = DEBUG_METHOD_NULL;
+ free (methods);
+ }
+
+ /* The struct type was created as an indirect type pointing at
+ it->slot. We update it->slot to automatically update all
+ references to this struct. */
+ it->slot = debug_make_object_type (dhandle,
+ class != 'u',
+ debug_get_type_size (dhandle,
+ it->slot),
+ fields, baseclasses, dmethods,
+ vptrbase, ownvptr);
+ if (it->slot == DEBUG_TYPE_NULL)
+ return false;
+
+ return true;
+}
+
+/* Read C++ default argument value and reference type information. */
+
+static boolean
+ieee_read_cxx_defaults (info, pp, count)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+ unsigned long count;
+{
+ const bfd_byte *start;
+ const char *fnname;
+ unsigned long fnlen;
+ bfd_vma defcount;
+
+ start = *pp;
+
+ /* Giving the function name before the argument count is an addendum
+ to the spec. The function name is demangled, though, so this
+ record must always refer to the current function. */
+
+ if (info->blockstack.bsp <= info->blockstack.stack
+ || info->blockstack.bsp[-1].fnindx == (unsigned int) -1)
+ {
+ ieee_error (info, start, "C++ default values not in a function");
+ return false;
+ }
+
+ if (! ieee_require_atn65 (info, pp, &fnname, &fnlen)
+ || ! ieee_require_asn (info, pp, &defcount))
+ return false;
+ count -= 2;
+
+ while (defcount-- > 0)
+ {
+ bfd_vma type, val;
+ const char *strval;
+ unsigned long strvallen;
+
+ if (! ieee_require_asn (info, pp, &type))
+ return false;
+ --count;
+
+ switch (type)
+ {
+ case 0:
+ case 4:
+ break;
+
+ case 1:
+ case 2:
+ if (! ieee_require_asn (info, pp, &val))
+ return false;
+ --count;
+ break;
+
+ case 3:
+ case 7:
+ if (! ieee_require_atn65 (info, pp, &strval, &strvallen))
+ return false;
+ --count;
+ break;
+
+ default:
+ ieee_error (info, start, "unrecognized C++ default type");
+ return false;
+ }
+
+ /* We have no way to record the default argument values, so we
+ just ignore them. FIXME. */
+ }
+
+ /* Any remaining arguments are indices of parameters that are really
+ reference type. */
+ if (count > 0)
+ {
+ PTR dhandle;
+ debug_type *arg_slots;
+
+ dhandle = info->dhandle;
+ arg_slots = info->types.types[info->blockstack.bsp[-1].fnindx].arg_slots;
+ while (count-- > 0)
+ {
+ bfd_vma indx;
+ debug_type target;
+
+ if (! ieee_require_asn (info, pp, &indx))
+ return false;
+ /* The index is 1 based. */
+ --indx;
+ if (arg_slots == NULL
+ || arg_slots[indx] == DEBUG_TYPE_NULL
+ || (debug_get_type_kind (dhandle, arg_slots[indx])
+ != DEBUG_KIND_POINTER))
+ {
+ ieee_error (info, start, "reference parameter is not a pointer");
+ return false;
+ }
+
+ target = debug_get_target_type (dhandle, arg_slots[indx]);
+ arg_slots[indx] = debug_make_reference_type (dhandle, target);
+ if (arg_slots[indx] == DEBUG_TYPE_NULL)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* Read a C++ reference definition. */
+
+static boolean
+ieee_read_reference (info, pp)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+{
+ const bfd_byte *start;
+ bfd_vma flags;
+ const char *class, *name;
+ unsigned long classlen, namlen;
+ debug_type *pslot;
+ debug_type target;
+
+ start = *pp;
+
+ if (! ieee_require_asn (info, pp, &flags))
+ return false;
+
+ /* Giving the class name before the member name is in an addendum to
+ the spec. */
+ if (flags == 3)
+ {
+ if (! ieee_require_atn65 (info, pp, &class, &classlen))
+ return false;
+ }
+
+ if (! ieee_require_atn65 (info, pp, &name, &namlen))
+ return false;
+
+ pslot = NULL;
+ if (flags != 3)
+ {
+ int pass;
+
+ /* We search from the last variable indices to the first in
+ hopes of finding local variables correctly. We search the
+ local variables on the first pass, and the global variables
+ on the second. FIXME: This probably won't work in all cases.
+ On the other hand, I don't know what will. */
+ for (pass = 0; pass < 2; pass++)
+ {
+ struct ieee_vars *vars;
+ int i;
+ struct ieee_var *pv = NULL;
+
+ if (pass == 0)
+ vars = &info->vars;
+ else
+ {
+ vars = info->global_vars;
+ if (vars == NULL)
+ break;
+ }
+
+ for (i = (int) vars->alloc - 1; i >= 0; i--)
+ {
+ boolean found;
+
+ pv = vars->vars + i;
+
+ if (pv->pslot == NULL
+ || pv->namlen != namlen
+ || strncmp (pv->name, name, namlen) != 0)
+ continue;
+
+ found = false;
+ switch (flags)
+ {
+ default:
+ ieee_error (info, start,
+ "unrecognized C++ reference type");
+ return false;
+
+ case 0:
+ /* Global variable or function. */
+ if (pv->kind == IEEE_GLOBAL
+ || pv->kind == IEEE_EXTERNAL
+ || pv->kind == IEEE_FUNCTION)
+ found = true;
+ break;
+
+ case 1:
+ /* Global static variable or function. */
+ if (pv->kind == IEEE_STATIC
+ || pv->kind == IEEE_FUNCTION)
+ found = true;
+ break;
+
+ case 2:
+ /* Local variable. */
+ if (pv->kind == IEEE_LOCAL)
+ found = true;
+ break;
+ }
+
+ if (found)
+ break;
+ }
+
+ if (i >= 0)
+ {
+ pslot = pv->pslot;
+ break;
+ }
+ }
+ }
+ else
+ {
+ struct ieee_tag *it;
+
+ for (it = info->tags; it != NULL; it = it->next)
+ {
+ if (it->name[0] == class[0]
+ && strncmp (it->name, class, classlen) == 0
+ && strlen (it->name) == classlen)
+ {
+ if (it->fslots != NULL)
+ {
+ const debug_field *pf;
+ unsigned int findx;
+
+ pf = debug_get_fields (info->dhandle, it->type);
+ if (pf == NULL)
+ {
+ ieee_error (info, start,
+ "C++ reference in class with no fields");
+ return false;
+ }
+
+ for (findx = 0; *pf != DEBUG_FIELD_NULL; pf++, findx++)
+ {
+ const char *fname;
+
+ fname = debug_get_field_name (info->dhandle, *pf);
+ if (fname == NULL)
+ return false;
+ if (strncmp (fname, name, namlen) == 0
+ && strlen (fname) == namlen)
+ {
+ pslot = it->fslots + findx;
+ break;
+ }
+ }
+ }
+
+ break;
+ }
+ }
+ }
+
+ if (pslot == NULL)
+ {
+ ieee_error (info, start, "C++ reference not found");
+ return false;
+ }
+
+ /* We allocated the type of the object as an indirect type pointing
+ to *pslot, which we can now update to be a reference type. */
+ if (debug_get_type_kind (info->dhandle, *pslot) != DEBUG_KIND_POINTER)
+ {
+ ieee_error (info, start, "C++ reference is not pointer");
+ return false;
+ }
+
+ target = debug_get_target_type (info->dhandle, *pslot);
+ *pslot = debug_make_reference_type (info->dhandle, target);
+ if (*pslot == DEBUG_TYPE_NULL)
+ return false;
+
+ return true;
+}
+
+/* Require an ASN record. */
+
+static boolean
+ieee_require_asn (info, pp, pv)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+ bfd_vma *pv;
+{
+ const bfd_byte *start;
+ ieee_record_enum_type c;
+ bfd_vma varindx;
+
+ start = *pp;
+
+ c = (ieee_record_enum_type) **pp;
+ if (c != ieee_e2_first_byte_enum)
+ {
+ ieee_error (info, start, "missing required ASN");
+ return false;
+ }
+ ++*pp;
+
+ c = (ieee_record_enum_type) (((unsigned int) c << 8) | **pp);
+ if (c != ieee_asn_record_enum)
+ {
+ ieee_error (info, start, "missing required ASN");
+ return false;
+ }
+ ++*pp;
+
+ /* Just ignore the variable index. */
+ if (! ieee_read_number (info, pp, &varindx))
+ return false;
+
+ return ieee_read_expression (info, pp, pv);
+}
+
+/* Require an ATN65 record. */
+
+static boolean
+ieee_require_atn65 (info, pp, pname, pnamlen)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+ const char **pname;
+ unsigned long *pnamlen;
+{
+ const bfd_byte *start;
+ ieee_record_enum_type c;
+ bfd_vma name_indx, type_indx, atn_code;
+
+ start = *pp;
+
+ c = (ieee_record_enum_type) **pp;
+ if (c != ieee_at_record_enum)
+ {
+ ieee_error (info, start, "missing required ATN65");
+ return false;
+ }
+ ++*pp;
+
+ c = (ieee_record_enum_type) (((unsigned int) c << 8) | **pp);
+ if (c != ieee_atn_record_enum)
+ {
+ ieee_error (info, start, "missing required ATN65");
+ return false;
+ }
+ ++*pp;
+
+ if (! ieee_read_number (info, pp, &name_indx)
+ || ! ieee_read_number (info, pp, &type_indx)
+ || ! ieee_read_number (info, pp, &atn_code))
+ return false;
+
+ /* Just ignore name_indx. */
+
+ if (type_indx != 0 || atn_code != 65)
+ {
+ ieee_error (info, start, "bad ATN65 record");
+ return false;
+ }
+
+ return ieee_read_id (info, pp, pname, pnamlen);
+}
+
+/* Convert a register number in IEEE debugging information into a
+ generic register number. */
+
+static int
+ieee_regno_to_genreg (abfd, r)
+ bfd *abfd;
+ int r;
+{
+ switch (bfd_get_arch (abfd))
+ {
+ case bfd_arch_m68k:
+ /* For some reasons stabs adds 2 to the floating point register
+ numbers. */
+ if (r >= 16)
+ r += 2;
+ break;
+
+ case bfd_arch_i960:
+ /* Stabs uses 0 to 15 for r0 to r15, 16 to 31 for g0 to g15, and
+ 32 to 35 for fp0 to fp3. */
+ --r;
+ break;
+
+ default:
+ break;
+ }
+
+ return r;
+}
+
+/* Convert a generic register number to an IEEE specific one. */
+
+static int
+ieee_genreg_to_regno (abfd, r)
+ bfd *abfd;
+ int r;
+{
+ switch (bfd_get_arch (abfd))
+ {
+ case bfd_arch_m68k:
+ /* For some reason stabs add 2 to the floating point register
+ numbers. */
+ if (r >= 18)
+ r -= 2;
+ break;
+
+ case bfd_arch_i960:
+ /* Stabs uses 0 to 15 for r0 to r15, 16 to 31 for g0 to g15, and
+ 32 to 35 for fp0 to fp3. */
+ ++r;
+ break;
+
+ default:
+ break;
+ }
+
+ return r;
+}
+
+/* These routines build IEEE debugging information out of the generic
+ debugging information. */
+
+/* We build the IEEE debugging information byte by byte. Rather than
+ waste time copying data around, we use a linked list of buffers to
+ hold the data. */
+
+#define IEEE_BUFSIZE (490)
+
+struct ieee_buf
+{
+ /* Next buffer. */
+ struct ieee_buf *next;
+ /* Number of data bytes in this buffer. */
+ unsigned int c;
+ /* Bytes. */
+ bfd_byte buf[IEEE_BUFSIZE];
+};
+
+/* A list of buffers. */
+
+struct ieee_buflist
+{
+ /* Head of list. */
+ struct ieee_buf *head;
+ /* Tail--last buffer on list. */
+ struct ieee_buf *tail;
+};
+
+/* In order to generate the BB11 blocks required by the HP emulator,
+ we keep track of ranges of addresses which correspond to a given
+ compilation unit. */
+
+struct ieee_range
+{
+ /* Next range. */
+ struct ieee_range *next;
+ /* Low address. */
+ bfd_vma low;
+ /* High address. */
+ bfd_vma high;
+};
+
+/* This structure holds information for a class on the type stack. */
+
+struct ieee_type_class
+{
+ /* The name index in the debugging information. */
+ unsigned int indx;
+ /* The pmisc records for the class. */
+ struct ieee_buflist pmiscbuf;
+ /* The number of pmisc records. */
+ unsigned int pmisccount;
+ /* The name of the class holding the virtual table, if not this
+ class. */
+ const char *vclass;
+ /* Whether this class holds its own virtual table. */
+ boolean ownvptr;
+ /* The largest virtual table offset seen so far. */
+ bfd_vma voffset;
+ /* The current method. */
+ const char *method;
+ /* Additional pmisc records used to record fields of reference type. */
+ struct ieee_buflist refs;
+};
+
+/* This is how we store types for the writing routines. Most types
+ are simply represented by a type index. */
+
+struct ieee_write_type
+{
+ /* Type index. */
+ unsigned int indx;
+ /* The size of the type, if known. */
+ unsigned int size;
+ /* The name of the type, if any. */
+ const char *name;
+ /* If this is a function or method type, we build the type here, and
+ only add it to the output buffers if we need it. */
+ struct ieee_buflist fndef;
+ /* If this is a struct, this is where the struct definition is
+ built. */
+ struct ieee_buflist strdef;
+ /* If this is a class, this is where the class information is built. */
+ struct ieee_type_class *classdef;
+ /* Whether the type is unsigned. */
+ unsigned int unsignedp : 1;
+ /* Whether this is a reference type. */
+ unsigned int referencep : 1;
+ /* Whether this is in the local type block. */
+ unsigned int localp : 1;
+ /* Whether this is a duplicate struct definition which we are
+ ignoring. */
+ unsigned int ignorep : 1;
+};
+
+/* This is the type stack used by the debug writing routines. FIXME:
+ We could generate more efficient output if we remembered when we
+ have output a particular type before. */
+
+struct ieee_type_stack
+{
+ /* Next entry on stack. */
+ struct ieee_type_stack *next;
+ /* Type information. */
+ struct ieee_write_type type;
+};
+
+/* This is a list of associations between a name and some types.
+ These are used for typedefs and tags. */
+
+struct ieee_name_type
+{
+ /* Next type for this name. */
+ struct ieee_name_type *next;
+ /* ID number. For a typedef, this is the index of the type to which
+ this name is typedefed. */
+ unsigned int id;
+ /* Type. */
+ struct ieee_write_type type;
+ /* If this is a tag which has not yet been defined, this is the
+ kind. If the tag has been defined, this is DEBUG_KIND_ILLEGAL. */
+ enum debug_type_kind kind;
+};
+
+/* We use a hash table to associate names and types. */
+
+struct ieee_name_type_hash_table
+{
+ struct bfd_hash_table root;
+};
+
+struct ieee_name_type_hash_entry
+{
+ struct bfd_hash_entry root;
+ /* Information for this name. */
+ struct ieee_name_type *types;
+};
+
+/* This is a list of enums. */
+
+struct ieee_defined_enum
+{
+ /* Next enum. */
+ struct ieee_defined_enum *next;
+ /* Type index. */
+ unsigned int indx;
+ /* Whether this enum has been defined. */
+ boolean defined;
+ /* Tag. */
+ const char *tag;
+ /* Names. */
+ const char **names;
+ /* Values. */
+ bfd_signed_vma *vals;
+};
+
+/* We keep a list of modified versions of types, so that we don't
+ output them more than once. */
+
+struct ieee_modified_type
+{
+ /* Pointer to this type. */
+ unsigned int pointer;
+ /* Function with unknown arguments returning this type. */
+ unsigned int function;
+ /* Const version of this type. */
+ unsigned int const_qualified;
+ /* Volatile version of this type. */
+ unsigned int volatile_qualified;
+ /* List of arrays of this type of various bounds. */
+ struct ieee_modified_array_type *arrays;
+};
+
+/* A list of arrays bounds. */
+
+struct ieee_modified_array_type
+{
+ /* Next array bounds. */
+ struct ieee_modified_array_type *next;
+ /* Type index with these bounds. */
+ unsigned int indx;
+ /* Low bound. */
+ bfd_signed_vma low;
+ /* High bound. */
+ bfd_signed_vma high;
+};
+
+/* This is a list of pending function parameter information. We don't
+ output them until we see the first block. */
+
+struct ieee_pending_parm
+{
+ /* Next pending parameter. */
+ struct ieee_pending_parm *next;
+ /* Name. */
+ const char *name;
+ /* Type index. */
+ unsigned int type;
+ /* Whether the type is a reference. */
+ boolean referencep;
+ /* Kind. */
+ enum debug_parm_kind kind;
+ /* Value. */
+ bfd_vma val;
+};
+
+/* This is the handle passed down by debug_write. */
+
+struct ieee_handle
+{
+ /* BFD we are writing to. */
+ bfd *abfd;
+ /* Whether we got an error in a subroutine called via traverse or
+ map_over_sections. */
+ boolean error;
+ /* Current data buffer list. */
+ struct ieee_buflist *current;
+ /* Current data buffer. */
+ struct ieee_buf *curbuf;
+ /* Filename of current compilation unit. */
+ const char *filename;
+ /* Module name of current compilation unit. */
+ const char *modname;
+ /* List of buffer for global types. */
+ struct ieee_buflist global_types;
+ /* List of finished data buffers. */
+ struct ieee_buflist data;
+ /* List of buffers for typedefs in the current compilation unit. */
+ struct ieee_buflist types;
+ /* List of buffers for variables and functions in the current
+ compilation unit. */
+ struct ieee_buflist vars;
+ /* List of buffers for C++ class definitions in the current
+ compilation unit. */
+ struct ieee_buflist cxx;
+ /* List of buffers for line numbers in the current compilation unit. */
+ struct ieee_buflist linenos;
+ /* Ranges for the current compilation unit. */
+ struct ieee_range *ranges;
+ /* Ranges for all debugging information. */
+ struct ieee_range *global_ranges;
+ /* Nested pending ranges. */
+ struct ieee_range *pending_ranges;
+ /* Type stack. */
+ struct ieee_type_stack *type_stack;
+ /* Next unallocated type index. */
+ unsigned int type_indx;
+ /* Next unallocated name index. */
+ unsigned int name_indx;
+ /* Typedefs. */
+ struct ieee_name_type_hash_table typedefs;
+ /* Tags. */
+ struct ieee_name_type_hash_table tags;
+ /* Enums. */
+ struct ieee_defined_enum *enums;
+ /* Modified versions of types. */
+ struct ieee_modified_type *modified;
+ /* Number of entries allocated in modified. */
+ unsigned int modified_alloc;
+ /* 4 byte complex type. */
+ unsigned int complex_float_index;
+ /* 8 byte complex type. */
+ unsigned int complex_double_index;
+ /* The depth of block nesting. This is 0 outside a function, and 1
+ just after start_function is called. */
+ unsigned int block_depth;
+ /* The name of the current function. */
+ const char *fnname;
+ /* List of buffers for the type of the function we are currently
+ writing out. */
+ struct ieee_buflist fntype;
+ /* List of buffers for the parameters of the function we are
+ currently writing out. */
+ struct ieee_buflist fnargs;
+ /* Number of arguments written to fnargs. */
+ unsigned int fnargcount;
+ /* Pending function parameters. */
+ struct ieee_pending_parm *pending_parms;
+ /* Current line number filename. */
+ const char *lineno_filename;
+ /* Line number name index. */
+ unsigned int lineno_name_indx;
+ /* Filename of pending line number. */
+ const char *pending_lineno_filename;
+ /* Pending line number. */
+ unsigned long pending_lineno;
+ /* Address of pending line number. */
+ bfd_vma pending_lineno_addr;
+ /* Highest address seen at end of procedure. */
+ bfd_vma highaddr;
+};
+
+static boolean ieee_init_buffer
+ PARAMS ((struct ieee_handle *, struct ieee_buflist *));
+static boolean ieee_change_buffer
+ PARAMS ((struct ieee_handle *, struct ieee_buflist *));
+static boolean ieee_append_buffer
+ PARAMS ((struct ieee_handle *, struct ieee_buflist *,
+ struct ieee_buflist *));
+static boolean ieee_real_write_byte PARAMS ((struct ieee_handle *, int));
+static boolean ieee_write_2bytes PARAMS ((struct ieee_handle *, int));
+static boolean ieee_write_number PARAMS ((struct ieee_handle *, bfd_vma));
+static boolean ieee_write_id PARAMS ((struct ieee_handle *, const char *));
+static boolean ieee_write_asn
+ PARAMS ((struct ieee_handle *, unsigned int, bfd_vma));
+static boolean ieee_write_atn65
+ PARAMS ((struct ieee_handle *, unsigned int, const char *));
+static boolean ieee_push_type
+ PARAMS ((struct ieee_handle *, unsigned int, unsigned int, boolean,
+ boolean));
+static unsigned int ieee_pop_type PARAMS ((struct ieee_handle *));
+static void ieee_pop_unused_type PARAMS ((struct ieee_handle *));
+static unsigned int ieee_pop_type_used
+ PARAMS ((struct ieee_handle *, boolean));
+static boolean ieee_add_range
+ PARAMS ((struct ieee_handle *, boolean, bfd_vma, bfd_vma));
+static boolean ieee_start_range PARAMS ((struct ieee_handle *, bfd_vma));
+static boolean ieee_end_range PARAMS ((struct ieee_handle *, bfd_vma));
+static boolean ieee_define_type
+ PARAMS ((struct ieee_handle *, unsigned int, boolean, boolean));
+static boolean ieee_define_named_type
+ PARAMS ((struct ieee_handle *, const char *, unsigned int, unsigned int,
+ boolean, boolean, struct ieee_buflist *));
+static struct ieee_modified_type *ieee_get_modified_info
+ PARAMS ((struct ieee_handle *, unsigned int));
+static struct bfd_hash_entry *ieee_name_type_newfunc
+ PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
+static boolean ieee_write_undefined_tag
+ PARAMS ((struct ieee_name_type_hash_entry *, PTR));
+static boolean ieee_finish_compilation_unit PARAMS ((struct ieee_handle *));
+static void ieee_add_bb11_blocks PARAMS ((bfd *, asection *, PTR));
+static boolean ieee_add_bb11
+ PARAMS ((struct ieee_handle *, asection *, bfd_vma, bfd_vma));
+static boolean ieee_output_pending_parms PARAMS ((struct ieee_handle *));
+static unsigned int ieee_vis_to_flags PARAMS ((enum debug_visibility));
+static boolean ieee_class_method_var
+ PARAMS ((struct ieee_handle *, const char *, enum debug_visibility, boolean,
+ boolean, boolean, bfd_vma, boolean));
+
+static boolean ieee_start_compilation_unit PARAMS ((PTR, const char *));
+static boolean ieee_start_source PARAMS ((PTR, const char *));
+static boolean ieee_empty_type PARAMS ((PTR));
+static boolean ieee_void_type PARAMS ((PTR));
+static boolean ieee_int_type PARAMS ((PTR, unsigned int, boolean));
+static boolean ieee_float_type PARAMS ((PTR, unsigned int));
+static boolean ieee_complex_type PARAMS ((PTR, unsigned int));
+static boolean ieee_bool_type PARAMS ((PTR, unsigned int));
+static boolean ieee_enum_type
+ PARAMS ((PTR, const char *, const char **, bfd_signed_vma *));
+static boolean ieee_pointer_type PARAMS ((PTR));
+static boolean ieee_function_type PARAMS ((PTR, int, boolean));
+static boolean ieee_reference_type PARAMS ((PTR));
+static boolean ieee_range_type PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma));
+static boolean ieee_array_type
+ PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma, boolean));
+static boolean ieee_set_type PARAMS ((PTR, boolean));
+static boolean ieee_offset_type PARAMS ((PTR));
+static boolean ieee_method_type PARAMS ((PTR, boolean, int, boolean));
+static boolean ieee_const_type PARAMS ((PTR));
+static boolean ieee_volatile_type PARAMS ((PTR));
+static boolean ieee_start_struct_type
+ PARAMS ((PTR, const char *, unsigned int, boolean, unsigned int));
+static boolean ieee_struct_field
+ PARAMS ((PTR, const char *, bfd_vma, bfd_vma, enum debug_visibility));
+static boolean ieee_end_struct_type PARAMS ((PTR));
+static boolean ieee_start_class_type
+ PARAMS ((PTR, const char *, unsigned int, boolean, unsigned int, boolean,
+ boolean));
+static boolean ieee_class_static_member
+ PARAMS ((PTR, const char *, const char *, enum debug_visibility));
+static boolean ieee_class_baseclass
+ PARAMS ((PTR, bfd_vma, boolean, enum debug_visibility));
+static boolean ieee_class_start_method PARAMS ((PTR, const char *));
+static boolean ieee_class_method_variant
+ PARAMS ((PTR, const char *, enum debug_visibility, boolean, boolean,
+ bfd_vma, boolean));
+static boolean ieee_class_static_method_variant
+ PARAMS ((PTR, const char *, enum debug_visibility, boolean, boolean));
+static boolean ieee_class_end_method PARAMS ((PTR));
+static boolean ieee_end_class_type PARAMS ((PTR));
+static boolean ieee_typedef_type PARAMS ((PTR, const char *));
+static boolean ieee_tag_type
+ PARAMS ((PTR, const char *, unsigned int, enum debug_type_kind));
+static boolean ieee_typdef PARAMS ((PTR, const char *));
+static boolean ieee_tag PARAMS ((PTR, const char *));
+static boolean ieee_int_constant PARAMS ((PTR, const char *, bfd_vma));
+static boolean ieee_float_constant PARAMS ((PTR, const char *, double));
+static boolean ieee_typed_constant PARAMS ((PTR, const char *, bfd_vma));
+static boolean ieee_variable
+ PARAMS ((PTR, const char *, enum debug_var_kind, bfd_vma));
+static boolean ieee_start_function PARAMS ((PTR, const char *, boolean));
+static boolean ieee_function_parameter
+ PARAMS ((PTR, const char *, enum debug_parm_kind, bfd_vma));
+static boolean ieee_start_block PARAMS ((PTR, bfd_vma));
+static boolean ieee_end_block PARAMS ((PTR, bfd_vma));
+static boolean ieee_end_function PARAMS ((PTR));
+static boolean ieee_lineno
+ PARAMS ((PTR, const char *, unsigned long, bfd_vma));
+
+static const struct debug_write_fns ieee_fns =
+{
+ ieee_start_compilation_unit,
+ ieee_start_source,
+ ieee_empty_type,
+ ieee_void_type,
+ ieee_int_type,
+ ieee_float_type,
+ ieee_complex_type,
+ ieee_bool_type,
+ ieee_enum_type,
+ ieee_pointer_type,
+ ieee_function_type,
+ ieee_reference_type,
+ ieee_range_type,
+ ieee_array_type,
+ ieee_set_type,
+ ieee_offset_type,
+ ieee_method_type,
+ ieee_const_type,
+ ieee_volatile_type,
+ ieee_start_struct_type,
+ ieee_struct_field,
+ ieee_end_struct_type,
+ ieee_start_class_type,
+ ieee_class_static_member,
+ ieee_class_baseclass,
+ ieee_class_start_method,
+ ieee_class_method_variant,
+ ieee_class_static_method_variant,
+ ieee_class_end_method,
+ ieee_end_class_type,
+ ieee_typedef_type,
+ ieee_tag_type,
+ ieee_typdef,
+ ieee_tag,
+ ieee_int_constant,
+ ieee_float_constant,
+ ieee_typed_constant,
+ ieee_variable,
+ ieee_start_function,
+ ieee_function_parameter,
+ ieee_start_block,
+ ieee_end_block,
+ ieee_end_function,
+ ieee_lineno
+};
+
+/* Initialize a buffer to be empty. */
+
+/*ARGSUSED*/
+static boolean
+ieee_init_buffer (info, buflist)
+ struct ieee_handle *info;
+ struct ieee_buflist *buflist;
+{
+ buflist->head = NULL;
+ buflist->tail = NULL;
+ return true;
+}
+
+/* See whether a buffer list has any data. */
+
+#define ieee_buffer_emptyp(buflist) ((buflist)->head == NULL)
+
+/* Change the current buffer to a specified buffer chain. */
+
+static boolean
+ieee_change_buffer (info, buflist)
+ struct ieee_handle *info;
+ struct ieee_buflist *buflist;
+{
+ if (buflist->head == NULL)
+ {
+ struct ieee_buf *buf;
+
+ buf = (struct ieee_buf *) xmalloc (sizeof *buf);
+ buf->next = NULL;
+ buf->c = 0;
+ buflist->head = buf;
+ buflist->tail = buf;
+ }
+
+ info->current = buflist;
+ info->curbuf = buflist->tail;
+
+ return true;
+}
+
+/* Append a buffer chain. */
+
+/*ARGSUSED*/
+static boolean
+ieee_append_buffer (info, mainbuf, newbuf)
+ struct ieee_handle *info;
+ struct ieee_buflist *mainbuf;
+ struct ieee_buflist *newbuf;
+{
+ if (newbuf->head != NULL)
+ {
+ if (mainbuf->head == NULL)
+ mainbuf->head = newbuf->head;
+ else
+ mainbuf->tail->next = newbuf->head;
+ mainbuf->tail = newbuf->tail;
+ }
+ return true;
+}
+
+/* Write a byte into the buffer. We use a macro for speed and a
+ function for the complex cases. */
+
+#define ieee_write_byte(info, b) \
+ ((info)->curbuf->c < IEEE_BUFSIZE \
+ ? ((info)->curbuf->buf[(info)->curbuf->c++] = (b), true) \
+ : ieee_real_write_byte ((info), (b)))
+
+static boolean
+ieee_real_write_byte (info, b)
+ struct ieee_handle *info;
+ int b;
+{
+ if (info->curbuf->c >= IEEE_BUFSIZE)
+ {
+ struct ieee_buf *n;
+
+ n = (struct ieee_buf *) xmalloc (sizeof *n);
+ n->next = NULL;
+ n->c = 0;
+ if (info->current->head == NULL)
+ info->current->head = n;
+ else
+ info->current->tail->next = n;
+ info->current->tail = n;
+ info->curbuf = n;
+ }
+
+ info->curbuf->buf[info->curbuf->c] = b;
+ ++info->curbuf->c;
+
+ return true;
+}
+
+/* Write out two bytes. */
+
+static boolean
+ieee_write_2bytes (info, i)
+ struct ieee_handle *info;
+ int i;
+{
+ return (ieee_write_byte (info, i >> 8)
+ && ieee_write_byte (info, i & 0xff));
+}
+
+/* Write out an integer. */
+
+static boolean
+ieee_write_number (info, v)
+ struct ieee_handle *info;
+ bfd_vma v;
+{
+ bfd_vma t;
+ bfd_byte ab[20];
+ bfd_byte *p;
+ unsigned int c;
+
+ if (v <= (bfd_vma) ieee_number_end_enum)
+ return ieee_write_byte (info, (int) v);
+
+ t = v;
+ p = ab + sizeof ab;
+ while (t != 0)
+ {
+ *--p = t & 0xff;
+ t >>= 8;
+ }
+ c = (ab + 20) - p;
+
+ if (c > (unsigned int) (ieee_number_repeat_end_enum
+ - ieee_number_repeat_start_enum))
+ {
+ fprintf (stderr, "IEEE numeric overflow: 0x");
+ fprintf_vma (stderr, v);
+ fprintf (stderr, "\n");
+ return false;
+ }
+
+ if (! ieee_write_byte (info, (int) ieee_number_repeat_start_enum + c))
+ return false;
+ for (; c > 0; --c, ++p)
+ {
+ if (! ieee_write_byte (info, *p))
+ return false;
+ }
+
+ return true;
+}
+
+/* Write out a string. */
+
+static boolean
+ieee_write_id (info, s)
+ struct ieee_handle *info;
+ const char *s;
+{
+ unsigned int len;
+
+ len = strlen (s);
+ if (len <= 0x7f)
+ {
+ if (! ieee_write_byte (info, len))
+ return false;
+ }
+ else if (len <= 0xff)
+ {
+ if (! ieee_write_byte (info, (int) ieee_extension_length_1_enum)
+ || ! ieee_write_byte (info, len))
+ return false;
+ }
+ else if (len <= 0xffff)
+ {
+ if (! ieee_write_byte (info, (int) ieee_extension_length_2_enum)
+ || ! ieee_write_2bytes (info, len))
+ return false;
+ }
+ else
+ {
+ fprintf (stderr, "IEEE string length overflow: %u\n", len);
+ return false;
+ }
+
+ for (; *s != '\0'; s++)
+ if (! ieee_write_byte (info, *s))
+ return false;
+
+ return true;
+}
+
+/* Write out an ASN record. */
+
+static boolean
+ieee_write_asn (info, indx, val)
+ struct ieee_handle *info;
+ unsigned int indx;
+ bfd_vma val;
+{
+ return (ieee_write_2bytes (info, (int) ieee_asn_record_enum)
+ && ieee_write_number (info, indx)
+ && ieee_write_number (info, val));
+}
+
+/* Write out an ATN65 record. */
+
+static boolean
+ieee_write_atn65 (info, indx, s)
+ struct ieee_handle *info;
+ unsigned int indx;
+ const char *s;
+{
+ return (ieee_write_2bytes (info, (int) ieee_atn_record_enum)
+ && ieee_write_number (info, indx)
+ && ieee_write_number (info, 0)
+ && ieee_write_number (info, 65)
+ && ieee_write_id (info, s));
+}
+
+/* Push a type index onto the type stack. */
+
+static boolean
+ieee_push_type (info, indx, size, unsignedp, localp)
+ struct ieee_handle *info;
+ unsigned int indx;
+ unsigned int size;
+ boolean unsignedp;
+ boolean localp;
+{
+ struct ieee_type_stack *ts;
+
+ ts = (struct ieee_type_stack *) xmalloc (sizeof *ts);
+ memset (ts, 0, sizeof *ts);
+
+ ts->type.indx = indx;
+ ts->type.size = size;
+ ts->type.unsignedp = unsignedp;
+ ts->type.localp = localp;
+
+ ts->next = info->type_stack;
+ info->type_stack = ts;
+
+ return true;
+}
+
+/* Pop a type index off the type stack. */
+
+static unsigned int
+ieee_pop_type (info)
+ struct ieee_handle *info;
+{
+ return ieee_pop_type_used (info, true);
+}
+
+/* Pop an unused type index off the type stack. */
+
+static void
+ieee_pop_unused_type (info)
+ struct ieee_handle *info;
+{
+ (void) ieee_pop_type_used (info, false);
+}
+
+/* Pop a used or unused type index off the type stack. */
+
+static unsigned int
+ieee_pop_type_used (info, used)
+ struct ieee_handle *info;
+ boolean used;
+{
+ struct ieee_type_stack *ts;
+ unsigned int ret;
+
+ ts = info->type_stack;
+ assert (ts != NULL);
+
+ /* If this is a function type, and we need it, we need to append the
+ actual definition to the typedef block now. */
+ if (used && ! ieee_buffer_emptyp (&ts->type.fndef))
+ {
+ struct ieee_buflist *buflist;
+
+ if (ts->type.localp)
+ {
+ /* Make sure we have started the types block. */
+ if (ieee_buffer_emptyp (&info->types))
+ {
+ if (! ieee_change_buffer (info, &info->types)
+ || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 1)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, info->modname))
+ return false;
+ }
+ buflist = &info->types;
+ }
+ else
+ {
+ /* Make sure we started the global type block. */
+ if (ieee_buffer_emptyp (&info->global_types))
+ {
+ if (! ieee_change_buffer (info, &info->global_types)
+ || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 2)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, ""))
+ return false;
+ }
+ buflist = &info->global_types;
+ }
+
+ if (! ieee_append_buffer (info, buflist, &ts->type.fndef))
+ return false;
+ }
+
+ ret = ts->type.indx;
+ info->type_stack = ts->next;
+ free (ts);
+ return ret;
+}
+
+/* Add a range of bytes included in the current compilation unit. */
+
+static boolean
+ieee_add_range (info, global, low, high)
+ struct ieee_handle *info;
+ boolean global;
+ bfd_vma low;
+ bfd_vma high;
+{
+ struct ieee_range **plist, *r, **pr;
+
+ if (low == (bfd_vma) -1 || high == (bfd_vma) -1 || low == high)
+ return true;
+
+ if (global)
+ plist = &info->global_ranges;
+ else
+ plist = &info->ranges;
+
+ for (r = *plist; r != NULL; r = r->next)
+ {
+ if (high >= r->low && low <= r->high)
+ {
+ /* The new range overlaps r. */
+ if (low < r->low)
+ r->low = low;
+ if (high > r->high)
+ r->high = high;
+ pr = &r->next;
+ while (*pr != NULL && (*pr)->low <= r->high)
+ {
+ struct ieee_range *n;
+
+ if ((*pr)->high > r->high)
+ r->high = (*pr)->high;
+ n = (*pr)->next;
+ free (*pr);
+ *pr = n;
+ }
+ return true;
+ }
+ }
+
+ r = (struct ieee_range *) xmalloc (sizeof *r);
+ memset (r, 0, sizeof *r);
+
+ r->low = low;
+ r->high = high;
+
+ /* Store the ranges sorted by address. */
+ for (pr = plist; *pr != NULL; pr = &(*pr)->next)
+ if ((*pr)->low > high)
+ break;
+ r->next = *pr;
+ *pr = r;
+
+ return true;
+}
+
+/* Start a new range for which we only have the low address. */
+
+static boolean
+ieee_start_range (info, low)
+ struct ieee_handle *info;
+ bfd_vma low;
+{
+ struct ieee_range *r;
+
+ r = (struct ieee_range *) xmalloc (sizeof *r);
+ memset (r, 0, sizeof *r);
+ r->low = low;
+ r->next = info->pending_ranges;
+ info->pending_ranges = r;
+ return true;
+}
+
+/* Finish a range started by ieee_start_range. */
+
+static boolean
+ieee_end_range (info, high)
+ struct ieee_handle *info;
+ bfd_vma high;
+{
+ struct ieee_range *r;
+ bfd_vma low;
+
+ assert (info->pending_ranges != NULL);
+ r = info->pending_ranges;
+ low = r->low;
+ info->pending_ranges = r->next;
+ free (r);
+ return ieee_add_range (info, false, low, high);
+}
+
+/* Start defining a type. */
+
+static boolean
+ieee_define_type (info, size, unsignedp, localp)
+ struct ieee_handle *info;
+ unsigned int size;
+ boolean unsignedp;
+ boolean localp;
+{
+ return ieee_define_named_type (info, (const char *) NULL,
+ (unsigned int) -1, size, unsignedp,
+ localp, (struct ieee_buflist *) NULL);
+}
+
+/* Start defining a named type. */
+
+static boolean
+ieee_define_named_type (info, name, indx, size, unsignedp, localp, buflist)
+ struct ieee_handle *info;
+ const char *name;
+ unsigned int indx;
+ unsigned int size;
+ boolean unsignedp;
+ boolean localp;
+ struct ieee_buflist *buflist;
+{
+ unsigned int type_indx;
+ unsigned int name_indx;
+
+ if (indx != (unsigned int) -1)
+ type_indx = indx;
+ else
+ {
+ type_indx = info->type_indx;
+ ++info->type_indx;
+ }
+
+ name_indx = info->name_indx;
+ ++info->name_indx;
+
+ if (name == NULL)
+ name = "";
+
+ /* If we were given a buffer, use it; otherwise, use either the
+ local or the global type information, and make sure that the type
+ block is started. */
+ if (buflist != NULL)
+ {
+ if (! ieee_change_buffer (info, buflist))
+ return false;
+ }
+ else if (localp)
+ {
+ if (! ieee_buffer_emptyp (&info->types))
+ {
+ if (! ieee_change_buffer (info, &info->types))
+ return false;
+ }
+ else
+ {
+ if (! ieee_change_buffer (info, &info->types)
+ || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 1)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, info->modname))
+ return false;
+ }
+ }
+ else
+ {
+ if (! ieee_buffer_emptyp (&info->global_types))
+ {
+ if (! ieee_change_buffer (info, &info->global_types))
+ return false;
+ }
+ else
+ {
+ if (! ieee_change_buffer (info, &info->global_types)
+ || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 2)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, ""))
+ return false;
+ }
+ }
+
+ /* Push the new type on the type stack, write out an NN record, and
+ write out the start of a TY record. The caller will then finish
+ the TY record. */
+ if (! ieee_push_type (info, type_indx, size, unsignedp, localp))
+ return false;
+
+ return (ieee_write_byte (info, (int) ieee_nn_record)
+ && ieee_write_number (info, name_indx)
+ && ieee_write_id (info, name)
+ && ieee_write_byte (info, (int) ieee_ty_record_enum)
+ && ieee_write_number (info, type_indx)
+ && ieee_write_byte (info, 0xce)
+ && ieee_write_number (info, name_indx));
+}
+
+/* Get an entry to the list of modified versions of a type. */
+
+static struct ieee_modified_type *
+ieee_get_modified_info (info, indx)
+ struct ieee_handle *info;
+ unsigned int indx;
+{
+ if (indx >= info->modified_alloc)
+ {
+ unsigned int nalloc;
+
+ nalloc = info->modified_alloc;
+ if (nalloc == 0)
+ nalloc = 16;
+ while (indx >= nalloc)
+ nalloc *= 2;
+ info->modified = ((struct ieee_modified_type *)
+ xrealloc (info->modified,
+ nalloc * sizeof *info->modified));
+ memset (info->modified + info->modified_alloc, 0,
+ (nalloc - info->modified_alloc) * sizeof *info->modified);
+ info->modified_alloc = nalloc;
+ }
+
+ return info->modified + indx;
+}
+
+/* Routines for the hash table mapping names to types. */
+
+/* Initialize an entry in the hash table. */
+
+static struct bfd_hash_entry *
+ieee_name_type_newfunc (entry, table, string)
+ struct bfd_hash_entry *entry;
+ struct bfd_hash_table *table;
+ const char *string;
+{
+ struct ieee_name_type_hash_entry *ret =
+ (struct ieee_name_type_hash_entry *) entry;
+
+ /* Allocate the structure if it has not already been allocated by a
+ subclass. */
+ if (ret == NULL)
+ ret = ((struct ieee_name_type_hash_entry *)
+ bfd_hash_allocate (table, sizeof *ret));
+ if (ret == NULL)
+ return NULL;
+
+ /* Call the allocation method of the superclass. */
+ ret = ((struct ieee_name_type_hash_entry *)
+ bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
+ if (ret)
+ {
+ /* Set local fields. */
+ ret->types = NULL;
+ }
+
+ return (struct bfd_hash_entry *) ret;
+}
+
+/* Look up an entry in the hash table. */
+
+#define ieee_name_type_hash_lookup(table, string, create, copy) \
+ ((struct ieee_name_type_hash_entry *) \
+ bfd_hash_lookup (&(table)->root, (string), (create), (copy)))
+
+/* Traverse the hash table. */
+
+#define ieee_name_type_hash_traverse(table, func, info) \
+ (bfd_hash_traverse \
+ (&(table)->root, \
+ (boolean (*) PARAMS ((struct bfd_hash_entry *, PTR))) (func), \
+ (info)))
+
+/* The general routine to write out IEEE debugging information. */
+
+boolean
+write_ieee_debugging_info (abfd, dhandle)
+ bfd *abfd;
+ PTR dhandle;
+{
+ struct ieee_handle info;
+ asection *s;
+ const char *err;
+ struct ieee_buf *b;
+
+ memset (&info, 0, sizeof info);
+ info.abfd = abfd;
+ info.type_indx = 256;
+ info.name_indx = 32;
+
+ if (! bfd_hash_table_init (&info.typedefs.root, ieee_name_type_newfunc)
+ || ! bfd_hash_table_init (&info.tags.root, ieee_name_type_newfunc))
+ return false;
+
+ if (! ieee_init_buffer (&info, &info.global_types)
+ || ! ieee_init_buffer (&info, &info.data)
+ || ! ieee_init_buffer (&info, &info.types)
+ || ! ieee_init_buffer (&info, &info.vars)
+ || ! ieee_init_buffer (&info, &info.cxx)
+ || ! ieee_init_buffer (&info, &info.linenos)
+ || ! ieee_init_buffer (&info, &info.fntype)
+ || ! ieee_init_buffer (&info, &info.fnargs))
+ return false;
+
+ if (! debug_write (dhandle, &ieee_fns, (PTR) &info))
+ return false;
+
+ if (info.filename != NULL)
+ {
+ if (! ieee_finish_compilation_unit (&info))
+ return false;
+ }
+
+ /* Put any undefined tags in the global typedef information. */
+ info.error = false;
+ ieee_name_type_hash_traverse (&info.tags,
+ ieee_write_undefined_tag,
+ (PTR) &info);
+ if (info.error)
+ return false;
+
+ /* Prepend the global typedef information to the other data. */
+ if (! ieee_buffer_emptyp (&info.global_types))
+ {
+ /* The HP debugger seems to have a bug in which it ignores the
+ last entry in the global types, so we add a dummy entry. */
+ if (! ieee_change_buffer (&info, &info.global_types)
+ || ! ieee_write_byte (&info, (int) ieee_nn_record)
+ || ! ieee_write_number (&info, info.name_indx)
+ || ! ieee_write_id (&info, "")
+ || ! ieee_write_byte (&info, (int) ieee_ty_record_enum)
+ || ! ieee_write_number (&info, info.type_indx)
+ || ! ieee_write_byte (&info, 0xce)
+ || ! ieee_write_number (&info, info.name_indx)
+ || ! ieee_write_number (&info, 'P')
+ || ! ieee_write_number (&info, (int) builtin_void + 32)
+ || ! ieee_write_byte (&info, (int) ieee_be_record_enum))
+ return false;
+
+ if (! ieee_append_buffer (&info, &info.global_types, &info.data))
+ return false;
+ info.data = info.global_types;
+ }
+
+ /* Make sure that we have declare BB11 blocks for each range in the
+ file. They are added to info->vars. */
+ info.error = false;
+ if (! ieee_init_buffer (&info, &info.vars))
+ return false;
+ bfd_map_over_sections (abfd, ieee_add_bb11_blocks, (PTR) &info);
+ if (info.error)
+ return false;
+ if (! ieee_buffer_emptyp (&info.vars))
+ {
+ if (! ieee_change_buffer (&info, &info.vars)
+ || ! ieee_write_byte (&info, (int) ieee_be_record_enum))
+ return false;
+
+ if (! ieee_append_buffer (&info, &info.data, &info.vars))
+ return false;
+ }
+
+ /* Now all the data is in info.data. Write it out to the BFD. We
+ normally would need to worry about whether all the other sections
+ are set up yet, but the IEEE backend will handle this particular
+ case correctly regardless. */
+ if (ieee_buffer_emptyp (&info.data))
+ {
+ /* There is no debugging information. */
+ return true;
+ }
+ err = NULL;
+ s = bfd_make_section (abfd, ".debug");
+ if (s == NULL)
+ err = "bfd_make_section";
+ if (err == NULL)
+ {
+ if (! bfd_set_section_flags (abfd, s, SEC_DEBUGGING | SEC_HAS_CONTENTS))
+ err = "bfd_set_section_flags";
+ }
+ if (err == NULL)
+ {
+ bfd_size_type size;
+
+ size = 0;
+ for (b = info.data.head; b != NULL; b = b->next)
+ size += b->c;
+ if (! bfd_set_section_size (abfd, s, size))
+ err = "bfd_set_section_size";
+ }
+ if (err == NULL)
+ {
+ file_ptr offset;
+
+ offset = 0;
+ for (b = info.data.head; b != NULL; b = b->next)
+ {
+ if (! bfd_set_section_contents (abfd, s, b->buf, offset, b->c))
+ {
+ err = "bfd_set_section_contents";
+ break;
+ }
+ offset += b->c;
+ }
+ }
+
+ if (err != NULL)
+ {
+ fprintf (stderr, "%s: %s: %s\n", bfd_get_filename (abfd), err,
+ bfd_errmsg (bfd_get_error ()));
+ return false;
+ }
+
+ bfd_hash_table_free (&info.typedefs.root);
+ bfd_hash_table_free (&info.tags.root);
+
+ return true;
+}
+
+/* Write out information for an undefined tag. This is called via
+ ieee_name_type_hash_traverse. */
+
+static boolean
+ieee_write_undefined_tag (h, p)
+ struct ieee_name_type_hash_entry *h;
+ PTR p;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ struct ieee_name_type *nt;
+
+ for (nt = h->types; nt != NULL; nt = nt->next)
+ {
+ unsigned int name_indx;
+ char code;
+
+ if (nt->kind == DEBUG_KIND_ILLEGAL)
+ continue;
+
+ if (ieee_buffer_emptyp (&info->global_types))
+ {
+ if (! ieee_change_buffer (info, &info->global_types)
+ || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 2)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, ""))
+ {
+ info->error = true;
+ return false;
+ }
+ }
+ else
+ {
+ if (! ieee_change_buffer (info, &info->global_types))
+ {
+ info->error = true;
+ return false;
+ }
+ }
+
+ name_indx = info->name_indx;
+ ++info->name_indx;
+ if (! ieee_write_byte (info, (int) ieee_nn_record)
+ || ! ieee_write_number (info, name_indx)
+ || ! ieee_write_id (info, nt->type.name)
+ || ! ieee_write_byte (info, (int) ieee_ty_record_enum)
+ || ! ieee_write_number (info, nt->type.indx)
+ || ! ieee_write_byte (info, 0xce)
+ || ! ieee_write_number (info, name_indx))
+ {
+ info->error = true;
+ return false;
+ }
+
+ switch (nt->kind)
+ {
+ default:
+ abort ();
+ info->error = true;
+ return false;
+ case DEBUG_KIND_STRUCT:
+ case DEBUG_KIND_CLASS:
+ code = 'S';
+ break;
+ case DEBUG_KIND_UNION:
+ case DEBUG_KIND_UNION_CLASS:
+ code = 'U';
+ break;
+ case DEBUG_KIND_ENUM:
+ code = 'E';
+ break;
+ }
+ if (! ieee_write_number (info, code)
+ || ! ieee_write_number (info, 0))
+ {
+ info->error = true;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* Start writing out information for a compilation unit. */
+
+static boolean
+ieee_start_compilation_unit (p, filename)
+ PTR p;
+ const char *filename;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ const char *modname;
+ char *c, *s;
+ unsigned int nindx;
+
+ if (info->filename != NULL)
+ {
+ if (! ieee_finish_compilation_unit (info))
+ return false;
+ }
+
+ info->filename = filename;
+ modname = strrchr (filename, '/');
+ if (modname != NULL)
+ ++modname;
+ else
+ {
+ modname = strrchr (filename, '\\');
+ if (modname != NULL)
+ ++modname;
+ else
+ modname = filename;
+ }
+ c = xstrdup (modname);
+ s = strrchr (c, '.');
+ if (s != NULL)
+ *s = '\0';
+ info->modname = c;
+
+ if (! ieee_init_buffer (info, &info->types)
+ || ! ieee_init_buffer (info, &info->vars)
+ || ! ieee_init_buffer (info, &info->cxx)
+ || ! ieee_init_buffer (info, &info->linenos))
+ return false;
+ info->ranges = NULL;
+
+ /* Always include a BB1 and a BB3 block. That is what the output of
+ the MRI linker seems to look like. */
+ if (! ieee_change_buffer (info, &info->types)
+ || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 1)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, info->modname))
+ return false;
+
+ nindx = info->name_indx;
+ ++info->name_indx;
+ if (! ieee_change_buffer (info, &info->vars)
+ || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 3)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, info->modname))
+ return false;
+
+ return true;
+}
+
+/* Finish up a compilation unit. */
+
+static boolean
+ieee_finish_compilation_unit (info)
+ struct ieee_handle *info;
+{
+ struct ieee_range *r;
+
+ if (! ieee_buffer_emptyp (&info->types))
+ {
+ if (! ieee_change_buffer (info, &info->types)
+ || ! ieee_write_byte (info, (int) ieee_be_record_enum))
+ return false;
+ }
+
+ if (! ieee_buffer_emptyp (&info->cxx))
+ {
+ /* Append any C++ information to the global function and
+ variable information. */
+ assert (! ieee_buffer_emptyp (&info->vars));
+ if (! ieee_change_buffer (info, &info->vars))
+ return false;
+
+ /* We put the pmisc records in a dummy procedure, just as the
+ MRI compiler does. */
+ if (! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 6)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, "__XRYCPP")
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, info->highaddr - 1)
+ || ! ieee_append_buffer (info, &info->vars, &info->cxx)
+ || ! ieee_change_buffer (info, &info->vars)
+ || ! ieee_write_byte (info, (int) ieee_be_record_enum)
+ || ! ieee_write_number (info, info->highaddr - 1))
+ return false;
+ }
+
+ if (! ieee_buffer_emptyp (&info->vars))
+ {
+ if (! ieee_change_buffer (info, &info->vars)
+ || ! ieee_write_byte (info, (int) ieee_be_record_enum))
+ return false;
+ }
+
+ if (info->pending_lineno_filename != NULL)
+ {
+ /* Force out the pending line number. */
+ if (! ieee_lineno ((PTR) info, (const char *) NULL, 0, (bfd_vma) -1))
+ return false;
+ }
+ if (! ieee_buffer_emptyp (&info->linenos))
+ {
+ if (! ieee_change_buffer (info, &info->linenos)
+ || ! ieee_write_byte (info, (int) ieee_be_record_enum))
+ return false;
+ if (strcmp (info->filename, info->lineno_filename) != 0)
+ {
+ /* We were not in the main file. We just closed the
+ included line number block, and now we must close the
+ main line number block. */
+ if (! ieee_write_byte (info, (int) ieee_be_record_enum))
+ return false;
+ }
+ }
+
+ if (! ieee_append_buffer (info, &info->data, &info->types)
+ || ! ieee_append_buffer (info, &info->data, &info->vars)
+ || ! ieee_append_buffer (info, &info->data, &info->linenos))
+ return false;
+
+ /* Build BB10/BB11 blocks based on the ranges we recorded. */
+ if (! ieee_change_buffer (info, &info->data))
+ return false;
+
+ if (! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 10)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, info->modname)
+ || ! ieee_write_id (info, "")
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, "GNU objcopy"))
+ return false;
+
+ for (r = info->ranges; r != NULL; r = r->next)
+ {
+ bfd_vma low, high;
+ asection *s;
+ int kind;
+
+ low = r->low;
+ high = r->high;
+
+ /* Find the section corresponding to this range. */
+ for (s = info->abfd->sections; s != NULL; s = s->next)
+ {
+ if (bfd_get_section_vma (info->abfd, s) <= low
+ && high <= (bfd_get_section_vma (info->abfd, s)
+ + bfd_section_size (info->abfd, s)))
+ break;
+ }
+
+ if (s == NULL)
+ {
+ /* Just ignore this range. */
+ continue;
+ }
+
+ /* Coalesce ranges if it seems reasonable. */
+ while (r->next != NULL
+ && high + 0x1000 >= r->next->low
+ && (r->next->high
+ <= (bfd_get_section_vma (info->abfd, s)
+ + bfd_section_size (info->abfd, s))))
+ {
+ r = r->next;
+ high = r->high;
+ }
+
+ if ((s->flags & SEC_CODE) != 0)
+ kind = 1;
+ else if ((s->flags & SEC_READONLY) != 0)
+ kind = 3;
+ else
+ kind = 2;
+
+ if (! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 11)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, "")
+ || ! ieee_write_number (info, kind)
+ || ! ieee_write_number (info, s->index + IEEE_SECTION_NUMBER_BASE)
+ || ! ieee_write_number (info, low)
+ || ! ieee_write_byte (info, (int) ieee_be_record_enum)
+ || ! ieee_write_number (info, high - low))
+ return false;
+
+ /* Add this range to the list of global ranges. */
+ if (! ieee_add_range (info, true, low, high))
+ return false;
+ }
+
+ if (! ieee_write_byte (info, (int) ieee_be_record_enum))
+ return false;
+
+ return true;
+}
+
+/* Add BB11 blocks describing each range that we have not already
+ described. */
+
+static void
+ieee_add_bb11_blocks (abfd, sec, data)
+ bfd *abfd;
+ asection *sec;
+ PTR data;
+{
+ struct ieee_handle *info = (struct ieee_handle *) data;
+ bfd_vma low, high;
+ struct ieee_range *r;
+
+ low = bfd_get_section_vma (abfd, sec);
+ high = low + bfd_section_size (abfd, sec);
+
+ /* Find the first range at or after this section. The ranges are
+ sorted by address. */
+ for (r = info->global_ranges; r != NULL; r = r->next)
+ if (r->high > low)
+ break;
+
+ while (low < high)
+ {
+ if (r == NULL || r->low >= high)
+ {
+ if (! ieee_add_bb11 (info, sec, low, high))
+ info->error = true;
+ return;
+ }
+
+ if (low < r->low
+ && r->low - low > 0x100)
+ {
+ if (! ieee_add_bb11 (info, sec, low, r->low))
+ {
+ info->error = true;
+ return;
+ }
+ }
+ low = r->high;
+
+ r = r->next;
+ }
+}
+
+/* Add a single BB11 block for a range. We add it to info->vars. */
+
+static boolean
+ieee_add_bb11 (info, sec, low, high)
+ struct ieee_handle *info;
+ asection *sec;
+ bfd_vma low;
+ bfd_vma high;
+{
+ int kind;
+
+ if (! ieee_buffer_emptyp (&info->vars))
+ {
+ if (! ieee_change_buffer (info, &info->vars))
+ return false;
+ }
+ else
+ {
+ const char *filename, *modname;
+ char *c, *s;
+
+ /* Start the enclosing BB10 block. */
+ filename = bfd_get_filename (info->abfd);
+ modname = strrchr (filename, '/');
+ if (modname != NULL)
+ ++modname;
+ else
+ {
+ modname = strrchr (filename, '\\');
+ if (modname != NULL)
+ ++modname;
+ else
+ modname = filename;
+ }
+ c = xstrdup (modname);
+ s = strrchr (c, '.');
+ if (s != NULL)
+ *s = '\0';
+
+ if (! ieee_change_buffer (info, &info->vars)
+ || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 10)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, c)
+ || ! ieee_write_id (info, "")
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, "GNU objcopy"))
+ return false;
+
+ free (c);
+ }
+
+ if ((sec->flags & SEC_CODE) != 0)
+ kind = 1;
+ else if ((sec->flags & SEC_READONLY) != 0)
+ kind = 3;
+ else
+ kind = 2;
+
+ if (! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 11)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, "")
+ || ! ieee_write_number (info, kind)
+ || ! ieee_write_number (info, sec->index + IEEE_SECTION_NUMBER_BASE)
+ || ! ieee_write_number (info, low)
+ || ! ieee_write_byte (info, (int) ieee_be_record_enum)
+ || ! ieee_write_number (info, high - low))
+ return false;
+
+ return true;
+}
+
+/* Start recording information from a particular source file. This is
+ used to record which file defined which types, variables, etc. It
+ is not used for line numbers, since the lineno entry point passes
+ down the file name anyhow. IEEE debugging information doesn't seem
+ to store this information anywhere. */
+
+/*ARGSUSED*/
+static boolean
+ieee_start_source (p, filename)
+ PTR p;
+ const char *filename;
+{
+ return true;
+}
+
+/* Make an empty type. */
+
+static boolean
+ieee_empty_type (p)
+ PTR p;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ return ieee_push_type (info, (int) builtin_unknown, 0, false, false);
+}
+
+/* Make a void type. */
+
+static boolean
+ieee_void_type (p)
+ PTR p;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ return ieee_push_type (info, (int) builtin_void, 0, false, false);
+}
+
+/* Make an integer type. */
+
+static boolean
+ieee_int_type (p, size, unsignedp)
+ PTR p;
+ unsigned int size;
+ boolean unsignedp;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ unsigned int indx;
+
+ switch (size)
+ {
+ case 1:
+ indx = (int) builtin_signed_char;
+ break;
+ case 2:
+ indx = (int) builtin_signed_short_int;
+ break;
+ case 4:
+ indx = (int) builtin_signed_long;
+ break;
+ case 8:
+ indx = (int) builtin_signed_long_long;
+ break;
+ default:
+ fprintf (stderr, "IEEE unsupported integer type size %u\n", size);
+ return false;
+ }
+
+ if (unsignedp)
+ ++indx;
+
+ return ieee_push_type (info, indx, size, unsignedp, false);
+}
+
+/* Make a floating point type. */
+
+static boolean
+ieee_float_type (p, size)
+ PTR p;
+ unsigned int size;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ unsigned int indx;
+
+ switch (size)
+ {
+ case 4:
+ indx = (int) builtin_float;
+ break;
+ case 8:
+ indx = (int) builtin_double;
+ break;
+ case 12:
+ /* FIXME: This size really depends upon the processor. */
+ indx = (int) builtin_long_double;
+ break;
+ case 16:
+ indx = (int) builtin_long_long_double;
+ break;
+ default:
+ fprintf (stderr, "IEEE unsupported float type size %u\n", size);
+ return false;
+ }
+
+ return ieee_push_type (info, indx, size, false, false);
+}
+
+/* Make a complex type. */
+
+static boolean
+ieee_complex_type (p, size)
+ PTR p;
+ unsigned int size;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ char code;
+
+ switch (size)
+ {
+ case 4:
+ if (info->complex_float_index != 0)
+ return ieee_push_type (info, info->complex_float_index, size * 2,
+ false, false);
+ code = 'c';
+ break;
+ case 12:
+ case 16:
+ /* These cases can be output by gcc -gstabs. Outputting the
+ wrong type is better than crashing. */
+ case 8:
+ if (info->complex_double_index != 0)
+ return ieee_push_type (info, info->complex_double_index, size * 2,
+ false, false);
+ code = 'd';
+ break;
+ default:
+ fprintf (stderr, "IEEE unsupported complex type size %u\n", size);
+ return false;
+ }
+
+ /* FIXME: I don't know what the string is for. */
+ if (! ieee_define_type (info, size * 2, false, false)
+ || ! ieee_write_number (info, code)
+ || ! ieee_write_id (info, ""))
+ return false;
+
+ if (size == 4)
+ info->complex_float_index = info->type_stack->type.indx;
+ else
+ info->complex_double_index = info->type_stack->type.indx;
+
+ return true;
+}
+
+/* Make a boolean type. IEEE doesn't support these, so we just make
+ an integer type instead. */
+
+static boolean
+ieee_bool_type (p, size)
+ PTR p;
+ unsigned int size;
+{
+ return ieee_int_type (p, size, true);
+}
+
+/* Make an enumeration. */
+
+static boolean
+ieee_enum_type (p, tag, names, vals)
+ PTR p;
+ const char *tag;
+ const char **names;
+ bfd_signed_vma *vals;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ struct ieee_defined_enum *e;
+ boolean localp, simple;
+ unsigned int indx;
+ int i = 0;
+
+ localp = false;
+ indx = (unsigned int) -1;
+ for (e = info->enums; e != NULL; e = e->next)
+ {
+ if (tag == NULL)
+ {
+ if (e->tag != NULL)
+ continue;
+ }
+ else
+ {
+ if (e->tag == NULL
+ || tag[0] != e->tag[0]
+ || strcmp (tag, e->tag) != 0)
+ continue;
+ }
+
+ if (! e->defined)
+ {
+ /* This enum tag has been seen but not defined. */
+ indx = e->indx;
+ break;
+ }
+
+ if (names != NULL && e->names != NULL)
+ {
+ for (i = 0; names[i] != NULL && e->names[i] != NULL; i++)
+ {
+ if (names[i][0] != e->names[i][0]
+ || vals[i] != e->vals[i]
+ || strcmp (names[i], e->names[i]) != 0)
+ break;
+ }
+ }
+
+ if ((names == NULL && e->names == NULL)
+ || (names != NULL
+ && e->names != NULL
+ && names[i] == NULL
+ && e->names[i] == NULL))
+ {
+ /* We've seen this enum before. */
+ return ieee_push_type (info, e->indx, 0, true, false);
+ }
+
+ if (tag != NULL)
+ {
+ /* We've already seen an enum of the same name, so we must make
+ sure to output this one locally. */
+ localp = true;
+ break;
+ }
+ }
+
+ /* If this is a simple enumeration, in which the values start at 0
+ and always increment by 1, we can use type E. Otherwise we must
+ use type N. */
+
+ simple = true;
+ if (names != NULL)
+ {
+ for (i = 0; names[i] != NULL; i++)
+ {
+ if (vals[i] != i)
+ {
+ simple = false;
+ break;
+ }
+ }
+ }
+
+ if (! ieee_define_named_type (info, tag, indx, 0, true, localp,
+ (struct ieee_buflist *) NULL)
+ || ! ieee_write_number (info, simple ? 'E' : 'N'))
+ return false;
+ if (simple)
+ {
+ /* FIXME: This is supposed to be the enumeration size, but we
+ don't store that. */
+ if (! ieee_write_number (info, 4))
+ return false;
+ }
+ if (names != NULL)
+ {
+ for (i = 0; names[i] != NULL; i++)
+ {
+ if (! ieee_write_id (info, names[i]))
+ return false;
+ if (! simple)
+ {
+ if (! ieee_write_number (info, vals[i]))
+ return false;
+ }
+ }
+ }
+
+ if (! localp)
+ {
+ if (indx == (unsigned int) -1)
+ {
+ e = (struct ieee_defined_enum *) xmalloc (sizeof *e);
+ memset (e, 0, sizeof *e);
+ e->indx = info->type_stack->type.indx;
+ e->tag = tag;
+
+ e->next = info->enums;
+ info->enums = e;
+ }
+
+ e->names = names;
+ e->vals = vals;
+ e->defined = true;
+ }
+
+ return true;
+}
+
+/* Make a pointer type. */
+
+static boolean
+ieee_pointer_type (p)
+ PTR p;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ boolean localp;
+ unsigned int indx;
+ struct ieee_modified_type *m = NULL;
+
+ localp = info->type_stack->type.localp;
+ indx = ieee_pop_type (info);
+
+ /* A pointer to a simple builtin type can be obtained by adding 32.
+ FIXME: Will this be a short pointer, and will that matter? */
+ if (indx < 32)
+ return ieee_push_type (info, indx + 32, 0, true, false);
+
+ if (! localp)
+ {
+ m = ieee_get_modified_info (p, indx);
+ if (m == NULL)
+ return false;
+
+ /* FIXME: The size should depend upon the architecture. */
+ if (m->pointer > 0)
+ return ieee_push_type (info, m->pointer, 4, true, false);
+ }
+
+ if (! ieee_define_type (info, 4, true, localp)
+ || ! ieee_write_number (info, 'P')
+ || ! ieee_write_number (info, indx))
+ return false;
+
+ if (! localp)
+ m->pointer = info->type_stack->type.indx;
+
+ return true;
+}
+
+/* Make a function type. This will be called for a method, but we
+ don't want to actually add it to the type table in that case. We
+ handle this by defining the type in a private buffer, and only
+ adding that buffer to the typedef block if we are going to use it. */
+
+static boolean
+ieee_function_type (p, argcount, varargs)
+ PTR p;
+ int argcount;
+ boolean varargs;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ boolean localp;
+ unsigned int *args = NULL;
+ int i;
+ unsigned int retindx;
+ struct ieee_buflist fndef;
+ struct ieee_modified_type *m;
+
+ localp = false;
+
+ if (argcount > 0)
+ {
+ args = (unsigned int *) xmalloc (argcount * sizeof *args);
+ for (i = argcount - 1; i >= 0; i--)
+ {
+ if (info->type_stack->type.localp)
+ localp = true;
+ args[i] = ieee_pop_type (info);
+ }
+ }
+ else if (argcount < 0)
+ varargs = false;
+
+ if (info->type_stack->type.localp)
+ localp = true;
+ retindx = ieee_pop_type (info);
+
+ m = NULL;
+ if (argcount < 0 && ! localp)
+ {
+ m = ieee_get_modified_info (p, retindx);
+ if (m == NULL)
+ return false;
+
+ if (m->function > 0)
+ return ieee_push_type (info, m->function, 0, true, false);
+ }
+
+ /* An attribute of 0x41 means that the frame and push mask are
+ unknown. */
+ if (! ieee_init_buffer (info, &fndef)
+ || ! ieee_define_named_type (info, (const char *) NULL,
+ (unsigned int) -1, 0, true, localp,
+ &fndef)
+ || ! ieee_write_number (info, 'x')
+ || ! ieee_write_number (info, 0x41)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, retindx)
+ || ! ieee_write_number (info, (bfd_vma) argcount + (varargs ? 1 : 0)))
+ return false;
+ if (argcount > 0)
+ {
+ for (i = 0; i < argcount; i++)
+ if (! ieee_write_number (info, args[i]))
+ return false;
+ free (args);
+ }
+ if (varargs)
+ {
+ /* A varargs function is represented by writing out the last
+ argument as type void *, although this makes little sense. */
+ if (! ieee_write_number (info, (bfd_vma) builtin_void + 32))
+ return false;
+ }
+
+ if (! ieee_write_number (info, 0))
+ return false;
+
+ /* We wrote the information into fndef, in case we don't need it.
+ It will be appended to info->types by ieee_pop_type. */
+ info->type_stack->type.fndef = fndef;
+
+ if (m != NULL)
+ m->function = info->type_stack->type.indx;
+
+ return true;
+}
+
+/* Make a reference type. */
+
+static boolean
+ieee_reference_type (p)
+ PTR p;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ /* IEEE appears to record a normal pointer type, and then use a
+ pmisc record to indicate that it is really a reference. */
+
+ if (! ieee_pointer_type (p))
+ return false;
+ info->type_stack->type.referencep = true;
+ return true;
+}
+
+/* Make a range type. */
+
+static boolean
+ieee_range_type (p, low, high)
+ PTR p;
+ bfd_signed_vma low;
+ bfd_signed_vma high;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ unsigned int size;
+ boolean unsignedp, localp;
+
+ size = info->type_stack->type.size;
+ unsignedp = info->type_stack->type.unsignedp;
+ localp = info->type_stack->type.localp;
+ ieee_pop_unused_type (info);
+ return (ieee_define_type (info, size, unsignedp, localp)
+ && ieee_write_number (info, 'R')
+ && ieee_write_number (info, (bfd_vma) low)
+ && ieee_write_number (info, (bfd_vma) high)
+ && ieee_write_number (info, unsignedp ? 0 : 1)
+ && ieee_write_number (info, size));
+}
+
+/* Make an array type. */
+
+/*ARGSUSED*/
+static boolean
+ieee_array_type (p, low, high, stringp)
+ PTR p;
+ bfd_signed_vma low;
+ bfd_signed_vma high;
+ boolean stringp;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ unsigned int eleindx;
+ boolean localp;
+ unsigned int size;
+ struct ieee_modified_type *m = NULL;
+ struct ieee_modified_array_type *a;
+
+ /* IEEE does not store the range, so we just ignore it. */
+ ieee_pop_unused_type (info);
+ localp = info->type_stack->type.localp;
+ size = info->type_stack->type.size;
+ eleindx = ieee_pop_type (info);
+
+ /* If we don't know the range, treat the size as exactly one
+ element. */
+ if (low < high)
+ size *= (high - low) + 1;
+
+ if (! localp)
+ {
+ m = ieee_get_modified_info (info, eleindx);
+ if (m == NULL)
+ return false;
+
+ for (a = m->arrays; a != NULL; a = a->next)
+ {
+ if (a->low == low && a->high == high)
+ return ieee_push_type (info, a->indx, size, false, false);
+ }
+ }
+
+ if (! ieee_define_type (info, size, false, localp)
+ || ! ieee_write_number (info, low == 0 ? 'Z' : 'C')
+ || ! ieee_write_number (info, eleindx))
+ return false;
+ if (low != 0)
+ {
+ if (! ieee_write_number (info, low))
+ return false;
+ }
+
+ if (! ieee_write_number (info, high + 1))
+ return false;
+
+ if (! localp)
+ {
+ a = (struct ieee_modified_array_type *) xmalloc (sizeof *a);
+ memset (a, 0, sizeof *a);
+
+ a->indx = info->type_stack->type.indx;
+ a->low = low;
+ a->high = high;
+
+ a->next = m->arrays;
+ m->arrays = a;
+ }
+
+ return true;
+}
+
+/* Make a set type. */
+
+static boolean
+ieee_set_type (p, bitstringp)
+ PTR p;
+ boolean bitstringp;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ boolean localp;
+ unsigned int eleindx;
+
+ localp = info->type_stack->type.localp;
+ eleindx = ieee_pop_type (info);
+
+ /* FIXME: We don't know the size, so we just use 4. */
+
+ return (ieee_define_type (info, 0, true, localp)
+ && ieee_write_number (info, 's')
+ && ieee_write_number (info, 4)
+ && ieee_write_number (info, eleindx));
+}
+
+/* Make an offset type. */
+
+static boolean
+ieee_offset_type (p)
+ PTR p;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ unsigned int targetindx, baseindx;
+
+ targetindx = ieee_pop_type (info);
+ baseindx = ieee_pop_type (info);
+
+ /* FIXME: The MRI C++ compiler does not appear to generate any
+ useful type information about an offset type. It just records a
+ pointer to member as an integer. The MRI/HP IEEE spec does
+ describe a pmisc record which can be used for a pointer to
+ member. Unfortunately, it does not describe the target type,
+ which seems pretty important. I'm going to punt this for now. */
+
+ return ieee_int_type (p, 4, true);
+}
+
+/* Make a method type. */
+
+static boolean
+ieee_method_type (p, domain, argcount, varargs)
+ PTR p;
+ boolean domain;
+ int argcount;
+ boolean varargs;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ /* FIXME: The MRI/HP IEEE spec defines a pmisc record to use for a
+ method, but the definition is incomplete. We just output an 'x'
+ type. */
+
+ if (domain)
+ ieee_pop_unused_type (info);
+
+ return ieee_function_type (p, argcount, varargs);
+}
+
+/* Make a const qualified type. */
+
+static boolean
+ieee_const_type (p)
+ PTR p;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ unsigned int size;
+ boolean unsignedp, localp;
+ unsigned int indx;
+ struct ieee_modified_type *m = NULL;
+
+ size = info->type_stack->type.size;
+ unsignedp = info->type_stack->type.unsignedp;
+ localp = info->type_stack->type.localp;
+ indx = ieee_pop_type (info);
+
+ if (! localp)
+ {
+ m = ieee_get_modified_info (info, indx);
+ if (m == NULL)
+ return false;
+
+ if (m->const_qualified > 0)
+ return ieee_push_type (info, m->const_qualified, size, unsignedp,
+ false);
+ }
+
+ if (! ieee_define_type (info, size, unsignedp, localp)
+ || ! ieee_write_number (info, 'n')
+ || ! ieee_write_number (info, 1)
+ || ! ieee_write_number (info, indx))
+ return false;
+
+ if (! localp)
+ m->const_qualified = info->type_stack->type.indx;
+
+ return true;
+}
+
+/* Make a volatile qualified type. */
+
+static boolean
+ieee_volatile_type (p)
+ PTR p;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ unsigned int size;
+ boolean unsignedp, localp;
+ unsigned int indx;
+ struct ieee_modified_type *m = NULL;
+
+ size = info->type_stack->type.size;
+ unsignedp = info->type_stack->type.unsignedp;
+ localp = info->type_stack->type.localp;
+ indx = ieee_pop_type (info);
+
+ if (! localp)
+ {
+ m = ieee_get_modified_info (info, indx);
+ if (m == NULL)
+ return false;
+
+ if (m->volatile_qualified > 0)
+ return ieee_push_type (info, m->volatile_qualified, size, unsignedp,
+ false);
+ }
+
+ if (! ieee_define_type (info, size, unsignedp, localp)
+ || ! ieee_write_number (info, 'n')
+ || ! ieee_write_number (info, 2)
+ || ! ieee_write_number (info, indx))
+ return false;
+
+ if (! localp)
+ m->volatile_qualified = info->type_stack->type.indx;
+
+ return true;
+}
+
+/* Convert an enum debug_visibility into a CXXFLAGS value. */
+
+static unsigned int
+ieee_vis_to_flags (visibility)
+ enum debug_visibility visibility;
+{
+ switch (visibility)
+ {
+ default:
+ abort ();
+ case DEBUG_VISIBILITY_PUBLIC:
+ return CXXFLAGS_VISIBILITY_PUBLIC;
+ case DEBUG_VISIBILITY_PRIVATE:
+ return CXXFLAGS_VISIBILITY_PRIVATE;
+ case DEBUG_VISIBILITY_PROTECTED:
+ return CXXFLAGS_VISIBILITY_PROTECTED;
+ }
+ /*NOTREACHED*/
+}
+
+/* Start defining a struct type. We build it in the strdef field on
+ the stack, to avoid confusing type definitions required by the
+ fields with the struct type itself. */
+
+static boolean
+ieee_start_struct_type (p, tag, id, structp, size)
+ PTR p;
+ const char *tag;
+ unsigned int id;
+ boolean structp;
+ unsigned int size;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ boolean localp, ignorep;
+ boolean copy;
+ char ab[20];
+ const char *look;
+ struct ieee_name_type_hash_entry *h;
+ struct ieee_name_type *nt, *ntlook;
+ struct ieee_buflist strdef;
+
+ localp = false;
+ ignorep = false;
+
+ /* We need to create a tag for internal use even if we don't want
+ one for external use. This will let us refer to an anonymous
+ struct. */
+ if (tag != NULL)
+ {
+ look = tag;
+ copy = false;
+ }
+ else
+ {
+ sprintf (ab, "__anon%u", id);
+ look = ab;
+ copy = true;
+ }
+
+ /* If we already have references to the tag, we must use the
+ existing type index. */
+ h = ieee_name_type_hash_lookup (&info->tags, look, true, copy);
+ if (h == NULL)
+ return false;
+
+ nt = NULL;
+ for (ntlook = h->types; ntlook != NULL; ntlook = ntlook->next)
+ {
+ if (ntlook->id == id)
+ nt = ntlook;
+ else if (! ntlook->type.localp)
+ {
+ /* We are creating a duplicate definition of a globally
+ defined tag. Force it to be local to avoid
+ confusion. */
+ localp = true;
+ }
+ }
+
+ if (nt != NULL)
+ {
+ assert (localp == nt->type.localp);
+ if (nt->kind == DEBUG_KIND_ILLEGAL && ! localp)
+ {
+ /* We've already seen a global definition of the type.
+ Ignore this new definition. */
+ ignorep = true;
+ }
+ }
+ else
+ {
+ nt = (struct ieee_name_type *) xmalloc (sizeof *nt);
+ memset (nt, 0, sizeof *nt);
+ nt->id = id;
+ nt->type.name = h->root.string;
+ nt->next = h->types;
+ h->types = nt;
+ nt->type.indx = info->type_indx;
+ ++info->type_indx;
+ }
+
+ nt->kind = DEBUG_KIND_ILLEGAL;
+
+ if (! ieee_init_buffer (info, &strdef)
+ || ! ieee_define_named_type (info, tag, nt->type.indx, size, true,
+ localp, &strdef)
+ || ! ieee_write_number (info, structp ? 'S' : 'U')
+ || ! ieee_write_number (info, size))
+ return false;
+
+ if (! ignorep)
+ {
+ const char *hold;
+
+ /* We never want nt->type.name to be NULL. We want the rest of
+ the type to be the object set up on the type stack; it will
+ have a NULL name if tag is NULL. */
+ hold = nt->type.name;
+ nt->type = info->type_stack->type;
+ nt->type.name = hold;
+ }
+
+ info->type_stack->type.name = tag;
+ info->type_stack->type.strdef = strdef;
+ info->type_stack->type.ignorep = ignorep;
+
+ return true;
+}
+
+/* Add a field to a struct. */
+
+static boolean
+ieee_struct_field (p, name, bitpos, bitsize, visibility)
+ PTR p;
+ const char *name;
+ bfd_vma bitpos;
+ bfd_vma bitsize;
+ enum debug_visibility visibility;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ unsigned int size;
+ boolean unsignedp;
+ boolean referencep;
+ boolean localp;
+ unsigned int indx;
+ bfd_vma offset;
+
+ assert (info->type_stack != NULL
+ && info->type_stack->next != NULL
+ && ! ieee_buffer_emptyp (&info->type_stack->next->type.strdef));
+
+ /* If we are ignoring this struct definition, just pop and ignore
+ the type. */
+ if (info->type_stack->next->type.ignorep)
+ {
+ ieee_pop_unused_type (info);
+ return true;
+ }
+
+ size = info->type_stack->type.size;
+ unsignedp = info->type_stack->type.unsignedp;
+ referencep = info->type_stack->type.referencep;
+ localp = info->type_stack->type.localp;
+ indx = ieee_pop_type (info);
+
+ if (localp)
+ info->type_stack->type.localp = true;
+
+ if (info->type_stack->type.classdef != NULL)
+ {
+ unsigned int flags;
+ unsigned int nindx;
+
+ /* This is a class. We must add a description of this field to
+ the class records we are building. */
+
+ flags = ieee_vis_to_flags (visibility);
+ nindx = info->type_stack->type.classdef->indx;
+ if (! ieee_change_buffer (info,
+ &info->type_stack->type.classdef->pmiscbuf)
+ || ! ieee_write_asn (info, nindx, 'd')
+ || ! ieee_write_asn (info, nindx, flags)
+ || ! ieee_write_atn65 (info, nindx, name)
+ || ! ieee_write_atn65 (info, nindx, name))
+ return false;
+ info->type_stack->type.classdef->pmisccount += 4;
+
+ if (referencep)
+ {
+ unsigned int nindx;
+
+ /* We need to output a record recording that this field is
+ really of reference type. We put this on the refs field
+ of classdef, so that it can be appended to the C++
+ records after the class is defined. */
+
+ nindx = info->name_indx;
+ ++info->name_indx;
+
+ if (! ieee_change_buffer (info,
+ &info->type_stack->type.classdef->refs)
+ || ! ieee_write_byte (info, (int) ieee_nn_record)
+ || ! ieee_write_number (info, nindx)
+ || ! ieee_write_id (info, "")
+ || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum)
+ || ! ieee_write_number (info, nindx)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, 62)
+ || ! ieee_write_number (info, 80)
+ || ! ieee_write_number (info, 4)
+ || ! ieee_write_asn (info, nindx, 'R')
+ || ! ieee_write_asn (info, nindx, 3)
+ || ! ieee_write_atn65 (info, nindx, info->type_stack->type.name)
+ || ! ieee_write_atn65 (info, nindx, name))
+ return false;
+ }
+ }
+
+ /* If the bitsize doesn't match the expected size, we need to output
+ a bitfield type. */
+ if (size == 0 || bitsize == 0 || bitsize == size * 8)
+ offset = bitpos / 8;
+ else
+ {
+ if (! ieee_define_type (info, 0, unsignedp,
+ info->type_stack->type.localp)
+ || ! ieee_write_number (info, 'g')
+ || ! ieee_write_number (info, unsignedp ? 0 : 1)
+ || ! ieee_write_number (info, bitsize)
+ || ! ieee_write_number (info, indx))
+ return false;
+ indx = ieee_pop_type (info);
+ offset = bitpos;
+ }
+
+ /* Switch to the struct we are building in order to output this
+ field definition. */
+ return (ieee_change_buffer (info, &info->type_stack->type.strdef)
+ && ieee_write_id (info, name)
+ && ieee_write_number (info, indx)
+ && ieee_write_number (info, offset));
+}
+
+/* Finish up a struct type. */
+
+static boolean
+ieee_end_struct_type (p)
+ PTR p;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ struct ieee_buflist *pb;
+
+ assert (info->type_stack != NULL
+ && ! ieee_buffer_emptyp (&info->type_stack->type.strdef));
+
+ /* If we were ignoring this struct definition because it was a
+ duplicate defintion, just through away whatever bytes we have
+ accumulated. Leave the type on the stack. */
+ if (info->type_stack->type.ignorep)
+ return true;
+
+ /* If this is not a duplicate definition of this tag, then localp
+ will be false, and we can put it in the global type block.
+ FIXME: We should avoid outputting duplicate definitions which are
+ the same. */
+ if (! info->type_stack->type.localp)
+ {
+ /* Make sure we have started the global type block. */
+ if (ieee_buffer_emptyp (&info->global_types))
+ {
+ if (! ieee_change_buffer (info, &info->global_types)
+ || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 2)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, ""))
+ return false;
+ }
+ pb = &info->global_types;
+ }
+ else
+ {
+ /* Make sure we have started the types block. */
+ if (ieee_buffer_emptyp (&info->types))
+ {
+ if (! ieee_change_buffer (info, &info->types)
+ || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 1)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, info->modname))
+ return false;
+ }
+ pb = &info->types;
+ }
+
+ /* Append the struct definition to the types. */
+ if (! ieee_append_buffer (info, pb, &info->type_stack->type.strdef)
+ || ! ieee_init_buffer (info, &info->type_stack->type.strdef))
+ return false;
+
+ /* Leave the struct on the type stack. */
+
+ return true;
+}
+
+/* Start a class type. */
+
+static boolean
+ieee_start_class_type (p, tag, id, structp, size, vptr, ownvptr)
+ PTR p;
+ const char *tag;
+ unsigned int id;
+ boolean structp;
+ unsigned int size;
+ boolean vptr;
+ boolean ownvptr;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ const char *vclass;
+ struct ieee_buflist pmiscbuf;
+ unsigned int indx;
+ struct ieee_type_class *classdef;
+
+ /* A C++ class is output as a C++ struct along with a set of pmisc
+ records describing the class. */
+
+ /* We need to have a name so that we can associate the struct and
+ the class. */
+ if (tag == NULL)
+ {
+ char *t;
+
+ t = (char *) xmalloc (20);
+ sprintf (t, "__anon%u", id);
+ tag = t;
+ }
+
+ /* We can't write out the virtual table information until we have
+ finished the class, because we don't know the virtual table size.
+ We get the size from the largest voffset we see. */
+ vclass = NULL;
+ if (vptr && ! ownvptr)
+ {
+ vclass = info->type_stack->type.name;
+ assert (vclass != NULL);
+ /* We don't call ieee_pop_unused_type, since the class should
+ get defined. */
+ (void) ieee_pop_type (info);
+ }
+
+ if (! ieee_start_struct_type (p, tag, id, structp, size))
+ return false;
+
+ indx = info->name_indx;
+ ++info->name_indx;
+
+ /* We write out pmisc records into the classdef field. We will
+ write out the pmisc start after we know the number of records we
+ need. */
+ if (! ieee_init_buffer (info, &pmiscbuf)
+ || ! ieee_change_buffer (info, &pmiscbuf)
+ || ! ieee_write_asn (info, indx, 'T')
+ || ! ieee_write_asn (info, indx, structp ? 'o' : 'u')
+ || ! ieee_write_atn65 (info, indx, tag))
+ return false;
+
+ classdef = (struct ieee_type_class *) xmalloc (sizeof *classdef);
+ memset (classdef, 0, sizeof *classdef);
+
+ classdef->indx = indx;
+ classdef->pmiscbuf = pmiscbuf;
+ classdef->pmisccount = 3;
+ classdef->vclass = vclass;
+ classdef->ownvptr = ownvptr;
+
+ info->type_stack->type.classdef = classdef;
+
+ return true;
+}
+
+/* Add a static member to a class. */
+
+static boolean
+ieee_class_static_member (p, name, physname, visibility)
+ PTR p;
+ const char *name;
+ const char *physname;
+ enum debug_visibility visibility;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ unsigned int flags;
+ unsigned int nindx;
+
+ /* We don't care about the type. Hopefully there will be a call to
+ ieee_variable declaring the physical name and the type, since
+ that is where an IEEE consumer must get the type. */
+ ieee_pop_unused_type (info);
+
+ assert (info->type_stack != NULL
+ && info->type_stack->type.classdef != NULL);
+
+ flags = ieee_vis_to_flags (visibility);
+ flags |= CXXFLAGS_STATIC;
+
+ nindx = info->type_stack->type.classdef->indx;
+
+ if (! ieee_change_buffer (info, &info->type_stack->type.classdef->pmiscbuf)
+ || ! ieee_write_asn (info, nindx, 'd')
+ || ! ieee_write_asn (info, nindx, flags)
+ || ! ieee_write_atn65 (info, nindx, name)
+ || ! ieee_write_atn65 (info, nindx, physname))
+ return false;
+ info->type_stack->type.classdef->pmisccount += 4;
+
+ return true;
+}
+
+/* Add a base class to a class. */
+
+static boolean
+ieee_class_baseclass (p, bitpos, virtual, visibility)
+ PTR p;
+ bfd_vma bitpos;
+ boolean virtual;
+ enum debug_visibility visibility;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ const char *bname;
+ boolean localp;
+ unsigned int bindx;
+ char *fname;
+ unsigned int flags;
+ unsigned int nindx;
+
+ assert (info->type_stack != NULL
+ && info->type_stack->type.name != NULL
+ && info->type_stack->next != NULL
+ && info->type_stack->next->type.classdef != NULL
+ && ! ieee_buffer_emptyp (&info->type_stack->next->type.strdef));
+
+ bname = info->type_stack->type.name;
+ localp = info->type_stack->type.localp;
+ bindx = ieee_pop_type (info);
+
+ /* We are currently defining both a struct and a class. We must
+ write out a field definition in the struct which holds the base
+ class. The stabs debugging reader will create a field named
+ _vb$CLASS for a virtual base class, so we just use that. FIXME:
+ we should not depend upon a detail of stabs debugging. */
+ if (virtual)
+ {
+ fname = (char *) xmalloc (strlen (bname) + sizeof "_vb$");
+ sprintf (fname, "_vb$%s", bname);
+ flags = BASEFLAGS_VIRTUAL;
+ }
+ else
+ {
+ if (localp)
+ info->type_stack->type.localp = true;
+
+ fname = (char *) xmalloc (strlen (bname) + sizeof "_b$");
+ sprintf (fname, "_b$%s", bname);
+
+ if (! ieee_change_buffer (info, &info->type_stack->type.strdef)
+ || ! ieee_write_id (info, fname)
+ || ! ieee_write_number (info, bindx)
+ || ! ieee_write_number (info, bitpos / 8))
+ return false;
+ flags = 0;
+ }
+
+ if (visibility == DEBUG_VISIBILITY_PRIVATE)
+ flags |= BASEFLAGS_PRIVATE;
+
+ nindx = info->type_stack->type.classdef->indx;
+
+ if (! ieee_change_buffer (info, &info->type_stack->type.classdef->pmiscbuf)
+ || ! ieee_write_asn (info, nindx, 'b')
+ || ! ieee_write_asn (info, nindx, flags)
+ || ! ieee_write_atn65 (info, nindx, bname)
+ || ! ieee_write_asn (info, nindx, 0)
+ || ! ieee_write_atn65 (info, nindx, fname))
+ return false;
+ info->type_stack->type.classdef->pmisccount += 5;
+
+ free (fname);
+
+ return true;
+}
+
+/* Start building a method for a class. */
+
+static boolean
+ieee_class_start_method (p, name)
+ PTR p;
+ const char *name;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ assert (info->type_stack != NULL
+ && info->type_stack->type.classdef != NULL
+ && info->type_stack->type.classdef->method == NULL);
+
+ info->type_stack->type.classdef->method = name;
+
+ return true;
+}
+
+/* Define a new method variant, either static or not. */
+
+static boolean
+ieee_class_method_var (info, physname, visibility, staticp, constp,
+ volatilep, voffset, context)
+ struct ieee_handle *info;
+ const char *physname;
+ enum debug_visibility visibility;
+ boolean staticp;
+ boolean constp;
+ boolean volatilep;
+ bfd_vma voffset;
+ boolean context;
+{
+ unsigned int flags;
+ unsigned int nindx;
+ boolean virtual;
+
+ /* We don't need the type of the method. An IEEE consumer which
+ wants the type must track down the function by the physical name
+ and get the type from that. */
+ ieee_pop_unused_type (info);
+
+ /* We don't use the context. FIXME: We probably ought to use it to
+ adjust the voffset somehow, but I don't really know how. */
+ if (context)
+ ieee_pop_unused_type (info);
+
+ assert (info->type_stack != NULL
+ && info->type_stack->type.classdef != NULL
+ && info->type_stack->type.classdef->method != NULL);
+
+ flags = ieee_vis_to_flags (visibility);
+
+ /* FIXME: We never set CXXFLAGS_OVERRIDE, CXXFLAGS_OPERATOR,
+ CXXFLAGS_CTORDTOR, CXXFLAGS_CTOR, or CXXFLAGS_INLINE. */
+
+ if (staticp)
+ flags |= CXXFLAGS_STATIC;
+ if (constp)
+ flags |= CXXFLAGS_CONST;
+ if (volatilep)
+ flags |= CXXFLAGS_VOLATILE;
+
+ nindx = info->type_stack->type.classdef->indx;
+
+ virtual = context || voffset > 0;
+
+ if (! ieee_change_buffer (info,
+ &info->type_stack->type.classdef->pmiscbuf)
+ || ! ieee_write_asn (info, nindx, virtual ? 'v' : 'm')
+ || ! ieee_write_asn (info, nindx, flags)
+ || ! ieee_write_atn65 (info, nindx,
+ info->type_stack->type.classdef->method)
+ || ! ieee_write_atn65 (info, nindx, physname))
+ return false;
+
+ if (virtual)
+ {
+ if (voffset > info->type_stack->type.classdef->voffset)
+ info->type_stack->type.classdef->voffset = voffset;
+ if (! ieee_write_asn (info, nindx, voffset))
+ return false;
+ ++info->type_stack->type.classdef->pmisccount;
+ }
+
+ if (! ieee_write_asn (info, nindx, 0))
+ return false;
+
+ info->type_stack->type.classdef->pmisccount += 5;
+
+ return true;
+}
+
+/* Define a new method variant. */
+
+static boolean
+ieee_class_method_variant (p, physname, visibility, constp, volatilep,
+ voffset, context)
+ PTR p;
+ const char *physname;
+ enum debug_visibility visibility;
+ boolean constp;
+ boolean volatilep;
+ bfd_vma voffset;
+ boolean context;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ return ieee_class_method_var (info, physname, visibility, false, constp,
+ volatilep, voffset, context);
+}
+
+/* Define a new static method variant. */
+
+static boolean
+ieee_class_static_method_variant (p, physname, visibility, constp, volatilep)
+ PTR p;
+ const char *physname;
+ enum debug_visibility visibility;
+ boolean constp;
+ boolean volatilep;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ return ieee_class_method_var (info, physname, visibility, true, constp,
+ volatilep, 0, false);
+}
+
+/* Finish up a method. */
+
+static boolean
+ieee_class_end_method (p)
+ PTR p;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ assert (info->type_stack != NULL
+ && info->type_stack->type.classdef != NULL
+ && info->type_stack->type.classdef->method != NULL);
+
+ info->type_stack->type.classdef->method = NULL;
+
+ return true;
+}
+
+/* Finish up a class. */
+
+static boolean
+ieee_end_class_type (p)
+ PTR p;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ unsigned int nindx;
+
+ assert (info->type_stack != NULL
+ && info->type_stack->type.classdef != NULL);
+
+ /* If we were ignoring this class definition because it was a
+ duplicate definition, just through away whatever bytes we have
+ accumulated. Leave the type on the stack. */
+ if (info->type_stack->type.ignorep)
+ return true;
+
+ nindx = info->type_stack->type.classdef->indx;
+
+ /* If we have a virtual table, we can write out the information now. */
+ if (info->type_stack->type.classdef->vclass != NULL
+ || info->type_stack->type.classdef->ownvptr)
+ {
+ if (! ieee_change_buffer (info,
+ &info->type_stack->type.classdef->pmiscbuf)
+ || ! ieee_write_asn (info, nindx, 'z')
+ || ! ieee_write_atn65 (info, nindx, "")
+ || ! ieee_write_asn (info, nindx,
+ info->type_stack->type.classdef->voffset))
+ return false;
+ if (info->type_stack->type.classdef->ownvptr)
+ {
+ if (! ieee_write_atn65 (info, nindx, ""))
+ return false;
+ }
+ else
+ {
+ if (! ieee_write_atn65 (info, nindx,
+ info->type_stack->type.classdef->vclass))
+ return false;
+ }
+ if (! ieee_write_asn (info, nindx, 0))
+ return false;
+ info->type_stack->type.classdef->pmisccount += 5;
+ }
+
+ /* Now that we know the number of pmisc records, we can write out
+ the atn62 which starts the pmisc records, and append them to the
+ C++ buffers. */
+
+ if (! ieee_change_buffer (info, &info->cxx)
+ || ! ieee_write_byte (info, (int) ieee_nn_record)
+ || ! ieee_write_number (info, nindx)
+ || ! ieee_write_id (info, "")
+ || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum)
+ || ! ieee_write_number (info, nindx)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, 62)
+ || ! ieee_write_number (info, 80)
+ || ! ieee_write_number (info,
+ info->type_stack->type.classdef->pmisccount))
+ return false;
+
+ if (! ieee_append_buffer (info, &info->cxx,
+ &info->type_stack->type.classdef->pmiscbuf))
+ return false;
+ if (! ieee_buffer_emptyp (&info->type_stack->type.classdef->refs))
+ {
+ if (! ieee_append_buffer (info, &info->cxx,
+ &info->type_stack->type.classdef->refs))
+ return false;
+ }
+
+ return ieee_end_struct_type (p);
+}
+
+/* Push a previously seen typedef onto the type stack. */
+
+static boolean
+ieee_typedef_type (p, name)
+ PTR p;
+ const char *name;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ struct ieee_name_type_hash_entry *h;
+ struct ieee_name_type *nt;
+
+ h = ieee_name_type_hash_lookup (&info->typedefs, name, false, false);
+
+ /* h should never be NULL, since that would imply that the generic
+ debugging code has asked for a typedef which it has not yet
+ defined. */
+ assert (h != NULL);
+
+ /* We always use the most recently defined type for this name, which
+ will be the first one on the list. */
+
+ nt = h->types;
+ if (! ieee_push_type (info, nt->type.indx, nt->type.size,
+ nt->type.unsignedp, nt->type.localp))
+ return false;
+
+ /* Copy over any other type information we may have. */
+ info->type_stack->type = nt->type;
+
+ return true;
+}
+
+/* Push a tagged type onto the type stack. */
+
+static boolean
+ieee_tag_type (p, name, id, kind)
+ PTR p;
+ const char *name;
+ unsigned int id;
+ enum debug_type_kind kind;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ boolean localp;
+ boolean copy;
+ char ab[20];
+ struct ieee_name_type_hash_entry *h;
+ struct ieee_name_type *nt;
+
+ if (kind == DEBUG_KIND_ENUM)
+ {
+ struct ieee_defined_enum *e;
+
+ if (name == NULL)
+ abort ();
+ for (e = info->enums; e != NULL; e = e->next)
+ if (e->tag != NULL && strcmp (e->tag, name) == 0)
+ return ieee_push_type (info, e->indx, 0, true, false);
+
+ e = (struct ieee_defined_enum *) xmalloc (sizeof *e);
+ memset (e, 0, sizeof *e);
+
+ e->indx = info->type_indx;
+ ++info->type_indx;
+ e->tag = name;
+ e->defined = false;
+
+ e->next = info->enums;
+ info->enums = e;
+
+ return ieee_push_type (info, e->indx, 0, true, false);
+ }
+
+ localp = false;
+
+ copy = false;
+ if (name == NULL)
+ {
+ sprintf (ab, "__anon%u", id);
+ name = ab;
+ copy = true;
+ }
+
+ h = ieee_name_type_hash_lookup (&info->tags, name, true, copy);
+ if (h == NULL)
+ return false;
+
+ for (nt = h->types; nt != NULL; nt = nt->next)
+ {
+ if (nt->id == id)
+ {
+ if (! ieee_push_type (info, nt->type.indx, nt->type.size,
+ nt->type.unsignedp, nt->type.localp))
+ return false;
+ /* Copy over any other type information we may have. */
+ info->type_stack->type = nt->type;
+ return true;
+ }
+
+ if (! nt->type.localp)
+ {
+ /* This is a duplicate of a global type, so it must be
+ local. */
+ localp = true;
+ }
+ }
+
+ nt = (struct ieee_name_type *) xmalloc (sizeof *nt);
+ memset (nt, 0, sizeof *nt);
+
+ nt->id = id;
+ nt->type.name = h->root.string;
+ nt->type.indx = info->type_indx;
+ nt->type.localp = localp;
+ ++info->type_indx;
+ nt->kind = kind;
+
+ nt->next = h->types;
+ h->types = nt;
+
+ if (! ieee_push_type (info, nt->type.indx, 0, false, localp))
+ return false;
+
+ info->type_stack->type.name = h->root.string;
+
+ return true;
+}
+
+/* Output a typedef. */
+
+static boolean
+ieee_typdef (p, name)
+ PTR p;
+ const char *name;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ struct ieee_write_type type;
+ unsigned int indx;
+ boolean found;
+ boolean localp;
+ struct ieee_name_type_hash_entry *h;
+ struct ieee_name_type *nt;
+
+ type = info->type_stack->type;
+ indx = type.indx;
+
+ /* If this is a simple builtin type using a builtin name, we don't
+ want to output the typedef itself. We also want to change the
+ type index to correspond to the name being used. We recognize
+ names used in stabs debugging output even if they don't exactly
+ correspond to the names used for the IEEE builtin types. */
+ found = false;
+ if (indx <= (unsigned int) builtin_bcd_float)
+ {
+ switch ((enum builtin_types) indx)
+ {
+ default:
+ break;
+
+ case builtin_void:
+ if (strcmp (name, "void") == 0)
+ found = true;
+ break;
+
+ case builtin_signed_char:
+ case builtin_char:
+ if (strcmp (name, "signed char") == 0)
+ {
+ indx = (unsigned int) builtin_signed_char;
+ found = true;
+ }
+ else if (strcmp (name, "char") == 0)
+ {
+ indx = (unsigned int) builtin_char;
+ found = true;
+ }
+ break;
+
+ case builtin_unsigned_char:
+ if (strcmp (name, "unsigned char") == 0)
+ found = true;
+ break;
+
+ case builtin_signed_short_int:
+ case builtin_short:
+ case builtin_short_int:
+ case builtin_signed_short:
+ if (strcmp (name, "signed short int") == 0)
+ {
+ indx = (unsigned int) builtin_signed_short_int;
+ found = true;
+ }
+ else if (strcmp (name, "short") == 0)
+ {
+ indx = (unsigned int) builtin_short;
+ found = true;
+ }
+ else if (strcmp (name, "short int") == 0)
+ {
+ indx = (unsigned int) builtin_short_int;
+ found = true;
+ }
+ else if (strcmp (name, "signed short") == 0)
+ {
+ indx = (unsigned int) builtin_signed_short;
+ found = true;
+ }
+ break;
+
+ case builtin_unsigned_short_int:
+ case builtin_unsigned_short:
+ if (strcmp (name, "unsigned short int") == 0
+ || strcmp (name, "short unsigned int") == 0)
+ {
+ indx = builtin_unsigned_short_int;
+ found = true;
+ }
+ else if (strcmp (name, "unsigned short") == 0)
+ {
+ indx = builtin_unsigned_short;
+ found = true;
+ }
+ break;
+
+ case builtin_signed_long:
+ case builtin_int: /* FIXME: Size depends upon architecture. */
+ case builtin_long:
+ if (strcmp (name, "signed long") == 0)
+ {
+ indx = builtin_signed_long;
+ found = true;
+ }
+ else if (strcmp (name, "int") == 0)
+ {
+ indx = builtin_int;
+ found = true;
+ }
+ else if (strcmp (name, "long") == 0
+ || strcmp (name, "long int") == 0)
+ {
+ indx = builtin_long;
+ found = true;
+ }
+ break;
+
+ case builtin_unsigned_long:
+ case builtin_unsigned: /* FIXME: Size depends upon architecture. */
+ case builtin_unsigned_int: /* FIXME: Like builtin_unsigned. */
+ if (strcmp (name, "unsigned long") == 0
+ || strcmp (name, "long unsigned int") == 0)
+ {
+ indx = builtin_unsigned_long;
+ found = true;
+ }
+ else if (strcmp (name, "unsigned") == 0)
+ {
+ indx = builtin_unsigned;
+ found = true;
+ }
+ else if (strcmp (name, "unsigned int") == 0)
+ {
+ indx = builtin_unsigned_int;
+ found = true;
+ }
+ break;
+
+ case builtin_signed_long_long:
+ if (strcmp (name, "signed long long") == 0
+ || strcmp (name, "long long int") == 0)
+ found = true;
+ break;
+
+ case builtin_unsigned_long_long:
+ if (strcmp (name, "unsigned long long") == 0
+ || strcmp (name, "long long unsigned int") == 0)
+ found = true;
+ break;
+
+ case builtin_float:
+ if (strcmp (name, "float") == 0)
+ found = true;
+ break;
+
+ case builtin_double:
+ if (strcmp (name, "double") == 0)
+ found = true;
+ break;
+
+ case builtin_long_double:
+ if (strcmp (name, "long double") == 0)
+ found = true;
+ break;
+
+ case builtin_long_long_double:
+ if (strcmp (name, "long long double") == 0)
+ found = true;
+ break;
+ }
+
+ if (found)
+ type.indx = indx;
+ }
+
+ h = ieee_name_type_hash_lookup (&info->typedefs, name, true, false);
+ if (h == NULL)
+ return false;
+
+ /* See if we have already defined this type with this name. */
+ localp = type.localp;
+ for (nt = h->types; nt != NULL; nt = nt->next)
+ {
+ if (nt->id == indx)
+ {
+ /* If this is a global definition, then we don't need to
+ do anything here. */
+ if (! nt->type.localp)
+ {
+ ieee_pop_unused_type (info);
+ return true;
+ }
+ }
+ else
+ {
+ /* This is a duplicate definition, so make this one local. */
+ localp = true;
+ }
+ }
+
+ /* We need to add a new typedef for this type. */
+
+ nt = (struct ieee_name_type *) xmalloc (sizeof *nt);
+ memset (nt, 0, sizeof *nt);
+ nt->id = indx;
+ nt->type = type;
+ nt->type.name = name;
+ nt->type.localp = localp;
+ nt->kind = DEBUG_KIND_ILLEGAL;
+
+ nt->next = h->types;
+ h->types = nt;
+
+ if (found)
+ {
+ /* This is one of the builtin typedefs, so we don't need to
+ actually define it. */
+ ieee_pop_unused_type (info);
+ return true;
+ }
+
+ indx = ieee_pop_type (info);
+
+ if (! ieee_define_named_type (info, name, (unsigned int) -1, type.size,
+ type.unsignedp, localp,
+ (struct ieee_buflist *) NULL)
+ || ! ieee_write_number (info, 'T')
+ || ! ieee_write_number (info, indx))
+ return false;
+
+ /* Remove the type we just added to the type stack. This should not
+ be ieee_pop_unused_type, since the type is used, we just don't
+ need it now. */
+ (void) ieee_pop_type (info);
+
+ return true;
+}
+
+/* Output a tag for a type. We don't have to do anything here. */
+
+static boolean
+ieee_tag (p, name)
+ PTR p;
+ const char *name;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ /* This should not be ieee_pop_unused_type, since we want the type
+ to be defined. */
+ (void) ieee_pop_type (info);
+ return true;
+}
+
+/* Output an integer constant. */
+
+static boolean
+ieee_int_constant (p, name, val)
+ PTR p;
+ const char *name;
+ bfd_vma val;
+{
+ /* FIXME. */
+ return true;
+}
+
+/* Output a floating point constant. */
+
+static boolean
+ieee_float_constant (p, name, val)
+ PTR p;
+ const char *name;
+ double val;
+{
+ /* FIXME. */
+ return true;
+}
+
+/* Output a typed constant. */
+
+static boolean
+ieee_typed_constant (p, name, val)
+ PTR p;
+ const char *name;
+ bfd_vma val;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ /* FIXME. */
+ ieee_pop_unused_type (info);
+ return true;
+}
+
+/* Output a variable. */
+
+static boolean
+ieee_variable (p, name, kind, val)
+ PTR p;
+ const char *name;
+ enum debug_var_kind kind;
+ bfd_vma val;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ unsigned int name_indx;
+ unsigned int size;
+ boolean referencep;
+ unsigned int type_indx;
+ boolean asn;
+ int refflag;
+
+ size = info->type_stack->type.size;
+ referencep = info->type_stack->type.referencep;
+ type_indx = ieee_pop_type (info);
+
+ assert (! ieee_buffer_emptyp (&info->vars));
+ if (! ieee_change_buffer (info, &info->vars))
+ return false;
+
+ name_indx = info->name_indx;
+ ++info->name_indx;
+
+ /* Write out an NN and an ATN record for this variable. */
+ if (! ieee_write_byte (info, (int) ieee_nn_record)
+ || ! ieee_write_number (info, name_indx)
+ || ! ieee_write_id (info, name)
+ || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum)
+ || ! ieee_write_number (info, name_indx)
+ || ! ieee_write_number (info, type_indx))
+ return false;
+ switch (kind)
+ {
+ default:
+ abort ();
+ return false;
+ case DEBUG_GLOBAL:
+ if (! ieee_write_number (info, 8)
+ || ! ieee_add_range (info, false, val, val + size))
+ return false;
+ refflag = 0;
+ asn = true;
+ break;
+ case DEBUG_STATIC:
+ if (! ieee_write_number (info, 3)
+ || ! ieee_add_range (info, false, val, val + size))
+ return false;
+ refflag = 1;
+ asn = true;
+ break;
+ case DEBUG_LOCAL_STATIC:
+ if (! ieee_write_number (info, 3)
+ || ! ieee_add_range (info, false, val, val + size))
+ return false;
+ refflag = 2;
+ asn = true;
+ break;
+ case DEBUG_LOCAL:
+ if (! ieee_write_number (info, 1)
+ || ! ieee_write_number (info, val))
+ return false;
+ refflag = 2;
+ asn = false;
+ break;
+ case DEBUG_REGISTER:
+ if (! ieee_write_number (info, 2)
+ || ! ieee_write_number (info,
+ ieee_genreg_to_regno (info->abfd, val)))
+ return false;
+ refflag = 2;
+ asn = false;
+ break;
+ }
+
+ if (asn)
+ {
+ if (! ieee_write_asn (info, name_indx, val))
+ return false;
+ }
+
+ /* If this is really a reference type, then we just output it with
+ pointer type, and must now output a C++ record indicating that it
+ is really reference type. */
+ if (referencep)
+ {
+ unsigned int nindx;
+
+ nindx = info->name_indx;
+ ++info->name_indx;
+
+ /* If this is a global variable, we want to output the misc
+ record in the C++ misc record block. Otherwise, we want to
+ output it just after the variable definition, which is where
+ the current buffer is. */
+ if (refflag != 2)
+ {
+ if (! ieee_change_buffer (info, &info->cxx))
+ return false;
+ }
+
+ if (! ieee_write_byte (info, (int) ieee_nn_record)
+ || ! ieee_write_number (info, nindx)
+ || ! ieee_write_id (info, "")
+ || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum)
+ || ! ieee_write_number (info, nindx)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, 62)
+ || ! ieee_write_number (info, 80)
+ || ! ieee_write_number (info, 3)
+ || ! ieee_write_asn (info, nindx, 'R')
+ || ! ieee_write_asn (info, nindx, refflag)
+ || ! ieee_write_atn65 (info, nindx, name))
+ return false;
+ }
+
+ return true;
+}
+
+/* Start outputting information for a function. */
+
+static boolean
+ieee_start_function (p, name, global)
+ PTR p;
+ const char *name;
+ boolean global;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ boolean referencep;
+ unsigned int retindx, typeindx;
+
+ referencep = info->type_stack->type.referencep;
+ retindx = ieee_pop_type (info);
+
+ /* Besides recording a BB4 or BB6 block, we record the type of the
+ function in the BB1 typedef block. We can't write out the full
+ type until we have seen all the parameters, so we accumulate it
+ in info->fntype and info->fnargs. */
+ if (! ieee_buffer_emptyp (&info->fntype))
+ {
+ /* FIXME: This might happen someday if we support nested
+ functions. */
+ abort ();
+ }
+
+ info->fnname = name;
+
+ /* An attribute of 0x40 means that the push mask is unknown. */
+ if (! ieee_define_named_type (info, name, (unsigned int) -1, 0, false, true,
+ &info->fntype)
+ || ! ieee_write_number (info, 'x')
+ || ! ieee_write_number (info, 0x40)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, retindx))
+ return false;
+
+ typeindx = ieee_pop_type (info);
+
+ if (! ieee_init_buffer (info, &info->fnargs))
+ return false;
+ info->fnargcount = 0;
+
+ /* If the function return value is actually a reference type, we
+ must add a record indicating that. */
+ if (referencep)
+ {
+ unsigned int nindx;
+
+ nindx = info->name_indx;
+ ++info->name_indx;
+ if (! ieee_change_buffer (info, &info->cxx)
+ || ! ieee_write_byte (info, (int) ieee_nn_record)
+ || ! ieee_write_number (info, nindx)
+ || ! ieee_write_id (info, "")
+ || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum)
+ || ! ieee_write_number (info, nindx)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, 62)
+ || ! ieee_write_number (info, 80)
+ || ! ieee_write_number (info, 3)
+ || ! ieee_write_asn (info, nindx, 'R')
+ || ! ieee_write_asn (info, nindx, global ? 0 : 1)
+ || ! ieee_write_atn65 (info, nindx, name))
+ return false;
+ }
+
+ assert (! ieee_buffer_emptyp (&info->vars));
+ if (! ieee_change_buffer (info, &info->vars))
+ return false;
+
+ /* The address is written out as the first block. */
+
+ ++info->block_depth;
+
+ return (ieee_write_byte (info, (int) ieee_bb_record_enum)
+ && ieee_write_byte (info, global ? 4 : 6)
+ && ieee_write_number (info, 0)
+ && ieee_write_id (info, name)
+ && ieee_write_number (info, 0)
+ && ieee_write_number (info, typeindx));
+}
+
+/* Add a function parameter. This will normally be called before the
+ first block, so we postpone them until we see the block. */
+
+static boolean
+ieee_function_parameter (p, name, kind, val)
+ PTR p;
+ const char *name;
+ enum debug_parm_kind kind;
+ bfd_vma val;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ struct ieee_pending_parm *m, **pm;
+
+ assert (info->block_depth == 1);
+
+ m = (struct ieee_pending_parm *) xmalloc (sizeof *m);
+ memset (m, 0, sizeof *m);
+
+ m->next = NULL;
+ m->name = name;
+ m->referencep = info->type_stack->type.referencep;
+ m->type = ieee_pop_type (info);
+ m->kind = kind;
+ m->val = val;
+
+ for (pm = &info->pending_parms; *pm != NULL; pm = &(*pm)->next)
+ ;
+ *pm = m;
+
+ /* Add the type to the fnargs list. */
+ if (! ieee_change_buffer (info, &info->fnargs)
+ || ! ieee_write_number (info, m->type))
+ return false;
+ ++info->fnargcount;
+
+ return true;
+}
+
+/* Output pending function parameters. */
+
+static boolean
+ieee_output_pending_parms (info)
+ struct ieee_handle *info;
+{
+ struct ieee_pending_parm *m;
+ unsigned int refcount;
+
+ refcount = 0;
+ for (m = info->pending_parms; m != NULL; m = m->next)
+ {
+ enum debug_var_kind vkind;
+
+ switch (m->kind)
+ {
+ default:
+ abort ();
+ return false;
+ case DEBUG_PARM_STACK:
+ case DEBUG_PARM_REFERENCE:
+ vkind = DEBUG_LOCAL;
+ break;
+ case DEBUG_PARM_REG:
+ case DEBUG_PARM_REF_REG:
+ vkind = DEBUG_REGISTER;
+ break;
+ }
+
+ if (! ieee_push_type (info, m->type, 0, false, false))
+ return false;
+ info->type_stack->type.referencep = m->referencep;
+ if (m->referencep)
+ ++refcount;
+ if (! ieee_variable ((PTR) info, m->name, vkind, m->val))
+ return false;
+ }
+
+ /* If there are any reference parameters, we need to output a
+ miscellaneous record indicating them. */
+ if (refcount > 0)
+ {
+ unsigned int nindx, varindx;
+
+ /* FIXME: The MRI compiler outputs the demangled function name
+ here, but we are outputting the mangled name. */
+ nindx = info->name_indx;
+ ++info->name_indx;
+ if (! ieee_change_buffer (info, &info->vars)
+ || ! ieee_write_byte (info, (int) ieee_nn_record)
+ || ! ieee_write_number (info, nindx)
+ || ! ieee_write_id (info, "")
+ || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum)
+ || ! ieee_write_number (info, nindx)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, 62)
+ || ! ieee_write_number (info, 80)
+ || ! ieee_write_number (info, refcount + 3)
+ || ! ieee_write_asn (info, nindx, 'B')
+ || ! ieee_write_atn65 (info, nindx, info->fnname)
+ || ! ieee_write_asn (info, nindx, 0))
+ return false;
+ for (m = info->pending_parms, varindx = 1;
+ m != NULL;
+ m = m->next, varindx++)
+ {
+ if (m->referencep)
+ {
+ if (! ieee_write_asn (info, nindx, varindx))
+ return false;
+ }
+ }
+ }
+
+ m = info->pending_parms;
+ while (m != NULL)
+ {
+ struct ieee_pending_parm *next;
+
+ next = m->next;
+ free (m);
+ m = next;
+ }
+
+ info->pending_parms = NULL;
+
+ return true;
+}
+
+/* Start a block. If this is the first block, we output the address
+ to finish the BB4 or BB6, and then output the function parameters. */
+
+static boolean
+ieee_start_block (p, addr)
+ PTR p;
+ bfd_vma addr;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ if (! ieee_change_buffer (info, &info->vars))
+ return false;
+
+ if (info->block_depth == 1)
+ {
+ if (! ieee_write_number (info, addr)
+ || ! ieee_output_pending_parms (info))
+ return false;
+ }
+ else
+ {
+ if (! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 6)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, "")
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, addr))
+ return false;
+ }
+
+ if (! ieee_start_range (info, addr))
+ return false;
+
+ ++info->block_depth;
+
+ return true;
+}
+
+/* End a block. */
+
+static boolean
+ieee_end_block (p, addr)
+ PTR p;
+ bfd_vma addr;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ /* The address we are given is the end of the block, but IEEE seems
+ to want to the address of the last byte in the block, so we
+ subtract one. */
+ if (! ieee_change_buffer (info, &info->vars)
+ || ! ieee_write_byte (info, (int) ieee_be_record_enum)
+ || ! ieee_write_number (info, addr - 1))
+ return false;
+
+ if (! ieee_end_range (info, addr))
+ return false;
+
+ --info->block_depth;
+
+ if (addr > info->highaddr)
+ info->highaddr = addr;
+
+ return true;
+}
+
+/* End a function. */
+
+static boolean
+ieee_end_function (p)
+ PTR p;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ assert (info->block_depth == 1);
+
+ --info->block_depth;
+
+ /* Now we can finish up fntype, and add it to the typdef section.
+ At this point, fntype is the 'x' type up to the argument count,
+ and fnargs is the argument types. We must add the argument
+ count, and we must add the level. FIXME: We don't record varargs
+ functions correctly. In fact, stabs debugging does not give us
+ enough information to do so. */
+ if (! ieee_change_buffer (info, &info->fntype)
+ || ! ieee_write_number (info, info->fnargcount)
+ || ! ieee_change_buffer (info, &info->fnargs)
+ || ! ieee_write_number (info, 0))
+ return false;
+
+ /* Make sure the typdef block has been started. */
+ if (ieee_buffer_emptyp (&info->types))
+ {
+ if (! ieee_change_buffer (info, &info->types)
+ || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 1)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, info->modname))
+ return false;
+ }
+
+ if (! ieee_append_buffer (info, &info->types, &info->fntype)
+ || ! ieee_append_buffer (info, &info->types, &info->fnargs))
+ return false;
+
+ info->fnname = NULL;
+ if (! ieee_init_buffer (info, &info->fntype)
+ || ! ieee_init_buffer (info, &info->fnargs))
+ return false;
+ info->fnargcount = 0;
+
+ return true;
+}
+
+/* Record line number information. */
+
+static boolean
+ieee_lineno (p, filename, lineno, addr)
+ PTR p;
+ const char *filename;
+ unsigned long lineno;
+ bfd_vma addr;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ assert (info->filename != NULL);
+
+ /* The HP simulator seems to get confused when more than one line is
+ listed for the same address, at least if they are in different
+ files. We handle this by always listing the last line for a
+ given address, since that seems to be the one that gdb uses. */
+ if (info->pending_lineno_filename != NULL
+ && addr != info->pending_lineno_addr)
+ {
+ /* Make sure we have a line number block. */
+ if (! ieee_buffer_emptyp (&info->linenos))
+ {
+ if (! ieee_change_buffer (info, &info->linenos))
+ return false;
+ }
+ else
+ {
+ info->lineno_name_indx = info->name_indx;
+ ++info->name_indx;
+ if (! ieee_change_buffer (info, &info->linenos)
+ || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 5)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, info->filename)
+ || ! ieee_write_byte (info, (int) ieee_nn_record)
+ || ! ieee_write_number (info, info->lineno_name_indx)
+ || ! ieee_write_id (info, ""))
+ return false;
+ info->lineno_filename = info->filename;
+ }
+
+ if (strcmp (info->pending_lineno_filename, info->lineno_filename) != 0)
+ {
+ if (strcmp (info->filename, info->lineno_filename) != 0)
+ {
+ /* We were not in the main file. Close the block for the
+ included file. */
+ if (! ieee_write_byte (info, (int) ieee_be_record_enum))
+ return false;
+ if (strcmp (info->filename, info->pending_lineno_filename) == 0)
+ {
+ /* We need a new NN record, and we aren't about to
+ output one. */
+ info->lineno_name_indx = info->name_indx;
+ ++info->name_indx;
+ if (! ieee_write_byte (info, (int) ieee_nn_record)
+ || ! ieee_write_number (info, info->lineno_name_indx)
+ || ! ieee_write_id (info, ""))
+ return false;
+ }
+ }
+ if (strcmp (info->filename, info->pending_lineno_filename) != 0)
+ {
+ /* We are not changing to the main file. Open a block for
+ the new included file. */
+ info->lineno_name_indx = info->name_indx;
+ ++info->name_indx;
+ if (! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 5)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, info->pending_lineno_filename)
+ || ! ieee_write_byte (info, (int) ieee_nn_record)
+ || ! ieee_write_number (info, info->lineno_name_indx)
+ || ! ieee_write_id (info, ""))
+ return false;
+ }
+ info->lineno_filename = info->pending_lineno_filename;
+ }
+
+ if (! ieee_write_2bytes (info, (int) ieee_atn_record_enum)
+ || ! ieee_write_number (info, info->lineno_name_indx)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, 7)
+ || ! ieee_write_number (info, info->pending_lineno)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_asn (info, info->lineno_name_indx,
+ info->pending_lineno_addr))
+ return false;
+ }
+
+ info->pending_lineno_filename = filename;
+ info->pending_lineno = lineno;
+ info->pending_lineno_addr = addr;
+
+ return true;
+}
diff --git a/pstack/ieee.h b/pstack/ieee.h
new file mode 100644
index 00000000000..56634b2819a
--- /dev/null
+++ b/pstack/ieee.h
@@ -0,0 +1,138 @@
+/* IEEE Standard 695-1980 "Universal Format for Object Modules" header file
+ Contributed by Cygnus Support. */
+
+#define N_W_VARIABLES 8
+#define Module_Beginning 0xe0
+
+typedef struct ieee_module {
+ char *processor;
+ char *module_name;
+} ieee_module_begin_type;
+
+#define Address_Descriptor 0xec
+typedef struct ieee_address {
+bfd_vma number_of_bits_mau;
+ bfd_vma number_of_maus_in_address;
+
+ unsigned char byte_order;
+#define IEEE_LITTLE 0xcc
+#define IEEE_BIG 0xcd
+} ieee_address_descriptor_type;
+
+typedef union ieee_w_variable {
+ file_ptr offset[N_W_VARIABLES];
+ struct {
+ file_ptr extension_record;
+ file_ptr environmental_record;
+ file_ptr section_part;
+ file_ptr external_part;
+ file_ptr debug_information_part;
+ file_ptr data_part;
+ file_ptr trailer_part;
+ file_ptr me_record;
+ } r;
+} ieee_w_variable_type;
+
+
+
+
+
+typedef enum ieee_record
+{
+ ieee_number_start_enum = 0x00,
+ ieee_number_end_enum=0x7f,
+ ieee_number_repeat_start_enum = 0x80,
+ ieee_number_repeat_end_enum = 0x88,
+ ieee_number_repeat_4_enum = 0x84,
+ ieee_number_repeat_3_enum = 0x83,
+ ieee_number_repeat_2_enum = 0x82,
+ ieee_number_repeat_1_enum = 0x81,
+ ieee_module_beginning_enum = 0xe0,
+ ieee_module_end_enum = 0xe1,
+ ieee_extension_length_1_enum = 0xde,
+ ieee_extension_length_2_enum = 0xdf,
+ ieee_section_type_enum = 0xe6,
+ ieee_section_alignment_enum = 0xe7,
+ ieee_external_symbol_enum = 0xe8,
+ ieee_comma = 0x90,
+ ieee_external_reference_enum = 0xe9,
+ ieee_set_current_section_enum = 0xe5,
+ ieee_address_descriptor_enum = 0xec,
+ ieee_load_constant_bytes_enum = 0xed,
+ ieee_load_with_relocation_enum = 0xe4,
+
+ ieee_variable_A_enum = 0xc1,
+ ieee_variable_B_enum = 0xc2,
+ ieee_variable_C_enum = 0xc3,
+ ieee_variable_D_enum = 0xc4,
+ ieee_variable_E_enum = 0xc5,
+ ieee_variable_F_enum = 0xc6,
+ ieee_variable_G_enum = 0xc7,
+ ieee_variable_H_enum = 0xc8,
+ ieee_variable_I_enum = 0xc9,
+ ieee_variable_J_enum = 0xca,
+ ieee_variable_K_enum = 0xcb,
+ ieee_variable_L_enum = 0xcc,
+ ieee_variable_M_enum = 0xcd,
+ ieee_variable_N_enum = 0xce,
+ ieee_variable_O_enum = 0xcf,
+ ieee_variable_P_enum = 0xd0,
+ ieee_variable_Q_enum = 0xd1,
+ ieee_variable_R_enum = 0xd2,
+ ieee_variable_S_enum = 0xd3,
+ ieee_variable_T_enum = 0xd4,
+ ieee_variable_U_enum = 0xd5,
+ ieee_variable_V_enum = 0xd6,
+ ieee_variable_W_enum = 0xd7,
+ ieee_variable_X_enum = 0xd8,
+ ieee_variable_Y_enum = 0xd9,
+ ieee_variable_Z_enum = 0xda,
+ ieee_function_plus_enum = 0xa5,
+ ieee_function_minus_enum = 0xa6,
+ ieee_function_signed_open_b_enum = 0xba,
+ ieee_function_signed_close_b_enum = 0xbb,
+
+ ieee_function_unsigned_open_b_enum = 0xbc,
+ ieee_function_unsigned_close_b_enum = 0xbd,
+
+ ieee_function_either_open_b_enum = 0xbe,
+ ieee_function_either_close_b_enum = 0xbf,
+ ieee_record_seperator_enum = 0xdb,
+
+ ieee_e2_first_byte_enum = 0xe2,
+ ieee_section_size_enum = 0xe2d3,
+ ieee_physical_region_size_enum = 0xe2c1,
+ ieee_region_base_address_enum = 0xe2c2,
+ ieee_mau_size_enum = 0xe2c6,
+ ieee_m_value_enum = 0xe2cd,
+ ieee_section_base_address_enum = 0xe2cc,
+ ieee_asn_record_enum = 0xe2ce,
+ ieee_section_offset_enum = 0xe2d2,
+ ieee_value_starting_address_enum = 0xe2c7,
+ ieee_assign_value_to_variable_enum = 0xe2d7,
+ ieee_set_current_pc_enum = 0xe2d0,
+ ieee_value_record_enum = 0xe2c9,
+ ieee_nn_record = 0xf0,
+ ieee_at_record_enum = 0xf1,
+ ieee_ty_record_enum = 0xf2,
+ ieee_attribute_record_enum = 0xf1c9,
+ ieee_atn_record_enum = 0xf1ce,
+ ieee_external_reference_info_record_enum = 0xf1d8,
+ ieee_weak_external_reference_enum= 0xf4,
+ ieee_repeat_data_enum = 0xf7,
+ ieee_bb_record_enum = 0xf8,
+ ieee_be_record_enum = 0xf9
+} ieee_record_enum_type;
+
+
+typedef struct ieee_section {
+ unsigned int section_index;
+ unsigned int section_type;
+ char *section_name;
+ unsigned int parent_section_index;
+ unsigned int sibling_section_index;
+ unsigned int context_index;
+} ieee_section_type;
+#define IEEE_REFERENCE_BASE 11
+#define IEEE_PUBLIC_BASE 32
+#define IEEE_SECTION_NUMBER_BASE 1
diff --git a/pstack/libiberty.h b/pstack/libiberty.h
new file mode 100644
index 00000000000..ca0043d31c6
--- /dev/null
+++ b/pstack/libiberty.h
@@ -0,0 +1,180 @@
+/* Function declarations for libiberty.
+ Written by Cygnus Support, 1994.
+
+ The libiberty library provides a number of functions which are
+ missing on some operating systems. We do not declare those here,
+ to avoid conflicts with the system header files on operating
+ systems that do support those functions. In this file we only
+ declare those functions which are specific to libiberty. */
+
+#ifndef LIBIBERTY_H
+#define LIBIBERTY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ansidecl.h"
+
+/* Build an argument vector from a string. Allocates memory using
+ malloc. Use freeargv to free the vector. */
+
+extern char **buildargv PARAMS ((char *));
+
+/* Free a vector returned by buildargv. */
+
+extern void freeargv PARAMS ((char **));
+
+/* Duplicate an argument vector. Allocates memory using malloc. Use
+ freeargv to free the vector. */
+
+extern char **dupargv PARAMS ((char **));
+
+
+/* Return the last component of a path name. Note that we can't use a
+ prototype here because the parameter is declared inconsistently
+ across different systems, sometimes as "char *" and sometimes as
+ "const char *" */
+
+#if defined (__GNU_LIBRARY__ ) || defined (__linux__) || defined (__FreeBSD__)
+extern char *basename PARAMS ((const char *));
+#else
+extern char *basename ();
+#endif
+
+/* Concatenate an arbitrary number of strings, up to (char *) NULL.
+ Allocates memory using xmalloc. */
+
+extern char *concat PARAMS ((const char *, ...));
+
+/* Check whether two file descriptors refer to the same file. */
+
+extern int fdmatch PARAMS ((int fd1, int fd2));
+
+/* Get the amount of time the process has run, in microseconds. */
+
+extern long get_run_time PARAMS ((void));
+
+/* Choose a temporary directory to use for scratch files. */
+
+extern char *choose_temp_base PARAMS ((void));
+
+/* Allocate memory filled with spaces. Allocates using malloc. */
+
+extern const char *spaces PARAMS ((int count));
+
+/* Return the maximum error number for which strerror will return a
+ string. */
+
+extern int errno_max PARAMS ((void));
+
+/* Return the name of an errno value (e.g., strerrno (EINVAL) returns
+ "EINVAL"). */
+
+extern const char *strerrno PARAMS ((int));
+
+/* Given the name of an errno value, return the value. */
+
+extern int strtoerrno PARAMS ((const char *));
+
+/* ANSI's strerror(), but more robust. */
+
+extern char *xstrerror PARAMS ((int));
+
+/* Return the maximum signal number for which strsignal will return a
+ string. */
+
+extern int signo_max PARAMS ((void));
+
+/* Return a signal message string for a signal number
+ (e.g., strsignal (SIGHUP) returns something like "Hangup"). */
+/* This is commented out as it can conflict with one in system headers.
+ We still document its existence though. */
+
+/*extern const char *strsignal PARAMS ((int));*/
+
+/* Return the name of a signal number (e.g., strsigno (SIGHUP) returns
+ "SIGHUP"). */
+
+extern const char *strsigno PARAMS ((int));
+
+/* Given the name of a signal, return its number. */
+
+extern int strtosigno PARAMS ((const char *));
+
+/* Register a function to be run by xexit. Returns 0 on success. */
+
+extern int xatexit PARAMS ((void (*fn) (void)));
+
+/* Exit, calling all the functions registered with xatexit. */
+
+#ifndef __GNUC__
+extern void xexit PARAMS ((int status));
+#else
+void xexit PARAMS ((int status)) __attribute__ ((noreturn));
+#endif
+
+/* Set the program name used by xmalloc. */
+
+extern void xmalloc_set_program_name PARAMS ((const char *));
+
+/* Allocate memory without fail. If malloc fails, this will print a
+ message to stderr (using the name set by xmalloc_set_program_name,
+ if any) and then call xexit. */
+
+#ifdef ANSI_PROTOTYPES
+/* Get a definition for size_t. */
+#include <stddef.h>
+#endif
+extern PTR xmalloc PARAMS ((size_t));
+
+/* Reallocate memory without fail. This works like xmalloc.
+
+ FIXME: We do not declare the parameter types for the same reason as
+ xmalloc. */
+
+extern PTR xrealloc PARAMS ((PTR, size_t));
+
+/* Allocate memory without fail and set it to zero. This works like
+ xmalloc. */
+
+extern PTR xcalloc PARAMS ((size_t, size_t));
+
+/* Copy a string into a memory buffer without fail. */
+
+extern char *xstrdup PARAMS ((const char *));
+
+/* hex character manipulation routines */
+
+#define _hex_array_size 256
+#define _hex_bad 99
+extern char _hex_value[_hex_array_size];
+extern void hex_init PARAMS ((void));
+#define hex_p(c) (hex_value (c) != _hex_bad)
+/* If you change this, note well: Some code relies on side effects in
+ the argument being performed exactly once. */
+#define hex_value(c) (_hex_value[(unsigned char) (c)])
+
+/* Definitions used by the pexecute routine. */
+
+#define PEXECUTE_FIRST 1
+#define PEXECUTE_LAST 2
+#define PEXECUTE_ONE (PEXECUTE_FIRST + PEXECUTE_LAST)
+#define PEXECUTE_SEARCH 4
+#define PEXECUTE_VERBOSE 8
+
+/* Execute a program. */
+
+extern int pexecute PARAMS ((const char *, char * const *, const char *,
+ const char *, char **, char **, int));
+
+/* Wait for pexecute to finish. */
+
+extern int pwait PARAMS ((int, int *, int));
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* ! defined (LIBIBERTY_H) */
diff --git a/pstack/linuxthreads.c b/pstack/linuxthreads.c
new file mode 100644
index 00000000000..8624bd21782
--- /dev/null
+++ b/pstack/linuxthreads.c
@@ -0,0 +1,90 @@
+/* $Header$ */
+
+/*
+ * LinuxThreads specific stuff.
+ */
+
+#include <sys/types.h>
+
+#include <assert.h>
+#include <limits.h> /* PTHREAD_THREADS_MAX */
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sched.h>
+
+#include "linuxthreads.h"
+
+#define AT_INT(intval) *((int32_t*)(intval))
+
+/*
+ * Internal LinuxThreads variables.
+ * Official interface exposed to GDB.
+ */
+#if 1
+extern volatile int __pthread_threads_debug;
+extern volatile char __pthread_handles;
+extern char __pthread_initial_thread;
+/*extern volatile Elf32_Sym* __pthread_manager_thread;*/
+extern const int __pthread_sizeof_handle;
+extern const int __pthread_offsetof_descr;
+extern const int __pthread_offsetof_pid;
+extern volatile int __pthread_handles_num;
+#endif /* 0 */
+
+/*
+ * Notify others.
+ */
+int
+linuxthreads_notify_others( const int signotify)
+{
+ const pid_t mypid = getpid();
+ //const pthread_t mytid = pthread_self();
+ int i;
+ int threadcount = 0;
+ int threads[PTHREAD_THREADS_MAX];
+ int pid;
+
+ TRACE_FPRINTF((stderr, "theadcount:%d\n", __pthread_handles_num));
+ if (__pthread_handles_num==2) {
+ /* no threads beside the initial thread */
+ return 0;
+ }
+ /*assert(maxthreads>=3);
+ assert(maxthreads>=__pthread_handles_num+2);*/
+
+ // take the initial thread with us
+ pid = AT_INT(&__pthread_initial_thread + __pthread_offsetof_pid);
+ if (pid!=mypid && pid!=0)
+ threads[threadcount++] = pid;
+ // don't know why, but always handles[0]==handles[1]
+ for (i=1; i<__pthread_handles_num; ++i) {
+ const int descr = AT_INT(&__pthread_handles+i*__pthread_sizeof_handle+__pthread_offsetof_descr);
+ assert(descr!=0);
+ pid = AT_INT(descr+__pthread_offsetof_pid);
+ if (pid!=mypid && pid!=0)
+ threads[threadcount++] = pid;
+ }
+ /* TRACE_FPRINTF((stderr, "Stopping threads...")); */
+ //for (i=0; i<threadcount; ++i) {
+ // /* TRACE_FPRINTF((stderr, "%d ", threads[i])); */
+ // fflush(stdout);
+ // kill(threads[i], SIGSTOP); /* Tell thread to stop */
+ //}
+ /* TRACE_FPRINTF((stderr, " done!\n")); */
+ for (i=0; i<threadcount; ++i) {
+ TRACE_FPRINTF((stderr, "--- NOTIFYING %d\n", threads[i]));
+ kill(threads[i], signotify); /* Tell to print stack trace */
+ /* TRACE_FPRINTF((stderr, "--- WAITING FOR %d\n", threads[i])); */
+ /*pause(); Wait for confirmation. */
+ }
+ for (i=0; i<threadcount; ++i)
+ sched_yield();
+ for (i=0; i<threadcount; ++i) {
+ TRACE_FPRINTF((stderr, "--- KILLING %d\n", threads[i]));
+ kill(threads[i], SIGKILL); /* Tell thread die :) */
+ }
+ return __pthread_handles_num;
+}
+
diff --git a/pstack/linuxthreads.h b/pstack/linuxthreads.h
new file mode 100644
index 00000000000..f5eb0f652d8
--- /dev/null
+++ b/pstack/linuxthreads.h
@@ -0,0 +1,28 @@
+/* $Header$ */
+
+/*
+ * LinuxThreads specific stuff.
+ */
+
+#ifndef pstack_linuxthreads_h_
+#define pstack_linuxthreads_h_
+
+#include <pthread.h>
+#include "pstacktrace.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Tell other threads to dump stacks...
+ */
+int
+linuxthreads_notify_others( const int signotify);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* pstack_linuxthreads_h_ */
+
diff --git a/pstack/pstack.c b/pstack/pstack.c
new file mode 100644
index 00000000000..48280d4aedb
--- /dev/null
+++ b/pstack/pstack.c
@@ -0,0 +1,2745 @@
+/*
+ pstack.c -- asynchronous stack trace of a running process
+ Copyright (c) 1999 Ross Thompson
+ Author: Ross Thompson <ross@whatsis.com>
+ Critical bug fix: Tim Waugh
+*/
+
+/*
+ This file is free software; 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.
+*/
+
+/* RESTRICTIONS:
+
+ pstack currently works only on Linux, only on an x86 machine running
+ 32 bit ELF binaries (64 bit not supported). Also, for symbolic
+ information, you need to use a GNU compiler to generate your
+ program, and you can't strip symbols from the binaries. For thread
+ information to be dumped, you have to use the debug-aware version
+ of libpthread.so. (To check, run 'nm' on your libpthread.so, and
+ make sure that the symbol "__pthread_threads_debug" is defined.)
+
+ The details of pulling stuff out of ELF files and running through
+ program images is very platform specific, and I don't want to
+ try to support modes or machine types I can't test in or on.
+ If someone wants to generalize this to other architectures, I would
+ be happy to help and coordinate the activity. Please send me whatever
+ changes you make to support these machines, so that I can own the
+ central font of all truth (at least as regards this program).
+
+ Thanks
+*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+
+#include <assert.h>
+#include <fcntl.h>
+#include <link.h>
+#include <malloc.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <pthread.h>
+#include <limits.h> /* PTHREAD_THREADS_MAX */
+
+
+#include <bfd.h>
+
+#include "libiberty.h"
+
+#include "pstack.h" /* just one function */
+#include "budbg.h" /* binutils stuff related to debugging symbols. */
+#include "bucomm.h" /* some common stuff */
+#include "debug.h" /* and more binutils stuff... */
+#include "budbg.h"
+#include "linuxthreads.h" /* LinuxThreads specific stuff... */
+
+
+/*
+ * fprintf for file descriptors :) NOTE: we have to use fixed-size buffer :)(
+ * due to malloc's unavalaibility.
+ */
+int
+fdprintf( int fd,
+ const char* fmt,...)
+{
+ char xbuf[2048];// FIXME: enough?
+ va_list ap;
+ int r;
+ if (fd<0)
+ return -1;
+ va_start(ap, fmt);
+ r = vsnprintf(xbuf, sizeof(xbuf), fmt, ap);
+ va_end(ap);
+ return write(fd, xbuf, r);
+}
+
+int
+fdputc( char c,
+ int fd)
+{
+ if (fd<0)
+ return -1;
+ return write(fd, &c, sizeof(c));
+}
+
+int
+fdputs( const char* s,
+ int fd)
+{
+ if (fd<0)
+ return -1;
+ return write(fd, s, strlen(s));
+}
+
+/*
+ * Use this function to open log file.
+ * Flags: truncate on opening.
+ */
+static const char* path_format = "stack-trace-on-segv-%d.txt";
+static int
+open_log_file( const pthread_t tid,
+ const pid_t pid)
+{
+ char fname[PATH_MAX];
+ int r;
+ snprintf(fname, sizeof(fname), path_format, tid, pid);
+ r = open(fname, O_WRONLY|O_CREAT|O_TRUNC,
+ S_IRUSR|S_IWUSR);
+ if (r<0)
+ perror("open");
+ return r;
+}
+/*
+ * Add additional debugging information for functions.
+ */
+
+/*
+ * Lineno
+ */
+typedef struct {
+ int lineno;
+ bfd_vma addr;
+} debug_lineno_t;
+
+/*
+ * Block - a {} pair.
+ */
+typedef struct debug_block_st {
+ bfd_vma begin_addr; /* where did it start */
+ bfd_vma end_addr; /* where did it end */
+ struct debug_block_st* parent;
+ struct debug_block_st* childs;
+ int childs_count;
+} debug_block_t;
+
+/*
+ * Function parameter.
+ */
+typedef struct {
+ bfd_vma offset; /* Offset in the stack */
+ const char* name; /* And name. */
+} debug_parameter_t;
+
+/*
+ * Extra information about functions.
+ */
+typedef struct {
+ asymbol* symbol; /* mangled function name, addr */
+ debug_lineno_t* lines;
+ int lines_count;
+ int max_lines_count;
+ const char* name;
+ const char* filename;/* a file name it occured in... */
+ debug_block_t* block; /* each function has a block, or not, you know */
+ debug_parameter_t* argv; /* argument types. */
+ int argc;
+ int max_argc;
+} debug_function_t;
+
+/* This is the structure we use as a handle for these routines. */
+struct pr_handle
+{
+ /* File to print information to. */
+ FILE *f;
+ /* Current indentation level. */
+ unsigned int indent;
+ /* Type stack. */
+ struct pr_stack *stack;
+ /* Parameter number we are about to output. */
+ int parameter;
+ debug_block_t* block; /* current block */
+ debug_function_t* function; /* current function */
+ debug_function_t* functions; /* all functions */
+ int functions_size; /* current size */
+ int functions_maxsize; /* maximum size */
+};
+
+/* The type stack. */
+
+struct pr_stack
+{
+ /* Next element on the stack. */
+ struct pr_stack *next;
+ /* This element. */
+ char *type;
+ /* Current visibility of fields if this is a class. */
+ enum debug_visibility visibility;
+ /* Name of the current method we are handling. */
+ const char *method;
+};
+
+static void indent PARAMS ((struct pr_handle *));
+static boolean push_type PARAMS ((struct pr_handle *, const char *));
+static boolean prepend_type PARAMS ((struct pr_handle *, const char *));
+static boolean append_type PARAMS ((struct pr_handle *, const char *));
+static boolean substitute_type PARAMS ((struct pr_handle *, const char *));
+static boolean indent_type PARAMS ((struct pr_handle *));
+static char *pop_type PARAMS ((struct pr_handle *));
+static void print_vma PARAMS ((bfd_vma, char *, boolean, boolean));
+static boolean pr_fix_visibility
+ PARAMS ((struct pr_handle *, enum debug_visibility));
+
+static boolean pr_start_compilation_unit PARAMS ((PTR, const char *));
+static boolean pr_start_source PARAMS ((PTR, const char *));
+static boolean pr_empty_type PARAMS ((PTR));
+static boolean pr_void_type PARAMS ((PTR));
+static boolean pr_int_type PARAMS ((PTR, unsigned int, boolean));
+static boolean pr_float_type PARAMS ((PTR, unsigned int));
+static boolean pr_complex_type PARAMS ((PTR, unsigned int));
+static boolean pr_bool_type PARAMS ((PTR, unsigned int));
+static boolean pr_enum_type
+ PARAMS ((PTR, const char *, const char **, bfd_signed_vma *));
+static boolean pr_pointer_type PARAMS ((PTR));
+static boolean pr_function_type PARAMS ((PTR, int, boolean));
+static boolean pr_reference_type PARAMS ((PTR));
+static boolean pr_range_type PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma));
+static boolean pr_array_type
+ PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma, boolean));
+static boolean pr_set_type PARAMS ((PTR, boolean));
+static boolean pr_offset_type PARAMS ((PTR));
+static boolean pr_method_type PARAMS ((PTR, boolean, int, boolean));
+static boolean pr_const_type PARAMS ((PTR));
+static boolean pr_volatile_type PARAMS ((PTR));
+static boolean pr_start_struct_type
+ PARAMS ((PTR, const char *, unsigned int, boolean, unsigned int));
+static boolean pr_struct_field
+ PARAMS ((PTR, const char *, bfd_vma, bfd_vma, enum debug_visibility));
+static boolean pr_end_struct_type PARAMS ((PTR));
+static boolean pr_start_class_type
+ PARAMS ((PTR, const char *, unsigned int, boolean, unsigned int, boolean,
+ boolean));
+static boolean pr_class_static_member
+ PARAMS ((PTR, const char *, const char *, enum debug_visibility));
+static boolean pr_class_baseclass
+ PARAMS ((PTR, bfd_vma, boolean, enum debug_visibility));
+static boolean pr_class_start_method PARAMS ((PTR, const char *));
+static boolean pr_class_method_variant
+ PARAMS ((PTR, const char *, enum debug_visibility, boolean, boolean,
+ bfd_vma, boolean));
+static boolean pr_class_static_method_variant
+ PARAMS ((PTR, const char *, enum debug_visibility, boolean, boolean));
+static boolean pr_class_end_method PARAMS ((PTR));
+static boolean pr_end_class_type PARAMS ((PTR));
+static boolean pr_typedef_type PARAMS ((PTR, const char *));
+static boolean pr_tag_type
+ PARAMS ((PTR, const char *, unsigned int, enum debug_type_kind));
+static boolean pr_typdef PARAMS ((PTR, const char *));
+static boolean pr_tag PARAMS ((PTR, const char *));
+static boolean pr_int_constant PARAMS ((PTR, const char *, bfd_vma));
+static boolean pr_float_constant PARAMS ((PTR, const char *, double));
+static boolean pr_typed_constant PARAMS ((PTR, const char *, bfd_vma));
+static boolean pr_variable
+ PARAMS ((PTR, const char *, enum debug_var_kind, bfd_vma));
+static boolean pr_start_function PARAMS ((PTR, const char *, boolean));
+static boolean pr_function_parameter
+ PARAMS ((PTR, const char *, enum debug_parm_kind, bfd_vma));
+static boolean pr_start_block PARAMS ((PTR, bfd_vma));
+static boolean pr_end_block PARAMS ((PTR, bfd_vma));
+static boolean pr_end_function PARAMS ((PTR));
+static boolean pr_lineno PARAMS ((PTR, const char *, unsigned long, bfd_vma));
+
+static const struct debug_write_fns pr_fns =
+{
+ pr_start_compilation_unit,
+ pr_start_source,
+ pr_empty_type,
+ pr_void_type,
+ pr_int_type,
+ pr_float_type,
+ pr_complex_type,
+ pr_bool_type,
+ pr_enum_type,
+ pr_pointer_type,
+ pr_function_type,
+ pr_reference_type,
+ pr_range_type,
+ pr_array_type,
+ pr_set_type,
+ pr_offset_type,
+ pr_method_type,
+ pr_const_type,
+ pr_volatile_type,
+ pr_start_struct_type,
+ pr_struct_field,
+ pr_end_struct_type,
+ pr_start_class_type,
+ pr_class_static_member,
+ pr_class_baseclass,
+ pr_class_start_method,
+ pr_class_method_variant,
+ pr_class_static_method_variant,
+ pr_class_end_method,
+ pr_end_class_type,
+ pr_typedef_type,
+ pr_tag_type,
+ pr_typdef,
+ pr_tag,
+ pr_int_constant,
+ pr_float_constant,
+ pr_typed_constant,
+ pr_variable,
+ pr_start_function,
+ pr_function_parameter,
+ pr_start_block,
+ pr_end_block,
+ pr_end_function,
+ pr_lineno
+};
+
+
+/* Indent to the current indentation level. */
+
+static void
+indent (info)
+ struct pr_handle *info;
+{
+ unsigned int i;
+
+ for (i = 0; i < info->indent; i++)
+ TRACE_PUTC ((' ', info->f));
+}
+
+/* Push a type on the type stack. */
+
+static boolean
+push_type (info, type)
+ struct pr_handle *info;
+ const char *type;
+{
+ struct pr_stack *n;
+
+ if (type == NULL)
+ return false;
+
+ n = (struct pr_stack *) xmalloc (sizeof *n);
+ memset (n, 0, sizeof *n);
+
+ n->type = xstrdup (type);
+ n->visibility = DEBUG_VISIBILITY_IGNORE;
+ n->method = NULL;
+ n->next = info->stack;
+ info->stack = n;
+
+ return true;
+}
+
+/* Prepend a string onto the type on the top of the type stack. */
+
+static boolean
+prepend_type (info, s)
+ struct pr_handle *info;
+ const char *s;
+{
+ char *n;
+
+ assert (info->stack != NULL);
+
+ n = (char *) xmalloc (strlen (s) + strlen (info->stack->type) + 1);
+ sprintf (n, "%s%s", s, info->stack->type);
+ free (info->stack->type);
+ info->stack->type = n;
+
+ return true;
+}
+
+/* Append a string to the type on the top of the type stack. */
+
+static boolean
+append_type (info, s)
+ struct pr_handle *info;
+ const char *s;
+{
+ unsigned int len;
+
+ if (s == NULL)
+ return false;
+
+ assert (info->stack != NULL);
+
+ len = strlen (info->stack->type);
+ info->stack->type = (char *) xrealloc (info->stack->type,
+ len + strlen (s) + 1);
+ strcpy (info->stack->type + len, s);
+
+ return true;
+}
+
+/* We use an underscore to indicate where the name should go in a type
+ string. This function substitutes a string for the underscore. If
+ there is no underscore, the name follows the type. */
+
+static boolean
+substitute_type (info, s)
+ struct pr_handle *info;
+ const char *s;
+{
+ char *u;
+
+ assert (info->stack != NULL);
+
+ u = strchr (info->stack->type, '|');
+ if (u != NULL)
+ {
+ char *n;
+
+ n = (char *) xmalloc (strlen (info->stack->type) + strlen (s));
+
+ memcpy (n, info->stack->type, u - info->stack->type);
+ strcpy (n + (u - info->stack->type), s);
+ strcat (n, u + 1);
+
+ free (info->stack->type);
+ info->stack->type = n;
+
+ return true;
+ }
+
+ if (strchr (s, '|') != NULL
+ && (strchr (info->stack->type, '{') != NULL
+ || strchr (info->stack->type, '(') != NULL))
+ {
+ if (! prepend_type (info, "(")
+ || ! append_type (info, ")"))
+ return false;
+ }
+
+ if (*s == '\0')
+ return true;
+
+ return (append_type (info, " ")
+ && append_type (info, s));
+}
+
+/* Indent the type at the top of the stack by appending spaces. */
+
+static boolean
+indent_type (info)
+ struct pr_handle *info;
+{
+ unsigned int i;
+
+ for (i = 0; i < info->indent; i++)
+ {
+ if (! append_type (info, " "))
+ return false;
+ }
+
+ return true;
+}
+
+/* Pop a type from the type stack. */
+
+static char *
+pop_type (info)
+ struct pr_handle *info;
+{
+ struct pr_stack *o;
+ char *ret;
+
+ assert (info->stack != NULL);
+
+ o = info->stack;
+ info->stack = o->next;
+ ret = o->type;
+ free (o);
+
+ return ret;
+}
+
+/* Print a VMA value into a string. */
+
+static void
+print_vma (vma, buf, unsignedp, hexp)
+ bfd_vma vma;
+ char *buf;
+ boolean unsignedp;
+ boolean hexp;
+{
+ if (sizeof (vma) <= sizeof (unsigned long))
+ {
+ if (hexp)
+ sprintf (buf, "0x%lx", (unsigned long) vma);
+ else if (unsignedp)
+ sprintf (buf, "%lu", (unsigned long) vma);
+ else
+ sprintf (buf, "%ld", (long) vma);
+ }
+ else
+ {
+ buf[0] = '0';
+ buf[1] = 'x';
+ sprintf_vma (buf + 2, vma);
+ }
+}
+
+/* Start a new compilation unit. */
+
+static boolean
+pr_start_compilation_unit (p, filename)
+ PTR p;
+ const char *filename;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ assert (info->indent == 0);
+/*
+ TRACE_FPRINTF( (info->f, "%s:\n", filename));
+*/
+ return true;
+}
+
+/* Start a source file within a compilation unit. */
+
+static boolean
+pr_start_source (p, filename)
+ PTR p;
+ const char *filename;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ assert (info->indent == 0);
+/*
+ TRACE_FPRINTF( (info->f, " %s:\n", filename));
+*/
+ return true;
+}
+
+/* Push an empty type onto the type stack. */
+
+static boolean
+pr_empty_type (p)
+ PTR p;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ return push_type (info, "<undefined>");
+}
+
+/* Push a void type onto the type stack. */
+
+static boolean
+pr_void_type (p)
+ PTR p;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ return push_type (info, "void");
+}
+
+/* Push an integer type onto the type stack. */
+
+static boolean
+pr_int_type (p, size, unsignedp)
+ PTR p;
+ unsigned int size;
+ boolean unsignedp;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char ab[10];
+
+ sprintf (ab, "%sint%d", unsignedp ? "u" : "", size * 8);
+ return push_type (info, ab);
+}
+
+/* Push a floating type onto the type stack. */
+
+static boolean
+pr_float_type (p, size)
+ PTR p;
+ unsigned int size;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char ab[10];
+
+ if (size == 4)
+ return push_type (info, "float");
+ else if (size == 8)
+ return push_type (info, "double");
+
+ sprintf (ab, "float%d", size * 8);
+ return push_type (info, ab);
+}
+
+/* Push a complex type onto the type stack. */
+
+static boolean
+pr_complex_type (p, size)
+ PTR p;
+ unsigned int size;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ if (! pr_float_type (p, size))
+ return false;
+
+ return prepend_type (info, "complex ");
+}
+
+/* Push a boolean type onto the type stack. */
+
+static boolean
+pr_bool_type (p, size)
+ PTR p;
+ unsigned int size;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char ab[10];
+
+ sprintf (ab, "bool%d", size * 8);
+
+ return push_type (info, ab);
+}
+
+/* Push an enum type onto the type stack. */
+
+static boolean
+pr_enum_type (p, tag, names, values)
+ PTR p;
+ const char *tag;
+ const char **names;
+ bfd_signed_vma *values;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ unsigned int i;
+ bfd_signed_vma val;
+
+ if (! push_type (info, "enum "))
+ return false;
+ if (tag != NULL)
+ {
+ if (! append_type (info, tag)
+ || ! append_type (info, " "))
+ return false;
+ }
+ if (! append_type (info, "{ "))
+ return false;
+
+ if (names == NULL)
+ {
+ if (! append_type (info, "/* undefined */"))
+ return false;
+ }
+ else
+ {
+ val = 0;
+ for (i = 0; names[i] != NULL; i++)
+ {
+ if (i > 0)
+ {
+ if (! append_type (info, ", "))
+ return false;
+ }
+
+ if (! append_type (info, names[i]))
+ return false;
+
+ if (values[i] != val)
+ {
+ char ab[20];
+
+ print_vma (values[i], ab, false, false);
+ if (! append_type (info, " = ")
+ || ! append_type (info, ab))
+ return false;
+ val = values[i];
+ }
+
+ ++val;
+ }
+ }
+
+ return append_type (info, " }");
+}
+
+/* Turn the top type on the stack into a pointer. */
+
+static boolean
+pr_pointer_type (p)
+ PTR p;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *s;
+
+ assert (info->stack != NULL);
+
+ s = strchr (info->stack->type, '|');
+ if (s != NULL && s[1] == '[')
+ return substitute_type (info, "(*|)");
+ return substitute_type (info, "*|");
+}
+
+/* Turn the top type on the stack into a function returning that type. */
+
+static boolean
+pr_function_type (p, argcount, varargs)
+ PTR p;
+ int argcount;
+ boolean varargs;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char **arg_types;
+ unsigned int len;
+ char *s;
+
+ assert (info->stack != NULL);
+
+ len = 10;
+
+ if (argcount <= 0)
+ {
+ arg_types = NULL;
+ len += 15;
+ }
+ else
+ {
+ int i;
+
+ arg_types = (char **) xmalloc (argcount * sizeof *arg_types);
+ for (i = argcount - 1; i >= 0; i--)
+ {
+ if (! substitute_type (info, ""))
+ return false;
+ arg_types[i] = pop_type (info);
+ if (arg_types[i] == NULL)
+ return false;
+ len += strlen (arg_types[i]) + 2;
+ }
+ if (varargs)
+ len += 5;
+ }
+
+ /* Now the return type is on the top of the stack. */
+
+ s = (char *) xmalloc (len);
+ strcpy (s, "(|) (");
+
+ if (argcount < 0)
+ {
+#if 0
+ /* Turn off unknown arguments. */
+ strcat (s, "/* unknown */");
+#endif
+ }
+ else
+ {
+ int i;
+
+ for (i = 0; i < argcount; i++)
+ {
+ if (i > 0)
+ strcat (s, ", ");
+ strcat (s, arg_types[i]);
+ }
+ if (varargs)
+ {
+ if (i > 0)
+ strcat (s, ", ");
+ strcat (s, "...");
+ }
+ if (argcount > 0)
+ free (arg_types);
+ }
+
+ strcat (s, ")");
+
+ if (! substitute_type (info, s))
+ return false;
+
+ free (s);
+
+ return true;
+}
+
+/* Turn the top type on the stack into a reference to that type. */
+
+static boolean
+pr_reference_type (p)
+ PTR p;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ assert (info->stack != NULL);
+
+ return substitute_type (info, "&|");
+}
+
+/* Make a range type. */
+
+static boolean
+pr_range_type (p, lower, upper)
+ PTR p;
+ bfd_signed_vma lower;
+ bfd_signed_vma upper;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char abl[20], abu[20];
+
+ assert (info->stack != NULL);
+
+ if (! substitute_type (info, ""))
+ return false;
+
+ print_vma (lower, abl, false, false);
+ print_vma (upper, abu, false, false);
+
+ return (prepend_type (info, "range (")
+ && append_type (info, "):")
+ && append_type (info, abl)
+ && append_type (info, ":")
+ && append_type (info, abu));
+}
+
+/* Make an array type. */
+
+/*ARGSUSED*/
+static boolean
+pr_array_type (p, lower, upper, stringp)
+ PTR p;
+ bfd_signed_vma lower;
+ bfd_signed_vma upper;
+ boolean stringp;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *range_type;
+ char abl[20], abu[20], ab[50];
+
+ range_type = pop_type (info);
+ if (range_type == NULL)
+ return false;
+
+ if (lower == 0)
+ {
+ if (upper == -1)
+ sprintf (ab, "|[]");
+ else
+ {
+ print_vma (upper + 1, abu, false, false);
+ sprintf (ab, "|[%s]", abu);
+ }
+ }
+ else
+ {
+ print_vma (lower, abl, false, false);
+ print_vma (upper, abu, false, false);
+ sprintf (ab, "|[%s:%s]", abl, abu);
+ }
+
+ if (! substitute_type (info, ab))
+ return false;
+
+ if (strcmp (range_type, "int") != 0)
+ {
+ if (! append_type (info, ":")
+ || ! append_type (info, range_type))
+ return false;
+ }
+
+ if (stringp)
+ {
+ if (! append_type (info, " /* string */"))
+ return false;
+ }
+
+ return true;
+}
+
+/* Make a set type. */
+
+/*ARGSUSED*/
+static boolean
+pr_set_type (p, bitstringp)
+ PTR p;
+ boolean bitstringp;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ if (! substitute_type (info, ""))
+ return false;
+
+ if (! prepend_type (info, "set { ")
+ || ! append_type (info, " }"))
+ return false;
+
+ if (bitstringp)
+ {
+ if (! append_type (info, "/* bitstring */"))
+ return false;
+ }
+
+ return true;
+}
+
+/* Make an offset type. */
+
+static boolean
+pr_offset_type (p)
+ PTR p;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *t;
+
+ if (! substitute_type (info, ""))
+ return false;
+
+ t = pop_type (info);
+ if (t == NULL)
+ return false;
+
+ return (substitute_type (info, "")
+ && prepend_type (info, " ")
+ && prepend_type (info, t)
+ && append_type (info, "::|"));
+}
+
+/* Make a method type. */
+
+static boolean
+pr_method_type (p, domain, argcount, varargs)
+ PTR p;
+ boolean domain;
+ int argcount;
+ boolean varargs;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ unsigned int len;
+ char *domain_type;
+ char **arg_types;
+ char *s;
+
+ len = 10;
+
+ if (! domain)
+ domain_type = NULL;
+ else
+ {
+ if (! substitute_type (info, ""))
+ return false;
+ domain_type = pop_type (info);
+ if (domain_type == NULL)
+ return false;
+ if (strncmp (domain_type, "class ", sizeof "class " - 1) == 0
+ && strchr (domain_type + sizeof "class " - 1, ' ') == NULL)
+ domain_type += sizeof "class " - 1;
+ else if (strncmp (domain_type, "union class ",
+ sizeof "union class ") == 0
+ && (strchr (domain_type + sizeof "union class " - 1, ' ')
+ == NULL))
+ domain_type += sizeof "union class " - 1;
+ len += strlen (domain_type);
+ }
+
+ if (argcount <= 0)
+ {
+ arg_types = NULL;
+ len += 15;
+ }
+ else
+ {
+ int i;
+
+ arg_types = (char **) xmalloc (argcount * sizeof *arg_types);
+ for (i = argcount - 1; i >= 0; i--)
+ {
+ if (! substitute_type (info, ""))
+ return false;
+ arg_types[i] = pop_type (info);
+ if (arg_types[i] == NULL)
+ return false;
+ len += strlen (arg_types[i]) + 2;
+ }
+ if (varargs)
+ len += 5;
+ }
+
+ /* Now the return type is on the top of the stack. */
+
+ s = (char *) xmalloc (len);
+ if (! domain)
+ *s = '\0';
+ else
+ strcpy (s, domain_type);
+ strcat (s, "::| (");
+
+ if (argcount < 0)
+ strcat (s, "/* unknown */");
+ else
+ {
+ int i;
+
+ for (i = 0; i < argcount; i++)
+ {
+ if (i > 0)
+ strcat (s, ", ");
+ strcat (s, arg_types[i]);
+ }
+ if (varargs)
+ {
+ if (i > 0)
+ strcat (s, ", ");
+ strcat (s, "...");
+ }
+ if (argcount > 0)
+ free (arg_types);
+ }
+
+ strcat (s, ")");
+
+ if (! substitute_type (info, s))
+ return false;
+
+ free (s);
+
+ return true;
+}
+
+/* Make a const qualified type. */
+
+static boolean
+pr_const_type (p)
+ PTR p;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ return substitute_type (info, "const |");
+}
+
+/* Make a volatile qualified type. */
+
+static boolean
+pr_volatile_type (p)
+ PTR p;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ return substitute_type (info, "volatile |");
+}
+
+/* Start accumulating a struct type. */
+
+static boolean
+pr_start_struct_type (p, tag, id, structp, size)
+ PTR p;
+ const char *tag;
+ unsigned int id;
+ boolean structp;
+ unsigned int size;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ info->indent += 2;
+
+ if (! push_type (info, structp ? "struct " : "union "))
+ return false;
+ if (tag != NULL)
+ {
+ if (! append_type (info, tag))
+ return false;
+ }
+ else
+ {
+ char idbuf[20];
+
+ sprintf (idbuf, "%%anon%u", id);
+ if (! append_type (info, idbuf))
+ return false;
+ }
+
+ if (! append_type (info, " {"))
+ return false;
+ if (size != 0 || tag != NULL)
+ {
+ char ab[30];
+
+ if (! append_type (info, " /*"))
+ return false;
+
+ if (size != 0)
+ {
+ sprintf (ab, " size %u", size);
+ if (! append_type (info, ab))
+ return false;
+ }
+ if (tag != NULL)
+ {
+ sprintf (ab, " id %u", id);
+ if (! append_type (info, ab))
+ return false;
+ }
+ if (! append_type (info, " */"))
+ return false;
+ }
+ if (! append_type (info, "\n"))
+ return false;
+
+ info->stack->visibility = DEBUG_VISIBILITY_PUBLIC;
+
+ return indent_type (info);
+}
+
+/* Output the visibility of a field in a struct. */
+
+static boolean
+pr_fix_visibility (info, visibility)
+ struct pr_handle *info;
+ enum debug_visibility visibility;
+{
+ const char *s;
+ char *t;
+ unsigned int len;
+
+ assert (info->stack != NULL);
+
+ if (info->stack->visibility == visibility)
+ return true;
+
+ assert (info->stack->visibility != DEBUG_VISIBILITY_IGNORE);
+
+ switch (visibility)
+ {
+ case DEBUG_VISIBILITY_PUBLIC:
+ s = "public";
+ break;
+ case DEBUG_VISIBILITY_PRIVATE:
+ s = "private";
+ break;
+ case DEBUG_VISIBILITY_PROTECTED:
+ s = "protected";
+ break;
+ case DEBUG_VISIBILITY_IGNORE:
+ s = "/* ignore */";
+ break;
+ default:
+ abort ();
+ return false;
+ }
+
+ /* Trim off a trailing space in the struct string, to make the
+ output look a bit better, then stick on the visibility string. */
+
+ t = info->stack->type;
+ len = strlen (t);
+ assert (t[len - 1] == ' ');
+ t[len - 1] = '\0';
+
+ if (! append_type (info, s)
+ || ! append_type (info, ":\n")
+ || ! indent_type (info))
+ return false;
+
+ info->stack->visibility = visibility;
+
+ return true;
+}
+
+/* Add a field to a struct type. */
+
+static boolean
+pr_struct_field (p, name, bitpos, bitsize, visibility)
+ PTR p;
+ const char *name;
+ bfd_vma bitpos;
+ bfd_vma bitsize;
+ enum debug_visibility visibility;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char ab[20];
+ char *t;
+
+ if (! substitute_type (info, name))
+ return false;
+
+ if (! append_type (info, "; /* "))
+ return false;
+
+ if (bitsize != 0)
+ {
+ print_vma (bitsize, ab, true, false);
+ if (! append_type (info, "bitsize ")
+ || ! append_type (info, ab)
+ || ! append_type (info, ", "))
+ return false;
+ }
+
+ print_vma (bitpos, ab, true, false);
+ if (! append_type (info, "bitpos ")
+ || ! append_type (info, ab)
+ || ! append_type (info, " */\n")
+ || ! indent_type (info))
+ return false;
+
+ t = pop_type (info);
+ if (t == NULL)
+ return false;
+
+ if (! pr_fix_visibility (info, visibility))
+ return false;
+
+ return append_type (info, t);
+}
+
+/* Finish a struct type. */
+
+static boolean
+pr_end_struct_type (p)
+ PTR p;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *s;
+
+ assert (info->stack != NULL);
+ assert (info->indent >= 2);
+
+ info->indent -= 2;
+
+ /* Change the trailing indentation to have a close brace. */
+ s = info->stack->type + strlen (info->stack->type) - 2;
+ assert (s[0] == ' ' && s[1] == ' ' && s[2] == '\0');
+
+ *s++ = '}';
+ *s = '\0';
+
+ return true;
+}
+
+/* Start a class type. */
+
+static boolean
+pr_start_class_type (p, tag, id, structp, size, vptr, ownvptr)
+ PTR p;
+ const char *tag;
+ unsigned int id;
+ boolean structp;
+ unsigned int size;
+ boolean vptr;
+ boolean ownvptr;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *tv = NULL;
+
+ info->indent += 2;
+
+ if (vptr && ! ownvptr)
+ {
+ tv = pop_type (info);
+ if (tv == NULL)
+ return false;
+ }
+
+ if (! push_type (info, structp ? "class " : "union class "))
+ return false;
+ if (tag != NULL)
+ {
+ if (! append_type (info, tag))
+ return false;
+ }
+ else
+ {
+ char idbuf[20];
+
+ sprintf (idbuf, "%%anon%u", id);
+ if (! append_type (info, idbuf))
+ return false;
+ }
+
+ if (! append_type (info, " {"))
+ return false;
+ if (size != 0 || vptr || ownvptr || tag != NULL)
+ {
+ if (! append_type (info, " /*"))
+ return false;
+
+ if (size != 0)
+ {
+ char ab[20];
+
+ sprintf (ab, "%u", size);
+ if (! append_type (info, " size ")
+ || ! append_type (info, ab))
+ return false;
+ }
+
+ if (vptr)
+ {
+ if (! append_type (info, " vtable "))
+ return false;
+ if (ownvptr)
+ {
+ if (! append_type (info, "self "))
+ return false;
+ }
+ else
+ {
+ if (! append_type (info, tv)
+ || ! append_type (info, " "))
+ return false;
+ }
+ }
+
+ if (tag != NULL)
+ {
+ char ab[30];
+
+ sprintf (ab, " id %u", id);
+ if (! append_type (info, ab))
+ return false;
+ }
+
+ if (! append_type (info, " */"))
+ return false;
+ }
+
+ info->stack->visibility = DEBUG_VISIBILITY_PRIVATE;
+
+ return (append_type (info, "\n")
+ && indent_type (info));
+}
+
+/* Add a static member to a class. */
+
+static boolean
+pr_class_static_member (p, name, physname, visibility)
+ PTR p;
+ const char *name;
+ const char *physname;
+ enum debug_visibility visibility;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *t;
+
+ if (! substitute_type (info, name))
+ return false;
+
+ if (! prepend_type (info, "static ")
+ || ! append_type (info, "; /* ")
+ || ! append_type (info, physname)
+ || ! append_type (info, " */\n")
+ || ! indent_type (info))
+ return false;
+
+ t = pop_type (info);
+ if (t == NULL)
+ return false;
+
+ if (! pr_fix_visibility (info, visibility))
+ return false;
+
+ return append_type (info, t);
+}
+
+/* Add a base class to a class. */
+
+static boolean
+pr_class_baseclass (p, bitpos, virtual, visibility)
+ PTR p;
+ bfd_vma bitpos;
+ boolean virtual;
+ enum debug_visibility visibility;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *t;
+ const char *prefix;
+ char ab[20];
+ char *s, *l, *n;
+
+ assert (info->stack != NULL && info->stack->next != NULL);
+
+ if (! substitute_type (info, ""))
+ return false;
+
+ t = pop_type (info);
+ if (t == NULL)
+ return false;
+
+ if (strncmp (t, "class ", sizeof "class " - 1) == 0)
+ t += sizeof "class " - 1;
+
+ /* Push it back on to take advantage of the prepend_type and
+ append_type routines. */
+ if (! push_type (info, t))
+ return false;
+
+ if (virtual)
+ {
+ if (! prepend_type (info, "virtual "))
+ return false;
+ }
+
+ switch (visibility)
+ {
+ case DEBUG_VISIBILITY_PUBLIC:
+ prefix = "public ";
+ break;
+ case DEBUG_VISIBILITY_PROTECTED:
+ prefix = "protected ";
+ break;
+ case DEBUG_VISIBILITY_PRIVATE:
+ prefix = "private ";
+ break;
+ default:
+ prefix = "/* unknown visibility */ ";
+ break;
+ }
+
+ if (! prepend_type (info, prefix))
+ return false;
+
+ if (bitpos != 0)
+ {
+ print_vma (bitpos, ab, true, false);
+ if (! append_type (info, " /* bitpos ")
+ || ! append_type (info, ab)
+ || ! append_type (info, " */"))
+ return false;
+ }
+
+ /* Now the top of the stack is something like "public A / * bitpos
+ 10 * /". The next element on the stack is something like "class
+ xx { / * size 8 * /\n...". We want to substitute the top of the
+ stack in before the {. */
+ s = strchr (info->stack->next->type, '{');
+ assert (s != NULL);
+ --s;
+
+ /* If there is already a ':', then we already have a baseclass, and
+ we must append this one after a comma. */
+ for (l = info->stack->next->type; l != s; l++)
+ if (*l == ':')
+ break;
+ if (! prepend_type (info, l == s ? " : " : ", "))
+ return false;
+
+ t = pop_type (info);
+ if (t == NULL)
+ return false;
+
+ n = (char *) xmalloc (strlen (info->stack->type) + strlen (t) + 1);
+ memcpy (n, info->stack->type, s - info->stack->type);
+ strcpy (n + (s - info->stack->type), t);
+ strcat (n, s);
+
+ free (info->stack->type);
+ info->stack->type = n;
+
+ free (t);
+
+ return true;
+}
+
+/* Start adding a method to a class. */
+
+static boolean
+pr_class_start_method (p, name)
+ PTR p;
+ const char *name;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ assert (info->stack != NULL);
+ info->stack->method = name;
+ return true;
+}
+
+/* Add a variant to a method. */
+
+static boolean
+pr_class_method_variant (p, physname, visibility, constp, volatilep, voffset,
+ context)
+ PTR p;
+ const char *physname;
+ enum debug_visibility visibility;
+ boolean constp;
+ boolean volatilep;
+ bfd_vma voffset;
+ boolean context;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *method_type;
+ char *context_type;
+
+ assert (info->stack != NULL);
+ assert (info->stack->next != NULL);
+
+ /* Put the const and volatile qualifiers on the type. */
+ if (volatilep)
+ {
+ if (! append_type (info, " volatile"))
+ return false;
+ }
+ if (constp)
+ {
+ if (! append_type (info, " const"))
+ return false;
+ }
+
+ /* Stick the name of the method into its type. */
+ if (! substitute_type (info,
+ (context
+ ? info->stack->next->next->method
+ : info->stack->next->method)))
+ return false;
+
+ /* Get the type. */
+ method_type = pop_type (info);
+ if (method_type == NULL)
+ return false;
+
+ /* Pull off the context type if there is one. */
+ if (! context)
+ context_type = NULL;
+ else
+ {
+ context_type = pop_type (info);
+ if (context_type == NULL)
+ return false;
+ }
+
+ /* Now the top of the stack is the class. */
+
+ if (! pr_fix_visibility (info, visibility))
+ return false;
+
+ if (! append_type (info, method_type)
+ || ! append_type (info, " /* ")
+ || ! append_type (info, physname)
+ || ! append_type (info, " "))
+ return false;
+ if (context || voffset != 0)
+ {
+ char ab[20];
+
+ if (context)
+ {
+ if (! append_type (info, "context ")
+ || ! append_type (info, context_type)
+ || ! append_type (info, " "))
+ return false;
+ }
+ print_vma (voffset, ab, true, false);
+ if (! append_type (info, "voffset ")
+ || ! append_type (info, ab))
+ return false;
+ }
+
+ return (append_type (info, " */;\n")
+ && indent_type (info));
+}
+
+/* Add a static variant to a method. */
+
+static boolean
+pr_class_static_method_variant (p, physname, visibility, constp, volatilep)
+ PTR p;
+ const char *physname;
+ enum debug_visibility visibility;
+ boolean constp;
+ boolean volatilep;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *method_type;
+
+ assert (info->stack != NULL);
+ assert (info->stack->next != NULL);
+ assert (info->stack->next->method != NULL);
+
+ /* Put the const and volatile qualifiers on the type. */
+ if (volatilep)
+ {
+ if (! append_type (info, " volatile"))
+ return false;
+ }
+ if (constp)
+ {
+ if (! append_type (info, " const"))
+ return false;
+ }
+
+ /* Mark it as static. */
+ if (! prepend_type (info, "static "))
+ return false;
+
+ /* Stick the name of the method into its type. */
+ if (! substitute_type (info, info->stack->next->method))
+ return false;
+
+ /* Get the type. */
+ method_type = pop_type (info);
+ if (method_type == NULL)
+ return false;
+
+ /* Now the top of the stack is the class. */
+
+ if (! pr_fix_visibility (info, visibility))
+ return false;
+
+ return (append_type (info, method_type)
+ && append_type (info, " /* ")
+ && append_type (info, physname)
+ && append_type (info, " */;\n")
+ && indent_type (info));
+}
+
+/* Finish up a method. */
+
+static boolean
+pr_class_end_method (p)
+ PTR p;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ info->stack->method = NULL;
+ return true;
+}
+
+/* Finish up a class. */
+
+static boolean
+pr_end_class_type (p)
+ PTR p;
+{
+ return pr_end_struct_type (p);
+}
+
+/* Push a type on the stack using a typedef name. */
+
+static boolean
+pr_typedef_type (p, name)
+ PTR p;
+ const char *name;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ return push_type (info, name);
+}
+
+/* Push a type on the stack using a tag name. */
+
+static boolean
+pr_tag_type (p, name, id, kind)
+ PTR p;
+ const char *name;
+ unsigned int id;
+ enum debug_type_kind kind;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ const char *t, *tag;
+ char idbuf[20];
+
+ switch (kind)
+ {
+ case DEBUG_KIND_STRUCT:
+ t = "struct ";
+ break;
+ case DEBUG_KIND_UNION:
+ t = "union ";
+ break;
+ case DEBUG_KIND_ENUM:
+ t = "enum ";
+ break;
+ case DEBUG_KIND_CLASS:
+ t = "class ";
+ break;
+ case DEBUG_KIND_UNION_CLASS:
+ t = "union class ";
+ break;
+ default:
+ abort ();
+ return false;
+ }
+
+ if (! push_type (info, t))
+ return false;
+ if (name != NULL)
+ tag = name;
+ else
+ {
+ sprintf (idbuf, "%%anon%u", id);
+ tag = idbuf;
+ }
+
+ if (! append_type (info, tag))
+ return false;
+ if (name != NULL && kind != DEBUG_KIND_ENUM)
+ {
+ sprintf (idbuf, " /* id %u */", id);
+ if (! append_type (info, idbuf))
+ return false;
+ }
+
+ return true;
+}
+
+/* Output a typedef. */
+
+static boolean
+pr_typdef (p, name)
+ PTR p;
+ const char *name;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *s;
+
+ if (! substitute_type (info, name))
+ return false;
+
+ s = pop_type (info);
+ if (s == NULL)
+ return false;
+/*
+ indent (info);
+ TRACE_FPRINTF( (info->f, "typedef %s;\n", s));
+*/
+ free (s);
+
+ return true;
+}
+
+/* Output a tag. The tag should already be in the string on the
+ stack, so all we have to do here is print it out. */
+
+/*ARGSUSED*/
+static boolean
+pr_tag (p, name)
+ PTR p;
+ const char *name;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *t;
+
+ t = pop_type (info);
+ if (t == NULL)
+ return false;
+/*
+ indent (info);
+ TRACE_FPRINTF( (info->f, "%s;\n", t));
+*/
+ free (t);
+
+ return true;
+}
+
+/* Output an integer constant. */
+
+static boolean
+pr_int_constant (p, name, val)
+ PTR p;
+ const char *name;
+ bfd_vma val;
+{
+/*
+ struct pr_handle *info = (struct pr_handle *) p;
+ char ab[20];
+ indent (info);
+ print_vma (val, ab, false, false);
+ TRACE_FPRINTF( (info->f, "const int %s = %s;\n", name, ab));
+ */
+ return true;
+}
+
+/* Output a floating point constant. */
+
+static boolean
+pr_float_constant (p, name, val)
+ PTR p;
+ const char *name;
+ double val;
+{
+/*
+ struct pr_handle *info = (struct pr_handle *) p;
+ indent (info);
+ TRACE_FPRINTF( (info->f, "const double %s = %g;\n", name, val));
+ */
+ return true;
+}
+
+/* Output a typed constant. */
+
+static boolean
+pr_typed_constant (p, name, val)
+ PTR p;
+ const char *name;
+ bfd_vma val;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *t;
+
+ t = pop_type (info);
+ if (t == NULL)
+ return false;
+/*
+ char ab[20];
+ indent (info);
+ print_vma (val, ab, false, false);
+ TRACE_FPRINTF( (info->f, "const %s %s = %s;\n", t, name, ab));
+*/
+ free (t);
+
+ return true;
+}
+
+/* Output a variable. */
+
+static boolean
+pr_variable (p, name, kind, val)
+ PTR p;
+ const char *name;
+ enum debug_var_kind kind;
+ bfd_vma val;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *t;
+ char ab[20];
+ (void)ab;
+
+ if (! substitute_type (info, name))
+ return false;
+
+ t = pop_type (info);
+ if (t == NULL)
+ return false;
+
+#if 0
+ indent (info);
+ switch (kind)
+ {
+ case DEBUG_STATIC:
+ case DEBUG_LOCAL_STATIC:
+ TRACE_FPRINTF( (info->f, "static "));
+ break;
+ case DEBUG_REGISTER:
+ TRACE_FPRINTF( (info->f, "register "));
+ break;
+ default:
+ break;
+ }
+ print_vma (val, ab, true, true);
+ TRACE_FPRINTF( (info->f, "%s /* %s */;\n", t, ab));
+#else /* 0 */
+#if 0
+ if (kind==DEBUG_STATIC || kind==DEBUG_LOCAL_STATIC) {
+ print_vma (val, ab, true, true);
+ TRACE_FPRINTF( (info->f, "STATIC_VAR: %s /* %s */;\n", t, ab));
+ }
+#endif /* 0 */
+#endif /* !0 */
+
+ free (t);
+
+ return true;
+}
+
+/* Start outputting a function. */
+
+static boolean
+pr_start_function (p, name, global)
+ PTR p;
+ const char *name;
+ boolean global;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *t;
+
+ if (! substitute_type (info, name))
+ return false;
+
+ t = pop_type (info);
+ if (t == NULL)
+ return false;
+
+#if 0
+ indent (info);
+ if (! global)
+ TRACE_FPRINTF( (info->f, "static "));
+ TRACE_FPRINTF( (info->f, "%s (", t));
+ info->parameter = 1;
+#else /* 0 */
+ if (info->functions_size==info->functions_maxsize) {
+ info->functions_maxsize *= 2;
+ info->functions = xrealloc(info->functions,
+ info->functions_maxsize*sizeof(debug_function_t));
+ assert(info->functions!=0);
+ }
+ /* info->functions[info->functions_size] = xmalloc(sizeof(debug_function_t)); */
+ info->function = &info->functions[info->functions_size];
+ ++info->functions_size;
+ info->function->symbol = NULL;
+ info->function->lines = NULL;
+ info->function->lines_count = 0;
+ info->function->max_lines_count = 0;
+ info->function->name = t;
+ info->function->filename = NULL;
+ info->function->block = NULL;
+ info->function->argv = NULL;
+ info->function->argc = 0;
+ info->function->max_argc = 0;
+#endif /* !0 */
+ return true;
+}
+
+/* Output a function parameter. */
+
+static boolean
+pr_function_parameter (p, name, kind, val)
+ PTR p;
+ const char *name;
+ enum debug_parm_kind kind;
+ bfd_vma val;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ debug_function_t* f = info->function;
+ char *t;
+ char ab[20];
+ (void)ab;
+
+ if (kind == DEBUG_PARM_REFERENCE
+ || kind == DEBUG_PARM_REF_REG)
+ {
+ if (! pr_reference_type (p))
+ return false;
+ }
+
+ if (! substitute_type (info, name))
+ return false;
+
+ t = pop_type (info);
+ if (t == NULL)
+ return false;
+
+#if 0
+ if (info->parameter != 1)
+ TRACE_FPRINTF( (info->f, ", "));
+
+ if (kind == DEBUG_PARM_REG || kind == DEBUG_PARM_REF_REG)
+ TRACE_FPRINTF( (info->f, "register "));
+
+ print_vma (val, ab, true, true);
+ TRACE_FPRINTF( (info->f, "%s /* %s */", t, ab));
+ free (t);
+ ++info->parameter;
+#else /* 0 */
+ assert(f!=NULL);
+ if (f->argv==NULL) {
+ f->max_argc = 7; /* rarely anyone has more than that many args... */
+ f->argv = xmalloc(sizeof(debug_parameter_t)*f->max_argc);
+ } else if (f->argc==f->max_argc) {
+ f->max_argc *= 2;
+ f->argv = realloc(f->argv,sizeof(debug_parameter_t)*f->max_argc);
+ }
+ f->argv[f->argc].offset = val;
+ f->argv[f->argc].name = t;
+ ++f->argc;
+#endif /* !0 */
+ return true;
+}
+
+/* Start writing out a block. */
+
+static boolean
+pr_start_block (p, addr)
+ PTR p;
+ bfd_vma addr;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char ab[20];
+ debug_block_t* block = 0;
+ (void)ab;
+#if 0
+ if (info->parameter > 0)
+ {
+ TRACE_FPRINTF( (info->f, ")\n"));
+ info->parameter = 0;
+ }
+ indent (info);
+ print_vma (addr, ab, true, true);
+ TRACE_FPRINTF( (info->f, "{ /* %s */\n", ab));
+ info->indent += 2;
+#else
+ if (info->block) {
+ if (info->block->childs_count==0)
+ info->block->childs = xmalloc(sizeof(debug_block_t));
+ else
+ info->block->childs = xrealloc(info->block->childs,
+ info->block->childs_count*sizeof(debug_block_t));
+ block = &info->block->childs[info->block->childs_count];
+ } else {
+ block = xmalloc(sizeof(debug_block_t));
+ info->function->block = block;
+ }
+ block->begin_addr = addr;
+ block->end_addr = 0;
+ block->parent = info->block;
+ block->childs = NULL;
+ block->childs_count = 0;
+ info->block = block;
+#endif
+ return true;
+}
+
+/* Write out line number information. */
+
+static boolean
+pr_lineno (p, filename, lineno, addr)
+ PTR p;
+ const char *filename;
+ unsigned long lineno;
+ bfd_vma addr;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char ab[20];
+ debug_function_t* f = info->function;
+ (void)ab;
+
+#if 0
+ indent (info);
+ print_vma (addr, ab, true, true);
+ TRACE_FPRINTF( (info->f, "/* file %s line %lu addr %s */\n", filename, lineno, ab));
+#else /* 0 */
+ if (f==NULL) /* FIXME: skips junk silently. */
+ return true;
+ /* assert(f!=NULL); */
+ if (f->filename==NULL) {
+ f->filename = filename;
+ assert(f->lines==0);
+ f->max_lines_count = 4;
+ f->lines = xmalloc(sizeof(debug_lineno_t)*f->max_lines_count);
+ }
+ if (f->lines_count==f->max_lines_count) {
+ f->max_lines_count *= 2;
+ f->lines = xrealloc(f->lines, sizeof(debug_lineno_t)*f->max_lines_count);
+ }
+ f->lines[f->lines_count].lineno = lineno;
+ f->lines[f->lines_count].addr = addr;
+ ++f->lines_count;
+#endif /* !0 */
+
+ return true;
+}
+
+/* Finish writing out a block. */
+
+static boolean
+pr_end_block (p, addr)
+ PTR p;
+ bfd_vma addr;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+#if 0
+ char ab[20];
+
+ info->indent -= 2;
+ indent (info);
+ print_vma (addr, ab, true, true);
+ TRACE_FPRINTF( (info->f, "} /* %s */\n", ab));
+#else /* 0 */
+ assert(info->block!=0);
+ info->block->end_addr = addr;
+ info->block = info->block->parent;
+#endif /* !0 */
+
+ return true;
+}
+
+/* Finish writing out a function. */
+
+/*ARGSUSED*/
+static boolean
+pr_end_function (p)
+ PTR p;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ assert(info->block==0);
+ info->function = NULL;
+ return true;
+}
+
+/* third parameter to segv_action. */
+/* Got it after a bit of head scratching and stack dumping. */
+typedef struct {
+ u_int32_t foo1; /* +0x00 */
+ u_int32_t foo2;
+ u_int32_t foo3;
+ u_int32_t foo4; /* usually 2 */
+ u_int32_t foo5; /* +0x10 */
+ u_int32_t xgs; /* always zero */
+ u_int32_t xfs; /* always zero */
+ u_int32_t xes; /* always es=ds=ss */
+ u_int32_t xds; /* +0x20 */
+ u_int32_t edi;
+ u_int32_t esi;
+ u_int32_t ebp;
+ u_int32_t esp; /* +0x30 */
+ u_int32_t ebx;
+ u_int32_t edx;
+ u_int32_t ecx;
+ u_int32_t eax; /* +0x40 */
+ u_int32_t foo11; /* usually 0xe */
+ u_int32_t foo12; /* usually 0x6 */
+ u_int32_t eip; /* instruction pointer */
+ u_int32_t xcs; /* +0x50 */
+ u_int32_t foo21; /* usually 0x2 */
+ u_int32_t foo22; /* second stack pointer?! Probably. */
+ u_int32_t xss;
+ u_int32_t foo31; /* +0x60 */ /* usually 0x0 */
+ u_int32_t foo32; /* usually 0x2 */
+ u_int32_t fault_addr; /* Address which caused a fault */
+ u_int32_t foo41; /* usually 0x2 */
+} signal_regs_t;
+
+signal_regs_t* ptrace_regs = 0; /* Tells my_ptrace to "ptrace" current process" */
+/*
+ * my_ptrace: small wrapper around ptrace.
+ * Act as normal ptrace if ptrace_regs==0.
+ * Read data from current process if ptrace_regs!=0.
+ */
+static int
+my_ptrace( int request,
+ int pid,
+ int addr,
+ int data)
+{
+ if (ptrace_regs==0)
+ return ptrace(request, pid, addr, data);
+ /* we are tracing ourselves! */
+ switch (request) {
+ case PTRACE_ATTACH: return 0;
+ case PTRACE_CONT: return 0;
+ case PTRACE_DETACH: return 0;
+ case PTRACE_PEEKUSER:
+ switch (addr / 4) {
+ case EIP: return ptrace_regs->eip;
+ case EBP: return ptrace_regs->ebp;
+ default: assert(0);
+ }
+ case PTRACE_PEEKTEXT: /* FALLTHROUGH */
+ case PTRACE_PEEKDATA: return *(int*)(addr);
+ default: assert(0);
+ }
+ errno = 1; /* what to do here? */
+ return 1; /* failed?! */
+}
+
+#define MAXARGS 6
+
+/*
+ * To minimize the number of parameters.
+ */
+typedef struct {
+ asymbol** syms; /* Sorted! */
+ int symcount;
+ debug_function_t** functions;
+ int functions_size;
+} symbol_data_t;
+
+/*
+ * Perform a search. A binary search for a symbol.
+ */
+static void
+decode_symbol( symbol_data_t* symbol_data,
+ const unsigned long addr,
+ char* buf,
+ const int bufsize)
+{
+ asymbol** syms = symbol_data->syms;
+ const int symcount = symbol_data->symcount;
+ int bottom = 0;
+ int top = symcount - 1;
+ int i;
+ if (symcount==0) {
+ sprintf(buf, "????");
+ return;
+ }
+ while (top>bottom+1) {
+ i = (top+bottom) / 2;
+ if (bfd_asymbol_value(syms[i])==addr) {
+ sprintf(buf, "%s", syms[i]->name);
+ return;
+ } else if (bfd_asymbol_value(syms[i]) > addr)
+ top = i;
+ else
+ bottom = i;
+ }
+ i = bottom;
+ if (addr<bfd_asymbol_value(syms[i]) || addr>(syms[i]->section->vma+syms[i]->section->_cooked_size))
+ sprintf(buf, "????");
+ else
+ sprintf(buf, "%s + 0x%lx", syms[i]->name, addr-bfd_asymbol_value(syms[i]));
+}
+
+/*
+ * 1. Perform a binary search for an debug_function_t.
+ * 2. Fill buf/bufsize with name, parameters and lineno, if found
+ * Or with '????' otherwise.
+ */
+static debug_function_t*
+find_debug_function_t( symbol_data_t* symbol_data,
+ const pid_t pid,
+ const unsigned long fp, /* frame pointer */
+ const unsigned long addr,
+ char* buf, /* string buffer */
+ const int bufsize)/* FIXME: not used! */
+{
+ debug_function_t** syms = symbol_data->functions;
+ debug_function_t* f = NULL;
+ debug_block_t* block = NULL;
+ debug_lineno_t* lineno = NULL;
+ const int symcount = symbol_data->functions_size;
+ int bottom = 0;
+ int top = symcount - 1;
+ int i;
+ char* bufptr = buf;
+
+ if (symcount==0) {
+ sprintf(buf, "????");
+ return NULL;
+ }
+ while (top>bottom+1) {
+ i = (top+bottom) / 2;
+ if (syms[i]->block->begin_addr==addr) {
+ f = syms[i];
+ break;
+ } else if (syms[i]->block->begin_addr > addr)
+ top = i;
+ else
+ if (syms[i]->block->end_addr >= addr) {
+ f = syms[i];
+ break;
+ } else
+ bottom = i;
+ }
+ i = bottom;
+ if (f!=0)
+ block = f->block;
+ else {
+ block = syms[i]->block;
+ if (block->begin_addr>=addr && block->end_addr<=addr)
+ f = syms[i];
+ }
+ if (f==0)
+ sprintf(buf, "????");
+ else {
+ /*
+ * Do the backtrace the GDB way...
+ */
+ unsigned long arg;
+ /* assert(f->lines_count>0); */
+ if (f->lines_count>0) {
+ lineno = &f->lines[f->lines_count-1];
+ for (i=1; i<f->lines_count; ++i)
+ if (f->lines[i].addr>addr) {
+ lineno = &f->lines[i-1];
+ break;
+ }
+ }
+ bufptr[0] = 0;
+ bufptr += sprintf(bufptr, "%s+0x%lx (", f->name, addr-block->begin_addr);
+ for (i=0; i<f->argc; ++i) {
+ bufptr += sprintf(bufptr, "%s = ", f->argv[i].name);
+ /* FIXME: better parameter printing */
+ errno = 0;
+ arg = my_ptrace(PTRACE_PEEKDATA, pid, fp+f->argv[i].offset, 0);
+ assert(errno==0);
+ bufptr += sprintf(bufptr, "0x%x", arg);
+ if (i!=f->argc-1)
+ bufptr += sprintf(bufptr, ", ");
+ }
+ if (lineno!=0)
+ bufptr += sprintf(bufptr, ") at %s:%d", f->filename, lineno->lineno);
+ }
+ return f;
+}
+
+/*
+ * Advance through the stacks and display frames as needed.
+ */
+static int
+my_crawl( int pid,
+ symbol_data_t* symbol_data,
+ int fout)
+{
+ unsigned long pc = 0;
+ unsigned long fp = 0;
+ unsigned long nextfp;
+ unsigned long nargs;
+ unsigned long i;
+ unsigned long arg;
+ char buf[8096]; // FIXME: enough?
+ debug_function_t* f = 0;
+
+ errno = 0;
+
+ pc = my_ptrace(PTRACE_PEEKUSER, pid, EIP * 4, 0);
+ if (!errno)
+ fp = my_ptrace(PTRACE_PEEKUSER, pid, EBP * 4, 0);
+
+ if (!errno) {
+#if 1
+ f = find_debug_function_t(symbol_data, pid, fp, pc, buf, sizeof(buf));
+ fdprintf(fout,"0x%08lx: %s", pc, buf);
+ for ( ; !errno && fp; ) {
+ nextfp = my_ptrace(PTRACE_PEEKDATA, pid, fp, 0);
+ if (errno)
+ break;
+
+ if (f==0) {
+ nargs = (nextfp - fp - 8) / 4;
+ if (nargs > MAXARGS)
+ nargs = MAXARGS;
+ if (nargs > 0) {
+ fdputs(" (", fout);
+ for (i = 1; i <= nargs; i++) {
+ arg = my_ptrace(PTRACE_PEEKDATA, pid, fp + 4 * (i + 1), 0);
+ if (errno)
+ break;
+ fdprintf(fout,"%lx", arg);
+ if (i < nargs)
+ fdputs(", ", fout);
+ }
+ fdputc(')', fout);
+ nargs = nextfp - fp - 8 - (4 * nargs);
+ if (!errno && nargs > 0)
+ fdprintf(fout," + %lx\n", nargs);
+ else
+ fdputc('\n', fout);
+ } else
+ fdputc('\n', fout);
+ } else
+ fdputc('\n', fout);
+
+ if (errno || !nextfp)
+ break;
+ pc = my_ptrace(PTRACE_PEEKDATA, pid, fp + 4, 0);
+ fp = nextfp;
+ if (errno)
+ break;
+ f = find_debug_function_t(symbol_data, pid, fp, pc, buf, sizeof(buf));
+ fdprintf(fout,"0x%08lx: %s", pc, buf);
+ }
+#else /* 1 */
+ decode_symbol(symbol_data, pc, buf, sizeof(buf));
+ fdprintf(fout,"0x%08lx: %s", pc, buf);
+ for ( ; !errno && fp; ) {
+ nextfp = my_ptrace(PTRACE_PEEKDATA, pid, fp, 0);
+ if (errno)
+ break;
+
+ nargs = (nextfp - fp - 8) / 4;
+ if (nargs > MAXARGS)
+ nargs = MAXARGS;
+ if (nargs > 0) {
+ fputs(" (", fout);
+ for (i = 1; i <= nargs; i++) {
+ arg = my_ptrace(PTRACE_PEEKDATA, pid, fp + 4 * (i + 1), 0);
+ if (errno)
+ break;
+ fdprintf(fout,"%lx", arg);
+ if (i < nargs)
+ fputs(", ", fout);
+ }
+ fdputc(')', fout);
+ nargs = nextfp - fp - 8 - (4 * nargs);
+ if (!errno && nargs > 0)
+ fdprintf(fout," + %lx\n", nargs);
+ else
+ fdputc('\n', fout);
+ } else
+ fdputc('\n', fout);
+
+ if (errno || !nextfp)
+ break;
+ pc = my_ptrace(PTRACE_PEEKDATA, pid, fp + 4, 0);
+ fp = nextfp;
+ if (errno)
+ break;
+ decode_symbol(symbol_data, pc, buf, sizeof(buf));
+ fdprintf(fout,"0x%08lx: %s", pc, buf);
+ }
+#endif /* !1 */
+ }
+ if (errno)
+ perror("my_crawl");
+ return errno;
+}
+
+/* layout from /usr/src/linux/arch/i386/kernel/process.c */
+static void
+show_regs( signal_regs_t* regs,
+ int fd)
+{
+ /* long cr0 = 0L, cr2 = 0L, cr3 = 0L; */
+
+ fdprintf(fd,"\n");
+ fdprintf(fd,"FAULT ADDR: %08x\n", regs->fault_addr);
+ fdprintf(fd,"EIP: %04x:[<%08x>]",0xffff & regs->xcs,regs->eip);
+ if (regs->xcs & 3)
+ fdprintf(fd," ESP: %04x:%08x",0xffff & regs->xss,regs->esp);
+ /*fdprintf(fd," EFLAGS: %08lx\n",regs->eflags); */
+ fdprintf(fd, "\n");
+ fdprintf(fd,"EAX: %08x EBX: %08x ECX: %08x EDX: %08x\n",
+ regs->eax,regs->ebx,regs->ecx,regs->edx);
+ fdprintf(fd,"ESI: %08x EDI: %08x EBP: %08x",
+ regs->esi, regs->edi, regs->ebp);
+ fdprintf(fd," DS: %04x ES: %04x\n",
+ 0xffff & regs->xds,0xffff & regs->xes);
+ /*
+ __asm__("movl %%cr0, %0": "=r" (cr0));
+ __asm__("movl %%cr2, %0": "=r" (cr2));
+ __asm__("movl %%cr3, %0": "=r" (cr3));
+ fprintf(stderr,"CR0: %08lx CR2: %08lx CR3: %08lx\n", cr0, cr2, cr3); */
+}
+
+/*
+ * Load a BFD for an executable based on PID. Return 0 on failure.
+ */
+static bfd*
+load_bfd( const int pid)
+{
+ char filename[512];
+ bfd* abfd = 0;
+
+ /* Get the contents from procfs. */
+#if 1
+ sprintf(filename, "/proc/%d/exe", pid);
+#else
+ sprintf(filename, "crashing");
+#endif
+
+ if ((abfd = bfd_openr (filename, 0))== NULL)
+ bfd_nonfatal (filename);
+ else {
+ char** matching;
+ assert(bfd_check_format(abfd, bfd_archive)!=true);
+
+ /*
+ * There is no indication in BFD documentation that it should be done.
+ * God knows why...
+ */
+ if (!bfd_check_format_matches (abfd, bfd_object, &matching)) {
+ bfd_nonfatal (bfd_get_filename (abfd));
+ if (bfd_get_error () == bfd_error_file_ambiguously_recognized) {
+ list_matching_formats (matching);
+ free (matching);
+ }
+ }
+ }
+ return abfd;
+}
+
+/*
+ * Those are for qsort. We need only function addresses, so all the others don't count.
+ */
+/*
+ * Compare two BFD::asymbol-s.
+ */
+static int
+compare_symbols(const void* ap,
+ const void* bp)
+{
+ const asymbol *a = *(const asymbol **)ap;
+ const asymbol *b = *(const asymbol **)bp;
+ if (bfd_asymbol_value (a) > bfd_asymbol_value (b))
+ return 1;
+ else if (bfd_asymbol_value (a) < bfd_asymbol_value (b))
+ return -1;
+ return 0;
+}
+
+/*
+ * Compare two debug_asymbol_t-s.
+ */
+static int
+compare_debug_function_t(const void* ap,
+ const void* bp)
+{
+ const debug_function_t *a = *(const debug_function_t **)ap;
+ const debug_function_t *b = *(const debug_function_t **)bp;
+ assert(a->block!=0);
+ assert(b->block!=0);
+ {
+ const bfd_vma addr1 = a->block->begin_addr;
+ const bfd_vma addr2 = b->block->begin_addr;
+ if (addr1 > addr2)
+ return 1;
+ else if (addr2 > addr1)
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Filter out (in place) symbols that are useless for stack tracing.
+ * COUNT is the number of elements in SYMBOLS.
+ * Return the number of useful symbols.
+ */
+
+static long
+remove_useless_symbols( asymbol** symbols,
+ long count)
+{
+ asymbol** in_ptr = symbols;
+ asymbol** out_ptr = symbols;
+
+ while (--count >= 0) {
+ asymbol *sym = *in_ptr++;
+
+ if (sym->name == NULL || sym->name[0] == '\0' || sym->value==0)
+ continue;
+ if (sym->flags & (BSF_DEBUGGING))
+ continue;
+ if (bfd_is_und_section (sym->section) || bfd_is_com_section (sym->section))
+ continue;
+ *out_ptr++ = sym;
+ }
+ return out_ptr - symbols;
+}
+
+/*
+ * Debugging information.
+ */
+static bfd* abfd = 0;
+static PTR dhandle = 0;
+static asymbol** syms = 0;
+static long symcount = 0;
+static asymbol** sorted_syms = 0;
+static long sorted_symcount = 0;
+static debug_function_t** functions = 0;
+static int functions_size = 0;
+static int sigreport = SIGUSR1;
+static pthread_t segv_tid; /* What thread did SEGV? */
+static pid_t segv_pid;
+
+/*
+ * We'll get here after a SIGSEGV. But you can install it on other signals, too :)
+ * Because we are in the middle of the SIGSEGV, we are on our own. We can't do
+ * any malloc(), any fopen(), nothing. The last is actually a sin. We event can't
+ * fprintf(stderr,...)!!!
+ */
+static void
+segv_action(int signo, siginfo_t* siginfo, void* ptr)
+{
+ symbol_data_t symbol_data;
+ int fd = -1;
+
+ segv_pid = getpid();
+ segv_tid = pthread_self();
+ fd = open_log_file(segv_tid, segv_pid);
+ /* signal(SIGSEGV, SIG_DFL); */
+ ptrace_regs = (signal_regs_t*)ptr;
+ assert(ptrace_regs!=0);
+
+ /* Show user how guilty we are. */
+ fdprintf(fd,"--------- SEGV in PROCESS %d, THREAD %d ---------------\n", segv_pid, pthread_self());
+ show_regs(ptrace_regs, fd);
+
+ /* Some form of stack trace, too. */
+ fdprintf(fd, "STACK TRACE:\n");
+
+ symbol_data.syms = sorted_syms;
+ symbol_data.symcount = sorted_symcount;
+ symbol_data.functions = functions;
+ symbol_data.functions_size = functions_size;
+ my_crawl(segv_pid, &symbol_data, fd);
+ //fflush(stdout);
+ close(fd);
+ linuxthreads_notify_others(sigreport);
+}
+
+
+static void
+report_action(int signo, siginfo_t* siginfo, void* ptr)
+{
+ const int pid = getpid();
+ pthread_t tid = pthread_self();
+ symbol_data_t symbol_data;
+ int fd;
+ if (pthread_equal(tid, segv_tid)) {
+ /* We have already printed our stack trace... */
+ return;
+ }
+
+ fd = open_log_file(tid, pid);
+ fdprintf(fd, "REPORT: CURRENT PROCESS:%d, THREAD:%d\n", getpid(), pthread_self());
+ /* signal(SIGSEGV, SIG_DFL); */
+ ptrace_regs = (signal_regs_t*)ptr;
+ assert(ptrace_regs!=0);
+
+ /* Show user how guilty we are. */
+ fdprintf(fd,"--------- STACK TRACE FOR PROCESS %d, THREAD %d ---------------\n", pid, pthread_self());
+ show_regs(ptrace_regs, fd);
+
+ /* Some form of stack trace, too. */
+ fdprintf(fd, "STACK TRACE:\n");
+
+ symbol_data.syms = sorted_syms;
+ symbol_data.symcount = sorted_symcount;
+ symbol_data.functions = functions;
+ symbol_data.functions_size = functions_size;
+ my_crawl(pid, &symbol_data, fd);
+ //fflush(stdout);
+ close(fd);
+ /* Tell segv_thread to proceed after pause(). */
+ /*pthread_kill(segv_tid, sigreport);
+ kill(segv_pid, sigreport);
+ pthread_cancel(tid); */
+}
+
+/*
+ * Main library routine. Just call it on your program.
+ */
+int
+pstack_install_segv_action( const char* path_format_)
+{
+ const int pid = getpid();
+ struct sigaction act;
+
+ /* Store what we have to for later usage. */
+ path_format = path_format_;
+
+ /* We need a signal action for SIGSEGV and sigreport ! */
+ sigreport = SIGUSR1;
+ act.sa_handler = 0;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_SIGINFO|SA_ONESHOT; /* Just one SIGSEGV. */
+ act.sa_sigaction = segv_action;
+ act.sa_restorer = NULL;
+ if (sigaction(SIGSEGV, &act, NULL)!=0) {
+ perror("sigaction");
+ return 1;
+ }
+ act.sa_sigaction = report_action;
+ act.sa_flags = SA_SIGINFO; /* But many sigreports. */
+ if (sigaction(sigreport, &act, NULL)!=0) {
+ perror("sigaction");
+ return 1;
+ }
+
+ /* And a little setup for libiberty. */
+ program_name = "crashing";
+ xmalloc_set_program_name (program_name);
+
+ /* Umm, and initialize BFD, too */
+ bfd_init();
+#if 0
+ list_supported_targets(0, stdout);
+ set_default_bfd_target();
+#endif /* 0 */
+
+ if ((abfd = load_bfd(pid))==0)
+ fprintf(stderr, "BFD load failed..\n");
+ else {
+ long storage_needed = bfd_get_symtab_upper_bound (abfd);
+ long i;
+ (void)i;
+
+ if (storage_needed < 0)
+ fprintf(stderr, "Symbol table size estimation failure.\n");
+ else if (storage_needed > 0) {
+ syms = (asymbol **) xmalloc (storage_needed);
+ symcount = bfd_canonicalize_symtab (abfd, syms);
+
+ TRACE_FPRINTF((stderr, "TOTAL: %ld SYMBOLS.\n", symcount));
+ /* We need debugging info, too! */
+ if (symcount==0 || (dhandle = read_debugging_info (abfd, syms, symcount))==0)
+ fprintf(stderr, "NO DEBUGGING INFORMATION FOUND.\n");
+
+ /* We make a copy of syms to sort. We don't want to sort syms
+ because that will screw up the relocs. */
+ sorted_syms = (asymbol **) xmalloc (symcount * sizeof (asymbol *));
+ memcpy (sorted_syms, syms, symcount * sizeof (asymbol *));
+
+#if 0
+ for (i=0; i<symcount; ++i)
+ if (syms[i]->name!=0 && strlen(syms[i]->name)>0 && syms[i]->value!=0)
+ printf("%08lx T %s\n", syms[i]->section->vma + syms[i]->value, syms[i]->name);
+#endif
+ sorted_symcount = remove_useless_symbols (sorted_syms, symcount);
+ TRACE_FPRINTF((stderr, "SORTED: %ld SYMBOLS.\n", sorted_symcount));
+
+ /* Sort the symbols into section and symbol order */
+ qsort (sorted_syms, sorted_symcount, sizeof (asymbol *), compare_symbols);
+#if 0
+ for (i=0; i<sorted_symcount; ++i)
+ if (sorted_syms[i]->name!=0 && strlen(sorted_syms[i]->name)>0 && sorted_syms[i]->value!=0)
+ printf("%08lx T %s\n", sorted_syms[i]->section->vma + sorted_syms[i]->value, sorted_syms[i]->name);
+#endif
+ /* We have symbols, we need debugging info somehow sorted out. */
+ if (dhandle==0) {
+ fprintf(stderr, "STACK TRACE WILL BE UNCOMFORTABLE.\n");
+ } else {
+ /* Start collecting the debugging information.... */
+ struct pr_handle info;
+
+ info.f = stdout;
+ info.indent = 0;
+ info.stack = NULL;
+ info.parameter = 0;
+ info.block = NULL;
+ info.function = NULL;
+ info.functions_size = 0;
+ info.functions_maxsize = 1000;
+ info.functions = (debug_function_t*)xmalloc(sizeof(debug_function_t)*info.functions_maxsize);
+ debug_write (dhandle, &pr_fns, (PTR) &info);
+ TRACE_FPRINTF((stdout, "\n%d DEBUG SYMBOLS\n", info.functions_size));
+ assert(info.functions_size!=0);
+ functions = xmalloc(sizeof(debug_function_t*)*info.functions_size);
+ functions_size = info.functions_size;
+ for (i=0; i<functions_size; ++i)
+ functions[i] = &info.functions[i];
+ /* Sort the symbols into section and symbol order */
+ qsort (functions, functions_size, sizeof(debug_function_t*),
+ compare_debug_function_t);
+#if 0
+ for (i=0; i<info.functions_size; ++i)
+ fprintf(stdout, "%08lx T %s\n", info.functions[i].block->begin_addr, info.functions[i].name);
+#endif
+ fflush(stdout);
+ }
+ } else /* storage_needed == 0 */
+ fprintf(stderr, "NO SYMBOLS FOUND.\n");
+ }
+ return 0;
+}
+
+/*********************************************************************/
+/*********************************************************************/
+/*********************************************************************/
diff --git a/pstack/pstack.h b/pstack/pstack.h
new file mode 100644
index 00000000000..4c4fad7e754
--- /dev/null
+++ b/pstack/pstack.h
@@ -0,0 +1,22 @@
+/* $Header$ */
+
+#ifndef pstack_pstack_h_
+#define pstack_pstack_h_
+
+#include "pstacktrace.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Install the stack-trace-on-SEGV handler....
+ */
+extern int
+pstack_install_segv_action( const char* path_format);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* pstack_pstack_h_ */
+
diff --git a/pstack/pstacktrace.h b/pstack/pstacktrace.h
new file mode 100644
index 00000000000..c884bcb9f87
--- /dev/null
+++ b/pstack/pstacktrace.h
@@ -0,0 +1,24 @@
+/* $Header$ */
+
+/*
+ * Debugging macros.
+ */
+
+#ifndef pstacktrace_h_
+#define pstacktrace_h_
+
+#define PSTACK_DEBUG 1
+#undef PSTACK_DEBUG
+
+#ifdef PSTACK_DEBUG
+# define TRACE_PUTC(a) putc a
+# define TRACE_FPUTS(a) fputs a
+# define TRACE_FPRINTF(a) fprintf a
+#else /* PSTACK_DEBUG */
+# define TRACE_PUTC(a) (void)0
+# define TRACE_FPUTS(a) (void)0
+# define TRACE_FPRINTF(a) (void)0
+#endif /* !PSTACK_DEBUG */
+
+#endif /* pstacktrace_h_ */
+
diff --git a/pstack/rddbg.c b/pstack/rddbg.c
new file mode 100644
index 00000000000..be3dfc21c57
--- /dev/null
+++ b/pstack/rddbg.c
@@ -0,0 +1,462 @@
+/* rddbg.c -- Read debugging information into a generic form.
+ Copyright (C) 1995, 96, 1997 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <ian@cygnus.com>.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; 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 reads debugging information into a generic form. This
+ file knows how to dig the debugging information out of an object
+ file. */
+
+#include <bfd.h>
+#include "bucomm.h"
+#include <libiberty.h>
+#include "debug.h"
+#include "budbg.h"
+
+static boolean read_section_stabs_debugging_info
+ PARAMS ((bfd *, asymbol **, long, PTR, boolean *));
+static boolean read_symbol_stabs_debugging_info
+ PARAMS ((bfd *, asymbol **, long, PTR, boolean *));
+static boolean read_ieee_debugging_info PARAMS ((bfd *, PTR, boolean *));
+static void save_stab PARAMS ((int, int, bfd_vma, const char *));
+static void stab_context PARAMS ((void));
+static void free_saved_stabs PARAMS ((void));
+
+/* Read debugging information from a BFD. Returns a generic debugging
+ pointer. */
+
+PTR
+read_debugging_info (abfd, syms, symcount)
+ bfd *abfd;
+ asymbol **syms;
+ long symcount;
+{
+ PTR dhandle;
+ boolean found;
+
+ dhandle = debug_init ();
+ if (dhandle == NULL)
+ return NULL;
+
+ if (! read_section_stabs_debugging_info (abfd, syms, symcount, dhandle,
+ &found))
+ return NULL;
+
+ if (bfd_get_flavour (abfd) == bfd_target_aout_flavour)
+ {
+ if (! read_symbol_stabs_debugging_info (abfd, syms, symcount, dhandle,
+ &found))
+ return NULL;
+ }
+
+ if (bfd_get_flavour (abfd) == bfd_target_ieee_flavour)
+ {
+ if (! read_ieee_debugging_info (abfd, dhandle, &found))
+ return NULL;
+ }
+
+ /* Try reading the COFF symbols if we didn't find any stabs in COFF
+ sections. */
+ if (! found
+ && bfd_get_flavour (abfd) == bfd_target_coff_flavour
+ && symcount > 0)
+ {
+#if 0
+/*
+ * JZ: Do we need coff?
+ */
+ if (! parse_coff (abfd, syms, symcount, dhandle))
+#else
+ fprintf (stderr, "%s: COFF support temporarily disabled\n",
+ bfd_get_filename (abfd));
+ return NULL;
+#endif
+ return NULL;
+ found = true;
+ }
+
+ if (! found)
+ {
+ fprintf (stderr, "%s: no recognized debugging information\n",
+ bfd_get_filename (abfd));
+ return NULL;
+ }
+
+ return dhandle;
+}
+
+/* Read stabs in sections debugging information from a BFD. */
+
+static boolean
+read_section_stabs_debugging_info (abfd, syms, symcount, dhandle, pfound)
+ bfd *abfd;
+ asymbol **syms;
+ long symcount;
+ PTR dhandle;
+ boolean *pfound;
+{
+ static struct
+ {
+ const char *secname;
+ const char *strsecname;
+ } names[] = { { ".stab", ".stabstr" } };
+ unsigned int i;
+ PTR shandle;
+
+ *pfound = false;
+ shandle = NULL;
+
+ for (i = 0; i < sizeof names / sizeof names[0]; i++)
+ {
+ asection *sec, *strsec;
+
+ sec = bfd_get_section_by_name (abfd, names[i].secname);
+ strsec = bfd_get_section_by_name (abfd, names[i].strsecname);
+ if (sec != NULL && strsec != NULL)
+ {
+ bfd_size_type stabsize, strsize;
+ bfd_byte *stabs, *strings;
+ bfd_byte *stab;
+ bfd_size_type stroff, next_stroff;
+
+ stabsize = bfd_section_size (abfd, sec);
+ stabs = (bfd_byte *) xmalloc (stabsize);
+ if (! bfd_get_section_contents (abfd, sec, stabs, 0, stabsize))
+ {
+ fprintf (stderr, "%s: %s: %s\n",
+ bfd_get_filename (abfd), names[i].secname,
+ bfd_errmsg (bfd_get_error ()));
+ return false;
+ }
+
+ strsize = bfd_section_size (abfd, strsec);
+ strings = (bfd_byte *) xmalloc (strsize);
+ if (! bfd_get_section_contents (abfd, strsec, strings, 0, strsize))
+ {
+ fprintf (stderr, "%s: %s: %s\n",
+ bfd_get_filename (abfd), names[i].strsecname,
+ bfd_errmsg (bfd_get_error ()));
+ return false;
+ }
+
+ if (shandle == NULL)
+ {
+ shandle = start_stab (dhandle, abfd, true, syms, symcount);
+ if (shandle == NULL)
+ return false;
+ }
+
+ *pfound = true;
+
+ stroff = 0;
+ next_stroff = 0;
+ for (stab = stabs; stab < stabs + stabsize; stab += 12)
+ {
+ bfd_size_type strx;
+ int type;
+ int other;
+ int desc;
+ bfd_vma value;
+
+ /* This code presumes 32 bit values. */
+
+ strx = bfd_get_32 (abfd, stab);
+ type = bfd_get_8 (abfd, stab + 4);
+ other = bfd_get_8 (abfd, stab + 5);
+ desc = bfd_get_16 (abfd, stab + 6);
+ value = bfd_get_32 (abfd, stab + 8);
+
+ if (type == 0)
+ {
+ /* Special type 0 stabs indicate the offset to the
+ next string table. */
+ stroff = next_stroff;
+ next_stroff += value;
+ }
+ else
+ {
+ char *f, *s;
+
+ f = NULL;
+ s = (char *) strings + stroff + strx;
+ while (s[strlen (s) - 1] == '\\'
+ && stab + 12 < stabs + stabsize)
+ {
+ char *p;
+
+ stab += 12;
+ p = s + strlen (s) - 1;
+ *p = '\0';
+ s = concat (s,
+ ((char *) strings
+ + stroff
+ + bfd_get_32 (abfd, stab)),
+ (const char *) NULL);
+
+ /* We have to restore the backslash, because, if
+ the linker is hashing stabs strings, we may
+ see the same string more than once. */
+ *p = '\\';
+
+ if (f != NULL)
+ free (f);
+ f = s;
+ }
+
+ save_stab (type, desc, value, s);
+
+ if (! parse_stab (dhandle, shandle, type, desc, value, s))
+ {
+#if 0
+/*
+ * JZ: skip the junk.
+ */
+ stab_context ();
+ free_saved_stabs ();
+ return false;
+#endif
+ }
+
+ /* Don't free f, since I think the stabs code
+ expects strings to hang around. This should be
+ straightened out. FIXME. */
+ }
+ }
+
+ free_saved_stabs ();
+ free (stabs);
+
+ /* Don't free strings, since I think the stabs code expects
+ the strings to hang around. This should be straightened
+ out. FIXME. */
+ }
+ }
+
+ if (shandle != NULL)
+ {
+ if (! finish_stab (dhandle, shandle))
+ return false;
+ }
+
+ return true;
+}
+
+/* Read stabs in the symbol table. */
+
+static boolean
+read_symbol_stabs_debugging_info (abfd, syms, symcount, dhandle, pfound)
+ bfd *abfd;
+ asymbol **syms;
+ long symcount;
+ PTR dhandle;
+ boolean *pfound;
+{
+ PTR shandle;
+ asymbol **ps, **symend;
+
+ shandle = NULL;
+ symend = syms + symcount;
+ for (ps = syms; ps < symend; ps++)
+ {
+ symbol_info i;
+
+ bfd_get_symbol_info (abfd, *ps, &i);
+
+ if (i.type == '-')
+ {
+ const char *s;
+ char *f;
+
+ if (shandle == NULL)
+ {
+ shandle = start_stab (dhandle, abfd, false, syms, symcount);
+ if (shandle == NULL)
+ return false;
+ }
+
+ *pfound = true;
+
+ s = i.name;
+ f = NULL;
+ while (s[strlen (s) - 1] == '\\'
+ && ps + 1 < symend)
+ {
+ char *sc, *n;
+
+ ++ps;
+ sc = xstrdup (s);
+ sc[strlen (sc) - 1] = '\0';
+ n = concat (sc, bfd_asymbol_name (*ps), (const char *) NULL);
+ free (sc);
+ if (f != NULL)
+ free (f);
+ f = n;
+ s = n;
+ }
+
+ save_stab (i.stab_type, i.stab_desc, i.value, s);
+
+ if (! parse_stab (dhandle, shandle, i.stab_type, i.stab_desc,
+ i.value, s))
+ {
+ stab_context ();
+ free_saved_stabs ();
+ return false;
+ }
+
+ /* Don't free f, since I think the stabs code expects
+ strings to hang around. This should be straightened out.
+ FIXME. */
+ }
+ }
+
+ free_saved_stabs ();
+
+ if (shandle != NULL)
+ {
+ if (! finish_stab (dhandle, shandle))
+ return false;
+ }
+
+ return true;
+}
+
+/* Read IEEE debugging information. */
+
+static boolean
+read_ieee_debugging_info (abfd, dhandle, pfound)
+ bfd *abfd;
+ PTR dhandle;
+ boolean *pfound;
+{
+ asection *dsec;
+ bfd_size_type size;
+ bfd_byte *contents;
+
+ /* The BFD backend puts the debugging information into a section
+ named .debug. */
+
+ dsec = bfd_get_section_by_name (abfd, ".debug");
+ if (dsec == NULL)
+ return true;
+
+ size = bfd_section_size (abfd, dsec);
+ contents = (bfd_byte *) xmalloc (size);
+ if (! bfd_get_section_contents (abfd, dsec, contents, 0, size))
+ return false;
+
+ if (! parse_ieee (dhandle, abfd, contents, size))
+ return false;
+
+ free (contents);
+
+ *pfound = true;
+
+ return true;
+}
+
+/* Record stabs strings, so that we can give some context for errors. */
+
+#define SAVE_STABS_COUNT (16)
+
+struct saved_stab
+{
+ int type;
+ int desc;
+ bfd_vma value;
+ char *string;
+};
+
+static struct saved_stab saved_stabs[SAVE_STABS_COUNT];
+static int saved_stabs_index;
+
+/* Save a stabs string. */
+
+static void
+save_stab (type, desc, value, string)
+ int type;
+ int desc;
+ bfd_vma value;
+ const char *string;
+{
+ if (saved_stabs[saved_stabs_index].string != NULL)
+ free (saved_stabs[saved_stabs_index].string);
+ saved_stabs[saved_stabs_index].type = type;
+ saved_stabs[saved_stabs_index].desc = desc;
+ saved_stabs[saved_stabs_index].value = value;
+ saved_stabs[saved_stabs_index].string = xstrdup (string);
+ saved_stabs_index = (saved_stabs_index + 1) % SAVE_STABS_COUNT;
+}
+
+/* Provide context for an error. */
+
+static void
+stab_context ()
+{
+ int i;
+
+ fprintf (stderr, "Last stabs entries before error:\n");
+ fprintf (stderr, "n_type n_desc n_value string\n");
+
+ i = saved_stabs_index;
+ do
+ {
+ struct saved_stab *stabp;
+
+ stabp = saved_stabs + i;
+ if (stabp->string != NULL)
+ {
+ const char *s;
+
+ s = bfd_get_stab_name (stabp->type);
+ if (s != NULL)
+ fprintf (stderr, "%-6s", s);
+ else if (stabp->type == 0)
+ fprintf (stderr, "HdrSym");
+ else
+ fprintf (stderr, "%-6d", stabp->type);
+ fprintf (stderr, " %-6d ", stabp->desc);
+ fprintf_vma (stderr, stabp->value);
+ if (stabp->type != 0)
+ fprintf (stderr, " %s", stabp->string);
+ fprintf (stderr, "\n");
+ }
+ i = (i + 1) % SAVE_STABS_COUNT;
+ }
+ while (i != saved_stabs_index);
+}
+
+/* Free the saved stab strings. */
+
+static void
+free_saved_stabs ()
+{
+ int i;
+
+ for (i = 0; i < SAVE_STABS_COUNT; i++)
+ {
+ if (saved_stabs[i].string != NULL)
+ {
+ free (saved_stabs[i].string);
+ saved_stabs[i].string = NULL;
+ }
+ }
+
+ saved_stabs_index = 0;
+}
diff --git a/pstack/stabs.c b/pstack/stabs.c
new file mode 100644
index 00000000000..076231d19cb
--- /dev/null
+++ b/pstack/stabs.c
@@ -0,0 +1,5082 @@
+/* stabs.c -- Parse stabs debugging information
+ Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <ian@cygnus.com>.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA. */
+
+/* This file contains code which parses stabs debugging information.
+ The organization of this code is based on the gdb stabs reading
+ code. The job it does is somewhat different, because it is not
+ trying to identify the correct address for anything. */
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include <bfd.h>
+#include "bucomm.h"
+#include <libiberty.h>
+#include "demangle.h"
+#include "debug.h"
+#include "budbg.h"
+
+/* Meaningless definition needs by aout64.h. FIXME. */
+#define BYTES_IN_WORD 4
+
+#include "aout/aout64.h"
+#include "aout/stab_gnu.h"
+
+/* The number of predefined XCOFF types. */
+
+#define XCOFF_TYPE_COUNT 34
+
+/* This structure is used as a handle so that the stab parsing doesn't
+ need to use any static variables. */
+
+struct stab_handle
+{
+ /* The BFD. */
+ bfd *abfd;
+ /* True if this is stabs in sections. */
+ boolean sections;
+ /* The symbol table. */
+ asymbol **syms;
+ /* The number of symbols. */
+ long symcount;
+ /* The accumulated file name string. */
+ char *so_string;
+ /* The value of the last N_SO symbol. */
+ bfd_vma so_value;
+ /* The value of the start of the file, so that we can handle file
+ relative N_LBRAC and N_RBRAC symbols. */
+ bfd_vma file_start_offset;
+ /* The offset of the start of the function, so that we can handle
+ function relative N_LBRAC and N_RBRAC symbols. */
+ bfd_vma function_start_offset;
+ /* The version number of gcc which compiled the current compilation
+ unit, 0 if not compiled by gcc. */
+ int gcc_compiled;
+ /* Whether an N_OPT symbol was seen that was not generated by gcc,
+ so that we can detect the SunPRO compiler. */
+ boolean n_opt_found;
+ /* The main file name. */
+ char *main_filename;
+ /* A stack of unfinished N_BINCL files. */
+ struct bincl_file *bincl_stack;
+ /* A list of finished N_BINCL files. */
+ struct bincl_file *bincl_list;
+ /* Whether we are inside a function or not. */
+ boolean within_function;
+ /* The address of the end of the function, used if we have seen an
+ N_FUN symbol while in a function. This is -1 if we have not seen
+ an N_FUN (the normal case). */
+ bfd_vma function_end;
+ /* The depth of block nesting. */
+ int block_depth;
+ /* List of pending variable definitions. */
+ struct stab_pending_var *pending;
+ /* Number of files for which we have types. */
+ unsigned int files;
+ /* Lists of types per file. */
+ struct stab_types **file_types;
+ /* Predefined XCOFF types. */
+ debug_type xcoff_types[XCOFF_TYPE_COUNT];
+ /* Undefined tags. */
+ struct stab_tag *tags;
+};
+
+/* A list of these structures is used to hold pending variable
+ definitions seen before the N_LBRAC of a block. */
+
+struct stab_pending_var
+{
+ /* Next pending variable definition. */
+ struct stab_pending_var *next;
+ /* Name. */
+ const char *name;
+ /* Type. */
+ debug_type type;
+ /* Kind. */
+ enum debug_var_kind kind;
+ /* Value. */
+ bfd_vma val;
+};
+
+/* A list of these structures is used to hold the types for a single
+ file. */
+
+struct stab_types
+{
+ /* Next set of slots for this file. */
+ struct stab_types *next;
+ /* Types indexed by type number. */
+#define STAB_TYPES_SLOTS (16)
+ debug_type types[STAB_TYPES_SLOTS];
+};
+
+/* We keep a list of undefined tags that we encounter, so that we can
+ fill them in if the tag is later defined. */
+
+struct stab_tag
+{
+ /* Next undefined tag. */
+ struct stab_tag *next;
+ /* Tag name. */
+ const char *name;
+ /* Type kind. */
+ enum debug_type_kind kind;
+ /* Slot to hold real type when we discover it. If we don't, we fill
+ in an undefined tag type. */
+ debug_type slot;
+ /* Indirect type we have created to point at slot. */
+ debug_type type;
+};
+
+static char *savestring PARAMS ((const char *, int));
+static bfd_vma parse_number PARAMS ((const char **, boolean *));
+static void bad_stab PARAMS ((const char *));
+static void warn_stab PARAMS ((const char *, const char *));
+static boolean parse_stab_string
+ PARAMS ((PTR, struct stab_handle *, int, int, bfd_vma, const char *));
+static debug_type parse_stab_type
+ PARAMS ((PTR, struct stab_handle *, const char *, const char **,
+ debug_type **));
+static boolean parse_stab_type_number
+ PARAMS ((const char **, int *));
+static debug_type parse_stab_range_type
+ PARAMS ((PTR, struct stab_handle *, const char *, const char **,
+ const int *));
+static debug_type parse_stab_sun_builtin_type PARAMS ((PTR, const char **));
+static debug_type parse_stab_sun_floating_type
+ PARAMS ((PTR, const char **));
+static debug_type parse_stab_enum_type PARAMS ((PTR, const char **));
+static debug_type parse_stab_struct_type
+ PARAMS ((PTR, struct stab_handle *, const char *, const char **, boolean,
+ const int *));
+static boolean parse_stab_baseclasses
+ PARAMS ((PTR, struct stab_handle *, const char **, debug_baseclass **));
+static boolean parse_stab_struct_fields
+ PARAMS ((PTR, struct stab_handle *, const char **, debug_field **,
+ boolean *));
+static boolean parse_stab_cpp_abbrev
+ PARAMS ((PTR, struct stab_handle *, const char **, debug_field *));
+static boolean parse_stab_one_struct_field
+ PARAMS ((PTR, struct stab_handle *, const char **, const char *,
+ debug_field *, boolean *));
+static boolean parse_stab_members
+ PARAMS ((PTR, struct stab_handle *, const char *, const char **,
+ const int *, debug_method **));
+static debug_type parse_stab_argtypes
+ PARAMS ((PTR, struct stab_handle *, debug_type, const char *, const char *,
+ debug_type, const char *, boolean, boolean, const char **));
+static boolean parse_stab_tilde_field
+ PARAMS ((PTR, struct stab_handle *, const char **, const int *,
+ debug_type *, boolean *));
+static debug_type parse_stab_array_type
+ PARAMS ((PTR, struct stab_handle *, const char **, boolean));
+static void push_bincl PARAMS ((struct stab_handle *, const char *, bfd_vma));
+static const char *pop_bincl PARAMS ((struct stab_handle *));
+static boolean find_excl
+ PARAMS ((struct stab_handle *, const char *, bfd_vma));
+static boolean stab_record_variable
+ PARAMS ((PTR, struct stab_handle *, const char *, debug_type,
+ enum debug_var_kind, bfd_vma));
+static boolean stab_emit_pending_vars PARAMS ((PTR, struct stab_handle *));
+static debug_type *stab_find_slot
+ PARAMS ((struct stab_handle *, const int *));
+static debug_type stab_find_type
+ PARAMS ((PTR, struct stab_handle *, const int *));
+static boolean stab_record_type
+ PARAMS ((PTR, struct stab_handle *, const int *, debug_type));
+static debug_type stab_xcoff_builtin_type
+ PARAMS ((PTR, struct stab_handle *, int));
+static debug_type stab_find_tagged_type
+ PARAMS ((PTR, struct stab_handle *, const char *, int,
+ enum debug_type_kind));
+static debug_type *stab_demangle_argtypes
+ PARAMS ((PTR, struct stab_handle *, const char *, boolean *));
+
+/* Save a string in memory. */
+
+static char *
+savestring (start, len)
+ const char *start;
+ int len;
+{
+ char *ret;
+
+ ret = (char *) xmalloc (len + 1);
+ memcpy (ret, start, len);
+ ret[len] = '\0';
+ return ret;
+}
+
+/* Read a number from a string. */
+
+static bfd_vma
+parse_number (pp, poverflow)
+ const char **pp;
+ boolean *poverflow;
+{
+ unsigned long ul;
+ const char *orig;
+
+ if (poverflow != NULL)
+ *poverflow = false;
+
+ orig = *pp;
+
+ errno = 0;
+ ul = strtoul (*pp, (char **) pp, 0);
+ if (ul + 1 != 0 || errno == 0)
+ return (bfd_vma) ul;
+
+ /* Note that even though strtoul overflowed, it should have set *pp
+ to the end of the number, which is where we want it. */
+
+ if (sizeof (bfd_vma) > sizeof (unsigned long))
+ {
+ const char *p;
+ boolean neg;
+ int base;
+ bfd_vma over, lastdig;
+ boolean overflow;
+ bfd_vma v;
+
+ /* Our own version of strtoul, for a bfd_vma. */
+
+ p = orig;
+
+ neg = false;
+ if (*p == '+')
+ ++p;
+ else if (*p == '-')
+ {
+ neg = true;
+ ++p;
+ }
+
+ base = 10;
+ if (*p == '0')
+ {
+ if (p[1] == 'x' || p[1] == 'X')
+ {
+ base = 16;
+ p += 2;
+ }
+ else
+ {
+ base = 8;
+ ++p;
+ }
+ }
+
+ over = ((bfd_vma) (bfd_signed_vma) -1) / (bfd_vma) base;
+ lastdig = ((bfd_vma) (bfd_signed_vma) -1) % (bfd_vma) base;
+
+ overflow = false;
+ v = 0;
+ while (1)
+ {
+ int d;
+
+ d = *p++;
+ if (isdigit ((unsigned char) d))
+ d -= '0';
+ else if (isupper ((unsigned char) d))
+ d -= 'A';
+ else if (islower ((unsigned char) d))
+ d -= 'a';
+ else
+ break;
+
+ if (d >= base)
+ break;
+
+ if (v > over || (v == over && (bfd_vma) d > lastdig))
+ {
+ overflow = true;
+ break;
+ }
+ }
+
+ if (! overflow)
+ {
+ if (neg)
+ v = - v;
+ return v;
+ }
+ }
+
+ /* If we get here, the number is too large to represent in a
+ bfd_vma. */
+
+ if (poverflow != NULL)
+ *poverflow = true;
+ else
+ warn_stab (orig, "numeric overflow");
+
+ return 0;
+}
+
+/* Give an error for a bad stab string. */
+
+static void
+bad_stab (p)
+ const char *p;
+{
+ fprintf (stderr, "Bad stab: %s\n", p);
+}
+
+/* Warn about something in a stab string. */
+
+static void
+warn_stab (p, err)
+ const char *p;
+ const char *err;
+{
+ fprintf (stderr, "Warning: %s: %s\n", err, p);
+}
+
+/* Create a handle to parse stabs symbols with. */
+
+/*ARGSUSED*/
+PTR
+start_stab (dhandle, abfd, sections, syms, symcount)
+ PTR dhandle;
+ bfd *abfd;
+ boolean sections;
+ asymbol **syms;
+ long symcount;
+{
+ struct stab_handle *ret;
+
+ ret = (struct stab_handle *) xmalloc (sizeof *ret);
+ memset (ret, 0, sizeof *ret);
+ ret->abfd = abfd;
+ ret->sections = sections;
+ ret->syms = syms;
+ ret->symcount = symcount;
+ ret->files = 1;
+ ret->file_types = (struct stab_types **) xmalloc (sizeof *ret->file_types);
+ ret->file_types[0] = NULL;
+ ret->function_end = (bfd_vma) -1;
+ return (PTR) ret;
+}
+
+/* When we have processed all the stabs information, we need to go
+ through and fill in all the undefined tags. */
+
+boolean
+finish_stab (dhandle, handle)
+ PTR dhandle;
+ PTR handle;
+{
+ struct stab_handle *info = (struct stab_handle *) handle;
+ struct stab_tag *st;
+
+ if (info->within_function)
+ {
+ if (! stab_emit_pending_vars (dhandle, info)
+ || ! debug_end_function (dhandle, info->function_end))
+ return false;
+ info->within_function = false;
+ info->function_end = (bfd_vma) -1;
+ }
+
+ for (st = info->tags; st != NULL; st = st->next)
+ {
+ enum debug_type_kind kind;
+
+ kind = st->kind;
+ if (kind == DEBUG_KIND_ILLEGAL)
+ kind = DEBUG_KIND_STRUCT;
+ st->slot = debug_make_undefined_tagged_type (dhandle, st->name, kind);
+ if (st->slot == DEBUG_TYPE_NULL)
+ return false;
+ }
+
+ return true;
+}
+
+/* Handle a single stabs symbol. */
+
+boolean
+parse_stab (dhandle, handle, type, desc, value, string)
+ PTR dhandle;
+ PTR handle;
+ int type;
+ int desc;
+ bfd_vma value;
+ const char *string;
+{
+ struct stab_handle *info = (struct stab_handle *) handle;
+
+ /* gcc will emit two N_SO strings per compilation unit, one for the
+ directory name and one for the file name. We just collect N_SO
+ strings as we see them, and start the new compilation unit when
+ we see a non N_SO symbol. */
+ if (info->so_string != NULL
+ && (type != N_SO || *string == '\0' || value != info->so_value))
+ {
+ if (! debug_set_filename (dhandle, info->so_string))
+ return false;
+ info->main_filename = info->so_string;
+
+ info->gcc_compiled = 0;
+ info->n_opt_found = false;
+
+ /* Generally, for stabs in the symbol table, the N_LBRAC and
+ N_RBRAC symbols are relative to the N_SO symbol value. */
+ if (! info->sections)
+ info->file_start_offset = info->so_value;
+
+ /* We need to reset the mapping from type numbers to types. We
+ can't free the old mapping, because of the use of
+ debug_make_indirect_type. */
+ info->files = 1;
+ info->file_types = ((struct stab_types **)
+ xmalloc (sizeof *info->file_types));
+ info->file_types[0] = NULL;
+
+ info->so_string = NULL;
+
+ /* Now process whatever type we just got. */
+ }
+
+ switch (type)
+ {
+ case N_FN:
+ case N_FN_SEQ:
+ break;
+
+ case N_LBRAC:
+ /* Ignore extra outermost context from SunPRO cc and acc. */
+ if (info->n_opt_found && desc == 1)
+ break;
+
+ if (! info->within_function)
+ {
+ fprintf (stderr, "N_LBRAC not within function\n");
+ return false;
+ }
+
+ /* Start an inner lexical block. */
+ if (! debug_start_block (dhandle,
+ (value
+ + info->file_start_offset
+ + info->function_start_offset)))
+ return false;
+
+ /* Emit any pending variable definitions. */
+ if (! stab_emit_pending_vars (dhandle, info))
+ return false;
+
+ ++info->block_depth;
+ break;
+
+ case N_RBRAC:
+ /* Ignore extra outermost context from SunPRO cc and acc. */
+ if (info->n_opt_found && desc == 1)
+ break;
+
+ /* We shouldn't have any pending variable definitions here, but,
+ if we do, we probably need to emit them before closing the
+ block. */
+ if (! stab_emit_pending_vars (dhandle, info))
+ return false;
+
+ /* End an inner lexical block. */
+ if (! debug_end_block (dhandle,
+ (value
+ + info->file_start_offset
+ + info->function_start_offset)))
+ return false;
+
+ --info->block_depth;
+ if (info->block_depth < 0)
+ {
+ fprintf (stderr, "Too many N_RBRACs\n");
+ return false;
+ }
+ break;
+
+ case N_SO:
+ /* This always ends a function. */
+ if (info->within_function)
+ {
+ bfd_vma endval;
+
+ endval = value;
+ if (*string != '\0'
+ && info->function_end != (bfd_vma) -1
+ && info->function_end < endval)
+ endval = info->function_end;
+ if (! stab_emit_pending_vars (dhandle, info)
+ || ! debug_end_function (dhandle, endval))
+ return false;
+ info->within_function = false;
+ info->function_end = (bfd_vma) -1;
+ }
+
+ /* An empty string is emitted by gcc at the end of a compilation
+ unit. */
+ if (*string == '\0')
+ return true;
+
+ /* Just accumulate strings until we see a non N_SO symbol. If
+ the string starts with '/', we discard the previously
+ accumulated strings. */
+ if (info->so_string == NULL)
+ info->so_string = xstrdup (string);
+ else
+ {
+ char *f;
+
+ f = info->so_string;
+ if (*string == '/')
+ info->so_string = xstrdup (string);
+ else
+ info->so_string = concat (info->so_string, string,
+ (const char *) NULL);
+ free (f);
+ }
+
+ info->so_value = value;
+
+ break;
+
+ case N_SOL:
+ /* Start an include file. */
+ if (! debug_start_source (dhandle, string))
+ return false;
+ break;
+
+ case N_BINCL:
+ /* Start an include file which may be replaced. */
+ push_bincl (info, string, value);
+ if (! debug_start_source (dhandle, string))
+ return false;
+ break;
+
+ case N_EINCL:
+ /* End an N_BINCL include. */
+ if (! debug_start_source (dhandle, pop_bincl (info)))
+ return false;
+ break;
+
+ case N_EXCL:
+ /* This is a duplicate of a header file named by N_BINCL which
+ was eliminated by the linker. */
+ if (! find_excl (info, string, value))
+ return false;
+ break;
+
+ case N_SLINE:
+ if (! debug_record_line (dhandle, desc,
+ value + info->function_start_offset))
+ return false;
+ break;
+
+ case N_BCOMM:
+ if (! debug_start_common_block (dhandle, string))
+ return false;
+ break;
+
+ case N_ECOMM:
+ if (! debug_end_common_block (dhandle, string))
+ return false;
+ break;
+
+ case N_FUN:
+ if (*string == '\0')
+ {
+ if (info->within_function)
+ {
+ /* This always marks the end of a function; we don't
+ need to worry about info->function_end. */
+ if (info->sections)
+ value += info->function_start_offset;
+ if (! stab_emit_pending_vars (dhandle, info)
+ || ! debug_end_function (dhandle, value))
+ return false;
+ info->within_function = false;
+ info->function_end = (bfd_vma) -1;
+ }
+ break;
+ }
+
+ /* A const static symbol in the .text section will have an N_FUN
+ entry. We need to use these to mark the end of the function,
+ in case we are looking at gcc output before it was changed to
+ always emit an empty N_FUN. We can't call debug_end_function
+ here, because it might be a local static symbol. */
+ if (info->within_function
+ && (info->function_end == (bfd_vma) -1
+ || value < info->function_end))
+ info->function_end = value;
+
+ /* Fall through. */
+ /* FIXME: gdb checks the string for N_STSYM, N_LCSYM or N_ROSYM
+ symbols, and if it does not start with :S, gdb relocates the
+ value to the start of the section. gcc always seems to use
+ :S, so we don't worry about this. */
+ /* Fall through. */
+ default:
+ {
+ const char *colon;
+
+ colon = strchr (string, ':');
+ if (colon != NULL
+ && (colon[1] == 'f' || colon[1] == 'F'))
+ {
+ if (info->within_function)
+ {
+ bfd_vma endval;
+
+ endval = value;
+ if (info->function_end != (bfd_vma) -1
+ && info->function_end < endval)
+ endval = info->function_end;
+ if (! stab_emit_pending_vars (dhandle, info)
+ || ! debug_end_function (dhandle, endval))
+ return false;
+ info->function_end = (bfd_vma) -1;
+ }
+ /* For stabs in sections, line numbers and block addresses
+ are offsets from the start of the function. */
+ if (info->sections)
+ info->function_start_offset = value;
+ info->within_function = true;
+ }
+
+ if (! parse_stab_string (dhandle, info, type, desc, value, string))
+ return false;
+ }
+ break;
+
+ case N_OPT:
+ if (string != NULL && strcmp (string, "gcc2_compiled.") == 0)
+ info->gcc_compiled = 2;
+ else if (string != NULL && strcmp (string, "gcc_compiled.") == 0)
+ info->gcc_compiled = 1;
+ else
+ info->n_opt_found = true;
+ break;
+
+ case N_OBJ:
+ case N_ENDM:
+ case N_MAIN:
+ break;
+ }
+
+ return true;
+}
+
+/* Parse the stabs string. */
+
+static boolean
+parse_stab_string (dhandle, info, stabtype, desc, value, string)
+ PTR dhandle;
+ struct stab_handle *info;
+ int stabtype;
+ int desc;
+ bfd_vma value;
+ const char *string;
+{
+ const char *p;
+ char *name;
+ int type;
+ debug_type dtype;
+ boolean synonym;
+ unsigned int lineno;
+ debug_type *slot;
+
+ p = strchr (string, ':');
+ if (p == NULL)
+ return true;
+
+ while (p[1] == ':')
+ {
+ p += 2;
+ p = strchr (p, ':');
+ if (p == NULL)
+ {
+ bad_stab (string);
+ return false;
+ }
+ }
+
+ /* GCC 2.x puts the line number in desc. SunOS apparently puts in
+ the number of bytes occupied by a type or object, which we
+ ignore. */
+ if (info->gcc_compiled >= 2)
+ lineno = desc;
+ else
+ lineno = 0;
+
+ /* FIXME: Sometimes the special C++ names start with '.'. */
+ name = NULL;
+ if (string[0] == '$')
+ {
+ switch (string[1])
+ {
+ case 't':
+ name = "this";
+ break;
+ case 'v':
+ /* Was: name = "vptr"; */
+ break;
+ case 'e':
+ name = "eh_throw";
+ break;
+ case '_':
+ /* This was an anonymous type that was never fixed up. */
+ break;
+ case 'X':
+ /* SunPRO (3.0 at least) static variable encoding. */
+ break;
+ default:
+ warn_stab (string, "unknown C++ encoded name");
+ break;
+ }
+ }
+
+ if (name == NULL)
+ {
+ if (p == string || (string[0] == ' ' && p == string + 1))
+ name = NULL;
+ else
+ name = savestring (string, p - string);
+ }
+
+ ++p;
+ if (isdigit ((unsigned char) *p) || *p == '(' || *p == '-')
+ type = 'l';
+ else
+ type = *p++;
+
+ switch (type)
+ {
+ case 'c':
+ /* c is a special case, not followed by a type-number.
+ SYMBOL:c=iVALUE for an integer constant symbol.
+ SYMBOL:c=rVALUE for a floating constant symbol.
+ SYMBOL:c=eTYPE,INTVALUE for an enum constant symbol.
+ e.g. "b:c=e6,0" for "const b = blob1"
+ (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;"). */
+ if (*p != '=')
+ {
+ bad_stab (string);
+ return false;
+ }
+ ++p;
+ switch (*p++)
+ {
+ case 'r':
+ /* Floating point constant. */
+ if (! debug_record_float_const (dhandle, name, atof (p)))
+ return false;
+ break;
+ case 'i':
+ /* Integer constant. */
+ /* Defining integer constants this way is kind of silly,
+ since 'e' constants allows the compiler to give not only
+ the value, but the type as well. C has at least int,
+ long, unsigned int, and long long as constant types;
+ other languages probably should have at least unsigned as
+ well as signed constants. */
+ if (! debug_record_int_const (dhandle, name, atoi (p)))
+ return false;
+ break;
+ case 'e':
+ /* SYMBOL:c=eTYPE,INTVALUE for a constant symbol whose value
+ can be represented as integral.
+ e.g. "b:c=e6,0" for "const b = blob1"
+ (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;"). */
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL,
+ &p, (debug_type **) NULL);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (*p != ',')
+ {
+ bad_stab (string);
+ return false;
+ }
+ if (! debug_record_typed_const (dhandle, name, dtype, atoi (p)))
+ return false;
+ break;
+ default:
+ bad_stab (string);
+ return false;
+ }
+
+ break;
+
+ case 'C':
+ /* The name of a caught exception. */
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL,
+ &p, (debug_type **) NULL);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (! debug_record_label (dhandle, name, dtype, value))
+ return false;
+ break;
+
+ case 'f':
+ case 'F':
+ /* A function definition. */
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (! debug_record_function (dhandle, name, dtype, type == 'F', value))
+ return false;
+
+ /* Sun acc puts declared types of arguments here. We don't care
+ about their actual types (FIXME -- we should remember the whole
+ function prototype), but the list may define some new types
+ that we have to remember, so we must scan it now. */
+ while (*p == ';')
+ {
+ ++p;
+ if (parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL)
+ == DEBUG_TYPE_NULL)
+ return false;
+ }
+
+ break;
+
+ case 'G':
+ {
+ char leading;
+ long c;
+ asymbol **ps;
+
+ /* A global symbol. The value must be extracted from the
+ symbol table. */
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ leading = bfd_get_symbol_leading_char (info->abfd);
+ for (c = info->symcount, ps = info->syms; c > 0; --c, ++ps)
+ {
+ const char *n;
+
+ n = bfd_asymbol_name (*ps);
+ if (leading != '\0' && *n == leading)
+ ++n;
+ if (*n == *name && strcmp (n, name) == 0)
+ break;
+ }
+ if (c > 0)
+ value = bfd_asymbol_value (*ps);
+ if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_GLOBAL,
+ value))
+ return false;
+ }
+ break;
+
+ /* This case is faked by a conditional above, when there is no
+ code letter in the dbx data. Dbx data never actually
+ contains 'l'. */
+ case 'l':
+ case 's':
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_LOCAL,
+ value))
+ return false;
+ break;
+
+ case 'p':
+ /* A function parameter. */
+ if (*p != 'F')
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
+ else
+ {
+ /* pF is a two-letter code that means a function parameter in
+ Fortran. The type-number specifies the type of the return
+ value. Translate it into a pointer-to-function type. */
+ ++p;
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
+ if (dtype != DEBUG_TYPE_NULL)
+ {
+ debug_type ftype;
+
+ ftype = debug_make_function_type (dhandle, dtype,
+ (debug_type *) NULL, false);
+ dtype = debug_make_pointer_type (dhandle, ftype);
+ }
+ }
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_STACK,
+ value))
+ return false;
+
+ /* FIXME: At this point gdb considers rearranging the parameter
+ address on a big endian machine if it is smaller than an int.
+ We have no way to do that, since we don't really know much
+ about the target. */
+
+ break;
+
+ case 'P':
+ if (stabtype == N_FUN)
+ {
+ /* Prototype of a function referenced by this file. */
+ while (*p == ';')
+ {
+ ++p;
+ if (parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL)
+ == DEBUG_TYPE_NULL)
+ return false;
+ }
+ break;
+ }
+ /* Fall through. */
+ case 'R':
+ /* Parameter which is in a register. */
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REG,
+ value))
+ return false;
+ break;
+
+ case 'r':
+ /* Register variable (either global or local). */
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_REGISTER,
+ value))
+ return false;
+
+ /* FIXME: At this point gdb checks to combine pairs of 'p' and
+ 'r' stabs into a single 'P' stab. */
+
+ break;
+
+ case 'S':
+ /* Static symbol at top level of file */
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_STATIC,
+ value))
+ return false;
+ break;
+
+ case 't':
+ /* A typedef. */
+ dtype = parse_stab_type (dhandle, info, name, &p, &slot);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (name == NULL)
+ {
+ /* A nameless type. Nothing to do. */
+ return true;
+ }
+
+ dtype = debug_name_type (dhandle, name, dtype);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+
+ if (slot != NULL)
+ *slot = dtype;
+
+ break;
+
+ case 'T':
+ /* Struct, union, or enum tag. For GNU C++, this can be be followed
+ by 't' which means we are typedef'ing it as well. */
+ if (*p != 't')
+ {
+ synonym = false;
+ /* FIXME: gdb sets synonym to true if the current language
+ is C++. */
+ }
+ else
+ {
+ synonym = true;
+ ++p;
+ }
+
+ dtype = parse_stab_type (dhandle, info, name, &p, &slot);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (name == NULL)
+ return true;
+
+ dtype = debug_tag_type (dhandle, name, dtype);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (slot != NULL)
+ *slot = dtype;
+
+ /* See if we have a cross reference to this tag which we can now
+ fill in. */
+ {
+ register struct stab_tag **pst;
+
+ for (pst = &info->tags; *pst != NULL; pst = &(*pst)->next)
+ {
+ if ((*pst)->name[0] == name[0]
+ && strcmp ((*pst)->name, name) == 0)
+ {
+ (*pst)->slot = dtype;
+ *pst = (*pst)->next;
+ break;
+ }
+ }
+ }
+
+ if (synonym)
+ {
+ dtype = debug_name_type (dhandle, name, dtype);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+
+ if (slot != NULL)
+ *slot = dtype;
+ }
+
+ break;
+
+ case 'V':
+ /* Static symbol of local scope */
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ /* FIXME: gdb checks os9k_stabs here. */
+ if (! stab_record_variable (dhandle, info, name, dtype,
+ DEBUG_LOCAL_STATIC, value))
+ return false;
+ break;
+
+ case 'v':
+ /* Reference parameter. */
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REFERENCE,
+ value))
+ return false;
+ break;
+
+ case 'a':
+ /* Reference parameter which is in a register. */
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REF_REG,
+ value))
+ return false;
+ break;
+
+ case 'X':
+ /* This is used by Sun FORTRAN for "function result value".
+ Sun claims ("dbx and dbxtool interfaces", 2nd ed)
+ that Pascal uses it too, but when I tried it Pascal used
+ "x:3" (local symbol) instead. */
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_LOCAL,
+ value))
+ return false;
+ break;
+
+ default:
+ bad_stab (string);
+ return false;
+ }
+
+ /* FIXME: gdb converts structure values to structure pointers in a
+ couple of cases, depending upon the target. */
+
+ return true;
+}
+
+/* Parse a stabs type. The typename argument is non-NULL if this is a
+ typedef or a tag definition. The pp argument points to the stab
+ string, and is updated. The slotp argument points to a place to
+ store the slot used if the type is being defined. */
+
+static debug_type
+parse_stab_type (dhandle, info, typename, pp, slotp)
+ PTR dhandle;
+ struct stab_handle *info;
+ const char *typename;
+ const char **pp;
+ debug_type **slotp;
+{
+ const char *orig;
+ int typenums[2];
+ int size;
+ boolean stringp;
+ int descriptor;
+ debug_type dtype;
+
+ if (slotp != NULL)
+ *slotp = NULL;
+
+ orig = *pp;
+
+ size = -1;
+ stringp = false;
+
+ /* Read type number if present. The type number may be omitted.
+ for instance in a two-dimensional array declared with type
+ "ar1;1;10;ar1;1;10;4". */
+ if (! isdigit ((unsigned char) **pp) && **pp != '(' && **pp != '-')
+ {
+ /* 'typenums=' not present, type is anonymous. Read and return
+ the definition, but don't put it in the type vector. */
+ typenums[0] = typenums[1] = -1;
+ }
+ else
+ {
+ if (! parse_stab_type_number (pp, typenums))
+ return DEBUG_TYPE_NULL;
+
+ if (**pp != '=')
+ {
+ /* Type is not being defined here. Either it already
+ exists, or this is a forward reference to it. */
+ return stab_find_type (dhandle, info, typenums);
+ }
+
+ /* Only set the slot if the type is being defined. This means
+ that the mapping from type numbers to types will only record
+ the name of the typedef which defines a type. If we don't do
+ this, then something like
+ typedef int foo;
+ int i;
+ will record that i is of type foo. Unfortunately, stabs
+ information is ambiguous about variable types. For this code,
+ typedef int foo;
+ int i;
+ foo j;
+ the stabs information records both i and j as having the same
+ type. This could be fixed by patching the compiler. */
+ if (slotp != NULL && typenums[0] >= 0 && typenums[1] >= 0)
+ *slotp = stab_find_slot (info, typenums);
+
+ /* Type is being defined here. */
+ /* Skip the '='. */
+ ++*pp;
+
+ while (**pp == '@')
+ {
+ const char *p = *pp + 1;
+ const char *attr;
+
+ if (isdigit ((unsigned char) *p) || *p == '(' || *p == '-')
+ {
+ /* Member type. */
+ break;
+ }
+
+ /* Type attributes. */
+ attr = p;
+
+ for (; *p != ';'; ++p)
+ {
+ if (*p == '\0')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ }
+ *pp = p + 1;
+
+ switch (*attr)
+ {
+ case 's':
+ size = atoi (attr + 1);
+ if (size <= 0)
+ size = -1;
+ break;
+
+ case 'S':
+ stringp = true;
+ break;
+
+ default:
+ /* Ignore unrecognized type attributes, so future
+ compilers can invent new ones. */
+ break;
+ }
+ }
+ }
+
+ descriptor = **pp;
+ ++*pp;
+
+ switch (descriptor)
+ {
+ case 'x':
+ {
+ enum debug_type_kind code;
+ const char *q1, *q2, *p;
+
+ /* A cross reference to another type. */
+
+ switch (**pp)
+ {
+ case 's':
+ code = DEBUG_KIND_STRUCT;
+ break;
+ case 'u':
+ code = DEBUG_KIND_UNION;
+ break;
+ case 'e':
+ code = DEBUG_KIND_ENUM;
+ break;
+ default:
+ /* Complain and keep going, so compilers can invent new
+ cross-reference types. */
+ warn_stab (orig, "unrecognized cross reference type");
+ code = DEBUG_KIND_STRUCT;
+ break;
+ }
+ ++*pp;
+
+ q1 = strchr (*pp, '<');
+ p = strchr (*pp, ':');
+ if (p == NULL)
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ while (q1 != NULL && p > q1 && p[1] == ':')
+ {
+ q2 = strchr (q1, '>');
+ if (q2 == NULL || q2 < p)
+ break;
+ p += 2;
+ p = strchr (p, ':');
+ if (p == NULL)
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ }
+
+ dtype = stab_find_tagged_type (dhandle, info, *pp, p - *pp, code);
+
+ *pp = p + 1;
+ }
+ break;
+
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '(':
+ {
+ const char *hold;
+ int xtypenums[2];
+
+ /* This type is defined as another type. */
+
+ (*pp)--;
+ hold = *pp;
+
+ /* Peek ahead at the number to detect void. */
+ if (! parse_stab_type_number (pp, xtypenums))
+ return DEBUG_TYPE_NULL;
+
+ if (typenums[0] == xtypenums[0] && typenums[1] == xtypenums[1])
+ {
+ /* This type is being defined as itself, which means that
+ it is void. */
+ dtype = debug_make_void_type (dhandle);
+ }
+ else
+ {
+ *pp = hold;
+
+ /* Go back to the number and have parse_stab_type get it.
+ This means that we can deal with something like
+ t(1,2)=(3,4)=... which the Lucid compiler uses. */
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL,
+ pp, (debug_type **) NULL);
+ if (dtype == DEBUG_TYPE_NULL)
+ return DEBUG_TYPE_NULL;
+ }
+
+ if (typenums[0] != -1)
+ {
+ if (! stab_record_type (dhandle, info, typenums, dtype))
+ return DEBUG_TYPE_NULL;
+ }
+
+ break;
+ }
+
+ case '*':
+ dtype = debug_make_pointer_type (dhandle,
+ parse_stab_type (dhandle, info,
+ (const char *) NULL,
+ pp,
+ (debug_type **) NULL));
+ break;
+
+ case '&':
+ /* Reference to another type. */
+ dtype = (debug_make_reference_type
+ (dhandle,
+ parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL)));
+ break;
+
+ case 'f':
+ /* Function returning another type. */
+ /* FIXME: gdb checks os9k_stabs here. */
+ dtype = (debug_make_function_type
+ (dhandle,
+ parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL),
+ (debug_type *) NULL, false));
+ break;
+
+ case 'k':
+ /* Const qualifier on some type (Sun). */
+ /* FIXME: gdb accepts 'c' here if os9k_stabs. */
+ dtype = debug_make_const_type (dhandle,
+ parse_stab_type (dhandle, info,
+ (const char *) NULL,
+ pp,
+ (debug_type **) NULL));
+ break;
+
+ case 'B':
+ /* Volatile qual on some type (Sun). */
+ /* FIXME: gdb accepts 'i' here if os9k_stabs. */
+ dtype = (debug_make_volatile_type
+ (dhandle,
+ parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL)));
+ break;
+
+ case '@':
+ /* Offset (class & variable) type. This is used for a pointer
+ relative to an object. */
+ {
+ debug_type domain;
+ debug_type memtype;
+
+ /* Member type. */
+
+ domain = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
+ if (domain == DEBUG_TYPE_NULL)
+ return DEBUG_TYPE_NULL;
+
+ if (**pp != ',')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+
+ memtype = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
+ if (memtype == DEBUG_TYPE_NULL)
+ return DEBUG_TYPE_NULL;
+
+ dtype = debug_make_offset_type (dhandle, domain, memtype);
+ }
+ break;
+
+ case '#':
+ /* Method (class & fn) type. */
+ if (**pp == '#')
+ {
+ debug_type return_type;
+
+ ++*pp;
+ return_type = parse_stab_type (dhandle, info, (const char *) NULL,
+ pp, (debug_type **) NULL);
+ if (return_type == DEBUG_TYPE_NULL)
+ return DEBUG_TYPE_NULL;
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+ dtype = debug_make_method_type (dhandle, return_type,
+ DEBUG_TYPE_NULL,
+ (debug_type *) NULL, false);
+ }
+ else
+ {
+ debug_type domain;
+ debug_type return_type;
+ debug_type *args;
+ unsigned int n;
+ unsigned int alloc;
+ boolean varargs;
+
+ domain = parse_stab_type (dhandle, info, (const char *) NULL,
+ pp, (debug_type **) NULL);
+ if (domain == DEBUG_TYPE_NULL)
+ return DEBUG_TYPE_NULL;
+
+ if (**pp != ',')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+
+ return_type = parse_stab_type (dhandle, info, (const char *) NULL,
+ pp, (debug_type **) NULL);
+ if (return_type == DEBUG_TYPE_NULL)
+ return DEBUG_TYPE_NULL;
+
+ alloc = 10;
+ args = (debug_type *) xmalloc (alloc * sizeof *args);
+ n = 0;
+ while (**pp != ';')
+ {
+ if (**pp != ',')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+
+ if (n + 1 >= alloc)
+ {
+ alloc += 10;
+ args = ((debug_type *)
+ xrealloc ((PTR) args, alloc * sizeof *args));
+ }
+
+ args[n] = parse_stab_type (dhandle, info, (const char *) NULL,
+ pp, (debug_type **) NULL);
+ if (args[n] == DEBUG_TYPE_NULL)
+ return DEBUG_TYPE_NULL;
+ ++n;
+ }
+ ++*pp;
+
+ /* If the last type is not void, then this function takes a
+ variable number of arguments. Otherwise, we must strip
+ the void type. */
+ if (n == 0
+ || debug_get_type_kind (dhandle, args[n - 1]) != DEBUG_KIND_VOID)
+ varargs = true;
+ else
+ {
+ --n;
+ varargs = false;
+ }
+
+ args[n] = DEBUG_TYPE_NULL;
+
+ dtype = debug_make_method_type (dhandle, return_type, domain, args,
+ varargs);
+ }
+ break;
+
+ case 'r':
+ /* Range type. */
+ dtype = parse_stab_range_type (dhandle, info, typename, pp, typenums);
+ break;
+
+ case 'b':
+ /* FIXME: gdb checks os9k_stabs here. */
+ /* Sun ACC builtin int type. */
+ dtype = parse_stab_sun_builtin_type (dhandle, pp);
+ break;
+
+ case 'R':
+ /* Sun ACC builtin float type. */
+ dtype = parse_stab_sun_floating_type (dhandle, pp);
+ break;
+
+ case 'e':
+ /* Enumeration type. */
+ dtype = parse_stab_enum_type (dhandle, pp);
+ break;
+
+ case 's':
+ case 'u':
+ /* Struct or union type. */
+ dtype = parse_stab_struct_type (dhandle, info, typename, pp,
+ descriptor == 's', typenums);
+ break;
+
+ case 'a':
+ /* Array type. */
+ if (**pp != 'r')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+
+ dtype = parse_stab_array_type (dhandle, info, pp, stringp);
+ break;
+
+ case 'S':
+ dtype = debug_make_set_type (dhandle,
+ parse_stab_type (dhandle, info,
+ (const char *) NULL,
+ pp,
+ (debug_type **) NULL),
+ stringp);
+ break;
+
+ default:
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+
+ if (dtype == DEBUG_TYPE_NULL)
+ return DEBUG_TYPE_NULL;
+
+ if (typenums[0] != -1)
+ {
+ if (! stab_record_type (dhandle, info, typenums, dtype))
+ return DEBUG_TYPE_NULL;
+ }
+
+ if (size != -1)
+ {
+ if (! debug_record_type_size (dhandle, dtype, (unsigned int) size))
+ return DEBUG_TYPE_NULL;
+ }
+
+ return dtype;
+}
+
+/* Read a number by which a type is referred to in dbx data, or
+ perhaps read a pair (FILENUM, TYPENUM) in parentheses. Just a
+ single number N is equivalent to (0,N). Return the two numbers by
+ storing them in the vector TYPENUMS. */
+
+static boolean
+parse_stab_type_number (pp, typenums)
+ const char **pp;
+ int *typenums;
+{
+ const char *orig;
+
+ orig = *pp;
+
+ if (**pp != '(')
+ {
+ typenums[0] = 0;
+ typenums[1] = (int) parse_number (pp, (boolean *) NULL);
+ }
+ else
+ {
+ ++*pp;
+ typenums[0] = (int) parse_number (pp, (boolean *) NULL);
+ if (**pp != ',')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ ++*pp;
+ typenums[1] = (int) parse_number (pp, (boolean *) NULL);
+ if (**pp != ')')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ ++*pp;
+ }
+
+ return true;
+}
+
+/* Parse a range type. */
+
+static debug_type
+parse_stab_range_type (dhandle, info, typename, pp, typenums)
+ PTR dhandle;
+ struct stab_handle *info;
+ const char *typename;
+ const char **pp;
+ const int *typenums;
+{
+ const char *orig;
+ int rangenums[2];
+ boolean self_subrange;
+ debug_type index_type;
+ const char *s2, *s3;
+ bfd_signed_vma n2, n3;
+ boolean ov2, ov3;
+
+ orig = *pp;
+
+ index_type = DEBUG_TYPE_NULL;
+
+ /* First comes a type we are a subrange of.
+ In C it is usually 0, 1 or the type being defined. */
+ if (! parse_stab_type_number (pp, rangenums))
+ return DEBUG_TYPE_NULL;
+
+ self_subrange = (rangenums[0] == typenums[0]
+ && rangenums[1] == typenums[1]);
+
+ if (**pp == '=')
+ {
+ *pp = orig;
+ index_type = parse_stab_type (dhandle, info, (const char *) NULL,
+ pp, (debug_type **) NULL);
+ if (index_type == DEBUG_TYPE_NULL)
+ return DEBUG_TYPE_NULL;
+ }
+
+ if (**pp == ';')
+ ++*pp;
+
+ /* The remaining two operands are usually lower and upper bounds of
+ the range. But in some special cases they mean something else. */
+ s2 = *pp;
+ n2 = parse_number (pp, &ov2);
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+
+ s3 = *pp;
+ n3 = parse_number (pp, &ov3);
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+
+ if (ov2 || ov3)
+ {
+ /* gcc will emit range stabs for long long types. Handle this
+ as a special case. FIXME: This needs to be more general. */
+#define LLLOW "01000000000000000000000;"
+#define LLHIGH "0777777777777777777777;"
+#define ULLHIGH "01777777777777777777777;"
+ if (index_type == DEBUG_TYPE_NULL)
+ {
+ if (strncmp (s2, LLLOW, sizeof LLLOW - 1) == 0
+ && strncmp (s3, LLHIGH, sizeof LLHIGH - 1) == 0)
+ return debug_make_int_type (dhandle, 8, false);
+ if (! ov2
+ && n2 == 0
+ && strncmp (s3, ULLHIGH, sizeof ULLHIGH - 1) == 0)
+ return debug_make_int_type (dhandle, 8, true);
+ }
+
+ warn_stab (orig, "numeric overflow");
+ }
+
+ if (index_type == DEBUG_TYPE_NULL)
+ {
+ /* A type defined as a subrange of itself, with both bounds 0,
+ is void. */
+ if (self_subrange && n2 == 0 && n3 == 0)
+ return debug_make_void_type (dhandle);
+
+ /* A type defined as a subrange of itself, with n2 positive and
+ n3 zero, is a complex type, and n2 is the number of bytes. */
+ if (self_subrange && n3 == 0 && n2 > 0)
+ return debug_make_complex_type (dhandle, n2);
+
+ /* If n3 is zero and n2 is positive, this is a floating point
+ type, and n2 is the number of bytes. */
+ if (n3 == 0 && n2 > 0)
+ return debug_make_float_type (dhandle, n2);
+
+ /* If the upper bound is -1, this is an unsigned int. */
+ if (n2 == 0 && n3 == -1)
+ {
+ /* When gcc is used with -gstabs, but not -gstabs+, it will emit
+ long long int:t6=r1;0;-1;
+ long long unsigned int:t7=r1;0;-1;
+ We hack here to handle this reasonably. */
+ if (typename != NULL)
+ {
+ if (strcmp (typename, "long long int") == 0)
+ return debug_make_int_type (dhandle, 8, false);
+ else if (strcmp (typename, "long long unsigned int") == 0)
+ return debug_make_int_type (dhandle, 8, true);
+ }
+ /* FIXME: The size here really depends upon the target. */
+ return debug_make_int_type (dhandle, 4, true);
+ }
+
+ /* A range of 0 to 127 is char. */
+ if (self_subrange && n2 == 0 && n3 == 127)
+ return debug_make_int_type (dhandle, 1, false);
+
+ /* FIXME: gdb checks for the language CHILL here. */
+
+ if (n2 == 0)
+ {
+ if (n3 < 0)
+ return debug_make_int_type (dhandle, - n3, true);
+ else if (n3 == 0xff)
+ return debug_make_int_type (dhandle, 1, true);
+ else if (n3 == 0xffff)
+ return debug_make_int_type (dhandle, 2, true);
+ /* -1 is used for the upper bound of (4 byte) "unsigned int"
+ and "unsigned long", and we already checked for that, so
+ don't need to test for it here. */
+ }
+ else if (n3 == 0
+ && n2 < 0
+ && (self_subrange || n2 == -8))
+ return debug_make_int_type (dhandle, - n2, true);
+ else if (n2 == - n3 - 1)
+ {
+ if (n3 == 0x7f)
+ return debug_make_int_type (dhandle, 1, false);
+ else if (n3 == 0x7fff)
+ return debug_make_int_type (dhandle, 2, false);
+ else if (n3 == 0x7fffffff)
+ return debug_make_int_type (dhandle, 4, false);
+ }
+ }
+
+ /* At this point I don't have the faintest idea how to deal with a
+ self_subrange type; I'm going to assume that this is used as an
+ idiom, and that all of them are special cases. So . . . */
+ if (self_subrange)
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+
+ index_type = stab_find_type (dhandle, info, rangenums);
+ if (index_type == DEBUG_TYPE_NULL)
+ {
+ /* Does this actually ever happen? Is that why we are worrying
+ about dealing with it rather than just calling error_type? */
+ warn_stab (orig, "missing index type");
+ index_type = debug_make_int_type (dhandle, 4, false);
+ }
+
+ return debug_make_range_type (dhandle, index_type, n2, n3);
+}
+
+/* Sun's ACC uses a somewhat saner method for specifying the builtin
+ typedefs in every file (for int, long, etc):
+
+ type = b <signed> <width>; <offset>; <nbits>
+ signed = u or s. Possible c in addition to u or s (for char?).
+ offset = offset from high order bit to start bit of type.
+ width is # bytes in object of this type, nbits is # bits in type.
+
+ The width/offset stuff appears to be for small objects stored in
+ larger ones (e.g. `shorts' in `int' registers). We ignore it for now,
+ FIXME. */
+
+static debug_type
+parse_stab_sun_builtin_type (dhandle, pp)
+ PTR dhandle;
+ const char **pp;
+{
+ const char *orig;
+ boolean unsignedp;
+ bfd_vma bits;
+
+ orig = *pp;
+
+ switch (**pp)
+ {
+ case 's':
+ unsignedp = false;
+ break;
+ case 'u':
+ unsignedp = true;
+ break;
+ default:
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+
+ /* For some odd reason, all forms of char put a c here. This is strange
+ because no other type has this honor. We can safely ignore this because
+ we actually determine 'char'acterness by the number of bits specified in
+ the descriptor. */
+ if (**pp == 'c')
+ ++*pp;
+
+ /* The first number appears to be the number of bytes occupied
+ by this type, except that unsigned short is 4 instead of 2.
+ Since this information is redundant with the third number,
+ we will ignore it. */
+ (void) parse_number (pp, (boolean *) NULL);
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+
+ /* The second number is always 0, so ignore it too. */
+ (void) parse_number (pp, (boolean *) NULL);
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+
+ /* The third number is the number of bits for this type. */
+ bits = parse_number (pp, (boolean *) NULL);
+
+ /* The type *should* end with a semicolon. If it are embedded
+ in a larger type the semicolon may be the only way to know where
+ the type ends. If this type is at the end of the stabstring we
+ can deal with the omitted semicolon (but we don't have to like
+ it). Don't bother to complain(), Sun's compiler omits the semicolon
+ for "void". */
+ if (**pp == ';')
+ ++*pp;
+
+ if (bits == 0)
+ return debug_make_void_type (dhandle);
+
+ return debug_make_int_type (dhandle, bits / 8, unsignedp);
+}
+
+/* Parse a builtin floating type generated by the Sun compiler. */
+
+static debug_type
+parse_stab_sun_floating_type (dhandle, pp)
+ PTR dhandle;
+ const char **pp;
+{
+ const char *orig;
+ bfd_vma details;
+ bfd_vma bytes;
+
+ orig = *pp;
+
+ /* The first number has more details about the type, for example
+ FN_COMPLEX. */
+ details = parse_number (pp, (boolean *) NULL);
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+
+ /* The second number is the number of bytes occupied by this type */
+ bytes = parse_number (pp, (boolean *) NULL);
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+
+ if (details == NF_COMPLEX
+ || details == NF_COMPLEX16
+ || details == NF_COMPLEX32)
+ return debug_make_complex_type (dhandle, bytes);
+
+ return debug_make_float_type (dhandle, bytes);
+}
+
+/* Handle an enum type. */
+
+static debug_type
+parse_stab_enum_type (dhandle, pp)
+ PTR dhandle;
+ const char **pp;
+{
+ const char *orig;
+ const char **names;
+ bfd_signed_vma *values;
+ unsigned int n;
+ unsigned int alloc;
+
+ orig = *pp;
+
+ /* FIXME: gdb checks os9k_stabs here. */
+
+ /* The aix4 compiler emits an extra field before the enum members;
+ my guess is it's a type of some sort. Just ignore it. */
+ if (**pp == '-')
+ {
+ while (**pp != ':')
+ ++*pp;
+ ++*pp;
+ }
+
+ /* Read the value-names and their values.
+ The input syntax is NAME:VALUE,NAME:VALUE, and so on.
+ A semicolon or comma instead of a NAME means the end. */
+ alloc = 10;
+ names = (const char **) xmalloc (alloc * sizeof *names);
+ values = (bfd_signed_vma *) xmalloc (alloc * sizeof *values);
+ n = 0;
+ while (**pp != '\0' && **pp != ';' && **pp != ',')
+ {
+ const char *p;
+ char *name;
+ bfd_signed_vma val;
+
+ p = *pp;
+ while (*p != ':')
+ ++p;
+
+ name = savestring (*pp, p - *pp);
+
+ *pp = p + 1;
+ val = (bfd_signed_vma) parse_number (pp, (boolean *) NULL);
+ if (**pp != ',')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+
+ if (n + 1 >= alloc)
+ {
+ alloc += 10;
+ names = ((const char **)
+ xrealloc ((PTR) names, alloc * sizeof *names));
+ values = ((bfd_signed_vma *)
+ xrealloc ((PTR) values, alloc * sizeof *values));
+ }
+
+ names[n] = name;
+ values[n] = val;
+ ++n;
+ }
+
+ names[n] = NULL;
+ values[n] = 0;
+
+ if (**pp == ';')
+ ++*pp;
+
+ return debug_make_enum_type (dhandle, names, values);
+}
+
+/* Read the description of a structure (or union type) and return an object
+ describing the type.
+
+ PP points to a character pointer that points to the next unconsumed token
+ in the the stabs string. For example, given stabs "A:T4=s4a:1,0,32;;",
+ *PP will point to "4a:1,0,32;;". */
+
+static debug_type
+parse_stab_struct_type (dhandle, info, tagname, pp, structp, typenums)
+ PTR dhandle;
+ struct stab_handle *info;
+ const char *tagname;
+ const char **pp;
+ boolean structp;
+ const int *typenums;
+{
+ const char *orig;
+ bfd_vma size;
+ debug_baseclass *baseclasses;
+ debug_field *fields;
+ boolean statics;
+ debug_method *methods;
+ debug_type vptrbase;
+ boolean ownvptr;
+
+ orig = *pp;
+
+ /* Get the size. */
+ size = parse_number (pp, (boolean *) NULL);
+
+ /* Get the other information. */
+ if (! parse_stab_baseclasses (dhandle, info, pp, &baseclasses)
+ || ! parse_stab_struct_fields (dhandle, info, pp, &fields, &statics)
+ || ! parse_stab_members (dhandle, info, tagname, pp, typenums, &methods)
+ || ! parse_stab_tilde_field (dhandle, info, pp, typenums, &vptrbase,
+ &ownvptr))
+ return DEBUG_TYPE_NULL;
+
+ if (! statics
+ && baseclasses == NULL
+ && methods == NULL
+ && vptrbase == DEBUG_TYPE_NULL
+ && ! ownvptr)
+ return debug_make_struct_type (dhandle, structp, size, fields);
+
+ return debug_make_object_type (dhandle, structp, size, fields, baseclasses,
+ methods, vptrbase, ownvptr);
+}
+
+/* The stabs for C++ derived classes contain baseclass information which
+ is marked by a '!' character after the total size. This function is
+ called when we encounter the baseclass marker, and slurps up all the
+ baseclass information.
+
+ Immediately following the '!' marker is the number of base classes that
+ the class is derived from, followed by information for each base class.
+ For each base class, there are two visibility specifiers, a bit offset
+ to the base class information within the derived class, a reference to
+ the type for the base class, and a terminating semicolon.
+
+ A typical example, with two base classes, would be "!2,020,19;0264,21;".
+ ^^ ^ ^ ^ ^ ^ ^
+ Baseclass information marker __________________|| | | | | | |
+ Number of baseclasses __________________________| | | | | | |
+ Visibility specifiers (2) ________________________| | | | | |
+ Offset in bits from start of class _________________| | | | |
+ Type number for base class ___________________________| | | |
+ Visibility specifiers (2) _______________________________| | |
+ Offset in bits from start of class ________________________| |
+ Type number of base class ____________________________________|
+
+ Return true for success, false for failure. */
+
+static boolean
+parse_stab_baseclasses (dhandle, info, pp, retp)
+ PTR dhandle;
+ struct stab_handle *info;
+ const char **pp;
+ debug_baseclass **retp;
+{
+ const char *orig;
+ unsigned int c, i;
+ debug_baseclass *classes;
+
+ *retp = NULL;
+
+ orig = *pp;
+
+ if (**pp != '!')
+ {
+ /* No base classes. */
+ return true;
+ }
+ ++*pp;
+
+ c = (unsigned int) parse_number (pp, (boolean *) NULL);
+
+ if (**pp != ',')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ ++*pp;
+
+ classes = (debug_baseclass *) xmalloc ((c + 1) * sizeof (**retp));
+
+ for (i = 0; i < c; i++)
+ {
+ boolean virtual;
+ enum debug_visibility visibility;
+ bfd_vma bitpos;
+ debug_type type;
+
+ switch (**pp)
+ {
+ case '0':
+ virtual = false;
+ break;
+ case '1':
+ virtual = true;
+ break;
+ default:
+ warn_stab (orig, "unknown virtual character for baseclass");
+ virtual = false;
+ break;
+ }
+ ++*pp;
+
+ switch (**pp)
+ {
+ case '0':
+ visibility = DEBUG_VISIBILITY_PRIVATE;
+ break;
+ case '1':
+ visibility = DEBUG_VISIBILITY_PROTECTED;
+ break;
+ case '2':
+ visibility = DEBUG_VISIBILITY_PUBLIC;
+ break;
+ default:
+ warn_stab (orig, "unknown visibility character for baseclass");
+ visibility = DEBUG_VISIBILITY_PUBLIC;
+ break;
+ }
+ ++*pp;
+
+ /* The remaining value is the bit offset of the portion of the
+ object corresponding to this baseclass. Always zero in the
+ absence of multiple inheritance. */
+ bitpos = parse_number (pp, (boolean *) NULL);
+ if (**pp != ',')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ ++*pp;
+
+ type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
+ if (type == DEBUG_TYPE_NULL)
+ return false;
+
+ classes[i] = debug_make_baseclass (dhandle, type, bitpos, virtual,
+ visibility);
+ if (classes[i] == DEBUG_BASECLASS_NULL)
+ return false;
+
+ if (**pp != ';')
+ return false;
+ ++*pp;
+ }
+
+ classes[i] = DEBUG_BASECLASS_NULL;
+
+ *retp = classes;
+
+ return true;
+}
+
+/* Read struct or class data fields. They have the form:
+
+ NAME : [VISIBILITY] TYPENUM , BITPOS , BITSIZE ;
+
+ At the end, we see a semicolon instead of a field.
+
+ In C++, this may wind up being NAME:?TYPENUM:PHYSNAME; for
+ a static field.
+
+ The optional VISIBILITY is one of:
+
+ '/0' (VISIBILITY_PRIVATE)
+ '/1' (VISIBILITY_PROTECTED)
+ '/2' (VISIBILITY_PUBLIC)
+ '/9' (VISIBILITY_IGNORE)
+
+ or nothing, for C style fields with public visibility.
+
+ Returns 1 for success, 0 for failure. */
+
+static boolean
+parse_stab_struct_fields (dhandle, info, pp, retp, staticsp)
+ PTR dhandle;
+ struct stab_handle *info;
+ const char **pp;
+ debug_field **retp;
+ boolean *staticsp;
+{
+ const char *orig;
+ const char *p;
+ debug_field *fields;
+ unsigned int c;
+ unsigned int alloc;
+
+ *retp = NULL;
+ *staticsp = false;
+
+ orig = *pp;
+
+ c = 0;
+ alloc = 10;
+ fields = (debug_field *) xmalloc (alloc * sizeof *fields);
+ while (**pp != ';')
+ {
+ /* FIXME: gdb checks os9k_stabs here. */
+
+ p = *pp;
+
+ /* Add 1 to c to leave room for NULL pointer at end. */
+ if (c + 1 >= alloc)
+ {
+ alloc += 10;
+ fields = ((debug_field *)
+ xrealloc ((PTR) fields, alloc * sizeof *fields));
+ }
+
+ /* If it starts with CPLUS_MARKER it is a special abbreviation,
+ unless the CPLUS_MARKER is followed by an underscore, in
+ which case it is just the name of an anonymous type, which we
+ should handle like any other type name. We accept either '$'
+ or '.', because a field name can never contain one of these
+ characters except as a CPLUS_MARKER. */
+
+ if ((*p == '$' || *p == '.') && p[1] != '_')
+ {
+ ++*pp;
+ if (! parse_stab_cpp_abbrev (dhandle, info, pp, fields + c))
+ return false;
+ ++c;
+ continue;
+ }
+
+ /* Look for the ':' that separates the field name from the field
+ values. Data members are delimited by a single ':', while member
+ functions are delimited by a pair of ':'s. When we hit the member
+ functions (if any), terminate scan loop and return. */
+
+ p = strchr (p, ':');
+ if (p == NULL)
+ {
+ bad_stab (orig);
+ return false;
+ }
+
+ if (p[1] == ':')
+ break;
+
+ if (! parse_stab_one_struct_field (dhandle, info, pp, p, fields + c,
+ staticsp))
+ return false;
+
+ ++c;
+ }
+
+ fields[c] = DEBUG_FIELD_NULL;
+
+ *retp = fields;
+
+ return true;
+}
+
+/* Special GNU C++ name. */
+
+static boolean
+parse_stab_cpp_abbrev (dhandle, info, pp, retp)
+ PTR dhandle;
+ struct stab_handle *info;
+ const char **pp;
+ debug_field *retp;
+{
+ const char *orig;
+ int cpp_abbrev;
+ debug_type context;
+ const char *name;
+ const char *typename;
+ debug_type type;
+ bfd_vma bitpos;
+
+ *retp = DEBUG_FIELD_NULL;
+
+ orig = *pp;
+
+ if (**pp != 'v')
+ {
+ bad_stab (*pp);
+ return false;
+ }
+ ++*pp;
+
+ cpp_abbrev = **pp;
+ ++*pp;
+
+ /* At this point, *pp points to something like "22:23=*22...", where
+ the type number before the ':' is the "context" and everything
+ after is a regular type definition. Lookup the type, find it's
+ name, and construct the field name. */
+
+ context = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
+ if (context == DEBUG_TYPE_NULL)
+ return false;
+
+ switch (cpp_abbrev)
+ {
+ case 'f':
+ /* $vf -- a virtual function table pointer. */
+ name = "_vptr$";
+ break;
+ case 'b':
+ /* $vb -- a virtual bsomethingorother */
+ typename = debug_get_type_name (dhandle, context);
+ if (typename == NULL)
+ {
+ warn_stab (orig, "unnamed $vb type");
+ typename = "FOO";
+ }
+ name = concat ("_vb$", typename, (const char *) NULL);
+ break;
+ default:
+ warn_stab (orig, "unrecognized C++ abbreviation");
+ name = "INVALID_CPLUSPLUS_ABBREV";
+ break;
+ }
+
+ if (**pp != ':')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ ++*pp;
+
+ type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
+ if (**pp != ',')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ ++*pp;
+
+ bitpos = parse_number (pp, (boolean *) NULL);
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ ++*pp;
+
+ *retp = debug_make_field (dhandle, name, type, bitpos, 0,
+ DEBUG_VISIBILITY_PRIVATE);
+ if (*retp == DEBUG_FIELD_NULL)
+ return false;
+
+ return true;
+}
+
+/* Parse a single field in a struct or union. */
+
+static boolean
+parse_stab_one_struct_field (dhandle, info, pp, p, retp, staticsp)
+ PTR dhandle;
+ struct stab_handle *info;
+ const char **pp;
+ const char *p;
+ debug_field *retp;
+ boolean *staticsp;
+{
+ const char *orig;
+ char *name;
+ enum debug_visibility visibility;
+ debug_type type;
+ bfd_vma bitpos;
+ bfd_vma bitsize;
+
+ orig = *pp;
+
+ /* FIXME: gdb checks ARM_DEMANGLING here. */
+
+ name = savestring (*pp, p - *pp);
+
+ *pp = p + 1;
+
+ if (**pp != '/')
+ visibility = DEBUG_VISIBILITY_PUBLIC;
+ else
+ {
+ ++*pp;
+ switch (**pp)
+ {
+ case '0':
+ visibility = DEBUG_VISIBILITY_PRIVATE;
+ break;
+ case '1':
+ visibility = DEBUG_VISIBILITY_PROTECTED;
+ break;
+ case '2':
+ visibility = DEBUG_VISIBILITY_PUBLIC;
+ break;
+ default:
+ warn_stab (orig, "unknown visibility character for field");
+ visibility = DEBUG_VISIBILITY_PUBLIC;
+ break;
+ }
+ ++*pp;
+ }
+
+ type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
+ if (type == DEBUG_TYPE_NULL)
+ return false;
+
+ if (**pp == ':')
+ {
+ char *varname;
+
+ /* This is a static class member. */
+ ++*pp;
+ p = strchr (*pp, ';');
+ if (p == NULL)
+ {
+ bad_stab (orig);
+ return false;
+ }
+
+ varname = savestring (*pp, p - *pp);
+
+ *pp = p + 1;
+
+ *retp = debug_make_static_member (dhandle, name, type, varname,
+ visibility);
+ *staticsp = true;
+
+ return true;
+ }
+
+ if (**pp != ',')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ ++*pp;
+
+ bitpos = parse_number (pp, (boolean *) NULL);
+ if (**pp != ',')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ ++*pp;
+
+ bitsize = parse_number (pp, (boolean *) NULL);
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ ++*pp;
+
+ if (bitpos == 0 && bitsize == 0)
+ {
+ /* This can happen in two cases: (1) at least for gcc 2.4.5 or
+ so, it is a field which has been optimized out. The correct
+ stab for this case is to use VISIBILITY_IGNORE, but that is a
+ recent invention. (2) It is a 0-size array. For example
+ union { int num; char str[0]; } foo. Printing "<no value>"
+ for str in "p foo" is OK, since foo.str (and thus foo.str[3])
+ will continue to work, and a 0-size array as a whole doesn't
+ have any contents to print.
+
+ I suspect this probably could also happen with gcc -gstabs
+ (not -gstabs+) for static fields, and perhaps other C++
+ extensions. Hopefully few people use -gstabs with gdb, since
+ it is intended for dbx compatibility. */
+ visibility = DEBUG_VISIBILITY_IGNORE;
+ }
+
+ /* FIXME: gdb does some stuff here to mark fields as unpacked. */
+
+ *retp = debug_make_field (dhandle, name, type, bitpos, bitsize, visibility);
+
+ return true;
+}
+
+/* Read member function stabs info for C++ classes. The form of each member
+ function data is:
+
+ NAME :: TYPENUM[=type definition] ARGS : PHYSNAME ;
+
+ An example with two member functions is:
+
+ afunc1::20=##15;:i;2A.;afunc2::20:i;2A.;
+
+ For the case of overloaded operators, the format is op$::*.funcs, where
+ $ is the CPLUS_MARKER (usually '$'), `*' holds the place for an operator
+ name (such as `+=') and `.' marks the end of the operator name. */
+
+static boolean
+parse_stab_members (dhandle, info, tagname, pp, typenums, retp)
+ PTR dhandle;
+ struct stab_handle *info;
+ const char *tagname;
+ const char **pp;
+ const int *typenums;
+ debug_method **retp;
+{
+ const char *orig;
+ debug_method *methods;
+ unsigned int c;
+ unsigned int alloc;
+
+ *retp = NULL;
+
+ orig = *pp;
+
+ alloc = 0;
+ methods = NULL;
+ c = 0;
+
+ while (**pp != ';')
+ {
+ const char *p;
+ char *name;
+ debug_method_variant *variants;
+ unsigned int cvars;
+ unsigned int allocvars;
+ debug_type look_ahead_type;
+
+ p = strchr (*pp, ':');
+ if (p == NULL || p[1] != ':')
+ break;
+
+ /* FIXME: Some systems use something other than '$' here. */
+ if ((*pp)[0] != 'o' || (*pp)[1] != 'p' || (*pp)[2] != '$')
+ {
+ name = savestring (*pp, p - *pp);
+ *pp = p + 2;
+ }
+ else
+ {
+ /* This is a completely wierd case. In order to stuff in the
+ names that might contain colons (the usual name delimiter),
+ Mike Tiemann defined a different name format which is
+ signalled if the identifier is "op$". In that case, the
+ format is "op$::XXXX." where XXXX is the name. This is
+ used for names like "+" or "=". YUUUUUUUK! FIXME! */
+ *pp = p + 2;
+ for (p = *pp; *p != '.' && *p != '\0'; p++)
+ ;
+ if (*p != '.')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ name = savestring (*pp, p - *pp);
+ *pp = p + 1;
+ }
+
+ allocvars = 10;
+ variants = ((debug_method_variant *)
+ xmalloc (allocvars * sizeof *variants));
+ cvars = 0;
+
+ look_ahead_type = DEBUG_TYPE_NULL;
+
+ do
+ {
+ debug_type type;
+ boolean stub;
+ char *argtypes;
+ enum debug_visibility visibility;
+ boolean constp, volatilep, staticp;
+ bfd_vma voffset;
+ debug_type context;
+ const char *physname;
+ boolean varargs;
+
+ if (look_ahead_type != DEBUG_TYPE_NULL)
+ {
+ /* g++ version 1 kludge */
+ type = look_ahead_type;
+ look_ahead_type = DEBUG_TYPE_NULL;
+ }
+ else
+ {
+ type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
+ if (type == DEBUG_TYPE_NULL)
+ return false;
+ if (**pp != ':')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ }
+
+ ++*pp;
+ p = strchr (*pp, ';');
+ if (p == NULL)
+ {
+ bad_stab (orig);
+ return false;
+ }
+
+ stub = false;
+ if (debug_get_type_kind (dhandle, type) == DEBUG_KIND_METHOD
+ && debug_get_parameter_types (dhandle, type, &varargs) == NULL)
+ stub = true;
+
+ argtypes = savestring (*pp, p - *pp);
+ *pp = p + 1;
+
+ switch (**pp)
+ {
+ case '0':
+ visibility = DEBUG_VISIBILITY_PRIVATE;
+ break;
+ case '1':
+ visibility = DEBUG_VISIBILITY_PROTECTED;
+ break;
+ default:
+ visibility = DEBUG_VISIBILITY_PUBLIC;
+ break;
+ }
+ ++*pp;
+
+ constp = false;
+ volatilep = false;
+ switch (**pp)
+ {
+ case 'A':
+ /* Normal function. */
+ ++*pp;
+ break;
+ case 'B':
+ /* const member function. */
+ constp = true;
+ ++*pp;
+ break;
+ case 'C':
+ /* volatile member function. */
+ volatilep = true;
+ ++*pp;
+ break;
+ case 'D':
+ /* const volatile member function. */
+ constp = true;
+ volatilep = true;
+ ++*pp;
+ break;
+ case '*':
+ case '?':
+ case '.':
+ /* File compiled with g++ version 1; no information. */
+ break;
+ default:
+ warn_stab (orig, "const/volatile indicator missing");
+ break;
+ }
+
+ staticp = false;
+ switch (**pp)
+ {
+ case '*':
+ /* virtual member function, followed by index. The sign
+ bit is supposedly set to distinguish
+ pointers-to-methods from virtual function indicies. */
+ ++*pp;
+ voffset = parse_number (pp, (boolean *) NULL);
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ ++*pp;
+ voffset &= 0x7fffffff;
+
+ if (**pp == ';' || *pp == '\0')
+ {
+ /* Must be g++ version 1. */
+ context = DEBUG_TYPE_NULL;
+ }
+ else
+ {
+ /* Figure out from whence this virtual function
+ came. It may belong to virtual function table of
+ one of its baseclasses. */
+ look_ahead_type = parse_stab_type (dhandle, info,
+ (const char *) NULL,
+ pp,
+ (debug_type **) NULL);
+ if (**pp == ':')
+ {
+ /* g++ version 1 overloaded methods. */
+ context = DEBUG_TYPE_NULL;
+ }
+ else
+ {
+ context = look_ahead_type;
+ look_ahead_type = DEBUG_TYPE_NULL;
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ ++*pp;
+ }
+ }
+ break;
+
+ case '?':
+ /* static member function. */
+ ++*pp;
+ staticp = true;
+ voffset = 0;
+ context = DEBUG_TYPE_NULL;
+ if (strncmp (argtypes, name, strlen (name)) != 0)
+ stub = true;
+ break;
+
+ default:
+ warn_stab (orig, "member function type missing");
+ voffset = 0;
+ context = DEBUG_TYPE_NULL;
+ break;
+
+ case '.':
+ ++*pp;
+ voffset = 0;
+ context = DEBUG_TYPE_NULL;
+ break;
+ }
+
+ /* If the type is not a stub, then the argtypes string is
+ the physical name of the function. Otherwise the
+ argtypes string is the mangled form of the argument
+ types, and the full type and the physical name must be
+ extracted from them. */
+ if (! stub)
+ physname = argtypes;
+ else
+ {
+ debug_type class_type, return_type;
+
+ class_type = stab_find_type (dhandle, info, typenums);
+ if (class_type == DEBUG_TYPE_NULL)
+ return false;
+ return_type = debug_get_return_type (dhandle, type);
+ if (return_type == DEBUG_TYPE_NULL)
+ {
+ bad_stab (orig);
+ return false;
+ }
+ type = parse_stab_argtypes (dhandle, info, class_type, name,
+ tagname, return_type, argtypes,
+ constp, volatilep, &physname);
+ if (type == DEBUG_TYPE_NULL)
+ return false;
+ }
+
+ if (cvars + 1 >= allocvars)
+ {
+ allocvars += 10;
+ variants = ((debug_method_variant *)
+ xrealloc ((PTR) variants,
+ allocvars * sizeof *variants));
+ }
+
+ if (! staticp)
+ variants[cvars] = debug_make_method_variant (dhandle, physname,
+ type, visibility,
+ constp, volatilep,
+ voffset, context);
+ else
+ variants[cvars] = debug_make_static_method_variant (dhandle,
+ physname,
+ type,
+ visibility,
+ constp,
+ volatilep);
+ if (variants[cvars] == DEBUG_METHOD_VARIANT_NULL)
+ return false;
+
+ ++cvars;
+ }
+ while (**pp != ';' && **pp != '\0');
+
+ variants[cvars] = DEBUG_METHOD_VARIANT_NULL;
+
+ if (**pp != '\0')
+ ++*pp;
+
+ if (c + 1 >= alloc)
+ {
+ alloc += 10;
+ methods = ((debug_method *)
+ xrealloc ((PTR) methods, alloc * sizeof *methods));
+ }
+
+ methods[c] = debug_make_method (dhandle, name, variants);
+
+ ++c;
+ }
+
+ if (methods != NULL)
+ methods[c] = DEBUG_METHOD_NULL;
+
+ *retp = methods;
+
+ return true;
+}
+
+/* Parse a string representing argument types for a method. Stabs
+ tries to save space by packing argument types into a mangled
+ string. This string should give us enough information to extract
+ both argument types and the physical name of the function, given
+ the tag name. */
+
+static debug_type
+parse_stab_argtypes (dhandle, info, class_type, fieldname, tagname,
+ return_type, argtypes, constp, volatilep, pphysname)
+ PTR dhandle;
+ struct stab_handle *info;
+ debug_type class_type;
+ const char *fieldname;
+ const char *tagname;
+ debug_type return_type;
+ const char *argtypes;
+ boolean constp;
+ boolean volatilep;
+ const char **pphysname;
+{
+ boolean is_full_physname_constructor;
+ boolean is_constructor;
+ boolean is_destructor;
+ debug_type *args;
+ boolean varargs;
+
+ /* Constructors are sometimes handled specially. */
+ is_full_physname_constructor = ((argtypes[0] == '_'
+ && argtypes[1] == '_'
+ && (isdigit ((unsigned char) argtypes[2])
+ || argtypes[2] == 'Q'
+ || argtypes[2] == 't'))
+ || strncmp (argtypes, "__ct", 4) == 0);
+
+ is_constructor = (is_full_physname_constructor
+ || (tagname != NULL
+ && strcmp (fieldname, tagname) == 0));
+ is_destructor = ((argtypes[0] == '_'
+ && (argtypes[1] == '$' || argtypes[1] == '.')
+ && argtypes[2] == '_')
+ || strncmp (argtypes, "__dt", 4) == 0);
+
+ if (is_destructor || is_full_physname_constructor)
+ *pphysname = argtypes;
+ else
+ {
+ unsigned int len;
+ const char *const_prefix;
+ const char *volatile_prefix;
+ char buf[20];
+ unsigned int mangled_name_len;
+ char *physname;
+
+ len = tagname == NULL ? 0 : strlen (tagname);
+ const_prefix = constp ? "C" : "";
+ volatile_prefix = volatilep ? "V" : "";
+
+ if (len == 0)
+ sprintf (buf, "__%s%s", const_prefix, volatile_prefix);
+ else if (tagname != NULL && strchr (tagname, '<') != NULL)
+ {
+ /* Template methods are fully mangled. */
+ sprintf (buf, "__%s%s", const_prefix, volatile_prefix);
+ tagname = NULL;
+ len = 0;
+ }
+ else
+ sprintf (buf, "__%s%s%d", const_prefix, volatile_prefix, len);
+
+ mangled_name_len = ((is_constructor ? 0 : strlen (fieldname))
+ + strlen (buf)
+ + len
+ + strlen (argtypes)
+ + 1);
+
+ if (fieldname[0] == 'o'
+ && fieldname[1] == 'p'
+ && (fieldname[2] == '$' || fieldname[2] == '.'))
+ {
+ const char *opname;
+
+ opname = cplus_mangle_opname (fieldname + 3, 0);
+ if (opname == NULL)
+ {
+ fprintf (stderr, "No mangling for \"%s\"\n", fieldname);
+ return DEBUG_TYPE_NULL;
+ }
+ mangled_name_len += strlen (opname);
+ physname = (char *) xmalloc (mangled_name_len);
+ strncpy (physname, fieldname, 3);
+ strcpy (physname + 3, opname);
+ }
+ else
+ {
+ physname = (char *) xmalloc (mangled_name_len);
+ if (is_constructor)
+ physname[0] = '\0';
+ else
+ strcpy (physname, fieldname);
+ }
+
+ strcat (physname, buf);
+ if (tagname != NULL)
+ strcat (physname, tagname);
+ strcat (physname, argtypes);
+
+ *pphysname = physname;
+ }
+
+ if (*argtypes == '\0' || is_destructor)
+ {
+ args = (debug_type *) xmalloc (sizeof *args);
+ *args = NULL;
+ return debug_make_method_type (dhandle, return_type, class_type, args,
+ false);
+ }
+
+ args = stab_demangle_argtypes (dhandle, info, *pphysname, &varargs);
+ if (args == NULL)
+ return DEBUG_TYPE_NULL;
+
+ return debug_make_method_type (dhandle, return_type, class_type, args,
+ varargs);
+}
+
+/* The tail end of stabs for C++ classes that contain a virtual function
+ pointer contains a tilde, a %, and a type number.
+ The type number refers to the base class (possibly this class itself) which
+ contains the vtable pointer for the current class.
+
+ This function is called when we have parsed all the method declarations,
+ so we can look for the vptr base class info. */
+
+static boolean
+parse_stab_tilde_field (dhandle, info, pp, typenums, retvptrbase, retownvptr)
+ PTR dhandle;
+ struct stab_handle *info;
+ const char **pp;
+ const int *typenums;
+ debug_type *retvptrbase;
+ boolean *retownvptr;
+{
+ const char *orig;
+ const char *hold;
+ int vtypenums[2];
+
+ *retvptrbase = DEBUG_TYPE_NULL;
+ *retownvptr = false;
+
+ orig = *pp;
+
+ /* If we are positioned at a ';', then skip it. */
+ if (**pp == ';')
+ ++*pp;
+
+ if (**pp != '~')
+ return true;
+
+ ++*pp;
+
+ if (**pp == '=' || **pp == '+' || **pp == '-')
+ {
+ /* Obsolete flags that used to indicate the presence of
+ constructors and/or destructors. */
+ ++*pp;
+ }
+
+ if (**pp != '%')
+ return true;
+
+ ++*pp;
+
+ hold = *pp;
+
+ /* The next number is the type number of the base class (possibly
+ our own class) which supplies the vtable for this class. */
+ if (! parse_stab_type_number (pp, vtypenums))
+ return false;
+
+ if (vtypenums[0] == typenums[0]
+ && vtypenums[1] == typenums[1])
+ *retownvptr = true;
+ else
+ {
+ debug_type vtype;
+ const char *p;
+
+ *pp = hold;
+
+ vtype = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
+ for (p = *pp; *p != ';' && *p != '\0'; p++)
+ ;
+ if (*p != ';')
+ {
+ bad_stab (orig);
+ return false;
+ }
+
+ *retvptrbase = vtype;
+
+ *pp = p + 1;
+ }
+
+ return true;
+}
+
+/* Read a definition of an array type. */
+
+static debug_type
+parse_stab_array_type (dhandle, info, pp, stringp)
+ PTR dhandle;
+ struct stab_handle *info;
+ const char **pp;
+ boolean stringp;
+{
+ const char *orig;
+ const char *p;
+ int typenums[2];
+ debug_type index_type;
+ boolean adjustable;
+ bfd_signed_vma lower, upper;
+ debug_type element_type;
+
+ /* Format of an array type:
+ "ar<index type>;lower;upper;<array_contents_type>".
+ OS9000: "arlower,upper;<array_contents_type>".
+
+ Fortran adjustable arrays use Adigits or Tdigits for lower or upper;
+ for these, produce a type like float[][]. */
+
+ orig = *pp;
+
+ /* FIXME: gdb checks os9k_stabs here. */
+
+ /* If the index type is type 0, we take it as int. */
+ p = *pp;
+ if (! parse_stab_type_number (&p, typenums))
+ return DEBUG_TYPE_NULL;
+ if (typenums[0] == 0 && typenums[1] == 0 && **pp != '=')
+ {
+ index_type = debug_find_named_type (dhandle, "int");
+ if (index_type == DEBUG_TYPE_NULL)
+ {
+ index_type = debug_make_int_type (dhandle, 4, false);
+ if (index_type == DEBUG_TYPE_NULL)
+ return DEBUG_TYPE_NULL;
+ }
+ *pp = p;
+ }
+ else
+ {
+ index_type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
+ }
+
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+
+ adjustable = false;
+
+ if (! isdigit ((unsigned char) **pp) && **pp != '-')
+ {
+ ++*pp;
+ adjustable = true;
+ }
+
+ lower = (bfd_signed_vma) parse_number (pp, (boolean *) NULL);
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+
+ if (! isdigit ((unsigned char) **pp) && **pp != '-')
+ {
+ ++*pp;
+ adjustable = true;
+ }
+
+ upper = (bfd_signed_vma) parse_number (pp, (boolean *) NULL);
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+
+ element_type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
+ if (element_type == DEBUG_TYPE_NULL)
+ return DEBUG_TYPE_NULL;
+
+ if (adjustable)
+ {
+ lower = 0;
+ upper = -1;
+ }
+
+ return debug_make_array_type (dhandle, element_type, index_type, lower,
+ upper, stringp);
+}
+
+/* This struct holds information about files we have seen using
+ N_BINCL. */
+
+struct bincl_file
+{
+ /* The next N_BINCL file. */
+ struct bincl_file *next;
+ /* The next N_BINCL on the stack. */
+ struct bincl_file *next_stack;
+ /* The file name. */
+ const char *name;
+ /* The hash value. */
+ bfd_vma hash;
+ /* The file index. */
+ unsigned int file;
+ /* The list of types defined in this file. */
+ struct stab_types *file_types;
+};
+
+/* Start a new N_BINCL file, pushing it onto the stack. */
+
+static void
+push_bincl (info, name, hash)
+ struct stab_handle *info;
+ const char *name;
+ bfd_vma hash;
+{
+ struct bincl_file *n;
+
+ n = (struct bincl_file *) xmalloc (sizeof *n);
+ n->next = info->bincl_list;
+ n->next_stack = info->bincl_stack;
+ n->name = name;
+ n->hash = hash;
+ n->file = info->files;
+ n->file_types = NULL;
+ info->bincl_list = n;
+ info->bincl_stack = n;
+
+ ++info->files;
+ info->file_types = ((struct stab_types **)
+ xrealloc ((PTR) info->file_types,
+ (info->files
+ * sizeof *info->file_types)));
+ info->file_types[n->file] = NULL;
+}
+
+/* Finish an N_BINCL file, at an N_EINCL, popping the name off the
+ stack. */
+
+static const char *
+pop_bincl (info)
+ struct stab_handle *info;
+{
+ struct bincl_file *o;
+
+ o = info->bincl_stack;
+ if (o == NULL)
+ return info->main_filename;
+ info->bincl_stack = o->next_stack;
+
+ o->file_types = info->file_types[o->file];
+
+ if (info->bincl_stack == NULL)
+ return info->main_filename;
+ return info->bincl_stack->name;
+}
+
+/* Handle an N_EXCL: get the types from the corresponding N_BINCL. */
+
+static boolean
+find_excl (info, name, hash)
+ struct stab_handle *info;
+ const char *name;
+ bfd_vma hash;
+{
+ struct bincl_file *l;
+
+ ++info->files;
+ info->file_types = ((struct stab_types **)
+ xrealloc ((PTR) info->file_types,
+ (info->files
+ * sizeof *info->file_types)));
+
+ for (l = info->bincl_list; l != NULL; l = l->next)
+ if (l->hash == hash && strcmp (l->name, name) == 0)
+ break;
+ if (l == NULL)
+ {
+ warn_stab (name, "Undefined N_EXCL");
+ info->file_types[info->files - 1] = NULL;
+ return true;
+ }
+
+ info->file_types[info->files - 1] = l->file_types;
+
+ return true;
+}
+
+/* Handle a variable definition. gcc emits variable definitions for a
+ block before the N_LBRAC, so we must hold onto them until we see
+ it. The SunPRO compiler emits variable definitions after the
+ N_LBRAC, so we can call debug_record_variable immediately. */
+
+static boolean
+stab_record_variable (dhandle, info, name, type, kind, val)
+ PTR dhandle;
+ struct stab_handle *info;
+ const char *name;
+ debug_type type;
+ enum debug_var_kind kind;
+ bfd_vma val;
+{
+ struct stab_pending_var *v;
+
+ if ((kind == DEBUG_GLOBAL || kind == DEBUG_STATIC)
+ || ! info->within_function
+ || (info->gcc_compiled == 0 && info->n_opt_found))
+ return debug_record_variable (dhandle, name, type, kind, val);
+
+ v = (struct stab_pending_var *) xmalloc (sizeof *v);
+ memset (v, 0, sizeof *v);
+
+ v->next = info->pending;
+ v->name = name;
+ v->type = type;
+ v->kind = kind;
+ v->val = val;
+ info->pending = v;
+
+ return true;
+}
+
+/* Emit pending variable definitions. This is called after we see the
+ N_LBRAC that starts the block. */
+
+static boolean
+stab_emit_pending_vars (dhandle, info)
+ PTR dhandle;
+ struct stab_handle *info;
+{
+ struct stab_pending_var *v;
+
+ v = info->pending;
+ while (v != NULL)
+ {
+ struct stab_pending_var *next;
+
+ if (! debug_record_variable (dhandle, v->name, v->type, v->kind, v->val))
+ return false;
+
+ next = v->next;
+ free (v);
+ v = next;
+ }
+
+ info->pending = NULL;
+
+ return true;
+}
+
+/* Find the slot for a type in the database. */
+
+static debug_type *
+stab_find_slot (info, typenums)
+ struct stab_handle *info;
+ const int *typenums;
+{
+ int filenum;
+ int index;
+ struct stab_types **ps;
+
+ filenum = typenums[0];
+ index = typenums[1];
+
+ if (filenum < 0 || (unsigned int) filenum >= info->files)
+ {
+ fprintf (stderr, "Type file number %d out of range\n", filenum);
+ return NULL;
+ }
+ if (index < 0)
+ {
+ fprintf (stderr, "Type index number %d out of range\n", index);
+ return NULL;
+ }
+
+ ps = info->file_types + filenum;
+
+ while (index >= STAB_TYPES_SLOTS)
+ {
+ if (*ps == NULL)
+ {
+ *ps = (struct stab_types *) xmalloc (sizeof **ps);
+ memset (*ps, 0, sizeof **ps);
+ }
+ ps = &(*ps)->next;
+ index -= STAB_TYPES_SLOTS;
+ }
+ if (*ps == NULL)
+ {
+ *ps = (struct stab_types *) xmalloc (sizeof **ps);
+ memset (*ps, 0, sizeof **ps);
+ }
+
+ return (*ps)->types + index;
+}
+
+/* Find a type given a type number. If the type has not been
+ allocated yet, create an indirect type. */
+
+static debug_type
+stab_find_type (dhandle, info, typenums)
+ PTR dhandle;
+ struct stab_handle *info;
+ const int *typenums;
+{
+ debug_type *slot;
+
+ if (typenums[0] == 0 && typenums[1] < 0)
+ {
+ /* A negative type number indicates an XCOFF builtin type. */
+ return stab_xcoff_builtin_type (dhandle, info, typenums[1]);
+ }
+
+ slot = stab_find_slot (info, typenums);
+ if (slot == NULL)
+ return DEBUG_TYPE_NULL;
+
+ if (*slot == DEBUG_TYPE_NULL)
+ return debug_make_indirect_type (dhandle, slot, (const char *) NULL);
+
+ return *slot;
+}
+
+/* Record that a given type number refers to a given type. */
+
+static boolean
+stab_record_type (dhandle, info, typenums, type)
+ PTR dhandle;
+ struct stab_handle *info;
+ const int *typenums;
+ debug_type type;
+{
+ debug_type *slot;
+
+ slot = stab_find_slot (info, typenums);
+ if (slot == NULL)
+ return false;
+
+ /* gdb appears to ignore type redefinitions, so we do as well. */
+
+ *slot = type;
+
+ return true;
+}
+
+/* Return an XCOFF builtin type. */
+
+static debug_type
+stab_xcoff_builtin_type (dhandle, info, typenum)
+ PTR dhandle;
+ struct stab_handle *info;
+ int typenum;
+{
+ debug_type rettype;
+ const char *name;
+
+ if (typenum >= 0 || typenum < -XCOFF_TYPE_COUNT)
+ {
+ fprintf (stderr, "Unrecognized XCOFF type %d\n", typenum);
+ return DEBUG_TYPE_NULL;
+ }
+ if (info->xcoff_types[-typenum] != NULL)
+ return info->xcoff_types[-typenum];
+
+ switch (-typenum)
+ {
+ case 1:
+ /* The size of this and all the other types are fixed, defined
+ by the debugging format. */
+ name = "int";
+ rettype = debug_make_int_type (dhandle, 4, false);
+ break;
+ case 2:
+ name = "char";
+ rettype = debug_make_int_type (dhandle, 1, false);
+ break;
+ case 3:
+ name = "short";
+ rettype = debug_make_int_type (dhandle, 2, false);
+ break;
+ case 4:
+ name = "long";
+ rettype = debug_make_int_type (dhandle, 4, false);
+ break;
+ case 5:
+ name = "unsigned char";
+ rettype = debug_make_int_type (dhandle, 1, true);
+ break;
+ case 6:
+ name = "signed char";
+ rettype = debug_make_int_type (dhandle, 1, false);
+ break;
+ case 7:
+ name = "unsigned short";
+ rettype = debug_make_int_type (dhandle, 2, true);
+ break;
+ case 8:
+ name = "unsigned int";
+ rettype = debug_make_int_type (dhandle, 4, true);
+ break;
+ case 9:
+ name = "unsigned";
+ rettype = debug_make_int_type (dhandle, 4, true);
+ case 10:
+ name = "unsigned long";
+ rettype = debug_make_int_type (dhandle, 4, true);
+ break;
+ case 11:
+ name = "void";
+ rettype = debug_make_void_type (dhandle);
+ break;
+ case 12:
+ /* IEEE single precision (32 bit). */
+ name = "float";
+ rettype = debug_make_float_type (dhandle, 4);
+ break;
+ case 13:
+ /* IEEE double precision (64 bit). */
+ name = "double";
+ rettype = debug_make_float_type (dhandle, 8);
+ break;
+ case 14:
+ /* This is an IEEE double on the RS/6000, and different machines
+ with different sizes for "long double" should use different
+ negative type numbers. See stabs.texinfo. */
+ name = "long double";
+ rettype = debug_make_float_type (dhandle, 8);
+ break;
+ case 15:
+ name = "integer";
+ rettype = debug_make_int_type (dhandle, 4, false);
+ break;
+ case 16:
+ name = "boolean";
+ rettype = debug_make_bool_type (dhandle, 4);
+ break;
+ case 17:
+ name = "short real";
+ rettype = debug_make_float_type (dhandle, 4);
+ break;
+ case 18:
+ name = "real";
+ rettype = debug_make_float_type (dhandle, 8);
+ break;
+ case 19:
+ /* FIXME */
+ name = "stringptr";
+ rettype = NULL;
+ break;
+ case 20:
+ /* FIXME */
+ name = "character";
+ rettype = debug_make_int_type (dhandle, 1, true);
+ break;
+ case 21:
+ name = "logical*1";
+ rettype = debug_make_bool_type (dhandle, 1);
+ break;
+ case 22:
+ name = "logical*2";
+ rettype = debug_make_bool_type (dhandle, 2);
+ break;
+ case 23:
+ name = "logical*4";
+ rettype = debug_make_bool_type (dhandle, 4);
+ break;
+ case 24:
+ name = "logical";
+ rettype = debug_make_bool_type (dhandle, 4);
+ break;
+ case 25:
+ /* Complex type consisting of two IEEE single precision values. */
+ name = "complex";
+ rettype = debug_make_complex_type (dhandle, 8);
+ break;
+ case 26:
+ /* Complex type consisting of two IEEE double precision values. */
+ name = "double complex";
+ rettype = debug_make_complex_type (dhandle, 16);
+ break;
+ case 27:
+ name = "integer*1";
+ rettype = debug_make_int_type (dhandle, 1, false);
+ break;
+ case 28:
+ name = "integer*2";
+ rettype = debug_make_int_type (dhandle, 2, false);
+ break;
+ case 29:
+ name = "integer*4";
+ rettype = debug_make_int_type (dhandle, 4, false);
+ break;
+ case 30:
+ /* FIXME */
+ name = "wchar";
+ rettype = debug_make_int_type (dhandle, 2, false);
+ break;
+ case 31:
+ name = "long long";
+ rettype = debug_make_int_type (dhandle, 8, false);
+ break;
+ case 32:
+ name = "unsigned long long";
+ rettype = debug_make_int_type (dhandle, 8, true);
+ break;
+ case 33:
+ name = "logical*8";
+ rettype = debug_make_bool_type (dhandle, 8);
+ break;
+ case 34:
+ name = "integer*8";
+ rettype = debug_make_int_type (dhandle, 8, false);
+ break;
+ default:
+ abort ();
+ }
+
+ rettype = debug_name_type (dhandle, name, rettype);
+
+ info->xcoff_types[-typenum] = rettype;
+
+ return rettype;
+}
+
+/* Find or create a tagged type. */
+
+static debug_type
+stab_find_tagged_type (dhandle, info, p, len, kind)
+ PTR dhandle;
+ struct stab_handle *info;
+ const char *p;
+ int len;
+ enum debug_type_kind kind;
+{
+ char *name;
+ debug_type dtype;
+ struct stab_tag *st;
+
+ name = savestring (p, len);
+
+ /* We pass DEBUG_KIND_ILLEGAL because we want all tags in the same
+ namespace. This is right for C, and I don't know how to handle
+ other languages. FIXME. */
+ dtype = debug_find_tagged_type (dhandle, name, DEBUG_KIND_ILLEGAL);
+ if (dtype != DEBUG_TYPE_NULL)
+ {
+ free (name);
+ return dtype;
+ }
+
+ /* We need to allocate an entry on the undefined tag list. */
+ for (st = info->tags; st != NULL; st = st->next)
+ {
+ if (st->name[0] == name[0]
+ && strcmp (st->name, name) == 0)
+ {
+ if (st->kind == DEBUG_KIND_ILLEGAL)
+ st->kind = kind;
+ free (name);
+ break;
+ }
+ }
+ if (st == NULL)
+ {
+ st = (struct stab_tag *) xmalloc (sizeof *st);
+ memset (st, 0, sizeof *st);
+
+ st->next = info->tags;
+ st->name = name;
+ st->kind = kind;
+ st->slot = DEBUG_TYPE_NULL;
+ st->type = debug_make_indirect_type (dhandle, &st->slot, name);
+ info->tags = st;
+ }
+
+ return st->type;
+}
+
+/* In order to get the correct argument types for a stubbed method, we
+ need to extract the argument types from a C++ mangled string.
+ Since the argument types can refer back to the return type, this
+ means that we must demangle the entire physical name. In gdb this
+ is done by calling cplus_demangle and running the results back
+ through the C++ expression parser. Since we have no expression
+ parser, we must duplicate much of the work of cplus_demangle here.
+
+ We assume that GNU style demangling is used, since this is only
+ done for method stubs, and only g++ should output that form of
+ debugging information. */
+
+/* This structure is used to hold a pointer to type information which
+ demangling a string. */
+
+struct stab_demangle_typestring
+{
+ /* The start of the type. This is not null terminated. */
+ const char *typestring;
+ /* The length of the type. */
+ unsigned int len;
+};
+
+/* This structure is used to hold information while demangling a
+ string. */
+
+struct stab_demangle_info
+{
+ /* The debugging information handle. */
+ PTR dhandle;
+ /* The stab information handle. */
+ struct stab_handle *info;
+ /* The array of arguments we are building. */
+ debug_type *args;
+ /* Whether the method takes a variable number of arguments. */
+ boolean varargs;
+ /* The array of types we have remembered. */
+ struct stab_demangle_typestring *typestrings;
+ /* The number of typestrings. */
+ unsigned int typestring_count;
+ /* The number of typestring slots we have allocated. */
+ unsigned int typestring_alloc;
+};
+
+static void stab_bad_demangle PARAMS ((const char *));
+static unsigned int stab_demangle_count PARAMS ((const char **));
+static boolean stab_demangle_get_count
+ PARAMS ((const char **, unsigned int *));
+static boolean stab_demangle_prefix
+ PARAMS ((struct stab_demangle_info *, const char **));
+static boolean stab_demangle_function_name
+ PARAMS ((struct stab_demangle_info *, const char **, const char *));
+static boolean stab_demangle_signature
+ PARAMS ((struct stab_demangle_info *, const char **));
+static boolean stab_demangle_qualified
+ PARAMS ((struct stab_demangle_info *, const char **, debug_type *));
+static boolean stab_demangle_template
+ PARAMS ((struct stab_demangle_info *, const char **));
+static boolean stab_demangle_class
+ PARAMS ((struct stab_demangle_info *, const char **, const char **));
+static boolean stab_demangle_args
+ PARAMS ((struct stab_demangle_info *, const char **, debug_type **,
+ boolean *));
+static boolean stab_demangle_arg
+ PARAMS ((struct stab_demangle_info *, const char **, debug_type **,
+ unsigned int *, unsigned int *));
+static boolean stab_demangle_type
+ PARAMS ((struct stab_demangle_info *, const char **, debug_type *));
+static boolean stab_demangle_fund_type
+ PARAMS ((struct stab_demangle_info *, const char **, debug_type *));
+static boolean stab_demangle_remember_type
+ PARAMS ((struct stab_demangle_info *, const char *, int));
+
+/* Warn about a bad demangling. */
+
+static void
+stab_bad_demangle (s)
+ const char *s;
+{
+ fprintf (stderr, "bad mangled name `%s'\n", s);
+}
+
+/* Get a count from a stab string. */
+
+static unsigned int
+stab_demangle_count (pp)
+ const char **pp;
+{
+ unsigned int count;
+
+ count = 0;
+ while (isdigit ((unsigned char) **pp))
+ {
+ count *= 10;
+ count += **pp - '0';
+ ++*pp;
+ }
+ return count;
+}
+
+/* Require a count in a string. The count may be multiple digits, in
+ which case it must end in an underscore. */
+
+static boolean
+stab_demangle_get_count (pp, pi)
+ const char **pp;
+ unsigned int *pi;
+{
+ if (! isdigit ((unsigned char) **pp))
+ return false;
+
+ *pi = **pp - '0';
+ ++*pp;
+ if (isdigit ((unsigned char) **pp))
+ {
+ unsigned int count;
+ const char *p;
+
+ count = *pi;
+ p = *pp;
+ do
+ {
+ count *= 10;
+ count += *p - '0';
+ ++p;
+ }
+ while (isdigit ((unsigned char) *p));
+ if (*p == '_')
+ {
+ *pp = p + 1;
+ *pi = count;
+ }
+ }
+
+ return true;
+}
+
+/* This function demangles a physical name, returning a NULL
+ terminated array of argument types. */
+
+static debug_type *
+stab_demangle_argtypes (dhandle, info, physname, pvarargs)
+ PTR dhandle;
+ struct stab_handle *info;
+ const char *physname;
+ boolean *pvarargs;
+{
+ struct stab_demangle_info minfo;
+
+ minfo.dhandle = dhandle;
+ minfo.info = info;
+ minfo.args = NULL;
+ minfo.varargs = false;
+ minfo.typestring_alloc = 10;
+ minfo.typestrings = ((struct stab_demangle_typestring *)
+ xmalloc (minfo.typestring_alloc
+ * sizeof *minfo.typestrings));
+ minfo.typestring_count = 0;
+
+ /* cplus_demangle checks for special GNU mangled forms, but we can't
+ see any of them in mangled method argument types. */
+
+ if (! stab_demangle_prefix (&minfo, &physname))
+ goto error_return;
+
+ if (*physname != '\0')
+ {
+ if (! stab_demangle_signature (&minfo, &physname))
+ goto error_return;
+ }
+
+ free (minfo.typestrings);
+ minfo.typestrings = NULL;
+
+ if (minfo.args == NULL)
+ fprintf (stderr, "no argument types in mangled string\n");
+
+ *pvarargs = minfo.varargs;
+ return minfo.args;
+
+ error_return:
+ if (minfo.typestrings != NULL)
+ free (minfo.typestrings);
+ return NULL;
+}
+
+/* Demangle the prefix of the mangled name. */
+
+static boolean
+stab_demangle_prefix (minfo, pp)
+ struct stab_demangle_info *minfo;
+ const char **pp;
+{
+ const char *scan;
+ unsigned int i;
+
+ /* cplus_demangle checks for global constructors and destructors,
+ but we can't see them in mangled argument types. */
+
+ /* Look for `__'. */
+ scan = *pp;
+ do
+ {
+ scan = strchr (scan, '_');
+ }
+ while (scan != NULL && *++scan != '_');
+
+ if (scan == NULL)
+ {
+ stab_bad_demangle (*pp);
+ return false;
+ }
+
+ --scan;
+
+ /* We found `__'; move ahead to the last contiguous `__' pair. */
+ i = strspn (scan, "_");
+ if (i > 2)
+ scan += i - 2;
+
+ if (scan == *pp
+ && (isdigit ((unsigned char) scan[2])
+ || scan[2] == 'Q'
+ || scan[2] == 't'))
+ {
+ /* This is a GNU style constructor name. */
+ *pp = scan + 2;
+ return true;
+ }
+ else if (scan == *pp
+ && ! isdigit ((unsigned char) scan[2])
+ && scan[2] != 't')
+ {
+ /* Look for the `__' that separates the prefix from the
+ signature. */
+ while (*scan == '_')
+ ++scan;
+ scan = strstr (scan, "__");
+ if (scan == NULL || scan[2] == '\0')
+ {
+ stab_bad_demangle (*pp);
+ return false;
+ }
+
+ return stab_demangle_function_name (minfo, pp, scan);
+ }
+ else if (scan[2] != '\0')
+ {
+ /* The name doesn't start with `__', but it does contain `__'. */
+ return stab_demangle_function_name (minfo, pp, scan);
+ }
+ else
+ {
+ stab_bad_demangle (*pp);
+ return false;
+ }
+ /*NOTREACHED*/
+}
+
+/* Demangle a function name prefix. The scan argument points to the
+ double underscore which separates the function name from the
+ signature. */
+
+static boolean
+stab_demangle_function_name (minfo, pp, scan)
+ struct stab_demangle_info *minfo;
+ const char **pp;
+ const char *scan;
+{
+ const char *name;
+
+ /* The string from *pp to scan is the name of the function. We
+ don't care about the name, since we just looking for argument
+ types. However, for conversion operators, the name may include a
+ type which we must remember in order to handle backreferences. */
+
+ name = *pp;
+ *pp = scan + 2;
+
+ if (*pp - name >= 5
+ && strncmp (name, "type", 4) == 0
+ && (name[4] == '$' || name[4] == '.'))
+ {
+ const char *tem;
+
+ /* This is a type conversion operator. */
+ tem = name + 5;
+ if (! stab_demangle_type (minfo, &tem, (debug_type *) NULL))
+ return false;
+ }
+ else if (name[0] == '_'
+ && name[1] == '_'
+ && name[2] == 'o'
+ && name[3] == 'p')
+ {
+ const char *tem;
+
+ /* This is a type conversion operator. */
+ tem = name + 4;
+ if (! stab_demangle_type (minfo, &tem, (debug_type *) NULL))
+ return false;
+ }
+
+ return true;
+}
+
+/* Demangle the signature. This is where the argument types are
+ found. */
+
+static boolean
+stab_demangle_signature (minfo, pp)
+ struct stab_demangle_info *minfo;
+ const char **pp;
+{
+ const char *orig;
+ boolean expect_func, func_done;
+ const char *hold;
+
+ orig = *pp;
+
+ expect_func = false;
+ func_done = false;
+ hold = NULL;
+
+ while (**pp != '\0')
+ {
+ switch (**pp)
+ {
+ case 'Q':
+ hold = *pp;
+ if (! stab_demangle_qualified (minfo, pp, (debug_type *) NULL)
+ || ! stab_demangle_remember_type (minfo, hold, *pp - hold))
+ return false;
+ expect_func = true;
+ hold = NULL;
+ break;
+
+ case 'S':
+ /* Static member function. FIXME: Can this happen? */
+ if (hold == NULL)
+ hold = *pp;
+ ++*pp;
+ break;
+
+ case 'C':
+ /* Const member function. */
+ if (hold == NULL)
+ hold = *pp;
+ ++*pp;
+ break;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ if (hold == NULL)
+ hold = *pp;
+ if (! stab_demangle_class (minfo, pp, (const char **) NULL)
+ || ! stab_demangle_remember_type (minfo, hold, *pp - hold))
+ return false;
+ expect_func = true;
+ hold = NULL;
+ break;
+
+ case 'F':
+ /* Function. I don't know if this actually happens with g++
+ output. */
+ hold = NULL;
+ func_done = true;
+ ++*pp;
+ if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
+ return false;
+ break;
+
+ case 't':
+ /* Template. */
+ if (hold == NULL)
+ hold = *pp;
+ if (! stab_demangle_template (minfo, pp)
+ || ! stab_demangle_remember_type (minfo, hold, *pp - hold))
+ return false;
+ hold = NULL;
+ expect_func = true;
+ break;
+
+ case '_':
+ /* At the outermost level, we cannot have a return type
+ specified, so if we run into another '_' at this point we
+ are dealing with a mangled name that is either bogus, or
+ has been mangled by some algorithm we don't know how to
+ deal with. So just reject the entire demangling. */
+ stab_bad_demangle (orig);
+ return false;
+
+ default:
+ /* Assume we have stumbled onto the first outermost function
+ argument token, and start processing args. */
+ func_done = true;
+ if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
+ return false;
+ break;
+ }
+
+ if (expect_func)
+ {
+ func_done = true;
+ if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
+ return false;
+ }
+ }
+
+ if (! func_done)
+ {
+ /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and
+ bar__3fooi is 'foo::bar(int)'. We get here when we find the
+ first case, and need to ensure that the '(void)' gets added
+ to the current declp. */
+ if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
+ return false;
+ }
+
+ return true;
+}
+
+/* Demangle a qualified name, such as "Q25Outer5Inner" which is the
+ mangled form of "Outer::Inner". */
+
+static boolean
+stab_demangle_qualified (minfo, pp, ptype)
+ struct stab_demangle_info *minfo;
+ const char **pp;
+ debug_type *ptype;
+{
+ const char *orig;
+ const char *p;
+ unsigned int qualifiers;
+ debug_type context;
+
+ orig = *pp;
+
+ switch ((*pp)[1])
+ {
+ case '_':
+ /* GNU mangled name with more than 9 classes. The count is
+ preceded by an underscore (to distinguish it from the <= 9
+ case) and followed by an underscore. */
+ p = *pp + 2;
+ if (! isdigit ((unsigned char) *p) || *p == '0')
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ qualifiers = atoi (p);
+ while (isdigit ((unsigned char) *p))
+ ++p;
+ if (*p != '_')
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ *pp = p + 1;
+ break;
+
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ qualifiers = (*pp)[1] - '0';
+ /* Skip an optional underscore after the count. */
+ if ((*pp)[2] == '_')
+ ++*pp;
+ *pp += 2;
+ break;
+
+ case '0':
+ default:
+ stab_bad_demangle (orig);
+ return false;
+ }
+
+ context = DEBUG_TYPE_NULL;
+
+ /* Pick off the names. */
+ while (qualifiers-- > 0)
+ {
+ if (**pp == '_')
+ ++*pp;
+ if (**pp == 't')
+ {
+ /* FIXME: I don't know how to handle the ptype != NULL case
+ here. */
+ if (! stab_demangle_template (minfo, pp))
+ return false;
+ }
+ else
+ {
+ unsigned int len;
+
+ len = stab_demangle_count (pp);
+ if (strlen (*pp) < len)
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+
+ if (ptype != NULL)
+ {
+ const debug_field *fields;
+
+ fields = NULL;
+ if (context != DEBUG_TYPE_NULL)
+ fields = debug_get_fields (minfo->dhandle, context);
+
+ context = DEBUG_TYPE_NULL;
+
+ if (fields != NULL)
+ {
+ char *name;
+
+ /* Try to find the type by looking through the
+ fields of context until we find a field with the
+ same type. This ought to work for a class
+ defined within a class, but it won't work for,
+ e.g., an enum defined within a class. stabs does
+ not give us enough information to figure out the
+ latter case. */
+
+ name = savestring (*pp, len);
+
+ for (; *fields != DEBUG_FIELD_NULL; fields++)
+ {
+ debug_type ft;
+ const char *dn;
+
+ ft = debug_get_field_type (minfo->dhandle, *fields);
+ if (ft == NULL)
+ return false;
+ dn = debug_get_type_name (minfo->dhandle, ft);
+ if (dn != NULL && strcmp (dn, name) == 0)
+ {
+ context = ft;
+ break;
+ }
+ }
+
+ free (name);
+ }
+
+ if (context == DEBUG_TYPE_NULL)
+ {
+ /* We have to fall back on finding the type by name.
+ If there are more types to come, then this must
+ be a class. Otherwise, it could be anything. */
+
+ if (qualifiers == 0)
+ {
+ char *name;
+
+ name = savestring (*pp, len);
+ context = debug_find_named_type (minfo->dhandle,
+ name);
+ free (name);
+ }
+
+ if (context == DEBUG_TYPE_NULL)
+ {
+ context = stab_find_tagged_type (minfo->dhandle,
+ minfo->info,
+ *pp, len,
+ (qualifiers == 0
+ ? DEBUG_KIND_ILLEGAL
+ : DEBUG_KIND_CLASS));
+ if (context == DEBUG_TYPE_NULL)
+ return false;
+ }
+ }
+ }
+
+ *pp += len;
+ }
+ }
+
+ if (ptype != NULL)
+ *ptype = context;
+
+ return true;
+}
+
+/* Demangle a template. */
+
+static boolean
+stab_demangle_template (minfo, pp)
+ struct stab_demangle_info *minfo;
+ const char **pp;
+{
+ const char *orig;
+ unsigned int r, i;
+
+ orig = *pp;
+
+ ++*pp;
+
+ /* Skip the template name. */
+ r = stab_demangle_count (pp);
+ if (r == 0 || strlen (*pp) < r)
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ *pp += r;
+
+ /* Get the size of the parameter list. */
+ if (stab_demangle_get_count (pp, &r) == 0)
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+
+ for (i = 0; i < r; i++)
+ {
+ if (**pp == 'Z')
+ {
+ /* This is a type parameter. */
+ ++*pp;
+ if (! stab_demangle_type (minfo, pp, (debug_type *) NULL))
+ return false;
+ }
+ else
+ {
+ const char *old_p;
+ boolean pointerp, realp, integralp, charp, boolp;
+ boolean done;
+
+ old_p = *pp;
+ pointerp = false;
+ realp = false;
+ integralp = false;
+ charp = false;
+ boolp = false;
+ done = false;
+
+ /* This is a value parameter. */
+
+ if (! stab_demangle_type (minfo, pp, (debug_type *) NULL))
+ return false;
+
+ while (*old_p != '\0' && ! done)
+ {
+ switch (*old_p)
+ {
+ case 'P':
+ case 'p':
+ case 'R':
+ pointerp = true;
+ done = true;
+ break;
+ case 'C': /* Const. */
+ case 'S': /* Signed. */
+ case 'U': /* Unsigned. */
+ case 'V': /* Volatile. */
+ case 'F': /* Function. */
+ case 'M': /* Member function. */
+ case 'O': /* ??? */
+ ++old_p;
+ break;
+ case 'Q': /* Qualified name. */
+ integralp = true;
+ done = true;
+ break;
+ case 'T': /* Remembered type. */
+ abort ();
+ case 'v': /* Void. */
+ abort ();
+ case 'x': /* Long long. */
+ case 'l': /* Long. */
+ case 'i': /* Int. */
+ case 's': /* Short. */
+ case 'w': /* Wchar_t. */
+ integralp = true;
+ done = true;
+ break;
+ case 'b': /* Bool. */
+ boolp = true;
+ done = true;
+ break;
+ case 'c': /* Char. */
+ charp = true;
+ done = true;
+ break;
+ case 'r': /* Long double. */
+ case 'd': /* Double. */
+ case 'f': /* Float. */
+ realp = true;
+ done = true;
+ break;
+ default:
+ /* Assume it's a user defined integral type. */
+ integralp = true;
+ done = true;
+ break;
+ }
+ }
+
+ if (integralp)
+ {
+ if (**pp == 'm')
+ ++*pp;
+ while (isdigit ((unsigned char) **pp))
+ ++*pp;
+ }
+ else if (charp)
+ {
+ unsigned int val;
+
+ if (**pp == 'm')
+ ++*pp;
+ val = stab_demangle_count (pp);
+ if (val == 0)
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ }
+ else if (boolp)
+ {
+ unsigned int val;
+
+ val = stab_demangle_count (pp);
+ if (val != 0 && val != 1)
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ }
+ else if (realp)
+ {
+ if (**pp == 'm')
+ ++*pp;
+ while (isdigit ((unsigned char) **pp))
+ ++*pp;
+ if (**pp == '.')
+ {
+ ++*pp;
+ while (isdigit ((unsigned char) **pp))
+ ++*pp;
+ }
+ if (**pp == 'e')
+ {
+ ++*pp;
+ while (isdigit ((unsigned char) **pp))
+ ++*pp;
+ }
+ }
+ else if (pointerp)
+ {
+ unsigned int len;
+
+ if (! stab_demangle_get_count (pp, &len))
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ *pp += len;
+ }
+ }
+ }
+
+ return true;
+}
+
+/* Demangle a class name. */
+
+static boolean
+stab_demangle_class (minfo, pp, pstart)
+ struct stab_demangle_info *minfo;
+ const char **pp;
+ const char **pstart;
+{
+ const char *orig;
+ unsigned int n;
+
+ orig = *pp;
+
+ n = stab_demangle_count (pp);
+ if (strlen (*pp) < n)
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+
+ if (pstart != NULL)
+ *pstart = *pp;
+
+ *pp += n;
+
+ return true;
+}
+
+/* Demangle function arguments. If the pargs argument is not NULL, it
+ is set to a NULL terminated array holding the arguments. */
+
+static boolean
+stab_demangle_args (minfo, pp, pargs, pvarargs)
+ struct stab_demangle_info *minfo;
+ const char **pp;
+ debug_type **pargs;
+ boolean *pvarargs;
+{
+ const char *orig;
+ unsigned int alloc, count;
+
+ orig = *pp;
+
+ alloc = 10;
+ if (pargs != NULL)
+ {
+ *pargs = (debug_type *) xmalloc (alloc * sizeof **pargs);
+ *pvarargs = false;
+ }
+ count = 0;
+
+ while (**pp != '_' && **pp != '\0' && **pp != 'e')
+ {
+ if (**pp == 'N' || **pp == 'T')
+ {
+ char temptype;
+ unsigned int r, t;
+
+ temptype = **pp;
+ ++*pp;
+
+ if (temptype == 'T')
+ r = 1;
+ else
+ {
+ if (! stab_demangle_get_count (pp, &r))
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ }
+
+ if (! stab_demangle_get_count (pp, &t))
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+
+ if (t >= minfo->typestring_count)
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ while (r-- > 0)
+ {
+ const char *tem;
+
+ tem = minfo->typestrings[t].typestring;
+ if (! stab_demangle_arg (minfo, &tem, pargs, &count, &alloc))
+ return false;
+ }
+ }
+ else
+ {
+ if (! stab_demangle_arg (minfo, pp, pargs, &count, &alloc))
+ return false;
+ }
+ }
+
+ if (pargs != NULL)
+ (*pargs)[count] = DEBUG_TYPE_NULL;
+
+ if (**pp == 'e')
+ {
+ if (pargs != NULL)
+ *pvarargs = true;
+ ++*pp;
+ }
+
+ return true;
+}
+
+/* Demangle a single argument. */
+
+static boolean
+stab_demangle_arg (minfo, pp, pargs, pcount, palloc)
+ struct stab_demangle_info *minfo;
+ const char **pp;
+ debug_type **pargs;
+ unsigned int *pcount;
+ unsigned int *palloc;
+{
+ const char *start;
+ debug_type type;
+
+ start = *pp;
+ if (! stab_demangle_type (minfo, pp,
+ pargs == NULL ? (debug_type *) NULL : &type)
+ || ! stab_demangle_remember_type (minfo, start, *pp - start))
+ return false;
+
+ if (pargs != NULL)
+ {
+ if (type == DEBUG_TYPE_NULL)
+ return false;
+
+ if (*pcount + 1 >= *palloc)
+ {
+ *palloc += 10;
+ *pargs = ((debug_type *)
+ xrealloc (*pargs, *palloc * sizeof **pargs));
+ }
+ (*pargs)[*pcount] = type;
+ ++*pcount;
+ }
+
+ return true;
+}
+
+/* Demangle a type. If the ptype argument is not NULL, *ptype is set
+ to the newly allocated type. */
+
+static boolean
+stab_demangle_type (minfo, pp, ptype)
+ struct stab_demangle_info *minfo;
+ const char **pp;
+ debug_type *ptype;
+{
+ const char *orig;
+
+ orig = *pp;
+
+ switch (**pp)
+ {
+ case 'P':
+ case 'p':
+ /* A pointer type. */
+ ++*pp;
+ if (! stab_demangle_type (minfo, pp, ptype))
+ return false;
+ if (ptype != NULL)
+ *ptype = debug_make_pointer_type (minfo->dhandle, *ptype);
+ break;
+
+ case 'R':
+ /* A reference type. */
+ ++*pp;
+ if (! stab_demangle_type (minfo, pp, ptype))
+ return false;
+ if (ptype != NULL)
+ *ptype = debug_make_reference_type (minfo->dhandle, *ptype);
+ break;
+
+ case 'A':
+ /* An array. */
+ {
+ unsigned long high;
+
+ ++*pp;
+ high = 0;
+ while (**pp != '\0' && **pp != '_')
+ {
+ if (! isdigit ((unsigned char) **pp))
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ high *= 10;
+ high += **pp - '0';
+ ++*pp;
+ }
+ if (**pp != '_')
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ ++*pp;
+
+ if (! stab_demangle_type (minfo, pp, ptype))
+ return false;
+ if (ptype != NULL)
+ {
+ debug_type int_type;
+
+ int_type = debug_find_named_type (minfo->dhandle, "int");
+ if (int_type == NULL)
+ int_type = debug_make_int_type (minfo->dhandle, 4, false);
+ *ptype = debug_make_array_type (minfo->dhandle, *ptype, int_type,
+ 0, high, false);
+ }
+ }
+ break;
+
+ case 'T':
+ /* A back reference to a remembered type. */
+ {
+ unsigned int i;
+ const char *p;
+
+ ++*pp;
+ if (! stab_demangle_get_count (pp, &i))
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ if (i >= minfo->typestring_count)
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ p = minfo->typestrings[i].typestring;
+ if (! stab_demangle_type (minfo, &p, ptype))
+ return false;
+ }
+ break;
+
+ case 'F':
+ /* A function. */
+ {
+ debug_type *args;
+ boolean varargs;
+
+ ++*pp;
+ if (! stab_demangle_args (minfo, pp,
+ (ptype == NULL
+ ? (debug_type **) NULL
+ : &args),
+ (ptype == NULL
+ ? (boolean *) NULL
+ : &varargs)))
+ return false;
+ if (**pp != '_')
+ {
+ /* cplus_demangle will accept a function without a return
+ type, but I don't know when that will happen, or what
+ to do if it does. */
+ stab_bad_demangle (orig);
+ return false;
+ }
+ ++*pp;
+ if (! stab_demangle_type (minfo, pp, ptype))
+ return false;
+ if (ptype != NULL)
+ *ptype = debug_make_function_type (minfo->dhandle, *ptype, args,
+ varargs);
+
+ }
+ break;
+
+ case 'M':
+ case 'O':
+ {
+ boolean memberp, constp, volatilep;
+ debug_type *args;
+ boolean varargs;
+ unsigned int n;
+ const char *name;
+
+ memberp = **pp == 'M';
+ constp = false;
+ volatilep = false;
+ args = NULL;
+ varargs = false;
+
+ ++*pp;
+ if (! isdigit ((unsigned char) **pp))
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ n = stab_demangle_count (pp);
+ if (strlen (*pp) < n)
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ name = *pp;
+ *pp += n;
+
+ if (memberp)
+ {
+ if (**pp == 'C')
+ {
+ constp = true;
+ ++*pp;
+ }
+ else if (**pp == 'V')
+ {
+ volatilep = true;
+ ++*pp;
+ }
+ if (**pp != 'F')
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ ++*pp;
+ if (! stab_demangle_args (minfo, pp,
+ (ptype == NULL
+ ? (debug_type **) NULL
+ : &args),
+ (ptype == NULL
+ ? (boolean *) NULL
+ : &varargs)))
+ return false;
+ }
+
+ if (**pp != '_')
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ ++*pp;
+
+ if (! stab_demangle_type (minfo, pp, ptype))
+ return false;
+
+ if (ptype != NULL)
+ {
+ debug_type class_type;
+
+ class_type = stab_find_tagged_type (minfo->dhandle, minfo->info,
+ name, (int) n,
+ DEBUG_KIND_CLASS);
+ if (class_type == DEBUG_TYPE_NULL)
+ return false;
+
+ if (! memberp)
+ *ptype = debug_make_offset_type (minfo->dhandle, class_type,
+ *ptype);
+ else
+ {
+ /* FIXME: We have no way to record constp or
+ volatilep. */
+ *ptype = debug_make_method_type (minfo->dhandle, *ptype,
+ class_type, args, varargs);
+ }
+ }
+ }
+ break;
+
+ case 'G':
+ ++*pp;
+ if (! stab_demangle_type (minfo, pp, ptype))
+ return false;
+ break;
+
+ case 'C':
+ ++*pp;
+ if (! stab_demangle_type (minfo, pp, ptype))
+ return false;
+ if (ptype != NULL)
+ *ptype = debug_make_const_type (minfo->dhandle, *ptype);
+ break;
+
+ case 'Q':
+ {
+ const char *hold;
+
+ hold = *pp;
+ if (! stab_demangle_qualified (minfo, pp, ptype))
+ return false;
+ }
+ break;
+
+ default:
+ if (! stab_demangle_fund_type (minfo, pp, ptype))
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+/* Demangle a fundamental type. If the ptype argument is not NULL,
+ *ptype is set to the newly allocated type. */
+
+static boolean
+stab_demangle_fund_type (minfo, pp, ptype)
+ struct stab_demangle_info *minfo;
+ const char **pp;
+ debug_type *ptype;
+{
+ const char *orig;
+ boolean constp, volatilep, unsignedp, signedp;
+ boolean done;
+
+ orig = *pp;
+
+ constp = false;
+ volatilep = false;
+ unsignedp = false;
+ signedp = false;
+
+ done = false;
+ while (! done)
+ {
+ switch (**pp)
+ {
+ case 'C':
+ constp = true;
+ ++*pp;
+ break;
+
+ case 'U':
+ unsignedp = true;
+ ++*pp;
+ break;
+
+ case 'S':
+ signedp = true;
+ ++*pp;
+ break;
+
+ case 'V':
+ volatilep = true;
+ ++*pp;
+ break;
+
+ default:
+ done = true;
+ break;
+ }
+ }
+
+ switch (**pp)
+ {
+ case '\0':
+ case '_':
+ /* cplus_demangle permits this, but I don't know what it means. */
+ stab_bad_demangle (orig);
+ break;
+
+ case 'v': /* void */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle, "void");
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_void_type (minfo->dhandle);
+ }
+ ++*pp;
+ break;
+
+ case 'x': /* long long */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle,
+ (unsignedp
+ ? "long long unsigned int"
+ : "long long int"));
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_int_type (minfo->dhandle, 8, unsignedp);
+ }
+ ++*pp;
+ break;
+
+ case 'l': /* long */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle,
+ (unsignedp
+ ? "long unsigned int"
+ : "long int"));
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_int_type (minfo->dhandle, 4, unsignedp);
+ }
+ ++*pp;
+ break;
+
+ case 'i': /* int */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle,
+ (unsignedp
+ ? "unsigned int"
+ : "int"));
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_int_type (minfo->dhandle, 4, unsignedp);
+ }
+ ++*pp;
+ break;
+
+ case 's': /* short */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle,
+ (unsignedp
+ ? "short unsigned int"
+ : "short int"));
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_int_type (minfo->dhandle, 2, unsignedp);
+ }
+ ++*pp;
+ break;
+
+ case 'b': /* bool */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle, "bool");
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_bool_type (minfo->dhandle, 4);
+ }
+ ++*pp;
+ break;
+
+ case 'c': /* char */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle,
+ (unsignedp
+ ? "unsigned char"
+ : (signedp
+ ? "signed char"
+ : "char")));
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_int_type (minfo->dhandle, 1, unsignedp);
+ }
+ ++*pp;
+ break;
+
+ case 'w': /* wchar_t */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle, "__wchar_t");
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_int_type (minfo->dhandle, 2, true);
+ }
+ ++*pp;
+ break;
+
+ case 'r': /* long double */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle, "long double");
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_float_type (minfo->dhandle, 8);
+ }
+ ++*pp;
+ break;
+
+ case 'd': /* double */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle, "double");
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_float_type (minfo->dhandle, 8);
+ }
+ ++*pp;
+ break;
+
+ case 'f': /* float */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle, "float");
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_float_type (minfo->dhandle, 4);
+ }
+ ++*pp;
+ break;
+
+ case 'G':
+ ++*pp;
+ if (! isdigit ((unsigned char) **pp))
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ /* Fall through. */
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ {
+ const char *hold;
+
+ if (! stab_demangle_class (minfo, pp, &hold))
+ return false;
+ if (ptype != NULL)
+ {
+ char *name;
+
+ name = savestring (hold, *pp - hold);
+ *ptype = debug_find_named_type (minfo->dhandle, name);
+ if (*ptype == DEBUG_TYPE_NULL)
+ {
+ /* FIXME: It is probably incorrect to assume that
+ undefined types are tagged types. */
+ *ptype = stab_find_tagged_type (minfo->dhandle, minfo->info,
+ hold, *pp - hold,
+ DEBUG_KIND_ILLEGAL);
+ }
+ free (name);
+ }
+ }
+ break;
+
+ case 't':
+ if (! stab_demangle_template (minfo, pp))
+ return false;
+ if (ptype != NULL)
+ {
+ debug_type t;
+
+ /* FIXME: I really don't know how a template should be
+ represented in the current type system. Perhaps the
+ template should be demangled into a string, and the type
+ should be represented as a named type. However, I don't
+ know what the base type of the named type should be. */
+ t = debug_make_void_type (minfo->dhandle);
+ t = debug_make_pointer_type (minfo->dhandle, t);
+ t = debug_name_type (minfo->dhandle, "TEMPLATE", t);
+ *ptype = t;
+ }
+ break;
+
+ default:
+ stab_bad_demangle (orig);
+ return false;
+ }
+
+ if (ptype != NULL)
+ {
+ if (constp)
+ *ptype = debug_make_const_type (minfo->dhandle, *ptype);
+ if (volatilep)
+ *ptype = debug_make_volatile_type (minfo->dhandle, *ptype);
+ }
+
+ return true;
+}
+
+/* Remember a type string in a demangled string. */
+
+static boolean
+stab_demangle_remember_type (minfo, p, len)
+ struct stab_demangle_info *minfo;
+ const char *p;
+ int len;
+{
+ if (minfo->typestring_count >= minfo->typestring_alloc)
+ {
+ minfo->typestring_alloc += 10;
+ minfo->typestrings = ((struct stab_demangle_typestring *)
+ xrealloc (minfo->typestrings,
+ (minfo->typestring_alloc
+ * sizeof *minfo->typestrings)));
+ }
+
+ minfo->typestrings[minfo->typestring_count].typestring = p;
+ minfo->typestrings[minfo->typestring_count].len = (unsigned int) len;
+ ++minfo->typestring_count;
+
+ return true;
+}
diff --git a/readline/bind.c b/readline/bind.c
index 57383239098..f122bdf4860 100644
--- a/readline/bind.c
+++ b/readline/bind.c
@@ -108,7 +108,7 @@ Keymap rl_binding_keymap;
/* Forward declarations */
void rl_set_keymap_from_edit_mode ();
-static int _rl_read_init_file ();
+static int _rl_read_init_file (const char *filename, int include_level);
static int glean_key_from_name ();
static int substring_member_of_array ();
@@ -570,10 +570,7 @@ rl_named_function (string)
type of the object pointed to. One of ISFUNC (function), ISKMAP (keymap),
or ISMACR (macro). */
Function *
-rl_function_of_keyseq (keyseq, map, type)
- char *keyseq;
- Keymap map;
- int *type;
+rl_function_of_keyseq (const char *keyseq, Keymap map, int *type)
{
register int i;
@@ -629,7 +626,7 @@ rl_function_of_keyseq (keyseq, map, type)
static char *last_readline_init_file = (char *)NULL;
/* The file we're currently reading key bindings from. */
-static char *current_readline_init_file;
+static const char *current_readline_init_file;
static int current_readline_init_include_level;
static int current_readline_init_lineno;
@@ -685,8 +682,8 @@ _rl_read_file (filename, sizep)
/* Re-read the current keybindings file. */
int
-rl_re_read_init_file (count, ignore)
- int count, ignore;
+rl_re_read_init_file (int count __attribute__((unused)),
+ int ignore __attribute__((unused)))
{
int r;
r = rl_read_init_file ((char *)NULL);
@@ -702,8 +699,7 @@ rl_re_read_init_file (count, ignore)
If the file existed and could be opened and read, 0 is returned,
otherwise errno is returned. */
int
-rl_read_init_file (filename)
- char *filename;
+rl_read_init_file (const char *filename)
{
/* Default the filename. */
if (filename == 0)
@@ -722,9 +718,7 @@ rl_read_init_file (filename)
}
static int
-_rl_read_init_file (filename, include_level)
- char *filename;
- int include_level;
+_rl_read_init_file (const char *filename, int include_level)
{
register int i;
char *buffer, *openname, *line, *end;
@@ -739,7 +733,7 @@ _rl_read_init_file (filename, include_level)
if (buffer == 0)
return (errno);
-
+
if (include_level == 0 && filename != last_readline_init_file)
{
FREE (last_readline_init_file);
@@ -797,7 +791,7 @@ _rl_init_file_error (msg)
/* Conditionals. */
/* Calling programs set this to have their argv[0]. */
-char *rl_readline_name = "other";
+const char *rl_readline_name = "other";
/* Stack of previous values of parsing_conditionalized_out. */
static unsigned char *if_stack = (unsigned char *)NULL;
@@ -881,7 +875,7 @@ parser_if (args)
/* Invert the current parser state if there is anything on the stack. */
static int
parser_else (args)
- char *args;
+char *args __attribute__((unused));
{
register int i;
@@ -906,7 +900,7 @@ parser_else (args)
_rl_parsing_conditionalized_out from the stack. */
static int
parser_endif (args)
- char *args;
+char *args __attribute__((unused));
{
if (if_stack_depth)
_rl_parsing_conditionalized_out = if_stack[--if_stack_depth];
@@ -919,7 +913,8 @@ static int
parser_include (args)
char *args;
{
- char *old_init_file, *e;
+ const char *old_init_file;
+ char *e;
int old_line_number, old_include_level, r;
if (_rl_parsing_conditionalized_out)
@@ -940,10 +935,10 @@ parser_include (args)
return r;
}
-
+
/* Associate textual names with actual functions. */
static struct {
- char *name;
+ const char *name;
Function *function;
} parser_directives [] = {
{ "if", parser_if },
@@ -1233,7 +1228,7 @@ rl_parse_and_bind (string)
false. */
static struct {
- char *name;
+ const char *name;
int *value;
} boolean_varlist [] = {
#if defined (PAREN_MATCHING)
@@ -1375,7 +1370,7 @@ rl_variable_bind (name, value)
_rl_isearch_terminators[end] = '\0';
free (v);
}
-
+
/* For the time being, unknown variable names are simply ignored. */
return 0;
}
@@ -1384,7 +1379,7 @@ rl_variable_bind (name, value)
For example, `Space' returns ' '. */
typedef struct {
- char *name;
+ const char *name;
int value;
} assoc_list;
@@ -1418,7 +1413,7 @@ glean_key_from_name (name)
/* Auxiliary functions to manage keymaps. */
static struct {
- char *name;
+ const char *name;
Keymap map;
} keymap_names[] = {
{ "emacs", emacs_standard_keymap },
@@ -1446,7 +1441,7 @@ rl_get_keymap_by_name (name)
return ((Keymap) NULL);
}
-char *
+const char *
rl_get_keymap_name (map)
Keymap map;
{
@@ -1456,7 +1451,7 @@ rl_get_keymap_name (map)
return (keymap_names[i].name);
return ((char *)NULL);
}
-
+
void
rl_set_keymap (map)
Keymap map;
@@ -1482,7 +1477,7 @@ rl_set_keymap_from_edit_mode ()
#endif /* VI_MODE */
}
-char *
+const char *
rl_get_keymap_name_from_edit_mode ()
{
if (rl_editing_mode == emacs_mode)
@@ -1675,7 +1670,7 @@ rl_invoking_keyseqs_in_map (function, map)
keyname[0] = (char) key;
keyname[1] = '\0';
}
-
+
strcat (keyname, seqs[i]);
free (seqs[i]);
@@ -1780,8 +1775,8 @@ rl_function_dumper (print_readably)
rl_outstream. If an explicit argument is given, then print
the output in such a way that it can be read back in. */
int
-rl_dump_functions (count, key)
- int count, key;
+rl_dump_functions (int count __attribute__((unused)),
+ int key __attribute__((unused)))
{
if (rl_dispatching)
fprintf (rl_outstream, "\r\n");
@@ -1865,8 +1860,8 @@ rl_macro_dumper (print_readably)
}
int
-rl_dump_macros (count, key)
- int count, key;
+rl_dump_macros (int count __attribute__((unused)),
+ int key __attribute__((unused)))
{
if (rl_dispatching)
fprintf (rl_outstream, "\r\n");
@@ -1880,7 +1875,7 @@ rl_variable_dumper (print_readably)
int print_readably;
{
int i;
- char *kname;
+ const char *kname;
for (i = 0; boolean_varlist[i].name; i++)
{
@@ -1955,8 +1950,8 @@ rl_variable_dumper (print_readably)
rl_outstream. If an explicit argument is given, then print
the output in such a way that it can be read back in. */
int
-rl_dump_variables (count, key)
- int count, key;
+rl_dump_variables (int count __attribute__((unused)),
+ int key __attribute__((unused)))
{
if (rl_dispatching)
fprintf (rl_outstream, "\r\n");
diff --git a/readline/callback.c b/readline/callback.c
index 6915be483a4..200f3cc37f9 100644
--- a/readline/callback.c
+++ b/readline/callback.c
@@ -29,6 +29,7 @@
#if defined (READLINE_CALLBACKS)
+#include <stdlib.h>
#include <sys/types.h>
#include <stdio.h>
diff --git a/readline/complete.c b/readline/complete.c
index ade317ff578..8810ca06d5f 100644
--- a/readline/complete.c
+++ b/readline/complete.c
@@ -95,7 +95,7 @@ extern int rl_display_fixed;
VFunction *rl_completion_display_matches_hook = (VFunction *)NULL;
/* Forward declarations for functions defined and used in this file. */
-char *filename_completion_function ();
+char *filename_completion_function (const char *text, int state);
char **completion_matches ();
#if defined (VISIBLE_STATS)
@@ -186,15 +186,15 @@ int rl_completion_query_items = 100;
/* The basic list of characters that signal a break between words for the
completer routine. The contents of this variable is what breaks words
in the shell, i.e. " \t\n\"\\'`@$><=" */
-char *rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{(";
+const char *rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{(";
/* List of basic quoting characters. */
-char *rl_basic_quote_characters = "\"'";
+const char *rl_basic_quote_characters = "\"'";
/* The list of characters that signal a break between words for
rl_complete_internal. The default list is the contents of
rl_basic_word_break_characters. */
-char *rl_completer_word_break_characters = (char *)NULL;
+const char *rl_completer_word_break_characters = (char *)NULL;
/* List of characters which can be used to quote a substring of the line.
Completion occurs on the entire substring, and within the substring
@@ -241,7 +241,7 @@ Function *rl_ignore_some_completions_function = (Function *)NULL;
and a pointer to the quoting character to be used, which the function can
reset if desired. */
CPFunction *rl_filename_quoting_function = rl_quote_filename;
-
+
/* Function to call to remove quoting characters from a filename. Called
before completion is attempted, so the embedded quotes do not interfere
with matching names in the file system. Readline doesn't do anything
@@ -291,14 +291,14 @@ rl_complete (ignore, invoking_key)
/* List the possible completions. See description of rl_complete (). */
int
rl_possible_completions (ignore, invoking_key)
- int ignore, invoking_key;
+ int ignore __attribute__((unused)), invoking_key __attribute__((unused));
{
return (rl_complete_internal ('?'));
}
int
rl_insert_completions (ignore, invoking_key)
- int ignore, invoking_key;
+ int ignore __attribute__((unused)), invoking_key __attribute__((unused));
{
return (rl_complete_internal ('*'));
}
@@ -513,7 +513,7 @@ print_filename (to_print, full_pathname)
static char *
rl_quote_filename (s, rtype, qcp)
char *s;
- int rtype;
+ int rtype __attribute__((unused));
char *qcp;
{
char *r;
@@ -1010,7 +1010,7 @@ display_matches (matches)
(*rl_completion_display_matches_hook) (matches, len, max);
return;
}
-
+
/* If there are many items, then ask the user if she really wants to
see them all. */
if (len >= rl_completion_query_items)
@@ -1356,9 +1356,7 @@ rl_complete_internal (what_to_do)
when there are no more matches.
*/
char **
-completion_matches (text, entry_function)
- char *text;
- CPFunction *entry_function;
+completion_matches (const char *text, CPFunction *entry_function)
{
/* Number of slots in match_list. */
int match_list_size;
@@ -1403,9 +1401,7 @@ completion_matches (text, entry_function)
TEXT contains a partial username preceded by a random
character (usually `~'). */
char *
-username_completion_function (text, state)
- char *text;
- int state;
+username_completion_function (const char *text, int state)
{
#if defined (__GO32__) || defined (__WIN__) || defined (__OPENNT)
return (char *)NULL;
@@ -1460,9 +1456,7 @@ username_completion_function (text, state)
because of all the pathnames that must be followed when looking up the
completion for a command. */
char *
-filename_completion_function (text, state)
- char *text;
- int state;
+filename_completion_function (const char *text, int state)
{
static DIR *directory = (DIR *)NULL;
static char *filename = (char *)NULL;
@@ -1639,8 +1633,7 @@ filename_completion_function (text, state)
hit the end of the match list, we restore the original unmatched text,
ring the bell, and reset the counter to zero. */
int
-rl_menu_complete (count, ignore)
- int count, ignore;
+rl_menu_complete (int count, int ignore __attribute__((unused)))
{
Function *our_func;
int matching_filenames, found_quote;
diff --git a/readline/display.c b/readline/display.c
index 25aba64ca67..e21af1f472d 100644
--- a/readline/display.c
+++ b/readline/display.c
@@ -79,9 +79,9 @@ extern int _rl_output_character_function ();
#endif
extern int _rl_backspace ();
-extern char *term_clreol, *term_clrpag;
-extern char *term_im, *term_ic, *term_ei, *term_DC;
-extern char *term_up, *term_dc, *term_cr, *term_IC;
+extern const char *term_clreol, *term_clrpag;
+extern const char *term_im, *term_ic, *term_ei, *term_DC;
+extern const char *term_up, *term_dc, *term_cr, *term_IC;
extern int screenheight, screenwidth, screenchars;
extern int terminal_can_insert, _rl_term_autowrap;
@@ -141,7 +141,7 @@ int _rl_suppress_redisplay = 0;
/* The stuff that gets printed out before the actual text of the line.
This is usually pointing to rl_prompt. */
-char *rl_display_prompt = (char *)NULL;
+const char *rl_display_prompt = (char *)NULL;
/* Pseudo-global variables declared here. */
/* The visible cursor position. If you print some text, adjust this. */
@@ -218,7 +218,7 @@ expand_prompt (pmt, lp, lip)
l = strlen (pmt);
r = ret = xmalloc (l + 1);
-
+
for (rl = ignoring = last = 0, p = pmt; p && *p; p++)
{
/* This code strips the invisible character string markers
@@ -315,7 +315,7 @@ rl_redisplay ()
register char *line;
int c_pos, inv_botlin, lb_botlin, lb_linenum;
int newlines, lpos, temp;
- char *prompt_this_line;
+ const char *prompt_this_line;
if (!readline_echoing_p)
return;
@@ -831,7 +831,7 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
if (old[0] && new[0])
old[0] = new[0];
}
-
+
/* Find first difference. */
for (ofd = old, nfd = new;
(ofd - old < omax) && *ofd && (*ofd == *nfd);
@@ -1229,8 +1229,7 @@ rl_message (va_alist)
}
#else /* !USE_VARARGS */
int
-rl_message (format, arg1, arg2)
- char *format;
+rl_message (char *format, void *arg1, void *arg2)
{
sprintf (msg_buf, format, arg1, arg2);
rl_display_prompt = msg_buf;
@@ -1512,7 +1511,8 @@ cr ()
void
_rl_redisplay_after_sigwinch ()
{
- char *t, *oldp, *oldl, *oldlprefix;
+ char *t, *oldl, *oldlprefix;
+ const char *oldp;
/* Clear the current line and put the cursor at column 0. Make sure
the right thing happens if we have wrapped to a new screen line. */
diff --git a/readline/funmap.c b/readline/funmap.c
index f6b86286fe0..472119bd80a 100644
--- a/readline/funmap.c
+++ b/readline/funmap.c
@@ -180,16 +180,14 @@ static FUNMAP default_funmap[] = {
};
int
-rl_add_funmap_entry (name, function)
- char *name;
- Function *function;
+rl_add_funmap_entry (const char *name, Function *function)
{
if (funmap_entry + 2 >= funmap_size)
{
funmap_size += 64;
funmap = (FUNMAP **)xrealloc (funmap, funmap_size * sizeof (FUNMAP *));
}
-
+
funmap[funmap_entry] = (FUNMAP *)xmalloc (sizeof (FUNMAP));
funmap[funmap_entry]->name = name;
funmap[funmap_entry]->function = function;
@@ -236,7 +234,7 @@ rl_funmap_names ()
result = (char **)xrealloc (result, result_size * sizeof (char *));
}
- result[result_index] = funmap[result_index]->name;
+ result[result_index] = (char*) funmap[result_index]->name;
result[result_index + 1] = (char *)NULL;
}
@@ -245,10 +243,10 @@ rl_funmap_names ()
}
/* Things that mean `Control'. */
-char *possible_control_prefixes[] = {
+const char *possible_control_prefixes[] = {
"Control-", "C-", "CTRL-", (char *)NULL
};
-char *possible_meta_prefixes[] = {
+const char *possible_meta_prefixes[] = {
"Meta", "M-", (char *)NULL
};
diff --git a/readline/histexpand.c b/readline/histexpand.c
index 30c6131801d..f78838ef2ba 100644
--- a/readline/histexpand.c
+++ b/readline/histexpand.c
@@ -87,7 +87,7 @@ char history_comment_char = '\0';
/* The list of characters which inhibit the expansion of text if found
immediately following history_expansion_char. */
-char *history_no_expand_chars = " \t\n\r=";
+const char *history_no_expand_chars = " \t\n\r=";
/* If set to a non-zero value, single quotes inhibit history expansion.
The default is 0. */
@@ -249,7 +249,7 @@ get_history_event (string, caller_index, delimiting_quote)
{
entry = current_history ();
history_offset = history_length;
-
+
/* If this was a substring search, then remember the
string that we matched for word substitution. */
if (substring_okay)
@@ -342,7 +342,8 @@ hist_error(s, start, current, errtype)
char *s;
int start, current, errtype;
{
- char *temp, *emsg;
+ char *temp;
+ const char *emsg;
int ll, elen;
ll = current - start;
@@ -514,7 +515,7 @@ history_expand_internal (string, start, end_index_ptr, ret_string, current_line)
quoted_search_delimiter = string[i - 1];
event = get_history_event (string, &i, quoted_search_delimiter);
}
-
+
if (event == 0)
{
*ret_string = hist_error (string, start, i, EVENT_NOT_FOUND);
@@ -825,7 +826,7 @@ history_expand (hstring, output)
*output = savestring (hstring);
return (0);
}
-
+
/* Prepare the buffer for printing error messages. */
result = xmalloc (result_len = 256);
result[0] = '\0';
@@ -904,7 +905,7 @@ history_expand (hstring, output)
i++;
}
}
-
+
if (string[i] != history_expansion_char)
{
free (result);
@@ -1239,7 +1240,7 @@ history_tokenize_internal (string, wind, indp)
return (result);
start = i;
-
+
if (member (string[i], "()\n"))
{
i++;
diff --git a/readline/histfile.c b/readline/histfile.c
index 3325b7fc1f7..1da45b00b58 100644
--- a/readline/histfile.c
+++ b/readline/histfile.c
@@ -84,14 +84,15 @@ static char *
history_filename (filename)
char *filename;
{
- char *return_val, *home;
+ char *return_val;
+ const char *home;
int home_len;
return_val = filename ? savestring (filename) : (char *)NULL;
if (return_val)
return (return_val);
-
+
home = get_env_value ("HOME");
if (home == 0)
@@ -130,11 +131,10 @@ read_history_range (filename, from, to)
char *filename;
int from, to;
{
- register int line_start, line_end;
char *input, *buffer;
int file, current_line;
struct stat finfo;
- size_t file_size;
+ size_t line_start, line_end, file_size;
buffer = (char *)NULL;
input = history_filename (filename);
diff --git a/readline/history.c b/readline/history.c
index d56ffacc6a0..804ffddcd89 100644
--- a/readline/history.c
+++ b/readline/history.c
@@ -161,7 +161,7 @@ history_set_pos (pos)
history_offset = pos;
return (1);
}
-
+
/* Return the current history array. The caller has to be carefull, since this
is the actual array of data, and could be bashed or made corrupt easily.
The array is terminated with a NULL pointer. */
diff --git a/readline/history.h b/readline/history.h
index 8ecce726779..88bf471bb62 100644
--- a/readline/history.h
+++ b/readline/history.h
@@ -116,7 +116,7 @@ extern HIST_ENTRY **history_list __P((void));
/* Returns the number which says what history element we are now
looking at. */
extern int where_history __P((void));
-
+
/* Return the history entry at the current position, as determined by
history_offset. If there is no entry there, return a NULL pointer. */
HIST_ENTRY *current_history __P((void));
@@ -232,8 +232,8 @@ extern int max_input_history;
extern char history_expansion_char;
extern char history_subst_char;
extern char history_comment_char;
-extern char *history_no_expand_chars;
-extern char *history_search_delimiter_chars;
+extern const char *history_no_expand_chars;
+extern const char *history_search_delimiter_chars;
extern int history_quotes_inhibit_expansion;
/* If set, this function is called to decide whether or not a particular
diff --git a/readline/histsearch.c b/readline/histsearch.c
index 7e98e950acb..eb17e9332e8 100644
--- a/readline/histsearch.c
+++ b/readline/histsearch.c
@@ -52,7 +52,7 @@ extern int history_offset;
/* The list of alternate characters that can delimit a history search
string. */
-char *history_search_delimiter_chars = (char *)NULL;
+const char *history_search_delimiter_chars = (char *)NULL;
/* Search the history for STRING, starting at history_offset.
If DIRECTION < 0, then the search is through previous entries, else
diff --git a/readline/input.c b/readline/input.c
index e23af552494..ea1342969b0 100644
--- a/readline/input.c
+++ b/readline/input.c
@@ -311,7 +311,7 @@ _rl_input_available ()
void
_rl_insert_typein (c)
int c;
-{
+{
int key, t, i;
char *string;
diff --git a/readline/isearch.c b/readline/isearch.c
index ae8dce520f0..a4a294b6b20 100644
--- a/readline/isearch.c
+++ b/readline/isearch.c
@@ -97,7 +97,8 @@ rl_forward_search_history (sign, key)
static void
rl_display_search (search_string, reverse_p, where)
char *search_string;
- int reverse_p, where;
+ int reverse_p;
+ int where __attribute__((unused));
{
char *message;
int msglen, searchlen;
@@ -144,8 +145,7 @@ rl_display_search (search_string, reverse_p, where)
DIRECTION is which direction to search; >= 0 means forward, < 0 means
backwards. */
static int
-rl_search_history (direction, invoking_key)
- int direction, invoking_key;
+rl_search_history (int direction, int invoking_key __attribute__((unused)))
{
/* The string that the user types in to search for. */
char *search_string;
diff --git a/readline/kill.c b/readline/kill.c
index 0b4714fafa8..78387e138c2 100644
--- a/readline/kill.c
+++ b/readline/kill.c
@@ -82,8 +82,7 @@ static int rl_kill_ring_length;
/* How to say that you only want to save a certain amount
of kill material. */
int
-rl_set_retained_kills (num)
- int num;
+rl_set_retained_kills (int num __attribute__((unused)))
{
return 0;
}
@@ -285,8 +284,8 @@ rl_backward_kill_line (direction, ignore)
/* Kill the whole line, no matter where point is. */
int
-rl_kill_full_line (count, ignore)
- int count, ignore;
+rl_kill_full_line (int count __attribute__((unused)),
+ int ignore __attribute__((unused)))
{
rl_begin_undo_group ();
rl_point = 0;
@@ -302,8 +301,7 @@ rl_kill_full_line (count, ignore)
/* This does what C-w does in Unix. We can't prevent people from
using behaviour that they expect. */
int
-rl_unix_word_rubout (count, key)
- int count, key;
+rl_unix_word_rubout (int count, int key __attribute__((unused)))
{
int orig_point;
@@ -336,8 +334,8 @@ rl_unix_word_rubout (count, key)
into the line at all, and if you aren't, then you know what you are
doing. */
int
-rl_unix_line_discard (count, key)
- int count, key;
+rl_unix_line_discard (int count __attribute__((unused)),
+ int key __attribute__((unused)))
{
if (rl_point == 0)
ding ();
@@ -374,16 +372,16 @@ region_kill_internal (delete)
/* Copy the text in the region to the kill ring. */
int
-rl_copy_region_to_kill (count, ignore)
- int count, ignore;
+rl_copy_region_to_kill (int count __attribute__((unused)),
+ int key __attribute__((unused)))
{
return (region_kill_internal (0));
}
/* Kill the text between the point and mark. */
int
-rl_kill_region (count, ignore)
- int count, ignore;
+rl_kill_region (int count __attribute__((unused)),
+ int key __attribute__((unused)))
{
int r;
@@ -442,11 +440,11 @@ rl_copy_backward_word (count, key)
return (_rl_copy_word_as_kill (count, -1));
}
-
+
/* Yank back the last killed text. This ignores arguments. */
int
-rl_yank (count, ignore)
- int count, ignore;
+rl_yank (int count __attribute__((unused)),
+ int key __attribute__((unused)))
{
if (rl_kill_ring == 0)
{
@@ -464,8 +462,8 @@ rl_yank (count, ignore)
delete that text from the line, rotate the index down, and
yank back some other text. */
int
-rl_yank_pop (count, key)
- int count, key;
+rl_yank_pop (int count __attribute__((unused)),
+ int key __attribute__((unused)))
{
int l, n;
@@ -592,7 +590,7 @@ rl_yank_last_arg (count, key)
if (history_skip < 0)
history_skip = 0;
}
-
+
if (explicit_arg_p)
retval = rl_yank_nth_arg_internal (count_passed, key, history_skip);
else
diff --git a/readline/macro.c b/readline/macro.c
index f3c442b41c3..b4d7835c631 100644
--- a/readline/macro.c
+++ b/readline/macro.c
@@ -90,7 +90,7 @@ static int current_macro_index;
It is a linked list of string/index for each saved macro. */
struct saved_macro {
struct saved_macro *next;
- char *string;
+ const char *string;
int sindex;
};
@@ -100,11 +100,10 @@ static struct saved_macro *macro_list = (struct saved_macro *)NULL;
/* Set up to read subsequent input from STRING.
STRING is free ()'ed when we are done with it. */
void
-_rl_with_macro_input (string)
- char *string;
+_rl_with_macro_input (const char *string)
{
_rl_push_executing_macro ();
- _rl_executing_macro = string;
+ _rl_executing_macro = (char*) string;
executing_macro_index = 0;
}
@@ -155,7 +154,7 @@ _rl_pop_executing_macro ()
if (macro_list)
{
macro = macro_list;
- _rl_executing_macro = macro_list->string;
+ _rl_executing_macro = (char*) macro_list->string;
executing_macro_index = macro_list->sindex;
macro_list = macro_list->next;
free (macro);
@@ -206,8 +205,8 @@ _rl_kill_kbd_macro ()
definition to the end of the existing macro, and start by
re-executing the existing macro. */
int
-rl_start_kbd_macro (ignore1, ignore2)
- int ignore1, ignore2;
+rl_start_kbd_macro (int count __attribute__((unused)),
+ int key __attribute__((unused)))
{
if (_rl_defining_kbd_macro)
{
@@ -231,8 +230,7 @@ rl_start_kbd_macro (ignore1, ignore2)
A numeric argument says to execute the macro right now,
that many times, counting the definition as the first time. */
int
-rl_end_kbd_macro (count, ignore)
- int count, ignore;
+rl_end_kbd_macro (int count, int ignore __attribute__((unused)))
{
if (_rl_defining_kbd_macro == 0)
{
@@ -251,8 +249,7 @@ rl_end_kbd_macro (count, ignore)
/* Execute the most recently defined keyboard macro.
COUNT says how many times to execute it. */
int
-rl_call_last_kbd_macro (count, ignore)
- int count, ignore;
+rl_call_last_kbd_macro (int count, int key __attribute__((unused)))
{
if (current_macro == 0)
_rl_abort_internal ();
diff --git a/readline/readline.c b/readline/readline.c
index 622811fc11e..1da73250773 100644
--- a/readline/readline.c
+++ b/readline/readline.c
@@ -129,8 +129,8 @@ extern int _rl_suppress_redisplay;
extern char *rl_display_prompt;
/* Variables imported from complete.c. */
-extern char *rl_completer_word_break_characters;
-extern char *rl_basic_word_break_characters;
+extern const char *rl_completer_word_break_characters;
+extern const char *rl_basic_word_break_characters;
extern int rl_completion_query_items;
extern int rl_complete_with_tilde_expansion;
@@ -181,7 +181,7 @@ extern char *xmalloc (), *xrealloc ();
/* */
/* **************************************************************** */
-char *rl_library_version = RL_LIBRARY_VERSION;
+const char *rl_library_version = RL_LIBRARY_VERSION;
/* A pointer to the keymap that is currently in use.
By default, it is the standard emacs keymap. */
@@ -280,7 +280,7 @@ int _rl_mark_modified_lines = 0;
/* The style of `bell' notification preferred. This can be set to NO_BELL,
AUDIBLE_BELL, or VISIBLE_BELL. */
int _rl_bell_preference = AUDIBLE_BELL;
-
+
/* String inserted into the line by rl_insert_comment (). */
char *_rl_comment_begin;
@@ -755,7 +755,7 @@ readline_initialize_everything ()
/* Decide whether we should automatically go into eight-bit mode. */
_rl_init_eightbit ();
-
+
/* Read in the init file. */
rl_read_init_file ((char *)NULL);
@@ -914,7 +914,7 @@ rl_digit_loop ()
/* Add the current digit to the argument in progress. */
int
rl_digit_argument (ignore, key)
- int ignore, key;
+ int ignore __attribute__((unused)), key;
{
rl_pending_input = key;
return (rl_digit_loop ());
@@ -944,7 +944,7 @@ _rl_init_argument ()
dispatch on it. If the key is the abort character then abort. */
int
rl_universal_argument (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
rl_numeric_arg *= 4;
return (rl_digit_loop ());
@@ -960,8 +960,7 @@ rl_universal_argument (count, key)
way that you should do insertion. rl_insert () calls this
function. */
int
-rl_insert_text (string)
- char *string;
+rl_insert_text (const char *string)
{
register int i, l = strlen (string);
@@ -1147,7 +1146,7 @@ rl_backward (count, key)
/* Move to the beginning of the line. */
int
rl_beg_of_line (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
rl_point = 0;
return 0;
@@ -1156,7 +1155,7 @@ rl_beg_of_line (count, key)
/* Move to the end of the line. */
int
rl_end_of_line (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
rl_point = rl_end;
return 0;
@@ -1253,7 +1252,7 @@ rl_backward_word (count, key)
/* Clear the current line. Numeric argument to C-l does this. */
int
rl_refresh_line (ignore1, ignore2)
- int ignore1, ignore2;
+ int ignore1 __attribute__((unused)), ignore2 __attribute__((unused));
{
int curr_line, nleft;
@@ -1313,7 +1312,7 @@ rl_clear_screen (count, key)
int
rl_arrow_keys (count, c)
- int count, c;
+ int count, c __attribute__((unused));
{
int ch;
@@ -1417,7 +1416,7 @@ rl_insert (count, c)
/* Insert the next typed character verbatim. */
int
rl_quoted_insert (count, key)
- int count, key;
+ int count, key __attribute__((unused));
{
int c;
@@ -1428,7 +1427,7 @@ rl_quoted_insert (count, key)
/* Insert a tab character. */
int
rl_tab_insert (count, key)
- int count, key;
+ int count, key __attribute__((unused));
{
return (rl_insert (count, '\t'));
}
@@ -1438,7 +1437,7 @@ rl_tab_insert (count, key)
meaning in the future. */
int
rl_newline (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
rl_done = 1;
@@ -1466,7 +1465,7 @@ rl_newline (count, key)
is special cased. */
int
rl_do_lowercase_version (ignore1, ignore2)
- int ignore1, ignore2;
+ int ignore1 __attribute__((unused)), ignore2 __attribute__((unused));
{
return 0;
}
@@ -1548,12 +1547,12 @@ rl_rubout_or_delete (count, key)
return (rl_rubout (count, key));
else
return (rl_delete (count, key));
-}
+}
/* Delete all spaces and tabs around point. */
int
rl_delete_horizontal_space (count, ignore)
- int count, ignore;
+ int count __attribute__((unused)), ignore __attribute__((unused));
{
int start = rl_point;
@@ -1594,7 +1593,7 @@ rl_delete_or_show_completions (count, key)
A K*rn shell style function. */
int
rl_insert_comment (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
rl_beg_of_line (1, key);
rl_insert_text (_rl_comment_begin ? _rl_comment_begin
@@ -1620,7 +1619,7 @@ static int rl_change_case ();
/* Uppercase the word at point. */
int
rl_upcase_word (count, key)
- int count, key;
+ int count, key __attribute__((unused));
{
return (rl_change_case (count, UpCase));
}
@@ -1628,7 +1627,7 @@ rl_upcase_word (count, key)
/* Lowercase the word at point. */
int
rl_downcase_word (count, key)
- int count, key;
+ int count, key __attribute__((unused));
{
return (rl_change_case (count, DownCase));
}
@@ -1636,7 +1635,7 @@ rl_downcase_word (count, key)
/* Upcase the first letter, downcase the rest. */
int
rl_capitalize_word (count, key)
- int count, key;
+ int count, key __attribute__((unused));
{
return (rl_change_case (count, CapCase));
}
@@ -1760,7 +1759,7 @@ rl_transpose_words (count, key)
then transpose the characters before point. */
int
rl_transpose_chars (count, key)
- int count, key;
+ int count, key __attribute__((unused));
{
char dummy[2];
@@ -1853,14 +1852,14 @@ _rl_char_search (count, fdir, bdir)
int
rl_char_search (count, key)
- int count, key;
+ int count, key __attribute__((unused));
{
return (_rl_char_search (count, FFIND, BFIND));
}
int
rl_backward_char_search (count, key)
- int count, key;
+ int count, key __attribute__((unused));
{
return (_rl_char_search (count, BFIND, FFIND));
}
@@ -1965,7 +1964,7 @@ maybe_save_line ()
/* Meta-< goes to the start of the history. */
int
rl_beginning_of_history (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
return (rl_get_previous_history (1 + where_history (), key));
}
@@ -1973,7 +1972,7 @@ rl_beginning_of_history (count, key)
/* Meta-> goes to the end of the history. (The current line). */
int
rl_end_of_history (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
maybe_replace_line ();
using_history ();
@@ -2105,7 +2104,7 @@ _rl_set_mark_at_pos (position)
/* A bindable command to set the mark. */
int
rl_set_mark (count, key)
- int count, key;
+ int count, key __attribute__((unused));
{
return (_rl_set_mark_at_pos (rl_explicit_arg ? count : rl_point));
}
@@ -2113,7 +2112,7 @@ rl_set_mark (count, key)
/* Exchange the position of mark and point. */
int
rl_exchange_point_and_mark (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
if (rl_mark > rl_end)
rl_mark = -1;
@@ -2137,7 +2136,7 @@ rl_exchange_point_and_mark (count, key)
/* How to toggle back and forth between editing modes. */
int
rl_vi_editing_mode (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
#if defined (VI_MODE)
rl_editing_mode = vi_mode;
@@ -2148,7 +2147,7 @@ rl_vi_editing_mode (count, key)
int
rl_emacs_editing_mode (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
rl_editing_mode = emacs_mode;
_rl_keymap = emacs_standard_keymap;
diff --git a/readline/readline.h b/readline/readline.h
index dba1a0fdde9..7804d31efb1 100644
--- a/readline/readline.h
+++ b/readline/readline.h
@@ -60,7 +60,7 @@ extern UNDO_LIST *rl_undo_list;
/* The data structure for mapping textual names to code addresses. */
typedef struct _funmap {
- char *name;
+ const char *name;
Function *function;
} FUNMAP;
@@ -286,17 +286,17 @@ extern int rl_translate_keyseq __P((char *, char *, int *));
extern char *rl_untranslate_keyseq __P((int));
extern Function *rl_named_function __P((char *));
-extern Function *rl_function_of_keyseq __P((char *, Keymap, int *));
+extern Function *rl_function_of_keyseq __P((const char *, Keymap, int *));
extern void rl_list_funmap_names __P((void));
extern char **rl_invoking_keyseqs_in_map __P((Function *, Keymap));
extern char **rl_invoking_keyseqs __P((Function *));
-
+
extern void rl_function_dumper __P((int));
extern void rl_macro_dumper __P((int));
extern void rl_variable_dumper __P((int));
-extern int rl_read_init_file __P((char *));
+extern int rl_read_init_file __P((const char *));
extern int rl_parse_and_bind __P((char *));
/* Functions for manipulating keymaps. */
@@ -306,14 +306,14 @@ extern Keymap rl_make_keymap __P((void));
extern void rl_discard_keymap __P((Keymap));
extern Keymap rl_get_keymap_by_name __P((char *));
-extern char *rl_get_keymap_name __P((Keymap));
+extern const char *rl_get_keymap_name __P((Keymap));
extern void rl_set_keymap __P((Keymap));
extern Keymap rl_get_keymap __P((void));
extern void rl_set_keymap_from_edit_mode __P((void));
-extern char *rl_get_keymap_name_from_edit_mode __P((void));
+extern const char *rl_get_keymap_name_from_edit_mode __P((void));
/* Functions for manipulating the funmap, which maps command names to functions. */
-extern int rl_add_funmap_entry __P((char *, Function *));
+extern int rl_add_funmap_entry __P((const char *, Function *));
extern void rl_initialize_funmap __P((void));
extern char **rl_funmap_names __P((void));
@@ -351,7 +351,7 @@ extern void rl_save_prompt __P((void));
extern void rl_restore_prompt __P((void));
/* Modifying text. */
-extern int rl_insert_text __P((char *));
+extern int rl_insert_text __P((const char *));
extern int rl_delete_text __P((int, int));
extern int rl_kill_text __P((int, int));
extern char *rl_copy_text __P((int, int));
@@ -380,7 +380,7 @@ extern int rl_clear_signals __P((void));
extern void rl_cleanup_after_signal __P((void));
extern void rl_reset_after_signal __P((void));
extern void rl_free_line_state __P((void));
-
+
/* Undocumented. */
extern int rl_expand_prompt __P((char *));
@@ -392,9 +392,9 @@ extern int maybe_replace_line __P((void));
extern int rl_complete_internal __P((int));
extern void rl_display_match_list __P((char **, int, int));
-extern char **completion_matches __P((char *, CPFunction *));
-extern char *username_completion_function __P((char *, int));
-extern char *filename_completion_function __P((char *, int));
+extern char **completion_matches __P((const char *, CPFunction *));
+extern char *username_completion_function __P((const char *, int));
+extern char *filename_completion_function __P((const char *, int));
/* **************************************************************** */
/* */
@@ -403,11 +403,11 @@ extern char *filename_completion_function __P((char *, int));
/* **************************************************************** */
/* The version of this incarnation of the readline library. */
-extern char *rl_library_version;
+extern const char *rl_library_version;
/* The name of the calling program. You should initialize this to
whatever was in argv[0]. It is used when parsing conditionals. */
-extern char *rl_readline_name;
+extern const char *rl_readline_name;
/* The prompt readline uses. This is set from the argument to
readline (), and should not be assigned to directly. */
@@ -448,7 +448,7 @@ extern Function *rl_startup_hook;
readline_internal_setup () returns and readline_internal starts
reading input characters. */
extern Function *rl_pre_input_hook;
-
+
/* The address of a function to call periodically while Readline is
awaiting character input, or NULL, for no event handling. */
extern Function *rl_event_hook;
@@ -506,12 +506,12 @@ extern CPPFunction *rl_attempted_completion_function;
/* The basic list of characters that signal a break between words for the
completer routine. The initial contents of this variable is what
breaks words in the shell, i.e. "n\"\\'`@$>". */
-extern char *rl_basic_word_break_characters;
+extern const char *rl_basic_word_break_characters;
/* The list of characters that signal a break between words for
rl_complete_internal. The default list is the contents of
rl_basic_word_break_characters. */
-extern char *rl_completer_word_break_characters;
+extern const char *rl_completer_word_break_characters;
/* List of characters which can be used to quote a substring of the line.
Completion occurs on the entire substring, and within the substring
@@ -520,7 +520,7 @@ extern char *rl_completer_word_break_characters;
extern char *rl_completer_quote_characters;
/* List of quote characters which cause a word break. */
-extern char *rl_basic_quote_characters;
+extern const char *rl_basic_quote_characters;
/* List of characters that need to be quoted in filenames by the completer. */
extern char *rl_filename_quote_characters;
@@ -599,7 +599,7 @@ extern int rl_ignore_completion_duplicates;
/* If this is non-zero, completion is (temporarily) inhibited, and the
completion character will be inserted as any other. */
extern int rl_inhibit_completion;
-
+
/* Definitions available for use by readline clients. */
#define RL_PROMPT_START_IGNORE '\001'
#define RL_PROMPT_END_IGNORE '\002'
diff --git a/readline/rlstdc.h b/readline/rlstdc.h
index d2c5f874d7a..f79cf89fe76 100644
--- a/readline/rlstdc.h
+++ b/readline/rlstdc.h
@@ -76,4 +76,8 @@
#endif /* !__STDC__ */
+#if !defined(__attribute__) && (defined(__cplusplus) || !defined(__GNUC__) || __GNUC__ == 2 && __GNUC_MINOR__ < 8)
+#define __attribute__(A)
+#endif
+
#endif /* !_RL_STDC_H_ */
diff --git a/readline/rltty.c b/readline/rltty.c
index b4d0cf127d5..f87c1c9747f 100644
--- a/readline/rltty.c
+++ b/readline/rltty.c
@@ -368,12 +368,15 @@ static TIOTYPE otio;
# define OUTPUT_BEING_FLUSHED(tp) 0
#endif
+#if defined (_AIX) || (defined (FLUSHO) && defined (_AIX41))
static void
rltty_warning (msg)
char *msg;
{
fprintf (stderr, "readline: warning: %s\n", msg);
}
+#endif
+
#if defined (_AIX)
void
@@ -604,8 +607,8 @@ rl_deprep_terminal ()
/* **************************************************************** */
int
-rl_restart_output (count, key)
- int count, key;
+rl_restart_output (int count __attribute__((unused)),
+ int key __attribute__((unused)))
{
int fildes = fileno (rl_outstream);
#if defined (TIOCSTART)
@@ -637,8 +640,8 @@ rl_restart_output (count, key)
}
int
-rl_stop_output (count, key)
- int count, key;
+rl_stop_output (int count __attribute__((unused)),
+ int key __attribute__((unused)))
{
int fildes = fileno (rl_instream);
diff --git a/readline/search.c b/readline/search.c
index f198e7409e5..0179d8da2f1 100644
--- a/readline/search.c
+++ b/readline/search.c
@@ -247,8 +247,7 @@ noninc_search (dir, pchar)
/* Search forward through the history list for a string. If the vi-mode
code calls this, KEY will be `?'. */
int
-rl_noninc_forward_search (count, key)
- int count, key;
+rl_noninc_forward_search (int count __attribute__((unused)), int key)
{
noninc_search (1, (key == '?') ? '?' : 0);
return 0;
@@ -257,8 +256,7 @@ rl_noninc_forward_search (count, key)
/* Reverse search the history list for a string. If the vi-mode code
calls this, KEY will be `/'. */
int
-rl_noninc_reverse_search (count, key)
- int count, key;
+rl_noninc_reverse_search (int count __attribute__((unused)), int key)
{
noninc_search (-1, (key == '/') ? '/' : 0);
return 0;
@@ -267,8 +265,8 @@ rl_noninc_reverse_search (count, key)
/* Search forward through the history list for the last string searched
for. If there is no saved search string, abort. */
int
-rl_noninc_forward_search_again (count, key)
- int count, key;
+rl_noninc_forward_search_again (int count __attribute__((unused)),
+ int key __attribute__((unused)))
{
if (!noninc_search_string)
{
@@ -282,8 +280,8 @@ rl_noninc_forward_search_again (count, key)
/* Reverse search in the history list for the last string searched
for. If there is no saved search string, abort. */
int
-rl_noninc_reverse_search_again (count, key)
- int count, key;
+rl_noninc_reverse_search_again (int count __attribute__((unused)),
+ int key __attribute__((unused)))
{
if (!noninc_search_string)
{
@@ -352,8 +350,7 @@ rl_history_search_internal (count, direction)
from the start of the line to rl_point. This is a non-incremental
search. */
int
-rl_history_search_forward (count, ignore)
- int count, ignore;
+rl_history_search_forward (int count, int ignore __attribute__((unused)))
{
if (count == 0)
return (0);
@@ -366,8 +363,7 @@ rl_history_search_forward (count, ignore)
from the start of the line to rl_point. This is a non-incremental
search. */
int
-rl_history_search_backward (count, ignore)
- int count, ignore;
+rl_history_search_backward (int count, int ignore __attribute__((unused)))
{
if (count == 0)
return (0);
diff --git a/readline/shell.c b/readline/shell.c
index 4d9e0064d3f..becd66e0f9a 100644
--- a/readline/shell.c
+++ b/readline/shell.c
@@ -26,6 +26,7 @@
# include <config.h>
#endif
+#include <stdio.h>
#include <sys/types.h>
#if defined (HAVE_UNISTD_H)
diff --git a/readline/terminal.c b/readline/terminal.c
index 6e94bdc4011..1d2fead7768 100644
--- a/readline/terminal.c
+++ b/readline/terminal.c
@@ -99,8 +99,8 @@ char PC, *BC, *UP;
#endif /* __linux__ */
/* Some strings to control terminal actions. These are output by tputs (). */
-char *term_goto, *term_clreol, *term_cr, *term_clrpag, *term_backspace;
-char *term_pc;
+char *term_goto, *term_clreol, *term_clrpag, *term_backspace;
+char *term_cr, *term_pc;
/* Non-zero if we determine that the terminal can do character insertion. */
int terminal_can_insert = 0;
@@ -245,8 +245,8 @@ rl_resize_terminal ()
}
struct _tc_string {
- char *tc_var;
- char **tc_value;
+ const char *tc_var;
+ char **tc_value;
};
/* This should be kept sorted, just in case we decide to change the
@@ -291,7 +291,7 @@ get_term_capabilities (bp)
{
register int i;
- for (i = 0; i < NUM_TC_STRINGS; i++)
+ for (i = 0; i < (int) NUM_TC_STRINGS; i++)
*(tc_strings[i].tc_value) = tgetstr (tc_strings[i].tc_var, bp);
tcap_initialized = 1;
}
@@ -304,7 +304,7 @@ _rl_init_terminal_io (terminal_name)
screenwidth = ScreenCols ();
screenheight = ScreenRows ();
screenchars = screenwidth * screenheight;
- term_cr = "\r";
+ term_cr = (char*) "\r";
term_im = term_ei = term_ic = term_IC = (char *)NULL;
term_up = term_dc = term_DC = visible_bell = (char *)NULL;
@@ -322,7 +322,8 @@ _rl_init_terminal_io (terminal_name)
return;
#else /* !__GO32__ */
- char *term, *buffer;
+ const char *term;
+ char *buffer;
int tty;
Keymap xkeymap;
@@ -347,7 +348,7 @@ _rl_init_terminal_io (terminal_name)
screenwidth = 79;
screenheight = 24;
screenchars = 79 * 24;
- term_cr = "\r";
+ term_cr = (char*) "\r";
term_im = term_ei = term_ic = term_IC = (char *)NULL;
term_up = term_dc = term_DC = visible_bell = (char *)NULL;
term_ku = term_kd = term_kl = term_kr = (char *)NULL;
@@ -367,7 +368,7 @@ _rl_init_terminal_io (terminal_name)
UP = term_up;
if (!term_cr)
- term_cr = "\r";
+ term_cr = (char*) "\r";
tty = rl_instream ? fileno (rl_instream) : 0;
@@ -427,7 +428,7 @@ rl_get_termcap (cap)
if (tcap_initialized == 0)
return ((char *)NULL);
- for (i = 0; i < NUM_TC_STRINGS; i++)
+ for (i = 0; i < (int) NUM_TC_STRINGS; i++)
{
if (tc_strings[i].tc_var[0] == cap[0] && strcmp (tc_strings[i].tc_var, cap) == 0)
return *(tc_strings[i].tc_value);
diff --git a/readline/tilde.c b/readline/tilde.c
index 65a1e2f3902..05c9ed741ed 100644
--- a/readline/tilde.c
+++ b/readline/tilde.c
@@ -82,13 +82,13 @@ extern char *get_env_value ();
/* The default value of tilde_additional_prefixes. This is set to
whitespace preceding a tilde so that simple programs which do not
perform any word separation get desired behaviour. */
-static char *default_prefixes[] =
+static const char *default_prefixes[] =
{ " ~", "\t~", (char *)NULL };
/* The default value of tilde_additional_suffixes. This is set to
whitespace or newline so that simple programs which do not
perform any word separation get desired behaviour. */
-static char *default_suffixes[] =
+static const char *default_suffixes[] =
{ " ", "\n", (char *)NULL };
/* If non-null, this contains the address of a function that the application
@@ -106,12 +106,12 @@ CPFunction *tilde_expansion_failure_hook = (CPFunction *)NULL;
/* When non-null, this is a NULL terminated array of strings which
are duplicates for a tilde prefix. Bash uses this to expand
`=~' and `:~'. */
-char **tilde_additional_prefixes = default_prefixes;
+const char ** tilde_additional_prefixes = default_prefixes;
/* When non-null, this is a NULL terminated array of strings which match
the end of a username, instead of just "/". Bash sets this to
`:' and `=~'. */
-char **tilde_additional_suffixes = default_suffixes;
+const char **tilde_additional_suffixes = default_suffixes;
/* Find the start of a tilde expansion in STRING, and return the index of
the tilde which starts the expansion. Place the length of the text
@@ -122,7 +122,7 @@ tilde_find_prefix (string, len)
int *len;
{
register int i, j, string_len;
- register char **prefixes = tilde_additional_prefixes;
+ register const char **prefixes = tilde_additional_prefixes;
string_len = strlen (string);
*len = 0;
@@ -154,7 +154,7 @@ tilde_find_suffix (string)
char *string;
{
register int i, j, string_len;
- register char **suffixes;
+ register const char **suffixes;
suffixes = tilde_additional_suffixes;
string_len = strlen (string);
diff --git a/readline/tilde.h b/readline/tilde.h
index 634b95449aa..45eea1b66e5 100644
--- a/readline/tilde.h
+++ b/readline/tilde.h
@@ -48,12 +48,12 @@ extern CPFunction *tilde_expansion_failure_hook;
/* When non-null, this is a NULL terminated array of strings which
are duplicates for a tilde prefix. Bash uses this to expand
`=~' and `:~'. */
-extern char **tilde_additional_prefixes;
+extern const char **tilde_additional_prefixes;
/* When non-null, this is a NULL terminated array of strings which match
the end of a username, instead of just "/". Bash sets this to
`:' and `=~'. */
-extern char **tilde_additional_suffixes;
+extern const char **tilde_additional_suffixes;
/* Return a new string which is the result of tilde expanding STRING. */
extern char *tilde_expand ();
diff --git a/readline/undo.c b/readline/undo.c
index 68710b667ed..c8f4892b774 100644
--- a/readline/undo.c
+++ b/readline/undo.c
@@ -174,7 +174,7 @@ _rl_fix_last_undo_of_type (type, start, end)
for (rl = rl_undo_list; rl; rl = rl->next)
{
- if (rl->what == type)
+ if ((int) rl->what == type)
{
rl->start = start;
rl->end = end;
@@ -225,8 +225,8 @@ rl_modifying (start, end)
/* Revert the current line to its previous state. */
int
-rl_revert_line (count, key)
- int count, key;
+rl_revert_line (int count __attribute__((unused)),
+ int key __attribute__((unused)))
{
if (!rl_undo_list)
ding ();
@@ -240,8 +240,7 @@ rl_revert_line (count, key)
/* Do some undoing of things that were done. */
int
-rl_undo_command (count, key)
- int count, key;
+rl_undo_command (int count, int key __attribute__((unused)))
{
if (count < 0)
return 0; /* Nothing to do. */
diff --git a/readline/util.c b/readline/util.c
index 1dc3b664f1c..bcd8f3bc5b2 100644
--- a/readline/util.c
+++ b/readline/util.c
@@ -81,7 +81,7 @@ extern char *xmalloc (), *xrealloc ();
in words, or 1 if it is. */
int _rl_allow_pathname_alphabetic_chars = 0;
-static char *pathname_alphabetic_chars = "/-_=~.#$";
+static const char *pathname_alphabetic_chars = "/-_=~.#$";
int
alphabetic (c)
@@ -113,15 +113,15 @@ _rl_abort_internal ()
}
int
-rl_abort (count, key)
- int count, key;
+rl_abort (int count __attribute__((unused)),
+ int key __attribute__((unused)))
{
return (_rl_abort_internal ());
}
int
-rl_tty_status (count, key)
- int count, key;
+rl_tty_status (int count __attribute__((unused)),
+ int key __attribute__((unused)))
{
#if defined (TIOCSTAT)
ioctl (1, TIOCSTAT, (char *)0);
@@ -170,8 +170,8 @@ rl_extend_line_buffer (len)
/* A function for simple tilde expansion. */
int
-rl_tilde_expand (ignore, key)
- int ignore, key;
+rl_tilde_expand (int ignore __attribute__((unused)),
+ int key __attribute__((unused)))
{
register int start, end;
char *homedir, *temp;
diff --git a/readline/vi_mode.c b/readline/vi_mode.c
index 2a4f11d28a4..eb392b643ba 100644
--- a/readline/vi_mode.c
+++ b/readline/vi_mode.c
@@ -98,7 +98,7 @@ extern int rl_vi_check ();
static int _rl_vi_doing_insert;
/* Command keys which do movement for xxx_to commands. */
-static char *vi_motion = " hl^$0ftFt;,%wbeWBE|";
+static const char *vi_motion = " hl^$0ftFt;,%wbeWBE|";
/* Keymap used for vi replace characters. Created dynamically since
rarely used. */
@@ -126,7 +126,7 @@ static int _rl_vi_last_key_before_insert;
static int vi_redoing;
/* Text modification commands. These are the `redoable' commands. */
-static char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~";
+static const char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~";
/* Arrays for the saved marks. */
static int vi_mark_chars[27];
@@ -136,7 +136,11 @@ static int rl_digit_loop1 ();
void
_rl_vi_initialize_line ()
{
- register int i;
+#ifndef __QNXNTO__
+ register uint i;
+#else
+ register unsigned int i;
+#endif
for (i = 0; i < (int) sizeof (vi_mark_chars) / sizeof (int); i++)
vi_mark_chars[i] = -1;
@@ -183,7 +187,7 @@ _rl_vi_stuff_insert (count)
puts you back into insert mode. */
int
rl_vi_redo (count, c)
- int count, c;
+ int count, c __attribute__((unused));
{
if (!rl_explicit_arg)
{
@@ -215,11 +219,11 @@ rl_vi_undo (count, key)
{
return (rl_undo_command (count, key));
}
-
+
/* Yank the nth arg from the previous line into this line at point. */
int
-rl_vi_yank_arg (count, key)
- int count, key;
+rl_vi_yank_arg (count, key)
+ int count, key __attribute__((unused));
{
/* Readline thinks that the first word on a line is the 0th, while vi
thinks the first word on a line is the 1st. Compensate. */
@@ -300,7 +304,7 @@ rl_vi_search (count, key)
/* Completion, from vi's point of view. */
int
rl_vi_complete (ignore, key)
- int ignore, key;
+ int ignore __attribute__((unused)), key;
{
if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point])))
{
@@ -329,7 +333,7 @@ rl_vi_complete (ignore, key)
/* Tilde expansion for vi mode. */
int
rl_vi_tilde_expand (ignore, key)
- int ignore, key;
+ int ignore __attribute__((unused)), key;
{
rl_tilde_expand (0, key);
_rl_vi_set_last (key, 1, rl_arg_sign); /* XXX */
@@ -401,7 +405,7 @@ rl_vi_end_word (count, key)
/* Move forward a word the way that 'W' does. */
int
rl_vi_fWord (count, ignore)
- int count, ignore;
+ int count, ignore __attribute__((unused));
{
while (count-- && rl_point < (rl_end - 1))
{
@@ -418,7 +422,7 @@ rl_vi_fWord (count, ignore)
int
rl_vi_bWord (count, ignore)
- int count, ignore;
+ int count, ignore __attribute__((unused));
{
while (count-- && rl_point > 0)
{
@@ -442,7 +446,7 @@ rl_vi_bWord (count, ignore)
int
rl_vi_eWord (count, ignore)
- int count, ignore;
+ int count, ignore __attribute__((unused));
{
while (count-- && rl_point < (rl_end - 1))
{
@@ -472,7 +476,7 @@ rl_vi_eWord (count, ignore)
int
rl_vi_fword (count, ignore)
- int count, ignore;
+ int count, ignore __attribute__((unused));
{
while (count-- && rl_point < (rl_end - 1))
{
@@ -498,7 +502,7 @@ rl_vi_fword (count, ignore)
int
rl_vi_bword (count, ignore)
- int count, ignore;
+ int count, ignore __attribute__((unused));
{
while (count-- && rl_point > 0)
{
@@ -537,7 +541,7 @@ rl_vi_bword (count, ignore)
int
rl_vi_eword (count, ignore)
- int count, ignore;
+ int count, ignore __attribute__((unused));
{
while (count-- && rl_point < rl_end - 1)
{
@@ -562,7 +566,7 @@ rl_vi_eword (count, ignore)
int
rl_vi_insert_beg (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
rl_beg_of_line (1, key);
rl_vi_insertion_mode (1, key);
@@ -571,7 +575,7 @@ rl_vi_insert_beg (count, key)
int
rl_vi_append_mode (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
if (rl_point < rl_end)
rl_point++;
@@ -581,7 +585,7 @@ rl_vi_append_mode (count, key)
int
rl_vi_append_eol (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
rl_end_of_line (1, key);
rl_vi_append_mode (1, key);
@@ -591,7 +595,7 @@ rl_vi_append_eol (count, key)
/* What to do in the case of C-d. */
int
rl_vi_eof_maybe (count, c)
- int count, c;
+ int count __attribute__((unused)), c __attribute__((unused));
{
return (rl_newline (1, '\n'));
}
@@ -602,7 +606,7 @@ rl_vi_eof_maybe (count, c)
switching keymaps. */
int
rl_vi_insertion_mode (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
_rl_keymap = vi_insertion_keymap;
_rl_vi_last_key_before_insert = key;
@@ -633,7 +637,7 @@ _rl_vi_save_insert (up)
strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1);
vi_insert_buffer[len-1] = '\0';
}
-
+
void
_rl_vi_done_inserting ()
{
@@ -664,7 +668,7 @@ _rl_vi_done_inserting ()
int
rl_vi_movement_mode (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
if (rl_point > 0)
rl_backward (1, key);
@@ -686,7 +690,7 @@ rl_vi_arg_digit (count, c)
int
rl_vi_change_case (count, ignore)
- int count, ignore;
+ int count, ignore __attribute__((unused));
{
char c = 0;
@@ -724,7 +728,7 @@ rl_vi_change_case (count, ignore)
int
rl_vi_put (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end))
rl_point++;
@@ -881,7 +885,7 @@ rl_digit_loop1 ()
int
rl_vi_delete_to (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
int c;
@@ -961,7 +965,7 @@ rl_vi_change_to (count, key)
int
rl_vi_yank_to (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
int c, save = rl_point;
@@ -1006,7 +1010,7 @@ rl_vi_delete (count, key)
end = rl_end;
rl_kill_text (rl_point, end);
-
+
if (rl_point > 0 && rl_point == rl_end)
rl_backward (1, key);
return (0);
@@ -1014,7 +1018,7 @@ rl_vi_delete (count, key)
int
rl_vi_back_to_indent (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
rl_beg_of_line (1, key);
while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
@@ -1024,7 +1028,7 @@ rl_vi_back_to_indent (count, key)
int
rl_vi_first_print (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
return (rl_vi_back_to_indent (1, key));
}
@@ -1071,7 +1075,7 @@ rl_vi_char_search (count, key)
/* Match brackets */
int
rl_vi_match (ignore, key)
- int ignore, key;
+ int ignore __attribute__((unused)), key;
{
int count = 1, brack, pos;
@@ -1152,7 +1156,7 @@ rl_vi_bracktype (c)
int
rl_vi_change_char (count, key)
- int count, key;
+ int count, key __attribute__((unused));
{
int c;
@@ -1278,7 +1282,7 @@ rl_vi_overstrike_delete (count, key)
int
rl_vi_replace (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
int i;
@@ -1339,7 +1343,7 @@ rl_vi_possible_completions()
/* Functions to save and restore marks. */
int
rl_vi_set_mark (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
int ch;
@@ -1356,7 +1360,7 @@ rl_vi_set_mark (count, key)
int
rl_vi_goto_mark (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
int ch;
diff --git a/regex/cclass.h b/regex/cclass.h
index 7d9a7ccc7c2..e0f752f38b8 100644
--- a/regex/cclass.h
+++ b/regex/cclass.h
@@ -15,7 +15,7 @@
#define CCLASS_LAST 12
extern struct cclass {
- char *name;
- char *chars;
- char *multis;
+ const char *name;
+ const char *chars;
+ const char *multis;
} cclasses[];
diff --git a/regex/cname.h b/regex/cname.h
index 2b6a1a8496f..06865f3e102 100644
--- a/regex/cname.h
+++ b/regex/cname.h
@@ -1,7 +1,7 @@
/* character-name table */
static struct cname {
- char *name;
- char code;
+ const char *name;
+ const char code;
} cnames[] = {
{"NUL", '\0'},
{"SOH", '\001'},
diff --git a/regex/debug.c b/regex/debug.c
index 8c6fd14a209..35279941d48 100644
--- a/regex/debug.c
+++ b/regex/debug.c
@@ -1,4 +1,4 @@
-#include <global.h>
+#include <my_global.h>
#include <m_ctype.h>
#include <m_string.h>
#include <sys/types.h>
diff --git a/regex/main.c b/regex/main.c
index 4b607f401ca..7844a4d8384 100644
--- a/regex/main.c
+++ b/regex/main.c
@@ -1,4 +1,4 @@
-#include <global.h>
+#include <my_global.h>
#include <m_string.h>
#include <sys/types.h>
#include <regex.h>
@@ -133,9 +133,9 @@ FILE *in;
int i;
char erbuf[100];
size_t ne;
- char *badpat = "invalid regular expression";
+ const char *badpat = "invalid regular expression";
# define SHORT 10
- char *bpname = "REG_BADPAT";
+ const char *bpname = "REG_BADPAT";
regex_t re;
while (fgets(inbuf, sizeof(inbuf), in) != NULL) {
@@ -152,7 +152,7 @@ FILE *in;
}
for (i = 0; i < nf; i++)
if (strcmp(f[i], "\"\"") == 0)
- f[i] = "";
+ f[i] = (char*) "";
if (nf <= 3)
f[3] = NULL;
if (nf <= 4)
@@ -217,7 +217,7 @@ int opts; /* may not match f1 */
char erbuf[100];
int err;
int len;
- char *type = (opts & REG_EXTENDED) ? "ERE" : "BRE";
+ const char *type = (opts & REG_EXTENDED) ? "ERE" : "BRE";
register int i;
char *grump;
char f0copy[1000];
@@ -291,7 +291,7 @@ int opts; /* may not match f1 */
nshould = split(f4, should+1, NSHOULD-1, ",");
if (nshould == 0) {
nshould = 1;
- should[1] = "";
+ should[1] = (char*) "";
}
for (i = 1; i < NSUBS; i++) {
grump = check(f2, subs[i], should[i]);
@@ -317,7 +317,7 @@ char *s;
{
register char *p;
register int o = (type == 'c') ? copts : eopts;
- register char *legal = (type == 'c') ? "bisnmp" : "^$#tl";
+ register const char *legal = (type == 'c') ? "bisnmp" : "^$#tl";
for (p = s; *p != '\0'; p++)
if (strchr(legal, *p) != NULL)
@@ -417,7 +417,7 @@ char *should;
should = NULL;
if (should != NULL && should[0] == '@') {
at = should + 1;
- should = "";
+ should = (char*) "";
}
/* check rm_so and rm_eo for consistency */
@@ -434,7 +434,7 @@ char *should;
if (sub.rm_so == -1 && should == NULL)
return(NULL);
if (sub.rm_so == -1)
- return("did not match");
+ return((char*) "did not match");
/* check for in range */
if ((int) sub.rm_eo > (int) strlen(str)) {
diff --git a/regex/regcomp.c b/regex/regcomp.c
index 048f45ca71c..6f8221a706d 100644
--- a/regex/regcomp.c
+++ b/regex/regcomp.c
@@ -1,4 +1,4 @@
-#include <global.h>
+#include <my_global.h>
#include <m_string.h>
#include <m_ctype.h>
#include <regex.h>
@@ -219,7 +219,7 @@ int stop; /* character this ERE should end at */
conc = HERE();
while (MORE() && (c = PEEK()) != '|' && c != stop)
p_ere_exp(p);
- if(REQUIRE(HERE() != conc, REG_EMPTY)); /* require nonempty */
+ if(REQUIRE(HERE() != conc, REG_EMPTY)) {}/* require nonempty */
if (!EAT('|'))
break; /* NOTE BREAK OUT */
@@ -266,11 +266,11 @@ register struct parse *p;
pos = HERE();
switch (c) {
case '(':
- if(REQUIRE(MORE(), REG_EPAREN));
+ if(REQUIRE(MORE(), REG_EPAREN)) {}
p->g->nsub++;
subno = (sopno) p->g->nsub;
if (subno < NPAREN)
- p->pbegin[subno] = HERE();
+ p->pbegin[subno] = HERE();
EMIT(OLPAREN, subno);
if (!SEE(')'))
p_ere(p, ')');
@@ -279,7 +279,7 @@ register struct parse *p;
assert(p->pend[subno] != 0);
}
EMIT(ORPAREN, subno);
- if(MUSTEAT(')', REG_EPAREN));
+ if(MUSTEAT(')', REG_EPAREN)) {}
break;
#ifndef POSIX_MISTAKE
case ')': /* happens only if no current unmatched ( */
@@ -322,12 +322,12 @@ register struct parse *p;
p_bracket(p);
break;
case '\\':
- if(REQUIRE(MORE(), REG_EESCAPE));
+ if(REQUIRE(MORE(), REG_EESCAPE)) {}
c = GETNEXT();
ordinary(p, c);
break;
case '{': /* okay as ordinary except if digit follows */
- if(REQUIRE(!MORE() || !isdigit(PEEK()), REG_BADRPT));
+ if(REQUIRE(!MORE() || !isdigit(PEEK()), REG_BADRPT)) {}
/* FALLTHROUGH */
default:
ordinary(p, c);
@@ -343,7 +343,7 @@ register struct parse *p;
return; /* no repetition, we're done */
NEXT();
- if(REQUIRE(!wascaret, REG_BADRPT));
+ if(REQUIRE(!wascaret, REG_BADRPT)) {}
switch (c) {
case '*': /* implemented as +? */
/* this case does not require the (y|) trick, noKLUDGE */
@@ -370,7 +370,7 @@ register struct parse *p;
if (EAT(',')) {
if (isdigit(PEEK())) {
count2 = p_count(p);
- if(REQUIRE(count <= count2, REG_BADBR));
+ if(REQUIRE(count <= count2, REG_BADBR)) {}
} else /* single number with comma */
count2 = RE_INFINITY;
} else /* just a single number */
@@ -379,7 +379,7 @@ register struct parse *p;
if (!EAT('}')) { /* error heuristics */
while (MORE() && PEEK() != '}')
NEXT();
- if(REQUIRE(MORE(), REG_EBRACE));
+ if(REQUIRE(MORE(), REG_EBRACE)) {}
SETERROR(REG_BADBR);
}
break;
@@ -402,7 +402,7 @@ static void
p_str(p)
register struct parse *p;
{
- if(REQUIRE(MORE(), REG_EMPTY));
+ if(REQUIRE(MORE(), REG_EMPTY)) {}
while (MORE())
ordinary(p, GETNEXT());
}
@@ -445,7 +445,7 @@ register int end2; /* second terminating character */
p->g->neol++;
}
- if(REQUIRE(HERE() != start, REG_EMPTY)); /* require nonempty */
+ if(REQUIRE(HERE() != start, REG_EMPTY)) {} /* require nonempty */
}
/*
@@ -470,7 +470,7 @@ int starordinary; /* is a leading * an ordinary character? */
assert(MORE()); /* caller should have ensured this */
c = GETNEXT();
if (c == '\\') {
- if(REQUIRE(MORE(), REG_EESCAPE));
+ if(REQUIRE(MORE(), REG_EESCAPE)) {}
c = BACKSL | (unsigned char)GETNEXT();
}
switch (c) {
@@ -500,7 +500,7 @@ int starordinary; /* is a leading * an ordinary character? */
assert(p->pend[subno] != 0);
}
EMIT(ORPAREN, subno);
- if(REQUIRE(EATTWO('\\', ')'), REG_EPAREN));
+ if(REQUIRE(EATTWO('\\', ')'), REG_EPAREN)) {}
break;
case BACKSL|')': /* should not get here -- must be user */
case BACKSL|'}':
@@ -530,7 +530,7 @@ int starordinary; /* is a leading * an ordinary character? */
p->g->backrefs = 1;
break;
case '*':
- if(REQUIRE(starordinary, REG_BADRPT));
+ if(REQUIRE(starordinary, REG_BADRPT)) {}
/* FALLTHROUGH */
default:
ordinary(p, c &~ BACKSL);
@@ -548,7 +548,7 @@ int starordinary; /* is a leading * an ordinary character? */
if (EAT(',')) {
if (MORE() && isdigit(PEEK())) {
count2 = p_count(p);
- if(REQUIRE(count <= count2, REG_BADBR));
+ if(REQUIRE(count <= count2, REG_BADBR)) {}
} else /* single number with comma */
count2 = RE_INFINITY;
} else /* just a single number */
@@ -557,7 +557,7 @@ int starordinary; /* is a leading * an ordinary character? */
if (!EATTWO('\\', '}')) { /* error heuristics */
while (MORE() && !SEETWO('\\', '}'))
NEXT();
- if(REQUIRE(MORE(), REG_EBRACE));
+ if(REQUIRE(MORE(), REG_EBRACE)) {}
SETERROR(REG_BADBR);
}
} else if (c == (unsigned char)'$') /* $ (but not \$) ends it */
@@ -582,7 +582,7 @@ register struct parse *p;
ndigits++;
}
- if(REQUIRE(ndigits > 0 && count <= DUPMAX, REG_BADBR));
+ if(REQUIRE(ndigits > 0 && count <= DUPMAX, REG_BADBR)) {}
return(count);
}
@@ -622,7 +622,7 @@ register struct parse *p;
p_b_term(p, cs);
if (EAT('-'))
CHadd(cs, '-');
- if(MUSTEAT(']', REG_EBRACK));
+ if(MUSTEAT(']', REG_EBRACK)) {}
if (p->error != 0) /* don't mess things up further */
return;
@@ -693,21 +693,21 @@ register cset *cs;
switch (c) {
case ':': /* character class */
NEXT2();
- if(REQUIRE(MORE(), REG_EBRACK));
+ if(REQUIRE(MORE(), REG_EBRACK)) {}
c = PEEK();
- if(REQUIRE(c != '-' && c != ']', REG_ECTYPE));
+ if(REQUIRE(c != '-' && c != ']', REG_ECTYPE)) {}
p_b_cclass(p, cs);
- if(REQUIRE(MORE(), REG_EBRACK));
- if(REQUIRE(EATTWO(':', ']'), REG_ECTYPE));
+ if(REQUIRE(MORE(), REG_EBRACK)) {}
+ if(REQUIRE(EATTWO(':', ']'), REG_ECTYPE)) {}
break;
case '=': /* equivalence class */
NEXT2();
- if(REQUIRE(MORE(), REG_EBRACK));
+ if(REQUIRE(MORE(), REG_EBRACK)) {}
c = PEEK();
- if(REQUIRE(c != '-' && c != ']', REG_ECOLLATE));
+ if(REQUIRE(c != '-' && c != ']', REG_ECOLLATE)) {}
p_b_eclass(p, cs);
- if(REQUIRE(MORE(), REG_EBRACK));
- if(REQUIRE(EATTWO('=', ']'), REG_ECOLLATE));
+ if(REQUIRE(MORE(), REG_EBRACK)) {}
+ if(REQUIRE(EATTWO('=', ']'), REG_ECOLLATE)) {}
break;
default: /* symbol, ordinary character, or range */
/* xxx revision needed for multichar stuff */
@@ -722,7 +722,7 @@ register cset *cs;
} else
finish = start;
/* xxx what about signed chars here... */
- if(REQUIRE(start <= finish, REG_ERANGE));
+ if(REQUIRE(start <= finish, REG_ERANGE)) {}
for (i = start; i <= finish; i++)
CHadd(cs, i);
break;
@@ -756,10 +756,10 @@ register cset *cs;
return;
}
- u = cp->chars;
+ u = (char*) cp->chars;
while ((c = *u++) != '\0')
CHadd(cs, c);
- for (u = cp->multis; *u != '\0'; u += strlen(u) + 1)
+ for (u = (char*) cp->multis; *u != '\0'; u += strlen(u) + 1)
MCadd(p, cs, u);
}
@@ -790,13 +790,13 @@ register struct parse *p;
{
register char value;
- if(REQUIRE(MORE(), REG_EBRACK));
+ if(REQUIRE(MORE(), REG_EBRACK)) {}
if (!EATTWO('[', '.'))
return(GETNEXT());
/* collating symbol */
value = p_b_coll_elem(p, '.');
- if(REQUIRE(EATTWO('.', ']'), REG_ECOLLATE));
+ if(REQUIRE(EATTWO('.', ']'), REG_ECOLLATE)) {}
return(value);
}
@@ -1189,6 +1189,7 @@ register char *cp;
cs->multis[cs->smultis - 1] = '\0';
}
+#ifdef NOT_USED
/*
- mcsub - subtract a collating element from a cset
== static void mcsub(register cset *cs, register char *cp);
@@ -1246,6 +1247,7 @@ register char *cp;
return(p);
return(NULL);
}
+#endif
/*
- mcinvert - invert the list of collating elements in a cset
@@ -1256,8 +1258,8 @@ register char *cp;
*/
static void
mcinvert(p, cs)
-register struct parse *p;
-register cset *cs;
+ register struct parse *p __attribute__((unused));
+ register cset *cs __attribute__((unused));
{
assert(cs->multis == NULL); /* xxx */
}
@@ -1271,8 +1273,8 @@ register cset *cs;
*/
static void
mccase(p, cs)
-register struct parse *p;
-register cset *cs;
+register struct parse *p __attribute__((unused));
+register cset *cs __attribute__((unused));
{
assert(cs->multis == NULL); /* xxx */
}
diff --git a/regex/regcomp.ih b/regex/regcomp.ih
index 0776e7185cd..4ae45bbf4a9 100644
--- a/regex/regcomp.ih
+++ b/regex/regcomp.ih
@@ -28,9 +28,11 @@ static int freezeset(register struct parse *p, register cset *cs);
static int firstch(register struct parse *p, register cset *cs);
static int nch(register struct parse *p, register cset *cs);
static void mcadd(register struct parse *p, register cset *cs, register char *cp);
+#ifdef NOT_USED
static void mcsub(register cset *cs, register char *cp);
static int mcin(register cset *cs, register char *cp);
static char *mcfind(register cset *cs, register char *cp);
+#endif
static void mcinvert(register struct parse *p, register cset *cs);
static void mccase(register struct parse *p, register cset *cs);
static int isinsets(register struct re_guts *g, int c);
diff --git a/regex/regerror.c b/regex/regerror.c
index a356912564a..0a7b7c8da2c 100644
--- a/regex/regerror.c
+++ b/regex/regerror.c
@@ -1,4 +1,4 @@
-#include <global.h>
+#include <my_global.h>
#include <m_string.h>
#include <m_ctype.h>
#include <regex.h>
@@ -28,8 +28,8 @@
*/
static struct rerr {
int code;
- char *name;
- char *explain;
+ const char *name;
+ const char *explain;
} rerrs[] = {
{REG_NOMATCH, "REG_NOMATCH", "regexec() failed to match"},
{REG_BADPAT, "REG_BADPAT", "invalid regular expression"},
@@ -83,7 +83,7 @@ size_t errbuf_size;
assert(strlen(convbuf) < sizeof(convbuf));
s = convbuf;
} else
- s = r->explain;
+ s = (char*) r->explain;
}
len = strlen(s) + 1;
@@ -113,7 +113,7 @@ char *localbuf;
if (strcmp(r->name, preg->re_endp) == 0)
break;
if (r->code == 0)
- return("0");
+ return((char*) "0");
sprintf(localbuf, "%d", r->code);
return(localbuf);
diff --git a/regex/regexec.c b/regex/regexec.c
index 853bd7aa263..7f2704f8214 100644
--- a/regex/regexec.c
+++ b/regex/regexec.c
@@ -5,7 +5,7 @@
* macros that code uses. This lets the same code operate on two different
* representations for state sets.
*/
-#include <global.h>
+#include <my_global.h>
#include <m_string.h>
#include <m_ctype.h>
#include <regex.h>
diff --git a/regex/regexp.c b/regex/regexp.c
index 706208a6b25..8ddf90f2943 100644
--- a/regex/regexp.c
+++ b/regex/regexp.c
@@ -58,7 +58,7 @@
*/
/* Headers */
-#include "global.h"
+#include "my_global.h"
#include <ctype.h>
#include "regexp.h"
#ifdef __WIN__
diff --git a/regex/regfree.c b/regex/regfree.c
index a0dd8087a45..6ab50735075 100644
--- a/regex/regfree.c
+++ b/regex/regfree.c
@@ -1,4 +1,4 @@
-#include <global.h>
+#include <my_global.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/regex/reginit.c b/regex/reginit.c
index b5815e7d01c..18647c386fc 100644
--- a/regex/reginit.c
+++ b/regex/reginit.c
@@ -1,6 +1,6 @@
/* Init cclasses array from ctypes */
-#include <global.h>
+#include <my_global.h>
#include <m_ctype.h>
#include <m_string.h>
#include "cclass.h"
@@ -63,7 +63,7 @@ void regex_end()
{
int i;
for (i=0; i < CCLASS_LAST ; i++)
- free(cclasses[i].chars);
+ free((char*) cclasses[i].chars);
regex_inited=0;
}
}
diff --git a/regex/split.c b/regex/split.c
index 188bdb775b9..bd2a53c01e3 100644
--- a/regex/split.c
+++ b/regex/split.c
@@ -27,7 +27,7 @@ char *sep; /* "" white, "c" single char, "ab" [ab]+ */
continue;
p--;
trimtrail = 1;
- sep = " \t"; /* note, code below knows this is 2 long */
+ sep = (char*) " \t"; /* note, code below knows this is 2 long */
sepc = ' ';
} else
trimtrail = 0;
diff --git a/scripts/Makefile.am b/scripts/Makefile.am
index 18957b6422d..1c3b8083347 100644
--- a/scripts/Makefile.am
+++ b/scripts/Makefile.am
@@ -20,6 +20,7 @@ bin_SCRIPTS = @server_scripts@ \
msql2mysql \
mysql_config \
mysql_fix_privilege_tables \
+ mysql_fix_extensions \
mysql_setpermission \
mysql_zap \
mysqlaccess \
@@ -28,12 +29,14 @@ bin_SCRIPTS = @server_scripts@ \
mysql_find_rows \
mysqlhotcopy \
mysqldumpslow \
+ mysql_explain_log \
mysqld_multi
EXTRA_SCRIPTS = make_binary_distribution.sh \
msql2mysql.sh \
mysql_config.sh \
mysql_fix_privilege_tables.sh \
+ mysql_fix_extensions.sh \
mysql_install_db.sh \
mysql_setpermission.sh \
mysql_zap.sh \
@@ -43,8 +46,9 @@ EXTRA_SCRIPTS = make_binary_distribution.sh \
mysql_find_rows.sh \
mysqlhotcopy.sh \
mysqldumpslow.sh \
+ mysql_explain_log.sh \
mysqld_multi.sh \
- safe_mysqld.sh
+ mysqld_safe.sh
EXTRA_DIST = $(EXTRA_SCRIPTS) \
mysqlaccess.conf \
@@ -59,6 +63,7 @@ CLEANFILES = @server_scripts@ \
msql2mysql \
mysql_config \
mysql_fix_privilege_tables \
+ mysql_fix_extensions \
mysql_setpermission \
mysql_zap \
mysqlaccess \
@@ -95,6 +100,8 @@ SUFFIXES = .sh
-e 's!@''CXXFLAGS''@!@SAVE_CXXFLAGS@!'\
-e 's!@''LDFLAGS''@!@SAVE_LDFLAGS@!'\
-e 's!@''CLIENT_LIBS''@!@CLIENT_LIBS@!' \
+ -e 's!@''LIBS''@!@LIBS@!' \
+ -e 's!@''innodb_system_libs''@!@innodb_system_libs@!' \
-e 's!@''VERSION''@!@VERSION@!' \
-e 's!@''MYSQL_SERVER_SUFFIX''@!@MYSQL_SERVER_SUFFIX@!' \
-e 's!@''COMPILATION_COMMENT''@!@COMPILATION_COMMENT@!' \
diff --git a/scripts/explain_log.sh b/scripts/explain_log.sh
new file mode 100644
index 00000000000..c4a4ef21568
--- /dev/null
+++ b/scripts/explain_log.sh
@@ -0,0 +1,383 @@
+#!@PERL@ -w
+use strict;
+use DBI;
+
+use Getopt::Long;
+$Getopt::Long::ignorecase=0;
+
+print "explain_log provided by http://www.mobile.de\n";
+print "=========== ================================\n";
+
+my $Param={};
+
+$Param->{host}='';
+$Param->{user}='';
+$Param->{password}='';
+$Param->{PrintError}=0;
+
+if (!GetOptions ('date|d:i' => \$Param->{ViewDate},
+ 'host|h:s' => \$Param->{host},
+ 'user|u:s' => \$Param->{user},
+ 'password|p:s' => \$Param->{password},
+ 'printerror|e:s' => \$Param->{PrintError},
+ )) {
+ ShowOptions();
+}
+else {
+ $Param->{UpdateCount} = 0;
+ $Param->{SelectCount} = 0;
+ $Param->{IdxUseCount} = 0;
+ $Param->{LineCount} = 0;
+
+ $Param->{Init} = 0;
+ $Param->{Field} = 0;
+ $Param->{Refresh} = 0;
+ $Param->{QueryCount} = 0;
+ $Param->{Statistics} =0;
+
+ $Param->{Query} = undef;
+ $Param->{ALL} = undef ;
+ $Param->{Comment} = undef ;
+
+ @{$Param->{Rows}} = (qw|possible_keys key type|);
+
+ if ($Param->{ViewDate}) {
+ $Param->{View} = 0;
+ }
+ else {
+ $Param->{View} = 1;
+ }
+
+ #print "Date=$Param->{ViewDate}, host=$Param->{host}, user=$Param->{user}, password=$Param->{password}\n";
+
+ $Param->{dbh}=DBI->connect("DBI:mysql:host=$Param->{host}",$Param->{user},$Param->{password},{PrintError=>0});
+ if (DBI::err()) {
+ print "Error: " . DBI::errstr() . "\n";
+ }
+ else {
+ $Param->{Start} = time;
+ while(<STDIN>) {
+ $Param->{LineCount} ++ ;
+
+ if ($Param->{ViewDate} ) {
+ if (m/^(\d{6})\s+\d{1,2}:\d\d:\d\d\s.*$/) { # get date
+ #print "# $1 #\n";
+ if ($1 == $Param->{ViewDate}) {
+ $Param->{View} = 1;
+ }
+ else {
+ $Param->{View} = 0;
+ }
+ }
+ }
+ if ($Param->{View} ) {
+ #print "->>>$_";
+
+ if (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Connect.+\s+on\s+(.*)$/i) { # get connection ID($2) and database($3)
+ #print "C-$1--$2--$3------\n";
+ RunQuery($Param);
+ if (defined $3) {
+ $Param->{CID}->{$2} = $3 ;
+ #print "DB:$Param->{CID}->{$2} .. $2 .. $3 \n";
+ }
+ }
+
+ elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Connect.+$/i) { # get connection ID($2) and database($3)
+ #print "\n <<<<<<<<<<<<<<<<<<----------------------------<<<<<<<<<<<<<<<< \n";
+ #print "Connect \n";
+ RunQuery($Param);
+ }
+ elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Change user .*\s+on\s+(.*)$/i) { # get connection ID($2) and database($3)
+ #print "C-$1--$2--$3------\n";
+ RunQuery($Param);
+ if (defined $3) {
+ $Param->{CID}->{$2} = $3 ;
+ #print "DB:$Param->{CID}->{$2} .. $2 .. $3 \n";
+ }
+ }
+
+ elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Quit\s+$/i) { # remove connection ID($2) and querystring
+ #print "Q-$1--$2--------\n";
+ RunQuery($Param);
+ delete $Param->{CID}->{$2} ;
+ }
+
+ elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Query\s+(select.+)$/i) { # get connection ID($2) and querystring
+ #print "S1-$1--$2--$3------\n";
+ RunQuery($Param);
+ unless ($Param->{CID}->{$2}) {
+ #print "Error: No Database for Handle: $2 found\n";
+ }
+ else {
+ $Param->{DB}=$Param->{CID}->{$2};
+
+ my $s = "$3";
+ $s =~ s/from\s/from $Param->{DB}./i;
+ $Param->{Query}="EXPLAIN $s";
+
+ #$s =~ m/from\s+(\w+[.]\w+)/i;
+ #$Param->{tab} =$1;
+ #print "-- $Param->{tab} -- $s --\n";
+ }
+ }
+
+ elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Query\s+(update.+)$/i) { # get connection ID($2) and querystring
+ #print "S2--$1--$2--$3------\n";
+ RunQuery($Param);
+ unless ($Param->{CID}->{$2}) {
+ #print "Error: No Database for Handle: $2 found\n";
+ }
+ else {
+ $Param->{DB}=$Param->{CID}->{$2};
+
+ my $ud = $3;
+ $ud =~ m/^update\s+(\w+).+(where.+)$/i;
+ $Param->{Query} ="EXPLAIN SELECT * FROM $1 $2";
+ $Param->{Query} =~ s/from\s/from $Param->{DB}./i;
+
+ #$Param->{Query} =~ m/from\s+(\w+[.]\w+)/i;
+ #$Param->{tab} =$1;
+ }
+ }
+
+ elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Statistics\s+(.*)$/i) { # get connection ID($2) and info?
+ $Param->{Statistics} ++;
+ #print "Statistics--$1--$2--$3------\n";
+ RunQuery($Param);
+ }
+ elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Query\s+(.+)$/i) { # get connection ID($2)
+ $Param->{QueryCount} ++;
+ #print "Query-NULL $3\n";
+ RunQuery($Param);
+ }
+ elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Refresh\s+(.+)$/i) { # get connection ID($2)
+ $Param->{Refresh} ++;
+ #print "Refresh\n";
+ RunQuery($Param);
+ }
+ elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Init\s+(.+)$/i) { # get connection ID($2)
+ $Param->{Init} ++;
+ #print "Init $3\n";
+ RunQuery($Param);
+ }
+ elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Field\s+(.+)$/i) { # get connection ID($2)
+ $Param->{Field} ++;
+ #print "Field $3\n";
+ RunQuery($Param);
+ }
+
+ elsif (m/^\s+(.+)$/ ) { # command could be some lines ...
+ #print "multi-lined ($1)\n";
+ my ($A)=$1;
+ chomp $A;
+ $Param->{Query} .= " $1";
+ #print "multi-lined ($1)<<$Param->{Query}>>\n";
+ }
+
+
+ }
+
+ }
+
+ $Param->{dbh}->disconnect();
+
+ if (1 == 0) {
+ print "\nunclosed handles----------------------------------------\n";
+ my $count=0;
+ foreach (sort keys %{$Param->{CID}}) {
+ print "$count | $_ : $Param->{CID}->{$_} \n";
+ $count ++;
+ }
+ }
+
+ print "\nIndex usage ------------------------------------\n";
+ foreach my $t (sort keys %{$Param->{Data}}) {
+ print "\nTable\t$t: ---\n";
+ foreach my $k (sort keys %{$Param->{Data}->{$t}}) {
+ print " count\t$k:\n";
+ my %h = %{$Param->{Data}->{$t}->{$k}};
+ foreach (sort {$h{$a} <=> $h{$b}} keys %h) {
+ print " $Param->{Data}->{$t}->{$k}->{$_}\t$_\n";
+ }
+ }
+ }
+
+ $Param->{AllCount}=0;
+ print "\nQueries causing table scans -------------------\n\n";
+ foreach (@{$Param->{ALL}}) {
+ $Param->{AllCount} ++;
+ print "$_\n";
+ }
+ print "Sum: $Param->{AllCount} table scans\n";
+
+ print "\nSummary ---------------------------------------\n\n";
+ print "Select: \t$Param->{SelectCount} queries\n";
+ print "Update: \t$Param->{UpdateCount} queries\n";
+ print "\n";
+
+ print "Init: \t$Param->{Init} times\n";
+ print "Field: \t$Param->{Field} times\n";
+ print "Refresh: \t$Param->{Refresh} times\n";
+ print "Query: \t$Param->{QueryCount} times\n";
+ print "Statistics:\t$Param->{Statistics} times\n";
+ print "\n";
+
+ print "Logfile: \t$Param->{LineCount} lines\n";
+ print "Started: \t".localtime($Param->{Start})."\n";
+ print "Finished: \t".localtime(time)."\n";
+
+ }
+}
+
+
+###########################################################################
+#
+#
+#
+sub RunQuery {
+ my $Param = shift ;
+
+ if (defined $Param->{Query}) {
+ if (defined $Param->{DB} ) {
+
+ $Param->{Query} =~ m/from\s+(\w+[.]\w+|\w+)/i;
+ $Param->{tab} =$1;
+ #print "||$Param->{tab} -- $Param->{Query}\n";
+
+ my $sth=$Param->{dbh}->prepare("USE $Param->{DB}");
+ if (DBI::err()) {
+ if ($Param->{PrintError}) {print "Error: ".DBI::errstr()."\n";}
+ }
+ else {
+ $sth->execute();
+ if (DBI::err()) {
+ if ($Param->{PrintError}) {print "Error: ".DBI::errstr()."\n";}
+ }
+ else {
+ $sth->finish();
+
+ $sth=$Param->{dbh}->prepare($Param->{Query});
+ if (DBI::err()) {
+ if ($Param->{PrintError}) {print "Error: ".DBI::errstr()."\n";}
+ }
+ else {
+ #print "$Param->{Query}\n";
+ $sth->execute();
+ if (DBI::err()) {
+ if ($Param->{PrintError}) {print "[$Param->{LineCount}]<<$Param->{Query}>>\n";}
+ if ($Param->{PrintError}) {print "Error: ".DBI::errstr()."\n";}
+ }
+ else {
+ my $row = undef;
+ while ($row = $sth->fetchrow_hashref()) {
+ $Param->{SelectCount} ++;
+
+ if (defined $row->{Comment}) {
+ push (@{$Param->{Comment}}, "$row->{Comment}; $_; $Param->{DB}; $Param->{Query}");
+ }
+ foreach (@{$Param->{Rows}}) {
+ if (defined $row->{$_}) {
+ #if (($_ eq 'type' ) and ($row->{$_} eq 'ALL')) {
+ if ($row->{type} eq 'ALL') {
+ push (@{$Param->{ALL}}, "$Param->{Query}");
+ #print ">> $row->{$_} $_ $Param->{DB} $Param->{Query}\n";
+ }
+ $Param->{IdxUseCount} ++;
+ $Param->{Data}->{$Param->{tab}}->{$_}->{$row->{$_}} ++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ $sth->finish();
+ }
+ $Param->{Query} = undef ;
+ }
+}
+
+###########################################################################
+#
+#
+#
+sub ShowOptions {
+ print <<EOF;
+Usage: $0 [OPTIONS] < LOGFILE
+
+--date=YYMMDD select only entrys of date
+-d=YYMMDD
+--host=HOSTNAME db-host to ask
+-h=HOSTNAME
+--user=USERNAME db-user
+-u=USERNAME
+--password=PASSWORD password of db-user
+-p=PASSWORD
+
+Read logfile from STDIN an try to EXPLAIN all SELECT statements. All UPDATE statements are rewritten to an EXPLAIN SELECT statement. The results of the EXPLAIN statement are collected and counted. All results with type=ALL are collected in an separete list. Results are printed to STDOUT.
+
+EOF
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+explain_log.pl
+
+Feed a mysqld general logfile (created with mysqld --log) back into mysql
+and collect statistics about index usage with EXPLAIN.
+
+=head1 DISCUSSION
+
+To optimize your indices, you have to know which ones are actually
+used and what kind of queries are causing table scans. Especially
+if you are generating your queries dynamically and you have a huge
+amount of queries going on, this isn't easy.
+
+Use this tool to take a look at the effects of your real life queries.
+Then add indices to avoid table scans and remove those which aren't used.
+
+=head1 USAGE
+
+explain_log.pl [--date=YYMMDD] --host=dbhost] [--user=dbuser] [--password=dbpw] < logfile
+
+--date=YYMMDD select only entrys of date
+
+-d=YYMMDD
+
+--host=HOSTNAME db-host to ask
+
+-h=HOSTNAME
+
+--user=USERNAME db-user
+
+-u=USERNAME
+
+--password=PASSWORD password of db-user
+
+-p=PASSWORD
+
+=head1 EXAMPLE
+
+explain_log.pl --host=localhost --user=foo --password=bar < /var/lib/mysql/mobile.log
+
+=head1 AUTHOR
+
+ Stefan Nitz
+ Jan Willamowius <jan@mobile.de>, http://www.mobile.de
+
+=head1 RECRUITING
+
+If you are looking for a MySQL or Perl job, take a look at http://www.mobile.de
+and send me an email with your resume (you must be speaking German!).
+
+=head1 SEE ALSO
+
+mysql documentation
+
+=cut
diff --git a/scripts/make_binary_distribution.sh b/scripts/make_binary_distribution.sh
index 99eb9e42967..44dc9d44322 100644
--- a/scripts/make_binary_distribution.sh
+++ b/scripts/make_binary_distribution.sh
@@ -66,9 +66,12 @@ for i in extra/comp_err extra/replace extra/perror extra/resolveip \
myisam/myisampack sql/mysqld client/mysqlbinlog \
client/mysql sql/mysqld client/mysqlshow client/mysqlcheck \
client/mysqladmin client/mysqldump client/mysqlimport client/mysqltest \
+ client/mysqlmanagerc client/mysqlmanager-pwgen tools/mysqlmanager \
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/mysqlcheck client/.libs/mysqlbinlog \
+ client/.libs/mysqlmanagerc client/.libs/mysqlmanager-pwgen \
+ tools/.libs/mysqlmanager
do
if [ -f $i ]
then
@@ -88,7 +91,7 @@ do
fi
done
-for i in libmysql/.libs/libmysqlclient.a libmysql/.libs/libmysqlclient.so* libmysql/libmysqlclient.* libmysql_r/.libs/libmysqlclient_r.a libmysql_r/.libs/libmysqlclient_r.so* libmysql_r/libmysqlclient_r.* mysys/libmysys.a strings/libmystrings.a dbug/libdbug.a $BASE/lib
+for i in libmysql/.libs/libmysqlclient.a libmysql/.libs/libmysqlclient.so* libmysql/libmysqlclient.* libmysql_r/.libs/libmysqlclient_r.a libmysql_r/.libs/libmysqlclient_r.so* libmysql_r/libmysqlclient_r.* mysys/libmysys.a strings/libmystrings.a dbug/libdbug.a libmysqld/.libs/libmysqld.a libmysqld/.libs/libmysqld.so* libmysqld/libmysqld.a
do
if [ -f $i ]
then
@@ -118,7 +121,7 @@ rm -f $BASE/bin/Makefile* $BASE/bin/*.in $BASE/bin/*.sh $BASE/bin/mysql_install_
$BASE/bin/replace \@localstatedir\@ ./data \@bindir\@ ./bin \@scriptdir\@ ./bin \@libexecdir\@ ./bin \@sbindir\@ ./bin \@prefix\@ . \@HOSTNAME\@ @HOSTNAME@ < $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 < $SOURCE/support-files/mysql.server.sh > $BASE/support-files/mysql.server
-$BASE/bin/replace /my/gnu/bin/hostname /bin/hostname -- $BASE/bin/safe_mysqld
+$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/configure
diff --git a/scripts/mysql_config.sh b/scripts/mysql_config.sh
index 9320efdd2a1..6a31db9a2b3 100644
--- a/scripts/mysql_config.sh
+++ b/scripts/mysql_config.sh
@@ -87,16 +87,18 @@ client_libs='@CLIENT_LIBS@'
libs="$ldflags -L'$pkglibdir' -lmysqlclient $client_libs"
libs=`echo $libs | sed -e 's; +;;'`
cflags="-I'$pkgincludedir'"
+embedded_libs="$ldflags -L'$pkglibdir' -lmysqld @LIBS@ @innodb_system_libs@"
usage () {
cat <<EOF
Usage: $0 [OPTIONS]
Options:
- --cflags [$cflags]
- --libs [$libs]
- --socket [$socket]
- --port [$port]
- --version [$version]
+ --cflags [$cflags]
+ --libs [$libs]
+ --socket [$socket]
+ --port [$port]
+ --version [$version]
+ --libmysqld-libs [$embedded_libs]
EOF
exit 1
}
@@ -110,6 +112,7 @@ while test $# -gt 0; do
--socket) echo "$socket" ;;
--port) echo "$port" ;;
--version) echo "$version" ;;
+ --embedded-libs | --embedded | libmysqld-libs) echo "$embedded_libs" ;;
*) usage ;;
esac
diff --git a/scripts/mysql_explain_log.sh b/scripts/mysql_explain_log.sh
new file mode 100644
index 00000000000..d7f6bb97b40
--- /dev/null
+++ b/scripts/mysql_explain_log.sh
@@ -0,0 +1,383 @@
+#!@PERL@ -w
+use strict;
+use DBI;
+
+use Getopt::Long;
+$Getopt::Long::ignorecase=0;
+
+print "explain_log provided by http://www.mobile.de\n";
+print "=========== ================================\n";
+
+my $Param={};
+
+$Param->{host}='';
+$Param->{user}='';
+$Param->{password}='';
+$Param->{PrintError}=0;
+
+if (!GetOptions ('date|d:i' => \$Param->{ViewDate},
+ 'host|h:s' => \$Param->{host},
+ 'user|u:s' => \$Param->{user},
+ 'password|p:s' => \$Param->{password},
+ 'printerror|e:s' => \$Param->{PrintError},
+ )) {
+ ShowOptions();
+}
+else {
+ $Param->{UpdateCount} = 0;
+ $Param->{SelectCount} = 0;
+ $Param->{IdxUseCount} = 0;
+ $Param->{LineCount} = 0;
+
+ $Param->{Init} = 0;
+ $Param->{Field} = 0;
+ $Param->{Refresh} = 0;
+ $Param->{QueryCount} = 0;
+ $Param->{Statistics} =0;
+
+ $Param->{Query} = undef;
+ $Param->{ALL} = undef ;
+ $Param->{Comment} = undef ;
+
+ @{$Param->{Rows}} = (qw|possible_keys key type|);
+
+ if ($Param->{ViewDate}) {
+ $Param->{View} = 0;
+ }
+ else {
+ $Param->{View} = 1;
+ }
+
+ #print "Date=$Param->{ViewDate}, host=$Param->{host}, user=$Param->{user}, password=$Param->{password}\n";
+
+ $Param->{dbh}=DBI->connect("DBI:mysql:host=$Param->{host}",$Param->{user},$Param->{password},{PrintError=>0});
+ if (DBI::err()) {
+ print "Error: " . DBI::errstr() . "\n";
+ }
+ else {
+ $Param->{Start} = time;
+ while(<STDIN>) {
+ $Param->{LineCount} ++ ;
+
+ if ($Param->{ViewDate} ) {
+ if (m/^(\d{6})\s+\d{1,2}:\d\d:\d\d\s.*$/) { # get date
+ #print "# $1 #\n";
+ if ($1 == $Param->{ViewDate}) {
+ $Param->{View} = 1;
+ }
+ else {
+ $Param->{View} = 0;
+ }
+ }
+ }
+ if ($Param->{View} ) {
+ #print "->>>$_";
+
+ if (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Connect.+\s+on\s+(.*)$/i) { # get connection ID($2) and database($3)
+ #print "C-$1--$2--$3------\n";
+ RunQuery($Param);
+ if (defined $3) {
+ $Param->{CID}->{$2} = $3 ;
+ #print "DB:$Param->{CID}->{$2} .. $2 .. $3 \n";
+ }
+ }
+
+ elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Connect.+$/i) { # get connection ID($2) and database($3)
+ #print "\n <<<<<<<<<<<<<<<<<<----------------------------<<<<<<<<<<<<<<<< \n";
+ #print "Connect \n";
+ RunQuery($Param);
+ }
+ elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Change user .*\s+on\s+(.*)$/i) { # get connection ID($2) and database($3)
+ #print "C-$1--$2--$3------\n";
+ RunQuery($Param);
+ if (defined $3) {
+ $Param->{CID}->{$2} = $3 ;
+ #print "DB:$Param->{CID}->{$2} .. $2 .. $3 \n";
+ }
+ }
+
+ elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Quit\s+$/i) { # remove connection ID($2) and querystring
+ #print "Q-$1--$2--------\n";
+ RunQuery($Param);
+ delete $Param->{CID}->{$2} ;
+ }
+
+ elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Query\s+(select.+)$/i) { # get connection ID($2) and querystring
+ #print "S1-$1--$2--$3------\n";
+ RunQuery($Param);
+ unless ($Param->{CID}->{$2}) {
+ #print "Error: No Database for Handle: $2 found\n";
+ }
+ else {
+ $Param->{DB}=$Param->{CID}->{$2};
+
+ my $s = "$3";
+ $s =~ s/from\s/from $Param->{DB}./i;
+ $Param->{Query}="EXPLAIN $s";
+
+ #$s =~ m/from\s+(\w+[.]\w+)/i;
+ #$Param->{tab} =$1;
+ #print "-- $Param->{tab} -- $s --\n";
+ }
+ }
+
+ elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Query\s+(update.+)$/i) { # get connection ID($2) and querystring
+ #print "S2--$1--$2--$3------\n";
+ RunQuery($Param);
+ unless ($Param->{CID}->{$2}) {
+ #print "Error: No Database for Handle: $2 found\n";
+ }
+ else {
+ $Param->{DB}=$Param->{CID}->{$2};
+
+ my $ud = $3;
+ $ud =~ m/^update\s+(\w+).+(where.+)$/i;
+ $Param->{Query} ="EXPLAIN SELECT * FROM $1 $2";
+ $Param->{Query} =~ s/from\s/from $Param->{DB}./i;
+
+ #$Param->{Query} =~ m/from\s+(\w+[.]\w+)/i;
+ #$Param->{tab} =$1;
+ }
+ }
+
+ elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Statistics\s+(.*)$/i) { # get connection ID($2) and info?
+ $Param->{Statistics} ++;
+ #print "Statistics--$1--$2--$3------\n";
+ RunQuery($Param);
+ }
+ elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Query\s+(.+)$/i) { # get connection ID($2)
+ $Param->{QueryCount} ++;
+ #print "Query-NULL $3\n";
+ RunQuery($Param);
+ }
+ elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Refresh\s+(.+)$/i) { # get connection ID($2)
+ $Param->{Refresh} ++;
+ #print "Refresh\n";
+ RunQuery($Param);
+ }
+ elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Init\s+(.+)$/i) { # get connection ID($2)
+ $Param->{Init} ++;
+ #print "Init $3\n";
+ RunQuery($Param);
+ }
+ elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Field\s+(.+)$/i) { # get connection ID($2)
+ $Param->{Field} ++;
+ #print "Field $3\n";
+ RunQuery($Param);
+ }
+
+ elsif (m/^\s+(.+)$/ ) { # command could be some lines ...
+ #print "multi-lined ($1)\n";
+ my ($A)=$1;
+ chomp $A;
+ $Param->{Query} .= " $1";
+ #print "multi-lined ($1)<<$Param->{Query}>>\n";
+ }
+
+
+ }
+
+ }
+
+ $Param->{dbh}->disconnect();
+
+ if (1 == 0) {
+ print "\nunclosed handles----------------------------------------\n";
+ my $count=0;
+ foreach (sort keys %{$Param->{CID}}) {
+ print "$count | $_ : $Param->{CID}->{$_} \n";
+ $count ++;
+ }
+ }
+
+ print "\nIndex usage ------------------------------------\n";
+ foreach my $t (sort keys %{$Param->{Data}}) {
+ print "\nTable\t$t: ---\n";
+ foreach my $k (sort keys %{$Param->{Data}->{$t}}) {
+ print " count\t$k:\n";
+ my %h = %{$Param->{Data}->{$t}->{$k}};
+ foreach (sort {$h{$a} <=> $h{$b}} keys %h) {
+ print " $Param->{Data}->{$t}->{$k}->{$_}\t$_\n";
+ }
+ }
+ }
+
+ $Param->{AllCount}=0;
+ print "\nQueries causing table scans -------------------\n\n";
+ foreach (@{$Param->{ALL}}) {
+ $Param->{AllCount} ++;
+ print "$_\n";
+ }
+ print "Sum: $Param->{AllCount} table scans\n";
+
+ print "\nSummary ---------------------------------------\n\n";
+ print "Select: \t$Param->{SelectCount} queries\n";
+ print "Update: \t$Param->{UpdateCount} queries\n";
+ print "\n";
+
+ print "Init: \t$Param->{Init} times\n";
+ print "Field: \t$Param->{Field} times\n";
+ print "Refresh: \t$Param->{Refresh} times\n";
+ print "Query: \t$Param->{QueryCount} times\n";
+ print "Statistics:\t$Param->{Statistics} times\n";
+ print "\n";
+
+ print "Logfile: \t$Param->{LineCount} lines\n";
+ print "Started: \t".localtime($Param->{Start})."\n";
+ print "Finished: \t".localtime(time)."\n";
+
+ }
+}
+
+
+###########################################################################
+#
+#
+#
+sub RunQuery {
+ my $Param = shift ;
+
+ if (defined $Param->{Query}) {
+ if (defined $Param->{DB} ) {
+
+ $Param->{Query} =~ m/from\s+(\w+[.]\w+|\w+)/i;
+ $Param->{tab} =$1;
+ #print "||$Param->{tab} -- $Param->{Query}\n";
+
+ my $sth=$Param->{dbh}->prepare("USE $Param->{DB}");
+ if (DBI::err()) {
+ if ($Param->{PrintError}) {print "Error: ".DBI::errstr()."\n";}
+ }
+ else {
+ $sth->execute();
+ if (DBI::err()) {
+ if ($Param->{PrintError}) {print "Error: ".DBI::errstr()."\n";}
+ }
+ else {
+ $sth->finish();
+
+ $sth=$Param->{dbh}->prepare($Param->{Query});
+ if (DBI::err()) {
+ if ($Param->{PrintError}) {print "Error: ".DBI::errstr()."\n";}
+ }
+ else {
+ #print "$Param->{Query}\n";
+ $sth->execute();
+ if (DBI::err()) {
+ if ($Param->{PrintError}) {print "[$Param->{LineCount}]<<$Param->{Query}>>\n";}
+ if ($Param->{PrintError}) {print "Error: ".DBI::errstr()."\n";}
+ }
+ else {
+ my $row = undef;
+ while ($row = $sth->fetchrow_hashref()) {
+ $Param->{SelectCount} ++;
+
+ if (defined $row->{Comment}) {
+ push (@{$Param->{Comment}}, "$row->{Comment}; $_; $Param->{DB}; $Param->{Query}");
+ }
+ foreach (@{$Param->{Rows}}) {
+ if (defined $row->{$_}) {
+ #if (($_ eq 'type' ) and ($row->{$_} eq 'ALL')) {
+ if ($row->{type} eq 'ALL') {
+ push (@{$Param->{ALL}}, "$row->{$_} $_ $Param->{DB} $Param->{Query}");
+ #print ">> $row->{$_} $_ $Param->{DB} $Param->{Query}\n";
+ }
+ $Param->{IdxUseCount} ++;
+ $Param->{Data}->{$Param->{tab}}->{$_}->{$row->{$_}} ++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ $sth->finish();
+ }
+ $Param->{Query} = undef ;
+ }
+}
+
+###########################################################################
+#
+#
+#
+sub ShowOptions {
+ print <<EOF;
+Usage: $0 [OPTIONS] < LOGFILE
+
+--date=YYMMDD select only entrys of date
+-d=YYMMDD
+--host=HOSTNAME db-host to ask
+-h=HOSTNAME
+--user=USERNAME db-user
+-u=USERNAME
+--password=PASSWORD password of db-user
+-p=PASSWORD
+
+Read logfile from STDIN an try to EXPLAIN all SELECT statements. All UPDATE statements are rewritten to an EXPLAIN SELECT statement. The results of the EXPLAIN statement are collected and counted. All results with type=ALL are collected in an separete list. Results are printed to STDOUT.
+
+EOF
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+explain_log.pl
+
+Feed a mysqld general logfile (created with mysqld --log) back into mysql
+and collect statistics about index usage with EXPLAIN.
+
+=head1 DISCUSSION
+
+To optimize your indices, you have to know which ones are actually
+used and what kind of queries are causing table scans. Especially
+if you are generating your queries dynamically and you have a huge
+amount of queries going on, this isn't easy.
+
+Use this tool to take a look at the effects of your real life queries.
+Then add indices to avoid table scans and remove those which aren't used.
+
+=head1 USAGE
+
+explain_log.pl [--date=YYMMDD] --host=dbhost] [--user=dbuser] [--password=dbpw] < logfile
+
+--date=YYMMDD select only entrys of date
+
+-d=YYMMDD
+
+--host=HOSTNAME db-host to ask
+
+-h=HOSTNAME
+
+--user=USERNAME db-user
+
+-u=USERNAME
+
+--password=PASSWORD password of db-user
+
+-p=PASSWORD
+
+=head1 EXAMPLE
+
+explain_log.pl --host=localhost --user=foo --password=bar < /var/lib/mysql/mobile.log
+
+=head1 AUTHOR
+
+ Stefan Nitz
+ Jan Willamowius <jan@mobile.de>, http://www.mobile.de
+
+=head1 RECRUITING
+
+If you are looking for a MySQL or Perl job, take a look at http://www.mobile.de
+and send me an email with your resume (you must be speaking German!).
+
+=head1 SEE ALSO
+
+mysql documentation
+
+=cut
diff --git a/scripts/mysql_fix_extensions.sh b/scripts/mysql_fix_extensions.sh
new file mode 100644
index 00000000000..fbc72406f5e
--- /dev/null
+++ b/scripts/mysql_fix_extensions.sh
@@ -0,0 +1,16 @@
+#!@PERL@
+# This is a utility for MySQL. It is not needed by any standard part
+# of MySQL.
+
+# Usage: mysql_fix_extentions datadir
+# does not work with RAID, with InnoDB or BDB tables
+# makes .frm lowercase and .MYI/MYD/ISM/ISD uppercase
+# useful when datafiles are copied from windows
+
+die "Usage: $0 datadir\n" unless -d $ARGV[0];
+
+for $a (<$ARGV[0]/*/*.*>) { $_=$a;
+ s/\.frm$/.frm/i;
+ s/\.(is[md]|my[id])$/\U$&/i;
+ rename ($a, $_) || warn "Cannot rename $a => $_ : $!";
+}
diff --git a/scripts/mysql_fix_privilege_tables.sh b/scripts/mysql_fix_privilege_tables.sh
index 86312fdab52..7226840b475 100644
--- a/scripts/mysql_fix_privilege_tables.sh
+++ b/scripts/mysql_fix_privilege_tables.sh
@@ -56,6 +56,13 @@ END_OF_DATA
echo ""
fi
+echo "Adding columns needed by GRANT .. REQUIRE (openssl)"
+echo "You can ignore any Duplicate column errors"
+@bindir@/mysql --user=root --password="$root_password" --host="$host" mysql <<END_OF_DATA
+ALTER TABLE user ADD ssl_type enum('NONE','ANY','X509', 'SPECIFIED') DEFAULT 'NONE' NOT NULL, ADD ssl_cipher BLOB NOT NULL, ADD x509_issuer BLOB NOT NULL, ADD x509_subject BLOB NOT NULL
+END_OF_DATA
+echo ""
+
#
# Create tables_priv and columns_priv if they don't exists
#
@@ -96,6 +103,7 @@ echo "You can ignore any errors from this"
@bindir@/mysql -f --user=root --password="$root_password" --host="$host" mysql <<END_OF_DATA
ALTER TABLE columns_priv change Type Column_priv set('Select','Insert','Update','References') DEFAULT '' NOT NULL;
END_OF_DATA
+echo ""
#
# Add the new 'type' column to the func table.
@@ -107,3 +115,14 @@ echo "You can ignore any Duplicate column errors"
@bindir@/mysql --user=root --password=$root_password mysql <<EOF
alter table func add type enum ('function','aggregate') NOT NULL;
EOF
+echo ""
+
+echo "Converting all privilege tables to MyISAM format"
+@bindir@/mysql -f --user=root --password="$root_password" --host="$host" mysql <<END_OF_DATA
+ALTER TABLE user type=MyISAM;
+ALTER TABLE db type=MyISAM;
+ALTER TABLE host type=MyISAM;
+ALTER TABLE func type=MyISAM;
+ALTER TABLE columns_priv type=MyISAM;
+ALTER TABLE tables_priv type=MyISAM;
+END_OF_DATA
diff --git a/scripts/mysql_install_db.sh b/scripts/mysql_install_db.sh
index f7324668bd2..473b182de25 100644
--- a/scripts/mysql_install_db.sh
+++ b/scripts/mysql_install_db.sh
@@ -224,18 +224,25 @@ then
c_u="$c_u References_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
c_u="$c_u Index_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
c_u="$c_u Alter_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_u="$c_u ssl_type enum('NONE','ANY','X509', 'SPECIFIED') DEFAULT 'NONE' NOT NULL,"
+ c_u="$c_u ssl_cipher BLOB NOT NULL,"
+ c_u="$c_u x509_issuer BLOB NOT NULL,"
+ c_u="$c_u x509_subject BLOB NOT NULL,"
+ 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 PRIMARY KEY Host (Host,User)"
c_u="$c_u )"
c_u="$c_u comment='Users and global privileges';"
- i_u="INSERT INTO user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
- INSERT INTO user VALUES ('$hostname','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
+ i_u="INSERT INTO user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','NONE','','','',0,0,0);
+ INSERT INTO user VALUES ('$hostname','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','NONE','','','',0,0,0);
- REPLACE INTO user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
- REPLACE INTO user VALUES ('$hostname','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
+ REPLACE INTO user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','NONE','','','',0,0,0);
+ REPLACE INTO user VALUES ('$hostname','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','NONE','','','',0,0,0);
- INSERT INTO user VALUES ('localhost','','','N','N','N','N','N','N','N','N','N','N','N','N','N','N');
- INSERT INTO user VALUES ('$hostname','','','N','N','N','N','N','N','N','N','N','N','N','N','N','N');"
+ INSERT INTO user VALUES ('localhost','','','N','N','N','N','N','N','N','N','N','N','N','N','N','N','NONE','','','',0,0,0);
+ INSERT INTO user VALUES ('$hostname','','','N','N','N','N','N','N','N','N','N','N','N','N','N','N','NONE','','','',0,0,0);"
fi
if test ! -f $mdata/func.frm
@@ -290,7 +297,7 @@ fi
echo "Installing all prepared tables"
if eval "$execdir/mysqld $defaults --bootstrap --skip-grant-tables \
- --basedir=$basedir --datadir=$ldata --skip-innodb --skip-gemini --skip-bdb $args" << END_OF_DATA
+ --basedir=$basedir --datadir=$ldata --skip-innodb --skip-bdb $args" << END_OF_DATA
use mysql;
$c_d
$i_d
@@ -317,8 +324,8 @@ then
fi
echo "PLEASE REMEMBER TO SET A PASSWORD FOR THE MySQL root USER !"
echo "This is done with:"
- echo "$bindir/mysqladmin -u root -p password 'new-password'"
- echo "$bindir/mysqladmin -u root -h $hostname -p password 'new-password'"
+ echo "$bindir/mysqladmin -u root password 'new-password'"
+ echo "$bindir/mysqladmin -u root -h $hostname password 'new-password'"
echo "See the manual for more instructions."
#
# Print message about upgrading unless we have created a new db table.
@@ -333,7 +340,7 @@ then
if test "$IN_RPM" -eq 0
then
echo "You can start the MySQL daemon with:"
- echo "cd @prefix@ ; $bindir/safe_mysqld &"
+ echo "cd @prefix@ ; $bindir/mysqld_safe &"
echo
echo "You can test the MySQL daemon with the benchmarks in the 'sql-bench' directory:"
echo "cd sql-bench ; run-all-tests"
diff --git a/scripts/mysql_new_fix_privilege_tables.sh b/scripts/mysql_new_fix_privilege_tables.sh
new file mode 100644
index 00000000000..ce10ed0b412
--- /dev/null
+++ b/scripts/mysql_new_fix_privilege_tables.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+echo "This scripts updates the mysql.user, mysql.db, mysql.host and the"
+echo "mysql.func table to MySQL 3.22.14 and above."
+echo ""
+echo "This is needed if you want to use the new GRANT functions,"
+echo "CREATE AGGREAGATE FUNCTION or want to use the more secure passwords in 3.23"
+echo ""
+echo "If you get Access denied errors, you should run this script again"
+echo "and give the MySQL root user password as a argument!"
+
+root_password="$1"
+host="localhost"
+
+# Fix old password format, add File_priv and func table
+echo ""
+echo "If your tables are already up to date or partially up to date you will"
+echo "get some warnings about 'Duplicated column name'. You can safely ignore these!"
+
+# Add fields that can be used to limit number of questions and connections
+# for some users.
+
+@bindir@/mysql -f --user=root --password="$root_password" --host="$host" mysql <<END_OF_DATA
+alter table user add max_questions int(11) NOT NULL, add max_updates int(11) unsigned NOT NULL, add max_connections int(11) unsigned NOT NULL;
+END_OF_DATA
diff --git a/scripts/mysqld_multi.sh b/scripts/mysqld_multi.sh
index 1adaa458271..83d12239472 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.2";
+$VER="2.3";
$opt_config_file = undef();
$opt_example = 0;
@@ -183,7 +183,7 @@ sub report_mysqlds
sub start_mysqlds()
{
- my (@groups, $com, $i, @options, $j);
+ my (@groups, $com, $tmp, $i, @options, $j);
if (!$opt_no_log)
{
@@ -202,11 +202,20 @@ sub start_mysqlds()
@options = `$com`;
chop @options;
- $com = "$mysqld";
- for ($j = 0; defined($options[$j]); $j++)
+ $com= "$mysqld";
+ for ($j = 0, $tmp= ""; defined($options[$j]); $j++)
{
- $com.= " $options[$j]";
+ if ("--mysqld=" eq substr($options[$j], 0, 9))
+ {
+ $options[$j]=~ s/\-\-mysqld\=//;
+ $com= $options[$j];
+ }
+ else
+ {
+ $tmp.= " $options[$j]";
+ }
}
+ $com.= $tmp;
$com.= " >> $opt_log 2>&1" if (!$opt_no_log);
$com.= " &";
system($com);
@@ -457,12 +466,12 @@ sub example
# directory, that you have (just change the socket, -S=...)
# See more detailed information from chapter:
# '6 The MySQL Access Privilege System' from the MySQL manual.
-# 2.pid-file is very important, if you are using safe_mysqld to start mysqld
-# (e.g. --mysqld=safe_mysqld) Every mysqld should have it's own pid-file.
-# The advantage using safe_mysqld instead of mysqld directly here is, that
-# safe_mysqld 'guards' every mysqld process and will restart it, if mysqld
+# 2.pid-file is very important, if you are using mysqld_safe to start mysqld
+# (e.g. --mysqld=mysqld_safe) Every mysqld should have it's own pid-file.
+# The advantage using mysqld_safe instead of mysqld directly here is, that
+# mysqld_safe 'guards' every mysqld process and will restart it, if mysqld
# process fails due to signal kill -9, or similar. (Like segmentation fault,
-# which MySQL should never do, of course ;) Please note that safe_mysqld
+# which MySQL should never do, of course ;) Please note that mysqld_safe
# script may require that you start it from a certain place. This means that
# you may have to CD to a certain directory, before you start the
# mysqld_multi. If you have problems starting, please see the script.
@@ -497,7 +506,7 @@ sub example
# give you extra performance in a threaded system!
#
[mysqld_multi]
-mysqld = @bindir@/safe_mysqld
+mysqld = @bindir@/mysqld_safe
mysqladmin = @bindir@/mysqladmin
user = multi_admin
password = multipass
@@ -591,10 +600,15 @@ Options:
Using: $opt_log
--mysqladmin=... mysqladmin binary to be used for a server shutdown.
Using: $mysqladmin
---mysqld=... mysqld binary to be used. Note that you can give safe_mysqld
+--mysqld=... mysqld binary to be used. Note that you can give mysqld_safe
to this option also. The options are passed to mysqld. Just
- make sure you have mysqld in your PATH or fix safe_mysqld.
+ make sure you have mysqld in your PATH or fix mysqld_safe.
Using: $mysqld
+ Please note: Since mysqld_multi version 2.3 you can also
+ give this option in groups [mysqld#]! This will be
+ recognized as a special option and will not be passed
+ to the mysqld. This will allow one to start different
+ mysqld versions with mysqld_multi.
--no-log Print to stdout instead of the log file. By default the log
file is turned on.
--password=... Password for user for mysqladmin.
diff --git a/scripts/safe_mysqld-watch.sh b/scripts/mysqld_safe-watch.sh
index 30f95fd7a86..c59b3b2614d 100644
--- a/scripts/safe_mysqld-watch.sh
+++ b/scripts/mysqld_safe-watch.sh
@@ -8,7 +8,7 @@
# binary installation that has other paths than you are using.
#
# mysql.server works by first doing a cd to the base directory and from there
-# executing safe_mysqld
+# executing mysqld_safe
# Check if we are starting this relative (for the binary release)
if test -f ./data/mysql/db.frm -a -f ./share/mysql/english/errmsg.sys -a \
diff --git a/scripts/safe_mysqld.sh b/scripts/mysqld_safe.sh
index 3494e3d707e..e6ecbf6f729 100644
--- a/scripts/safe_mysqld.sh
+++ b/scripts/mysqld_safe.sh
@@ -8,7 +8,7 @@
# binary installation that has other paths than you are using.
#
# mysql.server works by first doing a cd to the base directory and from there
-# executing safe_mysqld
+# executing mysqld_safe
trap '' 1 2 3 15 # we shouldn't let anyone kill us
@@ -23,32 +23,37 @@ 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
# the command line) into the args variable.
- pick_args=$1; shift
+ pick_args=
+ if test "$1" = PICK-ARGS-FROM-ARGV
+ then
+ pick_args=1
+ shift
+ fi
for arg do
case "$arg" in
# these get passed explicitly to mysqld
- --basedir=*) MY_BASEDIR_VERSION=`echo "$arg" | sed -e "s;--[^=]*=;;"` ;;
- --datadir=*) DATADIR=`echo "$arg" | sed -e "s;--[^=]*=;;"` ;;
- --pid-file=*) pid_file=`echo "$arg" | sed -e "s;--[^=]*=;;"` ;;
+ --basedir=*) MY_BASEDIR_VERSION=`echo "$arg" | sed -e "s;--basedir=;;"` ;;
+ --datadir=*) DATADIR=`echo "$arg" | sed -e "s;--datadir=;;"` ;;
+ --pid-file=*) pid_file=`echo "$arg" | sed -e "s;--pid-file=;;"` ;;
--user=*) user=`echo "$arg" | sed -e "s;--[^=]*=;;"` ; SET_USER=1 ;;
- # these two might have been set in a [safe_mysqld] section of my.cnf
- # they get passed via environment variables to safe_mysqld
- --socket=*) MYSQL_UNIX_PORT=`echo "$arg" | sed -e "s;--[^=]*=;;"` ;;
- --port=*) MYSQL_TCP_PORT=`echo "$arg" | sed -e "s;--[^=]*=;;"` ;;
+ # these two might have been set in a [mysqld_safe] section of my.cnf
+ # they get passed via environment variables to mysqld_safe
+ --socket=*) MYSQL_UNIX_PORT=`echo "$arg" | sed -e "s;--socket=;;"` ;;
+ --port=*) MYSQL_TCP_PORT=`echo "$arg" | sed -e "s;--port=;;"` ;;
- # safe_mysqld-specific options
- --ledir=*) ledir=`echo "$arg" | sed -e "s;--[^=]*=;;"` ;;
- --err-log=*) err_log=`echo "$arg" | sed -e "s;--[^=]*=;;"` ;;
+ # mysqld_safe-specific options - must be set in my.cnf ([mysqld_safe])!
+ --ledir=*) ledir=`echo "$arg" | sed -e "s;--ledir=;;"` ;;
+ --err-log=*) err_log=`echo "$arg" | sed -e "s;--err-log=;;"` ;;
# QQ The --open-files should be removed
- --open-files=*) open_files=`echo "$arg" | sed -e "s;--[^=]*=;;"` ;;
- --open-files-limit=*) open_files=`echo "$arg" | sed -e "s;--[^=]*=;;"` ;;
- --core-file-size=*) core_file_size=`echo "$arg" | sed -e "s;--[^=]*=;;"` ;;
- --timezone=*) TZ=`echo "$arg" | sed -e "s;--[^=]*=;;"` ; export TZ; ;;
- --mysqld=*) MYSQLD=`echo "$arg" | sed -e "s;--[^=]*=;;"` ;;
+ --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; ;;
+ --mysqld=*) MYSQLD=`echo "$arg" | sed -e "s;--mysqld=;;"` ;;
--mysqld-version=*)
- tmp=`echo "$arg" | sed -e "s;--[^=]*=;;"`
+ tmp=`echo "$arg" | sed -e "s;--mysqld-version=;;"`
if test -n "$tmp"
then
MYSQLD="mysqld-$tmp"
@@ -57,7 +62,7 @@ parse_arguments() {
fi
;;
*)
- if test $pick_args -eq 1
+ if test -n "$pick_args"
then
# This sed command makes sure that any special chars are quoted,
# so the arg gets passed exactly to the server.
@@ -110,7 +115,7 @@ pid_file=
err_log=
SET_USER=0
-# Get first arguments from the my.cnf file, groups [mysqld] and [safe_mysqld]
+# Get first arguments from the my.cnf file, groups [mysqld] and [mysqld_safe]
# and then merge with the command line arguments
if test -x ./bin/my_print_defaults
then
@@ -126,15 +131,15 @@ else
fi
args=
-parse_arguments 0 `$print_defaults $defaults mysqld server safe_mysqld`
-parse_arguments 1 "$@"
+parse_arguments `$print_defaults $defaults mysqld server mysqld_safe safe_mysqld`
+parse_arguments PICK-ARGS-FROM-ARGV "$@"
if test ! -x $ledir/$MYSQLD
then
echo "The file $ledir/$MYSQLD doesn't exist or is not executable"
echo "Please do a cd to the mysql installation directory and restart"
echo "this script from there as follows:"
- echo "./bin/safe_mysqld".
+ echo "./bin/mysqld_safe".
exit 1
fi
@@ -154,15 +159,48 @@ export MYSQL_TCP_PORT
NOHUP_NICENESS="nohup"
-if test -w /
+
+# Using nice with no args to get the niceness level is GNU-specific.
+# This check could be extended for other operating systems (e.g.,
+# BSD could use "nohup sh -c 'ps -o nice -p $$' | tail -1").
+# But, it also seems that GNU nohup is the only one which messes
+# with the priority, so this is okay.
+if nohup nice > /dev/null 2>&1
then
- NOHUP_NICENESS=`nohup nice 2>&1`
- if test $? -eq 0 && test x"$NOHUP_NICENESS" != x0 && nice --1 echo foo > /dev/null 2>&1
- then
- NOHUP_NICENESS="nice --$NOHUP_NICENESS nohup"
- else
- NOHUP_NICENESS="nohup"
- fi
+ normal_niceness=`nice`
+ nohup_niceness=`nohup nice`
+
+ numeric_nice_values=1
+ for val in $normal_niceness $nohup_niceness
+ do
+ case "$val" in
+ -[0-9] | -[0-9][0-9] | -[0-9][0-9][0-9] | \
+ [0-9] | [0-9][0-9] | [0-9][0-9][0-9] )
+ ;;
+ * )
+ numeric_nice_values=0 ;;
+ esac
+ done
+
+ if test $numeric_nice_values -eq 1
+ then
+ nice_value_diff=`expr $nohup_niceness - $normal_niceness`
+ if test $? -eq 0 && test $nice_value_diff -gt 0 && \
+ nice --$nice_value_diff echo testing > /dev/null 2>&1
+ then
+ # nohup increases the priority (bad), and we are permitted
+ # to lower the priority
+ NOHUP_NICENESS="nice --$nice_value_diff nohup"
+ fi
+ fi
+else
+ if nohup echo testing > /dev/null 2>&1
+ then
+ :
+ else
+ # nohup doesn't work on this system
+ NOHUP_NICENESS=""
+ fi
fi
USER_OPTION=""
diff --git a/sql-bench/Comments/interbase b/sql-bench/Comments/interbase
new file mode 100644
index 00000000000..addaf74b63f
--- /dev/null
+++ b/sql-bench/Comments/interbase
@@ -0,0 +1,18 @@
+Running crash-me on Interbase:
+I
+- got opensource version of interbase 6.0.1
+ (both mode, classic and superserver),
+- set up DBD::InterBase from cpan,
+- created database "test" and set sql_dialect for that database to 3
+- executed crash-me for both interbase's models (classic and superserver).
+
+There were some problems during the execution:
+1) Sometimes client side got SIGSEGV , At that moment server side
+ writes
+ gds__alloc: non-positive size allocation request
+ to log file.
+ This problem has both models. I am not shure if it's interbase or
+ DBD:InterBase problem (though DBD::InterBase made all nesessary
+ tests during the installation without any problem)
+
+2) In "superserver" mode ibserver several times died (and ibguard restarted it)
diff --git a/sql-bench/Makefile.am b/sql-bench/Makefile.am
index 80806f35418..4bfa9868428 100644
--- a/sql-bench/Makefile.am
+++ b/sql-bench/Makefile.am
@@ -21,16 +21,18 @@ benchdir_root= $(prefix)
benchdir = $(benchdir_root)/sql-bench
bench_SCRIPTS = test-ATIS test-connect test-create test-insert \
test-big-tables test-select test-wisconsin \
- test-alter-table graph-compare-results \
+ test-alter-table test-transactions \
+ graph-compare-results \
bench-init.pl compare-results run-all-tests \
- server-cfg crash-me copy-db
+ server-cfg crash-me copy-db bench-count-distinct
CLEANFILES = $(bench_SCRIPTS)
EXTRA_SCRIPTS = test-ATIS.sh test-connect.sh test-create.sh \
test-insert.sh test-big-tables.sh test-select.sh \
test-alter-table.sh test-wisconsin.sh \
+ test-transactions.sh \
bench-init.pl.sh compare-results.sh server-cfg.sh \
run-all-tests.sh crash-me.sh copy-db.sh \
- graph-compare-results.sh
+ bench-count-distinct.sh graph-compare-results.sh
EXTRA_DIST = $(EXTRA_SCRIPTS)
dist-hook:
diff --git a/sql-bench/as3ap.sh b/sql-bench/as3ap.sh
new file mode 100644
index 00000000000..ed796249ebb
--- /dev/null
+++ b/sql-bench/as3ap.sh
@@ -0,0 +1,636 @@
+#!@PERL@
+# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#
+# 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
+#
+# AS3AP single-user benchmark.
+#
+
+##################### Standard benchmark inits ##############################
+
+use DBI;
+use Benchmark;
+
+chomp($pwd = `pwd`); $pwd = "." if ($pwd eq '');
+require "$pwd/bench-init.pl" || die "Can't read Configuration file: $!\n";
+
+$opt_loop_count=1;
+
+#Create tables
+
+$dbh = $server->connect();
+
+#Create Table
+$sth = $dbh->do("drop table uniques");
+$sth = $dbh->do("drop table updates");
+$sth = $dbh->do("drop table hundred");
+$sth = $dbh->do("drop table tenpct");
+$sth = $dbh->do("drop table tiny");
+
+#Temporary table
+$sth = $dbh->do("drop table saveupdates");
+
+@fields=("col_key int not null",
+ "col_int int not null",
+ "col_signed int not null",
+ "col_float float not null",
+ "col_double float not null",
+ "col_decim numeric(18,2) not null",
+ "col_date char(20) not null",
+ "col_code char(10) not null",
+ "col_name char(20) not null",
+ "col_address varchar(80) not null");
+
+do_many($dbh,$server->create("uniques",\@fields,[]));
+do_many($dbh,$server->create("updates",\@fields,[]));
+do_many($dbh,$server->create("hundred",\@fields,[]));
+do_many($dbh,$server->create("tenpct",\@fields,[]));
+do_many($dbh,$server->create("tiny",["col_key int not null"],[]));
+
+print "Start AS3AP benchmark\n\n";
+
+$start_time=new Benchmark;
+
+print "Load DATA\n";
+#Load DATA
+
+@table_names=("uniques","updates","hundred","tenpct","tiny");
+
+$loop_time=new Benchmark;
+
+if ($opt_fast && $server->{'limits'}->{'load_data_infile'})
+{
+ for ($ti = 0; $ti <= $#table_names; $ti++)
+ {
+ my $table_name = $table_names[$ti];
+ my $file = "$pwd/Data/AS3AP/${table_name}\.new";
+ print "$table_name - $file\n" if ($opt_debug);
+ $row_count += $server->insert_file($table_name,$file,$dbh);
+ }
+}
+else
+{
+ for ($ti = 0; $ti <= $#table_names; $ti++)
+ {
+ my $table_name = $table_names[$ti];
+ print "$table_name - $file\n" if ($opt_debug);
+ my $insert_start = "insert into $table_name values (";
+ open(DATA, "$pwd/Data/AS3AP/${table_name}\.new") || die "Can't open text file: $pwd/Data/AS3AP/${table_name}\.new\n";
+ while(<DATA>)
+ {
+ chomp;
+ next unless ( $_ =~ /\w/ ); # skip blank lines
+ $command = $insert_start."$_".")";
+ $command =~ $server->fix_to_insert($command);
+ print "$command\n" if ($opt_debug);
+ $sth = $dbh->do($command) or die "Got error: $DBI::errstr when executing '$command'\n";
+ $row_count++;
+ }
+ close(DATA);
+ }
+}
+
+$end_time=new Benchmark;
+print "Time for Load Data - " . "($row_count): " .
+timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+
+
+print "Create Index\n";
+
+test_command("create_idx_uniques_key_bt",
+ "time for create_idx_uniques_key_bt",
+ "create unique index uniques_key_bt on uniques (col_key)",$dbh,$opt_loop_count);
+
+test_command("create_idx_updates_key_bt",
+ "time for create_idx_updates_key_bt",
+ "create unique index updates_key_bt on updates (col_key)",$dbh,$opt_loop_count);
+
+test_command("create_idx_hundred_key_bt",
+ "time for create_idx_hundred_key_bt",
+ "create unique index hundred_key_bt on hundred (col_key)",
+ $dbh,$opt_loop_count);
+
+test_command("create_idx_tenpct_key_bt",
+ "time for create_idx_tenpct_key_bt",
+ "create unique index tenpct_key_bt on tenpct (col_key)",$dbh,$opt_loop_count);
+
+test_command("create_idx_tenpct_key_code_bt",
+ "time for create_idx_tenpct_key_code_bt",
+ "create index tenpct_key_code_bt on tenpct (col_key,col_code)",
+ $dbh,$opt_loop_count);
+
+test_command("create_idx_tiny_key_bt",
+ "time for create_idx_tiny_key_bt",
+ "create index tiny_key_bt on tiny (col_key)",$dbh,$opt_loop_count);
+
+test_command("create_idx_tenpct_int_bt",
+ "time for create_idx_tenpct_int_bt",
+ "create index tenpct_int_bt on tenpct (col_int)",$dbh,$opt_loop_count);
+
+test_command("create_idx_tenpct_signed_bt",
+ "time for create_idx_tenpct_signed_bt",
+ "create index tenpct_signed_bt on tenpct (col_signed)",$dbh,$opt_loop_count);
+
+test_command("create_idx_uniques_code_h",
+ "time for create_idx_uniques_code_h",
+ "create index uniques_code_h on uniques (col_code)",$dbh,$opt_loop_count);
+
+test_command("create_idx_tenpct_double_bt",
+ "time for create_idx_tenpct_double_bt",
+ "create index tenpct_double_bt on tenpct (col_double)",$dbh,$opt_loop_count);
+
+
+test_command("create_idx_updates_decim_bt",
+ "time for create_idx_updates_decim_bt",
+ "create index updates_decim_bt on updates (col_decim)",$dbh,$opt_loop_count);
+
+test_command("create_idx_tenpct_float_bt",
+ "time for create_idx_tenpct_float_bt",
+ "create index tenpct_float_bt on tenpct (col_float)",$dbh,$opt_loop_count);
+
+test_command("create_idx_updates_int_bt",
+ "time for create_idx_updates_int_bt",
+ "create index updates_int_bt on updates (col_int)",$dbh,$opt_loop_count);
+
+test_command("create_idx_tenpct_decim_bt",
+ "time for create_idx_tenpct_decim_bt",
+ "create index tenpct_decim_bt on tenpct (col_decim)",$dbh,$opt_loop_count);
+
+test_command("create_idx_hundred_code_h",
+ "time for create_idx_hundred_code_h",
+ "create index hundred_code_h on hundred (col_code)",$dbh,$opt_loop_count);
+
+test_command("create_idx_tenpct_name_h",
+ "time for create_idx_tenpct_name_h",
+ "create index tenpct_name_h on tenpct (col_name)",$dbh,$opt_loop_count);
+
+test_command("create_idx_updates_code_h",
+ "time for create_idx_updates_code_h",
+ "create index updates_code_h on updates (col_code)",$dbh,$opt_loop_count);
+
+test_command("create_idx_tenpct_code_h",
+ "time for create_idx_tenpct_code_h",
+ "create index tenpct_code_h on tenpct (col_code)",$dbh,$opt_loop_count);
+
+test_command("create_idx_updates_double_bt",
+ "time for create_idx_updates_double_bt",
+ "create index updates_double_bt on updates (col_double)",$dbh,$opt_loop_count);
+
+test_command("create_idx_hundred_foreign",
+ "time for create_idx_hundred_foreign",
+ "alter table hundred add constraint fk_hundred_updates foreign key (col_signed)
+ references updates (col_key)",$dbh,$opt_loop_count);
+
+test_query("sel_1_cl",
+ "Time to sel_1_cl",
+ "select col_key, col_int, col_signed, col_code, col_double, col_name
+ from updates where col_key = 1000",$dbh,$opt_loop_count);
+
+test_query("join_3_cl",
+ "Time to join_3_cl",
+ "select uniques.col_signed, uniques.col_date,
+ hundred.col_signed, hundred.col_date,
+ tenpct.col_signed, tenpct.col_date
+ from uniques, hundred, tenpct
+ where uniques.col_key = hundred.col_key
+ and uniques.col_key = tenpct.col_key
+ and uniques.col_key = 1000",$dbh,$opt_loop_count);
+
+test_query("sel_100_ncl",
+ "Time to sel_100_ncl",
+ "select col_key, col_int, col_signed, col_code,col_double, col_name
+ from updates where col_int <= 100",$dbh,$opt_loop_count);
+
+test_query("table_scan",
+ "Time to table_scan",
+ "select * from uniques where col_int = 1",$dbh,$opt_loop_count);
+
+test_query("agg_func",
+ "Time for agg_func",
+ "select min(col_key) from hundred group by col_name",$dbh,$opt_loop_count);
+
+test_query("agg_scal",
+ "Time for agg_scal",
+ "select min(col_key) from uniques",$dbh,$opt_loop_count);
+
+test_query("sel_100_cl",
+ "Time for sel_100_cl",
+ "select col_key, col_int, col_signed, col_code,
+ col_double, col_name
+ from updates where col_key <= 100",$dbh,$opt_loop_count);
+
+test_query("join_3_ncl",
+ "Time for join_3_ncl",
+ "select uniques.col_signed, uniques.col_date,
+ hundred.col_signed, hundred.col_date,
+ tenpct.col_signed, tenpct.col_date
+ from uniques, hundred, tenpct
+ where uniques.col_code = hundred.col_code
+ and uniques.col_code = tenpct.col_code
+ and uniques.col_code = 'BENCHMARKS'",$dbh,$opt_loop_count);
+
+test_query("sel_10pct_ncl",
+ "Time for sel_10pct_ncl",
+ "select col_key, col_int, col_signed, col_code,
+ col_double, col_name
+ from tenpct
+ where col_name = 'THE+ASAP+BENCHMARKS+'",$dbh,$opt_loop_count);
+
+if ($limits->{'subqueries'}){
+ test_query("agg_simple_report",
+ "Time for agg_simple_report",
+ "select avg(updates.col_decim)
+ from updates
+ where updates.col_key in
+ (select updates.col_key
+ from updates, hundred
+ where hundred.col_key = updates.col_key
+ and updates.col_decim > 980000000)",$dbh,$opt_loop_count);
+}else{
+ print "agg_simple_report - Failed\n\n";
+}
+
+test_query("agg_info_retrieval",
+ "Time for agg_info_retrieval",
+ "select count(col_key)
+ from tenpct
+ where col_name = 'THE+ASAP+BENCHMARKS'
+ and col_int <= 100000000
+ and col_signed between 1 and 99999999
+ and not (col_float between -450000000 and 450000000)
+ and col_double > 600000000
+ and col_decim < -600000000",$dbh,$opt_loop_count);
+
+if ($limits->{'views'}){
+ test_query("agg_create_view",
+ "Time for agg_create_view",
+ "create view
+ reportview(col_key,col_signed,col_date,col_decim,
+ col_name,col_code,col_int) as
+ select updates.col_key, updates.col_signed,
+ updates.col_date, updates.col_decim,
+ hundred.col_name, hundred.col_code,
+ hundred.col_int
+ from updates, hundred
+ where updates.col_key = hundred.col_key",$dbh,$opt_loop_count);
+
+ test_query("agg_subtotal_report",
+ "Time for agg_subtotal_report",
+ "select avg(col_signed), min(col_signed), max(col_signed),
+ max(col_date), min(col_date),
+ count(distinct col_name), count(col_name),
+ col_code, col_int
+ from reportview
+ where col_decim >980000000
+ group by col_code, col_int",$dbh,$opt_loop_count);
+
+
+ test_query("agg_total_report",
+ "Time for agg_total_report",
+ "select avg(col_signed), min(col_signed), max(col_signed),
+ max(col_date), min(col_date),
+ count(distinct col_name), count(col_name),
+ count(col_code), count(col_int)
+ from reportview
+ where col_decim >980000000",$dbh,$opt_loop_count);
+}else{
+ print "agg_create_view - Failed\n\n";
+ print "agg_subtotal_report - Failed\n\n";
+ print "agg_total_report - Failed\n\n";
+}
+
+#fix from here
+test_query("join_2_cl",
+ "Time for join_2_cl",
+ "select uniques.col_signed, uniques.col_name,
+ hundred.col_signed, hundred.col_name
+ from uniques, hundred
+ where uniques.col_key = hundred.col_key
+ and uniques.col_key =1000"
+ ,$dbh,$opt_loop_count);
+
+test_query("join_2",
+ "Time for join_2",
+ "select uniques.col_signed, uniques.col_name,
+ hundred.col_signed, hundred.col_name
+ from uniques, hundred
+ where uniques.col_address = hundred.col_address
+ and uniques.col_address = 'SILICON VALLEY'"
+ ,$dbh,$opt_loop_count);
+
+test_query("sel_variable_select_low",
+ "Time for sel_variable_select_low",
+ "select col_key, col_int, col_signed, col_code,
+ col_double, col_name
+ from tenpct
+ where col_signed < -500000000"
+ ,$dbh,$opt_loop_count);
+
+test_query("sel_variable_select_high",
+ "Time for sel_variable_select_high",
+ "select col_key, col_int, col_signed, col_code,
+ col_double, col_name
+ from tenpct
+ where col_signed < -250000000"
+ ,$dbh,$opt_loop_count);
+
+test_query("join_4_cl",
+ "Time for join_4_cl",
+ "select uniques.col_date, hundred.col_date,
+ tenpct.col_date, updates.col_date
+ from uniques, hundred, tenpct, updates
+ where uniques.col_key = hundred.col_key
+ and uniques.col_key = tenpct.col_key
+ and uniques.col_key = updates.col_key
+ and uniques.col_key = 1000"
+ ,$dbh,$opt_loop_count);
+
+test_query("proj_100",
+ "Time for proj_100",
+ "select distinct col_address, col_signed from hundred"
+ ,$dbh,$opt_loop_count);
+
+test_query("join_4_ncl",
+ "Time for join_4_ncl",
+ "select uniques.col_date, hundred.col_date,
+ tenpct.col_date, updates.col_date
+ from uniques, hundred, tenpct, updates
+ where uniques.col_code = hundred.col_code
+ and uniques.col_code = tenpct.col_code
+ and uniques.col_code = updates.col_code
+ and uniques.col_code = 'BENCHMARKS'"
+ ,$dbh,$opt_loop_count);
+
+test_query("proj_10pct",
+ "Time for proj_10pct",
+ "select distinct col_signed from tenpct"
+ ,$dbh,$opt_loop_count);
+
+test_query("sel_1_ncl",
+ "Time for sel_1_ncl",
+ "select col_key, col_int, col_signed, col_code,
+ col_double, col_name
+ from updates where col_code = 'BENCHMARKS'"
+ ,$dbh,$opt_loop_count);
+
+test_query("join_2_ncl",
+ "Time for join_2_ncl",
+ "select uniques.col_signed, uniques.col_name,
+ hundred.col_signed, hundred.col_name
+ from uniques, hundred
+ where uniques.col_code = hundred.col_code
+ and uniques.col_code = 'BENCHMARKS'"
+ ,$dbh,$opt_loop_count);
+
+if ($limits->{'foreign_key'}){
+ do_many($dbh,$server->create("integrity_temp",\@fields,[]));
+
+ test_query("integrity_test_1",
+ "Time for integrity_test",
+ "insert into integrity_temp select *
+ from hundred where col_int=0",$dbh,$opt_loop_count);
+
+ test_query("integrity_test_2",
+ "Time for integrity_test",
+ "update hundred set col_signed = '-500000000'
+ where col_int = 0",$dbh,$opt_loop_count);
+
+ test_query("integrity_test_3",
+ "Time for integrity_test",
+ "update hundred set col_signed = '-500000000'
+ where col_int = 0",$dbh,$opt_loop_count);
+
+
+}else{
+ print "integrity_test - Failed\n\n";
+}
+
+push @drop_seq_command,$server->drop_index("updates","updates_int_bt");
+push @drop_seq_command,$server->drop_index("updates","updates_double_bt");
+push @drop_seq_command,$server->drop_index("updates","updates_decim_bt");
+push @drop_seq_command,$server->drop_index("updates","updates_code_h");
+
+test_many_command("Drop updates keys",
+ "Time for drop_updates_keys",
+ \@drop_seq_command,$dbh,$opt_loop_count);
+
+do_many($dbh,$server->create("saveupdates",\@fields,[]));
+
+test_command("bulk_save",
+ "Time for bulk_save",
+ "insert into saveupdates select *
+ from updates where col_key between 5000 and 5999"
+ ,$dbh,$opt_loop_count);
+
+test_command("bulk_modify",
+ "Time for bulk_modify",
+ "update updates
+ set col_key = col_key - 100000
+ where col_key between 5000 and 5999"
+ ,$dbh,$opt_loop_count);
+
+safe_command("upd_append_duplicate",
+ "Time for upd_append_duplicate",
+ "insert into updates
+ values (6000, 0, 60000, 39997.90,
+ 50005.00, 50005.00,
+ '11/10/1985', 'CONTROLLER',
+ 'ALICE IN WONDERLAND',
+ 'UNIVERSITY OF ILLINOIS AT CHICAGO')"
+ ,$dbh,$opt_loop_count);
+
+test_command("upd_remove_duplicate",
+ "Time for upd_remove_duplicate",
+ "delete from updates where col_key = 6000 and col_int = 0"
+ ,$dbh,$opt_loop_count);
+
+test_command("upd_app_t_mid",
+ "Time for upd_app_t_mid",
+ "insert into updates
+ values (5005, 5005, 50005, 50005.00, 50005.00,
+ 50005.00, '1/1/1988', 'CONTROLLER',
+ 'ALICE IN WONDERLAND',
+ 'UNIVERSITY OF ILLINOIS AT CHICAGO')"
+ ,$dbh,$opt_loop_count);
+
+test_command("upd_mod_t_mid",
+ "Time for upd_mod_t_mid",
+ "update updates set col_key = '-5000'
+ where col_key = 5005"
+ ,$dbh,$opt_loop_count);
+
+test_command("upd_del_t_mid",
+ "Time for upd_del_t_mid",
+ "delete from updates
+ where (col_key='5005') or (col_key='-5000')"
+ ,$dbh,$opt_loop_count);
+
+test_command("upd_app_t_end",
+ "Time for upd_app_t_end",
+ "delete from updates
+ where (col_key='5005') or (col_key='-5000')"
+ ,$dbh,$opt_loop_count);
+
+test_command("upd_mod_t_end",
+ "Time for upd_mod_t_end",
+ "update updates
+ set col_key = -1000
+ where col_key = 1000000001"
+ ,$dbh,$opt_loop_count);
+
+test_command("upd_del_t_end",
+ "Time for upd_del_t_end",
+ "delete from updates where col_key = -1000"
+ ,$dbh,$opt_loop_count);
+
+test_command("create_idx_updates_code_h",
+ "time for create_idx_updates_code_h",
+ "create index updates_code_h on updates (col_code)",
+ $dbh,$opt_loop_count);
+
+test_command("upd_app_t_mid",
+ "Time for upd_app_t_mid",
+ "insert into updates
+ values (5005, 5005, 50005, 50005.00, 50005.00,
+ 50005.00, '1/1/1988', 'CONTROLLER',
+ 'ALICE IN WONDERLAND',
+ 'UNIVERSITY OF ILLINOIS AT CHICAGO')"
+ ,$dbh,$opt_loop_count);
+
+test_command("upd_mod_t_cod",
+ "Time for upd_mod_t_cod",
+ "update updates
+ set col_code = 'SQL+GROUPS'
+ where col_key = 5005"
+ ,$dbh,$opt_loop_count);
+
+test_command("upd_del_t_mid",
+ "Time for upd_del_t_mid",
+ "delete from updates
+ where (col_key='5005') or (col_key='-5000')"
+ ,$dbh,$opt_loop_count);
+
+test_command("create_idx_updates_int_bt",
+ "time for create_idx_updates_int_bt",
+ "create index updates_int_bt on updates (col_int)",
+ $dbh,$opt_loop_count);
+
+test_command("upd_app_t_mid",
+ "Time for upd_app_t_mid",
+ "insert into updates
+ values (5005, 5005, 50005, 50005.00, 50005.00,
+ 50005.00, '1/1/1988', 'CONTROLLER',
+ 'ALICE IN WONDERLAND',
+ 'UNIVERSITY OF ILLINOIS AT CHICAGO')"
+ ,$dbh,$opt_loop_count);
+
+test_command("upd_mod_t_int",
+ "Time for upd_mod_t_int",
+ "update updates set col_int = 50015 where col_key = 5005"
+ ,$dbh,$opt_loop_count);
+
+test_command("upd_del_t_mid",
+ "Time for upd_del_t_mid",
+ "delete from updates
+ where (col_key='5005') or (col_key='-5000')"
+ ,$dbh,$opt_loop_count);
+
+test_command("bulk_append",
+ "Time for bulk_append",
+ "insert into updates select * from saveupdates"
+ ,$dbh,$opt_loop_count);
+
+test_command("bulk_delete",
+ "Time for bulk_delete",
+ "delete from updates where col_key < 0"
+ ,$dbh,$opt_loop_count);
+
+################################ END ###################################
+####
+#### End of the test...Finally print time used to execute the
+#### whole test.
+
+$dbh->disconnect;
+
+end_benchmark($start_time);
+
+############################ HELP FUNCTIONS ##############################
+
+sub test_query
+{
+ my($test_text,$result_text,$query,$dbh,$count)=@_;
+ my($i,$loop_time,$end_time);
+
+ print $test_text . "\n";
+ $loop_time=new Benchmark;
+ for ($i=0 ; $i < $count ; $i++)
+ {
+ defined(fetch_all_rows($dbh,$query)) or warn $DBI::errstr;
+ }
+ $end_time=new Benchmark;
+ print $result_text . "($count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+}
+
+
+sub test_command
+{
+ my($test_text,$result_text,$query,$dbh,$count)=@_;
+ my($i,$loop_time,$end_time);
+
+ print $test_text . "\n";
+ $loop_time=new Benchmark;
+ for ($i=0 ; $i < $count ; $i++)
+ {
+ $dbh->do($query) or die $DBI::errstr;
+ }
+ $end_time=new Benchmark;
+ print $result_text . "($count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+}
+
+sub safe_command
+{
+ my($test_text,$result_text,$query,$dbh,$count)=@_;
+ my($i,$loop_time,$end_time);
+
+ print $test_text . "\n";
+ $loop_time=new Benchmark;
+ for ($i=0 ; $i < $count ; $i++)
+ {
+ safe_do_many($dbh,$query);
+ }
+ $end_time=new Benchmark;
+ print $result_text . "($count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+}
+
+sub test_many_command
+{
+ my($test_text,$result_text,$query,$dbh,$count)=@_;
+ my($i,$loop_time,$end_time);
+
+ $loop_time=new Benchmark;
+ for ($i=0 ; $i < $count ; $i++)
+ {
+ safe_do_many($dbh, @$query);
+ }
+ $end_time=new Benchmark;
+ print $result_text . "($count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+}
+
+
diff --git a/sql-bench/bench-count-distinct.sh b/sql-bench/bench-count-distinct.sh
new file mode 100644
index 00000000000..1359a864ac1
--- /dev/null
+++ b/sql-bench/bench-count-distinct.sh
@@ -0,0 +1,258 @@
+#!@PERL@
+# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#
+# 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
+#
+# Test of selecting on keys that consist of many parts
+#
+##################### Standard benchmark inits ##############################
+
+use DBI;
+use Getopt::Long;
+use Benchmark;
+
+$opt_loop_count=10000;
+$opt_medium_loop_count=200;
+$opt_small_loop_count=10;
+$opt_regions=6;
+$opt_groups=100;
+
+chomp($pwd = `pwd`); $pwd = "." if ($pwd eq '');
+require "$pwd/bench-init.pl" || die "Can't read Configuration file: $!\n";
+
+$columns=min($limits->{'max_columns'},500,($limits->{'query_size'}-50)/24,
+ $limits->{'max_conditions'}/2-3);
+
+if ($opt_small_test)
+{
+ $opt_loop_count/=10;
+ $opt_medium_loop_count/=10;
+ $opt_small_loop_count/=10;
+ $opt_groups/=10;
+}
+
+print "Testing the speed of selecting on keys that consist of many parts\n";
+print "The test-table has $opt_loop_count rows and the test is done with $columns ranges.\n\n";
+
+####
+#### Connect and start timeing
+####
+
+$dbh = $server->connect();
+$start_time=new Benchmark;
+
+####
+#### Create needed tables
+####
+
+goto select_test if ($opt_skip_create);
+
+print "Creating table\n";
+$dbh->do("drop table bench1" . $server->{'drop_attr'});
+
+do_many($dbh,$server->create("bench1",
+ ["region char(1) NOT NULL",
+ "idn integer(6) NOT NULL",
+ "rev_idn integer(6) NOT NULL",
+ "grp integer(6) NOT NULL"],
+ ["primary key (region,idn)",
+ "unique (region,rev_idn)",
+ "unique (region,grp,idn)"]));
+if ($opt_lock_tables)
+{
+ do_query($dbh,"LOCK TABLES bench1 WRITE");
+}
+
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(1,\$dbh);
+}
+
+####
+#### Insert $opt_loop_count records with
+#### region: "A" -> "E"
+#### idn: 0 -> count
+#### rev_idn: count -> 0,
+#### grp: distributed values 0 - > count/100
+####
+
+print "Inserting $opt_loop_count rows\n";
+
+$loop_time=new Benchmark;
+$query="insert into bench1 values (";
+$half_done=$opt_loop_count/2;
+for ($id=0,$rev_id=$opt_loop_count-1 ; $id < $opt_loop_count ; $id++,$rev_id--)
+{
+ $grp=$id*3 % $opt_groups;
+ $region=chr(65+$id%$opt_regions);
+ do_query($dbh,"$query'$region',$id,$rev_id,$grp)");
+ if ($id == $half_done)
+ { # Test with different insert
+ $query="insert into bench1 (region,idn,rev_idn,grp) values (";
+ }
+}
+
+$end_time=new Benchmark;
+print "Time to insert ($opt_loop_count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+
+if ($opt_lock_tables)
+{
+ do_query($dbh,"UNLOCK TABLES");
+}
+
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(0,\$dbh,"bench1");
+}
+
+if ($opt_lock_tables)
+{
+ do_query($dbh,"LOCK TABLES bench1 WRITE");
+}
+
+####
+#### Do some selects on the table
+####
+
+select_test:
+
+
+
+if ($limits->{'group_distinct_functions'})
+{
+ print "Testing count(distinct) on the table\n";
+ $loop_time=new Benchmark;
+ $rows=$estimated=$count=0;
+ for ($i=0 ; $i < $opt_medium_loop_count ; $i++)
+ {
+ $count++;
+ $rows+=fetch_all_rows($dbh,"select count(distinct region) from bench1");
+ $end_time=new Benchmark;
+ last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$i+1,
+ $opt_medium_loop_count));
+ }
+ print_time($estimated);
+ print " for count_distinct_key_prefix ($count:$rows): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+ $loop_time=new Benchmark;
+ $rows=$estimated=$count=0;
+ for ($i=0 ; $i < $opt_medium_loop_count ; $i++)
+ {
+ $count++;
+ $rows+=fetch_all_rows($dbh,"select count(distinct grp) from bench1");
+ $end_time=new Benchmark;
+ last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$i+1,
+ $opt_medium_loop_count));
+ }
+ print_time($estimated);
+ print " for count_distinct ($count:$rows): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+ $loop_time=new Benchmark;
+ $rows=$estimated=$count=0;
+ for ($i=0 ; $i < $opt_medium_loop_count ; $i++)
+ {
+ $count++;
+ $rows+=fetch_all_rows($dbh,"select count(distinct grp),count(distinct rev_idn) from bench1");
+ $end_time=new Benchmark;
+ last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$i+1,
+ $opt_medium_loop_count));
+ }
+ print_time($estimated);
+ print " for count_distinct_2 ($count:$rows): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+ $loop_time=new Benchmark;
+ $rows=$estimated=$count=0;
+ for ($i=0 ; $i < $opt_medium_loop_count ; $i++)
+ {
+ $count++;
+ $rows+=fetch_all_rows($dbh,"select region,count(distinct idn) from bench1 group by region");
+ $end_time=new Benchmark;
+ last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$i+1,
+ $opt_medium_loop_count));
+ }
+ print_time($estimated);
+ print " for count_distinct_group_on_key ($count:$rows): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+ $loop_time=new Benchmark;
+ $rows=$estimated=$count=0;
+ for ($i=0 ; $i < $opt_medium_loop_count ; $i++)
+ {
+ $count++;
+ $rows+=fetch_all_rows($dbh,"select grp,count(distinct idn) from bench1 group by grp");
+ $end_time=new Benchmark;
+ last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$i+1,
+ $opt_medium_loop_count));
+ }
+ print_time($estimated);
+ print " for count_distinct_group_on_key_parts ($count:$rows): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+ $loop_time=new Benchmark;
+ $rows=$estimated=$count=0;
+ for ($i=0 ; $i < $opt_medium_loop_count ; $i++)
+ {
+ $count++;
+ $rows+=fetch_all_rows($dbh,"select grp,count(distinct rev_idn) from bench1 group by grp");
+ $end_time=new Benchmark;
+ last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$i+1,
+ $opt_medium_loop_count));
+ }
+ print_time($estimated);
+ print " for count_distinct_group ($count:$rows): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+ $loop_time=new Benchmark;
+ $rows=$estimated=$count=0;
+ $test_count=$opt_medium_loop_count/10;
+ for ($i=0 ; $i < $test_count ; $i++)
+ {
+ $count++;
+ $rows+=fetch_all_rows($dbh,"select idn,count(distinct region) from bench1 group by idn");
+ $end_time=new Benchmark;
+ last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$i+1,
+ $test_count));
+ }
+ print_time($estimated);
+ print " for count_distinct_big ($count:$rows): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+}
+
+####
+#### End of benchmark
+####
+
+if ($opt_lock_tables)
+{
+ do_query($dbh,"UNLOCK TABLES");
+}
+if (!$opt_skip_delete)
+{
+ do_query($dbh,"drop table bench1" . $server->{'drop_attr'});
+}
+
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(0,\$dbh);
+}
+
+$dbh->disconnect; # close connection
+
+end_benchmark($start_time);
diff --git a/sql-bench/bench-init.pl.sh b/sql-bench/bench-init.pl.sh
index 204d15d7ab3..4e7e1c29504 100644
--- a/sql-bench/bench-init.pl.sh
+++ b/sql-bench/bench-init.pl.sh
@@ -38,24 +38,28 @@ require "$pwd/server-cfg" || die "Can't read Configuration file: $!\n";
$|=1; # Output data immediately
-$opt_skip_test=$opt_skip_create=$opt_skip_delete=$opt_verbose=$opt_fast_insert=$opt_lock_tables=$opt_debug=$opt_skip_delete=$opt_fast=$opt_force=$opt_log=$opt_use_old_results=$opt_help=$opt_odbc=$opt_small_test=$opt_small_tables=$opt_samll_key_tables=$opt_stage=$opt_old_headers=$opt_die_on_errors=$opt_tcpip=0;
+$opt_skip_test=$opt_skip_create=$opt_skip_delete=$opt_verbose=$opt_fast_insert=$opt_lock_tables=$opt_debug=$opt_skip_delete=$opt_fast=$opt_force=$opt_log=$opt_use_old_results=$opt_help=$opt_odbc=$opt_small_test=$opt_small_tables=$opt_samll_key_tables=$opt_stage=$opt_old_headers=$opt_die_on_errors=$opt_tcpip=$opt_random=0;
$opt_cmp=$opt_user=$opt_password="";
$opt_server="mysql"; $opt_dir="output";
$opt_host="localhost";$opt_database="test";
$opt_machine=""; $opt_suffix="";
$opt_create_options=undef;
+$opt_optimization="None";
+$opt_hw="";
+$opt_threads=5;
$opt_time_limit=10*60; # Don't wait more than 10 min for some tests
$log_prog_args=join(" ", skip_arguments(\@ARGV,"comments","cmp","server",
"user", "host", "database", "password",
"use-old-results","skip-test",
+ "optimization","hw",
"machine", "dir", "suffix", "log"));
-GetOptions("skip-test=s","comments=s","cmp=s","server=s","user=s","host=s","database=s","password=s","loop-count=i","row-count=i","skip-create","skip-delete","verbose","fast-insert","lock-tables","debug","fast","force","field-count=i","regions=i","groups=i","time-limit=i","log","use-old-results","machine=s","dir=s","suffix=s","help","odbc","small-test","small-tables","small-key-tables","stage=i","old-headers","die-on-errors","create-options=s","hires","tcpip","silent") || usage();
+GetOptions("skip-test=s","comments=s","cmp=s","server=s","user=s","host=s","database=s","password=s","loop-count=i","row-count=i","skip-create","skip-delete","verbose","fast-insert","lock-tables","debug","fast","force","field-count=i","regions=i","groups=i","time-limit=i","log","use-old-results","machine=s","dir=s","suffix=s","help","odbc","small-test","small-tables","small-key-tables","stage=i","threads=i","random","old-headers","die-on-errors","create-options=s","hires","tcpip","silent","optimization=s","hw=s","socket=s") || usage();
usage() if ($opt_help);
$server=get_server($opt_server,$opt_host,$opt_database,$opt_odbc,
- machine_part());
+ machine_part(), $opt_socket);
$limits=merge_limits($server,$opt_cmp);
$date=date();
@estimated=(0.0,0.0,0.0); # For estimated time support
@@ -515,6 +519,10 @@ All benchmarks takes the following options:
--password='password'
Password for the current user.
+--socket='socket'
+ If the database supports connecting through a Unix socket,
+ use this socket to connect
+
--regions
This is a test specific option that is only used when debugging a test.
This usually means how AND levels should be tested.
@@ -553,6 +561,13 @@ All benchmarks takes the following options:
different server options without overwritten old files.
When using --fast the suffix is automaticly set to '_fast'.
+--random
+ Inform test suite that we are generate random inital values for sequence of
+ test executions. It should be used for imitation of real conditions.
+
+--threads=# (Default 5)
+ Number of threads for multi-user benchmarks.
+
--tcpip
Inform test suite that we are using TCP/IP to connect to the server. In
this case we can\t do many new connections in a row as we in this case may
@@ -572,6 +587,13 @@ All benchmarks takes the following options:
--verbose
This is a test specific option that is only used when debugging a test.
Print more information about what is going on.
+
+--optimization='some comments'
+ Add coments about optimization of DBMS, which was done before the test.
+
+--hw='some comments'
+ Add coments about hardware used for this test.
+
EOF
exit(0);
}
diff --git a/sql-bench/crash-me.sh b/sql-bench/crash-me.sh
index f6985adc5c0..9572143ae53 100644
--- a/sql-bench/crash-me.sh
+++ b/sql-bench/crash-me.sh
@@ -143,7 +143,15 @@ $longreadlen=16000000; # For retrieval buffer
#
use sigtrap; # Must be removed with perl5.005_2 on Win98
$SIG{PIPE} = 'IGNORE';
-$SIG{SEGV} = sub {warn('SEGFAULT')};
+$problem_counter=0;
+$SIG{SEGV} = sub {
+ $problem_counter +=1;
+ if ($problem_counter >= 100) {
+ die("Too many problems, try to restart");
+ } else {
+ warn('SEGFAULT');
+ };
+};
$dbh=safe_connect();
#
@@ -252,6 +260,8 @@ report("Functions",'functions',"select 1+1 $end_query");
report("Group functions",'group_functions',"select count(*) from crash_me");
report("Group functions with distinct",'group_distinct_functions',
"select count(distinct a) from crash_me");
+report("Group functions with several distinct",'group_many_distinct_functions',
+ "select count(distinct a), count(distinct b) from crash_me");
report("Group by",'group_by',"select a from crash_me group by a");
report("Group by position",'group_by_position',
"select a from crash_me group by 1");
@@ -1438,6 +1448,14 @@ if (!report("case independent table names","table_name_case",
safe_query("drop table crash_q $drop_attr");
}
+if (!report("case independent field names","field_name_case",
+ "create table crash_q (q integer)",
+ "insert into crash_q(Q) values (1)",
+ "drop table crash_q $drop_attr"))
+{
+ safe_query("drop table crash_q $drop_attr");
+}
+
if (!report("drop table if exists","drop_if_exists",
"create table crash_q (q integer)",
"drop table if exists crash_q $drop_attr"))
@@ -2450,6 +2468,7 @@ sub report
print "$prompt: ";
if (!defined($limits{$limit}))
{
+ save_config_data($limit,"incompleted",$prompt);
save_config_data($limit,safe_query(\@queries) ? "yes" : "no",$prompt);
}
print "$limits{$limit}\n";
@@ -2462,6 +2481,7 @@ sub report_fail
print "$prompt: ";
if (!defined($limits{$limit}))
{
+ save_config_data($limit,"incompleted",$prompt);
save_config_data($limit,safe_query(\@queries) ? "no" : "yes",$prompt);
}
print "$limits{$limit}\n";
@@ -2478,6 +2498,7 @@ sub report_one
print "$prompt: ";
if (!defined($limits{$limit}))
{
+ save_config_data($limit,"incompleted",$prompt);
$result="no";
foreach $query (@$queries)
{
@@ -2503,6 +2524,7 @@ sub report_result
print "$prompt: ";
if (!defined($limits{$limit}))
{
+ save_config_data($limit,"incompleted",$prompt);
$error=safe_query_result($query,"1",2);
save_config_data($limit,$error ? "not supported" : $last_result,$prompt);
}
@@ -2515,6 +2537,7 @@ sub report_trans
my ($limit,$queries,$check,$clear)=@_;
if (!defined($limits{$limit}))
{
+ save_config_data($limit,"incompleted",$prompt);
eval {undef($dbh->{AutoCommit})};
if (!$@)
{
@@ -2524,21 +2547,21 @@ sub report_trans
if ($rc) {
$dbh->{AutoCommit} = 1;
if (safe_query_result($check,"","")) {
- save_config_data($limit,"yes",$prompt);
+ save_config_data($limit,"yes",$limit);
}
safe_query($clear);
} else {
$dbh->{AutoCommit} = 1;
- save_config_data($limit,"error",$prompt);
+ save_config_data($limit,"error",$limit);
}
} else {
- save_config_data($limit,"error",$prompt);
+ save_config_data($limit,"error",$limit);
}
$dbh->{AutoCommit} = 1;
}
else
{
- save_config_data($limit,"no",$prompt);
+ save_config_data($limit,"no",$limit);
}
safe_query($clear);
}
@@ -2556,9 +2579,11 @@ sub check_and_report
print "$prompt: " if (!defined($skip_prompt));
if (!defined($limits{$limit}))
{
+ save_config_data($limit,"incompleted",$prompt);
$tmp=1-safe_query(\@$pre);
$tmp=safe_query_result($query,$answer,$string_type) if (!$tmp);
safe_query(\@$post);
+ delete $limits{$limit};
if ($function == 3) # Report error as 'no'.
{
$function=0;
@@ -2587,8 +2612,10 @@ sub try_and_report
my ($tmp,$test,$type);
print "$prompt: ";
+
if (!defined($limits{$limit}))
{
+ save_config_data($limit,"incompleted",$prompt);
$type="no"; # Not supported
foreach $test (@tests)
{
@@ -2699,7 +2726,7 @@ sub safe_query_result
elsif ($result_type == 5) # Result should have given prefix
{
$result= -1 if (length($row->[0]) < length($answer) &&
- substring($row->[0],1,length($answer)) ne $answer);
+ substr($row->[0],1,length($answer)) ne $answer);
}
elsif ($result_type == 6) # Exact match but ignore errors
{
@@ -2760,6 +2787,8 @@ sub find_limit()
print "$end (cache)\n";
return $end;
}
+ save_config_data($limit,"incompleted",$prompt);
+
if (defined($query->{'init'}) && !defined($end=$limits{'restart'}{'tohigh'}))
{
if (!safe_query($query->{'init'}))
diff --git a/sql-bench/limits/db2.cfg b/sql-bench/limits/db2.cfg
index 31280fbe643..5b2c0e172e7 100644
--- a/sql-bench/limits/db2.cfg
+++ b/sql-bench/limits/db2.cfg
@@ -1,34 +1,68 @@
-#This file is automaticly generated by crash-me 1.19a
+#This file is automaticly generated by crash-me 1.57
NEG=yes # update of column= -column
+Need_cast_for_null=no # Need to cast NULL for arithmetic
alter_add_col=yes # Alter table add column
+alter_add_constraint=yes # Alter table add constraint
+alter_add_foreign_key=yes # Alter table add foreign key
+alter_add_multi_col=no # Alter table add many columns
+alter_add_primary_key=with constraint # Alter table add primary key
+alter_add_unique=no # Alter table add unique
+alter_alter_col=no # Alter table alter column default
alter_change_col=no # Alter table change column
alter_drop_col=no # Alter table drop column
+alter_drop_constraint=yes # Alter table drop constraint
+alter_drop_foreign_key=with drop constraint # Alter table drop foreign key
+alter_drop_primary_key=drop primary key # Alter table drop primary key
+alter_drop_unique=no # Alter table drop unique
alter_modify_col=no # Alter table modify column
alter_rename_table=no # Alter table rename table
atomic_updates=yes # atomic updates
atomic_updates_with_rollback=yes # atomic_updates_with_rollback
-binary_items=no # binary items (0x41)
-case_insensitive_strings=no # case insensitive compare
-char_is_space_filled=no # char are space filled
+automatic_rowid=no # Automatic row id
+binary_numbers=no # binary numbers (0b1001)
+binary_strings=no # binary strings (b'0110')
+case_insensitive_strings=no # Case insensitive compare
+char_is_space_filled=yes # char are space filled
column_alias=yes # Column alias
+columns_in_group_by=+64 # number of columns in group by
+columns_in_order_by=+64 # number of columns in order by
comment_#=no # # as comment
-comment_--=yes # -- as comment
+comment_--=yes # -- as comment (ANSI)
comment_/**/=no # /* */ as comment
+comment_//=no # // as comment
compute=no # Compute
-connections=125 # Simultaneous connections
+connections=40 # Simultaneous connections (installation default)
+constraint_check=yes # Column constraints
+constraint_check_table=yes # Table constraints
+constraint_null=no # NULL constraint (SyBase style)
crash_me_safe=no # crash me safe
-crash_me_version=1.19a # crash me version
+crash_me_version=1.57 # crash me version
create_default=yes # default value for column
+create_default_func=no # default value function for column
+create_if_not_exists=no # create table if not exists
create_index=yes # create index
+create_schema=no # Create SCHEMA
+create_table_select=no # create table from select
cross_join=no # cross join (same as from a,b)
date_as_string=no # String functions on date columns
+date_infinity=no # Supports 'infinity dates
+date_last=no # Supports 9999-12-31 dates
+date_one=no # Supports 0001-01-01 dates
date_with_YY=no # Supports YY-MM-DD dates
date_zero=no # Supports 0000-00-00 dates
+domains=no # Domains (ANSI SQL)
+dont_require_cast_to_float=yes # No need to cast from integer to float
double_quotes=yes # Double '' as ' in strings
+drop_if_exists=no # drop table if exists
drop_index=yes # drop index
+drop_requires_cascade=no # drop table require cascade/restrict
+drop_restrict=no # drop table with cascade/restrict
+end_colon=yes # allows end ';'
except=yes # except
except_all=yes # except all
+except_all_incompat=no # except all (incompatible lists)
+except_incompat=no # except (incompatible lists)
float_int_expr=yes # mixing of integer and float in expression
foreign_key=yes # foreign keys
foreign_key_syntax=yes # foreign key syntax
@@ -41,6 +75,8 @@ func_extra_<>=no # Function <> in SELECT
func_extra_==no # Function =
func_extra_add_months=no # Function ADD_MONTHS
func_extra_and_or=no # Function AND and OR in SELECT
+func_extra_ascii_char=no # Function ASCII_CHAR
+func_extra_ascii_code=no # Function ASCII_CODE
func_extra_atn2=no # Function ATN2
func_extra_auto_num2string=no # Function automatic num->string convert
func_extra_auto_string2num=no # Function automatic string->num convert
@@ -72,6 +108,7 @@ func_extra_in_num=no # Function IN on numbers in SELECT
func_extra_in_str=no # Function IN on strings in SELECT
func_extra_initcap=no # Function INITCAP
func_extra_instr=no # Function LOCATE as INSTR
+func_extra_instr_oracle=no # Function INSTR (Oracle syntax)
func_extra_instrb=no # Function INSTRB
func_extra_interval=no # Function INTERVAL
func_extra_last_day=no # Function LAST_DAY
@@ -84,16 +121,15 @@ func_extra_ln=yes # Function LN
func_extra_log(m_n)=no # Function LOG(m,n)
func_extra_logn=no # Function LOGN
func_extra_lpad=no # Function LPAD
-func_extra_max_num=no # Function MAX on numbers
func_extra_mdy=no # Function MDY
func_extra_mid=no # Function SUBSTRING as MID
-func_extra_min_num=no # Function MIN on numbers
func_extra_months_between=no # Function MONTHS_BETWEEN
func_extra_not=no # Function NOT in SELECT
func_extra_not_between=no # Function NOT BETWEEN in SELECT
func_extra_not_like=no # Function NOT LIKE in SELECT
func_extra_odbc_convert=no # Function ODBC CONVERT
func_extra_password=no # Function PASSWORD
+func_extra_paste=no # Function PASTE
func_extra_patindex=no # Function PATINDEX
func_extra_period_add=no # Function PERIOD_ADD
func_extra_period_diff=no # Function PERIOD_DIFF
@@ -112,6 +148,8 @@ func_extra_strcmp=no # Function STRCMP
func_extra_stuff=no # Function STUFF
func_extra_substrb=no # Function SUBSTRB
func_extra_substring_index=no # Function SUBSTRING_INDEX
+func_extra_sysdate=no # Function SYSDATE
+func_extra_tail=no # Function TAIL
func_extra_tanh=no # Function TANH
func_extra_time_to_sec=no # Function TIME_TO_SEC
func_extra_to_days=no # Function TO_DAYS
@@ -126,6 +164,7 @@ func_extra_version=no # Function VERSION
func_extra_weekday=no # Function WEEKDAY
func_extra_|=no # Function | (bitwise or)
func_extra_||=no # Function OR as '||'
+func_extra_~*=no # Function ~* (case insensitive compare)
func_odbc_abs=yes # Function ABS
func_odbc_acos=yes # Function ACOS
func_odbc_ascii=yes # Function ASCII
@@ -133,31 +172,30 @@ func_odbc_asin=yes # Function ASIN
func_odbc_atan=yes # Function ATAN
func_odbc_atan2=error # Function ATAN2
func_odbc_ceiling=yes # Function CEILING
-func_odbc_char=error # Function CHAR
+func_odbc_char=yes # Function CHAR
func_odbc_concat=yes # Function CONCAT(2 arg)
func_odbc_cos=yes # Function COS
func_odbc_cot=yes # Function COT
-func_odbc_curdate=no # Function CURDATE
-func_odbc_curtime=no # Function CURTIME
-func_odbc_database=no # Function DATABASE
-func_odbc_dayname=no # Function DAYNAME
-func_odbc_dayofmonth=no # Function DAYOFMONTH
-func_odbc_dayofweek=no # Function DAYOFWEEK
-func_odbc_dayofyear=no # Function DAYOFYEAR
+func_odbc_curdate=yes # Function CURDATE
+func_odbc_curtime=yes # Function CURTIME
+func_odbc_database=yes # Function DATABASE
+func_odbc_dayname=yes # Function DAYNAME
+func_odbc_dayofmonth=yes # Function DAYOFMONTH
+func_odbc_dayofweek=yes # Function DAYOFWEEK
+func_odbc_dayofyear=yes # Function DAYOFYEAR
func_odbc_degrees=yes # Function DEGREES
func_odbc_difference=yes # Function DIFFERENCE()
func_odbc_exp=yes # Function EXP
-func_odbc_extract=no # Function EXTRACT
func_odbc_floor=yes # Function FLOOR
func_odbc_fn_left=yes # Function ODBC syntax LEFT & RIGHT
func_odbc_hour=yes # Function HOUR
-func_odbc_hour_time=no # Function ANSI HOUR
-func_odbc_ifnull=no # Function IFNULL
+func_odbc_hour_time=yes # Function ANSI HOUR
+func_odbc_ifnull=yes # Function IFNULL
func_odbc_insert=yes # Function INSERT
func_odbc_lcase=yes # Function LCASE
func_odbc_left=yes # Function LEFT
func_odbc_length=yes # Function REAL LENGTH
-func_odbc_length_without_space=error # Function ODBC LENGTH
+func_odbc_length_without_space=yes # Function ODBC LENGTH
func_odbc_locate_2=yes # Function LOCATE(2 arg)
func_odbc_locate_3=yes # Function LOCATE(3 arg)
func_odbc_log=yes # Function LOG
@@ -165,12 +203,12 @@ func_odbc_log10=yes # Function LOG10
func_odbc_ltrim=yes # Function LTRIM
func_odbc_minute=yes # Function MINUTE
func_odbc_mod=yes # Function MOD
-func_odbc_month=no # Function MONTH
-func_odbc_monthname=no # Function MONTHNAME
-func_odbc_now=no # Function NOW
-func_odbc_pi=no # Function PI
+func_odbc_month=yes # Function MONTH
+func_odbc_monthname=yes # Function MONTHNAME
+func_odbc_now=yes # Function NOW
+func_odbc_pi=yes # Function PI
func_odbc_power=yes # Function POWER
-func_odbc_quarter=no # Function QUARTER
+func_odbc_quarter=yes # Function QUARTER
func_odbc_radians=yes # Function RADIANS
func_odbc_rand=yes # Function RAND
func_odbc_repeat=yes # Function REPEAT
@@ -184,38 +222,43 @@ func_odbc_sin=yes # Function SIN
func_odbc_soundex=yes # Function SOUNDEX
func_odbc_space=yes # Function SPACE
func_odbc_sqrt=yes # Function SQRT
-func_odbc_substring=no # Function ODBC SUBSTRING
+func_odbc_substring=yes # Function ODBC SUBSTRING
func_odbc_tan=yes # Function TAN
func_odbc_timestampadd=no # Function TIMESTAMPADD
func_odbc_timestampdiff=no # Function TIMESTAMPDIFF
func_odbc_truncate=yes # Function TRUNCATE
-func_odbc_ucase=no # Function UCASE
-func_odbc_user=yes # Function USER
-func_odbc_user()=no # Function USER()
-func_odbc_week=no # Function WEEK
-func_odbc_year=no # Function YEAR
+func_odbc_ucase=yes # Function UCASE
+func_odbc_user()=yes # Function USER()
+func_odbc_week=yes # Function WEEK
+func_odbc_year=yes # Function YEAR
func_sql_+=yes # Function +, -, * and /
func_sql_bit_length=no # Function BIT_LENGTH
-func_sql_case=yes # Function CASE
func_sql_cast=yes # Function CAST
func_sql_char_length=no # Function CHAR_LENGTH
+func_sql_char_length(constant)=no # Function CHAR_LENGTH(constant)
func_sql_character_length=no # Function CHARACTER_LENGTH
+func_sql_coalesce=no # Function COALESCE
func_sql_concat_as_||=yes # Function concatenation with ||
func_sql_current_date=no # Function CURRENT_DATE
-func_sql_current_date()=no # Function CURRENT_DATE()
func_sql_current_time=no # Function CURRENT_TIME
-func_sql_current_time()=no # Function CURRENT_TIME()
func_sql_current_timestamp=no # Function CURRENT_TIMESTAMP
-func_sql_current_timestamp()=no # Function CURRENT_TIMESTAMP()
-func_sql_lower=no # Function LOWER
+func_sql_current_user=no # Function CURRENT_USER
+func_sql_extract_sql=no # Function EXTRACT
+func_sql_localtime=no # Function LOCALTIME
+func_sql_localtimestamp=no # Function LOCALTIMESTAMP
+func_sql_lower=yes # Function LOWER
+func_sql_nullif_num=yes # Function NULLIF with numbers
+func_sql_nullif_string=yes # Function NULLIF with strings
func_sql_octet_length=no # Function OCTET_LENGTH
func_sql_position=no # Function POSITION
+func_sql_searched_case=yes # Function searched CASE
func_sql_session_user=no # Function SESSION_USER
+func_sql_simple_case=yes # Function simple CASE
func_sql_substring=no # Function ANSI SQL SUBSTRING
-func_extra_sysdate=no # Function SYSDATE
func_sql_system_user=no # Function SYSTEM_USER
func_sql_trim=no # Function TRIM
-func_sql_upper=no # Function UPPER
+func_sql_upper=yes # Function UPPER
+func_sql_user=yes # Function USER
func_where_between=yes # Function BETWEEN
func_where_eq_all=yes # Function = ALL
func_where_eq_any=yes # Function = ANY
@@ -235,36 +278,49 @@ func_where_unique=no # Function UNIQUE
functions=yes # Functions
group_by=yes # Group by
group_by_alias=no # Group by alias
-group_by_null=yes # Test nulls in group by
+group_by_null=yes # Group on column with null values
group_by_position=no # Group by position
group_distinct_functions=yes # Group functions with distinct
group_func_extra_bit_and=no # Group function BIT_AND
group_func_extra_bit_or=no # Group function BIT_OR
+group_func_extra_count_distinct_list=no # Group function COUNT(DISTINCT expr,expr,...)
group_func_extra_std=no # Group function STD
group_func_extra_stddev=yes # Group function STDDEV
group_func_extra_variance=yes # Group function VARIANCE
+group_func_sql_any=no # Group function ANY
group_func_sql_avg=yes # Group function AVG
group_func_sql_count_*=yes # Group function COUNT (*)
group_func_sql_count_column=yes # Group function COUNT column name
-group_func_sql_count_distinct=yes # Group function COUNT DISTINCT column name
+group_func_sql_count_distinct=yes # Group function COUNT(DISTINCT expr)
+group_func_sql_every=no # Group function EVERY
group_func_sql_max=yes # Group function MAX on numbers
group_func_sql_max_str=yes # Group function MAX on strings
group_func_sql_min=yes # Group function MIN on numbers
group_func_sql_min_str=yes # Group function MIN on strings
+group_func_sql_some=no # Group function SOME
group_func_sql_sum=yes # Group function SUM
group_functions=yes # Group functions
+group_on_unused=yes # Group on unused column
+has_true_false=no # TRUE and FALSE
having=yes # Having
having_with_alias=no # Having on alias
having_with_group=yes # Having with group function
-ignore_end_space=yes # ignore end space in compare
+hex_numbers=no # hex numbers (0x41)
+hex_strings=yes # hex strings (x'1ace')
+ignore_end_space=yes # Ignore end space in compare
index_in_create=no # index in create table
index_namespace=no # different namespace for index
index_parts=no # index on column part (extension)
+inner_join=yes # inner join
insert_empty_string=yes # insert empty string
+insert_multi_value=yes # INSERT with Value lists
insert_select=yes # insert INTO ... SELECT ...
+insert_with_set=no # INSERT with set syntax
intersect=yes # intersect
intersect_all=yes # intersect all
-join_tables=+64 # tables in join
+intersect_all_incompat=no # intersect all (incompatible lists)
+intersect_incompat=no # intersect (incompatible lists)
+join_tables=10 # tables in join
left_outer_join=yes # left outer join
left_outer_join_using=no # left outer join using
like_with_column=no # column LIKE column
@@ -273,150 +329,194 @@ lock_tables=yes # lock table
logical_value=not supported # Value of logical operation (1=1)
max_big_expressions=1 # big expressions
max_char_size=254 # max char() size
-max_column_name=18 # column name length
+max_column_name=30 # column name length
max_columns=500 # Columns in table
-max_conditions=418 # OR and AND in WHERE
-max_expressions=9820 # simple expressions
+max_conditions=2082 # OR and AND in WHERE
+max_expressions=9543 # simple expressions
max_index=+64 # max index
-max_index_length=255 # index length
+max_index_length=1024 # index length
max_index_name=18 # index name length
max_index_part_length=254 # max index part length
-max_index_parts=15 # index parts
-max_index_varchar_part_length=251 # index varchar part length
+max_index_parts=16 # index parts
+max_index_varchar_part_length=255 # index varchar part length
max_row_length=4005 # max table row length (without blobs)
max_row_length_with_null=3989 # table row length with nulls (without blobs)
-max_select_alias_name=18 # select alias name length
+max_select_alias_name=30 # select alias name length
max_stack_expression=1363 # stacked expressions
-max_table_alias_name=18 # table alias name length
-max_table_name=18 # table name length
+max_table_alias_name=128 # table alias name length
+max_table_name=128 # table name length
max_unique_index=+64 # unique indexes
max_varchar_size=4000 # max varchar() size
minus=no # minus
+minus_incompat=no # minus (incompatible lists)
minus_neg=no # Calculate 1--1
multi_drop=no # many tables to drop table
multi_strings=no # Multiple line strings
multi_table_delete=no # DELETE FROM table1,table2...
multi_table_update=no # Update with many tables
natural_join=no # natural join
+natural_join_incompat=no # natural join (incompatible lists)
natural_left_outer_join=no # natural left outer join
no_primary_key=yes # Tables without primary key
null_concat_expr=no # Is 'a' || NULL = NULL
null_in_index=yes # null in index
-null_in_unique=no # null in unique
+null_in_unique=no # null in unique index
null_num_expr=no # Is 1+NULL = NULL
+nulls_in_unique=no # null combination in unique index
odbc_left_outer_join=yes # left outer join odbc style
-operating_system=Windows NT Version 4.0 # crash-me tested on
+operating_system=Linux 2.4.4-64GB-SMP i686 # crash-me tested on
order_by=yes # Order by
order_by_alias=yes # Order by alias
+order_by_function=yes # Order by function
order_by_position=yes # Order by position
+order_by_remember_desc=no # Order by DESC is remembered
+order_on_unused=yes # Order by on unused column
primary_key_in_create=yes # primary key in create table
-query_size=19662 # query size
+psm_functions=no # PSM functions (ANSI SQL)
+psm_modules=no # PSM modules (ANSI SQL)
+psm_procedures=no # PSM procedures (ANSI SQL)
+psm_trigger=no # Triggers (ANSI SQL)
+query_size=65535 # query size
+quote_ident_with_"=yes # " as identifier quote (ANSI SQL)
+quote_ident_with_[=no # [] as identifier quote
+quote_ident_with_`=no # ` as identifier quote
quote_with_"=no # Allows ' and " as string markers
-recursive_subqueries=22 # recursive subqueries
+recursive_subqueries=8 # recursive subqueries
remember_end_space=no # Remembers end space in char()
remember_end_space_varchar=yes # Remembers end space in varchar()
+rename_table=yes # rename table
repeat_string_size=4000 # return string size from function
right_outer_join=yes # right outer join
+rowid=no # Type for row id
select_constants=yes # Select constants
-select_string_size=4000 # constant string size in SELECT
+select_limit=no # LIMIT number of rows
+select_limit2=no # SELECT with LIMIT #,#
+select_string_size=32672 # constant string size in SELECT
select_table_update=yes # Update with sub select
select_without_from=no # SELECT without FROM
-server_version=IBM DB2 5 # server version
+server_version=IBM DB2 7.2 # server version
simple_joins=yes # ANSI SQL simple joins
+storage_of_float=truncate # Storage of float values
subqueries=yes # subqueries
table_alias=yes # Table alias
+table_name_case=yes # case independent table names
table_wildcard=yes # Select table_name.*
-transactions=yes # transactions
+temporary_table=no # temporary tables
+transactions=yes # constant string size in where
+truncate_table=no # truncate
type_extra_abstime=no # Type abstime
type_extra_bfile=no # Type bfile
type_extra_blob=no # Type blob
type_extra_bool=no # Type bool
type_extra_box=no # Type box
type_extra_byte=no # Type byte
-type_extra_char(1_arg)_binary=no # Type char(1 arg) binary
-type_extra_char16=no # Type char16
-type_extra_char2=no # Type char2
-type_extra_char4=no # Type char4
-type_extra_char8=no # Type char8
+type_extra_char(1_arg)_binary=no # Type char(1 arg) binary
+type_extra_cidr=no # Type cidr
type_extra_circle=no # Type circle
type_extra_clob=no # Type clob
type_extra_datetime=no # Type datetime
-type_extra_enum(1_arg)=no # Type enum(1 arg)
-type_sql_float(1_arg)=yes # Type float(1 arg)
+type_extra_double=yes # Type double
+type_extra_enum(1_arg)=no # Type enum(1 arg)
+type_extra_float(2_arg)=no # Type float(2 arg)
type_extra_float4=no # Type float4
type_extra_float8=no # Type float8
type_extra_image=no # Type image
-type_extra_int(1_arg)_zerofill=no # Type int(1 arg) zerofill
+type_extra_inet=no # Type inet
+type_extra_int(1_arg)_zerofill=no # Type int(1 arg) zerofill
type_extra_int1=no # Type int1
type_extra_int2=no # Type int2
type_extra_int3=no # Type int3
type_extra_int4=no # Type int4
type_extra_int8=no # Type int8
type_extra_int_auto_increment=no # Type int not null auto_increment
+type_extra_int_identity=no # Type int not null identity
+type_extra_int_unsigned=no # Type int unsigned
+type_extra_interval=no # Type interval
type_extra_line=no # Type line
type_extra_long=no # Type long
type_extra_long_raw=no # Type long raw
type_extra_long_varbinary=no # Type long varbinary
-type_extra_long_varchar(1_arg)=no # Type long varchar(1 arg)
+type_extra_long_varchar(1_arg)=no # Type long varchar(1 arg)
type_extra_lseg=no # Type lseg
+type_extra_macaddr=no # Type macaddr
type_extra_mediumint=no # Type mediumint
type_extra_mediumtext=no # Type mediumtext
type_extra_middleint=no # Type middleint
type_extra_mlslabel=no # Type mlslabel
type_extra_money=no # Type money
-type_sql_nchar(1_arg)=no # Type nchar(1 arg)
type_extra_nclob=no # Type nclob
type_extra_number=no # Type number
-type_extra_number(1_arg)=no # Type number(1 arg)
-type_extra_nvarchar(2_arg)=no # Type nvarchar(2 arg)
+type_extra_number(1_arg)=no # Type number(1 arg)
+type_extra_number(2_arg)=no # Type number(2 arg)
type_extra_nvarchar2(1_arg)=no # Type nvarchar2(1 arg)
type_extra_path=no # Type path
type_extra_point=no # Type point
type_extra_polygon=no # Type polygon
-type_extra_raw(1_arg)=no # Type raw(1 arg)
+type_extra_raw(1_arg)=no # Type raw(1 arg)
type_extra_reltime=no # Type reltime
type_extra_rowid=no # Type rowid
type_extra_serial=no # Type serial
-type_extra_set(1_arg)=no # Type set(1 arg)
+type_extra_set(1_arg)=no # Type set(1 arg)
type_extra_smalldatetime=no # Type smalldatetime
type_extra_smallfloat=no # Type smallfloat
type_extra_smallmoney=no # Type smallmoney
type_extra_text=no # Type text
-type_extra_text(1_arg)=no # Type text(1 arg)
+type_extra_text(1_arg)=no # Type text(1 arg)
type_extra_timespan=no # Type timespan
+type_extra_uint=no # Type uint
type_extra_varchar2(1_arg)=no # Type varchar2(1 arg)
type_extra_year=no # Type year
-type_odbc_bigint=no # Type bigint
-type_odbc_binary(1_arg)=no # Type binary(1 arg)
+type_odbc_bigint=yes # Type bigint
+type_odbc_binary(1_arg)=no # Type binary(1 arg)
type_odbc_datetime=no # Type datetime
-type_sql_smallint=yes # Type smallint
type_odbc_tinyint=no # Type tinyint
type_odbc_varbinary(1_arg)=no # Type varbinary(1 arg)
type_sql_bit=no # Type bit
type_sql_bit(1_arg)=no # Type bit(1 arg)
type_sql_bit_varying(1_arg)=no # Type bit varying(1 arg)
-type_sql_char(1_arg)=yes # Type char(1 arg)
-type_sql_char_varying(1_arg)=yes # Type char varying(1 arg)
+type_sql_boolean=no # Type boolean
+type_sql_char(1_arg)=yes # Type char(1 arg)
+type_sql_char_varying(1_arg)=yes # Type char varying(1 arg)
type_sql_character(1_arg)=yes # Type character(1 arg)
type_sql_character_varying(1_arg)=yes # Type character varying(1 arg)
type_sql_date=yes # Type date
type_sql_dec(2_arg)=yes # Type dec(2 arg)
-type_sql_decimal(2_arg)=yes # Type decimal(2 arg)
-type_extra_double=yes # Type double
+type_sql_decimal(2_arg)=yes # Type decimal(2 arg)
type_sql_double_precision=yes # Type double precision
type_sql_float=yes # Type float
-type_extra_float(2_arg)=no # Type float(1 arg)
+type_sql_float(1_arg)=yes # Type float(1 arg)
type_sql_int=yes # Type int
type_sql_integer=yes # Type integer
+type_sql_interval_day=no # Type interval day
+type_sql_interval_day_to_hour=no # Type interval day to hour
+type_sql_interval_day_to_minute=no # Type interval day to minute
+type_sql_interval_day_to_second=no # Type interval day to second
+type_sql_interval_hour=no # Type interval hour
+type_sql_interval_hour_to_minute=no # Type interval hour to minute
+type_sql_interval_hour_to_second=no # Type interval hour to second
+type_sql_interval_minute=no # Type interval minute
+type_sql_interval_minute_to_second=no # Type interval minute to second
+type_sql_interval_month=no # Type interval month
+type_sql_interval_second=no # Type interval second
type_sql_interval_year=no # Type interval year
-type_sql_numeric(2_arg)=yes # Type numeric(2 arg)
+type_sql_interval_year_to_month=no # Type interval year to month
+type_sql_national_char_varying(1_arg)=no # Type national char varying(1 arg)
+type_sql_national_character(1_arg)=no # Type national character(1 arg)
+type_sql_national_character_varying(1_arg)=no # Type national character varying(1 arg)
+type_sql_nchar(1_arg)=no # Type nchar(1 arg)
+type_sql_nchar_varying(1_arg)=no # Type nchar varying(1 arg)
+type_sql_numeric(2_arg)=yes # Type numeric(2 arg)
type_sql_real=yes # Type real
+type_sql_smallint=yes # Type smallint
type_sql_time=yes # Type time
type_sql_timestamp=yes # Type timestamp
-type_sql_varchar(1_arg)=yes # Type varchar(1 arg)
+type_sql_timestamp_with_time_zone=no # Type timestamp with time zone
+type_sql_varchar(1_arg)=yes # Type varchar(1 arg)
union=yes # union
union_all=yes # union all
+union_all_incompat=yes # union all (incompatible lists)
+union_incompat=yes # union (incompatible lists)
unique_in_create=yes # unique in create table
unique_null_in_create=no # unique null in create
views=yes # views
-where_string_size=4000 # constant string size in where
+where_string_size=32672 # constant string size in where
diff --git a/sql-bench/limits/interbase-dialect1.cfg b/sql-bench/limits/interbase-dialect1.cfg
new file mode 100644
index 00000000000..046627be513
--- /dev/null
+++ b/sql-bench/limits/interbase-dialect1.cfg
@@ -0,0 +1,514 @@
+#This file is automaticly generated by crash-me 1.57
+
+NEG=no # update of column= -column
+Need_cast_for_null=no # Need to cast NULL for arithmetic
+alter_add_col=yes # Alter table add column
+alter_add_constraint=yes # Alter table add constraint
+alter_add_foreign_key=yes # Alter table add foreign key
+alter_add_multi_col=with add # Alter table add many columns
+alter_add_primary_key=with constraint # Alter table add primary key
+alter_add_unique=no # Alter table add unique
+alter_alter_col=no # Alter table alter column default
+alter_change_col=no # Alter table change column
+alter_drop_col=no # Alter table drop column
+alter_drop_constraint=yes # Alter table drop constraint
+alter_drop_foreign_key=with drop constraint # Alter table drop foreign key
+alter_drop_primary_key=no # Alter table drop primary key
+alter_drop_unique=no # Alter table drop unique
+alter_modify_col=no # Alter table modify column
+alter_rename_table=no # Alter table rename table
+atomic_updates=no # atomic updates
+automatic_rowid=no # Automatic row id
+binary_numbers=yes # binary numbers (0b1001)
+binary_strings=no # binary strings (b'0110')
+case_insensitive_strings=no # Case insensitive compare
+char_is_space_filled=yes # char are space filled
+column_alias=yes # Column alias
+columns_in_order_by=37 # number of columns in order by
+comment_#=no # # as comment
+comment_--=no # -- as comment (ANSI)
+comment_/**/=yes # /* */ as comment
+comment_//=no # // as comment
+compute=no # Compute
+connections=1000 # Simultaneous connections (installation default)
+constraint_check=no # Column constraints
+constraint_check_table=no # Table constraints
+constraint_null=no # NULL constraint (SyBase style)
+crash_me_safe=yes # crash me safe
+crash_me_version=1.57 # crash me version
+create_default=yes # default value for column
+create_default_func=no # default value function for column
+create_if_not_exists=no # create table if not exists
+create_index=yes # create index
+create_schema=no # Create SCHEMA
+create_table_select=no # create table from select
+cross_join=no # cross join (same as from a,b)
+date_infinity=no # Supports 'infinity dates
+date_last=no # Supports 9999-12-31 dates
+date_one=no # Supports 0001-01-01 dates
+date_with_YY=no # Supports YY-MM-DD dates
+date_zero=no # Supports 0000-00-00 dates
+domains=no # Domains (ANSI SQL)
+double_quotes=yes # Double '' as ' in strings
+drop_if_exists=no # drop table if exists
+drop_index=yes # drop index
+drop_requires_cascade=no # drop table require cascade/restrict
+drop_restrict=no # drop table with cascade/restrict
+end_colon=yes # allows end ';'
+except=no # except
+except_all=no # except all
+except_all_incompat=no # except all (incompatible lists)
+except_incompat=no # except (incompatible lists)
+float_int_expr=yes # mixing of integer and float in expression
+foreign_key_syntax=no # foreign key syntax
+full_outer_join=yes # full outer join
+func_extra_!=no # Function NOT as '!' in SELECT
+func_extra_%=no # Function MOD as %
+func_extra_&=no # Function & (bitwise and)
+func_extra_&&=no # Function AND as '&&'
+func_extra_<>=no # Function <> in SELECT
+func_extra_==no # Function =
+func_extra_add_months=no # Function ADD_MONTHS
+func_extra_and_or=no # Function AND and OR in SELECT
+func_extra_ascii_char=no # Function ASCII_CHAR
+func_extra_ascii_code=no # Function ASCII_CODE
+func_extra_atn2=no # Function ATN2
+func_extra_auto_num2string=no # Function automatic num->string convert
+func_extra_auto_string2num=no # Function automatic string->num convert
+func_extra_between=no # Function BETWEEN in SELECT
+func_extra_binary_shifts=no # Function << and >> (bitwise shifts)
+func_extra_bit_count=no # Function BIT_COUNT
+func_extra_ceil=no # Function CEIL
+func_extra_charindex=no # Function CHARINDEX
+func_extra_chr=no # Function CHR
+func_extra_concat_as_+=no # Function concatenation with +
+func_extra_concat_list=no # Function CONCAT(list)
+func_extra_convert=no # Function CONVERT
+func_extra_cosh=no # Function COSH
+func_extra_date_format=no # Function DATE_FORMAT
+func_extra_dateadd=no # Function DATEADD
+func_extra_datediff=no # Function DATEDIFF
+func_extra_datename=no # Function DATENAME
+func_extra_datepart=no # Function DATEPART
+func_extra_elt=no # Function ELT
+func_extra_encrypt=no # Function ENCRYPT
+func_extra_field=no # Function FIELD
+func_extra_format=no # Function FORMAT
+func_extra_from_days=no # Function FROM_DAYS
+func_extra_from_unixtime=no # Function FROM_UNIXTIME
+func_extra_getdate=no # Function GETDATE
+func_extra_greatest=no # Function GREATEST
+func_extra_if=no # Function IF
+func_extra_in_num=no # Function IN on numbers in SELECT
+func_extra_in_str=no # Function IN on strings in SELECT
+func_extra_initcap=no # Function INITCAP
+func_extra_instr=no # Function LOCATE as INSTR
+func_extra_instr_oracle=no # Function INSTR (Oracle syntax)
+func_extra_instrb=no # Function INSTRB
+func_extra_interval=no # Function INTERVAL
+func_extra_last_day=no # Function LAST_DAY
+func_extra_last_insert_id=no # Function LAST_INSERT_ID
+func_extra_least=no # Function LEAST
+func_extra_lengthb=no # Function LENGTHB
+func_extra_like=no # Function LIKE in SELECT
+func_extra_like_escape=no # Function LIKE ESCAPE in SELECT
+func_extra_ln=no # Function LN
+func_extra_log(m_n)=no # Function LOG(m,n)
+func_extra_logn=no # Function LOGN
+func_extra_lpad=no # Function LPAD
+func_extra_mdy=no # Function MDY
+func_extra_mid=no # Function SUBSTRING as MID
+func_extra_months_between=no # Function MONTHS_BETWEEN
+func_extra_not=no # Function NOT in SELECT
+func_extra_not_between=no # Function NOT BETWEEN in SELECT
+func_extra_not_like=no # Function NOT LIKE in SELECT
+func_extra_odbc_convert=no # Function ODBC CONVERT
+func_extra_password=no # Function PASSWORD
+func_extra_paste=no # Function PASTE
+func_extra_patindex=no # Function PATINDEX
+func_extra_period_add=no # Function PERIOD_ADD
+func_extra_period_diff=no # Function PERIOD_DIFF
+func_extra_pow=no # Function POW
+func_extra_range=no # Function RANGE
+func_extra_regexp=no # Function REGEXP in SELECT
+func_extra_replicate=no # Function REPLICATE
+func_extra_reverse=no # Function REVERSE
+func_extra_root=no # Function ROOT
+func_extra_round1=no # Function ROUND(1 arg)
+func_extra_rpad=no # Function RPAD
+func_extra_sec_to_time=no # Function SEC_TO_TIME
+func_extra_sinh=no # Function SINH
+func_extra_str=no # Function STR
+func_extra_strcmp=no # Function STRCMP
+func_extra_stuff=no # Function STUFF
+func_extra_substrb=no # Function SUBSTRB
+func_extra_substring_index=no # Function SUBSTRING_INDEX
+func_extra_sysdate=no # Function SYSDATE
+func_extra_tail=no # Function TAIL
+func_extra_tanh=no # Function TANH
+func_extra_time_to_sec=no # Function TIME_TO_SEC
+func_extra_to_days=no # Function TO_DAYS
+func_extra_translate=no # Function TRANSLATE
+func_extra_trim_many_char=no # Function TRIM; Many char extension
+func_extra_trim_substring=no # Function TRIM; Substring extension
+func_extra_trunc=no # Function TRUNC
+func_extra_uid=no # Function UID
+func_extra_unix_timestamp=no # Function UNIX_TIMESTAMP
+func_extra_userenv=no # Function USERENV
+func_extra_version=no # Function VERSION
+func_extra_weekday=no # Function WEEKDAY
+func_extra_|=no # Function | (bitwise or)
+func_extra_||=no # Function OR as '||'
+func_extra_~*=no # Function ~* (case insensitive compare)
+func_odbc_abs=no # Function ABS
+func_odbc_acos=no # Function ACOS
+func_odbc_ascii=no # Function ASCII
+func_odbc_asin=no # Function ASIN
+func_odbc_atan=no # Function ATAN
+func_odbc_atan2=no # Function ATAN2
+func_odbc_ceiling=no # Function CEILING
+func_odbc_char=no # Function CHAR
+func_odbc_concat=no # Function CONCAT(2 arg)
+func_odbc_cos=no # Function COS
+func_odbc_cot=no # Function COT
+func_odbc_curdate=no # Function CURDATE
+func_odbc_curtime=no # Function CURTIME
+func_odbc_database=no # Function DATABASE
+func_odbc_dayname=no # Function DAYNAME
+func_odbc_dayofmonth=no # Function DAYOFMONTH
+func_odbc_dayofweek=no # Function DAYOFWEEK
+func_odbc_dayofyear=no # Function DAYOFYEAR
+func_odbc_degrees=no # Function DEGREES
+func_odbc_difference=no # Function DIFFERENCE()
+func_odbc_exp=no # Function EXP
+func_odbc_floor=no # Function FLOOR
+func_odbc_fn_left=no # Function ODBC syntax LEFT & RIGHT
+func_odbc_hour=no # Function HOUR
+func_odbc_hour_time=no # Function ANSI HOUR
+func_odbc_ifnull=no # Function IFNULL
+func_odbc_insert=no # Function INSERT
+func_odbc_lcase=no # Function LCASE
+func_odbc_left=no # Function LEFT
+func_odbc_length=no # Function REAL LENGTH
+func_odbc_length_without_space=no # Function ODBC LENGTH
+func_odbc_locate_2=no # Function LOCATE(2 arg)
+func_odbc_locate_3=no # Function LOCATE(3 arg)
+func_odbc_log=no # Function LOG
+func_odbc_log10=no # Function LOG10
+func_odbc_ltrim=no # Function LTRIM
+func_odbc_minute=no # Function MINUTE
+func_odbc_mod=no # Function MOD
+func_odbc_month=no # Function MONTH
+func_odbc_monthname=no # Function MONTHNAME
+func_odbc_now=no # Function NOW
+func_odbc_pi=no # Function PI
+func_odbc_power=no # Function POWER
+func_odbc_quarter=no # Function QUARTER
+func_odbc_radians=no # Function RADIANS
+func_odbc_rand=no # Function RAND
+func_odbc_repeat=no # Function REPEAT
+func_odbc_replace=no # Function REPLACE
+func_odbc_right=no # Function RIGHT
+func_odbc_round=no # Function ROUND(2 arg)
+func_odbc_rtrim=no # Function RTRIM
+func_odbc_second=no # Function SECOND
+func_odbc_sign=no # Function SIGN
+func_odbc_sin=no # Function SIN
+func_odbc_soundex=no # Function SOUNDEX
+func_odbc_space=no # Function SPACE
+func_odbc_sqrt=no # Function SQRT
+func_odbc_substring=no # Function ODBC SUBSTRING
+func_odbc_tan=no # Function TAN
+func_odbc_timestampadd=no # Function TIMESTAMPADD
+func_odbc_timestampdiff=no # Function TIMESTAMPDIFF
+func_odbc_truncate=no # Function TRUNCATE
+func_odbc_ucase=no # Function UCASE
+func_odbc_user()=no # Function USER()
+func_odbc_week=no # Function WEEK
+func_odbc_year=no # Function YEAR
+func_sql_+=yes # Function +, -, * and /
+func_sql_bit_length=no # Function BIT_LENGTH
+func_sql_cast=yes # Function CAST
+func_sql_char_length=no # Function CHAR_LENGTH
+func_sql_char_length(constant)=no # Function CHAR_LENGTH(constant)
+func_sql_character_length=no # Function CHARACTER_LENGTH
+func_sql_coalesce=no # Function COALESCE
+func_sql_concat_as_||=yes # Function concatenation with ||
+func_sql_current_date=no # Function CURRENT_DATE
+func_sql_current_time=no # Function CURRENT_TIME
+func_sql_current_timestamp=yes # Function CURRENT_TIMESTAMP
+func_sql_current_user=no # Function CURRENT_USER
+func_sql_extract_sql=yes # Function EXTRACT
+func_sql_localtime=no # Function LOCALTIME
+func_sql_localtimestamp=no # Function LOCALTIMESTAMP
+func_sql_lower=no # Function LOWER
+func_sql_nullif_num=no # Function NULLIF with numbers
+func_sql_nullif_string=no # Function NULLIF with strings
+func_sql_octet_length=no # Function OCTET_LENGTH
+func_sql_position=no # Function POSITION
+func_sql_searched_case=no # Function searched CASE
+func_sql_session_user=no # Function SESSION_USER
+func_sql_simple_case=no # Function simple CASE
+func_sql_substring=no # Function ANSI SQL SUBSTRING
+func_sql_system_user=no # Function SYSTEM_USER
+func_sql_trim=no # Function TRIM
+func_sql_upper=yes # Function UPPER
+func_sql_user=yes # Function USER
+func_where_between=yes # Function BETWEEN
+func_where_eq_all=yes # Function = ALL
+func_where_eq_any=yes # Function = ANY
+func_where_eq_some=yes # Function = SOME
+func_where_exists=yes # Function EXISTS
+func_where_in_num=yes # Function IN on numbers
+func_where_like=yes # Function LIKE
+func_where_like_escape=yes # Function LIKE ESCAPE
+func_where_match=no # Function MATCH
+func_where_match_unique=no # Function MATCH UNIQUE
+func_where_matches=no # Function MATCHES
+func_where_not_between=yes # Function NOT BETWEEN
+func_where_not_exists=yes # Function NOT EXISTS
+func_where_not_like=yes # Function NOT LIKE
+func_where_not_unique=no # Function NOT UNIQUE
+func_where_unique=no # Function UNIQUE
+functions=yes # Functions
+group_by=yes # Group by
+group_by_alias=no # Group by alias
+group_by_null=yes # Group on column with null values
+group_by_position=no # Group by position
+group_distinct_functions=yes # Group functions with distinct
+group_func_extra_bit_and=no # Group function BIT_AND
+group_func_extra_bit_or=no # Group function BIT_OR
+group_func_extra_count_distinct_list=no # Group function COUNT(DISTINCT expr,expr,...)
+group_func_extra_std=no # Group function STD
+group_func_extra_stddev=no # Group function STDDEV
+group_func_extra_variance=no # Group function VARIANCE
+group_func_sql_any=no # Group function ANY
+group_func_sql_avg=yes # Group function AVG
+group_func_sql_count_*=yes # Group function COUNT (*)
+group_func_sql_count_column=yes # Group function COUNT column name
+group_func_sql_count_distinct=yes # Group function COUNT(DISTINCT expr)
+group_func_sql_every=no # Group function EVERY
+group_func_sql_max=yes # Group function MAX on numbers
+group_func_sql_max_str=yes # Group function MAX on strings
+group_func_sql_min=yes # Group function MIN on numbers
+group_func_sql_min_str=yes # Group function MIN on strings
+group_func_sql_some=no # Group function SOME
+group_func_sql_sum=yes # Group function SUM
+group_functions=yes # Group functions
+group_on_unused=yes # Group on unused column
+has_true_false=no # TRUE and FALSE
+having=yes # Having
+having_with_alias=no # Having on alias
+having_with_group=yes # Having with group function
+hex_numbers=yes # hex numbers (0x41)
+hex_strings=no # hex strings (x'1ace')
+ignore_end_space=yes # Ignore end space in compare
+index_in_create=no # index in create table
+index_namespace=no # different namespace for index
+index_parts=no # index on column part (extension)
+inner_join=yes # inner join
+insert_empty_string=no # insert empty string
+insert_multi_value=no # INSERT with Value lists
+insert_select=no # insert INTO ... SELECT ...
+insert_with_set=no # INSERT with set syntax
+intersect=no # intersect
+intersect_all=no # intersect all
+intersect_all_incompat=no # intersect all (incompatible lists)
+intersect_incompat=no # intersect (incompatible lists)
+join_tables=+64 # tables in join
+left_outer_join=yes # left outer join
+left_outer_join_using=no # left outer join using
+like_with_column=no # column LIKE column
+like_with_number=no # LIKE on numbers
+lock_tables=no # lock table
+logical_value=not supported # Value of logical operation (1=1)
+max_big_expressions=1 # big expressions
+max_char_size=32767 # max char() size
+max_column_name=18 # column name length
+max_columns=4759 # Columns in table
+max_conditions=2944 # OR and AND in WHERE
+max_expressions=+10000 # simple expressions
+max_index=+64 # max index
+max_index_name=31 # index name length
+max_index_parts=16 # index parts
+max_index_varchar_part_length=249 # index varchar part length
+max_row_length=64744 # max table row length (without blobs)
+max_row_length_with_null=64744 # table row length with nulls (without blobs)
+max_select_alias_name=132 # select alias name length
+max_stack_expression=165 # stacked expressions
+max_table_alias_name=255 # table alias name length
+max_table_name=31 # table name length
+max_unique_index=+64 # unique indexes
+max_varchar_size=10923 # max varchar() size
+minus=no # minus
+minus_incompat=no # minus (incompatible lists)
+minus_neg=yes # Calculate 1--1
+multi_drop=no # many tables to drop table
+multi_strings=no # Multiple line strings
+multi_table_delete=no # DELETE FROM table1,table2...
+multi_table_update=no # Update with many tables
+natural_join=no # natural join
+natural_join_incompat=no # natural join (incompatible lists)
+natural_left_outer_join=no # natural left outer join
+no_primary_key=yes # Tables without primary key
+null_concat_expr=no # Is 'a' || NULL = NULL
+null_in_index=yes # null in index
+null_in_unique=no # null in unique index
+null_num_expr=no # Is 1+NULL = NULL
+nulls_in_unique=no # null combination in unique index
+odbc_left_outer_join=no # left outer join odbc style
+operating_system=Linux 2.4.4-64GB-SMP i686 # crash-me tested on
+order_by=yes # Order by
+order_by_alias=no # Order by alias
+order_by_function=no # Order by function
+order_by_position=yes # Order by position
+order_by_remember_desc=no # Order by DESC is remembered
+order_on_unused=yes # Order by on unused column
+primary_key_in_create=yes # primary key in create table
+psm_functions=no # PSM functions (ANSI SQL)
+psm_modules=no # PSM modules (ANSI SQL)
+psm_procedures=no # PSM procedures (ANSI SQL)
+psm_trigger=no # Triggers (ANSI SQL)
+query_size=65535 # query size
+quote_ident_with_"=yes # " as identifier quote (ANSI SQL)
+quote_ident_with_[=no # [] as identifier quote
+quote_ident_with_`=no # ` as identifier quote
+quote_with_"=no # Allows ' and " as string markers
+recursive_subqueries=61 # recursive subqueries
+remember_end_space=no # Remembers end space in char()
+remember_end_space_varchar=yes # Remembers end space in varchar()
+rename_table=no # rename table
+right_outer_join=yes # right outer join
+rowid=no # Type for row id
+select_constants=yes # Select constants
+select_limit=no # LIMIT number of rows
+select_limit2=no # SELECT with LIMIT #,#
+select_string_size=32767 # constant string size in SELECT
+select_table_update=yes # Update with sub select
+select_without_from=no # SELECT without FROM
+server_version=6.0.1 # server version
+simple_joins=yes # ANSI SQL simple joins
+storage_of_float=round # Storage of float values
+subqueries=yes # subqueries
+table_alias=no # Table alias
+table_name_case=yes # case independent table names
+table_wildcard=yes # Select table_name.*
+temporary_table=no # temporary tables
+transactions=error # constant string size in where
+truncate_table=no # truncate
+type_extra_abstime=no # Type abstime
+type_extra_bfile=no # Type bfile
+type_extra_blob=yes # Type blob
+type_extra_bool=no # Type bool
+type_extra_box=no # Type box
+type_extra_byte=no # Type byte
+type_extra_char(1_arg)_binary=no # Type char(1 arg) binary
+type_extra_cidr=no # Type cidr
+type_extra_circle=no # Type circle
+type_extra_clob=no # Type clob
+type_extra_datetime=no # Type datetime
+type_extra_double=no # Type double
+type_extra_enum(1_arg)=no # Type enum(1 arg)
+type_extra_float(2_arg)=no # Type float(2 arg)
+type_extra_float4=no # Type float4
+type_extra_float8=no # Type float8
+type_extra_image=no # Type image
+type_extra_inet=no # Type inet
+type_extra_int(1_arg)_zerofill=no # Type int(1 arg) zerofill
+type_extra_int1=no # Type int1
+type_extra_int2=no # Type int2
+type_extra_int3=no # Type int3
+type_extra_int4=no # Type int4
+type_extra_int8=no # Type int8
+type_extra_int_auto_increment=no # Type int not null auto_increment
+type_extra_int_identity=no # Type int not null identity
+type_extra_int_unsigned=no # Type int unsigned
+type_extra_interval=no # Type interval
+type_extra_line=no # Type line
+type_extra_long=no # Type long
+type_extra_long_raw=no # Type long raw
+type_extra_long_varbinary=no # Type long varbinary
+type_extra_long_varchar(1_arg)=no # Type long varchar(1 arg)
+type_extra_lseg=no # Type lseg
+type_extra_macaddr=no # Type macaddr
+type_extra_mediumint=no # Type mediumint
+type_extra_mediumtext=no # Type mediumtext
+type_extra_middleint=no # Type middleint
+type_extra_mlslabel=no # Type mlslabel
+type_extra_money=no # Type money
+type_extra_nclob=no # Type nclob
+type_extra_number=no # Type number
+type_extra_number(1_arg)=no # Type number(1 arg)
+type_extra_number(2_arg)=no # Type number(2 arg)
+type_extra_nvarchar2(1_arg)=no # Type nvarchar2(1 arg)
+type_extra_path=no # Type path
+type_extra_point=no # Type point
+type_extra_polygon=no # Type polygon
+type_extra_raw(1_arg)=no # Type raw(1 arg)
+type_extra_reltime=no # Type reltime
+type_extra_rowid=no # Type rowid
+type_extra_serial=no # Type serial
+type_extra_set(1_arg)=no # Type set(1 arg)
+type_extra_smalldatetime=no # Type smalldatetime
+type_extra_smallfloat=no # Type smallfloat
+type_extra_smallmoney=no # Type smallmoney
+type_extra_text=no # Type text
+type_extra_text(1_arg)=no # Type text(1 arg)
+type_extra_timespan=no # Type timespan
+type_extra_uint=no # Type uint
+type_extra_varchar2(1_arg)=no # Type varchar2(1 arg)
+type_extra_year=no # Type year
+type_odbc_bigint=no # Type bigint
+type_odbc_binary(1_arg)=no # Type binary(1 arg)
+type_odbc_datetime=no # Type datetime
+type_odbc_tinyint=no # Type tinyint
+type_odbc_varbinary(1_arg)=no # Type varbinary(1 arg)
+type_sql_bit=no # Type bit
+type_sql_bit(1_arg)=no # Type bit(1 arg)
+type_sql_bit_varying(1_arg)=no # Type bit varying(1 arg)
+type_sql_boolean=no # Type boolean
+type_sql_char(1_arg)=yes # Type char(1 arg)
+type_sql_char_varying(1_arg)=yes # Type char varying(1 arg)
+type_sql_character(1_arg)=yes # Type character(1 arg)
+type_sql_character_varying(1_arg)=yes # Type character varying(1 arg)
+type_sql_date=no # Type date
+type_sql_dec(2_arg)=yes # Type dec(2 arg)
+type_sql_decimal(2_arg)=yes # Type decimal(2 arg)
+type_sql_double_precision=yes # Type double precision
+type_sql_float=yes # Type float
+type_sql_float(1_arg)=yes # Type float(1 arg)
+type_sql_int=yes # Type int
+type_sql_integer=yes # Type integer
+type_sql_interval_day=no # Type interval day
+type_sql_interval_day_to_hour=no # Type interval day to hour
+type_sql_interval_day_to_minute=no # Type interval day to minute
+type_sql_interval_day_to_second=no # Type interval day to second
+type_sql_interval_hour=no # Type interval hour
+type_sql_interval_hour_to_minute=no # Type interval hour to minute
+type_sql_interval_hour_to_second=no # Type interval hour to second
+type_sql_interval_minute=no # Type interval minute
+type_sql_interval_minute_to_second=no # Type interval minute to second
+type_sql_interval_month=no # Type interval month
+type_sql_interval_second=no # Type interval second
+type_sql_interval_year=no # Type interval year
+type_sql_interval_year_to_month=no # Type interval year to month
+type_sql_national_char_varying(1_arg)=yes # Type national char varying(1 arg)
+type_sql_national_character(1_arg)=yes # Type national character(1 arg)
+type_sql_national_character_varying(1_arg)=yes # Type national character varying(1 arg)
+type_sql_nchar(1_arg)=yes # Type nchar(1 arg)
+type_sql_nchar_varying(1_arg)=yes # Type nchar varying(1 arg)
+type_sql_numeric(2_arg)=yes # Type numeric(2 arg)
+type_sql_real=yes # Type real
+type_sql_smallint=yes # Type smallint
+type_sql_time=no # Type time
+type_sql_timestamp=yes # Type timestamp
+type_sql_timestamp_with_time_zone=no # Type timestamp with time zone
+type_sql_varchar(1_arg)=yes # Type varchar(1 arg)
+union=yes # union
+union_all=yes # union all
+union_all_incompat=yes # union all (incompatible lists)
+union_incompat=yes # union (incompatible lists)
+unique_in_create=yes # unique in create table
+unique_null_in_create=no # unique null in create
+views=no # views
+where_string_size=32767 # constant string size in where
diff --git a/sql-bench/limits/interbase-dialect3.cfg b/sql-bench/limits/interbase-dialect3.cfg
new file mode 100644
index 00000000000..fdc93098688
--- /dev/null
+++ b/sql-bench/limits/interbase-dialect3.cfg
@@ -0,0 +1,514 @@
+#This file is automaticly generated by crash-me 1.57
+
+NEG=no # update of column= -column
+Need_cast_for_null=no # Need to cast NULL for arithmetic
+alter_add_col=yes # Alter table add column
+alter_add_constraint=yes # Alter table add constraint
+alter_add_foreign_key=yes # Alter table add foreign key
+alter_add_multi_col=with add # Alter table add many columns
+alter_add_primary_key=with constraint # Alter table add primary key
+alter_add_unique=no # Alter table add unique
+alter_alter_col=no # Alter table alter column default
+alter_change_col=no # Alter table change column
+alter_drop_col=no # Alter table drop column
+alter_drop_constraint=yes # Alter table drop constraint
+alter_drop_foreign_key=with drop constraint # Alter table drop foreign key
+alter_drop_primary_key=no # Alter table drop primary key
+alter_drop_unique=no # Alter table drop unique
+alter_modify_col=no # Alter table modify column
+alter_rename_table=no # Alter table rename table
+atomic_updates=no # atomic updates
+automatic_rowid=no # Automatic row id
+binary_numbers=yes # binary numbers (0b1001)
+binary_strings=no # binary strings (b'0110')
+case_insensitive_strings=no # Case insensitive compare
+char_is_space_filled=yes # char are space filled
+column_alias=yes # Column alias
+columns_in_order_by=37 # number of columns in order by
+comment_#=no # # as comment
+comment_--=no # -- as comment (ANSI)
+comment_/**/=yes # /* */ as comment
+comment_//=no # // as comment
+compute=no # Compute
+connections=1000 # Simultaneous connections (installation default)
+constraint_check=no # Column constraints
+constraint_check_table=no # Table constraints
+constraint_null=no # NULL constraint (SyBase style)
+crash_me_safe=yes # crash me safe
+crash_me_version=1.57 # crash me version
+create_default=yes # default value for column
+create_default_func=no # default value function for column
+create_if_not_exists=no # create table if not exists
+create_index=yes # create index
+create_schema=no # Create SCHEMA
+create_table_select=no # create table from select
+cross_join=no # cross join (same as from a,b)
+date_infinity=no # Supports 'infinity dates
+date_last=error # Supports 9999-12-31 dates
+date_one=error # Supports 0001-01-01 dates
+date_with_YY=no # Supports YY-MM-DD dates
+date_zero=no # Supports 0000-00-00 dates
+domains=no # Domains (ANSI SQL)
+double_quotes=yes # Double '' as ' in strings
+drop_if_exists=no # drop table if exists
+drop_index=yes # drop index
+drop_requires_cascade=no # drop table require cascade/restrict
+drop_restrict=no # drop table with cascade/restrict
+end_colon=yes # allows end ';'
+except=no # except
+except_all=no # except all
+except_all_incompat=no # except all (incompatible lists)
+except_incompat=no # except (incompatible lists)
+float_int_expr=yes # mixing of integer and float in expression
+foreign_key_syntax=no # foreign key syntax
+full_outer_join=yes # full outer join
+func_extra_!=no # Function NOT as '!' in SELECT
+func_extra_%=no # Function MOD as %
+func_extra_&=no # Function & (bitwise and)
+func_extra_&&=no # Function AND as '&&'
+func_extra_<>=no # Function <> in SELECT
+func_extra_==no # Function =
+func_extra_add_months=no # Function ADD_MONTHS
+func_extra_and_or=no # Function AND and OR in SELECT
+func_extra_ascii_char=no # Function ASCII_CHAR
+func_extra_ascii_code=no # Function ASCII_CODE
+func_extra_atn2=no # Function ATN2
+func_extra_auto_num2string=no # Function automatic num->string convert
+func_extra_auto_string2num=no # Function automatic string->num convert
+func_extra_between=no # Function BETWEEN in SELECT
+func_extra_binary_shifts=no # Function << and >> (bitwise shifts)
+func_extra_bit_count=no # Function BIT_COUNT
+func_extra_ceil=no # Function CEIL
+func_extra_charindex=no # Function CHARINDEX
+func_extra_chr=no # Function CHR
+func_extra_concat_as_+=no # Function concatenation with +
+func_extra_concat_list=no # Function CONCAT(list)
+func_extra_convert=no # Function CONVERT
+func_extra_cosh=no # Function COSH
+func_extra_date_format=no # Function DATE_FORMAT
+func_extra_dateadd=no # Function DATEADD
+func_extra_datediff=no # Function DATEDIFF
+func_extra_datename=no # Function DATENAME
+func_extra_datepart=no # Function DATEPART
+func_extra_elt=no # Function ELT
+func_extra_encrypt=no # Function ENCRYPT
+func_extra_field=no # Function FIELD
+func_extra_format=no # Function FORMAT
+func_extra_from_days=no # Function FROM_DAYS
+func_extra_from_unixtime=no # Function FROM_UNIXTIME
+func_extra_getdate=no # Function GETDATE
+func_extra_greatest=no # Function GREATEST
+func_extra_if=no # Function IF
+func_extra_in_num=no # Function IN on numbers in SELECT
+func_extra_in_str=no # Function IN on strings in SELECT
+func_extra_initcap=no # Function INITCAP
+func_extra_instr=no # Function LOCATE as INSTR
+func_extra_instr_oracle=no # Function INSTR (Oracle syntax)
+func_extra_instrb=no # Function INSTRB
+func_extra_interval=no # Function INTERVAL
+func_extra_last_day=no # Function LAST_DAY
+func_extra_last_insert_id=no # Function LAST_INSERT_ID
+func_extra_least=no # Function LEAST
+func_extra_lengthb=no # Function LENGTHB
+func_extra_like=no # Function LIKE in SELECT
+func_extra_like_escape=no # Function LIKE ESCAPE in SELECT
+func_extra_ln=no # Function LN
+func_extra_log(m_n)=no # Function LOG(m,n)
+func_extra_logn=no # Function LOGN
+func_extra_lpad=no # Function LPAD
+func_extra_mdy=no # Function MDY
+func_extra_mid=no # Function SUBSTRING as MID
+func_extra_months_between=no # Function MONTHS_BETWEEN
+func_extra_not=no # Function NOT in SELECT
+func_extra_not_between=no # Function NOT BETWEEN in SELECT
+func_extra_not_like=no # Function NOT LIKE in SELECT
+func_extra_odbc_convert=no # Function ODBC CONVERT
+func_extra_password=no # Function PASSWORD
+func_extra_paste=no # Function PASTE
+func_extra_patindex=no # Function PATINDEX
+func_extra_period_add=no # Function PERIOD_ADD
+func_extra_period_diff=no # Function PERIOD_DIFF
+func_extra_pow=no # Function POW
+func_extra_range=no # Function RANGE
+func_extra_regexp=no # Function REGEXP in SELECT
+func_extra_replicate=no # Function REPLICATE
+func_extra_reverse=no # Function REVERSE
+func_extra_root=no # Function ROOT
+func_extra_round1=no # Function ROUND(1 arg)
+func_extra_rpad=no # Function RPAD
+func_extra_sec_to_time=no # Function SEC_TO_TIME
+func_extra_sinh=no # Function SINH
+func_extra_str=no # Function STR
+func_extra_strcmp=no # Function STRCMP
+func_extra_stuff=no # Function STUFF
+func_extra_substrb=no # Function SUBSTRB
+func_extra_substring_index=no # Function SUBSTRING_INDEX
+func_extra_sysdate=no # Function SYSDATE
+func_extra_tail=no # Function TAIL
+func_extra_tanh=no # Function TANH
+func_extra_time_to_sec=no # Function TIME_TO_SEC
+func_extra_to_days=no # Function TO_DAYS
+func_extra_translate=no # Function TRANSLATE
+func_extra_trim_many_char=no # Function TRIM; Many char extension
+func_extra_trim_substring=no # Function TRIM; Substring extension
+func_extra_trunc=no # Function TRUNC
+func_extra_uid=no # Function UID
+func_extra_unix_timestamp=no # Function UNIX_TIMESTAMP
+func_extra_userenv=no # Function USERENV
+func_extra_version=no # Function VERSION
+func_extra_weekday=no # Function WEEKDAY
+func_extra_|=no # Function | (bitwise or)
+func_extra_||=no # Function OR as '||'
+func_extra_~*=no # Function ~* (case insensitive compare)
+func_odbc_abs=no # Function ABS
+func_odbc_acos=no # Function ACOS
+func_odbc_ascii=no # Function ASCII
+func_odbc_asin=no # Function ASIN
+func_odbc_atan=no # Function ATAN
+func_odbc_atan2=no # Function ATAN2
+func_odbc_ceiling=no # Function CEILING
+func_odbc_char=no # Function CHAR
+func_odbc_concat=no # Function CONCAT(2 arg)
+func_odbc_cos=no # Function COS
+func_odbc_cot=no # Function COT
+func_odbc_curdate=no # Function CURDATE
+func_odbc_curtime=no # Function CURTIME
+func_odbc_database=no # Function DATABASE
+func_odbc_dayname=no # Function DAYNAME
+func_odbc_dayofmonth=no # Function DAYOFMONTH
+func_odbc_dayofweek=no # Function DAYOFWEEK
+func_odbc_dayofyear=no # Function DAYOFYEAR
+func_odbc_degrees=no # Function DEGREES
+func_odbc_difference=no # Function DIFFERENCE()
+func_odbc_exp=no # Function EXP
+func_odbc_floor=no # Function FLOOR
+func_odbc_fn_left=no # Function ODBC syntax LEFT & RIGHT
+func_odbc_hour=no # Function HOUR
+func_odbc_hour_time=no # Function ANSI HOUR
+func_odbc_ifnull=no # Function IFNULL
+func_odbc_insert=no # Function INSERT
+func_odbc_lcase=no # Function LCASE
+func_odbc_left=no # Function LEFT
+func_odbc_length=no # Function REAL LENGTH
+func_odbc_length_without_space=no # Function ODBC LENGTH
+func_odbc_locate_2=no # Function LOCATE(2 arg)
+func_odbc_locate_3=no # Function LOCATE(3 arg)
+func_odbc_log=no # Function LOG
+func_odbc_log10=no # Function LOG10
+func_odbc_ltrim=no # Function LTRIM
+func_odbc_minute=no # Function MINUTE
+func_odbc_mod=no # Function MOD
+func_odbc_month=no # Function MONTH
+func_odbc_monthname=no # Function MONTHNAME
+func_odbc_now=no # Function NOW
+func_odbc_pi=no # Function PI
+func_odbc_power=no # Function POWER
+func_odbc_quarter=no # Function QUARTER
+func_odbc_radians=no # Function RADIANS
+func_odbc_rand=no # Function RAND
+func_odbc_repeat=no # Function REPEAT
+func_odbc_replace=no # Function REPLACE
+func_odbc_right=no # Function RIGHT
+func_odbc_round=no # Function ROUND(2 arg)
+func_odbc_rtrim=no # Function RTRIM
+func_odbc_second=no # Function SECOND
+func_odbc_sign=no # Function SIGN
+func_odbc_sin=no # Function SIN
+func_odbc_soundex=no # Function SOUNDEX
+func_odbc_space=no # Function SPACE
+func_odbc_sqrt=no # Function SQRT
+func_odbc_substring=no # Function ODBC SUBSTRING
+func_odbc_tan=no # Function TAN
+func_odbc_timestampadd=no # Function TIMESTAMPADD
+func_odbc_timestampdiff=no # Function TIMESTAMPDIFF
+func_odbc_truncate=no # Function TRUNCATE
+func_odbc_ucase=no # Function UCASE
+func_odbc_user()=no # Function USER()
+func_odbc_week=no # Function WEEK
+func_odbc_year=no # Function YEAR
+func_sql_+=yes # Function +, -, * and /
+func_sql_bit_length=no # Function BIT_LENGTH
+func_sql_cast=yes # Function CAST
+func_sql_char_length=no # Function CHAR_LENGTH
+func_sql_char_length(constant)=no # Function CHAR_LENGTH(constant)
+func_sql_character_length=no # Function CHARACTER_LENGTH
+func_sql_coalesce=no # Function COALESCE
+func_sql_concat_as_||=yes # Function concatenation with ||
+func_sql_current_date=yes # Function CURRENT_DATE
+func_sql_current_time=yes # Function CURRENT_TIME
+func_sql_current_timestamp=yes # Function CURRENT_TIMESTAMP
+func_sql_current_user=no # Function CURRENT_USER
+func_sql_extract_sql=yes # Function EXTRACT
+func_sql_localtime=no # Function LOCALTIME
+func_sql_localtimestamp=no # Function LOCALTIMESTAMP
+func_sql_lower=no # Function LOWER
+func_sql_nullif_num=no # Function NULLIF with numbers
+func_sql_nullif_string=no # Function NULLIF with strings
+func_sql_octet_length=no # Function OCTET_LENGTH
+func_sql_position=no # Function POSITION
+func_sql_searched_case=no # Function searched CASE
+func_sql_session_user=no # Function SESSION_USER
+func_sql_simple_case=no # Function simple CASE
+func_sql_substring=no # Function ANSI SQL SUBSTRING
+func_sql_system_user=no # Function SYSTEM_USER
+func_sql_trim=no # Function TRIM
+func_sql_upper=yes # Function UPPER
+func_sql_user=yes # Function USER
+func_where_between=yes # Function BETWEEN
+func_where_eq_all=yes # Function = ALL
+func_where_eq_any=yes # Function = ANY
+func_where_eq_some=yes # Function = SOME
+func_where_exists=yes # Function EXISTS
+func_where_in_num=yes # Function IN on numbers
+func_where_like=yes # Function LIKE
+func_where_like_escape=yes # Function LIKE ESCAPE
+func_where_match=no # Function MATCH
+func_where_match_unique=no # Function MATCH UNIQUE
+func_where_matches=no # Function MATCHES
+func_where_not_between=yes # Function NOT BETWEEN
+func_where_not_exists=yes # Function NOT EXISTS
+func_where_not_like=yes # Function NOT LIKE
+func_where_not_unique=no # Function NOT UNIQUE
+func_where_unique=no # Function UNIQUE
+functions=yes # Functions
+group_by=yes # Group by
+group_by_alias=no # Group by alias
+group_by_null=yes # Group on column with null values
+group_by_position=no # Group by position
+group_distinct_functions=yes # Group functions with distinct
+group_func_extra_bit_and=no # Group function BIT_AND
+group_func_extra_bit_or=no # Group function BIT_OR
+group_func_extra_count_distinct_list=no # Group function COUNT(DISTINCT expr,expr,...)
+group_func_extra_std=no # Group function STD
+group_func_extra_stddev=no # Group function STDDEV
+group_func_extra_variance=no # Group function VARIANCE
+group_func_sql_any=no # Group function ANY
+group_func_sql_avg=yes # Group function AVG
+group_func_sql_count_*=yes # Group function COUNT (*)
+group_func_sql_count_column=yes # Group function COUNT column name
+group_func_sql_count_distinct=yes # Group function COUNT(DISTINCT expr)
+group_func_sql_every=no # Group function EVERY
+group_func_sql_max=yes # Group function MAX on numbers
+group_func_sql_max_str=yes # Group function MAX on strings
+group_func_sql_min=yes # Group function MIN on numbers
+group_func_sql_min_str=yes # Group function MIN on strings
+group_func_sql_some=no # Group function SOME
+group_func_sql_sum=yes # Group function SUM
+group_functions=yes # Group functions
+group_on_unused=yes # Group on unused column
+has_true_false=no # TRUE and FALSE
+having=yes # Having
+having_with_alias=no # Having on alias
+having_with_group=yes # Having with group function
+hex_numbers=yes # hex numbers (0x41)
+hex_strings=no # hex strings (x'1ace')
+ignore_end_space=yes # Ignore end space in compare
+index_in_create=no # index in create table
+index_namespace=no # different namespace for index
+index_parts=no # index on column part (extension)
+inner_join=yes # inner join
+insert_empty_string=no # insert empty string
+insert_multi_value=no # INSERT with Value lists
+insert_select=no # insert INTO ... SELECT ...
+insert_with_set=no # INSERT with set syntax
+intersect=no # intersect
+intersect_all=no # intersect all
+intersect_all_incompat=no # intersect all (incompatible lists)
+intersect_incompat=no # intersect (incompatible lists)
+join_tables=+64 # tables in join
+left_outer_join=yes # left outer join
+left_outer_join_using=no # left outer join using
+like_with_column=no # column LIKE column
+like_with_number=no # LIKE on numbers
+lock_tables=no # lock table
+logical_value=not supported # Value of logical operation (1=1)
+max_big_expressions=1 # big expressions
+max_char_size=32767 # max char() size
+max_columns=4759 # Columns in table
+max_conditions=5888 # OR and AND in WHERE
+max_expressions=+10000 # simple expressions
+max_index=+64 # max index
+max_index_name=31 # index name length
+max_index_parts=16 # index parts
+max_index_varchar_part_length=249 # index varchar part length
+max_row_length=64744 # max table row length (without blobs)
+max_row_length_with_null=64744 # table row length with nulls (without blobs)
+max_select_alias_name=132 # select alias name length
+max_stack_expression=165 # stacked expressions
+max_table_alias_name=255 # table alias name length
+max_table_name=31 # table name length
+max_unique_index=+64 # unique indexes
+max_varchar_size=10923 # max varchar() size
+minus=no # minus
+minus_incompat=no # minus (incompatible lists)
+minus_neg=yes # Calculate 1--1
+multi_drop=no # many tables to drop table
+multi_strings=no # Multiple line strings
+multi_table_delete=no # DELETE FROM table1,table2...
+multi_table_update=no # Update with many tables
+natural_join=no # natural join
+natural_join_incompat=no # natural join (incompatible lists)
+natural_left_outer_join=no # natural left outer join
+no_primary_key=yes # Tables without primary key
+null_concat_expr=no # Is 'a' || NULL = NULL
+null_in_index=yes # null in index
+null_in_unique=no # null in unique index
+null_num_expr=no # Is 1+NULL = NULL
+nulls_in_unique=no # null combination in unique index
+odbc_left_outer_join=no # left outer join odbc style
+operating_system=Linux 2.4.4-64GB-SMP i686 # crash-me tested on
+order_by=yes # Order by
+order_by_alias=no # Order by alias
+order_by_function=no # Order by function
+order_by_position=yes # Order by position
+order_by_remember_desc=no # Order by DESC is remembered
+order_on_unused=yes # Order by on unused column
+primary_key_in_create=yes # primary key in create table
+psm_functions=no # PSM functions (ANSI SQL)
+psm_modules=no # PSM modules (ANSI SQL)
+psm_procedures=no # PSM procedures (ANSI SQL)
+psm_trigger=no # Triggers (ANSI SQL)
+query_size=65535 # query size
+quote_ident_with_"=yes # " as identifier quote (ANSI SQL)
+quote_ident_with_[=no # [] as identifier quote
+quote_ident_with_`=no # ` as identifier quote
+quote_with_"=no # Allows ' and " as string markers
+recursive_subqueries=61 # recursive subqueries
+remember_end_space=no # Remembers end space in char()
+remember_end_space_varchar=yes # Remembers end space in varchar()
+rename_table=no # rename table
+right_outer_join=yes # right outer join
+rowid=no # Type for row id
+select_constants=yes # Select constants
+select_limit=no # LIMIT number of rows
+select_limit2=no # SELECT with LIMIT #,#
+select_string_size=32767 # constant string size in SELECT
+select_table_update=yes # Update with sub select
+select_without_from=no # SELECT without FROM
+server_version=6.0.1 # server version
+simple_joins=yes # ANSI SQL simple joins
+storage_of_float=round # Storage of float values
+subqueries=yes # subqueries
+table_alias=no # Table alias
+table_name_case=yes # case independent table names
+table_wildcard=yes # Select table_name.*
+temporary_table=no # temporary tables
+transactions=error # constant string size in where
+truncate_table=no # truncate
+type_extra_abstime=no # Type abstime
+type_extra_bfile=no # Type bfile
+type_extra_blob=yes # Type blob
+type_extra_bool=no # Type bool
+type_extra_box=no # Type box
+type_extra_byte=no # Type byte
+type_extra_char(1_arg)_binary=no # Type char(1 arg) binary
+type_extra_cidr=no # Type cidr
+type_extra_circle=no # Type circle
+type_extra_clob=no # Type clob
+type_extra_datetime=no # Type datetime
+type_extra_double=no # Type double
+type_extra_enum(1_arg)=no # Type enum(1 arg)
+type_extra_float(2_arg)=no # Type float(2 arg)
+type_extra_float4=no # Type float4
+type_extra_float8=no # Type float8
+type_extra_image=no # Type image
+type_extra_inet=no # Type inet
+type_extra_int(1_arg)_zerofill=no # Type int(1 arg) zerofill
+type_extra_int1=no # Type int1
+type_extra_int2=no # Type int2
+type_extra_int3=no # Type int3
+type_extra_int4=no # Type int4
+type_extra_int8=no # Type int8
+type_extra_int_auto_increment=no # Type int not null auto_increment
+type_extra_int_identity=no # Type int not null identity
+type_extra_int_unsigned=no # Type int unsigned
+type_extra_interval=no # Type interval
+type_extra_line=no # Type line
+type_extra_long=no # Type long
+type_extra_long_raw=no # Type long raw
+type_extra_long_varbinary=no # Type long varbinary
+type_extra_long_varchar(1_arg)=no # Type long varchar(1 arg)
+type_extra_lseg=no # Type lseg
+type_extra_macaddr=no # Type macaddr
+type_extra_mediumint=no # Type mediumint
+type_extra_mediumtext=no # Type mediumtext
+type_extra_middleint=no # Type middleint
+type_extra_mlslabel=no # Type mlslabel
+type_extra_money=no # Type money
+type_extra_nclob=no # Type nclob
+type_extra_number=no # Type number
+type_extra_number(1_arg)=no # Type number(1 arg)
+type_extra_number(2_arg)=no # Type number(2 arg)
+type_extra_nvarchar2(1_arg)=no # Type nvarchar2(1 arg)
+type_extra_path=no # Type path
+type_extra_point=no # Type point
+type_extra_polygon=no # Type polygon
+type_extra_raw(1_arg)=no # Type raw(1 arg)
+type_extra_reltime=no # Type reltime
+type_extra_rowid=no # Type rowid
+type_extra_serial=no # Type serial
+type_extra_set(1_arg)=no # Type set(1 arg)
+type_extra_smalldatetime=no # Type smalldatetime
+type_extra_smallfloat=no # Type smallfloat
+type_extra_smallmoney=no # Type smallmoney
+type_extra_text=no # Type text
+type_extra_text(1_arg)=no # Type text(1 arg)
+type_extra_timespan=no # Type timespan
+type_extra_uint=no # Type uint
+type_extra_varchar2(1_arg)=no # Type varchar2(1 arg)
+type_extra_year=no # Type year
+type_odbc_bigint=no # Type bigint
+type_odbc_binary(1_arg)=no # Type binary(1 arg)
+type_odbc_datetime=no # Type datetime
+type_odbc_tinyint=no # Type tinyint
+type_odbc_varbinary(1_arg)=no # Type varbinary(1 arg)
+type_sql_=no # Type
+type_sql_bit=no # Type bit
+type_sql_bit(1_arg)=no # Type bit(1 arg)
+type_sql_bit_varying(1_arg)=no # Type bit varying(1 arg)
+type_sql_boolean=no # Type boolean
+type_sql_char(1_arg)=yes # Type char(1 arg)
+type_sql_char_varying(1_arg)=yes # Type char varying(1 arg)
+type_sql_character(1_arg)=yes # Type character(1 arg)
+type_sql_character_varying(1_arg)=yes # Type character varying(1 arg)
+type_sql_date=yes # Type date
+type_sql_dec(2_arg)=yes # Type dec(2 arg)
+type_sql_decimal(2_arg)=yes # Type decimal(2 arg)
+type_sql_double_precision=yes # Type double precision
+type_sql_float=yes # Type float
+type_sql_float(1_arg)=yes # Type float(1 arg)
+type_sql_int=yes # Type int
+type_sql_integer=yes # Type integer
+type_sql_interval_day=no # Type interval day
+type_sql_interval_day_to_hour=no # Type interval day to hour
+type_sql_interval_day_to_minute=no # Type interval day to minute
+type_sql_interval_day_to_second=no # Type interval day to second
+type_sql_interval_hour=no # Type interval hour
+type_sql_interval_hour_to_minute=no # Type interval hour to minute
+type_sql_interval_hour_to_second=no # Type interval hour to second
+type_sql_interval_minute=no # Type interval minute
+type_sql_interval_minute_to_second=no # Type interval minute to second
+type_sql_interval_month=no # Type interval month
+type_sql_interval_second=no # Type interval second
+type_sql_interval_year=no # Type interval year
+type_sql_interval_year_to_month=no # Type interval year to month
+type_sql_national_char_varying(1_arg)=yes # Type national char varying(1 arg)
+type_sql_national_character(1_arg)=yes # Type national character(1 arg)
+type_sql_national_character_varying(1_arg)=yes # Type national character varying(1 arg)
+type_sql_nchar(1_arg)=yes # Type nchar(1 arg)
+type_sql_nchar_varying(1_arg)=yes # Type nchar varying(1 arg)
+type_sql_numeric(2_arg)=yes # Type numeric(2 arg)
+type_sql_real=yes # Type real
+type_sql_smallint=yes # Type smallint
+type_sql_time=yes # Type time
+type_sql_timestamp=yes # Type timestamp
+type_sql_timestamp_with_time_zone=no # Type timestamp with time zone
+type_sql_varchar(1_arg)=yes # Type varchar(1 arg)
+union=yes # union
+union_all=yes # union all
+union_all_incompat=yes # union all (incompatible lists)
+union_incompat=yes # union (incompatible lists)
+unique_in_create=yes # unique in create table
+unique_null_in_create=no # unique null in create
+views=no # views
+where_string_size=32767 # constant string size in where
diff --git a/sql-bench/limits/interbase-superserver.cfg b/sql-bench/limits/interbase-superserver.cfg
new file mode 100644
index 00000000000..87da0d0633c
--- /dev/null
+++ b/sql-bench/limits/interbase-superserver.cfg
@@ -0,0 +1,514 @@
+#This file is automaticly generated by crash-me 1.57
+
+NEG=no # update of column= -column
+Need_cast_for_null=no # Need to cast NULL for arithmetic
+alter_add_col=yes # Alter table add column
+alter_add_constraint=yes # Alter table add constraint
+alter_add_foreign_key=yes # Alter table add foreign key
+alter_add_multi_col=with add # Alter table add many columns
+alter_add_primary_key=with constraint # Alter table add primary key
+alter_add_unique=no # Alter table add unique
+alter_alter_col=no # Alter table alter column default
+alter_change_col=no # Alter table change column
+alter_drop_col=no # Alter table drop column
+alter_drop_constraint=yes # Alter table drop constraint
+alter_drop_foreign_key=with drop constraint # Alter table drop foreign key
+alter_drop_primary_key=no # Alter table drop primary key
+alter_drop_unique=no # Alter table drop unique
+alter_modify_col=no # Alter table modify column
+alter_rename_table=no # Alter table rename table
+atomic_updates=no # atomic updates
+automatic_rowid=no # Automatic row id
+binary_numbers=yes # binary numbers (0b1001)
+binary_strings=no # binary strings (b'0110')
+case_insensitive_strings=no # Case insensitive compare
+char_is_space_filled=yes # char are space filled
+column_alias=yes # Column alias
+columns_in_order_by=37 # number of columns in order by
+comment_#=no # # as comment
+comment_--=no # -- as comment (ANSI)
+comment_/**/=yes # /* */ as comment
+comment_//=no # // as comment
+compute=no # Compute
+connections=395 # Simultaneous connections (installation default)
+constraint_check=no # Column constraints
+constraint_check_table=no # Table constraints
+constraint_null=no # NULL constraint (SyBase style)
+crash_me_safe=no # crash me safe
+crash_me_version=1.57 # crash me version
+create_default=yes # default value for column
+create_default_func=no # default value function for column
+create_if_not_exists=no # create table if not exists
+create_index=yes # create index
+create_schema=no # Create SCHEMA
+create_table_select=no # create table from select
+cross_join=no # cross join (same as from a,b)
+date_infinity=no # Supports 'infinity dates
+date_last=error # Supports 9999-12-31 dates
+date_one=error # Supports 0001-01-01 dates
+date_with_YY=no # Supports YY-MM-DD dates
+date_zero=no # Supports 0000-00-00 dates
+domains=no # Domains (ANSI SQL)
+double_quotes=yes # Double '' as ' in strings
+drop_if_exists=no # drop table if exists
+drop_index=yes # drop index
+drop_requires_cascade=no # drop table require cascade/restrict
+drop_restrict=no # drop table with cascade/restrict
+end_colon=yes # allows end ';'
+except=no # except
+except_all=no # except all
+except_all_incompat=no # except all (incompatible lists)
+except_incompat=no # except (incompatible lists)
+float_int_expr=yes # mixing of integer and float in expression
+foreign_key_syntax=no # foreign key syntax
+full_outer_join=yes # full outer join
+func_extra_!=no # Function NOT as '!' in SELECT
+func_extra_%=no # Function MOD as %
+func_extra_&=no # Function & (bitwise and)
+func_extra_&&=no # Function AND as '&&'
+func_extra_<>=no # Function <> in SELECT
+func_extra_==no # Function =
+func_extra_add_months=no # Function ADD_MONTHS
+func_extra_and_or=no # Function AND and OR in SELECT
+func_extra_ascii_char=no # Function ASCII_CHAR
+func_extra_ascii_code=no # Function ASCII_CODE
+func_extra_atn2=no # Function ATN2
+func_extra_auto_num2string=no # Function automatic num->string convert
+func_extra_auto_string2num=no # Function automatic string->num convert
+func_extra_between=no # Function BETWEEN in SELECT
+func_extra_binary_shifts=no # Function << and >> (bitwise shifts)
+func_extra_bit_count=no # Function BIT_COUNT
+func_extra_ceil=no # Function CEIL
+func_extra_charindex=no # Function CHARINDEX
+func_extra_chr=no # Function CHR
+func_extra_concat_as_+=no # Function concatenation with +
+func_extra_concat_list=no # Function CONCAT(list)
+func_extra_convert=no # Function CONVERT
+func_extra_cosh=no # Function COSH
+func_extra_date_format=no # Function DATE_FORMAT
+func_extra_dateadd=no # Function DATEADD
+func_extra_datediff=no # Function DATEDIFF
+func_extra_datename=no # Function DATENAME
+func_extra_datepart=no # Function DATEPART
+func_extra_elt=no # Function ELT
+func_extra_encrypt=no # Function ENCRYPT
+func_extra_field=no # Function FIELD
+func_extra_format=no # Function FORMAT
+func_extra_from_days=no # Function FROM_DAYS
+func_extra_from_unixtime=no # Function FROM_UNIXTIME
+func_extra_getdate=no # Function GETDATE
+func_extra_greatest=no # Function GREATEST
+func_extra_if=no # Function IF
+func_extra_in_num=no # Function IN on numbers in SELECT
+func_extra_in_str=no # Function IN on strings in SELECT
+func_extra_initcap=no # Function INITCAP
+func_extra_instr=no # Function LOCATE as INSTR
+func_extra_instr_oracle=no # Function INSTR (Oracle syntax)
+func_extra_instrb=no # Function INSTRB
+func_extra_interval=no # Function INTERVAL
+func_extra_last_day=no # Function LAST_DAY
+func_extra_last_insert_id=no # Function LAST_INSERT_ID
+func_extra_least=no # Function LEAST
+func_extra_lengthb=no # Function LENGTHB
+func_extra_like=no # Function LIKE in SELECT
+func_extra_like_escape=no # Function LIKE ESCAPE in SELECT
+func_extra_ln=no # Function LN
+func_extra_log(m_n)=no # Function LOG(m,n)
+func_extra_logn=no # Function LOGN
+func_extra_lpad=no # Function LPAD
+func_extra_mdy=no # Function MDY
+func_extra_mid=no # Function SUBSTRING as MID
+func_extra_months_between=no # Function MONTHS_BETWEEN
+func_extra_not=no # Function NOT in SELECT
+func_extra_not_between=no # Function NOT BETWEEN in SELECT
+func_extra_not_like=no # Function NOT LIKE in SELECT
+func_extra_odbc_convert=no # Function ODBC CONVERT
+func_extra_password=no # Function PASSWORD
+func_extra_paste=no # Function PASTE
+func_extra_patindex=no # Function PATINDEX
+func_extra_period_add=no # Function PERIOD_ADD
+func_extra_period_diff=no # Function PERIOD_DIFF
+func_extra_pow=no # Function POW
+func_extra_range=no # Function RANGE
+func_extra_regexp=no # Function REGEXP in SELECT
+func_extra_replicate=no # Function REPLICATE
+func_extra_reverse=no # Function REVERSE
+func_extra_root=no # Function ROOT
+func_extra_round1=no # Function ROUND(1 arg)
+func_extra_rpad=no # Function RPAD
+func_extra_sec_to_time=no # Function SEC_TO_TIME
+func_extra_sinh=no # Function SINH
+func_extra_str=no # Function STR
+func_extra_strcmp=no # Function STRCMP
+func_extra_stuff=no # Function STUFF
+func_extra_substrb=no # Function SUBSTRB
+func_extra_substring_index=no # Function SUBSTRING_INDEX
+func_extra_sysdate=no # Function SYSDATE
+func_extra_tail=no # Function TAIL
+func_extra_tanh=no # Function TANH
+func_extra_time_to_sec=no # Function TIME_TO_SEC
+func_extra_to_days=no # Function TO_DAYS
+func_extra_translate=no # Function TRANSLATE
+func_extra_trim_many_char=no # Function TRIM; Many char extension
+func_extra_trim_substring=no # Function TRIM; Substring extension
+func_extra_trunc=no # Function TRUNC
+func_extra_uid=no # Function UID
+func_extra_unix_timestamp=no # Function UNIX_TIMESTAMP
+func_extra_userenv=no # Function USERENV
+func_extra_version=no # Function VERSION
+func_extra_weekday=no # Function WEEKDAY
+func_extra_|=no # Function | (bitwise or)
+func_extra_||=no # Function OR as '||'
+func_extra_~*=no # Function ~* (case insensitive compare)
+func_odbc_abs=no # Function ABS
+func_odbc_acos=no # Function ACOS
+func_odbc_ascii=no # Function ASCII
+func_odbc_asin=no # Function ASIN
+func_odbc_atan=no # Function ATAN
+func_odbc_atan2=no # Function ATAN2
+func_odbc_ceiling=no # Function CEILING
+func_odbc_char=no # Function CHAR
+func_odbc_concat=no # Function CONCAT(2 arg)
+func_odbc_cos=no # Function COS
+func_odbc_cot=no # Function COT
+func_odbc_curdate=no # Function CURDATE
+func_odbc_curtime=no # Function CURTIME
+func_odbc_database=no # Function DATABASE
+func_odbc_dayname=no # Function DAYNAME
+func_odbc_dayofmonth=no # Function DAYOFMONTH
+func_odbc_dayofweek=no # Function DAYOFWEEK
+func_odbc_dayofyear=no # Function DAYOFYEAR
+func_odbc_degrees=no # Function DEGREES
+func_odbc_difference=no # Function DIFFERENCE()
+func_odbc_exp=no # Function EXP
+func_odbc_floor=no # Function FLOOR
+func_odbc_fn_left=no # Function ODBC syntax LEFT & RIGHT
+func_odbc_hour=no # Function HOUR
+func_odbc_hour_time=no # Function ANSI HOUR
+func_odbc_ifnull=no # Function IFNULL
+func_odbc_insert=no # Function INSERT
+func_odbc_lcase=no # Function LCASE
+func_odbc_left=no # Function LEFT
+func_odbc_length=no # Function REAL LENGTH
+func_odbc_length_without_space=no # Function ODBC LENGTH
+func_odbc_locate_2=no # Function LOCATE(2 arg)
+func_odbc_locate_3=no # Function LOCATE(3 arg)
+func_odbc_log=no # Function LOG
+func_odbc_log10=no # Function LOG10
+func_odbc_ltrim=no # Function LTRIM
+func_odbc_minute=no # Function MINUTE
+func_odbc_mod=no # Function MOD
+func_odbc_month=no # Function MONTH
+func_odbc_monthname=no # Function MONTHNAME
+func_odbc_now=no # Function NOW
+func_odbc_pi=no # Function PI
+func_odbc_power=no # Function POWER
+func_odbc_quarter=no # Function QUARTER
+func_odbc_radians=no # Function RADIANS
+func_odbc_rand=no # Function RAND
+func_odbc_repeat=no # Function REPEAT
+func_odbc_replace=no # Function REPLACE
+func_odbc_right=no # Function RIGHT
+func_odbc_round=no # Function ROUND(2 arg)
+func_odbc_rtrim=no # Function RTRIM
+func_odbc_second=no # Function SECOND
+func_odbc_sign=no # Function SIGN
+func_odbc_sin=no # Function SIN
+func_odbc_soundex=no # Function SOUNDEX
+func_odbc_space=no # Function SPACE
+func_odbc_sqrt=no # Function SQRT
+func_odbc_substring=no # Function ODBC SUBSTRING
+func_odbc_tan=no # Function TAN
+func_odbc_timestampadd=no # Function TIMESTAMPADD
+func_odbc_timestampdiff=no # Function TIMESTAMPDIFF
+func_odbc_truncate=no # Function TRUNCATE
+func_odbc_ucase=no # Function UCASE
+func_odbc_user()=no # Function USER()
+func_odbc_week=no # Function WEEK
+func_odbc_year=no # Function YEAR
+func_sql_+=yes # Function +, -, * and /
+func_sql_bit_length=no # Function BIT_LENGTH
+func_sql_cast=yes # Function CAST
+func_sql_char_length=no # Function CHAR_LENGTH
+func_sql_char_length(constant)=no # Function CHAR_LENGTH(constant)
+func_sql_character_length=no # Function CHARACTER_LENGTH
+func_sql_coalesce=no # Function COALESCE
+func_sql_concat_as_||=yes # Function concatenation with ||
+func_sql_current_date=yes # Function CURRENT_DATE
+func_sql_current_time=yes # Function CURRENT_TIME
+func_sql_current_timestamp=yes # Function CURRENT_TIMESTAMP
+func_sql_current_user=no # Function CURRENT_USER
+func_sql_extract_sql=yes # Function EXTRACT
+func_sql_localtime=no # Function LOCALTIME
+func_sql_localtimestamp=no # Function LOCALTIMESTAMP
+func_sql_lower=no # Function LOWER
+func_sql_nullif_num=no # Function NULLIF with numbers
+func_sql_nullif_string=no # Function NULLIF with strings
+func_sql_octet_length=no # Function OCTET_LENGTH
+func_sql_position=no # Function POSITION
+func_sql_searched_case=no # Function searched CASE
+func_sql_session_user=no # Function SESSION_USER
+func_sql_simple_case=no # Function simple CASE
+func_sql_substring=no # Function ANSI SQL SUBSTRING
+func_sql_system_user=no # Function SYSTEM_USER
+func_sql_trim=no # Function TRIM
+func_sql_upper=yes # Function UPPER
+func_sql_user=yes # Function USER
+func_where_between=yes # Function BETWEEN
+func_where_eq_all=yes # Function = ALL
+func_where_eq_any=yes # Function = ANY
+func_where_eq_some=yes # Function = SOME
+func_where_exists=yes # Function EXISTS
+func_where_in_num=yes # Function IN on numbers
+func_where_like=yes # Function LIKE
+func_where_like_escape=yes # Function LIKE ESCAPE
+func_where_match=no # Function MATCH
+func_where_match_unique=no # Function MATCH UNIQUE
+func_where_matches=no # Function MATCHES
+func_where_not_between=yes # Function NOT BETWEEN
+func_where_not_exists=yes # Function NOT EXISTS
+func_where_not_like=yes # Function NOT LIKE
+func_where_not_unique=no # Function NOT UNIQUE
+func_where_unique=no # Function UNIQUE
+functions=yes # Functions
+group_by=yes # Group by
+group_by_alias=no # Group by alias
+group_by_null=yes # Group on column with null values
+group_by_position=no # Group by position
+group_distinct_functions=yes # Group functions with distinct
+group_func_extra_bit_and=no # Group function BIT_AND
+group_func_extra_bit_or=no # Group function BIT_OR
+group_func_extra_count_distinct_list=no # Group function COUNT(DISTINCT expr,expr,...)
+group_func_extra_std=no # Group function STD
+group_func_extra_stddev=no # Group function STDDEV
+group_func_extra_variance=no # Group function VARIANCE
+group_func_sql_any=no # Group function ANY
+group_func_sql_avg=yes # Group function AVG
+group_func_sql_count_*=yes # Group function COUNT (*)
+group_func_sql_count_column=yes # Group function COUNT column name
+group_func_sql_count_distinct=yes # Group function COUNT(DISTINCT expr)
+group_func_sql_every=no # Group function EVERY
+group_func_sql_max=yes # Group function MAX on numbers
+group_func_sql_max_str=yes # Group function MAX on strings
+group_func_sql_min=yes # Group function MIN on numbers
+group_func_sql_min_str=yes # Group function MIN on strings
+group_func_sql_some=no # Group function SOME
+group_func_sql_sum=yes # Group function SUM
+group_functions=yes # Group functions
+group_on_unused=yes # Group on unused column
+has_true_false=no # TRUE and FALSE
+having=yes # Having
+having_with_alias=no # Having on alias
+having_with_group=yes # Having with group function
+hex_numbers=yes # hex numbers (0x41)
+hex_strings=no # hex strings (x'1ace')
+ignore_end_space=yes # Ignore end space in compare
+index_in_create=no # index in create table
+index_namespace=no # different namespace for index
+index_parts=no # index on column part (extension)
+inner_join=yes # inner join
+insert_empty_string=no # insert empty string
+insert_multi_value=no # INSERT with Value lists
+insert_select=no # insert INTO ... SELECT ...
+insert_with_set=no # INSERT with set syntax
+intersect=no # intersect
+intersect_all=no # intersect all
+intersect_all_incompat=no # intersect all (incompatible lists)
+intersect_incompat=no # intersect (incompatible lists)
+join_tables=+64 # tables in join
+left_outer_join=yes # left outer join
+left_outer_join_using=no # left outer join using
+like_with_column=no # column LIKE column
+like_with_number=no # LIKE on numbers
+lock_tables=no # lock table
+logical_value=not supported # Value of logical operation (1=1)
+max_big_expressions=1 # big expressions
+max_char_size=32745 # max char() size
+max_column_name=18 # column name length
+max_columns=4759 # Columns in table
+max_conditions=441504 # OR and AND in WHERE
+max_expressions=5486 # simple expressions
+max_index=+64 # max index
+max_index_name=31 # index name length
+max_index_parts=16 # index parts
+max_index_varchar_part_length=218 # index varchar part length
+max_row_length=64744 # max table row length (without blobs)
+max_row_length_with_null=64744 # table row length with nulls (without blobs)
+max_select_alias_name=132 # select alias name length
+max_stack_expression=165 # stacked expressions
+max_table_alias_name=255 # table alias name length
+max_table_name=31 # table name length
+max_unique_index=+64 # unique indexes
+max_varchar_size=32745 # max varchar() size
+minus=no # minus
+minus_incompat=no # minus (incompatible lists)
+minus_neg=yes # Calculate 1--1
+multi_drop=no # many tables to drop table
+multi_strings=no # Multiple line strings
+multi_table_delete=no # DELETE FROM table1,table2...
+multi_table_update=no # Update with many tables
+natural_join=no # natural join
+natural_join_incompat=no # natural join (incompatible lists)
+natural_left_outer_join=no # natural left outer join
+no_primary_key=yes # Tables without primary key
+null_concat_expr=no # Is 'a' || NULL = NULL
+null_in_index=yes # null in index
+null_in_unique=no # null in unique index
+null_num_expr=no # Is 1+NULL = NULL
+nulls_in_unique=no # null combination in unique index
+odbc_left_outer_join=no # left outer join odbc style
+operating_system=Linux 2.4.4-64GB-SMP i686 # crash-me tested on
+order_by=yes # Order by
+order_by_alias=no # Order by alias
+order_by_function=no # Order by function
+order_by_position=yes # Order by position
+order_by_remember_desc=no # Order by DESC is remembered
+order_on_unused=yes # Order by on unused column
+primary_key_in_create=yes # primary key in create table
+psm_functions=no # PSM functions (ANSI SQL)
+psm_modules=no # PSM modules (ANSI SQL)
+psm_procedures=no # PSM procedures (ANSI SQL)
+psm_trigger=no # Triggers (ANSI SQL)
+query_size=16777216 # query size
+quote_ident_with_"=yes # " as identifier quote (ANSI SQL)
+quote_ident_with_[=no # [] as identifier quote
+quote_ident_with_`=no # ` as identifier quote
+quote_with_"=no # Allows ' and " as string markers
+recursive_subqueries=61 # recursive subqueries
+remember_end_space=no # Remembers end space in char()
+remember_end_space_varchar=yes # Remembers end space in varchar()
+rename_table=no # rename table
+right_outer_join=yes # right outer join
+rowid=no # Type for row id
+select_constants=yes # Select constants
+select_limit=no # LIMIT number of rows
+select_limit2=no # SELECT with LIMIT #,#
+select_string_size=32767 # constant string size in SELECT
+select_table_update=yes # Update with sub select
+select_without_from=no # SELECT without FROM
+server_version=6.0.1 # server version
+simple_joins=yes # ANSI SQL simple joins
+storage_of_float=round # Storage of float values
+subqueries=yes # subqueries
+table_alias=no # Table alias
+table_name_case=yes # case independent table names
+table_wildcard=yes # Select table_name.*
+temporary_table=no # temporary tables
+transactions=error # constant string size in where
+truncate_table=no # truncate
+type_extra_abstime=no # Type abstime
+type_extra_bfile=no # Type bfile
+type_extra_blob=yes # Type blob
+type_extra_bool=no # Type bool
+type_extra_box=no # Type box
+type_extra_byte=no # Type byte
+type_extra_char(1_arg)_binary=no # Type char(1 arg) binary
+type_extra_cidr=no # Type cidr
+type_extra_circle=no # Type circle
+type_extra_clob=no # Type clob
+type_extra_datetime=no # Type datetime
+type_extra_double=no # Type double
+type_extra_enum(1_arg)=no # Type enum(1 arg)
+type_extra_float(2_arg)=no # Type float(2 arg)
+type_extra_float4=no # Type float4
+type_extra_float8=no # Type float8
+type_extra_image=no # Type image
+type_extra_inet=no # Type inet
+type_extra_int(1_arg)_zerofill=no # Type int(1 arg) zerofill
+type_extra_int1=no # Type int1
+type_extra_int2=no # Type int2
+type_extra_int3=no # Type int3
+type_extra_int4=no # Type int4
+type_extra_int8=no # Type int8
+type_extra_int_auto_increment=no # Type int not null auto_increment
+type_extra_int_identity=no # Type int not null identity
+type_extra_int_unsigned=no # Type int unsigned
+type_extra_interval=no # Type interval
+type_extra_line=no # Type line
+type_extra_long=no # Type long
+type_extra_long_raw=no # Type long raw
+type_extra_long_varbinary=no # Type long varbinary
+type_extra_long_varchar(1_arg)=no # Type long varchar(1 arg)
+type_extra_lseg=no # Type lseg
+type_extra_macaddr=no # Type macaddr
+type_extra_mediumint=no # Type mediumint
+type_extra_mediumtext=no # Type mediumtext
+type_extra_middleint=no # Type middleint
+type_extra_mlslabel=no # Type mlslabel
+type_extra_money=no # Type money
+type_extra_nclob=no # Type nclob
+type_extra_number=no # Type number
+type_extra_number(1_arg)=no # Type number(1 arg)
+type_extra_number(2_arg)=no # Type number(2 arg)
+type_extra_nvarchar2(1_arg)=no # Type nvarchar2(1 arg)
+type_extra_path=no # Type path
+type_extra_point=no # Type point
+type_extra_polygon=no # Type polygon
+type_extra_raw(1_arg)=no # Type raw(1 arg)
+type_extra_reltime=no # Type reltime
+type_extra_rowid=no # Type rowid
+type_extra_serial=no # Type serial
+type_extra_set(1_arg)=no # Type set(1 arg)
+type_extra_smalldatetime=no # Type smalldatetime
+type_extra_smallfloat=no # Type smallfloat
+type_extra_smallmoney=no # Type smallmoney
+type_extra_text=no # Type text
+type_extra_text(1_arg)=no # Type text(1 arg)
+type_extra_timespan=no # Type timespan
+type_extra_uint=no # Type uint
+type_extra_varchar2(1_arg)=no # Type varchar2(1 arg)
+type_extra_year=no # Type year
+type_odbc_bigint=no # Type bigint
+type_odbc_binary(1_arg)=no # Type binary(1 arg)
+type_odbc_datetime=no # Type datetime
+type_odbc_tinyint=no # Type tinyint
+type_odbc_varbinary(1_arg)=no # Type varbinary(1 arg)
+type_sql_bit=no # Type bit
+type_sql_bit(1_arg)=no # Type bit(1 arg)
+type_sql_bit_varying(1_arg)=no # Type bit varying(1 arg)
+type_sql_boolean=no # Type boolean
+type_sql_char(1_arg)=yes # Type char(1 arg)
+type_sql_char_varying(1_arg)=yes # Type char varying(1 arg)
+type_sql_character(1_arg)=yes # Type character(1 arg)
+type_sql_character_varying(1_arg)=yes # Type character varying(1 arg)
+type_sql_date=yes # Type date
+type_sql_dec(2_arg)=yes # Type dec(2 arg)
+type_sql_decimal(2_arg)=yes # Type decimal(2 arg)
+type_sql_double_precision=yes # Type double precision
+type_sql_float=yes # Type float
+type_sql_float(1_arg)=yes # Type float(1 arg)
+type_sql_int=yes # Type int
+type_sql_integer=yes # Type integer
+type_sql_interval_day=no # Type interval day
+type_sql_interval_day_to_hour=no # Type interval day to hour
+type_sql_interval_day_to_minute=no # Type interval day to minute
+type_sql_interval_day_to_second=no # Type interval day to second
+type_sql_interval_hour=no # Type interval hour
+type_sql_interval_hour_to_minute=no # Type interval hour to minute
+type_sql_interval_hour_to_second=no # Type interval hour to second
+type_sql_interval_minute=no # Type interval minute
+type_sql_interval_minute_to_second=no # Type interval minute to second
+type_sql_interval_month=no # Type interval month
+type_sql_interval_second=no # Type interval second
+type_sql_interval_year=no # Type interval year
+type_sql_interval_year_to_month=no # Type interval year to month
+type_sql_national_char_varying(1_arg)=yes # Type national char varying(1 arg)
+type_sql_national_character(1_arg)=yes # Type national character(1 arg)
+type_sql_national_character_varying(1_arg)=yes # Type national character varying(1 arg)
+type_sql_nchar(1_arg)=yes # Type nchar(1 arg)
+type_sql_nchar_varying(1_arg)=yes # Type nchar varying(1 arg)
+type_sql_numeric(2_arg)=yes # Type numeric(2 arg)
+type_sql_real=yes # Type real
+type_sql_smallint=yes # Type smallint
+type_sql_time=yes # Type time
+type_sql_timestamp=yes # Type timestamp
+type_sql_timestamp_with_time_zone=no # Type timestamp with time zone
+type_sql_varchar(1_arg)=yes # Type varchar(1 arg)
+union=yes # union
+union_all=yes # union all
+union_all_incompat=yes # union all (incompatible lists)
+union_incompat=yes # union (incompatible lists)
+unique_in_create=yes # unique in create table
+unique_null_in_create=no # unique null in create
+views=no # views
+where_string_size=32767 # constant string size in where
diff --git a/sql-bench/run-all-tests.sh b/sql-bench/run-all-tests.sh
index c2f687a9375..f392431140c 100644
--- a/sql-bench/run-all-tests.sh
+++ b/sql-bench/run-all-tests.sh
@@ -109,7 +109,9 @@ print "Running tests on: $machine\n";
print "Arguments: $log_prog_args\n";
print "Comments: $opt_comments\n";
print "Limits from: $opt_cmp\n";
-print "Server version: $server_version\n\n";
+print "Server version: $server_version\n";
+print "Optimization: $opt_optimization\n";
+print "Hardware: $opt_hw\n\n";
$estimated=$warning=$got_warning=0;
@@ -195,6 +197,10 @@ while (<test-*>)
print "Summary for $prog: ", join(" ",@prog_sum), "\n";
}
}
+ elsif ($last_line =~ /^Test skipped/i)
+ {
+ print "$last_line\n";
+ }
else
{
$errors++;
@@ -281,10 +287,6 @@ sub read_headers
{
$log_prog_args=$1;
}
- elsif (/^Comments.*:\s+(.*)$/)
- {
- $opt_comments=$1;
- }
elsif (/^Limits.*:\s+(.*)$/)
{
$opt_cmp=$1;
@@ -293,6 +295,14 @@ sub read_headers
{
$server_version=$1;
}
+ elsif (/^Optimiz.*:\s+(.*)$/)
+ {
+ $opt_optimization=$1;
+ }
+ elsif (/^Hardwar.*:\s+(.*)$/)
+ {
+ $opt_hw=$1;
+ }
}
close(TMP);
}
diff --git a/sql-bench/server-cfg.sh b/sql-bench/server-cfg.sh
index 886c428e3b9..a4e74fcb4f9 100644
--- a/sql-bench/server-cfg.sh
+++ b/sql-bench/server-cfg.sh
@@ -33,10 +33,10 @@
sub get_server
{
- my ($name,$host,$database,$odbc,$machine)=@_;
+ my ($name,$host,$database,$odbc,$machine,$socket)=@_;
my ($server);
if ($name =~ /mysql/i)
- { $server=new db_MySQL($host, $database, $machine); }
+ { $server=new db_MySQL($host, $database, $machine, $socket); }
elsif ($name =~ /pg/i)
{ $server= new db_Pg($host,$database); }
elsif ($name =~ /msql/i)
@@ -73,7 +73,7 @@ sub get_server
{ $server= new db_interbase($host,$database); }
else
{
- die "Unknown sql server name used: $name\nUse one of: Access, Adabas, AdabasD, Empress, FrontBase, Oracle, Informix, DB2, mSQL, Mimer, MS-SQL, MySQL, Pg, Solid or Sybase.\nIf the connection is done trough ODBC the name must end with _ODBC\n";
+ die "Unknown sql server name used: $name\nUse one of: Access, Adabas, AdabasD, Empress, FrontBase, Oracle, Informix, InterBase, DB2, mSQL, Mimer, MS-SQL, MySQL, Pg, Solid or Sybase.\nIf the connection is done trough ODBC the name must end with _ODBC\n";
}
if ($name =~ /_ODBC$/i || defined($odbc) && $odbc)
{
@@ -106,13 +106,14 @@ package db_MySQL;
sub new
{
- my ($type,$host,$database,$machine)= @_;
+ my ($type,$host,$database,$machine,$socket)= @_;
my $self= {};
my %limits;
bless $self;
$self->{'cmp_name'} = "mysql";
- $self->{'data_source'} = "DBI:mysql:$database:$host";
+ $self->{'data_source'} = "DBI:mysql:database=$database;host=$host";
+ $self->{'data_source'} .= ";mysql_socket=$socket" if($socket);
$self->{'limits'} = \%limits;
$self->{'smds'} = \%smds;
$self->{'blob'} = "blob";
@@ -120,6 +121,7 @@ sub new
$self->{'double_quotes'} = 1; # Can handle: 'Walker''s'
$self->{'vacuum'} = 1; # When using with --fast
$self->{'drop_attr'} = "";
+ $self->{'transactions'} = 0; # Transactions disabled by default
$limits{'NEG'} = 1; # Supports -id
$limits{'alter_add_multi_col'}= 1; #Have ALTER TABLE t add a int,add b int;
@@ -144,7 +146,8 @@ sub new
$limits{'join_optimizer'} = 1; # Can optimize FROM tables
$limits{'left_outer_join'} = 1; # Supports left outer joins
$limits{'like_with_column'} = 1; # Can use column1 LIKE column2
- $limits{'limit'} = 1; # supports the limit attribute
+ $limits{'limit'} = 1; # supports the limit attribute
+ $limits{'truncate_table'} = 1;
$limits{'load_data_infile'} = 1; # Has load data infile
$limits{'lock_tables'} = 1; # Has lock tables
$limits{'max_column_name'} = 64; # max table and column name
@@ -194,12 +197,14 @@ sub new
$main::opt_create_options =~ /type=innodb/i)
{
$limits{'max_text_size'} = 8000; # Limit in Innobase
+ $self->{'transactions'} = 1; # Transactions enabled
}
if (defined($main::opt_create_options) &&
$main::opt_create_options =~ /type=gemini/i)
{
$limits{'working_blobs'} = 0; # Blobs not implemented yet
$limits{'max_tables'} = 500;
+ $self->{'transactions'} = 1; # Transactions enabled
}
return $self;
@@ -330,6 +335,12 @@ sub reconnect_on_errors
return 0;
}
+sub fix_for_insert
+{
+ my ($self,$cmd) = @_;
+ return $cmd;
+}
+
#
# Optimize tables for better performance
#
@@ -349,7 +360,6 @@ sub vacuum
}
}
-
#############################################################################
# Definitions for mSQL
#############################################################################
@@ -368,6 +378,7 @@ sub new
$self->{'limits'} = \%limits;
$self->{'double_quotes'} = 0;
$self->{'drop_attr'} = "";
+ $self->{'transactions'} = 0; # No transactions
$self->{'blob'} = "text(" . $limits{'max_text_size'} .")";
$self->{'text'} = "text(" . $limits{'max_text_size'} .")";
@@ -542,6 +553,12 @@ sub reconnect_on_errors
return 0;
}
+sub fix_for_insert
+{
+ my ($self,$cmd) = @_;
+ return $cmd;
+}
+
#############################################################################
# Definitions for PostgreSQL #
#############################################################################
@@ -563,6 +580,7 @@ sub new
$self->{'text'} = "text";
$self->{'double_quotes'} = 1;
$self->{'drop_attr'} = "";
+ $self->{'transactions'} = 1; # Transactions enabled
$self->{"vacuum"} = 1;
$limits{'join_optimizer'} = 1; # Can optimize FROM tables
$limits{'load_data_infile'} = 0;
@@ -603,6 +621,7 @@ sub new
$limits{'select_without_from'}= 1;
$limits{'subqueries'} = 1;
$limits{'table_wildcard'} = 1;
+ $limits{'truncate_table'} = 1;
$limits{'unique_index'} = 1; # Unique index works or not
$limits{'working_all_fields'} = 1;
$limits{'working_blobs'} = 1; # If big varchar/blobs works
@@ -798,6 +817,12 @@ sub reconnect_on_errors
return 0;
}
+sub fix_for_insert
+{
+ my ($self,$cmd) = @_;
+ return $cmd;
+}
+
sub vacuum
{
my ($self,$full_vacuum,$dbh_ref,@tables)=@_;
@@ -851,6 +876,7 @@ sub new
$self->{'text'} = "long varchar";
$self->{'double_quotes'} = 1;
$self->{'drop_attr'} = "";
+ $self->{'transactions'} = 1; # Transactions enabled
$limits{'max_conditions'} = 9999; # Probably big enough
$limits{'max_columns'} = 2000; # From crash-me
@@ -1063,6 +1089,12 @@ sub small_rollback_segment
return 0;
}
+sub fix_for_insert
+{
+ my ($self,$cmd) = @_;
+ return $cmd;
+}
+
sub reconnect_on_errors
{
return 0;
@@ -1092,6 +1124,7 @@ sub new
$self->{'text'} = "text";
$self->{'double_quotes'} = 1; # Can handle: 'Walker''s'
$self->{'drop_attr'} = "";
+ $self->{'transactions'} = 1; # Transactions enabled
$limits{'max_conditions'} = 1258;
$limits{'max_columns'} = 226; # server is disconnecting????
@@ -1325,6 +1358,14 @@ sub query {
return $sql;
}
+sub fix_for_insert
+{
+ my ($self,$cmd) = @_;
+ $cmd =~ s/\'\'/\' \'/g;
+ return $cmd;
+}
+
+
sub drop_index
{
my ($self,$table,$index) = @_;
@@ -1374,6 +1415,7 @@ sub new
$self->{'text'} = "long";
$self->{'double_quotes'} = 1; # Can handle: 'Walker''s'
$self->{'drop_attr'} = "";
+ $self->{'transactions'} = 1; # Transactions enabled
$self->{"vacuum"} = 1;
$limits{'max_conditions'} = 9999; # (Actually not a limit)
@@ -1385,6 +1427,7 @@ sub new
$limits{'max_index_parts'} = 16; # Max segments/key
$limits{'max_column_name'} = 32; # max table and column name
+ $limits{'truncate_table'} = 1;
$limits{'join_optimizer'} = 1; # Can optimize FROM tables
$limits{'load_data_infile'} = 0; # Has load data infile
$limits{'lock_tables'} = 0; # Has lock tables
@@ -1546,6 +1589,14 @@ sub query {
return $sql;
}
+sub fix_for_insert
+{
+ my ($self,$cmd) = @_;
+ $cmd =~ s/\'\'/\' \'/g;
+ return $cmd;
+}
+
+
sub drop_index
{
my ($self,$table,$index) = @_;
@@ -1629,6 +1680,7 @@ sub new
$self->{'text'} = "byte in table";
$self->{'double_quotes'} = 0; # Can handle: 'Walker''s'
$self->{'drop_attr'} = "";
+ $self->{'transactions'} = 1; # Transactions enabled
$self->{'host'} = $host;
$limits{'NEG'} = 1; # Supports -id
@@ -1778,6 +1830,16 @@ sub query {
return $sql;
}
+
+sub fix_for_insert
+{
+ my ($self,$cmd) = @_;
+ $cmd =~ s/\\\'//g;
+ return $cmd;
+}
+
+
+
sub drop_index
{
my ($self,$table,$index) = @_;
@@ -1805,6 +1867,7 @@ sub reconnect_on_errors
return 0;
}
+
#############################################################################
# Configuration for Access
#############################################################################
@@ -1830,6 +1893,7 @@ sub new
$self->{'text'} = "blob"; # text ?
$self->{'double_quotes'} = 1; # Can handle: 'Walker''s'
$self->{'drop_attr'} = "";
+ $self->{'transactions'} = 1; # Transactions enabled
$limits{'max_conditions'} = 97; # We get 'Query is too complex'
$limits{'max_columns'} = 255; # Max number of columns in table
@@ -1981,6 +2045,12 @@ sub reconnect_on_errors
return 1;
}
+sub fix_for_insert
+{
+ my ($self,$cmd) = @_;
+ return $cmd;
+}
+
#############################################################################
# Configuration for Microsoft SQL server
#############################################################################
@@ -2006,6 +2076,7 @@ sub new
$self->{'text'} = "text";
$self->{'double_quotes'} = 1; # Can handle: 'Walker''s'
$self->{'drop_attr'} = "";
+ $self->{'transactions'} = 1; # Transactions enabled
$limits{'max_conditions'} = 1030; # We get 'Query is too complex'
$limits{'max_columns'} = 250; # Max number of columns in table
@@ -2168,10 +2239,15 @@ sub reconnect_on_errors
return 0;
}
+sub fix_for_insert
+{
+ my ($self,$cmd) = @_;
+ return $cmd;
+}
+
#############################################################################
# Configuration for Sybase
#############################################################################
-
package db_sybase;
sub new
@@ -2182,10 +2258,10 @@ sub new
bless $self;
$self->{'cmp_name'} = "sybase";
- $self->{'data_source'} = "DBI:ODBC:$database";
+ $self->{'data_source'} = "DBI:Sybase:database=$database";
if (defined($host) && $host ne "")
{
- $self->{'data_source'} .= ":$host";
+ $self->{'data_source'} .= ";hostname=$host";
}
$self->{'limits'} = \%limits;
$self->{'smds'} = \%smds;
@@ -2193,6 +2269,7 @@ sub new
$self->{'text'} = "text";
$self->{'double_quotes'} = 1; # Can handle: 'Walker''s'
$self->{'drop_attr'} = "";
+ $self->{'transactions'} = 1; # Transactions enabled
$self->{"vacuum"} = 1;
$limits{'max_conditions'} = 1030; # We get 'Query is too complex'
@@ -2249,7 +2326,19 @@ sub new
sub version
{
my ($self)=@_;
- return "Sybase enterprise 11.5 NT"; #DBI/ODBC can't return the server version
+ my ($dbh,$sth,$version,@row);
+
+ $dbh=$self->connect();
+ $sth = $dbh->prepare('SELECT @@version') or die $DBI::errstr;
+ $version="Sybase (unknown)";
+ if ($sth->execute && (@row = $sth->fetchrow_array))
+ {
+ $version=$row[0];
+ }
+ $sth->finish;
+ $dbh->disconnect;
+ return $version;
+
}
sub connect
@@ -2257,7 +2346,7 @@ sub connect
my ($self)=@_;
my ($dbh);
$dbh=DBI->connect($self->{'data_source'}, $main::opt_user,
- $main::opt_password,{ PrintError => 0}) ||
+ $main::opt_password,{ PrintError => 0 , AutoCommit => 1}) ||
die "Got error: '$DBI::errstr' when connecting to " . $self->{'data_source'} ." with user: '$main::opt_user' password: '$main::opt_password'\n";
return $dbh;
}
@@ -2342,9 +2431,17 @@ sub reconnect_on_errors
return 0;
}
+sub fix_for_insert
+{
+ my ($self,$cmd) = @_;
+ return $cmd;
+}
+
#
# optimize the tables ....
-#
+# WARNING (from walrus)! This sub will work only from DBD:sybase
+# driver. Because if we use ODBC we don't know actual database name
+# (but DSN name only)
sub vacuum
{
my ($self,$full_vacuum,$dbh_ref)=@_;
@@ -2356,7 +2453,25 @@ sub vacuum
}
$dbh=$$dbh_ref;
$loop_time=new Benchmark;
- $dbh->do("analyze table ?? compute statistics") || die "Got error: $DBI::errstr when executing 'vacuum'\n";
+ my (@tables,$sth,$current_table,$current_base);
+ $dbh->do("dump tran $database with truncate_only");
+ $sth=$dbh->prepare("sp_tables" ) or die "prepere";
+ $sth->execute() or die "execute";
+ while (@row = $sth->fetchrow_array()) {
+ $current_table = $row[2];
+ $current_base = $row[0];
+ next if ($current_table =~ /^sys/);
+ push(@tables,$current_table) if ($database == $current_base);
+ }
+
+ $sth->finish();
+
+ foreach $table (@tables) {
+# print "$table: \n";
+ $dbh->do("update statistics $table") or print "Oops!";
+ }
+
+# $dbh->do("analyze table ?? compute statistics") || die "Got error: $DBI::errstr when executing 'vacuum'\n";
$end_time=new Benchmark;
print "Time for book-keeping (1): " .
Benchmark::timestr(Benchmark::timediff($end_time, $loop_time),"all") . "\n\n";
@@ -2364,6 +2479,8 @@ sub vacuum
}
+
+
#############################################################################
# Definitions for Adabas
#############################################################################
@@ -2385,6 +2502,7 @@ sub new
$self->{'text'} = "long";
$self->{'double_quotes'} = 1; # Can handle: 'Walker''s'
$self->{'drop_attr'} = "";
+ $self->{'transactions'} = 1; # Transactions enabled
$limits{'max_conditions'} = 50; # (Actually not a limit)
$limits{'max_columns'} = 254; # Max number of columns in table
@@ -2574,6 +2692,12 @@ sub reconnect_on_errors
return 0;
}
+sub fix_for_insert
+{
+ my ($self,$cmd) = @_;
+ return $cmd;
+}
+
#############################################################################
# Configuration for IBM DB2
#############################################################################
@@ -2599,6 +2723,7 @@ sub new
$self->{'text'} = "varchar(255)";
$self->{'double_quotes'} = 1; # Can handle: 'Walker''s'
$self->{'drop_attr'} = "";
+ $self->{'transactions'} = 1; # Transactions enabled
$limits{'max_conditions'} = 418; # We get 'Query is too complex'
$limits{'max_columns'} = 500; # Max number of columns in table
@@ -2747,6 +2872,12 @@ sub reconnect_on_errors
return 0;
}
+sub fix_for_insert
+{
+ my ($self,$cmd) = @_;
+ return $cmd;
+}
+
#############################################################################
# Configuration for MIMER
#############################################################################
@@ -2768,6 +2899,7 @@ sub new
$self->{'text'} = "character varying(15000)";
$self->{'double_quotes'} = 1; # Can handle: 'Walker''s'
$self->{'drop_attr'} = "";
+ $self->{'transactions'} = 1; # Transactions enabled
$self->{'char_null'} = "cast(NULL as char(1))";
$self->{'numeric_null'} = "cast(NULL as int)";
@@ -2836,7 +2968,6 @@ sub new
$smds{'q15'} = 'd';
$smds{'q16'} = 'a';
$smds{'q17'} = 'c';
-
return $self;
}
@@ -2885,23 +3016,35 @@ sub connect
sub create
{
my($self,$table_name,$fields,$index,$options) = @_;
- my($query,@queries);
+ my($query,@queries,@indexes);
$query="create table $table_name (";
foreach $field (@$fields)
{
$field =~ s/ decimal/ double(10,2)/i;
$field =~ s/ big_decimal/ double(10,2)/i;
- $field =~ s/ date/ int/i; # Because of tcp ?
+ $field =~ s/ tinyint\(.*\)/ smallint/i;
+ $field =~ s/ smallint\(.*\)/ smallint/i;
+ $field =~ s/ mediumint/ integer/i;
+ $field =~ s/ float\(.*\)/ float/i;
+# $field =~ s/ date/ int/i; # Because of tcp ?
$query.= $field . ',';
}
foreach $index (@$index)
{
- $query.= $index . ',';
+ if ( $index =~ /\bINDEX\b/i )
+ {
+ my @fields = split(' ',$index);
+ my $query="CREATE INDEX $fields[1] ON $table_name $fields[2]";
+ push(@indexes,$query);
+
+ } else {
+ $query.= $index . ',';
+ }
}
substr($query,-1)=")"; # Remove last ',';
$query.=" $options" if (defined($options));
- push(@queries,$query);
+ push(@queries,$query,@indexes);
return @queries;
}
@@ -2947,6 +3090,12 @@ sub reconnect_on_errors
return 0;
}
+sub fix_for_insert
+{
+ my ($self,$cmd) = @_;
+ return $cmd;
+}
+
#############################################################################
# Configuration for InterBase
#############################################################################
@@ -2961,13 +3110,14 @@ sub new
bless $self;
$self->{'cmp_name'} = "interbase";
- $self->{'data_source'} = "DBI:InterBase:database=$database";
+ $self->{'data_source'} = "DBI:InterBase:database=$database:ib_dialect=3";
$self->{'limits'} = \%limits;
$self->{'smds'} = \%smds;
$self->{'blob'} = "blob";
$self->{'text'} = "";
$self->{'double_quotes'} = 1; # Can handle: 'Walker''s'
$self->{'drop_attr'} = "";
+ $self->{'transactions'} = 1; # Transactions enabled
$self->{'char_null'} = "";
$self->{'numeric_null'} = "";
@@ -3159,6 +3309,12 @@ sub reconnect_on_errors
return 1;
}
+sub fix_for_insert
+{
+ my ($self,$cmd) = @_;
+ return $cmd;
+}
+
#############################################################################
# Configuration for FrontBase
#############################################################################
@@ -3180,6 +3336,7 @@ sub new
$self->{'text'} = "varchar(8000000)";
$self->{'double_quotes'} = 1; # Can handle: 'Walker''s'
$self->{'drop_attr'} = ' restrict';
+ $self->{'transactions'} = 1; # Transactions enabled
$self->{'error_on_execute_means_zero_rows'}=1;
$limits{'max_conditions'} = 5427; # (Actually not a limit)
@@ -3247,13 +3404,13 @@ sub version
my ($self)=@_;
my ($dbh,$sth,$version,@row);
- $dbh=$self->connect();
+# $dbh=$self->connect();
#
# Pick up SQLGetInfo option SQL_DBMS_VER (18)
#
#$version = $dbh->func(18, GetInfo);
- $version="FrontBase 2.1";
- $dbh->disconnect;
+ $version="FrontBase 3.3";
+# $dbh->disconnect;
return $version;
}
@@ -3288,7 +3445,7 @@ sub connect
sub create
{
my($self,$table_name,$fields,$index,$options) = @_;
- my($query,@queries);
+ my($query,@queries,@indexes,@keys);
$query="create table $table_name (";
foreach $field (@$fields)
@@ -3306,18 +3463,18 @@ sub create
}
foreach $ind (@$index)
{
- my @index;
- if ( $ind =~ /\bKEY\b/i ){
+# my @index;
+ if ( $ind =~ /(\bKEY\b)|(\bUNIQUE\b)/i ){
push(@keys,"ALTER TABLE $table_name ADD $ind");
}else{
- my @fields = split(' ',$index);
+ my @fields = split(' ',$ind);
my $query="CREATE INDEX $fields[1] ON $table_name $fields[2]";
- push(@index,$query);
+ push(@indexes,$query);
}
}
substr($query,-1)=")"; # Remove last ',';
$query.=" $options" if (defined($options));
- push(@queries,$query);
+ push(@queries,$query,@keys,@indexes);
return @queries;
}
@@ -3363,4 +3520,10 @@ sub reconnect_on_errors
return 1;
}
+sub fix_for_insert
+{
+ my ($self,$cmd) = @_;
+ return $cmd;
+}
+
1;
diff --git a/sql-bench/test-ATIS.sh b/sql-bench/test-ATIS.sh
index 77e0e7d79bf..ac3d7360198 100644
--- a/sql-bench/test-ATIS.sh
+++ b/sql-bench/test-ATIS.sh
@@ -106,6 +106,12 @@ if (!$opt_skip_create)
}
else
{
+ if ($opt_fast && $server->{transactions})
+ {
+ $dbh->{AutoCommit} = 0;
+ print "Transactions enabled\n" if ($opt_debug);
+ }
+
for ($ti = 0; $ti <= $#table_names; $ti++)
{
my $table_name = $table_names[$ti];
@@ -119,8 +125,7 @@ if (!$opt_skip_create)
chomp;
next unless ( $_ =~ /\w/ ); # skip blank lines
my $command = $insert_start . $_ . ")";
- $command =~ s/\'\'/\' \'/g if ($opt_server =~ /empress/i || $opt_server =~ /oracle/i);
- $command =~ s/\\'//g if ($opt_server =~ /informix/i);
+ $command = $server->fix_for_insert($command);
print "$command\n" if ($opt_debug);
$command =~ s/\\'/\'\'/g if ($double_quotes);
@@ -128,8 +133,14 @@ if (!$opt_skip_create)
$row_count++;
}
}
+ if ($opt_fast && $server->{transactions})
+ {
+ $dbh->commit;
+ $dbh->{AutoCommit} = 1;
+ }
close(DATA);
}
+
if ($opt_lock_tables)
{
$dbh->do("UNLOCK TABLES");
@@ -213,7 +224,7 @@ print "Retrieving data\n";
"SELECT airport.country_name,state.state_name,city.city_name,airport_service.direction FROM airport_service,state,airport,city WHERE airport_service.city_code=city.city_code AND airport_service.airport_code=airport.airport_code AND state.state_code=airport.state_code AND state.state_code=city.state_code AND airport.state_code=city.state_code AND airport.country_name=city.country_name AND airport.country_name=state.country_name AND city.time_zone_code=airport.time_zone_code GROUP BY airport.country_name,state.state_name,city.city_name,airport_service.direction ORDER BY state_name DESC",11,$limits->{'group_functions'},
"SELECT airport.country_name,state.state_name,city.city_name,airport_service.direction FROM airport_service,state,airport,city WHERE airport_service.city_code=city.city_code AND airport_service.airport_code=airport.airport_code AND state.state_code=airport.state_code AND state.state_code=city.state_code AND airport.state_code=city.state_code AND airport.country_name=city.country_name AND airport.country_name=state.country_name AND city.time_zone_code=airport.time_zone_code GROUP BY airport.country_name,state.state_name,city.city_name,airport_service.direction ORDER BY state_name",11,$limits->{'group_functions'},
"SELECT from_airport,to_airport,fare.fare_class,night,one_way_cost,rnd_trip_cost,class_days FROM compound_class,fare WHERE compound_class.fare_class=fare.fare_class AND one_way_cost <= 825 AND one_way_cost >= 280 AND from_airport='SFO' AND to_airport='DFW' GROUP BY from_airport,to_airport,fare.fare_class,night,one_way_cost,rnd_trip_cost,class_days ORDER BY one_way_cost",10,$limits->{'group_functions'},
- "select engines,category,cruising_speed,from_airport,to_airport FROM aircraft,flight WHERE category='JET' AND ENGINES >= 1 AND aircraft.aircraft_code=flight.aircraft_code AND to_airport NOT LIKE from_airport AND stops>0 GROUP BY engines,category,cruising_speed,from_airport,to_airport ORDER BY engines DESC",29,$limits->{'group_functions'} && $limits->{'like_with_column'},
+ "select engines,category,cruising_speed,from_airport,to_airport FROM aircraft,flight WHERE category='JET' AND engines >= 1 AND aircraft.aircraft_code=flight.aircraft_code AND to_airport NOT LIKE from_airport AND stops>0 GROUP BY engines,category,cruising_speed,from_airport,to_airport ORDER BY engines DESC",29,$limits->{'group_functions'} && $limits->{'like_with_column'},
);
@Q=(\@Q1,\@Q2,\@Q21,\@Q3,\@Q4);
diff --git a/sql-bench/test-alter-table.sh b/sql-bench/test-alter-table.sh
index 276c4863d8c..cc6453188de 100644
--- a/sql-bench/test-alter-table.sh
+++ b/sql-bench/test-alter-table.sh
@@ -74,11 +74,25 @@ do_many($dbh,$server->create("bench",\@fields,\@index));
print "Insert data into the table\n";
$loop_time=new Benchmark;
+
+if ($opt_fast && $server->{transactions})
+{
+ $dbh->{AutoCommit} = 0;
+ print "Transactions enabled\n" if ($opt_debug);
+}
+
for ($i=0 ; $i < $opt_row_count ; $i++)
{
$query="insert into bench values ( " . ("$i," x ($opt_start_field_count-1)) . "$i)";
$dbh->do($query) or die $DBI::errstr;
}
+
+if ($opt_fast && $server->{transactions})
+{
+ $dbh->commit;
+ $dbh->{AutoCommit} = 1;
+}
+
$end_time=new Benchmark;
print "Time for insert ($opt_row_count)",
diff --git a/sql-bench/test-big-tables.sh b/sql-bench/test-big-tables.sh
index ac942f2b571..151a169d31f 100644
--- a/sql-bench/test-big-tables.sh
+++ b/sql-bench/test-big-tables.sh
@@ -127,14 +127,28 @@ end_benchmark($start_time);
sub test_query
{
my($test_text,$result_text,$query,$dbh,$count)=@_;
- my($i,$loop_time,$end_time);
+ my($i,$loop_time,$end_time, $using_transactions);
print $test_text . "\n";
$loop_time=new Benchmark;
+
+ $using_transactions=0;
+ if ($opt_fast && server->{transactions} && $query=~ /^insert /i)
+ {
+ $using_transactions=1;
+ $dbh->{AutoCommit} = 0;
+ print "Transactions enabled\n" if ($opt_debug);
+ }
for ($i=0 ; $i < $count ; $i++)
{
defined(fetch_all_rows($dbh,$query)) or die $DBI::errstr;
}
+ if ($using_transactions)
+ {
+ $dbh->commit;
+ $dbh->{AutoCommit} = 1;
+ }
+
$end_time=new Benchmark;
print $result_text . "($count): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
diff --git a/sql-bench/test-connect.sh b/sql-bench/test-connect.sh
index 862161e3a03..0f1aca5aaa7 100644
--- a/sql-bench/test-connect.sh
+++ b/sql-bench/test-connect.sh
@@ -27,7 +27,7 @@
use DBI;
use Benchmark;
-$opt_loop_count=10000; # Change this to make test harder/easier
+$opt_loop_count=100000; # Change this to make test harder/easier
$str_length=65000; # This is the length of blob strings in PART:5
$max_test=20; # How many times to test if the server is busy
@@ -43,9 +43,10 @@ if ($opt_small_test)
}
$opt_loop_count=min(1000, $opt_loop_count) if ($opt_tcpip);
+$small_loop_count=$opt_loop_count/10; # For connect tests
print "Testing the speed of connecting to the server and sending of data\n";
-print "All tests are done $opt_loop_count times\n\n";
+print "Connect tests are done $small_loop_count times and other tests $opt_loop_count times\n\n";
################################# PART:1 ###################################
####
@@ -59,7 +60,7 @@ print "Testing connection/disconnect\n";
$loop_time=new Benchmark;
$errors=0;
-for ($i=0 ; $i < $opt_loop_count ; $i++)
+for ($i=0 ; $i < $small_loop_count ; $i++)
{
print "$i " if (($opt_debug));
for ($j=0; $j < $max_test ; $j++)
@@ -80,27 +81,27 @@ for ($i=0 ; $i < $opt_loop_count ; $i++)
}
$end_time=new Benchmark;
print "Warning: $errors connections didn't work without a time delay\n" if ($errors);
-print "Time to connect ($opt_loop_count): " .
+print "Time to connect ($small_loop_count): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
################################# PART:2 ###################################
#### Now we shall do first one connect, then simple select
#### (select 1..) and then close connection. This will be
-#### done $opt_loop_count times.
+#### done $small_loop_count times.
if ($limits->{'select_without_from'})
{
print "Test connect/simple select/disconnect\n";
$loop_time=new Benchmark;
- for ($i=0; $i<$opt_loop_count; $i++)
+ for ($i=0; $i < $small_loop_count; $i++)
{
$dbh = DBI->connect($server->{'data_source'}, $opt_user, $opt_password) || die $DBI::errstr;
- $sth = $dbh->do("select 1") or die $DBI::errstr;
+ $sth = $dbh->do("select $i") or die $DBI::errstr;
$dbh->disconnect;
}
$end_time=new Benchmark;
- print "Time for connect+select_simple ($opt_loop_count): " .
+ print "Time for connect+select_simple ($small_loop_count): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
}
@@ -116,16 +117,33 @@ if ($limits->{'select_without_from'})
{
print "Test simple select\n";
$loop_time=new Benchmark;
- for ($i=0 ; $i<$opt_loop_count ; $i++)
+ for ($i=0 ; $i < $opt_loop_count ; $i++)
{
- $sth = $dbh->do("select 1") or die $DBI::errstr;
+ $sth = $dbh->do("select $i") or die $DBI::errstr;
}
$end_time=new Benchmark;
print "Time for select_simple ($opt_loop_count): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
}
-################################# PART:4 ###################################
+###########################################################################
+#### The same as the previous test, but always execute the same select
+#### This is done to test the query cache for real simple selects.
+
+if ($limits->{'select_without_from'})
+{
+ print "Test simple select\n";
+ $loop_time=new Benchmark;
+ for ($i=0 ; $i < $opt_loop_count ; $i++)
+ {
+ $sth = $dbh->do("select 10000") or die $DBI::errstr;
+ }
+ $end_time=new Benchmark;
+ print "Time for select_simple_cache ($opt_loop_count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+}
+
+##########################################################################
#### First, we'll create a simple table 'bench1'
#### Then we shall do $opt_loop_count selects from this table.
#### Table will contain very simple data.
@@ -152,7 +170,7 @@ print "Testing connect/select 1 row from table/disconnect\n";
$loop_time=new Benchmark;
$errors=0;
-for ($i=0 ; $i<$opt_loop_count ; $i++)
+for ($i=0 ; $i < $small_loop_count ; $i++)
{
for ($j=0; $j < $max_test ; $j++)
{
@@ -161,14 +179,14 @@ for ($i=0 ; $i<$opt_loop_count ; $i++)
}
die $DBI::errstr if ($j == $max_test);
- $sth = $dbh->do("select * from bench1") #Select * from table with 1 record
+ $sth = $dbh->do("select a,i,s,$i from bench1") # Select * from table with 1 record
or die $DBI::errstr;
$dbh->disconnect;
}
$end_time=new Benchmark;
print "Warning: $errors connections didn't work without a time delay\n" if ($errors);
-print "Time to connect+select_1_row ($opt_loop_count): " .
+print "Time to connect+select_1_row ($small_loop_count): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
#
@@ -179,9 +197,9 @@ print "Testing select 1 row from table\n";
$dbh = $server->connect();
$loop_time=new Benchmark;
-for ($i=0 ; $i<$opt_loop_count ; $i++)
+for ($i=0 ; $i < $opt_loop_count ; $i++)
{
- $sth = $dbh->do("select * from bench1") # Select * from table with 1 record
+ $sth = $dbh->do("select a,i,s,$i from bench1") # Select * from table with 1 record
or die $DBI::errstr;
}
@@ -190,8 +208,24 @@ print "Time to select_1_row ($opt_loop_count): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
#
-# The same test, but with 2 rows.
+# Same test (as with one row) but now with a cacheable query
#
+
+$loop_time=new Benchmark;
+
+for ($i=0 ; $i < $opt_loop_count ; $i++)
+{
+ $sth = $dbh->do("select a,i,s from bench1") # Select * from table with 1 record
+ or die $DBI::errstr;
+}
+$end_time=new Benchmark;
+print "Time to select_1_row_cache ($opt_loop_count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+
+#
+# The same test, but with 2 rows (not cacheable).
+#
+
print "Testing select 2 rows from table\n";
$sth = $dbh->do("insert into bench1 values(2,200,'BBB')")
@@ -199,9 +233,9 @@ $sth = $dbh->do("insert into bench1 values(2,200,'BBB')")
$loop_time=new Benchmark;
-for ($i=0 ; $i<$opt_loop_count ; $i++)
+for ($i=0 ; $i < $opt_loop_count ; $i++)
{
- $sth = $dbh->do("select * from bench1") # Select * from table with 2 record
+ $sth = $dbh->do("select a,i,s,$i from bench1") # Select * from table with 2 record
or die $DBI::errstr;
}
@@ -209,14 +243,18 @@ $end_time=new Benchmark;
print "Time to select_2_rows ($opt_loop_count): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+#
+# Simple test to test speed of functions.
+#
+
if ($limits->{'functions'})
{
print "Test select with aritmetic (+)\n";
$loop_time=new Benchmark;
- for ($i=0; $i<$opt_loop_count; $i++)
+ for ($i=0; $i < $opt_loop_count; $i++)
{
- $sth = $dbh->do("select a+a+a+a+a+a+a+a+a+a from bench1") or die $DBI::errstr;
+ $sth = $dbh->do("select a+a+a+a+a+a+a+a+a+$i from bench1") or die $DBI::errstr;
}
$end_time=new Benchmark;
print "Time for select_column+column ($opt_loop_count): " .
@@ -254,9 +292,9 @@ if ($opt_fast && defined($server->{vacuum}))
$loop_time=new Benchmark;
-for ($i=0 ; $i < $opt_loop_count ; $i++)
+for ($i=0 ; $i < $small_loop_count ; $i++)
{
- $sth = $dbh->prepare("select * from bench1");
+ $sth = $dbh->prepare("select b,$i from bench1");
if (!$sth->execute || !(@row = $sth->fetchrow_array) ||
length($row[0]) != $str_length)
{
@@ -266,14 +304,14 @@ for ($i=0 ; $i < $opt_loop_count ; $i++)
}
$end_time=new Benchmark;
-print "Time to select_big_str ($opt_loop_count): " .
+print "Time to select_big_str ($small_loop_count): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
$sth = $dbh->do("drop table bench1" . $server->{'drop_attr'})
or do
{
# Fix for Access 2000
- die $dbh->errstr if (!$dbh->abort_if_fatal_error());
+ die $dbh->errstr if (!$server->abort_if_fatal_error());
};
if ($opt_fast && defined($server->{vacuum}))
diff --git a/sql-bench/test-insert.sh b/sql-bench/test-insert.sh
index 655e38b1b0e..085d7cce7f3 100644
--- a/sql-bench/test-insert.sh
+++ b/sql-bench/test-insert.sh
@@ -29,6 +29,7 @@
use DBI;
use Benchmark;
+use Data::Dumper;
$opt_loop_count=100000; # number of rows/3
$small_loop_count=10; # Loop for full table retrieval
@@ -132,6 +133,12 @@ else
$query="insert into bench1 (id,id2,id3,dummy1) values ";
}
+if ($opt_fast && $server->{transactions})
+{
+ $dbh->{AutoCommit} = 0;
+ print "Transactions enabled\n" if ($opt_debug);
+}
+
if (($opt_fast || $opt_fast_insert) && $server->{'limits'}->{'insert_multi_value'})
{
$query_size=$server->{'limits'}->{'query_size'};
@@ -209,6 +216,12 @@ else
}
}
+if ($opt_fast && $server->{transactions})
+{
+ $dbh->commit;
+ $dbh->{AutoCommit} = 1;
+}
+
$end_time=new Benchmark;
print "Time for insert (" . ($total_rows) . "): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
@@ -234,6 +247,12 @@ if ($limits->{'unique_index'})
{
print "Testing insert of duplicates\n";
$loop_time=new Benchmark;
+
+ if ($opt_fast && $server->{transactions})
+ {
+ $dbh->{AutoCommit} = 0;
+ }
+
for ($i=0 ; $i < $opt_loop_count ; $i++)
{
$tmpvar^= ((($tmpvar + 63) + $i)*3 % $opt_loop_count);
@@ -244,6 +263,11 @@ if ($limits->{'unique_index'})
die "Didn't get an error when inserting duplicate record $tmp\n";
}
}
+ if ($opt_fast && $server->{transactions})
+ {
+ $dbh->commit;
+ $dbh->{AutoCommit} = 1;
+ }
$end_time=new Benchmark;
print "Time for insert_duplicates (" . ($opt_loop_count) . "): " .
@@ -577,7 +601,6 @@ if ($limits->{'group_functions'})
}
$sth->finish;
-
$count++;
$sth=$dbh->prepare($query="select count(*),sum(id+0.0),min(id),max(id),avg(id-0.0) from bench1") or die $DBI::errstr;
$sth->execute or die $DBI::errstr;
@@ -917,13 +940,19 @@ print "Time for update_with_key (" . ($opt_loop_count*3) . "): " .
timestr(timediff($end_time, $loop_time),"all") . "\n";
$loop_time=new Benchmark;
-for ($i=0 ; $i < $opt_loop_count*3 ; $i+=3)
+$count=0;
+for ($i=1 ; $i < $opt_loop_count*3 ; $i+=3)
{
$sth = $dbh->do("update bench1 set dummy1='updated' where id=$i") or die $DBI::errstr;
+ $end_time=new Benchmark;
+ last if ($estimated=predict_query_time($loop_time,$end_time,\$i,$tests,
+ $opt_loop_count));
}
-
-$end_time=new Benchmark;
-print "Time for update_with_key_prefix (" . ($opt_loop_count) . "): " .
+if ($estimated)
+{ print "Estimated time"; }
+else
+{ print "Time"; }
+print " for update_with_key_prefix (" . ($opt_loop_count) . "): " .
timestr(timediff($end_time, $loop_time),"all") . "\n";
print "\nTesting update of all rows\n";
@@ -1167,7 +1196,7 @@ if (!$opt_skip_delete)
}
$end_time=new Benchmark;
- print "Time for delete_all ($count): " .
+ print "Time for delete_range ($count): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
if ($opt_lock_tables)
@@ -1203,6 +1232,7 @@ print "Insert into table with $keys keys and with a primary key with $seg parts\
# Make keys on the most important types
@types=(0,0,0,1,0,0,0,1,1,1,1,1,1,1,1,1,1); # A 1 for each char field
push(@fields,"field1 tinyint not null");
+push(@fields,"field_search tinyint not null");
push(@fields,"field2 mediumint not null");
push(@fields,"field3 smallint not null");
push(@fields,"field4 char(16) not null");
@@ -1222,9 +1252,10 @@ for ($i= 1 ; $i <= $seg ; $i++)
}
substr($query,-1)=")";
push (@keys,$query);
+push (@keys,"index index2 (field_search)");
#Create other keys
-for ($i=2 ; $i <= $keys ; $i++)
+for ($i=3 ; $i <= $keys ; $i++)
{
push(@keys,"index index$i (field$i)");
}
@@ -1242,6 +1273,11 @@ if ($server->small_rollback_segment())
}
$loop_time=new Benchmark;
+if ($opt_fast && $server->{transactions})
+{
+ $dbh->{AutoCommit} = 0;
+}
+
$fields=$#fields;
if (($opt_fast || $opt_fast_insert) && $server->{'limits'}->{'insert_multi_value'})
{
@@ -1250,11 +1286,11 @@ if (($opt_fast || $opt_fast_insert) && $server->{'limits'}->{'insert_multi_value
$res=$query;
for ($i=0; $i < $many_keys_loop_count; $i++)
{
+ $id= $i & 127;
$rand=$random[$i];
- $tmp="(" . ($i & 127) . ",$rand," . ($i & 32766) .
- ",'ABCDEF$rand',0,";
+ $tmp="($id,$id,$rand," . ($i & 32766) . ",'ABCDEF$rand',0,";
- for ($j=5; $j <= $fields ; $j++)
+ for ($j=6; $j <= $fields ; $j++)
{
$tmp.= ($types[$j] == 0) ? "$rand," : "'$rand',";
}
@@ -1275,11 +1311,12 @@ else
{
for ($i=0; $i < $many_keys_loop_count; $i++)
{
+ $id= $i & 127;
$rand=$random[$i];
- $query="insert into bench1 values (" . ($i & 127) . ",$rand," . ($i & 32767) .
+ $query="insert into bench1 values ($id,$id,$rand," . ($i & 32767) .
",'ABCDEF$rand',0,";
- for ($j=5; $j <= $fields ; $j++)
+ for ($j=6; $j <= $fields ; $j++)
{
$query.= ($types[$j] == 0) ? "$rand," : "'$rand',";
}
@@ -1288,6 +1325,13 @@ else
$dbh->do($query) or die "Got error $DBI::errstr with query: $query\n";
}
}
+
+if ($opt_fast && $server->{transactions})
+{
+ $dbh->commit;
+ $dbh->{AutoCommit} = 1;
+}
+
$end_time=new Benchmark;
print "Time for insert_key ($many_keys_loop_count): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
@@ -1316,11 +1360,24 @@ if ($opt_fast && defined($server->{vacuum}))
print "Testing update of keys\n";
$loop_time=new Benchmark;
+
+if ($opt_fast && $server->{transactions})
+{
+ $dbh->{AutoCommit} = 0;
+}
+
for ($i=0 ; $i< 256; $i++)
{
- $dbh->do("update bench1 set field5=1 where field1=$i")
- or die "Got error $DBI::errstr with query: update bench1 set field5=1 where field1=$i\n";
+ $dbh->do("update bench1 set field5=1 where field_search=$i")
+ or die "Got error $DBI::errstr with query: update bench1 set field5=1 where field_search=$i\n";
+}
+
+if ($opt_fast && $server->{transactions})
+{
+ $dbh->commit;
+ $dbh->{AutoCommit} = 1;
}
+
$end_time=new Benchmark;
print "Time for update_of_primary_key_many_keys (256): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
@@ -1360,29 +1417,31 @@ $count=0;
for ($i=0 ; $i < 128 ; $i++)
{
$count++;
- $dbh->do("delete from bench1 where field1 = $i") or die $DBI::errstr;
+ $dbh->do("delete from bench1 where field_search = $i") or die $DBI::errstr;
}
$end_time=new Benchmark;
print "Time for delete_big_many_keys ($count): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+if ($opt_lock_tables)
+{
+ $sth = $dbh->do("UNLOCK TABLES") || die $DBI::errstr;
+}
+
print "Deleting everything from table\n";
$count=1;
if ($opt_fast)
{
- $dbh->do("delete from bench1") or die $DBI::errstr;
+ $query= ($limits->{'truncate_table'} ? "truncate table bench1" :
+ "delete from bench1");
+ $dbh->do($query) or die $DBI::errstr;
}
else
{
$dbh->do("delete from bench1 where field1 > 0") or die $DBI::errstr;
}
-if ($opt_lock_tables)
-{
- $sth = $dbh->do("UNLOCK TABLES") || die $DBI::errstr;
-}
-
$end_time=new Benchmark;
print "Time for delete_all_many_keys ($count): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
@@ -1409,12 +1468,18 @@ if ($limits->{'insert_multi_value'})
"dummy1 char(30)"],
["primary key (id,id2)",
"index index_id3 (id3)"]));
+
+ $loop_time=new Benchmark;
+
if ($opt_lock_tables)
{
$sth = $dbh->do("LOCK TABLES bench1 write") || die $DBI::errstr;
}
+ if ($opt_fast && $server->{transactions})
+ {
+ $dbh->{AutoCommit} = 0;
+ }
- $loop_time=new Benchmark;
print "Inserting $opt_loop_count rows with multiple values\n";
$query="insert into bench1 values ";
$res=$query;
@@ -1437,6 +1502,11 @@ if ($limits->{'insert_multi_value'})
{
$sth = $dbh->do("UNLOCK TABLES ") || die $DBI::errstr;
}
+ if ($opt_fast && $server->{transactions})
+ {
+ $dbh->commit;
+ $dbh->{AutoCommit} = 1;
+ }
$end_time=new Benchmark;
print "Time for multiple_value_insert (" . ($opt_loop_count) . "): " .
diff --git a/sql-bench/test-select.sh b/sql-bench/test-select.sh
index 1ecad5804c5..a5ae1da7283 100644
--- a/sql-bench/test-select.sh
+++ b/sql-bench/test-select.sh
@@ -92,6 +92,12 @@ if ($opt_fast && defined($server->{vacuum}))
print "Inserting $opt_loop_count rows\n";
$loop_time=new Benchmark;
+
+if ($opt_fast && $server->{transactions})
+{
+ $dbh->{AutoCommit} = 0;
+}
+
$query="insert into bench1 values (";
$half_done=$opt_loop_count/2;
for ($id=0,$rev_id=$opt_loop_count-1 ; $id < $opt_loop_count ; $id++,$rev_id--)
@@ -105,6 +111,12 @@ for ($id=0,$rev_id=$opt_loop_count-1 ; $id < $opt_loop_count ; $id++,$rev_id--)
}
}
+if ($opt_fast && $server->{transactions})
+{
+ $dbh->commit;
+ $dbh->{AutoCommit} = 1;
+}
+
$end_time=new Benchmark;
print "Time to insert ($opt_loop_count): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
@@ -141,10 +153,10 @@ if ($limits->{'group_functions'})
$loop_time=new Benchmark;
for ($tests=0 ; $tests < $opt_loop_count ; $tests++)
{
- fetch_all_rows($dbh,"select sum(idn+$tests),sum(rev_idn-$tests) from bench1");
+ fetch_all_rows($dbh,"select sum(idn+100),sum(rev_idn-100) from bench1");
}
$end_time=new Benchmark;
- print "Time for select_query_cache ($opt_loop_count): " .
+ print "Time for select_cache ($opt_loop_count): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
# If the database has a query cache, the following loop should be much
@@ -156,7 +168,7 @@ if ($limits->{'group_functions'})
fetch_all_rows($dbh,"select sum(idn+$tests),sum(rev_idn-$tests) from bench1");
}
$end_time=new Benchmark;
- print "Time for select_query_cache2 ($opt_loop_count): " .
+ print "Time for select_cache2 ($opt_loop_count): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
}
diff --git a/sql-bench/test-transactions.sh b/sql-bench/test-transactions.sh
new file mode 100644
index 00000000000..b081b89fb69
--- /dev/null
+++ b/sql-bench/test-transactions.sh
@@ -0,0 +1,297 @@
+#!@PERL@
+# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#
+# 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
+#
+# Test of transactions performance.
+#
+
+##################### Standard benchmark inits ##############################
+
+use DBI;
+use Benchmark;
+#use warnings;
+
+$opt_groups=27; # Characters are 'A' -> Z
+
+$opt_loop_count=10000; # Change this to make test harder/easier
+$opt_medium_loop_count=100; # Change this to make test harder/easier
+
+chomp($pwd = `pwd`); $pwd = "." if ($pwd eq '');
+require "$pwd/bench-init.pl" || die "Can't read Configuration file: $!\n";
+
+# Avoid warnings for variables in bench-init.pl
+# (Only works with perl 5.6)
+#our ($opt_small_test, $opt_small_tables, $opt_debug, $opt_force);
+
+if ($opt_small_test || $opt_small_tables)
+{
+ $opt_loop_count/=100;
+ $opt_medium_loop_count/=10;
+}
+
+
+if (!$server->{transactions} && !$opt_force)
+{
+ print "Test skipped because the database doesn't support transactions\n";
+ exit(0);
+}
+
+####
+#### Connect and start timeing
+####
+
+$start_time=new Benchmark;
+$dbh = $server->connect();
+
+###
+### Create Table
+###
+
+print "Creating tables\n";
+$dbh->do("drop table bench1");
+$dbh->do("drop table bench2");
+
+do_many($dbh,$server->create("bench1",
+ ["idn int NOT NULL",
+ "rev_idn int NOT NULL",
+ "region char(1) NOT NULL",
+ "grp int NOT NULL",
+ "updated tinyint NOT NULL"],
+ ["primary key (idn)",
+ "unique (region,grp)"]));
+do_many($dbh,$server->create("bench2",
+ ["idn int NOT NULL",
+ "rev_idn int NOT NULL",
+ "region char(1) NOT NULL",
+ "grp int NOT NULL",
+ "updated tinyint NOT NULL"],
+ ["primary key (idn)",
+ "unique (region,grp)"]));
+
+$dbh->{AutoCommit} = 0;
+
+###
+### Test insert perfomance
+###
+
+test_insert("bench1","insert_commit",0);
+test_insert("bench2","insert_autocommit",1);
+
+sub test_insert
+{
+ my ($table, $test_name, $auto_commit)= @_;
+ my ($loop_time,$end_time,$id,$rev_id,$grp,$region);
+
+ $dbh->{AutoCommit}= $auto_commit;
+ $loop_time=new Benchmark;
+
+ for ($id=0,$rev_id=$opt_loop_count-1 ; $id < $opt_loop_count ;
+ $id++,$rev_id--)
+ {
+ $grp=$id/$opt_groups;
+ $region=chr(65+$id%$opt_groups);
+ do_query($dbh,"insert into $table values ($id,$rev_id,'$region',$grp,0)");
+ }
+
+ $dbh->commit if (!$auto_commit);
+ $end_time=new Benchmark;
+ print "Time for $test_name ($opt_loop_count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+}
+
+###
+### Test rollback performance
+###
+
+print "Test transactions rollback performance\n" if($opt_debug);
+
+##
+## Insert rollback test
+##
+
+#
+# Test is done by inserting 100 rows in a table with lots of rows and
+# then doing a rollback on these
+#
+
+{
+ my ($id,$rev_id,$grp,$region,$end,$loop_time,$end_time,$commit_loop,$count);
+
+ $dbh->{AutoCommit} = 0;
+ $loop_time=new Benchmark;
+ $end=$opt_loop_count*2;
+ $count=0;
+
+ for ($commit_loop=1, $id=$opt_loop_count ; $id < $end ;
+ $id++, $commit_loop++)
+ {
+ $rev_id=$end-$id;
+ $grp=$id/$opt_groups;
+ $region=chr(65+$id%$opt_groups);
+ do_query($dbh,"insert into bench1 values ($id,$rev_id,'$region',$grp,0)");
+ if ($commit_loop >= $opt_medium_loop_count)
+ {
+ $dbh->rollback;
+ $commit_loop=0;
+ $count++;
+ }
+ }
+ if ($commit_loop > 1)
+ {
+ $dbh->rollback;
+ $count++;
+ }
+ $end_time=new Benchmark;
+ print "Time for insert_rollback ($count:$opt_loop_count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+}
+
+##
+## Update rollback test
+##
+
+#
+# Test is done by updating 100 rows in a table with lots of rows and
+# then doing a rollback on these
+#
+
+{
+ my ($id,$loop_time,$end_time,$commit_loop,$count);
+
+ $dbh->{AutoCommit} = 0;
+ $loop_time=new Benchmark;
+ $end=$opt_loop_count*2;
+ $count=0;
+
+ for ($commit_loop=1, $id=0 ; $id < $opt_loop_count ; $id++, $commit_loop++)
+ {
+ do_query($dbh,"update bench1 set updated=2 where idn=$id");
+ if ($commit_loop >= $opt_medium_loop_count)
+ {
+ $dbh->rollback;
+ $commit_loop=0;
+ $count++;
+ }
+ }
+ if ($commit_loop > 1)
+ {
+ $dbh->rollback;
+ $count++;
+ }
+ $end_time=new Benchmark;
+ print "Time for update_rollback ($count:$opt_loop_count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+}
+
+##
+## Delete rollback test
+##
+
+#
+# Test is done by deleting 100 rows in a table with lots of rows and
+# then doing a rollback on these
+#
+
+{
+ my ($id,$loop_time,$end_time,$commit_loop,$count);
+
+ $dbh->{AutoCommit} = 0;
+ $loop_time=new Benchmark;
+ $end=$opt_loop_count*2;
+ $count=0;
+
+ for ($commit_loop=1, $id=0 ; $id < $opt_loop_count ; $id++, $commit_loop++)
+ {
+ do_query($dbh,"delete from bench1 where idn=$id");
+ if ($commit_loop >= $opt_medium_loop_count)
+ {
+ $dbh->rollback;
+ $commit_loop=0;
+ $count++;
+ }
+ }
+ if ($commit_loop > 1)
+ {
+ $dbh->rollback;
+ $count++;
+ }
+ $end_time=new Benchmark;
+ print "Time for delete_rollback ($count:$opt_loop_count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+}
+
+
+###
+### Test update perfomance
+###
+
+test_update("bench1","update_commit",0);
+test_update("bench2","update_autocommit",1);
+
+sub test_update
+{
+ my ($table, $test_name, $auto_commit)= @_;
+ my ($loop_time,$end_time,$id);
+
+ $dbh->{AutoCommit}= $auto_commit;
+ $loop_time=new Benchmark;
+
+ for ($id=0 ; $id < $opt_loop_count ; $id++)
+ {
+ do_query($dbh,"update bench1 set updated=1 where idn=$id");
+ }
+
+ $dbh->commit if (!$auto_commit);
+ $end_time=new Benchmark;
+ print "Time for $test_name ($opt_loop_count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+}
+
+###
+### Test delete perfomance
+###
+
+test_delete("bench1","delete_commit",0);
+test_delete("bench2","delete_autocommit",1);
+
+sub test_delete
+{
+ my ($table, $test_name, $auto_commit)= @_;
+ my ($loop_time,$end_time,$id);
+
+ $dbh->{AutoCommit}= $auto_commit;
+ $loop_time=new Benchmark;
+
+ for ($id=0 ; $id < $opt_loop_count ; $id++)
+ {
+ do_query($dbh,"delete from $table where idn=$id");
+ }
+ $dbh->commit if (!$auto_commit);
+ $end_time=new Benchmark;
+ print "Time for $test_name ($opt_loop_count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+}
+
+####
+#### End of benchmark
+####
+
+$sth = $dbh->do("drop table bench1" . $server->{'drop_attr'}) or die $DBI::errstr;
+$sth = $dbh->do("drop table bench2" . $server->{'drop_attr'}) or die $DBI::errstr;
+
+$dbh->disconnect; # close connection
+end_benchmark($start_time);
diff --git a/sql-bench/test-wisconsin.sh b/sql-bench/test-wisconsin.sh
index a017120259e..adc3e5b5aa4 100644
--- a/sql-bench/test-wisconsin.sh
+++ b/sql-bench/test-wisconsin.sh
@@ -48,27 +48,36 @@ init_query();
print "Wisconsin benchmark test\n\n";
-if (!$opt_skip_create)
+if ($opt_skip_create)
{
- $loop_time= new Benchmark;
- for($ti = 0; $ti <= $#table_names; $ti++)
+ if ($opt_lock_tables)
{
- my $table_name = $table_names[$ti];
- my $array_ref = $tables[$ti];
-
- # This may fail if we have no table so do not check answer
- $sth = $dbh->do("drop table $table_name" . $server->{'drop_attr'});
- print "Creating table $table_name\n" if ($opt_verbose);
- do_many($dbh,@$array_ref);
+ @tmp=@table_names; push(@tmp,@extra_names);
+ $sth = $dbh->do("LOCK TABLES " . join(" WRITE,", @tmp) . " WRITE") ||
+ die $DBI::errstr;
}
- $end_time=new Benchmark;
- print "Time for create_table ($#tables): " .
- timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+ goto start_benchmark;
+}
- if ($opt_fast && defined($server->{vacuum}))
- {
- $server->vacuum(1,\$dbh);
- }
+$loop_time= new Benchmark;
+for($ti = 0; $ti <= $#table_names; $ti++)
+{
+ my $table_name = $table_names[$ti];
+ my $array_ref = $tables[$ti];
+
+ # This may fail if we have no table so do not check answer
+ $sth = $dbh->do("drop table $table_name" . $server->{'drop_attr'});
+ print "Creating table $table_name\n" if ($opt_verbose);
+ do_many($dbh,@$array_ref);
+}
+$end_time=new Benchmark;
+print "Time for create_table ($#tables): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(1,\$dbh);
+}
####
@@ -100,6 +109,11 @@ if ($opt_fast && $server->{'limits'}->{'load_data_infile'})
}
else
{
+ if ($opt_fast && $server->{transactions})
+ {
+ $dbh->{AutoCommit} = 0;
+ }
+
for ($ti = 0; $ti <= $#table_names; $ti++)
{
my $table_name = $table_names[$ti];
@@ -124,10 +138,17 @@ else
}
close(DATA);
}
+
if ($opt_lock_tables)
{
do_query($dbh,"UNLOCK TABLES");
}
+if ($opt_fast && $server->{transactions})
+{
+ $dbh->commit;
+ $dbh->{AutoCommit} = 1;
+}
+
$end_time=new Benchmark;
print "Time to insert ($row_count): " .
timestr(timediff($end_time, $loop_time),"all") . "\n";
@@ -159,13 +180,6 @@ $sth = $dbh->do("delete from Bprime where Bprime.unique2 >= 1000") or
$end_time=new Benchmark;
print "Time to delete_big (1): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
-}
-elsif ($opt_lock_tables)
-{
- @tmp=@table_names; push(@tmp,@extra_names);
- $sth = $dbh->do("LOCK TABLES " . join(" WRITE,", @tmp) . " WRITE") ||
- die $DBI::errstr;
-}
if ($opt_fast && defined($server->{vacuum}))
{
@@ -176,7 +190,9 @@ if ($opt_fast && defined($server->{vacuum}))
#### Running the benchmark
####
-print "Running actual benchmark\n";
+start_benchmark:
+
+print "Running the actual benchmark\n";
$loop_time= new Benchmark;
$count=0;
@@ -226,7 +242,7 @@ sub init_data
{
@onek=
$server->create("onek",
- ["unique1 int(4) NOT NULL",
+ ["unique1 int(5) NOT NULL",
"unique2 int(4) NOT NULL",
"two int(4)",
"four int(4)",
diff --git a/sql/ChangeLog b/sql/ChangeLog
index 2289765afad..a75e9761766 100644
--- a/sql/ChangeLog
+++ b/sql/ChangeLog
@@ -1,3 +1,8 @@
+2000-12-07 Jeremy Cole <jeremy@mysql.com>
+
+* Added UPDATE ... ORDER BY ...
+* Added DELETE ... ORDER BY ...
+
2000-11-11 Jeremy Cole <jeremy@mysql.com>
* Added ALTER TABLE ... ORDER BY ...
diff --git a/sql/Makefile.am b/sql/Makefile.am
index 47cee300b09..e1ed9ad8915 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -21,27 +21,29 @@ MYSQLDATAdir = $(localstatedir)
MYSQLSHAREdir = $(pkgdatadir)
MYSQLBASEdir= $(prefix)
INCLUDES = @MT_INCLUDES@ \
- @bdb_includes@ @innodb_includes@ @gemini_includes@ \
+ @bdb_includes@ @innodb_includes@ \
-I$(srcdir)/../include \
-I$(srcdir)/../regex \
- -I$(srcdir) -I../include -I.. -I.
+ -I$(srcdir) -I../include -I. $(openssl_includes)
WRAPLIBS= @WRAPLIBS@
SUBDIRS = share
libexec_PROGRAMS = mysqld
noinst_PROGRAMS = gen_lex_hash
-gen_lex_hash_LDFLAGS = @NOINST_LDFLAGS@
-LDADD = ../isam/libnisam.a \
- ../merge/libmerge.a \
+gen_lex_hash_LDFLAGS = @NOINST_LDFLAGS@
+LDADD = @isam_libs@ \
../myisam/libmyisam.a \
../myisammrg/libmyisammrg.a \
../heap/libheap.a \
+ ../vio/libvio.a \
../mysys/libmysys.a \
../dbug/libdbug.a \
../regex/libregex.a \
../strings/libmystrings.a
+
mysqld_LDADD = @MYSQLD_EXTRA_LDFLAGS@ \
- @bdb_libs@ @innodb_libs@ @gemini_libs@ \
- $(LDADD) $(CXXLDFLAGS) $(WRAPLIBS) @LIBDL@
+ @bdb_libs@ @innodb_libs@ @pstack_libs@ \
+ @innodb_system_libs@ \
+ $(LDADD) $(CXXLDFLAGS) $(WRAPLIBS) @LIBDL@ @openssl_libs@
noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
item_strfunc.h item_timefunc.h item_uniq.h \
item_create.h mysql_priv.h \
@@ -49,37 +51,37 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
sql_manager.h sql_map.h sql_string.h unireg.h \
field.h handler.h \
ha_isammrg.h ha_isam.h ha_myisammrg.h\
- ha_heap.h ha_myisam.h ha_berkeley.h ha_innobase.h \
- ha_gemini.h opt_range.h opt_ft.h \
+ ha_heap.h ha_myisam.h ha_berkeley.h ha_innodb.h \
+ opt_range.h opt_ft.h \
sql_select.h structs.h table.h sql_udf.h hash_filo.h\
- lex.h lex_symbol.h sql_acl.h sql_crypt.h md5.h \
+ lex.h lex_symbol.h sql_acl.h sql_crypt.h \
log_event.h mini_client.h sql_repl.h slave.h \
- stacktrace.h
-mysqld_SOURCES = sql_lex.cc \
+ stacktrace.h sql_sort.h sql_cache.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 \
thr_malloc.cc item_create.cc \
field.cc key.cc sql_class.cc sql_list.cc \
- net_serv.cc violite.c net_pkg.cc lock.cc my_lock.c \
+ net_serv.cc net_pkg.cc lock.cc my_lock.c \
sql_string.cc sql_manager.cc sql_map.cc \
mysqld.cc password.c hash_filo.cc hostname.cc \
convert.cc sql_parse.cc sql_yacc.yy \
sql_base.cc table.cc sql_select.cc sql_insert.cc \
- sql_update.cc sql_delete.cc sql_do.cc \
+ sql_update.cc sql_delete.cc uniques.cc sql_do.cc \
procedure.cc item_uniq.cc sql_test.cc \
log.cc log_event.cc init.cc derror.cc sql_acl.cc \
- unireg.cc \
+ unireg.cc des_key_file.cc \
time.cc opt_range.cc opt_sum.cc opt_ft.cc \
records.cc filesort.cc handler.cc \
ha_heap.cc ha_myisam.cc ha_myisammrg.cc \
- ha_berkeley.cc ha_innobase.cc ha_gemini.cc \
+ ha_berkeley.cc ha_innodb.cc \
ha_isam.cc ha_isammrg.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 \
+ slave.cc sql_repl.cc sql_union.cc \
mini_client.cc mini_client_errors.c \
- md5.c stacktrace.c
+ stacktrace.c repl_failsafe.h repl_failsafe.cc
gen_lex_hash_SOURCES = gen_lex_hash.cc
gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS)
diff --git a/sql/cache_manager.cc b/sql/cache_manager.cc
index 9ea25315f8c..307fe331e5c 100644
--- a/sql/cache_manager.cc
+++ b/sql/cache_manager.cc
@@ -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 */
@@ -18,7 +18,7 @@
#pragma implementation /* gcc: Class implementation */
#endif
-#include <global.h>
+#include <my_global.h>
#include <my_sys.h>
#include "cache_manager.h"
@@ -117,7 +117,7 @@ void *cache_manager::alloc(uint size)
{
void *llist;
void *abs_ptr;
-
+
size=ALIGN_SIZE(size+HEADER_LENGTH+SUFFIX_LENGTH);
if (!(llist = find_in_llist(size)))
{
@@ -127,7 +127,7 @@ void *cache_manager::alloc(uint size)
}
size_of_found_block=int4korr((char*) llist) & ALLOC_MASK;
// if (size_of_found_block < SMALLEST_BLOCK)
-
+
abs_ptr = link_into_abs(llist);
return abs_ptr;
}
diff --git a/sql/cache_manager.h b/sql/cache_manager.h
index fc3b8f7016a..d422a86ea8e 100644
--- a/sql/cache_manager.h
+++ b/sql/cache_manager.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 */
@@ -59,7 +59,3 @@ class cache_manager {
bool *dealloc(void *); /* Deallocate blocks (with *ptr_arg) */
void clear(void); /* Clear the cache */
};
-
-
-
-
diff --git a/sql/convert.cc b/sql/convert.cc
index 3e0fbf18ace..7a06208759c 100644
--- a/sql/convert.cc
+++ b/sql/convert.cc
@@ -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 */
@@ -397,19 +397,19 @@ static unsigned char win1251ukr_koi8_ukr[256] = {
****************************************************************************/
-CONVERT conv_cp1251_koi8("cp1251_koi8", cp1251_koi8, koi8_cp1251);
+CONVERT conv_cp1251_koi8("cp1251_koi8", cp1251_koi8, koi8_cp1251, 1);
#ifdef DEFINE_ALL_CHARACTER_SETS
-CONVERT conv_cp1250_latin2("cp1250_latin2", t1250_til2, til2_t1250);
-CONVERT conv_kam_latin2("kam_latin2", tkam_til2, til2_tkam);
-CONVERT conv_mac_latin2("mac_latin2", tmac_til2, til2_tmac);
-CONVERT conv_macce_latin2("macce_latin2", tmacce_til2, til2_tmacce);
-CONVERT conv_pc2_latin2("pc2_latin2", tpc2_til2, til2_tpc2);
-CONVERT conv_vga_latin2("vga_latin2", tvga_til2, til2_tvga);
-CONVERT conv_koi8_cp1251("koi8_cp1251", koi8_cp1251, cp1251_koi8);
+CONVERT conv_cp1250_latin2("cp1250_latin2", t1250_til2, til2_t1250, 2);
+CONVERT conv_kam_latin2("kam_latin2", tkam_til2, til2_tkam, 3);
+CONVERT conv_mac_latin2("mac_latin2", tmac_til2, til2_tmac, 4);
+CONVERT conv_macce_latin2("macce_latin2", tmacce_til2, til2_tmacce, 5);
+CONVERT conv_pc2_latin2("pc2_latin2", tpc2_til2, til2_tpc2, 6);
+CONVERT conv_vga_latin2("vga_latin2", tvga_til2, til2_tvga, 7);
+CONVERT conv_koi8_cp1251("koi8_cp1251", koi8_cp1251, cp1251_koi8, 8);
CONVERT conv_win1251ukr_koi8_ukr("win1251ukr_koi8_ukr", win1251ukr_koi8_ukr,
- koi8_ukr_win1251ukr);
+ koi8_ukr_win1251ukr, 9);
CONVERT conv_koi8_ukr_win1251ukr("koi8_ukr_win1251ukr", koi8_ukr_win1251ukr,
- win1251ukr_koi8_ukr);
+ win1251ukr_koi8_ukr, 10);
#endif /* DEFINE_ALL_CHARACTER_SETS */
CONVERT *convert_tables[]= {
diff --git a/sql/custom_conf.h b/sql/custom_conf.h
index af6012e28ec..19ced12bfbb 100644
--- a/sql/custom_conf.h
+++ b/sql/custom_conf.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 */
diff --git a/sql/derror.cc b/sql/derror.cc
index 62971fde394..7ebe6e4b3c5 100644
--- a/sql/derror.cc
+++ b/sql/derror.cc
@@ -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 */
@@ -44,13 +44,14 @@ static void read_texts(const char *file_name,const char ***point,
uint error_messages)
{
register uint i;
- uint ant,funktpos,length,textant;
+ uint count,funktpos,length,textcount;
File file;
char name[FN_REFLEN];
const char *buff;
uchar head[32],*pos;
DBUG_ENTER("read_texts");
+ *point=0; // If something goes wrong
LINT_INIT(buff);
funktpos=0;
if ((file=my_open(fn_format(name,file_name,language,"",4),
@@ -63,37 +64,38 @@ static void read_texts(const char *file_name,const char ***point,
if (head[0] != (uchar) 254 || head[1] != (uchar) 254 ||
head[2] != 2 || head[3] != 1)
goto err; /* purecov: inspected */
- textant=head[4];
- length=uint2korr(head+6); ant=uint2korr(head+8);
+ textcount=head[4];
+ length=uint2korr(head+6); count=uint2korr(head+8);
- if (ant < error_messages)
+ if (count < error_messages)
{
- fprintf(stderr,"\n%s: Fatal error: Error message file '%s' had only %d error messages, but it should have at least %d error messages.\n\
-Check that the above file is the right version for this program!\n\n",
- my_progname,name,ant,error_messages);
+ sql_print_error("\
+Error message file '%s' had only %d error messages,\n\
+but it should contain at least %d error messages.\n\
+Check that the above file is the right version for this program!",
+ name,count,error_messages);
VOID(my_close(file,MYF(MY_WME)));
- clean_up(0); /* Clean_up frees everything */
- exit(1); /* We can't continue */
+ unireg_abort(1);
}
x_free((gptr) *point); /* Free old language */
if (!(*point= (const char**)
- my_malloc((uint) (length+ant*sizeof(char*)),MYF(0))))
+ my_malloc((uint) (length+count*sizeof(char*)),MYF(0))))
{
funktpos=2; /* purecov: inspected */
goto err; /* purecov: inspected */
}
- buff= (char*) (*point + ant);
+ buff= (char*) (*point + count);
- if (my_read(file,(byte*) buff,(uint) ant*2,MYF(MY_NABP))) goto err;
- for (i=0, pos= (uchar*) buff ; i< ant ; i++)
+ if (my_read(file,(byte*) buff,(uint) count*2,MYF(MY_NABP))) goto err;
+ for (i=0, pos= (uchar*) buff ; i< count ; i++)
{
(*point)[i]=buff+uint2korr(pos);
pos+=2;
}
if (my_read(file,(byte*) buff,(uint) length,MYF(MY_NABP))) goto err;
- for (i=1 ; i < textant ; i++)
+ for (i=1 ; i < textcount ; i++)
{
point[i]= *point +uint2korr(head+10+i+i);
}
@@ -103,20 +105,19 @@ Check that the above file is the right version for this program!\n\n",
err:
switch (funktpos) {
case 2:
- buff="\n%s: Fatal error: Not enough memory for messagefile '%s'\n\n";
+ buff="Not enough memory for messagefile '%s'";
break;
case 1:
- buff="\n%s: Fatal error: Can't read from messagefile '%s'\n\n";
+ buff="Can't read from messagefile '%s'";
break;
default:
- buff="\n%s: Fatal error: Can't find messagefile '%s'\n\n";
+ buff="Can't find messagefile '%s'";
break;
}
if (file != FERR)
VOID(my_close(file,MYF(MY_WME)));
- fprintf(stderr,buff,my_progname,name);
- clean_up(0); /* Clean_up frees everything */
- exit(1); /* We can't continue */
+ sql_print_error(buff,name);
+ unireg_abort(1);
} /* read_texts */
diff --git a/sql/des_key_file.cc b/sql/des_key_file.cc
new file mode 100644
index 00000000000..d9c924b5a3c
--- /dev/null
+++ b/sql/des_key_file.cc
@@ -0,0 +1,107 @@
+/* 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 <mysql_priv.h>
+#include <m_ctype.h>
+
+#ifdef HAVE_OPENSSL
+
+struct st_des_keyschedule des_keyschedule[10];
+uint des_default_key;
+pthread_mutex_t LOCK_des_key_file;
+static int initialized;
+
+/*
+ Function which loads DES keys from plaintext file into memory on MySQL
+ server startup and on command FLUSH DES_KEY_FILE.
+ Blame tonu@spam.ee on bugs ;)
+
+ RETURN
+ 0 ok
+ 1 Error
+*/
+
+bool
+load_des_key_file(const char *file_name)
+{
+ bool result=1;
+ File file;
+ IO_CACHE io;
+ DBUG_ENTER("load_des_key_file");
+ DBUG_PRINT("enter",("name: %s",file_name));
+
+ if (!initialized)
+ {
+ initialized=1;
+ pthread_mutex_init(&LOCK_des_key_file,MY_MUTEX_INIT_FAST);
+ }
+
+ VOID(pthread_mutex_lock(&LOCK_des_key_file));
+ if ((file=my_open(file_name,O_RDONLY | O_BINARY ,MYF(MY_WME))) < 0 ||
+ init_io_cache(&io, file, IO_SIZE*2, READ_CACHE, 0, 0, MYF(MY_WME)))
+ goto error;
+
+ bzero((char*) des_keyschedule,sizeof(struct st_des_keyschedule) * 10);
+ des_default_key=15; // Impossible key
+ for (;;)
+ {
+ char *start, *end;
+ char buf[1024], offset;
+ st_des_keyblock keyblock;
+ uint length;
+
+ if (!(length=my_b_gets(&io,buf,sizeof(buf)-1)))
+ break; // End of file
+ offset=buf[0];
+ if (offset >= '0' && offset <= '9') // If ok key
+ {
+ offset=(char) (offset - '0');
+ // Remove newline and possible other control characters
+ for (start=buf+1 ; isspace(*start) ; start++) ;
+ end=buf+length;
+ for (end=strend(buf) ; end > start && !isgraph(end[-1]) ; end--) ;
+
+ if (start != end)
+ {
+ des_cblock ivec;
+ bzero((char*) &ivec,sizeof(ivec));
+ // We make good 24-byte (168 bit) key from given plaintext key with MD5
+ EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL,
+ (uchar *) start, (int) (end-start),1,
+ (uchar *) &keyblock,
+ ivec);
+ des_set_key_unchecked(&keyblock.key1,des_keyschedule[(int)offset].ks1);
+ des_set_key_unchecked(&keyblock.key2,des_keyschedule[(int)offset].ks2);
+ des_set_key_unchecked(&keyblock.key3,des_keyschedule[(int)offset].ks3);
+ if (des_default_key == 15)
+ des_default_key= (uint) offset; // use first as def.
+ }
+ }
+ else if (offset != '#')
+ sql_print_error("load_des_file: Found wrong key_number: %c",offset);
+ }
+ result=0;
+
+error:
+ if (file >= 0)
+ {
+ my_close(file,MYF(0));
+ end_io_cache(&io);
+ }
+ VOID(pthread_mutex_unlock(&LOCK_des_key_file));
+ DBUG_RETURN(result);
+}
+#endif /* HAVE_OPENSSL */
diff --git a/sql/field.cc b/sql/field.cc
index c6a26a48c0c..32679f549ba 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -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 */
@@ -63,7 +63,7 @@ const char field_separator=',';
*****************************************************************************/
/*
- ** Calculate length of number and it's parts
+ ** Calculate length of number and its parts
** Increment cuted_fields if wrong number
*/
@@ -215,18 +215,19 @@ static bool test_if_real(const char *str,int length)
/****************************************************************************
** Functions for the base classes
-** This is a unpacked number.
+** This is an unpacked number.
****************************************************************************/
Field::Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg)
- :ptr(ptr_arg),null_ptr(null_ptr_arg),null_bit(null_bit_arg),
- table(table_arg),query_id(0),key_start(0),part_of_key(0),part_of_sortkey(0),
- table_name(table_arg ? table_arg->table_name : 0),
- field_name(field_name_arg), unireg_check(unireg_check_arg),
- field_length(length_arg)
+ :ptr(ptr_arg),null_ptr(null_ptr_arg),
+ table(table_arg),table_name(table_arg ? table_arg->table_name : 0),
+ field_name(field_name_arg),
+ query_id(0),key_start(0),part_of_key(0),part_of_sortkey(0),
+ unireg_check(unireg_check_arg),
+ field_length(length_arg),null_bit(null_bit_arg)
{
flags=null_ptr ? 0: NOT_NULL_FLAG;
}
@@ -242,13 +243,13 @@ void Field::copy_from_tmp(int row_offset)
memcpy(ptr,ptr+row_offset,pack_length());
if (null_ptr)
{
- *null_ptr= ((null_ptr[0] & (uchar) ~(uint) null_bit) |
- null_ptr[row_offset] & (uchar) null_bit);
+ *null_ptr= (uchar) ((null_ptr[0] & (uchar) ~(uint) null_bit) |
+ null_ptr[row_offset] & (uchar) null_bit);
}
}
-bool Field::send(String *packet)
+bool Field::send(THD *thd, String *packet)
{
if (is_null())
return net_store_null(packet);
@@ -256,7 +257,7 @@ bool Field::send(String *packet)
String tmp(buff,sizeof(buff));
val_str(&tmp,&tmp);
CONVERT *convert;
- if ((convert=current_thd->convert_set))
+ if ((convert=thd->convert_set))
return convert->store(packet,tmp.ptr(),tmp.length());
return net_store_data(packet,tmp.ptr(),tmp.length());
}
@@ -368,7 +369,7 @@ bool Field::optimize_range()
/****************************************************************************
** Functions for the Field_decimal class
-** This is a unpacked number.
+** This is an unpacked number.
****************************************************************************/
void
@@ -410,7 +411,7 @@ void Field_decimal::store(const char *from,uint len)
{
fyllchar = '0';
if (from != end)
- while (*from == '0' && from != end-1) // Skipp prezero
+ while (*from == '0' && from != end-1) // Skip prezero
from++;
}
else
@@ -464,7 +465,7 @@ void Field_decimal::store(const char *from,uint len)
if (tmp_dec--)
{
*to++ ='.';
- if (decstr.nr_dec) from++; // Skipp '.'
+ if (decstr.nr_dec) from++; // Skip '.'
for (i=(int) min(decstr.nr_dec,tmp_dec) ; i-- > 0 ; ) *to++ = *from++;
for (i=(int) (tmp_dec-min(decstr.nr_dec,tmp_dec)) ; i-- > 0 ; ) *to++ = '0';
}
@@ -1049,7 +1050,7 @@ void Field_short::sort_string(char *to,uint length __attribute__((unused)))
if (unsigned_flag)
to[0] = ptr[0];
else
- to[0] = ptr[0] ^ 128; /* Revers signbit */
+ to[0] = (char) (ptr[0] ^ 128); /* Revers signbit */
to[1] = ptr[1];
}
else
@@ -1058,7 +1059,7 @@ void Field_short::sort_string(char *to,uint length __attribute__((unused)))
if (unsigned_flag)
to[0] = ptr[1];
else
- to[0] = ptr[1] ^ 128; /* Revers signbit */
+ to[0] = (char) (ptr[1] ^ 128); /* Revers signbit */
to[1] = ptr[0];
}
}
@@ -1129,12 +1130,12 @@ void Field_medium::store(double nr)
}
else if (nr >= (double) (long) (1L << 24))
{
- ulong tmp=(ulong) (1L << 24)-1L;
+ uint32 tmp=(uint32) (1L << 24)-1L;
int3store(ptr,tmp);
current_thd->cuted_fields++;
}
else
- int3store(ptr,(ulong) nr);
+ int3store(ptr,(uint32) nr);
}
else
{
@@ -1171,7 +1172,7 @@ void Field_medium::store(longlong nr)
current_thd->cuted_fields++;
}
else
- int3store(ptr,(ulong) nr);
+ int3store(ptr,(uint32) nr);
}
else
{
@@ -1449,7 +1450,7 @@ int Field_long::cmp(const char *a_ptr, const char *b_ptr)
longget(b,b_ptr);
}
if (unsigned_flag)
- return ((ulong) a < (ulong) b) ? -1 : ((ulong) a > (ulong) b) ? 1 : 0;
+ return ((uint32) a < (uint32) b) ? -1 : ((uint32) a > (uint32) b) ? 1 : 0;
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
@@ -1461,7 +1462,7 @@ void Field_long::sort_string(char *to,uint length __attribute__((unused)))
if (unsigned_flag)
to[0] = ptr[0];
else
- to[0] = ptr[0] ^ 128; /* Revers signbit */
+ to[0] = (char) (ptr[0] ^ 128); /* Revers signbit */
to[1] = ptr[1];
to[2] = ptr[2];
to[3] = ptr[3];
@@ -1472,7 +1473,7 @@ void Field_long::sort_string(char *to,uint length __attribute__((unused)))
if (unsigned_flag)
to[0] = ptr[3];
else
- to[0] = ptr[3] ^ 128; /* Revers signbit */
+ to[0] = (char) (ptr[3] ^ 128); /* Revers signbit */
to[1] = ptr[2];
to[2] = ptr[1];
to[3] = ptr[0];
@@ -1660,7 +1661,7 @@ void Field_longlong::sort_string(char *to,uint length __attribute__((unused)))
if (unsigned_flag)
to[0] = ptr[0];
else
- to[0] = ptr[0] ^ 128; /* Revers signbit */
+ to[0] = (char) (ptr[0] ^ 128); /* Revers signbit */
to[1] = ptr[1];
to[2] = ptr[2];
to[3] = ptr[3];
@@ -1675,7 +1676,7 @@ void Field_longlong::sort_string(char *to,uint length __attribute__((unused)))
if (unsigned_flag)
to[0] = ptr[7];
else
- to[0] = ptr[7] ^ 128; /* Revers signbit */
+ to[0] = (char) (ptr[7] ^ 128); /* Revers signbit */
to[1] = ptr[6];
to[2] = ptr[5];
to[3] = ptr[4];
@@ -1712,6 +1713,11 @@ void Field_float::store(double nr)
float j;
if (dec < NOT_FIXED_DEC)
nr=floor(nr*log_10[dec]+0.5)/log_10[dec]; // To fixed point
+ if (unsigned_flag && nr < 0)
+ {
+ current_thd->cuted_fields++;
+ nr=0;
+ }
if (nr < -FLT_MAX)
{
j= -FLT_MAX;
@@ -1738,6 +1744,11 @@ void Field_float::store(double nr)
void Field_float::store(longlong nr)
{
float j= (float) nr;
+ if (unsigned_flag && j < 0)
+ {
+ current_thd->cuted_fields++;
+ j=0;
+ }
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
{
@@ -1910,7 +1921,7 @@ void Field_float::sort_string(char *to,uint length __attribute__((unused)))
{ /* make complement */
uint i;
for (i=0 ; i < sizeof(nr); i++)
- tmp[i]=tmp[i] ^ (uchar) 255;
+ tmp[i]= (uchar) (tmp[i] ^ (uchar) 255);
}
else
{
@@ -1944,6 +1955,11 @@ void Field_double::store(const char *from,uint len)
double j= atof(tmp_str.c_ptr());
if (errno || current_thd->count_cuted_fields && !test_if_real(from,len))
current_thd->cuted_fields++;
+ if (unsigned_flag && j < 0)
+ {
+ current_thd->cuted_fields++;
+ j=0;
+ }
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
{
@@ -1959,6 +1975,11 @@ void Field_double::store(double nr)
{
if (dec < NOT_FIXED_DEC)
nr=floor(nr*log_10[dec]+0.5)/log_10[dec]; // To fixed point
+ if (unsigned_flag && nr < 0)
+ {
+ current_thd->cuted_fields++;
+ nr=0;
+ }
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
{
@@ -1973,6 +1994,11 @@ void Field_double::store(double nr)
void Field_double::store(longlong nr)
{
double j= (double) nr;
+ if (unsigned_flag && j < 0)
+ {
+ current_thd->cuted_fields++;
+ j=0;
+ }
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
{
@@ -2278,10 +2304,10 @@ void Field_timestamp::store(longlong nr)
{
part1=(long) (nr/LL(1000000));
part2=(long) (nr - (longlong) part1*LL(1000000));
- l_time.year= part1/10000L; part1%=10000L;
+ l_time.year= (int) (part1/10000L); part1%=10000L;
l_time.month= (int) part1 / 100;
- l_time.day= (int) part1 % 100;
- l_time.hour= part2/10000L; part2%=10000L;
+ l_time.day= (int) part1 % 100;
+ l_time.hour= (int) (part2/10000L); part2%=10000L;
l_time.minute=(int) part2 / 100;
l_time.second=(int) part2 % 100;
timestamp=my_gmt_sec(&l_time);
@@ -2295,7 +2321,7 @@ void Field_timestamp::store(longlong nr)
}
else
#endif
- longstore(ptr,(ulong)timestamp);
+ longstore(ptr,(uint32) timestamp);
}
@@ -2596,7 +2622,7 @@ void Field_time::store(longlong nr)
double Field_time::val_real(void)
{
- ulong j= (ulong) uint3korr(ptr);
+ uint32 j= (uint32) uint3korr(ptr);
return (double) j;
}
@@ -2632,19 +2658,19 @@ bool Field_time::get_time(TIME *ltime)
ltime->neg= 1;
tmp=-tmp;
}
- ltime->hour=tmp/10000;
+ ltime->hour= (int) (tmp/10000);
tmp-=ltime->hour*10000;
- ltime->minute= tmp/100;
- ltime->second= tmp % 100;
+ ltime->minute= (int) tmp/100;
+ ltime->second= (int) tmp % 100;
ltime->second_part=0;
return 0;
}
int Field_time::cmp(const char *a_ptr, const char *b_ptr)
{
- long a,b;
- a=(long) sint3korr(a_ptr);
- b=(long) sint3korr(b_ptr);
+ int32 a,b;
+ a=(int32) sint3korr(a_ptr);
+ b=(int32) sint3korr(b_ptr);
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
@@ -2755,14 +2781,14 @@ void Field_year::sql_type(String &res) const
** Stored as a 4 byte unsigned int
****************************************************************************/
-void Field_date::store(const char *from,uint len)
+void Field_date::store(const char *from, uint len)
{
TIME l_time;
- ulong tmp;
+ uint32 tmp;
if (str_to_TIME(from,len,&l_time,1) == TIMESTAMP_NONE)
tmp=0;
else
- tmp=(ulong) l_time.year*10000L + (ulong) (l_time.month*100+l_time.day);
+ tmp=(uint32) l_time.year*10000L + (uint32) (l_time.month*100+l_time.day);
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
{
@@ -2934,7 +2960,7 @@ void Field_newdate::store(double nr)
void Field_newdate::store(longlong nr)
{
- long tmp;
+ int32 tmp;
if (nr >= LL(100000000) && nr <= LL(99991231235959))
nr=nr/LL(1000000); // Timestamp to date
if (nr < 0L || nr > 99991231L)
@@ -2944,16 +2970,16 @@ void Field_newdate::store(longlong nr)
}
else
{
- tmp=(long) nr;
+ tmp=(int32) nr;
if (tmp)
{
if (tmp < YY_PART_YEAR*10000L) // Fix short dates
- tmp+=20000000L;
+ tmp+= (uint32) 20000000L;
else if (tmp < 999999L)
- tmp+=19000000L;
+ tmp+= (uint32) 19000000L;
}
- uint month=((tmp/100) % 100);
- uint day= tmp%100;
+ uint month= (uint) ((tmp/100) % 100);
+ uint day= (uint) (tmp%100);
if (month > 12 || day > 31)
{
tmp=0L; // Don't allow date to change
@@ -2962,7 +2988,7 @@ void Field_newdate::store(longlong nr)
else
tmp= day + month*32 + (tmp/10000)*16*32;
}
- int3store(ptr,tmp);
+ int3store(ptr,(int32) tmp);
}
void Field_newdate::store_time(TIME *ltime,timestamp_type type)
@@ -2987,7 +3013,7 @@ double Field_newdate::val_real(void)
longlong Field_newdate::val_int(void)
{
- ulong j=uint3korr(ptr);
+ ulong j= uint3korr(ptr);
j= (j % 32L)+(j / 32L % 16L)*100L + (j/(16L*32L))*10000L;
return (longlong) j;
}
@@ -2997,25 +3023,25 @@ String *Field_newdate::val_str(String *val_buffer,
{
val_buffer->alloc(field_length);
val_buffer->length(field_length);
- ulong tmp=(ulong) uint3korr(ptr);
+ uint32 tmp=(uint32) uint3korr(ptr);
int part;
char *pos=(char*) val_buffer->ptr()+10;
/* Open coded to get more speed */
- *pos--=0;
+ *pos--=0; // End NULL
part=(int) (tmp & 31);
- *pos--='0'+part%10;
- *pos--='0'+part/10;
- *pos--='-';
+ *pos--= (char) ('0'+part%10);
+ *pos--= (char) ('0'+part/10);
+ *pos--= '-';
part=(int) (tmp >> 5 & 15);
- *pos--='0'+part%10;
- *pos--='0'+part/10;
- *pos--='-';
+ *pos--= (char) ('0'+part%10);
+ *pos--= (char) ('0'+part/10);
+ *pos--= '-';
part=(int) (tmp >> 9);
- *pos--='0'+part%10; part/=10;
- *pos--='0'+part%10; part/=10;
- *pos--='0'+part%10; part/=10;
- *pos='0'+part;
+ *pos--= (char) ('0'+part%10); part/=10;
+ *pos--= (char) ('0'+part%10); part/=10;
+ *pos--= (char) ('0'+part%10); part/=10;
+ *pos= (char) ('0'+part);
return val_buffer;
}
@@ -3023,7 +3049,7 @@ bool Field_newdate::get_date(TIME *ltime,bool fuzzydate)
{
if (is_null())
return 1;
- ulong tmp=(ulong) uint3korr(ptr);
+ uint32 tmp=(uint32) uint3korr(ptr);
bzero((char*) ltime,sizeof(*ltime));
ltime->day= tmp & 31;
ltime->month= (tmp >> 5) & 15;
@@ -3039,9 +3065,9 @@ bool Field_newdate::get_time(TIME *ltime)
int Field_newdate::cmp(const char *a_ptr, const char *b_ptr)
{
- ulong a,b;
- a=(ulong) uint3korr(a_ptr);
- b=(ulong) uint3korr(b_ptr);
+ uint32 a,b;
+ a=(uint32) uint3korr(a_ptr);
+ b=(uint32) uint3korr(b_ptr);
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
@@ -3175,44 +3201,44 @@ String *Field_datetime::val_str(String *val_buffer,
pos=(char*) val_buffer->ptr()+19;
*pos--=0;
- *pos--='0'+(char) (part2%10); part2/=10;
- *pos--='0'+(char) (part2%10); part3= (int) (part2 / 10);
- *pos--=':';
- *pos--='0'+(char) (part3%10); part3/=10;
- *pos--='0'+(char) (part3%10); part3/=10;
- *pos--=':';
- *pos--='0'+(char) (part3%10); part3/=10;
- *pos--='0'+(char) part3;
- *pos--=' ';
- *pos--='0'+(char) (part1%10); part1/=10;
- *pos--='0'+(char) (part1%10); part1/=10;
- *pos--='-';
- *pos--='0'+(char) (part1%10); part1/=10;
- *pos--='0'+(char) (part1%10); part3= (int) (part1/10);
- *pos--='-';
- *pos--='0'+(char) (part3%10); part3/=10;
- *pos--='0'+(char) (part3%10); part3/=10;
- *pos--='0'+(char) (part3%10); part3/=10;
- *pos='0'+(char) part3;
+ *pos--= (char) ('0'+(char) (part2%10)); part2/=10;
+ *pos--= (char) ('0'+(char) (part2%10)); part3= (int) (part2 / 10);
+ *pos--= ':';
+ *pos--= (char) ('0'+(char) (part3%10)); part3/=10;
+ *pos--= (char) ('0'+(char) (part3%10)); part3/=10;
+ *pos--= ':';
+ *pos--= (char) ('0'+(char) (part3%10)); part3/=10;
+ *pos--= (char) ('0'+(char) part3);
+ *pos--= ' ';
+ *pos--= (char) ('0'+(char) (part1%10)); part1/=10;
+ *pos--= (char) ('0'+(char) (part1%10)); part1/=10;
+ *pos--= '-';
+ *pos--= (char) ('0'+(char) (part1%10)); part1/=10;
+ *pos--= (char) ('0'+(char) (part1%10)); part3= (int) (part1/10);
+ *pos--= '-';
+ *pos--= (char) ('0'+(char) (part3%10)); part3/=10;
+ *pos--= (char) ('0'+(char) (part3%10)); part3/=10;
+ *pos--= (char) ('0'+(char) (part3%10)); part3/=10;
+ *pos=(char) ('0'+(char) part3);
return val_buffer;
}
bool Field_datetime::get_date(TIME *ltime,bool fuzzydate)
{
longlong tmp=Field_datetime::val_int();
- long part1,part2;
- part1=(long) (tmp/LL(1000000));
- part2=(long) (tmp - (ulonglong) part1*LL(1000000));
+ uint32 part1,part2;
+ part1=(uint32) (tmp/LL(1000000));
+ part2=(uint32) (tmp - (ulonglong) part1*LL(1000000));
ltime->time_type= TIMESTAMP_FULL;
- ltime->neg=0;
- ltime->second_part=0;
- ltime->second= part2%100;
- ltime->minute= part2/100%100;
- ltime->hour= part2/10000;
- ltime->day= part1%100;
- ltime->month= part1/100%100;
- ltime->year= part1/10000;
+ ltime->neg= 0;
+ ltime->second_part= 0;
+ ltime->second= (int) (part2%100);
+ ltime->minute= (int) (part2/100%100);
+ ltime->hour= (int) (part2/10000);
+ ltime->day= (int) (part1%100);
+ ltime->month= (int) (part1/100%100);
+ ltime->year= (int) (part1/10000);
return (!fuzzydate && (!ltime->month || !ltime->day)) ? 1 : 0;
}
@@ -3331,7 +3357,7 @@ void Field_string::store(longlong nr)
{
char buff[22];
char *end=longlong10_to_str(nr,buff,-10);
- Field_string::store(buff,end-buff);
+ Field_string::store(buff,(uint) (end-buff));
}
@@ -3522,7 +3548,7 @@ void Field_varstring::store(longlong nr)
{
char buff[22];
char *end=longlong10_to_str(nr,buff,-10);
- Field_varstring::store(buff,end-buff);
+ Field_varstring::store(buff,(uint) (end-buff));
}
@@ -3613,9 +3639,9 @@ char *Field_varstring::pack(char *to, const char *from, uint max_length)
uint length=uint2korr(from);
if (length > max_length)
length=max_length;
- *to++= (length & 255);
+ *to++= (char) (length & 255);
if (max_length > 255)
- *to++= (uchar) (length >> 8);
+ *to++= (char) (length >> 8);
if (length)
memcpy(to, from+2, length);
return to+length;
@@ -3704,7 +3730,7 @@ uint Field_varstring::max_packed_col_length(uint max_length)
** packlength slot and may be from 1-4.
****************************************************************************/
-Field_blob::Field_blob(char *ptr_arg, uchar *null_ptr_arg, uint null_bit_arg,
+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,
bool binary_arg)
@@ -3721,7 +3747,7 @@ Field_blob::Field_blob(char *ptr_arg, uchar *null_ptr_arg, uint null_bit_arg,
}
-void Field_blob::store_length(ulong number)
+void Field_blob::store_length(uint32 number)
{
switch (packlength) {
case 1:
@@ -3748,9 +3774,9 @@ void Field_blob::store_length(ulong number)
shortstore(ptr,(unsigned short) number);
break;
case 3:
- if (number > (ulong) (1L << 24))
+ if (number > (uint32) (1L << 24))
{
- number= (ulong) (1L << 24)-1L;
+ number= (uint32) (1L << 24)-1L;
current_thd->cuted_fields++;
}
int3store(ptr,number);
@@ -3768,11 +3794,11 @@ void Field_blob::store_length(ulong number)
}
-ulong Field_blob::get_length(const char *pos)
+uint32 Field_blob::get_length(const char *pos)
{
switch (packlength) {
case 1:
- return (ulong) (uchar) pos[0];
+ return (uint32) (uchar) pos[0];
case 2:
{
uint16 tmp;
@@ -3782,10 +3808,10 @@ ulong Field_blob::get_length(const char *pos)
else
#endif
shortget(tmp,pos);
- return (ulong) tmp;
+ return (uint32) tmp;
}
case 3:
- return (ulong) uint3korr(pos);
+ return (uint32) uint3korr(pos);
case 4:
{
uint32 tmp;
@@ -3795,7 +3821,7 @@ ulong Field_blob::get_length(const char *pos)
else
#endif
longget(tmp,pos);
- return (ulong) tmp;
+ return (uint32) tmp;
}
}
return 0; // Impossible
@@ -3841,14 +3867,14 @@ void Field_blob::store(const char *from,uint len)
void Field_blob::store(double nr)
{
value.set(nr);
- Field_blob::store(value.ptr(),value.length());
+ Field_blob::store(value.ptr(),(uint) value.length());
}
void Field_blob::store(longlong nr)
{
value.set(nr);
- Field_blob::store(value.ptr(),value.length());
+ Field_blob::store(value.ptr(), (uint) value.length());
}
@@ -3859,7 +3885,7 @@ double Field_blob::val_real(void)
memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
if (!blob)
return 0.0;
- ulong length=get_length(ptr);
+ uint32 length=get_length(ptr);
char save=blob[length]; // Ok to patch blob in NISAM
blob[length]=0;
@@ -3875,7 +3901,7 @@ longlong Field_blob::val_int(void)
memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
if (!blob)
return 0;
- ulong length=get_length(ptr);
+ uint32 length=get_length(ptr);
char save=blob[length]; // Ok to patch blob in NISAM
blob[length]=0;
@@ -3898,8 +3924,8 @@ String *Field_blob::val_str(String *val_buffer __attribute__((unused)),
}
-int Field_blob::cmp(const char *a,ulong a_length, const char *b,
- ulong b_length)
+int Field_blob::cmp(const char *a,uint32 a_length, const char *b,
+ uint32 b_length)
{
int diff;
if (binary_flag)
@@ -3933,11 +3959,11 @@ int Field_blob::cmp_binary_offset(uint row_offset)
int Field_blob::cmp_binary(const char *a_ptr, const char *b_ptr,
- ulong max_length)
+ uint32 max_length)
{
char *a,*b;
uint diff;
- ulong a_length,b_length;
+ uint32 a_length,b_length;
memcpy_fixed(&a,a_ptr+packlength,sizeof(char*));
memcpy_fixed(&b,b_ptr+packlength,sizeof(char*));
a_length=get_length(a_ptr);
@@ -3956,9 +3982,9 @@ int Field_blob::cmp_binary(const char *a_ptr, const char *b_ptr,
void Field_blob::get_key_image(char *buff,uint length)
{
length-=HA_KEY_BLOB_LENGTH;
- ulong blob_length=get_length(ptr);
+ uint32 blob_length=get_length(ptr);
char *blob;
- if ((ulong) length > blob_length)
+ if ((uint32) length > blob_length)
{
#ifdef HAVE_purify
bzero(buff+2+blob_length, (length-blob_length));
@@ -4052,7 +4078,7 @@ char *Field_blob::pack(char *to, const char *from, uint max_length)
{
char *save=ptr;
ptr=(char*) from;
- ulong length=get_length(); // Length of from string
+ uint32 length=get_length(); // Length of from string
if (length > max_length)
{
ptr=to;
@@ -4075,7 +4101,7 @@ char *Field_blob::pack(char *to, const char *from, uint max_length)
const char *Field_blob::unpack(char *to, const char *from)
{
memcpy(to,from,packlength);
- ulong length=get_length(from);
+ uint32 length=get_length(from);
from+=packlength;
if (length)
memcpy_fixed(to+packlength, &from, sizeof(from));
@@ -4084,60 +4110,6 @@ const char *Field_blob::unpack(char *to, const char *from)
return from+length;
}
-
-#ifdef HAVE_GEMINI_DB
-/* Blobs in Gemini tables are stored separately from the rows which contain
-** them (except for tiny blobs, which are stored in the row). For all other
-** blob types (blob, mediumblob, longblob), the row contains the length of
-** the blob data and a blob id. These methods (pack_id, get_id, and
-** unpack_id) handle packing and unpacking blob fields in Gemini rows.
-*/
-char *Field_blob::pack_id(char *to, const char *from, ulonglong id, uint max_length)
-{
- char *save=ptr;
- ptr=(char*) from;
- ulong length=get_length(); // Length of from string
- if (length > max_length)
- {
- ptr=to;
- length=max_length;
- store_length(length); // Store max length
- ptr=(char*) from;
- }
- else
- memcpy(to,from,packlength); // Copy length
- if (length)
- {
- int8store(to+packlength, id);
- }
- ptr=save; // Restore org row pointer
- return to+packlength+sizeof(id);
-}
-
-
-ulonglong Field_blob::get_id(const char *from)
-{
- ulonglong id = 0;
- ulong length=get_length(from);
- if (length)
- id=uint8korr(from+packlength);
- return id;
-}
-
-
-const char *Field_blob::unpack_id(char *to, const char *from, const char *bdata)
-{
- memcpy(to,from,packlength);
- ulong length=get_length(from);
- from+=packlength;
- if (length)
- memcpy_fixed(to+packlength, &bdata, sizeof(bdata));
- else
- bzero(to+packlength,sizeof(bdata));
- return from+sizeof(ulonglong);
-}
-#endif /* HAVE_GEMINI_DB */
-
/* Keys for blobs are like keys on varchars */
int Field_blob::pack_cmp(const char *a, const char *b, uint key_length)
@@ -4194,7 +4166,7 @@ char *Field_blob::pack_key(char *to, const char *from, uint max_length)
{
char *save=ptr;
ptr=(char*) from;
- ulong length=get_length(); // Length of from string
+ uint32 length=get_length(); // Length of from string
if (length > max_length)
length=max_length;
*to++= (uchar) length;
@@ -4217,9 +4189,9 @@ char *Field_blob::pack_key_from_key_image(char *to, const char *from,
uint length=uint2korr(from);
if (length > max_length)
length=max_length;
- *to++= (length & 255);
+ *to++= (char) (length & 255);
if (max_length > 255)
- *to++= (uchar) (length >> 8);
+ *to++= (char) (length >> 8);
if (length)
memcpy(to, from+2, length);
return to+length;
@@ -4332,7 +4304,7 @@ void Field_enum::store(const char *from,uint length)
conv=buff;
}
my_errno=0;
- tmp=strtoul(conv,&end,10);
+ tmp=(uint) strtoul(conv,&end,10);
if (my_errno || end != conv+length || tmp > typelib->count)
{
tmp=0;
@@ -4602,7 +4574,7 @@ bool Field_enum::eq_def(Field *field)
if (!Field::eq_def(field))
return 0;
TYPELIB *from_lib=((Field_enum*) field)->typelib;
-
+
if (typelib->count < from_lib->count)
return 0;
for (uint i=0 ; i < from_lib->count ; i++)
@@ -4612,7 +4584,7 @@ bool Field_enum::eq_def(Field *field)
}
bool Field_num::eq_def(Field *field)
-{
+{
if (!Field::eq_def(field))
return 0;
Field_num *from_num= (Field_num*) field;
@@ -4678,7 +4650,7 @@ uint pack_length_to_packflag(uint type)
Field *make_field(char *ptr, uint32 field_length,
- uchar *null_pos, uint null_bit,
+ uchar *null_pos, uchar null_bit,
uint pack_flag,
Field::utype unireg_check,
TYPELIB *interval,
diff --git a/sql/field.h b/sql/field.h
index b138eb772d8..a9b257f0c3a 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1,23 +1,23 @@
/* 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 */
/*
-** Because of the function new_field all field classes that have static
-** variables must declare the size_of() member function.
+ Because of the function new_field() all field classes that have static
+ variables must declare the size_of() member function.
*/
#ifdef __GNUC__
@@ -31,27 +31,28 @@ struct st_cache_field;
void field_conv(Field *to,Field *from);
class Field {
- Field(const Item &); /* Prevent use of theese */
+ Field(const Item &); /* Prevent use of these */
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) {} /*lint -e715 */
- enum utype { NONE,DATE,SHIELD,NOEMPTY,CASEUP,PNR,BGNR,PGNR,YES,NO,REL,
- CHECK,EMPTY,UNKNOWN_FIELD,CASEDN,NEXT_NUMBER,INTERVAL_FIELD,
- BIT_FIELD, TIMESTAMP_FIELD,CAPITALIZE,BLOB_FIELD};
- char *ptr; // Position to field in record
+ char *ptr; // Position to field in record
uchar *null_ptr; // Byte where null_bit is
- uint8 null_bit; // And position to it
struct st_table *table; // Pointer for table
- ulong query_id; // For quick test of used fields
- key_map key_start,part_of_key,part_of_sortkey;// Field is part of these keys.
- const char *table_name,*field_name;
- utype unireg_check;
- uint32 field_length; // Length of field
- uint16 flags;
-
- Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,uint null_bit_arg,
+ const char *table_name,*field_name;
+ ulong 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;
+ enum utype { NONE,DATE,SHIELD,NOEMPTY,CASEUP,PNR,BGNR,PGNR,YES,NO,REL,
+ CHECK,EMPTY,UNKNOWN_FIELD,CASEDN,NEXT_NUMBER,INTERVAL_FIELD,
+ BIT_FIELD, TIMESTAMP_FIELD,CAPITALIZE,BLOB_FIELD};
+ utype unireg_check;
+ uint32 field_length; // Length of field
+ uint16 flags;
+ uchar null_bit; // Bit used to test null bit
+
+ Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,uchar null_bit_arg,
utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg);
virtual ~Field() {}
@@ -77,7 +78,7 @@ public:
virtual enum_field_types real_type() const { return type(); }
inline int cmp(const char *str) { return cmp(ptr,str); }
virtual int cmp(const char *,const char *)=0;
- virtual int cmp_binary(const char *a,const char *b, ulong max_length=~0L)
+ 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()); }
@@ -92,7 +93,7 @@ public:
// Caller beware: sql_type can change str.Ptr, so check
// ptr() to see if it changed if you are using your own buffer
// in str and restore it with set() if needed
-
+
virtual uint size_of() const =0; // For new field
inline bool is_null(uint row_offset=0)
{ return null_ptr ? (null_ptr[row_offset] & null_bit ? 1 : 0) : table->null_row; }
@@ -101,30 +102,30 @@ public:
inline void set_null(int row_offset=0)
{ if (null_ptr) null_ptr[row_offset]|= null_bit; }
inline void set_notnull(int row_offset=0)
- { if (null_ptr) null_ptr[row_offset]&= ~null_bit; }
+ { 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 sort_string(char *buff,uint length)=0;
virtual bool optimize_range();
virtual bool store_for_compare() { return 0; }
- inline Field *new_field(struct st_table *new_table)
- {
- Field *tmp= (Field*) sql_memdup((char*) this,size_of());
- if (tmp)
- {
- tmp->table=new_table;
- tmp->key_start=tmp->part_of_key=tmp->part_of_sortkey=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;
- }
- inline void move_field(char *ptr_arg,uchar *null_ptr_arg,uint null_bit_arg)
+ Field *new_field(MEM_ROOT *root, struct st_table *new_table)
+ {
+ Field *tmp= (Field*) memdup_root(root,(char*) this,size_of());
+ if (tmp)
{
- ptr=ptr_arg; null_ptr=null_ptr_arg; null_bit=null_bit_arg;
+ tmp->table=new_table;
+ tmp->key_start=tmp->part_of_key=tmp->part_of_sortkey=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;
+ }
+ inline 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;
+ }
inline void move_field(char *ptr_arg) { ptr=ptr_arg; }
inline void move_field(my_ptrdiff_t ptr_diff)
{
@@ -154,10 +155,10 @@ public:
ptr-=row_offset;
return tmp;
}
- bool send(String *packet);
+ bool send(THD *thd, String *packet);
virtual char *pack(char* to, const char *from, uint max_length=~(uint) 0)
{
- uint length=pack_length();
+ uint32 length=pack_length();
memcpy(to,from,length);
return to+length;
}
@@ -212,10 +213,10 @@ public:
const uint8 dec;
bool zerofill,unsigned_flag; // Purify cannot handle bit fields
Field_num(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
- uint null_bit_arg, utype unireg_check_arg,
+ uchar null_bit_arg, utype unireg_check_arg,
const char *field_name_arg,
struct st_table *table_arg,
- uint dec_arg,bool zero_arg,bool unsigned_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)
@@ -230,7 +231,7 @@ public:
void add_zerofill_and_unsigned(String &res) const;
friend class create_field;
void make_field(Send_field *);
- uint decimals() const { return dec; }
+ uint decimals() const { return (uint) dec; }
uint size_of() const { return sizeof(*this); }
bool eq_def(Field *field);
};
@@ -239,7 +240,7 @@ public:
class Field_str :public Field {
public:
Field_str(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
- uint null_bit_arg, utype unireg_check_arg,
+ uchar null_bit_arg, utype unireg_check_arg,
const char *field_name_arg,
struct st_table *table_arg)
:Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
@@ -256,10 +257,10 @@ public:
class Field_decimal :public Field_num {
public:
Field_decimal(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,
- uint dec_arg,bool zero_arg,bool unsigned_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)
@@ -285,7 +286,7 @@ public:
class Field_tiny :public Field_num {
public:
Field_tiny(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,
bool zero_arg, bool unsigned_arg)
@@ -314,7 +315,7 @@ public:
class Field_short :public Field_num {
public:
Field_short(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,
bool zero_arg, bool unsigned_arg)
@@ -343,7 +344,7 @@ public:
class Field_medium :public Field_num {
public:
Field_medium(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,
bool zero_arg, bool unsigned_arg)
@@ -372,7 +373,7 @@ public:
class Field_long :public Field_num {
public:
Field_long(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,
bool zero_arg, bool unsigned_arg)
@@ -407,7 +408,7 @@ public:
class Field_longlong :public Field_num {
public:
Field_longlong(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,
bool zero_arg, bool unsigned_arg)
@@ -415,10 +416,11 @@ public:
unireg_check_arg, field_name_arg, table_arg,
0, zero_arg,unsigned_arg)
{}
- Field_longlong(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
- struct st_table *table_arg)
+ Field_longlong(uint32 len_arg,bool maybe_null_arg,
+ const char *field_name_arg,
+ struct st_table *table_arg, bool unsigned_arg)
:Field_num((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg, table_arg,0,0,0)
+ NONE, field_name_arg, table_arg,0,0,unsigned_arg)
{}
enum Item_result result_type () const { return INT_RESULT; }
enum_field_types type() const { return FIELD_TYPE_LONGLONG;}
@@ -441,10 +443,10 @@ public:
class Field_float :public Field_num {
public:
Field_float(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,
- uint dec_arg,bool zero_arg,bool unsigned_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)
@@ -468,16 +470,16 @@ public:
class Field_double :public Field_num {
public:
Field_double(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,
- uint dec_arg,bool zero_arg,bool unsigned_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_double(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg,
- struct st_table *table_arg, uint dec_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)
{}
@@ -566,7 +568,7 @@ public:
class Field_year :public Field_tiny {
public:
Field_year(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg)
:Field_tiny(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
@@ -585,12 +587,16 @@ public:
class Field_date :public Field_str {
public:
- Field_date(char *ptr_arg, uchar *null_ptr_arg, uint null_bit_arg,
+ Field_date(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)
:Field_str(ptr_arg, 10, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, table_arg)
{}
+ Field_date(bool maybe_null_arg, const char *field_name_arg,
+ struct st_table *table_arg)
+ :Field_str((char*) 0,10, maybe_null_arg ? (uchar*) "": 0,0,
+ NONE, field_name_arg, table_arg) {}
enum_field_types type() const { return FIELD_TYPE_DATE;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; }
enum Item_result cmp_type () const { return INT_RESULT; }
@@ -611,7 +617,7 @@ public:
class Field_newdate :public Field_str {
public:
- Field_newdate(char *ptr_arg, uchar *null_ptr_arg, uint null_bit_arg,
+ Field_newdate(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)
:Field_str(ptr_arg, 10, null_ptr_arg, null_bit_arg,
@@ -642,12 +648,16 @@ public:
class Field_time :public Field_str {
public:
- Field_time(char *ptr_arg, uchar *null_ptr_arg, uint null_bit_arg,
+ Field_time(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)
:Field_str(ptr_arg, 8, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, table_arg)
{}
+ Field_time(bool maybe_null_arg, const char *field_name_arg,
+ struct st_table *table_arg)
+ :Field_str((char*) 0,8, maybe_null_arg ? (uchar*) "": 0,0,
+ NONE, field_name_arg, table_arg) {}
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; }
@@ -670,12 +680,16 @@ public:
class Field_datetime :public Field_str {
public:
- Field_datetime(char *ptr_arg, uchar *null_ptr_arg, uint null_bit_arg,
+ Field_datetime(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)
:Field_str(ptr_arg, 19, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, table_arg)
{}
+ Field_datetime(bool maybe_null_arg, const char *field_name_arg,
+ struct st_table *table_arg)
+ :Field_str((char*) 0,19, maybe_null_arg ? (uchar*) "": 0,0,
+ NONE, field_name_arg, table_arg) {}
enum_field_types type() const { return FIELD_TYPE_DATETIME;}
#ifdef HAVE_LONG_LONG
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; }
@@ -704,7 +718,7 @@ class Field_string :public Field_str {
bool binary_flag;
public:
Field_string(char *ptr_arg, uint32 len_arg,uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,bool binary_arg)
:Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
@@ -759,7 +773,7 @@ class Field_varstring :public Field_str {
bool binary_flag;
public:
Field_varstring(char *ptr_arg, uint32 len_arg,uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,bool binary_arg)
:Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
@@ -812,7 +826,7 @@ class Field_blob :public Field_str {
String value; // For temporaries
bool binary_flag;
public:
- Field_blob(char *ptr_arg, uchar *null_ptr_arg, uint null_bit_arg,
+ 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,
bool binary_arg);
@@ -836,21 +850,22 @@ public:
longlong val_int(void);
String *val_str(String*,String *);
int cmp(const char *,const char*);
- int cmp(const char *a, ulong a_length, const char *b, ulong b_length);
+ 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, ulong max_length=~0L);
+ 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); }
- void reset(void) { bzero(ptr,packlength+sizeof(char*)); }
+ uint32 pack_length() const
+ { return (uint32) (packlength+table->blob_ptr_size); }
+ void reset(void) { bzero(ptr, packlength+sizeof(char*)); }
void reset_fields() { bzero((char*) &value,sizeof(value)); }
- void store_length(ulong number);
- inline ulong get_length(uint row_offset=0)
+ void store_length(uint32 number);
+ inline uint32 get_length(uint row_offset=0)
{ return get_length(ptr+row_offset); }
- ulong get_length(const char *ptr);
+ uint32 get_length(const char *ptr);
bool binary() const { return binary_flag; }
inline void get_ptr(char **str)
{
@@ -861,7 +876,7 @@ public:
memcpy(ptr,length,packlength);
memcpy_fixed(ptr+packlength,&data,sizeof(char*));
}
- inline void set_ptr(ulong length,char *data)
+ inline void set_ptr(uint32 length,char *data)
{
store_length(length);
memcpy_fixed(ptr+packlength,&data,sizeof(char*));
@@ -882,21 +897,6 @@ public:
}
char *pack(char *to, const char *from, uint max_length= ~(uint) 0);
const char *unpack(char *to, const char *from);
-#ifdef HAVE_GEMINI_DB
- char *pack_id(char *to, const char *from, ulonglong id,
- uint max_length= ~(uint) 0);
- ulonglong get_id(const char *from);
- const char *unpack_id(char *to, const char *from, const char *bdata);
- inline void get_ptr_from_key_image(char **str,char *key_str)
- {
- *str = key_str + sizeof(uint16);
- }
- inline uint get_length_from_key_image(char *key_str)
- {
- return uint2korr(key_str);
- }
- enum_field_types blobtype() { return (packlength == 1 ? FIELD_TYPE_TINY_BLOB : FIELD_TYPE_BLOB);}
-#endif
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);
int pack_cmp(const char *a, const char *b, uint key_length);
@@ -916,7 +916,7 @@ protected:
public:
TYPELIB *typelib;
Field_enum(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,uint packlength_arg,
TYPELIB *typelib_arg)
@@ -953,7 +953,7 @@ public:
class Field_set :public Field_enum {
public:
Field_set(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,uint32 packlength_arg,
TYPELIB *typelib_arg)
@@ -1036,7 +1036,7 @@ public:
Field *make_field(char *ptr, uint32 field_length,
- uchar *null_pos, uint null_bit,
+ uchar *null_pos, uchar null_bit,
uint pack_flag, Field::utype unireg_check,
TYPELIB *interval, const char *field_name,
struct st_table *table);
@@ -1079,7 +1079,7 @@ bool test_if_int(const char *str,int length);
#define f_is_zerofill(x) ((x) & FIELDFLAG_ZEROFILL)
#define f_is_packed(x) ((x) & FIELDFLAG_PACK)
#define f_packtype(x) (((x) >> FIELDFLAG_PACK_SHIFT) & 15)
-#define f_decimals(x) (((x) >> FIELDFLAG_DEC_SHIFT) & FIELDFLAG_MAX_DEC)
+#define f_decimals(x) ((uint8) (((x) >> FIELDFLAG_DEC_SHIFT) & FIELDFLAG_MAX_DEC))
#define f_is_alpha(x) (!f_is_num(x))
#define f_is_binary(x) ((x) & FIELDFLAG_BINARY)
#define f_is_enum(x) ((x) & FIELDFLAG_INTERVAL)
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index 606edd84c74..c7a6d778953 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -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 */
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 86c95395965..7e3d1c96f57 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -22,13 +22,11 @@
#include <stddef.h> /* for macro offsetof */
#endif
#include <m_ctype.h>
+#include "sql_sort.h"
+
#ifndef THREAD
-#define SKIPP_DBUG_IN_FILESORT
+#define SKIP_DBUG_IN_FILESORT
#endif
- /* static variabels */
-
-#define MERGEBUFF 7
-#define MERGEBUFF2 15
/* How to write record_ref. */
@@ -36,85 +34,63 @@
if (my_b_write((file),(byte*) (from),param->ref_length)) \
DBUG_RETURN(1);
-typedef struct st_buffpek { /* Struktur om sorteringsbuffrarna */
- my_off_t file_pos; /* Where we are in the sort file */
- uchar *base,*key; /* key pointers */
- ha_rows count; /* Number of rows in table */
- ulong mem_count; /* numbers of keys in memory */
- ulong max_keys; /* Max keys in buffert */
-} BUFFPEK;
-
-
-typedef struct st_sort_param {
- uint sort_length; /* Length of sortarg */
- uint keys; /* Max antal nycklar / buffert */
- uint ref_length; /* Length of record ref. */
- ha_rows max_rows,examined_rows;
- TABLE *sort_form; /* For quicker make_sortkey */
- SORT_FIELD *local_sortorder;
- SORT_FIELD *end;
-#ifdef USE_STRCOLL
- char* tmp_buffer;
-#endif
-} SORTPARAM;
-
/* functions defined in this file */
static char **make_char_array(register uint fields, uint length, myf my_flag);
+static BUFFPEK *read_buffpek_from_file(IO_CACHE *buffer_file, uint count);
static ha_rows find_all_keys(SORTPARAM *param,SQL_SELECT *select,
- uchar * *sort_keys,
- BUFFPEK *buffpek,uint *maxbuffer,
+ uchar * *sort_keys, IO_CACHE *buffer_file,
IO_CACHE *tempfile,IO_CACHE *indexfile);
static int write_keys(SORTPARAM *param,uchar * *sort_keys,
- uint count,BUFFPEK *buffpek,
- IO_CACHE *tempfile);
-static void make_sortkey(SORTPARAM *param,uchar *to,
- byte *ref_pos);
-static bool save_index(SORTPARAM *param,uchar **sort_keys, uint count);
-static int merge_many_buff(SORTPARAM *param,uchar * *sort_keys,
- BUFFPEK *buffpek,
- uint *maxbuffer, IO_CACHE *t_file);
-static uint read_to_buffer(IO_CACHE *fromfile,BUFFPEK *buffpek,
- uint sort_length);
-static int merge_buffers(SORTPARAM *param,IO_CACHE *from_file,
- IO_CACHE *to_file,uchar * *sort_keys,
- BUFFPEK *lastbuff,BUFFPEK *Fb,
- BUFFPEK *Tb,int flag);
-static int merge_index(SORTPARAM *param,uchar * *sort_keys,
+ uint count, IO_CACHE *buffer_file, IO_CACHE *tempfile);
+static void make_sortkey(SORTPARAM *param,uchar *to, byte *ref_pos);
+static 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 uint sortlength(SORT_FIELD *sortorder,uint length);
- /* Makes a indexfil of recordnumbers of a sorted database */
- /* outfile is reset before data is written to it, if it wasn't
- open a new file is opened */
+ /*
+ Creates a set of pointers that can be used to read the rows
+ in sorted order. This should be done with the functions
+ in records.cc
+
+ Before calling filesort, one must have done
+ table->file->info(HA_STATUS_VARIABLE)
-ha_rows filesort(TABLE **table, SORT_FIELD *sortorder, uint s_length,
+ The result set is stored in table->io_cache or
+ table->record_pointers
+ */
+
+ha_rows filesort(TABLE *table, SORT_FIELD *sortorder, uint s_length,
SQL_SELECT *select, ha_rows special, ha_rows max_rows,
ha_rows *examined_rows)
{
int error;
- uint memavl,old_memavl,maxbuffer,skr;
+ ulong memavl;
+ uint maxbuffer;
BUFFPEK *buffpek;
ha_rows records;
uchar **sort_keys;
- IO_CACHE tempfile,*selected_records_file,*outfile;
+ IO_CACHE tempfile, buffpek_pointers, *selected_records_file, *outfile;
SORTPARAM param;
DBUG_ENTER("filesort");
- DBUG_EXECUTE("info",TEST_filesort(table,sortorder,s_length,special););
-#ifdef SKIPP_DBUG_IN_FILESORT
+ DBUG_EXECUTE("info",TEST_filesort(sortorder,s_length,special););
+#ifdef SKIP_DBUG_IN_FILESORT
DBUG_PUSH(""); /* No DBUG here */
#endif
- outfile= table[0]->io_cache;
+ outfile= table->io_cache;
my_b_clear(&tempfile);
- buffpek= (BUFFPEK *) NULL; sort_keys= (uchar **) NULL; error= 1;
- maxbuffer=1;
- param.ref_length= table[0]->file->ref_length;
+ my_b_clear(&buffpek_pointers);
+ buffpek=0;
+ sort_keys= (uchar **) NULL;
+ error= 1;
+ bzero((char*) &param,sizeof(param));
+ param.ref_length= table->file->ref_length;
param.sort_length=sortlength(sortorder,s_length)+ param.ref_length;
param.max_rows= max_rows;
- param.examined_rows=0;
if (select && select->quick)
{
@@ -139,17 +115,14 @@ ha_rows filesort(TABLE **table, SORT_FIELD *sortorder, uint s_length,
#ifdef CAN_TRUST_RANGE
else if (select && select->quick && select->quick->records > 0L)
{
- /* Get record-count */
- table[0]->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
records=min((ha_rows) (select->quick->records*2+EXTRA_RECORDS*2),
- table[0]->file->records)+EXTRA_RECORDS;
+ table->file->records)+EXTRA_RECORDS;
selected_records_file=0;
}
#endif
else
{
- table[0]->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);/* Get record-count */
- records=table[0]->file->estimate_number_of_rows();
+ records=table->file->estimate_number_of_rows();
selected_records_file= 0;
}
if (param.sort_length == param.ref_length && records > param.max_rows)
@@ -164,51 +137,34 @@ ha_rows filesort(TABLE **table, SORT_FIELD *sortorder, uint s_length,
memavl=sortbuff_size;
while (memavl >= MIN_SORT_MEMORY)
{
- if ((ulonglong) (records+1)*(param.sort_length+sizeof(char*))+sizeof(BUFFPEK)*10 <
- (ulonglong) memavl)
- param.keys=(uint) records+1;
- else
- {
- maxbuffer=1;
- do
- {
- skr=maxbuffer;
- if (memavl < sizeof(BUFFPEK)*maxbuffer)
- {
- my_error(ER_OUT_OF_SORTMEMORY,MYF(ME_ERROR+ME_WAITTANG));
- goto err;
- }
- param.keys=(memavl-sizeof(BUFFPEK)*maxbuffer)/
- (param.sort_length+sizeof(char*));
- }
- while ((maxbuffer= (uint) (records/param.keys+1)) != skr);
- }
- if ((sort_keys= (uchar **) make_char_array(param.keys,param.sort_length,
+ ulong old_memavl;
+ ulong keys= memavl/(param.sort_length+sizeof(char*));
+ param.keys=(uint) min(records+1, keys);
+ if ((sort_keys= (uchar **) make_char_array(param.keys, param.sort_length,
MYF(0))))
- if ((buffpek = (BUFFPEK*) my_malloc((uint) sizeof(BUFFPEK)*
- (maxbuffer+10),
- MYF(0))))
- break;
- else
- my_free((gptr) sort_keys,MYF(0));
+ break;
old_memavl=memavl;
if ((memavl=memavl/4*3) < MIN_SORT_MEMORY && old_memavl > MIN_SORT_MEMORY)
memavl=MIN_SORT_MEMORY;
}
- param.keys--;
- maxbuffer+=10; /* Some extra range */
-
if (memavl < MIN_SORT_MEMORY)
{
my_error(ER_OUTOFMEMORY,MYF(ME_ERROR+ME_WAITTANG),sortbuff_size);
goto err;
}
- param.sort_form= table[0];
+ if (open_cached_file(&buffpek_pointers,mysql_tmpdir,TEMP_PREFIX,
+ DISK_BUFFER_SIZE, MYF(MY_WME)))
+ goto err;
+
+ param.keys--;
+ param.sort_form= table;
param.end=(param.local_sortorder=sortorder)+s_length;
- if ((records=find_all_keys(&param,select,sort_keys,buffpek,&maxbuffer,
+ if ((records=find_all_keys(&param,select,sort_keys, &buffpek_pointers,
&tempfile, selected_records_file)) ==
HA_POS_ERROR)
goto err;
+ maxbuffer= (uint) (my_b_tell(&buffpek_pointers)/sizeof(*buffpek));
+
if (maxbuffer == 0) // The whole set is in memory
{
if (save_index(&param,sort_keys,(uint) records))
@@ -216,6 +172,9 @@ ha_rows filesort(TABLE **table, SORT_FIELD *sortorder, uint s_length,
}
else
{
+ if (!(buffpek=read_buffpek_from_file(&buffpek_pointers, maxbuffer)))
+ goto err;
+ close_cached_file(&buffpek_pointers);
/* Open cached file if it isn't open */
if (! my_b_inited(outfile) &&
open_cached_file(outfile,mysql_tmpdir,TEMP_PREFIX,READ_RECORD_BUFFER,
@@ -223,14 +182,21 @@ ha_rows filesort(TABLE **table, SORT_FIELD *sortorder, uint s_length,
goto err;
reinit_io_cache(outfile,WRITE_CACHE,0L,0,0);
+ /*
+ Use also the space previously used by string pointers in sort_buffer
+ for temporary key storage.
+ */
param.keys=((param.keys*(param.sort_length+sizeof(char*))) /
param.sort_length-1);
- if (merge_many_buff(&param,sort_keys,buffpek,&maxbuffer,&tempfile))
+ maxbuffer--; // Offset from 0
+ if (merge_many_buff(&param,(uchar*) sort_keys,buffpek,&maxbuffer,
+ &tempfile))
goto err;
if (flush_io_cache(&tempfile) ||
reinit_io_cache(&tempfile,READ_CACHE,0L,0,0))
goto err;
- if (merge_index(&param,sort_keys,buffpek,maxbuffer,&tempfile,outfile))
+ if (merge_index(&param,(uchar*) sort_keys,buffpek,maxbuffer,&tempfile,
+ outfile))
goto err;
}
if (records > param.max_rows)
@@ -245,6 +211,7 @@ ha_rows filesort(TABLE **table, SORT_FIELD *sortorder, uint s_length,
x_free((gptr) sort_keys);
x_free((gptr) buffpek);
close_cached_file(&tempfile);
+ close_cached_file(&buffpek_pointers);
if (my_b_inited(outfile))
{
if (flush_io_cache(outfile))
@@ -262,7 +229,7 @@ ha_rows filesort(TABLE **table, SORT_FIELD *sortorder, uint s_length,
else
statistic_add(filesort_rows, records, &LOCK_status);
*examined_rows= param.examined_rows;
-#ifdef SKIPP_DBUG_IN_FILESORT
+#ifdef SKIP_DBUG_IN_FILESORT
DBUG_POP(); /* Ok to DBUG */
#endif
DBUG_PRINT("exit",("records: %ld",records));
@@ -289,11 +256,33 @@ static char **make_char_array(register uint fields, uint length, myf my_flag)
} /* make_char_array */
+ /* Read all buffer pointers into memory */
+
+static BUFFPEK *read_buffpek_from_file(IO_CACHE *buffpek_pointers, uint count)
+{
+ ulong length;
+ BUFFPEK *tmp;
+ DBUG_ENTER("read_buffpek_from_file");
+ tmp=(BUFFPEK*) my_malloc(length=sizeof(BUFFPEK)*count, MYF(MY_WME));
+ if (tmp)
+ {
+ if (reinit_io_cache(buffpek_pointers,READ_CACHE,0L,0,0) ||
+ my_b_read(buffpek_pointers, (byte*) tmp, length))
+ {
+ my_free((char*) tmp, MYF(0));
+ tmp=0;
+ }
+ }
+ DBUG_RETURN(tmp);
+}
+
+
+
/* Search after sort_keys and place them in a temp. file */
static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
uchar **sort_keys,
- BUFFPEK *buffpek, uint *maxbuffer,
+ IO_CACHE *buffpek_pointers,
IO_CACHE *tempfile, IO_CACHE *indexfile)
{
int error,flag,quick_select;
@@ -375,9 +364,8 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
{
if (idx == param->keys)
{
- if (indexpos >= *maxbuffer ||
- write_keys(param,sort_keys,idx,buffpek+indexpos,tempfile))
- DBUG_RETURN(HA_POS_ERROR);
+ if (write_keys(param,sort_keys,idx,buffpek_pointers,tempfile))
+ DBUG_RETURN(HA_POS_ERROR);
idx=0; indexpos++;
if (param->ref_length == param->sort_length &&
my_b_tell(tempfile)/param->sort_length >= param->max_rows)
@@ -399,11 +387,9 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
file->print_error(error,MYF(ME_ERROR | ME_WAITTANG)); /* purecov: inspected */
DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
}
- if (indexpos)
- if (indexpos >= *maxbuffer ||
- write_keys(param,sort_keys,idx,buffpek+indexpos,tempfile))
- DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
- *maxbuffer=indexpos;
+ if (indexpos &&
+ write_keys(param,sort_keys,idx,buffpek_pointers,tempfile))
+ DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
DBUG_RETURN(my_b_inited(tempfile) ?
(ha_rows) (my_b_tell(tempfile)/param->sort_length) :
idx);
@@ -412,10 +398,13 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
/* Skriver en buffert med nycklar till filen */
-static int write_keys(SORTPARAM *param, register uchar **sort_keys, uint count,
- BUFFPEK *buffpek, IO_CACHE *tempfile)
+static int
+write_keys(SORTPARAM *param, register uchar **sort_keys, uint count,
+ IO_CACHE *buffpek_pointers, IO_CACHE *tempfile)
{
uint sort_length;
+ uchar **end;
+ BUFFPEK buffpek;
DBUG_ENTER("write_keys");
sort_length=param->sort_length;
@@ -427,15 +416,20 @@ static int 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)))
- DBUG_RETURN(1); /* purecov: inspected */
- buffpek->file_pos=my_b_tell(tempfile);
+ 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 */
- buffpek->count=(ha_rows) count;
- for (uchar **end=sort_keys+count ; sort_keys != end ; sort_keys++)
+ buffpek.count=(ha_rows) count;
+ for (end=sort_keys+count ; sort_keys != end ; sort_keys++)
if (my_b_write(tempfile,(byte*) *sort_keys,(uint) sort_length))
- DBUG_RETURN(1);
+ goto err;
+ if (my_b_write(buffpek_pointers, (byte*) &buffpek, sizeof(buffpek)))
+ goto err;
DBUG_RETURN(0);
+
+err:
+ DBUG_RETURN(1);
} /* write_keys */
@@ -458,10 +452,7 @@ static void make_sortkey(register SORTPARAM *param,
{
if (field->is_null())
{
- if (sort_field->reverse)
- bfill(to,sort_field->length+1,(char) 255);
- else
- bzero((char*) to,sort_field->length+1);
+ bzero((char*) to,sort_field->length+1);
to+= sort_field->length+1;
continue;
}
@@ -631,8 +622,8 @@ static bool save_index(SORTPARAM *param, uchar **sort_keys, uint count)
/* Merge buffers to make < MERGEBUFF2 buffers */
-static int merge_many_buff(SORTPARAM *param, uchar **sort_keys,
- BUFFPEK *buffpek, uint *maxbuffer, IO_CACHE *t_file)
+int merge_many_buff(SORTPARAM *param, uchar *sort_buffer,
+ BUFFPEK *buffpek, uint *maxbuffer, IO_CACHE *t_file)
{
register int i;
IO_CACHE t_file2,*from_file,*to_file,*temp;
@@ -654,11 +645,11 @@ static int merge_many_buff(SORTPARAM *param, uchar **sort_keys,
lastbuff=buffpek;
for (i=0 ; i <= (int) *maxbuffer-MERGEBUFF*3/2 ; i+=MERGEBUFF)
{
- if (merge_buffers(param,from_file,to_file,sort_keys,lastbuff++,
+ if (merge_buffers(param,from_file,to_file,sort_buffer,lastbuff++,
buffpek+i,buffpek+i+MERGEBUFF-1,0))
break; /* purecov: inspected */
}
- if (merge_buffers(param,from_file,to_file,sort_keys,lastbuff++,
+ if (merge_buffers(param,from_file,to_file,sort_buffer,lastbuff++,
buffpek+i,buffpek+ *maxbuffer,0))
break; /* purecov: inspected */
if (flush_io_cache(to_file))
@@ -677,8 +668,8 @@ static int merge_many_buff(SORTPARAM *param, uchar **sort_keys,
/* Read data to buffer */
/* This returns (uint) -1 if something goes wrong */
-static uint read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek,
- uint sort_length)
+uint read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek,
+ uint sort_length)
{
register uint count;
uint length;
@@ -699,39 +690,44 @@ static uint read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek,
/* Merge buffers to one buffer */
-static int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
- IO_CACHE *to_file, uchar **sort_keys,
- BUFFPEK *lastbuff, BUFFPEK *Fb, BUFFPEK *Tb,
- int flag)
+int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
+ IO_CACHE *to_file, uchar *sort_buffer,
+ BUFFPEK *lastbuff, BUFFPEK *Fb, BUFFPEK *Tb,
+ int flag)
{
int error;
uint sort_length,offset;
ulong maxcount;
- ha_rows count,max_rows;
+ ha_rows max_rows,org_max_rows;
my_off_t to_start_filepos;
uchar *strpos;
BUFFPEK *buffpek,**refpek;
QUEUE queue;
+ qsort2_cmp cmp;
volatile bool *killed= &current_thd->killed;
+ bool not_killable;
DBUG_ENTER("merge_buffers");
statistic_increment(filesort_merge_passes, &LOCK_status);
+ if (param->not_killable)
+ {
+ killed= &not_killable;
+ not_killable=0;
+ }
- count=error=0;
- offset=param->sort_length-param->ref_length;
+ error=0;
+ offset=(sort_length=param->sort_length)-param->ref_length;
maxcount=(ulong) (param->keys/((uint) (Tb-Fb) +1));
to_start_filepos=my_b_tell(to_file);
- strpos=(uchar*) sort_keys;
- sort_length=param->sort_length;
- max_rows=param->max_rows;
+ strpos=(uchar*) sort_buffer;
+ org_max_rows=max_rows=param->max_rows;
if (init_queue(&queue,(uint) (Tb-Fb)+1,offsetof(BUFFPEK,key),0,
(int (*) (void *, byte *,byte*))
- get_ptr_compare(sort_length),(void*) &sort_length))
+ (cmp=get_ptr_compare(sort_length)),(void*) &sort_length))
DBUG_RETURN(1); /* purecov: inspected */
for (buffpek= Fb ; buffpek <= Tb ; buffpek++)
{
- count+= buffpek->count;
buffpek->base= strpos;
buffpek->max_keys=maxcount;
strpos+= (uint) (error=(int) read_to_buffer(from_file,buffpek,
@@ -741,15 +737,46 @@ static int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
queue_insert(&queue,(byte*) buffpek);
}
+ if (param->unique_buff)
+ {
+ /*
+ Called by Unique::get()
+ Copy the first argument to param->unique_buff for unique removal.
+ Store it also in 'to_file'.
+
+ This is safe as we know that there is always more than one element
+ in each block to merge (This is guaranteed by the Unique:: algorithm
+ */
+ buffpek=(BUFFPEK*) queue_top(&queue);
+ memcpy(param->unique_buff, buffpek->key, sort_length);
+ if (my_b_write(to_file,(byte*) buffpek->key, sort_length))
+ {
+ error=1; goto err; /* purecov: inspected */
+ }
+ buffpek->key+=sort_length;
+ buffpek->mem_count--;
+ max_rows--;
+ queue_replaced(&queue); // Top element has been used
+ }
+ else
+ cmp=0; // Not unique
+
while (queue.elements > 1)
{
if (*killed)
{
- error=1; goto err; /* purecov: inspected */
+ error=1; goto err; /* purecov: inspected */
}
for (;;)
{
buffpek=(BUFFPEK*) queue_top(&queue);
+ if (cmp) // Remove duplicates
+ {
+ if (!(*cmp)(&sort_length, &(param->unique_buff),
+ (uchar**) &buffpek->key))
+ goto skip_duplicate;
+ memcpy(param->unique_buff, (uchar*) buffpek->key,sort_length);
+ }
if (flag == 0)
{
if (my_b_write(to_file,(byte*) buffpek->key, sort_length))
@@ -766,6 +793,8 @@ static int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
error=0; /* purecov: inspected */
goto end; /* purecov: inspected */
}
+
+ skip_duplicate:
buffpek->key+=sort_length;
if (! --buffpek->mem_count)
{
@@ -798,14 +827,28 @@ static int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
break; /* One buffer have been removed */
}
else if (error == -1)
- goto err; /* purecov: inspected */
+ goto err; /* purecov: inspected */
}
queue_replaced(&queue); /* Top element has been replaced */
}
}
buffpek=(BUFFPEK*) queue_top(&queue);
- buffpek->base=(uchar *) sort_keys;
+ buffpek->base= sort_buffer;
buffpek->max_keys=param->keys;
+
+ /*
+ As we know all entries in the buffer are unique, we only have to
+ check if the first one is the same as the last one we wrote
+ */
+ if (cmp)
+ {
+ if (!(*cmp)(&sort_length, &(param->unique_buff), (uchar**) &buffpek->key))
+ {
+ buffpek->key+=sort_length; // Remove duplicate
+ --buffpek->mem_count;
+ }
+ }
+
do
{
if ((ha_rows) buffpek->mem_count > max_rows)
@@ -813,6 +856,7 @@ static int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
buffpek->mem_count=(uint) max_rows;
buffpek->count=0; /* Don't read more */
}
+ max_rows-=buffpek->mem_count;
if (flag == 0)
{
if (my_b_write(to_file,(byte*) buffpek->key,
@@ -837,7 +881,7 @@ static int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
!= -1 && error != 0);
end:
- lastbuff->count=min(count,param->max_rows);
+ lastbuff->count=min(org_max_rows-max_rows,param->max_rows);
lastbuff->file_pos=to_start_filepos;
err:
delete_queue(&queue);
@@ -847,12 +891,12 @@ err:
/* Do a merge to output-file (save only positions) */
-static int merge_index(SORTPARAM *param, uchar **sort_keys,
+static int merge_index(SORTPARAM *param, uchar *sort_buffer,
BUFFPEK *buffpek, uint maxbuffer,
IO_CACHE *tempfile, IO_CACHE *outfile)
{
DBUG_ENTER("merge_index");
- if (merge_buffers(param,tempfile,outfile,sort_keys,buffpek,buffpek,
+ if (merge_buffers(param,tempfile,outfile,sort_buffer,buffpek,buffpek,
buffpek+maxbuffer,1))
DBUG_RETURN(1); /* purecov: inspected */
DBUG_RETURN(0);
diff --git a/sql/frm_crypt.cc b/sql/frm_crypt.cc
index 629e4ffab95..8dd70900648 100644
--- a/sql/frm_crypt.cc
+++ b/sql/frm_crypt.cc
@@ -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 */
diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc
index 7bbf08b50f3..7ebdbcd8ba8 100644
--- a/sql/gen_lex_hash.cc
+++ b/sql/gen_lex_hash.cc
@@ -16,17 +16,18 @@
#define NO_YACC_SYMBOLS
-#include <global.h>
+#include <my_global.h>
#include <my_sys.h>
#include <m_string.h>
#ifndef __GNU_LIBRARY__
-#define __GNU_LIBRARY__ // Skipp warnings in getopt.h
+#define __GNU_LIBRARY__ // Skip warnings in getopt.h
#endif
#include <getopt.h>
#include "mysql_version.h"
#include "lex.h"
-bool opt_search=0,opt_verbose=0;
+bool opt_search=0;
+int opt_verbose=0;
ulong opt_count=100000;
#define max_allowed_array 8000 // Don't generate bigger arrays than this
@@ -216,7 +217,7 @@ you have to change 'main' to print out the new function\n");
return(1);
}
- if (opt_verbose)
+ if (opt_verbose > 1)
fprintf (stderr,"Info: Possible add values: %d\n",found-type_count);
for (prime=primes; (function_mod=*prime) ; prime++)
@@ -385,7 +386,7 @@ static int get_options(int argc, char **argv)
opt_search=1;
break;
case 'v':
- opt_verbose=1;
+ opt_verbose++;
break;
case 'V': usage(1); exit(0);
case 'I':
@@ -481,7 +482,8 @@ int main(int argc,char **argv)
int error;
MY_INIT(argv[0]);
- start_value=6130115L; best_t1=3632784L; best_t2=86437L; best_type=3; /* mode=4229 add=2 type: 0 */
+
+ start_value=1109118L; best_t1=6657025L; best_t2=6114496L; best_type=1; /* mode=4903 add=3 type: 0 */
if (get_options(argc,(char **) argv))
exit(1);
@@ -501,7 +503,7 @@ int main(int argc,char **argv)
printf("start_value=%ldL; best_t1=%ldL; best_t2=%ldL; best_type=%d; /* mode=%d add=%d type: %d */\n",
start_value, best_t1,best_t2,best_type,best_mod,best_add,
best_functype);
-
+ best_start_value=start_value;
for (uint i=1 ; i <= opt_count ; i++)
{
if (i % 10 == 0)
@@ -524,6 +526,10 @@ int main(int argc,char **argv)
best_start_value,best_t1,best_t2,best_type,best_mod,best_add,
best_functype);
}
+ if (opt_verbose && (i % 20000) == 0)
+ printf("\nstart_value=%ldL; best_t1=%ldL; best_t2=%ldL; best_type=%d; /* mode=%d add=%d type: %d */\n",
+ best_start_value,best_t1,best_t2,best_type,best_mod,best_add,
+ best_functype);
}
}
diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc
index f52b99f5a12..614d1b5abf5 100644
--- a/sql/ha_berkeley.cc
+++ b/sql/ha_berkeley.cc
@@ -1043,9 +1043,9 @@ int ha_berkeley::restore_keys(DB_TXN *trans, key_map changed_keys,
break; /* purecov: inspected */
}
}
-
+
err:
- dbug_assert(error != DB_KEYEXIST);
+ DBUG_ASSERT(error != DB_KEYEXIST);
DBUG_RETURN(error);
}
@@ -1187,7 +1187,7 @@ int ha_berkeley::remove_key(DB_TXN *trans, uint keynr, const byte *record,
((table->key_info[keynr].flags & (HA_NOSAME | HA_NULL_PART_KEY)) ==
HA_NOSAME))
{ // Unique key
- dbug_assert(keynr == primary_key || prim_key->data != key_buff2);
+ DBUG_ASSERT(keynr == primary_key || prim_key->data != key_buff2);
error=key_file[keynr]->del(key_file[keynr], trans,
keynr == primary_key ?
prim_key :
@@ -1201,7 +1201,7 @@ int ha_berkeley::remove_key(DB_TXN *trans, uint keynr, const byte *record,
row to find the key to be delete and delete it.
We will never come here with keynr = primary_key
*/
- dbug_assert(keynr != primary_key && prim_key->data != key_buff2);
+ DBUG_ASSERT(keynr != primary_key && prim_key->data != key_buff2);
DBC *tmp_cursor;
if (!(error=key_file[keynr]->cursor(key_file[keynr], trans,
&tmp_cursor, 0)))
@@ -1454,6 +1454,37 @@ int ha_berkeley::index_read(byte * buf, const byte * key,
DBUG_RETURN(error);
}
+/*
+ Read last key is solved by reading the next key and then reading
+ the previous key
+*/
+
+int ha_berkeley::index_read_last(byte * buf, const byte * key, uint key_len)
+{
+ DBT row;
+ int error;
+ KEY *key_info= &table->key_info[active_index];
+ DBUG_ENTER("ha_berkeley::index_read");
+
+ statistic_increment(ha_read_key_count,&LOCK_status);
+ bzero((char*) &row,sizeof(row));
+
+ /* read of partial key */
+ pack_key(&last_key, active_index, key_buff, key, key_len);
+ /* Store for compare */
+ memcpy(key_buff2, key_buff, (key_len=last_key.size));
+ key_info->handler.bdb_return_if_eq= 1;
+ error=read_row(cursor->c_get(cursor, &last_key, &row, DB_SET_RANGE),
+ (char*) buf, active_index, &row, (DBT*) 0, 0);
+ key_info->handler.bdb_return_if_eq= 0;
+ bzero((char*) &row,sizeof(row));
+ if (read_row(cursor->c_get(cursor, &last_key, &row, DB_PREV),
+ (char*) buf, active_index, &row, &last_key, 1) ||
+ berkeley_key_cmp(table, key_info, key_buff2, key_len))
+ error=HA_ERR_KEY_NOT_FOUND;
+ DBUG_RETURN(error);
+}
+
int ha_berkeley::index_next(byte * buf)
{
@@ -1565,12 +1596,13 @@ 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");
active_index= (uint) -1; // Don't delete via cursor
- return read_row(file->get(file, transaction,
- get_pos(&db_pos, pos),
- &current_row, 0),
- (char*) buf, primary_key, &current_row, (DBT*) 0, 0);
+ DBUG_RETURN(read_row(file->get(file, transaction,
+ get_pos(&db_pos, pos),
+ &current_row, 0),
+ (char*) buf, primary_key, &current_row, (DBT*) 0, 0));
}
void ha_berkeley::position(const byte *record)
@@ -1879,13 +1911,14 @@ int ha_berkeley::delete_table(const char *name)
{
int error;
char name_buff[FN_REFLEN];
+ DBUG_ENTER("delete_table");
if ((error=db_create(&file, db_env, 0)))
my_errno=error; /* purecov: inspected */
else
error=file->remove(file,fn_format(name_buff,name,"",ha_berkeley_ext,2 | 4),
NULL,0);
file=0; // Safety
- return error;
+ DBUG_RETURN(error);
}
/*
@@ -2175,7 +2208,7 @@ static BDB_SHARE *get_share(const char *table_name, TABLE *table)
char *tmp_name;
DB **key_file;
u_int32_t *key_type;
-
+
if ((share=(BDB_SHARE *)
my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
&share, sizeof(*share),
diff --git a/sql/ha_berkeley.h b/sql/ha_berkeley.h
index ab1ead5a3e9..f30d4e12d6d 100644
--- a/sql/ha_berkeley.h
+++ b/sql/ha_berkeley.h
@@ -89,15 +89,16 @@ class ha_berkeley: public handler
int_option_flag(HA_READ_NEXT | HA_READ_PREV |
HA_REC_NOT_IN_SEQ |
HA_KEYPOS_TO_RNDPOS | HA_READ_ORDER | HA_LASTKEY_ORDER |
- HA_LONGLONG_KEYS | HA_NULL_KEY | HA_HAVE_KEY_READ_ONLY |
- HA_BLOB_KEY | HA_NOT_EXACT_COUNT | HA_NO_FULLTEXT_KEY |
+ HA_NULL_KEY | HA_HAVE_KEY_READ_ONLY |
+ HA_BLOB_KEY | HA_NOT_EXACT_COUNT |
HA_PRIMARY_KEY_IN_READ_INDEX | HA_DROP_BEFORE_CREATE |
- HA_AUTO_PART_KEY),
+ HA_AUTO_PART_KEY | HA_TABLE_SCAN_ON_INDEX),
changed_rows(0),last_dup_key((uint) -1),version(0),using_ignore(0)
{
}
~ha_berkeley() {}
const char *table_type() const { return "BerkeleyDB"; }
+ const char *index_type(uint key_number) { return "BTREE"; }
const char **bas_ext() const;
ulong option_flag() const { return int_option_flag; }
uint max_record_length() const { return HA_MAX_REC_LENGTH; }
@@ -122,6 +123,7 @@ class ha_berkeley: public handler
uint key_len, 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);
+ int index_read_last(byte * buf, const byte * key, uint key_len);
int index_next(byte * buf);
int index_next_same(byte * buf, const byte *key, uint keylen);
int index_prev(byte * buf);
diff --git a/sql/ha_gemini.cc b/sql/ha_gemini.cc
deleted file mode 100644
index e8130c55fc7..00000000000
--- a/sql/ha_gemini.cc
+++ /dev/null
@@ -1,3630 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & NuSphere Corporation
-
- This program is free software; 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 based on ha_berkeley.cc */
-
-#ifdef __GNUC__
-#pragma implementation // gcc: Class implementation
-#endif
-
-#include "mysql_priv.h"
-#ifdef HAVE_GEMINI_DB
-#include "ha_gemini.h"
-#include "dbconfig.h"
-#include "dsmpub.h"
-#include "recpub.h"
-#include "vststat.h"
-
-#include <m_ctype.h>
-#include <myisampack.h>
-#include <m_string.h>
-#include <assert.h>
-#include <hash.h>
-#include <stdarg.h>
-#include "geminikey.h"
-
-#define gemini_msg MSGD_CALLBACK
-
-pthread_mutex_t gem_mutex;
-
-static HASH gem_open_tables;
-static GEM_SHARE *get_share(const char *table_name, TABLE *table);
-static int free_share(GEM_SHARE *share, bool mutex_is_locked);
-static byte* gem_get_key(GEM_SHARE *share,uint *length,
- my_bool not_used __attribute__((unused)));
-static void gemini_lock_table_overflow_error(dsmContext_t *pcontext);
-
-const char *ha_gemini_ext=".gmd";
-const char *ha_gemini_idx_ext=".gmi";
-
-bool gemini_skip=0;
-long gemini_options = 0;
-long gemini_buffer_cache;
-long gemini_io_threads;
-long gemini_log_cluster_size;
-long gemini_locktablesize;
-long gemini_lock_wait_timeout;
-long gemini_spin_retries;
-long gemini_connection_limit;
-char *gemini_basedir;
-
-const char gemini_dbname[] = "gemini";
-dsmContext_t *pfirstContext = NULL;
-
-ulong gemini_recovery_options = GEMINI_RECOVERY_FULL;
-/* bits in gemini_recovery_options */
-const char *gemini_recovery_names[] =
-{ "FULL", "NONE", "FORCE" };
-TYPELIB gemini_recovery_typelib= {array_elements(gemini_recovery_names),"",
- gemini_recovery_names};
-
-const int start_of_name = 2; /* Name passed as ./<db>/<table-name>
- and we're not interested in the ./ */
-static const int keyBufSize = MAXKEYSZ + FULLKEYHDRSZ + MAX_REF_PARTS + 16;
-
-static int gemini_tx_begin(THD *thd);
-static void print_msg(THD *thd, const char *table_name, const char *op_name,
- const char *msg_type, const char *fmt, ...);
-
-static int gemini_helper_threads(dsmContext_t *pContext);
-pthread_handler_decl(gemini_watchdog,arg );
-pthread_handler_decl(gemini_rl_writer,arg );
-pthread_handler_decl(gemini_apw,arg);
-
-/* General functions */
-
-bool gemini_init(void)
-{
- dsmStatus_t rc = 0;
- char pmsgsfile[MAXPATHN];
-
- DBUG_ENTER("gemini_init");
-
- gemini_basedir=mysql_home;
- /* If datadir isn't set, bail out */
- if (*mysql_real_data_home == '\0')
- {
- goto badret;
- }
-
- /* dsmContextCreate and dsmContextSetString(DSM_TAGDB_DBNAME) must
- ** be the first DSM calls we make so that we can log any errors which
- ** occur in subsequent DSM calls. DO NOT INSERT ANY DSM CALLS IN
- ** BETWEEN THIS COMMENT AND THE COMMENT THAT SAYS "END OF CODE..."
- */
- /* Gotta connect to the database regardless of the operation */
- rc = dsmContextCreate(&pfirstContext);
- if( rc != 0 )
- {
- gemini_msg(pfirstContext, "dsmContextCreate failed %l",rc);
- goto badret;
- }
- /* This call will also open the log file */
- rc = dsmContextSetString(pfirstContext, DSM_TAGDB_DBNAME,
- strlen(gemini_dbname), (TEXT *)gemini_dbname);
- if( rc != 0 )
- {
- gemini_msg(pfirstContext, "Dbname tag failed %l", rc);
- goto badret;
- }
- /* END OF CODE NOT TO MESS WITH */
-
- fn_format(pmsgsfile, GEM_MSGS_FILE, language, ".db", 2 | 4);
- rc = dsmContextSetString(pfirstContext, DSM_TAGDB_MSGS_FILE,
- strlen(pmsgsfile), (TEXT *)pmsgsfile);
- if( rc != 0 )
- {
- gemini_msg(pfirstContext, "MSGS_DIR tag failed %l", rc);
- goto badret;
- }
-
- strxmov(pmsgsfile, gemini_basedir, GEM_SYM_FILE, NullS);
- rc = dsmContextSetString(pfirstContext, DSM_TAGDB_SYMFILE,
- strlen(pmsgsfile), (TEXT *)pmsgsfile);
- if( rc != 0 )
- {
- gemini_msg(pfirstContext, "SYMFILE tag failed %l", rc);
- goto badret;
- }
-
- rc = dsmContextSetLong(pfirstContext,DSM_TAGDB_ACCESS_TYPE,DSM_ACCESS_STARTUP);
- if ( rc != 0 )
- {
- gemini_msg(pfirstContext, "ACCESS TAG set failed %l",rc);
- goto badret;
- }
- rc = dsmContextSetLong(pfirstContext,DSM_TAGDB_ACCESS_ENV, DSM_SQL_ENGINE);
- if( rc != 0 )
- {
- gemini_msg(pfirstContext, "ACCESS_ENV set failed %l",rc);
- goto badret;
- }
-
- rc = dsmContextSetString(pfirstContext, DSM_TAGDB_DATADIR,
- strlen(mysql_real_data_home),
- (TEXT *)mysql_real_data_home);
- if( rc != 0 )
- {
- gemini_msg(pfirstContext, "Datadir tag failed %l", rc);
- goto badret;
- }
-
- rc = dsmContextSetLong(pfirstContext, DSM_TAGDB_MAX_USERS,
- gemini_connection_limit);
- if(rc != 0)
- {
- gemini_msg(pfirstContext, "MAX_USERS tag set failed %l",rc);
- goto badret;
- }
-
- rc = dsmContextSetLong(pfirstContext, DSM_TAGDB_DEFAULT_LOCK_TIMEOUT,
- gemini_lock_wait_timeout);
- if(rc != 0)
- {
- gemini_msg(pfirstContext, "MAX_LOCK_ENTRIES tag set failed %l",rc);
- goto badret;
- }
-
- rc = dsmContextSetLong(pfirstContext, DSM_TAGDB_MAX_LOCK_ENTRIES,
- gemini_locktablesize);
- if(rc != 0)
- {
- gemini_msg(pfirstContext, "MAX_LOCK_ENTRIES tag set failed %l",rc);
- goto badret;
- }
-
- rc = dsmContextSetLong(pfirstContext, DSM_TAGDB_SPIN_AMOUNT,
- gemini_spin_retries);
- if(rc != 0)
- {
- gemini_msg(pfirstContext, "SPIN_AMOUNT tag set failed %l",rc);
- goto badret;
- }
-
- /* blocksize is hardcoded to 8K. Buffer cache is in bytes
- need to convert this to 8K blocks */
- gemini_buffer_cache = gemini_buffer_cache / 8192;
- rc = dsmContextSetLong(pfirstContext, DSM_TAGDB_DB_BUFFERS,
- gemini_buffer_cache);
- if(rc != 0)
- {
- gemini_msg(pfirstContext, "DB_BUFFERS tag set failed %l",rc);
- goto badret;
- }
-
- rc = dsmContextSetLong(pfirstContext, DSM_TAGDB_FLUSH_AT_COMMIT,
- ((gemini_options & GEMOPT_FLUSH_LOG) ? 0 : 1));
- if(rc != 0)
- {
- gemini_msg(pfirstContext, "FLush_Log_At_Commit tag set failed %l",rc);
- goto badret;
- }
- rc = dsmContextSetLong(pfirstContext, DSM_TAGDB_DIRECT_IO,
- ((gemini_options & GEMOPT_UNBUFFERED_IO) ? 1 : 0));
- if(rc != 0)
- {
- gemini_msg(pfirstContext, "DIRECT_IO tag set failed %l",rc);
- goto badret;
- }
-
- rc = dsmContextSetLong(pfirstContext, DSM_TAGDB_CRASH_PROTECTION,
- ((gemini_recovery_options & GEMINI_RECOVERY_FULL) ? 1 : 0));
- if(rc != 0)
- {
- gemini_msg(pfirstContext, "CRASH_PROTECTION tag set failed %l",rc);
- goto badret;
- }
-
- if (gemini_recovery_options & GEMINI_RECOVERY_FORCE)
- {
- rc = dsmContextSetLong(pfirstContext, DSM_TAGDB_FORCE_ACCESS, 1);
- if(rc != 0)
- {
- printf("CRASH_PROTECTION tag set failed %ld",rc);
- goto badret;
- }
- }
-
- /* cluster size will come in bytes, need to convert it to
- 16 K units. */
- gemini_log_cluster_size = (gemini_log_cluster_size + 16383) / 16384;
- rc = dsmContextSetLong(pfirstContext, DSM_TAGDB_BI_CLUSTER_SIZE,
- gemini_log_cluster_size);
-
- if(rc != 0)
- {
- gemini_msg(pfirstContext, "CRASH_PROTECTION tag set failed %l",rc);
- goto badret;
- }
-
- rc = dsmUserConnect(pfirstContext,(TEXT *)"Multi-user",
- DSM_DB_OPENDB | DSM_DB_OPENFILE);
- if( rc != 0 )
- {
- /* Message is output in dbenv() */
- goto badret;
- }
- /* Set access to shared for subsequent user connects */
- rc = dsmContextSetLong(pfirstContext,DSM_TAGDB_ACCESS_TYPE,DSM_ACCESS_SHARED);
-
- rc = gemini_helper_threads(pfirstContext);
-
-
- (void) hash_init(&gem_open_tables,32,0,0,
- (hash_get_key) gem_get_key,0,0);
- pthread_mutex_init(&gem_mutex,NULL);
-
-
- DBUG_RETURN(0);
-
-badret:
- gemini_skip = 1;
- DBUG_RETURN(0);
-}
-
-static int gemini_helper_threads(dsmContext_t *pContext)
-{
- int rc = 0;
- int i;
- pthread_attr_t thr_attr;
-
- pthread_t hThread;
- DBUG_ENTER("gemini_helper_threads");
-
- (void) pthread_attr_init(&thr_attr);
-#if !defined(HAVE_DEC_3_2_THREADS)
- pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_SYSTEM);
- (void) pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
- pthread_attr_setstacksize(&thr_attr,32768);
-#endif
- rc = pthread_create (&hThread, &thr_attr, gemini_watchdog, (void *)pContext);
- if (rc)
- {
- gemini_msg(pContext, "Can't Create gemini watchdog thread");
- goto done;
- }
- if(!gemini_io_threads)
- goto done;
-
- rc = pthread_create(&hThread, &thr_attr, gemini_rl_writer, (void *)pContext);
- if(rc)
- {
- gemini_msg(pContext, "Can't create Gemini recovery log writer thread");
- goto done;
- }
-
- for(i = gemini_io_threads - 1;i;i--)
- {
- rc = pthread_create(&hThread, &thr_attr, gemini_apw, (void *)pContext);
- if(rc)
- {
- gemini_msg(pContext, "Can't create Gemini database page writer thread");
- goto done;
- }
- }
-done:
-
- DBUG_RETURN(rc);
-}
-
-pthread_handler_decl(gemini_watchdog,arg )
-{
- int rc = 0;
- dsmContext_t *pcontext = (dsmContext_t *)arg;
- dsmContext_t *pmyContext = NULL;
-
-
- rc = dsmContextCopy(pcontext,&pmyContext, DSMCONTEXTDB);
- if( rc != 0 )
- {
- gemini_msg(pcontext, "dsmContextCopy failed for Gemini watchdog %d",rc);
-
- return 0;
- }
- rc = dsmUserConnect(pmyContext,NULL,0);
-
- if( rc != 0 )
- {
- gemini_msg(pcontext, "dsmUserConnect failed for Gemini watchdog %d",rc);
-
- return 0;
- }
-
- my_thread_init();
- pthread_detach_this_thread();
-
- while(rc == 0)
- {
- rc = dsmDatabaseProcessEvents(pmyContext);
- if(!rc)
- rc = dsmWatchdog(pmyContext);
- sleep(1);
- }
- rc = dsmUserDisconnect(pmyContext,0);
- my_thread_end();
- return 0;
-}
-
-pthread_handler_decl(gemini_rl_writer,arg )
-{
- int rc = 0;
- dsmContext_t *pcontext = (dsmContext_t *)arg;
- dsmContext_t *pmyContext = NULL;
-
-
- rc = dsmContextCopy(pcontext,&pmyContext, DSMCONTEXTDB);
- if( rc != 0 )
- {
- gemini_msg(pcontext, "dsmContextCopy failed for Gemini recovery log writer %d",rc);
-
- return 0;
- }
- rc = dsmUserConnect(pmyContext,NULL,0);
-
- if( rc != 0 )
- {
- gemini_msg(pcontext, "dsmUserConnect failed for Gemini recovery log writer %d",rc);
-
- return 0;
- }
-
- my_thread_init();
- pthread_detach_this_thread();
-
- while(rc == 0)
- {
- rc = dsmRLwriter(pmyContext);
- }
- rc = dsmUserDisconnect(pmyContext,0);
- my_thread_end();
- return 0;
-}
-
-pthread_handler_decl(gemini_apw,arg )
-{
- int rc = 0;
- dsmContext_t *pcontext = (dsmContext_t *)arg;
- dsmContext_t *pmyContext = NULL;
-
- my_thread_init();
- pthread_detach_this_thread();
-
- rc = dsmContextCopy(pcontext,&pmyContext, DSMCONTEXTDB);
- if( rc != 0 )
- {
- gemini_msg(pcontext, "dsmContextCopy failed for Gemini page writer %d",rc);
- my_thread_end();
- return 0;
- }
- rc = dsmUserConnect(pmyContext,NULL,0);
-
- if( rc != 0 )
- {
- gemini_msg(pcontext, "dsmUserConnect failed for Gemini page writer %d",rc);
- my_thread_end();
- return 0;
- }
-
- while(rc == 0)
- {
- rc = dsmAPW(pmyContext);
- }
- rc = dsmUserDisconnect(pmyContext,0);
- my_thread_end();
- return 0;
-}
-
-int gemini_set_option_long(int optid, long optval)
-{
- dsmStatus_t rc = 0;
-
- switch (optid)
- {
- case GEM_OPTID_SPIN_RETRIES:
- /* If we don't have a context yet, skip the set and just save the
- ** value in gemini_spin_retries for a later gemini_init(). This
- ** may not ever happen, but we're covered if it does.
- */
- if (pfirstContext)
- {
- rc = dsmContextSetLong(pfirstContext, DSM_TAGDB_SPIN_AMOUNT,
- optval);
- }
- if (rc)
- {
- gemini_msg(pfirstContext, "SPIN_AMOUNT tag set failed %l",rc);
- }
- else
- {
- gemini_spin_retries = optval;
- }
- break;
- }
-
- return rc;
-}
-
-static int gemini_connect(THD *thd)
-{
- DBUG_ENTER("gemini_connect");
-
- dsmStatus_t rc;
-
- rc = dsmContextCopy(pfirstContext,(dsmContext_t **)&thd->gemini.context,
- DSMCONTEXTDB);
- if( rc != 0 )
- {
- gemini_msg(pfirstContext, "dsmContextCopy failed %l",rc);
-
- return(rc);
- }
- rc = dsmUserConnect((dsmContext_t *)thd->gemini.context,NULL,0);
-
- if( rc != 0 )
- {
- gemini_msg(pfirstContext, "dsmUserConnect failed %l",rc);
-
- return(rc);
- }
- rc = (dsmStatus_t)gemini_tx_begin(thd);
-
- DBUG_RETURN(rc);
-}
-
-void gemini_disconnect(THD *thd)
-{
- dsmStatus_t rc;
-
- if(thd->gemini.context)
- {
- rc = dsmUserDisconnect((dsmContext_t *)thd->gemini.context,0);
- }
- return;
-}
-
-bool gemini_end(void)
-{
- dsmStatus_t rc;
- THD *thd;
-
- DBUG_ENTER("gemini_end");
-
- hash_free(&gem_open_tables);
- pthread_mutex_destroy(&gem_mutex);
- if(pfirstContext)
- {
- rc = dsmShutdownSet(pfirstContext, DSM_SHUTDOWN_NORMAL);
- sleep(2);
- rc = dsmContextSetLong(pfirstContext,DSM_TAGDB_ACCESS_TYPE,DSM_ACCESS_STARTUP);
- rc = dsmShutdown(pfirstContext, DSMNICEBIT,DSMNICEBIT);
- }
- DBUG_RETURN(0);
-}
-
-bool gemini_flush_logs()
-{
- DBUG_ENTER("gemini_flush_logs");
-
- DBUG_RETURN(0);
-}
-
-static int gemini_tx_begin(THD *thd)
-{
- dsmStatus_t rc;
- DBUG_ENTER("gemini_tx_begin");
-
- thd->gemini.savepoint = 1;
-
- rc = dsmTransaction((dsmContext_t *)thd->gemini.context,
- &thd->gemini.savepoint,DSMTXN_START,0,NULL);
- if(!rc)
- thd->gemini.needSavepoint = 1;
-
- thd->gemini.tx_isolation = thd->tx_isolation;
-
- DBUG_PRINT("trans",("beginning transaction"));
- DBUG_RETURN(rc);
-}
-
-int gemini_commit(THD *thd)
-{
- dsmStatus_t rc;
- LONG txNumber = 0;
-
- DBUG_ENTER("gemini_commit");
-
- if(!thd->gemini.context)
- DBUG_RETURN(0);
-
- rc = dsmTransaction((dsmContext_t *)thd->gemini.context,
- 0,DSMTXN_COMMIT,0,NULL);
- if(!rc)
- rc = gemini_tx_begin(thd);
-
- thd->gemini.lock_count = 0;
-
- DBUG_PRINT("trans",("ending transaction"));
- DBUG_RETURN(rc);
-}
-
-int gemini_rollback(THD *thd)
-{
- dsmStatus_t rc;
- LONG txNumber;
-
- DBUG_ENTER("gemini_rollback");
- DBUG_PRINT("trans",("aborting transaction"));
-
- if(!thd->gemini.context)
- DBUG_RETURN(0);
-
- thd->gemini.savepoint = 0;
- rc = dsmTransaction((dsmContext_t *)thd->gemini.context,
- &thd->gemini.savepoint,DSMTXN_ABORT,0,NULL);
- if(!rc)
- rc = gemini_tx_begin(thd);
-
- thd->gemini.lock_count = 0;
-
- DBUG_RETURN(rc);
-}
-
-int gemini_rollback_to_savepoint(THD *thd)
-{
- dsmStatus_t rc = 0;
- DBUG_ENTER("gemini_rollback_to_savepoint");
- if(thd->gemini.savepoint > 1)
- {
- rc = dsmTransaction((dsmContext_t *)thd->gemini.context,
- &thd->gemini.savepoint,DSMTXN_UNSAVE,0,NULL);
- }
- DBUG_RETURN(rc);
-}
-
-int gemini_recovery_logging(THD *thd, bool on)
-{
- int error;
- int noLogging;
-
- if(!thd->gemini.context)
- return 0;
-
- if(on)
- noLogging = 0;
- else
- noLogging = 1;
-
- error = dsmContextSetLong((dsmContext_t *)thd->gemini.context,
- DSM_TAGCONTEXT_NO_LOGGING,noLogging);
- return error;
-}
-
-/* gemDataType - translates from mysql data type constant to gemini
- key services data type contstant */
-int gemDataType ( int mysqlType )
-{
- switch (mysqlType)
- {
- case FIELD_TYPE_LONG:
- case FIELD_TYPE_TINY:
- case FIELD_TYPE_SHORT:
- case FIELD_TYPE_TIMESTAMP:
- case FIELD_TYPE_LONGLONG:
- case FIELD_TYPE_INT24:
- case FIELD_TYPE_DATE:
- case FIELD_TYPE_TIME:
- case FIELD_TYPE_DATETIME:
- case FIELD_TYPE_YEAR:
- case FIELD_TYPE_NEWDATE:
- case FIELD_TYPE_ENUM:
- case FIELD_TYPE_SET:
- return GEM_INT;
- case FIELD_TYPE_DECIMAL:
- return GEM_DECIMAL;
- case FIELD_TYPE_FLOAT:
- return GEM_FLOAT;
- case FIELD_TYPE_DOUBLE:
- return GEM_DOUBLE;
- case FIELD_TYPE_TINY_BLOB:
- return GEM_TINYBLOB;
- case FIELD_TYPE_MEDIUM_BLOB:
- return GEM_MEDIUMBLOB;
- case FIELD_TYPE_LONG_BLOB:
- return GEM_LONGBLOB;
- case FIELD_TYPE_BLOB:
- return GEM_BLOB;
- case FIELD_TYPE_VAR_STRING:
- case FIELD_TYPE_STRING:
- return GEM_CHAR;
- }
- return -1;
-}
-
-/*****************************************************************************
-** Gemini tables
-*****************************************************************************/
-
-const char **ha_gemini::bas_ext() const
-{ static const char *ext[]= { ha_gemini_ext, ha_gemini_idx_ext, NullS };
- return ext;
-}
-
-
-int ha_gemini::open(const char *name, int mode, uint test_if_locked)
-{
- dsmObject_t tableId = 0;
- THD *thd;
- char name_buff[FN_REFLEN];
- char tabname_buff[FN_REFLEN];
- char dbname_buff[FN_REFLEN];
- unsigned i,nameLen;
- LONG txNumber;
- dsmStatus_t rc;
-
- DBUG_ENTER("ha_gemini::open");
-
- thd = current_thd;
- /* Init shared structure */
- if (!(share=get_share(name,table)))
- {
- DBUG_RETURN(1); /* purecov: inspected */
- }
- thr_lock_data_init(&share->lock,&lock,(void*) 0);
-
- ref_length = sizeof(dsmRecid_t);
-
- if(thd->gemini.context == NULL)
- {
- /* Need to get this thread a connection into the database */
- rc = gemini_connect(thd);
- if(rc)
- return rc;
- }
- if (!(rec_buff=(byte*)my_malloc(table->rec_buff_length,
- MYF(MY_WME))))
- {
- DBUG_RETURN(1);
- }
-
- /* separate out the name of the table and the database (a VST must be
- ** created in the mysql database)
- */
- rc = gemini_parse_table_name(name, dbname_buff, tabname_buff);
- if (rc == 0)
- {
- if (strcmp(dbname_buff, "mysql") == 0)
- {
- tableId = gemini_is_vst(tabname_buff);
- }
- }
- sprintf(name_buff, "%s.%s", dbname_buff, tabname_buff);
-
- /* if it's not a VST, get the table number the regular way */
- if (!tableId)
- {
- rc = dsmObjectNameToNum((dsmContext_t *)thd->gemini.context,
- (dsmText_t *)name_buff,
- &tableId);
- if (rc)
- {
- gemini_msg((dsmContext_t *)thd->gemini.context,
- "Unable to find table number for %s", name_buff);
- DBUG_RETURN(rc);
- }
- }
- tableNumber = tableId;
-
- if(!rc)
- rc = index_open(name_buff);
-
- fixed_length_row=!(table->db_create_options & HA_OPTION_PACK_RECORD);
- key_read = 0;
- using_ignore = 0;
-
- /* Get the gemini table status -- we want to know if the table
- crashed while being in the midst of a repair operation */
- rc = dsmTableStatus((dsmContext_t *)thd->gemini.context,
- tableNumber,&tableStatus);
- if(tableStatus == DSM_OBJECT_IN_REPAIR)
- tableStatus = HA_ERR_CRASHED;
-
- pthread_mutex_lock(&share->mutex);
- share->use_count++;
- pthread_mutex_unlock(&share->mutex);
-
- if (table->blob_fields)
- {
- /* Allocate room for the blob ids from an unpacked row. Note that
- ** we may not actually need all of this space because tiny blobs
- ** are stored in the packed row, not in a separate storage object
- ** like larger blobs. But we allocate an entry for all blobs to
- ** keep the code simpler.
- */
- pBlobDescs = (gemBlobDesc_t *)my_malloc(
- table->blob_fields * sizeof(gemBlobDesc_t),
- MYF(MY_WME | MY_ZEROFILL));
- }
- else
- {
- pBlobDescs = 0;
- }
-
- get_index_stats(thd);
- info(HA_STATUS_CONST);
-
- DBUG_RETURN (rc);
-}
-
-/* Look up and store the object numbers for the indexes on this table */
-int ha_gemini::index_open(char *tableName)
-{
- dsmStatus_t rc = 0;
- int nameLen;
-
- DBUG_ENTER("ha_gemini::index_open");
- if(table->keys)
- {
- THD *thd = current_thd;
- dsmObject_t objectNumber;
- if (!(pindexNumbers=(dsmIndex_t *)my_malloc(table->keys*sizeof(dsmIndex_t),
- MYF(MY_WME))))
- {
- DBUG_RETURN(1);
- }
- nameLen = strlen(tableName);
- tableName[nameLen] = '.';
- nameLen++;
-
- for( uint i = 0; i < table->keys && !rc; i++)
- {
- strcpy(&tableName[nameLen],table->key_info[i].name);
- rc = dsmObjectNameToNum((dsmContext_t *)thd->gemini.context,
- (dsmText_t *)tableName,
- &objectNumber);
- if (rc)
- {
- gemini_msg((dsmContext_t *)thd->gemini.context,
- "Unable to file Index number for %s", tableName);
- DBUG_RETURN(rc);
- }
- pindexNumbers[i] = objectNumber;
- }
- }
- else
- pindexNumbers = 0;
-
- DBUG_RETURN(rc);
-}
-
-int ha_gemini::close(void)
-{
- DBUG_ENTER("ha_gemini::close");
- my_free((char*)rec_buff,MYF(MY_ALLOW_ZERO_PTR));
- rec_buff = 0;
- my_free((char *)pindexNumbers,MYF(MY_ALLOW_ZERO_PTR));
- pindexNumbers = 0;
-
- if (pBlobDescs)
- {
- for (uint i = 0; i < table->blob_fields; i++)
- {
- my_free((char*)pBlobDescs[i].pBlob, MYF(MY_ALLOW_ZERO_PTR));
- }
- my_free((char *)pBlobDescs, MYF(0));
- pBlobDescs = 0;
- }
-
- DBUG_RETURN(free_share(share, 0));
-}
-
-
-int ha_gemini::write_row(byte * record)
-{
- int error = 0;
- dsmRecord_t dsmRecord;
- THD *thd;
-
- DBUG_ENTER("write_row");
-
- if(tableStatus == HA_ERR_CRASHED)
- DBUG_RETURN(tableStatus);
-
- thd = current_thd;
-
- statistic_increment(ha_write_count,&LOCK_status);
- if (table->time_stamp)
- update_timestamp(record+table->time_stamp-1);
-
- if(thd->gemini.needSavepoint || using_ignore)
- {
- thd->gemini.savepoint++;
- error = dsmTransaction((dsmContext_t *)thd->gemini.context,
- &thd->gemini.savepoint,
- DSMTXN_SAVE, 0, 0);
- if (error)
- DBUG_RETURN(error);
- thd->gemini.needSavepoint = 0;
- }
-
- if (table->next_number_field && record == table->record[0])
- {
- if(thd->next_insert_id)
- {
- ULONG64 nr;
- /* A set insert-id statement so set the auto-increment value if this
- value is higher than it's current value */
- error = dsmTableAutoIncrement((dsmContext_t *)thd->gemini.context,
- tableNumber, (ULONG64 *)&nr,1);
- if(thd->next_insert_id > nr)
- {
- error = dsmTableAutoIncrementSet((dsmContext_t *)thd->gemini.context,
- tableNumber,
- (ULONG64)thd->next_insert_id);
- }
- }
-
- update_auto_increment();
- }
-
- dsmRecord.table = tableNumber;
- dsmRecord.maxLength = table->rec_buff_length;
-
- if ((error=pack_row((byte **)&dsmRecord.pbuffer, (int *)&dsmRecord.recLength,
- record, FALSE)))
- {
- DBUG_RETURN(error);
- }
-
- error = dsmRecordCreate((dsmContext_t *)thd->gemini.context,
- &dsmRecord,0);
-
- if(!error)
- {
- error = handleIndexEntries(record, dsmRecord.recid,KEY_CREATE);
- if(error == HA_ERR_FOUND_DUPP_KEY && using_ignore)
- {
- dsmStatus_t rc;
- rc = dsmTransaction((dsmContext_t *)thd->gemini.context,
- &thd->gemini.savepoint,DSMTXN_UNSAVE,0,NULL);
- thd->gemini.needSavepoint = 1;
- }
- }
- if(error == DSM_S_RQSTREJ)
- error = HA_ERR_LOCK_WAIT_TIMEOUT;
-
- DBUG_RETURN(error);
-}
-
-longlong ha_gemini::get_auto_increment()
-{
- longlong nr;
- int error;
- int update;
- THD *thd=current_thd;
-
- if(thd->lex.sql_command == SQLCOM_SHOW_TABLES)
- update = 0;
- else
- update = 1;
-
- error = dsmTableAutoIncrement((dsmContext_t *)thd->gemini.context,
- tableNumber, (ULONG64 *)&nr,
- update);
- return nr;
-}
-
-/* Put or delete index entries for a row */
-int ha_gemini::handleIndexEntries(const byte * record, dsmRecid_t recid,
- enum_key_string_options option)
-{
- dsmStatus_t rc = 0;
-
- DBUG_ENTER("handleIndexEntries");
-
- for (uint i = 0; i < table->keys && rc == 0; i++)
- {
- rc = handleIndexEntry(record, recid,option, i);
- }
- DBUG_RETURN(rc);
-}
-
-int ha_gemini::handleIndexEntry(const byte * record, dsmRecid_t recid,
- enum_key_string_options option,uint keynr)
-{
- dsmStatus_t rc = 0;
- KEY *key_info;
- int keyStringLen;
- bool thereIsAnull;
- THD *thd;
-
- AUTOKEY(theKey,keyBufSize);
-
- DBUG_ENTER("handleIndexEntry");
-
- thd = current_thd;
- key_info=table->key_info+keynr;
- thereIsAnull = FALSE;
- rc = createKeyString(record, key_info, theKey.akey.keystr,
- sizeof(theKey.apad),&keyStringLen,
- (short)pindexNumbers[keynr],
- &thereIsAnull);
- if(!rc)
- {
- theKey.akey.index = pindexNumbers[keynr];
- theKey.akey.keycomps = (COUNT)key_info->key_parts;
-
- /* We have to subtract three here since cxKeyPrepare
- expects that the three lead bytes of the header are
- not counted in this length -- But cxKeyPrepare also
- expects that these three bytes are present in the keystr */
- theKey.akey.keyLen = (COUNT)keyStringLen - FULLKEYHDRSZ;
- theKey.akey.unknown_comp = (dsmBoolean_t)thereIsAnull;
- theKey.akey.word_index = 0;
- theKey.akey.descending_key =0;
- if(option == KEY_CREATE)
- {
- rc = dsmKeyCreate((dsmContext_t *)thd->gemini.context, &theKey.akey,
- (dsmTable_t)tableNumber, recid, NULL);
- if(rc == DSM_S_IXDUPKEY)
- {
- last_dup_key=keynr;
- rc = HA_ERR_FOUND_DUPP_KEY;
- }
- }
- else if(option == KEY_DELETE)
- {
- rc = dsmKeyDelete((dsmContext_t *)thd->gemini.context, &theKey.akey,
- (dsmTable_t)tableNumber, recid, 0, NULL);
- }
- else
- {
- /* KEY_CHECK */
- dsmCursid_t aCursorId;
- int error;
-
- rc = dsmCursorCreate((dsmContext_t *)thd->gemini.context,
- (dsmTable_t)tableNumber,
- (dsmIndex_t)pindexNumbers[keynr],
- &aCursorId,NULL);
-
- rc = dsmCursorFind((dsmContext_t *)thd->gemini.context,
- &aCursorId,&theKey.akey,NULL,DSMDBKEY,
- DSMFINDFIRST,DSM_LK_SHARE,0,
- &lastRowid,0);
- error = dsmCursorDelete((dsmContext_t *)thd->gemini.context,
- &aCursorId, 0);
-
- }
- }
- DBUG_RETURN(rc);
-}
-
-int ha_gemini::createKeyString(const byte * record, KEY *pkeyinfo,
- unsigned char *pkeyBuf, int bufSize,
- int *pkeyStringLen,
- short geminiIndexNumber,
- bool *thereIsAnull)
-{
- dsmStatus_t rc = 0;
- int componentLen;
- int fieldType;
- int isNull;
- uint key_part_length;
-
- KEY_PART_INFO *key_part;
-
- DBUG_ENTER("createKeyString");
-
- rc = gemKeyInit(pkeyBuf,pkeyStringLen, geminiIndexNumber);
-
- for(uint i = 0; i < pkeyinfo->key_parts && rc == 0; i++)
- {
- unsigned char *pos;
-
- key_part = pkeyinfo->key_part + i;
- key_part_length = key_part->length;
- fieldType = gemDataType(key_part->field->type());
- switch (fieldType)
- {
- case GEM_CHAR:
- {
- /* Save the current ptr to the field in case we're building a key
- to remove an old key value when an indexed character column
- gets updated. */
- char *ptr = key_part->field->ptr;
- key_part->field->ptr = (char *)record + key_part->offset;
- key_part->field->sort_string((char*)rec_buff, key_part->length);
- key_part->field->ptr = ptr;
- pos = (unsigned char *)rec_buff;
- }
- break;
-
- case GEM_TINYBLOB:
- case GEM_BLOB:
- case GEM_MEDIUMBLOB:
- case GEM_LONGBLOB:
- ((Field_blob*)key_part->field)->get_ptr((char**)&pos);
- key_part_length = ((Field_blob*)key_part->field)->get_length(
- (char*)record + key_part->offset);
- break;
-
- default:
- pos = (unsigned char *)record + key_part->offset;
- break;
- }
-
- isNull = record[key_part->null_offset] & key_part->null_bit;
- if(isNull)
- *thereIsAnull = TRUE;
-
- rc = gemFieldToIdxComponent(pos,
- (unsigned long) key_part_length,
- fieldType,
- isNull ,
- key_part->field->flags & UNSIGNED_FLAG,
- pkeyBuf + *pkeyStringLen,
- bufSize,
- &componentLen);
- *pkeyStringLen += componentLen;
- }
- DBUG_RETURN(rc);
-}
-
-
-int ha_gemini::update_row(const byte * old_record, byte * new_record)
-{
- int error = 0;
- dsmRecord_t dsmRecord;
- unsigned long savepoint;
- THD *thd = current_thd;
- DBUG_ENTER("update_row");
-
- statistic_increment(ha_update_count,&LOCK_status);
- if (table->time_stamp)
- update_timestamp(new_record+table->time_stamp-1);
-
- if(thd->gemini.needSavepoint || using_ignore)
- {
- thd->gemini.savepoint++;
- error = dsmTransaction((dsmContext_t *)thd->gemini.context,
- &thd->gemini.savepoint,
- DSMTXN_SAVE, 0, 0);
- if (error)
- DBUG_RETURN(error);
- thd->gemini.needSavepoint = 0;
- }
- for (uint keynr=0 ; keynr < table->keys ; keynr++)
- {
- if(key_cmp(keynr,old_record, new_record,FALSE))
- {
- error = handleIndexEntry(old_record,lastRowid,KEY_DELETE,keynr);
- if(error)
- DBUG_RETURN(error);
- error = handleIndexEntry(new_record, lastRowid, KEY_CREATE, keynr);
- if(error)
- {
- if (using_ignore && error == HA_ERR_FOUND_DUPP_KEY)
- {
- dsmStatus_t rc;
- rc = dsmTransaction((dsmContext_t *)thd->gemini.context,
- &thd->gemini.savepoint,DSMTXN_UNSAVE,0,NULL);
- thd->gemini.needSavepoint = 1;
- }
- DBUG_RETURN(error);
- }
- }
- }
-
- dsmRecord.table = tableNumber;
- dsmRecord.recid = lastRowid;
- dsmRecord.maxLength = table->rec_buff_length;
-
- if ((error=pack_row((byte **)&dsmRecord.pbuffer, (int *)&dsmRecord.recLength,
- new_record, TRUE)))
- {
- DBUG_RETURN(error);
- }
- error = dsmRecordUpdate((dsmContext_t *)thd->gemini.context,
- &dsmRecord, 0, NULL);
-
- DBUG_RETURN(error);
-}
-
-
-int ha_gemini::delete_row(const byte * record)
-{
- int error = 0;
- dsmRecord_t dsmRecord;
- THD *thd = current_thd;
- dsmContext_t *pcontext = (dsmContext_t *)thd->gemini.context;
- DBUG_ENTER("delete_row");
-
- statistic_increment(ha_delete_count,&LOCK_status);
-
- if(thd->gemini.needSavepoint)
- {
- thd->gemini.savepoint++;
- error = dsmTransaction(pcontext, &thd->gemini.savepoint, DSMTXN_SAVE, 0, 0);
- if (error)
- DBUG_RETURN(error);
- thd->gemini.needSavepoint = 0;
- }
-
- dsmRecord.table = tableNumber;
- dsmRecord.recid = lastRowid;
-
- error = handleIndexEntries(record, dsmRecord.recid,KEY_DELETE);
- if(!error)
- {
- error = dsmRecordDelete(pcontext, &dsmRecord, 0, NULL);
- }
-
- /* Delete any blobs associated with this row */
- if (table->blob_fields)
- {
- dsmBlob_t gemBlob;
-
- gemBlob.areaType = DSMOBJECT_BLOB;
- gemBlob.blobObjNo = tableNumber;
- for (uint i = 0; i < table->blob_fields; i++)
- {
- if (pBlobDescs[i].blobId)
- {
- gemBlob.blobId = pBlobDescs[i].blobId;
- my_free((char *)pBlobDescs[i].pBlob, MYF(MY_ALLOW_ZERO_PTR));
- dsmBlobStart(pcontext, &gemBlob);
- dsmBlobDelete(pcontext, &gemBlob, NULL);
- /* according to DSM doc, no need to call dsmBlobEnd() */
- }
- }
- }
-
- DBUG_RETURN(error);
-}
-
-int ha_gemini::index_init(uint keynr)
-{
- int error = 0;
- THD *thd;
- DBUG_ENTER("index_init");
- thd = current_thd;
-
- lastRowid = 0;
- active_index=keynr;
- error = dsmCursorCreate((dsmContext_t *)thd->gemini.context,
- (dsmTable_t)tableNumber,
- (dsmIndex_t)pindexNumbers[keynr],
- &cursorId,NULL);
- pbracketBase = (dsmKey_t *)my_malloc(sizeof(dsmKey_t) + keyBufSize,
- MYF(MY_WME));
- if(!pbracketBase)
- DBUG_RETURN(1);
- pbracketLimit = (dsmKey_t *)my_malloc(sizeof(dsmKey_t) + keyBufSize,MYF(MY_WME));
- if(!pbracketLimit)
- {
- my_free((char *)pbracketLimit,MYF(0));
- DBUG_RETURN(1);
- }
- pbracketBase->index = 0;
- pbracketLimit->index = (dsmIndex_t)pindexNumbers[keynr];
- pbracketBase->descending_key = pbracketLimit->descending_key = 0;
- pbracketBase->ksubstr = pbracketLimit->ksubstr = 0;
- pbracketLimit->keycomps = pbracketBase->keycomps = 1;
-
- pfoundKey = (dsmKey_t *)my_malloc(sizeof(dsmKey_t) + keyBufSize,MYF(MY_WME));
- if(!pfoundKey)
- {
- my_free((char *)pbracketLimit,MYF(0));
- my_free((char *)pbracketBase,MYF(0));
- DBUG_RETURN(1);
- }
-
- DBUG_RETURN(error);
-}
-
-int ha_gemini::index_end()
-{
- int error = 0;
- THD *thd;
- DBUG_ENTER("index_end");
- thd = current_thd;
- error = dsmCursorDelete((dsmContext_t *)thd->gemini.context,
- &cursorId, 0);
- if(pbracketLimit)
- my_free((char *)pbracketLimit,MYF(0));
- if(pbracketBase)
- my_free((char *)pbracketBase,MYF(0));
- if(pfoundKey)
- my_free((char *)pfoundKey,MYF(0));
-
- pbracketLimit = 0;
- pbracketBase = 0;
- pfoundKey = 0;
- DBUG_RETURN(error);
-}
-
-/* This is only used to read whole keys */
-
-int ha_gemini::index_read_idx(byte * buf, uint keynr, const byte * key,
- uint key_len, enum ha_rkey_function find_flag)
-{
- int error = 0;
- DBUG_ENTER("index_read_idx");
- statistic_increment(ha_read_key_count,&LOCK_status);
-
- error = index_init(keynr);
- if (!error)
- error = index_read(buf,key,key_len,find_flag);
-
- if(error == HA_ERR_END_OF_FILE)
- error = HA_ERR_KEY_NOT_FOUND;
-
- table->status = error ? STATUS_NOT_FOUND : 0;
- DBUG_RETURN(error);
-}
-
-int ha_gemini::pack_key( uint keynr, dsmKey_t *pkey,
- const byte *key_ptr, uint key_length)
-{
- KEY *key_info=table->key_info+keynr;
- KEY_PART_INFO *key_part=key_info->key_part;
- KEY_PART_INFO *end=key_part+key_info->key_parts;
- int rc;
- int componentLen;
- DBUG_ENTER("pack_key");
-
- rc = gemKeyInit(pkey->keystr,&componentLen,
- (short)pindexNumbers[active_index]);
- pkey->keyLen = componentLen;
-
- for (; key_part != end && (int) key_length > 0 && !rc; key_part++)
- {
- uint offset=0;
- unsigned char *pos;
- uint key_part_length = key_part->length;
-
- int fieldType;
- if (key_part->null_bit)
- {
- offset=1;
- if (*key_ptr != 0) // Store 0 if NULL
- {
- key_length-= key_part->store_length;
- key_ptr+= key_part->store_length;
- rc = gemFieldToIdxComponent(
- (unsigned char *)key_ptr + offset,
- (unsigned long) key_part_length,
- 0,
- 1 , /* Tells it to build a null component */
- key_part->field->flags & UNSIGNED_FLAG,
- pkey->keystr + pkey->keyLen,
- keyBufSize,
- &componentLen);
- pkey->keyLen += componentLen;
- continue;
- }
- }
- fieldType = gemDataType(key_part->field->type());
- switch (fieldType)
- {
- case GEM_CHAR:
- key_part->field->store((char*)key_ptr + offset, key_part->length);
- key_part->field->sort_string((char*)rec_buff, key_part->length);
- pos = (unsigned char *)rec_buff;
- break;
-
- case GEM_TINYBLOB:
- case GEM_BLOB:
- case GEM_MEDIUMBLOB:
- case GEM_LONGBLOB:
- ((Field_blob*)key_part->field)->get_ptr((char**)&pos);
- key_part_length = ((Field_blob*)key_part->field)->get_length(
- (char*)key_ptr + offset);
- break;
-
- default:
- pos = (unsigned char *)key_ptr + offset;
- break;
- }
-
- rc = gemFieldToIdxComponent(
- pos,
- (unsigned long) key_part_length,
- fieldType,
- 0 ,
- key_part->field->flags & UNSIGNED_FLAG,
- pkey->keystr + pkey->keyLen,
- keyBufSize,
- &componentLen);
-
- key_ptr+=key_part->store_length;
- key_length-=key_part->store_length;
- pkey->keyLen += componentLen;
- }
- DBUG_RETURN(rc);
-}
-
-void ha_gemini::unpack_key(char *record, dsmKey_t *key, uint index)
-{
- KEY *key_info=table->key_info+index;
- KEY_PART_INFO *key_part= key_info->key_part,
- *end=key_part+key_info->key_parts;
- int fieldIsNull, fieldType;
- int rc = 0;
-
- char unsigned *pos= &key->keystr[FULLKEYHDRSZ+4/* 4 for the index number*/];
-
- for ( ; key_part != end; key_part++)
- {
- fieldType = gemDataType(key_part->field->type());
- if(fieldType == GEM_CHAR)
- {
- /* Can't get data from character indexes since the sort weights
- are in the index and not the characters. */
- key_read = 0;
- }
- rc = gemIdxComponentToField(pos, fieldType,
- (unsigned char *)record + key_part->field->offset(),
- //key_part->field->field_length,
- key_part->length,
- key_part->field->decimals(),
- &fieldIsNull);
- if(fieldIsNull)
- {
- record[key_part->null_offset] |= key_part->null_bit;
- }
- else if (key_part->null_bit)
- {
- record[key_part->null_offset]&= ~key_part->null_bit;
- }
- while(*pos++); /* Advance to next field in key by finding */
- /* a null byte */
- }
-}
-
-int ha_gemini::index_read(byte * buf, const byte * key,
- uint key_len, enum ha_rkey_function find_flag)
-{
- int error = 0;
- THD *thd;
- int componentLen;
-
- DBUG_ENTER("index_read");
- statistic_increment(ha_read_key_count,&LOCK_status);
-
-
- pbracketBase->index = (short)pindexNumbers[active_index];
- pbracketBase->keycomps = 1;
-
-
- /* Its a greater than operation so create a base bracket
- from the input key data. */
- error = pack_key(active_index, pbracketBase, key, key_len);
- if(error)
- goto errorReturn;
-
- if(find_flag == HA_READ_AFTER_KEY)
- {
- /* A greater than operation */
- error = gemKeyAddLow(pbracketBase->keystr + pbracketBase->keyLen,
- &componentLen);
- pbracketBase->keyLen += componentLen;
- }
- if(find_flag == HA_READ_KEY_EXACT)
- {
- /* Need to set up a high bracket for an equality operator
- Which is a copy of the base bracket plus a hi lim term */
- bmove(pbracketLimit,pbracketBase,(size_t)pbracketBase->keyLen + sizeof(dsmKey_t));
- error = gemKeyAddHigh(pbracketLimit->keystr + pbracketLimit->keyLen,
- &componentLen);
- if(error)
- goto errorReturn;
- pbracketLimit->keyLen += componentLen;
- }
- else
- {
- /* Always add a high range -- except for HA_READ_KEY_EXACT this
- is all we need for the upper index bracket */
- error = gemKeyHigh(pbracketLimit->keystr, &componentLen,
- pbracketLimit->index);
-
- pbracketLimit->keyLen = componentLen;
- }
- /* We have to subtract the header size here since cxKeyPrepare
- expects that the three lead bytes of the header are
- not counted in this length -- But cxKeyPrepare also
- expects that these three bytes are present in the keystr */
- pbracketBase->keyLen -= FULLKEYHDRSZ;
- pbracketLimit->keyLen -= FULLKEYHDRSZ;
-
- thd = current_thd;
-
- error = findRow(thd, DSMFINDFIRST, buf);
-
-errorReturn:
- if (error == DSM_S_ENDLOOP)
- error = HA_ERR_KEY_NOT_FOUND;
-
- table->status = error ? STATUS_NOT_FOUND : 0;
- DBUG_RETURN(error);
-}
-
-
-int ha_gemini::index_next(byte * buf)
-{
- THD *thd;
- int error = 1;
- int keyStringLen=0;
- dsmMask_t findMode;
- DBUG_ENTER("index_next");
-
- if(tableStatus == HA_ERR_CRASHED)
- DBUG_RETURN(tableStatus);
-
- thd = current_thd;
-
- if(pbracketBase->index == 0)
- {
- error = gemKeyLow(pbracketBase->keystr, &keyStringLen,
- pbracketLimit->index);
-
- pbracketBase->keyLen = (COUNT)keyStringLen - FULLKEYHDRSZ;
- pbracketBase->index = pbracketLimit->index;
- error = gemKeyHigh(pbracketLimit->keystr, &keyStringLen,
- pbracketLimit->index);
- pbracketLimit->keyLen = (COUNT)keyStringLen - FULLKEYHDRSZ;
-
- findMode = DSMFINDFIRST;
- }
- else
- findMode = DSMFINDNEXT;
-
- error = findRow(thd,findMode,buf);
-
- if (error == DSM_S_ENDLOOP)
- error = HA_ERR_END_OF_FILE;
-
- table->status = error ? STATUS_NOT_FOUND : 0;
- DBUG_RETURN(error);
-}
-
-int ha_gemini::index_next_same(byte * buf, const byte *key, uint keylen)
-{
- int error = 0;
- DBUG_ENTER("index_next_same");
- statistic_increment(ha_read_next_count,&LOCK_status);
- DBUG_RETURN(index_next(buf));
-}
-
-
-int ha_gemini::index_prev(byte * buf)
-{
- int error = 0;
- THD *thd = current_thd;
-
- DBUG_ENTER("index_prev");
- statistic_increment(ha_read_prev_count,&LOCK_status);
-
- error = findRow(thd, DSMFINDPREV, buf);
-
- if (error == DSM_S_ENDLOOP)
- error = HA_ERR_END_OF_FILE;
-
-
- table->status = error ? STATUS_NOT_FOUND : 0;
- DBUG_RETURN(error);
-}
-
-
-int ha_gemini::index_first(byte * buf)
-{
- DBUG_ENTER("index_first");
- statistic_increment(ha_read_first_count,&LOCK_status);
- DBUG_RETURN(index_next(buf));
-}
-
-int ha_gemini::index_last(byte * buf)
-{
- int error = 0;
- THD *thd;
- int keyStringLen;
- dsmMask_t findMode;
- thd = current_thd;
-
- DBUG_ENTER("index_last");
- statistic_increment(ha_read_last_count,&LOCK_status);
-
- error = gemKeyLow(pbracketBase->keystr, &keyStringLen,
- pbracketLimit->index);
-
- pbracketBase->keyLen = (COUNT)keyStringLen - FULLKEYHDRSZ;
- pbracketBase->index = pbracketLimit->index;
- error = gemKeyHigh(pbracketLimit->keystr, &keyStringLen,
- pbracketLimit->index);
- pbracketLimit->keyLen = (COUNT)keyStringLen - FULLKEYHDRSZ;
-
- error = findRow(thd,DSMFINDLAST,buf);
-
- if (error == DSM_S_ENDLOOP)
- error = HA_ERR_END_OF_FILE;
-
- table->status = error ? STATUS_NOT_FOUND : 0;
- DBUG_RETURN(error);
-}
-
-int ha_gemini::rnd_init(bool scan)
-{
- THD *thd = current_thd;
-
- lastRowid = 0;
-
- return 0;
-}
-
-int ha_gemini::rnd_end()
-{
-/*
- return gem_scan_end();
-*/
- return 0;
-}
-
-int ha_gemini::rnd_next(byte *buf)
-{
- int error = 0;
- dsmRecord_t dsmRecord;
- THD *thd;
-
- DBUG_ENTER("rnd_next");
-
- if(tableStatus == HA_ERR_CRASHED)
- DBUG_RETURN(tableStatus);
-
- thd = current_thd;
- if(thd->gemini.tx_isolation == ISO_READ_COMMITTED && !(lockMode & DSM_LK_EXCL)
- && lastRowid)
- error = dsmObjectUnlock((dsmContext_t *)thd->gemini.context,
- tableNumber, DSMOBJECT_RECORD, lastRowid,
- lockMode | DSM_UNLK_FREE, 0);
-
- statistic_increment(ha_read_rnd_next_count,&LOCK_status);
- dsmRecord.table = tableNumber;
- dsmRecord.recid = lastRowid;
- dsmRecord.pbuffer = (dsmBuffer_t *)rec_buff;
- dsmRecord.recLength = table->reclength;
- dsmRecord.maxLength = table->rec_buff_length;
-
- error = dsmTableScan((dsmContext_t *)thd->gemini.context,
- &dsmRecord, DSMFINDNEXT, lockMode, 0);
-
- if(!error)
- {
- lastRowid = dsmRecord.recid;
- error = unpack_row((char *)buf,(char *)dsmRecord.pbuffer);
- }
- if(!error)
- ;
- else
- {
- lastRowid = 0;
- if (error == DSM_S_ENDLOOP)
- error = HA_ERR_END_OF_FILE;
- else if (error == DSM_S_RQSTREJ)
- error = HA_ERR_LOCK_WAIT_TIMEOUT;
- else if (error == DSM_S_LKTBFULL)
- {
- error = HA_ERR_LOCK_TABLE_FULL;
- gemini_lock_table_overflow_error((dsmContext_t *)thd->gemini.context);
- }
- }
- table->status = error ? STATUS_NOT_FOUND : 0;
- DBUG_RETURN(error);
-}
-
-
-int ha_gemini::rnd_pos(byte * buf, byte *pos)
-{
- int error;
- int rc;
-
- THD *thd;
-
- statistic_increment(ha_read_rnd_count,&LOCK_status);
- thd = current_thd;
- memcpy((void *)&lastRowid,pos,ref_length);
- if(thd->gemini.tx_isolation == ISO_READ_COMMITTED && !(lockMode & DSM_LK_EXCL))
- {
- /* Lock the row */
-
- error = dsmObjectLock((dsmContext_t *)thd->gemini.context,
- (dsmObject_t)tableNumber,DSMOBJECT_RECORD,lastRowid,
- lockMode, 1, 0);
- if ( error )
- goto errorReturn;
- }
- error = fetch_row(thd->gemini.context, buf);
- if(thd->gemini.tx_isolation == ISO_READ_COMMITTED && !(lockMode & DSM_LK_EXCL))
- {
- /* Unlock the row */
-
- rc = dsmObjectUnlock((dsmContext_t *)thd->gemini.context,
- (dsmObject_t)tableNumber,DSMOBJECT_RECORD,lastRowid,
- lockMode | DSM_UNLK_FREE , 0);
- }
- if(error == DSM_S_RMNOTFND)
- error = HA_ERR_RECORD_DELETED;
-
- errorReturn:
- table->status = error ? STATUS_NOT_FOUND : 0;
- return error;
-}
-
-int ha_gemini::fetch_row(void *gemini_context,const byte *buf)
-{
- dsmStatus_t rc = 0;
- dsmRecord_t dsmRecord;
-
- DBUG_ENTER("fetch_row");
- dsmRecord.table = tableNumber;
- dsmRecord.recid = lastRowid;
- dsmRecord.pbuffer = (dsmBuffer_t *)rec_buff;
- dsmRecord.recLength = table->reclength;
- dsmRecord.maxLength = table->rec_buff_length;
-
- rc = dsmRecordGet((dsmContext_t *)gemini_context,
- &dsmRecord, 0);
-
- if(!rc)
- {
- rc = unpack_row((char *)buf,(char *)dsmRecord.pbuffer);
- }
-
- DBUG_RETURN(rc);
-}
-int ha_gemini::findRow(THD *thd, dsmMask_t findMode, byte *buf)
-{
- dsmStatus_t rc;
- dsmKey_t *pkey;
-
- DBUG_ENTER("findRow");
-
- if(thd->gemini.tx_isolation == ISO_READ_COMMITTED && !(lockMode & DSM_LK_EXCL)
- && lastRowid)
- rc = dsmObjectUnlock((dsmContext_t *)thd->gemini.context,
- tableNumber, DSMOBJECT_RECORD, lastRowid,
- lockMode | DSM_UNLK_FREE, 0);
- if( key_read )
- pkey = pfoundKey;
- else
- pkey = 0;
-
- rc = dsmCursorFind((dsmContext_t *)thd->gemini.context,
- &cursorId,
- pbracketBase,
- pbracketLimit,
- DSMPARTIAL,
- findMode,
- lockMode,
- NULL,
- &lastRowid,
- pkey);
- if( rc )
- goto errorReturn;
-
- if(key_read)
- {
- unpack_key((char*)buf, pkey, active_index);
- }
- if(!key_read) /* unpack_key may have turned off key_read */
- {
- rc = fetch_row((dsmContext_t *)thd->gemini.context,buf);
- }
-
-errorReturn:
- if(!rc)
- ;
- else
- {
- lastRowid = 0;
- if(rc == DSM_S_RQSTREJ)
- rc = HA_ERR_LOCK_WAIT_TIMEOUT;
- else if (rc == DSM_S_LKTBFULL)
- {
- rc = HA_ERR_LOCK_TABLE_FULL;
- gemini_lock_table_overflow_error((dsmContext_t *)thd->gemini.context);
- }
- }
-
- DBUG_RETURN(rc);
-}
-
-void ha_gemini::position(const byte *record)
-{
- memcpy(ref,&lastRowid,ref_length);
-}
-
-
-void ha_gemini::info(uint flag)
-{
- DBUG_ENTER("info");
-
- if ((flag & HA_STATUS_VARIABLE))
- {
- THD *thd = current_thd;
- dsmStatus_t error;
- ULONG64 rows;
-
- if(thd->gemini.context == NULL)
- {
- /* Need to get this thread a connection into the database */
- error = gemini_connect(thd);
- if(error)
- DBUG_VOID_RETURN;
- }
-
- error = dsmRowCount((dsmContext_t *)thd->gemini.context,tableNumber,&rows);
- records = (ha_rows)rows;
- deleted = 0;
- }
- if ((flag & HA_STATUS_CONST))
- {
- ha_rows *rec_per_key = share->rec_per_key;
- for (uint i = 0; i < table->keys; i++)
- for(uint k=0;
- k < table->key_info[i].key_parts; k++,rec_per_key++)
- table->key_info[i].rec_per_key[k] = *rec_per_key;
- }
- if ((flag & HA_STATUS_ERRKEY))
- {
- errkey=last_dup_key;
- }
- if ((flag & HA_STATUS_TIME))
- {
- ;
- }
- if ((flag & HA_STATUS_AUTO))
- {
- THD *thd = current_thd;
- dsmStatus_t error;
-
- error = dsmTableAutoIncrement((dsmContext_t *)thd->gemini.context,
- tableNumber,
- (ULONG64 *)&auto_increment_value,
- 0);
- /* Should return the next auto-increment value that
- will be given -- so we need to increment the one dsm
- currently reports. */
- auto_increment_value++;
- }
-
- DBUG_VOID_RETURN;
-}
-
-
-int ha_gemini::extra(enum ha_extra_function operation)
-{
- switch (operation)
- {
- case HA_EXTRA_RESET:
- case HA_EXTRA_RESET_STATE:
- key_read=0;
- using_ignore=0;
- break;
- case HA_EXTRA_KEYREAD:
- key_read=1; // Query satisfied with key
- break;
- case HA_EXTRA_NO_KEYREAD:
- key_read=0;
- break;
- case HA_EXTRA_IGNORE_DUP_KEY:
- using_ignore=1;
- break;
- case HA_EXTRA_NO_IGNORE_DUP_KEY:
- using_ignore=0;
- break;
-
- default:
- break;
- }
- return 0;
-}
-
-
-int ha_gemini::reset(void)
-{
- key_read=0; // Reset to state after open
- return 0;
-}
-
-
-/*
- As MySQL will execute an external lock for every new table it uses
- we can use this to start the transactions.
-*/
-
-int ha_gemini::external_lock(THD *thd, int lock_type)
-{
- dsmStatus_t rc = 0;
- LONG txNumber;
-
- DBUG_ENTER("ha_gemini::external_lock");
-
- if (lock_type != F_UNLCK)
- {
- if (!thd->gemini.lock_count)
- {
- thd->gemini.lock_count = 1;
- thd->gemini.tx_isolation = thd->tx_isolation;
- }
- // lockMode has already been set in store_lock
- // If the statement about to be executed calls for
- // exclusive locks and we're running at read uncommitted
- // isolation level then raise an error.
- if(thd->gemini.tx_isolation == ISO_READ_UNCOMMITTED)
- {
- if(lockMode == DSM_LK_EXCL)
- {
- DBUG_RETURN(HA_ERR_READ_ONLY_TRANSACTION);
- }
- else
- {
- lockMode = DSM_LK_NOLOCK;
- }
- }
-
- if(thd->gemini.context == NULL)
- {
- /* Need to get this thread a connection into the database */
- rc = gemini_connect(thd);
- if(rc)
- return rc;
- }
- /* Set need savepoint flag */
- thd->gemini.needSavepoint = 1;
-
- if(rc)
- DBUG_RETURN(rc);
-
-
- if( thd->in_lock_tables || thd->gemini.tx_isolation == ISO_SERIALIZABLE )
- {
- rc = dsmObjectLock((dsmContext_t *)thd->gemini.context,
- (dsmObject_t)tableNumber,DSMOBJECT_TABLE,0,
- lockMode, 1, 0);
- if(rc == DSM_S_RQSTREJ)
- rc = HA_ERR_LOCK_WAIT_TIMEOUT;
- }
- }
- else /* lock_type == F_UNLK */
- {
- /* Commit the tx if we're in auto-commit mode */
- if (!(thd->options & OPTION_NOT_AUTO_COMMIT)&&
- !(thd->options & OPTION_BEGIN))
- gemini_commit(thd);
- }
-
- DBUG_RETURN(rc);
-}
-
-
-THR_LOCK_DATA **ha_gemini::store_lock(THD *thd, THR_LOCK_DATA **to,
- enum thr_lock_type lock_type)
-{
- if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
- {
- /* If we are not doing a LOCK TABLE, then allow multiple writers */
- if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
- lock_type <= TL_WRITE) &&
- !thd->in_lock_tables)
- lock_type = TL_WRITE_ALLOW_WRITE;
- lock.type=lock_type;
- }
- if(table->reginfo.lock_type > TL_WRITE_ALLOW_READ)
- lockMode = DSM_LK_EXCL;
- else
- lockMode = DSM_LK_SHARE;
-
- *to++= &lock;
- return to;
-}
-
-void ha_gemini::update_create_info(HA_CREATE_INFO *create_info)
-{
- table->file->info(HA_STATUS_AUTO | HA_STATUS_CONST);
- if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
- {
- create_info->auto_increment_value=auto_increment_value;
- }
-}
-
-int ha_gemini::create(const char *name, register TABLE *form,
- HA_CREATE_INFO *create_info)
-{
- THD *thd;
- char name_buff[FN_REFLEN];
- char dbname_buff[FN_REFLEN];
- DBUG_ENTER("ha_gemini::create");
- dsmContext_t *pcontext;
- dsmStatus_t rc;
- dsmArea_t areaNumber;
- dsmObject_t tableNumber = 0;
- dsmDbkey_t dummy = 0;
- unsigned i;
- int baseNameLen;
- dsmObject_t indexNumber;
-
- /* separate out the name of the table and the database (a VST must be
- ** created in the mysql database)
- */
- rc = gemini_parse_table_name(name, dbname_buff, name_buff);
- if (rc == 0)
- {
- /* If the table is a VST, don't create areas or extents */
- if (strcmp(dbname_buff, "mysql") == 0)
- {
- tableNumber = gemini_is_vst(name_buff);
- if (tableNumber)
- {
- return 0;
- }
- }
- }
-
- thd = current_thd;
- if(thd->gemini.context == NULL)
- {
- /* Need to get this thread a connection into the database */
- rc = gemini_connect(thd);
- if(rc)
- return rc;
- }
- pcontext = (dsmContext_t *)thd->gemini.context;
-
- if(thd->gemini.needSavepoint || using_ignore)
- {
- thd->gemini.savepoint++;
- rc = dsmTransaction((dsmContext_t *)thd->gemini.context,
- &thd->gemini.savepoint,
- DSMTXN_SAVE, 0, 0);
- if (rc)
- DBUG_RETURN(rc);
- thd->gemini.needSavepoint = 0;
- }
-
- fn_format(name_buff, name, "", ha_gemini_ext, 2 | 4);
- /* Create a storage area */
- rc = dsmAreaNew(pcontext,gemini_blocksize,DSMAREA_TYPE_DATA,
- &areaNumber, gemini_recbits,
- (dsmText_t *)"gemini_data_area");
- if( rc != 0 )
- {
- gemini_msg(pcontext, "dsmAreaNew failed %l",rc);
- return(rc);
- }
-
- /* Create an extent */
- /* Don't pass in leading ./ in name_buff */
- rc = dsmExtentCreate(pcontext,areaNumber,1,15,5,
- (dsmText_t *)&name_buff[start_of_name]);
- if( rc != 0 )
- {
- gemini_msg(pcontext, "dsmExtentCreate failed %l",rc);
- return(rc);
- }
-
- /* Create the table storage object */
- /* Change slashes in the name to periods */
- for( i = 0; i < strlen(name_buff); i++)
- if(name_buff[i] == '/' || name_buff[i] == '\\')
- name_buff[i] = '.';
-
- /* Get rid of .gmd suffix */
- name_buff[strlen(name_buff) - 4] = '\0';
-
- rc = dsmObjectCreate(pcontext, areaNumber, &tableNumber,
- DSMOBJECT_MIXTABLE,0,0,0,
- (dsmText_t *)&name_buff[start_of_name],
- &dummy,&dummy);
-
- if (rc == 0 && table->blob_fields)
- {
- /* create a storage object record for blob fields */
- rc = dsmObjectCreate(pcontext, areaNumber, &tableNumber,
- DSMOBJECT_BLOB,0,0,0,
- (dsmText_t *)&name_buff[start_of_name],
- &dummy,&dummy);
- if( rc != 0 )
- {
- gemini_msg(pcontext, "dsmObjectCreate for blob object failed %l",rc);
- return(rc);
- }
- }
-
- if(rc == 0 && form->keys)
- {
- fn_format(name_buff, name, "", ha_gemini_idx_ext, 2 | 4);
- /* Create a storage area */
- rc = dsmAreaNew(pcontext,gemini_blocksize,DSMAREA_TYPE_DATA,
- &areaNumber, gemini_recbits,
- (dsmText_t *)"gemini_index_area");
- if( rc != 0 )
- {
- gemini_msg(pcontext, "dsmAreaNew failed %l",rc);
- return(rc);
- }
- /* Create an extent */
- /* Don't pass in leading ./ in name_buff */
- rc = dsmExtentCreate(pcontext,areaNumber,1,15,5,
- (dsmText_t *)&name_buff[start_of_name]);
- if( rc != 0 )
- {
- gemini_msg(pcontext, "dsmExtentCreate failed %l",rc);
- return(rc);
- }
-
- /* Change slashes in the name to periods */
- for( i = 0; i < strlen(name_buff); i++)
- if(name_buff[i] == '/' || name_buff[i] == '\\')
- name_buff[i] = '.';
-
- /* Get rid of .gmi suffix */
- name_buff[strlen(name_buff) - 4] = '\0';
-
- baseNameLen = strlen(name_buff);
- name_buff[baseNameLen] = '.';
- baseNameLen++;
- for( i = 0; i < form->keys; i++)
- {
- dsmObjectAttr_t indexUnique;
-
- indexNumber = DSMINDEX_INVALID;
- /* Create a storage object record for each index */
- /* Add the index name so the object name is in the form
- <db>.<table>.<index_name> */
- strcpy(&name_buff[baseNameLen],table->key_info[i].name);
- if(table->key_info[i].flags & HA_NOSAME)
- indexUnique = 1;
- else
- indexUnique = 0;
- rc = dsmObjectCreate(pcontext, areaNumber, &indexNumber,
- DSMOBJECT_MIXINDEX,indexUnique,tableNumber,
- DSMOBJECT_MIXTABLE,
- (dsmText_t *)&name_buff[start_of_name],
- &dummy,&dummy);
-
- }
- }
- /* The auto_increment value is the next one to be given
- out so give dsm one less than this value */
- if(create_info->auto_increment_value)
- rc = dsmTableAutoIncrementSet(pcontext,tableNumber,
- create_info->auto_increment_value-1);
-
- /* Get a table lock on this table in case this table is being
- created as part of an alter table statement. We don't want
- the alter table statement to abort because of a lock table overflow
- */
- if (thd->lex.sql_command == SQLCOM_CREATE_INDEX ||
- thd->lex.sql_command == SQLCOM_ALTER_TABLE ||
- thd->lex.sql_command == SQLCOM_DROP_INDEX)
- {
- rc = dsmObjectLock(pcontext,
- (dsmObject_t)tableNumber,DSMOBJECT_TABLE,0,
- DSM_LK_EXCL, 1, 0);
- /* and don't commit so we won't release the table on the table number
- of the table being altered */
- }
- else
- {
- if(!rc)
- rc = gemini_commit(thd);
- }
-
- DBUG_RETURN(rc);
-}
-
-int ha_gemini::delete_table(const char *pname)
-{
- THD *thd;
- dsmStatus_t rc;
- dsmContext_t *pcontext;
- unsigned i,nameLen;
- dsmArea_t indexArea = 0;
- dsmArea_t tableArea = 0;
- dsmObjectAttr_t objectAttr;
- dsmObject_t associate;
- dsmObjectType_t associateType;
- dsmDbkey_t block, root;
- int need_txn = 0;
- dsmObject_t tableNum = 0;
- char name_buff[FN_REFLEN];
- char dbname_buff[FN_REFLEN];
- DBUG_ENTER("ha_gemini::delete_table");
-
- /* separate out the name of the table and the database (a VST must be
- ** located in the mysql database)
- */
- rc = gemini_parse_table_name(pname, dbname_buff, name_buff);
- if (rc == 0)
- {
- /* If the table is a VST, there are no areas or extents to delete */
- if (strcmp(dbname_buff, "mysql") == 0)
- {
- tableNum = gemini_is_vst(name_buff);
- if (tableNum)
- {
- return 0;
- }
- }
- }
-
- thd = current_thd;
- if(thd->gemini.context == NULL)
- {
- /* Need to get this thread a connection into the database */
- rc = gemini_connect(thd);
- if(rc)
- {
- DBUG_RETURN(rc);
- }
- }
- pcontext = (dsmContext_t *)thd->gemini.context;
-
-
- bzero(name_buff, FN_REFLEN);
-
- nameLen = strlen(pname);
- for( i = start_of_name; i < nameLen; i++)
- {
- if(pname[i] == '/' || pname[i] == '\\')
- name_buff[i-start_of_name] = '.';
- else
- name_buff[i-start_of_name] = pname[i];
- }
-
- rc = dsmObjectNameToNum(pcontext, (dsmText_t *)name_buff,
- (dsmObject_t *)&tableNum);
- if (rc)
- {
- gemini_msg(pcontext, "Unable to find table number for %s", name_buff);
- rc = gemini_rollback(thd);
- if (rc)
- {
- gemini_msg(pcontext, "Error in rollback %l",rc);
- }
- DBUG_RETURN(rc);
- }
-
- rc = dsmObjectInfo(pcontext, tableNum, DSMOBJECT_MIXTABLE, tableNum,
- &tableArea, &objectAttr, &associateType, &block, &root);
- if (rc)
- {
- gemini_msg(pcontext, "Failed to get area number for table %d, %s, return %l",
- tableNum, pname, rc);
- rc = gemini_rollback(thd);
- if (rc)
- {
- gemini_msg(pcontext, "Error in rollback %l",rc);
- }
- }
-
- indexArea = DSMAREA_INVALID;
-
- /* Delete the indexes and tables storage objects for with the table */
- rc = dsmObjectDeleteAssociate(pcontext, tableNum, &indexArea);
- if (rc)
- {
- gemini_msg(pcontext, "Error deleting storage objects for table number %d, return %l",
- (int)tableNum, rc);
-
- /* roll back txn and return */
- rc = gemini_rollback(thd);
- if (rc)
- {
- gemini_msg(pcontext, "Error in rollback %l",rc);
- }
- DBUG_RETURN(rc);
- }
-
- if (indexArea != DSMAREA_INVALID)
- {
- /* Delete the extents for both Index and Table */
- rc = dsmExtentDelete(pcontext, indexArea);
- rc = dsmAreaDelete(pcontext, indexArea);
- if (rc)
- {
- gemini_msg(pcontext, "Error deleting Index Area %l, return %l", indexArea, rc);
-
- /* roll back txn and return */
- rc = gemini_rollback(thd);
- if (rc)
- {
- gemini_msg(pcontext, "Error in rollback %l",rc);
- }
- DBUG_RETURN(rc);
- }
- }
-
- rc = dsmExtentDelete(pcontext, tableArea);
- rc = dsmAreaDelete(pcontext, tableArea);
- if (rc)
- {
- gemini_msg(pcontext, "Error deleting table Area %l, name %s, return %l",
- tableArea, pname, rc);
- /* roll back txn and return */
- rc = gemini_rollback(thd);
- if (rc)
- {
- gemini_msg(pcontext, "Error in rollback %l",rc);
- }
- DBUG_RETURN(rc);
- }
-
-
- /* Commit the transaction */
- rc = gemini_commit(thd);
- if (rc)
- {
- gemini_msg(pcontext, "Failed to commit transaction %l",rc);
- }
-
-
- /* now remove all the files that need to be removed and
- cause a checkpoint so recovery will work */
- rc = dsmExtentUnlink(pcontext);
-
- DBUG_RETURN(0);
-}
-
-
-int ha_gemini::rename_table(const char *pfrom, const char *pto)
-{
- THD *thd;
- dsmContext_t *pcontext;
- dsmStatus_t rc;
- char dbname_buff[FN_REFLEN];
- char name_buff[FN_REFLEN];
- char newname_buff[FN_REFLEN];
- char newextname_buff[FN_REFLEN];
- char newidxextname_buff[FN_REFLEN];
- unsigned i, nameLen;
- dsmObject_t tableNum;
- dsmArea_t indexArea = 0;
- dsmArea_t tableArea = 0;
-
- DBUG_ENTER("ha_gemini::rename_table");
-
- /* don't allow rename of VSTs */
- rc = gemini_parse_table_name(pfrom, dbname_buff, name_buff);
- if (rc == 0)
- {
- /* If the table is a VST, don't create areas or extents */
- if (strcmp(dbname_buff, "mysql") == 0)
- {
- if (gemini_is_vst(name_buff))
- {
- return DSM_S_CANT_RENAME_VST;
- }
- }
- }
-
- thd = current_thd;
- if (thd->gemini.context == NULL)
- {
- /* Need to get this thread a connection into the database */
- rc = gemini_connect(thd);
- if (rc)
- {
- DBUG_RETURN(rc);
- }
- }
-
- pcontext = (dsmContext_t *)thd->gemini.context;
-
- /* change the slashes to dots in the old and new names */
- nameLen = strlen(pfrom);
- for( i = start_of_name; i < nameLen; i++)
- {
- if(pfrom[i] == '/' || pfrom[i] == '\\')
- name_buff[i-start_of_name] = '.';
- else
- name_buff[i-start_of_name] = pfrom[i];
- }
- name_buff[i-start_of_name] = '\0';
-
- nameLen = strlen(pto);
- for( i = start_of_name; i < nameLen; i++)
- {
- if(pto[i] == '/' || pto[i] == '\\')
- newname_buff[i-start_of_name] = '.';
- else
- newname_buff[i-start_of_name] = pto[i];
- }
- newname_buff[i-start_of_name] = '\0';
-
- /* generate new extent names (for table and index extents) */
- fn_format(newextname_buff, pto, "", ha_gemini_ext, 2 | 4);
- fn_format(newidxextname_buff, pto, "", ha_gemini_idx_ext, 2 | 4);
-
- rc = dsmObjectNameToNum(pcontext, (dsmText_t *)name_buff, &tableNum);
- if (rc)
- {
- gemini_msg(pcontext, "Unable to file Table number for %s", name_buff);
- goto errorReturn;
- }
-
- rc = dsmObjectRename(pcontext, tableNum,
- (dsmText_t *)newname_buff,
- (dsmText_t *)&newidxextname_buff[start_of_name],
- (dsmText_t *)&newextname_buff[start_of_name],
- &indexArea, &tableArea);
- if (rc)
- {
- gemini_msg(pcontext, "Failed to rename %s to %s",name_buff,newname_buff);
- goto errorReturn;
- }
-
- /* Rename the physical table and index files (if necessary).
- ** Close the file, rename it, and reopen it (have to do it this
- ** way so rename works on Windows).
- */
- if (!(rc = dsmAreaClose(pcontext, tableArea)))
- {
- if (!(rc = rename_file_ext(pfrom, pto, ha_gemini_ext)))
- {
- rc = dsmAreaOpen(pcontext, tableArea, 0);
- if (rc)
- {
- gemini_msg(pcontext, "Failed to reopen area %d",tableArea);
- }
- }
- }
-
- if (!rc && indexArea)
- {
- if (!(rc = dsmAreaClose(pcontext, indexArea)))
- {
- if (!(rc = rename_file_ext(pfrom, pto, ha_gemini_idx_ext)))
- {
- rc = dsmAreaOpen(pcontext, indexArea, 0);
- if (rc)
- {
- gemini_msg(pcontext, "Failed to reopen area %d",tableArea);
- }
- }
- }
- }
-
-errorReturn:
- DBUG_RETURN(rc);
-}
-
-
-/*
- 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
- that we can decide if we should scan the table or use keys.
-*/
-
-double ha_gemini::scan_time()
-{
- return (double)records /
- (double)((gemini_blocksize / (double)table->reclength));
-}
-
-int ha_gemini::analyze(THD* thd, HA_CHECK_OPT* check_opt)
-{
- int error;
- uint saveIsolation;
- dsmMask_t saveLockMode;
-
- check_opt->quick = TRUE;
- check_opt->optimize = TRUE; // Tells check not to get table lock
- saveLockMode = lockMode;
- saveIsolation = thd->gemini.tx_isolation;
- thd->gemini.tx_isolation = ISO_READ_UNCOMMITTED;
- lockMode = DSM_LK_NOLOCK;
- error = check(thd,check_opt);
- lockMode = saveLockMode;
- thd->gemini.tx_isolation = saveIsolation;
- return (error);
-}
-
-int ha_gemini::check(THD* thd, HA_CHECK_OPT* check_opt)
-{
- int error = 0;
- int checkStatus = HA_ADMIN_OK;
- ha_rows indexCount;
- byte *buf = 0, *indexBuf = 0, *prevBuf = 0;
- int errorCount = 0;
-
- info(HA_STATUS_VARIABLE); // Makes sure row count is up to date
-
- /* Get a shared table lock */
- if(thd->gemini.needSavepoint)
- {
- /* We don't really need a savepoint here but do it anyway
- just to keep the savepoint number correct. */
- thd->gemini.savepoint++;
- error = dsmTransaction((dsmContext_t *)thd->gemini.context,
- &thd->gemini.savepoint,
- DSMTXN_SAVE, 0, 0);
- if (error)
- return(error);
- thd->gemini.needSavepoint = 0;
- }
- buf = (byte*)my_malloc(table->rec_buff_length,MYF(MY_WME));
- indexBuf = (byte*)my_malloc(table->rec_buff_length,MYF(MY_WME));
- prevBuf = (byte*)my_malloc(table->rec_buff_length,MYF(MY_WME |MY_ZEROFILL ));
-
- /* Lock the table */
- if (!check_opt->optimize)
- error = dsmObjectLock((dsmContext_t *)thd->gemini.context,
- (dsmObject_t)tableNumber,
- DSMOBJECT_TABLE,0,
- DSM_LK_SHARE, 1, 0);
- if(error)
- {
- gemini_msg((dsmContext_t *)thd->gemini.context,
- "Failed to lock table %d, error %d",tableNumber, error);
- return error;
- }
-
- ha_rows *rec_per_key = share->rec_per_key;
- /* If quick option just scan along index converting and counting entries */
- for (uint i = 0; i < table->keys; i++)
- {
- key_read = 1; // Causes data to be extracted from the keys
- indexCount = 0;
- // Clear the cardinality stats for this index
- memset(table->key_info[i].rec_per_key,0,
- sizeof(table->key_info[0].rec_per_key[0]) *
- table->key_info[i].key_parts);
- error = index_init(i);
- error = index_first(indexBuf);
- while(!error)
- {
- indexCount++;
- if(!check_opt->quick)
- {
- /* Fetch row and compare to data produced from key */
- error = fetch_row(thd->gemini.context,buf);
- if(!error)
- {
- if(key_cmp(i,buf,indexBuf,FALSE))
- {
-
- gemini_msg((dsmContext_t *)thd->gemini.context,
- "Check Error! Key does not match row for rowid %d for index %s",
- lastRowid,table->key_info[i].name);
- print_msg(thd,table->real_name,"check","error",
- "Key does not match row for rowid %d for index %s",
- lastRowid,table->key_info[i].name);
- checkStatus = HA_ADMIN_CORRUPT;
- errorCount++;
- if(errorCount > 1000)
- goto error_return;
- }
- else if(error == DSM_S_RMNOTFND)
- {
- errorCount++;
- checkStatus = HA_ADMIN_CORRUPT;
- gemini_msg((dsmContext_t *)thd->gemini.context,
- "Check Error! Key does not have a valid row pointer %d for index %s",
- lastRowid,table->key_info[i].name);
- print_msg(thd,table->real_name,"check","error",
- "Key does not have a valid row pointer %d for index %s",
- lastRowid,table->key_info[i].name);
- if(errorCount > 1000)
- goto error_return;
- error = 0;
- }
- }
- }
-
- key_cmp(i,indexBuf,prevBuf,TRUE);
- bcopy((void *)indexBuf,(void *)prevBuf,table->rec_buff_length);
-
- if(!error)
- error = index_next(indexBuf);
- }
-
- for(uint j=1; j < table->key_info[i].key_parts; j++)
- {
- table->key_info[i].rec_per_key[j] += table->key_info[i].rec_per_key[j-1];
- }
- for(uint k=0; k < table->key_info[i].key_parts; k++)
- {
- if (table->key_info[i].rec_per_key[k])
- table->key_info[i].rec_per_key[k] =
- records / table->key_info[i].rec_per_key[k];
- *rec_per_key = table->key_info[i].rec_per_key[k];
- rec_per_key++;
- }
-
- if(error == HA_ERR_END_OF_FILE)
- {
- /* Check count of rows */
-
- if(records != indexCount)
- {
- /* Number of index entries does not agree with the number of
- rows in the index. */
- checkStatus = HA_ADMIN_CORRUPT;
- gemini_msg((dsmContext_t *)thd->gemini.context,
- "Check Error! Total rows %d does not match total index entries %d for %s",
- records, indexCount,
- table->key_info[i].name);
- print_msg(thd,table->real_name,"check","error",
- "Total rows %d does not match total index entries %d for %s",
- records, indexCount,
- table->key_info[i].name);
- }
- }
- else
- {
- checkStatus = HA_ADMIN_FAILED;
- goto error_return;
- }
- index_end();
- }
- if(!check_opt->quick)
- {
- /* Now scan the table and for each row generate the keys
- and find them in the index */
- error = fullCheck(thd, buf);
- if(error)
- checkStatus = error;
- }
- // Store the key distribution information
- error = saveKeyStats(thd);
-
-error_return:
- my_free((char*)buf,MYF(MY_ALLOW_ZERO_PTR));
- my_free((char*)indexBuf,MYF(MY_ALLOW_ZERO_PTR));
- my_free((char*)prevBuf,MYF(MY_ALLOW_ZERO_PTR));
-
- index_end();
- key_read = 0;
- if(!check_opt->optimize)
- {
- error = dsmObjectUnlock((dsmContext_t *)thd->gemini.context,
- (dsmObject_t)tableNumber,
- DSMOBJECT_TABLE,0,
- DSM_LK_SHARE,0);
- if (error)
- {
- gemini_msg((dsmContext_t *)thd->gemini.context,
- "Unable to unlock table %d", tableNumber);
- }
- }
-
- return checkStatus;
-}
-
-int ha_gemini::saveKeyStats(THD *thd)
-{
- dsmStatus_t rc = 0;
-
- /* Insert a row in the indexStats table for each column of
- each index of the table */
-
- for(uint i = 0; i < table->keys; i++)
- {
- for (uint j = 0; j < table->key_info[i].key_parts && !rc ;j++)
- {
- rc = dsmIndexStatsPut((dsmContext_t *)thd->gemini.context,
- tableNumber, pindexNumbers[i],
- j, (LONG64)table->key_info[i].rec_per_key[j]);
- if (rc)
- {
- gemini_msg((dsmContext_t *)thd->gemini.context,
- "Failed to update index stats for table %d, index %d",
- tableNumber, pindexNumbers[i]);
- }
- }
- }
- return rc;
-}
-
-int ha_gemini::fullCheck(THD *thd,byte *buf)
-{
- int error;
- int errorCount = 0;
- int checkStatus = 0;
-
- lastRowid = 0;
-
- while(((error = rnd_next( buf)) != HA_ERR_END_OF_FILE) && errorCount <= 1000)
- {
- if(!error)
- {
- error = handleIndexEntries(buf,lastRowid,KEY_CHECK);
- if(error)
- {
- /* Error finding an index entry for a row. */
- print_msg(thd,table->real_name,"check","error",
- "Unable to find all index entries for row %d",
- lastRowid);
- errorCount++;
- checkStatus = HA_ADMIN_CORRUPT;
- error = 0;
- }
- }
- else
- {
- /* Error reading a row */
- print_msg(thd,table->real_name,"check","error",
- "Error reading row %d status = %d",
- lastRowid,error);
- errorCount++;
- checkStatus = HA_ADMIN_CORRUPT;
- error = 0;
- }
- }
-
- return checkStatus;
-}
-
-int ha_gemini::repair(THD* thd, HA_CHECK_OPT* check_opt)
-{
- int error;
- dsmRecord_t dsmRecord;
- byte *buf;
-
- if(thd->gemini.needSavepoint)
- {
- /* We don't really need a savepoint here but do it anyway
- just to keep the savepoint number correct. */
- thd->gemini.savepoint++;
- error = dsmTransaction((dsmContext_t *)thd->gemini.context,
- &thd->gemini.savepoint,
- DSMTXN_SAVE, 0, 0);
- if (error)
- {
- gemini_msg((dsmContext_t *)thd->gemini.context,
- "Error setting savepoint number %d, error %d",
- thd->gemini.savepoint++, error);
- return(error);
- }
- thd->gemini.needSavepoint = 0;
- }
-
-
- /* Lock the table */
- error = dsmObjectLock((dsmContext_t *)thd->gemini.context,
- (dsmObject_t)tableNumber,
- DSMOBJECT_TABLE,0,
- DSM_LK_EXCL, 1, 0);
- if(error)
- {
- gemini_msg((dsmContext_t *)thd->gemini.context,
- "Failed to lock table %d, error %d",tableNumber, error);
- return error;
- }
-
- error = dsmContextSetLong((dsmContext_t *)thd->gemini.context,
- DSM_TAGCONTEXT_NO_LOGGING,1);
-
- error = dsmTableReset((dsmContext_t *)thd->gemini.context,
- (dsmTable_t)tableNumber, table->keys,
- pindexNumbers);
- if (error)
- {
- gemini_msg((dsmContext_t *)thd->gemini.context,
- "dsmTableReset failed for table %d, error %d",tableNumber, error);
- }
-
- buf = (byte*)my_malloc(table->rec_buff_length,MYF(MY_WME));
- dsmRecord.table = tableNumber;
- dsmRecord.recid = 0;
- dsmRecord.pbuffer = (dsmBuffer_t *)rec_buff;
- dsmRecord.recLength = table->reclength;
- dsmRecord.maxLength = table->rec_buff_length;
- while(!error)
- {
- error = dsmTableScan((dsmContext_t *)thd->gemini.context,
- &dsmRecord, DSMFINDNEXT, DSM_LK_NOLOCK,
- 1);
- if(!error)
- {
- if (!(error = unpack_row((char *)buf,(char *)dsmRecord.pbuffer)))
- {
- error = handleIndexEntries(buf,dsmRecord.recid,KEY_CREATE);
- if(error == HA_ERR_FOUND_DUPP_KEY)
- {
- /* We don't want to stop on duplicate keys -- we're repairing
- here so let's get as much repaired as possible. */
- error = 0;
- }
- }
- }
- }
- error = dsmObjectUnlock((dsmContext_t *)thd->gemini.context,
- (dsmObject_t)tableNumber,
- DSMOBJECT_TABLE,0,
- DSM_LK_EXCL,0);
- if (error)
- {
- gemini_msg((dsmContext_t *)thd->gemini.context,
- "Unable to unlock table %d", tableNumber);
- }
-
- my_free((char*)buf,MYF(MY_ALLOW_ZERO_PTR));
-
- error = dsmContextSetLong((dsmContext_t *)thd->gemini.context,
- DSM_TAGCONTEXT_NO_LOGGING,0);
-
- return error;
-}
-
-
-int ha_gemini::restore(THD* thd, HA_CHECK_OPT *check_opt)
-{
- dsmContext_t *pcontext = (dsmContext_t *)thd->gemini.context;
- char* backup_dir = thd->lex.backup_dir;
- char src_path[FN_REFLEN], dst_path[FN_REFLEN];
- char* table_name = table->real_name;
- int error = 0;
- int errornum;
- const char* errmsg = "";
- dsmArea_t tableArea = 0;
- dsmObjectAttr_t objectAttr;
- dsmObject_t associate;
- dsmObjectType_t associateType;
- dsmDbkey_t block, root;
- dsmStatus_t rc;
-
- rc = dsmObjectInfo(pcontext, tableNumber, DSMOBJECT_MIXTABLE, tableNumber,
- &tableArea, &objectAttr, &associateType, &block, &root);
- if (rc)
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed in dsmObjectInfo (.gmd) (Error %d)";
- errornum = rc;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- rc = dsmAreaFlush(pcontext, tableArea, FLUSH_BUFFERS | FLUSH_SYNC);
- if (rc)
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed in dsmAreaFlush (.gmd) (Error %d)";
- errornum = rc;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- rc = dsmAreaClose(pcontext, tableArea);
- if (rc)
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed in dsmAreaClose (.gmd) (Error %d)";
- errornum = rc;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- /* Restore the data file */
- if (!fn_format(src_path, table_name, backup_dir, ha_gemini_ext, 4 + 64))
- {
- return HA_ADMIN_INVALID;
- }
-
- if (my_copy(src_path, fn_format(dst_path, table->path, "",
- ha_gemini_ext, 4), MYF(MY_WME)))
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed in my_copy (.gmd) (Error %d)";
- errornum = errno;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- rc = dsmAreaFlush(pcontext, tableArea, FREE_BUFFERS);
- if (rc)
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed in dsmAreaFlush (.gmd) (Error %d)";
- errornum = rc;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- rc = dsmAreaOpen(pcontext, tableArea, 1);
- if (rc)
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed in dsmAreaOpen (.gmd) (Error %d)";
- errornum = rc;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
-#ifdef GEMINI_BACKUP_IDX
- dsmArea_t indexArea = 0;
-
- rc = dsmObjectInfo(pcontext, tableNumber, DSMOBJECT_MIXINDEX, &indexArea,
- &objectAttr, &associate, &associateType, &block, &root);
- if (rc)
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed in dsmObjectInfo (.gmi) (Error %d)";
- errornum = rc;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- rc = dsmAreaClose(pcontext, indexArea);
- if (rc)
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed in dsmAreaClose (.gmi) (Error %d)";
- errornum = rc;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- /* Restore the index file */
- if (!fn_format(src_path, table_name, backup_dir, ha_gemini_idx_ext, 4 + 64))
- {
- return HA_ADMIN_INVALID;
- }
-
- if (my_copy(src_path, fn_format(dst_path, table->path, "",
- ha_gemini_idx_ext, 4), MYF(MY_WME)))
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed in my_copy (.gmi) (Error %d)";
- errornum = errno;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- rc = dsmAreaOpen(pcontext, indexArea, 1);
- if (rc)
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed in dsmAreaOpen (.gmi) (Error %d)";
- errornum = rc;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- return HA_ADMIN_OK;
-#else /* #ifdef GEMINI_BACKUP_IDX */
- HA_CHECK_OPT tmp_check_opt;
- tmp_check_opt.init();
- /* The following aren't currently implemented in ha_gemini::repair
- ** tmp_check_opt.quick = 1;
- ** tmp_check_opt.flags |= T_VERY_SILENT;
- */
- return (repair(thd, &tmp_check_opt));
-#endif /* #ifdef GEMINI_BACKUP_IDX */
-
- err:
- {
-#if 0
- /* mi_check_print_error is in ha_myisam.cc, so none of the informative
- ** error messages above is currently being printed
- */
- MI_CHECK param;
- myisamchk_init(&param);
- param.thd = thd;
- param.op_name = (char*)"restore";
- param.table_name = table->table_name;
- param.testflag = 0;
- mi_check_print_error(&param,errmsg, errornum);
-#endif
- return error;
- }
-}
-
-
-int ha_gemini::backup(THD* thd, HA_CHECK_OPT *check_opt)
-{
- dsmContext_t *pcontext = (dsmContext_t *)thd->gemini.context;
- char* backup_dir = thd->lex.backup_dir;
- char src_path[FN_REFLEN], dst_path[FN_REFLEN];
- char* table_name = table->real_name;
- int error = 0;
- int errornum;
- const char* errmsg = "";
- dsmArea_t tableArea = 0;
- dsmObjectAttr_t objectAttr;
- dsmObject_t associate;
- dsmObjectType_t associateType;
- dsmDbkey_t block, root;
- dsmStatus_t rc;
-
- rc = dsmObjectInfo(pcontext, tableNumber, DSMOBJECT_MIXTABLE, tableNumber,
- &tableArea, &objectAttr, &associateType, &block, &root);
- if (rc)
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed in dsmObjectInfo (.gmd) (Error %d)";
- errornum = rc;
- goto err;
- }
-
- /* Flush the buffers before backing up the table */
- dsmAreaFlush((dsmContext_t *)thd->gemini.context, tableArea,
- FLUSH_BUFFERS | FLUSH_SYNC);
- if (rc)
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed in dsmAreaFlush (.gmd) (Error %d)";
- errornum = rc;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- /* Backup the .FRM file */
- if (!fn_format(dst_path, table_name, backup_dir, reg_ext, 4 + 64))
- {
- errmsg = "Failed in fn_format() for .frm file: errno = %d";
- error = HA_ADMIN_INVALID;
- errornum = errno;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- if (my_copy(fn_format(src_path, table->path,"", reg_ext, 4),
- dst_path,
- MYF(MY_WME | MY_HOLD_ORIGINAL_MODES )))
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed copying .frm file: errno = %d";
- errornum = errno;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- /* Backup the data file */
- if (!fn_format(dst_path, table_name, backup_dir, ha_gemini_ext, 4 + 64))
- {
- errmsg = "Failed in fn_format() for .GMD file: errno = %d";
- error = HA_ADMIN_INVALID;
- errornum = errno;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- if (my_copy(fn_format(src_path, table->path,"", ha_gemini_ext, 4),
- dst_path,
- MYF(MY_WME | MY_HOLD_ORIGINAL_MODES )) )
- {
- errmsg = "Failed copying .GMD file: errno = %d";
- error= HA_ADMIN_FAILED;
- errornum = errno;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
-#ifdef GEMINI_BACKUP_IDX
- dsmArea_t indexArea = 0;
-
- rc = dsmObjectInfo(pcontext, tableNumber, DSMOBJECT_MIXINDEX, &indexArea,
- &objectAttr, &associate, &associateType, &block, &root);
- if (rc)
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed in dsmObjectInfo (.gmi) (Error %d)";
- errornum = rc;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- /* Backup the index file */
- if (!fn_format(dst_path, table_name, backup_dir, ha_gemini_idx_ext, 4 + 64))
- {
- errmsg = "Failed in fn_format() for .GMI file: errno = %d";
- error = HA_ADMIN_INVALID;
- errornum = errno;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- if (my_copy(fn_format(src_path, table->path,"", ha_gemini_idx_ext, 4),
- dst_path,
- MYF(MY_WME | MY_HOLD_ORIGINAL_MODES )) )
- {
- errmsg = "Failed copying .GMI file: errno = %d";
- error= HA_ADMIN_FAILED;
- errornum = errno;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-#endif /* #ifdef GEMINI_BACKUP_IDX */
-
- return HA_ADMIN_OK;
-
- err:
- {
-#if 0
- /* mi_check_print_error is in ha_myisam.cc, so none of the informative
- ** error messages above is currently being printed
- */
- MI_CHECK param;
- myisamchk_init(&param);
- param.thd = thd;
- param.op_name = (char*)"backup";
- param.table_name = table->table_name;
- param.testflag = 0;
- mi_check_print_error(&param,errmsg, errornum);
-#endif
- return error;
- }
-}
-
-
-int ha_gemini::optimize(THD* thd, HA_CHECK_OPT *check_opt)
-{
- return HA_ADMIN_ALREADY_DONE;
-}
-
-
-ha_rows ha_gemini::records_in_range(int keynr,
- 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)
-{
- int error;
- int componentLen;
- float pctInrange;
- ha_rows rows = 5;
-
- DBUG_ENTER("records_in_range");
-
- error = index_init(keynr);
- if(error)
- DBUG_RETURN(rows);
-
- pbracketBase->index = (short)pindexNumbers[keynr];
- pbracketBase->keycomps = 1;
-
- if(start_key)
- {
- error = pack_key(keynr, pbracketBase, start_key, start_key_len);
- if(start_search_flag == HA_READ_AFTER_KEY)
- {
- /* A greater than operation */
- error = gemKeyAddLow(pbracketBase->keystr + pbracketBase->keyLen,
- &componentLen);
- pbracketBase->keyLen += componentLen;
- }
- }
- else
- {
- error = gemKeyLow(pbracketBase->keystr, &componentLen,
- pbracketBase->index);
- pbracketBase->keyLen = componentLen;
-
- }
- pbracketBase->keyLen -= FULLKEYHDRSZ;
-
- if(end_key)
- {
- error = pack_key(keynr, pbracketLimit, end_key, end_key_len);
- if(!error && end_search_flag == HA_READ_AFTER_KEY)
- {
- error = gemKeyAddHigh(pbracketLimit->keystr + pbracketLimit->keyLen,
- &componentLen);
- pbracketLimit->keyLen += componentLen;
- }
- }
- else
- {
- error = gemKeyHigh(pbracketLimit->keystr,&componentLen,
- pbracketLimit->index);
- pbracketLimit->keyLen = componentLen;
- }
-
- pbracketLimit->keyLen -= FULLKEYHDRSZ;
- error = dsmIndexRowsInRange((dsmContext_t *)current_thd->gemini.context,
- pbracketBase,pbracketLimit,
- tableNumber,
- &pctInrange);
- if(pctInrange >= 1)
- rows = (ha_rows)pctInrange;
- else
- {
- rows = (ha_rows)(records * pctInrange);
- if(!rows && pctInrange > 0)
- rows = 1;
- }
- index_end();
-
- DBUG_RETURN(rows);
-}
-
-
-/*
- Pack a row for storage. If the row is of fixed length, just store the
- row 'as is'.
- If not, we will generate a packed row suitable for storage.
- This will only fail if we don't have enough memory to pack the row, which;
- may only happen in rows with blobs, as the default row length is
- pre-allocated.
-*/
-int ha_gemini::pack_row(byte **pprow, int *ppackedLength, const byte *record,
- bool update)
-{
- THD *thd = current_thd;
- dsmContext_t *pcontext = (dsmContext_t *)thd->gemini.context;
- gemBlobDesc_t *pBlobDesc = pBlobDescs;
-
- if (fixed_length_row)
- {
- *pprow = (byte *)record;
- *ppackedLength=(int)table->reclength;
- return 0;
- }
- /* Copy null bits */
- memcpy(rec_buff, record, table->null_bytes);
- byte *ptr=rec_buff + table->null_bytes;
-
- for (Field **field=table->field ; *field ; field++)
- {
-#ifdef GEMINI_TINYBLOB_IN_ROW
- /* Tiny blobs (255 bytes or less) are stored in the row; larger
- ** blobs are stored in a separate storage object (see ha_gemini::create).
- */
- if ((*field)->type() == FIELD_TYPE_BLOB &&
- ((Field_blob*)*field)->blobtype() != FIELD_TYPE_TINY_BLOB)
-#else
- if ((*field)->type() == FIELD_TYPE_BLOB)
-#endif
- {
- dsmBlob_t gemBlob;
- char *blobptr;
-
- gemBlob.areaType = DSMOBJECT_BLOB;
- gemBlob.blobObjNo = tableNumber;
- gemBlob.blobId = 0;
- gemBlob.totLength = gemBlob.segLength =
- ((Field_blob*)*field)->get_length((char*)record + (*field)->offset());
- ((Field_blob*)*field)->get_ptr((char**) &blobptr);
- gemBlob.pBuffer = (dsmBuffer_t *)blobptr;
- gemBlob.blobContext.blobOffset = 0;
- if (gemBlob.totLength)
- {
- dsmBlobStart(pcontext, &gemBlob);
- if (update && pBlobDesc->blobId)
- {
- gemBlob.blobId = pBlobDesc->blobId;
- dsmBlobUpdate(pcontext, &gemBlob, NULL);
- }
- else
- {
- dsmBlobPut(pcontext, &gemBlob, NULL);
- }
- dsmBlobEnd(pcontext, &gemBlob);
- }
- ptr = (byte*)((Field_blob*)*field)->pack_id((char*) ptr,
- (char*)record + (*field)->offset(), (longlong)gemBlob.blobId);
-
- pBlobDesc++;
- }
- else
- {
- ptr=(byte*) (*field)->pack((char*) ptr, (char*)record + (*field)->offset());
- }
- }
-
- *pprow=rec_buff;
- *ppackedLength= (ptr - rec_buff);
- return 0;
-}
-
-int ha_gemini::unpack_row(char *record, char *prow)
-{
- THD *thd = current_thd;
- dsmContext_t *pcontext = (dsmContext_t *)thd->gemini.context;
- gemBlobDesc_t *pBlobDesc = pBlobDescs;
-
- if (fixed_length_row)
- {
- /* If the table is a VST, the row is in Gemini internal format.
- ** Convert the fields to MySQL format.
- */
- if (RM_IS_VST(tableNumber))
- {
- int i = 2; /* VST fields are numbered sequentially starting at 2 */
- long longValue;
- char *fld;
- unsigned long unknown;
-
- for (Field **field = table->field; *field; field++, i++)
- {
- switch ((*field)->type())
- {
- case FIELD_TYPE_LONG:
- case FIELD_TYPE_TINY:
- case FIELD_TYPE_SHORT:
- case FIELD_TYPE_TIMESTAMP:
- case FIELD_TYPE_LONGLONG:
- case FIELD_TYPE_INT24:
- case FIELD_TYPE_DATE:
- case FIELD_TYPE_TIME:
- case FIELD_TYPE_DATETIME:
- case FIELD_TYPE_YEAR:
- case FIELD_TYPE_NEWDATE:
- case FIELD_TYPE_ENUM:
- case FIELD_TYPE_SET:
- recGetLONG((dsmText_t *)prow, i, 0, &longValue, &unknown);
- if (unknown)
- {
- (*field)->set_null();
- }
- else
- {
- (*field)->set_notnull();
- (*field)->store((longlong)longValue);
- }
- break;
-
- case FIELD_TYPE_DECIMAL:
- case FIELD_TYPE_DOUBLE:
- case FIELD_TYPE_TINY_BLOB:
- case FIELD_TYPE_MEDIUM_BLOB:
- case FIELD_TYPE_LONG_BLOB:
- case FIELD_TYPE_BLOB:
- case FIELD_TYPE_VAR_STRING:
- break;
-
- case FIELD_TYPE_STRING:
- svcByteString_t stringFld;
-
- fld = (char *)my_malloc((*field)->field_length, MYF(MY_WME));
- stringFld.pbyte = (TEXT *)fld;
- stringFld.size = (*field)->field_length;
- recGetBYTES((dsmText_t *)prow, i, 0, &stringFld, &unknown);
- if (unknown)
- {
- (*field)->set_null();
- }
- else
- {
- (*field)->set_notnull();
- (*field)->store(fld, (*field)->field_length);
- }
- my_free(fld, MYF(MY_ALLOW_ZERO_PTR));
- break;
-
- default:
- break;
- }
- }
- }
- else
- {
- memcpy(record,(char*) prow,table->reclength);
- }
- }
- else
- {
- /* Copy null bits */
- const char *ptr= (const char*) prow;
- memcpy(record, ptr, table->null_bytes);
- ptr+=table->null_bytes;
-
- for (Field **field=table->field ; *field ; field++)
- {
-#ifdef GEMINI_TINYBLOB_IN_ROW
- /* Tiny blobs (255 bytes or less) are stored in the row; larger
- ** blobs are stored in a separate storage object (see ha_gemini::create).
- */
- if ((*field)->type() == FIELD_TYPE_BLOB &&
- ((Field_blob*)*field)->blobtype() != FIELD_TYPE_TINY_BLOB)
-#else
- if ((*field)->type() == FIELD_TYPE_BLOB)
-#endif
- {
- dsmBlob_t gemBlob;
-
- gemBlob.areaType = DSMOBJECT_BLOB;
- gemBlob.blobObjNo = tableNumber;
- gemBlob.blobId = (dsmBlobId_t)(((Field_blob*)*field)->get_id(ptr));
- if (gemBlob.blobId)
- {
- gemBlob.totLength =
- gemBlob.segLength = ((Field_blob*)*field)->get_length(ptr);
- /* Allocate memory to store the blob. This memory is freed
- ** the next time unpack_row is called for this table.
- */
- gemBlob.pBuffer = (dsmBuffer_t *)my_malloc(gemBlob.totLength,
- MYF(0));
- if (!gemBlob.pBuffer)
- {
- return HA_ERR_OUT_OF_MEM;
- }
- gemBlob.blobContext.blobOffset = 0;
- dsmBlobStart(pcontext, &gemBlob);
- dsmBlobGet(pcontext, &gemBlob, NULL);
- dsmBlobEnd(pcontext, &gemBlob);
- }
- else
- {
- gemBlob.pBuffer = 0;
- }
- ptr = ((Field_blob*)*field)->unpack_id(record + (*field)->offset(),
- ptr, (char *)gemBlob.pBuffer);
- pBlobDesc->blobId = gemBlob.blobId;
- my_free((char*)pBlobDesc->pBlob, MYF(MY_ALLOW_ZERO_PTR));
- pBlobDesc->pBlob = gemBlob.pBuffer;
- pBlobDesc++;
- }
- else
- {
- ptr= (*field)->unpack(record + (*field)->offset(), ptr);
- }
- }
- }
-
- return 0;
-}
-
-int ha_gemini::key_cmp(uint keynr, const byte * old_row,
- const byte * new_row, bool updateStats)
-{
- KEY_PART_INFO *key_part=table->key_info[keynr].key_part;
- KEY_PART_INFO *end=key_part+table->key_info[keynr].key_parts;
-
- for ( uint i = 0 ; key_part != end ; key_part++, i++)
- {
- 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))
- {
- if(updateStats)
- table->key_info[keynr].rec_per_key[i]++;
- return 1;
- }
- else if((old_row[key_part->null_offset] & key_part->null_bit) &&
- (new_row[key_part->null_offset] & key_part->null_bit))
- /* Both are null */
- continue;
- }
- if (key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH))
- {
- if (key_part->field->cmp_binary((char*)(old_row + key_part->offset),
- (char*)(new_row + key_part->offset),
- (ulong) key_part->length))
- {
- if(updateStats)
- table->key_info[keynr].rec_per_key[i]++;
- return 1;
- }
- }
- else
- {
- if (memcmp(old_row+key_part->offset, new_row+key_part->offset,
- key_part->length))
- {
- /* Check for special case of -0 which causes table check
- to find an invalid key when comparing the the index
- value of 0 to the -0 stored in the row */
- if(key_part->field->type() == FIELD_TYPE_DECIMAL)
- {
- double fieldValue;
- char *ptr = key_part->field->ptr;
-
- key_part->field->ptr = (char *)old_row + key_part->offset;
- fieldValue = key_part->field->val_real();
- if(fieldValue == 0)
- {
- key_part->field->ptr = (char *)new_row + key_part->offset;
- fieldValue = key_part->field->val_real();
- if(fieldValue == 0)
- {
- key_part->field->ptr = ptr;
- continue;
- }
- }
- key_part->field->ptr = ptr;
- }
- if(updateStats)
- {
- table->key_info[keynr].rec_per_key[i]++;
- }
- return 1;
- }
- }
- }
- return 0;
-}
-
-int gemini_parse_table_name(const char *fullname, char *dbname, char *tabname)
-{
- char *namestart;
- char *nameend;
-
- /* separate out the name of the table and the database
- */
- namestart = (char *)strchr(fullname + start_of_name, '/');
- if (!namestart)
- {
- /* if on Windows, slashes go the other way */
- namestart = (char *)strchr(fullname + start_of_name, '\\');
- }
- nameend = (char *)strchr(fullname + start_of_name, '.');
- /* sometimes fullname has an extension, sometimes it doesn't */
- if (!nameend)
- {
- nameend = (char *)fullname + strlen(fullname);
- }
- strncpy(dbname, fullname + start_of_name,
- (namestart - fullname) - start_of_name);
- dbname[(namestart - fullname) - start_of_name] = '\0';
- strncpy(tabname, namestart + 1, (nameend - namestart) - 1);
- tabname[nameend - namestart - 1] = '\0';
-
- return 0;
-}
-
-/* PROGRAM: gemini_is_vst - if the name is the name of a VST, return
- * its number
- *
- * RETURNS: Table number if a match is found
- * 0 if not a VST
- */
-int
-gemini_is_vst(const char *pname) /* IN the name */
-{
- int tablenum = 0;
-
- for (int i = 0; i < vstnumfils; i++)
- {
- if (strcmp(pname, vstfil[i].filename) == 0)
- {
- tablenum = vstfil[i].filnum;
- break;
- }
- }
-
- return tablenum;
-}
-
-static void print_msg(THD *thd, const char *table_name, const char *op_name,
- const char *msg_type, const char *fmt, ...)
-{
- String* packet = &thd->packet;
- packet->length(0);
- char msgbuf[256];
- msgbuf[0] = 0;
- va_list args;
- va_start(args,fmt);
-
- my_vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
- msgbuf[sizeof(msgbuf) - 1] = 0; // healthy paranoia
-
- DBUG_PRINT(msg_type,("message: %s",msgbuf));
-
- net_store_data(packet, table_name);
- net_store_data(packet, op_name);
- net_store_data(packet, msg_type);
- net_store_data(packet, msgbuf);
- if (my_net_write(&thd->net, (char*)thd->packet.ptr(),
- thd->packet.length()))
- thd->killed=1;
-}
-
-/* Load shared area with rows per key statistics */
-void
-ha_gemini::get_index_stats(THD *thd)
-{
- dsmStatus_t rc = 0;
- ha_rows *rec_per_key = share->rec_per_key;
-
- for(uint i = 0; i < table->keys && !rc; i++)
- {
- for (uint j = 0; j < table->key_info[i].key_parts && !rc;j++)
- {
- LONG64 rows_per_key;
- rc = dsmIndexStatsGet((dsmContext_t *)thd->gemini.context,
- tableNumber, pindexNumbers[i],(int)j,
- &rows_per_key);
- if (rc)
- {
- gemini_msg((dsmContext_t *)thd->gemini.context,
- "Index Statistics faild for table %d index %d, error %d",
- tableNumber, pindexNumbers[i], rc);
- }
- *rec_per_key = (ha_rows)rows_per_key;
- rec_per_key++;
- }
- }
- return;
-}
-
-/****************************************************************************
- Handling the shared GEM_SHARE structure that is needed to provide
- a global in memory storage location of the rec_per_key stats used
- by the optimizer.
-****************************************************************************/
-
-static byte* gem_get_key(GEM_SHARE *share,uint *length,
- my_bool not_used __attribute__((unused)))
-{
- *length=share->table_name_length;
- return (byte*) share->table_name;
-}
-
-static GEM_SHARE *get_share(const char *table_name, TABLE *table)
-{
- GEM_SHARE *share;
-
- pthread_mutex_lock(&gem_mutex);
- uint length=(uint) strlen(table_name);
- if (!(share=(GEM_SHARE*) hash_search(&gem_open_tables, (byte*) table_name,
- length)))
- {
- ha_rows *rec_per_key;
- char *tmp_name;
-
- if ((share=(GEM_SHARE *)
- my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
- &share, sizeof(*share),
- &rec_per_key, table->key_parts * sizeof(ha_rows),
- &tmp_name, length+1,
- NullS)))
- {
- share->rec_per_key = rec_per_key;
- share->table_name = tmp_name;
- share->table_name_length=length;
- strcpy(share->table_name,table_name);
- if (hash_insert(&gem_open_tables, (byte*) share))
- {
- pthread_mutex_unlock(&gem_mutex);
- my_free((gptr) share,0);
- return 0;
- }
- thr_lock_init(&share->lock);
- pthread_mutex_init(&share->mutex,NULL);
- }
- }
- pthread_mutex_unlock(&gem_mutex);
- return share;
-}
-
-static int free_share(GEM_SHARE *share, bool mutex_is_locked)
-{
- pthread_mutex_lock(&gem_mutex);
- if (mutex_is_locked)
- pthread_mutex_unlock(&share->mutex);
- if (!--share->use_count)
- {
- hash_delete(&gem_open_tables, (byte*) share);
- thr_lock_delete(&share->lock);
- pthread_mutex_destroy(&share->mutex);
- my_free((gptr) share, MYF(0));
- }
- pthread_mutex_unlock(&gem_mutex);
- return 0;
-}
-
-static void gemini_lock_table_overflow_error(dsmContext_t *pcontext)
-{
- gemini_msg(pcontext, "The total number of locks exceeds the lock table size");
- gemini_msg(pcontext, "Either increase gemini_lock_table_size or use a");
- gemini_msg(pcontext, "different transaction isolation level");
-}
-
-#endif /* HAVE_GEMINI_DB */
diff --git a/sql/ha_gemini.h b/sql/ha_gemini.h
deleted file mode 100644
index 96c0cdd4241..00000000000
--- a/sql/ha_gemini.h
+++ /dev/null
@@ -1,208 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & NuSphere Corporation
-
- This program is free software; 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
-
-#include "gem_global.h"
-#include "dstd.h"
-#include "dsmpub.h"
-
-/* class for the the gemini handler */
-
-enum enum_key_string_options{KEY_CREATE,KEY_DELETE,KEY_CHECK};
-typedef struct st_gemini_share {
- ha_rows *rec_per_key;
- THR_LOCK lock;
- pthread_mutex_t mutex;
- char *table_name;
- uint table_name_length,use_count;
-} GEM_SHARE;
-
-typedef struct gemBlobDesc
-{
- dsmBlobId_t blobId;
- dsmBuffer_t *pBlob;
-} gemBlobDesc_t;
-
-class ha_gemini: public handler
-{
- /* define file as an int for now until we have a real file struct */
- int file;
- uint int_option_flag;
- int tableNumber;
- dsmIndex_t *pindexNumbers; // dsm object numbers for the indexes on this table
- dsmRecid_t lastRowid;
- uint last_dup_key;
- bool fixed_length_row, key_read, using_ignore;
- byte *rec_buff;
- dsmKey_t *pbracketBase;
- dsmKey_t *pbracketLimit;
- dsmKey_t *pfoundKey;
- dsmMask_t tableStatus; // Crashed/repair status
- gemBlobDesc_t *pBlobDescs;
-
- int index_open(char *tableName);
- int pack_row(byte **prow, int *ppackedLength, const byte *record,
- bool update);
- int unpack_row(char *record, char *prow);
- int findRow(THD *thd, dsmMask_t findMode, byte *buf);
- int fetch_row(void *gemini_context, const byte *buf);
- int handleIndexEntries(const byte * record, dsmRecid_t recid,
- enum_key_string_options option);
-
- int handleIndexEntry(const byte * record, dsmRecid_t recid,
- enum_key_string_options option,uint keynr);
-
- int createKeyString(const byte * record, KEY *pkeyinfo,
- unsigned char *pkeyBuf, int bufSize,
- int *pkeyStringLen, short geminiIndexNumber,
- bool *thereIsAnull);
- int fullCheck(THD *thd,byte *buf);
-
- int pack_key( uint keynr, dsmKey_t *pkey,
- const byte *key_ptr, uint key_length);
-
- void unpack_key(char *record, dsmKey_t *key, uint index);
-
- int key_cmp(uint keynr, const byte * old_row,
- const byte * new_row, bool updateStats);
-
- int saveKeyStats(THD *thd);
- void get_index_stats(THD *thd);
-
- short cursorId; /* cursorId of active index cursor if any */
- dsmMask_t lockMode; /* Shared or exclusive */
-
- /* FIXFIX Don't know why we need this because I don't know what
- store_lock method does but we core dump without this */
- THR_LOCK_DATA lock;
- GEM_SHARE *share;
-
- public:
- ha_gemini(TABLE *table): handler(table), file(0),
- int_option_flag(HA_READ_NEXT | HA_READ_PREV |
- HA_REC_NOT_IN_SEQ |
- HA_KEYPOS_TO_RNDPOS | HA_READ_ORDER | HA_LASTKEY_ORDER |
- HA_LONGLONG_KEYS | HA_NULL_KEY | HA_HAVE_KEY_READ_ONLY |
- HA_BLOB_KEY |
- HA_NO_TEMP_TABLES | HA_NO_FULLTEXT_KEY |
- /*HA_NOT_EXACT_COUNT | */
- /*HA_KEY_READ_WRONG_STR |*/ HA_DROP_BEFORE_CREATE),
- pbracketBase(0),pbracketLimit(0),pfoundKey(0),
- cursorId(0)
- {
- }
- ~ha_gemini() {}
- const char *table_type() const { return "Gemini"; }
- const char **bas_ext() const;
- ulong option_flag() const { return int_option_flag; }
- uint max_record_length() const { return MAXRECSZ; }
- uint max_keys() const { return MAX_KEY-1; }
- uint max_key_parts() const { return MAX_REF_PARTS; }
- uint max_key_length() const { return MAXKEYSZ / 2; }
- bool fast_key_read() { return 1;}
- bool has_transactions() { return 1;}
-
- int open(const char *name, int mode, uint test_if_locked);
- int close(void);
- double scan_time();
- 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 index);
- int index_end();
- int index_read(byte * buf, const byte * key,
- uint key_len, 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);
- int index_next(byte * buf);
- int index_next_same(byte * buf, const byte *key, uint keylen);
- int index_prev(byte * buf);
- int index_first(byte * buf);
- int index_last(byte * buf);
- int rnd_init(bool scan=1);
- int rnd_end();
- 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 reset(void);
- int analyze(THD* thd, HA_CHECK_OPT* check_opt);
- int check(THD* thd, HA_CHECK_OPT* check_opt);
- int repair(THD* thd, HA_CHECK_OPT* check_opt);
- int restore(THD* thd, HA_CHECK_OPT* check_opt);
- int backup(THD* thd, HA_CHECK_OPT* check_opt);
- int optimize(THD* thd, HA_CHECK_OPT* check_opt);
- int external_lock(THD *thd, int lock_type);
- virtual longlong get_auto_increment();
- void position(byte *record);
- ha_rows records_in_range(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);
- void update_create_info(HA_CREATE_INFO *create_info);
- int create(const char *name, register TABLE *form,
- HA_CREATE_INFO *create_info);
- int delete_table(const char *name);
- int rename_table(const char* from, const char* to);
- THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
- enum thr_lock_type lock_type);
-};
-
-#define GEMOPT_FLUSH_LOG 0x00000001
-#define GEMOPT_UNBUFFERED_IO 0x00000002
-
-#define GEMINI_RECOVERY_FULL 0x00000001
-#define GEMINI_RECOVERY_NONE 0x00000002
-#define GEMINI_RECOVERY_FORCE 0x00000004
-
-#define GEM_OPTID_SPIN_RETRIES 1
-
-extern bool gemini_skip;
-extern SHOW_COMP_OPTION have_gemini;
-extern long gemini_options;
-extern long gemini_buffer_cache;
-extern long gemini_io_threads;
-extern long gemini_log_cluster_size;
-extern long gemini_locktablesize;
-extern long gemini_lock_wait_timeout;
-extern long gemini_spin_retries;
-extern long gemini_connection_limit;
-extern char *gemini_basedir;
-extern TYPELIB gemini_recovery_typelib;
-extern ulong gemini_recovery_options;
-
-bool gemini_init(void);
-bool gemini_end(void);
-bool gemini_flush_logs(void);
-int gemini_commit(THD *thd);
-int gemini_rollback(THD *thd);
-int gemini_recovery_logging(THD *thd, bool on);
-void gemini_disconnect(THD *thd);
-int gemini_rollback_to_savepoint(THD *thd);
-int gemini_parse_table_name(const char *fullname, char *dbname, char *tabname);
-int gemini_is_vst(const char *pname);
-int gemini_set_option_long(int optid, long optval);
-
-const int gemini_blocksize = BLKSIZE;
-const int gemini_recbits = DEFAULT_RECBITS;
-
-extern "C" void uttrace(void);
diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc
index 13dccc2bf64..5f482bca1e8 100644
--- a/sql/ha_heap.cc
+++ b/sql/ha_heap.cc
@@ -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 */
@@ -33,7 +33,7 @@ const char **ha_heap::bas_ext() const
int ha_heap::open(const char *name, int mode, uint test_if_locked)
{
- uint key,part,parts,mem_per_row=0;
+ uint key,parts,mem_per_row=0;
ulong max_rows;
HP_KEYDEF *keydef;
HP_KEYSEG *seg;
@@ -48,24 +48,38 @@ int ha_heap::open(const char *name, int mode, uint test_if_locked)
for (key=0 ; key < table->keys ; key++)
{
KEY *pos=table->key_info+key;
+ KEY_PART_INFO *key_part= pos->key_part;
+ KEY_PART_INFO *key_part_end= key_part+pos->key_parts;
+
mem_per_row += (pos->key_length + (sizeof(char*) * 2));
-
+
keydef[key].keysegs=(uint) pos->key_parts;
- keydef[key].flag = (pos->flags & HA_NOSAME);
+ keydef[key].flag = (pos->flags & (HA_NOSAME | HA_NULL_ARE_EQUAL));
keydef[key].seg=seg;
-
- for (part=0 ; part < pos->key_parts ; part++)
+
+ for (; key_part != key_part_end ; key_part++, seg++)
{
- uint flag=pos->key_part[part].key_type;
+ uint flag=key_part->key_type;
+ Field *field=key_part->field;
if (!f_is_packed(flag) &&
f_packtype(flag) == (int) FIELD_TYPE_DECIMAL &&
!(flag & FIELDFLAG_BINARY))
seg->type= (int) HA_KEYTYPE_TEXT;
else
seg->type= (int) HA_KEYTYPE_BINARY;
- seg->start=(uint) pos->key_part[part].offset;
- seg->length=(uint) pos->key_part[part].length;
- seg++;
+ seg->start=(uint) key_part->offset;
+ seg->length=(uint) key_part->length;
+ if (field->null_ptr)
+ {
+ seg->null_bit=field->null_bit;
+ seg->null_pos= (uint) (field->null_ptr-
+ (uchar*) table->record[0]);
+ }
+ else
+ {
+ seg->null_bit=0;
+ seg->null_pos=0;
+ }
}
}
mem_per_row += MY_ALIGN(table->reclength+1, sizeof(char*));
@@ -77,7 +91,8 @@ int ha_heap::open(const char *name, int mode, uint test_if_locked)
table->max_rows : max_rows),
table->min_rows);
my_free((gptr) keydef,MYF(0));
- info(HA_STATUS_NO_LOCK | HA_STATUS_CONST | HA_STATUS_VARIABLE);
+ if (file)
+ info(HA_STATUS_NO_LOCK | HA_STATUS_CONST | HA_STATUS_VARIABLE);
ref_length=sizeof(HEAP_PTR);
return (!file ? errno : 0);
}
@@ -147,7 +162,7 @@ int ha_heap::index_prev(byte * buf)
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
-
+
int ha_heap::index_first(byte * buf)
{
statistic_increment(ha_read_first_count,&LOCK_status);
@@ -227,7 +242,7 @@ int ha_heap::delete_all_rows()
int ha_heap::external_lock(THD *thd, int lock_type)
{
return 0; // No external locking
-}
+}
THR_LOCK_DATA **ha_heap::store_lock(THD *thd,
THR_LOCK_DATA **to,
@@ -247,7 +262,7 @@ THR_LOCK_DATA **ha_heap::store_lock(THD *thd,
int ha_heap::delete_table(const char *name)
{
- int error=heap_delete_all(name);
+ int error=heap_delete_table(name);
return error == ENOENT ? 0 : error;
}
@@ -272,7 +287,6 @@ ha_rows ha_heap::records_in_range(int inx,
return 10; // Good guess
}
-/* We can just delete the heap on creation */
int ha_heap::create(const char *name, TABLE *form, HA_CREATE_INFO *create_info)
diff --git a/sql/ha_heap.h b/sql/ha_heap.h
index 6b7e9c6c626..c8f29dea53c 100644
--- a/sql/ha_heap.h
+++ b/sql/ha_heap.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 */
@@ -31,11 +31,12 @@ class ha_heap: public handler
ha_heap(TABLE *table): handler(table), file(0) {}
~ha_heap() {}
const char *table_type() const { return "HEAP"; }
+ const char *index_type(uint key_number) { return "HASH"; }
const char **bas_ext() const;
ulong option_flag() const
{ return (HA_READ_RND_SAME | HA_NO_INDEX | HA_ONLY_WHOLE_INDEX |
HA_WRONG_ASCII_ORDER | HA_KEYPOS_TO_RNDPOS | HA_NO_BLOBS |
- HA_REC_NOT_IN_SEQ | HA_NO_FULLTEXT_KEY); }
+ HA_NULL_KEY | HA_REC_NOT_IN_SEQ | HA_NOT_READ_PREFIX_LAST); }
uint max_record_length() const { return HA_MAX_REC_LENGTH; }
uint max_keys() const { return MAX_KEY; }
uint max_key_parts() const { return MAX_REF_PARTS; }
diff --git a/sql/ha_innobase.cc b/sql/ha_innodb.cc
index 9159ef3f1c1..c4b71113c56 100644
--- a/sql/ha_innobase.cc
+++ b/sql/ha_innodb.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & InnoDB Oy
+/* Copyright (C) 2000 MySQL AB & InnoDB 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,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 */
-/* This file defines the InnoDB handler: the interface between MySQL and
-InnoDB */
-
+/*
+ This file defines the InnoDB handler: the interface between MySQL and InnoDB */
+
/* TODO list for the InnoDB handler:
- Ask Monty if strings of different languages can exist in the same
database. Answer: in near future yes, but not yet.
*/
-
+
#ifdef __GNUC__
#pragma implementation // gcc: Class implementation
#endif
@@ -35,7 +35,7 @@ InnoDB */
#define MAX_ULONG_BIT ((ulong) 1 << (sizeof(ulong)*8-1))
-#include "ha_innobase.h"
+#include "ha_innodb.h"
/* We must declare this here because we undef SAFE_MUTEX below */
pthread_mutex_t innobase_mutex;
@@ -87,11 +87,10 @@ long innobase_mirrored_log_groups, innobase_log_files_in_group,
/* The default values for the following char* start-up parameters
are determined in innobase_init below: */
-
-/* innobase_data_file_path=ibdata:15,idata2:1,... */
-
+
+ /* innobase_data_file_path=ibdata:15,idata2:1,... */
+
char* innobase_data_home_dir = NULL;
-char* innobase_data_file_path = NULL;
char* innobase_log_group_home_dir = NULL;
char* innobase_log_arch_dir = NULL;
char* innobase_unix_file_flush_method = NULL;
@@ -104,6 +103,14 @@ my_bool innobase_log_archive = FALSE;
my_bool innobase_use_native_aio = FALSE;
my_bool innobase_fast_shutdown = TRUE;
+/*
+ Set default InnoDB size to 64M, to let users use InnoDB without having
+ to specify any startup options.
+*/
+
+char *innobase_data_file_path= (char*) "ibdata1:64M";
+char *internal_innobase_data_file_path=0;
+
/* The following counter is used to convey information to InnoDB
about server activity: in selects it is not sensible to call
srv_active_wake_master_thread after each fetch or search, we only do
@@ -234,7 +241,7 @@ convert_error_code_to_mysql(
return(HA_ERR_TO_BIG_ROW);
} else {
- dbug_assert(0);
+ DBUG_ASSERT(0);
return(-1); // Unknown error
}
@@ -274,7 +281,7 @@ innobase_mysql_print_thd(
}
if (thd->query) {
- printf("\n%.100s", thd->query);
+ printf("\n%-.100s", thd->query);
}
printf("\n");
@@ -297,7 +304,7 @@ check_trx_exists(
trx = (trx_t*) thd->transaction.all.innobase_tid;
if (trx == NULL) {
- dbug_assert(thd != NULL);
+ DBUG_ASSERT(thd != NULL);
trx = trx_allocate_for_mysql();
trx->mysql_thd = thd;
@@ -353,12 +360,27 @@ innobase_init(void)
/*===============*/
/* out: TRUE if error */
{
- static char current_dir[3];
int err;
bool ret;
-
+ char current_lib[3], *default_path;
+
DBUG_ENTER("innobase_init");
-
+
+ /*
+ When using the embedded server, the datadirectory is not
+ in the current directory.
+ */
+ if (mysql_embedded)
+ default_path=mysql_real_data_home;
+ else
+ {
+ /* It's better to use current lib, to keep path's short */
+ current_lib[0] = FN_CURLIB;
+ current_lib[1] = FN_LIBCHAR;
+ current_lib[2] = 0;
+ default_path=current_lib;
+ }
+
if (specialflag & SPECIAL_NO_PRIOR) {
srv_set_thread_priorities = FALSE;
} else {
@@ -366,34 +388,19 @@ innobase_init(void)
srv_query_thread_priority = QUERY_PRIOR;
}
- /* Use current_dir if no paths are set */
- current_dir[0] = FN_CURLIB;
- current_dir[1] = FN_LIBCHAR;
- current_dir[2] = 0;
-
- /* Set InnoDB initialization parameters according to the values
- read from MySQL .cnf file */
-
- if (!innobase_data_file_path) {
- fprintf(stderr,
- "Cannot initialize InnoDB as 'innodb_data_file_path' is not set.\n"
- "If you do not want to use transactional InnoDB tables, add a line\n"
- "skip-innodb\n"
- "to the [mysqld] section of init parameters in your my.cnf\n"
- "or my.ini. If you want to use InnoDB tables, add for example,\n"
- "innodb_data_file_path = ibdata1:30M:autoextend\n"
- "But to get good performance you should adjust for your hardware\n"
- "the InnoDB startup options listed in section 2 at\n"
- "http://www.innodb.com/ibman.html\n");
+ /*
+ Set InnoDB initialization parameters according to the values
+ read from MySQL .cnf file
+ */
- innodb_skip=1;
- DBUG_RETURN(FALSE); /* Continue without InnoDB */
- }
+ // Make a copy of innobase_data_file_path to not modify the original
+ internal_innobase_data_file_path=my_strdup(innobase_data_file_path,
+ MYF(MY_WME));
srv_data_home = (innobase_data_home_dir ? innobase_data_home_dir :
- current_dir);
+ default_path);
srv_arch_dir = (innobase_log_arch_dir ? innobase_log_arch_dir :
- current_dir);
+ default_path);
ret = (bool)
srv_parse_data_file_paths_and_sizes(innobase_data_file_path,
@@ -404,14 +411,12 @@ innobase_init(void)
&srv_auto_extend_last_data_file,
&srv_last_file_size_max);
if (ret == FALSE) {
- fprintf(stderr,
- "InnoDB: syntax error in innodb_data_file_path\n");
- DBUG_RETURN(TRUE);
+ sql_print_error("InnoDB: syntax error in innodb_data_file_path");
+ DBUG_RETURN(TRUE);
}
- if (!innobase_log_group_home_dir) {
- innobase_log_group_home_dir = current_dir;
- }
+ if (!innobase_log_group_home_dir)
+ innobase_log_group_home_dir= default_path;
ret = (bool)
srv_parse_log_group_home_dirs(innobase_log_group_home_dir,
@@ -424,7 +429,6 @@ innobase_init(void)
DBUG_RETURN(TRUE);
}
-
srv_unix_file_flush_method_str = (innobase_unix_file_flush_method ?
innobase_unix_file_flush_method :
(char*)"fdatasync");
@@ -450,12 +454,13 @@ innobase_init(void)
srv_fast_shutdown = (ibool) innobase_fast_shutdown;
+ srv_print_verbose_log = mysql_embedded ? 0 : 1;
if (strcmp(default_charset_info->name, "latin1") == 0) {
/* Store the character ordering table to InnoDB.
For non-latin1 charsets we use the MySQL comparison
functions, and consequently we do not need to know
the ordering internally in InnoDB. */
-
+
memcpy(srv_latin1_ordering,
default_charset_info->sort_order, 256);
}
@@ -487,6 +492,7 @@ innobase_end(void)
err = innobase_shutdown_for_mysql();
hash_free(&innobase_open_tables);
+ my_free(internal_innobase_data_file_path,MYF(MY_ALLOW_ZERO_PTR));
if (err != DB_SUCCESS) {
@@ -553,7 +559,6 @@ innobase_commit(
/* Release possible statement level resources */
innobase_release_stat_resources(trx);
-
trx_mark_sql_stat_end(trx);
#ifndef DBUG_OFF
@@ -714,7 +719,7 @@ normalize_table_name(
name_ptr = ptr + 1;
- dbug_assert(ptr > name);
+ DBUG_ASSERT(ptr > name);
ptr--;
@@ -741,7 +746,7 @@ normalize_table_name(
}
/*********************************************************************
-Creates and opens a handle to a table which already exists in an Innnobase
+Creates and opens a handle to a table which already exists in an Innobase
database. */
int
@@ -793,13 +798,13 @@ ha_innobase::open(
if (NULL == ib_table) {
- fprintf(stderr,
-"InnoDB: Error: cannot find table %s from the internal data dictionary\n"
-"InnoDB: of InnoDB though the .frm file for the table exists. Maybe you\n"
-"InnoDB: have deleted and recreated InnoDB data files but have forgotten\n"
-"InnoDB: to delete the corresponding .frm files of InnoDB tables, or you\n"
-"InnoDB: have moved .frm files to another database?\n",
- norm_name);
+ sql_print_error("InnoDB error:\n\
+Cannot find table %s from the internal data dictionary\n\
+of InnoDB though the .frm file for the table exists. Maybe you\n\
+have deleted and recreated InnoDB data files but have forgotten\n\
+to delete the corresponding .frm files of InnoDB tables, or you\n\
+have moved .frm files to another database?",
+ norm_name);
free_share(share);
my_free((char*) upd_buff, MYF(0));
@@ -827,20 +832,22 @@ ha_innobase::open(
primary_key = 0;
key_used_on_scan = 0;
- /* MySQL allocates the buffer for ref */
+ /*
+ MySQL allocates the buffer for ref.
+ This includes all keys + one byte for each column
+ that may be NULL.
+ The ref_length must be exact as possible as
+ all reference buffers are allocated based on this.
+ */
- ref_length = table->key_info->key_length
- + table->key_info->key_parts + 10;
-
- /* One byte per key field is consumed to the SQL NULL
- info of the field; we add also 10 bytes of safety margin */
+ ref_length = table->key_info->key_length;
} else {
((row_prebuilt_t*)innobase_prebuilt)
->clust_index_was_generated = TRUE;
- ref_length = DATA_ROW_ID_LEN + 10;
-
- dbug_assert(key_used_on_scan == MAX_KEY);
+ ref_length = DATA_ROW_ID_LEN;
+
+ DBUG_ASSERT(key_used_on_scan == MAX_KEY);
}
auto_inc_counter_for_this_stat = 0;
@@ -984,8 +991,8 @@ innobase_mysql_cmp(
enum_field_types mysql_tp;
int ret;
- dbug_assert(a_length != UNIV_SQL_NULL);
- dbug_assert(b_length != UNIV_SQL_NULL);
+ DBUG_ASSERT(a_length != UNIV_SQL_NULL);
+ DBUG_ASSERT(b_length != UNIV_SQL_NULL);
mysql_tp = (enum_field_types) mysql_type;
@@ -1023,11 +1030,11 @@ get_innobase_type_from_mysql_type(
8 bits: this is used in ibuf and also when DATA_NOT_NULL is
ORed to the type */
- dbug_assert((ulint)FIELD_TYPE_STRING < 256);
- dbug_assert((ulint)FIELD_TYPE_VAR_STRING < 256);
- dbug_assert((ulint)FIELD_TYPE_DOUBLE < 256);
- dbug_assert((ulint)FIELD_TYPE_FLOAT < 256);
- dbug_assert((ulint)FIELD_TYPE_DECIMAL < 256);
+ DBUG_ASSERT((ulint)FIELD_TYPE_STRING < 256);
+ DBUG_ASSERT((ulint)FIELD_TYPE_VAR_STRING < 256);
+ DBUG_ASSERT((ulint)FIELD_TYPE_DOUBLE < 256);
+ DBUG_ASSERT((ulint)FIELD_TYPE_FLOAT < 256);
+ DBUG_ASSERT((ulint)FIELD_TYPE_DECIMAL < 256);
switch (field->type()) {
case FIELD_TYPE_VAR_STRING: if (field->flags & BINARY_FLAG) {
@@ -1119,7 +1126,12 @@ ha_innobase::store_key_val_for_row(
buff += key_part->length;
}
- DBUG_RETURN(buff - buff_start);
+ /*
+ We have to zero-fill the buffer to be able to compare two
+ keys to see if they are equal
+ */
+ bzero(buff, (ref_length- (uint) (buff - buff_start)));
+ return ref_length;
}
/******************************************************************
@@ -1154,7 +1166,7 @@ build_template(
if (prebuilt->read_just_key) {
/* MySQL has instructed us that it is enough to
fetch the columns in the key */
-
+
fetch_all_in_key = TRUE;
} else {
/* We are building a temporary table: fetch all
@@ -1163,7 +1175,7 @@ build_template(
we use below to detect required columns does not
reveal that. Actually, it might be enough to
fetch only all in the key also in this case! */
-
+
templ_type = ROW_MYSQL_WHOLE_ROW;
}
}
@@ -1294,7 +1306,7 @@ ha_innobase::write_row(
row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt;
int error;
longlong auto_inc;
-
+
DBUG_ENTER("ha_innobase::write_row");
statistic_increment(ha_write_count, &LOCK_status);
@@ -1316,7 +1328,7 @@ ha_innobase::write_row(
/* Fetch the value the user possibly has set in the
autoincrement field */
-
+
auto_inc = table->next_number_field->val_int();
/* In replication and also otherwise the auto-inc column
@@ -1344,7 +1356,7 @@ ha_innobase::write_row(
auto-inc column */
user_thd->next_insert_id = auto_inc;
}
-
+
if (auto_inc != 0) {
/* This call will calculate the max of the
current value and the value supplied by the user, if
@@ -1363,11 +1375,11 @@ ha_innobase::write_row(
srv_conc_exit_innodb(prebuilt->trx);
if (error != DB_SUCCESS) {
-
+
error = convert_error_code_to_mysql(error);
goto func_exit;
}
-
+
dict_table_autoinc_update(prebuilt->table, auto_inc);
} else {
srv_conc_enter_innodb(prebuilt->trx);
@@ -1377,8 +1389,8 @@ ha_innobase::write_row(
error = row_lock_table_autoinc_for_mysql(
prebuilt);
if (error != DB_SUCCESS) {
- srv_conc_exit_innodb(prebuilt->trx);
-
+ srv_conc_exit_innodb(prebuilt->trx);
+
error = convert_error_code_to_mysql(
error);
goto func_exit;
@@ -1396,7 +1408,7 @@ ha_innobase::write_row(
user_thd->next_insert_id = auto_inc;
}
}
-
+
update_auto_increment();
if (auto_inc == 0) {
@@ -1410,15 +1422,15 @@ ha_innobase::write_row(
srv_conc_exit_innodb(prebuilt->trx);
if (error != DB_SUCCESS) {
-
+
error = convert_error_code_to_mysql(error);
goto func_exit;
}
-
+
dict_table_autoinc_initialize(prebuilt->table,
auto_inc);
}
-
+
/* We have to set sql_stat_start to TRUE because
update_auto_increment may have called a select, and
has reset that flag; row_insert_for_mysql has to
@@ -1878,6 +1890,24 @@ ha_innobase::index_read(
DBUG_RETURN(error);
}
+
+/*
+ The following functions works like index_read, but it find the last
+ row with the current index prefix.
+ This code is disabled until Heikki has verified that InnoDB support the
+ HA_READ_PREFIX_LAST flag and removed the HA_NOT_READ_PREFIX_LAST
+ flag from ha_innodb.h
+*/
+
+int
+ha_innobase::index_read_last(mysql_byte *buf,
+ const mysql_byte *key_ptr,
+ uint key_len)
+{
+ return index_read(buf, key_ptr, key_len, HA_READ_PREFIX_LAST);
+}
+
+
/************************************************************************
Changes the active index of a handle. */
@@ -1889,47 +1919,43 @@ ha_innobase::change_active_index(
index, even if it was internally generated by
InnoDB */
{
- row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
- KEY* key;
+ row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
+ KEY* key;
- statistic_increment(ha_read_key_count, &LOCK_status);
+ statistic_increment(ha_read_key_count, &LOCK_status);
+ DBUG_ENTER("change_active_index");
- DBUG_ENTER("index_read_idx");
+ active_index = keynr;
- active_index = keynr;
+ if (keynr != MAX_KEY && table->keys > 0) {
+ key = table->key_info + active_index;
- if (keynr != MAX_KEY && table->keys > 0) {
- key = table->key_info + active_index;
+ prebuilt->index = dict_table_get_index_noninline(
+ prebuilt->table, key->name);
+ } else {
+ prebuilt->index = dict_table_get_first_index_noninline(
+ prebuilt->table);
+ }
- prebuilt->index = dict_table_get_index_noninline(
- prebuilt->table, key->name);
- } else {
- prebuilt->index = dict_table_get_first_index_noninline(
- prebuilt->table);
- }
+ if (!prebuilt->index) {
+ sql_print_error("Innodb could not find key n:o %u with name %s from dict cache for table %s", keynr, key->name, prebuilt->table->name);
+ return(1);
+ }
- if (!prebuilt->index) {
- fprintf(stderr,
- "InnoDB: Could not find key n:o %u with name %s from dict cache\n"
- "InnoDB: for table %s\n", keynr, key->name, prebuilt->table->name);
+ assert(prebuilt->search_tuple != 0);
- return(1);
- }
-
- assert(prebuilt->search_tuple);
+ dtuple_set_n_fields(prebuilt->search_tuple, prebuilt->index->n_fields);
- dtuple_set_n_fields(prebuilt->search_tuple, prebuilt->index->n_fields);
+ dict_index_copy_types(prebuilt->search_tuple, prebuilt->index,
+ prebuilt->index->n_fields);
- dict_index_copy_types(prebuilt->search_tuple, prebuilt->index,
- prebuilt->index->n_fields);
+ /* Maybe MySQL changes the active index for a handle also
+ during some queries, we do not know: then it is safest to build
+ the template such that all columns will be fetched */
- /* Maybe MySQL changes the active index for a handle also
- during some queries, we do not know: then it is safest to build
- the template such that all columns will be fetched */
+ build_template(prebuilt, user_thd, table, ROW_MYSQL_WHOLE_ROW);
- build_template(prebuilt, user_thd, table, ROW_MYSQL_WHOLE_ROW);
-
- return(0);
+ DBUG_RETURN(0);
}
/**************************************************************************
@@ -1980,7 +2006,7 @@ ha_innobase::general_fetch(
DBUG_ENTER("general_fetch");
srv_conc_enter_innodb(prebuilt->trx);
-
+
ret = row_search_for_mysql((byte*)buf, 0, prebuilt, match_mode,
direction);
srv_conc_exit_innodb(prebuilt->trx);
@@ -2116,7 +2142,7 @@ ha_innobase::rnd_init(
bool scan) /* in: ???????? */
{
int err;
-
+
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
if (prebuilt->clust_index_was_generated) {
@@ -2185,8 +2211,9 @@ ha_innobase::rnd_pos(
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
int error;
uint keynr = active_index;
-
DBUG_ENTER("rnd_pos");
+ DBUG_DUMP("key", (char*) pos, ref_stored_len);
+
statistic_increment(ha_read_rnd_count, &LOCK_status);
if (prebuilt->clust_index_was_generated) {
@@ -2201,11 +2228,15 @@ ha_innobase::rnd_pos(
}
if (error) {
+ DBUG_PRINT("error",("Got error: %ld",error));
DBUG_RETURN(error);
}
-
- error = index_read(buf, pos, ref_stored_len, HA_READ_KEY_EXACT);
+ error = index_read(buf, pos, ref_stored_len, HA_READ_KEY_EXACT);
+ if (error)
+ {
+ DBUG_PRINT("error",("Got error: %ld",error));
+ }
change_active_index(keynr);
DBUG_RETURN(error);
@@ -2240,11 +2271,11 @@ ha_innobase::position(
len = store_key_val_for_row(primary_key, (char*) ref, record);
}
- dbug_assert(len <= ref_length);
-
+ DBUG_ASSERT(len == ref_length);
ref_stored_len = len;
}
+
/*********************************************************************
Creates a table definition to an InnoDB database. */
static
@@ -2332,7 +2363,8 @@ create_index(
ind_type = 0;
- if (strcmp(key->name, "PRIMARY") == 0) {
+ if (key_num == form->primary_key)
+ {
ind_type = ind_type | DICT_CLUSTERED;
}
@@ -2404,8 +2436,7 @@ ha_innobase::create(
int error;
dict_table_t* innobase_table;
trx_t* trx;
- int primary_key_no = -1;
- KEY* key;
+ int primary_key_no;
uint i;
char name2[FN_REFLEN];
char norm_name[FN_REFLEN];
@@ -2433,13 +2464,9 @@ ha_innobase::create(
/* Look for a primary key */
- for (i = 0; i < form->keys; i++) {
- key = form->key_info + i;
-
- if (strcmp(key->name, "PRIMARY") == 0) {
- primary_key_no = (int) i;
- }
- }
+ primary_key_no= (table->primary_key != MAX_KEY ?
+ (int) table->primary_key :
+ -1);
/* Our function row_get_mysql_key_number_for_index assumes
the primary key is always number 0, if it exists */
@@ -2510,12 +2537,12 @@ ha_innobase::create(
/* Flush the log to reduce probability that the .frm files and
the InnoDB data dictionary get out-of-sync if the user runs
with innodb_flush_log_at_trx_commit = 0 */
-
+
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP);
innobase_table = dict_table_get(norm_name, NULL);
- assert(innobase_table);
+ assert(innobase_table != 0);
/* Tell the InnoDB server that there might be work for
utility threads: */
@@ -2565,7 +2592,7 @@ ha_innobase::delete_table(
/* Flush the log to reduce probability that the .frm files and
the InnoDB data dictionary get out-of-sync if the user runs
with innodb_flush_log_at_trx_commit = 0 */
-
+
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP);
/* Tell the InnoDB server that there might be work for
@@ -2599,9 +2626,9 @@ innobase_drop_database(
char* ptr;
int error;
char namebuf[10000];
-
+
ptr = strend(path) - 2;
-
+
while (ptr >= path && *ptr != '\\' && *ptr != '/') {
ptr--;
len++;
@@ -2612,16 +2639,8 @@ innobase_drop_database(
memcpy(namebuf, ptr, len);
namebuf[len] = '/';
namebuf[len + 1] = '\0';
-
#ifdef __WIN__
- /* Put to lower case */
-
- ptr = namebuf;
-
- while (*ptr != '\0') {
- *ptr = tolower(*ptr);
- ptr++;
- }
+ casedn_str(namebuf);
#endif
trx = trx_allocate_for_mysql();
@@ -2630,7 +2649,7 @@ innobase_drop_database(
/* Flush the log to reduce probability that the .frm files and
the InnoDB data dictionary get out-of-sync if the user runs
with innodb_flush_log_at_trx_commit = 0 */
-
+
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP);
/* Tell the InnoDB server that there might be work for
@@ -2683,7 +2702,7 @@ ha_innobase::rename_table(
/* Flush the log to reduce probability that the .frm files and
the InnoDB data dictionary get out-of-sync if the user runs
with innodb_flush_log_at_trx_commit = 0 */
-
+
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP);
/* Tell the InnoDB server that there might be work for
@@ -2740,7 +2759,7 @@ ha_innobase::records_in_range(
/* Warning: since it is not sure that MySQL calls external_lock
before calling this function, the trx field in prebuilt can be
obsolete! */
-
+
active_index = keynr;
key = table->key_info + active_index;
@@ -2792,7 +2811,7 @@ ha_innobase::estimate_number_of_rows(void)
dict_index_t* index;
ulonglong estimate;
ulonglong data_file_length;
-
+
/* Warning: since it is not sure that MySQL calls external_lock
before calling this function, the trx field in prebuilt can be
obsolete! */
@@ -2800,7 +2819,7 @@ ha_innobase::estimate_number_of_rows(void)
DBUG_ENTER("info");
index = dict_table_get_first_index_noninline(prebuilt->table);
-
+
data_file_length = ((ulonglong) index->stat_n_leaf_pages)
* UNIV_PAGE_SIZE;
@@ -2811,8 +2830,8 @@ ha_innobase::estimate_number_of_rows(void)
of the formula below. */
estimate = 2 * data_file_length / dict_index_calc_min_rec_len(index);
-
- return((ha_rows) estimate);
+
+ DBUG_RETURN((ha_rows) estimate);
}
/*************************************************************************
@@ -2856,7 +2875,7 @@ ha_innobase::info(
/* Warning: since it is not sure that MySQL calls external_lock
before calling this function, the trx field in prebuilt can be
obsolete! */
-
+
ib_table = prebuilt->table;
if (flag & HA_STATUS_TIME) {
@@ -2913,11 +2932,11 @@ ha_innobase::info(
if (rec_per_key == 0) {
rec_per_key = 1;
}
-
- table->key_info[i].rec_per_key[j]
+
+ table->key_info[i].rec_per_key[j]
= rec_per_key;
}
-
+
index = dict_table_get_next_index_noninline(index);
}
}
@@ -2955,7 +2974,7 @@ ha_innobase::check(
{
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
ulint ret;
-
+
ut_a(prebuilt->trx && prebuilt->trx->magic_n == TRX_MAGIC_N);
if (prebuilt->mysql_template == NULL) {
@@ -2970,7 +2989,7 @@ ha_innobase::check(
if (ret == DB_SUCCESS) {
return(HA_ADMIN_OK);
}
-
+
return(HA_ADMIN_CORRUPT);
}
@@ -3010,12 +3029,12 @@ ha_innobase::update_table_comment(
(ulong) innobase_get_free_space());
/* We assume 450 - length bytes of space to print info */
-
+
if (length < 450) {
dict_print_info_on_foreign_keys(FALSE, pos, 450 - length,
prebuilt->table);
}
-
+
return(str);
}
@@ -3184,6 +3203,7 @@ ha_innobase::external_lock(
& (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN))) {
innobase_commit(thd, trx);
+ thd->transaction.all.innodb_active_trans=0;
}
}
}
diff --git a/sql/ha_innobase.h b/sql/ha_innodb.h
index 9f752dd2eda..a0f3ea28d2c 100644
--- a/sql/ha_innobase.h
+++ b/sql/ha_innodb.h
@@ -1,7 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
- && Innobase Oy
-
- -This file is modified from ha_berkeley.h of MySQL distribution-
+/* Copyright (C) 2000 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
@@ -17,13 +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 */
+/*
+ This file is based on ha_berkeley.h of MySQL distribution
+
+ This file defines the Innodb handler: the interface between MySQL and
+ Innodb
+*/
+
#ifdef __GNUC__
#pragma interface /* gcc class implementation */
#endif
-/* This file defines the Innobase handler: the interface between MySQL and
-Innobase */
-
typedef struct st_innobase_share {
THR_LOCK lock;
pthread_mutex_t mutex;
@@ -32,11 +33,11 @@ typedef struct st_innobase_share {
} INNOBASE_SHARE;
-/* The class defining a handle to an Innobase table */
+/* The class defining a handle to an Innodb table */
class ha_innobase: public handler
{
void* innobase_prebuilt; /* (row_prebuilt_t*) prebuilt
- struct in Innobase, used to save
+ struct in Innodb, used to save
CPU */
THD* user_thd; /* the thread handle of the user
currently using the handle; this is
@@ -50,7 +51,7 @@ class ha_innobase: public handler
byte* upd_buff; /* buffer used in updates */
byte* key_val_buff; /* buffer used in converting
search key values from MySQL format
- to Innobase format */
+ to Innodb format */
uint ref_stored_len; /* length of the key value stored to
'ref' buffer of the handle, if any */
ulong int_option_flag;
@@ -78,12 +79,13 @@ class ha_innobase: public handler
HA_REC_NOT_IN_SEQ |
HA_KEYPOS_TO_RNDPOS | HA_LASTKEY_ORDER |
HA_HAVE_KEY_READ_ONLY | HA_READ_NOT_EXACT_KEY |
- HA_LONGLONG_KEYS | HA_NULL_KEY |
- HA_NOT_EXACT_COUNT | HA_NO_FULLTEXT_KEY |
+ HA_NULL_KEY |
+ HA_NOT_EXACT_COUNT |
HA_NO_WRITE_DELAYED |
HA_PRIMARY_KEY_IN_READ_INDEX |
- HA_DROP_BEFORE_CREATE |
- HA_NO_PREFIX_CHAR_KEYS),
+ HA_DROP_BEFORE_CREATE | HA_NOT_READ_PREFIX_LAST |
+ HA_NO_PREFIX_CHAR_KEYS |
+ HA_TABLE_SCAN_ON_INDEX),
last_dup_key((uint) -1),
start_of_scan(0)
{
@@ -91,6 +93,7 @@ class ha_innobase: public handler
~ha_innobase() {}
const char* table_type() const { return("InnoDB");}
+ const char *index_type(uint key_number) { return "BTREE"; }
const char** bas_ext() const;
ulong option_flag() const { return int_option_flag; }
uint max_record_length() const { return HA_MAX_REC_LENGTH; }
@@ -121,9 +124,10 @@ class ha_innobase: 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);
+ uint key_len, 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);
+ 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_next_same(byte * buf, const byte *key, uint keylen);
int index_prev(byte * buf);
diff --git a/sql/ha_isam.cc b/sql/ha_isam.cc
index ac37d09e6b4..7c9c7a64c9d 100644
--- a/sql/ha_isam.cc
+++ b/sql/ha_isam.cc
@@ -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 */
@@ -20,6 +20,7 @@
#endif
#include "mysql_priv.h"
+#ifdef HAVE_ISAM
#include <m_ctype.h>
#include <myisampack.h>
#include "ha_isam.h"
@@ -108,6 +109,15 @@ int ha_isam::index_read_idx(byte * buf, uint index, const byte * key,
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);
@@ -123,7 +133,7 @@ int ha_isam::index_prev(byte * buf)
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);
@@ -235,7 +245,7 @@ int ha_isam::reset(void)
int ha_isam::external_lock(THD *thd, int lock_type)
{
return nisam_lock_database(file,lock_type);
-}
+}
THR_LOCK_DATA **ha_isam::store_lock(THD *thd,
@@ -315,7 +325,7 @@ int ha_isam::create(const char *name, register TABLE *form,
{
/* skip null fields */
if (!(temp_length= (*field)->pack_length()))
- continue; /* Skipp null-fields */
+ continue; /* Skip null-fields */
if (! found || fieldpos < minpos ||
(fieldpos == minpos && temp_length < length))
{
@@ -343,15 +353,15 @@ int ha_isam::create(const char *name, register TABLE *form,
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_SKIPP_ZERO;
+ 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_SKIPP_ENDSPACE :
- FIELD_SKIPP_PRESPACE);
+ FIELD_SKIP_ENDSPACE :
+ FIELD_SKIP_PRESPACE);
recinfo_pos++ ->base.length=(uint16) length;
recpos=minpos+length;
DBUG_PRINT("loop",("length: %d type: %d",
@@ -388,3 +398,4 @@ ha_rows ha_isam::records_in_range(int inx,
end_key,end_key_len,
end_search_flag);
}
+#endif /* HAVE_ISAM */
diff --git a/sql/ha_isam.h b/sql/ha_isam.h
index 5e01edcf889..4194632ddbe 100644
--- a/sql/ha_isam.h
+++ b/sql/ha_isam.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 */
@@ -33,11 +33,12 @@ class ha_isam: public handler
int_option_flag(HA_READ_NEXT | HA_READ_PREV | HA_READ_RND_SAME |
HA_KEYPOS_TO_RNDPOS | HA_READ_ORDER | HA_LASTKEY_ORDER |
HA_HAVE_KEY_READ_ONLY | HA_READ_NOT_EXACT_KEY |
- HA_LONGLONG_KEYS | HA_KEY_READ_WRONG_STR | HA_DUPP_POS |
- HA_NOT_DELETE_WITH_CACHE | HA_NO_FULLTEXT_KEY)
+ HA_KEY_READ_WRONG_STR | HA_DUPP_POS |
+ HA_NOT_DELETE_WITH_CACHE)
{}
~ha_isam() {}
const char *table_type() const { return "ISAM"; }
+ const char *index_type(uint key_number) { return "BTREE"; }
const char **bas_ext() const;
ulong option_flag() const { return int_option_flag; }
uint max_record_length() const { return HA_MAX_REC_LENGTH; }
@@ -56,6 +57,7 @@ class ha_isam: public handler
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);
@@ -80,9 +82,3 @@ class ha_isam: public handler
enum thr_lock_type lock_type);
};
-
-
-
-
-
-
diff --git a/sql/ha_isammrg.cc b/sql/ha_isammrg.cc
index dd2e4e2f723..b110ffba2f9 100644
--- a/sql/ha_isammrg.cc
+++ b/sql/ha_isammrg.cc
@@ -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 */
@@ -20,11 +20,12 @@
#endif
#include "mysql_priv.h"
+#ifdef HAVE_ISAM
#include <m_ctype.h>
#ifndef MASTER
-#include "../srclib/merge/mrgdef.h"
+#include "../srclib/merge/mrg_def.h"
#else
-#include "../merge/mrgdef.h"
+#include "../merge/mrg_def.h"
#endif
#include "ha_isammrg.h"
@@ -109,7 +110,7 @@ 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);
@@ -178,7 +179,7 @@ int ha_isammrg::reset(void)
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
{
@@ -208,3 +209,4 @@ int ha_isammrg::create(const char *name, register TABLE *form,
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
index c8eb7dd9f69..1ee0b0e2547 100644
--- a/sql/ha_isammrg.h
+++ b/sql/ha_isammrg.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 */
@@ -32,8 +32,9 @@ class ha_isammrg: public handler
~ha_isammrg() {}
const char *table_type() const { return "MRG_ISAM"; }
const char **bas_ext() const;
- ulong option_flag() const { return HA_READ_RND_SAME | HA_KEYPOS_TO_RNDPOS
- | HA_REC_NOT_IN_SEQ | HA_NO_FULLTEXT_KEY;}
+ ulong option_flag() const { return (HA_READ_RND_SAME | HA_KEYPOS_TO_RNDPOS |
+ HA_NOT_READ_PREFIX_LAST |
+ HA_REC_NOT_IN_SEQ); }
uint max_record_length() const { return HA_MAX_REC_LENGTH; }
uint max_keys() const { return 0; }
uint max_key_parts() const { return 0; }
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 595c83ff8ef..df55cdd0033 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -36,7 +36,7 @@ ulong myisam_recover_options= HA_RECOVER_NONE;
/* bits in myisam_recover_options */
const char *myisam_recover_names[] =
{ "DEFAULT", "BACKUP", "FORCE", "QUICK", NullS};
-TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names),"",
+TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"",
myisam_recover_names};
@@ -80,9 +80,8 @@ static void mi_check_print_msg(MI_CHECK *param, const char* msg_type,
net_store_data(packet, msgbuf);
if (my_net_write(&thd->net, (char*)thd->packet.ptr(), thd->packet.length()))
- fprintf(stderr,
- "Failed on my_net_write, writing to stderr instead: %s\n",
- msgbuf);
+ sql_print_error("Failed on my_net_write, writing to stderr instead: %s\n",
+ msgbuf);
return;
}
@@ -122,6 +121,13 @@ const char **ha_myisam::bas_ext() const
{ static const char *ext[]= { ".MYD",".MYI", NullS }; return ext; }
+const char *ha_myisam::index_type(uint key_number)
+{
+ return ((table->key_info[key_number].flags & HA_FULLTEXT) ?
+ "FULLTEXT" :
+ "BTREE");
+}
+
int ha_myisam::net_read_dump(NET* net)
{
int data_fd = file->dfile;
@@ -130,7 +136,7 @@ int ha_myisam::net_read_dump(NET* net)
my_seek(data_fd, 0L, MY_SEEK_SET, MYF(MY_WME));
for(;;)
{
- uint packet_len = my_net_read(net);
+ ulong packet_len = my_net_read(net);
if (!packet_len)
break ; // end of file
if (packet_len == packet_error)
@@ -139,7 +145,7 @@ int ha_myisam::net_read_dump(NET* net)
error= -1;
goto err;
}
- if (my_write(data_fd, (byte*)net->read_pos, packet_len,
+ if (my_write(data_fd, (byte*)net->read_pos, (uint) packet_len,
MYF(MY_WME|MY_FNABP)))
{
error = errno;
@@ -283,7 +289,7 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt)
error = chk_key(&param, file);
if (!error)
{
- if ((!check_opt->quick &&
+ if ((!(param.testflag & T_QUICK) &&
((share->options &
(HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ||
(param.testflag & (T_EXTEND | T_MEDIUM)))) ||
@@ -324,7 +330,6 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt)
mi_mark_crashed(file);
file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
}
- check_opt->retry_without_quick=param.retry_without_quick;
thd->proc_info=old_proc_info;
return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
@@ -374,14 +379,14 @@ int ha_myisam::restore(THD* thd, HA_CHECK_OPT *check_opt)
char* backup_dir = thd->lex.backup_dir;
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
char* table_name = table->real_name;
+ int error;
+ const char* errmsg;
DBUG_ENTER("restore");
- if (!fn_format(src_path, table_name, backup_dir, MI_NAME_DEXT, 4 + 64))
+ if (fn_format_relative_to_data_home(src_path, table_name, backup_dir,
+ MI_NAME_DEXT))
DBUG_RETURN(HA_ADMIN_INVALID);
- int error = 0;
- const char* errmsg = "";
-
if (my_copy(src_path, fn_format(dst_path, table->path, "",
MI_NAME_DEXT, 4), MYF(MY_WME)))
{
@@ -391,8 +396,7 @@ int ha_myisam::restore(THD* thd, HA_CHECK_OPT *check_opt)
}
tmp_check_opt.init();
- tmp_check_opt.quick = 1;
- tmp_check_opt.flags |= T_VERY_SILENT | T_CALC_CHECKSUM;
+ tmp_check_opt.flags |= T_VERY_SILENT | T_CALC_CHECKSUM | T_QUICK;
DBUG_RETURN(repair(thd, &tmp_check_opt));
err:
@@ -404,7 +408,7 @@ int ha_myisam::restore(THD* thd, HA_CHECK_OPT *check_opt)
param.db_name = table->table_cache_key;
param.table_name = table->table_name;
param.testflag = 0;
- mi_check_print_error(&param,errmsg, errno );
+ mi_check_print_error(&param,errmsg, my_errno);
DBUG_RETURN(error);
}
}
@@ -415,41 +419,47 @@ int ha_myisam::backup(THD* thd, HA_CHECK_OPT *check_opt)
char* backup_dir = thd->lex.backup_dir;
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
char* table_name = table->real_name;
- int error = 0;
- const char* errmsg = "";
-
- if (!fn_format(dst_path, table_name, backup_dir, reg_ext, 4 + 64))
- {
- 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, 4),
- dst_path,
- MYF(MY_WME | MY_HOLD_ORIGINAL_MODES )))
+ int error;
+ const char *errmsg;
+ DBUG_ENTER("ha_myisam::backup");
+
+ if (fn_format_relative_to_data_home(dst_path, table_name, backup_dir,
+ reg_ext))
+ {
+ errmsg = "Failed in fn_format() for .frm file: errno = %d";
+ error = HA_ADMIN_INVALID;
+ goto err;
+ }
+
+ if (my_copy(fn_format(src_path, table->path,"", reg_ext, MY_UNPACK_FILENAME),
+ dst_path,
+ MYF(MY_WME | MY_HOLD_ORIGINAL_MODES)))
{
error = HA_ADMIN_FAILED;
errmsg = "Failed copying .frm file: errno = %d";
goto err;
}
- if (!fn_format(dst_path, table_name, backup_dir, MI_NAME_DEXT, 4 + 64))
- {
- errmsg = "Failed in fn_format() for .MYD file: errno = %d";
- error = HA_ADMIN_INVALID;
- goto err;
- }
+ /* Change extension */
+ if (!fn_format(dst_path, dst_path, "", MI_NAME_DEXT,
+ MY_REPLACE_EXT | MY_UNPACK_FILENAME | MY_SAFE_PATH))
+ {
+ errmsg = "Failed in fn_format() for .MYD file: errno = %d";
+ error = HA_ADMIN_INVALID;
+ goto err;
+ }
- if (my_copy(fn_format(src_path, table->path,"", MI_NAME_DEXT, 4),
+ if (my_copy(fn_format(src_path, table->path,"", MI_NAME_DEXT,
+ MY_UNPACK_FILENAME),
dst_path,
- MYF(MY_WME | MY_HOLD_ORIGINAL_MODES )) )
- {
- errmsg = "Failed copying .MYD file: errno = %d";
- error= HA_ADMIN_FAILED;
- goto err;
- }
- return HA_ADMIN_OK;
+ MYF(MY_WME | MY_HOLD_ORIGINAL_MODES)))
+ {
+ errmsg = "Failed copying .MYD file: errno = %d";
+ error= HA_ADMIN_FAILED;
+ goto err;
+ }
+ DBUG_RETURN(HA_ADMIN_OK);
+
err:
{
MI_CHECK param;
@@ -459,8 +469,8 @@ int ha_myisam::backup(THD* thd, HA_CHECK_OPT *check_opt)
param.db_name = table->table_cache_key;
param.table_name = table->table_name;
param.testflag = 0;
- mi_check_print_error(&param,errmsg, errno );
- return error;
+ mi_check_print_error(&param,errmsg, my_errno);
+ DBUG_RETURN(error);
}
}
@@ -476,24 +486,23 @@ 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)) |
+ param.testflag = ((check_opt->flags & ~(T_EXTEND)) |
T_SILENT | T_FORCE_CREATE |
(check_opt->flags & T_EXTEND ? T_REP : T_REP_BY_SORT));
- if (check_opt->quick)
- param.opt_rep_quick++;
param.sort_buffer_length= check_opt->sort_buffer_size;
start_records=file->state->records;
while ((error=repair(thd,param,0)) && param.retry_repair)
{
param.retry_repair=0;
- if (param.retry_without_quick && param.opt_rep_quick)
+ if ((param.testflag & T_RETRY_WITHOUT_QUICK) &&
+ (param.testflag & T_QUICK))
{
- param.opt_rep_quick=0;
+ param.testflag&= ~T_RETRY_WITHOUT_QUICK;
sql_print_error("Warning: Retrying repair of: '%s' without quick",
table->path);
continue;
}
- param.opt_rep_quick=0; // Safety
+ param.testflag&= ~T_QUICK;
if ((param.testflag & T_REP_BY_SORT))
{
param.testflag= (param.testflag & ~T_REP_BY_SORT) | T_REP;
@@ -525,8 +534,6 @@ int ha_myisam::optimize(THD* thd, HA_CHECK_OPT *check_opt)
param.op_name = (char*) "optimize";
param.testflag = (check_opt->flags | T_SILENT | T_FORCE_CREATE |
T_REP_BY_SORT | T_STATISTICS | T_SORT_INDEX);
- if (check_opt->quick)
- param.opt_rep_quick++;
param.sort_buffer_length= check_opt->sort_buffer_size;
return repair(thd,param,1);
}
@@ -537,8 +544,8 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
int error=0;
uint local_testflag=param.testflag;
bool optimize_done= !optimize, statistics_done=0;
- char fixed_name[FN_REFLEN];
const char *old_proc_info=thd->proc_info;
+ char fixed_name[FN_REFLEN];
MYISAM_SHARE* share = file->s;
ha_rows rows= file->state->records;
DBUG_ENTER("ha_myisam::repair");
@@ -550,8 +557,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
param.thd=thd;
param.tmpdir=mysql_tmpdir;
param.out_flag=0;
- VOID(fn_format(fixed_name,file->filename,"",MI_NAME_IEXT,
- 4+ (param.opt_follow_links ? 16 : 0)));
+ strmov(fixed_name,file->filename);
// Don't lock tables if we have used LOCK TABLE
if (!thd->locked_tables && mi_lock_database(file,F_WRLCK))
@@ -562,7 +568,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
if (!optimize ||
((file->state->del || share->state.split != file->state->records) &&
- (!param.opt_rep_quick ||
+ (!(param.testflag & T_QUICK) ||
!(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))))
{
ulonglong key_map= ((local_testflag & T_CREATE_MISSING_KEYS) ?
@@ -576,13 +582,15 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
param.testflag|= T_STATISTICS; // We get this for free
thd->proc_info="Repair by sorting";
statistics_done=1;
- error = mi_repair_by_sort(&param, file, fixed_name, param.opt_rep_quick);
+ error = mi_repair_by_sort(&param, file, fixed_name,
+ param.testflag & T_QUICK);
}
else
{
thd->proc_info="Repair with keycache";
param.testflag &= ~T_REP_BY_SORT;
- error= mi_repair(&param, file, fixed_name, param.opt_rep_quick);
+ error= mi_repair(&param, file, fixed_name,
+ param.testflag & T_QUICK);
}
param.testflag=testflag;
optimize_done=1;
@@ -653,8 +661,21 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
void ha_myisam::deactivate_non_unique_index(ha_rows rows)
{
- if (!(specialflag & SPECIAL_SAFE_MODE))
- mi_disable_non_unique_index(file,rows);
+ MYISAM_SHARE* share = file->s;
+ if (share->state.key_map == ((ulonglong) 1L << share->base.keys)-1)
+ {
+ if (!(specialflag & SPECIAL_SAFE_MODE))
+ if (rows==HA_POS_ERROR)
+ mi_extra(file, HA_EXTRA_NO_KEYS);
+ else
+ {
+ mi_disable_non_unique_index(file,rows);
+ mi_extra(file, HA_EXTRA_BULK_INSERT_BEGIN);
+ }
+ enable_activate_all_index=1;
+ }
+ else
+ enable_activate_all_index=0;
}
@@ -664,21 +685,25 @@ bool ha_myisam::activate_all_index(THD *thd)
MI_CHECK param;
MYISAM_SHARE* share = file->s;
DBUG_ENTER("activate_all_index");
- if (share->state.key_map != set_bits(ulonglong, share->base.keys))
+
+ mi_extra(file, HA_EXTRA_BULK_INSERT_END);
+ if (enable_activate_all_index &&
+ share->state.key_map != set_bits(ulonglong, share->base.keys))
{
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 |
+ param.testflag = (T_SILENT | T_REP_BY_SORT | T_QUICK |
T_CREATE_MISSING_KEYS | T_TRUST_HEADER);
param.myf_rw&= ~MY_WAIT_IF_FULL;
param.sort_buffer_length= myisam_sort_buffer_size;
- param.opt_rep_quick++; // Don't copy data file
param.tmpdir=mysql_tmpdir;
error=repair(thd,param,0) != HA_ADMIN_OK;
thd->proc_info=save_proc_info;
}
+ else
+ enable_activate_all_index=1;
DBUG_RETURN(error);
}
@@ -694,16 +719,16 @@ bool ha_myisam::check_and_repair(THD *thd)
check_opt.flags= T_MEDIUM | T_AUTO_REPAIR;
// Don't use quick if deleted rows
if (!file->state->del && (myisam_recover_options & HA_RECOVER_QUICK))
- check_opt.quick=1;
+ check_opt.flags|=T_QUICK;
sql_print_error("Warning: Checking table: '%s'",table->path);
if ((marked_crashed=mi_is_crashed(file)) || check(thd, &check_opt))
{
sql_print_error("Warning: Recovering table: '%s'",table->path);
- check_opt.quick= !check_opt.retry_without_quick && !marked_crashed;
- check_opt.flags=(((myisam_recover_options & HA_RECOVER_BACKUP) ?
- T_BACKUP_DATA : 0) |
- (!(myisam_recover_options & HA_RECOVER_FORCE) ?
- T_SAFE_REPAIR : 0)) | T_AUTO_REPAIR;
+ check_opt.flags=
+ ((myisam_recover_options & HA_RECOVER_BACKUP ? T_BACKUP_DATA : 0) |
+ (marked_crashed ? 0 : T_QUICK) |
+ (myisam_recover_options & HA_RECOVER_FORCE ? 0 : T_SAFE_REPAIR) |
+ T_AUTO_REPAIR);
if (repair(thd, &check_opt))
error=1;
}
@@ -748,6 +773,14 @@ int ha_myisam::index_read_idx(byte * buf, uint index, const byte * key,
return error;
}
+int ha_myisam::index_read_last(byte * buf, const byte * key, uint key_len)
+{
+ statistic_increment(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;
+}
+
int ha_myisam::index_next(byte * buf)
{
statistic_increment(ha_read_next_count,&LOCK_status);
@@ -829,6 +862,8 @@ void ha_myisam::position(const byte* record)
void ha_myisam::info(uint flag)
{
MI_ISAMINFO info;
+ char name_buff[FN_REFLEN];
+
(void) mi_status(file,&info,flag);
if (flag & HA_STATUS_VARIABLE)
{
@@ -858,6 +893,18 @@ void ha_myisam::info(uint flag)
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
+ if table is symlinked (Ie; Real name is not same as generated name)
+ */
+ data_file_name=index_file_name=0;
+ fn_format(name_buff, file->filename, "", MI_NAME_DEXT, 2);
+ if (strcmp(name_buff, info.data_file_name))
+ data_file_name=info.data_file_name;
+ strmov(fn_ext(name_buff),MI_NAME_IEXT);
+ if (strcmp(name_buff, info.index_file_name))
+ index_file_name=info.index_file_name;
}
if (flag & HA_STATUS_ERRKEY)
{
@@ -875,7 +922,8 @@ int ha_myisam::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))
+ operation == HA_EXTRA_KEYREAD ||
+ operation == HA_EXTRA_BULK_INSERT_BEGIN))
return 0;
return mi_extra(file,operation);
}
@@ -924,10 +972,12 @@ void ha_myisam::update_create_info(HA_CREATE_INFO *create_info)
create_info->raid_chunks= raid_chunks;
create_info->raid_chunksize= raid_chunksize;
}
+ create_info->data_file_name=data_file_name;
+ create_info->index_file_name=index_file_name;
}
-int ha_myisam::create(const char *name, register TABLE *form,
+int ha_myisam::create(const char *name, register TABLE *table,
HA_CREATE_INFO *info)
{
int error;
@@ -939,20 +989,20 @@ int ha_myisam::create(const char *name, register TABLE *form,
MI_KEYDEF *keydef;
MI_COLUMNDEF *recinfo,*recinfo_pos;
MI_KEYSEG *keyseg;
- uint options=form->db_options_in_use;
+ uint options=table->db_options_in_use;
DBUG_ENTER("ha_myisam::create");
type=HA_KEYTYPE_BINARY; // Keep compiler happy
if (!(my_multi_malloc(MYF(MY_WME),
- &recinfo,(form->fields*2+2)*sizeof(MI_COLUMNDEF),
- &keydef, form->keys*sizeof(MI_KEYDEF),
+ &recinfo,(table->fields*2+2)*sizeof(MI_COLUMNDEF),
+ &keydef, table->keys*sizeof(MI_KEYDEF),
&keyseg,
- ((form->key_parts + form->keys) * sizeof(MI_KEYSEG)),
+ ((table->key_parts + table->keys) * sizeof(MI_KEYSEG)),
0)))
DBUG_RETURN(1);
- pos=form->key_info;
- for (i=0; i < form->keys ; i++, pos++)
+ pos=table->key_info;
+ for (i=0; i < table->keys ; i++, pos++)
{
keydef[i].flag= (pos->flags & (HA_NOSAME | HA_FULLTEXT));
keydef[i].seg=keyseg;
@@ -995,7 +1045,7 @@ int ha_myisam::create(const char *name, register TABLE *form,
{
keydef[i].seg[j].null_bit=field->null_bit;
keydef[i].seg[j].null_pos= (uint) (field->null_ptr-
- (uchar*) form->record[0]);
+ (uchar*) table->record[0]);
}
else
{
@@ -1013,26 +1063,26 @@ int ha_myisam::create(const char *name, register TABLE *form,
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() -
- form->blob_ptr_size);
+ table->blob_ptr_size);
}
}
keyseg+=pos->key_parts;
}
recpos=0; recinfo_pos=recinfo;
- while (recpos < (uint) form->reclength)
+ while (recpos < (uint) table->reclength)
{
Field **field,*found=0;
- minpos=form->reclength; length=0;
+ minpos=table->reclength; length=0;
- for (field=form->field ; *field ; field++)
+ for (field=table->field ; *field ; field++)
{
if ((fieldpos=(*field)->offset()) >= recpos &&
fieldpos <= minpos)
{
/* skip null fields */
if (!(temp_length= (*field)->pack_length()))
- continue; /* Skipp null-fields */
+ continue; /* Skip null-fields */
if (! found || fieldpos < minpos ||
(fieldpos == minpos && temp_length < length))
{
@@ -1058,20 +1108,20 @@ int ha_myisam::create(const char *name, register TABLE *form,
else if (!(options & HA_OPTION_PACK_RECORD))
recinfo_pos->type= (int) FIELD_NORMAL;
else if (found->zero_pack())
- recinfo_pos->type= (int) FIELD_SKIPP_ZERO;
+ 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_SKIPP_ENDSPACE :
- FIELD_SKIPP_PRESPACE);
+ 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*) form->record[0]);
+ (uchar*) table->record[0]);
}
else
{
@@ -1086,18 +1136,23 @@ int ha_myisam::create(const char *name, register TABLE *form,
}
MI_CREATE_INFO create_info;
bzero((char*) &create_info,sizeof(create_info));
- create_info.max_rows=form->max_rows;
- create_info.reloc_rows=form->min_rows;
+ create_info.max_rows=table->max_rows;
+ create_info.reloc_rows=table->min_rows;
create_info.auto_increment=(info->auto_increment_value ?
info->auto_increment_value -1 :
(ulonglong) 0);
- create_info.data_file_length=(ulonglong) form->max_rows*form->avg_row_length;
+ create_info.data_file_length= ((ulonglong) table->max_rows *
+ table->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;
-
- error=mi_create(fn_format(buff,name,"","",2+4+16),
- form->keys,keydef,
+ 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;
+
+ error=mi_create(fn_format(buff,name,"","",2+4),
+ table->keys,keydef,
(uint) (recinfo_pos-recinfo), recinfo,
0, (MI_UNIQUEDEF*) 0,
&create_info,
@@ -1128,7 +1183,7 @@ longlong ha_myisam::get_auto_increment()
longlong nr;
int error;
- byte key[MAX_KEY_LENGTH];
+ byte key[MI_MAX_KEY_LENGTH];
(void) extra(HA_EXTRA_KEYREAD);
key_copy(key,table,table->next_number_index,
table->next_number_key_offset);
@@ -1167,9 +1222,8 @@ int ha_myisam::ft_read(byte * buf)
thread_safe_increment(ha_read_next_count,&LOCK_status); // why ?
- error=ft_read_next((FT_DOCLIST *) ft_handler,(char*) buf);
+ error=ft_handler->please->read_next(ft_handler,(char*) buf);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
-
diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h
index 6451e2b80ee..75655a2b505 100644
--- a/sql/ha_myisam.h
+++ b/sql/ha_myisam.h
@@ -38,24 +38,29 @@ class ha_myisam: public handler
{
MI_INFO *file;
uint int_option_flag;
+ char *data_file_name, *index_file_name;
+ bool enable_activate_all_index;
int repair(THD *thd, MI_CHECK &param, bool optimize);
public:
ha_myisam(TABLE *table): handler(table), file(0),
int_option_flag(HA_READ_NEXT | HA_READ_PREV | HA_READ_RND_SAME |
- HA_KEYPOS_TO_RNDPOS | HA_READ_ORDER | HA_LASTKEY_ORDER |
+ HA_KEYPOS_TO_RNDPOS | HA_READ_ORDER | HA_LASTKEY_ORDER |
HA_HAVE_KEY_READ_ONLY | HA_READ_NOT_EXACT_KEY |
- HA_LONGLONG_KEYS | HA_NULL_KEY |
- HA_DUPP_POS | HA_BLOB_KEY | HA_AUTO_PART_KEY)
+ HA_NULL_KEY |
+ HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER |
+ HA_DUPP_POS | HA_BLOB_KEY | HA_AUTO_PART_KEY),
+ enable_activate_all_index(1)
{}
~ha_myisam() {}
const char *table_type() const { return "MyISAM"; }
+ const char *index_type(uint key_number);
const char **bas_ext() const;
ulong option_flag() const { return int_option_flag; }
uint max_record_length() const { return HA_MAX_REC_LENGTH; }
uint max_keys() const { return MI_MAX_KEY; }
uint max_key_parts() const { return MAX_REF_PARTS; }
- uint max_key_length() const { return MAX_KEY_LENGTH; }
+ uint max_key_length() const { return MI_MAX_KEY_LENGTH; }
int open(const char *name, int mode, uint test_if_locked);
int close(void);
@@ -66,6 +71,7 @@ class ha_myisam: public handler
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);
@@ -73,9 +79,15 @@ class ha_myisam: public handler
int index_next_same(byte *buf, const byte *key, uint keylen);
int index_end() { ft_handler=NULL; return 0; }
int ft_init()
- { if(!ft_handler) return 1; ft_reinit_search(ft_handler); return 0; }
- void *ft_init_ext(uint inx,const byte *key, uint keylen, bool presort)
- { return ft_init_search(file,inx,(byte*) key,keylen,presort); }
+ {
+ if (!ft_handler)
+ return 1;
+ ft_handler->please->reinit_search(ft_handler);
+ return 0;
+ }
+ FT_INFO *ft_init_ext(uint mode, uint inx,const byte *key, uint keylen,
+ bool presort)
+ { return ft_init_search(mode, file,inx,(byte*) key,keylen,presort); }
int ft_read(byte *buf);
int rnd_init(bool scan=1);
int rnd_next(byte *buf);
diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc
index e5fb0310a36..42f8b807898 100644
--- a/sql/ha_myisammrg.cc
+++ b/sql/ha_myisammrg.cc
@@ -23,9 +23,9 @@
#include <m_ctype.h>
#include "ha_myisammrg.h"
#ifndef MASTER
-#include "../srclib/myisammrg/mymrgdef.h"
+#include "../srclib/myisammrg/myrg_def.h"
#else
-#include "../myisammrg/mymrgdef.h"
+#include "../myisammrg/myrg_def.h"
#endif
/*****************************************************************************
@@ -38,10 +38,15 @@ const char **ha_myisammrg::bas_ext() const
int ha_myisammrg::open(const char *name, int mode, uint test_if_locked)
{
char name_buff[FN_REFLEN];
+ DBUG_PRINT("info", ("ha_myisammrg::open"));
if (!(file=myrg_open(fn_format(name_buff,name,"","",2 | 4), mode,
test_if_locked)))
+ {
+ DBUG_PRINT("info", ("ha_myisammrg::open exit %d", my_errno));
return (my_errno ? my_errno : -1);
-
+ }
+ DBUG_PRINT("info", ("ha_myisammrg::open myrg_extrafunc..."))
+ myrg_extrafunc(file, &query_cache_invalidate_by_MyISAM_filename);
if (!(test_if_locked == HA_OPEN_WAIT_IF_LOCKED ||
test_if_locked == HA_OPEN_ABORT_IF_LOCKED))
myrg_extra(file,HA_EXTRA_NO_WAIT_LOCK);
@@ -66,7 +71,13 @@ int ha_myisammrg::close(void)
int ha_myisammrg::write_row(byte * buf)
{
- return (my_errno=HA_ERR_WRONG_COMMAND);
+ statistic_increment(ha_write_count,&LOCK_status);
+ if (table->time_stamp)
+ update_timestamp(buf+table->time_stamp-1);
+ if (table->next_number_field && buf == table->record[0])
+ return (my_errno=HA_ERR_WRONG_COMMAND);
+ // update_auto_increment(); - [phi] have to check this before allowing it
+ return myrg_write(file,buf);
}
int ha_myisammrg::update_row(const byte * old_data, byte * new_data)
@@ -101,6 +112,15 @@ int ha_myisammrg::index_read_idx(byte * buf, uint index, const byte * key,
return error;
}
+int ha_myisammrg::index_read_last(byte * buf, const byte * key, uint key_len)
+{
+ statistic_increment(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;
+ return error;
+}
+
int ha_myisammrg::index_next(byte * buf)
{
statistic_increment(ha_read_next_count,&LOCK_status);
@@ -185,6 +205,11 @@ void ha_myisammrg::info(uint flag)
int ha_myisammrg::extra(enum ha_extra_function operation)
{
+ /* As this is just a mapping, we don't have to force the underlying
+ tables to be closed */
+ if (operation == HA_EXTRA_FORCE_REOPEN ||
+ operation == HA_EXTRA_PREPARE_FOR_DELETE)
+ return 0;
return myrg_extra(file,operation);
}
@@ -221,6 +246,7 @@ THR_LOCK_DATA **ha_myisammrg::store_lock(THD *thd,
void ha_myisammrg::update_create_info(HA_CREATE_INFO *create_info)
{
+ // [phi] auto_increment stuff is missing (but currently not needed)
DBUG_ENTER("ha_myisammrg::update_create_info");
if (!(create_info->used_fields & HA_CREATE_USED_UNION))
{
@@ -231,7 +257,7 @@ void ha_myisammrg::update_create_info(HA_CREATE_INFO *create_info)
for (table=file->open_tables ; table != file->end_table ; table++)
{
- char *name=table->table->s->filename;
+ char *name=table->table->filename;
char buff[FN_REFLEN];
TABLE_LIST *ptr;
if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
@@ -245,6 +271,10 @@ void ha_myisammrg::update_create_info(HA_CREATE_INFO *create_info)
}
*create_info->merge_list.next=0;
}
+ if (!(create_info->used_fields & HA_CREATE_USED_INSERT_METHOD))
+ {
+ create_info->merge_insert_method = file->merge_insert_method;
+ }
DBUG_VOID_RETURN;
err:
@@ -267,18 +297,25 @@ int ha_myisammrg::create(const char *name, register TABLE *form,
*pos++= tables->real_name;
*pos=0;
DBUG_RETURN(myrg_create(fn_format(buff,name,"","",2+4+16),
- (const char **) table_names, (my_bool) 0));
+ (const char **) table_names,
+ create_info->merge_insert_method,
+ (my_bool) 0));
}
void ha_myisammrg::append_create_info(String *packet)
{
char buff[FN_REFLEN];
+ if (file->merge_insert_method != MERGE_INSERT_DISABLED)
+ {
+ packet->append(" INSERT_METHOD=",15);
+ packet->append(get_type(&merge_insert_method,file->merge_insert_method-1));
+ }
packet->append(" UNION=(",8);
MYRG_TABLE *table,*first;
for (first=table=file->open_tables ; table != file->end_table ; table++)
{
- char *name=table->table->s->filename;
+ char *name=table->table->filename;
fn_format(buff,name,"","",3);
if (table != first)
packet->append(',');
diff --git a/sql/ha_myisammrg.h b/sql/ha_myisammrg.h
index b97baa0703c..2ab3a807543 100644
--- a/sql/ha_myisammrg.h
+++ b/sql/ha_myisammrg.h
@@ -35,10 +35,10 @@ class ha_myisammrg: public handler
ulong option_flag() const
{ return (HA_REC_NOT_IN_SEQ | HA_READ_NEXT |
HA_READ_PREV | HA_READ_RND_SAME |
- HA_HAVE_KEY_READ_ONLY | HA_NO_FULLTEXT_KEY |
+ HA_HAVE_KEY_READ_ONLY |
HA_KEYPOS_TO_RNDPOS | HA_READ_ORDER |
HA_LASTKEY_ORDER | HA_READ_NOT_EXACT_KEY |
- HA_LONGLONG_KEYS | HA_NULL_KEY | HA_BLOB_KEY); }
+ HA_NULL_KEY | HA_BLOB_KEY); }
uint max_record_length() const { return HA_MAX_REC_LENGTH; }
uint max_keys() const { return MI_MAX_KEY; }
uint max_key_parts() const { return MAX_REF_PARTS; }
@@ -55,6 +55,7 @@ class ha_myisammrg: public handler
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);
@@ -74,4 +75,5 @@ class ha_myisammrg: public handler
enum thr_lock_type lock_type);
void update_create_info(HA_CREATE_INFO *create_info);
void append_create_info(String *packet);
+ MYRG_INFO *myrg_info() { return file; }
};
diff --git a/sql/handler.cc b/sql/handler.cc
index 098c3130de2..3e951efff48 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -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 */
@@ -25,7 +25,7 @@
#include "ha_heap.h"
#include "ha_myisam.h"
#include "ha_myisammrg.h"
-#ifndef NO_ISAM
+#ifdef HAVE_ISAM
#include "ha_isam.h"
#include "ha_isammrg.h"
#endif
@@ -33,10 +33,7 @@
#include "ha_berkeley.h"
#endif
#ifdef HAVE_INNOBASE_DB
-#include "ha_innobase.h"
-#endif
-#ifdef HAVE_GEMINI_DB
-#include "ha_gemini.h"
+#include "ha_innodb.h"
#endif
#include <myisampack.h>
#include <errno.h>
@@ -48,6 +45,7 @@ static int NEAR_F delete_file(const char *name,const char *ext,int extflag);
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;
const char *ha_table_type[] = {
@@ -78,21 +76,15 @@ enum db_type ha_checktype(enum db_type database_type)
return(berkeley_skip ? DB_TYPE_MYISAM : database_type);
#endif
#ifdef HAVE_INNOBASE_DB
- case DB_TYPE_INNOBASE:
+ case DB_TYPE_INNODB:
return(innodb_skip ? DB_TYPE_MYISAM : database_type);
#endif
-#ifdef HAVE_GEMINI_DB
- case DB_TYPE_GEMINI:
- return(gemini_skip ? DB_TYPE_MYISAM : database_type);
-#endif
#ifndef NO_HASH
case DB_TYPE_HASH:
#endif
-#ifndef NO_MERGE
- case DB_TYPE_MRG_ISAM:
-#endif
-#ifndef NO_ISAM
+#ifdef HAVE_ISAM
case DB_TYPE_ISAM:
+ case DB_TYPE_MRG_ISAM:
#endif
case DB_TYPE_HEAP:
case DB_TYPE_MYISAM:
@@ -111,11 +103,9 @@ handler *get_new_handler(TABLE *table, enum db_type db_type)
#ifndef NO_HASH
return new ha_hash(table);
#endif
-#ifndef NO_MERGE
+#ifdef HAVE_ISAM
case DB_TYPE_MRG_ISAM:
return new ha_isammrg(table);
-#endif
-#ifndef NO_ISAM
case DB_TYPE_ISAM:
return new ha_isam(table);
#endif
@@ -124,13 +114,9 @@ handler *get_new_handler(TABLE *table, enum db_type db_type)
return new ha_berkeley(table);
#endif
#ifdef HAVE_INNOBASE_DB
- case DB_TYPE_INNOBASE:
+ case DB_TYPE_INNODB:
return new ha_innobase(table);
#endif
-#ifdef HAVE_GEMINI_DB
- case DB_TYPE_GEMINI:
- return new ha_gemini(table);
-#endif
case DB_TYPE_HEAP:
return new ha_heap(table);
case DB_TYPE_MYISAM:
@@ -166,17 +152,6 @@ int ha_init()
have_innodb=SHOW_OPTION_DISABLED;
}
#endif
-#ifdef HAVE_GEMINI_DB
- if (!gemini_skip)
- {
- if (gemini_init())
- return -1;
- if (!gemini_skip) // If we couldn't use handler
- opt_using_transactions=1;
- else
- have_gemini=SHOW_OPTION_DISABLED;
- }
-#endif
return 0;
}
@@ -186,14 +161,14 @@ int ha_init()
int ha_panic(enum ha_panic_function flag)
{
int error=0;
-#ifndef NO_MERGE
- error|=mrg_panic(flag);
-#endif
#ifndef NO_HASH
error|=h_panic(flag); /* fix hash */
#endif
- error|=heap_panic(flag);
+#ifdef HAVE_ISAM
+ error|=mrg_panic(flag);
error|=nisam_panic(flag);
+#endif
+ error|=heap_panic(flag);
error|=mi_panic(flag);
error|=myrg_panic(flag);
#ifdef HAVE_BERKELEY_DB
@@ -204,10 +179,6 @@ int ha_panic(enum ha_panic_function flag)
if (!innodb_skip)
error|=innobase_end();
#endif
-#ifdef HAVE_GEMINI_DB
- if (!gemini_skip)
- error|=gemini_end();
-#endif
return error;
} /* ha_panic */
@@ -225,12 +196,6 @@ void ha_close_connection(THD* thd)
if (!innodb_skip)
innobase_close_connection(thd);
#endif
-#ifdef HAVE_GEMINI_DB
- if (!gemini_skip && thd->gemini.context)
- {
- gemini_disconnect(thd);
- }
-#endif /* HAVE_GEMINI_DB */
}
/*
@@ -305,6 +270,7 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans)
#ifdef USING_TRANSACTIONS
if (opt_using_transactions)
{
+ bool operation_done=0;
/* Update the binary log if we have cached some queries */
if (trans == &thd->transaction.all && mysql_bin_log.is_open() &&
my_b_tell(&thd->transaction.trans_log))
@@ -334,25 +300,18 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans)
error=1;
}
trans->innodb_active_trans=0;
- }
-#endif
-#ifdef HAVE_GEMINI_DB
- /* Commit the transaction in behalf of the commit statement
- or if we're in auto-commit mode */
- if((trans == &thd->transaction.all) ||
- (!(thd->options & (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN))))
- {
- error=gemini_commit(thd);
- if (error)
+ if (trans == &thd->transaction.all)
{
- my_error(ER_ERROR_DURING_COMMIT, MYF(0), error);
- error=1;
+ query_cache.invalidate(Query_cache_table::INNODB);
+ operation_done=1;
}
}
#endif
if (error && trans == &thd->transaction.all && mysql_bin_log.is_open())
sql_print_error("Error: Got error during commit; Binlog is not up to date!");
thd->tx_isolation=thd->session_tx_isolation;
+ if (operation_done)
+ statistic_increment(ha_commit_count,&LOCK_status);
}
#endif // using transactions
DBUG_RETURN(error);
@@ -366,6 +325,7 @@ int ha_rollback_trans(THD *thd, THD_TRANS *trans)
#ifdef USING_TRANSACTIONS
if (opt_using_transactions)
{
+ bool operation_done=0;
#ifdef HAVE_BERKELEY_DB
if (trans->bdb_tid)
{
@@ -375,6 +335,7 @@ int ha_rollback_trans(THD *thd, THD_TRANS *trans)
error=1;
}
trans->bdb_tid=0;
+ operation_done=1;
}
#endif
#ifdef HAVE_INNOBASE_DB
@@ -386,18 +347,7 @@ int ha_rollback_trans(THD *thd, THD_TRANS *trans)
error=1;
}
trans->innodb_active_trans=0;
- }
-#endif
-#ifdef HAVE_GEMINI_DB
- if((trans == &thd->transaction.stmt) &&
- (thd->options & (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN)))
- error = gemini_rollback_to_savepoint(thd);
- else
- error=gemini_rollback(thd);
- if (error)
- {
- my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), error);
- error=1;
+ operation_done=1;
}
#endif
if (trans == &thd->transaction.all)
@@ -405,22 +355,13 @@ int ha_rollback_trans(THD *thd, THD_TRANS *trans)
WRITE_CACHE, (my_off_t) 0, 0, 1);
thd->transaction.trans_log.end_of_file= max_binlog_cache_size;
thd->tx_isolation=thd->session_tx_isolation;
+ if (operation_done)
+ statistic_increment(ha_rollback_count,&LOCK_status);
}
#endif /* USING_TRANSACTIONS */
DBUG_RETURN(error);
}
-void ha_set_spin_retries(uint retries)
-{
-#ifdef HAVE_GEMINI_DB
- if (!gemini_skip)
- {
- gemini_set_option_long(GEM_OPTID_SPIN_RETRIES, retries);
- }
-#endif /* HAVE_GEMINI_DB */
-}
-
-
bool ha_flush_logs()
{
bool result=0;
@@ -449,7 +390,7 @@ int ha_delete_table(enum db_type table_type, const char *path)
delete file;
return error;
}
-
+
void ha_store_ptr(byte *buff, uint pack_length, my_off_t pos)
{
switch (pack_length) {
@@ -536,9 +477,8 @@ int handler::ha_open(const char *name, int mode, int test_if_locked)
{
if (table->db_options_in_use & HA_OPTION_READ_ONLY_DATA)
table->db_stat|=HA_READ_ONLY;
- }
- if (!error)
- {
+ (void) extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL
+
if (!alloc_root_inited(&table->mem_root)) // If temporary table
ref=(byte*) sql_alloc(ALIGN_SIZE(ref_length)*2);
else
@@ -584,17 +524,37 @@ int handler::analyze(THD* thd, HA_CHECK_OPT* check_opt)
return HA_ADMIN_NOT_IMPLEMENTED;
}
- /* Read first row from a table */
+/*
+ Read first row (only) from a table
+ This is never called for InnoDB or BDB tables, as these table types
+ has the HA_NOT_EXACT_COUNT set.
+*/
-int handler::rnd_first(byte * buf)
+int handler::read_first_row(byte * buf, uint primary_key)
{
register int error;
- DBUG_ENTER("handler::rnd_first");
+ DBUG_ENTER("handler::read_first_row");
statistic_increment(ha_read_first_count,&LOCK_status);
- (void) rnd_init();
- while ((error= rnd_next(buf)) == HA_ERR_RECORD_DELETED) ;
- (void) rnd_end();
+
+ /*
+ If there is very few deleted rows in the table, find the first row by
+ scanning the table.
+ */
+ if (deleted < 10 || primary_key >= MAX_KEY ||
+ !(option_flag() & HA_READ_ORDER))
+ {
+ (void) rnd_init();
+ while ((error= rnd_next(buf)) == HA_ERR_RECORD_DELETED) ;
+ (void) rnd_end();
+ }
+ else
+ {
+ /* Find the first row through the primary key */
+ (void) index_init(primary_key);
+ error=index_first(buf);
+ (void) index_end();
+ }
DBUG_RETURN(error);
}
@@ -610,7 +570,7 @@ int handler::restart_rnd_next(byte *buf, byte *pos)
}
- /* Set a timestamp in record */
+/* Set a timestamp in record */
void handler::update_timestamp(byte *record)
{
@@ -626,9 +586,10 @@ void handler::update_timestamp(byte *record)
return;
}
- /* Updates field with field_type NEXT_NUMBER according to following:
- ** if field = 0 change field to the next free key in database.
- */
+/*
+ Updates field with field_type NEXT_NUMBER according to following:
+ if field = 0 change field to the next free key in database.
+*/
void handler::update_auto_increment()
{
@@ -811,22 +772,6 @@ int handler::rename_table(const char * from, const char * to)
DBUG_RETURN(0);
}
-int ha_commit_rename(THD *thd)
-{
- int error=0;
-#ifdef HAVE_GEMINI_DB
- /* Gemini needs to commit the rename; otherwise a rollback will change
- ** the table names back internally but the physical files will still
- ** have the new names.
- */
- if (ha_commit_stmt(thd))
- error= -1;
- if (ha_commit(thd))
- error= -1;
-#endif
- return error;
-}
-
/* Tell the handler to turn on or off logging to the handler's
recovery log
*/
@@ -835,14 +780,6 @@ int ha_recovery_logging(THD *thd, bool on)
int error=0;
DBUG_ENTER("ha_recovery_logging");
-#ifdef USING_TRANSACTIONS
- if (opt_using_transactions)
- {
-#ifdef HAVE_GEMINI_DB
- error = gemini_recovery_logging(thd, on);
-#endif
- }
-#endif
DBUG_RETURN(error);
}
@@ -862,8 +799,10 @@ int handler::index_next_same(byte *buf, const byte *key, uint keylen)
/*
- The following is only needed if we would like to use the database
- for internal temporary tables
+ This is called to delete all rows in a table
+ If the handler don't support this, then this function will
+ return HA_ERR_WRONG_COMMAND and MySQL will delete the rows one
+ by one.
*/
int handler::delete_all_rows()
@@ -896,14 +835,16 @@ 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) {
- if (table.db_type == DB_TYPE_INNOBASE) {
+ if (error)
+ {
+ if (table.db_type == DB_TYPE_INNODB)
+ {
/* Creation of InnoDB table cannot fail because of an OS error:
put error as the number */
my_error(ER_CANT_CREATE_TABLE,MYF(ME_BELL+ME_WAITTANG),name,error);
- } else {
- my_error(ER_CANT_CREATE_TABLE,MYF(ME_BELL+ME_WAITTANG),name,my_errno);
}
+ else
+ my_error(ER_CANT_CREATE_TABLE,MYF(ME_BELL+ME_WAITTANG),name,my_errno);
}
DBUG_RETURN(error != 0);
}
@@ -921,5 +862,5 @@ 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(buff,MYF(MY_WME)));
+ return(my_delete_with_symlink(buff,MYF(MY_WME)));
}
diff --git a/sql/handler.h b/sql/handler.h
index 89c19993238..868badf4d49 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -21,11 +21,13 @@
#pragma interface /* gcc class implementation */
#endif
+#include <ft_global.h>
+
#ifndef NO_HASH
#define NO_HASH /* Not yet implemented */
#endif
-#if defined(HAVE_BERKELEY_DB) || defined(HAVE_INNOBASE_DB) || defined(HAVE_GEMINI_DB)
+#if defined(HAVE_BERKELEY_DB) || defined(HAVE_INNOBASE_DB)
#define USING_TRANSACTIONS
#endif
@@ -40,25 +42,21 @@
#define HA_ADMIN_INVALID -5
/* Bits in bas_flag to show what database can do */
-
#define HA_READ_NEXT 1 /* Read next record with same key */
#define HA_READ_PREV 2 /* Read prev. record with same key */
#define HA_READ_ORDER 4 /* Read through record-keys in order */
#define HA_READ_RND_SAME 8 /* Read RND-record to KEY-record
(To update with RND-read) */
#define HA_KEYPOS_TO_RNDPOS 16 /* ha_info gives pos to record */
-#define HA_LASTKEY_ORDER 32 /* Next record gives next record
- according last record read (even
- if database is updated after read) */
+#define HA_TABLE_SCAN_ON_INDEX 32 /* No separate data/index file */
#define HA_REC_NOT_IN_SEQ 64 /* ha_info don't return recnumber;
It returns a position to ha_r_rnd */
#define HA_ONLY_WHOLE_INDEX 128 /* Can't use part key searches */
-#define HA_RSAME_NO_INDEX 256 /* RSAME can't restore index */
+#define HA_NOT_READ_PREFIX_LAST 256 /* RSAME can't restore index */
#define HA_WRONG_ASCII_ORDER 512 /* Can't use sorting through key */
#define HA_HAVE_KEY_READ_ONLY 1024 /* Can read only keys (no record) */
#define HA_READ_NOT_EXACT_KEY 2048 /* Can read record after/before key */
#define HA_NO_INDEX 4096 /* No index needed for next/prev */
-#define HA_LONGLONG_KEYS 8192 /* Can have longlong as key */
#define HA_KEY_READ_WRONG_STR 16384 /* keyread returns converted strings */
#define HA_NULL_KEY 32768 /* One can have keys with NULL */
#define HA_DUPP_POS 65536 /* ha_position() gives dupp row */
@@ -74,7 +72,15 @@
#define HA_NOT_DELETE_WITH_CACHE (HA_NOT_READ_AFTER_KEY*2)
#define HA_NO_TEMP_TABLES (HA_NOT_DELETE_WITH_CACHE*2)
#define HA_NO_PREFIX_CHAR_KEYS (HA_NO_TEMP_TABLES*2)
-#define HA_NO_FULLTEXT_KEY (HA_NO_PREFIX_CHAR_KEYS*2)
+#define HA_CAN_FULLTEXT (HA_NO_PREFIX_CHAR_KEYS*2)
+#define HA_CAN_SQL_HANDLER (HA_CAN_FULLTEXT*2)
+
+/* Old not used flags */
+/*
+ Next record gives next record according last record read (even
+ if database is updated after read)
+*/
+#define HA_LASTKEY_ORDER 0
/* Parameters for open() (in register form->filestat) */
/* HA_GET_INFO does an implicit HA_ABORT_IF_LOCKED */
@@ -93,7 +99,7 @@
/* Error on write which is recoverable (Key exist) */
-#define HA_WRITE_SKIPP 121 /* Duplicate key on write */
+#define HA_WRITE_SKIP 121 /* Duplicate key on write */
#define HA_READ_CHECK 123 /* Update with is recoverable */
#define HA_CANT_DO_THAT 131 /* Databasehandler can't do it */
@@ -111,23 +117,27 @@ 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_INNOBASE, DB_TYPE_GEMINI,
+ DB_TYPE_BERKELEY_DB, DB_TYPE_INNODB, DB_TYPE_GEMINI,
DB_TYPE_DEFAULT };
-enum row_type { ROW_TYPE_DEFAULT, ROW_TYPE_FIXED, ROW_TYPE_DYNAMIC,
- ROW_TYPE_COMPRESSED };
+enum row_type { ROW_TYPE_NOT_USED=-1, ROW_TYPE_DEFAULT, ROW_TYPE_FIXED,
+ ROW_TYPE_DYNAMIC, ROW_TYPE_COMPRESSED};
/* 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_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
typedef struct st_thd_trans {
void *bdb_tid;
void *innobase_tid;
- void *gemini_tid;
bool innodb_active_trans;
} THD_TRANS;
@@ -143,6 +153,7 @@ typedef struct st_ha_create_information
ulonglong max_rows,min_rows;
ulonglong auto_increment_value;
char *comment,*password;
+ char *data_file_name, *index_file_name;
char *create_statement;
uint options; /* OR of HA_CREATE_ options */
uint raid_type,raid_chunks;
@@ -150,6 +161,7 @@ typedef struct st_ha_create_information
bool if_not_exists;
ulong used_fields;
SQL_LIST merge_list;
+ uint merge_insert_method;
} HA_CREATE_INFO;
@@ -162,14 +174,11 @@ extern ulong myisam_sort_buffer_size;
typedef struct st_ha_check_opt
{
ulong sort_buffer_size;
- uint flags;
- bool quick;
- bool changed_files;
- bool optimize;
- bool retry_without_quick;
+ uint flags; /* isam layer flags (e.g. for myisamchk) */
+ uint sql_flags; /* sql layer flags - for something myisamchk cannot do */
inline void init()
{
- flags= 0; quick= optimize= retry_without_quick=0;
+ flags= sql_flags= 0;
sort_buffer_size = myisam_sort_buffer_size;
}
} HA_CHECK_OPT;
@@ -201,7 +210,7 @@ public:
time_t check_time;
time_t update_time;
ulong mean_rec_length; /* physical reclength */
- void *ft_handler;
+ FT_INFO *ft_handler;
bool auto_increment_column_changed;
handler(TABLE *table_arg) : table(table_arg),active_index(MAX_REF_PARTS),
@@ -227,6 +236,7 @@ public:
virtual bool has_transactions(){ return 0;}
virtual uint extra_rec_buf_length() { return 0; }
virtual ha_rows estimate_number_of_rows() { return records+EXTRA_RECORDS; }
+ virtual const char *index_type(uint key_number) { return "";}
virtual int index_init(uint idx) { active_index=idx; return 0;}
virtual int index_end() {return 0; }
@@ -238,7 +248,7 @@ public:
virtual int update_row(const byte * old_data, byte * new_data)=0;
virtual int delete_row(const byte * buf)=0;
virtual int index_read(byte * buf, const byte * key,
- uint key_len, enum ha_rkey_function find_flag)=0;
+ uint key_len, enum ha_rkey_function find_flag)=0;
virtual int index_read_idx(byte * buf, uint index, const byte * key,
uint key_len, enum ha_rkey_function find_flag)=0;
virtual int index_next(byte * buf)=0;
@@ -246,17 +256,21 @@ public:
virtual int index_first(byte * buf)=0;
virtual int index_last(byte * buf)=0;
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 ft_init()
{ return -1; }
- virtual void *ft_init_ext(uint inx,const byte *key, uint keylen,
+ virtual FT_INFO *ft_init_ext(uint mode,uint inx,const byte *key, uint keylen,
bool presort)
- { return (void *)NULL; }
+ { return NULL; }
virtual int ft_read(byte *buf) { return -1; }
virtual int rnd_init(bool scan=1)=0;
virtual int rnd_end() { return 0; }
virtual int rnd_next(byte *buf)=0;
virtual int rnd_pos(byte * buf, byte *pos)=0;
- virtual int rnd_first(byte *buf);
+ virtual int read_first_row(byte *buf, uint primary_key);
virtual int restart_rnd_next(byte *buf, byte *pos);
virtual ha_rows records_in_range(int inx,
const byte *start_key,uint start_key_len,
@@ -320,17 +334,6 @@ public:
enum thr_lock_type lock_type)=0;
};
-#ifdef HAVE_GEMINI_DB
-struct st_gemini
-{
- void *context;
- unsigned long savepoint;
- bool needSavepoint;
- uint tx_isolation;
- uint lock_count;
-};
-#endif
-
/* Some extern variables used with handlers */
extern const char *ha_row_type[];
@@ -342,6 +345,8 @@ extern TYPELIB ha_table_typelib, tx_isolation_typelib;
#define ha_commit(thd) (ha_commit_trans((thd), &((thd)->transaction.all)))
#define ha_rollback(thd) (ha_rollback_trans((thd), &((thd)->transaction.all)))
+#define ha_supports_generate(T) (T != DB_TYPE_INNODB)
+
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);
@@ -364,5 +369,4 @@ int ha_rollback_trans(THD *thd, THD_TRANS *trans);
int ha_autocommit_or_rollback(THD *thd, int error);
void ha_set_spin_retries(uint retries);
bool ha_flush_logs(void);
-int ha_commit_rename(THD *thd);
int ha_recovery_logging(THD *thd, bool on);
diff --git a/sql/hash_filo.cc b/sql/hash_filo.cc
index 990d2d662d6..b85f8054f10 100644
--- a/sql/hash_filo.cc
+++ b/sql/hash_filo.cc
@@ -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 */
diff --git a/sql/hash_filo.h b/sql/hash_filo.h
index 157c2739add..b8d45f0d3be 100644
--- a/sql/hash_filo.h
+++ b/sql/hash_filo.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 */
@@ -24,7 +24,7 @@
#define HASH_FILO_H
#ifdef __GNUC__
-#pragma interface /* gcc class implementation */
+#pragma interface /* gcc class interface */
#endif
class hash_filo_element
diff --git a/sql/hostname.cc b/sql/hostname.cc
index bc812341337..7d4e4a8ca75 100644
--- a/sql/hostname.cc
+++ b/sql/hostname.cc
@@ -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 */
diff --git a/sql/init.cc b/sql/init.cc
index e6606b82b7c..df06ddd41ef 100644
--- a/sql/init.cc
+++ b/sql/init.cc
@@ -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 */
diff --git a/sql/item.cc b/sql/item.cc
index 0ce37cdd593..dac10eafafb 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -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 */
@@ -37,7 +37,7 @@ void item_init(void)
Item::Item()
{
marker=0;
- binary=maybe_null=null_value=with_sum_func=0;
+ binary=maybe_null=null_value=with_sum_func=unsigned_flag=0;
name=0;
decimals=0; max_length=0;
next=current_thd->free_list; // Put in free list
@@ -132,6 +132,7 @@ void Item_field::set_field(Field *field_par)
table_name=field_par->table_name;
field_name=field_par->field_name;
binary=field_par->binary();
+ unsigned_flag=test(field_par->flags & UNSIGNED_FLAG);
}
const char *Item_ident::full_name() const
@@ -247,6 +248,22 @@ void Item_int::print(String *str)
str->append(name);
}
+String *Item_uint::val_str(String *str)
+{
+ str->set((ulonglong) value);
+ return str;
+}
+
+void Item_uint::print(String *str)
+{
+ if (!name)
+ {
+ str_value.set((ulonglong) value);
+ name=str_value.c_ptr();
+ }
+ str->append(name);
+}
+
String *Item_real::val_str(String *str)
{
@@ -299,13 +316,21 @@ bool Item::fix_fields(THD *thd,
bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables)
{
- if (!field)
+ if (!field) // If field is not checked
{
Field *tmp;
if (!(tmp=find_field_in_tables(thd,this,tables)))
return 1;
set_field(tmp);
}
+ else if (thd && thd->set_query_id && field->query_id != thd->query_id)
+ {
+ /* We only come here in unions */
+ TABLE *table=field->table;
+ field->query_id=thd->query_id;
+ table->used_fields++;
+ table->used_keys&=field->part_of_key;
+ }
return 0;
}
@@ -319,6 +344,8 @@ void Item::init_make_field(Send_field *tmp_field,
tmp_field->type=field_type;
tmp_field->length=max_length;
tmp_field->decimals=decimals;
+ if (unsigned_flag)
+ tmp_field->flags |= UNSIGNED_FLAG;
}
/* ARGSUSED */
@@ -334,6 +361,13 @@ void Item_int::make_field(Send_field *tmp_field)
init_make_field(tmp_field,FIELD_TYPE_LONGLONG);
}
+void Item_uint::make_field(Send_field *tmp_field)
+{
+ init_make_field(tmp_field,FIELD_TYPE_LONGLONG);
+ tmp_field->flags|= UNSIGNED_FLAG;
+ unsigned_flag=1;
+}
+
void Item_real::make_field(Send_field *tmp_field)
{
init_make_field(tmp_field,FIELD_TYPE_DOUBLE);
@@ -552,19 +586,19 @@ void Item_varbinary::make_field(Send_field *tmp_field)
** pack data in buffer for sending
*/
-bool Item::send(String *packet)
+bool Item::send(THD *thd, String *packet)
{
char buff[MAX_FIELD_WIDTH];
+ CONVERT *convert;
String s(buff,sizeof(buff)),*res;
if (!(res=val_str(&s)))
return net_store_null(packet);
- CONVERT *convert;
- if ((convert=current_thd->convert_set))
+ if ((convert=thd->convert_set))
return convert->store(packet,res->ptr(),res->length());
return net_store_data(packet,res->ptr(),res->length());
}
-bool Item_null::send(String *packet)
+bool Item_null::send(THD *thd, String *packet)
{
return net_store_null(packet);
}
@@ -578,7 +612,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables)
{
if (!ref)
{
- if (!(ref=find_item_in_list(this,thd->lex.item_list)))
+ if (!(ref=find_item_in_list(this,thd->lex.select->item_list)))
return 1;
max_length= (*ref)->max_length;
maybe_null= (*ref)->maybe_null;
@@ -694,5 +728,6 @@ bool field_is_equal_to_item(Field *field,Item *item)
#ifdef __GNUC__
template class List<Item>;
template class List_iterator<Item>;
+template class List_iterator_fast<Item>;
template class List<List_item>;
#endif
diff --git a/sql/item.h b/sql/item.h
index 41b897956db..575af197e7d 100644
--- a/sql/item.h
+++ b/sql/item.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 */
@@ -23,7 +23,7 @@ struct st_table_list;
void item_init(void); /* Init item functions */
class Item {
- Item(const Item &); /* Prevent use of theese */
+ Item(const Item &); /* Prevent use of these */
void operator=(Item &);
public:
static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); }
@@ -43,6 +43,7 @@ public:
my_bool maybe_null; /* If item may be null */
my_bool null_value; /* if item is null */
my_bool binary;
+ my_bool unsigned_flag;
my_bool with_sum_func;
@@ -55,7 +56,7 @@ public:
virtual bool save_in_field(Field *field);
virtual void save_org_in_field(Field *field)
{ (void) save_in_field(field); }
- virtual bool send(String *str);
+ virtual bool send(THD *thd, String *str);
virtual bool eq(const Item *, bool binary_cmp) const;
virtual Item_result result_type () const { return REAL_RESULT; }
virtual enum Type type() const =0;
@@ -63,7 +64,7 @@ public:
virtual longlong val_int()=0;
virtual String *val_str(String*)=0;
virtual void make_field(Send_field *field)=0;
- virtual Field *tmp_table_field() { return 0; }
+ virtual Field *tmp_table_field(TABLE *t_arg=(TABLE *)0) { return 0; }
virtual const char *full_name() const { return name ? name : "???"; }
virtual double val_result() { return val(); }
virtual longlong val_int_result() { return val_int(); }
@@ -80,6 +81,7 @@ public:
virtual void split_sum_func(List<Item> &fields) {}
virtual bool get_date(TIME *ltime,bool fuzzydate);
virtual bool get_time(TIME *ltime);
+ virtual bool is_null() { return 0; }
};
@@ -116,7 +118,7 @@ public:
double val_result();
longlong val_int_result();
String *str_result(String* tmp);
- bool send(String *str_arg) { return result_field->send(str_arg); }
+ bool send(THD *thd, String *str_arg) { return result_field->send(thd,str_arg); }
void make_field(Send_field *field);
bool fix_fields(THD *,struct st_table_list *);
bool save_in_field(Field *field);
@@ -126,9 +128,10 @@ public:
{
return field->result_type();
}
- Field *tmp_table_field() { return result_field; }
+ Field *tmp_table_field(TABLE *t_arg=(TABLE *)0) { return result_field; }
bool get_date(TIME *ltime,bool fuzzydate);
bool get_time(TIME *ltime);
+ bool is_null() { return field->is_null(); }
};
@@ -146,9 +149,10 @@ public:
bool save_in_field(Field *field);
enum Item_result result_type () const
{ return STRING_RESULT; }
- bool send(String *str);
+ bool send(THD *thd, String *str);
bool basic_const_item() const { return 1; }
Item *new_item() { return new Item_null(name); }
+ bool is_null() { return 1; }
};
@@ -181,6 +185,19 @@ public:
};
+class Item_uint :public Item_int
+{
+public:
+ Item_uint(const char *str_arg, uint length) :
+ Item_int(str_arg, (longlong) strtoull(str_arg,(char**) 0,10), length) {}
+ double val() { return ulonglong2double(value); }
+ String *val_str(String*);
+ void make_field(Send_field *field);
+ Item *new_item() { return new Item_uint(name,max_length); }
+ void print(String *str);
+};
+
+
class Item_real :public Item
{
public:
@@ -189,14 +206,14 @@ public:
Item_real(const char *str_arg,uint length) :value(atof(str_arg))
{
name=(char*) str_arg;
- decimals=nr_of_decimals(str_arg);
+ decimals=(uint8) nr_of_decimals(str_arg);
max_length=length;
}
Item_real(const char *str,double val_arg,uint decimal_par,uint length)
:value(val_arg)
{
name=(char*) str;
- decimals=decimal_par;
+ decimals=(uint8) decimal_par;
max_length=length;
}
Item_real(double value_par) :value(value_par) {}
@@ -292,7 +309,7 @@ public:
Field *result_field; /* Save result here */
Item_result_field() :result_field(0) {}
~Item_result_field() {} /* Required with gcc 2.95 */
- Field *tmp_table_field() { return result_field; }
+ Field *tmp_table_field(TABLE *t_arg=(TABLE *)0) { return result_field; }
table_map used_tables() const { return 1; }
virtual void fix_length_and_dec()=0;
};
@@ -328,11 +345,16 @@ public:
null_value=(*ref)->null_value;
return tmp;
}
+ bool is_null()
+ {
+ (void) (*ref)->val_int_result();
+ return (*ref)->null_value;
+ }
bool get_date(TIME *ltime,bool fuzzydate)
{
return (null_value=(*ref)->get_date(ltime,fuzzydate));
}
- bool send(String *tmp) { return (*ref)->send(tmp); }
+ bool send(THD *thd, String *tmp) { return (*ref)->send(thd, tmp); }
void make_field(Send_field *field) { (*ref)->make_field(field); }
bool fix_fields(THD *,struct st_table_list *);
bool save_in_field(Field *field) { return (*ref)->save_in_field(field); }
@@ -372,6 +394,7 @@ public:
void copy();
table_map used_tables() const { return (table_map) 1L; }
bool const_item() const { return 0; }
+ bool is_null() { return null_value; }
};
diff --git a/sql/item_buff.cc b/sql/item_buff.cc
index 61e1f5498a9..b55a4dc66a0 100644
--- a/sql/item_buff.cc
+++ b/sql/item_buff.cc
@@ -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 */
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 373aede7b6b..0c83698e60a 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -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 */
@@ -254,7 +254,7 @@ longlong Item_func_strcmp::val_int()
null_value=1;
return 0;
}
- int value=stringcmp(a,b);
+ int value= binary ? stringcmp(a,b) : sortcmp(a,b);
null_value=0;
return !value ? 0 : (value < 0 ? (longlong) -1 : (longlong) 1);
}
@@ -955,7 +955,7 @@ void Item_func_in::fix_length_and_dec()
for (uint i=0 ; i < arg_count ; i++)
{
array->set(j,args[i]);
- if (!args[i]->null_value) // Skipp NULL values
+ if (!args[i]->null_value) // Skip NULL values
j++;
}
if ((array->used_count=j))
@@ -1129,7 +1129,7 @@ void Item_cond::update_used_tables()
{
used_tables_cache=0;
const_item_cache=1;
- List_iterator<Item> li(list);
+ List_iterator_fast<Item> li(list);
Item *item;
while ((item=li++))
{
@@ -1143,7 +1143,7 @@ void Item_cond::update_used_tables()
void Item_cond::print(String *str)
{
str->append('(');
- List_iterator<Item> li(list);
+ List_iterator_fast<Item> li(list);
Item *item;
if ((item=li++))
item->print(str);
@@ -1160,7 +1160,7 @@ void Item_cond::print(String *str)
longlong Item_cond_and::val_int()
{
- List_iterator<Item> li(list);
+ List_iterator_fast<Item> li(list);
Item *item;
while ((item=li++))
{
@@ -1179,7 +1179,7 @@ longlong Item_cond_and::val_int()
longlong Item_cond_or::val_int()
{
- List_iterator<Item> li(list);
+ List_iterator_fast<Item> li(list);
Item *item;
null_value=0;
while ((item=li++))
@@ -1197,14 +1197,12 @@ longlong Item_cond_or::val_int()
longlong Item_func_isnull::val_int()
{
- (void) args[0]->val();
- return (args[0]->null_value) ? 1 : 0;
+ return args[0]->is_null() ? 1: 0;
}
longlong Item_func_isnotnull::val_int()
{
- (void) args[0]->val();
- return !(args[0]->null_value) ? 1 : 0;
+ return args[0]->is_null() ? 0 : 1;
}
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 5ee0687c064..c9c7d5654d6 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.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 */
@@ -46,6 +46,7 @@ public:
virtual enum Functype rev_functype() const { return UNKNOWN_FUNC; }
bool have_rev_func() const { return rev_functype() != UNKNOWN_FUNC; }
void print(String *str) { Item_func::print_op(str); }
+ bool is_null() { return test(args[0]->is_null() || args[1]->is_null()); }
};
@@ -459,7 +460,10 @@ public:
Item_func_isnotnull(Item *a) :Item_bool_func(a) {}
longlong val_int();
enum Functype functype() const { return ISNOTNULL_FUNC; }
- void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=0; }
+ void fix_length_and_dec()
+ {
+ decimals=0; max_length=1; maybe_null=0;
+ }
const char *func_name() const { return "isnotnull"; }
optimize_type select_optimize() const { return OPTIMIZE_NULL; }
};
diff --git a/sql/item_create.cc b/sql/item_create.cc
index ef9f5f2d38b..6f64e9517ba 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -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 */
@@ -65,7 +65,9 @@ Item *create_func_ceiling(Item* a)
Item *create_func_connection_id(void)
{
- return new Item_int("CONNECTION_ID()",(longlong) current_thd->thread_id,10);
+ THD *thd=current_thd;
+ thd->safe_to_cache_query=0;
+ return new Item_int("CONNECTION_ID()",(longlong) thd->thread_id,10);
}
Item *create_func_conv(Item* a, Item *b, Item *c)
@@ -129,6 +131,13 @@ Item *create_func_floor(Item* a)
return new Item_func_floor(a);
}
+Item *create_func_found_rows(void)
+{
+ THD *thd=current_thd;
+ thd->safe_to_cache_query=0;
+ return new Item_int("FOUND_ROWS()",(longlong) thd->found_rows(),21);
+}
+
Item *create_func_from_days(Item* a)
{
return new Item_func_from_days(a);
@@ -136,13 +145,13 @@ Item *create_func_from_days(Item* a)
Item *create_func_get_lock(Item* a, Item *b)
{
+ current_thd->safe_to_cache_query=0;
return new Item_func_get_lock(a, b);
}
Item *create_func_hex(Item *a)
{
- return new Item_func_conv(a,new Item_int((int32) 10,2),
- new Item_int((int32) 16,2));
+ return new Item_func_hex(a);
}
Item *create_func_inet_ntoa(Item* a)
@@ -191,6 +200,11 @@ Item *create_func_length(Item* a)
return new Item_func_length(a);
}
+Item *create_func_bit_length(Item* a)
+{
+ return new Item_func_bit_length(a);
+}
+
Item *create_func_char_length(Item* a)
{
return new Item_func_char_length(a);
@@ -274,6 +288,7 @@ Item *create_func_radians(Item *a)
Item *create_func_release_lock(Item* a)
{
+ current_thd->safe_to_cache_query=0;
return new Item_func_release_lock(a);
}
@@ -374,10 +389,27 @@ Item *create_func_year(Item* a)
Item *create_load_file(Item* a)
{
+ current_thd->safe_to_cache_query=0;
return new Item_load_file(a);
}
Item *create_wait_for_master_pos(Item* a, Item* b)
{
+ current_thd->safe_to_cache_query=0;
return new Item_master_pos_wait(a, b);
}
+
+Item *create_func_cast(Item *a, Item_cast cast_type)
+{
+ Item *res;
+ LINT_INIT(res);
+ switch (cast_type) {
+ case ITEM_CAST_BINARY: res= new Item_func_binary(a); break;
+ case ITEM_CAST_SIGNED_INT: res= new Item_func_signed(a); break;
+ case ITEM_CAST_UNSIGNED_INT: res= new Item_func_unsigned(a); break;
+ 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;
+ }
+ return res;
+}
diff --git a/sql/item_create.h b/sql/item_create.h
index cc7497b0183..580596505da 100644
--- a/sql/item_create.h
+++ b/sql/item_create.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 */
@@ -22,6 +22,7 @@ Item *create_func_ascii(Item* a);
Item *create_func_asin(Item* a);
Item *create_func_bin(Item* a);
Item *create_func_bit_count(Item* a);
+Item *create_func_bit_length(Item* a);
Item *create_func_ceiling(Item* a);
Item *create_func_char_length(Item* a);
Item *create_func_connection_id(void);
@@ -37,6 +38,7 @@ Item *create_func_degrees(Item *);
Item *create_func_exp(Item* a);
Item *create_func_find_in_set(Item* a, Item *b);
Item *create_func_floor(Item* a);
+Item *create_func_found_rows(void);
Item *create_func_from_days(Item* a);
Item *create_func_get_lock(Item* a, Item *b);
Item *create_func_hex(Item *a);
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 9f94a25cbf9..e643075b0bc 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -43,7 +43,7 @@ Item_func::Item_func(List<Item> &list)
if ((args=(Item**) sql_alloc(sizeof(Item*)*arg_count)))
{
uint i=0;
- List_iterator<Item> li(list);
+ List_iterator_fast<Item> li(list);
Item *item;
while ((item=li++))
@@ -184,8 +184,10 @@ String *Item_num_func::val_str(String *str)
longlong nr=val_int();
if (null_value)
return 0; /* purecov: inspected */
- else
+ else if (!unsigned_flag)
str->set(nr);
+ else
+ str->set((ulonglong) nr);
}
else
{
@@ -207,24 +209,31 @@ void Item_func::fix_num_length_and_dec()
max_length=float_length(decimals);
}
-
String *Item_int_func::val_str(String *str)
{
longlong nr=val_int();
if (null_value)
return 0;
- else
+ else if (!unsigned_flag)
str->set(nr);
+ else
+ str->set((ulonglong) nr);
return str;
}
-/* Change from REAL_RESULT (default) to INT_RESULT if both arguments are integers */
+/*
+ Change from REAL_RESULT (default) to INT_RESULT if both arguments are
+ integers
+*/
void Item_num_op::find_num_type(void)
{
if (args[0]->result_type() == INT_RESULT &&
args[1]->result_type() == INT_RESULT)
+ {
hybrid_type=INT_RESULT;
+ unsigned_flag=args[0]->unsigned_flag | args[1]->unsigned_flag;
+ }
}
String *Item_num_op::val_str(String *str)
@@ -234,8 +243,10 @@ String *Item_num_op::val_str(String *str)
longlong nr=val_int();
if (null_value)
return 0; /* purecov: inspected */
- else
+ else if (!unsigned_flag)
str->set(nr);
+ else
+ str->set((ulonglong) nr);
}
else
{
@@ -269,6 +280,21 @@ longlong Item_func_plus::val_int()
return (longlong) Item_func_plus::val();
}
+
+/*
+ The following function is here to allow the user to force
+ subtraction of UNSIGNED BIGINT to return negative values.
+*/
+
+void Item_func_minus::fix_length_and_dec()
+{
+ Item_num_op::fix_length_and_dec();
+ if (unsigned_flag &&
+ (current_thd->sql_mode & MODE_NO_UNSIGNED_SUBTRACTION))
+ unsigned_flag=0;
+}
+
+
double Item_func_minus::val()
{
double value=args[0]->val() - args[1]->val();
@@ -610,8 +636,9 @@ double Item_func_rand::val()
{
if (arg_count)
{ // Only use argument once in query
- ulong tmp=((ulong) args[0]->val_int())+55555555L;
- randominit(&current_thd->rand,tmp,tmp/2);
+ uint32 tmp= (uint32) (args[0]->val_int());
+ randominit(&current_thd->rand,(uint32) (tmp*0x10001L+55555555L),
+ (uint32) (tmp*0x10000001L));
#ifdef DELETE_ITEMS
delete args[0];
#endif
@@ -667,8 +694,10 @@ String *Item_func_min_max::val_str(String *str)
longlong nr=val_int();
if (null_value)
return 0;
- else
+ else if (!unsigned_flag)
str->set(nr);
+ else
+ str->set((ulonglong) nr);
return str;
}
case REAL_RESULT:
@@ -784,9 +813,7 @@ longlong Item_func_locate::val_int()
{
String *a=args[0]->val_str(&value1);
String *b=args[1]->val_str(&value2);
-#ifdef USE_MB
bool binary_str = args[0]->binary || args[1]->binary;
-#endif
if (!a || !b)
{
null_value=1;
@@ -840,7 +867,8 @@ longlong Item_func_locate::val_int()
return 0;
}
#endif /* USE_MB */
- return (longlong) (a->strstr(*b,start)+1) ;
+ return (longlong) (binary ? a->strstr(*b,start) :
+ (a->strstr_case(*b,start)))+1;
}
@@ -1050,7 +1078,8 @@ udf_handler::~udf_handler()
}
free_udf(u_d);
}
- delete [] buffers;
+ if (buffers) // Because of bug in ecc
+ delete [] buffers;
}
@@ -1306,8 +1335,10 @@ String *Item_func_udf_int::val_str(String *str)
longlong nr=val_int();
if (null_value)
return 0;
- else
+ else if (!unsigned_flag)
str->set(nr);
+ else
+ str->set((ulonglong) nr);
return str;
}
@@ -1402,19 +1433,19 @@ void item_user_lock_release(ULL *ull)
if (mysql_bin_log.is_open())
{
THD *thd = current_thd;
- int save_errno;
+ uint save_query_length;
char buf[256];
String tmp(buf,sizeof(buf));
tmp.length(0);
tmp.append("DO RELEASE_LOCK(\"");
tmp.append(ull->key,ull->key_length);
tmp.append("\")");
- save_errno=thd->net.last_errno;
- thd->net.last_errno=0;
+ save_query_length=thd->query_length;
thd->query_length=tmp.length();
Query_log_event qev(thd,tmp.ptr());
+ qev.error_code=0; // this query is always safe to run on slave
mysql_bin_log.write(&qev);
- thd->net.last_errno=save_errno;
+ thd->query_length=save_query_length;
}
if (--ull->count)
pthread_cond_signal(&ull->cond);
@@ -1432,7 +1463,7 @@ longlong Item_master_pos_wait::val_int()
THD* thd = current_thd;
String *log_name = args[0]->val_str(&value);
int event_count;
-
+
null_value=0;
if (thd->slave_thread || !log_name || !log_name->length())
{
@@ -1440,14 +1471,83 @@ longlong Item_master_pos_wait::val_int()
return 0;
}
ulong pos = (ulong)args[1]->val_int();
- if ((event_count = glob_mi.wait_for_pos(thd, log_name, pos)) == -1)
+ LOCK_ACTIVE_MI;
+ if ((event_count = active_mi->rli.wait_for_pos(thd, log_name, pos)) == -1)
{
null_value = 1;
event_count=0;
}
+ UNLOCK_ACTIVE_MI;
return event_count;
}
+#ifdef EXTRA_DEBUG
+void debug_sync_point(const char* lock_name, uint lock_timeout)
+{
+ THD* thd=current_thd;
+ ULL* ull;
+ struct timespec abstime;
+ int lock_name_len,error=0;
+ lock_name_len=strlen(lock_name);
+ pthread_mutex_lock(&LOCK_user_locks);
+
+ if (thd->ull)
+ {
+ item_user_lock_release(thd->ull);
+ thd->ull=0;
+ }
+
+ /* if the lock has not been aquired by some client, we do not want to
+ create an entry for it, since we immediately release the lock. In
+ this case, we will not be waiting, but rather, just waste CPU and
+ memory on the whole deal
+ */
+ if (!(ull= ((ULL*) hash_search(&hash_user_locks,lock_name,
+ lock_name_len))))
+ {
+ pthread_mutex_unlock(&LOCK_user_locks);
+ return;
+ }
+ ull->count++;
+
+ /* structure is now initialized. Try to get the lock */
+ /* Set up control struct to allow others to abort locks */
+ thd->proc_info="User lock";
+ thd->mysys_var->current_mutex= &LOCK_user_locks;
+ thd->mysys_var->current_cond= &ull->cond;
+
+ set_timespec(abstime,lock_timeout);
+ while (!thd->killed &&
+ (error=pthread_cond_timedwait(&ull->cond,&LOCK_user_locks,&abstime))
+ != ETIME && error != ETIMEDOUT && ull->locked) ;
+ if (ull->locked)
+ {
+ if (!--ull->count)
+ delete ull; // Should never happen
+ }
+ else
+ {
+ ull->locked=1;
+ ull->thread=thd->real_id;
+ thd->ull=ull;
+ }
+ pthread_mutex_unlock(&LOCK_user_locks);
+ pthread_mutex_lock(&thd->mysys_var->mutex);
+ thd->proc_info=0;
+ thd->mysys_var->current_mutex= 0;
+ thd->mysys_var->current_cond= 0;
+ pthread_mutex_unlock(&thd->mysys_var->mutex);
+ pthread_mutex_lock(&LOCK_user_locks);
+ if (thd->ull)
+ {
+ item_user_lock_release(thd->ull);
+ thd->ull=0;
+ }
+ pthread_mutex_unlock(&LOCK_user_locks);
+}
+
+#endif
+
/*
Get a user level lock. If the thread has an old lock this is first released.
Returns 1: Got lock
@@ -1504,14 +1604,7 @@ longlong Item_func_get_lock::val_int()
thd->mysys_var->current_mutex= &LOCK_user_locks;
thd->mysys_var->current_cond= &ull->cond;
-#ifdef HAVE_TIMESPEC_TS_SEC
- abstime.ts_sec=time((time_t*) 0)+(time_t) timeout;
- abstime.ts_nsec=0;
-#else
- abstime.tv_sec=time((time_t*) 0)+(time_t) timeout;
- abstime.tv_nsec=0;
-#endif
-
+ set_timespec(abstime,timeout);
while (!thd->killed &&
(error=pthread_cond_timedwait(&ull->cond,&LOCK_user_locks,&abstime))
!= ETIME && error != ETIMEDOUT && ull->locked) ;
@@ -1941,44 +2034,6 @@ err:
return 0;
}
-double Item_func_match::val()
-{
- if (ft_handler==NULL)
- return -1.0;
-
- if (join_key)
- {
- if (table->file->ft_handler)
- return ft_get_relevance(ft_handler);
-
- join_key=0; // Magic here ! See ha_myisam::ft_read()
- }
-
- /* we'll have to find ft_relevance manually in ft_handler array */
-
- int a,b,c;
- FT_DOC *docs=ft_handler->doc;
- my_off_t docid=table->file->row_position();
-
- if ((null_value=(docid==HA_OFFSET_ERROR)))
- return 0.0;
-
- // Assuming docs[] is sorted by dpos...
-
- for (a=0, b=ft_handler->ndocs, c=(a+b)/2; b-a>1; c=(a+b)/2)
- {
- if (docs[c].dpos > docid)
- b=c;
- else
- a=c;
- }
- if (docs[a].dpos == docid)
- return docs[a].weight;
- else
- return 0.0;
-
-}
-
void Item_func_match::init_search(bool no_order)
{
if (ft_handler)
@@ -1993,20 +2048,24 @@ void Item_func_match::init_search(bool no_order)
return;
}
+ if (key == NO_SUCH_KEY)
+ concat=new Item_func_concat_ws (new Item_string(" ",1), fields);
+
String *ft_tmp=0;
char tmp1[FT_QUERY_MAXLEN];
String tmp2(tmp1,sizeof(tmp1));
- // MATCH ... AGAINST (NULL) is meaningless, but possible
+ // MATCH ... AGAINST (NULL) is meaningless, but possible
if (!(ft_tmp=key_item()->val_str(&tmp2)))
{
ft_tmp=&tmp2;
tmp2.set("",0);
}
- ft_handler=(FT_DOCLIST *)
- table->file->ft_init_ext(key, (byte*) ft_tmp->ptr(), ft_tmp->length(),
- join_key && !no_order);
+ ft_handler=table->file->ft_init_ext(mode, key,
+ (byte*) ft_tmp->ptr(),
+ ft_tmp->length(),
+ join_key && !no_order);
if (join_key)
{
@@ -2023,12 +2082,11 @@ bool Item_func_match::fix_fields(THD *thd,struct st_table_list *tlist)
maybe_null=1;
join_key=0;
- /* Serg:
- I'd rather say now that const_item is assumed in quite a bit of
- places, so it would be difficult to remove; If it would ever to be
- removed, this should include modifications to find_best and auto_close
- as complement to auto_init code above.
- */
+ /* const_item is assumed in quite a bit of places, so it would be difficult
+ to remove; If it would ever to be removed, this should include
+ modifications to find_best and auto_close as complement to auto_init code
+ above.
+ */
if (Item_func::fix_fields(thd,tlist) || !const_item())
{
my_error(ER_WRONG_ARGUMENTS,MYF(0),"AGAINST");
@@ -2042,29 +2100,33 @@ bool Item_func_match::fix_fields(THD *thd,struct st_table_list *tlist)
if (item->type() == Item::REF_ITEM)
li.replace(item= *((Item_ref *)item)->ref);
if (item->type() != Item::FIELD_ITEM || !item->used_tables())
- {
- my_error(ER_WRONG_ARGUMENTS,MYF(0),"MATCH");
- return 1;
- }
+ key=NO_SUCH_KEY;
used_tables_cache|=item->used_tables();
}
/* check that all columns come from the same table */
if (count_bits(used_tables_cache) != 1)
+ key=NO_SUCH_KEY;
+ const_item_cache=0;
+ table=((Item_field *)fields.head())->field->table;
+ table->fulltext_searched=1;
+ record=table->record[0];
+ if (key == NO_SUCH_KEY && mode != FT_BOOL)
{
my_error(ER_WRONG_ARGUMENTS,MYF(0),"MATCH");
return 1;
}
- const_item_cache=0;
- table=((Item_field *)fields.head())->field->table;
return 0;
}
-
bool Item_func_match::fix_index()
{
- List_iterator<Item> li(fields);
+ List_iterator_fast<Item> li(fields);
Item_field *item;
uint ft_to_key[MAX_KEY], ft_cnt[MAX_KEY], fts=0, key;
+ uint max_cnt=0, mkeys=0;
+
+ if (this->key == NO_SUCH_KEY)
+ return 0;
for (key=0 ; key<table->keys ; key++)
{
@@ -2078,11 +2140,7 @@ bool Item_func_match::fix_index()
}
if (!fts)
- {
- my_printf_error(ER_FT_MATCHING_KEY_NOT_FOUND,
- ER(ER_FT_MATCHING_KEY_NOT_FOUND),MYF(0));
- return 1;
- }
+ goto err;
while ((item=(Item_field*)(li++)))
{
@@ -2099,7 +2157,6 @@ bool Item_func_match::fix_index()
}
}
- uint max_cnt=0, mkeys=0;
for (key=0 ; key<fts ; key++)
{
if (ft_cnt[key] > max_cnt)
@@ -2130,6 +2187,12 @@ bool Item_func_match::fix_index()
return 0;
}
+err:
+ if (mode == FT_BOOL)
+ {
+ this->key=NO_SUCH_KEY;
+ return 0;
+ }
my_printf_error(ER_FT_MATCHING_KEY_NOT_FOUND,
ER(ER_FT_MATCHING_KEY_NOT_FOUND),MYF(0));
return 1;
@@ -2152,6 +2215,30 @@ bool Item_func_match::eq(const Item *item, bool binary_cmp) const
return 0;
}
+double Item_func_match::val()
+{
+ if (ft_handler == NULL)
+ return -1.0;
+
+ if (join_key)
+ {
+ if (table->file->ft_handler)
+ return ft_handler->please->get_relevance(ft_handler);
+
+ join_key=0;
+ }
+
+ if (key == NO_SUCH_KEY)
+ {
+ String *a=concat->val_str(&value);
+ if ((null_value= (a==0)))
+ return 0;
+ return ft_handler->please->find_relevance(ft_handler,
+ (byte *)a->ptr(), a->length());
+ }
+ else
+ return ft_handler->please->find_relevance(ft_handler, record, 0);
+}
/***************************************************************************
System variables
diff --git a/sql/item_func.h b/sql/item_func.h
index 35af4540f7c..c3e437712ee 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -119,6 +119,7 @@ public:
{
return (null_value=args[0]->get_time(ltime));
}
+ bool is_null() { (void) val_int(); return null_value; }
friend class udf_handler;
};
@@ -134,6 +135,11 @@ public:
longlong val_int() { return (longlong) val(); }
enum Item_result result_type () const { return REAL_RESULT; }
void fix_length_and_dec() { decimals=NOT_FIXED_DEC; max_length=float_length(decimals); }
+ Field *tmp_table_field(TABLE *t_arg)
+ {
+ if (!t_arg) return result_field;
+ return new Field_double(max_length, maybe_null, name,t_arg,decimals);
+ }
};
class Item_num_func :public Item_func
@@ -147,6 +153,7 @@ public:
longlong val_int() { return (longlong) val(); }
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; }
};
@@ -161,23 +168,55 @@ class Item_num_op :public Item_func
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; }
+ Field *tmp_table_field(TABLE *t_arg)
+ {
+ if (!t_arg) return result_field;
+ return args[0]->result_type() == INT_RESULT ? ((max_length > 11) ? (Field *)new Field_longlong(max_length,maybe_null,name, t_arg,unsigned_flag) : (Field *)new Field_long(max_length,maybe_null,name, t_arg,unsigned_flag)) : (Field *) new Field_double(max_length, maybe_null, name,t_arg,decimals);
+ }
};
class Item_int_func :public Item_func
{
public:
- Item_int_func() :Item_func() {}
- Item_int_func(Item *a) :Item_func(a) {}
- Item_int_func(Item *a,Item *b) :Item_func(a,b) {}
- Item_int_func(Item *a,Item *b,Item *c) :Item_func(a,b,c) {}
- Item_int_func(List<Item> &list) :Item_func(list) {}
+ 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; }
double val() { return (double) 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() {}
+ Field *tmp_table_field(TABLE *t_arg)
+ {
+ if (!t_arg) return result_field;
+ return (max_length > 11) ? (Field *)new Field_longlong(max_length,maybe_null,name, t_arg,unsigned_flag) : (Field *)new Field_long(max_length,maybe_null,name, t_arg,unsigned_flag);
+ }
+};
+
+class Item_func_signed :public Item_int_func
+{
+public:
+ Item_func_signed(Item *a) :Item_int_func(a) {}
+ double val() { return args[0]->val(); }
+ longlong val_int() { return args[0]->val_int(); }
+ void fix_length_and_dec()
+ { max_length=args[0]->max_length; unsigned_flag=0; }
+};
+
+class Item_func_unsigned :public Item_int_func
+{
+public:
+ Item_func_unsigned(Item *a) :Item_int_func(a) {}
+ double val() { return args[0]->val(); }
+ longlong val_int() { return args[0]->val_int(); }
+ void fix_length_and_dec()
+ { max_length=args[0]->max_length; unsigned_flag=1; }
};
+
class Item_func_plus :public Item_num_op
{
public:
@@ -194,8 +233,10 @@ public:
const char *func_name() const { return "-"; }
double val();
longlong val_int();
+ void fix_length_and_dec();
};
+
class Item_func_mul :public Item_num_op
{
public:
@@ -483,6 +524,14 @@ public:
void fix_length_and_dec() { max_length=10; }
};
+class Item_func_bit_length :public Item_func_length
+{
+public:
+ Item_func_bit_length(Item *a) :Item_func_length(a) {}
+ longlong val_int() { return Item_func_length::val_int()*8; }
+ const char *func_name() const { return "bit_length"; }
+};
+
class Item_func_char_length :public Item_int_func
{
String value;
@@ -551,7 +600,6 @@ public:
Item_func_ord(Item *a) :Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "ord"; }
- void fix_length_and_dec() { max_length=21; }
};
class Item_func_find_in_set :public Item_int_func
@@ -573,7 +621,7 @@ public:
Item_func_bit_or(Item *a,Item *b) :Item_int_func(a,b) {}
longlong val_int();
const char *func_name() const { return "|"; }
- void fix_length_and_dec() { decimals=0; max_length=21; }
+ void fix_length_and_dec() { unsigned_flag=1; }
};
class Item_func_bit_and :public Item_int_func
@@ -582,7 +630,7 @@ public:
Item_func_bit_and(Item *a,Item *b) :Item_int_func(a,b) {}
longlong val_int();
const char *func_name() const { return "&"; }
- void fix_length_and_dec() { decimals=0; max_length=21; }
+ void fix_length_and_dec() { unsigned_flag=1; }
};
class Item_func_bit_count :public Item_int_func
@@ -591,7 +639,7 @@ public:
Item_func_bit_count(Item *a) :Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "bit_count"; }
- void fix_length_and_dec() { decimals=0; max_length=2; }
+ void fix_length_and_dec() { max_length=2; }
};
class Item_func_shift_left :public Item_int_func
@@ -600,7 +648,7 @@ public:
Item_func_shift_left(Item *a,Item *b) :Item_int_func(a,b) {}
longlong val_int();
const char *func_name() const { return "<<"; }
- void fix_length_and_dec() { decimals=0; max_length=21; }
+ void fix_length_and_dec() { unsigned_flag=1; }
};
class Item_func_shift_right :public Item_int_func
@@ -609,7 +657,6 @@ public:
Item_func_shift_right(Item *a,Item *b) :Item_int_func(a,b) {}
longlong val_int();
const char *func_name() const { return ">>"; }
- void fix_length_and_dec() { decimals=0; max_length=21; }
};
class Item_func_bit_neg :public Item_int_func
@@ -618,7 +665,7 @@ public:
Item_func_bit_neg(Item *a) :Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "~"; }
- void fix_length_and_dec() { decimals=0; max_length=21; }
+ void fix_length_and_dec() { unsigned_flag=1; }
};
class Item_func_set_last_insert_id :public Item_int_func
@@ -627,7 +674,7 @@ public:
Item_func_set_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() { decimals=0; max_length=args[0]->max_length; }
+ void fix_length_and_dec() { max_length=args[0]->max_length; }
};
class Item_func_benchmark :public Item_int_func
@@ -639,7 +686,7 @@ class Item_func_benchmark :public Item_int_func
{}
longlong val_int();
const char *func_name() const { return "benchmark"; }
- void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=0; }
+ void fix_length_and_dec() { max_length=1; maybe_null=0; }
};
@@ -771,7 +818,7 @@ class Item_func_get_lock :public Item_int_func
Item_func_get_lock(Item *a,Item *b) :Item_int_func(a,b) {}
longlong val_int();
const char *func_name() const { return "get_lock"; }
- void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=1;}
+ void fix_length_and_dec() { max_length=1; maybe_null=1;}
};
class Item_func_release_lock :public Item_int_func
@@ -781,7 +828,7 @@ class Item_func_release_lock :public Item_int_func
Item_func_release_lock(Item *a) :Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "release_lock"; }
- void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=1;}
+ void fix_length_and_dec() { max_length=1; maybe_null=1;}
};
/* replication functions */
@@ -793,7 +840,7 @@ class Item_master_pos_wait :public Item_int_func
Item_master_pos_wait(Item *a,Item *b) :Item_int_func(a,b) {}
longlong val_int();
const char *func_name() const { return "master_pos_wait"; }
- void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=1;}
+ void fix_length_and_dec() { max_length=1; maybe_null=1;}
};
@@ -863,34 +910,63 @@ class Item_func_match :public Item_real_func
{
public:
List<Item> fields;
+ String value;
TABLE *table;
- uint key;
- bool join_key;
Item_func_match *master;
- FT_DOCLIST *ft_handler;
+ FT_INFO * ft_handler;
+ Item *concat;
+ byte *record;
+ uint key, mode;
+ bool join_key;
Item_func_match(List<Item> &a, Item *b): Item_real_func(b),
- fields(a), table(0), join_key(0), master(0), ft_handler(0) {}
+ fields(a), table(0), master(0), ft_handler(0),
+ concat(0), key(0), join_key(0) {}
~Item_func_match()
{
- if (!master)
+ if (!master && ft_handler)
{
- if (ft_handler)
- {
- ft_close_search(ft_handler);
- if(join_key)
- table->file->ft_handler=0;
- }
+ ft_handler->please->close_search(ft_handler);
+ ft_handler=0;
+ if(join_key)
+ table->file->ft_handler=0;
+ table->fulltext_searched=0;
}
+ if (concat) delete concat;
}
- const char *func_name() const { return "match"; }
enum Functype functype() const { return FT_FUNC; }
void update_used_tables() {}
bool fix_fields(THD *thd,struct st_table_list *tlist);
bool eq(const Item *, bool binary_cmp) const;
- double val();
longlong val_int() { return val()!=0.0; }
+ double val();
bool fix_index();
void init_search(bool no_order);
};
+
+class Item_func_match_nl :public Item_func_match
+{
+public:
+ Item_func_match_nl(List<Item> &a, Item *b):
+ Item_func_match(a,b) { mode=FT_NL; }
+ const char *func_name() const { return "match_nl"; }
+};
+
+class Item_func_match_bool :public Item_func_match
+{
+public:
+ Item_func_match_bool(List<Item> &a, Item *b):
+ Item_func_match(a,b) { mode=FT_BOOL; }
+ const char *func_name() const { return "match_bool"; }
+};
+
+/* For type casts */
+
+enum Item_cast
+{
+ ITEM_CAST_BINARY, ITEM_CAST_SIGNED_INT, ITEM_CAST_UNSIGNED_INT,
+ ITEM_CAST_DATE, ITEM_CAST_TIME, ITEM_CAST_DATETIME
+};
+
+Item *create_func_cast(Item *a, Item_cast cast_type);
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index bd7fde79629..c64fdc7a049 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -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 */
@@ -17,7 +17,7 @@
/* This file defines all string functions
** Warning: Some string functions doesn't always put and end-null on a String
-** (This shouldn't be neaded)
+** (This shouldn't be needed)
*/
#ifdef __GNUC__
@@ -30,7 +30,9 @@
#ifdef HAVE_CRYPT_H
#include <crypt.h>
#endif
-
+#ifdef HAVE_OPENSSL
+#include <openssl/des.h>
+#endif /* HAVE_OPENSSL */
#include "md5.h"
String empty_string("");
@@ -66,14 +68,18 @@ String *Item_func_md5::val_str(String *str)
String * sptr= args[0]->val_str(str);
if (sptr)
{
- MD5_CTX context;
+ my_MD5_CTX context;
unsigned char digest[16];
null_value=0;
- MD5Init (&context);
- MD5Update (&context,(unsigned char *) sptr->ptr(), sptr->length());
- MD5Final (digest, &context);
- str->alloc(32); // Ensure that memory is free
+ my_MD5Init (&context);
+ my_MD5Update (&context,(unsigned char *) sptr->ptr(), sptr->length());
+ my_MD5Final (digest, &context);
+ if (str->alloc(32)) // Ensure that memory is free
+ {
+ null_value=1;
+ return 0;
+ }
sprintf((char *) str->ptr(),
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
digest[0], digest[1], digest[2], digest[3],
@@ -199,11 +205,167 @@ void Item_func_concat::fix_length_and_dec()
}
}
+/*
+ Function des_encrypt() by tonu@spam.ee & monty
+ Works only if compiled with OpenSSL library support.
+ This returns a binary string where first character is
+ CHAR(128 | key-number).
+ If one uses a string key key_number is 127.
+ Encryption result is longer than original by formula:
+ new_length= org_length + (8-(org_length % 8))+1
+*/
+
+String *Item_func_des_encrypt::val_str(String *str)
+{
+#ifdef HAVE_OPENSSL
+ des_cblock ivec;
+ struct st_des_keyblock keyblock;
+ struct st_des_keyschedule keyschedule;
+ const char *append_str="********";
+ uint key_number, res_length, tail;
+ String *res= args[0]->val_str(str);
+
+ if ((null_value=args[0]->null_value))
+ return 0;
+ if ((res_length=res->length()) == 0)
+ return &empty_string;
+
+ if (arg_count == 1)
+ {
+ /* Protect against someone doing FLUSH DES_KEY_FILE */
+ VOID(pthread_mutex_lock(&LOCK_des_key_file));
+ keyschedule= des_keyschedule[key_number=des_default_key];
+ VOID(pthread_mutex_unlock(&LOCK_des_key_file));
+ }
+ else if (args[1]->result_type() == INT_RESULT)
+ {
+ key_number= (uint) args[1]->val_int();
+ if (key_number > 9)
+ goto error;
+ VOID(pthread_mutex_lock(&LOCK_des_key_file));
+ keyschedule= des_keyschedule[key_number];
+ VOID(pthread_mutex_unlock(&LOCK_des_key_file));
+ }
+ else
+ {
+ String *keystr=args[1]->val_str(&tmp_value);
+ if (!keystr)
+ goto error;
+ key_number=127; // User key string
+
+ /* We make good 24-byte (168 bit) key from given plaintext key with MD5 */
+ bzero((char*) &ivec,sizeof(ivec));
+ EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL,
+ (uchar*) keystr->ptr(), (int) keystr->length(),
+ 1, (uchar*) &keyblock,ivec);
+ des_set_key_unchecked(&keyblock.key1,keyschedule.ks1);
+ des_set_key_unchecked(&keyblock.key2,keyschedule.ks2);
+ des_set_key_unchecked(&keyblock.key3,keyschedule.ks3);
+ }
+
+ /*
+ The problem: DES algorithm requires original data to be in 8-bytes
+ chunks. Missing bytes get filled with '*'s and result of encryption
+ can be up to 8 bytes longer than original string. When decrypted,
+ we do not know the size of original string :(
+ We add one byte with value 0x1..0x8 as the last byte of the padded
+ string marking change of string length.
+ */
+
+ tail= (8-(res_length) % 8); // 1..8 marking extra length
+ res_length+=tail;
+ if (tail && res->append(append_str, tail) || tmp_value.alloc(res_length+1))
+ goto error;
+ (*res)[res_length-1]=tail; // save extra length
+ tmp_value.length(res_length+1);
+ tmp_value[0]=(char) (128 | key_number);
+ // Real encryption
+ bzero((char*) &ivec,sizeof(ivec));
+ des_ede3_cbc_encrypt((const uchar*) (res->ptr()),
+ (uchar*) (tmp_value.ptr()+1),
+ res_length,
+ keyschedule.ks1,
+ keyschedule.ks2,
+ keyschedule.ks3,
+ &ivec, TRUE);
+ return &tmp_value;
+
+error:
+#endif /* HAVE_OPENSSL */
+ null_value=1;
+ return 0;
+}
+
+
+String *Item_func_des_decrypt::val_str(String *str)
+{
+#ifdef HAVE_OPENSSL
+ des_key_schedule ks1, ks2, ks3;
+ des_cblock ivec;
+ struct st_des_keyblock keyblock;
+ struct st_des_keyschedule keyschedule;
+ String *res= args[0]->val_str(str);
+ uint length=res->length(),tail;
+
+ if ((null_value=args[0]->null_value))
+ return 0;
+ length=res->length();
+ if (length < 9 || (length % 8) != 1 || !((*res)[0] & 128))
+ return res; // Skip decryption if not encrypted
+
+ if (arg_count == 1) // If automatic uncompression
+ {
+ uint key_number=(uint) (*res)[0] & 127;
+ // Check if automatic key and that we have privilege to uncompress using it
+ if (!(current_thd->master_access & PROCESS_ACL) || key_number > 9)
+ goto error;
+ VOID(pthread_mutex_lock(&LOCK_des_key_file));
+ keyschedule= des_keyschedule[key_number];
+ VOID(pthread_mutex_unlock(&LOCK_des_key_file));
+ }
+ else
+ {
+ // We make good 24-byte (168 bit) key from given plaintext key with MD5
+ String *keystr=args[1]->val_str(&tmp_value);
+ if (!keystr)
+ goto error;
+
+ bzero((char*) &ivec,sizeof(ivec));
+ EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL,
+ (uchar*) keystr->ptr(),(int) keystr->length(),
+ 1,(uchar*) &keyblock,ivec);
+ // Here we set all 64-bit keys (56 effective) one by one
+ des_set_key_unchecked(&keyblock.key1,keyschedule.ks1);
+ des_set_key_unchecked(&keyblock.key2,keyschedule.ks2);
+ des_set_key_unchecked(&keyblock.key3,keyschedule.ks3);
+ }
+ if (tmp_value.alloc(length-1))
+ goto error;
+
+ bzero((char*) &ivec,sizeof(ivec));
+ des_ede3_cbc_encrypt((const uchar*) res->ptr()+1,
+ (uchar*) (tmp_value.ptr()),
+ length-1,
+ keyschedule.ks1,
+ keyschedule.ks2,
+ keyschedule.ks3,
+ &ivec, FALSE);
+ /* Restore old length of key */
+ if ((tail=(uint) (uchar) tmp_value[length-2]) > 8)
+ goto error; // Wrong key
+ tmp_value.length(length-1-tail);
+ return &tmp_value;
+
+error:
+#endif /* HAVE_OPENSSL */
+ null_value=1;
+ return 0;
+}
/*
-** concat with separator. First arg is the separator
-** concat_ws takes at least two arguments.
+ concat with separator. First arg is the separator
+ concat_ws takes at least two arguments.
*/
String *Item_func_concat_ws::val_str(String *str)
@@ -232,7 +394,7 @@ String *Item_func_concat_ws::val_str(String *str)
for (i++; i < arg_count ; i++)
{
if (!(res2= args[i]->val_str(use_as_buff)) || !res2->length())
- continue; // Skipp NULL and empty string
+ continue; // Skip NULL and empty string
if (res->length() + sep_str->length() + res2->length() >
max_allowed_packet)
@@ -385,7 +547,7 @@ void Item_func_reverse::fix_length_and_dec()
/*
** Replace all occurences of string2 in string1 with string3.
-** Don't reallocate val_str() if not neaded
+** Don't reallocate val_str() if not needed
*/
/* TODO: Fix that this works with binary strings when using USE_MB */
@@ -521,7 +683,7 @@ String *Item_func_insert::val_str(String *str)
}
#endif
if (start > res->length()+1)
- return res; // Wrong param; skipp insert
+ return res; // Wrong param; skip insert
if (length > res->length()-start)
length=res->length()-start;
if (res->length() - length + res2->length() > max_allowed_packet)
@@ -1098,7 +1260,7 @@ void Item_func_soundex::fix_length_and_dec()
/*
If alpha, map input letter to soundex code.
- If not alpha and remove_garbage is set then skipp to next char
+ If not alpha and remove_garbage is set then skip to next char
else return 0
*/
@@ -1125,12 +1287,12 @@ String *Item_func_soundex::val_str(String *str)
if ((null_value=args[0]->null_value))
return 0; /* purecov: inspected */
- if (str_value.alloc(max(res->length(),4)))
+ if (tmp_value.alloc(max(res->length(),4)))
return str; /* purecov: inspected */
- char *to= (char *) str_value.ptr();
+ char *to= (char *) tmp_value.ptr();
char *from= (char *) res->ptr(), *end=from+res->length();
- while (from != end && isspace(*from)) // Skipp pre-space
+ while (from != end && isspace(*from)) // Skip pre-space
from++; /* purecov: inspected */
if (from == end)
return &empty_string; // No alpha characters.
@@ -1151,11 +1313,11 @@ String *Item_func_soundex::val_str(String *str)
last_ch = ch; // save code of last input letter
} // for next double-letter check
}
- for (end=(char*) str_value.ptr()+4 ; to < end ; to++)
+ for (end=(char*) tmp_value.ptr()+4 ; to < end ; to++)
*to = '0';
*to=0; // end string
- str_value.length((uint) (to-str_value.ptr()));
- return &str_value;
+ tmp_value.length((uint) (to-tmp_value.ptr()));
+ return &tmp_value;
}
@@ -1305,7 +1467,7 @@ String *Item_func_make_set::val_str(String *str)
if (bits & 1)
{
String *res= (*ptr)->val_str(str);
- if (res) // Skipp nulls
+ if (res) // Skip nulls
{
if (!first_found)
{ // First argument
@@ -1610,6 +1772,45 @@ String *Item_func_conv::val_str(String *str)
return str;
}
+
+String *Item_func_hex::val_str(String *str)
+{
+ if (args[0]->result_type() != STRING_RESULT)
+ {
+ /* Return hex of unsigned longlong value */
+ longlong dec= args[0]->val_int();
+ char ans[65],*ptr;
+ if ((null_value= args[0]->null_value))
+ return 0;
+ ptr= longlong2str(dec,ans,16);
+ if (str->copy(ans,(uint32) (ptr-ans)))
+ return &empty_string; // End of memory
+ return str;
+ }
+
+ /* Convert given string to a hex string, character by character */
+ String *res= args[0]->val_str(str);
+ const char *from, *end;
+ char *to;
+ if (!res || tmp_value.alloc(res->length()*2))
+ {
+ null_value=1;
+ return 0;
+ }
+ null_value=0;
+ tmp_value.length(res->length()*2);
+ for (from=res->ptr(), end=from+res->length(), to= (char*) tmp_value.ptr();
+ from != end ;
+ from++, to+=2)
+ {
+ uint tmp=(uint) (uchar) *from;
+ to[0]=_dig_vec[tmp >> 4];
+ to[1]=_dig_vec[tmp & 15];
+ }
+ return &tmp_value;
+}
+
+
#include <my_dir.h> // For my_stat
String *Item_load_file::val_str(String *str)
@@ -1731,7 +1932,7 @@ String* Item_func_inet_ntoa::val_str(String* str)
// we handle the possibility of an 8-byte IP address
// however, we do not want to confuse those who are just using
// 4 byte ones
-
+
for (p= buf + 8; p > buf+4 && p[-1] == 0 ; p-- ) ;
num[3]='.';
while (p-- > buf)
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 1b829b19439..1279a5099d5 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.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,6 +35,11 @@ public:
double val();
enum Item_result result_type () const { return STRING_RESULT; }
void left_right_max_length();
+ Field *tmp_table_field(TABLE *t_arg)
+ {
+ if (!t_arg) return result_field;
+ return (max_length > 255) ? (Field *)new Field_blob(max_length,maybe_null, name,t_arg, binary) : (Field *) new Field_string(max_length,maybe_null, name,t_arg, binary);
+ }
};
class Item_func_md5 :public Item_str_func
@@ -222,6 +227,29 @@ public:
const char *func_name() const { return "password"; }
};
+class Item_func_des_encrypt :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_des_encrypt(Item *a) :Item_str_func(a) {}
+ Item_func_des_encrypt(Item *a, Item *b): Item_str_func(a,b) {}
+ String *val_str(String *);
+ void fix_length_and_dec()
+ { maybe_null=1; max_length = args[0]->max_length+8; }
+ const char *func_name() const { return "des_encrypt"; }
+};
+
+class Item_func_des_decrypt :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_des_decrypt(Item *a) :Item_str_func(a) {}
+ Item_func_des_decrypt(Item *a, Item *b): Item_str_func(a,b) {}
+ String *val_str(String *);
+ void fix_length_and_dec() { maybe_null=1; max_length = args[0]->max_length; }
+ const char *func_name() const { return "des_decrypt"; }
+};
+
class Item_func_encrypt :public Item_str_func
{
String tmp_value;
@@ -274,6 +302,7 @@ public:
class Item_func_soundex :public Item_str_func
{
+ String tmp_value;
public:
Item_func_soundex(Item *a) :Item_str_func(a) {}
String *val_str(String *);
@@ -389,12 +418,25 @@ public:
void fix_length_and_dec() { decimals=0; max_length=64; }
};
+
+class Item_func_hex :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_hex(Item *a) :Item_str_func(a) {}
+ const char *func_name() const { return "hex"; }
+ String *val_str(String *);
+ void fix_length_and_dec() { decimals=0; max_length=args[0]->max_length*2; }
+};
+
+
class Item_func_binary :public Item_str_func
{
public:
Item_func_binary(Item *a) :Item_str_func(a) {}
const char *func_name() const { return "binary"; }
- String *val_str(String *a) { return (args[0]->val_str(a)); }
+ String *val_str(String *a)
+ { a=args[0]->val_str(a); null_value=args[0]->null_value; return a; }
void fix_length_and_dec() { binary=1; max_length=args[0]->max_length; }
void print(String *str) { print_op(str); }
};
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 5b24a1eda90..e8f16e3ed56 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -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 */
@@ -30,7 +30,7 @@ Item_sum::Item_sum(List<Item> &list)
if ((args=(Item**) sql_alloc(sizeof(Item*)*arg_count)))
{
uint i=0;
- List_iterator<Item> li(list);
+ List_iterator_fast<Item> li(list);
Item *item;
while ((item=li++))
@@ -52,6 +52,8 @@ void Item_sum::make_field(Send_field *tmp_field)
tmp_field->flags=0;
if (!maybe_null)
tmp_field->flags|= NOT_NULL_FLAG;
+ if (unsigned_flag)
+ tmp_field->flags |= UNSIGNED_FLAG;
tmp_field->length=max_length;
tmp_field->decimals=decimals;
tmp_field->type=(result_type() == INT_RESULT ? FIELD_TYPE_LONG :
@@ -150,7 +152,7 @@ Item_sum_hybrid::fix_fields(THD *thd,TABLE_LIST *tables)
return 1;
hybrid_type=item->result_type();
if (hybrid_type == INT_RESULT)
- max_length=21;
+ max_length=20;
else if (hybrid_type == REAL_RESULT)
max_length=float_length(decimals);
else
@@ -158,6 +160,7 @@ Item_sum_hybrid::fix_fields(THD *thd,TABLE_LIST *tables)
decimals=item->decimals;
maybe_null=item->maybe_null;
binary=item->binary;
+ unsigned_flag=item->unsigned_flag;
result_field=0;
null_value=1;
fix_length_and_dec();
@@ -323,12 +326,27 @@ double Item_sum_hybrid::val()
{
if (null_value)
return 0.0;
- if (hybrid_type == STRING_RESULT)
- {
+ switch (hybrid_type) {
+ case STRING_RESULT:
String *res; res=val_str(&str_value);
return res ? atof(res->c_ptr()) : 0.0;
+ case INT_RESULT:
+ if (unsigned_flag)
+ return ulonglong2double(sum_int);
+ return (double) sum_int;
+ case REAL_RESULT:
+ return sum;
}
- return sum;
+ return 0; // Keep compiler happy
+}
+
+longlong Item_sum_hybrid::val_int()
+{
+ if (null_value)
+ return 0;
+ if (hybrid_type == INT_RESULT)
+ return sum_int;
+ return (longlong) Item_sum_hybrid::val();
}
@@ -337,25 +355,26 @@ Item_sum_hybrid::val_str(String *str)
{
if (null_value)
return 0;
- if (hybrid_type == STRING_RESULT)
+ switch (hybrid_type) {
+ case STRING_RESULT:
return &value;
- str->set(sum,decimals);
- return str;
+ case REAL_RESULT:
+ str->set(sum,decimals);
+ break;
+ case INT_RESULT:
+ if (unsigned_flag)
+ str->set((ulonglong) sum_int);
+ else
+ str->set((longlong) sum_int);
+ break;
+ }
+ return str; // Keep compiler happy
}
-
bool Item_sum_min::add()
{
- if (hybrid_type != STRING_RESULT)
- {
- double nr=args[0]->val();
- if (!args[0]->null_value && (null_value || nr < sum))
- {
- sum=nr;
- null_value=0;
- }
- }
- else
+ switch (hybrid_type) {
+ case STRING_RESULT:
{
String *result=args[0]->val_str(&tmp_value);
if (!args[0]->null_value &&
@@ -366,22 +385,39 @@ bool Item_sum_min::add()
null_value=0;
}
}
- return 0;
-}
-
-
-bool Item_sum_max::add()
-{
- if (hybrid_type != STRING_RESULT)
+ break;
+ case INT_RESULT:
+ {
+ longlong nr=args[0]->val_int();
+ if (!args[0]->null_value && (null_value ||
+ (unsigned_flag &&
+ (ulonglong) nr < (ulonglong) sum_int) ||
+ (!unsigned_flag && nr < sum_int)))
+ {
+ sum_int=nr;
+ null_value=0;
+ }
+ }
+ break;
+ case REAL_RESULT:
{
double nr=args[0]->val();
- if (!args[0]->null_value && (null_value || nr > sum))
+ if (!args[0]->null_value && (null_value || nr < sum))
{
sum=nr;
null_value=0;
}
}
- else
+ break;
+ }
+ return 0;
+}
+
+
+bool Item_sum_max::add()
+{
+ switch (hybrid_type) {
+ case STRING_RESULT:
{
String *result=args[0]->val_str(&tmp_value);
if (!args[0]->null_value &&
@@ -392,6 +428,31 @@ bool Item_sum_max::add()
null_value=0;
}
}
+ break;
+ case INT_RESULT:
+ {
+ longlong nr=args[0]->val_int();
+ if (!args[0]->null_value && (null_value ||
+ (unsigned_flag &&
+ (ulonglong) nr > (ulonglong) sum_int) ||
+ (!unsigned_flag && nr > sum_int)))
+ {
+ sum_int=nr;
+ null_value=0;
+ }
+ }
+ break;
+ case REAL_RESULT:
+ {
+ double nr=args[0]->val();
+ if (!args[0]->null_value && (null_value || nr > sum))
+ {
+ sum=nr;
+ null_value=0;
+ }
+ }
+ break;
+ }
return 0;
}
@@ -676,9 +737,17 @@ Item_sum_hybrid::min_max_update_int_field(int offset)
nr=args[0]->val_int();
if (!args[0]->null_value)
{
- if (result_field->is_null(offset) ||
- (cmp_sign > 0 ? old_nr > nr : old_nr < nr))
+ if (result_field->is_null(offset))
old_nr=nr;
+ else
+ {
+ bool res=(unsigned_flag ?
+ (ulonglong) old_nr > (ulonglong) nr :
+ old_nr > nr);
+ /* (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(offset))
@@ -788,11 +857,74 @@ String *Item_std_field::val_str(String *str)
#include "sql_select.h"
+static int simple_raw_key_cmp(void* arg, byte* key1, byte* key2)
+{
+ return memcmp(key1, key2, *(uint*) arg);
+}
+
+static int simple_str_key_cmp(void* arg, byte* key1, byte* key2)
+{
+ return my_sortcmp((char*) key1, (char*) key2, *(uint*) arg);
+}
+
+/*
+ Did not make this one static - at least gcc gets confused when
+ I try to declare a static function as a friend. If you can figure
+ out the syntax to make a static function a friend, make this one
+ static
+*/
+
+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;
+ uint32 *lengths=item->field_lengths;
+ for (; field < field_end; ++field)
+ {
+ Field* f = *field;
+ int len = *lengths++;
+ int res = f->key_cmp(key1, key2);
+ if (res)
+ return res;
+ key1 += len;
+ key2 += len;
+ }
+ 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)
+{
+ byte* buf = item->table->record[0];
+ int error;
+ /*
+ The first item->rec_offset bytes are taken care of with
+ restore_record(table,2) 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;
+ }
+ return 0;
+}
+
+
Item_sum_count_distinct::~Item_sum_count_distinct()
{
if (table)
free_tmp_table(current_thd, table);
delete tmp_table_param;
+ if (use_tree)
+ delete_tree(&tree);
}
@@ -829,22 +961,125 @@ bool Item_sum_count_distinct::setup(THD *thd)
tmp_table_param->cleanup();
}
if (!(table=create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1,
- 0, 0, current_lex->options | thd->options)))
+ 0, 0,
+ current_lex->select->options | thd->options)))
return 1;
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)
+ {
+ qsort_cmp2 compare_key;
+ void* cmp_arg;
+
+ // to make things easier for dump_leaf if we ever have to dump to MyISAM
+ restore_record(table,2);
+
+ if (table->fields == 1)
+ {
+ /*
+ 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())
+ {
+ /*
+ If we have a string, we must take care of charsets and case
+ sensitivity
+ */
+ case FIELD_TYPE_STRING:
+ case FIELD_TYPE_VAR_STRING:
+ compare_key = (qsort_cmp2)(field->binary() ? simple_raw_key_cmp:
+ simple_str_key_cmp);
+ 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;
+ break;
+ }
+ key_length = field->pack_length();
+ cmp_arg = (void*) &key_length;
+ rec_offset = 1;
+ }
+ else // too bad, cannot cheat - there is more than one field
+ {
+ 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)
+ {
+ compare_key = (qsort_cmp2)simple_raw_key_cmp;
+ cmp_arg = (void*) &key_length;
+ }
+ else
+ {
+ compare_key = (qsort_cmp2) composite_key_cmp ;
+ cmp_arg = (void*) this;
+ }
+ }
+
+ init_tree(&tree, min(max_heap_table_size, sortbuff_size/16), 0,
+ key_length, compare_key, 0, NULL, cmp_arg);
+ use_tree = 1;
+
+ /*
+ The only time 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) ? max_heap_table_size/key_length :
+ 1);
+ }
return 0;
}
+int Item_sum_count_distinct::tree_to_myisam()
+{
+ if (create_myisam_from_heap(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;
+}
+
void Item_sum_count_distinct::reset()
{
- if (table)
+ if (use_tree)
+ reset_tree(&tree);
+ else if (table)
{
table->file->extra(HA_EXTRA_NO_CACHE);
table->file->delete_all_rows();
table->file->extra(HA_EXTRA_WRITE_CACHE);
- (void) add();
}
+ (void) add();
}
bool Item_sum_count_distinct::add()
@@ -859,7 +1094,21 @@ bool Item_sum_count_distinct::add()
if ((*field)->is_real_null(0))
return 0; // Don't count NULL
- if ((error=table->file->write_row(table->record[0])))
+ if (use_tree)
+ {
+ /*
+ If the tree got too big, convert to MyISAM, otherwise insert into the
+ tree.
+ */
+ 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))
+ 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)
@@ -875,6 +1124,8 @@ longlong Item_sum_count_distinct::val_int()
{
if (!table) // Empty query
return LL(0);
+ if (use_tree)
+ return tree.elements_in_tree;
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
return table->file->records;
}
@@ -897,7 +1148,7 @@ void Item_udf_sum::reset()
bool Item_udf_sum::add()
{
- DBUG_ENTER("Item_udf_sum::reset");
+ DBUG_ENTER("Item_udf_sum::add");
udf.add(&null_value);
DBUG_RETURN(0);
}
diff --git a/sql/item_sum.h b/sql/item_sum.h
index f68dfee1b61..a963799b6a7 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.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 */
@@ -21,6 +21,8 @@
#pragma interface /* gcc class implementation */
#endif
+#include <my_tree.h>
+
class Item_sum :public Item_result_field
{
public:
@@ -62,6 +64,7 @@ public:
{ return new Item_field(field);}
table_map used_tables() const { return ~(table_map) 0; } /* Not used */
bool const_item() const { return 0; }
+ bool is_null() { return null_value; }
void update_used_tables() { }
void make_field(Send_field *field);
void print(String *str);
@@ -144,13 +147,36 @@ class Item_sum_count_distinct :public Item_sum_int
TABLE *table;
table_map used_table_cache;
bool fix_fields(THD *thd,TABLE_LIST *tables);
+ uint32 *field_lengths;
TMP_TABLE_PARAM *tmp_table_param;
- bool always_null;
+ TREE tree;
+ uint key_length;
+
+ // 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 dump_leaf(byte* key, uint32 count __attribute__((unused)),
+ Item_sum_count_distinct* item);
public:
Item_sum_count_distinct(List<Item> &list)
:Item_sum_int(list),table(0),used_table_cache(~(table_map) 0),
- tmp_table_param(0),always_null(0)
+ tmp_table_param(0),use_tree(0),always_null(0)
{ quick_group=0; }
~Item_sum_count_distinct();
table_map used_tables() const { return used_table_cache; }
@@ -177,6 +203,7 @@ public:
enum Type type() const { return FIELD_AVG_ITEM; }
double val();
longlong val_int() { return (longlong) val(); }
+ bool is_null() { (void) val_int(); return null_value; }
String *val_str(String*);
void make_field(Send_field *field);
void fix_length_and_dec() {}
@@ -214,6 +241,7 @@ public:
double val();
longlong val_int() { return (longlong) val(); }
String *val_str(String*);
+ bool is_null() { (void) val_int(); return null_value; }
void make_field(Send_field *field);
void fix_length_and_dec() {}
};
@@ -246,6 +274,7 @@ class Item_sum_hybrid :public Item_sum
protected:
String value,tmp_value;
double sum;
+ longlong sum_int;
Item_result hybrid_type;
int cmp_sign;
table_map used_table_cache;
@@ -261,12 +290,13 @@ class Item_sum_hybrid :public Item_sum
void reset()
{
sum=0.0;
+ sum_int=0;
value.length(0);
null_value=1;
add();
}
double val();
- longlong val_int() { return (longlong) val(); } /* Real as default */
+ longlong val_int();
void reset_field();
String *val_str(String *);
void make_const() { used_table_cache=0; }
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index eb9b1423c78..9a003b79609 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -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 */
@@ -672,7 +672,7 @@ String *Item_func_date_format::val_str(String *str)
else
size=format_length(format);
if (format == str)
- str=&value; // Save result here
+ str= &value; // Save result here
if (str->alloc(size))
{
null_value=1;
@@ -1123,3 +1123,13 @@ longlong Item_extract::val_int()
}
return 0; // Impossible
}
+
+
+void Item_typecast::print(String *str)
+{
+ str->append("CAST(");
+ args[0]->print(str);
+ str->append(" AS ");
+ str->append(func_name());
+ str->append(')');
+}
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 6913d4c6809..aa4140192ab 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.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 */
@@ -229,6 +229,33 @@ public:
const char *func_name() const { return "date"; }
void fix_length_and_dec() { decimals=0; max_length=10; }
bool save_in_field(Field *to);
+ void make_field(Send_field *tmp_field)
+ {
+ init_make_field(tmp_field,FIELD_TYPE_DATE);
+ }
+ Field *tmp_table_field(TABLE *t_arg)
+ {
+ if (!t_arg) return result_field;
+ return new Field_date(maybe_null, name, t_arg);
+ }
+};
+
+
+class Item_date_func :public Item_str_func
+{
+public:
+ Item_date_func() :Item_str_func() {}
+ Item_date_func(Item *a) :Item_str_func(a) {}
+ Item_date_func(Item *a,Item *b) :Item_str_func(a,b) {}
+ void make_field(Send_field *tmp_field)
+ {
+ init_make_field(tmp_field,FIELD_TYPE_DATETIME);
+ }
+ Field *tmp_table_field(TABLE *t_arg)
+ {
+ if (!t_arg) return result_field;
+ return new Field_datetime(maybe_null, name, t_arg);
+ }
};
@@ -247,6 +274,15 @@ public:
{ str_value.set(buff,buff_length); return &str_value; }
const char *func_name() const { return "curtime"; }
void fix_length_and_dec();
+ void make_field(Send_field *tmp_field)
+ {
+ init_make_field(tmp_field,FIELD_TYPE_TIME);
+ }
+ Field *tmp_table_field(TABLE *t_arg)
+ {
+ if (!t_arg) return result_field;
+ return new Field_time(maybe_null, name, t_arg);
+ }
};
@@ -263,15 +299,15 @@ public:
};
-class Item_func_now :public Item_func
+class Item_func_now :public Item_date_func
{
longlong value;
char buff[20];
uint buff_length;
TIME ltime;
public:
- Item_func_now() :Item_func() {}
- Item_func_now(Item *a) :Item_func(a) {}
+ 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() { return (double) value; }
longlong val_int() { return value; }
@@ -308,16 +344,16 @@ public:
};
-class Item_func_from_unixtime :public Item_func
+class Item_func_from_unixtime :public Item_date_func
{
public:
- Item_func_from_unixtime(Item *a) :Item_func(a) {}
+ Item_func_from_unixtime(Item *a) :Item_date_func(a) {}
double val() { return (double) Item_func_from_unixtime::val_int(); }
longlong val_int();
String *val_str(String *str);
const char *func_name() const { return "from_unixtime"; }
void fix_length_and_dec() { decimals=0; max_length=19; }
- enum Item_result result_type () const { return STRING_RESULT; }
+// enum Item_result result_type () const { return STRING_RESULT; }
bool get_date(TIME *res,bool fuzzy_date);
};
@@ -331,6 +367,15 @@ public:
String *val_str(String *);
void fix_length_and_dec() { maybe_null=1; max_length=13; }
const char *func_name() const { return "sec_to_time"; }
+ void make_field(Send_field *tmp_field)
+ {
+ init_make_field(tmp_field,FIELD_TYPE_TIME);
+ }
+ Field *tmp_table_field(TABLE *t_arg)
+ {
+ if (!t_arg) return result_field;
+ return new Field_time(maybe_null, name, t_arg);
+ }
};
enum interval_type { INTERVAL_YEAR, INTERVAL_MONTH, INTERVAL_DAY,
@@ -340,7 +385,7 @@ enum interval_type { INTERVAL_YEAR, INTERVAL_MONTH, INTERVAL_DAY,
INTERVAL_HOUR_MINUTE, INTERVAL_HOUR_SECOND,
INTERVAL_MINUTE_SECOND};
-class Item_date_add_interval :public Item_str_func
+class Item_date_add_interval :public Item_date_func
{
const interval_type int_type;
String value;
@@ -348,7 +393,7 @@ class Item_date_add_interval :public Item_str_func
public:
Item_date_add_interval(Item *a,Item *b,interval_type type_arg,bool neg_arg)
- :Item_str_func(a,b),int_type(type_arg), date_sub_interval(neg_arg) {}
+ :Item_date_func(a,b),int_type(type_arg), date_sub_interval(neg_arg) {}
String *val_str(String *);
const char *func_name() const { return "date_add_interval"; }
void fix_length_and_dec() { maybe_null=1; max_length=19; value.alloc(32);}
@@ -369,3 +414,62 @@ class Item_extract :public Item_int_func
const char *func_name() const { return "extract"; }
void fix_length_and_dec();
};
+
+class Item_typecast :public Item_str_func
+{
+public:
+ Item_typecast(Item *a) :Item_str_func(a) {}
+ String *val_str(String *a)
+ { a=args[0]->val_str(a); null_value=args[0]->null_value; return a; }
+ void fix_length_and_dec() { max_length=args[0]->max_length; }
+ void print(String *str);
+};
+
+
+class Item_date_typecast :public Item_typecast
+{
+public:
+ Item_date_typecast(Item *a) :Item_typecast(a) {}
+ const char *func_name() const { return "date"; }
+ void make_field(Send_field *tmp_field)
+ {
+ init_make_field(tmp_field,FIELD_TYPE_DATE);
+ }
+ Field *tmp_table_field(TABLE *t_arg)
+ {
+ if (!t_arg) return result_field;
+ return new Field_date(maybe_null, name, t_arg);
+ }
+};
+
+class Item_time_typecast :public Item_typecast
+{
+public:
+ Item_time_typecast(Item *a) :Item_typecast(a) {}
+ const char *func_name() const { return "time"; }
+ void make_field(Send_field *tmp_field)
+ {
+ init_make_field(tmp_field,FIELD_TYPE_TIME);
+ }
+ Field *tmp_table_field(TABLE *t_arg)
+ {
+ if (!t_arg) return result_field;
+ return new Field_time(maybe_null, name, t_arg);
+ }
+};
+
+class Item_datetime_typecast :public Item_typecast
+{
+public:
+ Item_datetime_typecast(Item *a) :Item_typecast(a) {}
+ const char *func_name() const { return "datetime"; }
+ void make_field(Send_field *tmp_field)
+ {
+ init_make_field(tmp_field,FIELD_TYPE_DATETIME);
+ }
+ Field *tmp_table_field(TABLE *t_arg)
+ {
+ if (!t_arg) return result_field;
+ return new Field_datetime(maybe_null, name, t_arg);
+ }
+};
diff --git a/sql/item_uniq.cc b/sql/item_uniq.cc
index 80ed6433fd8..88e0cbbc0e6 100644
--- a/sql/item_uniq.cc
+++ b/sql/item_uniq.cc
@@ -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 */
diff --git a/sql/item_uniq.h b/sql/item_uniq.h
index ff11222e2ee..4be64ecc74a 100644
--- a/sql/item_uniq.h
+++ b/sql/item_uniq.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 */
diff --git a/sql/key.cc b/sql/key.cc
index 80a33bc45d3..d2f483e3d73 100644
--- a/sql/key.cc
+++ b/sql/key.cc
@@ -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 */
@@ -96,7 +96,7 @@ void key_copy(byte *key,TABLE *table,uint idx,uint key_length)
length=min(key_length,key_part->length);
set_if_smaller(blob_length,length);
int2store(key,(uint) blob_length);
- key+=2; // Skipp length info
+ key+=2; // Skip length info
memcpy(key,pos,blob_length);
}
else
@@ -250,7 +250,7 @@ void key_unpack(String *to,TABLE *table,uint idx)
bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields)
{
- List_iterator<Item> f(fields);
+ List_iterator_fast<Item> f(fields);
KEY_PART_INFO *key_part,*key_part_end;
for (key_part=table->key_info[idx].key_part,key_part_end=key_part+
table->key_info[idx].key_parts ;
@@ -258,7 +258,7 @@ bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields)
key_part++)
{
Item_field *field;
-
+
if (key_part->field == table->timestamp_field)
return 1; // Can't be used for update
diff --git a/sql/lex.h b/sql/lex.h
index 30fbf46e354..10c1ad766d5 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -62,18 +62,21 @@ static SYMBOL symbols[] = {
{ "AVG_ROW_LENGTH", SYM(AVG_ROW_LENGTH),0,0},
{ "AUTO_INCREMENT", SYM(AUTO_INC),0,0},
{ "AUTOCOMMIT", SYM(AUTOCOMMIT),0,0},
- { "BACKUP", SYM(BACKUP_SYM),0,0},
- { "BEGIN", SYM(BEGIN_SYM),0,0},
+ { "BACKUP", SYM(BACKUP_SYM),0,0},
+ { "BEGIN", SYM(BEGIN_SYM),0,0},
{ "BERKELEYDB", SYM(BERKELEY_DB_SYM),0,0},
{ "BDB", SYM(BERKELEY_DB_SYM),0,0},
{ "BETWEEN", SYM(BETWEEN_SYM),0,0},
{ "BIGINT", SYM(BIGINT),0,0},
{ "BIT", SYM(BIT_SYM),0,0},
{ "BINARY", SYM(BINARY),0,0},
+ { "BINLOG", SYM(BINLOG_SYM),0,0},
{ "BLOB", SYM(BLOB_SYM),0,0},
{ "BOOL", SYM(BOOL_SYM),0,0},
+ { "BOOLEAN", SYM(BOOLEAN_SYM),0,0},
{ "BOTH", SYM(BOTH),0,0},
{ "BY", SYM(BY),0,0},
+ { "CACHE", SYM(CACHE_SYM),0,0},
{ "CASCADE", SYM(CASCADE),0,0},
{ "CASE", SYM(CASE_SYM),0,0},
{ "CHAR", SYM(CHAR_SYM),0,0},
@@ -82,6 +85,8 @@ static SYMBOL symbols[] = {
{ "CHANGED", SYM(CHANGED),0,0},
{ "CHECK", SYM(CHECK_SYM),0,0},
{ "CHECKSUM", SYM(CHECKSUM_SYM),0,0},
+ { "CIPHER", SYM(CIPHER_SYM),0,0},
+ { "CLOSE", SYM(CLOSE_SYM),0,0},
{ "COLUMN", SYM(COLUMN_SYM),0,0},
{ "COLUMNS", SYM(COLUMNS),0,0},
{ "COMMENT", SYM(COMMENT_SYM),0,0},
@@ -106,12 +111,16 @@ static SYMBOL symbols[] = {
{ "DAY_SECOND", SYM(DAY_SECOND_SYM),0,0},
{ "DEC", SYM(DECIMAL_SYM),0,0},
{ "DECIMAL", SYM(DECIMAL_SYM),0,0},
+ { "DES_KEY_FILE", SYM(DES_KEY_FILE),0,0},
{ "DEFAULT", SYM(DEFAULT),0,0},
{ "DELAYED", SYM(DELAYED_SYM),0,0},
{ "DELAY_KEY_WRITE", SYM(DELAY_KEY_WRITE_SYM),0,0},
{ "DELETE", SYM(DELETE_SYM),0,0},
+ { "DEMAND", SYM(DEMAND_SYM),0,0},
{ "DESC", SYM(DESC),0,0},
{ "DESCRIBE", SYM(DESCRIBE),0,0},
+ { "DIRECTORY", SYM(DIRECTORY_SYM),0,0},
+ { "DISABLE", SYM(DISABLE_SYM),0,0},
{ "DISTINCT", SYM(DISTINCT),0,0},
{ "DISTINCTROW", SYM(DISTINCT),0,0}, /* Access likes this */
{ "DO", SYM(DO_SYM),0,0},
@@ -123,8 +132,10 @@ static SYMBOL symbols[] = {
{ "ELSE", SYM(ELSE),0,0},
{ "ESCAPE", SYM(ESCAPE_SYM),0,0},
{ "ESCAPED", SYM(ESCAPED),0,0},
+ { "ENABLE", SYM(ENABLE_SYM),0,0},
{ "ENCLOSED", SYM(ENCLOSED),0,0},
{ "ENUM", SYM(ENUM),0,0},
+ { "EVENTS", SYM(EVENTS_SYM),0,0},
{ "EXPLAIN", SYM(DESCRIBE),0,0},
{ "EXISTS", SYM(EXISTS),0,0},
{ "EXTENDED", SYM(EXTENDED_SYM),0,0},
@@ -147,13 +158,12 @@ static SYMBOL symbols[] = {
{ "FULL", SYM(FULL),0,0},
{ "FULLTEXT", SYM(FULLTEXT_SYM),0,0},
{ "FUNCTION", SYM(UDF_SYM),0,0},
- { "GEMINI", SYM(GEMINI_SYM),0,0},
- { "GEMINI_SPIN_RETRIES", SYM(GEMINI_SPIN_RETRIES),0,0},
{ "GLOBAL", SYM(GLOBAL_SYM),0,0},
{ "GRANT", SYM(GRANT),0,0},
{ "GRANTS", SYM(GRANTS),0,0},
{ "GROUP", SYM(GROUP),0,0},
{ "HAVING", SYM(HAVING),0,0},
+ { "HANDLER", SYM(HANDLER_SYM),0,0},
{ "HEAP", SYM(HEAP_SYM),0,0},
{ "HIGH_PRIORITY", SYM(HIGH_PRIORITY),0,0},
{ "HOUR", SYM(HOUR_SYM),0,0},
@@ -164,12 +174,14 @@ static SYMBOL symbols[] = {
{ "IGNORE", SYM(IGNORE_SYM),0,0},
{ "IN", SYM(IN_SYM),0,0},
{ "INDEX", SYM(INDEX),0,0},
+ { "INDEXES", SYM(INDEXES),0,0},
{ "INFILE", SYM(INFILE),0,0},
{ "INNER", SYM(INNER_SYM),0,0},
{ "INNOBASE", SYM(INNOBASE_SYM),0,0},
{ "INNODB", SYM(INNOBASE_SYM),0,0},
{ "INSERT", SYM(INSERT),0,0},
{ "INSERT_ID", SYM(INSERT_ID),0,0},
+ { "INSERT_METHOD", SYM(INSERT_METHOD),0,0},
{ "INT", SYM(INT_SYM),0,0},
{ "INTEGER", SYM(INT_SYM),0,0},
{ "INTERVAL", SYM(INTERVAL_SYM),0,0},
@@ -179,14 +191,17 @@ static SYMBOL symbols[] = {
{ "INT4", SYM(INT_SYM),0,0},
{ "INT8", SYM(BIGINT),0,0},
{ "INTO", SYM(INTO),0,0},
+ { "IO_THREAD", SYM(IO_THREAD),0,0},
{ "IF", SYM(IF),0,0},
{ "IS", SYM(IS),0,0},
{ "ISOLATION", SYM(ISOLATION),0,0},
{ "ISAM", SYM(ISAM_SYM),0,0},
+ { "ISSUER", SYM(ISSUER_SYM),0,0},
{ "JOIN", SYM(JOIN_SYM),0,0},
{ "KEY", SYM(KEY_SYM),0,0},
{ "KEYS", SYM(KEYS),0,0},
{ "KILL", SYM(KILL_SYM),0,0},
+ { "LAST", SYM(LAST_SYM),0,0},
{ "LAST_INSERT_ID", SYM(LAST_INSERT_ID),0,0},
{ "LEADING", SYM(LEADING),0,0},
{ "LEFT", SYM(LEFT),0,0},
@@ -210,8 +225,10 @@ static SYMBOL symbols[] = {
{ "MASTER_LOG_POS", SYM(MASTER_LOG_POS_SYM),0,0},
{ "MASTER_PASSWORD", SYM(MASTER_PASSWORD_SYM),0,0},
{ "MASTER_PORT", SYM(MASTER_PORT_SYM),0,0},
+ { "MASTER_SERVER_ID", SYM(MASTER_SERVER_ID_SYM),0,0},
{ "MASTER_USER", SYM(MASTER_USER_SYM),0,0},
{ "MAX_ROWS", SYM(MAX_ROWS),0,0},
+ { "MAX_QUERIES_PER_HOUR", SYM(MAX_QUERIES_PER_HOUR), 0,0},
{ "MATCH", SYM(MATCH),0,0},
{ "MEDIUMBLOB", SYM(MEDIUMBLOB),0,0},
{ "MEDIUMTEXT", SYM(MEDIUMTEXT),0,0},
@@ -229,11 +246,14 @@ static SYMBOL symbols[] = {
{ "MYISAM", SYM(MYISAM_SYM),0,0},
{ "NATURAL", SYM(NATURAL),0,0},
{ "NATIONAL", SYM(NATIONAL_SYM),0,0},
+ { "NEXT", SYM(NEXT_SYM),0,0},
+ { "NEW", SYM(NEW_SYM),0,0},
{ "NCHAR", SYM(NCHAR_SYM),0,0},
- { "NUMERIC", SYM(NUMERIC_SYM),0,0},
{ "NO", SYM(NO_SYM),0,0},
{ "NOT", SYM(NOT),0,0},
{ "NULL", SYM(NULL_SYM),0,0},
+ { "NUMERIC", SYM(NUMERIC_SYM),0,0},
+ { "OFF", SYM(OFF),0,0},
{ "ON", SYM(ON),0,0},
{ "OPEN", SYM(OPEN_SYM),0,0},
{ "OPTIMIZE", SYM(OPTIMIZE),0,0},
@@ -248,11 +268,13 @@ static SYMBOL symbols[] = {
{ "PASSWORD", SYM(PASSWORD),0,0},
{ "PURGE", SYM(PURGE),0,0},
{ "PRECISION", SYM(PRECISION),0,0},
+ { "PREV", SYM(PREV_SYM),0,0},
{ "PRIMARY", SYM(PRIMARY_SYM),0,0},
{ "PROCEDURE", SYM(PROCEDURE),0,0},
{ "PROCESS" , SYM(PROCESS),0,0},
{ "PROCESSLIST", SYM(PROCESSLIST_SYM),0,0},
{ "PRIVILEGES", SYM(PRIVILEGES),0,0},
+ { "QUERY", SYM(QUERY_SYM),0,0},
{ "QUICK", SYM(QUICK),0,0},
{ "RAID0", SYM(RAID_0_SYM),0,0},
{ "READ", SYM(READ_SYM),0,0},
@@ -264,6 +286,7 @@ static SYMBOL symbols[] = {
{ "REPAIR", SYM(REPAIR),0,0},
{ "REPLACE", SYM(REPLACE),0,0},
{ "REPEATABLE", SYM(REPEATABLE_SYM),0,0},
+ { "REQUIRE", SYM(REQUIRE_SYM),0,0},
{ "RESET", SYM(RESET_SYM),0,0},
{ "RESTORE", SYM(RESTORE_SYM),0,0},
{ "RESTRICT", SYM(RESTRICT),0,0},
@@ -279,6 +302,7 @@ static SYMBOL symbols[] = {
{ "SERIALIZABLE", SYM(SERIALIZABLE_SYM),0,0},
{ "SESSION", SYM(SESSION_SYM),0,0},
{ "SET", SYM(SET),0,0},
+ { "SIGNED", SYM(SIGNED_SYM),0,0},
{ "SHARE", SYM(SHARE_SYM),0,0},
{ "SHOW", SYM(SHOW),0,0},
{ "SHUTDOWN", SYM(SHUTDOWN),0,0},
@@ -290,17 +314,23 @@ static SYMBOL symbols[] = {
{ "SQL_BIG_SELECTS", SYM(SQL_BIG_SELECTS),0,0},
{ "SQL_BIG_TABLES", SYM(SQL_BIG_TABLES),0,0},
{ "SQL_BUFFER_RESULT", SYM(SQL_BUFFER_RESULT),0,0},
+ { "SQL_CACHE", SYM(SQL_CACHE_SYM), 0, 0},
+ { "SQL_CALC_FOUND_ROWS", SYM(SQL_CALC_FOUND_ROWS),0,0},
{ "SQL_LOG_BIN", SYM(SQL_LOG_BIN),0,0},
{ "SQL_LOG_OFF", SYM(SQL_LOG_OFF),0,0},
{ "SQL_LOG_UPDATE", SYM(SQL_LOG_UPDATE),0,0},
{ "SQL_LOW_PRIORITY_UPDATES", SYM(SQL_LOW_PRIORITY_UPDATES),0,0},
{ "SQL_MAX_JOIN_SIZE",SYM(SQL_MAX_JOIN_SIZE), 0, 0},
+ { "SQL_NO_CACHE", SYM(SQL_NO_CACHE_SYM), 0, 0},
+ { "SQL_QUERY_CACHE_TYPE",SYM(SQL_QUERY_CACHE_TYPE_SYM), 0, 0},
{ "SQL_QUOTE_SHOW_CREATE",SYM(SQL_QUOTE_SHOW_CREATE), 0, 0},
{ "SQL_SAFE_UPDATES", SYM(SQL_SAFE_UPDATES),0,0},
{ "SQL_SELECT_LIMIT", SYM(SQL_SELECT_LIMIT),0,0},
{ "SQL_SLAVE_SKIP_COUNTER", SYM(SQL_SLAVE_SKIP_COUNTER),0,0},
{ "SQL_SMALL_RESULT", SYM(SQL_SMALL_RESULT),0,0},
+ { "SQL_THREAD", SYM(SQL_THREAD),0,0},
{ "SQL_WARNINGS", SYM(SQL_WARNINGS),0,0},
+ { "SSL", SYM(SSL_SYM),0,0},
{ "STRAIGHT_JOIN", SYM(STRAIGHT_JOIN),0,0},
{ "START", SYM(START_SYM),0,0},
{ "STARTING", SYM(STARTING),0,0},
@@ -308,6 +338,7 @@ static SYMBOL symbols[] = {
{ "STRING", SYM(STRING_SYM),0,0},
{ "STOP", SYM(STOP_SYM),0,0},
{ "STRIPED", SYM(RAID_STRIPED_SYM),0,0},
+ { "SUBJECT", SYM(SUBJECT_SYM),0,0},
{ "TABLE", SYM(TABLE_SYM),0,0},
{ "TABLES", SYM(TABLES),0,0},
{ "TEMPORARY", SYM(TEMPORARY),0,0},
@@ -330,6 +361,7 @@ static SYMBOL symbols[] = {
{ "UNLOCK", SYM(UNLOCK_SYM),0,0},
{ "UNSIGNED", SYM(UNSIGNED),0,0},
{ "USE", SYM(USE_SYM),0,0},
+ { "USE_FRM", SYM(USE_FRM),0,0},
{ "USING", SYM(USING),0,0},
{ "UPDATE", SYM(UPDATE_SYM),0,0},
{ "USAGE", SYM(USAGE),0,0},
@@ -343,6 +375,7 @@ static SYMBOL symbols[] = {
{ "WRITE", SYM(WRITE_SYM),0,0},
{ "WHEN", SYM(WHEN_SYM),0,0},
{ "WHERE", SYM(WHERE),0,0},
+ { "X509", SYM(X509_SYM),0,0},
{ "YEAR", SYM(YEAR_SYM),0,0},
{ "YEAR_MONTH", SYM(YEAR_MONTH_SYM),0,0},
{ "ZEROFILL", SYM(ZEROFILL),0,0},
@@ -363,7 +396,9 @@ static SYMBOL sql_functions[] = {
{ "BIT_COUNT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_bit_count)},
{ "BIT_OR", SYM(BIT_OR),0,0},
{ "BIT_AND", SYM(BIT_AND),0,0},
+ { "CAST", SYM(CAST_SYM),0,0},
{ "CEILING", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ceiling)},
+ { "BIT_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_bit_length)},
{ "CHAR_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_char_length)},
{ "CHARACTER_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_char_length)},
{ "COALESCE", SYM(COALESCE),0,0},
@@ -371,6 +406,7 @@ static SYMBOL sql_functions[] = {
{ "CONCAT_WS", SYM(CONCAT_WS),0,0},
{ "CONNECTION_ID", SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_connection_id)},
{ "CONV", SYM(FUNC_ARG3),0,CREATE_FUNC(create_func_conv)},
+ { "CONVERT", SYM(CONVERT_SYM),0,0},
{ "COUNT", SYM(COUNT_SYM),0,0},
{ "COS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_cos)},
{ "COT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_cot)},
@@ -385,6 +421,8 @@ static SYMBOL sql_functions[] = {
{ "DAYOFYEAR", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_dayofyear)},
{ "DECODE", SYM(DECODE_SYM),0,0},
{ "DEGREES", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_degrees)},
+ { "DES_ENCRYPT", SYM(DES_ENCRYPT_SYM),0,0},
+ { "DES_DECRYPT", SYM(DES_DECRYPT_SYM),0,0},
{ "ELT", SYM(ELT_FUNC),0,0},
{ "ENCODE", SYM(ENCODE_SYM),0,0},
{ "ENCRYPT", SYM(ENCRYPT),0,0},
@@ -395,6 +433,7 @@ static SYMBOL sql_functions[] = {
{ "FIND_IN_SET", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_find_in_set)},
{ "FLOOR", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_floor)},
{ "FORMAT", SYM(FORMAT_SYM),0,0},
+ { "FOUND_ROWS", SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_found_rows)},
{ "FROM_DAYS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_from_days)},
{ "FROM_UNIXTIME", SYM(FROM_UNIXTIME),0,0},
{ "GET_LOCK", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_get_lock)},
diff --git a/sql/lex_symbol.h b/sql/lex_symbol.h
index a011e27b59e..9fff1751b1b 100644
--- a/sql/lex_symbol.h
+++ b/sql/lex_symbol.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 */
diff --git a/sql/lock.cc b/sql/lock.cc
index a9054b99186..db849757741 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -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 */
@@ -55,33 +55,13 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **tables,uint count)
Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
Wait until the lock is gone
*/
- if (thd->global_read_lock) // This thread had the read locks
+ if (wait_if_global_read_lock(thd, 1))
{
- my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE,MYF(0),
- write_lock_used->table_name);
my_free((gptr) sql_lock,MYF(0));
sql_lock=0;
break;
}
-
- pthread_mutex_lock(&LOCK_open);
- thd->mysys_var->current_mutex= &LOCK_open;
- thd->mysys_var->current_cond= &COND_refresh;
- thd->proc_info="Waiting for table";
-
- while (global_read_lock && ! thd->killed &&
- thd->version == refresh_version)
- {
- (void) pthread_cond_wait(&COND_refresh,&LOCK_open);
- }
- pthread_mutex_unlock(&LOCK_open);
- pthread_mutex_lock(&thd->mysys_var->mutex);
- thd->mysys_var->current_mutex= 0;
- thd->mysys_var->current_cond= 0;
- thd->proc_info= 0;
- pthread_mutex_unlock(&thd->mysys_var->mutex);
-
- if (thd->version != refresh_version || thd->killed)
+ if (thd->version != refresh_version)
{
my_free((gptr) sql_lock,MYF(0));
goto retry;
@@ -401,6 +381,36 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
*****************************************************************************/
/*
+ Lock and wait for the named lock.
+ Returns 0 on ok
+*/
+
+int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list)
+{
+ int lock_retcode;
+ int error= -1;
+ DBUG_ENTER("lock_and_wait_for_table_name");
+
+ if (wait_if_global_read_lock(thd,0))
+ DBUG_RETURN(1);
+ VOID(pthread_mutex_lock(&LOCK_open));
+ if ((lock_retcode = lock_table_name(thd, table_list)) < 0)
+ goto end;
+ if (lock_retcode && wait_for_locked_table_names(thd, table_list))
+ {
+ unlock_table_name(thd, table_list);
+ goto end;
+ }
+ error=0;
+
+end:
+ pthread_mutex_unlock(&LOCK_open);
+ start_waiting_global_read_lock(thd);
+ DBUG_RETURN(error);
+}
+
+
+/*
Put a not open table with an old refresh version in the table cache.
This will force any other threads that uses the table to release it
as soon as possible.
@@ -411,7 +421,6 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
> 0 table locked, but someone is using it
*/
-
int lock_table_name(THD *thd, TABLE_LIST *table_list)
{
TABLE *table;
@@ -429,10 +438,11 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list)
if (table->in_use == thd)
DBUG_RETURN(0);
- /* Create a table entry with the right key and with an old refresh version */
- /* Note that we must use my_malloc() here as this is freed by the table
- cache */
-
+ /*
+ Create a table entry with the right key and with an old refresh version
+ Note that we must use my_malloc() here as this is freed by the table
+ cache
+ */
if (!(table= (TABLE*) my_malloc(sizeof(*table)+key_length,
MYF(MY_WME | MY_ZEROFILL))))
DBUG_RETURN(-1);
@@ -510,3 +520,102 @@ static void print_lock_error(int error)
DBUG_VOID_RETURN;
}
+
+/****************************************************************************
+ Handling of global read locks
+
+ The global locks are handled through the global variables:
+ global_read_lock
+ waiting_for_read_lock
+ protect_against_global_read_lock
+****************************************************************************/
+
+volatile uint global_read_lock=0;
+static volatile uint protect_against_global_read_lock=0;
+static volatile uint waiting_for_read_lock=0;
+
+bool lock_global_read_lock(THD *thd)
+{
+ DBUG_ENTER("lock_global_read_lock");
+
+ if (!thd->global_read_lock)
+ {
+ (void) pthread_mutex_lock(&LOCK_open);
+ const char *old_message=thd->enter_cond(&COND_refresh, &LOCK_open,
+ "Waiting to get readlock");
+ DBUG_PRINT("info",
+ ("waiting_for: %d protect_against: %d",
+ waiting_for_read_lock, protect_against_global_read_lock));
+
+ waiting_for_read_lock++;
+ while (protect_against_global_read_lock && !thd->killed)
+ pthread_cond_wait(&COND_refresh, &LOCK_open);
+ waiting_for_read_lock--;
+ thd->exit_cond(old_message);
+ if (thd->killed)
+ {
+ (void) pthread_mutex_unlock(&LOCK_open);
+ DBUG_RETURN(1);
+ }
+ thd->global_read_lock=1;
+ global_read_lock++;
+ (void) pthread_mutex_unlock(&LOCK_open);
+ }
+ DBUG_RETURN(0);
+}
+
+void unlock_global_read_lock(THD *thd)
+{
+ uint tmp;
+ thd->global_read_lock=0;
+ pthread_mutex_lock(&LOCK_open);
+ tmp= --global_read_lock;
+ pthread_mutex_unlock(&LOCK_open);
+ /* Send the signal outside the mutex to avoid a context switch */
+ if (!tmp)
+ pthread_cond_broadcast(&COND_refresh);
+}
+
+
+bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh)
+{
+ const char *old_message;
+ bool result=0;
+ DBUG_ENTER("wait_if_global_read_lock");
+
+ (void) pthread_mutex_lock(&LOCK_open);
+ if (global_read_lock)
+ {
+ if (thd->global_read_lock) // This thread had the read locks
+ {
+ my_error(ER_CANT_UPDATE_WITH_READLOCK,MYF(0));
+ (void) pthread_mutex_unlock(&LOCK_open);
+ DBUG_RETURN(1);
+ }
+ old_message=thd->enter_cond(&COND_refresh, &LOCK_open,
+ "Waiting for release of readlock");
+ while (global_read_lock && ! thd->killed &&
+ (!abort_on_refresh || thd->version == refresh_version))
+ (void) pthread_cond_wait(&COND_refresh,&LOCK_open);
+ if (thd->killed)
+ result=1;
+ thd->exit_cond(old_message);
+ }
+ if (!abort_on_refresh && !result)
+ protect_against_global_read_lock++;
+ pthread_mutex_unlock(&LOCK_open);
+ DBUG_RETURN(result);
+}
+
+
+void start_waiting_global_read_lock(THD *thd)
+{
+ bool tmp;
+ DBUG_ENTER("start_waiting_global_read_lock");
+ (void) pthread_mutex_lock(&LOCK_open);
+ tmp= (!--protect_against_global_read_lock && waiting_for_read_lock);
+ (void) pthread_mutex_unlock(&LOCK_open);
+ if (tmp)
+ pthread_cond_broadcast(&COND_refresh);
+ DBUG_VOID_RETURN;
+}
diff --git a/sql/log.cc b/sql/log.cc
index bc2b19d921f..1052b3379b3 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -29,6 +29,7 @@
#include <my_dir.h>
#include <stdarg.h>
#include <m_ctype.h> // For test_if_number
+#include <assert.h>
MYSQL_LOG mysql_log,mysql_update_log,mysql_slow_log,mysql_bin_log;
extern I_List<i_string> binlog_do_db, binlog_ignore_db;
@@ -81,7 +82,8 @@ static int find_uniq_filename(char *name)
MYSQL_LOG::MYSQL_LOG(): last_time(0), query_start(0),index_file(-1),
name(0), log_type(LOG_CLOSED),write_error(0),
- inited(0), no_rotate(0)
+ inited(0), file_id(1),no_rotate(0),
+ need_start_event(1)
{
/*
We don't want to intialize LOCK_Log here as the thread system may
@@ -136,14 +138,19 @@ bool MYSQL_LOG::open_index( int options)
MYF(MY_WME))) < 0);
}
-void MYSQL_LOG::init(enum_log_type log_type_arg)
+void MYSQL_LOG::init(enum_log_type log_type_arg,
+ enum cache_type io_cache_type_arg,
+ bool no_auto_events_arg)
{
log_type = log_type_arg;
+ io_cache_type = io_cache_type_arg;
+ no_auto_events = no_auto_events_arg;
if (!inited)
{
inited=1;
(void) pthread_mutex_init(&LOCK_log,MY_MUTEX_INIT_SLOW);
(void) pthread_mutex_init(&LOCK_index, MY_MUTEX_INIT_SLOW);
+ (void) pthread_cond_init(&update_cond, 0);
}
}
@@ -157,16 +164,17 @@ void MYSQL_LOG::close_index()
}
void MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
- const char *new_name)
+ const char *new_name, enum cache_type io_cache_type_arg,
+ bool no_auto_events_arg)
{
MY_STAT tmp_stat;
char buff[512];
File file= -1;
bool do_magic;
-
+ int open_flags = O_CREAT | O_APPEND | O_BINARY;
if (!inited && log_type_arg == LOG_BIN && *fn_ext(log_name))
no_rotate = 1;
- init(log_type_arg);
+ init(log_type_arg,io_cache_type_arg,no_auto_events_arg);
if (!(name=my_strdup(log_name,MYF(MY_WME))))
goto err;
@@ -174,7 +182,12 @@ void MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
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;
+ else
+ open_flags |= O_WRONLY;
+
if (log_type == LOG_BIN && !index_file_name[0])
fn_format(index_file_name, name, mysql_data_home, ".index", 6);
@@ -182,9 +195,9 @@ void MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
do_magic = ((log_type == LOG_BIN) && !my_stat(log_file_name,
&tmp_stat, MYF(0)));
- if ((file=my_open(log_file_name,O_CREAT | O_APPEND | O_WRONLY | O_BINARY,
+ if ((file=my_open(log_file_name,open_flags,
MYF(MY_WME | ME_WAITTANG))) < 0 ||
- init_io_cache(&log_file, file, IO_SIZE, WRITE_CACHE,
+ init_io_cache(&log_file, file, IO_SIZE, io_cache_type,
my_tell(file,MYF(MY_WME)), 0, MYF(MY_WME | MY_NABP)))
goto err;
@@ -220,19 +233,26 @@ void MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
}
else if (log_type == LOG_BIN)
{
+ bool error;
/*
Explanation of the boolean black magic:
if we are supposed to write magic number try write
- clean up if failed
+ clean
+up if failed
then if index_file has not been previously opened, try to open it
clean up if failed
*/
if ((do_magic && my_b_write(&log_file, (byte*) BINLOG_MAGIC, 4)) ||
open_index(O_APPEND | O_RDWR | O_CREAT))
goto err;
- Start_log_event s;
- bool error;
- s.write(&log_file);
+
+ if (need_start_event && !no_auto_events)
+ {
+ Start_log_event s;
+ s.set_log_pos(this);
+ s.write(&log_file);
+ need_start_event=0;
+ }
flush_io_cache(&log_file);
pthread_mutex_lock(&LOCK_index);
error=(my_write(index_file, (byte*) log_file_name, strlen(log_file_name),
@@ -254,9 +274,7 @@ err:
end_io_cache(&log_file);
x_free(name); name=0;
log_type=LOG_CLOSED;
-
return;
-
}
int MYSQL_LOG::get_current_log(LOG_INFO* linfo)
@@ -269,7 +287,8 @@ int MYSQL_LOG::get_current_log(LOG_INFO* linfo)
}
// if log_name is "" we stop at the first entry
-int MYSQL_LOG::find_first_log(LOG_INFO* linfo, const char* log_name)
+int MYSQL_LOG::find_first_log(LOG_INFO* linfo, const char* log_name,
+ bool need_mutex)
{
if (index_file < 0)
return LOG_INFO_INVALID;
@@ -280,7 +299,8 @@ int MYSQL_LOG::find_first_log(LOG_INFO* linfo, const char* log_name)
// mutex needed because we need to make sure the file pointer does not move
// from under our feet
- pthread_mutex_lock(&LOCK_index);
+ if (need_mutex)
+ pthread_mutex_lock(&LOCK_index);
if (init_io_cache(&io_cache, index_file, IO_SIZE, READ_CACHE, (my_off_t) 0,
0, MYF(MY_WME)))
{
@@ -309,14 +329,15 @@ int MYSQL_LOG::find_first_log(LOG_INFO* linfo, const char* log_name)
error = 0;
err:
- pthread_mutex_unlock(&LOCK_index);
+ if (need_mutex)
+ pthread_mutex_unlock(&LOCK_index);
end_io_cache(&io_cache);
return error;
}
-int MYSQL_LOG::find_next_log(LOG_INFO* linfo)
+int MYSQL_LOG::find_next_log(LOG_INFO* linfo, bool need_lock)
{
// mutex needed because we need to make sure the file pointer does not move
// from under our feet
@@ -325,8 +346,8 @@ int MYSQL_LOG::find_next_log(LOG_INFO* linfo)
char* fname = linfo->log_file_name;
IO_CACHE io_cache;
uint length;
-
- pthread_mutex_lock(&LOCK_index);
+ if (need_lock)
+ pthread_mutex_lock(&LOCK_index);
if (init_io_cache(&io_cache, index_file, IO_SIZE,
READ_CACHE, (my_off_t) linfo->index_file_offset, 0,
MYF(MY_WME)))
@@ -344,16 +365,135 @@ int MYSQL_LOG::find_next_log(LOG_INFO* linfo)
error = 0;
err:
- pthread_mutex_unlock(&LOCK_index);
+ if (need_lock)
+ pthread_mutex_unlock(&LOCK_index);
end_io_cache(&io_cache);
return error;
}
-
+
+int MYSQL_LOG::reset_logs(THD* thd)
+{
+ LOG_INFO linfo;
+ int error=0;
+ const char* save_name;
+ enum_log_type save_log_type;
+ pthread_mutex_lock(&LOCK_log);
+ if (find_first_log(&linfo,""))
+ {
+ error=1;
+ goto err;
+ }
+
+ for(;;)
+ {
+ my_delete(linfo.log_file_name, MYF(MY_WME));
+ if (find_next_log(&linfo))
+ break;
+ }
+ save_name=name;
+ name=0;
+ save_log_type=log_type;
+ close(1);
+ my_delete(index_file_name, MYF(MY_WME));
+ if (thd && !thd->slave_thread)
+ need_start_event=1;
+ open(save_name,save_log_type,0,io_cache_type,no_auto_events);
+ my_free((gptr)save_name,MYF(0));
+err:
+ pthread_mutex_unlock(&LOCK_log);
+ return error;
+}
+
+
+int MYSQL_LOG::purge_first_log(struct st_relay_log_info* rli)
+{
+ // pre-conditions
+ DBUG_ASSERT(is_open());
+ DBUG_ASSERT(index_file >= 0);
+ DBUG_ASSERT(rli->slave_running == 1);
+ DBUG_ASSERT(!strcmp(rli->linfo.log_file_name,rli->relay_log_name));
+ /*
+ Assume that we have previously read the first log and
+ stored it in rli->relay_log_name
+ */
+ DBUG_ASSERT(rli->linfo.index_file_offset ==
+ strlen(rli->relay_log_name) + 1);
+ int tmp_fd;
+ char* fname, *io_buf;
+ int error = 0;
+
+ if (!(fname= (char*) my_malloc(IO_SIZE+FN_REFLEN, MYF(MY_WME))))
+ return 1;
+ pthread_mutex_lock(&LOCK_index);
+ my_seek(index_file,rli->linfo.index_file_offset,
+ MY_SEEK_SET, MYF(MY_WME));
+ io_buf = fname + FN_REFLEN;
+ strxmov(fname,rli->relay_log_name,".tmp",NullS);
+
+ if ((tmp_fd = my_open(fname,O_CREAT|O_BINARY|O_RDWR, MYF(MY_WME))) < 0)
+ {
+ error = 1;
+ goto err;
+ }
+ for (;;)
+ {
+ int bytes_read;
+ bytes_read = my_read(index_file, (byte*) io_buf, IO_SIZE, MYF(0));
+ if (bytes_read < 0) // error
+ {
+ error=1;
+ goto err;
+ }
+ if (!bytes_read)
+ break; // end of file
+ // otherwise, we've read something and need to write it out
+ if (my_write(tmp_fd, (byte*) io_buf, bytes_read, MYF(MY_WME|MY_NABP)))
+ {
+ error=1;
+ goto err;
+ }
+ }
+
+err:
+ if (tmp_fd)
+ my_close(tmp_fd, MYF(MY_WME));
+ if (error)
+ my_delete(fname, MYF(0)); // do not report error if the file is not there
+ else
+ {
+ my_close(index_file, MYF(MY_WME));
+ if (my_rename(fname,index_file_name,MYF(MY_WME)) ||
+ (index_file=my_open(index_file_name,O_BINARY|O_RDWR|O_APPEND,
+ MYF(MY_WME)))<0 ||
+ my_delete(rli->relay_log_name, MYF(MY_WME)))
+ error=1;
+ if ((error=find_first_log(&rli->linfo,"",0/*no mutex*/)))
+ {
+ char buff[22];
+ sql_print_error("next log error=%d,offset=%s,log=%s",error,
+ llstr(rli->linfo.index_file_offset,buff),
+ rli->linfo.log_file_name);
+ goto err2;
+ }
+ rli->relay_log_pos = 4;
+ strnmov(rli->relay_log_name,rli->linfo.log_file_name,
+ sizeof(rli->relay_log_name));
+ }
+ /*
+ No need to free io_buf because we allocated both fname and io_buf in
+ one malloc()
+ */
+
+err2:
+ pthread_mutex_unlock(&LOCK_index);
+ my_free(fname, MYF(MY_WME));
+ return error;
+}
+
+
int MYSQL_LOG::purge_logs(THD* thd, const char* to_log)
{
- if (index_file < 0) return LOG_INFO_INVALID;
- if (no_rotate) return LOG_INFO_PURGE_NO_ROTATE;
int error;
char fname[FN_REFLEN];
char *p;
@@ -364,6 +504,10 @@ int MYSQL_LOG::purge_logs(THD* thd, const char* to_log)
LINT_INIT(purge_offset);
IO_CACHE io_cache;
+ if (index_file < 0)
+ return LOG_INFO_INVALID;
+ if (no_rotate)
+ return LOG_INFO_PURGE_NO_ROTATE;
pthread_mutex_lock(&LOCK_index);
if (init_io_cache(&io_cache,index_file, IO_SIZE*2, READ_CACHE, (my_off_t) 0,
@@ -385,9 +529,8 @@ int MYSQL_LOG::purge_logs(THD* thd, const char* to_log)
goto err;
}
logs_to_keep_inited = 1;
-
- for(;;)
+ for (;;)
{
my_off_t init_purge_offset= my_b_tell(&io_cache);
if (!(fname_len=my_b_gets(&io_cache, fname, FN_REFLEN)))
@@ -399,14 +542,14 @@ int MYSQL_LOG::purge_logs(THD* thd, const char* to_log)
}
fname[--fname_len]=0; // kill \n
- if(!memcmp(fname, to_log, fname_len + 1 ))
+ if (!memcmp(fname, to_log, fname_len + 1 ))
{
found_log = 1;
purge_offset = init_purge_offset;
}
// if one of the logs before the target is in use
- if(!found_log && log_in_use(fname))
+ if (!found_log && log_in_use(fname))
{
error = LOG_INFO_IN_USE;
goto err;
@@ -422,13 +565,13 @@ int MYSQL_LOG::purge_logs(THD* thd, const char* to_log)
}
end_io_cache(&io_cache);
- if(!found_log)
+ if (!found_log)
{
error = LOG_INFO_EOF;
goto err;
}
- for(i = 0; i < logs_to_purge.elements; i++)
+ for (i = 0; i < logs_to_purge.elements; i++)
{
char* l;
get_dynamic(&logs_to_purge, (gptr)&l, i);
@@ -436,9 +579,10 @@ int MYSQL_LOG::purge_logs(THD* thd, const char* to_log)
sql_print_error("Error deleting %s during purge", l);
}
- // if we get killed -9 here, the sysadmin would have to do a small
- // vi job on the log index file after restart - otherwise, this should
- // be safe
+ /*
+ If we get killed -9 here, the sysadmin would have to edit
+ the log index file after restart - otherwise, this should be safe
+ */
#ifdef HAVE_FTRUNCATE
if (ftruncate(index_file,0))
{
@@ -451,9 +595,9 @@ during log purge for write");
#else
my_close(index_file, MYF(MY_WME));
my_delete(index_file_name, MYF(MY_WME));
- if(!(index_file = my_open(index_file_name,
+ if ((index_file = my_open(index_file_name,
O_CREAT | O_BINARY | O_RDWR | O_APPEND,
- MYF(MY_WME))))
+ MYF(MY_WME)))<0)
{
sql_print_error("Could not re-open the binlog index file \
during log purge for write");
@@ -462,7 +606,7 @@ during log purge for write");
}
#endif
- for(i = 0; i < logs_to_keep.elements; i++)
+ for (i = 0; i < logs_to_keep.elements; i++)
{
char* l;
get_dynamic(&logs_to_keep, (gptr)&l, i);
@@ -480,15 +624,14 @@ during log purge for write");
err:
pthread_mutex_unlock(&LOCK_index);
- if(logs_to_purge_inited)
+ if (logs_to_purge_inited)
delete_dynamic(&logs_to_purge);
- if(logs_to_keep_inited)
+ if (logs_to_keep_inited)
delete_dynamic(&logs_to_keep);
end_io_cache(&io_cache);
return error;
}
-
// we assume that buf has at least FN_REFLEN bytes alloced
void MYSQL_LOG::make_log_name(char* buf, const char* log_ident)
{
@@ -533,20 +676,36 @@ void MYSQL_LOG::new_file(bool inside_mutex)
}
if (log_type == LOG_BIN)
{
- /*
- We log the whole file name for log file as the user may decide
- to change base names at some point.
- */
- Rotate_log_event r(new_name+dirname_length(new_name));
- r.write(&log_file);
- VOID(pthread_cond_broadcast(&COND_binlog_update));
+ if (!no_auto_events)
+ {
+ /*
+ We log the whole file name for log file as the user may decide
+ to change base names at some point.
+ */
+ THD* thd = current_thd;
+ Rotate_log_event r(thd,new_name+dirname_length(new_name));
+ r.set_log_pos(this);
+
+ /*
+ This log rotation could have been initiated by a master of
+ the slave running with log-bin we set the flag on rotate
+ event to prevent inifinite log rotation loop
+ */
+ if (thd && thd->slave_thread)
+ r.flags |= LOG_EVENT_FORCED_ROTATE_F;
+ r.write(&log_file);
+ }
+ // update needs to be signaled 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();
}
+ else
+ strmov(new_name, old_name); // Reopen old file name
}
- else
- strmov(new_name, old_name); // Reopen old file name
name=0;
close();
- open(old_name, log_type, new_name);
+ open(old_name, log_type, new_name, io_cache_type, no_auto_events);
my_free(old_name,MYF(0));
last_time=query_start=0;
write_error=0;
@@ -555,6 +714,58 @@ void MYSQL_LOG::new_file(bool inside_mutex)
}
}
+bool MYSQL_LOG::append(Log_event* ev)
+{
+ bool error = 0;
+ pthread_mutex_lock(&LOCK_log);
+
+ DBUG_ASSERT(log_file.type == SEQ_READ_APPEND);
+ // Log_event::write() is smart enough to use my_b_write() or
+ // my_b_append() depending on the kind of cache we have
+ if (ev->write(&log_file))
+ {
+ error=1;
+ goto err;
+ }
+ if ((uint)my_b_append_tell(&log_file) > max_binlog_size)
+ {
+ new_file(1);
+ }
+ signal_update();
+err:
+ pthread_mutex_unlock(&LOCK_log);
+ return error;
+}
+
+bool MYSQL_LOG::appendv(const char* buf, uint len,...)
+{
+ bool error = 0;
+ va_list(args);
+ va_start(args,len);
+
+ DBUG_ASSERT(log_file.type == SEQ_READ_APPEND);
+
+ pthread_mutex_lock(&LOCK_log);
+ do
+ {
+ if (my_b_append(&log_file,(byte*) buf,len))
+ {
+ error = 1;
+ break;
+ }
+ } while ((buf=va_arg(args,const char*)) && (len=va_arg(args,uint)));
+
+ if ((uint) my_b_append_tell(&log_file) > max_binlog_size)
+ {
+ new_file(1);
+ }
+
+ if (!error)
+ signal_update();
+ pthread_mutex_unlock(&LOCK_log);
+ return error;
+}
+
bool MYSQL_LOG::write(THD *thd,enum enum_server_command command,
const char *format,...)
@@ -635,9 +846,8 @@ bool MYSQL_LOG::write(THD *thd,enum enum_server_command command,
return 0;
}
-/* Write to binary log in a format to be used for replication */
-bool MYSQL_LOG::write(Query_log_event* event_info)
+bool MYSQL_LOG::write(Log_event* event_info)
{
/* In most cases this is only called if 'is_open()' is true */
bool error=0;
@@ -649,35 +859,46 @@ bool MYSQL_LOG::write(Query_log_event* event_info)
if (is_open())
{
THD *thd=event_info->thd;
- IO_CACHE *file = (event_info->cache_stmt ? &thd->transaction.trans_log :
+ const char* db = event_info->get_db();
+#ifdef USING_TRANSACTIONS
+ IO_CACHE *file = ((event_info->get_cache_stmt() && thd) ?
+ &thd->transaction.trans_log :
&log_file);
- if ((!(thd->options & OPTION_BIN_LOG) &&
+#else
+ IO_CACHE *file = &log_file;
+#endif
+ if ((thd && !(thd->options & OPTION_BIN_LOG) &&
(thd->master_access & PROCESS_ACL)) ||
- !db_ok(event_info->db, binlog_do_db, binlog_ignore_db))
+ (db && !db_ok(db, binlog_do_db, binlog_ignore_db)))
{
VOID(pthread_mutex_unlock(&LOCK_log));
return 0;
}
error=1;
-
- if (thd->last_insert_id_used)
+ /*
+ No check for auto events flag here - this write method should
+ never be called if auto-events are enabled
+ */
+ if (thd && thd->last_insert_id_used)
{
- Intvar_log_event e((uchar)LAST_INSERT_ID_EVENT, thd->last_insert_id);
- if(thd->server_id)
- e.server_id = thd->server_id;
+ Intvar_log_event e(thd,(uchar)LAST_INSERT_ID_EVENT,thd->last_insert_id);
+ e.set_log_pos(this);
+ if (thd->server_id)
+ e.server_id = thd->server_id;
if (e.write(file))
goto err;
}
- if (thd->insert_id_used)
+ if (thd && thd->insert_id_used)
{
- Intvar_log_event e((uchar)INSERT_ID_EVENT, thd->last_insert_id);
- if(thd->server_id)
- e.server_id = thd->server_id;
+ Intvar_log_event e(thd,(uchar)INSERT_ID_EVENT,thd->last_insert_id);
+ e.set_log_pos(this);
+ if (thd->server_id)
+ e.server_id = thd->server_id;
if (e.write(file))
goto err;
}
- if (thd->convert_set)
+ if (thd && thd->convert_set)
{
char buf[1024] = "SET CHARACTER SET ";
char* p = strend(buf);
@@ -686,27 +907,32 @@ bool MYSQL_LOG::write(Query_log_event* event_info)
// just in case somebody wants it later
thd->query_length = (uint)(p - buf);
Query_log_event e(thd, buf);
+ e.set_log_pos(this);
if (e.write(file))
goto err;
thd->query_length = save_query_length; // clean up
}
+ event_info->set_log_pos(this);
if (event_info->write(file) ||
file == &log_file && flush_io_cache(file))
goto err;
error=0;
- should_rotate = (file == &log_file && my_b_tell(file) >= max_binlog_size);
- /* 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! */
+ /*
+ 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!
+ */
- if (file == &log_file) {
+ if (file == &log_file)
+ {
error = ha_report_binlog_offset_and_commit(thd, log_file_name,
- file->pos_in_file);
+ file->pos_in_file);
+ should_rotate= (my_b_tell(file) >= (my_off_t) max_binlog_size);
}
err:
@@ -719,7 +945,7 @@ err:
write_error=1;
}
if (file == &log_file)
- VOID(pthread_cond_broadcast(&COND_binlog_update));
+ signal_update();
}
if (should_rotate)
new_file(1); // inside mutex
@@ -727,6 +953,15 @@ err:
return error;
}
+uint MYSQL_LOG::next_file_id()
+{
+ uint res;
+ pthread_mutex_lock(&LOCK_log);
+ res = file_id++;
+ pthread_mutex_unlock(&LOCK_log);
+ return res;
+}
+
/*
Write a cached log entry to the binary log
We only come here if there is something in the cache.
@@ -741,7 +976,7 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache)
if (is_open())
{
uint length;
-
+ //QQ: this looks like a bug - why READ_CACHE?
if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0))
{
sql_print_error(ER(ER_ERROR_ON_WRITE), cache->file_name, errno);
@@ -750,13 +985,13 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache)
length=my_b_bytes_in_cache(cache);
do
{
- if (my_b_write(&log_file, cache->rc_pos, length))
+ if (my_b_write(&log_file, cache->read_pos, length))
{
if (!write_error)
sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
goto err;
}
- cache->rc_pos=cache->rc_end; // Mark buffer used up
+ cache->read_pos=cache->read_end; // Mark buffer used up
} while ((length=my_b_fill(cache)));
if (flush_io_cache(&log_file))
{
@@ -780,7 +1015,7 @@ err:
if (error)
write_error=1;
else
- VOID(pthread_cond_broadcast(&COND_binlog_update));
+ signal_update();
VOID(pthread_mutex_unlock(&LOCK_log));
@@ -788,42 +1023,6 @@ err:
}
-bool MYSQL_LOG::write(Load_log_event* event_info)
-{
- bool error=0;
- bool should_rotate = 0;
-
- if (inited)
- {
- VOID(pthread_mutex_lock(&LOCK_log));
- if (is_open())
- {
- THD *thd=event_info->thd;
- if ((thd->options & OPTION_BIN_LOG) ||
- !(thd->master_access & PROCESS_ACL))
- {
- if (event_info->write(&log_file) || flush_io_cache(&log_file))
- {
- if (!write_error)
- sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
- error=write_error=1;
- }
- should_rotate = (my_b_tell(&log_file) >= max_binlog_size);
- VOID(pthread_cond_broadcast(&COND_binlog_update));
- }
- }
-
- if(should_rotate)
- new_file(1); // inside mutex
-
- VOID(pthread_mutex_unlock(&LOCK_log));
- }
-
-
- return error;
-}
-
-
/* Write update log in a format suitable for incremental backup */
bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
@@ -946,20 +1145,37 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
return error;
}
+void MYSQL_LOG:: wait_for_update(THD* thd)
+{
+ const char* old_msg = thd->enter_cond(&update_cond, &LOCK_log,
+ "Slave: waiting for binlog update");
+ pthread_cond_wait(&update_cond, &LOCK_log);
+ // this is not a bug - we unlock the mutex for the caller, and expect him
+ // to lock it and then not unlock it upon return. This is a rather odd
+ // way of doing things, but this is the cleanest way I could think of to
+ // solve the race deadlock caused by THD::awake() first acquiring mysys_var
+ // mutex and then the current mutex, while wait_for_update being called with
+ // the current mutex already aquired and THD::exit_cond() trying to acquire
+ // mysys_var mutex. We do need the mutex to be acquired prior to the
+ // invocation of wait_for_update in all cases, so mutex acquisition inside
+ // wait_for_update() is not an option
+ pthread_mutex_unlock(&LOCK_log);
+ thd->exit_cond(old_msg);
+}
void MYSQL_LOG::close(bool exiting)
{ // One can't set log_type here!
if (is_open())
{
- File file=log_file.file;
- if (log_type == LOG_BIN)
+ if (log_type == LOG_BIN && !no_auto_events)
{
Stop_log_event s;
+ s.set_log_pos(this);
s.write(&log_file);
- VOID(pthread_cond_broadcast(&COND_binlog_update));
+ signal_update();
}
end_io_cache(&log_file);
- if (my_close(file,MYF(0)) < 0 && ! write_error)
+ if (my_close(log_file.file,MYF(0)) < 0 && ! write_error)
{
write_error=1;
sql_print_error(ER(ER_ERROR_ON_WRITE),name,errno);
diff --git a/sql/log_event.cc b/sql/log_event.cc
index c30d03adaf5..528110deb74 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -20,25 +20,377 @@
#pragma implementation // gcc: Class implementation
#endif
#include "mysql_priv.h"
+#include "slave.h"
+#include <my_dir.h>
#endif /* MYSQL_CLIENT */
+#include <assert.h>
-static void pretty_print_char(FILE* file, int c)
+inline int my_b_safe_write(IO_CACHE* file, const byte *buf,
+ int len)
{
+ /*
+ Sasha: We are not writing this with the ? operator to avoid hitting
+ a possible compiler bug. At least gcc 2.95 cannot deal with
+ several layers of ternary operators that evaluated comma(,) operator
+ expressions inside - I do have a test case if somebody wants it
+ */
+ if (file->type == SEQ_READ_APPEND)
+ return my_b_append(file, buf,len);
+ return my_b_write(file, buf,len);
+}
+
+#ifdef MYSQL_CLIENT
+static void pretty_print_str(FILE* file, char* str, int len)
+{
+ char* end = str + len;
fputc('\'', file);
- switch(c) {
- case '\n': fprintf(file, "\\n"); break;
- case '\r': fprintf(file, "\\r"); break;
- case '\\': fprintf(file, "\\\\"); break;
- case '\b': fprintf(file, "\\b"); break;
- case '\'': fprintf(file, "\\'"); break;
- case 0 : fprintf(file, "\\0"); break;
- default:
- fputc(c, file);
- break;
+ while (str < end)
+ {
+ char c;
+ switch ((c=*str++)) {
+ case '\n': fprintf(file, "\\n"); break;
+ case '\r': fprintf(file, "\\r"); break;
+ case '\\': fprintf(file, "\\\\"); break;
+ case '\b': fprintf(file, "\\b"); break;
+ case '\t': fprintf(file, "\\t"); break;
+ case '\'': fprintf(file, "\\'"); break;
+ case 0 : fprintf(file, "\\0"); break;
+ default:
+ fputc(c, file);
+ break;
+ }
}
fputc('\'', file);
}
+#endif
+
+#ifndef MYSQL_CLIENT
+
+inline int ignored_error_code(int err_code)
+{
+ return use_slave_mask && bitmap_is_set(&slave_error_mask, err_code);
+}
+
+
+static void pretty_print_str(String* packet, char* str, int len)
+{
+ char* end = str + len;
+ packet->append('\'');
+ while (str < end)
+ {
+ char c;
+ switch((c=*str++)) {
+ case '\n': packet->append( "\\n"); break;
+ case '\r': packet->append( "\\r"); break;
+ case '\\': packet->append( "\\\\"); break;
+ case '\b': packet->append( "\\b"); break;
+ case '\t': packet->append( "\\t"); break;
+ case '\'': packet->append( "\\'"); break;
+ case 0 : packet->append( "\\0"); break;
+ default:
+ packet->append((char)c);
+ break;
+ }
+ }
+ packet->append('\'');
+}
+
+
+static inline char* slave_load_file_stem(char*buf, uint file_id,
+ int event_server_id)
+{
+ fn_format(buf,"SQL_LOAD-",slave_load_tmpdir,"",4+32);
+ buf = strend(buf);
+ buf = int10_to_str(::server_id, buf, 10);
+ *buf++ = '-';
+ buf = int10_to_str(event_server_id, buf, 10);
+ *buf++ = '-';
+ return int10_to_str(file_id, buf, 10);
+}
+
+#endif
+
+const char* Log_event::get_type_str()
+{
+ switch(get_type_code())
+ {
+ case START_EVENT: return "Start";
+ case STOP_EVENT: return "Stop";
+ case QUERY_EVENT: return "Query";
+ case ROTATE_EVENT: return "Rotate";
+ case INTVAR_EVENT: return "Intvar";
+ case LOAD_EVENT: return "Load";
+ case NEW_LOAD_EVENT: return "New_load";
+ case SLAVE_EVENT: return "Slave";
+ case CREATE_FILE_EVENT: return "Create_file";
+ case APPEND_BLOCK_EVENT: return "Append_block";
+ case DELETE_FILE_EVENT: return "Delete_file";
+ case EXEC_LOAD_EVENT: return "Exec_load";
+ default: /* impossible */ return "Unknown";
+ }
+}
+
+#ifndef MYSQL_CLIENT
+Log_event::Log_event(THD* thd_arg, uint16 flags_arg):
+ exec_time(0),
+ flags(flags_arg),cached_event_len(0),
+ temp_buf(0),thd(thd_arg)
+{
+ if (thd)
+ {
+ server_id = thd->server_id;
+ when = thd->start_time;
+ log_pos = thd->log_pos;
+ }
+ else
+ {
+ server_id = ::server_id;
+ when = time(NULL);
+ log_pos=0;
+ }
+}
+
+static void cleanup_load_tmpdir()
+{
+ MY_DIR *dirp;
+ FILEINFO *file;
+ uint i;
+ if (!(dirp=my_dir(slave_load_tmpdir,MYF(MY_WME))))
+ return;
+
+ for (i=0;i<(uint)dirp->number_off_files;i++)
+ {
+ file=dirp->dir_entry+i;
+ if (!memcmp(file->name,"SQL_LOAD-",9))
+ my_delete(file->name,MYF(MY_WME));
+ }
+
+ my_dirend(dirp);
+}
+
+#endif
+
+Log_event::Log_event(const char* buf, bool old_format):
+ cached_event_len(0),temp_buf(0)
+{
+ when = uint4korr(buf);
+ server_id = uint4korr(buf + SERVER_ID_OFFSET);
+ if (old_format)
+ {
+ log_pos=0;
+ flags=0;
+ }
+ else
+ {
+ log_pos = uint4korr(buf + LOG_POS_OFFSET);
+ flags = uint2korr(buf + FLAGS_OFFSET);
+ }
+#ifndef MYSQL_CLIENT
+ thd = 0;
+#endif
+}
+
+
+#ifndef MYSQL_CLIENT
+
+int Log_event::exec_event(struct st_relay_log_info* rli)
+{
+ if (rli)
+ {
+ rli->inc_pos(get_event_len(),log_pos);
+ DBUG_ASSERT(rli->sql_thd != 0);
+ flush_relay_log_info(rli);
+ }
+ return 0;
+}
+
+void Log_event::pack_info(String* packet)
+{
+ net_store_data(packet, "", 0);
+}
+
+void Query_log_event::pack_info(String* packet)
+{
+ char buf[256];
+ String tmp(buf, sizeof(buf));
+ tmp.length(0);
+ if (db && db_len)
+ {
+ tmp.append("use ");
+ tmp.append(db, db_len);
+ tmp.append("; ", 2);
+ }
+
+ if (query && q_len)
+ tmp.append(query, q_len);
+ net_store_data(packet, (char*)tmp.ptr(), tmp.length());
+}
+
+void Start_log_event::pack_info(String* packet)
+{
+ char buf1[256];
+ String tmp(buf1, sizeof(buf1));
+ tmp.length(0);
+ char buf[22];
+
+ tmp.append("Server ver: ");
+ tmp.append(server_version);
+ tmp.append(", Binlog ver: ");
+ tmp.append(llstr(binlog_version, buf));
+ net_store_data(packet, tmp.ptr(), tmp.length());
+}
+
+void Load_log_event::pack_info(String* packet)
+{
+ char buf[256];
+ String tmp(buf, sizeof(buf));
+ tmp.length(0);
+ if(db && db_len)
+ {
+ tmp.append("use ");
+ tmp.append(db, db_len);
+ tmp.append("; ", 2);
+ }
+
+ tmp.append("LOAD DATA INFILE '");
+ tmp.append(fname, fname_len);
+ tmp.append("' ", 2);
+ if(sql_ex.opt_flags && REPLACE_FLAG )
+ tmp.append(" REPLACE ");
+ else if(sql_ex.opt_flags && IGNORE_FLAG )
+ tmp.append(" IGNORE ");
+
+ tmp.append("INTO TABLE ");
+ tmp.append(table_name);
+ if (sql_ex.field_term_len)
+ {
+ tmp.append(" FIELDS TERMINATED BY ");
+ pretty_print_str(&tmp, sql_ex.field_term, sql_ex.field_term_len);
+ }
+
+ if (sql_ex.enclosed_len)
+ {
+ if (sql_ex.opt_flags && OPT_ENCLOSED_FLAG )
+ tmp.append(" OPTIONALLY ");
+ tmp.append( " ENCLOSED BY ");
+ pretty_print_str(&tmp, sql_ex.enclosed, sql_ex.enclosed_len);
+ }
+
+ if (sql_ex.escaped_len)
+ {
+ tmp.append( " ESCAPED BY ");
+ pretty_print_str(&tmp, sql_ex.escaped, sql_ex.escaped_len);
+ }
+
+ if (sql_ex.line_term_len)
+ {
+ tmp.append(" LINES TERMINATED BY ");
+ pretty_print_str(&tmp, sql_ex.line_term, sql_ex.line_term_len);
+ }
+
+ if (sql_ex.line_start_len)
+ {
+ tmp.append(" LINES STARTING BY ");
+ pretty_print_str(&tmp, sql_ex.line_start, sql_ex.line_start_len);
+ }
+
+ if ((int)skip_lines > 0)
+ tmp.append( " IGNORE %ld LINES ", (long) skip_lines);
+
+ if (num_fields)
+ {
+ uint i;
+ const char* field = fields;
+ tmp.append(" (");
+ for(i = 0; i < num_fields; i++)
+ {
+ if(i)
+ tmp.append(" ,");
+ tmp.append( field);
+
+ field += field_lens[i] + 1;
+ }
+ tmp.append(')');
+ }
+
+ net_store_data(packet, tmp.ptr(), tmp.length());
+}
+
+void Rotate_log_event::pack_info(String* packet)
+{
+ char buf1[256];
+ String tmp(buf1, sizeof(buf1));
+ tmp.length(0);
+ char buf[22];
+ tmp.append(new_log_ident, ident_len);
+ tmp.append(";pos=");
+ tmp.append(llstr(pos,buf));
+ if(flags & LOG_EVENT_FORCED_ROTATE_F)
+ tmp.append("; forced by master");
+ net_store_data(packet, tmp.ptr(), tmp.length());
+}
+
+void Intvar_log_event::pack_info(String* packet)
+{
+ char buf1[256];
+ String tmp(buf1, sizeof(buf1));
+ tmp.length(0);
+ char buf[22];
+ tmp.append(get_var_type_name());
+ tmp.append('=');
+ tmp.append(llstr(val, buf));
+ net_store_data(packet, tmp.ptr(), tmp.length());
+}
+
+void Slave_log_event::pack_info(String* packet)
+{
+ char buf1[256];
+ String tmp(buf1, sizeof(buf1));
+ tmp.length(0);
+ char buf[22];
+ tmp.append("host=");
+ tmp.append(master_host);
+ tmp.append(",port=");
+ tmp.append(llstr(master_port,buf));
+ tmp.append(",log=");
+ tmp.append(master_log);
+ tmp.append(",pos=");
+ tmp.append(llstr(master_pos,buf));
+ net_store_data(packet, tmp.ptr(), tmp.length());
+}
+
+
+void Log_event::init_show_field_list(List<Item>* field_list)
+{
+ field_list->push_back(new Item_empty_string("Log_name", 20));
+ field_list->push_back(new Item_empty_string("Pos", 20));
+ field_list->push_back(new Item_empty_string("Event_type", 20));
+ field_list->push_back(new Item_empty_string("Server_id", 20));
+ field_list->push_back(new Item_empty_string("Orig_log_pos", 20));
+ field_list->push_back(new Item_empty_string("Info", 20));
+}
+
+int Log_event::net_send(THD* thd, const char* log_name, my_off_t pos)
+{
+ String* packet = &thd->packet;
+ const char* p = strrchr(log_name, FN_LIBCHAR);
+ const char* event_type;
+ if (p)
+ log_name = p + 1;
+
+ packet->length(0);
+ net_store_data(packet, log_name, strlen(log_name));
+ net_store_data(packet, (longlong) pos);
+ event_type = get_type_str();
+ net_store_data(packet, event_type, strlen(event_type));
+ net_store_data(packet, server_id);
+ net_store_data(packet, (longlong) log_pos);
+ pack_info(packet);
+ return my_net_write(&thd->net, (char*) packet->ptr(), packet->length());
+}
+
+#endif
int Query_log_event::write(IO_CACHE* file)
{
@@ -52,7 +404,6 @@ int Log_event::write(IO_CACHE* file)
int Log_event::write_header(IO_CACHE* file)
{
- // make sure to change this when the header gets bigger
char buf[LOG_EVENT_HEADER_LEN];
char* pos = buf;
int4store(pos, (ulong) when); // timestamp
@@ -63,7 +414,11 @@ int Log_event::write_header(IO_CACHE* file)
long tmp=get_data_size() + LOG_EVENT_HEADER_LEN;
int4store(pos, tmp);
pos += 4;
- return (my_b_write(file, (byte*) buf, (uint) (pos - buf)));
+ int4store(pos, log_pos);
+ pos += 4;
+ int2store(pos, flags);
+ pos += 2;
+ return (my_b_safe_write(file, (byte*) buf, (uint) (pos - buf)));
}
#ifndef MYSQL_CLIENT
@@ -117,157 +472,144 @@ int Log_event::read_log_event(IO_CACHE* file, String* packet,
#define UNLOCK_MUTEX
#endif
+#ifndef MYSQL_CLIENT
+#define LOCK_MUTEX if(log_lock) pthread_mutex_lock(log_lock);
+#else
+#define LOCK_MUTEX
+#endif
+
// 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)
+Log_event* Log_event::read_log_event(IO_CACHE* file,
+ pthread_mutex_t* log_lock,
+ bool old_format)
#else
-Log_event* Log_event::read_log_event(IO_CACHE* file)
+Log_event* Log_event::read_log_event(IO_CACHE* file, bool old_format)
#endif
{
- time_t timestamp;
- uint32 server_id;
-
- char buf[LOG_EVENT_HEADER_LEN-4];
-#ifndef MYSQL_CLIENT
- if(log_lock) pthread_mutex_lock(log_lock);
-#endif
- if (my_b_read(file, (byte *) buf, sizeof(buf)))
+ char head[LOG_EVENT_HEADER_LEN];
+ uint header_size = old_format ? OLD_HEADER_LEN :
+ LOG_EVENT_HEADER_LEN;
+ LOCK_MUTEX;
+ if (my_b_read(file, (byte *) head, header_size ))
{
- UNLOCK_MUTEX
- return NULL;
+ UNLOCK_MUTEX;
+ return 0;
}
- timestamp = uint4korr(buf);
- server_id = uint4korr(buf + 5);
-
- switch(buf[EVENT_TYPE_OFFSET])
- {
- case QUERY_EVENT:
+
+ uint data_len = uint4korr(head + EVENT_LEN_OFFSET);
+ char* buf = 0;
+ const char* error = 0;
+ Log_event* res = 0;
+
+ if (data_len > max_allowed_packet)
{
- Query_log_event* q = new Query_log_event(file, timestamp, server_id);
- UNLOCK_MUTEX
- if (!q->query)
- {
- delete q;
- q=NULL;
- }
- return q;
+ error = "Event too big";
+ goto err;
}
-
- case LOAD_EVENT:
+
+ if (data_len < header_size)
{
- Load_log_event* l = new Load_log_event(file, timestamp, server_id);
- UNLOCK_MUTEX
- if (!l->table_name)
- {
- delete l;
- l=NULL;
- }
- return l;
+ error = "Event too small";
+ goto err;
}
-
- case ROTATE_EVENT:
+ // some events use the extra byte to null-terminate strings
+ if (!(buf = my_malloc(data_len+1, MYF(MY_WME))))
{
- Rotate_log_event* r = new Rotate_log_event(file, timestamp, server_id);
- UNLOCK_MUTEX
- if (!r->new_log_ident)
- {
- delete r;
- r=NULL;
- }
- return r;
+ error = "Out of memory";
+ goto err;
}
-
- case INTVAR_EVENT:
+ buf[data_len] = 0;
+ memcpy(buf, head, header_size);
+ if (my_b_read(file, (byte*) buf + header_size,
+ data_len - header_size))
{
- Intvar_log_event* e = new Intvar_log_event(file, timestamp, server_id);
- UNLOCK_MUTEX
- if (e->type == INVALID_INT_EVENT)
- {
- delete e;
- e=NULL;
- }
- return e;
+ error = "read error";
+ goto err;
}
-
- case START_EVENT:
- {
- Start_log_event* e = new Start_log_event(file, timestamp, server_id);
- UNLOCK_MUTEX
- return e;
- }
- case STOP_EVENT:
- {
- Stop_log_event* e = new Stop_log_event(file, timestamp, server_id);
- UNLOCK_MUTEX
- return e;
- }
- default:
- break;
+ if ((res = read_log_event(buf, data_len, &error, old_format)))
+ res->register_temp_buf(buf);
+err:
+ UNLOCK_MUTEX;
+ if (error)
+ {
+ 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));
}
-
- // default
- UNLOCK_MUTEX
- return NULL;
+ return res;
}
-Log_event* Log_event::read_log_event(const char* buf, int event_len)
+Log_event* Log_event::read_log_event(const char* buf, int event_len,
+ const char **error, bool old_format)
{
- if(event_len < EVENT_LEN_OFFSET ||
- (uint)event_len != uint4korr(buf+EVENT_LEN_OFFSET))
+ if (event_len < EVENT_LEN_OFFSET ||
+ (uint)event_len != uint4korr(buf+EVENT_LEN_OFFSET))
return NULL; // general sanity check - will fail on a partial read
+ Log_event* ev = NULL;
+
switch(buf[EVENT_TYPE_OFFSET])
{
case QUERY_EVENT:
- {
- Query_log_event* q = new Query_log_event(buf, event_len);
- if (!q->query)
- {
- delete q;
- return NULL;
- }
-
- return q;
- }
-
+ ev = new Query_log_event(buf, event_len, old_format);
+ break;
case LOAD_EVENT:
- {
- Load_log_event* l = new Load_log_event(buf, event_len);
- if (!l->table_name)
- {
- delete l;
- return NULL;
- }
-
- return l;
- }
-
+ ev = new Create_file_log_event(buf, event_len, old_format);
+ break;
+ case NEW_LOAD_EVENT:
+ ev = new Load_log_event(buf, event_len, old_format);
+ break;
case ROTATE_EVENT:
- {
- Rotate_log_event* r = new Rotate_log_event(buf, event_len);
- if (!r->new_log_ident)
- {
- delete r;
- return NULL;
- }
-
- return r;
- }
- case START_EVENT: return new Start_log_event(buf);
- case STOP_EVENT: return new Stop_log_event(buf);
- case INTVAR_EVENT: return new Intvar_log_event(buf);
+ ev = new Rotate_log_event(buf, event_len, old_format);
+ break;
+ case SLAVE_EVENT:
+ ev = new Slave_log_event(buf, event_len);
+ break;
+ case CREATE_FILE_EVENT:
+ ev = new Create_file_log_event(buf, event_len, old_format);
+ break;
+ case APPEND_BLOCK_EVENT:
+ ev = new Append_block_log_event(buf, event_len);
+ break;
+ case DELETE_FILE_EVENT:
+ ev = new Delete_file_log_event(buf, event_len);
+ break;
+ case EXEC_LOAD_EVENT:
+ ev = new Execute_load_log_event(buf, event_len);
+ break;
+ case START_EVENT:
+ ev = new Start_log_event(buf, old_format);
+ break;
+ case STOP_EVENT:
+ ev = new Stop_log_event(buf, old_format);
+ break;
+ case INTVAR_EVENT:
+ ev = new Intvar_log_event(buf, old_format);
+ break;
default:
break;
}
- return NULL; // default value
+ if (!ev) return 0;
+ if (!ev->is_valid())
+ {
+ *error= "Found invalid event in binary log";
+ delete ev;
+ return 0;
+ }
+ ev->cached_event_len = event_len;
+ return ev;
}
+#ifdef MYSQL_CLIENT
void Log_event::print_header(FILE* file)
{
+ char llbuff[22];
fputc('#', file);
print_timestamp(file);
- fprintf(file, " server id %d ", server_id);
+ fprintf(file, " server id %d log_pos %s ", server_id,
+ llstr(log_pos,llbuff));
}
void Log_event::print_timestamp(FILE* file, time_t* ts)
@@ -321,6 +663,7 @@ void Stop_log_event::print(FILE* file, bool short_form, char* last_db)
void Rotate_log_event::print(FILE* file, bool short_form, char* last_db)
{
+ char buf[22];
if (short_form)
return;
@@ -329,64 +672,55 @@ void Rotate_log_event::print(FILE* file, bool short_form, char* last_db)
if (new_log_ident)
my_fwrite(file, (byte*) new_log_ident, (uint)ident_len,
MYF(MY_NABP | MY_WME));
- fprintf(file, "\n");
+ fprintf(file, "pos=%s\n", llstr(pos, buf));
fflush(file);
}
-Rotate_log_event::Rotate_log_event(IO_CACHE* file, time_t when_arg,
- uint32 server_id):
- Log_event(when_arg, 0, 0, server_id),new_log_ident(NULL),alloced(0)
-{
- char *tmp_ident;
- char buf[4];
-
- if (my_b_read(file, (byte*) buf, sizeof(buf)))
- return;
- ulong event_len;
- event_len = uint4korr(buf);
- if (event_len < ROTATE_EVENT_OVERHEAD)
- return;
-
- ident_len = (uchar)(event_len - ROTATE_EVENT_OVERHEAD);
- if (!(tmp_ident = (char*) my_malloc((uint)ident_len, MYF(MY_WME))))
- return;
- if (my_b_read( file, (byte*) tmp_ident, (uint) ident_len))
- {
- my_free((gptr) tmp_ident, MYF(0));
- return;
- }
-
- new_log_ident = tmp_ident;
- alloced = 1;
-}
+#endif /* #ifdef MYSQL_CLIENT */
-Start_log_event::Start_log_event(const char* buf) :Log_event(buf)
+Start_log_event::Start_log_event(const char* buf,
+ bool old_format) :Log_event(buf, old_format)
{
- buf += EVENT_LEN_OFFSET + 4; // skip even length
- binlog_version = uint2korr(buf);
- memcpy(server_version, buf + 2, sizeof(server_version));
- created = uint4korr(buf + 2 + sizeof(server_version));
+ buf += (old_format) ? OLD_HEADER_LEN : LOG_EVENT_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);
}
int Start_log_event::write_data(IO_CACHE* file)
{
- char buff[sizeof(server_version)+2+4];
- int2store(buff,binlog_version);
- memcpy(buff+2,server_version,sizeof(server_version));
- int4store(buff+2+sizeof(server_version),created);
- return (my_b_write(file, (byte*) buff, sizeof(buff)) ? -1 : 0);
+ char buff[START_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);
}
-Rotate_log_event::Rotate_log_event(const char* buf, int event_len):
- Log_event(buf),new_log_ident(NULL),alloced(0)
+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)
{
// the caller will ensure that event_len is what we have at
// EVENT_LEN_OFFSET
- if(event_len < ROTATE_EVENT_OVERHEAD)
+ int header_size = (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
+ uint ident_offset;
+ if(event_len < header_size)
return;
-
- ident_len = (uchar)(event_len - ROTATE_EVENT_OVERHEAD);
- if (!(new_log_ident = (char*) my_memdup((byte*) buf + LOG_EVENT_HEADER_LEN,
+ buf += header_size;
+ if (old_format)
+ {
+ ident_len = (uchar)(event_len - OLD_HEADER_LEN);
+ pos = 4;
+ ident_offset = 0;
+ }
+ else
+ {
+ ident_len = (uchar)(event_len - ROTATE_EVENT_OVERHEAD);
+ pos = uint8korr(buf + R_POS_OFFSET);
+ ident_offset = ROTATE_HEADER_LEN;
+ }
+ if (!(new_log_ident = (char*) my_memdup((byte*) buf + ident_offset,
(uint) ident_len, MYF(MY_WME))))
return;
@@ -395,68 +729,66 @@ Rotate_log_event::Rotate_log_event(const char* buf, int event_len):
int Rotate_log_event::write_data(IO_CACHE* file)
{
- return my_b_write(file, (byte*) new_log_ident, (uint) ident_len) ? -1 :0;
+ char buf[ROTATE_HEADER_LEN];
+ int8store(buf, pos + R_POS_OFFSET);
+ return my_b_safe_write(file, (byte*)buf, ROTATE_HEADER_LEN) ||
+ my_b_safe_write(file, (byte*)new_log_ident, (uint) ident_len);
}
-Query_log_event::Query_log_event(IO_CACHE* file, time_t when_arg,
- uint32 server_id):
- Log_event(when_arg,0,0,server_id),data_buf(0),query(NULL),db(NULL)
-{
- char buf[QUERY_HEADER_LEN + 4];
- ulong data_len;
- if (my_b_read(file, (byte*) buf, sizeof(buf)))
- return; // query == NULL will tell the
- // caller there was a problem
- data_len = uint4korr(buf);
- if (data_len < QUERY_EVENT_OVERHEAD)
- return; // tear-drop attack protection :)
-
- data_len -= QUERY_EVENT_OVERHEAD;
- exec_time = uint4korr(buf + 8);
- db_len = (uint)buf[12];
- error_code = uint2korr(buf + 13);
-
- /* Allocate one byte extra for end \0 */
- if (!(data_buf = (char*) my_malloc(data_len+1, MYF(MY_WME))))
- return;
- if (my_b_read( file, (byte*) data_buf, data_len))
+#ifndef MYSQL_CLIENT
+Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
+ bool using_trans):
+ Log_event(thd_arg), data_buf(0), query(query_arg), db(thd_arg->db),
+ q_len(thd_arg->query_length),
+ error_code(thd_arg->killed ? ER_SERVER_SHUTDOWN: thd_arg->net.last_errno),
+ thread_id(thd_arg->thread_id),
+ cache_stmt(using_trans &&
+ (thd_arg->options & (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN)))
{
- my_free((gptr) data_buf, MYF(0));
- data_buf = 0;
- return;
+ time_t end_time;
+ time(&end_time);
+ exec_time = (ulong) (end_time - thd->start_time);
+ db_len = (db) ? (uint32) strlen(db) : 0;
}
+#endif
- thread_id = uint4korr(buf + 4);
- db = data_buf;
- query=data_buf + db_len + 1;
- q_len = data_len - 1 - db_len;
- *((char*) query + q_len) = 0; // Safety
-}
-
-Query_log_event::Query_log_event(const char* buf, int event_len):
- Log_event(buf),data_buf(0), query(NULL), db(NULL)
+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)
{
- if ((uint)event_len < QUERY_EVENT_OVERHEAD)
- return;
ulong data_len;
- buf += EVENT_LEN_OFFSET;
- data_len = event_len - QUERY_EVENT_OVERHEAD;
+ 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;
+ }
- exec_time = uint4korr(buf + 8);
- error_code = uint2korr(buf + 13);
+ exec_time = uint4korr(buf + Q_EXEC_TIME_OFFSET);
+ error_code = uint2korr(buf + Q_ERR_CODE_OFFSET);
if (!(data_buf = (char*) my_malloc(data_len + 1, MYF(MY_WME))))
return;
- memcpy(data_buf, buf + QUERY_HEADER_LEN + 4, data_len);
- thread_id = uint4korr(buf + 4);
+ memcpy(data_buf, buf + Q_DATA_OFFSET, data_len);
+ thread_id = uint4korr(buf + Q_THREAD_ID_OFFSET);
db = data_buf;
- db_len = (uint)buf[12];
+ 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;
}
+#ifdef MYSQL_CLIENT
+
void Query_log_event::print(FILE* file, bool short_form, char* last_db)
{
char buff[40],*end; // Enough for SET TIMESTAMP
@@ -485,52 +817,50 @@ void Query_log_event::print(FILE* file, bool short_form, char* last_db)
fprintf(file, ";\n");
}
+#endif
+
int Query_log_event::write_data(IO_CACHE* file)
{
if (!query) return -1;
char buf[QUERY_HEADER_LEN];
- char* pos = buf;
- int4store(pos, thread_id);
- pos += 4;
- int4store(pos, exec_time);
- pos += 4;
- *pos++ = (char)db_len;
- int2store(pos, error_code);
- pos += 2;
-
- return (my_b_write(file, (byte*) buf, (uint)(pos - buf)) ||
- my_b_write(file, (db) ? (byte*) db : (byte*)"", db_len + 1) ||
- my_b_write(file, (byte*) query, q_len)) ? -1 : 0;
+ int4store(buf + Q_THREAD_ID_OFFSET, thread_id);
+ int4store(buf + Q_EXEC_TIME_OFFSET, exec_time);
+ 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;
}
-Intvar_log_event:: Intvar_log_event(IO_CACHE* file, time_t when_arg,
- uint32 server_id)
- :Log_event(when_arg,0,0,server_id), type(INVALID_INT_EVENT)
+Intvar_log_event::Intvar_log_event(const char* buf, bool old_format):
+ Log_event(buf, old_format)
{
- char buf[9+4];
- if (!my_b_read(file, (byte*) buf, sizeof(buf)))
- {
- type = buf[4];
- val = uint8korr(buf+1+4);
- }
+ buf += (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
+ type = buf[I_TYPE_OFFSET];
+ val = uint8korr(buf+I_VAL_OFFSET);
}
-Intvar_log_event::Intvar_log_event(const char* buf):Log_event(buf)
+const char* Intvar_log_event::get_var_type_name()
{
- buf += LOG_EVENT_HEADER_LEN;
- type = buf[0];
- val = uint8korr(buf+1);
+ switch(type)
+ {
+ case LAST_INSERT_ID_EVENT: return "LAST_INSERT_ID";
+ case INSERT_ID_EVENT: return "INSERT_ID";
+ default: /* impossible */ return "UNKNOWN";
+ }
}
int Intvar_log_event::write_data(IO_CACHE* file)
{
char buf[9];
- buf[0] = type;
- int8store(buf + 1, val);
- return my_b_write(file, (byte*) buf, sizeof(buf));
+ buf[I_TYPE_OFFSET] = type;
+ int8store(buf + I_VAL_OFFSET, val);
+ return my_b_safe_write(file, (byte*) buf, sizeof(buf));
}
+#ifdef MYSQL_CLIENT
void Intvar_log_event::print(FILE* file, bool short_form, char* last_db)
{
char llbuff[22];
@@ -554,100 +884,255 @@ void Intvar_log_event::print(FILE* file, bool short_form, char* last_db)
fflush(file);
}
+#endif
-int Load_log_event::write_data(IO_CACHE* file)
+int Load_log_event::write_data_header(IO_CACHE* file)
{
char buf[LOAD_HEADER_LEN];
- int4store(buf, thread_id);
- int4store(buf + 4, exec_time);
- int4store(buf + 8, skip_lines);
- buf[12] = (char)table_name_len;
- buf[13] = (char)db_len;
- int4store(buf + 14, num_fields);
-
- if(my_b_write(file, (byte*)buf, sizeof(buf)) ||
- my_b_write(file, (byte*)&sql_ex, sizeof(sql_ex)))
- return 1;
+ int4store(buf + L_THREAD_ID_OFFSET, thread_id);
+ int4store(buf + L_EXEC_TIME_OFFSET, exec_time);
+ int4store(buf + L_SKIP_LINES_OFFSET, skip_lines);
+ 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);
+}
+int Load_log_event::write_data_body(IO_CACHE* file)
+{
+ if (sql_ex.write_data(file)) return 1;
if (num_fields && fields && field_lens)
{
- if(my_b_write(file, (byte*)field_lens, num_fields) ||
- my_b_write(file, (byte*)fields, field_block_len))
+ if (my_b_safe_write(file, (byte*)field_lens, num_fields) ||
+ my_b_safe_write(file, (byte*)fields, field_block_len))
return 1;
}
- if(my_b_write(file, (byte*)table_name, table_name_len + 1) ||
- my_b_write(file, (byte*)db, db_len + 1) ||
- my_b_write(file, (byte*)fname, fname_len))
+ return (my_b_safe_write(file, (byte*)table_name, table_name_len + 1) ||
+ my_b_safe_write(file, (byte*)db, db_len + 1) ||
+ my_b_safe_write(file, (byte*)fname, fname_len));
+}
+
+
+static bool write_str(IO_CACHE *file, char *str, byte length)
+{
+ return (my_b_safe_write(file, &length, 1) ||
+ my_b_safe_write(file, (byte*) str, (int) length));
+}
+
+int 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) ||
+ my_b_safe_write(file,(byte*) &opt_flags,1));
+ }
+ else
+ {
+ old_sql_ex old_ex;
+ old_ex.field_term= *field_term;
+ old_ex.enclosed= *enclosed;
+ old_ex.line_term= *line_term;
+ old_ex.line_start= *line_start;
+ 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));
+ }
+}
+
+static inline int read_str(char * &buf, char *buf_end, char * &str,
+ uint8 &len)
+{
+ if (buf + (uint) (uchar) *buf >= buf_end)
return 1;
+ len = (uint8) *buf;
+ str= buf+1;
+ buf+= (uint) len+1;
return 0;
}
-Load_log_event::Load_log_event(IO_CACHE* file, time_t when, uint32 server_id):
- Log_event(when,0,0,server_id),data_buf(0),num_fields(0),
- fields(0),field_lens(0),field_block_len(0),
- table_name(0),db(0),fname(0)
+char* sql_ex_info::init(char* buf,char* buf_end,bool use_new_format)
{
- char buf[LOAD_HEADER_LEN + 4];
- ulong data_len;
- if (my_b_read(file, (byte*)buf, sizeof(buf)) ||
- my_b_read(file, (byte*)&sql_ex, sizeof(sql_ex)))
- return;
-
- data_len = uint4korr(buf) - LOAD_EVENT_OVERHEAD;
- if (!(data_buf = (char*)my_malloc(data_len + 1, MYF(MY_WME))))
- return;
- if (my_b_read(file, (byte*)data_buf, data_len))
- return;
- copy_log_event(buf,data_len);
+ cached_new_format = use_new_format;
+ if (use_new_format)
+ {
+ empty_flags=0;
+ /* the code below assumes that buf will not disappear from
+ under our feet during the lifetime of the event. This assumption
+ holds true in the slave thread if the log is in new format, but is not
+ 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))
+ return 0;
+ opt_flags = *buf++;
+ }
+ else
+ {
+ field_term_len= enclosed_len= line_term_len= line_start_len= escaped_len=1;
+ field_term = buf++;
+ enclosed= buf++;
+ line_term= buf++;
+ line_start= buf++;
+ escaped= buf++;
+ opt_flags = *buf++;
+ empty_flags=*buf++;
+ if (empty_flags & FIELD_TERM_EMPTY)
+ field_term_len=0;
+ if (empty_flags & ENCLOSED_EMPTY)
+ enclosed_len=0;
+ if (empty_flags & LINE_TERM_EMPTY)
+ line_term_len=0;
+ if (empty_flags & LINE_START_EMPTY)
+ line_start_len=0;
+ if (empty_flags & ESCAPED_EMPTY)
+ escaped_len=0;
+ }
+ return buf;
}
-Load_log_event::Load_log_event(const char* buf, int event_len):
- Log_event(buf),data_buf(0),num_fields(0),fields(0),
+
+#ifndef MYSQL_CLIENT
+Load_log_event::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):
+ Log_event(thd),thread_id(thd->thread_id),
+ num_fields(0),fields(0),field_lens(0),field_block_len(0),
+ table_name(table_name_arg),
+ db(db_arg),
+ fname(ex->file_name)
+ {
+ time_t end_time;
+ time(&end_time);
+ exec_time = (ulong) (end_time - thd->start_time);
+ db_len = (db) ? (uint32) strlen(db) : 0;
+ table_name_len = (table_name) ? (uint32) strlen(table_name) : 0;
+ fname_len = (fname) ? (uint) strlen(fname) : 0;
+ sql_ex.field_term = (char*) ex->field_term->ptr();
+ sql_ex.field_term_len = (uint8) ex->field_term->length();
+ sql_ex.enclosed = (char*) ex->enclosed->ptr();
+ sql_ex.enclosed_len = (uint8) ex->enclosed->length();
+ sql_ex.line_term = (char*) ex->line_term->ptr();
+ sql_ex.line_term_len = (uint8) ex->line_term->length();
+ sql_ex.line_start = (char*) ex->line_start->ptr();
+ sql_ex.line_start_len = (uint8) ex->line_start->length();
+ sql_ex.escaped = (char*) ex->escaped->ptr();
+ sql_ex.escaped_len = (uint8) ex->escaped->length();
+ sql_ex.opt_flags = 0;
+ sql_ex.cached_new_format = -1;
+
+ if(ex->dumpfile)
+ sql_ex.opt_flags |= DUMPFILE_FLAG;
+ if(ex->opt_enclosed)
+ sql_ex.opt_flags |= OPT_ENCLOSED_FLAG;
+
+ sql_ex.empty_flags = 0;
+
+ switch(handle_dup)
+ {
+ case DUP_IGNORE: sql_ex.opt_flags |= IGNORE_FLAG; break;
+ case DUP_REPLACE: sql_ex.opt_flags |= REPLACE_FLAG; break;
+ case DUP_ERROR: break;
+ }
+
+
+ if(!ex->field_term->length())
+ sql_ex.empty_flags |= FIELD_TERM_EMPTY;
+ if(!ex->enclosed->length())
+ sql_ex.empty_flags |= ENCLOSED_EMPTY;
+ if(!ex->line_term->length())
+ sql_ex.empty_flags |= LINE_TERM_EMPTY;
+ if(!ex->line_start->length())
+ sql_ex.empty_flags |= LINE_START_EMPTY;
+ if(!ex->escaped->length())
+ sql_ex.empty_flags |= ESCAPED_EMPTY;
+
+ skip_lines = ex->skip_lines;
+
+ List_iterator<Item> li(fields_arg);
+ field_lens_buf.length(0);
+ fields_buf.length(0);
+ Item* item;
+ while((item = li++))
+ {
+ num_fields++;
+ uchar len = (uchar) strlen(item->name);
+ field_block_len += len + 1;
+ fields_buf.append(item->name, len + 1);
+ field_lens_buf.append((char*)&len, 1);
+ }
+
+ field_lens = (const uchar*)field_lens_buf.ptr();
+ fields = fields_buf.ptr();
+ }
+
+#endif
+
+// the caller must do buf[event_len] = 0 before he starts using the
+// 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),
table_name(0),db(0),fname(0)
{
- ulong data_len;
-
- if((uint)event_len < (LOAD_EVENT_OVERHEAD + LOG_EVENT_HEADER_LEN))
+ if (!event_len) // derived class, will call copy_log_event() itself
return;
- buf += EVENT_LEN_OFFSET;
- memcpy(&sql_ex, buf + LOAD_HEADER_LEN + 4, sizeof(sql_ex));
- data_len = event_len;
-
- if(!(data_buf = (char*)my_malloc(data_len + 1, MYF(MY_WME))))
- return;
- memcpy(data_buf, buf + 22 + sizeof(sql_ex), data_len);
- copy_log_event(buf, data_len);
+ copy_log_event(buf, event_len, old_format);
}
-void Load_log_event::copy_log_event(const char *buf, ulong data_len)
+int Load_log_event::copy_log_event(const char *buf, ulong event_len,
+ bool old_format)
{
- thread_id = uint4korr(buf+4);
- exec_time = uint4korr(buf+8);
- skip_lines = uint4korr(buf + 12);
- table_name_len = (uint)buf[16];
- db_len = (uint)buf[17];
- num_fields = uint4korr(buf + 18);
+ uint data_len;
+ char* buf_end = (char*)buf + event_len;
+ const char* data_head = buf + ((old_format) ?
+ OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN);
+ 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);
+ table_name_len = (uint)data_head[L_TBL_LEN_OFFSET];
+ 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 + OLD_HEADER_LEN : get_data_body_offset();
+
+ if ((int) event_len < body_offset)
+ 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)))
+ return 1;
+
+ data_len = event_len - body_offset;
if (num_fields > data_len) // simple sanity check against corruption
- return;
-
- field_lens = (uchar*) data_buf;
+ return 1;
uint i;
for (i = 0; i < num_fields; i++)
{
field_block_len += (uint)field_lens[i] + 1;
}
fields = (char*)field_lens + num_fields;
-
- *((char*)data_buf+data_len) = 0;
table_name = fields + field_block_len;
db = table_name + table_name_len + 1;
fname = db + db_len + 1;
- fname_len = data_len - 2 - db_len - table_name_len - num_fields -
- field_block_len;
+ fname_len = strlen(fname);
+ // null termination is accomplished by the caller doing buf[event_len]=0
+ return 0;
}
+#ifdef MYSQL_CLIENT
void Load_log_event::print(FILE* file, bool short_form, char* last_db)
{
@@ -669,7 +1154,7 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db)
if(db && db[0] && !same_db)
fprintf(file, "use %s;\n", db);
- fprintf(file, "LOAD DATA INFILE '%s' ", fname);
+ fprintf(file, "LOAD DATA INFILE '%-*s' ", fname_len, fname);
if(sql_ex.opt_flags && REPLACE_FLAG )
fprintf(file," REPLACE ");
@@ -677,36 +1162,36 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db)
fprintf(file," IGNORE ");
fprintf(file, "INTO TABLE %s ", table_name);
- if(!(sql_ex.empty_flags & FIELD_TERM_EMPTY))
+ if(sql_ex.field_term)
{
fprintf(file, " FIELDS TERMINATED BY ");
- pretty_print_char(file, sql_ex.field_term);
+ pretty_print_str(file, sql_ex.field_term, sql_ex.field_term_len);
}
- if(!(sql_ex.empty_flags & ENCLOSED_EMPTY))
+ if(sql_ex.enclosed)
{
if(sql_ex.opt_flags && OPT_ENCLOSED_FLAG )
fprintf(file," OPTIONALLY ");
fprintf(file, " ENCLOSED BY ");
- pretty_print_char(file, sql_ex.enclosed);
+ pretty_print_str(file, sql_ex.enclosed, sql_ex.enclosed_len);
}
- if(!(sql_ex.empty_flags & ESCAPED_EMPTY))
+ if (sql_ex.escaped)
{
fprintf(file, " ESCAPED BY ");
- pretty_print_char(file, sql_ex.escaped);
+ pretty_print_str(file, sql_ex.escaped, sql_ex.escaped_len);
}
- if(!(sql_ex.empty_flags & LINE_TERM_EMPTY))
+ if (sql_ex.line_term)
{
fprintf(file," LINES TERMINATED BY ");
- pretty_print_char(file, sql_ex.line_term);
+ pretty_print_str(file, sql_ex.line_term, sql_ex.line_term_len);
}
- if(!(sql_ex.empty_flags & LINE_START_EMPTY))
+ if (sql_ex.line_start)
{
fprintf(file," LINES STARTING BY ");
- pretty_print_char(file, sql_ex.line_start);
+ pretty_print_str(file, sql_ex.line_start, sql_ex.line_start_len);
}
if((int)skip_lines > 0)
@@ -731,18 +1216,794 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db)
fprintf(file, ";\n");
}
+#endif /* #ifdef MYSQL_CLIENT */
+
#ifndef MYSQL_CLIENT
+void Log_event::set_log_pos(MYSQL_LOG* log)
+ {
+ if (!log_pos)
+ log_pos = my_b_tell(&log->log_file);
+ }
+
void Load_log_event::set_fields(List<Item> &fields)
{
uint i;
const char* field = this->fields;
- for(i = 0; i < num_fields; i++)
+ for (i = 0; i < num_fields; i++)
+ {
+ fields.push_back(new Item_field(db, table_name, field));
+ field += field_lens[i] + 1;
+ }
+}
+
+
+Slave_log_event::Slave_log_event(THD* thd_arg,
+ struct st_relay_log_info* rli):
+ Log_event(thd_arg),mem_pool(0),master_host(0)
+{
+ if (!rli->inited)
+ 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);
+ pthread_mutex_lock(&rli->data_lock);
+ master_host_len = strlen(mi->host);
+ master_log_len = strlen(rli->master_log_name);
+ // on OOM, just do not initialize the structure and print the error
+ if ((mem_pool = (char*)my_malloc(get_data_size() + 1,
+ MYF(MY_WME))))
+ {
+ master_host = mem_pool + SL_MASTER_HOST_OFFSET ;
+ memcpy(master_host, mi->host, master_host_len + 1);
+ master_log = master_host + master_host_len + 1;
+ memcpy(master_log, rli->master_log_name, master_log_len + 1);
+ master_port = mi->port;
+ master_pos = rli->master_log_pos;
+ }
+ else
+ sql_print_error("Out of memory while recording slave event");
+ pthread_mutex_unlock(&rli->data_lock);
+ pthread_mutex_unlock(&mi->data_lock);
+}
+
+
+#endif
+
+
+Slave_log_event::~Slave_log_event()
+{
+ my_free(mem_pool, MYF(MY_ALLOW_ZERO_PTR));
+}
+
+#ifdef MYSQL_CLIENT
+
+void Slave_log_event::print(FILE* file, bool short_form, char* last_db)
+{
+ char llbuff[22];
+ if(short_form)
+ return;
+ print_header(file);
+ fputc('\n', file);
+ fprintf(file, "Slave: master_host='%s' master_port=%d \
+ master_log=%s master_pos=%s\n",
+ master_host, master_port, master_log, llstr(master_pos, llbuff));
+}
+
+#endif
+
+int Slave_log_event::get_data_size()
+{
+ return master_host_len + master_log_len + 1 + SL_MASTER_HOST_OFFSET;
+}
+
+int Slave_log_event::write_data(IO_CACHE* file)
+{
+ 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());
+}
+
+void Slave_log_event::init_from_mem_pool(int data_size)
+{
+ master_pos = uint8korr(mem_pool + SL_MASTER_POS_OFFSET);
+ master_port = uint2korr(mem_pool + SL_MASTER_PORT_OFFSET);
+ master_host = mem_pool + SL_MASTER_HOST_OFFSET;
+ master_host_len = strlen(master_host);
+ // safety
+ master_log = master_host + master_host_len + 1;
+ if(master_log > mem_pool + data_size)
+ {
+ master_host = 0;
+ return;
+ }
+ master_log_len = strlen(master_log);
+}
+
+Slave_log_event::Slave_log_event(const char* buf, int event_len):
+ Log_event(buf,0),mem_pool(0),master_host(0)
+{
+ event_len -= LOG_EVENT_HEADER_LEN;
+ if(event_len < 0)
+ return;
+ if(!(mem_pool = (char*)my_malloc(event_len + 1, MYF(MY_WME))))
+ return;
+ memcpy(mem_pool, buf + LOG_EVENT_HEADER_LEN, event_len);
+ mem_pool[event_len] = 0;
+ init_from_mem_pool(event_len);
+}
+
+#ifndef MYSQL_CLIENT
+Create_file_log_event::Create_file_log_event(THD* thd_arg, sql_exchange* ex,
+ const char* db_arg, const char* table_name_arg,
+ List<Item>& fields_arg, enum enum_duplicates handle_dup,
+ char* block_arg, uint block_len_arg):
+ Load_log_event(thd_arg,ex,db_arg,table_name_arg,fields_arg,handle_dup),
+ fake_base(0),block(block_arg),block_len(block_len_arg),
+ file_id(thd_arg->file_id = mysql_bin_log.next_file_id())
+{
+ sql_ex.force_new_format();
+}
+#endif
+
+int Create_file_log_event::write_data_body(IO_CACHE* file)
+{
+ int 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));
+}
+
+int 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;
+ byte buf[CREATE_FILE_HEADER_LEN];
+ int4store(buf + CF_FILE_ID_OFFSET, file_id);
+ return my_b_safe_write(file, buf, CREATE_FILE_HEADER_LEN);
+}
+
+int 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;
+ return res;
+}
+
+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)
+{
+ int block_offset;
+ if (copy_log_event(buf,len,old_format))
+ return;
+ if (!old_format)
+ {
+ file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN +
+ + LOAD_HEADER_LEN + CF_FILE_ID_OFFSET);
+ block_offset = LOG_EVENT_HEADER_LEN + Load_log_event::get_data_size() +
+ CREATE_FILE_HEADER_LEN + 1; // 1 for \0 terminating fname
+ if (len < block_offset)
+ return;
+ block = (char*)buf + block_offset;
+ block_len = len - block_offset;
+ }
+ else
+ {
+ sql_ex.force_new_format();
+ inited_from_old = 1;
+ }
+}
+
+
+#ifdef MYSQL_CLIENT
+void Create_file_log_event::print(FILE* file, bool short_form,
+ char* last_db)
+{
+ if (short_form)
+ return;
+ Load_log_event::print(file, 1, last_db);
+ fprintf(file, " file_id=%d, block_len=%d\n", file_id, block_len);
+}
+#endif
+
+#ifndef MYSQL_CLIENT
+void Create_file_log_event::pack_info(String* packet)
+{
+ char buf1[256];
+ String tmp(buf1, sizeof(buf1));
+ tmp.length(0);
+ char buf[22];
+ tmp.append("db=");
+ tmp.append(db, db_len);
+ tmp.append(";table=");
+ tmp.append(table_name, table_name_len);
+ tmp.append(";file_id=");
+ tmp.append(llstr(file_id,buf));
+ tmp.append(";block_len=");
+ tmp.append(llstr(block_len,buf));
+ net_store_data(packet, (char*)tmp.ptr(), tmp.length());
+}
+#endif
+
+#ifndef MYSQL_CLIENT
+Append_block_log_event::Append_block_log_event(THD* thd_arg, char* block_arg,
+ uint block_len_arg):
+ Log_event(thd_arg), block(block_arg),block_len(block_len_arg),
+ file_id(thd_arg->file_id)
+{
+}
+#endif
+
+Append_block_log_event::Append_block_log_event(const char* buf, int len):
+ Log_event(buf, 0),block(0)
+{
+ if((uint)len < APPEND_BLOCK_EVENT_OVERHEAD)
+ 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;
+}
+
+int Append_block_log_event::write_data(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) ||
+ my_b_safe_write(file, (byte*) block, block_len));
+}
+
+#ifdef MYSQL_CLIENT
+void Append_block_log_event::print(FILE* file, bool short_form,
+ char* last_db)
+{
+ 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);
+}
+#endif
+#ifndef MYSQL_CLIENT
+void Append_block_log_event::pack_info(String* packet)
+{
+ char buf1[256];
+ String tmp(buf1, sizeof(buf1));
+ tmp.length(0);
+ char buf[22];
+ tmp.append(";file_id=");
+ tmp.append(llstr(file_id,buf));
+ tmp.append(";block_len=");
+ tmp.append(llstr(block_len,buf));
+ net_store_data(packet, (char*)tmp.ptr(), tmp.length());
+}
+#endif
+
+#ifndef MYSQL_CLIENT
+Delete_file_log_event::Delete_file_log_event(THD* thd_arg):
+ Log_event(thd_arg),file_id(thd_arg->file_id)
+{
+}
+#endif
+
+Delete_file_log_event::Delete_file_log_event(const char* buf, int len):
+ Log_event(buf, 0),file_id(0)
+{
+ if((uint)len < DELETE_FILE_EVENT_OVERHEAD)
+ return;
+ file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + AB_FILE_ID_OFFSET);
+}
+
+int Delete_file_log_event::write_data(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);
+}
+
+#ifdef MYSQL_CLIENT
+void Delete_file_log_event::print(FILE* file, bool short_form,
+ char* last_db)
+{
+ if (short_form)
+ return;
+ print_header(file);
+ fputc('\n', file);
+ fprintf(file, "#Delete_file: file_id=%d\n",
+ file_id);
+}
+#endif
+#ifndef MYSQL_CLIENT
+void Delete_file_log_event::pack_info(String* packet)
+{
+ char buf1[256];
+ String tmp(buf1, sizeof(buf1));
+ tmp.length(0);
+ char buf[22];
+ tmp.append(";file_id=");
+ tmp.append(llstr(file_id,buf));
+ net_store_data(packet, (char*)tmp.ptr(), tmp.length());
+}
+#endif
+
+#ifndef MYSQL_CLIENT
+Execute_load_log_event::Execute_load_log_event(THD* thd_arg):
+ Log_event(thd_arg),file_id(thd_arg->file_id)
+{
+}
+#endif
+
+Execute_load_log_event::Execute_load_log_event(const char* buf,int len):
+ Log_event(buf, 0),file_id(0)
+{
+ if((uint)len < EXEC_LOAD_EVENT_OVERHEAD)
+ return;
+ file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + EL_FILE_ID_OFFSET);
+}
+
+int Execute_load_log_event::write_data(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);
+}
+
+#ifdef MYSQL_CLIENT
+void Execute_load_log_event::print(FILE* file, bool short_form,
+ char* last_db)
+{
+ if (short_form)
+ return;
+ print_header(file);
+ fputc('\n', file);
+ fprintf(file, "#Exec_load: file_id=%d\n",
+ file_id);
+}
+#endif
+#ifndef MYSQL_CLIENT
+void Execute_load_log_event::pack_info(String* packet)
+{
+ char buf1[256];
+ String tmp(buf1, sizeof(buf1));
+ tmp.length(0);
+ char buf[22];
+ tmp.append(";file_id=");
+ tmp.append(llstr(file_id,buf));
+ net_store_data(packet, (char*)tmp.ptr(), tmp.length());
+}
+#endif
+
+#ifndef MYSQL_CLIENT
+int Query_log_event::exec_event(struct st_relay_log_info* rli)
+{
+ int expected_error,actual_error = 0;
+ init_sql_alloc(&thd->mem_root, 8192,0);
+ thd->db = rewrite_db((char*)db);
+ DBUG_ASSERT(q_len == strlen(query));
+ if (db_ok(thd->db, replicate_do_db, replicate_ignore_db))
+ {
+ thd->query = (char*)query;
+ thd->set_time((time_t)when);
+ thd->current_tablenr = 0;
+ VOID(pthread_mutex_lock(&LOCK_thread_count));
+ thd->query_id = query_id++;
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ thd->query_error = 0; // clear error
+ thd->net.last_errno = 0;
+ thd->net.last_error[0] = 0;
+ thd->slave_proxy_id = thread_id; // for temp tables
+
+ // sanity check to make sure the master did not get a really bad
+ // error on the query
+ if (ignored_error_code((expected_error = error_code)) ||
+ !check_expected_error(thd,rli,expected_error))
{
- fields.push_back(new Item_field(db, table_name, field));
- field += field_lens[i] + 1;
+ mysql_parse(thd, thd->query, q_len);
+ if (expected_error !=
+ (actual_error = thd->net.last_errno) && expected_error)
+ {
+ const char* errmsg = "Slave: did not get the expected error\
+ running query from master - expected: '%s' (%d), got '%s' (%d)";
+ sql_print_error(errmsg, ER_SAFE(expected_error),
+ expected_error,
+ actual_error ? thd->net.last_error: "no error",
+ actual_error);
+ thd->query_error = 1;
+ }
+ else if (expected_error == actual_error
+ || ignored_error_code(actual_error))
+ {
+ thd->query_error = 0;
+ *rli->last_slave_error = 0;
+ rli->last_slave_errno = 0;
+ }
}
+ else
+ {
+ // master could be inconsistent, abort and tell DBA to check/fix it
+ thd->db = thd->query = 0;
+ thd->convert_set = 0;
+ close_thread_tables(thd);
+ free_root(&thd->mem_root,0);
+ return 1;
+ }
+ }
+ thd->db = 0; // prevent db from being freed
+ thd->query = 0; // just to be sure
+ // assume no convert for next query unless set explictly
+ thd->convert_set = 0;
+ close_thread_tables(thd);
+
+ if (thd->query_error || thd->fatal_error)
+ {
+ slave_print_error(rli,actual_error, "error '%s' on query '%s'",
+ actual_error ? thd->net.last_error :
+ "unexpected success or fatal error", query);
+ free_root(&thd->mem_root,0);
+ return 1;
+ }
+ free_root(&thd->mem_root,0);
+ return Log_event::exec_event(rli);
+}
+
+int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli)
+{
+ init_sql_alloc(&thd->mem_root, 8192,0);
+ thd->db = rewrite_db((char*)db);
+ thd->query = 0;
+ thd->query_error = 0;
+
+ if(db_ok(thd->db, replicate_do_db, replicate_ignore_db))
+ {
+ thd->set_time((time_t)when);
+ thd->current_tablenr = 0;
+ VOID(pthread_mutex_lock(&LOCK_thread_count));
+ thd->query_id = query_id++;
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+
+ TABLE_LIST tables;
+ bzero((char*) &tables,sizeof(tables));
+ tables.db = thd->db;
+ tables.name = tables.real_name = (char*)table_name;
+ tables.lock_type = TL_WRITE;
+ // the table will be opened in mysql_load
+ if(table_rules_on && !tables_ok(thd, &tables))
+ {
+ // TODO: this is a bug - this needs to be moved to the I/O thread
+ if (net)
+ skip_load_data_infile(net);
+ }
+ else
+ {
+ char llbuff[22];
+ enum enum_duplicates handle_dup = DUP_IGNORE;
+ if (sql_ex.opt_flags && REPLACE_FLAG)
+ handle_dup = DUP_REPLACE;
+ sql_exchange ex((char*)fname, sql_ex.opt_flags &&
+ DUMPFILE_FLAG );
+ String field_term(sql_ex.field_term,sql_ex.field_term_len);
+ String enclosed(sql_ex.enclosed,sql_ex.enclosed_len);
+ String line_term(sql_ex.line_term,sql_ex.line_term_len);
+ String line_start(sql_ex.line_start,sql_ex.line_start_len);
+ String escaped(sql_ex.escaped,sql_ex.escaped_len);
+
+ ex.opt_enclosed = (sql_ex.opt_flags & OPT_ENCLOSED_FLAG);
+ if (sql_ex.empty_flags & FIELD_TERM_EMPTY)
+ ex.field_term->length(0);
+
+ ex.skip_lines = skip_lines;
+ List<Item> fields;
+ set_fields(fields);
+ thd->slave_proxy_id = thd->thread_id;
+ if (net)
+ {
+ // mysql_load will use thd->net to read the file
+ thd->net.vio = net->vio;
+ // make sure the client does not get confused
+ // about the packet sequence
+ thd->net.pkt_nr = net->pkt_nr;
+ }
+ if(mysql_load(thd, &ex, &tables, fields, handle_dup, net != 0,
+ TL_WRITE))
+ thd->query_error = 1;
+ if(thd->cuted_fields)
+ sql_print_error("Slave: load data infile at position %s in log \
+'%s' produced %d warning(s)", llstr(rli->master_log_pos,llbuff), RPL_LOG_NAME,
+ thd->cuted_fields );
+ if(net)
+ net->pkt_nr = thd->net.pkt_nr;
+ }
+ }
+ else
+ {
+ // we will just ask the master to send us /dev/null if we do not
+ // want to load the data
+ // TODO: this a bug - needs to be done in I/O thread
+ if (net)
+ skip_load_data_infile(net);
+ }
+
+ thd->net.vio = 0;
+ thd->db = 0;// prevent db from being freed
+ close_thread_tables(thd);
+ if(thd->query_error)
+ {
+ int sql_error = thd->net.last_errno;
+ if (!sql_error)
+ sql_error = ER_UNKNOWN_ERROR;
+
+ slave_print_error(rli,sql_error,
+ "Slave: Error '%s' running load data infile ",
+ ER_SAFE(sql_error));
+ free_root(&thd->mem_root,0);
+ return 1;
+ }
+ free_root(&thd->mem_root,0);
+
+ if(thd->fatal_error)
+ {
+ sql_print_error("Slave: Fatal error running LOAD DATA INFILE ");
+ return 1;
+ }
+
+ return Log_event::exec_event(rli);
+}
+
+int Start_log_event::exec_event(struct st_relay_log_info* rli)
+{
+ close_temporary_tables(thd);
+ // if we have old format, load_tmpdir is cleaned up by the I/O thread
+ // TODO: cleanup_load_tmpdir() needs to remove only the files associated
+ // with the server id that has just started
+ if (!rli->mi->old_format)
+ cleanup_load_tmpdir();
+ return Log_event::exec_event(rli);
+}
+
+int Stop_log_event::exec_event(struct st_relay_log_info* rli)
+{
+ // do not clean up immediately after rotate event
+ if (rli->master_log_pos > 4)
+ {
+ close_temporary_tables(thd);
+ cleanup_load_tmpdir();
+ }
+ /*
+ We do not want to update master_log pos because we get a rotate event
+ before stop, so by now master_log_name is set to the next log
+ if we updated it, we will have incorrect master coordinates and this
+ could give false triggers in MASTER_POS_WAIT() that we have reached
+ the targed position when in fact we have not
+ */
+ rli->inc_pos(get_event_len(), 0);
+ flush_relay_log_info(rli);
+ return 0;
+}
+
+int Rotate_log_event::exec_event(struct st_relay_log_info* rli)
+{
+ bool rotate_binlog = 0, write_slave_event = 0;
+ char* log_name = rli->master_log_name;
+ pthread_mutex_lock(&rli->data_lock);
+ // TODO: probably needs re-write
+ // rotate local binlog only if the name of remote has changed
+ if (!*log_name || !(log_name[ident_len] == 0 &&
+ !memcmp(log_name, new_log_ident, ident_len)))
+ {
+ write_slave_event = (!(flags & LOG_EVENT_FORCED_ROTATE_F)
+ && mysql_bin_log.is_open());
+ rotate_binlog = (*log_name && write_slave_event);
+ if (ident_len >= sizeof(rli->master_log_name))
+ return 1;
+ memcpy(log_name, new_log_ident,ident_len);
+ log_name[ident_len] = 0;
+ }
+ rli->master_log_pos = pos;
+ rli->relay_log_pos += get_event_len();
+ if (rotate_binlog)
+ {
+ mysql_bin_log.new_file();
+ rli->master_log_pos = 4;
+ }
+ pthread_cond_broadcast(&rli->data_cond);
+ pthread_mutex_unlock(&rli->data_lock);
+ flush_relay_log_info(rli);
+
+ if (write_slave_event)
+ {
+ Slave_log_event s(thd, rli);
+ if (s.master_host)
+ {
+ s.set_log_pos(&mysql_bin_log);
+ s.server_id = ::server_id;
+ mysql_bin_log.write(&s);
+ }
+ }
+ return 0;
+}
+
+int Intvar_log_event::exec_event(struct st_relay_log_info* rli)
+{
+ switch (type)
+ {
+ case LAST_INSERT_ID_EVENT:
+ thd->last_insert_id_used = 1;
+ thd->last_insert_id = val;
+ break;
+ case INSERT_ID_EVENT:
+ thd->next_insert_id = val;
+ break;
+ }
+ rli->inc_pending(get_event_len());
+ return 0;
+}
+
+int Slave_log_event::exec_event(struct st_relay_log_info* rli)
+{
+ if(mysql_bin_log.is_open())
+ mysql_bin_log.write(this);
+ return Log_event::exec_event(rli);
+}
+
+int Create_file_log_event::exec_event(struct st_relay_log_info* rli)
+{
+ char fname_buf[FN_REFLEN+10];
+ char *p;
+ int fd = -1;
+ IO_CACHE file;
+ int error = 1;
+
+ bzero((char*)&file, sizeof(file));
+ p = slave_load_file_stem(fname_buf, file_id, server_id);
+ strmov(p, ".info"); // strmov takes less code than memcpy
+ if ((fd = my_open(fname_buf, O_WRONLY|O_CREAT|O_BINARY|O_TRUNC,
+ MYF(MY_WME))) < 0 ||
+ init_io_cache(&file, fd, IO_SIZE, WRITE_CACHE, (my_off_t)0, 0,
+ MYF(MY_WME|MY_NABP)))
+ {
+ slave_print_error(rli,my_errno, "Could not open file '%s'", fname_buf);
+ goto err;
+ }
+ // a trick to avoid allocating another buffer
+ strmov(p, ".data");
+ fname = fname_buf;
+ fname_len = (uint)(p-fname) + 5;
+ if (write_base(&file))
+ {
+ strmov(p, ".info"); // to have it right in the error message
+ slave_print_error(rli,my_errno, "Could not write to file '%s'", fname_buf);
+ goto err;
+ }
+ end_io_cache(&file);
+ my_close(fd, MYF(0));
+
+ // fname_buf now already has .data, not .info, because we did our trick
+ if ((fd = my_open(fname_buf, O_WRONLY|O_CREAT|O_BINARY|O_TRUNC,
+ MYF(MY_WME))) < 0)
+ {
+ slave_print_error(rli,my_errno, "Could not open file '%s'", fname_buf);
+ goto err;
+ }
+ if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP)))
+ {
+ slave_print_error(rli,my_errno, "Write to '%s' failed", fname_buf);
+ goto err;
+ }
+ if (mysql_bin_log.is_open())
+ mysql_bin_log.write(this);
+ error=0;
+err:
+ if (error)
+ end_io_cache(&file);
+ if (fd >= 0)
+ my_close(fd, MYF(0));
+ return error ? 1 : Log_event::exec_event(rli);
+}
+
+int Delete_file_log_event::exec_event(struct st_relay_log_info* rli)
+{
+ char fname[FN_REFLEN+10];
+ char* p;
+ p = slave_load_file_stem(fname, file_id, server_id);
+ memcpy(p, ".data", 6);
+ (void)my_delete(fname, MYF(MY_WME));
+ memcpy(p, ".info", 6);
+ (void)my_delete(fname, MYF(MY_WME));
+ if (mysql_bin_log.is_open())
+ mysql_bin_log.write(this);
+ return Log_event::exec_event(rli);
}
+int Append_block_log_event::exec_event(struct st_relay_log_info* rli)
+{
+ char fname[FN_REFLEN+10];
+ char* p;
+ int fd = -1;
+ int error = 1;
+ p = slave_load_file_stem(fname, file_id, server_id);
+ memcpy(p, ".data", 6);
+ if ((fd = my_open(fname, O_WRONLY|O_APPEND|O_BINARY, MYF(MY_WME))) < 0)
+ {
+ slave_print_error(rli,my_errno, "Could not open file '%s'", fname);
+ goto err;
+ }
+ if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP)))
+ {
+ slave_print_error(rli,my_errno, "Write to '%s' failed", fname);
+ goto err;
+ }
+ if (mysql_bin_log.is_open())
+ mysql_bin_log.write(this);
+ error=0;
+err:
+ if (fd >= 0)
+ my_close(fd, MYF(0));
+ return error ? error : Log_event::exec_event(rli);
+}
+
+int Execute_load_log_event::exec_event(struct st_relay_log_info* rli)
+{
+ char fname[FN_REFLEN+10];
+ char* p;
+ int fd = -1;
+ int error = 1;
+ ulong save_options;
+ IO_CACHE file;
+ Load_log_event* lev = 0;
+ p = slave_load_file_stem(fname, file_id, server_id);
+ memcpy(p, ".info", 6);
+ bzero((char*)&file, sizeof(file));
+ if ((fd = my_open(fname, O_RDONLY|O_BINARY, MYF(MY_WME))) < 0 ||
+ init_io_cache(&file, fd, IO_SIZE, READ_CACHE, (my_off_t)0, 0,
+ MYF(MY_WME|MY_NABP)))
+ {
+ slave_print_error(rli,my_errno, "Could not open file '%s'", fname);
+ goto err;
+ }
+ if (!(lev = (Load_log_event*)Log_event::read_log_event(&file,
+ (pthread_mutex_t*)0,
+ (bool)0))
+ || lev->get_type_code() != NEW_LOAD_EVENT)
+ {
+ slave_print_error(rli,0, "File '%s' appears corrupted", fname);
+ goto err;
+ }
+ // we want to disable binary logging in slave thread
+ // because we need the file events to appear in the same order
+ // as they do on the master relative to other events, so that we
+ // can preserve ascending order of log sequence numbers - needed
+ // to handle failover
+ save_options = thd->options;
+ thd->options &= ~ (ulong) (OPTION_BIN_LOG);
+ lev->thd = thd;
+ if (lev->exec_event(0,0))
+ {
+ slave_print_error(rli,my_errno, "Failed executing load from '%s'", fname);
+ thd->options = save_options;
+ goto err;
+ }
+ thd->options = save_options;
+ (void)my_delete(fname, MYF(MY_WME));
+ memcpy(p, ".data", 6);
+ (void)my_delete(fname, MYF(MY_WME));
+ if (mysql_bin_log.is_open())
+ mysql_bin_log.write(this);
+ error = 0;
+err:
+ delete lev;
+ end_io_cache(&file);
+ if (fd >= 0)
+ my_close(fd, MYF(0));
+ return error ? error : Log_event::exec_event(rli);
+}
+
+
#endif
diff --git a/sql/log_event.h b/sql/log_event.h
index a31c698fae9..a29c3952d46 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -34,40 +34,195 @@
#define LOG_READ_TOO_LARGE -7
#define LOG_EVENT_OFFSET 4
-#define BINLOG_VERSION 1
+#define BINLOG_VERSION 3
+
+/* we could have used SERVER_VERSION_LENGTH, but this introduces an
+ obscure dependency - if somebody decided to change SERVER_VERSION_LENGTH
+ this would have broke the replication protocol
+*/
+#define ST_SERVER_VER_LEN 50
+
+#define DUMPFILE_FLAG 0x1
+#define OPT_ENCLOSED_FLAG 0x2
+#define REPLACE_FLAG 0x4
+#define IGNORE_FLAG 0x8
+
+#define FIELD_TERM_EMPTY 0x1
+#define ENCLOSED_EMPTY 0x2
+#define LINE_TERM_EMPTY 0x4
+#define LINE_START_EMPTY 0x8
+#define ESCAPED_EMPTY 0x10
+
+struct old_sql_ex
+ {
+ char field_term;
+ char enclosed;
+ char line_term;
+ char line_start;
+ char escaped;
+ char opt_flags;
+ char empty_flags;
+ };
+
+#define NUM_LOAD_DELIM_STRS 5
+
+
+struct sql_ex_info
+ {
+ char* field_term;
+ char* enclosed;
+ char* line_term;
+ char* line_start;
+ char* escaped;
+ uint8 field_term_len,enclosed_len,line_term_len,line_start_len,
+ escaped_len;
+ char opt_flags;
+ char empty_flags;
+ int cached_new_format;
+
+ // store in new format even if old is possible
+ 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);
+ char* init(char* buf,char* buf_end,bool use_new_format);
+ bool new_format()
+ {
+ return (cached_new_format != -1) ? cached_new_format :
+ (cached_new_format=(field_term_len > 1 ||
+ enclosed_len > 1 ||
+ line_term_len > 1 || line_start_len > 1 ||
+ escaped_len > 1));
+ }
+ } ;
+
+/* Binary log consists of events. Each event has a fixed length header,
+ followed by possibly variable ( depending on the type of event) length
+ data body. The data body consists of an optional fixed length segment
+ (post-header), and an optional variable length segment. See #defines and
+ comments below for the format specifics
+*/
+
+
+/* event-specific post-header sizes */
+#define LOG_EVENT_HEADER_LEN 19
+#define OLD_HEADER_LEN 13
+#define QUERY_HEADER_LEN (4 + 4 + 1 + 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 CREATE_FILE_HEADER_LEN 4
+#define APPEND_BLOCK_HEADER_LEN 4
+#define EXEC_LOAD_HEADER_LEN 4
+#define DELETE_FILE_HEADER_LEN 4
+
+/* event header offsets */
-#define LOG_EVENT_HEADER_LEN 13
-#define QUERY_HEADER_LEN (sizeof(uint32) + sizeof(uint32) + \
- sizeof(uchar) + sizeof(uint16))
-#define LOAD_HEADER_LEN (sizeof(uint32) + sizeof(uint32) + \
- + sizeof(uint32) + 2 + sizeof(uint32))
-#define EVENT_LEN_OFFSET 9
#define EVENT_TYPE_OFFSET 4
+#define SERVER_ID_OFFSET 5
+#define EVENT_LEN_OFFSET 9
+#define LOG_POS_OFFSET 13
+#define FLAGS_OFFSET 17
+
+/* start event post-header */
+
+#define ST_BINLOG_VER_OFFSET 0
+#define ST_SERVER_VER_OFFSET 2
+#define ST_CREATED_OFFSET (ST_SERVER_VER_OFFSET + ST_SERVER_VER_LEN)
+
+/* slave event post-header */
+
+#define SL_MASTER_PORT_OFFSET 8
+#define SL_MASTER_POS_OFFSET 0
+#define SL_MASTER_HOST_OFFSET 10
+
+/* query event post-header */
+
+#define Q_THREAD_ID_OFFSET 0
+#define Q_EXEC_TIME_OFFSET 4
+#define Q_DB_LEN_OFFSET 8
+#define Q_ERR_CODE_OFFSET 9
+#define Q_DATA_OFFSET QUERY_HEADER_LEN
+
+/* Intvar event post-header */
+
+#define I_TYPE_OFFSET 0
+#define I_VAL_OFFSET 1
+
+/* Load event post-header */
+
+#define L_THREAD_ID_OFFSET 0
+#define L_EXEC_TIME_OFFSET 4
+#define L_SKIP_LINES_OFFSET 8
+#define L_TBL_LEN_OFFSET 12
+#define L_DB_LEN_OFFSET 13
+#define L_NUM_FIELDS_OFFSET 14
+#define L_SQL_EX_OFFSET 18
+#define L_DATA_OFFSET LOAD_HEADER_LEN
+
+/* Rotate event post-header */
+
+#define R_POS_OFFSET 0
+#define R_IDENT_OFFSET 8
+
+#define CF_FILE_ID_OFFSET 0
+#define CF_DATA_OFFSET CREATE_FILE_HEADER_LEN
+
+#define AB_FILE_ID_OFFSET 0
+#define AB_DATA_OFFSET APPEND_BLOCK_HEADER_LEN
+
+#define EL_FILE_ID_OFFSET 0
+
+#define DF_FILE_ID_OFFSET 0
+
#define QUERY_EVENT_OVERHEAD (LOG_EVENT_HEADER_LEN+QUERY_HEADER_LEN)
-#define ROTATE_EVENT_OVERHEAD LOG_EVENT_HEADER_LEN
-#define LOAD_EVENT_OVERHEAD (LOG_EVENT_HEADER_LEN+LOAD_HEADER_LEN+sizeof(sql_ex_info))
+#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)
+
#define BINLOG_MAGIC "\xfe\x62\x69\x6e"
+#define LOG_EVENT_TIME_F 0x1
+#define LOG_EVENT_FORCED_ROTATE_F 0x2
+
enum Log_event_type { START_EVENT = 1, QUERY_EVENT =2,
STOP_EVENT=3, ROTATE_EVENT = 4, INTVAR_EVENT=5,
- LOAD_EVENT=6};
+ 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};
enum Int_event_type { INVALID_INT_EVENT = 0, LAST_INSERT_ID_EVENT = 1, INSERT_ID_EVENT = 2
};
#ifndef MYSQL_CLIENT
class String;
+class MYSQL_LOG;
+class THD;
#endif
extern uint32 server_id;
+struct st_relay_log_info;
+
class Log_event
{
public:
time_t when;
ulong exec_time;
- int valid_exec_time; // if false, the exec time setting is bogus
uint32 server_id;
+ my_off_t log_pos;
+ uint16 flags;
+ int cached_event_len;
+ char* temp_buf;
+#ifndef MYSQL_CLIENT
+ THD* thd;
+#endif
static void *operator new(size_t size)
{
@@ -81,41 +236,63 @@ public:
int write(IO_CACHE* file);
int write_header(IO_CACHE* file);
- virtual int write_data(IO_CACHE* file __attribute__((unused))) { return 0; }
+ 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)))
+ { return 0; }
+ virtual int write_data_body(IO_CACHE* file __attribute__((unused)))
+ { return 0; }
virtual Log_event_type get_type_code() = 0;
- Log_event(time_t when_arg, ulong exec_time_arg = 0,
- int valid_exec_time_arg = 0, uint32 server_id_arg = 0):
- when(when_arg), exec_time(exec_time_arg),
- valid_exec_time(valid_exec_time_arg)
- {
- server_id = server_id_arg ? server_id_arg : (::server_id);
- }
-
- Log_event(const char* buf): valid_exec_time(0)
- {
- when = uint4korr(buf);
- server_id = uint4korr(buf + 5);
- }
-
- virtual ~Log_event() {}
-
+ virtual bool is_valid() = 0;
+ virtual bool get_cache_stmt() { return 0; }
+ Log_event(const char* buf, bool old_format);
+#ifndef MYSQL_CLIENT
+ Log_event(THD* thd_arg, uint16 flags_arg = 0);
+#endif
+ virtual ~Log_event() { free_temp_buf();}
+ void register_temp_buf(char* buf) { temp_buf = buf; }
+ void free_temp_buf()
+ {
+ if (temp_buf)
+ {
+ my_free(temp_buf, MYF(0));
+ temp_buf = 0;
+ }
+ }
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()); }
+#ifdef MYSQL_CLIENT
virtual void print(FILE* file, bool short_form = 0, char* last_db = 0) = 0;
-
void print_timestamp(FILE* file, time_t *ts = 0);
void print_header(FILE* file);
-
+#endif
+
#ifndef MYSQL_CLIENT
// if mutex is 0, the read will proceed without mutex
- static Log_event* read_log_event(IO_CACHE* file, pthread_mutex_t* log_lock);
+ static Log_event* read_log_event(IO_CACHE* file,
+ pthread_mutex_t* log_lock,
+ bool old_format);
#else // avoid having to link mysqlbinlog against libpthread
- static Log_event* read_log_event(IO_CACHE* file);
+ static Log_event* read_log_event(IO_CACHE* file, bool old_format);
#endif
- static Log_event* read_log_event(const char* buf, int event_len);
+ static Log_event* read_log_event(const char* buf, int event_len,
+ const char **error, bool old_format);
+ const char* get_type_str();
#ifndef MYSQL_CLIENT
static int read_log_event(IO_CACHE* file, String* packet,
pthread_mutex_t* log_lock);
+ void set_log_pos(MYSQL_LOG* log);
+ virtual void pack_info(String* packet);
+ int net_send(THD* thd, const char* log_name, my_off_t pos);
+ static void init_show_field_list(List<Item>* field_list);
+ virtual int exec_event(struct st_relay_log_info* rli);
+ virtual const char* get_db()
+ {
+ return thd ? thd->db : 0;
+ }
#endif
};
@@ -135,28 +312,17 @@ public:
uint16 error_code;
ulong thread_id;
#if !defined(MYSQL_CLIENT)
- THD* thd;
bool cache_stmt;
- Query_log_event(THD* thd_arg, const char* query_arg, bool using_trans=0):
- Log_event(thd_arg->start_time,0,1,thd_arg->server_id), data_buf(0),
- query(query_arg), db(thd_arg->db), q_len(thd_arg->query_length),
- error_code(thd_arg->killed ? ER_SERVER_SHUTDOWN: thd_arg->net.last_errno),
- thread_id(thd_arg->thread_id), thd(thd_arg),
- cache_stmt(using_trans &&
- (thd_arg->options & (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN)))
- {
- time_t end_time;
- time(&end_time);
- exec_time = (ulong) (end_time - thd->start_time);
- db_len = (db) ? (uint32) strlen(db) : 0;
- // do not log stray system errors such as EE_WRITE
- if (error_code < ERRMOD)
- error_code = 0;
- }
+
+ Query_log_event(THD* thd_arg, const char* query_arg,
+ bool using_trans=0);
+ const char* get_db() { return db; }
+ void pack_info(String* packet);
+ int exec_event(struct st_relay_log_info* rli);
+ bool get_cache_stmt() { return cache_stmt; }
#endif
- Query_log_event(IO_CACHE* file, time_t when, uint32 server_id_arg);
- Query_log_event(const char* buf, int event_len);
+ Query_log_event(const char* buf, int event_len, bool old_format);
~Query_log_event()
{
if (data_buf)
@@ -167,46 +333,55 @@ public:
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 +
- sizeof(uint32) // thread_id
- + sizeof(uint32) // exec_time
- + sizeof(uint16) // error_code
+ 4 // thread_id
+ + 4 // exec_time
+ + 2 // error_code
;
}
-
+#ifdef MYSQL_CLIENT
void print(FILE* file, bool short_form = 0, char* last_db = 0);
+#endif
};
-#define DUMPFILE_FLAG 0x1
-#define OPT_ENCLOSED_FLAG 0x2
-#define REPLACE_FLAG 0x4
-#define IGNORE_FLAG 0x8
-
-#define FIELD_TERM_EMPTY 0x1
-#define ENCLOSED_EMPTY 0x2
-#define LINE_TERM_EMPTY 0x4
-#define LINE_START_EMPTY 0x8
-#define ESCAPED_EMPTY 0x10
+class Slave_log_event: public Log_event
+{
+protected:
+ char* mem_pool;
+ void init_from_mem_pool(int data_size);
+public:
+ my_off_t master_pos;
+ char* master_host;
+ char* master_log;
+ int master_host_len;
+ int master_log_len;
+ uint16 master_port;
+#ifndef MYSQL_CLIENT
+ Slave_log_event(THD* thd_arg, struct st_relay_log_info* rli);
+ void pack_info(String* packet);
+ int exec_event(struct st_relay_log_info* rli);
+#endif
+
+ Slave_log_event(const char* buf, int event_len);
+ ~Slave_log_event();
+ int get_data_size();
+ bool is_valid() { return master_host != 0; }
+ Log_event_type get_type_code() { return SLAVE_EVENT; }
+#ifdef MYSQL_CLIENT
+ void print(FILE* file, bool short_form = 0, char* last_db = 0);
+#endif
+ int write_data(IO_CACHE* file );
-struct sql_ex_info
- {
- char field_term;
- char enclosed;
- char line_term;
- char line_start;
- char escaped;
- char opt_flags; // flags for the options
- char empty_flags; // flags to indicate which of the terminating charact
- } ;
+};
class Load_log_event: public Log_event
{
protected:
- char* data_buf;
- void copy_log_event(const char *buf, ulong data_len);
+ int copy_log_event(const char *buf, ulong event_len, bool old_format);
public:
ulong thread_id;
@@ -217,7 +392,6 @@ public:
const char* fields;
const uchar* field_lens;
uint32 field_block_len;
-
const char* table_name;
const char* db;
@@ -226,89 +400,31 @@ public:
sql_ex_info sql_ex;
#if !defined(MYSQL_CLIENT)
- THD* thd;
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 ):
- Log_event(thd->start_time),data_buf(0),thread_id(thd->thread_id),
- num_fields(0),fields(0),field_lens(0),field_block_len(0),
- table_name(table_name_arg),
- db(db_arg),
- fname(ex->file_name),
- thd(thd)
- {
- time_t end_time;
- time(&end_time);
- exec_time = (ulong) (end_time - thd->start_time);
- valid_exec_time = 1;
- db_len = (db) ? (uint32) strlen(db) : 0;
- table_name_len = (table_name) ? (uint32) strlen(table_name) : 0;
- fname_len = (fname) ? (uint) strlen(fname) : 0;
- sql_ex.field_term = (*ex->field_term)[0];
- sql_ex.enclosed = (*ex->enclosed)[0];
- sql_ex.line_term = (*ex->line_term)[0];
- sql_ex.line_start = (*ex->line_start)[0];
- sql_ex.escaped = (*ex->escaped)[0];
- sql_ex.opt_flags = 0;
- if(ex->dumpfile)
- sql_ex.opt_flags |= DUMPFILE_FLAG;
- if(ex->opt_enclosed)
- sql_ex.opt_flags |= OPT_ENCLOSED_FLAG;
-
- sql_ex.empty_flags = 0;
-
- switch(handle_dup)
- {
- case DUP_IGNORE: sql_ex.opt_flags |= IGNORE_FLAG; break;
- case DUP_REPLACE: sql_ex.opt_flags |= REPLACE_FLAG; break;
- case DUP_ERROR: break;
- }
-
- if(!ex->field_term->length())
- sql_ex.empty_flags |= FIELD_TERM_EMPTY;
- if(!ex->enclosed->length())
- sql_ex.empty_flags |= ENCLOSED_EMPTY;
- if(!ex->line_term->length())
- sql_ex.empty_flags |= LINE_TERM_EMPTY;
- if(!ex->line_start->length())
- sql_ex.empty_flags |= LINE_START_EMPTY;
- if(!ex->escaped->length())
- sql_ex.empty_flags |= ESCAPED_EMPTY;
-
- skip_lines = ex->skip_lines;
-
- List_iterator<Item> li(fields_arg);
- field_lens_buf.length(0);
- fields_buf.length(0);
- Item* item;
- while((item = li++))
- {
- num_fields++;
- uchar len = (uchar) strlen(item->name);
- field_block_len += len + 1;
- fields_buf.append(item->name, len + 1);
- field_lens_buf.append((char*)&len, 1);
- }
-
- field_lens = (const uchar*)field_lens_buf.ptr();
- fields = fields_buf.ptr();
- }
+
+ 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);
void set_fields(List<Item> &fields_arg);
+ void pack_info(String* packet);
+ const char* get_db() { return db; }
+ int exec_event(struct st_relay_log_info* rli)
+ {
+ return exec_event(thd->slave_net,rli);
+ }
+ int exec_event(NET* net, struct st_relay_log_info* rli);
#endif
- Load_log_event(IO_CACHE * file, time_t when, uint32 server_id_arg);
- Load_log_event(const char* buf, int event_len);
+ Load_log_event(const char* buf, int event_len, bool old_format);
~Load_log_event()
{
- if (data_buf)
- {
- my_free((gptr) data_buf, MYF(0));
- }
}
- Log_event_type get_type_code() { return LOAD_EVENT; }
- int write_data(IO_CACHE* file); // returns 0 on success, -1 on error
+ 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; }
int get_data_size()
{
return table_name_len + 2 + db_len + 2 + fname_len
@@ -316,11 +432,13 @@ public:
+ 4 // exec_time
+ 4 // skip_lines
+ 4 // field block len
- + sizeof(sql_ex) + field_block_len + num_fields*sizeof(uchar) ;
+ + sql_ex.data_size() + field_block_len + num_fields;
;
}
-
+ int get_data_body_offset() { return LOAD_EVENT_OVERHEAD; }
+#ifdef MYSQL_CLIENT
void print(FILE* file, bool short_form = 0, char* last_db = 0);
+#endif
};
extern char server_version[SERVER_VERSION_LENGTH];
@@ -330,35 +448,30 @@ class Start_log_event: public Log_event
public:
uint32 created;
uint16 binlog_version;
- char server_version[50];
-
- Start_log_event() :Log_event(time(NULL)),binlog_version(BINLOG_VERSION)
+ char server_version[ST_SERVER_VER_LEN];
+#ifndef MYSQL_CLIENT
+ Start_log_event() :Log_event((THD*)0),binlog_version(BINLOG_VERSION)
{
created = (uint32) when;
- memcpy(server_version, ::server_version, sizeof(server_version));
- }
- Start_log_event(IO_CACHE* file, time_t when_arg, uint32 server_id_arg) :
- Log_event(when_arg, 0, 0, server_id_arg)
- {
- char buf[sizeof(server_version) + 2 + 4 + 4];
- if (my_b_read(file, (byte*) buf, sizeof(buf)))
- return;
- binlog_version = uint2korr(buf+4);
- memcpy(server_version, buf + 6, sizeof(server_version));
- server_version[sizeof(server_version)-1]=0;
- created = uint4korr(buf + 6 + sizeof(server_version));
+ memcpy(server_version, ::server_version, ST_SERVER_VER_LEN);
}
- Start_log_event(const char* buf);
-
+#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; }
int get_data_size()
{
- // sizeof(binlog_version) + sizeof(server_version) sizeof(created)
- return 2 + sizeof(server_version) + 4;
+ return START_HEADER_LEN;
}
+#ifndef MYSQL_CLIENT
+ void pack_info(String* packet);
+ int exec_event(struct st_relay_log_info* rli);
+#endif
+#ifdef MYSQL_CLIENT
void print(FILE* file, bool short_form = 0, char* last_db = 0);
+#endif
};
class Intvar_log_event: public Log_event
@@ -366,37 +479,48 @@ class Intvar_log_event: public Log_event
public:
ulonglong val;
uchar type;
- Intvar_log_event(uchar type_arg, ulonglong val_arg)
- :Log_event(time(NULL)),val(val_arg),type(type_arg)
+#ifndef MYSQL_CLIENT
+ Intvar_log_event(THD* thd_arg,uchar type_arg, ulonglong val_arg)
+ :Log_event(thd_arg),val(val_arg),type(type_arg)
{}
- Intvar_log_event(IO_CACHE* file, time_t when, uint32 server_id_arg);
- Intvar_log_event(const char* buf);
+#endif
+ Intvar_log_event(const char* buf, bool old_format);
~Intvar_log_event() {}
Log_event_type get_type_code() { return INTVAR_EVENT;}
+ const char* get_var_type_name();
int get_data_size() { return sizeof(type) + sizeof(val);}
int write_data(IO_CACHE* file);
+ bool is_valid() { return 1; }
+#ifndef MYSQL_CLIENT
+ void pack_info(String* packet);
+ int exec_event(struct st_relay_log_info* rli);
+#endif
-
+#ifdef MYSQL_CLIENT
void print(FILE* file, bool short_form = 0, char* last_db = 0);
+#endif
};
class Stop_log_event: public Log_event
{
public:
- Stop_log_event() :Log_event(time(NULL))
+#ifndef MYSQL_CLIENT
+ Stop_log_event() :Log_event((THD*)0)
{}
- Stop_log_event(IO_CACHE* file, time_t when_arg, uint32 server_id_arg):
- Log_event(when_arg,0,0,server_id_arg)
- {
- byte skip[4];
- my_b_read(file, skip, sizeof(skip)); // skip the event length
- }
- Stop_log_event(const char* buf):Log_event(buf)
+#endif
+ Stop_log_event(const char* buf, bool old_format):Log_event(buf,
+ old_format)
{
}
~Stop_log_event() {}
Log_event_type get_type_code() { return STOP_EVENT;}
+ bool is_valid() { return 1; }
+#ifdef MYSQL_CLIENT
void print(FILE* file, bool short_form = 0, char* last_db = 0);
+#endif
+#ifndef MYSQL_CLIENT
+ int exec_event(struct st_relay_log_info* rli);
+#endif
};
class Rotate_log_event: public Log_event
@@ -404,27 +528,172 @@ class Rotate_log_event: public Log_event
public:
const char* new_log_ident;
uchar ident_len;
+ ulonglong pos;
bool alloced;
-
- Rotate_log_event(const char* new_log_ident_arg, uint ident_len_arg = 0) :
- Log_event(time(NULL)),
+#ifndef MYSQL_CLIENT
+ Rotate_log_event(THD* thd_arg, const char* new_log_ident_arg,
+ uint ident_len_arg = 0,ulonglong pos_arg = 4) :
+ Log_event(thd_arg),
new_log_ident(new_log_ident_arg),
- ident_len(ident_len_arg ? ident_len_arg : (uint) strlen(new_log_ident_arg)),
+ ident_len(ident_len_arg ? ident_len_arg :
+ (uint) strlen(new_log_ident_arg)), pos(pos_arg),
alloced(0)
{}
-
- Rotate_log_event(IO_CACHE* file, time_t when, uint32 server_id_arg) ;
- Rotate_log_event(const char* buf, int event_len);
+#endif
+ Rotate_log_event(const char* buf, int event_len, bool old_format);
~Rotate_log_event()
{
if (alloced)
my_free((gptr) new_log_ident, MYF(0));
}
Log_event_type get_type_code() { return ROTATE_EVENT;}
- int get_data_size() { return ident_len;}
+ int get_data_size() { return ident_len + ROTATE_HEADER_LEN;}
+ bool is_valid() { return new_log_ident != 0; }
+ int write_data(IO_CACHE* file);
+#ifdef MYSQL_CLIENT
+ void print(FILE* file, bool short_form = 0, char* last_db = 0);
+#endif
+#ifndef MYSQL_CLIENT
+ void pack_info(String* packet);
+ int exec_event(struct st_relay_log_info* rli);
+#endif
+};
+
+/* the classes below are for the new LOAD DATA INFILE logging */
+
+class Create_file_log_event: public Load_log_event
+{
+protected:
+ // pretend we are Load event, so we can write out just
+ // our Load part - used on the slave when writing event out to
+ // SQL_LOAD-*.info file
+ bool fake_base;
+public:
+ char* block;
+ uint block_len;
+ uint file_id;
+ bool inited_from_old;
+#ifndef MYSQL_CLIENT
+ Create_file_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,
+ char* block_arg, uint block_len_arg);
+#endif
+
+ Create_file_log_event(const char* buf, int event_len, bool old_format);
+ ~Create_file_log_event()
+ {
+ }
+ Log_event_type get_type_code()
+ {
+ return fake_base ? Load_log_event::get_type_code() : CREATE_FILE_EVENT;
+ }
+ int get_data_size() { return fake_base ? Load_log_event::get_data_size() :
+ 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);
+ int write_base(IO_CACHE* file); // cut out Create_file extentions and
+ // write it as Load event - used on the slave
+
+#ifdef MYSQL_CLIENT
+ void print(FILE* file, bool short_form = 0, char* last_db = 0);
+#endif
+#ifndef MYSQL_CLIENT
+ void pack_info(String* packet);
+ int exec_event(struct st_relay_log_info* rli);
+#endif
+};
+
+class Append_block_log_event: public Log_event
+{
+public:
+ char* block;
+ uint block_len;
+ uint file_id;
+
+#ifndef MYSQL_CLIENT
+ Append_block_log_event(THD* thd, char* block_arg,
+ uint block_len_arg);
+ int exec_event(struct st_relay_log_info* rli);
+#endif
+
+ Append_block_log_event(const char* buf, int event_len);
+ ~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);
+
+#ifdef MYSQL_CLIENT
+ void print(FILE* file, bool short_form = 0, char* last_db = 0);
+#endif
+#ifndef MYSQL_CLIENT
+ void pack_info(String* packet);
+#endif
+};
+
+class Delete_file_log_event: public Log_event
+{
+public:
+ uint file_id;
+#ifndef MYSQL_CLIENT
+ Delete_file_log_event(THD* thd);
+#endif
+
+ Delete_file_log_event(const char* buf, int event_len);
+ ~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);
+
+#ifdef MYSQL_CLIENT
+ void print(FILE* file, bool short_form = 0, char* last_db = 0);
+#endif
+#ifndef MYSQL_CLIENT
+ void pack_info(String* packet);
+ int exec_event(struct st_relay_log_info* rli);
+#endif
+};
+
+class Execute_load_log_event: public Log_event
+{
+public:
+ uint file_id;
+
+#ifndef MYSQL_CLIENT
+ Execute_load_log_event(THD* thd);
+#endif
+
+ Execute_load_log_event(const char* buf, int event_len);
+ ~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);
+
+#ifdef MYSQL_CLIENT
void print(FILE* file, bool short_form = 0, char* last_db = 0);
+#endif
+#ifndef MYSQL_CLIENT
+ void pack_info(String* packet);
+ int exec_event(struct st_relay_log_info* rli);
+#endif
};
#endif
+
+
+
diff --git a/sql/matherr.c b/sql/matherr.c
index 8523a78ce94..ea0c15d2feb 100644
--- a/sql/matherr.c
+++ b/sql/matherr.c
@@ -1,22 +1,22 @@
/* 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 */
/* Fix that we got POSTFIX_ERROR when doing unreasonable math (not core) */
-#include <global.h>
+#include <my_global.h>
#include <errno.h>
/* Fix that we gets POSTFIX_ERROR when error in math */
diff --git a/sql/mf_iocache.cc b/sql/mf_iocache.cc
index cddacaa820f..1bc65eebd23 100644
--- a/sql/mf_iocache.cc
+++ b/sql/mf_iocache.cc
@@ -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 */
@@ -42,293 +42,6 @@ static void my_aiowait(my_aio_result *result);
extern "C" {
/*
- ** if cachesize == 0 then use default cachesize (from s-file)
- ** if file == -1 then real_open_cached_file() will be called.
- ** returns 0 if ok
- */
-
-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)
-{
- uint min_cache;
- DBUG_ENTER("init_io_cache");
- DBUG_PRINT("enter",("type: %d pos: %ld",(int) type, (ulong) seek_offset));
-
- /* There is no file in net_reading */
- info->file= file;
- if (!cachesize)
- if (! (cachesize= my_default_record_cache_size))
- DBUG_RETURN(1); /* No cache requested */
- min_cache=use_async_io ? IO_SIZE*4 : IO_SIZE*2;
- if (type == READ_CACHE)
- { /* Assume file isn't growing */
- if (cache_myflags & MY_DONT_CHECK_FILESIZE)
- {
- cache_myflags &= ~MY_DONT_CHECK_FILESIZE;
- }
- else
- {
- my_off_t file_pos,end_of_file;
- if ((file_pos=my_tell(file,MYF(0)) == MY_FILEPOS_ERROR))
- DBUG_RETURN(1);
- end_of_file=my_seek(file,0L,MY_SEEK_END,MYF(0));
- if (end_of_file < seek_offset)
- end_of_file=seek_offset;
- VOID(my_seek(file,file_pos,MY_SEEK_SET,MYF(0)));
- if ((my_off_t) cachesize > end_of_file-seek_offset+IO_SIZE*2-1)
- {
- cachesize=(uint) (end_of_file-seek_offset)+IO_SIZE*2-1;
- use_async_io=0; /* No nead to use async */
- }
- }
- }
- if ((int) type < (int) READ_NET)
- {
- for (;;)
- {
- cachesize=(uint) ((ulong) (cachesize + min_cache-1) &
- (ulong) ~(min_cache-1));
- if (cachesize < min_cache)
- cachesize = min_cache;
- if ((info->buffer=
- (byte*) my_malloc(cachesize,
- MYF((cache_myflags & ~ MY_WME) |
- (cachesize == min_cache ? MY_WME : 0)))) != 0)
- break; /* Enough memory found */
- if (cachesize == min_cache)
- DBUG_RETURN(2); /* Can't alloc cache */
- cachesize= (uint) ((long) cachesize*3/4); /* Try with less memory */
- }
- }
- else
- info->buffer=0;
- DBUG_PRINT("info",("init_io_cache: cachesize = %u",cachesize));
- info->pos_in_file= seek_offset;
- info->read_length=info->buffer_length=cachesize;
- info->seek_not_done= test(file >= 0 && type != READ_FIFO &&
- type != READ_NET);
- info->myflags=cache_myflags & ~(MY_NABP | MY_FNABP);
- info->rc_request_pos=info->rc_pos=info->buffer;
-
- if (type == READ_CACHE || type == READ_NET || type == READ_FIFO)
- {
- info->rc_end=info->buffer; /* Nothing in cache */
- }
- else /* type == WRITE_CACHE */
- {
- info->rc_end=info->buffer+info->buffer_length- (seek_offset & (IO_SIZE-1));
- }
- /* end_of_file may be changed by user later */
- info->end_of_file= ((type == READ_NET || type == READ_FIFO ) ? 0
- : ~(my_off_t) 0);
- info->type=type;
- info->error=0;
- info->read_function=(type == READ_NET) ? _my_b_net_read : _my_b_read; /* net | file */
-#ifdef HAVE_AIOWAIT
- if (use_async_io && ! my_disable_async_io)
- {
- DBUG_PRINT("info",("Using async io"));
- info->read_length/=2;
- info->read_function=_my_b_async_read;
- }
- info->inited=info->aio_result.pending=0;
-#endif
- DBUG_RETURN(0);
-} /* init_io_cache */
-
-
- /* Wait until current request is ready */
-
-#ifdef HAVE_AIOWAIT
-static void my_aiowait(my_aio_result *result)
-{
- if (result->pending)
- {
- struct aio_result_t *tmp;
- for (;;)
- {
- if ((int) (tmp=aiowait((struct timeval *) 0)) == -1)
- {
- if (errno == EINTR)
- continue;
- DBUG_PRINT("error",("No aio request, error: %d",errno));
- result->pending=0; /* Assume everythings is ok */
- break;
- }
- ((my_aio_result*) tmp)->pending=0;
- if ((my_aio_result*) tmp == result)
- break;
- }
- }
- return;
-}
-#endif
-
- /* Use this to reset cache to start or other type */
- /* Some simple optimizing is done when reinit in current buffer */
-
-my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type,
- my_off_t seek_offset,
- pbool use_async_io __attribute__((unused)),
- pbool clear_cache)
-{
- DBUG_ENTER("reinit_io_cache");
-
- info->seek_not_done= test(info->file >= 0); /* Seek not done */
-
- /* If the whole file is in memory, avoid flushing to disk */
- if (! clear_cache &&
- seek_offset >= info->pos_in_file &&
- seek_offset <= info->pos_in_file +
- (uint) (info->rc_end - info->rc_request_pos))
- { /* use current buffer */
- if (info->type == WRITE_CACHE && type == READ_CACHE)
- {
- info->rc_end=info->rc_pos;
- info->end_of_file=my_b_tell(info);
- }
- else if (type == WRITE_CACHE)
- {
- if (info->type == READ_CACHE)
- info->rc_end=info->buffer+info->buffer_length;
- info->end_of_file = ~(my_off_t) 0;
- }
- info->rc_pos=info->rc_request_pos+(seek_offset-info->pos_in_file);
-#ifdef HAVE_AIOWAIT
- my_aiowait(&info->aio_result); /* Wait for outstanding req */
-#endif
- }
- else
- {
- /*
- If we change from WRITE_CACHE to READ_CACHE, assume that everything
- after the current positions should be ignored
- */
- if (info->type == WRITE_CACHE && type == READ_CACHE)
- info->end_of_file=my_b_tell(info);
- /* No need to flush cache if we want to reuse it */
- if ((type != WRITE_CACHE || !clear_cache) && flush_io_cache(info))
- DBUG_RETURN(1);
- if (info->pos_in_file != seek_offset)
- {
- info->pos_in_file=seek_offset;
- info->seek_not_done=1;
- }
- info->rc_request_pos=info->rc_pos=info->buffer;
- if (type == READ_CACHE || type == READ_NET || type == READ_FIFO)
- {
- info->rc_end=info->buffer; /* Nothing in cache */
- }
- else
- {
- info->rc_end=info->buffer+info->buffer_length-
- (seek_offset & (IO_SIZE-1));
- info->end_of_file= ((type == READ_NET || type == READ_FIFO) ? 0 :
- ~(my_off_t) 0);
- }
- }
- info->type=type;
- info->error=0;
- info->read_function=(type == READ_NET) ? _my_b_net_read : _my_b_read;
-#ifdef HAVE_AIOWAIT
- if (type != READ_NET)
- {
- if (use_async_io && ! my_disable_async_io &&
- ((ulong) info->buffer_length <
- (ulong) (info->end_of_file - seek_offset)))
- {
- info->read_length=info->buffer_length/2;
- info->read_function=_my_b_async_read;
- }
- }
- info->inited=0;
-#endif
- DBUG_RETURN(0);
-} /* init_io_cache */
-
-
-
- /*
- Read buffered. Returns 1 if can't read requested characters
- This function is only called from the my_b_read() macro
- when there isn't enough characters in the buffer to
- satisfy the request.
- Returns 0 we succeeded in reading all data
- */
-
-int _my_b_read(register IO_CACHE *info, byte *Buffer, uint Count)
-{
- uint length,diff_length,left_length;
- my_off_t max_length, pos_in_file;
-
- if ((left_length=(uint) (info->rc_end-info->rc_pos)))
- {
- dbug_assert(Count >= left_length); /* User is not using my_b_read() */
- memcpy(Buffer,info->rc_pos, (size_t) (left_length));
- Buffer+=left_length;
- Count-=left_length;
- }
- /* pos_in_file always point on where info->buffer was read */
- pos_in_file=info->pos_in_file+(uint) (info->rc_end - info->buffer);
- if (info->seek_not_done)
- { /* File touched, do seek */
- VOID(my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0)));
- info->seek_not_done=0;
- }
- diff_length=(uint) (pos_in_file & (IO_SIZE-1));
- if (Count >= (uint) (IO_SIZE+(IO_SIZE-diff_length)))
- { /* Fill first intern buffer */
- uint read_length;
- if (info->end_of_file == pos_in_file)
- { /* End of file */
- info->error=(int) left_length;
- return 1;
- }
- length=(Count & (uint) ~(IO_SIZE-1))-diff_length;
- if ((read_length=my_read(info->file,Buffer,(uint) length,info->myflags))
- != (uint) length)
- {
- info->error= read_length == (uint) -1 ? -1 :
- (int) (read_length+left_length);
- return 1;
- }
- Count-=length;
- Buffer+=length;
- pos_in_file+=length;
- left_length+=length;
- diff_length=0;
- }
- max_length=info->read_length-diff_length;
- if (info->type != READ_FIFO &&
- (info->end_of_file - pos_in_file) < max_length)
- max_length = info->end_of_file - pos_in_file;
- if (!max_length)
- {
- if (Count)
- {
- info->error= left_length; /* We only got this many char */
- return 1;
- }
- length=0; /* Didn't read any chars */
- }
- else if ((length=my_read(info->file,info->buffer,(uint) max_length,
- info->myflags)) < Count ||
- length == (uint) -1)
- {
- if (length != (uint) -1)
- memcpy(Buffer,info->buffer,(size_t) length);
- info->error= length == (uint) -1 ? -1 : (int) (length+left_length);
- return 1;
- }
- info->rc_pos=info->buffer+Count;
- info->rc_end=info->buffer+length;
- info->pos_in_file=pos_in_file;
- memcpy(Buffer,info->buffer,(size_t) Count);
- return 0;
-}
-
- /*
** Read buffered from the net.
** Returns 1 if can't read requested characters
** Returns 0 if record read
@@ -337,353 +50,34 @@ int _my_b_read(register IO_CACHE *info, byte *Buffer, uint Count)
int _my_b_net_read(register IO_CACHE *info, byte *Buffer,
uint Count __attribute__((unused)))
{
- int read_length;
+ ulong read_length;
NET *net= &(current_thd)->net;
+ DBUG_ENTER("_my_b_net_read");
- if (info->end_of_file)
- return 1; /* because my_b_get (no _) takes 1 byte at a time */
+ if (!info->end_of_file)
+ DBUG_RETURN(1); /* because my_b_get (no _) takes 1 byte at a time */
read_length=my_net_read(net);
- if (read_length == (int) packet_error)
+ if (read_length == packet_error)
{
info->error= -1;
- return 1;
+ DBUG_RETURN(1);
}
if (read_length == 0)
{
- /* End of file from client */
- info->end_of_file = 1; return 1;
+ info->end_of_file= 0; /* End of file from client */
+ DBUG_RETURN(1);
}
/* to set up stuff for my_b_get (no _) */
- info->rc_end = (info->rc_pos = (byte*) net->read_pos) + read_length;
- Buffer[0] = info->rc_pos[0]; /* length is always 1 */
- info->rc_pos++;
- return 0;
-}
-
-#ifdef HAVE_AIOWAIT
-
-int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count)
-{
- uint length,read_length,diff_length,left_length,use_length,org_Count;
- my_off_t max_length;
- my_off_t next_pos_in_file;
- byte *read_buffer;
-
- memcpy(Buffer,info->rc_pos,
- (size_t) (left_length=(uint) (info->rc_end-info->rc_pos)));
- Buffer+=left_length;
- org_Count=Count;
- Count-=left_length;
-
- if (info->inited)
- { /* wait for read block */
- info->inited=0; /* No more block to read */
- my_aiowait(&info->aio_result); /* Wait for outstanding req */
- if (info->aio_result.result.aio_errno)
- {
- if (info->myflags & MY_WME)
- my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
- my_filename(info->file),
- info->aio_result.result.aio_errno);
- my_errno=info->aio_result.result.aio_errno;
- info->error= -1;
- return(1);
- }
- if (! (read_length = (uint) info->aio_result.result.aio_return) ||
- read_length == (uint) -1)
- {
- my_errno=0; /* For testing */
- info->error= (read_length == (uint) -1 ? -1 :
- (int) (read_length+left_length));
- return(1);
- }
- info->pos_in_file+=(uint) (info->rc_end - info->rc_request_pos);
-
- if (info->rc_request_pos != info->buffer)
- info->rc_request_pos=info->buffer;
- else
- info->rc_request_pos=info->buffer+info->read_length;
- info->rc_pos=info->rc_request_pos;
- next_pos_in_file=info->aio_read_pos+read_length;
-
- /* Check if pos_in_file is changed
- (_ni_read_cache may have skipped some bytes) */
-
- if (info->aio_read_pos < info->pos_in_file)
- { /* Fix if skipped bytes */
- if (info->aio_read_pos + read_length < info->pos_in_file)
- {
- read_length=0; /* Skipp block */
- next_pos_in_file=info->pos_in_file;
- }
- else
- {
- my_off_t offset= (info->pos_in_file - info->aio_read_pos);
- info->pos_in_file=info->aio_read_pos; /* Whe are here */
- info->rc_pos=info->rc_request_pos+offset;
- read_length-=offset; /* Bytes left from rc_pos */
- }
- }
-#ifndef DBUG_OFF
- if (info->aio_read_pos > info->pos_in_file)
- {
- my_errno=EINVAL;
- return(info->read_length= -1);
- }
-#endif
- /* Copy found bytes to buffer */
- length=min(Count,read_length);
- memcpy(Buffer,info->rc_pos,(size_t) length);
- Buffer+=length;
- Count-=length;
- left_length+=length;
- info->rc_end=info->rc_pos+read_length;
- info->rc_pos+=length;
- }
- else
- next_pos_in_file=(info->pos_in_file+ (uint)
- (info->rc_end - info->rc_request_pos));
-
- /* If reading large blocks, or first read or read with skipp */
- if (Count)
- {
- if (next_pos_in_file == info->end_of_file)
- {
- info->error=(int) (read_length+left_length);
- return 1;
- }
- VOID(my_seek(info->file,next_pos_in_file,MY_SEEK_SET,MYF(0)));
- read_length=IO_SIZE*2- (uint) (next_pos_in_file & (IO_SIZE-1));
- if (Count < read_length)
- { /* Small block, read to cache */
- if ((read_length=my_read(info->file,info->rc_request_pos,
- read_length, info->myflags)) == (uint) -1)
- return info->error= -1;
- use_length=min(Count,read_length);
- memcpy(Buffer,info->rc_request_pos,(size_t) use_length);
- info->rc_pos=info->rc_request_pos+Count;
- info->rc_end=info->rc_request_pos+read_length;
- info->pos_in_file=next_pos_in_file; /* Start of block in cache */
- next_pos_in_file+=read_length;
-
- if (Count != use_length)
- { /* Didn't find hole block */
- if (info->myflags & (MY_WME | MY_FAE | MY_FNABP) && Count != org_Count)
- my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
- my_filename(info->file),my_errno);
- info->error=(int) (read_length+left_length);
- return 1;
- }
- }
- else
- { /* Big block, don't cache it */
- if ((read_length=my_read(info->file,Buffer,(uint) Count,info->myflags))
- != Count)
- {
- info->error= read_length == (uint) -1 ? -1 : read_length+left_length;
- return 1;
- }
- info->rc_pos=info->rc_end=info->rc_request_pos;
- info->pos_in_file=(next_pos_in_file+=Count);
- }
- }
-
- /* Read next block with asyncronic io */
- max_length=info->end_of_file - next_pos_in_file;
- diff_length=(next_pos_in_file & (IO_SIZE-1));
-
- if (max_length > (my_off_t) info->read_length - diff_length)
- max_length= (my_off_t) info->read_length - diff_length;
- if (info->rc_request_pos != info->buffer)
- read_buffer=info->buffer;
- else
- read_buffer=info->buffer+info->read_length;
- info->aio_read_pos=next_pos_in_file;
- if (max_length)
- {
- info->aio_result.result.aio_errno=AIO_INPROGRESS; /* Marker for test */
- DBUG_PRINT("aioread",("filepos: %ld length: %ld",
- (ulong) next_pos_in_file,(ulong) max_length));
- if (aioread(info->file,read_buffer,(int) max_length,
- (my_off_t) next_pos_in_file,MY_SEEK_SET,
- &info->aio_result.result))
- { /* Skipp async io */
- my_errno=errno;
- DBUG_PRINT("error",("got error: %d, aio_result: %d from aioread, async skipped",
- errno, info->aio_result.result.aio_errno));
- if (info->rc_request_pos != info->buffer)
- {
- bmove(info->buffer,info->rc_request_pos,
- (uint) (info->rc_end - info->rc_pos));
- info->rc_request_pos=info->buffer;
- info->rc_pos-=info->read_length;
- info->rc_end-=info->read_length;
- }
- info->read_length=info->buffer_length; /* Use hole buffer */
- info->read_function=_my_b_read; /* Use normal IO_READ next */
- }
- else
- info->inited=info->aio_result.pending=1;
- }
- return 0; /* Block read, async in use */
-} /* _my_b_async_read */
-#endif
-
-
-/* Read one byte when buffer is empty */
-
-int _my_b_get(IO_CACHE *info)
-{
- byte buff;
- if ((*(info)->read_function)(info,&buff,1))
- return my_b_EOF;
- return (int) (uchar) buff;
-}
-
- /* Returns != 0 if error on write */
-
-int _my_b_write(register IO_CACHE *info, const byte *Buffer, uint Count)
-{
- uint rest_length,length;
-
- rest_length=(uint) (info->rc_end - info->rc_pos);
- memcpy(info->rc_pos,Buffer,(size_t) rest_length);
- Buffer+=rest_length;
- Count-=rest_length;
- info->rc_pos+=rest_length;
- if (info->pos_in_file+info->buffer_length > info->end_of_file)
- {
- my_errno=errno=EFBIG;
- return info->error = -1;
- }
- if (flush_io_cache(info))
- return 1;
- if (Count >= IO_SIZE)
- { /* Fill first intern buffer */
- length=Count & (uint) ~(IO_SIZE-1);
- if (info->seek_not_done)
- { /* File touched, do seek */
- VOID(my_seek(info->file,info->pos_in_file,MY_SEEK_SET,MYF(0)));
- info->seek_not_done=0;
- }
- if (my_write(info->file,Buffer,(uint) length,info->myflags | MY_NABP))
- return info->error= -1;
- Count-=length;
- Buffer+=length;
- info->pos_in_file+=length;
- }
- memcpy(info->rc_pos,Buffer,(size_t) Count);
- info->rc_pos+=Count;
- return 0;
-}
-
-
-/*
- Write a block to disk where part of the data may be inside the record
- buffer. As all write calls to the data goes through the cache,
- we will never get a seek over the end of the buffer
-*/
-
-int my_block_write(register IO_CACHE *info, const byte *Buffer, uint Count,
- my_off_t pos)
-{
- uint length;
- int error=0;
-
- if (pos < info->pos_in_file)
- {
- /* Of no overlap, write everything without buffering */
- if (pos + Count <= info->pos_in_file)
- return my_pwrite(info->file, Buffer, Count, pos,
- info->myflags | MY_NABP);
- /* Write the part of the block that is before buffer */
- length= (uint) (info->pos_in_file - pos);
- if (my_pwrite(info->file, Buffer, length, pos, info->myflags | MY_NABP))
- info->error=error=-1;
- Buffer+=length;
- pos+= length;
- Count-= length;
- }
-
- /* Check if we want to write inside the used part of the buffer.*/
- length= (uint) (info->rc_end - info->buffer);
- if (pos < info->pos_in_file + length)
- {
- uint offset= (uint) (pos - info->pos_in_file);
- length-=offset;
- if (length > Count)
- length=Count;
- memcpy(info->buffer+offset, Buffer, length);
- Buffer+=length;
- Count-= length;
- /* Fix length of buffer if the new data was larger */
- if (info->buffer+length > info->rc_pos)
- info->rc_pos=info->buffer+length;
- if (!Count)
- return (error);
- }
- /* Write at the end of the current buffer; This is the normal case */
- if (_my_b_write(info, Buffer, Count))
- error= -1;
- return error;
-}
-
- /* Flush write cache */
-
-int flush_io_cache(IO_CACHE *info)
-{
- uint length;
- DBUG_ENTER("flush_io_cache");
-
- if (info->type == WRITE_CACHE)
- {
- if (info->file == -1)
- {
- if (real_open_cached_file(info))
- DBUG_RETURN((info->error= -1));
- }
- if (info->rc_pos != info->buffer)
- {
- length=(uint) (info->rc_pos - info->buffer);
- if (info->seek_not_done)
- { /* File touched, do seek */
- if (my_seek(info->file,info->pos_in_file,MY_SEEK_SET,MYF(0)) ==
- MY_FILEPOS_ERROR)
- DBUG_RETURN((info->error= -1));
- info->seek_not_done=0;
- }
- info->rc_pos=info->buffer;
- info->pos_in_file+=length;
- info->rc_end=(info->buffer+info->buffer_length-
- (info->pos_in_file & (IO_SIZE-1)));
- if (my_write(info->file,info->buffer,length,info->myflags | MY_NABP))
- DBUG_RETURN((info->error= -1));
- DBUG_RETURN(0);
- }
- }
-#ifdef HAVE_AIOWAIT
- else if (info->type != READ_NET)
- {
- my_aiowait(&info->aio_result); /* Wait for outstanding req */
- info->inited=0;
- }
-#endif
+ info->read_end = (info->read_pos = (byte*) net->read_pos) + read_length;
+ Buffer[0] = info->read_pos[0]; /* length is always 1 */
+ info->read_pos++;
+
+ /*
+ info->request_pos is used by log_loaded_block() to know the size
+ of the current block
+ */
+ info->request_pos=info->read_pos;
DBUG_RETURN(0);
}
-
-int end_io_cache(IO_CACHE *info)
-{
- int error=0;
- DBUG_ENTER("end_io_cache");
- if (info->buffer)
- {
- if (info->file != -1) /* File doesn't exist */
- error=flush_io_cache(info);
- my_free((gptr) info->buffer,MYF(MY_WME));
- info->buffer=info->rc_pos=(byte*) 0;
- }
- DBUG_RETURN(error);
-} /* end_io_cache */
-
} /* extern "C" */
diff --git a/sql/mini_client.cc b/sql/mini_client.cc
index 3dfd58375a5..c31fa573fea 100644
--- a/sql/mini_client.cc
+++ b/sql/mini_client.cc
@@ -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 */
@@ -22,25 +22,21 @@
in case we decide to make them external at some point
*/
-#define DONT_USE_RAID
+#ifdef EMBEDDED_LIBRARY
+#define net_read_timeout net_read_timeout1
+#define net_write_timeout net_write_timeout1
+#endif
+
#if defined(__WIN__)
#include <winsock.h>
-#include <odbcinst.h>
-/* Disable alarms */
-typedef my_bool ALARM;
-#define thr_alarm_init(A) (*(A))=0
-#define thr_alarm_in_use(A) (*(A))
-#define thr_end_alarm(A)
-#define thr_alarm(A,B,C) local_thr_alarm((A),(B),(C))
-inline int local_thr_alarm(my_bool *A,int B __attribute__((unused)),ALARM *C __attribute__((unused)))
-{
- *A=1;
- return 0;
-}
-#define thr_got_alarm(A) 0
+#include <odbcinst.h> /* QQ: Is this really needed ? */
+#define DONT_USE_THR_ALARM
#endif
-#include <global.h>
+#include <my_global.h>
+#include <mysql_embed.h>
+#include <mysql_com.h>
+#include <violite.h>
#include <my_sys.h>
#include <mysys_err.h>
#include <m_string.h>
@@ -50,9 +46,8 @@ inline int local_thr_alarm(my_bool *A,int B __attribute__((unused)),ALARM *C __a
#include "mysql_version.h"
#include "mysqld_error.h"
#include "errmsg.h"
-#include <violite.h>
-#if defined( OS2) && defined( MYSQL_SERVER)
+#if defined( OS2) && defined(MYSQL_SERVER)
#undef ER
#define ER CER
#endif
@@ -76,23 +71,35 @@ extern "C" { // Because of SCO 3.2V4.2
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
-#endif
+#endif /*!defined(MSDOS) && !defined(__WIN__) */
#ifdef HAVE_SYS_UN_H
# include <sys/un.h>
#endif
#if defined(THREAD)
#include <my_pthread.h> /* because of signal() */
-#include <thr_alarm.h>
#endif
+#include <thr_alarm.h>
#ifndef INADDR_NONE
#define INADDR_NONE -1
#endif
-
}
-static void mc_end_server(MYSQL *mysql);
+static void mc_free_rows(MYSQL_DATA *cur);
+static MYSQL_FIELD *unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields,
+ my_bool default_value,
+ my_bool long_flag_protocol);
+
+void mc_end_server(MYSQL *mysql);
static int mc_sock_connect(File s, const struct sockaddr *name, uint namelen, uint to);
static void mc_free_old_query(MYSQL *mysql);
+static int mc_send_file_to_server(MYSQL *mysql, const char *filename);
+static my_ulonglong mc_net_field_length_ll(uchar **packet);
+static ulong mc_net_field_length(uchar **packet);
+static int mc_read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row,
+ ulong *lengths);
+static MYSQL_DATA *mc_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
+ uint fields);
+
#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES)
@@ -187,8 +194,7 @@ HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host,
** Init MySQL structure or allocate one
****************************************************************************/
-MYSQL * STDCALL
-mc_mysql_init(MYSQL *mysql)
+MYSQL *mc_mysql_init(MYSQL *mysql)
{
init_client_errs();
if (!mysql)
@@ -210,7 +216,7 @@ mc_mysql_init(MYSQL *mysql)
** Shut down connection
**************************************************************************/
-static void
+void
mc_end_server(MYSQL *mysql)
{
DBUG_ENTER("mc_end_server");
@@ -332,11 +338,11 @@ static int mc_sock_connect(my_socket s, const struct sockaddr *name,
** or packet is an error message
*****************************************************************************/
-uint STDCALL
+ulong
mc_net_safe_read(MYSQL *mysql)
{
NET *net= &mysql->net;
- uint len=0;
+ ulong len=0;
if (net->vio != 0)
len=my_net_read(net);
@@ -393,17 +399,17 @@ max_allowed_packet on this server");
}
-char * STDCALL mc_mysql_error(MYSQL *mysql)
+char *mc_mysql_error(MYSQL *mysql)
{
return (mysql)->net.last_error;
}
-int STDCALL mc_mysql_errno(MYSQL *mysql)
+int mc_mysql_errno(MYSQL *mysql)
{
return (mysql)->net.last_errno;
}
-my_bool STDCALL mc_mysql_reconnect(MYSQL *mysql)
+my_bool mc_mysql_reconnect(MYSQL *mysql)
{
MYSQL tmp_mysql;
DBUG_ENTER("mc_mysql_reconnect");
@@ -433,7 +439,7 @@ my_bool STDCALL mc_mysql_reconnect(MYSQL *mysql)
-int STDCALL
+int
mc_simple_command(MYSQL *mysql,enum enum_server_command command,
const char *arg, uint length, my_bool skipp_check)
{
@@ -486,7 +492,7 @@ mc_simple_command(MYSQL *mysql,enum enum_server_command command,
}
-MYSQL * STDCALL
+MYSQL *
mc_mysql_connect(MYSQL *mysql,const char *host, const char *user,
const char *passwd, const char *db,
uint port, const char *unix_socket,uint client_flag)
@@ -495,7 +501,7 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user,
my_socket sock;
ulong ip_addr;
struct sockaddr_in sock_addr;
- uint pkt_length;
+ ulong pkt_length;
NET *net= &mysql->net;
thr_alarm_t alarmed;
ALARM alarm_buff;
@@ -761,6 +767,20 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user,
mysql->client_flag=client_flag;
#ifdef HAVE_OPENSSL
+ if ((mysql->server_capabilities & CLIENT_SSL) &&
+ (mysql->options.use_ssl || (client_flag & CLIENT_SSL)))
+ {
+ DBUG_PRINT("info", ("Changing IO layer to SSL"));
+ client_flag |= CLIENT_SSL;
+ }
+ else
+ {
+ if (client_flag & CLIENT_SSL)
+ {
+ DBUG_PRINT("info", ("Leaving IO layer intact because server doesn't support SSL"));
+ }
+ client_flag &= ~CLIENT_SSL;
+ }
/* Oops.. are we careful enough to not send ANY information */
/* without encryption? */
if (client_flag & CLIENT_SSL)
@@ -769,15 +789,14 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user,
goto error;
/* Do the SSL layering. */
DBUG_PRINT("info", ("IO layer change in progress..."));
- VioSSLConnectorFd* connector_fd = (VioSSLConnectorFd*)
- (mysql->connector_fd);
- VioSocket* vio_socket = (VioSocket*)(mysql->net.vio);
- VioSSL* vio_ssl = connector_fd->connect(vio_socket);
- mysql->net.vio = (NetVio*)(vio_ssl);
+ DBUG_PRINT("info", ("IO context %p",((struct st_VioSSLConnectorFd*)mysql->connector_fd)->ssl_context_));
+ sslconnect((struct st_VioSSLConnectorFd*)(mysql->connector_fd),mysql->net.vio,60L);
+ DBUG_PRINT("info", ("IO layer change done!"));
}
#endif /* HAVE_OPENSSL */
-
int3store(buff+2,max_allowed_packet);
+
+
if (user && user[0])
strmake(buff+5,user,32);
else
@@ -816,12 +835,38 @@ error:
DBUG_RETURN(0);
}
+
+#ifdef HAVE_OPENSSL
+/*
+**************************************************************************
+** Free strings in the SSL structure and clear 'use_ssl' flag.
+** NB! Errors are not reported until you do mysql_real_connect.
+**************************************************************************
+*/
+int
+mysql_ssl_clear(MYSQL *mysql)
+{
+ my_free(mysql->options.ssl_key, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.ssl_cert, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.ssl_ca, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.ssl_capath, MYF(MY_ALLOW_ZERO_PTR));
+ mysql->options.ssl_key = 0;
+ mysql->options.ssl_cert = 0;
+ mysql->options.ssl_ca = 0;
+ mysql->options.ssl_capath = 0;
+ mysql->options.use_ssl = FALSE;
+ my_free(mysql->connector_fd,MYF(MY_ALLOW_ZERO_PTR));
+ mysql->connector_fd = 0;
+ return 0;
+}
+#endif /* HAVE_OPENSSL */
+
/*************************************************************************
** Send a QUIT to the server and close the connection
** If handle is alloced by mysql connect free it.
*************************************************************************/
-void STDCALL
+void
mc_mysql_close(MYSQL *mysql)
{
DBUG_ENTER("mysql_close");
@@ -844,11 +889,502 @@ mc_mysql_close(MYSQL *mysql)
bzero((char*) &mysql->options,sizeof(mysql->options));
mysql->net.vio = 0;
#ifdef HAVE_OPENSSL
- ((VioConnectorFd*)(mysql->connector_fd))->delete();
- mysql->connector_fd = 0;
+ mysql_ssl_clear(mysql);
#endif /* HAVE_OPENSSL */
if (mysql->free_me)
my_free((gptr) mysql,MYF(0));
}
DBUG_VOID_RETURN;
}
+
+void mc_mysql_free_result(MYSQL_RES *result)
+{
+ DBUG_ENTER("mc_mysql_free_result");
+ DBUG_PRINT("enter",("mysql_res: %lx",result));
+ if (result)
+ {
+ if (result->handle && result->handle->status == MYSQL_STATUS_USE_RESULT)
+ {
+ DBUG_PRINT("warning",("Not all rows in set were read; Ignoring rows"));
+ for (;;)
+ {
+ ulong pkt_len;
+ if ((pkt_len=mc_net_safe_read(result->handle)) == packet_error)
+ break;
+ if (pkt_len == 1 && result->handle->net.read_pos[0] == 254)
+ break; /* End of data */
+ }
+ result->handle->status=MYSQL_STATUS_READY;
+ }
+ mc_free_rows(result->data);
+ if (result->fields)
+ free_root(&result->field_alloc,MYF(0));
+ if (result->row)
+ my_free((gptr) result->row,MYF(0));
+ my_free((gptr) result,MYF(0));
+ }
+ DBUG_VOID_RETURN;
+}
+
+static void mc_free_rows(MYSQL_DATA *cur)
+{
+ if (cur)
+ {
+ free_root(&cur->alloc,MYF(0));
+ my_free((gptr) cur,MYF(0));
+ }
+}
+
+static MYSQL_FIELD *
+mc_unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields,
+ my_bool default_value, my_bool long_flag_protocol)
+{
+ MYSQL_ROWS *row;
+ MYSQL_FIELD *field,*result;
+ DBUG_ENTER("unpack_fields");
+
+ field=result=(MYSQL_FIELD*) alloc_root(alloc,sizeof(MYSQL_FIELD)*fields);
+ if (!result)
+ DBUG_RETURN(0);
+
+ for (row=data->data; row ; row = row->next,field++)
+ {
+ field->table= strdup_root(alloc,(char*) row->data[0]);
+ field->name= strdup_root(alloc,(char*) row->data[1]);
+ field->length= (uint) uint3korr(row->data[2]);
+ field->type= (enum enum_field_types) (uchar) row->data[3][0];
+ if (long_flag_protocol)
+ {
+ field->flags= uint2korr(row->data[4]);
+ field->decimals=(uint) (uchar) row->data[4][2];
+ }
+ else
+ {
+ field->flags= (uint) (uchar) row->data[4][0];
+ field->decimals=(uint) (uchar) row->data[4][1];
+ }
+ if (INTERNAL_NUM_FIELD(field))
+ field->flags|= NUM_FLAG;
+ if (default_value && row->data[5])
+ field->def=strdup_root(alloc,(char*) row->data[5]);
+ else
+ field->def=0;
+ field->max_length= 0;
+ }
+ mc_free_rows(data); /* Free old data */
+ DBUG_RETURN(result);
+}
+
+int
+mc_mysql_send_query(MYSQL* mysql, const char* query, uint length)
+{
+ return mc_simple_command(mysql, COM_QUERY, query, length, 1);
+}
+
+int mc_mysql_read_query_result(MYSQL *mysql)
+{
+ uchar *pos;
+ ulong field_count;
+ MYSQL_DATA *fields;
+ ulong length;
+ DBUG_ENTER("mc_mysql_read_query_result");
+
+ if ((length = mc_net_safe_read(mysql)) == packet_error)
+ DBUG_RETURN(-1);
+ mc_free_old_query(mysql); /* Free old result */
+get_info:
+ pos=(uchar*) mysql->net.read_pos;
+ if ((field_count= mc_net_field_length(&pos)) == 0)
+ {
+ mysql->affected_rows= mc_net_field_length_ll(&pos);
+ mysql->insert_id= mc_net_field_length_ll(&pos);
+ if (mysql->server_capabilities & CLIENT_TRANSACTIONS)
+ {
+ mysql->server_status=uint2korr(pos); pos+=2;
+ }
+ if (pos < mysql->net.read_pos+length && mc_net_field_length(&pos))
+ mysql->info=(char*) pos;
+ DBUG_RETURN(0);
+ }
+ if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */
+ {
+ int error=mc_send_file_to_server(mysql,(char*) pos);
+ if ((length=mc_net_safe_read(mysql)) == packet_error || error)
+ DBUG_RETURN(-1);
+ goto get_info; /* Get info packet */
+ }
+ if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
+ mysql->server_status|= SERVER_STATUS_IN_TRANS;
+
+ mysql->extra_info= mc_net_field_length_ll(&pos); /* Maybe number of rec */
+ if (!(fields=mc_read_rows(mysql,(MYSQL_FIELD*) 0,5)))
+ DBUG_RETURN(-1);
+ if (!(mysql->fields=mc_unpack_fields(fields,&mysql->field_alloc,
+ (uint) field_count,0,
+ (my_bool) test(mysql->server_capabilities &
+ CLIENT_LONG_FLAG))))
+ DBUG_RETURN(-1);
+ mysql->status=MYSQL_STATUS_GET_RESULT;
+ mysql->field_count=field_count;
+ DBUG_RETURN(0);
+}
+
+int mc_mysql_query(MYSQL *mysql, const char *query, uint length)
+{
+ DBUG_ENTER("mysql_real_query");
+ DBUG_PRINT("enter",("handle: %lx",mysql));
+ DBUG_PRINT("query",("Query = \"%s\"",query));
+ if (!length)
+ length = strlen(query);
+ if (mc_simple_command(mysql,COM_QUERY,query,length,1))
+ DBUG_RETURN(-1);
+ DBUG_RETURN(mc_mysql_read_query_result(mysql));
+}
+
+static int mc_send_file_to_server(MYSQL *mysql, const char *filename)
+{
+ int fd, readcount, result= -1;
+ uint packet_length=MY_ALIGN(mysql->net.max_packet-16,IO_SIZE);
+ char *buf, tmp_name[FN_REFLEN];
+ DBUG_ENTER("send_file_to_server");
+
+ if (!(buf=my_malloc(packet_length,MYF(0))))
+ {
+ strmov(mysql->net.last_error, ER(mysql->net.last_errno=CR_OUT_OF_MEMORY));
+ DBUG_RETURN(-1);
+ }
+
+ fn_format(tmp_name,filename,"","",4); /* Convert to client format */
+ if ((fd = my_open(tmp_name,O_RDONLY, MYF(0))) < 0)
+ {
+ my_net_write(&mysql->net,"",0); // Server needs one packet
+ net_flush(&mysql->net);
+ mysql->net.last_errno=EE_FILENOTFOUND;
+ my_snprintf(mysql->net.last_error,sizeof(mysql->net.last_error)-1,
+ EE(mysql->net.last_errno),tmp_name, errno);
+ goto err;
+ }
+
+ while ((readcount = (int) my_read(fd,(byte*) buf,packet_length,MYF(0))) > 0)
+ {
+ if (my_net_write(&mysql->net,buf,readcount))
+ {
+ DBUG_PRINT("error",("Lost connection to MySQL server during LOAD DATA of local file"));
+ mysql->net.last_errno=CR_SERVER_LOST;
+ strmov(mysql->net.last_error,ER(mysql->net.last_errno));
+ goto err;
+ }
+ }
+ /* Send empty packet to mark end of file */
+ if (my_net_write(&mysql->net,"",0) || net_flush(&mysql->net))
+ {
+ mysql->net.last_errno=CR_SERVER_LOST;
+ sprintf(mysql->net.last_error,ER(mysql->net.last_errno),errno);
+ goto err;
+ }
+ if (readcount < 0)
+ {
+ mysql->net.last_errno=EE_READ; /* the errmsg for not entire file read */
+ my_snprintf(mysql->net.last_error,sizeof(mysql->net.last_error)-1,
+ tmp_name,errno);
+ goto err;
+ }
+ result=0; // Ok
+
+err:
+ if (fd >= 0)
+ (void) my_close(fd,MYF(0));
+ my_free(buf,MYF(0));
+ DBUG_RETURN(result);
+}
+
+
+/* Get the length of next field. Change parameter to point at fieldstart */
+static ulong mc_net_field_length(uchar **packet)
+{
+ reg1 uchar *pos= *packet;
+ if (*pos < 251)
+ {
+ (*packet)++;
+ return (ulong) *pos;
+ }
+ if (*pos == 251)
+ {
+ (*packet)++;
+ return NULL_LENGTH;
+ }
+ if (*pos == 252)
+ {
+ (*packet)+=3;
+ return (ulong) uint2korr(pos+1);
+ }
+ if (*pos == 253)
+ {
+ (*packet)+=4;
+ return (ulong) uint3korr(pos+1);
+ }
+ (*packet)+=9; /* Must be 254 when here */
+ return (ulong) uint4korr(pos+1);
+}
+
+/* Same as above, but returns ulonglong values */
+
+static my_ulonglong mc_net_field_length_ll(uchar **packet)
+{
+ reg1 uchar *pos= *packet;
+ if (*pos < 251)
+ {
+ (*packet)++;
+ return (my_ulonglong) *pos;
+ }
+ if (*pos == 251)
+ {
+ (*packet)++;
+ return (my_ulonglong) NULL_LENGTH;
+ }
+ if (*pos == 252)
+ {
+ (*packet)+=3;
+ return (my_ulonglong) uint2korr(pos+1);
+ }
+ if (*pos == 253)
+ {
+ (*packet)+=4;
+ return (my_ulonglong) uint3korr(pos+1);
+ }
+ (*packet)+=9; /* Must be 254 when here */
+#ifdef NO_CLIENT_LONGLONG
+ return (my_ulonglong) uint4korr(pos+1);
+#else
+ return (my_ulonglong) uint8korr(pos+1);
+#endif
+}
+
+/* Read all rows (fields or data) from server */
+
+static MYSQL_DATA *mc_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
+ uint fields)
+{
+ uint field;
+ ulong pkt_len;
+ ulong len;
+ uchar *cp;
+ char *to;
+ MYSQL_DATA *result;
+ MYSQL_ROWS **prev_ptr,*cur;
+ NET *net = &mysql->net;
+ DBUG_ENTER("mc_read_rows");
+
+ if ((pkt_len=mc_net_safe_read(mysql)) == packet_error)
+ DBUG_RETURN(0);
+ if (!(result=(MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA),
+ MYF(MY_ZEROFILL))))
+ {
+ net->last_errno=CR_OUT_OF_MEMORY;
+ strmov(net->last_error,ER(net->last_errno));
+ DBUG_RETURN(0);
+ }
+ init_alloc_root(&result->alloc,8192,0); /* Assume rowlength < 8192 */
+ result->alloc.min_malloc=sizeof(MYSQL_ROWS);
+ prev_ptr= &result->data;
+ result->rows=0;
+ result->fields=fields;
+
+ while (*(cp=net->read_pos) != 254 || pkt_len != 1)
+ {
+ result->rows++;
+ if (!(cur= (MYSQL_ROWS*) alloc_root(&result->alloc,
+ sizeof(MYSQL_ROWS))) ||
+ !(cur->data= ((MYSQL_ROW)
+ alloc_root(&result->alloc,
+ (fields+1)*sizeof(char *)+pkt_len))))
+ {
+ mc_free_rows(result);
+ net->last_errno=CR_OUT_OF_MEMORY;
+ strmov(net->last_error,ER(net->last_errno));
+ DBUG_RETURN(0);
+ }
+ *prev_ptr=cur;
+ prev_ptr= &cur->next;
+ to= (char*) (cur->data+fields+1);
+ for (field=0 ; field < fields ; field++)
+ {
+ if ((len=(ulong) mc_net_field_length(&cp)) == NULL_LENGTH)
+ { /* null field */
+ cur->data[field] = 0;
+ }
+ else
+ {
+ cur->data[field] = to;
+ memcpy(to,(char*) cp,len); to[len]=0;
+ to+=len+1;
+ cp+=len;
+ if (mysql_fields)
+ {
+ if (mysql_fields[field].max_length < len)
+ mysql_fields[field].max_length=len;
+ }
+ }
+ }
+ cur->data[field]=to; /* End of last field */
+ if ((pkt_len=mc_net_safe_read(mysql)) == packet_error)
+ {
+ mc_free_rows(result);
+ DBUG_RETURN(0);
+ }
+ }
+ *prev_ptr=0; /* last pointer is null */
+ DBUG_PRINT("exit",("Got %d rows",result->rows));
+ DBUG_RETURN(result);
+}
+
+
+/*
+** Read one row. Uses packet buffer as storage for fields.
+** When next packet is read, the previous field values are destroyed
+*/
+
+
+static int mc_read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row,
+ ulong *lengths)
+{
+ uint field;
+ ulong pkt_len,len;
+ uchar *pos,*prev_pos;
+
+ if ((pkt_len=mc_net_safe_read(mysql)) == packet_error)
+ return -1;
+ if (pkt_len == 1 && mysql->net.read_pos[0] == 254)
+ return 1; /* End of data */
+ prev_pos= 0; /* allowed to write at packet[-1] */
+ pos=mysql->net.read_pos;
+ for (field=0 ; field < fields ; field++)
+ {
+ if ((len=(ulong) mc_net_field_length(&pos)) == NULL_LENGTH)
+ { /* null field */
+ row[field] = 0;
+ *lengths++=0;
+ }
+ else
+ {
+ row[field] = (char*) pos;
+ pos+=len;
+ *lengths++=len;
+ }
+ if (prev_pos)
+ *prev_pos=0; /* Terminate prev field */
+ prev_pos=pos;
+ }
+ row[field]=(char*) prev_pos+1; /* End of last field */
+ *prev_pos=0; /* Terminate last field */
+ return 0;
+}
+
+my_ulonglong mc_mysql_num_rows(MYSQL_RES *res)
+{
+ return res->row_count;
+}
+
+unsigned int mc_mysql_num_fields(MYSQL_RES *res)
+{
+ return res->field_count;
+}
+
+void mc_mysql_data_seek(MYSQL_RES *result, my_ulonglong row)
+{
+ MYSQL_ROWS *tmp=0;
+ DBUG_PRINT("info",("mysql_data_seek(%ld)",(long) row));
+ if (result->data)
+ for (tmp=result->data->data; row-- && tmp ; tmp = tmp->next) ;
+ result->current_row=0;
+ result->data_cursor = tmp;
+}
+
+MYSQL_ROW STDCALL mc_mysql_fetch_row(MYSQL_RES *res)
+{
+ DBUG_ENTER("mc_mysql_fetch_row");
+ if (!res->data)
+ { /* Unbufferred fetch */
+ if (!res->eof)
+ {
+ if (!(mc_read_one_row(res->handle,res->field_count,res->row,
+ res->lengths)))
+ {
+ res->row_count++;
+ DBUG_RETURN(res->current_row=res->row);
+ }
+ else
+ {
+ DBUG_PRINT("info",("end of data"));
+ res->eof=1;
+ res->handle->status=MYSQL_STATUS_READY;
+ }
+ }
+ DBUG_RETURN((MYSQL_ROW) NULL);
+ }
+ {
+ MYSQL_ROW tmp;
+ if (!res->data_cursor)
+ {
+ DBUG_PRINT("info",("end of data"));
+ DBUG_RETURN(res->current_row=(MYSQL_ROW) NULL);
+ }
+ tmp = res->data_cursor->data;
+ res->data_cursor = res->data_cursor->next;
+ DBUG_RETURN(res->current_row=tmp);
+ }
+}
+
+int mc_mysql_select_db(MYSQL *mysql, const char *db)
+{
+ int error;
+ DBUG_ENTER("mysql_select_db");
+ DBUG_PRINT("enter",("db: '%s'",db));
+
+ if ((error=mc_simple_command(mysql,COM_INIT_DB,db,(uint) strlen(db),0)))
+ DBUG_RETURN(error);
+ my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR));
+ mysql->db=my_strdup(db,MYF(MY_WME));
+ DBUG_RETURN(0);
+}
+
+
+MYSQL_RES *mc_mysql_store_result(MYSQL *mysql)
+{
+ MYSQL_RES *result;
+ DBUG_ENTER("mysql_store_result");
+
+ if (!mysql->fields)
+ DBUG_RETURN(0);
+ if (mysql->status != MYSQL_STATUS_GET_RESULT)
+ {
+ strmov(mysql->net.last_error,
+ ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC));
+ DBUG_RETURN(0);
+ }
+ mysql->status=MYSQL_STATUS_READY; /* server is ready */
+ if (!(result=(MYSQL_RES*) my_malloc(sizeof(MYSQL_RES)+
+ sizeof(ulong)*mysql->field_count,
+ MYF(MY_ZEROFILL))))
+ {
+ mysql->net.last_errno=CR_OUT_OF_MEMORY;
+ strmov(mysql->net.last_error, ER(mysql->net.last_errno));
+ DBUG_RETURN(0);
+ }
+ result->eof=1; /* Marker for buffered */
+ result->lengths=(ulong*) (result+1);
+ if (!(result->data=mc_read_rows(mysql,mysql->fields,mysql->field_count)))
+ {
+ my_free((gptr) result,MYF(0));
+ DBUG_RETURN(0);
+ }
+ mysql->affected_rows= result->row_count= result->data->rows;
+ result->data_cursor= result->data->data;
+ result->fields= mysql->fields;
+ result->field_alloc= mysql->field_alloc;
+ result->field_count= mysql->field_count;
+ result->current_field=0;
+ result->current_row=0; /* Must do a fetch first */
+ mysql->fields=0; /* fields is now in result */
+ DBUG_RETURN(result); /* Data fetched */
+}
diff --git a/sql/mini_client.h b/sql/mini_client.h
index f7d95a1b66e..6721b072080 100644
--- a/sql/mini_client.h
+++ b/sql/mini_client.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 */
@@ -18,30 +18,34 @@
#define _MINI_CLIENT_H
-MYSQL* STDCALL
-mc_mysql_connect(MYSQL *mysql,const char *host, const char *user,
+MYSQL* mc_mysql_connect(MYSQL *mysql,const char *host, const char *user,
const char *passwd, const char *db,
uint port, const char *unix_socket,uint client_flag);
-int STDCALL
-mc_simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg,
+int mc_simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg,
uint length, my_bool skipp_check);
-void STDCALL
-mc_mysql_close(MYSQL *mysql);
+void mc_mysql_close(MYSQL *mysql);
-MYSQL * STDCALL
-mc_mysql_init(MYSQL *mysql);
+MYSQL * mc_mysql_init(MYSQL *mysql);
-void STDCALL
-mc_mysql_debug(const char *debug);
+void mc_mysql_debug(const char *debug);
-uint STDCALL
-mc_net_safe_read(MYSQL *mysql);
+ulong mc_net_safe_read(MYSQL *mysql);
-char * STDCALL mc_mysql_error(MYSQL *mysql);
-int STDCALL mc_mysql_errno(MYSQL *mysql);
-my_bool STDCALL mc_mysql_reconnect(MYSQL* mysql);
+char * mc_mysql_error(MYSQL *mysql);
+int mc_mysql_errno(MYSQL *mysql);
+my_bool mc_mysql_reconnect(MYSQL* mysql);
+int mc_mysql_send_query(MYSQL* mysql, const char* query, uint length);
+int mc_mysql_read_query_result(MYSQL *mysql);
+int mc_mysql_query(MYSQL *mysql, const char *query, uint length);
+MYSQL_RES * mc_mysql_store_result(MYSQL *mysql);
+void mc_mysql_free_result(MYSQL_RES *result);
+void mc_mysql_data_seek(MYSQL_RES *result, my_ulonglong row);
+my_ulonglong mc_mysql_num_rows(MYSQL_RES *res);
+unsigned int mc_mysql_num_fields(MYSQL_RES *res);
+MYSQL_ROW STDCALL mc_mysql_fetch_row(MYSQL_RES *res);
+int mc_mysql_select_db(MYSQL *mysql, const char *db);
+void mc_end_server(MYSQL *mysql);
#endif
-
diff --git a/sql/my_lock.c b/sql/my_lock.c
index 647c07a03c3..4d451fcff22 100644
--- a/sql/my_lock.c
+++ b/sql/my_lock.c
@@ -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 */
@@ -19,7 +19,7 @@
#else
#undef MAP_TO_USE_RAID /* Avoid RAID mappings */
-#include <global.h>
+#include <my_global.h>
#include <my_sys.h>
#include <mysys_err.h>
#include <my_pthread.h>
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 657ca3274cd..924f85b0a89 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -17,16 +17,16 @@
#ifndef _MYSQL_PRIV_H
#define _MYSQL_PRIV_H
-#include <global.h>
+#include <my_global.h>
+#include "mysql_embed.h"
#include <my_sys.h>
#include <m_string.h>
-#include "mysql_version.h"
+#include <mysql_version.h>
#include <hash.h>
#include <signal.h>
#include <thr_lock.h>
#include <my_base.h> /* Needed by field.h */
#include <my_bitmap.h>
-#include <violite.h>
#ifdef __EMX__
#undef write // remove pthread.h macro definition for EMX
@@ -37,6 +37,7 @@ typedef ulong key_map; /* Used for finding keys */
typedef ulong key_part_map; /* Used for finding key parts */
#include "mysql_com.h"
+#include <violite.h>
#include "unireg.h"
void init_sql_alloc(MEM_ROOT *root, uint block_size, uint pre_alloc_size);
@@ -47,6 +48,8 @@ char *sql_strmake(const char *str,uint len);
gptr sql_memdup(const void * ptr,unsigned size);
void sql_element_free(void *ptr);
void kill_one_thread(THD *thd, ulong id);
+int net_request_file(NET* net, const char* fname);
+char* query_table_status(THD *thd,const char *db,const char *table_name);
#define x_free(A) { my_free((gptr) (A),MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR)); }
#define safeFree(x) { if(x) { my_free((gptr) x,MYF(0)); x = NULL; } }
@@ -69,7 +72,6 @@ void kill_one_thread(THD *thd, ulong id);
#define HASH_PASSWORD_LENGTH 16
#define HOST_CACHE_SIZE 128
#define MAX_ACCEPT_RETRY 10 // Test accept this many times
-#define MAX_BLOB_WIDTH 8192 // Default width for blob
#define MAX_FIELDS_BEFORE_HASH 32
#define USER_VARS_HASH_SIZE 16
#define STACK_MIN_SIZE 8192 // Abort if less stack during eval.
@@ -147,9 +149,9 @@ void kill_one_thread(THD *thd, ulong id);
#define SELECT_DESCRIBE 4
#define SELECT_SMALL_RESULT 8
#define SELECT_BIG_RESULT 16
-#define SELECT_HIGH_PRIORITY 64 /* Intern */
-#define SELECT_USE_CACHE 256 /* Intern */
-#define SELECT_COUNT_DISTINCT 512 /* Intern */
+#define OPTION_FOUND_ROWS 32
+#define OPTION_TO_QUERY_CACHE 64
+#define SELECT_NO_JOIN_CACHE 256 /* Intern */
#define OPTION_BIG_TABLES 512 /* for SQL OPTION */
#define OPTION_BIG_SELECTS 1024 /* for SQL OPTION */
@@ -176,16 +178,33 @@ void kill_one_thread(THD *thd, ulong id);
#define QUERY_NO_INDEX_USED OPTION_STATUS_NO_TRANS_UPDATE*2
#define QUERY_NO_GOOD_INDEX_USED QUERY_NO_INDEX_USED*2
+#define SELECT_NO_UNLOCK (QUERY_NO_GOOD_INDEX_USED*2)
+#define TMP_TABLE_ALL_COLUMNS (SELECT_NO_UNLOCK*2)
+
/* Bits for different SQL modes modes (including ANSI mode) */
-#define MODE_REAL_AS_FLOAT 1
-#define MODE_PIPES_AS_CONCAT 2
-#define MODE_ANSI_QUOTES 4
-#define MODE_IGNORE_SPACE 8
-#define MODE_SERIALIZABLE 16
-#define MODE_ONLY_FULL_GROUP_BY 32
+#define MODE_REAL_AS_FLOAT 1
+#define MODE_PIPES_AS_CONCAT 2
+#define MODE_ANSI_QUOTES 4
+#define MODE_IGNORE_SPACE 8
+#define MODE_SERIALIZABLE 16
+#define MODE_ONLY_FULL_GROUP_BY 32
+#define MODE_NO_UNSIGNED_SUBTRACTION 64
#define RAID_BLOCK_SIZE 1024
+// Sync points allow us to force the server to reach a certain line of code
+// and block there until the client tells the server it is ok to go on.
+// The client tells the server to block with SELECT GET_LOCK()
+// and unblocks it with SELECT RELEASE_LOCK(). Used for debugging difficult
+// concurrency problems
+#ifdef EXTRA_DEBUG
+#define DBUG_SYNC_POINT(lock_name,lock_timeout) \
+ debug_sync_point(lock_name,lock_timeout)
+void debug_sync_point(const char* lock_name, uint lock_timeout);
+#else
+#define DBUG_SYNC_POINT(lock_name,lock_timeout)
+#endif
+
/* BINLOG_DUMP options */
#define BINLOG_DUMP_NON_BLOCK 1
@@ -232,17 +251,22 @@ inline THD *_current_thd(void)
#include "item.h"
#include "sql_class.h"
#include "opt_range.h"
+#include "sql_cache.h"
-
-void mysql_create_db(THD *thd, char *db, uint create_info);
+int mysql_create_db(THD *thd, char *db, uint create_info, bool silent);
+int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent);
void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags);
int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists);
+int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
+ bool log_query);
int quick_rm_table(enum db_type base,const char *db,
const char *table_name);
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);
void mysql_init_select(LEX *lex);
+bool mysql_new_select(LEX *lex);
+void mysql_init_multi_delete(LEX *lex);
void init_max_user_conn(void);
void free_max_user_conn(void);
pthread_handler_decl(handle_one_connection,arg);
@@ -252,23 +276,21 @@ void end_thread(THD *thd,bool put_in_cache);
void flush_thread_cache();
void mysql_execute_command(void);
bool do_command(THD *thd);
+bool dispatch_command(enum enum_server_command command, THD *thd,
+ char* packet, uint packet_length);
bool check_stack_overrun(THD *thd,char *dummy);
-bool reload_acl_and_cache(THD *thd, uint options, TABLE_LIST *tables);
-void mysql_rm_db(THD *thd,char *db,bool if_exists);
+bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables);
void table_cache_init(void);
void table_cache_free(void);
uint cached_tables(void);
void kill_mysql(void);
void close_connection(NET *net,uint errcode=0,bool lock=1);
bool check_access(THD *thd,uint access,const char *db=0,uint *save_priv=0,
- bool no_grant=0);
-bool check_table_access(THD *thd,uint want_access,TABLE_LIST *tables);
+ bool no_grant=0, bool no_errors=0);
+bool check_table_access(THD *thd,uint want_access, TABLE_LIST *tables,
+ bool no_errors=0);
bool check_process_priv(THD *thd=0);
-int generate_table(THD *thd, TABLE_LIST *table_list,
- TABLE *locked_table);
-
-
int mysql_backup_table(THD* thd, TABLE_LIST* table_list);
int mysql_restore_table(THD* thd, TABLE_LIST* table_list);
@@ -282,7 +304,6 @@ int mysql_optimize_table(THD* thd, TABLE_LIST* table_list,
HA_CHECK_OPT* check_opt);
/* net_pkg.c */
-void send_error(NET *net,uint sql_errno=0, const char *err=0);
void send_warning(NET *net, uint sql_errno, const char *err=0);
void net_printf(NET *net,uint sql_errno, ...);
void send_ok(NET *net,ha_rows affected_rows=0L,ulonglong id=0L,
@@ -309,10 +330,12 @@ SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length);
int setup_order(THD *thd,TABLE_LIST *tables, List<Item> &fields,
List <Item> &all_fields, ORDER *order);
+int handle_select(THD *thd, LEX *lex, select_result *result);
int mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &list,COND *conds,
ORDER *order, ORDER *group,Item *having,ORDER *proc_param,
- uint select_type,select_result *result);
-Field *create_tmp_field(TABLE *table,Item *item, Item::Type type,
+ ulong select_type,select_result *result);
+int mysql_union(THD *thd,LEX *lex,select_result *result);
+Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item_result_field ***copy_func, Field **from_field,
bool group,bool modify_item);
int mysql_create_table(THD *thd,const char *db, const char *table_name,
@@ -336,7 +359,9 @@ int mysql_alter_table(THD *thd, char *new_db, char *new_name,
List<Alter_column> &alter_list,
ORDER *order,
bool drop_primary,
- enum enum_duplicates handle_duplicates);
+ enum enum_duplicates handle_duplicates,
+ enum enum_enable_or_disable keys_onoff=LEAVE_AS_IS,
+ bool simple_alter=0);
bool mysql_rename_table(enum db_type base,
const char *old_db,
const char * old_name,
@@ -347,15 +372,17 @@ int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys);
int mysql_drop_index(THD *thd, TABLE_LIST *table_list,
List<Alter_drop> &drop_list);
int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields,
- List<Item> &values,COND *conds, ha_rows limit,
+ List<Item> &values,COND *conds,
+ ORDER *order, ha_rows limit,
enum enum_duplicates handle_duplicates,
thr_lock_type lock_type);
int mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields,
List<List_item> &values, enum_duplicates flag,
thr_lock_type lock_type);
void kill_delayed_threads(void);
-int mysql_delete(THD *thd,TABLE_LIST *table,COND *conds,ha_rows rows,
- thr_lock_type lock_type, ulong options);
+int mysql_delete(THD *thd, TABLE_LIST *table, COND *conds, ORDER *order,
+ ha_rows rows, thr_lock_type lock_type, ulong options);
+int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok=0);
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,
bool *refresh);
@@ -373,13 +400,28 @@ void abort_locked_tables(THD *thd,const char *db, const char *table_name);
Field *find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables);
Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
bool check_grant,bool allow_rowid);
+#ifdef HAVE_OPENSSL
+struct st_des_keyblock
+{
+ des_cblock key1, key2, key3;
+};
+struct st_des_keyschedule
+{
+ des_key_schedule ks1, ks2, ks3;
+};
+extern char *des_key_file;
+extern struct st_des_keyschedule des_keyschedule[10];
+extern uint des_default_key;
+extern pthread_mutex_t LOCK_des_key_file;
+bool load_des_key_file(const char *file_name);
+#endif /* HAVE_OPENSSL */
/* sql_do.cc */
int mysql_do(THD *thd, List<Item> &values);
/* sql_list.c */
int mysqld_show_dbs(THD *thd,const char *wild);
-int mysqld_show_open_tables(THD *thd,const char *db,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,
@@ -395,6 +437,12 @@ 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);
+/* sql_handler.cc */
+int mysql_ha_open(THD *thd, TABLE_LIST *tables);
+int mysql_ha_close(THD *thd, TABLE_LIST *tables, bool dont_send_ok=0);
+int mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *,
+ List<Item> *,enum ha_rkey_function,Item *,ha_rows,ha_rows);
+
/* sql_base.cc */
void set_item_name(Item *item,char *pos,uint length);
bool add_field_to_list(char *field_name, enum enum_field_types type,
@@ -416,9 +464,13 @@ 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);
Item ** find_item_in_list(Item *item,List<Item> &items);
+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);
int setup_fields(THD *thd,TABLE_LIST *tables,List<Item> &item,
- bool set_query_id,List<Item> *sum_func_list);
+ bool set_query_id,List<Item> *sum_func_list,
+ bool allow_sum_func);
int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds);
int setup_ftfuncs(THD *thd);
int init_ftfuncs(THD *thd, bool no_order);
@@ -433,6 +485,7 @@ bool send_fields(THD *thd,List<Item> &item,uint send_field_count);
void free_io_cache(TABLE *entry);
void intern_close_table(TABLE *entry);
void close_thread_tables(THD *thd,bool locked=0);
+bool close_thread_table(THD *thd, TABLE **table_ptr);
void close_temporary_tables(THD *thd);
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);
@@ -447,8 +500,7 @@ 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);
int fill_record(Field **field,List<Item> &values);
-int list_open_tables(THD *thd,List<char> *files, const char *db,const char *wild);
-char* query_table_status(THD *thd,const char *db,const char *table_name);
+OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild);
/* sql_calc.cc */
bool eval_const_cond(COND *cond);
@@ -463,7 +515,7 @@ int write_record(TABLE *table,COPY_INFO *info);
/* bits set in manager_status */
#define MANAGER_BERKELEY_LOG_CLEANUP (1L << 0)
extern ulong volatile manager_status;
-extern bool volatile manager_thread_in_use;
+extern bool volatile manager_thread_in_use, mqh_used;
extern pthread_t manager_thread;
extern pthread_mutex_t LOCK_manager;
extern pthread_cond_t COND_manager;
@@ -473,8 +525,7 @@ pthread_handler_decl(handle_manager, arg);
#ifndef DBUG_OFF
void print_where(COND *cond,const char *info);
void print_cached_tables(void);
-void TEST_filesort(TABLE **form,SORT_FIELD *sortorder,uint s_length,
- ha_rows special);
+void TEST_filesort(SORT_FIELD *sortorder,uint s_length, ha_rows special);
#endif
void mysql_print_status(THD *thd);
/* key.cc */
@@ -489,11 +540,17 @@ void init_errmessage(void);
void sql_perror(const char *message);
void sql_print_error(const char *format,...)
__attribute__ ((format (printf, 1, 2)));
+bool fn_format_relative_to_data_home(my_string to, const char *name,
+ const char *dir, const char *extension);
+void open_log(MYSQL_LOG *log, const char *hostname,
+ const char *opt_name, const char *extension,
+ enum_log_type type, bool read_append = 0,
+ bool no_auto_events = 0);
extern uint32 server_id;
-extern char mysql_data_home[2],server_version[SERVER_VERSION_LENGTH],
+extern char *mysql_data_home,server_version[SERVER_VERSION_LENGTH],
max_sort_char, mysql_real_data_home[];
-extern my_string mysql_unix_port,mysql_tmpdir;
+extern my_string mysql_tmpdir;
extern const char *first_keyword, *localhost, *delayed_user;
extern ulong refresh_version,flush_version, thread_id,query_id,opened_tables,
created_tmp_tables, created_tmp_disk_tables,
@@ -507,8 +564,9 @@ 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,
slave_open_temp_tables;
-extern uint test_flags,select_errors,mysql_port,ha_open_options;
+extern uint test_flags,select_errors,ha_open_options;
extern ulong thd_startup_options, slow_launch_threads, slow_launch_time;
+extern ulong query_cache_startup_type;
extern time_t start_time;
extern const char *command_name[];
extern I_List<THD> threads;
@@ -520,17 +578,18 @@ extern pthread_mutex_t LOCK_mysql_create_db,LOCK_Acl,LOCK_open,
LOCK_thread_count,LOCK_mapped_file,LOCK_user_locks, LOCK_status,
LOCK_grant, LOCK_error_log, LOCK_delayed_insert,
LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone,
- LOCK_binlog_update, LOCK_slave, LOCK_server_id;
-extern pthread_cond_t COND_refresh,COND_thread_count, COND_binlog_update,
- COND_slave_stopped, COND_slave_start;
+ LOCK_server_id, LOCK_slave_list, LOCK_active_mi;
+extern pthread_cond_t COND_refresh,COND_thread_count;
extern pthread_attr_t connection_attrib;
extern bool opt_endinfo, using_udf_functions, locked_in_memory,
- opt_using_transactions, use_temp_pool, opt_local_infile;
+ opt_using_transactions, use_temp_pool, mysql_embedded;
+extern bool opt_local_infile;
extern char f_fyllchar;
extern 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_read_rnd_count, ha_read_rnd_next_count;
+ ha_read_rnd_count, ha_read_rnd_next_count,
+ ha_commit_count, ha_rollback_count;
extern MY_BITMAP temp_pool;
extern uchar *days_in_month;
extern DATE_FORMAT dayord;
@@ -542,14 +601,15 @@ extern ulong keybuff_size,sortbuff_size,max_item_sort_length,table_cache_size,
max_insert_delayed_threads, max_user_connections,
long_query_count,net_wait_timeout,net_interactive_timeout,
net_read_timeout,net_write_timeout,
- what_to_log,flush_time, opt_sql_mode,
+ what_to_log,flush_time,opt_sql_mode,
max_tmp_tables,max_heap_table_size,query_buff_size,
lower_case_table_names,thread_stack,thread_stack_min,
binlog_cache_size, max_binlog_cache_size, record_rnd_cache_size;
extern ulong com_stat[(uint) SQLCOM_END], com_other;
extern ulong specialflag, current_pid;
-extern bool low_priority_updates, using_update_log,opt_warnings;
-extern bool opt_sql_bin_update, opt_safe_show_db, opt_safe_user_create;
+extern bool low_priority_updates, using_update_log;
+extern bool opt_sql_bin_update, opt_safe_show_db, opt_warnings,
+ opt_safe_user_create, opt_no_mix_types;
extern char language[LIBLEN],reg_ext[FN_EXTLEN],blob_newline;
extern const char **errmesg; /* Error messages */
extern const char *default_tx_isolation_name;
@@ -558,6 +618,7 @@ extern struct show_var_st init_vars[];
extern struct show_var_st status_vars[];
extern enum db_type default_table_type;
extern enum enum_tx_isolation default_tx_isolation;
+extern char glob_hostname[FN_REFLEN];
#ifndef __WIN__
extern pthread_t signal_thread;
@@ -573,8 +634,13 @@ void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count);
void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table);
void mysql_lock_abort(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);
+void start_waiting_global_read_lock(THD *thd);
/* Lock based on name */
+int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list);
int lock_table_name(THD *thd, TABLE_LIST *table_list);
void unlock_table_name(THD *thd, TABLE_LIST *table_list);
bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list);
@@ -617,7 +683,7 @@ void init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form,
SQL_SELECT *select,
int use_record_cache, bool print_errors);
void end_read_record(READ_RECORD *info);
-ha_rows filesort(TABLE **form,struct st_sort_field *sortorder, uint s_length,
+ha_rows filesort(TABLE *form,struct st_sort_field *sortorder, uint s_length,
SQL_SELECT *select, ha_rows special,ha_rows max_rows,
ha_rows *examined_rows);
void change_double_for_sort(double nr,byte *to);
@@ -659,7 +725,6 @@ void hostname_cache_refresh(void);
bool get_interval_info(const char *str,uint length,uint count,
long *values);
/* sql_cache */
-
extern bool sql_cache_init();
extern void sql_cache_free();
extern int sql_cache_hit(THD *thd, char *inBuf, uint length);
@@ -668,7 +733,7 @@ extern int sql_cache_hit(THD *thd, char *inBuf, uint length);
inline bool add_item_to_list(Item *item)
{
- return current_lex->item_list.push_back(item);
+ return current_lex->select->item_list.push_back(item);
}
inline bool add_value_to_list(Item *value)
{
@@ -676,11 +741,11 @@ inline bool add_value_to_list(Item *value)
}
inline bool add_order_to_list(Item *item,bool asc)
{
- return add_to_list(current_lex->order_list,item,asc);
+ return add_to_list(current_lex->select->order_list,item,asc);
}
inline bool add_group_to_list(Item *item,bool asc)
{
- return add_to_list(current_lex->group_list,item,asc);
+ return add_to_list(current_lex->select->group_list,item,asc);
}
inline void mark_as_null_row(TABLE *table)
{
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 1fb39e56840..8f0440ecc04 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -21,15 +21,13 @@
#include "sql_acl.h"
#include "slave.h"
#include "sql_repl.h"
+#include "repl_failsafe.h"
#include "stacktrace.h"
#ifdef HAVE_BERKELEY_DB
#include "ha_berkeley.h"
#endif
#ifdef HAVE_INNOBASE_DB
-#include "ha_innobase.h"
-#endif
-#ifdef HAVE_GEMINI_DB
-#include "ha_gemini.h"
+#include "ha_innodb.h"
#endif
#include "ha_myisam.h"
#include <nisam.h>
@@ -40,10 +38,16 @@
#define ONE_THREAD
#endif
+/* do stack traces are only supported on linux intel */
+#if defined(__linux__) && defined(__i386__) && defined(USE_PSTACK)
+#define HAVE_STACK_TRACE_ON_SEGV
+#include "../pstack/pstack.h"
+char pstack_file_name[80];
+#endif /* __linux__ */
+
#if defined(HAVE_DEC_3_2_THREADS) || defined(SIGNALS_DONT_BREAK_READ)
#define HAVE_CLOSE_SERVER_SOCK 1
-void close_server_sock();
-#endif
+#endif
extern "C" { // Because of SCO 3.2V4.2
#include <errno.h>
@@ -77,9 +81,7 @@ extern "C" { // Because of SCO 3.2V4.2
#include <sys/select.h>
#endif
#include <sys/utsname.h>
-#else
-#include <windows.h>
-#endif // __WIN__
+#endif /* __WIN__ */
#ifdef HAVE_LIBWRAP
#include <tcpd.h>
@@ -112,8 +114,13 @@ typedef fp_except fp_except_t;
inline void reset_floating_point_exceptions()
{
/* Don't fall for overflow, underflow,divide-by-zero or loss of precision */
- fpsetmask(~(FP_X_INV | FP_X_DNML | FP_X_OFL | FP_X_UFL |
- FP_X_DZ | FP_X_IMP));
+#if defined(__i386__)
+ fpsetmask(~(FP_X_INV | FP_X_DNML | FP_X_OFL | FP_X_UFL | FP_X_DZ |
+ FP_X_IMP));
+#else
+ fpsetmask(~(FP_X_INV | FP_X_OFL | FP_X_UFL | FP_X_DZ |
+ FP_X_IMP));
+#endif
}
#else
#define reset_floating_point_exceptions()
@@ -182,17 +189,12 @@ SHOW_COMP_OPTION have_berkeley_db=SHOW_OPTION_YES;
#else
SHOW_COMP_OPTION have_berkeley_db=SHOW_OPTION_NO;
#endif
-#ifdef HAVE_GEMINI_DB
-SHOW_COMP_OPTION have_gemini=SHOW_OPTION_YES;
-#else
-SHOW_COMP_OPTION have_gemini=SHOW_OPTION_NO;
-#endif
#ifdef HAVE_INNOBASE_DB
SHOW_COMP_OPTION have_innodb=SHOW_OPTION_YES;
#else
SHOW_COMP_OPTION have_innodb=SHOW_OPTION_NO;
#endif
-#ifndef NO_ISAM
+#ifdef HAVE_ISAM
SHOW_COMP_OPTION have_isam=SHOW_OPTION_YES;
#else
SHOW_COMP_OPTION have_isam=SHOW_OPTION_NO;
@@ -203,16 +205,19 @@ SHOW_COMP_OPTION have_raid=SHOW_OPTION_YES;
SHOW_COMP_OPTION have_raid=SHOW_OPTION_NO;
#endif
#ifdef HAVE_OPENSSL
-SHOW_COMP_OPTION have_ssl=SHOW_OPTION_YES;
+SHOW_COMP_OPTION have_openssl=SHOW_OPTION_YES;
#else
-SHOW_COMP_OPTION have_ssl=SHOW_OPTION_NO;
+SHOW_COMP_OPTION have_openssl=SHOW_OPTION_NO;
#endif
+SHOW_COMP_OPTION have_symlink=SHOW_OPTION_YES;
-static bool opt_skip_slave_start = 0; // if set, slave is not autostarted
+bool opt_skip_slave_start = 0; // If set, slave is not autostarted
+static bool opt_do_pstack = 0;
static ulong opt_specialflag=SPECIAL_ENGLISH;
-static my_socket unix_sock= INVALID_SOCKET,ip_sock= INVALID_SOCKET;
static ulong back_log,connect_timeout,concurrency;
+static ulong opt_myisam_block_size;
+static my_socket unix_sock= INVALID_SOCKET,ip_sock= INVALID_SOCKET;
static my_string opt_logname=0,opt_update_logname=0,
opt_binlog_index_name = 0,opt_slow_logname=0;
static char mysql_home[FN_REFLEN],pidfile_name[FN_REFLEN];
@@ -222,32 +227,30 @@ static bool opt_log,opt_update_log,opt_bin_log,opt_slow_log,opt_noacl,
opt_myisam_log=0,
opt_large_files=sizeof(my_off_t) > 4;
bool opt_sql_bin_update = 0, opt_log_slave_updates = 0, opt_safe_show_db=0,
- opt_safe_user_create=0;
+ opt_show_slave_auth_info = 0, opt_old_rpl_compat = 0,
+ opt_safe_user_create = 0, opt_no_mix_types = 0;
+volatile bool mqh_used = 0;
FILE *bootstrap_file=0;
int segfaulted = 0; // ensure we do not enter SIGSEGV handler twice
-extern MASTER_INFO glob_mi;
-extern int init_master_info(MASTER_INFO* mi);
-// if sql_bin_update is true, SQL_LOG_UPDATE and SQL_LOG_BIN are kept in sync,
-// and are treated as aliases for each other
+/*
+ If sql_bin_update is true, SQL_LOG_UPDATE and SQL_LOG_BIN are kept in sync,
+ and are treated as aliases for each other
+*/
static bool kill_in_progress=FALSE;
static struct rand_struct sql_rand;
static int cleanup_done;
static char **defaults_argv,time_zone[30];
static const char *default_table_type_name;
-static char glob_hostname[FN_REFLEN];
+char glob_hostname[FN_REFLEN];
+#include "sslopt-vars.h"
#ifdef HAVE_OPENSSL
-static bool opt_use_ssl = FALSE;
-static char *opt_ssl_key = 0;
-static char *opt_ssl_cert = 0;
-static char *opt_ssl_ca = 0;
-static char *opt_ssl_capath = 0;
-static VioSSLAcceptorFd* ssl_acceptor_fd = 0;
+char *des_key_file = 0;
+struct st_VioSSLAcceptorFd * ssl_acceptor_fd = 0;
#endif /* HAVE_OPENSSL */
-
I_List <i_string_pair> replicate_rewrite_db;
I_List<i_string> replicate_do_db, replicate_ignore_db;
// allow the user to tell us which db to replicate and which to ignore
@@ -258,9 +261,9 @@ uint32 server_id = 0;
bool server_id_supplied = 0;
uint mysql_port;
-uint test_flags, select_errors=0, dropping_tables=0,ha_open_options=0;
+uint test_flags = 0, select_errors=0, dropping_tables=0,ha_open_options=0;
uint volatile thread_count=0, thread_running=0, kill_cached_threads=0,
- wake_thread=0, global_read_lock=0;
+ wake_thread=0;
ulong thd_startup_options=(OPTION_UPDATE_LOG | OPTION_AUTO_IS_NULL |
OPTION_BIN_LOG | OPTION_QUOTE_SHOW_CREATE );
uint protocol_version=PROTOCOL_VERSION;
@@ -274,14 +277,21 @@ ulong keybuff_size,sortbuff_size,max_item_sort_length,table_cache_size,
ulong com_stat[(uint) SQLCOM_END], com_other;
ulong slave_net_timeout;
ulong thread_cache_size=0, binlog_cache_size=0, max_binlog_cache_size=0;
+ulong query_cache_size=0, query_cache_limit=0, query_cache_startup_type=1;
volatile ulong cached_thread_count=0;
// replication parameters, if master_host is not NULL, we are a slave
my_string master_user = (char*) "test", master_password = 0, master_host=0,
- master_info_file = (char*) "master.info";
+ master_info_file = (char*) "master.info",
+ relay_log_info_file = (char*) "relay-log.info",
+ master_ssl_key=0, master_ssl_cert=0;
+my_string report_user = 0, report_password = 0, report_host=0;
+
const char *localhost=LOCAL_HOST;
const char *delayed_user="DELAYED";
uint master_port = MYSQL_PORT, master_connect_retry = 60;
+uint report_port = MYSQL_PORT;
+bool master_ssl = 0;
ulong max_tmp_tables,max_heap_table_size,master_retry_count=0;
ulong bytes_sent = 0L, bytes_received = 0L;
@@ -309,11 +319,20 @@ ulong slow_launch_threads = 0;
ulong myisam_max_sort_file_size, myisam_max_extra_sort_file_size;
char mysql_real_data_home[FN_REFLEN],
- mysql_data_home[2],language[LIBLEN],reg_ext[FN_EXTLEN],
+ language[LIBLEN],reg_ext[FN_EXTLEN],
default_charset[LIBLEN],mysql_charsets_dir[FN_REFLEN], *charsets_list,
blob_newline,f_fyllchar,max_sort_char,*mysqld_user,*mysqld_chroot,
*opt_init_file;
+#ifndef EMBEDDED_LIBRARY
+char mysql_data_home_buff[2], *mysql_data_home=mysql_data_home_buff;
+bool mysql_embedded=0;
+#else
+char *mysql_data_home=mysql_real_data_home;
+bool mysql_embedded=1;
+#endif
+
char *opt_bin_logname = 0; // this one needs to be seen in sql_parse.cc
+char *opt_relay_logname = 0, *opt_relaylog_index_name=0;
char server_version[SERVER_VERSION_LENGTH]=MYSQL_SERVER_VERSION;
const char *first_keyword="first";
const char **errmesg; /* Error messages */
@@ -322,10 +341,9 @@ const char *sql_mode_str="OFF";
const char *default_tx_isolation_name;
enum_tx_isolation default_tx_isolation=ISO_READ_COMMITTED;
-#ifdef HAVE_GEMINI_DB
-const char *gemini_recovery_options_str="FULL";
-#endif
-my_string mysql_unix_port=NULL,mysql_tmpdir=NULL;
+uint rpl_recovery_rank=0;
+
+my_string mysql_unix_port=NULL, mysql_tmpdir=NULL, allocated_mysql_tmpdir=NULL;
ulong my_bind_addr; /* the address we bind to */
DATE_FORMAT dayord;
double log_10[32]; /* 10 potences */
@@ -335,8 +353,8 @@ time_t start_time;
ulong opt_sql_mode = 0L;
const char *sql_mode_names[] =
{ "REAL_AS_FLOAT", "PIPES_AS_CONCAT", "ANSI_QUOTES", "IGNORE_SPACE",
- "SERIALIZE","ONLY_FULL_GROUP_BY", NullS };
-TYPELIB sql_mode_typelib= {array_elements(sql_mode_names),"",
+ "SERIALIZE","ONLY_FULL_GROUP_BY", "NO_UNSIGNED_SUBTRACTION",NullS };
+TYPELIB sql_mode_typelib= {array_elements(sql_mode_names)-1,"",
sql_mode_names};
MY_BITMAP temp_pool;
@@ -350,8 +368,10 @@ pthread_mutex_t LOCK_mysql_create_db, LOCK_Acl, LOCK_open, LOCK_thread_count,
LOCK_error_log,
LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create,
LOCK_crypt, LOCK_bytes_sent, LOCK_bytes_received,
- LOCK_binlog_update, LOCK_slave, LOCK_server_id,
- LOCK_user_conn;
+ LOCK_server_id,
+ LOCK_user_conn, LOCK_slave_list, LOCK_active_mi;
+
+Query_cache query_cache;
pthread_cond_t COND_refresh,COND_thread_count,COND_binlog_update,
COND_slave_stopped, COND_slave_start;
@@ -363,10 +383,12 @@ enum db_type default_table_type=DB_TYPE_MYISAM;
#ifdef __WIN__
#undef getpid
#include <process.h>
+#if !defined(EMBEDDED_LIBRARY)
HANDLE hEventShutdown;
#include "nt_servc.h"
static NTService Service; // Service object for WinNT
#endif
+#endif
#ifdef OS2
pthread_cond_t eventShutdown;
@@ -381,6 +403,7 @@ static void fix_paths(void);
static pthread_handler_decl(handle_connections_sockets,arg);
static pthread_handler_decl(kill_server_thread,arg);
static int bootstrap(FILE *file);
+static void close_server_sock();
static bool read_init_file(char *file_name);
#ifdef __NT__
static pthread_handler_decl(handle_connections_namedpipes,arg);
@@ -430,15 +453,7 @@ static void close_connections(void)
if (pthread_kill(select_thread,THR_CLIENT_ALARM))
break; // allready dead
#endif
-#ifdef HAVE_TIMESPEC_TS_SEC
- abstime.ts_sec=time(NULL)+2; // Bsd 2.1
- abstime.ts_nsec=0;
-#else
- struct timeval tv;
- gettimeofday(&tv,0);
- abstime.tv_sec=tv.tv_sec+2;
- abstime.tv_nsec=tv.tv_usec*1000;
-#endif
+ set_timespec(abstime, 2);
for (uint tmp=0 ; tmp < 10 ; tmp++)
{
error=pthread_cond_timedwait(&COND_thread_count,&LOCK_thread_count,
@@ -450,9 +465,7 @@ static void close_connections(void)
if (error != 0 && !count++)
sql_print_error("Got error %d from pthread_cond_timedwait",error);
#endif
-#if defined(HAVE_DEC_3_2_THREADS) || defined(SIGNALS_DONT_BREAK_READ)
close_server_sock();
-#endif
}
(void) pthread_mutex_unlock(&LOCK_thread_count);
#endif /* __WIN__ */
@@ -470,28 +483,28 @@ static void close_connections(void)
}
}
#ifdef __NT__
-if (hPipe != INVALID_HANDLE_VALUE && opt_enable_named_pipe)
-{
- HANDLE temp;
- DBUG_PRINT( "quit", ("Closing named pipes") );
-
- /* Create connection to the handle named pipe handler to break the loop */
- if ((temp = CreateFile(szPipeName,
- GENERIC_READ | GENERIC_WRITE,
- 0,
- NULL,
- OPEN_EXISTING,
- 0,
- NULL )) != INVALID_HANDLE_VALUE)
+ if (hPipe != INVALID_HANDLE_VALUE && opt_enable_named_pipe)
{
- WaitNamedPipe(szPipeName, 1000);
- DWORD dwMode = PIPE_READMODE_BYTE | PIPE_WAIT;
- SetNamedPipeHandleState(temp, &dwMode, NULL, NULL);
- CancelIo(temp);
- DisconnectNamedPipe(temp);
- CloseHandle(temp);
+ HANDLE temp;
+ DBUG_PRINT( "quit", ("Closing named pipes") );
+
+ /* Create connection to the handle named pipe handler to break the loop */
+ if ((temp = CreateFile(szPipeName,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL )) != INVALID_HANDLE_VALUE)
+ {
+ WaitNamedPipe(szPipeName, 1000);
+ DWORD dwMode = PIPE_READMODE_BYTE | PIPE_WAIT;
+ SetNamedPipeHandleState(temp, &dwMode, NULL, NULL);
+ CancelIo(temp);
+ DisconnectNamedPipe(temp);
+ CloseHandle(temp);
+ }
}
- }
#endif
#ifdef HAVE_SYS_UN_H
if (unix_sock != INVALID_SOCKET)
@@ -538,7 +551,7 @@ if (hPipe != INVALID_HANDLE_VALUE && opt_enable_named_pipe)
/* Force remaining threads to die by closing the connection to the client */
- (void) my_net_init(&net, (Vio*) 0);
+ (void) my_net_init(&net, (st_vio*) 0);
for (;;)
{
DBUG_PRINT("quit",("Locking LOCK_thread_count"));
@@ -579,59 +592,68 @@ if (hPipe != INVALID_HANDLE_VALUE && opt_enable_named_pipe)
DBUG_VOID_RETURN;
}
-#ifdef HAVE_CLOSE_SERVER_SOCK
-void close_server_sock()
+static void close_server_sock()
{
+#ifdef HAVE_CLOSE_SERVER_SOCK
DBUG_ENTER("close_server_sock");
- if (ip_sock != INVALID_SOCKET)
+ my_socket tmp_sock;
+ tmp_sock=ip_sock;
+ if (tmp_sock != INVALID_SOCKET)
{
- DBUG_PRINT("info",("closing TCP/IP socket"));
- VOID(shutdown(ip_sock,2));
- VOID(closesocket(ip_sock));
ip_sock=INVALID_SOCKET;
+ DBUG_PRINT("info",("closing TCP/IP socket"));
+ VOID(shutdown(tmp_sock,2));
+ VOID(closesocket(tmp_sock));
}
- if (unix_sock != INVALID_SOCKET)
+ tmp_sock=unix_sock;
+ if (tmp_sock != INVALID_SOCKET)
{
+ unix_sock=INVALID_SOCKET;
DBUG_PRINT("info",("closing Unix socket"));
- VOID(shutdown(unix_sock,2));
- VOID(closesocket(unix_sock));
+ VOID(shutdown(tmp_sock,2));
+ VOID(closesocket(tmp_sock));
VOID(unlink(mysql_unix_port));
- unix_sock=INVALID_SOCKET;
}
DBUG_VOID_RETURN;
-}
#endif
+}
void kill_mysql(void)
{
DBUG_ENTER("kill_mysql");
+
#ifdef SIGNALS_DONT_BREAK_READ
close_server_sock(); /* force accept to wake up */
-#endif
+#endif
+
#if defined(__WIN__)
+#if !defined(EMBEDDED_LIBRARY)
{
if (!SetEvent(hEventShutdown))
{
DBUG_PRINT("error",("Got error: %ld from SetEvent",GetLastError()));
}
- // or:
- // HANDLE hEvent=OpenEvent(0, FALSE, "MySqlShutdown");
- // SetEvent(hEventShutdown);
- // CloseHandle(hEvent);
+ /*
+ or:
+ HANDLE hEvent=OpenEvent(0, FALSE, "MySqlShutdown");
+ SetEvent(hEventShutdown);
+ CloseHandle(hEvent);
+ */
}
+#endif
#elif defined(OS2)
pthread_cond_signal( &eventShutdown); // post semaphore
#elif defined(HAVE_PTHREAD_KILL)
- if (pthread_kill(signal_thread,MYSQL_KILL_SIGNAL))// End everything nicely
+ if (pthread_kill(signal_thread,SIGTERM)) /* End everything nicely */
{
DBUG_PRINT("error",("Got error %d from pthread_kill",errno)); /* purecov: inspected */
}
#elif !defined(SIGNALS_DONT_BREAK_READ)
- kill(current_pid,MYSQL_KILL_SIGNAL);
+ kill(current_pid,SIGTERM);
#endif
DBUG_PRINT("quit",("After pthread_kill"));
shutdown_in_progress=1; // Safety if kill didn't work
-#ifdef SIGNALS_DONT_BREAK_READ
+#ifdef SIGNALS_DONT_BREAK_READ
if (!abort_loop)
{
pthread_t tmp;
@@ -661,8 +683,7 @@ static void __cdecl kill_server(int sig_ptr)
int sig=(int) (long) sig_ptr; // This is passed a int
DBUG_ENTER("kill_server");
- // if there is a signal during the kill in progress, we do not need
- // another one
+ // if there is a signal during the kill in progress, ignore the other
if (kill_in_progress) // Safety
RETURN_FROM_KILL_SERVER;
kill_in_progress=TRUE;
@@ -687,7 +708,7 @@ static void __cdecl kill_server(int sig_ptr)
#ifdef USE_ONE_SIGNAL_HAND
-pthread_handler_decl(kill_server_thread,arg __attribute__((unused)))
+static pthread_handler_decl(kill_server_thread,arg __attribute__((unused)))
{
my_thread_init(); // Initialize new thread
kill_server(0);
@@ -696,6 +717,11 @@ pthread_handler_decl(kill_server_thread,arg __attribute__((unused)))
}
#endif
+#if defined(__amiga__)
+#undef sigset
+#define sigset signal
+#endif
+
static sig_handler print_signal_warning(int sig)
{
if (opt_warnings)
@@ -714,15 +740,19 @@ static sig_handler print_signal_warning(int sig)
void unireg_end(int signal_number __attribute__((unused)))
{
clean_up();
+ my_thread_end();
pthread_exit(0); // Exit is in main thread
}
void unireg_abort(int exit_code)
{
+ DBUG_ENTER("unireg_abort");
if (exit_code)
sql_print_error("Aborting\n");
clean_up(); /* purecov: inspected */
+ DBUG_PRINT("quit",("done with cleanup in unireg_abort"));
+ my_thread_end();
exit(exit_code); /* purecov: inspected */
}
@@ -736,7 +766,7 @@ void clean_up(bool print_message)
bitmap_free(&slave_error_mask);
acl_free(1);
grant_free();
- sql_cache_free();
+ query_cache.destroy();
table_cache_free();
hostname_cache_free();
item_user_lock_free();
@@ -750,27 +780,42 @@ void clean_up(bool print_message)
#ifdef USE_RAID
end_raid();
#endif
+#ifdef HAVE_OPENSSL
+ my_free(opt_ssl_key,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(opt_ssl_cert,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(opt_ssl_ca,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(opt_ssl_capath,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(opt_ssl_cipher,MYF(MY_ALLOW_ZERO_PTR));
+ my_free((gptr) ssl_acceptor_fd, MYF(MY_ALLOW_ZERO_PTR));
+ opt_ssl_key=opt_ssl_cert=opt_ssl_ca=opt_ssl_capath=0;
+#endif /* HAVE_OPENSSL */
+
free_defaults(defaults_argv);
my_free(charsets_list, MYF(MY_ALLOW_ZERO_PTR));
- my_free(mysql_tmpdir,MYF(0));
+ my_free(allocated_mysql_tmpdir,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(slave_load_tmpdir,MYF(MY_ALLOW_ZERO_PTR));
x_free(opt_bin_logname);
+ x_free(opt_relay_logname);
bitmap_free(&temp_pool);
free_max_user_conn();
-#ifndef __WIN__
+ end_slave_list();
+
+#if !defined(__WIN__) && !defined(EMBEDDED_LIBRARY)
if (!opt_bootstrap)
(void) my_delete(pidfile_name,MYF(0)); // This may not always exist
#endif
- if (print_message)
+ if (print_message && errmesg)
sql_print_error(ER(ER_SHUTDOWN_COMPLETE),my_progname);
x_free((gptr) my_errmsg[ERRMAPP]); /* Free messages */
- my_thread_end();
-
+ DBUG_PRINT("quit", ("Error messages freed"));
/* Tell main we are ready */
(void) pthread_mutex_lock(&LOCK_thread_count);
+ DBUG_PRINT("quit", ("got thread count lock"));
ready_to_exit=1;
/* do the broadcast inside the lock to ensure that my_end() is not called */
(void) pthread_cond_broadcast(&COND_thread_count);
(void) pthread_mutex_unlock(&LOCK_thread_count);
+ DBUG_PRINT("quit", ("done with cleanup"));
} /* clean_up */
@@ -830,20 +875,33 @@ static void set_user(const char *user)
if (!strcmp(user,"root"))
return; // Avoid problem with dynamic libraries
+ uid_t uid;
if (!(ent = getpwnam(user)))
{
- fprintf(stderr,"Fatal error: Can't change to run as user '%s' ; Please check that the user exists!\n",user);
- unireg_abort(1);
+ // allow a numeric uid to be used
+ const char *pos;
+ for (pos=user; isdigit(*pos); pos++) ;
+ if (*pos) // Not numeric id
+ {
+ fprintf(stderr,"Fatal error: Can't change to run as user '%s' ; Please check that the user exists!\n",user);
+ unireg_abort(1);
+ }
+ uid=atoi(user); // Use numberic uid
}
+ else
+ {
#ifdef HAVE_INITGROUPS
- initgroups((char*) user,ent->pw_gid);
+ initgroups((char*) user,ent->pw_gid);
#endif
- if (setgid(ent->pw_gid) == -1)
- {
- sql_perror("setgid");
- unireg_abort(1);
+ if (setgid(ent->pw_gid) == -1)
+ {
+ sql_perror("setgid");
+ unireg_abort(1);
+ }
+ uid=ent->pw_uid;
}
- if (setuid(ent->pw_uid) == -1)
+
+ if (setuid(uid) == -1)
{
sql_perror("setuid");
unireg_abort(1);
@@ -913,14 +971,16 @@ static void server_init(void)
unireg_abort(1);
}
if (listen(ip_sock,(int) back_log) < 0)
- sql_print_error("Warning: listen() on TCP/IP failed with error %d",
+ {
+ sql_print_error("Error: listen() on TCP/IP failed with error %d",
socket_errno);
+ unireg_abort(1);
+ }
}
if (mysqld_chroot)
set_root(mysqld_chroot);
-
- set_user(mysqld_user); // set_user now takes care of mysqld_user==NULL
+ set_user(mysqld_user); // Works also with mysqld_user==NULL
#ifdef __NT__
/* create named pipe */
@@ -1023,7 +1083,7 @@ void yyerror(const char *s)
void close_connection(NET *net,uint errcode,bool lock)
{
- Vio* vio;
+ st_vio* vio;
DBUG_ENTER("close_connection");
DBUG_PRINT("enter",("fd: %s error: '%s'",
net->vio? vio_description(net->vio):"(not connected)",
@@ -1088,6 +1148,8 @@ void end_thread(THD *thd, bool put_in_cache)
DBUG_PRINT("info", ("sending a broadcast"))
/* Tell main we are ready */
+ // TODO: explain why we broadcast outside of the lock or
+ // fix the bug - Sasha
(void) pthread_mutex_unlock(&LOCK_thread_count);
(void) pthread_cond_broadcast(&COND_thread_count);
DBUG_PRINT("info", ("unlocked thread_count mutex"))
@@ -1101,20 +1163,6 @@ void end_thread(THD *thd, bool put_in_cache)
DBUG_VOID_RETURN;
}
-#ifdef SIGNALS_DONT_BREAK_READ
-inline void kill_broken_server()
-{
- /* hack to get around signals ignored in syscalls for problem OS's */
- if (unix_sock == INVALID_SOCKET || ip_sock ==INVALID_SOCKET)
- {
- select_thread_in_use = 0;
- kill_server((void*)MYSQL_KILL_SIGNAL); /* never returns */
- }
-}
-#define MAYBE_BROKEN_SYSCALL kill_broken_server();
-#else
-#define MAYBE_BROKEN_SYSCALL
-#endif
/* Start a cached thread. LOCK_thread_count is locked on entry */
@@ -1182,19 +1230,6 @@ static void start_signal_handler(void)
}
#elif defined(__EMX__)
-static void init_signals(void)
-{
- signal(SIGQUIT, sig_kill);
- signal(SIGKILL, sig_kill);
- signal(SIGTERM, sig_kill);
- signal(SIGINT, sig_kill);
- signal(SIGHUP, sig_reload); // Flush everything
- signal(SIGALRM, SIG_IGN);
- signal(SIGBREAK,SIG_IGN);
- signal_thread = pthread_self();
-}
-
-
static void sig_reload(int signo)
{
reload_acl_and_cache((THD*) 0,REFRESH_LOG, (TABLE_LIST*) 0); // Flush everything
@@ -1211,10 +1246,22 @@ static void sig_kill(int signo)
signal(signo, SIG_ACK);
}
+static void init_signals(void)
+{
+ signal(SIGQUIT, sig_kill);
+ signal(SIGKILL, sig_kill);
+ signal(SIGTERM, sig_kill);
+ signal(SIGINT, sig_kill);
+ signal(SIGHUP, sig_reload); // Flush everything
+ signal(SIGALRM, SIG_IGN);
+ signal(SIGBREAK,SIG_IGN);
+ signal_thread = pthread_self();
+}
static void start_signal_handler(void)
{
}
+
#else /* if ! __WIN__ && ! __EMX__ */
#ifdef HAVE_LINUXTHREADS
@@ -1225,10 +1272,10 @@ static sig_handler handle_segfault(int sig)
{
THD *thd=current_thd;
/*
- Strictly speaking, we should need a mutex here
+ Strictly speaking, one needs a mutex here
but since we have got SIGSEGV already, things are a mess
so not having the mutex is not as bad as possibly using a buggy
- mutex - so we keep things simple.
+ mutex - so we keep things simple
*/
if (segfaulted)
{
@@ -1240,13 +1287,13 @@ static sig_handler handle_segfault(int sig)
fprintf(stderr,"\
mysqld got signal %d;\n\
This could be because you hit a bug. It is also possible that this binary\n\
-or one of the libraries it was linked agaist is corrupt, improperly built,\n\
+or one of the libraries it was linked against is corrupt, improperly built,\n\
or misconfigured. This error can also be caused by malfunctioning hardware.\n",
sig);
fprintf(stderr, "\
We will try our best to scrape up some info that will hopefully help diagnose\n\
the problem, but since we have already crashed, something is definitely wrong\n\
-and this may fail\n\n");
+and this may fail.\n\n");
fprintf(stderr, "key_buffer_size=%ld\n", keybuff_size);
fprintf(stderr, "record_buffer=%ld\n", my_default_record_cache_size);
fprintf(stderr, "sort_buffer=%ld\n", sortbuff_size);
@@ -1257,15 +1304,15 @@ and this may fail\n\n");
key_buffer_size + (record_buffer + sort_buffer)*max_connections = %ld K\n\
bytes of memory\n", (keybuff_size + (my_default_record_cache_size +
sortbuff_size) * max_connections)/ 1024);
- fprintf(stderr, "Hope that's ok, if not, decrease some variables in the equation\n\n");
+ fprintf(stderr, "Hope that's ok; if not, decrease some variables in the equation.\n\n");
#if defined(HAVE_LINUXTHREADS)
if (sizeof(char*) == 4 && thread_count > UNSAFE_DEFAULT_LINUX_THREADS)
{
fprintf(stderr, "\
You seem to be running 32-bit Linux and have %d concurrent connections.\n\
-If you have not changed STACK_SIZE in LinuxThreads and build the binary \n\
-yourself, LinuxThreads is quite likely to steal a part of global heap for\n\
+If you have not changed STACK_SIZE in LinuxThreads and built the binary \n\
+yourself, LinuxThreads is quite likely to steal a part of the global heap for\n\
the thread stack. Please read http://www.mysql.com/doc/L/i/Linux.html\n\n",
thread_count);
}
@@ -1274,9 +1321,7 @@ the thread stack. Please read http://www.mysql.com/doc/L/i/Linux.html\n\n",
#ifdef HAVE_STACKTRACE
if(!(test_flags & TEST_NO_STACKTRACE))
{
-#ifdef HAVE_GEMINI_DB
- utrace();
-#endif
+ fprintf(stderr,"thd=%p\n",thd);
print_stacktrace(thd ? (gptr) thd->thread_stack : (gptr) 0,
thread_stack);
}
@@ -1289,12 +1334,12 @@ Some pointers may be invalid and cause the dump to abort...\n");
fprintf(stderr, "\n\
Successfully dumped variables, if you ran with --log, take a look at the\n\
details of what thread %ld did to cause the crash. In some cases of really\n\
-bad corruption, the values shown above may be invalid\n\n",
+bad corruption, the values shown above may be invalid.\n\n",
thd->thread_id);
}
fprintf(stderr, "\
The manual page at http://www.mysql.com/doc/C/r/Crashing.html contains\n\
-information that should help you find out what is causing the crash\n");
+information that should help you find out what is causing the crash.\n");
fflush(stderr);
#endif /* HAVE_STACKTRACE */
@@ -1326,7 +1371,11 @@ static void init_signals(void)
sigprocmask(SIG_SETMASK,&sa.sa_mask,NULL);
init_stacktrace();
+#if defined(__amiga__)
+ sa.sa_handler=(void(*)())handle_segfault;
+#else
sa.sa_handler=handle_segfault;
+#endif
sigaction(SIGSEGV, &sa, NULL);
#ifdef SIGBUS
sigaction(SIGBUS, &sa, NULL);
@@ -1345,8 +1394,8 @@ static void init_signals(void)
sigaddset(&set,SIGQUIT);
sigaddset(&set,SIGTERM);
sigaddset(&set,SIGHUP);
- sigset(SIGTERM,print_signal_warning); // If it's blocked by parent
- signal(SIGHUP,print_signal_warning); // If it's blocked by parent
+ signal(SIGTERM,SIG_DFL); // If it's blocked by parent
+ signal(SIGHUP,SIG_DFL); // If it's blocked by parent
#ifdef SIGTSTP
sigaddset(&set,SIGTSTP);
#endif
@@ -1430,6 +1479,13 @@ static void *signal_hand(void *arg __attribute__((unused)))
(void) my_close(pidFile,MYF(0));
}
}
+#ifdef HAVE_STACK_TRACE_ON_SEGV
+ if (opt_do_pstack)
+ {
+ sprintf(pstack_file_name,"mysqld-%lu-%%d-%%d.backtrace", (ulong)getpid());
+ pstack_install_segv_action(pstack_file_name);
+ }
+#endif /* HAVE_STACK_TRACE_ON_SEGV */
// signal to start_signal_handler that we are ready
(void) pthread_mutex_lock(&LOCK_thread_count);
@@ -1441,7 +1497,7 @@ static void *signal_hand(void *arg __attribute__((unused)))
int error; // Used when debugging
if (shutdown_in_progress && !abort_loop)
{
- sig= MYSQL_KILL_SIGNAL;
+ sig=SIGTERM;
error=0;
}
else
@@ -1464,15 +1520,18 @@ static 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*) 0))
+ (void*) sig))
sql_print_error("Error: Can't create thread to kill server");
#else
- kill_server((void*) sig); // MIT THREAD has a alarm thread
+ kill_server((void*) sig); // MIT THREAD has a alarm thread
#endif
}
break;
case SIGHUP:
- reload_acl_and_cache((THD*) 0,REFRESH_LOG,
+ reload_acl_and_cache((THD*) 0,
+ (REFRESH_LOG | REFRESH_TABLES | REFRESH_FAST |
+ REFRESH_STATUS | REFRESH_GRANT | REFRESH_THREADS |
+ REFRESH_HOSTS),
(TABLE_LIST*) 0); // Flush logs
mysql_print_status((THD*) 0); // Send debug some info
break;
@@ -1542,8 +1601,9 @@ pthread_handler_decl(handle_shutdown,arg)
/* this call should create the message queue for this thread */
PeekMessage(&msg, NULL, 1, 65534,PM_NOREMOVE);
-
+#if !defined(EMBEDDED_LIBRARY)
if (WaitForSingleObject(hEventShutdown,INFINITE)==WAIT_OBJECT_0)
+#endif
kill_server(MYSQL_KILL_SIGNAL);
return 0;
}
@@ -1571,8 +1631,10 @@ pthread_handler_decl(handle_shutdown,arg)
// close semaphore and kill server
pthread_cond_destroy( &eventShutdown);
- // exit main loop on main thread, so kill will be done from
- // main thread (this is thread 2)
+ /*
+ Exit main loop on main thread, so kill will be done from
+ main thread (this is thread 2)
+ */
abort_loop = 1;
// unblock select()
@@ -1589,15 +1651,17 @@ const char *load_default_groups[]= { "mysqld","server",0 };
char *libwrapName=NULL;
#endif
-static void open_log(MYSQL_LOG *log, const char *hostname,
+void open_log(MYSQL_LOG *log, const char *hostname,
const char *opt_name, const char *extension,
- enum_log_type type)
+ enum_log_type type, bool read_append,
+ bool no_auto_events)
{
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.
+ /*
+ 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(strcend(tmp,'.'),extension);
@@ -1614,7 +1678,8 @@ static void open_log(MYSQL_LOG *log, const char *hostname,
opt_name=tmp;
}
}
- log->open(opt_name,type);
+ log->open(opt_name,type,0,(read_append) ? SEQ_READ_APPEND : WRITE_CACHE,
+ no_auto_events);
}
@@ -1710,33 +1775,35 @@ int main(int argc, char **argv)
(void) pthread_mutex_init(&LOCK_bytes_sent,MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_bytes_received,MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_timezone,MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_binlog_update, MY_MUTEX_INIT_FAST); // QQ NOT USED
- (void) pthread_mutex_init(&LOCK_slave, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_server_id, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_user_conn, MY_MUTEX_INIT_FAST);
+ (void) pthread_mutex_init(&LOCK_rpl_status, MY_MUTEX_INIT_FAST);
+ (void) pthread_mutex_init(&LOCK_active_mi, MY_MUTEX_INIT_FAST);
(void) pthread_cond_init(&COND_thread_count,NULL);
(void) pthread_cond_init(&COND_refresh,NULL);
(void) pthread_cond_init(&COND_thread_cache,NULL);
(void) pthread_cond_init(&COND_flush_thread_cache,NULL);
(void) pthread_cond_init(&COND_manager,NULL);
- (void) pthread_cond_init(&COND_binlog_update, NULL);
- (void) pthread_cond_init(&COND_slave_stopped, NULL);
- (void) pthread_cond_init(&COND_slave_start, NULL);
+ (void) pthread_cond_init(&COND_rpl_status, NULL);
init_signals();
if (set_default_charset_by_name(default_charset, MYF(MY_WME)))
- unireg_abort(1);
+ exit( 1 );
charsets_list = list_charsets(MYF(MY_COMPILED_SETS|MY_CONFIG_SETS));
#ifdef HAVE_OPENSSL
if (opt_use_ssl)
{
- ssl_acceptor_fd = VioSSLAcceptorFd_new(opt_ssl_key, opt_ssl_cert,
- opt_ssl_ca, opt_ssl_capath);
+ 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: %p",ssl_acceptor_fd));
if (!ssl_acceptor_fd)
- opt_use_ssl=0;
- /* having ssl_acceptor_fd!=0 signals the use of SSL */
+ opt_use_ssl = 0;
+ /* having ssl_acceptor_fd != 0 signals the use of SSL */
}
+ if (des_key_file)
+ load_des_key_file(des_key_file);
#endif /* HAVE_OPENSSL */
#ifdef HAVE_LIBWRAP
@@ -1757,7 +1824,7 @@ int main(int argc, char **argv)
pthread_attr_setscope(&connection_attrib, PTHREAD_SCOPE_SYSTEM);
#if defined( SET_RLIMIT_NOFILE) || defined( OS2)
- /* connections and databases neads lots of files */
+ /* connections and databases needs lots of files */
{
uint wanted_files=10+(uint) max(max_connections*5,
max_connections+table_cache_size*2);
@@ -1801,14 +1868,12 @@ int main(int argc, char **argv)
server_init();
table_cache_init();
hostname_cache_init();
- sql_cache_init();
+ query_cache.result_size_limit(query_cache_limit);
+ query_cache.resize(query_cache_size);
randominit(&sql_rand,(ulong) start_time,(ulong) start_time/2);
reset_floating_point_exceptions();
init_thr_lock();
-
- /* Fix varibles that are base 1024*1024 */
- myisam_max_temp_length= (my_off_t) min(((ulonglong) myisam_max_sort_file_size)*1024*1024, (ulonglong) MAX_FILE_SIZE);
- myisam_max_extra_temp_length= (my_off_t) min(((ulonglong) myisam_max_extra_sort_file_size)*1024*1024, (ulonglong) MAX_FILE_SIZE);
+ init_slave_list();
/* Setup log files */
if (opt_log)
@@ -1819,19 +1884,9 @@ int main(int argc, char **argv)
LOG_NEW);
using_update_log=1;
}
-
- //make sure slave thread gets started
- // if server_id is set, valid master.info is present, and master_host has
- // not been specified
- if(server_id && !master_host)
- {
- char fname[FN_REFLEN+128];
- MY_STAT stat_area;
- fn_format(fname, master_info_file, mysql_data_home, "", 4+16+32);
- if(my_stat(fname, &stat_area, MYF(0)) && !init_master_info(&glob_mi))
- master_host = glob_mi.host;
- }
-
+
+ init_slave();
+
if (opt_bin_log && !server_id)
{
server_id= !master_host ? 1 : 2;
@@ -1868,7 +1923,7 @@ The server will not act as a slave.");
LOG_BIN);
using_update_log=1;
}
-
+
if (opt_slow_log)
open_log(&mysql_slow_log, glob_hostname, opt_slow_logname, "-slow.log",
LOG_NORMAL);
@@ -1898,15 +1953,15 @@ The server will not act as a slave.");
}
#else
locked_in_memory=0;
-#endif
+#endif
if (opt_myisam_log)
(void) mi_log( 1 );
- ft_init_stopwords(ft_precompiled_stopwords); /* SerG */
+ ft_init_stopwords(ft_precompiled_stopwords);
#ifdef __WIN__
if (!opt_console)
- FreeConsole(); // Remove window
+ FreeConsole(); // Remove window
#endif
/*
@@ -1927,14 +1982,13 @@ The server will not act as a slave.");
(void) pthread_kill(signal_thread,MYSQL_KILL_SIGNAL);
#ifndef __WIN__
if (!opt_bootstrap)
- (void) my_delete(pidfile_name,MYF(MY_WME)); // Not neaded anymore
+ (void) my_delete(pidfile_name,MYF(MY_WME)); // Not needed anymore
#endif
exit(1);
}
if (!opt_noacl)
(void) grant_init();
- if (max_user_connections)
- init_max_user_conn();
+ init_max_user_conn();
#ifdef HAVE_DLOPEN
if (!opt_noacl)
@@ -1956,7 +2010,7 @@ The server will not act as a slave.");
}
}
(void) thr_setconcurrency(concurrency); // 10 by default
-#ifdef __WIN__ //IRENA
+#if defined(__WIN__) && !defined(EMBEDDED_LIBRARY) //IRENA
{
hEventShutdown=CreateEvent(0, FALSE, FALSE, "MySqlShutdown");
pthread_t hThread;
@@ -1987,17 +2041,6 @@ The server will not act as a slave.");
sql_print_error("Warning: Can't create thread to manage maintenance");
}
- // slave thread
- if (master_host)
- {
- pthread_t hThread;
- if (!opt_skip_slave_start &&
- pthread_create(&hThread, &connection_attrib, handle_slave, 0))
- sql_print_error("Warning: Can't create thread to handle slave");
- else if(opt_skip_slave_start)
- init_master_info(&glob_mi);
- }
-
printf(ER(ER_READY),my_progname,server_version,"");
fflush(stdout);
@@ -2044,7 +2087,7 @@ The server will not act as a slave.");
}
#else
handle_connections_sockets(0);
-#ifdef EXTRA_DEBUG
+#ifdef EXTRA_DEBUG2
sql_print_error("Exiting main thread");
#endif
#endif /* __NT__ */
@@ -2054,17 +2097,18 @@ The server will not act as a slave.");
DBUG_PRINT("quit",("Exiting main thread"));
#ifndef __WIN__
-#ifdef EXTRA_DEBUG
+#ifdef EXTRA_DEBUG2
sql_print_error("Before Lock_thread_count");
#endif
(void) pthread_mutex_lock(&LOCK_thread_count);
+ DBUG_PRINT("quit", ("Got thread_count mutex"));
select_thread_in_use=0; // For close_connections
(void) pthread_cond_broadcast(&COND_thread_count);
(void) pthread_mutex_unlock(&LOCK_thread_count);
-#ifdef EXTRA_DEBUG
+#ifdef EXTRA_DEBUG2
sql_print_error("After lock_thread_count");
#endif
-#endif
+#endif /* __WIN__ */
/* Wait until cleanup is done */
(void) pthread_mutex_lock(&LOCK_thread_count);
@@ -2073,22 +2117,16 @@ The server will not act as a slave.");
pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
}
(void) pthread_mutex_unlock(&LOCK_thread_count);
-#ifdef __WIN__
- if (Service.IsNT())
- {
- if(start_mode)
- Service.Stop();
- else
- {
- Service.SetShutdownEvent(0);
- if(hEventShutdown) CloseHandle(hEventShutdown);
- }
- }
- else
- {
+
+#if defined(__WIN__) && !defined(EMBEDDED_LIBRARY)
+ if (Service.IsNT() && start_mode)
+ Service.Stop();
+ else
+ {
Service.SetShutdownEvent(0);
- if(hEventShutdown) CloseHandle(hEventShutdown);
- }
+ if (hEventShutdown)
+ CloseHandle(hEventShutdown);
+ }
#endif
my_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
exit(0);
@@ -2096,7 +2134,7 @@ The server will not act as a slave.");
}
-#ifdef __WIN__
+#if defined(__WIN__) && !defined(EMBEDDED_LIBRARY)
/* ------------------------------------------------------------------------
main and thread entry function for Win32
(all this is needed only to run mysqld as a service on WinNT)
@@ -2143,9 +2181,11 @@ int main(int argc, char **argv)
}
}
- // This is a WIN95 machine or a start of mysqld as a standalone program
- // we have to pass the arguments, in case of NT-service this will be done
- // by ServiceMain()
+ /*
+ This is a WIN95 machine or a start of mysqld as a standalone program
+ we have to pass the arguments, in case of NT-service this will be done
+ by ServiceMain()
+ */
Service.my_argc=argc;
Service.my_argv=argv;
@@ -2162,7 +2202,7 @@ static int bootstrap(FILE *file)
int error;
thd->bootstrap=1;
thd->client_capabilities=0;
- my_net_init(&thd->net,(Vio*) 0);
+ my_net_init(&thd->net,(st_vio*) 0);
thd->max_packet_length=thd->net.max_packet;
thd->master_access= ~0;
thd->thread_id=thread_id++;
@@ -2280,7 +2320,7 @@ static void create_new_thread(THD *thd)
(void) pthread_mutex_unlock(&LOCK_thread_count);
DBUG_VOID_RETURN;
}
-
+
(void) pthread_mutex_unlock(&LOCK_thread_count);
}
}
@@ -2288,6 +2328,20 @@ static void create_new_thread(THD *thd)
DBUG_VOID_RETURN;
}
+#ifdef SIGNALS_DONT_BREAK_READ
+inline void kill_broken_server()
+{
+ /* hack to get around signals ignored in syscalls for problem OS's */
+ if (unix_sock == INVALID_SOCKET || ip_sock ==INVALID_SOCKET)
+ {
+ select_thread_in_use = 0;
+ kill_server((void*)MYSQL_KILL_SIGNAL); /* never returns */
+ }
+}
+#define MAYBE_BROKEN_SYSCALL kill_broken_server();
+#else
+#define MAYBE_BROKEN_SYSCALL
+#endif
/* Handle new connections and spawn new process to handle them */
@@ -2300,7 +2354,7 @@ pthread_handler_decl(handle_connections_sockets,arg __attribute__((unused)))
THD *thd;
struct sockaddr_in cAddr;
int ip_flags=0,socket_flags=0,flags;
- Vio *vio_tmp;
+ st_vio *vio_tmp;
DBUG_ENTER("handle_connections_sockets");
LINT_INIT(new_sock);
@@ -2338,13 +2392,15 @@ pthread_handler_decl(handle_connections_sockets,arg __attribute__((unused)))
if (!select_errors++ && !abort_loop) /* purecov: inspected */
sql_print_error("mysqld: Got error %d from select",socket_errno); /* purecov: inspected */
}
- MAYBE_BROKEN_SYSCALL;
+ MAYBE_BROKEN_SYSCALL
continue;
}
#endif /* HPUX */
if (abort_loop)
+ {
+ MAYBE_BROKEN_SYSCALL;
break;
-
+ }
/*
** Is this a new connection request
*/
@@ -2410,21 +2466,31 @@ pthread_handler_decl(handle_connections_sockets,arg __attribute__((unused)))
struct request_info req;
signal(SIGCHLD, SIG_DFL);
request_init(&req, RQ_DAEMON, libwrapName, RQ_FILE, new_sock, NULL);
+#ifndef __linux__
fromhost(&req);
if (!hosts_access(&req))
{
- // This may be stupid but refuse() includes an exit(0)
- // which we surely don't want...
- // clean_exit() - same stupid thing ...
+ /*
+ This may be stupid but refuse() includes an exit(0)
+ which we surely don't want...
+ clean_exit() - same stupid thing ...
+ */
syslog(deny_severity, "refused connect from %s", eval_client(&req));
+#else
+ fromhost();
+ if (!hosts_access())
+ {
+ syslog(deny_severity, "refused connect from %s", eval_client());
+#endif
if (req.sink)
((void (*)(int))req.sink)(req.fd);
- // C++ sucks (the gibberish in front just translates the supplied
- // sink function pointer in the req structure from a void (*sink)();
- // to a void(*sink)(int) if you omit the cast, the C++ compiler
- // will cry...
-
+ /*
+ C++ sucks (the gibberish in front just translates the supplied
+ sink function pointer in the req structure from a void (*sink)();
+ to a void(*sink)(int) if you omit the cast, the C++ compiler
+ will cry...
+ */
(void) shutdown(new_sock,2); // This looks fine to me...
(void) closesocket(new_sock);
continue;
@@ -2452,7 +2518,8 @@ pthread_handler_decl(handle_connections_sockets,arg __attribute__((unused)))
if (!(thd= new THD))
{
- (void) shutdown(new_sock,2); VOID(closesocket(new_sock));
+ (void) shutdown(new_sock,2);
+ VOID(closesocket(new_sock));
continue;
}
if (!(vio_tmp=vio_new(new_sock,
@@ -2604,6 +2671,8 @@ enum options {
OPT_MASTER_PASSWORD, OPT_MASTER_PORT,
OPT_MASTER_INFO_FILE, OPT_MASTER_CONNECT_RETRY,
OPT_MASTER_RETRY_COUNT,
+ OPT_MASTER_SSL, OPT_MASTER_SSL_KEY,
+ OPT_MASTER_SSL_CERT,
OPT_SQL_BIN_UPDATE_SAME, OPT_REPLICATE_DO_DB,
OPT_REPLICATE_IGNORE_DB, OPT_LOG_SLAVE_UPDATES,
OPT_BINLOG_DO_DB, OPT_BINLOG_IGNORE_DB,
@@ -2622,18 +2691,22 @@ enum options {
OPT_INNODB_LOG_ARCH_DIR,
OPT_INNODB_LOG_ARCHIVE,
OPT_INNODB_FLUSH_LOG_AT_TRX_COMMIT,
+ OPT_INNODB_FLUSH_METHOD,
OPT_INNODB_FAST_SHUTDOWN,
- OPT_INNODB_UNIX_FILE_FLUSH_METHOD,
OPT_SAFE_SHOW_DB,
- OPT_GEMINI_SKIP, OPT_INNODB_SKIP,
+ OPT_INNODB_SKIP, OPT_SKIP_SAFEMALLOC,
OPT_TEMP_POOL, OPT_TX_ISOLATION,
- OPT_GEMINI_FLUSH_LOG, OPT_GEMINI_RECOVER,
- OPT_GEMINI_UNBUFFERED_IO, OPT_SKIP_SAFEMALLOC,
OPT_SKIP_STACK_TRACE, OPT_SKIP_SYMLINKS,
OPT_MAX_BINLOG_DUMP_EVENTS, OPT_SPORADIC_BINLOG_DUMP_FAIL,
OPT_SAFE_USER_CREATE, OPT_SQL_MODE,
OPT_HAVE_NAMED_PIPE,
- OPT_SLAVE_SKIP_ERRORS, OPT_LOCAL_INFILE
+ OPT_DO_PSTACK, OPT_REPORT_HOST,
+ OPT_REPORT_USER, OPT_REPORT_PASSWORD, OPT_REPORT_PORT,
+ OPT_SHOW_SLAVE_AUTH_INFO, OPT_OLD_RPL_COMPAT,
+ OPT_SLAVE_LOAD_TMPDIR, OPT_NO_MIX_TYPE,
+ OPT_RPL_RECOVERY_RANK,OPT_INIT_RPL_ROLE,
+ OPT_RELAY_LOG, OPT_RELAY_LOG_INDEX, OPT_RELAY_LOG_INFO_FILE,
+ OPT_SLAVE_SKIP_ERRORS, OPT_DES_KEY_FILE, OPT_LOCAL_INFILE
};
static struct option long_options[] = {
@@ -2661,19 +2734,17 @@ static struct option long_options[] = {
{"character-sets-dir", required_argument, 0, (int) OPT_CHARSETS_DIR},
{"datadir", required_argument, 0, 'h'},
{"debug", optional_argument, 0, '#'},
+ {"des-key-file", required_argument, 0, (int) OPT_DES_KEY_FILE},
{"default-character-set", required_argument, 0, 'C'},
{"default-table-type", required_argument, 0, (int) OPT_TABLE_TYPE},
{"delay-key-write-for-all-tables",
no_argument, 0, (int) OPT_DELAY_KEY_WRITE},
{"enable-locking", no_argument, 0, (int) OPT_ENABLE_LOCK},
{"enable-named-pipe", no_argument, 0, (int) OPT_HAVE_NAMED_PIPE},
+ {"enable-pstack", no_argument, 0, (int) OPT_DO_PSTACK},
{"exit-info", optional_argument, 0, 'T'},
{"flush", no_argument, 0, (int) OPT_FLUSH},
-#ifdef HAVE_GEMINI_DB
- {"gemini-flush-log-at-commit",no_argument, 0, (int) OPT_GEMINI_FLUSH_LOG},
- {"gemini-recovery", required_argument, 0, (int) OPT_GEMINI_RECOVER},
- {"gemini-unbuffered-io", no_argument, 0, (int) OPT_GEMINI_UNBUFFERED_IO},
-#endif
+ {"init-rpl-role", required_argument, 0, (int) OPT_INIT_RPL_ROLE},
/* We must always support this option to make scripts like mysqltest easier
to do */
{"innodb_data_file_path", required_argument, 0,
@@ -2692,7 +2763,7 @@ static struct option long_options[] = {
{"innodb_fast_shutdown", optional_argument, 0,
OPT_INNODB_FAST_SHUTDOWN},
{"innodb_flush_method", required_argument, 0,
- OPT_INNODB_UNIX_FILE_FLUSH_METHOD},
+ OPT_INNODB_FLUSH_METHOD},
#endif
{"help", no_argument, 0, '?'},
{"init-file", required_argument, 0, (int) OPT_INIT_FILE},
@@ -2714,10 +2785,15 @@ static struct option long_options[] = {
{"master-connect-retry", required_argument, 0, (int) OPT_MASTER_CONNECT_RETRY},
{"master-retry-count", required_argument, 0, (int) OPT_MASTER_RETRY_COUNT},
{"master-info-file", required_argument, 0, (int) OPT_MASTER_INFO_FILE},
+ {"master-ssl", optional_argument, 0, (int) OPT_MASTER_SSL},
+ {"master-ssl-key", optional_argument, 0, (int) OPT_MASTER_SSL_KEY},
+ {"master-ssl-cert", optional_argument, 0, (int) OPT_MASTER_SSL_CERT},
{"myisam-recover", optional_argument, 0, (int) OPT_MYISAM_RECOVER},
{"memlock", no_argument, 0, (int) OPT_MEMLOCK},
- // needs to be available for the test case to pass in non-debugging mode
- // is a no-op
+ /*
+ Option needs to be available for the test case to pass in non-debugging
+ mode. is a no-op.
+ */
{"disconnect-slave-event-count", required_argument, 0,
(int) OPT_DISCONNECT_SLAVE_EVENT_COUNT},
{"abort-slave-event-count", required_argument, 0,
@@ -2729,7 +2805,11 @@ static struct option long_options[] = {
{"safemalloc-mem-limit", required_argument, 0, (int)
OPT_SAFEMALLOC_MEM_LIMIT},
{"new", no_argument, 0, 'n'},
- {"old-protocol", no_argument, 0, 'o'},
+#ifdef NOT_YET
+ {"no-mix-table-types", no_argument, 0, (int) OPT_NO_MIX_TYPE},
+#endif
+ {"old-protocol", no_argument, 0, 'o'},
+ {"old-rpl-compat", no_argument, 0, (int) OPT_OLD_RPL_COMPAT},
#ifdef ONE_THREAD
{"one-thread", no_argument, 0, (int) OPT_ONE_THREAD},
#endif
@@ -2738,24 +2818,33 @@ static struct option long_options[] = {
{"replicate-do-db", required_argument, 0, (int) OPT_REPLICATE_DO_DB},
{"replicate-do-table", required_argument, 0,
(int) OPT_REPLICATE_DO_TABLE},
- {"replicate-wild-do-table", required_argument, 0,
+ {"replicate-wild-do-table", required_argument, 0,
(int) OPT_REPLICATE_WILD_DO_TABLE},
- {"replicate-ignore-db", required_argument, 0,
+ {"replicate-ignore-db", required_argument, 0,
(int) OPT_REPLICATE_IGNORE_DB},
{"replicate-ignore-table", required_argument, 0,
(int) OPT_REPLICATE_IGNORE_TABLE},
{"replicate-wild-ignore-table", required_argument, 0,
(int) OPT_REPLICATE_WILD_IGNORE_TABLE},
- {"replicate-rewrite-db", required_argument, 0,
+ {"replicate-rewrite-db", required_argument, 0,
(int) OPT_REPLICATE_REWRITE_DB},
+ // In replication, we may need to tell the other servers how to connect
+ {"report-host", required_argument, 0, (int) OPT_REPORT_HOST},
+ {"report-user", required_argument, 0, (int) OPT_REPORT_USER},
+ {"report-password", required_argument, 0, (int) OPT_REPORT_PASSWORD},
+ {"report-port", required_argument, 0, (int) OPT_REPORT_PORT},
+ {"rpl-recovery-rank", required_argument, 0, (int) OPT_RPL_RECOVERY_RANK},
+ {"relay-log", required_argument, 0, (int) OPT_RELAY_LOG},
+ {"relay-log-index", required_argument, 0, (int) OPT_RELAY_LOG_INDEX},
{"safe-mode", no_argument, 0, (int) OPT_SAFE},
{"safe-show-database", no_argument, 0, (int) OPT_SAFE_SHOW_DB},
{"safe-user-create", no_argument, 0, (int) OPT_SAFE_USER_CREATE},
{"server-id", required_argument, 0, (int) OPT_SERVER_ID},
{"set-variable", required_argument, 0, 'O'},
+ {"show-slave-auth-info", no_argument, 0,
+ (int) OPT_SHOW_SLAVE_AUTH_INFO},
{"skip-bdb", no_argument, 0, (int) OPT_BDB_SKIP},
{"skip-innodb", no_argument, 0, (int) OPT_INNODB_SKIP},
- {"skip-gemini", no_argument, 0, (int) OPT_GEMINI_SKIP},
{"skip-concurrent-insert", no_argument, 0, (int) OPT_SKIP_CONCURRENT_INSERT},
{"skip-delay-key-write", no_argument, 0, (int) OPT_SKIP_DELAY_KEY_WRITE},
{"skip-grant-tables", no_argument, 0, (int) OPT_SKIP_GRANT},
@@ -2770,7 +2859,10 @@ static struct option long_options[] = {
{"skip-stack-trace", no_argument, 0, (int) OPT_SKIP_STACK_TRACE},
{"skip-symlink", no_argument, 0, (int) OPT_SKIP_SYMLINKS},
{"skip-thread-priority", no_argument, 0, (int) OPT_SKIP_PRIOR},
- {"slave-skip-errors", required_argument,0,
+ {"relay-log-info-file", required_argument, 0,
+ (int) OPT_RELAY_LOG_INFO_FILE},
+ {"slave-load-tmpdir", required_argument, 0, (int) OPT_SLAVE_LOAD_TMPDIR},
+ {"slave-skip-errors", required_argument, 0,
(int) OPT_SLAVE_SKIP_ERRORS},
{"socket", required_argument, 0, (int) OPT_SOCKET},
{"sql-bin-update-same", no_argument, 0, (int) OPT_SQL_BIN_UPDATE_SAME},
@@ -2820,22 +2912,12 @@ CHANGEABLE_VAR changeable_vars[] = {
DELAYED_QUEUE_SIZE, 1, ~0L, 0, 1 },
{ "flush_time", (long*) &flush_time,
FLUSH_TIME, 0, LONG_TIMEOUT, 0, 1 },
-#ifdef HAVE_GEMINI_DB
- { "gemini_buffer_cache", (long*) &gemini_buffer_cache,
- 128 * 8192, 16, LONG_MAX, 0, 1 },
- { "gemini_connection_limit", (long*) &gemini_connection_limit,
- 100, 10, LONG_MAX, 0, 1 },
- { "gemini_io_threads", (long*) &gemini_io_threads,
- 2, 0, 256, 0, 1 },
- { "gemini_log_cluster_size", (long*) &gemini_log_cluster_size,
- 256 * 1024, 16 * 1024, LONG_MAX, 0, 1 },
- { "gemini_lock_table_size", (long*) &gemini_locktablesize,
- 4096, 1024, LONG_MAX, 0, 1 },
- { "gemini_lock_wait_timeout",(long*) &gemini_lock_wait_timeout,
- 10, 1, LONG_MAX, 0, 1 },
- { "gemini_spin_retries", (long*) &gemini_spin_retries,
- 1, 0, LONG_MAX, 0, 1 },
-#endif
+ { "ft_min_word_len", (long*) &ft_min_word_len,
+ 4, 1, HA_FT_MAXLEN, 0, 1 },
+ { "ft_max_word_len", (long*) &ft_max_word_len,
+ HA_FT_MAXLEN, 10, HA_FT_MAXLEN, 0, 1 },
+ { "ft_max_word_len_for_sort",(long*) &ft_max_word_len_for_sort,
+ 20, 4, HA_FT_MAXLEN, 0, 1 },
#ifdef HAVE_INNOBASE_DB
{"innodb_mirrored_log_groups",
(long*) &innobase_mirrored_log_groups, 1, 1, 10, 0, 1},
@@ -2897,6 +2979,11 @@ CHANGEABLE_VAR changeable_vars[] = {
0, 1, ~0L, 0, 1 },
{ "max_write_lock_count", (long*) &max_write_lock_count,
~0L, 1, ~0L, 0, 1 },
+ { "myisam_bulk_insert_tree_size", (long*) &myisam_bulk_insert_tree_size,
+ 8192*1024, 0, ~0L, 0, 1 },
+ { "myisam_block_size", (long*) &opt_myisam_block_size,
+ MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH, MI_MAX_KEY_BLOCK_LENGTH,
+ 0, MI_MIN_KEY_BLOCK_LENGTH },
{ "myisam_max_extra_sort_file_size",
(long*) &myisam_max_extra_sort_file_size,
(long) (MI_MAX_TEMP_LENGTH/(1024L*1024L)), 0, ~0L, 0, 1 },
@@ -2916,6 +3003,12 @@ CHANGEABLE_VAR changeable_vars[] = {
0, 0, 65535, 0, 1},
{ "query_buffer_size", (long*) &query_buff_size,
0, MALLOC_OVERHEAD, (long) ~0, MALLOC_OVERHEAD, IO_SIZE },
+ { "query_cache_limit", (long*) &query_cache_limit,
+ 1024*1024L, 0, ULONG_MAX, 0, 1},
+ { "query_cache_size", (long*) &query_cache_size,
+ 0, 0, ULONG_MAX, 0, 1},
+ { "query_cache_startup_type",(long*) &query_cache_startup_type,
+ 1, 0, 2, 0, 1},
{ "record_buffer", (long*) &my_default_record_cache_size,
128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, ~0L, MALLOC_OVERHEAD, IO_SIZE },
{ "record_rnd_buffer", (long*) &record_rnd_cache_size,
@@ -2967,22 +3060,16 @@ struct show_var_st init_vars[]= {
{"delayed_queue_size", (char*) &delayed_queue_size, SHOW_LONG},
{"flush", (char*) &myisam_flush, SHOW_MY_BOOL},
{"flush_time", (char*) &flush_time, SHOW_LONG},
-#ifdef HAVE_GEMINI_DB
- {"gemini_buffer_cache", (char*) &gemini_buffer_cache, SHOW_LONG},
- {"gemini_connection_limit", (char*) &gemini_connection_limit, SHOW_LONG},
- {"gemini_io_threads", (char*) &gemini_io_threads, SHOW_LONG},
- {"gemini_log_cluster_size", (char*) &gemini_log_cluster_size, SHOW_LONG},
- {"gemini_lock_table_size", (char*) &gemini_locktablesize, SHOW_LONG},
- {"gemini_lock_wait_timeout",(char*) &gemini_lock_wait_timeout, SHOW_LONG},
- {"gemini_recovery_options", (char*) &gemini_recovery_options_str, SHOW_CHAR_PTR},
- {"gemini_spin_retries", (char*) &gemini_spin_retries, SHOW_LONG},
-#endif
+ {"ft_min_word_len", (char*) &ft_min_word_len, SHOW_LONG},
+ {"ft_max_word_len", (char*) &ft_max_word_len, SHOW_LONG},
+ {"ft_max_word_len_for_sort",(char*) &ft_max_word_len_for_sort, SHOW_LONG},
+ {"ft_boolean_syntax", (char*) ft_boolean_syntax, SHOW_CHAR},
{"have_bdb", (char*) &have_berkeley_db, SHOW_HAVE},
- {"have_gemini", (char*) &have_gemini, SHOW_HAVE},
{"have_innodb", (char*) &have_innodb, SHOW_HAVE},
{"have_isam", (char*) &have_isam, SHOW_HAVE},
{"have_raid", (char*) &have_raid, SHOW_HAVE},
- {"have_openssl", (char*) &have_ssl, SHOW_HAVE},
+ {"have_symlink", (char*) &have_symlink, SHOW_HAVE},
+ {"have_openssl", (char*) &have_openssl, SHOW_HAVE},
{"init_file", (char*) &opt_init_file, SHOW_CHAR_PTR},
#ifdef HAVE_INNOBASE_DB
{"innodb_additional_mem_pool_size", (char*) &innobase_additional_mem_pool_size, SHOW_LONG },
@@ -3016,7 +3103,7 @@ struct show_var_st init_vars[]= {
{"log_update", (char*) &opt_update_log, SHOW_BOOL},
{"log_bin", (char*) &opt_bin_log, SHOW_BOOL},
{"log_slave_updates", (char*) &opt_log_slave_updates, SHOW_BOOL},
- {"log_long_queries", (char*) &opt_slow_log, SHOW_BOOL},
+ {"log_slow_queries", (char*) &opt_slow_log, SHOW_BOOL},
{"long_query_time", (char*) &long_query_time, SHOW_LONG},
{"low_priority_updates", (char*) &low_priority_updates, SHOW_BOOL},
{"lower_case_table_names", (char*) &lower_case_table_names, SHOW_LONG},
@@ -3032,10 +3119,11 @@ struct show_var_st init_vars[]= {
{"max_user_connections", (char*) &max_user_connections, SHOW_LONG},
{"max_tmp_tables", (char*) &max_tmp_tables, SHOW_LONG},
{"max_write_lock_count", (char*) &max_write_lock_count, SHOW_LONG},
+ {"myisam_bulk_insert_tree_size", (char*) &myisam_bulk_insert_tree_size, SHOW_INT},
{"myisam_max_extra_sort_file_size", (char*) &myisam_max_extra_sort_file_size,
SHOW_LONG},
{"myisam_max_sort_file_size",(char*) &myisam_max_sort_file_size, SHOW_LONG},
- {"myisam_recover_options", (char*) &myisam_recover_options, SHOW_LONG},
+ {"myisam_recover_options", (char*) &myisam_recover_options_str, SHOW_CHAR_PTR},
{"myisam_sort_buffer_size", (char*) &myisam_sort_buffer_size, SHOW_LONG},
#ifdef __NT__
{"named_pipe", (char*) &opt_enable_named_pipe, SHOW_BOOL},
@@ -3050,7 +3138,11 @@ struct show_var_st init_vars[]= {
{"protocol_version", (char*) &protocol_version, SHOW_INT},
{"record_buffer", (char*) &my_default_record_cache_size,SHOW_LONG},
{"record_rnd_buffer", (char*) &record_rnd_cache_size, SHOW_LONG},
+ {"rpl_recovery_rank", (char*) &rpl_recovery_rank, SHOW_LONG},
{"query_buffer_size", (char*) &query_buff_size, SHOW_LONG},
+ {"query_cache_limit", (char*) &query_cache.query_cache_limit, SHOW_LONG},
+ {"query_cache_size", (char*) &query_cache.query_cache_size, SHOW_LONG},
+ {"query_cache_startup_type",(char*) &query_cache_startup_type, SHOW_LONG},
{"safe_show_database", (char*) &opt_safe_show_db, SHOW_BOOL},
{"server_id", (char*) &server_id, SHOW_LONG},
{"slave_net_timeout", (char*) &slave_net_timeout, SHOW_LONG},
@@ -3098,16 +3190,21 @@ struct show_var_st status_vars[]= {
{"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_delete", (char*) (com_stat+(uint) SQLCOM_DELETE),SHOW_LONG},
+ {"Com_delete_multi", (char*) (com_stat+(uint) SQLCOM_DELETE_MULTI),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_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_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},
@@ -3122,6 +3219,7 @@ struct show_var_st status_vars[]= {
{"Com_rollback", (char*) (com_stat+(uint) SQLCOM_ROLLBACK),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_create", (char*) (com_stat+(uint) SQLCOM_SHOW_CREATE),SHOW_LONG},
{"Com_show_databases", (char*) (com_stat+(uint) SQLCOM_SHOW_DATABASES),SHOW_LONG},
@@ -3130,8 +3228,10 @@ struct show_var_st status_vars[]= {
{"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_stat", (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_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_stat", (char*) (com_stat+(uint) SQLCOM_SHOW_SLAVE_STAT),SHOW_LONG},
{"Com_show_status", (char*) (com_stat+(uint) SQLCOM_SHOW_STATUS),SHOW_LONG},
{"Com_show_tables", (char*) (com_stat+(uint) SQLCOM_SHOW_TABLES),SHOW_LONG},
@@ -3149,6 +3249,7 @@ struct show_var_st status_vars[]= {
{"Delayed_writes", (char*) &delayed_insert_writes, SHOW_LONG},
{"Delayed_errors", (char*) &delayed_insert_errors, 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_read_first", (char*) &ha_read_first_count, SHOW_LONG},
{"Handler_read_key", (char*) &ha_read_key_count, SHOW_LONG},
@@ -3156,6 +3257,7 @@ struct show_var_st status_vars[]= {
{"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_used", (char*) &_my_blocks_used, SHOW_LONG_CONST},
@@ -3171,19 +3273,55 @@ struct show_var_st status_vars[]= {
{"Open_streams", (char*) &my_stream_opened, SHOW_INT_CONST},
{"Opened_tables", (char*) &opened_tables, SHOW_LONG},
{"Questions", (char*) 0, SHOW_QUESTION},
+ {"Qcache_queries_in_cache", (char*) &query_cache.queries_in_cache, SHOW_LONG_CONST},
+ {"Qcache_inserts", (char*) &query_cache.inserts, SHOW_LONG},
+ {"Qcache_hits", (char*) &query_cache.hits, SHOW_LONG},
+ {"Qcache_not_cached", (char*) &query_cache.refused, SHOW_LONG},
+ {"Qcache_free_memory", (char*) &query_cache.free_memory,
+ SHOW_LONG_CONST},
+ {"Qcache_free_blocks", (char*) &query_cache.free_memory_blocks,
+ SHOW_LONG_CONST},
+ {"Qcache_total_blocks", (char*) &query_cache.total_blocks,
+ SHOW_LONG_CONST},
+ {"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},
- {"Slave_running", (char*) &slave_running, SHOW_BOOL},
{"Slave_open_temp_tables", (char*) &slave_open_temp_tables, SHOW_LONG},
+ {"Slave_running", (char*) 0, SHOW_SLAVE_RUNNING},
{"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},
+#ifdef HAVE_OPENSSL
+ {"ssl_accepts", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT},
+ {"ssl_finished_accepts", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT_GOOD},
+ {"ssl_finished_connects", (char*) 0, SHOW_SSL_CTX_SESS_CONNECT_GOOD},
+ {"ssl_accept_renegotiates", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE},
+ {"ssl_connect_renegotiates", (char*) 0, SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE},
+ {"ssl_callback_cache_hits", (char*) 0, SHOW_SSL_CTX_SESS_CB_HITS},
+ {"ssl_session_cache_hits", (char*) 0, SHOW_SSL_CTX_SESS_HITS},
+ {"ssl_session_cache_misses", (char*) 0, SHOW_SSL_CTX_SESS_MISSES},
+ {"ssl_session_cache_timeouts", (char*) 0, SHOW_SSL_CTX_SESS_TIMEOUTS},
+ {"ssl_used_session_cache_entries",(char*) 0, SHOW_SSL_CTX_SESS_NUMBER},
+ {"ssl_client_connects", (char*) 0, SHOW_SSL_CTX_SESS_CONNECT},
+ {"ssl_session_cache_overflows", (char*) 0, SHOW_SSL_CTX_SESS_CACHE_FULL},
+ {"ssl_session_cache_size", (char*) 0, SHOW_SSL_CTX_SESS_GET_CACHE_SIZE},
+ {"ssl_session_cache_mode", (char*) 0, SHOW_SSL_CTX_GET_SESSION_CACHE_MODE},
+ {"ssl_sessions_reused", (char*) 0, SHOW_SSL_SESSION_REUSED},
+ {"ssl_ctx_verify_mode", (char*) 0, SHOW_SSL_CTX_GET_VERIFY_MODE},
+ {"ssl_ctx_verify_depth", (char*) 0, SHOW_SSL_CTX_GET_VERIFY_DEPTH},
+ {"ssl_verify_mode", (char*) 0, SHOW_SSL_GET_VERIFY_MODE},
+ {"ssl_verify_depth", (char*) 0, SHOW_SSL_GET_VERIFY_DEPTH},
+ {"ssl_version", (char*) 0, SHOW_SSL_GET_VERSION},
+ {"ssl_cipher", (char*) 0, SHOW_SSL_GET_CIPHER},
+ {"ssl_cipher_list", (char*) 0, SHOW_SSL_GET_CIPHER_LIST},
+ {"ssl_default_timeout", (char*) 0, SHOW_SSL_GET_DEFAULT_TIMEOUT},
+#endif /* HAVE_OPENSSL */
{"Table_locks_immediate", (char*) &locks_immediate, SHOW_LONG},
{"Table_locks_waited", (char*) &locks_waited, SHOW_LONG},
{"Threads_cached", (char*) &cached_thread_count, SHOW_LONG_CONST},
@@ -3204,7 +3342,7 @@ static void use_help(void)
{
print_version();
printf("Use '--help' or '--no-defaults --help' for a list of available options\n");
-}
+}
static void usage(void)
{
@@ -3244,8 +3382,15 @@ Starts the MySQL server\n");
Set the default table type for tables\n\
--delay-key-write-for-all-tables\n\
Don't flush key buffers between writes for any MyISAM\n\
- table\n\
+ table\n");
+#ifdef HAVE_OPENSSL
+ puts("\
+ --des-key-file Load keys for des_encrypt() and des_encrypt\n\
+ from given file");
+#endif /* HAVE_OPENSSL */
+ puts("\
--enable-locking Enable system locking\n\
+ --enable-pstack Print a symbolic stack trace on failure\n\
-T, --exit-info Used for debugging; Use at your own risk!\n\
--flush Flush tables to disk between SQL commands\n\
-?, --help Display this help and exit\n\
@@ -3278,18 +3423,17 @@ Starts the MySQL server\n");
puts("\
-O, --set-variable var=option\n\
Give a variable an value. --help lists variables\n\
- -Sg, --skip-grant-tables\n\
- Start without grant tables. This gives all users\n\
- FULL ACCESS to all tables!\n\
--safe-mode Skip some optimize stages (for testing)\n\
--safe-show-database Don't show databases for which the user has no\n\
privileges\n\
- --safe-user-create Don't new users cretaion without privileges to the\n\
- mysql.user table\n\
+ --safe-user-create Don't allow new user creation by the user who has\n\
+ no write privileges to the mysql.user table\n\
--skip-concurrent-insert\n\
Don't use concurrent insert with MyISAM\n\
--skip-delay-key-write\n\
Ignore the delay_key_write option for all tables\n\
+ --skip-grant-tables Start without grant tables. This gives all users\n\
+ FULL ACCESS to all tables!\n\
--skip-host-cache Don't cache host names\n\
--skip-locking Don't use system locking. To use isamchk one has\n\
to shut down the server.\n\
@@ -3300,6 +3444,7 @@ Starts the MySQL server\n");
/* We have to break the string here because of VC++ limits */
puts("\
--skip-stack-trace Don't print a stack trace on failure\n\
+ --skip-symlink Don't allow symlinking of tables\n\
--skip-show-database Don't allow 'SHOW DATABASE' commands\n\
--skip-thread-priority\n\
Don't give threads different priorities.\n\
@@ -3307,7 +3452,8 @@ Starts the MySQL server\n");
-t, --tmpdir=path Path for temporary files\n\
--sql-mode=option[,option[,option...]] where option can be one of:\n\
REAL_AS_FLOAT, PIPES_AS_CONCAT, ANSI_QUOTES,\n\
- IGNORE_SPACE, SERIALIZE, ONLY_FULL_GROUP_BY.\n\
+ IGNORE_SPACE, SERIALIZE, ONLY_FULL_GROUP_BY,\n\
+ NO_UNSIGNED_SUBTRACTION.\n\
--transaction-isolation\n\
Default transaction isolation level\n\
--temp-pool Use a pool of temporary files\n\
@@ -3341,16 +3487,6 @@ Starts the MySQL server\n");
--skip-bdb Don't use berkeley db (will save memory)\n\
");
#endif /* HAVE_BERKELEY_DB */
-#ifdef HAVE_GEMINI_DB
- puts("\
- --gemini-recovery=mode Set Crash Recovery operating mode\n\
- (FULL, NONE, FORCE - default FULL)\n\
- --gemini-flush-log-at-commit\n\
- Every commit forces a write to the reovery log\n\
- --gemini-unbuffered-io Use unbuffered i/o\n\
- --skip-gemini Don't use gemini (will save memory)\n\
-");
-#endif
#ifdef HAVE_INNOBASE_DB
puts("\
--innodb_data_home_dir=dir The common part for Innodb table spaces\n\
@@ -3438,7 +3574,7 @@ static void set_options(void)
#endif
#if defined( HAVE_mit_thread ) || defined( __WIN__ ) || defined( HAVE_LINUXTHREADS )
- my_disable_locking = 1;
+ my_disable_locking=myisam_single_user= 1;
#endif
my_bind_addr = htonl( INADDR_ANY );
}
@@ -3450,6 +3586,16 @@ static void get_options(int argc,char **argv)
int c,option_index=0;
myisam_delay_key_write=1; // Allow use of this
+#ifndef HAVE_purify
+ my_use_symdir=1; // Use internal symbolic links
+#else
+ /* Symlinks gives too many warnings with purify */
+ my_disable_symlinks=1;
+ my_use_symdir=0;
+ have_symlink=SHOW_OPTION_DISABLED;
+#endif
+
+ optind = 0; // setup in case getopt() was called previously
while ((c=getopt_long(argc,argv,"ab:C:h:#::T::?l::L:O:P:sS::t:u:noVvWI?",
long_options, &option_index)) != EOF)
{
@@ -3509,6 +3655,18 @@ static void get_options(int argc,char **argv)
safemalloc_mem_limit = atoi(optarg);
#endif
break;
+ case OPT_RPL_RECOVERY_RANK:
+ rpl_recovery_rank=atoi(optarg);
+ break;
+ case OPT_SLAVE_LOAD_TMPDIR:
+ slave_load_tmpdir = my_strdup(optarg, MYF(MY_FAE));
+ break;
+ case OPT_OLD_RPL_COMPAT:
+ opt_old_rpl_compat = 1;
+ break;
+ case OPT_SHOW_SLAVE_AUTH_INFO:
+ opt_show_slave_auth_info = 1;
+ break;
case OPT_SOCKET:
mysql_unix_port= optarg;
break;
@@ -3541,20 +3699,6 @@ static void get_options(int argc,char **argv)
test_flags= optarg ? (uint) atoi(optarg) : 0;
opt_endinfo=1;
break;
- case 'S':
- if (!optarg)
- opt_specialflag|= SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE;
- else if (!strcmp(optarg,"l"))
- my_disable_locking=1;
- else if (!strcmp(optarg,"g"))
- opt_noacl=1;
- else
- {
- fprintf(stderr,"%s: Unrecognized option: %s\n",my_progname,optarg);
- use_help();
- exit(1);
- }
- break;
case (int) OPT_BIG_TABLES:
thd_startup_options|=OPTION_BIG_TABLES;
break;
@@ -3567,6 +3711,14 @@ static void get_options(int argc,char **argv)
opt_update_log=1;
opt_update_logname=optarg; // Use hostname.# if null
break;
+ case (int) OPT_RELAY_LOG_INDEX:
+ opt_relaylog_index_name = optarg;
+ break;
+ case (int) OPT_RELAY_LOG:
+ x_free(opt_relay_logname);
+ if (optarg && optarg[0])
+ opt_relay_logname=my_strdup(optarg,MYF(0));
+ break;
case (int) OPT_BIN_LOG_INDEX:
opt_binlog_index_name = optarg;
break;
@@ -3602,6 +3754,17 @@ static void get_options(int argc,char **argv)
opt_log_slave_updates = 1;
break;
+ case (int) OPT_INIT_RPL_ROLE:
+ {
+ int role;
+ if ((role=find_type(optarg, &rpl_role_typelib, 2)) <= 0)
+ {
+ fprintf(stderr, "Unknown replication role: %s\n", optarg);
+ exit(1);
+ }
+ rpl_status = (role == 1) ? RPL_AUTH_MASTER : RPL_IDLE_SLAVE;
+ break;
+ }
case (int)OPT_REPLICATE_IGNORE_DB:
{
i_string *db = new i_string(optarg);
@@ -3721,12 +3884,14 @@ static void get_options(int argc,char **argv)
break;
case (int) OPT_SKIP_NEW:
opt_specialflag|= SPECIAL_NO_NEW_FUNC;
- default_table_type=DB_TYPE_ISAM;
myisam_delay_key_write=0;
myisam_concurrent_insert=0;
myisam_recover_options= HA_RECOVER_NONE;
my_disable_symlinks=1;
+ my_use_symdir=0;
+ have_symlink=SHOW_OPTION_DISABLED;
ha_open_options&= ~HA_OPEN_ABORT_IF_CRASHED;
+ query_cache_size=0;
break;
case (int) OPT_SAFE:
opt_specialflag|= SPECIAL_SAFE_MODE;
@@ -3744,13 +3909,13 @@ static void get_options(int argc,char **argv)
opt_noacl=1;
break;
case (int) OPT_SKIP_LOCK:
- my_disable_locking=1;
+ my_disable_locking=myisam_single_user= 1;
break;
case (int) OPT_SKIP_HOST_CACHE:
opt_specialflag|= SPECIAL_NO_HOST_CACHE;
break;
case (int) OPT_ENABLE_LOCK:
- my_disable_locking=0;
+ my_disable_locking=myisam_single_user=0;
break;
case (int) OPT_USE_LOCKING:
my_disable_locking=0;
@@ -3761,6 +3926,9 @@ static void get_options(int argc,char **argv)
case (int) OPT_LONG_FORMAT:
opt_specialflag|=SPECIAL_LONG_LOG_FORMAT;
break;
+ case (int) OPT_NO_MIX_TYPE:
+ opt_no_mix_types = 1;
+ break;
case (int) OPT_SKIP_NETWORKING:
opt_disable_networking=1;
mysql_port=0;
@@ -3784,6 +3952,8 @@ static void get_options(int argc,char **argv)
break;
case (int) OPT_SKIP_SYMLINKS:
my_disable_symlinks=1;
+ my_use_symdir=0;
+ have_symlink=SHOW_OPTION_DISABLED;
break;
case (int) OPT_BIND_ADDRESS:
if (optarg && isdigit(optarg[0]))
@@ -3832,7 +4002,10 @@ static void get_options(int argc,char **argv)
break;
#endif
case (int) OPT_FLUSH:
- nisam_flush=myisam_flush=1;
+#ifdef HAVE_ISAM
+ nisam_flush=1;
+#endif
+ myisam_flush=1;
flush_time=0; // No auto flush
break;
case OPT_LOW_PRIORITY_UPDATES:
@@ -3873,6 +4046,11 @@ static void get_options(int argc,char **argv)
charsets_dir = mysql_charsets_dir;
break;
#include "sslopt-case.h"
+ case OPT_DES_KEY_FILE:
+#ifdef HAVE_OPENSSL
+ des_key_file=optarg;
+#endif
+ break;
case OPT_TX_ISOLATION:
{
int type;
@@ -3928,27 +4106,6 @@ static void get_options(int argc,char **argv)
have_berkeley_db=SHOW_OPTION_DISABLED;
#endif
break;
- case OPT_GEMINI_SKIP:
-#ifdef HAVE_GEMINI_DB
- gemini_skip=1;
- have_gemini=SHOW_OPTION_DISABLED;
- break;
- case OPT_GEMINI_RECOVER:
- gemini_recovery_options_str=optarg;
- if ((gemini_recovery_options=
- find_bit_type(optarg, &gemini_recovery_typelib)) == ~(ulong) 0)
- {
- fprintf(stderr, "Unknown option to gemini-recovery: %s\n",optarg);
- exit(1);
- }
- break;
- case OPT_GEMINI_FLUSH_LOG:
- gemini_options |= GEMOPT_FLUSH_LOG;
- break;
- case OPT_GEMINI_UNBUFFERED_IO:
- gemini_options |= GEMOPT_UNBUFFERED_IO;
-#endif
- break;
case OPT_INNODB_SKIP:
#ifdef HAVE_INNOBASE_DB
innodb_skip=1;
@@ -3979,13 +4136,16 @@ static void get_options(int argc,char **argv)
case OPT_INNODB_FAST_SHUTDOWN:
innobase_fast_shutdown= optarg ? test(atoi(optarg)) : 1;
break;
- case OPT_INNODB_UNIX_FILE_FLUSH_METHOD:
+ case OPT_INNODB_FLUSH_METHOD:
innobase_unix_file_flush_method=optarg;
break;
#endif /* HAVE_INNOBASE_DB */
+ case OPT_DO_PSTACK:
+ opt_do_pstack = 1;
+ break;
case OPT_MYISAM_RECOVER:
{
- if (!optarg)
+ if (!optarg || !optarg[0])
{
myisam_recover_options= HA_RECOVER_DEFAULT;
myisam_recover_options_str= myisam_recover_typelib.type_names[0];
@@ -4029,9 +4189,33 @@ static void get_options(int argc,char **argv)
case OPT_MASTER_INFO_FILE:
master_info_file=optarg;
break;
+ case OPT_RELAY_LOG_INFO_FILE:
+ relay_log_info_file=optarg;
+ break;
case OPT_MASTER_PORT:
master_port= atoi(optarg);
break;
+ case OPT_MASTER_SSL:
+ master_ssl=atoi(optarg);
+ break;
+ case OPT_MASTER_SSL_KEY:
+ master_ssl_key=optarg;
+ break;
+ case OPT_MASTER_SSL_CERT:
+ master_ssl_cert=optarg;
+ break;
+ case OPT_REPORT_HOST:
+ report_host=optarg;
+ break;
+ case OPT_REPORT_USER:
+ report_user=optarg;
+ break;
+ case OPT_REPORT_PASSWORD:
+ report_password=optarg;
+ break;
+ case OPT_REPORT_PORT:
+ report_port= atoi(optarg);
+ break;
case OPT_MASTER_CONNECT_RETRY:
master_connect_retry= atoi(optarg);
break;
@@ -4055,7 +4239,7 @@ static void get_options(int argc,char **argv)
exit(1);
}
}
- // Skipp empty arguments (from shell)
+ // Skip empty arguments (from shell)
while (argc != optind && !argv[optind][0])
optind++;
if (argc != optind)
@@ -4064,12 +4248,19 @@ static void get_options(int argc,char **argv)
use_help();
exit(1);
}
+ optind = 0; // setup so that getopt_long() can be called again
fix_paths();
default_table_type_name=ha_table_typelib.type_names[default_table_type-1];
default_tx_isolation_name=tx_isolation_typelib.type_names[default_tx_isolation];
/* To be deleted in MySQL 4.0 */
if (!record_rnd_cache_size)
record_rnd_cache_size=my_default_record_cache_size;
+
+ /* Fix variables that are base 1024*1024 */
+ myisam_max_temp_length= (my_off_t) min(((ulonglong) myisam_max_sort_file_size)*1024*1024, (ulonglong) MAX_FILE_SIZE);
+ myisam_max_extra_temp_length= (my_off_t) min(((ulonglong) myisam_max_extra_sort_file_size)*1024*1024, (ulonglong) MAX_FILE_SIZE);
+
+ myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size);
}
@@ -4087,12 +4278,34 @@ static char *get_relative_path(const char *path)
}
+/*
+ Fix filename and replace extension where 'dir' is relative to
+ mysql_real_data_home.
+ Return 1 if len(path) > FN_REFLEN
+*/
+
+bool
+fn_format_relative_to_data_home(my_string to, const char *name,
+ const char *dir, const char *extension)
+{
+ char tmp_path[FN_REFLEN];
+ if (!test_if_hard_path(dir))
+ {
+ strxnmov(tmp_path,sizeof(tmp_path)-1, mysql_real_data_home,
+ dir, NullS);
+ dir=tmp_path;
+ }
+ return !fn_format(to, name, dir, extension,
+ MY_REPLACE_EXT | MY_UNPACK_FILENAME | MY_SAFE_PATH);
+}
+
+
static void fix_paths(void)
{
(void) fn_format(mysql_home,mysql_home,"","",16); // Remove symlinks
- convert_dirname(mysql_home);
- convert_dirname(mysql_real_data_home);
- convert_dirname(language);
+ convert_dirname(mysql_home,mysql_home,NullS);
+ convert_dirname(mysql_real_data_home,mysql_real_data_home,NullS);
+ convert_dirname(language,language,NullS);
(void) my_load_path(mysql_home,mysql_home,""); // Resolve current dir
(void) my_load_path(mysql_real_data_home,mysql_real_data_home,mysql_home);
(void) my_load_path(pidfile_name,pidfile_name,mysql_real_data_home);
@@ -4102,7 +4315,7 @@ static void fix_paths(void)
strmake(buff,sharedir,sizeof(buff)-1); /* purecov: tested */
else
strxnmov(buff,sizeof(buff)-1,mysql_home,sharedir,NullS);
- convert_dirname(buff);
+ convert_dirname(buff,buff,NullS);
(void) my_load_path(language,language,buff);
/* If --character-sets-dir isn't given, use shared library dir */
@@ -4117,11 +4330,16 @@ static void fix_paths(void)
char *tmp= (char*) my_malloc(FN_REFLEN,MYF(MY_FAE));
if (tmp)
{
- strmake(tmp, mysql_tmpdir, FN_REFLEN-1);
- mysql_tmpdir=tmp;
- convert_dirname(mysql_tmpdir);
- mysql_tmpdir=(char*) my_realloc(mysql_tmpdir,(uint) strlen(mysql_tmpdir)+1,
+ char *end=convert_dirname(tmp, mysql_tmpdir, NullS);
+
+ mysql_tmpdir=(char*) my_realloc(tmp,(uint) (end-tmp)+1,
MYF(MY_HOLD_ON_ERROR));
+ allocated_mysql_tmpdir=mysql_tmpdir;
+ }
+ if (!slave_load_tmpdir)
+ {
+ // no need to check return value, if we fail, my_malloc() never returns
+ slave_load_tmpdir = (char*) my_strdup(mysql_tmpdir, MYF(MY_FAE));
}
}
@@ -4140,16 +4358,17 @@ static uint set_maximum_open_files(uint max_file_limit)
rlimit.rlim_cur=rlimit.rlim_max=max_file_limit;
if (setrlimit(RLIMIT_NOFILE,&rlimit))
{
- sql_print_error("Warning: setrlimit couldn't increase number of open files to more than %ld",
- old_cur); /* purecov: inspected */
+ sql_print_error("Warning: setrlimit couldn't increase number of open files to more than %lu (request: %u)",
+ old_cur, max_file_limit); /* purecov: inspected */
max_file_limit=old_cur;
}
else
{
(void) getrlimit(RLIMIT_NOFILE,&rlimit);
if ((uint) rlimit.rlim_cur != max_file_limit)
- sql_print_error("Warning: setrlimit returned ok, but didn't change limits. Max open files is %ld",
- (ulong) rlimit.rlim_cur); /* purecov: inspected */
+ sql_print_error("Warning: setrlimit returned ok, but didn't change limits. Max open files is %ld (request: %u)",
+ (ulong) rlimit.rlim_cur,
+ max_file_limit); /* purecov: inspected */
max_file_limit=rlimit.rlim_cur;
}
}
@@ -4197,6 +4416,7 @@ static ulong find_bit_type(const char *x, TYPELIB *bit_lib)
DBUG_PRINT("enter",("x: '%s'",x));
found=0;
+ found_end= 0;
pos=(my_string) x;
while (*pos == ' ') pos++;
found_end= *pos == 0;
@@ -4205,7 +4425,7 @@ static ulong find_bit_type(const char *x, TYPELIB *bit_lib)
if (!*(end=strcend(pos,','))) /* Let end point at fieldend */
{
while (end > pos && end[-1] == ' ')
- end--; /* Skipp end-space */
+ end--; /* Skip end-space */
found_end=1;
}
found_int=0; found_count=0;
diff --git a/sql/net_pkg.cc b/sql/net_pkg.cc
index 0b50b34c7bd..64c1b07a493 100644
--- a/sql/net_pkg.cc
+++ b/sql/net_pkg.cc
@@ -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 */
@@ -30,6 +30,7 @@ void send_error(NET *net, uint sql_errno, const char *err)
err ? err : net->last_error[0] ?
net->last_error : "NULL"));
+ query_cache_abort(net);
if (thd)
thd->query_error = 1; // needed to catch query errors during replication
if (!err)
@@ -51,6 +52,7 @@ void send_error(NET *net, uint sql_errno, const char *err)
{
if (thd && thd->bootstrap)
{
+ /* In bootstrap it's ok to print on stderr */
fprintf(stderr,"ERROR: %d %s\n",sql_errno,err);
}
DBUG_VOID_RETURN;
@@ -102,9 +104,9 @@ net_printf(NET *net, uint errcode, ...)
DBUG_ENTER("net_printf");
DBUG_PRINT("enter",("message: %u",errcode));
- if(thd) thd->query_error = 1;
- // if we are here, something is wrong :-)
-
+ if (thd)
+ thd->query_error = 1; // if we are here, something is wrong :-)
+ query_cache_abort(net); // Safety
va_start(args,errcode);
format=ER(errcode);
offset= net->return_errno ? 2 : 0;
@@ -119,6 +121,7 @@ net_printf(NET *net, uint errcode, ...)
{
if (thd && thd->bootstrap)
{
+ /* In bootstrap it's ok to print on stderr */
fprintf(stderr,"ERROR: %d %s\n",errcode,text_pos);
thd->fatal_error=1;
}
@@ -142,7 +145,7 @@ send_ok(NET *net,ha_rows affected_rows,ulonglong id,const char *message)
{
if (net->no_send_ok) // hack for re-parsing queries
return;
-
+
char buff[MYSQL_ERRMSG_SIZE+10],*pos;
DBUG_ENTER("send_ok");
buff[0]=0; // No fields
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index 750079b39a5..811f36bd82e 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 and read of logical packets to/from socket
** Writes are cached into net_buffer_length big packets.
@@ -22,95 +21,83 @@
** 3 byte length & 1 byte package-number.
*/
+#ifdef EMBEDDED_LIBRARY
+#define net_read_timeout net_read_timeout1
+#define net_write_timeout net_write_timeout1
+#endif
+
#ifdef __WIN__
#include <winsock.h>
#endif
-#include <global.h>
-#include <violite.h>
+#include <my_global.h>
+#include <mysql.h>
+#include <mysql_embed.h>
+#include <mysql_com.h>
+#include <mysqld_error.h>
#include <my_sys.h>
#include <m_string.h>
-#include "mysql.h"
-#include "mysqld_error.h"
+#include <my_net.h>
+#include <violite.h>
#include <signal.h>
#include <errno.h>
-#include <sys/types.h>
+
+/*
+ The following handles the differences when this is linked between the
+ client and the server.
+
+ This gives an error if a too big packet is found
+ The server can change this with the -O switch, but because the client
+ can't normally do this the client should have a bigger max_allowed_packet.
+*/
#ifdef MYSQL_SERVER
ulong max_allowed_packet=65536;
extern ulong net_read_timeout,net_write_timeout;
extern uint test_flags;
+#define USE_QUERY_CACHE
+extern void query_cache_insert(NET *net, const char *packet, ulong length);
#else
ulong max_allowed_packet=16*1024*1024L;
ulong net_read_timeout= NET_READ_TIMEOUT;
ulong net_write_timeout= NET_WRITE_TIMEOUT;
#endif
-ulong net_buffer_length=8192; /* Default length. Enlarged if necessary */
-#if !defined(__WIN__) && !defined(MSDOS)
-#include <sys/socket.h>
-#else
-#undef MYSQL_SERVER /* Win32 can't handle interrupts */
-#endif
-#if !defined(MSDOS) && !defined(__WIN__) && !defined(HAVE_BROKEN_NETINET_INCLUDES) && !defined(__BEOS__)
-#include <netinet/in_systm.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#if !defined(alpha_linux_port)
-#include <netinet/tcp.h>
+#if defined(__WIN__) || !defined(MYSQL_SERVER)
+ /* The following is because alarms doesn't work on windows. */
+#define NO_ALARM
#endif
-#endif
-#include "mysqld_error.h"
-#ifdef MYSQL_SERVER
+
+#ifndef NO_ALARM
#include "my_pthread.h"
-#include "thr_alarm.h"
void sql_print_error(const char *format,...);
#define RETRY_COUNT mysqld_net_retry_count
extern ulong mysqld_net_retry_count;
-#else
-
-#ifdef OS2 /* avoid name conflict */
-#define thr_alarm_t thr_alarm_t_net
-#define ALARM ALARM_net
-#endif
-
-typedef my_bool thr_alarm_t;
-typedef my_bool ALARM;
-#define thr_alarm_init(A) (*(A))=0
-#define thr_alarm_in_use(A) (*(A))
-#define thr_end_alarm(A)
-#define thr_alarm(A,B,C) local_thr_alarm((A),(B),(C))
-inline int local_thr_alarm(my_bool *A,int B __attribute__((unused)),ALARM *C __attribute__((unused)))
-{
- *A=1;
- return 0;
-}
-#define thr_got_alarm(A) 0
-#define RETRY_COUNT 1
-#endif
-
-#ifdef MYSQL_SERVER
-extern ulong bytes_sent, bytes_received;
+extern ulong bytes_sent, bytes_received;
extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
#else
#undef statistic_add
#define statistic_add(A,B,C)
-#endif
+#define DONT_USE_THR_ALARM
+#define RETRY_COUNT 1
+#endif /* NO_ALARM */
-/*
-** Give error if a too big packet is found
-** The server can change this with the -O switch, but because the client
-** can't normally do this the client should have a bigger max-buffer.
-*/
+#include "thr_alarm.h"
#define TEST_BLOCKING 8
-static int net_write_buff(NET *net,const char *packet,uint len);
+#define MAX_THREE_BYTES 255L*255L*255L
+
+ulong net_buffer_length=8192; /* Default length. Enlarged if necessary */
+
+static int net_write_buff(NET *net,const char *packet,ulong len);
/* Init with packet info */
int my_net_init(NET *net, Vio* vio)
{
- if (!(net->buff=(uchar*) my_malloc(net_buffer_length,MYF(MY_WME))))
+ if (!(net->buff=(uchar*) my_malloc((uint32) net_buffer_length+
+ NET_HEADER_SIZE + COMP_HEADER_SIZE,
+ MYF(MY_WME))))
return 1;
if (net_buffer_length > max_allowed_packet)
max_allowed_packet=net_buffer_length;
@@ -119,12 +106,13 @@ int my_net_init(NET *net, Vio* vio)
net->no_send_ok = 0;
net->error=0; net->return_errno=0; net->return_status=0;
net->timeout=(uint) net_read_timeout; /* Timeout for read */
- net->pkt_nr=0;
+ net->pkt_nr=net->compress_pkt_nr=0;
net->write_pos=net->read_pos = net->buff;
net->last_error[0]=0;
net->compress=0; net->reading_or_writing=0;
net->where_b = net->remain_in_buf=0;
net->last_errno=0;
+ net->query_cache_query=0;
if (vio != 0) /* If real connection */
{
@@ -157,8 +145,12 @@ static my_bool net_realloc(NET *net, ulong length)
net->last_errno=ER_NET_PACKET_TOO_LARGE;
return 1;
}
- pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
- if (!(buff=(uchar*) my_realloc((char*) net->buff, pkt_length, MYF(MY_WME))))
+ pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
+ /* We must allocate some extra bytes for the end 0 and to be able to
+ read big compressed blocks */
+ if (!(buff=(uchar*) my_realloc((char*) net->buff, (uint32) pkt_length +
+ NET_HEADER_SIZE + COMP_HEADER_SIZE,
+ MYF(MY_WME))))
{
net->error=1;
#ifdef MYSQL_SERVER
@@ -175,22 +167,22 @@ static my_bool net_realloc(NET *net, ulong length)
void net_clear(NET *net)
{
-#ifndef EXTRA_DEBUG
- int count; // One may get 'unused' warning
+#if !defined(EXTRA_DEBUG) && !defined(EMBEDDED_LIBRARY)
+ int count; /* One may get 'unused' warn */
bool is_blocking=vio_is_blocking(net->vio);
if (is_blocking)
vio_blocking(net->vio, FALSE);
if (!vio_is_blocking(net->vio)) /* Safety if SSL */
{
while ( (count = vio_read(net->vio, (char*) (net->buff),
- net->max_packet)) > 0)
+ (uint32) net->max_packet)) > 0)
DBUG_PRINT("info",("skipped %d bytes from file: %s",
count,vio_description(net->vio)));
if (is_blocking)
vio_blocking(net->vio, TRUE);
}
#endif /* EXTRA_DEBUG */
- net->pkt_nr=0; /* Ready for new command */
+ net->pkt_nr=net->compress_pkt_nr=0; /* Ready for new command */
net->write_pos=net->buff;
}
@@ -203,9 +195,12 @@ int net_flush(NET *net)
if (net->buff != net->write_pos)
{
error=net_real_write(net,(char*) net->buff,
- (uint) (net->write_pos - net->buff));
+ (ulong) (net->write_pos - net->buff));
net->write_pos=net->buff;
}
+ /* Sync packet number if using compression */
+ if (net->compress)
+ net->pkt_nr=net->compress_pkt_nr;
DBUG_RETURN(error);
}
@@ -214,44 +209,91 @@ int net_flush(NET *net)
** Write something to server/client buffer
*****************************************************************************/
-
/*
** Write a logical packet with packet header
** Format: Packet length (3 bytes), packet number(1 byte)
** When compression is used a 3 byte compression length is added
-** NOTE: If compression is used the original package is destroyed!
+** NOTE: If compression is used the original package is modified!
*/
int
my_net_write(NET *net,const char *packet,ulong len)
{
uchar buff[NET_HEADER_SIZE];
+ /*
+ Big packets are handled by splitting them in packets of MAX_THREE_BYTES
+ length. The last packet is always a packet that is < MAX_THREE_BYTES.
+ (The last packet may even have a lengt of 0)
+ */
+ while (len >= MAX_THREE_BYTES)
+ {
+ const ulong z_size = MAX_THREE_BYTES;
+ int3store(buff, z_size);
+ buff[3]= (uchar) net->pkt_nr++;
+ if (net_write_buff(net, (char*) buff, NET_HEADER_SIZE) ||
+ net_write_buff(net, packet, z_size))
+ return 1;
+ packet += z_size;
+ len-= z_size;
+ }
+ /* Write last packet */
int3store(buff,len);
- buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
+ buff[3]= (uchar) net->pkt_nr++;
if (net_write_buff(net,(char*) buff,NET_HEADER_SIZE))
return 1;
return net_write_buff(net,packet,len);
}
+/*
+ Send a command to the server.
+ As the command is part of the first data packet, we have to do some data
+ juggling to put the command in there, without having to create a new
+ packet.
+ This function will split big packets into sub-packets if needed.
+ (Each sub packet can only be 2^24 bytes)
+*/
+
int
net_write_command(NET *net,uchar command,const char *packet,ulong len)
{
+ ulong length=len+1; /* 1 extra byte for command */
uchar buff[NET_HEADER_SIZE+1];
- uint length=len+1; /* 1 extra byte for command */
+ uint header_size=NET_HEADER_SIZE+1;
+ buff[4]=command; /* For first packet */
+ if (length >= MAX_THREE_BYTES)
+ {
+ /* Take into account that we have the command in the first header */
+ len= MAX_THREE_BYTES -1;
+ do
+ {
+ int3store(buff, MAX_THREE_BYTES);
+ buff[3]= (uchar) net->pkt_nr++;
+ if (net_write_buff(net,(char*) buff, header_size) ||
+ net_write_buff(net,packet,len))
+ return 1;
+ packet+= len;
+ length-= MAX_THREE_BYTES;
+ len=MAX_THREE_BYTES;
+ header_size=NET_HEADER_SIZE;
+ } while (length >= MAX_THREE_BYTES);
+ len=length; /* Data left to be written */
+ }
int3store(buff,length);
- buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
- buff[4]=command;
- if (net_write_buff(net,(char*) buff,5))
- return 1;
- return test(net_write_buff(net,packet,len) || net_flush(net));
+ buff[3]= (uchar) net->pkt_nr++;
+ return test(net_write_buff(net,(char*) buff,header_size) ||
+ net_write_buff(net,packet,len) || net_flush(net));
}
+/*
+ Caching the data in a local buffer before sending it.
+ One can force the buffer to be flushed with 'net_flush'.
+*/
static int
-net_write_buff(NET *net,const char *packet,uint len)
+net_write_buff(NET *net,const char *packet,ulong len)
{
- uint left_length=(uint) (net->buff_end - net->write_pos);
+ ulong left_length=(ulong) (net->buff_end - net->write_pos);
while (len > left_length)
{
@@ -268,21 +310,30 @@ net_write_buff(NET *net,const char *packet,uint len)
return 0;
}
-/* Read and write using timeouts */
+
+/*
+ Read and write one packet using timeouts.
+ If needed, the packet is compressed before sending.
+*/
int
net_real_write(NET *net,const char *packet,ulong len)
{
- int length;
+ long int length;
char *pos,*end;
thr_alarm_t alarmed;
-#if !defined(__WIN__)
+#ifndef NO_ALARM
ALARM alarm_buff;
#endif
uint retry_count=0;
my_bool net_blocking = vio_is_blocking(net->vio);
DBUG_ENTER("net_real_write");
+#ifdef MYSQL_SERVER
+ if (net->query_cache_query != 0)
+ query_cache_insert(net, packet, len);
+#endif
+
if (net->error == 2)
DBUG_RETURN(-1); /* socket can't be used */
@@ -293,8 +344,8 @@ net_real_write(NET *net,const char *packet,ulong len)
ulong complen;
uchar *b;
uint header_length=NET_HEADER_SIZE+COMP_HEADER_SIZE;
- if (!(b=(uchar*) my_malloc(len + NET_HEADER_SIZE + COMP_HEADER_SIZE,
- MYF(MY_WME))))
+ if (!(b=(uchar*) my_malloc((uint32) len + NET_HEADER_SIZE +
+ COMP_HEADER_SIZE, MYF(MY_WME))))
{
#ifdef MYSQL_SERVER
net->last_errno=ER_OUT_OF_RESOURCES;
@@ -313,25 +364,25 @@ net_real_write(NET *net,const char *packet,ulong len)
}
int3store(&b[NET_HEADER_SIZE],complen);
int3store(b,len);
- b[3]=(uchar) (net->pkt_nr++);
+ b[3]=(uchar) (net->compress_pkt_nr++);
len+= header_length;
packet= (char*) b;
}
#endif /* HAVE_COMPRESS */
/* DBUG_DUMP("net",packet,len); */
-#ifdef MYSQL_SERVER
+#ifndef NO_ALARM
thr_alarm_init(&alarmed);
if (net_blocking)
thr_alarm(&alarmed,(uint) net_write_timeout,&alarm_buff);
#else
alarmed=0;
-#endif /* MYSQL_SERVER */
+#endif /* NO_ALARM */
pos=(char*) packet; end=pos+len;
while (pos != end)
{
- if ((int) (length=vio_write(net->vio,pos,(int) (end-pos))) <= 0)
+ if ((long) (length=vio_write(net->vio,pos,(uint32) (end-pos))) <= 0)
{
my_bool interrupted = vio_should_retry(net->vio);
#if (!defined(__WIN__) && !defined(__EMX__) && !defined(OS2))
@@ -408,14 +459,13 @@ net_real_write(NET *net,const char *packet,ulong len)
** Read something from server/clinet
*****************************************************************************/
-#ifdef MYSQL_SERVER
-
+#ifndef NO_ALARM
/*
Help function to clear the commuication buffer when we get a too
big packet
*/
-static void my_net_skip_rest(NET *net, ulong remain, thr_alarm_t *alarmed)
+static void my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed)
{
ALARM alarm_buff;
uint retry_count=0;
@@ -431,21 +481,27 @@ static void my_net_skip_rest(NET *net, ulong remain, thr_alarm_t *alarmed)
if ((int) (length=vio_read(net->vio,(char*) net->buff,remain)) <= 0L)
{
my_bool interrupted = vio_should_retry(net->vio);
- if (!thr_got_alarm(alarmed) && interrupted)
+ if (!thr_got_alarm(&alarmed) && interrupted)
{ /* Probably in MIT threads */
if (retry_count++ < RETRY_COUNT)
continue;
}
return;
}
- remain -=(ulong) length;
- statistic_add(bytes_received,(ulong) length,&LOCK_bytes_received);
+ remain -= (uint32) length;
+ statistic_add(bytes_received,length,&LOCK_bytes_received);
}
}
-#endif /* MYSQL_SERVER */
+#endif /* NO_ALARM */
+
+/*
+ Reads one packet to net->buff + net->where_b
+ Returns length of packet. Long packets are handled by my_net_read().
+ This function reallocates the net->buff buffer if necessary.
+*/
-static uint
+static ulong
my_real_read(NET *net, ulong *complen)
{
uchar *pos;
@@ -453,20 +509,20 @@ my_real_read(NET *net, ulong *complen)
uint i,retry_count=0;
ulong len=packet_error;
thr_alarm_t alarmed;
-#if (!defined(__WIN__) && !defined(__EMX__) && !defined(OS2)) || defined(MYSQL_SERVER)
+#ifndef NO_ALARM
ALARM alarm_buff;
#endif
my_bool net_blocking=vio_is_blocking(net->vio);
- ulong remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
- NET_HEADER_SIZE);
+ uint32 remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
+ NET_HEADER_SIZE);
*complen = 0;
net->reading_or_writing=1;
thr_alarm_init(&alarmed);
-#ifdef MYSQL_SERVER
+#ifndef NO_ALARM
if (net_blocking)
thr_alarm(&alarmed,net->timeout,&alarm_buff);
-#endif /* MYSQL_SERVER */
+#endif /* NO_ALARM */
pos = net->buff + net->where_b; /* net->packet -4 */
for (i=0 ; i < 2 ; i++)
@@ -535,7 +591,7 @@ my_real_read(NET *net, ulong *complen)
continue;
}
#endif
- DBUG_PRINT("error",("Couldn't read packet: remain: %d errno: %d length: %d alarmed: %d", remain,vio_errno(net->vio),length,alarmed));
+ DBUG_PRINT("error",("Couldn't read packet: remain: %lu errno: %d length: %ld alarmed: %d", remain,vio_errno(net->vio),length,alarmed));
len= packet_error;
net->error=2; /* Close socket */
#ifdef MYSQL_SERVER
@@ -544,7 +600,7 @@ my_real_read(NET *net, ulong *complen)
#endif
goto end;
}
- remain -= (ulong) length;
+ remain -= (uint32) length;
pos+= (ulong) length;
statistic_add(bytes_received,(ulong) length,&LOCK_bytes_received);
}
@@ -556,9 +612,9 @@ my_real_read(NET *net, ulong *complen)
if (net->buff[net->where_b] != (uchar) 255)
{
DBUG_PRINT("error",
- ("Packets out of order (Found: %d, expected %d)",
+ ("Packets out of order (Found: %d, expected %u)",
(int) net->buff[net->where_b + 3],
- (uint) (uchar) net->pkt_nr));
+ net->pkt_nr));
#ifdef EXTRA_DEBUG
fprintf(stderr,"Packets out of order (Found: %d, expected %d)\n",
(int) net->buff[net->where_b + 3],
@@ -571,7 +627,7 @@ my_real_read(NET *net, ulong *complen)
#endif
goto end;
}
- net->pkt_nr++;
+ net->compress_pkt_nr= ++net->pkt_nr;
#ifdef HAVE_COMPRESS
if (net->compress)
{
@@ -581,23 +637,24 @@ my_real_read(NET *net, ulong *complen)
#endif
len=uint3korr(net->buff+net->where_b);
+ if (!len) /* End of big multi-packet */
+ goto end;
helping = max(len,*complen) + net->where_b;
/* The necessary size of net->buff */
if (helping >= net->max_packet)
{
- /* We must allocate one extra byte for the end null */
- if (net_realloc(net,helping+1))
+ if (net_realloc(net,helping))
{
-#ifdef MYSQL_SERVER
+#ifndef NO_ALARM
if (i == 1)
- my_net_skip_rest(net, len, &alarmed);
+ my_net_skip_rest(net, (uint32) len, &alarmed);
#endif
len= packet_error; /* Return error */
goto end;
}
}
pos=net->buff + net->where_b;
- remain = len;
+ remain = (uint32) len;
}
}
@@ -611,7 +668,21 @@ end:
return(len);
}
-uint
+
+/*
+ Read a packet from the client/server and return it without the internal
+ package header.
+ If the packet is the first packet of a multi-packet packet
+ (which is indicated by the length of the packet = 0xffffff) then
+ all sub packets are read and concatenated.
+ If the packet was compressed, its uncompressed and the length of the
+ uncompressed packet is returned.
+
+ The function returns the length of the found packet or packet_error.
+ net->read_pos points to the read data.
+*/
+
+ulong
my_net_read(NET *net)
{
ulong len,complen;
@@ -620,65 +691,137 @@ my_net_read(NET *net)
if (!net->compress)
{
#endif
- len = my_real_read (net,&complen);
+ len = my_real_read(net,&complen);
+ if (len == MAX_THREE_BYTES)
+ {
+ /* First packet of a multi-packet. Concatenate the packets */
+ ulong save_pos = net->where_b;
+ ulong total_length=0;
+ do
+ {
+ net->where_b += len;
+ total_length += len;
+ len = my_real_read (net,&complen);
+ } while (len == MAX_THREE_BYTES);
+ if (len != packet_error)
+ len+= total_length;
+ net->where_b = save_pos;
+ }
net->read_pos = net->buff + net->where_b;
if (len != packet_error)
net->read_pos[len]=0; /* Safeguard for mysql_use_result */
return len;
#ifdef HAVE_COMPRESS
}
- if (net->remain_in_buf)
- net->buff[net->buf_length - net->remain_in_buf]=net->save_char;
- for (;;)
+ else
{
+ /* We are using the compressed protocol */
+
+ ulong buf_length= net->buf_length;
+ ulong start_of_packet= net->buf_length - net->remain_in_buf;
+ ulong first_packet_offset=start_of_packet;
+ uint read_length, multi_byte_packet=0;
+
if (net->remain_in_buf)
{
- uchar *pos = net->buff + net->buf_length - net->remain_in_buf;
- if (net->remain_in_buf >= 4)
+ /* Restore the character that was overwritten by the end 0 */
+ net->buff[start_of_packet]=net->save_char;
+ }
+ else
+ {
+ /* reuse buffer, as there is noting in it that we need */
+ buf_length=start_of_packet=first_packet_offset=0;
+ }
+ for (;;)
+ {
+ ulong packet_len;
+
+ if (buf_length - start_of_packet >= NET_HEADER_SIZE)
{
- net->length = uint3korr(pos);
- if (net->length <= net->remain_in_buf - 4)
+ read_length = uint3korr(net->buff+start_of_packet);
+ if (!read_length)
+ {
+ /* End of multi-byte packet */
+ start_of_packet += NET_HEADER_SIZE;
+ break;
+ }
+ if (read_length + NET_HEADER_SIZE <= buf_length - start_of_packet)
{
- /* We have a full packet */
- len=net->length;
- net->remain_in_buf -= net->length + 4;
- net->read_pos=pos + 4;
- break; /* We have a full packet */
+ if (multi_byte_packet)
+ {
+ /* Remove packet header for second packet */
+ memmove(net->buff + first_packet_offset + start_of_packet,
+ net->buff + first_packet_offset + start_of_packet +
+ NET_HEADER_SIZE,
+ buf_length - start_of_packet);
+ start_of_packet += read_length;
+ buf_length -= NET_HEADER_SIZE;
+ }
+ else
+ start_of_packet+= read_length + NET_HEADER_SIZE;
+
+ if (read_length != MAX_THREE_BYTES) /* last package */
+ {
+ multi_byte_packet= 0; /* No last zero len packet */
+ break;
+ }
+ multi_byte_packet= NET_HEADER_SIZE;
+ /* Move data down to read next data packet after current one */
+ if (first_packet_offset)
+ {
+ memmove(net->buff,net->buff+first_packet_offset,
+ buf_length-first_packet_offset);
+ buf_length-=first_packet_offset;
+ start_of_packet -= first_packet_offset;
+ first_packet_offset=0;
+ }
+ continue;
}
}
/* Move data down to read next data packet after current one */
- if (net->buf_length != net->remain_in_buf)
+ if (first_packet_offset)
{
- memmove(net->buff,pos,net->remain_in_buf);
- net->buf_length=net->remain_in_buf;
+ memmove(net->buff,net->buff+first_packet_offset,
+ buf_length-first_packet_offset);
+ buf_length-=first_packet_offset;
+ start_of_packet -= first_packet_offset;
+ first_packet_offset=0;
}
- net->where_b=net->buf_length;
- }
- else
- {
- net->where_b=0;
- net->buf_length=0;
- }
- if ((len = my_real_read(net,&complen)) == packet_error)
- break;
- if (my_uncompress((byte*) net->buff + net->where_b, &len, &complen))
- {
- len= packet_error;
- net->error=2; /* caller will close socket */
+ net->where_b=buf_length;
+ if ((packet_len = my_real_read(net,&complen)) == packet_error)
+ return packet_error;
+ if (my_uncompress((byte*) net->buff + net->where_b, &packet_len,
+ &complen))
+ {
+ net->error=2; /* caller will close socket */
#ifdef MYSQL_SERVER
- net->last_errno=ER_NET_UNCOMPRESS_ERROR;
+ net->last_errno=ER_NET_UNCOMPRESS_ERROR;
#endif
- break;
+ return packet_error;
+ }
+ buf_length+=packet_len;
}
- net->buf_length+=len;
- net->remain_in_buf+=len;
- }
- if (len != packet_error)
- {
+
+ net->read_pos= net->buff+ first_packet_offset + NET_HEADER_SIZE;
+ net->buf_length= buf_length;
+ net->remain_in_buf= (ulong) (buf_length - start_of_packet);
+ len = ((ulong) (start_of_packet - first_packet_offset) - NET_HEADER_SIZE -
+ multi_byte_packet);
net->save_char= net->read_pos[len]; /* Must be saved */
net->read_pos[len]=0; /* Safeguard for mysql_use_result */
}
+#endif /* HAVE_COMPRESS */
return len;
-#endif
}
+
+int net_request_file(NET* net, const char* fname)
+{
+ char tmp [FN_REFLEN+1],*end;
+ DBUG_ENTER("net_request_file");
+ tmp[0] = (char) 251; /* NULL_LENGTH */
+ end=strnmov(tmp+1,fname,sizeof(tmp)-2);
+ DBUG_RETURN(my_net_write(net,tmp,(uint) (end-tmp)) ||
+ net_flush(net));
+}
+
diff --git a/sql/opt_ft.h b/sql/opt_ft.h
index dcbbb8abcec..b055edc107c 100644
--- a/sql/opt_ft.h
+++ b/sql/opt_ft.h
@@ -29,7 +29,7 @@ public:
TABLE_REF *ref;
FT_SELECT(TABLE *table, TABLE_REF *tref) :
- QUICK_SELECT (table,tref->key,1), ref(tref) {}
+ QUICK_SELECT (table,tref->key,1), ref(tref) { init(); }
int init() { return error=file->ft_init(); }
int get_next() { return error=file->ft_read(record); }
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index b95b97d670f..20f198182f4 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -33,6 +33,7 @@
#include <m_ctype.h>
#include <nisam.h>
#include "sql_select.h"
+#include <assert.h>
#ifndef EXTRA_DEBUG
@@ -279,21 +280,21 @@ public:
typedef struct st_qsel_param {
- uint baseflag,keys,max_key_part;
- table_map prev_tables,read_tables,current_table;
TABLE *table;
- bool quick; // Don't calulate possible keys
KEY_PART *key_parts,*key_parts_end,*key[MAX_KEY];
+ MEM_ROOT *mem_root;
+ table_map prev_tables,read_tables,current_table;
+ uint baseflag,keys,max_key_part;
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
} PARAM;
-
static SEL_TREE * get_mm_parts(PARAM *param,Field *field,
Item_func::Functype type,Item *value,
Item_result cmp_type);
-static SEL_ARG *get_mm_leaf(Field *field,KEY_PART *key_part,
+static SEL_ARG *get_mm_leaf(PARAM *param,Field *field,KEY_PART *key_part,
Item_func::Functype type,Item *value);
static bool like_range(const char *ptr,uint length,char wild_prefix,
uint field_length, char *min_str,char *max_str,
@@ -382,7 +383,7 @@ SQL_SELECT::~SQL_SELECT()
#undef index // Fix for Unixware 7
QUICK_SELECT::QUICK_SELECT(TABLE *table,uint key_nr,bool no_alloc)
- :error(0),index(key_nr),max_used_key_length(0),head(table),
+ :dont_free(0),error(0),index(key_nr),max_used_key_length(0),head(table),
it(ranges),range(0)
{
if (!no_alloc)
@@ -399,13 +400,11 @@ QUICK_SELECT::QUICK_SELECT(TABLE *table,uint key_nr,bool no_alloc)
QUICK_SELECT::~QUICK_SELECT()
{
- file->index_end();
- free_root(&alloc,MYF(0));
-}
-
-int QUICK_SELECT::init()
-{
- return error=file->index_init(index);
+ if (!dont_free)
+ {
+ file->index_end();
+ free_root(&alloc,MYF(0));
+ }
}
QUICK_RANGE::QUICK_RANGE()
@@ -533,7 +532,7 @@ static int sel_cmp(Field *field, char *a,char *b,uint8 a_flag,uint8 b_flag)
}
if (*a)
goto end; // NULL where equal
- a++; b++; // Skipp NULL marker
+ a++; b++; // Skip NULL marker
}
cmp=field->key_cmp((byte*) a,(byte*) b);
if (cmp) return cmp < 0 ? -1 : 1; // The values differed
@@ -586,6 +585,9 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
uint idx;
double scan_time;
DBUG_ENTER("test_quick_select");
+ DBUG_PRINT("enter",("keys_to_use: %lu prev_tables: %lu const_tables: %lu",
+ (ulong) keys_to_use, (ulong) prev_tables,
+ (ulong) const_tables));
delete quick;
quick=0;
@@ -604,7 +606,7 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
if (limit < records)
read_time=(double) records+scan_time+1; // Force to use index
else if (read_time <= 2.0 && !force_quick_range)
- DBUG_RETURN(0); /* No nead for quick select */
+ DBUG_RETURN(0); /* No need for quick select */
DBUG_PRINT("info",("Time to scan table: %ld",(long) read_time));
@@ -623,6 +625,7 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
param.current_table= head->map;
param.table=head;
param.keys=0;
+ param.mem_root= &alloc;
current_thd->no_errors=1; // Don't warn about NULL
init_sql_alloc(&alloc,2048,0);
@@ -891,7 +894,7 @@ get_mm_parts(PARAM *param,Field *field, Item_func::Functype type,Item *value,
tree=new SEL_TREE();
if (!value || !(value->used_tables() & ~param->read_tables))
{
- sel_arg=get_mm_leaf(key_part->field,key_part,type,value);
+ sel_arg=get_mm_leaf(param,key_part->field,key_part,type,value);
if (!sel_arg)
continue;
if (sel_arg->type == SEL_ARG::IMPOSSIBLE)
@@ -911,7 +914,7 @@ get_mm_parts(PARAM *param,Field *field, Item_func::Functype type,Item *value,
static SEL_ARG *
-get_mm_leaf(Field *field,KEY_PART *key_part,
+get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
Item_func::Functype type,Item *value)
{
uint maybe_null=(uint) field->real_maybe_null();
@@ -956,7 +959,7 @@ get_mm_leaf(Field *field,KEY_PART *key_part,
field_length=length;
}
length+=offset;
- if (!(min_str= (char*) sql_alloc(length*2)))
+ if (!(min_str= (char*) alloc_root(param->mem_root, length*2)))
DBUG_RETURN(0);
max_str=min_str+length;
if (maybe_null)
@@ -1023,7 +1026,8 @@ get_mm_leaf(Field *field,KEY_PART *key_part,
if (type == Item_func::EQUAL_FUNC)
{
/* convert column_name <=> NULL -> column_name IS NULL */
- char *str= (char*) sql_alloc(1); // Get local copy of key
+ // Get local copy of key
+ char *str= (char*) alloc_root(param->mem_root,1);
if (!*str)
DBUG_RETURN(0);
*str = 1;
@@ -1032,7 +1036,8 @@ get_mm_leaf(Field *field,KEY_PART *key_part,
DBUG_RETURN(&null_element); // NULL is never true
}
// Get local copy of key
- char *str= (char*) sql_alloc(key_part->part_length+maybe_null);
+ char *str= (char*) alloc_root(param->mem_root,
+ key_part->part_length+maybe_null);
if (!str)
DBUG_RETURN(0);
if (maybe_null)
@@ -1098,7 +1103,7 @@ static bool like_range(const char *ptr,uint ptr_length,char escape,
{
if (*ptr == escape && ptr+1 != end)
{
- ptr++; // Skipp escape
+ ptr++; // Skip escape
*min_str++= *max_str++ = *ptr;
continue;
}
@@ -2232,7 +2237,7 @@ get_quick_select(PARAM *param,uint idx,SEL_ARG *key_tree)
else
{
quick->key_parts=(KEY_PART*)
- sql_memdup(param->key[idx],
+ memdup_root(&quick->alloc,(char*) param->key[idx],
sizeof(KEY_PART)*
param->table->key_info[param->real_keynr[idx]].key_parts);
}
@@ -2403,7 +2408,7 @@ QUICK_SELECT *get_quick_select_for_ref(TABLE *table, TABLE_REF *ref)
(key_info->flags & HA_NOSAME)) ? EQ_RANGE : 0);
if (!(quick->key_parts=key_part=(KEY_PART *)
- sql_alloc(sizeof(KEY_PART)*ref->key_parts)))
+ alloc_root(&quick->alloc,sizeof(KEY_PART)*ref->key_parts)))
goto err;
for (part=0 ; part < ref->key_parts ;part++,key_part++)
@@ -2455,8 +2460,8 @@ int QUICK_SELECT::get_next()
if ((error=file->index_first(record)))
DBUG_RETURN(error); // Empty table
if (cmp_next(range) == 0)
- DBUG_RETURN(0); // No matching records
- range=0; // To next range
+ DBUG_RETURN(0);
+ range=0; // No matching records; go to next range
continue;
}
if ((result = file->index_read(record,(byte*) range->min_key,
@@ -2516,6 +2521,225 @@ int QUICK_SELECT::cmp_next(QUICK_RANGE *range)
return (range->flag & NEAR_MAX) ? 1 : 0; // Exact match
}
+
+/*
+ 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
+ should be done is to factor out the data that is needed into a base
+ class (QUICK_SELECT), and then have two subclasses (_ASC and _DESC)
+ which handle the ranges and implement the get_next() function. But
+ 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)
+{
+ bool not_read_after_key = file->option_flag() & HA_NOT_READ_AFTER_KEY;
+ QUICK_RANGE *r;
+
+ it.rewind();
+ for (r = it++; r; r = it++)
+ {
+ rev_ranges.push_front(r);
+ if (not_read_after_key && range_reads_after_key(r) ||
+ test_if_null_range(r,used_key_parts))
+ {
+ it.rewind(); // Reset range
+ error = HA_ERR_UNSUPPORTED;
+ dont_free=1; // Don't free memory from 'q'
+ return;
+ }
+ }
+ /* Remove EQ_RANGE flag for keys that are not using the full key */
+ for (r = rev_it++; r; r = rev_it++)
+ {
+ if ((r->flag & EQ_RANGE) &&
+ head->key_info[index].key_length != r->max_length)
+ r->flag&= ~EQ_RANGE;
+ }
+ rev_it.rewind();
+ q->dont_free=1; // Don't free shared mem
+ delete q;
+}
+
+
+int QUICK_SELECT_DESC::get_next()
+{
+ DBUG_ENTER("QUICK_SELECT_DESC::get_next");
+
+ /* The max key is handled as follows:
+ * - if there is NO_MAX_RANGE, start at the end and move backwards
+ * - if it is an EQ_RANGE, which means that max key covers the entire
+ * key, go directly to the key and read through it (sorting backwards is
+ * same as sorting forwards)
+ * - if it is NEAR_MAX, go to the key or next, step back once, and
+ * move backwards
+ * - otherwise (not NEAR_MAX == include the key), go after the key,
+ * step back once, and move backwards
+ */
+
+ for (;;)
+ {
+ int result;
+ if (range)
+ { // Already read through key
+ result = ((range->flag & EQ_RANGE)
+ ? file->index_next_same(record, (byte*) range->min_key,
+ range->min_length) :
+ file->index_prev(record));
+ if (!result)
+ {
+ if (cmp_prev(*rev_it.ref()) == 0)
+ DBUG_RETURN(0);
+ }
+ else if (result != HA_ERR_END_OF_FILE)
+ DBUG_RETURN(result);
+ }
+
+ if (!(range=rev_it++))
+ DBUG_RETURN(HA_ERR_END_OF_FILE); // All ranges used
+
+ if (range->flag & NO_MAX_RANGE) // Read last record
+ {
+ int error;
+ if ((error=file->index_last(record)))
+ DBUG_RETURN(error); // Empty table
+ if (cmp_prev(range) == 0)
+ DBUG_RETURN(0);
+ range=0; // No matching records; go to next range
+ continue;
+ }
+
+ if (range->flag & EQ_RANGE)
+ {
+ result = file->index_read(record, (byte*) range->max_key,
+ range->max_length, HA_READ_KEY_EXACT);
+ }
+ else
+ {
+ DBUG_ASSERT(range->flag & NEAR_MAX || range_reads_after_key(range));
+ /* Note: even if max_key is only a prefix, HA_READ_AFTER_KEY will
+ * do the right thing - go past all keys which match the prefix */
+ result=file->index_read(record, (byte*) range->max_key,
+ range->max_length,
+ ((range->flag & NEAR_MAX) ?
+ HA_READ_KEY_EXACT : HA_READ_AFTER_KEY));
+ result = file->index_prev(record);
+ }
+ if (result)
+ {
+ if (result != HA_ERR_KEY_NOT_FOUND)
+ DBUG_RETURN(result);
+ range=0; // Not found, to next range
+ continue;
+ }
+ if (cmp_prev(range) == 0)
+ {
+ if (range->flag == (UNIQUE_RANGE | EQ_RANGE))
+ range = 0; // Stop searching
+ DBUG_RETURN(0); // Found key is in range
+ }
+ range = 0; // To next range
+ }
+}
+
+/*
+ * Returns 0 if found key is inside range (found key >= range->min_key).
+ */
+int QUICK_SELECT_DESC::cmp_prev(QUICK_RANGE *range)
+{
+ if (range->flag & NO_MIN_RANGE)
+ return (0); /* key can't be to small */
+
+ KEY_PART *key_part = key_parts;
+ for (char *key = range->min_key, *end = key + range->min_length;
+ key < end;
+ key += key_part++->part_length)
+ {
+ int cmp;
+ if (key_part->null_bit)
+ {
+ // this key part allows null values; NULL is lower than everything else
+ if (*key++)
+ {
+ // the range is expecting a null value
+ if (!key_part->field->is_null())
+ return 0; // not null -- still inside the range
+ continue; // null -- exact match, go to next key part
+ }
+ else if (key_part->field->is_null())
+ return 1; // null -- outside the range
+ }
+ if ((cmp = key_part->field->key_cmp((byte*) key,
+ key_part->part_length)) > 0)
+ return 0;
+ if (cmp < 0)
+ return 1;
+ }
+ return (range->flag & NEAR_MIN) ? 1 : 0; // Exact match
+}
+
+/*
+ * True if this range will require using HA_READ_AFTER_KEY
+ See comment in get_next() about this
+ */
+
+bool QUICK_SELECT_DESC::range_reads_after_key(QUICK_RANGE *range)
+{
+ return ((range->flag & (NO_MAX_RANGE | NEAR_MAX)) ||
+ !(range->flag & EQ_RANGE) ||
+ head->key_info[index].key_length != range->max_length) ? 1 : 0;
+}
+
+/* True if we are reading over a key that may have a NULL value */
+
+bool QUICK_SELECT_DESC::test_if_null_range(QUICK_RANGE *range,
+ uint used_key_parts)
+{
+ uint offset,end;
+ KEY_PART *key_part = key_parts,
+ *key_part_end= key_part+used_key_parts;
+
+ for (offset= 0, end = min(range->min_length, range->max_length) ;
+ offset < end && key_part != key_part_end ;
+ offset += key_part++->part_length)
+ {
+ uint null_length=test(key_part->null_bit);
+ if (!memcmp((char*) range->min_key+offset, (char*) range->max_key+offset,
+ key_part->part_length + null_length))
+ {
+ offset+=null_length;
+ continue;
+ }
+ if (null_length && range->min_key[offset])
+ return 1; // min_key is null and max_key isn't
+ // Range doesn't cover NULL. This is ok if there is no more null parts
+ break;
+ }
+ /*
+ If the next min_range is > NULL, then we can use this, even if
+ it's a NULL key
+ Example: SELECT * FROM t1 WHERE a = 2 AND b >0 ORDER BY a DESC,b DESC;
+
+ */
+ if (key_part != key_part_end && key_part->null_bit)
+ {
+ if (offset >= range->min_length || range->min_key[offset])
+ return 1; // Could be null
+ key_part++;
+ }
+ /*
+ If any of the key parts used in the ORDER BY could be NULL, we can't
+ use the key to sort the data.
+ */
+ for (; key_part != key_part_end ; key_part++)
+ if (key_part->null_bit)
+ return 1; // Covers null part
+ return 0;
+}
+
+
/*****************************************************************************
** Print a quick range for debugging
** TODO:
diff --git a/sql/opt_range.h b/sql/opt_range.h
index 247dd260817..f48a3936a17 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -48,15 +48,16 @@ class QUICK_RANGE :public Sql_alloc {
uint flag_arg)
: min_key((char*) sql_memdup(min_key_arg,min_length_arg+1)),
max_key((char*) sql_memdup(max_key_arg,max_length_arg+1)),
- min_length(min_length_arg),
- max_length(max_length_arg),
- flag(flag_arg)
+ min_length((uint16) min_length_arg),
+ max_length((uint16) max_length_arg),
+ flag((uint16) flag_arg)
{}
};
+
class QUICK_SELECT {
public:
- bool next;
+ bool next,dont_free;
int error;
uint index,max_used_key_length;
TABLE *head;
@@ -74,12 +75,30 @@ public:
QUICK_SELECT(TABLE *table,uint index_arg,bool no_alloc=0);
virtual ~QUICK_SELECT();
void reset(void) { next=0; it.rewind(); }
- virtual int init();
+ int init() { return error=file->index_init(index); }
virtual int get_next();
+ virtual bool reverse_sorted() { return 0; }
int cmp_next(QUICK_RANGE *range);
bool unique_key_range();
};
+
+class QUICK_SELECT_DESC: public QUICK_SELECT
+{
+public:
+ QUICK_SELECT_DESC(QUICK_SELECT *q, uint used_key_parts);
+ int get_next();
+ bool reverse_sorted() { return 1; }
+private:
+ int cmp_prev(QUICK_RANGE *range);
+ bool range_reads_after_key(QUICK_RANGE *range);
+ bool test_if_null_range(QUICK_RANGE *range, uint used_key_parts);
+ void reset(void) { next=0; rev_it.rewind(); }
+ List<QUICK_RANGE> rev_ranges;
+ List_iterator<QUICK_RANGE> rev_it;
+};
+
+
class SQL_SELECT :public Sql_alloc {
public:
QUICK_SELECT *quick; // If quick-select used
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index df49d52d54a..78878c40b37 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -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 */
@@ -32,7 +32,7 @@ static bool find_range_key(TABLE_REF *ref, Field* field,COND *cond);
int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
{
- List_iterator<Item> it(all_fields);
+ List_iterator_fast<Item> it(all_fields);
int const_result=1;
bool recalc_const_item=0;
table_map removed_tables=0;
@@ -205,7 +205,7 @@ uint count_table_entries(COND *cond,TABLE *table)
if (((Item_cond*) cond)->functype() == Item_func::COND_OR_FUNC)
return (cond->used_tables() & table->map) ? MAX_REF_PARTS+1 : 0;
- List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
+ List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list());
Item *item;
uint count=0;
while ((item=li++))
@@ -250,7 +250,7 @@ bool part_of_cond(COND *cond,Field *field)
if (((Item_cond*) cond)->functype() == Item_func::COND_OR_FUNC)
return 0; // Already checked
- List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
+ List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list());
Item *item;
while ((item=li++))
{
@@ -291,7 +291,7 @@ bool part_of_cond(COND *cond,Field *field)
static bool find_range_key(TABLE_REF *ref, Field* field, COND *cond)
{
if (!(field->flags & PART_KEY_FLAG))
- return 0; // Not part of a key. Skipp it
+ return 0; // Not part of a key. Skip it
TABLE *table=field->table;
if (table->file->option_flag() & HA_WRONG_ASCII_ORDER)
@@ -299,13 +299,14 @@ static bool find_range_key(TABLE_REF *ref, Field* field, COND *cond)
uint idx=0;
/* Check if some key has field as first key part */
- if (field->key_start && (! cond || ! (cond->used_tables() & table->map)))
+ if ((field->key_start & field->table->keys_in_use_for_query) &&
+ (! cond || ! (cond->used_tables() & table->map)))
{
for (key_map key=field->key_start ; !(key & 1) ; idx++)
key>>=1;
ref->key_length=0;
ref->key=idx;
- if (field->part_of_key & ((table_map) 1 << idx))
+ if (field->part_of_key & ((key_map) 1 << idx))
{
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
@@ -350,7 +351,7 @@ static bool find_range_key(TABLE_REF *ref, Field* field, COND *cond)
{
ref->key_length= (uint) (key_ptr-ref->key_buff);
ref->key=idx;
- if (field->part_of_key & ((table_map) 1 << idx))
+ if (field->part_of_key & ((key_map) 1 << idx))
{
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
diff --git a/sql/password.c b/sql/password.c
index 1c88aabcce2..48181ea18e6 100644
--- a/sql/password.c
+++ b/sql/password.c
@@ -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 */
@@ -34,7 +34,7 @@
This saves a hashed number as a string in the password field.
*****************************************************************************/
-#include <global.h>
+#include <my_global.h>
#include <my_sys.h>
#include <m_string.h>
#include "mysql.h"
diff --git a/sql/procedure.cc b/sql/procedure.cc
index 526bbe0feab..437bd82d6e5 100644
--- a/sql/procedure.cc
+++ b/sql/procedure.cc
@@ -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 */
diff --git a/sql/procedure.h b/sql/procedure.h
index 1583f1169ce..db0e0b7f9e2 100644
--- a/sql/procedure.h
+++ b/sql/procedure.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 */
diff --git a/sql/records.cc b/sql/records.cc
index d436f4f58fe..f156fdaf406 100644
--- a/sql/records.cc
+++ b/sql/records.cc
@@ -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 */
@@ -51,12 +51,7 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
tempfile= &select->file;
else
tempfile= table->io_cache;
- if (select && select->quick && (! tempfile || !tempfile->buffer))
- {
- DBUG_PRINT("info",("using rr_quick"));
- info->read_record=rr_quick;
- }
- else if (tempfile && my_b_inited(tempfile)) // Test if ref-records was used
+ if (tempfile && my_b_inited(tempfile)) // Test if ref-records was used
{
DBUG_PRINT("info",("using rr_from_tempfile"));
info->read_record=rr_from_tempfile;
@@ -84,8 +79,14 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
}
}
}
+ else if (select && select->quick)
+ {
+ DBUG_PRINT("info",("using rr_quick"));
+ info->read_record=rr_quick;
+ }
else if (table->record_pointers)
{
+ DBUG_PRINT("info",("using record_pointers"));
table->file->rnd_init(0);
info->cache_pos=table->record_pointers;
info->cache_end=info->cache_pos+ table->found_records*info->ref_length;
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
new file mode 100644
index 00000000000..257418d1682
--- /dev/null
+++ b/sql/repl_failsafe.cc
@@ -0,0 +1,853 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB & Sasha
+
+ This program is free software; 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 */
+
+// Sasha Pachev <sasha@mysql.com> is currently in charge of this file
+
+#include "mysql_priv.h"
+#include "repl_failsafe.h"
+#include "sql_repl.h"
+#include "slave.h"
+#include "sql_acl.h"
+#include "mini_client.h"
+#include "log_event.h"
+#include <mysql.h>
+#include <thr_alarm.h>
+
+#define SLAVE_LIST_CHUNK 128
+#define SLAVE_ERRMSG_SIZE (FN_REFLEN+64)
+
+
+RPL_STATUS rpl_status=RPL_NULL;
+pthread_mutex_t LOCK_rpl_status;
+pthread_cond_t COND_rpl_status;
+HASH slave_list;
+extern const char* any_db;
+
+const char *rpl_role_type[] = {"MASTER","SLAVE",NullS};
+TYPELIB rpl_role_typelib = {array_elements(rpl_role_type)-1,"",
+ rpl_role_type};
+
+const char* rpl_status_type[] = {"AUTH_MASTER","ACTIVE_SLAVE","IDLE_SLAVE",
+ "LOST_SOLDIER","TROOP_SOLDIER",
+ "RECOVERY_CAPTAIN","NULL",NullS};
+TYPELIB rpl_status_typelib= {array_elements(rpl_status_type)-1,"",
+ rpl_status_type};
+
+static Slave_log_event* find_slave_event(IO_CACHE* log,
+ const char* log_file_name,
+ char* errmsg);
+
+static int init_failsafe_rpl_thread(THD* thd)
+{
+ DBUG_ENTER("init_failsafe_rpl_thread");
+ thd->system_thread = thd->bootstrap = 1;
+ thd->client_capabilities = 0;
+ my_net_init(&thd->net, 0);
+ thd->net.timeout = slave_net_timeout;
+ thd->max_packet_length=thd->net.max_packet;
+ thd->master_access= ~0;
+ thd->priv_user = 0;
+ thd->system_thread = 1;
+ pthread_mutex_lock(&LOCK_thread_count);
+ thd->thread_id = thread_id++;
+ pthread_mutex_unlock(&LOCK_thread_count);
+
+ if (init_thr_lock() ||
+ my_pthread_setspecific_ptr(THR_THD, thd) ||
+ my_pthread_setspecific_ptr(THR_MALLOC, &thd->mem_root) ||
+ my_pthread_setspecific_ptr(THR_NET, &thd->net))
+ {
+ close_connection(&thd->net,ER_OUT_OF_RESOURCES); // is this needed?
+ end_thread(thd,0);
+ DBUG_RETURN(-1);
+ }
+
+ thd->mysys_var=my_thread_var;
+ thd->dbug_thread_id=my_thread_id();
+#if !defined(__WIN__) && !defined(OS2)
+ sigset_t set;
+ VOID(sigemptyset(&set)); // Get mask in use
+ VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
+#endif
+
+ thd->mem_root.free=thd->mem_root.used=0;
+ if (thd->max_join_size == (ulong) ~0L)
+ thd->options |= OPTION_BIG_SELECTS;
+
+ thd->proc_info="Thread initialized";
+ thd->version=refresh_version;
+ thd->set_time();
+ DBUG_RETURN(0);
+}
+
+void change_rpl_status(RPL_STATUS from_status, RPL_STATUS to_status)
+{
+ pthread_mutex_lock(&LOCK_rpl_status);
+ if (rpl_status == from_status || rpl_status == RPL_ANY)
+ rpl_status = to_status;
+ pthread_cond_signal(&COND_rpl_status);
+ pthread_mutex_unlock(&LOCK_rpl_status);
+}
+
+#define get_object(p, obj) \
+{\
+ uint len = (uint)*p++; \
+ if (p + len > p_end || len >= sizeof(obj)) \
+ goto err; \
+ strmake(obj,(char*) p,len); \
+ p+= len; \
+}\
+
+static inline int cmp_master_pos(Slave_log_event* sev, LEX_MASTER_INFO* mi)
+{
+ return cmp_master_pos(sev->master_log, sev->master_pos, mi->log_file_name,
+ mi->pos);
+}
+
+void unregister_slave(THD* thd, bool only_mine, bool need_mutex)
+{
+ if (need_mutex)
+ pthread_mutex_lock(&LOCK_slave_list);
+ if (thd->server_id)
+ {
+ SLAVE_INFO* old_si;
+ if ((old_si = (SLAVE_INFO*)hash_search(&slave_list,
+ (byte*)&thd->server_id, 4)) &&
+ (!only_mine || old_si->thd == thd))
+ hash_delete(&slave_list, (byte*)old_si);
+ }
+ if (need_mutex)
+ pthread_mutex_unlock(&LOCK_slave_list);
+}
+
+int register_slave(THD* thd, uchar* packet, uint packet_length)
+{
+ SLAVE_INFO *si;
+ int res = 1;
+ uchar* p = packet, *p_end = packet + packet_length;
+
+ if (check_access(thd, FILE_ACL, any_db))
+ return 1;
+
+ if (!(si = (SLAVE_INFO*)my_malloc(sizeof(SLAVE_INFO), MYF(MY_WME))))
+ goto err;
+
+ thd->server_id = si->server_id = uint4korr(p);
+ p += 4;
+ get_object(p,si->host);
+ get_object(p,si->user);
+ get_object(p,si->password);
+ si->port = uint2korr(p);
+ p += 2;
+ si->rpl_recovery_rank = uint4korr(p);
+ p += 4;
+ if (!(si->master_id = uint4korr(p)))
+ si->master_id = server_id;
+ si->thd = thd;
+ pthread_mutex_lock(&LOCK_slave_list);
+
+ unregister_slave(thd,0,0);
+ res = hash_insert(&slave_list, (byte*) si);
+ pthread_mutex_unlock(&LOCK_slave_list);
+ return res;
+
+err:
+ if (si)
+ my_free((gptr) si, MYF(MY_WME));
+ return res;
+}
+
+static uint32* slave_list_key(SLAVE_INFO* si, uint* len,
+ my_bool not_used __attribute__((unused)))
+{
+ *len = 4;
+ return &si->server_id;
+}
+
+static void slave_info_free(void *s)
+{
+ my_free((gptr) s, MYF(MY_WME));
+}
+
+void init_slave_list()
+{
+ hash_init(&slave_list, SLAVE_LIST_CHUNK, 0, 0,
+ (hash_get_key) slave_list_key, slave_info_free, 0);
+ pthread_mutex_init(&LOCK_slave_list, MY_MUTEX_INIT_FAST);
+}
+
+void end_slave_list()
+{
+ /* No protection by a mutex needed as we are only called at shutdown */
+ if (hash_inited(&slave_list))
+ {
+ hash_free(&slave_list);
+ pthread_mutex_destroy(&LOCK_slave_list);
+ }
+}
+
+static int find_target_pos(LEX_MASTER_INFO* mi, IO_CACHE* log, char* errmsg)
+{
+ uint32 log_pos = (uint32) mi->pos;
+ uint32 target_server_id = mi->server_id;
+
+ for (;;)
+ {
+ Log_event* ev;
+ if (!(ev = Log_event::read_log_event(log, (pthread_mutex_t*)0,
+ 0)))
+ {
+ if (log->error > 0)
+ strmov(errmsg, "Binary log truncated in the middle of event");
+ else if (log->error < 0)
+ strmov(errmsg, "I/O error reading binary log");
+ else
+ strmov(errmsg, "Could not find target event in the binary log");
+ return 1;
+ }
+
+ if (ev->log_pos == log_pos && ev->server_id == target_server_id)
+ {
+ delete ev;
+ mi->pos = my_b_tell(log);
+ return 0;
+ }
+
+ delete ev;
+ }
+}
+
+
+int translate_master(THD* thd, LEX_MASTER_INFO* mi, char* errmsg)
+{
+ LOG_INFO linfo;
+ char search_file_name[FN_REFLEN],last_log_name[FN_REFLEN];
+ IO_CACHE log;
+ File file = -1, last_file = -1;
+ pthread_mutex_t *log_lock;
+ const char* errmsg_p;
+ Slave_log_event* sev = 0;
+ my_off_t last_pos = 0;
+ int error = 1;
+ int cmp_res;
+ LINT_INIT(cmp_res);
+
+ if (!mysql_bin_log.is_open())
+ {
+ strmov(errmsg,"Binary log is not open");
+ return 1;
+ }
+
+ if (!server_id_supplied)
+ {
+ strmov(errmsg, "Misconfigured master - server id was not set");
+ return 1;
+ }
+
+ linfo.index_file_offset = 0;
+
+
+ search_file_name[0] = 0;
+
+ if (mysql_bin_log.find_first_log(&linfo, search_file_name))
+ {
+ strmov(errmsg,"Could not find first log");
+ return 1;
+ }
+ thd->current_linfo = &linfo;
+
+ bzero((char*) &log,sizeof(log));
+ log_lock = mysql_bin_log.get_log_lock();
+ pthread_mutex_lock(log_lock);
+
+ for (;;)
+ {
+ if ((file=open_binlog(&log, linfo.log_file_name, &errmsg_p)) < 0)
+ {
+ strmov(errmsg, errmsg_p);
+ goto err;
+ }
+
+ if (!(sev = find_slave_event(&log, linfo.log_file_name, errmsg)))
+ goto err;
+
+ cmp_res = cmp_master_pos(sev, mi);
+ delete sev;
+
+ if (!cmp_res)
+ {
+ /* Copy basename */
+ fn_format(mi->log_file_name, linfo.log_file_name, "","",1);
+ mi->pos = my_b_tell(&log);
+ goto mi_inited;
+ }
+ else if (cmp_res > 0)
+ {
+ if (!last_pos)
+ {
+ strmov(errmsg,
+ "Slave event in first log points past the target position");
+ goto err;
+ }
+ end_io_cache(&log);
+ (void) my_close(file, MYF(MY_WME));
+ if (init_io_cache(&log, (file = last_file), IO_SIZE, READ_CACHE, 0, 0,
+ MYF(MY_WME)))
+ {
+ errmsg[0] = 0;
+ goto err;
+ }
+ break;
+ }
+
+ strmov(last_log_name, linfo.log_file_name);
+ last_pos = my_b_tell(&log);
+
+ switch (mysql_bin_log.find_next_log(&linfo)) {
+ case LOG_INFO_EOF:
+ if (last_file >= 0)
+ (void)my_close(last_file, MYF(MY_WME));
+ last_file = -1;
+ goto found_log;
+ case 0:
+ break;
+ default:
+ strmov(errmsg, "Error reading log index");
+ goto err;
+ }
+
+ end_io_cache(&log);
+ if (last_file >= 0)
+ (void) my_close(last_file, MYF(MY_WME));
+ last_file = file;
+ }
+
+found_log:
+ my_b_seek(&log, last_pos);
+ if (find_target_pos(mi,&log,errmsg))
+ goto err;
+ fn_format(mi->log_file_name, last_log_name, "","",1); /* Copy basename */
+
+mi_inited:
+ error = 0;
+err:
+ pthread_mutex_unlock(log_lock);
+ end_io_cache(&log);
+ pthread_mutex_lock(&LOCK_thread_count);
+ thd->current_linfo = 0;
+ pthread_mutex_unlock(&LOCK_thread_count);
+ if (file >= 0)
+ (void) my_close(file, MYF(MY_WME));
+ if (last_file >= 0 && last_file != file)
+ (void) my_close(last_file, MYF(MY_WME));
+
+ return error;
+}
+
+// caller must delete result when done
+static Slave_log_event* find_slave_event(IO_CACHE* log,
+ const char* log_file_name,
+ char* errmsg)
+{
+ Log_event* ev;
+ int i;
+ bool slave_event_found = 0;
+ LINT_INIT(ev);
+
+ for (i = 0; i < 2; i++)
+ {
+ if (!(ev = Log_event::read_log_event(log, (pthread_mutex_t*)0, 0)))
+ {
+ my_snprintf(errmsg, SLAVE_ERRMSG_SIZE,
+ "Error reading event in log '%s'",
+ (char*)log_file_name);
+ return 0;
+ }
+ if (ev->get_type_code() == SLAVE_EVENT)
+ {
+ slave_event_found = 1;
+ break;
+ }
+ delete ev;
+ }
+ if (!slave_event_found)
+ {
+ my_snprintf(errmsg, SLAVE_ERRMSG_SIZE,
+ "Could not find slave event in log '%s'",
+ (char*)log_file_name);
+ delete ev;
+ return 0;
+ }
+
+ return (Slave_log_event*)ev;
+}
+
+
+int show_new_master(THD* thd)
+{
+ DBUG_ENTER("show_new_master");
+ List<Item> field_list;
+ char errmsg[SLAVE_ERRMSG_SIZE];
+ LEX_MASTER_INFO* lex_mi = &thd->lex.mi;
+
+ errmsg[0]=0; // Safety
+ if (translate_master(thd, lex_mi, errmsg))
+ {
+ if (errmsg[0])
+ net_printf(&thd->net, ER_ERROR_WHEN_EXECUTING_COMMAND,
+ "SHOW NEW MASTER", errmsg);
+ else
+ send_error(&thd->net, 0);
+
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ String* packet = &thd->packet;
+ field_list.push_back(new Item_empty_string("Log_name", 20));
+ field_list.push_back(new Item_empty_string("Log_pos", 20));
+ if (send_fields(thd, field_list, 1))
+ DBUG_RETURN(-1);
+ packet->length(0);
+ net_store_data(packet, lex_mi->log_file_name);
+ net_store_data(packet, (longlong)lex_mi->pos);
+ if (my_net_write(&thd->net, packet->ptr(), packet->length()))
+ DBUG_RETURN(-1);
+ send_eof(&thd->net);
+ DBUG_RETURN(0);
+ }
+}
+
+int update_slave_list(MYSQL* mysql)
+{
+ MYSQL_RES* res=0;
+ MYSQL_ROW row;
+ const char* error=0;
+ bool have_auth_info;
+ int port_ind;
+
+ if (mc_mysql_query(mysql,"SHOW SLAVE HOSTS",0) ||
+ !(res = mc_mysql_store_result(mysql)))
+ {
+ error = "Query error";
+ goto err;
+ }
+
+ switch (mc_mysql_num_fields(res))
+ {
+ case 5:
+ have_auth_info = 0;
+ port_ind=2;
+ break;
+ case 7:
+ have_auth_info = 1;
+ port_ind=4;
+ break;
+ default:
+ error = "Invalid number of fields in SHOW SLAVE HOSTS";
+ goto err;
+ }
+
+ pthread_mutex_lock(&LOCK_slave_list);
+
+ while ((row = mc_mysql_fetch_row(res)))
+ {
+ uint32 server_id;
+ SLAVE_INFO* si, *old_si;
+ server_id = atoi(row[0]);
+ if ((old_si = (SLAVE_INFO*)hash_search(&slave_list,
+ (byte*)&server_id,4)))
+ si = old_si;
+ else
+ {
+ if (!(si = (SLAVE_INFO*)my_malloc(sizeof(SLAVE_INFO), MYF(MY_WME))))
+ {
+ error = "Out of memory";
+ pthread_mutex_unlock(&LOCK_slave_list);
+ goto err;
+ }
+ si->server_id = server_id;
+ hash_insert(&slave_list, (byte*)si);
+ }
+ strnmov(si->host, row[1], sizeof(si->host));
+ si->port = atoi(row[port_ind]);
+ si->rpl_recovery_rank = atoi(row[port_ind+1]);
+ si->master_id = atoi(row[port_ind+2]);
+ if (have_auth_info)
+ {
+ strnmov(si->user, row[2], sizeof(si->user));
+ strnmov(si->password, row[3], sizeof(si->password));
+ }
+ }
+ pthread_mutex_unlock(&LOCK_slave_list);
+err:
+ if (res)
+ mc_mysql_free_result(res);
+ if (error)
+ {
+ sql_print_error("Error updating slave list:",error);
+ return 1;
+ }
+ return 0;
+}
+
+int find_recovery_captain(THD* thd, MYSQL* mysql)
+{
+
+ return 0;
+}
+
+pthread_handler_decl(handle_failsafe_rpl,arg)
+{
+ DBUG_ENTER("handle_failsafe_rpl");
+ THD *thd = new THD;
+ thd->thread_stack = (char*)&thd;
+ MYSQL* recovery_captain = 0;
+ pthread_detach_this_thread();
+ if (init_failsafe_rpl_thread(thd) || !(recovery_captain=mc_mysql_init(0)))
+ {
+ sql_print_error("Could not initialize failsafe replication thread");
+ goto err;
+ }
+ pthread_mutex_lock(&LOCK_rpl_status);
+ while (!thd->killed && !abort_loop)
+ {
+ bool break_req_chain = 0;
+ const char* msg = thd->enter_cond(&COND_rpl_status,
+ &LOCK_rpl_status, "Waiting for request");
+ pthread_cond_wait(&COND_rpl_status, &LOCK_rpl_status);
+ thd->proc_info="Processing request";
+ while (!break_req_chain)
+ {
+ switch (rpl_status)
+ {
+ case RPL_LOST_SOLDIER:
+ if (find_recovery_captain(thd, recovery_captain))
+ rpl_status=RPL_TROOP_SOLDIER;
+ else
+ rpl_status=RPL_RECOVERY_CAPTAIN;
+ break_req_chain=1; /* for now until other states are implemented */
+ break;
+ default:
+ break_req_chain=1;
+ break;
+ }
+ }
+ thd->exit_cond(msg);
+ }
+ pthread_mutex_unlock(&LOCK_rpl_status);
+err:
+ if (recovery_captain)
+ mc_mysql_close(recovery_captain);
+ delete thd;
+ my_thread_end();
+ pthread_exit(0);
+ DBUG_RETURN(0);
+}
+
+int show_slave_hosts(THD* thd)
+{
+ List<Item> field_list;
+ NET* net = &thd->net;
+ String* packet = &thd->packet;
+ DBUG_ENTER("show_slave_hosts");
+
+ field_list.push_back(new Item_empty_string("Server_id", 20));
+ field_list.push_back(new Item_empty_string("Host", 20));
+ if (opt_show_slave_auth_info)
+ {
+ field_list.push_back(new Item_empty_string("User",20));
+ field_list.push_back(new Item_empty_string("Password",20));
+ }
+ field_list.push_back(new Item_empty_string("Port",20));
+ field_list.push_back(new Item_empty_string("Rpl_recovery_rank", 20));
+ field_list.push_back(new Item_empty_string("Master_id", 20));
+
+ if (send_fields(thd, field_list, 1))
+ DBUG_RETURN(-1);
+
+ pthread_mutex_lock(&LOCK_slave_list);
+
+ for (uint i = 0; i < slave_list.records; ++i)
+ {
+ SLAVE_INFO* si = (SLAVE_INFO*) hash_element(&slave_list, i);
+ packet->length(0);
+ net_store_data(packet, si->server_id);
+ net_store_data(packet, si->host);
+ if (opt_show_slave_auth_info)
+ {
+ net_store_data(packet, si->user);
+ net_store_data(packet, si->password);
+ }
+ net_store_data(packet, (uint32) si->port);
+ net_store_data(packet, si->rpl_recovery_rank);
+ net_store_data(packet, si->master_id);
+ if (my_net_write(net, (char*)packet->ptr(), packet->length()))
+ {
+ pthread_mutex_unlock(&LOCK_slave_list);
+ DBUG_RETURN(-1);
+ }
+ }
+ pthread_mutex_unlock(&LOCK_slave_list);
+ send_eof(net);
+ DBUG_RETURN(0);
+}
+
+int connect_to_master(THD *thd, MYSQL* mysql, MASTER_INFO* mi)
+{
+ if (!mc_mysql_connect(mysql, mi->host, mi->user, mi->password, 0,
+ mi->port, 0, 0))
+ {
+ sql_print_error("Connection to master failed: %s",
+ mc_mysql_error(mysql));
+ return 1;
+ }
+ return 0;
+}
+
+
+static inline void cleanup_mysql_results(MYSQL_RES* db_res,
+ MYSQL_RES** cur, MYSQL_RES** start)
+{
+ for( ; cur >= start; --cur)
+ {
+ if (*cur)
+ mc_mysql_free_result(*cur);
+ }
+ mc_mysql_free_result(db_res);
+}
+
+
+static inline int fetch_db_tables(THD* thd, MYSQL* mysql, const char* db,
+ MYSQL_RES* table_res, MASTER_INFO* mi)
+{
+ MYSQL_ROW row;
+ for( row = mc_mysql_fetch_row(table_res); row;
+ row = mc_mysql_fetch_row(table_res))
+ {
+ TABLE_LIST table;
+ const char* table_name = row[0];
+ int error;
+ if (table_rules_on)
+ {
+ table.next = 0;
+ table.db = (char*)db;
+ table.real_name = (char*)table_name;
+ table.updating = 1;
+ if (!tables_ok(thd, &table))
+ continue;
+ }
+ if ((error = fetch_master_table(thd, db, table_name, mi, mysql)))
+ return error;
+ }
+ return 0;
+}
+
+
+int load_master_data(THD* thd)
+{
+ MYSQL mysql;
+ MYSQL_RES* master_status_res = 0;
+ bool slave_was_running = 0;
+ int error = 0;
+ const char* errmsg=0;
+ int restart_thread_mask;
+ mc_mysql_init(&mysql);
+
+ // we do not want anyone messing with the slave at all for the entire
+ // duration of the data load;
+ LOCK_ACTIVE_MI;
+ lock_slave_threads(active_mi);
+ init_thread_mask(&restart_thread_mask,active_mi,0 /*not inverse*/);
+ if (restart_thread_mask &&
+ (error=terminate_slave_threads(active_mi,restart_thread_mask,
+ 1 /*skip lock*/)))
+ {
+ send_error(&thd->net,error);
+ unlock_slave_threads(active_mi);
+ UNLOCK_ACTIVE_MI;
+ return 1;
+ }
+
+ if (connect_to_master(thd, &mysql, active_mi))
+ {
+ net_printf(&thd->net, error = ER_CONNECT_TO_MASTER,
+ mc_mysql_error(&mysql));
+ goto err;
+ }
+
+ // now that we are connected, get all database and tables in each
+ {
+ MYSQL_RES *db_res, **table_res, **table_res_end, **cur_table_res;
+ uint num_dbs;
+
+ if (mc_mysql_query(&mysql, "show databases", 0) ||
+ !(db_res = mc_mysql_store_result(&mysql)))
+ {
+ net_printf(&thd->net, error = ER_QUERY_ON_MASTER,
+ mc_mysql_error(&mysql));
+ goto err;
+ }
+
+ if (!(num_dbs = (uint) mc_mysql_num_rows(db_res)))
+ goto err;
+ // in theory, the master could have no databases at all
+ // and run with skip-grant
+
+ if (!(table_res = (MYSQL_RES**)thd->alloc(num_dbs * sizeof(MYSQL_RES*))))
+ {
+ net_printf(&thd->net, error = ER_OUTOFMEMORY);
+ goto err;
+ }
+
+ // this is a temporary solution until we have online backup
+ // capabilities - to be replaced once online backup is working
+ // we wait to issue FLUSH TABLES WITH READ LOCK for as long as we
+ // can to minimize the lock time
+ if (mc_mysql_query(&mysql, "FLUSH TABLES WITH READ LOCK", 0) ||
+ mc_mysql_query(&mysql, "SHOW MASTER STATUS",0) ||
+ !(master_status_res = mc_mysql_store_result(&mysql)))
+ {
+ net_printf(&thd->net, error = ER_QUERY_ON_MASTER,
+ mc_mysql_error(&mysql));
+ goto err;
+ }
+
+ // go through every table in every database, and if the replication
+ // rules allow replicating it, get it
+
+ table_res_end = table_res + num_dbs;
+
+ for(cur_table_res = table_res; cur_table_res < table_res_end;
+ cur_table_res++)
+ {
+ // since we know how many rows we have, this can never be NULL
+ MYSQL_ROW row = mc_mysql_fetch_row(db_res);
+ char* db = row[0];
+
+ /*
+ Do not replicate databases excluded by rules
+ also skip mysql database - in most cases the user will
+ mess up and not exclude mysql database with the rules when
+ he actually means to - in this case, he is up for a surprise if
+ his priv tables get dropped and downloaded from master
+ TODO - add special option, not enabled
+ by default, to allow inclusion of mysql database into load
+ data from master
+ */
+
+ if (!db_ok(db, replicate_do_db, replicate_ignore_db) ||
+ !strcmp(db,"mysql"))
+ {
+ *cur_table_res = 0;
+ continue;
+ }
+
+ if (mysql_rm_db(thd, db, 1,1) ||
+ mysql_create_db(thd, db, 0, 1))
+ {
+ send_error(&thd->net, 0, 0);
+ cleanup_mysql_results(db_res, cur_table_res - 1, table_res);
+ goto err;
+ }
+
+ if (mc_mysql_select_db(&mysql, db) ||
+ mc_mysql_query(&mysql, "show tables", 0) ||
+ !(*cur_table_res = mc_mysql_store_result(&mysql)))
+ {
+ net_printf(&thd->net, error = ER_QUERY_ON_MASTER,
+ mc_mysql_error(&mysql));
+ cleanup_mysql_results(db_res, cur_table_res - 1, table_res);
+ goto err;
+ }
+
+ if ((error = fetch_db_tables(thd,&mysql,db,*cur_table_res,active_mi)))
+ {
+ // we do not report the error - fetch_db_tables handles it
+ cleanup_mysql_results(db_res, cur_table_res, table_res);
+ goto err;
+ }
+ }
+
+ cleanup_mysql_results(db_res, cur_table_res - 1, table_res);
+
+ // adjust position in the master
+ if (master_status_res)
+ {
+ MYSQL_ROW row = mc_mysql_fetch_row(master_status_res);
+
+ /*
+ We need this check because the master may not be running with
+ log-bin, but it will still allow us to do all the steps
+ of LOAD DATA FROM MASTER - no reason to forbid it, really,
+ although it does not make much sense for the user to do it
+ */
+ if (row[0] && row[1])
+ {
+ strmake(active_mi->master_log_name, row[0],
+ sizeof(active_mi->master_log_name));
+ active_mi->master_log_pos = strtoull(row[1], (char**) 0, 10);
+ if (active_mi->master_log_pos < 4)
+ active_mi->master_log_pos = 4; // don't hit the magic number
+ active_mi->rli.pending = 0;
+ flush_master_info(active_mi);
+ }
+ mc_mysql_free_result(master_status_res);
+ }
+
+ if (mc_mysql_query(&mysql, "UNLOCK TABLES", 0))
+ {
+ net_printf(&thd->net, error = ER_QUERY_ON_MASTER,
+ mc_mysql_error(&mysql));
+ goto err;
+ }
+ }
+ thd->proc_info="purging old relay logs";
+ if (purge_relay_logs(&active_mi->rli,0 /* not only reset, but also reinit*/,
+ &errmsg))
+ {
+ send_error(&thd->net, 0, "Failed purging old relay logs");
+ unlock_slave_threads(active_mi);
+ UNLOCK_ACTIVE_MI;
+ return 1;
+ }
+ pthread_mutex_lock(&active_mi->rli.data_lock);
+ active_mi->rli.master_log_pos = active_mi->master_log_pos;
+ strnmov(active_mi->rli.master_log_name,active_mi->master_log_name,
+ sizeof(active_mi->rli.master_log_name));
+ flush_relay_log_info(&active_mi->rli);
+ pthread_cond_broadcast(&active_mi->rli.data_cond);
+ pthread_mutex_unlock(&active_mi->rli.data_lock);
+ thd->proc_info = "starting slave";
+ if (restart_thread_mask)
+ {
+ error=start_slave_threads(0 /* mutex not needed*/,
+ 1 /* wait for start*/,
+ active_mi,master_info_file,relay_log_info_file,
+ restart_thread_mask);
+ }
+
+err:
+ unlock_slave_threads(active_mi);
+ UNLOCK_ACTIVE_MI;
+ thd->proc_info = 0;
+
+ mc_mysql_close(&mysql); // safe to call since we always do mc_mysql_init()
+ if (!error)
+ send_ok(&thd->net);
+
+ return error;
+}
diff --git a/sql/repl_failsafe.h b/sql/repl_failsafe.h
new file mode 100644
index 00000000000..77bc03ce8c0
--- /dev/null
+++ b/sql/repl_failsafe.h
@@ -0,0 +1,38 @@
+#ifndef REPL_FAILSAFE_H
+#define REPL_FAILSAFE_H
+
+#include "mysql.h"
+#include "my_sys.h"
+#include "slave.h"
+
+typedef enum {RPL_AUTH_MASTER=0,RPL_ACTIVE_SLAVE,RPL_IDLE_SLAVE,
+ RPL_LOST_SOLDIER,RPL_TROOP_SOLDIER,
+ RPL_RECOVERY_CAPTAIN,RPL_NULL /* inactive */,
+ RPL_ANY /* wild card used by change_rpl_status */ } RPL_STATUS;
+extern RPL_STATUS rpl_status;
+
+extern pthread_mutex_t LOCK_rpl_status;
+extern pthread_cond_t COND_rpl_status;
+extern TYPELIB rpl_role_typelib, rpl_status_typelib;
+extern uint rpl_recovery_rank;
+extern const char* rpl_role_type[], *rpl_status_type[];
+
+pthread_handler_decl(handle_failsafe_rpl,arg);
+void change_rpl_status(RPL_STATUS from_status, RPL_STATUS to_status);
+int find_recovery_captain(THD* thd, MYSQL* mysql);
+int update_slave_list(MYSQL* mysql);
+
+extern HASH slave_list;
+
+int 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);
+int translate_master(THD* thd, LEX_MASTER_INFO* mi, char* errmsg);
+void init_slave_list();
+void end_slave_list();
+int register_slave(THD* thd, uchar* packet, uint packet_length);
+void unregister_slave(THD* thd, bool only_mine, bool need_mutex);
+
+#endif
diff --git a/sql/share/Makefile.am b/sql/share/Makefile.am
index b72f7493e20..c70ac9ccf57 100644
--- a/sql/share/Makefile.am
+++ b/sql/share/Makefile.am
@@ -28,5 +28,11 @@ install-data-local:
$(INSTALL_DATA) $(srcdir)/charsets/Index $(DESTDIR)$(pkgdatadir)/charsets/Index
$(INSTALL_DATA) $(srcdir)/charsets/*.conf $(DESTDIR)$(pkgdatadir)/charsets
+fix_errors:
+ for lang in @AVAILABLE_LANGUAGES@; \
+ do \
+ ../../extra/comp_err $(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 b/sql/share/charsets/Index
index b91e27e7c02..5cf30682cc0 100644
--- a/sql/share/charsets/Index
+++ b/sql/share/charsets/Index
@@ -1,6 +1,7 @@
# sql/share/charsets/Index
#
-# This file lists all of the available character sets.
+# This file lists all of the available character sets. Please keep this
+# file sorted by character set number.
big5 1
@@ -34,3 +35,4 @@ croat 27
gbk 28
cp1257 29
latin5 30
+latin1_de 31
diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt
index d1638bee16e..950ca4f6623 100644
--- a/sql/share/czech/errmsg.txt
+++ b/sql/share/czech/errmsg.txt
@@ -14,198 +14,198 @@
"isamchk",
"NE",
"ANO",
-"Nemohu vytvo-Bøit soubor '%-.64s' (chybový kód: %d)",-A
-"Nemohu vytvo-Bøit tabulku '%-.64s' (chybový kód: %d)",-A
-"Nemohu vytvo-Bøit databázi '%-.64s', chyba %d",-A
-"Nemohu vytvo-Bøit databázi '%-.64s', databáze ji¾ existuje",-A
-"Nemohu zru-B¹it databázi '%-.64s', databáze neexistuje",-A
-"Chyba p-Bøi ru¹ení databáze (nemohu vymazat '%-.64s', chyba %d)",-A
-"Chyba p-Bøi ru¹ení databáze (nemohu vymazat adresáø '%-.64s', chyba %d)",-A
-"Chyba p-Bøi výmazu '%-.64s' (chybový kód: %d)",-A
-"Nemohu -Bèíst záznam v systémové tabulce",-A
-"Nemohu z-Bískat stav '%-.64s' (chybový kód: %d)",-A
-"Chyba p-Bøi zji¹»ování pracovní adresáø (chybový kód: %d)",-A
-"Nemohu uzamknout soubor (chybov-Bý kód: %d)",-A
-"Nemohu otev-Bøít soubor '%-.64s' (chybový kód: %d)",-A
-"Nemohu naj-Bít soubor '%-.64s' (chybový kód: %d)",-A
-"Nemohu -Bèíst adresáø '%-.64s' (chybový kód: %d)",-A
-"Nemohu zm-Bìnit adresáø na '%-.64s' (chybový kód: %d)",-A
-"Z-Báznam byl zmìnìn od posledního ètení v tabulce '%-.64s'",-A
-"Disk je pln-Bý (%s), èekám na uvolnìní nìjakého místa ...",-A
-"Nemohu zapsat, zdvojen-Bý klíè v tabulce '%-.64s'",-A
-"Chyba p-Bøi zavírání '%-.64s' (chybový kód: %d)",-A
-"Chyba p-Bøi ètení souboru '%-.64s' (chybový kód: %d)",-A
-"Chyba p-Bøi pøejmenování '%-.64s' na '%-.64s' (chybový kód: %d)",-A
-"Chyba p-Bøi zápisu do souboru '%-.64s' (chybový kód: %d)",-A
-"'%-.64s' je zam-Bèen proti zmìnám",-A
-"T-Bøídìní pøeru¹eno",-A
+"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', chyba %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",-A
-"Obsluha tabulky '%-.64s' nem-Bá tento parametr",-A
-"Nemohu naj-Bít záznam v '%-.64s'",-A
-"Nespr-Bávná informace v souboru '%-.64s'",-A
-"Nespr-Bávný klíè pro tabulku '%-.64s'. Pokuste se ho opravit",-A
-"Star-Bý klíèový soubor pro '%-.64s'. Opravte ho.",-A
-"'%-.64s' je jen pro -Bètení",-A
-"M-Bálo pamìti. Pøestartujte daemona a zkuste znovu (je potøeba %d bytù)",-A
-"M-Bálo pamìti pro tøídìní. Zvy¹te velikost tøídícího bufferu",-A
-"Neo-Bèekávaný konec souboru pøi ètení '%-.64s' (chybový kód: %d)",-A
-"P-Bøíli¹ mnoho spojení",-A
-"M-Bálo prostoru/pamìti pro thread",-A
-"Nemohu zjistit jm-Béno stroje pro Va¹i adresu",-A
-"Chyba p-Bøi ustavování spojení",-A
-"P-Bøístup pro u¾ivatele '%-.32s@%-.64s' k databázi '%-.64s' není povolen",-A
-"P-Bøístup pro u¾ivatele '%-.32s@%-.64s' (s heslem %s)",-A
-"Nebyla vybr-Bána ¾ádná databáze",-A
-"Nezn-Bámý pøíkaz",-A
-"Sloupec '%-.64s' nem-Bù¾e být null",-A
-"Nezn-Bámá databáze '%-.64s'",-A
-"Tabulka '%-.64s' ji-B¾ existuje",-A
-"Nezn-Bámá tabulka '%-.64s'",-A
-"Sloupec '%-.64s' v %s nen-Bí zcela jasný",-A
-"Prob-Bíhá ukonèování práce serveru",-A
-"Nezn-Bámý sloupec '%-.64s' v %s",-A
-"Pou-B¾ité '%-.64s' nebylo v group by",-A
-"Nemohu pou-B¾ít group na '%-.64s'",-A
-"P-Bøíkaz obsahuje zároveò funkci sum a sloupce",-A
-"Po-Bèet sloupcù neodpovídá zadané hodnotì",-A
-"Jm-Béno identifikátoru '%-.64s' je pøíli¹ dlouhé",-A
-"Zdvojen-Bé jméno sloupce '%-.64s'",-A
-"Zdvojen-Bé jméno klíèe '%-.64s'",-A
-"Zvojen-Bý klíè '%-.64s' (èíslo klíèe %d)",-A
-"Chybn-Bá specifikace sloupce '%-.64s'",-A
-"%s bl-Bízko '%-.64s' na øádku %d",-A
-"V-Býsledek dotazu je prázdný",-A
-"Nejednozna-Bèná tabulka/alias: '%-.64s'",-A
-"Chybn-Bá defaultní hodnota pro '%-.64s'",-A
-"Definov-Báno více primárních klíèù",-A
-"Zad-Báno pøíli¹ mnoho klíèù, je povoleno nejvíce %d klíèù",-A
-"Zad-Báno pøíli¹ mnoho èást klíèù, je povoleno nejvíce %d èástí",-A
-"Zadan-Bý klíè byl pøíli¹ dlouhý, nejvìt¹í délka klíèe je %d",-A
-"Kl-Bíèový sloupec '%-.64s' v tabulce neexistuje",-A
-"Blob sloupec '%-.64s' nem-Bù¾e být pou¾it jako klíè",-A
-"P-Bøíli¹ velká délka sloupce '%-.64s' (nejvíce %d). Pou¾ijte BLOB",-A
-"M-Bù¾ete mít pouze jedno AUTO pole a to musí být definováno jako klíè",-A
-"%s: p-Bøipraven na spojení\n",-A
-"%s: norm-Bální ukonèení\n",-A
-"%s: p-Bøijat signal %d, konèím\n",-A
-"%s: ukon-Bèení práce hotovo\n",-A
-"%s: n-Básilné uzavøení threadu %ld u¾ivatele '%-.64s'\n",-A
-"Nemohu vytvo-Bøit IP socket",-A
-"Tabulka '%-.64s' nem-Bá index odpovídající CREATE INDEX. Vytvoøte tabulku znovu",-A
-"Argument separ-Bátoru polo¾ek nebyl oèekáván. Pøeètìte si manuál",-A
-"Nen-Bí mo¾né pou¾ít pevný rowlength s BLOBem. Pou¾ijte 'fields terminated by'.",-A
-"Soubor '%-.64s' mus-Bí být v adresáøi databáze nebo èitelný pro v¹echny",-A
-"Soubor '%-.64s' ji-B¾ existuje",-A
-"Z-Báznamù: %ld Vymazáno: %ld Pøeskoèeno: %ld Varování: %ld",-A
-"Z-Báznamù: %ld Zdvojených: %ld",-A
-"Chybn-Bá podèást klíèe -- není to øetìzec nebo je del¹í ne¾ délka èásti klíèe",-A
-"Nen-Bí mo¾né vymazat v¹echny polo¾ky s ALTER TABLE. Pou¾ijte DROP TABLE",-A
-"Nemohu zru-B¹it '%-.64s' (provést DROP). Zkontrolujte, zda neexistují záznamy/klíèe",-A
-"Z-Báznamù: %ld Zdvojených: %ld Varování: %ld",-A
-"INSERT TABLE '%-.64s' nen-Bí dovoleno v seznamu tabulek FROM",-A
-"Nezn-Bámá identifikace threadu: %lu",-A
-"Nejste vlastn-Bíkem threadu %lu",-A
-"Nejsou pou-B¾ity ¾ádné tabulky",-A
-"P-Bøíli¹ mnoho øetìzcù pro sloupec %s a SET",-A
-"Nemohu vytvo-Bøit jednoznaèné jméno logovacího souboru %s.(1-999)\n",-A
-"Tabulka '%-.64s' byla zam-Bèena s READ a nemù¾e být zmìnìna",-A
-"Tabulka '%-.64s' nebyla zam-Bèena s LOCK TABLES",-A
-"Blob polo-B¾ka '%-.64s' nemù¾e mít defaultní hodnotu",-A
-"Nep-Bøípustné jméno databáze '%-.64s'",-A
-"Nep-Bøípustné jméno tabulky '%-.64s'",-A
-"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 OPTION SQL_BIG_SELECTS=1",-A
-"Nezn-Bámá chyba",-A
-"Nezn-Bámá procedura %s",-A
-"Chybn-Bý poèet parametrù procedury %s",-A
-"Chybn-Bé parametry procedury %s",-A
-"Nezn-Bámá tabulka '%-.64s' v %s",-A
-"Polo-B¾ka '%-.64s' je zadána dvakrát",-A
-"Nespr-Bávné pou¾ití funkce group",-A
-"Tabulka '%-.64s' pou-B¾ívá roz¹íøení, které v této verzi MySQL není",-A
-"Tabulka mus-Bí mít alespoò jeden sloupec",-A
-"Tabulka '%-.64s' je pln-Bá",-A
-"Nezn-Bámá znaková sada: '%-.64s'",-A
-"P-Bøíli¹ mnoho tabulek, MySQL jich mù¾e mít v joinu jen %d",-A
-"P-Bøíli¹ mnoho polo¾ek",-A
-"-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",-A
-"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",-A
-"V OUTER JOIN byl nalezen k-Bøí¾ový odkaz. Provìøte ON podmínky",-A
-"Sloupec '%-.32s' je pou-B¾it s UNIQUE nebo INDEX, ale není definován jako NOT NULL",-A
-"Nemohu na-Bèíst funkci '%-.64s'",-A
+"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í\n",
+"%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",
+"INSERT TABLE '%-.64s' nen-Bí dovoleno v seznamu tabulek FROM",
+"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 OPTION 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",-A
-"Funkce '%-.64s' ji-B¾ existuje",-A
-"Nemohu otev-Bøít sdílenou knihovnu '%-.64s' (errno: %d %s)",-A
-"Nemohu naj-Bít funkci '%-.64s' v knihovnì'",-A
-"Funkce '%-.64s' nen-Bí definována",-A
-"Stroj '%-.64s' je zablokov-Bán kvùli mnoha chybám pøi pøipojování. Odblokujete pou¾itím 'mysqladmin flush-hosts'",-A
-"Stroj '%-.64s' nem-Bá povoleno se k tomuto MySQL serveru pøipojit",-A
-"Pou-B¾íváte MySQL jako anonymní u¾ivatel a anonymní u¾ivatelé nemají povoleno mìnit hesla",-A
-"Na zm-Bìnu hesel ostatním musíte mít právo provést update tabulek v databázi mysql",-A
-"V tabulce user nen-Bí ¾ádný odpovídající øádek",-A
-"Nalezen-Bých øádkù: %ld Zmìnìno: %ld Varování: %ld",-A
-"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",-A
-"Po-Bèet sloupcù neodpovídá poètu hodnot na øádku %ld",-A
-"Nemohu znovuotev-Bøít tabulku: '%-.64s',-A
-"Neplatn-Bé u¾ití hodnoty NULL",-A
-"Regul-Bární výraz vrátil chybu '%-.64s'",-A
-"Pokud nen-Bí ¾ádná GROUP BY klauzule, není dovoleno souèasné pou¾ití GROUP polo¾ek (MIN(),MAX(),COUNT()...) s ne GROUP polo¾kami",-A
-"Neexistuje odpov-Bídající grant pro u¾ivatele '%-.32s' na stroji '%-.64s'",-A
-"%-.16s p-Bøíkaz nepøístupný pro u¾ivatele: '%-.32s@%-.64s' pro tabulku '%-.64s'",-A
-"%-.16s p-Bøíkaz nepøístupný pro u¾ivatele: '%-.32s@%-.64s' pro sloupec '%-.64s' v tabulce '%-.64s'",-A
-"Neplatn-Bý pøíkaz GRANT/REVOKE. Prosím, pøeètìte si v manuálu, jaká privilegia je mo¾né pou¾ít.",-A
-"Argument p-Bøíkazu GRANT u¾ivatel nebo stroj je pøíli¹ dlouhý",-A
+"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'",-A
-"Pou-B¾itý pøíkaz není v této verzi MySQL povolen",-A
-"Va-B¹e syntaxe je nìjaká divná",-A
-"Zpo-B¾dìný insert threadu nebyl schopen získat po¾adovaný zámek pro tabulku %-.64s",-A
-"P-Bøíli¹ mnoho zpo¾dìných threadù",-A
-"Zru-B¹eno spojení %ld do databáze: '%-.64s' u¾ivatel: '%-.64s' (%s)",-A
-"Zji-B¹tìn pøíchozí packet del¹í ne¾ 'max_allowed_packet'",-A
-"Zji-B¹tìna chyba pøi ètení z roury spojení",-A
-"Zji-B¹tìna chyba fcntl()",-A
-"P-Bøíchozí packety v chybném poøadí",-A
-"Nemohu rozkomprimovat komunika-Bèní packet",-A
-"Zji-B¹tìna chyba pøi ètení komunikaèního packetu",-A
-"Zji-B¹tìn timeout pøi ètení komunikaèního packetu",-A
-"Zji-B¹tìna chyba pøi zápisu komunikaèního packetu",-A
-"Zji-B¹tìn timeout pøi zápisu komunikaèního packetu",-A
-"V-Býsledný øetìzec je del¹í ne¾ max_allowed_packet",-A
-"Typ pou-B¾ité tabulky nepodporuje BLOB/TEXT sloupce",-A
-"Typ pou-B¾ité tabulky nepodporuje AUTO_INCREMENT sloupce",-A
-"INSERT DELAYED nen-Bí mo¾no s tabulkou '%-.64s' pou¾ít, proto¾e je zamèená pomocí LOCK TABLES",-A
-"Nespr-Bávné jméno sloupce '%-.100s'",-A
-"Handler pou-B¾ité tabulky neumí indexovat sloupce '%-.64s'",-A
-"V-B¹echny tabulky v MERGE tabulce nejsou definovány stejnì",-A
-"Kv-Bùli unique constraintu nemozu zapsat do tabulky '%-.64s'",-A
-"BLOB sloupec '%-.64s' je pou-B¾it ve specifikaci klíèe bez délky",-A
-"V-B¹echny èásti primárního klíèe musejí být NOT NULL; pokud potøebujete NULL, pou¾ijte UNIQUE",-A
-"V-Býsledek obsahuje více ne¾ jeden øádek",-A
-"Tento typ tabulky vy-B¾aduje primární klíè",-A
-"Tato verze MySQL nen-Bí zkompilována s podporou RAID",-A
-"Update tabulky bez WHERE s kl-Bíèem není v módu bezpeèných update dovoleno",-A
-"Kl-Bíè '%-.64s' v tabulce '%-.64s' neexistuje",-A
-"Nemohu otev-Bøít tabulku",-A
+"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 check/repair",
-"Proveden-Bí tohoto pøíkazu není v transakci dovoleno",-A
-"Chyba %d p-Bøi COMMIT",-A
-"Chyba %d p-Bøi ROLLBACK",-A
-"Chyba %d p-Bøi FLUSH_LOGS",-A
-"Chyba %d p-Bøi CHECKPOINT",-A
-"Spojen-Bí %ld do databáze: '%-.64s' u¾ivatel: '%-.32s' stroj: `%-.64s' (%-.64s) bylo pøeru¹eno",-A
-"Handler tabulky nepodporuje bin-Bární dump",-A
-"Binlog uzav-Bøen pøi pokusu o FLUSH MASTER",-A
-"P-Bøebudování indexu dumpnuté tabulky '%-.64s' nebylo úspì¹né",-A
+"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",-A
-"S-Bí»ová chyba pøi zápisu na master",-A
-"-B®ádný sloupec nemá vytvoøen fulltextový index",-A
-"Nemohu prov-Bést zadaný pøíkaz, proto¾e existují aktivní zamèené tabulky nebo aktivní transakce",-A
-"Nezn-Bámá systémová promìnná '%-.64'",-A
-"Tabulka '%-.64s' je ozna-Bèena jako poru¹ená a mìla by být opravena",-A
-"Tabulka '%-.64s' je ozna-Bèena jako poru¹ená a poslední (automatická?) oprava se nezdaøila",-A
+"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á '%-.64'",
+"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",
"Warning: 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 SLAVE STOP first",
@@ -228,3 +228,12 @@
"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",
+"Wrong 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)",
diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt
index 6585f717a78..d87ed4ee629 100644
--- a/sql/share/danish/errmsg.txt
+++ b/sql/share/danish/errmsg.txt
@@ -222,3 +222,12 @@
"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",
+"Wrong 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)",
diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt
index d14400edc69..9af197e9e4b 100644
--- a/sql/share/dutch/errmsg.txt
+++ b/sql/share/dutch/errmsg.txt
@@ -2,9 +2,10 @@
This file is public domain and comes with NO WARRANTY of any kind
Dutch error messages (share/dutch/errmsg.txt)
- Arjen G. Lentz (agl@bitbike.com)
+ 2001-08-02 - Arjen Lentz (agl@bitbike.com)
Completed earlier partial translation; worked on consistency and spelling.
- Version: 02-08-2001
+ 2002-01-29 - Arjen Lentz (arjen@mysql.com)
+ Translated new error messages.
*/
"hashchk",
@@ -16,9 +17,9 @@
"Kan database '%-.64s' niet aanmaken (Errcode: %d)",
"Kan database '%-.64s' niet aanmaken. Database bestaat reeds",
"Kan database '%-.64s' niet verwijderen. Database bestaat niet",
-"Error verwijderen database (kan '%-.64s' niet verwijderen, Errcode: %d)",
-"Error verwijderen database (kan rmdir '%-.64s' niet uitvoeren, Errcode: %d)",
-"Error bij het verwijderen van '%-.64s' (Errcode: %d)",
+"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)",
@@ -167,8 +168,8 @@
"Communicatiepakket kon niet worden gedecomprimeerd",
"Fout bij het lezen van communicatiepakketten"
"Timeout bij het lezen van communicatiepakketten",
-"Got an error writing communication packets",
-"Got timeout writing communication packets",
+"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",
@@ -218,10 +219,19 @@
"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 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",
+"%-.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",
+"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt
index 384d2c846c2..5033449c266 100644
--- a/sql/share/english/errmsg.txt
+++ b/sql/share/english/errmsg.txt
@@ -219,3 +219,12 @@
"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",
+"Wrong 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)",
diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt
index 20891c7b001..6a83468eae5 100644
--- a/sql/share/estonian/errmsg.txt
+++ b/sql/share/estonian/errmsg.txt
@@ -1,225 +1,235 @@
-/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
- This file is public domain and comes with NO WARRANTY of any kind
+/*
+ Copyright Abandoned 1997 MySQL AB
+ This file is public domain and comes with NO WARRANTY of any kind
+ Esialgne tõlge: Tõnu Samuel (tonu@spam.ee)
+ Parandanud ja täiendanud: Indrek Siitan (tfr@mysql.com)
- Translated into estonian language by Tonu Samuel
- email: tonu@spam.ee
*/
"hashchk",
"isamchk",
"EI",
"JAH",
-"Ei saa luua tabelit '%-.64s' (vea kood: %d)",
-"Ei saa luua tabelit '%-.64s' (vea kood: %d)",
-"Ei saa luua andmebaasi '%-.64s'. (vea kood: %d)",
-"Ei saa luua andmebaasi '%-.64s'. Andmebaas on juba olemas",
-"Ei saa kustutada andmebaasi '%-.64s'. Andmebaasi ei eksisteeri",
-"Ei saa kustutada andmebaasi (Ei saa kustutada faili '%-.64s', vea kood: %d)",
-"Ei saa kustutada andmebaasi (Ei saa kustutada kataloogi '%-.64s', vea kood: %d)",
-"Viga '%-.64s' kustutamisel (vea kood: %d)",
-"Ei saa lugeda kirjet in süsteemsest tabelist",
-"Ei saa lugeda '%-.64s' olekut (vea kood: %d)",
-"Ei saa teada jooksva kataloogi nime (vea kood: %d)",
-"Ei saa avada lukustusfaili (vea kood: %d)",
-"Ei saa avada faili: '%-.64s'. (vea kood: %d)",
-"Ei leia faili: '%-.64s' (vea kood: %d)",
-"Ei saa lugeda kataloogi '%-.64s' (vea kood: %d)",
-"Ei saa siseneda kataloogi '%-.64s' (vea kood: %d)",
-"Kirje on muutunud võrreldes eelmise lugemisega tabelis '%-.64s'",
-"Ketas on täis (%s). Ootame kuni tekib vaba ruumi....",
-"Ei saa kirjutada, Korduv võti tabelis '%-.64s'",
-"Viga faili '%-.64s' sulgemisel (vea kood: %d)",
-"Viga faili '%-.64s' lugemisel (vea kood: %d)",
-"Viga faili '%-.64s' ringi nimetamisel '%-.64s'-ks (vea kood: %d)",
-"Viga faili '%-.64s' kirjutamisel (vea kood: %d)",
+"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' puudub '%-.64s' jaoks",
-"Viga %d tabelitöötluses",
-"Table handler for '%-.64s' doesn't have this option",
+"Vaade '%-.64s' ei eksisteeri '%-.64s' jaoks",
+"Tabeli handler tagastas vea %d",
+"Tabeli '%-.64s' handler ei toeta antud operatsiooni",
"Ei suuda leida kirjet '%-.64s'-s",
-"Väär informatsiion failis '%-.64s'",
-"Vigastatud võtmefail tabelile '%-.64s'",
-"Vana võtmefail tabelile '%-.64s'. Proovi teda parandada",
-"Tabel '%-.64s' on ainult lugemise õigusega",
-"Mälu sai otsa. Proovi MySQL uuesti käivitada (Puudu jäi %d baiti)",
-"Mälu sai sorteerimie ajal otsa. Suurenda MySQL-i sorteerimispuhvrit",
-"Ootamatu faili lõpp leitud faili '%-.64s' lugemisel (vea kood: %d)",
+"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.",
+"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 piiratud kasutajale: '%-.32s@%-.64s' andmebaasi '%-.64s'",
-"Ligipääs piiratud kasutajale: '%-.32s@%-.64s' (Kasutab parooli: %s)",
-"Andmebaas pole valitud",
+"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 olla null",
+"Tulp '%-.64s' ei saa omada nullväärtust",
"Tundmatu andmebaas '%-.64s'",
-"Tabel '%-.64s' on juba olemas",
+"Tabel '%-.64s' juba eksisteerib",
"Tundmatu tabel '%-.64s'",
-"Tulp: '%-.64s' in %-.64s on väär",
+"Väli '%-.64s' %-.64s-s ei ole ühene",
"Serveri seiskamine käib",
-"Tundmatu tulp '%-.64s' in '%-.64s'",
-"'%-.64s' puudub GROUP BY-s",
+"Tundmatu tulp '%-.64s' '%-.64s'-s",
+"'%-.64s' puudub GROUP BY klauslis",
"Ei saa grupeerida '%-.64s' järgi",
-"Lauses on korraga nii tulbad kui summad",
-"Tuplade arv tabelis erineb antud väärtuste arvust",
+"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 nimi '%-.64s' võtmele %d",
-"Väär tulba kirjeldus tulbale '%-.64s'",
-"%s '%-.80s' ligidal reas %d",
+"Kattuv väärtus '%-.64s' võtmele %d",
+"Vigane tulba kirjeldus tulbale '%-.64s'",
+"%s '%-.80s' ligidal real %d",
"Tühi päring",
-"Pole unikaalne tabel/alias '%-.64s'",
-"Vale vaikeväärtus '%-.64s'",
-"Mitut põhivõtit (PRIMARY KEY) ei saa olla",
-"Liiga palju võtmeid määratletud. Maksimaalselt võib olla %d võtit",
+"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",
-"Määratletud võti sai liiga pikk. Maksimaalne lubatud pikkus on %d",
-"Võtme tulp '%-.64s' puudub antud tabelis",
-"BLOB tulpa '%-.64s' ei saa kasutada võtmena",
-"Tulba '%-.64s' pikkus on liiga pikk (maksimaalne = %d).",
-"Tabeli kohta saab olla ainult üks auto_increment tulp ja see peab olema samas ka võtmena",
+"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\n",
"%s: MySQL lõpetas\n",
-"%s: Sain signaali %d. Lõpetan!\n",
+"%s: sain signaali %d. Lõpetan!\n",
"%s: Lõpp\n",
-"%s: Sulgen jõuga threadi %ld kasutaja: '%-.64s'\n",
-"Ei saa luua IP pesa",
+"%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 on väär. Vaata kasutamisjuhendisse",
-"BLOB väljadega ei saa kasutada fikseeritud väljapikkust. Seetõttu on vajalik lisaklausel 'fields terminated by'.",
-"Fail '%-.64s' peab asuma andmebaasi kataloogis ning olema loetav",
-"Fail '%-.64s' on juba olemas",
-"Kirjed: %ld Kustutatud: %ld Vahele jäetud: %ld Hoiatusi: %ld",
-"Kirjed: %ld Topelt: %ld",
-"Väär võtme osa. Kasutatud võtme osa ei ole string või on pikkus pikem kui võtme osa",
-"ALTER TABLE abil ei saa koiki tulpasid kustutada. DROP TABLE kustutab terve tabeli",
-"Ei saa kustutada '%-.64s'. On selline tulp või võti üldse olemas?",
-"Kirjed: %ld Topelt: %ld Hoiatusi: %ld",
-"INSERT TABLE '%-.64s' pole lubatud FROM tabelite nimekirjas",
-"Tundmatu threadi id: %lu",
-"Pole threadi %lu omanik",
-"Pole kasutatud tabeleid",
-"Liiga palju stringe tulbale %-.64s ja tüübile SET",
-"Ei saa luua ainulaadset failinime %-.64s.(1-999)\n",
-"Tabel '%-.64s' on lukustatud ainult lugemiseks ja sinna kirjutada ei saa",
-"Tabel '%-.64s' pole lukustatud käsuga LOCK TABLES",
-"BLOB tüüpi tulbal '%-.64s' ei saa olla vaikeväärtust",
-"Väär andmebaasi nimi '%-.100s'",
-"Väär tabeli nimi '%-.100s'",
-"SELECT lause peab läbi vaatama suure hulga kirjeid ja võtaks tõenäoliselt liiga kaua aega. Tasub kontrollide WHERE klauslit ja vajadusel kasutada käsku SET OPTION SQL_BIG_SELECTS=1",
+"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",
+"INSERT TABLE '%-.64s' ei ole lubatud FROM tabelite nimekirjas",
+"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 OPTION SQL_BIG_SELECTS=1",
"Tundmatu viga",
"Tundmatu protseduur '%-.64s'",
-"Väär parameetrite hulk protseduurile '%-.64s'",
-"Valed parameetrid protseduurile '%-.64s'",
-"Tundmatu tabel '%-.64s' %s-s",
+"Vale parameetrite hulk protseduurile '%-.64s'",
+"Vigased parameetrid protseduurile '%-.64s'",
+"Tundmatu tabel '%-.64s' %-.32s-s",
"Tulp '%-.64s' on määratletud topelt",
-"GROUP BY funktsiooni väärkasutamine",
-"Tabel '%-.64s' kasutab laiendit, mis on tundmatu sellele MySQL versioonile",
-"Tabelil peab olema vähemalt üks tulp",
+"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",
-"Tundmatu kooditabel: '%-.64s'",
-"Liiga palju tabeleid. MySQL oskab kasutada kuni %d tabelit JOINi puhul",
+"Vigane kooditabel '%-.64s'",
+"Liiga palju tabeleid. MySQL suudab JOINiga ühendada kuni %d tabelit",
"Liiga palju tulpasid",
-"Liiga pikk kirje. Maksimaalne kirje pikkus arvestamata BLOB tüüpi on %d. Võib-olla aitab mõnede väljade muutmine BLOB tüübiks",
-"Threadi stack overrun: Used: %ld of a %ld stack. Use 'mysqld -O thlugeda_stack=#' to specify a bigger stack if needed",
-"Ristsõltuvus OUTER JOIN-s. ON tingimused tuleks üle kontrollida",
-"Tulp '%-.64s' on kasutused indeksis kui pole defineeritud tüübiga NOT NULL",
-"Ei saa avada funktsiooni '%-.64s'",
-"Ei saa algväärtustada funktsiooni '%-.64s'; %-.80s",
+"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' on juba olemas",
-"Ei saa avada teeki '%-.64s' (vea kood: %d %s)",
-"Ei leia funktsiooni '%-.64s' selles teegis'",
-"Funktsiooni '%-.64s' pole defineeritud",
-"Masin '%-.64s' blokeeritud hulgaliste ühendusvigade pärast. Blokeeringu saab eemaldada käsuga 'mysqladmin flush-hosts'",
-"Masinale '%-.64s' pole lubatud ligipääsu sellele MySQL serverile",
+"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",
-"Teil peab olema tabelite muutmise õigus muutmaks teiste paroole",
-"Ei leia kirjet kasutajate tabelis",
-"Sobinud kirjed: %ld Muudetud: %ld Hoiatusi: %ld",
-"Ei saa luua threadi (vea kood %d). Kui mälu pole otsas, tasub operatsioonisüsteemi spetsiifilist viga",
-"Tulpade arv ei vasta väärtuste hulgale reas %ld",
-"Ei saa avada tabelit: '%-.64s',
+"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",
-"Viga '%-.64s' regexp-i käest",
-"GROUP tulpade segamine (MIN(),MAX(),COUNT()...) on väär kui ei kasutata GROUP BY klauslit",
-"Sellist õigust ei ole kasutajale '%-.32s' masinast '%-.64s'",
-"%-.16s käsk pole lubatud kasutajale '%-.32s@%-.64s' tabelile '%-.64s'",
-"%-.16s käsk pole lubatud kasutajale '%-.32s@%-.64s' tulbale '%-.64s' tabelis '%-.64s'",
-"Väär GRANT/REVOKE kasutus",
-"Masina või kasutaja nimi on liiga pikk GRANT lauses",
-"Tabelit '%-64s.%s' ei leitud",
-"Sellist õigust pole kasutajale '%-.32s' masinast '%-.64s' tabelile '%-.64s'",
-"Antud käsk pole lubatud selle MySQL-i versiooniga",
+"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 thread ei saanud nõutavat lukku tabelile %-.64s",
-"Liiga palju DELAYED threade on kasutusel",
-"Ühendus katkestatud %ld andmebaasile '%-.64s' kasutaja '%-.64s' (%s)",
-"Sain lubatust suurema paketi (max_allowed_packet)",
-"Got a read error from the connection pipe",
-"Got an error from fcntl()",
-"Got packets out of order",
-"Ei suuda ühendust lahti pakkida",
-"Viga ühenduse lugemisel",
-"Aeg sai otsa ühenduse lugemisel",
-"Viga ühenduse kirjutamisel",
-"Aeg sai otsa ühenduse kirjutamisel",
-"Tulemuseks saadud string on pikem kui max_allowed_packet väärtus",
-"Kasutatud tabeli tüüp ei toeta BLOB/TEXT tulpasid",
-"Kasutatud tabeli tüüp ei toeta AUTO_INCREMENT tulpasid",
-"INSERT DELAYED käsku ei saa kasutada tabeliga '%-.64s', kuna see on lukus käsuga LOCK TABLES",
-"Väär tulba nimi '%-.100s'",
-"Kasutusel olev tabelite haldur ei oska indekseerida tulpa '%-.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",
-"Tulemis on rohkem kui üks kirje",
-"This table type requires a primary key",
-"Antud MySQL ei ole kompileeritud RAID-i toega",
-"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'",
-"Ei suuda tabelit avada",
-"See tabelitüüp ei toeta käske CHECK/REPAIR",
-"Puudub õigus selle transaktsioonikäsu andmiseks",
-"Sain vea %d COMMIT käsu täitmisel",
-"Sain vea %d ROLLBACK käsu täitmisel",
-"Sain vea %d FLUSH_LOGS käsu täitmisel",
-"Sain vea %d CHECKPOINT käsu täitmisel",
-"Ühendus %ld katkestatud andmebaas: '%-.64s' kasutaja: '%-.32s' masin: `%-.64s' (%-.64s)",
+"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 CHECK/REPAIR 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",
-"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",
-"Tundmatu süsteemne muutja '%-.64'",
+"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 '%-.64'",
"Tabel '%-.64s' on märgitud vigaseks ja tuleb parandada",
-"Tabel '%-.64s' on märgitud vigaseks ja viimane (automaatne?) parandamiskatse ebaõnnestus",
-"Warning: 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',
+"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 SLAVE STOP first",
"This operation requires a running slave, configure slave and do SLAVE START",
"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
"Could not initialize master info structure, check permisions on master.info",
"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",
-"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",
-"Wrong 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",
+"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)",
diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt
index 104e561d642..cf3e3e845e4 100644
--- a/sql/share/french/errmsg.txt
+++ b/sql/share/french/errmsg.txt
@@ -219,3 +219,12 @@
"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",
+"Wrong 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)",
diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt
index d0a08a1e7a8..19d46fabab8 100644
--- a/sql/share/german/errmsg.txt
+++ b/sql/share/german/errmsg.txt
@@ -222,3 +222,12 @@
"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",
+"Wrong 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)",
diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt
index f778cb857d7..f9b4f137f82 100644
--- a/sql/share/greek/errmsg.txt
+++ b/sql/share/greek/errmsg.txt
@@ -219,3 +219,12 @@
"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",
+"Wrong 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)",
diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt
index 6ff12c8b49e..38877371243 100644
--- a/sql/share/hungarian/errmsg.txt
+++ b/sql/share/hungarian/errmsg.txt
@@ -221,3 +221,12 @@
"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",
+"Wrong 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)",
diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt
index 7a3daca9a59..e8cfd5a63a9 100644
--- a/sql/share/italian/errmsg.txt
+++ b/sql/share/italian/errmsg.txt
@@ -219,3 +219,12 @@
"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",
+"Wrong 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)",
diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt
index fab60948943..98bc099954f 100644
--- a/sql/share/japanese/errmsg.txt
+++ b/sql/share/japanese/errmsg.txt
@@ -221,3 +221,12 @@
"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",
+"Wrong 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)",
diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt
index 0dac448e2b2..f6cc890cb39 100644
--- a/sql/share/korean/errmsg.txt
+++ b/sql/share/korean/errmsg.txt
@@ -219,3 +219,12 @@
"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",
+"Wrong 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)",
diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt
index 78075c3990c..adffc27949f 100644
--- a/sql/share/norwegian-ny/errmsg.txt
+++ b/sql/share/norwegian-ny/errmsg.txt
@@ -221,3 +221,12 @@
"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",
+"Wrong 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)",
diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt
index 997d667f812..09a1ea4684c 100644
--- a/sql/share/norwegian/errmsg.txt
+++ b/sql/share/norwegian/errmsg.txt
@@ -221,3 +221,12 @@
"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",
+"Wrong 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)",
diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt
index f317d99d48f..12a9bd358b5 100644
--- a/sql/share/polish/errmsg.txt
+++ b/sql/share/polish/errmsg.txt
@@ -223,3 +223,12 @@
"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",
+"Wrong 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)",
diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt
index a3ae06d193f..b7feb0a7b0d 100644
--- a/sql/share/portuguese/errmsg.txt
+++ b/sql/share/portuguese/errmsg.txt
@@ -219,3 +219,12 @@
"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",
+"Wrong 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)",
diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt
index 26d9f34528a..8e48cabfc39 100644
--- a/sql/share/romanian/errmsg.txt
+++ b/sql/share/romanian/errmsg.txt
@@ -223,3 +223,12 @@
"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",
+"Wrong 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)",
diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt
index c02c47696b0..8ed33ec21a0 100644
--- a/sql/share/russian/errmsg.txt
+++ b/sql/share/russian/errmsg.txt
@@ -222,3 +222,12 @@
"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",
+"ïÛÉÂËÁ ÓÏÅÄÉÎÅÎÉÑ Ó master: %-.128s",
+"ïÛÉÂËÁ ×Ù×ÏÌÎÅÎÉÑ ÚÁÐÒÏÓÁ ÎÁ master: %-.128s",
+"ïÛÉÂËÁ ×ÙÐÏÌÎÅÎÉÑ ËÏÍÁÎÄÙ %s: %-.128s",
+"îÅÐÒÁ×ÉÌØÎÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ %s É %s",
+"éÓÐÏÌØÚÕÅÍÙÅ SELECT-×ÙÒÁÖÅÎÉÑ ÉÍÅÀÔ ÒÁÚÎÙÅ ËÏÌÉÞÅÓÔ×Á ÓÔÏÌÂÃÏ×",
+"îÅ×ÏÚÍÏÖÎÏ ×ÙÐÏÌÎÉÔØ ÚÁÐÒÏÓ ÉÚ-ÚÁ ËÏÎÆÌÉËÔÎÏÊ ÂÌÏËÉÒÏ×ËÉ ÞÔÅÎÉÑ",
+"ïÄÎÏ×ÒÅÍÅÎÎÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ transactional É non-transactional ÔÁÂÌÉà ÏÔËÌÀÞÅÎÏ",
+"ïÐÃÉÑ '%s' ÉÓÐÏÌØÚÏ×ÁÎÁ Ä×ÁÖÄÙ",
+"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt
index 189db8a66f8..06503cdf69e 100644
--- a/sql/share/slovak/errmsg.txt
+++ b/sql/share/slovak/errmsg.txt
@@ -227,3 +227,12 @@
"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",
+"Wrong 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)",
diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt
index 57d4ac9646a..4240581c5b8 100644
--- a/sql/share/spanish/errmsg.txt
+++ b/sql/share/spanish/errmsg.txt
@@ -220,3 +220,12 @@
"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 de coneccion a master: %-128s",
+"Error executando el query en master: %-128%",
+"Error de %s: %-128%",
+"Wrong 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)",
diff --git a/sql/share/swedish/errmsg.OLD b/sql/share/swedish/errmsg.OLD
index cc54e051e63..3dd14c8b613 100644
--- a/sql/share/swedish/errmsg.OLD
+++ b/sql/share/swedish/errmsg.OLD
@@ -205,11 +205,17 @@
"Kunde inte initializera replications-strukturerna. Kontrollera privilegerna för 'master.info'",
"Kunde inte starta en tråd för replikering",
"Användare '%-.64s' har redan 'max_user_connections' aktiva inloggningar",
-"Du kan endast använda konstant-uttryck med SET",
-"Lock wait timeout exceeded",
-"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",
-#ER_WRONG_ARGUMENTS
+"Man kan endast använda konstant-uttryck med SET",
+"Fick inte ett lås i tid",
+"Antal lås överskrider antalet reserverade lås",
+"Updaterings-lå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äs-lås",
+"CREATE DATABASE är inte tillåtet när man har ett globalt läs-lås",
"Felaktiga argument till %s",
+"%-.32s@%-.64s har inte rättigheter att skapa nya användare",
+"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",
diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt
index 1b7b6012a39..e774f4a2c5c 100644
--- a/sql/share/swedish/errmsg.txt
+++ b/sql/share/swedish/errmsg.txt
@@ -219,3 +219,12 @@
"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)",
diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt
index 4508fc75c27..c4c89433331 100644
--- a/sql/share/ukrainian/errmsg.txt
+++ b/sql/share/ukrainian/errmsg.txt
@@ -224,3 +224,12 @@
"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",
+"Wrong 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)",
diff --git a/sql/slave.cc b/sql/slave.cc
index cff3af42ce1..176f5db2f79 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -20,48 +20,134 @@
#include <myisam.h>
#include "mini_client.h"
#include "slave.h"
+#include "sql_repl.h"
+#include "repl_failsafe.h"
#include <thr_alarm.h>
#include <my_dir.h>
+#include <assert.h>
-#define RPL_LOG_NAME (glob_mi.log_file_name[0] ? glob_mi.log_file_name :\
- "FIRST")
-
-volatile bool slave_running = 0;
-pthread_t slave_real_id;
-MASTER_INFO glob_mi;
-MY_BITMAP slave_error_mask;
bool use_slave_mask = 0;
+MY_BITMAP slave_error_mask;
+
+typedef bool (*CHECK_KILLED_FUNC)(THD*,void*);
+
+volatile bool slave_sql_running = 0, slave_io_running = 0;
+char* slave_load_tmpdir = 0;
+MASTER_INFO main_mi;
+MASTER_INFO* active_mi;
+volatile int active_mi_in_use = 0;
HASH replicate_do_table, replicate_ignore_table;
DYNAMIC_ARRAY replicate_wild_do_table, replicate_wild_ignore_table;
bool do_table_inited = 0, ignore_table_inited = 0;
bool wild_do_table_inited = 0, wild_ignore_table_inited = 0;
bool table_rules_on = 0;
-uint32 slave_skip_counter = 0;
static TABLE* save_temporary_tables = 0;
-THD* slave_thd = 0;
// when slave thread exits, we need to remember the temporary tables so we
// can re-use them on slave start
-static int last_slave_errno = 0;
-static char last_slave_error[1024] = "";
+// TODO: move the vars below under MASTER_INFO
#ifndef DBUG_OFF
int disconnect_slave_event_count = 0, abort_slave_event_count = 0;
-static int events_till_disconnect = -1, events_till_abort = -1;
+static int events_till_disconnect = -1;
+int events_till_abort = -1;
static int stuck_count = 0;
#endif
+typedef enum { SLAVE_THD_IO, SLAVE_THD_SQL} SLAVE_THD_TYPE;
-inline void skip_load_data_infile(NET* net);
-inline bool slave_killed(THD* thd);
-static int init_slave_thread(THD* thd);
+void skip_load_data_infile(NET* net);
+static int process_io_rotate(MASTER_INFO* mi, Rotate_log_event* rev);
+static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev);
+static int queue_old_event(MASTER_INFO* mi, const char* buf,
+ uint event_len);
+static inline bool io_slave_killed(THD* thd,MASTER_INFO* mi);
+static inline bool sql_slave_killed(THD* thd,RELAY_LOG_INFO* rli);
+static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type);
static int safe_connect(THD* thd, MYSQL* mysql, MASTER_INFO* mi);
static int safe_reconnect(THD* thd, MYSQL* mysql, MASTER_INFO* mi);
-static int safe_sleep(THD* thd, int sec);
-static int request_table_dump(MYSQL* mysql, char* db, char* table);
+static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi,
+ bool reconnect);
+static int safe_sleep(THD* thd, int sec, CHECK_KILLED_FUNC thread_killed,
+ void* thread_killed_arg);
+static int request_table_dump(MYSQL* mysql, const char* db, const char* table);
static int create_table_from_dump(THD* thd, NET* net, const char* db,
const char* table_name);
-inline char* rewrite_db(char* db);
-static int check_expected_error(THD* thd, int expected_error);
+static int check_master_version(MYSQL* mysql, MASTER_INFO* mi);
+
+char* rewrite_db(char* db);
+
+void init_thread_mask(int* mask,MASTER_INFO* mi,bool inverse)
+{
+ bool set_io = mi->slave_running, set_sql = mi->rli.slave_running;
+ if (inverse)
+ {
+ /* This makes me think of the Russian idiom "I am not I, and this is
+ not my horse", which is used to deny reponsibility for
+ one's actions.
+ */
+ set_io = !set_io;
+ set_sql = !set_sql;
+ }
+ register int tmp_mask=0;
+ if (set_io)
+ tmp_mask |= SLAVE_IO;
+ if (set_sql)
+ tmp_mask |= SLAVE_SQL;
+ *mask = tmp_mask;
+}
+
+void lock_slave_threads(MASTER_INFO* mi)
+{
+ //TODO: see if we can do this without dual mutex
+ pthread_mutex_lock(&mi->run_lock);
+ pthread_mutex_lock(&mi->rli.run_lock);
+}
+
+void unlock_slave_threads(MASTER_INFO* mi)
+{
+ //TODO: see if we can do this without dual mutex
+ pthread_mutex_unlock(&mi->rli.run_lock);
+ pthread_mutex_unlock(&mi->run_lock);
+}
+
+int init_slave()
+{
+ // TODO (multi-master): replace this with list initialization
+ active_mi = &main_mi;
+
+ // TODO: the code below is a copy-paste mess - clean it up
+ /*
+ make sure slave thread gets started if server_id is set,
+ valid master.info is present, and master_host has not been specified
+ */
+ if (server_id && !master_host)
+ {
+ // TODO: re-write this to interate through the list of files
+ // for multi-master
+ char fname[FN_REFLEN+128];
+ MY_STAT stat_area;
+ fn_format(fname, master_info_file, mysql_data_home, "", 4+16+32);
+ if (my_stat(fname, &stat_area, MYF(0)) &&
+ !init_master_info(active_mi,master_info_file,relay_log_info_file))
+ master_host = active_mi->host;
+ }
+ // slave thread
+ if (master_host)
+ {
+ if (!opt_skip_slave_start && start_slave_threads(1 /* need mutex */,
+ 0 /* no wait for start*/,
+ active_mi,
+ master_info_file,
+ relay_log_info_file,
+ SLAVE_IO|SLAVE_SQL
+ ))
+ sql_print_error("Warning: Can't create threads to handle slave");
+ else if (opt_skip_slave_start)
+ if (init_master_info(active_mi, master_info_file, relay_log_info_file))
+ sql_print_error("Warning: failed to initialized master info");
+ }
+ return 0;
+}
static void free_table_ent(TABLE_RULE_ENT* e)
{
@@ -75,10 +161,79 @@ static byte* get_table_key(TABLE_RULE_ENT* e, uint* len,
return (byte*)e->db;
}
+// TODO: check proper initialization of master_log_name/master_log_pos
+int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,
+ ulonglong pos, bool need_data_lock,
+ const char** errmsg)
+{
+ if (rli->log_pos_current)
+ return 0;
+ pthread_mutex_t *log_lock=rli->relay_log.get_log_lock();
+ pthread_mutex_lock(log_lock);
+ if (need_data_lock)
+ pthread_mutex_lock(&rli->data_lock);
+
+ if (rli->cur_log_fd >= 0)
+ {
+ end_io_cache(&rli->cache_buf);
+ my_close(rli->cur_log_fd, MYF(MY_WME));
+ rli->cur_log_fd = -1;
+ }
+
+ if (!log)
+ log = rli->relay_log_name; // already inited
+ if (!pos)
+ pos = rli->relay_log_pos; // already inited
+ else
+ rli->relay_log_pos = pos;
+ if (rli->relay_log.find_first_log(&rli->linfo,log))
+ {
+ *errmsg="Could not find first log during relay log initialization";
+ goto err;
+ }
+ strnmov(rli->relay_log_name,rli->linfo.log_file_name,
+ sizeof(rli->relay_log_name));
+ // to make end_io_cache(&rli->cache_buf) safe in all cases
+ if (!rli->inited)
+ bzero((char*) &rli->cache_buf, sizeof(IO_CACHE));
+ if (rli->relay_log.is_active(rli->linfo.log_file_name))
+ {
+ if (my_b_tell((rli->cur_log=rli->relay_log.get_log_file())) == 0 &&
+ check_binlog_magic(rli->cur_log,errmsg))
+ {
+ goto err;
+ }
+ rli->cur_log_init_count=rli->cur_log->init_count;
+ }
+ else
+ {
+ if (rli->inited)
+ end_io_cache(&rli->cache_buf);
+ if (rli->cur_log_fd>=0)
+ my_close(rli->cur_log_fd,MYF(MY_WME));
+ if ((rli->cur_log_fd=open_binlog(&rli->cache_buf,
+ rli->linfo.log_file_name,errmsg)) < 0)
+ {
+ goto err;
+ }
+ rli->cur_log = &rli->cache_buf;
+ }
+ if (pos > 4)
+ my_b_seek(rli->cur_log,(off_t)pos);
+ rli->log_pos_current=1;
+err:
+ pthread_cond_broadcast(&rli->data_cond);
+ if (need_data_lock)
+ pthread_mutex_unlock(&rli->data_lock);
+ pthread_mutex_unlock(log_lock);
+ return (*errmsg) ? 1 : 0;
+}
+
/* called from get_options() in mysqld.cc on start-up */
void init_slave_skip_errors(char* arg)
{
char* p;
+ my_bool last_was_digit = 0;
if (bitmap_init(&slave_error_mask,MAX_SLAVE_ERROR,0))
{
fprintf(stderr, "Badly out of memory, please check your system status\n");
@@ -104,6 +259,219 @@ void init_slave_skip_errors(char* arg)
}
}
+// we assume we have a run lock on rli and that the both slave thread
+// are not running
+int purge_relay_logs(RELAY_LOG_INFO* rli, bool just_reset, const char** errmsg)
+{
+ if (!rli->inited)
+ return 0; /* successfully do nothing */
+ DBUG_ASSERT(rli->slave_running == 0);
+ DBUG_ASSERT(rli->mi->slave_running == 0);
+ int error=0;
+ rli->slave_skip_counter=0;
+ pthread_mutex_lock(&rli->data_lock);
+ rli->pending=0;
+ rli->master_log_name[0]=0;
+ rli->master_log_pos=0; // 0 means uninitialized
+ if (rli->relay_log.reset_logs(rli->sql_thd) ||
+ rli->relay_log.find_first_log(&rli->linfo,""))
+ {
+ *errmsg = "Failed during log reset";
+ error=1;
+ goto err;
+ }
+ strnmov(rli->relay_log_name,rli->linfo.log_file_name,
+ sizeof(rli->relay_log_name));
+ rli->relay_log_pos=4;
+ rli->log_pos_current=0;
+ if (!just_reset)
+ error = init_relay_log_pos(rli,0,0,0/*do not need data lock*/,errmsg);
+err:
+ pthread_mutex_unlock(&rli->data_lock);
+ return error;
+}
+
+int terminate_slave_threads(MASTER_INFO* mi,int thread_mask,bool skip_lock)
+{
+ if (!mi->inited)
+ return 0; /* successfully do nothing */
+ int error,force_all = (thread_mask & SLAVE_FORCE_ALL);
+ pthread_mutex_t *sql_lock = &mi->rli.run_lock, *io_lock = &mi->run_lock;
+ pthread_mutex_t *sql_cond_lock,*io_cond_lock;
+
+ sql_cond_lock=sql_lock;
+ io_cond_lock=io_lock;
+
+ if (skip_lock)
+ {
+ sql_lock = io_lock = 0;
+ }
+ if ((thread_mask & (SLAVE_IO|SLAVE_FORCE_ALL)) && mi->slave_running)
+ {
+ mi->abort_slave=1;
+ if ((error=terminate_slave_thread(mi->io_thd,io_lock,
+ io_cond_lock,
+ &mi->stop_cond,
+ &mi->slave_running)) &&
+ !force_all)
+ return error;
+ }
+ if ((thread_mask & (SLAVE_SQL|SLAVE_FORCE_ALL)) && mi->rli.slave_running)
+ {
+ DBUG_ASSERT(mi->rli.sql_thd != 0) ;
+ mi->rli.abort_slave=1;
+ if ((error=terminate_slave_thread(mi->rli.sql_thd,sql_lock,
+ sql_cond_lock,
+ &mi->rli.stop_cond,
+ &mi->rli.slave_running)) &&
+ !force_all)
+ return error;
+ }
+ return 0;
+}
+
+int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock,
+ pthread_mutex_t *cond_lock,
+ pthread_cond_t* term_cond,
+ volatile bool* slave_running)
+{
+ if (term_lock)
+ {
+ pthread_mutex_lock(term_lock);
+ if (!*slave_running)
+ {
+ pthread_mutex_unlock(term_lock);
+ return ER_SLAVE_NOT_RUNNING;
+ }
+ }
+ DBUG_ASSERT(thd != 0);
+ KICK_SLAVE(thd);
+ while (*slave_running)
+ {
+ /* there is a small chance that slave thread might miss the first
+ alarm. To protect againts it, resend the signal until it reacts
+ */
+ struct timespec abstime;
+#ifdef HAVE_TIMESPEC_TS_SEC
+ abstime.ts_sec=time(NULL)+2;
+ abstime.ts_nsec=0;
+#elif defined(__WIN__)
+ abstime.tv_sec=time((time_t*) 0)+2;
+ abstime.tv_nsec=0;
+#else
+ struct timeval tv;
+ gettimeofday(&tv,0);
+ abstime.tv_sec=tv.tv_sec+2;
+ abstime.tv_nsec=tv.tv_usec*1000;
+#endif
+ DBUG_ASSERT_LOCK(cond_lock);
+ pthread_cond_timedwait(term_cond, cond_lock, &abstime);
+ if (*slave_running)
+ KICK_SLAVE(thd);
+ }
+ if (term_lock)
+ pthread_mutex_unlock(term_lock);
+ return 0;
+}
+
+int start_slave_thread(pthread_handler h_func, pthread_mutex_t* start_lock,
+ pthread_mutex_t *cond_lock,
+ pthread_cond_t* start_cond,
+ volatile bool* slave_running,
+ MASTER_INFO* mi)
+{
+ pthread_t th;
+ DBUG_ASSERT(mi->inited);
+ if (start_lock)
+ pthread_mutex_lock(start_lock);
+ if (!server_id)
+ {
+ if (start_cond)
+ pthread_cond_broadcast(start_cond);
+ if (start_lock)
+ pthread_mutex_unlock(start_lock);
+ sql_print_error("Server id not set, will not start slave");
+ return ER_BAD_SLAVE;
+ }
+
+ if (*slave_running)
+ {
+ if (start_cond)
+ pthread_cond_broadcast(start_cond);
+ if (start_lock)
+ pthread_mutex_unlock(start_lock);
+ return ER_SLAVE_MUST_STOP;
+ }
+ if (pthread_create(&th, &connection_attrib, h_func, (void*)mi))
+ {
+ if (start_lock)
+ pthread_mutex_unlock(start_lock);
+ return ER_SLAVE_THREAD;
+ }
+ if (start_cond && cond_lock)
+ {
+ THD* thd = current_thd;
+ while (!*slave_running)
+ {
+ const char* old_msg = thd->enter_cond(start_cond,cond_lock,
+ "Waiting for slave thread to start");
+ pthread_cond_wait(start_cond,cond_lock);
+ thd->exit_cond(old_msg);
+ // TODO: in a very rare case of init_slave_thread failing, it is
+ // possible that we can get stuck here since slave_running will not
+ // be set. We need to change slave_running to int and have -1 as
+ // error code
+ if (thd->killed)
+ {
+ pthread_mutex_unlock(cond_lock);
+ return ER_SERVER_SHUTDOWN;
+ }
+ }
+ }
+ if (start_lock)
+ pthread_mutex_unlock(start_lock);
+ return 0;
+}
+/* SLAVE_FORCE_ALL is not implemented here on purpose since it does not make
+ sense to do that for starting a slave - we always care if it actually
+ started the threads that were not previously running
+*/
+int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
+ MASTER_INFO* mi, const char* master_info_fname,
+ const char* slave_info_fname, int thread_mask)
+{
+ pthread_mutex_t *lock_io=0,*lock_sql=0,*lock_cond_io=0,*lock_cond_sql=0;
+ pthread_cond_t* cond_io=0,*cond_sql=0;
+ int error=0;
+
+ if (need_slave_mutex)
+ {
+ lock_io = &mi->run_lock;
+ lock_sql = &mi->rli.run_lock;
+ }
+ if (wait_for_start)
+ {
+ cond_io = &mi->start_cond;
+ cond_sql = &mi->rli.start_cond;
+ lock_cond_io = &mi->run_lock;
+ lock_cond_sql = &mi->rli.run_lock;
+ }
+ if (init_master_info(mi,master_info_fname,slave_info_fname))
+ return ER_MASTER_INFO;
+
+ if ((thread_mask & SLAVE_IO) &&
+ (error=start_slave_thread(handle_slave_io,lock_io,lock_cond_io,
+ cond_io,&mi->slave_running,
+ mi)))
+ return error;
+ if ((thread_mask & SLAVE_SQL) &&
+ (error=start_slave_thread(handle_slave_sql,lock_sql,lock_cond_sql,
+ cond_sql,
+ &mi->rli.slave_running,mi)))
+ return error;
+ return 0;
+}
+
void init_table_rule_hash(HASH* h, bool* h_inited)
{
hash_init(h, TABLE_RULE_HASH_SIZE,0,0,
@@ -124,11 +492,11 @@ static TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len)
uint i;
const char* key_end = key + len;
- for(i = 0; i < a->elements; i++)
+ for (i = 0; i < a->elements; i++)
{
TABLE_RULE_ENT* e ;
get_dynamic(a, (gptr)&e, i);
- if(!wild_case_compare(key, key_end, (const char*)e->db,
+ if (!wild_case_compare(key, key_end, (const char*)e->db,
(const char*)(e->db + e->key_len),'\\'))
return e;
}
@@ -152,7 +520,7 @@ int tables_ok(THD* thd, TABLE_LIST* tables)
if (hash_search(&replicate_do_table, (byte*) hash_key, len))
return 1;
}
- if (ignore_table_inited) // if there are any do's
+ if (ignore_table_inited) // if there are any ignores
{
if (hash_search(&replicate_ignore_table, (byte*) hash_key, len))
return 0;
@@ -217,38 +585,55 @@ static void free_string_array(DYNAMIC_ARRAY *a)
delete_dynamic(a);
}
+static int end_slave_on_walk(MASTER_INFO* mi, gptr /*unused*/)
+{
+ end_master_info(mi);
+ return 0;
+}
+
void end_slave()
{
- pthread_mutex_lock(&LOCK_slave);
- if (slave_running)
- {
- abort_slave = 1;
- thr_alarm_kill(slave_real_id);
-#ifdef SIGNAL_WITH_VIO_CLOSE
- slave_thd->close_active_vio();
-#endif
- while (slave_running)
- pthread_cond_wait(&COND_slave_stopped, &LOCK_slave);
- }
- pthread_mutex_unlock(&LOCK_slave);
-
- end_master_info(&glob_mi);
- if(do_table_inited)
+ // TODO: replace the line below with
+ // list_walk(&master_list, (list_walk_action)end_slave_on_walk,0);
+ // once multi-master code is ready
+ terminate_slave_threads(active_mi,SLAVE_FORCE_ALL);
+ end_master_info(active_mi);
+ if (do_table_inited)
hash_free(&replicate_do_table);
- if(ignore_table_inited)
+ if (ignore_table_inited)
hash_free(&replicate_ignore_table);
- if(wild_do_table_inited)
+ if (wild_do_table_inited)
free_string_array(&replicate_wild_do_table);
- if(wild_ignore_table_inited)
+ if (wild_ignore_table_inited)
free_string_array(&replicate_wild_ignore_table);
}
-inline bool slave_killed(THD* thd)
+static bool io_slave_killed(THD* thd, MASTER_INFO* mi)
{
- return abort_slave || abort_loop || thd->killed;
+ DBUG_ASSERT(mi->io_thd == thd);
+ DBUG_ASSERT(mi->slave_running == 1); // tracking buffer overrun
+ return mi->abort_slave || abort_loop || thd->killed;
}
-inline void skip_load_data_infile(NET* net)
+static bool sql_slave_killed(THD* thd, RELAY_LOG_INFO* rli)
+{
+ DBUG_ASSERT(rli->sql_thd == thd);
+ DBUG_ASSERT(rli->slave_running == 1);// tracking buffer overrun
+ return rli->abort_slave || abort_loop || thd->killed;
+}
+
+void slave_print_error(RELAY_LOG_INFO* rli, int err_code, const char* msg, ...)
+{
+ va_list args;
+ va_start(args,msg);
+ my_vsnprintf(rli->last_slave_error,
+ sizeof(rli->last_slave_error), msg, args);
+ sql_print_error("Slave: %s, error_code=%d", rli->last_slave_error,
+ err_code);
+ rli->last_slave_errno = err_code;
+}
+
+void skip_load_data_infile(NET* net)
{
(void)my_net_write(net, "\xfb/dev/null", 10);
(void)net_flush(net);
@@ -256,7 +641,7 @@ inline void skip_load_data_infile(NET* net)
send_ok(net); // the master expects it
}
-inline char* rewrite_db(char* db)
+char* rewrite_db(char* db)
{
if(replicate_rewrite_db.is_empty() || !db) return db;
I_List_iterator<i_string_pair> it(replicate_rewrite_db);
@@ -274,7 +659,7 @@ inline char* rewrite_db(char* db)
int db_ok(const char* db, I_List<i_string> &do_list,
I_List<i_string> &ignore_list )
{
- if(do_list.is_empty() && ignore_list.is_empty())
+ if (do_list.is_empty() && ignore_list.is_empty())
return 1; // ok to replicate if the user puts no constraints
// if the user has specified restrictions on which databases to replicate
@@ -352,16 +737,65 @@ static int init_intvar_from_file(int* var, IO_CACHE* f, int default_val)
return 1;
}
+static int check_master_version(MYSQL* mysql, MASTER_INFO* mi)
+{
+ MYSQL_RES* res;
+ MYSQL_ROW row;
+ const char* version;
+ const char* errmsg = 0;
+
+ if (mc_mysql_query(mysql, "SELECT VERSION()", 0)
+ || !(res = mc_mysql_store_result(mysql)))
+ {
+ sql_print_error("Error checking master version: %s",
+ mc_mysql_error(mysql));
+ return 1;
+ }
+ if (!(row = mc_mysql_fetch_row(res)))
+ {
+ errmsg = "Master returned no rows for SELECT VERSION()";
+ goto err;
+ }
+ if (!(version = row[0]))
+ {
+ errmsg = "Master reported NULL for the version";
+ goto err;
+ }
+
+ switch (*version)
+ {
+ case '3':
+ mi->old_format = 1;
+ break;
+ case '4':
+ mi->old_format = 0;
+ break;
+ default:
+ errmsg = "Master reported unrecognized MySQL version";
+ goto err;
+ }
+err:
+ if (res)
+ mc_mysql_free_result(res);
+ if (errmsg)
+ {
+ sql_print_error(errmsg);
+ return 1;
+ }
+ return 0;
+}
+
static int create_table_from_dump(THD* thd, NET* net, const char* db,
const char* table_name)
{
- uint packet_len = my_net_read(net); // read create table statement
+ ulong packet_len = my_net_read(net); // read create table statement
Vio* save_vio;
HA_CHECK_OPT check_opt;
TABLE_LIST tables;
int error= 1;
handler *file;
+ uint save_options;
if (packet_len == packet_error)
{
@@ -387,12 +821,17 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db,
thd->current_tablenr = 0;
thd->query_error = 0;
thd->net.no_send_ok = 1;
+
+ /* we do not want to log create table statement */
+ save_options = thd->options;
+ thd->options &= ~OPTION_BIN_LOG;
thd->proc_info = "Creating table from master dump";
// save old db in case we are creating in a different database
char* save_db = thd->db;
- thd->db = thd->last_nx_db;
+ thd->db = (char*)db;
mysql_parse(thd, thd->query, packet_len); // run create table
thd->db = save_db; // leave things the way the were before
+ thd->options = save_options;
if (thd->query_error)
goto err; // mysql_parse took care of the error send
@@ -420,8 +859,7 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db,
}
check_opt.init();
- check_opt.flags|= T_VERY_SILENT | T_CALC_CHECKSUM;
- check_opt.quick = 1;
+ check_opt.flags|= T_VERY_SILENT | T_CALC_CHECKSUM | T_QUICK;
thd->proc_info = "Rebuilding the index on master dump table";
// we do not want repair() to spam us with messages
// just send them to the error log, and report the failure in case of
@@ -439,51 +877,62 @@ err:
return error;
}
-int fetch_nx_table(THD* thd, MASTER_INFO* mi)
+int fetch_master_table(THD* thd, const char* db_name, const char* table_name,
+ MASTER_INFO* mi, MYSQL* mysql)
{
- MYSQL* mysql = mc_mysql_init(NULL);
int error = 1;
- int nx_errno = 0;
- if (!mysql)
- {
- sql_print_error("fetch_nx_table: Error in mysql_init()");
- nx_errno = ER_GET_ERRNO;
+ int fetch_errno = 0;
+ bool called_connected = (mysql != NULL);
+ if (!called_connected && !(mysql = mc_mysql_init(NULL)))
+ {
+ sql_print_error("fetch_master_table: Error in mysql_init()");
+ fetch_errno = ER_GET_ERRNO;
goto err;
}
- safe_connect(thd, mysql, mi);
- if (slave_killed(thd))
+ if (!called_connected)
+ {
+ if (connect_to_master(thd, mysql, mi))
+ {
+ sql_print_error("Could not connect to master while fetching table\
+ '%-64s.%-64s'", db_name, table_name);
+ fetch_errno = ER_CONNECT_TO_MASTER;
+ goto err;
+ }
+ }
+ if (thd->killed)
goto err;
- if (request_table_dump(mysql, thd->last_nx_db, thd->last_nx_table))
+ if (request_table_dump(mysql, db_name, table_name))
{
- nx_errno = ER_GET_ERRNO;
- sql_print_error("fetch_nx_table: failed on table dump request ");
+ fetch_errno = ER_GET_ERRNO;
+ sql_print_error("fetch_master_table: failed on table dump request ");
goto err;
}
- if (create_table_from_dump(thd, &mysql->net, thd->last_nx_db,
- thd->last_nx_table))
- {
+ if (create_table_from_dump(thd, &mysql->net, db_name,
+ table_name))
+ {
// create_table_from_dump will have sent the error alread
- sql_print_error("fetch_nx_table: failed on create table ");
+ sql_print_error("fetch_master_table: failed on create table ");
goto err;
}
-
error = 0;
-
err:
- if (mysql)
+ if (mysql && !called_connected)
mc_mysql_close(mysql);
- if (nx_errno && thd->net.vio)
- send_error(&thd->net, nx_errno, "Error in fetch_nx_table");
+ if (fetch_errno && thd->net.vio)
+ send_error(&thd->net, fetch_errno, "Error in fetch_master_table");
thd->net.no_send_ok = 0; // Clear up garbage after create_table_from_dump
return error;
}
void end_master_info(MASTER_INFO* mi)
{
- if(mi->fd >= 0)
+ if (!mi->inited)
+ return;
+ end_relay_log_info(&mi->rli);
+ if (mi->fd >= 0)
{
end_io_cache(&mi->file);
(void)my_close(mi->fd, MYF(MY_WME));
@@ -492,21 +941,141 @@ void end_master_info(MASTER_INFO* mi)
mi->inited = 0;
}
-int init_master_info(MASTER_INFO* mi)
+int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
+{
+ if (rli->inited)
+ return 0;
+ MY_STAT stat_area;
+ char fname[FN_REFLEN+128];
+ int info_fd;
+ const char* msg = 0;
+ int error = 0;
+ fn_format(fname, info_fname,
+ mysql_data_home, "", 4+32);
+ pthread_mutex_lock(&rli->data_lock);
+ info_fd = rli->info_fd;
+ rli->pending = 0;
+ rli->cur_log_fd = -1;
+ rli->slave_skip_counter=0;
+ rli->log_pos_current=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));
+ }
+ rli->relay_log.set_index_file_name(opt_relaylog_index_name);
+ open_log(&rli->relay_log, glob_hostname, opt_relay_logname, "-relay-bin",
+ LOG_BIN, 1 /* read_append cache */,
+ 1 /* no auto events*/);
+
+ /* if file does not exist */
+ if (!my_stat(fname, &stat_area, MYF(0)))
+ {
+ // if someone removed the file from underneath our feet, just close
+ // the old descriptor and re-create the old file
+ if (info_fd >= 0)
+ my_close(info_fd, MYF(MY_WME));
+ if ((info_fd = my_open(fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0
+ || init_io_cache(&rli->info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L,0,
+ MYF(MY_WME)))
+ {
+ if(info_fd >= 0)
+ my_close(info_fd, MYF(0));
+ rli->info_fd=-1;
+ pthread_mutex_unlock(&rli->data_lock);
+ return 1;
+ }
+ if (init_relay_log_pos(rli,"",4,0/*no data mutex*/,&msg))
+ goto err;
+ rli->master_log_pos = 0; // uninitialized
+ rli->info_fd = info_fd;
+ }
+ else // file exists
+ {
+ if(info_fd >= 0)
+ reinit_io_cache(&rli->info_file, READ_CACHE, 0L,0,0);
+ else if((info_fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0
+ || init_io_cache(&rli->info_file, info_fd,
+ IO_SIZE*2, READ_CACHE, 0L,
+ 0, MYF(MY_WME)))
+ {
+ if (info_fd >= 0)
+ my_close(info_fd, MYF(0));
+ rli->info_fd=-1;
+ pthread_mutex_unlock(&rli->data_lock);
+ return 1;
+ }
+
+ rli->info_fd = info_fd;
+ if (init_strvar_from_file(rli->relay_log_name,
+ sizeof(rli->relay_log_name), &rli->info_file,
+ (char*)"") ||
+ init_intvar_from_file((int*)&rli->relay_log_pos,
+ &rli->info_file, 4) ||
+ init_strvar_from_file(rli->master_log_name,
+ sizeof(rli->master_log_name), &rli->info_file,
+ (char*)"") ||
+ init_intvar_from_file((int*)&rli->master_log_pos,
+ &rli->info_file, 0))
+ {
+ msg="Error reading slave log configuration";
+ goto err;
+ }
+ if (init_relay_log_pos(rli,0 /*log already inited*/,
+ 0 /*pos already inited*/,
+ 0 /* no data lock*/,
+ &msg))
+ goto err;
+ }
+ DBUG_ASSERT(rli->relay_log_pos >= 4);
+ DBUG_ASSERT(my_b_tell(rli->cur_log) == rli->relay_log_pos);
+ rli->inited = 1;
+ // now change the cache from READ to WRITE - must do this
+ // before flush_relay_log_info
+ reinit_io_cache(&rli->info_file, WRITE_CACHE,0L,0,1);
+ error=test(flush_relay_log_info(rli));
+ pthread_mutex_unlock(&rli->data_lock);
+ return error;
+
+err:
+ sql_print_error(msg);
+ end_io_cache(&rli->info_file);
+ my_close(info_fd, MYF(0));
+ rli->info_fd=-1;
+ pthread_mutex_unlock(&rli->data_lock);
+ return 1;
+}
+
+
+int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
+ const char* slave_info_fname)
{
if (mi->inited)
return 0;
- int fd,length,error;
+ if (init_relay_log_info(&mi->rli, slave_info_fname))
+ return 1;
+ mi->rli.mi = mi;
+ mi->mysql=0;
+ mi->file_id=1;
+ mi->ignore_stop_event=0;
+ int fd,error;
MY_STAT stat_area;
char fname[FN_REFLEN+128];
const char *msg;
- fn_format(fname, master_info_file, mysql_data_home, "", 4+16+32);
+ fn_format(fname, master_info_fname, mysql_data_home, "", 4+32);
- // we need a mutex while we are changing master info parameters to
- // keep other threads from reading bogus info
+ /*
+ We need a mutex while we are changing master info parameters to
+ keep other threads from reading bogus info
+ */
- pthread_mutex_lock(&mi->lock);
- mi->pending = 0;
+ pthread_mutex_lock(&mi->data_lock);
fd = mi->fd;
// we do not want any messages if the file does not exist
@@ -522,11 +1091,13 @@ int init_master_info(MASTER_INFO* mi)
{
if(fd >= 0)
my_close(fd, MYF(0));
- pthread_mutex_unlock(&mi->lock);
+ mi->fd=-1;
+ end_relay_log_info(&mi->rli);
+ pthread_mutex_unlock(&mi->data_lock);
return 1;
}
- mi->log_file_name[0] = 0;
- mi->pos = 4; // skip magic number
+ mi->master_log_name[0] = 0;
+ mi->master_log_pos = 4; // skip magic number
mi->fd = fd;
if (master_host)
@@ -548,99 +1119,145 @@ int init_master_info(MASTER_INFO* mi)
{
if(fd >= 0)
my_close(fd, MYF(0));
- pthread_mutex_unlock(&mi->lock);
+ mi->fd=-1;
+ end_relay_log_info(&mi->rli);
+ pthread_mutex_unlock(&mi->data_lock);
return 1;
}
-
- if ((length=my_b_gets(&mi->file, mi->log_file_name,
- sizeof(mi->log_file_name))) < 1)
- {
- msg="Error reading log file name from master info file ";
- goto error;
- }
-
- mi->log_file_name[length-1]= 0; // kill \n
- /* Reuse fname buffer */
- if(!my_b_gets(&mi->file, fname, sizeof(fname)))
- {
- msg="Error reading log file position from master info file";
- goto error;
- }
- mi->pos = strtoull(fname,(char**) 0, 10);
mi->fd = fd;
- if(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) ||
- init_strvar_from_file(mi->password, HASH_PASSWORD_LENGTH+1, &mi->file,
- master_password) ||
- init_intvar_from_file((int*)&mi->port, &mi->file, master_port) ||
- init_intvar_from_file((int*)&mi->connect_retry, &mi->file,
- master_connect_retry))
+ if (init_strvar_from_file(mi->master_log_name,
+ sizeof(mi->master_log_name), &mi->file,
+ (char*)"") ||
+ init_intvar_from_file((int*)&mi->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) ||
+ init_strvar_from_file(mi->password, HASH_PASSWORD_LENGTH+1, &mi->file,
+ master_password) ||
+ init_intvar_from_file((int*)&mi->port, &mi->file, master_port) ||
+ init_intvar_from_file((int*)&mi->connect_retry, &mi->file,
+ master_connect_retry))
{
msg="Error reading master configuration";
- goto error;
+ goto err;
}
}
mi->inited = 1;
- // now change the cache from READ to WRITE - must do this
- // before flush_master_info
- reinit_io_cache(&mi->file, WRITE_CACHE, 0L,0,1);
+ // now change cache READ -> WRITE - must do this before flush_master_info
+ reinit_io_cache(&mi->file, WRITE_CACHE,0L,0,1);
error=test(flush_master_info(mi));
- pthread_mutex_unlock(&mi->lock);
+ pthread_mutex_unlock(&mi->data_lock);
return error;
-error:
+err:
sql_print_error(msg);
end_io_cache(&mi->file);
+ end_relay_log_info(&mi->rli);
+ DBUG_ASSERT(fd>=0);
my_close(fd, MYF(0));
- pthread_mutex_unlock(&mi->lock);
+ mi->fd=-1;
+ pthread_mutex_unlock(&mi->data_lock);
return 1;
}
-int show_master_info(THD* thd)
+int register_slave_on_master(MYSQL* mysql)
+{
+ String packet;
+ char buf[4];
+
+ if (!report_host)
+ return 0;
+
+ int4store(buf, server_id);
+ packet.append(buf, 4);
+
+ net_store_data(&packet, report_host);
+ if (report_user)
+ net_store_data(&packet, report_user);
+ else
+ packet.append((char)0);
+
+ if(report_password)
+ net_store_data(&packet, report_user);
+ else
+ packet.append((char)0);
+
+ int2store(buf, (uint16)report_port);
+ packet.append(buf, 2);
+ int4store(buf, rpl_recovery_rank);
+ packet.append(buf, 4);
+ int4store(buf, 0); /* tell the master will fill in master_id */
+ packet.append(buf, 4);
+
+ if (mc_simple_command(mysql, COM_REGISTER_SLAVE, (char*)packet.ptr(),
+ packet.length(), 0))
+ {
+ sql_print_error("Error on COM_REGISTER_SLAVE: '%s'",
+ mc_mysql_error(mysql));
+ return 1;
+ }
+
+ return 0;
+}
+
+int show_master_info(THD* thd, MASTER_INFO* mi)
{
+ // TODO: fix this for multi-master
DBUG_ENTER("show_master_info");
List<Item> field_list;
field_list.push_back(new Item_empty_string("Master_Host",
- sizeof(glob_mi.host)));
+ sizeof(mi->host)));
field_list.push_back(new Item_empty_string("Master_User",
- sizeof(glob_mi.user)));
+ sizeof(mi->user)));
field_list.push_back(new Item_empty_string("Master_Port", 6));
field_list.push_back(new Item_empty_string("Connect_retry", 6));
- field_list.push_back( new Item_empty_string("Log_File",
+ field_list.push_back(new Item_empty_string("Master_Log_File",
+ FN_REFLEN));
+ field_list.push_back(new Item_empty_string("Read_Master_Log_Pos", 12));
+ field_list.push_back(new Item_empty_string("Relay_Log_File",
+ FN_REFLEN));
+ field_list.push_back(new Item_empty_string("Relay_Log_Pos", 12));
+ field_list.push_back(new Item_empty_string("Relay_Master_Log_File",
FN_REFLEN));
- field_list.push_back(new Item_empty_string("Pos", 12));
- field_list.push_back(new Item_empty_string("Slave_Running", 3));
+ field_list.push_back(new Item_empty_string("Slave_IO_Running", 3));
+ field_list.push_back(new Item_empty_string("Slave_SQL_Running", 3));
field_list.push_back(new Item_empty_string("Replicate_do_db", 20));
field_list.push_back(new Item_empty_string("Replicate_ignore_db", 20));
field_list.push_back(new Item_empty_string("Last_errno", 4));
field_list.push_back(new Item_empty_string("Last_error", 20));
field_list.push_back(new Item_empty_string("Skip_counter", 12));
+ field_list.push_back(new Item_empty_string("Exec_master_log_pos", 12));
if(send_fields(thd, field_list, 1))
DBUG_RETURN(-1);
String* packet = &thd->packet;
packet->length(0);
- pthread_mutex_lock(&glob_mi.lock);
- net_store_data(packet, glob_mi.host);
- net_store_data(packet, glob_mi.user);
- net_store_data(packet, (uint32) glob_mi.port);
- net_store_data(packet, (uint32) glob_mi.connect_retry);
- net_store_data(packet, glob_mi.log_file_name);
- net_store_data(packet, (uint32) glob_mi.pos); // QQ: Should be fixed
- pthread_mutex_unlock(&glob_mi.lock);
- pthread_mutex_lock(&LOCK_slave);
- net_store_data(packet, slave_running ? "Yes":"No");
- pthread_mutex_unlock(&LOCK_slave);
+ pthread_mutex_lock(&mi->data_lock);
+ pthread_mutex_lock(&mi->rli.data_lock);
+ net_store_data(packet, mi->host);
+ net_store_data(packet, mi->user);
+ net_store_data(packet, (uint32) mi->port);
+ net_store_data(packet, (uint32) mi->connect_retry);
+ net_store_data(packet, mi->master_log_name);
+ net_store_data(packet, (longlong) mi->master_log_pos);
+ net_store_data(packet, mi->rli.relay_log_name +
+ dirname_length(mi->rli.relay_log_name));
+ net_store_data(packet, (longlong) mi->rli.relay_log_pos);
+ net_store_data(packet, mi->rli.master_log_name);
+ net_store_data(packet, mi->slave_running ? "Yes":"No");
+ net_store_data(packet, mi->rli.slave_running ? "Yes":"No");
net_store_data(packet, &replicate_do_db);
net_store_data(packet, &replicate_ignore_db);
- net_store_data(packet, (uint32)last_slave_errno);
- net_store_data(packet, last_slave_error);
- net_store_data(packet, slave_skip_counter);
+ net_store_data(packet, (uint32)mi->rli.last_slave_errno);
+ net_store_data(packet, mi->rli.last_slave_error);
+ net_store_data(packet, mi->rli.slave_skip_counter);
+ net_store_data(packet, (longlong) mi->rli.master_log_pos);
+ pthread_mutex_unlock(&mi->rli.data_lock);
+ pthread_mutex_unlock(&mi->data_lock);
if (my_net_write(&thd->net, (char*)thd->packet.ptr(), packet->length()))
DBUG_RETURN(-1);
@@ -655,54 +1272,58 @@ int flush_master_info(MASTER_INFO* mi)
char lbuf[22];
my_b_seek(file, 0L);
- my_b_printf(file, "%s\n%s\n%s\n%s\n%s\n%d\n%d\n",
- mi->log_file_name, llstr(mi->pos, lbuf), mi->host, mi->user,
- mi->password, mi->port, mi->connect_retry);
+ my_b_printf(file, "%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n",
+ mi->master_log_name, llstr(mi->master_log_pos, lbuf),
+ mi->host, mi->user,
+ mi->password, mi->port, mi->connect_retry
+ );
flush_io_cache(file);
return 0;
}
-int st_master_info::wait_for_pos(THD* thd, String* log_name, ulonglong log_pos)
+int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
+ ulonglong log_pos)
{
if (!inited) return -1;
- bool pos_reached;
+ bool pos_reached = 0;
int event_count = 0;
- pthread_mutex_lock(&lock);
- while(!thd->killed)
+ pthread_mutex_lock(&data_lock);
+ while (!thd->killed)
{
int cmp_result;
- if (*log_file_name)
+ DBUG_ASSERT(*master_log_name || master_log_pos == 0);
+ if (*master_log_name)
{
/*
We should use dirname_length() here when we have a version of
this that doesn't modify the argument */
- char *basename = strrchr(log_file_name, FN_LIBCHAR);
+ char *basename = strrchr(master_log_name, FN_LIBCHAR);
if (basename)
++basename;
else
- basename = log_file_name;
+ basename = master_log_name;
cmp_result = strncmp(basename, log_name->ptr(),
log_name->length());
}
else
cmp_result = 0;
- pos_reached = ((!cmp_result && pos >= log_pos) || cmp_result > 0);
+ pos_reached = ((!cmp_result && master_log_pos >= log_pos) ||
+ cmp_result > 0);
if (pos_reached || thd->killed)
break;
- const char* msg = thd->enter_cond(&cond, &lock,
+ const char* msg = thd->enter_cond(&data_cond, &data_lock,
"Waiting for master update");
- pthread_cond_wait(&cond, &lock);
+ pthread_cond_wait(&data_cond, &data_lock);
thd->exit_cond(msg);
event_count++;
}
- pthread_mutex_unlock(&lock);
+ pthread_mutex_unlock(&data_lock);
return thd->killed ? -1 : event_count;
}
-
-static int init_slave_thread(THD* thd)
+static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
{
DBUG_ENTER("init_slave_thread");
thd->system_thread = thd->bootstrap = 1;
@@ -716,7 +1337,7 @@ static int init_slave_thread(THD* thd)
thd->options = (((opt_log_slave_updates) ? OPTION_BIN_LOG:0) | OPTION_AUTO_IS_NULL) ;
thd->system_thread = 1;
thd->client_capabilities = CLIENT_LOCAL_FILES;
- slave_real_id=thd->real_id=pthread_self();
+ thd->real_id=pthread_self();
pthread_mutex_lock(&LOCK_thread_count);
thd->thread_id = thread_id++;
pthread_mutex_unlock(&LOCK_thread_count);
@@ -726,7 +1347,6 @@ static int init_slave_thread(THD* thd)
my_pthread_setspecific_ptr(THR_MALLOC, &thd->mem_root) ||
my_pthread_setspecific_ptr(THR_NET, &thd->net))
{
- close_connection(&thd->net,ER_OUT_OF_RESOURCES); // is this needed?
end_thread(thd,0);
DBUG_RETURN(-1);
}
@@ -743,14 +1363,22 @@ static int init_slave_thread(THD* thd)
if (thd->max_join_size == (ulong) ~0L)
thd->options |= OPTION_BIG_SELECTS;
- thd->proc_info="Waiting for master update";
+ if (thd_type == SLAVE_THD_SQL)
+ {
+ thd->proc_info = "Waiting for the next event in slave queue";
+ }
+ else
+ {
+ thd->proc_info="Waiting for master update";
+ }
thd->version=refresh_version;
thd->set_time();
DBUG_RETURN(0);
}
-static int safe_sleep(THD* thd, int sec)
+static int safe_sleep(THD* thd, int sec, CHECK_KILLED_FUNC thread_killed,
+ void* thread_killed_arg)
{
thr_alarm_t alarmed;
thr_alarm_init(&alarmed);
@@ -773,21 +1401,21 @@ static int safe_sleep(THD* thd, int sec)
if (thr_alarm_in_use(&alarmed))
thr_end_alarm(&alarmed);
- if (slave_killed(thd))
+ if ((*thread_killed)(thd,thread_killed_arg))
return 1;
start_time=time((time_t*) 0);
}
return 0;
}
-
static int request_dump(MYSQL* mysql, MASTER_INFO* mi)
{
char buf[FN_REFLEN + 10];
int len;
int binlog_flags = 0; // for now
- char* logname = mi->log_file_name;
- int4store(buf, mi->pos);
+ char* logname = mi->master_log_name;
+ // TODO if big log files: Change next to int8store()
+ int4store(buf, (longlong) mi->master_log_pos);
int2store(buf + 4, binlog_flags);
int4store(buf + 6, server_id);
len = (uint) strlen(logname);
@@ -805,7 +1433,7 @@ static int request_dump(MYSQL* mysql, MASTER_INFO* mi)
return 0;
}
-static int request_table_dump(MYSQL* mysql, char* db, char* table)
+static int request_table_dump(MYSQL* mysql, const char* db, const char* table)
{
char buf[1024];
char * p = buf;
@@ -833,10 +1461,9 @@ command");
return 0;
}
-
-static uint read_event(MYSQL* mysql, MASTER_INFO *mi)
+static ulong read_event(MYSQL* mysql, MASTER_INFO *mi)
{
- uint len = packet_error;
+ ulong len = packet_error;
// for convinience lets think we start by
// being in the interrupted state :-)
int read_errno = EINTR;
@@ -848,15 +1475,15 @@ static uint read_event(MYSQL* mysql, MASTER_INFO *mi)
return packet_error;
#endif
- while (!abort_loop && !abort_slave && len == packet_error &&
+ while (!abort_loop && !mi->abort_slave && len == packet_error &&
read_errno == EINTR )
{
len = mc_net_safe_read(mysql);
read_errno = errno;
}
- if (abort_loop || abort_slave)
+ if (abort_loop || mi->abort_slave)
return packet_error;
- if (len == packet_error || (int) len < 1)
+ if (len == packet_error || (long) len < 1)
{
sql_print_error("Error reading packet from server: %s (read_errno %d,\
server_errno=%d)",
@@ -877,328 +1504,71 @@ server_errno=%d)",
return len - 1;
}
-static int check_expected_error(THD* thd, int expected_error)
+int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int expected_error)
{
- switch(expected_error)
+ switch (expected_error)
{
case ER_NET_READ_ERROR:
case ER_NET_ERROR_ON_WRITE:
case ER_SERVER_SHUTDOWN:
case ER_NEW_ABORTING_CONNECTION:
- my_snprintf(last_slave_error, sizeof(last_slave_error),
+ my_snprintf(rli->last_slave_error, sizeof(rli->last_slave_error),
"Slave: query '%s' partially completed on the master \
and was aborted. There is a chance that your master is inconsistent at this \
point. If you are sure that your master is ok, run this query manually on the\
slave and then restart the slave with SET SQL_SLAVE_SKIP_COUNTER=1;\
SLAVE START;", thd->query);
- last_slave_errno = expected_error;
- sql_print_error("%s",last_slave_error);
+ rli->last_slave_errno = expected_error;
+ sql_print_error("%s",rli->last_slave_error);
return 1;
default:
return 0;
}
}
-inline int ignored_error_code(int err_code)
+static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
{
- return use_slave_mask && bitmap_is_set(&slave_error_mask, err_code);
-}
-
-static int exec_event(THD* thd, NET* net, MASTER_INFO* mi, int event_len)
-{
- Log_event * ev = Log_event::read_log_event((const char*)net->read_pos + 1,
- event_len);
- char llbuff[22];
-
+ DBUG_ASSERT(rli->sql_thd==thd);
+ Log_event * ev = next_event(rli);
+ DBUG_ASSERT(rli->sql_thd==thd);
+ if (sql_slave_killed(thd,rli))
+ return 1;
if (ev)
{
int type_code = ev->get_type_code();
- if (ev->server_id == ::server_id || slave_skip_counter)
+ int exec_res;
+ pthread_mutex_lock(&rli->data_lock);
+ if (ev->server_id == ::server_id ||
+ (rli->slave_skip_counter && type_code != ROTATE_EVENT))
{
- if(type_code == LOAD_EVENT)
- skip_load_data_infile(net);
-
- mi->inc_pos(event_len);
- flush_master_info(mi);
- if(slave_skip_counter && /* protect against common user error of
+ /* TODO: I/O thread should not even log events with the same server id */
+ rli->inc_pos(ev->get_event_len(),
+ type_code != STOP_EVENT ? ev->log_pos : LL(0),
+ 1/* skip lock*/);
+ flush_relay_log_info(rli);
+ if (rli->slave_skip_counter && /* protect against common user error of
setting the counter to 1 instead of 2
while recovering from an failed
auto-increment insert */
- !(type_code == INTVAR_EVENT &&
- slave_skip_counter == 1))
- --slave_skip_counter;
+ !((type_code == INTVAR_EVENT || type_code == STOP_EVENT) &&
+ rli->slave_skip_counter == 1))
+ --rli->slave_skip_counter;
+ pthread_mutex_unlock(&rli->data_lock);
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
- if(!ev->when)
+ if (!ev->when)
ev->when = time(NULL);
-
- switch(type_code) {
- case QUERY_EVENT:
- {
- Query_log_event* qev = (Query_log_event*)ev;
- int q_len = qev->q_len;
- int expected_error,actual_error = 0;
- init_sql_alloc(&thd->mem_root, 8192,0);
- thd->db = rewrite_db((char*)qev->db);
- if (db_ok(thd->db, replicate_do_db, replicate_ignore_db))
- {
- thd->query = (char*)qev->query;
- thd->set_time((time_t)qev->when);
- thd->current_tablenr = 0;
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- thd->query_id = query_id++;
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
- thd->last_nx_table = thd->last_nx_db = 0;
- thd->query_error = 0; // clear error
- thd->net.last_errno = 0;
- thd->net.last_error[0] = 0;
- thd->slave_proxy_id = qev->thread_id; // for temp tables
-
- // sanity check to make sure the master did not get a really bad
- // error on the query
- if (ignored_error_code((expected_error=qev->error_code)) ||
- !check_expected_error(thd, expected_error))
- {
- mysql_parse(thd, thd->query, q_len);
- if (expected_error !=
- (actual_error = thd->net.last_errno) && expected_error &&
- !ignored_error_code(actual_error))
- {
- const char* errmsg = "Slave: did not get the expected error\
- running query from master - expected: '%s' (%d), got '%s' (%d)";
- sql_print_error(errmsg, ER_SAFE(expected_error),
- expected_error,
- actual_error ? thd->net.last_error:"no error",
- actual_error);
- thd->query_error = 1;
- }
- else if (expected_error == actual_error ||
- ignored_error_code(actual_error))
- {
- thd->query_error = 0;
- *last_slave_error = 0;
- last_slave_errno = 0;
- }
- }
- else
- {
- // master could be inconsistent, abort and tell DBA to check/fix it
- thd->db = thd->query = 0;
- thd->convert_set = 0;
- close_thread_tables(thd);
- free_root(&thd->mem_root,0);
- delete ev;
- return 1;
- }
- }
- thd->db = 0; // prevent db from being freed
- thd->query = 0; // just to be sure
- // assume no convert for next query unless set explictly
- thd->convert_set = 0;
- close_thread_tables(thd);
-
- if (thd->query_error || thd->fatal_error)
- {
- sql_print_error("Slave: error running query '%s' ",
- qev->query);
- last_slave_errno = actual_error ? actual_error : -1;
- my_snprintf(last_slave_error, sizeof(last_slave_error),
- "error '%s' on query '%s'",
- actual_error ? thd->net.last_error :
- "unexpected success or fatal error",
- qev->query
- );
- free_root(&thd->mem_root,0);
- delete ev;
- return 1;
- }
- free_root(&thd->mem_root,0);
- delete ev;
-
- mi->inc_pos(event_len);
- flush_master_info(mi);
- break;
- }
-
- case LOAD_EVENT:
- {
- Load_log_event* lev = (Load_log_event*)ev;
- init_sql_alloc(&thd->mem_root, 8192,0);
- thd->db = rewrite_db((char*)lev->db);
- thd->query = 0;
- thd->query_error = 0;
-
- if(db_ok(thd->db, replicate_do_db, replicate_ignore_db))
- {
- thd->set_time((time_t)lev->when);
- thd->current_tablenr = 0;
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- thd->query_id = query_id++;
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
-
- TABLE_LIST tables;
- bzero((char*) &tables,sizeof(tables));
- tables.db = thd->db;
- tables.name = tables.real_name = (char*)lev->table_name;
- tables.lock_type = TL_WRITE;
- // the table will be opened in mysql_load
- if(table_rules_on && !tables_ok(thd, &tables))
- {
- skip_load_data_infile(net);
- }
- else
- {
- enum enum_duplicates handle_dup = DUP_IGNORE;
- if(lev->sql_ex.opt_flags && REPLACE_FLAG)
- handle_dup = DUP_REPLACE;
- sql_exchange ex((char*)lev->fname, lev->sql_ex.opt_flags &&
- DUMPFILE_FLAG );
- String field_term(&lev->sql_ex.field_term, 1),
- enclosed(&lev->sql_ex.enclosed, 1),
- line_term(&lev->sql_ex.line_term,1),
- escaped(&lev->sql_ex.escaped, 1),
- line_start(&lev->sql_ex.line_start, 1);
-
- ex.field_term = &field_term;
- if(lev->sql_ex.empty_flags & FIELD_TERM_EMPTY)
- ex.field_term->length(0);
-
- ex.enclosed = &enclosed;
- if(lev->sql_ex.empty_flags & ENCLOSED_EMPTY)
- ex.enclosed->length(0);
-
- ex.line_term = &line_term;
- if(lev->sql_ex.empty_flags & LINE_TERM_EMPTY)
- ex.line_term->length(0);
-
- ex.line_start = &line_start;
- if(lev->sql_ex.empty_flags & LINE_START_EMPTY)
- ex.line_start->length(0);
-
- ex.escaped = &escaped;
- if(lev->sql_ex.empty_flags & ESCAPED_EMPTY)
- ex.escaped->length(0);
-
- ex.opt_enclosed = (lev->sql_ex.opt_flags & OPT_ENCLOSED_FLAG);
- if(lev->sql_ex.empty_flags & FIELD_TERM_EMPTY)
- ex.field_term->length(0);
-
- ex.skip_lines = lev->skip_lines;
-
-
- List<Item> fields;
- lev->set_fields(fields);
- thd->slave_proxy_id = thd->thread_id;
- thd->net.vio = net->vio;
- // mysql_load will use thd->net to read the file
- thd->net.pkt_nr = net->pkt_nr;
- // make sure the client does not get confused
- // about the packet sequence
- if(mysql_load(thd, &ex, &tables, fields, handle_dup, 1,
- TL_WRITE))
- thd->query_error = 1;
- if(thd->cuted_fields)
- sql_print_error("Slave: load data infile at position %s in log \
-'%s' produced %d warning(s)", llstr(glob_mi.pos,llbuff), RPL_LOG_NAME,
- thd->cuted_fields );
- net->pkt_nr = thd->net.pkt_nr;
- }
- }
- else
- {
- // we will just ask the master to send us /dev/null if we do not
- // want to load the data :-)
- skip_load_data_infile(net);
- }
-
- thd->net.vio = 0;
- thd->db = 0;// prevent db from being freed
- close_thread_tables(thd);
- if(thd->query_error)
- {
- int sql_error = thd->net.last_errno;
- if(!sql_error)
- sql_error = ER_UNKNOWN_ERROR;
-
- sql_print_error("Slave: Error '%s' running load data infile ",
- ER(sql_error));
- delete ev;
- free_root(&thd->mem_root,0);
- return 1;
- }
-
- delete ev;
- free_root(&thd->mem_root,0);
-
- if(thd->fatal_error)
- {
- sql_print_error("Slave: Fatal error running query '%s' ",
- thd->query);
- return 1;
- }
-
- mi->inc_pos(event_len);
- flush_master_info(mi);
- break;
- }
-
- case START_EVENT:
- mi->inc_pos(event_len);
- flush_master_info(mi);
- delete ev;
- break;
-
- case STOP_EVENT:
- if(mi->pos > 4) // stop event should be ignored after rotate event
- {
- close_temporary_tables(thd);
- mi->inc_pos(event_len);
- flush_master_info(mi);
- }
- delete ev;
- break;
- case ROTATE_EVENT:
- {
- Rotate_log_event* rev = (Rotate_log_event*)ev;
- int ident_len = rev->ident_len;
- pthread_mutex_lock(&mi->lock);
- memcpy(mi->log_file_name, rev->new_log_ident,ident_len );
- mi->log_file_name[ident_len] = 0;
- mi->pos = 4; // skip magic number
- pthread_cond_broadcast(&mi->cond);
- pthread_mutex_unlock(&mi->lock);
- flush_master_info(mi);
-#ifndef DBUG_OFF
- if(abort_slave_event_count)
- ++events_till_abort;
-#endif
- delete ev;
- break;
- }
-
- case INTVAR_EVENT:
- {
- Intvar_log_event* iev = (Intvar_log_event*)ev;
- switch(iev->type)
- {
- case LAST_INSERT_ID_EVENT:
- thd->last_insert_id_used = 1;
- thd->last_insert_id = iev->val;
- break;
- case INSERT_ID_EVENT:
- thd->next_insert_id = iev->val;
- break;
-
- }
- mi->inc_pending(event_len);
- delete ev;
- break;
- }
- }
+ ev->thd = thd;
+ thd->log_pos = ev->log_pos;
+ exec_res = ev->exec_event(rli);
+ DBUG_ASSERT(rli->sql_thd==thd);
+ delete ev;
+ return exec_res;
}
else
{
@@ -1208,338 +1578,702 @@ This may also be a network problem, or just a bug in the master or slave code.\
");
return 1;
}
- return 0;
}
-
-// slave thread
-pthread_handler_decl(handle_slave,arg __attribute__((unused)))
+/* slave I/O thread */
+pthread_handler_decl(handle_slave_io,arg)
{
#ifndef DBUG_OFF
- slave_begin:
+slave_begin:
#endif
THD *thd; // needs to be first for thread_stack
MYSQL *mysql = NULL ;
+ MASTER_INFO* mi = (MASTER_INFO*)arg;
char llbuff[22];
-
- pthread_mutex_lock(&LOCK_slave);
- if (!server_id)
- {
- pthread_cond_broadcast(&COND_slave_start);
- pthread_mutex_unlock(&LOCK_slave);
- sql_print_error("Server id not set, will not start slave");
- pthread_exit((void*)1);
- }
+ bool retried_once = 0;
+ ulonglong last_failed_pos = 0; // TODO: see if last_failed_pos is needed
+ DBUG_ASSERT(mi->inited);
- if(slave_running)
- {
- pthread_cond_broadcast(&COND_slave_start);
- pthread_mutex_unlock(&LOCK_slave);
- pthread_exit((void*)1); // safety just in case
- }
- slave_running = 1;
- abort_slave = 0;
+ pthread_mutex_lock(&mi->run_lock);
#ifndef DBUG_OFF
- events_till_abort = abort_slave_event_count;
+ mi->events_till_abort = abort_slave_event_count;
#endif
- pthread_cond_broadcast(&COND_slave_start);
- pthread_mutex_unlock(&LOCK_slave);
-
- // int error = 1;
- bool retried_once = 0;
- ulonglong last_failed_pos = 0;
// needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff
my_thread_init();
- slave_thd = thd = new THD; // note that contructor of THD uses DBUG_ !
- thd->set_time();
- DBUG_ENTER("handle_slave");
+ thd = new THD; // note that contructor of THD uses DBUG_ !
+ DBUG_ENTER("handle_slave_io");
pthread_detach_this_thread();
- if (init_slave_thread(thd) || init_master_info(&glob_mi))
- {
- sql_print_error("Failed during slave thread initialization");
- goto err;
- }
+ if (init_slave_thread(thd, SLAVE_THD_IO))
+ {
+ pthread_cond_broadcast(&mi->start_cond);
+ pthread_mutex_unlock(&mi->run_lock);
+ sql_print_error("Failed during slave I/O thread initialization");
+ goto err;
+ }
+ mi->io_thd = thd;
thd->thread_stack = (char*)&thd; // remember where our stack is
- thd->temporary_tables = save_temporary_tables; // restore temp tables
threads.append(thd);
- glob_mi.pending = 0; //this should always be set to 0 when the slave thread
- // is started
+ mi->slave_running = 1;
+ mi->abort_slave = 0;
+ pthread_cond_broadcast(&mi->start_cond);
+ pthread_mutex_unlock(&mi->run_lock);
DBUG_PRINT("info",("master info: log_file_name=%s, position=%s",
- glob_mi.log_file_name, llstr(glob_mi.pos,llbuff)));
-
+ mi->master_log_name, llstr(mi->master_log_pos,llbuff)));
- if (!(mysql = mc_mysql_init(NULL)))
+ if (!(mi->mysql = mysql = mc_mysql_init(NULL)))
{
- sql_print_error("Slave thread: error in mc_mysql_init()");
+ sql_print_error("Slave I/O thread: error in mc_mysql_init()");
goto err;
}
thd->proc_info = "connecting to master";
#ifndef DBUG_OFF
- sql_print_error("Slave thread initialized");
+ sql_print_error("Slave I/O thread initialized");
#endif
// we can get killed during safe_connect
- if (!safe_connect(thd, mysql, &glob_mi))
- sql_print_error("Slave: connected to master '%s@%s:%d',\
- replication started in log '%s' at position %s", glob_mi.user,
- glob_mi.host, glob_mi.port,
- RPL_LOG_NAME,
- llstr(glob_mi.pos,llbuff));
+ if (!safe_connect(thd, mysql, mi))
+ sql_print_error("Slave I/O thread: connected to master '%s@%s:%d',\
+ replication started in log '%s' at position %s", mi->user,
+ mi->host, mi->port,
+ IO_RPL_LOG_NAME,
+ llstr(mi->master_log_pos,llbuff));
else
{
- sql_print_error("Slave thread killed while connecting to master");
+ sql_print_error("Slave I/O thread killed while connecting to master");
goto err;
}
-
+
connected:
+
+ thd->slave_net = &mysql->net;
+ thd->proc_info = "Checking master version";
+ if (check_master_version(mysql, mi))
+ goto err;
+ if (!mi->old_format)
+ {
+ /*
+ Register ourselves with the master.
+ If fails, this is not fatal - we just print the error message and go
+ on with life.
+ */
+ thd->proc_info = "Registering slave on master";
+ if (register_slave_on_master(mysql) || update_slave_list(mysql))
+ goto err;
+ }
- while (!slave_killed(thd))
+ while (!io_slave_killed(thd,mi))
{
- thd->proc_info = "Requesting binlog dump";
- if(request_dump(mysql, &glob_mi))
- {
- sql_print_error("Failed on request_dump()");
- if(slave_killed(thd))
- {
- sql_print_error("Slave thread killed while requesting master \
+ thd->proc_info = "Requesting binlog dump";
+ if (request_dump(mysql, mi))
+ {
+ sql_print_error("Failed on request_dump()");
+ if(io_slave_killed(thd,mi))
+ {
+ sql_print_error("Slave I/O thread killed while requesting master \
dump");
- goto err;
- }
+ goto err;
+ }
- thd->proc_info = "Waiiting to reconnect after a failed dump request";
- if(mysql->net.vio)
- vio_close(mysql->net.vio);
- // first time retry immediately, assuming that we can recover
- // right away - if first time fails, sleep between re-tries
- // hopefuly the admin can fix the problem sometime
- if(retried_once)
- safe_sleep(thd, glob_mi.connect_retry);
- else
- retried_once = 1;
+ thd->proc_info = "Waiiting to reconnect after a failed dump request";
+ mc_end_server(mysql);
+ /*
+ First time retry immediately, assuming that we can recover
+ right away - if first time fails, sleep between re-tries
+ hopefuly the admin can fix the problem sometime
+ */
+ if (retried_once)
+ safe_sleep(thd,mi->connect_retry,(CHECK_KILLED_FUNC)io_slave_killed,
+ (void*)mi);
+ else
+ retried_once = 1;
- if(slave_killed(thd))
- {
- sql_print_error("Slave thread killed while retrying master \
+ if (io_slave_killed(thd,mi))
+ {
+ sql_print_error("Slave I/O thread killed while retrying master \
dump");
- goto err;
- }
-
- thd->proc_info = "Reconnecting after a failed dump request";
- last_failed_pos=glob_mi.pos;
- sql_print_error("Slave: failed dump request, reconnecting to \
-try again, log '%s' at postion %s", RPL_LOG_NAME,
- llstr(last_failed_pos,llbuff));
- if(safe_reconnect(thd, mysql, &glob_mi) || slave_killed(thd))
- {
- sql_print_error("Slave thread killed during or after reconnect");
- goto err;
- }
-
- goto connected;
- }
+ goto err;
+ }
- while(!slave_killed(thd))
- {
- thd->proc_info = "Reading master update";
- uint event_len = read_event(mysql, &glob_mi);
- if(slave_killed(thd))
- {
- sql_print_error("Slave thread killed while reading event");
- goto err;
- }
+ thd->proc_info = "Reconnecting after a failed dump request";
+ sql_print_error("Slave I/O thread: failed dump request, \
+reconnecting to try again, log '%s' at postion %s", IO_RPL_LOG_NAME,
+ llstr(mi->master_log_pos,llbuff));
+ if (safe_reconnect(thd, mysql, mi) || io_slave_killed(thd,mi))
+ {
+ sql_print_error("Slave I/O thread killed during or \
+after reconnect");
+ goto err;
+ }
+
+ goto connected;
+ }
+
+ while (!io_slave_killed(thd,mi))
+ {
+ thd->proc_info = "Reading master update";
+ ulong event_len = read_event(mysql, mi);
+ if (io_slave_killed(thd,mi))
+ {
+ sql_print_error("Slave I/O thread killed while reading event");
+ goto err;
+ }
- if (event_len == packet_error)
- {
- if(mc_mysql_errno(mysql) == ER_NET_PACKET_TOO_LARGE)
- {
- sql_print_error("Log entry on master is longer than \
-max_allowed_packet on slave. Slave thread will be aborted. If the entry is \
-really supposed to be that long, restart the server with a higher value of \
-max_allowed_packet. The current value is %ld", max_allowed_packet);
- goto err;
- }
+ if (event_len == packet_error)
+ {
+ if (mc_mysql_errno(mysql) == ER_NET_PACKET_TOO_LARGE)
+ {
+ sql_print_error("Log entry on master is longer than \
+max_allowed_packet (%ld) on slave. Slave thread will be aborted. If the entry \
+is correct, restart the server with a higher value of max_allowed_packet",
+ max_allowed_packet);
+ goto err;
+ }
- thd->proc_info = "Waiting to reconnect after a failed read";
- if(mysql->net.vio)
- vio_close(mysql->net.vio);
- if(retried_once) // punish repeat offender with sleep
- safe_sleep(thd, glob_mi.connect_retry);
- else
- retried_once = 1;
+ thd->proc_info = "Waiting to reconnect after a failed read";
+ mc_end_server(mysql);
+ if (retried_once) // punish repeat offender with sleep
+ safe_sleep(thd,mi->connect_retry,(CHECK_KILLED_FUNC)io_slave_killed,
+ (void*)mi);
+ else
+ retried_once = 1;
- if(slave_killed(thd))
- {
- sql_print_error("Slave thread killed while waiting to \
+ if (io_slave_killed(thd,mi))
+ {
+ sql_print_error("Slave I/O thread killed while waiting to \
reconnect after a failed read");
- goto err;
- }
- thd->proc_info = "Reconnecting after a failed read";
- last_failed_pos= glob_mi.pos;
- sql_print_error("Slave: Failed reading log event, \
-reconnecting to retry, log '%s' position %s", RPL_LOG_NAME,
- llstr(last_failed_pos, llbuff));
- if(safe_reconnect(thd, mysql, &glob_mi) || slave_killed(thd))
- {
- sql_print_error("Slave thread killed during or after a \
+ goto err;
+ }
+ thd->proc_info = "Reconnecting after a failed read";
+ sql_print_error("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) || io_slave_killed(thd,mi))
+ {
+ sql_print_error("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)
+ goto err;
+ }
+ goto connected;
+ } // if(event_len == packet_error)
- thd->proc_info = "Processing master log event";
- if(exec_event(thd, &mysql->net, &glob_mi, event_len))
- {
- sql_print_error("\
-Error running query, slave aborted. Fix the problem, and re-start \
-the slave thread with \"mysqladmin start-slave\". We stopped at log \
-'%s' position %s",
- RPL_LOG_NAME, llstr(glob_mi.pos, llbuff));
- goto err;
- // there was an error running the query
- // abort the slave thread, when the problem is fixed, the user
- // should restart the slave with mysqladmin start-slave
- }
+ thd->proc_info = "Queueing event from master";
+ if (queue_event(mi,(const char*)mysql->net.read_pos + 1,
+ event_len))
+ {
+ sql_print_error("Slave I/O thread could not queue event \
+from master");
+ goto err;
+ }
+ flush_master_info(mi);
+ // TODO: check debugging abort code
#ifndef DBUG_OFF
- if(abort_slave_event_count && !--events_till_abort)
- {
- sql_print_error("Slave: debugging abort");
- goto err;
- }
+ if (abort_slave_event_count && !--events_till_abort)
+ {
+ sql_print_error("Slave I/O thread: debugging abort");
+ goto err;
+ }
#endif
-
- // successful exec with offset advance,
- // the slave repents and his sins are forgiven!
- if(glob_mi.pos > last_failed_pos)
- {
- retried_once = 0;
+ }
+ }
+
+ // error = 0;
+err:
+ // print the current replication position
+ sql_print_error("Slave I/O thread exiting, read up to log '%s', position %s",
+ IO_RPL_LOG_NAME, llstr(mi->master_log_pos,llbuff));
+ thd->query = thd->db = 0; // extra safety
+ if (mysql)
+ {
+ mc_mysql_close(mysql);
+ mi->mysql=0;
+ }
+ thd->proc_info = "Waiting for slave mutex on exit";
+ pthread_mutex_lock(&mi->run_lock);
+ mi->slave_running = 0;
+ mi->io_thd = 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
+ DBUG_ASSERT(thd->net.buff != 0);
+ net_end(&thd->net); // destructor will not free it, because net.vio is 0
+ pthread_mutex_lock(&LOCK_thread_count);
+ delete thd;
+ pthread_mutex_unlock(&LOCK_thread_count);
+ pthread_cond_broadcast(&mi->stop_cond); // tell the world we are done
+ pthread_mutex_unlock(&mi->run_lock);
+ my_thread_end();
#ifndef DBUG_OFF
- stuck_count = 0;
-#endif
- }
+ if(abort_slave_event_count && !events_till_abort)
+ goto slave_begin;
+#endif
+ pthread_exit(0);
+ DBUG_RETURN(0); // Can't return anything here
+}
+
+
+/* slave SQL logic thread */
+
+pthread_handler_decl(handle_slave_sql,arg)
+{
#ifndef DBUG_OFF
- else
- {
- // show a little mercy, allow slave to read one more event
- // before cutting him off - otherwise he gets stuck
- // on Intvar events, since they do not advance the offset
- // immediately
- if (++stuck_count > 2)
- events_till_disconnect++;
- }
-#endif
- } // while(!slave_killed(thd)) - read/exec loop
- } // while(!slave_killed(thd)) - slave loop
+slave_begin:
+#endif
+ THD *thd; /* needs to be first for thread_stack */
+ MYSQL *mysql = NULL ;
+ bool retried_once = 0;
+ ulonglong last_failed_pos = 0; // TODO: see if this can be removed
+ char llbuff[22],llbuff1[22];
+ RELAY_LOG_INFO* rli = &((MASTER_INFO*)arg)->rli;
+ const char* errmsg=0;
+ DBUG_ASSERT(rli->inited);
+ pthread_mutex_lock(&rli->run_lock);
+ DBUG_ASSERT(!rli->slave_running);
+#ifndef DBUG_OFF
+ rli->events_till_abort = abort_slave_event_count;
+#endif
+
+
+ // needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff
+ my_thread_init();
+ thd = new THD; // note that contructor of THD uses DBUG_ !
+ DBUG_ENTER("handle_slave_sql");
+
+ pthread_detach_this_thread();
+ if (init_slave_thread(thd, SLAVE_THD_SQL))
+ {
+ /*
+ TODO: this is currently broken - slave start and change master
+ will be stuck if we fail here
+ */
+ pthread_cond_broadcast(&rli->start_cond);
+ pthread_mutex_unlock(&rli->run_lock);
+ sql_print_error("Failed during slave thread initialization");
+ goto err;
+ }
+ thd->thread_stack = (char*)&thd; // remember where our stack is
+ thd->temporary_tables = rli->save_temporary_tables; // restore temp tables
+ threads.append(thd);
+ rli->sql_thd = thd;
+ rli->slave_running = 1;
+ rli->abort_slave = 0;
+ pthread_cond_broadcast(&rli->start_cond);
+ pthread_mutex_unlock(&rli->run_lock);
+ rli->pending = 0; //this should always be set to 0 when the slave thread
+ // is started
+ if (init_relay_log_pos(rli,0,0,1/*need data lock*/,&errmsg))
+ {
+ sql_print_error("Error initializing relay log position: %s",
+ errmsg);
+ goto err;
+ }
+ DBUG_ASSERT(rli->relay_log_pos >= 4);
+ DBUG_ASSERT(my_b_tell(rli->cur_log) == rli->relay_log_pos);
+
+ DBUG_PRINT("info",("master info: log_file_name=%s, position=%s",
+ rli->master_log_name, llstr(rli->master_log_pos,llbuff)));
+ DBUG_ASSERT(rli->sql_thd == thd);
+ sql_print_error("Slave SQL thread initialized, starting replication in \
+log '%s' at position %s,relay log: name='%s',pos='%s'", RPL_LOG_NAME,
+ llstr(rli->master_log_pos,llbuff),rli->relay_log_name,
+ llstr(rli->relay_log_pos,llbuff1));
+ while (!sql_slave_killed(thd,rli))
+ {
+ thd->proc_info = "Processing master log event";
+ DBUG_ASSERT(rli->sql_thd == thd);
+ if (exec_relay_log_event(thd,rli))
+ {
+ // do not scare the user if SQL thread was simply killed or stopped
+ if (!sql_slave_killed(thd,rli))
+ sql_print_error("\
+Error running query, slave SQL thread aborted. Fix the problem, and restart \
+the slave SQL thread with \"SLAVE START\". We stopped at log \
+'%s' position %s",
+ RPL_LOG_NAME, llstr(rli->master_log_pos, llbuff));
+ goto err;
+ }
+ } // while(!sql_slave_killed(thd,rli)) - read/exec loop
// error = 0;
err:
// print the current replication position
- sql_print_error("Slave thread exiting, replication stopped in log '%s' at \
-position %s",
- RPL_LOG_NAME, llstr(glob_mi.pos,llbuff));
+ sql_print_error("Slave SQL thread exiting, replication stopped in log \
+ '%s' at position %s",
+ RPL_LOG_NAME, llstr(rli->master_log_pos,llbuff));
thd->query = thd->db = 0; // extra safety
- if(mysql)
- mc_mysql_close(mysql);
thd->proc_info = "Waiting for slave mutex on exit";
- pthread_mutex_lock(&LOCK_slave);
- slave_running = 0;
- abort_slave = 0;
- save_temporary_tables = thd->temporary_tables;
+ pthread_mutex_lock(&rli->run_lock);
+ DBUG_ASSERT(rli->slave_running == 1); // tracking buffer overrun
+ rli->slave_running = 0;
+ rli->save_temporary_tables = thd->temporary_tables;
+
+ /*
+ TODO: see if we can do this conditionally in next_event() instead
+ to avoid unneeded position re-init
+ */
+ rli->log_pos_current=0;
thd->temporary_tables = 0; // remove tempation from destructor to close them
- pthread_cond_broadcast(&COND_slave_stopped); // tell the world we are done
- pthread_mutex_unlock(&LOCK_slave);
+ DBUG_ASSERT(thd->net.buff != 0);
net_end(&thd->net); // destructor will not free it, because we are weird
- slave_thd = 0;
+ DBUG_ASSERT(rli->sql_thd == thd);
+ rli->sql_thd = 0;
+ pthread_mutex_lock(&LOCK_thread_count);
delete thd;
+ pthread_mutex_unlock(&LOCK_thread_count);
+ pthread_cond_broadcast(&rli->stop_cond);
+ // tell the world we are done
+ pthread_mutex_unlock(&rli->run_lock);
my_thread_end();
-#ifndef DBUG_OFF
- if(abort_slave_event_count && !events_till_abort)
+#ifndef DBUG_OFF // TODO: reconsider the code below
+ if (abort_slave_event_count && !rli->events_till_abort)
goto slave_begin;
#endif
pthread_exit(0);
DBUG_RETURN(0); // Can't return anything here
}
+static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev)
+{
+ int error = 1;
+ ulong num_bytes;
+ bool cev_not_written;
+ THD* thd;
+ NET* net = &mi->mysql->net;
-/* try to connect until successful or slave killed */
+ if (unlikely(!cev->is_valid()))
+ return 1;
+ /*
+ TODO: fix to honor table rules, not only db rules
+ */
+ if (!db_ok(cev->db, replicate_do_db, replicate_ignore_db))
+ {
+ skip_load_data_infile(net);
+ return 0;
+ }
+ DBUG_ASSERT(cev->inited_from_old);
+ thd = mi->io_thd;
+ thd->file_id = cev->file_id = mi->file_id++;
+ thd->server_id = cev->server_id;
+ cev_not_written = 1;
+
+ if (unlikely(net_request_file(net,cev->fname)))
+ {
+ sql_print_error("Slave I/O: failed requesting download of '%s'",
+ cev->fname);
+ goto err;
+ }
-static int safe_connect(THD* thd, MYSQL* mysql, MASTER_INFO* mi)
+ /* this dummy block is so we could insantiate Append_block_log_event
+ once and then modify it slightly instead of doing it multiple times
+ in the loop
+ */
+ {
+ Append_block_log_event aev(thd,0,0);
+
+ for (;;)
+ {
+ if (unlikely((num_bytes=my_net_read(net)) == packet_error))
+ {
+ sql_print_error("Network read error downloading '%s' from master",
+ cev->fname);
+ goto err;
+ }
+ if (unlikely(!num_bytes)) /* eof */
+ {
+ send_ok(net); /* 3.23 master wants it */
+ Execute_load_log_event xev(thd);
+ xev.log_pos = mi->master_log_pos;
+ if (unlikely(mi->rli.relay_log.append(&xev)))
+ {
+ sql_print_error("Slave I/O: error writing Exec_load event to \
+relay log");
+ goto err;
+ }
+ break;
+ }
+ if (unlikely(cev_not_written))
+ {
+ 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 \
+relay log");
+ goto err;
+ }
+ cev_not_written=0;
+ }
+ else
+ {
+ aev.block = (char*)net->read_pos;
+ aev.block_len = num_bytes;
+ aev.log_pos = mi->master_log_pos;
+ if (unlikely(mi->rli.relay_log.append(&aev)))
+ {
+ sql_print_error("Slave I/O: error writing Append_block event to \
+relay log");
+ goto err;
+ }
+ }
+ }
+ }
+ error=0;
+err:
+ return error;
+}
+
+// We assume we already locked mi->data_lock
+static int process_io_rotate(MASTER_INFO* mi, Rotate_log_event* rev)
{
- int slave_was_killed;
+ if (unlikely(!rev->is_valid()))
+ return 1;
+ DBUG_ASSERT(rev->ident_len<sizeof(mi->master_log_name));
+ memcpy(mi->master_log_name,rev->new_log_ident,
+ rev->ident_len);
+ mi->master_log_name[rev->ident_len] = 0;
+ mi->master_log_pos = rev->pos;
#ifndef DBUG_OFF
- events_till_disconnect = disconnect_slave_event_count;
-#endif
- while(!(slave_was_killed = slave_killed(thd)) &&
- !mc_mysql_connect(mysql, mi->host, mi->user, mi->password, 0,
- mi->port, 0, 0))
+ /*
+ If we do not do this, we will be getting the first
+ rotate event forever, so we need to not disconnect after one.
+ */
+ if (disconnect_slave_event_count)
+ events_till_disconnect++;
+#endif
+ return 0;
+}
+
+/*
+ TODO: verify the issue with stop events, see if we need them at all
+ in the relay log
+ TODO: test this code before release - it has to be tested on a separte
+ setup with 3.23 master
+*/
+
+static int queue_old_event(MASTER_INFO *mi, const char *buf,
+ ulong event_len)
+{
+ const char *errmsg = 0;
+ bool inc_pos = 1;
+ bool processed_stop_event = 0;
+ char* tmp_buf = 0;
+ /* if we get Load event, we need to pass a non-reusable buffer
+ to read_log_event, so we do a trick
+ */
+ if (buf[EVENT_TYPE_OFFSET] == LOAD_EVENT)
+ {
+ if (unlikely(!(tmp_buf=(char*)my_malloc(event_len+1,MYF(MY_WME)))))
+ {
+ sql_print_error("Slave I/O: out of memory for Load event");
+ return 1;
+ }
+ memcpy(tmp_buf,buf,event_len);
+ tmp_buf[event_len]=0; // Create_file constructor wants null-term buffer
+ buf = (const char*)tmp_buf;
+ }
+ Log_event *ev = Log_event::read_log_event(buf,event_len, &errmsg,
+ 1 /*old format*/ );
+ if (unlikely(!ev))
{
- sql_print_error("Slave thread: error connecting to master: %s (%d),\
- retry in %d sec", mc_mysql_error(mysql), errno, mi->connect_retry);
- safe_sleep(thd, mi->connect_retry);
+ 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));
+ return 1;
}
-
- if(!slave_was_killed)
+ pthread_mutex_lock(&mi->data_lock);
+ ev->log_pos = mi->master_log_pos;
+ switch (ev->get_type_code()) {
+ case ROTATE_EVENT:
+ if (unlikely(process_io_rotate(mi,(Rotate_log_event*)ev)))
{
- mysql_log.write(thd, COM_CONNECT_OUT, "%s@%s:%d",
- mi->user, mi->host, mi->port);
-#ifdef SIGNAL_WITH_VIO_CLOSE
- thd->set_active_vio(mysql->net.vio);
-#endif
+ delete ev;
+ pthread_mutex_unlock(&mi->data_lock);
+ DBUG_ASSERT(!tmp_buf);
+ return 1;
}
+ mi->ignore_stop_event=1;
+ inc_pos = 0;
+ break;
+ case STOP_EVENT:
+ processed_stop_event=1;
+ break;
+ case CREATE_FILE_EVENT:
+ {
+ int error = process_io_create_file(mi,(Create_file_log_event*)ev);
+ delete ev;
+ mi->master_log_pos += event_len;
+ pthread_mutex_unlock(&mi->data_lock);
+ DBUG_ASSERT(tmp_buf);
+ my_free((char*)tmp_buf, MYF(0));
+ return error;
+ }
+ default:
+ mi->ignore_stop_event=0;
+ break;
+ }
+ if (likely(!processed_stop_event || !mi->ignore_stop_event))
+ {
+ if (unlikely(mi->rli.relay_log.append(ev)))
+ {
+ delete ev;
+ pthread_mutex_unlock(&mi->data_lock);
+ DBUG_ASSERT(!tmp_buf);
+ return 1;
+ }
+ }
+ delete ev;
+ if (likely(inc_pos))
+ mi->master_log_pos += event_len;
+ if (unlikely(processed_stop_event))
+ mi->ignore_stop_event=1;
+ pthread_mutex_unlock(&mi->data_lock);
+ DBUG_ASSERT(!tmp_buf);
+ return 0;
+}
+
+/*
+ TODO: verify the issue with stop events, see if we need them at all
+ in the relay log
+*/
+
+int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
+{
+ int error=0;
+ bool inc_pos = 1;
+ bool processed_stop_event = 0;
+ if (mi->old_format)
+ return queue_old_event(mi,buf,event_len);
+
+ pthread_mutex_lock(&mi->data_lock);
- return slave_was_killed;
+ /*
+ TODO: figure out if other events in addition to Rotate
+ require special processing
+ */
+ switch (buf[EVENT_TYPE_OFFSET]) {
+ case STOP_EVENT:
+ processed_stop_event=1;
+ break;
+ case ROTATE_EVENT:
+ {
+ Rotate_log_event rev(buf,event_len,0);
+ if (unlikely(process_io_rotate(mi,&rev)))
+ return 1;
+ inc_pos=0;
+ mi->ignore_stop_event=1;
+ break;
+ }
+ default:
+ mi->ignore_stop_event=0;
+ break;
+ }
+
+ if (likely((!processed_stop_event || !mi->ignore_stop_event) &&
+ !(error = mi->rli.relay_log.appendv(buf,event_len,0))))
+ {
+ if (likely(inc_pos))
+ mi->master_log_pos += event_len;
+ }
+ if (unlikely(processed_stop_event))
+ mi->ignore_stop_event=1;
+ pthread_mutex_unlock(&mi->data_lock);
+ return error;
+}
+
+
+void end_relay_log_info(RELAY_LOG_INFO* rli)
+{
+ if (!rli->inited)
+ return;
+ if (rli->info_fd >= 0)
+ {
+ end_io_cache(&rli->info_file);
+ (void)my_close(rli->info_fd, MYF(MY_WME));
+ rli->info_fd = -1;
+ }
+ if (rli->cur_log_fd >= 0)
+ {
+ end_io_cache(&rli->cache_buf);
+ (void)my_close(rli->cur_log_fd, MYF(MY_WME));
+ rli->cur_log_fd = -1;
+ }
+ rli->inited = 0;
+ rli->log_pos_current=0;
+ rli->relay_log.close(1);
}
+/* try to connect until successful or slave killed */
+static int safe_connect(THD* thd, MYSQL* mysql, MASTER_INFO* mi)
+{
+ return connect_to_master(thd, mysql, mi, 0);
+}
+
+
/*
Try to connect until successful or slave killed or we have retried
master_retry_count times
*/
-static int safe_reconnect(THD* thd, MYSQL* mysql, MASTER_INFO* mi)
+static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi,
+ bool reconnect)
{
int slave_was_killed;
int last_errno= -2; // impossible error
ulong err_count=0;
char llbuff[22];
- /*
- If we lost connection after reading a state set event
- we will be re-reading it, so pending needs to be cleared
- */
- mi->pending = 0;
#ifndef DBUG_OFF
events_till_disconnect = disconnect_slave_event_count;
#endif
- while (!(slave_was_killed = slave_killed(thd)) && mc_mysql_reconnect(mysql))
+ while (!(slave_was_killed = io_slave_killed(thd,mi)) &&
+ (reconnect ? mc_mysql_reconnect(mysql) != 0 :
+ !mc_mysql_connect(mysql, mi->host, mi->user, mi->password, 0,
+ mi->port, 0, 0)))
{
/* Don't repeat last error */
if (mc_mysql_errno(mysql) != last_errno)
{
- sql_print_error("Slave thread: error re-connecting to master: \
-%s, last_errno=%d, retry in %d sec",
+ sql_print_error("Slave I/O thread: error connecting to master \
+'%s@%s:%d': \
+%s, last_errno=%d, retry in %d sec",mi->user,mi->host,mi->port,
mc_mysql_error(mysql), last_errno=mc_mysql_errno(mysql),
mi->connect_retry);
}
- safe_sleep(thd, mi->connect_retry);
- /* if master_retry_count is not set, keep trying until success */
+ safe_sleep(thd,mi->connect_retry,(CHECK_KILLED_FUNC)io_slave_killed,
+ (void*)mi);
+ /*
+ By default we try forever. The reason is that failure will trigger
+ master election, so if the user did not set master_retry_count we
+ do not want to have electioin triggered on the first failure to
+ connect
+ */
if (master_retry_count && err_count++ == master_retry_count)
{
slave_was_killed=1;
+ if (reconnect)
+ change_rpl_status(RPL_ACTIVE_SLAVE,RPL_LOST_SOLDIER);
break;
}
}
if (!slave_was_killed)
{
- sql_print_error("Slave: reconnected to master '%s@%s:%d',\
-replication resumed in log '%s' at position %s", glob_mi.user,
- glob_mi.host, glob_mi.port,
- RPL_LOG_NAME,
- llstr(glob_mi.pos,llbuff));
+ if (reconnect)
+ sql_print_error("Slave: connected to master '%s@%s:%d',\
+replication resumed in log '%s' at position %s", mi->user,
+ mi->host, mi->port,
+ IO_RPL_LOG_NAME,
+ llstr(mi->master_log_pos,llbuff));
+ else
+ {
+ change_rpl_status(RPL_IDLE_SLAVE,RPL_ACTIVE_SLAVE);
+ mysql_log.write(thd, COM_CONNECT_OUT, "%s@%s:%d",
+ mi->user, mi->host, mi->port);
+ }
#ifdef SIGNAL_WITH_VIO_CLOSE
thd->set_active_vio(mysql->net.vio);
#endif
@@ -1548,6 +2282,211 @@ replication resumed in log '%s' at position %s", glob_mi.user,
return slave_was_killed;
}
+
+/*
+ Try to connect until successful or slave killed or we have retried
+ master_retry_count times
+*/
+
+static int safe_reconnect(THD* thd, MYSQL* mysql, MASTER_INFO* mi)
+{
+ return connect_to_master(thd, mysql, mi, 1);
+}
+
+int flush_relay_log_info(RELAY_LOG_INFO* rli)
+{
+ register IO_CACHE* file = &rli->info_file;
+ char lbuf[22],lbuf1[22];
+
+ my_b_seek(file, 0L);
+ my_b_printf(file, "%s\n%s\n%s\n%s\n",
+ rli->relay_log_name, llstr(rli->relay_log_pos, lbuf),
+ rli->master_log_name, llstr(rli->master_log_pos, lbuf1)
+ );
+ flush_io_cache(file);
+ flush_io_cache(rli->cur_log);
+ return 0;
+}
+
+IO_CACHE* reopen_relay_log(RELAY_LOG_INFO* rli, const char** errmsg)
+{
+ DBUG_ASSERT(rli->cur_log != &rli->cache_buf);
+ IO_CACHE* cur_log = rli->cur_log=&rli->cache_buf;
+ DBUG_ASSERT(rli->cur_log_fd == -1);
+ if ((rli->cur_log_fd=open_binlog(cur_log,rli->relay_log_name,
+ errmsg)) <0)
+ return 0;
+ my_b_seek(cur_log,rli->relay_log_pos);
+ return cur_log;
+}
+
+Log_event* next_event(RELAY_LOG_INFO* rli)
+{
+ Log_event* ev;
+ IO_CACHE* cur_log = rli->cur_log;
+ pthread_mutex_t *log_lock = rli->relay_log.get_log_lock();
+ const char* errmsg=0;
+ THD* thd = rli->sql_thd;
+ bool was_killed;
+ DBUG_ASSERT(thd != 0);
+
+ /*
+ For most operations we need to protect rli members with data_lock,
+ so we will hold it for the most of the loop below
+ However, we will release it whenever it is worth the hassle,
+ and in the cases when we go into a pthread_cond_wait() with the
+ non-data_lock mutex
+ */
+ pthread_mutex_lock(&rli->data_lock);
+
+ for (; !(was_killed=sql_slave_killed(thd,rli)) ;)
+ {
+ /*
+ We can have two kinds of log reading:
+ hot_log - rli->cur_log points at the IO_CACHE of relay_log, which
+ is actively being updated by the I/O thread. We need to be careful
+ in this case and make sure that we are not looking at a stale log that
+ has already been rotated. If it has been, we reopen the log
+ the other case is much simpler - we just have a read only log that
+ nobody else will be updating.
+ */
+ bool hot_log;
+ if ((hot_log = (cur_log != &rli->cache_buf)))
+ {
+ DBUG_ASSERT(rli->cur_log_fd == -1); // foreign descriptor
+ pthread_mutex_lock(log_lock);
+
+ /*
+ Reading cur_log->init_count here is safe because the log will only
+ be rotated when we hold relay_log.LOCK_log
+ */
+ if (cur_log->init_count != rli->cur_log_init_count)
+ {
+ if (!(cur_log=reopen_relay_log(rli,&errmsg)))
+ {
+ pthread_mutex_unlock(log_lock);
+ goto err;
+ }
+ pthread_mutex_unlock(log_lock);
+ hot_log=0;
+ }
+ }
+ DBUG_ASSERT(my_b_tell(cur_log) >= 4);
+ DBUG_ASSERT(my_b_tell(cur_log) == rli->relay_log_pos + rli->pending);
+ /* relay log is always in new format - if the master is 3.23, the
+ I/O thread will convert the format for us
+ */
+ if ((ev=Log_event::read_log_event(cur_log,0,(bool)0/*new format*/)))
+ {
+ DBUG_ASSERT(thd==rli->sql_thd);
+ if (hot_log)
+ pthread_mutex_unlock(log_lock);
+ pthread_mutex_unlock(&rli->data_lock);
+ return ev;
+ }
+ DBUG_ASSERT(thd==rli->sql_thd);
+ if (!cur_log->error) /* EOF */
+ {
+ /*
+ On a hot log, EOF means that there are no more updates to
+ process and we must block until I/O thread adds some and
+ signals us to continue
+ */
+ if (hot_log)
+ {
+ DBUG_ASSERT(cur_log->init_count == rli->cur_log_init_count);
+ /*
+ We can, and should release data_lock while we are waiting for
+ update. If we do not, show slave status will block
+ */
+ pthread_mutex_unlock(&rli->data_lock);
+
+ /*
+ IMPORTANT: note that wait_for_update will unlock LOCK_log, but
+ expects the caller to lock it
+ */
+ rli->relay_log.wait_for_update(rli->sql_thd);
+
+ // re-acquire data lock since we released it earlier
+ pthread_mutex_lock(&rli->data_lock);
+ continue;
+ }
+ else
+ {
+ /*
+ If the log was not hot, we need to move to the next log in
+ sequence. The next log could be hot or cold, we deal with both
+ cases separately after doing some common initialization
+ */
+ end_io_cache(cur_log);
+ DBUG_ASSERT(rli->cur_log_fd >= 0);
+ my_close(rli->cur_log_fd, MYF(MY_WME));
+ rli->cur_log_fd = -1;
+
+ // purge_first_log will properly set up relay log coordinates in rli
+ if (rli->relay_log.purge_first_log(rli))
+ {
+ errmsg = "Error purging processed log";
+ goto err;
+ }
+
+ // next log is hot
+ if (rli->relay_log.is_active(rli->linfo.log_file_name))
+ {
+#ifdef EXTRA_DEBUG
+ sql_print_error("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_init_count = cur_log->init_count;
+ DBUG_ASSERT(rli->cur_log_fd == -1);
+
+ /*
+ Read pointer has to be at the start since we are the only
+ reader
+ */
+ if (check_binlog_magic(cur_log,&errmsg))
+ goto err;
+ continue;
+ }
+ /*
+ if we get here, the log was not hot, so we will have to
+ open it ourselves
+ */
+#ifdef EXTRA_DEBUG
+ sql_print_error("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,
+ &errmsg)) <0)
+ goto err;
+ }
+ }
+ else // read failed with a non-EOF error
+ {
+ // TODO: come up with something better to handle this error
+ sql_print_error("Slave SQL thread: I/O error reading \
+event(errno=%d,cur_log->error=%d)",
+ my_errno,cur_log->error);
+ // set read position to the beginning of the event
+ my_b_seek(cur_log,rli->relay_log_pos+rli->pending);
+ // no need to hog the mutex while we sleep
+ pthread_mutex_unlock(&rli->data_lock);
+ safe_sleep(rli->sql_thd,1,(CHECK_KILLED_FUNC)sql_slave_killed,
+ (void*)rli);
+ pthread_mutex_lock(&rli->data_lock);
+ }
+ }
+ if (!errmsg && was_killed)
+ errmsg = "slave SQL thread was killed";
+err:
+ pthread_mutex_unlock(&rli->data_lock);
+ sql_print_error("Error reading relay log event: %s", errmsg);
+ return 0;
+}
+
+
#ifdef __GNUC__
template class I_List_iterator<i_string>;
template class I_List_iterator<i_string_pair>;
diff --git a/sql/slave.h b/sql/slave.h
index 2934e675d56..9d3f55cbfbf 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -1,65 +1,298 @@
#ifndef SLAVE_H
#define SLAVE_H
+#include "mysql.h"
+#include "my_list.h"
#define SLAVE_NET_TIMEOUT 3600
+#define MAX_SLAVE_ERRMSG 1024
#define MAX_SLAVE_ERROR 2000
+/*
+ The replication is accomplished by starting two threads - I/O
+ thread, and SQL thread. I/O thread is associated with its
+ MASTER_INFO struct, so MASTER_INFO can be viewed as I/O thread
+ descriptor. SQL thread is associated with RELAY_LOG_INFO struct.
+
+ I/O thread reads maintains a connection to the master, and reads log
+ events from the master as they arrive, queueing them by writing them
+ out into the temporary slave binary log (relay log). The SQL thread,
+ in turn, reads the slave binary log executing each event.
+
+ Relay log is needed to be able to handle situations when there is a large
+ backlog of unprocessed events from the master (eg. one particular update
+ takes a day to finish), and to be able to restart the slave server without
+ having to re-read the master updates.
+ */
+
extern ulong slave_net_timeout, master_retry_count;
extern MY_BITMAP slave_error_mask;
extern bool use_slave_mask;
+extern char* slave_load_tmpdir;
+extern my_string master_info_file,relay_log_info_file;
+extern my_string opt_relay_logname, opt_relaylog_index_name;
+extern bool opt_skip_slave_start;
+struct st_master_info;
+
+/*
+ TODO: this needs to be redone, but for now it does not matter since
+ we do not have multi-master yet.
+*/
+
+#define LOCK_ACTIVE_MI { pthread_mutex_lock(&LOCK_active_mi); \
+ ++active_mi_in_use; \
+ pthread_mutex_unlock(&LOCK_active_mi);}
+
+#define UNLOCK_ACTIVE_MI { pthread_mutex_lock(&LOCK_active_mi); \
+ --active_mi_in_use; \
+ pthread_mutex_unlock(&LOCK_active_mi); }
+
+/*
+ st_relay_log_info contains information on the current relay log and
+ relay log offset, and master log name and log sequence corresponding to the
+ last update. Additionally, misc information specific to the SQL thread is
+ included.
+
+ st_relay_log_info is initialized from the slave.info file if such exists.
+ Otherwise, data members are intialized with defaults. The initialization is
+ done with init_relay_log_info() call.
+
+ The format of slave.info file:
+
+ relay_log_name
+ relay_log_pos
+ master_log_name
+ master_log_pos
+
+ To clean up, call end_relay_log_info()
+ */
+
+typedef struct st_relay_log_info
+{
+ /*** The following variables can only be read when protect by data lock ****/
+ /*
+ info_fd - file descriptor of the info file. set only during
+ initialization or clean up - safe to read anytime
+ cur_log_fd - file descriptor of the current read relay log
+ */
+ File info_fd,cur_log_fd;
+ // name of current read relay log
+ char relay_log_name[FN_REFLEN];
+ // master log name corresponding to current read position
+ char master_log_name[FN_REFLEN];
+ // original log position of last processed event
+ volatile my_off_t master_log_pos;
+
+ /*
+ current offset in the relay log.
+ pending - in some cases we do not increment offset immediately after
+ processing an event, because the following event needs to be processed
+ atomically together with this one ( so far, there is only one type of
+ such event - Intvar_event that sets auto_increment value). However, once
+ both events have been processed, we need to increment by the cumulative
+ offset. pending stored the extra offset to be added to the position.
+ */
+ ulonglong relay_log_pos, pending;
+
+ // protected with internal locks
+ // must get data_lock when resetting the logs
+ MYSQL_LOG relay_log;
+ LOG_INFO linfo;
+ IO_CACHE cache_buf,*cur_log;
+
+ /*** The following variables are safe to read any time ***/
+
+ // IO_CACHE of the info file - set only during init or end
+ IO_CACHE info_file;
+
+ /*
+ When we restart slave thread we need to have access to the previously
+ created temporary tables. Modified only on init/end and by the SQL
+ thread, read only by SQL thread.
+ */
+ TABLE* save_temporary_tables;
+
+ /*
+ standard lock acquistion order to avoid deadlocks:
+ run_lock, data_lock, relay_log.LOCK_log, relay_log.LOCK_index
+ */
+ pthread_mutex_t data_lock,run_lock;
+
+ /*
+ start_cond is broadcast when SQL thread is started
+ stop_cond - when stopped
+ data_cond - when data protected by data_lock changes
+ */
+ pthread_cond_t start_cond, stop_cond, data_cond;
+ // if not set, the value of other members of the structure are undefined
+ bool inited;
+
+ // parent master info structure
+ struct st_master_info *mi;
+
+ /*
+ Needed to deal properly with cur_log getting closed and re-opened with
+ a different log under our feet
+ */
+ int cur_log_init_count;
+
+ volatile bool abort_slave, slave_running;
+
+ /*
+ Needed for problems when slave stops and we want to restart it
+ skipping one or more events in the master log that have caused
+ errors, and have been manually applied by DBA already.
+ */
+ volatile uint32 slave_skip_counter;
+#ifndef DBUG_OFF
+ int events_till_abort;
+#endif
+ int last_slave_errno;
+ char last_slave_error[MAX_SLAVE_ERRMSG];
+ THD* sql_thd;
+ bool log_pos_current;
+
+ st_relay_log_info():info_fd(-1),cur_log_fd(-1),inited(0),
+ cur_log_init_count(0),
+ log_pos_current(0)
+ {
+ relay_log_name[0] = master_log_name[0] = 0;
+ bzero(&info_file,sizeof(info_file));
+ pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST);
+ pthread_cond_init(&data_cond, NULL);
+ pthread_cond_init(&start_cond, NULL);
+ pthread_cond_init(&stop_cond, NULL);
+ }
+ ~st_relay_log_info()
+ {
+ pthread_mutex_destroy(&run_lock);
+ pthread_mutex_destroy(&data_lock);
+ pthread_cond_destroy(&data_cond);
+ pthread_cond_destroy(&start_cond);
+ pthread_cond_destroy(&stop_cond);
+ }
+ inline void inc_pending(ulonglong val)
+ {
+ pending += val;
+ }
+ // TODO: this probably needs to be fixed
+ inline void inc_pos(ulonglong val, ulonglong log_pos, bool skip_lock=0)
+ {
+ if (!skip_lock)
+ pthread_mutex_lock(&data_lock);
+ relay_log_pos += val+pending;
+ pending = 0;
+ if (log_pos)
+ master_log_pos = log_pos+ val;
+ pthread_cond_broadcast(&data_cond);
+ if (!skip_lock)
+ pthread_mutex_unlock(&data_lock);
+ }
+ /*
+ thread safe read of position - not needed if we are in the slave thread,
+ but required otherwise
+ */
+ inline void read_pos(ulonglong& var)
+ {
+ pthread_mutex_lock(&data_lock);
+ var = relay_log_pos;
+ pthread_mutex_unlock(&data_lock);
+ }
+
+ int wait_for_pos(THD* thd, String* log_name, ulonglong log_pos);
+} RELAY_LOG_INFO;
+
+/*
+ repopen_relay_log() is called when we notice that the current "hot" log
+ got rotated under our feet
+*/
+
+IO_CACHE* reopen_relay_log(RELAY_LOG_INFO* rli, const char** errmsg);
+Log_event* next_event(RELAY_LOG_INFO* rli);
+
+
+/*
+ st_master_info contains information about how to connect to a master,
+ current master log name, and current log offset, as well as misc
+ control variables
+
+ st_master_info is initialized once from the master.info file if such
+ exists. Otherwise, data members corresponding to master.info fields are
+ initialized with defaults specified by master-* options. The initialization
+ is done through init_master_info() call.
+
+ The format of master.info file:
+
+ log_name
+ log_pos
+ master_host
+ master_user
+ master_pass
+ master_port
+ master_connect_retry
+
+ To write out the contents of master.info file to disk ( needed every
+ time we read and queue data from the master ), a call to
+ flush_master_info() is required.
+
+ To clean up, call end_master_info()
+*/
+
+
typedef struct st_master_info
{
- char log_file_name[FN_REFLEN];
- ulonglong pos,pending;
- File fd; // we keep the file open, so we need to remember the file pointer
+ char master_log_name[FN_REFLEN];
+
+ my_off_t master_log_pos;
+ File fd;
IO_CACHE file;
+
// the variables below are needed because we can change masters on the fly
char host[HOSTNAME_LENGTH+1];
char user[USERNAME_LENGTH+1];
char password[HASH_PASSWORD_LENGTH+1];
+ pthread_mutex_t data_lock,run_lock;
+ pthread_cond_t data_cond,start_cond,stop_cond;
+ THD *io_thd;
+ MYSQL* mysql;
+ uint32 file_id; // for 3.23 load data infile
+ RELAY_LOG_INFO rli;
uint port;
uint connect_retry;
- pthread_mutex_t lock;
- pthread_cond_t cond;
+#ifndef DBUG_OFF
+ int events_till_abort;
+#endif
bool inited;
+ bool old_format; // master binlog is in 3.23 format
+ volatile bool abort_slave, slave_running;
+ bool ignore_stop_event;
+
- st_master_info():pending(0),fd(-1),inited(0)
+ st_master_info():fd(-1), io_thd(0), inited(0), old_format(0)
{
host[0] = 0; user[0] = 0; password[0] = 0;
- pthread_mutex_init(&lock, MY_MUTEX_INIT_FAST);
- pthread_cond_init(&cond, NULL);
+ bzero(&file,sizeof(file));
+ pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST);
+ pthread_cond_init(&data_cond, NULL);
+ pthread_cond_init(&start_cond, NULL);
+ pthread_cond_init(&stop_cond, NULL);
}
~st_master_info()
{
- pthread_mutex_destroy(&lock);
- pthread_cond_destroy(&cond);
- }
- inline void inc_pending(ulonglong val)
- {
- pending += val;
- }
- inline void inc_pos(ulonglong val)
- {
- pthread_mutex_lock(&lock);
- pos += val + pending;
- pending = 0;
- pthread_cond_broadcast(&cond);
- pthread_mutex_unlock(&lock);
- }
- // thread safe read of position - not needed if we are in the slave thread,
- // but required otherwise
- inline void read_pos(ulonglong& var)
- {
- pthread_mutex_lock(&lock);
- var = pos;
- pthread_mutex_unlock(&lock);
+ pthread_mutex_destroy(&run_lock);
+ pthread_mutex_destroy(&data_lock);
+ pthread_cond_destroy(&data_cond);
+ pthread_cond_destroy(&start_cond);
+ pthread_cond_destroy(&stop_cond);
}
- int wait_for_pos(THD* thd, String* log_name, ulonglong log_pos);
} MASTER_INFO;
+int queue_event(MASTER_INFO* mi,const char* buf,ulong event_len);
+
typedef struct st_table_rule_ent
{
char* db;
@@ -69,45 +302,100 @@ typedef struct st_table_rule_ent
#define TABLE_RULE_HASH_SIZE 16
#define TABLE_RULE_ARR_SIZE 16
+#define MAX_SLAVE_ERRMSG 1024
+
+#define RPL_LOG_NAME (rli->master_log_name[0] ? rli->master_log_name :\
+ "FIRST")
+#define IO_RPL_LOG_NAME (mi->master_log_name[0] ? mi->master_log_name :\
+ "FIRST")
+
+/* masks for start/stop operations on io and sql slave threads */
+#define SLAVE_IO 1
+#define SLAVE_SQL 2
+/*
+ If the following is set, if first gives an error, second will be
+ tried. Otherwise, if first fails, we fail.
+*/
+#define SLAVE_FORCE_ALL 4
+
+int init_slave();
+void init_slave_skip_errors(char* arg);
int flush_master_info(MASTER_INFO* mi);
+int flush_relay_log_info(RELAY_LOG_INFO* rli);
+int register_slave_on_master(MYSQL* mysql);
+int terminate_slave_threads(MASTER_INFO* mi, int thread_mask,
+ bool skip_lock = 0);
+int terminate_slave_thread(THD* thd, pthread_mutex_t* term_mutex,
+ pthread_mutex_t* cond_lock,
+ pthread_cond_t* term_cond,
+ volatile bool* slave_running);
+int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
+ MASTER_INFO* mi, const char* master_info_fname,
+ const char* slave_info_fname, int thread_mask);
+/*
+ cond_lock is usually same as start_lock. It is needed for the case when
+ start_lock is 0 which happens if start_slave_thread() is called already
+ inside the start_lock section, but at the same time we want a
+ pthread_cond_wait() on start_cond,start_lock
+*/
+int start_slave_thread(pthread_handler h_func, pthread_mutex_t* start_lock,
+ pthread_mutex_t *cond_lock,
+ pthread_cond_t* start_cond,
+ volatile bool* slave_running,
+ MASTER_INFO* mi);
+
+// If fd is -1, dump to NET
+int mysql_table_dump(THD* thd, const char* db,
+ const char* tbl_name, int fd = -1);
-int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd = -1);
-// if fd is -1, dump to NET
-int fetch_nx_table(THD* thd, MASTER_INFO* mi);
// retrieve non-exitent table from master
-// the caller must set thd->last_nx_table and thd->last_nx_db first
-int show_master_info(THD* thd);
+int fetch_master_table(THD* thd, const char* db_name, const char* table_name,
+ MASTER_INFO* mi, MYSQL* mysql);
+
+int show_master_info(THD* thd, MASTER_INFO* mi);
int show_binlog_info(THD* thd);
+// See if the query uses any tables that should not be replicated
int tables_ok(THD* thd, TABLE_LIST* tables);
-// see if the query uses any tables that should not be replicated
+/*
+ Check to see if the database is ok to operate on with respect to the
+ do and ignore lists - used in replication
+*/
int db_ok(const char* db, I_List<i_string> &do_list,
I_List<i_string> &ignore_list );
-// check to see if the database is ok to operate on with respect to the
-// do and ignore lists - used in replication
int add_table_rule(HASH* h, const char* table_spec);
int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec);
void init_table_rule_hash(HASH* h, bool* h_inited);
void init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited);
-void init_slave_skip_errors(char* arg);
+char* rewrite_db(char* db);
+int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int error_code);
+void skip_load_data_infile(NET* net);
+void slave_print_error(RELAY_LOG_INFO* rli,int err_code, const char* msg, ...);
void end_slave(); // clean up
-int init_master_info(MASTER_INFO* mi);
+int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
+ const char* slave_info_fname);
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);
+
+int purge_relay_logs(RELAY_LOG_INFO* rli,bool just_reset,const char** errmsg);
+
extern bool opt_log_slave_updates ;
-pthread_handler_decl(handle_slave,arg);
-extern bool volatile abort_loop, abort_slave, slave_running;
-extern uint32 slave_skip_counter;
-// needed for problems when slave stops and
-// we want to restart it skipping one or more events in the master log that
-// have caused errors, and have been manually applied by DBA already
-
-extern pthread_t slave_real_id;
-extern THD* slave_thd;
-extern MASTER_INFO glob_mi;
+pthread_handler_decl(handle_slave_io,arg);
+pthread_handler_decl(handle_slave_sql,arg);
+extern bool volatile abort_loop;
+extern MASTER_INFO main_mi, *active_mi; // active_mi for multi-master
+extern volatile int active_mi_in_use;
+extern LIST master_list;
extern HASH replicate_do_table, replicate_ignore_table;
extern DYNAMIC_ARRAY replicate_wild_do_table, replicate_wild_ignore_table;
extern bool do_table_inited, ignore_table_inited,
@@ -119,14 +407,13 @@ extern int disconnect_slave_event_count, abort_slave_event_count ;
#endif
// the master variables are defaults read from my.cnf or command line
-extern uint master_port, master_connect_retry;
+extern uint master_port, master_connect_retry, report_port;
extern my_string master_user, master_password, master_host,
- master_info_file;
+ master_info_file, relay_log_info_file, report_user, report_host,
+ report_password;
extern I_List<i_string> replicate_do_db, replicate_ignore_db;
extern I_List<i_string_pair> replicate_rewrite_db;
extern I_List<THD> threads;
#endif
-
-
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 33924ada8ab..104b431bdbb 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -1,15 +1,15 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
+/* 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 */
@@ -58,9 +58,13 @@ class ACL_USER :public ACL_ACCESS
{
public:
acl_host_and_ip host;
- uint hostname_length;
+ uint hostname_length, questions, updates;
char *user,*password;
ulong salt[2];
+#ifdef HAVE_OPENSSL
+ enum SSL_type ssl_type;
+ const char *ssl_cipher, *x509_issuer, *x509_subject;
+#endif /* HAVE_OPENSSL */
};
class ACL_DB :public ACL_ACCESS
@@ -106,7 +110,7 @@ static void update_hostname(acl_host_and_ip *host, const char *hostname);
static bool compare_hostname(const acl_host_and_ip *host, const char *hostname,
const char *ip);
-int acl_init(bool dont_read_acl_tables)
+int acl_init(bool dont_read_acl_tables)
{
THD *thd;
TABLE_LIST tables[3];
@@ -128,7 +132,8 @@ int acl_init(bool dont_read_acl_tables)
thd->mysys_var=my_thread_var;
thd->current_tablenr=0;
thd->open_tables=0;
- thd->db=my_strdup("mysql",MYF(0));
+ thd->db= my_strdup("mysql",MYF(0));
+ thd->db_length=5; // Safety
bzero((char*) &tables,sizeof(tables));
tables[0].name=tables[0].real_name=(char*) "host";
tables[1].name=tables[1].real_name=(char*) "user";
@@ -199,6 +204,26 @@ int acl_init(bool dont_read_acl_tables)
update_hostname(&user.host,get_field(&mem, table,0));
user.user=get_field(&mem, table,1);
user.password=get_field(&mem, table,2);
+#ifdef HAVE_OPENSSL
+ DBUG_PRINT("info",("table->fields=%d",table->fields));
+ if (table->fields >= 21) /* From 4.0.0 we have more fields */
+ {
+ char *ssl_type=get_field(&mem, table,17);
+ if (!strcmp(ssl_type, "ANY"))
+ user.ssl_type=SSL_TYPE_ANY;
+ else if (!strcmp(ssl_type, "X509"))
+ user.ssl_type=SSL_TYPE_X509;
+ else if (!strcmp(ssl_type, "SPECIFIED"))
+ user.ssl_type=SSL_TYPE_SPECIFIED;
+ else
+ user.ssl_type=SSL_TYPE_NONE;
+ user.ssl_cipher=get_field(&mem, table, 18);
+ user.x509_issuer=get_field(&mem, table, 19);
+ user.x509_subject=get_field(&mem, table, 20);
+ }
+ else
+ user.ssl_type=SSL_TYPE_NONE;
+#endif /* HAVE_OPENSSL */
if (user.password && (length=(uint) strlen(user.password)) == 8 &&
protocol_version == PROTOCOL_VERSION)
{
@@ -218,6 +243,18 @@ int acl_init(bool dont_read_acl_tables)
user.access=get_access(table,3);
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 >=23)
+ {
+ /* Table has new MySQL usage limits */
+ char *ptr = get_field(&mem, table, 21);
+ user.questions=atoi(ptr);
+ ptr = get_field(&mem, table, 22);
+ user.updates=atoi(ptr);
+ if (user.questions)
+ mqh_used=1;
+ }
+ else
+ user.questions=user.updates=0;
#ifndef TO_BE_REMOVED
if (table->fields <= 13)
{ // Without grant
@@ -398,16 +435,20 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
}
-/* Get master privilges for user (priviliges for all tables) */
-
+/*
+ Get master privilges for user (priviliges for all tables).
+ Required before connecting to MySQL
+*/
-uint acl_getroot(const char *host, const char *ip, const char *user,
+uint acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
const char *password,const char *message,char **priv_user,
- bool old_ver)
+ bool old_ver, uint *max_questions)
{
uint user_access=NO_ACCESS;
*priv_user=(char*) user;
+ char *ptr=0;
+ *max_questions=0;
if (!initialized)
return (uint) ~NO_ACCESS; // If no data allow anything /* purecov: tested */
VOID(pthread_mutex_lock(&acl_cache->lock));
@@ -428,7 +469,94 @@ uint acl_getroot(const char *host, const char *ip, const char *user,
!check_scramble(password,message,acl_user->salt,
(my_bool) old_ver)))
{
+#ifdef HAVE_OPENSSL
+ Vio *vio=thd->net.vio;
+ /*
+ In this point we know that user is allowed to connect
+ from given host by given username/password pair. Now
+ we check if SSL is required, if user is using SSL and
+ if X509 certificate attributes are OK
+ */
+ switch(acl_user->ssl_type) {
+ case SSL_TYPE_NONE: /* SSL is not required to connect */
+ user_access=acl_user->access;
+ break;
+ case SSL_TYPE_ANY: /* Any kind of SSL is good enough */
+ if (vio_type(vio) == VIO_TYPE_SSL)
+ user_access=acl_user->access;
+ break;
+ case SSL_TYPE_X509: /* Client should have any valid certificate. */
+ /*
+ Connections with non-valid certificates are dropped already
+ in sslaccept() anyway, so we do not check validity here.
+ */
+ if (SSL_get_peer_certificate(vio->ssl_))
+ user_access=acl_user->access;
+ break;
+ case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */
+ /*
+ We do not check for absence of SSL because without SSL it does
+ not pass all checks here anyway.
+ If cipher name is specified, we compare it to actual cipher in
+ use.
+ */
+ if (acl_user->ssl_cipher)
+ DBUG_PRINT("info",("comparing ciphers: '%s' and '%s'",
+ acl_user->ssl_cipher,
+ SSL_get_cipher(vio->ssl_)));
+ if (!strcmp(acl_user->ssl_cipher,SSL_get_cipher(vio->ssl_)))
+ user_access=acl_user->access;
+ else
+ {
+ user_access=NO_ACCESS;
+ break;
+ }
+ /* Prepare certificate (if exists) */
+ DBUG_PRINT("info",("checkpoint 1"));
+ X509* cert=SSL_get_peer_certificate(vio->ssl_);
+ DBUG_PRINT("info",("checkpoint 2"));
+ /* If X509 issuer is speified, we check it... */
+ if (acl_user->x509_issuer)
+ {
+ DBUG_PRINT("info",("checkpoint 3"));
+ ptr = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
+ DBUG_PRINT("info",("comparing issuers: '%s' and '%s'",
+ acl_user->x509_issuer, ptr));
+ if (!strcmp(acl_user->x509_issuer,ptr))
+ user_access=acl_user->access;
+ else
+ {
+ user_access=NO_ACCESS;
+ free(ptr);
+ break;
+ }
+ free(ptr);
+ }
+ DBUG_PRINT("info",("checkpoint 4"));
+ /* X509 subject is specified, we check it .. */
+ if (acl_user->x509_subject)
+ {
+ ptr = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
+ DBUG_PRINT("info",("comparing subjects: '%s' and '%s'",
+ acl_user->x509_subject, ptr));
+ if (!strcmp(acl_user->x509_subject,ptr))
+ user_access=acl_user->access;
+ else
+ {
+ user_access=NO_ACCESS;
+ free(ptr);
+ break;
+ }
+ free(ptr);
+ }
+ DBUG_PRINT("info",("checkpoint 5"));
+ break;
+ }
+ DBUG_PRINT("info",("checkpoint 6"));
+#else /* HAVE_OPENSSL */
user_access=acl_user->access;
+#endif /* HAVE_OPENSSL */
+ *max_questions=acl_user->questions;
if (!acl_user->user)
*priv_user=(char*) ""; // Change to anonymous user /* purecov: inspected */
break;
@@ -457,7 +585,13 @@ static byte* check_get_key(ACL_USER *buff,uint *length,
}
static void acl_update_user(const char *user, const char *host,
- const char *password, uint privileges)
+ const char *password,
+ enum SSL_type ssl_type,
+ const char *ssl_cipher,
+ const char *x509_issuer,
+ const char *x509_subject,
+ unsigned int mqh,
+ uint privileges)
{
for (uint i=0 ; i < acl_users.elements ; i++)
{
@@ -470,6 +604,13 @@ static void acl_update_user(const char *user, const char *host,
acl_user->host.hostname && !strcmp(host,acl_user->host.hostname))
{
acl_user->access=privileges;
+ acl_user->questions=mqh;
+#ifdef HAVE_OPENSSL
+ acl_user->ssl_type=ssl_type;
+ acl_user->ssl_cipher=ssl_cipher;
+ acl_user->x509_issuer=x509_issuer;
+ acl_user->x509_subject=x509_subject;
+#endif /* HAVE_OPENSSL */
if (password)
{
if (!password[0])
@@ -488,7 +629,12 @@ static void acl_update_user(const char *user, const char *host,
static void acl_insert_user(const char *user, const char *host,
- const char *password,
+ const char *password,
+ enum SSL_type ssl_type,
+ const char *ssl_cipher,
+ const char *x509_issuer,
+ const char *x509_subject,
+ unsigned int mqh,
uint privileges)
{
ACL_USER acl_user;
@@ -496,8 +642,15 @@ static void acl_insert_user(const char *user, const char *host,
update_hostname(&acl_user.host,strdup_root(&mem,host));
acl_user.password=0;
acl_user.access=privileges;
+ acl_user.questions=mqh;
acl_user.sort=get_sort(2,acl_user.host.hostname,acl_user.user);
acl_user.hostname_length=(uint) strlen(acl_user.host.hostname);
+#ifdef HAVE_OPENSSL
+ acl_user.ssl_type=ssl_type;
+ acl_user.ssl_cipher=ssl_cipher;
+ acl_user.x509_issuer=x509_issuer;
+ acl_user.x509_subject=x509_subject;
+#endif /* HAVE_OPENSSL */
if (password)
{
acl_user.password=(char*) ""; // Just point at something
@@ -570,12 +723,17 @@ uint acl_get(const char *host, const char *ip, const char *bin_ip,
{
uint host_access,db_access,i,key_length;
db_access=0; host_access= ~0;
- char key[ACL_KEY_LENGTH],*end;
+ char key[ACL_KEY_LENGTH],*tmp_db,*end;
acl_entry *entry;
VOID(pthread_mutex_lock(&acl_cache->lock));
memcpy_fixed(&key,bin_ip,sizeof(struct in_addr));
- end=strmov(strmov(key+sizeof(struct in_addr),user)+1,db);
+ end=strmov((tmp_db=strmov(key+sizeof(struct in_addr),user)+1),db);
+ if (lower_case_table_names)
+ {
+ casedn_str(tmp_db);
+ db=tmp_db;
+ }
key_length=(uint) (end-key);
if ((entry=(acl_entry*) acl_cache->search(key,key_length)))
{
@@ -641,7 +799,7 @@ int wild_case_compare(const char *str,const char *wildstr)
{
reg3 int flag;
DBUG_ENTER("wild_case_compare");
-
+ DBUG_PRINT("enter",("str='%s', wildstr='%s'",str,wildstr));
while (*wildstr)
{
while (*wildstr && *wildstr != wild_many && *wildstr != wild_one)
@@ -653,7 +811,7 @@ int wild_case_compare(const char *str,const char *wildstr)
if (! *wildstr ) DBUG_RETURN (*str != 0);
if (*wildstr++ == wild_one)
{
- if (! *str++) DBUG_RETURN (1); /* One char; skipp */
+ if (! *str++) DBUG_RETURN (1); /* One char; skip */
}
else
{ /* Found '*' */
@@ -765,10 +923,13 @@ bool change_password(THD *thd, const char *host, const char *user,
char *new_password)
{
uint length=0;
+ DBUG_ENTER("change_password");
+ DBUG_PRINT("enter",("thd=%x, host='%s', user='%s', new_password='%s'",thd,host,user,new_password));
+
if (!initialized)
{
send_error(&thd->net, ER_PASSWORD_NOT_ALLOWED); /* purecov: inspected */
- return 1; /* purecov: inspected */
+ DBUG_RETURN(1); /* purecov: inspected */
}
if (!host)
host=thd->ip; /* purecov: tested */
@@ -781,12 +942,12 @@ bool change_password(THD *thd, const char *host, const char *user,
my_strcasecmp(host,thd->host ? thd->host : thd->ip)))
{
if (check_access(thd, UPDATE_ACL, "mysql",0,1))
- return 1;
+ DBUG_RETURN(1);
}
if (!thd->slave_thread && !thd->user[0])
{
send_error(&thd->net, ER_PASSWORD_ANONYMOUS_USER);
- return 1;
+ DBUG_RETURN(1);
}
VOID(pthread_mutex_lock(&acl_cache->lock));
ACL_USER *acl_user;
@@ -794,7 +955,7 @@ bool change_password(THD *thd, const char *host, const char *user,
{
send_error(&thd->net, ER_PASSWORD_NO_MATCH);
VOID(pthread_mutex_unlock(&acl_cache->lock));
- return 1;
+ DBUG_RETURN(1);
}
if (update_user_table(thd,
acl_user->host.hostname ? acl_user->host.hostname : "",
@@ -803,7 +964,7 @@ bool change_password(THD *thd, const char *host, const char *user,
{
VOID(pthread_mutex_unlock(&acl_cache->lock)); /* purecov: deadcode */
send_error(&thd->net,0); /* purecov: deadcode */
- return 1; /* purecov: deadcode */
+ DBUG_RETURN(1); /* purecov: deadcode */
}
get_salt_from_password(acl_user->salt,new_password);
if (!new_password[0])
@@ -814,7 +975,7 @@ bool change_password(THD *thd, const char *host, const char *user,
VOID(pthread_mutex_unlock(&acl_cache->lock));
char buff[460];
-
+
Query_log_event qinfo(thd, buff);
qinfo.q_len =
my_sprintf(buff,
@@ -824,7 +985,7 @@ bool change_password(THD *thd, const char *host, const char *user,
new_password));
mysql_update_log.write(thd,buff,qinfo.q_len);
mysql_bin_log.write(&qinfo);
- return 0;
+ DBUG_RETURN(0);
}
@@ -835,17 +996,23 @@ bool change_password(THD *thd, const char *host, const char *user,
static ACL_USER *
find_acl_user(const char *host, const char *user)
{
+ DBUG_ENTER("find_acl_user");
+ DBUG_PRINT("enter",("host='%s', user='%s'",host,user));
for (uint i=0 ; i < acl_users.elements ; i++)
{
ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
+ DBUG_PRINT("info",("strcmp('%s','%s'), compare_hostname('%s','%s'),",
+ user,acl_user->user,(host),(acl_user->host)));
if (!acl_user->user && !user[0] ||
acl_user->user && !strcmp(user,acl_user->user))
{
- if (compare_hostname(&acl_user->host,host,host))
- return acl_user;
+ if (compare_hostname(&(acl_user->host),host,host))
+ {
+ DBUG_RETURN(acl_user);
+ }
}
}
- return 0;
+ DBUG_RETURN(0);
}
/*****************************************************************************
@@ -974,7 +1141,7 @@ static bool test_if_create_new_users(THD *thd)
** Handle GRANT commands
****************************************************************************/
-static int replace_user_table(TABLE *table, const LEX_USER &combo,
+static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
uint rights, char what, bool create_user)
{
int error = -1;
@@ -1008,7 +1175,7 @@ static int replace_user_table(TABLE *table, const LEX_USER &combo,
my_printf_error(ER_NO_PERMISSION_TO_CREATE_USER,
ER(ER_NO_PERMISSION_TO_CREATE_USER),
MYF(0),thd->user,
- thd->host ? thd->host : thd->ip ? thd->ip: "");
+ thd->host_or_ip);
error= -1;
goto end;
}
@@ -1034,7 +1201,43 @@ static int replace_user_table(TABLE *table, const LEX_USER &combo,
table->field[i]->store(&what,1);
}
rights=get_access(table,3);
-
+#ifdef HAVE_OPENSSL
+ /* We write down SSL related ACL stuff */
+ DBUG_PRINT("info",("table->fields=%d",table->fields));
+ if (table->fields >= 21) /* From 4.0.0 we have more fields */
+ {
+ table->field[18]->store("",0);
+ table->field[19]->store("",0);
+ table->field[20]->store("",0);
+ switch (thd->lex.ssl_type) {
+ case SSL_TYPE_ANY:
+ table->field[17]->store("ANY",3);
+ break;
+ case SSL_TYPE_X509:
+ table->field[17]->store("X509",4);
+ break;
+ case SSL_TYPE_SPECIFIED:
+ table->field[17]->store("SPECIFIED",9);
+ if (thd->lex.ssl_cipher)
+ table->field[18]->store(thd->lex.ssl_cipher,
+ strlen(thd->lex.ssl_cipher));
+ if (thd->lex.x509_issuer)
+ table->field[19]->store(thd->lex.x509_issuer,
+ strlen(thd->lex.x509_issuer));
+ if (thd->lex.x509_subject)
+ table->field[20]->store(thd->lex.x509_subject,
+ strlen(thd->lex.x509_subject));
+ break;
+ default:
+ table->field[17]->store("NONE",4);
+ }
+ }
+#endif /* HAVE_OPENSSL */
+ if (table->fields >= 23 && thd->lex.mqh)
+ {
+ table->field[21]->store((longlong) thd->lex.mqh);
+ mqh_used=1;
+ }
if (old_row_exists)
{
/*
@@ -1061,16 +1264,28 @@ static int replace_user_table(TABLE *table, const LEX_USER &combo,
}
error=0; // Privileges granted / revoked
- end:
+end:
if (!error)
{
acl_cache->clear(1); // Clear privilege cache
if (!combo.password.str)
password=0; // No password given on command
if (old_row_exists)
- acl_update_user(combo.user.str,combo.host.str,password,rights);
+ acl_update_user(combo.user.str,combo.host.str,password,
+ thd->lex.ssl_type,
+ thd->lex.ssl_cipher,
+ thd->lex.x509_issuer,
+ thd->lex.x509_subject,
+ thd->lex.mqh,
+ rights);
else
- acl_insert_user(combo.user.str,combo.host.str,password,rights);
+ acl_insert_user(combo.user.str,combo.host.str,password,
+ thd->lex.ssl_type,
+ thd->lex.ssl_cipher,
+ thd->lex.x509_issuer,
+ thd->lex.x509_subject,
+ thd->lex.mqh,
+ rights);
}
table->file->index_end();
DBUG_RETURN(error);
@@ -1201,6 +1416,11 @@ public:
db = strdup_root(&memex,d);
user = strdup_root(&memex,u);
tname= strdup_root(&memex,t);
+ if (lower_case_table_names)
+ {
+ casedn_str(db);
+ casedn_str(tname);
+ }
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);
@@ -1222,7 +1442,13 @@ public:
privs = cols = 0; /* purecov: inspected */
return; /* purecov: inspected */
}
- key_length = (uint) strlen(db) + (uint) strlen(user) + (uint) strlen (tname) + 3;
+ if (lower_case_table_names)
+ {
+ casedn_str(db);
+ casedn_str(tname);
+ }
+ key_length = ((uint) strlen(db) + (uint) strlen(user) +
+ (uint) strlen(tname) + 3);
hash_key = (char*) alloc_root(&memex,key_length);
strmov(strmov(strmov(hash_key,user)+1,db)+1,tname);
privs = (uint) form->field[6]->val_int();
@@ -1505,8 +1731,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
uint store_table_rights,store_col_rights;
DBUG_ENTER("replace_table_table");
- strxmov(grantor,thd->user,"@",thd->host ? thd->host : thd->ip ? thd->ip :"",
- NullS);
+ strxmov(grantor, thd->user, "@", thd->host_or_ip, NullS);
// The following should always succeed as new users are created before
// this function is called!
@@ -1617,6 +1842,9 @@ int mysql_table_grant (THD *thd, TABLE_LIST *table_list,
TABLE_LIST tables[3];
bool create_new_users=0;
DBUG_ENTER("mysql_table_grant");
+ DBUG_PRINT("info",("ssl_cipher=%s",thd->lex.ssl_cipher));
+ DBUG_PRINT("info",("x509_issuer=%s",thd->lex.x509_issuer));
+ DBUG_PRINT("info",("x509_subject=%s",thd->lex.x509_subject));
if (!initialized)
{
@@ -1706,9 +1934,10 @@ int mysql_table_grant (THD *thd, TABLE_LIST *table_list,
continue;
}
/* Create user if needed */
- if (replace_user_table(tables[0].table,
- *Str,
- 0,
+ if (replace_user_table(thd,
+ tables[0].table,
+ *Str,
+ 0,
revoke_grant ? 'N' : 'Y',
create_new_users))
{
@@ -1801,7 +2030,7 @@ int mysql_table_grant (THD *thd, TABLE_LIST *table_list,
pthread_mutex_unlock(&LOCK_grant);
if (!result)
send_ok(&thd->net);
- /* Tables are automaticly closed */
+ /* Tables are automatically closed */
DBUG_RETURN(result);
}
@@ -1811,7 +2040,7 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, uint rights,
{
List_iterator <LEX_USER> str_list (list);
LEX_USER *Str;
- char what;
+ char what,tmp_db[NAME_LEN+1];
bool create_new_users=0;
TABLE_LIST tables[2];
DBUG_ENTER("mysql_grant");
@@ -1823,6 +2052,12 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, uint rights,
}
what = (revoke_grant) ? 'N' : 'Y';
+ if (lower_case_table_names && db)
+ {
+ strmov(tmp_db,db);
+ casedn_str(tmp_db);
+ db=tmp_db;
+ }
/* open the mysql.user and mysql.db tables */
@@ -1862,7 +2097,8 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, uint rights,
result= -1;
continue;
}
- if ((replace_user_table(tables[0].table,
+ if ((replace_user_table(thd,
+ tables[0].table,
*Str,
(!db ? rights : 0), what, create_new_users)))
result= -1;
@@ -1918,7 +2154,8 @@ int grant_init (void)
thd->mysys_var=my_thread_var;
thd->current_tablenr=0;
thd->open_tables=0;
- thd->db=my_strdup("mysql",MYF(0));
+ thd->db= my_strdup("mysql",MYF(0));
+ thd->db_length=5; // Safety
bzero((char*) &tables,sizeof(tables));
tables[0].name=tables[0].real_name= (char*) "tables_priv";
tables[1].name=tables[1].real_name= (char*) "columns_priv";
@@ -1954,7 +2191,7 @@ int grant_init (void)
delete thd;
DBUG_RETURN(0); // Empty table is ok!
}
- grant_option = TRUE;
+ grant_option= TRUE;
t_table->file->index_end();
MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
@@ -2040,8 +2277,8 @@ bool check_grant(THD *thd, uint want_access, TABLE_LIST *tables,
table->grant.want_privilege=0;
continue; // Already checked
}
- const char *db = table->db ? table->db : thd->db;
- GRANT_TABLE *grant_table = table_hash_search(thd->host,thd->ip,db,user,
+ GRANT_TABLE *grant_table = table_hash_search(thd->host,thd->ip,
+ table->db,user,
table->real_name,0);
if (!grant_table)
{
@@ -2095,7 +2332,7 @@ bool check_grant(THD *thd, uint want_access, TABLE_LIST *tables,
net_printf(&thd->net,ER_TABLEACCESS_DENIED_ERROR,
command,
thd->priv_user,
- thd->host ? thd->host : (thd->ip ? thd->ip : "unknown"),
+ thd->host_or_ip,
table ? table->real_name : "unknown");
}
return 1;
@@ -2158,7 +2395,7 @@ bool check_grant_column (THD *thd,TABLE *table, const char *name,
MYF(0),
command,
thd->priv_user,
- thd->host ? thd->host : (thd->ip ? thd->ip : "unknown"),
+ thd->host_or_ip,
name,
table ? table->real_name : "unknown");
}
@@ -2216,7 +2453,7 @@ bool check_grant_all_columns(THD *thd,uint want_access, TABLE *table)
MYF(0),
command,
thd->priv_user,
- thd->host ? thd->host : (thd->ip ? thd->ip : "unknown"),
+ thd->host_or_ip,
field ? field->field_name : "unknown",
table->real_name);
return 1;
@@ -2323,9 +2560,10 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
{
uint counter, want_access,index;
int error = 0;
+ int ssl_options = 0;
ACL_USER *acl_user; ACL_DB *acl_db;
char buff[1024];
- DBUG_ENTER("mysql_grant");
+ DBUG_ENTER("mysql_show_grants");
LINT_INIT(acl_user);
if (!initialized)
@@ -2416,8 +2654,50 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
global.append(passd_buff);
global.append('\'');
}
+#ifdef HAVE_OPENSSL
+ /* "show grants" SSL related stuff */
+ if (acl_user->ssl_type == SSL_TYPE_ANY)
+ global.append(" REQUIRE SSL",12);
+ else if (acl_user->ssl_type==SSL_TYPE_X509)
+ global.append(" REQUIRE X509",13);
+ else if (acl_user->ssl_type==SSL_TYPE_SPECIFIED)
+ {
+ global.append(" REQUIRE ",9);
+ if (acl_user->x509_issuer)
+ {
+ if (ssl_options++)
+ global.append(" AND ",5);
+ global.append("ISSUER \"",8);
+ global.append(acl_user->x509_issuer,strlen(acl_user->x509_issuer));
+ global.append("\"",1);
+ }
+ if (acl_user->x509_subject)
+ {
+ if (ssl_options++)
+ global.append(" AND ",5);
+ global.append("SUBJECT \"",9);
+ global.append(acl_user->x509_subject,strlen(acl_user->x509_subject));
+ global.append("\"",1);
+ }
+ if (acl_user->ssl_cipher)
+ {
+ if (ssl_options++)
+ global.append(" AND ",5);
+ global.append("CIPHER \"",8);
+ global.append(acl_user->ssl_cipher,strlen(acl_user->ssl_cipher));
+ global.append("\"",1);
+ }
+ }
+#endif /* HAVE_OPENSSL */
if (want_access & GRANT_ACL)
global.append(" WITH GRANT OPTION",18);
+ else if (acl_user->questions)
+ {
+ char buff[65], *p; // just as in int2str
+ global.append(" WITH MAX_QUERIES_PER_HOUR = ",29);
+ p=int2str(acl_user->questions,buff,10);
+ global.append(buff,p-buff);
+ }
thd->packet.length(0);
net_store_data(&thd->packet,global.ptr(),global.length());
if (my_net_write(&thd->net,(char*) thd->packet.ptr(),
@@ -2465,9 +2745,9 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
}
}
}
- db.append (" ON ",4);
+ db.append (" ON '",5);
db.append(acl_db->db);
- db.append (".* TO '",7);
+ db.append ("'.* TO '",8);
db.append(lex_user->user.str,lex_user->user.length);
db.append ("'@'",3);
db.append(lex_user->host.str, lex_user->host.length);
@@ -2580,6 +2860,16 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
}
+uint get_mqh(const char *user, const char *host)
+{
+ if (!initialized) return 0;
+
+ ACL_USER *acl_user;
+ acl_user= find_acl_user(host,user);
+ return (acl_user) ? acl_user->questions : 0;
+}
+
+
/*****************************************************************************
** Instantiate used templates
*****************************************************************************/
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index cf9696d51e7..f118ac17789 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.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 */
@@ -59,9 +59,9 @@ void acl_reload(void);
void acl_free(bool end=0);
uint acl_get(const char *host, const char *ip, const char *bin_ip,
const char *user, const char *db);
-uint acl_getroot(const char *host, const char *ip, const char *user,
+uint acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
const char *password,const char *scramble,char **priv_user,
- bool old_ver);
+ bool old_ver, uint *max);
bool acl_check_host(const char *host, const char *ip);
bool change_password(THD *thd, const char *host, const char *user,
char *password);
@@ -82,3 +82,4 @@ bool check_grant_db(THD *thd,const char *db);
uint get_table_grant(THD *thd, TABLE_LIST *table);
uint get_column_grant(THD *thd, TABLE_LIST *table, Field *field);
int mysql_show_grants(THD *thd, LEX_USER *user);
+uint get_mqh(const char *user, const char *host);
diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc
index de367e8c052..df8a8f1fdde 100644
--- a/sql/sql_analyse.cc
+++ b/sql/sql_analyse.cc
@@ -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 */
@@ -38,6 +38,37 @@
#define UINT_MAX24 0xffffff
#define UINT_MAX32 0xffffffff
+int sortcmp2(void* cmp_arg __attribute__((unused)),
+ const String *a,const String *b)
+{
+ return sortcmp(a,b);
+}
+
+int stringcmp2(void* cmp_arg __attribute__((unused)),
+ const String *a,const String *b)
+{
+ return stringcmp(a,b);
+}
+
+int compare_double2(void* cmp_arg __attribute__((unused)),
+ const double *s, const double *t)
+{
+ return compare_double(s,t);
+}
+
+int compare_longlong2(void* cmp_arg __attribute__((unused)),
+ const longlong *s, const longlong *t)
+{
+ return compare_longlong(s,t);
+}
+
+int compare_ulonglong2(void* cmp_arg __attribute__((unused)),
+ const ulonglong *s, const ulonglong *t)
+{
+ return compare_ulonglong(s,t);
+}
+
+
Procedure *
proc_analyse_init(THD *thd, ORDER *param, select_result *result,
List<Item> &field_list)
@@ -96,7 +127,7 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result,
pc->f_end = pc->f_info + field_list.elements;
pc->fields = field_list;
- List_iterator<Item> it(pc->fields);
+ List_iterator_fast<Item> it(pc->fields);
f_info = pc->f_info;
Item *item;
@@ -859,7 +890,7 @@ int collect_string(String *element,
int collect_real(double *element, element_count count __attribute__((unused)),
TREE_INFO *info)
{
- char buff[255];
+ char buff[MAX_FIELD_WIDTH];
String s(buff, sizeof(buff));
if (info->found)
@@ -878,7 +909,7 @@ int collect_longlong(longlong *element,
element_count count __attribute__((unused)),
TREE_INFO *info)
{
- char buff[255];
+ char buff[MAX_FIELD_WIDTH];
String s(buff, sizeof(buff));
if (info->found)
@@ -897,7 +928,7 @@ int collect_ulonglong(ulonglong *element,
element_count count __attribute__((unused)),
TREE_INFO *info)
{
- char buff[255];
+ char buff[MAX_FIELD_WIDTH];
String s(buff, sizeof(buff));
if (info->found)
diff --git a/sql/sql_analyse.h b/sql/sql_analyse.h
index ce5c0af6a96..1c60d0c150f 100644
--- a/sql/sql_analyse.h
+++ b/sql/sql_analyse.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 */
@@ -21,8 +21,6 @@
#pragma interface /* gcc class implementation */
#endif
-#include <my_tree.h>
-
#define DEC_IN_AVG 4
typedef struct st_number_info
@@ -53,8 +51,14 @@ uint check_ulonglong(const char *str, uint length);
bool get_ev_num_info(EV_NUM_INFO *ev_info, NUM_INFO *info, const char *num);
bool test_if_number(NUM_INFO *info, const char *str, uint str_len);
int compare_double(const double *s, const double *t);
+int compare_double2(void* cmp_arg __attribute__((unused)),
+ const double *s, const double *t);
int compare_longlong(const longlong *s, const longlong *t);
+int compare_longlong2(void* cmp_arg __attribute__((unused)),
+ const longlong *s, const longlong *t);
int compare_ulonglong(const ulonglong *s, const ulonglong *t);
+int compare_ulonglong2(void* cmp_arg __attribute__((unused)),
+ const ulonglong *s, const ulonglong *t);
Procedure *proc_analyse_init(THD *thd, ORDER *param, select_result *result,
List<Item> &field_list);
void free_string(String*);
@@ -91,6 +95,11 @@ public:
int collect_string(String *element, element_count count,
TREE_INFO *info);
+int sortcmp2(void* cmp_arg __attribute__((unused)),
+ const String *a,const String *b);
+int stringcmp2(void* cmp_arg __attribute__((unused)),
+ const String *a,const String *b);
+
class field_str :public field_info
{
String min_arg, max_arg;
@@ -105,9 +114,9 @@ public:
max_arg(""), sum(0),
must_be_blob(0), was_zero_fill(0),
was_maybe_zerofill(0), can_be_still_num(1)
- { init_tree(&tree, 0, sizeof(String), a->binary ?
- (qsort_cmp) stringcmp : (qsort_cmp) sortcmp,
- 0, (void (*)(void*)) free_string); };
+ { init_tree(&tree, 0, 0, sizeof(String), a->binary ?
+ (qsort_cmp2) stringcmp2 : (qsort_cmp2) sortcmp2,
+ 0, (tree_element_free) free_string, NULL); };
void add();
void get_opt_type(String*, ha_rows);
@@ -145,8 +154,8 @@ class field_real: public field_info
public:
field_real(Item* a, analyse* b) :field_info(a,b),
min_arg(0), max_arg(0), sum(0), sum_sqr(0), max_notzero_dec_len(0)
- { init_tree(&tree, 0, sizeof(double),
- (qsort_cmp) compare_double, 0, NULL); }
+ { init_tree(&tree, 0, 0, sizeof(double),
+ (qsort_cmp2) compare_double2, 0, NULL, NULL); }
void add();
void get_opt_type(String*, ha_rows);
@@ -191,8 +200,8 @@ class field_longlong: public field_info
public:
field_longlong(Item* a, analyse* b) :field_info(a,b),
min_arg(0), max_arg(0), sum(0), sum_sqr(0)
- { init_tree(&tree, 0, sizeof(longlong),
- (qsort_cmp) compare_longlong, 0, NULL); }
+ { init_tree(&tree, 0, 0, sizeof(longlong),
+ (qsort_cmp2) compare_longlong2, 0, NULL, NULL); }
void add();
void get_opt_type(String*, ha_rows);
@@ -236,8 +245,8 @@ class field_ulonglong: public field_info
public:
field_ulonglong(Item* a, analyse * b) :field_info(a,b),
min_arg(0), max_arg(0), sum(0),sum_sqr(0)
- { init_tree(&tree, 0, sizeof(ulonglong),
- (qsort_cmp) compare_ulonglong, 0, NULL); }
+ { init_tree(&tree, 0, 0, sizeof(ulonglong),
+ (qsort_cmp2) compare_ulonglong2, 0, NULL, NULL); }
void add();
void get_opt_type(String*, ha_rows);
String *get_min_arg(String *s) { s->set(min_arg); return s; }
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index e4a797efaaf..88854396ae3 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -15,7 +15,7 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/* Basic functions neaded by many modules */
+/* Basic functions needed by many modules */
#include "mysql_priv.h"
#include "sql_acl.h"
@@ -34,8 +34,6 @@ HASH open_cache; /* Used by mysql_test */
static int open_unireg_entry(THD *thd,TABLE *entry,const char *db,
const char *name, const char *alias, bool locked);
-static bool insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
- const char *table_name, List_iterator<Item> *it);
static void free_cache_entry(TABLE *entry);
static void mysql_rm_tmp_tables(void);
static key_map get_key_map_from_key_list(TABLE *table,
@@ -111,75 +109,73 @@ static void check_unused(void)
#define check_unused()
#endif
-int list_open_tables(THD *thd,List<char> *tables, const char *db,
- const char *wild)
+OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild)
{
int result = 0;
uint col_access=thd->col_access;
+ OPEN_TABLE_LIST **start_list, *open_list;
TABLE_LIST table_list;
+ char name[NAME_LEN*2];
DBUG_ENTER("list_open_tables");
+
VOID(pthread_mutex_lock(&LOCK_open));
bzero((char*) &table_list,sizeof(table_list));
+ start_list= &open_list;
+ open_list=0;
- for (uint idx=0 ; idx < open_cache.records; idx++)
+ for (uint idx=0 ; result == 0 && idx < open_cache.records; idx++)
{
+ OPEN_TABLE_LIST *table;
TABLE *entry=(TABLE*) hash_element(&open_cache,idx);
- if ((!entry->real_name) || strcmp(entry->table_cache_key,db))
- continue;
- if (wild && wild[0] && wild_compare(entry->real_name,wild))
- continue;
- if (db && !(col_access & TABLE_ACLS))
+
+ if ((!entry->real_name))
+ continue; // Shouldn't happen
+ if (wild)
{
- table_list.db= (char*) db;
- table_list.real_name= entry->real_name;/*real name*/
- table_list.grant.privilege=col_access;
- if (check_grant(thd,TABLE_ACLS,&table_list,1,1))
- continue;
+ strxmov(name,entry->table_cache_key,".",entry->real_name,NullS);
+ if (wild_compare(name,wild))
+ continue;
}
- /* need to check if he have't already listed it */
- List_iterator<char> it(*tables);
- char *table_name;
- int check = 0;
- while (check == 0 && (table_name=it++))
+ /* 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.grant.privilege=0;
+ if (check_table_access(thd,SELECT_ACL | EXTRA_ACL,&table_list))
+ continue;
+
+ /* need to check if we haven't already listed it */
+ for (table= open_list ; table ; table=table->next)
{
- if (!strcmp(table_name,entry->real_name))
- check++;
+ if (!strcmp(table->table,entry->real_name) &&
+ !strcmp(table->db,entry->table_cache_key))
+ {
+ if (entry->in_use)
+ table->in_use++;
+ if (entry->locked_by_name)
+ table->locked++;
+ break;
+ }
}
- if (check)
+ if (table)
continue;
-
- if (tables->push_back(thd->strdup(entry->real_name)))
+ if (!(*start_list = (OPEN_TABLE_LIST *)
+ sql_alloc(sizeof(**start_list)+entry->key_length)))
{
- result = -1;
+ 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);
+ (*start_list)->in_use= entry->in_use ? 1 : 0;
+ (*start_list)->locked= entry->locked_by_name ? 1 : 0;
+ start_list= &(*start_list)->next;
+ *start_list=0;
}
-
VOID(pthread_mutex_unlock(&LOCK_open));
- DBUG_RETURN(result);
-}
-
-char*
-query_table_status(THD *thd,const char *db,const char *table_name)
-{
- int cached = 0, in_use = 0;
- char info[256];
-
- for (uint idx=0 ; idx < open_cache.records; idx++)
- {
- TABLE *entry=(TABLE*) hash_element(&open_cache,idx);
- if (strcmp(entry->table_cache_key,db) ||
- strcmp(entry->real_name,table_name))
- continue;
-
- cached++;
- if (entry->in_use)
- in_use++;
- }
-
- sprintf(info, "cached=%d, in_use=%d", cached, in_use);
- return thd->strdup(info);
+ DBUG_RETURN(open_list);
}
@@ -195,7 +191,7 @@ query_table_status(THD *thd,const char *db,const char *table_name)
bool
send_fields(THD *thd,List<Item> &list,uint flag)
{
- List_iterator<Item> it(list);
+ List_iterator_fast<Item> it(list);
Item *item;
char buff[80];
CONVERT *convert= (flag & 4) ? (CONVERT*) 0 : thd->convert_set;
@@ -259,7 +255,7 @@ send_fields(THD *thd,List<Item> &list,uint flag)
if (my_net_write(&thd->net, (char*) packet->ptr(),packet->length()))
break; /* purecov: inspected */
}
- send_eof(&thd->net,(test_flags & TEST_MIT_THREAD) ? 0: 1);
+ send_eof(&thd->net);
return 0;
err:
send_error(&thd->net,ER_OUT_OF_RESOURCES); /* purecov: inspected */
@@ -304,6 +300,7 @@ static void free_cache_entry(TABLE *table)
void free_io_cache(TABLE *table)
{
+ DBUG_ENTER("free_io_cache");
if (table->io_cache)
{
close_cached_file(table->io_cache);
@@ -315,6 +312,7 @@ void free_io_cache(TABLE *table)
my_free((gptr) table->record_pointers,MYF(0));
table->record_pointers=0;
}
+ DBUG_VOID_RETURN;
}
/* Close all tables which aren't in use by any thread */
@@ -418,7 +416,6 @@ void close_thread_tables(THD *thd, bool locked)
DBUG_VOID_RETURN; // LOCK TABLES in use
}
- TABLE *table,*next;
bool found_old_table=0;
if (thd->lock)
@@ -431,41 +428,10 @@ void close_thread_tables(THD *thd, bool locked)
DBUG_PRINT("info", ("thd->open_tables=%p", thd->open_tables));
- for (table=thd->open_tables ; table ; table=next)
- {
- next=table->next;
- if (table->version != refresh_version ||
- thd->version != refresh_version || !table->db_stat)
- {
- VOID(hash_delete(&open_cache,(byte*) table));
- found_old_table=1;
- }
- else
- {
- if (table->flush_version != flush_version)
- {
- table->flush_version=flush_version;
- table->file->extra(HA_EXTRA_FLUSH);
- }
- else
- {
- // Free memory and reset for next loop
- table->file->extra(HA_EXTRA_RESET);
- }
- table->in_use=0;
- if (unused_tables)
- {
- table->next=unused_tables; /* Link in last */
- table->prev=unused_tables->prev;
- unused_tables->prev=table;
- table->prev->next=table;
- }
- else
- unused_tables=table->next=table->prev=table;
- }
- }
+ while (thd->open_tables)
+ found_old_table|=close_thread_table(thd, &thd->open_tables);
thd->some_tables_deleted=0;
- thd->open_tables=0;
+
/* Free tables to hold down open files */
while (open_cache.records > table_cache_size && unused_tables)
VOID(hash_delete(&open_cache,(byte*) unused_tables)); /* purecov: tested */
@@ -481,6 +447,48 @@ void close_thread_tables(THD *thd, bool locked)
DBUG_VOID_RETURN;
}
+/* move one table to free list */
+
+bool close_thread_table(THD *thd, TABLE **table_ptr)
+{
+ DBUG_ENTER("close_thread_table");
+
+ bool found_old_table=0;
+ TABLE *table=*table_ptr;
+
+ *table_ptr=table->next;
+ if (table->version != refresh_version ||
+ thd->version != refresh_version || !table->db_stat)
+ {
+ VOID(hash_delete(&open_cache,(byte*) table));
+ found_old_table=1;
+ }
+ else
+ {
+ if (table->flush_version != flush_version)
+ {
+ table->flush_version=flush_version;
+ table->file->extra(HA_EXTRA_FLUSH);
+ }
+ else
+ {
+ // Free memory and reset for next loop
+ table->file->extra(HA_EXTRA_RESET);
+ }
+ table->in_use=0;
+ if (unused_tables)
+ {
+ table->next=unused_tables; /* Link in last */
+ table->prev=unused_tables->prev;
+ unused_tables->prev=table;
+ table->prev->next=table;
+ }
+ else
+ unused_tables=table->next=table->prev=table;
+ }
+ DBUG_RETURN(found_old_table);
+}
+
/* Close and delete temporary tables */
void close_temporary(TABLE *table,bool delete_table)
@@ -505,7 +513,7 @@ void close_temporary_tables(THD *thd)
const uint init_query_buf_size = 11; // "drop table "
uint query_buf_size;
bool found_user_tables = 0;
-
+
LINT_INIT(end);
query_buf_size = init_query_buf_size;
@@ -582,7 +590,7 @@ bool close_temporary_table(THD *thd, const char *db, const char *table_name)
table= *prev;
*prev= table->next;
close_temporary(table);
- if(thd->slave_thread)
+ if (thd->slave_thread)
--slave_open_temp_tables;
return 0;
}
@@ -605,8 +613,6 @@ bool rename_temporary_table(THD* thd, TABLE *table, const char *db,
}
-
-
/* move table first in unused links */
static void relink_unused(TABLE *table)
@@ -690,7 +696,7 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
if (thd->killed)
DBUG_RETURN(0);
TABLE* table;
- if(!(table = table_list->table))
+ if (!(table = table_list->table))
DBUG_RETURN(0);
char* db = thd->db ? thd->db : table_list->db;
@@ -703,11 +709,11 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
if (open_unireg_entry(thd, table, db, table_name, table_name, 1) ||
!(table->table_cache_key =memdup_root(&table->mem_root,(char*) key,
key_length)))
- {
- closefrm(table);
- pthread_mutex_unlock(&LOCK_open);
- DBUG_RETURN(0);
- }
+ {
+ closefrm(table);
+ pthread_mutex_unlock(&LOCK_open);
+ DBUG_RETURN(0);
+ }
table->key_length=key_length;
table->version=0;
@@ -837,25 +843,6 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
!(table->table_cache_key=memdup_root(&table->mem_root,(char*) key,
key_length)))
{
- MEM_ROOT* glob_alloc;
- LINT_INIT(glob_alloc);
-
- if (errno == ENOENT &&
- (glob_alloc = my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC)))
- // Sasha: needed for replication
- // remember the name of the non-existent table
- // so we can try to download it from the master
- {
- int table_name_len = (uint) strlen(table_name);
- int db_len = (uint) strlen(db);
- thd->last_nx_db = alloc_root(glob_alloc,db_len + table_name_len + 2);
- if(thd->last_nx_db)
- {
- thd->last_nx_table = thd->last_nx_db + db_len + 1;
- memcpy(thd->last_nx_table, table_name, table_name_len + 1);
- memcpy(thd->last_nx_db, db, db_len + 1);
- }
- }
table->next=table->prev=table;
free_cache_entry(table);
VOID(pthread_mutex_unlock(&LOCK_open));
@@ -896,7 +883,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
table->outer_join=table->null_row=table->maybe_null=0;
table->status=STATUS_NO_RECORD;
table->keys_in_use_for_query=table->used_keys= table->keys_in_use;
- dbug_assert(table->key_read == 0);
+ DBUG_ASSERT(table->key_read == 0);
DBUG_RETURN(table);
}
@@ -1180,7 +1167,7 @@ bool wait_for_tables(THD *thd)
/* Now we can open all tables without any interference */
thd->proc_info="Reopen tables";
result=reopen_tables(thd,0,0);
-
+
}
pthread_mutex_unlock(&LOCK_open);
thd->proc_info=0;
@@ -1315,7 +1302,6 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
if (error)
goto err;
}
- (void) entry->file->extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL
DBUG_RETURN(0);
err:
DBUG_RETURN(1);
@@ -1338,7 +1324,7 @@ int open_tables(THD *thd,TABLE_LIST *start)
{
if (!tables->table &&
!(tables->table=open_table(thd,
- tables->db ? tables->db : thd->db,
+ tables->db,
tables->real_name,
tables->name, &refresh)))
{
@@ -1395,7 +1381,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
DBUG_ENTER("open_ltable");
thd->proc_info="Opening table";
- while (!(table=open_table(thd,table_list->db ? table_list->db : thd->db,
+ while (!(table=open_table(thd,table_list->db,
table_list->real_name,table_list->name,
&refresh)) && refresh) ;
if (table)
@@ -1404,11 +1390,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
#if defined( __WIN__) || defined(OS2)
/* Win32 can't drop a file that is open */
- if (lock_type == TL_WRITE_ALLOW_READ
-#ifdef HAVE_GEMINI_DB
- && table->db_type != DB_TYPE_GEMINI
-#endif /* HAVE_GEMINI_DB */
- )
+ if (lock_type == TL_WRITE_ALLOW_READ)
{
lock_type= TL_WRITE;
}
@@ -1517,7 +1499,6 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
DBUG_RETURN(0);
}
- tmp_table->file->extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL
tmp_table->reginfo.lock_type=TL_WRITE; // Simulate locked
tmp_table->tmp_table = (tmp_table->file->has_transactions() ?
TRANSACTIONAL_TMP_TABLE : TMP_TABLE);
@@ -1534,8 +1515,8 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
{
tmp_table->next=thd->temporary_tables;
thd->temporary_tables=tmp_table;
- if(thd->slave_thread)
- ++slave_open_temp_tables;
+ if (thd->slave_thread)
+ slave_open_temp_tables++;
}
DBUG_RETURN(tmp_table);
}
@@ -1595,18 +1576,13 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
{
field->query_id=thd->query_id;
table->used_fields++;
- if (field->part_of_key)
- {
- if (!(field->part_of_key & table->ref_primary_key))
- table->used_keys&=field->part_of_key;
- }
- else
- table->used_keys=0;
+ table->used_keys&=field->part_of_key;
}
else
thd->dupp_field=field;
}
- if (check_grants && !thd->master_access && check_grant_column(thd,table,name,length))
+ if (check_grants && !thd->master_access &&
+ check_grant_column(thd,table,name,length))
return WRONG_GRANT;
return field;
}
@@ -1627,9 +1603,7 @@ find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables)
for (; tables ; tables=tables->next)
{
if (!strcmp(tables->name,table_name) &&
- (!db ||
- (tables->db && !strcmp(db,tables->db)) ||
- (!tables->db && !strcmp(db,thd->db))))
+ (!db || !strcmp(db,tables->db)))
{
found_table=1;
Field *find=find_field_in_table(thd,tables->table,name,length,
@@ -1672,7 +1646,8 @@ find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables)
for (; tables ; tables=tables->next)
{
Field *field=find_field_in_table(thd,tables->table,name,length,
- grant_option && !thd->master_access, allow_rowid);
+ grant_option &&
+ !thd->master_access, allow_rowid);
if (field)
{
if (field == WRONG_GRANT)
@@ -1753,14 +1728,15 @@ find_item_in_list(Item *find,List<Item> &items)
****************************************************************************/
int setup_fields(THD *thd, TABLE_LIST *tables, List<Item> &fields,
- bool set_query_id, List<Item> *sum_func_list)
+ bool set_query_id, List<Item> *sum_func_list,
+ bool allow_sum_func)
{
reg2 Item *item;
List_iterator<Item> it(fields);
DBUG_ENTER("setup_fields");
thd->set_query_id=set_query_id;
- thd->allow_sum_func= test(sum_func_list);
+ thd->allow_sum_func= allow_sum_func;
thd->where="field list";
while ((item=it++))
@@ -1776,7 +1752,8 @@ int setup_fields(THD *thd, TABLE_LIST *tables, List<Item> &fields,
{
if (item->fix_fields(thd,tables))
DBUG_RETURN(-1); /* purecov: inspected */
- if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM)
+ if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM &&
+ sum_func_list)
item->split_sum_func(*sum_func_list);
thd->used_tables|=item->used_tables();
}
@@ -1795,27 +1772,40 @@ bool setup_tables(TABLE_LIST *tables)
{
DBUG_ENTER("setup_tables");
uint tablenr=0;
- for (TABLE_LIST *table=tables ; table ; table=table->next,tablenr++)
- {
- table->table->tablenr=tablenr;
- table->table->map= (table_map) 1 << tablenr;
- if ((table->table->outer_join=table->outer_join))
- table->table->maybe_null=1; // LEFT OUTER JOIN ...
- if (table->use_index)
+ for (TABLE_LIST *table_list=tables ; table_list ;
+ table_list=table_list->next,tablenr++)
+ {
+ TABLE *table=table_list->table;
+
+ table->used_fields=0;
+ table->const_table=0;
+ table->outer_join=table->null_row=0;
+ table->status=STATUS_NO_RECORD;
+ table->keys_in_use_for_query=table->used_keys= table->keys_in_use;
+ table->maybe_null=test(table->outer_join=table_list->outer_join);
+ table->tablenr=tablenr;
+ table->map= (table_map) 1 << tablenr;
+ if (table_list->use_index)
{
- key_map map= get_key_map_from_key_list(table->table,
- table->use_index);
+ key_map map= get_key_map_from_key_list(table,
+ table_list->use_index);
if (map == ~(key_map) 0)
DBUG_RETURN(1);
- table->table->keys_in_use_for_query=map;
+ table->keys_in_use_for_query=map;
}
- if (table->ignore_index)
+ if (table_list->ignore_index)
{
- key_map map= get_key_map_from_key_list(table->table,
- table->ignore_index);
+ key_map map= get_key_map_from_key_list(table,
+ table_list->ignore_index);
if (map == ~(key_map) 0)
DBUG_RETURN(1);
- table->table->keys_in_use_for_query &= ~map;
+ table->keys_in_use_for_query &= ~map;
+ }
+ if (table_list->shared)
+ {
+ /* Clear query_id that may have been set by previous select */
+ for (Field **ptr=table->field ; *ptr ; ptr++)
+ (*ptr)->query_id=0;
}
}
if (tablenr > MAX_TABLES)
@@ -1831,7 +1821,7 @@ static key_map get_key_map_from_key_list(TABLE *table,
List<String> *index_list)
{
key_map map=0;
- List_iterator<String> it(*index_list);
+ List_iterator_fast<String> it(*index_list);
String *name;
uint pos;
while ((name=it++))
@@ -1852,7 +1842,7 @@ static key_map get_key_map_from_key_list(TABLE *table,
** Returns pointer to last inserted field if ok
****************************************************************************/
-static bool
+bool
insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
const char *table_name, List_iterator<Item> *it)
{
@@ -1867,8 +1857,7 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
check_grant_all_columns(thd,SELECT_ACL,table) )
DBUG_RETURN(-1);
if (!table_name || (!strcmp(table_name,tables->name) &&
- (!db_name || !tables->db ||
- !strcmp(tables->db,db_name))))
+ (!db_name || !strcmp(tables->db,db_name))))
{
Field **ptr=table->field,*field;
thd->used_tables|=table->map;
@@ -1882,14 +1871,7 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
if (field->query_id == thd->query_id)
thd->dupp_field=field;
field->query_id=thd->query_id;
-
- if (field->part_of_key)
- {
- if (!(field->part_of_key & table->ref_primary_key))
- table->used_keys&=field->part_of_key;
- }
- else
- table->used_keys=0;
+ table->used_keys&=field->part_of_key;
}
/* All fields are used */
table->used_fields=table->fields;
@@ -1957,7 +1939,6 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
// TODO: This could be optimized to use hashed names if t2 had a hash
for (j=0 ; j < t2->fields ; j++)
{
- key_map tmp_map;
if (!my_strcasecmp(t1->field[i]->field_name,
t2->field[j]->field_name))
{
@@ -1970,20 +1951,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
/* Mark field used for table cache */
t1->field[i]->query_id=t2->field[j]->query_id=thd->query_id;
cond_and->list.push_back(tmp);
- if ((tmp_map=t1->field[i]->part_of_key))
- {
- if (!(tmp_map & t1->ref_primary_key))
- t1->used_keys&=tmp_map;
- }
- else
- t1->used_keys=0;
- if ((tmp_map=t2->field[j]->part_of_key))
- {
- if (!(tmp_map & t2->ref_primary_key))
- t2->used_keys&=tmp_map;
- }
- else
- t2->used_keys=0;
+ t1->used_keys&= t1->field[i]->part_of_key;
+ t2->used_keys&= t2->field[j]->part_of_key;
break;
}
}
@@ -2011,7 +1980,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
int
fill_record(List<Item> &fields,List<Item> &values)
{
- List_iterator<Item> f(fields),v(values);
+ List_iterator_fast<Item> f(fields),v(values);
Item *value;
Item_field *field;
DBUG_ENTER("fill_record");
@@ -2029,7 +1998,7 @@ fill_record(List<Item> &fields,List<Item> &values)
int
fill_record(Field **ptr,List<Item> &values)
{
- List_iterator<Item> v(values);
+ List_iterator_fast<Item> v(values);
Item *value;
DBUG_ENTER("fill_record");
@@ -2092,7 +2061,8 @@ int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
create_info.db_type=DB_TYPE_DEFAULT;
DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name,
&create_info, table_list,
- fields, keys, drop, alter, (ORDER*)0, FALSE, DUP_ERROR));
+ fields, keys, drop, alter, (ORDER*)0, FALSE,
+ DUP_ERROR));
}
@@ -2107,7 +2077,8 @@ int mysql_drop_index(THD *thd, TABLE_LIST *table_list, List<Alter_drop> &drop)
create_info.db_type=DB_TYPE_DEFAULT;
DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name,
&create_info, table_list,
- fields, keys, drop, alter, (ORDER*)0, FALSE, DUP_ERROR));
+ fields, keys, drop, alter, (ORDER*)0, FALSE,
+ DUP_ERROR));
}
/*****************************************************************************
@@ -2172,7 +2143,10 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
THD *in_use;
table->version=0L; /* Free when thread is ready */
if (!(in_use=table->in_use))
+ {
+ DBUG_PRINT("info",("Table was not in use"));
relink_unused(table);
+ }
else if (in_use != thd)
{
in_use->some_tables_deleted=1;
@@ -2202,8 +2176,8 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
int setup_ftfuncs(THD *thd)
{
- List_iterator<Item_func_match> li(thd->lex.ftfunc_list),
- lj(thd->lex.ftfunc_list);
+ List_iterator<Item_func_match> li(thd->lex.select->ftfunc_list),
+ lj(thd->lex.select->ftfunc_list);
Item_func_match *ftf, *ftf2;
while ((ftf=li++))
@@ -2223,16 +2197,17 @@ int setup_ftfuncs(THD *thd)
int init_ftfuncs(THD *thd, bool no_order)
{
- List_iterator<Item_func_match> li(thd->lex.ftfunc_list);
- Item_func_match *ifm;
- DBUG_PRINT("info",("Performing FULLTEXT search"));
- thd->proc_info="FULLTEXT initialization";
-
- while ((ifm=li++))
+ if (thd->lex.select->ftfunc_list.elements)
{
- ifm->init_search(no_order);
- }
+ List_iterator<Item_func_match> li(thd->lex.select->ftfunc_list);
+ Item_func_match *ifm;
+ DBUG_PRINT("info",("Performing FULLTEXT search"));
+ thd->proc_info="FULLTEXT initialization";
+ while ((ifm=li++))
+ {
+ ifm->init_search(no_order);
+ }
+ }
return 0;
}
-
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 09d436c0c9c..c5ebeead05a 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -1,98 +1,3448 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
+/* 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 */
+/*
+ Description of the query cache:
+
+1. Query_cache object consists of
+ - query cache memory pool (cache)
+ - queries hash (queries)
+ - tables hash (tables)
+ - list of blocks ordered as they allocated in memory
+(first_block)
+ - list of queries block (queries_blocks)
+ - list of used tables (tables_blocks)
+
+2. Query cache memory pool (cache) consists of
+ - table of steps of memory bins allocation
+ - table of free memory bins
+ - blocks of memory
+
+3. Memory blocks
+
+Every memory block has the following structure:
+
++----------------------------------------------------------+
+| Block header (Query_cache_block structure) |
++----------------------------------------------------------+
+|Table of database table lists (used for queries & tables) |
++----------------------------------------------------------+
+| Type depended header |
+|(Query_cache_query, Query_cache_table, Query_cache_result)|
++----------------------------------------------------------+
+| Data ... |
++----------------------------------------------------------+
+
+Block header consists of:
+- type:
+ FREE Free memory block
+ QUERY Query block
+ RESULT Ready to send result
+ RES_CONT Result's continuation
+ RES_BEG First block of results, that is not yet complete,
+ written to cache
+ RES_INCOMPLETE Allocated for results data block
+ TABLE Block with database table description
+ INCOMPLETE The destroyed block
+- length of block (length)
+- length of data & headers (used)
+- physical list links (pnext/pprev) - used for the list of
+ blocks ordered as they are allocated in physical memory
+- logical list links (next/prev) - used for queries block list, tables block
+ list, free memory block lists and list of results block in query
+- number of elements in table of database table list (n_tables)
+
+4. Query & results blocks
+
+Query stored in cache consists of following blocks:
+
+more more
+recent+-------------+ old
+<-----|Query block 1|------> double linked list of queries block
+ prev | | next
+ +-------------+
+ <-| table 0 |-> (see "Table of database table lists" description)
+ <-| table 1 |->
+ | ... | +--------------------------+
+ +-------------+ +-------------------------+ |
+NET | | | V V |
+struct| | +-+------------+ +------------+ |
+<-----|query header |----->|Result block|-->|Result block|-+ doublelinked
+writer| |result| |<--| | list of results
+ +-------------+ +------------+ +------------+
+ |charset | +------------+ +------------+ no table of dbtables
+ |encoding + | | result | | result |
+ |query text |<-----| header | | header |------+
+ +-------------+parent| | | |parent|
+ ^ +------------+ +------------+ |
+ | |result data | |result data | |
+ | +------------+ +------------+ |
+ +---------------------------------------------------+
+
+First query is registered. During the registration query block is
+allocated. This query block is included in query hash and is linked
+with appropriate database tables lists (if there is no appropriate
+list exists it will be created).
+
+Later when query has performed results is written into the result blocks.
+A result block cannot be smaller then QUERY_CACHE_MIN_RESULT_DATA_SIZE.
+
+When new result is written to cache it is appended to the last result
+block, if no more free space left in the last block, new block is
+allocated.
+
+5. Table of database table lists.
+
+For quick invalidation of queries all query are linked in lists on used
+database tables basis (when table will be changed (insert/delete/...)
+this queries will be removed from cache).
+
+Root of such list is table block:
+
+ +------------+ list of used tables (used while invalidation of
+<----| Table |-----> whole database)
+ prev| block |next +-----------+
+ | | +-----------+ |Query block|
+ | | |Query block| +-----------+
+ +------------+ +-----------+ | ... |
+ +->| table 0 |------>|table 0 |----->| table N |---+
+ |+-| |<------| |<-----| |<-+|
+ || +------------+ | ... | | ... | ||
+ || |table header| +-----------+ +-----------+ ||
+ || +------------+ | ... | | ... | ||
+ || |db name + | +-----------+ +-----------+ ||
+ || |table name | ||
+ || +------------+ ||
+ |+--------------------------------------------------------+|
+ +----------------------------------------------------------+
+
+Table block is included into the tables hash (tables).
+
+6. Free blocks, free blocks bins & steps of freeblock bins.
+
+When we just started only one free memory block existed. All query
+cache memory (that will be used for block allocation) were
+containing in this block.
+When a new block is allocated we find most suitable memory block
+(minimal of >= required size). If such a block can not be found, we try
+to find max block < required size (if we allocate block for results).
+If there is no free memory, oldest query is removed from cache, and then
+we try to allocate memory. Last step should be repeated until we find
+suitable block or until there is no unlocked query found.
+
+If the block is found and its length more then we need, it should be
+split into 2 blocks.
+New blocks cannot be smaller then min_allocation_unit_bytes.
+
+When a block becomes free, its neighbor-blocks should be tested and if
+there are free blocks among them, they should be joined into one block.
+
+Free memory blocks are stored in bins according to their sizes.
+The bins are stored in size-descending order.
+These bins are distributed (by size) approximately logarithmically.
+
+First bin (number 0) stores free blocks with
+size <= query_cache_size>>QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2.
+It is first (number 0) step.
+On the next step distributed (1 + QUERY_CACHE_MEM_BIN_PARTS_INC) *
+QUERY_CACHE_MEM_BIN_PARTS_MUL bins. This bins allocated in interval from
+query_cache_size>>QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2 to
+query_cache_size>>QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2 >>
+QUERY_CACHE_MEM_BIN_STEP_PWR2
+...
+On each step interval decreases in 2 power of
+QUERY_CACHE_MEM_BIN_STEP_PWR2
+times, number of bins (that distributed on this step) increases. If on
+the previous step there were N bins distributed , on the current there
+would be distributed
+(N + QUERY_CACHE_MEM_BIN_PARTS_INC) * QUERY_CACHE_MEM_BIN_PARTS_MUL
+bins.
+Last distributed bin stores blocks with size near min_allocation_unit
+bytes.
+
+For example:
+ query_cache_size>>QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2 = 100,
+ min_allocation_unit = 17,
+ QUERY_CACHE_MEM_BIN_STEP_PWR2 = 1,
+ QUERY_CACHE_MEM_BIN_PARTS_INC = 1,
+ QUERY_CACHE_MEM_BIN_PARTS_MUL = 1
+ (in followed picture showed right (low) bound of bin):
+
+ | 100>>1 50>>1 |25>>1|
+ | | | | | |
+ | 100 75 50 41 33 25 21 18 15| 12 | - bins right (low) bounds
+
+ |\---/\-----/\--------/\--------|---/ |
+ | 0 1 2 3 | | - steps
+ \-----------------------------/ \---/
+ bins that we store in cache this bin showed for example only
+
+
+Calculation of steps/bins distribution is performed only when query cache
+is resized.
+
+When we need to find appropriate bin, first we should find appropriate
+step, then we should calculate number of bins that are using data
+stored in Query_cache_memory_bin_step structure.
+
+Free memory blocks are sorted in bins in lists with size-ascending order
+(more small blocks needed frequently then bigger one).
+
+7. Packing cache.
+
+Query cache packing is divided into two operation:
+ - pack_cache
+ - join_results
+
+pack_cache moved all blocks to "top" of cache and create one block of free
+space at the "bottom":
+
+ before pack_cache after pack_cache
+ +-------------+ +-------------+
+ | query 1 | | query 1 |
+ +-------------+ +-------------+
+ | table 1 | | table 1 |
+ +-------------+ +-------------+
+ | results 1.1 | | results 1.1 |
+ +-------------+ +-------------+
+ | free | | query 2 |
+ +-------------+ +-------------+
+ | query 2 | | table 2 |
+ +-------------+ ---> +-------------+
+ | table 2 | | results 1.2 |
+ +-------------+ +-------------+
+ | results 1.2 | | results 2 |
+ +-------------+ +-------------+
+ | free | | free |
+ +-------------+ | |
+ | results 2 | | |
+ +-------------+ | |
+ | free | | |
+ +-------------+ +-------------+
+
+pack_cache scan blocks in physical address order and move every non-free
+block "higher".
+
+pack_cach remove every free block it finds. The length of the deleted block
+is accumulated to the "gap". All non free blocks should be shifted with the
+"gap" step.
+
+join_results scans all complete queries. If the results of query are not
+stored in the same block, join_results tries to move results so, that they
+are stored in one block.
+
+ before join_results after join_results
+ +-------------+ +-------------+
+ | query 1 | | query 1 |
+ +-------------+ +-------------+
+ | table 1 | | table 1 |
+ +-------------+ +-------------+
+ | results 1.1 | | free |
+ +-------------+ +-------------+
+ | query 2 | | query 2 |
+ +-------------+ +-------------+
+ | table 2 | | table 2 |
+ +-------------+ ---> +-------------+
+ | results 1.2 | | free |
+ +-------------+ +-------------+
+ | results 2 | | results 2 |
+ +-------------+ +-------------+
+ | free | | results 1 |
+ | | | |
+ | | +-------------+
+ | | | free |
+ | | | |
+ +-------------+ +-------------+
+
+If join_results allocated new block(s) then we need call pack_cache again.
+
+TODO list:
+
+ - Invalidate queries that use innoDB tables changed in transaction & remove
+ invalidation by table type
+ - Delayed till after-parsing qache answer (for column rights processing)
+ - Optimize cache resizing
+ - if new_size < old_size then pack & shrink
+ - if new_size > old_size copy cached query to new cache
+ - Move MRG_MYISAM table type processing to handlers, something like:
+ tables_used->table->file->register_used_filenames(callback,
+ first_argument);
+ - In Query_cache::insert_table eliminate strlen(). To do this we have to
+ add db_len to the TABLE_LIST and TABLE structures.
+*/
+
#include "mysql_priv.h"
#include <m_ctype.h>
#include <my_dir.h>
#include <hash.h>
+#include "sql_acl.h"
+#include "ha_myisammrg.h"
+#ifndef MASTER
+#include "../srclib/myisammrg/myrg_def.h"
+#else
+#include "../myisammrg/myrg_def.h"
+#endif
+#include <assert.h>
+
+#if defined(EXTRA_DEBUG) && !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",\
+ (ulong)(M))); pthread_mutex_unlock(M);}
+#define SEM_LOCK(M) { int val = 0; sem_getvalue (M, &val); \
+ DBUG_PRINT("lock", ("sem lock 0x%lx (%d)", (ulong)(M), val)); \
+ sem_wait(M); DBUG_PRINT("lock", ("sem lock ok")); }
+#define SEM_UNLOCK(M) {DBUG_PRINT("info", ("sem unlock 0x%lx", (ulong)(M))); \
+ sem_post(M); DBUG_PRINT("info", ("sem unlock ok")); }
+#define STRUCT_LOCK(M) {DBUG_PRINT("lock", ("%d struct lock...",__LINE__)); \
+ pthread_mutex_lock(M);DBUG_PRINT("lock", ("struct lock OK"));}
+#define STRUCT_UNLOCK(M) { \
+ DBUG_PRINT("lock", ("%d struct unlock...",__LINE__)); \
+ pthread_mutex_unlock(M);DBUG_PRINT("lock", ("struct unlock OK"));}
+#define BLOCK_LOCK_WR(B) {DBUG_PRINT("lock", ("%d LOCK_WR 0x%lx",\
+ __LINE__,(ulong)(B))); \
+ B->query()->lock_writing();}
+#define BLOCK_LOCK_RD(B) {DBUG_PRINT("lock", ("%d LOCK_RD 0x%lx",\
+ __LINE__,(ulong)(B))); \
+ B->query()->lock_reading();}
+#define BLOCK_UNLOCK_WR(B) { \
+ DBUG_PRINT("lock", ("%d UNLOCK_WR 0x%lx",\
+ __LINE__,(ulong)(B)));B->query()->unlock_writing();}
+#define BLOCK_UNLOCK_RD(B) { \
+ DBUG_PRINT("lock", ("%d UNLOCK_RD 0x%lx",\
+ __LINE__,(ulong)(B)));B->query()->unlock_reading();}
+#define DUMP(C) DBUG_EXECUTE("qcache", {\
+ (C)->cache_dump(); (C)->queries_dump();(C)->tables_dump();})
+#else
+#define MUTEX_LOCK(M) pthread_mutex_lock(M)
+#define MUTEX_UNLOCK(M) pthread_mutex_unlock(M)
+#define SEM_LOCK(M) sem_wait(M)
+#define SEM_UNLOCK(M) sem_post(M)
+#define STRUCT_LOCK(M) pthread_mutex_lock(M)
+#define STRUCT_UNLOCK(M) pthread_mutex_unlock(M)
+#define BLOCK_LOCK_WR(B) B->query()->lock_writing()
+#define BLOCK_LOCK_RD(B) B->query()->lock_reading()
+#define BLOCK_UNLOCK_WR(B) B->query()->unlock_writing()
+#define BLOCK_UNLOCK_RD(B) B->query()->unlock_reading()
+#define DUMP(C)
+#endif
+
+/*****************************************************************************
+ Query_cache_block_table method(s)
+*****************************************************************************/
+
+inline Query_cache_block * Query_cache_block_table::block()
+{
+ return (Query_cache_block *)(((byte*)this) -
+ ALIGN_SIZE(sizeof(Query_cache_block_table)*n) -
+ ALIGN_SIZE(sizeof(Query_cache_block)));
+};
+
+/*****************************************************************************
+ Query_cache_block method(s)
+*****************************************************************************/
+
+void Query_cache_block::init(ulong block_length)
+{
+ DBUG_ENTER("Query_cache_block::init");
+ DBUG_PRINT("qcache", ("init block 0x%lx length: %lu", (ulong) this,
+ block_length));
+ length = block_length;
+ used = 0;
+ type = Query_cache_block::FREE;
+ n_tables = 0;
+ DBUG_VOID_RETURN;
+}
+
+void Query_cache_block::destroy()
+{
+ DBUG_ENTER("Query_cache_block::destroy");
+ DBUG_PRINT("qcache", ("destroy block 0x%lx, type %d",
+ (ulong) this, type));
+ type = INCOMPLETE;
+ DBUG_VOID_RETURN;
+}
+
+inline uint Query_cache_block::headers_len()
+{
+ return (ALIGN_SIZE(sizeof(Query_cache_block_table)*n_tables) +
+ ALIGN_SIZE(sizeof(Query_cache_block)));
+}
+
+inline gptr Query_cache_block::data(void)
+{
+ return (gptr)( ((byte*)this) + headers_len() );
+}
+
+inline Query_cache_query * Query_cache_block::query()
+{
+#ifndef DBUG_OFF
+ if (type != QUERY)
+ query_cache.wreck(__LINE__, "incorrect block type");
+#endif
+ return (Query_cache_query *) data();
+}
+
+inline Query_cache_table * Query_cache_block::table()
+{
+#ifndef DBUG_OFF
+ if (type != TABLE)
+ query_cache.wreck(__LINE__, "incorrect block type");
+#endif
+ return (Query_cache_table *) data();
+}
+
+inline Query_cache_result * Query_cache_block::result()
+{
+#ifndef DBUG_OFF
+ if (type != RESULT && type != RES_CONT && type != RES_BEG &&
+ type != RES_INCOMPLETE)
+ query_cache.wreck(__LINE__, "incorrect block type");
+#endif
+ return (Query_cache_result *) data();
+}
+
+inline Query_cache_block_table * Query_cache_block::table(TABLE_COUNTER_TYPE n)
+{
+ return ((Query_cache_block_table *)
+ (((byte*)this)+ALIGN_SIZE(sizeof(Query_cache_block)) +
+ n*sizeof(Query_cache_block_table)));
+}
+
+
+/*****************************************************************************
+ * Query_cache_table method(s)
+ *****************************************************************************/
+
+extern "C"
+{
+byte *query_cache_table_get_key(const byte *record, uint *length,
+ my_bool not_used __attribute__((unused)))
+{
+ Query_cache_block* table_block = (Query_cache_block*) record;
+ *length = (table_block->used - table_block->headers_len() -
+ ALIGN_SIZE(sizeof(Query_cache_table)));
+ return (((byte *) table_block->data()) +
+ ALIGN_SIZE(sizeof(Query_cache_table)));
+}
+}
+
+/*****************************************************************************
+ Query_cache_query methods
+*****************************************************************************/
+
+void Query_cache_query::init_n_lock()
+{
+ DBUG_ENTER("Query_cache_query::init_n_lock");
+ res=0; wri = 0; len = 0;
+ sem_init(&lock, 0, 1);
+ pthread_mutex_init(&clients_guard,MY_MUTEX_INIT_FAST);
+ clients = 0;
+ lock_writing();
+ DBUG_PRINT("qcache", ("inited & locked query for block 0x%lx",
+ ((byte*) this)-ALIGN_SIZE(sizeof(Query_cache_block))));
+ DBUG_VOID_RETURN;
+}
+
+
+void Query_cache_query::unlock_n_destroy()
+{
+ DBUG_ENTER("Query_cache_query::unlock_n_destroy");
+ DBUG_PRINT("qcache", ("destroyed & unlocked query for block 0x%lx",
+ ((byte*)this)-ALIGN_SIZE(sizeof(Query_cache_block))));
+ /*
+ The following call is not needed on system where one can destroy an
+ active semaphore
+ */
+ this->unlock_writing();
+ sem_destroy(&lock);
+ pthread_mutex_destroy(&clients_guard);
+ DBUG_VOID_RETURN;
+}
-#define SQL_CACHE_LENGTH 30 // 300 crashes apple gcc.
-HASH sql_cache;
-static LEX lex_array_static[SQL_CACHE_LENGTH];
-LEX * lex_array = lex_array_static;
-int last_lex_array_item = SQL_CACHE_LENGTH - 1;
+/*
+ Following methods work for block read/write locking only in this
+ particular case and in interaction with structure_guard_mutex.
-/* Function to return a text string from a LEX struct */
-static byte *cache_key(const byte *record, uint *length, my_bool not_used)
+ Lock for write prevents any other locking. (exclusive use)
+ Lock for read prevents only locking for write.
+*/
+
+void Query_cache_query::lock_writing()
+{
+ SEM_LOCK(&lock);
+}
+
+
+/*
+ Needed for finding queries, that we may delete from cache.
+ We don't want to wait while block become unlocked. In addition,
+ block locking means that query is now used and we don't need to
+ remove it.
+*/
+
+my_bool Query_cache_query::try_lock_writing()
+{
+ DBUG_ENTER("Query_cache_block::try_lock_writing");
+ if (sem_trywait(&lock)!=0 || clients != 0)
+ {
+ DBUG_PRINT("info", ("can't lock semaphore"));
+ DBUG_RETURN(0);
+ }
+ DBUG_PRINT("info", ("mutex 'lock' 0x%lx locked", (ulong) &lock));
+ DBUG_RETURN(1);
+}
+
+
+void Query_cache_query::lock_reading()
+{
+ MUTEX_LOCK(&clients_guard);
+ if ( ++clients == 1 )
+ SEM_LOCK(&lock);
+ MUTEX_UNLOCK(&clients_guard);
+}
+
+
+void Query_cache_query::unlock_writing()
+{
+ SEM_UNLOCK(&lock);
+}
+
+
+void Query_cache_query::unlock_reading()
+{
+ /*
+ To avoid unlocking semaphore before unlocking mutex (that may cause
+ destroying locked mutex), we use temporary boolean variable 'unlock'.
+ */
+ MUTEX_LOCK(&clients_guard);
+ bool ulock = ((--clients) == 0);
+ MUTEX_UNLOCK(&clients_guard);
+ if (ulock) SEM_UNLOCK(&lock);
+}
+
+extern "C"
+{
+byte *query_cache_query_get_key(const byte *record, uint *length,
+ my_bool not_used)
+{
+ Query_cache_block *query_block = (Query_cache_block*) record;
+ *length = (query_block->used - query_block->headers_len() -
+ ALIGN_SIZE(sizeof(Query_cache_query)));
+ return (((byte *) query_block->data()) +
+ ALIGN_SIZE(sizeof(Query_cache_query)));
+}
+}
+
+/*****************************************************************************
+ Functions to store things into the query cache
+*****************************************************************************/
+
+/*
+ Insert the packet into the query cache.
+ This should only be called if net->query_cache_query != 0
+*/
+
+void query_cache_insert(NET *net, const char *packet, ulong length)
+{
+ DBUG_ENTER("query_cache_insert");
+
+#ifndef DBUG_OFF
+ // Check if we have called query_cache.wreck() (which disables the cache)
+ if (query_cache.query_cache_size == 0)
+ DBUG_VOID_RETURN;
+#endif
+
+ STRUCT_LOCK(&query_cache.structure_guard_mutex);
+ Query_cache_block *query_block = ((Query_cache_block*)
+ net->query_cache_query);
+ if (query_block)
+ {
+ Query_cache_query *header = query_block->query();
+ Query_cache_block *result = header->result();
+
+ DUMP(&query_cache);
+ BLOCK_LOCK_WR(query_block);
+ DBUG_PRINT("qcache", ("insert packet %lu bytes long",length));
+
+ /*
+ On success STRUCT_UNLOCK(&query_cache.structure_guard_mutex) will be
+ done by query_cache.append_result_data if success (if not we need
+ query_cache.structure_guard_mutex locked to free query)
+ */
+ if (!query_cache.append_result_data(&result, length, (gptr) packet,
+ query_block))
+ {
+ query_cache.refused++;
+ DBUG_PRINT("warning", ("Can't append data"));
+ header->result(result);
+ DBUG_PRINT("qcache", ("free query 0x%lx", (ulong) query_block));
+ // The following call will remove the lock on query_block
+ query_cache.free_query(query_block);
+ // append_result_data no success => we need unlock
+ STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+ DBUG_VOID_RETURN;
+ }
+ header->result(result);
+ BLOCK_UNLOCK_WR(query_block);
+ }
+ else
+ STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+ DBUG_EXECUTE("check_querycache",query_cache.check_integrity(0););
+ DBUG_VOID_RETURN;
+}
+
+
+void query_cache_abort(NET *net)
+{
+ DBUG_ENTER("query_cache_abort");
+
+#ifndef DBUG_OFF
+ // Check if we have called query_cache.wreck() (which disables the cache)
+ if (query_cache.query_cache_size == 0)
+ DBUG_VOID_RETURN;
+#endif
+ if (net->query_cache_query != 0) // Quick check on unlocked structure
+ {
+ STRUCT_LOCK(&query_cache.structure_guard_mutex);
+ Query_cache_block *query_block = ((Query_cache_block*)
+ net->query_cache_query);
+ if (query_block) // Test if changed by other thread
+ {
+ DUMP(&query_cache);
+ BLOCK_LOCK_WR(query_block);
+ // The following call will remove the lock on query_block
+ query_cache.free_query(query_block);
+ }
+ net->query_cache_query=0;
+ DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
+ STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+void query_cache_end_of_result(NET *net)
{
-#ifdef QQ
- LEX *lex=(LEX*) record;
- *length = lex->sql_query_length;
- // *length = strlen(lex->ptr);
- return (byte*) lex->sql_query_text;
- // return (byte*) lex->ptr;
+ DBUG_ENTER("query_cache_end_of_result");
+
+#ifndef DBUG_OFF
+ // Check if we have called query_cache.wreck() (which disables the cache)
+ if (query_cache.query_cache_size == 0) DBUG_VOID_RETURN;
+#endif
+
+ if (net->query_cache_query != 0) // Quick check on unlocked structure
+ {
+ STRUCT_LOCK(&query_cache.structure_guard_mutex);
+ Query_cache_block *query_block = ((Query_cache_block*)
+ net->query_cache_query);
+ if (query_block)
+ {
+ DUMP(&query_cache);
+ BLOCK_LOCK_WR(query_block);
+ Query_cache_query *header = query_block->query();
+ Query_cache_block *last_result_block = header->result()->prev;
+ ulong allign_size = ALIGN_SIZE(last_result_block->used);
+ ulong len = max(query_cache.min_allocation_unit, allign_size);
+ if (last_result_block->length >= query_cache.min_allocation_unit + len)
+ query_cache.split_block(last_result_block,len);
+ STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+
+#ifndef DBUG_OFF
+ if (header->result() == 0)
+ {
+ DBUG_PRINT("error", ("end of data whith no result. query '%s'",
+ header->query()));
+ query_cache.wreck(__LINE__, "");
+ DBUG_VOID_RETURN;
+ }
#endif
- return 0;
+ header->found_rows(current_thd->limit_found_rows);
+ header->result()->type = Query_cache_block::RESULT;
+ header->writer(0);
+ BLOCK_UNLOCK_WR(query_block);
+ }
+ else
+ {
+ // Cache was flushed or resized and query was deleted => do nothing
+ STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+ }
+ net->query_cache_query=0;
+ DBUG_EXECUTE("check_querycache",query_cache.check_integrity(0););
+ }
+ DBUG_VOID_RETURN;
+}
+
+void query_cache_invalidate_by_MyISAM_filename(const char *filename)
+{
+ query_cache.invalidate_by_MyISAM_filename(filename);
+ DBUG_EXECUTE("check_querycache",query_cache.check_integrity(0););
+}
+
+
+/*****************************************************************************
+ Query_cache methods
+*****************************************************************************/
+
+Query_cache::Query_cache(ulong query_cache_limit,
+ ulong min_allocation_unit,
+ ulong min_result_data_size,
+ uint def_query_hash_size ,
+ uint def_table_hash_size)
+ :query_cache_size(0),
+ query_cache_limit(query_cache_limit),
+ queries_in_cache(0), hits(0), inserts(0), refused(0),
+ total_blocks(0),
+ min_allocation_unit(min_allocation_unit),
+ min_result_data_size(min_result_data_size),
+ def_query_hash_size(def_query_hash_size),
+ def_table_hash_size(def_table_hash_size),
+ initialized(0)
+{
+ ulong min_needed=(ALIGN_SIZE(sizeof(Query_cache_block)) +
+ ALIGN_SIZE(sizeof(Query_cache_block_table)) +
+ ALIGN_SIZE(sizeof(Query_cache_query)) + 3);
+ set_if_bigger(min_allocation_unit,min_needed);
+ this->min_allocation_unit = min_allocation_unit;
+ set_if_bigger(this->min_result_data_size,min_allocation_unit);
+}
+
+
+ulong Query_cache::resize(ulong query_cache_size)
+{
+ DBUG_ENTER("Query_cache::resize");
+ DBUG_PRINT("qcache", ("from %lu to %lu",this->query_cache_size,
+ query_cache_size));
+ free_cache(0);
+ this->query_cache_size=query_cache_size;
+ DBUG_RETURN(init_cache());
+}
+
+
+void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
+{
+ TABLE_COUNTER_TYPE tables;
+ ulong tot_length;
+ DBUG_ENTER("Query_cache::store_query");
+ if (query_cache_size == 0)
+ DBUG_VOID_RETURN;
+
+ if ((tables = is_cacheable(thd, thd->query_length,
+ thd->query, &thd->lex, tables_used)))
+ {
+ NET *net = &thd->net;
+ byte flags = (thd->client_capabilities & CLIENT_LONG_FLAG ? 0x80 : 0);
+ STRUCT_LOCK(&structure_guard_mutex);
+
+ if (query_cache_size == 0)
+ DBUG_VOID_RETURN;
+ DUMP(this);
+
+ /* Key is query + database + flag */
+ if (thd->db_length)
+ {
+ memcpy(thd->query+thd->query_length+1, thd->db, thd->db_length);
+ DBUG_PRINT("qcache", ("database : %s length %u",
+ thd->db, thd->db_length));
+ }
+ else
+ {
+ DBUG_PRINT("qcache", ("No active database"));
+ }
+ /*
+ Prepare flags:
+ most significant bit - CLIENT_LONG_FLAG,
+ other - charset number (0 no charset convertion)
+ */
+ if (thd->convert_set != 0)
+ {
+ flags|= (byte) thd->convert_set->number();
+ DBUG_ASSERT(thd->convert_set->number() < 128);
+ }
+ tot_length=thd->query_length+thd->db_length+2;
+ thd->query[tot_length-1] = (char) flags;
+
+ /* Check if another thread is processing the same query? */
+ Query_cache_block *competitor = (Query_cache_block *)
+ hash_search(&queries, (byte*) thd->query, tot_length);
+ DBUG_PRINT("qcache", ("competitor 0x%lx, flags %x", (ulong) competitor,
+ flags));
+ if (competitor == 0)
+ {
+ /* Query is not in cache and no one is working with it; Store it */
+ Query_cache_block *query_block;
+ query_block= write_block_data(tot_length, (gptr) thd->query,
+ ALIGN_SIZE(sizeof(Query_cache_query)),
+ Query_cache_block::QUERY, tables, 1);
+ if (query_block != 0)
+ {
+ DBUG_PRINT("qcache", ("query block 0x%lx allocated, %lu",
+ (ulong) query_block, query_block->used));
+
+ Query_cache_query *header = query_block->query();
+ header->init_n_lock();
+ if (hash_insert(&queries, (byte*) query_block))
+ {
+ refused++;
+ DBUG_PRINT("qcache", ("insertion in query hash"));
+ header->unlock_n_destroy();
+ free_memory_block(query_block);
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ goto end;
+ }
+ if (!register_all_tables(query_block, tables_used, tables))
+ {
+ refused++;
+ DBUG_PRINT("warning", ("tables list including failed"));
+ hash_delete(&queries, (byte *) query_block);
+ header->unlock_n_destroy();
+ free_memory_block(query_block);
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ goto end;
+ }
+ double_linked_list_simple_include(query_block, &queries_blocks);
+ inserts++;
+ queries_in_cache++;
+ STRUCT_UNLOCK(&structure_guard_mutex);
+
+ net->query_cache_query= (gptr) query_block;
+ header->writer(net);
+ // init_n_lock make query block locked
+ BLOCK_UNLOCK_WR(query_block);
+ }
+ else
+ {
+ // We have not enough memory to store query => do nothing
+ refused++;
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_PRINT("warning", ("Can't allocate query"));
+ }
+ }
+ else
+ {
+ // Another thread is processing the same query => do nothing
+ refused++;
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_PRINT("qcache", ("Another thread process same query"));
+ }
+ }
+ else
+ statistic_increment(refused, &structure_guard_mutex);
+
+end:
+ DBUG_VOID_RETURN;
+}
+
+/*
+ Check if the query is in the cache. If it was cached, send it
+ to the user.
+
+ RESULTS
+ 1 Query was not cached.
+ 0 The query was cached and user was sent the result.
+ -1 The query was cached but we didn't have rights to use it.
+ No error is sent to the client yet.
+*/
+
+
+
+int
+Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
+{
+ Query_cache_query *query;
+ Query_cache_block *first_result_block, *result_block;
+ Query_cache_block_table *block_table, *block_table_end;
+ ulong tot_length;
+ byte flags;
+ DBUG_ENTER("Query_cache::send_result_to_client");
+
+ if (query_cache_size == 0 ||
+ /*
+ it is not possible to check has_transactions() function of handler
+ because tables not opened yet
+ */
+ (thd->options & (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN)) ||
+ thd->query_cache_type == 0)
+
+ {
+ DBUG_PRINT("qcache", ("query cache disabled or not in autocommit mode"));
+ goto err;
+ }
+
+ /* Check that we haven't forgot to reset the query cache variables */
+ DBUG_ASSERT(thd->net.query_cache_query == 0);
+
+ if (!thd->safe_to_cache_query)
+ {
+ DBUG_PRINT("qcache", ("SELECT is non-cacheable"));
+ goto err;
+ }
+
+ /*
+ Test if the query is a SELECT
+ (pre-space is removed in dispatch_command)
+ */
+ if (toupper(sql[0]) != 'S' || toupper(sql[1]) != 'E' ||
+ toupper(sql[2]) !='L')
+ {
+ DBUG_PRINT("qcache", ("The statement is not a SELECT; Not cached"));
+ goto err;
+ }
+
+ STRUCT_LOCK(&structure_guard_mutex);
+ if (query_cache_size == 0)
+ {
+ DBUG_PRINT("qcache", ("query cache disabled"));
+ goto err_unlock;
+ }
+ Query_cache_block *query_block;
+
+ tot_length=query_length+thd->db_length+2;
+ if (thd->db_length)
+ {
+ memcpy(sql+query_length+1, thd->db, thd->db_length);
+ DBUG_PRINT("qcache", ("database: '%s' length %u",
+ thd->db, thd->db_length));
+ }
+ else
+ {
+ DBUG_PRINT("qcache", ("No active database"));
+ }
+ /*
+ prepare flags:
+ Most significant bit - CLIENT_LONG_FLAG,
+ Other - charset number (0 no charset convertion)
+ */
+ flags = (thd->client_capabilities & CLIENT_LONG_FLAG ? 0x80 : 0);
+ if (thd->convert_set != 0)
+ {
+ flags |= (byte) thd->convert_set->number();
+ DBUG_ASSERT(thd->convert_set->number() < 128);
+ }
+ sql[tot_length-1] = (char) flags;
+ query_block = (Query_cache_block *) hash_search(&queries, (byte*) sql,
+ tot_length);
+ /* Quick abort on unlocked data */
+ if (query_block == 0 ||
+ query_block->query()->result() == 0 ||
+ query_block->query()->result()->type != Query_cache_block::RESULT)
+ {
+ DBUG_PRINT("qcache", ("No query in query hash or no results"));
+ goto err_unlock;
+ }
+ DBUG_PRINT("qcache", ("Query in query hash 0x%lx", (ulong)query_block));
+
+ /* Now lock and test that nothing changed while blocks was unlocked */
+ BLOCK_LOCK_RD(query_block);
+
+ query = query_block->query();
+ result_block= first_result_block= query->result();
+
+ if (result_block == 0 || result_block->type != Query_cache_block::RESULT)
+ {
+ /* The query is probably yet processed */
+ DBUG_PRINT("qcache", ("query found, but no data or data incomplete"));
+ BLOCK_UNLOCK_RD(query_block);
+ goto err_unlock;
+ }
+ DBUG_PRINT("qcache", ("Query have result 0x%lx", (ulong) query));
+
+ // Check access;
+ block_table= query_block->table(0);
+ block_table_end= block_table+query_block->n_tables;
+ for ( ; block_table != block_table_end; block_table++)
+ {
+ TABLE_LIST table_list;
+ bzero((char*) &table_list,sizeof(table_list));
+
+ Query_cache_table *table = block_table->parent;
+ table_list.db = table->db();
+ table_list.name = table_list.real_name = table->table();
+ if (check_table_access(thd,SELECT_ACL,&table_list,1))
+ {
+ DBUG_PRINT("qcache",
+ ("probably no SELECT access to %s.%s => return to normal processing",
+ table_list.db, table_list.name));
+ refused++; // This is actually a hit
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ thd->safe_to_cache_query=0; // Don't try to cache this
+ BLOCK_UNLOCK_RD(query_block);
+ DBUG_RETURN(-1); // Privilege error
+ }
+ if (table_list.grant.want_privilege)
+ {
+ DBUG_PRINT("qcache", ("Need to check column privileges for %s.%s",
+ table_list.db, table_list.name));
+ BLOCK_UNLOCK_RD(query_block);
+ thd->safe_to_cache_query=0; // Don't try to cache this
+ goto err_unlock; // Parse query
+ }
+ }
+ move_to_query_list_end(query_block);
+ hits++;
+ STRUCT_UNLOCK(&structure_guard_mutex);
+
+ /*
+ Send cached result to client
+ */
+ do
+ {
+ DBUG_PRINT("qcache", ("Results (len %lu, used %lu, headers %lu)",
+ result_block->length, result_block->used,
+ result_block->headers_len()+
+ ALIGN_SIZE(sizeof(Query_cache_result))));
+
+ Query_cache_result *result = result_block->result();
+ if (net_real_write(&thd->net, result->data(),
+ result_block->used -
+ result_block->headers_len() -
+ ALIGN_SIZE(sizeof(Query_cache_result))))
+ break; // Client aborted
+ result_block = result_block->next;
+ } while (result_block != first_result_block);
+
+ thd->limit_found_rows = query->found_rows();
+
+ BLOCK_UNLOCK_RD(query_block);
+ DBUG_RETURN(1); // Result sent to client
+
+err_unlock:
+ STRUCT_UNLOCK(&structure_guard_mutex);
+err:
+ DBUG_RETURN(0); // Query was not cached
+}
+
+/*
+ Remove all cached queries that uses any of the tables in the list
+*/
+
+void Query_cache::invalidate(TABLE_LIST *tables_used)
+{
+ DBUG_ENTER("Query_cache::invalidate (table list)");
+ if (query_cache_size > 0)
+ {
+ STRUCT_LOCK(&structure_guard_mutex);
+ if (query_cache_size > 0)
+ {
+ DUMP(this);
+ for ( ; tables_used; tables_used=tables_used->next)
+ invalidate_table(tables_used);
+ }
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ }
+ DBUG_VOID_RETURN;
+}
+
+/*
+ Remove all cached queries that uses the given table
+*/
+
+void Query_cache::invalidate(TABLE *table)
+{
+ DBUG_ENTER("Query_cache::invalidate (table)");
+ if (query_cache_size > 0)
+ {
+ STRUCT_LOCK(&structure_guard_mutex);
+ if (query_cache_size > 0)
+ invalidate_table(table);
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ }
+ DBUG_VOID_RETURN;
+}
+
+/*
+ Remove all cached queries that uses the given table type.
+*/
+
+void Query_cache::invalidate(Query_cache_table::query_cache_table_type type)
+{
+ DBUG_ENTER("Query_cache::invalidate (type)");
+ if (query_cache_size > 0)
+ {
+ STRUCT_LOCK(&structure_guard_mutex);
+ DUMP(this);
+ if (query_cache_size > 0)
+ {
+ /* invalidate_table reduce list while only root of list remain */
+ while (tables_blocks[type] != 0)
+ invalidate_table(tables_blocks[type]);
+ }
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Remove all cached queries that uses the given database
+*/
+
+void Query_cache::invalidate(char *db)
+{
+ DBUG_ENTER("Query_cache::invalidate (db)");
+ if (query_cache_size > 0)
+ {
+ STRUCT_LOCK(&structure_guard_mutex);
+ if (query_cache_size > 0)
+ {
+ DUMP(this);
+ for (int i=0 ; i < (int) Query_cache_table::TYPES_NUMBER; i++)
+ {
+ /* invalidate_table reduce list while only root of list remain */
+ while (tables_blocks[i] !=0 )
+ invalidate_table(tables_blocks[i]);
+ }
+ }
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+void Query_cache::invalidate_by_MyISAM_filename(const char *filename)
+{
+ DBUG_ENTER("Query_cache::invalidate_by_MyISAM_filename");
+ if (query_cache_size > 0)
+ {
+ /* Calculate the key outside the lock to make the lock shorter */
+ char key[MAX_DBKEY_LENGTH];
+ uint key_length= filename_2_table_key(key, filename);
+ STRUCT_LOCK(&structure_guard_mutex);
+ if (query_cache_size > 0) // Safety if cache removed
+ {
+ Query_cache_block *table_block;
+ if ((table_block = (Query_cache_block*) hash_search(&tables,
+ (byte*) key,
+ key_length)))
+ invalidate_table(table_block);
+ }
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ }
+ DBUG_VOID_RETURN;
+}
+
+ /* Remove all queries from cache */
+
+void Query_cache::flush()
+{
+ DBUG_ENTER("Query_cache::flush");
+ STRUCT_LOCK(&structure_guard_mutex);
+ if (query_cache_size > 0)
+ {
+ DUMP(this);
+ flush_cache();
+ DUMP(this);
+ }
+
+ DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_VOID_RETURN;
+}
+
+ /* Join result in cache in 1 block (if result length > join_limit) */
+
+void Query_cache::pack(ulong join_limit, uint iteration_limit)
+{
+ DBUG_ENTER("Query_cache::pack");
+ uint i = 0;
+ do
+ {
+ pack_cache();
+ } while ((++i < iteration_limit) && join_results(join_limit));
+ DBUG_VOID_RETURN;
+}
+
+
+void Query_cache::destroy()
+{
+ if ( !initialized )
+ {
+ DBUG_PRINT("qcache", ("Query Cache not initialized"));
+ return;
+ }
+ DBUG_ENTER("Query_cache::destroy");
+ free_cache(1);
+ pthread_mutex_destroy(&structure_guard_mutex);
+ initialized = 0;
+ DBUG_VOID_RETURN;
+}
+
+
+/*****************************************************************************
+ init/destroy
+*****************************************************************************/
+
+void Query_cache::init()
+{
+ DBUG_ENTER("Query_cache::init");
+ pthread_mutex_init(&structure_guard_mutex,MY_MUTEX_INIT_FAST);
+ initialized = 1;
+ DBUG_VOID_RETURN;
+}
+
+
+ulong Query_cache::init_cache()
+{
+ uint mem_bin_count, num, step;
+ ulong mem_bin_size, prev_size, inc;
+ ulong additional_data_size, max_mem_bin_size, approx_additional_data_size;
+
+ DBUG_ENTER("Query_cache::init_cache");
+ if (!initialized)
+ init();
+ approx_additional_data_size = (sizeof(Query_cache) +
+ sizeof(gptr)*(def_query_hash_size+
+ def_query_hash_size));
+ if (query_cache_size < approx_additional_data_size)
+ goto err;
+
+ query_cache_size -= approx_additional_data_size;
+
+ /*
+ Count memory bins number.
+ Check section 6. in start comment for the used algorithm.
+ */
+
+ max_mem_bin_size = query_cache_size >> QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2;
+ mem_bin_count = (uint) ((1 + QUERY_CACHE_MEM_BIN_PARTS_INC) *
+ QUERY_CACHE_MEM_BIN_PARTS_MUL);
+ mem_bin_num = 1;
+ mem_bin_steps = 1;
+ mem_bin_size = max_mem_bin_size >> QUERY_CACHE_MEM_BIN_STEP_PWR2;
+ prev_size = 0;
+ while (mem_bin_size > min_allocation_unit)
+ {
+ mem_bin_num += mem_bin_count;
+ prev_size = mem_bin_size;
+ mem_bin_size >>= QUERY_CACHE_MEM_BIN_STEP_PWR2;
+ mem_bin_steps++;
+ mem_bin_count += QUERY_CACHE_MEM_BIN_PARTS_INC;
+ mem_bin_count = (uint) (mem_bin_count * QUERY_CACHE_MEM_BIN_PARTS_MUL);
+
+ // Prevent too small bins spacing
+ if (mem_bin_count > (mem_bin_size >> QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2))
+ mem_bin_count= (mem_bin_size >> QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2);
+ }
+ inc = (prev_size - mem_bin_size) / mem_bin_count;
+ mem_bin_num += (mem_bin_count - (min_allocation_unit - mem_bin_size)/inc);
+ mem_bin_steps++;
+ additional_data_size = ((mem_bin_num+1) *
+ ALIGN_SIZE(sizeof(Query_cache_memory_bin))+
+ (mem_bin_steps *
+ ALIGN_SIZE(sizeof(Query_cache_memory_bin_step))));
+
+ if (query_cache_size < additional_data_size)
+ goto err;
+ query_cache_size -= additional_data_size;
+
+ STRUCT_LOCK(&structure_guard_mutex);
+ if (query_cache_size <= min_allocation_unit)
+ {
+ DBUG_PRINT("qcache",
+ (" query_cache_size <= min_allocation_unit => cache disabled"));
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ goto err;
+ }
+
+ if (!(cache = (byte *)
+ my_malloc_lock(query_cache_size+additional_data_size, MYF(0))))
+ {
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ goto err;
+ }
+
+ DBUG_PRINT("qcache", ("cache length %lu, min unit %lu, %u bins",
+ query_cache_size, min_allocation_unit, mem_bin_num));
+
+ steps = (Query_cache_memory_bin_step *) cache;
+ bins = ((Query_cache_memory_bin *)
+ (cache + mem_bin_steps *
+ ALIGN_SIZE(sizeof(Query_cache_memory_bin_step))));
+
+ first_block = (Query_cache_block *) (cache + additional_data_size);
+ first_block->init(query_cache_size);
+ total_blocks++;
+ first_block->pnext=first_block->pprev=first_block;
+ first_block->next=first_block->prev=first_block;
+
+ /* Prepare bins */
+
+ bins[0].init(max_mem_bin_size);
+ steps[0].init(max_mem_bin_size,0,0);
+ mem_bin_count = (uint) ((1 + QUERY_CACHE_MEM_BIN_PARTS_INC) *
+ QUERY_CACHE_MEM_BIN_PARTS_MUL);
+ num= step= 1;
+ mem_bin_size = max_mem_bin_size >> QUERY_CACHE_MEM_BIN_STEP_PWR2;
+ while (mem_bin_size > min_allocation_unit)
+ {
+ ulong incr = (steps[step-1].size - mem_bin_size) / mem_bin_count;
+ unsigned long size = mem_bin_size;
+ for (uint i= mem_bin_count; i > 0; i--)
+ {
+ bins[num+i-1].init(size);
+ size += incr;
+ }
+ num += mem_bin_count;
+ steps[step].init(mem_bin_size, num-1, incr);
+ mem_bin_size >>= QUERY_CACHE_MEM_BIN_STEP_PWR2;
+ step++;
+ mem_bin_count += QUERY_CACHE_MEM_BIN_PARTS_INC;
+ mem_bin_count = (uint) (mem_bin_count * QUERY_CACHE_MEM_BIN_PARTS_MUL);
+ if (mem_bin_count > (mem_bin_size >> QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2))
+ mem_bin_count=(mem_bin_size >> QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2);
+ }
+ inc = (steps[step-1].size - mem_bin_size) / mem_bin_count;
+
+ /*
+ num + mem_bin_count > mem_bin_num, but index never be > mem_bin_num
+ because block with size < min_allocated_unit never will be requested
+ */
+
+ steps[step].init(mem_bin_size, num + mem_bin_count - 1, inc);
+ {
+ uint skiped = (min_allocation_unit - mem_bin_size)/inc;
+ ulong size = mem_bin_size + inc*skiped;
+ uint i = mem_bin_count - skiped;
+ while (i-- > 0)
+ {
+ bins[num+i].init(size);
+ size += inc;
+ }
+ }
+ bins[mem_bin_num].number = 1; // For easy end test in get_free_block
+ free_memory = free_memory_blocks = 0;
+ insert_into_free_memory_list(first_block);
+
+ DUMP(this);
+
+ VOID(hash_init(&queries,def_query_hash_size, 0, 0,
+ query_cache_query_get_key, 0, 0));
+ VOID(hash_init(&tables,def_table_hash_size, 0, 0,
+ query_cache_table_get_key, 0, 0));
+
+ queries_in_cache = 0;
+ queries_blocks = 0;
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_RETURN(query_cache_size +
+ additional_data_size + approx_additional_data_size);
+
+err:
+ make_disabled();
+ DBUG_RETURN(0);
+}
+
+
+/* Disable the use of the query cache */
+
+void Query_cache::make_disabled()
+{
+ DBUG_ENTER("Query_cache::make_disabled");
+ query_cache_size= 0;
+ free_memory= 0;
+ bins= 0;
+ steps= 0;
+ cache= 0;
+ mem_bin_num= mem_bin_steps= 0;
+ queries_in_cache= 0;
+ first_block= 0;
+ DBUG_VOID_RETURN;
+}
+
+
+void Query_cache::free_cache(my_bool destruction)
+{
+ DBUG_ENTER("Query_cache::free_cache");
+ if (query_cache_size > 0)
+ {
+ if (!destruction)
+ STRUCT_LOCK(&structure_guard_mutex);
+
+ flush_cache();
+#ifndef DBUG_OFF
+ if (bins[0].free_blocks == 0)
+ {
+ wreck(__LINE__,"no free memory found in (bins[0].free_blocks");
+ DBUG_VOID_RETURN;
+ }
+#endif
+
+ /* Becasue we did a flush, all cache memory must be in one this block */
+ bins[0].free_blocks->destroy();
+ total_blocks--;
+#ifndef DBUG_OFF
+ if (free_memory != query_cache_size)
+ DBUG_PRINT("qcache", ("free memory %lu (should be %lu)",
+ free_memory , query_cache_size));
+#endif
+ my_free((gptr) cache, MYF(MY_ALLOW_ZERO_PTR));
+ make_disabled();
+ hash_free(&queries);
+ hash_free(&tables);
+ if (!destruction)
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ }
+ DBUG_VOID_RETURN;
+}
+
+/*****************************************************************************
+ Free block data
+*****************************************************************************/
+
+/*
+ The following assumes we have a lock on the cache
+*/
+
+void Query_cache::flush_cache()
+{
+ while (queries_blocks != 0)
+ {
+ BLOCK_LOCK_WR(queries_blocks);
+ free_query(queries_blocks);
+ }
+}
+
+/*
+ Free oldest query that is not in use by another thread.
+ Returns 1 if we couldn't remove anything
+*/
+
+my_bool Query_cache::free_old_query()
+{
+ DBUG_ENTER("Query_cache::free_old_query");
+ if (queries_blocks)
+ {
+ /*
+ try_lock_writing used to prevent client because here lock
+ sequence is breached.
+ Also we don't need remove locked queries at this point.
+ */
+ Query_cache_block *query_block = 0;
+ if (queries_blocks != 0)
+ {
+ Query_cache_block *block = queries_blocks;
+ /* Search until we find first query that we can remove */
+ do
+ {
+ Query_cache_query *header = block->query();
+ if (header->result() != 0 &&
+ header->result()->type == Query_cache_block::RESULT &&
+ block->query()->try_lock_writing())
+ {
+ query_block = block;
+ break;
+ }
+ } while ((block=block->next) != queries_blocks );
+ }
+
+ if (query_block != 0)
+ {
+ free_query(query_block);
+ DBUG_RETURN(0);
+ }
+ }
+ DBUG_RETURN(1); // Nothing to remove
+}
+
+/*
+ Free query from query cache.
+ query_block must be locked for writing.
+ This function will remove (and destroy) the lock for the query.
+*/
+
+void Query_cache::free_query(Query_cache_block *query_block)
+{
+ DBUG_ENTER("Query_cache::free_query");
+ DBUG_PRINT("qcache", ("free query 0x%lx %lu bytes result",
+ (ulong) query_block,
+ query_block->query()->length() ));
+
+ queries_in_cache--;
+ hash_delete(&queries,(byte *) query_block);
+
+ Query_cache_query *query = query_block->query();
+
+ if (query->writer() != 0)
+ {
+ /* Tell MySQL that this query should not be cached anymore */
+ query->writer()->query_cache_query = 0;
+ query->writer(0);
+ }
+ double_linked_list_exclude(query_block, &queries_blocks);
+ Query_cache_block_table *table=query_block->table(0);
+
+ for (TABLE_COUNTER_TYPE i=0; i < query_block->n_tables; i++)
+ unlink_table(table++);
+ Query_cache_block *result_block = query->result();
+
+ /*
+ The following is true when query destruction was called and no results
+ in query . (query just registered and then abort/pack/flush called)
+ */
+ if (result_block != 0)
+ {
+ Query_cache_block *block = result_block;
+ do
+ {
+ Query_cache_block *current = block;
+ block = block->next;
+ free_memory_block(current);
+ } while (block != result_block);
+ }
+
+ query->unlock_n_destroy();
+ free_memory_block(query_block);
+
+ DBUG_VOID_RETURN;
+}
+
+/*****************************************************************************
+ Query data creation
+*****************************************************************************/
+
+Query_cache_block *
+Query_cache::write_block_data(ulong data_len, gptr data,
+ ulong header_len,
+ Query_cache_block::block_type type,
+ TABLE_COUNTER_TYPE ntab,
+ my_bool under_guard)
+{
+ ulong all_headers_len = (ALIGN_SIZE(sizeof(Query_cache_block)) +
+ ALIGN_SIZE(ntab*sizeof(Query_cache_block_table)) +
+ header_len);
+ ulong len = data_len + all_headers_len;
+ DBUG_ENTER("Query_cache::write_block_data");
+ DBUG_PRINT("qcache", ("data: %ld, header: %ld, all header: %ld",
+ data_len, header_len, all_headers_len));
+ Query_cache_block *block = allocate_block(max(len, min_allocation_unit),
+ 1, 0, under_guard);
+ if (block != 0)
+ {
+ block->type = type;
+ block->n_tables = ntab;
+ block->used = len;
+
+ memcpy((void*) (((byte *) block)+ all_headers_len),
+ (void*) data, data_len);
+ }
+ DBUG_RETURN(block);
+}
+
+
+/*
+ On success STRUCT_UNLOCK(&query_cache.structure_guard_mutex) will be done.
+*/
+
+my_bool
+Query_cache::append_result_data(Query_cache_block **current_block,
+ ulong data_len, gptr data,
+ Query_cache_block *query_block)
+{
+ DBUG_ENTER("Query_cache::append_result_data");
+ DBUG_PRINT("qcache", ("append %lu bytes to 0x%lx query",
+ data_len, query_block));
+
+ if (query_block->query()->add(data_len) > query_cache_limit)
+ {
+ DBUG_PRINT("qcache", ("size limit reached %lu > %lu",
+ query_block->query()->length(),
+ query_cache_limit));
+ DBUG_RETURN(0);
+ }
+ if (*current_block == 0)
+ {
+ DBUG_PRINT("qcache", ("allocated first result data block %lu", data_len));
+ /*
+ STRUCT_UNLOCK(&structure_guard_mutex) Will be done by
+ write_result_data if success;
+ */
+ DBUG_RETURN(write_result_data(current_block, data_len, data, query_block,
+ Query_cache_block::RES_BEG));
+ }
+ Query_cache_block *last_block = (*current_block)->prev;
+
+ DBUG_PRINT("qcache", ("lastblock 0x%lx len %lu used %lu",
+ (ulong) last_block, last_block->length,
+ last_block->used));
+ my_bool success = 1;
+ ulong last_block_free_space= last_block->length - last_block->used;
+
+ /*
+ We will first allocate and write the 'tail' of data, that doesn't fit
+ in the 'last_block'. Only if this succeeds, we will fill the last_block.
+ This saves us a memcpy if the query doesn't fit in the query cache.
+ */
+
+ // Try join blocks if physically next block is free...
+ ulong tail = data_len - last_block_free_space;
+ ulong append_min = get_min_append_result_data_size();
+ if (last_block_free_space < data_len &&
+ append_next_free_block(last_block,
+ max(tail, append_min)))
+ last_block_free_space = last_block->length - last_block->used;
+ // If no space in last block (even after join) allocate new block
+ if (last_block_free_space < data_len)
+ {
+ DBUG_PRINT("qcache", ("allocate new block for %lu bytes",
+ data_len-last_block_free_space));
+ Query_cache_block *new_block = 0;
+ /*
+ On success STRUCT_UNLOCK(&structure_guard_mutex) will be done
+ by the next call
+ */
+ success = write_result_data(&new_block, data_len-last_block_free_space,
+ (gptr)(((byte*)data)+last_block_free_space),
+ query_block,
+ Query_cache_block::RES_CONT);
+ /*
+ new_block may be != 0 even !success (if write_result_data
+ allocate a small block but failed to allocate continue)
+ */
+ if (new_block != 0)
+ double_linked_list_join(last_block, new_block);
+ }
+ else
+ {
+ // It is success (nobody can prevent us write data)
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ }
+
+ // Now finally write data to the last block
+ if (success && last_block_free_space > 0)
+ {
+ ulong to_copy = min(data_len,last_block_free_space);
+ DBUG_PRINT("qcache", ("use free space %lub at block 0x%lx to copy %lub",
+ last_block_free_space, (ulong)last_block, to_copy));
+ memcpy((void*) (((byte*) last_block) + last_block->used), (void*) data,
+ to_copy);
+ last_block->used+=to_copy;
+ }
+ DBUG_RETURN(success);
+}
+
+
+my_bool Query_cache::write_result_data(Query_cache_block **result_block,
+ ulong data_len, gptr data,
+ Query_cache_block *query_block,
+ Query_cache_block::block_type type)
+{
+ DBUG_ENTER("Query_cache::write_result_data");
+ DBUG_PRINT("qcache", ("data_len %lu",data_len));
+
+ /*
+ Reserve block(s) for filling
+ During data allocation we must have structure_guard_mutex locked.
+ As data copy is not a fast operation, it's better if we don't have
+ structure_guard_mutex locked during data coping.
+ Thus we first allocate space and lock query, then unlock
+ structure_guard_mutex and copy data.
+ */
+
+ my_bool success = allocate_data_chain(result_block, data_len, query_block,
+ type == Query_cache_block::RES_BEG);
+ if (success)
+ {
+ // It is success (nobody can prevent us write data)
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ byte *rest = (byte*) data;
+ Query_cache_block *block = *result_block;
+ uint headers_len = (ALIGN_SIZE(sizeof(Query_cache_block)) +
+ ALIGN_SIZE(sizeof(Query_cache_result)));
+ // Now fill list of blocks that created by allocate_data_chain
+ do
+ {
+ block->type = type;
+ ulong length = block->used - headers_len;
+ DBUG_PRINT("qcache", ("write %lu byte in block 0x%lx",length,
+ (ulong)block));
+ memcpy((void*)(((byte*) block)+headers_len), (void*) rest, length);
+ rest += length;
+ block = block->next;
+ type = Query_cache_block::RES_CONT;
+ } while (block != *result_block);
+ }
+ else
+ {
+ if (*result_block != 0)
+ {
+ // Destroy list of blocks that was created & locked by lock_result_data
+ Query_cache_block *block = *result_block;
+ do
+ {
+ Query_cache_block *current = block;
+ block = block->next;
+ free_memory_block(current);
+ } while (block != *result_block);
+ *result_block = 0;
+ /*
+ It is not success => not unlock structure_guard_mutex (we need it to
+ free query)
+ */
+ }
+ }
+ DBUG_PRINT("qcache", ("success %d", (int) success));
+ DBUG_RETURN(success);
+}
+
+inline ulong Query_cache::get_min_first_result_data_size()
+{
+ if (queries_in_cache < QUERY_CACHE_MIN_ESTIMATED_QUERIES_NUMBER)
+ return min_result_data_size;
+ ulong avg_result = (query_cache_size - free_memory) / queries_in_cache;
+ avg_result = min(avg_result, query_cache_limit);
+ return max(min_result_data_size, avg_result);
+}
+
+inline ulong Query_cache::get_min_append_result_data_size()
+{
+ return min_result_data_size;
+}
+
+/*
+ Allocate one or more blocks to hold data
+*/
+
+my_bool Query_cache::allocate_data_chain(Query_cache_block **result_block,
+ ulong data_len,
+ Query_cache_block *query_block,
+ my_bool first_block)
+{
+ ulong all_headers_len = (ALIGN_SIZE(sizeof(Query_cache_block)) +
+ ALIGN_SIZE(sizeof(Query_cache_result)));
+ ulong len = data_len + all_headers_len;
+ DBUG_ENTER("Query_cache::allocate_data_chain");
+ DBUG_PRINT("qcache", ("data_len %lu, all_headers_len %lu",
+ data_len, all_headers_len));
+
+ ulong min_size = (first_block ?
+ get_min_first_result_data_size():
+ get_min_append_result_data_size());
+ *result_block = allocate_block(max(min_size,len),
+ min_result_data_size == 0,
+ all_headers_len + min_result_data_size,
+ 1);
+ my_bool success = (*result_block != 0);
+ if (success)
+ {
+ Query_cache_block *new_block= *result_block;
+ new_block->n_tables = 0;
+ new_block->used = 0;
+ new_block->type = Query_cache_block::RES_INCOMPLETE;
+ new_block->next = new_block->prev = new_block;
+ Query_cache_result *header = new_block->result();
+ header->parent(query_block);
+
+ if (new_block->length < len)
+ {
+ /*
+ We got less memory then we need (no big memory blocks) =>
+ Continue to allocated more blocks until we got everything we need.
+ */
+ Query_cache_block *next_block;
+ if ((success = allocate_data_chain(&next_block,
+ len - new_block->length,
+ query_block, first_block)))
+ double_linked_list_join(new_block, next_block);
+ }
+ if (success)
+ {
+ new_block->used = min(len, new_block->length);
+
+ DBUG_PRINT("qcache", ("Block len %lu used %lu",
+ new_block->length, new_block->used));
+ }
+ else
+ DBUG_PRINT("warning", ("Can't allocate block for continue"));
+ }
+ else
+ DBUG_PRINT("warning", ("Can't allocate block for results"));
+ DBUG_RETURN(success);
+}
+
+/*****************************************************************************
+ Tables management
+*****************************************************************************/
+
+/*
+ Invalidate the first table in the table_list
+*/
+
+void Query_cache::invalidate_table(TABLE_LIST *table_list)
+{
+ if (table_list->table != 0)
+ invalidate_table(table_list->table); // Table is open
+ else
+ {
+ char key[MAX_DBKEY_LENGTH];
+ uint key_length;
+ Query_cache_block *table_block;
+ key_length=(uint) (strmov(strmov(key,table_list->db)+1,
+ table_list->real_name) -key)+ 1;
+
+ // We don't store temporary tables => no key_length+=4 ...
+ if ((table_block = (Query_cache_block*)
+ hash_search(&tables,(byte*) key,key_length)))
+ invalidate_table(table_block);
+ }
}
-/* At the moment we do not really want to do anything upon delete */
-static void free_cache_entry(void *entry)
+void Query_cache::invalidate_table(TABLE *table)
{
+ Query_cache_block *table_block;
+ if ((table_block = ((Query_cache_block*)
+ hash_search(&tables, (byte*) table->table_cache_key,
+ table->key_length))))
+ invalidate_table(table_block);
}
-/* Initialization of the SQL cache hash -- should be called during
- the bootstrap stage */
-bool sql_cache_init(void)
+void Query_cache::invalidate_table(Query_cache_block *table_block)
{
- if (query_buff_size)
+ Query_cache_block_table *list_root = table_block->table(0);
+ while (list_root->next != list_root)
{
- VOID(hash_init(&sql_cache, 4096, 0, 0,
- cache_key,
- (void (*)(void*)) free_cache_entry,
- 0));
+ Query_cache_block *query_block = list_root->next->block();
+ BLOCK_LOCK_WR(query_block);
+ free_query(query_block);
}
- return 0;
}
-/* Clearing the SQL cache hash -- during shutdown */
-void sql_cache_free(void)
+
+my_bool Query_cache::register_all_tables(Query_cache_block *block,
+ TABLE_LIST *tables_used,
+ TABLE_COUNTER_TYPE tables)
{
- hash_free(&sql_cache);
+ TABLE_COUNTER_TYPE n;
+ DBUG_PRINT("qcache", ("register tables block 0x%lx, n %d, header %x",
+ (ulong) block, (int) tables,
+ (int) ALIGN_SIZE(sizeof(Query_cache_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,
+ Query_cache_table::type_convertion(tables_used->table->
+ db_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];
+ uint key_length =filename_2_table_key(key, table->table->filename);
+ (++block_table)->n= ++n;
+ if (!insert_table(key_length, key, block_table,
+ Query_cache_table::type_convertion(DB_TYPE_MYISAM)))
+ goto err;
+ }
+ }
+ }
+
+err:
+ if (tables_used)
+ {
+ DBUG_PRINT("qcache", ("failed at table %d", (int) n));
+ /* Unlink the tables we allocated above */
+ for (Query_cache_block_table *tmp = block->table(0) ;
+ tmp != block_table;
+ tmp++)
+ unlink_table(tmp);
+ }
+ return (tables_used == 0);
}
-/* Finds whether the SQL command is already in the cache, at any case
- establishes correct LEX structure in the THD (either from
- cache or a new one) */
+/*
+ Insert used tablename in cache
+ Returns 0 on error
+*/
-int sql_cache_hit(THD *thd, char *sql, uint length)
+my_bool
+Query_cache::insert_table(uint key_len, char *key,
+ Query_cache_block_table *node,
+ Query_cache_table::query_cache_table_type type)
{
-#ifdef QQ
- LEX *ptr;
- ptr = (LEX *)hash_search(&sql_cache, sql, length);
- if (ptr) {
- fprintf(stderr, "Query `%s' -- hit in the cache (%p)\n", ptr->sql_query_text, ptr);
- thd->lex_ptr = ptr;
- ptr->thd = thd;
- } else {
- thd->lex_ptr = ptr = lex_array + last_lex_array_item--;
+ DBUG_ENTER("Query_cache::insert_table");
+ DBUG_PRINT("qcache", ("insert table node 0x%lx, len %d",
+ (ulong)node, key_len));
+
+ Query_cache_block *table_block = ((Query_cache_block *)
+ hash_search(&tables, (byte*) key,
+ key_len));
+
+ if (table_block == 0)
+ {
+ DBUG_PRINT("qcache", ("new table block from 0x%lx (%u)",
+ (ulong) key, (int) key_len));
+ table_block = write_block_data(key_len, (gptr) key,
+ ALIGN_SIZE(sizeof(Query_cache_table)),
+ Query_cache_block::TABLE,
+ 1, 1);
+ if (table_block == 0)
+ {
+ DBUG_PRINT("qcache", ("Can't write table name to cache"));
+ DBUG_RETURN(0);
+ }
+ Query_cache_table *header = table_block->table();
+ header->type(type);
+ double_linked_list_simple_include(table_block,
+ &tables_blocks[type]);
+ Query_cache_block_table *list_root = table_block->table(0);
+ list_root->n = 0;
+ list_root->next = list_root->prev = list_root;
+ if (hash_insert(&tables, (const byte *) table_block))
+ {
+ DBUG_PRINT("qcache", ("Can't insert table to hash"));
+ // write_block_data return locked block
+ free_memory_block(table_block);
+ DBUG_RETURN(0);
+ }
+ char *db = header->db();
+ header->table(db + strlen(db) + 1);
+ }
+
+ Query_cache_block_table *list_root = table_block->table(0);
+ node->next = list_root->next;
+ list_root->next = node;
+ node->next->prev = node;
+ node->prev = list_root;
+ node->parent = table_block->table();
+ DBUG_RETURN(1);
+}
+
+
+void Query_cache::unlink_table(Query_cache_block_table *node)
+{
+ DBUG_ENTER("Query_cache::unlink_table");
+ node->prev->next = node->next;
+ node->next->prev = node->prev;
+ Query_cache_block_table *neighbour = node->next;
+ if (neighbour->next == neighbour)
+ {
+ // list is empty (neighbor is root of list)
+ Query_cache_block *table_block = neighbour->block();
+ double_linked_list_exclude(table_block,
+ &tables_blocks[table_block->table()->type()]);
+ hash_delete(&tables,(byte *) table_block);
+ free_memory_block(table_block);
+ }
+ DBUG_VOID_RETURN;
+}
+
+/*****************************************************************************
+ Free memory management
+*****************************************************************************/
+
+Query_cache_block *
+Query_cache::allocate_block(ulong len, my_bool not_less, ulong min,
+ my_bool under_guard)
+{
+ DBUG_ENTER("Query_cache::allocate_n_lock_block");
+ DBUG_PRINT("qcache", ("len %lu, not less %d, min %lu, uder_guard %d",
+ len, not_less,min,under_guard));
+
+ if (len >= min(query_cache_size, query_cache_limit))
+ {
+ DBUG_PRINT("qcache", ("Query cache hase only %lu memory and limit %lu",
+ query_cache_size, query_cache_limit));
+ DBUG_RETURN(0); // in any case we don't have such piece of memory
+ }
+
+ if (!under_guard)
+ STRUCT_LOCK(&structure_guard_mutex);
+
+ /* Free old queries until we have enough memory to store this block */
+ Query_cache_block *block;
+ do
+ {
+ block= get_free_block(len, not_less, min);
+ }
+ while (block == 0 && !free_old_query());
+
+ if (block != 0) // If we found a suitable block
+ {
+ if (block->length >= ALIGN_SIZE(len) + min_allocation_unit)
+ split_block(block,ALIGN_SIZE(len));
+ }
- lex_start(thd, (uchar *)sql, length);
+ if (!under_guard)
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_RETURN(block);
+}
+
+
+Query_cache_block *
+Query_cache::get_free_block(ulong len, my_bool not_less, ulong min)
+{
+ Query_cache_block *block = 0, *first = 0;
+ DBUG_ENTER("Query_cache::get_free_block");
+ DBUG_PRINT("qcache",("length %lu, not_less %d, min %lu", len,
+ (int)not_less, min));
- if (hash_insert(&sql_cache, (const byte *)ptr)) {
- fprintf(stderr, "Out of memory during hash_insert?\n");
+ /* Find block with minimal size > len */
+ uint start = find_bin(len);
+ // try matching bin
+ if (bins[start].number != 0)
+ {
+ Query_cache_block *list = bins[start].free_blocks;
+ ulong max_len = list->prev->length;
+ if (list->prev->length >= len) // check block with max size
+ {
+ first = list;
+ uint n = 0;
+ while ( n < QUERY_CACHE_MEM_BIN_TRY &&
+ first->length < len) //we don't need irst->next != list
+ {
+ first=first->next;
+ n++;
+ }
+ if (first->length >= len)
+ block=first;
+ else // we don't need if (first->next != list)
+ {
+ n = 0;
+ block = list->prev;
+ while (n < QUERY_CACHE_MEM_BIN_TRY &&
+ block->length > len)
+ {
+ block=block->prev;
+ n++;
+ }
+ if(block->length < len)
+ block=block->next;
+ }
}
- fprintf(stderr, "Query `%s' not found in the cache -- insert %p from slot %d\n", thd->lex_ptr->ptr, ptr, last_lex_array_item+1);
- if (!hash_search(&sql_cache, sql, length)) {
- fprintf(stderr, "I just enterred a hash key but it's not where -- what's that?\n");
- } else {
- fprintf(stderr, "Inserted to cache\n");
+ else
+ first = list->prev;
+ }
+ if (block == 0 && start > 0)
+ {
+ DBUG_PRINT("qcache",("Try bins with bigger block size"));
+ // Try more big bins
+ int i = start - 1;
+ while (i > 0 && bins[i].number == 0)
+ i--;
+ if (bins[i].number > 0)
+ block = bins[i].free_blocks;
+ }
+
+ // If no big blocks => try less size (if it is possible)
+ if (block == 0 && ! not_less)
+ {
+ DBUG_PRINT("qcache",("Try to allocate a smaller block"));
+ if (first != 0 && first->length > min)
+ block = first;
+ else
+ {
+ uint i = start + 1;
+ /* bins[mem_bin_num].number contains 1 for easy end test */
+ for (i= start+1 ; bins[i].number == 0 ; i++) ;
+ if (i < mem_bin_num && bins[i].free_blocks->prev->length >= min)
+ block = bins[i].free_blocks->prev;
}
- return 0;
}
+ if (block != 0)
+ exclude_from_free_memory_list(block);
+
+ DBUG_PRINT("qcache",("getting block 0x%lx", (ulong) block));
+ DBUG_RETURN(block);
+}
+
+
+void Query_cache::free_memory_block(Query_cache_block *block)
+{
+ DBUG_ENTER("Query_cache::free_memory_block");
+ block->used=0;
+ DBUG_PRINT("qcache",("first_block 0x%lx, block 0x%lx, pnext 0x%lx pprev 0x%lx",
+ (ulong) first_block, (ulong) block,block->pnext,
+ (ulong) block->pprev));
+
+ if (block->pnext != first_block && block->pnext->is_free())
+ block = join_free_blocks(block, block->pnext);
+ if (block != first_block && block->pprev->is_free())
+ block = join_free_blocks(block->pprev, block->pprev);
+ insert_into_free_memory_list(block);
+ DBUG_VOID_RETURN;
+}
+
+
+void Query_cache::split_block(Query_cache_block *block, ulong len)
+{
+ DBUG_ENTER("Query_cache::split_block");
+ Query_cache_block *new_block = (Query_cache_block*)(((byte*) block)+len);
+
+ new_block->init(block->length - len);
+ total_blocks++;
+ block->length=len;
+ new_block->pnext = block->pnext;
+ block->pnext = new_block;
+ new_block->pprev = block;
+ new_block->pnext->pprev = new_block;
+
+ if (block->type == Query_cache_block::FREE)
+ // if block was free then it already joined with all free neighbours
+ insert_into_free_memory_list(new_block);
+ else
+ free_memory_block(new_block);
+
+ DBUG_PRINT("qcache", ("split 0x%lx (%lu) new 0x%lx",
+ (ulong) block, len, (ulong) new_block));
+ DBUG_VOID_RETURN;
+}
+
+
+Query_cache_block *
+Query_cache::join_free_blocks(Query_cache_block *first_block,
+ Query_cache_block *block_in_list)
+{
+ Query_cache_block *second_block;
+ DBUG_ENTER("Query_cache::join_free_blocks");
+ DBUG_PRINT("qcache",
+ ("join first 0x%lx, pnext 0x%lx, in list 0x%lx",
+ (ulong) first_block, (ulong) first_block->pnext,
+ (ulong) block_in_list));
+
+ exclude_from_free_memory_list(block_in_list);
+ second_block = first_block->pnext;
+ // May be was not free block
+ second_block->used=0;
+ second_block->destroy();
+ total_blocks--;
+
+ first_block->length += second_block->length;
+ first_block->pnext = second_block->pnext;
+ second_block->pnext->pprev = first_block;
+
+ DBUG_RETURN(first_block);
+}
+
+
+my_bool Query_cache::append_next_free_block(Query_cache_block *block,
+ ulong add_size)
+{
+ Query_cache_block *next_block = block->pnext;
+ DBUG_ENTER("Query_cache::append_next_free_block");
+ DBUG_PRINT("enter", ("block 0x%lx, add_size %lu", (ulong) block,
+ add_size));
+
+ if (next_block != first_block && next_block->is_free())
+ {
+ ulong old_len = block->length;
+ exclude_from_free_memory_list(next_block);
+ next_block->destroy();
+ total_blocks--;
+
+ block->length += next_block->length;
+ block->pnext = next_block->pnext;
+ next_block->pnext->pprev = block;
+
+ if (block->length > ALIGN_SIZE(old_len + add_size) + min_allocation_unit)
+ split_block(block,ALIGN_SIZE(old_len + add_size));
+ DBUG_PRINT("exit", ("block was appended"));
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+void Query_cache::exclude_from_free_memory_list(Query_cache_block *free_block)
+{
+ DBUG_ENTER("Query_cache::exclude_from_free_memory_list");
+ Query_cache_memory_bin *bin = *((Query_cache_memory_bin **)
+ free_block->data());
+ double_linked_list_exclude(free_block, &bin->free_blocks);
+ bin->number--;
+ free_memory-=free_block->length;
+ free_memory_blocks--;
+ DBUG_PRINT("qcache",("exclude block 0x%lx, bin 0x%lx", (ulong) free_block,
+ (ulong) bin));
+ DBUG_VOID_RETURN;
+}
+
+void Query_cache::insert_into_free_memory_list(Query_cache_block *free_block)
+{
+ DBUG_ENTER("Query_cache::insert_into_free_memory_list");
+ uint idx = find_bin(free_block->length);
+ insert_into_free_memory_sorted_list(free_block, &bins[idx].free_blocks);
+ /*
+ We have enough memory in block for storing bin reference due to
+ min_allocation_unit choice
+ */
+ Query_cache_memory_bin **bin_ptr = ((Query_cache_memory_bin**)
+ free_block->data());
+ *bin_ptr = bins+idx;
+ (*bin_ptr)->number++;
+ DBUG_PRINT("qcache",("insert block 0x%lx, bin[%d] 0x%lx",
+ (ulong) free_block, idx, (ulong) *bin_ptr));
+ DBUG_VOID_RETURN;
+}
+
+uint Query_cache::find_bin(ulong size)
+{
+ DBUG_ENTER("Query_cache::find_bin");
+ // Binary search
+ int left = 0, right = mem_bin_steps;
+ do
+ {
+ int middle = (left + right) / 2;
+ if (steps[middle].size > size)
+ left = middle+1;
+ else
+ right = middle;
+ } while (left < right);
+ if (left == 0)
+ {
+ // first bin not subordinate of common rules
+ DBUG_PRINT("qcache", ("first bin (# 0), size %lu",size));
+ DBUG_RETURN(0);
+ }
+ uint bin = steps[left].idx -
+ (uint)((size - steps[left].size)/steps[left].increment);
+#ifndef DBUG_OFF
+ bins_dump();
#endif
- return 1;
+ DBUG_PRINT("qcache", ("bin %u step %u, size %lu step size %lu",
+ bin, left, size, steps[left].size));
+ DBUG_RETURN(bin);
+}
+
+
+/*****************************************************************************
+ Lists management
+*****************************************************************************/
+
+void Query_cache::move_to_query_list_end(Query_cache_block *query_block)
+{
+ DBUG_ENTER("Query_cache::move_to_query_list_end");
+ double_linked_list_exclude(query_block, &queries_blocks);
+ double_linked_list_simple_include(query_block, &queries_blocks);
+ DBUG_VOID_RETURN;
+}
+
+
+void Query_cache::insert_into_free_memory_sorted_list(Query_cache_block *
+ new_block,
+ Query_cache_block **
+ list)
+{
+ DBUG_ENTER("Query_cache::insert_into_free_memory_sorted_list");
+ /*
+ list sorted by size in ascendant order, because we need small blocks
+ more frequently than bigger ones
+ */
+
+ new_block->used = 0;
+ new_block->n_tables = 0;
+ new_block->type = Query_cache_block::FREE;
+
+ if (*list == 0)
+ {
+ *list = new_block->next=new_block->prev=new_block;
+ DBUG_PRINT("qcache", ("inserted into empty list"));
+ }
+ else
+ {
+ Query_cache_block *point = *list;
+ if (point->length >= new_block->length)
+ {
+ point = point->prev;
+ *list = new_block;
+ }
+ else
+ {
+ /* Find right position in sorted list to put block */
+ while (point->next != *list &&
+ point->next->length < new_block->length)
+ point=point->next;
+ }
+ new_block->prev = point;
+ new_block->next = point->next;
+ new_block->next->prev = new_block;
+ point->next = new_block;
+ }
+ free_memory+=new_block->length;
+ free_memory_blocks++;
+ DBUG_VOID_RETURN;
}
+
+
+void
+Query_cache::double_linked_list_simple_include(Query_cache_block *point,
+ Query_cache_block **
+ list_pointer)
+{
+ DBUG_ENTER("Query_cache::double_linked_list_simple_include");
+ DBUG_PRINT("qcache", ("including block 0x%lx", (ulong) point));
+ if (*list_pointer == 0)
+ *list_pointer=point->next=point->prev=point;
+ else
+ {
+ // insert to and of list
+ point->next = (*list_pointer);
+ point->prev = (*list_pointer)->prev;
+ point->prev->next = point;
+ (*list_pointer)->prev = point;
+ }
+ DBUG_VOID_RETURN;
+}
+
+void
+Query_cache::double_linked_list_exclude(Query_cache_block *point,
+ Query_cache_block **list_pointer)
+{
+ DBUG_ENTER("Query_cache::double_linked_list_exclude");
+ DBUG_PRINT("qcache", ("excluding block 0x%lx, list 0x%lx",
+ (ulong) point, (ulong) list_pointer));
+ if (point->next == point)
+ *list_pointer = 0; // empty list
+ else
+ {
+ point->next->prev = point->prev;
+ point->prev->next = point->next;
+ if (point == *list_pointer)
+ *list_pointer = point->next;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+void Query_cache::double_linked_list_join(Query_cache_block *head_tail,
+ Query_cache_block *tail_head)
+{
+ Query_cache_block *head_head = head_tail->next,
+ *tail_tail = tail_head->prev;
+ head_head->prev = tail_tail;
+ head_tail->next = tail_head;
+ tail_head->prev = head_tail;
+ tail_tail->next = head_head;
+}
+
+/*****************************************************************************
+ Query
+*****************************************************************************/
+
+/*
+ If query is cacheable return number tables in query
+ (query without tables are not cached)
+*/
+
+TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len,
+ char *query,
+ LEX *lex, TABLE_LIST *tables_used)
+{
+ TABLE_COUNTER_TYPE tables = 0;
+ DBUG_ENTER("Query_cache::is_cacheable");
+
+ if (lex->sql_command == SQLCOM_SELECT &&
+ thd->temporary_tables == 0 &&
+ (thd->query_cache_type == 1 ||
+ (thd->query_cache_type == 2 && (lex->select->options &
+ OPTION_TO_QUERY_CACHE))) &&
+ thd->safe_to_cache_query)
+ {
+ my_bool has_transactions = 0;
+ DBUG_PRINT("qcache", ("options %lx %lx, type %u",
+ OPTION_TO_QUERY_CACHE,
+ lex->select->options,
+ (int) thd->query_cache_type));
+
+ for (; tables_used; tables_used=tables_used->next)
+ {
+ tables++;
+ DBUG_PRINT("qcache", ("table %s, db %s, type %u",
+ tables_used->real_name,
+ tables_used->db, tables_used->table->db_type));
+ has_transactions = (has_transactions ||
+ tables_used->table->file->has_transactions());
+
+ if (tables_used->table->db_type == DB_TYPE_MRG_ISAM)
+ {
+ DBUG_PRINT("qcache", ("select not cacheable: used MRG_ISAM 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();
+ tables+= (file->end_table - file->open_tables);
+ }
+ }
+
+ if ((thd->options & (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN)) &&
+ has_transactions)
+ {
+ DBUG_PRINT("qcache", ("not in autocommin mode"));
+ DBUG_RETURN(0);
+ }
+ DBUG_PRINT("qcache", ("select is using %d tables", tables));
+ DBUG_RETURN(tables);
+ }
+
+ DBUG_PRINT("qcache",
+ ("not interesting query: %d or not cacheable, options %lx %lx, type %u",
+ (int) lex->sql_command,
+ OPTION_TO_QUERY_CACHE,
+ lex->select->options,
+ (int) thd->query_cache_type));
+ DBUG_RETURN(0);
+}
+
+
+/*****************************************************************************
+ Packing
+*****************************************************************************/
+
+void Query_cache::pack_cache()
+{
+ DBUG_ENTER("Query_cache::pack_cache");
+ STRUCT_LOCK(&structure_guard_mutex);
+ DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
+
+ byte *border = 0;
+ Query_cache_block *before = 0;
+ ulong gap = 0;
+ my_bool ok = 1;
+ Query_cache_block *block = first_block;
+ DUMP(this);
+
+ if (first_block)
+ {
+ do
+ {
+ Query_cache_block *next=block->pnext;
+ ok = move_by_type(&border, &before, &gap, block);
+ block = next;
+ } while (ok && block != first_block);
+
+ if (border != 0)
+ {
+ Query_cache_block *new_block = (Query_cache_block *) border;
+ new_block->init(gap);
+ total_blocks++;
+ new_block->pnext = before->pnext;
+ before->pnext = new_block;
+ new_block->pprev = before;
+ new_block->pnext->pprev = new_block;
+ insert_into_free_memory_list(new_block);
+ }
+ DUMP(this);
+ }
+
+ DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_VOID_RETURN;
+}
+
+
+my_bool Query_cache::move_by_type(byte **border,
+ Query_cache_block **before, ulong *gap,
+ Query_cache_block *block)
+{
+ DBUG_ENTER("Query_cache::move_by_type");
+
+ my_bool ok = 1;
+ switch (block->type) {
+ case Query_cache_block::FREE:
+ {
+ DBUG_PRINT("qcache", ("block 0x%lx FREE", (ulong) block));
+ if (*border == 0)
+ {
+ *border = (byte *) block;
+ *before = block->pprev;
+ DBUG_PRINT("qcache", ("gap beginning here"));
+ }
+ exclude_from_free_memory_list(block);
+ *gap +=block->length;
+ block->pprev->pnext=block->pnext;
+ block->pnext->pprev=block->pprev;
+ block->destroy();
+ total_blocks--;
+ DBUG_PRINT("qcache", ("added to gap (%lu)", *gap));
+ break;
+ }
+ case Query_cache_block::TABLE:
+ {
+ DBUG_PRINT("qcache", ("block 0x%lx TABLE", (ulong) block));
+ if (*border == 0)
+ break;
+ ulong len = block->length, used = block->used;
+ Query_cache_block_table *list_root = block->table(0);
+ Query_cache_block_table *tprev = list_root->prev,
+ *tnext = list_root->next;
+ Query_cache_block *prev = block->prev,
+ *next = block->next,
+ *pprev = block->pprev,
+ *pnext = block->pnext,
+ *new_block =(Query_cache_block *) *border;
+ uint tablename_offset = block->table()->table() - block->table()->db();
+ char *data = (char*) block->data();
+ byte *key;
+ uint key_length;
+ key=query_cache_table_get_key((byte*) block, &key_length, 0);
+ hash_search(&tables, (byte*) key, key_length);
+
+ block->destroy();
+ new_block->init(len);
+ new_block->type=Query_cache_block::TABLE;
+ new_block->used=used;
+ new_block->n_tables=1;
+ memmove((char*) new_block->data(), data, len-new_block->headers_len());
+ relink(block, new_block, next, prev, pnext, pprev);
+ if (tables_blocks[new_block->table()->type()] == block)
+ tables_blocks[new_block->table()->type()] = new_block;
+
+ Query_cache_block_table *nlist_root = new_block->table(0);
+ nlist_root->n = 0;
+ nlist_root->next = tnext;
+ tnext->prev = nlist_root;
+ nlist_root->prev = tprev;
+ tprev->next = nlist_root;
+ DBUG_PRINT("qcache",
+ ("list_root: 0x%lx tnext 0x%lx tprev 0x%lx tprev->next 0x%lx tnext->prev 0x%lx",
+ (ulong) list_root, (ulong) tnext, (ulong) tprev,
+ (ulong)tprev->next, (ulong)tnext->prev));
+ /*
+ Go through all queries that uses this table and change them to
+ point to the new table object
+ */
+ Query_cache_table *new_block_table=new_block->table();
+ for (;tnext != nlist_root; tnext=tnext->next)
+ tnext->parent= new_block_table;
+ *border += len;
+ *before = new_block;
+ /* Fix pointer to table name */
+ new_block->table()->table(new_block->table()->db() + tablename_offset);
+ /* Fix hash to point at moved block */
+ hash_replace(&tables, tables.current_record, (byte*) new_block);
+
+ DBUG_PRINT("qcache", ("moved %lu bytes to 0x%lx, new gap at 0x%lx",
+ len, (ulong) new_block, (ulong) *border));
+ break;
+ }
+ case Query_cache_block::QUERY:
+ {
+ DBUG_PRINT("qcache", ("block 0x%lx QUERY", (ulong) block));
+ if (*border == 0)
+ break;
+ BLOCK_LOCK_WR(block);
+ ulong len = block->length, used = block->used;
+ TABLE_COUNTER_TYPE n_tables = block->n_tables;
+ Query_cache_block *prev = block->prev,
+ *next = block->next,
+ *pprev = block->pprev,
+ *pnext = block->pnext,
+ *new_block =(Query_cache_block*) *border;
+ char *data = (char*) block->data();
+ Query_cache_block *first_result_block = ((Query_cache_query *)
+ block->data())->result();
+ byte *key;
+ uint key_length;
+ key=query_cache_query_get_key((byte*) block, &key_length, 0);
+ hash_search(&queries, (byte*) key, key_length);
+ // Move table of used tables
+ memmove((char*) new_block->table(0), (char*) block->table(0),
+ ALIGN_SIZE(n_tables*sizeof(Query_cache_block_table)));
+ block->query()->unlock_n_destroy();
+ block->destroy();
+ new_block->init(len);
+ new_block->type=Query_cache_block::QUERY;
+ new_block->used=used;
+ new_block->n_tables=n_tables;
+ memmove((char*) new_block->data(), data, len - new_block->headers_len());
+ relink(block, new_block, next, prev, pnext, pprev);
+ if (queries_blocks == block)
+ queries_blocks = new_block;
+ for (TABLE_COUNTER_TYPE j=0; j < n_tables; j++)
+ {
+ Query_cache_block_table *block_table = new_block->table(j);
+ block_table->next->prev = block_table;
+ block_table->prev->next = block_table;
+ }
+ DBUG_PRINT("qcache", ("after circle tt"));
+ *border += len;
+ *before = new_block;
+ new_block->query()->result(first_result_block);
+ if (first_result_block != 0)
+ {
+ Query_cache_block *result_block = first_result_block;
+ do
+ {
+ result_block->result()->parent(new_block);
+ result_block = result_block->next;
+ } while ( result_block != first_result_block );
+ }
+ Query_cache_query *new_query= ((Query_cache_query *) new_block->data());
+ sem_init(&new_query->lock, 0, 1);
+ pthread_mutex_init(&new_query->clients_guard,MY_MUTEX_INIT_FAST);
+
+ /*
+ If someone is writing to this block, inform the writer that the block
+ has been moved.
+ */
+ NET *net = new_block->query()->writer();
+ if (net != 0)
+ {
+ net->query_cache_query= (gptr) new_block;
+ }
+ /* Fix hash to point at moved block */
+ hash_replace(&queries, queries.current_record, (byte*) new_block);
+ DBUG_PRINT("qcache", ("moved %lu bytes to 0x%lx, new gap at 0x%lx",
+ len, (ulong) new_block, (ulong) *border));
+ break;
+ }
+ case Query_cache_block::RES_INCOMPLETE:
+ case Query_cache_block::RES_BEG:
+ case Query_cache_block::RES_CONT:
+ case Query_cache_block::RESULT:
+ {
+ DBUG_PRINT("qcache", ("block 0x%lx RES* (%d)", (ulong) block,
+ (int) block->type));
+ if (*border == 0)
+ break;
+ Query_cache_block *query_block = block->result()->parent(),
+ *next = block->next,
+ *prev = block->prev;
+ Query_cache_block::block_type type = block->type;
+ BLOCK_LOCK_WR(query_block);
+ ulong len = block->length, used = block->used;
+ Query_cache_block *pprev = block->pprev,
+ *pnext = block->pnext,
+ *new_block =(Query_cache_block*) *border;
+ char *data = (char*) block->data();
+ block->destroy();
+ new_block->init(len);
+ new_block->type=type;
+ new_block->used=used;
+ memmove((char*) new_block->data(), data, len - new_block->headers_len());
+ relink(block, new_block, next, prev, pnext, pprev);
+ new_block->result()->parent(query_block);
+ Query_cache_query *query = query_block->query();
+ if (query->result() == block)
+ query->result(new_block);
+ *border += len;
+ *before = new_block;
+ /* If result writing complete && we have free space in block */
+ ulong free_space = new_block->length - new_block->used;
+ if (query->result()->type == Query_cache_block::RESULT &&
+ new_block->length > new_block->used &&
+ *gap + free_space > min_allocation_unit &&
+ new_block->length - free_space > min_allocation_unit)
+ {
+ *border -= free_space;
+ *gap += free_space;
+ new_block->length -= free_space;
+ }
+ BLOCK_UNLOCK_WR(query_block);
+ DBUG_PRINT("qcache", ("moved %lu bytes to 0x%lx, new gap at 0x%lx",
+ len, (ulong) new_block, (ulong) *border));
+ break;
+ }
+ default:
+ DBUG_PRINT("error", ("unexpected block type %d, block 0x%lx",
+ (int)block->type, (ulong) block));
+ ok = 0;
+ }
+ DBUG_RETURN(ok);
+}
+
+
+void Query_cache::relink(Query_cache_block *oblock,
+ Query_cache_block *nblock,
+ Query_cache_block *next, Query_cache_block *prev,
+ Query_cache_block *pnext, Query_cache_block *pprev)
+{
+ if (prev == oblock) //check pointer to himself
+ {
+ nblock->prev = nblock;
+ nblock->next = nblock;
+ }
+ else
+ {
+ nblock->prev = prev;
+ prev->next=nblock;
+ }
+ if (next != oblock)
+ {
+ nblock->next = next;
+ next->prev=nblock;
+ }
+ nblock->pprev = pprev; // Physical pointer to himself have only 1 free block
+ nblock->pnext = pnext;
+ pprev->pnext=nblock;
+ pnext->pprev=nblock;
+}
+
+
+my_bool Query_cache::join_results(ulong join_limit)
+{
+ my_bool has_moving = 0;
+ DBUG_ENTER("Query_cache::join_results");
+
+ STRUCT_LOCK(&structure_guard_mutex);
+ if (queries_blocks != 0)
+ {
+ Query_cache_block *block = queries_blocks;
+ do
+ {
+ Query_cache_query *header = block->query();
+ if (header->result() != 0 &&
+ header->result()->type == Query_cache_block::RESULT &&
+ header->length() > join_limit)
+ {
+ Query_cache_block *new_result_block =
+ get_free_block(header->length() +
+ ALIGN_SIZE(sizeof(Query_cache_block)) +
+ ALIGN_SIZE(sizeof(Query_cache_result)), 1, 0);
+ if (new_result_block != 0)
+ {
+ has_moving = 1;
+ Query_cache_block *first_result = header->result();
+ ulong new_len = (header->length() +
+ ALIGN_SIZE(sizeof(Query_cache_block)) +
+ ALIGN_SIZE(sizeof(Query_cache_result)));
+ if (new_result_block->length >
+ ALIGN_SIZE(new_len) + min_allocation_unit)
+ split_block(new_result_block, ALIGN_SIZE(new_len));
+ BLOCK_LOCK_WR(block);
+ header->result(new_result_block);
+ new_result_block->type = Query_cache_block::RESULT;
+ new_result_block->n_tables = 0;
+ new_result_block->used = new_len;
+
+ new_result_block->next = new_result_block->prev = new_result_block;
+ DBUG_PRINT("qcache", ("new block %lu/%lu (%lu)",
+ new_result_block->length,
+ new_result_block->used,
+ header->length()));
+
+ Query_cache_result *new_result = new_result_block->result();
+ new_result->parent(block);
+ byte *write_to = (byte*) new_result->data();
+ Query_cache_block *result_block = first_result;
+ do
+ {
+ ulong len = (result_block->used - result_block->headers_len() -
+ ALIGN_SIZE(sizeof(Query_cache_result)));
+ DBUG_PRINT("loop", ("add block %lu/%lu (%lu)",
+ result_block->length,
+ result_block->used,
+ len));
+ memcpy((char *) write_to,
+ (char*) result_block->result()->data(),
+ len);
+ write_to += len;
+ Query_cache_block *old_result_block = result_block;
+ result_block = result_block->next;
+ free_memory_block(old_result_block);
+ } while (result_block != first_result);
+ BLOCK_UNLOCK_WR(block);
+ }
+ }
+ block = block->next;
+ } while ( block != queries_blocks );
+ }
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_RETURN(has_moving);
+}
+
+
+uint Query_cache::filename_2_table_key (char *key, const char *path)
+{
+ char tablename[FN_REFLEN+2], *filename, *dbname;
+ uint db_length;
+ DBUG_ENTER("Query_cache::filename_2_table_key");
+
+ /* Safety if filename didn't have a directory name */
+ tablename[0]= FN_LIBCHAR;
+ tablename[1]= FN_LIBCHAR;
+ /* Convert filename to this OS's format in tablename */
+ fn_format(tablename + 2, path, "", "", MY_REPLACE_EXT);
+ filename= tablename + dirname_length(tablename + 2) + 2;
+ /* Find start of databasename */
+ for (dbname= filename - 2 ; dbname[-1] != FN_LIBCHAR ; dbname--) ;
+ db_length= (filename - dbname) - 1;
+ DBUG_PRINT("qcache", ("table '%-.*s.%s'", db_length, dbname, filename));
+
+ DBUG_RETURN((uint) (strmov(strmake(key, dbname, db_length) + 1,
+ filename) -key) + 1);
+}
+
+
+/****************************************************************************
+ Functions to be used when debugging
+****************************************************************************/
+
+#if defined(DBUG_OFF) && !defined(USE_QUERY_CACHE_INTEGRITY_CHECK)
+
+void wreck(uint line, const char *message) {}
+void bins_dump() {}
+void cache_dump() {}
+void queries_dump() {}
+void tables_dump() {}
+my_bool check_integrity(bool not_locked) { return 0; }
+my_bool in_list(Query_cache_block * root, Query_cache_block * point,
+ const char *name) { return 0;}
+my_bool in_blocks(Query_cache_block * point) { return 0; }
+
+#else
+
+void Query_cache::wreck(uint line, const char *message)
+{
+ THD *thd=current_thd;
+ DBUG_ENTER("Query_cache::wreck");
+ query_cache_size = 0;
+ if (*message)
+ DBUG_PRINT("error", (" %s", message));
+ DBUG_PRINT("warning", ("=================================="));
+ DBUG_PRINT("warning", ("%5d QUERY CACHE WRECK => DISABLED",line));
+ DBUG_PRINT("warning", ("=================================="));
+ if (thd)
+ thd->killed = 1;
+ cache_dump();
+ /* check_integrity(0); */ /* Can't call it here because of locks */
+ bins_dump();
+ DBUG_VOID_RETURN;
+}
+
+
+void Query_cache::bins_dump()
+{
+ uint i;
+
+ if ( !initialized )
+ {
+ DBUG_PRINT("qcache", ("Query Cache not initialized"));
+ return;
+ }
+
+ DBUG_PRINT("qcache", ("mem_bin_num=%u, mem_bin_steps=%u",
+ mem_bin_num, mem_bin_steps));
+ DBUG_PRINT("qcache", ("-------------------------"));
+ DBUG_PRINT("qcache", (" size idx step"));
+ DBUG_PRINT("qcache", ("-------------------------"));
+ for (i=0; i < mem_bin_steps; i++)
+ {
+ DBUG_PRINT("qcache", ("%10lu %3d %10lu", steps[i].size, steps[i].idx,
+ steps[i].increment));
+ }
+ DBUG_PRINT("qcache", ("-------------------------"));
+ DBUG_PRINT("qcache", (" size num"));
+ DBUG_PRINT("qcache", ("-------------------------"));
+ for (i=0; i < mem_bin_num; i++)
+ {
+ DBUG_PRINT("qcache", ("%10lu %3d 0x%lx", bins[i].size, bins[i].number,
+ (ulong)&(bins[i])));
+ if (bins[i].free_blocks)
+ {
+ Query_cache_block *block = bins[i].free_blocks;
+ do{
+ DBUG_PRINT("qcache", ("\\-- %lu 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx",
+ block->length, (ulong)block,
+ (ulong)block->next, (ulong)block->prev,
+ (ulong)block->pnext, (ulong)block->pprev));
+ block = block->next;
+ } while ( block != bins[i].free_blocks );
+ }
+ }
+ DBUG_PRINT("qcache", ("-------------------------"));
+}
+
+
+void Query_cache::cache_dump()
+{
+
+ if ( !initialized )
+ {
+ DBUG_PRINT("qcache", ("Query Cache not initialized"));
+ return;
+ }
+
+ DBUG_PRINT("qcache", ("-------------------------------------"));
+ DBUG_PRINT("qcache", (" length used t nt"));
+ DBUG_PRINT("qcache", ("-------------------------------------"));
+ Query_cache_block *i = first_block;
+ do
+ {
+ DBUG_PRINT("qcache",
+ ("%10lu %10lu %1d %2d 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx",
+ i->length, i->used, (int)i->type,
+ i->n_tables, (ulong)i,
+ (ulong)i->next, (ulong)i->prev, (ulong)i->pnext,
+ (ulong)i->pprev));
+ i = i->pnext;
+ } while ( i != first_block );
+ DBUG_PRINT("qcache", ("-------------------------------------"));
+}
+
+
+void Query_cache::queries_dump()
+{
+
+ if ( !initialized )
+ {
+ DBUG_PRINT("qcache", ("Query Cache not initialized"));
+ return;
+ }
+
+ DBUG_PRINT("qcache", ("------------------"));
+ DBUG_PRINT("qcache", (" QUERIES"));
+ DBUG_PRINT("qcache", ("------------------"));
+ if (queries_blocks != 0)
+ {
+ Query_cache_block *block = queries_blocks;
+ do
+ {
+ uint len;
+ char *str = (char*) query_cache_query_get_key((byte*) block, &len, 0);
+ len--; // Point at flags
+ uint flags = (uint) (uchar) str[len];
+ str[len]=0;
+ DBUG_PRINT("qcache", ("%u (%u,%u) '%s' '%s'",
+ ((flags & QUERY_CACHE_CLIENT_LONG_FLAG_MASK)? 1:0),
+ (flags & QUERY_CACHE_CHARSET_CONVERT_MASK), len,
+ str,strend(str)+1));
+ DBUG_PRINT("qcache", ("-b- 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx", (ulong) block,
+ (ulong) block->next, (ulong) block->prev,
+ (ulong)block->pnext, (ulong)block->pprev));
+ str[len]=(char) flags;
+ for (TABLE_COUNTER_TYPE t = 0; t < block->n_tables; t++)
+ {
+ Query_cache_table *table = block->table(t)->parent;
+ DBUG_PRINT("qcache", ("-t- '%s' '%s'", table->db(), table->table()));
+ }
+ Query_cache_query *header = block->query();
+ if (header->result())
+ {
+ Query_cache_block *result_block = header->result();
+ Query_cache_block *result_beg = result_block;
+ do
+ {
+ DBUG_PRINT("qcache", ("-r- %u %lu/%lu 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx",
+ (uint) result_block->type,
+ result_block->length, result_block->used,
+ (ulong) result_block,
+ (ulong) result_block->next,
+ (ulong) result_block->prev,
+ (ulong) result_block->pnext,
+ (ulong) result_block->pprev));
+ result_block = result_block->next;
+ } while ( result_block != result_beg );
+ }
+ } while ((block=block->next) != queries_blocks);
+ }
+ else
+ {
+ DBUG_PRINT("qcache", ("no queries in list"));
+ }
+ DBUG_PRINT("qcache", ("------------------"));
+}
+
+
+void Query_cache::tables_dump()
+{
+
+ if ( !initialized )
+ {
+ DBUG_PRINT("qcache", ("Query Cache not initialized"));
+ return;
+ }
+
+ DBUG_PRINT("qcache", ("--------------------"));
+ DBUG_PRINT("qcache", ("TABLES"));
+ DBUG_PRINT("qcache", ("--------------------"));
+ for (int i=0; i < (int) Query_cache_table::TYPES_NUMBER; i++)
+ {
+ DBUG_PRINT("qcache", ("--- type %u", i));
+ if (tables_blocks[i] != 0)
+ {
+ Query_cache_block *table_block = tables_blocks[i];
+ do
+ {
+ Query_cache_table *table = table_block->table();
+ DBUG_PRINT("qcache", ("'%s' '%s'", table->db(), table->table()));
+ table_block = table_block->next;
+ } while ( table_block != tables_blocks[i]);
+ }
+ else
+ DBUG_PRINT("qcache", ("no tables in list"));
+ }
+ DBUG_PRINT("qcache", ("--------------------"));
+}
+
+
+my_bool Query_cache::check_integrity(bool not_locked)
+{
+ my_bool result = 0;
+ uint i;
+ DBUG_ENTER("check_integrity");
+
+ if (query_cache_size == 0)
+ {
+ DBUG_PRINT("qcache", ("Query Cache not initialized"));
+ DBUG_RETURN(0);
+ }
+ if (!not_locked)
+ STRUCT_LOCK(&structure_guard_mutex);
+
+ if (hash_check(&queries))
+ {
+ DBUG_PRINT("error", ("queries hash is damaged"));
+ result = 1;
+ }
+
+ if (hash_check(&tables))
+ {
+ DBUG_PRINT("error", ("tables hash is damaged"));
+ result = 1;
+ }
+
+ DBUG_PRINT("qcache", ("physical address check ..."));
+ ulong free=0, used=0;
+ Query_cache_block * block = first_block;
+ do
+ {
+ DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
+ (ulong) block, (uint) block->type));
+ // Check memory allocation
+ if (block->pnext == first_block) // Is it last block?
+ {
+ if ( ((byte*)block) + block->length !=
+ ((byte*)first_block) + query_cache_size )
+ {
+ DBUG_PRINT("error",
+ ("block 0x%lx, type %u, ended at 0x%lx, but cache ended at 0x%lx",
+ (ulong) block, (uint) block->type,
+ (ulong) (((byte*)block) + block->length),
+ (ulong) (((byte*)first_block) + query_cache_size)));
+ result = 1;
+ }
+ }
+ else
+ if (((byte*)block) + block->length != ((byte*)block->pnext))
+ {
+ DBUG_PRINT("error",
+ ("block 0x%lx, type %u, ended at 0x%lx, but next block begining at 0x%lx",
+ (ulong) block, (uint) block->type,
+ (ulong) (((byte*)block) + block->length),
+ (ulong) ((byte*)block->pnext)));
+ }
+ if (block->type == Query_cache_block::FREE)
+ free+=block->length;
+ else
+ used+=block->length;
+ switch(block->type) {
+ case Query_cache_block::FREE:
+ {
+ Query_cache_memory_bin *bin = *((Query_cache_memory_bin **)
+ block->data());
+ //is it correct pointer?
+ if ( ((byte*)bin) < ((byte*)bins) ||
+ ((byte*)bin) >= ((byte*)first_block))
+ {
+ DBUG_PRINT("error",
+ ("free block 0x%lx have bin pointer 0x%lx beyaond of bins array bounds [0x%lx,0x%lx]",
+ (ulong) block,
+ (ulong) bin,
+ (ulong) bins,
+ (ulong) first_block));
+ result = 1;
+ }
+ else
+ {
+ int idx = (((byte*)bin) - ((byte*)bins)) /
+ sizeof(Query_cache_memory_bin);
+ if (in_list(bins[idx].free_blocks, block, "free memory"))
+ result = 1;
+ }
+ break;
+ }
+ case Query_cache_block::TABLE:
+ if (in_list(tables_blocks[block->table()->type()], block, "tables"))
+ result = 1;
+ if (in_table_list(block->table(0), block->table(0), "table list root"))
+ result = 1;
+ break;
+ case Query_cache_block::QUERY:
+ {
+ if (in_list(queries_blocks, block, "query"))
+ result = 1;
+ for (TABLE_COUNTER_TYPE j=0; j < block->n_tables; j++)
+ {
+ Query_cache_block_table *block_table = block->table(j);
+ Query_cache_block_table *block_table_root =
+ (Query_cache_block_table *)
+ (((byte*)block_table->parent) -
+ ALIGN_SIZE(sizeof(Query_cache_block_table)));
+
+ if (in_table_list(block_table, block_table_root, "table list"))
+ result = 1;
+ }
+ break;
+ }
+ case Query_cache_block::RES_INCOMPLETE:
+ // This type of block can be not lincked yet (in multithread environment)
+ break;
+ case Query_cache_block::RES_BEG:
+ case Query_cache_block::RES_CONT:
+ case Query_cache_block::RESULT:
+ {
+ Query_cache_block * query_block = block->result()->parent();
+ if ( ((byte*)query_block) < ((byte*)first_block) ||
+ ((byte*)query_block) >= (((byte*)first_block) + query_cache_size))
+ {
+ DBUG_PRINT("error",
+ ("result block 0x%lx have query block pointer 0x%lx beyaond of block pool bounds [0x%lx,0x%lx]",
+ (ulong) block,
+ (ulong) query_block,
+ (ulong) first_block,
+ (ulong) (((byte*)first_block) + query_cache_size)));
+ result = 1;
+ }
+ else
+ {
+ BLOCK_LOCK_RD(query_block);
+ if (in_list(queries_blocks, query_block, "query from results"))
+ result = 1;
+ if (in_list(query_block->query()->result(), block,
+ "results"))
+ result = 1;
+ BLOCK_UNLOCK_RD(query_block);
+ }
+ break;
+ }
+ default:
+ DBUG_PRINT("error",
+ ("block 0x%lx have incorrect type %u",
+ block, block->type));
+ result = 1;
+ }
+
+ block = block->pnext;
+ } while (block != first_block);
+
+ if (used + free != query_cache_size)
+ {
+ DBUG_PRINT("error",
+ ("used memory (%lu) + free memory (%lu) != query_cache_size (%lu)",
+ used, free, query_cache_size));
+ result = 1;
+ }
+
+ if (free != free_memory)
+ {
+ DBUG_PRINT("error",
+ ("free memory (%lu) != free_memory (%lu)",
+ free, free_memory));
+ result = 1;
+ }
+
+ DBUG_PRINT("qcache", ("check queries ..."));
+ if ((block = queries_blocks))
+ {
+ do
+ {
+ DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
+ (ulong) block, (uint) block->type));
+ uint length;
+ byte *key = query_cache_query_get_key((byte*) block, &length, 0);
+ gptr val = hash_search(&queries, key, length);
+ if (((gptr)block) != val)
+ {
+ DBUG_PRINT("error", ("block 0x%lx found in queries hash like 0x%lx",
+ (ulong) block, (ulong) val));
+ }
+ if (in_blocks(block))
+ result = 1;
+ Query_cache_block * results = block->query()->result();
+ if (results)
+ {
+ Query_cache_block * result_block = results;
+ do
+ {
+ DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
+ (ulong) block, (uint) block->type));
+ if (in_blocks(result_block))
+ result = 1;
+
+ result_block = result_block->next;
+ } while (result_block != results);
+ }
+ block = block->next;
+ } while (block != queries_blocks);
+ }
+
+ DBUG_PRINT("qcache", ("check tables ..."));
+ for (i=0 ; (int) i < (int) Query_cache_table::TYPES_NUMBER; i++)
+ {
+ if ((block = tables_blocks[i]))
+ {
+ do
+ {
+ DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
+ (ulong) block, (uint) block->type));
+ uint length;
+ byte *key = query_cache_table_get_key((byte*) block, &length, 0);
+ gptr val = hash_search(&tables, key, length);
+ if (((gptr)block) != val)
+ {
+ DBUG_PRINT("error", ("block 0x%lx found in tables hash like 0x%lx",
+ (ulong) block, (ulong) val));
+ }
+
+ if (in_blocks(block))
+ result = 1;
+ block=block->next;
+ } while (block != tables_blocks[i]);
+ }
+ }
+
+ DBUG_PRINT("qcache", ("check free blocks"));
+ for (i = 0; i < mem_bin_num; i++)
+ {
+ if ((block = bins[i].free_blocks))
+ {
+ uint count = 0;
+ do
+ {
+ DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
+ (ulong) block, (uint) block->type));
+ if (in_blocks(block))
+ result = 1;
+
+ count++;
+ block=block->next;
+ } while (block != bins[i].free_blocks);
+ if (count != bins[i].number)
+ {
+ DBUG_PRINT("error", ("bin[%d].number is %d, but bin have %d blocks",
+ bins[i].number, count));
+ result = 1;
+ }
+ }
+ }
+ DBUG_ASSERT(result == 0);
+ if (!not_locked)
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_RETURN(result);
+}
+
+
+my_bool Query_cache::in_blocks(Query_cache_block * point)
+{
+ my_bool result = 0;
+ Query_cache_block *block = point;
+ //back
+ do
+ {
+ if (block->pprev->pnext != block)
+ {
+ DBUG_PRINT("error",
+ ("block 0x%lx in physical list is incorrect linked, prev block 0x%lx refered as next to 0x%lx (check from 0x%lx)",
+ (ulong) block, (ulong) block->pprev,
+ (ulong) block->pprev->pnext,
+ (ulong) point));
+ //back trace
+ for(; block != point; block = block->pnext)
+ DBUG_PRINT("error", ("back trace 0x%lx", (ulong) block));
+ result = 1;
+ goto err1;
+ }
+ block = block->pprev;
+ } while (block != first_block && block != point);
+ if (block != first_block)
+ {
+ DBUG_PRINT("error",
+ ("block 0x%lx (0x%lx<-->0x%lx) not owned by pysical list",
+ (ulong) block, (ulong) block->pprev, (ulong )block->pnext));
+ return 1;
+ }
+
+err1:
+ //forward
+ block = point;
+ do
+ {
+ if (block->pnext->pprev != block)
+ {
+ DBUG_PRINT("error",
+ ("block 0x%lx in physicel list is incorrect linked, next block 0x%lx refered as prev to 0x%lx (check from 0x%lx)",
+ (ulong) block, (ulong) block->pnext,
+ (ulong) block->pnext->pprev,
+ (ulong) point));
+ //back trace
+ for(; block != point; block = block->pprev)
+ DBUG_PRINT("error", ("back trace 0x%lx", (ulong) block));
+ result = 1;
+ goto err2;
+ }
+ block = block->pnext;
+ } while (block != first_block);
+err2:
+ return result;
+}
+
+
+my_bool Query_cache::in_list(Query_cache_block * root,
+ Query_cache_block * point,
+ const char *name)
+{
+ my_bool result = 0;
+ Query_cache_block *block = point;
+ //back
+ do
+ {
+ if (block->prev->next != block)
+ {
+ DBUG_PRINT("error",
+ ("block 0x%lx in list '%s' 0x%lx is incorrect linked, prev block 0x%lx refered as next to 0x%lx (check from 0x%lx)",
+ (ulong) block, name, (ulong) root, (ulong) block->prev,
+ (ulong) block->prev->next,
+ (ulong) point));
+ //back trace
+ for(; block != point; block = block->next)
+ DBUG_PRINT("error", ("back trace 0x%lx", (ulong) block));
+ result = 1;
+ goto err1;
+ }
+ block = block->prev;
+ } while (block != root && block != point);
+ if (block != root)
+ {
+ DBUG_PRINT("error",
+ ("block 0x%lx (0x%lx<-->0x%lx) not owned by list '%s' 0x%lx",
+ (ulong) block,
+ (ulong) block->prev, (ulong) block->next,
+ name, (ulong) root));
+ return 1;
+ }
+err1:
+ // forward
+ block = point;
+ do
+ {
+ if (block->next->prev != block)
+ {
+ DBUG_PRINT("error",
+ ("block 0x%lx in list '%s' 0x%lx is incorrect linked, next block 0x%lx refered as prev to 0x%lx (check from 0x%lx)",
+ (ulong) block, name, (ulong) root, (ulong) block->next,
+ (ulong) block->next->prev,
+ (ulong) point));
+ //back trace
+ for (; block != point; block = block->prev)
+ DBUG_PRINT("error", ("back trace 0x%lx", (ulong) block));
+ result = 1;
+ goto err2;
+ }
+ block = block->next;
+ } while (block != root);
+err2:
+ return result;
+}
+
+void dump_node(Query_cache_block_table * node,
+ const char * call, const char * descr)
+{
+ DBUG_PRINT("qcache", ("%s: %s: node: 0x%lx", call, descr, (ulong) node));
+ DBUG_PRINT("qcache", ("%s: %s: node block: 0x%lx",
+ call, descr, (ulong) node->block()));
+ DBUG_PRINT("qcache", ("%s: %s: next: 0x%lx", call, descr,
+ (ulong) node->next));
+ DBUG_PRINT("qcache", ("%s: %s: prev: 0x%lx", call, descr,
+ (ulong) node->prev));
+}
+
+my_bool Query_cache::in_table_list(Query_cache_block_table * root,
+ Query_cache_block_table * point,
+ const char *name)
+{
+ my_bool result = 0;
+ Query_cache_block_table *table = point;
+ dump_node(root, name, "parameter root");
+ //back
+ do
+ {
+ dump_node(table, name, "list element << ");
+ if (table->prev->next != table)
+ {
+ DBUG_PRINT("error",
+ ("table 0x%lx(0x%lx) in list '%s' 0x%lx(0x%lx) is incorrect linked, prev table 0x%lx(0x%lx) refered as next to 0x%lx(0x%lx) (check from 0x%lx(0x%lx))",
+ (ulong) table, (ulong) table->block(), name,
+ (ulong) root, (ulong) root->block(),
+ (ulong) table->prev, (ulong) table->prev->block(),
+ (ulong) table->prev->next,
+ (ulong) table->prev->next->block(),
+ (ulong) point, (ulong) point->block()));
+ //back trace
+ for(; table != point; table = table->next)
+ DBUG_PRINT("error", ("back trace 0x%lx(0x%lx)",
+ (ulong) table, (ulong) table->block()));
+ result = 1;
+ goto err1;
+ }
+ table = table->prev;
+ } while (table != root && table != point);
+ if (table != root)
+ {
+ DBUG_PRINT("error",
+ ("table 0x%lx(0x%lx) (0x%lx(0x%lx)<-->0x%lx(0x%lx)) not owned by list '%s' 0x%lx(0x%lx)",
+ (ulong) table, (ulong) table->block(),
+ (ulong) table->prev, (ulong) table->prev->block(),
+ (ulong) table->next, (ulong) table->next->block(),
+ name, (ulong) root, (ulong) root->block()));
+ return 1;
+ }
+err1:
+ // forward
+ table = point;
+ do
+ {
+ dump_node(table, name, "list element >> ");
+ if (table->next->prev != table)
+ {
+ DBUG_PRINT("error",
+ ("table 0x%lx(0x%lx) in list '%s' 0x%lx(0x%lx) is incorrect linked, next table 0x%lx(0x%lx) refered as prev to 0x%lx(0x%lx) (check from 0x%lx(0x%lx))",
+ (ulong) table, (ulong) table->block(),
+ name, (ulong) root, (ulong) root->block(),
+ (ulong) table->next, (ulong) table->next->block(),
+ (ulong) table->next->prev,
+ (ulong) table->next->prev->block(),
+ (ulong) point, (ulong) point->block()));
+ //back trace
+ for (; table != point; table = table->prev)
+ DBUG_PRINT("error", ("back trace 0x%lx(0x%lx)",
+ (ulong) table, (ulong) table->block()));
+ result = 1;
+ goto err2;
+ }
+ table = table->next;
+ } while (table != root);
+err2:
+ return result;
+}
+
+#endif /* DBUG_OFF */
diff --git a/sql/sql_cache.h b/sql/sql_cache.h
new file mode 100644
index 00000000000..b1d8eb23198
--- /dev/null
+++ b/sql/sql_cache.h
@@ -0,0 +1,418 @@
+/* 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 */
+
+#ifndef _SQL_CACHE_H
+#define _SQL_CACHE_H
+
+/* Query cache */
+
+/*
+ Can't create new free memory block if unused memory in block less
+ then QUERY_CACHE_MIN_ALLOCATION_UNIT.
+ if QUERY_CACHE_MIN_ALLOCATION_UNIT == 0 then
+ QUERY_CACHE_MIN_ALLOCATION_UNIT choosed automaticaly
+*/
+#define QUERY_CACHE_MIN_ALLOCATION_UNIT 512
+
+/* inittial size of hashes */
+#define QUERY_CACHE_DEF_QUERY_HASH_SIZE 1024
+#define QUERY_CACHE_DEF_TABLE_HASH_SIZE 1024
+
+/* minimal result data size when data allocated */
+#define QUERY_CACHE_MIN_RESULT_DATA_SIZE 1024*4
+
+/*
+ start estimation of first result block size only when number of queries
+ bigger then:
+*/
+#define QUERY_CACHE_MIN_ESTIMATED_QUERIES_NUMBER 3
+
+
+
+/* memory bins size spacing (see at Query_cache::init_cache (sql_cache.cc)) */
+#define QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2 4
+#define QUERY_CACHE_MEM_BIN_STEP_PWR2 2
+#define QUERY_CACHE_MEM_BIN_PARTS_INC 1
+#define QUERY_CACHE_MEM_BIN_PARTS_MUL 1.2
+#define QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2 3
+
+/* how many free blocks check when finding most suitable before other 'end'
+ of list of free blocks */
+#define QUERY_CACHE_MEM_BIN_TRY 5
+
+/* query flags masks */
+#define QUERY_CACHE_CLIENT_LONG_FLAG_MASK 0x80
+#define QUERY_CACHE_CHARSET_CONVERT_MASK 0x7F
+
+/* packing parameters */
+#define QUERY_CACHE_PACK_ITERATION 2
+#define QUERY_CACHE_PACK_LIMIT (512*1024L)
+
+#define TABLE_COUNTER_TYPE uint8
+
+#include <my_semaphore.h>
+
+struct Query_cache_block;
+struct Query_cache_block_table;
+struct Query_cache_table;
+struct Query_cache_query;
+struct Query_cache_result;
+class Query_cache;
+
+
+struct Query_cache_block_table
+{
+ TABLE_COUNTER_TYPE n; // numbr in table (from 0)
+ Query_cache_block_table *next, *prev;
+ Query_cache_table *parent;
+ inline Query_cache_block *block();
+};
+
+
+struct Query_cache_block
+{
+ enum block_type {FREE, QUERY, RESULT, RES_CONT, RES_BEG,
+ RES_INCOMPLETE, TABLE, INCOMPLETE};
+
+ ulong length; // length of all block
+ ulong used; // length of data
+ /*
+ Not used **pprev, **prev because really needed access to pervious block:
+ *pprev to join free blocks
+ *prev to access to opposite side of list in cyclic sorted list
+ */
+ Query_cache_block *pnext,*pprev, // physical next/previous block
+ *next,*prev; // logical next/previous block
+ block_type type;
+ TABLE_COUNTER_TYPE n_tables; // number of tables in query
+
+ inline my_bool is_free(void) { return type == FREE; }
+ void init(ulong length);
+ void destroy();
+ inline uint headers_len();
+ inline gptr data(void);
+ inline Query_cache_query *query();
+ inline Query_cache_table *table();
+ inline Query_cache_result *result();
+ inline Query_cache_block_table *table(TABLE_COUNTER_TYPE n);
+};
+
+
+struct Query_cache_query
+{
+ ulonglong limit_found_rows;
+ Query_cache_block *res;
+ NET *wri;
+ ulong len;
+ sem_t lock; // R/W lock of block
+ pthread_mutex_t clients_guard;
+ uint clients;
+
+ inline void init_n_lock();
+ void unlock_n_destroy();
+ inline ulonglong found_rows() { return limit_found_rows; }
+ inline void found_rows(ulonglong rows) { limit_found_rows = rows; }
+ inline Query_cache_block *result() { return res; }
+ inline void result(Query_cache_block *p) { res=p; }
+ inline NET *writer() { return wri; }
+ inline void writer(NET *p) { wri=p; }
+ inline ulong length() { return len; }
+ inline ulong add(ulong packet_len) { return(len += packet_len); }
+ inline void length(ulong length) { len = length; }
+ inline gptr query()
+ {
+ return (gptr)(((byte*)this)+
+ ALIGN_SIZE(sizeof(Query_cache_query)));
+ }
+ void lock_writing();
+ void lock_reading();
+ my_bool try_lock_writing();
+ void unlock_writing();
+ void unlock_reading();
+ static byte *cache_key(const byte *record, uint *length, my_bool not_used);
+};
+
+
+struct Query_cache_table
+{
+ enum query_cache_table_type {OTHER=0, INNODB=1, TYPES_NUMBER=2};
+ inline static query_cache_table_type type_convertion(db_type type)
+ {
+ return (type == DB_TYPE_INNODB ? INNODB : OTHER);
+ }
+
+ char *tbl;
+ query_cache_table_type tp;
+
+ inline query_cache_table_type type() { return tp; }
+ inline void type(query_cache_table_type t) { tp = t;}
+ inline char *db() { return (char *) data(); }
+ inline char *table() { return tbl; }
+ inline void table(char *table) { tbl = table; }
+ inline gptr data()
+ {
+ return (gptr)(((byte*)this)+
+ ALIGN_SIZE(sizeof(Query_cache_table)));
+ }
+};
+
+struct Query_cache_result
+{
+ Query_cache_block *query;
+
+ inline gptr data()
+ {
+ return (gptr)(((byte*) this)+
+ ALIGN_SIZE(sizeof(Query_cache_result)));
+ }
+ /* data_continue (if not whole packet contained by this block) */
+ inline Query_cache_block *parent() { return query; }
+ inline void parent (Query_cache_block *p) { query=p; }
+};
+
+
+extern "C" {
+ byte *query_cache_query_get_key(const byte *record, uint *length,
+ my_bool not_used);
+ byte *query_cache_table_get_key(const byte *record, uint *length,
+ my_bool not_used);
+ void query_cache_insert(THD *thd, const char *packet, ulong length);
+ void query_cache_end_of_result(THD *thd);
+ void query_cache_abort(THD *thd);
+ void query_cache_invalidate_by_MyISAM_filename(const char* filename);
+}
+
+struct Query_cache_memory_bin
+{
+#ifndef DBUG_OFF
+ ulong size;
+#endif
+ uint number;
+ Query_cache_block *free_blocks;
+
+ inline void init(ulong size)
+ {
+#ifndef DBUG_OFF
+ this->size = size;
+#endif
+ number = 0;
+ free_blocks = 0;
+ }
+};
+
+struct Query_cache_memory_bin_step
+{
+ ulong size;
+ ulong increment;
+ uint idx;
+ inline void init(ulong size, uint idx, ulong increment)
+ {
+ this->size = size;
+ this->idx = idx;
+ this->increment = increment;
+ }
+};
+
+class Query_cache
+{
+public:
+ /* Info */
+ ulong query_cache_size, query_cache_limit;
+ /* statistics */
+ ulong free_memory, queries_in_cache, hits, inserts, refused,
+ free_memory_blocks, total_blocks;
+
+protected:
+ /*
+ The following mutex is locked when searching or changing global
+ query, tables lists or hashes. When we are operating inside the
+ query structure we locked an internal query block mutex.
+ LOCK SEQUENCE (to prevent deadlocks):
+ 1. structure_guard_mutex
+ 2. query block (for operation inside query (query block/results))
+ */
+ pthread_mutex_t structure_guard_mutex;
+ byte *cache; // cache memory
+ Query_cache_block *first_block; // physical location block list
+ Query_cache_block *queries_blocks; // query list (LIFO)
+ Query_cache_block *tables_blocks[Query_cache_table::TYPES_NUMBER];
+
+ Query_cache_memory_bin *bins; // free block lists
+ Query_cache_memory_bin_step *steps; // bins spacing info
+ HASH queries, tables;
+ /* options */
+ ulong min_allocation_unit, min_result_data_size;
+ uint def_query_hash_size, def_table_hash_size;
+ uint mem_bin_num, mem_bin_steps; // See at init_cache & find_bin
+
+ my_bool initialized;
+
+ /* Exclude/include from cyclic double linked list */
+ static void double_linked_list_exclude(Query_cache_block *point,
+ Query_cache_block **list_pointer);
+ static void double_linked_list_simple_include(Query_cache_block *point,
+ Query_cache_block **
+ list_pointer);
+ static void double_linked_list_join(Query_cache_block *head_tail,
+ Query_cache_block *tail_head);
+
+ /* Table key generation */
+ static uint filename_2_table_key (char *key, const char *filename);
+
+ /* The following functions require that structure_guard_mutex is locked */
+ void flush_cache();
+ my_bool free_old_query();
+ void free_query(Query_cache_block *point);
+ my_bool allocate_data_chain(Query_cache_block **result_block,
+ ulong data_len,
+ Query_cache_block *query_block,
+ my_bool first_block);
+ void invalidate_table(TABLE_LIST *table);
+ void invalidate_table(TABLE *table);
+ void invalidate_table(Query_cache_block *table_block);
+ 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,
+ Query_cache_table::query_cache_table_type type);
+ void unlink_table(Query_cache_block_table *node);
+ Query_cache_block *get_free_block (ulong len, my_bool not_less,
+ ulong min);
+ void free_memory_block(Query_cache_block *point);
+ void split_block(Query_cache_block *block, ulong len);
+ Query_cache_block *join_free_blocks(Query_cache_block *first_block,
+ Query_cache_block *block_in_list);
+ my_bool append_next_free_block(Query_cache_block *block,
+ ulong add_size);
+ void exclude_from_free_memory_list(Query_cache_block *free_block);
+ void insert_into_free_memory_list(Query_cache_block *new_block);
+ my_bool move_by_type(byte **border, Query_cache_block **before,
+ ulong *gap, Query_cache_block *i);
+ uint find_bin(ulong size);
+ void move_to_query_list_end(Query_cache_block *block);
+ void insert_into_free_memory_sorted_list(Query_cache_block *new_block,
+ Query_cache_block **list);
+ void pack_cache();
+ void relink(Query_cache_block *oblock,
+ Query_cache_block *nblock,
+ Query_cache_block *next,
+ Query_cache_block *prev,
+ Query_cache_block *pnext,
+ Query_cache_block *pprev);
+ my_bool join_results(ulong join_limit);
+
+ /*
+ Following function control structure_guard_mutex
+ by themself or don't need structure_guard_mutex
+ */
+ void init();
+ ulong init_cache();
+ void make_disabled();
+ void free_cache(my_bool destruction);
+ Query_cache_block *write_block_data(ulong data_len, gptr data,
+ ulong header_len,
+ Query_cache_block::block_type type,
+ TABLE_COUNTER_TYPE ntab = 0,
+ my_bool under_guard=0);
+ my_bool append_result_data(Query_cache_block **result,
+ ulong data_len, gptr data,
+ Query_cache_block *parent);
+ my_bool write_result_data(Query_cache_block **result,
+ ulong data_len, gptr data,
+ Query_cache_block *parent,
+ Query_cache_block::block_type
+ type=Query_cache_block::RESULT);
+ inline ulong get_min_first_result_data_size();
+ inline ulong get_min_append_result_data_size();
+ Query_cache_block *allocate_block(ulong len, my_bool not_less,
+ ulong min,
+ my_bool under_guard=0);
+ /*
+ If query is cacheable return number tables in query
+ (query without tables not cached)
+ */
+ TABLE_COUNTER_TYPE is_cacheable(THD *thd, uint32 query_len, char *query,
+ LEX *lex, TABLE_LIST *tables_used);
+ public:
+
+ Query_cache(ulong query_cache_limit = ULONG_MAX,
+ ulong min_allocation_unit = QUERY_CACHE_MIN_ALLOCATION_UNIT,
+ ulong min_result_data_size = QUERY_CACHE_MIN_RESULT_DATA_SIZE,
+ uint def_query_hash_size = QUERY_CACHE_DEF_QUERY_HASH_SIZE,
+ uint def_table_hash_size = QUERY_CACHE_DEF_TABLE_HASH_SIZE);
+
+ /* resize query cache (return real query size, 0 if disabled) */
+ ulong resize(ulong query_cache_size);
+ inline void result_size_limit(ulong limit){query_cache_limit=limit;}
+
+ /* register query in cache */
+ void store_query(THD *thd, TABLE_LIST *used_tables);
+
+ /*
+ Check if the query is in the cache and if this is true send the
+ data to client.
+ */
+ int send_result_to_client(THD *thd, char *query, uint query_length);
+
+ /* Remove all queries that uses any of the listed following tables */
+ void invalidate(TABLE_LIST *tables_used);
+ void invalidate(TABLE *table);
+
+ /* Remove all queries that uses tables of pointed type*/
+ void invalidate(Query_cache_table::query_cache_table_type type);
+
+ /* Remove all queries that uses any of the tables in following database */
+ void invalidate(char *db);
+
+ /* Remove all queries that uses any of the listed following table */
+ void invalidate_by_MyISAM_filename(const char *filename);
+
+ void flush();
+ void pack(ulong join_limit = QUERY_CACHE_PACK_LIMIT,
+ uint iteration_limit = QUERY_CACHE_PACK_ITERATION);
+
+ void destroy();
+
+ friend void query_cache_insert(NET *net, const char *packet, ulong length);
+ friend void query_cache_end_of_result(NET *net);
+ friend void query_cache_abort(NET *net);
+
+ /*
+ The following functions are only used when debugging
+ We don't protect these with ifndef DEBUG_OFF to not have to recompile
+ everything if we want to add checks of the cache at some places.
+ */
+ void wreck(uint line, const char *message);
+ void bins_dump();
+ void cache_dump();
+ void queries_dump();
+ void tables_dump();
+ my_bool check_integrity(bool not_locked);
+ my_bool in_list(Query_cache_block * root, Query_cache_block * point,
+ const char *name);
+ my_bool in_table_list(Query_cache_block_table * root,
+ Query_cache_block_table * point,
+ const char *name);
+ my_bool in_blocks(Query_cache_block * point);
+};
+
+extern Query_cache query_cache;
+void query_cache_insert(NET *net, const char *packet, ulong length);
+void query_cache_end_of_result(NET *net);
+void query_cache_abort(NET *net);
+
+#endif
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index ace7c291ed3..f6f66b0b7da 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -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 */
@@ -49,6 +49,8 @@ template class List<Alter_drop>;
template class List_iterator<Alter_drop>;
template class List<Alter_column>;
template class List_iterator<Alter_column>;
+template class List<Set_option>;
+template class List_iterator<Set_option>;
#endif
/****************************************************************************
@@ -80,22 +82,23 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
global_read_lock(0),bootstrap(0)
{
host=user=priv_user=db=query=ip=0;
+ host_or_ip="unknown ip";
locked=killed=count_cuted_fields=some_tables_deleted=no_errors=password=
- query_start_used=0;
- query_length=col_access=0;
+ query_start_used=safe_to_cache_query=0;
+ db_length=query_length=col_access=0;
query_error=0;
next_insert_id=last_insert_id=0;
- open_tables=temporary_tables=0;
+ open_tables=temporary_tables=handler_tables=0;
+ handler_items=0;
tmp_table=0;
lock=locked_tables=0;
used_tables=0;
- gemini_spin_retries=0;
cuted_fields=sent_row_count=0L;
start_time=(time_t) 0;
current_linfo = 0;
slave_thread = 0;
slave_proxy_id = 0;
- last_nx_table = last_nx_db = 0;
+ file_id = 0;
cond_count=0;
convert_set=0;
mysys_var=0;
@@ -105,9 +108,6 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
#ifdef __WIN__
real_id = 0;
#endif
-#ifdef HAVE_GEMINI_DB
- bzero((char *)&gemini, sizeof(gemini));
-#endif
#ifdef SIGNAL_WITH_VIO_CLOSE
active_vio = 0;
pthread_mutex_init(&active_vio_lock, MY_MUTEX_INIT_FAST);
@@ -117,9 +117,12 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
proc_info="login";
where="field list";
server_id = ::server_id;
+ slave_net = 0;
+ log_pos = 0;
server_status=SERVER_STATUS_AUTOCOMMIT;
update_lock_default= low_priority_updates ? TL_WRITE_LOW_PRIORITY : TL_WRITE;
options=thd_startup_options;
+ query_cache_type = (byte) query_cache_startup_type;
sql_mode=(uint) opt_sql_mode;
inactive_timeout=net_wait_timeout;
open_options=ha_open_options;
@@ -133,6 +136,7 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
/* Initialize sub structures */
bzero((char*) &mem_root,sizeof(mem_root));
+ user_connect=(UC *)0;
hash_init(&user_vars, USER_VARS_HASH_SIZE, 0, 0,
(hash_get_key) get_var_key,
(void (*)(void*)) free_var,0);
@@ -160,6 +164,11 @@ void THD::cleanup(void)
lock=locked_tables; locked_tables=0;
close_thread_tables(this);
}
+ if (handler_tables)
+ {
+ open_tables=handler_tables; handler_tables=0;
+ close_thread_tables(this);
+ }
close_temporary_tables(this);
#ifdef USING_TRANSACTIONS
if (opt_using_transactions)
@@ -184,12 +193,7 @@ THD::~THD()
if (!cleanup_done)
cleanup();
if (global_read_lock)
- {
- pthread_mutex_lock(&LOCK_open);
- ::global_read_lock--;
- pthread_cond_broadcast(&COND_refresh);
- pthread_mutex_unlock(&LOCK_open);
- }
+ unlock_global_read_lock(this);
if (ull)
{
pthread_mutex_lock(&LOCK_user_locks);
@@ -199,7 +203,7 @@ THD::~THD()
hash_free(&user_vars);
DBUG_PRINT("info", ("freeing host"));
-
+
if (host != localhost) // If not pointer to constant
safeFree(host);
if (user != delayed_user)
@@ -214,10 +218,11 @@ THD::~THD()
DBUG_VOID_RETURN;
}
-void THD::prepare_to_die()
+void THD::awake(bool prepare_to_die)
{
+ if (prepare_to_die)
+ killed = 1;
thr_alarm_kill(real_id);
- killed = 1;
#ifdef SIGNAL_WITH_VIO_CLOSE
close_active_vio();
#endif
@@ -226,6 +231,10 @@ void THD::prepare_to_die()
pthread_mutex_lock(&mysys_var->mutex);
if (!system_thread) // Don't abort locks
mysys_var->abort=1;
+ // this broadcast could be up in the air if the victim thread
+ // exits the cond in the time between read and broadcast, but that is
+ // ok since all we want to do is to make the victim thread get out
+ // of waiting on current_cond
if (mysys_var->current_cond)
{
pthread_mutex_lock(mysys_var->current_mutex);
@@ -277,7 +286,7 @@ bool select_send::send_fields(List<Item> &list,uint flag)
bool select_send::send_data(List<Item> &items)
{
- List_iterator<Item> li(items);
+ List_iterator_fast<Item> li(items);
String *packet= &thd->packet;
DBUG_ENTER("send_data");
@@ -290,7 +299,7 @@ bool select_send::send_data(List<Item> &items)
Item *item;
while ((item=li++))
{
- if (item->send(packet))
+ if (item->send(thd, packet))
{
packet->free(); // Free used
my_error(ER_OUT_OF_RESOURCES,MYF(0));
@@ -302,12 +311,6 @@ bool select_send::send_data(List<Item> &items)
DBUG_RETURN(error);
}
-
-void select_send::send_error(uint errcode,const char *err)
-{
- ::send_error(&thd->net,errcode,err);
-}
-
bool select_send::send_eof()
{
/* Unlock tables before sending packet to gain some speed */
@@ -370,7 +373,7 @@ select_export::prepare(List<Item> &list)
}
/* Check if there is any blobs in data */
{
- List_iterator<Item> li(list);
+ List_iterator_fast<Item> li(list);
Item *item;
while ((item=li++))
{
@@ -417,7 +420,7 @@ bool select_export::send_data(List<Item> &items)
Item *item;
char *buff_ptr=buff;
uint used_length=0,items_left=items.elements;
- List_iterator<Item> li(items);
+ List_iterator_fast<Item> li(items);
if (my_b_write(&cache,(byte*) exchange->line_start->ptr(),
exchange->line_start->length()))
@@ -610,7 +613,7 @@ select_dump::prepare(List<Item> &list __attribute__((unused)))
bool select_dump::send_data(List<Item> &items)
{
- List_iterator<Item> li(items);
+ List_iterator_fast<Item> li(items);
char buff[MAX_FIELD_WIDTH];
String tmp(buff,sizeof(buff)),*res;
tmp.length(0);
diff --git a/sql/sql_class.h b/sql/sql_class.h
index d9497907926..a1423cfcdf1 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.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 */
@@ -21,10 +21,14 @@
#pragma interface /* gcc class implementation */
#endif
+// TODO: create log.h and move all the log header stuff there
+
class Query_log_event;
class Load_log_event;
+class Slave_log_event;
-
+enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE };
+enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY };
enum enum_duplicates { DUP_ERROR, DUP_REPLACE, DUP_IGNORE };
enum enum_log_type { LOG_CLOSED, LOG_NORMAL, LOG_NEW, LOG_BIN };
@@ -38,6 +42,8 @@ enum enum_log_type { LOG_CLOSED, LOG_NORMAL, LOG_NEW, LOG_BIN };
#define LOG_INFO_FATAL -7
#define LOG_INFO_IN_USE -8
+struct st_relay_log_info;
+
typedef struct st_log_info
{
char log_file_name[FN_REFLEN];
@@ -49,6 +55,7 @@ typedef struct st_log_info
~st_log_info() { pthread_mutex_destroy(&lock);}
} LOG_INFO;
+class Log_event;
class MYSQL_LOG {
private:
@@ -61,39 +68,65 @@ class MYSQL_LOG {
char time_buff[20],db[NAME_LEN+1];
char log_file_name[FN_REFLEN],index_file_name[FN_REFLEN];
bool write_error,inited;
+ uint file_id; // current file sequence number for load data infile
+ // binary logging
bool no_rotate; // for binlog - if log name can never change
// we should not try to rotate it or write any rotation events
// the user should use FLUSH MASTER instead of FLUSH LOGS for
// purging
+ enum cache_type io_cache_type;
+ bool need_start_event;
+ pthread_cond_t update_cond;
+ bool no_auto_events; // for relay binlog
+ friend class Log_event;
public:
MYSQL_LOG();
~MYSQL_LOG();
pthread_mutex_t* get_log_lock() { return &LOCK_log; }
+ IO_CACHE* get_log_file() { return &log_file; }
+ void signal_update() { pthread_cond_broadcast(&update_cond);}
+ void wait_for_update(THD* thd);
+ void set_need_start_event() { need_start_event = 1; }
void set_index_file_name(const char* index_file_name = 0);
- void init(enum_log_type log_type_arg);
+ void init(enum_log_type log_type_arg,
+ enum cache_type io_cache_type_arg = WRITE_CACHE,
+ bool no_auto_events_arg = 0);
void open(const char *log_name,enum_log_type log_type,
- const char *new_name=0);
+ const char *new_name, enum cache_type io_cache_type_arg,
+ bool no_auto_events_arg);
void new_file(bool inside_mutex = 0);
bool open_index(int options);
void close_index();
- bool write(THD *thd, enum enum_server_command command,const char *format,...);
+ 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(Query_log_event* event_info); // binary log write
- bool write(Load_log_event* event_info);
+ bool write(Log_event* event_info); // binary log write
bool write(THD *thd, IO_CACHE *cache);
+
+ /*
+ v stands for vector
+ invoked as appendv(buf1,len1,buf2,len2,...,bufn,lenn,0)
+ */
+ 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 purge_logs(THD* thd, const char* to_log);
+ int purge_first_log(struct st_relay_log_info* rli);
+ int reset_logs(THD* thd);
void close(bool exiting = 0); // if we are exiting, we also want to close the
// index file
// iterating through the log index file
- int find_first_log(LOG_INFO* linfo, const char* log_name);
- int find_next_log(LOG_INFO* linfo);
+ int find_first_log(LOG_INFO* linfo, const char* log_name,
+ bool need_mutex=1);
+ int find_next_log(LOG_INFO* linfo, bool need_mutex=1);
int get_current_log(LOG_INFO* linfo);
+ uint next_file_id();
inline bool is_open() { return log_type != LOG_CLOSED; }
char* get_index_fname() { return index_file_name;}
@@ -114,14 +147,16 @@ class CONVERT
void convert_array(const uchar *mapping,uchar *buff,uint length);
public:
const char *name;
- CONVERT(const char *name_par,uchar *from_par,uchar *to_par)
- :from_map(from_par),to_map(to_par),name(name_par) {}
+ uint numb;
+ CONVERT(const char *name_par,uchar *from_par,uchar *to_par, uint number)
+ :from_map(from_par),to_map(to_par),name(name_par),numb(number) {}
friend CONVERT *get_convert_set(const char *name_ptr);
inline void convert(char *a,uint length)
{
convert_array(from_map, (uchar*) a,length);
}
bool store(String *, const char *,uint);
+ inline uint number() { return numb; }
};
typedef struct st_copy_info {
@@ -214,49 +249,85 @@ public:
};
-/****************************************************************************
-** every connection is handle by a thread with a THD
-****************************************************************************/
-
class delayed_insert;
+/* For each client connection we create a separate thread with THD serving as
+ a thread/connection descriptor */
+
class THD :public ilink {
public:
- NET net;
- LEX lex;
- MEM_ROOT mem_root;
- HASH user_vars;
- String packet; /* Room for 1 row */
- struct sockaddr_in remote;
- struct rand_struct rand;
+ NET net; // client connection descriptor
+ LEX lex; // parse tree descriptor
+ MEM_ROOT mem_root; // memory allocation pool
+ HASH user_vars; // hash for user variables
+ String packet; // dynamic string buffer used for network I/O
+ struct sockaddr_in remote; // client socket address
+ struct rand_struct rand; // used for authentication
+
+ /* query points to the current query,
+ thread_stack is a pointer to the stack frame of handle_one_connection(),
+ which is called first in the thread for handling a client
+ */
char *query,*thread_stack;
+ /*
+ host - host of the client
+ user - user of the client, set to NULL until the user has been read from
+ the connection
+ priv_user - not sure why we have it, but it is set to "boot" when we run
+ with --bootstrap
+ db - currently selected database
+ ip - client IP
+ */
+
char *host,*user,*priv_user,*db,*ip;
- const char *proc_info;
+ /* proc_info points to a string that will show in the Info column of
+ SHOW PROCESSLIST output
+ host_or_ip points to host if host is available, otherwise points to ip
+ */
+ const char *proc_info, *host_or_ip;
+
+ /*
+ client_capabilities has flags describing what the client can do
+ sql_mode determines if certain non-standard SQL behaviour should be
+ enabled
+ max_packet_length - supposed to be maximum packet length the client
+ can handle, but it currently appears to be assigned but never used
+ except for one debugging statement
+ */
uint client_capabilities,sql_mode,max_packet_length;
+
+ /*
+ master_access - privillege descriptor mask for system threads
+ db_access - privillege descriptor mask for regular threads
+ */
uint master_access,db_access;
- TABLE *open_tables,*temporary_tables;
+
+ /*
+ open_tables - list of regular tables in use by this thread
+ temporary_tables - list of temp tables in use by this thread
+ handler_tables - list of tables that were opened with HANDLER OPEN
+ and are still in use by this thread
+ */
+ TABLE *open_tables,*temporary_tables, *handler_tables;
+ // TODO: document the variables below
MYSQL_LOCK *lock,*locked_tables;
ULL *ull;
struct st_my_thread_var *mysys_var;
enum enum_server_command command;
uint32 server_id;
+ uint32 file_id; // for LOAD DATA INFILE
const char *where;
- char* last_nx_table; // last non-existent table, we need this for replication
- char* last_nx_db; // database of the last nx table
- time_t start_time,time_after_lock,user_time;
- time_t connect_time,thr_create_time; // track down slow pthread_create
+ time_t start_time,time_after_lock,user_time;
+ time_t connect_time,thr_create_time; // track down slow pthread_create
thr_lock_type update_lock_default;
delayed_insert *di;
struct st_transactions {
IO_CACHE trans_log;
- THD_TRANS all; /* Trans since BEGIN WORK */
- THD_TRANS stmt; /* Trans for current statement */
+ THD_TRANS all; // Trans since BEGIN WORK
+ THD_TRANS stmt; // Trans for current statement
uint bdb_lock_count;
} transaction;
-#ifdef HAVE_GEMINI_DB
- struct st_gemini gemini;
-#endif
- Item *free_list;
+ Item *free_list, *handler_items;
CONVERT *convert_set;
Field *dupp_field;
#ifndef __WIN__
@@ -266,32 +337,43 @@ public:
Vio* active_vio;
pthread_mutex_t active_vio_lock;
#endif
- ulonglong next_insert_id,last_insert_id,current_insert_id;
- ha_rows select_limit,offset_limit,default_select_limit,cuted_fields,
- max_join_size, sent_row_count, examined_row_count;
- table_map used_tables;
- ulong query_id,version, inactive_timeout,options,thread_id;
- ulong gemini_spin_retries;
- long dbug_thread_id;
+ ulonglong next_insert_id,last_insert_id,current_insert_id,
+ limit_found_rows;
+ ha_rows select_limit,offset_limit,default_select_limit,cuted_fields,
+ max_join_size, sent_row_count, examined_row_count;
+ table_map used_tables;
+ UC *user_connect;
+ ulong query_id,version, inactive_timeout,options,thread_id;
+ long dbug_thread_id;
pthread_t real_id;
- uint current_tablenr,tmp_table,cond_count,col_access,query_length;
- uint server_status,open_options;
+ uint current_tablenr,tmp_table,cond_count,col_access;
+ uint server_status,open_options;
+ uint32 query_length;
+ uint32 db_length;
enum_tx_isolation tx_isolation, session_tx_isolation;
char scramble[9];
+ uint8 query_cache_type; // type of query cache processing
bool slave_thread;
bool set_query_id,locked,count_cuted_fields,some_tables_deleted;
bool no_errors, allow_sum_func, password, fatal_error;
bool query_start_used,last_insert_id_used,insert_id_used;
bool system_thread,in_lock_tables,global_read_lock;
bool query_error, bootstrap, cleanup_done;
+ bool safe_to_cache_query;
bool volatile killed;
+ /*
+ If we do a purge of binary logs, log index info of the threads
+ that are currently reading it needs to be adjusted. To do that
+ each thread that is using LOG_INFO needs to adjust the pointer to it
+ */
LOG_INFO* current_linfo;
- // if we do a purge of binary logs, log index info of the threads
- // that are currently reading it needs to be adjusted. To do that
- // each thread that is using LOG_INFO needs to adjust the pointer to it
-
- ulong slave_proxy_id; // in slave thread we need to know in behalf of which
- // thread the query is being run to replicate temp tables properly
+ /*
+ In slave thread we need to know in behalf of which
+ thread the query is being run to replicate temp tables properly
+ */
+ ulong slave_proxy_id;
+ NET* slave_net; // network connection from slave -> m.
+ my_off_t log_pos;
THD();
~THD();
@@ -321,7 +403,7 @@ public:
pthread_mutex_unlock(&active_vio_lock);
}
#endif
- void prepare_to_die();
+ void awake(bool prepare_to_die);
inline const char* enter_cond(pthread_cond_t *cond, pthread_mutex_t* mutex,
const char* msg)
{
@@ -355,16 +437,18 @@ public:
}
return last_insert_id;
}
+ 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.gemini_tid != 0);
+ transaction.all.innodb_active_trans != 0);
#else
return 0;
#endif
-
}
inline gptr alloc(unsigned int size) { return alloc_root(&mem_root,size); }
inline gptr calloc(unsigned int size)
@@ -376,8 +460,17 @@ public:
}
inline char *strdup(const char *str)
{ return strdup_root(&mem_root,str); }
- inline char *memdup(const char *str, unsigned int size)
+ inline char *strmake(const char *str, uint size)
+ { return strmake_root(&mem_root,str,size); }
+ inline char *memdup(const char *str, uint size)
{ return memdup_root(&mem_root,str,size); }
+ inline char *memdup_w_gap(const char *str, uint size, uint gap)
+ {
+ gptr ptr;
+ if ((ptr=alloc_root(&mem_root,size+gap)))
+ memcpy(ptr,str,size);
+ return ptr;
+ }
};
@@ -399,6 +492,10 @@ public:
** This is used to get result from a select
*/
+class JOIN;
+
+void send_error(NET *net,uint sql_errno=0, const char *err=0);
+
class select_result :public Sql_alloc {
protected:
THD *thd;
@@ -408,7 +505,11 @@ public:
virtual int prepare(List<Item> &list) { return 0; }
virtual bool send_fields(List<Item> &list,uint flag)=0;
virtual bool send_data(List<Item> &items)=0;
- virtual void send_error(uint errcode,const char *err)=0;
+ virtual void initialize_tables (JOIN *join=0) {}
+ virtual void send_error(uint errcode,const char *err)
+ {
+ ::send_error(&thd->net,errcode,err);
+ }
virtual bool send_eof()=0;
virtual void abort() {}
};
@@ -419,7 +520,6 @@ public:
select_send() {}
bool send_fields(List<Item> &list,uint flag);
bool send_data(List<Item> &items);
- void send_error(uint errcode,const char *err);
bool send_eof();
};
@@ -443,6 +543,7 @@ public:
bool send_eof();
};
+
class select_dump :public select_result {
sql_exchange *exchange;
File file;
@@ -463,29 +564,28 @@ public:
class select_insert :public select_result {
- protected:
+ public:
TABLE *table;
List<Item> *fields;
- uint save_time_stamp;
ulonglong last_insert_id;
COPY_INFO info;
+ uint save_time_stamp;
-public:
select_insert(TABLE *table_par,List<Item> *fields_par,enum_duplicates duplic)
- :table(table_par),fields(fields_par), save_time_stamp(0),last_insert_id(0)
- {
- bzero((char*) &info,sizeof(info));
- info.handle_duplicates=duplic;
- }
+ :table(table_par),fields(fields_par), last_insert_id(0), save_time_stamp(0) {
+ bzero((char*) &info,sizeof(info));
+ info.handle_duplicates=duplic;
+ }
~select_insert();
int prepare(List<Item> &list);
- bool send_fields(List<Item> &list,
- uint flag) { return 0; }
+ bool send_fields(List<Item> &list, uint flag)
+ { return 0; }
bool send_data(List<Item> &items);
void send_error(uint errcode,const char *err);
bool send_eof();
};
+
class select_create: public select_insert {
ORDER *group;
const char *db;
@@ -512,6 +612,22 @@ public:
void abort();
};
+class select_union :public select_result {
+ public:
+ TABLE *table;
+ COPY_INFO info;
+ uint save_time_stamp;
+
+ select_union(TABLE *table_par);
+ ~select_union();
+ int prepare(List<Item> &list);
+ bool send_fields(List<Item> &list, uint flag)
+ { return 0; }
+ bool send_data(List<Item> &items);
+ bool send_eof();
+ bool flush();
+};
+
/* Structs used when sorting */
typedef struct st_sort_field {
@@ -561,3 +677,89 @@ class user_var_entry
Item_result type;
};
+/* Class for unique (removing of duplicates) */
+
+class Unique :public Sql_alloc
+{
+ DYNAMIC_ARRAY file_ptrs;
+ ulong max_elements, max_in_memory_size;
+ IO_CACHE file;
+ TREE tree;
+ byte *record_pointers;
+ bool flush();
+
+public:
+ ulong elements;
+ Unique(qsort_cmp2 comp_func, void * comp_func_fixed_arg,
+ uint size, ulong max_in_memory_size_arg);
+ ~Unique();
+ inline bool unique_add(gptr ptr)
+ {
+ if (tree.elements_in_tree > max_elements && flush())
+ return 1;
+ return !tree_insert(&tree,ptr,0);
+ }
+
+ bool get(TABLE *table);
+
+ 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);
+};
+
+ class multi_delete : public select_result {
+ TABLE_LIST *delete_tables, *table_being_deleted;
+#ifdef SINISAS_STRIP
+ IO_CACHE **tempfiles;
+ byte *memory_lane;
+#else
+ Unique **tempfiles;
+#endif
+ THD *thd;
+ ha_rows deleted;
+ uint num_of_tables;
+ int error;
+ thr_lock_type lock_option;
+ bool do_delete, not_trans_safe;
+ public:
+ multi_delete(THD *thd, TABLE_LIST *dt, thr_lock_type lock_option_arg,
+ uint num_of_tables);
+ ~multi_delete();
+ int prepare(List<Item> &list);
+ bool send_fields(List<Item> &list,
+ uint flag) { return 0; }
+ bool send_data(List<Item> &items);
+ void initialize_tables (JOIN *join);
+ void send_error(uint errcode,const char *err);
+ int do_deletes (bool from_send_error);
+ bool send_eof();
+ };
+
+ class multi_update : public select_result {
+ TABLE_LIST *update_tables, *table_being_updated;
+// Unique **tempfiles;
+ COPY_INFO *infos;
+ TABLE **tmp_tables;
+ THD *thd;
+ ha_rows updated, found;
+ List<Item> fields;
+ List <Item> **fields_by_tables;
+ thr_lock_type lock_option;
+ enum enum_duplicates dupl;
+ uint num_of_tables, num_fields, num_updated, *save_time_stamps, *field_sequence;
+ int error;
+ bool do_update, not_trans_safe;
+ public:
+ multi_update(THD *thd_arg, TABLE_LIST *ut, List<Item> &fs,
+ enum enum_duplicates handle_duplicates,
+ thr_lock_type lock_option_arg, uint num);
+ ~multi_update();
+ int prepare(List<Item> &list);
+ bool send_fields(List<Item> &list,
+ uint flag) { return 0; }
+ bool send_data(List<Item> &items);
+ void initialize_tables (JOIN *join);
+ void send_error(uint errcode,const char *err);
+ int do_updates (bool from_send_error);
+ bool send_eof();
+ };
+
diff --git a/sql/sql_crypt.cc b/sql/sql_crypt.cc
index 371d63f8c73..f2e4a8934be 100644
--- a/sql/sql_crypt.cc
+++ b/sql/sql_crypt.cc
@@ -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 */
diff --git a/sql/sql_crypt.h b/sql/sql_crypt.h
index b3a9d54133f..1b27f0a4d27 100644
--- a/sql/sql_crypt.h
+++ b/sql/sql_crypt.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 */
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 1e798a392b1..dd8ed634011 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -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 */
@@ -25,45 +25,28 @@
#include <direct.h>
#endif
-static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *path,
+static long mysql_rm_known_files(THD *thd, MY_DIR *dirp,
+ const char *db, const char *path,
uint level);
/* db-name is already validated when we come here */
-void mysql_create_db(THD *thd, char *db, uint create_options)
+int mysql_create_db(THD *thd, char *db, uint create_options, bool silent)
{
char path[FN_REFLEN+16];
MY_DIR *dirp;
long result=1;
+ int error = 0;
DBUG_ENTER("mysql_create_db");
-
+
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
- VOID(pthread_mutex_lock(&LOCK_open));
// do not create database if another thread is holding read lock
- if (global_read_lock)
+ if (wait_if_global_read_lock(thd,0))
{
- if (thd->global_read_lock)
- {
- net_printf(&thd->net, ER_CREATE_DB_WITH_READ_LOCK);
- VOID(pthread_mutex_unlock(&LOCK_open));
- goto exit;
- }
- while (global_read_lock && ! thd->killed)
- {
- (void) pthread_cond_wait(&COND_refresh,&LOCK_open);
- }
-
- if (thd->killed)
- {
- net_printf(&thd->net, ER_SERVER_SHUTDOWN);
- VOID(pthread_mutex_unlock(&LOCK_open));
- goto exit;
- }
-
+ error= -1;
+ goto exit2;
}
-
- VOID(pthread_mutex_unlock(&LOCK_open));
/* Check directory */
(void)sprintf(path,"%s/%s", mysql_data_home, db);
@@ -73,7 +56,8 @@ void mysql_create_db(THD *thd, char *db, uint create_options)
my_dirend(dirp);
if (!(create_options & HA_LEX_CREATE_IF_NOT_EXISTS))
{
- net_printf(&thd->net,ER_DB_CREATE_EXISTS,db);
+ my_error(ER_DB_CREATE_EXISTS,MYF(0),db);
+ error = -1;
goto exit;
}
result = 0;
@@ -83,137 +67,148 @@ void mysql_create_db(THD *thd, char *db, uint create_options)
strend(path)[-1]=0; // Remove last '/' from path
if (my_mkdir(path,0777,MYF(0)) < 0)
{
- net_printf(&thd->net,ER_CANT_CREATE_DB,db,my_errno);
+ my_error(ER_CANT_CREATE_DB,MYF(0),db,my_errno);
+ error = -1;
goto exit;
}
}
- if (!thd->query)
- {
- thd->query = path;
- thd->query_length = (uint) (strxmov(path,"create database ", db, NullS)-
- path);
- }
+
+ if (!silent)
{
- mysql_update_log.write(thd,thd->query, thd->query_length);
- if (mysql_bin_log.is_open())
+ if (!thd->query)
{
- Query_log_event qinfo(thd, thd->query);
- mysql_bin_log.write(&qinfo);
+ thd->query = path;
+ thd->query_length = (uint) (strxmov(path,"create database ", db, NullS)-
+ path);
}
+ {
+ mysql_update_log.write(thd,thd->query, thd->query_length);
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query);
+ mysql_bin_log.write(&qinfo);
+ }
+ }
+ if (thd->query == path)
+ {
+ thd->query = 0; // just in case
+ thd->query_length = 0;
+ }
+ send_ok(&thd->net, result);
}
- if (thd->query == path)
- {
- thd->query = 0; // just in case
- thd->query_length = 0;
- }
- send_ok(&thd->net, result);
exit:
+ start_waiting_global_read_lock(thd);
+exit2:
VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
- DBUG_VOID_RETURN;
+ DBUG_RETURN(error);
}
-const char *del_exts[]=
-{".frm",".ISM",".ISD",".ISM",".HSH",".DAT",".MRG",".MYI",".MYD", ".db", ".BAK", NullS};
+const char *del_exts[]= {".frm", ".BAK", ".TMD", NullS};
static TYPELIB deletable_extentions=
{array_elements(del_exts)-1,"del_exts", del_exts};
+const char *known_exts[]=
+{".ISM",".ISD",".ISM",".MRG",".MYI",".MYD",".db",NullS};
+static TYPELIB known_extentions=
+{array_elements(known_exts)-1,"known_exts", known_exts};
+
+/*
+ Drop all tables in a database.
+
+ db-name is already validated when we come here
+ If thd == 0, do not write any messages; This is useful in replication
+ when we want to remove a stale database before replacing it with the new one
+*/
-/* db-name is already validated when we come here */
-void mysql_rm_db(THD *thd,char *db,bool if_exists)
+int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
{
long deleted=0;
+ int error = 0;
char path[FN_REFLEN+16];
MY_DIR *dirp;
DBUG_ENTER("mysql_rm_db");
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
- VOID(pthread_mutex_lock(&LOCK_open));
// do not drop database if another thread is holding read lock
- if (global_read_lock)
+ if (wait_if_global_read_lock(thd,0))
{
- if (thd->global_read_lock)
- {
- net_printf(&thd->net, ER_DROP_DB_WITH_READ_LOCK);
- goto exit;
- }
- while (global_read_lock && ! thd->killed)
- {
- (void) pthread_cond_wait(&COND_refresh,&LOCK_open);
- }
-
- if (thd->killed)
- {
- net_printf(&thd->net, ER_SERVER_SHUTDOWN);
- goto exit;
- }
+ error= -1;
+ goto exit2;
}
(void) sprintf(path,"%s/%s",mysql_data_home,db);
unpack_dirname(path,path); // Convert if not unix
/* See if the directory exists */
- if (!(dirp = my_dir(path,MYF(MY_WME | MY_DONT_SORT))))
+ if (!(dirp = my_dir(path,MYF(MY_DONT_SORT))))
{
if (!if_exists)
- net_printf(&thd->net,ER_DB_DROP_EXISTS,db);
- else
+ {
+ error= -1;
+ my_error(ER_DB_DROP_EXISTS,MYF(0),db);
+ }
+ else if (!silent)
send_ok(&thd->net,0);
goto exit;
}
remove_db_from_cache(db);
- if ((deleted=mysql_rm_known_files(thd, dirp, path,0)) >= 0)
+ error = -1;
+ if ((deleted=mysql_rm_known_files(thd, dirp, db, path,0)) >= 0 && thd)
{
- if (!thd->query)
- {
- thd->query = path;
- thd->query_length = (uint) (strxmov(path,"drop database ", db, NullS)-
- path);
- }
- mysql_update_log.write(thd, thd->query, thd->query_length);
- if (mysql_bin_log.is_open())
- {
- Query_log_event qinfo(thd, thd->query);
- mysql_bin_log.write(&qinfo);
- }
- if (thd->query == path)
+ ha_drop_database(path);
+ query_cache.invalidate(db);
+ if (!silent)
{
- thd->query = 0; // just in case
- thd->query_length = 0;
+ if (!thd->query)
+ {
+ thd->query = path;
+ thd->query_length = (uint) (strxmov(path,"drop database ", db, NullS)-
+ path);
+ }
+ mysql_update_log.write(thd, thd->query, thd->query_length);
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query);
+ mysql_bin_log.write(&qinfo);
+ }
+ if (thd->query == path)
+ {
+ thd->query = 0; // just in case
+ thd->query_length = 0;
+ }
+ send_ok(&thd->net,(ulong) deleted);
}
- send_ok(&thd->net,(ulong) deleted);
+ error = 0;
}
exit:
- VOID(pthread_mutex_unlock(&LOCK_open));
+ start_waiting_global_read_lock(thd);
+exit2:
VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
- /* It seems MySQL may call this function when there still are queries
- running on tables of the database. Since InnoDB waits until the
- queries have ended, we have to call ha_drop_database outside
- the above two mutexes to avoid deadlocks. */
-
- ha_drop_database(path);
-
- DBUG_VOID_RETURN;
+ DBUG_RETURN(error);
}
/*
Removes files with known extensions plus all found subdirectories that
are 2 digits (raid directories).
+ thd MUST be set when calling this function!
*/
-static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *org_path,
- uint level)
+static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
+ const char *org_path, uint level)
{
long deleted=0;
ulong found_other_files=0;
char filePath[FN_REFLEN];
+ TABLE_LIST *tot_list=0, **tot_list_next;
DBUG_ENTER("mysql_rm_known_files");
DBUG_PRINT("enter",("path: %s", org_path));
- /* remove all files with known extensions */
+
+ tot_list_next= &tot_list;
for (uint idx=2 ;
idx < (uint) dirp->number_off_files && !thd->killed ;
@@ -233,7 +228,7 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *org_path,
if ((new_dirp = my_dir(newpath,MYF(MY_DONT_SORT))))
{
DBUG_PRINT("my",("New subdir found: %s", newpath));
- if ((mysql_rm_known_files(thd,new_dirp,newpath,1)) < 0)
+ if ((mysql_rm_known_files(thd, new_dirp, NullS, newpath,1)) < 0)
{
my_dirend(dirp);
DBUG_RETURN(-1);
@@ -243,27 +238,44 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *org_path,
}
if (find_type(fn_ext(file->name),&deletable_extentions,1+2) <= 0)
{
- found_other_files++;
+ if (find_type(fn_ext(file->name),&known_extentions,1+2) <= 0)
+ found_other_files++;
continue;
}
strxmov(filePath,org_path,"/",file->name,NullS);
- unpack_filename(filePath,filePath);
- if (my_delete(filePath,MYF(MY_WME)))
+ if (db && !my_strcasecmp(fn_ext(file->name), reg_ext))
{
- net_printf(&thd->net,ER_DB_DROP_DELETE,filePath,my_error);
- my_dirend(dirp);
- DBUG_RETURN(-1);
+ /* Drop the table nicely */
+ *fn_ext(file->name)=0; // Remove extension
+ TABLE_LIST *table_list=(TABLE_LIST*)
+ thd->calloc(sizeof(*table_list)+ strlen(db)+strlen(file->name)+2);
+ if (!table_list)
+ {
+ my_dirend(dirp);
+ DBUG_RETURN(-1);
+ }
+ table_list->db= (char*) (table_list+1);
+ strmov(table_list->real_name=strmov(table_list->db,db)+1,
+ file->name);
+ /* Link into list */
+ (*tot_list_next)= table_list;
+ tot_list_next= &table_list->next;
}
- deleted++;
- }
+ else
+ {
+ if (my_delete_with_symlink(filePath,MYF(MY_WME)))
+ {
+ my_dirend(dirp);
+ DBUG_RETURN(-1);
+ }
+ deleted++;
+ }
+ }
my_dirend(dirp);
- if (thd->killed)
- {
- send_error(&thd->net,ER_SERVER_SHUTDOWN);
+ if (thd->killed || (tot_list && mysql_rm_table_part2(thd, tot_list, 1, 1)))
DBUG_RETURN(-1);
- }
/*
If the directory is a symbolic link, remove the link first, then
@@ -283,20 +295,19 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *org_path,
/* Don't give errors if we can't delete 'RAID' directory */
if (level)
DBUG_RETURN(deleted);
- send_error(&thd->net);
DBUG_RETURN(-1);
}
path=filePath;
}
#endif
- /* Remove last FN_LIBCHAR to not cause a probelm on OS/2 */
+ /* Remove last FN_LIBCHAR to not cause a problem on OS/2 */
char *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)
{
- net_printf(&thd->net,ER_DB_DROP_RMDIR, path,errno);
+ my_error(ER_DB_DROP_RMDIR, MYF(0), path, errno);
DBUG_RETURN(-1);
}
}
@@ -306,25 +317,25 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *org_path,
bool mysql_change_db(THD *thd,const char *name)
{
- int length;
+ int length, db_length;
char *dbname=my_strdup((char*) name,MYF(MY_WME));
char path[FN_REFLEN];
uint db_access;
DBUG_ENTER("mysql_change_db");
- if (!dbname || !(length=stripp_sp(dbname)))
+ if (!dbname || !(db_length=stripp_sp(dbname)))
{
x_free(dbname); /* purecov: inspected */
send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
- if ((length > NAME_LEN) || check_db_name(dbname))
+ if ((db_length > NAME_LEN) || check_db_name(dbname))
{
net_printf(&thd->net,ER_WRONG_DB_NAME, dbname);
x_free(dbname);
DBUG_RETURN(1);
}
- DBUG_PRINT("general",("Use database: %s", dbname));
+ DBUG_PRINT("info",("Use database: %s", dbname));
if (test_all_bits(thd->master_access,DB_ACLS))
db_access=DB_ACLS;
else
@@ -335,11 +346,11 @@ bool mysql_change_db(THD *thd,const char *name)
{
net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR,
thd->priv_user,
- thd->host ? thd->host : thd->ip ? thd->ip : "unknown",
+ thd->host_or_ip,
dbname);
mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
thd->priv_user,
- thd->host ? thd->host : thd->ip ? thd->ip : "unknown",
+ thd->host_or_ip,
dbname);
my_free(dbname,MYF(0));
DBUG_RETURN(1);
@@ -358,6 +369,7 @@ bool mysql_change_db(THD *thd,const char *name)
send_ok(&thd->net);
x_free(thd->db);
thd->db=dbname;
+ thd->db_length=db_length;
thd->db_access=db_access;
DBUG_RETURN(0);
}
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 930e71d7678..a155abc522b 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* 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
@@ -15,118 +15,28 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/* Delete of records */
-
-#include "mysql_priv.h"
-#include "ha_innobase.h"
-
/*
- Optimize delete of all rows by doing a full generate of the table
- This will work even if the .ISM and .ISD tables are destroyed
-*/
-
-int generate_table(THD *thd, TABLE_LIST *table_list, TABLE *locked_table)
-{
- char path[FN_REFLEN];
- int error;
- TABLE **table_ptr;
- DBUG_ENTER("generate_table");
-
- thd->proc_info="generate_table";
+ Delete of records and truncate of tables.
- if (global_read_lock)
- {
- if(thd->global_read_lock)
- {
- my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE,MYF(0),
- table_list->real_name);
- DBUG_RETURN(-1);
- }
- pthread_mutex_lock(&LOCK_open);
- while (global_read_lock && ! thd->killed ||
- thd->version != refresh_version)
- {
- (void) pthread_cond_wait(&COND_refresh,&LOCK_open);
- }
- pthread_mutex_unlock(&LOCK_open);
- }
+ Multi-table deletes were introduced by Monty and Sinisa
+*/
- /* If it is a temporary table, close and regenerate it */
- if ((table_ptr=find_temporary_table(thd,table_list->db,
- table_list->real_name)))
- {
- TABLE *table= *table_ptr;
- HA_CREATE_INFO create_info;
- table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK);
- bzero((char*) &create_info,sizeof(create_info));
- create_info.auto_increment_value= table->file->auto_increment_value;
- db_type table_type=table->db_type;
- strmov(path,table->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);
- if ((error= (int) !(open_temporary_table(thd, path, table_list->db,
- table_list->real_name, 1))))
- {
- (void) rm_temporary_table(table_type, path);
- }
- }
- else
- {
- (void) sprintf(path,"%s/%s/%s%s",mysql_data_home,table_list->db,
- table_list->real_name,reg_ext);
- fn_format(path,path,"","",4);
- VOID(pthread_mutex_lock(&LOCK_open));
- if (locked_table)
- mysql_lock_abort(thd,locked_table); // end threads waiting on lock
- // close all copies in use
- if (remove_table_from_cache(thd,table_list->db,table_list->real_name))
- {
- if (!locked_table)
- {
- VOID(pthread_mutex_unlock(&LOCK_open));
- DBUG_RETURN(1); // We must get a lock on table
- }
- }
- if (locked_table)
- locked_table->file->extra(HA_EXTRA_FORCE_REOPEN);
- if (thd->locked_tables)
- close_data_tables(thd,table_list->db,table_list->real_name);
- else
- close_thread_tables(thd,1);
- HA_CREATE_INFO create_info;
- bzero((char*) &create_info,sizeof(create_info));
- *fn_ext(path)=0; // Remove the .frm extension
- error= ha_create_table(path,&create_info,1) ? -1 : 0;
- if (thd->locked_tables && reopen_tables(thd,1,0))
- error= -1;
- VOID(pthread_mutex_unlock(&LOCK_open));
- }
- if (!error)
- {
- mysql_update_log.write(thd,thd->query,thd->query_length);
- if (mysql_bin_log.is_open())
- {
- Query_log_event qinfo(thd, thd->query);
- mysql_bin_log.write(&qinfo);
- }
- send_ok(&thd->net); // This should return record count
- }
- DBUG_RETURN(error ? -1 : 0);
-}
+#include "mysql_priv.h"
+#include "ha_innodb.h"
+#include "sql_select.h"
-int mysql_delete(THD *thd,TABLE_LIST *table_list,COND *conds,ha_rows limit,
- thr_lock_type lock_type, ulong options)
+int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
+ ha_rows limit, thr_lock_type lock_type, ulong options)
{
int error;
TABLE *table;
- SQL_SELECT *select;
+ SQL_SELECT *select=0;
READ_RECORD info;
- bool using_limit=limit != HA_POS_ERROR;
- bool use_generate_table,using_transactions;
+ bool using_limit=limit != HA_POS_ERROR;
+ bool using_transactions;
+ ha_rows deleted;
DBUG_ENTER("mysql_delete");
if (!table_list->db)
@@ -137,40 +47,39 @@ int mysql_delete(THD *thd,TABLE_LIST *table_list,COND *conds,ha_rows limit,
DBUG_RETURN(1);
}
- use_generate_table= (!using_limit && !conds &&
- !(specialflag &
- (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) &&
- !(thd->options &
- (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN)));
-#ifdef HAVE_INNOBASE_DB
- /* We need to add code to not generate table based on the table type */
- if (!innodb_skip)
- use_generate_table=0; // Innodb can't use re-generate table
-#endif
- if (use_generate_table && ! thd->open_tables)
- {
- error=generate_table(thd,table_list,(TABLE*) 0);
- if (error <= 0)
- DBUG_RETURN(error); // Error or ok
- }
- if (!(table = open_ltable(thd,table_list,
- limit != HA_POS_ERROR ? TL_WRITE_LOW_PRIORITY :
- lock_type)))
+ if (!(table = open_ltable(thd,table_list, lock_type)))
DBUG_RETURN(-1);
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
thd->proc_info="init";
- if (use_generate_table)
- DBUG_RETURN(generate_table(thd,table_list,table));
table->map=1;
if (setup_conds(thd,table_list,&conds) || setup_ftfuncs(thd))
DBUG_RETURN(-1);
+ /* Test if the user wants to delete all rows */
+ if (!using_limit && (!conds || conds->const_item()) &&
+ !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)))
+ {
+ deleted= table->file->records;
+ if (!(error=table->file->delete_all_rows()))
+ {
+ error= -1; // ok
+ goto cleanup;
+ }
+ if (error != HA_ERR_WRONG_COMMAND)
+ {
+ table->file->print_error(error,MYF(0));
+ error=0;
+ goto cleanup;
+ }
+ /* Handler didn't support fast delete; Delete rows one by one */
+ }
+
table->used_keys=table->quick_keys=0; // Can't use 'only index'
select=make_select(table,0,0,conds,&error);
if (error)
DBUG_RETURN(-1);
if ((select && select->check_quick(test(thd->options & SQL_SAFE_UPDATES),
- limit)) ||
+ limit)) ||
!limit)
{
delete select;
@@ -181,7 +90,7 @@ int mysql_delete(THD *thd,TABLE_LIST *table_list,COND *conds,ha_rows limit,
/* If running in safe sql mode, don't allow updates without keys */
if (!table->quick_keys)
{
- thd->lex.options|=QUERY_NO_INDEX_USED;
+ thd->lex.select_lex.options|=QUERY_NO_INDEX_USED;
if ((thd->options & OPTION_SAFE_UPDATES) && limit == HA_POS_ERROR)
{
delete select;
@@ -189,11 +98,37 @@ int mysql_delete(THD *thd,TABLE_LIST *table_list,COND *conds,ha_rows limit,
DBUG_RETURN(1);
}
}
- (void) table->file->extra(HA_EXTRA_NO_READCHECK);
if (options & OPTION_QUICK)
(void) table->file->extra(HA_EXTRA_QUICK);
- init_read_record(&info,thd,table,select,-1,1);
- ulong deleted=0L;
+
+ if (order)
+ {
+ uint length;
+ SORT_FIELD *sortorder;
+ TABLE_LIST tables;
+ List<Item> fields;
+ List<Item> all_fields;
+ ha_rows examined_rows;
+
+ bzero((char*) &tables,sizeof(tables));
+ tables.table = table;
+
+ table->io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
+ MYF(MY_FAE | MY_ZEROFILL));
+ if (setup_order(thd, &tables, fields, all_fields, order) ||
+ !(sortorder=make_unireg_sortorder(order, &length)) ||
+ (table->found_records = filesort(table, sortorder, length,
+ (SQL_SELECT *) 0, 0L, HA_POS_ERROR,
+ &examined_rows))
+ == HA_POS_ERROR)
+ {
+ delete select;
+ DBUG_RETURN(-1); // This will force out message
+ }
+ }
+
+ init_read_record(&info,thd,table,select,1,1);
+ deleted=0L;
init_ftfuncs(thd,1);
thd->proc_info="updating";
while (!(error=info.read_record(&info)) && !thd->killed)
@@ -221,9 +156,11 @@ int mysql_delete(THD *thd,TABLE_LIST *table_list,COND *conds,ha_rows limit,
}
thd->proc_info="end";
end_read_record(&info);
- (void) table->file->extra(HA_EXTRA_READCHECK);
+ free_io_cache(table); // Will not do any harm
if (options & OPTION_QUICK)
(void) table->file->extra(HA_EXTRA_NORMAL);
+
+cleanup:
using_transactions=table->file->has_transactions();
if (deleted && (error <= 0 || !using_transactions))
{
@@ -244,6 +181,8 @@ int mysql_delete(THD *thd,TABLE_LIST *table_list,COND *conds,ha_rows limit,
mysql_unlock_tables(thd, thd->lock);
thd->lock=0;
}
+ if (deleted)
+ query_cache.invalidate(table_list);
delete select;
if (error >= 0) // Fatal error
send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN: 0);
@@ -255,3 +194,377 @@ int mysql_delete(THD *thd,TABLE_LIST *table_list,COND *conds,ha_rows limit,
DBUG_RETURN(0);
}
+
+/***************************************************************************
+** delete multiple tables from join
+***************************************************************************/
+
+#define MEM_STRIP_BUF_SIZE sortbuff_size
+
+int refposcmp2(void* arg, const void *a,const void *b)
+{
+ return memcmp(a,b, *(int*) arg);
+}
+
+multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt,
+ thr_lock_type lock_option_arg,
+ uint num_of_tables_arg)
+ : delete_tables (dt), thd(thd_arg), deleted(0),
+ num_of_tables(num_of_tables_arg), error(0), lock_option(lock_option_arg),
+ do_delete(false)
+{
+ uint counter=0;
+ not_trans_safe=false;
+ tempfiles = (Unique **) sql_calloc(sizeof(Unique *) * (num_of_tables-1));
+
+ /* Don't use key read with MULTI-TABLE-DELETE */
+ dt->table->used_keys=0;
+ for (dt=dt->next ; dt ; dt=dt->next,counter++)
+ {
+ TABLE *table=dt->table;
+ table->used_keys=0;
+ tempfiles[counter] = new Unique (refposcmp2,
+ (void *) &table->file->ref_length,
+ table->file->ref_length,
+ MEM_STRIP_BUF_SIZE);
+ }
+}
+
+
+int
+multi_delete::prepare(List<Item> &values)
+{
+ DBUG_ENTER("multi_delete::prepare");
+ do_delete = true;
+ thd->proc_info="deleting from main table";
+
+ if (thd->options & OPTION_SAFE_UPDATES)
+ {
+ TABLE_LIST *table_ref;
+ for (table_ref=delete_tables; table_ref; table_ref=table_ref->next)
+ {
+ TABLE *table=table_ref->table;
+ if ((thd->options & OPTION_SAFE_UPDATES) && !table->quick_keys)
+ {
+ my_error(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,MYF(0));
+ DBUG_RETURN(1);
+ }
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+
+void
+multi_delete::initialize_tables(JOIN *join)
+{
+ TABLE_LIST *walk;
+ table_map tables_to_delete_from=0;
+ for (walk= delete_tables ; walk ; walk=walk->next)
+ tables_to_delete_from|= walk->table->map;
+
+ walk= delete_tables;
+ for (JOIN_TAB *tab=join->join_tab, *end=join->join_tab+join->tables;
+ tab < end;
+ tab++)
+ {
+ if (tab->table->map & tables_to_delete_from)
+ {
+ /* We are going to delete from this table */
+ walk->table=tab->table;
+ walk=walk->next;
+ if (tab == join->join_tab)
+ tab->table->no_keyread=1;
+ if (!not_trans_safe && !tab->table->file->has_transactions())
+ not_trans_safe=true;
+ }
+ }
+ init_ftfuncs(thd,1);
+}
+
+
+multi_delete::~multi_delete()
+{
+ for (table_being_deleted=delete_tables ;
+ table_being_deleted ;
+ table_being_deleted=table_being_deleted->next)
+ {
+ TABLE *t=table_being_deleted->table;
+ free_io_cache(t); // Alloced by unique
+ t->no_keyread=0;
+ }
+
+ for (uint counter = 0; counter < num_of_tables-1; counter++)
+ {
+ if (tempfiles[counter])
+ delete tempfiles[counter];
+ }
+}
+
+
+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++)
+ {
+ TABLE *table=table_being_deleted->table;
+
+ /* Check if we are using outer join and we didn't find the row */
+ if (table->status & (STATUS_NULL_ROW | STATUS_DELETED))
+ continue;
+
+ table->file->position(table->record[0]);
+
+ if (secure_counter < 0)
+ {
+ /* If this is the table we are scanning */
+ table->status|= STATUS_DELETED;
+ if (!(error=table->file->delete_row(table->record[0])))
+ deleted++;
+ else
+ {
+ table->file->print_error(error,MYF(0));
+ DBUG_RETURN(1);
+ }
+ }
+ else
+ {
+ error=tempfiles[secure_counter]->unique_add((char*) table->file->ref);
+ if (error)
+ {
+ error=-1;
+ DBUG_RETURN(1);
+ }
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+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->net,errcode,err);
+
+ /* If nothing deleted return */
+ if (!deleted)
+ DBUG_VOID_RETURN;
+
+ /* Below can happen when thread is killed early ... */
+ if (!table_being_deleted)
+ table_being_deleted=delete_tables;
+
+ /*
+ If rows from the first table only has been deleted and it is
+ transactional, just do rollback.
+ The same if all tables are transactional, regardless of where we are.
+ In all other cases do attempt deletes ...
+ */
+ if ((table_being_deleted->table->file->has_transactions() &&
+ table_being_deleted == delete_tables) || !not_trans_safe)
+ ha_rollback_stmt(thd);
+ else if (do_delete)
+ {
+ VOID(do_deletes(1));
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Do delete from other tables.
+ Returns values:
+ 0 ok
+ 1 error
+*/
+
+int multi_delete::do_deletes(bool from_send_error)
+{
+ int error = 0, counter = 0;
+
+ if (from_send_error)
+ {
+ /* Found out table number for 'table_being_deleted' */
+ for (TABLE_LIST *aux=delete_tables;
+ aux != table_being_deleted;
+ aux=aux->next)
+ counter++;
+ }
+ else
+ table_being_deleted = delete_tables;
+
+ do_delete = false;
+ for (table_being_deleted=table_being_deleted->next;
+ table_being_deleted ;
+ table_being_deleted=table_being_deleted->next, counter++)
+ {
+ TABLE *table = table_being_deleted->table;
+ if (tempfiles[counter]->get(table))
+ {
+ error=1;
+ break;
+ }
+
+ READ_RECORD info;
+ init_read_record(&info,thd,table,NULL,0,0);
+ while (!(error=info.read_record(&info)) &&
+ (!thd->killed || from_send_error || not_trans_safe))
+ {
+ if ((error=table->file->delete_row(table->record[0])))
+ {
+ table->file->print_error(error,MYF(0));
+ break;
+ }
+ deleted++;
+ }
+ end_read_record(&info);
+ if (error == -1) // End of file
+ error = 0;
+ }
+ return error;
+}
+
+
+/*
+ return: 0 sucess
+ 1 error
+*/
+
+bool multi_delete::send_eof()
+{
+ thd->proc_info="deleting from reference tables";
+
+ /* Does deletes for the last n - 1 tables, returns 0 if ok */
+ int error = do_deletes(0); // returns 0 if success
+
+ /* reset used flags */
+ thd->proc_info="end";
+ if (error)
+ {
+ ::send_error(&thd->net);
+ return 1;
+ }
+
+ /*
+ Write the SQL statement to the binlog if we deleted
+ rows and we succeeded, or also in an error case when there
+ was a non-transaction-safe table involved, since
+ modifications in it cannot be rolled back.
+ */
+ if (deleted || not_trans_safe)
+ {
+ mysql_update_log.write(thd,thd->query,thd->query_length);
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query);
+ if (mysql_bin_log.write(&qinfo) &&
+ !not_trans_safe)
+ error=1; // Log write failed: roll back the SQL statement
+ }
+ /* Commit or rollback the current SQL statement */
+ VOID(ha_autocommit_or_rollback(thd,error > 0));
+ }
+ if (deleted)
+ query_cache.invalidate(delete_tables);
+ ::send_ok(&thd->net,deleted);
+ return 0;
+}
+
+
+/***************************************************************************
+* TRUNCATE TABLE
+****************************************************************************/
+
+/*
+ Optimize delete of all rows by doing a full generate of the table
+ This will work even if the .ISM and .ISD tables are destroyed
+
+ dont_send_ok should be set if:
+ - We should always wants to generate the table (even if the table type
+ normally can't safely do this.
+ - We don't want an ok to be sent to the end user.
+ - We don't want to log the truncate command
+ - 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)
+{
+ HA_CREATE_INFO create_info;
+ char path[FN_REFLEN];
+ TABLE **table_ptr;
+ int error;
+ DBUG_ENTER("mysql_truncate");
+
+ /* 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 *table= *table_ptr;
+ HA_CREATE_INFO create_info;
+ table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK);
+ bzero((char*) &create_info,sizeof(create_info));
+ create_info.auto_increment_value= table->file->auto_increment_value;
+ db_type table_type=table->db_type;
+
+ strmov(path,table->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))))
+ (void) rm_temporary_table(table_type, path);
+ DBUG_RETURN(error ? -1 : 0);
+ }
+
+ (void) sprintf(path,"%s/%s/%s%s",mysql_data_home,table_list->db,
+ table_list->real_name,reg_ext);
+ fn_format(path,path,"","",4);
+
+ if (!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->real_name);
+ DBUG_RETURN(-1);
+ }
+ if (!ha_supports_generate(table_type))
+ {
+ /* Probably InnoDB table */
+ DBUG_RETURN(mysql_delete(thd,table_list, (COND*) 0, (ORDER*) 0,
+ HA_POS_ERROR, TL_WRITE, 0));
+ }
+ if (lock_and_wait_for_table_name(thd, table_list))
+ DBUG_RETURN(-1);
+ }
+
+ bzero((char*) &create_info,sizeof(create_info));
+ *fn_ext(path)=0; // Remove the .frm extension
+ error= ha_create_table(path,&create_info,1) ? -1 : 0;
+ query_cache.invalidate(table_list);
+
+ if (!dont_send_ok)
+ {
+ if (!error)
+ {
+ mysql_update_log.write(thd,thd->query,thd->query_length);
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query);
+ mysql_bin_log.write(&qinfo);
+ }
+ send_ok(&thd->net); // This should return record count
+ }
+ unlock_table_name(thd, table_list);
+ }
+ else if (error)
+ unlock_table_name(thd, table_list);
+ DBUG_RETURN(error ? -1 : 0);
+}
diff --git a/sql/sql_do.cc b/sql/sql_do.cc
index 57a6f88ed63..70124c2d796 100644
--- a/sql/sql_do.cc
+++ b/sql/sql_do.cc
@@ -25,7 +25,7 @@ int mysql_do(THD *thd, List<Item> &values)
List_iterator<Item> li(values);
Item *value;
DBUG_ENTER("mysql_do");
- if (setup_fields(thd,0, values, 0, 0))
+ if (setup_fields(thd,0, values, 0, 0, 0))
DBUG_RETURN(-1);
while ((value = li++))
value->val_int();
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
new file mode 100644
index 00000000000..8f9d3474ce2
--- /dev/null
+++ b/sql/sql_handler.cc
@@ -0,0 +1,278 @@
+/* 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 */
+
+
+/* HANDLER ... commands - direct access to ISAM */
+
+#include <assert.h>
+#include "mysql_priv.h"
+#include "sql_select.h"
+
+/* TODO:
+ HANDLER blabla OPEN [ AS foobar ] [ (column-list) ]
+
+ the most natural (easiest, fastest) way to do it is to
+ compute List<Item> field_list not in mysql_ha_read
+ but in mysql_ha_open, and then store it in TABLE structure.
+
+ The problem here is that mysql_parse calls free_item to free all the
+ items allocated at the end of every query. The workaround would to
+ keep two item lists per THD - normal free_list and handler_items.
+ The second is to be freeed only on thread end. mysql_ha_open should
+ then do { handler_items=concat(handler_items, free_list); free_list=0; }
+
+ But !!! do_cammand calls free_root at the end of every query and frees up
+ all the sql_alloc'ed memory. It's harder to work around...
+ */
+
+#define HANDLER_TABLES_HACK(thd) { \
+ TABLE *tmp=thd->open_tables; \
+ thd->open_tables=thd->handler_tables; \
+ thd->handler_tables=tmp; }
+
+static TABLE **find_table_ptr_by_name(THD *thd, const char *db,
+ const char *table_name);
+
+int mysql_ha_open(THD *thd, TABLE_LIST *tables)
+{
+ HANDLER_TABLES_HACK(thd);
+ int err=open_tables(thd,tables);
+ HANDLER_TABLES_HACK(thd);
+ if (err)
+ return -1;
+
+ // there can be only one table in *tables
+ if (!(tables->table->file->option_flag() & HA_CAN_SQL_HANDLER))
+ {
+ my_printf_error(ER_ILLEGAL_HA,ER(ER_ILLEGAL_HA),MYF(0), tables->name);
+ mysql_ha_close(thd, tables,1);
+ return -1;
+ }
+
+ send_ok(&thd->net);
+ return 0;
+}
+
+int mysql_ha_close(THD *thd, TABLE_LIST *tables, bool dont_send_ok)
+{
+ TABLE **ptr=find_table_ptr_by_name(thd, tables->db, tables->name);
+
+ if (*ptr)
+ {
+ VOID(pthread_mutex_lock(&LOCK_open));
+ close_thread_table(thd, ptr);
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ }
+ else
+ {
+ my_printf_error(ER_UNKNOWN_TABLE,ER(ER_UNKNOWN_TABLE),MYF(0),
+ tables->name,"HANDLER");
+ return -1;
+ }
+ if (!dont_send_ok)
+ send_ok(&thd->net);
+ return 0;
+}
+
+static enum enum_ha_read_modes rkey_to_rnext[]=
+ { RNEXT, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV };
+
+
+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)
+{
+ int err, keyno=-1;
+ TABLE *table=*find_table_ptr_by_name(thd, tables->db, tables->name);
+ if (!table)
+ {
+ my_printf_error(ER_UNKNOWN_TABLE,ER(ER_UNKNOWN_TABLE),MYF(0),
+ tables->name,"HANDLER");
+ return -1;
+ }
+ tables->table=table;
+
+ if (cond && cond->fix_fields(thd,tables))
+ return -1;
+
+ if (keyname)
+ {
+ if ((keyno=find_type(keyname, &table->keynames, 1+2)-1)<0)
+ {
+ my_printf_error(ER_KEY_DOES_NOT_EXITS,ER(ER_KEY_DOES_NOT_EXITS),MYF(0),
+ keyname,tables->name);
+ return -1;
+ }
+ }
+
+ List<Item> list;
+ list.push_front(new Item_field(NULL,NULL,"*"));
+ List_iterator<Item> it(list);
+ uint num_rows;
+ it++;
+
+ insert_fields(thd,tables,tables->db,tables->name,&it);
+
+ table->file->index_init(keyno);
+
+ select_limit+=offset_limit;
+ send_fields(thd,list,1);
+
+ HANDLER_TABLES_HACK(thd);
+ MYSQL_LOCK *lock=mysql_lock_tables(thd,&tables->table,1);
+ HANDLER_TABLES_HACK(thd);
+ if (!lock)
+ goto err0; // mysql_lock_tables() printed error message already
+
+ for (num_rows=0; num_rows < select_limit; )
+ {
+ switch(mode) {
+ case RFIRST:
+ err=keyname ?
+ table->file->index_first(table->record[0]) :
+ table->file->rnd_init(1) ||
+ table->file->rnd_next(table->record[0]);
+ mode=RNEXT;
+ break;
+ case RLAST:
+ DBUG_ASSERT(keyname != 0);
+ err=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]);
+ break;
+ case RPREV:
+ DBUG_ASSERT(keyname != 0);
+ err=table->file->index_prev(table->record[0]);
+ break;
+ case RKEY:
+ {
+ DBUG_ASSERT(keyname != 0);
+ KEY *keyinfo=table->key_info+keyno;
+ KEY_PART_INFO *key_part=keyinfo->key_part;
+ uint key_len;
+ byte *key;
+ 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);
+ goto err;
+ }
+ List_iterator_fast<Item> it_ke(*key_expr);
+ Item *item;
+ for (key_len=0 ; (item=it_ke++) ; key_part++)
+ {
+ item->save_in_field(key_part->field);
+ key_len+=key_part->store_length;
+ }
+ if (!(key= (byte*) sql_calloc(ALIGN_SIZE(key_len))))
+ {
+ send_error(&thd->net,ER_OUTOFMEMORY);
+ goto err;
+ }
+ key_copy(key, table, keyno, key_len);
+ err=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->net,ER_ILLEGAL_HA);
+ goto err;
+ }
+
+ if (err)
+ {
+ if (err != HA_ERR_KEY_NOT_FOUND && err != HA_ERR_END_OF_FILE)
+ {
+ sql_print_error("mysql_ha_read: Got error %d when reading table",
+ err);
+ table->file->print_error(err,MYF(0));
+ goto err;
+ }
+ goto ok;
+ }
+ if (cond)
+ {
+ err=err;
+ if(!cond->val_int())
+ continue;
+ }
+ if (num_rows>=offset_limit)
+ {
+ if (!err)
+ {
+ String *packet = &thd->packet;
+ Item *item;
+ packet->length(0);
+ it.rewind();
+ while ((item=it++))
+ {
+ if (item->send(thd,packet))
+ {
+ packet->free(); // Free used
+ my_error(ER_OUT_OF_RESOURCES,MYF(0));
+ goto err;
+ }
+ }
+ my_net_write(&thd->net, (char*)packet->ptr(), packet->length());
+ }
+ }
+ num_rows++;
+ }
+ok:
+ mysql_unlock_tables(thd,lock);
+ send_eof(&thd->net);
+ return 0;
+err:
+ mysql_unlock_tables(thd,lock);
+err0:
+ return -1;
+}
+
+/**************************************************************************
+ 2Monty: It could easily happen, that the following service functions are
+ already defined somewhere in the code, but I failed to find them.
+ If this is the case, just say a word and I'll use old functions here.
+**************************************************************************/
+
+/* Note: this function differs from find_locked_table() because we're looking
+ here for alias, not real table name
+ */
+static TABLE **find_table_ptr_by_name(THD *thd, const char *db,
+ const char *table_name)
+{
+ int dblen;
+ TABLE **ptr;
+
+ if (!db || ! *db)
+ db= thd->db ? thd->db : "";
+ dblen=strlen(db)+1;
+ ptr=&(thd->handler_tables);
+
+ for (TABLE *table=*ptr; table ; table=*ptr)
+ {
+ if (!memcmp(table->table_cache_key, db, dblen) &&
+ !my_strcasecmp(table->table_name,table_name))
+ break;
+ ptr=&(table->next);
+ }
+ return ptr;
+}
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index d8861390d87..0898ad4bffb 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -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 */
@@ -78,7 +78,8 @@ check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
table_list.grant=table->grant;
thd->dupp_field=0;
- if (setup_tables(&table_list) || setup_fields(thd,&table_list,fields,1,0))
+ if (setup_tables(&table_list) ||
+ setup_fields(thd,&table_list,fields,1,0,0))
return -1;
if (thd->dupp_field)
{
@@ -102,14 +103,14 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
int error;
bool log_on= ((thd->options & OPTION_UPDATE_LOG) ||
!(thd->master_access & PROCESS_ACL));
- bool using_transactions;
+ bool using_transactions, bulk_insert=0;
uint value_count;
uint save_time_stamp;
ulong counter = 1;
ulonglong id;
COPY_INFO info;
TABLE *table;
- List_iterator<List_item> its(values_list);
+ List_iterator_fast<List_item> its(values_list);
List_item *values;
char *query=thd->query;
DBUG_ENTER("mysql_insert");
@@ -151,7 +152,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
save_time_stamp=table->time_stamp;
values= its++;
if (check_insert_fields(thd,table,fields,*values,1) ||
- setup_tables(table_list) || setup_fields(thd,table_list,*values,0,0))
+ setup_tables(table_list) || setup_fields(thd,table_list,*values,0,0,0))
{
table->time_stamp=save_time_stamp;
goto abort;
@@ -168,7 +169,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
table->time_stamp=save_time_stamp;
goto abort;
}
- if (setup_fields(thd,table_list,*values,0,0))
+ if (setup_fields(thd,table_list,*values,0,0,0))
{
table->time_stamp=save_time_stamp;
goto abort;
@@ -192,6 +193,14 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
thd->proc_info="update";
if (duplic == DUP_IGNORE || duplic == DUP_REPLACE)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
+ if ((bulk_insert= (values_list.elements > 1 &&
+ lock_type != TL_WRITE_DELAYED &&
+ !(specialflag & SPECIAL_SAFE_MODE))))
+ {
+ table->file->extra(HA_EXTRA_WRITE_CACHE);
+ table->file->extra(HA_EXTRA_BULK_INSERT_BEGIN);
+ }
+
while ((values = its++))
{
if (fields.elements || !value_count)
@@ -256,6 +265,25 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
}
else
{
+ if (bulk_insert)
+ {
+ if (table->file->extra(HA_EXTRA_NO_CACHE))
+ {
+ if (!error)
+ {
+ table->file->print_error(my_errno,MYF(0));
+ error=1;
+ }
+ }
+ if (table->file->extra(HA_EXTRA_BULK_INSERT_END))
+ {
+ if (!error)
+ {
+ table->file->print_error(my_errno,MYF(0));
+ error=1;
+ }
+ }
+ }
if (id && values_list.elements != 1)
thd->insert_id(id); // For update log
else if (table->next_number_field)
@@ -282,13 +310,14 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
}
}
thd->proc_info="end";
+ if (info.copied || info.deleted)
+ query_cache.invalidate(table_list);
table->time_stamp=save_time_stamp; // Restore auto timestamp ptr
table->next_number_field=0;
thd->count_cuted_fields=0;
thd->next_insert_id=0; // Reset this if wrongly used
if (duplic == DUP_IGNORE || duplic == DUP_REPLACE)
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
-
if (error)
goto abort;
@@ -335,18 +364,18 @@ int write_record(TABLE *table,COPY_INFO *info)
{
int error;
char *key=0;
-
+
info->records++;
if (info->handle_duplicates == DUP_REPLACE)
{
while ((error=table->file->write_row(table->record[0])))
{
- if (error != HA_WRITE_SKIPP)
+ if (error != HA_WRITE_SKIP)
goto err;
uint key_nr;
if ((int) (key_nr = table->file->get_dup_key(error)) < 0)
{
- error=HA_WRITE_SKIPP; /* Database can't find key */
+ error=HA_WRITE_SKIP; /* Database can't find key */
goto err;
}
/*
@@ -364,12 +393,12 @@ int write_record(TABLE *table,COPY_INFO *info)
}
else
{
- if (table->file->extra(HA_EXTRA_FLUSH_CACHE)) /* Not neaded with NISAM */
+ if (table->file->extra(HA_EXTRA_FLUSH_CACHE)) /* Not needed with NISAM */
{
error=my_errno;
goto err;
}
-
+
if (!key)
{
if (!(key=(char*) my_safe_alloca(table->max_unique_length,
@@ -507,7 +536,7 @@ public:
}
~delayed_insert()
{
- /* The following is not really neaded, but just for safety */
+ /* The following is not really needed, but just for safety */
delayed_row *row;
while ((row=rows.get()))
delete row;
@@ -646,7 +675,7 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
/* Copy error message and abort */
thd->fatal_error=1;
strmov(thd->net.last_error,tmp->thd.net.last_error);
- thd->net.last_errno=thd->net.last_errno;
+ thd->net.last_errno=tmp->thd.net.last_errno;
}
tmp->unlock();
pthread_mutex_unlock(&LOCK_delayed_create);
@@ -710,9 +739,9 @@ TABLE *delayed_insert::get_local_table(THD* client_thd)
}
client_thd->proc_info="allocating local table";
- copy= (TABLE*) sql_alloc(sizeof(*copy)+
- (table->fields+1)*sizeof(Field**)+
- table->reclength);
+ copy= (TABLE*) client_thd->alloc(sizeof(*copy)+
+ (table->fields+1)*sizeof(Field**)+
+ table->reclength);
if (!copy)
goto error;
*copy= *table;
@@ -730,7 +759,7 @@ TABLE *delayed_insert::get_local_table(THD* client_thd)
found_next_number_field=table->found_next_number_field;
for (org_field=table->field ; *org_field ; org_field++,field++)
{
- if (!(*field= (*org_field)->new_field(copy)))
+ if (!(*field= (*org_field)->new_field(&client_thd->mem_root,copy)))
return 0;
(*field)->move_field(adjust_ptrs); // Point at copy->record[0]
if (*org_field == found_next_number_field)
@@ -959,23 +988,12 @@ static pthread_handler_decl(handle_delayed_insert,arg)
if (!di->status && !di->stacked_inserts)
{
struct timespec abstime;
-#if defined(HAVE_TIMESPEC_TS_SEC)
- abstime.ts_sec=time((time_t*) 0)+(time_t) delayed_insert_timeout;
- abstime.ts_nsec=0;
-#elif defined(__WIN__)
- abstime.tv_sec=time((time_t*) 0)+(time_t) delayed_insert_timeout;
- abstime.tv_nsec=0;
-#else
- struct timeval tv;
- gettimeofday(&tv,0);
- abstime.tv_sec=tv.tv_sec+(time_t) delayed_insert_timeout;
- abstime.tv_nsec=tv.tv_usec*1000;
-#endif
+ set_timespec(abstime, delayed_insert_timeout);
/* Information for pthread_kill */
di->thd.mysys_var->current_mutex= &di->mutex;
di->thd.mysys_var->current_cond= &di->cond;
- di->thd.proc_info=0;
+ di->thd.proc_info="Waiting for INSERT";
DBUG_PRINT("info",("Waiting for someone to insert rows"));
while (!thd->killed)
@@ -1010,6 +1028,7 @@ static pthread_handler_decl(handle_delayed_insert,arg)
pthread_mutex_unlock(&di->thd.mysys_var->mutex);
pthread_mutex_lock(&di->mutex);
}
+ di->thd.proc_info=0;
if (di->tables_in_use && ! thd->lock)
{
@@ -1198,6 +1217,7 @@ bool delayed_insert::handle_inserts(void)
sql_print_error("%s",thd.net.last_error);
goto err;
}
+ query_cache.invalidate(table);
if (thr_reschedule_write_lock(*thd.lock->locks))
{
/* This should never happen */
@@ -1222,6 +1242,7 @@ bool delayed_insert::handle_inserts(void)
sql_print_error("%s",thd.net.last_error);
goto err;
}
+ query_cache.invalidate(table);
pthread_mutex_lock(&mutex);
DBUG_RETURN(0);
@@ -1255,7 +1276,7 @@ select_insert::prepare(List<Item> &values)
restore_record(table,2); // Get empty record
table->next_number_field=table->found_next_number_field;
- thd->count_cuted_fields=1; /* calc cuted fields */
+ thd->count_cuted_fields=1; // calc cuted fields
thd->cuted_fields=0;
if (info.handle_duplicates != DUP_REPLACE)
table->file->extra(HA_EXTRA_WRITE_CACHE);
@@ -1307,7 +1328,9 @@ void select_insert::send_error(uint errcode,const char *err)
::send_error(&thd->net,errcode,err);
table->file->extra(HA_EXTRA_NO_CACHE);
table->file->activate_all_index(thd);
- ha_rollback(thd);
+ ha_rollback_stmt(thd);
+ if (info.copied || info.deleted)
+ query_cache.invalidate(table);
}
@@ -1319,6 +1342,8 @@ bool select_insert::send_eof()
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
if ((error2=ha_autocommit_or_rollback(thd,error)) && ! error)
error=error2;
+ if (info.copied || info.deleted)
+ query_cache.invalidate(table);
if (error)
{
@@ -1407,6 +1432,7 @@ bool select_create::send_data(List<Item> &values)
extern HASH open_cache;
+
bool select_create::send_eof()
{
bool tmp=select_insert::send_eof();
@@ -1419,7 +1445,8 @@ bool select_create::send_eof()
mysql_unlock_tables(thd, lock);
if (!table->tmp_table)
hash_delete(&open_cache,(byte*) table);
- lock=0; table=0;
+ lock=0;
+ table=0;
VOID(pthread_mutex_unlock(&LOCK_open));
}
return tmp;
@@ -1451,7 +1478,7 @@ void select_create::abort()
*****************************************************************************/
#ifdef __GNUC__
-template class List_iterator<List_item>;
+template class List_iterator_fast<List_item>;
template class I_List<delayed_insert>;
template class I_List_iterator<delayed_insert>;
template class I_List<delayed_row>;
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index a3c3db8947e..43195bc908b 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -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 */
@@ -142,20 +142,21 @@ LEX *lex_start(THD *thd, uchar *buf,uint length)
lex->next_state=STATE_START;
lex->end_of_query=(lex->ptr=buf)+length;
lex->yylineno = 1;
- lex->create_refs=lex->in_comment=0;
+ lex->select->create_refs=lex->in_comment=0;
lex->length=0;
- lex->in_sum_expr=0;
- lex->expr_list.empty();
- lex->ftfunc_list.empty();
- lex->convert_set=thd->convert_set;
+ lex->select->in_sum_expr=0;
+ lex->select->expr_list.empty();
+ lex->select->ftfunc_list.empty();
+ lex->convert_set=(lex->thd=thd)->convert_set;
lex->yacc_yyss=lex->yacc_yyvs=0;
lex->ignore_space=test(thd->sql_mode & MODE_IGNORE_SPACE);
+ lex->slave_thd_opt=0;
return lex;
}
void lex_end(LEX *lex)
{
- lex->expr_list.delete_elements(); // If error when parsing sql-varargs
+ lex->select->expr_list.delete_elements(); // If error when parsing sql-varargs
x_free(lex->yacc_yyss);
x_free(lex->yacc_yyvs);
}
@@ -196,12 +197,12 @@ static int find_keyword(LEX *lex, uint len, bool function)
/* make a copy of token before ptr and set yytoklen */
-static inline LEX_STRING get_token(LEX *lex,uint length)
+LEX_STRING get_token(LEX *lex,uint length)
{
LEX_STRING tmp;
yyUnget(); // ptr points now after last token char
tmp.length=lex->yytoklen=length;
- tmp.str=(char*) sql_strmake((char*) lex->tok_start,tmp.length);
+ tmp.str=(char*) lex->thd->strmake((char*) lex->tok_start,tmp.length);
return tmp;
}
@@ -250,7 +251,7 @@ static char *get_text(LEX *lex)
str=lex->tok_start+1;
end=lex->ptr-1;
- if (!(start=(uchar*) sql_alloc((uint) (end-str)+1)))
+ if (!(start=(uchar*) lex->thd->alloc((uint) (end-str)+1)))
return (char*) ""; // Sql_alloc has set error flag
if (!found_escape)
{
@@ -337,7 +338,8 @@ static const char *longlong_str="9223372036854775807";
static const uint longlong_len=19;
static const char *signed_longlong_str="-9223372036854775808";
static const uint signed_longlong_len=19;
-
+static const char *unsigned_longlong_str="18446744073709551615";
+static const uint unsigned_longlong_len=20;
inline static uint int_token(const char *str,uint length)
{
@@ -393,7 +395,13 @@ inline static uint int_token(const char *str,uint length)
else if (length < longlong_len)
return LONG_NUM;
else if (length > longlong_len)
- return REAL_NUM;
+ {
+ if (length > unsigned_longlong_len)
+ return REAL_NUM;
+ cmp=unsigned_longlong_str;
+ smaller=ULONGLONG_NUM;
+ bigger=REAL_NUM;
+ }
else
{
cmp=longlong_str;
@@ -430,7 +438,7 @@ int yylex(void *arg)
switch(state) {
case STATE_OPERATOR_OR_IDENT: // Next is operator or keyword
case STATE_START: // Start of token
- // Skipp startspace
+ // Skip startspace
for (c=yyGet() ; (state_map[c] == STATE_SKIP) ; c= yyGet())
{
if (c == '\n')
@@ -458,6 +466,11 @@ int yylex(void *arg)
return((int) c);
case STATE_IDENT: // Incomplete keyword or ident
+ if ((c == 'x' || c == 'X') && yyPeek() == '\'')
+ { // Found x'hex-number'
+ state=STATE_HEX_NUMBER;
+ break;
+ }
#if defined(USE_MB) && defined(USE_MB_IDENT)
if (use_mb(default_charset_info))
{
@@ -509,6 +522,8 @@ int yylex(void *arg)
yySkip(); // next state does a unget
}
yylval->lex_str=get_token(lex,length);
+ if (lex->convert_set)
+ lex->convert_set->convert((char*) yylval->lex_str.str,lex->yytoklen);
return(IDENT);
case STATE_IDENT_SEP: // Found ident and now '.'
@@ -518,7 +533,7 @@ int yylex(void *arg)
c=yyGet(); // should be '.'
return((int) c);
- case STATE_NUMBER_IDENT: // number or ident which starts with num
+ case STATE_NUMBER_IDENT: // number or ident which num-start
while (isdigit((c = yyGet()))) ;
if (state_map[c] != STATE_IDENT)
{ // Can't be identifier
@@ -544,10 +559,10 @@ int yylex(void *arg)
lex->tok_start[0] == '0' )
{ // Varbinary
while (isxdigit((c = yyGet()))) ;
- if ((lex->ptr - lex->tok_start) >= 4)
+ if ((lex->ptr - lex->tok_start) >= 4 && state_map[c] != STATE_IDENT)
{
yylval->lex_str=get_token(lex,yyLength());
- yylval->lex_str.str+=2; // Skipp 0x
+ yylval->lex_str.str+=2; // Skip 0x
yylval->lex_str.length-=2;
lex->yytoklen-=2;
return (HEX_NUM);
@@ -597,10 +612,12 @@ int yylex(void *arg)
case STATE_FOUND_IDENT: // Complete ident
yylval->lex_str=get_token(lex,yyLength());
+ if (lex->convert_set)
+ lex->convert_set->convert((char*) yylval->lex_str.str,lex->yytoklen);
return(IDENT);
case STATE_USER_VARIABLE_DELIMITER:
- lex->tok_start=lex->ptr; // Skipp first `
+ lex->tok_start=lex->ptr; // Skip first `
#ifdef USE_MB
if (use_mb(default_charset_info))
{
@@ -625,14 +642,17 @@ int yylex(void *arg)
c != (uchar) NAMES_SEP_CHAR) ;
}
yylval->lex_str=get_token(lex,yyLength());
+ if (lex->convert_set)
+ lex->convert_set->convert((char*) yylval->lex_str.str,lex->yytoklen);
if (state_map[c] == STATE_USER_VARIABLE_DELIMITER)
- yySkip(); // Skipp end `
+ yySkip(); // Skip end `
return(IDENT);
case STATE_SIGNED_NUMBER: // Incomplete signed number
if (prev_state == STATE_OPERATOR_OR_IDENT)
{
- if (c == '-' && yyPeek() == '-' && isspace(yyPeek2()))
+ if (c == '-' && yyPeek() == '-' &&
+ (isspace(yyPeek2()) || iscntrl(yyPeek2())))
state=STATE_COMMENT;
else
state= STATE_CHAR; // Must be operator
@@ -672,7 +692,7 @@ int yylex(void *arg)
{
c = yyGet();
if (c == '-' || c == '+')
- c = yyGet(); // Skipp sign
+ c = yyGet(); // Skip sign
if (!isdigit(c))
{ // No digit after sign
state= STATE_CHAR;
@@ -685,6 +705,21 @@ int yylex(void *arg)
yylval->lex_str=get_token(lex,yyLength());
return(REAL_NUM);
+ case STATE_HEX_NUMBER: // Found x'hexstring'
+ yyGet(); // Skip '
+ while (isxdigit((c = yyGet()))) ;
+ length=(lex->ptr - lex->tok_start); // Length of hexnum+3
+ if (!(length & 1) || 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 x'
+ yylval->lex_str.length-=3; // Don't count x' and last '
+ lex->yytoklen-=3;
+ return (HEX_NUM);
+
case STATE_CMP_OP: // Incomplete comparison operator
if (state_map[yyPeek()] == STATE_CMP_OP ||
state_map[yyPeek()] == STATE_LONG_CMP_OP)
@@ -734,7 +769,7 @@ int yylex(void *arg)
return(TEXT_STRING);
case STATE_COMMENT: // Comment
- lex->options|= OPTION_FOUND_COMMENT;
+ lex->select_lex.options|= OPTION_FOUND_COMMENT;
while ((c = yyGet()) != '\n' && c) ;
yyUnget(); // Safety against eof
state = STATE_START; // Try again
@@ -746,7 +781,7 @@ int yylex(void *arg)
break;
}
yySkip(); // Skip '*'
- lex->options|= OPTION_FOUND_COMMENT;
+ lex->select_lex.options|= OPTION_FOUND_COMMENT;
if (yyPeek() == '!') // MySQL command in comment
{
ulong version=MYSQL_VERSION_ID;
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 2b889d356bb..ecfb3dec99c 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.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 */
@@ -22,7 +22,7 @@ class Table_ident;
class sql_exchange;
class LEX_COLUMN;
-// The following hack is neaded because mysql_yacc.cc does not define
+// The following hack is needed because mysql_yacc.cc does not define
// YYSTYPE before including this file
#ifdef MYSQL_YACC
@@ -53,7 +53,11 @@ enum enum_sql_command {
SQLCOM_BEGIN, SQLCOM_LOAD_MASTER_TABLE, SQLCOM_CHANGE_MASTER,
SQLCOM_RENAME_TABLE, SQLCOM_BACKUP_TABLE, SQLCOM_RESTORE_TABLE,
SQLCOM_RESET, SQLCOM_PURGE, SQLCOM_SHOW_BINLOGS,
- SQLCOM_SHOW_OPEN_TABLES, SQLCOM_DO, SQLCOM_EMPTY_QUERY,
+ SQLCOM_SHOW_OPEN_TABLES, SQLCOM_LOAD_MASTER_DATA,
+ SQLCOM_HA_OPEN, SQLCOM_HA_CLOSE, SQLCOM_HA_READ,
+ SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_DELETE_MULTI, SQLCOM_MULTI_UPDATE,
+ SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER, SQLCOM_DO,
+ SQLCOM_EMPTY_QUERY,
SQLCOM_END
};
@@ -63,6 +67,7 @@ enum lex_states { STATE_START, STATE_CHAR, STATE_IDENT,
STATE_FOUND_IDENT,
STATE_SIGNED_NUMBER,
STATE_REAL,
+ STATE_HEX_NUMBER,
STATE_CMP_OP,
STATE_LONG_CMP_OP,
STATE_STRING,
@@ -92,60 +97,96 @@ typedef struct st_lex_master_info
char* host, *user, *password,*log_file_name;
uint port, connect_retry;
ulonglong pos;
+ ulong server_id;
} LEX_MASTER_INFO;
+
+enum sub_select_type {UNSPECIFIED_TYPE,UNION_TYPE, INTERSECT_TYPE, EXCEPT_TYPE, NOT_A_SELECT};
+
+/* The state of the lex parsing for selects */
+
+typedef struct st_select_lex {
+ enum sub_select_type linkage;
+ char *db,*db1,*table1,*db2,*table2; /* For outer join using .. */
+ Item *where,*having;
+ ha_rows select_limit,offset_limit;
+ ulong options;
+ List<List_item> expr_list;
+ List<List_item> when_list;
+ SQL_LIST order_list,table_list,group_list;
+ List<Item> item_list;
+ List<String> interval_list,use_index, *use_index_ptr,
+ ignore_index, *ignore_index_ptr;
+ List<Item_func_match> ftfunc_list;
+ uint in_sum_expr, sort_default;
+ bool create_refs, braces;
+ st_select_lex *next;
+} SELECT_LEX;
+
+
+class Set_option :public Sql_alloc {
+public:
+ const char *name;
+ Item *item;
+ uint name_length;
+ bool type; /* 1 if global */
+ Set_option(bool par_type, const char *par_name, uint length,
+ Item *par_item)
+ :name(par_name), item(par_item), name_length(length), type(par_type) {}
+};
+
+
/* The state of the lex parsing. This is saved in the THD struct */
typedef struct st_lex {
uint yylineno,yytoklen; /* Simulate lex */
LEX_YYSTYPE yylval;
+ SELECT_LEX select_lex, *select;
uchar *ptr,*tok_start,*tok_end,*end_of_query;
char *length,*dec,*change,*name;
- char *db,*db1,*table1,*db2,*table2; /* For outer join using .. */
char *backup_dir; /* For RESTORE/BACKUP */
char* to_log; /* For PURGE MASTER LOGS TO */
+ char* x509_subject,*x509_issuer,*ssl_cipher;
+ enum SSL_type ssl_type; /* defined in violite.h */
String *wild;
sql_exchange *exchange;
- ha_rows select_limit,offset_limit;
- List<List_item> expr_list;
- List<List_item> when_list;
- List<List_item> many_values;
List<key_part_spec> col_list;
List<Alter_drop> drop_list;
List<Alter_column> alter_list;
- List<String> interval_list,use_index,*use_index_ptr,
- ignore_index, *ignore_index_ptr;
+ List<String> interval_list;
List<st_lex_user> users_list;
List<LEX_COLUMN> columns;
List<Key> key_list;
List<create_field> create_list;
- List<Item> item_list,*insert_list,field_list,value_list;
- List<Item_func_match> ftfunc_list;
- SQL_LIST order_list,table_list,group_list,proc_list;
+ List<Item> *insert_list,field_list,value_list;
+ List<List_item> many_values;
+ List<Set_option> option_list;
+ SQL_LIST proc_list, auxilliary_table_list;
TYPELIB *interval;
create_field *last_field;
-
- Item *where,*having,*default_value;
+ Item *default_value;
CONVERT *convert_set;
LEX_USER *grant_user;
gptr yacc_yyss,yacc_yyvs;
+ THD *thd;
udf_func udf;
HA_CHECK_OPT check_opt; // check/repair options
HA_CREATE_INFO create_info;
LEX_MASTER_INFO mi; // used by CHANGE MASTER
ulong thread_id,type;
- ulong options;
- ulong gemini_spin_retries;
enum_sql_command sql_command;
enum lex_states next_state;
enum enum_duplicates duplicates;
enum enum_tx_isolation tx_isolation;
- uint in_sum_expr,grant,grant_tot_col,which_columns;
+ enum enum_ha_read_modes ha_read_mode;
+ enum ha_rkey_function ha_rkey_mode;
+ enum enum_enable_or_disable alter_keys_onoff;
+ uint grant,grant_tot_col,which_columns, union_option, mqh;
thr_lock_type lock_option;
- bool create_refs,drop_primary,drop_if_exists,local_file;
- bool in_comment,ignore_space,verbose;
-
+ bool drop_primary,drop_if_exists,local_file;
+ bool in_comment,ignore_space,verbose,simple_alter, option_type;
+ uint slave_thd_opt;
} LEX;
diff --git a/sql/sql_list.cc b/sql/sql_list.cc
index 7d5fc442121..1124605ca24 100644
--- a/sql/sql_list.cc
+++ b/sql/sql_list.cc
@@ -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 */
@@ -20,3 +20,5 @@
#endif
#include "mysql_priv.h"
+
+list_node end_of_list;
diff --git a/sql/sql_list.h b/sql/sql_list.h
index d21f2e658dc..542eef623f0 100644
--- a/sql/sql_list.h
+++ b/sql/sql_list.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 */
@@ -41,25 +41,40 @@ public:
/*
** basic single linked list
** Used for item and item_buffs.
+** All list ends with a pointer to the 'end_of_list' element, which
+** data pointer is a null pointer and the next pointer points to itself.
+** This makes it very fast to traverse lists as we don't have to
+** test for a specialend condition for list that can't contain a null
+** pointer.
*/
+class list_node :public Sql_alloc
+{
+public:
+ list_node *next;
+ void *info;
+ list_node(void *info_par,list_node *next_par)
+ :next(next_par),info(info_par)
+ {}
+ list_node() /* For end_of_list */
+ {
+ info=0;
+ next= this;
+ }
+ friend class base_list;
+ friend class base_list_iterator;
+};
+
+extern list_node end_of_list;
+
class base_list :public Sql_alloc {
protected:
- class list_node :public Sql_alloc
- {
- public:
- list_node *next;
- void *info;
- list_node(void *info_par,list_node *next_par) : next(next_par),info(info_par) {}
- friend class base_list;
- friend class base_list_iterator;
- };
list_node *first,**last;
public:
uint elements;
- inline void empty() { elements=0; first=0; last=&first;}
+ inline void empty() { elements=0; first= &end_of_list; last=&first;}
inline base_list() { empty(); }
inline base_list(const base_list &tmp) :Sql_alloc()
{
@@ -69,7 +84,7 @@ public:
}
inline bool push_back(void *info)
{
- if (((*last)=new list_node(info,0)))
+ if (((*last)=new list_node(info, &end_of_list)))
{
last= &(*last)->next;
elements++;
@@ -82,7 +97,7 @@ public:
list_node *node=new list_node(info,first);
if (node)
{
- if (!first)
+ if (last == &first)
last= &node->next;
first=node;
elements++;
@@ -96,22 +111,21 @@ public:
delete *prev;
*prev=node;
if (!--elements)
- {
last= &first;
- first=0;
- }
}
inline void *pop(void)
{
- if (!first) return 0;
+ if (first == &end_of_list) return 0;
list_node *tmp=first;
first=first->next;
if (!--elements)
last= &first;
return tmp->info;
}
- inline void *head() { return first ? first->info : 0; }
- inline void **head_ref() { return first ? &first->info : 0; }
+ inline void *head() { return first->info; }
+ inline void **head_ref() { return first != &end_of_list ? &first->info : 0; }
+ inline bool is_empty() { return first == &end_of_list ; }
+ inline list_node *last_ref() { return &end_of_list; }
friend class base_list_iterator;
protected:
@@ -129,7 +143,7 @@ protected:
class base_list_iterator
{
base_list *list;
- base_list::list_node **el,**prev,*current;
+ list_node **el,**prev,*current;
public:
base_list_iterator(base_list &list_par) :list(&list_par),el(&list_par.first),
prev(0),current(0)
@@ -137,16 +151,22 @@ public:
inline void *next(void)
{
prev=el;
- if (!(current= *el))
- return 0;
+ current= *el;
el= &current->next;
return current->info;
}
+ inline void *next_fast(void)
+ {
+ list_node *tmp;
+ tmp= *el;
+ el= &tmp->next;
+ return tmp->info;
+ }
inline void rewind(void)
{
el= &list->first;
}
- void *replace(void *element)
+ inline void *replace(void *element)
{ // Return old element
void *tmp=current->info;
current->info=element;
@@ -155,7 +175,7 @@ public:
void *replace(base_list &new_list)
{
void *ret_value=current->info;
- if (new_list.first)
+ if (!new_list.is_empty())
{
*new_list.last=current->next;
current->info=new_list.first->info;
@@ -182,7 +202,7 @@ public:
}
inline bool is_last(void)
{
- return *el == 0;
+ return el == &list->last_ref()->next;
}
};
@@ -200,7 +220,7 @@ public:
void delete_elements(void)
{
list_node *element,*next;
- for (element=first; element ; element=next)
+ for (element=first; element != &end_of_list; element=next)
{
next=element->next;
delete (T*) element->info;
@@ -215,18 +235,30 @@ template <class T> class List_iterator :public base_list_iterator
public:
List_iterator(List<T> &a) : base_list_iterator(a) {}
inline T* operator++(int) { return (T*) base_list_iterator::next(); }
- inline void rewind(void) { base_list_iterator::rewind(); }
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 remove(void) { base_list_iterator::remove(); }
inline void after(T *a) { base_list_iterator::after(a); }
inline T** ref(void) { return (T**) base_list_iterator::ref(); }
- inline bool is_last(void) { return base_list_iterator::is_last(); }
+};
+
+template <class T> class List_iterator_fast :public base_list_iterator
+{
+protected:
+ inline T *replace(T *a) { return (T*) 0; }
+ inline T *replace(List<T> &a) { return (T*) 0; }
+ inline void remove(void) { }
+ inline void after(T *a) { }
+ inline T** ref(void) { return (T**) 0; }
+
+public:
+ List_iterator_fast(List<T> &a) : base_list_iterator(a) {}
+ inline T* operator++(int) { return (T*) base_list_iterator::next_fast(); }
+ inline void rewind(void) { base_list_iterator::rewind(); }
};
/*
-** An simple intrusive list with automaticly removes element from list
+** A simple intrusive list which automaticly removes element from list
** on delete (for THD element)
*/
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 1dcc8c2130e..419e3fccabd 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -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 */
@@ -20,6 +20,7 @@
#include "mysql_priv.h"
#include <my_dir.h>
#include <m_ctype.h>
+#include "sql_repl.h"
class READ_INFO {
File file;
@@ -32,6 +33,7 @@ class READ_INFO {
int field_term_char,line_term_char,enclosed_char,escape_char;
int *stack,*stack_pos;
bool found_end_of_line,start_of_line,eof;
+ bool need_end_io_cache;
IO_CACHE cache;
NET *io_net;
@@ -50,6 +52,18 @@ public:
char unescape(char chr);
int terminator(char *ptr,uint length);
bool find_start_of_fields();
+ // we need to force cache close before destructor is invoked to log
+ // the last read block
+ void end_io_cache()
+ {
+ ::end_io_cache(&cache);
+ need_end_io_cache = 0;
+ }
+
+ // either this method, or we need to make cache public
+ // arg must be set from mysql_load() since constructor does not see
+ // either the table or THD value
+ void set_io_cache_arg(void* arg) { cache.arg = arg; }
};
static int read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,
@@ -67,10 +81,11 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
File file;
TABLE *table;
int error;
- uint save_skip_lines = ex->skip_lines;
String *field_term=ex->field_term,*escaped=ex->escaped,
*enclosed=ex->enclosed;
bool is_fifo=0;
+ LOAD_FILE_INFO lf_info;
+ char * db = table_list->db ? table_list->db : thd->db;
bool using_transactions;
DBUG_ENTER("mysql_load");
@@ -80,7 +95,6 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
MYF(0));
DBUG_RETURN(-1);
}
-
if (!(table = open_ltable(thd,table_list,lock_type)))
DBUG_RETURN(-1);
if (!fields.elements)
@@ -92,7 +106,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
else
{ // Part field list
thd->dupp_field=0;
- if (setup_tables(table_list) || setup_fields(thd,table_list,fields,1,0))
+ if (setup_tables(table_list) || setup_fields(thd,table_list,fields,1,0,0))
DBUG_RETURN(-1);
if (thd->dupp_field)
{
@@ -103,7 +117,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
uint tot_length=0;
bool use_blobs=0,use_timestamp=0;
- List_iterator<Item> it(fields);
+ List_iterator_fast<Item> it(fields);
Item_field *field;
while ((field=(Item_field*) it++))
@@ -133,12 +147,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
if (read_file_from_client)
{
- char tmp [FN_REFLEN+1],*end;
- DBUG_PRINT("info",("reading local file"));
- tmp[0] = (char) 251; /* NULL_LENGTH */
- end=strnmov(tmp+1,ex->file_name,sizeof(tmp)-2);
- (void) my_net_write(&thd->net,tmp,(uint) (end-tmp));
- (void) net_flush(&thd->net);
+ (void)net_request_file(&thd->net,ex->file_name);
file = -1;
}
else
@@ -161,9 +170,10 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
MY_STAT stat_info;
if (!my_stat(name,&stat_info,MYF(MY_WME)))
DBUG_RETURN(-1);
-
- // the file must be:
- if (!((stat_info.st_mode & S_IROTH) == S_IROTH && // readable by others
+
+ // if we are not in slave thread, the file must be:
+ if (!thd->slave_thread &&
+ !((stat_info.st_mode & S_IROTH) == S_IROTH && // readable by others
#ifndef __EMX__
(stat_info.st_mode & S_IFLNK) != S_IFLNK && // and not a symlink
#endif
@@ -196,13 +206,27 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
DBUG_RETURN(-1); // Can't allocate buffers
}
+ if (!opt_old_rpl_compat && 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.handle_dup = handle_duplicates;
+ lf_info.wrote_create_file = 0;
+ lf_info.last_pos_in_file = HA_POS_ERROR;
+ read_info.set_io_cache_arg((void*)&lf_info);
+ }
restore_record(table,2);
thd->count_cuted_fields=1; /* calc cuted fields */
thd->cuted_fields=0L;
if (ex->line_term->length() && field_term->length())
{
- while (ex->skip_lines--)
+ // ex->skip_lines needs to be preserved for logging
+ uint skip_lines = ex->skip_lines;
+ while (skip_lines--)
{
if (read_info.next_line())
break;
@@ -215,6 +239,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
table->time_stamp=0;
table->next_number_field=table->found_next_number_field;
VOID(table->file->extra(HA_EXTRA_WRITE_CACHE));
+ VOID(table->file->extra(HA_EXTRA_BULK_INSERT_BEGIN));
if (handle_duplicates == DUP_IGNORE ||
handle_duplicates == DUP_REPLACE)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
@@ -224,9 +249,10 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
error=read_fixed_length(thd,info,table,fields,read_info);
else
error=read_sep_field(thd,info,table,fields,read_info,*enclosed);
- if (table->file->extra(HA_EXTRA_NO_CACHE) ||
- table->file->activate_all_index(thd))
- error=1; /* purecov: inspected */
+ if (table->file->extra(HA_EXTRA_NO_CACHE))
+ error=1; /* purecov: inspected */
+ if (table->file->activate_all_index(thd))
+ error=1; /* purecov: inspected */
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
table->time_stamp=save_time_stamp;
table->next_number_field=0;
@@ -245,7 +271,15 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
{
if (using_transactions)
ha_autocommit_or_rollback(thd,error);
- DBUG_RETURN(-1); // Error on read
+ if (!opt_old_rpl_compat && mysql_bin_log.is_open())
+ {
+ if (lf_info.wrote_create_file)
+ {
+ Delete_file_log_event d(thd);
+ mysql_bin_log.write(&d);
+ }
+ }
+ DBUG_RETURN(-1); // Error on read
}
sprintf(name,ER(ER_LOAD_INFO),info.records,info.deleted,
info.records-info.copied,thd->cuted_fields);
@@ -253,15 +287,26 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
// on the slave thd->query is never initialized
if(!thd->slave_thread)
mysql_update_log.write(thd,thd->query,thd->query_length);
-
+
if (!using_transactions)
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
- if (!read_file_from_client && mysql_bin_log.is_open())
+ if (mysql_bin_log.is_open())
{
- ex->skip_lines = save_skip_lines;
- Load_log_event qinfo(thd, ex, table->table_cache_key, table->table_name,
- fields, handle_duplicates);
- mysql_bin_log.write(&qinfo);
+ if (opt_old_rpl_compat && !read_file_from_client)
+ {
+ Load_log_event qinfo(thd, ex, db, table->table_name, fields,
+ handle_duplicates);
+ mysql_bin_log.write(&qinfo);
+ }
+ if (!opt_old_rpl_compat)
+ {
+ read_info.end_io_cache(); // make sure last block gets logged
+ if (lf_info.wrote_create_file)
+ {
+ Execute_load_log_event e(thd);
+ mysql_bin_log.write(&e);
+ }
+ }
}
if (using_transactions)
error=ha_autocommit_or_rollback(thd,error);
@@ -277,7 +322,7 @@ static int
read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,List<Item> &fields,
READ_INFO &read_info)
{
- List_iterator<Item> it(fields);
+ List_iterator_fast<Item> it(fields);
Item_field *sql_field;
DBUG_ENTER("read_fixed_length");
@@ -325,7 +370,7 @@ read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,List<Item> &fields,
DBUG_RETURN(1);
if (table->next_number_field)
table->next_number_field->reset(); // Clear for next record
- if (read_info.next_line()) // Skipp to next line
+ if (read_info.next_line()) // Skip to next line
break;
if (read_info.line_cuted)
thd->cuted_fields++; /* To long row */
@@ -340,7 +385,7 @@ read_sep_field(THD *thd,COPY_INFO &info,TABLE *table,
List<Item> &fields, READ_INFO &read_info,
String &enclosed)
{
- List_iterator<Item> it(fields);
+ List_iterator_fast<Item> it(fields);
Item_field *sql_field;
uint enclosed_length;
DBUG_ENTER("read_sep_field");
@@ -401,7 +446,7 @@ read_sep_field(THD *thd,COPY_INFO &info,TABLE *table,
DBUG_RETURN(1);
if (table->next_number_field)
table->next_number_field->reset(); // Clear for next record
- if (read_info.next_line()) // Skipp to next line
+ if (read_info.next_line()) // Skip to next line
break;
if (read_info.line_cuted)
thd->cuted_fields++; /* To long row */
@@ -488,6 +533,21 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, String &field_term,
my_free((gptr) buffer,MYF(0)); /* purecov: inspected */
error=1;
}
+ 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
+ manual assignment
+ */
+ if (get_it_from_net)
+ cache.read_function = _my_b_net_read;
+
+ need_end_io_cache = 1;
+ if (!opt_old_rpl_compat && mysql_bin_log.is_open())
+ cache.pre_read = cache.pre_close =
+ (IO_CACHE_CALLBACK) log_loaded_block;
+ }
}
}
@@ -496,7 +556,8 @@ READ_INFO::~READ_INFO()
{
if (!error)
{
- end_io_cache(&cache);
+ if (need_end_io_cache)
+ ::end_io_cache(&cache);
my_free((gptr) buffer,MYF(0));
error=1;
}
@@ -536,10 +597,10 @@ int READ_INFO::read_field()
if (found_end_of_line)
return 1; // One have to call next_line
- /* Skipp until we find 'line_start' */
+ /* Skip until we find 'line_start' */
if (start_of_line)
- { // Skipp until line_start
+ { // Skip until line_start
start_of_line=0;
if (find_start_of_fields())
return 1;
@@ -682,7 +743,7 @@ found_eof:
/*
** One can't use fixed length with multi-byte charset **
*/
-
+
int READ_INFO::read_fixed_length()
{
int chr;
@@ -691,7 +752,7 @@ int READ_INFO::read_fixed_length()
return 1; // One have to call next_line
if (start_of_line)
- { // Skipp until line_start
+ { // Skip until line_start
start_of_line=0;
if (find_start_of_fields())
return 1;
diff --git a/sql/sql_manager.cc b/sql/sql_manager.cc
index 53953c96d0b..13cac83fc3f 100644
--- a/sql/sql_manager.cc
+++ b/sql/sql_manager.cc
@@ -55,13 +55,7 @@ pthread_handler_decl(handle_manager,arg __attribute__((unused)))
{
if (reset_flush_time)
{
-#ifdef HAVE_TIMESPEC_TS_SEC
- abstime.ts_sec = time(NULL)+flush_time; // Bsd 2.1
- abstime.ts_nsec = 0;
-#else
- abstime.tv_sec = time(NULL)+flush_time; // Linux or Solairs
- abstime.tv_nsec = 0;
-#endif
+ set_timespec(abstime, flush_time);
reset_flush_time = FALSE;
}
while (!manager_status && !error && !abort_loop)
diff --git a/sql/sql_map.cc b/sql/sql_map.cc
index 4578b85d10a..e7e24f957c6 100644
--- a/sql/sql_map.cc
+++ b/sql/sql_map.cc
@@ -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 */
diff --git a/sql/sql_map.h b/sql/sql_map.h
index 34f2f755b43..632eb6e4f64 100644
--- a/sql/sql_map.h
+++ b/sql/sql_map.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 */
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index fa4a4fd4f3b..e649f109a0d 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* 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
@@ -14,16 +14,38 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#ifdef EMBEDDED_LIBRARY
+#define net_read_timeout net_read_timeout1
+#define net_write_timeout net_write_timeout1
+#endif
#include "mysql_priv.h"
#include "sql_acl.h"
#include "sql_repl.h"
+#include "repl_failsafe.h"
#include <m_ctype.h>
#include <thr_alarm.h>
#include <myisam.h>
#include <my_dir.h>
#include <assert.h>
+#ifdef HAVE_OPENSSL
+/*
+ Without SSL the handshake consists of one packet. This packet
+ has both client capabilites and scrambled password.
+ With SSL the handshake might consist of two packets. If the first
+ packet (client capabilities) has CLIENT_SSL flag set, we have to
+ switch to SSL and read the second packet. The scrambled password
+ is in the second packet and client_capabilites field will be ignored.
+ Maybe it is better to accept flags other than CLIENT_SSL from the
+ second packet?
+*/
+#define SSL_HANDSHAKE_SIZE 2
+#define NORMAL_HANDSHAKE_SIZE 6
+#define MIN_HANDSHAKE_SIZE 2
+#else
+#define MIN_HANDSHAKE_SIZE 6
+#endif /* HAVE_OPENSSL */
#define SCRAMBLE_LENGTH 8
@@ -33,16 +55,18 @@ extern "C" pthread_mutex_t THR_LOCK_keycache;
extern "C" int gethostname(char *name, int namelen);
#endif
-static int check_for_max_user_connections(const char *user, int u_length,
- const char *host);
-static void decrease_user_connections(const char *user, const char *host);
+static int check_for_max_user_connections(UC *uc);
+static bool check_mqh(THD *thd);
+static void decrease_user_connections(UC *uc);
static bool check_db_used(THD *thd,TABLE_LIST *tables);
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
-static bool check_dup(THD *thd,const char *db,const char *name,
- TABLE_LIST *tables);
+static bool check_dup(const char *db, const char *name, TABLE_LIST *tables);
static void mysql_init_query(THD *thd);
static void remove_escape(char *name);
static void refresh_status(void);
+static bool append_file_to_dir(THD *thd, char **filename_ptr,
+ char *table_name);
+static bool create_total_list(THD *thd, LEX *lex, TABLE_LIST **result);
const char *any_db="*any*"; // Special symbol for check_access
@@ -50,13 +74,13 @@ const char *command_name[]={
"Sleep", "Quit", "Init DB", "Query", "Field List", "Create DB",
"Drop DB", "Refresh", "Shutdown", "Statistics", "Processlist",
"Connect","Kill","Debug","Ping","Time","Delayed_insert","Change user",
- "Binlog Dump","Table Dump", "Connect Out"
+ "Binlog Dump","Table Dump", "Connect Out", "Register Slave"
};
bool volatile abort_slave = 0;
#ifdef HAVE_OPENSSL
-extern VioSSLAcceptorFd* ssl_acceptor_fd;
+extern struct st_VioSSLAcceptorFd * ssl_acceptor_fd;
#endif /* HAVE_OPENSSL */
#ifdef __WIN__
@@ -66,8 +90,8 @@ static void test_signal(int sig_ptr)
MessageBox(NULL,"Test signal","DBUG",MB_OK);
#endif
#if defined(OS2)
- fprintf( stderr, "Test signal %d\n", sig_ptr);
- fflush( stderr);
+ fprintf(stderr, "Test signal %d\n", sig_ptr);
+ fflush(stderr);
#endif
}
static void init_signals(void)
@@ -93,43 +117,98 @@ inline bool end_active_trans(THD *thd)
}
+static HASH hash_user_connections;
+extern pthread_mutex_t LOCK_user_conn;
+
+static int get_or_create_user_conn(THD *thd, const char *user,
+ const char *host,
+ uint max_questions)
+{
+ int return_val=0;
+ uint temp_len;
+ char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
+ struct user_conn *uc;
+
+ DBUG_ASSERT(user != 0);
+ DBUG_ASSERT(host != 0);
+
+ temp_len= (uint) (strxnmov(temp_user, sizeof(temp_user)-1, user, "@", host,
+ NullS) - temp_user);
+ (void) pthread_mutex_lock(&LOCK_user_conn);
+ if (!(uc = (struct user_conn *) hash_search(&hash_user_connections,
+ (byte*) temp_user, temp_len)))
+ {
+ /* First connection for user; Create a user connection object */
+ if (!(uc= ((struct user_conn*)
+ my_malloc(sizeof(struct user_conn) + temp_len+1,
+ MYF(MY_WME)))))
+ {
+ send_error(&current_thd->net, 0, NullS); // Out of memory
+ return_val=1;
+ goto end;
+ }
+ uc->user=(char*) (uc+1);
+ memcpy(uc->user,temp_user,temp_len+1);
+ uc->len = temp_len;
+ uc->connections = 1;
+ uc->questions=0;
+ uc->max_questions=max_questions;
+ uc->intime=thd->thr_create_time;
+ if (hash_insert(&hash_user_connections, (byte*) uc))
+ {
+ my_free((char*) uc,0);
+ send_error(&current_thd->net, 0, NullS); // Out of memory
+ return_val=1;
+ goto end;
+ }
+ }
+ thd->user_connect=uc;
+end:
+ (void) pthread_mutex_unlock(&LOCK_user_conn);
+ return return_val;
+
+}
+
+
/*
-** Check if user is ok
-** Updates:
-** thd->user, thd->master_access, thd->priv_user, thd->db, thd->db_access
+ Check if user is ok
+ Updates:
+ thd->user, thd->master_access, thd->priv_user, thd->db, thd->db_access
*/
static bool check_user(THD *thd,enum_server_command command, const char *user,
const char *passwd, const char *db, bool check_count)
{
NET *net= &thd->net;
+ uint max_questions=0;
thd->db=0;
+ thd->db_length=0;
if (!(thd->user = my_strdup(user, MYF(0))))
{
send_error(net,ER_OUT_OF_RESOURCES);
return 1;
}
- thd->master_access=acl_getroot(thd->host, thd->ip, thd->user,
+ thd->master_access=acl_getroot(thd, thd->host, thd->ip, thd->user,
passwd, thd->scramble, &thd->priv_user,
protocol_version == 9 ||
!(thd->client_capabilities &
- CLIENT_LONG_PASSWORD));
- DBUG_PRINT("general",
+ CLIENT_LONG_PASSWORD),&max_questions);
+ DBUG_PRINT("info",
("Capabilities: %d packet_length: %d Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'",
thd->client_capabilities, thd->max_packet_length,
- thd->host ? thd->host : thd->ip, thd->priv_user,
+ thd->host_or_ip, thd->priv_user,
passwd[0] ? "yes": "no",
thd->master_access, thd->db ? thd->db : "*none*"));
if (thd->master_access & NO_ACCESS)
{
net_printf(net, ER_ACCESS_DENIED_ERROR,
thd->user,
- thd->host ? thd->host : thd->ip,
+ thd->host_or_ip,
passwd[0] ? ER(ER_YES) : ER(ER_NO));
mysql_log.write(thd,COM_CONNECT,ER(ER_ACCESS_DENIED_ERROR),
thd->user,
- thd->host ? thd->host : thd->ip ? thd->ip : "unknown ip",
+ thd->host_or_ip,
passwd[0] ? ER(ER_YES) : ER(ER_NO));
return(1); // Error already given
}
@@ -150,17 +229,20 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
(char*) "%s@%s on %s" :
(char*) "%s@%s as anonymous on %s"),
user,
- thd->host ? thd->host : thd->ip ? thd->ip : "unknown ip",
+ thd->host_or_ip,
db ? db : (char*) "");
thd->db_access=0;
- if (max_user_connections &&
- check_for_max_user_connections(user, strlen(user), thd->host))
+ /* Don't allow user to connect if he has done too many queries */
+ if ((max_questions || max_user_connections) && get_or_create_user_conn(thd,user,thd->host_or_ip,max_questions))
+ return -1;
+ if (max_user_connections && thd->user_connect &&
+ check_for_max_user_connections(thd->user_connect))
return -1;
if (db && db[0])
{
bool error=test(mysql_change_db(thd,db));
- if (error)
- decrease_user_connections(thd->user,thd->host);
+ if (error && thd->user_connect)
+ decrease_user_connections(thd->user_connect);
return error;
}
else
@@ -169,19 +251,10 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
}
/*
-** check for maximum allowable user connections
-** if mysql server is started with corresponding
-** variable that is greater then 0
+ Check for maximum allowable user connections, if the mysqld server is
+ started with corresponding variable that is greater then 0.
*/
-static HASH hash_user_connections;
-extern pthread_mutex_t LOCK_user_conn;
-
-struct user_conn {
- char *user;
- uint len, connections;
-};
-
static byte* get_key_conn(user_conn *buff, uint *length,
my_bool not_used __attribute__((unused)))
{
@@ -189,8 +262,6 @@ static byte* get_key_conn(user_conn *buff, uint *length,
return (byte*) buff->user;
}
-#define DEF_USER_COUNT 50
-
static void free_user(struct user_conn *uc)
{
my_free((char*) uc,MYF(0));
@@ -198,100 +269,44 @@ static void free_user(struct user_conn *uc)
void init_max_user_conn(void)
{
- (void) hash_init(&hash_user_connections,DEF_USER_COUNT,0,0,
+ (void) hash_init(&hash_user_connections,max_connections,0,0,
(hash_get_key) get_key_conn, (void (*)(void*)) free_user,
0);
}
-static int check_for_max_user_connections(const char *user, int u_length,
- const char *host)
+static int check_for_max_user_connections(UC *uc)
{
- int error=1;
- uint temp_len;
- char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
- struct user_conn *uc;
- if (!user)
- user="";
- if (!host)
- host="";
+ int error=0;
DBUG_ENTER("check_for_max_user_connections");
- DBUG_PRINT("enter",("user: '%s' host: '%s'", user, host));
-
- temp_len= (uint) (strxnmov(temp_user, sizeof(temp_user), user, "@", host,
- NullS) - temp_user);
- (void) pthread_mutex_lock(&LOCK_user_conn);
- uc = (struct user_conn *) hash_search(&hash_user_connections,
- (byte*) temp_user, temp_len);
- if (uc) /* user found ; check for no. of connections */
- {
- if (max_user_connections == (uint) uc->connections)
- {
- net_printf(&(current_thd->net),ER_TOO_MANY_USER_CONNECTIONS, temp_user);
- goto end;
- }
- uc->connections++;
- }
- else
+
+ if (max_user_connections <= (uint) uc->connections)
{
- /* the user is not found in the cache; Insert it */
- struct user_conn *uc= ((struct user_conn*)
- my_malloc(sizeof(struct user_conn) + temp_len+1,
- MYF(MY_WME)));
- if (!uc)
- {
- send_error(&current_thd->net, 0, NullS); // Out of memory
- goto end;
- }
- uc->user=(char*) (uc+1);
- memcpy(uc->user,temp_user,temp_len+1);
- uc->len = temp_len;
- uc->connections = 1;
- if (hash_insert(&hash_user_connections, (byte*) uc))
- {
- my_free((char*) uc,0);
- send_error(&current_thd->net, 0, NullS); // Out of memory
- goto end;
- }
+ net_printf(&(current_thd->net),ER_TOO_MANY_USER_CONNECTIONS, uc->user);
+ error=1;
+ goto end;
}
- error=0;
+ uc->connections++;
end:
- (void) pthread_mutex_unlock(&LOCK_user_conn);
DBUG_RETURN(error);
}
-static void decrease_user_connections(const char *user, const char *host)
+static void decrease_user_connections(UC *uc)
{
- char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
- int temp_len;
- struct user_conn *uc;
if (!max_user_connections)
return;
- if (!user)
- user="";
- if (!host)
- host="";
- DBUG_ENTER("decrease_user_connections");
- DBUG_PRINT("enter",("user: '%s' host: '%s'", user, host));
- temp_len= (uint) (strxnmov(temp_user, sizeof(temp_user), user, "@", host,
- NullS) - temp_user);
- (void) pthread_mutex_lock(&LOCK_user_conn);
+ DBUG_ENTER("decrease_user_connections");
- uc = (struct user_conn *) hash_search(&hash_user_connections,
- (byte*) temp_user, temp_len);
- dbug_assert(uc != 0); // We should always find the user
- if (!uc)
- goto end; // Safety; Something went wrong
- if (! --uc->connections)
+ if (!--uc->connections && !mqh_used)
{
/* Last connection for user; Delete it */
+ (void) pthread_mutex_lock(&LOCK_user_conn);
(void) hash_delete(&hash_user_connections,(byte*) uc);
+ (void) pthread_mutex_unlock(&LOCK_user_conn);
}
-end:
- (void) pthread_mutex_unlock(&LOCK_user_conn);
DBUG_VOID_RETURN;
}
@@ -303,22 +318,93 @@ void free_max_user_conn(void)
/*
-** check connnetion and get priviliges
-** returns 0 on ok, -1 < if error is given > 0 on error.
+ Check if maximum queries per hour limit has been reached
+ returns 0 if OK.
+
+ In theory we would need a mutex in the UC structure for this to be 100 %
+ safe, but as the worst scenario is that we would miss counting a couple of
+ queries, this isn't critical.
*/
+static bool check_mqh(THD *thd)
+{
+ bool error=0;
+ DBUG_ENTER("check_mqh");
+ UC *uc=thd->user_connect;
+ DBUG_ASSERT(uc != 0);
+
+ bool my_start = thd->start_time != 0;
+ time_t check_time = (my_start) ? thd->start_time : time(NULL);
+ if (check_time - uc->intime >= 3600)
+ {
+ (void) pthread_mutex_lock(&LOCK_user_conn);
+ uc->questions=1;
+ uc->intime=check_time;
+ (void) pthread_mutex_unlock(&LOCK_user_conn);
+ }
+ else if (uc->max_questions && ++(uc->questions) > uc->max_questions)
+ {
+ net_printf(&thd->net, ER_USER_LIMIT_REACHED, uc->user, "max_questions",
+ (long) uc->max_questions);
+ error=1;
+ goto end;
+ }
+
+end:
+ DBUG_RETURN(error);
+}
+
+
+static void reset_mqh(THD *thd, LEX_USER *lu, uint mq)
+{
+
+ (void) pthread_mutex_lock(&LOCK_user_conn);
+ if (lu) // for GRANT
+ {
+ UC *uc;
+ uint temp_len=lu->user.length+lu->host.length+2;
+ char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
+
+ memcpy(temp_user,lu->user.str,lu->user.length);
+ memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length);
+ temp_user[lu->user.length]=temp_user[temp_len-1]=0;
+ if ((uc = (struct user_conn *) hash_search(&hash_user_connections,
+ (byte*) temp_user, temp_len)))
+ {
+ uc->questions=0;
+ uc->max_questions=mq;
+ }
+ }
+ else // for FLUSH PRIVILEGES
+ {
+ for (uint idx=0;idx < hash_user_connections.records; idx++)
+ {
+ char user[USERNAME_LENGTH+1];
+ char *where;
+ UC *uc=(struct user_conn *) hash_element(&hash_user_connections, idx);
+ where=strchr(uc->user,'@');
+ strmake(user,uc->user,where - uc->user);
+ uc->max_questions=get_mqh(user,where+1);
+ }
+ }
+ (void) pthread_mutex_unlock(&LOCK_user_conn);
+}
+
+
+/*
+ Check connnetion and get priviliges
+ Returns 0 on ok, -1 < if error is given > 0 on error.
+*/
static int
check_connections(THD *thd)
{
uint connect_errors=0;
NET *net= &thd->net;
- /*
- ** store the connection details
- */
+ /* Store the connection details */
DBUG_PRINT("info", (("check_connections called by thread %d"),
thd->thread_id));
- DBUG_PRINT("general",("New connection received on %s",
+ DBUG_PRINT("info",("New connection received on %s",
vio_description(net->vio)));
if (!thd->host) // If TCP/IP connection
{
@@ -328,6 +414,7 @@ check_connections(THD *thd)
return (ER_BAD_HOST_ERROR);
if (!(thd->ip = my_strdup(ip,MYF(0))))
return (ER_OUT_OF_RESOURCES);
+ thd->host_or_ip=thd->ip;
#if !defined(HAVE_SYS_UN_H) || defined(HAVE_mit_thread)
/* Fast local hostname resolve for Win32 */
if (!strcmp(thd->ip,"127.0.0.1"))
@@ -341,65 +428,50 @@ check_connections(THD *thd)
if (connect_errors > max_connect_errors)
return(ER_HOST_IS_BLOCKED);
}
- DBUG_PRINT("general",("Host: %s ip: %s",
- thd->host ? thd->host : "unknown host",
- thd->ip ? thd->ip : "unknown ip"));
+ DBUG_PRINT("info",("Host: %s ip: %s",
+ thd->host ? thd->host : "unknown host",
+ thd->ip ? thd->ip : "unknown ip"));
if (acl_check_host(thd->host,thd->ip))
return(ER_HOST_NOT_PRIVILEGED);
}
else /* Hostname given means that the connection was on a socket */
{
- DBUG_PRINT("general",("Host: %s",thd->host));
+ DBUG_PRINT("info",("Host: %s",thd->host));
+ thd->host_or_ip=thd->host;
thd->ip=0;
bzero((char*) &thd->remote,sizeof(struct sockaddr));
}
vio_keepalive(net->vio, TRUE);
- /* nasty, but any other way? */
- uint pkt_len = 0;
+ ulong pkt_len=0;
{
/* buff[] needs to big enough to hold the server_version variable */
char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH+32],*end;
int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB;
+
if (opt_using_transactions)
client_flags|=CLIENT_TRANSACTIONS;
#ifdef HAVE_COMPRESS
client_flags |= CLIENT_COMPRESS;
#endif /* HAVE_COMPRESS */
+#ifdef HAVE_OPENSSL
+ if (ssl_acceptor_fd)
+ client_flags |= CLIENT_SSL; /* Wow, SSL is avalaible! */
+#endif /* HAVE_OPENSSL */
- end=strmov(buff,server_version)+1;
+ end=strnmov(buff,server_version,SERVER_VERSION_LENGTH)+1;
int4store((uchar*) end,thd->thread_id);
end+=4;
memcpy(end,thd->scramble,SCRAMBLE_LENGTH+1);
end+=SCRAMBLE_LENGTH +1;
-#ifdef HAVE_OPENSSL
- if (ssl_acceptor_fd)
- client_flags |= CLIENT_SSL; /* Wow, SSL is avalaible! */
- /*
- * Without SSL the handshake consists of one packet. This packet
- * has both client capabilites and scrambled password.
- * With SSL the handshake might consist of two packets. If the first
- * packet (client capabilities) has CLIENT_SSL flag set, we have to
- * switch to SSL and read the second packet. The scrambled password
- * is in the second packet and client_capabilites field will be ignored.
- * Maybe it is better to accept flags other than CLIENT_SSL from the
- * second packet?
- */
-#define SSL_HANDSHAKE_SIZE 2
-#define NORMAL_HANDSHAKE_SIZE 6
-#define MIN_HANDSHAKE_SIZE 2
-
-#else
-#define MIN_HANDSHAKE_SIZE 6
-#endif /* HAVE_OPENSSL */
int2store(end,client_flags);
- end[2]=MY_CHARSET_CURRENT;
+ end[2]=(char) MY_CHARSET_CURRENT;
int2store(end+3,thd->server_status);
bzero(end+5,13);
end+=18;
- if (net_write_command(net,protocol_version, buff,
+ if (net_write_command(net,(uchar) protocol_version, buff,
(uint) (end-buff)) ||
- (pkt_len=my_net_read(net)) == packet_error ||
+ (pkt_len= my_net_read(net)) == packet_error ||
pkt_len < MIN_HANDSHAKE_SIZE)
{
inc_host_errors(&thd->remote.sin_addr);
@@ -418,23 +490,18 @@ check_connections(THD *thd)
if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
thd->sql_mode|= MODE_IGNORE_SPACE;
#ifdef HAVE_OPENSSL
- DBUG_PRINT("info",
- ("pkt_len:%d, client capabilities: %d",
- pkt_len, thd->client_capabilities) );
+ DBUG_PRINT("info", ("client capabilities: %d", thd->client_capabilities));
if (thd->client_capabilities & CLIENT_SSL)
{
- DBUG_PRINT("info", ("Agreed to change IO layer to SSL") );
/* Do the SSL layering. */
DBUG_PRINT("info", ("IO layer change in progress..."));
- VioSocket* vio_socket = my_reinterpret_cast(VioSocket*)(net->vio);
- VioSSL* vio_ssl = ssl_acceptor_fd->accept(vio_socket);
- net->vio = my_reinterpret_cast(NetVio*) (vio_ssl);
+ sslaccept(ssl_acceptor_fd, net->vio, thd->inactive_timeout);
DBUG_PRINT("info", ("Reading user information over SSL layer"));
if ((pkt_len=my_net_read(net)) == packet_error ||
pkt_len < NORMAL_HANDSHAKE_SIZE)
{
- DBUG_PRINT("info", ("pkt_len:%d", pkt_len));
- DBUG_PRINT("error", ("Failed to read user information"));
+ DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
+ pkt_len));
inc_host_errors(&thd->remote.sin_addr);
return(ER_HANDSHAKE_ERROR);
}
@@ -463,7 +530,7 @@ check_connections(THD *thd)
if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
opt_using_transactions)
thd->net.return_status= &thd->server_status;
- net->timeout=net_read_timeout;
+ net->timeout=(uint) net_read_timeout;
if (check_user(thd,COM_CONNECT, user, passwd, db, 1))
return (-1);
thd->password=test(passwd[0]);
@@ -481,9 +548,9 @@ pthread_handler_decl(handle_one_connection,arg)
pthread_detach_this_thread();
-#if !defined( __WIN__) && !defined(OS2) /* Win32 calls this in pthread_create */
- if (my_thread_init()) // needed to be called first before we call
- // DBUG_ macros
+#if !defined( __WIN__) && !defined(OS2) // Win32 calls this in pthread_create
+ // The following calls needs to be done before we call DBUG_ macros
+ if (my_thread_init())
{
close_connection(&thd->net,ER_OUT_OF_RESOURCES);
statistic_increment(aborted_connects,&LOCK_thread_count);
@@ -492,13 +559,13 @@ pthread_handler_decl(handle_one_connection,arg)
}
#endif
- // handle_one_connection() is the only way a thread would start
- // and would always be on top of the stack
- // therefore, the thread stack always starts at the address of the first
- // local variable of handle_one_connection, which is thd
- // we need to know the start of the stack so that we could check for
- // stack overruns
-
+ /*
+ handle_one_connection() is the only way a thread would start
+ and would always be on top of the stack, therefore, the thread
+ stack always starts at the address of the first local variable
+ of handle_one_connection, which is thd. We need to know the
+ start of the stack so that we could check for stack overruns.
+ */
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_*
@@ -530,7 +597,7 @@ pthread_handler_decl(handle_one_connection,arg)
if ((error=check_connections(thd)))
{ // Wrong permissions
if (error > 0)
- net_printf(net,error,thd->host ? thd->host : thd->ip);
+ net_printf(net,error,thd->host_or_ip);
#ifdef __NT__
if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
sleep(1); /* must wait after eof() */
@@ -554,21 +621,22 @@ pthread_handler_decl(handle_one_connection,arg)
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)
{
if (!thd->killed && opt_warnings)
- sql_print_error(ER(ER_NEW_ABORTING_CONNECTION),
- thd->thread_id,(thd->db ? thd->db : "unconnected"),
- thd->user ? thd->user : "unauthenticated",
- (thd->host ? thd->host : thd->ip ? thd->ip : "unknown"),
- (net->last_errno ? ER(net->last_errno) :
- ER(ER_UNKNOWN_ERROR)));
+ sql_print_error(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(net,net->last_errno,NullS);
thread_safe_increment(aborted_threads,&LOCK_thread_count);
}
-
- decrease_user_connections(thd->user,thd->host);
+
end_thread:
close_connection(net);
end_thread(thd,1);
@@ -628,8 +696,17 @@ pthread_handler_decl(handle_bootstrap,arg)
length--;
buff[length]=0;
thd->current_tablenr=0;
- thd->query= thd->memdup(buff,length+1);
+ 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 (thd->user_connect && check_mqh(thd))
+ {
+ thd->net.error = 0;
+ close_thread_tables(thd); // Free tables
+ free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
+ break;
+ }
mysql_parse(thd,thd->query,length);
close_thread_tables(thd); // Free tables
if (thd->fatal_error)
@@ -664,7 +741,7 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
int error = 0;
DBUG_ENTER("mysql_table_dump");
db = (db && db[0]) ? db : thd->db;
- if (!(table_list = (TABLE_LIST*) sql_calloc(sizeof(TABLE_LIST))))
+ 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->name = tbl_name;
@@ -686,21 +763,19 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
goto err;
thd->free_list = 0;
+ thd->query_length=(uint) strlen(tbl_name);
thd->query = tbl_name;
- if((error = mysqld_dump_create_info(thd, table, -1)))
- {
- my_error(ER_GET_ERRNO, MYF(0));
- goto err;
- }
+ if ((error = mysqld_dump_create_info(thd, table, -1)))
+ {
+ my_error(ER_GET_ERRNO, MYF(0));
+ goto err;
+ }
net_flush(&thd->net);
- error = table->file->dump(thd,fd);
- if(error)
- my_error(ER_GET_ERRNO, MYF(0));
+ if ((error = table->file->dump(thd,fd)))
+ my_error(ER_GET_ERRNO, MYF(0));
err:
-
close_thread_tables(thd);
-
DBUG_RETURN(error);
}
@@ -710,13 +785,10 @@ err:
bool do_command(THD *thd)
{
char *packet;
- uint old_timeout,packet_length;
- bool error=0;
+ uint old_timeout;
+ ulong packet_length;
NET *net;
enum enum_server_command command;
- // commands which will always take a long time should be marked with
- // this so that they will not get logged to the slow query log
- bool slow_command=FALSE;
DBUG_ENTER("do_command");
net= &thd->net;
@@ -724,26 +796,42 @@ bool do_command(THD *thd)
packet=0;
old_timeout=net->timeout;
- net->timeout=thd->inactive_timeout; /* Wait max for 8 hours */
+ net->timeout=(uint) thd->inactive_timeout; // Wait max for 8 hours
net->last_error[0]=0; // Clear error message
net->last_errno=0;
net_new_transaction(net);
if ((packet_length=my_net_read(net)) == packet_error)
{
- DBUG_PRINT("general",("Got error reading command from socket %s",
- vio_description(net->vio) ));
+ DBUG_PRINT("info",("Got error reading command from socket %s",
+ vio_description(net->vio) ));
return TRUE;
}
else
{
packet=(char*) net->read_pos;
command = (enum enum_server_command) (uchar) packet[0];
- DBUG_PRINT("general",("Command on %s = %d (%s)",
- vio_description(net->vio), command,
- command_name[command]));
+ DBUG_PRINT("info",("Command on %s = %d (%s)",
+ vio_description(net->vio), command,
+ command_name[command]));
}
- net->timeout=old_timeout; /* Timeout */
+ net->timeout=old_timeout; // Timeout for writing
+ DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length));
+}
+
+
+bool dispatch_command(enum enum_server_command command, THD *thd,
+ char* packet, uint packet_length)
+{
+ NET *net= &thd->net;
+ bool error=0;
+ /*
+ Commands which will always take a long time should be marked with
+ this so that they will not get logged to the slow query log
+ */
+ bool slow_command=FALSE;
+ DBUG_ENTER("dispatch_command");
+
thd->command=command;
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query_id=query_id;
@@ -752,27 +840,34 @@ bool do_command(THD *thd)
thread_running++;
VOID(pthread_mutex_unlock(&LOCK_thread_count));
thd->set_time();
- thd->lex.options=0; // We store status here
- switch(command) {
+ thd->lex.select_lex.options=0; // We store status here
+ switch (command) {
case COM_INIT_DB:
thread_safe_increment(com_stat[SQLCOM_CHANGE_DB],&LOCK_thread_count);
- if (!mysql_change_db(thd,packet+1))
+ if (!mysql_change_db(thd,packet))
mysql_log.write(thd,command,"%s",thd->db);
break;
+ case COM_REGISTER_SLAVE:
+ {
+ if (register_slave(thd, (uchar*)packet, packet_length))
+ send_error(&thd->net);
+ else
+ send_ok(&thd->net);
+ break;
+ }
case COM_TABLE_DUMP:
{
thread_safe_increment(com_other,&LOCK_thread_count);
slow_command = TRUE;
- char* data = packet + 1;
- uint db_len = *data;
- uint tbl_len = *(data + db_len + 1);
- char* db = sql_alloc(db_len + tbl_len + 2);
- memcpy(db, data + 1, db_len);
+ uint db_len = *(uchar*)packet;
+ uint tbl_len = *(uchar*)(packet + db_len + 1);
+ char* db = thd->alloc(db_len + tbl_len + 2);
+ memcpy(db, packet + 1, db_len);
char* tbl_name = db + db_len;
*tbl_name++ = 0;
- memcpy(tbl_name, data + db_len + 2, tbl_len);
+ memcpy(tbl_name, packet + db_len + 2, tbl_len);
tbl_name[tbl_len] = 0;
- if(mysql_table_dump(thd, db, tbl_name, -1))
+ if (mysql_table_dump(thd, db, tbl_name, -1))
send_error(&thd->net); // dump to NET
break;
@@ -780,16 +875,18 @@ bool do_command(THD *thd)
case COM_CHANGE_USER:
{
thread_safe_increment(com_other,&LOCK_thread_count);
- char *user= (char*) packet+1;
+ char *user= (char*) packet;
char *passwd= strend(user)+1;
char *db= strend(passwd)+1;
/* Save user and privileges */
uint save_master_access=thd->master_access;
uint save_db_access= thd->db_access;
+ uint save_db_length= thd->db_length;
char *save_user= thd->user;
char *save_priv_user= thd->priv_user;
char *save_db= thd->db;
+ UC *save_uc= thd->user_connect;
if ((uint) ((uchar*) db - net->read_pos) > packet_length)
{ // Check if protocol is ok
@@ -803,11 +900,13 @@ bool do_command(THD *thd)
thd->master_access=save_master_access;
thd->db_access=save_db_access;
thd->db=save_db;
+ thd->db_length=save_db_length;
thd->user=save_user;
thd->priv_user=save_priv_user;
break;
}
- decrease_user_connections (save_user, thd->host);
+ if (max_connections && save_uc)
+ decrease_user_connections(save_uc);
x_free((gptr) save_db);
x_free((gptr) save_user);
thd->password=test(passwd[0]);
@@ -816,28 +915,44 @@ bool do_command(THD *thd)
case COM_QUERY:
{
+ packet_length--; // Remove end null
+ /* Remove garage at start and end of query */
+ while (isspace(packet[0]) && packet_length > 0)
+ {
+ packet++;
+ packet_length--;
+ }
char *pos=packet+packet_length; // Point at end null
- /* Remove garage at end of query */
- while (packet_length > 0 && pos[-1] == ';')
+ while (packet_length > 0 && (pos[-1] == ';' || isspace(pos[-1])))
{
pos--;
packet_length--;
}
- *pos=0;
- if (!(thd->query= (char*) thd->memdup((gptr) (packet+1),packet_length)))
+ /* We must allocate some extra memory for query cache */
+ if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet),
+ packet_length,
+ thd->db_length+2)))
break;
+ thd->query[packet_length]=0;
thd->packet.shrink(net_buffer_length); // Reclaim some memory
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),QUERY_PRIOR);
mysql_log.write(thd,command,"%s",thd->query);
DBUG_PRINT("query",("%s",thd->query));
- mysql_parse(thd,thd->query,packet_length-1);
+ if (thd->user_connect && check_mqh(thd))
+ {
+ error = TRUE; // Abort client
+ net->error = 0; // Don't give abort message
+ break;
+ }
+ /* thd->query_length is set by mysql_parse() */
+ mysql_parse(thd,thd->query,packet_length);
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),WAIT_PRIOR);
DBUG_PRINT("info",("query ready"));
break;
}
- case COM_FIELD_LIST: // This isn't actually neaded
+ case COM_FIELD_LIST: // This isn't actually needed
#ifdef DONT_ALLOW_SHOW_COMMANDS
send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
break;
@@ -853,8 +968,11 @@ bool do_command(THD *thd)
break;
}
thd->free_list=0;
- table_list.name=table_list.real_name=thd->strdup(packet+1);
- thd->query=fields=thd->strdup(strend(packet+1)+1);
+ table_list.name=table_list.real_name=thd->strdup(packet);
+ packet=strend(packet)+1;
+ // command not cachable => no gap for data base name
+ if (!(thd->query=fields=thd->memdup(packet,thd->query_length+1)))
+ break;
mysql_log.write(thd,command,"%s %s",table_list.real_name,fields);
remove_escape(table_list.real_name); // This can't have wildcards
@@ -875,10 +993,10 @@ bool do_command(THD *thd)
error=TRUE; // End server
break;
- case COM_CREATE_DB:
+ case COM_CREATE_DB: // QQ: To be removed
{
- char *db=thd->strdup(packet+1);
thread_safe_increment(com_stat[SQLCOM_CREATE_DB],&LOCK_thread_count);
+ char *db=thd->strdup(packet);
// null test to handle EOM
if (!db || !stripp_sp(db) || check_db_name(db))
{
@@ -887,44 +1005,49 @@ bool do_command(THD *thd)
}
if (check_access(thd,CREATE_ACL,db,0,1))
break;
- mysql_log.write(thd,command,packet+1);
- mysql_create_db(thd,db,0);
+ mysql_log.write(thd,command,packet);
+ mysql_create_db(thd,db,0,0);
break;
}
- case COM_DROP_DB:
+ case COM_DROP_DB: // QQ: To be removed
{
- char *db=thd->strdup(packet+1);
thread_safe_increment(com_stat[SQLCOM_DROP_DB],&LOCK_thread_count);
+ char *db=thd->strdup(packet);
// null test to handle EOM
if (!db || !stripp_sp(db) || check_db_name(db))
{
net_printf(&thd->net,ER_WRONG_DB_NAME, db ? db : "NULL");
break;
}
- if (check_access(thd,DROP_ACL,db,0,1) || end_active_trans(thd))
+ if (thd->locked_tables || thd->active_transaction())
+ {
+ send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION);
break;
+ }
mysql_log.write(thd,command,db);
- mysql_rm_db(thd,db,0);
+ mysql_rm_db(thd,db,0,0);
break;
}
case COM_BINLOG_DUMP:
{
thread_safe_increment(com_other,&LOCK_thread_count);
slow_command = TRUE;
- if(check_access(thd, FILE_ACL, any_db))
+ if (check_access(thd, FILE_ACL, any_db))
break;
mysql_log.write(thd,command, 0);
ulong pos;
ushort flags;
uint32 slave_server_id;
- pos = uint4korr(packet + 1);
- flags = uint2korr(packet + 5);
+ pos = uint4korr(packet);
+ flags = uint2korr(packet + 4);
pthread_mutex_lock(&LOCK_server_id);
- kill_zombie_dump_threads(slave_server_id = uint4korr(packet+7));
+ thd->server_id=0; /* avoid suicide */
+ kill_zombie_dump_threads(slave_server_id = uint4korr(packet+6));
thd->server_id = slave_server_id;
pthread_mutex_unlock(&LOCK_server_id);
- mysql_binlog_send(thd, thd->strdup(packet + 11), pos, flags);
+ mysql_binlog_send(thd, thd->strdup(packet + 10), pos, flags);
+ unregister_slave(thd,1,1);
// fake COM_QUIT -- if we get here, the thread needs to terminate
error = TRUE;
net->error = 0;
@@ -932,8 +1055,8 @@ bool do_command(THD *thd)
}
case COM_REFRESH:
{
- uint options=(uchar) packet[1];
thread_safe_increment(com_stat[SQLCOM_FLUSH],&LOCK_thread_count);
+ ulong options= (ulong) (uchar) packet[0];
if (check_access(thd,RELOAD_ACL,any_db))
break;
mysql_log.write(thd,command,NullS);
@@ -941,6 +1064,8 @@ bool do_command(THD *thd)
send_error(net,0);
else
send_eof(net);
+ if (mqh_used)
+ reset_mqh(thd,(LEX_USER *) NULL, 0);
break;
}
case COM_SHUTDOWN:
@@ -970,7 +1095,7 @@ bool do_command(THD *thd)
char buff[200];
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: %d Queries per second avg: %.3f",
+ "Uptime: %ld Threads: %d Questions: %lu Slow queries: %ld Opens: %ld Flush tables: %ld Open tables: %u Queries per second avg: %.3f",
uptime,
(int) thread_count,thd->query_id,long_query_count,
opened_tables,refresh_version, cached_tables(),
@@ -999,7 +1124,7 @@ bool do_command(THD *thd)
case COM_PROCESS_KILL:
{
thread_safe_increment(com_stat[SQLCOM_KILL],&LOCK_thread_count);
- ulong id=(ulong) uint4korr(packet+1);
+ ulong id=(ulong) uint4korr(packet);
kill_one_thread(thd,id);
break;
}
@@ -1037,7 +1162,7 @@ bool do_command(THD *thd)
thd->proc_info="logging slow query";
if ((ulong) (thd->start_time - thd->time_after_lock) > long_query_time ||
- ((thd->lex.options &
+ ((thd->lex.select_lex.options &
(QUERY_NO_INDEX_USED | QUERY_NO_GOOD_INDEX_USED)) &&
(specialflag & SPECIAL_LONG_LOG_FORMAT)))
{
@@ -1068,33 +1193,47 @@ mysql_execute_command(void)
int res=0;
THD *thd=current_thd;
LEX *lex= &thd->lex;
- TABLE_LIST *tables=(TABLE_LIST*) lex->table_list.first;
+ TABLE_LIST *tables=(TABLE_LIST*) lex->select_lex.table_list.first;
+ SELECT_LEX *select_lex = lex->select;
DBUG_ENTER("mysql_execute_command");
if (thd->slave_thread)
{
- // skip if we are in the slave thread, some table
- // rules have been given and the table list says the query should not be
- // replicated
- if(table_rules_on && tables && !tables_ok(thd,tables))
+ /*
+ Skip if we are in the slave thread, some table rules have been
+ given and the table list says the query should not be replicated
+ */
+ if (table_rules_on && tables && !tables_ok(thd,tables))
DBUG_VOID_RETURN;
- // this is a workaround to deal with the shortcoming
- // in 3.23.44-3.23.46 masters
- // in RELEASE_LOCK() logging. We re-write SELECT RELEASE_LOCK() as
- // DO RELEASE_LOCK()
+#ifndef TO_BE_DELETED
+ /*
+ This is a workaround to deal with the shortcoming in 3.23.44-3.23.46
+ masters in RELEASE_LOCK() logging. We re-write SELECT RELEASE_LOCK()
+ as DO RELEASE_LOCK()
+ */
if (lex->sql_command == SQLCOM_SELECT)
{
lex->sql_command = SQLCOM_DO;
- lex->insert_list = &lex->item_list;
+ lex->insert_list = &select_lex->item_list;
}
+#endif
}
+ /*
+ Skip if we are in the slave thread, some table rules have been given
+ and the table list says the query should not be replicated
+ */
+ if ((lex->select_lex.next && create_total_list(thd,lex,&tables)) ||
+ (table_rules_on && tables && thd->slave_thread &&
+ !tables_ok(thd,tables)))
+ DBUG_VOID_RETURN;
+
thread_safe_increment(com_stat[lex->sql_command],&LOCK_thread_count);
switch (lex->sql_command) {
case SQLCOM_SELECT:
{
select_result *result;
- if (lex->options & SELECT_DESCRIBE)
+ if (select_lex->options & SELECT_DESCRIBE)
lex->exchange=0;
if (tables)
{
@@ -1112,10 +1251,12 @@ mysql_execute_command(void)
break; // Error message is given
}
- thd->offset_limit=lex->offset_limit;
- thd->select_limit=lex->select_limit+lex->offset_limit;
- if (thd->select_limit < lex->select_limit)
+ thd->offset_limit=select_lex->offset_limit;
+ thd->select_limit=select_lex->select_limit+select_lex->offset_limit;
+ if (thd->select_limit < select_lex->select_limit)
thd->select_limit= HA_POS_ERROR; // no limit
+ if (thd->select_limit == HA_POS_ERROR)
+ select_lex->options&= ~OPTION_FOUND_ROWS;
if (lex->exchange)
{
@@ -1140,8 +1281,8 @@ mysql_execute_command(void)
{
res= -1;
#ifdef DELETE_ITEMS
- delete lex->having;
- delete lex->where;
+ delete select_lex->having;
+ delete select_lex->where;
#endif
break;
}
@@ -1159,22 +1300,11 @@ mysql_execute_command(void)
if (!(res=open_and_lock_tables(thd,tables)))
{
- res=mysql_select(thd,tables,lex->item_list,
- lex->where,
- (ORDER*) lex->order_list.first,
- (ORDER*) lex->group_list.first,
- lex->having,
- (ORDER*) lex->proc_list.first,
- lex->options | thd->options,
- result);
- if (res)
- result->abort();
+ query_cache.store_query(thd, tables);
+ res=handle_select(thd, lex, result);
}
- delete result;
-#ifdef DELETE_ITEMS
- delete lex->having;
- delete lex->where;
-#endif
+ else
+ delete result;
break;
}
case SQLCOM_DO:
@@ -1186,54 +1316,86 @@ mysql_execute_command(void)
break;
case SQLCOM_PURGE:
- {
- if (check_process_priv(thd))
- goto error;
- res = purge_master_logs(thd, lex->to_log);
- break;
- }
+ {
+ if (check_process_priv(thd))
+ goto error;
+ res = purge_master_logs(thd, lex->to_log);
+ break;
+ }
+ case SQLCOM_SHOW_NEW_MASTER:
+ {
+ if (check_access(thd, FILE_ACL, any_db))
+ goto error;
+ res = show_new_master(thd);
+ break;
+ }
+ case SQLCOM_SHOW_SLAVE_HOSTS:
+ {
+ if (check_access(thd, FILE_ACL, any_db))
+ goto error;
+ res = show_slave_hosts(thd);
+ break;
+ }
+ case SQLCOM_SHOW_BINLOG_EVENTS:
+ {
+ if (check_access(thd, FILE_ACL, any_db))
+ goto error;
+ res = show_binlog_events(thd);
+ break;
+ }
case SQLCOM_BACKUP_TABLE:
- {
- if (check_db_used(thd,tables) ||
- check_table_access(thd,SELECT_ACL, tables) ||
- check_access(thd, FILE_ACL, any_db))
- goto error; /* purecov: inspected */
- res = mysql_backup_table(thd, tables);
+ {
+ if (check_db_used(thd,tables) ||
+ check_table_access(thd,SELECT_ACL, tables) ||
+ check_access(thd, FILE_ACL, any_db))
+ goto error; /* purecov: inspected */
+ res = mysql_backup_table(thd, tables);
- break;
- }
+ break;
+ }
case SQLCOM_RESTORE_TABLE:
- {
- if (check_db_used(thd,tables) ||
- check_table_access(thd,INSERT_ACL, tables) ||
- check_access(thd, FILE_ACL, any_db))
- goto error; /* purecov: inspected */
- res = mysql_restore_table(thd, tables);
- break;
- }
+ {
+ if (check_db_used(thd,tables) ||
+ check_table_access(thd,INSERT_ACL, tables) ||
+ check_access(thd, FILE_ACL, any_db))
+ goto error; /* purecov: inspected */
+ res = mysql_restore_table(thd, tables);
+ break;
+ }
case SQLCOM_CHANGE_MASTER:
- {
- if(check_access(thd, PROCESS_ACL, any_db))
- goto error;
- res = change_master(thd);
- break;
- }
+ {
+ if (check_access(thd, PROCESS_ACL, any_db))
+ goto error;
+ LOCK_ACTIVE_MI;
+ res = change_master(thd,active_mi);
+ UNLOCK_ACTIVE_MI;
+ break;
+ }
case SQLCOM_SHOW_SLAVE_STAT:
- {
- if (check_process_priv(thd))
- goto error;
- res = show_master_info(thd);
- break;
- }
+ {
+ if (check_process_priv(thd))
+ goto error;
+ LOCK_ACTIVE_MI;
+ res = show_master_info(thd,active_mi);
+ UNLOCK_ACTIVE_MI;
+ break;
+ }
case SQLCOM_SHOW_MASTER_STAT:
- {
- if (check_process_priv(thd))
- goto error;
- res = show_binlog_info(thd);
- break;
- }
+ {
+ if (check_process_priv(thd))
+ goto error;
+ res = show_binlog_info(thd);
+ break;
+ }
+
+ case SQLCOM_LOAD_MASTER_DATA: // sync with master
+ if (check_process_priv(thd))
+ goto error;
+ res = load_master_data(thd);
+ break;
+
case SQLCOM_LOAD_MASTER_TABLE:
-
+ {
if (!tables->db)
tables->db=thd->db;
if (check_access(thd,CREATE_ACL,tables->db,&tables->grant.privilege))
@@ -1246,21 +1408,23 @@ mysql_execute_command(void)
bool error=check_grant(thd,CREATE_ACL,tables);
tables->next=tmp_table_list;
if (error)
- goto error;
+ goto error;
}
if (strlen(tables->name) > NAME_LEN)
{
net_printf(&thd->net,ER_WRONG_TABLE_NAME,tables->name);
break;
}
-
- thd->last_nx_table = tables->real_name;
- thd->last_nx_db = tables->db;
- if (fetch_nx_table(thd, &glob_mi))
- break; // fetch_nx_table did send the error to the client
- send_ok(&thd->net);
+ LOCK_ACTIVE_MI;
+ // fetch_master_table will send the error to the client on failure
+ if (!fetch_master_table(thd, tables->db, tables->real_name,
+ active_mi, 0))
+ {
+ send_ok(&thd->net);
+ }
+ UNLOCK_ACTIVE_MI;
break;
-
+ }
case SQLCOM_CREATE_TABLE:
if (!tables->db)
tables->db=thd->db;
@@ -1285,12 +1449,25 @@ mysql_execute_command(void)
res=0;
break;
}
- if (lex->item_list.elements) // With select
+#ifndef HAVE_READLINK
+ lex->create_info.data_file_name=lex->create_info.index_file_name=0;
+#else
+ /* Fix names if symlinked tables */
+ if (append_file_to_dir(thd, &lex->create_info.data_file_name,
+ tables->name) ||
+ append_file_to_dir(thd,&lex->create_info.index_file_name,
+ tables->name))
+ {
+ res=-1;
+ break;
+ }
+#endif
+ if (select_lex->item_list.elements) // With select
{
select_result *result;
if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
- check_dup(thd,tables->db,tables->real_name,tables->next))
+ check_dup(tables->db, tables->real_name, tables->next))
{
net_printf(&thd->net,ER_INSERT_TABLE_USED,tables->real_name);
DBUG_VOID_RETURN;
@@ -1303,31 +1480,22 @@ mysql_execute_command(void)
for (table = tables->next ; table ; table=table->next)
table->lock_type= lex->lock_option;
}
- thd->offset_limit=lex->offset_limit;
- thd->select_limit=lex->select_limit+lex->offset_limit;
- if (thd->select_limit < lex->select_limit)
+ thd->offset_limit=select_lex->offset_limit;
+ thd->select_limit=select_lex->select_limit+select_lex->offset_limit;
+ if (thd->select_limit < select_lex->select_limit)
thd->select_limit= HA_POS_ERROR; // No limit
+ /* Skip first table, which is the table we are creating */
+ lex->select_lex.table_list.first=
+ (byte*) (((TABLE_LIST *) lex->select_lex.table_list.first)->next);
if (!(res=open_and_lock_tables(thd,tables->next)))
{
- if ((result=new select_create(tables->db ? tables->db : thd->db,
- tables->real_name, &lex->create_info,
- lex->create_list,
- lex->key_list,
- lex->item_list,lex->duplicates)))
- {
- res=mysql_select(thd,tables->next,lex->item_list,
- lex->where,
- (ORDER*) lex->order_list.first,
- (ORDER*) lex->group_list.first,
- lex->having,
- (ORDER*) lex->proc_list.first,
- lex->options | thd->options,
- result);
- if (res)
- result->abort();
- delete result;
- }
+ if ((result=new select_create(tables->db ? tables->db : thd->db,
+ tables->real_name, &lex->create_info,
+ lex->create_list,
+ lex->key_list,
+ select_lex->item_list,lex->duplicates)))
+ res=handle_select(thd, lex, result);
else
res= -1;
}
@@ -1356,12 +1524,19 @@ mysql_execute_command(void)
break;
case SQLCOM_SLAVE_START:
- start_slave(thd);
+ {
+ LOCK_ACTIVE_MI;
+ start_slave(thd,active_mi,1 /* net report*/);
+ UNLOCK_ACTIVE_MI;
break;
+ }
case SQLCOM_SLAVE_STOP:
- stop_slave(thd);
+ {
+ LOCK_ACTIVE_MI;
+ stop_slave(thd,active_mi,1/* net report*/);
+ UNLOCK_ACTIVE_MI;
break;
-
+ }
case SQLCOM_ALTER_TABLE:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
@@ -1377,10 +1552,10 @@ mysql_execute_command(void)
}
if (!tables->db)
tables->db=thd->db;
- if (!lex->db)
- lex->db=tables->db;
+ if (!select_lex->db)
+ select_lex->db=tables->db;
if (check_access(thd,ALTER_ACL,tables->db,&tables->grant.privilege) ||
- check_access(thd,INSERT_ACL | CREATE_ACL,lex->db,&priv) ||
+ check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv) ||
check_merge_table_access(thd, tables->db,
(TABLE_LIST *)
lex->create_info.merge_list.first))
@@ -1396,22 +1571,27 @@ mysql_execute_command(void)
TABLE_LIST tmp_table;
bzero((char*) &tmp_table,sizeof(tmp_table));
tmp_table.real_name=lex->name;
- tmp_table.db=lex->db;
+ tmp_table.db=select_lex->db;
tmp_table.grant.privilege=priv;
if (check_grant(thd,INSERT_ACL | CREATE_ACL,tables))
goto error;
}
}
+ /* Don't yet allow changing of symlinks with ALTER TABLE */
+ 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;
else
- res= mysql_alter_table(thd, lex->db, lex->name,
+ {
+ res= mysql_alter_table(thd, select_lex->db, lex->name,
&lex->create_info,
tables, lex->create_list,
lex->key_list, lex->drop_list, lex->alter_list,
- (ORDER *) lex->order_list.first,
- lex->drop_primary, lex->duplicates);
+ (ORDER *) select_lex->order_list.first,
+ lex->drop_primary, lex->duplicates,
+ lex->alter_keys_onoff, lex->simple_alter);
+ }
break;
}
#endif
@@ -1435,11 +1615,12 @@ mysql_execute_command(void)
old_list.next=new_list.next=0;
if (check_grant(thd,ALTER_ACL,&old_list) ||
(!test_all_bits(table->next->grant.privilege,
- INSERT_ACL | CREATE_ACL) &&
+ INSERT_ACL | CREATE_ACL) &&
check_grant(thd,INSERT_ACL | CREATE_ACL, &new_list)))
goto error;
}
}
+ query_cache.invalidate(tables);
if (end_active_trans(thd))
res= -1;
else if (mysql_rename_tables(thd,tables))
@@ -1473,21 +1654,23 @@ mysql_execute_command(void)
}
#endif
case SQLCOM_REPAIR:
- {
- if (check_db_used(thd,tables) ||
- check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
- goto error; /* purecov: inspected */
- res = mysql_repair_table(thd, tables, &lex->check_opt);
- break;
- }
+ {
+ if (check_db_used(thd,tables) ||
+ check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
+ goto error; /* purecov: inspected */
+ res = mysql_repair_table(thd, tables, &lex->check_opt);
+ query_cache.invalidate(tables);
+ break;
+ }
case SQLCOM_CHECK:
- {
- if (check_db_used(thd,tables) ||
- check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables))
- goto error; /* purecov: inspected */
- res = mysql_check_table(thd, tables, &lex->check_opt);
- break;
- }
+ {
+ if (check_db_used(thd,tables) ||
+ check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables))
+ goto error; /* purecov: inspected */
+ res = mysql_check_table(thd, tables, &lex->check_opt);
+ query_cache.invalidate(tables);
+ break;
+ }
case SQLCOM_ANALYZE:
{
if (check_db_used(thd,tables) ||
@@ -1529,23 +1712,73 @@ mysql_execute_command(void)
goto error;
if (grant_option && check_grant(thd,UPDATE_ACL,tables))
goto error;
- if (lex->item_list.elements != lex->value_list.elements)
+ if (select_lex->item_list.elements != lex->value_list.elements)
{
send_error(&thd->net,ER_WRONG_VALUE_COUNT);
DBUG_VOID_RETURN;
}
- res = mysql_update(thd,tables,
- lex->item_list,
- lex->value_list,
- lex->where,
- lex->select_limit,
- lex->duplicates,
- lex->lock_option);
+ if (select_lex->table_list.elements == 1)
+ {
+ res = mysql_update(thd,tables,
+ select_lex->item_list,
+ lex->value_list,
+ select_lex->where,
+ (ORDER *) select_lex->order_list.first,
+ select_lex->select_limit,
+ lex->duplicates,
+ lex->lock_option);
#ifdef DELETE_ITEMS
- delete lex->where;
+ delete select_lex->where;
#endif
- break;
+ }
+ else
+ {
+ multi_update *result;
+ uint table_count;
+ TABLE_LIST *auxi;
+ lex->sql_command=SQLCOM_MULTI_UPDATE;
+ for (auxi=(TABLE_LIST*) tables, table_count=0 ; auxi ; auxi=auxi->next)
+ {
+ table_count++;
+ auxi->lock_type=TL_WRITE;
+ }
+ if (select_lex->order_list.elements || (select_lex->select_limit && select_lex->select_limit < INT_MAX))
+ {
+ send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /// will have to come up with something better eventually
+ DBUG_VOID_RETURN;
+ }
+ tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
+ if ((res=open_and_lock_tables(thd,tables)))
+ break;
+ if (!setup_fields(thd,tables,select_lex->item_list,1,0,0) &&
+ !setup_fields(thd,tables,lex->value_list,0,0,0) && ! thd->fatal_error &&
+ (result=new multi_update(thd,tables,select_lex->item_list,lex->duplicates,
+ lex->lock_option, table_count)))
+ {
+ List <Item> total_list;
+ List_iterator <Item> field_list(select_lex->item_list);
+ List_iterator <Item> value_list(lex->value_list);
+ Item *item;
+ while ((item=field_list++))
+ total_list.push_back(item);
+ while ((item=value_list++))
+ total_list.push_back(item);
+
+ res=mysql_select(thd,tables,total_list,
+ select_lex->where,
+ (ORDER *)NULL,(ORDER *)NULL,(Item *)NULL,
+ (ORDER *)NULL,
+ select_lex->options | thd->options |
+ SELECT_NO_JOIN_CACHE,
+ result);
+ delete result;
+ }
+ else
+ res= -1; // Error is not sent
+ close_thread_tables(thd);
+ }
+ break;
case SQLCOM_INSERT:
if (check_access(thd,INSERT_ACL,tables->db,&tables->grant.privilege))
goto error; /* purecov: inspected */
@@ -1570,6 +1803,7 @@ mysql_execute_command(void)
case SQLCOM_REPLACE_SELECT:
case SQLCOM_INSERT_SELECT:
{
+
// Check that we have modify privileges for the first table and
// select privileges for the rest
{
@@ -1587,51 +1821,50 @@ mysql_execute_command(void)
}
select_result *result;
- thd->offset_limit=lex->offset_limit;
- thd->select_limit=lex->select_limit+lex->offset_limit;
- if (thd->select_limit < lex->select_limit)
+ thd->offset_limit=select_lex->offset_limit;
+ thd->select_limit=select_lex->select_limit+select_lex->offset_limit;
+ if (thd->select_limit < select_lex->select_limit)
thd->select_limit= HA_POS_ERROR; // No limit
- if (check_dup(thd,tables->db,tables->real_name,tables->next))
+ if (check_dup(tables->db, tables->real_name, tables->next))
{
net_printf(&thd->net,ER_INSERT_TABLE_USED,tables->real_name);
DBUG_VOID_RETURN;
}
- tables->lock_type=TL_WRITE; // update first table
+ tables->lock_type=TL_WRITE; // update first table
{
TABLE_LIST *table;
for (table = tables->next ; table ; table=table->next)
table->lock_type= lex->lock_option;
}
- if (!(res=open_and_lock_tables(thd,tables)))
+
+ /* Skip first table, which is the table we are inserting in */
+ lex->select_lex.table_list.first=
+ (byte*) (((TABLE_LIST *) lex->select_lex.table_list.first)->next);
+ if (!(res=open_and_lock_tables(thd, tables)))
{
if ((result=new select_insert(tables->table,&lex->field_list,
- lex->sql_command == SQLCOM_REPLACE_SELECT ?
- DUP_REPLACE : DUP_IGNORE)))
- {
- res=mysql_select(thd,tables->next,lex->item_list,
- lex->where,
- (ORDER*) lex->order_list.first,
- (ORDER*) lex->group_list.first,
- lex->having,
- (ORDER*) lex->proc_list.first,
- lex->options | thd->options,
- result);
- delete result;
- }
- else
- res= -1;
+ lex->duplicates)))
+ res=handle_select(thd,lex,result);
}
-#ifdef DELETE_ITEMS
- delete lex->having;
- delete lex->where;
-#endif
+ else
+ res= -1;
break;
}
case SQLCOM_TRUNCATE:
- lex->where=0;
- lex->select_limit=HA_POS_ERROR;
- /* Fall through */
+ if (check_access(thd,DELETE_ACL,tables->db,&tables->grant.privilege))
+ goto error; /* purecov: inspected */
+ /*
+ Don't allow this within a transaction because we want to use
+ re-generate table
+ */
+ if (thd->locked_tables || thd->active_transaction())
+ {
+ send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION,NullS);
+ goto error;
+ }
+ res=mysql_truncate(thd,tables);
+ break;
case SQLCOM_DELETE:
{
if (check_access(thd,DELETE_ACL,tables->db,&tables->grant.privilege))
@@ -1644,20 +1877,87 @@ mysql_execute_command(void)
if (lex->sql_command == SQLCOM_TRUNCATE && end_active_trans(thd))
res= -1;
else
- res = mysql_delete(thd,tables,lex->where,lex->select_limit,
- lex->lock_option, lex->options);
+ res = mysql_delete(thd,tables, select_lex->where,
+ (ORDER*) select_lex->order_list.first,
+ select_lex->select_limit, lex->lock_option,
+ select_lex->options);
break;
}
- case SQLCOM_DROP_TABLE:
+ case SQLCOM_DELETE_MULTI:
+ {
+ TABLE_LIST *aux_tables=(TABLE_LIST *)thd->lex.auxilliary_table_list.first;
+ TABLE_LIST *auxi;
+ uint table_count=0;
+ multi_delete *result;
+
+ /* sql_yacc guarantees that tables and aux_tables are not zero */
+ if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
+ check_table_access(thd,SELECT_ACL, tables) ||
+ check_table_access(thd,DELETE_ACL, aux_tables))
+ goto error;
+ if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
+ {
+ send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
+ goto error;
+ }
+ for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next)
{
- if (check_table_access(thd,DROP_ACL,tables))
- goto error; /* purecov: inspected */
- if (end_active_trans(thd))
- res= -1;
- else
- res = mysql_rm_table(thd,tables,lex->drop_if_exists);
+ table_count++;
+ /* All tables in aux_tables must be found in FROM PART */
+ TABLE_LIST *walk;
+ for (walk=(TABLE_LIST*) tables ; walk ; walk=walk->next)
+ {
+ if (!strcmp(auxi->real_name,walk->real_name) &&
+ !strcmp(walk->db,auxi->db))
+ break;
+ }
+ if (!walk)
+ {
+ net_printf(&thd->net,ER_NONUNIQ_TABLE,auxi->real_name);
+ goto error;
+ }
+ auxi->lock_type=walk->lock_type=TL_WRITE;
+ auxi->table= (TABLE *) walk; // Remember corresponding table
}
+ tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
+ if (add_item_to_list(new Item_null()))
+ {
+ res= -1;
+ break;
+ }
+ thd->proc_info="init";
+ if ((res=open_and_lock_tables(thd,tables)))
+ break;
+ /* Fix tables-to-be-deleted-from list to point at opened tables */
+ for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next)
+ auxi->table= ((TABLE_LIST*) auxi->table)->table;
+ if (!thd->fatal_error && (result=new multi_delete(thd,aux_tables,
+ lex->lock_option,table_count)))
+ {
+ res=mysql_select(thd,tables,select_lex->item_list,
+ select_lex->where,
+ (ORDER *)NULL,(ORDER *)NULL,(Item *)NULL,
+ (ORDER *)NULL,
+ select_lex->options | thd->options |
+ SELECT_NO_JOIN_CACHE,
+ result);
+ delete result;
+ }
+ else
+ res= -1; // Error is not sent
+ close_thread_tables(thd);
break;
+ }
+ case SQLCOM_DROP_TABLE:
+ {
+ if (check_table_access(thd,DROP_ACL,tables))
+ goto error; /* purecov: inspected */
+ if (end_active_trans(thd))
+ res= -1;
+ else
+ res = mysql_rm_table(thd,tables,lex->drop_if_exists);
+ }
+ break;
case SQLCOM_DROP_INDEX:
if (!tables->db)
tables->db=thd->db;
@@ -1672,7 +1972,7 @@ mysql_execute_command(void)
break;
case SQLCOM_SHOW_DATABASES:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
- send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
+ send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
DBUG_VOID_RETURN;
#else
if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
@@ -1708,13 +2008,12 @@ mysql_execute_command(void)
#endif
case SQLCOM_SHOW_TABLES:
/* FALL THROUGH */
- case SQLCOM_SHOW_OPEN_TABLES:
#ifdef DONT_ALLOW_SHOW_COMMANDS
send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
DBUG_VOID_RETURN;
#else
{
- char *db=lex->db ? lex->db : thd->db;
+ char *db=select_lex->db ? select_lex->db : thd->db;
if (!db)
{
send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */
@@ -1729,34 +2028,32 @@ mysql_execute_command(void)
if (check_access(thd,SELECT_ACL,db,&thd->col_access))
goto error; /* purecov: inspected */
/* grant is checked in mysqld_show_tables */
- if (lex->sql_command == SQLCOM_SHOW_OPEN_TABLES)
- res= mysqld_show_open_tables(thd,db,
- (lex->wild ? lex->wild->ptr() : NullS));
- else if (lex->options & SELECT_DESCRIBE)
+ if (select_lex->options & SELECT_DESCRIBE)
res= mysqld_extend_show_tables(thd,db,
- (lex->wild ? lex->wild->ptr() : NullS));
+ (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_FIELDS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
DBUG_VOID_RETURN;
#else
{
- char *db=tables->db ? tables->db : thd->db;
- if (!db)
+ char *db=tables->db;
+ if (!*db)
{
send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */
goto error; /* purecov: inspected */
}
remove_escape(db); // Fix escaped '_'
remove_escape(tables->name);
- if (!tables->db)
- tables->db=thd->db;
if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,&thd->col_access))
goto error; /* purecov: inspected */
tables->grant.privilege=thd->col_access;
@@ -1774,7 +2071,7 @@ mysql_execute_command(void)
DBUG_VOID_RETURN;
#else
{
- char *db=tables->db ? tables->db : thd->db;
+ char *db=tables->db;
if (!db)
{
send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */
@@ -1794,7 +2091,7 @@ mysql_execute_command(void)
}
#endif
case SQLCOM_CHANGE_DB:
- mysql_change_db(thd,lex->db);
+ mysql_change_db(thd,select_lex->db);
break;
case SQLCOM_LOAD:
{
@@ -1815,7 +2112,7 @@ mysql_execute_command(void)
goto error;
}
if (check_access(thd,privilege,tables->db,&tables->grant.privilege) ||
- grant_option && check_grant(thd,privilege,tables))
+ grant_option && check_grant(thd,privilege,tables))
goto error;
}
res=mysql_load(thd, lex->exchange, tables, lex->field_list,
@@ -1824,22 +2121,17 @@ mysql_execute_command(void)
}
case SQLCOM_SET_OPTION:
{
- uint org_options=thd->options;
- thd->options=lex->options;
+ ulong org_options=thd->options;
+ thd->options=select_lex->options;
thd->update_lock_default= ((thd->options & OPTION_LOW_PRIORITY_UPDATES) ?
TL_WRITE_LOW_PRIORITY : TL_WRITE);
- thd->default_select_limit=lex->select_limit;
+ thd->default_select_limit=select_lex->select_limit;
thd->tx_isolation=lex->tx_isolation;
- if (thd->gemini_spin_retries != lex->gemini_spin_retries)
- {
- thd->gemini_spin_retries= lex->gemini_spin_retries;
- ha_set_spin_retries(thd->gemini_spin_retries);
- }
DBUG_PRINT("info",("options: %ld limit: %ld",
thd->options,(long) thd->default_select_limit));
/* Check if auto_commit mode changed */
- if ((org_options ^ lex->options) & OPTION_NOT_AUTO_COMMIT)
+ if ((org_options ^ select_lex->options) & OPTION_NOT_AUTO_COMMIT)
{
if ((org_options & OPTION_NOT_AUTO_COMMIT))
{
@@ -1873,13 +2165,7 @@ mysql_execute_command(void)
thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
}
if (thd->global_read_lock)
- {
- thd->global_read_lock=0;
- pthread_mutex_lock(&LOCK_open);
- global_read_lock--;
- pthread_cond_broadcast(&COND_refresh);
- pthread_mutex_unlock(&LOCK_open);
- }
+ unlock_global_read_lock(thd);
send_ok(&thd->net);
break;
case SQLCOM_LOCK_TABLES:
@@ -1891,6 +2177,8 @@ mysql_execute_command(void)
}
if (check_db_used(thd,tables) || end_active_trans(thd))
goto error;
+ if (grant_option && check_grant(thd,SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL,tables))
+ goto error;
thd->in_lock_tables=1;
thd->options|= OPTION_TABLE_LOCK;
if (!(res=open_and_lock_tables(thd,tables)))
@@ -1904,30 +2192,34 @@ mysql_execute_command(void)
thd->in_lock_tables=0;
break;
case SQLCOM_CREATE_DB:
+ {
+ if (!stripp_sp(lex->name) || check_db_name(lex->name))
{
- if (!stripp_sp(lex->name) || check_db_name(lex->name))
- {
- net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name);
- break;
- }
- if (check_access(thd,CREATE_ACL,lex->name,0,1))
- break;
- mysql_create_db(thd,lex->name,lex->create_info.options);
+ net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name);
break;
}
+ if (check_access(thd,CREATE_ACL,lex->name,0,1))
+ break;
+ res=mysql_create_db(thd,lex->name,lex->create_info.options,0);
+ break;
+ }
case SQLCOM_DROP_DB:
+ {
+ if (!stripp_sp(lex->name) || check_db_name(lex->name))
{
- if (!stripp_sp(lex->name) || check_db_name(lex->name))
- {
- net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name);
- break;
- }
- if (check_access(thd,DROP_ACL,lex->name,0,1) ||
- end_active_trans(thd))
- break;
- mysql_rm_db(thd,lex->name,lex->drop_if_exists);
+ net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name);
+ break;
+ }
+ if (check_access(thd,DROP_ACL,lex->name,0,1))
break;
+ if (thd->locked_tables || thd->active_transaction())
+ {
+ send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION);
+ goto error;
}
+ res=mysql_rm_db(thd,lex->name,lex->drop_if_exists,0);
+ break;
+ }
case SQLCOM_CREATE_FUNCTION:
if (check_access(thd,INSERT_ACL,"mysql",0,1))
break;
@@ -1948,78 +2240,83 @@ mysql_execute_command(void)
res= -1;
#endif
break;
- case SQLCOM_REVOKE:
- case SQLCOM_GRANT:
- {
- if (tables && !tables->db)
- tables->db=thd->db;
- if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
- tables && tables->db ? tables->db : lex->db,
- tables ? &tables->grant.privilege : 0,
- tables ? 0 : 1))
- 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;
- List_iterator <LEX_USER> user_list(lex->users_list);
- while ((user=user_list++))
- {
- if (user->password.str &&
- (strcmp(thd->user,user->user.str) ||
- user->host.str &&
- my_strcasecmp(user->host.str, thd->host ? thd->host : thd->ip)))
- {
- if (check_access(thd, UPDATE_ACL, "mysql",0,1))
- goto error;
- break; // We are allowed to do changes
- }
- }
- }
- if (tables)
- {
- if (grant_option && check_grant(thd,
- (lex->grant | lex->grant_tot_col |
- GRANT_ACL),
- tables))
- goto error;
- res = mysql_table_grant(thd,tables,lex->users_list, lex->columns,
- 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())
- {
- Query_log_event qinfo(thd, thd->query);
- mysql_bin_log.write(&qinfo);
- }
- }
- }
- else
- {
- if (lex->columns.elements)
- {
- net_printf(&thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
- res=1;
- }
- else
- res = mysql_grant(thd, 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())
- {
- Query_log_event qinfo(thd, thd->query);
- mysql_bin_log.write(&qinfo);
- }
- }
- }
- break;
- }
+ case SQLCOM_REVOKE:
+ case SQLCOM_GRANT:
+ {
+ if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
+ tables && tables->db ? tables->db : select_lex->db,
+ tables ? &tables->grant.privilege : 0,
+ tables ? 0 : 1))
+ 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;
+ List_iterator <LEX_USER> user_list(lex->users_list);
+ while ((user=user_list++))
+ {
+ if (user->password.str &&
+ (strcmp(thd->user,user->user.str) ||
+ user->host.str &&
+ my_strcasecmp(user->host.str, thd->host_or_ip)))
+ {
+ if (check_access(thd, UPDATE_ACL, "mysql",0,1))
+ goto error;
+ break; // We are allowed to do changes
+ }
+ }
+ }
+ if (tables)
+ {
+ if (grant_option && check_grant(thd,
+ (lex->grant | lex->grant_tot_col |
+ GRANT_ACL),
+ tables))
+ goto error;
+ if (!(res = mysql_table_grant(thd,tables,lex->users_list, lex->columns,
+ lex->grant,
+ lex->sql_command == SQLCOM_REVOKE)))
+ {
+ mysql_update_log.write(thd, thd->query, thd->query_length);
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query);
+ mysql_bin_log.write(&qinfo);
+ }
+ }
+ }
+ else
+ {
+ if (lex->columns.elements)
+ {
+ send_error(&thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
+ res=1;
+ }
+ 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())
+ {
+ Query_log_event qinfo(thd, thd->query);
+ mysql_bin_log.write(&qinfo);
+ }
+ if (mqh_used && lex->mqh)
+ {
+ List_iterator <LEX_USER> str_list(lex->users_list);
+ LEX_USER *user;
+ while ((user=str_list++))
+ reset_mqh(thd,user,lex->mqh);
+ }
+ }
+ }
+ break;
+ }
case SQLCOM_FLUSH:
case SQLCOM_RESET:
if (check_access(thd,RELOAD_ACL,any_db) || check_db_used(thd, tables))
@@ -2034,13 +2331,40 @@ mysql_execute_command(void)
break;
case SQLCOM_SHOW_GRANTS:
res=0;
- if ((thd->priv_user && !strcmp(thd->priv_user,lex->grant_user->user.str)) ||
+ if ((thd->priv_user &&
+ !strcmp(thd->priv_user,lex->grant_user->user.str)) ||
!check_access(thd, SELECT_ACL, "mysql",0,1))
{
res = mysql_show_grants(thd,lex->grant_user);
}
break;
+ case SQLCOM_HA_OPEN:
+ if (check_db_used(thd,tables) ||
+ check_table_access(thd,SELECT_ACL, tables))
+ goto error;
+ res = mysql_ha_open(thd, tables);
+ break;
+ case SQLCOM_HA_CLOSE:
+ if (check_db_used(thd,tables))
+ goto error;
+ res = mysql_ha_close(thd, tables);
+ break;
+ case SQLCOM_HA_READ:
+ if (check_db_used(thd,tables) ||
+ check_table_access(thd,SELECT_ACL, 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);
+ break;
+
case SQLCOM_BEGIN:
+ if (thd->locked_tables)
+ {
+ thd->lock=thd->locked_tables;
+ thd->locked_tables=0; // Will be automaticly closed
+ close_thread_tables(thd); // Free tables
+ }
if (end_active_trans(thd))
{
res= -1;
@@ -2059,13 +2383,17 @@ mysql_execute_command(void)
even if there is a problem with the OPTION_AUTO_COMMIT flag
(Which of course should never happen...)
*/
+ {
thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
if (!ha_commit(thd))
+ {
send_ok(&thd->net);
+ }
else
res= -1;
break;
+ }
case SQLCOM_ROLLBACK:
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
if (!ha_rollback(thd))
@@ -2104,7 +2432,7 @@ error:
bool
check_access(THD *thd,uint want_access,const char *db, uint *save_priv,
- bool dont_check_global_grants)
+ bool dont_check_global_grants, bool no_errors)
{
uint db_access,dummy;
if (save_priv)
@@ -2112,9 +2440,10 @@ check_access(THD *thd,uint want_access,const char *db, uint *save_priv,
else
save_priv= &dummy;
- if (!db && !thd->db && !dont_check_global_grants)
+ if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
{
- send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: tested */
+ if (!no_errors)
+ send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: tested */
return TRUE; /* purecov: tested */
}
@@ -2126,16 +2455,17 @@ check_access(THD *thd,uint want_access,const char *db, uint *save_priv,
if ((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL) ||
! db && dont_check_global_grants)
{ // We can never grant this
- net_printf(&thd->net,ER_ACCESS_DENIED_ERROR,
- thd->priv_user,
- thd->host ? thd->host : (thd->ip ? thd->ip : "unknown"),
- thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */
+ if (!no_errors)
+ net_printf(&thd->net,ER_ACCESS_DENIED_ERROR,
+ thd->priv_user,
+ thd->host_or_ip,
+ thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */
return TRUE; /* purecov: tested */
}
if (db == any_db)
return FALSE; // Allow select on anything
-
+
if (db && (!thd->db || strcmp(db,thd->db)))
db_access=acl_get(thd->host, thd->ip, (char*) &thd->remote.sin_addr,
thd->priv_user, db); /* purecov: inspected */
@@ -2149,10 +2479,11 @@ check_access(THD *thd,uint want_access,const char *db, uint *save_priv,
((grant_option && !dont_check_global_grants) &&
!(want_access & ~TABLE_ACLS)))
return FALSE; /* Ok */
- net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR,
- thd->priv_user,
- thd->host ? thd->host : (thd->ip ? thd->ip : "unknown"),
- db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */
+ if (!no_errors)
+ net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR,
+ thd->priv_user,
+ thd->host_or_ip,
+ db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */
return TRUE; /* purecov: tested */
}
@@ -2169,7 +2500,8 @@ bool check_process_priv(THD *thd)
*/
bool
-check_table_access(THD *thd,uint want_access,TABLE_LIST *tables)
+check_table_access(THD *thd,uint want_access,TABLE_LIST *tables,
+ bool no_errors)
{
uint found=0,found_access=0;
TABLE_LIST *org_tables=tables;
@@ -2184,20 +2516,20 @@ check_table_access(THD *thd,uint want_access,TABLE_LIST *tables)
tables->grant.privilege=found_access;
else
{
- if (check_access(thd,want_access,tables->db,&tables->grant.privilege))
+ if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
+ 0, no_errors))
return TRUE; // Access denied
found_access=tables->grant.privilege;
found=1;
}
}
- else if (check_access(thd,want_access,tables->db,&tables->grant.privilege))
+ else if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
+ 0, no_errors))
return TRUE; // Access denied
}
if (grant_option)
- {
- want_access &= ~EXTRA_ACL; // Remove SHOW attribute
- return check_grant(thd,want_access,org_tables);
- }
+ return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
+ test(want_access & EXTRA_ACL), no_errors);
return FALSE;
}
@@ -2301,42 +2633,75 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, int *yystacksize)
/****************************************************************************
- Initialize global thd variables neaded for query
+ Initialize global thd variables needed for query
****************************************************************************/
static void
mysql_init_query(THD *thd)
{
DBUG_ENTER("mysql_init_query");
- thd->lex.item_list.empty();
+ thd->lex.select_lex.item_list.empty();
thd->lex.value_list.empty();
- thd->lex.table_list.elements=0;
- thd->free_list=0;
-
- thd->lex.table_list.first=0;
- thd->lex.table_list.next= (byte**) &thd->lex.table_list.first;
+ thd->lex.select_lex.table_list.elements=0;
+ thd->free_list=0; thd->lex.union_option=0;
+ thd->lex.select = &thd->lex.select_lex;
+ thd->lex.select_lex.table_list.first=0;
+ thd->lex.select_lex.table_list.next= (byte**) &thd->lex.select_lex.table_list.first;
+ thd->lex.select_lex.next=0;
thd->fatal_error=0; // Safety
thd->last_insert_id_used=thd->query_start_used=thd->insert_id_used=0;
thd->sent_row_count=thd->examined_row_count=0;
+ thd->safe_to_cache_query=1;
DBUG_VOID_RETURN;
}
void
mysql_init_select(LEX *lex)
{
- lex->where=lex->having=0;
- lex->select_limit=current_thd->default_select_limit;
- lex->offset_limit=0L;
- lex->options=0;
+ SELECT_LEX *select_lex = lex->select;
+ select_lex->where=select_lex->having=0;
+ select_lex->select_limit=lex->thd->default_select_limit;
+ select_lex->offset_limit=0;
+ select_lex->options=0;
+ select_lex->linkage=UNSPECIFIED_TYPE;
lex->exchange = 0;
lex->proc_list.first=0;
- lex->order_list.elements=lex->group_list.elements=0;
- lex->order_list.first=0;
- lex->order_list.next= (byte**) &lex->order_list.first;
- lex->group_list.first=0;
- lex->group_list.next= (byte**) &lex->group_list.first;
+ select_lex->order_list.elements=select_lex->group_list.elements=0;
+ select_lex->order_list.first=0;
+ select_lex->order_list.next= (byte**) &select_lex->order_list.first;
+ select_lex->group_list.first=0;
+ select_lex->group_list.next= (byte**) &select_lex->group_list.first;
+ select_lex->next = (SELECT_LEX *)NULL;
+}
+
+bool
+mysql_new_select(LEX *lex)
+{
+ SELECT_LEX *select_lex = (SELECT_LEX *) lex->thd->calloc(sizeof(SELECT_LEX));
+ if (!select_lex)
+ return 1;
+ lex->select->next=select_lex;
+ lex->select=select_lex;
+ select_lex->table_list.next= (byte**) &select_lex->table_list.first;
+ select_lex->item_list.empty();
+ select_lex->when_list.empty();
+ select_lex->expr_list.empty();
+ select_lex->interval_list.empty();
+ select_lex->use_index.empty();
+ select_lex->ftfunc_list.empty();
+ return 0;
}
+void mysql_init_multi_delete(LEX *lex)
+{
+ lex->sql_command = SQLCOM_DELETE_MULTI;
+ mysql_init_select(lex);
+ lex->select->select_limit=HA_POS_ERROR;
+ lex->auxilliary_table_list=lex->select_lex.table_list;
+ lex->select->table_list.elements=0;
+ lex->select->table_list.first=0;
+ lex->select->table_list.next= (byte**) &(lex->select->table_list.first);
+}
void
mysql_parse(THD *thd,char *inBuf,uint length)
@@ -2345,12 +2710,20 @@ mysql_parse(THD *thd,char *inBuf,uint length)
mysql_init_query(thd);
thd->query_length = length;
- LEX *lex=lex_start(thd, (uchar*) inBuf, length);
- if (!yyparse() && ! thd->fatal_error)
- mysql_execute_command();
- thd->proc_info="freeing items";
- free_items(thd); /* Free strings used by items */
- lex_end(lex);
+ if (query_cache.send_result_to_client(thd, inBuf, length) <= 0)
+ {
+ LEX *lex=lex_start(thd, (uchar*) inBuf, length);
+ if (!yyparse() && ! thd->fatal_error)
+ {
+ mysql_execute_command();
+ query_cache_end_of_result(&thd->net);
+ }
+ else
+ query_cache_abort(&thd->net);
+ thd->proc_info="freeing items";
+ free_items(thd); /* Free strings used by items */
+ lex_end(lex);
+ }
DBUG_VOID_RETURN;
}
@@ -2656,6 +3029,8 @@ add_proc_to_list(Item *item)
static void remove_escape(char *name)
{
+ if (!*name) // For empty DB names
+ return;
char *to;
#ifdef USE_MB
char *strend=name+(uint) strlen(name);
@@ -2675,7 +3050,7 @@ static void remove_escape(char *name)
}
#endif
if (*name == '\\' && name[1])
- name++; // Skipp '\\'
+ name++; // Skip '\\'
*to++= *name;
}
*to=0;
@@ -2714,7 +3089,6 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
register TABLE_LIST *ptr;
THD *thd=current_thd;
char *alias_str;
- const char *current_db;
DBUG_ENTER("add_table_to_list");
if (!table)
@@ -2729,15 +3103,19 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
}
if (!alias) /* Alias is case sensitive */
- if (!(alias_str=sql_strmake(alias_str,table->table.length)))
+ if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
DBUG_RETURN(0);
- if (lower_case_table_names)
- casedn_str(table->table.str);
+
if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
DBUG_RETURN(0); /* purecov: inspected */
- ptr->db= table->db.str;
- ptr->real_name=table->table.str;
+ ptr->db= table->db.str ? table->db.str : (thd->db ? thd->db : (char*) "");
ptr->name=alias_str;
+ if (lower_case_table_names)
+ {
+ casedn_str(ptr->db);
+ casedn_str(table->table.str);
+ }
+ ptr->real_name=table->table.str;
ptr->lock_type=flags;
ptr->updating=updating;
if (use_index)
@@ -2748,26 +3126,86 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
sizeof(*ignore_index));
/* check that used name is unique */
- current_db=thd->db ? thd->db : "";
-
if (flags != TL_IGNORE)
{
- for (TABLE_LIST *tables=(TABLE_LIST*) thd->lex.table_list.first ; tables ;
+ for (TABLE_LIST *tables=(TABLE_LIST*) thd->lex.select->table_list.first ;
+ tables ;
tables=tables->next)
{
- if (!strcmp(alias_str,tables->name) &&
- !strcmp(ptr->db ? ptr->db : current_db,
- tables->db ? tables->db : current_db))
+ if (!strcmp(alias_str,tables->name) && !strcmp(ptr->db, tables->db))
{
net_printf(&thd->net,ER_NONUNIQ_TABLE,alias_str); /* purecov: tested */
DBUG_RETURN(0); /* purecov: tested */
}
}
}
- link_in_list(&thd->lex.table_list,(byte*) ptr,(byte**) &ptr->next);
+ link_in_list(&thd->lex.select->table_list,(byte*) ptr,(byte**) &ptr->next);
DBUG_RETURN(ptr);
}
+
+/*
+** This is used for UNION 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.
+*/
+
+static bool create_total_list(THD *thd, LEX *lex, TABLE_LIST **result)
+{
+ /* Handle the case when we are not using union */
+ if (!lex->select_lex.next)
+ {
+ *result= (TABLE_LIST*) lex->select_lex.table_list.first;
+ return 0;
+ }
+
+ SELECT_LEX *sl;
+ TABLE_LIST **new_table_list= result, *aux;
+
+ *new_table_list=0; // end result list
+ for (sl= &lex->select_lex; sl; sl=sl->next)
+ {
+ if (sl->order_list.first && sl->next && !sl->braces)
+ {
+ net_printf(&thd->net,ER_WRONG_USAGE,"UNION","ORDER BY");
+ return 1;
+ }
+ if ((aux= (TABLE_LIST*) sl->table_list.first))
+ {
+ TABLE_LIST *next;
+ for (; aux; aux=next)
+ {
+ TABLE_LIST *cursor;
+ next= aux->next;
+ for (cursor= *result; cursor; cursor=cursor->next)
+ if (!strcmp(cursor->db,aux->db) &&
+ !strcmp(cursor->real_name,aux->real_name) &&
+ !strcmp(cursor->name, aux->name))
+ break;
+ if (!cursor)
+ {
+ /* Add not used table to the total table list */
+ aux->lock_type= lex->lock_option;
+ if (!(cursor = (TABLE_LIST *) thd->memdup((char*) aux,
+ sizeof(*aux))))
+ {
+ send_error(&thd->net,0);
+ return 1;
+ }
+ *new_table_list= cursor;
+ new_table_list= &cursor->next;
+ *new_table_list=0; // end result list
+ }
+ else
+ aux->shared=1; // Mark that it's used twice
+ aux->table=(TABLE *) cursor;
+ }
+ }
+ }
+ return 0;
+}
+
+
void add_join_on(TABLE_LIST *b,Item *expr)
{
if (!b->on_expr)
@@ -2787,22 +3225,20 @@ void add_join_natural(TABLE_LIST *a,TABLE_LIST *b)
/* Check if name is used in table list */
-static bool check_dup(THD *thd,const char *db,const char *name,
- TABLE_LIST *tables)
+static bool check_dup(const char *db, const char *name, TABLE_LIST *tables)
{
- const char *thd_db=thd->db ? thd->db : any_db;
for (; tables ; tables=tables->next)
- if (!strcmp(name,tables->real_name) &&
- !strcmp(db ? db : thd_db, tables->db ? tables->db : thd_db))
+ if (!strcmp(name,tables->real_name) && !strcmp(db,tables->db))
return 1;
return 0;
}
-bool reload_acl_and_cache(THD *thd, uint options, TABLE_LIST *tables)
+bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
{
bool result=0;
select_errors=0; /* Write if more errors */
+ // TODO: figure out what's up with the commented out line below
// mysql_log.flush(); // Flush log
if (options & REFRESH_GRANT)
{
@@ -2818,12 +3254,21 @@ bool reload_acl_and_cache(THD *thd, uint options, TABLE_LIST *tables)
if (ha_flush_logs())
result=1;
}
+ if (options & REFRESH_QUERY_CACHE_FREE)
+ {
+ query_cache.pack(); // FLUSH QUERY CACHE
+ options &= ~REFRESH_QUERY_CACHE; //don't flush all cache, just free memory
+ }
+ if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
+ {
+ query_cache.flush(); // RESET QUERY CACHE
+ }
if (options & (REFRESH_TABLES | REFRESH_READ_LOCK))
{
- if ((options & REFRESH_READ_LOCK) && thd && ! thd->global_read_lock)
+ if ((options & REFRESH_READ_LOCK) && thd)
{
- thd->global_read_lock=1;
- thread_safe_increment(global_read_lock,&LOCK_open);
+ if (lock_global_read_lock(thd))
+ return 1;
}
result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables);
}
@@ -2834,10 +3279,22 @@ bool reload_acl_and_cache(THD *thd, uint options, TABLE_LIST *tables)
if (options & REFRESH_THREADS)
flush_thread_cache();
if (options & REFRESH_MASTER)
- reset_master();
- if (options & REFRESH_SLAVE)
- reset_slave();
-
+ if (reset_master(thd))
+ result=1;
+#ifdef OPENSSL
+ if (options & REFRESH_DES_KEY_FILE)
+ {
+ if (des_key_file)
+ result=load_des_key_file(des_key_file);
+ }
+#endif
+ if (options & REFRESH_SLAVE)
+ {
+ LOCK_ACTIVE_MI;
+ if (reset_slave(active_mi))
+ result=1;
+ UNLOCK_ACTIVE_MI;
+ }
return result;
}
@@ -2855,7 +3312,7 @@ void kill_one_thread(THD *thd, ulong id)
if ((thd->master_access & PROCESS_ACL) ||
!strcmp(thd->user,tmp->user))
{
- tmp->prepare_to_die();
+ tmp->awake(1 /*prepare to die*/);
error=0;
}
else
@@ -2884,3 +3341,29 @@ static void refresh_status(void)
pthread_mutex_unlock(&LOCK_status);
pthread_mutex_unlock(&THR_LOCK_keycache);
}
+
+
+ /* If pointer is not a null pointer, append filename to it */
+
+static bool append_file_to_dir(THD *thd, char **filename_ptr, char *table_name)
+{
+ char buff[FN_REFLEN],*ptr, *end;
+ if (!*filename_ptr)
+ return 0; // nothing to do
+
+ /* Check that the filename is not too long and it's a hard path */
+ if (strlen(*filename_ptr)+strlen(table_name) >= FN_REFLEN-1 ||
+ !test_if_hard_path(*filename_ptr))
+ {
+ my_error(ER_WRONG_TABLE_NAME, MYF(0), *filename_ptr);
+ return 1;
+ }
+ /* Fix is using unix filename format on dos */
+ strmov(buff,*filename_ptr);
+ end=convert_dirname(buff, *filename_ptr, NullS);
+ if (!(ptr=thd->alloc((uint) (end-buff)+(uint) strlen(table_name)+1)))
+ return 1; // End of memory
+ *filename_ptr=ptr;
+ strxmov(ptr,buff,table_name,NullS);
+ return 0;
+}
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index a6614f3f3f6..305491c7346 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -31,19 +31,21 @@ static TABLE_LIST *rename_tables(THD *thd, TABLE_LIST *table_list,
bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list)
{
- bool error=1,cerror,got_all_locks=1;
+ bool error=1,got_all_locks=1;
TABLE_LIST *lock_table,*ren_table=0;
DBUG_ENTER("mysql_rename_tables");
-
- /* Avoid problems with a rename on a table that we have locked or
- if the user is trying to to do this in a transcation context */
+
+ /*
+ Avoid problems with a rename on a table that we have locked or
+ if the user is trying to to do this in a transcation context
+ */
if (thd->locked_tables || thd->active_transaction())
{
my_error(ER_LOCK_OR_ACTIVE_TRANSACTION,MYF(0));
DBUG_RETURN(1);
}
-
+
VOID(pthread_mutex_lock(&LOCK_open));
for (lock_table=table_list ; lock_table ; lock_table=lock_table->next)
{
@@ -53,13 +55,13 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list)
if (got_lock)
got_all_locks=0;
}
-
+
if (!got_all_locks && wait_for_locked_table_names(thd,table_list))
goto end;
if (!(ren_table=rename_tables(thd,table_list,0)))
error=0;
-
+
end:
if (ren_table)
{
@@ -80,19 +82,14 @@ end:
for (table=table_list ;
table->next != ren_table ;
table=table->next->next) ;
- table=table->next->next; // Skipp error table
+ table=table->next->next; // Skip error table
/* Revert to old names */
rename_tables(thd, table, 1);
/* Note that lock_table == 0 here, so the unlock loop will work */
}
/* Lets hope this doesn't fail as the result will be messy */
- if ((cerror=ha_commit_rename(thd)))
- {
- my_error(ER_GET_ERRNO,MYF(0),cerror);
- error= 1;
- }
- else if (!error)
+ if (!error)
{
mysql_update_log.write(thd,thd->query,thd->query_length);
if (mysql_bin_log.is_open())
@@ -134,7 +131,7 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
if (!access(name,F_OK))
{
my_error(ER_TABLE_EXISTS_ERROR,MYF(0),name);
- return ren_table; // This can't be skipped
+ DBUG_RETURN(ren_table); // This can't be skipped
}
sprintf(name,"%s/%s/%s%s",mysql_data_home,
ren_table->db,ren_table->real_name,
@@ -143,7 +140,7 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
{
my_error(ER_FILE_NOT_FOUND, MYF(0), name, my_errno);
if (!skip_error)
- return ren_table;
+ DBUG_RETURN(ren_table);
}
else if (mysql_rename_table(table_type,
ren_table->db, ren_table->real_name,
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 1940ff360c2..c6384817512 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB & Sasha
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -15,17 +15,17 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
// Sasha Pachev <sasha@mysql.com> is currently in charge of this file
-// Do not mess with it without his permission!
#include "mysql_priv.h"
#include "sql_repl.h"
#include "sql_acl.h"
#include "log_event.h"
+#include "mini_client.h"
#include <thr_alarm.h>
#include <my_dir.h>
+#include <assert.h>
extern const char* any_db;
-extern pthread_handler_decl(handle_slave,arg);
#ifndef DBUG_OFF
int max_binlog_dump_events = 0; // unlimited
@@ -33,43 +33,66 @@ bool opt_sporadic_binlog_dump_fail = 0;
static int binlog_dump_count = 0;
#endif
+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;
+}
+
static int fake_rotate_event(NET* net, String* packet, char* log_file_name,
const char**errmsg)
{
- char header[LOG_EVENT_HEADER_LEN];
+ char header[LOG_EVENT_HEADER_LEN], buf[ROTATE_HEADER_LEN];
memset(header, 0, 4); // when does not matter
header[EVENT_TYPE_OFFSET] = ROTATE_EVENT;
- char* p = strrchr(log_file_name, FN_LIBCHAR);
- // find the last slash
- if(p)
- p++;
- else
- p = log_file_name;
+ char* p = log_file_name+dirname_length(log_file_name);
uint ident_len = (uint) strlen(p);
- ulong event_len = ident_len + sizeof(header);
- int4store(header + EVENT_TYPE_OFFSET + 1, server_id);
+ ulong event_len = ident_len + ROTATE_EVENT_OVERHEAD;
+ 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));
+ /* We need to split the next statement because of problem with cxx */
+ int4store(buf,4); // tell slave to skip magic number
+ int4store(buf+4,0);
+ packet->append(buf, ROTATE_HEADER_LEN);
packet->append(p,ident_len);
- if(my_net_write(net, (char*)packet->ptr(), packet->length()))
- {
- *errmsg = "failed on my_net_write()";
- return -1;
- }
+ if (my_net_write(net, (char*)packet->ptr(), packet->length()))
+ {
+ *errmsg = "failed on my_net_write()";
+ return -1;
+ }
return 0;
}
-
static int send_file(THD *thd)
{
NET* net = &thd->net;
int fd = -1,bytes, error = 1;
char fname[FN_REFLEN+1];
- char *buf;
const char *errmsg = 0;
int old_timeout;
uint packet_len;
+ char buf[IO_SIZE]; // It's safe to alloc this
DBUG_ENTER("send_file");
// the client might be slow loading the data, give him wait_timeout to do
@@ -77,40 +100,32 @@ static int send_file(THD *thd)
old_timeout = thd->net.timeout;
thd->net.timeout = thd->inactive_timeout;
- // spare the stack
- if(!(buf = alloc_root(&thd->mem_root,IO_SIZE)))
- {
- errmsg = "Out of memory";
- goto err;
- }
-
// we need net_flush here because the client will not know it needs to send
// us the file name until it has processed the load event entry
if (net_flush(net) || (packet_len = my_net_read(net)) == packet_error)
{
- errmsg = "Failed reading file name";
+ errmsg = "while reading file name";
goto err;
}
- *((char*)net->read_pos + packet_len) = 0; // terminate with \0
- //for fn_format
- fn_format(fname, (char*)net->read_pos + 1, "", "", 4);
+ // terminate with \0 for fn_format
+ *((char*)net->read_pos + packet_len) = 0;
+ fn_format(fname, (char*) net->read_pos + 1, "", "", 4);
// this is needed to make replicate-ignore-db
if (!strcmp(fname,"/dev/null"))
goto end;
- if ((fd = my_open(fname, O_RDONLY, MYF(MY_WME))) < 0)
+ if ((fd = my_open(fname, O_RDONLY, MYF(0))) < 0)
{
- errmsg = "Failed on my_open()";
+ errmsg = "on open of file";
goto err;
}
- while ((bytes = (int) my_read(fd, (byte*) buf, IO_SIZE,
- MYF(MY_WME))) > 0)
+ while ((bytes = (int) my_read(fd, (byte*) buf, IO_SIZE, MYF(0))) > 0)
{
if (my_net_write(net, buf, bytes))
{
- errmsg = "Failed on my_net_write()";
+ errmsg = "while writing data to client";
goto err;
}
}
@@ -119,18 +134,18 @@ static int send_file(THD *thd)
if (my_net_write(net, "", 0) || net_flush(net) ||
(my_net_read(net) == packet_error))
{
- errmsg = "failed negotiating file transfer close";
+ errmsg = "while negotiating file transfer close";
goto err;
}
error = 0;
err:
thd->net.timeout = old_timeout;
- if(fd >= 0)
- (void) my_close(fd, MYF(MY_WME));
+ if (fd >= 0)
+ (void) my_close(fd, MYF(0));
if (errmsg)
{
- sql_print_error("failed in send_file() : %s", errmsg);
+ sql_print_error("Failed in send_file() %s", errmsg);
DBUG_PRINT("error", (errmsg));
}
DBUG_RETURN(error);
@@ -138,34 +153,27 @@ static int send_file(THD *thd)
File open_binlog(IO_CACHE *log, const char *log_file_name,
- const char **errmsg)
+ const char **errmsg)
{
File file;
- char magic[4];
+
if ((file = my_open(log_file_name, O_RDONLY | O_BINARY, MYF(MY_WME))) < 0 ||
init_io_cache(log, file, IO_SIZE*2, READ_CACHE, 0, 0,
- MYF(MY_WME)))
+ MYF(MY_WME | MY_DONT_CHECK_FILESIZE)))
{
- *errmsg = "Could not open log file"; // This will not be sent
+ *errmsg = "Could not open log file"; // This will not be sent
goto err;
}
-
- if (my_b_read(log, (byte*) magic, sizeof(magic)))
- {
- *errmsg = "I/O error reading binlog magic number";
- goto err;
- }
- if (memcmp(magic, BINLOG_MAGIC, 4))
- {
- *errmsg = "Binlog has bad magic number, fire your magician";
+ if (check_binlog_magic(log,errmsg))
goto err;
- }
return file;
err:
- if (file > 0)
+ if (file >= 0)
+ {
my_close(file,MYF(0));
- end_io_cache(log);
+ end_io_cache(log);
+ }
return -1;
}
@@ -173,26 +181,27 @@ err:
void adjust_linfo_offsets(my_off_t purge_offset)
{
THD *tmp;
-
+
pthread_mutex_lock(&LOCK_thread_count);
I_List_iterator<THD> it(threads);
-
- while((tmp=it++))
- {
- LOG_INFO* linfo;
- if((linfo = tmp->current_linfo))
- {
- pthread_mutex_lock(&linfo->lock);
- // no big deal if we just started reading the log
- // nothing to adjust
- if(linfo->index_file_offset < purge_offset)
- linfo->fatal = (linfo->index_file_offset != 0);
- else
- linfo->index_file_offset -= purge_offset;
- pthread_mutex_unlock(&linfo->lock);
- }
- }
+ while ((tmp=it++))
+ {
+ LOG_INFO* linfo;
+ if ((linfo = tmp->current_linfo))
+ {
+ pthread_mutex_lock(&linfo->lock);
+ /* index file offset can be less that purge offset
+ only if we just started reading the index file. In that case
+ we have nothing to adjust
+ */
+ if (linfo->index_file_offset < purge_offset)
+ linfo->fatal = (linfo->index_file_offset != 0);
+ else
+ linfo->index_file_offset -= purge_offset;
+ pthread_mutex_unlock(&linfo->lock);
+ }
+ }
pthread_mutex_unlock(&LOCK_thread_count);
}
@@ -202,21 +211,21 @@ bool log_in_use(const char* log_name)
int log_name_len = strlen(log_name) + 1;
THD *tmp;
bool result = 0;
-
+
pthread_mutex_lock(&LOCK_thread_count);
I_List_iterator<THD> it(threads);
-
- while((tmp=it++))
+
+ while ((tmp=it++))
+ {
+ LOG_INFO* linfo;
+ if ((linfo = tmp->current_linfo))
{
- LOG_INFO* linfo;
- if((linfo = tmp->current_linfo))
- {
- pthread_mutex_lock(&linfo->lock);
- result = !memcmp(log_name, linfo->log_file_name, log_name_len);
- pthread_mutex_unlock(&linfo->lock);
- if(result) break;
- }
- }
+ pthread_mutex_lock(&linfo->lock);
+ result = !memcmp(log_name, linfo->log_file_name, log_name_len);
+ pthread_mutex_unlock(&linfo->lock);
+ if (result) break;
+ }
+ }
pthread_mutex_unlock(&LOCK_thread_count);
return result;
@@ -226,35 +235,35 @@ bool log_in_use(const char* log_name)
int purge_master_logs(THD* thd, const char* to_log)
{
char search_file_name[FN_REFLEN];
+ const char* errmsg = 0;
+
mysql_bin_log.make_log_name(search_file_name, to_log);
int res = mysql_bin_log.purge_logs(thd, search_file_name);
- const char* 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 \
+
+ 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_PURGE_NO_ROTATE: errmsg = "Cannot purge unrotatable log";
- 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;
- }
-
- if(errmsg)
- {
- send_error(&thd->net, 0, errmsg);
- return 1;
- }
+ case LOG_INFO_SEEK: errmsg = "Failed on fseek()"; break;
+ case LOG_INFO_PURGE_NO_ROTATE: errmsg = "Cannot purge unrotatable log";
+ 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;
+ }
+
+ if (errmsg)
+ {
+ send_error(&thd->net, 0, errmsg);
+ return 1;
+ }
else
send_ok(&thd->net);
-
+
return 0;
}
@@ -272,7 +281,7 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags)
NET* net = &thd->net;
#ifndef DBUG_OFF
int left_events = max_binlog_dump_events;
-#endif
+#endif
DBUG_ENTER("mysql_binlog_send");
bzero((char*) &log,sizeof(log));
@@ -282,25 +291,25 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags)
errmsg = "Master failed COM_BINLOG_DUMP to test if slave can recover";
goto err;
}
-#endif
+#endif
- if(!mysql_bin_log.is_open())
+ if (!mysql_bin_log.is_open())
{
errmsg = "Binary log is not open";
goto err;
}
- if(!server_id_supplied)
- {
- errmsg = "Misconfigured master - server id was not set";
- goto err;
- }
-
+ if (!server_id_supplied)
+ {
+ errmsg = "Misconfigured master - server id was not set";
+ goto err;
+ }
+
if (log_ident[0])
mysql_bin_log.make_log_name(search_file_name, log_ident);
else
search_file_name[0] = 0;
-
+
linfo.index_file_offset = 0;
thd->current_linfo = &linfo;
@@ -315,20 +324,21 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags)
if (pos < 4)
{
- errmsg = "Client requested master to start repliction from impossible position.\n";
+ errmsg = "Client requested master to start repliction from \
+impossible position";
goto err;
}
-
+
my_b_seek(&log, pos); // Seek will done on next read
packet->length(0);
- packet->append("\0", 1);
// we need to start a packet with something other than 255
// to distiquish it from error
+ packet->append("\0", 1);
- // tell the client log name with a fake rotate_event
// if we are at the start of the log
- if(pos == 4)
+ if (pos == 4)
{
+ // tell the client log name with a fake rotate_event
if (fake_rotate_event(net, packet, log_file_name, &errmsg))
goto err;
packet->length(0);
@@ -338,17 +348,17 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags)
while (!net->error && net->vio != 0 && !thd->killed)
{
pthread_mutex_t *log_lock = mysql_bin_log.get_log_lock();
-
+
while (!(error = Log_event::read_log_event(&log, packet, log_lock)))
{
#ifndef DBUG_OFF
- if(max_binlog_dump_events && !left_events--)
+ if (max_binlog_dump_events && !left_events--)
{
net_flush(net);
errmsg = "Debugging binlog dump abort";
goto err;
}
-#endif
+#endif
if (my_net_write(net, (char*)packet->ptr(), packet->length()) )
{
errmsg = "Failed on my_net_write()";
@@ -358,7 +368,7 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags)
(*packet)[LOG_EVENT_OFFSET+1] ));
if ((*packet)[LOG_EVENT_OFFSET+1] == LOAD_EVENT)
{
- if(send_file(thd))
+ if (send_file(thd))
{
errmsg = "failed in send_file()";
goto err;
@@ -367,15 +377,15 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags)
packet->length(0);
packet->append("\0",1);
}
-
+ // TODO: now that we are logging the offset, check to make sure
+ // the recorded offset and the actual match
if (error != LOG_READ_EOF)
{
- switch(error)
- {
- case LOG_READ_BOGUS:
+ switch(error) {
+ case LOG_READ_BOGUS:
errmsg = "bogus data in log event";
break;
- case LOG_READ_TOO_LARGE:
+ case LOG_READ_TOO_LARGE:
errmsg = "log event entry exceeded max_allowed_packet -\
increase max_allowed_packet on master";
break;
@@ -395,12 +405,12 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags)
goto err;
}
- if(!(flags & BINLOG_DUMP_NON_BLOCK) &&
+ if (!(flags & BINLOG_DUMP_NON_BLOCK) &&
mysql_bin_log.is_active(log_file_name))
+ {
// block until there is more data in the log
// unless non-blocking mode requested
- {
- if(net_flush(net))
+ if (net_flush(net))
{
errmsg = "failed on net_flush()";
goto err;
@@ -412,64 +422,56 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags)
// to signal us
{
log.error=0;
-
- // tell the kill thread how to wake us up
- thd->mysys_var->current_mutex = log_lock;
- thd->mysys_var->current_cond = &COND_binlog_update;
- const char* proc_info = thd->proc_info;
- thd->proc_info = "Slave connection: waiting for binlog update";
-
bool read_packet = 0, fatal_error = 0;
#ifndef DBUG_OFF
- if(max_binlog_dump_events && !left_events--)
+ if (max_binlog_dump_events && !left_events--)
{
net_flush(net);
errmsg = "Debugging binlog dump abort";
goto err;
}
-#endif
+#endif
// no one will update the log while we are reading
// now, but we'll be quick and just read one record
pthread_mutex_lock(log_lock);
- switch (Log_event::read_log_event(&log, packet, (pthread_mutex_t*) 0))
+ switch (Log_event::read_log_event(&log, packet, (pthread_mutex_t*)0))
{
case 0:
+ pthread_mutex_unlock(log_lock);
read_packet = 1;
// we read successfully, so we'll need to send it to the
// slave
break;
case LOG_READ_EOF:
- DBUG_PRINT("wait",("waiting for data on binary log"));
+ DBUG_PRINT("wait",("waiting for data in binary log"));
+ // wait_for_update unlocks the log lock - needed to avoid race
if (!thd->killed)
- pthread_cond_wait(&COND_binlog_update, log_lock);
+ mysql_bin_log.wait_for_update(thd);
+ else
+ pthread_mutex_unlock(log_lock);
+ DBUG_PRINT("wait",("binary log received update"));
break;
default:
+ pthread_mutex_unlock(log_lock);
fatal_error = 1;
break;
}
- pthread_mutex_unlock(log_lock);
-
- pthread_mutex_lock(&thd->mysys_var->mutex);
- thd->mysys_var->current_mutex= 0;
- thd->mysys_var->current_cond= 0;
- thd->proc_info= proc_info;
- pthread_mutex_unlock(&thd->mysys_var->mutex);
-
- if(read_packet)
+
+ if (read_packet)
{
thd->proc_info = "sending update to slave";
- if(my_net_write(net, (char*)packet->ptr(), packet->length()) )
+ if (my_net_write(net, (char*)packet->ptr(), packet->length()) )
{
errmsg = "Failed on my_net_write()";
goto err;
}
- if((*packet)[LOG_EVENT_OFFSET+1] == LOAD_EVENT)
+ if ((*packet)[LOG_EVENT_OFFSET+1] == LOAD_EVENT)
{
- if(send_file(thd))
+ if (send_file(thd))
{
errmsg = "failed in send_file()";
goto err;
@@ -481,7 +483,7 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags)
// we hit EOF pretty quick
}
- if(fatal_error)
+ if (fatal_error)
{
errmsg = "error reading log entry";
goto err;
@@ -494,8 +496,7 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags)
bool loop_breaker = 0;
// need this to break out of the for loop from switch
thd->proc_info = "switching to next log";
- switch(mysql_bin_log.find_next_log(&linfo))
- {
+ switch (mysql_bin_log.find_next_log(&linfo)) {
case LOG_INFO_EOF:
loop_breaker = (flags & BINLOG_DUMP_NON_BLOCK);
break;
@@ -506,12 +507,12 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags)
goto err;
}
- if(loop_breaker)
+ if (loop_breaker)
break;
end_io_cache(&log);
(void) my_close(file, MYF(MY_WME));
-
+
// fake Rotate_log event just in case it did not make it to the log
// otherwise the slave make get confused about the offset
if ((file=open_binlog(&log, log_file_name, &errmsg)) < 0 ||
@@ -525,13 +526,14 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags)
end_io_cache(&log);
(void)my_close(file, MYF(MY_WME));
-
+
send_eof(&thd->net);
thd->proc_info = "waiting to finalize termination";
pthread_mutex_lock(&LOCK_thread_count);
thd->current_linfo = 0;
pthread_mutex_unlock(&LOCK_thread_count);
DBUG_VOID_RETURN;
+
err:
thd->proc_info = "waiting to finalize termination";
end_io_cache(&log);
@@ -549,126 +551,114 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags)
DBUG_VOID_RETURN;
}
-int start_slave(THD* thd , bool net_report)
+int start_slave(THD* thd , MASTER_INFO* mi, bool net_report)
{
- if(!thd) thd = current_thd;
- NET* net = &thd->net;
int slave_errno = 0;
+ if (!thd) thd = current_thd;
+ NET* net = &thd->net;
+ int thread_mask;
+
if (check_access(thd, PROCESS_ACL, any_db))
return 1;
- pthread_mutex_lock(&LOCK_slave);
- if(!slave_running)
- {
- if(init_master_info(&glob_mi))
- slave_errno = ER_MASTER_INFO;
- else if(server_id_supplied && *glob_mi.host)
- {
- pthread_t hThread;
- if(pthread_create(&hThread, &connection_attrib, handle_slave, 0))
- {
- slave_errno = ER_SLAVE_THREAD;
- }
- while(!slave_running) // slave might already be running by now
- pthread_cond_wait(&COND_slave_start, &LOCK_slave);
- }
- else
- slave_errno = ER_BAD_SLAVE;
- }
+ lock_slave_threads(mi); // this allows us to cleanly read slave_running
+ init_thread_mask(&thread_mask,mi,1 /* inverse */);
+ if (thd->lex.slave_thd_opt)
+ thread_mask &= thd->lex.slave_thd_opt;
+ if (thread_mask)
+ {
+ if (server_id_supplied && (!mi->inited || (mi->inited && *mi->host)))
+ slave_errno = start_slave_threads(0 /*no mutex */,
+ 1 /* wait for start */,
+ mi,
+ master_info_file,relay_log_info_file,
+ thread_mask);
+ else
+ slave_errno = ER_BAD_SLAVE;
+ }
else
slave_errno = ER_SLAVE_MUST_STOP;
-
- pthread_mutex_unlock(&LOCK_slave);
- if(slave_errno)
- {
- if(net_report) send_error(net, slave_errno);
- return 1;
- }
- else if(net_report)
+
+ unlock_slave_threads(mi);
+
+ if (slave_errno)
+ {
+ if (net_report)
+ send_error(net, slave_errno);
+ return 1;
+ }
+ else if (net_report)
send_ok(net);
return 0;
}
-int stop_slave(THD* thd, bool net_report )
+int stop_slave(THD* thd, MASTER_INFO* mi, bool net_report )
{
- if(!thd) thd = current_thd;
- NET* net = &thd->net;
int slave_errno = 0;
-
+ if (!thd) thd = current_thd;
+ NET* net = &thd->net;
+
if (check_access(thd, PROCESS_ACL, any_db))
return 1;
+ thd->proc_info = "Killing slave";
+ int thread_mask;
+ lock_slave_threads(mi);
+ init_thread_mask(&thread_mask,mi,0 /* not inverse*/);
+ if (thd->lex.slave_thd_opt)
+ thread_mask &= thd->lex.slave_thd_opt;
+ slave_errno = (thread_mask) ?
+ terminate_slave_threads(mi,thread_mask,
+ 1 /*skip lock */) : ER_SLAVE_NOT_RUNNING;
+ unlock_slave_threads(mi);
+ thd->proc_info = 0;
- pthread_mutex_lock(&LOCK_slave);
- if (slave_running)
+ if (slave_errno)
{
- abort_slave = 1;
- KICK_SLAVE;
- // do not abort the slave in the middle of a query, so we do not set
- // thd->killed for the slave thread
- thd->proc_info = "waiting for slave to die";
- while(slave_running)
- {
- /* there is a small chance that slave thread might miss the first
- alarm. To protect againts it, resend the signal until it reacts
- */
-
- struct timespec abstime;
-#ifdef HAVE_TIMESPEC_TS_SEC
- abstime.ts_sec=time(NULL)+2;
- abstime.ts_nsec=0;
-#elif defined(__WIN__)
- abstime.tv_sec=time((time_t*) 0)+2;
- abstime.tv_nsec=0;
-#else
- struct timeval tv;
- gettimeofday(&tv,0);
- abstime.tv_sec=tv.tv_sec+2;
- abstime.tv_nsec=tv.tv_usec*1000;
-#endif
- pthread_cond_timedwait(&COND_slave_stopped, &LOCK_slave, &abstime);
- if (slave_running)
- KICK_SLAVE;
- }
+ if (net_report)
+ send_error(net, slave_errno);
+ return 1;
}
- else
- slave_errno = ER_SLAVE_NOT_RUNNING;
-
- pthread_mutex_unlock(&LOCK_slave);
- thd->proc_info = 0;
-
- if(slave_errno)
- {
- if(net_report) send_error(net, slave_errno);
- return 1;
- }
- else if(net_report)
+ else if (net_report)
send_ok(net);
return 0;
}
-void reset_slave()
+int reset_slave(MASTER_INFO* mi)
{
MY_STAT stat_area;
char fname[FN_REFLEN];
- bool slave_was_running ;
-
- pthread_mutex_lock(&LOCK_slave);
- if((slave_was_running = slave_running))
- {
- pthread_mutex_unlock(&LOCK_slave);
- stop_slave(0,0);
- }
- else
- pthread_mutex_unlock(&LOCK_slave);
+ int restart_thread_mask = 0,error=0;
+ const char* errmsg=0;
- end_master_info(&glob_mi);
- fn_format(fname, master_info_file, mysql_data_home, "", 4+16+32);
- if(my_stat(fname, &stat_area, MYF(0)))
- if(my_delete(fname, MYF(MY_WME)))
- return;
- if(slave_was_running)
- start_slave(0,0);
+ lock_slave_threads(mi);
+ init_thread_mask(&restart_thread_mask,mi,0 /* not inverse */);
+ if ((error=terminate_slave_threads(mi,restart_thread_mask,1 /*skip lock*/))
+ || (error=purge_relay_logs(&mi->rli,1 /*just reset*/,&errmsg)))
+ goto err;
+
+ end_master_info(mi);
+ fn_format(fname, master_info_file, mysql_data_home, "", 4+32);
+ if (my_stat(fname, &stat_area, MYF(0)) && my_delete(fname, MYF(MY_WME)))
+ {
+ error=1;
+ goto err;
+ }
+ fn_format(fname, relay_log_info_file, mysql_data_home, "", 4+32);
+ if (my_stat(fname, &stat_area, MYF(0)) && my_delete(fname, MYF(MY_WME)))
+ {
+ error=1;
+ goto err;
+ }
+ if (restart_thread_mask)
+ error=start_slave_threads(0 /* mutex not needed*/,
+ 1 /* wait for start*/,
+ mi,master_info_file,relay_log_info_file,
+ restart_thread_mask);
+ // TODO: fix error messages so they get to the client
+err:
+ unlock_slave_threads(mi);
+ return error;
}
void kill_zombie_dump_threads(uint32 slave_server_id)
@@ -677,121 +667,234 @@ void kill_zombie_dump_threads(uint32 slave_server_id)
I_List_iterator<THD> it(threads);
THD *tmp;
- while((tmp=it++))
+ while ((tmp=it++))
+ {
+ if (tmp->command == COM_BINLOG_DUMP &&
+ tmp->server_id == slave_server_id)
{
- if(tmp->command == COM_BINLOG_DUMP &&
- tmp->server_id == slave_server_id)
- {
- // here we do not call kill_one_thread()
- // it will be slow because it will iterate through the list
- // again. Plus it double-locks LOCK_thread_count, which
- // make safe_mutex complain and abort
- // so we just to our own thread murder
-
- thr_alarm_kill(tmp->real_id);
- tmp->killed = 1;
- tmp->mysys_var->abort = 1;
- pthread_mutex_lock(&tmp->mysys_var->mutex);
- if(tmp->mysys_var->current_cond)
- {
- pthread_mutex_lock(tmp->mysys_var->current_mutex);
- pthread_cond_broadcast(tmp->mysys_var->current_cond);
- pthread_mutex_unlock(tmp->mysys_var->current_mutex);
- }
- pthread_mutex_unlock(&tmp->mysys_var->mutex);
- }
- }
-
+ /*
+ Here we do not call kill_one_thread() as
+ it will be slow because it will iterate through the list
+ again. Plus it double-locks LOCK_tread_count, which
+ make safe_mutex complain and abort.
+ We just to do kill the thread ourselves.
+ */
+ tmp->awake(1/*prepare to die*/);
+ }
+ }
pthread_mutex_unlock(&LOCK_thread_count);
}
-int change_master(THD* thd)
+
+int change_master(THD* thd, MASTER_INFO* mi)
{
- bool slave_was_running;
+ int error=0,restart_thread_mask;
+ const char* errmsg=0;
+
// kill slave thread
- pthread_mutex_lock(&LOCK_slave);
- if((slave_was_running = slave_running))
- {
- abort_slave = 1;
- KICK_SLAVE;
- thd->proc_info = "waiting for slave to die";
- while(slave_running)
- pthread_cond_wait(&COND_slave_stopped, &LOCK_slave); // wait until done
- }
- pthread_mutex_unlock(&LOCK_slave);
+ lock_slave_threads(mi);
+ init_thread_mask(&restart_thread_mask,mi,0 /*not inverse*/);
+ if (restart_thread_mask &&
+ (error=terminate_slave_threads(mi,
+ restart_thread_mask,
+ 1 /*skip lock*/)))
+ {
+ send_error(&thd->net,error);
+ unlock_slave_threads(mi);
+ return 1;
+ }
thd->proc_info = "changing master";
LEX_MASTER_INFO* lex_mi = &thd->lex.mi;
+ // TODO: see if needs re-write
+ if (init_master_info(mi,master_info_file,relay_log_info_file))
+ {
+ send_error(&thd->net, 0, "Could not initialize master info");
+ unlock_slave_threads(mi);
+ return 1;
+ }
- if(init_master_info(&glob_mi))
- {
- send_error(&thd->net, 0, "Could not initialize master info");
- return 1;
- }
-
- pthread_mutex_lock(&glob_mi.lock);
- if((lex_mi->host || lex_mi->port) && !lex_mi->log_file_name && !lex_mi->pos)
- {
- // if we change host or port, we must reset the postion
- glob_mi.log_file_name[0] = 0;
- glob_mi.pos = 4; // skip magic number
- glob_mi.pending = 0;
- }
+ pthread_mutex_lock(&mi->data_lock);
+ if ((lex_mi->host || lex_mi->port) && !lex_mi->log_file_name && !lex_mi->pos)
+ {
+ // if we change host or port, we must reset the postion
+ mi->master_log_name[0] = 0;
+ mi->master_log_pos = 4; // skip magic number
+ mi->rli.pending = 0;
+ }
- if(lex_mi->log_file_name)
- strmake(glob_mi.log_file_name, lex_mi->log_file_name,
- sizeof(glob_mi.log_file_name));
- if(lex_mi->pos)
+ if (lex_mi->log_file_name)
+ strmake(mi->master_log_name, lex_mi->log_file_name,
+ sizeof(mi->master_log_name));
+ if (lex_mi->pos)
{
- glob_mi.pos = lex_mi->pos;
- glob_mi.pending = 0;
+ mi->master_log_pos = lex_mi->pos;
+ mi->rli.pending = 0;
}
-
- if(lex_mi->host)
- {
- strmake(glob_mi.host, lex_mi->host, sizeof(glob_mi.host));
- }
- if(lex_mi->user)
- strmake(glob_mi.user, lex_mi->user, sizeof(glob_mi.user));
- if(lex_mi->password)
- strmake(glob_mi.password, lex_mi->password, sizeof(glob_mi.password));
- if(lex_mi->port)
- glob_mi.port = lex_mi->port;
- if(lex_mi->connect_retry)
- glob_mi.connect_retry = lex_mi->connect_retry;
-
- flush_master_info(&glob_mi);
- pthread_mutex_unlock(&glob_mi.lock);
+
+ if (lex_mi->host)
+ strmake(mi->host, lex_mi->host, sizeof(mi->host));
+ if (lex_mi->user)
+ strmake(mi->user, lex_mi->user, sizeof(mi->user));
+ if (lex_mi->password)
+ strmake(mi->password, lex_mi->password, sizeof(mi->password));
+ if (lex_mi->port)
+ mi->port = lex_mi->port;
+ if (lex_mi->connect_retry)
+ mi->connect_retry = lex_mi->connect_retry;
+
+ flush_master_info(mi);
+ pthread_mutex_unlock(&mi->data_lock);
+ thd->proc_info="purging old relay logs";
+ if (purge_relay_logs(&mi->rli,0 /* not only reset, but also reinit*/,
+ &errmsg))
+ {
+ send_error(&thd->net, 0, "Failed purging old relay logs");
+ unlock_slave_threads(mi);
+ return 1;
+ }
+ pthread_mutex_lock(&mi->rli.data_lock);
+ mi->rli.master_log_pos = mi->master_log_pos;
+ strnmov(mi->rli.master_log_name,mi->master_log_name,
+ sizeof(mi->rli.master_log_name));
+ if (!mi->rli.master_log_name[0]) // uninitialized case
+ mi->rli.master_log_pos=0;
+ pthread_cond_broadcast(&mi->rli.data_cond);
+ pthread_mutex_unlock(&mi->rli.data_lock);
+
thd->proc_info = "starting slave";
- if(slave_was_running)
- start_slave(0,0);
+ if (restart_thread_mask)
+ error=start_slave_threads(0 /* mutex not needed*/,
+ 1 /* wait for start*/,
+ mi,master_info_file,relay_log_info_file,
+ restart_thread_mask);
+ unlock_slave_threads(mi);
thd->proc_info = 0;
-
- send_ok(&thd->net);
+ if (error)
+ send_error(&thd->net,error);
+ else
+ send_ok(&thd->net);
return 0;
}
-void reset_master()
+int reset_master(THD* thd)
{
- if(!mysql_bin_log.is_open())
+ if (!mysql_bin_log.is_open())
{
my_error(ER_FLUSH_MASTER_BINLOG_CLOSED, MYF(ME_BELL+ME_WAITTANG));
- return;
+ return 1;
}
+ return mysql_bin_log.reset_logs(thd);
+}
- LOG_INFO linfo;
- if (mysql_bin_log.find_first_log(&linfo, ""))
- return;
+int cmp_master_pos(const char* log_file_name1, ulonglong log_pos1,
+ const char* log_file_name2, ulonglong log_pos2)
+{
+ int res;
+ if ((res = strcmp(log_file_name1, log_file_name2)))
+ return res;
+ if (log_pos1 > log_pos2)
+ return 1;
+ else if (log_pos1 == log_pos2)
+ return 0;
+ return -1;
+}
- for(;;)
+int show_binlog_events(THD* thd)
+{
+ DBUG_ENTER("show_binlog_events");
+ List<Item> field_list;
+ const char* errmsg = 0;
+ IO_CACHE log;
+ File file = -1;
+
+ Log_event::init_show_field_list(&field_list);
+ if (send_fields(thd, field_list, 1))
+ DBUG_RETURN(-1);
+
+ if (mysql_bin_log.is_open())
+ {
+ LOG_INFO linfo;
+ char search_file_name[FN_REFLEN];
+ LEX_MASTER_INFO* lex_mi = &thd->lex.mi;
+ uint event_count, limit_start, limit_end;
+ const char* log_file_name = lex_mi->log_file_name;
+ Log_event* ev;
+ my_off_t pos = lex_mi->pos;
+
+ limit_start = thd->lex.select->offset_limit;
+ limit_end = thd->lex.select->select_limit + limit_start;
+
+ if (log_file_name)
+ mysql_bin_log.make_log_name(search_file_name, log_file_name);
+ else
+ search_file_name[0] = 0;
+
+ linfo.index_file_offset = 0;
+ thd->current_linfo = &linfo;
+
+ if (mysql_bin_log.find_first_log(&linfo, search_file_name))
+ {
+ errmsg = "Could not find target log";
+ goto err;
+ }
+
+ if ((file=open_binlog(&log, linfo.log_file_name, &errmsg)) < 0)
+ goto err;
+
+ if (pos < 4)
+ {
+ errmsg = "Invalid log position";
+ goto err;
+ }
+
+ pthread_mutex_lock(mysql_bin_log.get_log_lock());
+ my_b_seek(&log, pos);
+
+ for (event_count = 0;
+ (ev = Log_event::read_log_event(&log,(pthread_mutex_t*)0,0)); )
+ {
+ if (event_count >= limit_start &&
+ ev->net_send(thd, linfo.log_file_name, pos))
+ {
+ errmsg = "Net error";
+ delete ev;
+ pthread_mutex_unlock(mysql_bin_log.get_log_lock());
+ goto err;
+ }
+
+ pos = my_b_tell(&log);
+ delete ev;
+
+ if (++event_count >= limit_end)
+ break;
+ }
+
+ if (event_count < limit_end && log.error)
+ {
+ errmsg = "Wrong offset or I/O error";
+ pthread_mutex_unlock(mysql_bin_log.get_log_lock());
+ goto err;
+ }
+
+ pthread_mutex_unlock(mysql_bin_log.get_log_lock());
+ }
+
+err:
+ if (file >= 0)
{
- my_delete(linfo.log_file_name, MYF(MY_WME));
- if (mysql_bin_log.find_next_log(&linfo))
- break;
+ end_io_cache(&log);
+ (void) my_close(file, MYF(MY_WME));
}
- mysql_bin_log.close(1); // exiting close
- my_delete(mysql_bin_log.get_index_fname(), MYF(MY_WME));
- mysql_bin_log.open(opt_bin_logname,LOG_BIN);
+ if (errmsg)
+ {
+ net_printf(&thd->net, ER_ERROR_WHEN_EXECUTING_COMMAND,
+ "SHOW BINLOG EVENTS", errmsg);
+ DBUG_RETURN(1);
+ }
+
+ send_eof(&thd->net);
+ DBUG_RETURN(0);
}
int show_binlog_info(THD* thd)
@@ -803,36 +906,37 @@ int show_binlog_info(THD* thd)
field_list.push_back(new Item_empty_string("Binlog_do_db",20));
field_list.push_back(new Item_empty_string("Binlog_ignore_db",20));
- if(send_fields(thd, field_list, 1))
+ if (send_fields(thd, field_list, 1))
DBUG_RETURN(-1);
String* packet = &thd->packet;
packet->length(0);
- if(mysql_bin_log.is_open())
- {
- LOG_INFO li;
- mysql_bin_log.get_current_log(&li);
- int dir_len = dirname_length(li.log_file_name);
- net_store_data(packet, li.log_file_name + dir_len);
- net_store_data(packet, (longlong)li.pos);
- net_store_data(packet, &binlog_do_db);
- net_store_data(packet, &binlog_ignore_db);
- }
+ if (mysql_bin_log.is_open())
+ {
+ LOG_INFO li;
+ mysql_bin_log.get_current_log(&li);
+ int dir_len = dirname_length(li.log_file_name);
+ net_store_data(packet, li.log_file_name + dir_len);
+ net_store_data(packet, (longlong)li.pos);
+ net_store_data(packet, &binlog_do_db);
+ net_store_data(packet, &binlog_ignore_db);
+ }
else
- {
- net_store_null(packet);
- net_store_null(packet);
- net_store_null(packet);
- net_store_null(packet);
- }
+ {
+ net_store_null(packet);
+ net_store_null(packet);
+ net_store_null(packet);
+ net_store_null(packet);
+ }
- if(my_net_write(&thd->net, (char*)thd->packet.ptr(), packet->length()))
+ if (my_net_write(&thd->net, (char*)thd->packet.ptr(), packet->length()))
DBUG_RETURN(-1);
send_eof(&thd->net);
DBUG_RETURN(0);
}
+
int show_binlogs(THD* thd)
{
const char* errmsg = 0;
@@ -843,20 +947,20 @@ int show_binlogs(THD* thd)
String* packet = &thd->packet;
IO_CACHE io_cache;
uint length;
-
- if(!mysql_bin_log.is_open())
+
+ if (!mysql_bin_log.is_open())
{
errmsg = "binlog is not open";
goto err;
}
field_list.push_back(new Item_empty_string("Log_name", 128));
- if(send_fields(thd, field_list, 1))
+ if (send_fields(thd, field_list, 1))
{
sql_print_error("Failed in send_fields");
return 1;
}
-
+
mysql_bin_log.lock_index();
index_file = mysql_bin_log.get_index_file();
if (index_file < 0)
@@ -876,7 +980,7 @@ int show_binlogs(THD* thd)
int dir_len = dirname_length(fname);
packet->length(0);
net_store_data(packet, fname + dir_len, length-dir_len);
- if(my_net_write(net, (char*) packet->ptr(), packet->length()))
+ if (my_net_write(net, (char*) packet->ptr(), packet->length()))
{
sql_print_error("Failed in my_net_write");
end_io_cache(&io_cache);
@@ -884,10 +988,10 @@ int show_binlogs(THD* thd)
return 1;
}
}
-
+
mysql_bin_log.unlock_index();
end_io_cache(&io_cache);
- send_eof(net);
+ send_eof(net);
return 0;
err2:
@@ -898,5 +1002,34 @@ err:
return 1;
}
-
-
+int log_loaded_block(IO_CACHE* file)
+{
+ LOAD_FILE_INFO* lf_info;
+ uint block_len ;
+
+ /* file->request_pos contains position where we started last read */
+ char* buffer = (char*) file->request_pos;
+ if (!(block_len = (char*) file->read_end - (char*) buffer))
+ return 0;
+ lf_info = (LOAD_FILE_INFO*) file->arg;
+ if (lf_info->last_pos_in_file != HA_POS_ERROR &&
+ lf_info->last_pos_in_file >= file->pos_in_file)
+ return 0;
+ lf_info->last_pos_in_file = file->pos_in_file;
+ if (lf_info->wrote_create_file)
+ {
+ Append_block_log_event a(lf_info->thd, buffer, block_len);
+ 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, buffer,
+ block_len);
+ mysql_bin_log.write(&c);
+ lf_info->wrote_create_file = 1;
+ DBUG_SYNC_POINT("debug_lock.created_file_event",10);
+ }
+ return 0;
+}
diff --git a/sql/sql_repl.h b/sql/sql_repl.h
index aa07d859aec..360fd50a1e3 100644
--- a/sql/sql_repl.h
+++ b/sql/sql_repl.h
@@ -3,6 +3,18 @@
#include "slave.h"
+typedef struct st_slave_info
+{
+ uint32 server_id;
+ uint32 rpl_recovery_rank, master_id;
+ char host[HOSTNAME_LENGTH+1];
+ char user[USERNAME_LENGTH+1];
+ char password[HASH_PASSWORD_LENGTH+1];
+ uint16 port;
+ THD* thd;
+} SLAVE_INFO;
+
+extern bool opt_show_slave_auth_info, opt_old_rpl_compat;
extern char* master_host;
extern my_string opt_bin_logname, master_info_file;
extern uint32 server_id;
@@ -14,26 +26,40 @@ extern int max_binlog_dump_events;
extern bool opt_sporadic_binlog_dump_fail;
#endif
-#ifdef SIGNAL_WITH_VIO_CLOSE
-#define KICK_SLAVE { slave_thd->close_active_vio(); \
- thr_alarm_kill(slave_real_id); }
-#else
-#define KICK_SLAVE thr_alarm_kill(slave_real_id);
-#endif
+#define KICK_SLAVE(thd) thd->awake(0 /* do not prepare to die*/);
File open_binlog(IO_CACHE *log, const char *log_file_name,
const char **errmsg);
-int start_slave(THD* thd = 0, bool net_report = 1);
-int stop_slave(THD* thd = 0, bool net_report = 1);
-int change_master(THD* thd);
-void reset_slave();
-void reset_master();
+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);
+int cmp_master_pos(const char* log_file_name1, ulonglong log_pos1,
+ const char* log_file_name2, ulonglong log_pos2);
+int reset_slave(MASTER_INFO* mi);
+int reset_master(THD* thd);
int purge_master_logs(THD* thd, const char* to_log);
bool log_in_use(const char* log_name);
void adjust_linfo_offsets(my_off_t purge_offset);
int 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);
+
+typedef struct st_load_file_info
+{
+ THD* thd;
+ sql_exchange* ex;
+ List <Item> *fields;
+ enum enum_duplicates handle_dup;
+ char* db;
+ char* table_name;
+ bool wrote_create_file;
+ my_off_t last_pos_in_file;
+} LOAD_FILE_INFO;
+
+int log_loaded_block(IO_CACHE* file);
#endif
+
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index b7134062437..82fe4d0c723 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -41,13 +41,16 @@ static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,
uint tables,COND *conds,table_map table_map);
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 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);
static double prev_record_reads(JOIN *join,table_map found_ref);
static bool get_best_combination(JOIN *join);
-static store_key *get_store_key(KEYUSE *keyuse, table_map used_tables,
+static store_key *get_store_key(THD *thd,
+ KEYUSE *keyuse, table_map used_tables,
KEY_PART_INFO *key_part, char *key_buff,
uint maybe_null);
static bool make_simple_join(JOIN *join,TABLE *tmp_table);
@@ -68,7 +71,7 @@ static COND *remove_eq_conds(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,
- uint options);
+ ulong options);
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);
@@ -83,20 +86,23 @@ static int end_unique_update(JOIN *join,JOIN_TAB *join_tab,
static int 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_tables(JOIN *join);
+static int join_read_const_table(JOIN_TAB *tab, POSITION *pos);
static int join_read_system(JOIN_TAB *tab);
static int join_read_const(JOIN_TAB *tab);
static int join_read_key(JOIN_TAB *tab);
static int join_read_always_key(JOIN_TAB *tab);
+static int join_read_last_key(JOIN_TAB *tab);
static int join_no_more_records(READ_RECORD *info);
static int join_read_next(READ_RECORD *info);
static int join_init_quick_read_record(JOIN_TAB *tab);
static int test_if_quick_select(JOIN_TAB *tab);
static int join_init_read_record(JOIN_TAB *tab);
-static int join_init_read_first_with_key(JOIN_TAB *tab);
-static int join_init_read_next_with_key(READ_RECORD *info);
-static int join_init_read_last_with_key(JOIN_TAB *tab);
-static int join_init_read_prev_with_key(READ_RECORD *info);
+static int join_read_first(JOIN_TAB *tab);
+static int join_read_next(READ_RECORD *info);
+static int join_read_next_same(READ_RECORD *info);
+static int join_read_last(JOIN_TAB *tab);
+static int join_read_prev_same(READ_RECORD *info);
+static int join_read_prev(READ_RECORD *info);
static int join_ft_read_first(JOIN_TAB *tab);
static int join_ft_read_next(READ_RECORD *info);
static COND *make_cond_for_table(COND *cond,table_map table,
@@ -104,9 +110,8 @@ static COND *make_cond_for_table(COND *cond,table_map table,
static Item* part_of_refkey(TABLE *form,Field *field);
static uint find_shortest_key(TABLE *table, key_map usable_keys);
static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,
- ha_rows select_limit);
+ ha_rows select_limit, bool no_changes);
static int create_sort_index(JOIN_TAB *tab,ORDER *order,ha_rows select_limit);
-static bool fix_having(JOIN *join, Item **having);
static int remove_duplicates(JOIN *join,TABLE *entry,List<Item> &fields,
Item *having);
static int remove_dup_with_compare(THD *thd, TABLE *entry, Field **field,
@@ -139,23 +144,50 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab);
static void init_sum_functions(Item_sum **func);
static bool update_sum_func(Item_sum **func);
static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
- bool distinct);
+ bool distinct, const char *message=NullS);
static void describe_info(THD *thd, const char *info);
+/*
+ This handles SELECT with and without UNION
+*/
+
+int handle_select(THD *thd, LEX *lex, select_result *result)
+{
+ int res;
+ register SELECT_LEX *select_lex = &lex->select_lex;
+ if (select_lex->next)
+ res=mysql_union(thd,lex,result);
+ else
+ res=mysql_select(thd,(TABLE_LIST*) select_lex->table_list.first,
+ select_lex->item_list,
+ select_lex->where,
+ (ORDER*) select_lex->order_list.first,
+ (ORDER*) select_lex->group_list.first,
+ select_lex->having,
+ (ORDER*) lex->proc_list.first,
+ select_lex->options | thd->options,
+ result);
+ if (res && result)
+ result->abort();
+ delete result;
+ return res;
+}
+
+
/*****************************************************************************
** check fields, find best join, do the select and output fields.
-** mysql_select assumes that all tables are allready opened
+** mysql_select assumes that all tables are already opened
*****************************************************************************/
int
mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
ORDER *order, ORDER *group,Item *having,ORDER *proc_param,
- uint select_options,select_result *result)
+ ulong select_options,select_result *result)
{
TABLE *tmp_table;
- int error,tmp;
+ int error, tmp_error;
bool need_tmp,hidden_group_fields;
- bool simple_order,simple_group,no_order;
+ bool simple_order,simple_group,no_order, skip_sort_order, buffer_result;
Item::cond_result cond_value;
SQL_SELECT *select;
DYNAMIC_ARRAY keyuse;
@@ -163,20 +195,23 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
Procedure *procedure;
List<Item> all_fields(fields);
bool select_distinct;
+ SELECT_LEX *select_lex = &(thd->lex.select_lex);
+ SELECT_LEX *cur_sel = thd->lex.select;
DBUG_ENTER("mysql_select");
/* Check that all tables, fields, conds and order are ok */
select_distinct=test(select_options & SELECT_DISTINCT);
+ buffer_result=test(select_options & OPTION_BUFFER_RESULT) && !test(select_options & OPTION_FOUND_ROWS);
tmp_table=0;
select=0;
- no_order=0;
+ no_order=skip_sort_order=0;
bzero((char*) &keyuse,sizeof(keyuse));
thd->proc_info="init";
thd->used_tables=0; // Updated by setup_fields
if (setup_tables(tables) ||
- setup_fields(thd,tables,fields,1,&all_fields) ||
+ setup_fields(thd,tables,fields,1,&all_fields,1) ||
setup_conds(thd,tables,&conds) ||
setup_order(thd,tables,fields,all_fields,order) ||
setup_group(thd,tables,fields,all_fields,group,&hidden_group_fields))
@@ -205,7 +240,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
if (!group)
{
uint flag=0;
- List_iterator<Item> it(fields);
+ List_iterator_fast<Item> it(fields);
Item *item;
while ((item= it++))
{
@@ -274,12 +309,15 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
count_field_types(&join.tmp_table_param,all_fields,0);
join.const_tables=0;
join.having=0;
+ join.do_send_rows = 1;
join.group= group != 0;
+ join.row_limit= ((select_distinct || order || group) ? HA_POS_ERROR :
+ thd->select_limit);
#ifdef RESTRICTED_GROUP
if (join.sum_func_count && !group && (join.func_count || join.field_count))
{
- my_message(ER_WRONG_SUM_SELECT,ER(ER_WRONG_SUM_SELECT));
+ my_message(ER_WRONG_SUM_SELECT,ER(ER_WRONG_SUM_SELECT),MYF(0));
delete procedure;
DBUG_RETURN(-1);
}
@@ -315,10 +353,13 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
}
if (cond_value == Item::COND_FALSE || !thd->select_limit)
{ /* Impossible cond */
- error=return_zero_rows(result, tables, fields,
- join.tmp_table_param.sum_func_count != 0 && !group,
- select_options,"Impossible WHERE",having,
- procedure);
+ if (select_options & SELECT_DESCRIBE && select_lex->next)
+ select_describe(&join,false,false,false,"Impossible WHERE");
+ else
+ error=return_zero_rows(result, tables, fields,
+ join.tmp_table_param.sum_func_count != 0 && !group,
+ select_options,"Impossible WHERE",having,
+ procedure);
delete procedure;
DBUG_RETURN(error);
}
@@ -331,17 +372,23 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
{
if (res < 0)
{
- error=return_zero_rows(result, tables, fields, !group,
- select_options,"No matching min/max row",
- having,procedure);
+ if (select_options & SELECT_DESCRIBE && select_lex->next)
+ select_describe(&join,false,false,false,"No matching min/max row");
+ else
+ error=return_zero_rows(result, tables, fields, !group,
+ select_options,"No matching min/max row",
+ having,procedure);
delete procedure;
DBUG_RETURN(error);
}
if (select_options & SELECT_DESCRIBE)
{
- describe_info(thd,"Select tables optimized away");
+ if (select_lex->next)
+ select_describe(&join,false,false,false,"Select tables optimized away");
+ else
+ describe_info(thd,"Select tables optimized away");
delete procedure;
- DBUG_RETURN(0);
+ DBUG_RETURN(error);
}
tables=0; // All tables resolved
}
@@ -350,13 +397,18 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
{ // Only test of functions
error=0;
if (select_options & SELECT_DESCRIBE)
- describe_info(thd,"No tables used");
+ {
+ if (select_lex->next)
+ select_describe(&join,false,false,false,"No tables used");
+ else
+ describe_info(thd,"No tables used");
+ }
else
{
result->send_fields(fields,1);
if (!having || having->val_int())
{
- if (result->send_data(fields))
+ if (join.do_send_rows && result->send_data(fields))
{
result->send_error(0,NullS); /* purecov: inspected */
error=1;
@@ -368,7 +420,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
error=(int) result->send_eof();
}
delete procedure;
- DBUG_RETURN(0);
+ DBUG_RETURN(error);
}
error = -1;
@@ -376,13 +428,12 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
/* Calculate how to do the join */
thd->proc_info="statistics";
- if (make_join_statistics(&join,tables,conds,&keyuse) ||
- thd->fatal_error)
+ if (make_join_statistics(&join,tables,conds,&keyuse) || thd->fatal_error)
goto err;
thd->proc_info="preparing";
- if ((tmp=join_read_const_tables(&join)) > 0)
- goto err;
- if (tmp && !(select_options & SELECT_DESCRIBE))
+ result->initialize_tables(&join);
+ if (join.const_table_map != join.found_const_table_map &&
+ !(select_options & SELECT_DESCRIBE))
{
error=return_zero_rows(result,tables,fields,
join.tmp_table_param.sum_func_count != 0 &&
@@ -397,7 +448,8 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
error= 1; /* purecov: inspected */
goto err; /* purecov: inspected */
}
- if (join.const_tables && !thd->locked_tables)
+ if (join.const_tables && !thd->locked_tables &&
+ !(select_options & SELECT_NO_UNLOCK))
{
TABLE **table, **end;
for (table=join.table, end=table + join.const_tables ;
@@ -428,11 +480,14 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
}
if (make_join_select(&join,select,conds))
{
- error=return_zero_rows(result,tables,fields,
- join.tmp_table_param.sum_func_count != 0 && !group,
- select_options,
- "Impossible WHERE noticed after reading const tables",
- having,procedure);
+ if (select_options & SELECT_DESCRIBE && select_lex->next)
+ select_describe(&join,false,false,false,"Impossible WHERE noticed after reading const tables");
+ else
+ error=return_zero_rows(result,tables,fields,
+ join.tmp_table_param.sum_func_count != 0 && !group,
+ select_options,
+ "Impossible WHERE noticed after reading const tables",
+ having,procedure);
goto err;
}
@@ -446,7 +501,12 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
select_distinct=0;
}
else if (select_distinct && join.tables - join.const_tables == 1 &&
- (order || thd->select_limit == HA_POS_ERROR))
+ (thd->select_limit == HA_POS_ERROR ||
+ (join.select_options & OPTION_FOUND_ROWS) ||
+ order &&
+ !(skip_sort_order=
+ test_if_skip_sort_order(&join.join_tab[join.const_tables],
+ order, thd->select_limit,1))))
{
if ((group=create_distinct_group(order,fields)))
{
@@ -477,7 +537,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
(!group && join.tmp_table_param.sum_func_count))
order=0;
- // Can't use sort on head table if using cache
+ // Can't use sort on head table if using row cache
if (join.full_join)
{
if (group)
@@ -488,11 +548,13 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
need_tmp= (join.const_tables != join.tables &&
((select_distinct || !simple_order || !simple_group) ||
- (group && order) ||
- test(select_options & OPTION_BUFFER_RESULT)));
+ (group && order) || buffer_result));
- make_join_readinfo(&join, (select_options & SELECT_DESCRIBE) |
- (thd->lex.ftfunc_list.elements ? 0 : SELECT_USE_CACHE)); // No cache for MATCH
+ // No cache for MATCH
+ make_join_readinfo(&join,
+ (select_options & (SELECT_DESCRIBE |
+ SELECT_NO_JOIN_CACHE)) |
+ (cur_sel->ftfunc_list.elements ? SELECT_NO_JOIN_CACHE : 0));
/* Need to tell Innobase that to play it safe, it should fetch all
columns of the tables: this is because MySQL
@@ -506,7 +568,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
for (uint i_h = join.const_tables; i_h < join.tables; i_h++)
{
TABLE* table_h = join.join_tab[i_h].table;
- if (table_h->db_type == DB_TYPE_INNOBASE)
+ if (table_h->db_type == DB_TYPE_INNODB)
table_h->file->extra(HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE);
}
}
@@ -531,7 +593,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
((group && join.const_tables != join.tables &&
(!simple_group ||
!test_if_skip_sort_order(&join.join_tab[join.const_tables], group,
- HA_POS_ERROR))) ||
+ thd->select_limit,0))) ||
select_distinct) &&
join.tmp_table_param.quick_group && !procedure)
{
@@ -546,19 +608,19 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
(join.const_tables == join.tables ||
(simple_order &&
test_if_skip_sort_order(&join.join_tab[join.const_tables], order,
- (group ? HA_POS_ERROR :
- thd->select_limit)))))
+ (join.const_tables != join.tables - 1 ||
+ (join.select_options & OPTION_FOUND_ROWS)) ?
+ HA_POS_ERROR : thd->select_limit,0))))
order=0;
select_describe(&join,need_tmp,
- (order != 0 &&
- (!need_tmp || order != group || simple_group)),
+ order != 0 && !skip_sort_order,
select_distinct);
error=0;
goto err;
}
/* Perform FULLTEXT search before all regular searches */
- init_ftfuncs(thd, test(order));
+ init_ftfuncs(thd,test(order));
/* Create a tmp table if distinct or if the sort is too complicated */
if (need_tmp)
@@ -573,7 +635,8 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
group : (ORDER*) 0),
group ? 0 : select_distinct,
group && simple_group,
- order == 0,
+ (order == 0 || skip_sort_order) &&
+ !(join.select_options & OPTION_FOUND_ROWS),
join.select_options)))
goto err; /* purecov: inspected */
@@ -623,12 +686,22 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
break;
join_tab->not_used_in_distinct=1;
} while (join_tab-- != join.join_tab);
+ /* Optimize "select distinct b from t1 order by key_part_1 limit #" */
+ if (order && skip_sort_order)
+ {
+ (void) test_if_skip_sort_order(&join.join_tab[join.const_tables],
+ order, thd->select_limit,0);
+ order=0;
+ }
}
/* Copy data to the temporary table */
thd->proc_info="Copying to tmp table";
- if (do_select(&join,(List<Item> *) 0,tmp_table,0))
+ if ((tmp_error=do_select(&join,(List<Item> *) 0,tmp_table,0)))
+ {
+ error=tmp_error;
goto err; /* purecov: inspected */
+ }
if (join.having)
join.having=having=0; // Allready done
@@ -701,9 +774,11 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
group=0;
}
thd->proc_info="Copying to group table";
+ tmp_error= -1;
if (make_sum_func_list(&join,all_fields) ||
- do_select(&join,(List<Item> *) 0,tmp_table2,0))
+ (tmp_error=do_select(&join,(List<Item> *) 0,tmp_table2,0)))
{
+ error=tmp_error;
free_tmp_table(thd,tmp_table2);
goto err; /* purecov: inspected */
}
@@ -750,7 +825,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
(procedure && (procedure->flags & PROC_GROUP)))
{
alloc_group_fields(&join,group);
- setup_copy_fields(&join.tmp_table_param,all_fields);
+ setup_copy_fields(thd, &join.tmp_table_param,all_fields);
if (make_sum_func_list(&join,all_fields) || thd->fatal_error)
goto err; /* purecov: inspected */
}
@@ -761,13 +836,34 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
/* If we have already done the group, add HAVING to sorted table */
if (having && ! group && ! join.sort_and_group)
{
- if (fix_having(&join,&having))
- goto err;
+ having->update_used_tables(); // Some tables may have been const
+ JOIN_TAB *table=&join.join_tab[join.const_tables];
+ table_map used_tables= join.const_table_map | table->table->map;
+
+ Item* sort_table_cond=make_cond_for_table(having,used_tables,used_tables);
+ if (sort_table_cond)
+ {
+ if (!table->select)
+ if (!(table->select=new SQL_SELECT))
+ goto err;
+ if (!table->select->cond)
+ table->select->cond=sort_table_cond;
+ else // This should never happen
+ if (!(table->select->cond=new Item_cond_and(table->select->cond,
+ sort_table_cond)))
+ goto err;
+ table->select_cond=table->select->cond;
+ DBUG_EXECUTE("where",print_where(table->select->cond,
+ "select and having"););
+ having=make_cond_for_table(having,~ (table_map) 0,~used_tables);
+ DBUG_EXECUTE("where",print_where(conds,"having after sort"););
+ }
}
if (create_sort_index(&join.join_tab[join.const_tables],
group ? group : order,
(having || group ||
- join.const_tables != join.tables - 1) ?
+ join.const_tables != join.tables - 1 ||
+ (join.select_options & OPTION_FOUND_ROWS)) ?
HA_POS_ERROR : thd->select_limit))
goto err; /* purecov: inspected */
}
@@ -776,7 +872,8 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
error=do_select(&join,&fields,NULL,procedure);
err:
- thd->examined_row_count=join.examined_rows;
+ thd->limit_found_rows = join.send_records;
+ thd->examined_row_count = join.examined_rows;
thd->proc_info="end";
join.lock=0; // It's faster to unlock later
join_free(&join);
@@ -797,7 +894,7 @@ err:
*****************************************************************************/
static ha_rows get_quick_record_count(SQL_SELECT *select,TABLE *table,
- key_map keys)
+ key_map keys,ha_rows limit)
{
int error;
DBUG_ENTER("get_quick_record_count");
@@ -805,7 +902,7 @@ static ha_rows get_quick_record_count(SQL_SELECT *select,TABLE *table,
{
select->head=table;
table->reginfo.impossible_range=0;
- if ((error=select->test_quick_select(keys,(table_map) 0,HA_POS_ERROR))
+ if ((error=select->test_quick_select(keys,(table_map) 0,limit))
== 1)
DBUG_RETURN(select->quick->records);
if (error == -1)
@@ -825,7 +922,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
{
int error;
uint i,table_count,const_count,found_ref,refs,key,const_ref,eq_part;
- table_map const_table_map,all_table_map;
+ table_map const_table_map,found_const_table_map,all_table_map;
TABLE **table_vector;
JOIN_TAB *stat,*stat_end,*s,**stat_ref;
SQL_SELECT *select;
@@ -845,7 +942,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
join->best_ref=stat_vector;
stat_end=stat+table_count;
- const_table_map=all_table_map=0;
+ const_table_map=found_const_table_map=all_table_map=0;
const_count=0;
for (s=stat,i=0 ; tables ; s++,tables=tables->next,i++)
@@ -860,13 +957,13 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
bzero((char*) table->const_key_parts, sizeof(key_part_map)*table->keys);
all_table_map|= table->map;
s->join=join;
+ s->info=0; // For describe
if ((s->on_expr=tables->on_expr))
{
+ /* Left join */
if (!table->file->records)
{ // Empty table
- s->key_dependent=s->dependent=0;
- s->type=JT_SYSTEM;
- const_table_map|=table->map;
+ s->key_dependent=s->dependent=0; // Ignore LEFT JOIN depend.
set_position(join,const_count++,s,(KEYUSE*) 0);
continue;
}
@@ -885,10 +982,9 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
s->dependent=(table_map) 0;
s->key_dependent=(table_map) 0;
if ((table->system || table->file->records <= 1) && ! s->dependent &&
- !(table->file->option_flag() & HA_NOT_EXACT_COUNT))
+ !(table->file->option_flag() & HA_NOT_EXACT_COUNT) &&
+ !table->fulltext_searched)
{
- s->type=JT_SYSTEM;
- const_table_map|=table->map;
set_position(join,const_count++,s,(KEYUSE*) 0);
}
}
@@ -896,10 +992,10 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
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: 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)
{
@@ -936,31 +1032,66 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
conds,~outer_join))
DBUG_RETURN(1);
+ /* Read tables with 0 or 1 rows (system tables) */
+ join->const_table_map=const_table_map;
+
+ for (POSITION *p_pos=join->positions, *p_end=p_pos+const_count;
+ p_pos < p_end ;
+ p_pos++)
+ {
+ int tmp;
+ s= p_pos->table;
+ s->type=JT_SYSTEM;
+ join->const_table_map|=s->table->map;
+ if ((tmp=join_read_const_table(s, p_pos)))
+ {
+ if (tmp > 0)
+ DBUG_RETURN(1); // Fatal error
+ }
+ else
+ found_const_table_map|= s->table->map;
+ }
+
/* loop until no more const tables are found */
int ref_changed;
do
{
ref_changed = 0;
found_ref=0;
- for (JOIN_TAB **pos=stat_vector+const_count; (s= *pos) ; pos++)
+
+ /*
+ We only have to loop from stat_vector + const_count as
+ set_position() will move all const_tables first in stat_vector
+ */
+
+ for (JOIN_TAB **pos=stat_vector+const_count ; (s= *pos) ; pos++)
{
+ TABLE *table=s->table;
if (s->dependent) // If dependent on some table
{
- if (s->dependent & ~(const_table_map)) // All dep. must be constants
+ // All dep. must be constants
+ if (s->dependent & ~(join->const_table_map))
continue;
- if (s->table->file->records <= 1L &&
- !(s->table->file->option_flag() & HA_NOT_EXACT_COUNT))
+ if (table->file->records <= 1L &&
+ !(table->file->option_flag() & HA_NOT_EXACT_COUNT))
{ // system table
+ int tmp;
s->type=JT_SYSTEM;
- const_table_map|=s->table->map;
+ join->const_table_map|=table->map;
set_position(join,const_count++,s,(KEYUSE*) 0);
+ if ((tmp=join_read_const_table(s,join->positions+const_count-1)))
+ {
+ if (tmp > 0)
+ DBUG_RETURN(1); // Fatal error
+ }
+ else
+ found_const_table_map|= table->map;
continue;
}
}
/* check if table can be read by key or table only uses const refs */
if ((keyuse=s->keyuse))
{
- TABLE *table=s->table;
s->type= JT_REF;
while (keyuse->table == table)
{
@@ -973,7 +1104,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
{
if (keyuse->val->type() != Item::NULL_ITEM)
{
- if (!((~const_table_map) & keyuse->used_tables))
+ if (!((~join->const_table_map) & keyuse->used_tables))
const_ref|= (key_map) 1 << keyuse->keypart;
else
refs|=keyuse->used_tables;
@@ -987,10 +1118,22 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
{
if (const_ref == eq_part)
{ // Found everything for ref.
+ int tmp;
+ ref_changed = 1;
s->type=JT_CONST;
- const_table_map|=table->map;
+ join->const_table_map|=table->map;
set_position(join,const_count++,s,start_keyuse);
- ref_changed = 1;
+ if (create_ref_for_key(join, s, start_keyuse,
+ join->const_table_map))
+ DBUG_RETURN(1);
+ if ((tmp=join_read_const_table(s,
+ join->positions+const_count-1)))
+ {
+ if (tmp > 0)
+ DBUG_RETURN(1); // Fatal error
+ }
+ else
+ found_const_table_map|= table->map;
break;
}
else
@@ -999,7 +1142,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
}
}
}
- } while (const_table_map & found_ref && ref_changed);
+ } while (join->const_table_map & found_ref && ref_changed);
/* Calc how many (possible) matched records in each table */
@@ -1015,8 +1158,11 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
s->found_records=s->records=s->table->file->records;
s->read_time=(ha_rows) s->table->file->scan_time();
- /* Set a max range of how many seeks we can expect when using keys */
- s->worst_seeks= (double) (s->read_time*2);
+ /*
+ Set a max range of how many seeks we can expect when using keys
+ This was (s->read_time*5), but this was too low with small rows
+ */
+ s->worst_seeks= (double) s->found_records / 5;
if (s->worst_seeks < 2.0) // Fix for small tables
s->worst_seeks=2.0;
@@ -1026,10 +1172,11 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
{
ha_rows records;
if (!select)
- select=make_select(s->table,0,
- 0,
+ select=make_select(s->table, join->const_table_map,
+ join->const_table_map,
and_conds(conds,s->on_expr),&error);
- records=get_quick_record_count(select,s->table, s->const_keys);
+ records=get_quick_record_count(select,s->table, s->const_keys,
+ join->row_limit);
s->quick=select->quick;
s->needed_reg=select->needed_reg;
select->quick=0;
@@ -1047,10 +1194,10 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
join->map2table=stat_ref;
join->table= join->all_tables=table_vector;
join->const_tables=const_count;
- join->const_table_map=const_table_map;
+ join->found_const_table_map=found_const_table_map;
if (join->const_tables != join->tables)
- find_best_combination(join,all_table_map & ~const_table_map);
+ find_best_combination(join,all_table_map & ~join->const_table_map);
else
{
memcpy((gptr) join->best_positions,(gptr) join->positions,
@@ -1087,7 +1234,7 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
if (start == new_fields)
return start; // Impossible or
if (new_fields == end)
- return start; // No new fields, skipp all
+ return start; // No new fields, skip all
KEY_FIELD *first_free=new_fields;
@@ -1149,7 +1296,7 @@ add_key_field(KEY_FIELD **key_fields,uint and_level,
// Don't remove column IS NULL on a LEFT JOIN table
if (!eq_func || !value || value->type() != Item::NULL_ITEM ||
!field->table->maybe_null || field->null_ptr)
- return; // Not a key. Skipp it
+ return; // Not a key. Skip it
exists_optimize=1;
}
else
@@ -1168,11 +1315,13 @@ add_key_field(KEY_FIELD **key_fields,uint and_level,
else
{
JOIN_TAB *stat=field->table->reginfo.join_tab;
- stat[0].keys|=field->key_start; // Add possible keys
+ key_map possible_keys= (field->key_start &
+ field->table->keys_in_use_for_query);
+ stat[0].keys|= possible_keys; // Add possible keys
if (!value)
{ // Probably BETWEEN or IN
- stat[0].const_keys |= field->key_start;
+ stat[0].const_keys |= possible_keys;
return; // Can't be used as eq key
}
@@ -1186,7 +1335,7 @@ add_key_field(KEY_FIELD **key_fields,uint and_level,
*/
stat[0].key_dependent|=used_tables;
if (value->const_item())
- stat[0].const_keys |= field->key_start;
+ stat[0].const_keys |= possible_keys;
/* We can't always use indexes when comparing a string index to a
number. cmp_type() is checked to allow compare of dates to numbers */
@@ -1213,7 +1362,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
{
if (cond->type() == Item_func::COND_ITEM)
{
- List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
+ List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list());
KEY_FIELD *org_key_fields= *key_fields;
if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
@@ -1367,27 +1516,27 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
*arg1=(Item_func *)(func->arguments()[1]);
if ((functype == Item_func::GE_FUNC ||
functype == Item_func::GT_FUNC) &&
- arg0->type() == Item::FUNC_ITEM &&
+ arg0->type() == Item::FUNC_ITEM &&
arg0->functype() == Item_func::FT_FUNC &&
- arg1->const_item() && arg1->val()>=0)
+ arg1->const_item() && arg1->val()>0)
cond_func=(Item_func_match *) arg0;
else if ((functype == Item_func::LE_FUNC ||
functype == Item_func::LT_FUNC) &&
arg1->type() == Item::FUNC_ITEM &&
arg1->functype() == Item_func::FT_FUNC &&
- arg0->const_item() && arg0->val()>=0)
+ arg0->const_item() && arg0->val()>0)
cond_func=(Item_func_match *) arg1;
}
}
else if (cond->type() == Item::COND_ITEM)
{
- List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
+ List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list());
if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
{
Item *item;
/*
- I', (Sergei) too lazy to implement proper recursive descent here,
+ I'm (Sergei) too lazy to implement proper recursive descent here,
and anyway, nobody will use such a stupid queries
that will require it :-)
May be later...
@@ -1404,7 +1553,7 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
}
}
- if(!cond_func)
+ if (!cond_func || cond_func->key == NO_SUCH_KEY)
return;
KEYUSE keyuse;
@@ -1467,7 +1616,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
add_key_part(keyuse,field);
}
- if (thd->lex.ftfunc_list.elements)
+ if (thd->lex.select->ftfunc_list.elements)
{
add_ft_keys(keyuse,join_tab,cond,normal_tables);
}
@@ -1475,7 +1624,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
/*
** remove ref if there is a keypart which is a ref and a const.
** remove keyparts without previous keyparts.
- ** Special treatment for ft-keys. SerG.
+ ** Special treatment for ft-keys.
*/
if (keyuse->elements)
{
@@ -1716,7 +1865,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
{
/* we can use only index tree */
uint keys_per_block= table->file->block_size/2/
- keyinfo->key_length+1;
+ (keyinfo->key_length+table->file->ref_length)+1;
tmp=(record_count*(records+keys_per_block-1)/
keys_per_block);
}
@@ -1786,7 +1935,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
{
/* we can use only index tree */
uint keys_per_block= table->file->block_size/2/
- keyinfo->key_length+1;
+ (keyinfo->key_length+table->file->ref_length)+1;
tmp=record_count*(tmp+keys_per_block-1)/keys_per_block;
}
else
@@ -1811,10 +1960,17 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
/*
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]))
+ best_max_key_part >= s->table->quick_key_parts[best_key->key]) &&
+ !((s->table->file->option_flag() & HA_TABLE_SCAN_ON_INDEX) &&
+ s->table->used_keys && best_key))
{ // Check full join
if (s->on_expr)
{
@@ -1959,21 +2115,18 @@ prev_record_reads(JOIN *join,table_map found_ref)
static bool
get_best_combination(JOIN *join)
{
- uint i,key,tablenr;
+ uint i,tablenr;
table_map used_tables;
- TABLE *table;
JOIN_TAB *join_tab,*j;
KEYUSE *keyuse;
- KEY *keyinfo;
uint table_count;
+ THD *thd=join->thd;
table_count=join->tables;
if (!(join->join_tab=join_tab=
- (JOIN_TAB*) join->thd->alloc(sizeof(JOIN_TAB)*table_count)))
+ (JOIN_TAB*) thd->alloc(sizeof(JOIN_TAB)*table_count)))
return TRUE;
- join->const_tables=0; /* for checking */
- join->const_table_map=0;
join->full_join=0;
used_tables=0;
@@ -1982,188 +2135,188 @@ get_best_combination(JOIN *join)
TABLE *form;
*j= *join->best_positions[tablenr].table;
form=join->table[tablenr]=j->table;
- j->ref.key = -1;
- j->ref.key_parts=0;
- j->info=0; // For describe
used_tables|= form->map;
form->reginfo.join_tab=j;
if (!j->on_expr)
form->reginfo.not_exists_optimize=0; // Only with LEFT JOIN
+ if (j->type == JT_CONST)
+ continue; // Handled in make_join_stat..
+
+ j->ref.key = -1;
+ j->ref.key_parts=0;
if (j->type == JT_SYSTEM)
- {
- j->table->const_table=1;
- if (join->const_tables == tablenr)
- {
- join->const_tables++;
- join->const_table_map|=form->map;
- }
continue;
- }
if (!j->keys || !(keyuse= join->best_positions[tablenr].key))
{
j->type=JT_ALL;
if (tablenr != join->const_tables)
join->full_join=1;
}
- else
- {
- uint keyparts,length;
- bool ftkey=(keyuse->keypart == FT_KEYPART);
- /*
- ** Use best key from find_best
- */
- table=j->table;
- key=keyuse->key;
+ else if (create_ref_for_key(join, j, keyuse, used_tables))
+ return TRUE; // Something went wrong
+ }
- keyinfo=table->key_info+key;
- if (ftkey)
- {
- Item_func_match *ifm=(Item_func_match *)keyuse->val;
+ 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;
+}
- length=0;
- keyparts=1;
- ifm->join_key=1;
- }
- else
- {
- keyparts=length=0;
- do
- {
- if (!((~used_tables) & keyuse->used_tables))
- {
- if (keyparts == keyuse->keypart)
- {
- keyparts++;
- length+=keyinfo->key_part[keyuse->keypart].store_length;
- }
- }
- keyuse++;
- } while (keyuse->table == table && keyuse->key == key);
- } /* not ftkey */
-
- /* set up fieldref */
- keyinfo=table->key_info+key;
- j->ref.key_parts=keyparts;
- j->ref.key_length=length;
- j->ref.key=(int) key;
- if (!(j->ref.key_buff= (byte*) sql_calloc(ALIGN_SIZE(length)*2)) ||
- !(j->ref.key_copy= (store_key**) sql_alloc((sizeof(store_key*) *
- (keyparts+1)))) ||
- !(j->ref.items= (Item**) sql_alloc(sizeof(Item*)*keyparts)))
- {
- return TRUE;
- }
- j->ref.key_buff2=j->ref.key_buff+ALIGN_SIZE(length);
- j->ref.key_err=1;
- keyuse=join->best_positions[tablenr].key;
- store_key **ref_key=j->ref.key_copy;
- byte *key_buff=j->ref.key_buff;
- if (ftkey)
- {
- j->ref.items[0]=((Item_func*)(keyuse->val))->key_item();
- if (keyuse->used_tables)
- return TRUE; // not supported yet. SerG
+static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
+ table_map used_tables)
+{
+ KEYUSE *keyuse=org_keyuse;
+ bool ftkey=(keyuse->keypart == FT_KEYPART);
+ THD *thd= join->thd;
+ uint keyparts,length,key;
+ TABLE *table;
+ KEY *keyinfo;
- j->type=JT_FT;
- }
- else
- {
- THD *thd=join->thd;
- for (i=0 ; i < keyparts ; keyuse++,i++)
- {
- while (keyuse->keypart != i ||
- ((~used_tables) & keyuse->used_tables))
- keyuse++; /* Skipp other parts */
-
- uint maybe_null= test(keyinfo->key_part[i].null_bit);
- j->ref.items[i]=keyuse->val; // Save for cond removal
- if (!keyuse->used_tables &&
- !(join->select_options & SELECT_DESCRIBE))
- { // Compare against constant
- store_key_item *tmp=new store_key_item(keyinfo->key_part[i].field,
- (char*)key_buff +
- maybe_null,
- maybe_null ?
- (char*) key_buff : 0,
- keyinfo->key_part[i].length,
- keyuse->val);
- if (thd->fatal_error)
- {
- return TRUE;
- }
- tmp->copy();
- }
- else
- *ref_key++= get_store_key(keyuse,join->const_table_map,
- &keyinfo->key_part[i],
- (char*) key_buff,maybe_null);
- key_buff+=keyinfo->key_part[i].store_length;
- }
- } /* not ftkey */
- *ref_key=0; // end_marker
- if (j->type == JT_FT) /* no-op */;
- else if (j->type == JT_CONST)
+ /*
+ ** Use best key from find_best
+ */
+ table=j->table;
+ key=keyuse->key;
+ keyinfo=table->key_info+key;
+
+ if (ftkey)
+ {
+ Item_func_match *ifm=(Item_func_match *)keyuse->val;
+
+ length=0;
+ keyparts=1;
+ ifm->join_key=1;
+ }
+ else
+ {
+ keyparts=length=0;
+ do
+ {
+ if (!((~used_tables) & keyuse->used_tables))
{
- j->table->const_table=1;
- if (join->const_tables == tablenr)
+ if (keyparts == keyuse->keypart)
{
- join->const_tables++;
- join->const_table_map|=form->map;
+ keyparts++;
+ length+=keyinfo->key_part[keyuse->keypart].store_length;
}
}
- else if (((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY)) != HA_NOSAME) ||
- keyparts != keyinfo->key_parts)
- j->type=JT_REF; /* Must read with repeat */
- else if (ref_key == j->ref.key_copy)
- { /* Should never be reached */
- /*
- This happen if we are using a constant expression in the ON part
- of an LEFT JOIN.
- SELECT * FROM a LEFT JOIN b ON b.key=30
- Here we should not mark the table as a 'const' as a field may
- have a 'normal' value or a NULL value.
- */
- j->type=JT_CONST;
- if (join->const_tables == tablenr)
+ keyuse++;
+ } while (keyuse->table == table && keyuse->key == key);
+ } /* not ftkey */
+
+ /* set up fieldref */
+ keyinfo=table->key_info+key;
+ j->ref.key_parts=keyparts;
+ j->ref.key_length=length;
+ j->ref.key=(int) key;
+ if (!(j->ref.key_buff= (byte*) thd->calloc(ALIGN_SIZE(length)*2)) ||
+ !(j->ref.key_copy= (store_key**) thd->alloc((sizeof(store_key*) *
+ (keyparts+1)))) ||
+ !(j->ref.items= (Item**) thd->alloc(sizeof(Item*)*keyparts)))
+ {
+ return TRUE;
+ }
+ j->ref.key_buff2=j->ref.key_buff+ALIGN_SIZE(length);
+ j->ref.key_err=1;
+ keyuse=org_keyuse;
+
+ store_key **ref_key=j->ref.key_copy;
+ byte *key_buff=j->ref.key_buff;
+ if (ftkey)
+ {
+ j->ref.items[0]=((Item_func*)(keyuse->val))->key_item();
+ if (keyuse->used_tables)
+ return TRUE; // not supported yet. SerG
+
+ j->type=JT_FT;
+ }
+ else
+ {
+ uint i;
+ for (i=0 ; i < keyparts ; keyuse++,i++)
+ {
+ while (keyuse->keypart != i ||
+ ((~used_tables) & keyuse->used_tables))
+ keyuse++; /* Skip other parts */
+
+ uint maybe_null= test(keyinfo->key_part[i].null_bit);
+ j->ref.items[i]=keyuse->val; // Save for cond removal
+ if (!keyuse->used_tables &&
+ !(join->select_options & SELECT_DESCRIBE))
+ { // Compare against constant
+ store_key_item *tmp=new store_key_item(thd,
+ keyinfo->key_part[i].field,
+ (char*)key_buff +
+ maybe_null,
+ maybe_null ?
+ (char*) key_buff : 0,
+ keyinfo->key_part[i].length,
+ keyuse->val);
+ if (thd->fatal_error)
{
- join->const_tables++;
- join->const_table_map|=form->map;
+ return TRUE;
}
+ tmp->copy();
}
else
- j->type=JT_EQ_REF;
- }
+ *ref_key++= get_store_key(thd,
+ keyuse,join->const_table_map,
+ &keyinfo->key_part[i],
+ (char*) key_buff,maybe_null);
+ key_buff+=keyinfo->key_part[i].store_length;
+ }
+ } /* not ftkey */
+ *ref_key=0; // end_marker
+ if (j->type == JT_FT) /* no-op */;
+ else if (j->type == JT_CONST)
+ j->table->const_table=1;
+ else if (((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY))
+ != HA_NOSAME) ||
+ keyparts != keyinfo->key_parts)
+ j->type=JT_REF; /* Must read with repeat */
+ else if (ref_key == j->ref.key_copy)
+ { /* Should never be reached */
+ /*
+ This happen if we are using a constant expression in the ON part
+ of an LEFT JOIN.
+ SELECT * FROM a LEFT JOIN b ON b.key=30
+ Here we should not mark the table as a 'const' as a field may
+ have a 'normal' value or a NULL value.
+ */
+ j->type=JT_CONST;
}
-
- for (i=0 ; i < table_count ; i++)
- join->map2table[join->join_tab[i].table->tablenr]=join->join_tab+i;
- update_depend_map(join);
+ else
+ j->type=JT_EQ_REF;
return 0;
}
+
static store_key *
-get_store_key(KEYUSE *keyuse, table_map used_tables, KEY_PART_INFO *key_part,
- char *key_buff, uint maybe_null)
+get_store_key(THD *thd, KEYUSE *keyuse, table_map used_tables,
+ KEY_PART_INFO *key_part, char *key_buff, uint maybe_null)
{
if (!((~used_tables) & keyuse->used_tables)) // if const item
{
- return new store_key_const_item(key_part->field,
+ return new store_key_const_item(thd,
+ key_part->field,
key_buff + maybe_null,
maybe_null ? key_buff : 0,
key_part->length,
keyuse->val);
}
else if (keyuse->val->type() == Item::FIELD_ITEM)
- return new store_key_field(key_part->field,
+ return new store_key_field(thd,
+ key_part->field,
key_buff + maybe_null,
maybe_null ? key_buff : 0,
key_part->length,
((Item_field*) keyuse->val)->field,
keyuse->val->full_name());
- return new store_key_item(key_part->field,
+ return new store_key_item(thd,
+ key_part->field,
key_buff + maybe_null,
maybe_null ? key_buff : 0,
key_part->length,
@@ -2201,13 +2354,15 @@ make_simple_join(JOIN *join,TABLE *tmp_table)
join->tables=1;
join->const_tables=0;
join->const_table_map=0;
- join->tmp_table_param.copy_field_count=join->tmp_table_param.field_count=
- join->tmp_table_param.sum_func_count= join->tmp_table_param.func_count=0;
- join->tmp_table_param.copy_field=0;
+ join->tmp_table_param.field_count= join->tmp_table_param.sum_func_count=
+ join->tmp_table_param.func_count=0;
+ join->tmp_table_param.copy_field=join->tmp_table_param.copy_field_end=0;
join->first_record=join->sort_and_group=0;
join->sum_funcs=0;
join->send_records=(ha_rows) 0;
join->group=0;
+ join->do_send_rows = 1;
+ join->row_limit=HA_POS_ERROR;
join_tab->cache.buff=0; /* No cacheing */
join_tab->table=tmp_table;
@@ -2281,7 +2436,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
{
DBUG_EXECUTE("where",print_where(tmp,tab->table->table_name););
SQL_SELECT *sel=tab->select=(SQL_SELECT*)
- sql_memdup((gptr) select, sizeof(SQL_SELECT));
+ join->thd->memdup((gptr) select, sizeof(SQL_SELECT));
if (!sel)
DBUG_RETURN(1); // End of memory
tab->select_cond=sel->cond=tmp;
@@ -2323,15 +2478,19 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
*/
if ((tab->keys & ~ tab->const_keys && i > 0) ||
- tab->const_keys && i == join->const_tables &&
- join->thd->select_limit < join->best_positions[i].records_read)
+ (tab->const_keys && i == join->const_tables &&
+ join->thd->select_limit < join->best_positions[i].records_read &&
+ !(join->select_options & OPTION_FOUND_ROWS)))
{
/* Join with outer join condition */
COND *orig_cond=sel->cond;
sel->cond=and_conds(sel->cond,tab->on_expr);
if (sel->test_quick_select(tab->keys,
used_tables & ~ current_map,
- join->thd->select_limit) < 0)
+ (join->select_options &
+ OPTION_FOUND_ROWS ?
+ HA_POS_ERROR :
+ join->thd->select_limit)) < 0)
DBUG_RETURN(1); // Impossible range
sel->cond=orig_cond;
}
@@ -2358,8 +2517,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
current_map)))
{
DBUG_EXECUTE("where",print_where(tmp,"cache"););
- tab->cache.select=(SQL_SELECT*) sql_memdup((gptr) sel,
- sizeof(SQL_SELECT));
+ tab->cache.select=(SQL_SELECT*)
+ join->thd->memdup((gptr) sel, sizeof(SQL_SELECT));
tab->cache.select->cond=tmp;
tab->cache.select->read_tables=join->const_table_map;
}
@@ -2376,6 +2535,7 @@ static void
make_join_readinfo(JOIN *join,uint options)
{
uint i;
+ SELECT_LEX *select_lex = &(join->thd->lex.select_lex);
DBUG_ENTER("make_join_readinfo");
for (i=join->const_tables ; i < join->tables ; i++)
@@ -2408,7 +2568,8 @@ make_join_readinfo(JOIN *join,uint options)
table->file->index_init(tab->ref.key);
tab->read_first_record= join_read_key;
tab->read_record.read_record= join_no_more_records;
- if (table->used_keys & ((key_map) 1 << tab->ref.key))
+ if (table->used_keys & ((key_map) 1 << tab->ref.key) &&
+ !table->no_keyread)
{
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
@@ -2425,8 +2586,9 @@ make_join_readinfo(JOIN *join,uint options)
tab->quick=0;
table->file->index_init(tab->ref.key);
tab->read_first_record= join_read_always_key;
- tab->read_record.read_record= join_read_next;
- if (table->used_keys & ((key_map) 1 << tab->ref.key))
+ tab->read_record.read_record= join_read_next_same;
+ if (table->used_keys & ((key_map) 1 << tab->ref.key) &&
+ !table->no_keyread)
{
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
@@ -2443,7 +2605,7 @@ make_join_readinfo(JOIN *join,uint options)
** if previous table use cache
*/
table->status=STATUS_NO_RECORD;
- if (i != join->const_tables && (options & SELECT_USE_CACHE) &&
+ if (i != join->const_tables && !(options & SELECT_NO_JOIN_CACHE) &&
tab->use_quick != 2 && !tab->on_expr)
{
if ((options & SELECT_DESCRIBE) ||
@@ -2456,7 +2618,7 @@ make_join_readinfo(JOIN *join,uint options)
/* These init changes read_record */
if (tab->use_quick == 2)
{
- join->thd->lex.options|=QUERY_NO_GOOD_INDEX_USED;
+ select_lex->options|=QUERY_NO_GOOD_INDEX_USED;
tab->read_first_record= join_init_quick_read_record;
statistic_increment(select_range_check_count, &LOCK_status);
}
@@ -2471,7 +2633,7 @@ make_join_readinfo(JOIN *join,uint options)
}
else
{
- join->thd->lex.options|=QUERY_NO_INDEX_USED;
+ select_lex->options|=QUERY_NO_INDEX_USED;
statistic_increment(select_scan_count, &LOCK_status);
}
}
@@ -2483,22 +2645,25 @@ make_join_readinfo(JOIN *join,uint options)
}
else
{
- join->thd->lex.options|=QUERY_NO_INDEX_USED;
+ select_lex->options|=QUERY_NO_INDEX_USED;
statistic_increment(select_full_join_count, &LOCK_status);
}
}
- if (tab->select && tab->select->quick &&
- table->used_keys & ((key_map) 1 << tab->select->quick->index))
+ if (!table->no_keyread)
{
- table->key_read=1;
- table->file->extra(HA_EXTRA_KEYREAD);
- }
- else if (table->used_keys && ! (tab->select && tab->select->quick))
- { // Only read index tree
- tab->index=find_shortest_key(table, table->used_keys);
- tab->table->file->index_init(tab->index);
- tab->read_first_record= join_init_read_first_with_key;
- tab->type=JT_NEXT; // Read with index_first / index_next
+ if (tab->select && tab->select->quick &&
+ table->used_keys & ((key_map) 1 << tab->select->quick->index))
+ {
+ table->key_read=1;
+ table->file->extra(HA_EXTRA_KEYREAD);
+ }
+ else if (table->used_keys && ! (tab->select && tab->select->quick))
+ { // Only read index tree
+ tab->index=find_shortest_key(table, table->used_keys);
+ tab->table->file->index_init(tab->index);
+ tab->read_first_record= join_read_first;
+ tab->type=JT_NEXT; // Read with index_first / index_next
+ }
}
}
break;
@@ -2551,14 +2716,16 @@ join_free(JOIN *join)
}
// We are not using tables anymore
// Unlock all tables. We may be in an INSERT .... SELECT statement.
- if (join->lock && join->thd->lock)
+ if (join->lock && join->thd->lock &&
+ !(join->select_options & SELECT_NO_UNLOCK))
{
mysql_unlock_read_tables(join->thd, join->lock);// Don't free join->lock
join->lock=0;
}
join->group_fields.delete_elements();
join->tmp_table_param.copy_funcs.delete_elements();
- delete [] join->tmp_table_param.copy_field;
+ if (join->tmp_table_param.copy_field) // Because of bug in ecc
+ delete [] join->tmp_table_param.copy_field;
join->tmp_table_param.copy_field=0;
DBUG_VOID_RETURN;
}
@@ -2608,7 +2775,7 @@ eq_ref_table(JOIN *join, ORDER *start_order, JOIN_TAB *tab)
if (order)
{
found++;
- dbug_assert(!(order->used & map));
+ DBUG_ASSERT(!(order->used & map));
order->used|=map;
continue; // Used in ORDER BY
}
@@ -2723,7 +2890,7 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond, bool *simple_order)
else if (!(order_tables & not_const_tables))
{
DBUG_PRINT("info",("removing: %s", order->item[0]->full_name()));
- continue; // skipp const item
+ continue; // skip const item
}
else
{
@@ -2766,7 +2933,7 @@ return_zero_rows(select_result *result,TABLE_LIST *tables,List<Item> &fields,
DBUG_ENTER("return_zero_rows");
if (select_options & SELECT_DESCRIBE)
- {
+ {
describe_info(current_thd, info);
DBUG_RETURN(0);
}
@@ -2782,17 +2949,17 @@ return_zero_rows(select_result *result,TABLE_LIST *tables,List<Item> &fields,
if (having && having->val_int() == 0)
send_row=0;
}
- if (!tables || !(result->send_fields(fields,1)))
+ if (!(result->send_fields(fields,1)))
{
if (send_row)
result->send_data(fields);
- if (tables) // Not from do_select()
+ if (tables) // Not from do_select()
{
/* Close open cursors */
for (TABLE_LIST *table=tables; table ; table=table->next)
table->table->file->index_end();
- result->send_eof(); // Should be safe
}
+ result->send_eof(); // Should be safe
}
DBUG_RETURN(0);
}
@@ -2910,7 +3077,7 @@ propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_level,
{
bool and_level= ((Item_cond*) cond)->functype() ==
Item_func::COND_AND_FUNC;
- List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
+ List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list());
Item *item;
I_List<COND_CMP> save;
while ((item=li++))
@@ -3064,13 +3231,13 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value)
((Item_func*) cond)->functype() == Item_func::ISNULL_FUNC)
{
/*
- ** Handles this special case for some ODBC applications:
- ** The are requesting the row that was just updated with a auto_increment
- ** value with this construct:
- **
- ** SELECT * from table_name where auto_increment_column IS NULL
- ** This will be changed to:
- ** SELECT * from table_name where auto_increment_column = LAST_INSERT_ID
+ Handles this special case for some ODBC applications:
+ The are requesting the row that was just updated with a auto_increment
+ value with this construct:
+
+ SELECT * from table_name where auto_increment_column IS NULL
+ This will be changed to:
+ SELECT * from table_name where auto_increment_column = LAST_INSERT_ID
*/
Item_func_isnull *func=(Item_func_isnull*) cond;
@@ -3083,6 +3250,7 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value)
(thd->options & OPTION_AUTO_IS_NULL) &&
thd->insert_id())
{
+ query_cache_abort(&thd->net);
COND *new_cond;
if ((new_cond= new Item_func_eq(args[0],
new Item_int("last_insert_id()",
@@ -3126,7 +3294,7 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value)
}
}
*cond_value=Item::COND_OK;
- return cond; /* Point at next and level */
+ return cond; // Point at next and level
}
/*
@@ -3140,7 +3308,7 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item)
{
bool and_level= (((Item_cond*) cond)->functype()
== Item_func::COND_AND_FUNC);
- List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
+ List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list());
Item *item;
while ((item=li++))
{
@@ -3195,7 +3363,7 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item)
** for send_fields
****************************************************************************/
-Field *create_tmp_field(TABLE *table,Item *item, Item::Type type,
+Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item_result_field ***copy_func, Field **from_field,
bool group, bool modify_item)
{
@@ -3228,7 +3396,7 @@ Field *create_tmp_field(TABLE *table,Item *item, Item::Type type,
item->name,table,item_sum->decimals);
case INT_RESULT:
return new Field_longlong(item_sum->max_length,maybe_null,
- item->name,table);
+ item->name,table,item->unsigned_flag);
case STRING_RESULT:
if (item_sum->max_length > 255)
return new Field_blob(item_sum->max_length,maybe_null,
@@ -3237,7 +3405,7 @@ Field *create_tmp_field(TABLE *table,Item *item, Item::Type type,
item->name,table,item->binary);
}
}
- current_thd->fatal_error=1;
+ thd->fatal_error=1;
return 0; // Error
}
case Item::FIELD_ITEM:
@@ -3245,7 +3413,8 @@ Field *create_tmp_field(TABLE *table,Item *item, Item::Type type,
Field *org_field=((Item_field*) item)->field,*new_field;
*from_field=org_field;
- if ((new_field= org_field->new_field(table))) // Should always be true
+ // The following should always be true
+ if ((new_field= org_field->new_field(&thd->mem_root,table)))
{
if (modify_item)
((Item_field*) item)->result_field= new_field;
@@ -3279,7 +3448,7 @@ Field *create_tmp_field(TABLE *table,Item *item, Item::Type type,
break;
case INT_RESULT:
new_field=new Field_longlong(item->max_length,maybe_null,
- item->name,table);
+ item->name,table, item->unsigned_flag);
break;
case STRING_RESULT:
if (item->max_length > 255)
@@ -3305,13 +3474,14 @@ Field *create_tmp_field(TABLE *table,Item *item, Item::Type type,
TABLE *
create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
ORDER *group, bool distinct, bool save_sum_fields,
- bool allow_distinct_limit, uint select_options)
+ bool allow_distinct_limit, ulong select_options)
{
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;
+ bool not_all_columns= !(select_options & TMP_TABLE_ALL_COLUMNS);
char *tmpname,path[FN_REFLEN];
byte *pos,*group_buff;
uchar *null_flags;
@@ -3334,7 +3504,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
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,
+ 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,
@@ -3345,7 +3515,11 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
if (!param->quick_group)
group=0; // Can't use group key
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)
+ using_unique_constraint=1;
+ }
if (param->group_length >= MAX_BLOB_WIDTH)
using_unique_constraint=1;
if (group)
@@ -3402,24 +3576,27 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
reclength=blob_count=null_count=hidden_null_count=group_null_items=0;
param->using_indirect_summary_function=0;
- List_iterator<Item> li(fields);
+ List_iterator_fast<Item> li(fields);
Item *item;
Field **tmp_from_field=from_field;
while ((item=li++))
{
Item::Type type=item->type();
- if (item->with_sum_func && type != Item::SUM_FUNC_ITEM)
+ if (not_all_columns)
{
- /*
- Mark that the we have ignored an item that refers to a summary
- function. We need to know this if someone is going to use
- DISTINCT on the result.
- */
- param->using_indirect_summary_function=1;
- continue;
+ if (item->with_sum_func && type != Item::SUM_FUNC_ITEM)
+ {
+ /*
+ Mark that the we have ignored an item that refers to a summary
+ function. We need to know this if someone is going to use
+ DISTINCT on the result.
+ */
+ param->using_indirect_summary_function=1;
+ continue;
+ }
+ if (item->const_item()) // We don't have to store this
+ continue;
}
- if (item->const_item()) // We don't have to store this
- continue;
if (type == Item::SUM_FUNC_ITEM && !group && !save_sum_fields)
{ /* Can't calc group yet */
((Item_sum*) item)->result_field=0;
@@ -3429,8 +3606,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
if (!arg->const_item())
{
Field *new_field=
- create_tmp_field(table,arg,arg->type(),&copy_func,tmp_from_field,
- group != 0,1);
+ create_tmp_field(thd, table,arg,arg->type(),&copy_func,
+ tmp_from_field, group != 0,not_all_columns);
if (!new_field)
goto err; // Should be OOM
tmp_from_field++;
@@ -3446,8 +3623,9 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
}
else
{
- Field *new_field=create_tmp_field(table,item,type,&copy_func,
- tmp_from_field, group != 0,1);
+ Field *new_field=create_tmp_field(thd, table, item,type, &copy_func,
+ tmp_from_field, group != 0,
+ not_all_columns);
if (!new_field)
{
if (thd->fatal_error)
@@ -3543,6 +3721,10 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
{
if (field->flags & GROUP_FLAG && !using_unique_constraint)
{
+ /*
+ We have to reserve one byte here for NULL bits,
+ as this is updated by 'end_update()'
+ */
*pos++=0; // Null is stored here
recinfo->length=1;
recinfo->type=FIELD_NORMAL;
@@ -3577,14 +3759,14 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
(field->type() == FIELD_TYPE_STRING ||
field->type() == FIELD_TYPE_VAR_STRING) &&
length >= 10 && blob_count)
- recinfo->type=FIELD_SKIPP_ENDSPACE;
+ recinfo->type=FIELD_SKIP_ENDSPACE;
else
recinfo->type=FIELD_NORMAL;
if (!--hidden_field_count)
null_count=(null_count+7) & ~7; // move to next byte
}
- param->copy_field_count=(uint) (copy - param->copy_field);
+ param->copy_field_end=copy;
param->recinfo=recinfo;
store_record(table,2); // Make empty default record
@@ -3626,19 +3808,21 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
if (!using_unique_constraint)
{
group->buff=(char*) group_buff;
- if (!(group->field=field->new_field(table)))
+ if (!(group->field=field->new_field(&thd->mem_root,table)))
goto err; /* purecov: inspected */
if (maybe_null)
{
/*
- To be able to group on NULL, we move the null bit to be
- just before the column and extend the key to cover the null bit
+ To be able to group on NULL, we reserve place in group_buff
+ for the NULL flag just before the column.
+ The field data is after this flag.
+ The NULL flag is updated by 'end_update()' and 'end_write()'
*/
- *group_buff= 0; // Init null byte
- key_part_info->offset--;
- key_part_info->length++;
- group->field->move_field((char*) group_buff+1, (uchar*) group_buff,
- 1);
+ 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);
}
else
group->field->move_field((char*) group_buff);
@@ -3740,14 +3924,13 @@ static bool open_tmp_table(TABLE *table)
return(1);
}
/* VOID(ha_lock(table,F_WRLCK)); */ /* Single thread table */
- (void) table->file->extra(HA_EXTRA_NO_READCHECK); /* Not needed */
(void) table->file->extra(HA_EXTRA_QUICK); /* Faster */
return(0);
}
static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
- uint options)
+ ulong options)
{
int error;
MI_KEYDEF keydef;
@@ -3794,10 +3977,10 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
for (uint i=0; i < keyinfo->key_parts ; i++,seg++)
{
Field *field=keyinfo->key_part[i].field;
- seg->flag=0;
- seg->language=MY_CHARSET_CURRENT;
- seg->length=keyinfo->key_part[i].length;
- seg->start=keyinfo->key_part[i].offset;
+ seg->flag= 0;
+ seg->language= MY_CHARSET_CURRENT;
+ seg->length= keyinfo->key_part[i].length;
+ seg->start= keyinfo->key_part[i].offset;
if (field->flags & BLOB_FLAG)
{
seg->type=
@@ -3818,11 +4001,17 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
keyinfo->key_part[i].length > 4)
seg->flag|=HA_SPACE_PACK;
}
- if (using_unique_constraint &&
- !(field->flags & NOT_NULL_FLAG))
+ if (!(field->flags & NOT_NULL_FLAG))
{
seg->null_bit= field->null_bit;
seg->null_pos= (uint) (field->null_ptr - (uchar*) table->record[0]);
+ /*
+ We are using a GROUP BY on something that contains NULL
+ In this case we have to tell MyISAM that two NULL should
+ on INSERT be compared as equal
+ */
+ if (!using_unique_constraint)
+ keydef.flag|= HA_NULL_ARE_EQUAL;
}
}
}
@@ -3908,12 +4097,18 @@ bool create_myisam_from_heap(TABLE *table, TMP_TABLE_PARAM *param, int error,
thd->proc_info="converting HEAP to MyISAM";
if (create_myisam_tmp_table(&new_table,param,
- thd->lex.options | thd->options))
+ thd->lex.select_lex.options | thd->options))
goto err2;
if (open_tmp_table(&new_table))
goto err1;
table->file->index_end();
table->file->rnd_init();
+ if (table->no_rows)
+ {
+ new_table.file->extra(HA_EXTRA_NO_ROWS);
+ new_table.no_rows=1;
+ }
+
/* copy all old rows */
while (!table->file->rnd_next(new_table.record[1]))
{
@@ -3954,9 +4149,12 @@ bool create_myisam_from_heap(TABLE *table, TMP_TABLE_PARAM *param, int error,
}
-/*****************************************************************************
-** Make a join of all tables and write it on socket or to table
-*****************************************************************************/
+/****************************************************************************
+ 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)
@@ -4033,22 +4231,22 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
if (error == -3)
error=0; /* select_limit used */
}
- if (!table) /* If sending data to client */
+
+ /* Return 1 if error is sent; -1 if error should be sent */
+ if (error < 0)
{
- if (error < 0)
- join->result->send_error(0,NullS); /* purecov: inspected */
- else
+ join->result->send_error(0,NullS); /* purecov: inspected */
+ error=1; // Error sent
+ }
+ else
+ {
+ error=0;
+ if (!table) // If sending data to client
{
join_free(join); // Unlock all cursors
if (join->result->send_eof())
- error= -1;
+ error= 1; // Don't send error
}
- }
- else if (error < 0)
- join->result->send_error(0,NullS); /* purecov: inspected */
-
- if (error >= 0)
- {
DBUG_PRINT("info",("%ld records output",join->send_records));
}
if (table)
@@ -4059,15 +4257,15 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
my_errno=tmp;
error= -1;
}
- if (table->file->index_end())
+ if ((tmp=table->file->index_end()))
{
my_errno=tmp;
error= -1;
}
- if (error != old_error)
+ if (error == -1)
table->file->print_error(my_errno,MYF(0));
}
- DBUG_RETURN(error < 0);
+ DBUG_RETURN(error);
}
@@ -4143,10 +4341,8 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
info->file->unlock_row();
}
} while (!(error=info->read_record(info)));
- if (error > 0) // Fatal error
- return -1;
}
- else if (error > 0)
+ if (error > 0) // Fatal error
return -1;
if (!found && on_expr)
@@ -4237,45 +4433,44 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skipp_last)
*****************************************************************************/
static int
-join_read_const_tables(JOIN *join)
+join_read_const_table(JOIN_TAB *tab, POSITION *pos)
{
- uint i;
int error;
- DBUG_ENTER("join_read_const_tables");
- for (i=0 ; i < join->const_tables ; i++)
- {
- TABLE *form=join->table[i];
- form->null_row=0;
- form->status=STATUS_NO_RECORD;
-
- if (join->join_tab[i].type == JT_SYSTEM)
- {
- if ((error=join_read_system(join->join_tab+i)))
- { // Info for DESCRIBE
- join->join_tab[i].info="const row not found";
- join->best_positions[i].records_read=0.0;
- if (!form->outer_join || error > 0)
- DBUG_RETURN(error);
- }
- }
- else
- {
- if ((error=join_read_const(join->join_tab+i)))
- {
- join->join_tab[i].info="unique row not found";
- join->best_positions[i].records_read=0.0;
- if (!form->outer_join || error > 0)
- DBUG_RETURN(error);
- }
+ DBUG_ENTER("join_read_const_table");
+ TABLE *table=tab->table;
+ table->const_table=1;
+ table->null_row=0;
+ table->status=STATUS_NO_RECORD;
+
+ if (tab->type == JT_SYSTEM)
+ {
+ if ((error=join_read_system(tab)))
+ { // Info for DESCRIBE
+ 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)
+ DBUG_RETURN(error);
}
- if (join->join_tab[i].on_expr && !form->null_row)
+ }
+ else
+ {
+ if ((error=join_read_const(tab)))
{
- if ((form->null_row= test(join->join_tab[i].on_expr->val_int() == 0)))
- empty_record(form);
+ 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)
+ DBUG_RETURN(error);
}
- if (!form->null_row)
- form->maybe_null=0;
}
+ if (tab->on_expr && !table->null_row)
+ {
+ if ((table->null_row= test(tab->on_expr->val_int() == 0)))
+ empty_record(table);
+ }
+ if (!table->null_row)
+ table->maybe_null=0;
DBUG_RETURN(0);
}
@@ -4287,7 +4482,8 @@ join_read_system(JOIN_TAB *tab)
int error;
if (table->status & STATUS_GARBAGE) // If first read
{
- if ((error=table->file->rnd_first(table->record[0])))
+ if ((error=table->file->read_first_row(table->record[0],
+ table->primary_key)))
{
if (error != HA_ERR_END_OF_FILE)
{
@@ -4401,6 +4597,35 @@ join_read_always_key(JOIN_TAB *tab)
return 0;
}
+/*
+ This function is used when optimizing away ORDER BY in
+ SELECT * FROM t1 WHERE a=1 ORDER BY a DESC,b DESC
+*/
+
+static int
+join_read_last_key(JOIN_TAB *tab)
+{
+ int error;
+ TABLE *table= tab->table;
+
+ if (cp_buffer_from_ref(&tab->ref))
+ return -1;
+ if ((error=table->file->index_read_last(table->record[0],
+ tab->ref.key_buff,
+ tab->ref.key_length)))
+ {
+ if (error != HA_ERR_KEY_NOT_FOUND)
+ {
+ sql_print_error("read_const: Got error %d when reading table %s",error,
+ table->path);
+ table->file->print_error(error,MYF(0));
+ return 1;
+ }
+ return -1; /* purecov: inspected */
+ }
+ return 0;
+}
+
/* ARGSUSED */
static int
@@ -4411,7 +4636,7 @@ join_no_more_records(READ_RECORD *info __attribute__((unused)))
static int
-join_read_next(READ_RECORD *info)
+join_read_next_same(READ_RECORD *info)
{
int error;
TABLE *table= info->table;
@@ -4434,6 +4659,37 @@ join_read_next(READ_RECORD *info)
return 0;
}
+static int
+join_read_prev_same(READ_RECORD *info)
+{
+ int error;
+ TABLE *table= info->table;
+ JOIN_TAB *tab=table->reginfo.join_tab;
+
+ if ((error=table->file->index_prev(table->record[0])))
+ {
+ if (error != HA_ERR_END_OF_FILE)
+ {
+ sql_print_error("read_next: Got error %d when reading table %s",error,
+ table->path);
+ table->file->print_error(error,MYF(0));
+ error= 1;
+ }
+ else
+ {
+ table->status= STATUS_GARBAGE;
+ error= -1;
+ }
+ }
+ else if (key_cmp(table, tab->ref.key_buff, tab->ref.key,
+ tab->ref.key_length))
+ {
+ table->status=STATUS_NOT_FOUND;
+ error= -1;
+ }
+ return error;
+}
+
static int
join_init_quick_read_record(JOIN_TAB *tab)
@@ -4464,17 +4720,18 @@ join_init_read_record(JOIN_TAB *tab)
}
static int
-join_init_read_first_with_key(JOIN_TAB *tab)
+join_read_first(JOIN_TAB *tab)
{
int error;
TABLE *table=tab->table;
- if (!table->key_read && (table->used_keys & ((key_map) 1 << tab->index)))
+ if (!table->key_read && (table->used_keys & ((key_map) 1 << tab->index)) &&
+ !table->no_keyread)
{
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
}
tab->table->status=0;
- tab->read_record.read_record=join_init_read_next_with_key;
+ tab->read_record.read_record=join_read_next;
tab->read_record.table=table;
tab->read_record.file=table->file;
tab->read_record.index=tab->index;
@@ -4494,8 +4751,9 @@ join_init_read_first_with_key(JOIN_TAB *tab)
return 0;
}
+
static int
-join_init_read_next_with_key(READ_RECORD *info)
+join_read_next(READ_RECORD *info)
{
int error=info->file->index_next(info->record);
if (error)
@@ -4512,9 +4770,8 @@ join_init_read_next_with_key(READ_RECORD *info)
return 0;
}
-
static int
-join_init_read_last_with_key(JOIN_TAB *tab)
+join_read_last(JOIN_TAB *tab)
{
TABLE *table=tab->table;
int error;
@@ -4524,7 +4781,7 @@ join_init_read_last_with_key(JOIN_TAB *tab)
table->file->extra(HA_EXTRA_KEYREAD);
}
tab->table->status=0;
- tab->read_record.read_record=join_init_read_prev_with_key;
+ tab->read_record.read_record=join_read_prev;
tab->read_record.table=table;
tab->read_record.file=table->file;
tab->read_record.index=tab->index;
@@ -4544,8 +4801,9 @@ join_init_read_last_with_key(JOIN_TAB *tab)
return 0;
}
+
static int
-join_init_read_prev_with_key(READ_RECORD *info)
+join_read_prev(READ_RECORD *info)
{
int error=info->file->index_prev(info->record);
if (error)
@@ -4562,13 +4820,14 @@ join_init_read_prev_with_key(READ_RECORD *info)
return 0;
}
+
static int
join_ft_read_first(JOIN_TAB *tab)
{
int error;
TABLE *table= tab->table;
-#if 0
+#if NOT_USED_YET
if (cp_buffer_from_ref(&tab->ref)) // as ft-key doesn't use store_key's
return -1; // see also FT_SELECT::init()
#endif
@@ -4625,14 +4884,35 @@ 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
+ error=0;
if (join->procedure)
error=join->procedure->send_row(*join->fields);
- else
+ else if (join->do_send_rows)
error=join->result->send_data(*join->fields);
if (error)
DBUG_RETURN(-1); /* purecov: inspected */
- if (++join->send_records >= join->thd->select_limit)
+ if (++join->send_records >= join->thd->select_limit && join->do_send_rows)
+ {
+ if (join->select_options & OPTION_FOUND_ROWS)
+ {
+ JOIN_TAB *jt=join->join_tab;
+ if ((join->tables == 1) && !join->tmp_table && !join->sort_and_group
+ && !join->send_group_parts && !join->having && !jt->select_cond &&
+ !(jt->table->file->option_flag() & HA_NOT_EXACT_COUNT))
+ {
+ /* Join over all rows in table; Return number of found rows */
+ join->select_options ^= OPTION_FOUND_ROWS;
+ join->send_records = jt->records;
+ }
+ else
+ {
+ join->do_send_rows=0;
+ join->thd->select_limit = HA_POS_ERROR;
+ DBUG_RETURN(0);
+ }
+ }
DBUG_RETURN(-3); // Abort nicely
+ }
}
else
{
@@ -4663,9 +4943,10 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
int error;
if (join->procedure)
{
+ error=0;
if (join->having && join->having->val_int() == 0)
error= -1; // Didn't satisfy having
- else
+ else if (join->do_send_rows)
error=join->procedure->send_row(*join->fields) ? 1 : 0;
if (end_of_records && join->procedure->end_of_records())
error= 1; // Fatal error
@@ -4687,8 +4968,14 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
DBUG_RETURN(-1); /* purecov: inspected */
if (end_of_records)
DBUG_RETURN(0);
- if (!error && ++join->send_records >= join->thd->select_limit)
- DBUG_RETURN(-3); /* Abort nicely */
+ if (!error && ++join->send_records >= join->thd->select_limit &&
+ join->do_send_rows)
+ {
+ if (!(join->select_options & OPTION_FOUND_ROWS))
+ DBUG_RETURN(-3); // Abort nicely
+ join->do_send_rows=0;
+ join->thd->select_limit = HA_POS_ERROR;
+ }
}
}
else
@@ -4734,6 +5021,7 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
copy_fields(&join->tmp_table_param);
copy_funcs(join->tmp_table_param.funcs);
+#ifdef TO_BE_DELETED
if (!table->uniques) // If not unique handling
{
/* Copy null values from group to row */
@@ -4744,10 +5032,11 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (item->maybe_null)
{
Field *field=item->tmp_table_field();
- field->ptr[-1]= (byte) (field->is_null() ? 0 : 1);
+ field->ptr[-1]= (byte) (field->is_null() ? 1 : 0);
}
}
}
+#endif
if (!join->having || join->having->val_int())
{
join->found_records++;
@@ -4759,8 +5048,15 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (create_myisam_from_heap(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
- if (++join->send_records >= join->tmp_table_param.end_write_records)
+ }
+ 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);
+ join->do_send_rows=0;
+ join->thd->select_limit = HA_POS_ERROR;
+ DBUG_RETURN(0);
}
}
}
@@ -4795,8 +5091,9 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{
Item *item= *group->item;
item->save_org_in_field(group->field);
+ /* Store in the used key if the field was 0 */
if (item->maybe_null)
- group->buff[0]=item->null_value ? 0: 1; // Save reversed value
+ group->buff[-1]=item->null_value ? 1 : 0;
}
// table->file->index_init(0);
if (!table->file->index_read(table->record[1],
@@ -4955,7 +5252,7 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
/*****************************************************************************
** Remove calculation with tables that aren't yet read. Remove also tests
-** against fields that are read through key where the table is not a
+** against fields that are read through key where the table is not a
** outer join table.
** We can't remove tests that are made against columns which are stored
** in sorted order.
@@ -4974,8 +5271,7 @@ static bool test_if_ref(Item_field *left_item,Item *right_item)
{
if (right_item->type() == Item::FIELD_ITEM)
return (field->eq_def(((Item_field *) right_item)->field));
- if (right_item->const_item() &&
- (right_item->val_int() || !right_item->null_value))
+ if (right_item->const_item() && !(right_item->is_null()))
{
// We can remove binary fields and numerical fields except float,
// as float comparison isn't 100 % secure
@@ -5096,9 +5392,11 @@ part_of_refkey(TABLE *table,Field *field)
** Returns: 1 if key is ok.
** 0 if key can't be used
** -1 if reverse key can be used
+** used_key_parts is set to key parts used if length != 0
*****************************************************************************/
-static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx)
+static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
+ uint *used_key_parts)
{
KEY_PART_INFO *key_part,*key_part_end;
key_part=table->key_info[idx].key_part;
@@ -5130,6 +5428,7 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx)
reverse=flag; // Remember if reverse
key_part++;
}
+ *used_key_parts= (uint) (key_part - table->key_info[idx].key_part);
return reverse;
}
@@ -5152,17 +5451,20 @@ static uint find_shortest_key(TABLE *table, key_map usable_keys)
}
-/*****************************************************************************
-** If not selecting by given key, create a index how records should be read
-** return: 0 ok
-** -1 some fatal error
-** 1 no records
-*****************************************************************************/
+/*
+ Test if we can skip the ORDER BY by using an index.
+
+ If we can use an index, the JOIN_TAB / tab->select struct
+ is changed to use the index.
-/* Return 1 if we don't have to do file sorting */
+ Return:
+ 0 We have to use filesort to do the sorting
+ 1 We can use an index.
+*/
static bool
-test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit)
+test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
+ bool no_changes)
{
int ref_key;
TABLE *table=tab->table;
@@ -5190,10 +5492,55 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit)
if (ref_key >= 0)
{
+ /*
+ We come here when there is a REF key.
+ */
+ int order_direction;
+ uint used_key_parts;
/* Check if we get the rows in requested sorted order by using the key */
if ((usable_keys & ((key_map) 1 << ref_key)) &&
- test_if_order_by_key(order,table,ref_key) == 1)
+ (order_direction = test_if_order_by_key(order,table,ref_key,
+ &used_key_parts)))
+ {
+ if (order_direction == -1) // If ORDER BY ... DESC
+ {
+ if (select && select->quick)
+ {
+ /*
+ Don't reverse the sort order, if it's already done.
+ (In some cases test_if_order_by_key() can be called multiple times
+ */
+ if (!select->quick->reverse_sorted())
+ {
+ // ORDER BY range_key DESC
+ QUICK_SELECT_DESC *tmp=new QUICK_SELECT_DESC(select->quick,
+ used_key_parts);
+ if (!tmp || tmp->error)
+ {
+ delete tmp;
+ DBUG_RETURN(0); // Reverse sort not supported
+ }
+ select->quick=tmp;
+ }
+ DBUG_RETURN(1);
+ }
+ if (tab->ref.key_parts < used_key_parts)
+ {
+ /*
+ SELECT * FROM t1 WHERE a=1 ORDER BY a DESC,b DESC
+
+ Use a traversal function that starts by reading the last row
+ with key part (A) and then traverse the index backwards.
+ */
+ if (table->file->option_flag() & HA_NOT_READ_PREFIX_LAST)
+ DBUG_RETURN(1);
+ tab->read_first_record= join_read_last_key;
+ tab->read_record.read_record= join_read_prev_same;
+ /* fall through */
+ }
+ }
DBUG_RETURN(1); /* No need to sort */
+ }
}
else
{
@@ -5212,20 +5559,24 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit)
for (nr=0; keys ; keys>>=1, nr++)
{
+ uint not_used;
if (keys & 1)
{
int flag;
- if ((flag=test_if_order_by_key(order,table,nr)))
+ if ((flag=test_if_order_by_key(order, table, nr, &not_used)))
{
- tab->index=nr;
- tab->read_first_record= (flag > 0 ? join_init_read_first_with_key:
- join_init_read_last_with_key);
- table->file->index_init(nr);
- tab->type=JT_NEXT; // Read with index_first(), index_next()
- if (table->used_keys & ((key_map) 1 << nr))
+ if (!no_changes)
{
- table->key_read=1;
- table->file->extra(HA_EXTRA_KEYREAD);
+ tab->index=nr;
+ tab->read_first_record= (flag > 0 ? join_read_first:
+ join_read_last);
+ table->file->index_init(nr);
+ tab->type=JT_NEXT; // Read with index_first(), index_next()
+ if (table->used_keys & ((key_map) 1 << nr))
+ {
+ table->key_read=1;
+ table->file->extra(HA_EXTRA_KEYREAD);
+ }
}
DBUG_RETURN(1);
}
@@ -5235,6 +5586,14 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit)
DBUG_RETURN(0); // Can't use index.
}
+
+/*****************************************************************************
+ If not selecting by given key, create an index how records should be read
+ return: 0 ok
+ -1 some fatal error
+ 1 no records
+*****************************************************************************/
+
static int
create_sort_index(JOIN_TAB *tab,ORDER *order,ha_rows select_limit)
{
@@ -5245,7 +5604,7 @@ create_sort_index(JOIN_TAB *tab,ORDER *order,ha_rows select_limit)
SQL_SELECT *select=tab->select;
DBUG_ENTER("create_sort_index");
- if (test_if_skip_sort_order(tab,order,select_limit))
+ if (test_if_skip_sort_order(tab,order,select_limit,0))
DBUG_RETURN(0);
if (!(sortorder=make_unireg_sortorder(order,&length)))
goto err; /* purecov: inspected */
@@ -5278,8 +5637,11 @@ create_sort_index(JOIN_TAB *tab,ORDER *order,ha_rows select_limit)
goto err;
}
}
- table->found_records=filesort(&table,sortorder,length,
+ if (table->tmp_table)
+ table->file->info(HA_STATUS_VARIABLE); // Get record count
+ table->found_records=filesort(table,sortorder,length,
select, 0L, select_limit, &examined_rows);
+ tab->records=table->found_records; // For SQL_CALC_ROWS
delete select; // filesort did select
tab->select=0;
tab->select_cond=0;
@@ -5296,11 +5658,11 @@ err:
DBUG_RETURN(-1);
}
-
/*
** Add the HAVING criteria to table->select
*/
+#ifdef NOT_YET
static bool fix_having(JOIN *join, Item **having)
{
(*having)->update_used_tables(); // Some tables may have been const
@@ -5328,6 +5690,7 @@ static bool fix_having(JOIN *join, Item **having)
}
return 0;
}
+#endif
/*****************************************************************************
@@ -5378,7 +5741,6 @@ remove_duplicates(JOIN *join, TABLE *entry,List<Item> &fields, Item *having)
DBUG_ENTER("remove_duplicates");
entry->reginfo.lock_type=TL_WRITE;
- entry->file->extra(HA_EXTRA_NO_READCHECK);
/* Calculate how many saved fields there is in list */
field_count=0;
@@ -5564,7 +5926,7 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
if ((error=file->delete_row(record)))
goto err;
continue;
- }
+ }
/* copy fields to key buffer */
field_length=field_lengths;
@@ -6104,7 +6466,7 @@ count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields,
List_iterator<Item> li(fields);
Item *field;
- param->field_count=param->sum_func_count=param->func_count=
+ param->field_count=param->sum_func_count=param->func_count=
param->hidden_field_count=0;
param->quick_group=1;
while ((field=li++))
@@ -6198,7 +6560,8 @@ get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables)
static void
calc_group_buffer(JOIN *join,ORDER *group)
{
- uint key_length=0,parts=0;
+ uint key_length=0, parts=0, null_parts=0;
+
if (group)
join->group= 1;
for (; group ; group=group->next)
@@ -6219,10 +6582,11 @@ calc_group_buffer(JOIN *join,ORDER *group)
key_length+=(*group->item)->max_length;
parts++;
if ((*group->item)->maybe_null)
- key_length++;
+ null_parts++;
}
- join->tmp_table_param.group_length=key_length;
+ join->tmp_table_param.group_length=key_length+null_parts;
join->tmp_table_param.group_parts=parts;
+ join->tmp_table_param.group_null_parts=null_parts;
}
@@ -6273,7 +6637,7 @@ test_if_group_changed(List<Item_buff> &list)
*/
bool
-setup_copy_fields(TMP_TABLE_PARAM *param,List<Item> &fields)
+setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields)
{
Item *pos;
List_iterator<Item> li(fields);
@@ -6281,7 +6645,7 @@ setup_copy_fields(TMP_TABLE_PARAM *param,List<Item> &fields)
DBUG_ENTER("setup_copy_fields");
if (!(copy=param->copy_field= new Copy_field[param->field_count]))
- goto err;
+ goto err2;
param->copy_funcs.empty();
while ((pos=li++))
@@ -6301,7 +6665,7 @@ setup_copy_fields(TMP_TABLE_PARAM *param,List<Item> &fields)
/* set up save buffer and change result_field to point at saved value */
Field *field= item->field;
- item->result_field=field->new_field(field->table);
+ item->result_field=field->new_field(&thd->mem_root,field->table);
char *tmp=(char*) sql_alloc(field->pack_length()+1);
if (!tmp)
goto err;
@@ -6326,12 +6690,13 @@ setup_copy_fields(TMP_TABLE_PARAM *param,List<Item> &fields)
goto err;
}
}
- param->copy_field_count= (uint) (copy - param->copy_field);
+ param->copy_field_end= copy;
DBUG_RETURN(0);
err:
- delete [] param->copy_field;
+ delete [] param->copy_field; // This is never 0
param->copy_field=0;
+err2:
DBUG_RETURN(TRUE);
}
@@ -6344,17 +6709,16 @@ void
copy_fields(TMP_TABLE_PARAM *param)
{
Copy_field *ptr=param->copy_field;
- Copy_field *end=ptr+param->copy_field_count;
+ Copy_field *end=param->copy_field_end;
for ( ; ptr != end; ptr++)
(*ptr->do_copy)(ptr);
- List_iterator<Item> it(param->copy_funcs);
+ List_iterator_fast<Item> &it=param->copy_funcs_it;
+ it.rewind();
Item_copy_string *item;
while ((item = (Item_copy_string*) it++))
- {
item->copy();
- }
}
@@ -6612,163 +6976,191 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab)
****************************************************************************/
static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
- bool distinct)
+ bool distinct,const char *message)
{
List<Item> field_list;
Item *item;
+ List<Item> item_list;
THD *thd=join->thd;
+ MYSQL_LOCK *save_lock;
+ SELECT_LEX *select_lex = &(join->thd->lex.select_lex);
+ select_result *result=join->result;
DBUG_ENTER("select_describe");
/* Don't log this into the slow query log */
- join->thd->lex.options&= ~(QUERY_NO_INDEX_USED | QUERY_NO_GOOD_INDEX_USED);
- field_list.push_back(new Item_empty_string("table",NAME_LEN));
- field_list.push_back(new Item_empty_string("type",10));
- field_list.push_back(item=new Item_empty_string("possible_keys",
+ select_lex->options&= ~(QUERY_NO_INDEX_USED | QUERY_NO_GOOD_INDEX_USED);
+ if (thd->lex.select == select_lex)
+ {
+ field_list.push_back(new Item_empty_string("table",NAME_LEN));
+ field_list.push_back(new Item_empty_string("type",10));
+ field_list.push_back(item=new Item_empty_string("possible_keys",
NAME_LEN*MAX_KEY));
- item->maybe_null=1;
- field_list.push_back(item=new Item_empty_string("key",NAME_LEN));
- item->maybe_null=1;
- field_list.push_back(item=new Item_int("key_len",0,3));
- item->maybe_null=1;
- field_list.push_back(item=new Item_empty_string("ref",
- NAME_LEN*MAX_REF_PARTS));
- item->maybe_null=1;
- field_list.push_back(new Item_real("rows",0.0,0,10));
- field_list.push_back(new Item_empty_string("Extra",255));
- if (send_fields(thd,field_list,1))
- return; /* purecov: inspected */
+ item->maybe_null=1;
+ field_list.push_back(item=new Item_empty_string("key",NAME_LEN));
+ item->maybe_null=1;
+ field_list.push_back(item=new Item_int("key_len",0,3));
+ item->maybe_null=1;
+ field_list.push_back(item=new Item_empty_string("ref",
+ NAME_LEN*MAX_REF_PARTS));
+ item->maybe_null=1;
+ field_list.push_back(new Item_real("rows",0.0,0,10));
+ field_list.push_back(new Item_empty_string("Extra",255));
+ if (result->send_fields(field_list,1))
+ return;
+ }
- char buff[512],*buff_ptr;
- String tmp(buff,sizeof(buff)),*packet= &thd->packet;
- table_map used_tables=0;
- for (uint i=0 ; i < join->tables ; i++)
+ if (message)
{
- JOIN_TAB *tab=join->join_tab+i;
- TABLE *table=tab->table;
-
- if (tab->type == JT_ALL && tab->select && tab->select->quick)
- tab->type= JT_RANGE;
- packet->length(0);
- net_store_data(packet,table->table_name);
- net_store_data(packet,join_type_str[tab->type]);
- tmp.length(0);
- key_map bits;
- uint j;
- for (j=0,bits=tab->keys ; bits ; j++,bits>>=1)
- {
- if (bits & 1)
+ item_list.push_back(new Item_empty_string("",0));
+ item_list.push_back(new Item_empty_string("",0));
+ item_list.push_back(new Item_empty_string("",0));
+ item_list.push_back(new Item_empty_string("",0));
+ item_list.push_back(new Item_empty_string("",0));
+ item_list.push_back(new Item_empty_string("",0));
+ item_list.push_back(new Item_empty_string("",0));
+ item_list.push_back(new Item_string(message,strlen(message)));
+ if (result->send_data(item_list))
+ result->send_error(0,NullS);
+ }
+ else
+ {
+ table_map used_tables=0;
+ for (uint i=0 ; i < join->tables ; i++)
+ {
+ JOIN_TAB *tab=join->join_tab+i;
+ TABLE *table=tab->table;
+ char buff[512],*buff_ptr=buff;
+ char buff1[512], buff2[512], bufff[512];
+ String tmp1(buff1,sizeof(buff1));
+ String tmp2(buff2,sizeof(buff2));
+ item_list.empty();
+ if (tab->type == JT_ALL && tab->select && tab->select->quick)
+ tab->type= JT_RANGE;
+ item_list.push_back(new Item_string(table->table_name,strlen(table->table_name)));
+ item_list.push_back(new Item_string(join_type_str[tab->type],strlen(join_type_str[tab->type])));
+ tmp1.length(0); tmp2.length(0);
+ key_map bits;
+ uint j;
+ for (j=0,bits=tab->keys ; bits ; j++,bits>>=1)
{
- if (tmp.length())
- tmp.append(',');
- tmp.append(table->key_info[j].name);
+ if (bits & 1)
+ {
+ if (tmp1.length())
+ tmp1.append(',');
+ tmp1.append(table->key_info[j].name);
+ }
}
- }
- if (tmp.length())
- net_store_data(packet,tmp.ptr(),tmp.length());
- else
- net_store_null(packet);
- if (tab->ref.key_parts)
- {
- net_store_data(packet,table->key_info[tab->ref.key].name);
- net_store_data(packet,(uint32) tab->ref.key_length);
- tmp.length(0);
- for (store_key **ref=tab->ref.key_copy ; *ref ; ref++)
+ if (tmp1.length())
+ item_list.push_back(new Item_string(tmp1.ptr(),tmp1.length()));
+ else
+ item_list.push_back(new Item_null());
+ if (tab->ref.key_parts)
{
- if (tmp.length())
- tmp.append(',');
- tmp.append((*ref)->name());
+ item_list.push_back(new Item_string(table->key_info[tab->ref.key].name,
+ strlen(table->key_info[tab->ref.key].name)));
+ item_list.push_back(new Item_int((int32) tab->ref.key_length));
+ for (store_key **ref=tab->ref.key_copy ; *ref ; ref++)
+ {
+ if (tmp2.length())
+ tmp2.append(',');
+ tmp2.append((*ref)->name());
+ }
+ item_list.push_back(new Item_string(tmp2.ptr(),tmp2.length()));
}
- net_store_data(packet,tmp.ptr(),tmp.length());
- }
- else if (tab->type == JT_NEXT)
- {
- net_store_data(packet,table->key_info[tab->index].name);
- net_store_data(packet,(uint32) table->key_info[tab->index].key_length);
- net_store_null(packet);
- }
- else if (tab->select && tab->select->quick)
- {
- net_store_data(packet,table->key_info[tab->select->quick->index].name);;
- net_store_data(packet,(uint32) tab->select->quick->max_used_key_length);
- net_store_null(packet);
- }
- else
- {
- net_store_null(packet);
- net_store_null(packet);
- net_store_null(packet);
- }
- sprintf(buff,"%.0f",join->best_positions[i].records_read);
- net_store_data(packet,buff);
- my_bool key_read=table->key_read;
- if (tab->type == JT_NEXT &&
- ((table->used_keys & ((key_map) 1 << tab->index))))
- key_read=1;
-
- buff_ptr=buff;
- if (tab->info)
- net_store_data(packet,tab->info);
- else if (tab->select)
- {
- if (tab->use_quick == 2)
+ else if (tab->type == JT_NEXT)
{
- sprintf(buff_ptr,"range checked for each record (index map: %u)",
- tab->keys);
- buff_ptr=strend(buff_ptr);
+ item_list.push_back(new Item_string(table->key_info[tab->index].name,strlen(table->key_info[tab->index].name)));
+ item_list.push_back(new Item_int((int32) table->key_info[tab->index].key_length));
+ item_list.push_back(new Item_null());
+ }
+ else if (tab->select && tab->select->quick)
+ {
+ item_list.push_back(new Item_string(table->key_info[tab->select->quick->index].name,strlen(table->key_info[tab->select->quick->index].name)));
+ item_list.push_back(new Item_int((int32) tab->select->quick->max_used_key_length));
+ item_list.push_back(new Item_null());
}
else
- buff_ptr=strmov(buff_ptr,"where used");
- }
- if (key_read)
- {
- if (buff != buff_ptr)
{
- buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
+ item_list.push_back(new Item_null());
+ item_list.push_back(new Item_null());
+ item_list.push_back(new Item_null());
}
- buff_ptr=strmov(buff_ptr,"Using index");
- }
- if (table->reginfo.not_exists_optimize)
- {
- if (buff != buff_ptr)
+ sprintf(bufff,"%.0f",join->best_positions[i].records_read);
+ item_list.push_back(new Item_string(bufff,strlen(bufff)));
+ my_bool key_read=table->key_read;
+ if (tab->type == JT_NEXT &&
+ ((table->used_keys & ((key_map) 1 << tab->index))))
+ key_read=1;
+
+ if (tab->info)
+ item_list.push_back(new Item_string(tab->info,strlen(tab->info)));
+ else if (tab->select)
{
- buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
+ if (tab->use_quick == 2)
+ {
+ sprintf(buff_ptr,"range checked for each record (index map: %u)",
+ tab->keys);
+ buff_ptr=strend(buff_ptr);
+ }
+ else
+ buff_ptr=strmov(buff_ptr,"where used");
}
- buff_ptr=strmov(buff_ptr,"Not exists");
- }
- if (need_tmp_table)
- {
- need_tmp_table=0;
- if (buff != buff_ptr)
+ if (key_read)
{
- buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
+ if (buff != buff_ptr)
+ {
+ buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
+ }
+ buff_ptr=strmov(buff_ptr,"Using index");
}
- buff_ptr=strmov(buff_ptr,"Using temporary");
- }
- if (need_order)
- {
- need_order=0;
- if (buff != buff_ptr)
+ if (table->reginfo.not_exists_optimize)
{
- buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
+ if (buff != buff_ptr)
+ {
+ buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
+ }
+ buff_ptr=strmov(buff_ptr,"Not exists");
}
- buff_ptr=strmov(buff_ptr,"Using filesort");
- }
- if (distinct & test_all_bits(used_tables,thd->used_tables))
- {
- if (buff != buff_ptr)
+ if (need_tmp_table)
{
- buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
+ need_tmp_table=0;
+ if (buff != buff_ptr)
+ {
+ buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
+ }
+ buff_ptr=strmov(buff_ptr,"Using temporary");
}
- buff_ptr=strmov(buff_ptr,"Distinct");
+ if (need_order)
+ {
+ need_order=0;
+ if (buff != buff_ptr)
+ {
+ buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
+ }
+ buff_ptr=strmov(buff_ptr,"Using filesort");
+ }
+ if (distinct & test_all_bits(used_tables,thd->used_tables))
+ {
+ if (buff != buff_ptr)
+ {
+ buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
+ }
+ buff_ptr=strmov(buff_ptr,"Distinct");
+ }
+ item_list.push_back(new Item_string(buff,(uint) (buff_ptr - buff)));
+ // For next iteration
+ used_tables|=table->map;
+ if (result->send_data(item_list))
+ result->send_error(0,NullS);
}
- net_store_data(packet,buff,(uint) (buff_ptr - buff));
- if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
- DBUG_VOID_RETURN; /* purecov: inspected */
-
- // For next iteration
- used_tables|=table->map;
}
- send_eof(&thd->net);
+ if (!join->thd->lex.select->next)
+ {
+ save_lock=thd->lock;
+ thd->lock=(MYSQL_LOCK *)0;
+ result->send_eof();
+ thd->lock=save_lock;
+ }
DBUG_VOID_RETURN;
}
@@ -6779,7 +7171,7 @@ static void describe_info(THD *thd, const char *info)
String *packet= &thd->packet;
/* Don't log this into the slow query log */
- thd->lex.options&= ~(QUERY_NO_INDEX_USED | QUERY_NO_GOOD_INDEX_USED);
+ thd->lex.select_lex.options&= ~(QUERY_NO_INDEX_USED | QUERY_NO_GOOD_INDEX_USED);
field_list.push_back(new Item_empty_string("Comment",80));
if (send_fields(thd,field_list,1))
return; /* purecov: inspected */
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 1bf7d7863eb..befa1efde53 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.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 */
@@ -118,19 +118,22 @@ typedef struct st_position { /* Used in find_best */
class TMP_TABLE_PARAM {
public:
List<Item> copy_funcs;
- Copy_field *copy_field;
+ List_iterator_fast<Item> copy_funcs_it;
+ Copy_field *copy_field, *copy_field_end;
byte *group_buff;
Item_result_field **funcs;
MI_COLUMNDEF *recinfo,*start_recinfo;
KEY *keyinfo;
ha_rows end_write_records;
- uint copy_field_count,field_count,sum_func_count,func_count;
+ uint field_count,sum_func_count,func_count;
uint hidden_field_count;
- uint group_parts,group_length;
+ uint group_parts,group_length,group_null_parts;
uint quick_group;
bool using_indirect_summary_function;
- TMP_TABLE_PARAM() :copy_field(0), group_parts(0), group_length(0)
+ TMP_TABLE_PARAM()
+ :copy_funcs_it(copy_funcs), copy_field(0), group_parts(0),
+ group_length(0), group_null_parts(0)
{}
~TMP_TABLE_PARAM()
{
@@ -154,7 +157,8 @@ class JOIN {
uint tables,const_tables;
uint send_group_parts;
bool sort_and_group,first_record,full_join,group, no_field_update;
- table_map const_table_map,outer_join;
+ bool do_send_rows;
+ table_map const_table_map,found_const_table_map,outer_join;
ha_rows send_records,found_records,examined_rows,row_limit;
POSITION positions[MAX_TABLES+1],best_positions[MAX_TABLES+1];
double best_read;
@@ -183,11 +187,11 @@ void TEST_join(JOIN *join);
bool store_val_in_field(Field *field,Item *val);
TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
ORDER *group, bool distinct, bool save_sum_fields,
- bool allow_distinct_limit, uint select_options);
+ bool allow_distinct_limit, ulong select_options);
void free_tmp_table(THD *thd, TABLE *entry);
void count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields,
bool reset_with_sum_func);
-bool setup_copy_fields(TMP_TABLE_PARAM *param,List<Item> &fields);
+bool setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,List<Item> &fields);
void copy_fields(TMP_TABLE_PARAM *param);
void copy_funcs(Item_result_field **func_ptr);
bool create_myisam_from_heap(TABLE *table, TMP_TABLE_PARAM *param, int error,
@@ -207,7 +211,7 @@ class store_key :public Sql_alloc
char *null_ptr;
char err;
public:
- store_key(Field *field_arg, char *ptr, char *null, uint length)
+ store_key(THD *thd, Field *field_arg, char *ptr, char *null, uint length)
:null_ptr(null),err(0)
{
if (field_arg->type() == FIELD_TYPE_BLOB)
@@ -216,7 +220,7 @@ class store_key :public Sql_alloc
field_arg->table, field_arg->binary());
else
{
- to_field=field_arg->new_field(field_arg->table);
+ to_field=field_arg->new_field(&thd->mem_root,field_arg->table);
if (to_field)
to_field->move_field(ptr, (uchar*) null, 1);
}
@@ -232,9 +236,9 @@ class store_key_field: public store_key
Copy_field copy_field;
const char *field_name;
public:
- store_key_field(Field *to_field_arg, char *ptr, char *null_ptr_arg,
+ store_key_field(THD *thd, Field *to_field_arg, char *ptr, char *null_ptr_arg,
uint length, Field *from_field, const char *name_arg)
- :store_key(to_field_arg,ptr,
+ :store_key(thd, to_field_arg,ptr,
null_ptr_arg ? null_ptr_arg : from_field->maybe_null() ? &err
: NullS,length), field_name(name_arg)
{
@@ -257,9 +261,9 @@ class store_key_item :public store_key
protected:
Item *item;
public:
- store_key_item(Field *to_field_arg, char *ptr, char *null_ptr_arg,
+ store_key_item(THD *thd, Field *to_field_arg, char *ptr, char *null_ptr_arg,
uint length, Item *item_arg)
- :store_key(to_field_arg,ptr,
+ :store_key(thd, to_field_arg,ptr,
null_ptr_arg ? null_ptr_arg : item_arg->maybe_null ?
&err : NullS, length), item(item_arg)
{}
@@ -276,10 +280,10 @@ class store_key_const_item :public store_key_item
{
bool inited;
public:
- store_key_const_item(Field *to_field_arg, char *ptr,
+ store_key_const_item(THD *thd, Field *to_field_arg, char *ptr,
char *null_ptr_arg, uint length,
Item *item_arg)
- :store_key_item(to_field_arg,ptr,
+ :store_key_item(thd, to_field_arg,ptr,
null_ptr_arg ? null_ptr_arg : item_arg->maybe_null ?
&err : NullS, length, item_arg), inited(0)
{
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 018b43b11c8..08c17c2e25d 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 "sql_acl.h"
+#include "repl_failsafe.h"
#include <my_dir.h>
#ifdef HAVE_BERKELEY_DB
@@ -45,6 +46,8 @@ store_create_info(THD *thd, TABLE *table, String *packet);
static void
append_identifier(THD *thd, String *packet, const char *name);
+extern struct st_VioSSLAcceptorFd * ssl_acceptor_fd;
+
/****************************************************************************
** Send list of databases
** A database is a directory in the mysql_data_home directory
@@ -72,7 +75,7 @@ mysqld_show_dbs(THD *thd,const char *wild)
DBUG_RETURN(1);
if (mysql_find_files(thd,&files,NullS,mysql_data_home,wild,1))
DBUG_RETURN(1);
- List_iterator<char> it(files);
+ List_iterator_fast<char> it(files);
while ((file_name=it++))
{
if (!opt_safe_show_db || thd->master_access ||
@@ -81,7 +84,7 @@ mysqld_show_dbs(THD *thd,const char *wild)
(grant_option && !check_grant_db(thd, file_name)))
{
thd->packet.length(0);
- net_store_data(&thd->packet,file_name);
+ net_store_data(&thd->packet, thd->convert_set, file_name);
if (my_net_write(&thd->net, (char*) thd->packet.ptr(),
thd->packet.length()))
DBUG_RETURN(-1);
@@ -95,34 +98,31 @@ mysqld_show_dbs(THD *thd,const char *wild)
** List all open tables in a database
***************************************************************************/
-int mysqld_show_open_tables(THD *thd,const char *db,const char *wild)
+int mysqld_show_open_tables(THD *thd,const char *wild)
{
- Item_string *field=new Item_string("",0);
List<Item> field_list;
- char *end,*table_name;
- List<char> tables;
+ OPEN_TABLE_LIST *open_list;
+ CONVERT *convert=thd->convert_set;
DBUG_ENTER("mysqld_show_open_tables");
- field->name=(char*) thd->alloc(20+(uint) strlen(db)+(wild ? (uint) strlen(wild)+4:0));
- end=strxmov(field->name,"Open_tables_in_",db,NullS);
- if (wild && wild[0])
- strxmov(end," (",wild,")",NullS);
- field->max_length=NAME_LEN;
- field_list.push_back(field);
- field_list.push_back(new Item_empty_string("Comment",80));
+ 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_int("In_use",0, 4));
+ field_list.push_back(new Item_int("Name_locked",0, 4));
if (send_fields(thd,field_list,1))
DBUG_RETURN(1);
- if (list_open_tables(thd,&tables,db,wild))
+ if (!(open_list=list_open_tables(thd,wild)) && thd->fatal_error)
DBUG_RETURN(-1);
- List_iterator<char> it(tables);
- while ((table_name=it++))
+ for ( ; open_list ; open_list=open_list->next)
{
thd->packet.length(0);
- net_store_data(&thd->packet,table_name);
- net_store_data(&thd->packet,query_table_status(thd,db,table_name));
+ net_store_data(&thd->packet,convert, open_list->db);
+ net_store_data(&thd->packet,convert, open_list->table);
+ net_store_data(&thd->packet,open_list->in_use);
+ net_store_data(&thd->packet,open_list->locked);
if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length()))
DBUG_RETURN(-1);
}
@@ -157,11 +157,11 @@ int mysqld_show_tables(THD *thd,const char *db,const char *wild)
DBUG_RETURN(1);
if (mysql_find_files(thd,&files,db,path,wild,0))
DBUG_RETURN(-1);
- List_iterator<char> it(files);
+ List_iterator_fast<char> it(files);
while ((file_name=it++))
{
thd->packet.length(0);
- net_store_data(&thd->packet,file_name);
+ net_store_data(&thd->packet, thd->convert_set, file_name);
if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length()))
DBUG_RETURN(-1);
}
@@ -257,6 +257,7 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
char *file_name;
TABLE *table;
String *packet= &thd->packet;
+ CONVERT *convert=thd->convert_set;
DBUG_ENTER("mysqld_extend_show_tables");
(void) sprintf(path,"%s/%s",mysql_data_home,db);
@@ -296,20 +297,20 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
if (mysql_find_files(thd,&files,db,path,wild,0))
DBUG_RETURN(-1);
- List_iterator<char> it(files);
+ List_iterator_fast<char> it(files);
while ((file_name=it++))
{
TABLE_LIST table_list;
bzero((char*) &table_list,sizeof(table_list));
packet->length(0);
- net_store_data(packet,file_name);
+ net_store_data(packet,convert, file_name);
table_list.db=(char*) db;
table_list.real_name=table_list.name=file_name;
if (!(table = open_ltable(thd, &table_list, TL_READ)))
{
for (uint i=0 ; i < field_list.elements ; i++)
net_store_null(packet);
- net_store_data(packet,thd->net.last_error);
+ net_store_data(packet,convert, thd->net.last_error);
thd->net.last_error[0]=0;
}
else
@@ -317,8 +318,8 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
struct tm tm_tmp;
handler *file=table->file;
file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_NO_LOCK);
- net_store_data(packet, file->table_type());
- net_store_data(packet,
+ net_store_data(packet, convert, file->table_type());
+ net_store_data(packet, convert,
(table->db_options_in_use & HA_OPTION_PACK_RECORD) ?
"Dynamic" :
(table->db_options_in_use & HA_OPTION_COMPRESS_RECORD)
@@ -399,7 +400,7 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
my_raid_type(file->raid_type), file->raid_chunks, file->raid_chunksize/RAID_BLOCK_SIZE);
ptr=strmov(ptr,buff);
}
- net_store_data(packet, option_buff+1,
+ net_store_data(packet, convert, option_buff+1,
(ptr == option_buff ? 0 : (uint) (ptr-option_buff)-1));
}
{
@@ -431,6 +432,7 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
TABLE *table;
handler *file;
char tmp[MAX_FIELD_WIDTH];
+ CONVERT *convert=thd->convert_set;
DBUG_ENTER("mysqld_show_fields");
DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
table_list->real_name));
@@ -485,18 +487,18 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
bool null_default_value=0;
packet->length(0);
- net_store_data(packet,field->field_name);
+ net_store_data(packet,convert,field->field_name);
field->sql_type(type);
- net_store_data(packet,type.ptr(),type.length());
+ net_store_data(packet,convert,type.ptr(),type.length());
pos=(byte*) ((flags & NOT_NULL_FLAG) &&
field->type() != FIELD_TYPE_TIMESTAMP ?
"" : "YES");
- net_store_data(packet,(const char*) pos);
+ net_store_data(packet,convert,(const char*) pos);
pos=(byte*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
(field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
(field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
- net_store_data(packet,(char*) pos);
+ net_store_data(packet,convert,(char*) pos);
if (field->type() == FIELD_TYPE_TIMESTAMP ||
field->unireg_check == Field::NEXT_NUMBER)
@@ -505,17 +507,17 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
{ // Not null by default
type.set(tmp,sizeof(tmp));
field->val_str(&type,&type);
- net_store_data(packet,type.ptr(),type.length());
+ net_store_data(packet,convert,type.ptr(),type.length());
}
else if (field->maybe_null() || null_default_value)
net_store_null(packet); // Null as default
else
- net_store_data(packet,tmp,0);
+ net_store_data(packet,convert,tmp,0);
char *end=tmp;
if (field->unireg_check == Field::NEXT_NUMBER)
end=strmov(tmp,"auto_increment");
- net_store_data(packet,tmp,(uint) (end-tmp));
+ net_store_data(packet,convert,tmp,(uint) (end-tmp));
if (verbose)
{
@@ -530,7 +532,7 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
end=strmov(end,grant_types.type_names[bitnr]);
}
}
- net_store_data(packet,tmp+1,end == tmp ? 0 : (uint) (end-tmp-1));
+ net_store_data(packet,convert, tmp+1,end == tmp ? 0 : (uint) (end-tmp-1));
}
if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
DBUG_RETURN(1);
@@ -545,6 +547,7 @@ int
mysqld_show_create(THD *thd, TABLE_LIST *table_list)
{
TABLE *table;
+ CONVERT *convert=thd->convert_set;
DBUG_ENTER("mysqld_show_create");
DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
table_list->real_name));
@@ -566,7 +569,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
String *packet = &thd->packet;
{
packet->length(0);
- net_store_data(packet, table->table_name);
+ net_store_data(packet,convert, table->table_name);
// a hack - we need to reserve some space for the length before
// we know what it is - let's assume that the length of create table
// statement will fit into 3 bytes ( 16 MB max :-) )
@@ -623,6 +626,7 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
{
TABLE *table;
char buff[256];
+ CONVERT *convert=thd->convert_set;
DBUG_ENTER("mysqld_show_keys");
DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
table_list->real_name));
@@ -648,6 +652,8 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
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;
@@ -664,16 +670,18 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
{
packet->length(0);
- net_store_data(packet,table->table_name);
- net_store_data(packet,((key_info->flags & HA_NOSAME) ? "0" :"1"), 1);
- net_store_data(packet,key_info->name);
+ net_store_data(packet,convert,table->table_name);
+ net_store_data(packet,convert,((key_info->flags & HA_NOSAME) ? "0" :"1"), 1);
+ net_store_data(packet,convert,key_info->name);
end=int10_to_str((long) (j+1),(char*) buff,10);
- net_store_data(packet,buff,(uint) (end-buff));
- net_store_data(packet,key_part->field ? key_part->field->field_name :
+ net_store_data(packet,convert,buff,(uint) (end-buff));
+ net_store_data(packet,convert,
+ key_part->field ? key_part->field->field_name :
"?unknown field?");
if (table->file->option_flag() & HA_READ_ORDER)
- net_store_data(packet,((key_part->key_part_flag & HA_REVERSE_SORT)
- ? "D" : "A"), 1);
+ net_store_data(packet,convert,
+ ((key_part->key_part_flag & HA_REVERSE_SORT) ?
+ "D" : "A"), 1);
else
net_store_null(packet); /* purecov: inspected */
KEY *key=table->key_info+i;
@@ -681,21 +689,30 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
{
ulong records=(table->file->records / key->rec_per_key[j]);
end=int10_to_str((long) records, buff, 10);
- net_store_data(packet,buff,(uint) (end-buff));
+ net_store_data(packet,convert,buff,(uint) (end-buff));
}
else
net_store_null(packet);
+
+ /* Check if we have a key part that only uses part of the field */
if (!key_part->field ||
key_part->length !=
table->field[key_part->fieldnr-1]->key_length())
{
end=int10_to_str((long) key_part->length, buff,10); /* purecov: inspected */
- net_store_data(packet,buff,(uint) (end-buff)); /* purecov: inspected */
+ net_store_data(packet,convert,buff,(uint) (end-buff)); /* purecov: inspected */
}
else
net_store_null(packet);
net_store_null(packet); // No pack_information yet
- net_store_data(packet,key_info->flags & HA_FULLTEXT ? "FULLTEXT":"");
+
+ /* Null flag */
+ uint flags= key_part->field ? key_part->field->flags : 0;
+ char *pos=(char*) ((flags & NOT_NULL_FLAG) ? "" : "YES");
+ net_store_data(packet,convert,(const char*) pos);
+ net_store_data(packet,convert,table->file->index_type(i));
+ /* Comment */
+ net_store_data(packet,convert,"");
if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
DBUG_RETURN(1); /* purecov: inspected */
}
@@ -740,27 +757,29 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
int
mysqld_dump_create_info(THD *thd, TABLE *table, int fd)
{
+ CONVERT *convert=thd->convert_set;
DBUG_ENTER("mysqld_dump_create_info");
DBUG_PRINT("enter",("table: %s",table->real_name));
+
String* packet = &thd->packet;
packet->length(0);
-
- if(store_create_info(thd,table,packet))
+ if (store_create_info(thd,table,packet))
DBUG_RETURN(-1);
- if(fd < 0)
+ if (convert)
+ convert->convert((char*) packet->ptr(), packet->length());
+ if (fd < 0)
{
- if(my_net_write(&thd->net, (char*)packet->ptr(), packet->length()))
+ if (my_net_write(&thd->net, (char*)packet->ptr(), packet->length()))
DBUG_RETURN(-1);
VOID(net_flush(&thd->net));
}
else
{
- if(my_write(fd, (const byte*) packet->ptr(), packet->length(),
- MYF(MY_WME)))
+ if (my_write(fd, (const byte*) packet->ptr(), packet->length(),
+ MYF(MY_WME)))
DBUG_RETURN(-1);
}
-
DBUG_RETURN(0);
}
@@ -989,6 +1008,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
List<Item> field_list;
I_List<thread_info> thread_infos;
ulong max_query_length= verbose ? max_allowed_packet : PROCESS_LIST_WIDTH;
+ CONVERT *convert=thd->convert_set;
DBUG_ENTER("mysqld_list_processes");
field_list.push_back(new Item_int("Id",0,7));
@@ -1018,10 +1038,13 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
thread_info *thd_info=new thread_info;
thd_info->thread_id=tmp->thread_id;
- thd_info->user=thd->strdup(tmp->user ? tmp->user : (tmp->system_thread ?
- "system user" : "unauthenticated user"));
- thd_info->host=thd->strdup(tmp->host ? tmp->host : (tmp->ip ? tmp->ip :
- (tmp->system_thread ? "none" : "connecting host")));
+ thd_info->user=thd->strdup(tmp->user ? tmp->user :
+ (tmp->system_thread ?
+ "system user" : "unauthenticated user"));
+ thd_info->host=thd->strdup(tmp->host ? tmp->host :
+ (tmp->ip ? tmp->ip :
+ (tmp->system_thread ? "none" :
+ "connecting host")));
if ((thd_info->db=tmp->db)) // Safe test
thd_info->db=thd->strdup(thd_info->db);
thd_info->command=(int) tmp->command;
@@ -1053,9 +1076,8 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
thd_info->query=0;
if (tmp->query)
{
- uint length=(uint) strlen(tmp->query);
- if (length > max_query_length)
- length=max_query_length;
+ /* query_length is always set before tmp->query */
+ uint length= min(max_query_length, tmp->query_length);
thd_info->query=(char*) thd->memdup(tmp->query,length+1);
thd_info->query[length]=0;
}
@@ -1072,28 +1094,28 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
char buff[20],*end;
packet->length(0);
end=int10_to_str((long) thd_info->thread_id, buff,10);
- net_store_data(packet,buff,(uint) (end-buff));
- net_store_data(packet,thd_info->user);
- net_store_data(packet,thd_info->host);
+ net_store_data(packet,convert,buff,(uint) (end-buff));
+ net_store_data(packet,convert,thd_info->user);
+ net_store_data(packet,convert,thd_info->host);
if (thd_info->db)
- net_store_data(packet,thd_info->db);
+ net_store_data(packet,convert,thd_info->db);
else
net_store_null(packet);
if (thd_info->proc_info)
- net_store_data(packet,thd_info->proc_info);
+ net_store_data(packet,convert,thd_info->proc_info);
else
- net_store_data(packet,command_name[thd_info->command]);
+ net_store_data(packet,convert,command_name[thd_info->command]);
if (thd_info->start_time)
- net_store_data(packet,(uint32)
- (time((time_t*) 0) - thd_info->start_time));
+ net_store_data(packet,
+ (uint32) (time((time_t*) 0) - thd_info->start_time));
else
net_store_null(packet);
if (thd_info->state_info)
- net_store_data(packet,thd_info->state_info);
+ net_store_data(packet,convert,thd_info->state_info);
else
net_store_null(packet);
if (thd_info->query)
- net_store_data(packet,thd_info->query);
+ net_store_data(packet,convert,thd_info->query);
else
net_store_null(packet);
if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
@@ -1115,6 +1137,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables)
char buff[8192];
String packet2(buff,sizeof(buff));
List<Item> field_list;
+ CONVERT *convert=thd->convert_set;
DBUG_ENTER("mysqld_show");
field_list.push_back(new Item_empty_string("Variable_name",30));
field_list.push_back(new Item_empty_string("Value",256));
@@ -1128,7 +1151,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables)
if (!(wild && wild[0] && wild_compare(variables[i].name,wild)))
{
packet2.length(0);
- net_store_data(&packet2,variables[i].name);
+ net_store_data(&packet2,convert,variables[i].name);
switch (variables[i].type){
case SHOW_LONG:
case SHOW_LONG_CONST:
@@ -1155,7 +1178,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables)
break;
}
case SHOW_CHAR:
- net_store_data(&packet2,variables[i].value);
+ net_store_data(&packet2,convert, variables[i].value);
break;
case SHOW_STARTTIME:
net_store_data(&packet2,(uint32) (thd->query_start() - start_time));
@@ -1163,15 +1186,183 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables)
case SHOW_QUESTION:
net_store_data(&packet2,(uint32) thd->query_id);
break;
+ case SHOW_RPL_STATUS:
+ net_store_data(&packet2, rpl_status_type[(int)rpl_status]);
+ break;
+ case SHOW_SLAVE_RUNNING:
+ {
+ LOCK_ACTIVE_MI;
+ net_store_data(&packet2, (active_mi->slave_running &&
+ active_mi->rli.slave_running)
+ ? "ON" : "OFF");
+ UNLOCK_ACTIVE_MI;
+ break;
+ }
case SHOW_OPENTABLES:
net_store_data(&packet2,(uint32) cached_tables());
break;
case SHOW_CHAR_PTR:
{
char *value= *(char**) variables[i].value;
- net_store_data(&packet2,value ? value : "");
+ net_store_data(&packet2,convert, value ? value : "");
break;
}
+#ifdef HAVE_OPENSSL
+ /* First group - functions relying on CTX */
+ case SHOW_SSL_CTX_SESS_ACCEPT:
+ net_store_data(&packet2,(uint32)
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_accept(ssl_acceptor_fd->ssl_context_)));
+ break;
+ case SHOW_SSL_CTX_SESS_ACCEPT_GOOD:
+ net_store_data(&packet2,(uint32)
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_accept_good(ssl_acceptor_fd->ssl_context_)));
+ break;
+ case SHOW_SSL_CTX_SESS_CONNECT_GOOD:
+ net_store_data(&packet2,(uint32)
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_connect_good(ssl_acceptor_fd->ssl_context_)));
+ break;
+ case SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE:
+ net_store_data(&packet2,(uint32)
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context_)));
+ break;
+ case SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE:
+ net_store_data(&packet2,(uint32)
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd->ssl_context_)));
+ break;
+ case SHOW_SSL_CTX_SESS_CB_HITS:
+ net_store_data(&packet2,(uint32)
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_cb_hits(ssl_acceptor_fd->ssl_context_)));
+ break;
+ case SHOW_SSL_CTX_SESS_HITS:
+ net_store_data(&packet2,(uint32)
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_hits(ssl_acceptor_fd->ssl_context_)));
+ break;
+ case SHOW_SSL_CTX_SESS_CACHE_FULL:
+ net_store_data(&packet2,(uint32)
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_cache_full(ssl_acceptor_fd->ssl_context_)));
+ break;
+ case SHOW_SSL_CTX_SESS_MISSES:
+ net_store_data(&packet2,(uint32)
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_misses(ssl_acceptor_fd->ssl_context_)));
+ break;
+ case SHOW_SSL_CTX_SESS_TIMEOUTS:
+ net_store_data(&packet2,(uint32)
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context_)));
+ break;
+ case SHOW_SSL_CTX_SESS_NUMBER:
+ net_store_data(&packet2,(uint32)
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context_)));
+ break;
+ case SHOW_SSL_CTX_SESS_CONNECT:
+ net_store_data(&packet2,(uint32)
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context_)));
+ break;
+ case SHOW_SSL_CTX_SESS_GET_CACHE_SIZE:
+ net_store_data(&packet2,(uint32)
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context_)));
+ break;
+ case SHOW_SSL_CTX_GET_VERIFY_MODE:
+ net_store_data(&packet2,(uint32)
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context_)));
+ break;
+ case SHOW_SSL_CTX_GET_VERIFY_DEPTH:
+ net_store_data(&packet2,(uint32)
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context_)));
+ break;
+ case SHOW_SSL_CTX_GET_SESSION_CACHE_MODE:
+ if (!ssl_acceptor_fd)
+ {
+ net_store_data(&packet2,"NONE" );
+ break;
+ }
+ switch(SSL_CTX_get_session_cache_mode(ssl_acceptor_fd->ssl_context_))
+ {
+ case SSL_SESS_CACHE_OFF:
+ net_store_data(&packet2,"OFF" );
+ break;
+ case SSL_SESS_CACHE_CLIENT:
+ net_store_data(&packet2,"CLIENT" );
+ break;
+ case SSL_SESS_CACHE_SERVER:
+ net_store_data(&packet2,"SERVER" );
+ break;
+ case SSL_SESS_CACHE_BOTH:
+ net_store_data(&packet2,"BOTH" );
+ break;
+ case SSL_SESS_CACHE_NO_AUTO_CLEAR:
+ net_store_data(&packet2,"NO_AUTO_CLEAR" );
+ break;
+ case SSL_SESS_CACHE_NO_INTERNAL_LOOKUP:
+ net_store_data(&packet2,"NO_INTERNAL_LOOKUP" );
+ break;
+ default:
+ net_store_data(&packet2,"Unknown");
+ break;
+ }
+ break;
+ /* First group - functions relying on SSL */
+ case SHOW_SSL_GET_VERSION:
+ net_store_data(&packet2, thd->net.vio->ssl_ ?
+ SSL_get_version(thd->net.vio->ssl_) : "");
+ break;
+ case SHOW_SSL_SESSION_REUSED:
+ net_store_data(&packet2,(uint32) (thd->net.vio->ssl_ ?
+ SSL_session_reused(thd->net.vio->ssl_) : 0));
+ break;
+ case SHOW_SSL_GET_DEFAULT_TIMEOUT:
+ net_store_data(&packet2,(uint32) (thd->net.vio->ssl_ ?
+ SSL_get_default_timeout(thd->net.vio->ssl_):0));
+ break;
+ case SHOW_SSL_GET_VERIFY_MODE:
+ net_store_data(&packet2,(uint32) (thd->net.vio->ssl_ ?
+ SSL_get_verify_mode(thd->net.vio->ssl_):0));
+ break;
+ case SHOW_SSL_GET_VERIFY_DEPTH:
+ net_store_data(&packet2,(uint32) (thd->net.vio->ssl_ ?
+ SSL_get_verify_depth(thd->net.vio->ssl_):0));
+ break;
+ case SHOW_SSL_GET_CIPHER:
+ net_store_data(&packet2, thd->net.vio->ssl_ ?
+ SSL_get_cipher(thd->net.vio->ssl_) : "");
+ break;
+ case SHOW_SSL_GET_CIPHER_LIST:
+ if (thd->net.vio->ssl_)
+ {
+ char buf[1024], *pos;
+ pos=buf;
+ for (int i=0 ; i++ ;)
+ {
+ const char *p=SSL_get_cipher_list(thd->net.vio->ssl_,i);
+ if (p == NULL)
+ break;
+ pos=strmov(pos, p);
+ *pos++= ':';
+ }
+ if (pos != buf)
+ pos--; // Remove last ':'
+ *pos=0;
+ net_store_data(&packet2, buf);
+ }
+ else
+ net_store_data(&packet2, "");
+ break;
+
+#endif /* HAVE_OPENSSL */
}
if (my_net_write(&thd->net, (char*) packet2.ptr(),packet2.length()))
goto err; /* purecov: inspected */
@@ -1189,6 +1380,6 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables)
}
#ifdef __GNUC__
-template class List_iterator<char>;
+template class List_iterator_fast<char>;
template class List<char>;
#endif
diff --git a/sql/sql_sort.h b/sql/sql_sort.h
new file mode 100644
index 00000000000..62c5f1cb164
--- /dev/null
+++ b/sql/sql_sort.h
@@ -0,0 +1,55 @@
+/* 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 */
+
+/* Defines used by filesort and uniques */
+
+#define MERGEBUFF 7
+#define MERGEBUFF2 15
+
+typedef struct st_buffpek { /* Struktur om sorteringsbuffrarna */
+ my_off_t file_pos; /* Where we are in the sort file */
+ uchar *base,*key; /* key pointers */
+ ha_rows count; /* Number of rows in table */
+ ulong mem_count; /* numbers of keys in memory */
+ ulong max_keys; /* Max keys in buffert */
+} BUFFPEK;
+
+
+typedef struct st_sort_param {
+ uint sort_length; /* Length of sort columns */
+ uint keys; /* Max keys / buffert */
+ uint ref_length; /* Length of record ref. */
+ ha_rows max_rows,examined_rows;
+ TABLE *sort_form; /* For quicker make_sortkey */
+ SORT_FIELD *local_sortorder;
+ SORT_FIELD *end;
+ uchar *unique_buff;
+ bool not_killable;
+#ifdef USE_STRCOLL
+ char* tmp_buffer;
+#endif
+} SORTPARAM;
+
+
+int merge_many_buff(SORTPARAM *param, uchar *sort_buffer,
+ BUFFPEK *buffpek,
+ uint *maxbuffer, IO_CACHE *t_file);
+uint read_to_buffer(IO_CACHE *fromfile,BUFFPEK *buffpek,
+ uint sort_length);
+int merge_buffers(SORTPARAM *param,IO_CACHE *from_file,
+ IO_CACHE *to_file, uchar *sort_buffer,
+ BUFFPEK *lastbuff,BUFFPEK *Fb,
+ BUFFPEK *Tb,int flag);
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index e6cdd089bf1..8fe84947ac2 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program file 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 originally from the mysql distribution. Coded by monty */
@@ -21,7 +20,7 @@
#pragma implementation // gcc: Class implementation
#endif
-#include <global.h>
+#include <my_global.h>
#include <my_sys.h>
#include <m_string.h>
#include <m_ctype.h>
@@ -362,6 +361,37 @@ skipp:
return -1;
}
+/*
+ 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();
+skipp:
+ while (str != end)
+ {
+ if (my_sort_order[*str++] == my_sort_order[*search])
+ {
+ register char *i,*j;
+ i=(char*) str; j=(char*) search+1;
+ while (j != search_end)
+ if (my_sort_order[*i++] != my_sort_order[*j++]) goto skipp;
+ return (int) (str-Ptr) -1;
+ }
+ }
+ }
+ return -1;
+}
/*
** Search string from end. Offset is offset to the end of string
@@ -577,7 +607,7 @@ int wild_case_compare(const char *str,const char *str_end,
{
do
{
- if (str == str_end) // Skipp one char if possible
+ if (str == str_end) // Skip one char if possible
return (result);
INC_PTR(str,str_end);
} while (++wildstr < wildend && *wildstr == wild_one);
@@ -668,8 +698,11 @@ int wild_case_compare(const char *str,const char *str_end,
int wild_case_compare(String &match,String &wild, char escape)
{
- return wild_case_compare(match.ptr(),match.ptr()+match.length(),
- wild.ptr(), wild.ptr()+wild.length(),escape);
+ DBUG_ENTER("wild_case_compare");
+ DBUG_PRINT("enter",("match='%s', wild='%s', escape='%c'"
+ ,match.ptr(),wild.ptr(),escape));
+ DBUG_RETURN(wild_case_compare(match.ptr(),match.ptr()+match.length(),
+ wild.ptr(), wild.ptr()+wild.length(),escape));
}
/*
@@ -679,6 +712,9 @@ int wild_case_compare(String &match,String &wild, char escape)
int wild_compare(const char *str,const char *str_end,
const char *wildstr,const char *wildend,char escape)
{
+ DBUG_ENTER("wild_compare");
+ DBUG_PRINT("enter",("str='%s', str_end='%s', wildstr='%s', wildend='%s', escape='%c'"
+ ,str,str_end,wildstr,wildend,escape));
int result= -1; // Not found, using wildcards
while (wildstr != wildend)
{
@@ -687,17 +723,21 @@ int wild_compare(const char *str,const char *str_end,
if (*wildstr == escape && wildstr+1 != wildend)
wildstr++;
if (str == str_end || *wildstr++ != *str++)
- return(1);
+ {
+ DBUG_RETURN(1);
+ }
if (wildstr == wildend)
- return (str != str_end); // Match if both are at end
+ {
+ DBUG_RETURN(str != str_end); // Match if both are at end
+ }
result=1; // Found an anchor char
}
if (*wildstr == wild_one)
{
do
{
- if (str == str_end) // Skipp one char if possible
- return (result);
+ if (str == str_end) // Skip one char if possible
+ DBUG_RETURN(result);
str++;
} while (*++wildstr == wild_one && wildstr != wildend);
if (wildstr == wildend)
@@ -714,17 +754,22 @@ int wild_compare(const char *str,const char *str_end,
if (*wildstr == wild_one)
{
if (str == str_end)
- return (-1);
+ {
+ DBUG_RETURN(-1);
+ }
str++;
continue;
}
break; // Not a wild character
}
if (wildstr == wildend)
- return(0); // Ok if wild_many is last
+ {
+ DBUG_RETURN(0); // Ok if wild_many is last
+ }
if (str == str_end)
- return -1;
-
+ {
+ DBUG_RETURN(-1);
+ }
char cmp;
if ((cmp= *wildstr) == escape && wildstr+1 != wildend)
cmp= *++wildstr;
@@ -733,22 +778,30 @@ int wild_compare(const char *str,const char *str_end,
{
while (str != str_end && *str != cmp)
str++;
- if (str++ == str_end) return (-1);
+ if (str++ == str_end)
+ {
+ DBUG_RETURN(-1);
+ }
{
int tmp=wild_compare(str,str_end,wildstr,wildend,escape);
if (tmp <= 0)
- return (tmp);
+ {
+ DBUG_RETURN(tmp);
+ }
}
} while (str != str_end && wildstr[0] != wild_many);
- return(-1);
+ DBUG_RETURN(-1);
}
}
- return (str != str_end ? 1 : 0);
+ DBUG_RETURN(str != str_end ? 1 : 0);
}
int wild_compare(String &match,String &wild, char escape)
{
- return wild_compare(match.ptr(),match.ptr()+match.length(),
- wild.ptr(), wild.ptr()+wild.length(),escape);
+ DBUG_ENTER("wild_compare");
+ DBUG_PRINT("enter",("match='%s', wild='%s', escape='%c'"
+ ,match.ptr(),wild.ptr(),escape));
+ DBUG_RETURN(wild_compare(match.ptr(),match.ptr()+match.length(),
+ wild.ptr(), wild.ptr()+wild.length(),escape));
}
diff --git a/sql/sql_string.h b/sql/sql_string.h
index 31dea9991cc..ad7455ecbf1 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 originally from the mysql distribution. Coded by monty */
@@ -161,6 +160,7 @@ public:
bool append(const char *s,uint32 arg_length=0);
bool append(IO_CACHE* file, uint32 arg_length);
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 String &to);
inline bool append(char chr)
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 7b5fc5797c9..8013afa194b 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -26,6 +26,7 @@
#endif
extern HASH open_cache;
+static const char *primary_key_name="PRIMARY";
static bool check_if_keyname_exists(const char *name,KEY *start, KEY *end);
static char *make_unique_key_name(const char *field_name,KEY *start,KEY *end);
@@ -43,12 +44,7 @@ static int copy_data_between_tables(TABLE *from,TABLE *to,
int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists)
{
- char path[FN_REFLEN];
- String wrong_tables;
- bool some_tables_deleted=0;
- uint error;
- db_type table_type;
- TABLE_LIST *table;
+ int error;
DBUG_ENTER("mysql_rm_table");
/* mark for close and remove all cached entries */
@@ -72,7 +68,35 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists)
}
}
-
+ error=mysql_rm_table_part2(thd,tables,if_exists,0);
+
+ err:
+ VOID(pthread_cond_broadcast(&COND_refresh)); // Signal to refresh
+ pthread_mutex_unlock(&LOCK_open);
+
+ pthread_mutex_lock(&thd->mysys_var->mutex);
+ thd->mysys_var->current_mutex= 0;
+ thd->mysys_var->current_cond= 0;
+ pthread_mutex_unlock(&thd->mysys_var->mutex);
+
+ if (error)
+ DBUG_RETURN(-1);
+ send_ok(&thd->net);
+ DBUG_RETURN(0);
+}
+
+
+int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
+ bool dont_log_query)
+{
+ TABLE_LIST *table;
+ char path[FN_REFLEN];
+ String wrong_tables;
+ db_type table_type;
+ int error;
+ bool some_tables_deleted=0;
+ DBUG_ENTER("mysql_rm_table_part2");
+
for (table=tables ; table ; table=table->next)
{
char *db=table->db ? table->db : thd->db;
@@ -137,33 +161,25 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists)
}
if (some_tables_deleted)
{
- mysql_update_log.write(thd, thd->query,thd->query_length);
- if (mysql_bin_log.is_open())
+ query_cache.invalidate(tables);
+ if (!dont_log_query)
{
- Query_log_event qinfo(thd, thd->query);
- mysql_bin_log.write(&qinfo);
+ mysql_update_log.write(thd, thd->query,thd->query_length);
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query);
+ mysql_bin_log.write(&qinfo);
+ }
}
}
-
- error = 0;
- err:
- VOID(pthread_cond_broadcast(&COND_refresh)); // Signal to refresh
- pthread_mutex_unlock(&LOCK_open);
-
- pthread_mutex_lock(&thd->mysys_var->mutex);
- thd->mysys_var->current_mutex= 0;
- thd->mysys_var->current_cond= 0;
- pthread_mutex_unlock(&thd->mysys_var->mutex);
+ error = 0;
if (wrong_tables.length())
{
my_error(ER_BAD_TABLE_ERROR,MYF(0),wrong_tables.c_ptr());
error=1;
}
- if(error)
- DBUG_RETURN(-1);
- send_ok(&thd->net);
- DBUG_RETURN(0);
+ DBUG_RETURN(error);
}
@@ -181,6 +197,52 @@ int quick_rm_table(enum db_type base,const char *db,
return ha_delete_table(base,path) || error;
}
+/*
+ Sort keys in the following order:
+ - PRIMARY KEY
+ - UNIQUE keyws where all column are NOT NULL
+ - Other UNIQUE keys
+ - Normal keys
+ - Fulltext keys
+
+ This will make checking for duplicated keys faster and ensure that
+ PRIMARY keys are prioritized.
+*/
+
+
+static int sort_keys(KEY *a, KEY *b)
+{
+ if (a->flags & HA_NOSAME)
+ {
+ if (!(b->flags & HA_NOSAME))
+ return -1;
+ if ((a->flags ^ b->flags) & HA_NULL_PART_KEY)
+ {
+ /* Sort NOT NULL keys before other keys */
+ return (a->flags & HA_NULL_PART_KEY) ? 1 : -1;
+ }
+ if (a->name == primary_key_name)
+ return -1;
+ if (b->name == primary_key_name)
+ return 1;
+ }
+ else if (b->flags & HA_NOSAME)
+ return 1; // Prefer b
+
+ if ((a->flags ^ b->flags) & HA_FULLTEXT)
+ {
+ return (a->flags & HA_FULLTEXT) ? 1 : -1;
+ }
+ /*
+ Prefer original key order. usable_key_parts contains here
+ the original key position.
+ */
+ return ((a->usable_key_parts < b->usable_key_parts) ? -1 :
+ (a->usable_key_parts > b->usable_key_parts) ? 1 :
+ 0);
+}
+
+
/*****************************************************************************
* Create a table.
* If one creates a temporary table, this is automaticly opened
@@ -336,10 +398,9 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
List_iterator<Key> key_iterator(keys);
uint key_parts=0,key_count=keys.elements;
List<Key> keys_in_order; // Add new keys here
- Key *primary_key=0;
- bool unique_key=0;
+ bool primary_key=0,unique_key=0;
Key *key;
- uint tmp;
+ uint tmp, key_number;
tmp=min(file->max_keys(), MAX_KEY);
if (key_count > tmp)
{
@@ -347,12 +408,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
DBUG_RETURN(-1);
}
- /*
- Check keys;
- Put PRIMARY KEY first, then UNIQUE keys and other keys last
- This will make checking for duplicated keys faster and ensure that
- primary keys are prioritized.
- */
+ /* Calculate number of key segements */
while ((key=key_iterator++))
{
@@ -368,33 +424,6 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
DBUG_RETURN(-1);
}
key_parts+=key->columns.elements;
- if (key->type == Key::PRIMARY)
- {
- if (primary_key)
- {
- my_error(ER_MULTIPLE_PRI_KEY,MYF(0));
- DBUG_RETURN(-1);
- }
- primary_key=key;
- }
- else if (key->type == Key::UNIQUE)
- {
- unique_key=1;
- if (keys_in_order.push_front(key))
- DBUG_RETURN(-1);
- }
- else if (keys_in_order.push_back(key))
- DBUG_RETURN(-1);
- }
- if (primary_key)
- {
- if (keys_in_order.push_front(primary_key))
- DBUG_RETURN(-1);
- }
- else if (!unique_key && (file->option_flag() & HA_REQUIRE_PRIMARY_KEY))
- {
- my_error(ER_REQUIRES_PRIMARY_KEY,MYF(0));
- DBUG_RETURN(-1);
}
key_info_buffer=key_info=(KEY*) sql_calloc(sizeof(KEY)*key_count);
@@ -402,8 +431,9 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
if (!key_info_buffer || ! key_part_info)
DBUG_RETURN(-1); // Out of memory
- List_iterator<Key> key_iterator_in_order(keys_in_order);
- for (; (key=key_iterator_in_order++) ; key_info++)
+ key_iterator.rewind();
+ key_number=0;
+ for (; (key=key_iterator++) ; key_info++, key_number++)
{
uint key_length=0;
key_part_spec *column;
@@ -412,10 +442,11 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
(key->type == Key::FULLTEXT) ? HA_FULLTEXT : HA_NOSAME;
key_info->key_parts=(uint8) key->columns.elements;
key_info->key_part=key_part_info;
+ key_info->usable_key_parts= key_number;
if (key->type == Key::FULLTEXT)
{
- if (file->option_flag() & HA_NO_FULLTEXT_KEY)
+ if (!(file->option_flag() & HA_CAN_FULLTEXT))
{
my_error(ER_TABLE_CANT_HANDLE_FULLTEXT, MYF(0));
DBUG_RETURN(-1);
@@ -471,6 +502,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
MYF(0),column->field_name);
DBUG_RETURN(-1);
}
+ key_info->flags|= HA_NULL_PART_KEY;
}
if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
{
@@ -530,7 +562,15 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
if (column_nr == 0)
{
if (key->type == Key::PRIMARY)
- key_name="PRIMARY";
+ {
+ if (primary_key)
+ {
+ my_error(ER_MULTIPLE_PRI_KEY,MYF(0));
+ DBUG_RETURN(-1);
+ }
+ key_name=primary_key_name;
+ primary_key=1;
+ }
else if (!(key_name = key->name()))
key_name=make_unique_key_name(sql_field->field_name,
key_info_buffer,key_info);
@@ -542,18 +582,29 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
key_info->name=(char*) key_name;
}
}
+ if (!(key_info->flags & HA_NULL_PART_KEY))
+ unique_key=1;
key_info->key_length=(uint16) key_length;
- if (key_length > file->max_key_length() && key->type != Key::FULLTEXT)
+ uint max_key_length= max(file->max_key_length(), MAX_KEY_LENGTH);
+ if (key_length > max_key_length && key->type != Key::FULLTEXT)
{
- my_error(ER_TOO_LONG_KEY,MYF(0),file->max_key_length());
+ my_error(ER_TOO_LONG_KEY,MYF(0),max_key_length);
DBUG_RETURN(-1);
}
}
+ if (!unique_key && !primary_key &&
+ (file->option_flag() & HA_REQUIRE_PRIMARY_KEY))
+ {
+ my_error(ER_REQUIRES_PRIMARY_KEY,MYF(0));
+ DBUG_RETURN(-1);
+ }
if (auto_increment > 0)
{
my_error(ER_WRONG_AUTO_KEY,MYF(0));
DBUG_RETURN(-1);
}
+ /* Sort keys in optimized order */
+ qsort((gptr) key_info_buffer, key_count, sizeof(KEY), (qsort_cmp) sort_keys);
/* Check if table exists */
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
@@ -670,7 +721,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
DBUG_ENTER("create_table_from_items");
/* Add selected items to field list */
- List_iterator<Item> it(*items);
+ List_iterator_fast<Item> it(*items);
Item *item;
Field *tmp_field;
tmp_table.db_create_options=0;
@@ -688,8 +739,11 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
my_error(ER_WRONG_COLUMN_NAME,MYF(0),item->name);
DBUG_RETURN(0);
}
-
- Field *field=create_tmp_field(&tmp_table,item,item->type(),
+ Field *field;
+ if (item->type() == Item::FUNC_ITEM)
+ field=item->tmp_table_field(&tmp_table);
+ else
+ field=create_tmp_field(thd, &tmp_table, item, item->type(),
(Item_result_field***) 0, &tmp_field,0,0);
if (!field ||
!(cr_field=new create_field(field,(item->type() == Item::FIELD_ITEM ?
@@ -833,61 +887,46 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table)
char* table_name = table->name;
char* db = thd->db ? thd->db : table->db;
- if (!fn_format(src_path, table_name, backup_dir, reg_ext, 4 + 64))
+ if (fn_format_relative_to_data_home(src_path, table_name, backup_dir,
+ reg_ext))
DBUG_RETURN(-1); // protect buffer overflow
sprintf(dst_path, "%s/%s/%s", mysql_real_data_home, db, table_name);
- int lock_retcode;
- pthread_mutex_lock(&LOCK_open);
- if ((lock_retcode = lock_table_name(thd, table)) < 0)
- {
- pthread_mutex_unlock(&LOCK_open);
- DBUG_RETURN(-1);
- }
-
- if (lock_retcode && wait_for_locked_table_names(thd, table))
- {
- unlock_table_name(thd, table);
- pthread_mutex_unlock(&LOCK_open);
+ if (lock_and_wait_for_table_name(thd,table))
DBUG_RETURN(-1);
- }
- pthread_mutex_unlock(&LOCK_open);
if (my_copy(src_path,
- fn_format(dst_path, dst_path,"",
- reg_ext, 4),
- MYF(MY_WME)))
+ fn_format(dst_path, dst_path,"", reg_ext, 4),
+ MYF(MY_WME)))
{
unlock_table_name(thd, table);
DBUG_RETURN(send_check_errmsg(thd, table, "restore",
"Failed copying .frm file"));
}
- bool save_no_send_ok = thd->net.no_send_ok;
- thd->net.no_send_ok = 1;
- // generate table will try to send OK which messes up the output
- // for the client
-
- if (generate_table(thd, table, 0))
+ if (mysql_truncate(thd, table, 1))
{
unlock_table_name(thd, table);
- thd->net.no_send_ok = save_no_send_ok;
DBUG_RETURN(send_check_errmsg(thd, table, "restore",
"Failed generating table from .frm file"));
}
-
- thd->net.no_send_ok = save_no_send_ok;
}
+ // now we should be able to open the partially restored table
+ // to finish the restore in the handler later on
+ if (!(table->table = reopen_name_locked_table(thd, table)))
+ unlock_table_name(thd, table);
DBUG_RETURN(0);
}
+
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, bool restore,
+ bool open_for_modify,
uint extra_open_options,
+ int (*prepare_func)(THD *, TABLE_LIST *),
int (handler::*operator_func)
(THD *, HA_CHECK_OPT *))
{
@@ -919,18 +958,13 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
table->table = open_ltable(thd, table, lock_type);
thd->open_options&= ~extra_open_options;
packet->length(0);
- if (restore)
+ if (prepare_func)
{
- switch (prepare_for_restore(thd, table)) {
- case 1: continue; // error, message written to net
- case -1: goto err; // error, message could be written to net
- default: ;// should be 0 otherwise
+ switch ((*prepare_func)(thd, table)) {
+ case 1: continue; // error, message written to net
+ case -1: goto err; // error, message could be written to net
+ default: ; // should be 0 otherwise
}
-
- // now we should be able to open the partially restored table
- // to finish the restore in the handler later on
- if (!(table->table = reopen_name_locked_table(thd, table)))
- unlock_table_name(thd, table);
}
if (!table->table)
@@ -957,6 +991,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
sprintf(buff, ER(ER_OPEN_AS_READONLY), table_name);
net_store_data(packet, buff);
close_thread_tables(thd);
+ table->table=0; // For query cache
if (my_net_write(&thd->net, (char*) thd->packet.ptr(),
packet->length()))
goto err;
@@ -1034,6 +1069,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
remove_table_from_cache(thd, table->table->table_cache_key,
table->table->real_name);
close_thread_tables(thd);
+ table->table=0; // For query cache
if (my_net_write(&thd->net, (char*) packet->ptr(),
packet->length()))
goto err;
@@ -1043,9 +1079,12 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
DBUG_RETURN(0);
err:
close_thread_tables(thd); // Shouldn't be needed
+ if (table)
+ table->table=0;
DBUG_RETURN(-1);
}
+
int mysql_backup_table(THD* thd, TABLE_LIST* table_list)
{
DBUG_ENTER("mysql_backup_table");
@@ -1058,7 +1097,8 @@ int 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, 1,0,
+ "restore", TL_WRITE, 1, 0,
+ &prepare_for_restore,
&handler::restore));
}
@@ -1066,7 +1106,7 @@ int 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, 0, HA_OPEN_FOR_REPAIR,
+ "repair", TL_WRITE, 1, HA_OPEN_FOR_REPAIR, 0,
&handler::repair));
}
@@ -1105,7 +1145,7 @@ 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, 0, HA_OPEN_FOR_REPAIR,
+ 0, HA_OPEN_FOR_REPAIR, 0,
&handler::check));
}
@@ -1118,16 +1158,19 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
List<Alter_column> &alter_list,
ORDER *order,
bool drop_primary,
- enum enum_duplicates handle_duplicates)
+ enum enum_duplicates handle_duplicates,
+ enum enum_enable_or_disable keys_onoff,
+ bool simple_alter)
{
TABLE *table,*new_table;
int error;
char tmp_name[80],old_name[32],new_name_buff[FN_REFLEN],
- *table_name,*db;
+ *table_name,*db;
+ char index_file[FN_REFLEN], data_file[FN_REFLEN];
bool use_timestamp=0;
ha_rows copied,deleted;
ulonglong next_insert_id;
- uint save_time_stamp,db_create_options;
+ uint save_time_stamp,db_create_options, used_fields;
enum db_type old_db_type,new_db_type;
DBUG_ENTER("mysql_alter_table");
@@ -1136,6 +1179,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
db=table_list->db;
if (!new_db)
new_db=db;
+ used_fields=create_info->used_fields;
if (!(table=open_ltable(thd,table_list,TL_WRITE_ALLOW_READ)))
DBUG_RETURN(-1);
@@ -1181,42 +1225,49 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (create_info->db_type == DB_TYPE_DEFAULT)
create_info->db_type=old_db_type;
new_db_type=create_info->db_type= ha_checktype(create_info->db_type);
- if (create_info->row_type == ROW_TYPE_DEFAULT)
+ if (create_info->row_type == ROW_TYPE_NOT_USED)
create_info->row_type=table->row_type;
- /* Check if the user only wants to do a simple RENAME */
+ /* In some simple cases we need not to recreate the table */
thd->proc_info="setup";
- if (new_name != table_name &&
- !fields.elements && !keys.elements && ! drop_list.elements &&
- !alter_list.elements && !drop_primary &&
- new_db_type == old_db_type && create_info->max_rows == 0 &&
- create_info->auto_increment_value == 0 && !table->tmp_table)
+ if (simple_alter)
{
- thd->proc_info="rename";
- VOID(pthread_mutex_lock(&LOCK_open));
- /* Then do a 'simple' rename of the table */
error=0;
- if (!access(new_name_buff,F_OK))
- {
- my_error(ER_TABLE_EXISTS_ERROR,MYF(0),new_name);
- error= -1;
- }
- else
+ if (new_name != table_name)
{
- *fn_ext(new_name)=0;
- close_cached_table(thd,table);
- if (mysql_rename_table(old_db_type,db,table_name,new_db,new_name))
- error= -1;
+ thd->proc_info="rename";
+ VOID(pthread_mutex_lock(&LOCK_open));
+ /* Then do a 'simple' rename of the table */
+ error=0;
+ if (!access(new_name_buff,F_OK))
+ {
+ my_error(ER_TABLE_EXISTS_ERROR,MYF(0),new_name);
+ error= -1;
+ }
+ else
+ {
+ *fn_ext(new_name)=0;
+ close_cached_table(thd,table);
+ if (mysql_rename_table(old_db_type,db,table_name,new_db,new_name))
+ error= -1;
+ }
+ VOID(pthread_cond_broadcast(&COND_refresh));
+ VOID(pthread_mutex_unlock(&LOCK_open));
}
- if (!error && (error=ha_commit_rename(thd)))
+ if (!error)
{
- my_error(ER_GET_ERRNO,MYF(0),error);
- error=1;
+ switch (keys_onoff)
+ {
+ case LEAVE_AS_IS: break;
+ case ENABLE:
+ error=table->file->activate_all_index(thd);
+ break;
+ case DISABLE:
+ table->file->deactivate_non_unique_index(HA_POS_ERROR);
+ break;
+ }
}
-
- VOID(pthread_cond_broadcast(&COND_refresh));
- VOID(pthread_mutex_unlock(&LOCK_open));
if (!error)
{
mysql_update_log.write(thd, thd->query, thd->query_length);
@@ -1227,7 +1278,6 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
send_ok(&thd->net);
}
-
DBUG_RETURN(error);
}
@@ -1257,7 +1307,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
{
/* Reset auto_increment value if it was dropped */
if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
- !(create_info->used_fields & HA_CREATE_USED_AUTO))
+ !(used_fields & HA_CREATE_USED_AUTO))
{
create_info->auto_increment_value=0;
create_info->used_fields|=HA_CREATE_USED_AUTO;
@@ -1282,8 +1332,11 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
def->field=field;
if (def->sql_type == FIELD_TYPE_TIMESTAMP)
use_timestamp=1;
- create_list.push_back(def);
- def_it.remove();
+ if (!def->after)
+ {
+ create_list.push_back(def);
+ def_it.remove();
+ }
}
else
{ // Use old field value
@@ -1314,7 +1367,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
List_iterator<create_field> find_it(create_list);
while ((def=def_it++)) // Add new columns
{
- if (def->change)
+ if (def->change && ! def->field)
{
my_error(ER_BAD_FIELD_ERROR,MYF(0),def->change,table_name);
DBUG_RETURN(-1);
@@ -1443,20 +1496,25 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
goto err;
}
+ db_create_options=table->db_create_options & ~(HA_OPTION_PACK_RECORD);
(void) sprintf(tmp_name,"%s-%lx_%lx", tmp_file_prefix, current_pid,
thd->thread_id);
create_info->db_type=new_db_type;
- if (!create_info->max_rows)
- create_info->max_rows=table->max_rows;
- if (!create_info->avg_row_length)
- create_info->avg_row_length=table->avg_row_length;
- table->file->update_create_info(create_info);
if (!create_info->comment)
create_info->comment=table->comment;
+
/* let new create options override the old ones */
- db_create_options=table->db_create_options & ~(HA_OPTION_PACK_RECORD);
- if (create_info->table_options &
- (HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS))
+ if (!(used_fields & HA_CREATE_USED_MIN_ROWS))
+ create_info->min_rows=table->min_rows;
+ if (!(used_fields & HA_CREATE_USED_MAX_ROWS))
+ create_info->max_rows=table->max_rows;
+ if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH))
+ create_info->avg_row_length=table->avg_row_length;
+
+ table->file->update_create_info(create_info);
+ if ((create_info->table_options &
+ (HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS)) ||
+ (used_fields & HA_CREATE_USED_PACK_KEYS))
db_create_options&= ~(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS);
if (create_info->table_options &
(HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM))
@@ -1470,6 +1528,53 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (table->tmp_table)
create_info->options|=HA_LEX_CREATE_TMP_TABLE;
+ /*
+ Handling of symlinked tables:
+ If no rename:
+ Create new data file and index file on the same disk as the
+ old data and index files.
+ Copy data.
+ Rename new data file over old data file and new index file over
+ old index file.
+ Symlinks are not changed.
+
+ If rename:
+ Create new data file and index file on the same disk as the
+ old data and index files. Create also symlinks to point at
+ the new tables.
+ Copy data.
+ At end, rename temporary tables and symlinks to temporary table
+ to final table name.
+ Remove old table and old symlinks
+
+ If rename is made to another database:
+ Create new tables in new database.
+ Copy data.
+ Remove old table and symlinks.
+ */
+
+ if (!strcmp(db, new_db)) // Ignore symlink if db changed
+ {
+ if (create_info->index_file_name)
+ {
+ /* Fix index_file_name to have 'tmp_name' as basename */
+ strmov(index_file, tmp_name);
+ create_info->index_file_name=fn_same(index_file,
+ create_info->index_file_name,
+ 1);
+ }
+ if (create_info->data_file_name)
+ {
+ /* Fix data_file_name to have 'tmp_name' as basename */
+ strmov(data_file, tmp_name);
+ create_info->data_file_name=fn_same(data_file,
+ create_info->data_file_name,
+ 1);
+ }
+ }
+ else
+ create_info->data_file_name=create_info->index_file_name=0;
+
if ((error=mysql_create_table(thd, new_db, tmp_name,
create_info,
create_list,key_list,1,1))) // no logging
@@ -1608,24 +1713,30 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
if (error)
{
- // This shouldn't happen. We solve this the safe way by
- // closing the locked table.
+ /*
+ This shouldn't happen. We solve this the safe way by
+ closing the locked table.
+ */
close_cached_table(thd,table);
VOID(pthread_mutex_unlock(&LOCK_open));
goto err;
}
if (thd->lock || new_name != table_name) // True if WIN32
{
- // Not table locking or alter table with rename
- // free locks and remove old table
+ /*
+ Not table locking or alter table with rename
+ free locks and remove old table
+ */
close_cached_table(thd,table);
VOID(quick_rm_table(old_db_type,db,old_name));
}
else
{
- // Using LOCK TABLES without rename.
- // This code is never executed on WIN32!
- // Remove old renamed table, reopen table and get new locks
+ /*
+ Using LOCK TABLES without rename.
+ This code is never executed on WIN32!
+ Remove old renamed table, reopen table and get new locks
+ */
if (table)
{
VOID(table->file->extra(HA_EXTRA_FORCE_REOPEN)); // Use new file
@@ -1662,6 +1773,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
VOID(pthread_cond_broadcast(&COND_refresh));
VOID(pthread_mutex_unlock(&LOCK_open));
+ table_list->table=0; // For query cache
+ query_cache.invalidate(table_list);
end_temporary:
sprintf(tmp_name,ER(ER_INSERT_INFO),(ulong) (copied+deleted),
@@ -1671,7 +1784,6 @@ end_temporary:
DBUG_RETURN(0);
err:
- (void) ha_commit_rename(thd); // Just for safety
DBUG_RETURN(-1);
}
@@ -1730,8 +1842,8 @@ copy_data_between_tables(TABLE *from,TABLE *to,
if (setup_order(thd, &tables, fields, all_fields, order) ||
!(sortorder=make_unireg_sortorder(order, &length)) ||
- (from->found_records = filesort(&from, sortorder, length,
- (SQL_SELECT *) 0, 0L, HA_POS_ERROR,
+ (from->found_records = filesort(from, sortorder, length,
+ (SQL_SELECT *) 0, 0L, HA_POS_ERROR,
&examined_rows))
== HA_POS_ERROR)
goto err;
@@ -1781,7 +1893,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
}
end_read_record(&info);
free_io_cache(from);
- delete [] copy;
+ delete [] copy; // This is never 0
uint tmp_error;
if ((tmp_error=to->file->extra(HA_EXTRA_NO_CACHE)))
{
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
index c4c2855a63e..43c24da85a2 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -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 */
@@ -96,8 +96,7 @@ void print_cached_tables(void)
}
-void TEST_filesort(TABLE **table,SORT_FIELD *sortorder,uint s_length,
- ha_rows special)
+void TEST_filesort(SORT_FIELD *sortorder,uint s_length, ha_rows special)
{
char buff[256],buff2[256];
String str(buff,sizeof(buff)),out(buff2,sizeof(buff2));
diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc
index 8184ae3b15e..9493f969802 100644
--- a/sql/sql_udf.cc
+++ b/sql/sql_udf.cc
@@ -1,21 +1,19 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
+/* 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 implements 'user defined functions' */
/*
@@ -52,11 +50,11 @@ extern "C"
{
FreeLibrary((HMODULE)lib);
}
-
+
#elif !defined(OS2)
#include <dlfcn.h>
#endif
-
+
#include <stdarg.h>
#include <hash.h>
}
@@ -141,7 +139,8 @@ void udf_init()
new_thd->version = refresh_version; //current_thd->version;
new_thd->current_tablenr = 0;
new_thd->open_tables = 0;
- new_thd->db = my_strdup("mysql", MYF(0));
+ new_thd->db= my_strdup("mysql", MYF(0));
+ new_thd->db_length=5;
bzero((gptr) &tables,sizeof(tables));
tables.name = tables.real_name = (char*) "func";
diff --git a/sql/sql_udf.h b/sql/sql_udf.h
index d0b20f0a734..1ee9c44ce48 100644
--- a/sql/sql_udf.h
+++ b/sql/sql_udf.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 */
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
new file mode 100644
index 00000000000..82a88633b69
--- /dev/null
+++ b/sql/sql_union.cc
@@ -0,0 +1,260 @@
+/* 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 */
+
+
+/*
+ UNION of select's
+ UNION's were introduced by Monty and Sinisa <sinisa@mysql.com>
+*/
+
+
+#include "mysql_priv.h"
+#include "sql_select.h"
+
+
+int mysql_union(THD *thd, LEX *lex,select_result *result)
+{
+ SELECT_LEX *sl, *last_sl, *lex_sl;
+ ORDER *order;
+ List<Item> item_list;
+ TABLE *table;
+ int describe=(lex->select_lex.options & SELECT_DESCRIBE) ? 1 : 0;
+ int res;
+ TABLE_LIST result_table_list;
+ TMP_TABLE_PARAM tmp_table_param;
+ select_union *union_result;
+ DBUG_ENTER("mysql_union");
+
+ /* Fix tables 'to-be-unioned-from' list to point at opened tables */
+ last_sl= &lex->select_lex;
+ for (sl= last_sl;
+ sl && sl->linkage != NOT_A_SELECT;
+ last_sl=sl, sl=sl->next)
+ {
+ for (TABLE_LIST *cursor= (TABLE_LIST *)sl->table_list.first;
+ cursor;
+ cursor=cursor->next)
+ cursor->table= ((TABLE_LIST*) cursor->table)->table;
+ }
+
+ /* last_sel now points at the last select where the ORDER BY is stored */
+ if (sl)
+ {
+ /*
+ The found SL is an extra SELECT_LEX argument that contains
+ the ORDER BY and LIMIT parameter for the whole UNION
+ */
+ lex_sl= sl;
+ last_sl->next=0; // Remove this extra element
+ order= (ORDER *) lex_sl->order_list.first;
+ }
+ else if (!last_sl->braces)
+ {
+ lex_sl= last_sl; // ORDER BY is here
+ order= (ORDER *) lex_sl->order_list.first;
+ }
+ else
+ {
+ lex_sl=0;
+ order=0;
+ }
+
+ if (describe)
+ {
+ Item *item;
+ item_list.push_back(new Item_empty_string("table",NAME_LEN));
+ item_list.push_back(new Item_empty_string("type",10));
+ item_list.push_back(item=new Item_empty_string("possible_keys",
+ NAME_LEN*MAX_KEY));
+ item->maybe_null=1;
+ item_list.push_back(item=new Item_empty_string("key",NAME_LEN));
+ item->maybe_null=1;
+ item_list.push_back(item=new Item_int("key_len",0,3));
+ item->maybe_null=1;
+ item_list.push_back(item=new Item_empty_string("ref",
+ NAME_LEN*MAX_REF_PARTS));
+ item->maybe_null=1;
+ item_list.push_back(new Item_real("rows",0.0,0,10));
+ item_list.push_back(new Item_empty_string("Extra",255));
+ }
+ else
+ {
+ Item *item;
+ List_iterator<Item> it(lex->select_lex.item_list);
+ TABLE_LIST *first_table= (TABLE_LIST*) lex->select_lex.table_list.first;
+
+ /* Create a list of items that will be in the result set */
+ while ((item= it++))
+ if (item_list.push_back(item))
+ DBUG_RETURN(-1);
+ if (setup_fields(thd,first_table,item_list,0,0,1))
+ DBUG_RETURN(-1);
+ }
+
+ bzero((char*) &tmp_table_param,sizeof(tmp_table_param));
+ tmp_table_param.field_count=item_list.elements;
+ if (!(table=create_tmp_table(thd, &tmp_table_param, item_list,
+ (ORDER*) 0, !describe & !lex->union_option,
+ 1, 0,
+ (lex->select_lex.options | thd->options |
+ TMP_TABLE_ALL_COLUMNS))))
+ DBUG_RETURN(-1);
+ table->file->extra(HA_EXTRA_WRITE_CACHE);
+ 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.name=(char*) "union";
+ result_table_list.table=table;
+
+ if (!(union_result=new select_union(table)))
+ {
+ res= -1;
+ goto exit;
+ }
+ union_result->save_time_stamp=!describe;
+
+ for (sl= &lex->select_lex; sl; sl=sl->next)
+ {
+ lex->select=sl;
+ thd->offset_limit=sl->offset_limit;
+ thd->select_limit=sl->select_limit+sl->offset_limit;
+ if (thd->select_limit < sl->select_limit)
+ thd->select_limit= HA_POS_ERROR; // no limit
+ if (thd->select_limit == HA_POS_ERROR)
+ sl->options&= ~OPTION_FOUND_ROWS;
+
+ res=mysql_select(thd, (TABLE_LIST*) sl->table_list.first,
+ sl->item_list,
+ sl->where,
+ (sl->braces) ? (ORDER *)sl->order_list.first : (ORDER *) 0,
+ (ORDER*) sl->group_list.first,
+ sl->having,
+ (ORDER*) NULL,
+ sl->options | thd->options | SELECT_NO_UNLOCK | ((describe) ? SELECT_DESCRIBE : 0),
+ union_result);
+ if (res)
+ goto exit;
+ }
+ if (union_result->flush())
+ {
+ res= 1; // Error is already sent
+ goto exit;
+ }
+ delete union_result;
+
+ /* Send result to 'result' */
+ lex->select = &lex->select_lex;
+ res =-1;
+ {
+ /* Create a list of fields in the temporary table */
+ List_iterator<Item> it(item_list);
+ Field **field;
+#if 0
+ List<Item_func_match> ftfunc_list;
+ ftfunc_list.empty();
+#else
+ thd->lex.select_lex.ftfunc_list.empty();
+#endif
+
+ for (field=table->field ; *field ; field++)
+ {
+ (void) it++;
+ (void) it.replace(new Item_field(*field));
+ }
+ if (!thd->fatal_error) // Check if EOM
+ {
+ if (lex_sl)
+ {
+ thd->offset_limit=lex_sl->offset_limit;
+ thd->select_limit=lex_sl->select_limit+lex_sl->offset_limit;
+ if (thd->select_limit < lex_sl->select_limit)
+ thd->select_limit= HA_POS_ERROR; // no limit
+ if (thd->select_limit == HA_POS_ERROR)
+ thd->options&= ~OPTION_FOUND_ROWS;
+ }
+ if (describe)
+ thd->select_limit= HA_POS_ERROR; // no limit
+ res=mysql_select(thd,&result_table_list,
+ item_list, NULL, /*ftfunc_list,*/ order,
+ (ORDER*) NULL, NULL, (ORDER*) NULL,
+ thd->options, result);
+ }
+ }
+
+exit:
+ free_tmp_table(thd,table);
+ DBUG_RETURN(res);
+}
+
+
+/***************************************************************************
+** store records in temporary table for UNION
+***************************************************************************/
+
+select_union::select_union(TABLE *table_par)
+ :table(table_par)
+{
+ bzero((char*) &info,sizeof(info));
+ /*
+ We can always use DUP_IGNORE because the temporary table will only
+ contain a unique key if we are using not using UNION ALL
+ */
+ info.handle_duplicates=DUP_IGNORE;
+}
+
+select_union::~select_union()
+{
+}
+
+
+int select_union::prepare(List<Item> &list)
+{
+ if (save_time_stamp && list.elements != table->fields)
+ {
+ my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,
+ ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),MYF(0));
+ return -1;
+ }
+ return 0;
+}
+
+bool select_union::send_data(List<Item> &values)
+{
+ if (thd->offset_limit)
+ { // using limit offset,count
+ thd->offset_limit--;
+ return 0;
+ }
+ fill_record(table->field,values);
+ return write_record(table,&info) ? 1 : 0;
+}
+
+bool select_union::send_eof()
+{
+ return 0;
+}
+
+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->net);
+ return 1;
+ }
+ return 0;
+}
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index e5e246b3962..6c868b542d1 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -1,24 +1,29 @@
/* 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 of records */
+/* Update of records
+
+ Multi-table updates were introduced by Monty and Sinisa <sinisa@mysql.com>
+
+*/
#include "mysql_priv.h"
#include "sql_acl.h"
+#include "sql_select.h"
/* Return 0 if row hasn't changed */
@@ -40,8 +45,12 @@ static bool compare_record(TABLE *table, ulong query_id)
}
-int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields,
- List<Item> &values, COND *conds,
+int mysql_update(THD *thd,
+ TABLE_LIST *table_list,
+ List<Item> &fields,
+ List<Item> &values,
+ COND *conds,
+ ORDER *order,
ha_rows limit,
enum enum_duplicates handle_duplicates,
thr_lock_type lock_type)
@@ -87,7 +96,7 @@ int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields,
/* Check the fields we are going to modify */
table->grant.want_privilege=want_privilege;
- if (setup_fields(thd,table_list,fields,1,0))
+ if (setup_fields(thd,table_list,fields,1,0,0))
DBUG_RETURN(-1); /* purecov: inspected */
if (table->timestamp_field)
{
@@ -100,7 +109,7 @@ int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields,
/* Check values */
table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
- if (setup_fields(thd,table_list,values,0,0))
+ if (setup_fields(thd,table_list,values,0,0,0))
{
table->time_stamp=save_time_stamp; // Restore timestamp pointer
DBUG_RETURN(-1); /* purecov: inspected */
@@ -126,7 +135,7 @@ int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields,
/* If running in safe sql mode, don't allow updates without keys */
if (!table->quick_keys)
{
- thd->lex.options|=QUERY_NO_INDEX_USED;
+ thd->lex.select_lex.options|=QUERY_NO_INDEX_USED;
if ((thd->options & OPTION_SAFE_UPDATES) && limit == HA_POS_ERROR)
{
delete select;
@@ -146,7 +155,7 @@ int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields,
used_key_is_modified=check_if_key_used(table, used_index, fields);
else
used_key_is_modified=0;
- if (used_key_is_modified)
+ if (used_key_is_modified || order)
{
/*
** We can't update table directly; We must first search after all
@@ -166,8 +175,36 @@ int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields,
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
}
+
+ if (order)
+ {
+ uint length;
+ SORT_FIELD *sortorder;
+ TABLE_LIST tables;
+ List<Item> fields;
+ List<Item> all_fields;
+ ha_rows examined_rows;
+
+ bzero((char*) &tables,sizeof(tables));
+ tables.table = table;
+
+ table->io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
+ MYF(MY_FAE | MY_ZEROFILL));
+ if (setup_order(thd, &tables, fields, all_fields, order) ||
+ !(sortorder=make_unireg_sortorder(order, &length)) ||
+ (table->found_records = filesort(table, sortorder, length,
+ (SQL_SELECT *) 0, 0L,
+ HA_POS_ERROR, &examined_rows))
+ == HA_POS_ERROR)
+ {
+ delete select;
+ table->time_stamp=save_time_stamp; // Restore timestamp pointer
+ DBUG_RETURN(-1);
+ }
+ }
+
init_read_record(&info,thd,table,select,0,1);
- thd->proc_info="searching";
+ thd->proc_info="Searching rows for update";
while (!(error=info.read_record(&info)) && !thd->killed)
{
@@ -183,7 +220,7 @@ int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields,
}
else
{
- if (!(test_flags & 512)) /* For debugging */
+ if (!(test_flags & 512)) /* For debugging */
{
DBUG_DUMP("record",(char*) table->record[0],table->reclength);
}
@@ -205,7 +242,7 @@ int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields,
select->cond=0;
}
else
- {
+ {
select= new SQL_SELECT;
select->head=table;
}
@@ -216,12 +253,10 @@ int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields,
{
delete select;
table->time_stamp=save_time_stamp; // Restore timestamp pointer
- DBUG_RETURN(-1);
+ DBUG_RETURN(-1);
}
}
- if (!(test_flags & TEST_READCHECK)) /* For debugging */
- VOID(table->file->extra(HA_EXTRA_NO_READCHECK));
if (handle_duplicates == DUP_IGNORE)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
init_read_record(&info,thd,table,select,0,1);
@@ -229,7 +264,7 @@ int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields,
ha_rows updated=0L,found=0L;
thd->count_cuted_fields=1; /* calc cuted fields */
thd->cuted_fields=0L;
- thd->proc_info="updating";
+ thd->proc_info="Updating";
query_id=thd->query_id;
while (!(error=info.read_record(&info)) && !thd->killed)
@@ -266,7 +301,6 @@ int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields,
}
end_read_record(&info);
thd->proc_info="end";
- VOID(table->file->extra(HA_EXTRA_READCHECK));
VOID(table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY));
table->time_stamp=save_time_stamp; // Restore auto timestamp pointer
using_transactions=table->file->has_transactions();
@@ -289,6 +323,8 @@ int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields,
mysql_unlock_tables(thd, thd->lock);
thd->lock=0;
}
+ if (updated)
+ query_cache.invalidate(table_list);
delete select;
if (error >= 0)
send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN : 0); /* purecov: inspected */
@@ -303,5 +339,459 @@ int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields,
DBUG_PRINT("info",("%d records updated",updated));
}
thd->count_cuted_fields=0; /* calc cuted fields */
+ free_io_cache(table);
+ DBUG_RETURN(0);
+}
+
+/***************************************************************************
+** update multiple tables from join
+***************************************************************************/
+
+multi_update::multi_update(THD *thd_arg, TABLE_LIST *ut, List<Item> &fs,
+ enum enum_duplicates handle_duplicates, thr_lock_type lock_option_arg, uint num)
+ : update_tables (ut), thd(thd_arg), updated(0), found(0), fields(fs), lock_option(lock_option_arg),
+ dupl(handle_duplicates), num_of_tables(num), num_fields(0), num_updated(0) , error(0), do_update(false)
+{
+ save_time_stamps = (uint *) sql_calloc (sizeof(uint) * num_of_tables);
+ tmp_tables = (TABLE **)NULL;
+ int counter=0;
+ ulong timestamp_query_id;
+ not_trans_safe=false;
+ for (TABLE_LIST *dt=ut ; dt ; dt=dt->next,counter++)
+ {
+ TABLE *table=ut->table;
+// (void) ut->table->file->extra(HA_EXTRA_NO_KEYREAD);
+ dt->table->used_keys=0;
+ if (table->timestamp_field)
+ {
+ // Don't set timestamp column if this is modified
+ timestamp_query_id=table->timestamp_field->query_id;
+ table->timestamp_field->query_id=thd->query_id-1;
+ if (table->timestamp_field->query_id == thd->query_id)
+ table->time_stamp=0;
+ else
+ table->timestamp_field->query_id=timestamp_query_id;
+ }
+ save_time_stamps[counter]=table->time_stamp;
+ }
+ error = 1; // In case we do not reach prepare we have to reset timestamps
+}
+
+int
+multi_update::prepare(List<Item> &values)
+{
+ DBUG_ENTER("multi_update::prepare");
+ do_update = true;
+ thd->count_cuted_fields=1;
+ thd->cuted_fields=0L;
+ thd->proc_info="updating the main table";
+ TABLE_LIST *table_ref;
+
+ if (thd->options & OPTION_SAFE_UPDATES)
+ {
+ for (table_ref=update_tables; table_ref; table_ref=table_ref->next)
+ {
+ TABLE *table=table_ref->table;
+ if ((thd->options & OPTION_SAFE_UPDATES) && !table->quick_keys)
+ {
+ my_error(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,MYF(0));
+ DBUG_RETURN(1);
+ }
+ }
+ }
+// Here I have to connect fields with tables and only update tables that need to be updated ...
+
+// I calculate num_updated and fill-up table_sequence
+// Set table_list->shared to true or false, depending on whether table is to be updated or not
+ Item_field *item;
+ List_iterator<Item> it(fields);
+ num_fields=fields.elements;
+ field_sequence = (uint *) sql_alloc(sizeof(uint)*num_fields);
+ uint *int_ptr=field_sequence;
+ while ((item= (Item_field *)it++))
+ {
+ unsigned int counter=0;
+ for (table_ref=update_tables; table_ref; table_ref=table_ref->next, counter++)
+ {
+ if (table_ref->table == item->field->table && !table_ref->shared)
+ {
+ num_updated++;
+ table_ref->shared=1;
+ if (!not_trans_safe && !table_ref->table->file->has_transactions())
+ not_trans_safe=true;
+ table_ref->table->no_keyread=1; // to be moved if initialize_tables has to be used
+ break;
+ }
+ }
+ if (!table_ref)
+ {
+ error = 1; // A proper error message is due here
+ DBUG_RETURN(1);
+ }
+ else
+ *int_ptr++=counter;
+ }
+ if (!num_updated)
+ {
+ error = 1; // A proper error message is due here
+ DBUG_RETURN(1);
+ }
+
+// Here, I have to allocate the array of temporary tables
+// I have to treat a case of num_updated=1 differently in send_data() method.
+ if (num_updated > 1)
+ {
+ tmp_tables = (TABLE **) sql_calloc(sizeof(TABLE *) * (num_updated - 1));
+ infos = (COPY_INFO *) sql_calloc(sizeof(COPY_INFO) * (num_updated - 1));
+ fields_by_tables = (List_item **)sql_calloc(sizeof(List_item *) * num_updated);
+ unsigned int counter;
+ List<Item> *temp_fields;
+ for (table_ref=update_tables, counter = 0; table_ref; table_ref=table_ref->next)
+ {
+ if (!table_ref->shared)
+ continue;
+// Here we have to add row offset as an additional field ...
+ if (!(temp_fields = (List_item *)sql_calloc(sizeof(List_item))))
+ {
+ error = 1; // A proper error message is due here
+ DBUG_RETURN(1);
+ }
+ temp_fields->empty();
+ it.rewind(); int_ptr=field_sequence;
+ while ((item= (Item_field *)it++))
+ {
+ if (*int_ptr++ == counter)
+ temp_fields->push_back(item);
+ }
+ if (counter)
+ {
+ Field_string offset(table_ref->table->file->ref_length,false,"offset",table_ref->table,true);
+ temp_fields->push_front(new Item_field(((Field *)&offset)));
+// Here I make tmp tables
+ int cnt=counter-1;
+ TMP_TABLE_PARAM tmp_table_param;
+ bzero((char*) &tmp_table_param,sizeof(tmp_table_param));
+ tmp_table_param.field_count=temp_fields->elements;
+ if (!(tmp_tables[cnt]=create_tmp_table(thd, &tmp_table_param, *temp_fields,
+ (ORDER*) 0, 1, 0, 0, TMP_TABLE_ALL_COLUMNS)))
+ {
+ error = 1; // A proper error message is due here
+ DBUG_RETURN(1);
+ }
+ tmp_tables[cnt]->file->extra(HA_EXTRA_WRITE_CACHE);
+ tmp_tables[cnt]->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
+ infos[cnt].handle_duplicates=DUP_IGNORE;
+ temp_fields->pop(); // because we shall use those for values only ...
+ }
+ fields_by_tables[counter]=temp_fields;
+ counter++;
+ }
+ }
+ error = 0; // Timestamps do not need to be restored, so far ...
DBUG_RETURN(0);
}
+
+
+void
+multi_update::initialize_tables(JOIN *join)
+{
+/* We skip it as it only makes a mess ...........
+ TABLE_LIST *walk;
+ table_map tables_to_update_from=0;
+ for (walk= update_tables ; walk ; walk=walk->next)
+ tables_to_update_from|= walk->table->map;
+
+ walk= update_tables;
+ for (JOIN_TAB *tab=join->join_tab, *end=join->join_tab+join->tables;
+ tab < end;
+ tab++)
+ {
+ if (tab->table->map & tables_to_update_from)
+ {
+ We are going to update from this table
+ walk->table=tab->table;
+ walk=walk->next;
+ if (tab == join->join_tab)
+ tab->table->no_keyread=1;
+ }
+ }
+*/
+}
+
+
+multi_update::~multi_update()
+{
+ int counter = 0;
+ for (table_being_updated=update_tables ;
+ table_being_updated ;
+ counter++, table_being_updated=table_being_updated->next)
+ {
+ TABLE *table=table_being_updated->table;
+ table->no_keyread=0;
+ if (error)
+ table->time_stamp=save_time_stamps[counter];
+ }
+ if (tmp_tables)
+ for (uint counter = 0; counter < num_updated-1; counter++)
+ if (tmp_tables[counter])
+ free_tmp_table(thd,tmp_tables[counter]);
+}
+
+
+bool multi_update::send_data(List<Item> &values)
+{
+ List<Item> real_values(values);
+ for (uint counter = 0; counter < fields.elements; counter++)
+ real_values.pop();
+// We have skipped fields ....
+ if (num_updated == 1)
+ {
+ for (table_being_updated=update_tables ;
+ table_being_updated ;
+ table_being_updated=table_being_updated->next)
+ {
+ if (!table_being_updated->shared)
+ continue;
+ TABLE *table=table_being_updated->table;
+ /* Check if we are using outer join and we didn't find the row */
+ if (table->status & (STATUS_NULL_ROW | STATUS_UPDATED))
+ return 0;
+ table->file->position(table->record[0]);
+// Only one table being updated receives a completely different treatment
+ table->status|= STATUS_UPDATED;
+ store_record(table,1);
+ if (fill_record(fields,real_values))
+ return 1;
+ found++;
+ if (/* compare_record(table, query_id) && */
+ !(error=table->file->update_row(table->record[1], table->record[0])))
+ updated++;
+ return error;
+ }
+ }
+ else
+ {
+ int secure_counter= -1;
+ for (table_being_updated=update_tables ;
+ table_being_updated ;
+ table_being_updated=table_being_updated->next, secure_counter++)
+ {
+ if (!table_being_updated->shared)
+ continue;
+
+ TABLE *table=table_being_updated->table;
+ /* Check if we are using outer join and we didn't find the row */
+ if (table->status & (STATUS_NULL_ROW | STATUS_UPDATED))
+ continue;
+ table->file->position(table->record[0]);
+ Item *item;
+ List_iterator<Item> it(real_values);
+ List <Item> values_by_table;
+ uint *int_ptr=field_sequence;
+ while ((item= (Item *)it++))
+ {
+ if (*int_ptr++ == (uint) (secure_counter + 1))
+ values_by_table.push_back(item);
+ }
+// Here I am breaking values as per each table
+ if (secure_counter < 0)
+ {
+ table->status|= STATUS_UPDATED;
+ store_record(table,1);
+ if (fill_record(*fields_by_tables[0],values_by_table))
+ return 1;
+ found++;
+ if (/*compare_record(table, query_id) && */
+ !(error=table->file->update_row(table->record[1], table->record[0])))
+ updated++;
+ else
+ {
+ table->file->print_error(error,MYF(0));
+ if (!error) error=1;
+ return 1;
+ }
+ }
+ else
+ {
+ // Here we insert into each temporary table
+ values_by_table.push_front(new Item_string((char*) table->file->ref,
+ table->file->ref_length));
+ fill_record(tmp_tables[secure_counter]->field,values_by_table);
+ error= write_record(tmp_tables[secure_counter],
+ &(infos[secure_counter]));
+ if (error)
+ {
+ error=-1;
+ return 1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+void multi_update::send_error(uint errcode,const char *err)
+{
+ /* First send error what ever it is ... */
+ ::send_error(&thd->net,errcode,err);
+
+ /* reset used flags */
+// update_tables->table->no_keyread=0;
+
+ /* If nothing updated return */
+ if (!updated)
+ return;
+ /* Below can happen when thread is killed early ... */
+ if (!table_being_updated)
+ table_being_updated=update_tables;
+
+ /*
+ If rows from the first table only has been updated and it is transactional,
+ just do rollback.
+ The same if all tables are transactional, regardless of where we are.
+ In all other cases do attempt updates ...
+ */
+ if ((table_being_updated->table->file->has_transactions() &&
+ table_being_updated == update_tables) || !not_trans_safe)
+ ha_rollback_stmt(thd);
+ else if (do_update)
+ VOID(do_updates(true));
+}
+
+
+int multi_update::do_updates (bool from_send_error)
+{
+ int error = 0, counter = 0;
+
+ if (num_updated == 1)
+ return 0;
+ if (from_send_error)
+ {
+ /* Found out table number for 'table_being_updated' */
+ for (TABLE_LIST *aux=update_tables;
+ aux != table_being_updated;
+ aux=aux->next)
+ counter++;
+ }
+ else
+ table_being_updated = update_tables;
+
+ do_update = false;
+ for (table_being_updated=table_being_updated->next;
+ table_being_updated ;
+ table_being_updated=table_being_updated->next, counter++)
+ {
+ if (!table_being_updated->shared)
+ continue;
+
+ TABLE *table = table_being_updated->table;
+ TABLE *tmp_table=tmp_tables[counter];
+ if (tmp_table->file->extra(HA_EXTRA_NO_CACHE))
+ {
+ error=1;
+ break;
+ }
+ List<Item> list;
+ Field **ptr=tmp_table->field,*field;
+ // This is supposed to be something like insert_fields
+ thd->used_tables|=tmp_table->map;
+ while ((field = *ptr++))
+ {
+ list.push_back((Item *)new Item_field(field));
+ if (field->query_id == thd->query_id)
+ thd->dupp_field=field;
+ field->query_id=thd->query_id;
+ tmp_table->used_keys&=field->part_of_key;
+ }
+ tmp_table->used_fields=tmp_table->fields;
+ error=0; list.pop(); // we get position some other way ...
+ error = tmp_table->file->rnd_init(1);
+ if (error)
+ return error;
+ while (!(error=tmp_table->file->rnd_next(tmp_table->record[0])) &&
+ (!thd->killed || from_send_error || not_trans_safe))
+ {
+ found++;
+ error= table->file->rnd_pos(table->record[0],
+ (byte*) (*(tmp_table->field))->ptr);
+ if (error)
+ return error;
+ table->status|= STATUS_UPDATED;
+ store_record(table,1);
+ error= fill_record(*fields_by_tables[counter + 1],list) ||
+ /* compare_record(table, query_id) || */
+ table->file->update_row(table->record[1],table->record[0]);
+ if (error)
+ {
+ table->file->print_error(error,MYF(0));
+ break;
+ }
+ else
+ updated++;
+ }
+ if (error == HA_ERR_END_OF_FILE)
+ error = 0;
+ }
+ return error;
+}
+
+
+/* out: 1 if error, 0 if success */
+
+bool multi_update::send_eof()
+{
+ thd->proc_info="updating the reference tables";
+
+ /* Does updates for the last n - 1 tables, returns 0 if ok */
+ int error = do_updates(false); /* do_updates returns 0 if success */
+
+ /* reset used flags */
+#ifndef NOT_USED
+ update_tables->table->no_keyread=0;
+#endif
+ if (error == -1)
+ error = 0;
+ thd->proc_info="end";
+ if (error)
+ send_error(error,"An error occured in multi-table update");
+
+ /*
+ Write the SQL statement to the binlog if we updated
+ rows and we succeeded, or also in an error case when there
+ was a non-transaction-safe table involved, since
+ modifications in it cannot be rolled back.
+ */
+
+ if (updated || not_trans_safe)
+ {
+ mysql_update_log.write(thd,thd->query,thd->query_length);
+ Query_log_event qinfo(thd, thd->query);
+
+ /*
+ mysql_bin_log is not open if binlogging or replication
+ is not used
+ */
+
+ if (mysql_bin_log.is_open() && mysql_bin_log.write(&qinfo) &&
+ !not_trans_safe)
+ error=1; /* Log write failed: roll back the SQL statement */
+
+ /* Commit or rollback the current SQL statement */
+ VOID(ha_autocommit_or_rollback(thd,error > 0));
+ }
+ else
+ error=0; // this can happen only if it is end of file error
+ if (!error) // if the above log write did not fail ...
+ {
+ char buff[80];
+ sprintf(buff,ER(ER_UPDATE_INFO), (long) found, (long) updated,
+ (long) thd->cuted_fields);
+ if (updated)
+ query_cache.invalidate(update_tables);
+ ::send_ok(&thd->net,
+ (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
+ thd->insert_id_used ? thd->insert_id() : 0L,buff);
+ }
+ thd->count_cuted_fields=0;
+ return 0;
+}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 0cbf6f45194..83a21b03ac4 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2001 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
@@ -21,11 +21,13 @@
#define YYINITDEPTH 100
#define YYMAXDEPTH 3200 /* Because of 64K stack */
#define Lex current_lex
+#define Select Lex->select
#include "mysql_priv.h"
-#include "slave.h"
+#include "slave.h"
#include "sql_acl.h"
#include "lex_symbol.h"
#include <myisam.h>
+#include <myisammrg.h>
extern void yyerror(const char*);
int yylex(void *yylval);
@@ -42,7 +44,7 @@ inline Item *or_or_concat(Item* A, Item* B)
%union {
int num;
ulong ulong_num;
- ulonglong ulonglong_num;
+ ulonglong ulonglong_number;
LEX_STRING lex_str;
LEX_STRING *lex_str_ptr;
LEX_SYMBOL symbol;
@@ -54,7 +56,9 @@ inline Item *or_or_concat(Item* A, Item* B)
Key::Keytype key_type;
enum db_type db_type;
enum row_type row_type;
+ enum ha_rkey_function ha_rkey_mode;
enum enum_tx_isolation tx_isolation;
+ enum Item_cast cast_type;
String *string;
key_part_spec *key_part;
TABLE_LIST *table_list;
@@ -72,6 +76,13 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token END_OF_INPUT
+%token CLOSE_SYM
+%token HANDLER_SYM
+%token LAST_SYM
+%token NEXT_SYM
+%token PREV_SYM
+%token SQL_CALC_FOUND_ROWS
+
%token EQ
%token EQUAL_SYM
%token GE
@@ -90,7 +101,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token MIN_SYM
%token SUM_SYM
%token STD_SYM
-
+%token ABORT_SYM
%token ADD
%token ALTER
%token AFTER_SYM
@@ -112,6 +123,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token RESET_SYM
%token PURGE
%token SLAVE
+%token IO_THREAD
+%token SQL_THREAD
%token START_SYM
%token STOP_SYM
%token TRUNCATE_SYM
@@ -124,6 +137,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token LOCK_SYM
%token LOCKS_SYM
%token UNLOCK_SYM
+%token BINLOG_SYM
+%token EVENTS_SYM
%token ACTION
%token AGGREGATE_SYM
@@ -139,27 +154,37 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token BINARY
%token BIT_SYM
%token BOOL_SYM
+%token BOOLEAN_SYM
%token BOTH
%token BY
+%token CACHE_SYM
%token CASCADE
+%token CAST_SYM
%token CHECKSUM_SYM
%token CHECK_SYM
+%token CIPHER
%token COMMITTED_SYM
%token COLUMNS
%token COLUMN_SYM
%token CONCURRENT
%token CONSTRAINT
+%token CONVERT_SYM
%token DATABASES
%token DATA_SYM
%token DEFAULT
%token DELAYED_SYM
%token DELAY_KEY_WRITE_SYM
+%token DEMAND_SYM
%token DESC
%token DESCRIBE
+%token DES_KEY_FILE
+%token DISABLE_SYM
%token DISTINCT
%token DYNAMIC_SYM
+%token ENABLE_SYM
%token ENCLOSED
%token ESCAPED
+%token DIRECTORY_SYM
%token ESCAPE_SYM
%token EXISTS
%token EXTENDED_SYM
@@ -171,8 +196,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token FROM
%token FULL
%token FULLTEXT_SYM
-%token GEMINI_SYM
-%token GEMINI_SPIN_RETRIES
%token GLOBAL_SYM
%token GRANT
%token GRANTS
@@ -186,6 +209,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token IDENT
%token IGNORE_SYM
%token INDEX
+%token INDEXES
%token INFILE
%token INNER_SYM
%token INNOBASE_SYM
@@ -193,6 +217,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token IN_SYM
%token ISOLATION
%token ISAM_SYM
+%token ISSUER
%token JOIN_SYM
%token KEYS
%token KEY_SYM
@@ -211,22 +236,27 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token MASTER_USER_SYM
%token MASTER_LOG_FILE_SYM
%token MASTER_LOG_POS_SYM
+%token MASTER_LOG_SEQ_SYM
%token MASTER_PASSWORD_SYM
%token MASTER_PORT_SYM
%token MASTER_CONNECT_RETRY_SYM
+%token MASTER_SERVER_ID_SYM
%token MATCH
%token MAX_ROWS
+%token MAX_QUERIES_PER_HOUR
%token MEDIUM_SYM
%token MERGE_SYM
%token MIN_ROWS
%token MYISAM_SYM
%token NATIONAL_SYM
%token NATURAL
+%token NEW_SYM
%token NCHAR_SYM
%token NOT
%token NO_SYM
%token NULL_SYM
%token NUM
+%token OFF
%token ON
%token OPEN_SYM
%token OPTION
@@ -243,6 +273,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token PRIVILEGES
%token PROCESS
%token PROCESSLIST_SYM
+%token QUERY_SYM
%token RAID_0_SYM
%token RAID_STRIPED_SYM
%token RAID_TYPE
@@ -255,6 +286,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token RELOAD
%token RENAME
%token REPEATABLE_SYM
+%token REQUIRE_SYM
%token RESTORE_SYM
%token RESTRICT
%token REVOKE
@@ -265,9 +297,13 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token SERIALIZABLE_SYM
%token SESSION_SYM
%token SHUTDOWN
+%token SQL_CACHE_SYM
+%token SQL_NO_CACHE_SYM
+%token SSL_SYM
%token STARTING
%token STATUS_SYM
%token STRAIGHT_JOIN
+%token SUBJECT_SYM
%token TABLES
%token TABLE_SYM
%token TEMPORARY
@@ -288,6 +324,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token UNION_SYM
%token UNIQUE_SYM
%token USAGE
+%token USE_FRM
%token USE_SYM
%token USING
%token VALUES
@@ -295,6 +332,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token WHERE
%token WITH
%token WRITE_SYM
+%token X509_SYM
%token COMPRESSED_SYM
%token BIGINT
@@ -320,6 +358,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token PRECISION
%token QUICK
%token REAL
+%token SIGNED_SYM
%token SMALLINT
%token STRING_SYM
%token TEXT_SYM
@@ -328,6 +367,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token TINYBLOB
%token TINYINT
%token TINYTEXT
+%token ULONGLONG_NUM
%token UNSIGNED
%token VARBINARY
%token VARCHAR
@@ -352,6 +392,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%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
@@ -369,6 +411,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token IDENTIFIED_SYM
%token IF
%token INSERT_ID
+%token INSERT_METHOD
%token INTERVAL_SYM
%token LAST_INSERT_ID
%token LEFT
@@ -425,9 +468,14 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token SQL_WARNINGS
%token SQL_AUTO_IS_NULL
%token SQL_SAFE_UPDATES
+%token SQL_QUERY_CACHE_TYPE_SYM
%token SQL_QUOTE_SHOW_CREATE
%token SQL_SLAVE_SKIP_COUNTER
+%token ISSUER_SYM
+%token SUBJECT_SYM
+%token CIPHER_SYM
+
%left SET_VAR
%left OR_OR_CONCAT OR
%left AND
@@ -444,7 +492,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%type <lex_str>
IDENT TEXT_STRING REAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM LEX_HOSTNAME
- field_ident select_alias ident ident_or_text
+ ULONGLONG_NUM field_ident select_alias ident ident_or_text
%type <lex_str_ptr>
opt_table_alias
@@ -457,18 +505,18 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
opt_escape
%type <string>
- text_string
+ text_string
%type <num>
type int_type real_type order_dir opt_field_spec set_option lock_option
udf_type if_exists opt_local opt_table_options table_options
- table_option opt_if_not_exists
+ table_option opt_if_not_exists
%type <ulong_num>
- ULONG_NUM raid_types
+ ULONG_NUM raid_types merge_insert_types
-%type <ulonglong_num>
- ULONGLONG_NUM
+%type <ulonglong_number>
+ ulonglong_num
%type <item>
literal text_literal insert_ident order_ident
@@ -477,7 +525,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
using_list
%type <item_list>
- expr_list udf_expr_list when_list ident_list
+ expr_list udf_expr_list when_list ident_list ident_list_arg
%type <key_type>
key_type opt_unique_or_fulltext
@@ -503,6 +551,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%type <tx_isolation> tx_isolation isolation_types
+%type <ha_rkey_mode> handler_rkey_mode
+
+%type <cast_type> cast_type
+
%type <udf_type> udf_func_type
%type <symbol> FUNC_ARG0 FUNC_ARG1 FUNC_ARG2 FUNC_ARG3 keyword
@@ -519,13 +571,13 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
select_item_list select_item values_list no_braces
limit_clause delete_limit_clause fields opt_values values
procedure_list procedure_list2 procedure_item
- when_list2 expr_list2
+ when_list2 expr_list2 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 varchar
references opt_on_delete opt_on_delete_list opt_on_delete_item use
opt_delete_options opt_delete_option
- opt_outer table_list table opt_option opt_place opt_low_priority
+ opt_outer table_list table_name opt_option opt_place opt_low_priority
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
@@ -533,7 +585,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
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
- END_OF_INPUT
+ handler_rkey_function handler_read_or_scan
+ single_multi table_wild_list table_wild_one opt_wild union union_list
+ precision union_option
+END_OF_INPUT
%type <NONE>
'-' '+' '*' '/' '%' '(' ')'
@@ -546,7 +601,7 @@ query:
{
THD *thd=current_thd;
if (!thd->bootstrap &&
- (!(thd->lex.options & OPTION_FOUND_COMMENT)))
+ (!(thd->lex.select_lex.options & OPTION_FOUND_COMMENT)))
{
send_error(&current_thd->net,ER_EMPTY_QUERY);
YYABORT;
@@ -591,6 +646,7 @@ verb_clause:
| slave
| show
| truncate
+ | handler
| unlock
| update
| use
@@ -636,7 +692,7 @@ master_def:
Lex->mi.port = $3;
}
|
- MASTER_LOG_POS_SYM EQ ULONGLONG_NUM
+ MASTER_LOG_POS_SYM EQ ulonglong_num
{
Lex->mi.pos = $3;
}
@@ -647,7 +703,6 @@ master_def:
}
-
/* create a table */
create:
@@ -671,36 +726,41 @@ create:
| CREATE opt_unique_or_fulltext INDEX ident ON table_ident
{
- Lex->sql_command= SQLCOM_CREATE_INDEX;
+ LEX *lex=Lex;
+ lex->sql_command= SQLCOM_CREATE_INDEX;
if (!add_table_to_list($6,NULL,1))
YYABORT;
- Lex->create_list.empty();
- Lex->key_list.empty();
- Lex->col_list.empty();
- Lex->change=NullS;
+ lex->create_list.empty();
+ lex->key_list.empty();
+ lex->col_list.empty();
+ lex->change=NullS;
}
'(' key_list ')'
{
- Lex->key_list.push_back(new Key($2,$4.str,Lex->col_list));
- Lex->col_list.empty();
+ LEX *lex=Lex;
+ lex->key_list.push_back(new Key($2,$4.str,lex->col_list));
+ lex->col_list.empty();
}
| CREATE DATABASE opt_if_not_exists ident
{
- Lex->sql_command=SQLCOM_CREATE_DB;
- Lex->name=$4.str;
- Lex->create_info.options=$3;
+ LEX *lex=Lex;
+ lex->sql_command=SQLCOM_CREATE_DB;
+ lex->name=$4.str;
+ lex->create_info.options=$3;
}
| CREATE udf_func_type UDF_SYM ident
{
- Lex->sql_command = SQLCOM_CREATE_FUNCTION;
- Lex->udf.name=$4.str;
- Lex->udf.name_length=$4.length;
- Lex->udf.type= $2;
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_CREATE_FUNCTION;
+ lex->udf.name=$4.str;
+ lex->udf.name_length=$4.length;
+ lex->udf.type= $2;
}
UDF_RETURNS_SYM udf_type UDF_SONAME_SYM TEXT_STRING
{
- Lex->udf.returns=(Item_result) $7;
- Lex->udf.dl=$9.str;
+ LEX *lex=Lex;
+ lex->udf.returns=(Item_result) $7;
+ lex->udf.dl=$9.str;
}
create2:
@@ -711,10 +771,11 @@ create3:
/* empty */ {}
| opt_duplicate opt_as SELECT_SYM
{
- Lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ;
- mysql_init_select(Lex);
+ LEX *lex=Lex;
+ lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ;
+ mysql_init_select(lex);
}
- select_options select_item_list opt_select_from {}
+ select_options select_item_list opt_select_from union {}
opt_as:
/* empty */ {}
@@ -726,7 +787,7 @@ opt_table_options:
table_options:
table_option { $$=$1; }
- | table_option table_options { $$= $1 | $2 }
+ | table_option table_options { $$= $1 | $2; }
table_option:
TEMPORARY { $$=HA_LEX_CREATE_TMP_TABLE; }
@@ -745,13 +806,14 @@ create_table_options:
create_table_option:
TYPE_SYM EQ table_types { Lex->create_info.db_type= $3; }
- | MAX_ROWS EQ ULONGLONG_NUM { Lex->create_info.max_rows= $3; }
- | MIN_ROWS EQ ULONGLONG_NUM { Lex->create_info.min_rows= $3; }
- | AVG_ROW_LENGTH EQ ULONG_NUM { Lex->create_info.avg_row_length=$3; }
+ | MAX_ROWS EQ ulonglong_num { Lex->create_info.max_rows= $3; Lex->create_info.used_fields|= HA_CREATE_USED_MAX_ROWS;}
+ | MIN_ROWS EQ ulonglong_num { Lex->create_info.min_rows= $3; Lex->create_info.used_fields|= HA_CREATE_USED_MIN_ROWS;}
+ | AVG_ROW_LENGTH EQ ULONG_NUM { Lex->create_info.avg_row_length=$3; Lex->create_info.used_fields|= HA_CREATE_USED_AVG_ROW_LENGTH;}
| PASSWORD EQ TEXT_STRING { Lex->create_info.password=$3.str; }
| COMMENT_SYM EQ TEXT_STRING { Lex->create_info.comment=$3.str; }
- | AUTO_INC EQ ULONGLONG_NUM { Lex->create_info.auto_increment_value=$3; Lex->create_info.used_fields|= HA_CREATE_USED_AUTO;}
- | PACK_KEYS_SYM EQ ULONG_NUM { Lex->create_info.table_options|= $3 ? HA_OPTION_PACK_KEYS : HA_OPTION_NO_PACK_KEYS; }
+ | AUTO_INC EQ ulonglong_num { Lex->create_info.auto_increment_value=$3; Lex->create_info.used_fields|= HA_CREATE_USED_AUTO;}
+ | PACK_KEYS_SYM EQ 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 EQ 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 EQ ULONG_NUM { Lex->create_info.table_options|= $3 ? HA_OPTION_CHECKSUM : HA_OPTION_NO_CHECKSUM; }
| DELAY_KEY_WRITE_SYM EQ ULONG_NUM { Lex->create_info.table_options|= $3 ? HA_OPTION_DELAY_KEY_WRITE : HA_OPTION_NO_DELAY_KEY_WRITE; }
| ROW_FORMAT_SYM EQ row_types { Lex->create_info.row_type= $3; }
@@ -762,15 +824,18 @@ create_table_option:
{
/* Move the union list to the merge_list */
LEX *lex=Lex;
- TABLE_LIST *table_list= (TABLE_LIST*) lex->table_list.first;
- lex->create_info.merge_list= lex->table_list;
+ TABLE_LIST *table_list= (TABLE_LIST*) lex->select->table_list.first;
+ lex->create_info.merge_list= lex->select->table_list;
lex->create_info.merge_list.elements--;
lex->create_info.merge_list.first= (byte*) (table_list->next);
- lex->table_list.elements=1;
- lex->table_list.next= (byte**) &(table_list->next);
+ lex->select->table_list.elements=1;
+ lex->select->table_list.next= (byte**) &(table_list->next);
table_list->next=0;
lex->create_info.used_fields|= HA_CREATE_USED_UNION;
}
+ | INSERT_METHOD EQ merge_insert_types { Lex->create_info.merge_insert_method= $3; Lex->create_info.used_fields|= HA_CREATE_USED_INSERT_METHOD;}
+ | DATA_SYM DIRECTORY_SYM EQ TEXT_STRING { Lex->create_info.data_file_name= $4.str; }
+ | INDEX DIRECTORY_SYM EQ TEXT_STRING { Lex->create_info.index_file_name= $4.str; }
table_types:
ISAM_SYM { $$= DB_TYPE_ISAM; }
@@ -778,8 +843,7 @@ table_types:
| MERGE_SYM { $$= DB_TYPE_MRG_MYISAM; }
| HEAP_SYM { $$= DB_TYPE_HEAP; }
| BERKELEY_DB_SYM { $$= DB_TYPE_BERKELEY_DB; }
- | INNOBASE_SYM { $$= DB_TYPE_INNOBASE; }
- | GEMINI_SYM { $$= DB_TYPE_GEMINI; }
+ | INNOBASE_SYM { $$= DB_TYPE_INNODB; }
row_types:
DEFAULT { $$= ROW_TYPE_DEFAULT; }
@@ -792,6 +856,11 @@ raid_types:
| RAID_0_SYM { $$= RAID_TYPE_0; }
| ULONG_NUM { $$=$1;}
+merge_insert_types:
+ NO_SYM { $$= MERGE_INSERT_DISABLED; }
+ | FIRST_SYM { $$= MERGE_INSERT_TO_FIRST; }
+ | LAST_SYM { $$= MERGE_INSERT_TO_LAST; }
+
opt_select_from:
/* empty */
| select_from select_lock_type
@@ -818,8 +887,9 @@ field_list_item:
}
| key_type opt_ident '(' key_list ')'
{
- Lex->key_list.push_back(new Key($1,$2,Lex->col_list));
- Lex->col_list.empty(); /* Alloced by sql_alloc */
+ LEX *lex=Lex;
+ lex->key_list.push_back(new Key($1,$2,lex->col_list));
+ lex->col_list.empty(); /* Alloced by sql_alloc */
}
| opt_constraint FOREIGN KEY_SYM opt_ident '(' key_list ')' references
{
@@ -837,16 +907,18 @@ opt_constraint:
field_spec:
field_ident
{
- Lex->length=Lex->dec=0; Lex->type=0; Lex->interval=0;
- Lex->default_value=0;
+ LEX *lex=Lex;
+ lex->length=lex->dec=0; lex->type=0; lex->interval=0;
+ lex->default_value=0;
}
type opt_attribute
{
+ LEX *lex=Lex;
if (add_field_to_list($1.str,
(enum enum_field_types) $3,
- Lex->length,Lex->dec,Lex->type,
- Lex->default_value,Lex->change,
- Lex->interval))
+ lex->length,lex->dec,lex->type,
+ lex->default_value,lex->change,
+ lex->interval))
YYABORT;
}
@@ -898,12 +970,14 @@ type:
{ $$=FIELD_TYPE_DECIMAL;}
| ENUM {Lex->interval_list.empty();} '(' string_list ')'
{
- Lex->interval=typelib(Lex->interval_list);
+ LEX *lex=Lex;
+ lex->interval=typelib(lex->interval_list);
$$=FIELD_TYPE_ENUM;
}
| SET { Lex->interval_list.empty();} '(' string_list ')'
{
- Lex->interval=typelib(Lex->interval_list);
+ LEX *lex=Lex;
+ lex->interval=typelib(lex->interval_list);
$$=FIELD_TYPE_SET;
}
@@ -935,7 +1009,14 @@ real_type:
float_options:
/* empty */ {}
| '(' NUM ')' { Lex->length=$2.str; }
- | '(' NUM ',' NUM ')' { Lex->length=$2.str; Lex->dec=$4.str; }
+ | precision {}
+
+precision:
+ '(' NUM ',' NUM ')'
+ {
+ LEX *lex=Lex;
+ lex->length=$2.str; lex->dec=$4.str;
+ }
field_options:
/* empty */ {}
@@ -946,7 +1027,8 @@ field_opt_list:
| field_option {}
field_option:
- UNSIGNED { Lex->type|= UNSIGNED_FLAG;}
+ SIGNED_SYM {}
+ | UNSIGNED { Lex->type|= UNSIGNED_FLAG;}
| ZEROFILL { Lex->type|= UNSIGNED_FLAG | ZEROFILL_FLAG; }
opt_len:
@@ -955,7 +1037,7 @@ opt_len:
opt_precision:
/* empty */ {}
- | '(' NUM ',' NUM ')' { Lex->length=$2.str; Lex->dec=$4.str; }
+ | precision {}
opt_attribute:
/* empty */ {}
@@ -1022,6 +1104,7 @@ key_or_index:
keys_or_index:
KEYS {}
| INDEX {}
+ | INDEXES {}
opt_unique_or_fulltext:
/* empty */ { $$= Key::MULTIPLE; }
@@ -1062,12 +1145,15 @@ alter:
lex->col_list.empty();
lex->drop_list.empty();
lex->alter_list.empty();
- lex->order_list.elements=0;
- lex->order_list.first=0;
- lex->order_list.next= (byte**) &lex->order_list.first;
- lex->db=lex->name=0;
+ lex->select->order_list.elements=0;
+ lex->select->order_list.first=0;
+ lex->select->order_list.next= (byte**) &lex->select->order_list.first;
+ lex->select->db=lex->name=0;
bzero((char*) &lex->create_info,sizeof(lex->create_info));
lex->create_info.db_type= DB_TYPE_DEFAULT;
+ lex->create_info.row_type= ROW_TYPE_NOT_USED;
+ lex->alter_keys_onoff=LEAVE_AS_IS;
+ lex->simple_alter=1;
}
alter_list
@@ -1076,42 +1162,78 @@ alter_list:
| alter_list ',' alter_list_item
add_column:
- ADD opt_column { Lex->change=0;}
+ ADD opt_column { Lex->change=0; }
alter_list_item:
- add_column field_list_item opt_place
- | add_column '(' field_list ')'
- | CHANGE opt_column field_ident { Lex->change= $3.str; } field_spec
+ add_column field_list_item opt_place { Lex->simple_alter=0; }
+ | add_column '(' field_list ')' { Lex->simple_alter=0; }
+ | CHANGE opt_column field_ident
+ {
+ LEX *lex=Lex;
+ lex->change= $3.str; lex->simple_alter=0;
+ }
+ field_spec opt_place
| MODIFY_SYM opt_column field_ident
{
- Lex->length=Lex->dec=0; Lex->type=0; Lex->interval=0;
- Lex->default_value=0;
+ LEX *lex=Lex;
+ lex->length=lex->dec=0; lex->type=0; lex->interval=0;
+ lex->default_value=0;
+ lex->simple_alter=0;
}
type opt_attribute
{
+ LEX *lex=Lex;
if (add_field_to_list($3.str,
(enum enum_field_types) $5,
- Lex->length,Lex->dec,Lex->type,
- Lex->default_value, $3.str,
- Lex->interval))
+ lex->length,lex->dec,lex->type,
+ lex->default_value, $3.str,
+ lex->interval))
YYABORT;
+ lex->simple_alter=0;
}
+ opt_place
| DROP opt_column field_ident opt_restrict
- { Lex->drop_list.push_back(new Alter_drop(Alter_drop::COLUMN,
- $3.str)); }
- | DROP PRIMARY_SYM KEY_SYM { Lex->drop_primary=1; }
- | DROP FOREIGN KEY_SYM opt_ident {}
+ {
+ LEX *lex=Lex;
+ lex->drop_list.push_back(new Alter_drop(Alter_drop::COLUMN,
+ $3.str)); lex->simple_alter=0;
+ }
+ | DROP PRIMARY_SYM KEY_SYM
+ {
+ LEX *lex=Lex;
+ lex->drop_primary=1; lex->simple_alter=0;
+ }
+ | DROP FOREIGN KEY_SYM opt_ident { Lex->simple_alter=0; }
| DROP key_or_index field_ident
- { Lex->drop_list.push_back(new Alter_drop(Alter_drop::KEY,
- $3.str)); }
+ {
+ LEX *lex=Lex;
+ lex->drop_list.push_back(new Alter_drop(Alter_drop::KEY,
+ $3.str));
+ lex->simple_alter=0;
+ }
+ | DISABLE_SYM KEYS { Lex->alter_keys_onoff=DISABLE; }
+ | ENABLE_SYM KEYS { Lex->alter_keys_onoff=ENABLE; }
| ALTER opt_column field_ident SET DEFAULT literal
- { Lex->alter_list.push_back(new Alter_column($3.str,$6)); }
+ {
+ LEX *lex=Lex;
+ lex->alter_list.push_back(new Alter_column($3.str,$6));
+ lex->simple_alter=0;
+ }
| ALTER opt_column field_ident DROP DEFAULT
- { Lex->alter_list.push_back(new Alter_column($3.str,(Item*) 0)); }
+ {
+ LEX *lex=Lex;
+ lex->alter_list.push_back(new Alter_column($3.str,(Item*) 0));
+ lex->simple_alter=0;
+ }
| RENAME opt_to table_alias table_ident
- { Lex->db=$4->db.str ; Lex->name= $4->table.str; }
- | create_table_options
- | order_clause
+ {
+ LEX *lex=Lex;
+ lex->select->db=$4->db.str;
+ lex->name= $4->table.str;
+ lex->simple_alter=0;
+ }
+ | create_table_options { Lex->simple_alter=0; }
+ | order_clause { Lex->simple_alter=0; }
opt_column:
/* empty */ {}
@@ -1137,18 +1259,34 @@ opt_to:
| AS {}
slave:
- SLAVE START_SYM
+ SLAVE START_SYM slave_thread_opts
{
- Lex->sql_command = SQLCOM_SLAVE_START;
- Lex->type = 0;
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_SLAVE_START;
+ lex->type = 0;
}
|
- SLAVE STOP_SYM
+ SLAVE STOP_SYM slave_thread_opts
{
- Lex->sql_command = SQLCOM_SLAVE_STOP;
- Lex->type = 0;
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_SLAVE_STOP;
+ lex->type = 0;
};
+slave_thread_opts: slave_thread_opt
+ | slave_thread_opts ',' slave_thread_opt
+
+slave_thread_opt:
+ /*empty*/ {}
+ | SQL_THREAD
+ {
+ Lex->slave_thd_opt|=SLAVE_SQL;
+ }
+ | IO_THREAD
+ {
+ Lex->slave_thd_opt|=SLAVE_IO;
+ }
+
restore:
RESTORE_SYM table_or_tables
{
@@ -1168,53 +1306,67 @@ backup:
Lex->backup_dir = $6.str;
}
-
repair:
REPAIR table_or_tables
{
- Lex->sql_command = SQLCOM_REPAIR;
- Lex->check_opt.init();
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_REPAIR;
+ lex->check_opt.init();
}
- table_list opt_mi_check_type
+ table_list opt_mi_repair_type
-
-opt_mi_check_type:
+opt_mi_repair_type:
/* empty */ { Lex->check_opt.flags = T_MEDIUM; }
- | TYPE_SYM EQ mi_check_types {}
- | mi_check_types {}
+ | mi_repair_types {}
-mi_check_types:
- mi_check_type {}
- | mi_check_type mi_check_types {}
+mi_repair_types:
+ mi_repair_type {}
+ | mi_repair_type mi_repair_types {}
-mi_check_type:
- QUICK { Lex->check_opt.quick = 1; }
- | FAST_SYM { Lex->check_opt.flags|= T_FAST; }
- | MEDIUM_SYM { Lex->check_opt.flags|= T_MEDIUM; }
+mi_repair_type:
+ QUICK { Lex->check_opt.flags|= T_QUICK; }
| EXTENDED_SYM { Lex->check_opt.flags|= T_EXTEND; }
- | CHANGED { Lex->check_opt.flags|= T_CHECK_ONLY_CHANGED; }
+ | USE_FRM { /*Lex->check_opt.flags|= T_USEFRM;*/ }
analyze:
ANALYZE_SYM table_or_tables
{
- Lex->sql_command = SQLCOM_ANALYZE;
- Lex->check_opt.init();
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_ANALYZE;
+ lex->check_opt.init();
}
table_list opt_mi_check_type
check:
CHECK_SYM table_or_tables
{
- Lex->sql_command = SQLCOM_CHECK;
- Lex->check_opt.init();
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_CHECK;
+ lex->check_opt.init();
}
table_list opt_mi_check_type
+opt_mi_check_type:
+ /* empty */ { Lex->check_opt.flags = T_MEDIUM; }
+ | mi_check_types {}
+
+mi_check_types:
+ mi_check_type {}
+ | mi_check_type mi_check_types {}
+
+mi_check_type:
+ QUICK { Lex->check_opt.flags|= T_QUICK; }
+ | FAST_SYM { Lex->check_opt.flags|= T_FAST; }
+ | MEDIUM_SYM { Lex->check_opt.flags|= T_MEDIUM; }
+ | EXTENDED_SYM { Lex->check_opt.flags|= T_EXTEND; }
+ | CHANGED { Lex->check_opt.flags|= T_CHECK_ONLY_CHANGED; }
+
optimize:
OPTIMIZE table_or_tables
{
- Lex->sql_command = SQLCOM_OPTIMIZE;
- Lex->check_opt.init();
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_OPTIMIZE;
+ lex->check_opt.init();
}
table_list opt_mi_check_type
@@ -1242,17 +1394,24 @@ table_to_table:
select:
- SELECT_SYM
+ select_init { Lex->sql_command=SQLCOM_SELECT; }
+
+select_init:
+ SELECT_SYM select_part2 { Select->braces=false; } union
+ |
+ '(' SELECT_SYM select_part2 ')' { Select->braces=true;} union_opt
+
+
+select_part2:
{
LEX *lex=Lex;
- lex->sql_command= SQLCOM_SELECT;
lex->lock_option=TL_READ;
- mysql_init_select(lex);
+ mysql_init_select(lex);
}
select_options select_item_list select_into select_lock_type
select_into:
- /* empty */
+ limit_clause {}
| select_from
| opt_into select_from
| select_from opt_into
@@ -1270,20 +1429,23 @@ select_option_list:
| select_option
select_option:
- STRAIGHT_JOIN { Lex->options|= SELECT_STRAIGHT_JOIN; }
+ STRAIGHT_JOIN { Select->options|= SELECT_STRAIGHT_JOIN; }
| HIGH_PRIORITY { Lex->lock_option= TL_READ_HIGH_PRIORITY; }
- | DISTINCT { Lex->options|= SELECT_DISTINCT; }
- | SQL_SMALL_RESULT { Lex->options|= SELECT_SMALL_RESULT; }
- | SQL_BIG_RESULT { Lex->options|= SELECT_BIG_RESULT; }
- | SQL_BUFFER_RESULT { Lex->options|= OPTION_BUFFER_RESULT; }
+ | DISTINCT { Select->options|= SELECT_DISTINCT; }
+ | SQL_SMALL_RESULT { Select->options|= SELECT_SMALL_RESULT; }
+ | SQL_BIG_RESULT { Select->options|= SELECT_BIG_RESULT; }
+ | SQL_BUFFER_RESULT { Select->options|= OPTION_BUFFER_RESULT; }
+ | SQL_CALC_FOUND_ROWS { Select->options|= OPTION_FOUND_ROWS; }
+ | SQL_NO_CACHE_SYM { current_thd->safe_to_cache_query=0; }
+ | SQL_CACHE_SYM { Select->options |= OPTION_TO_QUERY_CACHE; }
| ALL {}
select_lock_type:
/* empty */
| FOR_SYM UPDATE_SYM
- { Lex->lock_option= TL_WRITE; }
+ { Lex->lock_option= TL_WRITE; current_thd->safe_to_cache_query=0; }
| LOCK_SYM IN_SYM SHARE_SYM MODE_SYM
- { Lex->lock_option= TL_READ_WITH_SHARED_LOCKS; }
+ { Lex->lock_option= TL_READ_WITH_SHARED_LOCKS; current_thd->safe_to_cache_query=0; }
select_item_list:
select_item_list ',' select_item
@@ -1451,9 +1613,18 @@ no_and_expr:
simple_expr:
simple_ident
| literal
- | '@' ident_or_text SET_VAR expr { $$= new Item_func_set_user_var($2,$4); }
- | '@' ident_or_text { $$= new Item_func_get_user_var($2); }
- | '@' '@' ident_or_text { if (!($$= get_system_var($3))) YYABORT; }
+ | '@' ident_or_text SET_VAR expr
+ { $$= new Item_func_set_user_var($2,$4);
+ current_thd->safe_to_cache_query=0;
+ }
+ | '@' ident_or_text
+ { $$= new Item_func_get_user_var($2);
+ current_thd->safe_to_cache_query=0;
+ }
+ | '@' '@' ident_or_text
+ { if (!($$= get_system_var($3))) YYABORT;
+ current_thd->safe_to_cache_query=0;
+ }
| sum_expr
| '-' expr %prec NEG { $$= new Item_func_neg($2); }
| '~' expr %prec NEG { $$= new Item_func_bit_neg($2); }
@@ -1461,15 +1632,17 @@ simple_expr:
| '!' expr %prec NEG { $$= new Item_func_not($2); }
| '(' expr ')' { $$= $2; }
| '{' ident expr '}' { $$= $3; }
- | MATCH '(' ident_list ')' AGAINST '(' expr ')'
- { Lex->ftfunc_list.push_back(
- (Item_func_match *)($$=new Item_func_match(*$3,$7))); }
- | MATCH ident_list AGAINST '(' expr ')'
- { Lex->ftfunc_list.push_back(
- (Item_func_match *)($$=new Item_func_match(*$2,$5))); }
+ | MATCH ident_list_arg AGAINST '(' expr ')'
+ { Select->ftfunc_list.push_back((Item_func_match *)
+ ($$=new Item_func_match_nl(*$2,$5))); }
+ | MATCH ident_list_arg AGAINST '(' expr IN_SYM BOOLEAN_SYM MODE_SYM ')'
+ { Select->ftfunc_list.push_back((Item_func_match *)
+ ($$=new Item_func_match_bool(*$2,$5))); }
| BINARY expr %prec NEG { $$= new Item_func_binary($2); }
+ | CAST_SYM '(' expr AS cast_type ')' { $$= create_func_cast($3, $5); }
| CASE_SYM opt_expr WHEN_SYM when_list opt_else END
- { $$= new Item_func_case(* $4, $2, $5 ) }
+ { $$= new Item_func_case(* $4, $2, $5 ); }
+ | CONVERT_SYM '(' expr ',' cast_type ')' { $$= create_func_cast($3, $5); }
| FUNC_ARG0 '(' ')'
{ $$= ((Item*(*)(void))($1.symbol->create_func))();}
| FUNC_ARG1 '(' expr ')'
@@ -1491,27 +1664,45 @@ simple_expr:
| CONCAT_WS '(' expr ',' expr_list ')'
{ $$= new Item_func_concat_ws($3, *$5); }
| CURDATE optional_braces
- { $$= new Item_func_curdate(); }
+ { $$= new Item_func_curdate(); current_thd->safe_to_cache_query=0; }
| CURTIME optional_braces
- { $$= new Item_func_curtime(); }
+ { $$= new Item_func_curtime(); current_thd->safe_to_cache_query=0; }
| CURTIME '(' expr ')'
- { $$= new Item_func_curtime($3); }
+ {
+ $$= new Item_func_curtime($3);
+ current_thd->safe_to_cache_query=0;
+ }
| DATE_ADD_INTERVAL '(' expr ',' INTERVAL_SYM expr interval ')'
{ $$= new Item_date_add_interval($3,$6,$7,0); }
| DATE_SUB_INTERVAL '(' expr ',' INTERVAL_SYM expr interval ')'
{ $$= new Item_date_add_interval($3,$6,$7,1); }
| DATABASE '(' ')'
- { $$= new Item_func_database(); }
+ {
+ $$= new Item_func_database();
+ current_thd->safe_to_cache_query=0;
+ }
| ELT_FUNC '(' expr ',' expr_list ')'
{ $$= new Item_func_elt($3, *$5); }
| MAKE_SET_SYM '(' expr ',' expr_list ')'
{ $$= new Item_func_make_set($3, *$5); }
- | ENCRYPT '(' expr ')' { $$= new Item_func_encrypt($3); }
+ | ENCRYPT '(' expr ')'
+ {
+ $$= new Item_func_encrypt($3);
+ current_thd->safe_to_cache_query=0;
+ }
| ENCRYPT '(' expr ',' expr ')' { $$= new Item_func_encrypt($3,$5); }
| DECODE_SYM '(' expr ',' TEXT_STRING ')'
{ $$= new Item_func_decode($3,$5.str); }
| ENCODE_SYM '(' expr ',' TEXT_STRING ')'
{ $$= new Item_func_encode($3,$5.str); }
+ | DES_DECRYPT_SYM '(' expr ')'
+ { $$= new Item_func_des_decrypt($3); }
+ | DES_DECRYPT_SYM '(' expr ',' expr ')'
+ { $$= new Item_func_des_decrypt($3,$5); }
+ | DES_ENCRYPT_SYM '(' expr ')'
+ { $$= new Item_func_des_encrypt($3); }
+ | DES_ENCRYPT_SYM '(' expr ',' expr ')'
+ { $$= new Item_func_des_encrypt($3,$5); }
| EXPORT_SET '(' expr ',' expr ',' expr ')'
{ $$= new Item_func_export_set($3, $5, $7); }
| EXPORT_SET '(' expr ',' expr ',' expr ',' expr ')'
@@ -1524,7 +1715,7 @@ simple_expr:
{ $$= new Item_func_from_unixtime($3); }
| FROM_UNIXTIME '(' expr ',' expr ')'
{
- $$= new Item_func_date_format(new Item_func_from_unixtime($3),$5,0);
+ $$= new Item_func_date_format (new Item_func_from_unixtime($3),$5,0);
}
| FIELD_FUNC '(' expr ',' expr_list ')'
{ $$= new Item_func_field($3, *$5); }
@@ -1543,10 +1734,12 @@ simple_expr:
{
$$= new Item_int((char*) "last_insert_id()",
current_thd->insert_id(),21);
+ current_thd->safe_to_cache_query=0;
}
| LAST_INSERT_ID '(' expr ')'
{
$$= new Item_func_set_last_insert_id($3);
+ current_thd->safe_to_cache_query=0;
}
| LEFT '(' expr ',' expr ')'
{ $$= new Item_func_left($3,$5); }
@@ -1563,14 +1756,19 @@ simple_expr:
| MONTH_SYM '(' expr ')'
{ $$= new Item_func_month($3); }
| NOW_SYM optional_braces
- { $$= new Item_func_now(); }
+ { $$= new Item_func_now(); current_thd->safe_to_cache_query=0;}
| NOW_SYM '(' expr ')'
- { $$= new Item_func_now($3); }
- | PASSWORD '(' expr ')' { $$= new Item_func_password($3); }
+ { $$= new Item_func_now($3); current_thd->safe_to_cache_query=0;}
+ | PASSWORD '(' expr ')'
+ {
+ $$= new Item_func_password($3);
+ }
| POSITION_SYM '(' no_in_expr IN_SYM expr ')'
{ $$ = new Item_func_locate($5,$3); }
- | RAND '(' expr ')' { $$= new Item_func_rand($3); }
- | RAND '(' ')' { $$= new Item_func_rand(); }
+ | RAND '(' expr ')'
+ { $$= new Item_func_rand($3); current_thd->safe_to_cache_query=0;}
+ | RAND '(' ')'
+ { $$= new Item_func_rand(); current_thd->safe_to_cache_query=0;}
| REPLACE '(' expr ',' expr ',' expr ')'
{ $$= new Item_func_replace($3,$5,$7); }
| RIGHT '(' expr ',' expr ')'
@@ -1608,6 +1806,7 @@ simple_expr:
$$ = new Item_sum_udf_str($1, *$3);
else
$$ = new Item_sum_udf_str($1);
+ current_thd->safe_to_cache_query=0;
}
| UDA_FLOAT_SUM '(' udf_expr_list ')'
{
@@ -1615,6 +1814,7 @@ simple_expr:
$$ = new Item_sum_udf_float($1, *$3);
else
$$ = new Item_sum_udf_float($1);
+ current_thd->safe_to_cache_query=0;
}
| UDA_INT_SUM '(' udf_expr_list ')'
{
@@ -1629,6 +1829,7 @@ simple_expr:
$$ = new Item_func_udf_str($1, *$3);
else
$$ = new Item_func_udf_str($1);
+ current_thd->safe_to_cache_query=0;
}
| UDF_FLOAT_FUNC '(' udf_expr_list ')'
{
@@ -1636,6 +1837,7 @@ simple_expr:
$$ = new Item_func_udf_float($1, *$3);
else
$$ = new Item_func_udf_float($1);
+ current_thd->safe_to_cache_query=0;
}
| UDF_INT_FUNC '(' udf_expr_list ')'
{
@@ -1643,15 +1845,21 @@ simple_expr:
$$ = new Item_func_udf_int($1, *$3);
else
$$ = new Item_func_udf_int($1);
+ current_thd->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); }
+ {
+ $$= new Item_func_unique_users($3,atoi($5.str),atoi($7.str), * $9);
+ }
| UNIX_TIMESTAMP '(' ')'
- { $$= new Item_func_unix_timestamp(); }
+ {
+ $$= new Item_func_unix_timestamp();
+ current_thd->safe_to_cache_query=0;
+ }
| UNIX_TIMESTAMP '(' expr ')'
{ $$= new Item_func_unix_timestamp($3); }
| USER '(' ')'
- { $$= new Item_func_user(); }
+ { $$= new Item_func_user(); current_thd->safe_to_cache_query=0; }
| WEEK_SYM '(' expr ')'
{ $$= new Item_func_week($3,new Item_int((char*) "0",0,1)); }
| WEEK_SYM '(' expr ',' expr ')'
@@ -1663,7 +1871,10 @@ simple_expr:
| YEARWEEK '(' expr ',' expr ')'
{ $$= new Item_func_yearweek($3, $5); }
| BENCHMARK_SYM '(' ULONG_NUM ',' expr ')'
- { $$=new Item_func_benchmark($3,$5); }
+ {
+ $$=new Item_func_benchmark($3,$5);
+ current_thd->safe_to_cache_query=0;
+ }
| EXTRACT_SYM '(' interval FROM expr ')'
{ $$=new Item_extract( $3, $5); }
@@ -1696,30 +1907,44 @@ sum_expr:
{ $$=new Item_sum_sum($3); }
in_sum_expr:
- { Lex->in_sum_expr++ }
+ { Select->in_sum_expr++; }
expr
{
- Lex->in_sum_expr--;
+ Select->in_sum_expr--;
$$=$2;
}
+cast_type:
+ BINARY { $$=ITEM_CAST_BINARY; }
+ | SIGNED_SYM { $$=ITEM_CAST_SIGNED_INT; }
+ | SIGNED_SYM INT_SYM { $$=ITEM_CAST_SIGNED_INT; }
+ | UNSIGNED { $$=ITEM_CAST_UNSIGNED_INT; }
+ | UNSIGNED INT_SYM { $$=ITEM_CAST_UNSIGNED_INT; }
+ | DATE_SYM { $$=ITEM_CAST_DATE; }
+ | TIME_SYM { $$=ITEM_CAST_TIME; }
+ | DATETIME { $$=ITEM_CAST_DATETIME; }
+
expr_list:
- { Lex->expr_list.push_front(new List<Item>); }
+ { Select->expr_list.push_front(new List<Item>); }
expr_list2
- { $$= Lex->expr_list.pop(); }
+ { $$= Select->expr_list.pop(); }
expr_list2:
- expr { Lex->expr_list.head()->push_back($1); }
- | expr_list2 ',' expr { Lex->expr_list.head()->push_back($3); }
+ expr { Select->expr_list.head()->push_back($1); }
+ | expr_list2 ',' expr { Select->expr_list.head()->push_back($3); }
+
+ident_list_arg:
+ ident_list { $$= $1; }
+ | '(' ident_list ')' { $$= $2; }
ident_list:
- { Lex->expr_list.push_front(new List<Item>); }
+ { Select->expr_list.push_front(new List<Item>); }
ident_list2
- { $$= Lex->expr_list.pop(); }
+ { $$= Select->expr_list.pop(); }
ident_list2:
- simple_ident { Lex->expr_list.head()->push_back($1); }
- | ident_list2 ',' simple_ident { Lex->expr_list.head()->push_back($3); }
+ simple_ident { Select->expr_list.head()->push_back($1); }
+ | ident_list2 ',' simple_ident { Select->expr_list.head()->push_back($3); }
opt_expr:
/* empty */ { $$= NULL; }
@@ -1730,20 +1955,22 @@ opt_else:
| ELSE expr { $$= $2; }
when_list:
- { Lex->when_list.push_front(new List<Item>) }
+ { Select->when_list.push_front(new List<Item>); }
when_list2
- { $$= Lex->when_list.pop(); }
+ { $$= Select->when_list.pop(); }
when_list2:
expr THEN_SYM expr
{
- Lex->when_list.head()->push_back($1);
- Lex->when_list.head()->push_back($3);
+ SELECT_LEX *sel=Select;
+ sel->when_list.head()->push_back($1);
+ sel->when_list.head()->push_back($3);
}
| when_list2 WHEN_SYM expr THEN_SYM expr
{
- Lex->when_list.head()->push_back($3);
- Lex->when_list.head()->push_back($5);
+ SELECT_LEX *sel=Select;
+ sel->when_list.head()->push_back($3);
+ sel->when_list.head()->push_back($5);
}
opt_pad:
@@ -1753,20 +1980,26 @@ opt_pad:
join_table_list:
'(' join_table_list ')' { $$=$2; }
| join_table { $$=$1; }
- | join_table_list normal_join join_table { $$=$3 }
+ | join_table_list normal_join join_table { $$=$3; }
| join_table_list STRAIGHT_JOIN join_table { $$=$3 ; $$->straight=1; }
| join_table_list INNER_SYM JOIN_SYM join_table ON expr
{ add_join_on($4,$6); $$=$4; }
| join_table_list INNER_SYM JOIN_SYM join_table
- { Lex->db1=$1->db; Lex->table1=$1->name;
- Lex->db2=$4->db; Lex->table2=$4->name; }
+ {
+ SELECT_LEX *sel=Select;
+ sel->db1=$1->db; sel->table1=$1->name;
+ sel->db2=$4->db; sel->table2=$4->name;
+ }
USING '(' using_list ')'
{ add_join_on($4,$8); $$=$4; }
| join_table_list LEFT opt_outer JOIN_SYM join_table ON expr
{ add_join_on($5,$7); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; }
| join_table_list LEFT opt_outer JOIN_SYM join_table
- { Lex->db1=$1->db; Lex->table1=$1->name;
- Lex->db2=$5->db; Lex->table2=$5->name; }
+ {
+ SELECT_LEX *sel=Select;
+ sel->db1=$1->db; sel->table1=$1->name;
+ sel->db2=$5->db; sel->table2=$5->name;
+ }
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
@@ -1774,8 +2007,11 @@ join_table_list:
| join_table_list RIGHT opt_outer JOIN_SYM join_table ON expr
{ add_join_on($1,$7); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$1; }
| join_table_list RIGHT opt_outer JOIN_SYM join_table
- { Lex->db1=$1->db; Lex->table1=$1->name;
- Lex->db2=$5->db; Lex->table2=$5->name; }
+ {
+ SELECT_LEX *sel=Select;
+ sel->db1=$1->db; sel->table1=$1->name;
+ sel->db2=$5->db; sel->table2=$5->name;
+ }
USING '(' using_list ')'
{ add_join_on($1,$9); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$1; }
| join_table_list NATURAL RIGHT opt_outer JOIN_SYM join_table
@@ -1789,10 +2025,16 @@ normal_join:
| CROSS JOIN_SYM {}
join_table:
- { Lex->use_index_ptr=Lex->ignore_index_ptr=0; }
+ {
+ SELECT_LEX *sel=Select;
+ sel->use_index_ptr=sel->ignore_index_ptr=0;
+ }
table_ident opt_table_alias opt_key_definition
- { if (!($$=add_table_to_list($2,$3,0,TL_UNLOCK, Lex->use_index_ptr,
- Lex->ignore_index_ptr))) YYABORT; }
+ {
+ SELECT_LEX *sel=Select;
+ if (!($$=add_table_to_list($2,$3,0,TL_UNLOCK, sel->use_index_ptr,
+ sel->ignore_index_ptr))) YYABORT;
+ }
| '{' ident join_table LEFT OUTER JOIN_SYM join_table ON expr '}'
{ add_join_on($7,$9); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; }
@@ -1803,30 +2045,41 @@ opt_outer:
opt_key_definition:
/* empty */ {}
| USE_SYM key_usage_list
- { Lex->use_index= *$2; Lex->use_index_ptr= &Lex->use_index; }
+ {
+ SELECT_LEX *sel=Select;
+ sel->use_index= *$2;
+ sel->use_index_ptr= &sel->use_index;
+ }
| IGNORE_SYM key_usage_list
- { Lex->ignore_index= *$2; Lex->ignore_index_ptr= &Lex->ignore_index;}
+ {
+ SELECT_LEX *sel=Select;
+ sel->ignore_index= *$2;
+ sel->ignore_index_ptr= &sel->ignore_index;
+ }
key_usage_list:
- key_or_index { Lex->interval_list.empty() } '(' key_usage_list2 ')'
- { $$= &Lex->interval_list; }
+ key_or_index { Select->interval_list.empty(); } '(' key_usage_list2 ')'
+ { $$= &Select->interval_list; }
key_usage_list2:
key_usage_list2 ',' ident
- { Lex->interval_list.push_back(new String((const char*) $3.str,$3.length)); }
+ { Select->interval_list.push_back(new String((const char*) $3.str,$3.length)); }
| ident
- { Lex->interval_list.push_back(new String((const char*) $1.str,$1.length)); }
+ { Select->interval_list.push_back(new String((const char*) $1.str,$1.length)); }
| PRIMARY_SYM
- { Lex->interval_list.push_back(new String("PRIMARY",7)); }
+ { Select->interval_list.push_back(new String("PRIMARY",7)); }
using_list:
ident
- { if (!($$= new Item_func_eq(new Item_field(Lex->db1,Lex->table1, $1.str), new Item_field(Lex->db2,Lex->table2,$1.str))))
+ {
+ SELECT_LEX *sel=Select;
+ if (!($$= new Item_func_eq(new Item_field(sel->db1,sel->table1, $1.str), new Item_field(sel->db2,sel->table2,$1.str))))
YYABORT;
}
| using_list ',' ident
{
- if (!($$= new Item_cond_and(new Item_func_eq(new Item_field(Lex->db1,Lex->table1,$3.str), new Item_field(Lex->db2,Lex->table2,$3.str)), $1)))
+ SELECT_LEX *sel=Select;
+ if (!($$= new Item_cond_and(new Item_func_eq(new Item_field(sel->db1,sel->table1,$3.str), new Item_field(sel->db2,sel->table2,$3.str)), $1)))
YYABORT;
}
@@ -1857,13 +2110,16 @@ opt_table_alias:
where_clause:
- /* empty */ { Lex->where= 0; }
- | WHERE expr { Lex->where= $2; }
+ /* empty */ { Select->where= 0; }
+ | WHERE expr { Select->where= $2; }
having_clause:
/* empty */
- | HAVING { Lex->create_refs=1; } expr
- { Lex->having= $3; Lex->create_refs=0; }
+ | HAVING { Select->create_refs=1; } expr
+ {
+ SELECT_LEX *sel=Select;
+ sel->having= $3; sel->create_refs=0;
+ }
opt_escape:
ESCAPE_SYM TEXT_STRING { $$= $2.str; }
@@ -1893,7 +2149,13 @@ opt_order_clause:
| order_clause
order_clause:
- ORDER_SYM BY order_list
+ ORDER_SYM BY
+ {
+ LEX *lex=Lex;
+ if (lex->sql_command == SQLCOM_MULTI_UPDATE)
+ YYABORT;
+ lex->select->sort_default=1;
+ } order_list
order_list:
order_list ',' order_ident order_dir
@@ -1908,33 +2170,41 @@ order_dir:
limit_clause:
- /* empty */
- {
- Lex->select_limit= current_thd->default_select_limit;
- Lex->offset_limit= 0L;
- }
+ /* empty */ {}
| LIMIT ULONG_NUM
- { Lex->select_limit= $2; Lex->offset_limit=0L; }
+ {
+ SELECT_LEX *sel=Select;
+ sel->select_limit= $2;
+ sel->offset_limit=0L;
+ }
| LIMIT ULONG_NUM ',' ULONG_NUM
- { Lex->select_limit= $4; Lex->offset_limit=$2; }
+ {
+ SELECT_LEX *sel=Select;
+ sel->select_limit= $4; sel->offset_limit=$2;
+ }
delete_limit_clause:
/* empty */
{
- Lex->select_limit= HA_POS_ERROR;
+ LEX *lex=Lex;
+ if (lex->sql_command == SQLCOM_MULTI_UPDATE)
+ YYABORT;
+ lex->select->select_limit= HA_POS_ERROR;
}
- | LIMIT ULONGLONG_NUM
- { Lex->select_limit= (ha_rows) $2; }
+ | LIMIT ulonglong_num
+ { Select->select_limit= (ha_rows) $2; }
ULONG_NUM:
- NUM { $$= strtoul($1.str,NULL,10); }
- | REAL_NUM { $$= strtoul($1.str,NULL,10); }
+ NUM { $$= strtoul($1.str,NULL,10); }
+ | ULONGLONG_NUM { $$= (ulong) strtoull($1.str,NULL,10); }
+ | REAL_NUM { $$= strtoul($1.str,NULL,10); }
| FLOAT_NUM { $$= strtoul($1.str,NULL,10); }
-ULONGLONG_NUM:
- NUM { $$= (ulonglong) strtoul($1.str,NULL,10); }
- | LONG_NUM { $$= strtoull($1.str,NULL,10); }
- | REAL_NUM { $$= strtoull($1.str,NULL,10); }
+ulonglong_num:
+ NUM { $$= (ulonglong) strtoul($1.str,NULL,10); }
+ | ULONGLONG_NUM { $$= strtoull($1.str,NULL,10); }
+ | LONG_NUM { $$= (ulonglong) strtoul($1.str,NULL,10); }
+ | REAL_NUM { $$= strtoull($1.str,NULL,10); }
| FLOAT_NUM { $$= strtoull($1.str,NULL,10); }
procedure_clause:
@@ -1947,6 +2217,7 @@ procedure_clause:
lex->proc_list.next= (byte**) &lex->proc_list.first;
if (add_proc_to_list(new Item_field(NULL,NULL,$2.str)))
YYABORT;
+ current_thd->safe_to_cache_query=0;
}
'(' procedure_list ')'
@@ -2000,36 +2271,40 @@ do: DO_SYM
drop:
DROP TABLE_SYM if_exists table_list opt_restrict
{
- Lex->sql_command = SQLCOM_DROP_TABLE;
- Lex->drop_if_exists = $3;
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_DROP_TABLE;
+ lex->drop_if_exists = $3;
}
| DROP INDEX ident ON table_ident {}
{
- Lex->sql_command= SQLCOM_DROP_INDEX;
- Lex->drop_list.empty();
- Lex->drop_list.push_back(new Alter_drop(Alter_drop::KEY,
+ LEX *lex=Lex;
+ lex->sql_command= SQLCOM_DROP_INDEX;
+ lex->drop_list.empty();
+ lex->drop_list.push_back(new Alter_drop(Alter_drop::KEY,
$3.str));
if (!add_table_to_list($5,NULL, 1))
YYABORT;
}
| DROP DATABASE if_exists ident
{
- Lex->sql_command= SQLCOM_DROP_DB;
- Lex->drop_if_exists=$3;
- Lex->name=$4.str;
+ LEX *lex=Lex;
+ lex->sql_command= SQLCOM_DROP_DB;
+ lex->drop_if_exists=$3;
+ lex->name=$4.str;
}
| DROP UDF_SYM ident
{
- Lex->sql_command = SQLCOM_DROP_FUNCTION;
- Lex->udf.name=$3.str;
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_DROP_FUNCTION;
+ lex->udf.name=$3.str;
}
table_list:
- table
- | table_list ',' table
+ table_name
+ | table_list ',' table_name
-table:
+table_name:
table_ident
{ if (!add_table_to_list($1,NULL,1)) YYABORT; }
@@ -2045,7 +2320,13 @@ insert:
INSERT { Lex->sql_command = SQLCOM_INSERT; } insert_lock_option opt_ignore insert2 insert_field_spec
replace:
- REPLACE { Lex->sql_command = SQLCOM_REPLACE; } replace_lock_option insert2 insert_field_spec
+ REPLACE
+ {
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_REPLACE;
+ lex->duplicates= DUP_REPLACE;
+ }
+ replace_lock_option insert2 insert_field_spec
insert_lock_option:
/* empty */ { Lex->lock_option= TL_WRITE_CONCURRENT_INSERT; }
@@ -2062,19 +2343,21 @@ insert2:
| insert_table {}
insert_table:
- table
+ table_name
{
- Lex->field_list.empty();
- Lex->many_values.empty();
- Lex->insert_list=0;
+ LEX *lex=Lex;
+ lex->field_list.empty();
+ lex->many_values.empty();
+ lex->insert_list=0;
}
insert_field_spec:
opt_field_spec insert_values {}
| SET
{
- if (!(Lex->insert_list = new List_item) ||
- Lex->many_values.push_back(Lex->insert_list))
+ LEX *lex=Lex;
+ if (!(lex->insert_list = new List_item) ||
+ lex->many_values.push_back(lex->insert_list))
YYABORT;
}
ident_eq_list
@@ -2098,7 +2381,7 @@ insert_values:
lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ;
mysql_init_select(lex);
}
- select_options select_item_list select_from select_lock_type {}
+ select_options select_item_list select_from select_lock_type union {}
values_list:
values_list ',' no_braces
@@ -2112,8 +2395,9 @@ ident_eq_list:
ident_eq_value:
simple_ident equal expr
{
- if (Lex->field_list.push_back($1) ||
- Lex->insert_list->push_back($3))
+ LEX *lex=Lex;
+ if (lex->field_list.push_back($1) ||
+ lex->insert_list->push_back($3))
YYABORT;
}
@@ -2128,7 +2412,8 @@ no_braces:
}
opt_values ')'
{
- if (Lex->many_values.push_back(Lex->insert_list))
+ LEX *lex=Lex;
+ if (lex->many_values.push_back(lex->insert_list))
YYABORT;
}
@@ -2151,8 +2436,15 @@ values:
/* Update rows in a table */
update:
- UPDATE_SYM opt_low_priority opt_ignore table SET update_list where_clause delete_limit_clause
- { Lex->sql_command = SQLCOM_UPDATE; }
+ UPDATE_SYM
+ {
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_UPDATE;
+ lex->select->order_list.elements=0;
+ lex->select->order_list.first=0;
+ lex->select->order_list.next= (byte**) &lex->select->order_list.first;
+ }
+ opt_low_priority opt_ignore join_table_list SET update_list where_clause opt_order_clause delete_limit_clause
update_list:
update_list ',' simple_ident equal expr
@@ -2174,31 +2466,69 @@ opt_low_priority:
delete:
DELETE_SYM
- {
- Lex->sql_command= SQLCOM_DELETE; Lex->options=0;
- Lex->lock_option= current_thd->update_lock_default;
+ {
+ LEX *lex=Lex;
+ lex->sql_command= SQLCOM_DELETE; lex->select->options=0;
+ lex->lock_option= lex->thd->update_lock_default;
+ lex->select->order_list.elements=0;
+ lex->select->order_list.first=0;
+ lex->select->order_list.next= (byte**) &lex->select->order_list.first;
}
- opt_delete_options FROM table
- where_clause delete_limit_clause
+ opt_delete_options single_multi {}
+
+single_multi:
+ FROM table_name where_clause opt_order_clause delete_limit_clause {}
+ | table_wild_list
+ { mysql_init_multi_delete(Lex); }
+ FROM join_table_list where_clause
+ | FROM table_wild_list
+ { mysql_init_multi_delete(Lex); }
+ USING join_table_list where_clause
+
+table_wild_list:
+ table_wild_one {}
+ | table_wild_list ',' table_wild_one {}
+
+table_wild_one:
+ ident opt_wild
+ {
+ if (!add_table_to_list(new Table_ident($1),NULL,1,TL_WRITE))
+ YYABORT;
+ }
+ | ident '.' ident opt_wild
+ {
+ if (!add_table_to_list(new Table_ident($1,$3,0),NULL,1,TL_WRITE))
+ YYABORT;
+ }
+
+opt_wild:
+ /* empty */ {}
+ | '.' '*' {}
opt_delete_options:
- /* empty */ {}
+ /* empty */ {}
| opt_delete_option opt_delete_options {}
opt_delete_option:
- QUICK { Lex->options|= OPTION_QUICK; }
+ QUICK { Select->options|= OPTION_QUICK; }
| LOW_PRIORITY { Lex->lock_option= TL_WRITE_LOW_PRIORITY; }
truncate:
- TRUNCATE_SYM opt_table_sym table
- { Lex->sql_command= SQLCOM_TRUNCATE; Lex->options=0;
- Lex->lock_option= current_thd->update_lock_default; }
+ TRUNCATE_SYM opt_table_sym table_name
+ {
+ LEX* lex = Lex;
+ lex->sql_command= SQLCOM_TRUNCATE;
+ lex->select->options=0;
+ lex->select->order_list.elements=0;
+ lex->select->order_list.first=0;
+ lex->select->order_list.next= (byte**) &lex->select->order_list.first;
+ lex->lock_option= current_thd->update_lock_default; }
opt_table_sym:
/* empty */
| TABLE_SYM
-
+
/* Show things */
show: SHOW { Lex->wild=0;} show_param
@@ -2207,18 +2537,26 @@ show_param:
DATABASES wild
{ Lex->sql_command= SQLCOM_SHOW_DATABASES; }
| TABLES opt_db wild
- { Lex->sql_command= SQLCOM_SHOW_TABLES; Lex->db= $2; Lex->options=0;}
+ {
+ LEX *lex=Lex;
+ lex->sql_command= SQLCOM_SHOW_TABLES;
+ lex->select->db= $2; lex->select->options=0;
+ }
| TABLE_SYM STATUS_SYM opt_db wild
- { Lex->sql_command= SQLCOM_SHOW_TABLES;
- Lex->options|= SELECT_DESCRIBE;
- Lex->db= $3;
+ {
+ LEX *lex=Lex;
+ lex->sql_command= SQLCOM_SHOW_TABLES;
+ lex->select->options|= SELECT_DESCRIBE;
+ lex->select->db= $3;
}
| OPEN_SYM TABLES opt_db wild
- { Lex->sql_command= SQLCOM_SHOW_OPEN_TABLES;
- Lex->db= $3;
- Lex->options=0;
+ {
+ LEX *lex=Lex;
+ lex->sql_command= SQLCOM_SHOW_OPEN_TABLES;
+ lex->select->db= $3;
+ lex->select->options=0;
}
- | opt_full COLUMNS FROM table_ident opt_db wild
+ | opt_full COLUMNS from_or_in table_ident opt_db wild
{
Lex->sql_command= SQLCOM_SHOW_FIELDS;
if ($5)
@@ -2226,10 +2564,31 @@ show_param:
if (!add_table_to_list($4,NULL,0))
YYABORT;
}
+ | NEW_SYM MASTER_SYM FOR_SYM SLAVE WITH MASTER_LOG_FILE_SYM EQ
+ TEXT_STRING AND MASTER_LOG_POS_SYM EQ ulonglong_num
+ AND MASTER_SERVER_ID_SYM EQ
+ ULONG_NUM
+ {
+ Lex->sql_command = SQLCOM_SHOW_NEW_MASTER;
+ Lex->mi.log_file_name = $8.str;
+ Lex->mi.pos = $12;
+ Lex->mi.server_id = $16;
+ }
| MASTER_SYM LOGS_SYM
{
Lex->sql_command = SQLCOM_SHOW_BINLOGS;
- }
+ }
+ | SLAVE HOSTS_SYM
+ {
+ Lex->sql_command = SQLCOM_SHOW_SLAVE_HOSTS;
+ }
+ | BINLOG_SYM EVENTS_SYM binlog_in binlog_from
+ {
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_SHOW_BINLOG_EVENTS;
+ lex->select->select_limit= lex->thd->default_select_limit;
+ lex->select->offset_limit= 0L;
+ } limit_clause
| keys_or_index FROM table_ident opt_db
{
Lex->sql_command= SQLCOM_SHOW_KEYS;
@@ -2247,8 +2606,12 @@ show_param:
| LOGS_SYM
{ Lex->sql_command= SQLCOM_SHOW_LOGS; }
| GRANTS FOR_SYM user
- { Lex->sql_command= SQLCOM_SHOW_GRANTS;
- Lex->grant_user=$3; Lex->grant_user->password.str=NullS; }
+ {
+ LEX *lex=Lex;
+ lex->sql_command= SQLCOM_SHOW_GRANTS;
+ lex->grant_user=$3;
+ lex->grant_user->password.str=NullS;
+ }
| CREATE TABLE_SYM table_ident
{
Lex->sql_command = SQLCOM_SHOW_CREATE;
@@ -2266,7 +2629,7 @@ show_param:
opt_db:
/* empty */ { $$= 0; }
- | FROM ident { $$= $2.str; }
+ | from_or_in ident { $$= $2.str; }
wild:
/* empty */
@@ -2276,18 +2639,32 @@ opt_full:
/* empty */ { Lex->verbose=0; }
| FULL { Lex->verbose=1; }
+from_or_in:
+ FROM
+ | IN_SYM
+
+binlog_in:
+ /* empty */ { Lex->mi.log_file_name = 0; }
+ | IN_SYM TEXT_STRING { Lex->mi.log_file_name = $2.str; }
+
+binlog_from:
+ /* empty */ { Lex->mi.pos = 4; /* skip magic number */ }
+ | FROM ulonglong_num { Lex->mi.pos = $2; }
+
+
/* A Oracle compatible synonym for show */
describe:
describe_command table_ident
{
- Lex->wild=0;
- Lex->verbose=0;
- Lex->sql_command=SQLCOM_SHOW_FIELDS;
+ LEX *lex=Lex;
+ lex->wild=0;
+ lex->verbose=0;
+ lex->sql_command=SQLCOM_SHOW_FIELDS;
if (!add_table_to_list($2, NULL,0))
YYABORT;
}
opt_describe_column
- | describe_command select { Lex->options|= SELECT_DESCRIBE };
+ | describe_command select { Lex->select_lex.options|= SELECT_DESCRIBE; }
describe_command:
@@ -2303,7 +2680,12 @@ opt_describe_column:
/* flush things */
flush:
- FLUSH_SYM {Lex->sql_command= SQLCOM_FLUSH; Lex->type=0; } flush_options
+ FLUSH_SYM
+ {
+ LEX *lex=Lex;
+ lex->sql_command= SQLCOM_FLUSH; lex->type=0;
+ }
+ flush_options
flush_options:
flush_options ',' flush_option
@@ -2312,30 +2694,41 @@ flush_options:
flush_option:
table_or_tables { Lex->type|= REFRESH_TABLES; } opt_table_list
| TABLES WITH READ_SYM LOCK_SYM { Lex->type|= REFRESH_TABLES | REFRESH_READ_LOCK; }
+ | QUERY_SYM CACHE_SYM { Lex->type|= REFRESH_QUERY_CACHE_FREE; }
| HOSTS_SYM { Lex->type|= REFRESH_HOSTS; }
| PRIVILEGES { Lex->type|= REFRESH_GRANT; }
| LOGS_SYM { Lex->type|= REFRESH_LOG; }
| STATUS_SYM { Lex->type|= REFRESH_STATUS; }
| SLAVE { Lex->type|= REFRESH_SLAVE; }
| MASTER_SYM { Lex->type|= REFRESH_MASTER; }
+ | DES_KEY_FILE { Lex->type|= REFRESH_DES_KEY_FILE; }
opt_table_list:
/* empty */ {}
| table_list {}
reset:
- RESET_SYM {Lex->sql_command= SQLCOM_RESET; Lex->type=0; } reset_options
-
+ RESET_SYM
+ {
+ LEX *lex=Lex;
+ lex->sql_command= SQLCOM_RESET; lex->type=0;
+ } reset_options
reset_options:
reset_options ',' reset_option
| reset_option
reset_option:
- SLAVE { Lex->type|= REFRESH_SLAVE; }
- | MASTER_SYM { Lex->type|= REFRESH_MASTER; }
+ SLAVE { Lex->type|= REFRESH_SLAVE; }
+ | MASTER_SYM { Lex->type|= REFRESH_MASTER; }
+ | QUERY_SYM CACHE_SYM { Lex->type|= REFRESH_QUERY_CACHE;}
purge:
- PURGE { Lex->sql_command = SQLCOM_PURGE; Lex->type=0;}
+ PURGE
+ {
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_PURGE;
+ lex->type=0;
+ }
MASTER_SYM LOGS_SYM TO_SYM TEXT_STRING
{
Lex->to_log = $6.str;
@@ -2346,30 +2739,34 @@ purge:
kill:
KILL_SYM expr
{
- if ($2->fix_fields(current_thd,0))
- {
- send_error(&current_thd->net, ER_SET_CONSTANTS_ONLY);
- YYABORT;
- }
- Lex->sql_command=SQLCOM_KILL;
- Lex->thread_id= (ulong) $2->val_int();
+ LEX *lex=Lex;
+ if ($2->fix_fields(lex->thd,0))
+ {
+ send_error(&lex->thd->net, ER_SET_CONSTANTS_ONLY);
+ YYABORT;
+ }
+ lex->sql_command=SQLCOM_KILL;
+ lex->thread_id= (ulong) $2->val_int();
}
/* change database */
use: USE_SYM ident
- { Lex->sql_command=SQLCOM_CHANGE_DB; Lex->db= $2.str; }
+ {
+ LEX *lex=Lex;
+ lex->sql_command=SQLCOM_CHANGE_DB; lex->select->db= $2.str;
+ }
/* import, export of files */
load: LOAD DATA_SYM load_data_lock opt_local INFILE TEXT_STRING
{
- LEX *lex= Lex;
+ LEX *lex=Lex;
lex->sql_command= SQLCOM_LOAD;
lex->local_file= $4;
- if (!(Lex->exchange= new sql_exchange($6.str,0)))
+ if (!(lex->exchange= new sql_exchange($6.str,0)))
YYABORT;
- Lex->field_list.empty();
+ lex->field_list.empty();
}
opt_duplicate INTO TABLE_SYM table_ident opt_field_term opt_line_term
opt_ignore_lines opt_field_spec
@@ -2385,6 +2782,11 @@ load: LOAD DATA_SYM load_data_lock opt_local INFILE TEXT_STRING
YYABORT;
}
+ |
+ LOAD DATA_SYM FROM MASTER_SYM
+ {
+ Lex->sql_command = SQLCOM_LOAD_MASTER_DATA;
+ }
opt_local:
/* empty */ { $$=0;}
@@ -2412,7 +2814,11 @@ field_term_list:
field_term:
TERMINATED BY text_string { Lex->exchange->field_term= $3;}
| OPTIONALLY ENCLOSED BY text_string
- { Lex->exchange->enclosed= $4; Lex->exchange->opt_enclosed=1;}
+ {
+ LEX *lex=Lex;
+ lex->exchange->enclosed= $4;
+ lex->exchange->opt_enclosed=1;
+ }
| ENCLOSED BY text_string { Lex->exchange->enclosed= $3;}
| ESCAPED BY text_string { Lex->exchange->escaped= $3;}
@@ -2452,11 +2858,12 @@ literal:
text_literal { $$ = $1; }
| NUM { $$ = new Item_int($1.str, (longlong) atol($1.str),$1.length); }
| LONG_NUM { $$ = new Item_int($1.str); }
+ | 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); }
| NULL_SYM { $$ = new Item_null();
Lex->next_state=STATE_OPERATOR_OR_IDENT;}
- | HEX_NUM { $$ = new Item_varbinary($1.str,$1.length)};
+ | HEX_NUM { $$ = new Item_varbinary($1.str,$1.length);}
| DATE_SYM text_literal { $$ = $2; }
| TIME_SYM text_literal { $$ = $2; }
| TIMESTAMP text_literal { $$ = $2; }
@@ -2479,13 +2886,25 @@ order_ident:
simple_ident:
ident
- { $$ = !Lex->create_refs || Lex->in_sum_expr > 0 ? (Item*) new Item_field(NullS,NullS,$1.str) : (Item*) new Item_ref(NullS,NullS,$1.str); }
+ {
+ SELECT_LEX *sel=Select;
+ $$ = !sel->create_refs || sel->in_sum_expr > 0 ? (Item*) new Item_field(NullS,NullS,$1.str) : (Item*) new Item_ref(NullS,NullS,$1.str);
+ }
| ident '.' ident
- { $$ = !Lex->create_refs || Lex->in_sum_expr > 0 ? (Item*) new Item_field(NullS,$1.str,$3.str) : (Item*) new Item_ref(NullS,$1.str,$3.str); }
+ {
+ SELECT_LEX *sel=Select;
+ $$ = !sel->create_refs || sel->in_sum_expr > 0 ? (Item*) new Item_field(NullS,$1.str,$3.str) : (Item*) new Item_ref(NullS,$1.str,$3.str);
+ }
| '.' ident '.' ident
- { $$ = !Lex->create_refs || Lex->in_sum_expr > 0 ? (Item*) new Item_field(NullS,$2.str,$4.str) : (Item*) new Item_ref(NullS,$2.str,$4.str); }
+ {
+ SELECT_LEX *sel=Select;
+ $$ = !sel->create_refs || sel->in_sum_expr > 0 ? (Item*) new Item_field(NullS,$2.str,$4.str) : (Item*) new Item_ref(NullS,$2.str,$4.str);
+ }
| ident '.' ident '.' ident
- { $$ = !Lex->create_refs || Lex->in_sum_expr > 0 ? (Item*) new Item_field((current_thd->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str) : (Item*) new Item_ref((current_thd->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str); }
+ {
+ SELECT_LEX *sel=Select;
+ $$ = !sel->create_refs || sel->in_sum_expr > 0 ? (Item*) new Item_field((current_thd->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str) : (Item*) new Item_ref((current_thd->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str);
+ }
field_ident:
@@ -2502,10 +2921,11 @@ ident:
IDENT { $$=$1; }
| keyword
{
+ LEX *lex;
$$.str=sql_strmake($1.str,$1.length);
$$.length=$1.length;
- if (Lex->next_state != STATE_END)
- Lex->next_state=STATE_OPERATOR_OR_IDENT;
+ if ((lex=Lex)->next_state != STATE_END)
+ lex->next_state=STATE_OPERATOR_OR_IDENT;
}
ident_or_text:
@@ -2541,14 +2961,19 @@ keyword:
| BACKUP_SYM {}
| BEGIN_SYM {}
| BERKELEY_DB_SYM {}
+ | BINLOG_SYM {}
| BIT_SYM {}
| BOOL_SYM {}
+ | BOOLEAN_SYM {}
+ | CACHE_SYM {}
| CHANGED {}
| CHECKSUM_SYM {}
| CHECK_SYM {}
+ | CIPHER_SYM {}
+ | CLOSE_SYM {}
| COMMENT_SYM {}
- | COMMIT_SYM {}
| COMMITTED_SYM {}
+ | COMMIT_SYM {}
| COMPRESSED_SYM {}
| CONCURRENT {}
| DATA_SYM {}
@@ -2556,29 +2981,39 @@ keyword:
| DATE_SYM {}
| DAY_SYM {}
| DELAY_KEY_WRITE_SYM {}
+ | DEMAND_SYM {}
+ | DES_KEY_FILE {}
+ | DIRECTORY_SYM {}
| DO_SYM {}
| DUMPFILE {}
| DYNAMIC_SYM {}
| END {}
| ENUM {}
| ESCAPE_SYM {}
+ | EVENTS_SYM {}
| EXTENDED_SYM {}
| FAST_SYM {}
+ | DISABLE_SYM {}
+ | ENABLE_SYM {}
| FULL {}
| FILE_SYM {}
| FIRST_SYM {}
| FIXED_SYM {}
| FLUSH_SYM {}
| GRANTS {}
- | GEMINI_SYM {}
| GLOBAL_SYM {}
| HEAP_SYM {}
+ | HANDLER_SYM {}
| HOSTS_SYM {}
| HOUR_SYM {}
| IDENTIFIED_SYM {}
+ | INDEXES {}
| ISOLATION {}
| ISAM_SYM {}
+ | ISSUER_SYM {}
| INNOBASE_SYM {}
+ | INSERT_METHOD {}
+ | LAST_SYM {}
| LEVEL_SYM {}
| LOCAL_SYM {}
| LOCKS_SYM {}
@@ -2592,6 +3027,7 @@ keyword:
| MASTER_USER_SYM {}
| MASTER_PASSWORD_SYM {}
| MASTER_CONNECT_RETRY_SYM {}
+ | MAX_QUERIES_PER_HOUR {}
| MEDIUM_SYM {}
| MERGE_SYM {}
| MINUTE_SYM {}
@@ -2602,12 +3038,17 @@ keyword:
| MYISAM_SYM {}
| NATIONAL_SYM {}
| NCHAR_SYM {}
+ | NEXT_SYM {}
+ | NEW_SYM {}
| NO_SYM {}
+ | OFF {}
| OPEN_SYM {}
| PACK_KEYS_SYM {}
| PASSWORD {}
+ | PREV_SYM {}
| PROCESS {}
| PROCESSLIST_SYM {}
+ | QUERY_SYM {}
| QUICK {}
| RAID_0_SYM {}
| RAID_CHUNKS {}
@@ -2626,12 +3067,18 @@ keyword:
| SECOND_SYM {}
| SERIALIZABLE_SYM {}
| SESSION_SYM {}
+ | SIGNED_SYM {}
| SHARE_SYM {}
| SHUTDOWN {}
+ | SLAVE {}
+ | SQL_CACHE_SYM {}
+ | SQL_NO_CACHE_SYM {}
+ | SQL_QUERY_CACHE_TYPE_SYM {}
| START_SYM {}
| STATUS_SYM {}
| STOP_SYM {}
| STRING_SYM {}
+ | SUBJECT_SYM {}
| TEMPORARY {}
| TEXT_SYM {}
| TRANSACTION_SYM {}
@@ -2641,23 +3088,23 @@ keyword:
| TYPE_SYM {}
| UDF_SYM {}
| UNCOMMITTED_SYM {}
+ | USE_FRM {}
| VARIABLES {}
| WORK_SYM {}
| YEAR_SYM {}
- | SLAVE {}
/* Option functions */
set:
SET opt_option
{
- THD *thd=current_thd;
- LEX *lex= &thd->lex;
+ LEX *lex=Lex;
lex->sql_command= SQLCOM_SET_OPTION;
- lex->options=thd->options;
- lex->select_limit=thd->default_select_limit;
- lex->gemini_spin_retries=thd->gemini_spin_retries;
- lex->tx_isolation=thd->tx_isolation;
+ lex->select->options=lex->thd->options;
+ lex->select->select_limit=lex->thd->default_select_limit;
+ lex->tx_isolation=lex->thd->tx_isolation;
+ lex->option_type=0;
+ lex->option_list.empty();
}
option_value_list
@@ -2667,36 +3114,41 @@ opt_option:
option_value_list:
option_value
+ | GLOBAL_SYM { Lex->option_type=1; } option_value
+ | LOCAL_SYM { Lex->option_type=0; } option_value
| option_value_list ',' option_value
option_value:
set_option equal NUM
{
+ SELECT_LEX *sel=Select;
if (atoi($3.str) == 0)
- Lex->options&= ~$1;
+ sel->options&= ~$1;
else
- Lex->options|= $1;
+ sel->options|= $1;
}
| set_isolation
| AUTOCOMMIT equal NUM
{
+ SELECT_LEX *sel=Select;
if (atoi($3.str) != 0) /* Test NOT AUTOCOMMIT */
- Lex->options&= ~(OPTION_NOT_AUTO_COMMIT);
+ sel->options&= ~(OPTION_NOT_AUTO_COMMIT);
else
- Lex->options|= OPTION_NOT_AUTO_COMMIT;
+ sel->options|= OPTION_NOT_AUTO_COMMIT;
}
| SQL_SELECT_LIMIT equal ULONG_NUM
{
- Lex->select_limit= $3;
+ Select->select_limit= $3;
}
| SQL_SELECT_LIMIT equal DEFAULT
{
- Lex->select_limit= HA_POS_ERROR;
+ Select->select_limit= HA_POS_ERROR;
}
| SQL_MAX_JOIN_SIZE equal ULONG_NUM
{
- current_thd->max_join_size= $3;
- Lex->options&= ~OPTION_BIG_SELECTS;
+ LEX *lex=Lex;
+ lex->thd->max_join_size= $3;
+ lex->select->options&= ~OPTION_BIG_SELECTS;
}
| SQL_MAX_JOIN_SIZE equal DEFAULT
{
@@ -2710,22 +3162,14 @@ option_value:
{
current_thd->user_time=0;
}
- | LAST_INSERT_ID equal ULONGLONG_NUM
+ | LAST_INSERT_ID equal ulonglong_num
{
current_thd->insert_id($3);
}
- | INSERT_ID equal ULONGLONG_NUM
+ | INSERT_ID equal ulonglong_num
{
current_thd->next_insert_id=$3;
}
- | GEMINI_SPIN_RETRIES equal ULONG_NUM
- {
- Lex->gemini_spin_retries= $3;
- }
- | GEMINI_SPIN_RETRIES equal DEFAULT
- {
- Lex->gemini_spin_retries= 1;
- }
| CHAR_SYM SET IDENT
{
CONVERT *tmp;
@@ -2753,6 +3197,7 @@ option_value:
$3->user.str,$5))
YYABORT;
}
+ | SQL_QUERY_CACHE_TYPE_SYM equal query_cache_type
| '@' ident_or_text equal expr
{
Item_func_set_user_var *item = new Item_func_set_user_var($2,$4);
@@ -2764,13 +3209,46 @@ option_value:
}
| SQL_SLAVE_SKIP_COUNTER equal ULONG_NUM
{
- pthread_mutex_lock(&LOCK_slave);
- if(slave_running)
+ LOCK_ACTIVE_MI;
+ pthread_mutex_lock(&active_mi->rli.run_lock);
+ if (active_mi->rli.slave_running)
send_error(&current_thd->net, ER_SLAVE_MUST_STOP);
else
- slave_skip_counter = $3;
- pthread_mutex_unlock(&LOCK_slave);
+ {
+ pthread_mutex_lock(&active_mi->rli.data_lock);
+ active_mi->rli.slave_skip_counter = $3;
+ pthread_mutex_unlock(&active_mi->rli.data_lock);
+ }
+ pthread_mutex_unlock(&active_mi->rli.run_lock);
+ UNLOCK_ACTIVE_MI;
}
+ | ident equal DEFAULT
+ {
+ LEX *lex=Lex;
+ lex->option_list.push_back(new Set_option(lex->option_type,
+ $1.str,$1.length,
+ (Item*) 0));
+ }
+ | ident equal expr
+ {
+ THD *thd=current_thd;
+ Item *item= $3;
+ if (item->fix_fields(current_thd,0))
+ {
+ send_error(&thd->net, ER_SET_CONSTANTS_ONLY);
+ YYABORT;
+ }
+ thd->lex.option_list.
+ push_back(new Set_option(thd->lex.option_type,
+ $1.str,$1.length,
+ item));
+ }
+
+query_cache_type:
+ NUM { current_thd->query_cache_type = set_zone(atoi($1.str),0,3); }
+ | OFF { current_thd->query_cache_type = 0; }
+ | ON { current_thd->query_cache_type = 1; }
+ | DEMAND_SYM { current_thd->query_cache_type = 2; }
text_or_password:
TEXT_STRING { $$=$1.str;}
@@ -2819,7 +3297,10 @@ set_isolation:
default_tx_isolation_name=tx_isolation_typelib.type_names[default_tx_isolation];
}
| SESSION_SYM tx_isolation
- { current_thd->session_tx_isolation= Lex->tx_isolation= $2; }
+ {
+ LEX *lex=Lex;
+ lex->thd->session_tx_isolation= lex->tx_isolation= $2;
+ }
| tx_isolation
{ Lex->tx_isolation= $1; }
@@ -2863,30 +3344,93 @@ unlock:
UNLOCK_SYM table_or_tables { Lex->sql_command=SQLCOM_UNLOCK_TABLES; }
+/*
+** Handler: direct access to ISAM functions
+*/
+
+handler:
+ HANDLER_SYM table_ident OPEN_SYM opt_table_alias
+ {
+ Lex->sql_command = SQLCOM_HA_OPEN;
+ if (!add_table_to_list($2,$4,0))
+ YYABORT;
+ }
+ | HANDLER_SYM table_ident CLOSE_SYM
+ {
+ Lex->sql_command = SQLCOM_HA_CLOSE;
+ if (!add_table_to_list($2,0,0))
+ YYABORT;
+ }
+ | HANDLER_SYM table_ident READ_SYM
+ {
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_HA_READ;
+ lex->ha_rkey_mode= HA_READ_KEY_EXACT; /* Avoid purify warnings */
+ lex->select->select_limit= 1;
+ lex->select->offset_limit= 0L;
+ if (!add_table_to_list($2,0,0))
+ YYABORT;
+ }
+ handler_read_or_scan where_clause limit_clause { }
+
+handler_read_or_scan:
+ handler_scan_function { Lex->backup_dir= 0; }
+ | ident handler_rkey_function { Lex->backup_dir= $1.str; }
+
+handler_scan_function:
+ FIRST_SYM { Lex->ha_read_mode = RFIRST; }
+ | NEXT_SYM { Lex->ha_read_mode = RNEXT; }
+
+handler_rkey_function:
+ FIRST_SYM { Lex->ha_read_mode = RFIRST; }
+ | NEXT_SYM { Lex->ha_read_mode = RNEXT; }
+ | PREV_SYM { Lex->ha_read_mode = RPREV; }
+ | LAST_SYM { Lex->ha_read_mode = RLAST; }
+ | handler_rkey_mode
+ {
+ LEX *lex=Lex;
+ lex->ha_read_mode = RKEY;
+ lex->ha_rkey_mode=$1;
+ if (!(lex->insert_list = new List_item))
+ YYABORT;
+ } '(' values ')' { }
+
+handler_rkey_mode:
+ EQ { $$=HA_READ_KEY_EXACT; }
+ | GE { $$=HA_READ_KEY_OR_NEXT; }
+ | LE { $$=HA_READ_KEY_OR_PREV; }
+ | GT_SYM { $$=HA_READ_AFTER_KEY; }
+ | LT { $$=HA_READ_BEFORE_KEY; }
+
/* GRANT / REVOKE */
revoke:
REVOKE
{
- Lex->sql_command = SQLCOM_REVOKE;
- Lex->users_list.empty();
- Lex->columns.empty();
- Lex->grant= Lex->grant_tot_col=0;
- Lex->db=0;
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_REVOKE;
+ lex->users_list.empty();
+ lex->columns.empty();
+ lex->grant= lex->grant_tot_col=0;
+ lex->select->db=0;
}
grant_privileges ON opt_table FROM user_list
grant:
GRANT
{
- Lex->sql_command = SQLCOM_GRANT;
- Lex->users_list.empty();
- Lex->columns.empty();
- Lex->grant= Lex->grant_tot_col=0;
- Lex->db=0;
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_GRANT;
+ lex->users_list.empty();
+ lex->columns.empty();
+ lex->grant= lex->grant_tot_col=0;
+ lex->select->db=0;
+ lex->ssl_type=SSL_TYPE_NONE;
+ lex->ssl_cipher=lex->x509_subject=lex->x509_issuer=0;
+ lex->mqh=0;
}
grant_privileges ON opt_table TO_SYM user_list
- grant_option
+ require_clause grant_options
grant_privileges:
grant_privilege_list {}
@@ -2920,46 +3464,84 @@ grant_privilege:
| FILE_SYM { Lex->grant |= FILE_ACL;}
| GRANT OPTION { Lex->grant |= GRANT_ACL;}
+require_list: require_list_element AND require_list
+| require_list_element
+
+require_list_element: SUBJECT_SYM TEXT_STRING
+ {
+ LEX *lex=Lex;
+ if (lex->x509_subject)
+ {
+ net_printf(&lex->thd->net,ER_DUP_ARGUMENT, "SUBJECT");
+ YYABORT;
+ }
+ lex->x509_subject=$2.str;
+ }
+ | ISSUER_SYM TEXT_STRING
+ {
+ LEX *lex=Lex;
+ if (lex->x509_issuer)
+ {
+ net_printf(&lex->thd->net,ER_DUP_ARGUMENT, "ISSUER");
+ YYABORT;
+ }
+ lex->x509_issuer=$2.str;
+ }
+ | CIPHER_SYM TEXT_STRING
+ {
+ LEX *lex=Lex;
+ if (lex->ssl_cipher)
+ {
+ net_printf(&lex->thd->net,ER_DUP_ARGUMENT, "CHIPER");
+ YYABORT;
+ }
+ lex->ssl_cipher=$2.str;
+ }
+
opt_table:
'*'
{
- Lex->db=current_thd->db;
- if (Lex->grant == UINT_MAX)
- Lex->grant = DB_ACLS & ~GRANT_ACL;
- else if (Lex->columns.elements)
+ LEX *lex=Lex;
+ lex->select->db=lex->thd->db;
+ if (lex->grant == UINT_MAX)
+ lex->grant = DB_ACLS & ~GRANT_ACL;
+ else if (lex->columns.elements)
{
- net_printf(&current_thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
+ send_error(&lex->thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
YYABORT;
- }
+ }
}
| ident '.' '*'
{
- Lex->db = $1.str;
- if (Lex->grant == UINT_MAX)
- Lex->grant = DB_ACLS & ~GRANT_ACL;
- else if (Lex->columns.elements)
+ LEX *lex=Lex;
+ lex->select->db = $1.str;
+ if (lex->grant == UINT_MAX)
+ lex->grant = DB_ACLS & ~GRANT_ACL;
+ else if (lex->columns.elements)
{
- net_printf(&current_thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
+ send_error(&lex->thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
YYABORT;
}
}
| '*' '.' '*'
{
- Lex->db = NULL;
- if (Lex->grant == UINT_MAX)
- Lex->grant = GLOBAL_ACLS & ~GRANT_ACL;
- else if (Lex->columns.elements)
+ LEX *lex=Lex;
+ lex->select->db = NULL;
+ if (lex->grant == UINT_MAX)
+ lex->grant = GLOBAL_ACLS & ~GRANT_ACL;
+ else if (lex->columns.elements)
{
- net_printf(&current_thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
+ send_error(&lex->thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
YYABORT;
}
}
| table_ident
{
+ LEX *lex=Lex;
if (!add_table_to_list($1,NULL,0))
YYABORT;
- if (Lex->grant == UINT_MAX)
- Lex->grant = TABLE_ACLS & ~GRANT_ACL;
+ if (lex->grant == UINT_MAX)
+ lex->grant = TABLE_ACLS & ~GRANT_ACL;
}
@@ -2990,7 +3572,11 @@ grant_user:
opt_column_list:
- /* empty */ { Lex->grant |= Lex->which_columns; }
+ /* empty */
+ {
+ LEX *lex=Lex;
+ lex->grant |= lex->which_columns;
+ }
| '(' column_list ')'
column_list:
@@ -3003,21 +3589,48 @@ column_list_id:
String *new_str = new String((const char*) $1.str,$1.length);
List_iterator <LEX_COLUMN> iter(Lex->columns);
class LEX_COLUMN *point;
+ LEX *lex=Lex;
while ((point=iter++))
{
if (!my_strcasecmp(point->column.ptr(),new_str->ptr()))
break;
}
- Lex->grant_tot_col|= Lex->which_columns;
+ lex->grant_tot_col|= lex->which_columns;
if (point)
- point->rights |= Lex->which_columns;
+ point->rights |= lex->which_columns;
else
- Lex->columns.push_back(new LEX_COLUMN (*new_str,Lex->which_columns));
+ lex->columns.push_back(new LEX_COLUMN (*new_str,lex->which_columns));
}
-grant_option:
+
+require_clause: /* empty */
+ | REQUIRE_SYM require_list
+ {
+ Lex->ssl_type=SSL_TYPE_SPECIFIED;
+ }
+ | REQUIRE_SYM SSL_SYM
+ {
+ Lex->ssl_type=SSL_TYPE_ANY;
+ }
+ | REQUIRE_SYM X509_SYM
+ {
+ Lex->ssl_type=SSL_TYPE_X509;
+ }
+
+grant_options:
/* empty */ {}
- | WITH GRANT OPTION { Lex->grant |= GRANT_ACL;}
+ | WITH grant_option_list
+
+grant_option_list:
+ grant_option_list grant_option {}
+ | grant_option {}
+
+grant_option:
+ GRANT OPTION { Lex->grant |= GRANT_ACL;}
+ | MAX_QUERIES_PER_HOUR EQ NUM
+ {
+ Lex->mqh=atoi($3.str);
+ }
begin:
BEGIN_SYM { Lex->sql_command = SQLCOM_BEGIN;} opt_work
@@ -3031,3 +3644,50 @@ commit:
rollback:
ROLLBACK_SYM { Lex->sql_command = SQLCOM_ROLLBACK;}
+
+
+/*
+** UNIONS : glue selects together
+*/
+
+
+union:
+ /* empty */ {}
+ | union_list
+
+union_list:
+ UNION_SYM union_option
+ {
+ LEX *lex=Lex;
+ if (lex->exchange)
+ {
+ /* Only the last SELECT can have INTO...... */
+ net_printf(&lex->thd->net, ER_WRONG_USAGE,"UNION","INTO");
+ YYABORT;
+ }
+ if (lex->select->linkage == NOT_A_SELECT || mysql_new_select(lex))
+ YYABORT;
+ lex->select->linkage=UNION_TYPE;
+ }
+ select_init
+
+union_opt:
+ union {}
+ | optional_order_or_limit {}
+
+optional_order_or_limit:
+ /* emty */ {}
+ |
+ {
+ LEX *lex=Lex;
+ if (!lex->select->braces || mysql_new_select(lex))
+ YYABORT;
+ mysql_init_select(lex);
+ lex->select->linkage=NOT_A_SELECT;
+ lex->select->select_limit=lex->thd->default_select_limit;
+ }
+ opt_order_clause limit_clause
+
+union_option:
+ /* empty */ {}
+ | ALL {Lex->union_option=1;}
diff --git a/sql/stacktrace.c b/sql/stacktrace.c
index f4415571f1b..d86d65f567e 100644
--- a/sql/stacktrace.c
+++ b/sql/stacktrace.c
@@ -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 */
-#include <global.h>
+#include <my_global.h>
#include "stacktrace.h"
#include <signal.h>
#include <my_pthread.h>
@@ -122,8 +122,8 @@ terribly wrong...\n");
return;
}
#endif /* __alpha__ */
-
- if (!stack_bottom)
+
+ if (!stack_bottom || (gptr) stack_bottom > (gptr) &fp)
{
ulong tmp= min(0x10000,thread_stack);
/* Assume that the stack starts at the previous even 65K */
@@ -150,7 +150,7 @@ terribly wrong...\n");
:"=r"(pc)
:"r"(pc));
#endif /* __alpha__ */
-
+
while (fp < (uchar**) stack_bottom)
{
#ifdef __i386__
@@ -165,7 +165,7 @@ terribly wrong...\n");
{
new_fp += 90;
}
-
+
if (fp && pc)
{
pc = find_prev_pc(pc, fp);
@@ -195,7 +195,7 @@ terribly wrong...\n");
}
fprintf(stderr, "Stack trace seems successful - bottom reached\n");
-
+
end:
fprintf(stderr, "Please read http://www.mysql.com/doc/U/s/Using_stack_trace.html and follow instructions on how to resolve the stack trace. Resolved\n\
stack trace is much more helpful in diagnosing the problem, so please do \n\
diff --git a/sql/structs.h b/sql/structs.h
index 36f503312c0..9e577128c8d 100644
--- a/sql/structs.h
+++ b/sql/structs.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 */
@@ -125,7 +125,23 @@ typedef struct {
enum SHOW_TYPE { SHOW_LONG,SHOW_CHAR,SHOW_INT,SHOW_CHAR_PTR,SHOW_BOOL,
SHOW_MY_BOOL,SHOW_OPENTABLES,SHOW_STARTTIME,SHOW_QUESTION,
- SHOW_LONG_CONST, SHOW_INT_CONST, SHOW_HAVE};
+ SHOW_LONG_CONST, SHOW_INT_CONST, SHOW_HAVE
+#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
+ ,SHOW_SSL_CTX_SESS_CB_HITS, SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE
+ ,SHOW_SSL_CTX_SESS_NUMBER, SHOW_SSL_SESSION_REUSED
+ ,SHOW_SSL_CTX_SESS_GET_CACHE_SIZE, SHOW_SSL_GET_CIPHER
+ ,SHOW_SSL_GET_DEFAULT_TIMEOUT, SHOW_SSL_GET_VERIFY_MODE
+ ,SHOW_SSL_CTX_GET_VERIFY_MODE, SHOW_SSL_GET_VERIFY_DEPTH
+ ,SHOW_SSL_CTX_GET_VERIFY_DEPTH, SHOW_SSL_CTX_SESS_CONNECT
+ ,SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE, SHOW_SSL_CTX_SESS_CONNECT_GOOD
+ ,SHOW_SSL_CTX_SESS_HITS, SHOW_SSL_CTX_SESS_MISSES
+ ,SHOW_SSL_CTX_SESS_TIMEOUTS, SHOW_SSL_CTX_SESS_CACHE_FULL
+ ,SHOW_SSL_GET_CIPHER_LIST
+#endif /* HAVE_OPENSSL */
+ ,SHOW_RPL_STATUS, SHOW_SLAVE_RUNNING
+};
enum SHOW_COMP_OPTION { SHOW_OPTION_YES, SHOW_OPTION_NO, SHOW_OPTION_DISABLED};
@@ -144,6 +160,14 @@ typedef struct st_lex_user {
LEX_STRING user, host, password;
} LEX_USER;
+
+typedef struct user_conn {
+ char *user;
+ uint len, connections, questions, max_questions;
+ time_t intime;
+} UC;
+
+
/* 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 */
@@ -154,13 +178,14 @@ typedef struct st_lex_user {
#define REG_MAY_BE_UPDATED 64
#define REG_AUTO_UPDATE 64 /* Used in D-forms for scroll-tables */
#define REG_OVERWRITE 128
-#define REG_SKIPP_DUPP 256
+#define REG_SKIP_DUP 256
/* Bits in form->status */
#define STATUS_NO_RECORD (1+2) /* Record isn't usably */
#define STATUS_GARBAGE 1
-#define STATUS_NOT_FOUND 2 /* No record in database when neaded */
+#define STATUS_NOT_FOUND 2 /* No record in database when needed */
#define STATUS_NO_PARENT 4 /* Parent record wasn't found */
#define STATUS_NOT_READ 8 /* Record isn't read */
#define STATUS_UPDATED 16 /* Record is updated by formula */
#define STATUS_NULL_ROW 32 /* table->null_row is set */
+#define STATUS_DELETED 64
diff --git a/sql/table.cc b/sql/table.cc
index 66cbe7cfa16..023d4d85df9 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -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 */
@@ -259,7 +259,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
outparam->comment=strdup_root(&outparam->mem_root,
(char*) head+47);
- DBUG_PRINT("form",("i_count: %d i_parts: %d index: %d n_length: %d int_length: %d", interval_count,interval_parts, outparam->keys,n_length,int_length));
+ DBUG_PRINT("info",("i_count: %d i_parts: %d index: %d n_length: %d int_length: %d", interval_count,interval_parts, outparam->keys,n_length,int_length));
if (!(field_ptr = (Field **)
alloc_root(&outparam->mem_root,
@@ -453,15 +453,20 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
if (key == primary_key)
{
field->flags|= PRI_KEY_FLAG;
+ /*
+ If this field is part of the primary key and all keys contains
+ 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|= ((key_map) 1 << primary_key);
+ field->part_of_key= outparam->keys_in_use;
}
if (field->key_length() != key_part->length)
{
key_part->key_part_flag|= HA_PART_KEY;
if (field->type() != FIELD_TYPE_BLOB)
{ // Create a new field
- field=key_part->field=field->new_field(outparam);
+ field=key_part->field=field->new_field(&outparam->mem_root,
+ outparam);
field->field_length=key_part->length;
}
}
@@ -478,8 +483,6 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
(outparam->keys_in_use & ((key_map) 1 << primary_key)))
{
outparam->primary_key=primary_key;
- if (outparam->file->option_flag() & HA_PRIMARY_KEY_IN_READ_INDEX)
- outparam->ref_primary_key= (key_map) 1 << primary_key;
/*
If we are using an integer as the primary key then allow the user to
refer to it as '_rowid'
@@ -821,7 +824,7 @@ fix_type_pointers(const char ***array, TYPELIB *point_to_type, uint types,
*type_name= '\0'; /* End string */
ptr=type_name;
}
- ptr+=2; /* Skipp end mark and last 0 */
+ ptr+=2; /* Skip end mark and last 0 */
}
else
ptr++;
@@ -995,6 +998,7 @@ File create_frm(register my_string name, uint reclength, uchar *fileinfo,
void update_create_info_from_table(HA_CREATE_INFO *create_info, TABLE *table)
{
+ 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;
@@ -1003,7 +1007,8 @@ void update_create_info_from_table(HA_CREATE_INFO *create_info, TABLE *table)
create_info->raid_type=table->raid_type;
create_info->raid_chunks=table->raid_chunks;
create_info->raid_chunksize=table->raid_chunksize;
-}
+ DBUG_VOID_RETURN;
+}
int
rename_file_ext(const char * from,const char * to,const char * ext)
diff --git a/sql/table.h b/sql/table.h
index b627a158556..606087ae3ac 100644
--- a/sql/table.h
+++ b/sql/table.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 */
@@ -89,14 +89,16 @@ struct st_table {
my_bool copy_blobs; /* copy_blobs when storing */
my_bool null_row; /* All columns are null */
my_bool maybe_null,outer_join; /* Used with OUTER JOIN */
- my_bool distinct,const_table;
+ 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 locked_by_flush;
my_bool locked_by_name;
+ my_bool fulltext_searched;
my_bool crashed;
my_bool is_view;
+ my_bool no_keyread;
Field *next_number_field, /* Set if next_number is activated */
*found_next_number_field, /* Set on open */
*rowid_field;
@@ -117,7 +119,7 @@ struct st_table {
byte *record_pointers; /* If sorted in memory */
ha_rows found_records; /* How many records in sort */
ORDER *group;
- key_map quick_keys, used_keys, ref_primary_key;
+ key_map quick_keys, used_keys;
ha_rows quick_rows[MAX_KEY];
uint quick_key_parts[MAX_KEY];
key_part_map const_key_parts[MAX_KEY];
@@ -145,4 +147,12 @@ typedef struct st_table_list {
uint outer_join; /* Which join type */
bool straight; /* optimize with prev table */
bool updating; /* for replicate-do/ignore table */
+ bool shared; /* Used twice in union */
} TABLE_LIST;
+
+typedef struct st_open_table_list
+{
+ struct st_open_table_list *next;
+ char *db,*table;
+ uint32 in_use,locked;
+} OPEN_TABLE_LIST;
diff --git a/sql/thr_malloc.cc b/sql/thr_malloc.cc
index deb304443df..8b9baa6f045 100644
--- a/sql/thr_malloc.cc
+++ b/sql/thr_malloc.cc
@@ -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 */
@@ -22,7 +22,9 @@
extern "C" {
void sql_alloc_error_handler(void)
{
- current_thd->fatal_error=1; /* purecov: inspected */
+ THD *thd=current_thd;
+ if (thd) // QQ; To be removed
+ thd->fatal_error=1; /* purecov: inspected */
sql_print_error(ER(ER_OUT_OF_RESOURCES));
}
}
diff --git a/sql/time.cc b/sql/time.cc
index 1d7e055f682..aab886648e3 100644
--- a/sql/time.cc
+++ b/sql/time.cc
@@ -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 */
@@ -24,7 +24,7 @@ static ulong const days_at_timestart=719528; /* daynr at 1970.01.01 */
uchar *days_in_month= (uchar*) "\037\034\037\036\037\036\037\037\036\037\036\037";
- /* Init some variabels neaded when using my_local_time */
+ /* Init some variabels needed when using my_local_time */
/* Currently only my_time_zone is inited */
static long my_time_zone=0;
@@ -54,7 +54,7 @@ void init_time(void)
This code handles also day light saving time.
The idea is to cache the time zone (including daylight saving time)
for the next call to make things faster.
-
+
*/
long my_gmt_sec(TIME *t)
@@ -128,7 +128,7 @@ long calc_daynr(uint year,uint month,uint day)
DBUG_ENTER("calc_daynr");
if (year == 0 && month == 0 && day == 0)
- DBUG_RETURN(0); /* Skipp errors */
+ DBUG_RETURN(0); /* Skip errors */
if (year < 200)
{
if ((year=year+1900) < 1900+YY_PART_YEAR)
@@ -176,7 +176,9 @@ uint calc_week(TIME *l_time, bool with_year, bool sunday_first_day_of_week,
ulong first_daynr=calc_daynr(l_time->year,1,1);
uint weekday=calc_weekday(first_daynr,sunday_first_day_of_week);
*year=l_time->year;
- if (l_time->month == 1 && weekday >= 4 && l_time->day <= 7-weekday)
+ if (l_time->month == 1 && l_time->day <= 7-weekday &&
+ ((!sunday_first_day_of_week && weekday >= 4) ||
+ (sunday_first_day_of_week && weekday != 0)))
{
/* Last week of the previous year */
if (!with_year)
@@ -186,7 +188,8 @@ uint calc_week(TIME *l_time, bool with_year, bool sunday_first_day_of_week,
first_daynr-= (days=calc_days_in_year(*year));
weekday= (weekday + 53*7- days) % 7;
}
- if (weekday >= 4)
+ if ((sunday_first_day_of_week && weekday != 0) ||
+ (!sunday_first_day_of_week && weekday >= 4))
days= daynr - (first_daynr+ (7-weekday));
else
days= daynr - (first_daynr - weekday);
@@ -431,7 +434,7 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date)
DBUG_ENTER("str_to_TIME");
DBUG_PRINT("enter",("str: %.*s",length,str));
- for (; str != end && !isdigit(*str) ; str++) ; // Skipp garbage
+ for (; str != end && !isdigit(*str) ; str++) ; // Skip garbage
if (str == end)
DBUG_RETURN(TIMESTAMP_NONE);
/*
@@ -591,7 +594,7 @@ bool str_to_time(const char *str,uint length,TIME *l_time)
date[0]=value;
state=1; // Assume next is hours
found_days=1;
- str++; // Skipp space;
+ str++; // Skip space;
}
else if ((end-str) > 1 && *str == ':' && isdigit(str[1]))
{
@@ -599,7 +602,7 @@ bool str_to_time(const char *str,uint length,TIME *l_time)
date[1]=value;
state=2;
found_hours=1;
- str++; // skipp ':'
+ str++; // skip ':'
}
else
{
@@ -620,7 +623,7 @@ bool str_to_time(const char *str,uint length,TIME *l_time)
date[state++]=value;
if (state == 4 || (end-str) < 2 || *str != ':' || !isdigit(str[1]))
break;
- str++; // Skipp ':'
+ str++; // Skip ':'
}
if (state != 4)
diff --git a/sql/udf_example.cc b/sql/udf_example.cc
index a91db5ee1cc..a5ec77f88e4 100644
--- a/sql/udf_example.cc
+++ b/sql/udf_example.cc
@@ -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 */
@@ -110,7 +110,7 @@
#include <stdio.h>
#include <string.h>
#else
-#include <global.h>
+#include <my_global.h>
#include <my_sys.h>
#endif
#include <mysql.h>
diff --git a/sql/uniques.cc b/sql/uniques.cc
new file mode 100644
index 00000000000..6b05618bcc7
--- /dev/null
+++ b/sql/uniques.cc
@@ -0,0 +1,166 @@
+/* Copyright (C) 2001 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 */
+
+/*
+ Function to handle quick removal of duplicates
+ This code is used when doing multi-table deletes to find the rows in
+ reference tables that needs to be deleted.
+
+ The basic idea is as follows:
+
+ Store first all strings in a binary tree, ignoring duplicates.
+ When the three uses more memory than 'max_heap_table_size',
+ write the tree (in sorted order) out to disk and start with a new tree.
+ When all data has been generated, merge the trees (removing any found
+ duplicates).
+
+ The unique entries will be returned in sort order, to ensure that we do the
+ deletes in disk order.
+*/
+
+#include "mysql_priv.h"
+#include "sql_sort.h"
+
+
+int unique_write_to_file(gptr key, element_count count, Unique *unique)
+{
+ return my_b_write(&unique->file, (byte*) key,
+ unique->tree.size_of_element) ? 1 : 0;
+}
+
+int unique_write_to_ptrs(gptr key, element_count count, Unique *unique)
+{
+ memcpy(unique->record_pointers, key, unique->tree.size_of_element);
+ unique->record_pointers+=unique->tree.size_of_element;
+ return 0;
+}
+
+Unique::Unique(qsort_cmp2 comp_func, void * comp_func_fixed_arg,
+ uint size, ulong max_in_memory_size_arg)
+ :max_in_memory_size(max_in_memory_size_arg),elements(0)
+{
+ my_b_clear(&file);
+ init_tree(&tree, max_in_memory_size / 16, 0, size, comp_func, 0, NULL, comp_func_fixed_arg);
+ /* If the following fail's the next add will also fail */
+ init_dynamic_array(&file_ptrs, sizeof(BUFFPEK), 16, 16);
+ 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));
+}
+
+
+Unique::~Unique()
+{
+ close_cached_file(&file);
+ delete_tree(&tree);
+ delete_dynamic(&file_ptrs);
+}
+
+
+ /* Write tree to disk; clear tree */
+bool Unique::flush()
+{
+ BUFFPEK file_ptr;
+ 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))
+ return 1;
+ delete_tree(&tree);
+ return 0;
+}
+
+
+/*
+ Modify the TABLE element so that when one calls init_records()
+ the rows will be read in priority order.
+*/
+
+bool Unique::get(TABLE *table)
+{
+ SORTPARAM sort_param;
+ table->found_records=elements+tree.elements_in_tree;
+
+ if (my_b_tell(&file) == 0)
+ {
+ /* Whole tree is in memory; Don't use disk if you don't need to */
+ if ((record_pointers=table->record_pointers= (byte*)
+ my_malloc(tree.size_of_element * tree.elements_in_tree, MYF(0))))
+ {
+ (void) tree_walk(&tree, (tree_walk_action) unique_write_to_ptrs,
+ this, left_root_right);
+ return 0;
+ }
+ }
+ /* Not enough memory; Save the result to file */
+ if (flush())
+ return 1;
+
+ IO_CACHE *outfile=table->io_cache;
+ BUFFPEK *file_ptr= (BUFFPEK*) file_ptrs.buffer;
+ uint maxbuffer= file_ptrs.elements - 1;
+ uchar *sort_buffer;
+ my_off_t save_pos;
+ bool error=1;
+
+ /* Open cached file if it isn't open */
+ outfile=table->io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
+ MYF(MY_ZEROFILL));
+
+ if (!outfile || ! my_b_inited(outfile) &&
+ open_cached_file(outfile,mysql_tmpdir,TEMP_PREFIX,READ_RECORD_BUFFER,
+ MYF(MY_WME)))
+ return 1;
+ reinit_io_cache(outfile,WRITE_CACHE,0L,0,0);
+
+ bzero((char*) &sort_param,sizeof(sort_param));
+ sort_param.max_rows= elements;
+ sort_param.sort_form=table;
+ sort_param.sort_length=sort_param.ref_length=tree.size_of_element;
+ sort_param.keys= max_in_memory_size / sort_param.sort_length;
+ sort_param.not_killable=1;
+
+ if (!(sort_buffer=(uchar*) my_malloc((sort_param.keys+1) *
+ sort_param.sort_length,
+ MYF(0))))
+ return 1;
+ sort_param.unique_buff= sort_buffer+(sort_param.keys*
+ sort_param.sort_length);
+
+ /* Merge the buffers to one file, removing duplicates */
+ if (merge_many_buff(&sort_param,sort_buffer,file_ptr,&maxbuffer,&file))
+ goto err;
+ if (flush_io_cache(&file) ||
+ reinit_io_cache(&file,READ_CACHE,0L,0,0))
+ goto err;
+ if (merge_buffers(&sort_param, &file, outfile, sort_buffer, file_ptr,
+ file_ptr, file_ptr+maxbuffer,0))
+ goto err;
+ error=0;
+err:
+ x_free((gptr) sort_buffer);
+ if (flush_io_cache(outfile))
+ error=1;
+
+ /* Setup io_cache for reading */
+ save_pos=outfile->pos_in_file;
+ if (reinit_io_cache(outfile,READ_CACHE,0L,0,0))
+ error=1;
+ outfile->end_of_file=save_pos;
+ return error;
+}
diff --git a/sql/unireg.cc b/sql/unireg.cc
index f7b040adebe..16ba8c7d58b 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -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 */
@@ -20,7 +20,7 @@
struct.
In the following functions FIELD * is an ordinary field-structure with
the following exeptions:
- sc_length,typepos,row,kol,dtype,regnr and field nead not to be set.
+ sc_length,typepos,row,kol,dtype,regnr and field need not to be set.
str is a (long) to record position where 0 is the first position.
*/
@@ -391,8 +391,8 @@ static bool pack_header(uchar *forminfo, enum db_type table_type,
int2store(forminfo+272,int_parts);
int2store(forminfo+274,int_length);
int2store(forminfo+276,time_stamp_pos);
- int2store(forminfo+278,80); /* Columns neaded */
- int2store(forminfo+280,22); /* Rows neaded */
+ int2store(forminfo+278,80); /* Columns needed */
+ int2store(forminfo+280,22); /* Rows needed */
int2store(forminfo+282,null_fields);
DBUG_RETURN(0);
} /* pack_header */
diff --git a/sql/unireg.h b/sql/unireg.h
index f8f5edd5156..c4d2052d1da 100644
--- a/sql/unireg.h
+++ b/sql/unireg.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 */
@@ -80,7 +80,7 @@
#define MYF_RW MYF(MY_WME+MY_NABP) /* Vid my_read & my_write */
#define SPECIAL_USE_LOCKS 1 /* Lock used databases */
-#define SPECIAL_NO_NEW_FUNC 2 /* Skipp new functions */
+#define SPECIAL_NO_NEW_FUNC 2 /* Skip new functions */
#define SPECIAL_NEW_FUNC 4 /* New nonstandard functions */
#define SPECIAL_WAIT_IF_LOCKED 8 /* Wait if locked database */
#define SPECIAL_SAME_DB_NAME 16 /* form name = file name */
diff --git a/strings/Makefile.am b/strings/Makefile.am
index 4c42f1ccb96..a29c5a3365d 100644
--- a/strings/Makefile.am
+++ b/strings/Makefile.am
@@ -22,7 +22,7 @@ pkglib_LIBRARIES = libmystrings.a
# Exact one of ASSEMBLER_X
if ASSEMBLER_x86
ASRCS = strings-x86.s longlong2str-x86.s
-CSRCS = bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c atof.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c 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 llstr.c ctype.c strnlen.c
+CSRCS = bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c atof.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c ctype.c strnlen.c
else
if ASSEMBLER_sparc
# These file MUST all be on the same line!! Otherwise automake
@@ -43,7 +43,7 @@ noinst_PROGRAMS = conf_to_src
# Default charset definitions
EXTRA_DIST = 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-tis620.c ctype-ujis.c ctype-latin1_de.c \
ctype_autoconf.c \
strto.c strings-x86.s longlong2str-x86.s \
strxmov.c bmove_upp.c strappend.c strcont.c strend.c \
diff --git a/strings/atof.c b/strings/atof.c
index 1ce16027089..0e0aa598718 100644
--- a/strings/atof.c
+++ b/strings/atof.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 quicker atof. About 2-10 times faster than standard atof on sparc.
@@ -23,7 +22,7 @@
Must be inited with init_my_atof to handle possibly overflows.
*/
-#include <global.h>
+#include <my_global.h>
#ifdef USE_MY_ATOF /* Skipp if we don't want it */
#include <m_ctype.h>
#include <floatingpoint.h>
diff --git a/strings/bchange.c b/strings/bchange.c
index 99066cf1e95..034dd3382e1 100644
--- a/strings/bchange.c
+++ b/strings/bchange.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 : bchange.c
Author : Michael widenius
@@ -25,10 +24,11 @@
src in a buffer with tot_length bytes.
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
-void bchange(register char *dst, uint old_length, register const char *src, uint new_length, uint tot_length)
+void bchange(register char *dst, uint old_length, register const char *src,
+ uint new_length, uint tot_length)
{
uint rest=tot_length-old_length;
if (old_length < new_length)
diff --git a/strings/bcmp.c b/strings/bcmp.c
index 3dce5025b64..64a6b72c443 100644
--- a/strings/bcmp.c
+++ b/strings/bcmp.c
@@ -1,30 +1,35 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
bcmp(s1, s2, len) returns 0 if the "len" bytes starting at "s1" are
identical to the "len" bytes starting at "s2", non-zero if they are
different.
- Now only used with purify.
+ Now only used with purify because purify gives wrong warnings when
+ comparing a shorter string with bcmp.
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
+#ifdef HAVE_purify
+#undef bcmp
+#undef HAVE_BCMP
+#endif
+
#if !defined(bcmp) && !defined(HAVE_BCMP)
#if defined(MC68000) && defined(DS90)
@@ -46,14 +51,11 @@ uint len; /* 0 <= len <= 65535 */
#else
-#ifdef HAVE_purify
-int my_bcmp(s1, s2, len)
+#ifndef HAVE_purify
+int bcmp(register const char *s1,register const char *s2, register uint len)
#else
-int bcmp(s1, s2, len)
+int my_bcmp(register const char *s1,register const char *s2, register uint len)
#endif
- register const char *s1;
- register const char *s2;
- register uint len;
{
while (len-- != 0 && *s1++ == *s2++) ;
return len+1;
diff --git a/strings/bcopy-duff.c b/strings/bcopy-duff.c
index 2f5a709c3a0..5ac6a716dab 100644
--- a/strings/bcopy-duff.c
+++ b/strings/bcopy-duff.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#define IFACTOR 4
diff --git a/strings/bfill.c b/strings/bfill.c
index ac5d3096b14..e0e22a7023e 100644
--- a/strings/bfill.c
+++ b/strings/bfill.c
@@ -1,3 +1,19 @@
+/* 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 */
+
/* File : bfill.c
Author : Richard A. O'Keefe.
Michael Widenius; ifdef MC68000
@@ -12,7 +28,7 @@
code is presented for your interest and amusement.
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
#if !defined(bfill) && !defined(HAVE_BFILL)
diff --git a/strings/bmove.c b/strings/bmove.c
index f63ff0bd4f8..3a76e783dda 100644
--- a/strings/bmove.c
+++ b/strings/bmove.c
@@ -1,3 +1,19 @@
+/* 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 */
+
/* File : bmove.c
Author : Richard A. O'Keefe.
Michael Widenius; ifdef MC68000
@@ -19,7 +35,7 @@
code is presented for your interest and amusement.
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
#if !defined(HAVE_BMOVE) && !defined(bmove)
diff --git a/strings/bmove512.c b/strings/bmove512.c
index 11dc282d05c..30ac4b744b6 100644
--- a/strings/bmove512.c
+++ b/strings/bmove512.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 : bmove512.c
Author : Michael Widenius;
@@ -27,7 +26,7 @@
fastest way to move a mutiple of 512 byte.
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
#ifndef bmove512
diff --git a/strings/bmove_upp.c b/strings/bmove_upp.c
index af6575ebf41..5319cd9611a 100644
--- a/strings/bmove_upp.c
+++ b/strings/bmove_upp.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 : bmove.c
Author : Michael widenius
@@ -24,7 +23,7 @@
"src-len" to the destination "dst-len" counting downwards.
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
#if defined(MC68000) && defined(DS90)
diff --git a/strings/bzero.c b/strings/bzero.c
index cc628e05277..a2b780cb396 100644
--- a/strings/bzero.c
+++ b/strings/bzero.c
@@ -1,3 +1,19 @@
+/* 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 */
+
/* File : bzero.c
Author : Richard A. O'Keefe.
Michael Widenius; ifdef MC68000
diff --git a/strings/conf_to_src.c b/strings/conf_to_src.c
index 89415d31820..22e04337b14 100644
--- a/strings/conf_to_src.c
+++ b/strings/conf_to_src.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* can't use -lmysys because this prog is used to create -lstrings */
diff --git a/strings/ctype-big5.c b/strings/ctype-big5.c
index cccf6730046..44f8a100897 100644
--- a/strings/ctype-big5.c
+++ b/strings/ctype-big5.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 basicly usa7 character sets with some extra functions
@@ -28,7 +27,7 @@
* .configure. mbmaxlen_big5=2
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
#include "m_ctype.h"
diff --git a/strings/ctype-czech.c b/strings/ctype-czech.c
index b47eaf3a63f..70f95e0d5d6 100644
--- a/strings/ctype-czech.c
+++ b/strings/ctype-czech.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 strings/ctype-czech.c for MySQL.
@@ -67,7 +66,7 @@
#ifdef REAL_MYSQL
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
#else
@@ -427,7 +426,7 @@ my_bool my_like_range_czech(const char *ptr,uint ptr_length,pchar escape,
*
* definition table reworked by Jaromir Dolecek <dolecek@ics.muni.cz>
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
uchar NEAR ctype_czech[257] = {
diff --git a/strings/ctype-euc_kr.c b/strings/ctype-euc_kr.c
index df6f8c496bc..d05ca518283 100644
--- a/strings/ctype-euc_kr.c
+++ b/strings/ctype-euc_kr.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 Korean EUC charset, and created by powerm90@tinc.co.kr.
@@ -27,7 +26,7 @@
* .configure. mbmaxlen_euc_kr=2
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
uchar NEAR ctype_euc_kr[257] =
diff --git a/strings/ctype-gb2312.c b/strings/ctype-gb2312.c
index a587d72905e..28717d98403 100644
--- a/strings/ctype-gb2312.c
+++ b/strings/ctype-gb2312.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 Chinese EUC character sets (GB2312), and created by Miles Tsai (net-bull@126.com).
*/
@@ -25,7 +24,7 @@
* .configure. mbmaxlen_gb2312=2
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
uchar NEAR ctype_gb2312[257] =
diff --git a/strings/ctype-gbk.c b/strings/ctype-gbk.c
index a5d55789bb8..9fccce175d8 100644
--- a/strings/ctype-gbk.c
+++ b/strings/ctype-gbk.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 Chinese character sets GBK, created by Wei He
(hewei@mail.ied.ac.cn)
@@ -28,7 +27,7 @@
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
#include "m_ctype.h"
@@ -2629,12 +2628,12 @@ int my_strnxfrm_gbk(uchar * dest, const uchar * src, int len, int srclen)
}
return srclen;
}
-
+
int my_strxfrm_gbk(uchar * dest, const uchar * src, int len)
{
return my_strnxfrm_gbk(dest,src,len,(uint) strlen((char*) src));
}
-
+
/*
** Calculate min_str and max_str that ranges a LIKE string.
** Arguments:
diff --git a/strings/ctype-latin1_de.c b/strings/ctype-latin1_de.c
new file mode 100644
index 00000000000..86b667b8f40
--- /dev/null
+++ b/strings/ctype-latin1_de.c
@@ -0,0 +1,361 @@
+/* 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 the latin1 character set with German sorting
+ *
+ * The modern sort order is used, where:
+ *
+ * 'ä' -> "ae"
+ * 'ö' -> "oe"
+ * 'ü' -> "ue"
+ * 'ß' -> "ss"
+ */
+
+/*
+ * 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_latin1_de=2
+ */
+
+#include <my_global.h>
+#include "m_string.h"
+#include "m_ctype.h"
+
+uchar ctype_latin1_de[] = {
+ 0,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 72, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 132,132,132,132,132,132,132,132,132,132, 16, 16, 16, 16, 16, 16,
+ 16,129,129,129,129,129,129, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 16, 16, 16, 16,
+ 16,130,130,130,130,130,130, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 16, 16, 16, 32,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 72, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 16, 1, 1, 1, 1, 1, 1, 1, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 16, 2, 2, 2, 2, 2, 2, 2, 2
+};
+
+uchar to_lower_latin1_de[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,
+ 112,113,114,115,116,117,118,119,120,121,122, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,
+ 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
+ 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
+ 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
+ 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
+ 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
+ 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
+ 240,241,242,243,244,245,246,215,248,249,250,251,252,253,254,223,
+ 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
+ 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
+};
+
+uchar to_upper_latin1_de[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,123,124,125,126,127,
+ 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
+ 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
+ 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
+ 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
+ 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
+ 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
+ 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
+ 208,209,210,211,212,213,214,247,216,217,218,219,220,221,222,255
+};
+
+/*
+ * This is a simple latin1 mapping table, which maps all accented
+ * characters to their non-accented equivalents. Note: in this
+ * table, 'ä' is mapped to 'A', 'ÿ' is mapped to 'Y', etc. - all
+ * accented characters except the following are treated the same way.
+ * Ü, ü, Ö, ö, Ä, ä
+ */
+
+uchar sort_order_latin1_de[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,123,124,125,126,127,
+ 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
+ 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
+ 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
+ 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
+ 65, 65, 65, 65,196, 65, 92, 67, 69, 69, 69, 69, 73, 73, 73, 73,
+ 68, 78, 79, 79, 79, 79,214,215,216, 85, 85, 85,220, 89,222,223,
+ 65, 65, 65, 65,196, 65, 92, 67, 69, 69, 69, 69, 73, 73, 73, 73,
+ 68, 78, 79, 79, 79, 79,214,247,216, 85, 85, 85,220, 89,222, 89
+};
+
+#define L1_AE 196
+#define L1_ae 228
+#define L1_OE 214
+#define L1_oe 246
+#define L1_UE 220
+#define L1_ue 252
+#define L1_ss 223
+
+
+/*
+ Some notes about the following comparison rules:
+ By definition, my_strnncoll_latin_de must works exactly as if had called
+ my_strnxfrm_latin_de() on both strings and compared the result strings.
+
+ This means that:
+ Ä must also matches ÁE and Aè, because my_strxn_frm_latin_de() will convert
+ both to AE.
+
+ The other option would be to not do any accent removal in
+ sort_order_latin_de[] at all
+*/
+
+
+#define CHECK_S1_COMBO(ch1, ch2, str1, str1_end, res_if_str1_smaller, str2, fst, snd, accent) \
+ /* Invariant: ch1 == fst == sort_order_latin1_de[accent] && ch1 != ch2 */ \
+ if (ch2 != accent) \
+ { \
+ ch1= fst; \
+ goto normal; \
+ } \
+ if (str1 == str1_end) \
+ return res_if_str1_smaller; \
+ { \
+ int diff = (int) sort_order_latin1_de[*str1] - snd; \
+ if (diff) \
+ return diff*(-(res_if_str1_smaller)); \
+ /* They are equal (e.g., "Ae" == 'ä') */ \
+ str1++; \
+ }
+
+
+int my_strnncoll_latin1_de(const uchar * s1, int len1,
+ const uchar * s2, int len2)
+{
+ const uchar *e1 = s1 + len1;
+ const uchar *e2 = s2 + len2;
+
+ while (s1 < e1 && s2 < e2)
+ {
+ /*
+ Because sort_order_latin1_de doesn't convert 'Ä', Ü or ß we
+ can use it here.
+ */
+ uchar c1 = sort_order_latin1_de[*s1++];
+ uchar c2 = sort_order_latin1_de[*s2++];
+ if (c1 != c2)
+ {
+ switch (c1) {
+ case 'A':
+ CHECK_S1_COMBO(c1, c2, s1, e1, -1, s2, 'A', 'E', L1_AE);
+ break;
+ case 'O':
+ CHECK_S1_COMBO(c1, c2, s1, e1, -1, s2, 'O', 'E', L1_OE);
+ break;
+ case 'U':
+ CHECK_S1_COMBO(c1, c2, s1, e1, -1, s2, 'U', 'E', L1_UE);
+ break;
+ case 'S':
+ CHECK_S1_COMBO(c1, c2, s1, e1, -1, s2, 'S', 'S', L1_ss);
+ break;
+ case L1_AE:
+ CHECK_S1_COMBO(c1, c2, s2, e2, 1, s1, 'A', 'E', 'A');
+ break;
+ case L1_OE:
+ CHECK_S1_COMBO(c1, c2, s2, e2, 1, s1, 'O', 'E', 'O');
+ break;
+ case L1_UE:
+ CHECK_S1_COMBO(c1, c2, s2, e2, 1, s1, 'U', 'E', 'U');
+ break;
+ case L1_ss:
+ CHECK_S1_COMBO(c1, c2, s2, e2, 1, s1, 'S', 'S', 'S');
+ break;
+ default:
+ /*
+ Handle the case where 'c2' is a special character
+ If this is true, we know that c1 can't match this character.
+ */
+ normal:
+ switch (c2) {
+ case L1_AE:
+ return (int) c1 - (int) 'A';
+ case L1_OE:
+ return (int) c1 - (int) 'O';
+ case L1_UE:
+ return (int) c1 - (int) 'U';
+ case L1_ss:
+ return (int) c1 - (int) 'S';
+ default:
+ {
+ int diff= (int) c1 - (int) c2;
+ if (diff)
+ return diff;
+ }
+ break;
+ }
+ }
+ }
+ }
+ /* A simple test of string lengths won't work -- we test to see
+ * which string ran out first */
+ return s1 < e1 ? 1 : s2 < e2 ? -1 : 0;
+}
+
+
+int my_strnxfrm_latin1_de(uchar * dest, const uchar * src, int len, int srclen)
+{
+ const uchar *dest_orig = dest;
+ const uchar *de = dest + len;
+ const uchar *se = src + srclen;
+ while (src < se && dest < de)
+ {
+ uchar chr=sort_order_latin1_de[*src];
+ switch (chr) {
+ case L1_AE:
+ *dest++ = 'A';
+ if (dest < de)
+ *dest++ = 'E';
+ break;
+ case L1_OE:
+ *dest++ = 'O';
+ if (dest < de)
+ *dest++ = 'E';
+ break;
+ case L1_UE:
+ *dest++ = 'U';
+ if (dest < de)
+ *dest++ = 'E';
+ break;
+ case L1_ss:
+ *dest++ = 'S';
+ if (dest < de)
+ *dest++ = 'S';
+ break;
+ default:
+ *dest++= chr;
+ break;
+ }
+ ++src;
+ }
+ return dest - dest_orig;
+}
+
+
+int my_strcoll_latin1_de(const uchar * s1, const uchar * s2)
+{
+ /* XXX QQ: This should be fixed to not call strlen */
+ return my_strnncoll_latin1_de(s1, strlen((char*) s1),
+ s2, strlen((char*) s2));
+}
+
+int my_strxfrm_latin1_de(uchar * dest, const uchar * src, int len)
+{
+ /* XXX QQ: This should be fixed to not call strlen */
+ return my_strnxfrm_latin1_de(dest, src, len, strlen((char*) src));
+}
+
+/*
+ * Calculate min_str and max_str that ranges a LIKE string.
+ * Arguments:
+ * ptr IN: Pointer to LIKE string.
+ * ptr_length IN: Length of LIKE string.
+ * escape IN: Escape character in LIKE. (Normally '\').
+ * No escape characters should appear in min_str or max_str
+ * res_length IN: Length of min_str and max_str.
+ * min_str IN/OUT: Smallest case sensitive string that ranges LIKE.
+ * Should be space padded to res_length.
+ * max_str IN/OUT: Largest case sensitive string that ranges LIKE.
+ * Normally padded with the biggest character sort value.
+ * min_length OUT: Length of min_str without space padding.
+ * max_length OUT: Length of max_str without space padding.
+ *
+ * The function should return 0 if ok and 1 if the LIKE string can't be
+ * optimized !
+ */
+
+#define min_sort_char ((char) 0)
+#define max_sort_char ((char) 255)
+#define wild_one '_'
+#define wild_many '%'
+
+my_bool my_like_range_latin1_de(const char *ptr, uint ptr_length,
+ pchar escape, 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;
+
+ for (; ptr != end && min_str != min_end; ptr++)
+ {
+ if (*ptr == escape && ptr + 1 != end)
+ {
+ ptr++; /* Skip escape */
+ *min_str++ = *max_str++ = *ptr;
+ continue;
+ }
+ if (*ptr == wild_one) /* '_' in SQL */
+ {
+ *min_str++ = min_sort_char;
+ *max_str++ = max_sort_char;
+ continue;
+ }
+ if (*ptr == wild_many) /* '%' in SQL */
+ {
+ *min_length = (uint)(min_str - min_org);
+ *max_length = res_length;
+ do {
+ *min_str++ = ' '; // Because if key compression
+ *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);
+
+ /* Temporary fix for handling wild_one at end of string (key compression) */
+ {
+ char *tmp;
+ for (tmp= min_str ; tmp > min_org && tmp[-1] == '\0';)
+ *--tmp=' ';
+ }
+
+ while (min_str != min_end)
+ *min_str++ = *max_str++ = ' '; // Because if key compression
+ return 0;
+}
diff --git a/strings/ctype-sjis.c b/strings/ctype-sjis.c
index 9f23d69eb12..5d5f64cc5fe 100644
--- a/strings/ctype-sjis.c
+++ b/strings/ctype-sjis.c
@@ -1,24 +1,23 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 Shift JIS charset, and created by tommy@valley.ne.jp.
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
#include "m_ctype.h"
diff --git a/strings/ctype-tis620.c b/strings/ctype-tis620.c
index 1c0acc38e24..370c4c773c6 100644
--- a/strings/ctype-tis620.c
+++ b/strings/ctype-tis620.c
@@ -1,3 +1,19 @@
+/* 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 */
+
/*
Copyright (C) 2001 by Korakot Chaovavanich <korakot@iname.com> and
Apisilp Trunganont <apisilp@pantip.inet.co.th>
@@ -27,7 +43,7 @@
* .configure. strxfrm_multiply_tis620=4
*/
-#include <global.h>
+#include <my_global.h>
#include <my_sys.h>
#include "m_string.h"
#include "m_ctype.h"
diff --git a/strings/ctype-ujis.c b/strings/ctype-ujis.c
index d994a2e5e96..2091a610d19 100644
--- a/strings/ctype-ujis.c
+++ b/strings/ctype-ujis.c
@@ -1,3 +1,19 @@
+/* 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 Japanese EUC charset, and created by tommy@valley.ne.jp.
*/
@@ -8,7 +24,7 @@
* .configure. mbmaxlen_ujis=3
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
uchar NEAR ctype_ujis[257] =
diff --git a/strings/ctype.c b/strings/ctype.c
index e66c9771d78..8e3571b1b88 100644
--- a/strings/ctype.c
+++ b/strings/ctype.c
@@ -1,23 +1,24 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <global.h>
+#include <my_global.h>
#include <m_ctype.h>
+#ifndef SCO
#include <m_string.h>
+#endif
/* generated by make, using conf_to_src */
#include "ctype_extra_sources.c"
diff --git a/strings/do_ctype.c b/strings/do_ctype.c
index e05926bf8d3..14ede6891da 100644
--- a/strings/do_ctype.c
+++ b/strings/do_ctype.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Prints case-convert and sort-convert tabell on stdout. This is used to
make _ctype.c easyer */
@@ -22,7 +21,7 @@
#undef DBUG_OFF
#endif
-#include <global.h>
+#include <my_global.h>
#include <ctype.h>
#include <my_sys.h>
#include "m_string.h"
diff --git a/strings/int2str.c b/strings/int2str.c
index 4003e8a6167..38e8a5182a3 100644
--- a/strings/int2str.c
+++ b/strings/int2str.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
Defines: int2str(), itoa(), ltoa()
@@ -39,7 +38,7 @@
itoa assumes that 10 -base numbers are allways signed and other arn't.
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
char NEAR _dig_vec[] =
diff --git a/strings/is_prefix.c b/strings/is_prefix.c
index d3f2b148de2..37d8002703b 100644
--- a/strings/is_prefix.c
+++ b/strings/is_prefix.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 : is_prefix.c
Author : Michael Widenius
@@ -23,7 +22,7 @@
A empty t is allways a prefix.
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
int is_prefix(register const char *s, register const char *t)
diff --git a/strings/llstr.c b/strings/llstr.c
index 470645a4f65..966b347ac7e 100644
--- a/strings/llstr.c
+++ b/strings/llstr.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
Defines: llstr();
@@ -26,7 +25,7 @@
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
char *llstr(longlong value,char *buff)
diff --git a/strings/longlong2str-x86.s b/strings/longlong2str-x86.s
index bafc485f759..98e60acbafb 100644
--- a/strings/longlong2str-x86.s
+++ b/strings/longlong2str-x86.s
@@ -1,18 +1,17 @@
-/* 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 */
+# 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
# Optimized longlong2str function for Intel 80x86 (gcc/gas syntax)
# Some set sequences are optimized for pentuimpro II
diff --git a/strings/longlong2str.c b/strings/longlong2str.c
index 5c4eaf98c85..a991c57b4d9 100644
--- a/strings/longlong2str.c
+++ b/strings/longlong2str.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
Defines: longlong2str();
@@ -39,7 +38,7 @@
itoa assumes that 10 -base numbers are allways signed and other arn't.
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
#if defined(HAVE_LONG_LONG) && !defined(longlong2str) && !defined(HAVE_LONGLONG2STR)
diff --git a/strings/memcmp.c b/strings/memcmp.c
index 1bb8deaeac0..2f1e4e2ea1f 100644
--- a/strings/memcmp.c
+++ b/strings/memcmp.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* memcmp(lhs, rhs, len)
compares the two memory areas lhs[0..len-1] ?? rhs[0..len-1]. It
diff --git a/strings/memcpy.c b/strings/memcpy.c
index 4fc84fb6052..de79e43ae72 100644
--- a/strings/memcpy.c
+++ b/strings/memcpy.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
memcpy(dst, src, len)
diff --git a/strings/memset.c b/strings/memset.c
index 57c8fea5ebe..53383beb170 100644
--- a/strings/memset.c
+++ b/strings/memset.c
@@ -1,3 +1,19 @@
+/* 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 */
+
/* File : memset.c
Author : Richard A. O'Keefe.
Updated: 25 May 1984
@@ -27,7 +43,7 @@ char *memset(char *dst,int chr, int len)
char *memset(char *dst, register pchar chr, register int len)
{
register char *d;
-
+
for (d = dst; --len >= 0; *d++ = chr) ;
return dst;
}
diff --git a/strings/r_strinstr.c b/strings/r_strinstr.c
index 882a4eda412..76d310a3fda 100644
--- a/strings/r_strinstr.c
+++ b/strings/r_strinstr.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
Author : David
@@ -24,7 +23,7 @@
the pattern counted from the begining of the string.
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
uint r_strinstr(reg1 my_string str,int from, reg4 my_string search)
diff --git a/strings/str2int.c b/strings/str2int.c
index 55fcd56adb9..58669287473 100644
--- a/strings/str2int.c
+++ b/strings/str2int.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
str2int(src, radix, lower, upper, &val)
@@ -39,7 +38,7 @@
call has no problems.
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
#include "m_ctype.h"
#include "my_sys.h" /* defines errno */
@@ -50,7 +49,8 @@
X >= 'a' && X <= 'z' ? X-'a'+10 :\
'\177')
-char *str2int(register const char *src, register int radix, long int lower, long int upper, long int *val)
+char *str2int(register const char *src, register int radix, long int lower,
+ long int upper, long int *val)
{
int sign; /* is number negative (+1) or positive (-1) */
int n; /* number of digits yet to be converted */
diff --git a/strings/str_test.c b/strings/str_test.c
index bd54bc6d806..bef48814f6d 100644
--- a/strings/str_test.c
+++ b/strings/str_test.c
@@ -1,23 +1,22 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 of all stringfunktions that is coded in assembler */
-#include <global.h>
+#include <my_global.h>
#include <stdarg.h>
#include "m_string.h"
diff --git a/strings/strappend.c b/strings/strappend.c
index d5defaeb0bf..9912bd5197d 100644
--- a/strings/strappend.c
+++ b/strings/strappend.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 : strappend.c
Author : Monty
@@ -25,7 +24,7 @@
trunked. The des+len character is allways set to NULL.
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
@@ -39,5 +38,3 @@ void strappend(register char *s, uint len, pchar fill)
while (s<endpos) *(s++) = fill;
*(endpos) = '\0';
} /* strappend */
-
-
diff --git a/strings/strcat.c b/strings/strcat.c
index 699729cd7b5..3c571514701 100644
--- a/strings/strcat.c
+++ b/strings/strcat.c
@@ -1,3 +1,19 @@
+/* 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 */
+
/* File : strcat.c
Author : Richard A. O'Keefe.
Updated: 10 April 1984
diff --git a/strings/strcend.c b/strings/strcend.c
index 246b81d7f7b..a3f00a1057b 100644
--- a/strings/strcend.c
+++ b/strings/strcend.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 : strcend.c
Author : Michael Widenius: ifdef MC68000
@@ -24,7 +23,7 @@
occurs, or a pointer to the end-null of s if c does not occur in s.
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
#if defined(MC68000) && defined(DS90)
diff --git a/strings/strchr.c b/strings/strchr.c
index ef117d85635..3f1a569c296 100644
--- a/strings/strchr.c
+++ b/strings/strchr.c
@@ -1,3 +1,19 @@
+/* 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 */
+
/* File : strchr.c
Author : Richard A. O'Keefe.
Michael Widenius: ifdef MC68000
diff --git a/strings/strcmp.c b/strings/strcmp.c
index d911b2daa17..d673c035dbc 100644
--- a/strings/strcmp.c
+++ b/strings/strcmp.c
@@ -1,3 +1,19 @@
+/* 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 */
+
/* File : strcmp.c
Author : Richard A. O'Keefe.
Updated: 10 April 1984
diff --git a/strings/strcont.c b/strings/strcont.c
index 5c7d5d2e55f..1d89be89517 100644
--- a/strings/strcont.c
+++ b/strings/strcont.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 : strcont.c
Author : Monty
@@ -26,7 +25,7 @@
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
my_string strcont(reg1 const char *str,reg2 const char *set)
diff --git a/strings/strend.c b/strings/strend.c
index 18b9d1fbd0d..d21abc79e2b 100644
--- a/strings/strend.c
+++ b/strings/strend.c
@@ -1,3 +1,19 @@
+/* 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 */
+
/* File : strend.c
Author : Richard A. O'Keefe.
Updated: 23 April 1984
@@ -10,7 +26,7 @@
Beware: the asm version works only if strlen(s) < 65535.
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
#if VaxAsm
diff --git a/strings/strfill.c b/strings/strfill.c
index ef0ccb567d1..0ef56a67706 100644
--- a/strings/strfill.c
+++ b/strings/strfill.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 : strfill.c
Author : Monty
@@ -25,7 +24,7 @@
strfill() returns pointer to dest+len;
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
my_string strfill(my_string s,uint len,pchar fill)
diff --git a/strings/strings-not-used.h b/strings/strings-not-used.h
index fa4dff318f5..e0dc1eac3a5 100644
--- a/strings/strings-not-used.h
+++ b/strings/strings-not-used.h
@@ -1,3 +1,19 @@
+/* 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 */
+
/* File : strings.h
Author : Richard A. O'Keefe.
Updated: 1 June 1984
@@ -13,7 +29,7 @@
#ifndef NullS
-#include <global.h> /* Define standar vars */
+#include <my_global.h> /* Define standar vars */
#include "m_string.h"
#define NUL '\0'
diff --git a/strings/strings-x86.s b/strings/strings-x86.s
index 5d7cbde1b38..8b29a2db7f1 100644
--- a/strings/strings-x86.s
+++ b/strings/strings-x86.s
@@ -1,38 +1,37 @@
-/* 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 */
-
-/* Optimized string functions Intel 80x86 (gcc/gas syntax) */
-
- .file "strings.s"
+# 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
+
+# Optimized string functions Intel 80x86 (gcc/gas syntax)
+
+ .file "strings.s"
.version "1.00"
.text
- /* Move a alligned, not overlapped, by (long) divided memory area */
- /* Args: to,from,length */
+# Move a alligned, not overlapped, by (long) divided memory area
+# Args: to,from,length
.globl bmove_allign
.type bmove_allign,@function
bmove_allign:
movl %edi,%edx
movl %esi,%eax
- movl 4(%esp),%edi /* to */
- movl 8(%esp),%esi /* from */
- movl 12(%esp),%ecx /* length */
- addw $3,%cx /* fix if not divisible with long */
+ movl 4(%esp),%edi # to
+ movl 8(%esp),%esi # from
+ movl 12(%esp),%ecx # length
+ addw $3,%cx # fix if not divisible with long
shrw $2,%cx
rep
movsl
@@ -42,198 +41,198 @@ bmove_allign:
.end:
.size bmove_allign,.end-bmove_allign
- /* Move a string from higher to lower */
- /* Arg from+1,to+1,length */
+ # Move a string from higher to lower
+ # Arg from+1,to+1,length
.globl bmove_upp
.type bmove_upp,@function
bmove_upp:
- std /* Work downward */
+ std # Work downward
movl %edi,%edx
movl %esi,%eax
- movl 4(%esp),%edi /* p1 */
- movl 8(%esp),%esi /* p2 */
- movl 12(%esp),%ecx /* length */
- decl %edi /* Don't move last arg */
+ movl 4(%esp),%edi # p1
+ movl 8(%esp),%esi # p2
+ movl 12(%esp),%ecx # length
+ decl %edi # Don't move last arg
decl %esi
rep
- movsb /* One byte a time because overlap */
- cld /* C library wants cld */
+ movsb # One byte a time because overlap
+ cld # C library wants cld
movl %eax,%esi
movl %edx,%edi
ret
.bmove_upp_end:
.size bmove_upp,.bmove_upp_end-bmove_upp
- /* Append fillchars to string */
- /* Args: dest,len,fill */
+ # Append fillchars to string
+ # Args: dest,len,fill
.globl strappend
.type strappend,@function
strappend:
pushl %edi
- movl 8(%esp),%edi /* Memory pointer */
- movl 12(%esp),%ecx /* Length */
- clrl %eax /* Find end of string */
+ movl 8(%esp),%edi # Memory pointer
+ movl 12(%esp),%ecx # Length
+ clrl %eax # Find end of string
repne
scasb
- jnz sa_99 /* String to long, shorten it */
- movzb 16(%esp),%eax /* Fillchar */
- decl %edi /* Point at end null */
- incl %ecx /* rep made one dec for null-char */
-
- movb %al,%ah /* (2) Set up a 32 bit pattern. */
- movw %ax,%dx /* (2) */
- shll $16,%eax /* (3) */
- movw %dx,%ax /* (2) %eax has the 32 bit pattern. */
-
- movl %ecx,%edx /* (2) Save the count of bytes. */
- shrl $2,%ecx /* (2) Number of dwords. */
+ jnz sa_99 # String to long, shorten it
+ movzb 16(%esp),%eax # Fillchar
+ decl %edi # Point at end null
+ incl %ecx # rep made one dec for null-char
+
+ movb %al,%ah # (2) Set up a 32 bit pattern.
+ movw %ax,%dx # (2)
+ shll $16,%eax # (3)
+ movw %dx,%ax # (2) %eax has the 32 bit pattern.
+
+ movl %ecx,%edx # (2) Save the count of bytes.
+ shrl $2,%ecx # (2) Number of dwords.
rep
- stosl /* (5 + 5n) */
- movb $3,%cl /* (2) */
- and %edx,%ecx /* (2) Fill in the odd bytes*/
+ stosl # (5 + 5n)
+ movb $3,%cl # (2)
+ and %edx,%ecx # (2) Fill in the odd bytes
rep
- stosb /* Move last bytes if any */
+ stosb # Move last bytes if any
-sa_99: movb $0,(%edi) /* End of string */
+sa_99: movb $0,(%edi) # End of string
popl %edi
ret
.strappend_end:
.size strappend,.strappend_end-strappend
- /* Find if string contains any char in another string */
- /* Arg: str,set */
- /* Ret: Pointer to first found char in str */
+ # Find if string contains any char in another string
+ # Arg: str,set
+ # Ret: Pointer to first found char in str
.globl strcont
.type strcont,@function
strcont:
movl %edi,%edx
pushl %esi
- movl 8(%esp),%esi /* str */
- movl 12(%esp),%ecx /* set */
- clrb %ah /* For endtest */
+ movl 8(%esp),%esi # str
+ movl 12(%esp),%ecx # set
+ clrb %ah # For endtest
jmp sc_60
sc_10: scasb
- jz sc_fo /* Found char */
-sc_20: cmp (%edi),%ah /* Test if null */
- jnz sc_10 /* Not end of set yet */
- incl %esi /* Next char in str */
-sc_60: movl %ecx,%edi /* %edi = Set */
- movb (%esi),%al /* Test if this char exist */
+ jz sc_fo # Found char
+sc_20: cmp (%edi),%ah # Test if null
+ jnz sc_10 # Not end of set yet
+ incl %esi # Next char in str
+sc_60: movl %ecx,%edi # %edi = Set
+ movb (%esi),%al # Test if this char exist
andb %al,%al
- jnz sc_20 /* Not end of string */
- clrl %esi /* Return Null */
-sc_fo: movl %esi,%eax /* Char found here */
- movl %edx,%edi /* Restore */
+ jnz sc_20 # Not end of string
+ clrl %esi # Return Null
+sc_fo: movl %esi,%eax # Char found here
+ movl %edx,%edi # Restore
popl %esi
ret
.strcont_end:
.size strcont,.strcont_end-strcont
- /* Find end of string */
- /* Arg: str */
- /* ret: Pointer to end null */
+ # Find end of string
+ # Arg: str
+ # ret: Pointer to end null
.globl strend
.type strend,@function
strend:
- movl %edi,%edx /* Save */
- movl 4(%esp),%edi /* str */
- clrl %eax /* Find end of string */
+ movl %edi,%edx # Save
+ movl 4(%esp),%edi # str
+ clrl %eax # Find end of string
movl %eax,%ecx
- decl %ecx /* ECX = -1 */
+ decl %ecx # ECX = -1
repne
scasb
movl %edi,%eax
- decl %eax /* End of string */
- movl %edx,%edi /* Restore */
+ decl %eax # End of string
+ movl %edx,%edi # Restore
ret
.strend_end:
.size strend,.strend_end-strend
- /* Make a string with len fill-chars and endnull */
- /* Args: dest,len,fill */
- /* Ret: dest+len */
+ # Make a string with len fill-chars and endnull
+ # Args: dest,len,fill
+ # Ret: dest+len
.globl strfill
.type strfill,@function
strfill:
pushl %edi
- movl 8(%esp),%edi /* Memory pointer */
- movl 12(%esp),%ecx /* Length */
- movzb 16(%esp),%eax /* Fill */
+ movl 8(%esp),%edi # Memory pointer
+ movl 12(%esp),%ecx # Length
+ movzb 16(%esp),%eax # Fill
- movb %al,%ah /* (2) Set up a 32 bit pattern */
- movw %ax,%dx /* (2) */
- shll $16,%eax /* (3) */
- movw %dx,%ax /* (2) %eax has the 32 bit pattern. */
+ movb %al,%ah # (2) Set up a 32 bit pattern
+ movw %ax,%dx # (2)
+ shll $16,%eax # (3)
+ movw %dx,%ax # (2) %eax has the 32 bit pattern.
- movl %ecx,%edx /* (2) Save the count of bytes. */
- shrl $2,%ecx /* (2) Number of dwords. */
+ movl %ecx,%edx # (2) Save the count of bytes.
+ shrl $2,%ecx # (2) Number of dwords.
rep
- stosl /* (5 + 5n) */
- movb $3,%cl /* (2) */
- and %edx,%ecx /* (2) Fill in the odd bytes */
+ stosl # (5 + 5n)
+ movb $3,%cl # (2)
+ and %edx,%ecx # (2) Fill in the odd bytes
rep
- stosb /* Move last bytes if any */
+ stosb # Move last bytes if any
- movb %cl,(%edi) /* End NULL */
- movl %edi,%eax /* End i %eax */
+ movb %cl,(%edi) # End NULL
+ movl %edi,%eax # End i %eax
popl %edi
ret
.strfill_end:
.size strfill,.strfill_end-strfill
- /* Find a char in or end of a string */
- /* Arg: str,char */
- /* Ret: pointer to found char or NullS */
+ # Find a char in or end of a string
+ # Arg: str,char
+ # Ret: pointer to found char or NullS
.globl strcend
.type strcend,@function
strcend:
movl %edi,%edx
- movl 4(%esp),%edi /* str */
- movb 8(%esp),%ah /* search */
- clrb %al /* for scasb to find end */
+ movl 4(%esp),%edi # str
+ movb 8(%esp),%ah # search
+ clrb %al # for scasb to find end
se_10: cmpb (%edi),%ah
- jz se_20 /* Found char */
+ jz se_20 # Found char
scasb
- jnz se_10 /* Not end */
- dec %edi /* Not found, point at end of string */
+ jnz se_10 # Not end
+ dec %edi # Not found, point at end of string
se_20: movl %edi,%eax
- movl %edx,%edi /* Restore */
+ movl %edx,%edi # Restore
ret
.strcend_end:
.size strcend,.strcend_end-strcend
- /* Test if string has a given suffix */
+ # Test if string has a given suffix
.globl is_prefix
.type is_prefix,@function
is_prefix:
- movl %edi,%edx /* Save %edi */
- pushl %esi /* and %esi */
- movl 12(%esp),%esi /* get suffix */
- movl 8(%esp),%edi /* s1 */
- movl $1,%eax /* Ok and zero-test */
+ movl %edi,%edx # Save %edi
+ pushl %esi # and %esi
+ movl 12(%esp),%esi # get suffix
+ movl 8(%esp),%edi # s1
+ movl $1,%eax # Ok and zero-test
ip_10: cmpb (%esi),%ah
- jz suf_ok /* End of string/ found suffix */
- cmpsb /* Compare strings */
- jz ip_10 /* Same, possible prefix */
- xor %eax,%eax /* Not suffix */
+ jz suf_ok # End of string/ found suffix
+ cmpsb # Compare strings
+ jz ip_10 # Same, possible prefix
+ xor %eax,%eax # Not suffix
suf_ok: popl %esi
movl %edx,%edi
ret
.is_prefix_end:
.size is_prefix,.is_prefix_end-is_prefix
- /* Find a substring in string */
- /* Arg: str,search */
+ # Find a substring in string
+ # Arg: str,search
.globl strstr
.type strstr,@function
@@ -241,31 +240,31 @@ suf_ok: popl %esi
strstr:
pushl %edi
pushl %esi
- movl 12(%esp),%esi /* str */
- movl 16(%esp),%edi /* search */
+ movl 12(%esp),%esi # str
+ movl 16(%esp),%edi # search
movl %edi,%ecx
- incl %ecx /* %ecx = search+1 */
- movb (%edi),%ah /* %ah = First char in search */
+ incl %ecx # %ecx = search+1
+ movb (%edi),%ah # %ah = First char in search
jmp sf_10
-sf_00: movl %edx,%esi /* si = Current str-pos */
-sf_10: movb (%esi),%al /* Test if this char exist */
+sf_00: movl %edx,%esi # si = Current str-pos
+sf_10: movb (%esi),%al # Test if this char exist
andb %al,%al
- jz sf_90 /* End of string, didn't find search */
+ jz sf_90 # End of string, didn't find search
incl %esi
cmpb %al,%ah
- jnz sf_10 /* Didn't find first char, continue */
- movl %esi,%edx /* Save str-pos in %edx */
+ jnz sf_10 # Didn't find first char, continue
+ movl %esi,%edx # Save str-pos in %edx
movl %ecx,%edi
sf_20: cmpb $0,(%edi)
- jz sf_fo /* Found substring */
+ jz sf_fo # Found substring
cmpsb
- jz sf_20 /* Char ok */
- jmp sf_00 /* Next str-pos */
+ jz sf_20 # Char ok
+ jmp sf_00 # Next str-pos
-sf_90: movl $1,%edx /* Return Null */
-sf_fo: movl %edx,%eax /* Char found here */
- decl %eax /* Pointed one after */
+sf_90: movl $1,%edx # Return Null
+sf_fo: movl %edx,%eax # Char found here
+ decl %eax # Pointed one after
popl %esi
popl %edi
ret
@@ -273,8 +272,8 @@ sf_fo: movl %edx,%eax /* Char found here */
.size strstr,.strstr_end-strstr
- /* Find a substring in string, return index */
- /* Arg: str,search */
+ # Find a substring in string, return index
+ # Arg: str,search
.globl strinstr
.type strinstr,@function
@@ -282,22 +281,22 @@ sf_fo: movl %edx,%eax /* Char found here */
strinstr:
pushl %ebp
movl %esp,%ebp
- pushl 12(%ebp) /* search */
- pushl 8(%ebp) /* str */
+ pushl 12(%ebp) # search
+ pushl 8(%ebp) # str
call strstr
add $8,%esp
or %eax,%eax
- jz si_99 /* Not found, return NULL */
- sub 8(%ebp),%eax /* Pos from start */
- inc %eax /* And first pos = 1 */
+ jz si_99 # Not found, return NULL
+ sub 8(%ebp),%eax # Pos from start
+ inc %eax # And first pos = 1
si_99: popl %ebp
ret
.strinstr_end:
.size strinstr,.strinstr_end-strinstr
- /* Make a string of len length from another string */
- /* Arg: dst,src,length */
- /* ret: end of dst */
+ # Make a string of len length from another string
+ # Arg: dst,src,length
+ # ret: end of dst
.globl strmake
.type strmake,@function
@@ -305,48 +304,48 @@ si_99: popl %ebp
strmake:
pushl %edi
pushl %esi
- movl 12(%esp),%edi /* dst */
- movl 16(%esp),%esi /* src */
- movl 20(%esp),%ecx /* Length of memory-area */
- clrb %al /* For test of end-null */
- jecxz sm_90 /* Nothing to move, put zero at end. */
-
-sm_10: cmpb (%esi),%al /* Next char to move */
- movsb /* move arg */
- jz sm_99 /* last char, we are ready */
- loop sm_10 /* Continue moving */
-sm_90: movb %al,(%edi) /* Set end pos */
- incl %edi /* Fix that di points at end null */
-sm_99: decl %edi /* di points now at end null */
- movl %edi,%eax /* Ret value.p $ */
+ movl 12(%esp),%edi # dst
+ movl 16(%esp),%esi # src
+ movl 20(%esp),%ecx # Length of memory-area
+ clrb %al # For test of end-null
+ jecxz sm_90 # Nothing to move, put zero at end.
+
+sm_10: cmpb (%esi),%al # Next char to move
+ movsb # move arg
+ jz sm_99 # last char, we are ready
+ loop sm_10 # Continue moving
+sm_90: movb %al,(%edi) # Set end pos
+ incl %edi # Fix that di points at end null
+sm_99: decl %edi # di points now at end null
+ movl %edi,%eax # Ret value.p $
popl %esi
popl %edi
ret
.strmake_end:
.size strmake,.strmake_end-strmake
- /* Move a string with max len chars */
- /* arg: dst,src,len */
- /* ret: pos to first null or dst+len */
+ # Move a string with max len chars
+ # arg: dst,src,len
+ # ret: pos to first null or dst+len
.globl strnmov
.type strnmov,@function
strnmov:
pushl %edi
pushl %esi
- movl 12(%esp),%edi /* dst */
- movl 16(%esp),%esi /* src */
- movl 20(%esp),%ecx /* Length of memory-area */
- jecxz snm_99 /* Nothing to do */
- clrb %al /* For test of end-null */
-
-snm_10: cmpb (%esi),%al /* Next char to move */
- movsb /* move arg */
- jz snm_20 /* last char, fill with null */
- loop snm_10 /* Continue moving */
- incl %edi /* Point two after last */
-snm_20: decl %edi /* Point at first null (or last+1) */
-snm_99: movl %edi,%eax /* Pointer at last char */
+ movl 12(%esp),%edi # dst
+ movl 16(%esp),%esi # src
+ movl 20(%esp),%ecx # Length of memory-area
+ jecxz snm_99 # Nothing to do
+ clrb %al # For test of end-null
+
+snm_10: cmpb (%esi),%al # Next char to move
+ movsb # move arg
+ jz snm_20 # last char, fill with null
+ loop snm_10 # Continue moving
+ incl %edi # Point two after last
+snm_20: decl %edi # Point at first null (or last+1)
+snm_99: movl %edi,%eax # Pointer at last char
popl %esi
popl %edi
ret
@@ -357,17 +356,17 @@ snm_99: movl %edi,%eax /* Pointer at last char */
.globl strmov
.type strmov,@function
strmov:
- movl %esi,%ecx /* Save old %esi and %edi */
+ movl %esi,%ecx # Save old %esi and %edi
movl %edi,%edx
- movl 8(%esp),%esi /* get source pointer (s2) */
- movl 4(%esp),%edi /* %edi -> s1 */
+ movl 8(%esp),%esi # get source pointer (s2)
+ movl 4(%esp),%edi # %edi -> s1
smo_10: movb (%esi),%al
- movsb /* move arg */
+ movsb # move arg
andb %al,%al
- jnz smo_10 /* Not last */
+ jnz smo_10 # Not last
movl %edi,%eax
dec %eax
- movl %ecx,%esi /* Restore */
+ movl %ecx,%esi # Restore
movl %edx,%edi
ret
.strmov_end:
@@ -376,29 +375,29 @@ smo_10: movb (%esi),%al
.globl strxmov
.type strxmov,@function
strxmov:
- movl %ebx,%edx /* Save %ebx, %esi and %edi */
+ movl %ebx,%edx # Save %ebx, %esi and %edi
mov %esi,%ecx
push %edi
- leal 8(%esp),%ebx /* Get destination */
+ leal 8(%esp),%ebx # Get destination
movl (%ebx),%edi
xorb %al,%al
- jmp next_str /* Handle source ebx+4 */
+ jmp next_str # Handle source ebx+4
start_str:
movsb
cmpb -1(%edi),%al
jne start_str
- decl %edi /* Don't copy last null */
+ decl %edi # Don't copy last null
next_str:
addl $4,%ebx
movl (%ebx),%esi
orl %esi,%esi
jne start_str
- movb %al,0(%edi) /* Force last to ASCII 0 */
+ movb %al,0(%edi) # Force last to ASCII 0
- movl %edi,%eax /* Return ptr to ASCII 0 */
- pop %edi /* Restore registers */
+ movl %edi,%eax # Return ptr to ASCII 0
+ pop %edi # Restore registers
movl %ecx,%esi
movl %edx,%ebx
ret
diff --git a/strings/strinstr.c b/strings/strinstr.c
index e1d502f4004..1c814d19d47 100644
--- a/strings/strinstr.c
+++ b/strings/strinstr.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 : strinstr.c
Author : Monty & David
@@ -27,7 +26,7 @@
char is 1.
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
uint strinstr(reg1 const char *str,reg4 const char *search)
diff --git a/strings/strlen.c b/strings/strlen.c
index c142a7f2b14..b9be374fa6e 100644
--- a/strings/strlen.c
+++ b/strings/strlen.c
@@ -1,3 +1,19 @@
+/* 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 */
+
/* File : strlen.c
Author : Richard A. O'Keefe. / Monty
Michael Widenius; ifdef MC68000
diff --git a/strings/strmake.c b/strings/strmake.c
index 66a230338a1..2e384fc168a 100644
--- a/strings/strmake.c
+++ b/strings/strmake.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 : strmake.c
Author : Michael Widenius
@@ -26,7 +25,7 @@
strmake() returns pointer to closing null
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
#ifdef BAD_STRING_COMPILER
diff --git a/strings/strmov.c b/strings/strmov.c
index 8f5beb41f41..507c2b6d997 100644
--- a/strings/strmov.c
+++ b/strings/strmov.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
strmov(dst, src) moves all the characters of src (including the
@@ -23,7 +22,7 @@
into dst, which seems useful.
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
#ifdef BAD_STRING_COMPILER
diff --git a/strings/strnlen.c b/strings/strnlen.c
index 3d625f7d48a..fc8879b3a41 100644
--- a/strings/strnlen.c
+++ b/strings/strnlen.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 : strnlen.c
Author : Michael Widenius
@@ -22,7 +21,7 @@
strnlen(s, len) returns the length of s or len if s is longer than len.
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
#ifndef HAVE_STRNLEN
diff --git a/strings/strnmov.c b/strings/strnmov.c
index ffc4a62f75e..362f3d6c4a8 100644
--- a/strings/strnmov.c
+++ b/strings/strnmov.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
strnmov(dst,src,length) moves length characters, or until end, of src to
@@ -22,7 +21,7 @@
truncated.
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
char *strnmov(register char *dst, register const char *src, uint n)
diff --git a/strings/strrchr.c b/strings/strrchr.c
index 5a045ac3740..fb588c015f2 100644
--- a/strings/strrchr.c
+++ b/strings/strrchr.c
@@ -1,3 +1,19 @@
+/* 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 */
+
/* File : strrchr.c
Author : Richard A. O'Keefe.
Updated: 10 April 1984
diff --git a/strings/strstr.c b/strings/strstr.c
index 572bf88c95c..66e9358b493 100644
--- a/strings/strstr.c
+++ b/strings/strstr.c
@@ -1,3 +1,19 @@
+/* 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 */
+
/* File : strstr.c
Author : Monty
Updated: 1986.11.24
@@ -10,7 +26,7 @@
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
#ifndef HAVE_STRSTR
diff --git a/strings/strto.c b/strings/strto.c
index d3392c794e9..84dccbcbeb8 100644
--- a/strings/strto.c
+++ b/strings/strto.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
strtol,strtoul,strtoll,strtoull
@@ -36,7 +35,7 @@
it can be compiled with the UNSIGNED and/or LONGLONG flag set
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
#include "m_ctype.h"
#include "my_sys.h" /* defines errno */
diff --git a/strings/strtol.c b/strings/strtol.c
index 87fe0d22cf3..10d7f8f9da6 100644
--- a/strings/strtol.c
+++ b/strings/strtol.c
@@ -1,23 +1,22 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 defines strtol() if neaded */
-#include <global.h>
+#include <my_global.h>
#if !defined(MSDOS) && !defined(HAVE_STRTOL) && !defined(__WIN__)
#include "strto.c"
#endif
diff --git a/strings/strtoll.c b/strings/strtoll.c
index 678c28649ef..8d0ba21d576 100644
--- a/strings/strtoll.c
+++ b/strings/strtoll.c
@@ -1,23 +1,22 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 is defines strtoll() if neaded */
-#include <global.h>
+#include <my_global.h>
#include <m_string.h>
#if !defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
#define USE_LONGLONG
diff --git a/strings/strtoul.c b/strings/strtoul.c
index e49a9ebea6a..00e1f820942 100644
--- a/strings/strtoul.c
+++ b/strings/strtoul.c
@@ -1,23 +1,22 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 is defines strtoul() if neaded */
-#include <global.h>
+#include <my_global.h>
#if !defined(MSDOS) && !defined(HAVE_STRTOUL)
#define USE_UNSIGNED
#include "strto.c"
diff --git a/strings/strtoull.c b/strings/strtoull.c
index 74dab95b801..25201e546ce 100644
--- a/strings/strtoull.c
+++ b/strings/strtoull.c
@@ -1,23 +1,22 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 is defines strtoull() */
-#include <global.h>
+#include <my_global.h>
#include <m_string.h>
#if !defined(HAVE_STRTOULL) && defined(HAVE_LONG_LONG)
#define USE_UNSIGNED
diff --git a/strings/strxmov.c b/strings/strxmov.c
index 7ee1d303ee8..d8532bac8b4 100644
--- a/strings/strxmov.c
+++ b/strings/strxmov.c
@@ -1,3 +1,19 @@
+/* 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 */
+
/* File : strxmov.c
Author : Richard A. O'Keefe.
Updated: 25 may 1984
@@ -13,7 +29,7 @@
character pointer, or not the same bit pattern as NullS.
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
#include <stdarg.h>
diff --git a/strings/strxnmov.c b/strings/strxnmov.c
index b55a2e0ab79..5e764e49e5a 100644
--- a/strings/strxnmov.c
+++ b/strings/strxnmov.c
@@ -1,3 +1,19 @@
+/* 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 */
+
/* File : strxnmov.c
Author : Richard A. O'Keefe.
Updated: 2 June 1984
@@ -20,7 +36,7 @@
needed.
*/
-#include <global.h>
+#include <my_global.h>
#include "m_string.h"
#include <stdarg.h>
diff --git a/strings/t_ctype.h b/strings/t_ctype.h
index 6699244c1f4..ac1fa408c0e 100644
--- a/strings/t_ctype.h
+++ b/strings/t_ctype.h
@@ -1,3 +1,19 @@
+/* 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 */
+
/*
Copyright (C) 1998, 1999 by Pruet Boonma, all rights reserved.
Copyright (C) 1998 by Theppitak Karoonboonyanan, all rights reserved.
@@ -125,7 +141,7 @@ enum l1_symbols {
L1_SARA_AI_MAIMUAN,
L1_SARA_AI_MAIMALAI
};
-
+
// level 2 symbols & order
enum l2_symbols {
L2_BLANK = TOT_LEVELS,
@@ -139,7 +155,7 @@ enum l2_symbols {
L2_TONE3,
L2_TONE4
};
-
+
// level 3 symbols & order
enum l3_symbols {
L3_BLANK = TOT_LEVELS,
diff --git a/strings/udiv.c b/strings/udiv.c
index 07af323a706..25f3f4685f0 100644
--- a/strings/udiv.c
+++ b/strings/udiv.c
@@ -1,23 +1,22 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Do udiv and urem if machine dosn't have it */
-#include <global.h>
+#include <my_global.h>
#include <math.h>
unsigned long udiv(long unsigned int a, long unsigned int b)
diff --git a/support-files/binary-configure.sh b/support-files/binary-configure.sh
index 682ea570b25..107f468bffc 100644
--- a/support-files/binary-configure.sh
+++ b/support-files/binary-configure.sh
@@ -20,5 +20,5 @@ then
echo "Starting the mysqld server. You can test that it is up and running"
echo "with the command:"
echo "./bin/mysqladmin version"
- ./bin/safe_mysqld &
+ ./bin/mysqld_safe &
fi
diff --git a/support-files/build-tags b/support-files/build-tags
new file mode 100755
index 00000000000..d5f9fbf5100
--- /dev/null
+++ b/support-files/build-tags
@@ -0,0 +1,9 @@
+#! /bin/sh
+
+rm -f TAGS
+filter='\.cc$\|\.c$\|\.h$\|\.yy$'
+files=`bk -r sfiles -gU | grep $filter `
+for f in $files ;
+do
+ etags -o TAGS --append $f
+done
diff --git a/support-files/mysql-max.spec.sh b/support-files/mysql-max.spec.sh
index 49f131154c0..5c4b16f0e9d 100644
--- a/support-files/mysql-max.spec.sh
+++ b/support-files/mysql-max.spec.sh
@@ -208,7 +208,7 @@ chmod -R og-rw $mysql_datadir/mysql
# Restart in the same way that mysqld will be started normally.
/etc/rc.d/init.d/mysql start
-# Allow safe_mysqld to start mysqld and print a message before we exit
+# Allow mysqld_safe to start mysqld and print a message before we exit
sleep 2
%preun
@@ -244,7 +244,7 @@ fi
%attr(755, root, root) /usr/bin/perror
%attr(755, root, root) /usr/bin/replace
%attr(755, root, root) /usr/bin/resolveip
-%attr(755, root, root) /usr/bin/safe_mysqld
+%attr(755, root, root) /usr/bin/mysqld_safe
%attr(755, root, root) /usr/bin/mysqld_multi
%attr(755, root, root) /usr/bin/my_print_defaults
diff --git a/support-files/mysql-multi.server.sh b/support-files/mysql-multi.server.sh
index 6c940630427..31020029354 100644
--- a/support-files/mysql-multi.server.sh
+++ b/support-files/mysql-multi.server.sh
@@ -133,14 +133,14 @@ case "$mode" in
'start')
# Start daemon
- if test -x $bindir/safe_mysqld
+ if test -x $bindir/mysqld_safe
then
# We only need to specify datadir and pid-file here and we
# get all other instance-specific config from $datadir/my.cnf.
# We have to explicitly pass --defaults-extra-file because it
# reads the config files before the command line options.
- # Also it must be first because of the way safe_mysqld works.
- $bindir/safe_mysqld --defaults-extra-file=$datadir/my.cnf \
+ # Also it must be first because of the way mysqld_safe works.
+ $bindir/mysqld_safe --defaults-extra-file=$datadir/my.cnf \
--datadir=$datadir --pid-file=$pid_file &
# Make lock for RedHat / SuSE
if test -d /var/lock/subsys
@@ -148,7 +148,7 @@ case "$mode" in
touch /var/lock/subsys/mysql
fi
else
- echo "Can't execute $bindir/safe_mysqld"
+ echo "Can't execute $bindir/mysqld_safe"
fi
;;
diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh
index 62381ccf0d3..eed749bf5b2 100644
--- a/support-files/mysql.server.sh
+++ b/support-files/mysql.server.sh
@@ -100,25 +100,25 @@ case "$mode" in
'start')
# Start daemon
- if test -x $bindir/safe_mysqld
+ if test -x $bindir/mysqld_safe
then
# Give extra arguments to mysqld with the my.cnf file. This script may
# be overwritten at next upgrade.
- $bindir/safe_mysqld --datadir=$datadir --pid-file=$pid_file &
+ $bindir/mysqld_safe --datadir=$datadir --pid-file=$pid_file &
# Make lock for RedHat / SuSE
if test -w /var/lock/subsys
then
touch /var/lock/subsys/mysql
fi
else
- echo "Can't execute $bindir/safe_mysqld"
+ echo "Can't execute $bindir/mysqld_safe"
fi
;;
'stop')
# Stop daemon. We use a signal here to avoid having to know the
# root password.
- if test -f "$pid_file"
+ if test -s "$pid_file"
then
mysqld_pid=`cat $pid_file`
echo "Killing mysqld with pid $mysqld_pid"
diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh
index 58909518b25..a6152fbde91 100644
--- a/support-files/mysql.spec.sh
+++ b/support-files/mysql.spec.sh
@@ -1,6 +1,6 @@
%define mysql_version @VERSION@
%define shared_lib_version @SHARED_LIB_VERSION@
-%define release 1
+%define release 2
%define mysqld_user mysql
%define see_base For a description of MySQL see the base MySQL RPM or http://www.mysql.com
@@ -143,6 +143,20 @@ Optional MySQL server binary that supports features
like transactional tables. To active this binary, just install this
package after the MySQL package.
+%package embedded
+Release: %{release}
+Requires: devel
+Summary: MySQL - embedded library
+Group: Applications/Databases
+Summary(pt_BR): MySQL - Medições de desempenho
+Group(pt_BR): Aplicações/Banco_de_Dados
+Obsoletes: embedded
+
+%description embedded
+This package contains the MySQL server as library.
+
+%{see_base}
+
%prep
%setup -n mysql-%{mysql_version}
@@ -177,6 +191,8 @@ sh -c "PATH=\"${MYSQL_BUILD_PATH:-/bin:/usr/bin}\" \
--infodir=/usr/info \
--includedir=/usr/include \
--mandir=/usr/man \
+ --with-embedded-server \
+ --enable-thread-safe-client \
--with-comment=\"Official MySQL RPM\";
# Add this for more debugging support
# --with-debug
@@ -203,7 +219,7 @@ RBR=$RPM_BUILD_ROOT
MBD=$RPM_BUILD_DIR/mysql-%{mysql_version}
if test -z "$RBR" -o "$RBR" = "/"
then
- echo "RPM_BUILD_ROOT has insecure value"
+ echo "RPM_BUILD_ROOT has stupid value"
exit 1
fi
rm -rf $RBR
@@ -375,11 +391,12 @@ fi
%attr(755, root, root) /usr/bin/mysqlbug
%attr(755, root, root) /usr/bin/mysqltest
%attr(755, root, root) /usr/bin/mysqlhotcopy
+%attr(755, root, root) /usr/bin/mysql_explain_log
%attr(755, root, root) /usr/bin/perror
%attr(755, root, root) /usr/bin/replace
%attr(755, root, root) /usr/bin/resolveip
+%attr(755, root, root) /usr/bin/mysqld_safe
%attr(755, root, root) /usr/bin/resolve_stack_dump
-%attr(755, root, root) /usr/bin/safe_mysqld
%attr(755, root, root) /usr/bin/mysqld_multi
%attr(755, root, root) /usr/bin/my_print_defaults
@@ -417,7 +434,7 @@ fi
%attr(644, root, man) %doc /usr/man/man1/mysqlshow.1*
%attr(644, root, man) %doc /usr/man/man1/perror.1*
%attr(644, root, man) %doc /usr/man/man1/replace.1*
-%attr(644, root, man) %doc /usr/man/man1/safe_mysqld.1*
+%attr(644, root, man) %doc /usr/man/man1/mysqld_safe.1*
%post shared
/sbin/ldconfig
@@ -438,16 +455,22 @@ fi
%files bench
%attr(-, root, root) /usr/share/sql-bench
%attr(-, root, root) /usr/share/mysql-test
+%attr(755, root, root) /usr/bin/mysqlmanager
+%attr(755, root, root) /usr/bin/mysqlmanager-pwgen
+%attr(755, root, root) /usr/bin/mysqlmanagerc
%files Max
%attr(755, root, root) /usr/sbin/mysqld-max
%attr(644, root, root) /usr/lib/mysql/mysqld-max.sym
+%files embedded
+%attr(755, root, root) /usr/lib/mysql/libmysqld.a
+
%changelog
-* Fri Feb 15 2002 Sasha
+* Mon Oct 8 2001 Monty
-- changed build to use --with-other-libc
+- Added embedded server as a separate RPM
* Fri Apr 13 2001 Monty
diff --git a/tests/fork2_test.pl b/tests/fork2_test.pl
index b5564e99c3f..19fab5a67d6 100755
--- a/tests/fork2_test.pl
+++ b/tests/fork2_test.pl
@@ -92,7 +92,7 @@ $errors=0;
while (($pid=wait()) != -1)
{
$ret=$?/256;
- print "thread '" . $work{$pid} . "' finnished with exit code $ret\n";
+ print "thread '" . $work{$pid} . "' finished with exit code $ret\n";
$errors++ if ($ret != 0);
}
diff --git a/tests/fork_big.pl b/tests/fork_big.pl
index e082225604c..c72eb59946b 100755
--- a/tests/fork_big.pl
+++ b/tests/fork_big.pl
@@ -106,7 +106,7 @@ $running_insert_threads=$opt_threads+$numtables;
while (($pid=wait()) != -1)
{
$ret=$?/256;
- print "thread '" . $work{$pid} . "' finnished with exit code $ret\n";
+ print "thread '" . $work{$pid} . "' finished with exit code $ret\n";
if ($work{$pid} =~ /^insert/)
{
if (!--$running_insert_threads)
diff --git a/tests/insert_and_repair.pl b/tests/insert_and_repair.pl
index 4d68c2ab9a0..1c7186bb651 100755
--- a/tests/insert_and_repair.pl
+++ b/tests/insert_and_repair.pl
@@ -56,7 +56,7 @@ $errors=0;
while (($pid=wait()) != -1)
{
$ret=$?/256;
- print "thread '" . $work{$pid} . "' finnished with exit code $ret\n";
+ print "thread '" . $work{$pid} . "' finished with exit code $ret\n";
$errors++ if ($ret != 0);
}
diff --git a/tests/mail_to_db.pl b/tests/mail_to_db.pl
index b758a171c77..671e8b23599 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.3";
+$VER = "2.6";
$opt_help = 0;
$opt_version = 0;
@@ -152,19 +152,77 @@ sub main
$dbh->disconnect if (!$opt_test);
$ignored = ($mail_no_from_f + $mail_no_subject_f + $mail_no_txt_f +
- $mail_too_big + $mail_duplicates);
- print "Mails inserted:\t\t\t$mail_inserted\n";
- print "Mails ignored:\t\t\t$ignored\n";
- print "Mails without \"From:\" -field:\t$mail_no_from_f\n";
- print "Mails without message:\t\t$mail_no_txt_f\n";
- print "Mails without subject:\t\t$mail_no_subject_f\n";
- print "Too big mails (> $opt_max_mail_size):\t$mail_too_big\n";
- print "Duplicate mails:\t\t$mail_duplicates\n";
- print "Forwarded mails:\t\t$mail_forwarded\n";
- print "Total number of mails:\t\t";
+ $mail_too_big + $mail_duplicates + $mail_fixed);
+ print "################################ Mail Report #################################\n\n";
+ print "Mails inserted:\t\t\t\t\t$mail_inserted\n";
+ print "--------------- ";
+ print "=" . "=" x length("$mail_inserted") . "=\n\n";
+ if ($ignored)
+ {
+ print "Ignored mails\n";
+ print "-------------\n";
+ if ($mail_no_from_f)
+ {
+ print "Reason: mail without \"From:\" -field:\t\t$mail_no_from_f\n";
+ }
+ else
+ {
+ print "";
+ }
+ if ($mail_no_txt_f)
+ {
+ print "Reason: mail without message:\t\t\t$mail_no_txt_f\n";
+ }
+ else
+ {
+ print "";
+ }
+ if ($mail_no_subject_f)
+ {
+ print "Reason: mail without subject:\t\t\t$mail_no_subject_f\n";
+ }
+ else
+ {
+ print "";
+ }
+ if ($mail_too_big)
+ {
+ print "Reason: mail too big, over $opt_max_mail_size bytes:\t\t";
+ print $mail_too_big;
+ print " (see --max_mail_size=#)\n";
+ }
+ else
+ {
+ print "";
+ }
+ if ($mail_duplicates)
+ {
+ print "Reason: duplicate mail, or in db already:\t$mail_duplicates\n";
+ }
+ else
+ {
+ print "";
+ }
+ if ($mail_fixed)
+ {
+ print "Reason: mail was an unsubscribe - mail:\t\t$mail_fixed\n";
+ }
+ else
+ {
+ print "";
+ }
+ print " ";
+ print "=" . "=" x length("$ignored") . "=\n";
+ print "Total number of ignored mails:\t\t\t$ignored\n\n";
+ }
+ print "Total number of mails:\t\t\t\t";
print $mail_inserted + $ignored;
- print "\n";
- print "Mails with unsubscribe removed:\t$mail_fixed\n";
+ print " (OK: ";
+ print sprintf("%.1f", (($mail_inserted / ($mail_inserted+$ignored)) * 100));
+ print "% Ignored: ";
+ print sprintf("%.1f", (($ignored / ($mail_inserted + $ignored)) * 100));
+ print "%)\n";
+ print "################################ End Report ##################################\n";
exit(0);
}
@@ -213,10 +271,10 @@ sub process_mail_file
%values = ();
$type = "";
$check = 0;
-
while (<FILE>)
{
chop;
+ chop if (substr($_, -1, 1) eq "\r");
if ($type ne "message")
{
if (/^Reply-To: (.*)/i)
@@ -269,7 +327,8 @@ sub process_mail_file
$values{$type} .= "\n" . $_;
$check--;
}
- elsif (/^From .* \d\d:\d\d:\d\d\s\d\d\d\d$/)
+ elsif (/^From .* \d\d:\d\d:\d\d\s\d\d\d\d/ ||
+ /^From .* \d\d\d\d\s\d\d:\d\d:\d\d/)
{
$values{'hash'} = checksum("$values{'message'}");
update_table($dbh, $file_name, \%values);
@@ -288,8 +347,11 @@ sub process_mail_file
$values{$type} .= "\n" . $_;
}
}
- $values{'hash'} = checksum("$values{'message'}");
- update_table($dbh, $file_name, \%values);
+ if (defined($values{'message'}))
+ {
+ $values{'hash'} = checksum("$values{'message'}");
+ update_table($dbh, $file_name, \%values);
+ }
}
####
@@ -335,26 +397,26 @@ sub date_parser
sub update_table
{
my($dbh, $file_name, $values) = @_;
- my($q,$tail,$message);
+ my($q, $tail, $message);
if (!defined($values->{'subject'}) || !defined($values->{'to'}))
{
$mail_no_subject_f++;
return; # Ignore these
}
- $message=$values->{'message'};
- $message =~ s/^\s*//; #removes whitespaces from the beginning
+ $message = $values->{'message'};
+ $message =~ s/^\s*//; # removes whitespaces from the beginning
restart:
- $message =~ s/[\s\n>]*$//; #removes whitespaces and '>' from the end
- $values->{'message'}=$message;
+ $message =~ s/[\s\n>]*$//; # removes whitespaces and '>' from the end
+ $values->{'message'} = $message;
foreach $tail (@remove_tail)
{
$message =~ s/$tail//;
}
if ($message ne $values->{'message'})
{
- $message =~ s/\s*$//; #removes whitespaces from the end
+ $message =~ s/\s*$//; # removes whitespaces from the end
$mail_fixed++;
goto restart; # Some mails may have duplicated messages
}
@@ -442,7 +504,7 @@ sub update_table
sub checksum
{
my ($txt)= @_;
- my ($crc,$i,$count);
+ my ($crc, $i, $count);
$count = length($txt);
for ($crc = $i = 0; $i < $count ; $i++)
{
diff --git a/tests/myisam-big-rows.tst b/tests/myisam-big-rows.tst
new file mode 100644
index 00000000000..56c06f4820f
--- /dev/null
+++ b/tests/myisam-big-rows.tst
@@ -0,0 +1,72 @@
+#
+# Test rows with length above > 16M
+# Note that for this to work, you should start mysqld with
+# -O max_allowed_packet=32M
+#
+
+drop table if exists t1;
+create table t1 (a tinyint not null auto_increment, b longblob not null, primary key (a)) checksum=1;
+
+insert into t1 (b) values(repeat(char(65),10));
+insert into t1 (b) values(repeat(char(66),10));
+insert into t1 (b) values(repeat(char(67),10));
+update t1 set b=repeat(char(68),16777216) where a=1;
+check table t1;
+update t1 set b=repeat(char(69),16777000) where a=2;
+update t1 set b=repeat(char(70),167) where a=3;
+update t1 set b=repeat(char(71),16778000) where a=1;
+update t1 set b=repeat(char(72),16778000) where a=3;
+select a,length(b) from t1;
+set @a=1;
+insert into t1 (b) values (repeat(char(73+@a),16777200+@a));
+set @a=@a+1;
+insert into t1 (b) values (repeat(char(73+@a),16777200+@a));
+set @a=@a+1;
+insert into t1 (b) values (repeat(char(73+@a),16777200+@a));
+set @a=@a+1;
+insert into t1 (b) values (repeat(char(73+@a),16777200+@a));
+set @a=@a+1;
+insert into t1 (b) values (repeat(char(73+@a),16777200+@a));
+set @a=@a+1;
+insert into t1 (b) values (repeat(char(73+@a),16777200+@a));
+set @a=@a+1;
+insert into t1 (b) values (repeat(char(73+@a),16777200+@a));
+set @a=@a+1;
+insert into t1 (b) values (repeat(char(73+@a),16777200+@a));
+set @a=@a+1;
+insert into t1 (b) values (repeat(char(73+@a),16777200+@a));
+set @a=@a+1;
+insert into t1 (b) values (repeat(char(73+@a),16777200+@a));
+set @a=@a+1;
+insert into t1 (b) values (repeat(char(73+@a),16777200+@a));
+set @a=@a+1;
+insert into t1 (b) values (repeat(char(73+@a),16777200+@a));
+set @a=@a+1;
+insert into t1 (b) values (repeat(char(73+@a),16777200+@a));
+set @a=@a+1;
+insert into t1 (b) values (repeat(char(73+@a),16777200+@a));
+set @a=@a+1;
+insert into t1 (b) values (repeat(char(73+@a),16777200+@a));
+set @a=@a+1;
+insert into t1 (b) values (repeat(char(73+@a),16777200+@a));
+set @a=@a+1;
+insert into t1 (b) values (repeat(char(73+@a),16777200+@a));
+set @a=@a+1;
+insert into t1 (b) values (repeat(char(73+@a),16777200+@a));
+update t1 set b=('A') where a=5;
+delete from t1 where a=7;
+set @a=@a+1;
+insert into t1 (b) values (repeat(char(73+@a),16777200+@a));
+update t1 set b=repeat(char(73+@a+1),17000000+@a) where a=last_insert_id();
+
+select a,mid(b,1,5),length(b) from t1;
+check table t1;
+repair table t1;
+check table t1;
+select a from table where b<>repeat(mid(b,1,1),length(b));
+delete from t1 where (a & 1);
+select a from table where b<>repeat(mid(b,1,1),length(b));
+check table t1;
+repair table t1;
+check table t1;
+drop table t1;
diff --git a/tests/rename_test.pl b/tests/rename_test.pl
index bdfb14be927..edf3216a62f 100755
--- a/tests/rename_test.pl
+++ b/tests/rename_test.pl
@@ -79,7 +79,7 @@ print "Total time: " .
exit(0);
#
-# Insert records in the table. Delete table when test is finnished
+# Insert records in the table. Delete table when test is finished
#
sub test_insert
diff --git a/tests/test_delayed_insert.pl b/tests/test_delayed_insert.pl
index e49d73a19bd..c7a8f0ca4b7 100755
--- a/tests/test_delayed_insert.pl
+++ b/tests/test_delayed_insert.pl
@@ -65,7 +65,7 @@ $errors=0;
while (($pid=wait()) != -1)
{
$ret=$?/256;
- print "thread '" . $work{$pid} . "' finnished with exit code $ret\n";
+ print "thread '" . $work{$pid} . "' finished with exit code $ret\n";
$errors++ if ($ret != 0);
}
diff --git a/tools/Makefile.am b/tools/Makefile.am
new file mode 100644
index 00000000000..e5130865a89
--- /dev/null
+++ b/tools/Makefile.am
@@ -0,0 +1,20 @@
+INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include \
+ $(openssl_includes) -I../include
+LDADD= @CLIENT_EXTRA_LDFLAGS@ ../libmysql_r/libmysqlclient_r.la @openssl_libs@
+bin_PROGRAMS= mysqlmanager
+mysqlmanager_SOURCES= mysqlmanager.c
+mysqlmanager_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES)
+DEF= -DUNDEF_THREADS_HACK
+
+OMIT_DEPENDENCIES = pthread.h stdio.h __stdio.h stdlib.h __stdlib.h math.h\
+ __math.h time.h __time.h unistd.h __unistd.h types.h \
+ xtypes.h ac-types.h posix.h string.h __string.h \
+ errno.h socket.h inet.h dirent.h netdb.h \
+ cleanup.h cond.h debug_out.h fd.h kernel.h mutex.h \
+ prio_queue.h pthread_attr.h pthread_once.h queue.h\
+ sleep.h specific.h version.h pwd.h timers.h uio.h \
+ cdefs.h machdep.h signal.h __signal.h util.h lex.h \
+ wait.h
+
+# Don't update the files from bitkeeper
+%::SCCS/s.%
diff --git a/tools/managertest1.nc b/tools/managertest1.nc
new file mode 100644
index 00000000000..bf1b82ed406
--- /dev/null
+++ b/tools/managertest1.nc
@@ -0,0 +1,16 @@
+def_exec server /usr/sbin/mysqld --socket=/tmp/temp.sock --skip-grant --skip-net --datadir=/tmp
+set_exec_con server root localhost /tmp/temp.sock
+set_exec_stdout server /tmp/mysqld.err
+set_exec_stderr server /tmp/mysqld.err
+start_exec server 3
+show_exec
+query server show variables like '%max_heap%';
+stop_exec server 3
+def_exec server /usr/sbin/mysqld --socket=/tmp/temp.sock --skip-grant --skip-net --datadir=/tmp -O max_heap_table_size=5000
+show_exec
+start_exec server 3
+query server show variables like '%max_heap%';
+show_exec
+stop_exec server 3
+show_exec
+quit
diff --git a/tools/mysqlmanager-sample.pwd b/tools/mysqlmanager-sample.pwd
new file mode 100644
index 00000000000..51c1ade1b77
--- /dev/null
+++ b/tools/mysqlmanager-sample.pwd
@@ -0,0 +1 @@
+root:5ebe2294ecd0e0f08eab7690d2a6ee69
diff --git a/tools/mysqlmanager.c b/tools/mysqlmanager.c
new file mode 100644
index 00000000000..bd43c6bc0ec
--- /dev/null
+++ b/tools/mysqlmanager.c
@@ -0,0 +1,1857 @@
+/* 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 */
+
+/* MySQL server management daemon
+ *
+ * Written by:
+ * Sasha Pachev <sasha@mysql.com>
+ **/
+
+#include <my_global.h>
+#include <my_pthread.h>
+#include <mysql.h>
+#include <mysql_version.h>
+#include <mysqld_error.h>
+#include <my_sys.h>
+#include <my_dir.h>
+#include <m_string.h>
+#include <m_ctype.h>
+#include <hash.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <violite.h>
+#include <md5.h>
+#include <signal.h>
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#define MANAGER_VERSION "1.0"
+#define MANAGER_GREETING "MySQL Server Management Daemon v. 1.0"
+
+#define LOG_ERR 1
+#define LOG_WARN 2
+#define LOG_INFO 3
+#define LOG_DEBUG 4
+
+#define CHILD_START 1
+#define CHILD_STOP 2
+
+#ifndef MANAGER_PORT
+#define MANAGER_PORT 23546
+#endif
+
+#ifndef MANAGER_CONNECT_RETRIES
+#define MANAGER_CONNECT_RETRIES 5
+#endif
+
+#ifndef MANAGER_MAX_CMD_LEN
+#define MANAGER_MAX_CMD_LEN 16384
+#endif
+
+#ifndef MANAGER_LOG_FILE
+#define MANAGER_LOG_FILE "/var/log/mysqlmanager.log"
+#endif
+
+#ifndef MANAGER_BACK_LOG
+#define MANAGER_BACK_LOG 50
+#endif
+
+#ifndef MAX_USER_NAME
+#define MAX_USER_NAME 16
+#endif
+
+#ifndef MANAGER_PW_FILE
+#define MANAGER_PW_FILE "/etc/mysqlmanager.passwd"
+#endif
+
+#ifndef MAX_HOST
+#define MAX_HOST 128
+#endif
+
+#ifndef MAX_LAUNCHER_MSG
+#define MAX_LAUNCHER_MSG 256
+#endif
+
+#define MAX_RETRY_COUNT 100
+
+/* Variable naming convention - if starts with manager_, either is set
+ directly by the user, or used closely in ocnjunction with a variable
+ set by the user
+*/
+
+#if defined(__i386__) && defined(HAVE_LINUXTHREADS)
+#define DO_STACKTRACE 1
+#endif
+
+uint manager_port = MANAGER_PORT;
+FILE* errfp;
+const char* manager_log_file = MANAGER_LOG_FILE;
+pthread_mutex_t lock_log,lock_shutdown,lock_exec_hash,lock_launch_thd;
+pthread_cond_t cond_launch_thd;
+pthread_t loop_th,launch_msg_th;
+int manager_sock = -1;
+uchar* stack_bottom=0;
+struct sockaddr_in manager_addr;
+ulong manager_bind_addr = INADDR_ANY;
+int manager_back_log = MANAGER_BACK_LOG;
+int in_shutdown = 0, shutdown_requested=0;
+int manager_connect_retries=MANAGER_CONNECT_RETRIES;
+const char* manager_greeting = MANAGER_GREETING;
+uint manager_max_cmd_len = MANAGER_MAX_CMD_LEN;
+const char* manager_pw_file=MANAGER_PW_FILE;
+int one_thread = 0; /* for debugging */
+
+typedef enum {PARAM_STDOUT,PARAM_STDERR} PARAM_TYPE;
+
+/* messages */
+
+#define MAX_CLIENT_MSG_LEN 256
+#define NET_BLOCK 2048
+#define MD5_LEN 16
+#define ESCAPE_CHAR '\\'
+#define EOL_CHAR '\n'
+
+/* access flags */
+
+#define PRIV_SHUTDOWN 1
+
+struct manager_thd
+{
+ NET net;
+ char user[MAX_USER_NAME+1];
+ int priv_flags;
+ char* cmd_buf;
+ int fatal,finished;
+};
+
+struct manager_user
+{
+ char user[MAX_USER_NAME+1];
+ char md5_pass[MD5_LEN];
+ int user_len;
+ const char* error;
+};
+
+HASH exec_hash,user_hash;
+struct manager_exec* cur_launch_exec=0;
+
+static struct manager_thd* manager_thd_new(Vio* vio);
+
+static struct manager_exec* manager_exec_new(char* arg_start,char* arg_end);
+static void manager_exec_print(NET* net,struct manager_exec* e);
+static void manager_thd_free(struct manager_thd* thd);
+static void manager_exec_free(void* e);
+static void manager_exec_connect(struct manager_exec* e);
+static int manager_exec_launch(struct manager_exec* e);
+static struct manager_exec* manager_exec_by_pid(pid_t pid);
+
+static struct manager_user* manager_user_new(char* buf);
+static void manager_user_free(void* u);
+
+static char* arg_strmov(char* dest, const char* src, int n);
+static byte* get_exec_key(const byte* e, uint* len,
+ my_bool __attribute__((unused)) t);
+static byte* get_user_key(const byte* u, uint* len,
+ my_bool __attribute__((unused)) t);
+static uint tokenize_args(char* arg_start,char** arg_end);
+static void init_arg_array(char* arg_str,char** args,uint arg_count);
+static int hex_val(char c);
+static int open_and_dup(int fd,char* path);
+static void update_req_len(struct manager_exec* e);
+
+typedef int (*manager_cmd_handler)(struct manager_thd*,char*,char*);
+
+static void handle_child(int __attribute__((unused)) sig);
+static void handle_sigpipe(int __attribute__((unused)) sig);
+
+/* exec() in a threaded application is full of problems
+ to solve this, we fork off a launcher at the very start
+ and communicate with it through a pipe
+*/
+static void fork_launcher();
+static void run_launcher_loop();
+int to_launcher_pipe[2],from_launcher_pipe[2];
+pid_t launcher_pid;
+int in_segfault=0;
+const char* pid_file = "/var/run/mysqlmanager.pid";
+int created_pid_file = 0;
+
+struct manager_cmd
+{
+ const char* name;
+ const char* help;
+ manager_cmd_handler handler_func;
+ int len;
+};
+
+struct manager_exec
+{
+ char* ident;
+ int ident_len;
+ const char* error;
+ char* bin_path;
+ char** args;
+ char con_user[16];
+ char con_pass[16];
+ int con_port;
+ pid_t pid;
+ int exit_code;
+ pthread_mutex_t lock;
+ pthread_cond_t cond;
+ pthread_t th;
+ char con_sock[FN_REFLEN];
+ char con_host[MAX_HOST];
+ char stderr_path[FN_REFLEN];
+ char stdout_path[FN_REFLEN];
+ MYSQL mysql;
+ char* data_buf;
+ int req_len;
+ int start_wait_timeout;
+ int stderr_path_size,stdout_path_size,data_buf_size;
+ int num_args;
+};
+
+static int set_exec_param(struct manager_thd* thd, char* args_start,
+ char* args_end, PARAM_TYPE param_type);
+
+#define HANDLE_DECL(com) static int com (struct manager_thd* thd, char* args_start,char* args_end)
+#define HANDLE_NOARG_DECL(com) static int com \
+ (struct manager_thd* thd, char* __attribute__((unused)) args_start,\
+ char* __attribute__((unused)) args_end)
+
+
+HANDLE_NOARG_DECL(handle_ping);
+HANDLE_NOARG_DECL(handle_quit);
+HANDLE_NOARG_DECL(handle_help);
+HANDLE_NOARG_DECL(handle_shutdown);
+HANDLE_DECL(handle_def_exec);
+HANDLE_DECL(handle_start_exec);
+HANDLE_DECL(handle_stop_exec);
+HANDLE_DECL(handle_set_exec_con);
+HANDLE_DECL(handle_set_exec_stdout);
+HANDLE_DECL(handle_set_exec_stderr);
+HANDLE_NOARG_DECL(handle_show_exec);
+HANDLE_DECL(handle_query);
+
+
+struct manager_cmd commands[] =
+{
+ {"ping", "Check if this server is alive", handle_ping,4},
+ {"quit", "Finish session", handle_quit,4},
+ {"shutdown", "Shutdown this server", handle_shutdown,8},
+ {"def_exec", "Define executable entry", handle_def_exec,8},
+ {"start_exec", "Launch process defined by executable entry",
+ handle_start_exec,10},
+ {"stop_exec", "Stop process defined by executable entry",
+ handle_stop_exec,9},
+ {"set_exec_con", "Set connection parameters for executable entry",
+ handle_set_exec_con,12},
+ {"set_exec_stdout", "Set stdout path for executable entry",
+ handle_set_exec_stdout,15},
+ {"set_exec_stderr", "Set stderr path for executable entry",
+ handle_set_exec_stderr,15},
+ {"query","Run query against MySQL server",handle_query,5},
+ {"show_exec","Show defined executable entries",handle_show_exec,9},
+ {"help", "Print this message", handle_help,4},
+ {0,0,0,0}
+};
+
+struct option long_options[] =
+{
+ {"debug", optional_argument, 0, '#'},
+ {"help", no_argument, 0, 'h'},
+ {"port", required_argument, 0, 'P'},
+ {"log", required_argument, 0, 'l'},
+ {"bind-address", required_argument, 0, 'b'},
+ {"tcp-backlog", required_argument, 0, 'B'},
+ {"greeting", required_argument, 0, 'g'},
+ {"max-command-len",required_argument,0,'m'},
+ {"one-thread",no_argument,0,'d'},
+ {"connect-retries",required_argument,0,'C'},
+ {"password-file",required_argument,0,'p'},
+ {"pid-file",required_argument,0,'f'},
+ {"version", no_argument, 0, 'V'},
+ {0, 0, 0, 0}
+};
+
+static void die(const char* fmt,...);
+static void print_time(FILE* fp);
+static void clean_up();
+static struct manager_cmd* lookup_cmd(char* s,int len);
+static int client_msg(NET* net,int err_code,const char* fmt,...);
+static int client_msg_pre(NET* net,int err_code,const char* fmt,...);
+static int client_msg_raw(NET* net,int err_code,int pre,const char* fmt,
+ va_list args);
+static int authenticate(struct manager_thd* thd);
+static char* read_line(struct manager_thd* thd); /* returns pointer to end of
+ line
+ */
+static pthread_handler_decl(process_connection, arg);
+static pthread_handler_decl(process_launcher_messages, arg);
+static int exec_line(struct manager_thd* thd,char* buf,char* buf_end);
+
+#ifdef DO_STACKTRACE
+void print_stacktrace();
+#endif
+
+static void log_msg(const char* fmt, int msg_type, va_list args);
+
+/* No 'inline' here becasue functions with ... can't do that portable */
+#define LOG_MSG_FUNC(type,TYPE) static void type \
+ (const char* fmt,...) { \
+ va_list args; \
+ va_start(args,fmt); \
+ log_msg(fmt,TYPE,args);\
+ }
+
+LOG_MSG_FUNC(log_err,LOG_ERR)
+LOG_MSG_FUNC(log_warn,LOG_WARN)
+LOG_MSG_FUNC(log_info,LOG_INFO)
+
+#ifndef DBUG_OFF
+LOG_MSG_FUNC(log_debug,LOG_DEBUG)
+#else
+void log_debug(const char* __attribute__((unused)) fmt,...) {}
+#endif
+
+static void handle_sigterm(int sig __attribute__((unused)))
+{
+ log_info("Got SIGTERM");
+ if (!one_thread)
+ {
+ kill(launcher_pid,SIGTERM);
+ pthread_kill(loop_th,SIGTERM);
+ }
+ clean_up();
+ exit(0);
+}
+
+#ifdef DO_STACKTRACE
+static void handle_segfault(int sig)
+{
+ if (in_segfault)
+ exit(1);
+ in_segfault=1;
+ fprintf(errfp,"Got fatal signal %d\n",sig);
+ print_stacktrace();
+ exit(1);
+}
+#endif
+
+static void handle_sigpipe(int __attribute__((unused)) sig)
+{
+ signal(SIGPIPE,handle_sigpipe);
+}
+
+#ifdef DO_STACKTRACE
+
+#define MAX_DEPTH 25
+#define SIGRETURN_FRAME_COUNT 1
+
+void print_stacktrace()
+{
+ uchar** fp;
+ int i;
+ LINT_INIT(fp);
+ fprintf(errfp,"Fatal errror, stacktrace follows:\n");
+#ifdef __i386__
+ __asm__ __volatile__("movl %%ebp,%0" :"=r"(fp) :"r"(fp));
+#endif
+ if (!fp)
+ {
+ fprintf(errfp,"frame points is NULL, cannot trace stack\n");
+ return;
+ }
+ for(i=0;i<MAX_DEPTH && fp<(uchar**)stack_bottom;i++)
+ {
+#ifdef __i386__
+ uchar** new_fp = (uchar**)*fp;
+ fprintf(errfp, "%p\n", i == SIGRETURN_FRAME_COUNT ?
+ *(fp+17) : *(fp+1));
+#endif /* __386__ */
+ if (new_fp <= fp )
+ {
+ fprintf(errfp, "New value of fp=%p failed sanity check,\
+ terminating stack trace!\n", new_fp);
+ return;
+ }
+ fp = new_fp;
+ }
+ fprintf(errfp,"Stack trace successful\n");
+ fflush(errfp);
+}
+#endif
+
+static int exec_line(struct manager_thd* thd,char* buf,char* buf_end)
+{
+ char* p=buf;
+ struct manager_cmd* cmd;
+ for (;p<buf_end && !isspace(*p);p++)
+ *p=tolower(*p);
+ log_info("Command '%s'", buf);
+ if (!(cmd=lookup_cmd(buf,(int)(p-buf))))
+ {
+ if(client_msg(&thd->net,MANAGER_CLIENT_ERR,
+ "Unrecognized command '%s', type help to see list of supported\
+ commands", buf))
+ thd->fatal=1;
+ return 1;
+ }
+ for (;p<buf_end && isspace(*p);p++);
+ return cmd->handler_func(thd,p,buf_end);
+}
+
+static struct manager_cmd* lookup_cmd(char* s,int len)
+{
+ struct manager_cmd* cmd = commands;
+ for (;cmd->name;cmd++)
+ {
+ if (cmd->len == len && !memcmp(cmd->name,s,len))
+ return cmd;
+ }
+ return 0;
+}
+
+HANDLE_NOARG_DECL(handle_ping)
+{
+ client_msg(&thd->net,MANAGER_OK,"Server management daemon is alive");
+ return 0;
+}
+
+HANDLE_NOARG_DECL(handle_quit)
+{
+ client_msg(&thd->net,MANAGER_OK,"Goodbye");
+ thd->finished=1;
+ return 0;
+}
+
+HANDLE_NOARG_DECL(handle_help)
+{
+ struct manager_cmd* cmd = commands;
+ NET* net = &thd->net;
+ client_msg_pre(net,MANAGER_INFO,"Available commands:");
+ for (;cmd->name;cmd++)
+ {
+ client_msg_pre(net,MANAGER_INFO,"%s - %s", cmd->name, cmd->help);
+ }
+ client_msg_pre(net,MANAGER_INFO,"End of help");
+ return 0;
+}
+
+HANDLE_NOARG_DECL(handle_shutdown)
+{
+ client_msg(&thd->net,MANAGER_OK,"Shutdown started, goodbye");
+ thd->finished=1;
+ shutdown_requested = 1;
+ if (!one_thread)
+ {
+ kill(launcher_pid,SIGTERM);
+ pthread_kill(loop_th,SIGTERM);
+ }
+ return 0;
+}
+
+HANDLE_DECL(handle_set_exec_con)
+{
+ int num_args;
+ const char* error=0;
+ struct manager_exec* e;
+ char* arg_p;
+ if ((num_args=tokenize_args(args_start,&args_end))<2)
+ {
+ error="Too few arguments";
+ goto err;
+ }
+ arg_p=args_start;
+ pthread_mutex_lock(&lock_exec_hash);
+ if (!(e=(struct manager_exec*)hash_search(&exec_hash,arg_p,
+ strlen(arg_p))))
+ {
+ pthread_mutex_unlock(&lock_exec_hash);
+ error="Exec definition entry does not exist";
+ goto err;
+ }
+ arg_p+=strlen(arg_p)+1;
+ arg_p+=(strnmov(e->con_user,arg_p,sizeof(e->con_user))-e->con_user)+1;
+ if (num_args >= 3)
+ {
+ arg_p+=(strnmov(e->con_host,arg_p,sizeof(e->con_host))-e->con_host)+1;
+ if (num_args == 4)
+ {
+ if (!(e->con_port=atoi(arg_p)))
+ strnmov(e->con_sock,arg_p,sizeof(e->con_sock));
+ else
+ e->con_sock[0]=0;
+ }
+ else if(num_args > 4)
+ {
+ pthread_mutex_unlock(&lock_exec_hash);
+ error="Too many arguments";
+ goto err;
+ }
+ }
+ pthread_mutex_unlock(&lock_exec_hash);
+ client_msg(&thd->net,MANAGER_OK,"Entry updated");
+ return 0;
+err:
+ client_msg(&thd->net,MANAGER_CLIENT_ERR,error);
+ return 1;
+}
+
+HANDLE_DECL(handle_set_exec_stdout)
+{
+ return set_exec_param(thd,args_start,args_end,PARAM_STDOUT);
+}
+
+HANDLE_DECL(handle_set_exec_stderr)
+{
+ return set_exec_param(thd,args_start,args_end,PARAM_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)
+ {
+ error="Too few arguments";
+ goto err;
+ }
+ arg_p=args_start;
+ pthread_mutex_lock(&lock_exec_hash);
+ if (!(e=(struct manager_exec*)hash_search(&exec_hash,arg_p,
+ strlen(arg_p))))
+ {
+ pthread_mutex_unlock(&lock_exec_hash);
+ error="Exec definition entry does not exist";
+ goto err;
+ }
+ arg_p+=strlen(arg_p)+1;
+ param_size=strlen(arg_p)+1;
+ switch (param_type)
+ {
+ case PARAM_STDOUT:
+ param=e->stdout_path;
+ e->req_len+=(param_size-e->stdout_path_size);
+ e->stdout_path_size=param_size;
+ break;
+ case PARAM_STDERR:
+ param=e->stderr_path;
+ e->req_len+=(param_size-e->stderr_path_size);
+ e->stderr_path_size=param_size;
+ break;
+ default:
+ error="Internal error";
+ goto err;
+ }
+ strnmov(param,arg_p,FN_REFLEN);
+ pthread_mutex_unlock(&lock_exec_hash);
+ client_msg(&thd->net,MANAGER_OK,"Entry updated");
+ return 0;
+err:
+ client_msg(&thd->net,MANAGER_CLIENT_ERR,error);
+ return 1;
+}
+
+
+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)
+ {
+ error="Too few arguments";
+ goto err;
+ }
+ ident_len=strlen(args_start);
+ pthread_mutex_lock(&lock_exec_hash);
+ if (!(e=(struct manager_exec*)hash_search(&exec_hash,args_start,
+ ident_len)))
+ {
+ pthread_mutex_unlock(&lock_exec_hash);
+ error="Exec definition entry does not exist";
+ goto err;
+ }
+ pthread_mutex_unlock(&lock_exec_hash);
+ manager_exec_launch(e);
+ if ((error=e->error))
+ goto err;
+ pthread_mutex_lock(&e->lock);
+ t.tv_sec=time(0)+(e->start_wait_timeout=atoi(args_start+ident_len+1));
+ t.tv_nsec=0;
+ if (!e->pid)
+ pthread_cond_timedwait(&e->cond,&e->lock,&t);
+ if (!e->pid)
+ {
+ pthread_mutex_unlock(&e->lock);
+ error="Process failed to start withing alotted time";
+ goto err;
+ }
+ mysql_close(&e->mysql);
+ manager_exec_connect(e);
+ error=e->error;
+ pthread_mutex_unlock(&e->lock);
+ if (error)
+ goto err;
+ client_msg(&thd->net,MANAGER_OK,"'%s' started",e->ident);
+ return 0;
+err:
+ client_msg(&thd->net,MANAGER_CLIENT_ERR,error);
+ return 1;
+}
+
+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)
+ {
+ error="Too few arguments";
+ goto err;
+ }
+ ident_len=strlen(args_start);
+ abstime.tv_sec=time(0)+atoi(args_start+1+ident_len);
+ abstime.tv_nsec=0;
+ pthread_mutex_lock(&lock_exec_hash);
+ if (!(e=(struct manager_exec*)hash_search(&exec_hash,args_start,
+ ident_len)))
+ {
+ pthread_mutex_unlock(&lock_exec_hash);
+ error="Exec definition entry does not exist";
+ goto err;
+ }
+ pthread_mutex_unlock(&lock_exec_hash);
+ pthread_mutex_lock(&e->lock);
+ e->th=pthread_self();
+ if (!e->pid)
+ {
+ /* e->th=0; */ /* th may be a struct */
+ pthread_mutex_unlock(&e->lock);
+ error="Process not running";
+ goto err;
+ }
+ if (mysql_shutdown(&e->mysql))
+ {
+ /* e->th=0; */ /* th may be a struct */
+ pthread_mutex_unlock(&e->lock);
+ error="Could not send shutdown command";
+ goto err;
+ }
+ if (e->pid)
+ pthread_cond_timedwait(&e->cond,&e->lock,&abstime);
+ if (e->pid)
+ error="Process failed to terminate within alotted time";
+ /* e->th=0; */ /* th may be a struct */
+ pthread_mutex_unlock(&e->lock);
+ if (!error)
+ {
+ client_msg(&thd->net,MANAGER_OK,"'%s' terminated",e->ident);
+ return 0;
+ }
+err:
+ client_msg(&thd->net,MANAGER_CLIENT_ERR,error);
+ return 1;
+}
+
+HANDLE_DECL(handle_query)
+{
+ const char* error=0;
+ struct manager_exec* e;
+ MYSQL_RES* res=0;
+ MYSQL_ROW row;
+ MYSQL_FIELD* fields;
+ int num_fields,i,ident_len;
+ char* ident,*query;
+ query=ident=args_start;
+ while (!isspace(*query))
+ query++;
+ if (query == ident)
+ {
+ error="Missing server identifier";
+ goto err;
+ }
+ ident_len=(int)(query-ident);
+ while (query<args_end && isspace(*query))
+ query++;
+ if (query == args_end)
+ {
+ error="Missing query";
+ goto err;
+ }
+ pthread_mutex_lock(&lock_exec_hash);
+ if (!(e=(struct manager_exec*)hash_search(&exec_hash,ident,
+ ident_len)))
+ {
+ pthread_mutex_unlock(&lock_exec_hash);
+ error="Exec definition entry does not exist";
+ goto err;
+ }
+ pthread_mutex_unlock(&lock_exec_hash);
+ pthread_mutex_lock(&e->lock);
+ if (!e->pid)
+ {
+ error="Process is not running";
+ pthread_mutex_unlock(&e->lock);
+ goto err;
+ }
+
+ if (mysql_query(&e->mysql,query))
+ {
+ error=mysql_error(&e->mysql);
+ pthread_mutex_unlock(&e->lock);
+ goto err;
+ }
+ if ((res=mysql_store_result(&e->mysql)))
+ {
+ char buf[MAX_CLIENT_MSG_LEN],*p,*buf_end;
+ fields=mysql_fetch_fields(res);
+ num_fields=mysql_num_fields(res);
+ p=buf;
+ buf_end=buf+sizeof(buf);
+ for (i=0;i<num_fields && p<buf_end-2;i++)
+ {
+ p=arg_strmov(p,fields[i].name,buf_end-p-2);
+ *p++='\t';
+ }
+ *p=0;
+ client_msg_pre(&thd->net,MANAGER_OK,buf);
+
+ while ((row=mysql_fetch_row(res)))
+ {
+ p=buf;
+ for (i=0;i<num_fields && p<buf_end-2;i++)
+ {
+ p=arg_strmov(p,row[i],buf_end-p-2);
+ *p++='\t';
+ }
+ *p=0;
+ client_msg_pre(&thd->net,MANAGER_OK,buf);
+ }
+ }
+ pthread_mutex_unlock(&e->lock);
+ client_msg(&thd->net,MANAGER_OK,"End");
+ return 0;
+err:
+ client_msg(&thd->net,MANAGER_CLIENT_ERR,error);
+ return 1;
+}
+
+HANDLE_DECL(handle_def_exec)
+{
+ struct manager_exec* e=0,*old_e;
+ const char* error=0;
+ if (!(e=manager_exec_new(args_start,args_end)))
+ {
+ error="Out of memory";
+ goto err;
+ }
+ if (e->error)
+ {
+ error=e->error;
+ goto err;
+ }
+ pthread_mutex_lock(&lock_exec_hash);
+ if ((old_e=(struct manager_exec*)hash_search(&exec_hash,(byte*)e->ident,
+ e->ident_len)))
+ {
+ strnmov(e->stdout_path,old_e->stdout_path,sizeof(e->stdout_path));
+ strnmov(e->stderr_path,old_e->stderr_path,sizeof(e->stderr_path));
+ strnmov(e->con_user,old_e->con_user,sizeof(e->con_user));
+ strnmov(e->con_host,old_e->con_host,sizeof(e->con_host));
+ strnmov(e->con_sock,old_e->con_sock,sizeof(e->con_sock));
+ e->con_port=old_e->con_port;
+ update_req_len(e);
+ hash_delete(&exec_hash,(byte*)old_e);
+ }
+ hash_insert(&exec_hash,(byte*)e);
+ pthread_mutex_unlock(&lock_exec_hash);
+ client_msg(&thd->net,MANAGER_OK,"Exec definition created");
+ return 0;
+err:
+ client_msg(&thd->net,MANAGER_CLIENT_ERR,error);
+ if (e)
+ manager_exec_free(e);
+ return 1;
+}
+
+HANDLE_NOARG_DECL(handle_show_exec)
+{
+ uint i;
+ client_msg_pre(&thd->net,MANAGER_INFO,"Exec_def\tPid\tExit_status\tCon_info\
+\tStdout\tStderr\tArguments");
+ pthread_mutex_lock(&lock_exec_hash);
+ for (i=0;i<exec_hash.records;i++)
+ {
+ struct manager_exec* e=(struct manager_exec*)hash_element(&exec_hash,i);
+ manager_exec_print(&thd->net,e);
+ }
+ pthread_mutex_unlock(&lock_exec_hash);
+ client_msg(&thd->net,MANAGER_INFO,"End");
+ return 0;
+}
+
+static struct manager_exec* manager_exec_by_pid(pid_t pid)
+{
+ struct manager_exec* e;
+ uint i;
+ pthread_mutex_lock(&lock_exec_hash);
+ for (i=0;i<exec_hash.records;i++)
+ {
+ e=(struct manager_exec*)hash_element(&exec_hash,i);
+ if (e->pid==pid)
+ {
+ pthread_mutex_unlock(&lock_exec_hash);
+ return e;
+ }
+ }
+ pthread_mutex_unlock(&lock_exec_hash);
+ return 0;
+}
+
+static void manager_exec_connect(struct manager_exec* e)
+{
+ int i;
+ int connect_retries;
+
+ if (!(connect_retries=e->start_wait_timeout))
+ connect_retries=manager_connect_retries;
+
+ for (i=0;i<connect_retries;i++)
+ {
+ if (mysql_real_connect(&e->mysql,e->con_host,e->con_user,e->con_pass,0,
+ e->con_port,e->con_sock,0))
+ return;
+ sleep(1);
+ }
+ e->error="Could not connect to MySQL server withing the number of tries";
+}
+
+static int manager_exec_launch(struct manager_exec* e)
+{
+ if (one_thread)
+ {
+ pid_t tmp_pid;
+ switch ((tmp_pid=fork()))
+ {
+ case -1:
+ e->error="Cannot fork";
+ return 1;
+ case 0:
+ {
+ int err_code;
+ close(manager_sock);
+ err_code=execv(e->bin_path,e->args);
+ exit(err_code);
+ }
+ default:
+ e->pid=tmp_pid;
+ manager_exec_connect(e);
+ return 0;
+ }
+ }
+ else
+ {
+ if (my_write(to_launcher_pipe[1],(byte*)&e->req_len,
+ sizeof(int),MYF(MY_NABP))||
+ my_write(to_launcher_pipe[1],(byte*)&e->num_args,
+ sizeof(int),MYF(MY_NABP)) ||
+ my_write(to_launcher_pipe[1],e->stdout_path,e->stdout_path_size,
+ MYF(MY_NABP)) ||
+ my_write(to_launcher_pipe[1],e->stderr_path,e->stderr_path_size,
+ MYF(MY_NABP)) ||
+ my_write(to_launcher_pipe[1],e->data_buf,e->data_buf_size,
+ MYF(MY_NABP)))
+ {
+ e->error="Failed write request to launcher";
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static char* arg_strmov(char* dest, const char* src, int n)
+{
+ char* dest_end = dest+n-1;
+ char c;
+ for (;dest<dest_end && (c=*src++);)
+ {
+ if (c=='%')
+ *dest++='%';
+ *dest++=c;
+ }
+ return dest;
+}
+
+static void manager_exec_print(NET* net,struct manager_exec* e)
+{
+ char buf[MAX_MYSQL_MANAGER_MSG];
+ char* p=buf,*buf_end=buf+sizeof(buf)-1;
+ char** args=e->args;
+
+ p=arg_strmov(p,e->ident,(int)(buf_end-p)-1);
+ *p++='\t';
+ if (p>buf_end-15)
+ goto end;
+ p=int10_to_str(e->pid,p,10);
+ *p++='\t';
+ p=int10_to_str(e->exit_code,p,10);
+ *p++='\t';
+
+ p=arg_strmov(p,e->con_user,(int)(buf_end-p)-1);
+ *p++='@';
+ if (p==buf_end)
+ goto end;
+ p=arg_strmov(p,e->con_host,(int)(buf_end-p)-11);
+ *p++=':';
+ if (p==buf_end-10)
+ goto end;
+ if (e->con_sock[0])
+ {
+ p=arg_strmov(p,e->con_sock,(int)(buf_end-p)-1);
+ }
+ else
+ {
+ p=int10_to_str(e->con_port,p,10);
+ }
+ *p++='\t';
+ p=arg_strmov(p,e->stdout_path,(int)(buf_end-p)-1);
+ if (p==buf_end-1)
+ goto end;
+ *p++='\t';
+ p=arg_strmov(p,e->stderr_path,(int)(buf_end-p)-1);
+ if (p==buf_end-1)
+ goto end;
+ *p++='\t';
+
+ for(;p<buf_end && *args;args++)
+ {
+ p=arg_strmov(p,*args,(int)(buf_end-p)-1);
+ *p++='\t';
+ }
+end:
+ *p=0;
+ client_msg_pre(net,MANAGER_INFO,buf);
+ return;
+}
+
+static int authenticate(struct manager_thd* thd)
+{
+ char* buf_end,*buf,*p,*p_end;
+ my_MD5_CTX context;
+ uchar digest[MD5_LEN];
+ struct manager_user* u;
+ char c;
+
+ client_msg(&thd->net,MANAGER_INFO, manager_greeting);
+ if (!(buf_end=read_line(thd)))
+ return -1;
+ for (buf=thd->cmd_buf,p=thd->user,p_end=p+MAX_USER_NAME;
+ buf<buf_end && (c=*buf) && p<p_end; buf++,p++)
+ {
+ if (isspace(c))
+ {
+ *p=0;
+ break;
+ }
+ else
+ *p=c;
+ }
+ if (p==p_end || buf==buf_end)
+ return 1;
+ if (!(u=(struct manager_user*)hash_search(&user_hash,thd->user,
+ (uint)(p-thd->user))))
+ return 1;
+ for (;isspace(*buf) && buf<buf_end;buf++) /* empty */;
+
+ my_MD5Init(&context);
+ my_MD5Update(&context,(uchar*) buf,(uint)(buf_end-buf));
+ my_MD5Final(digest,&context);
+ if (memcmp(u->md5_pass,digest,MD5_LEN))
+ return 1;
+ client_msg(&thd->net,MANAGER_OK,"OK");
+ return 0;
+}
+
+static void print_time(FILE* fp)
+{
+ struct tm now;
+ time_t t;
+ time(&t);
+ localtime_r(&t,&now);
+ fprintf(fp,"[%d-%02d-%02d %02d:%02d:%02d] ", now.tm_year+1900,
+ now.tm_mon+1,now.tm_mday,now.tm_hour,now.tm_min,
+ now.tm_sec);
+}
+
+static void die(const char* fmt, ...)
+{
+ va_list args;
+ va_start(args,fmt);
+ if (fmt)
+ {
+ if (errfp==stderr)
+ fprintf(errfp, "%s: ", my_progname);
+ else
+ {
+ print_time(errfp);
+ fprintf(errfp,"Fatal error: ");
+ }
+ vfprintf(errfp, fmt, args);
+ if (errno)
+ fprintf(errfp, " errno=%d", errno);
+ fprintf(errfp, "\n");
+ fflush(errfp);
+ }
+ va_end(args);
+ clean_up();
+ exit(1);
+}
+
+void print_msg_type(int msg_type)
+{
+ const char* msg;
+ switch (msg_type)
+ {
+ case LOG_ERR: msg = "ERROR"; break;
+ case LOG_WARN: msg = "WARNING"; break;
+ case LOG_INFO: msg = "INFO"; break;
+#ifndef DBUG_OFF
+ case LOG_DEBUG: msg = "DEBUG"; break;
+#endif
+ default: msg = "UNKNOWN TYPE"; break;
+ }
+ fprintf(errfp," %s: ", msg);
+}
+
+static void log_msg(const char* fmt, int msg_type, va_list args)
+{
+ pthread_mutex_lock(&lock_log);
+ print_time(errfp);
+ print_msg_type(msg_type);
+ vfprintf(errfp,fmt,args);
+ fputc('\n',errfp);
+ fflush(errfp);
+ pthread_mutex_unlock(&lock_log);
+}
+
+static pthread_handler_decl(process_launcher_messages,
+ __attribute__((unused)) arg)
+{
+ my_thread_init();
+ for (;!in_shutdown;)
+ {
+ pid_t pid;
+ struct manager_exec* e;
+ char buf[MAX_LAUNCHER_MSG];
+ if (read(from_launcher_pipe[0],buf,MAX_LAUNCHER_MSG)<0)
+ {
+ log_err("error reading launcher message");
+ sleep(1);
+ continue;
+ }
+ switch (buf[0])
+ {
+ case CHILD_START:
+ {
+ char* ident=buf+1;
+ int ident_len=strlen(ident);
+ memcpy(&pid,ident+ident_len+1,sizeof(pid));
+ log_debug("process message - ident=%s ident_len=%d pid=%d",ident,
+ ident_len,pid);
+ pthread_mutex_lock(&lock_exec_hash);
+ log_debug("hash has %d records",exec_hash.records);
+ e=(struct manager_exec*)hash_search(&exec_hash,ident,ident_len);
+ if (e)
+ {
+ pthread_mutex_lock(&e->lock);
+ e->pid=pid;
+ pthread_cond_broadcast(&e->cond);
+ pthread_mutex_unlock(&e->lock);
+ }
+ pthread_mutex_unlock(&lock_exec_hash);
+ log_debug("unlocked mutex");
+ break;
+ }
+ case CHILD_STOP:
+ memcpy(&pid,buf+1,sizeof(pid));
+ e=manager_exec_by_pid(pid);
+ if (e)
+ {
+ pthread_mutex_lock(&e->lock);
+ e->pid=0;
+ memcpy(&e->exit_code,buf+1+sizeof(pid),sizeof(int));
+ pthread_cond_broadcast(&e->cond);
+ pthread_mutex_unlock(&e->lock);
+ }
+ break;
+ default:
+ log_err("Got invalid launcher message");
+ break;
+ }
+ }
+ return 0;
+}
+
+static pthread_handler_decl(process_connection,arg)
+{
+ struct manager_thd* thd = (struct manager_thd*)arg;
+ my_thread_init();
+ pthread_detach_this_thread();
+ for (;!thd->finished;)
+ {
+ char* buf_end;
+ if ((!(buf_end=read_line(thd)) || exec_line(thd,thd->cmd_buf,buf_end))
+ && thd->fatal)
+ {
+ log_err("Thread aborted");
+ break;
+ }
+ }
+ manager_thd_free(thd);
+ pthread_exit(0);
+ return 0; /* Don't get cc warning */
+}
+
+static int client_msg_raw(NET* net, int err_code, int pre, const char* fmt,
+ va_list args)
+{
+ char buf[MAX_CLIENT_MSG_LEN],*p,*buf_end;
+ p=buf;
+ buf_end=buf+sizeof(buf);
+ p=int10_to_str(err_code,p,10);
+ if (pre)
+ *p++='-';
+ *p++=' ';
+ p+=my_vsnprintf(p,buf_end-p,fmt,args);
+ if (p>buf_end-2)
+ p=buf_end - 2;
+ *p++='\r';
+ *p++='\n';
+ log_debug("message to client: %-.*s",p-buf-2,buf);
+ if (my_net_write(net,buf,(uint)(p-buf)) || net_flush(net))
+ {
+ p[-2]=0;
+ log_err("Failed writing '%s' to client: errno=%d",buf,errno);
+ net_end(net);
+ return 1;
+ }
+ return 0;
+}
+
+static int client_msg(NET* net, int err_code, const char* fmt, ...)
+{
+ va_list args;
+ va_start(args,fmt);
+ return client_msg_raw(net,err_code,0,fmt,args);
+}
+
+static int client_msg_pre(NET* net, int err_code, const char* fmt, ...)
+{
+ va_list args;
+ va_start(args,fmt);
+ return client_msg_raw(net,err_code,1,fmt,args);
+}
+
+static char* read_line(struct manager_thd* thd)
+{
+ int len;
+ char* p, *buf_end;
+ if ((len=my_net_read(&thd->net)) == (int)packet_error || !len)
+ {
+ log_err("Error reading command from client (Error: %d)",
+ errno);
+ thd->fatal=1;
+ return 0;
+ }
+ buf_end=thd->cmd_buf+len;
+ for (p=thd->cmd_buf;p<buf_end;p++)
+ if (*p == '\r' || *p == '\n')
+ {
+ *p=0;
+ break;
+ }
+
+ return p;
+}
+
+static void handle_child(int __attribute__((unused)) sig)
+{
+ pid_t child;
+ int child_status;
+
+ for(;(child=waitpid(-1,&child_status,WNOHANG))>0;)
+ {
+ char msg_buf[1+sizeof(int)+sizeof(int)];
+ msg_buf[0]=CHILD_STOP;
+ memcpy(msg_buf+1,&child,sizeof(int));
+ memcpy(msg_buf+1+sizeof(int),&child_status,sizeof(int));
+ if (write(from_launcher_pipe[1],msg_buf,sizeof(msg_buf))!=sizeof(msg_buf))
+ log_err("launcher: error writing message on child exit");
+ }
+ signal(SIGCHLD,handle_child);
+}
+
+struct manager_thd* manager_thd_new(Vio* vio)
+{
+ struct manager_thd* tmp;
+ if (!(tmp=(struct manager_thd*)my_malloc(sizeof(*tmp),
+ MYF(0))))
+ {
+ log_err("Out of memory in manager_thd_new");
+ return 0;
+ }
+ my_net_init(&tmp->net,vio);
+ tmp->user[0]=0;
+ tmp->priv_flags=0;
+ tmp->fatal=tmp->finished=0;
+ tmp->cmd_buf= (char*) tmp->net.read_pos;
+ return tmp;
+}
+
+static void manager_thd_free(struct manager_thd* thd)
+{
+ NET* net=&thd->net;
+ if (net->vio)
+ {
+ vio_delete(net->vio);
+ net->vio=0;
+ }
+ net_end(&thd->net);
+}
+
+static void clean_up()
+{
+ pthread_mutex_lock(&lock_shutdown);
+ if (in_shutdown)
+ {
+ pthread_mutex_unlock(&lock_shutdown);
+ return;
+ }
+ in_shutdown = 1;
+ pthread_mutex_unlock(&lock_shutdown);
+ log_info("Shutdown started");
+ if (manager_sock)
+ close(manager_sock);
+ log_info("Ended");
+ if (errfp != stderr)
+ fclose(errfp);
+ hash_free(&exec_hash);
+ if (created_pid_file)
+ my_delete(pid_file, MYF(0));
+}
+
+static void print_version(void)
+{
+ printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,MANAGER_VERSION,
+ MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
+}
+
+static void usage()
+{
+ print_version();
+ printf("MySQL AB, by Sasha\n");
+ printf("This software comes with ABSOLUTELY NO WARRANTY\n\n");
+ printf("Manages instances of MySQL server.\n\n");
+ printf("Usage: %s [OPTIONS]", my_progname);
+ printf("\n\
+ -?, --help Display this help and exit.\n");
+#ifndef DBUG_OFF
+ puts("\
+ -#, --debug=[...] Output debug log. Often this is 'd:t:o,filename`");
+#endif
+ printf("\
+ -P, --port=... Port number to listen on.\n\
+ -l, --log=... Path to log file.\n\
+ -b, --bind-address=... Address to listen on.\n\
+ -B, --tcp-backlog==... Size of TCP/IP listen queue.\n\
+ -g, --greeting= Set greeting on connect \n\
+ -m, --max-command-len Maximum command length \n\
+ -d, --one-thread Use one thread ( for debugging) \n\
+ -C, --connect-retries Number of attempts to establish MySQL connection \n\
+ -m, --max-command-len Maximum command length \n\
+ -V, --version Output version information and exit.\n\n");
+}
+
+static int parse_args(int argc, char **argv)
+{
+ int c, option_index = 0;
+ while ((c=getopt_long(argc,argv,"P:?#:Vl:b:B:g:m:dC:p:f:",
+ long_options,&option_index)) != EOF)
+ {
+ switch (c)
+ {
+ case '#':
+ DBUG_PUSH(optarg ? optarg : "d:t:O,/tmp/mysqlmgrd.trace");
+ break;
+ case 'd':
+ one_thread=1;
+ break;
+ case 'p':
+ manager_pw_file=optarg;
+ break;
+ case 'f':
+ pid_file=optarg;
+ break;
+ case 'C':
+ manager_connect_retries=atoi(optarg);
+ break;
+ case 'P':
+ manager_port=atoi(optarg);
+ break;
+ case 'm':
+ manager_max_cmd_len=atoi(optarg);
+ break;
+ case 'g':
+ manager_greeting=optarg;
+ case 'b':
+ manager_bind_addr = inet_addr(optarg);
+ break;
+ case 'B':
+ manager_back_log = atoi(optarg);
+ break;
+ case 'l':
+ manager_log_file=optarg;
+ break;
+ case 'V':
+ print_version();
+ exit(0);
+ case '?':
+ usage();
+ exit(0);
+ default:
+ usage();
+ exit(1);
+ }
+ }
+ return 0;
+}
+
+static int init_server()
+{
+ int arg=1;
+ log_info("Started");
+ if ((manager_sock=socket(PF_INET,SOCK_STREAM,0)) < 0)
+ die("Could not create socket");
+ bzero((char*)&manager_addr, sizeof(manager_addr));
+ manager_addr.sin_family = AF_INET;
+ manager_addr.sin_addr.s_addr = manager_bind_addr;
+ manager_addr.sin_port = htons(manager_port);
+ setsockopt(manager_sock,SOL_SOCKET, SO_REUSEADDR,(char*)&arg,sizeof(arg));
+ if (bind(manager_sock,(struct sockaddr*)&manager_addr, sizeof(manager_addr)) < 0)
+ die("Could not bind");
+ if (listen(manager_sock,manager_back_log) < 0)
+ die("Could not listen");
+
+ return 0;
+}
+
+static int run_server_loop()
+{
+ pthread_t th;
+ struct manager_thd *thd;
+ int client_sock;
+ Vio* vio;
+ pthread_attr_t thr_attr;
+ (void) pthread_attr_init(&thr_attr);
+#if !defined(HAVE_DEC_3_2_THREADS)
+ pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_SYSTEM);
+ (void) pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
+#endif
+
+ for (;!shutdown_requested;)
+ {
+ size_socket len=sizeof(struct sockaddr_in);
+ if ((client_sock=accept(manager_sock,(struct sockaddr*)&manager_addr,
+ &len)) <0)
+ {
+ if (shutdown_requested)
+ break;
+ if (errno != EAGAIN)
+ {
+ log_warn("Error in accept, errno=%d", errno);
+ sleep(1); /* avoid tying up CPU if accept is broken */
+ }
+ continue;
+ }
+ if (shutdown_requested)
+ break;
+ if (!(vio=vio_new(client_sock,VIO_TYPE_TCPIP,FALSE)))
+ {
+ log_err("Could not create I/O object");
+ close(client_sock);
+ continue;
+ }
+ if (!(thd=manager_thd_new(vio)))
+ {
+ log_err("Could not create thread object");
+ vio_close(vio);
+ continue;
+ }
+ if (authenticate(thd))
+ {
+ client_msg(&thd->net,MANAGER_ACCESS, "Access denied");
+ manager_thd_free(thd);
+ log_info("Client failed to authenticate");
+ continue;
+ }
+ if (shutdown_requested)
+ {
+ manager_thd_free(thd);
+ break;
+ }
+ if (one_thread)
+ {
+ process_connection((void*)thd);
+ manager_thd_free(thd);
+ continue;
+ }
+ else if (pthread_create(&th,&thr_attr,process_connection,(void*)thd))
+ {
+ client_msg(&thd->net,MANAGER_INTERNAL_ERR,
+ "Could not create thread, errno=%d",
+ errno);
+ manager_thd_free(thd);
+ continue;
+ }
+ }
+ (void) pthread_attr_destroy(&thr_attr);
+ return 0;
+}
+
+static FILE* open_log_stream()
+{
+ FILE* fp;
+ if (!(fp=fopen(manager_log_file,"a")))
+ die("Could not open log file '%s'", manager_log_file);
+ return fp;
+}
+
+static byte* get_user_key(const byte* u, uint* len,
+ my_bool __attribute__((unused)) t)
+{
+ register const char* key;
+ key = ((struct manager_user*)u)->user;
+ *len = ((struct manager_user*)u)->user_len;
+ return (byte*)key;
+}
+
+static byte* get_exec_key(const byte* e, uint* len,
+ my_bool __attribute__((unused)) t)
+{
+ register const char* key;
+ key = ((struct manager_exec*)e)->ident;
+ *len = ((struct manager_exec*)e)->ident_len;
+ return (byte*)key;
+}
+
+static void init_arg_array(char* arg_str,char** args,uint arg_count)
+{
+ char* p = arg_str;
+ for (;arg_count>0;arg_count--)
+ {
+ *args++=p;
+ p += strlen(p)+1;
+ }
+ *args=0;
+}
+
+static uint tokenize_args(char* arg_start,char** arg_end)
+{
+ char* p, *p_write,*p_end;
+ uint arg_count=0;
+ int quoted=0,escaped=0,last_space=0;
+ p_end=*arg_end;
+ p_write=p=arg_start;
+ for(;p<p_end;p++)
+ {
+ char c = *p;
+ switch (c)
+ {
+ case ' ':
+ case '\r':
+ case '\n':
+ if (!quoted)
+ {
+ if (!last_space)
+ {
+ *p_write++=0;
+ arg_count++;
+ last_space=1;
+ }
+ }
+ else
+ *p_write++=c;
+ escaped=0;
+ break;
+ case '"':
+ if (!escaped)
+ quoted=!quoted;
+ else
+ *p_write++=c;
+ last_space=0;
+ escaped=0;
+ break;
+ case '\\':
+ if (!escaped)
+ escaped=1;
+ else
+ {
+ *p_write++=c;
+ escaped=0;
+ }
+ last_space=0;
+ break;
+ default:
+ escaped=last_space=0;
+ *p_write++=c;
+ break;
+ }
+ }
+ if (!last_space && p_write>arg_start)
+ arg_count++;
+ *p_write=0;
+ *arg_end=p_write;
+ log_debug("arg_count=%d,arg_start='%s'",arg_count,arg_start);
+ return arg_count;
+}
+
+static void update_req_len(struct manager_exec* e)
+{
+ e->req_len=e->data_buf_size+
+ (e->stdout_path_size=strlen(e->stdout_path)+1)+
+ (e->stderr_path_size=strlen(e->stderr_path)+1);
+ }
+
+static struct manager_exec* manager_exec_new(char* arg_start,char* arg_end)
+{
+ struct manager_exec* tmp;
+ char* first_arg;
+ uint arg_len,num_args;
+ num_args=tokenize_args(arg_start,&arg_end);
+ arg_len=(uint)(arg_end-arg_start)+1; /* include \0 terminator*/
+ if (!(tmp=(struct manager_exec*)my_malloc(sizeof(*tmp)+arg_len+
+ sizeof(char*)*num_args,
+ MYF(MY_ZEROFILL))))
+ return 0;
+ if (num_args<2)
+ {
+ tmp->error="Too few arguments";
+ return tmp;
+ }
+ /* We have to allocate 'args' first as this must be alligned */
+ tmp->args=(char**)(tmp +1);
+ tmp->data_buf= (char*) (tmp->args + num_args);
+ memcpy(tmp->data_buf,arg_start,arg_len);
+ tmp->data_buf_size=arg_len;
+ tmp->num_args=num_args;
+ tmp->ident=tmp->data_buf;
+ tmp->ident_len=strlen(tmp->ident);
+ first_arg=tmp->ident+tmp->ident_len+1;
+ init_arg_array(first_arg,tmp->args,num_args-1);
+ strmov(tmp->con_user,"root");
+ tmp->con_port=MYSQL_PORT;
+ memcpy(tmp->con_host,"localhost",10);
+ tmp->bin_path=tmp->args[0];
+ tmp->stdout_path_size=tmp->stderr_path_size=1;
+ tmp->req_len=tmp->data_buf_size+2;
+ pthread_mutex_init(&tmp->lock,0);
+ pthread_cond_init(&tmp->cond,0);
+ mysql_init(&tmp->mysql);
+ return tmp;
+}
+
+static void manager_exec_free(void* e)
+{
+ mysql_close(&((struct manager_exec*)e)->mysql);
+ my_free(e,MYF(0));
+}
+
+static int hex_val(char c)
+{
+ if (isdigit(c))
+ return c-'0';
+ c=tolower(c);
+ return c-'a'+10;
+}
+
+static struct manager_user* manager_user_new(char* buf)
+{
+ struct manager_user* tmp;
+ char* p,*user_end,*p_end;
+ char c;
+ if (!(tmp=(struct manager_user*)my_malloc(sizeof(*tmp),MYF(0))))
+ return 0;
+ p=tmp->user;
+ tmp->error=0;
+ user_end=p+MAX_USER_NAME;
+ for (;(c=*buf) && p<user_end;buf++)
+ {
+ if (c == ':')
+ {
+ *p=0;
+ tmp->user_len=p-tmp->user;
+ buf++;
+ break;
+ }
+ else
+ *p++=c;
+ }
+ if (!c)
+ tmp->error="Missing ':'";
+ if (p == user_end)
+ tmp->error="Username too long";
+ if (tmp->error)
+ return tmp;
+ if (strlen(buf) < 2*MD5_LEN)
+ {
+ tmp->error="Invalid MD5 sum, too short";
+ return tmp;
+ }
+ p=tmp->md5_pass;
+ p_end=p+MD5_LEN;
+ for (; p<p_end;p++,buf+=2)
+ {
+ *p=hex_val(*buf)*16+hex_val(buf[1]);
+ }
+
+ return tmp;
+}
+
+static void manager_user_free(void* u)
+{
+ my_free((gptr)u,MYF(0));
+}
+
+static void init_user_hash()
+{
+ FILE* f;
+ char buf[80];
+ int line_num=1;
+ if (hash_init(&user_hash,1024,0,0,get_user_key,manager_user_free,MYF(0)))
+ die("Could not initialize user hash");
+ if (!(f=fopen(manager_pw_file,"r")))
+ die("Could not open password file '%s'", manager_pw_file);
+ for (;;line_num++)
+ {
+ struct manager_user* u;
+ if (!fgets(buf,sizeof(buf),f) || feof(f))
+ break;
+ if (buf[0] == '#')
+ continue;
+ if (!(u=manager_user_new(buf)))
+ die("Out of memory while reading user line");
+ if (u->error)
+ {
+ die("Error on line %d of '%s': %s",line_num,manager_pw_file, u->error);
+ }
+ else
+ {
+ hash_insert(&user_hash,(gptr)u);
+ }
+ }
+ fclose(f);
+}
+
+static void init_pid_file()
+{
+ FILE* fp = fopen(pid_file, "w");
+ if (!fp)
+ die("Could not open pid file %s", pid_file);
+ created_pid_file=1;
+ fprintf(fp, "%d\n", (int) getpid());
+ fclose(fp);
+}
+
+static void init_globals()
+{
+ pthread_attr_t thr_attr;
+ if (hash_init(&exec_hash,1024,0,0,get_exec_key,manager_exec_free,MYF(0)))
+ die("Exec hash initialization failed");
+ if (!one_thread)
+ {
+ (void) pthread_attr_init(&thr_attr);
+#if !defined(HAVE_DEC_3_2_THREADS)
+ pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_SYSTEM);
+ (void) pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
+#endif
+ fork_launcher();
+ if (pthread_create(&launch_msg_th,&thr_attr,process_launcher_messages,0))
+ die("Could not start launcher message handler thread");
+ /* (void) pthread_attr_destroy(&thr_attr); */
+ }
+ init_user_hash();
+ init_pid_file();
+ loop_th=pthread_self();
+ signal(SIGPIPE,handle_sigpipe);
+ signal(SIGTERM,handle_sigterm);
+}
+
+static int open_and_dup(int fd,char* path)
+{
+ int old_fd;
+ if ((old_fd=my_open(path,O_WRONLY|O_APPEND|O_CREAT,MYF(0)))<0)
+ {
+ log_err("Could not open '%s' for append, errno=%d",path,errno);
+ return 1;
+ }
+ if (dup2(old_fd,fd)<0)
+ {
+ log_err("Failed in dup2(), errno=%d",errno);
+ return 1;
+ }
+ my_close(old_fd,MYF(0));
+ return 0;
+}
+
+static void run_launcher_loop()
+{
+ for (;;)
+ {
+ int req_len,ident_len,num_args;
+ char* request_buf=0;
+ pid_t pid;
+ char* exec_path,*ident,*stdout_path,*stderr_path;
+ char** args=0;
+
+ if (my_read(to_launcher_pipe[0],(byte*)&req_len,
+ sizeof(int),MYF(MY_NABP|MY_FULL_IO)) ||
+ my_read(to_launcher_pipe[0],(byte*)&num_args,
+ sizeof(int),MYF(MY_NABP|MY_FULL_IO)) ||
+ !(request_buf=(char*)my_malloc(req_len+sizeof(pid)+2,MYF(0))) ||
+ !(args=(char**)my_malloc(num_args*sizeof(char*),MYF(0))) ||
+ my_read(to_launcher_pipe[0],request_buf,req_len,
+ MYF(MY_NABP|MY_FULL_IO)))
+ {
+ log_err("launcher: Error reading request");
+ my_free((gptr)request_buf,MYF(MY_ALLOW_ZERO_PTR));
+ my_free((gptr)args,MYF(MY_ALLOW_ZERO_PTR));
+ sleep(1);
+ continue;
+ }
+ stdout_path=request_buf;
+ stderr_path=stdout_path+strlen(stdout_path)+1;
+ request_buf=stderr_path+strlen(stderr_path); /* black magic */
+ ident=request_buf+1;
+ ident_len=strlen(ident);
+ exec_path=ident+ident_len+1;
+ log_debug("num_args=%d,req_len=%d,ident=%s,ident_len=%d,exec_path=%s,\
+stdout_path=%s,stderr_path=%s",
+ num_args,
+ req_len,ident,ident_len,exec_path,stdout_path,stderr_path);
+ init_arg_array(exec_path,args,num_args-1);
+
+ switch ((pid=fork()))
+ {
+ case -1:
+ log_err("launcher: cannot fork");
+ sleep(1);
+ break;
+ case 0:
+ if (open_and_dup(1,stdout_path) || open_and_dup(2,stderr_path))
+ exit(1);
+ if (execv(exec_path,args))
+ log_err("launcher: cannot exec %s",exec_path);
+ exit(1);
+ default:
+ request_buf[0]=CHILD_START;
+ memcpy(request_buf+ident_len+2,&pid,sizeof(pid));
+ if (write(from_launcher_pipe[1],request_buf,ident_len+2+sizeof(pid))<0)
+ log_err("launcher: error sending launch status report");
+ break;
+ }
+ my_free((gptr)(stdout_path),MYF(0));
+ my_free((gptr)args,MYF(0));
+ }
+}
+
+static void fork_launcher()
+{
+ if (pipe(to_launcher_pipe) || pipe(from_launcher_pipe))
+ die("Could not create launcher pipes");
+ switch ((launcher_pid=fork()))
+ {
+ case 0:
+ signal(SIGCHLD,handle_child);
+ run_launcher_loop();
+ exit(0);
+ case -1: die("Could not fork the launcher");
+ default: return;
+ }
+}
+
+static int daemonize()
+{
+ switch (fork())
+ {
+ case -1:
+ die("Cannot fork");
+ case 0:
+ errfp = open_log_stream();
+ init_globals();
+ close(0);
+ close(1);
+ close(2);
+ init_server();
+ run_server_loop();
+ clean_up();
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+int main(int argc, char** argv)
+{
+ char c;
+ stack_bottom= (uchar *) &c;
+ MY_INIT(argv[0]);
+ errfp = stderr;
+ parse_args(argc,argv);
+ pthread_mutex_init(&lock_log,0);
+ pthread_mutex_init(&lock_shutdown,0);
+ pthread_mutex_init(&lock_exec_hash,0);
+ pthread_mutex_init(&lock_launch_thd,0);
+ pthread_cond_init(&cond_launch_thd,0);
+#ifdef DO_STACKTRACE
+ signal(SIGSEGV,handle_segfault);
+#endif
+ if (one_thread)
+ {
+ init_globals();
+ init_server();
+ run_server_loop();
+ clean_up();
+ return 0;
+ }
+ else
+ return daemonize();
+}
diff --git a/vio/Makefile.am b/vio/Makefile.am
index 9bb8691eee6..7119c278862 100644
--- a/vio/Makefile.am
+++ b/vio/Makefile.am
@@ -14,20 +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
-INCLUDES = -I$(srcdir)/../include -I../include \
- @OPENSSL_INCLUDES@
-LDADD = libvio.la
-pkglib_LTLIBRARIES = libvio.la
-noinst_PROGRAMS =
+INCLUDES = -I$(srcdir)/../include -I../include $(openssl_includes)
+LDADD = libvio.a $(openssl_libs)
+pkglib_LIBRARIES = libvio.a
+noinst_PROGRAMS = test-ssl test-sslserver test-sslclient
noinst_HEADERS =
-libvio_la_SOURCES = \
- Vio.cc VioAcceptorFd.cc \
- VioConnectorFd.cc VioFd.cc \
- VioHandle.cc VioSSL.cc \
- VioSSLFactoriesFd.cc VioSocket.cc \
- auto.cc hostnamexx.cc \
- vdbug.cc version.cc \
- vmem.cc violitexx.cc
+test_ssl_SOURCES = test-ssl.c
+test_ssl_LDADD = ../dbug/libdbug.a libvio.a ../mysys/libmysys.a \
+ ../strings/libmystrings.a libvio.a $(openssl_libs)
+test_sslserver_SOURCES = test-sslserver.c
+test_sslserver_LDADD = ../dbug/libdbug.a libvio.a ../mysys/libmysys.a \
+ ../strings/libmystrings.a libvio.a $(openssl_libs)
+test_sslclient_SOURCES = test-sslclient.c
+test_sslclient_LDADD = ../dbug/libdbug.a libvio.a ../mysys/libmysys.a \
+ ../strings/libmystrings.a libvio.a $(openssl_libs)
+libvio_a_SOURCES = vio.c viosocket.c viossl.c viosslfactories.c
OMIT_DEPENDENCIES = pthread.h stdio.h __stdio.h stdlib.h __stdlib.h math.h\
__math.h time.h __time.h unistd.h __unistd.h types.h \
diff --git a/vio/Vio.cc b/vio/Vio.cc
deleted file mode 100644
index b15f9cfa6d2..00000000000
--- a/vio/Vio.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
-** Virtual I/O library
-** Written by Andrei Errapart <andreie@no.spam.ee>
-*/
-
-#ifdef __GNUC__
-#pragma implementation // gcc: Class implementation
-#endif
-#include "vio-global.h"
-
-VIO_NS_BEGIN
-
-void
-Vio::release()
-{
- delete this;
-}
-
-Vio::~Vio()
-{
-}
-
-VIO_NS_END
diff --git a/vio/Vio.h b/vio/Vio.h
deleted file mode 100644
index 959d472873f..00000000000
--- a/vio/Vio.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Abstract Virtual IO interface - class Vio. Heavily
- * influenced by Berkeley sockets and oriented toward MySQL.
- */
-
-/*
-** Virtual I/O library
-** Written by Andrei Errapart <andreie@no.spam.ee>
-** Modified by Monty
-*/
-
-#ifdef __GNUC__
-#pragma interface /* gcc class implementation */
-#endif
-
-VIO_NS_BEGIN
-
-enum enum_vio_type { VIO_CLOSED, VIO_TYPE_TCPIP, VIO_TYPE_SOCKET,
- VIO_TYPE_NAMEDPIPE, VIO_TYPE_SSL};
-
-class Vio {
-public:
- virtual bool is_open() const = 0;
- virtual int read(vio_ptr buf, int size) = 0;
- virtual int write(const vio_ptr buf, int size) = 0;
- virtual int blocking(bool onoff) = 0;
- virtual bool blocking() const = 0;
- virtual bool fcntl() const = 0;
- virtual int fastsend(bool onoff = true) = 0;
- virtual int keepalive(bool onoff) = 0;
- virtual bool should_retry() const = 0;
- virtual int close() = 0;
- virtual void release();
- virtual const char* description() const = 0;
- virtual bool peer_addr(char *buf) const = 0;
- virtual const char* cipher_description() const = 0;
- virtual int vio_errno();
- virtual ~Vio();
-};
-
-/* Macros to simulate the violite C interface */
-
-
-Vio *vio_new(my_socket sd, enum enum_vio_type type,
- my_bool localhost);
-#ifdef __WIN__
-Vio* vio_new_win32pipe(HANDLE hPipe);
-#endif
-
-#define vio_delete(vio) delete vio
-#define vio_read(vio,buf,size) vio->read(buf,size)
-#define vio_write(vio,buf,size) vio->write(buf,size)
-#define vio_blocking(vio,mode) vio->blocking(mode)
-#define vio_is_blocking(vio) vio->is_blocking()
-#define vio_fastsend(vio,mode) vio->fastsend(mode)
-#define vio_keepalive(vio,mode) vio->keepalive(mode)
-#define vio_shouldretry(vio) vio->shouldretry(mode)
-#define vio_close(vio) vio->close()
-#define vio_description(vio) vio->description()
-#define vio_errno(Vio *vio) vio->errno()
-#define vio_peer_addr(vio,buf) vio->peer_addr(buf)
-#define vio_in_addr(vio,in) vio->in_addr(in)
-
-VIO_NS_END
diff --git a/vio/VioAcceptorFd.cc b/vio/VioAcceptorFd.cc
deleted file mode 100644
index 4572e2cb71b..00000000000
--- a/vio/VioAcceptorFd.cc
+++ /dev/null
@@ -1,18 +0,0 @@
-
-/*
-** Virtual I/O library
-** Written by Andrei Errapart <andreie@no.spam.ee>
-*/
-
-#include "vio-global.h"
-#ifdef __GNUC__
-#pragma implementation // gcc: Class implementation
-#endif
-
-VIO_NS_BEGIN
-
-VioAcceptorFd::~VioAcceptorFd()
-{
-}
-
-VIO_NS_END
diff --git a/vio/VioAcceptorFd.h b/vio/VioAcceptorFd.h
deleted file mode 100644
index e0441780db9..00000000000
--- a/vio/VioAcceptorFd.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
-** Virtual I/O library
-** Written by Andrei Errapart <andreie@no.spam.ee>
-*/
-
-/*
- * Abstract acceptor.
- */
-
-#ifdef __GNUC__
-#pragma interface /* gcc class implementation */
-#endif
-
-VIO_NS_BEGIN
-
-class VioAcceptorFd
-{
-public:
- virtual ~VioAcceptorFd();
- virtual Vio* accept( int fd) = 0;
-};
-
-VIO_NS_END
diff --git a/vio/VioConnectorFd.cc b/vio/VioConnectorFd.cc
deleted file mode 100644
index 49f81077a84..00000000000
--- a/vio/VioConnectorFd.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-
-/*
- * Unneccessary virtual destructor.
- */
-
-#include "vio-global.h"
-#include <unistd.h>
-#include <fcntl.h>
-#include <assert.h>
-
-#include "viotypes.h"
-#include "Vio.h"
-#include "VioConnectorFd.h"
-
-VIO_NS_BEGIN
-
-VioConnectorFd::~VioConnectorFd()
-{
-}
-
-VIO_NS_END
-
diff --git a/vio/VioConnectorFd.h b/vio/VioConnectorFd.h
deleted file mode 100644
index da684df5f1b..00000000000
--- a/vio/VioConnectorFd.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Abstract connector. The file (or socket) descriptor has to be
- * prepared.
- */
-
-#ifdef __GNUC__
-#pragma interface /* gcc class implementation */
-#endif
-
-VIO_NS_BEGIN
-
-class VioConnectorFd
-{
-public:
- virtual ~VioConnectorFd();
- virtual Vio* connect(int fd) = 0;
-};
-
-VIO_NS_END
diff --git a/vio/VioFd.cc b/vio/VioFd.cc
deleted file mode 100644
index da59798fc25..00000000000
--- a/vio/VioFd.cc
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
-** Virtual I/O library for files
-** Written by Andrei Errapart <andreie@no.spam.ee>
-** Checked and modfied by Monty
-*/
-
-#include "vio-global.h"
-#include <assert.h>
-
-#ifdef __GNUC__
-#pragma implementation // gcc: Class implementation
-#endif
-
-VIO_NS_BEGIN
-
-VioFd::VioFd( int fd) : fd_(fd)
-{
- sprintf(desc_, "VioFd(%d)", fd_);
-}
-
-VioFd:: ~VioFd()
-{
- if (fd_ >= 0)
- {
- it r = ::close(fd_);
- if ( r < 0)
- {
- /* FIXME: error handling (Not Critical for MySQL) */
- }
- }
-}
-
-
-bool
-VioFd::open() const
-{
- return fd_ >= 0;
-}
-
-int
-VioFd::read(vio_ptr buf, int size)
-{
- assert(fd_>=0);
- return ::read(fd_, buf, size);
-}
-
-int
-VioFd::write(const vio_ptr buf, int size)
-{
- assert(fd_>=0);
- return ::write(fd_, buf, size);
-}
-
-int
-VioFd::blocking(bool onoff)
-{
- if (onoff)
- return 0;
- else
- return -1;
-}
-
-bool
-VioFd::blocking() const
-{
- return true;
-}
-
-int
-VioFd::fastsend(bool tmp)
-{
- return 0;
-}
-
-
-int
-VioFd::keepalive(boolonoff)
-{
- return -2; // Why -2 ? (monty)
-}
-
-bool
-VioFd::fcntl() const
-{
- return FALSE;
-}
-
-bool
-VioFd::should_retry() const
-{
- return FALSE;
-}
-
-int
-VioFd::fcntl(int cmd)
-{
- assert(fd_>=0);
- return ::fcntl(fd_, cmd);
-}
-
-int
-VioFd::fcntl(int cmd, long arg)
-{
- assert(fd_>=0);
- return ::fcntl(fd_, cmd, arg);
-}
-
-int
-VioFd::fcntl(int cmd, struct flock* lock)
-{
- assert(fd_>=0);
- return ::fcntl(fd_, cmd, lock);
-}
-
-int
-VioFd::close()
-{
- int r = -2;
- if (fd_>=0)
- {
-
- if ((r= ::close(fd_)) == 0)
- fd_ = -1;
- }
- else
- {
- /* FIXME: error handling */
- }
- return r;
-}
-
-const char*
-VioFd::description() const
-{
- return desc_;
-}
-
-const char*
-VioFd::peer_addr() const
-{
- return "";
-}
-
-const char*
-VioFd::peer_name() const
-{
- return "localhost";
-}
-
-const char*
-VioFd::cipher_description() const
-{
- return "";
-}
-
-VIO_NS_END
diff --git a/vio/VioFd.h b/vio/VioFd.h
deleted file mode 100644
index f1c009d848c..00000000000
--- a/vio/VioFd.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Concrete Vio around a file descriptor.
- */
-
-#ifdef __GNUC__
-#pragma interface /* gcc class implementation */
-#endif
-
-VIO_NS_BEGIN
-
-class VioFd : public Vio
-{
-public:
- VioFd( int fd);
- virtual ~VioFd();
- virtual bool open() const;
- virtual int read( vio_ptr buf, int size);
- virtual int write( const vio_ptr buf, int size);
- virtual bool blocking() const;
- virtual int blocking(bool onoff);
- virtual int fastsend(bool onoff=true);
- virtual int keepalive( bool onoff);
- virtual bool fcntl() const;
- virtual bool should_retry() const;
- virtual int fcntl( int cmd);
- virtual int fcntl( int cmd, long arg);
- virtual int fcntl( int cmd, struct flock* lock);
- virtual int close();
- virtual const char* description() const;
- virtual const char* peer_addr() const;
- virtual bool peer_name(char *buf) const;
- virtual const char* cipher_description() const;
-private:
- int fd_;
- char desc_[100];
-};
-
-VIO_NS_END
diff --git a/vio/VioPipe.cc b/vio/VioPipe.cc
deleted file mode 100644
index 5d6f9f36496..00000000000
--- a/vio/VioPipe.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
-** Virtual I/O library for Windows named pipes
-** Written by Monty
-*/
-
-
-#ifdef __WIN32__
-#include "vio-global.h"
-
-#ifdef __GNUC__
-#pragma implementation // gcc: Class implementation
-#endif
-
-VIO_NS_BEGIN
-
-
-
-
-
-
-
-
-VIO_NS_END
-
-#endif /* WIN32 */
diff --git a/vio/VioPipe.h b/vio/VioPipe.h
deleted file mode 100644
index a6bb587c548..00000000000
--- a/vio/VioPipe.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Concrete Vio around Handle.
- */
-
-#ifdef __WIN__
-
-#ifdef __GNUC__
-#pragma interface /* gcc class implementation */
-#endif
-
-VIO_NS_BEGIN
-
-class VioPipe : public Vio
-{
-public:
- VioPipe(int fd);
- virtual ~VioPipe();
- virtual bool is_open() const;
- virtual int read(vio_ptr buf, int size);
- virtual int write(const vio_ptr buf, int size);
- virtual int blocking(bool onoff);
- virtual bool blocking() const;
- virtual bool fcntl() const;
- virtual int fastsend(bool onoff = true);
- virtual int keepalive(bool onoff);
- virtual bool should_retry() const;
- virtual int close();
- virtual void release();
- virtual const char* description() const;
- virtual bool peer_addr(char *buf) const;
- virtual const char* cipher_description() const { return "";}
- virtual int vio_errno();
-private:
-};
-
-VIO_NS_END
-
-#endif /* WIN32 */
diff --git a/vio/VioSSL.cc b/vio/VioSSL.cc
deleted file mode 100644
index 15964c09aba..00000000000
--- a/vio/VioSSL.cc
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
-** Virtual I/O library for SSL wrapper
-** Written by Andrei Errapart <andreie@no.spam.ee>
-*/
-
-/*
- * This file has some huge DBUG_ statements. Boy, this is silly...
- */
-
-#include "vio-global.h"
-#ifdef VIO_HAVE_OPENSSL
-#include <assert.h>
-#include <netinet/in.h>
-#include <openssl/x509.h>
-#include <openssl/ssl.h>
-#include <openssl/err.h>
-#include <openssl/pem.h>
-
-#ifdef __GNUC__
-#pragma implementation // gcc: Class implementation
-#endif
-
-VIO_NS_BEGIN
-
-#define this_ssl_con my_static_cast(SSL*)(this->ssl_con_)
-#define this_bio my_static_cast(BIO*)(this->bio_)
-typedef char* dataptr_t;
-
-static void
-report_errors()
-{
- unsigned long l;
- const char* file;
- const char* data;
- int line,flags;
- DBUG_ENTER("VioSSLConnectorFd::report_errors");
-
- while ((l=ERR_get_error_line_data(&file,&line,&data,&flags)) != 0)
- {
- char buf[200];
- DBUG_PRINT("error", ("OpenSSL: %s:%s:%d:%s\n", ERR_error_string(l,buf),
- file,line,(flags&ERR_TXT_STRING)?data:"")) ;
- }
- DBUG_VOID_RETURN;
-}
-
-//FIXME: duplicate code!
-VioSSL::VioSSL(int fd,
- vio_ptr ssl_context,
- int state)
- : bio_(0), ssl_con_(0), open_(FALSE), sd_(new VioSocket(fd))
-{
- DBUG_ENTER("VioSSL::VioSSL");
- DBUG_PRINT("enter", ("this=%p, fd=%d, ssl_context=%p, state=%d",
- this, fd, ssl_context, state));
- assert(fd!=0);
- assert(ssl_context!=0);
- assert(state==state_connect || state==state_accept);
-
- if (!init_bio_(fd, ssl_context, state, BIO_NOCLOSE))
- open_ = true;
- DBUG_VOID_RETURN;
-}
-
-
-VioSSL::VioSSL(VioSocket* sd,
- vio_ptr ssl_context,
- int state)
- :bio_(0), ssl_con_(0), open_(FALSE), sd_(sd)
-{
- DBUG_ENTER("VioSSL::VioSSL");
- DBUG_PRINT("enter",
- ("this=%p, sd=%s, ssl_context=%p, state=%d",
- this, sd ? sd->description() : "0", ssl_context, state));
- assert(sd != 0);
- assert(ssl_context != 0);
- assert(state == state_connect || state==state_accept);
-
- if (!init_bio_(sd->sd_, ssl_context, state, BIO_NOCLOSE))
- open_ = true;
- DBUG_VOID_RETURN;
-}
-
-VioSSL::~VioSSL()
-{
- DBUG_ENTER("VioSSL::~VioSSL");
- DBUG_PRINT("enter", ("this=%p", this));
- if (ssl_con_!=0)
- {
- SSL_shutdown(this_ssl_con);
- SSL_free(this_ssl_con);
- }
- if (sd_!=0)
- delete sd_;
- /* FIXME: no need to close bio? */
- /*
- if (bio_!=0)
- BIO_free(this_bio);
- */
- DBUG_VOID_RETURN;
-}
-
-bool
-VioSSL::is_open() const
-{
- return open_;
-}
-
-int
-VioSSL::read(vio_ptr buf, int size)
-{
- int r;
- DBUG_ENTER("VioSSL::read");
- DBUG_PRINT("enter", ("this=%p, buf=%p, size=%d", this, buf, size));
- assert(this_ssl_con != 0);
- r = SSL_read(this_ssl_con, my_static_cast(dataptr_t)(buf), size);
- if ( r< 0)
- report_errors();
- DBUG_PRINT("exit", ("r=%d", r));
- DBUG_RETURN(r);
-}
-
-int
-VioSSL::write(const vio_ptr buf, int size)
-{
- int r;
- DBUG_ENTER("VioSSL::write");
- DBUG_PRINT("enter", ("this=%p, buf=%p, size=%d", this, buf, size));
- assert(this_ssl_con!=0);
- r = SSL_write(this_ssl_con, my_static_cast(dataptr_t)(buf), size);
- if (r<0)
- report_errors();
- DBUG_PRINT("exit", ("r=%d", r));
- DBUG_RETURN(r);
-}
-
-int
-VioSSL::blocking(bool onoff)
-{
- int r;
- DBUG_ENTER("VioSSL::blocking");
- DBUG_PRINT("enter", ("this=%p, onoff=%s", this, onoff?"true":"false"));
- r = sd_->blocking(onoff);
- DBUG_PRINT("exit", ("r=%d", (int)r ));
- DBUG_RETURN(r);
-}
-
-bool
-VioSSL::blocking() const
-{
- bool r;
- DBUG_ENTER("VioSSL::blocking");
- DBUG_PRINT("enter", ("this=%p", this));
- r = sd_->blocking();
- DBUG_PRINT("exit", ("r=%d", (int)r ));
- DBUG_RETURN(r);
-}
-
-int
-VioSSL::fastsend(bool onoff)
-{
- int r;
- DBUG_ENTER("VioSSL::fastsend");
- DBUG_PRINT("enter", ("this=%p, onoff=%d", this, (int) onoff));
- r = sd_->fastsend(onoff);
- DBUG_PRINT("exit", ("r=%d", (int)r ));
- DBUG_RETURN(r);
-}
-
-int VioSSL::keepalive(bool onoff)
-{
- int r;
- DBUG_ENTER("VioSSL::keepalive");
- DBUG_PRINT("enter", ("this=%p, onoff=%d", this, (int) onoff));
- r = sd_->keepalive(onoff);
- DBUG_PRINT("exit", ("r=%d", int(r) ));
- DBUG_RETURN(r);
-}
-
-bool
-VioSSL::fcntl() const
-{
- bool r;
- DBUG_ENTER("VioSSL::fcntl");
- DBUG_PRINT("enter", ("this=%p", this));
- r = sd_->fcntl();
- DBUG_PRINT("exit", ("r=%d", (int)r ));
- DBUG_RETURN(r);
-}
-
-bool
-VioSSL::should_retry() const
-{
- bool r;
- DBUG_ENTER("VioSSL::should_retry");
- DBUG_PRINT("enter", ("this=%p", this));
- r = sd_->should_retry();
- DBUG_PRINT("exit", ("r=%d", (int)r ));
- DBUG_RETURN(r);
-}
-
-int
-VioSSL::close()
-{
- int r= -2;
- DBUG_ENTER("VioSSL::close");
- DBUG_PRINT("enter", ("this=%p", this));
- if (ssl_con)
- {
- r = SSL_shutdown(this_ssl_con);
- SSL_free(this_ssl_con);
- ssl_con_ = 0;
- BIO_free(this_bio);
- bio_ = 0;
- }
- DBUG_PRINT("exit", ("r=%d", r));
- DBUG_RETURN(r);
-}
-
-const char*
-VioSSL::description() const
-{
- return desc_;
-}
-
-const char*
-VioSSL::peer_addr() const
-{
- if (sd_!=0)
- return sd != 0 ? sd_->peer_addr() : "";
-}
-
-const char*
-VioSSL::peer_name() const
-{
- return sd != 0 ? sd_->peer_name() : "";
-}
-
-const char*
-VioSSL::cipher_description() const
-{
- return SSL_get_cipher_name(this_ssl_con);
-}
-
-
-int
-VioSSL::init_bio_(int fd,
- vio_ptr ssl_context,
- int state,
- int bio_flags)
-{
- DBUG_ENTER("VioSSL::init_bio_");
- DBUG_PRINT("enter",
- ("this=%p, fd=%p, ssl_context=%p, state=%d, bio_flags=%d",
- this, fd, ssl_context, state, bio_flags));
-
-
- if (!(ssl_con_ = SSL_new(my_static_cast(SSL_CTX*)(ssl_context))))
- {
- DBUG_PRINT("error", ("SSL_new failure"));
- report_errors();
- DBUG_RETURN(-1);
- }
- if (!(bio_ = BIO_new_socket(fd, bio_flags)))
- {
- DBUG_PRINT("error", ("BIO_new_socket failure"));
- report_errors();
- SSL_free(ssl_con_);
- ssl_con_ =0;
- DBUG_RETURN(-1);
- }
- SSL_set_bio(this_ssl_con, this_bio, this_bio);
- switch(state) {
- case state_connect:
- SSL_set_connect_state(this_ssl_con);
- break;
- case state_accept:
- SSL_set_accept_state(this_ssl_con);
- break;
- default:
- assert(0);
- }
- sprintf(desc_, "VioSSL(%d)", fd);
- ssl_cip_ = new SSL_CIPHER ;
- DBUG_RETURN(0);
-}
-
-
-VIO_NS_END
-
-#endif /* VIO_HAVE_OPENSSL */
-
diff --git a/vio/VioSSL.h b/vio/VioSSL.h
deleted file mode 100644
index 6446c10700e..00000000000
--- a/vio/VioSSL.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Concrete Vio around OpenSSL's SSL structure.
- */
-
-#ifdef __GNUC__
-#pragma interface /* gcc class implementation */
-#endif
-
-VIO_NS_BEGIN
-
-class VioSocket;
-
-class VioSSL : public Vio
-{
-public:
- enum {
- state_connect = 1,
- state_accept = 2
- };
-public:
- VioSSL(int fd, vio_ptr ssl_context, int state);
- VioSSL(VioSocket* sd, vio_ptr ssl_context, int state);
- virtual ~VioSSL();
- virtual bool open() const;
- virtual int read( vio_ptr buf, int size);
- virtual int write( const vio_ptr buf, int size);
- virtual bool blocking() const;
- virtual int blocking(bool onoff);
- virtual int fastsend(bool onoff=true);
- virtual int keepalive(bool onoff);
- virtual bool fcntl() const;
- virtual bool should_retry() const;
- virtual int close();
- virtual const char* description() const;
- virtual const char* peer_addr() const;
- virtual const char* peer_name() const;
- virtual const char* cipher_description() const;
-
-private:
- int init_bio_(int fd,
- vio_ptr ssl_context,
- int state,
- int bio_flags);
- vio_ptr bio_;
- vio_ptr ssl_con_;
- vio_ptr ssl_cip_;
- char desc_[100];
- bool open_;
- VioSocket* sd_;
-};
-
-VIO_NS_END
-
-#endif /* VIO_HAVE_OPENSSL */
diff --git a/vio/VioSSLAcceptorFd.cc b/vio/VioSSLAcceptorFd.cc
deleted file mode 100644
index f821685430e..00000000000
--- a/vio/VioSSLAcceptorFd.cc
+++ /dev/null
@@ -1,4 +0,0 @@
-
-#ifdef __GNUC__
-#pragma interface /* gcc class implementation */
-#endif
diff --git a/vio/VioSSLFactoriesFd.cc b/vio/VioSSLFactoriesFd.cc
deleted file mode 100644
index bd64202770a..00000000000
--- a/vio/VioSSLFactoriesFd.cc
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
-** Virtual I/O library
-** Written by Andrei Errapart <andreie@no.spam.ee>
-*/
-
-#include "vio-global.h"
-
-#ifdef VIO_HAVE_OPENSSL
-
-#ifdef __GNUC__
-#pragma implementation // gcc: Class implementation
-#endif
-
-#include <netinet/in.h>
-#include <openssl/x509.h>
-#include <openssl/ssl.h>
-#include <openssl/err.h>
-#include <openssl/pem.h>
-#include <openssl/asn1.h>
-
-VIO_NS_BEGIN
-
-#define this_ssl_method my_static_cast(SSL_METHOD*)(this->ssl_method_)
-#define this_ssl_context my_static_cast(SSL_CTX*)(this->ssl_context_)
-typedef unsigned char* ssl_data_ptr_t;
-
-static bool ssl_algorithms_added = FALSE;
-static bool ssl_error_strings_loaded= FALSE;
-static int verify_depth = 0;
-static int verify_error = X509_V_OK;
-
-static int
-vio_verify_callback(int ok, X509_STORE_CTX *ctx)
-{
- DBUG_ENTER("vio_verify_callback");
- DBUG_PRINT("enter", ("ok=%d, ctx=%p", ok, ctx));
- char buf[256];
- X509* err_cert;
- int err,depth;
-
- err_cert=X509_STORE_CTX_get_current_cert(ctx);
- err= X509_STORE_CTX_get_error(ctx);
- depth= X509_STORE_CTX_get_error_depth(ctx);
-
- X509_NAME_oneline(X509_get_subject_name(err_cert),buf,sizeof(buff));
- if (!ok)
- {
- DBUG_PRINT("error",("verify error:num=%d:%s\n",err,
- X509_verify_cert_error_string(err)));
- if (verify_depth >= depth)
- {
- ok=1;
- verify_error=X509_V_OK;
- }
- else
- {
- ok=0;
- verify_error=X509_V_ERR_CERT_CHAIN_TOO_LONG;
- }
- }
- switch (ctx->error) {
- case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
- X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert),buf,256);
- DBUG_PRINT("info",("issuer= %s\n",buf));
- break;
- case X509_V_ERR_CERT_NOT_YET_VALID:
- case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
- DBUG_PRINT("error", ("notBefore"));
- //ASN1_TIME_print_fp(stderr,X509_get_notBefore(ctx->current_cert));
- break;
- case X509_V_ERR_CERT_HAS_EXPIRED:
- case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
- DBUG_PRINT("error", ("notAfter error"));
- //ASN1_TIME_print_fp(stderr,X509_get_notAfter(ctx->current_cert));
- break;
- }
- DBUG_PRINT("exit", ("r=%d", ok));
- DBUG_RETURN(ok);
-}
-
-
-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=%p, key_file=%p",
- ctx, cert_file, key_file));
- if (cert_file != NULL)
- {
- if (SSL_CTX_use_certificate_file(ctx,cert_file,SSL_FILETYPE_PEM) <= 0)
- {
- DBUG_PRINT("error",("unable to get certificate from '%s'\n",cert_file));
- /* FIX stderr */
- ERR_print_errors_fp(stderr);
- DBUG_RETURN(0);
- }
- if (key_file == NULL)
- key_file = cert_file;
- if (SSL_CTX_use_PrivateKey_file(ctx,key_file,
- SSL_FILETYPE_PEM) <= 0)
- {
- DBUG_PRINT("error", ("unable to get private key from '%s'\n",key_file));
- /* FIX stderr */
- ERR_print_errors_fp(stderr);
- DBUG_RETURN(0);
- }
-
- /* If we are using DSA, we can copy the parameters from
- * the private key */
- /* Now we know that a key and cert have been set against
- * the SSL context */
- if (!SSL_CTX_check_private_key(ctx))
- {
- DBUG_PRINT("error", ("Private key does not match the certificate public key\n"));
- DBUG_RETURN(0);
- }
- }
- DBUG_RETURN(1);
-}
-
-/************************ VioSSLConnectorFd **********************************/
-VioSSLConnectorFd::VioSSLConnectorFd(const char* key_file,
- const char* cert_file,
- const char* ca_file,
- const char* ca_path)
-:ssl_context_(0),ssl_method_(0)
-{
- DBUG_ENTER("VioSSLConnectorFd::VioSSLConnectorFd");
- DBUG_PRINT("enter",
- ("this=%p, key_file=%s, cert_file=%s, ca_path=%s, ca_file=%s",
- this, key_file, cert_file, ca_path, ca_file));
-
- /* FIXME: constants! */
- int verify = SSL_VERIFY_PEER;
-
- if (!ssl_algorithms_added)
- {
- DBUG_PRINT("info", ("todo: SSLeay_add_ssl_algorithms()"));
- ssl_algorithms_added = true;
- SSLeay_add_ssl_algorithms();
- }
- if (!ssl_error_strings_loaded)
- {
- DBUG_PRINT("info", ("todo:SSL_load_error_strings()"));
- ssl_error_strings_loaded = true;
- SSL_load_error_strings();
- }
- ssl_method_ = SSLv3_client_method();
- ssl_context_ = SSL_CTX_new(this_ssl_method);
- if (ssl_context_ == 0)
- {
- DBUG_PRINT("error", ("SSL_CTX_new failed"));
- report_errors();
- goto ctor_failure;
- }
- /*
- * SSL_CTX_set_options
- * SSL_CTX_set_info_callback
- * SSL_CTX_set_cipher_list
- */
- SSL_CTX_set_verify(this_ssl_context, verify, vio_verify_callback);
- if (vio_set_cert_stuff(this_ssl_context, cert_file, key_file) == -1)
- {
- DBUG_PRINT("error", ("vio_set_cert_stuff failed"));
- report_errors();
- goto ctor_failure;
- }
- if (SSL_CTX_load_verify_locations( this_ssl_context, ca_file,ca_path)==0)
- {
- DBUG_PRINT("warning", ("SSL_CTX_load_verify_locations failed"));
- if (SSL_CTX_set_default_verify_paths(this_ssl_context)==0)
- {
- DBUG_PRINT("error", ("SSL_CTX_set_default_verify_paths failed"));
- report_errors();
- goto ctor_failure;
- }
- }
- DBUG_VOID_RETURN;
-ctor_failure:
- DBUG_PRINT("exit", ("there was an error"));
- DBUG_VOID_RETURN;
-}
-
-VioSSLConnectorFd::~VioSSLConnectorFd()
-{
- DBUG_ENTER("VioSSLConnectorFd::~VioSSLConnectorFd");
- DBUG_PRINT("enter", ("this=%p", this));
- if (ssl_context_!=0)
- SSL_CTX_free(this_ssl_context);
- DBUG_VOID_RETURN;
-}
-
-VioSSL* VioSSLConnectorFd::connect( int fd)
-{
- DBUG_ENTER("VioSSLConnectorFd::connect");
- DBUG_PRINT("enter", ("this=%p, fd=%d", this, fd));
- DBUG_RETURN(new VioSSL(fd, ssl_context_, VioSSL::state_connect));
-}
-
-VioSSL*
-VioSSLConnectorFd::connect( VioSocket* sd)
-{
- DBUG_ENTER("VioSSLConnectorFd::connect");
- DBUG_PRINT("enter", ("this=%p, sd=%s", this, sd->description()));
- DBUG_RETURN(new VioSSL(sd, ssl_context_, VioSSL::state_connect));
-}
-
-void
-VioSSLConnectorFd::report_errors()
-{
- unsigned long l;
- const char* file;
- const char* data;
- int line,flags;
-
- DBUG_ENTER("VioSSLConnectorFd::report_errors");
- DBUG_PRINT("enter", ("this=%p", this));
-
- while ((l=ERR_get_error_line_data(&file,&line,&data,&flags)) != 0)
- {
- char buf[200];
- DBUG_PRINT("error", ("OpenSSL: %s:%s:%d:%s\n", ERR_error_string(l,buf),
- file,line,(flags&ERR_TXT_STRING)?data:"")) ;
- }
- DBUG_VOID_RETURN;
-}
-
-/************************ VioSSLAcceptorFd **********************************/
-
-VioSSLAcceptorFd::VioSSLAcceptorFd(const char* key_file,
- const char* cert_file,
- const char* ca_file,
- const char* ca_path)
- :ssl_context_(0), ssl_method_(0)
-{
- DBUG_ENTER("VioSSLAcceptorFd::VioSSLAcceptorFd");
- DBUG_PRINT("enter",
- ("this=%p, key_file=%s, cert_file=%s, ca_path=%s, ca_file=%s",
- this, key_file, cert_file, ca_path, ca_file));
-
- /* FIXME: constants! */
- int verify = (SSL_VERIFY_PEER |
- SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
- SSL_VERIFY_CLIENT_ONCE);
- session_id_context_ = static_cast<vio_ptr>(this);
-
- if (!ssl_algorithms_added)
- {
- DBUG_PRINT("info", ("todo: SSLeay_add_ssl_algorithms()"));
- ssl_algorithms_added = true;
- SSLeay_add_ssl_algorithms();
- }
- if (!ssl_error_strings_loaded)
- {
- DBUG_PRINT("info", ("todo: SSL_load_error_strings()"));
- ssl_error_strings_loaded = true;
- SSL_load_error_strings();
- }
- ssl_method_ = SSLv3_server_method();
- ssl_context_ = SSL_CTX_new(this_ssl_method);
- if (ssl_context_==0)
- {
- DBUG_PRINT("error", ("SSL_CTX_new failed"));
- report_errors();
- goto ctor_failure;
- }
- /*
- * SSL_CTX_set_quiet_shutdown(ctx,1);
- *
- */
- SSL_CTX_sess_set_cache_size(this_ssl_context,128);
-
- /* DH?
- */
- SSL_CTX_set_verify(this_ssl_context, verify, vio_verify_callback);
- /*
- * Double cast needed at least for egcs-1.1.2 to
- * supress warnings:
- * 1) ANSI C++ blaah implicit cast from 'void*' to 'unsigned char*'
- * 2) static_cast from 'void**' to 'unsigned char*'
- * Wish I had a copy of standard handy...
- */
- SSL_CTX_set_session_id_context(this_ssl_context,
- my_static_cast(ssl_data_ptr_t)
- (my_static_cast(void*)(&session_id_context_)),
- sizeof(session_id_context_));
-
- /*
- * SSL_CTX_set_client_CA_list(ctx,SSL_load_client_CA_file(CAfile));
- */
- if (vio_set_cert_stuff(this_ssl_context, cert_file, key_file) == -1)
- {
- DBUG_PRINT("error", ("vio_set_cert_stuff failed"));
- report_errors();
- goto ctor_failure;
- }
- if (SSL_CTX_load_verify_locations( this_ssl_context, ca_file, ca_path)==0)
- {
- DBUG_PRINT("warning", ("SSL_CTX_load_verify_locations failed"));
- if (SSL_CTX_set_default_verify_paths(this_ssl_context)==0)
- {
- DBUG_PRINT("error", ("SSL_CTX_set_default_verify_paths failed"));
- report_errors();
- goto ctor_failure;
- }
- }
- DBUG_VOID_RETURN;
-ctor_failure:
- DBUG_PRINT("exit", ("there was an error"));
- DBUG_VOID_RETURN;
-}
-
-VioSSLAcceptorFd::~VioSSLAcceptorFd()
-{
- DBUG_ENTER("VioSSLAcceptorFd::~VioSSLAcceptorFd");
- DBUG_PRINT("enter", ("this=%p", this));
- if (ssl_context_!=0)
- SSL_CTX_free(this_ssl_context);
- DBUG_VOID_RETURN;
-}
-
-VioSSL*
-VioSSLAcceptorFd::accept(int fd)
-{
- DBUG_ENTER("VioSSLAcceptorFd::accept");
- DBUG_PRINT("enter", ("this=%p, fd=%d", this, fd));
- DBUG_RETURN(new VioSSL(fd, ssl_context_, VioSSL::state_accept));
-}
-
-VioSSL*
-VioSSLAcceptorFd::accept(VioSocket* sd)
-{
- DBUG_ENTER("VioSSLAcceptorFd::accept");
- DBUG_PRINT("enter", ("this=%p, sd=%s", this, sd->description()));
- DBUG_RETURN(new VioSSL(sd, ssl_context_, VioSSL::state_accept));
-}
-
-void
-VioSSLAcceptorFd::report_errors()
-{
- unsigned long l;
- const char* file;
- const char* data;
- int line,flags;
-
- DBUG_ENTER("VioSSLConnectorFd::report_errors");
- DBUG_PRINT("enter", ("this=%p", this));
-
- while ((l=ERR_get_error_line_data(&file,&line,&data,&flags)) != 0)
- {
- char buf[200];
- DBUG_PRINT("error", ("OpenSSL: %s:%s:%d:%s\n", ERR_error_string(l,buf),
- file,line,(flags&ERR_TXT_STRING)?data:"")) ;
- }
- DBUG_VOID_RETURN;
-}
-
-VIO_NS_END
-
-#endif /* VIO_HAVE_OPENSSL */
diff --git a/vio/VioSSLFactoriesFd.h b/vio/VioSSLFactoriesFd.h
deleted file mode 100644
index ed5a24f6b4a..00000000000
--- a/vio/VioSSLFactoriesFd.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Wrapper around SSL_CTX.
- */
-
-#ifdef VIO_HAVE_OPENSSL
-
-#ifdef __GNUC__
-#pragma interface /* gcc class implementation */
-#endif
-
-VIO_NS_BEGIN
-
-class VioSSLAcceptorFd : public VioAcceptorFd
-{
-public:
- VioSSLAcceptorFd(const char* key_file,
- const char* cert_file,
- const char* ca_file,
- const char* ca_path);
-
- virtual ~VioSSLAcceptorFd();
- virtual VioSSL* accept(int fd);
- virtual VioSSL* accept(VioSocket* sd);
-private:
- VioSSLAcceptorFd(const VioSSLAcceptorFd& rhs);//undefined
- VioSSLAcceptorFd& operator=(const VioSSLAcceptorFd& rhs);//undefined
-private:
- void report_errors();
- vio_ptr ssl_;
- vio_ptr ssl_context_;
- vio_ptr ssl_method_;
- vio_ptr session_id_context_;
-};
-
-VIO_NS_END
-
-/*
- * The Factory where Vio's are made!
- */
-
-class VioSSLConnectorFd : public VioConnectorFd
-{
-public:
- VioSSLConnectorFd(const char* key_file,
- const char* cert_file,
- const char* ca_file,
- const char* ca_path);
-
- virtual ~VioSSLConnectorFd();
- virtual VioSSL* connect(int fd);
- virtual VioSSL* connect(VioSocket* sd);
-private:
- VioSSLConnectorFd(const VioSSLConnectorFd& rhs);//undefined
- VioSSLConnectorFd& operator=(const VioSSLConnectorFd& rhs);//undefined
-private:
- void report_errors();
- vio_ptr ssl_context_;
- vio_ptr ssl_method_;
- vio_ptr ssl_;
-};
-
-VIO_NS_END
-
-#endif /* VIO_HAVE_OPENSSL */
diff --git a/vio/VioSocket.cc b/vio/VioSocket.cc
deleted file mode 100644
index e8390edb98a..00000000000
--- a/vio/VioSocket.cc
+++ /dev/null
@@ -1,326 +0,0 @@
-/* Copyright Abandoned 2000 Monty Program KB
-
- This file is public domain and comes with NO WARRANTY of any kind */
-
-/*
-** Virtual I/O library
-** Written by Andrei Errapart <andreie@no.spam.ee>
-*/
-
-#include "vio-global.h"
-#ifdef __GNUC__
-#pragma implementation // gcc: Class implementation
-#endif
-#include <assert.h>
-
-/*
- * Probably no need to clean this up
- */
-
-#ifdef _WIN32
-#include <winsock.h>
-#endif
-#include <sys/types.h>
-#if !defined(__WIN32__) && !defined(MSDOS)
-#include <sys/socket.h>
-#endif
-#if !defined(MSDOS) && !defined(__WIN32__) && !defined(HAVE_BROKEN_NETINET_INCLUDES)
-#include <netinet/in_systm.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#if !defined(alpha_linux_port)
-#include <netinet/tcp.h>
-#endif
-#if defined(__EMX__)
-#include <sys/ioctl.h>
-#define ioctlsocket(A,B,C) ioctl((A),(B),(void *)(C),sizeof(*(C)))
-#undef HAVE_FCNTL
-#endif
-#endif
-
-#if defined(MSDOS) || defined(__WIN32__)
-#ifdef __WIN32__
-#undef errno
-#undef EINTR
-#undef EAGAIN
-#define errno WSAGetLastError()
-#define EINTR WSAEINTR
-#define EAGAIN WSAEINPROGRESS
-#endif
-#endif
-#ifndef EWOULDBLOCK
-#define EWOULDBLOCK EAGAIN
-#endif
-
-#ifdef __cplusplus
-extern "C" { // Because of SCO 3.2V4.2
-#endif
-#ifndef __WIN32__
-#include <sys/resource.h>
-#ifdef HAVE_SYS_UN_H
-#include <sys/un.h>
-#endif
-#include <netdb.h>
-#include <sys/utsname.h>
-#endif // __WIN32__
-#ifdef __cplusplus
-}
-#endif
-
-VIO_NS_BEGIN
-
-#define this_ssl_cip my_static_cast(SSL_CIPHER*)(this->ssl_cip_)
-
-VioSocket::VioSocket(vio_socket sd, enum_vio_type type, bool localhost)
-:sd_(sd), localhost_(localhost), fcntl_(0),
- fcntl_set_(FALSE), cipher_description_(0)
-{
- DBUG_ENTER("VioSocket::VioSocket");
- DBUG_PRINT("enter", ("sd=%d", sd));
- if (type == VIO_TYPE_SOCKET)
- sprintf(desc_,"Socket (%d)",sd_);
- else
- sprintf(desc_,"TCP/IP (%d)",sd_);
- DBUG_VOID_RETURN;
-}
-
-VioSocket::~VioSocket()
-{
- DBUG_ENTER("VioSocket::~VioSocket");
- DBUG_PRINT("enter", ("sd_=%d", sd_));
- if (sd_>=0)
- close();
- DBUG_VOID_RETURN;
-}
-
-bool
-VioSocket::is_open() const
-{
- return sd_>=0;
-}
-
-int
-VioSocket::read(vio_ptr buf, int size)
-{
- int r;
- DBUG_ENTER("VioSocket::read");
- DBUG_PRINT("enter", ("sd_=%d, buf=%p, size=%d", sd_, buf, size));
- assert(sd_>=0);
-#if defined(MSDOS) || defined(__WIN32__)
- r = ::recv(sd_, buf, size,0);
-#else
- r = ::read(sd_, buf, size);
-#endif
-#ifndef DBUG_OFF
- if ( r < 0)
- {
- DBUG_PRINT("error", ("Got error %d during read",errno));
- }
-#endif /* DBUG_OFF */
- DBUG_PRINT("exit", ("%d", r));
- DBUG_RETURN(r);
-}
-
-int
-VioSocket::write(vio_ptr buf, int size)
-{
- int r;
- DBUG_ENTER("VioSocket::write");
- DBUG_PRINT("enter", ("sd_=%d, buf=%p, size=%d", sd_, buf, size));
- assert(sd_>=0);
-#if defined(__WIN32__)
- r = ::send(sd_, buf, size,0);
-#else
- r = ::write(sd_, buf, size);
-#endif /* __WIN32__ */
-#ifndef DBUG_OFF
- if (r < 0)
- {
- DBUG_PRINT("error", ("Got error %d on write",errno));
- }
-#endif /* DBUG_OFF */
- DBUG_RETURN(r);
-}
-
-int
-VioSocket::blocking(bool set_blocking_mode)
-{
- int r= 0;
- DBUG_ENTER("VioSocket::blocking");
- DBUG_PRINT("enter", ("set_blocking_mode: %d", (int) set_blocking_mode));
-
-#if !defined(___WIN32__) && !defined(__EMX__)
-#if !defined(NO_FCNTL_NONBLOCK)
- assert(sd_>=0);
-
- int old_fcntl=fcntl_;
- if (!fcntl_set_)
- {
- fcntl_set_ = true;
- old_fcntl= fcntl_ = fcntl(F_GETFL);
- }
- if (set_blocking_mode)
- fcntl_&=~O_NONBLOCK; //clear bit
- else
- fcntl_|=O_NONBLOCK; //set bit
- if (old_fcntl != fcntl_)
- r = ::fcntl(sd_, F_SETFL, fcntl_);
-#endif /* !defined(NO_FCNTL_NONBLOCK) */
-#else /* !defined(__WIN32__) && !defined(__EMX__) */
- {
- ulong arg;
- int old_fcntl=vio->fcntl_mode;
- if (!vio->fcntl_set)
- {
- vio->fcntl_set = TRUE;
- old_fnctl=vio->fcntl_mode=0;
- }
- if (set_blocking_mode)
- {
- arg = 0;
- fcntl_&=~ O_NONBLOCK; //clear bit
- }
- else
- {
- arg = 1;
- fcntl_|= O_NONBLOCK; //set bit
- }
- if (old_fcntl != fcntl_)
- r = ioctlsocket(sd_,FIONBIO,(void*)&arg,sizeof(arg));
- }
-#endif
- DBUG_RETURN(r);
-}
-
-bool
-VioSocket::blocking() const
-{
- DBUG_ENTER("VioSocket::blocking");
- bool r = !(fcntl_ & O_NONBLOCK);
- DBUG_PRINT("exit", ("%d", (int)r));
- DBUG_RETURN(r);
-}
-
-int
-VioSocket::fastsend(bool onoff)
-{
- int r=0;
- DBUG_ENTER("VioSocket::fastsend");
- DBUG_PRINT("enter", ("onoff:%d", (int)onoff));
- assert(sd_>=0);
-
-#ifdef IPTOS_THROUGHPUT
-#ifndef __EMX__
- int tos = IPTOS_THROUGHPUT;
- if (!setsockopt(sd_, IPPROTO_IP, IP_TOS, (void*) &tos, sizeof(tos)))
-#endif /* !__EMX__ */
- {
- int nodelay = 1;
- if (setsockopt(sd_, IPPROTO_TCP, TCP_NODELAY, (void*) &nodelay,
- sizeof(nodelay)))
- {
- DBUG_PRINT("warning",
- ("Couldn't set socket option for fast send"));
- r= -1;
- }
- }
-#endif /* IPTOS_THROUGHPUT */
- DBUG_PRINT("exit", ("%d", r));
- DBUG_RETURN(0);
-}
-
-
-int
-VioSocket::keepalive(bool set_keep_alive)
-{
- DBUG_ENTER("VioSocket::keepalive");
- DBUG_PRINT("enter", ("sd_=%d, set_keep_alive=%d", sd_,
- (int) set_keep_alive));
- assert(sd_>=0);
- uint opt= set_keep_alive ? 1 : 0;
- DBUG_RETURN(setsockopt(sd_, SOL_SOCKET, SO_KEEPALIVE, (char*) &opt,
- sizeof(opt)));
-}
-
-
-bool
-VioSocket::should_retry() const
-{
- int en = errno;
- return en == EAGAIN || en == EINTR || en == EWOULDBLOCK;
-}
-
-int
-VioSocket::close()
-{
- DBUG_ENTER("VioSocket::close");
- assert(sd_>=0);
- int r=0;
- if (::shutdown(sd_,2))
- r= -1;
- if (::closesocket(sd_))
- r= -1;
- if (r)
- {
- DBUG_PRINT("error", ("close() failed, error: %d",errno));
- /* FIXME: error handling (not critical for MySQL) */
- }
- sd_ = -1;
- DBUG_RETURN(r);
-}
-
-
-int
-VioSocket::shutdown(int how)
-{
- DBUG_ENTER("VioSocket::shutdown");
- DBUG_PRINT("enter", ("how=%d", how));
- assert(sd_>=0);
- int r = ::shutdown(sd_, how);
- DBUG_PRINT("exit", ("%d", r));
- DBUG_RETURN(r);
-}
-
-
-const char*
-VioSocket::description() const
-{
- return desc_;
-}
-
-
-bool
-VioSocket::peer_addr(char *buf) const
-{
- DBUG_ENTER("VioSocket::peer_addr");
- DBUG_PRINT("enter", ("sd_=%d", sd_));
- if (localhost_)
- {
- strmov(buf,"127.0.0.1");
- }
- else
- {
- size_socket addrLen= sizeof(struct sockaddr);
- if (getpeername(sd_, my_reinterpret_cast(struct sockaddr *) (&remote_),
- &addrLen) != 0)
- {
- DBUG_PRINT("exit", ("getpeername, error: %d", errno));
- DBUG_RETURN(1);
- }
- my_inet_ntoa(remote_.sin_addr,buf);
- }
- DBUG_PRINT("exit", ("addr=%s", buf));
- DBUG_RETURN(0);
-}
-
-
-const char*
-VioSocket::cipher_description() const
-{
- DBUG_ENTER("VioSocket::cipher_description");
- char *r = cipher_description_ ? cipher_description_:"";
- DBUG_PRINT("exit", ("name: %s", r));
- DBUG_RETURN(r);
-}
-
-VIO_NS_END
diff --git a/vio/VioSocket.h b/vio/VioSocket.h
deleted file mode 100644
index e2c6eafa516..00000000000
--- a/vio/VioSocket.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
-** Virtual I/O library
-** Written by Andrei Errapart <andreie@no.spam.ee>
-*/
-
-/*
- * Concrete Vio around socket. Doesn't differ much from VioFd.
- */
-
-#ifdef WIN32
- typedef SOCKET vio_socket;
-#else
- typedef int vio_socket;
-#endif /* WIN32 */
-
-VIO_NS_BEGIN
-
-class VioSSL;
-class VioSocket : public Vio
-{
-public:
- VioSocket(vio_socket sd, bool localhost=true);
- virtual ~VioSocket();
- virtual bool is_open() const;
- virtual int read(vio_ptr buf, int size);
- virtual int write(const vio_ptr buf, int size);
- virtual int blocking(bool onoff);
- virtual bool blocking() const;
- virtual int fastsend(bool onoff=true);
- virtual int keepalive(bool onoff);
- virtual bool should_retry() const;
- virtual int close();
- virtual const char* description() const;
- virtual bool peer_addr(char *buf) const;
- virtual const char* cipher_description() const;
- virtual int vio_errno();
- int shutdown(int how);
-
-private:
- vio_socket sd_;
- const bool localhost_;
- int fcntl_;
- bool fcntl_set_;
- char desc_[30];
- mutable struct sockaddr_in local_;
- mutable struct sockaddr_in remote_;
- mutable char* cipher_description_;
-
- friend class VioSSL; // he wants to tinker with this->sd_;
-};
-
-VIO_NS_END
-
-#endif /* vio_VioSocket_h_ */
-
diff --git a/vio/test-ssl.c b/vio/test-ssl.c
new file mode 100644
index 00000000000..09dae7ad5cf
--- /dev/null
+++ b/vio/test-ssl.c
@@ -0,0 +1,147 @@
+/* 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 */
+
+#include <my_global.h>
+#ifdef HAVE_OPENSSL
+#include <my_sys.h>
+#include <m_string.h>
+#include <m_ctype.h>
+#include "mysql.h"
+#include "errmsg.h"
+#include <my_dir.h>
+#ifndef __GNU_LIBRARY__
+#define __GNU_LIBRARY__ // Skip warnings in getopt.h
+#endif
+#include <getopt.h>
+#include <signal.h>
+#include <violite.h>
+
+const char *VER="0.1";
+
+
+#ifndef DBUG_OFF
+const char *default_dbug_option="d:t:O,-";
+#endif
+
+void
+fatal_error( const char* r)
+{
+ perror(r);
+ exit(0);
+}
+
+void
+print_usage()
+{
+ printf("viossl-test: testing SSL virtual IO. Usage:\n");
+ printf("viossl-test server-key server-cert client-key client-cert [CAfile] [CApath]\n");
+}
+
+int
+main( int argc,
+ char** argv)
+{
+ char* server_key = 0, *server_cert = 0;
+ char* client_key = 0, *client_cert = 0;
+ char* ca_file = 0, *ca_path = 0;
+ char* cipher=0;
+ int child_pid,sv[2];
+ struct st_VioSSLAcceptorFd* ssl_acceptor=0;
+ struct st_VioSSLConnectorFd* ssl_connector=0;
+ Vio* client_vio=0, *server_vio=0;
+ MY_INIT(argv[0]);
+ DBUG_PROCESS(argv[0]);
+ DBUG_PUSH(default_dbug_option);
+
+ if (argc<5)
+ {
+ print_usage();
+ return 1;
+ }
+
+ server_key = argv[1];
+ server_cert = argv[2];
+ client_key = argv[3];
+ client_cert = argv[4];
+ if (argc>5)
+ ca_file = argv[5];
+ if (argc>6)
+ ca_path = argv[6];
+ printf("Server key/cert : %s/%s\n", server_key, server_cert);
+ printf("Client key/cert : %s/%s\n", client_key, client_cert);
+ if (ca_file!=0)
+ printf("CAfile : %s\n", ca_file);
+ if (ca_path!=0)
+ printf("CApath : %s\n", ca_path);
+
+
+ if (socketpair(PF_UNIX, SOCK_STREAM, IPPROTO_IP, sv)==-1)
+ fatal_error("socketpair");
+
+ ssl_acceptor = new_VioSSLAcceptorFd(server_key, server_cert, ca_file, ca_path, cipher);
+ ssl_connector = new_VioSSLConnectorFd(client_key, client_cert, ca_file, ca_path, cipher);
+
+ client_vio = (struct st_vio*)my_malloc(sizeof(struct st_vio),MYF(0));
+ client_vio->sd = sv[0];
+ client_vio->vioblocking(client_vio,0);
+ sslconnect(ssl_connector,client_vio,60L);
+ server_vio = (struct st_vio*)my_malloc(sizeof(struct st_vio),MYF(0));
+ server_vio->sd = sv[1];
+ server_vio->vioblocking(client_vio,0);
+ sslaccept(ssl_acceptor,server_vio,60L);
+
+ printf("Socketpair: %d , %d\n", client_vio->sd, server_vio->sd);
+
+ child_pid = fork();
+ if (child_pid==-1) {
+ my_free((gptr)ssl_acceptor,MYF(0));
+ my_free((gptr)ssl_connector,MYF(0));
+ fatal_error("fork");
+ }
+ if (child_pid==0) {
+ //child, therefore, client
+ char xbuf[100];
+ int r = client_vio->read(client_vio,xbuf, sizeof(xbuf));
+ if (r<=0) {
+ my_free((gptr)ssl_acceptor,MYF(0));
+ my_free((gptr)ssl_connector,MYF(0));
+ fatal_error("client:SSL_read");
+ }
+ xbuf[r] = 0;
+ printf("client:got %s\n", xbuf);
+ my_free((gptr)client_vio,MYF(0));
+ my_free((gptr)ssl_acceptor,MYF(0));
+ my_free((gptr)ssl_connector,MYF(0));
+ } else {
+ const char* s = "Huhuhuh";
+ int r = server_vio->write(server_vio,(gptr)s, strlen(s));
+ if (r<=0) {
+ my_free((gptr)ssl_acceptor,MYF(0));
+ my_free((gptr)ssl_connector,MYF(0));
+ fatal_error("server:SSL_write");
+ }
+ my_free((gptr)server_vio,MYF(0));
+ my_free((gptr)ssl_acceptor,MYF(0));
+ my_free((gptr)ssl_connector,MYF(0));
+ }
+ return 0;
+}
+#else /* HAVE_OPENSSL */
+
+int main() {
+return 0;
+}
+#endif /* HAVE_OPENSSL */
diff --git a/vio/test-sslclient.c b/vio/test-sslclient.c
new file mode 100644
index 00000000000..51a78485642
--- /dev/null
+++ b/vio/test-sslclient.c
@@ -0,0 +1,105 @@
+/* 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 */
+
+#include <my_global.h>
+#ifdef HAVE_OPENSSL
+#include <my_sys.h>
+#include <m_string.h>
+#include <m_ctype.h>
+#include "mysql.h"
+#include "errmsg.h"
+#include <my_dir.h>
+#ifndef __GNU_LIBRARY__
+#define __GNU_LIBRARY__ // Skip warnings in getopt.h
+#endif
+#include <getopt.h>
+#include <signal.h>
+#include <violite.h>
+
+const char *VER="0.1";
+
+
+#ifndef DBUG_OFF
+const char *default_dbug_option="d:t:O,-";
+#endif
+
+void
+fatal_error( const char* r)
+{
+ perror(r);
+ exit(0);
+}
+
+int
+main( int argc __attribute__((unused)),
+ char** argv)
+{
+ char client_key[] = "../SSL/client-key.pem", client_cert[] = "../SSL/client-cert.pem";
+ char ca_file[] = "../SSL/cacert.pem", *ca_path = 0, *cipher=0;
+ struct st_VioSSLConnectorFd* ssl_connector=0;
+ struct sockaddr_in sa;
+ Vio* client_vio=0;
+ int err;
+ char xbuf[100]="Ohohhhhoh1234";
+ MY_INIT(argv[0]);
+ DBUG_PROCESS(argv[0]);
+ DBUG_PUSH(default_dbug_option);
+
+ printf("Client key/cert : %s/%s\n", client_key, client_cert);
+ if (ca_file!=0)
+ printf("CAfile : %s\n", ca_file);
+ if (ca_path!=0)
+ printf("CApath : %s\n", ca_path);
+
+ ssl_connector = new_VioSSLConnectorFd(client_key, client_cert, ca_file, ca_path, cipher);
+ if(!ssl_connector) {
+ fatal_error("client:new_VioSSLConnectorFd failed");
+ }
+
+ /* ----------------------------------------------- */
+ /* Create a socket and connect to server using normal socket calls. */
+
+ client_vio = vio_new(socket (AF_INET, SOCK_STREAM, 0), VIO_TYPE_TCPIP, TRUE);
+
+ memset (&sa, '\0', sizeof(sa));
+ sa.sin_family = AF_INET;
+ sa.sin_addr.s_addr = inet_addr ("127.0.0.1"); /* Server IP */
+ sa.sin_port = htons (1111); /* Server Port number */
+
+ err = connect(client_vio->sd, (struct sockaddr*) &sa,
+ sizeof(sa));
+
+ /* ----------------------------------------------- */
+ /* Now we have TCP conncetion. Start SSL negotiation. */
+ read(client_vio->sd,xbuf, sizeof(xbuf));
+ sslconnect(ssl_connector,client_vio,60L);
+ err = client_vio->read(client_vio,xbuf, sizeof(xbuf));
+ if (err<=0) {
+ my_free((gptr)ssl_connector,MYF(0));
+ fatal_error("client:SSL_read");
+ }
+ xbuf[err] = 0;
+ printf("client:got %s\n", xbuf);
+ my_free((gptr)client_vio,MYF(0));
+ my_free((gptr)ssl_connector,MYF(0));
+ return 0;
+}
+#else /* HAVE_OPENSSL */
+
+int main() {
+return 0;
+}
+#endif /* HAVE_OPENSSL */
diff --git a/vio/test-sslserver.c b/vio/test-sslserver.c
new file mode 100644
index 00000000000..988019a012b
--- /dev/null
+++ b/vio/test-sslserver.c
@@ -0,0 +1,157 @@
+/* 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 */
+
+#include <my_global.h>
+#ifdef HAVE_OPENSSL
+#include <my_sys.h>
+#include <m_string.h>
+#include <m_ctype.h>
+#include "mysql.h"
+#include "errmsg.h"
+#include <my_dir.h>
+#ifndef __GNU_LIBRARY__
+#define __GNU_LIBRARY__ // Skip warnings in getopt.h
+#endif
+#include <getopt.h>
+#include <signal.h>
+#include <violite.h>
+
+const char *VER="0.1";
+
+
+#ifndef DBUG_OFF
+const char *default_dbug_option="d:t:O,-";
+#endif
+
+static void
+fatal_error( const char* r)
+{
+ perror(r);
+ exit(0);
+}
+
+typedef struct {
+ int sd;
+ struct st_VioSSLAcceptorFd* ssl_acceptor;
+} TH_ARGS;
+
+static void
+do_ssl_stuff( TH_ARGS* args)
+{
+ const char* s = "Huhuhuhuuu";
+ Vio* server_vio;
+ int err;
+ DBUG_ENTER("do_ssl_stuff");
+
+ server_vio = vio_new(args->sd, VIO_TYPE_TCPIP, TRUE);
+
+ /* ----------------------------------------------- */
+ /* TCP connection is ready. Do server side SSL. */
+
+ err = write(server_vio->sd,(gptr)s, strlen(s));
+ sslaccept(args->ssl_acceptor,server_vio,60L);
+ err = server_vio->write(server_vio,(gptr)s, strlen(s));
+ DBUG_VOID_RETURN;
+}
+
+static void*
+client_thread( void* arg)
+{
+ my_thread_init();
+ do_ssl_stuff((TH_ARGS*)arg);
+}
+
+int
+main( int argc __attribute__((unused)),
+ char** argv)
+{
+ char server_key[] = "../SSL/server-key.pem",
+ server_cert[] = "../SSL/server-cert.pem";
+ char ca_file[] = "../SSL/cacert.pem",
+ *ca_path = 0,
+ *cipher = 0;
+ struct st_VioSSLAcceptorFd* ssl_acceptor;
+ pthread_t th;
+ TH_ARGS th_args;
+
+
+ struct sockaddr_in sa_serv;
+ struct sockaddr_in sa_cli;
+ int listen_sd;
+ int err;
+ size_t client_len;
+ int reuseaddr = 1; /* better testing, uh? */
+
+ MY_INIT(argv[0]);
+ DBUG_PROCESS(argv[0]);
+ DBUG_PUSH(default_dbug_option);
+
+ printf("Server key/cert : %s/%s\n", server_key, server_cert);
+ if (ca_file!=0)
+
+ printf("CAfile : %s\n", ca_file);
+ if (ca_path!=0)
+ printf("CApath : %s\n", ca_path);
+
+ th_args.ssl_acceptor = ssl_acceptor = new_VioSSLAcceptorFd(server_key, server_cert, ca_file, ca_path,cipher);
+
+ /* ----------------------------------------------- */
+ /* Prepare TCP socket for receiving connections */
+
+ listen_sd = socket (AF_INET, SOCK_STREAM, 0);
+ setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(&reuseaddr));
+
+ memset (&sa_serv, '\0', sizeof(sa_serv));
+ sa_serv.sin_family = AF_INET;
+ sa_serv.sin_addr.s_addr = INADDR_ANY;
+ sa_serv.sin_port = htons (1111); /* Server Port number */
+
+ err = bind(listen_sd, (struct sockaddr*) &sa_serv,
+ sizeof (sa_serv));
+
+ /* Receive a TCP connection. */
+
+ err = listen (listen_sd, 5);
+ client_len = sizeof(sa_cli);
+ th_args.sd = accept (listen_sd, (struct sockaddr*) &sa_cli, &client_len);
+ close (listen_sd);
+
+ printf ("Connection from %lx, port %x\n",
+ (long)sa_cli.sin_addr.s_addr, sa_cli.sin_port);
+
+ /* ----------------------------------------------- */
+ /* TCP connection is ready. Do server side SSL. */
+
+ err = pthread_create(&th, NULL, client_thread, (void*)&th_args);
+ DBUG_PRINT("info", ("pthread_create: %d", err));
+ pthread_join(th, NULL);
+
+#if 0
+ if (err<=0) {
+ my_free((gptr)ssl_acceptor,MYF(0));
+ fatal_error("server:SSL_write");
+ }
+#endif /* 0 */
+
+ my_free((gptr)ssl_acceptor,MYF(0));
+ return 0;
+}
+#else /* HAVE_OPENSSL */
+
+int main() {
+return 0;
+}
+#endif /* HAVE_OPENSSL */
diff --git a/vio/version.cc b/vio/version.cc
deleted file mode 100644
index 7c09d431a9d..00000000000
--- a/vio/version.cc
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "vio-global.h"
-
-extern "C" const char*
-vio_version()
-{
- return "0.2";
-}
diff --git a/vio/vio-global.h b/vio/vio-global.h
deleted file mode 100644
index 0c3d279695d..00000000000
--- a/vio/vio-global.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#include <global.h>
-
-#if !defined(VIO_HAVE_OPENSSL) && defined(HAVE_OPENSSL)
-#define VIO_HAVE_OPENSSL HAVE_OPENSSL
-#endif /* !defined(VIO_HAVE_OPENSSL) && defined(HAVE_OPENSSL) */
-
-#include "viotypes.h"
-#include "Vio.h"
-#include "VioAcceptorFd.h"
-#include "VioFd.h"
-#include "VioPipe.h"
-#include "VioSocket.h"
-#ifdef VIO_HAVE_OPENSSL
-#include "VioSSL.h"
-#include "VioSSLFactoriesFd.h"
-#endif /* VIO_HAVE_OPENSSL */
-
-
-#if VIO_HAVE_NAMESPACES
-#define VIO_STD_NS std
-#define VIO_STD_NS_USING using namespace std;
-#define VIO_NS VirtualIO
-#define VIO_NS_BEGIN namespace VIO_NS {
-#define VIO_NS_END }
-#define VIO_NS_USING using namespace VIO_NS;
-#else
-#define VIO_STD_NS
-#define VIO_STD_NS_USING
-#define VIO_NS
-#define VIO_NS_BEGIN
-#define VIO_NS_END
-#define VIO_NS_USING
-#endif
diff --git a/vio/vio.c b/vio/vio.c
new file mode 100644
index 00000000000..62814e50240
--- /dev/null
+++ b/vio/vio.c
@@ -0,0 +1,132 @@
+/* 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 */
+
+/*
+ Note that we can't have assertion on file descriptors; The reason for
+ this is that during mysql shutdown, another thread can close a file
+ we are working on. In this case we should just return read errors from
+ the file descriptior.
+*/
+
+#define DONT_MAP_VIO
+#include <my_global.h>
+#include <mysql_com.h>
+#include <violite.h>
+#include <errno.h>
+#include <my_sys.h>
+#include <my_net.h>
+#include <m_string.h>
+
+/*
+ * 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)
+{
+ DBUG_ENTER("vio_reset");
+ DBUG_PRINT("enter", ("type=%d sd=%d localhost=%d", type, sd, localhost));
+
+ bzero((char*) vio, sizeof(*vio));
+ vio->type = type;
+ vio->sd = sd;
+ vio->hPipe = hPipe;
+ vio->localhost= localhost;
+#ifdef HAVE_VIO
+#ifdef HAVE_OPENSSL
+ if (type == VIO_TYPE_SSL)
+ {
+ vio->viodelete =vio_ssl_delete;
+ vio->vioerrno =vio_ssl_errno;
+ vio->read =vio_ssl_read;
+ vio->write =vio_ssl_write;
+ vio->fastsend =vio_ssl_fastsend;
+ vio->viokeepalive =vio_ssl_keepalive;
+ vio->should_retry =vio_ssl_should_retry;
+ vio->vioclose =vio_ssl_close;
+ vio->peer_addr =vio_ssl_peer_addr;
+ vio->in_addr =vio_ssl_in_addr;
+ vio->vioblocking =vio_blocking;
+ vio->is_blocking =vio_is_blocking;
+ }
+ else /* default is VIO_TYPE_TCPIP */
+#endif /* HAVE_OPENSSL */
+ {
+ vio->viodelete =vio_delete;
+ vio->vioerrno =vio_errno;
+ vio->read =vio_read;
+ vio->write =vio_write;
+ vio->fastsend =vio_fastsend;
+ vio->viokeepalive =vio_keepalive;
+ vio->should_retry =vio_should_retry;
+ vio->vioclose =vio_close;
+ vio->peer_addr =vio_peer_addr;
+ vio->in_addr =vio_in_addr;
+ vio->vioblocking =vio_blocking;
+ vio->is_blocking =vio_is_blocking;
+ }
+#endif /* HAVE_VIO */
+ DBUG_VOID_RETURN;
+}
+
+/* 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;
+ DBUG_ENTER("vio_new");
+ DBUG_PRINT("enter", ("sd=%d", sd));
+ if ((vio = (Vio*) my_malloc(sizeof(*vio),MYF(MY_WME))))
+ {
+ vio_reset(vio, type, sd, 0, localhost);
+ sprintf(vio->desc,
+ (vio->type == VIO_TYPE_SOCKET ? "socket (%d)" : "TCP/IP (%d)"),
+ vio->sd);
+#if !defined(___WIN__) && !defined(__EMX__)
+#if !defined(NO_FCNTL_NONBLOCK)
+ vio->fcntl_mode = fcntl(sd, F_GETFL);
+#elif defined(HAVE_SYS_IOCTL_H) /* hpux */
+ /* Non blocking sockets doesn't work good on HPUX 11.0 */
+ (void) ioctl(sd,FIOSNBIO,0);
+#endif
+#else /* !defined(__WIN__) && !defined(__EMX__) */
+ {
+ /* set to blocking mode by default */
+ ulong arg=0, r;
+ r = ioctlsocket(sd,FIONBIO,(void*) &arg, sizeof(arg));
+ }
+#endif
+ }
+ DBUG_RETURN(vio);
+}
+
+
+#ifdef __WIN__
+
+Vio *vio_new_win32pipe(HANDLE hPipe)
+{
+ Vio *vio;
+ DBUG_ENTER("vio_new_handle");
+ if ((vio = (Vio*) my_malloc(sizeof(Vio),MYF(MY_WME))))
+ {
+ vio_reset(vio, VIO_TYPE_NAMEDPIPE, 0, hPipe, TRUE);
+ strmov(vio->desc, "named pipe");
+ }
+ DBUG_RETURN(vio);
+}
+
+#endif
diff --git a/vio/vioelitexx.cc b/vio/vioelitexx.cc
deleted file mode 100644
index 0eac28eaf55..00000000000
--- a/vio/vioelitexx.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-/* Copyright Abandoned 2000 Monty Program KB
- This file is public domain and comes with NO WARRANTY of any kind */
-
-/*
- * Renamed of violite.cc to violitexx.cc because of clashes
- * with violite.c
- * This file implements the same functions as in violite.c, but now using
- * the Vio class
- */
-
-#include "vio-global.h"
-
-Vio*
-vio_new(my_socket sd, enum_vio_type type, my_bool localhost)
-{
- return my_reinterpret_cast(Vio*) (new VioSocket(sd, type, localhost));
-}
-
-
-#ifdef __WIN32__
-Vio
-*vio_new_win32pipe(HANDLE hPipe)
-{
- return my_reinterpret_cast(Vio*) (new VioPipe(hPipe));
-}
-#endif
diff --git a/vio/violite.h b/vio/violite.h
deleted file mode 100644
index fc480f59db1..00000000000
--- a/vio/violite.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/* Copyright Abandoned 2000 Monty Program KB
- This file is public domain and comes with NO WARRANTY of any kind */
-
-/*
- * Vio Lite.
- * Purpose: include file for Vio that will work with C and C++
- */
-
-#ifndef vio_violite_h_
-#define vio_violite_h_
-
-#include "my_net.h" /* needed because of struct in_addr */
-
-#ifdef HAVE_VIO
-#include <Vio.h> /* Full VIO interface */
-#else
-
-/* Simple vio interface in C; The functions are implemented in violite.c */
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#ifndef Vio_defined
-#define Vio_defined
-struct st_vio; /* Only C */
-typedef struct st_vio Vio;
-#endif
-
-enum enum_vio_type { VIO_CLOSED, VIO_TYPE_TCPIP, VIO_TYPE_SOCKET,
- VIO_TYPE_NAMEDPIPE, VIO_TYPE_SSL};
-
-Vio* vio_new(my_socket sd,
- enum enum_vio_type type,
- my_bool localhost);
-#ifdef __WIN__
-Vio* vio_new_win32pipe(HANDLE hPipe);
-#endif
-void vio_delete(Vio* vio);
-
-/*
- * vio_read and vio_write should have the same semantics
- * as read(2) and write(2).
- */
-int vio_read( Vio* vio,
- gptr buf, int size);
-int vio_write( Vio* vio,
- const gptr buf,
- int size);
-/*
- * Whenever the socket is set to blocking mode or not.
- */
-int vio_blocking( Vio* vio,
- my_bool onoff);
-my_bool vio_is_blocking( Vio* vio);
-/*
- * setsockopt TCP_NODELAY at IPPROTO_TCP level, when possible.
- */
-int vio_fastsend( Vio* vio,
- my_bool onoff);
-/*
- * setsockopt SO_KEEPALIVE at SOL_SOCKET level, when possible.
- */
-int vio_keepalive( Vio* vio,
- my_bool onoff);
-/*
- * Whenever we should retry the last read/write operation.
- */
-my_bool vio_should_retry( Vio* vio);
-/*
- * When the workday is over...
- */
-int vio_close( Vio* vio);
-/*
- * Short text description of the socket for those, who are curious..
- */
-const char* vio_description( Vio* vio);
-
-/* Return the type of the connection */
- enum enum_vio_type vio_type(Vio* vio);
-
-/* Return last error number */
-int vio_errno(Vio *vio);
-
-/* Get socket number */
-my_socket vio_fd(Vio *vio);
-
-/*
- * Remote peer's address and name in text form.
- */
-my_bool vio_peer_addr(Vio * vio, char *buf);
-
-/* Remotes in_addr */
-
-void vio_in_addr(Vio *vio, struct in_addr *in);
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* HAVE_VIO */
-#endif /* vio_violite_h_ */
diff --git a/sql/violite.c b/vio/viosocket.c
index 37fee6fad3d..14b4305b95a 100644
--- a/sql/violite.c
+++ b/vio/viosocket.c
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- 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,
+/* 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
- 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 */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
Note that we can't have assertion on file descriptors; The reason for
@@ -22,128 +21,21 @@
the file descriptior.
*/
-#include <global.h>
-
-#ifndef HAVE_VIO /* is Vio suppored by the Vio lib ? */
+#define DONT_MAP_VIO
+#include <my_global.h>
+#include <mysql_com.h>
#include <errno.h>
-#include <assert.h>
#include <violite.h>
#include <my_sys.h>
#include <my_net.h>
#include <m_string.h>
-#ifdef HAVE_POLL
-#include <sys/poll.h>
-#endif
-#ifdef HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-
-#if !defined(MSDOS) && !defined(__WIN__) && !defined(HAVE_BROKEN_NETINET_INCLUDES) && !defined(__BEOS__) && !defined(__FreeBSD__)
-#include <netinet/in_systm.h>
-#include <netinet/ip.h>
-#if !defined(alpha_linux_port)
-#include <netinet/tcp.h>
-#endif
-#endif
-
-#if defined(__EMX__) || defined(OS2)
-#define ioctlsocket ioctl
-#endif /* defined(__EMX__) */
-
-#if defined(MSDOS) || defined(__WIN__)
-#define O_NONBLOCK 1 /* For emulation of fcntl() */
-#endif
-#ifndef EWOULDBLOCK
-#define SOCKET_EWOULDBLOCK SOCKET_EAGAIN
-#endif
#ifndef __WIN__
#define HANDLE void *
#endif
-struct st_vio
-{
- my_socket sd; /* my_socket - real or imaginary */
- HANDLE hPipe;
- my_bool localhost; /* Are we from localhost? */
- int fcntl_mode; /* Buffered fcntl(sd,F_GETFL) */
- struct sockaddr_in local; /* Local internet address */
- struct sockaddr_in remote; /* Remote internet address */
- enum enum_vio_type type; /* Type of connection */
- char desc[30]; /* String description */
-};
-
-typedef void *vio_ptr;
-typedef char *vio_cstring;
-
-/*
- * Helper to fill most of the Vio* with defaults.
- */
-
-static void vio_reset(Vio* vio, enum enum_vio_type type,
- my_socket sd, HANDLE hPipe,
- my_bool localhost)
-{
- bzero((char*) vio, sizeof(*vio));
- vio->type = type;
- vio->sd = sd;
- vio->hPipe = hPipe;
- vio->localhost= localhost;
-}
-
-/* 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;
- DBUG_ENTER("vio_new");
- DBUG_PRINT("enter", ("sd=%d", sd));
- if ((vio = (Vio*) my_malloc(sizeof(*vio),MYF(MY_WME))))
- {
- vio_reset(vio, type, sd, 0, localhost);
- sprintf(vio->desc,
- (vio->type == VIO_TYPE_SOCKET ? "socket (%d)" : "TCP/IP (%d)"),
- vio->sd);
-#if !defined(___WIN__) && !defined(__EMX__) && !defined(OS2)
-#if !defined(NO_FCNTL_NONBLOCK)
- vio->fcntl_mode = fcntl(sd, F_GETFL);
-#elif defined(HAVE_SYS_IOCTL_H) /* hpux */
- /* Non blocking sockets doesn't work good on HPUX 11.0 */
- (void) ioctl(sd,FIOSNBIO,0);
-#endif
-#else /* !defined(__WIN__) && !defined(__EMX__) */
- {
- /* set to blocking mode by default */
- ulong arg=0, r;
- r = ioctlsocket(vio->sd,FIONBIO,(void*) &arg, sizeof(arg));
- }
-#endif
- }
- DBUG_RETURN(vio);
-}
-
-
-#ifdef __WIN__
-
-Vio *vio_new_win32pipe(HANDLE hPipe)
-{
- Vio *vio;
- DBUG_ENTER("vio_new_handle");
- if ((vio = (Vio*) my_malloc(sizeof(Vio),MYF(MY_WME))))
- {
- vio_reset(vio, VIO_TYPE_NAMEDPIPE, 0, hPipe, TRUE);
- strmov(vio->desc, "named pipe");
- }
- DBUG_RETURN(vio);
-}
-
-#endif
-
-void vio_delete(Vio * vio)
+void vio_delete(Vio* vio)
{
/* It must be safe to delete null pointers. */
/* This matches the semantics of C++'s delete operator. */
@@ -165,18 +57,13 @@ int vio_read(Vio * vio, gptr buf, int size)
{
int r;
DBUG_ENTER("vio_read");
- DBUG_PRINT("enter", ("sd=%d size=%d", vio->sd, size));
-#if defined( __WIN__) || defined(OS2)
+ DBUG_PRINT("enter", ("sd=%d, buf=%p, size=%d", vio->sd, buf, size));
+#ifdef __WIN__
if (vio->type == VIO_TYPE_NAMEDPIPE)
{
DWORD length;
-#ifdef OS2
- if (!DosRead((HFILE)vio->hPipe, buf, size, &length))
- DBUG_RETURN(-1);
-#else
if (!ReadFile(vio->hPipe, buf, size, &length, NULL))
DBUG_RETURN(-1);
-#endif
DBUG_RETURN(length);
}
r = recv(vio->sd, buf, size,0);
@@ -187,7 +74,7 @@ int vio_read(Vio * vio, gptr buf, int size)
#ifndef DBUG_OFF
if (r < 0)
{
- DBUG_PRINT("vio_error", ("Got error %d during read",socket_errno));
+ DBUG_PRINT("vio_error", ("Got error %d during read",errno));
}
#endif /* DBUG_OFF */
DBUG_PRINT("exit", ("%d", r));
@@ -199,18 +86,13 @@ int vio_write(Vio * vio, const gptr buf, int size)
{
int r;
DBUG_ENTER("vio_write");
- DBUG_PRINT("enter", ("sd=%d size=%d", vio->sd, size));
-#if defined( __WIN__) || defined(OS2)
+ DBUG_PRINT("enter", ("sd=%d, buf=%p, size=%d", vio->sd, buf, size));
+#ifdef __WIN__
if ( vio->type == VIO_TYPE_NAMEDPIPE)
{
DWORD length;
-#ifdef OS2
- if (!DosWrite((HFILE)vio->hPipe, (char*) buf, size, &length))
- DBUG_RETURN(-1);
-#else
if (!WriteFile(vio->hPipe, (char*) buf, size, &length, NULL))
DBUG_RETURN(-1);
-#endif
DBUG_RETURN(length);
}
r = send(vio->sd, buf, size,0);
@@ -228,13 +110,14 @@ int vio_write(Vio * vio, const gptr buf, int size)
}
-int vio_blocking(Vio * vio, my_bool set_blocking_mode)
+int vio_blocking(Vio * vio __attribute__((unused)), my_bool set_blocking_mode)
{
int r=0;
DBUG_ENTER("vio_blocking");
DBUG_PRINT("enter", ("set_blocking_mode: %d", (int) set_blocking_mode));
-#if !defined(___WIN__) && !defined(__EMX__) && !defined(OS2)
+#if !defined(HAVE_OPENSSL)
+#if !defined(___WIN__) && !defined(__EMX__)
#if !defined(NO_FCNTL_NONBLOCK)
if (vio->sd >= 0)
@@ -269,6 +152,8 @@ int vio_blocking(Vio * vio, my_bool set_blocking_mode)
r = ioctlsocket(vio->sd,FIONBIO,(void*) &arg, sizeof(arg));
}
#endif /* !defined(__WIN__) && !defined(__EMX__) */
+#endif /* !defined (HAVE_OPENSSL) */
+ DBUG_PRINT("exit", ("return %d", r));
DBUG_RETURN(r);
}
@@ -314,7 +199,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)
{
@@ -331,7 +216,8 @@ my_bool
vio_should_retry(Vio * vio __attribute__((unused)))
{
int en = socket_errno;
- return en == SOCKET_EAGAIN || en == SOCKET_EINTR || en == SOCKET_EWOULDBLOCK;
+ return (en == SOCKET_EAGAIN || en == SOCKET_EINTR ||
+ en == SOCKET_EWOULDBLOCK);
}
@@ -439,5 +325,3 @@ my_bool vio_poll_read(Vio *vio,uint timeout)
DBUG_RETURN(fds.revents & POLLIN ? 0 : 1);
#endif
}
-
-#endif /* HAVE_VIO */
diff --git a/vio/viossl.c b/vio/viossl.c
new file mode 100644
index 00000000000..6d85b119f20
--- /dev/null
+++ b/vio/viossl.c
@@ -0,0 +1,360 @@
+/* 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 */
+
+/*
+ Note that we can't have assertion on file descriptors; The reason for
+ this is that during mysql shutdown, another thread can close a file
+ we are working on. In this case we should just return read errors from
+ the file descriptior.
+*/
+
+#include <my_global.h>
+
+#ifdef HAVE_OPENSSL
+
+#include <mysql_com.h>
+
+#include <errno.h>
+#include <assert.h>
+#include <violite.h>
+#include <my_sys.h>
+#include <my_net.h>
+#include <m_string.h>
+
+#ifndef __WIN__
+#define HANDLE void *
+#endif
+
+static void
+report_errors()
+{
+ unsigned long l;
+ const char* file;
+ const char* data;
+ int line,flags, any_ssl_error = 0;
+ DBUG_ENTER("report_errors");
+
+ while ((l=ERR_get_error_line_data(&file,&line,&data,&flags)) != 0)
+ {
+ char buf[200];
+ any_ssl_error = 1;
+ DBUG_PRINT("error", ("OpenSSL: %s:%s:%d:%s\n", ERR_error_string(l,buf),
+ file,line,(flags&ERR_TXT_STRING)?data:"")) ;
+ }
+ if (!any_ssl_error) {
+ DBUG_PRINT("info", ("No OpenSSL errors."));
+ }
+ DBUG_PRINT("info", ("BTW, errno=%d", socket_errno));
+ DBUG_VOID_RETURN;
+}
+
+
+void vio_ssl_delete(Vio * vio)
+{
+ /* It must be safe to delete null pointers. */
+ /* This matches the semantics of C++'s delete operator. */
+ if (vio)
+ {
+ if (vio->type != VIO_CLOSED)
+ vio_close(vio);
+ my_free((gptr) vio,MYF(0));
+ }
+}
+
+int vio_ssl_errno(Vio *vio __attribute__((unused)))
+{
+ return socket_errno; /* On Win32 this mapped to WSAGetLastError() */
+}
+
+
+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",
+ vio->sd, buf, size, vio->ssl_));
+
+#ifndef DBUG_OFF
+ errno = 0;
+#endif /* DBUG_OFF */
+ r = SSL_read(vio->ssl_, buf, size);
+#ifndef DBUG_OFF
+ if ( r<= 0) {
+ r=SSL_get_error(vio->ssl_, r);
+ DBUG_PRINT("info",("SSL_get_error returned %d",r));
+ report_errors();
+ }
+#endif /* DBUG_OFF */
+ DBUG_PRINT("exit", ("%d", r));
+ DBUG_RETURN(r);
+}
+
+
+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));
+
+#ifndef DBUG_OFF
+ errno = 0;
+#endif /* DBUG_OFF */
+ r = SSL_write(vio->ssl_, buf, size);
+#ifndef DBUG_OFF
+ if (r<0)
+ report_errors();
+#endif /* DBUG_OFF */
+ DBUG_PRINT("exit", ("%d", r));
+ DBUG_RETURN(r);
+}
+
+
+int vio_ssl_fastsend(Vio * vio __attribute__((unused)))
+{
+ int r=0;
+ DBUG_ENTER("vio_ssl_fastsend");
+
+#ifdef IPTOS_THROUGHPUT
+ {
+#ifndef __EMX__
+ int tos = IPTOS_THROUGHPUT;
+ if (!setsockopt(vio->sd, IPPROTO_IP, IP_TOS, (void *) &tos, sizeof(tos)))
+#endif /* !__EMX__ */
+ {
+ int nodelay = 1;
+ if (setsockopt(vio->sd, IPPROTO_TCP, TCP_NODELAY, (void *) &nodelay,
+ sizeof(nodelay))) {
+ DBUG_PRINT("warning",
+ ("Couldn't set socket option for fast send"));
+ r= -1;
+ }
+ }
+ }
+#endif /* IPTOS_THROUGHPUT */
+ DBUG_PRINT("exit", ("%d", r));
+ DBUG_RETURN(r);
+}
+
+int vio_ssl_keepalive(Vio* vio, my_bool set_keep_alive)
+{
+ int r=0;
+ uint opt = 0;
+ DBUG_ENTER("vio_ssl_keepalive");
+ DBUG_PRINT("enter", ("sd=%d, set_keep_alive=%d", vio->sd, (int)
+ set_keep_alive));
+ if (vio->type != VIO_TYPE_NAMEDPIPE)
+ {
+ if (set_keep_alive)
+ opt = 1;
+ r = setsockopt(vio->sd, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt,
+ sizeof(opt));
+ }
+ DBUG_RETURN(r);
+}
+
+
+my_bool
+vio_ssl_should_retry(Vio * vio __attribute__((unused)))
+{
+ int en = socket_errno;
+ return (en == SOCKET_EAGAIN || en == SOCKET_EINTR ||
+ en == SOCKET_EWOULDBLOCK);
+}
+
+
+int vio_ssl_close(Vio * vio)
+{
+ int r;
+ DBUG_ENTER("vio_ssl_close");
+ r=0;
+ if (vio->ssl_)
+ {
+ r = SSL_shutdown(vio->ssl_);
+ SSL_free(vio->ssl_);
+ vio->ssl_= 0;
+ }
+ if (shutdown(vio->sd,2))
+ r= -1;
+ if (closesocket(vio->sd))
+ r= -1;
+ if (r)
+ {
+ DBUG_PRINT("error", ("close() failed, error: %d",socket_errno));
+ report_errors();
+ /* FIXME: error handling (not critical for MySQL) */
+ }
+ vio->type= VIO_CLOSED;
+ vio->sd= -1;
+ DBUG_RETURN(r);
+}
+
+
+const char *vio_ssl_description(Vio * vio)
+{
+ return vio->desc;
+}
+
+enum enum_vio_type vio_ssl_type(Vio* vio)
+{
+ return vio->type;
+}
+
+my_socket vio_ssl_fd(Vio* vio)
+{
+ return vio->sd;
+}
+
+
+my_bool vio_ssl_peer_addr(Vio * vio, char *buf)
+{
+ DBUG_ENTER("vio_ssl_peer_addr");
+ DBUG_PRINT("enter", ("sd=%d", vio->sd));
+ if (vio->localhost)
+ {
+ strmov(buf,"127.0.0.1");
+ }
+ else
+ {
+ size_socket addrLen = sizeof(struct sockaddr);
+ if (getpeername(vio->sd, (struct sockaddr *) (& (vio->remote)),
+ &addrLen) != 0)
+ {
+ DBUG_PRINT("exit", ("getpeername, error: %d", socket_errno));
+ DBUG_RETURN(1);
+ }
+ /* FIXME */
+/* my_inet_ntoa(vio->remote.sin_addr,buf); */
+ }
+ DBUG_PRINT("exit", ("addr=%s", buf));
+ DBUG_RETURN(0);
+}
+
+
+void vio_ssl_in_addr(Vio *vio, struct in_addr *in)
+{
+ DBUG_ENTER("vio_ssl_in_addr");
+ if (vio->localhost)
+ bzero((char*) in, sizeof(*in)); /* This should never be executed */
+ else
+ *in=vio->remote.sin_addr;
+ DBUG_VOID_RETURN;
+}
+
+
+void sslaccept(struct st_VioSSLAcceptorFd* ptr, Vio* vio, long timeout)
+{
+ char *str;
+ char buf[1024];
+ X509* client_cert;
+ DBUG_ENTER("sslaccept");
+ DBUG_PRINT("enter", ("sd=%d ptr=%p", vio->sd,ptr));
+ vio_reset(vio,VIO_TYPE_SSL,vio->sd,0,FALSE);
+ vio->ssl_=0;
+ vio->open_=FALSE;
+ if (!(vio->ssl_ = SSL_new(ptr->ssl_context_)))
+ {
+ DBUG_PRINT("error", ("SSL_new failure"));
+ report_errors();
+ DBUG_VOID_RETURN;
+ }
+ DBUG_PRINT("info", ("ssl_=%p timeout=%ld",vio->ssl_, timeout));
+ SSL_clear(vio->ssl_);
+ vio_blocking(vio, FALSE);
+ SSL_SESSION_set_timeout(SSL_get_session(vio->ssl_), timeout);
+ SSL_set_fd(vio->ssl_,vio->sd);
+ SSL_set_accept_state(vio->ssl_);
+ SSL_do_handshake(vio->ssl_);
+ vio->open_ = TRUE;
+#ifndef DBUF_OFF
+ DBUG_PRINT("info",("SSL_get_cipher_name() = '%s'"
+ ,SSL_get_cipher_name(vio->ssl_)));
+ client_cert = SSL_get_peer_certificate (vio->ssl_);
+ if (client_cert != NULL) {
+ DBUG_PRINT("info",("Client certificate:"));
+ str = X509_NAME_oneline (X509_get_subject_name (client_cert), 0, 0);
+ DBUG_PRINT("info",("\t subject: %s", str));
+ free (str);
+
+ str = X509_NAME_oneline (X509_get_issuer_name (client_cert), 0, 0);
+ DBUG_PRINT("info",("\t issuer: %s", str));
+ free (str);
+
+ X509_free (client_cert);
+ } else
+ DBUG_PRINT("info",("Client does not have certificate."));
+
+ str=SSL_get_shared_ciphers(vio->ssl_, buf, sizeof(buf));
+ if(str)
+ {
+ DBUG_PRINT("info",("SSL_get_shared_ciphers() returned '%s'",str));
+ }
+ else
+ {
+ DBUG_PRINT("info",("no shared ciphers!"));
+ }
+
+#endif
+ DBUG_VOID_RETURN;
+}
+
+void sslconnect(struct st_VioSSLConnectorFd* ptr, Vio* vio, long timeout)
+{
+ char *str;
+ X509* server_cert;
+ DBUG_ENTER("sslconnect");
+ DBUG_PRINT("enter", ("sd=%d ptr=%p ctx: %p", vio->sd,ptr,ptr->ssl_context_));
+ vio_reset(vio,VIO_TYPE_SSL,vio->sd,0,FALSE);
+ vio->ssl_=0;
+ vio->open_=FALSE;
+ if (!(vio->ssl_ = SSL_new(ptr->ssl_context_)))
+ {
+ DBUG_PRINT("error", ("SSL_new failure"));
+ report_errors();
+ DBUG_VOID_RETURN;
+ }
+ DBUG_PRINT("info", ("ssl_=%p timeout=%ld",vio->ssl_, timeout));
+ SSL_clear(vio->ssl_);
+ vio_blocking(vio, FALSE);
+ SSL_SESSION_set_timeout(SSL_get_session(vio->ssl_), timeout);
+ SSL_set_fd (vio->ssl_, vio->sd);
+ SSL_set_connect_state(vio->ssl_);
+ SSL_do_handshake(vio->ssl_);
+ vio->open_ = TRUE;
+#ifndef DBUG_OFF
+ DBUG_PRINT("info",("SSL_get_cipher_name() = '%s'"
+ ,SSL_get_cipher_name(vio->ssl_)));
+ server_cert = SSL_get_peer_certificate (vio->ssl_);
+ if (server_cert != NULL) {
+ DBUG_PRINT("info",("Server certificate:"));
+ str = X509_NAME_oneline (X509_get_subject_name (server_cert), 0, 0);
+ DBUG_PRINT("info",("\t subject: %s", str));
+ free (str);
+
+ str = X509_NAME_oneline (X509_get_issuer_name (server_cert), 0, 0);
+ DBUG_PRINT("info",("\t issuer: %s", str));
+ free (str);
+
+ /* We could do all sorts of certificate verification stuff here before
+ * deallocating the certificate. */
+
+ X509_free (server_cert);
+ } else
+ DBUG_PRINT("info",("Server does not have certificate."));
+#endif
+ DBUG_VOID_RETURN;
+}
+
+#endif /* HAVE_OPENSSL */
diff --git a/vio/viosslfactories.c b/vio/viosslfactories.c
new file mode 100644
index 00000000000..322c1ce01e4
--- /dev/null
+++ b/vio/viosslfactories.c
@@ -0,0 +1,344 @@
+/* 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 */
+
+#include <my_global.h>
+
+#ifdef HAVE_OPENSSL
+
+#include <my_sys.h>
+#include <mysql_com.h>
+#include <violite.h>
+
+
+static bool ssl_algorithms_added = FALSE;
+static bool ssl_error_strings_loaded= FALSE;
+static int verify_depth = 0;
+static int verify_error = X509_V_OK;
+
+static unsigned char dh512_p[]={
+ 0xDA,0x58,0x3C,0x16,0xD9,0x85,0x22,0x89,0xD0,0xE4,0xAF,0x75,
+ 0x6F,0x4C,0xCA,0x92,0xDD,0x4B,0xE5,0x33,0xB8,0x04,0xFB,0x0F,
+ 0xED,0x94,0xEF,0x9C,0x8A,0x44,0x03,0xED,0x57,0x46,0x50,0xD3,
+ 0x69,0x99,0xDB,0x29,0xD7,0x76,0x27,0x6B,0xA2,0xD3,0xD4,0x12,
+ 0xE2,0x18,0xF4,0xDD,0x1E,0x08,0x4C,0xF6,0xD8,0x00,0x3E,0x7C,
+ 0x47,0x74,0xE8,0x33,
+};
+static unsigned char dh512_g[]={
+ 0x02,
+};
+
+static DH *get_dh512(void)
+{
+ DH *dh=NULL;
+
+ if ((dh=DH_new()) == NULL) return(NULL);
+ dh->p=BN_bin2bn(dh512_p,sizeof(dh512_p),NULL);
+ dh->g=BN_bin2bn(dh512_g,sizeof(dh512_g),NULL);
+ if ((dh->p == NULL) || (dh->g == NULL))
+ return(NULL);
+ return(dh);
+}
+
+static void
+report_errors()
+{
+ unsigned long l;
+ const char* file;
+ const char* data;
+ int line,flags;
+
+ DBUG_ENTER("report_errors");
+
+ while ((l=ERR_get_error_line_data(&file,&line,&data,&flags)) != 0)
+ {
+ char buf[200];
+ DBUG_PRINT("error", ("OpenSSL: %s:%s:%d:%s\n", ERR_error_string(l,buf),
+ file,line,(flags&ERR_TXT_STRING)?data:"")) ;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+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",
+ ctx, cert_file, key_file));
+ if (cert_file != NULL)
+ {
+ if (SSL_CTX_use_certificate_file(ctx,cert_file,SSL_FILETYPE_PEM) <= 0)
+ {
+ DBUG_PRINT("error",("unable to get certificate from '%s'\n",cert_file));
+ /* FIX stderr */
+ ERR_print_errors_fp(stderr);
+ DBUG_RETURN(0);
+ }
+ if (key_file == NULL)
+ key_file = cert_file;
+ if (SSL_CTX_use_PrivateKey_file(ctx,key_file,
+ SSL_FILETYPE_PEM) <= 0)
+ {
+ DBUG_PRINT("error", ("unable to get private key from '%s'\n",key_file));
+ /* FIX stderr */
+ ERR_print_errors_fp(stderr);
+ DBUG_RETURN(0);
+ }
+
+ /* If we are using DSA, we can copy the parameters from
+ * the private key */
+ /* Now we know that a key and cert have been set against
+ * the SSL context */
+ if (!SSL_CTX_check_private_key(ctx))
+ {
+ DBUG_PRINT("error", ("Private key does not match the certificate public key\n"));
+ DBUG_RETURN(0);
+ }
+ }
+ DBUG_RETURN(1);
+}
+
+
+static int
+vio_verify_callback(int ok, X509_STORE_CTX *ctx)
+{
+ char buf[256];
+ X509* err_cert;
+ int err,depth;
+
+ DBUG_ENTER("vio_verify_callback");
+ DBUG_PRINT("enter", ("ok=%d, ctx=%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);
+
+ X509_NAME_oneline(X509_get_subject_name(err_cert),buf,sizeof(buf));
+ if (!ok)
+ {
+ DBUG_PRINT("error",("verify error:num=%d:%s\n",err,
+ X509_verify_cert_error_string(err)));
+ if (verify_depth >= depth)
+ {
+ ok=1;
+ verify_error=X509_V_OK;
+ }
+ else
+ {
+ ok=0;
+ verify_error=X509_V_ERR_CERT_CHAIN_TOO_LONG;
+ }
+ }
+ switch (ctx->error) {
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+ X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert),buf,256);
+ DBUG_PRINT("info",("issuer= %s\n",buf));
+ break;
+ case X509_V_ERR_CERT_NOT_YET_VALID:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+ DBUG_PRINT("error", ("notBefore"));
+ /*ASN1_TIME_print_fp(stderr,X509_get_notBefore(ctx->current_cert));*/
+ break;
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+ DBUG_PRINT("error", ("notAfter error"));
+ /*ASN1_TIME_print_fp(stderr,X509_get_notAfter(ctx->current_cert));*/
+ break;
+ }
+ DBUG_PRINT("exit", ("r=%d", ok));
+ DBUG_RETURN(ok);
+}
+
+
+/************************ VioSSLConnectorFd **********************************/
+struct st_VioSSLConnectorFd* new_VioSSLConnectorFd(const char* key_file,
+ const char* cert_file,
+ const char* ca_file,
+ const char* ca_path,
+ const char* cipher)
+{
+ int verify = SSL_VERIFY_PEER;
+ struct st_VioSSLConnectorFd* ptr;
+ int result;
+ DH *dh=NULL;
+ DBUG_ENTER("new_VioSSLConnectorFd");
+ DBUG_PRINT("enter",
+ ("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_VioSSLConnectorFd*)my_malloc(sizeof(struct st_VioSSLConnectorFd),MYF(0));
+ ptr->ssl_context_=0;
+ ptr->ssl_method_=0;
+ /* FIXME: constants! */
+
+ if (!ssl_algorithms_added)
+ {
+ DBUG_PRINT("info", ("todo: OpenSSL_add_all_algorithms()"));
+ ssl_algorithms_added = TRUE;
+ OpenSSL_add_all_algorithms();
+ }
+ if (!ssl_error_strings_loaded)
+ {
+ DBUG_PRINT("info", ("todo:SSL_load_error_strings()"));
+ ssl_error_strings_loaded = TRUE;
+ SSL_load_error_strings();
+ }
+ ptr->ssl_method_ = TLSv1_client_method();
+ ptr->ssl_context_ = SSL_CTX_new(ptr->ssl_method_);
+ DBUG_PRINT("info", ("ssl_context_: %p",ptr->ssl_context_));
+ if (ptr->ssl_context_ == 0)
+ {
+ DBUG_PRINT("error", ("SSL_CTX_new failed"));
+ report_errors();
+ goto ctor_failure;
+ }
+ /*
+ * SSL_CTX_set_options
+ * SSL_CTX_set_info_callback
+ */
+ if(cipher)
+ {
+ result=SSL_CTX_set_cipher_list(ptr->ssl_context_, cipher);
+ DBUG_PRINT("info",("SSL_set_cipher_list() returned %d",result));
+ }
+ SSL_CTX_set_verify(ptr->ssl_context_, verify, vio_verify_callback);
+ if (vio_set_cert_stuff(ptr->ssl_context_, cert_file, key_file) == -1)
+ {
+ DBUG_PRINT("error", ("vio_set_cert_stuff failed"));
+ report_errors();
+ goto ctor_failure;
+ }
+ if (SSL_CTX_load_verify_locations( ptr->ssl_context_, ca_file,ca_path)==0)
+ {
+ DBUG_PRINT("warning", ("SSL_CTX_load_verify_locations failed"));
+ if (SSL_CTX_set_default_verify_paths(ptr->ssl_context_)==0)
+ {
+ DBUG_PRINT("error", ("SSL_CTX_set_default_verify_paths failed"));
+ report_errors();
+ goto ctor_failure;
+ }
+ }
+
+ /* DH stuff */
+ dh=get_dh512();
+ SSL_CTX_set_tmp_dh(ptr->ssl_context_,dh);
+ DH_free(dh);
+
+ DBUG_RETURN(ptr);
+ctor_failure:
+ DBUG_PRINT("exit", ("there was an error"));
+ my_free((gptr)ptr,MYF(0));
+ DBUG_RETURN(0);
+}
+
+
+/************************ VioSSLAcceptorFd **********************************/
+
+struct st_VioSSLAcceptorFd*
+new_VioSSLAcceptorFd(const char* key_file,
+ const char* cert_file,
+ const char* ca_file,
+ const char* ca_path,
+ const char* cipher)
+{
+ int verify = (SSL_VERIFY_PEER |
+ SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
+ SSL_VERIFY_CLIENT_ONCE);
+
+ struct st_VioSSLAcceptorFd* ptr;
+ int result;
+ DH *dh=NULL;
+ DBUG_ENTER("new_VioSSLAcceptorFd");
+ DBUG_PRINT("enter",
+ ("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*)my_malloc(sizeof(struct st_VioSSLAcceptorFd),MYF(0));
+ ptr->ssl_context_=0;
+ ptr->ssl_method_=0;
+ /* FIXME: constants! */
+ ptr->session_id_context_ = ptr;
+
+ if (!ssl_algorithms_added)
+ {
+ DBUG_PRINT("info", ("todo: OpenSSL_add_all_algorithms()"));
+ ssl_algorithms_added = TRUE;
+ OpenSSL_add_all_algorithms();
+
+ }
+ if (!ssl_error_strings_loaded)
+ {
+ DBUG_PRINT("info", ("todo: SSL_load_error_strings()"));
+ ssl_error_strings_loaded = TRUE;
+ SSL_load_error_strings();
+ }
+ ptr->ssl_method_ = TLSv1_server_method();
+ ptr->ssl_context_ = SSL_CTX_new(ptr->ssl_method_);
+ if (ptr->ssl_context_==0)
+ {
+ DBUG_PRINT("error", ("SSL_CTX_new failed"));
+ report_errors();
+ goto ctor_failure;
+ }
+ if(cipher)
+ {
+ result=SSL_CTX_set_cipher_list(ptr->ssl_context_, cipher);
+ DBUG_PRINT("info",("SSL_set_cipher_list() returned %d",result));
+ }
+ /*
+ * SSL_CTX_set_quiet_shutdown(ctx,1);
+ *
+ */
+ SSL_CTX_sess_set_cache_size(ptr->ssl_context_,128);
+
+
+
+ /* DH?
+ */
+ SSL_CTX_set_verify(ptr->ssl_context_, verify, vio_verify_callback);
+ SSL_CTX_set_session_id_context(ptr->ssl_context_,(const uchar*)&(ptr->session_id_context_),sizeof(ptr->session_id_context_));
+
+ /*
+ * SSL_CTX_set_client_CA_list(ctx,SSL_load_client_CA_file(CAfile));
+ */
+ if (vio_set_cert_stuff(ptr->ssl_context_, cert_file, key_file) == -1)
+ {
+ DBUG_PRINT("error", ("vio_set_cert_stuff failed"));
+ report_errors();
+ goto ctor_failure;
+ }
+ if (SSL_CTX_load_verify_locations( ptr->ssl_context_, ca_file, ca_path)==0)
+ {
+ DBUG_PRINT("warning", ("SSL_CTX_load_verify_locations failed"));
+ if (SSL_CTX_set_default_verify_paths(ptr->ssl_context_)==0)
+ {
+ DBUG_PRINT("error", ("SSL_CTX_set_default_verify_paths failed"));
+ report_errors();
+ goto ctor_failure;
+ }
+ }
+ /* DH stuff */
+ dh=get_dh512();
+ SSL_CTX_set_tmp_dh(ptr->ssl_context_,dh);
+ DH_free(dh);
+
+ DBUG_RETURN(ptr);
+ctor_failure:
+ DBUG_PRINT("exit", ("there was an error"));
+ my_free((gptr)ptr,MYF(0));
+ DBUG_RETURN(0);
+}
+
+
+#endif /* HAVE_OPENSSL */
diff --git a/vio/viotest-ssl.c b/vio/viotest-ssl.c
new file mode 100644
index 00000000000..8c549ae1d38
--- /dev/null
+++ b/vio/viotest-ssl.c
@@ -0,0 +1,156 @@
+/* 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 */
+
+#include <my_global.h>
+#ifdef HAVE_OPENSSL
+#include <my_sys.h>
+#include <m_string.h>
+#include <m_ctype.h>
+#include "mysql.h"
+#include "errmsg.h"
+#include <my_dir.h>
+#ifndef __GNU_LIBRARY__
+#define __GNU_LIBRARY__ // Skip warnings in getopt.h
+#endif
+#include <getopt.h>
+//#include "my_readline.h"
+#include <signal.h>
+#include <violite.h>
+
+const char *VER="0.1";
+
+
+#ifndef DBUG_OFF
+const char *default_dbug_option="d:t:O,/tmp/viotest-ssl.trace";
+#endif
+
+void
+fatal_error( const char* r)
+{
+ perror(r);
+ exit(0);
+}
+
+void
+print_usage()
+{
+ printf("viossl-test: testing SSL virtual IO. Usage:\n");
+ printf("viossl-test server-key server-cert client-key client-cert [CAfile] [CApath]\n");
+}
+
+int
+main( int argc,
+ char** argv)
+{
+ char* server_key = 0;
+ char* server_cert = 0;
+ char* client_key = 0;
+ char* client_cert = 0;
+ char* ca_file = 0;
+ char* ca_path = 0;
+ int child_pid,sv[2];
+ struct st_VioSSLAcceptorFd* ssl_acceptor=0;
+ struct st_VioSSLConnectorFd* ssl_connector=0;
+ Vio* client_vio=0;
+ Vio* server_vio=0;
+ MY_INIT(argv[0]);
+// DBUG_ENTER("main");
+ DBUG_PROCESS(argv[0]);
+ DBUG_PUSH(default_dbug_option);
+
+
+
+ if (argc<5)
+ {
+ print_usage();
+ return 1;
+ }
+
+ server_key = argv[1];
+ server_cert = argv[2];
+ client_key = argv[3];
+ client_cert = argv[4];
+ if (argc>5)
+ ca_file = argv[5];
+ if (argc>6)
+ ca_path = argv[6];
+ printf("Server key/cert : %s/%s\n", server_key, server_cert);
+ printf("Client key/cert : %s/%s\n", client_key, client_cert);
+ if (ca_file!=0)
+ printf("CAfile : %s\n", ca_file);
+ if (ca_path!=0)
+ printf("CApath : %s\n", ca_path);
+
+
+ if (socketpair(PF_UNIX, SOCK_STREAM, IPPROTO_IP, sv)==-1)
+ fatal_error("socketpair");
+
+ ssl_acceptor = new_VioSSLAcceptorFd(server_key, server_cert, ca_file, ca_path);
+ ssl_connector = new_VioSSLConnectorFd(client_key, client_cert, ca_file, ca_path);
+
+ client_vio = (Vio*)my_malloc(sizeof(struct st_vio),MYF(0));
+ client_vio->sd = sv[0];
+ sslconnect(ssl_connector,client_vio);
+ server_vio = (Vio*)my_malloc(sizeof(struct st_vio),MYF(0));
+ server_vio->sd = sv[1];
+ sslaccept(ssl_acceptor,server_vio);
+
+ printf("Socketpair: %d , %d\n", client_vio->sd, server_vio->sd);
+
+ child_pid = fork();
+ if (child_pid==-1) {
+ my_free((gptr)ssl_acceptor,MYF(0));
+ my_free((gptr)ssl_connector,MYF(0));
+ fatal_error("fork");
+ }
+ if (child_pid==0) {
+ //child, therefore, client
+ char xbuf[100];
+ int r = vio_ssl_read(client_vio,xbuf, sizeof(xbuf));
+ if (r<=0) {
+ my_free((gptr)ssl_acceptor,MYF(0));
+ my_free((gptr)ssl_connector,MYF(0));
+ fatal_error("client:SSL_read");
+ }
+// printf("*** client cipher %s\n",client_vio->cipher_description());
+ xbuf[r] = 0;
+ printf("client:got %s\n", xbuf);
+ my_free((gptr)client_vio,MYF(0));
+ my_free((gptr)ssl_acceptor,MYF(0));
+ my_free((gptr)ssl_connector,MYF(0));
+ sleep(1);
+ } else {
+ const char* s = "Huhuhuh";
+ int r = vio_ssl_write(server_vio,(gptr)s, strlen(s));
+ if (r<=0) {
+ my_free((gptr)ssl_acceptor,MYF(0));
+ my_free((gptr)ssl_connector,MYF(0));
+ fatal_error("server:SSL_write");
+ }
+// printf("*** server cipher %s\n",server_vio->cipher_description());
+ my_free((gptr)server_vio,MYF(0));
+ my_free((gptr)ssl_acceptor,MYF(0));
+ my_free((gptr)ssl_connector,MYF(0));
+ sleep(1);
+ }
+ return 0;
+}
+#else /* HAVE_OPENSSL */
+
+int main() {
+return 0;
+}
+#endif /* HAVE_OPENSSL */
diff --git a/vio/viotest-ssl.cc b/vio/viotest-ssl.cc
deleted file mode 100644
index a3ad92a7c9c..00000000000
--- a/vio/viotest-ssl.cc
+++ /dev/null
@@ -1,104 +0,0 @@
-#include "all.h"
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <stdio.h>
-#include <unistd.h>
-
-
-void
-fatal_error( const char* r)
-{
- perror(r);
- exit(0);
-}
-
-void
-print_usage()
-{
- printf("viossltest: testing SSL virtual IO. Usage:\n");
- printf("viossltest server-key server-cert client-key client-cert [CAfile] [CApath]\n");
-}
-
-int
-main( int argc,
- char** argv)
-{
- char* server_key = 0;
- char* server_cert = 0;
- char* client_key = 0;
- char* client_cert = 0;
- char* ca_file = 0;
- char* ca_path = 0;
- int sv[2];
-
- if (argc<5)
- {
- print_usage();
- return 1;
- }
-
- if (socketpair(PF_UNIX, SOCK_STREAM, IPPROTO_IP, sv)==-1)
- fatal_error("socketpair");
-
- server_key = argv[1];
- server_cert = argv[2];
- client_key = argv[3];
- client_cert = argv[4];
- if (argc>5)
- ca_file = argv[5];
- if (argc>6)
- ca_path = argv[6];
- printf("Server key/cert : %s/%s\n", server_key, server_cert);
- printf("Client key/cert : %s/%s\n", client_key, client_cert);
- if (ca_file!=0)
- printf("CAfile : %s\n", ca_file);
- if (ca_path!=0)
- printf("CApath : %s\n", ca_path);
-
- VIO_NS::VioSSLAcceptorFd* ssl_acceptor = new VIO_NS::VioSSLAcceptorFd(server_key, server_cert, ca_file, ca_path);
- VIO_NS::VioSSLConnectorFd* ssl_connector = new VIO_NS::VioSSLConnectorFd(client_key, client_cert, ca_file, ca_path);
-
- printf("Socketpair: %d , %d\n", sv[0], sv[1]);
-
- VIO_NS::VioSSL* client_vio = ssl_connector->connect(sv[0]);
- VIO_NS::VioSSL* server_vio = ssl_acceptor->accept(sv[1]);
-
-
- int child_pid = fork();
- if (child_pid==-1) {
- delete ssl_acceptor;
- delete ssl_connector;
- fatal_error("fork");
- }
- if (child_pid==0) {
- //child, therefore, client
- char xbuf[100];
- int r = client_vio->read(xbuf, sizeof(xbuf));
- if (r<=0) {
- delete ssl_acceptor;
- delete ssl_connector;
- fatal_error("client:SSL_read");
- }
- printf("*** client cipher %s\n",client_vio->cipher_description());
- xbuf[r] = 0;
- printf("client:got %s\n", xbuf);
- delete client_vio;
- delete ssl_acceptor;
- delete ssl_connector;
- sleep(1);
- } else {
- const char* s = "Huhuhuh";
- int r = server_vio->write((void *)s, strlen(s));
- if (r<=0) {
- delete ssl_acceptor;
- delete ssl_connector;
- fatal_error("server:SSL_write");
- }
- printf("*** server cipher %s\n",server_vio->cipher_description());
- delete server_vio;
- delete ssl_acceptor;
- delete ssl_connector;
- sleep(1);
- }
-}
diff --git a/vio/viotypes.h b/vio/viotypes.h
deleted file mode 100644
index 8d36a35c86f..00000000000
--- a/vio/viotypes.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
-** Virtual I/O library
-** Written by Andrei Errapart <andreie@no.spam.ee>
-*/
-
-/*
- * Some typedefs to external types.
- */
-#ifndef vio_viotypes_h_
-#define vio_viotypes_h_
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <sys/types.h>
-
-typedef int vio_bool_t;
-typedef void* vio_ptr_t;
-
-#ifdef __cplusplus
-VIO_NS_BEGIN
-
-typedef vio_ptr_t vio_ptr;
-typedef char* vio_cstring;
-typedef int32_t vio_int32;
-typedef u_int32_t vio_uint32;
-typedef vio_bool_t vio_bool;
-
-VIO_NS_END
-#endif /* __cplusplus */
-
-#endif /* vio_types_h_ */
-